diff --git a/isis/3rdParty/Makefile b/isis/3rdParty/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..acd40c46e26c3220550df4c3a0e578d3df629677 --- /dev/null +++ b/isis/3rdParty/Makefile @@ -0,0 +1,79 @@ +include $(ISISROOT)/make/isismake.macros + +.PHONY: libs plugins + +all: install + +install: libs plugins + +libs: + @for library in $(THIRDPARTYLIBS); do \ + $(INSTALL3P) $(INSTALL3POPTS) $$library $(ISISROOT)/3rdParty/lib/; \ + echo " [Installing $$library...]"; \ + if [ "$(HOST_ARCH)" == "Linux" ]; then \ + for file in $$library; do \ + localFile=$(ISISROOT)/3rdParty/lib/`basename $$file`; \ + existingRpath=`$(PATCHELF) --print-rpath "$$localFile" 2>&- | \ + cut -d '/' -f2-4`; \ + dollar='$$'; \ + newRpath=`echo "$${dollar}ORIGIN"`; \ + if [ "$$existingRpath" == "usgs/pkgs/local" ]; then \ + echo " [Patching" `basename $$file` "...]"; \ + $(PATCHELF) --set-rpath "$$newRpath" $$localFile; \ + fi \ + done; \ + fi; \ + done; \ + if [ "$(HOST_ARCH)" == "Darwin" ]; then \ + chmod u+w $(ISISROOT)/3rdParty/lib/libcrypto.*.dylib; \ + chmod u+w $(ISISROOT)/3rdParty/lib/libssl.*.dylib; \ + $(ISISROOT)/scripts/SetRunTimePath --libs \ + --libmap=$(ISISROOT)/scripts/darwin_lib_paths.lis \ + --liblog=DarwinLibs.lis --update \ + --relocdir=$(ISISROOT)/3rdParty/lib:$(ISISROOT)/3rdParty \ + --errlog=DarwinErrors.lis \ + `find $(ISISROOT)/3rdParty/lib -name '*.dylib' -type f` \ + > /dev/null; \ + $(ISISROOT)/scripts/SetRunTimePath --libs \ + --libmap=$(ISISROOT)/scripts/qt_paths.lis \ + --liblog=DarwinLibs.lis \ + --relocdir=$(ISISROOT)/3rdParty/lib:$ISISROOT/3rdParty \ + --update \ + `find $(ISISROOT)/3rdParty/lib -name 'Qt*' -print \ + -mindepth 3 -maxdepth 4 -type f` > /dev/null; \ + chmod u-w $(ISISROOT)/3rdParty/lib/libcrypto.*.dylib; \ + chmod u-w $(ISISROOT)/3rdParty/lib/libssl.*.dylib; \ + if [ -f "DarwinErrors.lis" ]; then \ + cat DarwinErrors.lis; \ + fi; \ + $(RM) DarwinErrors.lis DarwinLibs.lis; \ + fi + +plugins: + @for plugs in $(THIRDPARTYPLUGINS); do \ + echo " [Installing $$plugs...]"; \ + $(INSTALL3P) $(INSTALL3POPTS) $$plugs $(ISISROOT)/3rdParty/plugins/; \ + done; \ + if [ "$(HOST_ARCH)" == "Darwin" ]; then \ + $(ISISROOT)/scripts/SetRunTimePath --bundles \ + --libmap=$(ISISROOT)/scripts/qt_plugins_paths.lis \ + --liblog=DarwinLibs.lis --update \ + --relocdir=$(ISISROOT)/3rdParty/lib:$(ISISROOT)/3rdParty \ + --errlog=DarwinErrors.lis \ + `find $(ISISROOT)/3rdParty/plugins -name '*.bundle' -type f` \ + > /dev/null; \ + if [ -f "DarwinErrors.lis" ]; then \ + cat DarwinErrors.lis; \ + fi; \ + $(RM) DarwinErrors.lis DarwinLibs.lis; \ + fi + +clean: + rm -f lib/lib*.so* + @for plugs in plugins/*; do \ + if [ -d $$plugs -a $$plugs != "plugins/CVS" ]; \ + then \ + $(RM) -rf $$plugs; \ + fi \ + done; + diff --git a/isis/3rdParty/lib/README b/isis/3rdParty/lib/README new file mode 100644 index 0000000000000000000000000000000000000000..370c2cc66e12035bbc3d5d21135ea6a0fc096691 --- /dev/null +++ b/isis/3rdParty/lib/README @@ -0,0 +1,2 @@ +This directory contains O/S and hardware specific shared libraries needed +to execute ISIS applications diff --git a/isis/3rdParty/plugins/README b/isis/3rdParty/plugins/README new file mode 100644 index 0000000000000000000000000000000000000000..55cfae117e53899e546d9ffff6c44a4886d94f10 --- /dev/null +++ b/isis/3rdParty/plugins/README @@ -0,0 +1,2 @@ +This directory contains Qt plugins that are exported for use in Isis +applications. diff --git a/isis/IsisPreferences b/isis/IsisPreferences new file mode 100644 index 0000000000000000000000000000000000000000..cf9cb0471affa986e042a6d871e172e6501bd490 --- /dev/null +++ b/isis/IsisPreferences @@ -0,0 +1,118 @@ +####################################################### +# This file allows the user to customize their Isis +# configuration. See the Isis Preference Dictionary +# on our website isis.astrogeology.usgs.gov for a +# full description of each group. +######################################################## + +######################################################## +# Customize elements of the user interface +# +# ProgressBarPercent = 1 | 2 | 5 | 10 +# ProgressBar = On | Off +# GuiStyle = windows | motif | cde | motifplus | +# platinum | sgi | kde | aqua +# GuiHelpBrowser = { your preferred browser, may need path } +# GuiFontName = helvitica | times | charter | any legal font +# GuiFontSize = 10 | 12 | 14 | any font point size +# HistoryPath = { your preferred loaction for the application +# .par files } +# HistoryRecording = On | Off +# HistoryLength = (your preferred count of history entries +# to remember) +######################################################## + +Group=UserInterface + ProgressBarPercent = 10 + ProgressBar = On + GuiHelpBrowser = firefox + GuiFontName = helvitica + GuiFontSize = 10 + GuiWidth = 460 + GuiHeight = 600 + HistoryPath = $HOME/.Isis/history + HistoryRecording = On + HistoryLength = 10 +EndGroup + +######################################################## +# Customize how errors are reported +# +# FileLine = On | Off +# Format = Standard | Pvl +# StackTrace = On | Off +######################################################## + +Group = ErrorFacility + FileLine = Off + Format = Standard + StackTrace = Off +EndGroup + +######################################################## +# Customize how session logging is handled +# +# TerminalOutput = On | Off +# FileOutput = On | Off +# FileName = print.prt | /mydirectory/myfile.prt +# FileAccess = Append | Overwrite +######################################################## + +Group = SessionLog + TerminalOutput = Off + FileOutput = On + FileName = print.prt + FileAccess = Append +EndGroup + +######################################################## +# Customize how cubes are created +# +# Overwrite = Error | Allow +# Format = Attached | Detached +# History = On | Off +# MaximumSize = max # of gigabytes +######################################################## + +Group = CubeCustomization + Overwrite = Allow + Format = Attached + History = On + MaximumSize = 12 +EndGroup + +######################################################## +# Customize the location of mission specific data +# files (calibration and spice kernels). Usually this +# should be left to the Isis administrator +######################################################## + +Group = DataDirectory + Apollo15 = $ISIS3DATA/apollo15 + Apollo16 = $ISIS3DATA/apollo16 + Apollo17 = $ISIS3DATA/apollo17 + Base = $ISIS3DATA/base + Cassini = $ISIS3DATA/cassini + Chan1 = $ISIS3DATA/chan1 + Clementine1 = $ISIS3DATA/clementine1 + Dawn = $ISIS3DATA/dawn + Galileo = $ISIS3DATA/galileo + Lo = $ISIS3DATA/lo + Lro = $ISIS3DATA/lro + Mariner10 = $ISIS3DATA/mariner10 + Mer = $ISIS3DATA/mer + Mex = $ISIS3DATA/mex + Messenger = $ISIS3DATA/messenger + Mgs = $ISIS3DATA/mgs + Mro = $ISIS3DATA/mro + Odyssey = $ISIS3DATA/odyssey + Rolo = $ISIS3DATA/rolo + Smart1 = $ISIS3DATA/smart1 + Viking1 = $ISIS3DATA/viking1 + Viking2 = $ISIS3DATA/viking2 + Voyager1 = $ISIS3DATA/voyager1 + Voyager2 = $ISIS3DATA/voyager2 + Temporary = . +EndGroup + +End diff --git a/isis/Makefile b/isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bcf6f20f109884433d3bfb7ef0d1bde22e874cd4 --- /dev/null +++ b/isis/Makefile @@ -0,0 +1,188 @@ +include $(ISISROOT)/make/isismake.macros + +#---------------------------------------------------------------------------- +# Let the user know how to use the system +#---------------------------------------------------------------------------- +help: + echo "Isis Make System Commands" + echo "------------------------ " + echo "make all : Build and install the entire system (incs,api,apps,docs)" + echo "make incs : Install API include files" + echo "make api : Build and install the Isis API" + echo "make apps : Build and install Isis Applications" + echo "make docs : Build Isis Web Documentation" + echo "make cleansrc : Clean binaries from source tree" + echo "make clean : Clean source tree and install area" + echo "make unitTest : Build and execute unit tests for Isis API" + echo "make appTest : Build and execute application tests" + echo "make catTest : Build and execute category tests" + echo "make thirdParty: Copy required 3rdParty libraries into distribution" + +#---------------------------------------------------------------------------- +# Target = all +# Dependencies = includes api applications documentation thirdParty +# +# The API include files must be installed before the API can be constructed. +# After the API is created then the applications can be individually built +# and installed. Finally create the web documentation for the entire system. +#---------------------------------------------------------------------------- +all: incs thirdParty api apps docs + +#---------------------------------------------------------------------------- +# Target = incs +# Dependencies = none +# +# The API include files will be installed in $(ISISROOT)/inc. The Isis +# make system will traverse the objs directories (src/base/objs/*) and +# copy the include file from the individual object directory into the +# system directory $(ISISROOT)/inc. +#---------------------------------------------------------------------------- +incs: + echo "Installing include files" + mkdir -p inc + cd src; $(MAKE) includes + echo "Finished installing include files" + echo " " + +#---------------------------------------------------------------------------- +# Target = api +# Dependencies = objects +# +# The Isis API is essentially libisis.a which will be created in the +# directory $(ISISROOT)/lib. Make api traverses the objs directories +# (src/base/objs/*) and archives the ".o" files into libisis.a. Therefore +# the ".o" files must exist. +# +# Target = objects +# Dependencies = none +# +# Before the API can be built each individual object must be built. +# This target will traverse the objs directories and create the C++ +# object classes leaving the ".o" file in each individual directory. +# The API is not created until "make api" is performed +# +# Finally after the API is completed the shared libraries will be +# constructed from libisis.a +#---------------------------------------------------------------------------- +api: + echo "Building Isis API" + mkdir -p lib + cd src; $(MAKE) objects + cd src; $(MAKE) api + echo "Finished building Isis API" + echo " " + +# echo "Building Isis API with debugging" +# cd src; $(MAKE) objects MODE=DEBUG +# cd src; $(MAKE) api MODE=DEBUG +# echo "Finished building Isis API with debugging" +# echo " " + + echo "Creating Shared Libraries ..." + cp make/Makefile.libs lib/Makefile + cd lib; $(MAKE) shared + echo "Finished creating Shared Libraries ..." + echo " " + +#---------------------------------------------------------------------------- +# Target = apps +# Dependencies = none +# +# This will build and install all the Isis application in the directory +# $(ISISROOT)/bin. It also installs the application Xml file in +# $(ISISROOT/bin/xml. Again the make system traverse the apps directories +# (src/base/apps) and builds/installs each application. Of course the +# API must be built for this to work properly +#---------------------------------------------------------------------------- +apps: + echo "Building Isis Applications" + mkdir -p bin/xml + cd src; $(MAKE) applications + echo "Finished building Isis Applications" + echo " " + +#---------------------------------------------------------------------------- +# Target = docs +# Dependencies = none +# +# This target traverse both the objs and apps directories and moves the +# Xml and assets directories into specific sub-directories under +# $(ISISROOT)/src/docsys. Then it builds the entire docsys tree which +# generates the Isis Documentation under $(ISISROOT)/doc +#---------------------------------------------------------------------------- +docs: + echo "Building Isis Documentation" + mkdir -p doc + cd src; $(MAKE) documentation + cd src/docsys; $(MAKE) docs + echo "Finished building Isis Documentation" + +#---------------------------------------------------------------------------- +# Target = clean +# Dependencies = cleansrc +# +# This target cleans the entire Isis system. It cleans ".o" files and +# binary executables from the source tree. It also, clears the running +# areas under $ISISROOT (inc, doc, bini, bin/xml, and lib) +# +# Target = cleansrc +# Dependencies = none +# +# This walks the src tree and removes ".o" files and binary files +#---------------------------------------------------------------------------- +clean: cleansrc + echo "Cleaning Isis" + cd src; $(MAKE) clean + rm -rf inc + rm -rf doc + rm -rf bin + rm -rf lib + cd 3rdParty; $(MAKE) clean + echo "Finished Cleaning Isis" + +cleansrc: + cd src; $(MAKE) clean + +#---------------------------------------------------------------------------- +# Target = unitTest appTest appTest2 catTest +# Dependencies = none +# +# This target traverses both the objs and apps directories. In the object +# directories it will build the unitTest executable, run it, and difference +# the results with the unitTest truth data. In the application directories +# it will run the appTest script to ensure the program generates the proper +# output data (whether it be a cube, text file, postscript file, etc) +#---------------------------------------------------------------------------- +unitTest: + echo "Testing Isis API" + cd src; $(MAKE) unitTest + echo "Finished testing Isis API" + +appTest: + echo "Testing Isis Applications version 2" + cd src; $(MAKE) appTest + echo "Finished testing Isis Applications version 2" + +catTest: + echo "Testing Isis Category" + cd src; $(MAKE) catTest + echo "Finished testing Isis Category" + +#---------------------------------------------------------------------------- +# Target = thirdParty +# Dependencies = none +# +# This target is used only for external distributions that do not have +# the need to program. As a convenience we provide the shared libraries +# for 3rdParty packages used in ISIS so that external customers do +# not have to download and install RPMs. +#---------------------------------------------------------------------------- +HOST_ARCH ?= $(shell uname -s) +HOST_MACH = $(shell uname -m) + +thirdParty: + echo "Installing 3rdParty Libraries" + rm -f $(ISISROOT)/3rdParty/lib/lib* + echo $(HOST_ARCH) + $(MAKE) -C $(ISISROOT)/3rdParty install + diff --git a/isis/license.txt b/isis/license.txt new file mode 100644 index 0000000000000000000000000000000000000000..d027c85f72ad132acc9753cb7bef73201c6b5ce1 --- /dev/null +++ b/isis/license.txt @@ -0,0 +1,46 @@ +ISIS Licensing, copyright, distribution, and warranty information + +USGS-authored or produced data, information, and software are in the +public domain. + +Software and related material (data and (or) documentation), contained in or +furnished in connection with a software distribution, are made available by +the U.S. Geological Survey (USGS) to be used in the public interest and in +the advancement of science. You may, without any fee or cost, use, copy, +modify, or distribute this software, and any derivative works thereof, and +its supporting documentation, subject to the following restrictions and +understandings. + +If you distribute copies or modifications of the software and related +material, make sure the recipients receive a copy of this notice and +receive or can get a copy of the original distribution. If the software and +(or) related material are modified and distributed, it must be made clear +that the recipients do not have the original and they must be informed of +the extent of the modifications. For example, modified files must include a +prominent notice stating the modifications made, the author of the +modifications, and the date the modifications were made. This restriction is +necessary to guard against problems introduced in the software by others, +reflecting negatively on the reputation of the USGS. + +The software is public property and you therefore have the right to the +source code, if desired. You may charge fees for distribution, warranties, +and services provided in connection with the software or derivative works +thereof. The name USGS can be used in any advertising or publicity to +endorse or promote any products or commercial entity using this software +if specific written permission is obtained from the USGS. + +The user agrees to appropriately acknowledge the authors and the USGS in +publications that result from the use of this software or in products that +include this software in whole or in part. + +Because the software and related material are free (other than nominal +materials and handling fees) and provided "as is," the authors, the USGS, +and the United States Government have made no warranty, express or implied, +as to accuracy or completeness and are not obligated to provide the user +with any support, consulting, training or assistance of any kind with +regard to the use, operation, and performance of this software nor to +provide the user with any updates, revisions, new versions or "bug fixes." + +The user assumes all risk for any damages whatsoever resulting from +loss of use, data, or profits arising in connection with the access, +use, quality, or performance of this software diff --git a/isis/make/Makefile.apps b/isis/make/Makefile.apps new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/make/Makefile.apps @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/make/Makefile.appstree b/isis/make/Makefile.appstree new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/make/Makefile.appstree @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/make/Makefile.appstststree b/isis/make/Makefile.appstststree new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/make/Makefile.appstststree @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/make/Makefile.cat b/isis/make/Makefile.cat new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/make/Makefile.cat @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/make/Makefile.cattststree b/isis/make/Makefile.cattststree new file mode 100644 index 0000000000000000000000000000000000000000..016388fc898d8c89f380cae1fd08942c29611582 --- /dev/null +++ b/isis/make/Makefile.cattststree @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-42s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/make/Makefile.libs b/isis/make/Makefile.libs new file mode 100644 index 0000000000000000000000000000000000000000..cbbb9891e96edff7f4dbbf0ce3366215d80b7858 --- /dev/null +++ b/isis/make/Makefile.libs @@ -0,0 +1,15 @@ + +HOST_TYPE := $(shell uname -s) + +# Get archive to convert to shared +SRCS = $(wildcard *.a) + +ifeq ($(HOST_TYPE),Darwin) + SHARED = $(SRCS:%.a=%.dylib) +else + SHARED = $(SRCS:%.a=%.so) +endif + +shared: $(SHARED) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/make/Makefile.objs b/isis/make/Makefile.objs new file mode 100644 index 0000000000000000000000000000000000000000..205faace2eb30ed807ae27a1f9319b286f82b138 --- /dev/null +++ b/isis/make/Makefile.objs @@ -0,0 +1,5 @@ +INCS = $(wildcard Isis*.h) +SRCS = $(wildcard Isis*.cpp) +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/make/Makefile.objstree b/isis/make/Makefile.objstree new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/make/Makefile.objstree @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/make/Makefile.tsts b/isis/make/Makefile.tsts new file mode 100644 index 0000000000000000000000000000000000000000..56a29a70885cfe0f2f5b605b1a9700c1389ef82e --- /dev/null +++ b/isis/make/Makefile.tsts @@ -0,0 +1,6 @@ +APPNAME = + +include $(ISISROOT)/make/isismake.tsts + +commands: + > /dev/null; diff --git a/isis/make/config.darwin b/isis/make/config.darwin new file mode 100644 index 0000000000000000000000000000000000000000..23222d58f3caacecce311da4bebeb78429d960de --- /dev/null +++ b/isis/make/config.darwin @@ -0,0 +1,252 @@ +# $Id: config.darwin,v 1.47 2010/04/07 00:07:52 kbecker Exp $ +#-------------------------------------------------------------------------- +# Compiler options +#--------------------------------------------------------------------------- +# Basically is GNU g++/gcc +CXX = c++ +CC = cc + +ISISCPPFLAGS = -Wall +ISISCPPFLAGS += -ansi +ifeq ($(HOST_PROC), powerpc) +# Powerpc support + ISISCPPFLAGS += -DISIS_LITTLE_ENDIAN=0 +else +# Assumes Intel Mac + ISISCPPFLAGS += -DISIS_LITTLE_ENDIAN=1 +endif +ISISCPPFLAGS += -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE +ISISCPPFLAGS += -fPIC +ISISCPPFLAGS += -DGMM_USES_SUPERLU + +ifeq ($(findstring DEBUG, $(MODE)),DEBUG) + ISISCPPFLAGS += -g + ISISCPPFLAGS += -O0 +# ISISCPPFLAGS += -DCWDEBUG +else + ISISCPPFLAGS += -O1 + QTDARWINFLAGS += -DQT_NO_DEBUG +endif + +ISISCFLAGS = + +#--------------------------------------------------------------------------- +# Linker options. Runtime paths for Mac is rooted to $ISISROOT +#--------------------------------------------------------------------------- +ISISLDFLAGS = -headerpad_max_install_names -arch i386 -bind_at_load -Wl,-w +ISISLDRPATH = -Wl,-rpath,@loader_path/.. -Wl,-rpath,$(ISISROOT) +ISISSYSLIBS = -lz -lm -framework ApplicationServices +ISISSTATIC = +ISISDYNAMIC = + +#ifeq ($(findstring DEBUG, $(MODE)),DEBUG) +# ISISSYSLIBS += -lcwd +#endif + +#--------------------------------------------------------------------------- +# Shared library options +#--------------------------------------------------------------------------- +RANLIB = /usr/bin/ranlib +SHAREDLIBEXT = dylib +DYLIBVERSION = -compatibility_version $(ISISMAJOR).$(ISISMINOR) \ + -current_version $(ISISLIBVERSION) +DYLIBFLAGS = -dynamiclib -flat_namespace -single_module \ + -undefined suppress +ISISSHAREDFLAGS = -bundle -flat_namespace -dynamic -undefined suppress +ISISSHAREDON = +ISISSHAREDOFF = +ISISARFLAGS = + +#--------------------------------------------------------------------------- +# 3rd party directory root +#--------------------------------------------------------------------------- +ISIS3OPT ?= /opt/local +ISIS3LOCAL ?= /usgs/pkgs/local/isis$(ISISVERSION) + +#--------------------------------------------------------------------------- +# Set up for cwd +#--------------------------------------------------------------------------- +CWDINCDIR = +CWDLIBDIR = +CWDLIB = + +#--------------------------------------------------------------------------- +# Set up for Qwt +#--------------------------------------------------------------------------- +QWTDIR = $(ISIS3OPT) +QWTINCDIR = -I$(QWTDIR)/include +QWTLIBDIR = -L$(QWTDIR)/lib +QWTLIB = -lqwt + +#--------------------------------------------------------------------------- +# Set up for Qt +#--------------------------------------------------------------------------- +QTDARWINFLAGS += -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED +QTDIR = $(ISIS3OPT) +QTINCDIR = -I$(QTDIR)/libexec/qt4-mac/mkspecs/macx-g++ +QTINCDIR += -I$(QTDIR)/libexec/qt4-mac/include +QTINCDIR += -I$(QTDIR)/libexec/qt4-mac/include/QtCore +QTINCDIR += -I$(QTDIR)/libexec/qt4-mac/include/QtAssistant +QTINCDIR += -I$(QTDIR)/libexec/qt4-mac/include/QtGui +QTINCDIR += -I$(QTDIR)/libexec/qt4-mac/include/QtNetwork +QTINCDIR += -I$(QTDIR)/libexec/qt4-mac/include/QtScript +QTINCDIR += -I$(QTDIR)/libexec/qt4-mac/include/QtSql +QTINCDIR += -I$(QTDIR)/libexec/qt4-mac/include/QtSvg +QTINCDIR += -I$(QTDIR)/libexec/qt4-mac/include/QtWebKit +QTINCDIR += -I$(QTDIR)/libexec/qt4-mac/include/QtXml +QTINCDIR += -I$(QTDIR)/libexec/qt4-mac/include/QtXmlPatterns +QTLIBDIR = -L$(QTDIR)/libexec/qt4-mac/lib -F$(QTDIR)/libexec/qt4-mac/lib + +ISISCPPFLAGS += $(QTDARWINFLAGS) +QTCOMMONFRAMEWORKS = +QTFRAMEWORKS = -framework QtXmlPatterns -framework QtXml -framework QtNetwork \ + -framework QtSql -framework QtGui -framework QtCore -framework QtSvg +QTLIB = $(QTFRAMEWORKS) $(QTCOMMONFRAMEWORKS) + +QTOPENGL = -framework OpenGL -framework AGL + +UIC = $(QTDIR)/libexec/qt4-mac/bin/uic +RCC = $(QTDIR)/libexec/qt4-mac/bin/rcc +RCCDEFINES = +MOC = $(QTDIR)/libexec/qt4-mac/bin/moc +MOCDEFINES += $(QTDARWINFLAGS) +MOCDEFINES += $(QTINCDIR) +MOCDEFINES += -D__APPLE__ -D__GNUC__ + +#--------------------------------------------------------------------------- +# Set up for Xerces +#--------------------------------------------------------------------------- +XERCESINCDIR = -I$(ISIS3OPT)/include/xercesc +XERCESLIBDIR = -L$(ISIS3OPT)/lib +XERCESLIB = -lxerces-c + +XALAN = $(ISIS3OPT)/bin/Xalan + +#--------------------------------------------------------------------------- +# Set up for naif +#--------------------------------------------------------------------------- +NAIFINCDIR = -I$(ISIS3LOCAL)/include +NAIFLIBDIR = -L$(ISIS3LOCAL)/lib +NAIFLIB = -lcspice + +#--------------------------------------------------------------------------- +# Set up for TNT +#--------------------------------------------------------------------------- +TNTINCDIR = -I$(ISIS3LOCAL)/include/tnt +TNTLIBDIR = +TNTLIB = + +#--------------------------------------------------------------------------- +# Set up for JAMA +#--------------------------------------------------------------------------- +JAMAINCDIR = -I$(ISIS3LOCAL)/include/jama +JAMALIBDIR = +JAMALIB = + +#--------------------------------------------------------------------------- +# Set up for GEOS +#--------------------------------------------------------------------------- +GEOSINCDIR = -I$(ISIS3OPT)/include/geos +GEOSLIBDIR = -L$(ISIS3OPT)/lib +GEOSLIB = -lgeos + +#--------------------------------------------------------------------------- +# Set up for the GNU Scientific Library (GSL). Note that this setup +# suppports include patterns such as . With this +# format, any other include spec that points to the general include +# directory, such as GEOS, will suffice. Therefore, an explicit +# include directive is ommitted but provided as an empty reference +# in cases where it may be located elsewhere. This also goes for the +# library reference. +#--------------------------------------------------------------------------- +GSLINCDIR = -I$(ISIS3OPT)/include/gsl +GSLLIBDIR = -L$(ISIS3OPT)/lib +GSLLIB = -lgsl -lgslcblas + +#--------------------------------------------------------------------------- +# Set up for GMM +#--------------------------------------------------------------------------- +GMMINCDIR = -I$(ISIS3LOCAL)/include +GMMLIBDIR = +GMMLIB = + +#--------------------------------------------------------------------------- +# Set up for SuperLU +#--------------------------------------------------------------------------- +SUPERLUINCDIR = -I$(ISIS3LOCAL)/include/superlu +SUPERLULIBDIR = -L$(ISIS3LOCAL)/lib +ifeq ($(HOST_PROC), powerpc) +# Powerpc support + SUPERLULIB = -lsuperlu_3.0 -framework vecLib +else +# Assumes Intel Mac + SUPERLULIB = -lsuperlu_3.0 -lblas +endif + +#--------------------------------------------------------------------------- +# Set up for Google Protocol Buffers (ProtoBuf) +#--------------------------------------------------------------------------- +PROTOBUFINCDIR = -I$(ISIS3OPT)/include/google +PROTOBUFLIBDIR = -L$(ISIS3OPT)/lib +PROTOBUFLIB = -lprotobuf + +#--------------------------------------------------------------------------- +# Set up for kakadu +# The Kakadu library is proprietary. The source files cannot be distributed +# with ISIS3. If you need to rebuild ISIS3 on your system, then you will +# need to modify the lines below that pertain to the location of the +# header files and library on your system. The compilation flag, ENABLEJP2K, +# should be set to true if you are building with the Kakadu library and +# you want to use the JPEG2000 specific code in the ISIS3 system. Otherwise, +# set the ENABLEJP2K flag to false. +#--------------------------------------------------------------------------- +KAKADUINCDIR = -I$(ISIS3LOCAL)/include/kakadu/v6_3-00967N +KAKADULIBDIR = -L$(ISIS3LOCAL)/lib +KAKADULIB = -lkdu_a63R +ISISCPPFLAGS += -DENABLEJP2K=1 + + +#--------------------------------------------------------------------------- +# Set up for Boost Library +#--------------------------------------------------------------------------- +BOOSTINCDIR = -I$(ISIS3OPT)/include +BOOSTLIBDIR = -L$(ISIS3OPT)/lib +BOOSTLIB = + +#--------------------------------------------------------------------------- +# Define the third party distribution libraries (patterns) +#--------------------------------------------------------------------------- + +# Libraries +THIRDPARTYLIBS += "$(QTDIR)/libexec/qt4-mac/lib/QtXmlPatterns.framework" +THIRDPARTYLIBS += "$(QTDIR)/libexec/qt4-mac/lib/QtXml.framework" +THIRDPARTYLIBS += "$(QTDIR)/libexec/qt4-mac/lib/QtNetwork.framework" +THIRDPARTYLIBS += "$(QTDIR)/libexec/qt4-mac/lib/QtSql.framework" +THIRDPARTYLIBS += "$(QTDIR)/libexec/qt4-mac/lib/QtGui.framework" +THIRDPARTYLIBS += "$(QTDIR)/libexec/qt4-mac/lib/QtCore.framework" +THIRDPARTYLIBS += "$(QTDIR)/libexec/qt4-mac/lib/QtSvg.framework" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libqwt.*dylib" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libcspice*.dylib" +#THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libsuperlu_3.0.dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libprotobuf*.dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libiconv*.dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libxerces-c*.dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libgsl*.dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libz*.dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libssl*.dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libcrypto*.dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libpng12.*dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libpng.dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libtiff.*dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libjpeg.*dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libmng.*dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/liblcms.*dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libgeos*.dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/libsqlite3.*dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/postgresql*/libpq.*dylib" +THIRDPARTYLIBS += "$(ISIS3OPT)/lib/mysql5/mysql/libmysqlclient_r*.dylib" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libkdu_a63R.dylib" + +# Plugins +THIRDPARTYPLUGINS += "$(ISIS3OPT)/libexec/qt4-mac/plugins/" + diff --git a/isis/make/config.linux b/isis/make/config.linux new file mode 100644 index 0000000000000000000000000000000000000000..58a4668fe8b88eda3e57bfec1769be8228e42ac1 --- /dev/null +++ b/isis/make/config.linux @@ -0,0 +1,25 @@ +#--------------------------------------------------------------------------- +# Determine Linux Architecture. Ensure the host architecture is set +# and then determine machine type +#--------------------------------------------------------------------------- +HOST_ARCH ?= $(shell uname -s) +HOST_MACH := $(shell uname -m) +NODE_NAME := $(shell uname -n) + +# This allows us to continue building on Suse 9 systems. It makes some +# assumptions. See the file $ISISROOT/make/config.linux-Suse9. +ifeq ($(VENDOR),suse) + VERSION := $(basename $(shell fgrep -h -w VERSION /etc/SuSE-release | cut -d ' ' -f 3) ) +endif + +ifeq ($(HOST_ARCH),Linux) + ifeq ($(HOST_MACH),x86_64) + include $(ISISROOT)/make/config.linux-x86_64 + else + ifneq ($(VERSION),9) + include $(ISISROOT)/make/config.linux-x86_32 + else + include $(ISISROOT)/make/config.linux-Suse9 + endif + endif +endif diff --git a/isis/make/config.linux-RedHat b/isis/make/config.linux-RedHat new file mode 100644 index 0000000000000000000000000000000000000000..a33e3692d686a2712e0969fe19c871aed47a6d2b --- /dev/null +++ b/isis/make/config.linux-RedHat @@ -0,0 +1,194 @@ +#--------------------------------------------------------------------------- +# Compiler options +#--------------------------------------------------------------------------- +CXX = g++ +CC = gcc +ISISCPPFLAGS = -Wall +ISISCPPFLAGS += -ansi +ISISCPPFLAGS += -DISIS_LITTLE_ENDIAN=1 +ISISCPPFLAGS += -fPIC +ISISCPPFLAGS += -DGMM_USES_SUPERLU + +ifeq ($(findstring DEBUG, $(MODE)),DEBUG) + ISISCPPFLAGS += -g + ISISCPPFLAGS += -O0 + ISISCPPFLAGS += -DCWDEBUG -DLIBCWD_THREAD_SAFE -D_REENTRANT + + ifeq ($(findstring NOMEMCHECK, $(MODE)),NOMEMCHECK) + ISISCPPFLAGS += -DNOMEMCHECK + endif +else + ISISCPPFLAGS += -O1 +endif + +ISISCFLAGS = + +#--------------------------------------------------------------------------- +# Linker options +#--------------------------------------------------------------------------- +RANLIB = /bin/true +SHAREDLIBEXT = so + +ISISLDFLAGS = -Wl,-E -Xlinker '-z' -Xlinker 'origin' +ISISLDFLAGS += -Xlinker "-rpath" -Xlinker "${ISISROOT}/lib:${ISISROOT}/3rdParty/lib" +ISISSYSLIBS = +ISISSTATIC = -Wl,-Bstatic +ISISDYNAMIC = -Wl,-Bdynamic + +ifeq ($(findstring DEBUG, $(MODE)),DEBUG) + ISISSYSLIBS += -lcwd_r -pthread +endif + +#--------------------------------------------------------------------------- +# Shared library options +#--------------------------------------------------------------------------- +ISISSHAREDFLAGS = $(ISISLDFLAGS) -shared +ISISSHAREDON = -Wl,-whole-archive +ISISSHAREDOFF = -Wl,-no-whole-archive +ISISARFLAGS = + +#--------------------------------------------------------------------------- +# Set up local library designations +#--------------------------------------------------------------------------- +ISIS3SYSINC ?= /usr/include +ISIS3SYSLIB ?= /usr/lib64 +ISIS3LOCAL ?= /usgs/pkgs/local/isis$(ISISVERSION) + +#--------------------------------------------------------------------------- +# Set up for cwd +#--------------------------------------------------------------------------- +CWDINCDIR = -I$(ISIS3LOCAL)/include/libcwd +CWDLIBDIR = -L$(ISIS3LOCAL)/lib +CWDLIB = -lcwd_r + +#--------------------------------------------------------------------------- +# Set up for Qt +#--------------------------------------------------------------------------- + +QTINCDIR = -I$(ISIS3LOCAL)/include/qt/qt4.5.0 +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.5.0/Qt +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.5.0/QtCore +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.5.0/QtAssistant +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.5.0/QtGui +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.5.0/QtNetwork +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.5.0/QtScript +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.5.0/QtSql +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.5.0/QtSvg +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.5.0/QtWebKit +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.5.0/QtXml +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.5.0/QtXmlPatterns +QTLIBDIR = -L$(ISIS3LOCAL)/lib +QTLIB = -lQtXmlPatterns -lQtXml -lQtNetwork -lQtSql -lQtGui -lQtCore + +MOC = $(ISIS3LOCAL)/bin/moc +UIC = $(ISIS3LOCAL)/bin/uic +PATCHELF = $(ISIS3LOCAL)/bin/patchelf + +#--------------------------------------------------------------------------- +# Set up for Qwt +#--------------------------------------------------------------------------- +QWTINCDIR = -I$(ISIS3LOCAL)/include +QWTLIBDIR = -L$(ISIS3LOCAL)/lib +QWTLIB = -lqwt + +#--------------------------------------------------------------------------- +# Set up for Xerces +#--------------------------------------------------------------------------- +XERCESINCDIR = -I$(ISIS3SYSINC) +XERCESLIBDIR = -L$(ISIS3SYSLIB) +XERCESLIB = -lxerces-c + +#--------------------------------------------------------------------------- +# Set up for naif +#--------------------------------------------------------------------------- +NAIFINCDIR = -I$(ISIS3LOCAL)/include/naif +NAIFLIBDIR = -L$(ISIS3LOCAL)/lib +NAIFLIB = -lcspice + +#--------------------------------------------------------------------------- +# Set up for TNT +#--------------------------------------------------------------------------- +TNTINCDIR = -I$(ISIS3LOCAL)/include/tnt +TNTLIBDIR = +TNTLIB = + +#--------------------------------------------------------------------------- +# Set up for JAMA +#--------------------------------------------------------------------------- +JAMAINCDIR = -I$(ISIS3LOCAL)/include +JAMALIBDIR = +JAMALIB = + +#--------------------------------------------------------------------------- +# Set up for GEOS +#--------------------------------------------------------------------------- +GEOSINCDIR = -I$(ISIS3LOCAL)/include/geos/geos3.0.0 +GEOSLIBDIR = -L$(ISIS3LOCAL)/lib +GEOSLIB = -lgeos-3.1.0 + +#--------------------------------------------------------------------------- +# Set up for the GNU Scientific Library (GSL). Note that this setup +# suppports include patterns such as . With this +# format, any other include spec that points to the general include +# directory, such as GEOS, will suffice. Therefore, an explicit +# include directive is ommitted but provided as an empty reference +# in cases where it may be located elsewhere. This also goes for the +# library reference. +#--------------------------------------------------------------------------- +GSLINCDIR = +GSLLIBDIR = +GSLLIB = -lgsl -lgslcblas + +#--------------------------------------------------------------------------- +# Set up for GMM +#--------------------------------------------------------------------------- +GMMINCDIR = -I$(ISIS3LOCAL)/include +GMMLIBDIR = +GMMLIB = + +#--------------------------------------------------------------------------- +# Set up for SuperLU +#--------------------------------------------------------------------------- +SUPERLUINCDIR = -I$(ISIS3LOCAL)/include/superlu +SUPERLULIBDIR = -L$(ISIS3LOCAL)/lib +SUPERLULIB = -lsuperlu_3.0 -lblas -lgfortran + +#--------------------------------------------------------------------------- +# Set up for Google Protocol Buffers (ProtoBuf) +#--------------------------------------------------------------------------- +PROTOBUFINCDIR = -I$(ISIS3LOCAL)/include/google-protobuf/protobuf2.1.0 +PROTOBUFLIBDIR = -L$(ISIS3LOCAL)/lib +PROTOBUFLIB = -lprotobuf + +#--------------------------------------------------------------------------- +# Define the third party distribution libraries (patterns) +#--------------------------------------------------------------------------- + +# Libraries +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtXmlPatterns.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtXml.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtNetwork.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtSql.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtGui.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtCore.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libqwt.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libxerces-c.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libXercesMessages.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libgsl*.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libgeos-*.so" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libcspice.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libprotobuf.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libsuperlu_3.0.a" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libblas.so.*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libgfortran.so*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libicuuc.so*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libicudata.so*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libpq.so*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/mysql/libmysqlclient_r.so*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libssl.so*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libcrypto.so*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libreadline.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libcwd_r.so*" + +# Plugins +THIRDPARTYPLUGINS += "$(ISIS3LOCAL)/plugins/" diff --git a/isis/make/config.linux-Suse9 b/isis/make/config.linux-Suse9 new file mode 100644 index 0000000000000000000000000000000000000000..806b95d22a0c5969cecd0343f6aeebca4f3c0971 --- /dev/null +++ b/isis/make/config.linux-Suse9 @@ -0,0 +1,127 @@ +#--------------------------------------------------------------------------- +# Compiler options +#--------------------------------------------------------------------------- +CXX = g++ +CC = gcc +ISISCPPFLAGS = -Wall +ISISCPPFLAGS += -ansi +ISISCPPFLAGS += -DISIS_LITTLE_ENDIAN=1 +ISISCPPFLAGS += -fPIC + +ifeq ($(findstring DEBUG, $(MODE)),DEBUG) + ISISCPPFLAGS += -g + ISISCPPFLAGS += -O0 +# ISISCPPFLAGS += -DCWDEBUG +else + ISISCPPFLAGS += -O1 +endif + +ISISCFLAGS = + +#--------------------------------------------------------------------------- +# Linker options +#--------------------------------------------------------------------------- +RANLIB = /bin/true +SHAREDLIBEXT = so + +ISISLDFLAGS = -Wl,-E +ISISSYSLIBS = +ISISSTATIC = -Wl,-Bstatic +ISISDYNAMIC = -Wl,-Bdynamic + +#ifeq ($(findstring DEBUG, $(MODE)),DEBUG) +# ISISSYSLIBS += -lcwd_r +#endif + +#--------------------------------------------------------------------------- +# Shared library options +#--------------------------------------------------------------------------- +ISISSHAREDFLAGS = $(ISISLDFLAGS) -shared +ISISSHAREDON = -Wl,-whole-archive +ISISSHAREDOFF = -Wl,-no-whole-archive +ISISARFLAGS = + +#--------------------------------------------------------------------------- +# Set up local library designations +#--------------------------------------------------------------------------- +ISIS3SYSINC ?= /usgs/pkgs/local/isis$(ISISVERSION)/include +ISIS3SYSLIB ?= /usgs/pkgs/local/isis$(ISISVERSION)/lib +ISIS3LOCAL ?= /usgs/pkgs/local/isis$(ISISVERSION) + +#--------------------------------------------------------------------------- +# Set up for cwd +#--------------------------------------------------------------------------- +CWDINCDIR = +CWDLIBDIR = +CWDLIB = + +#--------------------------------------------------------------------------- +# Set up for Qt +#--------------------------------------------------------------------------- +QTINCDIR = -I$(ISIS3SYSINC)/Qt +QTLIBDIR = -L$(ISIS3SYSLIB) +QTLIB = -lQtNetwork -lQtSql -lQtGui -lQtCore + +#--------------------------------------------------------------------------- +# Set up for Qwt +#--------------------------------------------------------------------------- +QWTINCDIR = -I$(ISIS3LOCAL)/include/qwt +QWTLIBDIR = -L$(ISIS3LOCAL)/lib +QWTLIB = -lqwt + +#--------------------------------------------------------------------------- +# Set up for Xerces +#--------------------------------------------------------------------------- +XERCESINCDIR = -I$(ISIS3SYSINC) +XERCESLIBDIR = -L$(ISIS3SYSLIB) +XERCESLIB = -lxerces-c + +#--------------------------------------------------------------------------- +# Set up for naif +#--------------------------------------------------------------------------- +NAIFINCDIR = -I$(ISIS3LOCAL)/include/naif +NAIFLIBDIR = -L$(ISIS3LOCAL)/lib +NAIFLIB = -lcspice + +#--------------------------------------------------------------------------- +# Set up for TNT +#--------------------------------------------------------------------------- +TNTINCDIR = -I$(ISIS3LOCAL)/include/tnt +TNTLIBDIR = +TNTLIB = + +#--------------------------------------------------------------------------- +# Set up for JAMA +#--------------------------------------------------------------------------- +JAMAINCDIR = -I$(ISIS3LOCAL)/include/jama +JAMALIBDIR = +JAMALIB = +#--------------------------------------------------------------------------- +# Set up for GEOS +#--------------------------------------------------------------------------- +GEOSINCDIR = -I$(ISIS3LOCAL)/include +GEOSLIBDIR = -L$(ISIS3LOCAL)/lib +GEOSLIB = -lgeos + +#--------------------------------------------------------------------------- +# Set up for the GNU Scientific Library (GSL). Note that this setup +# suppports include patterns such as . With this +# format, any other include spec that points to the general include +# directory, such as GEOS, will suffice. Therefore, an explicit +# include directive is ommitted but provided as an empty reference +# in cases where it may be located elsewhere. This also goes for the +# library reference. +#--------------------------------------------------------------------------- +GSLINCDIR = +GSLLIBDIR = +GSLLIB = -lgsl -lgslcblas + +#--------------------------------------------------------------------------- +# Define the third party distribution libraries (patterns) +#--------------------------------------------------------------------------- + +# Libraries +THIRDPARTYLIBS = + +# Plugins +THIRDPARTYPLUGINS = diff --git a/isis/make/config.linux-x86_32 b/isis/make/config.linux-x86_32 new file mode 100644 index 0000000000000000000000000000000000000000..fd371d70038fb211210abbc6c897d27da7573be9 --- /dev/null +++ b/isis/make/config.linux-x86_32 @@ -0,0 +1,231 @@ +#--------------------------------------------------------------------------- +# Compiler options +#--------------------------------------------------------------------------- +CXX = g++ +CC = gcc +ISISCPPFLAGS = -Wall +ISISCPPFLAGS += -ansi +ISISCPPFLAGS += -DISIS_LITTLE_ENDIAN=1 +ISISCPPFLAGS += -fPIC +ISISCPPFLAGS += -DGMM_USES_SUPERLU + +ifeq ($(findstring DEBUG, $(MODE)),DEBUG) + ISISCPPFLAGS += -g + ISISCPPFLAGS += -O0 + ISISCPPFLAGS += -DCWDEBUG -DLIBCWD_THREAD_SAFE -D_REENTRANT + + ifeq ($(findstring NOMEMCHECK, $(MODE)),NOMEMCHECK) + ISISCPPFLAGS += -DNOMEMCHECK + endif +else + ISISCPPFLAGS += -O1 +endif + +ISISCFLAGS = + +#--------------------------------------------------------------------------- +# Linker options +#--------------------------------------------------------------------------- +RANLIB = /bin/true +SHAREDLIBEXT = so + +ISISLDFLAGS = -Wl,-E -Xlinker '-z' -Xlinker 'origin' +ISISLDFLAGS += -Xlinker "-rpath" -Xlinker "${ISISROOT}/lib:${ISISROOT}/3rdParty/lib" +ISISSYSLIBS = +ISISSTATIC = -Wl,-Bstatic +ISISDYNAMIC = -Wl,-Bdynamic + +ifeq ($(findstring DEBUG, $(MODE)),DEBUG) + ISISSYSLIBS += -lcwd_r -pthread +endif + +#--------------------------------------------------------------------------- +# Shared library options +#--------------------------------------------------------------------------- +ISISSHAREDFLAGS = $(ISISLDFLAGS) -shared +ISISSHAREDON = -Wl,-whole-archive +ISISSHAREDOFF = -Wl,-no-whole-archive +ISISARFLAGS = + +#--------------------------------------------------------------------------- +# Set up local library designations +#--------------------------------------------------------------------------- +ISIS3SYSINC ?= /usr/include +ISIS3SYSLIB ?= /usr/lib +ISIS3LOCAL ?= /usgs/pkgs/local/isis$(ISISVERSION) + +#--------------------------------------------------------------------------- +# Set up for cwd +#--------------------------------------------------------------------------- +CWDINCDIR = -I$(ISIS3LOCAL)/include/libcwd/libcwd1.0.3 +CWDLIBDIR = -L$(ISIS3LOCAL)/lib +CWDLIB = -lcwd_r + + +#--------------------------------------------------------------------------- +# Set up for Qt +#--------------------------------------------------------------------------- +QTINCDIR = -I$(ISIS3LOCAL)/include/qt/qt4.6.2 +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/Qt +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtCore +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtAssistant +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtGui +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtNetwork +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtScript +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtScriptTools +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtSql +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtSvg +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtWebKit +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtXml +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtXmlPatterns +QTLIBDIR = -L$(ISIS3LOCAL)/lib +QTLIB = -lQtXmlPatterns -lQtXml -lQtNetwork -lQtSql -lQtGui -lQtCore -lQtSvg + +UIC = $(ISIS3LOCAL)/bin/uic +MOC = $(ISIS3LOCAL)/bin/moc +RCC = $(ISIS3LOCAL)/bin/rcc +PATCHELF = $(ISIS3LOCAL)/bin/patchelf + +#--------------------------------------------------------------------------- +# Set up for Qwt +#--------------------------------------------------------------------------- +QWTINCDIR = -I$(ISIS3LOCAL)/include/qwt/qwt5.2.0/qwt +QWTLIBDIR = -L$(ISIS3LOCAL)/lib +QWTLIB = -lqwt + +#--------------------------------------------------------------------------- +# Set up for Xerces +#--------------------------------------------------------------------------- +XERCESINCDIR = -I$(ISIS3SYSINC) +XERCESLIBDIR = -L$(ISIS3SYSLIB) +XERCESLIB = -lxerces-c + +#--------------------------------------------------------------------------- +# Set up for naif +#--------------------------------------------------------------------------- +NAIFINCDIR = -I$(ISIS3LOCAL)/include/naif/cspice63 +NAIFLIBDIR = -L$(ISIS3LOCAL)/lib +NAIFLIB = -lcspice + +#--------------------------------------------------------------------------- +# Set up for TNT +#--------------------------------------------------------------------------- +TNTINCDIR = -I$(ISIS3LOCAL)/include/tnt/tnt126 +TNTLIBDIR = +TNTLIB = + +#--------------------------------------------------------------------------- +# Set up for JAMA +#--------------------------------------------------------------------------- +JAMAINCDIR = -I$(ISIS3LOCAL)/include/jama/jama125 +JAMALIBDIR = +JAMALIB = + +#--------------------------------------------------------------------------- +# Set up for GEOS +#--------------------------------------------------------------------------- +GEOSINCDIR = -I$(ISIS3LOCAL)/include/geos/geos3.2.0 +GEOSLIBDIR = -L$(ISIS3LOCAL)/lib +GEOSLIB = -lgeos-3.2.0 + +#--------------------------------------------------------------------------- +# Set up for the GNU Scientific Library (GSL). Note that this setup +# suppports include patterns such as . With this +# format, any other include spec that points to the general include +# directory, such as GEOS, will suffice. Therefore, an explicit +# include directive is ommitted but provided as an empty reference +# in cases where it may be located elsewhere. This also goes for the +# library reference. +#--------------------------------------------------------------------------- +GSLINCDIR = +GSLLIBDIR = +GSLLIB = -lgsl -lgslcblas + +#--------------------------------------------------------------------------- +# Set up for GMM +#--------------------------------------------------------------------------- +GMMINCDIR = -I$(ISIS3LOCAL)/include/gmm/gmm3.0.0 +GMMLIBDIR = +GMMLIB = + +#--------------------------------------------------------------------------- +# Set up for SuperLU +#--------------------------------------------------------------------------- +SUPERLUINCDIR = -I$(ISIS3LOCAL)/include/superlu/superlu3.0 +SUPERLULIBDIR = -L$(ISIS3LOCAL)/lib +SUPERLULIB = -lsuperlu_3.0 -lblas -lgfortran + + +#--------------------------------------------------------------------------- +# Set up for Google Protocol Buffers (ProtoBuf) +#--------------------------------------------------------------------------- +PROTOBUFINCDIR = -I$(ISIS3LOCAL)/include/google-protobuf/protobuf2.1.0 +PROTOBUFLIBDIR = -L$(ISIS3LOCAL)/lib +PROTOBUFLIB = -lprotobuf + + +#--------------------------------------------------------------------------- +# Set up for kakadu +# The Kakadu library is proprietary. The source files cannot be distributed +# with ISIS3. If you need to rebuild ISIS3 on your system, then you will +# need to modify the lines below that pertain to the location of the +# header files and library on your system. The compilation flag, ENABLEJP2K, +# should be set to true if you are building with the Kakadu library and +# you want to use the JPEG2000 specific code in the ISIS3 system. Otherwise, +# set the ENABLEJP2K flag to false. +#--------------------------------------------------------------------------- +KAKADUINCDIR = -I$(ISIS3LOCAL)/include/kakadu/v6_3-00967N +KAKADULIBDIR = -L$(ISIS3LOCAL)/lib +KAKADULIB = -lkdu_a63R +ISISCPPFLAGS += -DENABLEJP2K=1 + + +#--------------------------------------------------------------------------- +# Set up for BOOST +#--------------------------------------------------------------------------- +BOOSTINCDIR = -I$(ISIS3LOCAL)/include/boost/boost1.41.0 +BOOSTLIBDIR = +BOOSTLIB = +#BOOSTLIBDIR = -L$(ISIS3LOCAL)/lib +#BOOSTLIB = -lboost_date_time -lboost_filesystem -lboost_graph -lboost_math_c99f \ +# -lboost_math_c99l -lboost_math_c99 -lboost_math_tr1f -lboost_math_tr1l \ +# -lboost_math_tr1 -lboost_prg_exec_monitor -lboost_program_options \ +# -lboost_regex -lboost_serialization -lboost_signals -lboost_system \ +# -lboost_thread -lboost_unit_test_framework -lboost_wave -lboost_wserialization + + +#--------------------------------------------------------------------------- +# Define the third party distribution libraries (patterns) +#--------------------------------------------------------------------------- + +# Libraries +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtXmlPatterns.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtXml.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtNetwork.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtSql.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtGui.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtCore.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtSvg.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libqwt.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libprotobuf.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libgeos-*.so" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libcspice.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libsuperlu_3.0.a" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libcwd_r.so*" + +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libblas.so.*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libgfortran.so.*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libxerces-c.so*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libgsl*.so*" +#THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libicuuc.so*" +#THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libicudata.so*" +#THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libpq.so*" +#THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libmysqlclient_r.so*" +#THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libssl.so*" +#THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libcrypto.so*" +#THIRDPARTYLIBS += "/lib/libreadline.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libkdu_a63R.so*" + + +# Plugins +THIRDPARTYPLUGINS += "$(ISIS3LOCAL)/plugins/" diff --git a/isis/make/config.linux-x86_64 b/isis/make/config.linux-x86_64 new file mode 100644 index 0000000000000000000000000000000000000000..43105609f329d0b3fb5ae022e7f5ce2d5e5236d9 --- /dev/null +++ b/isis/make/config.linux-x86_64 @@ -0,0 +1,226 @@ +#--------------------------------------------------------------------------- +# Compiler options +#--------------------------------------------------------------------------- +CXX = g++ +CC = gcc +ISISCPPFLAGS = -Wall +ISISCPPFLAGS += -ansi +ISISCPPFLAGS += -DISIS_LITTLE_ENDIAN=1 +ISISCPPFLAGS += -fPIC +ISISCPPFLAGS += -DGMM_USES_SUPERLU + +ifeq ($(findstring DEBUG, $(MODE)),DEBUG) + ISISCPPFLAGS += -g + ISISCPPFLAGS += -O0 + ISISCPPFLAGS += -DCWDEBUG -DLIBCWD_THREAD_SAFE -D_REENTRANT + + ifeq ($(findstring NOMEMCHECK, $(MODE)),NOMEMCHECK) + ISISCPPFLAGS += -DNOMEMCHECK + endif +else + ISISCPPFLAGS += -O1 +endif + +ISISCFLAGS = + +#--------------------------------------------------------------------------- +# Linker options +#--------------------------------------------------------------------------- +RANLIB = /bin/true +SHAREDLIBEXT = so + +ISISLDFLAGS = -Wl,-E -Xlinker '-z' -Xlinker 'origin' +ISISLDFLAGS += -Xlinker "-rpath" -Xlinker "${ISISROOT}/lib:${ISISROOT}/3rdParty/lib" +ISISSYSLIBS = +ISISSTATIC = -Wl,-Bstatic +ISISDYNAMIC = -Wl,-Bdynamic + +ifeq ($(findstring DEBUG, $(MODE)),DEBUG) + ISISSYSLIBS += -lcwd_r -pthread +endif + +#--------------------------------------------------------------------------- +# Shared library options +#--------------------------------------------------------------------------- +ISISSHAREDFLAGS = $(ISISLDFLAGS) -shared +ISISSHAREDON = -Wl,-whole-archive +ISISSHAREDOFF = -Wl,-no-whole-archive +ISISARFLAGS = + +#--------------------------------------------------------------------------- +# Set up local library designations +#--------------------------------------------------------------------------- +ISIS3SYSINC ?= /usr/include +ISIS3SYSLIB ?= /usr/lib64 +ISIS3LOCAL ?= /usgs/pkgs/local/isis$(ISISVERSION) + +#--------------------------------------------------------------------------- +# Set up for cwd +#--------------------------------------------------------------------------- +CWDINCDIR = -I$(ISIS3LOCAL)/include/libcwd/libcwd1.0.3 +CWDLIBDIR = -L$(ISIS3LOCAL)/lib +CWDLIB = -lcwd_r + +#--------------------------------------------------------------------------- +# Set up for Qt +#--------------------------------------------------------------------------- +QTINCDIR = -I$(ISIS3LOCAL)/include/qt/qt4.6.2 +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/Qt +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtCore +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtAssistant +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtGui +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtNetwork +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtScript +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtScriptTools +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtSql +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtSvg +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtWebKit +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtXml +QTINCDIR += -I$(ISIS3LOCAL)/include/qt/qt4.6.2/QtXmlPatterns +QTLIBDIR = -L$(ISIS3LOCAL)/lib +QTLIB = -lQtXmlPatterns -lQtXml -lQtNetwork -lQtSql -lQtGui -lQtCore -lQtSvg + +UIC = $(ISIS3LOCAL)/bin/uic +MOC = $(ISIS3LOCAL)/bin/moc +RCC = $(ISIS3LOCAL)/bin/rcc +PATCHELF = $(ISIS3LOCAL)/bin/patchelf + +#--------------------------------------------------------------------------- +# Set up for Qwt +#--------------------------------------------------------------------------- +QWTINCDIR = -I$(ISIS3LOCAL)/include/qwt/qwt5.2.0 +QWTLIBDIR = -L$(ISIS3LOCAL)/lib +QWTLIB = -lqwt + +#--------------------------------------------------------------------------- +# Set up for Xerces +#--------------------------------------------------------------------------- +XERCESINCDIR = -I$(ISIS3SYSINC) +XERCESLIBDIR = -L$(ISIS3SYSLIB) +XERCESLIB = -lxerces-c + +#--------------------------------------------------------------------------- +# Set up for naif +#--------------------------------------------------------------------------- +NAIFINCDIR = -I$(ISIS3LOCAL)/include/naif/cspice63 +NAIFLIBDIR = -L$(ISIS3LOCAL)/lib +NAIFLIB = -lcspice + +#--------------------------------------------------------------------------- +# Set up for TNT +#--------------------------------------------------------------------------- +TNTINCDIR = -I$(ISIS3LOCAL)/include/tnt/tnt126 -I$(ISIS3LOCAL)/include/tnt/tnt126/tnt +TNTLIBDIR = +TNTLIB = + +#--------------------------------------------------------------------------- +# Set up for JAMA +#--------------------------------------------------------------------------- +JAMAINCDIR = -I$(ISIS3LOCAL)/include/jama/jama125 +JAMALIBDIR = +JAMALIB = + +#--------------------------------------------------------------------------- +# Set up for GEOS +#--------------------------------------------------------------------------- +GEOSINCDIR = -I$(ISIS3LOCAL)/include/geos/geos3.2.0 +GEOSLIBDIR = -L$(ISIS3LOCAL)/lib +GEOSLIB = -lgeos-3.2.0 + +#--------------------------------------------------------------------------- +# Set up for the GNU Scientific Library (GSL). Note that this setup +# suppports include patterns such as . With this +# format, any other include spec that points to the general include +# directory, such as GEOS, will suffice. Therefore, an explicit +# include directive is ommitted but provided as an empty reference +# in cases where it may be located elsewhere. This also goes for the +# library reference. +#--------------------------------------------------------------------------- +GSLINCDIR = +GSLLIBDIR = +GSLLIB = -lgsl -lgslcblas + +#--------------------------------------------------------------------------- +# Set up for GMM +#--------------------------------------------------------------------------- +GMMINCDIR = -I$(ISIS3LOCAL)/include/gmm/gmm3.0.0 +GMMLIBDIR = +GMMLIB = + +#--------------------------------------------------------------------------- +# Set up for SuperLU +#--------------------------------------------------------------------------- +SUPERLUINCDIR = -I$(ISIS3LOCAL)/include/superlu/superlu3.0 +SUPERLULIBDIR = -L$(ISIS3LOCAL)/lib +SUPERLULIB = -lsuperlu_3.0 -lblas -lgfortran + +#--------------------------------------------------------------------------- +# Set up for Google Protocol Buffers (ProtoBuf) +#--------------------------------------------------------------------------- +PROTOBUFINCDIR = -I$(ISIS3LOCAL)/include/google-protobuf/protobuf2.1.0 +PROTOBUFLIBDIR = -L$(ISIS3LOCAL)/lib +PROTOBUFLIB = -lprotobuf + +#--------------------------------------------------------------------------- +# Set up for kakadu +# The Kakadu library is proprietary. The source files cannot be distributed +# with ISIS3. If you need to rebuild ISIS3 on your system, then you will +# need to modify the lines below that pertain to the location of the +# header files and library on your system. The compilation flag, ENABLEJP2K, +# should be set to true if you are building with the Kakadu library and +# you want to use the JPEG2000 specific code in the ISIS3 system. Otherwise, +# set the ENABLEJP2K flag to false. +#--------------------------------------------------------------------------- +KAKADUINCDIR = -I$(ISIS3LOCAL)/include/kakadu/v6_3-00967N +KAKADULIBDIR = -L$(ISIS3LOCAL)/lib +KAKADULIB = -lkdu_a63R +ISISCPPFLAGS += -DENABLEJP2K=1 + +#--------------------------------------------------------------------------- +# Set up for BOOST +#--------------------------------------------------------------------------- +BOOSTINCDIR = -I$(ISIS3LOCAL)/include/boost/boost1.41.0 +BOOSTLIBDIR = +BOOSTLIB = +#BOOSTLIBDIR = -L$(ISIS3LOCAL)/lib +#BOOSTLIB = -lboost_date_time -lboost_filesystem -lboost_graph -lboost_math_c99f \ +# -lboost_math_c99l -lboost_math_c99 -lboost_math_tr1f -lboost_math_tr1l \ +# -lboost_math_tr1 -lboost_prg_exec_monitor -lboost_program_options \ +# -lboost_regex -lboost_serialization -lboost_signals -lboost_system \ +# -lboost_thread -lboost_unit_test_framework -lboost_wave -lboost_wserialization + +#--------------------------------------------------------------------------- +# Define the third party distribution libraries (patterns) +#--------------------------------------------------------------------------- + +# Libraries +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtXmlPatterns.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtXml.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtNetwork.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtSql.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtGui.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtCore.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtSvg.so*[^g]" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libqwt.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libprotobuf.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libgeos-*.so" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libcspice.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libsuperlu_3.0.a" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libcwd_r.so*" + +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libblas.so.*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libgfortran.so*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libxerces-c.so*" +THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libgsl*.so*" +#THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libicuuc.so*" +#THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libicudata.so*" +#THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libpq.so*" +#THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libmysqlclient_r.so*" +#THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libssl.so*" +#THIRDPARTYLIBS += "$(ISIS3SYSLIB)/libcrypto.so*" +#THIRDPARTYLIBS += "/lib64/libreadline.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libkdu_a63R.so*" + + +# Plugins +THIRDPARTYPLUGINS += "$(ISIS3LOCAL)/plugins/" diff --git a/isis/make/config.solaris b/isis/make/config.solaris new file mode 100644 index 0000000000000000000000000000000000000000..8d618af30000f42c0a261bc64908919fd4d9ec8b --- /dev/null +++ b/isis/make/config.solaris @@ -0,0 +1,149 @@ +#--------------------------------------------------------------------------- +# Compiler options +#--------------------------------------------------------------------------- +CXX = g++ +CC = gcc +ISISCPPFLAGS = -Wall +ISISCPPFLAGS += -ansi +ISISCPPFLAGS += -DISIS_LITTLE_ENDIAN=0 +ISISCPPFLAGS += -fPIC +ISISCPPFLAGS += -m64 +ISISCPPFLAGS += -D_XOPEN_SOURCE=500 -D__EXTENSIONS__ +ISISCPPFLAGS += -D_LP64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE +#ISISCPPFLAGS += -M + +ifeq ($(findstring DEBUG, $(MODE)),DEBUG) + ISISCPPFLAGS += -g + ISISCPPFLAGS += -O0 +# ISISCPPFLAGS += -DCWDEBUG +else + ISISCPPFLAGS += -O1 +endif + +ISISCFLAGS = -m64 + +#--------------------------------------------------------------------------- +# Linker options +#--------------------------------------------------------------------------- +RANLIB = /bin/true +SHAREDLIBEXT = so + +ISISLDFLAGS = +ISISLDFLAGS = -Wl -m64 +ISISSYSLIBS = -lsocket -ldl +ISISSTATIC = -Wl,-Bstatic +ISISDYNAMIC = -Wl,-Bdynamic + +#ifeq ($(findstring DEBUG, $(MODE)),DEBUG) +# ISISLDFLAGS += -lcwd +#endif + +#--------------------------------------------------------------------------- +# Shared library options +#--------------------------------------------------------------------------- +ISISSHAREDFLAGS = $(ISISLDFLAGS) -shared +ISISSHAREDON = -Xlinker -z -Xlinker allextract +ISISSHAREDOFF = -Xlinker -z -Xlinker defaultextract +ISISARFLAGS = -c + +#--------------------------------------------------------------------------- +# Set up local library designations +#--------------------------------------------------------------------------- +ISIS3OPT ?= /opt/local +ISIS3LOCAL ?= /usgs/pkgs/local/isis$(ISISVERSION) + +#--------------------------------------------------------------------------- +# Set up for cwd +#--------------------------------------------------------------------------- +CWDINCDIR = +CWDLIBDIR = +CWDLIB = + +#--------------------------------------------------------------------------- +# Set up for Qwt +#--------------------------------------------------------------------------- +QWTINCDIR = -I$(ISIS3LOCAL)/include/qwt +QWTLIBDIR = -L$(ISIS3LOCAL)/lib +QWTLIB = -lqwt + +#--------------------------------------------------------------------------- +# Set up for Qt +#--------------------------------------------------------------------------- +QTINCDIR = -I$(ISIS3LOCAL)/include/Qt +QTLIBDIR = -L$(ISIS3LOCAL)/lib +QTLIB = -lQtXmlPatterns -lQtXml -lQtNetwork -lQtSql -lQtGui -lQtCore + +UIC = $(ISIS3LOCAL)/bin/uic +MOC = $(ISIS3LOCAL)/bin/moc + +#--------------------------------------------------------------------------- +# Set up for Xerces +#--------------------------------------------------------------------------- +XERCESINCDIR = -I$(ISIS3LOCAL)/include +XERCESLIBDIR = -L$(ISIS3LOCAL)/lib +XERCESLIB = -lxerces-c + +XALAN = $(ISIS3LOCAL)/bin/Xalan + +#--------------------------------------------------------------------------- +# Set up for naif +#--------------------------------------------------------------------------- +NAIFINCDIR = -I$(ISIS3LOCAL)/include/naif +NAIFLIBDIR = -L$(ISIS3LOCAL)/lib +NAIFLIB = -lcspice + +#--------------------------------------------------------------------------- +# Set up for TNT +#--------------------------------------------------------------------------- +TNTINCDIR = -I$(ISIS3LOCAL)/include/tnt +TNTLIBDIR = +TNTLIB = + +#--------------------------------------------------------------------------- +# Set up for JAMA +#--------------------------------------------------------------------------- +JAMAINCDIR = -I$(ISIS3LOCAL)/include/jama +JAMALIBDIR = +JAMALIB = +#--------------------------------------------------------------------------- +# Set up for GEOS +#--------------------------------------------------------------------------- +GEOSINCDIR = -I$(ISIS3LOCAL)/include/geos/geos3.0.0 +GEOSLIBDIR = -L$(ISIS3LOCAL)/lib +GEOSLIB = -lgeos-3.0.0 + +#--------------------------------------------------------------------------- +# Set up for the GNU Scientific Library (GSL). Note that this setup +# suppports include patterns such as . With this +# format, any other include spec that points to the general include +# directory, such as GEOS, will suffice. Therefore, an explicit +# include directive is ommitted but provided as an empty reference +# in cases where it may be located elsewhere. This also goes for the +# library reference. +#--------------------------------------------------------------------------- +GSLINCDIR = +GSLLIBDIR = +GSLLIB = -lgsl -lgslcblas + +#--------------------------------------------------------------------------- +# Define the third party distribution libraries (patterns) +#--------------------------------------------------------------------------- + +# Libraries +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtXmlPatterns.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtXml.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtNetwork.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtSql.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtGui.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libQtCore.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libqwt.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libxerces-c.so*" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libgeos-*.so" +THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libcspice.so*" +THIRDPARTYLIBS += "/usr/local/lib/sparcv9/libstdc++.so*" +THIRDPARTYLIBS += "/usr/local/lib/sparcv9/libgcc_s.so*" + +#THIRDPARTYLIBS += "$(ISIS3LOCAL)/lib/libgsl*.so*" + +# Plugins +THIRDPARTYPLUGINS += "$(ISIS3LOCAL)/plugins/" diff --git a/isis/make/isismake.apps b/isis/make/isismake.apps new file mode 100644 index 0000000000000000000000000000000000000000..05d2445dd8b502cf0ef4ccdcb5e5f0d7b248075e --- /dev/null +++ b/isis/make/isismake.apps @@ -0,0 +1,159 @@ +include $(ISISROOT)/make/isismake.macros + +MOCINC = $(wildcard *.h) +MOCGEN = $(wildcard moc_*.cpp) +PROTOS = $(wildcard *.proto) +PROTOSGEN = $(wildcard *.pb.*) +PROTOSOBJ = $(wildcard *.pb.o) + +.SUFFIXES: +.SUFFIXES: .cpp .o +.SUFFIXES: .c .o +.SUFFIXES: .xml .html +.SUFFIXES: .proto .pb.h .pb.cc +.SUFFIXES: .cc .o + +app: $(BINS) + +$(BINS): $(OBJS) + $(CXX) $(ALLLIBDIRS) $(ISISLDFLAGS) $(ISISLDRPATH) -o $@ $(OBJS) $(ALLLIBS) + +.cpp.o : qtmoc + $(CXX) $(ALLINCDIRS) $(ISISCPPFLAGS) $(CPPFLAGS) -c -o $@ $? + +.c.o : + $(CC) $(ALLINCDIRS) $(ISISCFLAGS) $(CFLAGS) -c -o $@ $? + +.cc.o: + $(CXX) $(ALLINCDIRS) $(ISISCPPFLAGS) -c -o $@ $? + +.xml.html : + $(XALAN) -v -o $@ $? $(ISISROOT)/src/docsys/Application/presentation/ProgTester/IsisApplicationDocStyle.xsl + +protos: $(PROTOS:%.proto=%.pb.h) $(PROTOS:%.proto=%.pb.cc) + +%.pb.cc %.pb.h: %.proto + protoc -I$( /dev/null; \ + if [ -f "DarwinErrors.lis" ]; then \ + cat DarwinErrors.lis; \ + fi; \ + $(RM) DarwinErrors.lis; \ + fi + + +validxml: + $(XALAN) -v -o /dev/null $(BINS).xml $(ISISROOT)/src/docsys/Application/presentation/ProgTester/IsisApplicationDocStyle.xsl; + +docs: + mkdir -p $(ISISROOT)/src/docsys/Application/data/`basename $(CURDIR)` + cp -p `basename $(CURDIR)`.xml $(ISISROOT)/src/docsys/Application/data/`basename $(CURDIR)` + if [ -d assets ]; \ + then \ + cp -pr assets $(ISISROOT)/src/docsys/Application/data/`basename $(CURDIR)`; \ + fi + chmod -R +w $(ISISROOT)/src/docsys/Application/data/`basename $(CURDIR)` + +test: + if [ ! -d "tsts" ]; \ + then \ + echo ""; \ + printf %-6s ""; \ + echo "no tsts folder"; \ + elif [ -f "tsts/Makefile" ]; \ + then \ + cd tsts; $(MAKE) test; \ + else \ + echo ""; \ + printf %-6s ""; \ + echo "no makefile"; \ + fi + +testdir: + if [ ! -d "tsts" ]; \ + then \ + $(MKDIR) tsts; \ + $(CP) $(ISISROOT)/make/Makefile.appstststree tsts/Makefile; \ + else \ + echo ""; \ + printf %-6s ""; \ + echo "tsts folder already exists"; \ + fi + +html: + $(MAKE) `basename $(CURDIR)`.html; + +help: + echo "Isis Make Application Commands" + echo "------------------------ " + echo "make : Builds the Application" + echo "make MODE=DEBUG[,NOMEMCHECK] : Builds the Application for stack tracing and " + echo " memory debugging" + echo "make install : Calls the make target and copies the application" + echo " to $ISISROOT/bin/" + echo "make html : Builds the html page for the Application" + echo "make docs : Copies the .xml and assets folder to docsys area" + echo " for full documentation building" + echo "make clean : Removes the application, *.html and *.o files." + echo " Also cleans the test directories" + echo "make sanitize : Calls the clean target then removes tttt* junk.*" + echo " and TEMP* files" + echo "make testdir : Make the test directory for new applications" + echo "make test : Run all app tests and print result, remove" + echo " output" + echo "make test MODE=NOCLEAN : Run test and print result, leave output" + diff --git a/isis/make/isismake.appstree b/isis/make/isismake.appstree new file mode 100644 index 0000000000000000000000000000000000000000..2d8b76056003da45038d3548f66ccce7d250034e --- /dev/null +++ b/isis/make/isismake.appstree @@ -0,0 +1,31 @@ +include $(ISISROOT)/make/isismake.macros + +DIRONLY = $(subst /,,$(shell ls -d */)) +CVS := CVS + +APPLICATIONS = $(filter-out $(CVS), $(DIRONLY)) + +applications: + for i in $(APPLICATIONS); do \ + echo " Building and installing [$$i] ("`date +%T`")"; \ + cd $$i; $(MAKE) install; cd ..; \ + done + +documentation: + for i in $(APPLICATIONS); do \ + echo " Installing application documentation [$$i]"; \ + cd $$i; $(MAKE) docs; cd ..; \ + done + + +clean: + for i in $(APPLICATIONS); do \ + echo " Cleaning [$$i]"; \ + cd $$i; $(MAKE) clean; cd ..; \ + done + +test: + for i in $(APPLICATIONS); do \ + printf %-46s " Testing [$$i]"; \ + cd $$i; $(MAKE) test; cd ..; \ + done diff --git a/isis/make/isismake.cat b/isis/make/isismake.cat new file mode 100644 index 0000000000000000000000000000000000000000..d469e44b60129e5bf2b0a5af1dda10cb6e95cfbb --- /dev/null +++ b/isis/make/isismake.cat @@ -0,0 +1,87 @@ +include $(ISISROOT)/make/isismake.macros + +OBJECTS = $(filter-out objs/Makefile objs/CVS, $(wildcard objs/*)) +APPS = $(filter-out apps/Makefile apps/CVS, $(wildcard apps/*)) +NOAPPS = "no apps" + +applications: + if [ "$(APPS)" != "" ]; \ + then \ + echo ""; \ + cd apps; $(MAKE) applications; \ + else \ + echo ""; \ + printf %-4s ""; \ + echo "$(NOAPPS)"; \ + fi + +api: + if [ "$(OBJECTS)" != "" ]; \ + then \ + cd objs; $(MAKE) api; \ + fi + +includes: + if [ "$(OBJECTS)" != "" ]; \ + then \ + cd objs; $(MAKE) includes; \ + fi + +objects: + if [ "$(OBJECTS)" != "" ]; \ + then \ + cd objs; $(MAKE) objects; \ + fi + +documentation: + if [ "$(APPS)" != "" ]; \ + then \ + echo ""; \ + cd apps; $(MAKE) documentation; \ + else \ + echo ""; \ + printf %-4s ""; \ + echo "$(NOAPPS)"; \ + fi + +clean: + if [ "$(OBJECTS)" != "" ]; \ + then \ + cd objs; $(MAKE) clean; \ + fi + + if [ "$(APPS)" != "" ]; \ + then \ + cd apps; $(MAKE) clean; \ + fi + +unitTest: + if [ "$(OBJECTS)" != "" ]; \ + then \ + cd objs; $(MAKE) test; \ + fi + +appTest: + if [ "$(APPS)" != "" ]; \ + then \ + echo ""; \ + cd apps; $(MAKE) test; \ + else \ + echo ""; \ + printf %-4s ""; \ + echo "$(NOAPPS)"; \ + fi + +catTest: + if [ ! -d "tsts" ]; \ + then \ + echo ""; \ + printf %-4s ""; \ + echo "no tsts folder"; \ + elif [ -f "tsts/Makefile" ]; \ + then \ + cd tsts; $(MAKE) test; \ + else \ + echo "no makefile"; \ + fi + diff --git a/isis/make/isismake.macros b/isis/make/isismake.macros new file mode 100644 index 0000000000000000000000000000000000000000..74fd33a8d407862a8dff517a7c2ccba5b598d8fc --- /dev/null +++ b/isis/make/isismake.macros @@ -0,0 +1,182 @@ +SHELL=bash + +#--------------------------------------------------------------------------- +# Check to see if the programmer wants make to be noisy +#--------------------------------------------------------------------------- +ifeq ($(findstring LOUD, $(MODE)),LOUD) +else +.SILENT: +endif + +#--------------------------------------------------------------------------- +# Get the machine type and setup its environment +#--------------------------------------------------------------------------- +HOST_ARCH := $(shell uname -s) +HOST_MACH := $(shell uname -m) +HOST_PROC := $(shell uname -p) + +empty:= +space:=$(empty) $(empty) + +ifeq ($(findstring $(space),$(HOST_PROC)),$(space)) + HOST_PROC = unknown +endif + +ifeq ($(HOST_ARCH),SunOS) + include $(ISISROOT)/make/config.solaris +endif + +ifeq ($(HOST_ARCH),Linux) + include $(ISISROOT)/make/config.linux +endif + +ifeq ($(HOST_ARCH),Darwin) + include $(ISISROOT)/make/config.darwin +endif + +ifndef ISISCPPFLAGS + $(error Unsupported platform, can not make for $(HOST_ARCH)) +endif + +#--------------------------------------------------------------------------- +# Set up some basic commands +#--------------------------------------------------------------------------- +CXX ?= g++ +CC ?= gcc +LDSHARED ?= $(CXX) +MOC ?= moc +UIC ?= uic +XALAN ?= Xalan +LS ?= /bin/ls +RM ?= /bin/rm -f +CP ?= /bin/cp +LN ?= ln -s +CAT ?= /bin/cat +RANLIB ?= /usr/bin/true +MACHINE ?= uname +DIFF ?= /usr/bin/diff +GREP ?= grep +EVAL ?= eval +WHICH ?= which +DD ?= dd +MKDIR ?= mkdir -p +RMDIR ?= rmdir -p +MV ?= mv +RSYNC ?= rsync +SED ?= sed +DATE ?= /bin/date +PRINTF ?= /usr/bin/printf +ECHO ?= /bin/echo +CUT ?= /usr/bin/cut +PATCHELF ?= patchelf + +# Third party library/plugin install tool +INSTALL3P = $(RSYNC) +INSTALL3POPTS = -aq + +ifeq ($(HOST_ARCH),SunOS) + TAIL ?= /usr/xpg4/bin/tail +else + TAIL ?= tail +endif + +ifeq ($(HOST_ARCH),SunOS) + AWK ?= /usr/xpg4/bin/awk +else + AWK ?= awk +endif + + + +# set up HOST_OS +testFile = $(wildcard /etc/SuSE-release /etc/redhat-release /usr/bin/sw_vers ) +ifeq ($(testFile), /etc/SuSE-release) + HOST_OS = $(shell $(GREP) -i linux /etc/SuSE-release | $(CUT) -d ' ' -f 1,3 | $(SED) 's/ //g' | $(SED) 's/\./_/g') +else + ifeq ($(testFile), /etc/redhat-release) + HOST_OS = $(shell $(CUT) -d ' ' -f 1,2,7 /etc/redhat-release | $(SED) 's/ //g' | $(SED) 's/\./_/g') + else + ifeq ($(testFile), /usr/bin/sw_vers) + HOST_OS = $(shell sw_vers -productVersion | cut -d '.' -f1,2 | $(SED) 's/\./_/g') + endif + endif +endif + + +#--------------------------------------------------------------------------- +# Set up ISIS versioning +#--------------------------------------------------------------------------- +ISISVERSIONFULL := $(shell $(GREP) version $(ISISROOT)/src/base/objs/Constants/Constants.h | $(CUT) -d"(" -f2 | $(CUT) -d")" -f1) +ISISMAJOR := $(shell $(ECHO) $(ISISVERSIONFULL) | $(CUT) -d"." -f1) +ISISMINOR := $(shell $(ECHO) $(ISISVERSIONFULL) | $(CUT) -d"." -f2) +ISISMINORMINOR := $(shell $(ECHO) $(ISISVERSIONFULL) | $(CUT) -d"." -f3 | cut -d" " -f1) +ISISVERSION := $(ISISMAJOR).$(ISISMINOR).$(ISISMINORMINOR) +ISISLIBVERSION := $(shell echo $(ISISMAJOR).$(ISISMINOR).$(ISISMINORMINOR) | sed 's/[a-z].*$$//') +ISISRELEASE := REL_0_0 + +#--------------------------------------------------------------------------- +# Set up the Isis include and library directories +#--------------------------------------------------------------------------- +SHAREDEXT ?= so +ISISINCDIR = -I$(ISISROOT)/inc +ISISLIBDIR = -L$(ISISROOT)/lib +ISISLIB = -lisis$(ISISLIBVERSION) + +#--------------------------------------------------------------------------- +# Set up for the required elements in Isis makes +# NOTE: XTRAstuff comes from the make file of specific applications +#--------------------------------------------------------------------------- +ALLINCDIRS = -I. +ALLINCDIRS += $(XTRAINCDIRS) +ALLINCDIRS += $(ISISINCDIR) +ALLINCDIRS += $(CWDINCDIR) +ALLINCDIRS += $(QTINCDIR) +ALLINCDIRS += $(QWTINCDIR) +ALLINCDIRS += $(XERCESINCDIR) +ALLINCDIRS += $(NAIFINCDIR) +ALLINCDIRS += $(TNTINCDIR) +ALLINCDIRS += $(JAMAINCDIR) +ALLINCDIRS += $(GEOSINCDIR) +ALLINCDIRS += $(GSLINCDIR) +ALLINCDIRS += $(GMMINCDIR) +ALLINCDIRS += $(SUPERLUINCDIR) +ALLINCDIRS += $(PROTOBUFINCDIR) +ALLINCDIRS += $(BOOSTINCDIR) +ALLINCDIRS += $(KAKADUINCDIR) + +ALLLIBDIRS = -L. +ALLLIBDIRS += $(XTRALIBDIRS) +ALLLIBDIRS += $(ISISLIBDIR) +ALLLIBDIRS += $(QTLIBDIR) +ALLLIBDIRS += $(QWTLIBDIR) +ALLLIBDIRS += $(XERCESLIBDIR) +ALLLIBDIRS += $(NAIFLIBDIR) +ALLLIBDIRS += $(TNTLIBDIR) +ALLLIBDIRS += $(JAMALIBDIR) +ALLLIBDIRS += $(GEOSLIBDIR) +ALLLIBDIRS += $(GSLLIBDIR) +ALLLIBDIRS += $(GMMLIBDIR) +ALLLIBDIRS += $(SUPERLULIBDIR) +ALLLIBDIRS += $(PROTOBUFLIBDIR) +ALLLIBDIRS += $(BOOSTLIBDIR) +ALLLIBDIRS += $(KAKADULIBDIR) + +ALLLIBS = $(ISISLIB) +ifeq ($(findstring STATIC, $(MODE)),STATIC) + ALLLIBS = $(ISISSTATIC) $(ISISLIB) $(ISISDYNAMIC) +endif +ALLLIBS += $(ISISSYSLIBS) +ALLLIBS += $(XTRALIBS) +ALLLIBS += $(QTLIB) +ALLLIBS += $(QWTLIB) +ALLLIBS += $(XERCESLIB) +ALLLIBS += $(NAIFLIB) +ALLLIBS += $(TNTLIB) +ALLLIBS += $(JAMALIB) +ALLLIBS += $(GEOSLIB) +ALLLIBS += $(GSLLIB) +ALLLIBS += $(GMMLIB) +ALLLIBS += $(SUPERLULIB) +ALLLIBS += $(PROTOBUFLIB) +ALLLIBS += $(BOOSTLIB) +ALLLIBS += $(KAKADULIB) diff --git a/isis/make/isismake.objs b/isis/make/isismake.objs new file mode 100644 index 0000000000000000000000000000000000000000..dd077cd571d1394b842360c941e7b7df4fa0b491 --- /dev/null +++ b/isis/make/isismake.objs @@ -0,0 +1,195 @@ +include $(ISISROOT)/make/isismake.macros + +ROOTINCLUDES = $(addprefix $(ISISROOT)/inc/, $(INCS)) +PLUGINS = $(strip $(wildcard *.plugin)) +LIBRARY = lib$(shell basename $(CURDIR)) +ARCHIVELIB = $(LIBRARY).a +SHAREDLIB = $(LIBRARY).$(SHAREDLIBEXT) +PROTOS = $(wildcard *.proto) +PROTOSGEN = $(wildcard *.pb.*) +PROTOSOBJ = $(wildcard *.pb.o) +MOCINC = $(wildcard *.h) +MOCGEN = $(wildcard moc_*.cpp) + + +.SUFFIXES: #eliminate default suffixes +.SUFFIXES: .cpp .o +.SUFFIXES: .xml .html +.SUFFIXES: .a .so .dylib +.SUFFIXES: .proto .pb.h .pb.cc +.SUFFIXES: .cc .o + +object: $(OBJS) $(PROTOS:%.proto=%.pb.o) + +.cpp.o: protos qtmoc + $(CXX) $(ALLINCDIRS) $(ISISCPPFLAGS) -c -o $@ $? + +.cc.o: + $(CXX) $(ALLINCDIRS) $(ISISCPPFLAGS) -c -o $@ $? + +# Its not necessarily $(LIBRARY)! +.a.so : + $(LDSHARED) $(ISISSHAREDFLAGS) $(ISISSHAREDON) -o libisis$(ISISLIBVERSION).$(SHAREDLIBEXT) $? $(ISISSHAREDOFF) + $(LN) -f libisis$(ISISLIBVERSION).$(SHAREDLIBEXT) libisis$(ISISMAJOR).$(ISISMINOR).$(SHAREDLIBEXT) + $(LN) -f libisis$(ISISMAJOR).$(ISISMINOR).$(SHAREDLIBEXT) libisis$(ISISMAJOR).$(SHAREDLIBEXT) + +# Its not necessarily $(LIBRARY)! +.a.dylib : + $(RM) -rd .objs; + $(MKDIR) .objs && cd .objs && ar x ../$*.a; + $(LDSHARED) $(DYLIBFLAGS) $(ISISSHAREDON) -o $@ \ + -install_name $(CURDIR)/$@ $(DYLIBVERSION) .objs/*.o $(ISISSHAREDOFF) + $(LN) -f libisis$(ISISLIBVERSION).$(SHAREDLIBEXT) libisis$(ISISMAJOR).$(ISISMINOR).$(SHAREDLIBEXT) + $(LN) -f libisis$(ISISMAJOR).$(ISISMINOR).$(SHAREDLIBEXT) libisis$(ISISMAJOR).$(SHAREDLIBEXT) + $(RM) -rd .objs; + +incs: protos $(ROOTINCLUDES) + +$(ROOTINCLUDES): $(INCS) + cp -p ${@F} $(ISISROOT)/inc + chmod 644 $(ISISROOT)/inc/${@F} + +# For plugins, it is the $(LIBRARY) (more precisely $(SHAREDLIB)) +install: object + if [ "$(PLUGINS)" != "" ]; \ + then \ + touch $(ISISROOT)/lib/$(PLUGINS); \ + cat $(PLUGINS) >> $(ISISROOT)/lib/$(PLUGINS); \ + $(MAKE) plugin; \ + cp -p $(SHAREDLIB) $(ISISROOT)/lib; \ + elif [ "$(OBJS)" != "" ]; \ + then \ + ar $(ISISARFLAGS) -crs $(ISISROOT)/lib/libisis$(ISISLIBVERSION).a $(OBJS); \ + $(RANLIB) $(ISISROOT)/lib/libisis$(ISISLIBVERSION).a; \ + fi + +force: ; + +protos: $(PROTOS:%.proto=%.pb.h) $(PROTOS:%.proto=%.pb.cc) + +%.pb.cc %.pb.h: %.proto + protoc -I$(.truth" + echo "make ostruthdata : Runs the unitTest and creates OS specific truth" + echo "make protos : Builds the object of google protocol buffer(*.proto) files" + +html: force + mkdir -p docbuild + cat $(ISISROOT)/src/docsys/Object/build//Programmer.conf > docbuild/ProgTester_temp.conf + echo "FILE_PATTERNS = *.h *.cpp *.doxydef" >> docbuild/ProgTester_temp.conf + echo "OUTPUT_DIRECTORY = $(CURDIR)/" >> docbuild/ProgTester_temp.conf + echo "STRIP_FROM_PATH = $(CURDIR)/" >> docbuild/ProgTester_temp.conf + echo "LATEX_OUTPUT = $(CURDIR)/html/latex" >> docbuild/ProgTester_temp.conf + echo "INPUT = $(ISISROOT)/src/docsys/Object/build/isisDoxyDefs.doxydef $(CURDIR)/" >> docbuild/ProgTester_temp.conf + echo "HTML_HEADER = $(ISISROOT)/src/docsys/Object/build/IsisObjectHeaderProgTester.html" >> docbuild/ProgTester_temp.conf + echo "HTML_FOOTER = $(ISISROOT)/src/docsys/Object/build/IsisObjectFooterProgTester.html" >> docbuild/ProgTester_temp.conf + echo "HTML_OUTPUT = html" >> docbuild/ProgTester_temp.conf + echo "TAGFILES = " >> docbuild/ProgTester_temp.conf + echo "HTML_STYLESHEET = $(ISISROOT)/src/docsys/Object/build/doxygen.css" >> docbuild/ProgTester_temp.conf + echo "IMAGE_PATH = $(CURDIR)/" >> docbuild/ProgTester_temp.conf + + if [ "$(findstring LOUD,$(MODE))" = "LOUD" ]; \ + then \ + echo "QUIET = NO" >> docbuild/ProgTester_temp.conf; \ + echo "WARNINGS = YES" >> docbuild/ProgTester_temp.conf; \ + echo "WARN_IF_UNDOCUMENTED = YES" >> docbuild/ProgTester_temp.conf; \ + echo "WARN_IF_DOC_ERROR = YES" >> docbuild/ProgTester_temp.conf; \ + echo "WARN_NO_PARAMDOC = YES" >> docbuild/ProgTester_temp.conf; \ + else \ + echo "QUIET = YES" >> docbuild/ProgTester_temp.conf; \ + echo "WARNINGS = YES" >> docbuild/ProgTester_temp.conf; \ + echo "WARN_IF_UNDOCUMENTED = YES" >> docbuild/ProgTester_temp.conf; \ + echo "WARN_IF_DOC_ERROR = YES" >> docbuild/ProgTester_temp.conf; \ + echo "WARN_NO_PARAMDOC = YES" >> docbuild/ProgTester_temp.conf; \ + fi + + doxygen docbuild/ProgTester_temp.conf + -$(RM) -r docbuild + echo "View your documentation by opening the file html/index.html in a browser" + +clean: localclean + -$(RM) $(OBJS) $(PROTOSGEN) $(MOCGEN) unitTest.o unitTest print.prt $(ARCHIVELIB) $(SHAREDLIB) + -$(RM) -rf html + +localclean: + if [ "$(findstring cleanlocal,$(shell grep cleanlocal Makefile))" = "cleanlocal" ]; \ + then \ + $(MAKE) cleanlocal; \ + fi + +clean_protos: + -$(RM) $(PROTOSGEN) + +sanitize: clean + -$(RM) tttt* junk.* TEMP* + +test: + $(ISISROOT)/scripts/unitTester $(HOST_OS) ; \ + temp=$$? ; \ + if test $$temp -eq 0 ; \ + then \ + echo "Ok"; \ + elif test $$temp -eq 2 ; \ + then \ + echo "unitTest.cpp not found"; \ + elif test $$temp -eq 1 ; \ + then \ + echo "`basename $(CURDIR)`.truth not found"; \ + elif test $$temp -eq 3 ; \ + then \ + echo "Could not make unitTest"; \ + elif test $$temp -eq 4 ; \ + then \ + echo "UnitTest aborted"; \ + elif test $$temp -eq 5 ; \ + then \ + echo "Failed"; \ + else \ + echo "Unexpected system error"; \ + fi + +unitTest: $(OBJS) unitTest.o + $(CXX) $(ALLLIBDIRS) $(ISISLDFLAGS) -o $@ unitTest.o $(OBJS) $(ALLLIBS) + +plugin: $(OBJS) + $(LDSHARED) $(ALLLIBDIRS) $(ISISSHAREDFLAGS) $(ISISSHAREDON) \ + -o $(SHAREDLIB) $(OBJS) $(ISISSHAREDOFF) + +truthdata: unitTest + ./unitTest >& `basename $(CURDIR)`.truth; + +ostruthdata: unitTest + if [ $(HOST_OS) = "" ]; then \ + ./unitTest >& `basename $(CURDIR)`_$(HOST_ARCH)_$(HOST_PROC).truth; \ + else \ + ./unitTest >& `basename $(CURDIR)`_$(HOST_ARCH)_$(HOST_PROC)_$(HOST_OS).truth; \ + fi diff --git a/isis/make/isismake.objstree b/isis/make/isismake.objstree new file mode 100644 index 0000000000000000000000000000000000000000..8450f70c63f9ce70bd595858f451b66b8d93435a --- /dev/null +++ b/isis/make/isismake.objstree @@ -0,0 +1,51 @@ +include $(ISISROOT)/make/isismake.macros + +DIRONLY = $(subst /,,$(shell ls -d */)) +CVS := CVS + +OBJECTS = $(filter-out $(CVS), $(DIRONLY)) + +api: + if [ "$(OBJECTS)" != "" ]; \ + then \ + for i in $(OBJECTS); do \ + echo " Adding API object [$$i]"; \ + cd $$i; $(MAKE) install; cd ..; \ + done \ + fi + +objects: + if [ "$(OBJECTS)" != "" ]; \ + then \ + for i in $(OBJECTS); do \ + echo " Building object [$$i] ("`date +%T`")"; \ + cd $$i; $(MAKE) object; cd ..; \ + done \ + fi + +includes: + if [ "$(OBJECTS)" != "" ]; \ + then \ + for i in $(OBJECTS); do \ + echo " Installing includes [$$i]"; \ + cd $$i; $(MAKE) incs; cd ..; \ + done \ + fi + +clean: + if [ "$(OBJECTS)" != "" ]; \ + then \ + for i in $(OBJECTS); do \ + echo " Cleaning [$$i]"; \ + cd $$i; $(MAKE) clean; cd ..; \ + done \ + fi + +test: + if [ "$(OBJECTS)" != "" ]; \ + then \ + for i in $(OBJECTS); do \ + printf %-60s " Testing [$$i] ("`date +%T`")"; \ + cd $$i; $(MAKE) test; cd ..; \ + done \ + fi diff --git a/isis/make/isismake.tsts b/isis/make/isismake.tsts new file mode 100644 index 0000000000000000000000000000000000000000..fee1e750f4636c78ffcfad46def7e104a8a50e59 --- /dev/null +++ b/isis/make/isismake.tsts @@ -0,0 +1,757 @@ +#---------------------------------------------------------------------------- +# Makefile for running and maintaining tests +#---------------------------------------------------------------------------- + +include $(ISISROOT)/make/isismake.macros + +# File extensions that valid file types to compare +BINFILES = jpg tif bin fits raw bmp png bc img imq +PVLFILES = pvl + +# Determine isis path from the current directory and use that path to set the TESTDATA_PATH variable +DIR := `pwd` +STR :=$(AWK) -v str=$(DIR) 'BEGIN { pos=index( str, \"/isis/\" ); print substr( str, pos, length( str ) - pos + 1 ) }' +ISIS_PATH := $(shell $(AWK) -v str=$(DIR) 'BEGIN { pos=index( str, "/isis/" ); print substr( str, pos, length( str ) - pos + 1 ) }' ) +TESTDATA_PATH := $(ISIS3TESTDATA)$(ISIS_PATH) + +ifneq ("$(shell echo $(ISIS_PATH) | cut -d '/' -f2,3,5,7)", "isis/src/apps/tsts") + ifneq ("$(shell echo $(ISIS_PATH) | cut -d '/' -f2,3,5)", "isis/src/tsts") + $(error Your directory structure is not a legal isis structure!) + endif +endif + +# define local test folders +LOCAL_INPUT := input +LOCAL_TRUTH := truth + +ifeq ($(HOST_OS),"") + LOCAL_OSTRUTH := $(LOCAL_TRUTH).$(HOST_ARCH).$(HOST_PROC) +else + LOCAL_OSTRUTH := $(LOCAL_TRUTH).$(HOST_ARCH).$(HOST_PROC).$(HOST_OS) +endif + +# Sets the TRUTH variable to point to the truth directory to use +# This works by seeing if a local truth dir exists, and if it does +# then it will check for a local OS specific truth dir. However, +# if a local truth dir does not exist it will check the testdata +# area for the truth directory. If it finds one there, it will use it +# and check for OS specific. If neither are found, TRUTH should equal the +# local truth folder for a good error message. +TRUTH := $(LOCAL_TRUTH) + +# Local truth directory found, check for OS Specific +ifeq "$(shell test -d $(LOCAL_TRUTH) && echo YES)" "YES" +# TRUTH := $(LOCAL_TRUTH) not necessary - initialized to this already + + ifeq "$(shell test -d $(LOCAL_OSTRUTH) && echo YES)" "YES" + TRUTH := $(LOCAL_OSTRUTH) + endif +# Local truth directory not found, check for testdata +else + ifeq "$(shell test -d $(TESTDATA_PATH)/$(LOCAL_TRUTH) && echo YES)" "YES" + TRUTH := $(TESTDATA_PATH)/$(LOCAL_TRUTH) + + ifeq "$(shell test -d $(TESTDATA_PATH)/$(LOCAL_OSTRUTH) && echo YES)" "YES" + TRUTH := $(TESTDATA_PATH)/$(LOCAL_OSTRUTH) + endif + endif +endif + +# Set input variable to be the input directory +INPUT := $(LOCAL_INPUT) + +# Test to see if the input directory exists in the current directory +# If not then set it to the testdata directory. The INPUT does not have +# to exist, so if the testdata doesn't exist it is okay and will be handled +# properly. +ifeq "$(shell test -d $(INPUT) && echo YES)" "YES" + INPUT := $(LOCAL_INPUT) +else + INPUT := $(TESTDATA_PATH)/$(LOCAL_INPUT) +endif + +# Test to see if the executable exists above the test +# if it exists then set APPNAME to reflect that, if not then leave APPNAME alone +ifeq "$(shell test -f ../../$(APPNAME) && echo YES)" "YES" + APPNAME := ../../$(APPNAME) +else + APPNAME := $(APPNAME) +endif + +# set the output variable to the output directory +OUTPUT = output + +# Key word to signal that the test should not be cleaned +TESTNOCLEAN := NOCLEAN + +# Defined text statements +TESTPASSED =$(PRINTF) $(BLANKS) \"\"; echo -n "OK ... Case [$(CASE)] " +TESTFAILED =$(PRINTF) $(BLANKS) \"\"; echo -n "Failed ... Case [$(CASE)] " +TESTFILEFAILED =echo Failed ... File [$@] +FILENOTFOUND =echo Failed ... File does not exist [$@] +UNKNOWNFILE =echo Failed ... Unknown file type [$@] +NOTRUTH =echo Failed ... No truth folder or files +NOTRUTHFILE =echo Failed ... No files in truth directory +NOOUTPUT =$(PRINTF) $(BLANKS) ""; echo "Error ... Output folder does not exist" + +DIRPATTERN=2774 +FILEPATTERN=2664 +DIRLISTPATTERN="drwxrwsr--" + +#---------------------------------------------------------------------------- +# Target = help +# Dependencies = +# +# Displays a list of targets and their descriptions. +#---------------------------------------------------------------------------- +help: + echo "Isis Make Test Commands" + echo "------------------------ " + echo "make test : Run test and print result, remove output" + echo "make test MODE=NOCLEAN : Run test and print result, leave output" + echo "make output : Runs commands" + echo "make checkin : Copy input and truth files to testdata area" + echo "make checkout : Copy input and truth files to test" + echo "make compare : Compare truth against output files" + echo "make truthdata : Copy files from the output to the truth directory" + echo "make ostruthdata : Copy files from the output to os truth directory" + echo "make release : Remove input truth and output directories" + +#---------------------------------------------------------------------------- +# Target = test +# Dependencies = clean output compare +# +# Clean is to make sure that there is nothing in the +# output directory other than what is generated in the test. +# Output then generates the file from the test. Finally +# comparefiles shows the result of the test. If the truth +# directory doesn't exist that a message is printed stating so. +#---------------------------------------------------------------------------- +test: clean; \ + TIME1=`date +"%s"`; \ + if [ -d "$(TRUTH)" ]; \ + then \ + truthdir=`$(LS) $(TRUTH)`; \ + if [ "$$truthdir" == "" ]; \ + then \ + msg='$(NOTRUTHFILE)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + else \ + $(MAKE) output; \ + $(MAKE) comparefiles; \ + if [ "$(findstring $(TESTNOCLEAN), $(MODE))" != "$(TESTNOCLEAN)" ]; \ + then \ + $(MAKE) clean; \ + fi; \ + fi; \ + else \ + msg='$(NOTRUTH)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + fi; \ + if [ $$TIME1 = %s ]; \ + then \ + if [ -f casefailed.txt ]; \ + then \ + eval $(TESTFAILED); \ + echo; \ + $(CAT) casefailed.txt; \ + $(RM) casefailed.txt; \ + else \ + eval $(TESTPASSED); \ + echo; \ + fi; \ + else \ + TIME2=`date +"%s"`; \ + TIMEDIFF=`expr $$TIME2 - $$TIME1`; \ + SEC60=`expr $$TIMEDIFF % 60`; \ + MIN=`expr $$TIMEDIFF / 60`; \ + MIN60=`expr $$MIN % 60`; \ + HOUR=`expr $$MIN / 60`; \ + HOUR60=`expr $$HOUR % 60`; \ + if [ -f casefailed.txt ]; \ + then \ + eval $(TESTFAILED); \ + $(PRINTF) "(%.2i:%.2i:%.2i)\n" $$HOUR60 $$MIN60 $$SEC60; \ + $(CAT) casefailed.txt; \ + $(RM) casefailed.txt; \ + else \ + eval $(TESTPASSED); \ + $(PRINTF) "(%.2i:%.2i:%.2i)\n" $$HOUR60 $$MIN60 $$SEC60; \ + fi; \ + fi; + +#---------------------------------------------------------------------------- +# Target = compare +# Dependencies = All files in the truth directory +# +# Iterates over the list of files in the truth directory and +# compares the files against the files in the output +# directory. If there are any files that are not recognized +# then an unknown file message is printed. +#---------------------------------------------------------------------------- +compare: + if [ -d "output" ]; \ + then \ + if [ -d "$(TRUTH)" ]; \ + then \ + truthdir=`$(LS) $(TRUTH)`; \ + if [ "$$truthdir" == "" ]; \ + then \ + msg='$(NOTRUTHFILE)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + else \ + $(MAKE) comparefiles; \ + fi; \ + else \ + msg='$(NOTRUTH)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + fi; \ + if [ -f casefailed.txt ]; \ + then \ + eval $(TESTFAILED); \ + echo; \ + $(CAT) casefailed.txt; \ + $(RM) casefailed.txt; \ + else \ + eval $(TESTPASSED); \ + echo; \ + fi; \ + else \ + command='$(NOOUTPUT)'; \ + eval $$command; \ + fi; + +#---------------------------------------------------------------------------- +# Target = truthdata +# Dependencies = +# +# Copies the contents of the output directory to the truth +# directory. If the truth directory doesn't exist it is created. +# $(RSYNC) -ru --delete $(TESTDATA_PATH)/input/ input; \ +#---------------------------------------------------------------------------- +truthdata: + $(MKDIR) truth; + $(RSYNC) -rt --delete output/ truth; + +#---------------------------------------------------------------------------- +# Target = ostruthdata +# Dependencies = +# +# Copies the contents of the output directory to the truth +# directory. If the truth directory corresponding to the +# OS the test is being run on doesn't exist it is created. +#---------------------------------------------------------------------------- +ostruthdata: + osdir="$(TRUTH)"; \ + if [ "$(TRUTH)" = "truth" ]; then \ + if [ "$(HOST_OS)" = "" ]; then \ + osdir="$(TRUTH).$(HOST_ARCH).$(HOST_PROC)"; \ + else \ + osdir="$(TRUTH).$(HOST_ARCH).$(HOST_PROC).$(HOST_OS)"; \ + fi; \ + fi; \ + $(MKDIR) $$osdir; \ + $(RSYNC) -rt --delete $(OUTPUT)/ $$osdir; + +#---------------------------------------------------------------------------- +# Target = output +# Dependencies = temp commands modifyFiles +# +# Masks target command with a better name to just run the +# commands. If the output directory doesn't exist it is +# created. The temp target is needed because the directory +# output causes make to check the directory output if there +# is no dependency. Runs the commands and then +# modifies the output files based on the variables set +# in the test. +#---------------------------------------------------------------------------- +output: temp + $(MKDIR) $(OUTPUT); + $(MAKE) commands; + $(MAKE) modifyFiles; + +# needed to make the output target work +temp: + temp=""; + +#---------------------------------------------------------------------------- +# Target = clean +# Dependencies = +# +# Deletes the output directory. +#---------------------------------------------------------------------------- +clean: + $(RM) -r $(OUTPUT); \ + $(RM) print.prt; \ + +#---------------------------------------------------------------------------- +# Target = comparefiles +# Dependencies = All files in the truth directory +# +# Iterates over the list of files in the truth directory and +# compares the files against the files in the output +# directory. If there are any files that are not recognized +# then an unknown file message is printed. +#echo "t = $(notdir $(wildcard $(TRUTH)/*) )"; +#echo "b = $(BINFILES)"; +#---------------------------------------------------------------------------- +comparefiles: $(notdir $(wildcard $(TRUTH)/*) ) + temp=""; + +#---------------------------------------------------------------------------- +# Target = modifyFiles +# Dependencies = modText modBin +# +# Performs the modifications to the files in the output +# directory. Iterates over the output files and modifies +# the file based on variables such as .SKIPLINES +# Utilizes the modText and modBin targets to carryout +# the modifactions. +#---------------------------------------------------------------------------- +modifyFiles: + files="$(notdir $(wildcard $(OUTPUT)/*.txt) )"; \ + for i in $$files; do \ + $(MAKE) modText FILE=$$i; \ + done; + files="$(notdir $(wildcard $(foreach j, $(BINFILES), $(addprefix $(OUTPUT)/*., $j)) ) )"; \ + for i in $$files; do \ + $(MAKE) modBin FILE=$$i; \ + done; + files="$(notdir $(wildcard $(foreach j, $(PVLFILES), $(addprefix $(OUTPUT)/*., $j)) ) )"; \ + for i in $$files; do \ + $(MAKE) modText FILE=$$i; \ + done; + +#---------------------------------------------------------------------------- +# Target = modText +# Dependencies = +# +# Handles the modifactions of text files in the output +# directory. Looks at variables .SKIPLINES and .IGNORELINES. +# The variable FILE must be set to the name of the file in +# the output directory to be modified. +#---------------------------------------------------------------------------- +modText: + if [ "$(FILE)" != "" ]; \ + then \ + numLines="+0"; \ + if [ "$($(FILE).SKIPLINES)" != "" ]; \ + then \ + numLines="$($(FILE).SKIPLINES)"; \ + skipLines=`expr $($(FILE).SKIPLINES) + 1`; \ + numLines="+$$skipLines"; \ + fi; \ + $(TAIL) -n $$numLines $(OUTPUT)/$(FILE) > $(OUTPUT)/$(FILE).tail; \ + if [ "$($(FILE).IGNORELINES)" = "" ]; \ + then \ + $(CP) $(OUTPUT)/$(FILE).tail $(OUTPUT)/$(FILE).tail2; \ + else \ + command="grep -vw $(word 1, $($(FILE).IGNORELINES)) $(OUTPUT)/$(FILE).tail"; \ + if [ $(words $($(FILE).IGNORELINES)) != 1 ]; \ + then \ + command2="$(foreach i, $(wordlist 2, 10000, $($(FILE).IGNORELINES) ), | grep -vw $i)" ; \ + fi; \ + eval $$command$$command2 > $(OUTPUT)/$(FILE).tail2; \ + fi; \ + $(MV) $(OUTPUT)/$(FILE).tail2 $(OUTPUT)/$(FILE); \ + $(RM) $(OUTPUT)/$(FILE).tail; \ + fi + +#---------------------------------------------------------------------------- +# Target = modBin +# Dependencies = +# +# Handles the modifactions of bin files in the output +# directory. Looks at variables .BINSKIP and .BINCOUNT. +# The variable FILE must be set to the name of the file in +# the output directory to be modified. +#---------------------------------------------------------------------------- +modBin: + if [ "$(FILE)" != "" ]; \ + then \ + binskipstr=""; \ + bincountstr=""; \ + if [ "$($(FILE).BINSKIP)" != "" ]; \ + then \ + binskipstr="skip=$($(FILE).BINSKIP)"; \ + fi; \ + if [ "$($(FILE).BINCOUNT)" != "" ]; \ + then \ + bincountstr="count=$($(FILE).BINCOUNT)"; \ + fi; \ + $(DD) if=$(OUTPUT)/$(FILE) of=$(OUTPUT)/$(FILE).dd $$binskipstr $$bincountstr >& /dev/null; \ + $(MV) $(OUTPUT)/$(FILE).dd $(OUTPUT)/$(FILE); \ + fi + +force: ; + +#---------------------------------------------------------------------------- +# Target = %.cub +# Dependencies = +# +# Compare two cub files. This is a pattern rule used by the +# compare target to compare cubs in the truth directory +# against a similiarly named file in the output directory. +#---------------------------------------------------------------------------- +%.cub: force + if [ ! -f $(OUTPUT)/$@ ]; \ + then \ + msg='$(FILENOTFOUND)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + else \ + tolerancestr=""; \ + ignorestr="";\ + if [ "$($@.TOLERANCE)" != "" ]; \ + then \ + tolerancestr="tolerance=$($@.TOLERANCE)"; \ + fi; \ + if [ "$($@.IGNORESPECIAL)" != "" ]; \ + then \ + ignorestr="ignorespecial=$($@.IGNORESPECIAL)"; \ + fi; \ + $(ISISROOT)/bin/cubediff from=$(TRUTH)/$@ \ + from2=$(OUTPUT)/$@ \ + to=compare.txt \ + $$tolerancestr \ + $$ignorestr > /dev/null; \ + compResult=`$(ISISROOT)/bin/getkey from=compare.txt grp=Results keyword=Compare`; \ + command="";\ + if [ "$$compResult" = "DIFFERENT" ]; \ + then \ + msg='$(TESTFILEFAILED)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + fi ; \ + $(RM) compare.txt; \ + fi; + +#---------------------------------------------------------------------------- +# Target = %.txt +# Dependencies = +# +# Compare two text files. This is a pattern rule used by the +# compare target to compare text files in the truth directory +# against a similiarly named file in the output directory. +#---------------------------------------------------------------------------- +%.txt: force + if [ ! -f "$(OUTPUT)/$@" ]; \ + then \ + msg='$(FILENOTFOUND)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + else \ + command="";\ + $(DIFF) $(TRUTH)/$@ $(OUTPUT)/$@ > /dev/null; \ + if [ $$? -ne 0 ]; \ + then \ + msg='$(TESTFILEFAILED)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + fi; \ + fi + +#---------------------------------------------------------------------------- +# Target = %.pvl +# Dependencies = +# +# Compare two pvl files using pvldiff. The tolerances and ignore lines are +# specified in the file (if it exists) filename.DIFF. +#---------------------------------------------------------------------------- +%.pvl: force + if [ ! -f $(OUTPUT)/$@ ]; then \ + msg='$(FILENOTFOUND)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + else \ + difffile="$(INPUT)/$@.DIFF"; \ + if [ ! -f $$difffile ]; \ + then \ + difffile=''; \ + fi; \ + \ + $(ISISROOT)/bin/pvldiff from=$(TRUTH)/$@ from2=$(OUTPUT)/$@ \ + to=compare.txt diff=$$difffile >& /dev/null; \ + \ + compResult=`$(ISISROOT)/bin/getkey from=compare.txt grp=Results \ + keyword=Compare | tr '[:upper:]' '[:lower:]'`; \ + \ + if [ "$$compResult" = "different" ]; then \ + msg='$(TESTFILEFAILED)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + fi ; \ + $(RM) compare.txt; \ + fi; + +%.DIFF: force + temp=""; + +#---------------------------------------------------------------------------- +# Target = %.BIN +# Dependencies = +# +# Compare two bin files. This is a pattern rule used by the +# compare target to compare bin files in the truth directory +# against a similiarly named file in the output directory. +# This target covers any files with extension in the list in the +# variable BINFILES. +#---------------------------------------------------------------------------- +$(foreach i, $(BINFILES), $(addprefix %., $i)): + if [ ! -f "$(OUTPUT)/$@" ]; \ + then \ + msg='$(FILENOTFOUND)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + else \ + command="";\ + $(DIFF) $(TRUTH)/$@ $(OUTPUT)/$@ > /dev/null; \ + if [ $$? -ne 0 ]; \ + then \ + msg='$(TESTFILEFAILED)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + fi; \ + fi + +#---------------------------------------------------------------------------- +# Target = % +# Dependencies = +# +# Handles any other files that may be in the truth directory. +# Prints that the file is unknown. +#---------------------------------------------------------------------------- +% :: + msg='$(UNKNOWNFILE)'; \ + $(PRINTF) "$(BLANKS) " >> casefailed.txt; \ + $$msg >> casefailed.txt; \ + +#---------------------------------------------------------------------------- +# Target = checkin +# Dependencies = copyInTruth +# +# Copies data from the test into the test data area. +# ISIS3TESTDATA needs to be set to know where to copy +# data for this test to. Data in the input and all of the truth +# directories are copied to the test data area. +# +# Modified by: Stuart Sides 2007-01-09 +# Modified so we can do "make checkin" for files/dirs we do not own in the +# testdata area. +# The reasons for the (RM): +# NOTE: chmod docs say you can not set permissioins unless you own the file +# NOTE: rsync can not set the times on directories you do not own +# Thus the (RM) makes everything work +# Modified by: Steven Lambright 2007-07-18 +# Modified to properly sync the input folder because it is not required +#---------------------------------------------------------------------------- +checkin: + if [ "$(ISIS3TESTDATA)" != "" ]; \ + then \ + if [ -d "$(TRUTH)" ]; \ + then \ + truthdir=`$(LS) $(TRUTH)`; \ + if [ "$$truthdir" != "" ]; \ + then \ + $(RM) -rf $(TESTDATA_PATH); \ + $(MKDIR) -m775 $(TESTDATA_PATH); \ + if [ -d "$(LOCAL_INPUT)" ]; \ + then \ + $(MKDIR) -m775 $(TESTDATA_PATH)/input; \ + find $(TESTDATA_PATH)/../.. -type d -user `whoami` -exec chmod 2775 {} \; ; \ + inputdir=`$(LS) $(LOCAL_INPUT)`; \ + if [ "$$inputdir" != "" ]; \ + then \ + find $(LOCAL_INPUT) -type d -user `whoami` -exec chmod 2775 {} \; ; \ + find $(LOCAL_INPUT) -type f -user `whoami` -exec chmod 664 {} \; ; \ + $(RSYNC) -rt --delete $(LOCAL_INPUT)/ $(TESTDATA_PATH)/input; \ + fi; \ + elif [ -d "$(TESTDATA_PATH)/input" ]; \ + then \ + $(RM) -rf $(TESTDATA_PATH)/input; \ + fi; \ + $(MAKE) copyInTruth DEST=$(TESTDATA_PATH)/; \ + find $(TESTDATA_PATH)/../.. -type d -user `whoami` -exec chmod 2775 {} \; ; \ + find $(TESTDATA_PATH)/../.. -type f -user `whoami` -exec chmod 664 {} \; ; \ + else \ + echo "Truth directory empty"; \ + fi; \ + else \ + echo "Truth directory not found"; \ + fi; \ + else \ + echo "ISIS3TESTDATA not set"; \ + fi + +#---------------------------------------------------------------------------- +# Target = copyInTruth +# Dependencies = +# +# Copies all of the truth directories to the value in the +# variable DEST. Iterates over all of the directories in the +# test that have truth in it. Creates the directory in DEST +# and then copies all of the files in the truth directory to +# directory in DEST. +#---------------------------------------------------------------------------- +copyInTruth: + for i in $(wildcard truth*); do \ + $(MKDIR) -m2775 $(DEST)$$i; \ + files=`$(LS) $$i`; \ + if [ "$$files" != "" ]; \ + then \ + find $$i -type d -user `whoami` -exec chmod 2775 {} \; ; \ + find $$i -type f -user `whoami` -exec chmod 664 {} \; ; \ + $(RSYNC) -rt --delete $$i/ $(DEST)$$i; \ + fi; \ + done; + +#---------------------------------------------------------------------------- +# Target = checkout +# Dependencies = dirs copyOutTruth +# +# Copies data from the test data area into the test. +# ISIS3TESTDATA needs to be set to know where to get the +# test data from. Uses the TESTDATA_PATH to get the data +# for this test. Copies the files from the input directory in the +# TESTDATA_PATH to the input directory of the test. Then +# copies all of the truth directories and their contents to the test. +# If the input or truth directories exist in the local test a warning +# is printed and no copying takes place. +#---------------------------------------------------------------------------- +checkout: + if [ "$(ISIS3TESTDATA)" = "" ]; \ + then \ + echo "ISIS3TESTDATA not set"; \ + elif [ -d "$(LOCAL_INPUT)" ]; \ + then \ + echo "Input directory already exists, nothing copied"; \ + elif [ -d "$(LOCAL_TRUTH)" ]; \ + then \ + echo "Truth directory already exists, nothing copied"; \ + elif [ -d "$(LOCAL_OSTRUTH)" ]; \ + then \ + echo "OStruth directory already exists, nothing copied"; \ + else \ + if [ -d "$(TESTDATA_PATH)/input" ]; \ + then \ + inputdir=`$(LS) $(TESTDATA_PATH)/input`; \ + if [ "$$inputdir" != "" ]; \ + then \ + $(MAKE) dirs; \ + $(RSYNC) -rt --delete $(TESTDATA_PATH)/input/ input; \ + fi; \ + fi; \ + $(MAKE) copyOutTruth DEST=$(TESTDATA_PATH); \ + fi + +#---------------------------------------------------------------------------- +# Target = copyOutTruth +# Dependencies = +# +# Copies all of the truth directories from the value in the +# variable DEST. Iterates over all of the directories in +# DEST that have truth in it. Creates the directory in test +# and then copies all of the files from the DEST directory +# to the one in the test. +#---------------------------------------------------------------------------- +copyOutTruth: + for i in $(notdir $(wildcard $(DEST)/truth*) ); do \ + $(MKDIR) $$i; \ + files=`$(LS) $(DEST)/$$i`; \ + if [ "$$files" != "" ]; \ + then \ + $(RSYNC) -rt --delete $(DEST)/$$i/ $$i; \ + fi; \ + done; + + +#----------------------------------------------------------------------------# +# Target = release # +# Dependencies = clean # +# # +# Deletes all extraneous files and folders inside the current directory. # +# If any of these files or folders do not exist or don't match the ones # +# in $ISIS3TESTDATA then the user is prompted before continuing. # +#----------------------------------------------------------------------------# +release: clean + proceedWithRelease="true"; \ + \ + for i in $(notdir $(filter-out CVS Makefile print.prt $(OUTPUT), \ + $(wildcard *))); do \ + \ + $(DIFF) -r $$i $(TESTDATA_PATH)/$$i >& /dev/null; \ + \ + if [ "$$?" != "0" ]; then \ + continueAnyway="invalidAnswer"; \ + \ + until [ "$$continueAnyway" = "y" -o \ + "$$continueAnyway" = "yes" -o \ + "$$continueAnyway" = "n" -o \ + "$$continueAnyway" = "no" ]; do \ + \ + $(PRINTF) %-6s \ + "$$i was not checked in! Delete anyway? (y/n) "; \ + read continueAnyway; \ + continueAnyway=`echo $$continueAnyway | tr '[:upper:]' \ + '[:lower:]'`; \ + \ + done; \ + \ + if [ "$$continueAnyway" = "n" -o \ + "$$continueAnyway" = "no" ]; then \ + proceedWithRelease="false"; \ + break; \ + fi \ + fi \ + done; \ + \ + if [ "$$proceedWithRelease" = "true" ]; then \ + for i in $(notdir $(filter-out CVS Makefile print.prt $(OUTPUT), \ + $(wildcard *))); do \ + $(RM) -r $$i; \ + done; \ + fi + + +#---------------------------------------------------------------------------- +# Target = dirs +# Dependencies = +# +# Creates the necessary directories for the test. +#---------------------------------------------------------------------------- +dirs: + $(MKDIR) input; + +#---------------------------------------------------------------------------- +# Target=changePerms +# Dependencies = +# +# Changes the directory permissions starting at DEST_PATH +# and preceding up the directory path till a directory is found +# that matches the DIRLISTPATTERN variable. Both the +# LOOKUP and DEST_PATH variables need to be set in order +# to work properly. LOOKUP is the first directory to start checking +# folder permissions on, and DEST_PATH is the full directory +# path above the LOOKUP directory. +#---------------------------------------------------------------------------- +changePerms: + lookup=$(LOOKUP); \ + path=$(DEST_PATH); \ + permsline=`$(LS) -l $$path | grep -w $$lookup`; \ + perms=`perl -e 'print substr( @ARGV[0], 0, 10 )' $$permsline`; \ + while [ "$$perms" != $(DIRLISTPATTERN) ]; \ + do \ + t=`chmod $(DIRPATTERN) $$path/$$lookup`; \ + revpath=`perl -e 'print scalar reverse ( @ARGV[0] )' $$path`; \ + pos=`perl -e 'print index( @ARGV[0], "/" )' $$revpath`; \ + folderrev=`perl -e 'print substr( @ARGV[0], 0, @ARGV[1] )' $$revpath $$pos`; \ + lookup=`perl -e 'print scalar reverse ( @ARGV[0] )' $$folderrev`; \ + subpath=`perl -e 'print substr( @ARGV[0], @ARGV[1]+1, length( @ARGV[0] ) -@ARGV[1] +1)' $$revpath $$pos`; \ + path=`perl -e 'print scalar reverse( @ARGV[0] )' $$subpath`; \ + permsline=`$(LS) -l $$path | grep -w $$lookup`; \ + perms=`perl -e 'print substr( @ARGV[0], 0, 10 )' $$permsline`; \ + done diff --git a/isis/make/isismake.tststree b/isis/make/isismake.tststree new file mode 100644 index 0000000000000000000000000000000000000000..74abc682baf40d23c7ec30131c5324e4e4b37794 --- /dev/null +++ b/isis/make/isismake.tststree @@ -0,0 +1,89 @@ +include $(ISISROOT)/make/isismake.macros + +DIRONLY = $(subst /,,$(shell ls -d */)) +CVS := CVS +TESTS = $(filter-out $(CVS), $(DIRONLY)) + +#---------------------------------------------------------------------------- +# Target = help +# Dependencies = +# +# Displays a list of targets and their descriptions. +#---------------------------------------------------------------------------- +help: + echo "Isis Make Tests Commands" + echo "------------------------ " + echo "make test : Runs and displays results for all of the tests" + echo "make newtest TEST=testname : Creates a new test named testname" + +#---------------------------------------------------------------------------- +# Target = tests +# Dependencies = +# +# Iteretates over all of the tests and runs them. If the test +# has no makefile or there is no tests a message is +# printed saying so. +#---------------------------------------------------------------------------- +test: force + if [ "$(TESTS)" != "" ]; \ + then \ + echo ""; \ + for i in $(TESTS); do \ + cd $$i; \ + if [ -f "Makefile" ]; \ + then \ + $(MAKE) test CASE=$$i BLANKS=$(BLANKS); \ + else \ + printf $(BLANKS) ""; \ + echo "no makefile"; \ + fi ; \ + cd ..; \ + done \ + else \ + echo ""; \ + printf $(BLANKS) ""; \ + echo "no tests"; \ + fi +force: ; + +#---------------------------------------------------------------------------- +# Target = newtest +# Dependencies = variable TEST +# +# Creates a new test in the current directory. Relies on +# the TEST variable to create a new folder that will contain +# the new test. If the folder does not already exist then it is +# created and the right Makefile is copied into that directory +# and the test is told to create what it needs. +#---------------------------------------------------------------------------- +newtest: + if [ "$(TEST)" = "" ]; \ + then \ + echo "TEST needs to be set to create a new test"; \ + elif [ -d "$(TEST)" ]; \ + then \ + echo "The test already exists"; \ + else \ + $(MKDIR) $(TEST); \ + cd $(TEST); \ + $(CP) $(ISISROOT)/make/Makefile.tsts Makefile; \ + $(MAKE) dirs; \ + fi + +#---------------------------------------------------------------------------- +# Target = clean +# +# Removes the output from any previous tests +#---------------------------------------------------------------------------- +clean: + if [ "$(TESTS)" != "" ]; \ + then \ + for i in $(TESTS); do \ + cd $$i; \ + if [ -f "Makefile" ]; \ + then \ + $(MAKE) clean; \ + fi ; \ + cd ..; \ + done \ + fi diff --git a/isis/scripts/DarwinLibs.lis b/isis/scripts/DarwinLibs.lis new file mode 100644 index 0000000000000000000000000000000000000000..221c1cb0c1323bbebd773040a2cb1e9f1f5633e3 --- /dev/null +++ b/isis/scripts/DarwinLibs.lis @@ -0,0 +1,17 @@ +/farm/prog1/slambright/helix/myisis/isis/lib/libisis3.2.1.dylib +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/libz.1.dylib +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/QtXmlPatterns.framework/Versions/4/QtXmlPatterns +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/QtXml.framework/Versions/4/QtXml +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/QtNetwork.framework/Versions/4/QtNetwork +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/QtSql.framework/Versions/4/QtSql +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/QtGui.framework/Versions/4/QtGui +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/QtCore.framework/Versions/4/QtCore +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/QtSvg.framework/Versions/4/QtSvg +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/libqwt.5.2.0.dylib +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/libxerces-c.28.dylib +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/libcspice.dylib +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/libgeos-3.2.0.dylib +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/libgsl.0.dylib +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/libgslcblas.0.dylib +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/libprotobuf.6.dylib +/farm/prog1/slambright/helix/myisis/isis/3rdParty/lib/libkdu_a63R.dylib diff --git a/isis/scripts/DeployDarwin.csh b/isis/scripts/DeployDarwin.csh new file mode 100644 index 0000000000000000000000000000000000000000..8cd6944506dddc7bcbecda16f8586b69b8fe0dca --- /dev/null +++ b/isis/scripts/DeployDarwin.csh @@ -0,0 +1,52 @@ +#!/bin/csh +# $Id: DeployDarwin.csh,v 1.1 2010/04/09 23:19:58 slambright Exp $ + +if ($?ISISROOT == 0) then + echo "ISISROOT not set...must be set to target ISIS build!" + exit (1) +endif + +# Set runtime paths for all ISIS binary applications +/bin/rm -f DarwinLibs.lis DarwinErrors.lis +SetRunTimePath --bins --libmap=isis_bins_paths.lis --liblog=DarwinLibs.lis \ + --relocdir=$ISISROOT/3rdParty/lib:$ISISROOT/3rdParty:$ISISROOT \ + --errlog=DarwinErrors.lis \ + `find $ISISROOT/bin -maxdepth 1 -name '*' -type f` + + +# Patch all libraries in $ISISROOT/lib +#SetRunTimePath --libs --libmap=darwin_paths.lis --liblog=DarwinLibs.lis \ +# --relocdir=$ISISROOT/3rdParty/lib --update \ +# --errlog=DarwinErrors.lis \ +# `find $ISISROOT/lib -maxdepth 1 -name '*.dylib' -type f` + +# Process third party Qt frameworks +SetRunTimePath --libs --libmap=qt_paths.lis --liblog=DarwinLibs.lis \ + --relocdir=$ISISROOT/3rdParty/lib:$ISISROOT/3rdParty --update \ + `find $ISISROOT/3rdParty/lib -name 'Qt*' -print -mindepth 3 -maxdepth 4 -type f` + +# Process third party generic libraries +chmod u+w $ISISROOT/3rdParty/lib/libcrypto.*.dylib +chmod u+w $ISISROOT/3rdParty/lib/libssl.*.dylib +SetRunTimePath --libs --libmap=darwin_lib_paths.lis --liblog=DarwinLibs.lis \ + --relocdir=$ISISROOT/3rdParty/lib:$ISISROOT/3rdParty --update \ + --errlog=DarwinErrors.lis \ + `find $ISISROOT/3rdParty/lib -name '*.dylib' -maxdepth 1 -type f` +chmod u-w $ISISROOT/3rdParty/lib/libcrypto.*.dylib +chmod u-w $ISISROOT/3rdParty/lib/libssl.*.dylib + +# Patch IDL/IsisDlm +if (-e $ISISROOT/IsisDlm/lib/IsisDlm.so) then + SetRunTimePath --bundles --libmap=darwin_IsisDlm_paths.lis --liblog=DarwinLibs.lis \ + --relocdir=$ISISROOT/3rdParty:$ISISROOT/3rdParty/lib --update \ + --errlog=DarwinErrors.lis $ISISROOT/IsisDlm/lib/IsisDlm.so +endif + +# Finally, patch the (Qt) plugins +SetRunTimePath --bundles --libmap=qt_plugins_paths.lis --liblog=DarwinLibs.lis --update \ + --relocdir=$ISISROOT/3rdParty/lib:$ISISROOT/3rdParty \ + --errlog=DarwinErrors.lis \ + `find $ISISROOT/3rdParty/plugins -name '*.bundle' -type f` + + + diff --git a/isis/scripts/PullLastMod.xsl b/isis/scripts/PullLastMod.xsl new file mode 100644 index 0000000000000000000000000000000000000000..a74013ca3b0858984b08c8501a52130706098d0a --- /dev/null +++ b/isis/scripts/PullLastMod.xsl @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + ()() + + + + + + + diff --git a/isis/scripts/SetRunTimePath b/isis/scripts/SetRunTimePath new file mode 100755 index 0000000000000000000000000000000000000000..5816744ae7d4a3858f324ebd11711d970fefe0ac --- /dev/null +++ b/isis/scripts/SetRunTimePath @@ -0,0 +1,618 @@ +#!/usr/bin/perl +use Getopt::Long; +use File::Temp; +# use strict; + +my $SUCCESS = 0; +my $BAD_INPUT = 1; + +my ($progname) = ($0 =~ m#([^/]+)$#); # get the name of this program + +my $usage = " +Usage: $progname [-h] [-v] [--dryrun] {--bins | --libs | --bundles} + [--oldpath=] [--newpath=] [--libmap=] + [ --prepend | --append] [--liblog=] [--update] + [--install_root=] [--relocdir=] + file [file ...] + +where + -h Help, prints this menu + -v Verbose output + --dryrun Only show commands that will be executed. Note + this automatically turns on verbose. + --bins Input file(s) are binary application. Either this + option or the --libs or --bundles option is required. + --libs Input file(s) are libraries. Either this option or + the --bins or --bundles option is required. + --bundles [MACOSX] Specifies files are MacOSX bundles that must + be treated slightly different than a MacOSX library. + --oldpath= Old path to replace in library paths (MacOSX) + --newpath= New runtime path to set in binary + --libmap= As an alternative or an augmentation, you can provide + a file containing a list of oldpaths and newpaths. + Each line in the file contains a map of the oldpath + as the first column. The second column is the + newpath replacement for the old path. You can still + provide oldpath and newpath parameters. If provided, + they will be appended by default to the list read + from the file provided in libmap. Use the --prepend + and --append options to control this. Note that all + lines that begin with a # will be treated a comment + and ignored. This option is MacOSX specific/useful. + --prepend Prepend any library maps as provided in the oldpath and + newpath parameters to any read from the libmap + parameter if provided. + --append Append any library maps as provided in the oldpath and + newpath parameters to any read from the libmap + parameter if provided. [This is the default + behavior] + --liblog= Specify filename to write the names of all unique + libraries that were found during processing. This + is MacOSX specific/useful. + --update Used in conjuction with the \"liblog\" option. Setting + this parameter will cause the file provided in the + liblog parameter to be read in an used to initialize + the list. Only new libraries that don't previously + exist will be added. As such, it is not an error for + the liblog file to not exists. No error or warning + will be issued if the liblog file does not exist. + --install_root= This parameter only applies to Mac libraries (dylib) + files. The value of this parameter replaces the + root as defined in the --oldpath parameter or the + first column of the libmap file. If it not + provided, the install name for the library will not + be modified. + --relocdir= In conjunction with liblog, these directory prefixes + will be used to replace the prefix found during + processing to specify the actual deployment directory + location. The resulting list can be used to alter + the install_names of those libraries using this + same application for proper deployment. This is + MacOSX specific/useful. There is no default so if + no value is provided, it creates a list of absolute + library locations. + --errlog= If specified, it will contain a list of input files + that had errors during processing. If no errors + were encountered, the file is not modified. If + errors did occur, the files are appended to the + file name specified. + file [file...] Name of files to modify paths in + +$progname will modify runtime dynamic/shared library paths in binary +executables and, in some OSes (e.g., MacOSX), library install names. +This is necessary to eliminate the need for use of mostly problimatic +LD_LIBRARY_PATH/DYLD_LIBRARY_PATH environment variables. These have +led to problems on deployed versions of ISIS. + +Note, I recommend that the proper time to modify the runtime path on +executables is at install time. There will be trouble if you attempt +to make this modification at link time, since the runtime paths are +typically relative to the directory of the executable binary. + +MacOSX is far more complicated to create environment variable free deployment +of large software systems. As such, MacOSX requires additional considerations +(i.e., parameters) as there are runtime library path locations baked into the +dynamic libraries and for each shared library. + +On the other hand, Linux only requires one runtime path update with multiple +paths. Hence, the newpath parameter is typically all that is needed in order +to ensure deployment ready software systems. Unfortunately, Linux does not +readily provided a utility that modify rpaths after linking. There are two +third party applications that provided this capability. One is chrpath which +seems to be no longer maintained. The other is patchELF. This is the +recommended utility at this time as it offers more flexibility, such as +extending the size of the executables if needed in order to accomodate new +rpath entry lengths. + +MacOSX will require each library path in the executable to be +modified. In addition, MacOSX libraries require modification of the +install name of the library prior to deployment. All this can be accomplished +using the MacOSX install_name_tool utility. Linux platforms make use +of the chrpath or patchELF utility which are not available as a native +application on most Linux distributions. + +In addition to shared libraries and binary executables, plugins may +also require modification. +"; + +##################################################################### +# Author: Kris Becker, USGS, Flagstaff Original Version +# Date: 2010-02-25 +# Version: $Id: SetRunTimePath,v 1.1 2010/04/09 23:19:58 slambright Exp $ +##################################################################### +my $help = ''; # Help option + +# Get options +my $opterrs = GetOptions ( "h" => \$help, + "v" => \$verbose, + "dryrun" => \$dryrun, + "bins" => \$bins, + "libs" => \$libs, + "bundles" => \$bundles, + "oldpath=s" => \$oldpath, + "newpath=s" => \$newpath, + "libmap=s" => \$libmap, + "prepend" => \$prepend, + "append" => \$append, + "liblog=s" => \$liblog, + "errlog=s" => \$errlog, + "update" => \$update, + "relocdir=s" => \$relocdir, + "install_root=s" => \$install_root, + "changer=s" => \$myChanger, + "changeopt=s" => \$myChangerOpt, + "changelist=s" => \$myChangerList + ); + +#$dryrun = 1; ### Ensure test mode for now +die "$usage\n" if (!$opterrs); +die "$usage\n" if ($help); +Usage("*** Program Documentation ***\n") if ($#ARGV < 0); +#$verbose = 1 if ($dryrun); +my $fopt = 0; +$fopt += 1 if ($bins); +$fopt += 1 if ($libs); +$fopt += 1 if ($bundles); +Usage("Must give one and only one of --libs, --bins or --bundles") if ($fopt != 1); + +# Determine system architecture and initialize default changer +my $sysArch = "$^O"; +my $ChangerFunc = sub { die "Changer function not found for system $sysArch!\n" }; +my $CheckLibs = sub { die "Library checker function not available for $sysArch!\n" }; + +# Set up changer tool for the specific platform +my $changer = ""; +my $changerOption = ""; +my $changerList = ""; +if ($sysArch eq "darwin") { + $ChangerFunc = \&DarwinLibs if ($libs); + $ChangerFunc = \&DarwinBins if ($bins); + $ChangerFunc = \&DarwinBundles if ($bundles); + $CheckLibs = \&CheckDarwinLibs; + $changer = "/usr/bin/install_name_tool" if (!$changer); + $changerOption = "-change"; +} +elsif ($sysArch eq "linux") { + $ChangerFunc = \&LinuxLibs if ($libs); + $ChangerFunc = \&LinuxBins if ($bins); + $CheckLibs = \&CheckLinuxLibs; + if ($myChanger) { + $changer = $myChanger; + $changerOption = $myChangerOpt; + $changerList = $myChangerList; + } + else { + $changer = qx(which patchelf 2> /dev/null); + chomp $changer; + if ($changer) { + $changerOption = "--set-rpath"; + $changerList = "--print-rpath"; + } + else { + $changer = qx(which chrpath 2> /dev/null); + $changerOption = "-r"; + $changerList = "-l"; + } + } + +} +else { + Usage("Unsupported system ($sysArch) - can do Linux and MacOSX"); +} + +# Ensure we have an RPATH changer program +if (!$changer || !(-e $changer)) { + print STDERR " +*********** ERROR - No changer utility found for $sysArch platform *********** +Darwin uses the install_name_tool utility. Linux uses either patchelf or +chrpath, both of which are third party utilities. It may also be as simple +as adding the proper directory where these programs reside into your PATH +environment variable. +"; + exit (1); +} + +# Get the maps for each parameter +my @oldlibs = ParsePaths($oldpath); +my @newlibs = ParsePaths($newpath); +$CheckLibs->(\@oldlibs, \@newlibs); + +# Parse the relocation directories +my @libprefix = ParsePaths($relocdir); + +# Read the library map if provided +if ($libmap) { + open (LMAP, "<$libmap") or die "Could not open library map file ($libmap)\n"; + my @lmaps = ; + chomp @lmaps; + close (LMAP); + my @oldmap = (); + my @newmap = (); + my $lineno = 0; + map { + my $mline = Trim($_); + $lineno++; + # Ignore if a # in column 1 + if (! ($mline =~ m/^#/)) { + my @parts = split(/ +/, $mline); + my $pcount = scalar @parts; + die "Bad form at line $lineno - expected two columns (old new) libraries" + if ($pcount != 2); + push @oldmap, $parts[0]; + push @newmap, $parts[1]; + } + } @lmaps; + + + $CheckLibs->(\@oldmap, \@newmap); + +# Add library maps to input list in order specified + if ($prepend) { + push @oldmap, @oldlibs; + push @newmap, @newlibs; + @oldlibs = @oldmap; + @newlibs = @newmap; + } + else { + push @oldlibs, @oldmap; + push @newlibs, @newmap; + } + $CheckLibs->(\@oldlibs, \@newlibs); +} + + +# Initialize empty library list to contain affected libraries list (MacOSX). +my @libraries = (); +if (($update) && (-e $liblog)) { + print "Opening/loading library log file $liblog\n" if ($verbose); + open (LIBLOG, "<$liblog") or die "Cannot open library log file $liblog\n"; + @libraries = ; + chomp @libraries; + close (LIBLOG); +} + +# Loop through all input files. Initialize error list +my @errfiles = (); +foreach $file0 (@ARGV) { + print "\nProcessing file $file0...\n" if ($verbose); + $ChangerFunc->(\@oldlibs, \@newlibs, "$file0"); +} + +my $total = scalar @ARGV; +my $logged = scalar @libraries; +my $errors = scalar @errfiles; + +## Processing information +print "Total Files: $total\n"; +print "Libraries: $logged\n"; +map { print "$_\n" } @libraries if ($verbose); +print "Errors: $errors\n"; +map { print "$_\n" } @errfiles if ($verbose); + +# If specifed write out the unique libraries found. +if ($liblog) { + open (LIBS, ">$liblog") or die "Could not create file list ($liblog)\n"; + map { print LIBS "$_\n" } @libraries; + close (LIBS); +} + +# If specifed write out the error log if any occured +if ($errlog && ($errors > 0)) { + open (ERRS, ">>$errlog") or die "Could not open/create error file ($errlog)\n"; + map { print ERRS "$_\n" } @errlog; + close (ERRS); +} + + +exit(0); + +##################################################################### +# Parse out the paths of the libraries separated by colons. +##################################################################### +sub Trim { + my ($str) = @_; + $str =~ s/^\s+//; + $str =~ s/\s+$//; + return ($str); +} + +##################################################################### +# Parse out the paths of the libraries separated by colons. +##################################################################### +sub ParsePaths { + my ($paths) = @_; + my @parts = split(/:/, $paths); + my @lpaths = (); + map { push @lpaths, Trim("$_") } @parts; + return (@lpaths); +} + + +##################################################################### +# Check libraries for validity for Linux system processing +##################################################################### +sub CheckLinuxLibs { + my ($old, $new) = @_; + return; +} + +##################################################################### +# Check libraries for validity for Darwin system processing +##################################################################### +sub CheckDarwinLibs { + my ($old, $new) = @_; + my @dold = @$old; + my @dnew = @$new; + my $dold_size = scalar @dold; + my $dnew_size = scalar @dnew; + +## Check sizes + if (($dold_size != $dnew_size) && ($dnew_size != 1)) { + print STDERR "Number of old .vs. new not equal or new not one newpath\n"; + map { print STDERR "Old: $_\n" } @dold; + print STDERR "\n"; + map { print STDERR "New: $_\n" } @new; + exit (2); + } + +## Copy the last one of new to fill out the array to match the size +## of old + while ($dnew_size != $dold_size) { + push @$new, @$new[$dnew_size-1]; + $dnew_size++; + } + +## Now check to ensure that each library path in old is not a substring +## of any other on as that is probably not what is intended and erroneous. + my $conflicts = 0; + for (my $i = 0 ; $i < $dold_size-1 ; $i++) { + my $first = @dold[$i]; + for (my $j = $i+1 ; $j < $dold_size ; $j++) { + my $last = @dold[$j]; + if ($last =~ m!^$first!) { + print STDERR "$first ($i) is a substring of $last ($j) posing a conflict!\n"; + $conflicts++; + } + } + } + + if ($conflicts > 0) { + print STDERR " +You must reorder the old path list as it will cause trouble. Subsequent paths +that contain a subpath of a previous entry will produce an incorrect path. +This is almost certainly not what is intended. Reorder and try again. +"; + exit (3); + } + return; +} + +##################################################################### +# Update library log with input if not already in list +##################################################################### +sub AddLibrary { + my ($lib, $oldprefix) = @_; +# Determine if a user passed a specific path location and replace +# the existing prefix with it. + foreach $i (@libprefix) { + (my $reloclib = $lib) =~ s!$oldprefix!$i!; + if (-e $reloclib) { + $lib = $reloclib; + last; + } + } + +# Determine if the library already exits in the list + map { + return if ("$_" eq "$lib"); + } @libraries; + +# if it reaches here, add the new library + push @libraries, $lib; + return; +} + +##################################################################### +# Change MacOSX binaries library runtime paths +##################################################################### +sub DarwinPaths { + my ($file0) = @_; + my $command = "otool -L $file0"; + printCommand($command) if ($dryrun || $verbose); + my @paths = qx($command); + if ($? != 0) { + push @errfiles, $file0; + print STDERR "Cannot get library paths for file $file0\n" if ($verbose); + return (()); + } + chomp @paths; + shift (@paths); # First line returns the file name, ignore it + my @darwinLibs = (); + map { + my @parts = split(/ /,$_); + my $lib = shift @parts; + $lib = Trim($lib); + push @darwinLibs, $lib; + } @paths; + return (@darwinLibs); +} + +##################################################################### +# Change MacOSX binaries (executables or libraries) runtime paths +##################################################################### +sub ChangeDarwinLibPath { + my ($library, $oldpaths, $newpaths, $file0, $option) = @_; + my $old_size = scalar @$oldpaths; + my $new_size = scalar @$newpaths; + for (my $i = 0 ; $i < $old_size ; $i++) { + my $opath = @$oldpaths[$i]; + if ($library =~ m!^$opath! ) { + AddLibrary("$library", "$opath"); + my $npath = @$newpaths[$i]; + $npath = $install_root if ($option eq "-id"); + (my $newlib = $library) =~ s!$opath!$npath!; + print "\n\nChange $library to $newlib in $file0\n" if ($verbose); + my $target = $library if ($option eq "-change"); + my $command = "$changer $option $target $newlib $file0"; + if (execCommand($command) != 0) { + push @errfiles, $file0; + print STDERR "DarwinBins - Alteration of library path $library failed in file $file0\n" if ($verbose); + return (-1); + } + return (1); ## indicate success + } + } + return (0); +} + +##################################################################### +# Change MacOSX library install names and any runtime libraries +# contained therein. +##################################################################### +sub DarwinLibs { + my ($oldpath, $newpath, $file0) = @_; + my @paths = DarwinPaths($file0); + my $libid = shift @paths; + ChangeDarwinLibPath($libid, \@$oldpath, \@$newpath, $file0, "-id") if ($install_root); + map { + ChangeDarwinLibPath($_, \@$oldpath, \@$newpath, $file0, $changerOption); + } @paths; + return; +} + +##################################################################### +# Change MacOSX library install names and any runtime libraries +# contained therein. +##################################################################### +sub DarwinBundles { + my ($oldpath, $newpath, $file0) = @_; + my @paths = DarwinPaths($file0); + map { + ChangeDarwinLibPath($_, \@$oldpath, \@$newpath, $file0, $changerOption); + } @paths; + return; +} + +##################################################################### +# Change MacOSX binaries library runtime paths. This should also +# be used for (Qt) plugins (bundles). +##################################################################### +sub DarwinBins { + my ($oldpath, $newpath, $file0) = @_; + my $old_size = scalar @$oldpath; + my $new_size = scalar @$newpath; + my @paths = DarwinPaths($file0); + map { + ChangeDarwinLibPath($_, \@$oldpath, \@$newpath, $file0, $changerOption); + } @paths; + + return; +} + +##################################################################### +# Change MacOSX binaries (executables or libraries) runtime paths +##################################################################### +sub ChangeLinuxLibPath { + my ($library, $oldpaths, $newpaths, $file0, $option) = @_; + my $old_size = scalar @$oldpaths; + my $new_size = scalar @$newpaths; + for (my $i = 0 ; $i < $old_size ; $i++) { + my $opath = @$oldpaths[$i]; + if ($library =~ m!^$opath! ) { +## Got a pattern match on the existing rpath. Construct new rpath. + map { + my $llib = $_; + my $quote = "\\" if ($llib =~ m!^\$!); + $rpath .= "${colon}${quote}${llib}"; + $colon = ":"; + } @$newpath; + +## Modify the path + my $command = "$changer $option $rpath $file0 2>&1 > /dev/null"; + if (execCommand($command) != 0) { + push @errfiles, $file0; + print "ChangeLinuxLibPath - Error changing RPATH in library $file0\n" if ($verbose); + return(-1); ## failed + } + return (1); ## indicate success + } + } + return (0); +} + +##################################################################### +# Change Linux library install names +##################################################################### +sub LinuxLibs { + my ($oldpath, $newpath, $file) = @_; + +## Check existing library paths + my $runpath = qx($changer $changerList $file 2>&1); + if ($? != 0) { + push @errfiles, $file0; + print "LinuxLibs - Error on RPATH test in file $file\n" if ($verbose); + return (-1); + } + chomp $runpath; + my $status = ChangeLinuxLibPath($runpath, \@$oldpath, \@$newpath, + $file, $changerOption); + return ($status); +} + +##################################################################### +# Change Linux library install names +##################################################################### +sub LinuxBins { + my ($oldpath, $newpath, $file) = @_; + my $rpath = ""; + my $colon = ""; + map { + my $llib = $_; + my $quote = "\\" if ($llib =~ m!^\$!); + $rpath .= "${colon}${quote}${llib}"; + $colon = ":"; + } @$newpath; + + ## Change the path + my $command = "$changer $changerOption $rpath $file 2>&1 > /dev/null"; + my $status = execCommand($command); + if ($status != 0) { + push @errfiles, $file; + print "LinuxBins - Error changing RPATH test in binary $file\n" if ($verbose); + $status = -1; + } + return ($status); +} + + +##################################################################### +# printCommand - prints the command line to be executed +# Call: printCommand($command); +##################################################################### +sub printCommand { + my ($command) = @_; + print "$command\n"; +} + +##################################################################### +# printCommand - prints the command line to be executed +# Call: printCommand($command); +##################################################################### +sub execCommand { + my ($command) = @_; + printCommand($command) if ($verbose || $dryrun); + if ($dryrun) { return(0); } + else { return (system($command)); } +} + + +##################################################################### +# Prints usage +##################################################################### +sub Usage { + my ($message) = @_; + print STDERR "$message\n" if ($message); + print STDERR $usage; + exit ($BAD_INPUT); +} + diff --git a/isis/scripts/darwin_lib_paths.lis b/isis/scripts/darwin_lib_paths.lis new file mode 100644 index 0000000000000000000000000000000000000000..eaff8ed336a6a41af40a22cafa47677264c8e1fb --- /dev/null +++ b/isis/scripts/darwin_lib_paths.lis @@ -0,0 +1,8 @@ +# $Id: darwin_lib_paths.lis,v 1.1 2010/04/09 23:19:58 slambright Exp $ +# Default 3rdParty locations for Max OS X libraries. The first column servers +# as a pattern to search all cooked library paths and replace with second +# column. Order is crtical as more complete paths must come before +# directories higher in the hierarchy. +/usgs/pkgs/local(.*?)lib @loader_path +/opt/local/libexec/qt4-mac/lib @loader_path +/opt/local/lib @loader_path diff --git a/isis/scripts/isis3Startup.csh b/isis/scripts/isis3Startup.csh new file mode 100755 index 0000000000000000000000000000000000000000..61786f908526a4b76724e11ea80faae19aa126ca --- /dev/null +++ b/isis/scripts/isis3Startup.csh @@ -0,0 +1,79 @@ +#!/bin/csh +################################################################################ +# This file should be sourced within your current shell using the "source" +# command. Since this is only a beta version we do not suggest you add this +# command to your startup file +# +# On the command line type: +# > setenv ISISROOT ???? +# > source isis3Startup.csh +# +# Replace the "????" in the above command line with the path you installed +# the Isis distribution +# +#_HIST FEB 21 2006 - Jac Shinaman - USGS, Astrogeology - added code to prevent +# duplication of paths +# FEB 22 2006 - JRS - changed OsType to Platform to avoid conflicts with +# internal USGS initIsis.csh script +# JUL 12 2006 - Robert Wallace - Add ISIS3TESTDATA environment variable +# AUG 25 2008 - Kris Becker - Changed all references of DYLD_LIBRARY_PATH +# to DYLD_FALLBACK_LIBRARY_PATH. See +# http://www.osxfaq.com/man/1/dyld.ws. +# MAR 12 2009 - Christopher Austin - Changed the way ISIS3TESTDATE is set +# to prevent its setting for outside groups and default +# to "/usgs/cpkgs/isis3/testData" +#_VER $Id: isis3Startup.csh,v 1.5 2010/03/16 19:40:22 ehyer Exp $ +#_END +################################################################################ +# Check parameters +set QTPLUGINPATH = "true" +foreach arg ($argv) + if ( "$arg" == "-noqtpluginpath" ) then + set QTPLUGINPATH = "false" + else + echo "Uknown argument $arg" + exit 1 + endif +end + +# Establish a platform switch variable +set Platform = `uname -s` + +# Initialize the ISISROOT environment variable if it doesn't exist +# TODO: Test is obsolete, fail if no isisroot is set +if ($?ISISROOT == 0) then + setenv ISISROOT /usgs/pkgs/isis3/isis +endif + +# Initialize the ISIS3DATA environment variable +if (-d $ISISROOT/../data) then + setenv ISIS3DATA $ISISROOT/../data +else + setenv ISIS3DATA /usgs/cpkgs/isis3/data +endif + +# Initialize the ISIS3TESTDATA environment variable +if (-d /usgs/cpkgs/isis3/testData) then + setenv ISIS3TESTDATA /usgs/cpkgs/isis3/testData +else + if (-d $ISISROOT/../testData) then + setenv ISIS3TESTDATA $ISISROOT/../testData + endif +endif + +# Insert ISISROOT/bin in the PATH environment variable if it's not already there +if ($?PATH == 0) then + setenv PATH "$ISISROOT/bin" +else + printenv PATH |grep $ISISROOT/bin >& /dev/null + if ( $status != 0) then + setenv PATH "${PATH}:$ISISROOT/bin" + endif +endif + +# Create QT_PLUGIN_PATH env variable +if ($QTPLUGINPATH == "true") then + setenv QT_PLUGIN_PATH "$ISISROOT/3rdParty/plugins" +endif + +unset Platform diff --git a/isis/scripts/isis3Startup.sh b/isis/scripts/isis3Startup.sh new file mode 100755 index 0000000000000000000000000000000000000000..60ef7154409b34447ce4eca878919aec6366d7ad --- /dev/null +++ b/isis/scripts/isis3Startup.sh @@ -0,0 +1,46 @@ +#!/bin/sh +# +# This file should be executed within your current shell using the "." command +# Since this is only a beta version we do not suggest you add this +# command to your startup file +# +# On the command line type: +# > set ISISROOT=???? +# > . isis3Startup.sh +# +# Replace the "????" in the above command line with the path you installed +# the Isis distribution +# +if [ ! "$ISISROOT" ]; then + ISISROOT=/usgs/pkgs/isis3/isis + export ISISROOT +fi + +if [ -d $ISISROOT/../data ]; then + ISIS3DATA=$ISISROOT/../data +else + ISIS3DATA=/usgs/cpkgs/isis3/data +fi +export ISIS3DATA + +# Do not export when used by outside groups +if [ -d /usgs/cpkgs/isis3/testData ]; then + ISIS3TESTDATA=/usgs/cpkgs/isis3/testData + export ISIS3TESTDATA +else + if [ -d $ISISROOT/../testData ]; then + ISIS3TESTDATA=$ISISROOT/../testData + export ISIS3TESTDATA + fi +fi + +if [ "$PATH" ]; then + PATH="${PATH}:${ISISROOT}/bin" +else + PATH="$ISISROOT/bin" +fi +export PATH + +# Create QT_PLUGIN_PATH env variable +QT_PLUGIN_PATH="$ISISROOT/3rdParty/plugins" +export QT_PLUGIN_PATH diff --git a/isis/scripts/isis_bins_paths.lis b/isis/scripts/isis_bins_paths.lis new file mode 100644 index 0000000000000000000000000000000000000000..e8f40349041cdb0a9126dd84691ef496488720fa --- /dev/null +++ b/isis/scripts/isis_bins_paths.lis @@ -0,0 +1,7 @@ +# $Id: isis_bins_paths.lis,v 1.1 2010/04/09 23:19:58 slambright Exp $ +# ISIS application library path modifications are set to lookup relative +# to the rpath directories as specified at build/link time in the main apps. +/usgs/pkgs/local(.*?)lib @rpath/3rdParty/lib +/(.+)/isis/lib @rpath/lib +/opt/local/libexec/qt4-mac/lib @rpath/3rdParty/lib +/opt/local/lib @rpath/3rdParty/lib diff --git a/isis/scripts/qt_paths.lis b/isis/scripts/qt_paths.lis new file mode 100644 index 0000000000000000000000000000000000000000..492bf2291910f12a873febff902876e24a63382f --- /dev/null +++ b/isis/scripts/qt_paths.lis @@ -0,0 +1,9 @@ +# $Id: qt_paths.lis,v 1.1 2010/04/09 23:19:58 slambright Exp $ +# Qt Frameworks need relative path loading of all libraries they reference. +# They all will exist in $ISISROOT/3rdpaty/lib. The @loader_path is where +# the current library exists in the framework which is assumed to be +# $ISISROOT/3rdparty/lib/qt*.framework/Versions/4/. The path to all libraries +# are therefore fixed and the same path for all. +/usgs/pkgs/local(.*?)lib @loader_path/../../.. +/opt/local/libexec/qt4-mac/lib @loader_path/../../.. +/opt/local/lib @loader_path/../../.. diff --git a/isis/scripts/qt_plugins_paths.lis b/isis/scripts/qt_plugins_paths.lis new file mode 100644 index 0000000000000000000000000000000000000000..2f667031968b7ca33f4148deb5f09e89ec5ad697 --- /dev/null +++ b/isis/scripts/qt_plugins_paths.lis @@ -0,0 +1,11 @@ +# $Id: qt_plugins_paths.lis,v 1.1 2010/04/09 23:19:58 slambright Exp $ +# Qt plugis need relative path loading of all libraries they reference. +# They all will exist in $ISISROOT/3rdParty/lib. The @loader_path is where +# the current library exists in the plugin bundle which is assumed to be +# $ISISROOT/3rdParty/plugins/*/*/bundle. The path to all libraries +# are therefore fixed and the same path for all. +/usgs/pkgs/local(.*?)lib @loader_path/../../lib +/opt/local/libexec/qt4-mac/lib @loader_path/../../lib +/opt/local/lib/postgresql83 @loader_path/../../lib +/opt/local/lib/mysql5/mysql @loader_path/../../lib +/opt/local/lib @loader_path/../../lib diff --git a/isis/scripts/unitTester b/isis/scripts/unitTester new file mode 100755 index 0000000000000000000000000000000000000000..c7a1ffa58ae56d9acbda19f2a75172725c2bc784 --- /dev/null +++ b/isis/scripts/unitTester @@ -0,0 +1,73 @@ +#!/bin/sh +#--------------------------------------------------------------------------- +# This script is used by the Isis make system to execute the unitTest for +# objects in the Isis API. It simply builds the unitTest, executes the +# unitTest, and compares the difference between the output and the truth +# file. If any portion of the script fails or there are differences the +# the script exits with failure otherwise it exits with success. +# +# Error Code Meaning +# 0 Success +# 1 No truth file +# 2 No unitTest +# 3 Couldn't build unitTest +# 4 UnitTest crashed +# 5 Truth file and results differ +# 99 Unexpected System error +# +#--------------------------------------------------------------------------- +if [ -f /usr/xpg4/bin/grep ] +then + GREP=/usr/xpg4/bin/grep +else + GREP=grep +fi + +if [ ! -f unitTest.cpp ] +then + exit 2 +fi + +CWD=`pwd` +if [ $1 = "" ]; then + TRUTH=`basename $CWD`_`uname -s`_`uname -p`.truth || exit 99; +else + TRUTH=`basename $CWD`_`uname -s`_`uname -p`_${1}.truth || exit 99; +fi + +if [ ! -f $TRUTH ] +then + TRUTH=`basename $CWD`.truth || exit 99 + if [ ! -f $TRUTH ] + then + exit 1 + fi +fi + +make unitTest || exit 3 +RESULTS="unitTest.output" +/bin/rm -f $RESULTS +if [ ! -f unitTest.exclude ] +then + ./unitTest 1>$RESULTS 2>&1 || exit 4 + if `diff $TRUTH $RESULTS 1>/dev/null 2>&1` + then + /bin/rm $RESULTS + exit 0 + else + exit 5 + fi +else + ./unitTest 2>&1 | $GREP -v -f unitTest.exclude 1>$RESULTS 2>&1 || exit 4 + TRUTH2="temporary.unitTest.truth" + /bin/rm -f $TRUTH2 + cat $TRUTH | $GREP -v -f unitTest.exclude 1>$TRUTH2 2>&1 || exit 99 + if `diff $TRUTH2 $RESULTS 1>/dev/null 2>&1` + then + /bin/rm $RESULTS $TRUTH2 + exit 0 + else + /bin/rm $TRUTH2 + exit 5 + fi +fi diff --git a/isis/src/Makefile b/isis/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..41ddf8880c240465681474bdc481a70d6d220430 --- /dev/null +++ b/isis/src/Makefile @@ -0,0 +1,63 @@ +include $(ISISROOT)/make/isismake.macros + +PACKAGES = $(filter-out Makefile docsys CVS IsisObjectConvert.xsl, $(wildcard *)) + +applications: + for i in $(PACKAGES); do \ + printf %-46s " Working on Package [$$i]"; \ + cd $$i; $(MAKE) applications; cd ..; \ + done + +api: + for i in $(PACKAGES); do \ + echo " Working on Package [$$i] ("`date +%T`")"; \ + cd $$i; $(MAKE) api; cd ..; \ + done + +objects: + for i in $(PACKAGES); do \ + echo " Working on Package [$$i]"; \ + cd $$i; $(MAKE) objects; cd ..; \ + done +# Saved for inside if +# cd $$i; $(MAKE) clean; $(MAKE) objects; cd ..; \ + +includes: + for i in $(PACKAGES); do \ + echo " Working on Package [$$i] ("`date +%T`")"; \ + cd $$i; $(MAKE) includes; cd ..; \ + done + +documentation: + for i in $(PACKAGES); do \ + printf %-46s " Working on Package [$$i]"; \ + cd $$i; $(MAKE) documentation; cd ..; \ + done + +clean: + for i in $(PACKAGES); do \ + echo " Working on Package [$$i]"; \ + cd $$i; $(MAKE) clean; cd ..; \ + done + cd docsys; $(MAKE) clean; cd ..; + +unitTest: + for i in $(PACKAGES); do \ + if [ "$$i" != "qisis" ]; \ + then \ + echo " Working on Package [$$i]"; \ + cd $$i; $(MAKE) unitTest; cd ..; \ + fi \ + done + +appTest: + for i in $(PACKAGES); do \ + printf %-46s " Working on Package [$$i]"; \ + cd $$i; $(MAKE) appTest; cd ..; \ + done + +catTest: + for i in $(PACKAGES); do \ + printf %-46s " Working on Package [$$i]"; \ + cd $$i; $(MAKE) catTest; cd ..; \ + done diff --git a/isis/src/apollo/Makefile b/isis/src/apollo/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/apollo/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricCamera.cpp b/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7e12fc4a5717391f9afc2d1b99917248ef48de4 --- /dev/null +++ b/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricCamera.cpp @@ -0,0 +1,63 @@ +#include "ApolloMetricCamera.h" +#include "ApolloMetricDistortionMap.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "Filename.h" +#include "iException.h" +#include "iString.h" +#include "NaifStatus.h" +#include "ReseauDistortionMap.h" + +using namespace std; + +namespace Isis { + namespace Apollo { + // constructors + ApolloMetricCamera::ApolloMetricCamera (Isis::Pvl &lab) : Isis::FramingCamera(lab) { + NaifStatus::CheckErrors(); + + // Get the camera characteristics + SetFocalLength(); + SetPixelPitch(); + + // Setup detector map + new CameraDetectorMap(this); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this, NaifIkCode()); + focalMap->SetDetectorOrigin(ParentSamples()/2.0, ParentLines()/2.0); + + const PvlGroup &inst = lab.FindGroup("Instrument", Pvl::Traverse); + + iString ppKey("INS" + iString((int)NaifIkCode()) + "_PP"); + iString odkKey("INS" + iString((int)NaifIkCode()) + "_OD_K"); + iString decenterKey("INS" + iString((int)NaifIkCode()) + "_DECENTER"); + + new ApolloMetricDistortionMap(this, GetDouble(ppKey, 0), + GetDouble(ppKey, 1), GetDouble(odkKey, 0), GetDouble(odkKey, 1), + GetDouble(odkKey, 2), GetDouble(decenterKey, 0), + GetDouble(decenterKey, 1), GetDouble(decenterKey, 2)); + + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + // Create a cache and grab spice info since it does not change for + // a framing camera (fixed spacecraft position and pointing) + // Get the start time in et + string stime = inst["StartTime"]; + double time; + str2et_c(stime.c_str(), &time); + SetEphemerisTime(time); + LoadCache(); + + NaifStatus::CheckErrors(); + } + } +} + +extern "C" Isis::Camera *ApolloMetricCameraPlugin (Isis::Pvl &lab) { + return new Isis::Apollo::ApolloMetricCamera(lab); +} diff --git a/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricCamera.h b/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..861c278e8672f1873a48a67381fe712646deafaa --- /dev/null +++ b/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricCamera.h @@ -0,0 +1,30 @@ +#ifndef ApolloMetricCamera_h +#define ApolloMetricCamera_h + +#include "FramingCamera.h" +/** + * @brief Apollo Metric Camera Model + * + * This is the camera model for the Apollo metric camera. + * + * @ingroup Camera + * + * @author 2006-11-14 Jacob Danton + * + * @internal + * @history 2006-11-14 Jacob Danton - Original Version + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ +namespace Isis { + namespace Apollo { + class ApolloMetricCamera : public FramingCamera { + public: + ApolloMetricCamera (Isis::Pvl &lab); + + ~ApolloMetricCamera () {}; + }; + }; +}; + +#endif diff --git a/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricCamera.truth b/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..0db08d47ac59e99a1dc53499591040306d559cd4 --- /dev/null +++ b/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricCamera.truth @@ -0,0 +1,20 @@ +Unit Test for ApolloCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricDistortionMap.cpp b/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricDistortionMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50686480ab986d6741766b0a02f7854153f76db3 --- /dev/null +++ b/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricDistortionMap.cpp @@ -0,0 +1,144 @@ +#include "ApolloMetricDistortionMap.h" +#include "CameraFocalPlaneMap.h" + +using namespace std; + +namespace Isis { + ApolloMetricDistortionMap::ApolloMetricDistortionMap (Camera *parent, + double xp, double yp, + double k1,double k2, + double k3, double j1, + double j2, double t0) : + CameraDistortionMap(parent) { + + p_xp = xp; + p_yp = yp; + p_k1 = k1; + p_k2 = k2; + p_k3 = k3; + p_j1 = j1; + p_j2 = j2; + p_t0 = t0; + } + + /** + * Compute undistorted focal plane x/y + * + * Compute undistorted focal plane x/y given a distorted focal plane x/y. + * fter calling this method, you can obtain the undistorted + * x/y via the UndistortedFocalPlaneX and UndistortedFocalPlaneY methods + * + * @param dx distorted focal plane x in millimeters + * @param dy distorted focal plane y in millimeters + * + * @return if the conversion was successful + */ + bool ApolloMetricDistortionMap::SetFocalPlane(const double dx, const double dy) { + p_focalPlaneX = dx; + p_focalPlaneY = dy; + + // reducing to principal point offset (xp,yp) + double x = dx - p_xp; + double y = dy - p_yp; + + // r is the distance between the principal point and the measured point on the image + double rr = x*x + y*y; + double rrrr = rr*rr; + + // dr is the radial distortion contribution + // -dt*sin(p_t0) is the decentering distortion contribution in the x-direction + // dt*cos(p_t0) is the decentering distortion contribution in the y-direction + double dr = 1 + p_k1*rr + p_k2*rrrr + p_k3*rr*rrrr; + double dt = p_j1*rr + p_j2*rrrr; + + // image coordinates corrected for principal point, radial and decentering distortion + p_undistortedFocalPlaneX = dr*x - dt*sin(p_t0); + p_undistortedFocalPlaneY = dr*y + dt*cos(p_t0); + + return true; + } + + + /** + * Compute distorted focal plane x/y + * + * Compute distorted focal plane x/y given an undistorted focal plane x/y. + * After calling this method, you can obtain the distorted x/y via the + * FocalPlaneX and FocalPlaneY methods + * + * @param ux undistorted focal plane x in millimeters + * @param uy undistorted focal plane y in millimeters + * + * @return if the conversion was successful + */ + bool ApolloMetricDistortionMap::SetUndistortedFocalPlane(const double ux, const double uy) { + // image coordinates prior to introducing distortion + p_undistortedFocalPlaneX = ux; + p_undistortedFocalPlaneY = uy; + + double xt = ux; + double yt = uy; + + double xx,yy,rr,rrrr,dr; + double xdistortion,ydistortion; + double xdistorted,ydistorted; + double xprevious,yprevious; + // dr is the radial distortion contribution + // -dt*sin(p_t0) is the decentering distortion contribution in the x-direction + // dt*cos(p_t0) is the decentering distortion contribution in the y-direction + double dt; + + xprevious = 1000000.0; + yprevious = 1000000.0; + + double tolerance = 0.000001; + + bool bConverged = false; + + // iterating to introduce distortion... + // we stop when the difference between distorted coordinates + // in successive iterations is at or below the given tolerance + for( int i = 0; i < 50; i++ ) { + xx = xt*xt; + yy = yt*yt; + rr = xx + yy; + rrrr = rr *rr; + + // radial distortion + // dr is the radial distortion contribution + // -dt*sin(p_t0) is the decentering distortion contribution in the x-direction + // dt*cos(p_t0) is the decentering distortion contribution in the y-direction + dr = p_k1*rr + p_k2*rrrr + p_k3*rr*rrrr; + + dt = p_j1*rr + p_j2*rrrr; + + // distortion at the current point location + xdistortion = xt*dr - dt*sin(p_t0); + ydistortion = yt*dr + dt*cos(p_t0); + + // updated image coordinates + xt = ux - xdistortion; + yt = uy - ydistortion; + + // distorted point corrected for principal point + xdistorted = xt + p_xp; + ydistorted = yt + p_yp; + + // check for convergence + if( (fabs(xt - xprevious) <= tolerance) && (fabs(yt - yprevious) <= tolerance) ) { + bConverged = true; + break; + } + + xprevious = xt; + yprevious = yt; + } + + if( bConverged ) { + p_focalPlaneX = xdistorted; + p_focalPlaneY = ydistorted; + } + + return bConverged; + } +} diff --git a/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricDistortionMap.h b/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricDistortionMap.h new file mode 100644 index 0000000000000000000000000000000000000000..09103a2adf95e9b492da61e575edf9fd88493820 --- /dev/null +++ b/isis/src/apollo/objs/ApolloMetricCamera/ApolloMetricDistortionMap.h @@ -0,0 +1,24 @@ +#ifndef ApolloMetricDistortionMap_h +#define ApolloMetricDistortionMap_h + +#include "CameraDistortionMap.h" +#include "Camera.h" + +namespace Isis { + class ApolloMetricDistortionMap : public CameraDistortionMap { + public: + ApolloMetricDistortionMap (Camera *parent, double xp, double yp, double k1, double k2, double k3, double j1, double j2, double t0); + ~ApolloMetricDistortionMap () {}; + + bool SetFocalPlane (const double dx, const double dy); + bool SetUndistortedFocalPlane (const double ux, const double uy); + + private: // parameters below are from camera calibration report + double p_xp, p_yp; //!< principal point coordinates + double p_k1, p_k2, p_k3; //!< coefficients of radial distortion + double p_j1, p_j2; //!< coefficients of decentering distortion + double p_t0; //!< angle between positive x-axis of image and vector to imaged point + //!< used in computation of decentering distortion + }; +}; +#endif diff --git a/isis/src/apollo/objs/ApolloMetricCamera/Camera.plugin b/isis/src/apollo/objs/ApolloMetricCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..e0d1984d24d8c7607433be06c840e64217c9e817 --- /dev/null +++ b/isis/src/apollo/objs/ApolloMetricCamera/Camera.plugin @@ -0,0 +1,15 @@ +Group = Apollo15/Metric + Library = ApolloMetricCamera + Routine = ApolloMetricCameraPlugin + Version = 1 +EndGroup +Group = Apollo16/Metric + Library = ApolloMetricCamera + Routine = ApolloMetricCameraPlugin + Version = 1 +EndGroup +Group = Apollo17/Metric + Library = ApolloMetricCamera + Routine = ApolloMetricCameraPlugin + Version = 1 +EndGroup diff --git a/isis/src/apollo/objs/ApolloMetricCamera/Makefile b/isis/src/apollo/objs/ApolloMetricCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d5230a6aa2224f66f34e2649b719502fbad3297b --- /dev/null +++ b/isis/src/apollo/objs/ApolloMetricCamera/Makefile @@ -0,0 +1,5 @@ +INCS = ApolloMetricCamera.h ApolloMetricDistortionMap.h +SRCS = ApolloMetricCamera.cpp ApolloMetricDistortionMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/apollo/objs/ApolloMetricCamera/unitTest.cpp b/isis/src/apollo/objs/ApolloMetricCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f477ef93cbf1f78aeb9ef574b5b045763f413906 --- /dev/null +++ b/isis/src/apollo/objs/ApolloMetricCamera/unitTest.cpp @@ -0,0 +1,92 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" +#include "Filename.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for ApolloCamera..." << endl; + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + // double knownLat = -87.58875692974748; + // double knownLon = 21.19902564370578; + double knownLat = 12.40717735539371; + double knownLon = 67.74412494987295; + + Isis::Pvl p(Isis::Filename("$apollo15/testData/AS15-M-0533.cropped.cub").Expanded()); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.01) deltaSamp = 0; + if (fabs(deltaLine) < 0.01) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/apollo/objs/Makefile b/isis/src/apollo/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/apollo/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/base/Makefile b/isis/src/base/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/base/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/base/apps/Makefile b/isis/src/base/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/base/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/base/apps/algebra/Makefile b/isis/src/base/apps/algebra/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/algebra/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/algebra/algebra.cpp b/isis/src/base/apps/algebra/algebra.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3088484f7cbab5827630f06dc431b9b189dbe9d4 --- /dev/null +++ b/isis/src/base/apps/algebra/algebra.cpp @@ -0,0 +1,147 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void add (vector &in, + vector &out); +void sub (vector &in, + vector &out); +void mult (vector &in, + vector &out); +void div (vector &in, + vector &out); +void unary (Buffer &in, Buffer &out); + +double Isisa,Isisb,Isisc,Isisd,Isise; + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and output files + UserInterface &ui = Application::GetUserInterface(); + // Setup the input and output cubes + p.SetInputCube("FROM1"); + if (ui.WasEntered ("FROM2")) p.SetInputCube("FROM2"); + p.SetOutputCube ("TO"); + + // Get the coefficients + Isisa = ui.GetDouble ("A"); + Isisb = ui.GetDouble ("B"); + Isisc = ui.GetDouble ("C"); + Isisd = ui.GetDouble ("D"); + Isise = ui.GetDouble ("E"); + + // Start the processing based on the operator + string op = ui.GetString ("OPERATOR"); + if (op == "ADD" ) p.StartProcess(add); + if (op == "SUBTRACT") p.StartProcess(sub); + if (op == "MULTIPLY") p.StartProcess(mult); + if (op == "DIVIDE") p.StartProcess(div); + if (op == "UNARY") p.StartProcess(unary); + + // Cleanup + p.EndProcess(); +} + +// Add routine +void add (vector &in, vector &out) { + Buffer &inp1 = *in[0]; + Buffer &inp2 = *in[1]; + Buffer &outp = *out[0]; + + // Loop for each pixel in the line. + for (int i=0; i &in, vector &out) { + Buffer &inp1 = *in[0]; + Buffer &inp2 = *in[1]; + Buffer &outp = *out[0]; + + // Loop for each pixel in the line. + for (int i=0; i &in, vector &out) { + Buffer &inp1 = *in[0]; + Buffer &inp2 = *in[1]; + Buffer &outp = *out[0]; + + // Loop for each pixel in the line. + for (int i=0; i &in, vector &out) { + Buffer &inp1 = *in[0]; + Buffer &inp2 = *in[1]; + Buffer &outp = *out[0]; + + // Loop for each pixel in the line. + for (int i=0; i + + + + + Performs algebra on either one or two cubes + + + + This program will perform simple algebra on either one or two cubes. + The two cubes may be added, subtracted, multiplied or divided. The + following equations are used: + +
+    UNARY:      out = (A * from1) + C
+    ADD:        out = ((from1 - D) * A) + ((from2 - E) * B) + C
+    SUBTRACT:   out = ((from1 - D) * A) - ((from2 - E) * B) + C
+    MULTIPLY:   out = ((from1 - D) * A) * ((from2 - E) * B) + C
+    DIVIDE:     out = ((from1 - D) * A) / ((from2 - E) * B) + C
+    
+ + The FROM2 cube must have either one band or the same number of bands as the + FROM1 cube. If the FROM2 cube has one band, then the algebraic formula will + be applied to all bands in FROM1 using that single band in FROM2. If FROM2 + is a multi-band cube, the algebra will be performed between corresponding + bands from FROM1 and FROM2. +
+ + + + Original version + + + + Ported to Isis 3.0, combining add,mad,b16mad and mult. + + + Was not handling special pixel values correctly. If only one input + file, output the input special pixel value. If two input files and + one of the input values is a special pixel value, output a NULL. + + + Changed parameters MULT1,MULT2 and ADD to A,B and C respectively. + + + Removed from Utility category. + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Fixed typo in algebra.xml which caused IsisGui to display names + and input fields incorrectly. + + + Fixed division by zero problem with DIV operator and bug with + single files by adding UNARY operator. + + + Fixed division by zero problem with DIV operator and bug with + single files by adding UNARY operator. + + + Added the D and E coefficients + + + Modifed how special pixels are propagated to the output file. + Originally, all special pixel values and operations resulted in + Null being set to the output pixel. Now if the FROM1 pixel + is a special pixel, it is always propagated to the output file + unchanged without regard of the FROM2 pixel. If FROM1 is + not a special pixel and FROM2 is, the output pixel is set to + Null. + + + Fixed segmenation fault error. If the user did not enter a FROM2 value then tried to perform a non-unary operation + the program would crash. FIX:The program will inform the user of the error without crashing so they can make the + proper correction. + + + + + Math and Statistics + + + + + ratio + poly + + + + + add + mad + b16mad + mult + + + + + + cube + input + + First Input cube + + + Use this parameter to select the cube which is the first term in + the equation. + + + *.cub + + + + + cube + input + + Second Input Cube + + + This image will be used as the second term in the equation. This + cube must have either one band or the same number of bands as the + cube in FROM1. If this cube has one band, then the single band will + be applied to each band in FROM1 using the equation. If this cube + has multi-bands then each corresponding band in FROM2 is applied to + FROM1 using the equation. + + + *.cub + + + + + cube + real + output + + Output cube + + + This file will contain the results of the algebraically manipulated + cubes. + + + + + + + string + SUBTRACT + + Operation performed on cubes + + + Mathematical operation performed on the two input cubes + + + + + + + + + + + + double + + 1.0 + + Multiplicative constant for first input cube + + This defines the multiplicative constant for the first input + cube. + + + + + double + + 1.0 + + Multiplicative constant for second input cube + + This defines the multiplicative constant for the second input + cube. + + + + + double + + 0.0 + + Additive constant + + This defines the additive constant for entire equation. + + + + + double + + 0.0 + + Additive constant + + This defines the additive constant for the first input cube. + + + + + double + + 0.0 + + Additive constant + + This defines the additive constant for second input cube. + + + + +
diff --git a/isis/src/base/apps/algebra/tsts/Makefile b/isis/src/base/apps/algebra/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/algebra/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/algebra/tsts/add/Makefile b/isis/src/base/apps/algebra/tsts/add/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8caa1557ba4fd44769e1b6d54f25e3b4447d212a --- /dev/null +++ b/isis/src/base/apps/algebra/tsts/add/Makefile @@ -0,0 +1,12 @@ +APPNAME = algebra + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from1=$(INPUT)/isisTruth.cub+1 \ + from2=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/algebraTruth2.cub \ + operator=add \ + a=1 \ + b=1 \ + c=0 > /dev/null; diff --git a/isis/src/base/apps/algebra/tsts/divide/Makefile b/isis/src/base/apps/algebra/tsts/divide/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a55395bd5288f7849e65a0a424ba718141f69db9 --- /dev/null +++ b/isis/src/base/apps/algebra/tsts/divide/Makefile @@ -0,0 +1,12 @@ +APPNAME = algebra + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from1=$(INPUT)/isisTruth.cub+1 \ + from2=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/algebraTruth5.cub \ + operator=divide \ + a=1 \ + b=1 \ + c=0 > /dev/null; diff --git a/isis/src/base/apps/algebra/tsts/multiply/Makefile b/isis/src/base/apps/algebra/tsts/multiply/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3ab29eb3ed0983f4d3ffa381502723bd44295a6c --- /dev/null +++ b/isis/src/base/apps/algebra/tsts/multiply/Makefile @@ -0,0 +1,12 @@ +APPNAME = algebra + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from1=$(INPUT)/isisTruth.cub+1 \ + from2=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/algebraTruth4.cub \ + operator=multiply \ + a=1 \ + b=1 \ + c=0 > /dev/null; diff --git a/isis/src/base/apps/algebra/tsts/subtract/Makefile b/isis/src/base/apps/algebra/tsts/subtract/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fbb26950b88756b7a2f5a29ba49ae436cfa4fbd6 --- /dev/null +++ b/isis/src/base/apps/algebra/tsts/subtract/Makefile @@ -0,0 +1,11 @@ +APPNAME = algebra + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from1=$(INPUT)/isisTruth.cub+1 \ + from2=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/algebraTruth3.cub \ + a=1 \ + b=1 \ + c=0 > /dev/null; diff --git a/isis/src/base/apps/algebra/tsts/unary/Makefile b/isis/src/base/apps/algebra/tsts/unary/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d9f1c7a84fe7f74d3cd53232129ee363c39c28bb --- /dev/null +++ b/isis/src/base/apps/algebra/tsts/unary/Makefile @@ -0,0 +1,10 @@ +APPNAME = algebra + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from1=$(INPUT)/isisTruth.cub+1 \ + to= $(OUTPUT)/algebraTruth1.cub \ + operator=unary \ + a=1 \ + c=0 > /dev/null; diff --git a/isis/src/base/apps/appjit/LineScanCameraRotation.cpp b/isis/src/base/apps/appjit/LineScanCameraRotation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..21b18df78d20b5252c846cbdfa8d60c2ddad07cf --- /dev/null +++ b/isis/src/base/apps/appjit/LineScanCameraRotation.cpp @@ -0,0 +1,252 @@ +#include +#include +#include +#include +#include +#include + +#include "LineScanCameraRotation.h" +#include "Quaternion.h" +#include "LineEquation.h" +#include "BasisFunction.h" +#include "LeastSquares.h" +#include "BasisFunction.h" +#include "PolynomialUnivariate.h" +#include "iString.h" +#include "iException.h" +#include "Table.h" +#include "NaifStatus.h" + +// Declarations for binding for Naif Spicelib routine refchg_ that does not have +// a wrapper +extern int refchg_(integer *frame1, integer *frame2, doublereal *et, + doublereal *rotate); + +namespace Isis { + /** + * Construct an empty SpiceRotation class using a valid Naif frame code to + * set up for getting rotation from Spice kernels. See required reading + * ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/ascii/individual_docs/naif_ids.req + * + * @param frameCode Valid naif frame code. + */ + LineScanCameraRotation::LineScanCameraRotation( int frameCode, Isis::Pvl &lab, std::vector timeCache, double tol ) : SpiceRotation ( frameCode ) { + // Initialize optional paramters; + p_pitchRate = 0.; + p_yaw = 0.; + + // Load the Spice kernels to get state matrices + p_spi = 0; + p_spi = new Isis::Spice(lab); + + // Make sure the kernels are written to the labels and not just the tables (blobs) + if (!p_spi->HasKernels(lab)) { + std::string msg = "The master file must contain the kernel files. Rerun spiceinit with attach=no"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_cacheTime = timeCache; +// std::cout<InstrumentRotation()->SetFrame(frameCode); + p_crot = p_spi->InstrumentRotation(); + p_prot = p_spi->BodyRotation(); + p_spos = p_spi->InstrumentPosition(); + // Load the line scan specific rotation matrix caches before loading the regular Spice caches because + // the CreateCache method will unload all the kernels after the caches are created + LoadCache(); + p_spi->CreateCache(timeCache[0],timeCache[timeCache.size()-1],timeCache.size(), tol); + } + + + + /** + * Destroys the LineScanComeraRotation object + */ + LineScanCameraRotation::~LineScanCameraRotation () { + if (p_spi != 0) delete p_spi; + } + + + + /** Cache J2000 rotation quaternion over a time range. + * + * This method will load an internal cache with frames over a time + * range. This prevents the NAIF kernels from being read over-and-over + * again and slowing an application down due to I/O performance. Once the + * cache has been loaded then the kernels can be unloaded from the NAIF + * system. + * + */ + void LineScanCameraRotation::LoadCache () { + NaifStatus::CheckErrors(); + + double startTime = p_cacheTime[0]; + int size = p_cacheTime.size(); + double endTime = p_cacheTime[size-1]; + // TODO Add a label value to indicate pointing is already decomposed to line scan angles + // and set p_pointingDecomposition=none,framing angles, or line scan angles. + // Also add a label value to indicate jitterOffsets=jitterFileName + // Then we can decide whether to simply grab the crot angles or do new decomposition and whether + // to apply jitter or throw an error because jitter has already been applied. + + // *** May need to do a frame trace and load the frames (at least the constant ones) *** + + // Loop and load the cache + double cacheSlope = 0.0; + if (size > 1) cacheSlope = (endTime - startTime) / (double) (size - 1); + double state[6]; + double lt; + NaifStatus::CheckErrors(); + + double R[3]; // Direction of radial axis of line scan camera + double C[3]; // Direction of cross-track axis + double I[3]; // Direction of in-track axis + double *velocity; + std::vector IB(9); + std::vector CI(9); + SpiceRotation *prot = p_spi->BodyRotation(); + SpiceRotation *crot = p_spi->InstrumentRotation(); + + for (std::vector::iterator i=p_cacheTime.begin(); iSetEphemerisTime(et); + crot->SetEphemerisTime(et); + + // The following code will be put into method LoadIBcache() + spkezr_c ("MRO", et, "IAU_MARS", "NONE", "MARS", state, <); + NaifStatus::CheckErrors(); + + // Compute the direction of the radial axis (3) of the line scan camera + vscl_c(1./vnorm_c(state), state, R); // vscl and vnorm only operate on first 3 members of state + + // Compute the direction of the cross-track axis (2) of the line scan camera + velocity = state + 3; + vscl_c(1./vnorm_c(velocity), velocity, C); + vcrss_c(R, C, C); + + // Compute the direction of the in-track axis (1) of the line scan camera + vcrss_c(C, R, I); + + // Load the matrix IB and enter it into the cache + vequ_c (I, (SpiceDouble (*)) &IB[0]); + vequ_c (C, (SpiceDouble (*)) &IB[3]); + vequ_c (R, (SpiceDouble (*)) &IB[6]); + p_cacheIB.push_back(IB); + // end IB code + + // Compute the CIcr matrix - in-track, cross-track, radial frame to constant frame + mxmt_c((SpiceDouble (*)[3]) &(crot->TimeBasedMatrix())[0], (SpiceDouble (*)[3]) &(prot->Matrix())[0], + (SpiceDouble (*)[3]) &CI[0]); + + // Put CI into parent cache to use the parent class methods on it + mxmt_c((SpiceDouble (*)[3]) &CI[0], (SpiceDouble (*)[3]) &IB[0], (SpiceDouble (*)[3]) &CI[0]); + p_cache.push_back( CI ); + } + p_cachesLoaded = true; + SetSource(Memcache); + + NaifStatus::CheckErrors(); + } + + /** Cache J2000 rotation over existing cached time range using polynomials + * + * This method will reload an internal cache with matrices + * formed from rotation angles fit to polynomials over a time + * range. + * + * @param function1 The first polynomial function used to + * find the rotation angles + * @param function2 The second polynomial function used to + * find the rotation angles + * @param function3 The third polynomial function used to + * find the rotation angles + */ + void LineScanCameraRotation::ReloadCache (){ + NaifStatus::CheckErrors(); + + // Make sure caches are already loaded + if ( !p_cachesLoaded) { + std::string msg = "A LineScanCameraRotation cache has not been loaded yet"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Clear existing matrices from cache + p_cache.clear(); + + // Create polynomials fit to angles & use to reload cache + Isis::PolynomialUnivariate function1( p_degree ); + Isis::PolynomialUnivariate function2( p_degree ); + Isis::PolynomialUnivariate function3( p_degree ); + + // Get the coefficients of the polynomials already fit to the angles of rotation defining [CI] + std::vector coeffAng1; + std::vector coeffAng2; + std::vector coeffAng3; + GetPolynomial ( coeffAng1, coeffAng2, coeffAng3 ); + + // Reset linear term to center around zero -- what works best is either roll-avg & pitchavg+ or pitchavg+ & yawavg- +// coeffAng1[1] -= 0.0000158661225; +// coeffAng2[1] = 0.0000308433; +// coeffAng3[0] = -0.001517547; + if (p_pitchRate) coeffAng2[1] = p_pitchRate; + if (p_yaw) coeffAng3[0] = p_yaw; + + // Load the functions with the coefficients + function1.SetCoefficients ( coeffAng1 ); + function2.SetCoefficients ( coeffAng2 ); + function3.SetCoefficients ( coeffAng3 ); + + double CI[3][3]; + double IJ[3][3]; + std::vector rtime; + SpiceRotation *prot = p_spi->BodyRotation(); + std::vector CJ; + CJ.resize(9); + + for (std::vector::size_type pos=0;pos < p_cacheTime.size();pos++) { + double et = p_cacheTime.at(pos); + rtime.push_back((et - GetBaseTime() ) / GetTimeScale() ); + double angle1 = function1.Evaluate (rtime); + double angle2 = function2.Evaluate (rtime); + double angle3 = function3.Evaluate (rtime); + rtime.clear(); + +// Get the first angle back into the range Naif expects [180.,180.] + if (angle1 < -1*pi_c() ) { + angle1 += twopi_c(); + } + else if (angle1 > pi_c()) { + angle1 -= twopi_c(); + } + + eul2m_c ( (SpiceDouble) angle3, (SpiceDouble) angle2, (SpiceDouble) angle1, + p_axis3, p_axis2, p_axis1, + CI); + mxm_c ( (SpiceDouble (*)[3]) &(p_jitter->SetEphemerisTimeHPF(et))[0], CI, CI); + + prot->SetEphemerisTime(et); + mxm_c ( (SpiceDouble (*)[3]) &(p_cacheIB.at(pos))[0], (SpiceDouble (*)[3]) &(prot->Matrix())[0], IJ); + mxm_c (CI, IJ, (SpiceDouble (*)[3]) &CJ[0]); + + p_cache.push_back( CJ ); // J2000 to constant frame + } + + // Set source to cache to get updated values + SetSource(SpiceRotation::Memcache); + + // Make sure SetEphemerisTime updates the matrix by resetting it twice (in case the first one + // matches the current et. p_et is private and not available from the child class + NaifStatus::CheckErrors(); + SetEphemerisTime(p_cacheTime[0]); + SetEphemerisTime(p_cacheTime[1]); + + NaifStatus::CheckErrors(); + } + +} diff --git a/isis/src/base/apps/appjit/LineScanCameraRotation.h b/isis/src/base/apps/appjit/LineScanCameraRotation.h new file mode 100644 index 0000000000000000000000000000000000000000..65ee5e086a65de88cc0212333907151c2b0c5bae --- /dev/null +++ b/isis/src/base/apps/appjit/LineScanCameraRotation.h @@ -0,0 +1,129 @@ +#ifndef LineScanCameraRotation_h +#define LineScanCameraRotation_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2009/12/29 23:03:47 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" + +#include "SpiceRotation.h" +#include "SpicePosition.h" +#include "Table.h" +#include "Quaternion.h" +#include "PolynomialUnivariate.h" +#include "PixelOffset.h" +#include "Spice.h" + + +namespace Isis { + /** + * @brief Obtain SPICE rotation information for a body + * + * This class will obtain the rotation from J2000 to the ICR frame (with axes + * (defined in direction of in track, cross track, and radial) for HiRise. + * + * It is essentially used to convert position vectors from one frame to + * another, making it is a C++ wrapper to the NAIF routines pxform_c and + * mxv or mtxv. Therefore, appropriate NAIF kernels are expected to be + * loaded prior to using this class. A position can be returned in either + * the J2000 frame or the selected reference frame. See NAIF required + * reading for more information regarding this subject at + * ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/ascii/individual_docs/spk.req + *

+ * An important functionality of this class is the ability to cache the + * rotations so they do not have to be constantly read from the NAIF kernels + * and they can be more conveniently updated. Once the data is cached, the + * NAIF kernels can be unloaded. + * + * @ingroup SpiceInstrumentsAndCameras + * + * @author 2005-12-01 Debbie A. Cook + * + * @internal + * @history 2005-12-01 Debbie A. Cook Original Version modified from + * SpicePosition class by Jeff Anderson + * @history 2006-03-23 Jeff Anderson modified SetEphemerisTime to return + * if the time did not change to improve speed. + * @history 2006-10-18 Debbie A. Cook Added method, WrapAngle, to wrap + * angles around 2 pi + * @history 2007-12-05 Debbie A. Cook added method SetPolynomialDegree to + * allow the degree of the polynomials fit to the + * camera angles to be changed. Also changed the + * polynomial from a fixed 2nd order polynomial to + * an nth degree polynomial with one independent + * variable. PartialType was revised and the calls to + * SetReferencePartial (has an added argument, coefficient index) + * and DPolynomial (argument type changed to int) were revised. + * The function was changed from Parabola + * to Polynomial1Variable, now called + * PolynomialUnivariate. New methods GetBaseTime + * and SetOverrideBaseTime were added + * @history 2008-02-15 Debbie A. Cook added a new error message to handle the + * case where the Naif reference frame code is not + * recognized. + * @history 2008-06-18 Fixed documentation, added NaifStatus calls + * @history 2008-08-11 Debbie A. Cook Added method to set axes of rotation. + * Default axes are still 3,1,3 so existing software will + * not be affected by the change. + * @history 2008-12-12 Debbie A. Cook Added parameters for updated pitch rate and yaw + * and related methods + * @history 2009-07-31 Debbie A. Cook Added new argument, tol, for call to CreateCache + * method of Spice class + * @history 2009-10-01 Debbie A. Cook Modified methods to be compatible with changes made + * to parent class, SpiceRotation, to separate rotation into a constant + * rotation and a time-dependent rotation + */ + class LineScanCameraRotation : public Isis::SpiceRotation { + public: + //! Constructors +// LineScanCameraRotation( int frameCode, SpiceRotation *crot, SpiceRotation *prot, SpicePosition *spos ); + LineScanCameraRotation( int frameCode, Isis::Pvl &lab, std::vector timeCache, double tol); + + //! Destructor +// virtual ~LineScanCameraRotation() { }; + virtual ~LineScanCameraRotation(); + + void LoadCache(); + void SetJitter( PixelOffset *jitter) { p_jitter = jitter; }; + void ReloadCache(); + void ResetPitchRate( double pitchRate ) { p_pitchRate = pitchRate; }; + void ResetYaw( double yaw ) { p_yaw = yaw; }; + + private: + Isis::Spice *p_spi; + SpiceRotation *p_crot; //!< Camera rotation [CJ] + SpicePosition *p_spos; //!< Spacecraft position in J2000 + SpiceRotation *p_prot; //!< Planet rotation [PJ] + std::vector > p_cacheIB; //!< Cached rotations body-fixed to ICR + PixelOffset *p_jitter; //!< Jitter rotations from nominal camera to truth (jittering camera) + bool p_cachesLoaded; //!< Flag indicated p_cache and p_cacheIB are loaded + double p_pitchRate; //!< Optional update to pitch rate + double p_yaw; //!< Optional update to yaw + }; +}; + +#endif + diff --git a/isis/src/base/apps/appjit/Makefile b/isis/src/base/apps/appjit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/appjit/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/appjit/PixelOffset.cpp b/isis/src/base/apps/appjit/PixelOffset.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74122347f0409f69b8462c6c84ae45373744ad78 --- /dev/null +++ b/isis/src/base/apps/appjit/PixelOffset.cpp @@ -0,0 +1,338 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "PixelOffset.h" +#include "TextFile.h" +#include "LineEquation.h" +#include "LeastSquares.h" +#include "BasisFunction.h" +#include "PolynomialUnivariate.h" +#include "iString.h" +#include "iException.h" + + +namespace Isis { + /** + * Construct a Pixel Offset class loading the offsets in the input file into + * the offset caches. + * + * @param tableList Ascii table list of sample, line offsets and their corresponding time. + * @param fl Focal length of instrument in mm. + * @param pixpitch Pixel pitch of instrument in mm/pixel. + */ + PixelOffset::PixelOffset( const std::string &tableList, double fl, double pixPitch, double baseTime, + double timeScale, int degree ) { + p_focalLen = fl; + p_pixPitch = pixPitch; +// p_RJ.resize(9); + p_et = -DBL_MAX; + p_degree = degree; + p_baseTime = baseTime; + p_timeScale = timeScale; + p_angleScale = p_pixPitch/p_focalLen; + std::vector lines; + Isis::TextFile inputFile(tableList, "input", lines); + std::vector fields; + p_I.push_back(1.0); + p_I.push_back(0.0); + p_I.push_back(0.0); + p_I.push_back(0.0); + p_I.push_back(1.0); + p_I.push_back(0.0); + p_I.push_back(0.0); + p_I.push_back(0.0); + p_I.push_back(1.0); + + // New extrapolation 05-15-2010 + // Set 2 extra points on each end of the jitter range to cover time of observation + p_samples.push_back(0.); + p_samples.push_back(0.); + p_lines.push_back(0.); + p_lines.push_back(0.); + p_times.push_back(0.); + p_times.push_back(0.); + + + for (size_t iline=0; ilinesMax) sMax = p_samples[i]; + if (p_lines[i]lMax) lMax = p_lines[i]; + } + p_sampScale = (sMax - sMin)/2.; + p_sampOff = sMax - p_sampScale; + p_lineScale = (lMax - lMin)/2.; + p_lineOff = lMax - p_lineScale; + } + + /** Compute the angular equivalents for the offsets at a given time. + * + * This method computes the angular equivalents in radians for the offsets + * at a given et in seconds. The pixel offsets are interpolated from the + * offsets input in the table using a cubic interpolation and converted to + * angles based on the focal length and the pixel pitch. + * + * @param et ephemeris time in seconds + */ + void PixelOffset::SetEphemerisTime(double et) { + // Save the time + if (p_et == et) return; + p_et = et; + + // Otherwise determine the interval to interpolate. p_times, p_samples, and p_lines + // have been filled to the image begin and end times and beyond with an additional entry + // on each end so that the cubic interpolation will work for all image times + std::vector::iterator pos; + pos = upper_bound(p_times.begin(),p_times.end(),p_et); // returns the nearest endpoint if outside range + if (pos > p_times.end()-2) pos = p_times.end()-2; // Take care of time for last line of observation + + int index=0; + double soc0, soc1, soc2, soc3, loc0, loc1, loc2, loc3; + soc0=soc1=soc2=soc3=loc0=loc1=loc2=loc3=0.; + // Check to make sure the vectors are padded sufficiently to cover the image + if (pos >= p_times.begin()+2 ) { + index = distance(p_times.begin(),pos); + index--; //lower bound + soc3 = p_samples[index+2] - p_samples[index+1] - p_samples[index-1] + p_samples[index]; + soc2 = p_samples[index-1] - p_samples[index] - soc3; + soc1 = p_samples[index+1] - p_samples[index-1]; + soc0 = p_samples[index]; + loc3 = p_lines[index+2] - p_lines[index+1] - p_lines[index-1] + p_lines[index]; + loc2 = p_lines[index-1] - p_lines[index] - loc3; + loc1 = p_lines[index+1] - p_lines[index-1]; + loc0 = p_lines[index]; + } + else { + std::string msg; + msg = "Error in extrapolation code"; + throw iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (index < 0) index = 0; + +// Interpolate the offsets + double mult = (p_et - p_times[index]) / + (p_times[index+1] - p_times[index]); + double mult2 = mult*mult; + double sampleOff = soc3*mult*mult2 + soc2*mult2 + soc1*mult + soc0; + double lineOff = loc3*mult*mult2 + loc2*mult2 + loc1*mult + loc0; + + // std::cout<<" "< cacheTime ) { + p_cacheTime = cacheTime; + + // Make sure angles aren't already loaded TBD +/* if () { + std::string msg = "An angle cache has already been created"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } */ + + // Fill in extended sample/line/time jitter offset vectors for extrapolation + // Two extra at beginning -- added 05-15-2010 + double slope = (p_samples[3] - p_samples[2]) / (p_times[3] - p_times[2]); + p_times[1] = p_cacheTime[0]; + p_times[0] = p_times[1] - .01*(p_times[2] - p_times[1]); + p_samples[1] = slope*(p_times[1] - p_times[2]) + p_samples[2]; + // Alternative extrapolation to try if problems with current code + // set p_samples[0] = p_samples[1] + // Likewise for the end and for lines. + p_samples[0] = slope*(p_times[0] - p_times[2]) + p_samples[2]; + slope = (p_lines[3] - p_lines[2]) / (p_times[3] - p_times[2]); + p_lines[1] = slope*(p_times[1] - p_times[2]) + p_lines[2]; + p_lines[0] = slope*(p_times[0] - p_times[2]) + p_lines[2]; + + // Two extra at ending + int end = p_times.size() - 1; + slope = (p_samples[end] - p_samples[end-1]) / (p_times[end] - p_times[end-1]); + p_times.push_back(p_cacheTime[p_cacheTime.size()-1]); + p_times.push_back(p_times[end+1] + .01*(p_times[end+1] - p_cacheTime[end])); + p_samples.push_back(slope*(p_times[end+1] - p_times[end]) + p_samples[end]); + p_samples.push_back(slope*(p_times[end+2] - p_times[end]) + p_samples[end]); + slope = (p_lines[end] - p_lines[end-1]) / (p_times[end] - p_times[end-1]); + p_lines.push_back(slope*(p_times[end+1] - p_times[end]) + p_lines[end]); + p_lines.push_back(slope*(p_times[end+2] - p_times[end]) + p_lines[end]); + + // Loop and load the angle caches + // std::cout< time; + + // Load the known values to compute the fit equation + for (std::vector::size_type pos=0;pos < p_cacheTime.size();pos++) { + double t = p_cacheTime.at(pos); + +// Base fit on extent of coverage in the input offset file + if (t >= p_times[0] && t <= p_times[p_times.size()-1]) { + time.push_back( (t - p_baseTime) / p_timeScale ); + SetEphemerisTime( t ); + fitAng1->AddKnown ( time, p_cacheAngle1[pos] ); + fitAng2->AddKnown ( time, p_cacheAngle2[pos] ); + time.clear(); + } + } + + if (fitAng1->Knowns() == 0) { + std::string msg; + msg = "Cube time range is not covered by jitter file"; + throw iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + //Solve the equations for the coefficients + fitAng1->Solve(); + fitAng2->Solve(); + + // Delete the least squares objects now that we have all the coefficients + delete fitAng1; + delete fitAng2; + + // For now assume both angles are fit to a polynomial. Later they may + // each be fit to a unique basis function. + // Fill the coefficient vectors + + for ( int i = 0; i < function1.Coefficients(); i++) { + p_ang1Coefficients.push_back( function1.Coefficient( i ) ); + p_ang2Coefficients.push_back( function2.Coefficient( i ) ); + } + +// std::cout<<"Angle1 coeff="< PixelOffset::SetEphemerisTimeHPF ( const double et ) { + + Isis::PolynomialUnivariate function1( p_degree ); + Isis::PolynomialUnivariate function2( p_degree ); + + //If outside the range of the offsets just return the identity matrix + if (et < p_times[0] || et > p_times[p_times.size()-1]) { + return (p_I); + } + + // Load the functions with the coefficients + function1.SetCoefficients ( p_ang1Coefficients ); + function2.SetCoefficients ( p_ang2Coefficients ); + + // Compute polynomial approximations to angles, pangle1 and pangle2 + std::vector rtime; + rtime.push_back((et - p_baseTime) / p_timeScale); + double pangle1 = p_sampOff + p_sampScale*function1.Evaluate (rtime); + double pangle2 = p_lineOff + p_lineScale*function2.Evaluate (rtime); + + // Compute p_angles for this time + SetEphemerisTime(et); + double angle1 = p_angleScale*(p_angle1 - pangle1); + double angle2 = p_angleScale*(p_angle2 - pangle2); + + +// std::cout<<" "< TC(9); + + eul2m_c ( (SpiceDouble) 0., (SpiceDouble) angle2, (SpiceDouble) angle1, + 3, 2, 1, + (SpiceDouble(*) [3]) &TC[0]); + + return (TC); + } + + + + /** Wrap the input angle to keep it within 2pi radians of the + * angle to compare. + * + * @param [in] compareAngle + * @param [in] angle Angle to be wrapped if needed + * @return double Wrapped angle + * + */ + double PixelOffset::WrapAngle(double compareAngle, double angle) { + double diff1 = compareAngle - angle; + + if ( diff1 < -1*pi_c() ){ + angle -= twopi_c(); + } + else if (diff1 > pi_c() ) { + angle += twopi_c(); + } + return angle; + } + +} diff --git a/isis/src/base/apps/appjit/PixelOffset.h b/isis/src/base/apps/appjit/PixelOffset.h new file mode 100644 index 0000000000000000000000000000000000000000..f75c9bb167031f7966a104f7cb840eb2adc68674 --- /dev/null +++ b/isis/src/base/apps/appjit/PixelOffset.h @@ -0,0 +1,116 @@ +#ifndef PixelOffset_h +#define PixelOffset_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/05/18 00:05:29 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "PolynomialUnivariate.h" +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" + + +namespace Isis { + /** + * @brief Obtain rotation angles for a line scan camera pixel offsets + * + * This class will obtain the rotation from existing camera pointing to + * "corrected" camera pointing calculated from a table of pixel offsets + * and time (sample line et) + * + * This class was created to calculate the rotation matrix needed to + * remove jitter from a hirise image based on the table of offsets. + * + * @ingroup SpiceInstrumentsAndCameras + * + * @author 2008-08-20 Debbie A. Cook + * + * @internal + * @history 2008-08-20 Debbie A. Cook Original Version + * @history 2008-12-19 Debbie A. Cook Removed couts to prepare for commiting + * @history 2009-10-01 Debbie A. Cook Cleaned up extrapolation code + * @history 2010-05-17 Debbie A. Cook Recoded extrapolation to add 2 + * extra points on each end of the input data. The first point + * added on each end should be the start and end time of the + * observation. The added points are linearly interpolated from + * the beginning and final 2 points of input data. + */ + class PixelOffset { + public: + //! Constructors + PixelOffset( const std::string &tableList, double fl, double pixPitch, double baseTime, + double timeScale, int degree ); + + //! Destructor + virtual ~PixelOffset() { } + + //! Load the angles by interpolating the pixel offsets and converting to angles + void LoadAngles ( std::vector cacheTime ); + + //! Compute cubic interpolation for current time et + void Interp (); + + //! Compute coefficients for a polynomial fit to each angle based on scaled time + void SetPolynomial (); + + void SetEphemerisTime(const double et ); + + std::vector SetEphemerisTimeHPF(const double et ); + + double WrapAngle (double compareAngle, double angle); +// std::vector &Matrix() { return p_TC; }; + + + + private: + std::vector p_samples; + std::vector p_lines; + std::vector p_times; + std::vector p_I; + double p_focalLen; //!< Focal length of instrument in mm + double p_pixPitch; //!< Pixel pitch of instrument in mm/pixel + double p_et; //!< Current ephemeris time + + std::vector p_cacheAngle1; //! + std::vector p_cacheAngle2; + std::vector p_cacheTime; + // rotation at et + double p_baseTime; //!< Base time used in fit equations + double p_timeScale; //!< Time scale used in fit equations + std::vector p_ang1Coefficients; + std::vector p_ang2Coefficients; + //!< Coefficients of polynomials fit to + // each of three rotation angles + int p_degree; //!< Degree of fit polynomial for angles + double p_angle1; //!< Angle1 for current et in radians + double p_angle2; //!< Angle2 for current et in radians + double p_angleScale; //!< Scaler to reduce roundoff + double p_sampOff; + double p_sampScale; + double p_lineOff; + double p_lineScale; + }; +}; + +#endif + diff --git a/isis/src/base/apps/appjit/appjit.cpp b/isis/src/base/apps/appjit/appjit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6afaad3bc3781cf2a6e810b3f8c2d2e1c78c76ef --- /dev/null +++ b/isis/src/base/apps/appjit/appjit.cpp @@ -0,0 +1,152 @@ +#include "Isis.h" +#include "Cube.h" +#include "Table.h" +#include "Camera.h" +#include "LineScanCameraRotation.h" +#include "PixelOffset.h" +#include "SpiceRotation.h" +#include "iString.h" +#include "FileList.h" +#include "iException.h" +#include "CameraDetectorMap.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + /*Processing steps + 1. Open and read the jitter table, convert the pixel offsets to angles, + and create the polynomials (solve for the coefficients) to use to do + the high pass filter putting the results into a rotation matrix in the jitter class. + 2. Apply the jitter correction in the LineScanCameraRotation object of the master cube. + 3. Loop through FROMLIST correcting the pointing and writing out the + updated camera pointing from the master cube + */ + + int degree = ui.GetInteger("DEGREE"); + + // Get the input file list to make sure it is not empty and the master cube is included + FileList list; + list.Read(ui.GetFilename("FROMLIST")); + + if (list.size() < 1) { + string msg = "The input list file [" + ui.GetFilename("FROMLIST") + "is empty"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + int ifile = 0; + // Make sure the master file is included in the input file list + while (ifile < (int) list.size() && Filename(list[ifile]).Expanded() != Filename(ui.GetFilename("MASTER")).Expanded()) { + ifile++; + } + + if (ifile >= (int) list.size()) { + string msg = "The master file, [" + Filename(ui.GetFilename("MASTER")).Expanded() + " is not included in " + + "the input list file " + ui.GetFilename("FROMLIST") + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + bool step2 = false; + PvlGroup gp("AppjitResults"); + + //Step 1: Create the jitter rotation + + try { + // Open the master cube + Cube cube; + cube.Open(ui.GetFilename("MASTER"),"rw"); + + //check for existing polygon, if exists delete it + if (cube.Label()->HasObject("Polygon")){ + cube.Label()->DeleteObject("Polygon"); + } + + // Get the camera + Camera *cam = cube.Camera(); + if (cam->DetectorMap()->LineRate() == 0.0) { + string msg = "[" + ui.GetFilename("MASTER") + "] is not a line scan camera image"; + throw iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Create the master rotation to be corrected + int frameCode = cam->InstrumentRotation()->Frame(); + cam->SetImage(int(cube.Samples()/2), int(cube.Lines()/2) ); + double tol = cam->PixelResolution(); + + if (tol < 0.) { + // Alternative calculation of .01*ground resolution of a pixel + tol = cam->PixelPitch()*cam->SpacecraftAltitude()*1000./cam->FocalLength()/100.; + } + LineScanCameraRotation crot(frameCode, *(cube.Label()), cam->InstrumentRotation()->GetFullCacheTime(), tol ); + crot.SetPolynomialDegree(ui.GetInteger("DEGREE")); + crot.SetAxes(1, 2, 3); + if (ui.WasEntered("PITCHRATE")) crot.ResetPitchRate(ui.GetDouble("PITCHRATE")); + if (ui.WasEntered("YAW")) crot.ResetYaw(ui.GetDouble("YAW")); + crot.SetPolynomial(); + double baseTime = crot.GetBaseTime(); + double timeScale = crot.GetTimeScale(); + double fl = cam->FocalLength(); + double pixpitch = cam->PixelPitch(); + std::vector cacheTime = cam->InstrumentRotation()->GetFullCacheTime(); + + // Get the jitter in pixels, compute jitter angles, and fit a polynomial to each angle + PixelOffset jitter(ui.GetFilename("JITTERFILE"), fl, pixpitch, baseTime, timeScale, degree); + jitter.LoadAngles(cacheTime); + jitter.SetPolynomial(); + + // Set the jitter and apply to the instrument rotation + crot.SetJitter( &jitter ); + crot.ReloadCache(); + + // Pull out the pointing cache as a table and write it + Table cmatrix = crot.Cache("InstrumentPointing"); + cmatrix.Label().AddComment("Corrected using appjit and" + ui.GetFilename("JITTERFILE")); + cube.Write(cmatrix); + + // Write out the instrument position table + Isis::PvlGroup kernels = cube.Label()->FindGroup("Kernels",Isis::Pvl::Traverse); + + // Write out the "Table" label to the tabled kernels in the kernels group + kernels["InstrumentPointing"] = "Table"; +// kernels["InstrumentPosition"] = "Table"; + cube.PutGroup(kernels); + cube.Close(); + gp += PvlKeyword("StatusMaster",ui.GetFilename("MASTER") + ": camera pointing updated"); + + // Apply the dejittered pointing to the rest of the files + step2 = true; + for (int ifile = 0; ifile < (int) list.size(); ifile++) { + if (list[ifile] != ui.GetFilename("MASTER")) { + // Open the cube + cube.Open(list[ifile],"rw"); + //check for existing polygon, if exists delete it + if (cube.Label()->HasObject("Polygon")){ + cube.Label()->DeleteObject("Polygon"); + } + // Get the camera and make sure it is a line scan camera + Camera *cam = cube.Camera(); + if (cam->DetectorMap()->LineRate() == 0.0) { + string msg = "[" + ui.GetFilename("FROM") + "] is not a line scan camera"; + throw iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + // Pull out the pointing cache as a table and write it + cube.Write(cmatrix); + cube.PutGroup(kernels); + cube.Close(); + gp += PvlKeyword("Status" + iString(ifile), list[ifile] + ": camera pointing updated"); + } + } + Application::Log( gp ); + } + catch (iException &e) { + string msg; + if (!step2) { + msg = "Unable to fit pointing for [" + ui.GetFilename("MASTER") + "]"; + } + else { + msg = "Unable to update pointing for nonMaster file(s)"; + } + throw iException::Message(Isis::iException::User,msg,_FILEINFO_); + } +} diff --git a/isis/src/base/apps/appjit/appjit.xml b/isis/src/base/apps/appjit/appjit.xml new file mode 100644 index 0000000000000000000000000000000000000000..1d892f37099bf8865d86b6bd2895a883067124a7 --- /dev/null +++ b/isis/src/base/apps/appjit/appjit.xml @@ -0,0 +1,127 @@ + + + + Apply sample/line jitter offsets to the camera pointing of an observation + set + + + + This program requires an observation set of cubes to be initialized with + "spiceinit". It will then apply the offsets in the input jitter table, + after high pass filtering them, to the low pass filtered rotations in the + InstrumentPointing table of the cubes. The low pass filter is achieved by + using a least square solution to compute a polynomial fit of the right + ascension, declination, and twist angles of the rotation. This should reduce + "noisy" pointing data. To restore the original pointing just rerun + "spiceinit". + +

+ Note that this program should be used on line scan cameras. It will not work + on framing cameras. +

+ + + + Cameras + + + + + Original version + + + Corrected error handling for master file + + + Added new argument to LineScanCameraRotation + + + Added alternate tolerance calculation + + + + + + + filename + input + + Cubes to update + + + The file specifications for the input cubes all from the same + observation. The pointing for these cubes will be updated to correct + for jitter and smoothed to remove noise. + + + *.lis + + + + cube + input + + Cubes used to initialize pointint fit + + + The file specification of the cube used to set the apriori pointing + fit for all the cubes in the observation FROMLIST. + + + *.cub + + + + filename + input + + Ascii table of pixel jitter offsets for selected times + + + The file specification of the Ascii table of pixel offsets formatted + so that each line lists + sampleOffset lineOffset ephemerisTimeSeconds + + + *.txt + + + + + + + Degree of fit + + + Enter the degree of the polynomial to fit to the data + + integer + + 2 + + + + + Optional replacement pitch rate + + No change + + This value can be used to center the adjacent ccd line errors around + zero + + double + + + + Optional replacement yaw + + No change + + This value can be used to center the adjacent ccd sample errors around + zero + + double + + + + diff --git a/isis/src/base/apps/appjit/tsts/Makefile b/isis/src/base/apps/appjit/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/appjit/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/appjit/tsts/case1/Makefile b/isis/src/base/apps/appjit/tsts/case1/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..51140f5f1c55d9c850fc9963f7a14a3c64e47216 --- /dev/null +++ b/isis/src/base/apps/appjit/tsts/case1/Makefile @@ -0,0 +1,19 @@ +APPNAME = appjit + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(CP) $(INPUT)/PSP_007556_2010_RED4.balance.cropped.cub $(OUTPUT); + $(CP) $(INPUT)/PSP_007556_2010_RED5.balance.cropped.cub $(OUTPUT); + $(LS) -1 $(OUTPUT)/*.balance.cropped.cub > from.lis; + $(APPNAME) from=from.lis \ + master=$(OUTPUT)/PSP_007556_2010_RED5.balance.cropped.cub \ + jitter=$(INPUT)/PSP_007556_2010.txt \ + degree=2 > $(OUTPUT)/appjit.pvl; + tabledump from=$(OUTPUT)/PSP_007556_2010_RED4.balance.cropped.cub \ + to=$(OUTPUT)/red4.instrumentPointing.txt \ + name=InstrumentPointing > /dev/null; + tabledump from=$(OUTPUT)/PSP_007556_2010_RED5.balance.cropped.cub \ + name=InstrumentPointing \ + to=$(OUTPUT)/red5.instrumentPointing.txt > /dev/null; + $(RM) $(OUTPUT)/PSP_007556_2010_RED4.balance.cropped.cub $(OUTPUT)/PSP_007556_2010_RED5.balance.cropped.cub from.lis print.prt > /dev/null; diff --git a/isis/src/base/apps/appjit/tsts/case2/Makefile b/isis/src/base/apps/appjit/tsts/case2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c0fba119ab95824143e4c961a29d4962995493e9 --- /dev/null +++ b/isis/src/base/apps/appjit/tsts/case2/Makefile @@ -0,0 +1,19 @@ +APPNAME = appjit + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(CP) $(INPUT)/PSP_007556_2010_RED4.balance.cropped.cub $(OUTPUT); + $(CP) $(INPUT)/PSP_007556_2010_RED5.balance.cropped.cub $(OUTPUT); + $(LS) -1 $(OUTPUT)/*.balance.cropped.cub > from.lis; + $(APPNAME) from=from.lis \ + master=$(OUTPUT)/PSP_007556_2010_RED5.balance.cropped.cub \ + jitter=$(INPUT)/PSP_007556_2010.txt \ + degree=2 pitchrate=0.00003084333 yaw=-0.001517547 > $(OUTPUT)/appjit.pvl; + tabledump from=$(OUTPUT)/PSP_007556_2010_RED4.balance.cropped.cub \ + to=$(OUTPUT)/red4.instrumentPointing.txt \ + name=InstrumentPointing > /dev/null; + tabledump from=$(OUTPUT)/PSP_007556_2010_RED5.balance.cropped.cub \ + name=InstrumentPointing \ + to=$(OUTPUT)/red5.instrumentPointing.txt > /dev/null; + $(RM) $(OUTPUT)/PSP_007556_2010_RED4.balance.cropped.cub $(OUTPUT)/PSP_007556_2010_RED5.balance.cropped.cub from.lis print.prt > /dev/null; diff --git a/isis/src/base/apps/ascii2isis/Makefile b/isis/src/base/apps/ascii2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/ascii2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/ascii2isis/ascii2isis.cpp b/isis/src/base/apps/ascii2isis/ascii2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..41b79c3c2d44ac66dc0fbfb119bc575732196993 --- /dev/null +++ b/isis/src/base/apps/ascii2isis/ascii2isis.cpp @@ -0,0 +1,127 @@ +#include "Isis.h" + +#include +#include + +#include "ProcessBySpectra.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +// Global declarations +double TestSpecial(const double pixel); +void ascii2isis (Buffer &out); +ifstream fin; +string order; +//Initialize values to make special pixels invalid +double null_min = DBL_MAX; +double null_max = DBL_MIN; +double hrs_min = DBL_MAX; +double hrs_max = DBL_MIN; +double lrs_min = DBL_MAX; +double lrs_max = DBL_MIN; + +void IsisMain() { + + // Open input text file + UserInterface &ui = Application::GetUserInterface(); + string from = ui.GetFilename("FROM"); + // Get storage order of data + order = ui.GetString("ORDER"); + + // Get the size of the cube + int ns = ui.GetInteger("SAMPLES"); + int nl = ui.GetInteger("LINES"); + int nb = ui.GetInteger("BANDS"); + int skip = ui.GetInteger("SKIP"); + + // Setup output cube + CubeAttributeOutput &att = ui.GetOutputAttribute("TO"); + + // Set special pixel ranges + if (ui.GetBoolean("SETNULLRANGE")) { + null_min = ui.GetDouble("NULLMIN"); + null_max = ui.GetDouble("NULLMAX"); + } + if (ui.GetBoolean("SETHRSRANGE")) { + hrs_min = ui.GetDouble("HRSMIN"); + hrs_max = ui.GetDouble("HRSMAX"); + } + if (ui.GetBoolean("SETLRSRANGE")) { + lrs_min = ui.GetDouble("LRSMIN"); + lrs_max = ui.GetDouble("LRSMAX"); + } + + fin.open (from.c_str(),std::ios::in); + if (!fin.is_open()) { + string msg = "Cannot open input file [" + from + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // Skip header information if it exists + fin.seekg(skip,std::ios::beg); + + // Set up process depending on order + if (order == "BSQ") { + ProcessByLine p; + + p.SetOutputCube (ui.GetFilename("TO"),att,ns,nl,nb); + p.StartProcess(ascii2isis); + p.EndProcess(); + } + if (order == "BIL") { + ProcessBySpectra p(Isis::ProcessBySpectra::ByLine); + + // Set Special Pixel ranges + p.SetOutputCube (ui.GetFilename("TO"),att,ns,nl,nb); + p.StartProcess(ascii2isis); + p.EndProcess(); + } + if (order == "BIP") { + ProcessBySpectra p(Isis::ProcessBySpectra::PerPixel); + + p.SetOutputCube (ui.GetFilename("TO"),att,ns,nl,nb); + p.StartProcess(ascii2isis); + p.EndProcess(); + } + + fin.close (); +} + +void ascii2isis (Buffer &out) { + //Define all legal characters for the beginning of a number + const string legal = ".0123456789+-"; + for (int i=0; i> out[i]; + out[i] = TestSpecial(out[i]); + //Discard all nonlegal characters + while ((legal.find(fin.peek())== string::npos) && !fin.eof()) { + fin.ignore(); + } + } +} + +/** + * Tests the pixel. If it is valid it will return the dn value, + * otherwise it will return the Isis special pixel value that + * corresponds to it + * + * @param pixel The double precision value that represents a + * pixel. + * @return double The double precision value representing the + * pixel will return as a valid dn or changed to an isis + * special pixel. + */ + double TestSpecial(const double pixel){ + if (pixel <= null_max && pixel >= null_min){ + return Isis::NULL8; + } else if (pixel <= hrs_max && pixel >= hrs_min){ + return Isis::HIGH_REPR_SAT8; + } else if (pixel <= lrs_max && pixel >= lrs_min){ + return Isis::LOW_REPR_SAT8; + } else { + return pixel; + } + } diff --git a/isis/src/base/apps/ascii2isis/ascii2isis.xml b/isis/src/base/apps/ascii2isis/ascii2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..95373f7620db255f5d8f2289c14b25d45d6cf0fe --- /dev/null +++ b/isis/src/base/apps/ascii2isis/ascii2isis.xml @@ -0,0 +1,327 @@ + + + + Import ascii file as a cube + + + This program will read an ascii file and create a cube. The ascii values + can be delimited by spaces, tabs, commas or any other character that is + not a number, a period, or a plus or minus sign. + + + + Import and Export + + + + + Original version + + + Documentation fixes + + + Fixed problems with mixed separators. Added appTest. + + + Added ability to change special pixel ranges. Added example. + + + + + + + + filename + input + Input ascii file + + The file name of the input ascii file to be converted to cube. + + *.txt + + + cube + output + real + Output cube + + The file name of the output cube. + + *.cub + + + + + + string + + BSQ + + Storage order of data + + Storage order of image data defines which dimension varies the + fastest and the third varying the slowest (sample, line or band). + BSQ = Band Sequential (sample, line, band) + BIL = Band Interleaved by Line (sample, band, line) + BIP = Band Interleaved by Pixel (band, sample, line) + + + + + + + + + + integer + Number of samples in ascii + + This defines the number of samples in the ascii. + + + + + integer + Number of lines in raw image + + This defines the number of lines in the raw image. + + + + + integer + + 1 + + Number of bands in raw image + + This defines the number of bands in the raw image. If + greater than 1, the image is assumed to be in band sequential + order. + + + + + integer + + 0 + + Number of bytes to skip before reading data + + This defines the number of bytes to skip before the actual image + data is read. This would be for raw images with header data. + + + + + + + boolean + + NO + + Create special pixel values + + If this option is used input raw pixels below minimum and + above maximum will be converted to LRS and HRS respectively. Otherwise + pixels in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit real will + cause 0 and 255 to be actual values. If left as 8-bit then 0 will + be NULL and 255 will be HRS. + + + NULLMIN + NULLMAX + + + + + double + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + SETNULLRANGE + + + + double + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + SETNULLRANGE + + + + + boolean + + NO + + Create special pixel values + + If this option is used input raw pixels below minimum and + above maximum will be converted to LRS and HRS respectively. Otherwise + pixels in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit real will + cause 0 and 255 to be actual values. If left as 8-bit then 0 will + be NULL and 255 will be HRS. + + + HRSMIN + HRSMAX + + + + + double + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + SETHRSRANGE + + + + double + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + SETHRSRANGE + + + + + boolean + + NO + + Create special pixel values + + If this option is used input raw pixels below minimum and + above maximum will be converted to LRS and HRS respectively. Otherwise + pixels in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit real will + cause 0 and 255 to be actual values. If left as 8-bit then 0 will + be NULL and 255 will be HRS. + + + LRSMIN + LRSMAX + + + + + double + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + SETLRSRANGE + + + + double + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + SETLRSRANGE + + + + + + + + + Converting an ascii file to an Isis Cube + + + This example will show the conversion from a ascii file to a cube. + + + + FROM=input.txt TO=out.cub + samples=10 lines=10 skip=35 + + Convert the image input.txt to the Isis Cube out.cub + + + + + Convert the image input.txt to the Isis Cube out.cub + + The is the GUI for ascii2isis when converting the ascii file input.txt to the Isis Cube out.cub + + + + + + + + + + Ascii input file. + + + This is the ascii data + + FROM + + + + + + Output Isis Cube + + The is the output Isis Cube peaks.cub generated from this example. + + + + + + + diff --git a/isis/src/base/apps/ascii2isis/assets/images/ascii2isisGUI.jpg b/isis/src/base/apps/ascii2isis/assets/images/ascii2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..83f21aa79544193d03c45a0f178e9e067e606ec8 Binary files /dev/null and b/isis/src/base/apps/ascii2isis/assets/images/ascii2isisGUI.jpg differ diff --git a/isis/src/base/apps/ascii2isis/assets/images/out.jpg b/isis/src/base/apps/ascii2isis/assets/images/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..41e507d4bb396d79672dbc7fec5c33009aa7291f Binary files /dev/null and b/isis/src/base/apps/ascii2isis/assets/images/out.jpg differ diff --git a/isis/src/base/apps/ascii2isis/assets/input.txt b/isis/src/base/apps/ascii2isis/assets/input.txt new file mode 100644 index 0000000000000000000000000000000000000000..c8235539babaf119612a6e3ee86db835fcf19bcc --- /dev/null +++ b/isis/src/base/apps/ascii2isis/assets/input.txt @@ -0,0 +1,11 @@ +#Comment to test the skip function +0, 10, 20, 30, 40, 50, 60, 70, 80, 90 +10, 0, 20, 30, 40, 50, 60, 70, 80, 90 +10, 20, 0, 30, 40, 50, 60, 70, 80, 90 +10, 20, 30, 0, 40, 50, 60, 70, 80, 90 +10, 20, 30, 40, 0, 50, 60, 70, 80, 90 +10, 20, 30, 40, 50, 0, 60, 70, 80, 90 +10, 20, 30, 40, 50, 60, 0, 70, 80, 90 +10, 20, 30, 40, 50, 60, 70, 0, 80, 90 +10, 20, 30, 40, 50, 60, 70, 80, 0, 90 +10, 20, 30, 40, 50, 60, 70, 80, 90, 0 diff --git a/isis/src/base/apps/ascii2isis/assets/thumbs/ascii2isisGUI.jpg b/isis/src/base/apps/ascii2isis/assets/thumbs/ascii2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..898033b09adb3018a4ad70fa252c0cd107128e91 Binary files /dev/null and b/isis/src/base/apps/ascii2isis/assets/thumbs/ascii2isisGUI.jpg differ diff --git a/isis/src/base/apps/ascii2isis/assets/thumbs/out.jpg b/isis/src/base/apps/ascii2isis/assets/thumbs/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d51e8dbeef786b78d20b1145492fb6671e6a564b Binary files /dev/null and b/isis/src/base/apps/ascii2isis/assets/thumbs/out.jpg differ diff --git a/isis/src/base/apps/ascii2isis/tsts/Makefile b/isis/src/base/apps/ascii2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/ascii2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/ascii2isis/tsts/bil/Makefile b/isis/src/base/apps/ascii2isis/tsts/bil/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e5d48ed8ca18b95a0ce81e01075366b9a565ed3c --- /dev/null +++ b/isis/src/base/apps/ascii2isis/tsts/bil/Makefile @@ -0,0 +1,11 @@ +APPNAME = ascii2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ascii2isis_input.txt \ + to=$(OUTPUT)/ascii2isisBilTruth.cub \ + order=bil \ + lines=4 \ + samples=2 \ + bands=2 > /dev/null; diff --git a/isis/src/base/apps/ascii2isis/tsts/bip/Makefile b/isis/src/base/apps/ascii2isis/tsts/bip/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..14159012ee5741e2c537efc79d278e5b94057793 --- /dev/null +++ b/isis/src/base/apps/ascii2isis/tsts/bip/Makefile @@ -0,0 +1,11 @@ +APPNAME = ascii2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ascii2isis_input.txt \ + to=$(OUTPUT)/ascii2isisBipTruth.cub \ + order=bip \ + lines=4 \ + samples=2 \ + bands=2 > /dev/null; diff --git a/isis/src/base/apps/ascii2isis/tsts/bsq/Makefile b/isis/src/base/apps/ascii2isis/tsts/bsq/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..95bbbcdf780aed4fe73ac8fdbab92ad47bb8c725 --- /dev/null +++ b/isis/src/base/apps/ascii2isis/tsts/bsq/Makefile @@ -0,0 +1,12 @@ +APPNAME = ascii2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ascii2isis_input.txt \ + to=$(OUTPUT)/ascii2isisBsqTruth.cub \ + order=bsq \ + lines=4 \ + samples=2 \ + bands=2 \ + skip=35 > /dev/null; diff --git a/isis/src/base/apps/automos/Makefile b/isis/src/base/apps/automos/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/automos/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/automos/assets/Band.jpg b/isis/src/base/apps/automos/assets/Band.jpg new file mode 100644 index 0000000000000000000000000000000000000000..00da9784ff43cdb28283db1c7333e7cb2e505e78 Binary files /dev/null and b/isis/src/base/apps/automos/assets/Band.jpg differ diff --git a/isis/src/base/apps/automos/assets/Beneath.jpg b/isis/src/base/apps/automos/assets/Beneath.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db11367d8666e07383f180238c34c75cfaf01705 Binary files /dev/null and b/isis/src/base/apps/automos/assets/Beneath.jpg differ diff --git a/isis/src/base/apps/automos/assets/OnTop.jpg b/isis/src/base/apps/automos/assets/OnTop.jpg new file mode 100644 index 0000000000000000000000000000000000000000..24546949941162d28d3e241b39c88cecacc843d6 Binary files /dev/null and b/isis/src/base/apps/automos/assets/OnTop.jpg differ diff --git a/isis/src/base/apps/automos/automos.cpp b/isis/src/base/apps/automos/automos.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5dc7ae7d2c2acad11fafb2c6f03e80648cf8922d --- /dev/null +++ b/isis/src/base/apps/automos/automos.cpp @@ -0,0 +1,189 @@ +#define GUIHELPERS + +#include "Isis.h" +#include "ProcessMapMosaic.h" +#include "FileList.h" +#include "iException.h" +#include "SpecialPixel.h" +#include "ProjectionFactory.h" + +using namespace std; +using namespace Isis; + +void calcRange(double &minLat, double &maxLat, double &minLon, double &maxLon); +void helperButtonCalcRange (); + +map GuiHelpers() +{ + map helper; + helper ["helperButtonCalcRange"] = (void*) helperButtonCalcRange; + return helper; +} + +void IsisMain() +{ + FileList list; + UserInterface &ui = Application::GetUserInterface(); + + // Get the list of cubes to mosaic + list.Read(ui.GetFilename("FROMLIST")); + if (list.size() < 1) { + string msg = "The list file [" + ui.GetFilename("FROMLIST") + "does not contain any data"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + ProcessMapMosaic m; + + // Set the create flag-mosaic is always created in automos + m.SetCreateFlag(true); + + // Get the Track Flag + bool bTrack = ui.GetBoolean("TRACK"); + m.SetTrackFlag(bTrack); + + CubeAttributeOutput &oAtt = ui.GetOutputAttribute("MOSAIC"); + if (ui.GetString("GRANGE") == "USER") { + m.SetOutputCube(list, + ui.GetDouble("MINLAT"), ui.GetDouble("MAXLAT"), + ui.GetDouble("MINLON"), ui.GetDouble("MAXLON"), + oAtt, ui.GetFilename("MOSAIC")); + } + else { + m.SetOutputCube(list, oAtt, ui.GetFilename("MOSAIC")); + } + + // Set up the mosaic priority, either the input cubes will be + // placed ontop of each other in the mosaic or beneath each other or + // placed based on band with "Lesser" or "Greater" criteria + // Set up the mosaic priority, either the input cube will be + // placed ontop of the mosaic or beneath it + MosaicPriority priority; + string sType; + if (ui.GetString("PRIORITY") == "BENEATH") { + priority = mosaic; + } + else if (ui.GetString("PRIORITY") == "ONTOP") { + priority = input; + } + else { + priority = band; + sType = ui.GetString("TYPE"); + if (sType=="BANDNUMBER") { + m.SetBandNumber(ui.GetInteger("NUMBER")); + } + else { + // Key name & value + m.SetBandKeyWord(ui.GetString("KEYNAME"), ui.GetString("KEYVALUE")); + } + // Band Criteria + BandCriteria eCriteria = Lesser; + if (ui.GetString("CRITERIA") == "GREATER") + eCriteria = Greater; + m.SetBandCriteria(eCriteria); + } + + // Priority + m.SetPriority(priority); + + m.SetHighSaturationFlag(ui.GetBoolean("HIGHSATURATION")); + m.SetLowSaturationFlag (ui.GetBoolean("LOWSATURATION")); + m.SetNullFlag(ui.GetBoolean("NULL")); + + // Loop for each input file and place it in the output mosaic + + m.SetBandBinMatch(ui.GetBoolean("MATCHBANDBIN")); + + for (unsigned int i=0; i nbands) nbands = cube.Bands(); + + // See if the cube has a projection and make sure it matches + // previous input cubes + Projection *proj = Isis::ProjectionFactory::CreateFromCube(*(cube.Label())); + if (firstProj == NULL) { + firstProj = proj; + } + else if (*proj != *firstProj) { + string msg = "Mapping groups do not match between cubes [" + list[0] + "] and [" + list[i] + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + if (proj->HasGroundRange()) { + if (proj->MinimumLatitude() < minLat) minLat = proj->MinimumLatitude(); + if (proj->MaximumLatitude() > maxLat) maxLat = proj->MaximumLatitude(); + if (proj->MinimumLongitude() < minLon) minLon = proj->MinimumLongitude(); + if (proj->MaximumLongitude() > maxLon) maxLon = proj->MaximumLongitude(); + } + + // Cleanup + cube.Close(); + if (proj != firstProj) + delete proj; + } +} + +// Helper function to run calcRange function. +void helperButtonCalcRange () +{ + UserInterface &ui = Application::GetUserInterface(); + double minLat; + double maxLat; + double minLon; + double maxLon; + + // Run the function calcRange of calculate range info + calcRange(minLat,maxLat,minLon,maxLon); + + // Write ranges to the GUI + string use = "USER"; + ui.Clear("GRANGE"); + ui.PutAsString("GRANGE",use); + ui.Clear("MINLAT"); + ui.PutDouble("MINLAT",minLat); + ui.Clear("MAXLAT"); + ui.PutDouble("MAXLAT",maxLat); + ui.Clear("MINLON"); + ui.PutDouble("MINLON",minLon); + ui.Clear("MAXLON"); + ui.PutDouble("MAXLON",maxLon); +} diff --git a/isis/src/base/apps/automos/automos.xml b/isis/src/base/apps/automos/automos.xml new file mode 100644 index 0000000000000000000000000000000000000000..d049637192337661d7bed0704519b7c75ecd253f --- /dev/null +++ b/isis/src/base/apps/automos/automos.xml @@ -0,0 +1,535 @@ + + + + + Create a mosaic using a list of map projected cubes + + + + +

This program uses a text-based list of cubes, all in the same map projection and equivalent projection parameters (PixelResolution, + CenterLongitude, LatitudeSystem, etc), to generate a mosaic. By default, + The program automatically determines the size of the mosaic by examining each cube. The user also + has the option of entering their own lat/lon range to use for the mosaic. +

+

Tracking can be set at the time of Mosaic creation + only and cannot be turned on after the mosaic is created. But the tracking + will be turned off for multiband ONTOP and BENEATH priority even though it + was turned on while creating the mosaic. Tracking for multiband input with + ONTOP priority is possible only if all the Special Pixel Flags are set to + True else the Tracking will be turned off. ONTOP priority basically places + all the valid input pixels onto the mosaic unless the special pixel flags + are turned on or if mosaic has a NULL pixel. In a multi band scenario, a + pixel origin in particular line and sample will not be the same in all the + different bands, which means we have to keep track of every pixel in every + band. i.e. the size of the tracking bands will be the same as the number + of bands in the mosaic.i.e the number of bands will be doubled.

+

WARNING: If Tracking is turned on in a mosaic, any subsequent + applications that modify "dn" values will corrupt + the Tracking band. It may be necessary to remove + the Tracking band from the mosaic and then add it + back after all the processing is complete. See + "crop" and "cubeit". +

+

Priority BAND can track origin for multi band input image based on a + specified band using LESSER or GREATER than criteria. Each pixel in the + specified band is compared to the corresponding pixel in the chosen band + in the mosaic based on the chosen criteria. This comparison true or false + is used for all the other bands whether the input pixel is copied onto the + mosaic and hence the origin for that pixel is stored. Band can be chosen + by choosing the TYPE, BANDNUMBER or KEYWORD. If BANDNUMBER is chosen then + the band number can be entered in the NUMBER field. If KEYWORD is chosen + then PVL key name and value from the BANDBIN group can be entered in the + KEYNAME and KEYVALUE fields.

+

For example, for a multi band input with BAND priority, if the BAND + chosen is Emission Angle band(EMA), if input pixels are (30,30,30) in + EMA Band for some sample, line and the corresponding pixels in the EMA + band in the mosaic has (75, 75, 75) and the criteria is GREATER than, + then since input pixels are not GREATER than corresponding mosaic + pixels, then the input pixels are not copied to the mosaic, so also the + corresponding pixels in all the other bands in the input. Hence the + origin for those pixels remains unchanged. If LESSER than was the + criteria, then all the corresponding pixels in all the input bands will + be copied to the mosaic and the origin for those pixels is the current + input image. +

+

There are options like MATCHBANDIN, if set requires the specfied input + bands to match the mosaic bands and the bands can be anywhere in the + mosaic but must be contiguous for multi-band. If MATCHBANDIN is not set + then any input image can be placed on the mosaic within it's boundaries. +

+

Options HIGHSATURATION, LOWSATURATION and NULL if + set will cause the the input pixels with these values to be copied to the + mosaic for ONTOP and BAND priorities regardless of the CRITERIA for the + BAND priority. These options are not supported for BENEATH priority.

+

Currently Tracking can be viewed in the Advanced Tool Tracking option + of the qview application. Following are the Tracking info:

+

Index : Zero based and is in the order in which the image was + placed on the mosaic. No origin is represented as -1.

+

FileName: File name of input image

+

Serial Number:Serial Number of the input image

+

Following are the values for the origin band depending on the pixel type + + + + + +
Pixel Type

(bits)
Default

(No Origin)
Start ValueMax ValueTotal Images

Supported
32-16777216-167772151677721633549932
16-32768-3276732767 65535
801255255
+

+

Following is the table for Special Pixel options, input, mosaic + pixels and the resulting output for different priorities. +
Tags: F(FALSE), T(TRUE), V(VALID), HS(HIGH SATURATION), LS(LOW SATURATION), + S(SPECIAL PIXEL HS, LS, NULL), N(NULL), I(INPUT), M(MOSAIC), HL(HS,LS) +
+

+
  • + + + + +
    Priority Beneath
    Priority Beneath + + + + +
    BENEATH
    InputMosaic Output
    S,VNI
    S,VHL,VM






    +
  • + + + + +
    Priority OnTop
    Priority OnTop + + + + + + + + +
    ONTOP
    OptionsImages
    HSLSNULLInputMosaicOutput
    F F FVS,VI
    F F F S HL,VM
    F F F S,V N I
    T OR T OR TV S,VI
    T OR T OR TSS,VI (H,L,N)
    +





    +
  • + + + + +
    Priority Band
    Priority Band + + + + + + + + + + +
    BAND
    OptionsImages
    HSLSNULLInputMosaicOutput
    F FF VVCriteria based
    F F FVS I
    F F F S HL,VM
    F F FS,VNI
    T OR T OR T S S,V I(H,L,N)
    T OR T ORT VVCriteria based
    T OR T OR T V SI
    +
    + + + + + Mosaicking + + + + + Original version + + + Converted to Isis 3.0 + + + Fixed bug caused by PVL refactor + + + Added appTest, and fixed fromlist filter + + + Depricated CubeProjection and ProjectionManager to ProjectionFactory + + + Added user entered range and helper button + + + Added the MATCHBANDBIN option that checks to make sure the input + cube bandbin group matches the mosaic bandbin group. The default is true. + + + Added an exception that reports which input cube is causing a problem while mosaicking. + + + Program no longer throws an exception when an input cube does not fit into the output mosaic. Instead, any + files that are not included in the output are listed in the application log. + + + Corrected bug in determining if an image fits into the output mosaic + + + Fixed one of the application tests + + + Fixed bug where input cubes where incorrectly not processed. + + + This program now utilizes ProcessMapMosaic + + + Added option "TRACK" to track pixel origin. Also added new priority called + BAND where specified input and mosaic band is compared for moving input + to mosaic and to track the pixel origin. Added parameter "TYPE" to choose + Band "NUMBER" or PVL "KEYWORD" from the BandBin group. If "BANDNUMBER" is + chosen, then "NUMBER" is activated to enter band number. If "KEYWORD" + is chosen then parameter "KEYNAME" and "KEYVALUE" are activated to enter + key name and value from the BandBin group for band comparison. Band + comparison "CRITERIA" are "LESSER" or "GREATER" than. Also there are + options "HIGHSATURATION", "LOWSATURATION" and "NULL", set to true will + cause HS, LS and NULL input pixels to be copied to the mosaic regardless + of the priorities and criteria. These options are not supported for "BENEATH" priority. + Track the origin for multiband ONTOP priority if all the Special Pixel flags are set. + Store the Serial numbers of the input mosaic in the mosaic along with the file name. + + + + + + + filename + input + + List of cubes to mosaic + + + A list of map projected cubes to mosaic. The Mapping groups + must match in order to mosaic the cubes. + + + *.txt *.lis *.lst + + + + + cube + output + + Mosaic output cube + + + The mosaic cube which will have the input cube placed + into it. + + + *.cub + + + + + string + + ONTOP + + The priority of pixel placement + + This parameter is used to select one of three ways to mosaic the + pixels in areas of overlap. + + + + + + + + + + + + + string + + + BANDNUM + + + Indicate the Band name or number to be used for comparison + + The pixels in this band will be used for comparison between input + image and the mosaic for a decision to be made in copying image into + the mosaic. + + + + + + + + + integer + 1 + Enter the Band Number + The band number should match that in the + "OriginalBand" of "BandBin" Group + + + + string + OriginalBand + Enter the Key name as it appears in the PVL + The entered key name must match the key name in the + "BandBin" + + + + + string + 1 + Enter the value associated with the "KEYNAME" + This value must match the value associated with the key + name entered in the KEYNAME + + + + + string + LESSER + The criteria (Lesser or Greater) of pixel placement in a chosen band + + This parameter is used to select one of two ways to mosaic the + pixels in areas of overlap when doing by band comparison. + + + + + + + + + + + + string + AUTO + Ground Range Options + + The ground range can either be calculated automatically or entered by the user. + If the USER option is selected, values must be entered for the MINLAT, MAXLAT, + MINLON, and MAXLON parameters. AUTO is the default for this parameter. + + + + + + + + double + Minimum Latitude + + The minimum latitude value to use in the mosaic. + + + + helperButtonCalcRange + Calculate Ranges using FROMLIST + + This button will calculate the latitude and longitude range using the files in the FROMLIST. + + $ISIS3DATA/base/icons/exec.png + + + + + double + Maximum Latitude + + The maximum latitude value to use in the mosaic. + + + + double + Minimum Longitude + + The minimum longitude value to use in the mosaic. + + + + double + Maximum Longitude + + The maximum longitude value to use in the mosaic. + + + + + + + boolean + FALSE + + Track the mosaic origin + + + If selected the application will track the mosaic origin. Once + origin is tracked, the tracker cannot be turned off. + + + + boolean + Enforce BandBin Group Match + + This option causes the application to fail if the input bandbin group does not + match the mosaic bandbin group. + + TRUE + + + boolean + FALSE + Copy Input HS (Instrument and Representation) values + + This option causes High Saturation values (both Instrument and + Representation) in the input image to be automatically copied to the + mosaic irrespective of the priority + + + + boolean + FALSE + Copy Input LS (Instrument and Representation) values + + This option causes Low Saturation values (both Instrument and + Representation) in the input image to be automatically copied to the + mosaic irrespective of the priority + + + + boolean + FALSE + Copy Input NULL values + + This option causes NULL values in the input image to be automatically + copied to the mosaic irrespective of the priority + + + + + diff --git a/isis/src/base/apps/automos/tsts/Makefile b/isis/src/base/apps/automos/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/automos/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/automos/tsts/band/Makefile b/isis/src/base/apps/automos/tsts/band/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..646c3f336d6734e9557dbb514c4960d92c14f37a --- /dev/null +++ b/isis/src/base/apps/automos/tsts/band/Makefile @@ -0,0 +1,18 @@ +APPNAME = automos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) fromlist=$(INPUT)/FromList.lst \ + mosaic=$(OUTPUT)/automosTruth1.cub \ + priority=band \ + type=keyword \ + keyname=filternumber \ + keyvalue=5 \ + criteria=greater \ + grange=auto \ + track=true \ + matchbandbin=true \ + highsaturation=true \ + lowsaturation=true \ + null=false > /dev/null; diff --git a/isis/src/base/apps/automos/tsts/mosaic/Makefile b/isis/src/base/apps/automos/tsts/mosaic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..641ecfc73c661b0bbf4927514fc7f7e18ea7269e --- /dev/null +++ b/isis/src/base/apps/automos/tsts/mosaic/Makefile @@ -0,0 +1,7 @@ +APPNAME = automos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) fromlist=$(INPUT)/FromList.lst \ + mosaic=$(OUTPUT)/automosTruth1.cub > /dev/null; diff --git a/isis/src/base/apps/automos/tsts/priority/Makefile b/isis/src/base/apps/automos/tsts/priority/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d2fd7b7fd0850b3030504dc7fa62f8a4bf983f44 --- /dev/null +++ b/isis/src/base/apps/automos/tsts/priority/Makefile @@ -0,0 +1,8 @@ +APPNAME = automos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) fromlist=$(INPUT)/FromList.lst \ + mosaic=$(OUTPUT)/automosTruth2.cub \ + priority=beneath > /dev/null; diff --git a/isis/src/base/apps/autoregtemplate/Makefile b/isis/src/base/apps/autoregtemplate/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/autoregtemplate/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/autoregtemplate/autoregtemplate.cpp b/isis/src/base/apps/autoregtemplate/autoregtemplate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99cbd1c39a4742fc2f0f0d74b024a77eebe1a28e --- /dev/null +++ b/isis/src/base/apps/autoregtemplate/autoregtemplate.cpp @@ -0,0 +1,202 @@ +#include "Isis.h" +#include "PvlObject.h" +#include "PvlGroup.h" +#include "UserInterface.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + // Get user interface + UserInterface &ui = Application::GetUserInterface(); + + Pvl algos("$ISISROOT/lib/AutoReg.plugin"); + Pvl p; + + // Begin creating the mapping group + PvlObject autoreg("AutoRegistration"); + + // Make sure the entered algorithm name is valid + string algoName = ui.GetString("ALGORITHM"); + if (!algos.HasGroup(algoName)) { + // Give the user a list of possible algorithms + string msg = "Invalid Algorithm Name [" + algoName + "] " + + "Possible Algorithms are: "; + for (int i=0; i ssamp || pline + 2 > sline) { + string msg = "The Pattern Chip must span at least a 3x3 window in the "; + msg += "Search Chip"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Set up the pattern chip group + PvlGroup patternChip("PatternChip"); + patternChip += PvlKeyword("Samples",iString(psamp)); + patternChip += PvlKeyword("Lines",iString(pline)); + if (ui.WasEntered("PMIN")) { + patternChip += PvlKeyword("ValidMinimum",iString(ui.GetInteger("PMIN"))); + } + if (ui.WasEntered("PMAX")) { + patternChip += PvlKeyword("ValidMaximum",iString(ui.GetInteger("PMAX"))); + } + if (ui.WasEntered("MINIMUMZSCORE")) { + double minimum = ui.GetDouble("MINIMUMZSCORE"); + patternChip += PvlKeyword("MinimumZScore",iString(minimum)); + + if(minimum <= 0.0) { + string msg = "MINIMUMZSCORE must be greater than 0.0 (Default = 1.0)"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + // Set up the search chip group + PvlGroup searchChip("SearchChip"); + searchChip += PvlKeyword("Samples",iString(ssamp)); + searchChip += PvlKeyword("Lines",iString(sline)); + if (ui.WasEntered("SMIN")) { + searchChip += PvlKeyword("ValidMinimum",iString(ui.GetInteger("SMIN"))); + } + if (ui.WasEntered("SMAX")) { + searchChip += PvlKeyword("ValidMaximum",iString(ui.GetInteger("SMAX"))); + } + if (ui.WasEntered("VALIDPERCENT")) { + double percent = ui.GetDouble("VALIDPERCENT"); + searchChip += PvlKeyword("ValidPercent",iString(percent)); + + if ((percent <= 0.0) || (percent > 100.0)) { + string msg = "VALIDPERCENT must be between 0.0 and 100.0 (Default = 50.0)"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + // Add groups to the autoreg object + autoreg.AddGroup(patternChip); + autoreg.AddGroup(searchChip); + + // Set up the surface model testing group + if (subPixelAccuracy) { + PvlGroup surfaceModel("SurfaceModel"); + + double distanceTol = ui.GetDouble("DISTANCETOLERANCE"); + surfaceModel += PvlKeyword("DistanceTolerance",iString(distanceTol)); + + if (distanceTol <= 0.0) { + string msg = "DISTANCETOLERANCE must be greater than 0.0 (Default = 1.5)"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + int winSize = ui.GetInteger("WINDOWSIZE"); + surfaceModel += PvlKeyword("WindowSize",iString(winSize)); + + // Make sure the window size is at least 3 + if (winSize < 3) { + string msg = "WINDOWSIZE must be greater than or equal to 3 (Default = 5)"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Make sure the window size is odd + if (winSize % 2 == 0) { + string msg = "WINDOWSIZE must be an odd number (Default = 5)"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + if (ui.GetBoolean("ECCENTRICITYTESTING")) { + double eccRatio = ui.GetDouble("ECCENTRICITYRATIO"); + surfaceModel += PvlKeyword("EccentricityRatio",iString(eccRatio)); + + if (eccRatio < 1) { + string msg = "ECCENTRICITYRATIO must be 1.0 or larger (Default = 2.0)"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + if (ui.GetBoolean("RESIDUALTESTING")) { + double residualTol = ui.GetDouble("RESIDUALTOLERANCE"); + surfaceModel += PvlKeyword("ResidualTolerance",iString(residualTol)); + + if (residualTol < 0){ + string msg = "RESIDUALTOLERANCE must be 0.0 or larger (Default = 0.1)"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + autoreg.AddGroup(surfaceModel); + } + + // Add autoreg group to Pvl + p.AddObject(autoreg); + + // Write the autoreg group pvl to the output file + string output = ui.GetFilename("TO"); + p.Write(output); + + Isis::Application::GuiLog(p); +} diff --git a/isis/src/base/apps/autoregtemplate/autoregtemplate.xml b/isis/src/base/apps/autoregtemplate/autoregtemplate.xml new file mode 100644 index 0000000000000000000000000000000000000000..e61ff4adb783f577cbb1ad69246e58ba65a57559 --- /dev/null +++ b/isis/src/base/apps/autoregtemplate/autoregtemplate.xml @@ -0,0 +1,616 @@ + + + + + + Create autoregistration group template + + + + This program creates an autoregistration group template for autoregs. Given + a specific algorithm name, it will create that specific algorithm group template. + If you are unsure of what algorithm name you want to use, running the application + with an 'unknown' algorithm name will give you an error box containing a list of the + possible algorithm names. If a tolerance is specified, the application will automatically + insert the tolerance keyword and value into the autoreg template. The user must enter + values for the chip sizes of both the pattern and search chips. The output templates + can be used in applications that use autoregistrations, such as coreg, + pointreg, findrx, etc. + + + + + Original Version + + + Added SubpixelAccuracy option. + + + Added MinimumPatternZScore option and updated appTest. + + + Moved MininmumPatternZScore keyword to PatternChip Group + + + Updated to use the current version of keywords accepted by AutoReg, + improved documentation on parameters, and improved error reports. + + + Updated tests and examples. + + + Added CHIPINTERPOLATOR and INTERPOLATORTYPE parameters to Algorithm + group. Updated examples and added error unitTest. + + + + + + coreg + pointreg + findrx + + + + + Registration and Pattern Matching + + + + + + + filename + output + + Output text file containing autoreg template + + + This file will contain the autoregistration group template. + + + + + + + + string + + Name of Algorithm to create autoregistration group + + + This is the name of the algorithm for the autoregistration group being + created. If left as unknown, an error will be reported listing all possible + options for the algorithm name. + + Undefined + + + + double + + Tolerance + + + This is the value of the tolerance for the autoregistration, + represented in the template as the Tolerance keyword. + + + + + integer + + Reduction Factor + + + Reduction factor used to speed up the pattern matching algorithm. + + None + + + + boolean + + Use sub-pixel accuracy + + + This option allows the user to specify if sub-pixel accuracy will be used in + the registration. Enables the SurfaceModel options, as those tests + will only be performed when calculating to sub-pixel accuracy. When + this parameter is true, SurfaceModel parameters may be selected. + + + DISTANCETOLERANCE + WINDOWSIZE + ECCENTRICITYTESTING + ECCENTRICITYRATIO + RESIDUALTESTING + RESIDUALTOLERANCE + + TRUE + + + + boolean + + Include ChipInterpolator keyword in template. + + + Determines whether to include the ChipInterpolator keyword in the + generated template. When this parameter is true, INTERPOLATORTYPE + may be selected. + + + + false + + + + + INTERPOLATORTYPE + + + + + string + + Interpolator to be used to load chips. + + + Type of interpolator to be used to read and load the pattern and + search chips. + + CUBICCONVOLUTIONTYPE + + + + + + + + + + + + + integer + + Pattern Chip Sample Size + + + The sample size of the pattern chip for the autoregistration. + The Sample keyword in the PatternChip group will be set to + this value in the autoreg template. + + + + + integer + + Pattern Chip Line Size + + + The line size of the pattern chip for the autoregistration. + The Line keyword in the PatternChip group will be set to + this value in the autoreg template. + + + + + integer + + Pattern Chip Valid Minimum Pixel Value + + + The minimum value a pixel must have in order to be considered valid and used + in the autoregistration. This parameter is optional, and does + not have to be set. Within AutoReg, defaults to Isis' + ValidMinimum if not provided. + + None + + + + integer + + Pattern Chip Valid Maximum Pixel Value + + + The maximum value a pixel must have in order to be considered valid and used + in the autoregistration. This parameter is optional, and does + not have to be set. Within AutoReg, defaults to isis' + ValidMaximum if not provided. + + None + + + + double + + Minimum Pattern Chip Z-Score Range (Default = 1.0) + + + This option allows the user to specify the minimum z-score range for the minimum + and maximum values for the pattern chip that will be used in the + registration. Within AutoReg, will default to 1.0 if not + provided. + + None + + + + + + + + integer + + Search Chip Sample Size + + + The sample size of the search chip for the autoregistration. + The Sample keyword in the SearchChip group will be set to + this value in the autoreg template. + + + + + integer + + Search Chip Line Size + + + The line size of the search chip for the autoregistration. + The Line keyword in the SearchChip group will be set to + this value in the autoreg template. + + + + + integer + + Search Chip Minimum Valid Pixel Value + + + The minimum value a pixel must have in order to be considered valid and used + in the autoregistration. This parameter is optional, and does + not have to be set. Within AutoReg, defaults to Isis' + ValidMinimum if not provided. + + None + + + + integer + + Search Chip Maximum Valid Pixel Value + + + The maximum value a pixel must have in order to be considered valid and used + in the autoregistration. This parameter is optional, and does + not have to be set. Within AutoReg, defaults to isis' + ValidMaximum if not provided. + + None + + + + double + + Search Chip Valid Pixel Percent Value (Default = 50.0) + + + The minimum percent of pixels in the pattern chip that must be valid in order for + the autoregistration of the chip to be used. This parameter is optional, and does + not have to be set. Within AutoReg, will default to 50.0 if not + provided. + + None + + + + + + + + double + + Distance Tolerance + + + Set the distance the surface model is allowed to move away from + the best whole pixel fit in the chip. + + 1.5 + + + + integer + + Window Size + + + Set the surface model window size in terms of the legnth of a + square window. The pixels in this window will be used to fit a + surface model in order to compute to sub-pixel accuracy. Must + be odd and greater than or equal to three. + + 5 + + + + boolean + + Eccentricity Testing + + + Whether or not the eccentricity of the surface model should be + considered when calculating to sub-pixel accuracy. For the sake + of the template, disabling this parameter will result in no + EccentricityRatio keyword. In AutoReg, eccentricity testing is + disabled by not providing the EccentricityRatio keyword. + + + ECCENTRICITYRATIO + + FALSE + + + + double + + Ratio of Surface Model Major Axis to Normalized Minor Axis + + + Use eccentricity to throw out points whose surface models are + too elliptical. Though eccentricity is a decimal value between + 0 and 1, it can also be thought of as the ratio of the major + axis to the minor axis. Normalazing the minor axis to 1.0, the + anetecedent of that ratio becomes this value. This parameter + states "the major axis length can be no more than this many + times larger than the minor axis." + + 2.0 + + + + boolean + + Residual Testing + + + Whether or not the maximum average residual of the surface model + should be considered when calculating to sub-pixel accuracy. + For the sake of the template, disabling this parameter will + result in no ResidualTolerance keyword. In AutoReg, + eccentricity testing is disabled by not providing the + ResidualTolerance keyword. + + + RESIDUALTOLERANCE + + FALSE + + + + double + + Maximum Average Residual Tolerance + + + Set the maximum average residual allowed from the surface + model. Changing this tolerance allows the user to throw out + points whose surfaces cannot be modeled well. The average + residual is derived from the least squares solution fitting a + surface model to a set of known data points, and computed by + summing the absolute values of all the residuals (computed z + minus actual z) and dividing by the number of residuals. + + 0.1 + + + + + + + + + + Create an Autoreg Template with all Defaults + + + This example shows how the autoregtemplate application works, and how + to create a simple AutoReg template. Here, only the required parameters + have been entered. Because SubpixelAccuracy is "true" by default, there + is a SurfaceModel group in the output PVL containing the default + DistanceTolerance and WindowSize. +
    +            Object = AutoRegistration
    +              Group = Algorithm
    +                Name             = MaximumCorrelation
    +                Tolerance        = 0.7
    +                SubpixelAccuracy = True
    +              End_Group
    +            
    +              Group = PatternChip
    +                Samples = 15
    +                Lines   = 15
    +              End_Group
    +            
    +              Group = SearchChip
    +                Samples = 31
    +                Lines   = 31
    +              End_Group
    +            
    +              Group = SurfaceModel
    +                DistanceTolerance = 1.5
    +                WindowSize        = 5
    +              End_Group
    +            End_Object
    +            End
    +        
    + The above output is the text file resulting when the following + command line is run: +
    + + + algorithm=MaximumCorrelation tolerance=0.7 psamp=15 pline=15 + ssamp=31 sline=31 to=out.txt + + + Run autoregtemplate with an algorithm name, tolerance, output file + name, and search and pattern chip sizes. + + +
    + + + + Create an Autoreg Template without Subpixel Accuracy and with Chip + Interpolator specified + + + This example shows the process and results of creating an AutoReg + template that disables calculating to subpixel accuracy. All the + parameter values from the previous example are left the same, except + that the SUBPIXELACCURACY keyword is set to "false". As a result, there + is no SurfaceModel PVL group, and none of those keywords may be entered. + Notice, the INTERPOLATORTYPE parameter is not specified in the + commandline. Thus, the default cubic convolution type of interpolator + is used to load chips. +
    +            Object = AutoRegistration
    +              Group = Algorithm
    +                Name             = MaximumCorrelation 
    +                Tolerance        = 0.7 
    +                SubpixelAccuracy = False
    +                ChipInterpolator = CubicConvolutionType
    +              End_Group
    +            
    +              Group = PatternChip
    +                Samples = 15 
    +                Lines   = 15 
    +              End_Group
    +            
    +              Group = SearchChip
    +                Samples = 31 
    +                Lines   = 31 
    +              End_Group
    +            End_Object 
    +            End 
    +        
    + The above output is the text file resulting when the following + command line is run: +
    + + + algorithm=MaximumCorrelation tolerance=0.7 subpixelaccuracy=false + chipinterpolator=true psamp=15 pline=15 ssamp=31 sline=31 to=out.txt + + + Run autoregtemplate with an algorithm name, tolerance, output file + name, search and pattern chip sizes, specified chip interpolator, but + no subpixel accuracy computation. + + +
    + + + + Create an AutoReg Template Specifying Every Parameter + + + This example shows the kinds of values one might potentially enter for + every valid keyword in an AutoReg template. Every parameter is + specified in the template for this example. The only parameter not + specified in the command line is subpixel accuracy, which must remain at + its default ("true") in order to have a SurfaceModel group in the output + PVL. ChipInterpolator is enabled in order to choose an interpolator + type. Also, EccentricityTesting and ResidualTesting must be + enabled in order to enter values for their keywords, because unlike + MinimumZScore and ValidPercent (keywords that have defaults inside + AutoReg if not specified in the template), Eccentricity and Residual + testing are disabled altogether if EccentricityRatio and + ResidualTolerance are not specified in the AutoReg template. +
     
    +            Object = AutoRegistration
    +              Group = Algorithm
    +                Name             = MinimumDifference
    +                Tolerance        = 0.7
    +                ReductionFactor  = 2
    +                SubpixelAccuracy = True
    +                ChipInterpolator = NearestNeighborType
    +              End_Group
    +            
    +              Group = PatternChip
    +                Samples       = 15
    +                Lines         = 15
    +                ValidMinimum  = 1200
    +                ValidMaximum  = 2800
    +                MinimumZScore = 0.5
    +              End_Group
    +            
    +              Group = SearchChip
    +                Samples      = 31
    +                Lines        = 31
    +                ValidMinimum = 1200
    +                ValidMaximum = 2800
    +                ValidPercent = 75.0
    +              End_Group
    +            
    +              Group = SurfaceModel
    +                DistanceTolerance = 2.5
    +                WindowSize        = 11
    +                EccentricityRatio = 5.0
    +                ResidualTolerance = 0.001
    +              End_Group
    +            End_Object
    +            End
    +       
    + The above output is the text file resulting when the following command + line is run: +
    + + + algorithm=MinimumDifference tolerance=0.7 + reductionfactor=2 chipinterpolator=true + interpolatortype=nearestneighbor psamp=15 pline=15 pmin=1200 pmax=2800 + validpercent=75 ssamp=31 sline=31 smin=1200 smax=2800 minimumzscore = + 0.5 distancetolerance=2.5 windowsize=11 eccentricitytesting=true + eccentricityratio=5.0 residualtesting=true residualtolerance=0.001 + to=out.txt + + + Run autoregtemplate with all parameters specified by the user. + + +
    + +
    + +
    + diff --git a/isis/src/base/apps/autoregtemplate/tsts/Makefile b/isis/src/base/apps/autoregtemplate/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/autoregtemplate/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/autoregtemplate/tsts/errors/Makefile b/isis/src/base/apps/autoregtemplate/tsts/errors/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0024140ff658af261ccbc3ef4ac2102fc5b30607 --- /dev/null +++ b/isis/src/base/apps/autoregtemplate/tsts/errors/Makefile @@ -0,0 +1,122 @@ +.IGNORE: + +APPNAME = autoregtemplate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaxCor \ + tolerance=0.7 \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 2> $(OUTPUT)/error.txt > /dev/null; + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaximumCorrelation \ + tolerance=0.7 \ + reduction=0 \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 2>> $(OUTPUT)/error.txt > /dev/null; + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaximumCorrelation \ + tolerance=0.7 \ + interpolatortype=C \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 2>> $(OUTPUT)/error.txt > /dev/null; + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaximumCorrelation \ + tolerance=0.7 \ + chipinterpolator=true \ + interpolatortype=NONE \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 2>> $(OUTPUT)/error.txt > /dev/null; + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaximumCorrelation \ + tolerance=0.7 \ + chipinterpolator=true \ + psamp=15 \ + pline=15 \ + ssamp=3 \ + sline=3 2>> $(OUTPUT)/error.txt > /dev/null; + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaximumCorrelation \ + tolerance=0.7 \ + chipinterpolator=true \ + interpolatortype=cubic \ + psamp=15 \ + pline=15 \ + ssamp=17 \ + sline=16 2>> $(OUTPUT)/error.txt > /dev/null; + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaximumCorrelation \ + tolerance=0.7 \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 \ + minimumz=0 2>> $(OUTPUT)/error.txt > /dev/null; + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaximumCorrelation \ + tolerance=0.7 \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 \ + validpercent=0 2>> $(OUTPUT)/error.txt > /dev/null; + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaximumCorrelation \ + tolerance=0.7 \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 \ + subpixel=true \ + dist=0 2>> $(OUTPUT)/error.txt > /dev/null; + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaximumCorrelation \ + tolerance=0.7 \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 \ + subpixel=true \ + window=2 2>> $(OUTPUT)/error.txt > /dev/null; + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaximumCorrelation \ + tolerance=0.7 \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 \ + subpixel=true \ + window=4 2>> $(OUTPUT)/error.txt > /dev/null; + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaximumCorrelation \ + tolerance=0.7 \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 \ + subpixel=true \ + eccentricitytest=true \ + eccentricityratio=0 2>> $(OUTPUT)/error.txt > /dev/null; + $(APPNAME) to=$(OUTPUT)/autoregtemplateTruth.txt \ + algorithm=MaximumCorrelation \ + tolerance=0.7 \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 \ + subpixel=true \ + residualtest=true \ + residualtol=-1 2>> $(OUTPUT)/error.txt > /dev/null; + cat $(OUTPUT)/error.txt | sed s+/usgs/cpkgs/isis3/testData/isis/src/base/apps/mat2cnet/tsts/errors/++g > $(OUTPUT)/errors.txt; + rm -f $(OUTPUT)/error.txt; + rm -f $(OUTPUT)/autoregtemplateTruth.txt; diff --git a/isis/src/base/apps/autoregtemplate/tsts/maxCorr/Makefile b/isis/src/base/apps/autoregtemplate/tsts/maxCorr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5bffac5a100b099c525f9f0bff1ad518e2729852 --- /dev/null +++ b/isis/src/base/apps/autoregtemplate/tsts/maxCorr/Makefile @@ -0,0 +1,12 @@ +APPNAME = autoregtemplate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) algorithm=MaximumCorrelation \ + tolerance=0.7 \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 \ + to=$(OUTPUT)/autoregtemplateTruth1.txt > /dev/null; diff --git a/isis/src/base/apps/autoregtemplate/tsts/minDiff/Makefile b/isis/src/base/apps/autoregtemplate/tsts/minDiff/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f29284eac5407fedfafc10fb80386068e22b8eb5 --- /dev/null +++ b/isis/src/base/apps/autoregtemplate/tsts/minDiff/Makefile @@ -0,0 +1,27 @@ +APPNAME = autoregtemplate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) algorithm=MinimumDifference \ + tolerance=0.7 \ + reductionfactor=2 \ + chipinterpolator=true \ + interpolatortype=NEARESTNEIGHBORTYPE \ + psamp=15 \ + pline=15 \ + pmin=1200 \ + pmax=2800 \ + validpercent=75 \ + ssamp=31 \ + sline=31 \ + smin=1200 \ + smax=2800 \ + minimumzscore = 0.5 \ + distancetolerance=2.5 \ + windowsize=11 \ + eccentricitytesting=true \ + eccentricityratio=5.0 \ + residualtesting=true \ + residualtolerance=0.001 \ + to=$(OUTPUT)/autoregtemplateTruth2.txt > /dev/null; diff --git a/isis/src/base/apps/autoregtemplate/tsts/noSubpixel/Makefile b/isis/src/base/apps/autoregtemplate/tsts/noSubpixel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..15a3ce7971eaccbac0637d22e905ebf542748c07 --- /dev/null +++ b/isis/src/base/apps/autoregtemplate/tsts/noSubpixel/Makefile @@ -0,0 +1,15 @@ +APPNAME = autoregtemplate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) algorithm=MaximumCorrelation \ + tolerance=0.7 \ + subpixelaccuracy=false \ + chipinterpolator=t \ + interpolatortype=b \ + psamp=15 \ + pline=15 \ + ssamp=31 \ + sline=31 \ + to=$(OUTPUT)/autoregtemplateTruth3.txt > /dev/null; diff --git a/isis/src/base/apps/autoseed/Makefile b/isis/src/base/apps/autoseed/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/autoseed/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/autoseed/autoseed.cpp b/isis/src/base/apps/autoseed/autoseed.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e67ba3506fb5c701c7b38e29b8d0bb6c5f8af26f --- /dev/null +++ b/isis/src/base/apps/autoseed/autoseed.cpp @@ -0,0 +1,515 @@ +#include "Isis.h" + +#include +#include + +#include "Brick.h" +#include "CameraFactory.h" +#include "ControlNet.h" +#include "ControlMeasure.h" +#include "ControlPoint.h" +#include "Cube.h" +#include "geos/util/GEOSException.h" +#include "ID.h" +#include "iException.h" +#include "iString.h" +#include "ImageOverlap.h" +#include "ImageOverlapSet.h" +#include "PolygonSeeder.h" +#include "PolygonSeederFactory.h" +#include "PolygonTools.h" +#include "Process.h" +#include "Pvl.h" +#include "PvlKeyword.h" +#include "PvlGroup.h" +#include "SerialNumberList.h" +#include "UniversalGroundMap.h" +#include "SpecialPixel.h" + +enum SeedDomain { + XY, + SampleLine +}; + + +using namespace std; +using namespace Isis; + +void IsisMain() { + + UserInterface &ui = Application::GetUserInterface(); + SerialNumberList serialNumbers(ui.GetFilename("FROMLIST")); + + // Get the AutoSeed PVL internalized + Pvl seedDef(ui.GetFilename("SEEDDEF")); + + PolygonSeeder *seeder = PolygonSeederFactory::Create(seedDef); + Pvl invalidInput = seeder->InvalidInput(); + PvlGroup &unusedDefKeywords = invalidInput.FindGroup( + "PolygonSeederAlgorithm", Pvl::Traverse); + + // Get the distance from the edge of an image a measure must be + double pixelsFromEdge = -1.0; + if(seedDef.HasKeyword("PixelsFromEdge", Pvl::Traverse)) { + pixelsFromEdge = seedDef.FindKeyword("PixelsFromEdge", Pvl::Traverse); + if(unusedDefKeywords.HasKeyword("PixelsFromEdge")) + unusedDefKeywords.DeleteKeyword("PixelsFromEdge"); + } + + // Get the Emission range + double minEmission = 0.0; + double maxEmission = 180.0; + if(seedDef.HasKeyword("MinEmission", Pvl::Traverse)) { + minEmission = seedDef.FindKeyword("MinEmission", Pvl::Traverse); + if(unusedDefKeywords.HasKeyword("MinEmission")) + unusedDefKeywords.DeleteKeyword("MinEmission"); + } + if(seedDef.HasKeyword("MaxEmission", Pvl::Traverse)) { + maxEmission = seedDef.FindKeyword("MaxEmission", Pvl::Traverse); + if(unusedDefKeywords.HasKeyword("MaxEmission")) + unusedDefKeywords.DeleteKeyword("MaxEmission"); + } + + // Get the Incidence range + double minIncidence = 0.0; + double maxIncidence = 180.0; + if(seedDef.HasKeyword("MinIncidence", Pvl::Traverse)) { + minIncidence = seedDef.FindKeyword("MinIncidence", Pvl::Traverse); + if(unusedDefKeywords.HasKeyword("MinIncidence")) + unusedDefKeywords.DeleteKeyword("MinIncidence"); + } + if(seedDef.HasKeyword("MaxIncidence", Pvl::Traverse)) { + maxIncidence = seedDef.FindKeyword("MaxIncidence", Pvl::Traverse); + if(unusedDefKeywords.HasKeyword("MaxIncidence")) + unusedDefKeywords.DeleteKeyword("MaxIncidence"); + } + + // Get the DN range + bool hasDNRestriction = false; + double minDN = -DBL_MAX; + double maxDN = DBL_MAX; + if(seedDef.HasKeyword("MinDN", Pvl::Traverse)) { + minDN = seedDef.FindKeyword("MinDN", Pvl::Traverse); + hasDNRestriction = true; + if(unusedDefKeywords.HasKeyword("MinDN")) + unusedDefKeywords.DeleteKeyword("MinDN"); + } + if(seedDef.HasKeyword("MaxDN", Pvl::Traverse)) { + maxDN = seedDef.FindKeyword("MaxDN", Pvl::Traverse); + hasDNRestriction = true; + if(unusedDefKeywords.HasKeyword("MaxDN")) + unusedDefKeywords.DeleteKeyword("MaxDN"); + } + + // Get the resolution + double minResolution = 0.0; + double maxResolution = 0.0; + if(seedDef.HasKeyword("MinResolution", Pvl::Traverse)) { + minResolution = seedDef.FindKeyword("MinResolution", Pvl::Traverse); + if(unusedDefKeywords.HasKeyword("MinResolution")) + unusedDefKeywords.DeleteKeyword("MinResolution"); + } + if(seedDef.HasKeyword("MaxResolution", Pvl::Traverse)) { + maxResolution = seedDef.FindKeyword("MaxResolution", Pvl::Traverse); + if(unusedDefKeywords.HasKeyword("MaxResolution")) + unusedDefKeywords.DeleteKeyword("MaxResolution"); + } + + // Get seed domain for unit conversion, no keyword == XY + SeedDomain seedDomain = XY; + if(seedDef.HasKeyword("SeedDomain", Pvl::Traverse)) { + iString domain = (std::string) seedDef.FindKeyword("SeedDomain", Pvl::Traverse); + if(unusedDefKeywords.HasKeyword("SeedDomain")) + unusedDefKeywords.DeleteKeyword("SeedDomain"); + + if(domain.UpCase() == "SAMPLELINE") { + seedDomain = SampleLine; + } + else if(domain.UpCase() != "XY") { + iString msg = "Invalid value provided for keywork [SeedDomain]"; + msg += " Possible values include [XY, SampleLine]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + // Grab the labels from the first filename in the SerialNumberList to get + // some info + Pvl cubeLab(serialNumbers.Filename(0)); + + // Construct a Projection for converting between Lon/Lat and X/Y + // This is used inside the seeding algorithms. + // Note: Should this be an option to include this in the program? + PvlGroup inst = cubeLab.FindGroup("Instrument", Pvl::Traverse); + string target = inst["TargetName"]; + PvlGroup radii = Projection::TargetRadii(target); + Isis::Pvl maplab; + maplab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = maplab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius", (string)radii["EquatorialRadius"]); + mapGroup += Isis::PvlKeyword("PolarRadius", (string)radii["PolarRadius"]); + mapGroup += Isis::PvlKeyword("LatitudeType", "Planetocentric"); + mapGroup += Isis::PvlKeyword("LongitudeDirection", "PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain", 360); + mapGroup += Isis::PvlKeyword("CenterLatitude", 0); + mapGroup += Isis::PvlKeyword("CenterLongitude", 0); + mapGroup += Isis::PvlKeyword("ProjectionName", "Sinusoidal"); + + //PolygonSeeder *seeder = PolygonSeederFactory::Create(seedDef); + + Projection *proj = NULL; + UniversalGroundMap *ugmap = NULL; + if(seedDomain == XY) { + proj = Isis::ProjectionFactory::Create(maplab); + } + else if(seedDomain == SampleLine) { + Cube cube; + cube.Open(serialNumbers.Filename(0)); + ugmap = new UniversalGroundMap(*cube.Label()); + } + + // Create the control net to store the points in. + ControlNet cnet; + cnet.SetType(ControlNet::ImageToGround); + cnet.SetTarget(target); + string networkId = ui.GetString("NETWORKID"); + cnet.SetNetworkId(networkId); + cnet.SetUserName(Isis::Application::UserName()); + cnet.SetDescription(ui.GetString("DESCRIPTION")); + + // Set up an automatic id generator for the point ids + ID pointId = ID(ui.GetString("POINTID")); + + // Find all the overlaps between the images in the FROMLIST + // The overlap polygon coordinates are in Lon/Lat order + ImageOverlapSet overlaps; + overlaps.ReadImageOverlaps(ui.GetFilename("OVERLAPLIST")); + + // Create a Universal Ground Map (UGM) for each image in the list + int stats_noOverlap = 0; + int stats_tolerance = 0; + + map gMaps; + for(int sn = 0; sn < serialNumbers.Size(); ++sn) { + // Create the UGM for the cube associated with this SN + Pvl lab = Pvl(serialNumbers.Filename(sn)); + gMaps.insert(std::pair + (serialNumbers.SerialNumber(sn), new UniversalGroundMap(lab))); + } + + stringstream errors(stringstream::in | stringstream::out); + int errorNum = 0; + + // Process each overlap area + // Seed measurments into it + // Store the measurments in the control network + + bool previousControlNet = ui.WasEntered("CNET"); + + vector< geos::geom::Point *> points; + if(previousControlNet) { + + ControlNet precnet(ui.GetFilename("CNET")); + + Progress progress; + progress.SetText("Calculating Provided Control Net"); + progress.SetMaximumSteps(precnet.Size()); + progress.CheckStatus(); + + for(int i = 0 ; i < precnet.Size(); i ++) { + ControlPoint cp = precnet[i]; + ControlMeasure cm = cp[0]; + if(cp.HasReference()) { + cm = cp[cp.ReferenceIndex()]; + } + + string c = serialNumbers.Filename(cm.CubeSerialNumber()); + Pvl cubepvl(c); + Camera *cam = CameraFactory::Create(cubepvl); + cam->SetImage(cm.Sample(), cm.Line()); + + + points.push_back(Isis::globalFactory.createPoint(geos::geom::Coordinate( + cam->UniversalLongitude(), cam->UniversalLatitude()))); + + delete cam; + cam = NULL; + + progress.CheckStatus(); + } + + } + + Progress progress; + progress.SetText("Seeding Points"); + progress.SetMaximumSteps(overlaps.Size()); + progress.CheckStatus(); + + int cpIgnoredCount = 0; + int cmIgnoredCount = 0; + + for(int ov = 0; ov < overlaps.Size(); ++ov) { + progress.CheckStatus(); + + if(overlaps[ov]->Size() == 1) { + stats_noOverlap++; + continue; + } + + // Checks if this overlap was already seeded + if(previousControlNet) { + + // Grabs the Multipolygon's Envelope for Lat/Lon comparison + const geos::geom::MultiPolygon *lonLatPoly = overlaps[ov]->Polygon(); + + bool overlapSeeded = false; + for(unsigned int j = 0; j < lonLatPoly->getNumGeometries() && !overlapSeeded; j ++) { + const geos::geom::Geometry *lonLatGeom = lonLatPoly->getGeometryN(j); + + // Checks if Control Point is in the MultiPolygon using Lon/Lat + for(unsigned int i = 0 ; i < points.size() && !overlapSeeded; i ++) { + if(lonLatGeom->contains(points[i])) overlapSeeded = true; + } + } + + if(overlapSeeded) continue; + } + + // Seed this overlap with points + const geos::geom::MultiPolygon *polygonOverlaps = overlaps[ov]->Polygon(); + std::vector points; + + try { + geos::geom::MultiPolygon *mp = NULL; + if(seedDomain == XY) { + mp = PolygonTools::LatLonToXY(*polygonOverlaps, proj); + } + else if(seedDomain == SampleLine) { + mp = PolygonTools::LatLonToSampleLine(*polygonOverlaps, ugmap); + } + points = seeder->Seed(mp); + } + catch(iException &e) { + + if(ui.WasEntered("ERRORS")) { + + if(errorNum > 0) { + errors << endl; + } + errorNum ++; + + errors << e.PvlErrors().Group(0).FindKeyword("Message")[0]; + for(int serNum = 0; serNum < overlaps[ov]->Size(); serNum++) { + if(serNum == 0) { + errors << ": "; + } + else { + errors << ", "; + } + errors << (*overlaps[ov])[serNum]; + } + } + + e.Clear(); + continue; + } + + // No points were seeded in this polygon, so collect some stats and move on + //if (seed.size() == 0) { + if(points.size() == 0) { + stats_tolerance++; + continue; + } + + vector seed; + if(seedDomain == XY) { + // Convert the X/Y points back to Lat/Lon points + for(unsigned int pt = 0; pt < points.size(); pt ++) { + if(proj->SetCoordinate(points[pt]->getX(), points[pt]->getY())) { + seed.push_back(Isis::globalFactory.createPoint( + geos::geom::Coordinate(proj->UniversalLongitude(), + proj->UniversalLatitude()))); + } + else { + iString msg = "Unable to convert from X/Y to a (lon,lat)"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + } + else if(seedDomain == SampleLine) { + // Convert the Sample/Line points back to Lat/Lon points + for(unsigned int pt = 0; pt < points.size(); pt ++) { + if(ugmap->SetImage(points[pt]->getX(), points[pt]->getY())) { + seed.push_back(Isis::globalFactory.createPoint( + geos::geom::Coordinate(ugmap->UniversalLongitude(), + ugmap->UniversalLatitude()))); + } + else { + iString msg = "Unable to convert from Sample/Line to a (lon,lat)"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + } + + // Create a control point for each seeded point in this overlap + for(unsigned int point = 0; point < seed.size(); ++point) { + + ControlPoint control; + control.SetId(pointId.Next()); + control.SetType(ControlPoint::Tie); + + // Create a measurment at this point for each image in the overlap area + for(int sn = 0; sn < overlaps[ov]->Size(); ++sn) { + bool ignore = false; + + // Get the line/sample of the lat/lon for this cube + UniversalGroundMap *gmap = gMaps[(*overlaps[ov])[sn]]; + if(!gmap->SetUniversalGround(seed[point]->getY(), seed[point]->getX())) { + std::string msg = "Unable to set Universal Ground for Image:" + serialNumbers.Filename(sn); + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + + // Check the line/sample with the gmap for image edge + if(pixelsFromEdge > gmap->Sample() || pixelsFromEdge > gmap->Line() + || gmap->Sample() > gmap->Camera()->Samples() - pixelsFromEdge + || gmap->Line() > gmap->Camera()->Lines() - pixelsFromEdge) { + ignore = true; + } + + // Check the Emission/Incidence Angle with the camera from the gmap + if(gmap->Camera()->EmissionAngle() < minEmission || + gmap->Camera()->EmissionAngle() > maxEmission) { + ignore = true; + } + if(gmap->Camera()->IncidenceAngle() < minIncidence || + gmap->Camera()->IncidenceAngle() > maxIncidence) { + ignore = true; + } + + // Check the DNs with the cube, Note: this is costly to do + if(hasDNRestriction) { + Cube cube; + string c = serialNumbers.Filename((*overlaps[ov])[sn]); + cube.Open(c); + Isis::Brick brick(1, 1, 1, cube.PixelType()); + brick.SetBasePosition((int)gmap->Camera()->Sample(), (int)gmap->Camera()->Line(), (int)gmap->Camera()->Band()); + cube.Read(brick); + if(Isis::IsSpecial(brick[0]) || brick[0] > maxDN || brick[0] < minDN) { + ignore = true; + } + } + + // Check the Resolution with the camera from the gmap + if(gmap->Resolution() < minResolution || + (maxResolution > 0.0 && gmap->Resolution() > maxResolution)) { + ignore = true; + } + + // Put the line/samp into a measurment + ControlMeasure measurment; + measurment.SetCoordinate(gmap->Sample(), gmap->Line(), + ControlMeasure::Estimated); + measurment.SetType(ControlMeasure::Estimated); + measurment.SetCubeSerialNumber((*(overlaps[ov]))[sn]); + measurment.SetDateTime(); + measurment.SetIgnore(ignore); + if(ignore) { + cmIgnoredCount ++; + } + measurment.SetChooserName("Application autoseed"); + if(sn == 0) measurment.SetReference(true); + control.Add(measurment); + } + + if(control.NumValidMeasures() < 2) { + control.SetIgnore(true); + cpIgnoredCount ++; + } + + cnet.Add(control); + delete seed[point]; + + } // End of create control points loop + + } // End of seeding loop + + // All done with the UGMs so delete them + for(unsigned int sn = 0; sn < gMaps.size(); ++sn) { + UniversalGroundMap *gmap = gMaps[serialNumbers.SerialNumber(sn)]; + delete gmap; + } + + for(unsigned int i = 0 ; i < points.size(); i ++) { + delete points[i]; + points[i] = NULL; + } + + gMaps.clear(); + + //Log the ERRORS file + if(ui.WasEntered("ERRORS")) { + string errorname = ui.GetFilename("ERRORS"); + std::ofstream errorsfile; + errorsfile.open(errorname.c_str()); + errorsfile << errors.str(); + errorsfile.close(); + } + + // Make sure the control network is not empty + if(cnet.Size() == 0) { + string msg = "The ouput Control Network [TO] is empty. This is likely due"; + msg += " to the input cubes failing to overlap."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + // Write the control network out + cnet.Write(ui.GetFilename("TO")); + + // create SeedDef group and add to print.prt + PvlGroup pluginInfo = seeder->PluginParameters("SeedDefinition"); + pluginInfo.AddKeyword(PvlKeyword("MaxIncidence", maxIncidence)); + pluginInfo.AddKeyword(PvlKeyword("MaxEmission", maxEmission)); + Application::Log(pluginInfo); + + // inform user of any unused (invalid) keywords found in the def file + if(unusedDefKeywords.Keywords() != 0) { + PvlGroup unusedKeywords(unusedDefKeywords); + unusedKeywords.SetName("InvalidKeyordsFoundInDefFile"); + Application::Log(unusedKeywords); + } + + // calc # of points and measures for results group in print.prt + int cpCount = 0; + int msCount = 0; + for(int i = 0; i < cnet.Size(); i++) { + cpCount++; + for(int j = 0; j < cnet[i].Size(); j++) + msCount++; + } + + // create Results group and add to print.prt + PvlKeyword cpCountKeyword("ControlPointCount", iString(cpCount)); + PvlKeyword msCountKeyword("ControlMeasureCount", iString(msCount)); + PvlKeyword cpIgnoredCountKeyword("ControlPointsIgnored", iString(cpIgnoredCount)); + PvlKeyword cmIgnoredCountKeyword("ControlMeasuresIgnored", iString(cmIgnoredCount)); + + PvlGroup resultsGrp("Results"); + resultsGrp.AddKeyword(cpCountKeyword); + resultsGrp.AddKeyword(msCountKeyword); + resultsGrp.AddKeyword(cpIgnoredCountKeyword); + resultsGrp.AddKeyword(cmIgnoredCountKeyword); + + Application::Log(resultsGrp); + + if(seedDomain == XY) { + delete proj; + proj = NULL; + } + else if(seedDomain == SampleLine) { + delete ugmap; + ugmap = NULL; + } + + delete seeder; + seeder = NULL; + +} diff --git a/isis/src/base/apps/autoseed/autoseed.xml b/isis/src/base/apps/autoseed/autoseed.xml new file mode 100644 index 0000000000000000000000000000000000000000..adea8024cff7686db1bdd81cc6f6c9f7beb75edc --- /dev/null +++ b/isis/src/base/apps/autoseed/autoseed.xml @@ -0,0 +1,229 @@ + + + + + + Creates a control network for a list of images + + + +

    + This program creates a first guess control network with tie points between + overlapping images. The control network is based on the available pointing information + for each image (most likely SPICE). +

    +
    + + + Control Networks + + + + + Original version + + + Changed category from Geometry to Control Networks + + + Removed terminal output code + + + Added the "OVERLAPLIST" parameter. + + + Added the optional CNET parameter and fixed memory leaks. + + + Removed beta status, fixed a bug, and added test. + + + Replaced the cerr output with the ERRORS option. + + + Added the seed definition parameters to the results group of the + print.prt file + + + Fixed the progress objects. + + + Moved seed definition parameters to unique group, and encapsulated the + group creation within the seeding objects. + + + Added .def filter to the SEEDDEF parameter. + + + Added keywords to the SEEDDEF file which tell autoseed which Control + Measures to mark as ignored under the keyword's conditions. These new + keywords include "PixelsFromEdge", "MinEmission", "MaxEmission", + "MinIncidence", "MaxIncidence", "MinResolution", and "MaxResolution". + Any Control Point with less than 2 valid measures as a result of these + keywords will be marked as ignored. + + + Added the keywords "MinDN" and "MaxDN" to the SEEDDEF possibilities. + Using these keywords will increase runtime. + + + Added Results group to print.prt + + + Now throws an error if the output Control Net is empty. + + + Added optional parameters to results group. Also now report invalid + or unrecognized keywords found in the def file to the user. + + + Fixed error while checking for max and min dn values restriction for a + valid control point. Ignore control points with special pixel dn values. + + + Adapted to handle seeding in both XY and SampleLine units using the + optional Seeddef keywork SeedDomain. + + + Added the ControlPointsIgnored and ControlMeasuresIgnored keywords to the + results group. + + + Throw exception, when SetUniversalGround Fails + + + + + + + + + filename + input + + List of Input cubes to create a control network for + + + Use this parameter to select the filename which contains a list of + cube filename to be used to create the control network. + + + *.lis + + + + + filename + input + + PVL file containing the description of the autoseed plugin + + + Use this parameter to select the filename which contains the + definition of the type of autoseeding to be preformed. This file + must contain a valid Autoseed plugin definition in PVL format. + + + *.api *.def + + + + + filename + input + + Input cube overlap list + + + This file should contain overlaps of cubes in the control network. This file can be + generated by running "findimageoverlaps." + + + + + filename + input + No previous control network + Control Network which already seeds some of the overlap + + Use this parameter to provide a Control Network that already seeds a + portion of the provided overlap. The Control Points it contains will + prevent re-seeding during execution, resulting in a new Control + Network that only seeds overlaps that do not contain any Control + Points. You may then use cnetmerge to combine this Control Network + (CNET) with the resultant Control Network (TO) to create a single + Control Network for the entire overlap. + + *.net + + + + filename + output + + Output control network + + + This file will contain the autoseeded control network + + + + + filename + output + No Error Output + + Errors generated while seeding the overlaps + + + This file will contain the errors that occurred while seeding the overlaps. + + + + + + + + + string + + Name of this control network + + + The ID or name of this particular control network. This string + should be unique. + + + + + string + + The pattern to be used to create point ids. + + + A string with one and only one set of question marks ("?"). + This string will be used to create unique IDs for each control + point created by this program. The question marks will be replaced + with a number beginning with zero. For example the pattern + "User????" would create point IDs "User0001" through + "User9999". Note: Make sure there are enough "?"s for all the control + points that may be created during this run. If all question marks are + exausted the program will throw an error. + + + + + string + + The description of the network. + + + A string describing purpose of this control network. + + + + + + + +
    diff --git a/isis/src/base/apps/autoseed/tsts/Makefile b/isis/src/base/apps/autoseed/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/autoseed/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/autoseed/tsts/overlap/Makefile b/isis/src/base/apps/autoseed/tsts/overlap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7b37040d1cb5b8e19ed2cfc8292e716f6a926f98 --- /dev/null +++ b/isis/src/base/apps/autoseed/tsts/overlap/Makefile @@ -0,0 +1,26 @@ +APPNAME = autoseed + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(LS) $(INPUT)/*sub.cub > $(OUTPUT)/sub.lis; + $(APPNAME) fromlist=$(OUTPUT)/sub.lis \ + seeddef=$(INPUT)/grid.pvl \ + overlaplist=$(INPUT)/suboverlaps.def \ + to=$(OUTPUT)/sub.net.pvl \ + networkid=SubNetwork \ + pointid="sub????" \ + description=SubNetwork \ + > /dev/null; + $(APPNAME) fromlist=$(OUTPUT)/list.lis \ + seeddef=$(INPUT)/smallgrid.pvl \ + overlaplist=$(INPUT)/listoverlaps.def \ + cnet=$(OUTPUT)/sub.net.pvl \ + to=$(OUTPUT)/new.net.pvl \ + networkid=NewNetwork \ + pointid="new????" \ + description=NewNetwork \ + > /dev/null; + $(RM) $(OUTPUT)/list.lis; + $(RM) $(OUTPUT)/sub.lis; diff --git a/isis/src/base/apps/autoseed/tsts/seeddef/Makefile b/isis/src/base/apps/autoseed/tsts/seeddef/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9ee1420d2d11aa89f88834ae2fa7f227651502dc --- /dev/null +++ b/isis/src/base/apps/autoseed/tsts/seeddef/Makefile @@ -0,0 +1,37 @@ +APPNAME = autoseed + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) fromlist=$(OUTPUT)/list.lis \ + seeddef=$(INPUT)/gridPixels.pvl \ + overlaplist=$(INPUT)/listoverlaps.def \ + to=$(OUTPUT)/new.pixels.net.pvl \ + networkid=NewNetwork pointid="new????" description=NewNetwork \ + > /dev/null; + $(APPNAME) fromlist=$(OUTPUT)/list.lis \ + seeddef=$(INPUT)/gridEmission.pvl \ + overlaplist=$(INPUT)/listoverlaps.def \ + to=$(OUTPUT)/new.emission.net.pvl \ + networkid=NewNetwork pointid="new????" description=NewNetwork \ + > /dev/null; + $(APPNAME) fromlist=$(OUTPUT)/list.lis \ + seeddef=$(INPUT)/gridIncidence.pvl \ + overlaplist=$(INPUT)/listoverlaps.def \ + to=$(OUTPUT)/new.incidence.net.pvl \ + networkid=NewNetwork pointid="new????" description=NewNetwork \ + > /dev/null; + $(APPNAME) fromlist=$(OUTPUT)/list.lis \ + seeddef=$(INPUT)/gridResolution.pvl \ + overlaplist=$(INPUT)/listoverlaps.def \ + to=$(OUTPUT)/new.resolution.net.pvl \ + networkid=NewNetwork pointid="new????" description=NewNetwork \ + > /dev/null; + $(APPNAME) fromlist=$(OUTPUT)/list.lis \ + seeddef=$(INPUT)/gridDN.pvl \ + overlaplist=$(INPUT)/listoverlaps.def \ + to=$(OUTPUT)/new.dn.net.pvl \ + networkid=NewNetwork pointid="new????" description=NewNetwork \ + > /dev/null; + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/bandnorm/Makefile b/isis/src/base/apps/bandnorm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/bandnorm/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/bandnorm/bandnorm.cpp b/isis/src/base/apps/bandnorm/bandnorm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b8395ff83225a9d8c6ba328226a6e5408b4722d --- /dev/null +++ b/isis/src/base/apps/bandnorm/bandnorm.cpp @@ -0,0 +1,162 @@ +#include "Isis.h" + +// system include files go first +#include +#include +#include +#include +#include + +// Isis specific include files go next +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" +#include "Pvl.h" +#include "TextFile.h" +#include "Statistics.h" + +using namespace std; +using namespace Isis; + +static vector band; +static vector average; +static vector normalizer; + +// function prototypes +void getStats(Buffer &in); +void normalize(Buffer &in, Buffer &out); +void Tokenize( const string& str, + vector & tokens, + const string& delimiters = " " ); + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input cube + UserInterface &ui = Application::GetUserInterface(); + Cube *icube = p.SetInputCube("FROM"); + + // Now get the statistics for each band or the entire cube + string avg = ui.GetString("AVERAGE"); + p.StartProcess(getStats); + if (avg == "BAND") { + int b = 0; + Statistics stats; + for (int i=0; i<(int)average.size(); i++) { + if (b == band[i]) { + stats.AddData(&average[i],(unsigned int)1); + } + else { + normalizer.push_back(stats.Average()); + b++; + stats.Reset(); + } + } + normalizer.push_back(stats.Average()); + } + else if( avg == "PENCIL" ) { + TextFile pencil; + pencil.Open( ui.GetFilename("SPECTRUM") ); + if( pencil.LineCount()-1 < icube->Bands()) { + string msg = "The spectral pencil file [" + ui.GetAsString("SPECTRUM") + + "] does not contain enough data for all bands."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + string st; + int column=-1; + vector tokens; + pencil.GetLine( st ); //Takes care of title line + Tokenize( st, tokens, ", \"-+" ); + if( ui.GetAsString("METHOD") == "number" ) { + column = ui.GetInteger("NUMBER"); + } + else { + for( unsigned i=0; i tokens.size() ) { + string msg = "The column specified in file ["+ ui.GetFilename("SPECTRUM") + + "] was not found."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + // Add the correct column of data to normalizer + for( int i=0; iBands(); i++ ) { + tokens.clear(); + pencil.GetLine( st ); + Tokenize( st, tokens, ", \"" ); + normalizer.push_back( Isis::iString(tokens[column]).ToDouble() ); + } + } + else { // avg == "CUBE" + Statistics stats; + for (int i=0; i<(int)average.size(); i++) { + stats.AddData(&average[i],(unsigned int)1); + } + for (int b=0; bBands(); b++) { + normalizer.push_back(stats.Average()); + } + } + + // Setup the output file and apply the correction + p.SetOutputCube("TO"); + p.StartProcess(normalize); + + // Cleanup + p.EndProcess(); + normalizer.clear(); + band.clear(); +} + +//********************************************************** +// Get statistics on a band or entire cube +//********************************************************** +void getStats(Buffer &in) { + Statistics stats; + stats.AddData(in.DoubleBuffer(),in.size()); + average.push_back(stats.Average()); + band.push_back(in.Band()-1); +} + +// Apply coefficients +void normalize(Buffer &in, Buffer &out) { + int index = in.Band()-1; + double coeff = normalizer[index]; + + // Now loop and apply the coefficents + for (int i=0; i & tokens, + const string& delimiters ) +{ + //Skip delimiters at the beginning + string::size_type lastPos = str.find_first_not_of(delimiters, 0); + // Find first "non-delimiter". + string::size_type pos = str.find_first_of(delimiters, lastPos); + + while( string::npos != pos || string::npos != lastPos ) { + // Found a token, add it to the vector + tokens.push_back( str.substr( lastPos, pos - lastPos ) ); + // Skip delimiters + lastPos = str.find_first_not_of( delimiters, pos); + // Find next "non-delimiter" + pos = str.find_first_of(delimiters, lastPos); + } +} diff --git a/isis/src/base/apps/bandnorm/bandnorm.xml b/isis/src/base/apps/bandnorm/bandnorm.xml new file mode 100644 index 0000000000000000000000000000000000000000..a2d5839681548b7c1f9f458ff208dd787b14e354 --- /dev/null +++ b/isis/src/base/apps/bandnorm/bandnorm.xml @@ -0,0 +1,218 @@ + + + + + + Normalize bands in a cube + + + +

    + The program accomplishes the fairly straightforward task of taking an input + cube and outputting normalized values. +

    + Normalization may be done with respect to each band or the entire cube. + If the user were to normalize by band, the program would take a pass through + the data in order to determine the average of each band. Bandnorm will then + pass through each band again and normalize each one based on the average + of the given band. If normalizing by the entire cube, the first pass would compute + the average of the cube, and the second pass would normalize each band using + this average. Bandnorm can use a text file as the input for the average + value of each band. +

    + + + + + Original version + + + Added Spectral Pencil option. + + + Modified Spectral Pencil option to be more flexible with the structure of + its Spectral files, namely, allowing for more than one column, and + specifying which column to use durring normilization. + + + Removed references to CubeInfo + + + + + Math and Statistics + + + + + divfilter + + + + + + + + cube + input + + Input cube + + + This file will be the input cube that gets normalized. + + + *.cub + + + + + cube + output + + Output cube + + + Output file that will be created using average values from + the input cube to normalize. + + + + + + + string + BAND + Direction in which statistics and operations operate + + This is the the average to be used during normalization. If the user chooses + to use band averages, they intend to take in an entire band of data + and normalize based on the average of that band for each pixel in + that band. If they choose to use the average from the entire cube, + they intend to take in an entire cube of data and normalize each + pixel in each band based on the average of the entire cube. If they + choose pencil, they intend to use a file containing the averages of + each band to normalize each pixel in correlating band. This file is + best obtained using Qview's plot tool. + + + + + + + + + filename + input + Spectral Pencil + + The file with the spectrum data for each band to be normalized with. + It assumes this file was aquired using Qview's plot tool. The first + line of the spectrum file MUST be composed of titles, and the + following lines MUST be the data desired (in most cases the average) + of each band in sequential order, starting with the first band. Extra + lines are ignored. + + + *.txt *.lis + + + + string + BYNAME + The mothod used to determine desired column + + The method used to determine the correct data column of the spectrum + file wished to be used in creating the normalized cube. + + + + + + + + integer + 1 + Specifies column used by number + + Allows one to specify by column number within the given + spectrum file, the column data to be used to create the normalized + cube. + + + + string + Average + Specifies column used by name + + Allows one to specify by column name within the given + spectrum file, the column data to be used to create the normalized + cube. + + + + + + + diff --git a/isis/src/base/apps/bandnorm/tsts/Makefile b/isis/src/base/apps/bandnorm/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/bandnorm/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/bandnorm/tsts/default/Makefile b/isis/src/base/apps/bandnorm/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..37df99b1ab10ecf6f416b27d4187be143c07c1cb --- /dev/null +++ b/isis/src/base/apps/bandnorm/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = bandnorm + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/f348b26.cub \ + to=$(OUTPUT)/bandnormTruth.cub > /dev/null; diff --git a/isis/src/base/apps/bandnorm/tsts/pencil/Makefile b/isis/src/base/apps/bandnorm/tsts/pencil/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a2fe55328c93ec7748e59824d99a301aff2de6ad --- /dev/null +++ b/isis/src/base/apps/bandnorm/tsts/pencil/Makefile @@ -0,0 +1,22 @@ +APPNAME = bandnorm + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/peaks.cub \ + to=$(OUTPUT)/bandnormPeaksTruth.cub \ + AVERAGE=pencil SPECTRUM=$(INPUT)/peakspencil.txt \ + > /dev/null; + $(APPNAME) from=$(INPUT)/m0402852.cub \ + to=$(OUTPUT)/bandnormM040Truth.cub \ + AVERAGE=pencil SPECTRUM=$(INPUT)/m040285pencil.txt \ + > /dev/null; + $(APPNAME) from=$(INPUT)/I00831002RDRcropped.cub \ + to=$(OUTPUT)/bandnormI008Truth.cub \ + AVERAGE=pencil SPECTRUM=$(INPUT)/I00831002RDRpencil.txt \ + > /dev/null; + $(APPNAME) from=$(INPUT)/I00831002RDRcropped.cub \ + to=$(OUTPUT)/bandnormI008NumTruth.cub \ + AVERAGE=pencil SPECTRUM=$(INPUT)/I00831002RDRpencil.txt \ + METHOD=bynumber NUMBER=6 \ + > /dev/null; diff --git a/isis/src/base/apps/bandtrim/Makefile b/isis/src/base/apps/bandtrim/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/bandtrim/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/bandtrim/bandtrim.cpp b/isis/src/base/apps/bandtrim/bandtrim.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4043b8a62f220f95943be0b8a2be819314a11da3 --- /dev/null +++ b/isis/src/base/apps/bandtrim/bandtrim.cpp @@ -0,0 +1,35 @@ +#include "Isis.h" +#include "ProcessByBrick.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void BandTrim (Buffer &in, Buffer &out); + +void IsisMain() +{ + ProcessByBrick p; + Cube *icube = p.SetInputCube("FROM"); + p.SetBrickSize(1, 1, icube->Bands()); + p.SetOutputCube ("TO"); + p.StartProcess(BandTrim); + p.EndProcess(); +} + +// Trim spectral pixels if anyone of them is null +void BandTrim (Buffer &in, Buffer &out){ + // Copy input to output and check to see if we should null + bool nullPixels = false; + for (int i=0; i + + + + Propagates a NULL in any band to all other bands + + + + This program searches for NULL pixels in all bands of a cube. + When a NULL pixel is found the corresponding pixel is set to NULL in all + other bands. + + + + Trim and Mask + + + + + trim + mask + + + + + + Original version + + + Finished the program + + + Fixed documentation and added test + + + Removed references to CubeInfo + + + + + + + cube + input + + Input file to be trimmed + + + The cube containing the input data to be trimmed. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the trimmed data. + + + *.cub + + + + + + diff --git a/isis/src/base/apps/bandtrim/tsts/Makefile b/isis/src/base/apps/bandtrim/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/bandtrim/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/bandtrim/tsts/default/Makefile b/isis/src/base/apps/bandtrim/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4360b7671b42fb0e561ca75731a7979fe4d3a95e --- /dev/null +++ b/isis/src/base/apps/bandtrim/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = bandtrim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/input.cub TO=$(OUTPUT)/truth.cub > /dev/null; diff --git a/isis/src/base/apps/bandtrim/tsts/oneband/Makefile b/isis/src/base/apps/bandtrim/tsts/oneband/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4360b7671b42fb0e561ca75731a7979fe4d3a95e --- /dev/null +++ b/isis/src/base/apps/bandtrim/tsts/oneband/Makefile @@ -0,0 +1,6 @@ +APPNAME = bandtrim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/input.cub TO=$(OUTPUT)/truth.cub > /dev/null; diff --git a/isis/src/base/apps/butterworth/Makefile b/isis/src/base/apps/butterworth/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/butterworth/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/butterworth/butterworth.cpp b/isis/src/base/apps/butterworth/butterworth.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f1c470e238eff803f147721322038374dcd81082 --- /dev/null +++ b/isis/src/base/apps/butterworth/butterworth.cpp @@ -0,0 +1,129 @@ +#include "Isis.h" + +#include +#include + +#include "ProcessByLine.h" +#include "LineManager.h" + +using namespace std; +using namespace Isis; + +void lowpass (Buffer &in, Buffer &out); +void highpass (Buffer &in, Buffer &out); +void bandpass (Buffer &in, Buffer &out); +void bandstop (Buffer &in, Buffer &out); +double radius (int x1, int y1, int x2, int y2); + +int x, y, g; +double d, dw; + +void IsisMain() +{ + ProcessByLine p; + + UserInterface &ui = Application::GetUserInterface(); + + // Initialize the input and output cubes + Isis::Cube *icube = p.SetInputCube ("FROM"); + + // get the center pixels coordinates + x = (icube->Samples()+1)/2; + y = (icube->Lines()+1)/2; + + p.SetOutputCube ("TO"); + + // Get the input values + d = ui.GetDouble ("CUTOFF"); + dw = ui.GetDouble("BANDWIDTH"); + g = ui.GetInteger ("ORDER"); + + // checks the type and runs the appropriate filter + if (ui.GetString("TYPE") == "LOWPASS") { + p.StartProcess(lowpass); + } + else if (ui.GetString("TYPE") == "HIGHPASS") { + p.StartProcess(highpass); + } + else if (ui.GetString("TYPE") == "BANDPASS") { + p.StartProcess(bandpass); + } + else if (ui.GetString("TYPE") == "BANDSTOP") { + p.StartProcess(bandstop); + } + else { + string msg = "Unknow value for TYPE [" + + ui.GetString("TYPE") + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + p.EndProcess(); +} + +// Applies a lowpass filter to an image in the frequency domain. +void lowpass (Buffer &in, Buffer &out) +{ + double dist = 0.0; + double B = 0.0; + + for (int i=0; i + + Apply Butterworth filter for cube in fft frequency domain + + Applies a Butterworth filter to a cube. This filter is used + on images in the frequency domain. Use the fft app to transform an + image from a spacial to frequency domain and use the ifft app to transform from frequency to spacial. + + + Fourier Domain + + + + Original version + + + Documentation fixes + + + Removed references to CubeInfo + + + Removed outdated examples from the documentation. + + + + + + + cube + Input file + Cube to filter + input + *.cub + + + + cube + Output cube + The resultant cube + output + *.cub + + + + + + double + Cutoff frequency + The specified cutoff frequency. + 0.0 + 0.0 + + + + integer + Order + The order of the Butterworth filter. + 1 + 0 + + + + double + The width of the cutoff band. + This parameter is used when the type specified is "bandpass" or "bandstop". + 1.0 + 0.0 + + + + + + string + + LOWPASS + + Type of filter + + This is the type of filter to be performed on the input. + + + + + + + + + + + diff --git a/isis/src/base/apps/butterworth/tsts/Makefile b/isis/src/base/apps/butterworth/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/butterworth/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/butterworth/tsts/bandpass/Makefile b/isis/src/base/apps/butterworth/tsts/bandpass/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..216218ca9e713d4bf05c9f1dc295363121c1e6f3 --- /dev/null +++ b/isis/src/base/apps/butterworth/tsts/bandpass/Makefile @@ -0,0 +1,10 @@ +APPNAME = butterworth + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/testImage.cub \ + to=$(OUTPUT)/butterworthTruth3.cub \ + cutoff=50.0 \ + bandwidth=10.0 \ + type=bandpass > /dev/null; diff --git a/isis/src/base/apps/butterworth/tsts/bandstop/Makefile b/isis/src/base/apps/butterworth/tsts/bandstop/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..88c07cdffbf26c7cc02329c4e6a43d041f66dc6b --- /dev/null +++ b/isis/src/base/apps/butterworth/tsts/bandstop/Makefile @@ -0,0 +1,10 @@ +APPNAME = butterworth + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/testImage.cub \ + to=$(OUTPUT)/butterworthTruth4.cub \ + cutoff=50.0 \ + bandwidth=10.0 \ + type=bandstop > /dev/null; diff --git a/isis/src/base/apps/butterworth/tsts/highpass/Makefile b/isis/src/base/apps/butterworth/tsts/highpass/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..45813ad7495ec7b51db45af4697637f3f50a6bef --- /dev/null +++ b/isis/src/base/apps/butterworth/tsts/highpass/Makefile @@ -0,0 +1,12 @@ +APPNAME = butterworth + +# 9.6e-07 +butterworthTruth2.cub.TOLERANCE = .00000096 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/testImage.cub \ + to=$(OUTPUT)/butterworthTruth2.cub \ + cutoff=50.0 \ + type=highpass > /dev/null; diff --git a/isis/src/base/apps/butterworth/tsts/lowpass/Makefile b/isis/src/base/apps/butterworth/tsts/lowpass/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..91b60aeb1f644080eabe48eb534324e52e740ef4 --- /dev/null +++ b/isis/src/base/apps/butterworth/tsts/lowpass/Makefile @@ -0,0 +1,9 @@ +APPNAME = butterworth + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/testImage.cub \ + to=$(OUTPUT)/butterworthTruth1.cub \ + cutoff=50.0 \ + type=lowpass > /dev/null; diff --git a/isis/src/base/apps/cam2cam/Makefile b/isis/src/base/apps/cam2cam/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cam2cam/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cam2cam/cam2cam.cpp b/isis/src/base/apps/cam2cam/cam2cam.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aca8a6d9ebc0b8b22661fdf1e1fc028a03114a84 --- /dev/null +++ b/isis/src/base/apps/cam2cam/cam2cam.cpp @@ -0,0 +1,145 @@ +#include "Isis.h" +#include "CameraFactory.h" +#include "Camera.h" +#include "ProcessRubberSheet.h" +#include "iException.h" +#include "cam2cam.h" + +using namespace std; +using namespace Isis; + +// Global variables +void BandChange (const int band); +Camera *incam; + +void IsisMain() { + // Open the match cube and get the camera model on it + ProcessRubberSheet m; + Cube *mcube = m.SetInputCube("MATCH"); + Cube *ocube = m.SetOutputCube ("TO"); + + // Set up the default reference band to the middle of the cube + // If we have even bands it will be close to the middle + int referenceBand = ocube->Bands(); + referenceBand += (referenceBand % 2); + referenceBand /= 2; + + // See if the user wants to override the reference band + UserInterface &ui = Application::GetUserInterface(); + if (ui.WasEntered("REFBAND")) { + referenceBand = ui.GetInteger("REFBAND"); + } + + // Using the Camera method out of the object opack will not work, because the + // filename required by the Camera is not passed by the process class in this + // case. Use the CameraFactory to create the Camera instead to get around this + // problem. + Camera *outcam = CameraFactory::Create(*(mcube->Label())); + + // Set the reference band we want to match + PvlGroup instgrp = mcube->GetGroup("Instrument"); + if (!outcam->IsBandIndependent()) { + PvlKeyword rBand("ReferenceBand",referenceBand); + rBand.AddComment("# All bands are aligned to reference band"); + instgrp += rBand; + mcube->PutGroup(instgrp); + delete outcam; + outcam = NULL; + } + + // Only recreate the output camera if it was band dependent + if (outcam == NULL) outcam = CameraFactory::Create(*(mcube->Label())); + + // We might need the instrument group later, so get a copy before clearing the input + // cubes. + m.ClearInputCubes(); + + Cube *icube = m.SetInputCube ("FROM"); + incam = icube->Camera(); + + // Set up the transform object which will simply map + // output line/samps -> output lat/lons -> input line/samps + Transform *transform = new cam2cam (icube->Samples(), + icube->Lines(), + incam, + ocube->Samples(), + ocube->Lines(), + outcam); + + + // Add the reference band to the output if necessary + ocube->PutGroup(instgrp); + + // Set up the interpolator + Interpolator *interp = NULL; + if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { + interp = new Interpolator(Interpolator::NearestNeighborType); + } + else if (ui.GetString("INTERP") == "BILINEAR") { + interp = new Interpolator(Interpolator::BiLinearType); + } + else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { + interp = new Interpolator(Interpolator::CubicConvolutionType); + } + + // See if we need to deal with band dependent camera models + if (!incam->IsBandIndependent()) { + m.BandChange(BandChange); + } + + // Warp the cube + m.StartProcess(*transform, *interp); + m.EndProcess(); + + // Cleanup + delete transform; + delete interp; +} + +// Transform object constructor +cam2cam::cam2cam (const int inputSamples, const int inputLines, + Camera *incam, const int outputSamples, + const int outputLines, Camera *outcam) { + p_inputSamples = inputSamples; + p_inputLines = inputLines; + p_incam = incam; + + p_outputSamples = outputSamples; + p_outputLines = outputLines; + p_outcam = outcam; +} + +// Transform method mapping output line/samps to lat/lons to input line/samps +bool cam2cam::Xform (double &inSample, double &inLine, + const double outSample, const double outLine) { + // See if the output image coordinate converts to lat/lon + if (!p_outcam->SetImage(outSample,outLine)) return false; + + // Get the universal lat/lon and see if it can be converted to input line/samp + double lat = p_outcam->UniversalLatitude(); + double lon = p_outcam->UniversalLongitude(); + if (!p_incam->SetUniversalGround(lat,lon)) return false; + + // Make sure the point is inside the input image + if (p_incam->Sample() < 0.5) return false; + if (p_incam->Line() < 0.5) return false; + if (p_incam->Sample() > p_inputSamples + 0.5) return false; + if (p_incam->Line() > p_inputLines + 0.5) return false; + + // Everything is good + inSample = p_incam->Sample(); + inLine = p_incam->Line(); + return true; +} + +int cam2cam::OutputSamples () const { + return p_outputSamples; +} + +int cam2cam::OutputLines () const { + return p_outputLines; +} + +void BandChange (const int band) { + incam->SetBand(band); +} diff --git a/isis/src/base/apps/cam2cam/cam2cam.h b/isis/src/base/apps/cam2cam/cam2cam.h new file mode 100644 index 0000000000000000000000000000000000000000..bd78ccbb4385629101a982d1d44060e8b076872b --- /dev/null +++ b/isis/src/base/apps/cam2cam/cam2cam.h @@ -0,0 +1,30 @@ +#ifndef cam2cam_h +#define cam2cam_h + +#include "Transform.h" + +class cam2cam : public Isis::Transform { + private: + Isis::Camera *p_incam; + Isis::Camera *p_outcam; + int p_inputSamples; + int p_inputLines; + int p_outputSamples; + int p_outputLines; + + public: + // constructor + cam2cam (const int inputSamples, const int inputLines, Isis::Camera *incam, + const int outputSamples, const int outputLines, Isis::Camera *outcam); + + // destructor + ~cam2cam () {}; + + // Implementations for parent's pure virtual members + bool Xform (double &inSample, double &inLine, + const double outSample, const double outLine); + int OutputSamples () const; + int OutputLines () const; +}; + +#endif diff --git a/isis/src/base/apps/cam2cam/cam2cam.xml b/isis/src/base/apps/cam2cam/cam2cam.xml new file mode 100644 index 0000000000000000000000000000000000000000..932fbcc31541d675bffaaa586c5cacac78f65d28 --- /dev/null +++ b/isis/src/base/apps/cam2cam/cam2cam.xml @@ -0,0 +1,154 @@ + + + + + Convert camera image to a different camera image + + + + This program will convert a input camera cube to a different camera geometry. For example, given overlapping MGS MOC and Odyssey Themis cubes, + this program can convert the MOC image to have the same geometric camera characteristics as the Themis cube (or vice versa). Another use is to align + bands in a camera cube which has independent bands. For example, a raw Themis cube (after thm2isis) will not have aligned pixels. This program can + be used to align the pixels without going to a map projection. To prevent pixels from falling off the edge of the cube you can run pad on the cube prior to + this program. + + + + Cameras + + + + + Original version + + + Converted to Isis 3.0 + + + Added an appTest. + + + Fixed appTest to reflect changes in all camera models + + + Corrected setting of output file labels so that the Spice comes from the match cube and not the input cube + + + Fixed typo in documentation + + + Fixed an access on an invalid pointer that caused segmentation faults on + cubes in which the camera is band-dependant. + + + Fixed problems with reference bands on band-dependent instruments + + + Removed references to CubeInfo + + + + + lev1tolev1 + + + + + + cube + input + + Input camera cube + + + The camera cube which will be modified + + + *.cub + + + + + cube + input + + Instrument cube to match + + + This is the camera cube which will be matched. It must be only one band so use the input attributes to select the band to match. For example, + themis.cub+5. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube which will have the same camera geometry and image size as the match cube. + + + *.cub + + + + + + + integer + middle + Reference Band + + This is the reference band to be used in the MATCH cube. + That is, all bands in the FROM cube will be matched to + this band. The default is to use the middle band; however, + the user can enter any band number which is valid for the + instrument, regardless of whether the band is in the cube + or not. + This only applies to band dependent camera models such as + Themis. + + 1 + + + + string + + CUBICCONVOLUTION + + Type of interpolation + + This is the type of interpolation to be performed on the input. + + + + + + + + + + diff --git a/isis/src/base/apps/cam2cam/tsts/Makefile b/isis/src/base/apps/cam2cam/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cam2cam/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cam2cam/tsts/case01/Makefile b/isis/src/base/apps/cam2cam/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3ff79b590ef62beed09706cf6070cdac3062469f --- /dev/null +++ b/isis/src/base/apps/cam2cam/tsts/case01/Makefile @@ -0,0 +1,10 @@ +APPNAME = cam2cam + +cam2cam1.cub.TOLERANCE = .00000001 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.cub \ + match=$(INPUT)/ab102401.cub \ + to=$(OUTPUT)/cam2cam1.cub INTERP=BILINEAR > /dev/null; diff --git a/isis/src/base/apps/cam2cam/tsts/case02/Makefile b/isis/src/base/apps/cam2cam/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..202289d2da3fe8a942155422bee8a064c88229f6 --- /dev/null +++ b/isis/src/base/apps/cam2cam/tsts/case02/Makefile @@ -0,0 +1,11 @@ +APPNAME = cam2cam + +# 7.5e-09 +cam2cam2.cub.TOLERANCE = .0000000075 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.cub \ + match=$(INPUT)/ab102402.cub \ + to=$(OUTPUT)/cam2cam2.cub INTERP=BILINEAR > /dev/null; diff --git a/isis/src/base/apps/cam2map/Makefile b/isis/src/base/apps/cam2map/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cam2map/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cam2map/cam2map.cpp b/isis/src/base/apps/cam2map/cam2map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb213054f89da847c392d5b3918ad9f4dcc09c8d --- /dev/null +++ b/isis/src/base/apps/cam2map/cam2map.cpp @@ -0,0 +1,504 @@ +#define GUIHELPERS + +#include "Isis.h" +#include "Camera.h" +#include "ProjectionFactory.h" +#include "ProcessRubberSheet.h" +#include "iException.h" +#include "cam2map.h" + +using namespace std; +using namespace Isis; + +void PrintMap (); +void LoadMapRes (); +void LoadCameraRes (); +void LoadMapRange (); +void LoadCameraRange (); + +map GuiHelpers(){ + map helper; + helper ["PrintMap"] = (void*) PrintMap; + helper ["LoadMapRes"] = (void*) LoadMapRes; + helper ["LoadCameraRes"] = (void*) LoadCameraRes; + helper ["LoadMapRange"] = (void*) LoadMapRange; + helper ["LoadCameraRange"] = (void*) LoadCameraRange; + return helper; +} + + +// Global variables +void BandChange (const int band); +Cube *icube; +Camera *incam; + +void IsisMain() { + // We will be warping a cube + ProcessRubberSheet p; + + // Get the map projection file provided by the user + UserInterface &ui = Application::GetUserInterface(); + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + // Open the input cube and get the camera + icube = p.SetInputCube ("FROM"); + incam = icube->Camera(); + + // Make sure it is not the sky + if (incam->IsSky()) { + string msg = "The image [" + ui.GetFilename("FROM") + + "] is targeting the sky, use skymap instead."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Get the mapping grop + Pvl camMap; + incam->BasicMapping(camMap); + PvlGroup &camGrp = camMap.FindGroup("Mapping"); + + + // Make the target info match the user mapfile + double minlat,maxlat,minlon,maxlon; + incam->GroundRange(minlat,maxlat,minlon,maxlon,userMap); + camGrp.AddKeyword(PvlKeyword("MinimumLatitude",minlat),Pvl::Replace); + camGrp.AddKeyword(PvlKeyword("MaximumLatitude",maxlat),Pvl::Replace); + camGrp.AddKeyword(PvlKeyword("MinimumLongitude",minlon),Pvl::Replace); + camGrp.AddKeyword(PvlKeyword("MaximumLongitude",maxlon),Pvl::Replace); + + + // We want to delete the keywords we just added if the user wants the range + // out of the mapfile, otherwise they will replace any keywords not in the + // mapfile + if (ui.GetString("DEFAULTRANGE") == "MAP" || ui.GetBoolean("MATCHMAP")) { + camGrp.DeleteKeyword("MinimumLatitude"); + camGrp.DeleteKeyword("MaximumLatitude"); + camGrp.DeleteKeyword("MinimumLongitude"); + camGrp.DeleteKeyword("MaximumLongitude"); + } + // Otherwise, remove the keywords from the map file so the camera keywords + // will be propogated correctly + else { + while (userGrp.HasKeyword("MinimumLatitude")) { + userGrp.DeleteKeyword("MinimumLatitude"); + } + while (userGrp.HasKeyword("MinimumLongitude")) { + userGrp.DeleteKeyword("MinimumLongitude"); + } + while (userGrp.HasKeyword("MaximumLatitude")) { + userGrp.DeleteKeyword("MaximumLatitude"); + } + while (userGrp.HasKeyword("MaximumLongitude")) { + userGrp.DeleteKeyword("MaximumLongitude"); + } + } + + // If the user decided to enter a ground range then override + if (ui.WasEntered("MINLON") && !ui.GetBoolean("MATCHMAP")) { + userGrp.AddKeyword(PvlKeyword("MinimumLongitude", + ui.GetDouble("MINLON")),Pvl::Replace); + } + + if (ui.WasEntered("MAXLON") && !ui.GetBoolean("MATCHMAP")) { + userGrp.AddKeyword(PvlKeyword("MaximumLongitude", + ui.GetDouble("MAXLON")),Pvl::Replace); + } + + if (ui.WasEntered("MINLAT") && !ui.GetBoolean("MATCHMAP")) { + userGrp.AddKeyword(PvlKeyword("MinimumLatitude", + ui.GetDouble("MINLAT")),Pvl::Replace); + } + + if (ui.WasEntered("MAXLAT") && !ui.GetBoolean("MATCHMAP")) { + userGrp.AddKeyword(PvlKeyword("MaximumLatitude", + ui.GetDouble("MAXLAT")),Pvl::Replace); + } + + // If they want the res. from the mapfile, delete it from the camera so + // nothing gets overriden + if (ui.GetString("PIXRES") == "MAP" || ui.GetBoolean("MATCHMAP")) { + camGrp.DeleteKeyword("PixelResolution"); + } + // Otherwise, delete any resolution keywords from the mapfile so the camera + // info is propogated over + else if (ui.GetString("PIXRES") == "CAMERA") { + if (userGrp.HasKeyword("Scale")) { + userGrp.DeleteKeyword("Scale"); + } + if (userGrp.HasKeyword("PixelResolution")) { + userGrp.DeleteKeyword("PixelResolution"); + } + } + + // Copy any defaults that are not in the user map from the camera map file + for (int k=0; kIntersectsLongitudeDomain(userMap)) { + if (ui.GetString("LONSEAM") == "AUTO") { + if ((int) userGrp["LongitudeDomain"] == 360) { + userGrp.AddKeyword(PvlKeyword("LongitudeDomain",180), + Pvl::Replace); + if (incam->IntersectsLongitudeDomain(userMap)) { + // Its looks like a global image so switch back to the + // users preference + userGrp.AddKeyword(PvlKeyword("LongitudeDomain",360), + Pvl::Replace); + } + } + else { + userGrp.AddKeyword(PvlKeyword("LongitudeDomain",360), + Pvl::Replace); + if (incam->IntersectsLongitudeDomain(userMap)) { + // Its looks like a global image so switch back to the + // users preference + userGrp.AddKeyword(PvlKeyword("LongitudeDomain",180), + Pvl::Replace); + } + } + // Make the target info match the new longitude domain + double minlat,maxlat,minlon,maxlon; + incam->GroundRange(minlat,maxlat,minlon,maxlon,userMap); + if( !ui.WasEntered("MINLAT") ) { + userGrp.AddKeyword(PvlKeyword("MinimumLatitude",minlat),Pvl::Replace); + } + if( !ui.WasEntered("MAXLAT") ) { + userGrp.AddKeyword(PvlKeyword("MaximumLatitude",maxlat),Pvl::Replace); + } + if( !ui.WasEntered("MINLON") ) { + userGrp.AddKeyword(PvlKeyword("MinimumLongitude",minlon),Pvl::Replace); + } + if( !ui.WasEntered("MAXLON") ) { + userGrp.AddKeyword(PvlKeyword("MaximumLongitude",maxlon),Pvl::Replace); + } + } + + else if (ui.GetString("LONSEAM") == "ERROR") { + string msg = "The image [" + ui.GetFilename("FROM") + "] crosses the " + + "longitude seam"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + } + + // Use the updated label to create the output projection + int samples,lines; + Projection *outmap; + bool trim; + + // Determine the image size + if (ui.GetString("DEFAULTRANGE") == "MINIMIZE" && !ui.GetBoolean("MATCHMAP")) { + outmap = ProjectionFactory::CreateForCube(userMap,samples,lines,*incam); + trim = false; + } + else if (ui.GetString("DEFAULTRANGE") == "CAMERA" && !ui.GetBoolean("MATCHMAP")) { + outmap = ProjectionFactory::CreateForCube(userMap,samples,lines,false); + trim = ui.GetBoolean("TRIM"); + } + else { // DEFAULTRANGE = MAP + outmap = ProjectionFactory::CreateForCube(userMap,samples,lines, + ui.GetBoolean("MATCHMAP")); + trim = ui.GetBoolean("TRIM"); + } + + int tileStart, tileEnd; + incam->GetGeometricTilingHint(tileStart, tileEnd); + p.SetTiling(tileStart, tileEnd); + + // Output the mapping group used to the Gui session log + Application::GuiLog(userMap); + + // Set up the transform object which will simply map + // output line/samps -> output lat/lons -> input line/samps + Transform *transform = new cam2map (icube->Samples(), + icube->Lines(), + incam, + samples, + lines, + outmap, + trim); + + // Allocate the output cube and add the mapping labels + Cube *ocube = p.SetOutputCube ("TO", transform->OutputSamples(), + transform->OutputLines(), + icube->Bands()); + ocube->PutGroup(userGrp); + + // Set up the interpolator + Interpolator *interp = NULL; + if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { + interp = new Interpolator(Interpolator::NearestNeighborType); + } + else if (ui.GetString("INTERP") == "BILINEAR") { + interp = new Interpolator(Interpolator::BiLinearType); + } + else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { + interp = new Interpolator(Interpolator::CubicConvolutionType); + } + + // See if we need to deal with band dependent camera models + if (!incam->IsBandIndependent()) { + p.BandChange(BandChange); + } + + // See if center of input image projects. If it does, force tile + // containing this center to be processed in ProcessRubberSheet. + double centerSamp = icube->Samples () / 2.; + double centerLine = icube->Lines () / 2.; + if (incam->SetImage(centerSamp,centerLine)) { + if (outmap->SetUniversalGround(incam->UniversalLatitude(), + incam->UniversalLongitude())) { + p.ForceTile (outmap->WorldX(),outmap->WorldY ()); + } + } + // Create an alpha cube group for the output cube + if (!ocube->HasGroup("AlphaCube")) { + PvlGroup alpha("AlphaCube"); + alpha += PvlKeyword("AlphaSamples",icube->Samples()); + alpha += PvlKeyword("AlphaLines",icube->Lines()); + alpha += PvlKeyword("AlphaStartingSample",0.5); + alpha += PvlKeyword("AlphaStartingLine",0.5); + alpha += PvlKeyword("AlphaEndingSample",icube->Samples()+0.5); + alpha += PvlKeyword("AlphaEndingLine",icube->Lines()+0.5); + alpha += PvlKeyword("BetaSamples",icube->Samples()); + alpha += PvlKeyword("BetaLines",icube->Lines()); + ocube->PutGroup(alpha); + } + + // Warp the cube + p.StartProcess(*transform, *interp); + p.EndProcess(); + + // add mapping to print.prt + PvlGroup mapping = outmap->Mapping(); + Application::Log(mapping); + + // Cleanup + delete outmap; + delete transform; + delete interp; +} + +// Transform object constructor +cam2map::cam2map (const int inputSamples, const int inputLines, + Camera *incam, const int outputSamples, + const int outputLines, Projection *outmap, + bool trim) { + p_inputSamples = inputSamples; + p_inputLines = inputLines; + p_incam = incam; + + p_outputSamples = outputSamples; + p_outputLines = outputLines; + p_outmap = outmap; + + p_trim = trim; +} + +// Transform method mapping output line/samps to lat/lons to input line/samps +bool cam2map::Xform (double &inSample, double &inLine, + const double outSample, const double outLine) { + // See if the output image coordinate converts to lat/lon + if (!p_outmap->SetWorld(outSample,outLine)) return false; + + // See if we should trim + if ((p_trim) && (p_outmap->HasGroundRange())) { + if (p_outmap->Latitude() < p_outmap->MinimumLatitude()) return false; + if (p_outmap->Latitude() > p_outmap->MaximumLatitude()) return false; + if (p_outmap->Longitude() < p_outmap->MinimumLongitude()) return false; + if (p_outmap->Longitude() > p_outmap->MaximumLongitude()) return false; + } + + // Get the universal lat/lon and see if it can be converted to input line/samp + double lat = p_outmap->UniversalLatitude(); + double lon = p_outmap->UniversalLongitude(); + + if (!p_incam->SetUniversalGround(lat,lon)) return false; + + // Make sure the point is inside the input image + if (p_incam->Sample() < 0.5) return false; + if (p_incam->Line() < 0.5) return false; + if (p_incam->Sample() > p_inputSamples + 0.5) return false; + if (p_incam->Line() > p_inputLines + 0.5) return false; + + // Everything is good + inSample = p_incam->Sample(); + inLine = p_incam->Line(); + + return true; +} + +int cam2map::OutputSamples () const { + return p_outputSamples; +} + +int cam2map::OutputLines () const { + return p_outputLines; +} + +void BandChange (const int band) { + incam->SetBand(band); +} + +// Helper function to print out mapfile to session log +void PrintMap() { + UserInterface &ui = Application::GetUserInterface(); + + // Get mapping group from map file + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + //Write map file out to the log + Isis::Application::GuiLog(userGrp); +} + +// Helper function to get mapping resolution. +void LoadMapRes () { + UserInterface &ui = Application::GetUserInterface(); + + // Get mapping group from map file + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + // Set resolution + if (userGrp.HasKeyword("Scale")) { + ui.Clear("RESOLUTION"); + ui.PutDouble("RESOLUTION",userGrp["Scale"]); + ui.Clear("PIXRES"); + ui.PutAsString("PIXRES","PPD"); + } + else if (userGrp.HasKeyword("PixelResolution")) { + ui.Clear("RESOLUTION"); + ui.PutDouble("RESOLUTION",userGrp["PixelResolution"]); + ui.Clear("PIXRES"); + ui.PutAsString("PIXRES","MPP"); + } + else { + string msg = "No resolution value found in [" + ui.GetFilename("MAP") + "]"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } +} + +//Helper function to get camera resolution. +void LoadCameraRes () { + UserInterface &ui = Application::GetUserInterface(); + string file = ui.GetFilename("FROM"); + + // Open the input cube, get the camera object, and the cam map projection + Cube c; + c.Open(file); + Camera *cam = c.Camera(); + Pvl camMap; + cam->BasicMapping(camMap); + PvlGroup &camGrp = camMap.FindGroup("Mapping"); + + ui.Clear("RESOLUTION"); + ui.PutDouble("RESOLUTION",camGrp["PixelResolution"]); + + ui.Clear("PIXRES"); + ui.PutAsString("PIXRES","MPP"); +} + +//Helper function to get ground range from map file. +void LoadMapRange() { + UserInterface &ui = Application::GetUserInterface(); + + // Get map file + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + // Set ground range keywords that are found in mapfile + int count = 0; + ui.Clear("MINLAT"); + ui.Clear("MAXLAT"); + ui.Clear("MINLON"); + ui.Clear("MAXLON"); + if (userGrp.HasKeyword("MinimumLatitude")) { + ui.PutDouble("MINLAT",userGrp["MinimumLatitude"]); + count++; + } + if (userGrp.HasKeyword("MaximumLatitude")) { + ui.PutDouble("MAXLAT",userGrp["MaximumLatitude"]); + count++; + } + if (userGrp.HasKeyword("MinimumLongitude")) { + ui.PutDouble("MINLON",userGrp["MinimumLongitude"]); + count++; + } + if (userGrp.HasKeyword("MaximumLongitude")) { + ui.PutDouble("MAXLON",userGrp["MaximumLongitude"]); + count++; + } + + // Set default ground range param to map + ui.Clear("DEFAULTRANGE"); + ui.PutAsString("DEFAULTRANGE","MAP"); + + if (count < 4) { + string msg = "One or more of the values for the ground range was not found"; + msg += " in [" + ui.GetFilename("MAP") + "]"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } +} + +//Helper function to load camera range. +void LoadCameraRange () { + UserInterface &ui = Application::GetUserInterface(); + string file = ui.GetFilename("FROM"); + + // Get the map projection file provided by the user + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + + // Open the input cube, get the camera object, and the cam map projection + Cube c; + c.Open(file); + Camera *cam = c.Camera(); + + // Make the target info match the user mapfile + double minlat,maxlat,minlon,maxlon; + cam->GroundRange(minlat,maxlat,minlon,maxlon,userMap); + + // Set ground range parameters in UI + ui.Clear("MINLAT"); + ui.PutDouble("MINLAT",minlat); + ui.Clear("MAXLAT"); + ui.PutDouble("MAXLAT",maxlat); + ui.Clear("MINLON"); + ui.PutDouble("MINLON",minlon); + ui.Clear("MAXLON"); + ui.PutDouble("MAXLON",maxlon); + + // Set default ground range param to camera + ui.Clear("DEFAULTRANGE"); + ui.PutAsString("DEFAULTRANGE","CAMERA"); +} + diff --git a/isis/src/base/apps/cam2map/cam2map.h b/isis/src/base/apps/cam2map/cam2map.h new file mode 100644 index 0000000000000000000000000000000000000000..ecd2bca6c962a8789c0011ba49a0aabc6df19a62 --- /dev/null +++ b/isis/src/base/apps/cam2map/cam2map.h @@ -0,0 +1,32 @@ +#ifndef cam2map_h +#define cam2map_h + +#include "Transform.h" + +class cam2map : public Isis::Transform { + private: + Isis::Camera *p_incam; + Isis::Projection *p_outmap; + int p_inputSamples; + int p_inputLines; + bool p_trim; + int p_outputSamples; + int p_outputLines; + + public: + // constructor + cam2map (const int inputSamples, const int inputLines, Isis::Camera *incam, + const int outputSamples, const int outputLines, Isis::Projection *outmap, + bool trim); + + // destructor + ~cam2map () {}; + + // Implementations for parent's pure virtual members + bool Xform (double &inSample, double &inLine, + const double outSample, const double outLine); + int OutputSamples () const; + int OutputLines () const; +}; + +#endif diff --git a/isis/src/base/apps/cam2map/cam2map.xml b/isis/src/base/apps/cam2map/cam2map.xml new file mode 100644 index 0000000000000000000000000000000000000000..f5dee127764c2daae12dae4701ee9abf609e906a --- /dev/null +++ b/isis/src/base/apps/cam2map/cam2map.xml @@ -0,0 +1,581 @@ + + + + + + Convert camera image to a map projection + + + + This program converts a cube in camera coordinates to a map projection. The input cube requires SPICE data and therefore + the program "spiceinit" should be run on it prior to "cam2map". The map projection is defined using a PVL file specificied through the + MAP parameter. The system default is to use the Sinusoidal projection ($ISIS3DATA/base/templates/maps/sinusoidal.map). + +

    If you need to generate your own map file you can use the "maptemplate" program or alternatively, hand create a file using your favorite editor. + The map file need only specify the ProjectionName as defaults will be computed for the remaining map file parameters. The following table + indicates how the defaults are established: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PARAMETERDEFAULT
    TargetNameRead from Instrument group in the input cube labels
    EquatorialRadius
    PolarRadius
    Read from SPICE pck file set during spiceinit. The pck file is defined in the Kernels group via the TargetAttitudeShape keyword
    LatitudeTypePlanetocentric
    LongitudeDirectionPositiveEast
    LongitudeDomainNormally, 360. However, if the cube crosses the longitude boundary the value will change to 180
    MinimumLatitude
    MaximumLatitude
    MinimumLongitude
    MaximumLongitude
    Computed from the input cube or read from the map file. However, any combination of the four values can then be overridden by the user
    PixelResolution
    Scale
    Computed from the input cube or read from the map file. The value can be overridden by the user.
    + +

    + If you only entered the input cube (FROM) and output cube (TO) and changed no other parameters the following is the default Mapping group: +

    +
    +  Group = Mapping
    +    TargetName             = Obtained from the Instrument group
    +    EquatorialRadius       = Obtained from TargetAttitudeShape kernel
    +    PolarRadius            = Obtained from TargetAttitudeShape kernel
    +
    +    LatitudeType           = Planetocentric
    +    LongitudeDirection     = PositiveEast
    +    LongitudeDomain        = 360 (Could be automatically adjusted to 180 by LONSEAM)
    +
    +    MinimumLatitude        = Computed from the input camera cube
    +    MaximumLatitude        = Computed from the input camera cube
    +    MinimumLongitude       = Computed from the input camera cube
    +    MaximumLongitude       = Computed from the input camera cube
    +
    +    ProjectionName         = Sinusoidal
    +    CenterLongitude        = Average of MinimumLongitude and MaximumLongitude
    +    PixelResolution        = Computed from the input camera cube
    +  EndGroup
    +    
    + + Note that an important concept here is the map file can come from an existing map projected cube. + Because the cube has PVL labels and contains the Mapping group, you can essentially force + the input camera cube to have the same mapping parameters and/or selectively use some of the components of the cube's mapping group. + +

    If you are attempting to construct a mosaic, it is important that the PixelResolution, EquatorialRadius, PolarRadius, LatitudeType, + LongitudeDirection, LongitudeDomain, ProjectionName, and projection specific parameters (e.g., CenterLongitude, CenterLatitude) are the same for all cubes. That is, you should + create one map file and use it as input for all the cubes in your mosaic. + However, the ground range (MinimumLatitude, MaximumLatitude, MinimumLongitude, MaximumLongitude) should not be entered or you will create projected images + with large amounts of NULL pixels. The following Mapping group could be used for mosaicking: +

    +
    + Group = Mapping
    +   ProjectionName         = Sinusoidal
    +   CenterLongitude        = 0
    +   PixelResolution        = 100 <meters>
    + EndGroup
    +   
    + +

    + Finally, depending on the projection, problems can occur with cubes that fall on the projection longitude seam. For example, if you are making a mosaic with LongitudeDomain = 360 and + your cube crosses 0/360 seam, this program would compute the default longitude range of the cube to MinimumLongitude = 0 and MaximumLongitude = 360. A very large output image + could be created depending on the pixel resolution. The LONSEAM parameter allows you to selectively handle this case. If you are making mosaics near the seam you will need to + understand and alter the default for this parameter. +

    +
    + + + Map Projection + Cameras + + + + + Original version + + + Converted to Isis 3.0 + + + Added to Camera category + + + Modified filename parameters to be cube parameters where necessary + + + Reworked defaults for user parameters + + + Modified resolution parameters to eliminate inclusion/exclusion + dependences. + + + Added AUTOLON parameter + + + Fixed bug with ground range user option + + + Added appTest + + + Updated appTest + + + Fixed appTest to reflect changes made in all camera models + + + Check to see if center of input image projects, if it does, force the tile containing center + to be processed in ProcessRubberSheet. + + + Reworked user interface + + + Reworked code for new user interface and added helper buttons + + + Depricated CubeProjection and ProjectionManager to ProjectionFactory + + + Moved Helper buttons and fixed error checking in helper methods + + + Modified call to ProjectionFactory CreateForCube method to include a value of false + for the newly added sizeMatch parameter + + + Test to see if target is sky and abort + + + Add minimize option for DEFAULTRANGE + + + Fixed typo and corrected XML + + + Fixed lonseam option to work with minimize option correctly + + + Fixed bug where the ground range was not pulled from the map file when + it was supposed to be (using DEFAULTRANGE = MAP). + + + Added the MATCHMAP option. + + + Removed references to CubeInfo + + + Changed MATCHMAP to default off + + + Changed MATCHMAP to have exclusions. If MATCHMAP is true, the PIXRES and DEFAULTRANGE + options can not be set. Changed the code to enforce MATCHMAP. + + + Added the ability to change ProcessRubberSheet's tiling sizes. Now the Camera will decide upon the + tiling sizes used in ProcessRubberSheet, in order to fix problems found with the push frame cameras which + have small framelet sizes (less than 64 pixels tall). This is a passive ability with respect to the user; + no options or differences should be noticable. + + + Fixed DEFAULTRANGE > CAMERA option to accept MINLAT, MAXLAT, MINLON, and MAXLON + as overriding values. + + + Fixed parameter names. + + + Mapping group parameters are now placed into the print file. + + + + + lev1tolev2 + plansinu + planorth + + + + + + cube + input + + Input cube to project + + + The specification of the input cube to be projected. The cube must + have been initialized using the "spiceinit" program. + + + *.cub + + + + + filename + input + + File containing mapping parameters + + $base/templates/maps + $base/templates/maps/sinusoidal.map + + A file containing the desired output mapping parameters in PVL form. This + file can be a simple hand produced label file. It can also be an existing cube label + which contains a Mapping group. You can produce map file using the "maptemplate" program. + + + + PrintMap + View MapFile + + This helper button will cat out the mapping group of the given mapfile to the session log + of the application + + $ISIS3DATA/base/icons/labels.png + + + + *.map *.cub + + + + + cube + output + + Newly mapped cube + + + This file will contain the map projected image. + + + *.cub + + + + + + + boolean + false + Match the map file + + This makes the number of lines, number of samples, resolution + and ground range of the output cube match the MAP file. + + + PIXRES + RESOLUTION + DEFAULTRANGE + MINLAT + MAXLAT + MINLON + MAXLON + + + + string + Defines how the pixel resolution in the output map file is obtained + CAMERA + + This parameter is used to specify how the pixel resolution is obtained for the output map + projected cube. + + + + LoadCameraRes + Load Camera Resolution + This helper button will load the default resolution from the camera + $ISIS3DATA/base/icons/exec.png + + + LoadMapRes + Load Map File Resolution + This helper button will load the default resolution from the map file + + + + + + + + + + + + + + + double + Pixel resolution + + Specifies the resolution in either meters per pixel or pixels per degree + + 0.0 + + + + + + string + Defines how the default ground range is determined + MINIMIZE + + This parameter is used to specify how the default latitude/longitude ground range for the output map projected image + is obtained. The ground range can be obtained from the camera or map file. Note the user can overide the default using the MINLAT, MAXLAT, MINLON, MAXLON parameters. + The purpose of the ground range is to define the coverage of the map projected image. Essentially, the ground range and + pixel resolution are used to compute the size (samples and line) of the output image. + + + + + LoadCameraRange + Load Camera Ground Range + This helper button will load the default ground range from the camera + $ISIS3DATA/base/icons/exec.png + + + LoadMapRange + Load Map File Ground Range + This helper button will load the default ground range from the map file + + + + + + + + + + + + + + double + Minimum Latitude + Use default range + + The minimum latitude of the ground range. If this is entered by the user it will override the default camera or map value. By default, + planetocentric latitudes are assumed unless the MAP file specifies otherwise. + + + -90.0 + 90.0 + + + + double + Maximum Latitude + Use default range + + The maximum latitude of the ground range. If this is entered by the user it will override the default camera or map value. + By default, planetocentric latitudes are assumed unless the MAP file specifies otherwise. + + -90.0 + 90.0 + MINLAT + + + + double + Minimum Longitude + Use default range + + The minimum longitude of the ground range. If this is entered by the user it will override the default camera or map value. + By default, positive east longitudes in the range of 0 to 360 are assumed unless the MAP file specifies otherwise. + + + + + double + Maximum Longitude + Use default range + + The maximum longitude of the ground range. If this is entered by the user it will override the default camera or map value. + By default, positive east longitudes in the range of 0 to 360 are assumed unless the MAP file specifies otherwise. + + MINLON + + + + boolean + FALSE + + Trim pixels outside ground range + + + If this option is selected, pixels outside the latitude/longtiude + range will be trimmed or set to null. + This is useful for certain projections whose lines of latitude and + longitude are not parallel to image lines and sample columns. + + + + + + + string + AUTO + + How should images at the longitude seam be handled + + + With this option you can turn on/off the automatic longitude domain switching that occurs + when a file crosses the boundary of the longitude domain (0-360 or -180 to 180). If the switching is turn off then + you have the choice of making the program continue or exit when the cube does cross the bounday. + + + + + + + + + + + + + + + + string + + CUBICCONVOLUTION + + Type of interpolation + + This is the type of interpolation to be performed on the input. + + + + + + + + + +
    diff --git a/isis/src/base/apps/cam2map/tsts/Makefile b/isis/src/base/apps/cam2map/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cam2map/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cam2map/tsts/mpp/Makefile b/isis/src/base/apps/cam2map/tsts/mpp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..87261e50b9f91b49fcb09b2669d8a8e04b652027 --- /dev/null +++ b/isis/src/base/apps/cam2map/tsts/mpp/Makefile @@ -0,0 +1,18 @@ +APPNAME = cam2map + +cam2mapTruth.cub.TOLERANCE = .000001 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/ab102401.cub \ + to=$(OUTPUT)/cam2mapTruth.cub \ + pixres=mpp \ + defaultrange=camera \ + resolution=1000 > /dev/null; + $(APPNAME) from= $(INPUT)/ab102401.cub \ + to=$(OUTPUT)/cam2mapCheckRange.cub \ + defaultrange=camera \ + MINLAT=15.0 MAXLAT=20.0 MINLON=225.0 MAXLON=230.0 \ + pixres=mpp \ + resolution=1000 > /dev/null; diff --git a/isis/src/base/apps/cam2map/tsts/rngmap/Makefile b/isis/src/base/apps/cam2map/tsts/rngmap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f356fb947b644541f9fafc02bf7e19fbda07d93c --- /dev/null +++ b/isis/src/base/apps/cam2map/tsts/rngmap/Makefile @@ -0,0 +1,13 @@ +APPNAME = cam2map + +cam2mapTruth.cub.TOLERANCE = .000001 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/ab102401.cub \ + to=$(OUTPUT)/cam2mapTruth.cub \ + map=$(INPUT)/map.map \ + pixres=mpp \ + defaultrange=camera \ + resolution=1000 > /dev/null; diff --git a/isis/src/base/apps/caminfo/CamTools.cpp b/isis/src/base/apps/caminfo/CamTools.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1805d9128e664f39d4011a8c3011e56d3b536b7d --- /dev/null +++ b/isis/src/base/apps/caminfo/CamTools.cpp @@ -0,0 +1,713 @@ +/* @file + * $Revision: 1.16 $ + * $Date: 2009/12/29 23:03:47 $ + * $Id: CamTools.cpp,v 1.16 2009/12/29 23:03:47 ehyer Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privdacy.html. + */ +#include +#include +#include +#include +#include +#if defined(DEBUG) +#include +#endif +#include +#include +#include + +#include "CamTools.h" +#include "CameraFactory.h" +#include "Pvl.h" +#include "SpecialPixel.h" +#include "iTime.h" +#include "iString.h" +#include "iException.h" +#include "Statistics.h" +#include "naif/SpiceUsr.h" +#include "ProjectionFactory.h" +#include "PolygonTools.h" + +#include "geos/geom/GeometryFactory.h" +#include "geos/geom/Geometry.h" +#include "geos/geom/Point.h" + +using namespace std; + +namespace Isis { + +/** + * @brief Round values to specified precision + * + * @param value Value to round + * @param precision Precision to round value to + * + * @return double Rounded value + */ +inline double SetRound(double value, const int precision) { + double scale = pow(10.0, precision); + value = round(value * scale) / scale; + return (value); +} + +/** + * @brief Helper function to convert values to doubles + * + * @param T Type of value to convert + * @param value Value to convert + * + * @return double Converted value + */ +template double ToDouble(const T &value) { + return (iString(value).Trim(" \r\t\n").ToDouble()); +} + +/** + * @brief Helper function to convert values to strings + * + * @param T Type of value to convert + * @param value Value to convert + * + * @return string Converted value + */ +template std::string ToString(const T &value) { + return (iString(value).Trim(" \r\t\n")); +} + + + +bool BandGeometry::isPointValid(const double &sample, const double &line, + const Camera *camera) const { + int nl(_nLines), ns(_nSamps); + if ( camera != 0 ) { + nl = camera->Lines(); + ns = camera->Samples(); + } + + if (line < 0.5) return (false); + if (line > (nl+0.5)) return (false); + if (sample < 0.5) return (false); + if (sample > (ns+0.5)) return (false); + return (true); +} + +bool BandGeometry::hasCenterGeometry() const { + BandPropertiesListConstIter b; + for ( b = _gBandList.begin() ; b != _gBandList.end() ; ++b ) { + if ( !IsSpecial(b->centerLatitude) ) return (true); + } + // No valid center exists + return (false); +} + +/** + * @brief Check geometry for presence of limb + * + * This method checks corner geometry coordinates for the presence of a planet + * limb. This is a simple check for validity of the latitude coordinate at each + * image corner. If any of them are invalid (Nulls), then it is deamed to have + * a limb in the image. + * + * Note that this check is only valid if the determination of the geometry has + * been performed. So care should be used as to when this check is made. + * + * + * @return bool True if one of the corner latitude coordinates is NULL. + */ +bool BandGeometry::hasLimb() const { + BandPropertiesListConstIter b; + for ( b = _gBandList.begin() ; b != _gBandList.end() ; ++b ) { + if ( IsSpecial(b->upperLeftLatitude) ) return (true); + if ( IsSpecial(b->upperRightLatitude) ) return (true); + if ( IsSpecial(b->lowerRightLatitude) ) return (true); + if ( IsSpecial(b->lowerLeftLatitude) ) return (true); + } + // All outer geometry points are defined + return (false); +} + + +void BandGeometry::destruct() { + // Ensure this can be applied for reentrant operations + _gBandList.clear(); + for_each(_polys.begin(), _polys.end(), DeleteObject()); + delete _combined; + _combined = 0; + _radius = 1.0; +} + +void BandGeometry::collect(Camera &camera, Cube &cube, bool doGeometry, + bool doPolygon) { + destruct(); + + _nLines = cube.Lines(); + _nSamps = cube.Samples(); + _nBands = cube.Bands(); + + // Compute average planetary radius in meters. This is used as a fallback + // to compute surface area if no geoemetry has a center intersect point. + double radii[3]; + camera.Radii(radii); + _radius = (radii[0] + radii[1] + radii[2]) / 3.0 * 1000.0; + + double cLine = _nLines; + double cSamp = _nSamps; + double centerLine = cLine / 2.0; + double centerSamp = cSamp / 2.0; + + // Check to determine if geometry is band independant + _isBandIndependent = camera.IsBandIndependent(); + _hasCenterGeom = false; + int nbands = (_isBandIndependent ? 1 : _nBands); + for ( int band = 0 ; band < nbands ; band++ ) { + // Compute band geometry properties + GProperties g; + g.lines = _nLines; + g.samples = _nSamps; + g.bands = _nBands; + g.band = band + 1; + camera.SetBand(band+1); + g.realBand = cube.PhysicalBand(band+1); + + + g.target = camera.Target(); + + iTime t1(camera.CacheStartTime()); + g.startTime = t1.UTC(); + iTime t2(camera.CacheEndTime()); + g.endTime = t2.UTC(); + + g.centerLine = centerLine; + g.centerSamp = centerSamp; + + // Now compute elements for the center pixel + if (camera.SetImage(centerSamp,centerLine)) { + _hasCenterGeom = true; + g.centerLatitude = camera.UniversalLatitude(); + g.centerLongitude = camera.UniversalLongitude(); + g.radius = camera.LocalRadius(); + + g.rightAscension = camera.RightAscension(); + g.declination = camera.Declination(); + + g.sampRes = camera.SampleResolution(); + g.lineRes = camera.LineResolution(); + + g.solarLongitude = camera.SolarLongitude(); + g.northAzimuth = camera.NorthAzimuth(); + g.offNader = camera.OffNadirAngle(); + g.subSolarAzimuth = camera.SunAzimuth(); + g.subSpacecraftAzimuth = camera.SpacecraftAzimuth(); + g.localSolartime = camera.LocalSolarTime(); + g.targetCenterDistance = camera.TargetCenterDistance(); + g.slantDistance = camera.SlantDistance(); + + camera.SubSolarPoint(g.subSolarLatitude,g.subSolarLongitude); + g.subSolarGroundAzimuth = camera.GroundAzimuth(g.centerLatitude, + g.centerLongitude, + g.subSolarLatitude, + g.subSolarLongitude); + camera.SubSpacecraftPoint(g.subSpacecraftLatitude,g.subSpacecraftLongitude); + g.subSpacecraftGroundAzimuth = camera.GroundAzimuth(g.centerLatitude, + g.centerLongitude, + g.subSpacecraftLatitude, + g.subSpacecraftLongitude); + + + // solve for the parallax and shadow stuff + g.phase = camera.PhaseAngle(); + g.emi = camera.EmissionAngle(); + g.inc = camera.IncidenceAngle(); + + // Need some radian values + if ( !IsSpecial(g.emi) && !IsSpecial(g.subSpacecraftAzimuth) ) { + double emi_r = DegToRad(g.emi); + g.parallaxx = RadToDeg(-tan(emi_r)*cos(DegToRad(g.subSpacecraftAzimuth))); + g.parallaxy = RadToDeg(tan(emi_r)*sin(DegToRad(g.subSpacecraftAzimuth))); } + + if ( !IsSpecial(g.inc) && !IsSpecial(g.subSolarAzimuth) ) { + double inc_r = DegToRad(g.inc); + g.shadowx = RadToDeg(-tan(inc_r)*cos(DegToRad(g.subSolarAzimuth))); + g.shadowy = RadToDeg(tan(inc_r)*sin(DegToRad(g.subSolarAzimuth))); + } + } + // OK...now get corner pixel geometry. NOTE this resets image + // pixel location from center!!! + if ( camera.SetImage(1.0, 1.0) ) { + g.upperLeftLongitude = camera.UniversalLongitude(); + g.upperLeftLatitude = camera.UniversalLatitude(); + } + + if ( camera.SetImage(1.0, cLine) ) { + g.lowerLeftLongitude = camera.UniversalLongitude(); + g.lowerLeftLatitude = camera.UniversalLatitude(); + } + + if ( camera.SetImage(cSamp, cLine) ) { + g.lowerRightLongitude = camera.UniversalLongitude(); + g.lowerRightLatitude = camera.UniversalLatitude(); + } + + if ( camera.SetImage(cSamp, 1.0) ) { + g.upperRightLongitude = camera.UniversalLongitude(); + g.upperRightLatitude = camera.UniversalLatitude(); + } + + double minRes = camera.LowestImageResolution(); + double maxRes = camera.HighestImageResolution(); + if ( !(IsSpecial(minRes) || IsSpecial(maxRes)) ) { + g.grRes = (minRes+maxRes)/2.0; + } + + Pvl camMap; + camera.BasicMapping(camMap); + _mapping = camMap; + + // Test for interesting intersections + if (camera.IntersectsLongitudeDomain(camMap)) g.hasLongitudeBoundary = true; + camera.SetBand(band+1); + if (camera.SetUniversalGround(90.0, 0.0)) { + if ( isPointValid(camera.Sample(), camera.Line(), &camera) ) { + g.hasNorthPole = true; + } + } + if (camera.SetUniversalGround(-90.0, 0.0)) { + if ( isPointValid(camera.Sample(), camera.Line(), &camera) ) { + g.hasSouthPole = true; + } + } + + if ( doPolygon ) { + // Now compute the the image polygon + ImagePolygon poly; + poly.Incidence(_maxIncidence); + poly.Emission(_maxEmission); + poly.EllipsoidLimb(true); // Allow disabling of shape model for limbs + poly.Create(cube,_pixinc,_pixinc,1,1,0,0,band+1); + geos::geom::MultiPolygon *multiP = poly.Polys(); + _polys.push_back(multiP->clone()); + if (_combined == 0) { + _combined = multiP->clone(); + } + else { + // Construct composite (union) polygon + geos::geom::Geometry *old(_combined); + _combined = old->Union(multiP); + delete old; + } + + // multiP is freed by ImagePolygon object + _mapping = getProjGeometry(camera, multiP, g); + } + + // Save off this band geometry property + _gBandList.push_back(g); + } + + // Compute the remainder of the summary bands since some of the operations + // need the camera model + _summary = getGeometrySummary(); + if ( (size() != 1) && (doPolygon)) { + geos::geom::MultiPolygon *multiP = makeMultiPolygon(_combined); + _mapping = getProjGeometry(camera, multiP, _summary); + delete multiP; + } + + return; +} + + +void BandGeometry::generateGeometryKeys(PvlObject &pband) { + if ( size() <= 0 ) { + std::string mess = "No Band geometry available!"; + iException::Message(iException::Programmer, mess, _FILEINFO_); + } + + GProperties g = getGeometrySummary(); + +//geometry keywords for band output + pband += PvlKeyword("BandsUsed", size()); + pband += PvlKeyword("ReferenceBand", g.band); + pband += PvlKeyword("OriginalBand", g.realBand); + + pband += PvlKeyword("Target", g.target); + + pband += PvlKeyword("StartTime",g.startTime); + pband += PvlKeyword("EndTime",g.endTime); + + pband += ValidateKey("CenterLine",g.centerLine); + pband += ValidateKey("CenterSample",g.centerSamp); + pband += ValidateKey("CenterLatitude",g.centerLatitude); + pband += ValidateKey("CenterLongitude",g.centerLongitude); + pband += ValidateKey("CenterRadius",g.radius); + + pband += ValidateKey("RightAscension",g.rightAscension); + pband += ValidateKey("Declination",g.declination); + + pband += ValidateKey("UpperLeftLongitude",g.upperLeftLongitude); + pband += ValidateKey("UpperLeftLatitude",g.upperLeftLatitude); + pband += ValidateKey("LowerLeftLongitude",g.lowerLeftLongitude); + pband += ValidateKey("LowerLeftLatitude",g.lowerLeftLatitude); + pband += ValidateKey("LowerRightLongitude",g.lowerRightLongitude); + pband += ValidateKey("LowerRightLatitude",g.lowerRightLatitude); + pband += ValidateKey("UpperRightLongitude",g.upperRightLongitude); + pband += ValidateKey("UpperRightLatitude",g.upperRightLatitude); + + pband += ValidateKey("PhaseAngle",g.phase); + pband += ValidateKey("EmissionAngle",g.emi); + pband += ValidateKey("IncidenceAngle",g.inc); + + pband += ValidateKey("NorthAzimuth",g.northAzimuth); + pband += ValidateKey("OffNadir",g.offNader); + pband += ValidateKey("SolarLongitude",g.solarLongitude); + pband += ValidateKey("LocalTime",g.localSolartime); + pband += ValidateKey("TargetCenterDistance",g.targetCenterDistance); + pband += ValidateKey("SlantDistance",g.slantDistance); + + double aveRes(Null); + if (!IsSpecial(g.sampRes) && !IsSpecial(g.lineRes)) { + aveRes = (g.sampRes + g.lineRes) / 2.0; + } + + pband += ValidateKey("SampleResolution",g.sampRes); + pband += ValidateKey("LineResolution",g.lineRes); + pband += ValidateKey("PixelResolution",aveRes); + pband += ValidateKey("MeanGroundResolution",g.grRes); + + pband += ValidateKey("SubSolarAzimuth",g.subSolarAzimuth); + pband += ValidateKey("SubSolarGroundAzimuth",g.subSolarGroundAzimuth); + pband += ValidateKey("SubSolarLatitude", g.subSolarLatitude); + pband += ValidateKey("SubSolarLongitude",g.subSolarLongitude); + + pband += ValidateKey("SubSpacecraftAzimuth", g.subSpacecraftAzimuth); + pband += ValidateKey("SubSpacecraftGroundAzimuth", g.subSpacecraftGroundAzimuth); + pband += ValidateKey("SubSpacecraftLatitude",g.subSpacecraftLatitude); + pband += ValidateKey("SubSpacecraftLongitude",g.subSpacecraftLongitude); + + pband += ValidateKey("ParallaxX",g.parallaxx); + pband += ValidateKey("ParallaxY",g.parallaxy); + + pband += ValidateKey("ShadowX",g.shadowx); + pband += ValidateKey("ShadowY",g.shadowy); + + // Determine if image crosses Longitude domain + if ( g.hasLongitudeBoundary ) { + pband += PvlKeyword("HasLongitudeBoundary","TRUE"); + } + else { + pband += PvlKeyword("HasLongitudeBoundary","FALSE"); + } + + // Add test for North pole in image + if (g.hasNorthPole) { + pband += PvlKeyword("HasNorthPole", "TRUE"); + } + else { + pband += PvlKeyword("HasNorthPole", "FALSE"); + } + + // Add test for South pole in image + if (g.hasSouthPole) { + pband += PvlKeyword("HasSouthPole", "TRUE"); + } + else { + pband += PvlKeyword("HasSouthPole", "FALSE"); + } + + return; +} + +BandGeometry::GProperties BandGeometry::getGeometrySummary() const { + if ( _isBandIndependent || (size() == 1)) { + return (_gBandList[0]); + } + + // Get the centroid point of the union polygon + double plon(Null), plat(Null); + if ( _combined != 0 ) { + geos::geom::Point *center = _combined->getCentroid(); + plon = center->getX(); + plat = center->getY(); + delete center; + } + + GProperties bestBand; + double centerDistance(DBL_MAX); + + GProperties corners; + double ulDist(DBL_MIN), urDist(DBL_MIN), + lrDist(DBL_MIN), llDist(DBL_MIN); + + double radius = getRadius(); + + BandPropertiesListConstIter b; + for ( b = _gBandList.begin() ; b != _gBandList.end() ; ++b ) { + double thisDist; + + // Ensure the center latitude/logitude is defined (typically occurs when + // no polygon data is available). This scheme uses the first one defined. + if ( IsSpecial(plat) || IsSpecial(plon) ) { + plat = b->centerLatitude; + plon = b->centerLongitude; + } + + // Now check all data + bool isCloser = isDistShorter(centerDistance, plat, plon, + b->centerLatitude,b->centerLongitude, + radius, thisDist) ; + if (isCloser) { + bestBand = *b; + centerDistance = thisDist; + } + + // Do upper left and right corners + isCloser = isDistShorter(ulDist, plat, plon, + b->upperLeftLatitude, b->upperLeftLongitude, + radius, thisDist); + if ( !isCloser ) { + corners.upperLeftLatitude = b->upperLeftLatitude; + corners.upperLeftLongitude = b->upperLeftLongitude; + ulDist = thisDist; + } + + isCloser = isDistShorter(urDist, plat, plon, + b->upperRightLatitude, b->upperRightLongitude, + radius, thisDist); + if ( !isCloser ) { + corners.upperRightLatitude = b->upperRightLatitude; + corners.upperRightLongitude = b->upperRightLongitude; + urDist = thisDist; + } + + // Do lower left and right corners + isCloser = isDistShorter(llDist, plat, plon, + b->lowerLeftLatitude, b->lowerLeftLongitude, + radius, thisDist); + if ( !isCloser ) { + corners.lowerLeftLatitude = b->lowerLeftLatitude; + corners.lowerLeftLongitude = b->lowerLeftLongitude; + llDist = thisDist; + } + + isCloser = isDistShorter(lrDist, plat, plon, + b->lowerRightLatitude, b->lowerRightLongitude, + radius, thisDist); + if ( !isCloser ) { + corners.lowerRightLatitude = b->lowerRightLatitude; + corners.lowerRightLongitude = b->lowerRightLongitude; + lrDist = thisDist; + } + } + + // Add the corners to the returning property + bestBand.upperLeftLatitude = corners.upperLeftLatitude; + bestBand.upperLeftLongitude = corners.upperLeftLongitude; + bestBand.upperRightLatitude = corners.upperRightLatitude; + bestBand.upperRightLongitude = corners.upperRightLongitude; + bestBand.lowerLeftLatitude = corners.lowerLeftLatitude; + bestBand.lowerLeftLongitude = corners.lowerLeftLongitude; + bestBand.lowerRightLatitude = corners.lowerRightLatitude; + bestBand.lowerRightLongitude = corners.lowerRightLongitude; + return (bestBand); +} + + +Pvl BandGeometry::getProjGeometry(Camera &camera, + geos::geom::MultiPolygon *footprint, + GProperties &g) { + +#if defined(DEBUG) + std::ofstream fp("footprint.gml"); + fp << PolygonTools::ToGML(footprint, "Footprint"); + fp.close(); +#endif + // Get basic projection information. Assumes a Sinusoidal projection with + // East 360 longitude domain and planetocentric laitudes. + Pvl sinuMap; + camera.BasicMapping(sinuMap); + PvlGroup &mapping = sinuMap.FindGroup("Mapping"); + + double clon = g.centerLongitude; + double minLon = (double) mapping["MinimumLongitude"]; + double maxLon = (double) mapping["MaximumLongitude"]; + if ( IsSpecial(clon) ) clon = (minLon + maxLon)/2.0; + + // Make adjustments for center projection type/ranges. + // To be consistant with other implementations, do not + // convert poles to 180 domain. + geos::geom::MultiPolygon *poly180(0), *poly(footprint); + if ( g.hasLongitudeBoundary ) { + if ( !(g.hasNorthPole || g.hasSouthPole) ) { + // Convert the mapping group contents to 180 Longitude domain + PvlKeyword &ldkey = mapping["LongitudeDomain"]; + ldkey.SetValue("180"); + + PvlKeyword &minkey = mapping["MinimumLongitude"]; + PvlKeyword &maxkey = mapping["MaximumLongitude"]; + minkey.SetValue("-180.0"); + maxkey.SetValue("180.0"); + + // Compute new ranges + double minLat180, maxLat180, minLon180, maxLon180; + camera.GroundRange(minLat180, maxLat180, minLon180, maxLon180, sinuMap); + minkey.SetValue(ToString(minLon180)); + maxkey.SetValue(ToString(maxLon180)); + clon = (minLon180 + maxLon180) / 2.0; + + // Convert the polygon to 180 domain + poly = poly180 = PolygonTools::To180(footprint); +#if defined(DEBUG) + std::ofstream p180("poly180.gml"); + p180 << PolygonTools::ToGML(poly180, "180Domain"); + p180.close(); +#endif + + } + } + + mapping += PvlKeyword("CenterLongitude", clon); + + Projection *sinu = ProjectionFactory::Create(sinuMap, true); + geos::geom::MultiPolygon *sPoly = PolygonTools::LatLonToXY(*poly, sinu); +#if defined(DEBUG) + std::ofstream ll("sinuprojxy.gml"); + ll << PolygonTools::ToGML(sPoly, "SinuProjectedXY"); + ll.close(); +#endif + geos::geom::Point *center = sPoly->getCentroid(); + + sinu->SetCoordinate(center->getX(), center->getY()); + g.centroidLongitude = Projection::To360Domain(sinu->UniversalLongitude()); + g.centroidLatitude = sinu->UniversalLatitude(); + g.surfaceArea = sPoly->getArea() / (1000.0 * 1000.0); + delete center; + delete sPoly; + delete sinu; + delete poly180; + + if (camera.SetUniversalGround(g.centroidLatitude, g.centroidLongitude)) { + g.centroidLine = camera.Line(); + g.centroidSample = camera.Sample(); + g.centroidRadius = camera.LocalRadius(); + } + + return (sinuMap); +} + +void BandGeometry::generatePolygonKeys(PvlObject &pband) { + if ( size() <= 0 ) { + std::string mess = "No Band geometry available!"; + iException::Message(iException::Programmer, mess, _FILEINFO_); + } + + // Compute surface area - already done in collection phase + double radius = getRadius(); + double globalCoverage(Null); + if ( !IsSpecial(radius) ) { + double globalArea = 4.0 * pi_c() * (radius * radius) / (1000.0*1000.0); + globalCoverage = _summary.surfaceArea / globalArea * 100.0; + globalCoverage = SetRound(globalCoverage, 6); + } + + pband += ValidateKey("CentroidLine",_summary.centroidLine); + pband += ValidateKey("CentroidSample",_summary.centroidSample); + pband += ValidateKey("CentroidLatitude",_summary.centroidLatitude); + pband += ValidateKey("CentroidLongitude",_summary.centroidLongitude); + pband += ValidateKey("CentroidRadius",_summary.centroidRadius, "meters"); + pband += ValidateKey("SurfaceArea",_summary.surfaceArea,"km^2"); + pband += ValidateKey("GlobalCoverage",globalCoverage,"percent"); + if ( _combined != 0 ) { + pband += PvlKeyword("PixelIncrement", _pixinc); + if ( _combined->getGeometryTypeId() != geos::geom::GEOS_MULTIPOLYGON ) { + geos::geom::MultiPolygon *geom = makeMultiPolygon(_combined); + pband += PvlKeyword("GisFootprint", geom->toString()); + delete geom; + } + else { + pband += PvlKeyword("GisFootprint", _combined->toString()); + } + } + else { + pband += PvlKeyword("GisFootprint", Null); + } + + // Add the mapping group used to project polygon + pband.AddGroup(_mapping.FindGroup("Mapping")); + return; +} + +double BandGeometry::getRadius() const { + Statistics polyRadius, centRadius; + BandPropertiesListConstIter b; + for ( b = _gBandList.begin() ; b != _gBandList.end() ; ++b ) { + polyRadius.AddData(b->centroidRadius); + centRadius.AddData(b->radius); + } + double radius = polyRadius.Average(); + if ( IsSpecial(radius) ) radius = centRadius.Average(); + if ( IsSpecial(radius) ) radius = _radius; + return (radius); +} + +double BandGeometry::getPixelResolution() const { + Statistics groundRes, pixelRes; + BandPropertiesListConstIter b; + for ( b = _gBandList.begin() ; b != _gBandList.end() ; ++b ) { + pixelRes.AddData(b->sampRes); + pixelRes.AddData(b->lineRes); + groundRes.AddData(b->grRes); + } + + double res = groundRes.Average(); + if ( IsSpecial(res) ) res = pixelRes.Average(); + return (res); +} + +double BandGeometry::getPixelsPerDegree(double pixres, + double radius) const { + double circumference = 2.0 * pi_c() * radius; + double metersPerDegree = circumference / 360.0; + double pixelsPerDegree = metersPerDegree / pixres; + return (pixelsPerDegree); +} + + +bool BandGeometry::isDistShorter(double bestDist, double lat1, double lon1, + double lat2, double lon2, double radius, + double &thisDist) const { + if ( IsSpecial(lat1) ) return (false); + if ( IsSpecial(lon1) ) return (false); + if ( IsSpecial(lat2) ) return (false); + if ( IsSpecial(lon2) ) return (false); + if ( IsSpecial(radius) ) return (false); + + thisDist = Camera::Distance(lat1, lon1, lat2, lon2, radius); + return (thisDist < bestDist); +} + +geos::geom::MultiPolygon *BandGeometry::makeMultiPolygon( + geos::geom::Geometry *g) const { + vector polys; + polys.push_back(g); + const geos::geom::GeometryFactory *gfactory = geos::geom::GeometryFactory::getDefaultInstance(); + return (gfactory->createMultiPolygon(polys)); +} + + +} // namespace Isis diff --git a/isis/src/base/apps/caminfo/CamTools.h b/isis/src/base/apps/caminfo/CamTools.h new file mode 100644 index 0000000000000000000000000000000000000000..378d32bd010332965f1bf0f617b5ac4884e59af9 --- /dev/null +++ b/isis/src/base/apps/caminfo/CamTools.h @@ -0,0 +1,249 @@ +#if !defined(CamTools_h) +#define CamTools_h +/** + * @file + * $Revision: 1.10 $ + * $Date: 2009/08/25 01:37:55 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include + +#include "Pvl.h" +#include "PvlKeyword.h" +#include "SpecialPixel.h" +#include "ImagePolygon.h" +#include "iException.h" + +namespace Isis { + +/** + * @brief Checks value of key, produces appropriate value + * + * This function checks the value of the keyword for specialness + * and will create the appropriate keyword if it is special. + * + * @param keyname Name of keyword to create + * @param value Keyword value + * @param unit Optional unit qualifer with value + * + * @return PvlKeyword Returns newly created keyword/value + */ +inline PvlKeyword ValidateKey(const std::string keyname, + const double &value, + const std::string &unit = "") { + if (IsSpecial(value)) { + return (PvlKeyword(keyname,"NULL")); + } + else { + return (PvlKeyword(keyname,value,unit)); + } +} + +/** + * @brief Checks proper value of a NULLed keyword + * + * If the keyword is a NULL keyword, ensure it has proper value. + * + * @param keyname Name of keyword to create + * @param key Keyword/value set + * @param unit Optional unit qualifer with value + * + * @return PvlKeyword Returns newly created keyword/value + */ + +inline PvlKeyword ValidateKey(const std::string keyname, PvlKeyword &key, + const std::string &unit = "") { + if (key.IsNull()) { + return (PvlKeyword(keyname,"NULL")); + } + else { + return (ValidateKey(keyname,(double) key,unit)); + } +} + + +/** Returns degree to radian conversion factor */ +inline double DegToRad(const double ang) { return (ang * rpd_c()); } +/** Returns radians to degrees conversion factor */ +inline double RadToDeg(const double ang) { return (ang * dpr_c()); } + +/** A very useful, typesafe way to delete pointers in STL container + * Courtesy Scott Meyers, "Effective STL", Item 7, pg 37-40 */ +struct DeleteObject { + template + void operator()(const T* ptr) const { + delete ptr; + } +}; + + /** + * @brief Collect Band geometry + * + * This produces the geometry and polygon information from an image cube. It + * has some special processing that accounts for band independant geometrical + * image cubes. It processes each band and creates unique geometry and + * ploygon values consider this situation. The resulting polygon is a union + * of all bands, which is a (usually) slightly better footprint of the acutal + * footprint for the product. + * + * The other major advantage to this class is the corner latitude/longitude + * points are based upon the extents of each independant band data as the + * furthest point from the center of the polygon location (if requested by the + * user). + * + * @ingroup Utility + * @author 2008-09-10 Kris Becker + * @history 2009-02-26 Kris Becker - Removed unconditional computation of + * polygon even when the user did not request it. Reorganized some + * keywords to their relevant group locations. + * @history 2009-05-29 Kris Becker - Added _pixinx parameter + * @history 2009-06-22 Kris Becker - Added hasLimb() method to check for the + * presence of a planet limb; Added getProjGeometry() method. + * @history 2009-08-04 Christopher Austin - fixed ImagePolygon::Create call for + * the updated sampinc/lineinc implementation + * @history 2009-08-12 Kris Becker - Modified so that images that include + * poles are not converted to 180 domain when projected + * @history 2009-08-24 Kris Becker - Added ability to disable use of shape + * model when creating polygons that contains a limb + */ +class BandGeometry { + + public: + BandGeometry() : _nLines(0), _nSamps(0), _nBands(0), _pixinc(1), + _radius(1.0), _isBandIndependent(true), + _hasCenterGeom(false), _gBandList(), _polys(), + _combined(0), _mapping() { } + ~BandGeometry() { destruct(); } + + void setPixInc(const int pixinc) { _pixinc = pixinc; } + int getPixInc() const { return (_pixinc); } + void setMaxIncidence(const double maxinc) { _maxIncidence = maxinc; } + void setMaxEmission(const double maxema) { _maxEmission = maxema; } + int size() const { return (_gBandList.size()); } + bool isPointValid(const double &sample, const double &line, const Camera *camera = 0) const; + bool isBandIndependent() const { return (_isBandIndependent); } + bool hasCenterGeometry() const; + bool hasLimb() const; + void collect(Camera &camera, Cube &cube, bool doGeometry, bool doPolygon); + void generateGeometryKeys(PvlObject &pband); + void generatePolygonKeys(PvlObject &pband); + + private: + // Internal structure to contain geometric properties + struct GProperties { + GProperties() : lines(0), samples(0), bands(0), + band(0), realBand(0), target(""), + centerLine(0.0), centerSamp(0.0), + centerLatitude(Null), centerLongitude(Null), radius(Null), + rightAscension(Null), declination(Null), + centroidLatitude(Null), centroidLongitude(Null), + centroidLine(Null), centroidSample(Null), centroidRadius(Null), + surfaceArea(Null), phase(Null), emi(Null), inc(Null), + sampRes(Null), lineRes(Null), grRes(Null), + solarLongitude(Null), northAzimuth(Null), offNader(Null), + subSolarAzimuth(Null), subSolarGroundAzimuth(Null), + subSpacecraftAzimuth(Null), subSpacecraftGroundAzimuth(Null), + localSolartime (Null), targetCenterDistance(Null), slantDistance(Null), + subSolarLatitude(Null), subSolarLongitude(Null), + subSpacecraftLatitude(Null), subSpacecraftLongitude(Null), + startTime(""), endTime(""), + parallaxx(Null), parallaxy(Null), + shadowx(Null), shadowy(Null), + upperLeftLongitude(Null), upperLeftLatitude(Null), + lowerLeftLongitude(Null), lowerLeftLatitude(Null), + lowerRightLongitude(Null), lowerRightLatitude(Null), + upperRightLongitude(Null),upperRightLatitude(Null), + hasLongitudeBoundary(false), hasNorthPole(false), hasSouthPole(false) { } + ~GProperties() { } + + int lines, samples, bands; + int band, realBand; + std::string target; + double centerLine, centerSamp; + double centerLatitude, centerLongitude; + double radius; + double rightAscension, declination; + double centroidLatitude, centroidLongitude; + double centroidLine, centroidSample; + double centroidRadius, surfaceArea; + double phase, emi, inc; + double sampRes, lineRes, grRes; + double solarLongitude, northAzimuth, offNader; + double subSolarAzimuth, subSolarGroundAzimuth; + double subSpacecraftAzimuth, subSpacecraftGroundAzimuth; + double localSolartime, targetCenterDistance, slantDistance; + double subSolarLatitude, subSolarLongitude; + double subSpacecraftLatitude, subSpacecraftLongitude; + std::string startTime, endTime; + double parallaxx, parallaxy, shadowx, shadowy; + double upperLeftLongitude, upperLeftLatitude; + double lowerLeftLongitude, lowerLeftLatitude; + double lowerRightLongitude, lowerRightLatitude; + double upperRightLongitude, upperRightLatitude; + bool hasLongitudeBoundary, hasNorthPole, hasSouthPole; + }; + + typedef std::vector BandPropertiesList; + typedef BandPropertiesList::iterator BandPropertiesListIter; + typedef BandPropertiesList::const_iterator BandPropertiesListConstIter; + + // Internal structure to contain geometric properties + typedef std::vector BandPolygonList; + typedef BandPolygonList::iterator BandPolygonListIter; + typedef BandPolygonList::const_iterator BandPolygonListConstIter; + + + int _nLines; + int _nSamps; + int _nBands; + int _pixinc; + double _maxEmission; + double _maxIncidence; + double _radius; + bool _isBandIndependent; + bool _hasCenterGeom; + BandPropertiesList _gBandList; + BandPolygonList _polys; + geos::geom::Geometry *_combined; + GProperties _summary; + Pvl _mapping; + + void destruct(); + GProperties getGeometrySummary() const; + Pvl getProjGeometry(Camera &camera, geos::geom::MultiPolygon *footprint, + GProperties &g); + double getRadius() const; + double getPixelResolution() const; + double getPixelsPerDegree(double pixres, double radius) const; + bool isDistShorter(double bestDist, double lat1, double lon1, + double lat2, double lon2, double radius, + double &thisDist) const; + geos::geom::MultiPolygon *makeMultiPolygon(geos::geom::Geometry *g) const; + + +}; + +} // Namespace Isis + +#endif diff --git a/isis/src/base/apps/caminfo/Makefile b/isis/src/base/apps/caminfo/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/caminfo/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/caminfo/caminfo.cpp b/isis/src/base/apps/caminfo/caminfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fabdd7dfb60f21c99615ffb4a1a11258d28d09e6 --- /dev/null +++ b/isis/src/base/apps/caminfo/caminfo.cpp @@ -0,0 +1,210 @@ +#include "Isis.h" +#include +#include +#include + +#include "CamTools.h" +#include "Constants.h" +#include "CubeAttribute.h" +#include "Filename.h" +#include "iException.h" +#include "iString.h" +#include "iTime.h" +#include "LineManager.h" +#include "OriginalLabel.h" +#include "Process.h" +#include "Progress.h" +#include "Pvl.h" +#include "SerialNumber.h" +#include "SpecialPixel.h" +#include "Statistics.h" +#include "UserInterface.h" + +using namespace std; +using namespace Isis; + +void IsisMain () +{ + const string caminfo_program = "caminfo"; + const string caminfo_version = "2.2"; + const string caminfo_revision = "$Revision: 1.20 $"; + string caminfo_runtime = iTime::CurrentGMT(); + + Process p; + // Grab the file to import + UserInterface &ui = Application::GetUserInterface(); + string from = ui.GetAsString("FROM"); + Filename in = ui.GetFilename("FROM"); + bool doCamstat = ui.GetBoolean("CAMSTATS"); + + Pvl pout; + // if true then run spiceinit, xml default is FALSE + //spiceinit will use system kernels + if (ui.GetBoolean("SPICE")) { + string parameters = "FROM=" + in.Expanded(); + Isis::iApp->Exec("spiceinit",parameters); + } + + Cube *icube = p.SetInputCube("FROM"); + + // get some common things like #line, #samples, bands. + PvlObject params("Caminfo"); + PvlObject common("Parameters"); + common += PvlKeyword("Program", caminfo_program); + common += PvlKeyword("Version", caminfo_version); + common += PvlKeyword("IsisVersion", version); + common += PvlKeyword("RunDate", caminfo_runtime); + common += PvlKeyword("IsisId",SerialNumber::Compose(*icube)); + common += PvlKeyword("From",icube->Filename()); + common += PvlKeyword("Lines",icube->Lines()); + common += PvlKeyword("Samples",icube->Samples()); + common += PvlKeyword("Bands",icube->Bands()); + params.AddObject(common); + + // Run camstats on the entire image (all bands) + // another camstats will be run for each band and output + // for each band. + Pvl camPvl; // This becomes useful if there is only one band, which is + // frequent! Used below if single band image. + if (doCamstat) { + int linc = ui.GetInteger("LINC"); + int sinc = ui.GetInteger("SINC"); + Filename tempCamPvl; + tempCamPvl.Temporary(in.Basename()+"_", "pvl"); + string pvlOut = tempCamPvl.Expanded(); + PvlObject pcband("Camstats"); + //set up camstats run and execute + string parameters = "FROM=" + from + + " TO=" + pvlOut + + " LINC=" + iString(linc) + + " SINC=" + iString(sinc); + + Isis::iApp->Exec("camstats",parameters); + //out put to common object of the PVL + camPvl.Read(pvlOut); + remove(pvlOut.c_str()); + + PvlGroup cg = camPvl.FindGroup("Latitude",Pvl::Traverse); + pcband += ValidateKey("MinimumLatitude",cg["latitudeminimum"]); + pcband += ValidateKey("MaximumLatitude",cg["latitudemaximum"]); + cg = camPvl.FindGroup("Longitude",Pvl::Traverse); + pcband += ValidateKey("MinimumLongitude",cg["longitudeminimum"]); + pcband += ValidateKey("MaximumLongitude",cg["longitudemaximum"]); + cg = camPvl.FindGroup("Resolution",Pvl::Traverse); + pcband += ValidateKey("MinimumResolution",cg["resolutionminimum"]); + pcband += ValidateKey("MaximumResolution",cg["resolutionmaximum"]); + cg = camPvl.FindGroup("PhaseAngle",Pvl::Traverse); + pcband += ValidateKey("MinimumPhase",cg["phaseminimum"]); + pcband += ValidateKey("MaximumPhase",cg["phasemaximum"]); + cg = camPvl.FindGroup("EmissionAngle",Pvl::Traverse); + pcband += ValidateKey("MinimumEmission",cg["emissionminimum"]); + pcband += ValidateKey("MaximumEmission",cg["emissionmaximum"]); + cg = camPvl.FindGroup("IncidenceAngle",Pvl::Traverse); + pcband += ValidateKey("MinimumIncidence",cg["incidenceminimum"]); + pcband += ValidateKey("MaximumIncidence",cg["incidencemaximum"]); + cg = camPvl.FindGroup("LocalSolarTime",Pvl::Traverse); + pcband += ValidateKey("LocalTimeMinimum",cg["localsolartimeMinimum"]); + pcband += ValidateKey("LocalTimeMaximum",cg["localsolartimeMaximum"]); + params.AddObject(pcband); + } + + + // Add the input ISIS label if requested + if ( ui.GetBoolean("ISISLABEL") ) { + Pvl label = *(icube->Label()); + label.SetName("IsisLabel"); + params.AddObject(label); + } + + // write out the orginal label blob + if (ui.GetBoolean("ORIGINALLABEL")) { + OriginalLabel orig; + icube->Read(orig); + Pvl p = orig.ReturnLabels(); + p.SetName("OriginalLabel"); + params.AddObject(p); + } + + + // Compute statistics for entire cube + if ( ui.GetBoolean("STATISTICS") ) { + LineManager iline(*icube); + Statistics stats; + Progress progress; + progress.SetText("Statistics..."); + progress.SetMaximumSteps(icube->Lines()*icube->Bands()); + progress.CheckStatus(); + iline.SetLine(1); + for ( ; !iline.end() ; iline.next()) { + icube->Read(iline); + stats.AddData(iline.DoubleBuffer(), iline.size()); + progress.CheckStatus(); + } + + // Compute stats of entire cube + double nPixels = stats.TotalPixels(); + double nullpercent = (stats.NullPixels()/(nPixels))*100; + double hispercent = (stats.HisPixels()/(nPixels))*100; + double hrspercent = (stats.HrsPixels()/(nPixels))*100; + double lispercent = (stats.LisPixels()/(nPixels))*100; + double lrspercent = (stats.LrsPixels()/(nPixels))*100; + //statitics keyword output for band + + PvlObject sgroup("Statistics"); + sgroup += ValidateKey("MeanValue",stats.Average()); + sgroup += ValidateKey("StandardDeviation",stats.StandardDeviation()); + sgroup += ValidateKey("MinimumValue",stats.Minimum()); + sgroup += ValidateKey("MaximumValue",stats.Maximum()); + sgroup += PvlKeyword("PercentHIS",hispercent); + sgroup += PvlKeyword("PercentHRS",hrspercent); + sgroup += PvlKeyword("PercentLIS",lispercent); + sgroup += PvlKeyword("PercentLRS",lrspercent); + sgroup += PvlKeyword("PercentNull",nullpercent); + sgroup += PvlKeyword("TotalPixels",stats.TotalPixels()); + + params.AddObject(sgroup); + } + + Camera *cam = icube->Camera(); + + // for geometry, stats, camstats, or polygon get the info for each band + BandGeometry bandGeom; + bool doGeometry = ui.GetBoolean("GEOMETRY"); + bool doPolygon = ui.GetBoolean("POLYGON"); + if (doGeometry || doPolygon) { + int pixinc = ui.GetInteger("PIXINC"); + if (pixinc <= 0) pixinc = 100; + bandGeom.setPixInc(pixinc); + bandGeom.setMaxIncidence(ui.GetDouble("MAXINCIDENCE")); + bandGeom.setMaxEmission(ui.GetDouble("MAXEMISSION")); + bandGeom.collect(*cam, *icube, doGeometry, doPolygon); + + + // Check if the user requires valid image center geometry + if (ui.GetBoolean("VCAMERA") && (!bandGeom.hasCenterGeometry())) { + string msg = "Image center does not project in camera model"; + throw iException::Message(iException::Camera,msg,_FILEINFO_); + } + + // Write geometry data if requested + if (doGeometry) { + PvlObject ggroup("Geometry"); + bandGeom.generateGeometryKeys(ggroup); + params.AddObject(ggroup); + } + + // Write polygon group if requested + if (doPolygon) { + PvlObject ggroup("Polygon"); + bandGeom.generatePolygonKeys(ggroup); + params.AddObject(ggroup); + } + } + + // Output the result + string outFile = ui.GetFilename("TO"); + pout.AddObject(params); + pout.Write(outFile); +} + + diff --git a/isis/src/base/apps/caminfo/caminfo.xml b/isis/src/base/apps/caminfo/caminfo.xml new file mode 100644 index 0000000000000000000000000000000000000000..6a70174626f156c1fe1a663edb19f35f2b40497e --- /dev/null +++ b/isis/src/base/apps/caminfo/caminfo.xml @@ -0,0 +1,678 @@ + + + + + + Outputs a PVL file that contains camera information. + + + + This program requires the user supply a "level 1" cube. That is, a cube in raw camera geometry. + The user can choose to run spiceinit on the input cube. Spiceinit will use the system kernels, + so any user updates to SPICE information will be lost. The default is to not run spiceinit. + This program will output various spacecraft and instrument related + information. Some of the output information will be a compilation + of all bands, this will be put in the "Common" object of the PVL. Other + infomation will be for a given band and placed in the "BandSet" object. the + user can use the "output options" check boxes to control the infomation that + will be output to the PVL. if the polygon option is chosen, the image + polygon is output in well known text format. The following is an example of + the output given when caminfo is ran: + +
     
    +    
    +Object = Caminfo
    +  Object = Parameters
    +    Program     = caminfo
    +    Version     = 2.0
    +    IsisVersion = "3.1.18beta | 2008-09-10"
    +    RunDate     = 2008-09-23T04:04:40
    +    IsisId      = MeSSEnGeR/MDIS-WAC/1/0108827809:757000
    +    From        = EW0108827809H_iof.cub
    +    Lines       = 1024
    +    Samples     = 1024
    +    Bands       = 1
    +  End_Object
    +
    +  Object = Camstats
    +    MinimumLatitude   = -83.41440480372
    +    MaximumLatitude   = 3.7509815164171
    +    MinimumLongitude  = 130.12663958352
    +    MaximumLongitude  = 211.4118481043
    +    MinimumResolution = 2837.9275992245
    +    MaximumResolution = 3243.3476291415
    +    MinimumPhase      = 55.948494781205
    +    MaximumPhase      = 63.452364544485
    +    MinimumEmission   = 1.5987003275551
    +    MaximumEmission   = 89.906039419667
    +    MinimumIncidence  = 0.0061432307848179
    +    MaximumIncidence  = 84.83085856686
    +    LocalTimeMinimum  = 8.3450457249626
    +    LocalTimeMaximum  = 13.764059626348
    +  End_Object
    +
    +  Object = Statistics
    +    MeanValue         = 0.027290557106805
    +    StandardDeviation = 0.030059960910294
    +    MinimumValue      = 1.93800340639427e-04
    +    MaximumValue      = 0.13901169598103
    +    PercentHIS        = 0.0
    +    PercentHRS        = 0.0
    +    PercentLIS        = 0.0
    +    PercentLRS        = 0.0
    +    PercentNull       = 0.390625
    +    TotalPixels       = 1048576
    +  End_Object
    +
    +  Object = Geometry
    +    BandsUsed              = 1
    +    ReferenceBand          = 1
    +    OriginalBand           = 1
    +    Target                 = Mercury
    +    StartTime              = 2008-01-14T19:53:48.9698697
    +    EndTime                = 2008-01-14T19:53:48.9698697
    +    CenterLatitude         = -35.99699070995
    +    CenterLongitude        = 183.5425629901
    +    CenterRadius           = 2440000.0
    +    UpperLeftLongitude     = 130.629425434
    +    UpperLeftLatitude      = 2.2131023206612
    +    LowerLeftLongitude     = NULL
    +    LowerLeftLatitude      = NULL
    +    LowerRightLongitude    = NULL
    +    LowerRightLatitude     = NULL
    +    UpperRightLongitude    = NULL
    +    UpperRightLatitude     = NULL
    +    PhaseAngle             = 61.158147083403
    +    EmissionAngle          = 67.650944858113
    +    IncidenceAngle         = 36.012241921332
    +    NorthAzimuth           = 301.67928206242
    +    OffNadir               = 7.0664149700808
    +    SolarLongitude         = 251.5447380459
    +    LocalTime              = 11.906107285401
    +    TargetCenterDistance   = 2.2131023206612
    +    SlantDistance          = 17277.206903028
    +    SampleResolution       = 3082.7363142225
    +    LineResolution         = 3082.7363142225
    +    PixelResolution        = 3082.7363142225
    +    MeanGroundResolution   = 3040.5954926264
    +    SubSolarAzimuth        = 302.6826986422
    +    SubSolarLatitude       = -0.010137623850141
    +    SubSolarLongitude      = 184.95095370909
    +    SubSpacecraftAzimuth   = 220.05494431655
    +    SubSpacecraftLatitude  = -0.010137623850141
    +    SubSpacecraftLongitude = 129.16259115677
    +    ParallaxX              = 106.67119905901
    +    ParallaxY              = -89.682221077406
    +    ShadowX                = -22.488549587781
    +    ShadowY                = -35.052794194572
    +    HasLongitudeBoundary   = FALSE
    +    HasNorthPole           = FALSE
    +    HasSouthPole           = FALSE
    +  End_Object
    +
    +  Object = Polygon
    +    CentroidLine           = 444.50993729582
    +    CentroidSample         = 451.51727680485
    +    CentroidLatitude       = -29.640948990517
    +    CentroidLongitude      = 169.87095531121
    +    CentroidRadius         = 2440000.0
    +    SurfaceArea            = 8306887.6685914
    +    GlobalCoverage    = 11.103217 
    +    GisFootprint      = "MULTIPOLYGON (((130.6294254340024850 
    +                        2.2131023206611959, 132.6105055692809458 
    +                        2.1932630353674178, 134.5991041747939221 
    +                        2.1768866704663559, 136.5989383173149179 
    +                        2.1639614104686271, 138.6138732701137997 
    +                        2.1544991617480225, 140.6479870975472579 
    +                        2.1485370053737980, 142.7056447944214597 
    +                        2.1461393256491279, 144.7915859682860571 
    +                        2.1474007607611276, 146.9110313636781484 
    +                        2.1524501894704975, 149.0698155062488013 
    +                        2.1614560641171146, 151.2745557583258744 
    +                        2.1746335423788317, 153.5328727459032621 
    +                        2.1922540865408204, 155.8536845185811046 
    +                        2.2146585384017592, 158.2476088770336560 
    +                        2.2422752278895586, 160.7275286712950901 
    +                        2.2756455971466307, 163.3094106296108805 
    +                        2.3154614378397187, 166.0135340628912388 
    +                        2.3626208040715224, 168.8664138091551763 
    +                        2.4183154173570665, 171.9039685142860208 
    +                        2.4841743385969286, 175.1770904293465208 
    +                        2.5625157415150714, 178.7623042877256410 
    +                        2.6568269305599421, 182.7846940640967830 
    +                        2.7727925518573540, 187.4765775963039118 
    +                        2.9209141292952903, 193.3794591608424014 
    +                        3.1254813901633982, 202.8003290883544025 
    +                        3.4888589890121060, 208.9133243384161744 
    +                        3.6695683095888598, 209.4133181820310767 
    +                        1.4310443060885591, 210.6818642154790666 
    +                        -0.7847478854915861, 209.5295428597240175 
    +                        -3.0806311148737824, 209.1564870917320604 
    +                        -5.3515530445086279, 209.1471946316104891 
    +                        -7.6207555826676865, 209.5097635515893160 
    +                        -9.8977975847883499, 210.6196405642980096 
    +                        -12.1902347166813119, 209.7307796946379881 
    +                        -14.5159937391944958, 209.6716791291469804 
    +                        -16.8610282853524112, 210.5320551329192540 
    +                        -19.2444276256453826, 209.6857434743561157 
    +                        -21.6461554847044155, 210.0992760736354512 
    +                        -24.1062788576290039, 209.3212067909635721 
    +                        -26.5882617801216163, 210.2192163964995473 
    +                        -29.1708247809513495, 210.7328651668775876 
    +                        -31.8146583584688898, 210.8366440393211292 
    +                        -34.5240364830890556, 207.8981201575437865 
    +                        -37.1820074567976775, 208.4575193189786546 
    +                        -40.1005881182147590, 208.1640541101386361 
    +                        -43.1055322081764345, 207.7543072120501790 
    +                        -46.2586675543238570, 207.5314322096498643 
    +                        -49.2705498078119462, 206.7582955548065229 
    +                        -52.1936818866474255, 205.6192136018880490 
    +                        -54.7714148223784818, 205.4996167427121918 
    +                        -57.4727506257466345, 204.9971140635101960 
    +                        -60.0578811129010504, 203.2383821704212892 
    +                        -62.2679172921601563, 200.9300200165560284 
    +                        -64.4465030350149277, 199.8971714572124938 
    +                        -66.5763329778213091, 200.1258931627585582 
    +                        -68.8361711620767949, 199.2972511439178618 
    +                        -70.7805855358500509, 196.7792310173380201 
    +                        -72.5300352734659555, 194.4112185232692127 
    +                        -73.9561392970242792, 191.4374565775498809 
    +                        -73.6523681610309922, 188.2995100761490619 
    +                        -75.8654125285016363, 178.4906870778024199 
    +                        -77.0852300681489879, 176.5050970206753789 
    +                        -79.7808076095631549, 165.0757843694741496 
    +                        -81.0881608166793910, 152.4799804246200949 
    +                        -82.5308661672881669, 133.8681496681806493 
    +                        -81.5827311403438955, 131.8894853390425226 
    +                        -80.2140463705767246, 130.4765643322060669 
    +                        -67.9452677585599929, 130.2747604739123801 
    +                        -61.6120592839047703, 130.1922255563363535 
    +                        -56.7166648646946001, 130.1524766479689106 
    +                        -52.5703445634040207, 130.1336952263669104 
    +                        -48.8998968692273337, 130.1270042469504915 
    +                        -45.5637564899186245, 130.1280543588046328 
    +                        -42.4773145391421494, 130.1344515306429059 
    +                        -39.5851913980574466, 130.1447687819669454 
    +                        -36.8487550883130979, 130.1581055369937303 
    +                        -34.2397441886732210, 130.1738691835533643 
    +                        -31.7367005547381460, 130.1916578156440494 
    +                        -29.3228321892930808, 130.2111932749780863 
    +                        -26.9846618961309481, 130.2322809933899919 
    +                        -24.7111344971717593, 130.2547849487542067 
    +                        -22.4930050180680006, 130.2786115605614725 
    +                        -20.3224060723840729, 130.3036990978958727 
    +                        -18.1925334154776763, 130.3300106175650228 
    +                        -16.0974116238781058, 130.3575292469539306 
    +                        -14.0317153685153944, 130.3862550843450379 
    +                        -11.9906299772648701, 130.4162032634127115 
    +                        -9.9697401421569314, 130.4474028990480292 
    +                        -7.9649389431856257, 130.4798967426170293 
    +                        -5.9723515331285055, 130.5137414512137468 
    +                        -3.9882692673801907, 130.5490084324652855 
    +                        -2.0090910168198790, 130.5857852735746576 
    +                        -0.0312690207646566, 130.6241778074674187 
    +                        1.9487429878277542, 130.6294254340024850 
    +                        2.2131023206611959)))"
    +  End_Object
    +End_Object
    +End
    +
    + +

    + Output values that are not a range are calculated at the center of the + image. The SubSpacecraftLatitude and + SubSpacecraftLongitude make up the subspacecraft point, which is + the point on a body which lies directly beneath the spacecraft. The + SubSolarLatitude and SubSolarLongitude make up the subsolar + point, which is the point on a body's reference surface where a line from + the body center to the sun center intersects that surface. The + NorthAzimuth, SpacecraftAzimuth and SubSolarAzimuth are the + values of the angle between a line from the image center to the relative + point (North pole, SubSpacecraftLatitude/Longitude, SubSolar + Latitude/Longitude respectively) and a reference line in the image plane. + The reference line is a horizontal line from the image center to the + middle right edge of the image. The angles increase in a clockwise + direction. The LocalTime is the time at the current longitude + relative to the subsolar longitude, which has a time of 12 o'clock. The + SolarLongitude is LSubS, or the seasonal angle. +

    +
    + + + + Original version + + + Added an application test + + + Fixed WKT calls + + + Remove ToWKT calls and PolygonTools.h inclusion. The geos package now + has a method to return a WKT string, so the ToWKT method has been + removed from the PolygonTools class. + + + Made the following modifications: fixed typo in PercentNull and + MaximumLongitude keywords; use the base file name for generation of + temporary files to further ensure uniqueness; run camstats once if + there is only one band - doubles execution speed for single band + images when CAMSTATS option is used; substitute the NULL string for + all special pixel values; added corner pixel keywords for PDS + compatibility; added phase, emission, incidence angles + and line and sample pixel resolution at the center pixel; added test + for intersection of longitude domain, north and south poles and + keywords that report them; added option to output ISIS cube labels; + corrected computations for parallax and shadow keywords. + + + Renamed the HasLongitudeDomain keyword to HasLongitudeBoundary. + Makes more sense. + + + Corrected method call to compute polygon with proper parameters as + well as correct band number. Added code to better honor specific + cube attributes (such as band numbers) in computations. Also will + produce NULL valued keywords where NULLs are a produced instead of + the real value for the ISIS NULL pixel value. + + + Removed references to CubeInfo + + + Added Camera Test option to test for a valid camera at center of image + and return an error and end if a valid camera cannot be created. + + + Reworked the output PVL format; added more keywords to the Common object + that indicate versions and dates; added more values to Geometry and + Polygon object. + + + Corrected generation of polygon for multi-band data. It created a + POLYGON union instead of the required MULTIPOLYGON. + + + The target center distance and subspacecraft latitude were not properly + propagated to the output PVL file and consequently were invalid. This + has been corrected. + + + Added RightAscension, Declination, SubSolarGroundAzimuth, and + SubSpacecraftGroundAzimuth computations; added center line/sample image + coordinate used to compute center geometry; added check of valid image + line/sample coordinates when testing for north/south poles (some camera + models return valid states when coordinates are outside of image + boundaries). + + + Modified to actually exclude the unconditional computation of the image + polygon to assist in some geometry values. It is no longer computed if + the user does not select the POLYGON option. The implications of this + are that some of the keywords in the output Geometry group are no + longer ever relevant. These keywords were all moved to the Polygon + group. These keywords are: CentroidLine, CentroidSample, + CentroidLatitude, CentroidLongitude, CentroidRadius and SurfaceArea. + User will no longer see these values if the POLYGON option is not + selected. Also the Radius keyword in the Polygon group has been + removed as it is redundant with CentroidRadius. + + + Added PIXINC parameter to allow user to specify number of pixels to + skip around the perimiter of the image to compute the polygon. + + + Fixed bug where image was a 0 longitude boundary crosser. It would + typically fail when determining centroid information unless converted + to 180 domain. This will also be used at the poles as it seems to work + better in the 180 domain as well. (This process projects the footprint + to a Sinusoidal projection to determine area which requires an equal + area projection, such as Sinusoidal.) + + + Added the MAXEMISSION and MAXINCIDENCE limit parameters to better + control limb and terminator polygon generation. + + + Allow disabling of shape model use when constructing polygons that + contain limbs. + + + Removed polygon options group and placed the options within output + options. Added inclusion for parameters related to polygons to only be + available when polygons are selected. Made TO option not have a + default of None, updated documentation and modified formatting. + + + + + Cameras + + + + + + cube + input + + Filename of a cube + + + Input cube with appropriate camera labels (Instrument and kernel groups). This file must be in raw + camera space, which is a "level 1" cube. + + + *.cub *.CUB + + + + filename + output + + Output PVL filename + + + A text file in label format (PVL) which will contain the results of this program. This file can + be used in conjunction with the "getkey" program in order to pass the results to another + program when developing scripts. + + + *.txt *.pvl + + + + + + + boolean + + Include Geometry Information + + + Get geometry information from the camera at the center of the image. + These data are contained in the Geometry Object. The keyword/values + contained there are: + +
      +
    • BandsUsed
    • +
    • ReferenceBand
    • +
    • OriginalBand
    • +
    • Target
    • +
    • StartTime
    • +
    • EndTime
    • +
    • CenterLine
    • +
    • CenterSample
    • +
    • CenterLatitude
    • +
    • CenterLongitude
    • +
    • CenterRadius
    • +
    • RightAscension
    • +
    • Declination
    • +
    • UpperLeftLongitude
    • +
    • UpperLeftLatitude
    • +
    • LowerLeftLongitude
    • +
    • LowerLeftLatitude
    • +
    • LowerRightLongitude
    • +
    • LowerRightLatitude
    • +
    • UpperRightLongitude
    • +
    • UpperRightLatitude
    • +
    • PhaseAngle
    • +
    • EmissionAngle
    • +
    • IncidenceAngle
    • +
    • NorthAzimuth
    • +
    • OffNadir
    • +
    • SolarLongitude
    • +
    • LocalTime
    • +
    • TargetCenterDistance
    • +
    • SlantDistance
    • +
    • SampleResolution
    • +
    • LineResolution
    • +
    • PixelResolution
    • +
    • MeanGroundResolution
    • +
    • SubSolarAzimuth
    • +
    • SubSolarGroundAzimuth
    • +
    • SubSolarLatitude
    • +
    • SubSolarLongitude
    • +
    • SubSpacecraftAzimuth
    • +
    • SubSpacecraftGroundAzimuth
    • +
    • SubSpacecraftLatitude
    • +
    • SubSpacecraftLongitude
    • +
    • ParallaxX
    • +
    • ParallaxY
    • +
    • ShadowX
    • +
    • ShadowY
    • +
    • HasLongitudeBoundary
    • +
    • HasNorthPole
    • +
    • HasSouthPole
    • +
    + +
    + TRUE +
    + + + + boolean + + Include ISIS Label + + + This option will extract the ISIS label and write it to the output PVL + file. + + FALSE + + + + boolean + + Include the Original Label + + + Include the original labels of the cube in the PVL. + + FALSE + + + + boolean + + Gather DN Statistics. + + + Get DN statistics for all band within the cube. These data are + contained in the Statistics object. The keyword/values contained + therein are: +
      +
    • MeanValue
    • +
    • StandardDeviationi
    • +
    • MinimumValue
    • +
    • MaximumValue
    • +
    • PercentHIS
    • +
    • PercentHRS
    • +
    • PercentLIS
    • +
    • PrecentLRS
    • +
    • PercentNull
    • +
    • TotalPixels
    • +
    +
    + FALSE +
    + + + boolean + + Get Camera Statistics Information + + + Run camstats to get camera information that can be expressed as a range. + Camstats will run on the entire cube (common object), and then for each band(bandset object). + The default linc and sinc for camstats will is "1", the user can select a different linc and sinc. + Output values are: +
      +
    • MinimumLatitude
    • +
    • MaximumLatitude
    • +
    • MinimumLongitude
    • +
    • MaximumLongitude
    • +
    • MinimumResolution
    • +
    • MaximumResolution
    • +
    • MinimumPhase
    • +
    • MaximumPhase
    • +
    • MinimumEmission
    • +
    • MaximumEmission
    • +
    • MinimumIncidence
    • +
    • MaximumIncidence
    • +
    • MinimumLocalTime
    • +
    • MaximumLocalTime
    • +
    +
    + + SINC + LINC + + FALSE +
    + + + integer + + LINC for camstats + + + This is the line increment used by camstats. + + 1 + + + + integer + + SINC for camstats + + + This is the sample increment used by camstats. + + 1 + + + + boolean + FALSE + + Create polygon information + + + Use the imagePolygon class to gather polygon information. The output + polygon will be in well known text format (WKT). These data are + contained within the Polygon object. The keyword/values contained + therein are: +
      +
    • CentroidLine
    • +
    • CentroidSample
    • +
    • CentroidLatitude
    • +
    • CentroidLongitude
    • +
    • CentroidRadius
    • +
    • SurfaceArea
    • +
    • GlobalCoverage
    • +
    • GisFootprint
    • +
    +
    + + PIXINC + MAXEMISSION + MAXINCIDENCE + +
    + + + integer + + Polygon pixel increment + + + Specifies the number of pixels skip around the perimeter of the image + to compute the polygon footprint. Note that currently, an increment + of 1 will not work for pushframe instruments such as THEMIS-VIS. A + default of 0 will cause caminfo to arbitrarily set it to 100. + + 0 + + + + double + + Maximum emission angle to include in polygon + + +

    + Specifies the maximum emission angle that a polygon point is + allowed to have. This limit is useful for eliminating limb data + that cause numerous ragged spikes. Limb data will generally + result in odd polygon footprints as the geometry becomes + unstable at the limb due to obliqueness particularly when using + a DEM for the shape model (see spiceinit). This parameter + restricts the emission angle to create better behaved polygons + at the limb while sacrificing some (very oblique) data. +

    +

    + Note the images spiceinit'ed with a DEM, the emission angle + may need to shorted. The DEM at the limb will also cause + additional spiking. +

    +

    + The default value assumes no DEM is associated with movie. +

    +
    + 89.5 +
    + + + double + + Maximum incidence angle to include in polygon + + + Specifies the maximum incidence angle that a polygon point is + allowed to have. This limit is useful for eliminating + terminator data that may will typically be lost in photometric + corrections. This parameter restricts the incidence angle to + create more data relevant polygons at the terminator while + sacrificing some (non-photometric) data. + + 120.0 + +
    + + + + boolean + FALSE + + Run spiceinit on the input + + + If the user sets this to true then the spiceinit program will be + run on the input file. Spiceinit will use the system SPICE kernels, + so any updates to SPICE information will be lost. Spiceinit is in + this program to facilitate UPC processing. + + + + + + + boolean + FALSE + + Test image center for valid camera + + + If the user sets this parameter to true, a test will determine if a + valid camera can be created at the center of the image band. if a + valid camera cannot be created the program will end. The default is + to not test the camera and output any available information. + + + +
    +
    diff --git a/isis/src/base/apps/caminfo/resources/changes.txt b/isis/src/base/apps/caminfo/resources/changes.txt new file mode 100644 index 0000000000000000000000000000000000000000..33fc65b5673630c83779252dd27cff3c35e4c354 --- /dev/null +++ b/isis/src/base/apps/caminfo/resources/changes.txt @@ -0,0 +1,211 @@ + caminfo Modifications + September 18, 2008 + + +The caminfo application used by the UPC has had some extensive changes made to +support cubes where the bands have dependent geometry. This means each band in +the cube has a different geometric footprint. THEMIS IR and VIS are but one +example where bands have different geometric characteristics. + +caminfo is perhaps the most critical application in the processing of UPC data. +It computes and/or stores of all data that eventually is populated in the UPC +database. This document describes the changes and alludes to the impact it may +have on others who have come to rely on caminfo for their processing needs. + +Structural Changes +The change with the most impact is a restructuring of the PVL Object and Group +structure of the resulting PVL output file. No longer is each band's +individual geometry included in the PVL. The "BandSet" object has been removed +from the PVL. All "Band" groups that report individual geometry +characteristics have been removed. In general, All Groups have been replaced +with objects that are named the same as the parameters in the user interface. + +The top level object was renamed from "Parameters" to "Caminfo", the name of +the application. The "Common" object has been renamed to "Parameters" and only +IsisId, From, Lines, Samples and Bands are contained therein. This is a big +change from the old structure as the top level Object was named "Parameters" +and the "Common" Object contained all other Pvl structures. This essentially +eliminates an entire level of object nesting. + +The "CubeCamStats" Group has been renamed to the "Camstats" Object and is +contained in the "Caminfo" top level object. + +The statistics keywords in each old "Band" Group have been consolidated into +the "Statistics" Object. This object is new and now includes all data in all +bands of the input cube. This differs from the old version in that it only was +generated for each band an no data was available for the whole file. One +casualty occured in that the "MedianValue" keyword is no longer calculated. +This required two passes and was not the true median of the cube when they are +in floating point format. Note that in order to get the true median of a +dataset, the entire dataset must stored and sorted in order and the exact +middle value will be the median. This is impractical for large files. + +The Group "Band" in the "BandSet" Object has been replaced with the "Geometry" +Object in the "Caminfo" top level object. The "BandSet" Object has been +removed entirely. Note that a "Band" Group was generated for each band in a +mult-band cube. Bands are no longer being treated this way. They are +consolidated as a union of all band dependent bands. This is discussed in +detail below. + +The geometry characteristics contained in each "Band" Group are now +consolidated for all bands and contained in the "Geometry" Object. The +Geometry Object is contained in the "Caminfo" top level object. This new +object is a union of the geometric characteristics for all band dependent data +or simply the first band for data that is band independent. + +Some additional keywords have been added to the new "Geometry" Object. Many +of the keywords that were in the "Band" Group are retained, however, they +should be deemed representative of the complete image cube geometry and not +just one band. They are: + +BandsUsed - reports the number of bands used to generate the data +ReferenceBand - This reports the logical band used to describe the geometry + excluding the corners latitude/longitude keywords. This + reference band is selected as the band whose center + latitude is closest to the Centroid latitude/longitude of + the combined polygon of all bands. +OriginalBand - The physical band of ReferenceBand. Many times they will + be one in the same. +Target - Name of the target observed. This may be necessary if no + label output option is selected. +CenterRadius - The "local" radius at the CenterLatitude/CenterLongitude + coordinate. This may be the radius of the spheroid or the + DEM if one is available. +CentroidLatitude - Latitude coordinate of the centroid of the polygon. This + is computed using the union polygon of all bands. +CentroidLongitude - Longitude coordinate of the centroid of the polygon. This + is computed using the union polygon of all bands. +CentroidLine - Reports the line coordinate in the image where the polygon + centroid point is located. +CentroidSample - Reports the sample coordinate in the image where the + polygon centroid point is located. +CentroidRadius - "Local" radius at the polygon centroid. This may differ + from the CenterRadius. +MeanGroundResolution - Average of the lowest and highest occuring image + resolution. + + +Band-by-Band Processing +The biggest change in caminfo is perhaps how each band is considered in the +gathering of cube and geometry statistics and the characterization of the cube +geometry and polygon footprint for the product. Note that as far as I am +concerned, a UPC product or database entry refers uniquely to a single file. +It is with this in mind that motivated the choices made in implementing the +current version of caminfo. + +For band independant image cubes, only the first band is used to generate the +"Geometry" object. For band dependent data, the following processes are +employed: + +1) Polygons for all data are generated regardless as to if the user requested +polygon information. Polygons are used to assist in the full Geometry +characterization. + +2) The polygons for each band are unioned into one final multipolygon that +characterizes the full geometric footprint for all bands in the cube. + +3) The centroid latitude and longitude point is calculated for each band +polygon. This point is converted to line and sample and the local radius at +that position is recorded. + +4) The centroid point for the combined union polygon of all bands is computed. + +5) The union centroid point is used to determine the four corner +latitude/longitude points in the following fashion: + a) Each bands geometry is saved storing information that is reported + in the Geometry object. + b) At each corner the distance from the polygon centroid point to the + corner latitude/longitude point is computed. + c) The point that is furthest from the centroid point is saved as the + corner point. + d) All four corners are computed this way. + +The "Polygon" Object contains the GisFootprint along wth some new information. +In additon to the Well Known Text (WKT) format of the GIS footprint, the +centroid latitude/longitude point of the union polygon is recorded. + +Also reported is the Radius computed according to the following procedure: + a) The average radius of the image center and polygon center are + computed independantly. + b) If the polygon radius is valid, it is the reported Radius. + c) Otherwise the center image point radius is returned if it is valid. + d) And finally, if neither of the above two radii are valid, the + radius from the average of the three radii reported in the SPICE + kernels is reported. + +New to the "Polygon" Object is the surface area of the full polygon in units of +square kilometers. The surface area of the polygon is computed by projecting +the full footprint polygon into a sinusoidal projection in global map X/Y +coordinates. These coordinates are in meters. Then I use the GEOS getArea() +function of the polygon to compute the area of the polygon. + +Once this is computed, the global surface area in square kilometers is computed +as: + 4.0 * PI * radius^2 / (1000.0*1000.0) + +Then the ratio of polygon area to global area is calculated and converted to a +percentage of global coverage. This may be very helpful in the query process +to eliminate wide angle images or select a range of images within a certain +area resolution. + +Note that it is simple to compute individual band Geometry to emulate much of +how the old version computed band dependent geometry individually. Simply use +the band selection command line option to select the desired band to compute. +In my opinion, this approach is easier to manage as the PVL format remains +identical and is easier to manipulate with other tools outside the ISIS +programming environment (such as getkey, etc...). + +Here is a small diagram comparing the structural differences of the old version +and new version of the PVL output file format: + +---- OLD FORMAT ---- ---- NEW FORMAT ---- +Object = Parameters Object = Caminfo + Object = Common Object = Parameters + Group = CubeCamStats EndObject + EndGroup Object = Camstats + EndObject EndObject + Object = IsisLabel Object = IsisLabel + EndObject EndObject + Object = OriginalLabel Object = OriginalLabel + EndObject EndObject + Object = BandSet Object = Statistics + Group = Band EndObject + Band =1 Object = Geometry + EndGroup EndObject + Group = Band Object = Polygon + Band = 2 EndObject + EndGroup EndObject + EndObject End +EndObject +End + + +Attached are some examples of old and new output. If you would like to see the +images used to calculate these examples, please come see me. + +If you have strong objections to these modifications, you should bring them to +my attention ASAP as I need to commit these changes to CVS and use it to +restart pipeline processing. + +Thanks... + + + + + + + + + + + + + + + + + + + + + diff --git a/isis/src/base/apps/caminfo/tsts/Makefile b/isis/src/base/apps/caminfo/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/caminfo/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/caminfo/tsts/boundary/Makefile b/isis/src/base/apps/caminfo/tsts/boundary/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..eb55e4726e7aae71a9586f06e4b11928895d7307 --- /dev/null +++ b/isis/src/base/apps/caminfo/tsts/boundary/Makefile @@ -0,0 +1,9 @@ +APPNAME = caminfo + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/f217s25.cub \ + TO=$(OUTPUT)/caminfo.pvl ISISLABEL=true ORIGINAL=true \ + STATISTICS=true CAMSTATS=true linc=25 sinc=25 \ + POLYGON=true pixinc=100 > /dev/null; diff --git a/isis/src/base/apps/caminfo/tsts/default/Makefile b/isis/src/base/apps/caminfo/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3bf9a37807a1a367f17950ca78b672e3a90ed1db --- /dev/null +++ b/isis/src/base/apps/caminfo/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = caminfo + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/input.cub \ + TO=$(OUTPUT)/caminfo.pvl ISISLABEL=true ORIGINAL=true \ + STATISTICS=true CAMSTATS=true POLYGON=true pixinc=100 > /dev/null; diff --git a/isis/src/base/apps/caminfo/tsts/pole/Makefile b/isis/src/base/apps/caminfo/tsts/pole/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1e2ad4b836155dca1da6fa7f2a3d418e72983aaf --- /dev/null +++ b/isis/src/base/apps/caminfo/tsts/pole/Makefile @@ -0,0 +1,9 @@ +APPNAME = caminfo + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/f167s71.cub \ + TO=$(OUTPUT)/caminfo.pvl ISISLABEL=true ORIGINAL=true \ + STATISTICS=true CAMSTATS=true linc=25 sinc=25 \ + POLYGON=true pixinc=100 > /dev/null; diff --git a/isis/src/base/apps/campt/Makefile b/isis/src/base/apps/campt/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/campt/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/campt/campt.cpp b/isis/src/base/apps/campt/campt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0ed78d165e2fc66b0a804e807cf41b7b3fd08be --- /dev/null +++ b/isis/src/base/apps/campt/campt.cpp @@ -0,0 +1,142 @@ +#include "Isis.h" + +#include +#include + +#include "Brick.h" +#include "Camera.h" +#include "CameraPointInfo.h" +#include "iException.h" +#include "iTime.h" +#include "Progress.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + bool outsideAllowed = ui.GetBoolean("ALLOWOUTSIDE"); + + // Set up CameraPointInfo and set file + CameraPointInfo campt; + campt.SetCube(ui.GetFilename("FROM") + "+" + ui.GetInputAttribute("FROM").BandsStr()); + + Progress prog; + prog.SetMaximumSteps(1); + + // Depending on what type is selected, set values accordingly + PvlGroup *point = NULL; + if (ui.GetString("TYPE") == "IMAGE") { + double sample = 0.0; + double line = 0.0; + if (ui.WasEntered("SAMPLE") && ui.WasEntered("LINE")) { + sample = ui.GetDouble("SAMPLE"); + line = ui.GetDouble("LINE"); + point = campt.SetImage(sample, line, outsideAllowed); + } + else { + if (ui.WasEntered("SAMPLE")) { + sample = ui.GetDouble("SAMPLE"); + point = campt.SetSample(sample, outsideAllowed); + } + else if (ui.WasEntered("LINE")) { + line = ui.GetDouble("LINE"); + point = campt.SetLine(line, outsideAllowed); + } + else { + point = campt.SetCenter(outsideAllowed); + } + } + } + else { + double lat = ui.GetDouble("LATITUDE"); + double lon = ui.GetDouble("LONGITUDE"); + point = campt.SetGround(lat,lon, outsideAllowed); + } + + prog.CheckStatus(); + + // Log it + Application::Log((*point)); + + if (ui.WasEntered("TO")) { + // Get user params from ui + string outFile = Filename(ui.GetFilename("TO")).Expanded(); + bool exists = Filename(outFile).Exists(); + bool append = ui.GetBoolean("APPEND"); + + // Write the pvl group out to the file + if (ui.GetString("FORMAT") == "PVL") { + Pvl temp; + temp.SetTerminator(""); + temp.AddGroup((*point)); + if (append) { + temp.Append(outFile); + } + else { + temp.Write(outFile); + } + } + + // Create a flatfile from PVL data + // The flatfile is comma delimited and can be imported into Excel + else { + ofstream os; + bool writeHeader = false; + if (append) { + os.open(outFile.c_str(),ios::app); + if (!exists) { + writeHeader = true; + } + } + else { + os.open(outFile.c_str(),ios::out); + writeHeader = true; + } + + if(writeHeader) { + for(int i = 0; i < (*point).Keywords(); i++) { + if((*point)[i].Size() == 3) { + os << (*point)[i].Name() << "X," + << (*point)[i].Name() << "Y," + << (*point)[i].Name() << "Z"; + } + else { + os << (*point)[i].Name(); + } + + if(i < point->Keywords()-1) { + os << ","; + } + } + os << endl; + } + + for(int i = 0; i < (*point).Keywords(); i++) { + if((*point)[i].Size() == 3) { + os << (string)(*point)[i][0] << "," + << (string)(*point)[i][1] << "," + << (string)(*point)[i][2]; + } + else { + os << (string)(*point)[i]; + } + + if(i < (*point).Keywords()-1) { + os << ","; + } + } + os << endl; + } + } + else { + if (ui.GetString("FORMAT") == "FLAT") { + string msg = "Flat file must have a name."; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_ ); + } + } + delete point; + point = NULL; + prog.CheckStatus(); +} diff --git a/isis/src/base/apps/campt/campt.xml b/isis/src/base/apps/campt/campt.xml new file mode 100644 index 0000000000000000000000000000000000000000..d9972bdd9caf498d1876748c3379553a67311951 --- /dev/null +++ b/isis/src/base/apps/campt/campt.xml @@ -0,0 +1,330 @@ + + + + + Outputs latitude/longitude at line/sample or reverse + + + + This program requires the user supply a "level 1" cube. That is, a + cube in raw camera geometry. + The user must also enter one of the following coordinates: +
    +      line/sample
    +      latitude/longitude
    +    
    + The program will then compute the other coordinates and various other + spacecraft and instrument related information including but not limited to + the north azimuth, solar azimuth, + spacecraft azimuth, incidence angle, phase angle, emission angle, and + resolution. The following is an example of the output given when campt is ran: +
    +Group = GroundPoint
    +  Filename                   = /usgs/cpkgs/isis3/data/mgs/testData/ab102401.cub
    +  Sample                     = 1.0
    +  Line                       = 1.0
    +  PixelValue                 = 0.0607816
    +  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>
    +  LineResolution             = 536.05556350077 <m>
    +
    +  # Spacecraft Information
    +  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
    +  SolarDistance              = 1.4234246174889 <AU>
    +  SubSolarLatitude           = -9.1071705738361
    +  SubSolarLongitude          = 147.50443340123
    +  SubSolarGroundAzimuth      = 254.69139701227
    +
    +  # Illumination and Other
    +  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
    +End_Group
    +    
    +

    + In the output, all positions are in body fixed coordinates. The + SubSpacecraftLatitude and SubSpacecraftLongitude + make up the subspacecraft point, which is the point on a body which + lies directly beneath the spacecraft. The SubSolarLatitude + and SubSolarLongitude make up the subsolar point, which + is the point on a body's refernce surface where a line from the body + center to the sun center intersects that surface. The + NorthAzimuth, SpacecraftAzimuth, and + SubSolarAzimuth are the values of the angle between a line + from the image center to the relative point (North pole, SubSpacecraft + Latitude/Longitude, SubSolar Latitude/Longitude respectively) and a + reference line in the image plane. The reference line is a horizontal + line from the image center to the middle right edge of the image. The + angles increase in a clockwise direction. The LocalSolarTime + is the time at the current longitude relative to the subsolar longitude, + which has a time of 12 o'clock. The SolarLongitude + is LSubS, or the seasonal angle. +

    +
    + + + Cameras + + + + + Original version + + + Fixed bug in Latitude range + + + Added appTest + + + Fixed appTest to comply to changes in String + + + Fixed appTest files to comply with changes to all camera models + + + Modified to output a flatfile as well as a pvl, make GUI consistent with skypt + + + Added additional output + + + Modified to use OffNadirAngle instead of SpacecraftRoll angle due to + changes made to the camera class + + + Added RightAscension and Declination to PVL output. Program now requires + user to specify a filename when using FLAT option. Increased precision in + flatfile output and updated appTest truthdata. + + + Added default values for the lines and samples + + + Removed references to CubeInfo + + + Removed unnecessary duplicate cube creation + + + Added SubSolarGroundAzimuth and SubSpacecraftGroundAzimuth + to PVL output. The SubSolarGroundAzimuth is the clockwise + angle on the ground between a line drawn from the ground + point to the North pole of the body and a line drawn from + the ground point to the subsolar point. The + SubSpacecraftGroundAzimuth is defined similarly except it + uses the subspacecraft point. + + + Added the ALLOWOUTSIDE option + + + Modified to use new class CameraPointInfo + + + Added missed functionality for defaulting to center sample/line + + + + + levpt + lev1pt + photostat + + + + + + cube + input + + Filename of a cube + + + Input cube with appropriate camera labels + (Instrument and kernel groups) + + + *.cub + + + + + filename + output + Text file + None + + A text file in label format which will contain + the results of this program. This file can + be used in conjunction with the "getkey" program + in order to pass the results to another program + when developing scripts. + + + + + string + + Output Format + + + Format type for output file. Pvl format is default. + + PVL + + + + + + + + boolean + + Append Output to File + + + If this option is selected, the output from the application will be appended to the file. + If it is not selected, any information in the TO file will be overwritten. + + TRUE + + + + + + string + Coordinate selection + IMAGE + + + + + + This parameter is used to select the type of coordinate which will be used to + compute the other two remaining coordinates. + + + + + double + + Sample position to report + + Center sample + + This is the sample position used to compute infomration about the camera state at the pixel. + + + + + double + + Line position to report + + Center line + + This is the line position used to compute infomration about the camera state at the pixel. + + + + + double + + Latitude position + + + This is the planetocentric latitude to try to find in the camera image + + -90.0 + 90.0 + + + + double + + Longitude position + + + This is the positive east longitude to try to find in the camera image + + 0.0 + 360.0 + + + + boolean + + Allow sample/line values outside the image + + + When this is checked, sample/line values that are outside of the image (but close) + will be extrapolated. For example, a sample of -0.5 would be valid. If this is not + checked, a sample of -0.5 is not allowed. + + true + + + +
    diff --git a/isis/src/base/apps/campt/tsts/Makefile b/isis/src/base/apps/campt/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/campt/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/campt/tsts/default/Makefile b/isis/src/base/apps/campt/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ced5b414fa46fb80f549129f95bd79b2cc308654 --- /dev/null +++ b/isis/src/base/apps/campt/tsts/default/Makefile @@ -0,0 +1,10 @@ +APPNAME = campt + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/output.txt $(OUTPUT)/camptTruth1.pvl + $(APPNAME) \ + from=$(INPUT)/ab102401.cub \ + to=$(OUTPUT)/camptTruth1.pvl \ + > /dev/null diff --git a/isis/src/base/apps/campt/tsts/flat/Makefile b/isis/src/base/apps/campt/tsts/flat/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3501cf7424cf2ef95eac953f5a533d4b028ff67a --- /dev/null +++ b/isis/src/base/apps/campt/tsts/flat/Makefile @@ -0,0 +1,13 @@ +APPNAME = campt + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/ab102401.cub \ + to=$(OUTPUT)/camptTruthTemp.txt \ + format=FLAT \ + type=ground \ + latitude=34.444196777709 \ + longitude=223.84999971295 > /dev/null; + cut -d , -f 2- $(OUTPUT)/camptTruthTemp.txt >& $(OUTPUT)/camptTruth2.txt; + rm $(OUTPUT)/camptTruthTemp.txt; diff --git a/isis/src/base/apps/campt/tsts/setSL/Makefile b/isis/src/base/apps/campt/tsts/setSL/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..51075d1461a4f209843518b8368df8568d548b54 --- /dev/null +++ b/isis/src/base/apps/campt/tsts/setSL/Makefile @@ -0,0 +1,10 @@ +APPNAME = campt + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.cub \ + to=$(OUTPUT)/output.pvl \ + sample=25 line=25 \ + append=false \ + > /dev/null; diff --git a/isis/src/base/apps/camrange/Makefile b/isis/src/base/apps/camrange/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/camrange/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/camrange/camrange.cpp b/isis/src/base/apps/camrange/camrange.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8336d66444974364f2d39a49b8c7f70c9ef4b2bd --- /dev/null +++ b/isis/src/base/apps/camrange/camrange.cpp @@ -0,0 +1,116 @@ +#include "Isis.h" +#include "Process.h" +#include "Camera.h" +#include "Pvl.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + Process p; + + // Set the input image, get the camera model, and a basic mapping + // group + Cube *icube = p.SetInputCube("FROM"); + Camera *cam = icube->Camera(); + Pvl mapping; + cam->BasicMapping(mapping); + PvlGroup &mapgrp = mapping.FindGroup("Mapping"); + + // Setup the output results by first adding the filename + UserInterface &ui = Application::GetUserInterface(); + + // Get the radii + double radii[3]; + cam->Radii(radii); + PvlGroup target("Target"); + target += PvlKeyword("From",ui.GetFilename("FROM")); + target += PvlKeyword("TargetName",cam->Target()); + target += PvlKeyword("RadiusA",radii[0]*1000.0,"meters"); + target += PvlKeyword("RadiusB",radii[1]*1000.0,"meters"); + target += PvlKeyword("RadiusC",radii[2]*1000.0,"meters"); + + // Get resolution + PvlGroup res("PixelResolution"); + double lowres = cam->LowestImageResolution(); + double hires = cam->HighestImageResolution(); + res += PvlKeyword("Lowest",lowres,"meters"); + res += PvlKeyword("Highest",hires,"meters"); + + // Get the universal ground range + PvlGroup ugr("UniversalGroundRange"); + double minlat,maxlat,minlon,maxlon; + cam->GroundRange(minlat,maxlat,minlon,maxlon,mapping); + ugr += PvlKeyword("LatitudeType","Planetocentric"); + ugr += PvlKeyword("LongitudeDirection","PositiveEast"); + ugr += PvlKeyword("LongitudeDomain",360); + ugr += PvlKeyword("MinimumLatitude",minlat); + ugr += PvlKeyword("MaximumLatitude",maxlat); + ugr += PvlKeyword("MinimumLongitude",minlon); + ugr += PvlKeyword("MaximumLongitude",maxlon); + + // Get the ographic latitude range + mapgrp.AddKeyword(PvlKeyword("LatitudeType","Planetographic"), + Pvl::Replace); + cam->GroundRange(minlat,maxlat,minlon,maxlon,mapping); + PvlGroup ogr("LatitudeRange"); + ogr += PvlKeyword("LatitudeType","Planetographic"); + ogr += PvlKeyword("MinimumLatitude",minlat); + ogr += PvlKeyword("MaximumLatitude",maxlat); + + // Get positive west longitude coordinates in 360 domain + mapgrp.AddKeyword(PvlKeyword("LongitudeDirection","PositiveWest"), + Pvl::Replace); + cam->GroundRange(minlat,maxlat,minlon,maxlon,mapping); + PvlGroup pos360("PositiveWest360"); + pos360 += PvlKeyword("LongitudeDirection","PositiveWest"); + pos360 += PvlKeyword("LongitudeDomain",360); + pos360 += PvlKeyword("MinimumLongitude",minlon); + pos360 += PvlKeyword("MaximumLongitude",maxlon); + + // Get positive east longitude coordinates in 180 domain + mapgrp.AddKeyword(PvlKeyword("LongitudeDirection","PositiveEast"), + Pvl::Replace); + mapgrp.AddKeyword(PvlKeyword("LongitudeDomain","180"), + Pvl::Replace); + cam->GroundRange(minlat,maxlat,minlon,maxlon,mapping); + PvlGroup pos180("PositiveEast180"); + pos180 += PvlKeyword("LongitudeDirection","PositiveEast"); + pos180 += PvlKeyword("LongitudeDomain",180); + pos180 += PvlKeyword("MinimumLongitude",minlon); + pos180 += PvlKeyword("MaximumLongitude",maxlon); + + // Get positive west longitude coordinates in 180 domain + mapgrp.AddKeyword(PvlKeyword("LongitudeDirection","PositiveWest"), + Pvl::Replace); + cam->GroundRange(minlat,maxlat,minlon,maxlon,mapping); + PvlGroup neg180("PositiveWest180"); + neg180 += PvlKeyword("LongitudeDirection","PositiveWest"); + neg180 += PvlKeyword("LongitudeDomain",180); + neg180 += PvlKeyword("MinimumLongitude",minlon); + neg180 += PvlKeyword("MaximumLongitude",maxlon); + + // Write it to the log + Application::Log(target); + Application::Log(res); + Application::Log(ugr); + Application::Log(ogr); + Application::Log(pos360); + Application::Log(pos180); + Application::Log(neg180); + + // Write the output file if requested + if (ui.WasEntered("TO")) { + Pvl temp; + temp.AddGroup(target); + temp.AddGroup(res); + temp.AddGroup(ugr); + temp.AddGroup(ogr); + temp.AddGroup(pos360); + temp.AddGroup(pos180); + temp.AddGroup(neg180); + temp.Write(ui.GetFilename("TO","txt")); + } + + p.EndProcess(); +} diff --git a/isis/src/base/apps/camrange/camrange.xml b/isis/src/base/apps/camrange/camrange.xml new file mode 100644 index 0000000000000000000000000000000000000000..1c37af562ba732b76f9f3f493b6f5a9c3ced22b6 --- /dev/null +++ b/isis/src/base/apps/camrange/camrange.xml @@ -0,0 +1,140 @@ + + + + + Compute the lat/lon range of a camera image + + + + This program computes and outputs the latitude/longitude range of + an image in camera space, as well as the pixel resolution. An + example of the output generated is: +
    +      Object = Results
    +        From = moc.cub
    +
    +        Group = Target
    +          TargetName = Mars
    +          RadiusA    = 3396190.0 <meters>
    +          RadiusB    = 3396190.0 <meters>
    +          RadiusC    = 3376200.0 <meters>
    +        EndGroup
    +
    +        Group = PixelResolution
    +          Lowest  = 1.3890716392389 <meters>
    +          Highest = 1.3890519075556 <meters>
    +        EndGroup
    +
    +        Group = UniversalGroundRange
    +          LatitudeType       = Planetocentric
    +          LongitudeDirection = PositiveEast
    +          LongitudeDomain    = 360
    +          MinimumLatitude    = -79.61917144991
    +          MaximumLatitude    = -79.553447654676
    +          MinimumLongitude   = 123.79357963013
    +          MaximumLongitude   = 124.14022828935
    +        EndGroup
    +
    +        Group = LatitudeRange
    +          LatitudeType    = Planetographic
    +          MinimumLatitude = -79.73841136553
    +          MaximumLatitude = -79.673409432806
    +        EndGroup
    +
    +        Group = LongitudeRange1
    +          LongitudeDirection = PositiveWest
    +          LongitudeDomain    = 360
    +          MinimumLongitude   = 235.85977171065
    +          MaximumLongitude   = 236.20642036987
    +        EndGroup
    +
    +        Group = LongitudeRange2
    +          LongitudeDirection = PositiveEast
    +          LongitudeDomain    = 180
    +          MinimumLongitude   = 123.79357963013
    +          MaximumLongitude   = 124.14022828935
    +        EndGroup
    +
    +        Group = LongitudeRange3
    +          LongitudeDirection = PositiveWest
    +          LongitudeDomain    = 180
    +          MinimumLongitude   = -124.14022828935
    +          MaximumLongitude   = -123.79357963013
    +        EndGroup
    +      EndObject
    +
    +
    + + + Cameras + + + + + Original version + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Added edge option and modified to handle multi-band cubes. + + + Modified filename parameters to be cube parameters where necessary + + + Changed default extension handling mechanism + + + Modified to output various flavors of ground range (e.g. Planetocentric, + Planetographic, positive east, positive west, etc). + + + Modified appTest input image (image testData area was moved) + + + Modified appTest truth files, ranges changed in linescan cameras due to + a bug fix + + + Updated appTest + + + Updated appTest truth files (change due to modifications to all camera models) + + + Removed references to CubeInfo + + + + + + + cube + input + + Input cube to compute range + + + Use this parameter to select the filename of a cube with + camera labels. + + + *.cub + + + + + filename + output + None + + Output label + + + This file will contain the ground range of the cube + + + + +
    diff --git a/isis/src/base/apps/camrange/tsts/Makefile b/isis/src/base/apps/camrange/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/camrange/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/camrange/tsts/case01/Makefile b/isis/src/base/apps/camrange/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e259c83f01f3a495586baf5cda95e05337ba47bb --- /dev/null +++ b/isis/src/base/apps/camrange/tsts/case01/Makefile @@ -0,0 +1,9 @@ +APPNAME = camrange + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/ab102401.cub \ + to=$(OUTPUT)/camrangeTruth1.txt > /dev/null; + $(MV) $(OUTPUT)/camrangeTruth1.txt \ + $(OUTPUT)/camrangeTruth1.pvl > /dev/null; diff --git a/isis/src/base/apps/camrange/tsts/case02/Makefile b/isis/src/base/apps/camrange/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d16b500014e2b91cd8234fa8ee2eed9fe631029 --- /dev/null +++ b/isis/src/base/apps/camrange/tsts/case02/Makefile @@ -0,0 +1,9 @@ +APPNAME = camrange + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/ab102402.cub \ + to=$(OUTPUT)/camrangeTruth2.txt > /dev/null; + $(MV) $(OUTPUT)/camrangeTruth2.txt \ + $(OUTPUT)/camrangeTruth2.pvl > /dev/null; diff --git a/isis/src/base/apps/camstats/Makefile b/isis/src/base/apps/camstats/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/camstats/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/camstats/camstats.cpp b/isis/src/base/apps/camstats/camstats.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fdfbc21f8a0d757a1cfbe9a00193ca274d56dc7d --- /dev/null +++ b/isis/src/base/apps/camstats/camstats.cpp @@ -0,0 +1,432 @@ +#include "Isis.h" +#include "Statistics.h" +#include "Camera.h" +#include "UserInterface.h" +#include "Cube.h" +#include "Progress.h" +#include "Process.h" + +#include "iString.h" + +using namespace std; +using namespace Isis; + +//function to build stats data +void buildStats (Camera *cam, int &sample, int &line); +void writeFlat (ofstream &os, Statistics &s); + +/** Produces NULL values for special pixels + * + * @param keyname Name of keyword to generate + * @param value Value to write to keyword + * @param unit Optional units for keywords + * + * @return PvlKeyword Newly created keyword + */ +static inline PvlKeyword ValidateKey(const std::string keyname, const double + &value, const std::string &unit = "") { + if (IsSpecial(value)) { + return (PvlKeyword(keyname, "NULL")); + } + else { + return (PvlKeyword(keyname,value,unit)); + } +} + + +//global stats opjects that will be used by function +Statistics latStat; +Statistics lonStat; +Statistics resStat; +Statistics sampleResStat; +Statistics lineResStat; +Statistics aspectRatioStat; +Statistics phaseStat; +Statistics emissionStat; +Statistics incidenceStat; +Statistics localSolarTimeStat; +Statistics localRaduisStat; +Statistics northAzimuthStat; + +void IsisMain(){ + + Process p; + + // Reset all the stats objects because they are global + latStat.Reset(); + lonStat.Reset(); + resStat.Reset(); + sampleResStat.Reset(); + lineResStat.Reset(); + aspectRatioStat.Reset(); + phaseStat.Reset(); + emissionStat.Reset(); + incidenceStat.Reset(); + localSolarTimeStat.Reset(); + localRaduisStat.Reset(); + northAzimuthStat.Reset(); + + UserInterface &ui = Application::GetUserInterface(); + + Cube *icube = p.SetInputCube("FROM"); + Camera *cam = icube->Camera(); + +// Cube cube; +// cube.Open(ui.GetFilename("FROM")); +// Camera *cam = cube.Camera(); + + int eband = cam->Bands(); + // if the camera is band independent that only run one band + if (cam->IsBandIndependent()) eband = 1; + int linc = ui.GetInteger("LINC"); + int sinc = ui.GetInteger("SINC"); + + int pTotal = eband * ((cam->Lines()-2) / linc + 2) ; + Progress progress; + progress.SetMaximumSteps(pTotal); + progress.CheckStatus(); + + for (int band=1; band<=eband; band++) { + cam->SetBand(band); + for (int line=1; line<(int)cam->Lines(); line=line+linc) { + for (int sample=1; sample< cam->Samples(); sample=sample+sinc) { + buildStats(cam, sample, line); + } + //set the sample value to the last sample and run buildstats + int sample = cam->Samples(); + buildStats(cam, sample, line); + progress.CheckStatus(); + } + //set the line value to the last line and run on all samples(sample + sinc) + int line = cam->Lines(); + for (int sample=1; sample< cam->Samples(); sample=sample+sinc) { + buildStats(cam, sample, line); + } + //set last sample and run with last line + int sample = cam->Samples(); + buildStats(cam, sample, line); + progress.CheckStatus(); + } + + //Set up the Pvl groups and get min, max, avg, and sd for each statstics object + PvlGroup pUser("User Parameters"); + pUser += PvlKeyword("Filename",ui.GetFilename("FROM")); + pUser += PvlKeyword("Linc",ui.GetInteger("LINC")); + pUser += PvlKeyword("Sinc",ui.GetInteger("SINC")); + + PvlGroup pLat("Latitude"); + pLat += ValidateKey("LatitudeMinimum",latStat.Minimum()); + pLat += ValidateKey("LatitudeMaximum",latStat.Maximum()); + pLat += ValidateKey("LatitudeAverage",latStat.Average()); + pLat += ValidateKey("LatitudeStandardDeviation",latStat.StandardDeviation()); + + PvlGroup pLon("Longitude"); + pLon += ValidateKey("LongitudeMinimum",lonStat.Minimum()); + pLon += ValidateKey("LongitudeMaximum",lonStat.Maximum()); + pLon += ValidateKey("LongitudeAverage",lonStat.Average()); + pLon += ValidateKey("LongitudeStandardDeviation",lonStat.StandardDeviation()); + + PvlGroup pSampleRes("SampleResolution"); + pSampleRes += ValidateKey("SampleResolutionMinimum",sampleResStat.Minimum(), + "meters/pixel"); + pSampleRes += ValidateKey("SampleResolutionMaximum",sampleResStat.Maximum(), + "meters/pixel"); + pSampleRes += ValidateKey("SampleResolutionAverage",sampleResStat.Average(), + "meters/pixel"); + pSampleRes += ValidateKey("SampleResolutionStandardDeviation", + sampleResStat.StandardDeviation(),"meters/pixel"); + + PvlGroup pLineRes("LineResolution"); + pLineRes += ValidateKey("LineResolutionMinimum",lineResStat.Minimum(), + "meters/pixel"); + pLineRes += ValidateKey("LineResolutionMaximum",lineResStat.Maximum(), + "meters/pixel"); + pLineRes += ValidateKey("LineResolutionAverage",lineResStat.Average(), + "meters/pixel"); + pLineRes += ValidateKey("LineResolutionStandardDeviation", + lineResStat.StandardDeviation(),"meters/pixel"); + + PvlGroup pResolution("Resolution"); + pResolution += ValidateKey("ResolutionMinimum",resStat.Minimum(), + "meters/pixel"); + pResolution += ValidateKey("ResolutionMaximum",resStat.Maximum(), + "meters/pixel"); + pResolution += ValidateKey("ResolutionAverage",resStat.Average(), + "meters/pixel"); + pResolution += ValidateKey("ResolutionStandardDeviation", + resStat.StandardDeviation(),"meters/pixel"); + + PvlGroup pAspectRatio("AspectRatio"); + pAspectRatio += ValidateKey("AspectRatioMinimum",aspectRatioStat.Minimum()); + pAspectRatio += ValidateKey("AspectRatioMaximun",aspectRatioStat.Maximum()); + pAspectRatio += ValidateKey("AspectRatioAverage",aspectRatioStat.Average()); + pAspectRatio += ValidateKey("AspectRatioStandardDeviation", + aspectRatioStat.StandardDeviation()); + + PvlGroup pPhase("PhaseAngle"); + pPhase += ValidateKey("PhaseMinimum",phaseStat.Minimum()); + pPhase += ValidateKey("PhaseMaximum",phaseStat.Maximum()); + pPhase += ValidateKey("PhaseAverage",phaseStat.Average()); + pPhase += ValidateKey("PhaseStandardDeviation",phaseStat.StandardDeviation()); + + PvlGroup pEmission("EmissionAngle"); + pEmission += ValidateKey("EmissionMinimum",emissionStat.Minimum()); + pEmission += ValidateKey("EmissionMaximum",emissionStat.Maximum()); + pEmission += ValidateKey("EmissionAverage",emissionStat.Average()); + pEmission += ValidateKey("EmissionStandardDeviation", + emissionStat.StandardDeviation()); + + PvlGroup pIncidence("IncidenceAngle"); + pIncidence += ValidateKey("IncidenceMinimum",incidenceStat.Minimum()); + pIncidence += ValidateKey("IncidenceMaximum",incidenceStat.Maximum()); + pIncidence += ValidateKey("IncidenceAverage",incidenceStat.Average()); + pIncidence += ValidateKey("IncidenceStandardDeviation", + incidenceStat.StandardDeviation()); + + PvlGroup pTime("LocalSolarTime"); + pTime += ValidateKey("LocalSolarTimeMinimum",localSolarTimeStat.Minimum(), + "hours"); + pTime += ValidateKey("LocalSolarTimeMaximum",localSolarTimeStat.Maximum(), + "hours"); + pTime += ValidateKey("LocalSolarTimeAverage",localSolarTimeStat.Average(), + "hours"); + pTime += ValidateKey("LocalSolarTimeStandardDeviation", + localSolarTimeStat.StandardDeviation(),"hours"); + + PvlGroup pLocalRadius("LocalRadius"); + pLocalRadius += ValidateKey("LocalRadiusMinimum",localRaduisStat.Minimum()); + pLocalRadius += ValidateKey("LocalRadiusMaximum",localRaduisStat.Maximum()); + pLocalRadius += ValidateKey("LocalRadiusAverage",localRaduisStat.Average()); + pLocalRadius += ValidateKey("LocalRadiusStandardDeviation", + localRaduisStat.StandardDeviation()); + + PvlGroup pNorthAzimuth("NorthAzimuth"); + pNorthAzimuth += ValidateKey("NorthAzimuthMinimum",northAzimuthStat.Minimum()); + pNorthAzimuth += ValidateKey("NorthAzimuthMaximum",northAzimuthStat.Maximum()); + pNorthAzimuth += ValidateKey("NorthAzimuthAverage",northAzimuthStat.Average()); + pNorthAzimuth += ValidateKey("NorthAzimuthStandardDeviation", + northAzimuthStat.StandardDeviation()); + + // Send the Output to the log area + Application::Log(pUser); + Application::Log(pLat); + Application::Log(pLon); + Application::Log(pSampleRes); + Application::Log(pLineRes); + Application::Log(pResolution); + Application::Log(pAspectRatio); + Application::Log(pPhase); + Application::Log(pEmission); + Application::Log(pIncidence); + Application::Log(pTime); + Application::Log(pLocalRadius); + Application::Log(pNorthAzimuth); + + if (ui.WasEntered("TO")) { + string from = ui.GetFilename("FROM"); + string outfile = Filename(ui.GetFilename("TO")).Expanded(); + bool exists = Filename(outfile).Exists(); + bool append = ui.GetBoolean("APPEND"); + + //If the user chooses a fromat of PVL then write to the output file ("TO") + if (ui.GetString("FORMAT") == "PVL") { + Pvl temp; + temp.SetTerminator(""); + temp.AddGroup(pUser); + temp.AddGroup(pLat); + temp.AddGroup(pLon); + temp.AddGroup(pSampleRes); + temp.AddGroup(pLineRes); + temp.AddGroup(pResolution); + temp.AddGroup(pAspectRatio); + temp.AddGroup(pPhase); + temp.AddGroup(pEmission); + temp.AddGroup(pIncidence); + temp.AddGroup(pTime); + temp.AddGroup(pLocalRadius); + temp.AddGroup(pNorthAzimuth); + + if (append) { + temp.Append(outfile); + } + else { + temp.Write(outfile); + } + } + + //Create a flatfile of the data with columhn headings + // the flatfile is comma delimited and can be imported in to spreadsheets + else { + ofstream os; + bool writeHeader = true; + if (append) { + os.open(outfile.c_str(),ios::app); + if (exists) { + writeHeader = false; + } + } + else { + os.open(outfile.c_str(),ios::out); + } + + // if new file or append and no file exists then write header + if(writeHeader){ + os << "Filename,"<< + "LatitudeMinimum,"<< + "LatitudeMaximum,"<< + "LatitudeAverage,"<< + "LatitudeStandardDeviation,"<< + "LongitudeMinimum,"<< + "LongitudeMaximum,"<< + "LongitudeAverage,"<< + "LongitudeStandardDeviation,"<< + "SampleResolutionMinimum,"<< + "SampleResolutionMaximum,"<< + "SampleResolutionAverage,"<< + "SampleResolutionStandardDeviation,"<< + "LineResolutionMinimum,"<< + "LineResolutionMaximum,"<< + "LineResolutionAverage,"<< + "LineResolutionStandardDeviation,"<< + "ResolutionMinimum,"<< + "ResolutionMaximum,"<< + "ResolutionAverage,"<< + "ResolutionStandardDeviation,"<< + "AspectRatioMinimum,"<< + "AspectRatioMaximum,"<< + "AspectRatioAverage,"<< + "AspectRatioStandardDeviation,"<< + "PhaseMinimum,"<< + "PhaseMaximum,"<< + "PhaseAverage,"<< + "PhaseStandardDeviation,"<< + "EmissionMinimum,"<< + "EmissionMaximum,"<< + "EmissionAverage,"<< + "EmissionStandardDeviation,"<< + "IncidenceMinimum,"<< + "IncidenceMaximum,"<< + "IncidenceAverage,"<< + "IncidenceStandardDeviation,"<< + "LocalSolarTimeMinimum,"<< + "LocalSolarTimeMaximum,"<< + "LocalSolarTimeAverage,"<< + "LocalSolarTimeStandardDeviation,"<< + "LocalRadiusMaximum,"<< + "LocalRadiusMaximum,"<< + "LocalRadiusAverage,"<< + "LocalRadiusStandardDeviation,"<< + "NorthAzimuthMinimum,"<< + "NorthAzimuthMaximum,"<< + "NorthAzimuthAverage,"<< + "NorthAzimuthStandardDeviation,"< grps; + grps.push_back( pLat ); + grps.push_back( pLon ); + grps.push_back( pSampleRes ); + grps.push_back( pLineRes ); + grps.push_back( pResolution ); + grps.push_back( pAspectRatio ); + grps.push_back( pPhase ); + grps.push_back( pEmission ); + grps.push_back( pIncidence ); + grps.push_back( pTime ); + grps.push_back( pLocalRadius ); + grps.push_back( pNorthAzimuth ); + + for( vector::iterator g = grps.begin(); g != grps.end(); g++ ) { + int i = 0; + record[i++] = g->Name(); + record[i++] = (double) (*g)[0][0]; + record[i++] = (double) (*g)[1][0]; + record[i++] = (double) (*g)[2][0]; + record[i++] = (double) (*g)[3][0]; + table += record; + } + + icube->ReOpen( "rw" ); + icube->Write( table ); + p.WriteHistory(*icube); + icube->Close(); + + } + +} + +//function to add stats data to the stats object. +//also tests if the line and samp are valid +void buildStats (Camera *cam, int &sample, int &line){ + cam->SetImage(sample, line); + if (cam->HasSurfaceIntersection()) { + latStat.AddData(cam->UniversalLatitude()); + lonStat.AddData(cam->UniversalLongitude()); + resStat.AddData(cam->PixelResolution()); + sampleResStat.AddData(cam->SampleResolution()); + lineResStat.AddData(cam->LineResolution()); + phaseStat.AddData(cam->PhaseAngle()); + emissionStat.AddData(cam->EmissionAngle()); + incidenceStat.AddData(cam->IncidenceAngle()); + localSolarTimeStat.AddData(cam->LocalSolarTime()); + localRaduisStat.AddData(cam->LocalRadius()); + northAzimuthStat.AddData(cam->NorthAzimuth()); + + double Aratio = cam->LineResolution() / cam->SampleResolution(); + aspectRatioStat.AddData(Aratio); + } +} + +static inline string ValidateValue(const double &value) { + if ( IsSpecial(value) ) { + return (string("NULL")); + } + else { + return ((string) iString(value)); + } +} + +//function to write the stats values to flat file +void writeFlat (ofstream &os, Statistics &s){ + os << ValidateValue(s.Minimum())<<","<< + ValidateValue(s.Maximum())<<","<< + ValidateValue(s.Average())<<","<< + ValidateValue(s.StandardDeviation())<<","; +} diff --git a/isis/src/base/apps/camstats/camstats.xml b/isis/src/base/apps/camstats/camstats.xml new file mode 100644 index 0000000000000000000000000000000000000000..72f5706117a8d298f2933355e6f85245c4d6a12c --- /dev/null +++ b/isis/src/base/apps/camstats/camstats.xml @@ -0,0 +1,176 @@ + + + + + + Outputs camera statistics for a cube in raw camera geometry + + + + This program will generate camera statistics from a user supplied "level 1" cube. The output of camstats can be directed + to a PVL file or flat text file. For each output group, the program will calculate the minimum, maximum, average, and standard + deviation. The output groups are: +
    +      Latitude
    +      Longitude
    +      Sample Resolution
    +      Line Resolution
    +      Resolution
    +      Aspect Ratio
    +      Phase Angle
    +      Emission Angle
    +      Incidence Angle
    +      Local Solar Time
    +      North Azimuth
    +    
    + The output values are calculated using the full image area. However, the number of data collection + points for the statistics can be controlled by using the line increment (linc) and sample increment (sinc) + parameters. If the default linc and sinc of one are used then every line and sample of the image is + used in the calculation of the output values. If the user enters a linc or sinc, then the number of data + collection points will be reduced. However, the edges of the image area always used even if they an + incrament does not fall on the edge. + +
    + + + + Original version + + + Added an application test + + + Check for special pixel values and write them as NULL values in keywords + and the flat text file. + + + Removed references to CubeInfo + + + Added the ATTACH option + + + Camstats now outputs history to the cube when it finishes execution + + + + + Cameras + + + + + + cube + input + + Input file + + + Input cube with appropriate camera labels (instrument and kernel groups) + + + *.cub *.CUB + + + + boolean + + Attach result to the cube in the Table "CameraStatistics" + + + If this option is selected, the output camera statistics will be + attached as the Table "CameraStatistics" in the FROM cube's labels. + Note: This does alter the input cube. + + FALSE + + + + filename + output + + Text file output + + None + + A text file in label format which will contain the results of this program. this file can be used + in conjunction with the "getkey" program in order to pass the results to another program + when developing scripts. The output can also be a flat text file, see the "FORMAT" parameter. + + + *.txt *.TXT + + + + + string + + Output Format + + + Format type for output file. PVL format is the default. + + PVL + + + + + + + + boolean + + Append Output to File + + + If this option is selected, the output from the application will be appended to the "TO" file. if it is not + selected, and information in the "TO" file will be overwritten. + + FALSE + + + + + + + integer + + Line increment + + + Will contol the number of lines where statistical data is collected. if a LINC of 10 is entered, every tenth line + will be used in the data collection. + + 1 + + + + integer + + Sample increment + + + Will contol the number of samples where statistical data is collected. if a SINC of 10 is entered, every tenth sample + will be used in the data collection. + + 1 + + + +
    + diff --git a/isis/src/base/apps/camstats/tsts/Makefile b/isis/src/base/apps/camstats/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/camstats/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/camstats/tsts/default/Makefile b/isis/src/base/apps/camstats/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2943d9690c7084b30684fb56768f495282d2188a --- /dev/null +++ b/isis/src/base/apps/camstats/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = camstats + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/input.cub TO=$(OUTPUT)/output.pvl > /dev/null; + $(CP) $(INPUT)/input.cub $(OUTPUT)/attached.cub; + $(APPNAME) FROM=$(OUTPUT)/attached.cub ATTACH=true > /dev/null; diff --git a/isis/src/base/apps/camtrim/Makefile b/isis/src/base/apps/camtrim/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/camtrim/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/camtrim/camtrim.cpp b/isis/src/base/apps/camtrim/camtrim.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58fe72c7fb5291058ec6751a578ef179bb956c2a --- /dev/null +++ b/isis/src/base/apps/camtrim/camtrim.cpp @@ -0,0 +1,98 @@ +#include "Isis.h" +#include "Camera.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "ProjectionFactory.h" + +using namespace std; +using namespace Isis; + +// Global variables +Cube *icube; +Camera *cam; +Projection *proj; +double minlat; +double maxlat; +double minlon; +double maxlon; +int lastBand; + +void camtrim (Buffer &in, Buffer &out); + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and get the camera model + icube = p.SetInputCube("FROM"); + cam = icube->Camera(); + + // Create the output cube + p.SetOutputCube ("TO"); + + // Get the lat/lon range to trim + UserInterface &ui = Application::GetUserInterface(); + minlat = ui.GetDouble("MINLAT"); + maxlat = ui.GetDouble("MAXLAT"); + minlon = ui.GetDouble("MINLON"); + maxlon = ui.GetDouble("MAXLON"); + + // Get map projection to determine what type of + // lat/lons the user wants + if (ui.WasEntered("MAP")) { + Pvl lab; + lab.Read(ui.GetFilename("MAP")); + proj = ProjectionFactory::Create(lab); + + // add mapping to print.prt + PvlGroup mapping = proj->Mapping(); + Application::Log(mapping); + } + else { + proj = NULL; + } + + // Start the processing + lastBand = 0; + p.StartProcess(camtrim); + p.EndProcess(); +} + +// Line processing routine +void camtrim (Buffer &in, Buffer &out) { + // See if there is a change in band which would change the camera model + if (in.Band() != lastBand) { + lastBand = in.Band(); + cam->SetBand(icube->PhysicalBand(lastBand)); + } + + // Loop for each pixel in the line. + double samp,lat,lon; + double line = in.Line(); + for (int i=0; iSetImage(samp,line); + if (cam->HasSurfaceIntersection()) { + lat = cam->UniversalLatitude(); + lon = cam->UniversalLongitude(); + if (proj != NULL) { + proj->SetUniversalGround(lat,lon); + lat = proj->Latitude(); + lon = proj->Longitude(); + } + // Pixel is outside range + if ((lat < minlat) || (lat > maxlat) || + (lon < minlon) || (lon > maxlon)) { + out[i] = NULL8; + } + // Pixel inside range + else { + out[i] = in[i]; + } + } + // Trim outerspace + else { + out[i] = NULL8; + } + } +} diff --git a/isis/src/base/apps/camtrim/camtrim.xml b/isis/src/base/apps/camtrim/camtrim.xml new file mode 100644 index 0000000000000000000000000000000000000000..f69e30fb729ea8f4d5298bfd1e59f838d740393f --- /dev/null +++ b/isis/src/base/apps/camtrim/camtrim.xml @@ -0,0 +1,156 @@ + + + + + + Trims pixels outside of lat/lon range + + + + This program trims pixels outside of a user specified + latitude/longitude range. It is meant to work specifically on + camera based cubes. By default, the range is in Planetocentric + latitudes and 0 to 360 positive east longitudes. This can be + overridden using a map projection file. + + + + + Original version + + + Added program to the Cameras category + + + Fixed bug in the Xml file + + + Fixed problem with projection manager prematurely + destroying projection object + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Added dependent multi-band capabilities + + + Modified filename parameters to be cube parameters where necessary + + + Added appTest + + + Depricated CubeProjection and ProjectionManager to ProjectionFactory + + + Removed references to CubeInfo + + + Mapping group parameters are now placed into the print file. + + + + + Trim and Mask + Cameras + + + + + + cube + input + + Input cube to trim + + + Use this parameter to select the filename. All bands within the file + will be trimmed. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the circle trim. + + + + + filename + None + input + + Map projection label file + + + If a file is not given then this program will assume the + user is entering planetocentric latitude and positive east, + 0 to 360 longitudes. Otherwise the labels (LatitudeType, + LongitudeDomain, LongitudeDirection) in the map file + determine the user preferences. + + + + + + + double + Minimum Latitude + + Pixels which have a latitude less than this value will be + trimmed. + + -90 + 90 + + + + double + Maximum Latitude + + Pixels which have a latitude greater than this value will be + trimmed. + + -90 + 90 + + MINLAT + + + + + double + Minimum Longitude + + Pixels which have a longitude less than this value will be + trimmed. + + -360 + 360 + + + + double + Maximum Longitude + + Pixels which have a longitude less than this value will be + trimmed. + + -360 + 360 + + MINLON + + + + + diff --git a/isis/src/base/apps/camtrim/tsts/Makefile b/isis/src/base/apps/camtrim/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/camtrim/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/camtrim/tsts/case01/Makefile b/isis/src/base/apps/camtrim/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..24dcad90cf03bd04a60b1bbccfde5b94ac11b374 --- /dev/null +++ b/isis/src/base/apps/camtrim/tsts/case01/Makefile @@ -0,0 +1,11 @@ +APPNAME = camtrim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.cub \ + to=$(OUTPUT)/camtrimTruth1.cub \ + minlat=-90 \ + maxlat=90 \ + minlon=-360 \ + maxlon=360 > /dev/null; diff --git a/isis/src/base/apps/camtrim/tsts/case02/Makefile b/isis/src/base/apps/camtrim/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b8dcd9b115040e6ae9bcda9f304cbde44dc60b6b --- /dev/null +++ b/isis/src/base/apps/camtrim/tsts/case02/Makefile @@ -0,0 +1,11 @@ +APPNAME = camtrim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.cub \ + to=$(OUTPUT)/camtrimTruth2.cub \ + minlat=-45 \ + maxlat=45 \ + minlon=-180 \ + maxlon=180 > /dev/null; diff --git a/isis/src/base/apps/cathist/Makefile b/isis/src/base/apps/cathist/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cathist/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cathist/cathist.cpp b/isis/src/base/apps/cathist/cathist.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d63b344f7a02ebf0ce7056d6de2b2c86c70ffc6a --- /dev/null +++ b/isis/src/base/apps/cathist/cathist.cpp @@ -0,0 +1,55 @@ +#include "Isis.h" + +#include + +#include "Pvl.h" +#include "History.h" +#include "iString.h" + +using namespace Isis; +using namespace std; + +void IsisMain(){ + + // Get user entered file name & mode + UserInterface &ui = Application::GetUserInterface(); + string file = ui.GetFilename("FROM"); + string mode = ui.GetString("MODE"); + + // Extract history from file + History hist("IsisCube", file); + Pvl pvl = hist.ReturnHist(); + + // Print full history + if(mode=="FULL"){ + if (ui.IsInteractive()) { + Application::GuiLog(pvl); + } + else { + cout << pvl << endl; + } + } + + // Print brief history in command line form + else if(mode=="BRIEF"){ + for(int i=0; i + + + + Outputs the history of a cube + + + + This program will output the full or brief history of a .cub file. The brief mode + is especially useful for creating a script for a batch job, because the output is in the + command line format. + + + Utility + + + + + catlab + + + + + labels + + + + + Original version + + + Documentation fixes + + + Modified to output results in gui log if the gui is open + + + + + + + cube + input + + Input file the history is needed from + + + The cube file the history is to be extracted from. + + + *.cub + + + + + + string + Mode types + + Different modes that cathist can run in. + + FULL + + + + + + + + + + + Full printout of a .cub history + + This example shows the cathist application in the full mode. + This is the default mode. +
     
    +Object = mirror
    +  IsisVersion       = "3.0.2 beta | 2004-11-17"
    +  ProgramVersion    = 2003-07-29
    +  ExecutionDateTime = 2005-01-10T13:33:12
    +  HostName          = orkin
    +  UserName          = eribelin
    +  Description       = "Flip a cube from left-to-right"
    +
    +  Group = UserParameters
    +    FROM = peaks.cub
    +    TO   = temp.cub
    +  End_Group
    +End_Object
    +
    +Object = circle
    +  IsisVersion       = "3.0.2 beta | 2004-11-17"
    +  ProgramVersion    = 2003-07-29
    +  ExecutionDateTime = 2005-01-10T13:50:46
    +  HostName          = orkin
    +  UserName          = eribelin
    +  Description       = "Trims data outside of a circle"
    +
    +  Group = UserParameters
    +    FROM = temp.cub
    +    TO   = temp2.cub
    +  End_Group
    +End_Object
    +End
    +         
    +
    + + from=temp2.cub + + + Run the cathist application on a .cub file. + + +
    + + Brief printout of a .cub history + + This example shows the cathist application in the brief mode. +
    +mirror from=peaks.cub to=temp.cub
    +circle from=temp.cub to=temp2.cub
    +            
    +
    + + from=temp2.cub mode=brief + + + Run the cahist application on a .cub file in brief mode. + + +
    +
    + +
    diff --git a/isis/src/base/apps/cathist/tsts/Makefile b/isis/src/base/apps/cathist/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cathist/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cathist/tsts/modeBrief/Makefile b/isis/src/base/apps/cathist/tsts/modeBrief/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f98752c3276d06e213391673882636b99a9ccd57 --- /dev/null +++ b/isis/src/base/apps/cathist/tsts/modeBrief/Makefile @@ -0,0 +1,7 @@ +APPNAME = cathist + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + mode=brief > $(OUTPUT)/standardOutTruth2.txt; diff --git a/isis/src/base/apps/cathist/tsts/modeFull/Makefile b/isis/src/base/apps/cathist/tsts/modeFull/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..904cb770aefebe4150f455f9a2c948b88f2fe2d4 --- /dev/null +++ b/isis/src/base/apps/cathist/tsts/modeFull/Makefile @@ -0,0 +1,7 @@ +APPNAME = cathist + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + mode=full > $(OUTPUT)/standardOutTruth1.txt; diff --git a/isis/src/base/apps/catlab/Makefile b/isis/src/base/apps/catlab/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/catlab/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/catlab/catlab.cpp b/isis/src/base/apps/catlab/catlab.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18b742a79d76a91c2cce4d5431d44f60a4880e5f --- /dev/null +++ b/isis/src/base/apps/catlab/catlab.cpp @@ -0,0 +1,37 @@ +#include "Isis.h" + +#include + +#include "Pvl.h" + +using namespace Isis; +using namespace std; + + +void IsisMain() { + + // Get filename provided by the user + UserInterface &ui = Application::GetUserInterface(); + string file = ui.GetFilename("FROM"); + + // Extract label from file + Pvl label(file); + + // Output to file if entered + if(ui.WasEntered("TO")) { + label.Write( ui.GetFilename("TO") ); + } + + // Print label to the gui log if it is interactive + else if (ui.IsInteractive()) { + Application::GuiLog(label); + } + + // Print label to the screen if it is not + else { + cout << label << endl; + } + +} + + diff --git a/isis/src/base/apps/catlab/catlab.xml b/isis/src/base/apps/catlab/catlab.xml new file mode 100644 index 0000000000000000000000000000000000000000..46bc3ce716b3a9b1f8a2341a8d49830dcbeb711f --- /dev/null +++ b/isis/src/base/apps/catlab/catlab.xml @@ -0,0 +1,199 @@ + + + + + Outputs the label from a cube + + + + This program will output the labels from an Isis cube or its detached label + file. If it is run in gui mode, the label will be written to the gui log + screen. Otherwise, it will be written to the terminal window. + Note: This program is designed to output Isis cube + labels. However, it will work on many files with pds like labels. + + + + Utility + + + + + cathist + editlab + + + + + labels + + + + + Original version + + + Modified to output label to gui if it is in interactive mode + + + Documentation fixes + + + Added TO parameter + + + Added more filters for FROM and TO. Updated documentation. + + + + + + + cube + input + + Input cube + + + This is the input cube file from which the labels will be extracted. + + + *.cub *.lbl + + + + filename + output + + Optional output file. + + + No Output file will be created + + + The text file to which the result Pvl will be written. + + + *.txt *.prt *.pvl + + + + + + + + Default example + + This is an example of catlab with no output file. + + + + from=peaks.cub + + + In this example, catlab will extract the labels from the input + cube and output them to the terminal window: +
    +Object = IsisCube
    +  Object = Core
    +    /* Location of the core
    +    StartByte   = 65537
    +    Format      = Tile
    +    TileSamples = 128
    +    TileLines   = 128
    +
    +    Group = Dimensions
    +      Samples = 1024
    +      Lines   = 1024
    +      Bands   = 7
    +    End_Group
    +
    +    Group = Pixels
    +      Type       = Real
    +      ByteOrder  = LSB
    +      Base       = 0.0
    +      Multiplier = 1.0
    +    End_Group
    +  End_Object
    +
    +  Group = Bogus
    +    Key = Wow
    +  End_Group
    +End_Object
    +
    +Object = Label
    +  Bytes = 65536
    +End_Object
    +
    +Object = History
    +  Name = IsisCube 
    +  StartByte = 29425665 
    +  Bytes = 1048 
    +End_Object
    +End
    +        
    +
    +
    + + + + + Example using GUI + + + In this example, catlab will extract the labels from the input + cube and output them to the GUI log screeen. + + + + + +
    + + Example with output file created + + This is an example of catlab with an output file. + + + + from=peaks.cub to=peaks.pvl + + + In this example, catlab will extract the labels from the input + cube and output them to a pvl file. + + + + + + + Example using GUI + + + In this example, catlab will extract the labels from the input + cube and output them to a pvl file. They will not print in the + GUI log screeen. + + + + + + + + + Output pvl created by catlab. + + + In this example, the label is printed in a pvl file. This pvl is + identical to the terminal interface or GUI log screen + outputs in Example 1. + + + TO + + + + +
    + +
    diff --git a/isis/src/base/apps/catlab/tsts/Makefile b/isis/src/base/apps/catlab/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/catlab/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/catlab/tsts/case01/Makefile b/isis/src/base/apps/catlab/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..579b76ce2e0376e5d078271f7dda5ec7ba4a4d17 --- /dev/null +++ b/isis/src/base/apps/catlab/tsts/case01/Makefile @@ -0,0 +1,6 @@ +APPNAME = catlab + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 > $(OUTPUT)/standardOutTruth1.txt; diff --git a/isis/src/base/apps/catlab/tsts/case02/Makefile b/isis/src/base/apps/catlab/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..399c1c46c264c7cda2772d4a70d30863f4ff3a24 --- /dev/null +++ b/isis/src/base/apps/catlab/tsts/case02/Makefile @@ -0,0 +1,6 @@ +APPNAME = catlab + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 TO=$(OUTPUT)/standardOutTruth2.txt; diff --git a/isis/src/base/apps/catoriglab/Makefile b/isis/src/base/apps/catoriglab/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/catoriglab/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/catoriglab/catoriglab.cpp b/isis/src/base/apps/catoriglab/catoriglab.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f3355bb6befea0a58107363273ab3798a0fc64e --- /dev/null +++ b/isis/src/base/apps/catoriglab/catoriglab.cpp @@ -0,0 +1,18 @@ +#include "Isis.h" +#include "Pvl.h" +#include "OriginalLabel.h" + +using namespace Isis; +using namespace std; + +void IsisMain() { + + // Get user entered file name & mode + UserInterface &ui = Application::GetUserInterface(); + string file = ui.GetFilename("FROM"); + + // Extract history from file + OriginalLabel origLab(file); + Pvl pvl = origLab.ReturnLabels(); + cout << pvl << endl; +} diff --git a/isis/src/base/apps/catoriglab/catoriglab.xml b/isis/src/base/apps/catoriglab/catoriglab.xml new file mode 100644 index 0000000000000000000000000000000000000000..d571e6606e1f02d574c516ff30211044db201b93 --- /dev/null +++ b/isis/src/base/apps/catoriglab/catoriglab.xml @@ -0,0 +1,87 @@ + + + + + Outputs the original labels of a cube + + + + This program will output the full labels from the original source. + + + Utility + + + + + cathist + catlab + + + + + + Original version + + + Documentation fixes + + + + + + + cube + input + + Input file from which to extract the labels + + + The cube file from which to extract the original labels. + + + *.cub + + + + + + + + Full printout of the original labels in a cub + + This example shows how the catoriglab application works. + There are no defaults. +
     
    +PDS_VERSION_ID                = PDS3
    +
    +/* FILE DATA ELEMENTS */
    +RECORD_TYPE                   = FIXED_LENGTH
    +RECORD_BYTES                  = 2048
    +FILE_RECORDS                  = 1042
    +LABEL_RECORDS                 = 11
    +
    +/* POINTERS TO DATA OBJECTS */
    +^IMAGE_HEADER                 = 12
    +^IMAGE                        = 19
    +
    +/* IDENTIFICATION DATA ELEMENTS */
    +DATA_SET_ID                   = MER1-M-MI-2-EDR-OPS-V1.0
    +DATA_SET_NAME                 = "MER 1 MARS MICROSCOPIC IMAGER 
    +                                 CAMERA ED OPS VERSION 1.0"
    +       .
    +       .
    +       .
    +         
    +
    + + from=temp.cub + + + Run the catoriglab application on a .cub file. + + +
    +
    + +
    diff --git a/isis/src/base/apps/catoriglab/tsts/Makefile b/isis/src/base/apps/catoriglab/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/catoriglab/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/catoriglab/tsts/case01/Makefile b/isis/src/base/apps/catoriglab/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0c7c45c122178af2464208fb889f158798c7d00e --- /dev/null +++ b/isis/src/base/apps/catoriglab/tsts/case01/Makefile @@ -0,0 +1,8 @@ +APPNAME = catoriglab + +include $(ISISROOT)/make/isismake.tsts + +commands: + mer2isis from=$(INPUT)/test.IMG \ + to= $(OUTPUT)/mer1.cub > /dev/null; + $(APPNAME) from= $(OUTPUT)/mer1.cub > $(OUTPUT)/standardOutTruth1.pvl; diff --git a/isis/src/base/apps/catoriglab/tsts/case02/Makefile b/isis/src/base/apps/catoriglab/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..95acbf2392f742b89e385a961f706e94d4143f90 --- /dev/null +++ b/isis/src/base/apps/catoriglab/tsts/case02/Makefile @@ -0,0 +1,8 @@ +APPNAME = catoriglab + +include $(ISISROOT)/make/isismake.tsts + +commands: + mer2isis from=$(INPUT)/test2.IMG \ + to= $(OUTPUT)/mer2.cub > /dev/null; + $(APPNAME) from= $(OUTPUT)/mer2.cub > $(OUTPUT)/standardOutTruth2.pvl; diff --git a/isis/src/base/apps/circle/Makefile b/isis/src/base/apps/circle/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/circle/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/circle/assets/circle1_out.jpg b/isis/src/base/apps/circle/assets/circle1_out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a6f08635d7312fb52f6eee6330d677148bd5dbb9 Binary files /dev/null and b/isis/src/base/apps/circle/assets/circle1_out.jpg differ diff --git a/isis/src/base/apps/circle/assets/circle1_out_s.jpg b/isis/src/base/apps/circle/assets/circle1_out_s.jpg new file mode 100644 index 0000000000000000000000000000000000000000..467440b67e1afd3fcf54e472d7d9a23930f63ab5 Binary files /dev/null and b/isis/src/base/apps/circle/assets/circle1_out_s.jpg differ diff --git a/isis/src/base/apps/circle/assets/circle2_out.jpg b/isis/src/base/apps/circle/assets/circle2_out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..370252678ec5ada48cae22a2078ebfa3d13a0727 Binary files /dev/null and b/isis/src/base/apps/circle/assets/circle2_out.jpg differ diff --git a/isis/src/base/apps/circle/assets/circle2_out_s.jpg b/isis/src/base/apps/circle/assets/circle2_out_s.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d6b4b72577c26bfc5936868a83e4db61af9d7760 Binary files /dev/null and b/isis/src/base/apps/circle/assets/circle2_out_s.jpg differ diff --git a/isis/src/base/apps/circle/assets/circle_in.jpg b/isis/src/base/apps/circle/assets/circle_in.jpg new file mode 100644 index 0000000000000000000000000000000000000000..55b3005d5e05141df90b0afc4b4e517f9ad4c610 Binary files /dev/null and b/isis/src/base/apps/circle/assets/circle_in.jpg differ diff --git a/isis/src/base/apps/circle/assets/circle_in_s.jpg b/isis/src/base/apps/circle/assets/circle_in_s.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b362c8009ec0135a389a1388f56fbb317a761429 Binary files /dev/null and b/isis/src/base/apps/circle/assets/circle_in_s.jpg differ diff --git a/isis/src/base/apps/circle/assets/circle_out.jpg b/isis/src/base/apps/circle/assets/circle_out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0147072c0835ebfb314b450e559ed5f807532ea7 Binary files /dev/null and b/isis/src/base/apps/circle/assets/circle_out.jpg differ diff --git a/isis/src/base/apps/circle/assets/circle_out_s.jpg b/isis/src/base/apps/circle/assets/circle_out_s.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ab9c62095fcea67ff9d038a943c21314d20b4d02 Binary files /dev/null and b/isis/src/base/apps/circle/assets/circle_out_s.jpg differ diff --git a/isis/src/base/apps/circle/assets/screen1.jpg b/isis/src/base/apps/circle/assets/screen1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a694e2f860f322761d974762335acba06d5068be Binary files /dev/null and b/isis/src/base/apps/circle/assets/screen1.jpg differ diff --git a/isis/src/base/apps/circle/assets/screen1_s.jpg b/isis/src/base/apps/circle/assets/screen1_s.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5f0a3451b0338d48f6a1f8f0a04892f5bb621bd0 Binary files /dev/null and b/isis/src/base/apps/circle/assets/screen1_s.jpg differ diff --git a/isis/src/base/apps/circle/assets/screen2.jpg b/isis/src/base/apps/circle/assets/screen2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ef68299db2f16cc6d4d9be1d3e471fb9470f0cb3 Binary files /dev/null and b/isis/src/base/apps/circle/assets/screen2.jpg differ diff --git a/isis/src/base/apps/circle/assets/screen2_s.jpg b/isis/src/base/apps/circle/assets/screen2_s.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1d6241fa8453a49bf8727a05e6555984db045ccd Binary files /dev/null and b/isis/src/base/apps/circle/assets/screen2_s.jpg differ diff --git a/isis/src/base/apps/circle/assets/screen3.jpg b/isis/src/base/apps/circle/assets/screen3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e1e51dafed8dd8bee6abfc47a8c0d23fd2d8c7f0 Binary files /dev/null and b/isis/src/base/apps/circle/assets/screen3.jpg differ diff --git a/isis/src/base/apps/circle/assets/screen3_s.jpg b/isis/src/base/apps/circle/assets/screen3_s.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a0d0b3780f1fe17c37a65669efa39f6964d02a7d Binary files /dev/null and b/isis/src/base/apps/circle/assets/screen3_s.jpg differ diff --git a/isis/src/base/apps/circle/assets/screenblank.jpg b/isis/src/base/apps/circle/assets/screenblank.jpg new file mode 100644 index 0000000000000000000000000000000000000000..884ae141dad470263b78da5c64101fc03e414c50 Binary files /dev/null and b/isis/src/base/apps/circle/assets/screenblank.jpg differ diff --git a/isis/src/base/apps/circle/circle.cpp b/isis/src/base/apps/circle/circle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d4f225bf79554e14dd5a55f715e25ebda6bcdd7 --- /dev/null +++ b/isis/src/base/apps/circle/circle.cpp @@ -0,0 +1,59 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void circle (Buffer &in, Buffer &out); +double cline,csamp,radius; // Global variables + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and output cubes + Cube *icube = p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + + // Compute the defaults for user parameters + cline = icube->Lines() / 2; + csamp = icube->Samples() / 2; + radius = (cline < csamp) ? cline : csamp; + + // Override the defaults if the user entered a value + UserInterface &ui = Application::GetUserInterface(); + if (ui.WasEntered ("LINE")) cline = ui.GetDouble ("LINE"); + if (ui.WasEntered ("SAMPLE")) csamp = ui.GetDouble ("SAMPLE"); + if (ui.WasEntered ("RADIUS")) radius = ui.GetDouble ("RADIUS"); + + // Start the processing + p.StartProcess(circle); + p.EndProcess(); +} + +// Line processing routine +void circle (Buffer &in, Buffer &out) { + // Compute part of the distance (doesn't vary since the line is constant) + double dist, partA, partB; + partA = cline - (double) in.Line(); + partA *= partA; + + // Loop for each pixel in the line. + for (int i=0; i + + + + + Trims data outside of a circle + + + + This program will trim (set to NULL) all pixels in an input cube + which fall outside of a user defined circle. That is, given a + sample/line coordinate and a radius, all pixels whose distance away + from the input sample/line is further than the radius will be set to NULL. + This program is useful for trimming global cubes collected by framing + cameras. A global cube is one in which the limb of the planet/target body + is visible and therefore the camera has taken a picture of space as well as + the planet. Using this program you can ensure the space pixels are NULL. + This can be done by determining the sub-spacecraft point in sample/line + coordinates and the radius of the body. Note that the sample/line position + does not have to be within the image in question. + + + + + Original version + + + + Ported to Isis 3.0 + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Removed references to CubeInfo + + + + + Trim and Mask + + + + + + cube + input + + Input cube to trim + + + Use this parameter to select the filename. All bands within the file + will be trimmed. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the circle trim. + + + + + + + double + + Middle sample + + Sample coordinate of circle + + This defines the sample coordinate at the center of the circle. + It can be negative or greater than the number of samples in the + cube. + + + + + double + + Middle line + + Line coordinate of circle + + This defines the line coordinate at the center of the circle. + It can be negative or greater than the number of lines in the + cube. + + + + + double + + Half the image size + + Radius of the circle + + This defines the radius of the circle. Pixels outside the radius + of the circle centered at (SAMPLE,LINE) will be trimmed. The default + value is the lesser of half the samples or half the lines. + + 1.0 + + + + + + + Taking all defaults + + This example shows the result of taking all the default + parameters on the application circle. + line and samp defaulted to the center of the image, and + radius defaulted to the minimum of nl/2.0 and ns/2.0 + + + from=circle_in to=circle1_out + line and sample default to the center of the image, radius defaults to the lesser one half of the number of lines or the number of samples + + + + Input image for circle + This is the input image for the default example of circle. + + FROM + + + + + + Output image for circle + + This is the output image for circle. Notice the NULL values in the corners of this image. + + + TO + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform the default circle operation + + + + + + + Small centered circle + This example shows the result of setting a smaller radius than the minimum of ns/2.0 and nl/2.0. The center of the circle defaults to the center of the image + + from=circle_in to=circle_out rad=150 + line and sample default to the center of the input image, with a radius of 150 pixels + + + + Input image for circle + Input image + + FROM + + + + + Circle radius smaller than image + Output image for circle radius = 150 on a 500 by 500 image + + TO + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform a circle operation with a radius of 150 + + + + + + + Off centered + + This example shows the result of circle when the radius center is placed + at the center of the upper right quadrant of the image. The radius is large + enough to include data not in the immage. + + + from=circle_in to=circle2_out line=125 samp=375 rad=200 + the center of the circle is line 125 and sample 375, with a radius of 200 + + + + + Input image for circle + This is the input image for the default example of circle. + + + FROM + + + + + + Output image off centered example of circle + + + This is the output image for circle. Notice the NULL values of this image. + + + TO + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform a circle operation with a radius of 200 and centered on line/sample 125/375 + + + + + + + diff --git a/isis/src/base/apps/circle/tsts/Makefile b/isis/src/base/apps/circle/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/circle/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/circle/tsts/default/Makefile b/isis/src/base/apps/circle/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..21a20a137414b7f525b02f93abd101db33a821a3 --- /dev/null +++ b/isis/src/base/apps/circle/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = circle + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/circleTruth1.cub > /dev/null; diff --git a/isis/src/base/apps/circle/tsts/params/Makefile b/isis/src/base/apps/circle/tsts/params/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..42619425446370fc5a87eb1cc4e6835bff03011e --- /dev/null +++ b/isis/src/base/apps/circle/tsts/params/Makefile @@ -0,0 +1,10 @@ +APPNAME = circle + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/circleTruth2.cub \ + sample=0 \ + line=80 \ + radius=60.5 > /dev/null; diff --git a/isis/src/base/apps/circle2/Makefile b/isis/src/base/apps/circle2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/circle2/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/circle2/circle2.cpp b/isis/src/base/apps/circle2/circle2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f40fbe3e6d0bfa241f89406ba504d5cb1ddaa667 --- /dev/null +++ b/isis/src/base/apps/circle2/circle2.cpp @@ -0,0 +1,78 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void circle (Buffer &in, Buffer &out); +double cline,csamp,radius; // Global variables + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + + // Get the three points along the edge of the circle + UserInterface &ui = Application::GetUserInterface(); + double y1 = ui.GetDouble ("LINE1"); + double y2 = ui.GetDouble ("LINE2"); + double y3 = ui.GetDouble ("LINE3"); + double x1 = ui.GetDouble ("SAMP1"); + double x2 = ui.GetDouble ("SAMP2"); + double x3 = ui.GetDouble ("SAMP3"); + + // Compute the center line/samp and radius of the circle + double x21 = x2 - x1; + double y21 = y2 - y1; + double x31 = x3 - x1; + double y31 = y3 - y1; + double den = 2.0 * (x21*y31 - x31*y21); + if (den == 0.0) { + string message = "The three points lie on a line so a circle can not be computed"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + + double sq2 = x21*x21 + y21*y21; + double sq3 = x31*x31 + y31*y31; + csamp = (sq2*y31 - sq3*y21) / den; + cline = (sq3*x21 - sq2*x31) / den; + + radius = sqrt(csamp*csamp + cline*cline); + csamp += x1; + cline += y1; + + // Start the processing + p.StartProcess(circle); + p.EndProcess(); +} + +// Line processing routine +void circle (Buffer &in, Buffer &out) { + // Compute part of the distance (doesn't vary since the line is constant) + double dist, partA, partB; + partA = cline - (double) in.Line(); + partA *= partA; + + // Loop for each pixel in the line. + for (int i=0; i + + + + + Trims data outside of a circle + + + + This program will trim (set to NULL) all pixels in an input cube + which fall outside of a user defined circle. This works differently + than the circle program. It expects the user to supply three points + on the edge of the circle and will automatically computer the center + of the circle and the radius. + + + + + Original version + + + Ported to Isis 3.0 + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Added modifications to apptest by Kim + + + Modified filename parameters to be cube parameters where necessary + + + + + Trim and Mask + + + + getcirc + + + + + + cube + input + + Input cube to trim + + + Use this parameter to select the filename. All bands within the file + will be trimmed. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the circle trim. + + + + + + + double + First sample coordinate on the circle + + This defines the sample coordinate of a point on the circle. + + + + + double + First line coordinate on the circle + + This defines the line coordinate of a point on the circle. + + + + + + double + Second sample coordinate on the circle + + This defines the sample coordinate of a point on the circle. + + + + + double + Second line coordinate on the circle + + This defines the line coordinate of a point on the circle. + + + + + double + Third sample coordinate on the circle + + This defines the sample coordinate of a point on the circle. + + + + + double + Third line coordinate on the circle + + This defines the line coordinate of a point on the circle. + + + + + diff --git a/isis/src/base/apps/circle2/tsts/Makefile b/isis/src/base/apps/circle2/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/circle2/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/circle2/tsts/case01/Makefile b/isis/src/base/apps/circle2/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..16d75efb438e7f1e6a64fda6807cc02de1298ac9 --- /dev/null +++ b/isis/src/base/apps/circle2/tsts/case01/Makefile @@ -0,0 +1,13 @@ +APPNAME = circle2 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/circle2Truth1.cub \ + samp1=12 \ + line1=1 \ + samp2=15 \ + line2=1 \ + samp3=1 \ + line3=10 > /dev/null; diff --git a/isis/src/base/apps/circle2/tsts/case02/Makefile b/isis/src/base/apps/circle2/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..98e6e0af295fc40c54d5ffdefbdd2721a44f7b0d --- /dev/null +++ b/isis/src/base/apps/circle2/tsts/case02/Makefile @@ -0,0 +1,14 @@ +APPNAME = circle2 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/circle2Truth2.cub \ + samp1=1 \ + line1=1 \ + samp2=126 \ + line2=63 \ + samp3=1 \ + line3=126 > /dev/null; + diff --git a/isis/src/base/apps/cnet2mat/Makefile b/isis/src/base/apps/cnet2mat/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cnet2mat/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cnet2mat/cnet2mat.cpp b/isis/src/base/apps/cnet2mat/cnet2mat.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf2ce93f70c4aec2664a21b23db7f35b58c4787f --- /dev/null +++ b/isis/src/base/apps/cnet2mat/cnet2mat.cpp @@ -0,0 +1,196 @@ +#include "Isis.h" + +#include +#include +#include + +#include "Pvl.h" +#include "TextFile.h" +#include "FileList.h" +#include "SerialNumberList.h" +#include "ControlNet.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + + std::map fscMap; + std::map snMap; + + UserInterface &ui = Application::GetUserInterface(); + + FileList list2(ui.GetFilename("LIST2")); + + SerialNumberList snl(ui.GetFilename("LIST3")); + for (unsigned int f=0; f(f,fsc)); + snMap.insert(std::pair(sn,f)); + } + + ControlNet cnet(ui.GetFilename("CONTROL")); + + int mpTotal = 0; + + for (int i=0; i + + + + Converts an Isis3 control network file to an ISIS2 match point file. + + + +

    + This program converts an Isis3 control network file to an ISIS2 match + point file. +

    +
    + + + Control Networks + Import and Export + + + + + Original version + + + Added ability to use ISIS2 keyword IMAGE_NUMBER. Fixed bug where the + diameter was being written as an Isis::Null when it had not been set. + + + Changed the default point class of 'U' to 'M' to prevent qmatch issues. + + + All Ignored Control Measures as well as all Control Measures inside + ignored Control Points will now have the Type Unmeasured. + + + + + + + filename + input + + List of ISIS3 input cubes in the match point file. + + + A text file containing one column of ISIS3 cube file names. Every file + used in the match point file should be represented in this list. The + cubes must be available for the program to open and must be in the + same order as the Isis2 cubes in LIST2 + + + *.lis + + + + + filename + input + + Isis3 output control network file + + + Use this parameter to specify the control network file containing + the information to be translated into ISIS2 format + + + *.ctl + + + + + + + filename + input + + List of ISIS2 input cubes in the match point file. + + + A text file containing one column of ISIS2 cube file names. Every file + used in the match point file should be represented in this list. The + cubes must be available for the program to open and must be in the + same order as the Isis3 cubes in LIST3 + + + *.lis + + + + + filename + output + + ISIS2 match point file + + + Use this parameter to specify the target location of the output + control network file + + + *.mat + + + + +
    diff --git a/isis/src/base/apps/cnet2mat/tsts/Makefile b/isis/src/base/apps/cnet2mat/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cnet2mat/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cnet2mat/tsts/case01/Makefile b/isis/src/base/apps/cnet2mat/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2484615a57f2252d54e3743f19318de41682818c --- /dev/null +++ b/isis/src/base/apps/cnet2mat/tsts/case01/Makefile @@ -0,0 +1,13 @@ +APPNAME = cnet2mat + +include $(ISISROOT)/make/isismake.tsts + +commands: + ls $(INPUT)/Isis2_cube*.cub >& $(OUTPUT)/cub2.lis; + ls $(INPUT)/Isis3_cube*.cub >& $(OUTPUT)/cub3.lis; + $(APPNAME) list3=$(OUTPUT)/cub3.lis \ + control=$(INPUT)/testNet.ctl \ + list2=$(OUTPUT)/cub2.lis \ + match=$(OUTPUT)/cnet2matTruth1.txt > /dev/null; + rm -f $(OUTPUT)/cub2.lis; + rm -f $(OUTPUT)/cub3.lis; diff --git a/isis/src/base/apps/cnetadd/Makefile b/isis/src/base/apps/cnetadd/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cnetadd/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cnetadd/cnetadd.cpp b/isis/src/base/apps/cnetadd/cnetadd.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39e4ee31112df515dbc55911f26ec561ff8ebeb7 --- /dev/null +++ b/isis/src/base/apps/cnetadd/cnetadd.cpp @@ -0,0 +1,299 @@ +#include "Isis.h" + +#include "UserInterface.h" +#include "FileList.h" +#include "Filename.h" +#include "Pvl.h" +#include "SerialNumber.h" +#include "SerialNumberList.h" +#include "CameraFactory.h" +#include "ControlNet.h" +#include "ControlPoint.h" +#include "ControlMeasure.h" +#include "iException.h" +#include "CubeManager.h" +#include "iTime.h" + +#include +#include + +using namespace std; +using namespace Isis; + +void SetControlPointLatLon( const std::string &incubes, const std::string &cnet ); + +std::map< std::string, std::pair > p_pointLatLon; +std::map< int, set > p_modifiedMeasures; + +void IsisMain() { + + UserInterface &ui = Application::GetUserInterface(); + + FileList list2 (ui.GetFilename("ADDLIST")); + bool hasDuplicateSerialNumbers = false; + + bool log = false; + Filename logFile; + if (ui.WasEntered("LOG")) { + log = true; + logFile = ui.GetFilename("LOG"); + } + Pvl results; + results.SetName("cnetadd_Results"); + PvlKeyword added ("FilesAdded"); + PvlKeyword omitted ("FilesOmitted"); + PvlKeyword pointsModified ("PointsModified"); + + string retrievalOpt = ui.GetString("RETRIEVAL"); + PvlKeyword duplicates ("DupSerialNumbers"); + if (retrievalOpt == "REFERENCE") { + FileList list1 (ui.GetFilename("FROMLIST")); + SerialNumberList addSerials (ui.GetFilename("ADDLIST")); + SerialNumberList fromSerials (ui.GetFilename("FROMLIST")); + + //Check for duplicate files in the lists by serial number + for (int i = 0; i < addSerials.Size(); i++) { + + // Check for duplicate SNs accross the lists + if (fromSerials.HasSerialNumber(addSerials.SerialNumber(i))) { + duplicates.AddValue(addSerials.Filename(i)); + } + + // Check for duplicate SNs within the addlist + for (int j = i+1; j < addSerials.Size(); j++) { + if (addSerials.SerialNumber(i) == addSerials.SerialNumber(j)) { + string msg = "Add list files [" + addSerials.Filename(i) + "] and ["; + msg += addSerials.Filename(j) + "] share the same serial number."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + } + + // If duplicates throw error + if (duplicates.Size() > 0) { + hasDuplicateSerialNumbers = true; + } + + SetControlPointLatLon( ui.GetFilename("FROMLIST"), ui.GetFilename("INNET") ); + + } + + Filename outNet(ui.GetFilename("OUTNET")); + + ControlNet inNet = ControlNet(ui.GetFilename("INNET")); + inNet.SetUserName( Isis::Application::UserName() ); + //inNet.SetCreatedDate( Isis::Application::DateTime() ); //This should be done in ControlNet's Write fn + inNet.SetModifiedDate( Isis::iTime::CurrentLocalTime() ); + + Progress progress; + progress.SetText("Adding Images"); + progress.SetMaximumSteps(list2.size()); + progress.CheckStatus(); + + // loop through all the images + vector modPoints; + for (unsigned int img = 0; img < list2.size(); img++) { + Pvl cubepvl; + bool imageAdded = false; + cubepvl.Read(list2[img]); + Camera *cam = CameraFactory::Create(cubepvl); + + //loop through all the control points + for (int cp = 0; cp < inNet.Size(); cp++) { + ControlPoint point( inNet[cp] ); + + double latitude; + double longitude; + if (retrievalOpt == "REFERENCE") { + // Get the lat/long coords from the existing reference measure + latitude = p_pointLatLon[point.Id()].first; + longitude = p_pointLatLon[point.Id()].second; + } + else { + // Get the lat/long coords from the current control point + latitude = point.UniversalLatitude(); + longitude = point.UniversalLongitude(); + if( latitude == Isis::Null || longitude == Isis::Null ) { + std::string msg = "Unable to retreive lat/lon from Control Point ["; + msg += point.Id() + "]. RETREIVAL=POINT cannot be used unless all Control "; + msg += "Points have Latitude/Longitude keywords."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + + + if (cam->SetUniversalGround(latitude, longitude)) { + + // Make sure the samp & line are inside the image + if (cam->InCube()) { + + // If there are duplicate serial numbers in the addlist, prevent double adding + if( hasDuplicateSerialNumbers ) { + std::string sn = SerialNumber::Compose( cubepvl ); + bool hasSerialNumber = false; + + for( int cm = 0; cm < point.Size() && !hasSerialNumber; cm ++ ) { + if( sn == point[cm].CubeSerialNumber() ) { + hasSerialNumber = true; + } + } + + if( hasSerialNumber ) { continue; } + } + + ControlMeasure newCm; + newCm.SetCoordinate(cam->Sample(),cam->Line(),ControlMeasure::Estimated); + newCm.SetCubeSerialNumber(SerialNumber::Compose(cubepvl)); + newCm.SetDateTime(); + newCm.SetChooserName("Application cnetadd"); + inNet[cp].Add(newCm); + // Record the modified Point and Measure + p_modifiedMeasures[cp].insert(newCm.CubeSerialNumber()); + + if (retrievalOpt == "POINT" && inNet[cp].Size() == 1) { + inNet[cp].SetIgnore(false); + } + + if (log) { + + // If we can't find this control point in the list of control points + // that have already been modified, then add it to the list + bool doesntContainPoint = true; + for (unsigned int i = 0; i < modPoints.size() && doesntContainPoint; i++) { + if (modPoints[i] == cp) doesntContainPoint = false; + } + if (doesntContainPoint) { + modPoints.push_back(cp); + } + + imageAdded = true; + } + } + } + } + + delete cam; + cam = NULL; + + if (log) { + if (imageAdded) added.AddValue(Isis::Filename(list2[img]).Basename()); + else omitted.AddValue(Isis::Filename(list2[img]).Basename()); + } + + progress.CheckStatus(); + } + + if (log) { + + // Shell sort the list of modified control points + int increments[] = { 1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, + 861, 336, 112, 48, 21, 7, 3, 1 }; + for (unsigned int k = 0; k < 16; k++) { + int inc = increments[k]; + for (unsigned int i = inc; i < modPoints.size(); i++) { + int temp = modPoints[i]; + int j = i; + while (j >= inc && modPoints[j - inc] > temp) { + modPoints[j] = modPoints[j - inc]; + j -= inc; + } + modPoints[j] = temp; + } + } + + // Add the list of modified points to the output log file + for (unsigned int i = 0; i < modPoints.size(); i++) { + pointsModified += inNet[modPoints[i]].Id(); + } + + results.AddKeyword(added); + results.AddKeyword(omitted); + results.AddKeyword(pointsModified); + if( duplicates.Size() > 0 ) { + results.AddKeyword(duplicates); + } + + results.Write(logFile.Expanded()); + } + + // List the modified points + if( ui.WasEntered("MODIFIEDPOINTS") ) { + Filename pointList( ui.GetFilename("MODIFIEDPOINTS") ); + + // Set up the output file for writing + ofstream out_stream; + out_stream.open(pointList.Expanded().c_str(), std::ios::out); + out_stream.seekp(0,std::ios::beg); //Start writing from beginning of file + + for( std::map< int, std::set >::iterator it = p_modifiedMeasures.begin(); + it != p_modifiedMeasures.end(); it ++ ) { + out_stream << inNet[it->first].Id() << std::endl; + } + + out_stream.close(); + } + + // Modify the inNet to only have modified points/measures + if( ui.GetString("EXTRACT") == "MODIFIED" ) { + for( int cp = inNet.Size()-1; cp >= 0; cp -- ) { + std::map< int, set >::iterator it = p_modifiedMeasures.find(cp); + // If the point was not modified, delete + if( it == p_modifiedMeasures.end() ) { + inNet.Delete(cp); + } + // Else, remove the unwanted measures from the modified point + else { + for( int cm = inNet[cp].Size()-1; cm >= 0; cm -- ) { + if( !inNet[cp][cm].IsReference() && + it->second.find(inNet[cp][cm].CubeSerialNumber()) == it->second.end() ) { + inNet[cp].Delete(cm); + } + } + } + } + } + + inNet.Write(outNet.Expanded()); + +} + + +/** + * Calculates the lat/lon of the ControlNet. + * + * @param incubes The filename of the list of cubes in the ControlNet + * @param cnet The filename of the ControlNet + */ +void SetControlPointLatLon( const std::string &incubes, const std::string &cnet ) { + SerialNumberList snl( incubes ); + ControlNet net( cnet ); + + CubeManager manager; + manager.SetNumOpenCubes(50); //Should keep memory usage to around 1GB + + Progress progress; + progress.SetText("Calculating Lat/Lon"); + progress.SetMaximumSteps(net.Size()); + progress.CheckStatus(); + + for (int cp = 0; cp < net.Size(); cp++) { + ControlPoint point( net[cp] ); + ControlMeasure cm( point[ net[cp].ReferenceIndex() ] ); + + Cube *cube = manager.OpenCube( snl.Filename( cm.CubeSerialNumber() ) ); + try { + cube->Camera()->SetImage( cm.Sample(), cm.Line() ); + p_pointLatLon[point.Id()].first = cube->Camera()->UniversalLatitude(); + p_pointLatLon[point.Id()].second = cube->Camera()->UniversalLongitude(); + } catch (Isis::iException &e) { + std::string msg = "Unable to create camera for cube file ["; + msg += snl.Filename( cm.CubeSerialNumber() ) + "]"; + throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); + } + cube = NULL; //Do not delete, manager still has ownership + + progress.CheckStatus(); + } + + manager.CleanCubes(); +} diff --git a/isis/src/base/apps/cnetadd/cnetadd.xml b/isis/src/base/apps/cnetadd/cnetadd.xml new file mode 100644 index 0000000000000000000000000000000000000000..0eca035f4f28d2a7cfb6df7a335ef12cd6f219cd --- /dev/null +++ b/isis/src/base/apps/cnetadd/cnetadd.xml @@ -0,0 +1,245 @@ + + + + + + Adds images to an Isis3 control network file. + + + +

    + This program takes an input list of cubes and sees if they can be added to + an existing Isis3 control network file. +

    +
    + + + Control Networks + + + + + Original version + + + Fixed major memory leak and added memory control. Changed param NETWORK + to CNET, increased developer documentation, added a Progress Object + during lat/lon calculation. + + + Fixed an error with not catching the failed ground range setting. + + + Added radio button allowing user to fill a skeleton control network (no + control measures) generated by the seedgrid application so long as it + contains a latitude/longitude for each control point. This list of files + to add has also had its parameter name changed from FROMLIST2 to ADDLIST + for clarity. + + + When adding measures to a network generated by the seedgrid application, + the Ignore keyword for a control point is now set to false if the point + has at least two measures. + + + A sorted list of control points that were modified will now be put into + the log file. + + + Modified to handle duplicate Serial Numbers between the FROMLIST and + ADDLIST instead of throwing an exception. + + + Added modified point only cnet output, added list of modified points + output. + + + Added an error message when RETREIVAL=POINT is used but lat/lon values + are absent from the points. + + + + + + + + + filename + input + + List of ISIS3 input cubes in the control net. + + + A text file containing one column of ISIS3 cube file names. Every file + used in the control net file should be represented in this list. The + cubes must be available for the program to open. + + + *.lis + + + + + filename + input + + Isis3 existing control network file + + + Use this parameter to specify the control network file containing + the information. + + + *.net + + + + + filename + input + + List of ISIS3 input cubes to add to the control net. + + + A text file containing one column of ISIS3 cube file names. The cubes + must be available for the program to open. If cubes in this list are + also in the FROMLIST, process time will be increased. + + + *.lis + + + + + + + + + filename + output + + Isis3 output control network file + + + Use this parameter to specify the control network file to output + the information to. + + + *.net + + + + + filename + output + + Optional Log File + + + This optional log file contains information about which files were + added to the control net, which ones were not, and which Serial + Numbers were in both the FROMLIST and ADDLIST. + + NONE + + + + + + + + string + + Retrieve latitude and longitude from control points in the + control network or the reference cameras obtained from the + FROMLIST + + + This option allows the user to specify whether the latitude and + longitude used for calculating control measures' sample/line + information should be retrieved from the reference cameras + generated with the FROMLIST or the control points contained + within the input control network itself. If the POINT option is + selected, then there is no need to specify a FROMLIST, otherwise + one must be specified. + + REFERENCE + + + + + + + + string + ALL + Defines what Control Points are to be placed in OUTNET + + Use this parameter to determine whether to place all Control Points + in the OUTNET, or just the Control Points with new Control Measures + and reference image measures in the OUTNET. In this case, only + reference measures and new measures are placed in the Control + Points of the OUTNET. + + + + + + + + + filename + input + Do not list + Creates a list of all modified Control Points + + Create a list of the control points that were modified by the + addition of measures. + + *.lis *.txt + + + + + +
    diff --git a/isis/src/base/apps/cnetadd/tsts/Makefile b/isis/src/base/apps/cnetadd/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cnetadd/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cnetadd/tsts/default/Makefile b/isis/src/base/apps/cnetadd/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..db306dd3a2c9e72784bd70342894363d385eeac6 --- /dev/null +++ b/isis/src/base/apps/cnetadd/tsts/default/Makefile @@ -0,0 +1,20 @@ +APPNAME = cnetadd + +include $(ISISROOT)/make/isismake.tsts + +outnet.pvl.IGNORELINES = DateTime + +commands: + $(LS) $(INPUT)/*M.cub > $(OUTPUT)/add.lis; + $(LS) $(INPUT)/*cal.cub > $(OUTPUT)/files.lis; + $(APPNAME) fromlist=$(OUTPUT)/files.lis \ + innet=$(INPUT)/input.net addlist=$(OUTPUT)/add.lis \ + outnet=$(OUTPUT)/outnet.pvl log=$(OUTPUT)/outlog.pvl \ + > /dev/null; + $(APPNAME) fromlist=$(OUTPUT)/files.lis \ + innet=$(INPUT)/input.net addlist=$(OUTPUT)/add.lis \ + extract=modified modifiedpoints=$(OUTPUT)/modified.txt \ + outnet=$(OUTPUT)/modifiednet.pvl log=$(OUTPUT)/modifiedlog.pvl \ + > /dev/null; + $(RM) $(OUTPUT)/add.lis; + $(RM) $(OUTPUT)/files.lis; diff --git a/isis/src/base/apps/cnetadd/tsts/point/Makefile b/isis/src/base/apps/cnetadd/tsts/point/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..54c796c68fe7ea58d3ea6115708395624ab5c2e6 --- /dev/null +++ b/isis/src/base/apps/cnetadd/tsts/point/Makefile @@ -0,0 +1,13 @@ +APPNAME = cnetadd + +include $(ISISROOT)/make/isismake.tsts + +outnet.pvl.IGNORELINES = DateTime + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/add.lis; + $(APPNAME) innet=$(INPUT)/seedGrid.net addlist=$(OUTPUT)/add.lis \ + outnet=$(OUTPUT)/outnet.pvl log=$(OUTPUT)/outlog.pvl \ + retrieval=POINT \ + > /dev/null; + $(RM) $(OUTPUT)/add.lis; diff --git a/isis/src/base/apps/cnetcheck/Makefile b/isis/src/base/apps/cnetcheck/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cnetcheck/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cnetcheck/cnetcheck.cpp b/isis/src/base/apps/cnetcheck/cnetcheck.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa62f1e6185d905b25ddb4edade017bf87103c54 --- /dev/null +++ b/isis/src/base/apps/cnetcheck/cnetcheck.cpp @@ -0,0 +1,532 @@ +#include "Isis.h" + +#include +#include +#include +#include + +#include "Camera.h" +#include "CameraFactory.h" +#include "ControlNet.h" +#include "CubeManager.h" +#include "FileList.h" +#include "Filename.h" +#include "iString.h" +#include "ProjectionFactory.h" +#include "PvlGroup.h" +#include "PvlKeyword.h" +#include "SerialNumber.h" +#include "SerialNumberList.h" +#include "UserInterface.h" + +using namespace std; +using namespace Isis; + +map< string, set > constructPointSets(set &index, + ControlNet &innet); +vector< set > findIslands(set &index, map< string, + set > &adjCubes); +void WriteOutput( SerialNumberList num2cube, string suffix, + set &sns, map< string, set > &cps ); + +// Main program +void IsisMain() { + + Progress progress; + UserInterface &ui = Application::GetUserInterface(); + ControlNet innet( ui.GetFilename("CNET"), NULL, true ); + iString prefix(ui.GetString("PREFIX")); + bool ignore = ui.GetBoolean("IGNORE"); + + // Sets up the list of serial numbers for + FileList inlist(ui.GetFilename("FROMLIST")); + set inListNums; + map netSerialNumCount; + vector listedSerialNumbers; + SerialNumberList num2cube; + + if (inlist.size() > 0) { + progress.SetText("Initializing"); + progress.SetMaximumSteps(inlist.size()); + progress.CheckStatus(); + } + + for(int index = 0; index < (int)inlist.size(); index ++) { + num2cube.Add(inlist[index]); + iString st = num2cube.SerialNumber(inlist[index]); + inListNums.insert(st); + listedSerialNumbers.push_back(st); // Used with nonListedSerialNumbers + progress.CheckStatus(); + } + + vector nonListedSerialNumbers; + + set singleMeasureSerialNumbers; + map< string, set > singleMeasureControlPoints; + + set duplicateSerialNumbers; + map< string, set > duplicateControlPoints; + + set noLatLonSerialNumbers; + map< string, set > noLatLonControlPoints; + set latlonchecked; + + map< string, int > cubeMeasureCount; + + // Set calculating progress + if (innet.Size() > 0) { + progress.SetText("Calculating"); + progress.SetMaximumSteps(innet.Size()); + progress.CheckStatus(); + } + + // Manage cubes used in NOLATLON + CubeManager cbman; + cbman.SetNumOpenCubes(50); + + // Loop through all control points in control net + for(int cp = 0; cp < innet.Size(); cp ++) { + if(ignore && innet[cp].Ignore()) continue; + ControlPoint controlpt(innet[cp]); + + // Checks for lat/Lon production + if( ui.GetBoolean("NOLATLON") ) { + + // Loop through all control measures in control points + for (int cm = 0; cm < controlpt.Size(); cm ++) { + ControlMeasure controlms = controlpt[cm]; + + // If we have the cube, check it out + if (num2cube.HasSerialNumber(controlms.CubeSerialNumber())) { + Cube * cube = cbman.OpenCube(num2cube.Filename(controlms.CubeSerialNumber())); + Camera * cam = NULL; + bool createFail = false; + bool setPassed = true; + + // Try to create + try { + cam = cube->Camera(); + } catch(iException &e) { + createFail = true; + e.Clear(); + } + + // Check the exact measure location + if(!createFail) { + setPassed = cam->SetImage(controlms.Sample(), controlms.Line()); + } + + // Record it if it failed at anything + if(createFail || !setPassed) { + noLatLonSerialNumbers.insert(controlms.CubeSerialNumber()); + noLatLonControlPoints[controlms.CubeSerialNumber()].insert( controlpt.Id() ); + } + } + } + } + // Checks of the ControlPoint has only 1 Measure + if(controlpt.NumValidMeasures() == 1) { + string sn = controlpt[0].CubeSerialNumber(); + singleMeasureSerialNumbers.insert(sn); + singleMeasureControlPoints[sn].insert( controlpt.Id() ); + + // Records how many times a cube is in the ControlNet + cubeMeasureCount[sn] ++; + } + else { + // Checks for duplicate Measures for the same SerialNumber + vector controlMeasures; + for(int cm = 0; cm < controlpt.Size(); cm ++) { + if( ignore && controlpt[cm].Ignore() ) continue; + + controlMeasures.push_back(controlpt[cm]); + iString currentsn = controlpt[cm].CubeSerialNumber(); + + // Records how many times a cube is in the ControlNet + cubeMeasureCount[currentsn] ++; + + // Compares previous ControlMeasure SerialNumbers with the current + for(int pre_cm = controlMeasures.size()-1-1; pre_cm >= 0; pre_cm --) { + if( controlMeasures[pre_cm].CubeSerialNumber() == currentsn ) { + duplicateSerialNumbers.insert(currentsn); //serial number duplication + duplicateControlPoints[currentsn].insert( controlpt.Id() ); + } + } + + // Removes from the serial number list, cubes that are included in the cnet + inListNums.erase( currentsn ); + netSerialNumCount[currentsn] ++; + + // Records if the currentsnum is not in the input cube list + bool contains = false; + for(int sn = 0; sn < (int)listedSerialNumbers.size() && !contains; sn ++) { + if(currentsn == listedSerialNumbers[sn]) { + contains = true; + } + } + // Check if already added + for(int sn = 0; sn < (int)nonListedSerialNumbers.size() && !contains; sn ++) { + if(currentsn == nonListedSerialNumbers[sn]) { + contains = true; + } + } + + if(!contains) { + nonListedSerialNumbers.push_back(currentsn); + } + } + } + + progress.CheckStatus(); + } + + + // Checks/detects islands + set index; + map< string, set > adjCubes = constructPointSets(index, innet); + vector< set > islands = findIslands(index, adjCubes); + + // Output islands in the file-by-file format + // Islands that have no cubes listed in the input list will + // not be shown. + for(int i=0; i < (int)islands.size(); i++) { + string name(Filename(prefix + "Island." + iString(i+1)).Expanded()); + ofstream out_stream; + out_stream.open(name.c_str(), std::ios::out); + out_stream.seekp(0,std::ios::beg); //Start writing from beginning of file + + bool hasList = false; + for(set::iterator island = islands[i].begin(); + island != islands[i].end(); island++) { + if (num2cube.HasSerialNumber(*island)) { + out_stream << (num2cube.HasSerialNumber(*island) ? Filename(num2cube.Filename(*island)).Name() : "") << " " << *island; + out_stream << "\n"; + + hasList = true; + } + } + + out_stream.close(); + + if (!hasList) { + remove(name.c_str()); + } + } + + + // Output the results to screen and files accordingly + + PvlGroup results("Results"); + + stringstream ss (stringstream::in | stringstream::out); + + results.AddKeyword( PvlKeyword("Islands",iString((BigInt)islands.size())) ); + ss << endl << "----------------------------------------" \ + "----------------------------------------" << endl; + if(islands.size() == 1) { + ss << "The cubes are fully connected by the Control Network." << endl; + } + else if(islands.size() == 0) { + ss << "There are no control points in the provided Control Network ["; + ss << Filename(ui.GetFilename("CNET")).Name() << "]" << endl; + } + else { + ss << "The cubes are NOT fully connected by the Control Network." << endl; + ss << "There are " << islands.size() << " disjoint sets of cubes." << endl; + } + + if(ui.GetBoolean("SINGLEMEASURE") && singleMeasureSerialNumbers.size() > 0) { + results.AddKeyword( + PvlKeyword("SingleMeasure",iString((BigInt)singleMeasureSerialNumbers.size())) ); + + string name(Filename(prefix + "SinglePointCubes.txt").Expanded()); + WriteOutput( num2cube, name, + singleMeasureSerialNumbers, singleMeasureControlPoints ); + + int serials = singleMeasureSerialNumbers.size(); + ss << "----------------------------------------" \ + "----------------------------------------" << endl; + ss << "There " << ((serials == 1) ? "is " : "are ") << singleMeasureSerialNumbers.size(); + ss << ((serials == 1) ? " cube" : " cubes") << " in Control Points with only a single"; + ss << " Control Measure." << endl; + ss << "The serial numbers of these measures are listed in ["; + ss << Filename(name).Name() + "]" << endl; + } + + if(ui.GetBoolean("DUPLICATE") && duplicateSerialNumbers.size() > 0) { + results.AddKeyword( + PvlKeyword("DuplicateMeasures",iString((BigInt)duplicateSerialNumbers.size())) ); + + string name(Filename(prefix + "DuplicateMeasures.txt").Expanded()); + WriteOutput( num2cube, name, + duplicateSerialNumbers, duplicateControlPoints ); + + ss << "----------------------------------------" \ + "----------------------------------------" << endl; + ss << "There are " << duplicateSerialNumbers.size(); + ss << " duplicate Control Measures in the"; + ss << " Control Net." << endl; + ss << "The serial numbers of these duplicate Control Measures"; + ss << " are listed in [" + Filename(name).Name() + "]" << endl; + } + + if(ui.GetBoolean("NOLATLON") && noLatLonSerialNumbers.size() > 0) { + results.AddKeyword( + PvlKeyword("NoLatLonCubes",iString((BigInt)noLatLonSerialNumbers.size())) ); + + string name(Filename(prefix + "NoLatLon.txt").Expanded()); + WriteOutput( num2cube, name, + noLatLonSerialNumbers, noLatLonControlPoints ); + + ss << "----------------------------------------" \ + "----------------------------------------" << endl; + ss << "There are " << noLatLonSerialNumbers.size(); + ss << " serial numbers in the Control Network which are listed in the"; + ss << " input list and cannot compute latitude and longitudes." << endl; + ss << "These serial numbers, filenames, and control points are listed in ["; + ss << Filename(name).Name() + "]" << endl; + } + + // At this point, inListNums is the list of cubes NOT included in the + // ControlNet, and inListNums are their those cube's serial numbers. + if(ui.GetBoolean("NOCONTROL") && !inListNums.empty() ) { + results.AddKeyword( PvlKeyword("NoControl",iString((BigInt)inListNums.size())) ); + + string name(Filename(prefix + "NoControl.txt").Expanded()); + ofstream out_stream; + out_stream.open(name.c_str(), std::ios::out); + out_stream.seekp(0,std::ios::beg); //Start writing from beginning of file + + for( set::iterator sn = inListNums.begin(); + sn != inListNums.end(); + sn ++) { + out_stream << (*sn); + out_stream << "\t" << (num2cube.HasSerialNumber(*sn) ? Filename(num2cube.Filename(*sn)).Name() : ""); + out_stream << "\n"; + } + out_stream.close(); + + ss << "----------------------------------------" \ + "----------------------------------------" << endl; + ss << "There are " << inListNums.size(); + ss << " cubes in the input list [" << Filename(ui.GetFilename("FROMLIST")).Name(); + ss << "] which do not exist or are ignored in the Control Network ["; + ss << Filename(ui.GetFilename("CNET")).Name() << "]" << endl; + ss << "These cubes are listed in [" + Filename(name).Name() + "]" << endl; + } + + // In addition, nonListedSerialNumbers should be the SerialNumbers of + // ControlMeasures in the ControlNet that do not have a correlating + // cube in the input list. + if(ui.GetBoolean("NOCUBE") && nonListedSerialNumbers.size() > 0) { + results.AddKeyword( + PvlKeyword("NoCube",iString((BigInt)nonListedSerialNumbers.size())) ); + + string name(Filename(prefix + "NoCube.txt").Expanded()); + ofstream out_stream; + out_stream.open(name.c_str(), std::ios::out); + out_stream.seekp(0,std::ios::beg); //Start writing from beginning of file + + for(int sn=0; sn < (int)nonListedSerialNumbers.size(); sn++) { + out_stream << nonListedSerialNumbers[sn]; + out_stream << "\n"; + } + + out_stream.close(); + + ss << "----------------------------------------" \ + "----------------------------------------" << endl; + ss << "There are " << nonListedSerialNumbers.size(); + ss << " serial numbers in the Control Net ["; + ss << Filename(ui.GetFilename("CNET")).Basename(); + ss << "] which do not exist in the input list ["; + ss << Filename(ui.GetFilename("FROMLIST")).Name() << "]" << endl; + ss << "These serial numbers are listed in ["; + ss << Filename(name).Name() + "]" << endl; + } + + // At this point cubeMeasureCount should be equal to the number of + // ControlMeasures associated with each serial number. + if( ui.GetBoolean("SINGLECUBE") ) { + set singleMeasureCubes; + for( map::iterator cube = cubeMeasureCount.begin(); + cube != cubeMeasureCount.end(); + cube ++ ) { + if( cube->second == 1 ) { singleMeasureCubes.insert( cube->first ); } + } + + if( singleMeasureCubes.size() > 0 ) { + results.AddKeyword( + PvlKeyword("SingleCube",iString((BigInt)singleMeasureCubes.size())) ); + + string name(Filename(prefix + "SingleCube.txt").Expanded()); + ofstream out_stream; + out_stream.open(name.c_str(), std::ios::out); + out_stream.seekp(0,std::ios::beg); //Start writing from beginning of file + + for( set::iterator sn = singleMeasureCubes.begin(); + sn != singleMeasureCubes.end(); + sn ++ ) { + out_stream << (*sn); + out_stream << "\t" << (num2cube.HasSerialNumber(*sn) ? Filename(num2cube.Filename(*sn)).Name() : ""); + out_stream << "\n"; + } + + out_stream.close(); + + ss << "----------------------------------------" \ + "----------------------------------------" << endl; + ss << "There are " << singleMeasureCubes.size(); + ss << " serial numbers in the Control Net ["; + ss << Filename(ui.GetFilename("CNET")).Basename(); + ss << "] which only exist in one Control Measure." << endl; + ss << "These serial numbers are listed in ["; + ss << Filename(name).Name() + "]" << endl; + } + } + + ss << "----------------------------------------" \ + "----------------------------------------" << endl << endl; + std::string log = ss.str(); + Application::Log(results); + + if (ui.IsInteractive()) { + Application::GuiLog(log); + } + else { + cout << ss.str(); + } + +} + + +// Links cubes to other cubes it shares control points with +map< string, set > constructPointSets(set &index, + ControlNet &innet) { + map< string, set > adjPoints; + + bool ignore = Application::GetUserInterface().GetBoolean("IGNORE"); + for(int cp=0; cp < innet.Size(); cp++) { + + if(ignore && innet[cp].Ignore()) continue; + + if(innet[cp].NumValidMeasures() < 2) continue; + + ControlPoint controlpt = innet[cp]; + // Map SerialNumbers together based on ControlMeasures + for(int cm1=0; cm1 < controlpt.Size(); cm1++) { + if(ignore && controlpt.Ignore()) continue; + + std::string sn = controlpt[cm1].CubeSerialNumber(); + index.insert(sn); + for(int cm2=0; cm2 < controlpt.Size(); cm2++) { + if(ignore && controlpt[cm2].Ignore()) continue; + + if(cm1 != cm2) { + adjPoints[ sn ].insert( controlpt[cm2].CubeSerialNumber() ); + } + } + } + + } + + return adjPoints; +} + + +// Uses a depth-first search to construct the islands +vector< set > findIslands(set &index, + map< string, set > &adjCubes) { + vector< set > islands; + + while(index.size() != 0) { + set connectedSet; + + stack str_stack; + set::iterator first = index.begin(); + str_stack.push(*first); + + // Depth search + while(true) { + index.erase(str_stack.top()); + connectedSet.insert(str_stack.top()); + + // Find the first connected unvisited node + std::string nextNode = ""; + set neighbors = adjCubes[str_stack.top()]; + for (set::iterator i = neighbors.begin(); i != neighbors.end(); i++) { + if (index.count(*i) == 1) { + nextNode = *i; + break; + } + } + + if (nextNode != "") { + // Push the unvisited node + str_stack.push(nextNode); + } + else { + // Pop the visited node + str_stack.pop(); + + if (str_stack.size() == 0) break; + } + } + + islands.push_back(connectedSet); + } + + return islands; +} + + +// Writes the list of cubes [ SerialNumber, Filename, ControlPoints ] to the output file +void WriteOutput( SerialNumberList num2cube, string filename, + set &sns, map< string, set > &cps ) { + + UserInterface &ui = Application::GetUserInterface(); + + // Set the character to separate the entries + string delimit; + if (ui.GetString("DELIMIT") == "TAB") { + delimit = "\t"; + } + else if (ui.GetString("DELIMIT") == "COMMA") { + delimit = ","; + } + else if (ui.GetString("DELIMIT") == "SPACE") { + delimit = " "; + } + else { + delimit = ui.GetString("CUSTOM"); + } + + // Set up the output file for writing + ofstream out_stream; + out_stream.open(filename.c_str(), std::ios::out); + out_stream.seekp(0,std::ios::beg); //Start writing from beginning of file + + for( set::iterator sn = sns.begin(); + sn != sns.end(); sn++ ) { + // Serial Number of cube + out_stream << *sn; + + // Filename of cube if given + if( num2cube.HasSerialNumber(*sn) ) { + out_stream << delimit << Filename(num2cube.Filename(*sn)).Name(); + } + else { + out_stream << delimit << "UnknownFilename"; + } + + // Control Points where the cube was found to have the issue + for( set::iterator cp = cps[*sn].begin(); + cp != cps[*sn].end(); cp++ ) { + out_stream << "\t" << *cp; + } + + out_stream << "\n"; + } + + out_stream.close(); +} diff --git a/isis/src/base/apps/cnetcheck/cnetcheck.xml b/isis/src/base/apps/cnetcheck/cnetcheck.xml new file mode 100644 index 0000000000000000000000000000000000000000..3f9efd2426943e0b86ff97799019a7914b05c772 --- /dev/null +++ b/isis/src/base/apps/cnetcheck/cnetcheck.xml @@ -0,0 +1,295 @@ + + + + + + Checks for validity of a Control Net file. + + + + Checks for the validity of a Control Net file given a cube list. Its primary + function is to check and find islands of the Control Net. These islands + are then written to seperate files, which lists the cubes and their + corresponding serial number. If a serial number's cube is not listed in + the input list, than that cube will NOT be listed within the appropriate + island file. If an island file is missing altogether, it is due to the fact + that all of that islands cubes were not listed in the input list. + + cnetcheck should be ran from the directory you wish for the output files to + be written to. + + + + + Original version + + + Fixed output files to only show filenames and usage of c_str. + + + Fixed NoLatLon option. + + + Added Control Point IDs to the NoLatLon flat file. + + + Greatly optimized the NoLatLon option. + + + Renamed parameters: "LIST" is now "FROMLIST" and "CONTROL" is now "NETWORK" + + + Added the IGNORE option, which ignores ignored Control Points. + + + Added a results group that correlates parameter names to keywords, fixed + the newline character outputs, and changed NOMATCH to NOCONTROL. + + + Fixed the island detecting to disregard ignored control points and other + bug fixes. + + + Fixed a bug with ignored Control Measures, changed NETWORK to CNET, + changed the output formats to be more useful and consistant. + + + Cleaned up syntax and improved readability. + + + Added the SINGLECUBE parameter, renaming SINGLE to SINGLEMEASURE as a consequence. + + + Modified functionality of NOLATLON option to check all measures, not just + each cube. + + + Added the DELIMIT parameter + + + + + Control Networks + + + + + + filename + input + + List of ISIS3 input cubes in the Control Network + + + A text file containing one column of ISIS3 cube file names. Every file + used in the match point file should be represented in this list. + + + *.txt *.lis *.list + + + + + filename + input + + Isis3 input Control Network file + + + Use this parameter to specify the control network file containing + the information to be validated + + + *.net + + + + + + + + + string + + The character to be inserted between file entries + + + This option will determine which character will be used to + separate file entries, with the default option as a tab. + The other options are comma, to separate with a single + space, or "OTHER," which allows the user to input whatever + they wish as the delimiter character. + + TAB + + + + + + + + + string + User-defined delimiter + + This parameter is only used if the user has selected "OTHER" + as a delimiter. The user then enters something into this + parameter to use as a delimiter. + + + + + string + output + + Outputs results + + + The result of the validity check is placed in output files with the + given prefix. + + + + + boolean + True + + Ignores ignored Control Points when checking the Control Net. + + + When true, all ignored Control Points and all ignored Control + Measures provided by the Control Net will be discarded during + calculations. + + + + + boolean + True + + Check for Cubes in the FROMLIST which are not in the Control Net. + + + When true, a file named [PREFIX]NoMatch.txt will be created, which + will list all of the cubes, and their corresponding Serial Number + which do not exist within the provided Control Net. If there are no + such cubes, then no file is created. + + + + + boolean + True + + Checks for cubes in the Control Net that are not listed in the FROMLIST. + + + When true, a file named [PREFIX]NoCube.txt will be created, which + will list all of the Serial Numbers in the given Control Net which + do not have a corresponding Cube in the proveded List. If there are + no such Serial Numbers, then no file is created. + + + + + boolean + True + + Check for Control Points which contain a single Control Measure. + + + When true, a file named [PREFIX]SinglePointCubes.txt will be created, + which will list all of the Cubes which exist as a single Control + Measure in any Control Point within the provided Control Net. If there + are no such single Control Measures, then no file is created. + + + + + boolean + True + + Check for Control Points which contain the same cube in more than one Control Measure. + + + When true, a file named [PREFIX]DuplicateMeasures.txt will be created, + which will list all of the cubes which exist in more than one Control + Measure in a single Control Point within the provided Control Net. If + there are no such duplicate Control Measures, then no file is created. + + + + + boolean + True + + Check for Cubes which have only a single Control Measure. + + + When true, a file named [PREFIX]SingleCubes.txt will be created, + which will list all of the Cubes which exist in only a single Control + Measure within the entire Control Net. If there + are no such single Cubes, then no file is created. + + + + + boolean + True + + Check for measures for which latitudes and longitudes cannot be + computed for. + + + When true, a file named [PREFIX]NoLatLon.txt will be created, which + will list all of the serial numbers which are within the given Control + Net and listed in the input list which cannot compute a latitude and + longitude. These serial numbers will be followed by the Control Point + IDs in which they could not compute their latitudes and longitudes. + If there are no such serial numbers, then no file is created. + + Only cubes in both the FROMLIST and CNET are checked. + + + + + diff --git a/isis/src/base/apps/cnetcheck/tsts/Makefile b/isis/src/base/apps/cnetcheck/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cnetcheck/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cnetcheck/tsts/camera/Makefile b/isis/src/base/apps/cnetcheck/tsts/camera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1c65452ab0193ca70efdd915107b5b4d8953951b --- /dev/null +++ b/isis/src/base/apps/cnetcheck/tsts/camera/Makefile @@ -0,0 +1,12 @@ +APPNAME = cnetcheck + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) fromlist=$(OUTPUT)/list.lis prefix=$(OUTPUT)/cat \ + nocube=false \ + cnet=$(INPUT)/NearSide_All.net | grep -v "Processed" \ + > $(OUTPUT)/output.txt; + $(RM) $(OUTPUT)/list.lis; + $(RM) $(OUTPUT)/catIsland.* diff --git a/isis/src/base/apps/cnetcheck/tsts/default/Makefile b/isis/src/base/apps/cnetcheck/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..719cbebc454df5c4a65f98e7796d37e28f5606f1 --- /dev/null +++ b/isis/src/base/apps/cnetcheck/tsts/default/Makefile @@ -0,0 +1,17 @@ +APPNAME = cnetcheck + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) fromlist=$(OUTPUT)/list.lis prefix=$(OUTPUT)/cat \ + nolatlon = false \ + cnet=$(INPUT)/NearSide_All.net | grep -v "Processed" \ + > $(OUTPUT)/output.txt; + $(APPNAME) fromlist=$(OUTPUT)/list.lis prefix=$(OUTPUT)/com \ + ignore=false nolatlon=false delimit=comma \ + cnet=$(INPUT)/NearSide_All.net | grep -v "Processed" \ + > $(OUTPUT)/comoutput.txt; + $(RM) $(OUTPUT)/comIsland.* + $(RM) $(OUTPUT)/catIsland.* + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/cnetcheck/tsts/ignore/Makefile b/isis/src/base/apps/cnetcheck/tsts/ignore/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3274bfecf7a1f42cc9ace06f9cb3ffe967d3d4de --- /dev/null +++ b/isis/src/base/apps/cnetcheck/tsts/ignore/Makefile @@ -0,0 +1,12 @@ +APPNAME = cnetcheck + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) fromlist=$(OUTPUT)/list.lis prefix=$(OUTPUT)/cat \ + nolatlon = false \ + cnet=$(INPUT)/NearSide_All.net | grep -v "Processed" \ + > $(OUTPUT)/output.txt; + $(RM) $(OUTPUT)/list.lis; + $(RM) $(OUTPUT)/catIsland.* diff --git a/isis/src/base/apps/cnetcheck/tsts/nopoints/Makefile b/isis/src/base/apps/cnetcheck/tsts/nopoints/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2f6caccbdf1f438a19046ffd9b83c8f788e8aec7 --- /dev/null +++ b/isis/src/base/apps/cnetcheck/tsts/nopoints/Makefile @@ -0,0 +1,10 @@ +APPNAME = cnetcheck + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) fromlist=$(OUTPUT)/list.lis prefix=$(OUTPUT)/cat \ + cnet=$(INPUT)/cnet.net | grep -v "Processed" \ + > $(OUTPUT)/output.txt; + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/cnetedit/Makefile b/isis/src/base/apps/cnetedit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cnetedit/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cnetedit/cnetedit.cpp b/isis/src/base/apps/cnetedit/cnetedit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f5ac6b6d900e527254099dbfd26ba12abf1f1ad6 --- /dev/null +++ b/isis/src/base/apps/cnetedit/cnetedit.cpp @@ -0,0 +1,187 @@ +#include "Isis.h" +#include "ControlNet.h" +#include "SerialNumberList.h" +#include "ControlPointList.h" + +using namespace std; +using namespace Isis; + +void ProcessControlPoints (std::string psFileName, ControlNet & pcCnet, bool pbDelete, Pvl & pcPvlLog, bool pbPreserve); +void ProcessControlMeasures(std::string psFileName, ControlNet & pcCnet, bool pbDelete, bool pbPreserve); + +static int giPointsDeleted=0, giMeasuresDeleted=0; + +static bool gbLog; + +// Main program +void IsisMain() { + + // Get user parameters + UserInterface &ui = Application::GetUserInterface(); + ControlNet cnet( ui.GetFilename("CNET") ); + bool bDelete = ui.GetBoolean("DELETE"); + bool bPreserve = ui.GetBoolean("PRESERVE"); + bool bPointList=false, bCubeList=false; + Pvl pvlLog; + + gbLog=false; + + std::string sPointsFile, sMeasuresFile, sLogfile; + + //Get the Log file + if ( ui.WasEntered("LOG") ) { + sLogfile = ui.GetFilename("LOG"); + gbLog=true; + } + + //List has Points Ids + if ( ui.WasEntered("POINTLIST") ){ + sPointsFile = ui.GetFilename("POINTLIST"); + ProcessControlPoints(sPointsFile, cnet, bDelete, pvlLog, bPreserve); + } + + //List has Cube file names + if ( ui.WasEntered("FROMLIST") ) { + sMeasuresFile = ui.GetFilename("FROMLIST"); + ProcessControlMeasures(sMeasuresFile, cnet, bDelete, bPreserve); + } + + //No List files - only Delete option was chosen + if ( bDelete && !bPointList && !bCubeList ){ + for ( int cp = cnet.Size()-1; cp >= 0; cp -- ) { + if ( cnet[cp].Ignore() ) { + giMeasuresDeleted += cnet[cp].Size(); + cnet.Delete(cp); + giPointsDeleted++; + } + else { + for ( int cm = cnet[cp].Size()-1; cm >= 0; cm -- ) { + if ( cnet[cp][cm].Ignore() ) { + cnet[cp].Delete(cm); + giMeasuresDeleted++; + } + // Check if the number of measures in the point is zero or + // there are few measures in the point and preserve flag is false. + if ( ( (cnet[cp].Size() < 2 && !bPreserve) && cnet[cp].Type() != ControlPoint::Ground ) + || cnet[cp].Size() == 0 ) { + giMeasuresDeleted += cnet[cp].Size(); + cnet.Delete(cp); + giPointsDeleted++; + } + + } + } + } + } + + //log statistics + if ( gbLog ) { + pvlLog += Isis::PvlKeyword("PointsDeleted", giPointsDeleted); + pvlLog += Isis::PvlKeyword("MeasuresDeleted", giMeasuresDeleted); + + pvlLog.Write(sLogfile); + } + + cnet.Write( ui.GetFilename("ONET") ); +} + + + /** + * Reads the Control Points list and matches with the control + * network. If match was successful, ignore the point. If + * Delete option was chosen, delete the point + * + * @param psFileName - Filename with Control Points + * @param pcCnet - holds the input Control Network + * @param pbDelete - Delete option (true/false) + * @param pcPvlLog - Pvl for which control points stats have + * to be added + * @param pbPreserve - Preserve Control Points with Measures + * equal to one. (true/false) + * + * @return none + */ +void ProcessControlPoints(std::string psFileName, ControlNet & pcCnet, bool pbDelete, Pvl& pcPvlLog, bool pbPreserve) +{ + ControlPointList cpList(psFileName); + + for ( int cp = pcCnet.Size()-1; cp >= 0; cp -- ) { + + // Compare each Point Id listed with the Point in the + // Control Network for according exclusion + if ( cpList.HasControlPoint(pcCnet[cp].Id()) ) { + pcCnet[cp].SetIgnore(true); + } + + if ( pbDelete ){ + //look for previously ignored control points + if (pcCnet[cp].Ignore()){ + giMeasuresDeleted += pcCnet[cp].Size(); + pcCnet.Delete(cp); + giPointsDeleted++; + } + else{ + //look for previously ignored control measures + for ( int cm = pcCnet[cp].Size()-1; cm >= 0 ; cm-- ) { + if (pcCnet[cp][cm].Ignore() && pbDelete) { + pcCnet[cp].Delete(cm); + giMeasuresDeleted++; + } + } + // Check if there are too few measures in the point or the point was previously ignored + if (( (pcCnet[cp].Size() < 2 && !pbPreserve) && pcCnet[cp].Type() != ControlPoint::Ground ) + || pcCnet[cp].Size() == 0 || (pcCnet[cp].Ignore() && pbDelete)) { + giMeasuresDeleted += pcCnet[cp].Size(); + pcCnet.Delete(cp); + giPointsDeleted++; + } + } + } + } + if ( gbLog ) { + cpList.RegisterStatistics(pcPvlLog); + } +} + + /** + * Reads the Cube file list and creates the serial number of the + * Cubes. If Control Measure serial# matches with the control + * network,ignore the point. If Delete option was chosen, delete + * the Measure + * + * @param psFileName - Filename with Cube File names + * @param pcCnet - holds the input Control Network + * @param pbDelete - Delete option (true/false) + * @param pbPreserve - Preserve Control Points with Measures + * equal to one. (true/false) + * + * @return none + */ +void ProcessControlMeasures(std::string psFileName, ControlNet & pcCnet, bool pbDelete, bool pbPreserve) +{ + SerialNumberList snl = psFileName; + + for ( int cp = pcCnet.Size()-1; cp >= 0; cp -- ) { + + // Compare each Serial Number listed with the serial number in the + // Control Measure for according exclusion + for ( int cm = pcCnet[cp].Size()-1; cm >= 0 ; cm-- ) { + if ( snl.HasSerialNumber(pcCnet[cp][cm].CubeSerialNumber()) ) { + pcCnet[cp][cm].SetIgnore( true ); + } + //also look for previously ignored control measures + if ( pbDelete && pcCnet[cp][cm].Ignore() ) { + pcCnet[cp].Delete(cm); + giMeasuresDeleted++; + } + } + // Check if there are too few measures in the point or the point was previously ignored + if (( (pcCnet[cp].Size() < 2 && !pbPreserve) && pcCnet[cp].Type() != ControlPoint::Ground ) + || pcCnet[cp].Size() == 0 || (pcCnet[cp].Ignore() && pbDelete)) { + giMeasuresDeleted += pcCnet[cp].Size(); + pcCnet.Delete(cp); + giPointsDeleted++; + } + } +} + diff --git a/isis/src/base/apps/cnetedit/cnetedit.xml b/isis/src/base/apps/cnetedit/cnetedit.xml new file mode 100644 index 0000000000000000000000000000000000000000..a5524a05618cafde8867d057e6f863aa14b8dcb8 --- /dev/null +++ b/isis/src/base/apps/cnetedit/cnetedit.xml @@ -0,0 +1,175 @@ + + + + + + Edits Control Networks + + + +

    + This application enables the editiong of Control Networks. It may remove + all ignored Control Points and Control Measures. Also, it may take a + list of cubes and ignore all Control Measures contained by those cubes or + take list of control point ids. +

    +
    + + + + Original version + + + Added options, including EXCLUDELIST and DELETE + + + Renamed EXCLUDELIST to IGNORELIST and made other similar name changes. + + + Renamed IGNORELIST to FROMLIST and made other similar name changes + Added options HOLD and UNHOLD + Set the default as FALSE for DELETE Ignored Control Points and Measures + + + Renamed IGNORELIST to FROMLIST and reverted back to previous format + + + Set the default as FALSE for DELETE Ignored Control Points and Measures + + + Fixed an out of index bug. + + + Added parameter LOG to write logs into the file if explicitly stated, + parameter POINTLIST to read Control Point ID's from a file + reverted DELETE default to be TRUE + + + Added parameter PRESERVE with default FALSE. If set the Control Points with + Measures equal to one are not deleted + + + + + Control Networks + + + + + + + filename + input + + Input control network + + + This file is a control network generated from programs such as + autoseed or qnet. + + + *.net + + + + + filename + output + + Output control network + + + The file will contain the updated control network with edits. + + + *.net + + + + + filename + output + + None + + + Log the control network + + + If this file is entered then the log will be outputted to this file + + + *.* + + + + + + + filename + input + None + + File contains Cube file names from which Serial #'s are generated and + matching Control Measures will be ignored in the Control Network. + + + Use this parameter to select the filename which contains a list of + cubes. All of the Control Measures matching the serial # of the cube + will be ignored. If DELETE is also set to true, the ignored control + measures and points will be deleted. + + + *.lis + + + + + filename + input + None + + File contains Point Ids which will be ignored if matched in the + Control Network + + + Use this parameter to select the filename which contains a list of + point ids. All the Control Points with matching Ids will be ignored. If + DELETE is also set to true, all the ignored control measures and points + will be deleted. + + + *.lis + + + + + + + boolean + TRUE + + Delete Ignored Points and Measures + + + This option deletes all ignored Control Measures and Control Points. + If any Control Point results in less than 2 Control Measures, that + Control Point will be deleted as well. + + + + boolean + FALSE + + Preserve Points with Measures equal to One + + + This option preserves Control Points with Control Measures equal to + one. + + + + + + +
    \ No newline at end of file diff --git a/isis/src/base/apps/cnetedit/tsts/Makefile b/isis/src/base/apps/cnetedit/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..322a6262d1b4eed41a8685d2c217c28c2ec0e205 --- /dev/null +++ b/isis/src/base/apps/cnetedit/tsts/Makefile @@ -0,0 +1,5 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree + diff --git a/isis/src/base/apps/cnetedit/tsts/default/Makefile b/isis/src/base/apps/cnetedit/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5617e8c2d60bf59b280e68818547664a537100b7 --- /dev/null +++ b/isis/src/base/apps/cnetedit/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = cnetedit + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) CNET=$(INPUT)/cnet.net ONET=$(OUTPUT)/cnet.pvl> /dev/null; diff --git a/isis/src/base/apps/cnetedit/tsts/ignore/Makefile b/isis/src/base/apps/cnetedit/tsts/ignore/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b5393c3ed8141b64132d7450a4fe9043d29a472c --- /dev/null +++ b/isis/src/base/apps/cnetedit/tsts/ignore/Makefile @@ -0,0 +1,10 @@ +APPNAME = cnetedit + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) CNET=$(INPUT)/cnet.net \ + FROMLIST=$(OUTPUT)/list.lis \ + ONET=$(OUTPUT)/cnet.pvl > /dev/null; + $(RM) $(OUTPUT)/list.lis; \ No newline at end of file diff --git a/isis/src/base/apps/cnetedit/tsts/ignoreMeasuresPoints/Makefile b/isis/src/base/apps/cnetedit/tsts/ignoreMeasuresPoints/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..589ec9802f67ce991fb0d0ed1f400f0f57342267 --- /dev/null +++ b/isis/src/base/apps/cnetedit/tsts/ignoreMeasuresPoints/Makefile @@ -0,0 +1,10 @@ +APPNAME = cnetedit + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) CNET=$(INPUT)/cnet.net \ + FROMLIST=$(OUTPUT)/list.lis \ + POINTLIST=$(INPUT)/points.lis \ + ONET=$(OUTPUT)/cnet.pvl > /dev/null; diff --git a/isis/src/base/apps/cnetedit/tsts/ignorePoints/Makefile b/isis/src/base/apps/cnetedit/tsts/ignorePoints/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b76c310564ec70d01f64019bfed2bb6e1c33fdd1 --- /dev/null +++ b/isis/src/base/apps/cnetedit/tsts/ignorePoints/Makefile @@ -0,0 +1,8 @@ +APPNAME = cnetedit + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) CNET=$(INPUT)/cnet.net \ + POINTLIST=$(INPUT)/points.lis \ + ONET=$(OUTPUT)/cnet.pvl > /dev/null; diff --git a/isis/src/base/apps/cnetextract/Makefile b/isis/src/base/apps/cnetextract/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cnetextract/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cnetextract/cnetextract.cpp b/isis/src/base/apps/cnetextract/cnetextract.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22273735b4e830679e7e6987d07b60927e94f928 --- /dev/null +++ b/isis/src/base/apps/cnetextract/cnetextract.cpp @@ -0,0 +1,712 @@ +#include "Isis.h" + +#include +#include +#include + +#include "CameraFactory.h" +#include "ControlNet.h" +#include "ControlPoint.h" +#include "CubeManager.h" +#include "FileList.h" +#include "iException.h" +#include "iString.h" +#include "ProjectionFactory.h" +#include "Pvl.h" +#include "SerialNumber.h" +#include "UserInterface.h" + +using namespace std; +using namespace Isis; + +void ExtractPointList(ControlNet &outNet, vector & nonListedPoints); +void ExtractLatLonRange(ControlNet &outNet, vector & nonLatLonPoints, + vector & cannotGenerateLatLonPoints, map sn2filename); +bool NotInLatLonRange(double lat, double lon, double minlat, + double maxlat, double minlon, double maxlon); +void WriteCubeOutList(ControlNet cnet, map sn2file); +void WriteResults(string filename, vector results); + +// Main program +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + + if(!ui.WasEntered("FROMLIST") && ui.WasEntered("TOLIST")) { + std::string msg = "To create a [TOLIST] the [FROMLIST] parameter must be provided."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + bool noIgnore = ui.GetBoolean("NOIGNORE"); + bool noHeld = ui.GetBoolean("NOHELD"); + bool noSingleMeasure = ui.GetBoolean("NOSINGLEMEASURES"); + bool noMeasureless = ui.GetBoolean("NOMEASURELESS"); + bool noTolerancePoints = ui.GetBoolean("TOLERANCE"); + bool reference = ui.GetBoolean("REFERENCE"); + bool ground = ui.GetBoolean("GROUND"); + bool cubePoints = ui.GetBoolean("CUBES"); + bool cubeMeasures = ui.GetBoolean("CUBEMEASURES"); + bool pointsEntered = ui.WasEntered("POINTLIST"); + bool latLon = ui.GetBoolean("LATLON"); + + if(!(noIgnore || noHeld || noSingleMeasure || noMeasureless || noTolerancePoints || + reference || ground || cubePoints || pointsEntered || latLon)) { + std::string msg = "At least one filter must be selected ["; + msg += "NOIGNORE,NOHELD,NOSINGLEMEASURE,TOLERANCE,REFERENCE,GROUND,"; + msg += "POINTLIST,LATLON]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + /*else if( cubeMeasures && !cubePoints ) + { + std::string msg = "When CUBEMEASURES is selected, CUBEPOINTS must be given"; + msg += " a list of cubes."; + throw iException::Message( iException::User, msg, _FILEINFO_ ); + }*/ + + if(cubeMeasures || reference) { + noMeasureless = true; + } + + // Gets the input parameters + ControlNet outNet(ui.GetFilename("CNET")); + FileList inList; + if(ui.WasEntered("FROMLIST")) { + inList = ui.GetFilename("FROMLIST"); + } + + // Set up the Serial Number to Filename mapping + map sn2filename; + for(int cubeIndex = 0; cubeIndex < (int)inList.size(); cubeIndex ++) { + iString sn = SerialNumber::Compose(inList[cubeIndex]); + sn2filename[sn] = inList[cubeIndex]; + } + + + Progress progress; + progress.SetMaximumSteps(outNet.Size()); + progress.CheckStatus(); + + // Set up verctor records of how points/measures are removed + vector ignoredPoints; + vector ignoredMeasures; + vector heldPoints; + vector singleMeasurePoints; + vector measurelessPoints; + vector tolerancePoints; + vector nonReferenceMeasures; + vector nonGroundPoints; + vector nonCubePoints; + vector noCubeMeasures; + vector noMeasurePoints; + vector nonListedPoints; + vector nonLatLonPoints; + vector cannotGenerateLatLonPoints; + + // Set up comparison data + vector serialNumbers; + if(cubePoints) { + FileList cubeList(ui.GetFilename("CUBELIST")); + for(int cubeIndex = 0; cubeIndex < (int)cubeList.size(); cubeIndex ++) { + iString sn = SerialNumber::Compose(cubeList[cubeIndex]); + serialNumbers.push_back(sn); + } + } + + double tolerance = 0.0; + if(noTolerancePoints) { + tolerance = ui.GetDouble("PIXELTOLERANCE"); + } + + // Set up extracted network values + if(ui.WasEntered("NETWORKID")) + outNet.SetNetworkId(ui.GetString("NETWORKID")); + + outNet.SetUserName(Isis::Application::UserName()); + outNet.SetDescription(ui.GetString("DESCRIPTION")); + + + for(int cp = outNet.Size() - 1; cp >= 0; cp --) { + progress.CheckStatus(); + + // Do preliminary exclusion checks + if(noIgnore && outNet[cp].Ignore()) { + ignoredPoints.push_back(outNet[cp].Id()); + outNet.Delete(cp); + continue; + } + if(noHeld && outNet[cp].Held()) { + heldPoints.push_back(outNet[cp].Id()); + outNet.Delete(cp); + continue; + } + if(ground && !(outNet[cp].Type() == ControlPoint::Ground)) { + nonGroundPoints.push_back(outNet[cp].Id()); + outNet.Delete(cp); + continue; + } + + if(noSingleMeasure) { + bool invalidPoint = false; + invalidPoint |= noIgnore && (outNet[cp].NumValidMeasures() < 2); + invalidPoint |= outNet[cp].Size() < 2 && (outNet[cp].Type() != ControlPoint::Ground); + + if(invalidPoint) { + singleMeasurePoints.push_back(outNet[cp].Id()); + outNet.Delete(cp); + continue; + } + } + + // Change the current point into a new point by manipulation of its control measures + ControlPoint &newPoint = outNet[cp]; + + for(int cm = newPoint.Size() - 1; cm >= 0; cm --) { + if(noIgnore && newPoint[cm].Ignore()) { + ignoredMeasures.push_back(newPoint.Id() + "," + newPoint[cm].CubeSerialNumber()); + newPoint.Delete(cm); + } + else if(reference && !newPoint[cm].IsReference()) { + nonReferenceMeasures.push_back(newPoint.Id() + "," + newPoint[cm].CubeSerialNumber()); + newPoint.Delete(cm); + } + else if(cubeMeasures) { + bool hasSerialNumber = false; + + for(unsigned int sn = 0; sn < serialNumbers.size() && !hasSerialNumber; sn ++) { + if(serialNumbers[sn] == newPoint[cm].CubeSerialNumber()) hasSerialNumber = true; + } + + if(!hasSerialNumber) { + noCubeMeasures.push_back(newPoint.Id() + "," + newPoint[cm].CubeSerialNumber()); + newPoint.Delete(cm); + } + } + } + + // Check for line/sample errors above provided tolerance + if(noTolerancePoints) { + bool hasLowTolerance = true; + + for(int cm = 0; cm < newPoint.Size() && hasLowTolerance; cm ++) { + if(newPoint[cm].SampleError() >= tolerance || + newPoint[cm].LineError() >= tolerance) { + hasLowTolerance = false; + } + } + + if(hasLowTolerance) { + tolerancePoints.push_back(newPoint.Id()); + outNet.Delete(cp); + continue; + } + } + + // Do not add outPoint if it has too few measures + if(noSingleMeasure) { + bool invalidPoint = false; + invalidPoint |= noIgnore && (newPoint.NumValidMeasures() < 2); + invalidPoint |= newPoint.Size() < 2 && newPoint.Type() != ControlPoint::Ground; + + if(invalidPoint) { + singleMeasurePoints.push_back(outNet[cp].Id()); + outNet.Delete(cp); + continue; + } + } + + // Do not add outPoint if it does not have a cube in CUBELIST as asked + if(cubePoints && !cubeMeasures) { + bool hasSerialNumber = false; + + for(int cm = 0; cm < newPoint.Size() && !hasSerialNumber; cm ++) { + for(unsigned int sn = 0; sn < serialNumbers.size() && !hasSerialNumber; sn ++) { + if(serialNumbers[sn] == newPoint[cm].CubeSerialNumber()) hasSerialNumber = true; + } + } + + if(!hasSerialNumber) { + nonCubePoints.push_back(newPoint.Id()); + outNet.Delete(cp); + continue; + } + } + + if(noMeasureless && newPoint.Size() == 0) { + noMeasurePoints.push_back(newPoint.Id()); + outNet.Delete(cp); + continue; + } + } //! Finished with simple comparisons + + + /** + * Use another pass to check for Ids + */ + if(pointsEntered) { + ExtractPointList(outNet, nonListedPoints); + } + + + /** + * Use another pass on outNet, because this is by far the most time consuming + * process, and time could be saved by using the reduced size of outNet + */ + if(latLon) { + ExtractLatLonRange(outNet, nonLatLonPoints, cannotGenerateLatLonPoints, sn2filename); + } + + + // Write the filenames associated with outNet + WriteCubeOutList(outNet, sn2filename); + + Progress outProgress; + outProgress.SetText("Writing Control Network"); + outProgress.SetMaximumSteps(3); + outProgress.CheckStatus(); + + // Write the extracted Control Network + outNet.Write(ui.GetFilename("OUTNET")); + + outProgress.CheckStatus(); + + // Adds the remove history to the summary and results group + PvlGroup summary("ResultSummary"); + PvlGroup results("Results"); + + if(noIgnore) { + summary.AddKeyword(PvlKeyword("IgnoredPoints", iString((int)ignoredPoints.size()))); + summary.AddKeyword(PvlKeyword("IgnoredMeasures", iString((int)ignoredMeasures.size()))); + } + if(noHeld) { + summary.AddKeyword(PvlKeyword("HeldPoints", iString((int)heldPoints.size()))); + } + if(noSingleMeasure) { + summary.AddKeyword(PvlKeyword("SingleMeasurePoints", iString((int)singleMeasurePoints.size()))); + } + if(noMeasureless) { + summary.AddKeyword(PvlKeyword("MeasurelessPoints", iString((int)measurelessPoints.size()))); + } + if(noTolerancePoints) { + summary.AddKeyword(PvlKeyword("TolerancePoints", iString((int)tolerancePoints.size()))); + } + if(reference) { + summary.AddKeyword(PvlKeyword("NonReferenceMeasures", iString((int)nonReferenceMeasures.size()))); + } + if(ground) { + summary.AddKeyword(PvlKeyword("NonGroundPoints", iString((int)nonGroundPoints.size()))); + } + if(cubePoints) { + summary.AddKeyword(PvlKeyword("NonCubePoints", iString((int)nonCubePoints.size()))); + } + if(noMeasurePoints.size() != 0) { + summary.AddKeyword(PvlKeyword("NoCubeMeasure", iString((int)noMeasurePoints.size()))); + } + if(cubeMeasures) { + summary.AddKeyword(PvlKeyword("NoMeasurePoints", iString((int)noCubeMeasures.size()))); + } + if(pointsEntered) { + summary.AddKeyword(PvlKeyword("NonListedPoints", iString((int)nonListedPoints.size()))); + } + if(latLon) { + summary.AddKeyword(PvlKeyword("LatLonOutOfRange", iString((int)nonLatLonPoints.size()))); + summary.AddKeyword(PvlKeyword("NoLatLonPoints", iString((int)cannotGenerateLatLonPoints.size()))); + } + + outProgress.CheckStatus(); + + // Log Control Net results + Application::Log(summary); + + outProgress.CheckStatus(); + + if(ui.WasEntered("PREFIX")) { + Progress resultsProgress; + resultsProgress.SetText("Writing Results"); + resultsProgress.SetMaximumSteps(12); + resultsProgress.CheckStatus(); + + string prefix = ui.GetString("PREFIX"); + + if(noIgnore) { + string namecp(Filename(prefix + "IgnoredPoints.txt").Expanded()); + WriteResults(namecp, ignoredPoints); + string namecm(Filename(prefix + "IgnoredMeasures.txt").Expanded()); + WriteResults(namecm, ignoredMeasures); + } + + resultsProgress.CheckStatus(); + + if(noHeld) { + string name(Filename(prefix + "HeldPoints.txt").Expanded()); + WriteResults(name, heldPoints); + } + + resultsProgress.CheckStatus(); + + if(noSingleMeasure) { + string name(Filename(prefix + "SingleMeasurePoints.txt").Expanded()); + WriteResults(name, singleMeasurePoints); + } + + resultsProgress.CheckStatus(); + + if(noMeasureless) { + string name(Filename(prefix + "MeasurelessPoints.txt").Expanded()); + WriteResults(name, measurelessPoints); + } + + resultsProgress.CheckStatus(); + + if(noTolerancePoints) { + string name(Filename(prefix + "TolerancePoints.txt").Expanded()); + WriteResults(name, tolerancePoints); + } + + resultsProgress.CheckStatus(); + + if(reference) { + string name(Filename(prefix + "NonReferenceMeasures.txt").Expanded()); + WriteResults(name, nonReferenceMeasures); + } + + resultsProgress.CheckStatus(); + + if(ground) { + string name(Filename(prefix + "NonGroundPoints.txt").Expanded()); + WriteResults(name, nonGroundPoints); + } + + resultsProgress.CheckStatus(); + + if(cubePoints) { + string name(Filename(prefix + "NonCubePoints.txt").Expanded()); + WriteResults(name, nonCubePoints); + } + + resultsProgress.CheckStatus(); + + if(noMeasurePoints.size() != 0) { + string name(Filename(prefix + "NoMeasurePoints.txt").Expanded()); + WriteResults(name, noMeasurePoints); + } + + resultsProgress.CheckStatus(); + + if(cubeMeasures) { + string name(Filename(prefix + "NonCubeMeasures.txt").Expanded()); + WriteResults(name, noCubeMeasures); + } + + resultsProgress.CheckStatus(); + + if(pointsEntered) { + string name(Filename(prefix + "NonListedPoints.txt").Expanded()); + WriteResults(name, nonListedPoints); + } + + resultsProgress.CheckStatus(); + + if(latLon) { + string namenon(Filename(prefix + "LatLonOutOfRange.txt").Expanded()); + WriteResults(namenon, nonLatLonPoints); + string namegen(Filename(prefix + "NoLatLonPoints.txt").Expanded()); + WriteResults(namegen, cannotGenerateLatLonPoints); + } + + results.AddComment("Each keyword represents a filter parameter used." \ + " Check the documentation for specific keyword descriptions."); + Application::Log(results); + + resultsProgress.CheckStatus(); + } + +} + + +/** + * Removes control points not listed in POINTLIST + * + * @param outNet The output control net being removed from + * @param nonListedPoints The keyword recording all of the control points + * removed due to not being listed + */ +void ExtractPointList(ControlNet &outNet, vector & nonListedPoints) { + UserInterface &ui = Application::GetUserInterface(); + + FileList listedPoints(ui.GetFilename("POINTLIST")); + + for(int cp = outNet.Size() - 1; cp >= 0; cp --) { + bool isInList = false; + for(int pointId = 0; pointId < (int)listedPoints.size() && !isInList; pointId ++) { + isInList = outNet[cp].Id().compare(listedPoints[pointId]) == 0; + } + + if(!isInList) { + nonListedPoints.push_back(outNet[cp].Id()); + outNet.Delete(cp); + } + } +} + + +/** + * Removes control points not in the lat/lon range provided in the unput + * parameters. + * + * @param outNet The output control net being removed from + * @param noLanLonPoint The keyword recording all of the control points removed + * due to the provided lat/lon range + * @param noLanLonPoint The keyword recording all of the control points removed + * due to the inability to calculate the lat/lon for that + * point + */ +void ExtractLatLonRange(ControlNet &outNet, vector & nonLatLonPoints, + vector & cannotGenerateLatLonPoints, map sn2filename) { + if(outNet.Size() == 0) { + return; + } + + UserInterface &ui = Application::GetUserInterface(); + + // Get the lat/lon and fix the range for the internal 0/360 + double minlat = ui.GetDouble("MINLAT"); + double maxlat = ui.GetDouble("MAXLAT"); + double minlon = ui.GetDouble("MINLON"); + if(minlon < 0.0) { + minlon += 360; + } + double maxlon = ui.GetDouble("MAXLON"); + if(maxlon < 0.0) { + minlon += 360; + } + + Progress progress; + progress.SetText("Calculating lat/lon"); + progress.SetMaximumSteps(outNet.Size()); + progress.CheckStatus(); + + CubeManager manager; + manager.SetNumOpenCubes(50); //Should keep memory usage to around 1GB + + for(int cp = outNet.Size() - 1; cp >= 0; cp --) { + progress.CheckStatus(); + + // If the Contorl Network takes priority, use it + double pointLat = outNet[cp].UniversalLatitude(); + double pointLon = outNet[cp].UniversalLongitude(); + bool hasLatLon = pointLat != Isis::Null && pointLon != Isis::Null; + if(outNet[cp].Type() == Isis::ControlPoint::Ground || hasLatLon) { + if(NotInLatLonRange(pointLat, pointLon, minlat, maxlat, minlon, maxlon)) { + nonLatLonPoints.push_back(outNet[cp].Id()); + outNet.Delete(cp); + } + } + + /** + * If the lat/lon cannot be determined from the point, then we need to calculate + * lat/lon on our own + */ + else if(ui.WasEntered("FROMLIST")) { + + // Find a cube in the Control Point to get the lat/lon from + int cm = 0; + iString sn = ""; + double lat = 0.0; + double lon = 0.0; + double radius = 0.0; + + // First check the reference Measure + if(outNet[cp].HasReference()) { + cm = outNet[cp].ReferenceIndex(); + if(!sn2filename[outNet[cp][cm].CubeSerialNumber()].empty()) { + sn = outNet[cp][cm].CubeSerialNumber(); + } + } + + // Search for other Control Measures if needed + if(sn.empty()) { + // Find the Serial Number if it exists + for(int cm = 0; (cm < outNet[cp].Size()) && sn.empty(); cm ++) { + if(!sn2filename[outNet[cp][cm].CubeSerialNumber()].empty()) { + sn = outNet[cp][cm].CubeSerialNumber(); + } + } + } + + // Connot fine a cube to get the lat/lon from + if(sn.empty()) { + //cannotGenerateLatLonPoints += outNet[cp].Id(); + cannotGenerateLatLonPoints.push_back(outNet[cp].Id()); + outNet.Delete(cp); + } + + // Calculate the lat/lon and check for validity + else { + bool remove = false; + + Cube *cube = manager.OpenCube(sn2filename[sn]); + Camera *camera = cube->Camera(); + + if(camera == NULL) { + try { + Projection *projection = ProjectionFactory::Create((*(cube->Label()))); + + if(!projection->SetCoordinate(outNet[cp][cm].Sample(), outNet[cp][cm].Line())) { + nonLatLonPoints.push_back(outNet[cp].Id()); + remove = true; + } + + lat = projection->Latitude(); + lon = projection->Longitude(); + radius = projection->LocalRadius(); + + delete projection; + projection = NULL; + } + catch(iException &e) { + remove = true; + e.Clear(); + } + } + else { + if(!camera->SetImage(outNet[cp][cm].Sample(), outNet[cp][cm].Line())) { + nonLatLonPoints.push_back(outNet[cp].Id()); + remove = true; + } + + lat = camera->UniversalLatitude(); + lon = camera->UniversalLongitude(); + radius = camera->LocalRadius(); + + camera = NULL; + } + + cube = NULL; + + if(remove || NotInLatLonRange(lat, lon, minlat, maxlat, minlon, maxlon)) { + nonLatLonPoints.push_back(outNet[cp].Id()); + outNet.Delete(cp); + } + else { // Add the reference lat/lon/radius to the Control Point + outNet[cp].SetUniversalGround(lat, lon, radius); + } + } + } + else { + cannotGenerateLatLonPoints.push_back(outNet[cp].Id()); + outNet.Delete(cp); + } + + } + + manager.CleanCubes(); +} + + +/** + * Checks for correct lat/lon range, handling the meridian correctly + * + * @param lat The latitude to check + * @param lon The longitude to check + * @param minlat Minimum Latitude Minimum valid latitude + * @param maxlat Maximum Latitude Maximum valid latitude + * @param minlon Minimum Longitude Minimum valid longitude + * @param maxlon Maximum Longitude Maximum valid longitude + * + * @return bool True when the range is valid + */ +bool NotInLatLonRange(double lat, double lon, double minlat, + double maxlat, double minlon, double maxlon) { + bool inRange = true; + + // Check latitude range + if(inRange && minlat > maxlat) { + inRange &= (lat <= maxlat || lat >= minlat); + } + else if(inRange) { + inRange &= (lat >= minlat && lat <= maxlat); + } + + // Check longitude range + if(inRange && minlon > maxlon) { + inRange &= (lon <= maxlon || lon >= minlon); + } + else if(inRange) { + inRange &= (lon >= minlon && lon <= maxlon); + } + + return !inRange; +} + + +/** + * Finds and writes all input cubes contained within the given Control Network + * to the output file list + * + * @param cnet The Control Network to list the filenames contained within + * @param sn2file The map for converting the Control Network's serial numbers + * to filenames + */ +void WriteCubeOutList(ControlNet cnet, map sn2file) { + UserInterface &ui = Application::GetUserInterface(); + + if(ui.WasEntered("TOLIST")) { + + Progress p; + p.SetText("Writing Cube List"); + try { + p.SetMaximumSteps(cnet.Size()); + p.CheckStatus(); + } + catch(iException &e) { + e.Clear(); + string msg = "The provided filters have resulted in an empty Control Network."; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + + set outputsn; + for(int cp = 0; cp < cnet.Size(); cp ++) { + for(int cm = 0; cm < cnet[cp].Size(); cm ++) { + outputsn.insert(cnet[cp][cm].CubeSerialNumber()); + } + p.CheckStatus(); + } + + std::string toList = ui.GetFilename("TOLIST"); + ofstream out_stream; + out_stream.open(toList.c_str(), std::ios::out); + out_stream.seekp(0, std::ios::beg); //Start writing from beginning of file + + for(set::iterator sn = outputsn.begin(); sn != outputsn.end(); sn ++) { + if(!sn2file[(*sn)].empty()) { + out_stream << sn2file[(*sn)] << endl; + } + } + + out_stream.close(); + } +} + + +/** + * Places the output + * + * @param filename The file to write the vector of results to + * @param results A vector of points and/or measures not extracted + */ +void WriteResults(string filename, vector results) { + if(results.size() == 0) { + return; + } + + // Set up the output file for writing + ofstream out_stream; + out_stream.open(filename.c_str(), std::ios::out); + out_stream.seekp(0, std::ios::beg); //Start writing from beginning of file + + out_stream << results[0]; + for(unsigned int index = 1; index < results.size(); index ++) { + out_stream << std::endl << results[index]; + } + + out_stream.close(); +} diff --git a/isis/src/base/apps/cnetextract/cnetextract.xml b/isis/src/base/apps/cnetextract/cnetextract.xml new file mode 100644 index 0000000000000000000000000000000000000000..fa0c26d25317f35795558ec38972021fdb32a528 --- /dev/null +++ b/isis/src/base/apps/cnetextract/cnetextract.xml @@ -0,0 +1,507 @@ + + + + + + Extracts portions of an existing Control Network + + + +

    Extracts Control Points into a new Control Network from a specified Control + Network in accordance to specified filters.

    + +

    A summary of the Control Points not extracted, listed by the filter which + prevented them from being extracted, will be included in the record. See + the filter keywords for details.

    + +

    Currently, the filters are divided into four categories: Exclusive Filters, + Inclusive Filters, Cube Filters, and Lat/Lon Filters.

    + +

    Exclusive Filters prevent extraction. They are taken into consideration + last and have the highest priority. This means that if any other filter + creates a selected Exclusive Filter condition during processing, that + Exclusive Filter will prevent the extraction.
    + For example, if the Cube Filters CUBES, CUBELIST, and CUBEMEASURES are + used along with the Inclusive Filter NOSINGLEMEASURES, then an input Control + Point which contains only one cube in the CUBELIST will not be extracted, + reguardless of the number of Control Measures it had on input. This is + because NOSINGLEMEASURES will see it as a Control Point with exactly one + Control Measure and prevent its extraction.
    + If only Exclusive Filters are used, all Control Points/Measures that do not + have an exclusive property will be extracted.

    + +

    Inclusive Filters allow extraction. They only extract Control Points and/or + Measures that are included in the Inclusive Filter. In addition, each + Inclusive Filter is associated with an explicit property of the Control + Point/Measure. If more than one Inclusive Filter is selected, only Control + Points/Measures that contain all inclusive properties will be extracted.

    + +

    Cube Filters also allow extraction, however, they pertain to the + cubes contained within the Control Points/Measures.

    + +

    Lat/Lon Filters allow extraction as well, however, they only extract + Control Points/Measures that lie in the lat/lon bounding box.

    +
    + + + + Original version + + + Refactored for readability, added parameter defaults, and added detail to + the application log. + + + Added an additional output progress bar. + + + Added the points kept to the print file. + + + Fixed TOLIST blank lines, added the POINTLIST option, and changed the + CUBEPOINTS parameter to take a filename instead of a boolean. + + + Added the TOLERANCE parameter. + + + Changed the TOLERANCE keyword to extract points with an error greater + than or equal to the TOLERANCE, instead of less than or eqaul to. + + + Fixed the TOLERANCE code. + + + Fixed the interface to be more clear. + + + Added the GROUND parameter. + + + Added the USENETWORK parameter to avoid the need for spiceinit prior + to knowing which cubes are necessary for the extracted control network. + + + FROMLIST is now an option parameter, however, to be able to generate a + TOLIST, the FROMLIST must be provided. Also did some code cleanup. + + + Changed NOSINGLEMEASURES to NOMEASURELESS and fixed a simple progress + bug. + + + Fixed min/max lat/lon bounding issues. + + + Brought back NOSINGLEMEASURES while leaving NOMEASURELESS as is. + + + Added PREFIX and moved all detailed output from the print.prt to the + PREFIX files for each filter parameter. + + + Rewrote documentation and reorganized keywords into groups. + + + + + Control Networks + + + + + + + + filename + input + No input cube list + List of ISIS3 input cubes in the Control Network + + A text file containing one column of ISIS3 cube file names. Every file + used in the match point file should be represented in this list. + + + *.txt *.lis *.list + + + + + filename + input + Isis3 input Control Network file + + Use this parameter to specify the control network file to extract + the OUTNET from. + + + *.net + + + + + + + + + string + No results list + output + Outputs extraction results + + The Control Points and Control Measures not extracted will be placed + into output files with the given prefix. See each parameter in the + "Filter" group to see which files are created for each given filter + parameter. + + + + + filename + output + No output cube list + List of ISIS3 output cubes + + This text file contains one column of ISIS3 cube file names associated + with the OUTNET. This list can only include cubes that were privided + in the FROMLIST. + + + *.txt *.lis *.list + + + + + filename + output + Isis3 output Control Network file + + The resultant Control Network extracted from CNET. + + + *.net + + + + string + Parent Network Id + + Name of the extracted Control Network + + + The ID or name of the extracted Control Network. This string should + be unique. + + + + string + cnetextracted + + The description of the extracted network. + + + A string describing purpose of this extracted control network. + + + + + + + + + boolean + False + Do not extract ignored points + +

    When true, all ignored Control Points and all ignored Control + Measures provided by the input Control Net will not be included in + the output Control Network.

    + +

    When PREFIX is used, the file [PREFIX]IgnoredPoints.txt and + [PREFIX]IgnoredMeasures.txt will be created when using this parameter. + They list which Control Points and Control Measures were not + extracted due to this filter.

    +
    +
    + + + boolean + False + Do not extract held points + +

    When true, all held Control Points in the Control Net will not be + included in the output Control Network.

    + +

    When PREFIX is used, the file [PREFIX]HeldPoints.txt will be + created when using this parameter. It lists the Control Points that + were not extracted due to this filter.

    +
    +
    + + + boolean + False + Do not extract Control Points with exactly zero Control Measures + +

    When true, all Control Points that are reduced to zero Control + Measures (from other selected filters or have zero measureo on + input) will not be included in the output Control Network.

    + +

    When PREFIX is used, the file [PREFIX]MeasurelessPoints.txt will + be created when using this parameter. Each Control Point it lists was + not extracted due to this filter.

    +
    +
    + + + boolean + False + Do not extract Control Points with exactly one Control Measure + +

    When true, all Control Points that are reduced to one Control + Measure (from other selected filters or only have one measure on + input) will not be included in the output Control Network.

    + +

    When PREFIX is used, the file [PREFIX]SingleMeasurePoints.txt will + be created when using this parameter. Each Control Point it lists was + not extracted due to this filter.

    +
    + + REFERENCE + +
    + +
    + + + + + boolean + False + Only extract explicit reference Control Measures + +

    When true, only explicit reference Control Measures will be + extracted into the output Control Net.

    + +

    When this parameter is used, NOMEASURELESS will be set to TRUE + automatically, and NOSINGLEMEASURES will be disabled.

    + +

    When PREFIX is used, the file [PREFIX]NonReferenceMeasures.txt + will be created when using this parameter. Each Control Measure it + contains was not extracted due to this filter.

    +
    + + NOSINGLEMEASURES + +
    + + + boolean + False + Only extract ground Control Points + +

    When true, only ground Control Points will be extracted into the + output Control Net.

    + +

    When PREFIX is used, the file [PREFIX]NonGroundPoints.txt will be + created when using this parameter. Each Control Point it lists was not + extracted due to this filter.

    +
    +
    + + + boolean + False + Only extract Control Points with line or sample errors greater than PIXELTOLERANCE + +

    When true, extract all Control Points which have a line or a + sample error greater than or equal to the PIXELTOLERANCE value.

    + +

    The PIXELTOLERANCE is compared to the keywords ErrorLine and + ErrorSample.

    + +

    When PREFIX is used, the file [PREFIX]TolerancePoints.txt will be + created when using this parameter. Each Control Point it lists was not + extracted due to this filter.

    +
    + + PIXELTOLERANCE + +
    + + double + 10.0 + Only extract Control Points with a line or sample error greater than this value + + Control Points which contain at least one Control Measure with a line + or a sample error greater than or equal to this value will be extracted. + + + + + filename + input + None + File containing Control Point Ids which will be extracted + +

    Use this parameter to select the filename which contains a list of + point ids. All the Control Points with matching Ids will be extracted + as long as another seleted filter does not exclude the Control + Point.

    + +

    When PREFIX is used, the file [PREFIX]NonListedPoints.txt will be + created when using this parameter. Each Control Point it contains was + not extracted due to this filter.

    +
    + + *.lis + +
    + +
    + + + + + boolean + False + Only extract Control Points/Measures based on listed cubes + + When selected, only Control Points which contain the cubes listed in + CUBEPOINTS will be extracted. + + + CUBELIST + CUBEMEASURES + + + + + filename + input + Only extract Control Points containing the listed cubes + +

    Use this parameter to select the filename which contains a list of + cubes. All the Control Points which contain at least on of these + cubes will be extracted.

    + +

    When PREFIX is used, the file [PREFIX]NonCubePoints.txt will be + created when using this option. Each Control Point it lists was not + extracted due to this filter.

    +
    + + *.lis + +
    + + boolean + False + Only extract Control Measures containing a cube in CUBEPOINTS + +

    When true, remove all Control Measures from extracted Control + Points which do not contain a cube from the CUBEPOINTS list. + This option can only be used when a file has been provided for + CUBEPOINTS.

    + +

    When this parameter is used, NOMEASURELESS will be set to TRUE + automatically.

    + +

    When PREFIX is used, the file [PREFIX]NonCubeMeasures.txt will be + created when using this option. Each Control Measure it lists was not + extracted due to this filter.

    +
    +
    + +
    + + + + + boolean + False + Only extract Control Points in the lat/lon range + +

    When true, all Control Points that are outside of the provided + latitude longitude range will be removed. Control Points whos + latitude longitude cannot be computed will be removed.

    + +

    Ground Points will use the lat/lon values provided in the CNET + while Tie Points will calculate their lat/lon from the images + provided by the FROMLIST. These calculated lat/lon values will be + added to Tie Point in the OUTNET for reference purposes. No Isis + application will use these added Control Point keywords.

    + +

    When PREFIX is used, the files [PREFIX]LatLonOutOfRange.txt and + [PREFIX]NoLatLonPoint.txt will be created when using this option. + Each Control Point they list was not extracted due to this filter. + Control Points in [PREFIX]LatLonOutOfRange.txt did not fall within + the provided lat/lon bound. Each Control Points listed in + [PREFIX]NoLatLonPoint.txt do not have a determinable Latitude or + Longitude.

    + +

    Note: This option is expensive.

    +
    + + MINLAT + MAXLAT + MINLON + MAXLON + +
    + + double + -90.0 + -90.0 + 90.0 + Minimum Control Point Latitude + + Any Control Point with a latitude less than LATMIN will be removed. + + + + double + 90.0 + -90.0 + 90.0 + Maximum Control Point Latitude + + Any Control Point with a latitude greater than LATMAX will be removed. + + + + double + 0.0 + -180.0 + 360.0 + Minimum Control Point Longitude + +

    Any Control Point with a longitude less than LONMIN will be + removed.

    + +

    If MINLON is greater than MAXLON than the latitude range is + assumed to cross the 0/360 latitude boundry, where points with + latitudes greater than MINLON or less than MAXLON will be + included.

    +
    +
    + + double + 360.0 + -180.0 + 360.0 + Maximum Control Point Longitude + +

    Any Control Point with a longitude greater than LONMAX will be + removed.

    + +

    If MAXLON is less than MINLON than the latitude range is assumed + to cross the 0/360 latitude boundry, where points with latitudes + greater than MINLON or less than MAXLON will be included.

    +
    +
    + +
    + +
    + +
    diff --git a/isis/src/base/apps/cnetextract/tsts/Makefile b/isis/src/base/apps/cnetextract/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cnetextract/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cnetextract/tsts/basic/Makefile b/isis/src/base/apps/cnetextract/tsts/basic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c377bf95dcddd08b2e321e9c5f7876d8bdbcc515 --- /dev/null +++ b/isis/src/base/apps/cnetextract/tsts/basic/Makefile @@ -0,0 +1,13 @@ +APPNAME = cnetextract + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) fromlist=$(OUTPUT)/list.lis cnet=$(INPUT)/cnet.net \ + tolist=$(OUTPUT)/newList.lis outnet=$(OUTPUT)/newNet.pvl \ + networkid=new description=new prefix=$(OUTPUT)/pre \ + noignore=true noheld=true \ + nosinglemeasure=true nomeasureless=true > /dev/null; + $(RM) $(OUTPUT)/newList.lis; + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/cnetextract/tsts/cubes/Makefile b/isis/src/base/apps/cnetextract/tsts/cubes/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ff094c4539c4c5d5cc4a08cfbcde7c6b01ceb0bc --- /dev/null +++ b/isis/src/base/apps/cnetextract/tsts/cubes/Makefile @@ -0,0 +1,18 @@ +APPNAME = cnetextract + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) fromlist=$(OUTPUT)/list.lis cnet=$(INPUT)/cnet.net \ + tolist=$(OUTPUT)/newList.lis outnet=$(OUTPUT)/newNetPoint.pvl \ + networkid=new description=new prefix=$(OUTPUT)/point \ + noignore=true noheld=true \ + cubes=true cubelist=$(OUTPUT)/list.lis > /dev/null; + $(APPNAME) fromlist=$(OUTPUT)/list.lis cnet=$(INPUT)/cnet.net \ + tolist=$(OUTPUT)/newList.lis outnet=$(OUTPUT)/newNetMeasure.pvl \ + networkid=new description=new prefix=$(OUTPUT)/measure \ + noignore=true noheld=true \ + cubes=true cubelist=$(OUTPUT)/list.lis cubemeasures=true > /dev/null; + $(RM) $(OUTPUT)/newList.lis; + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/cnetextract/tsts/latlon/Makefile b/isis/src/base/apps/cnetextract/tsts/latlon/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2f2d449b49081bb08acc38d04c095c62fe03e20e --- /dev/null +++ b/isis/src/base/apps/cnetextract/tsts/latlon/Makefile @@ -0,0 +1,12 @@ +APPNAME = cnetextract + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) fromlist=$(OUTPUT)/list.lis cnet=$(INPUT)/cnet.net \ + tolist=$(OUTPUT)/newList.lis outnet=$(OUTPUT)/newNet.pvl \ + networkid=new description=new prefix=$(OUTPUT)/out \ + latlon=true minlat=15.0 maxlat=28.0 minlon=20.0 maxlon=28.0 > /dev/null; + $(RM) $(OUTPUT)/newList.lis; + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/cnetextract/tsts/nofromlist/Makefile b/isis/src/base/apps/cnetextract/tsts/nofromlist/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a3f5774b8b8d98eeb46a7b2f159a669628a66238 --- /dev/null +++ b/isis/src/base/apps/cnetextract/tsts/nofromlist/Makefile @@ -0,0 +1,8 @@ +APPNAME = cnetextract + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) cnet=$(INPUT)/cnet.net outnet=$(OUTPUT)/newNet.pvl \ + networkid=new description=new prefix=$(OUTPUT)/out \ + noignore=true noheld=true nomeasureless=true > /dev/null; diff --git a/isis/src/base/apps/cnetextract/tsts/pointlist/Makefile b/isis/src/base/apps/cnetextract/tsts/pointlist/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0486be694451131d523ba68dcc74192107d01556 --- /dev/null +++ b/isis/src/base/apps/cnetextract/tsts/pointlist/Makefile @@ -0,0 +1,13 @@ +APPNAME = cnetextract + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) fromlist=$(OUTPUT)/list.lis cnet=$(INPUT)/cnet.net \ + tolist=$(OUTPUT)/newList.lis outnet=$(OUTPUT)/newNet.pvl \ + networkid=new description=new prefix=$(OUTPUT)/out \ + noignore=true nomeasureless=true \ + pointlist=$(INPUT)/points.lis > /dev/null; + $(RM) $(OUTPUT)/newList.lis; + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/cnetextract/tsts/reference/Makefile b/isis/src/base/apps/cnetextract/tsts/reference/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..678df34cc7d4647017daf402748ebe9e75d4d3e5 --- /dev/null +++ b/isis/src/base/apps/cnetextract/tsts/reference/Makefile @@ -0,0 +1,12 @@ +APPNAME = cnetextract + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) fromlist=$(OUTPUT)/list.lis cnet=$(INPUT)/cnet.net \ + tolist=$(OUTPUT)/newList.lis outnet=$(OUTPUT)/newNet.pvl \ + networkid=new description=new prefix=$(OUTPUT)/out \ + reference=true > /dev/null; + $(RM) $(OUTPUT)/newList.lis; + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/cnetextract/tsts/tolerance/Makefile b/isis/src/base/apps/cnetextract/tsts/tolerance/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a8f4ec6ca4ec07b3e7b5bce9ec69a17134dee2cd --- /dev/null +++ b/isis/src/base/apps/cnetextract/tsts/tolerance/Makefile @@ -0,0 +1,12 @@ +APPNAME = cnetextract + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) fromlist=$(OUTPUT)/list.lis cnet=$(INPUT)/cnet.net \ + tolist=$(OUTPUT)/newList.lis outnet=$(OUTPUT)/newNet.pvl \ + networkid=new description=new prefix=$(OUTPUT)/out \ + nomeasureless=true tolerance=true pixel=8.0 > /dev/null; + $(RM) $(OUTPUT)/newList.lis; + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/cnetmerge/Makefile b/isis/src/base/apps/cnetmerge/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cnetmerge/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cnetmerge/cnetmerge.cpp b/isis/src/base/apps/cnetmerge/cnetmerge.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6ba0e95fe6cf0d0da7f122707081916578151e89 --- /dev/null +++ b/isis/src/base/apps/cnetmerge/cnetmerge.cpp @@ -0,0 +1,241 @@ +#include "Isis.h" + +#include + +#include "ControlNet.h" +#include "FileList.h" +#include "iException.h" +#include "iTime.h" +#include "Progress.h" + +using namespace std; +using namespace Isis; + +ControlPoint MergePoints( ControlPoint master, ControlPoint mergee, bool allowReferenceOverride, bool & needsReport ); + +// Main program +void IsisMain() { + // Get user parameters + UserInterface &ui = Application::GetUserInterface(); + FileList filelist; + if( ui.GetString("INPUTTYPE") == "LIST" ) { + filelist = ui.GetFilename("FROMLIST"); + } + else if ( ui.GetString("INPUTTYPE") == "CNETS" ) { + filelist.push_back( ui.GetFilename("FROM1") ); + filelist.push_back( ui.GetFilename("FROM2") ); + } + Filename outfile( ui.GetFilename("TO") ); + + bool allowPointOverride = false; + bool allowMeasureOverride = false; + if ( ui.GetString("DUPLICATEPOINTS") == "MERGE" ) { + allowPointOverride = ui.GetBoolean("OVERWRITEPOINTS"); + allowMeasureOverride = ui.GetBoolean("OVERWRITEMEASURES"); + } + + // Creates a Progress + Progress progress; + progress.SetMaximumSteps( filelist.size() ); + progress.CheckStatus(); + + // Set up the output ControlNet with the first Control Net in the list + ControlNet cnet( Filename(filelist[0]).Expanded() ); + cnet.SetNetworkId( ui.GetString("ID") ); + cnet.SetUserName( Isis::Application::UserName() ); + cnet.SetCreatedDate( Isis::Application::DateTime() ); + cnet.SetModifiedDate( Isis::iTime::CurrentLocalTime() ); + cnet.SetDescription( ui.GetString("DESCRIPTION") ); + + progress.CheckStatus(); + + ofstream ss; + bool report = false; + if( ui.WasEntered("REPORT") ) { + report = true; + string report = ui.GetFilename("REPORT"); + ss.open(report.c_str(),ios::out); + } + + for ( int f = 1; f < (int)filelist.size(); f ++ ) { + + ControlNet currentnet( Filename(filelist[f]).Expanded() ); + + // Checks to make sure the ControlNets are valid to merge + if ( cnet.Target() != currentnet.Target() ) { + string msg = "Input [" + currentnet.NetworkId() + "] does not target the "; + msg += "same target as other Control Nets."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // ERROR + if ( ui.GetString("DUPLICATEPOINTS") == "ERROR" ) { + + // Throws an error if there is a duplicate Control Point + for ( int cp=0; cpType() == ControlPoint::Ground && currentnet[cp].Type() == ControlPoint::Tie) + || (dupPoint->Held() && !currentnet[cp].Held()) ) { + ControlPoint mergedPoint = MergePoints( *dupPoint, currentnet[cp], !allowMeasureOverride, needsReport ); + + if( report && needsReport ) { + ss << " Control Measures from " << currentnet[cp].Id() << " were not merged due to conflicts." << endl; + } + + cnet.Delete( currentnet[cp].Id() ); + cnet.Add( mergedPoint ); + } + + else if ( (dupPoint->Type() == ControlPoint::Ground && currentnet[cp].Type() == ControlPoint::Ground) + || (dupPoint->Held() && currentnet[cp].Held()) ) { + + // See if there are conflicts in merging the 2 points + bool hasPointConflict = false; + if ( dupPoint->UniversalLatitude() > DBL_MIN && + dupPoint->UniversalLongitude() > DBL_MIN && + dupPoint->UniversalLatitude() == currentnet[cp].UniversalLatitude() && + dupPoint->UniversalLongitude() == currentnet[cp].UniversalLongitude() ) { + hasPointConflict = true; + } + + // Merge the Control Points correctly + if ( hasPointConflict ) { + if ( allowPointOverride ) { + ControlPoint mergedPoint = MergePoints( currentnet[cp], *dupPoint, allowMeasureOverride, needsReport ); + + if( report && needsReport ) { + ss << " Control Measures from " << currentnet[cp].Id() << " were not merged due to conflicts." << endl; + } + + cnet.Delete( currentnet[cp].Id() ); + cnet.Add( mergedPoint ); + } + else { + if( report ) { + ss << " The merge of Control Point " << currentnet[cp].Id() << " was canceled due to conflicts." << endl; + } + // These 3 lines keep cnet's points in order with an "unnecessary" delete + ControlPoint copyPoint = (*dupPoint); + cnet.Delete( currentnet[cp].Id() ); + cnet.Add( copyPoint ); + } + } + else { + ControlPoint mergedPoint = MergePoints( currentnet[cp], *dupPoint, allowMeasureOverride, needsReport ); + + if( report && needsReport ) { + ss << " Control Measures from " << currentnet[cp].Id() << " were not merged due to conflicts." << endl; + } + + cnet.Delete( currentnet[cp].Id() ); + cnet.Add( mergedPoint ); + } + } + + else { + ControlPoint mergedPoint = MergePoints( currentnet[cp], *dupPoint, allowMeasureOverride, needsReport ); + + if( report && needsReport ) { + ss << " Control Measures from " << currentnet[cp].Id() << " were not merged due to conflicts." << endl; + } + + cnet.Delete( currentnet[cp].Id() ); + cnet.Add( mergedPoint ); + } + + dupPoint = NULL; + } catch ( iException &e ) { + e.Clear(); + //then currentnet[i] was not found and was not deleted so: + //Add the point to the output ControlNet + cnet.Add( currentnet[cp] ); + } + } + + } + + progress.CheckStatus(); + } + + // Writes out the final Control Net + cnet.Write( outfile.Expanded() ); + +} + + +ControlPoint MergePoints( ControlPoint master, ControlPoint mergee, bool allowReferenceOverride, bool & needsReport ) { + ControlPoint newPoint = master; + + // Merge mergee measures into newPoint + for ( int cm = 0; cm < mergee.Size(); cm ++ ) { + bool merged = false; + + // Check for duplicate measures to know when to keep "older" measures + for ( int newcm = 0; newcm < newPoint.Size() && !merged; newcm ++ ) { + if ( mergee[cm].CubeSerialNumber() == newPoint[newcm].CubeSerialNumber() ) { + + if ( (mergee.Type() == ControlPoint::Ground || newPoint.Held()) ) { + if ( !allowReferenceOverride ) { + // Remove new measure, pull old measure, and Report that the new wasn't merged + if (mergee[cm].IsReference() && !newPoint[newcm].IsReference() && newPoint.HasReference() ) { + newPoint[newPoint.ReferenceIndex()].SetReference( false ); + } + newPoint[newcm] = mergee[cm]; + needsReport |= true; + } + } + + merged = true; + } + } + + // If no duplicate measure was found + if( !merged ) { + if ( newPoint.HasReference() && mergee[cm].IsReference() ) { + if ( allowReferenceOverride ) { + // Remove reference to old Measure and pull it over + mergee[cm].SetReference( false ); + newPoint.Add( mergee[cm] ); + } + else { + // Remove Reference from new measure and Report that it wasn't allowed + newPoint[newPoint.ReferenceIndex()].SetReference( false ); + newPoint.Add( mergee[cm] ); + needsReport |= true; + } + } + else { + newPoint.Add( mergee[cm] ); + } + } + } + + return newPoint; +} diff --git a/isis/src/base/apps/cnetmerge/cnetmerge.xml b/isis/src/base/apps/cnetmerge/cnetmerge.xml new file mode 100644 index 0000000000000000000000000000000000000000..1ecdffc45767f5fc765ae9910e32d57c3f180879 --- /dev/null +++ b/isis/src/base/apps/cnetmerge/cnetmerge.xml @@ -0,0 +1,255 @@ + + + + + + Merges 2 ControlNets into one. + + + +

    + Merges 2 Control Nets into a single Control Net. Each Control Net must + share the same target, and be of the same type (i .e. Singleton, + ImageToImage, ImageToGround ). +

    +
    + + + + Original version + + + Clarified error messages and added documentation. (Removed netmerge from + the system, because it did the same thing, just not quite as clean) + + + Fix xml app name error + + + Rebuilt for more Control Point Id control, including a REPLACE option. + Only FORCE prefixes the original Control Network Id to the new Control + Point Ids, then logs the number of duplicate Control Points. NORMAL and + REPLACE leave the Control Point Ids alone. + + + Added the FROMLIST input option. + + + Changed MERGETYPE param name and options to be more clear. Changed MODE + to INPUTTYPE. Added the REPORT param which reveals any Control Points + that have been renamed or replaced durring the merge. + + + Added Filename expansion to the listed nets and a few other minor + readability changes. + + + Multiple changes based on user request, including removal of RENAME, + replacing REPLACE with MERGE while merging at the Control Measure level. + + + Changed an outdated error message. + + + + + Control Networks + + + + + + + + string + LIST + File I/O options + + There is a choice to simply specify input cubes directly, use a list of input cubes in a text file, or to create output data only. + + + + + + + + + filename + input + + Input list file + + + This file contains a list of all the Control Nets to be merged + + + *.txt *.lis *.list *.lst + + + + + filename + input + + Input ControlNet + + + The first ControlNet to be merged. + + + *.ctl *.pvl *.net + + + + + filename + input + + Input ControlNet + + + The second ControlNet to be merged. + + + *.ctl *.pvl *.net + + + + + + + + + filename + output + + Merged ControlNet + + + The output ControlNet, which is the merged result of the two input + ControlNets. + + + *.ctl *.pvl *.net + + + + + filename + output + No Report Output + + Reports Control Points that were renamed or replaced + + + This file will contain a report that reveals all Control Points that + were renamed or replaced. If no Control Points were renamed or + replaced, than this file will be empty. + + + + + + + + + string + The NetworkId for the merged ControlNet + + The NetworkId keyword for the new merged ControlNet will be set to the + given value. + + + + + string + The Description for the merged ControlNet + + The Descrition keyword for the new merged ControlNet will be set to the + given value. + + + + + string + Defines how duplicate Control Points are handled + ERROR + + This parameter is used to specify how duplicate Control Points of the + given Control Networks are handled when merging. + + + + + + + + + boolean + False + Merge conficting Control Points + + Whenever a latitude or a longitude value has been changed on a held + or ground Control Point, then the changed values will be merged when + this parameter is TRUE. If this parameter is FALSE and a change is + found, the change will be noted in the REPORT file, but will not be + merged in the final output. + + + + + boolean + False + Merge conficting Control Measures + + Whenever a the reference measure has been changed in a held or + ground Control Measure, then the change will be merged when this + parameter is TRUE. If this parameter is FALSE and a reference measure + change is found, the change will be noted in the REPORT file, but + will not be merged in the final output. + + + + + + + +
    diff --git a/isis/src/base/apps/cnetmerge/tsts/Makefile b/isis/src/base/apps/cnetmerge/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cnetmerge/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cnetmerge/tsts/default/Makefile b/isis/src/base/apps/cnetmerge/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5a3e4472a7da04082e226f7e991c1530e00c1a4f --- /dev/null +++ b/isis/src/base/apps/cnetmerge/tsts/default/Makefile @@ -0,0 +1,12 @@ +APPNAME = cnetmerge + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) INPUTTYPE=cnets \ + FROM1=$(INPUT)/testNet.ctl \ + FROM2=$(INPUT)/testNet2.ctl \ + TO=$(OUTPUT)/testReplace.pvl \ + DUPLICATEPOINTS=merge \ + ID=testReplaceMerge DESCRIPTION=NewTextCtl \ + > /dev/null; diff --git a/isis/src/base/apps/cnetmerge/tsts/duplication/Makefile b/isis/src/base/apps/cnetmerge/tsts/duplication/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2c6501d593f47f14993972bda40b934f13edffe6 --- /dev/null +++ b/isis/src/base/apps/cnetmerge/tsts/duplication/Makefile @@ -0,0 +1,13 @@ +APPNAME = cnetmerge + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) INPUTTYPE=cnets \ + FROM1=$(INPUT)/testNet.ctl \ + FROM2=$(INPUT)/testNet2.ctl \ + TO=$(OUTPUT)/testReplace.pvl \ + DUPLICATEPOINTS=merge \ + REPORT=$(OUTPUT)/report.txt \ + ID=testReplaceMerge DESCRIPTION=NewTextCtl \ + > /dev/null; diff --git a/isis/src/base/apps/cnetmerge/tsts/ground/Makefile b/isis/src/base/apps/cnetmerge/tsts/ground/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..abca4d6021e1d4b1770825e9d83ba78d749b5637 --- /dev/null +++ b/isis/src/base/apps/cnetmerge/tsts/ground/Makefile @@ -0,0 +1,22 @@ +APPNAME = cnetmerge + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) INPUTTYPE=cnets \ + FROM1=$(INPUT)/testNetGround.ctl \ + FROM2=$(INPUT)/testNetReferences.ctl \ + TO=$(OUTPUT)/testGround.pvl \ + REPORT=$(OUTPUT)/groundReport.txt \ + DUPLICATEPOINTS=merge \ + ID=testReplaceMerge DESCRIPTION=NewTextCtl \ + > /dev/null; + $(APPNAME) INPUTTYPE=cnets \ + FROM1=$(INPUT)/testNetReferences.ctl \ + FROM2=$(INPUT)/testNetGround.ctl \ + TO=$(OUTPUT)/testReferences.pvl \ + REPORT=$(OUTPUT)/referenceReport.txt \ + DUPLICATEPOINTS=merge \ + OVERWRITEMEASURES=true \ + ID=testReplaceMerge DESCRIPTION=NewTextCtl \ + > /dev/null; diff --git a/isis/src/base/apps/cnetmerge/tsts/list/Makefile b/isis/src/base/apps/cnetmerge/tsts/list/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f758cbf858d61e27bc30be01e13fb840610b5285 --- /dev/null +++ b/isis/src/base/apps/cnetmerge/tsts/list/Makefile @@ -0,0 +1,14 @@ +APPNAME = cnetmerge + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.ctl > $(OUTPUT)/list.lis; + $(APPNAME) INPUTTYPE=list \ + FROMLIST=$(OUTPUT)/list.lis \ + TO=$(OUTPUT)/testReplace.pvl \ + DUPLICATEPOINTS=merge \ + REPORT=$(OUTPUT)/report.txt \ + ID=testReplaceMerge DESCRIPTION=NewTextCtl \ + > /dev/null; + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/cnetnewradii/Makefile b/isis/src/base/apps/cnetnewradii/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cnetnewradii/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cnetnewradii/assets/failures.pvl b/isis/src/base/apps/cnetnewradii/assets/failures.pvl new file mode 100644 index 0000000000000000000000000000000000000000..e14bcf01d315f6fca3ea0475aeb59bca5619ceff --- /dev/null +++ b/isis/src/base/apps/cnetnewradii/assets/failures.pvl @@ -0,0 +1,10 @@ +Group = Summary + Successes = 7 + Failures = 3 +End_Group + +# A point fails if we are unable to set universal ground or if the radius calculated is a special pixel value. +Group = Failures + PointIDs = "LOLA_FEB3, LOLA_FEB4, LOLA_FEB8" +End_Group +End diff --git a/isis/src/base/apps/cnetnewradii/assets/images/cnetnewradiiGui1.jpg b/isis/src/base/apps/cnetnewradii/assets/images/cnetnewradiiGui1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3b2bc4b68c3bba9d0a373e18b4826f19b2f3203 Binary files /dev/null and b/isis/src/base/apps/cnetnewradii/assets/images/cnetnewradiiGui1.jpg differ diff --git a/isis/src/base/apps/cnetnewradii/assets/images/cnetnewradiiGui2.jpg b/isis/src/base/apps/cnetnewradii/assets/images/cnetnewradiiGui2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6a5fd16432632d35a0182485222bb79372aa52af Binary files /dev/null and b/isis/src/base/apps/cnetnewradii/assets/images/cnetnewradiiGui2.jpg differ diff --git a/isis/src/base/apps/cnetnewradii/assets/images/inputDEM1.jpg b/isis/src/base/apps/cnetnewradii/assets/images/inputDEM1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..afa469effc1b49bb23f7d385f541843ffaa5fa39 Binary files /dev/null and b/isis/src/base/apps/cnetnewradii/assets/images/inputDEM1.jpg differ diff --git a/isis/src/base/apps/cnetnewradii/assets/images/inputDEM2.jpg b/isis/src/base/apps/cnetnewradii/assets/images/inputDEM2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9e014639265809c66c20a38b7f04102534414e86 Binary files /dev/null and b/isis/src/base/apps/cnetnewradii/assets/images/inputDEM2.jpg differ diff --git a/isis/src/base/apps/cnetnewradii/assets/inputcnet.pvl b/isis/src/base/apps/cnetnewradii/assets/inputcnet.pvl new file mode 100644 index 0000000000000000000000000000000000000000..ee7a3e8f4a3604933dd0838dca10f7cba4c38638 --- /dev/null +++ b/isis/src/base/apps/cnetnewradii/assets/inputcnet.pvl @@ -0,0 +1,292 @@ +Object = ControlNetwork + NetworkId = AS15_Rev4_AutoSeed + NetworkType = ImageToGround + TargetName = MOON + UserName = tbecker + Created = 2010-03-25T17:06:31 + LastModified = 2010-03-26T05:55:56 + Description = AS15_Rev4_AutoSeed + + Object = ControlPoint + PointType = Tie + PointId = AS15R4_0003 + Latitude = -26.725494037818 + Longitude = 178.2671495273 + Radius = 1734723.8455167 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 16641.066683342 + Line = 18441.299208028 + ErrorLine = 31.371961396097 + ErrorSample = -16.188068399169 + ErrorMagnitude = 35.302316076065 + DateTime = 2010-03-26T10:22:13 + ChooserName = tbecker + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:41.097 + MeasureType = Automatic + Sample = 21165.339298552 + Line = 18388.043343993 + ErrorLine = -31.468088376383 + ErrorSample = 16.087134599038 + ErrorMagnitude = 35.341710282207 + ZScore = (-1.8265233914471, 1.7170948216629) + DateTime = 2010-03-26T11:41:48 + ChooserName = tbecker + GoodnessOfFit = 0.95831193693118 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = AS15R4_0005 + Latitude = -25.016910097201 + Longitude = 178.21447560641 + Radius = 1734024.7049447 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 15537.131784551 + Line = 11119.450685981 + ErrorLine = 23.000341737652 + ErrorSample = -18.957401500413 + ErrorMagnitude = 29.806019386973 + DateTime = 2010-03-26T11:42:21 + ChooserName = tbecker + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:41.097 + MeasureType = Estimated + Sample = 20081.654717586 + Line = 11092.839678099 + ErrorLine = -22.947521239779 + ErrorSample = 18.63295081292 + ErrorMagnitude = 29.559695313836 + ZScore = (-3.8453926445342, 2.9646044014384) + DateTime = 2010-03-26T11:42:33 + ChooserName = tbecker + GoodnessOfFit = 0.46819498859581 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB1 + Latitude = -22.405161656842 + Longitude = 175.13615189262 + Radius = 0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 1748.4133699751 + Line = 1275.0785012628 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:22:20 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB2 + Latitude = -26.739277441672 + Longitude = 175.25974417689 + Radius = 0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 4866.542991192 + Line = 19934.177686413 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:24:19 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB3 + Latitude = -26.71892681544 + Longitude = 178.70609470425 + Radius = 0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 18375.381858411 + Line = 18227.026515154 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:26:34 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB4 + Latitude = -25.24563284454 + Longitude = 178.6731813868 + Radius = 0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 17618.053743943 + Line = 11634.768048021 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:27:57 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB5 + Latitude = -22.517216023506 + Longitude = 167.84166695506 + Radius = 0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:20:44.876 + MeasureType = Estimated + Sample = 18350.011205256 + Line = 6574.6967095522 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:11:32 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB6 + Latitude = -24.371395530564 + Longitude = 164.89045242137 + Radius = 0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:20:44.876 + MeasureType = Estimated + Sample = 7538.376041843 + Line = 17849.107247623 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:12:37 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB7 + Latitude = -22.141261108836 + Longitude = 164.86824950122 + Radius = 0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:20:44.876 + MeasureType = Estimated + Sample = 5246.5491442556 + Line = 7445.4873882713 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:13:59 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB8 + Latitude = -15.815860550749 + Longitude = 143.85339030177 + Radius = 0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:27:53.464 + MeasureType = Estimated + Sample = 9677.951478109 + Line = 3420.4384955915 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:41:43 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB9 + Latitude = -18.656246410701 + Longitude = 142.57663890403 + Radius = 0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:27:53.464 + MeasureType = Estimated + Sample = 8663.5116124686 + Line = 21584.797333383 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:43:28 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB10 + Latitude = -18.518634429218 + Longitude = 144.51633135074 + Radius = 0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:27:53.464 + MeasureType = Estimated + Sample = 18870.679628564 + Line = 17207.772627622 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:44:31 + ChooserName = tbecker + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/cnetnewradii/assets/outputcnet1.pvl b/isis/src/base/apps/cnetnewradii/assets/outputcnet1.pvl new file mode 100644 index 0000000000000000000000000000000000000000..db98450d8e3159e2c6007c146e5cdaf6fef67208 --- /dev/null +++ b/isis/src/base/apps/cnetnewradii/assets/outputcnet1.pvl @@ -0,0 +1,292 @@ +Object = ControlNetwork + NetworkId = TestNetwork1 + NetworkType = ImageToGround + TargetName = MOON + UserName = jwalldren + Created = 2010-05-27T08:56:47 + LastModified = 2010-05-27T08:56:47 + Description = AS15_Rev4_AutoSeed + + Object = ControlPoint + PointType = Tie + PointId = AS15R4_0003 + Latitude = -26.725494037818 + Longitude = 178.2671495273 + Radius = 1734723.8455167 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 16641.066683342 + Line = 18441.299208028 + ErrorLine = 31.371961396097 + ErrorSample = -16.188068399169 + ErrorMagnitude = 35.302316076065 + DateTime = 2010-03-26T10:22:13 + ChooserName = tbecker + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:41.097 + MeasureType = Automatic + Sample = 21165.339298552 + Line = 18388.043343993 + ErrorLine = -31.468088376383 + ErrorSample = 16.087134599038 + ErrorMagnitude = 35.341710282206 + ZScore = (-1.8265233914471, 1.7170948216629) + DateTime = 2010-03-26T11:41:48 + ChooserName = tbecker + GoodnessOfFit = 0.95831193693118 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = AS15R4_0005 + Latitude = -25.016910097201 + Longitude = 178.21447560641 + Radius = 1734024.7049447 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 15537.131784551 + Line = 11119.450685981 + ErrorLine = 23.000341737652 + ErrorSample = -18.957401500413 + ErrorMagnitude = 29.806019386973 + DateTime = 2010-03-26T11:42:21 + ChooserName = tbecker + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:41.097 + MeasureType = Estimated + Sample = 20081.654717586 + Line = 11092.839678099 + ErrorLine = -22.947521239779 + ErrorSample = 18.63295081292 + ErrorMagnitude = 29.559695313836 + ZScore = (-3.8453926445342, 2.9646044014384) + DateTime = 2010-03-26T11:42:33 + ChooserName = tbecker + GoodnessOfFit = 0.46819498859581 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB1 + Latitude = -22.405161656842 + Longitude = 175.13615189262 + Radius = 1735886.5 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 1748.4133699751 + Line = 1275.0785012628 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:22:20 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB2 + Latitude = -26.739277441672 + Longitude = 175.25974417689 + Radius = 1733416.0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 4866.542991192 + Line = 19934.177686413 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:24:19 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB3 + Latitude = -26.71892681544 + Longitude = 178.70609470425 + Radius = 1734120.0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 18375.381858411 + Line = 18227.026515154 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:26:34 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB4 + Latitude = -25.24563284454 + Longitude = 178.6731813868 + Radius = 1735973.0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 17618.053743943 + Line = 11634.768048021 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:27:57 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB5 + Latitude = -22.517216023506 + Longitude = 167.84166695506 + Radius = 1736570.0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:20:44.876 + MeasureType = Estimated + Sample = 18350.011205256 + Line = 6574.6967095522 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:11:32 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB6 + Latitude = -24.371395530564 + Longitude = 164.89045242137 + Radius = 1737721.5 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:20:44.876 + MeasureType = Estimated + Sample = 7538.376041843 + Line = 17849.107247623 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:12:37 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB7 + Latitude = -22.141261108836 + Longitude = 164.86824950122 + Radius = 1737969.0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:20:44.876 + MeasureType = Estimated + Sample = 5246.5491442556 + Line = 7445.4873882713 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:13:59 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB8 + Latitude = -15.815860550749 + Longitude = 143.85339030177 + Radius = 1742237.0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:27:53.464 + MeasureType = Estimated + Sample = 9677.951478109 + Line = 3420.4384955915 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:41:43 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB9 + Latitude = -18.656246410701 + Longitude = 142.57663890403 + Radius = 1742204.0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:27:53.464 + MeasureType = Estimated + Sample = 8663.5116124686 + Line = 21584.797333383 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:43:28 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB10 + Latitude = -18.518634429218 + Longitude = 144.51633135074 + Radius = 1742642.5 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:27:53.464 + MeasureType = Estimated + Sample = 18870.679628564 + Line = 17207.772627622 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:44:31 + ChooserName = tbecker + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/cnetnewradii/assets/outputcnet2.pvl b/isis/src/base/apps/cnetnewradii/assets/outputcnet2.pvl new file mode 100644 index 0000000000000000000000000000000000000000..b1239af8fc905b12a08a78b7c5005d8ba29b052d --- /dev/null +++ b/isis/src/base/apps/cnetnewradii/assets/outputcnet2.pvl @@ -0,0 +1,295 @@ +Object = ControlNetwork + NetworkId = TestNetwork2 + NetworkType = ImageToGround + TargetName = MOON + UserName = jwalldren + Created = 2010-05-27T08:50:20 + LastModified = 2010-05-27T08:50:20 + Description = AS15_Rev4_AutoSeed + + Object = ControlPoint + PointType = Tie + PointId = AS15R4_0003 + Latitude = -26.725494037818 + Longitude = 178.2671495273 + Radius = 1734723.8455167 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 16641.066683342 + Line = 18441.299208028 + ErrorLine = 31.371961396097 + ErrorSample = -16.188068399169 + ErrorMagnitude = 35.302316076065 + DateTime = 2010-03-26T10:22:13 + ChooserName = tbecker + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:41.097 + MeasureType = Automatic + Sample = 21165.339298552 + Line = 18388.043343993 + ErrorLine = -31.468088376383 + ErrorSample = 16.087134599038 + ErrorMagnitude = 35.341710282206 + ZScore = (-1.8265233914471, 1.7170948216629) + DateTime = 2010-03-26T11:41:48 + ChooserName = tbecker + GoodnessOfFit = 0.95831193693118 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = AS15R4_0005 + Latitude = -25.016910097201 + Longitude = 178.21447560641 + Radius = 1734024.7049447 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 15537.131784551 + Line = 11119.450685981 + ErrorLine = 23.000341737652 + ErrorSample = -18.957401500413 + ErrorMagnitude = 29.806019386973 + DateTime = 2010-03-26T11:42:21 + ChooserName = tbecker + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:41.097 + MeasureType = Estimated + Sample = 20081.654717586 + Line = 11092.839678099 + ErrorLine = -22.947521239779 + ErrorSample = 18.63295081292 + ErrorMagnitude = 29.559695313836 + ZScore = (-3.8453926445342, 2.9646044014384) + DateTime = 2010-03-26T11:42:33 + ChooserName = tbecker + GoodnessOfFit = 0.46819498859581 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB1 + Latitude = -22.405161656842 + Longitude = 175.13615189262 + Radius = 1735887.0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 1748.4133699751 + Line = 1275.0785012628 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:22:20 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB2 + Latitude = -26.739277441672 + Longitude = 175.25974417689 + Radius = 1733416.0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 4866.542991192 + Line = 19934.177686413 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:24:19 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB3 + Latitude = -26.71892681544 + Longitude = 178.70609470425 + Radius = 0.0 + Ignore = True + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 18375.381858411 + Line = 18227.026515154 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:26:34 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB4 + Latitude = -25.24563284454 + Longitude = 178.6731813868 + Radius = 0.0 + Ignore = True + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:17:20.758 + MeasureType = Estimated + Sample = 17618.053743943 + Line = 11634.768048021 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:27:57 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB5 + Latitude = -22.517216023506 + Longitude = 167.84166695506 + Radius = 1736570.0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:20:44.876 + MeasureType = Estimated + Sample = 18350.011205256 + Line = 6574.6967095522 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:11:32 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB6 + Latitude = -24.371395530564 + Longitude = 164.89045242137 + Radius = 1737721.5 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:20:44.876 + MeasureType = Estimated + Sample = 7538.376041843 + Line = 17849.107247623 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:12:37 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB7 + Latitude = -22.141261108836 + Longitude = 164.86824950122 + Radius = 1737969.0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:20:44.876 + MeasureType = Estimated + Sample = 5246.5491442556 + Line = 7445.4873882713 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:13:59 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB8 + Latitude = -15.815860550749 + Longitude = 143.85339030177 + Radius = 0.0 + Ignore = True + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:27:53.464 + MeasureType = Estimated + Sample = 9677.951478109 + Line = 3420.4384955915 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:41:43 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB9 + Latitude = -18.656246410701 + Longitude = 142.57663890403 + Radius = 1742204.0 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:27:53.464 + MeasureType = Estimated + Sample = 8663.5116124686 + Line = 21584.797333383 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:43:28 + ChooserName = tbecker + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = LOLA_FEB10 + Latitude = -18.518634429218 + Longitude = 144.51633135074 + Radius = 1742642.5 + + Group = ControlMeasure + SerialNumber = APOLLO15/METRIC/1971-07-30T02:27:53.464 + MeasureType = Estimated + Sample = 18870.679628564 + Line = 17207.772627622 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-04-01T16:44:31 + ChooserName = tbecker + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/cnetnewradii/assets/thumbs/cnetnewradiiGui1Thumb.jpg b/isis/src/base/apps/cnetnewradii/assets/thumbs/cnetnewradiiGui1Thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c025a25e276290ab7782f566bda3058cb154426b Binary files /dev/null and b/isis/src/base/apps/cnetnewradii/assets/thumbs/cnetnewradiiGui1Thumb.jpg differ diff --git a/isis/src/base/apps/cnetnewradii/assets/thumbs/cnetnewradiiGui2Thumb.jpg b/isis/src/base/apps/cnetnewradii/assets/thumbs/cnetnewradiiGui2Thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..20c41bd240e762a4e6a7f1c14651d4e694203ab7 Binary files /dev/null and b/isis/src/base/apps/cnetnewradii/assets/thumbs/cnetnewradiiGui2Thumb.jpg differ diff --git a/isis/src/base/apps/cnetnewradii/assets/thumbs/inputDEM1Thumb.jpg b/isis/src/base/apps/cnetnewradii/assets/thumbs/inputDEM1Thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c732da82e554218239c79dbb8e34be1bcf3a4d35 Binary files /dev/null and b/isis/src/base/apps/cnetnewradii/assets/thumbs/inputDEM1Thumb.jpg differ diff --git a/isis/src/base/apps/cnetnewradii/assets/thumbs/inputDEM2Thumb.jpg b/isis/src/base/apps/cnetnewradii/assets/thumbs/inputDEM2Thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..862693840f8f39567909ad07668702ad38224409 Binary files /dev/null and b/isis/src/base/apps/cnetnewradii/assets/thumbs/inputDEM2Thumb.jpg differ diff --git a/isis/src/base/apps/cnetnewradii/cnetnewradii.cpp b/isis/src/base/apps/cnetnewradii/cnetnewradii.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74fd38a5416ca2be62b2c093b29ff29f6afe6b98 --- /dev/null +++ b/isis/src/base/apps/cnetnewradii/cnetnewradii.cpp @@ -0,0 +1,125 @@ +#include "Isis.h" + +#include + +#include "Brick.h" +#include "ControlNet.h" +#include "ControlPoint.h" +#include "Cube.h" +#include "Filename.h" +#include "iException.h" +#include "UniversalGroundMap.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + + ControlNet cnet_in (ui.GetFilename("CNET")); + ControlNet cnet_out; + + // Get input cube and get camera model for it + string from = ui.GetFilename("DEM"); + Cube cube; + cube.Open(from); +// TODO: need empty constructor to declare ugm outside try/catch +// try { + UniversalGroundMap ugm(cube); +// } catch (iException e){ +// std::string msg = "Cannot initalize UniversalGroundMap for cube [" + from + "]"; +// throw iException::Message(iException::User,msg,_FILEINFO_); +// } + + + int numSuccesses = 0; + int numFailures = 0; + string failedIDs = ""; + + for (int i=0; i < cnet_in.Size() ; i++) { + ControlPoint temp_cp = cnet_in[i]; + if(temp_cp.Type() == ControlPoint::Ground) { + // Create Brick on samp, line to get the dn value of the pixel + Brick b(1,1,1,cube.PixelType()); + bool ugSuccess = ugm.SetUniversalGround(temp_cp.UniversalLatitude(), temp_cp.UniversalLongitude()); + b.SetBasePosition((int)ugm.Sample(),(int)ugm.Line(),1); + cube.Read(b); + double newRadius = b[0]; + + // if we are unable to calculate a valid Radius value for a point, + // we will ignore this point and keep track of it + if (IsSpecial(newRadius) || ugSuccess == false){ + numFailures++; + if (numFailures > 1) { + failedIDs = failedIDs + ", "; + } + failedIDs = failedIDs + temp_cp.Id(); + temp_cp.SetIgnore(true); + } + // otherwise, we will replace the computed radius value to the output control net + else{ + numSuccesses++; + temp_cp.SetUniversalGround(temp_cp.UniversalLatitude(), temp_cp.UniversalLongitude(), newRadius); + } + } + cnet_out.Add(temp_cp); + } + + if (numSuccesses == 0) { + string msg = "No valid radii can be calculated. Verify that the DEM [" + ui.GetAsString("DEM") + "] is valid."; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + + // Propogate and Create Labels + cnet_out.SetType(cnet_in.Type()); + cnet_out.SetTarget (cnet_in.Target()); + cnet_out.SetNetworkId(ui.GetString("NETWORKID")); + cnet_out.SetUserName(Isis::Application::UserName()); + cnet_out.SetDescription(cnet_in.Description()); + cnet_out.SetCreatedDate(Isis::Application::DateTime()); + + cnet_out.Write(ui.GetFilename("TO")); + + // Write results to Logs + // Summary group is created with the counts of successes and failures + PvlGroup summaryGroup = PvlGroup("Summary"); + summaryGroup.AddKeyword(PvlKeyword("Successes", numSuccesses)); + summaryGroup.AddKeyword(PvlKeyword("Failures", numFailures)); + + bool errorlog; + Filename errorlogFile; + // if a filename was entered, use it to create the log + if (ui.WasEntered("ERRORS")) { + errorlog = true; + errorlogFile = ui.GetFilename("ERRORS"); + } + // if no filename was entered, but there were some failures, + // create an error log named "failures" in the current directory + else if (numFailures > 0) { + errorlog = true; + errorlogFile = "failures.log"; + } + // if all radii are successfully calculated and no error + // file is named, only output summary to application log + else { + errorlog = false; + } + + if (errorlog) { + // Write details in error log + Pvl results; + results.SetName("Results"); + results.AddGroup(summaryGroup); + if (numFailures > 0) { + // if there are any failures, add comment to the summary log to alert user + summaryGroup.AddComment("Unable to calculate radius for all points. Point IDs for failures contained in ["+errorlogFile.Name()+"]."); + PvlGroup failGroup = PvlGroup("Failures"); + failGroup.AddComment("A point fails if we are unable to set universal ground or if the radius calculated is a special pixel value."); + failGroup.AddKeyword(PvlKeyword("PointIDs", failedIDs)); + results.AddGroup(failGroup); + } + results.Write(errorlogFile.Expanded()); + } + // Write summary to application log + Application::Log(summaryGroup); +} diff --git a/isis/src/base/apps/cnetnewradii/cnetnewradii.xml b/isis/src/base/apps/cnetnewradii/cnetnewradii.xml new file mode 100644 index 0000000000000000000000000000000000000000..cabe95c2dda7eefe3ca0a1b6ae2ea6491748a048 --- /dev/null +++ b/isis/src/base/apps/cnetnewradii/cnetnewradii.xml @@ -0,0 +1,266 @@ + + + + + Generate new radii from DEM for a ControlNet + + + +

    + This application will go through an existing ControlNet and copy it to a new + one. When it encounters a PointType Ground it will give the latitude and + longitude to a Universal Ground Map that is generated from the DEM and ask + it for a value back. The Radius of that ControlPoint is updated with the DN + value recieved from the DEM. +

    +

    + If, for a particular point, the application fails to set the Univeral + Ground or if the Radius calculated using the DEM returns Null (or any + other special pixel value), then the input Radius value is kept and the + point is set to Ignore=true. The number of these failures + are recorded in the application's log. The Point IDs for the + corresponding control points will be listed in the ERRORS log output file. + If the user did not enter a filename for this log and there are any + points that failed, one will be created with the name "failures.log". + Note: If a significant number of ground points in the + ControlNet fail to find a new Radius value, the user should make sure + that they have input the correct DEM for the network. +

    +
    + + + Control Networks + + + + + Original Version + + + Modified to handle control points that fail to calculate a new radius as + explained in the description. Added ERRORS parameter to list PointIDs of + the control points that failed to calculate a new radius. Added filters + for input and output parameters. + + + Created examples. + + + + + + + filename + input + + Input ControlNet + + + Use this parameter to select the input ControlNet to generate the + output from. + + + *.net *.pvl *.ctl *.cnet + + + + + filename + input + + Input DEM cube + + + Use this parameter to select the DEM to use with the original + ControlNet. + + + *.cub + + + + + filename + output + + Output ControlNet file + + + Use this parameter to specify the name of the output ControlNet. + + + *.net *.pvl *.ctl *.cnet + + + + + filename + output + No Error Output + + Optional log file containing failures. + + + This file will contain the Point IDs of all control points whose + radius could not be calculated from the DEM. This happens when the + radius value is a special pixel or when the program fails to set + universal ground given the lat/lon values of the control point. + + + *.log *.pvl *.txt + + + + + + + string + + Network Id for output ControlNet + + + The user must specify the Network Id for the ouput ControlNet + + + + + + + + All ground points successfully updated + + Example of the use of cnetnewradii on a ControlNet whose ground point + lat/lon values are all contained within the given DEM. + + + + cnet=../IN/inputcnet.pvl dem=../IN/inputDEM1.cub + to=../OUT/ouputcnet1.pvl networkid=TestNetwork1 + + + In this example, cnetnewradii will take the input control network and + copy it to the output network with new Radius values calculated for + all ground points using the DN value recieved from the DEM cube. + No error log will be generated. + + + + + + + Example GUI + + + Screen shot of GUI with parameters filled in to create ControlNet + with new Radius values. + + + + + + + + Input ControlNet for cnetnewradii + + Example of an input ControlNet whose Radius values will be updated + + CNET + + + Output ControlNet for cnetnewradii + + Example of an output ControlNet corresponding to the input example + with updated Radius values. Notice that Radius values have been + updated for all ground points. + + TO + + + + + Input DEM for cnetnewradii + + Example of an input DEM cube used by cnetnewradii to update the + Radius values of ground points in the ControlNet. + + + DEM + + + + + Some ground points fail to be updated + + Example of the use of cnetnewradii on a ControlNet that contains some + ground points whose Radius can not be calculated. + + + + cnet=../IN/inputcnet.pvl dem=../IN/inputDEM2.cub + to=../OUT/ouputcnet2.pvl networkid=TestNetwork2 + errors=../OUT/failures.pvl + + + In this example, cnetnewradii will take the input control network and + copy it to the output network with new Radius values calculated for + ground points using the DN value recieved from the DEM cube. The + PointIDs of ground points that fail to calculate a new Radius value + will be listed in the error log. + + + + + + + Example GUI + + + Screen shot of GUI with parameters filled in to create ControlNet + with new Radius values. + + + + + + + + Input ControlNet for cnetnewradii + + Example of an input ControlNet whose Radius values will be updated + + CNET + + + Output error log for cnetnewradii + + Example of an output error log containing the PointIDs of all points + that failed to calculate a new Radius value. + + ERRORS + + + Output ControlNet for cnetnewradii + + Example of an output ControlNet corresponding to the input example + with updated Radius values. Notice that the ground points + that failed are set to Ignore=True and their original radius values + are retained. + + TO + + + + + Input DEM for cnetnewradii + + Example of an input DEM cube used by cnetnewradii to update the + Radius values of ground points in the ControlNet. + + + DEM + + + + + +
    diff --git a/isis/src/base/apps/cnetnewradii/tsts/Makefile b/isis/src/base/apps/cnetnewradii/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cnetnewradii/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cnetnewradii/tsts/allsuccesses/Makefile b/isis/src/base/apps/cnetnewradii/tsts/allsuccesses/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..729f525bbb971de9964c1d897289c6070e70d20b --- /dev/null +++ b/isis/src/base/apps/cnetnewradii/tsts/allsuccesses/Makefile @@ -0,0 +1,10 @@ +APPNAME = cnetnewradii + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) CNET=$(INPUT)/AS15_Rev4_Reg_wLOLA.edited.net \ + DEM=$(INPUT)/ldem_8ppd_LATneg30toneg15_LON140to180.cub \ + TO=$(OUTPUT)/outputcnet.pvl \ + networkid=AllSuccessesTestCase_CnetNewRadii \ + errors=$(OUTPUT)/errors.pvl > /dev/null; diff --git a/isis/src/base/apps/cnetnewradii/tsts/errors/Makefile b/isis/src/base/apps/cnetnewradii/tsts/errors/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a97998f3949fe6249930b3cf83a3ce880ab20261 --- /dev/null +++ b/isis/src/base/apps/cnetnewradii/tsts/errors/Makefile @@ -0,0 +1,15 @@ +.IGNORE: + +APPNAME = cnetnewradii + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) CNET=$(INPUT)/AS15_Rev4_Reg_wLOLA.edited.net \ + DEM=$(INPUT)/ldem_8ppd_LATneg15to0_LON140to180.cub \ + TO=$(OUTPUT)/outputcnet.pvl \ + networkid=ErrorsTestCase_CnetNewRadii \ + errors=errors.pvl 2>> $(OUTPUT)/error1.txt > /dev/null; + cat $(OUTPUT)/error1.txt | sed s+/usgs/cpkgs/isis3/testData/isis/src/base/apps/cnetnewradii/tsts/errors/++g > $(OUTPUT)/error.txt; + rm -f $(OUTPUT)/error1.txt; + rm -f $(OUTPUT)/outputcnet.pvl; diff --git a/isis/src/base/apps/cnetnewradii/tsts/somefailures/Makefile b/isis/src/base/apps/cnetnewradii/tsts/somefailures/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c7afd19fa65b1cc87f1fd4b75f591fbbfc1a5d3d --- /dev/null +++ b/isis/src/base/apps/cnetnewradii/tsts/somefailures/Makefile @@ -0,0 +1,10 @@ +APPNAME = cnetnewradii + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) CNET=$(INPUT)/AS15_Rev4_Reg_wLOLA.edited.net \ + DEM=$(INPUT)/ldem_8ppd_LATneg30toneg18_LON142to178.cub \ + TO=$(OUTPUT)/outputcnet.pvl \ + networkid=SomeFailuresTestCase_CnetNewRadii > /dev/null; + mv failures.log $(OUTPUT)/failures.pvl; diff --git a/isis/src/base/apps/cnetref/CnetRefByEmission.cpp b/isis/src/base/apps/cnetref/CnetRefByEmission.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5522812fc65e3e328396ddae3716b3e58b35be76 --- /dev/null +++ b/isis/src/base/apps/cnetref/CnetRefByEmission.cpp @@ -0,0 +1,198 @@ +#include "CnetRefByEmission.h" +#include "ControlNet.h" +#include "PvlGroup.h" +#include "Camera.h" +#include "Portal.h" +#include "SpecialPixel.h" +#include "Pvl.h" + +namespace Isis { + /** + * Construct CnetRefByEmission with a PVL Def file + * + * @author Sharmila Prasad (5/14/2010) + * + * @param pPvlDef + * @param pOrigNet + * @param pNewNet + * @param psSerialNumfile + */ + CnetRefByEmission::CnetRefByEmission(Pvl *pPvlDef, std::string psSerialNumfile): CnetValidMeasure(pPvlDef) { + ReadSerialNumbers(psSerialNumfile); + } + + /** + * This traverses all the control points and measures in the network and + * checks for valid Measure which passes the Emission Incidence Angle, DN value tests + * and picks the Measure with the best Emission Angle (closer) to zero as the Reference + * + * @author Sharmila Prasad (5/14/2010) + * + * @return none + */ + void CnetRefByEmission::FindCnetRef(const ControlNet &pOrigNet, ControlNet &pNewNet) { + // Process each existing control point in the network + int iTotalMeasures = 0; + int iPointsModified = 0; + int iMeasuresModified = 0; + int iRefChanged = 0; + + //Status Report + mStatus.SetText("Choosing Reference by Emission..."); + mStatus.SetMaximumSteps(pOrigNet.Size()); + mStatus.CheckStatus(); + + for(int point = 0; point < pOrigNet.Size(); ++point) { + ControlPoint &origPnt = ((ControlNet &)pOrigNet)[point]; // to remove the const + + // Stats and Accounting + iTotalMeasures += origPnt.Size(); + + // Logging + PvlObject pvlPointObj("PointDetails"); + pvlPointObj += Isis::PvlKeyword("PointId", origPnt.Id()); + + // Create a new control point + ControlPoint newPnt; + newPnt.SetId(origPnt.Id()); + newPnt.SetType(origPnt.Type()); + + int iRefIndex = origPnt.ReferenceIndexNoException(); + iString istrTemp; + + std::vector pvlGrpVector; + std::vector bestEmissionAngle; + int iBestIndex = 0; + + // Only perform the interest operation on points of type "Tie" and + // Points having atleast 1 measure and Points not Ignored + if(!origPnt.Ignore() && origPnt.Type() == ControlPoint::Tie && iRefIndex >= 0) { + // Create a measurment for each image in this point using the reference + // lat/lon. + int iNumIgnore = 0; + iString istrTemp; + double dBestEmissionAngle = 135; + + for(int measure = 0; measure < origPnt.Size(); ++measure) { + + ControlMeasure newMsr(origPnt[measure]); //copy constructor + newMsr.SetDateTime(); + newMsr.SetChooserName("Application cnetref(Emission)"); + + std::string sn = origPnt[measure].CubeSerialNumber(); + double dSample = origPnt[measure].Sample(); + double dLine = origPnt[measure].Line(); + + // Log + PvlGroup pvlMeasureGrp("MeasureDetails"); + pvlMeasureGrp += Isis::PvlKeyword("SerialNum", sn); + pvlMeasureGrp += Isis::PvlKeyword("OriginalLocation", LocationString(dSample, dLine)); + + if(!newMsr.Ignore()) { + Cube *measureCube = mCubeMgr.OpenCube(mSerialNumbers.Filename(sn)); + + newMsr.SetReference(false); + newMsr.SetIgnore(false); + + if(ValidStandardOptions(dSample, dLine, measureCube, &pvlMeasureGrp)) { + if(mdEmissionAngle < dBestEmissionAngle) { + dBestEmissionAngle = mdEmissionAngle; + iBestIndex = measure; + } + } + else { + pvlMeasureGrp += Isis::PvlKeyword("Ignored", "Failed Emission, Incidence, Resolution and/or Dn Value Test"); + newMsr.SetIgnore(true); + iNumIgnore++; + } + bestEmissionAngle.push_back(mdEmissionAngle); + } // Ignore == false + else { + pvlMeasureGrp += Isis::PvlKeyword("Ignored", "Originally Ignored"); + iNumIgnore++; + } + newPnt.Add(newMsr); + if(newMsr != origPnt[measure]) { + iMeasuresModified++; + } + pvlGrpVector.push_back(pvlMeasureGrp); + }// end Measure + + if((newPnt.Size() - iNumIgnore) < 2) { + newPnt.SetIgnore(true); + pvlPointObj += Isis::PvlKeyword("Ignored", "Good Measures less than 2"); + } + + // Set the Reference + if(!newPnt.Ignore() && iBestIndex >= 0 && !newPnt[iBestIndex].Ignore()) { + newPnt[iBestIndex].SetReference(true); + pvlGrpVector[iBestIndex] += Isis::PvlKeyword("Reference", "true"); + } + + for(int i = 0; i < newPnt.Size(); i++) { + pvlPointObj += pvlGrpVector[i]; + } + pNewNet.Add(newPnt); + } // end Tie + else { + newPnt = origPnt; + if(iRefIndex < 0) { + pvlPointObj += Isis::PvlKeyword("Comments", "No Measures in the Point"); + } + else if(newPnt.Ignore()) { + pvlPointObj += Isis::PvlKeyword("Comments", "Point was originally Ignored"); + } + else { + pvlPointObj += Isis::PvlKeyword("Comments", "Not Tie Point"); + } + for(int measure = 0; measure < newPnt.Size(); measure++) { + newPnt[measure].SetDateTime(); + newPnt[measure].SetChooserName("Application cnetref(Emission)"); + } + pNewNet.Add(newPnt); + } + + if(newPnt != origPnt) { + iPointsModified++; + } + + if(!newPnt.Ignore() && iBestIndex != iRefIndex) { + iRefChanged++; + PvlGroup pvlRefChangeGrp("ReferenceChangeDetails"); + pvlRefChangeGrp += Isis::PvlKeyword("PrevSerialNumber", origPnt[iRefIndex].CubeSerialNumber()); + pvlRefChangeGrp += Isis::PvlKeyword("PrevEmAngle", bestEmissionAngle[iRefIndex]); + + istrTemp = iString((int)origPnt[iRefIndex].Sample()); + istrTemp += ","; + istrTemp += iString((int)origPnt[iRefIndex].Line()); + pvlRefChangeGrp += Isis::PvlKeyword("PrevLocation", istrTemp); + + pvlRefChangeGrp += Isis::PvlKeyword("NewSerialNumber", newPnt[iBestIndex].CubeSerialNumber()); + pvlRefChangeGrp += Isis::PvlKeyword("NewLeastEmAngle", bestEmissionAngle[iBestIndex]); + + istrTemp = iString((int)newPnt[iBestIndex].Sample()); + istrTemp += ","; + istrTemp += iString((int)newPnt[iBestIndex].Line()); + pvlRefChangeGrp += Isis::PvlKeyword("NewLocation", istrTemp); + + pvlPointObj += pvlRefChangeGrp; + } + else { + pvlPointObj += Isis::PvlKeyword("Reference", "No Change"); + } + + mPvlLog += pvlPointObj; + mStatus.CheckStatus(); + }// end Point + + // Basic Statistics + mStatisticsGrp += Isis::PvlKeyword("TotalPoints", pOrigNet.Size()); + mStatisticsGrp += Isis::PvlKeyword("PointsIgnored", (pNewNet.Size() - pNewNet.NumValidPoints())); + mStatisticsGrp += Isis::PvlKeyword("PointsModified", iPointsModified); + mStatisticsGrp += Isis::PvlKeyword("ReferenceChanged", iRefChanged); + mStatisticsGrp += Isis::PvlKeyword("TotalMeasures", iTotalMeasures); + mStatisticsGrp += Isis::PvlKeyword("MeasuresModified", iMeasuresModified); + + mPvlLog += mStatisticsGrp; + } +}; diff --git a/isis/src/base/apps/cnetref/CnetRefByEmission.h b/isis/src/base/apps/cnetref/CnetRefByEmission.h new file mode 100644 index 0000000000000000000000000000000000000000..4beafc6e35945c469b060820203a2a205dbaf642 --- /dev/null +++ b/isis/src/base/apps/cnetref/CnetRefByEmission.h @@ -0,0 +1,68 @@ +#ifndef _CnetRefByEmission_h_ +#define _CnetRefByEmission_h_ + +#include "CnetValidMeasure.h" + +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/06/23 22:29:14 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { + /** + * @brief Find a Reference in Control Point with the least Emission Angle + * + * This class is used find a Reference in Control Point with the least Emission Angle + * after it has passed all the validity test for Dn, Emission & Incidence Angles + * and Resolution. Processes the entire points in the Control Network + * + * @ingroup ControlNetwork + * + * @author 2010-06-10 Sharmila Prasad + * + * @see CnetValidMeasure, CnetRefByIncidence, CnetRefByResolution + * + * @internal + * @history 2010-06-10 Sharmila Prasad - Original version + * @history 2010-06-21 Sharmila Prasad - Remove references to UniversalGroundMap and Cubes + * use CubeManager instead + * @history 2010-06-23 Sharmila Prasad - Use CnetValidMeasure's Validate Standard Options & + * Std Options Pixels/Meters from Edge + * + */ + + class Pvl; + class ControlNet; + + class CnetRefByEmission : public CnetValidMeasure { + public: + CnetRefByEmission(Pvl *pPvlDef, std::string msSerialNumfile); + virtual ~CnetRefByEmission() {}; + + virtual Pvl &GetLogPvl(void) { + return mPvlLog; + }; + //!< Given Control Net, find the reference based on Emission Angle + virtual void FindCnetRef(const ControlNet &pOrigNet, ControlNet &pNewNet); + }; +}; +#endif + diff --git a/isis/src/base/apps/cnetref/CnetRefByIncidence.cpp b/isis/src/base/apps/cnetref/CnetRefByIncidence.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1161f21a0996531a0aa8eb5f0bfb27f65060eb07 --- /dev/null +++ b/isis/src/base/apps/cnetref/CnetRefByIncidence.cpp @@ -0,0 +1,197 @@ +#include "CnetRefByIncidence.h" +#include "ControlNet.h" +#include "PvlGroup.h" +#include "Camera.h" +#include "Portal.h" +#include "SpecialPixel.h" +#include "Pvl.h" + +namespace Isis { + /** + * Construct CnetRefByIncidence with a PVL Def file + * + * @author Sharmila Prasad (5/24/2010) + * + * @param pPvlDef + * @param pOrigNet + * @param pNewNet + * @param psSerialNumfile + */ + CnetRefByIncidence::CnetRefByIncidence(Pvl *pPvlDef, std::string psSerialNumfile): CnetValidMeasure(pPvlDef) { + ReadSerialNumbers(psSerialNumfile); + } + + /** + * This traverses all the control points and measures in the network and + * checks for valid Measure which passes the Emission Incidence Angle, DN value tests + * and picks the Measure with the best Incidence Angle (closer) to zero as the Reference + * + * @author Sharmila Prasad (5/24/2010) + * + * @return New ControlNet + */ + void CnetRefByIncidence::FindCnetRef(const ControlNet &pOrigNet, ControlNet &pNewNet) { + // Process each existing control point in the network + int iTotalMeasures = 0; + int iPointsModified = 0; + int iMeasuresModified = 0; + int iRefChanged = 0; + + //Status Report + mStatus.SetText("Choosing Reference by Incidence..."); + mStatus.SetMaximumSteps(pOrigNet.Size()); + mStatus.CheckStatus(); + + //mPvlLog += GetStdOptions(); + for(int point = 0; point < pOrigNet.Size(); ++point) { + ControlPoint &origPnt = ((ControlNet &)pOrigNet)[point]; // to remove the const + + // Stats and Accounting + iTotalMeasures += origPnt.Size(); + + // Logging + PvlObject pvlPointObj("PointDetails"); + pvlPointObj += Isis::PvlKeyword("PointId", origPnt.Id()); + + // Create a new control point + ControlPoint newPnt; + newPnt.SetId(origPnt.Id()); + newPnt.SetType(origPnt.Type()); + + int iRefIndex = origPnt.ReferenceIndexNoException(); + iString istrTemp; + + std::vector pvlGrpVector; + std::vector bestIncidenceAngle; + int iBestIndex = -1; + + // Only perform the interest operation on points of type "Tie" and + // Points having atleast 1 measure and Point must not be Ignored + if(!origPnt.Ignore() && origPnt.Type() == ControlPoint::Tie && iRefIndex >= 0) { + // Create a measurment for each image in this point using the reference + // lat/lon. + int iNumIgnore = 0; + iString istrTemp; + double dBestIncidenceAngle = 135; + + for(int measure = 0; measure < origPnt.Size(); ++measure) { + ControlMeasure newMsr(origPnt[measure]); //copy constructor + newMsr.SetDateTime(); + newMsr.SetChooserName("Application cnetref(Incidence)"); + + double dSample = origPnt[measure].Sample(); + double dLine = origPnt[measure].Line(); + std::string sn = origPnt[measure].CubeSerialNumber(); + + // Log + PvlGroup pvlMeasureGrp("MeasureDetails"); + pvlMeasureGrp += Isis::PvlKeyword("SerialNum", sn); + pvlMeasureGrp += Isis::PvlKeyword("OriginalLocation", LocationString(dSample, dLine)); + + if(!newMsr.Ignore()) { + Cube *measureCube = mCubeMgr.OpenCube(mSerialNumbers.Filename(sn)); + + newMsr.SetReference(false); + newMsr.SetIgnore(false); + + if(ValidStandardOptions(dSample, dLine, measureCube, &pvlMeasureGrp)) { + if(mdIncidenceAngle < dBestIncidenceAngle) { + dBestIncidenceAngle = mdIncidenceAngle; + iBestIndex = measure; + } + } + else { + pvlMeasureGrp += Isis::PvlKeyword("Ignored", "Failed Emission, Incidence, Resolution and/or Dn Value Test"); + newMsr.SetIgnore(true); + iNumIgnore++; + } + bestIncidenceAngle.push_back(mdIncidenceAngle); + } // Ignore==False + else { + pvlMeasureGrp += Isis::PvlKeyword("Ignored", "Originally Ignored"); + iNumIgnore++; + } + newPnt.Add(newMsr); + if(newMsr != origPnt[measure]) { + iMeasuresModified++; + } + pvlGrpVector.push_back(pvlMeasureGrp); + }// end Measure + + if((newPnt.Size() - iNumIgnore) < 2) { + newPnt.SetIgnore(true); + pvlPointObj += Isis::PvlKeyword("Ignored", "Good Measures less than 2"); + } + // Set the Reference + if(!newPnt.Ignore() && iBestIndex >= 0 && !newPnt[iBestIndex].Ignore()) { + newPnt[iBestIndex].SetReference(true); + pvlGrpVector[iBestIndex] += Isis::PvlKeyword("Reference", "true"); + } + + for(int i = 0; i < newPnt.Size(); i++) { + pvlPointObj += pvlGrpVector[i]; + } + pNewNet.Add(newPnt); + } // end Tie + else { + newPnt = origPnt; + if(iRefIndex < 0) { + pvlPointObj += Isis::PvlKeyword("Comments", "No Measures in the Point"); + } + else if(newPnt.Ignore()) { + pvlPointObj += Isis::PvlKeyword("Comments", "Point was originally Ignored"); + } + else { + pvlPointObj += Isis::PvlKeyword("Comments", "Not Tie Point"); + } + for(int measure = 0; measure < newPnt.Size(); measure++) { + newPnt[measure].SetDateTime(); + newPnt[measure].SetChooserName("Application cnetref(Incidence)"); + } + pNewNet.Add(newPnt); + } + + if(newPnt != origPnt) { + iPointsModified++; + } + + if(!newPnt.Ignore() && iBestIndex != iRefIndex) { + iRefChanged++; + PvlGroup pvlRefChangeGrp("ReferenceChangeDetails"); + pvlRefChangeGrp += Isis::PvlKeyword("PrevSerialNumber", origPnt[iRefIndex].CubeSerialNumber()); + pvlRefChangeGrp += Isis::PvlKeyword("PrevIncAngle", bestIncidenceAngle[iRefIndex]); + + istrTemp = iString((int)origPnt[iRefIndex].Sample()); + istrTemp += ","; + istrTemp += iString((int)origPnt[iRefIndex].Line()); + pvlRefChangeGrp += Isis::PvlKeyword("PrevLocation", istrTemp); + + pvlRefChangeGrp += Isis::PvlKeyword("NewSerialNumber", newPnt[iBestIndex].CubeSerialNumber()); + pvlRefChangeGrp += Isis::PvlKeyword("NewLeastIncAngle", bestIncidenceAngle[iBestIndex]); + + istrTemp = iString((int)newPnt[iBestIndex].Sample()); + istrTemp += ","; + istrTemp += iString((int)newPnt[iBestIndex].Line()); + pvlRefChangeGrp += Isis::PvlKeyword("NewLocation", istrTemp); + + pvlPointObj += pvlRefChangeGrp; + } + else { + pvlPointObj += Isis::PvlKeyword("Reference", "No Change"); + } + + mPvlLog += pvlPointObj; + mStatus.CheckStatus(); + }// end Point + + // Basic Statistics + mStatisticsGrp += Isis::PvlKeyword("TotalPoints", pOrigNet.Size()); + mStatisticsGrp += Isis::PvlKeyword("PointsIgnored", (pNewNet.Size() - pNewNet.NumValidPoints())); + mStatisticsGrp += Isis::PvlKeyword("PointsModified", iPointsModified); + mStatisticsGrp += Isis::PvlKeyword("ReferenceChanged", iRefChanged); + mStatisticsGrp += Isis::PvlKeyword("TotalMeasures", iTotalMeasures); + mStatisticsGrp += Isis::PvlKeyword("MeasuresModified", iMeasuresModified); + + mPvlLog += mStatisticsGrp; + } +}; diff --git a/isis/src/base/apps/cnetref/CnetRefByIncidence.h b/isis/src/base/apps/cnetref/CnetRefByIncidence.h new file mode 100644 index 0000000000000000000000000000000000000000..7563481dc588405edc9c0ab678249c84618ffc55 --- /dev/null +++ b/isis/src/base/apps/cnetref/CnetRefByIncidence.h @@ -0,0 +1,69 @@ +#ifndef _CnetRefByIncidence_h_ +#define _CnetRefByIncidence_h_ + +#include "CnetValidMeasure.h" + +/** + * @file + * $Revision: 1.5 $ + * $Date: + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { + + /** + * @brief Find a Reference in Control Point with the least Incidence Angle + * + * This class is used find a Reference in Control Point with the least Incidence Angle + * after it has passed all the validity test for Dn, Emission & Incidence Angles + * and Resolution. Processes the entire points in the Control Network + * + * @ingroup ControlNetwork + * + * @author 2010-06-10 Sharmila Prasad + * + * @see CnetValidMeasure, CnetRefByEmission, CnetRefByResolution + * + * @internal + * @history 2010-06-10 Sharmila Prasad Original version + * @history 2010-06-21 Sharmila Prasad - Remove references to UniversalGroundMap and Cubes + * use CubeManager instead + * @history 2010-06-23 Sharmila Prasad - Use CnetValidMeasure's Validate Standard Options & + * Std Options Pixels/Meters from Edge + */ + class Pvl; + class ControlNet; + + class CnetRefByIncidence : public CnetValidMeasure { + public: + CnetRefByIncidence(Pvl *pPvlDef, std::string msSerialNumfile); + virtual ~CnetRefByIncidence() {}; + + virtual Pvl &GetLogPvl(void) { + return mPvlLog; + }; + //!< Given Control Net, find the reference based on Incidence Angle + virtual void FindCnetRef(const ControlNet &pOrigNet, ControlNet &pNewNet); + + private: + }; +}; +#endif + diff --git a/isis/src/base/apps/cnetref/CnetRefByResolution.cpp b/isis/src/base/apps/cnetref/CnetRefByResolution.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d439613a2c2cc34679c901add232ac232cca36de --- /dev/null +++ b/isis/src/base/apps/cnetref/CnetRefByResolution.cpp @@ -0,0 +1,309 @@ +#include "ControlNet.h" +#include "PvlGroup.h" +#include "Camera.h" +#include "Portal.h" +#include "SpecialPixel.h" +#include "Pvl.h" +#include "SerialNumberList.h" + +#include "CnetRefByResolution.h" + +using namespace std; + +namespace Isis { + /** + * CnetRefByResolution constructor with the def file + * + * @author Sharmila Prasad (5/25/2010) + * + * @param pPvlDef + * @param pOrigNet + * @param pNewNet + * @param psSerialNumfile + * @param peType + * @param pdResValue + */ + CnetRefByResolution::CnetRefByResolution(Pvl *pPvlDef, std::string psSerialNumfile, ResolutionType peType, + double pdResValue, double pdMinRes, double pdMaxRes) : CnetValidMeasure(pPvlDef) { + mdResValue = pdResValue; + mdMinRes = pdMinRes; + mdMaxRes = pdMaxRes; + meType = peType; + ReadSerialNumbers(psSerialNumfile); + } + + /** + * FindCnetRef traverses all the control points and measures in the network and checks for valid Measure which passes + * the Emission Incidence Angle, DN value tests and chooses the measure with the best + * Resolution criteria as the reference. Creates a new control network with these adjustments. + * + * @author Sharmila Prasad (5/25/2010) + * + * @param pOrigNet + * @param pNewNet + * + */ + void CnetRefByResolution::FindCnetRef(const ControlNet &pOrigNet, ControlNet &pNewNet) { + // Process each existing control point in the network + int iTotalMeasures = 0; + int iPointsModified = 0; + int iMeasuresModified = 0; + //int iMeasuresTypeChanged=0; + int iRefChanged = 0; + + //Status Report + mStatus.SetText("Choosing Reference by Resolution..."); + mStatus.SetMaximumSteps(pOrigNet.Size()); + mStatus.CheckStatus(); + + //mPvlLog += GetStdOptions(); + for(int point = 0; point < pOrigNet.Size(); ++point) { + ControlPoint &origPnt = ((ControlNet &)pOrigNet)[point]; // to remove the const + + mdResVector.clear(); + + // Stats and Accounting + iTotalMeasures += origPnt.Size(); + + // Logging + PvlObject pvlPointObj("PointDetails"); + pvlPointObj += Isis::PvlKeyword("PointId", origPnt.Id()); + + // Create a new control point + ControlPoint newPnt; + newPnt.SetId(origPnt.Id()); + newPnt.SetType(origPnt.Type()); + + int iRefIndex = origPnt.ReferenceIndexNoException(); + iString istrTemp; + + std::vector pvlGrpVector; + int iBestIndex = 0; + + // Only perform the interest operation on points of type "Tie" and + // Points having atleast 1 measure and Point is not Ignored + if(!origPnt.Ignore() && origPnt.Type() == ControlPoint::Tie && iRefIndex >= 0) { + // Create a measurment for each image in this point using the reference + // lat/lon. + int iNumIgnore = 0; + iString istrTemp; + //double dBestResolution=135; + + for(int measure = 0; measure < origPnt.Size(); ++measure) { + + ControlMeasure newMsr(origPnt[measure]); //copy constructor + newMsr.SetDateTime(); + newMsr.SetChooserName("Application cnetref(Resolution)"); + + double dSample = origPnt[measure].Sample(); + double dLine = origPnt[measure].Line(); + std::string sn = origPnt[measure].CubeSerialNumber(); + + // Log + PvlGroup pvlMeasureGrp("MeasureDetails"); + pvlMeasureGrp += Isis::PvlKeyword("SerialNum", sn); + pvlMeasureGrp += Isis::PvlKeyword("OriginalLocation", LocationString(dSample, dLine)); + + if(!newMsr.Ignore()) { + Cube *measureCube = mCubeMgr.OpenCube(mSerialNumbers.Filename(sn)); + + newMsr.SetReference(false); + newMsr.SetIgnore(false); + + if(!ValidStandardOptions(dSample, dLine, measureCube, &pvlMeasureGrp)) { + pvlMeasureGrp += Isis::PvlKeyword("Ignored", "Failed Emission, Incidence, Resolution and/or Dn Value Test"); + newMsr.SetIgnore(true); + iNumIgnore++; + } + mdResVector.push_back(mdResolution); + } // Ignore == false + else { + pvlMeasureGrp += Isis::PvlKeyword("Ignored", "Originally Ignored"); + iNumIgnore++; + } + newPnt.Add(newMsr); + if(newMsr != origPnt[measure]) { + iMeasuresModified++; + } + pvlGrpVector.push_back(pvlMeasureGrp); + }// end Measure + + if((newPnt.Size() - iNumIgnore) < 2) { + newPnt.SetIgnore(true); + pvlPointObj += Isis::PvlKeyword("Ignored", "Good Measures less than 2"); + } + // Set the Reference + if(!newPnt.Ignore()) { + iBestIndex = GetReferenceByResolution(newPnt); + if(iBestIndex >= 0 && !newPnt[iBestIndex].Ignore()) { + newPnt[iBestIndex].SetReference(true); + pvlGrpVector[iBestIndex] += Isis::PvlKeyword("Reference", "true"); + } + else { + if(iBestIndex < 0 && meType == Range) { + pvlPointObj += Isis::PvlKeyword("NOTE", "No Valid Measures within the Resolution Range. Reference defaulted to the first Measure"); + } + iBestIndex = 0; + newPnt[iBestIndex].SetReference(true); + } + } + + for(int i = 0; i < newPnt.Size(); i++) { + pvlPointObj += pvlGrpVector[i]; + } + pNewNet.Add(newPnt); + } // end Tie + else { + newPnt = origPnt; + if(iRefIndex < 0) { + pvlPointObj += Isis::PvlKeyword("Comments", "No Measures in the Point"); + } + else if(newPnt.Ignore()) { + pvlPointObj += Isis::PvlKeyword("Comments", "Point was originally Ignored"); + } + else { + pvlPointObj += Isis::PvlKeyword("Comments", "Not Tie Point"); + } + for(int measure = 0; measure < newPnt.Size(); measure++) { + newPnt[measure].SetDateTime(); + newPnt[measure].SetChooserName("Application cnetref(Resolution)"); + } + pNewNet.Add(newPnt); + } + + if(newPnt != origPnt) { + iPointsModified++; + } + + if(!newPnt.Ignore() && iBestIndex != iRefIndex) { + iRefChanged++; + PvlGroup pvlRefChangeGrp("ReferenceChangeDetails"); + pvlRefChangeGrp += Isis::PvlKeyword("PrevSerialNumber", origPnt[iRefIndex].CubeSerialNumber()); + pvlRefChangeGrp += Isis::PvlKeyword("PrevResolution", mdResVector[iRefIndex]); + + istrTemp = iString((int)origPnt[iRefIndex].Sample()); + istrTemp += ","; + istrTemp += iString((int)origPnt[iRefIndex].Line()); + pvlRefChangeGrp += Isis::PvlKeyword("PrevLocation", istrTemp); + + pvlRefChangeGrp += Isis::PvlKeyword("NewSerialNumber", newPnt[iBestIndex].CubeSerialNumber()); + std::string sKeyName = "NewHighestResolution"; + if(meType == Low) { + sKeyName = "NewLeastResolution"; + } + else if(meType == Mean) { + pvlRefChangeGrp += Isis::PvlKeyword("MeanResolution", GetMeanResolution()); + sKeyName = "NewResolutionNeartoMean"; + } + else if(meType == Nearest) { + sKeyName = "NewResolutionNeartoValue"; + } + else if(meType == Range) { + sKeyName = "NewResolutionInRange"; + } + pvlRefChangeGrp += Isis::PvlKeyword(sKeyName, mdResVector[iBestIndex]); + + istrTemp = iString((int)newPnt[iBestIndex].Sample()); + istrTemp += ","; + istrTemp += iString((int)newPnt[iBestIndex].Line()); + pvlRefChangeGrp += Isis::PvlKeyword("NewLocation", istrTemp); + + pvlPointObj += pvlRefChangeGrp; + } + else { + pvlPointObj += Isis::PvlKeyword("Reference", "No Change"); + } + + mPvlLog += pvlPointObj; + mStatus.CheckStatus(); + }// end Point + + // Basic Statistics + mStatisticsGrp += Isis::PvlKeyword("TotalPoints", pOrigNet.Size()); + mStatisticsGrp += Isis::PvlKeyword("PointsIgnored", (pNewNet.Size() - pNewNet.NumValidPoints())); + mStatisticsGrp += Isis::PvlKeyword("PointsModified", iPointsModified); + mStatisticsGrp += Isis::PvlKeyword("ReferenceChanged", iRefChanged); + mStatisticsGrp += Isis::PvlKeyword("TotalMeasures", iTotalMeasures); + mStatisticsGrp += Isis::PvlKeyword("MeasuresModified", iMeasuresModified); + + mPvlLog += mStatisticsGrp; + } + + /** + * GetMeanResolution - Get Mean of all the resolutions of all the measures + * in the Control Point + * + * @author Sharmila Prasad (6/1/2010) + * + * @return double + */ + double CnetRefByResolution::GetMeanResolution(void) { + double dTotal = 0; + for(int i = 0; i < (int)mdResVector.size(); i++) { + dTotal += mdResVector[i]; + } + + return (dTotal / mdResVector.size()); + } + + /** + * GetReferenceByResolution - Get the Reference for each Control Point by user defined + * Resolution criteria + * + * @author Sharmila Prasad (6/1/2010) + * + * @return int + */ + int CnetRefByResolution::GetReferenceByResolution(ControlPoint &pNewPoint) { + int iBestIndex = -1; + double dBestResolution = -1; + double dMean = 0; + if(meType == Mean) { + dMean = GetMeanResolution(); + } + + for(int i = 0; i < (int)mdResVector.size(); i++) { + if(pNewPoint[i].Ignore()) { + continue; + } + else { + double dDiff = dBestResolution - mdResVector[i]; + if(meType == Low) { + if(dBestResolution == -1 || dDiff < 0) { + dBestResolution = mdResVector[i]; + iBestIndex = i; + } + } + else if(meType == High) { + double dDiff = dBestResolution - mdResVector[i]; + if(dBestResolution == -1 || dDiff > 0) { + dBestResolution = mdResVector[i]; + iBestIndex = i; + } + } + else if(meType == Mean) { + double dDiff = fabs(dMean - mdResVector[i]); + if(dBestResolution == -1 || dDiff < dBestResolution) { + dBestResolution = dDiff; + iBestIndex = i; + } + } + else if(meType == Nearest) { + double dDiff = fabs(mdResValue - mdResVector[i]); + if(dBestResolution == -1 || dDiff < dBestResolution) { + dBestResolution = dDiff; + iBestIndex = i; + } + } + else if(meType == Range) { + if(mdResVector[i] >= mdMinRes && mdResVector[i] <= mdMaxRes) { + iBestIndex = i; + return iBestIndex; + } + } + } + } + return iBestIndex; + } +}; + diff --git a/isis/src/base/apps/cnetref/CnetRefByResolution.h b/isis/src/base/apps/cnetref/CnetRefByResolution.h new file mode 100644 index 0000000000000000000000000000000000000000..f816c3133d762dbcc1fc2f649e26448639206bc8 --- /dev/null +++ b/isis/src/base/apps/cnetref/CnetRefByResolution.h @@ -0,0 +1,87 @@ +#ifndef _CnetRefByResolution_H_ +#define _CnetRefByResolution_H_ + +#include "CnetValidMeasure.h" + +/** + * @file + * $Revision: 1.5 $ + * $Date: + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { + + /** + * @brief Find a Reference in Control Point based on Resolution + * + * This class is used find a Reference in Control Point based on Resolution + * after it has passed all the validity test for Dn, Emission & Incidence Angles + * and Resolution. Processes the entire points in the Control Network + * + * Resolution choices could be based on highest, lowest Resolutions or Measure + * whose resolution is closest to mean of all the resolutions, Measure whose + * resolution is closest to user defined value or Measure whose resolution + * is in a given range + * + * @ingroup ControlNetwork + * + * @author 2010-06-10 Sharmila Prasad + * + * @see CnetValidMeasure, CnetRefByEmission, CnetRefByIncidence + * + * @internal + * @history 2010-06-10 Sharmila Prasad Original version + * @history 2010-06-21 Sharmila Prasad - Remove references to UniversalGroundMap and Cubes + * use CubeManager instead + * @history 2010-06-23 Sharmila Prasad - Use CnetValidMeasure's Validate Standard Options & + * Std Options Pixels/Meters from Edge + * + */ + enum ResolutionType {Low, High, Mean, Nearest, Range}; + + class Pvl; + class ControlNet; + + class CnetRefByResolution : public CnetValidMeasure { + public: + CnetRefByResolution(Pvl *pPvlDef, std::string psSerialNumfile, ResolutionType peType = Low, double pdResValue = 0, double pdMinRes = 0, double pdMaxRes = 0); + virtual ~CnetRefByResolution() {}; + + virtual Pvl &GetLogPvl(void) { + return mPvlLog; + }; + + //!< Get the Mean of all the Resolution in a Point + double GetMeanResolution(void); + + //!< Given Control Net, find the reference based on Resolution + virtual void FindCnetRef(const ControlNet &pOrigNet, ControlNet &pNewNet); + + private: + int GetReferenceByResolution(ControlPoint &pNewPoint); //!< Get the Reference based on Resolution type + std::vector mdResVector; //!< Store the Resolutions of all Measures in a Point + ResolutionType meType; //!< Resolution Type - Low, Mean, High, Value, Range + double mdResValue; //!< Resolution value for Type=Value + double mdMinRes; //!< Min Resolution for Type=Range + double mdMaxRes; //!< Max Resolution for Type=Range + }; +}; +#endif + diff --git a/isis/src/base/apps/cnetref/Makefile b/isis/src/base/apps/cnetref/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cnetref/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cnetref/cnetref.cpp b/isis/src/base/apps/cnetref/cnetref.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b6de7c79ebb4185898e0a29c2f98fae09027b563 --- /dev/null +++ b/isis/src/base/apps/cnetref/cnetref.cpp @@ -0,0 +1,192 @@ +#include "Isis.h" + +#include "Pvl.h" +#include "ControlNet.h" +#include "Progress.h" +#include "InterestOperatorFactory.h" +#include "InterestOperator.h" +#include "iException.h" + +#include "CnetRefByEmission.h" +#include "CnetRefByIncidence.h" +#include "CnetRefByResolution.h" + +#include + +using namespace std; +using namespace Isis; + +ResolutionType GetResolutionType(std::string psType); + +void IsisMain() { + + try { + UserInterface &ui = Application::GetUserInterface(); + std::string sSerialNumFile = ui.GetFilename("FROMLIST"); + + // Get the original control net internalized + Progress progress; + ControlNet origNet(ui.GetFilename("NETWORK"), &progress); + + // Create the new control net to store the points in. + ControlNet newNet; + newNet.SetType(origNet.Type()); + newNet.SetTarget(origNet.Target()); + if(ui.WasEntered("NETWORKID")) { + newNet.SetNetworkId(ui.GetString("NETWORKID")); + } + else { + newNet.SetNetworkId(origNet.NetworkId()); + } + + newNet.SetUserName(Isis::Application::UserName()); + + if(ui.WasEntered("DESCRIPTION")) { + newNet.SetDescription(ui.GetString("DESCRIPTION")); + } + else { + newNet.SetDescription(origNet.Description()); + } + + bool bDefFile = false; + Pvl *pvlDefFile = 0; + if(ui.WasEntered("DEFFILE")) { + bDefFile = true; + pvlDefFile = new Pvl(ui.GetFilename("DEFFILE")); + } + + // Get the output Log file + bool bLogFile = false; + string sLogFile; + if(ui.WasEntered("LOG")) { + sLogFile = ui.GetFilename("LOG"); + bLogFile = true; + } + + // get the Criteria option + CnetValidMeasure *cnetValidMeas = NULL; + std::string sCriteria = ui.GetString("CRITERIA"); + + // Process Reference by Emission Angle + if(sCriteria == "EMISSION") { + cnetValidMeas = new CnetRefByEmission(pvlDefFile, sSerialNumFile); + cnetValidMeas->FindCnetRef(origNet, newNet); + } + + // Process Reference by Incidence Angle + else if(sCriteria == "INCIDENCE") { + cnetValidMeas = new CnetRefByIncidence(pvlDefFile, sSerialNumFile); + cnetValidMeas->FindCnetRef(origNet, newNet); + } + + // Process Reference by Resolution + else if(sCriteria == "RESOLUTION") { + std::string sType = ui.GetString("TYPE"); + double dResValue = 0; + double dMinRes = 0, dMaxRes = 0; + if(sType == "NEAREST") { + dResValue = ui.GetDouble("RESVALUE"); + if(dResValue < 0) { + std::string message = "Invalid Nearest Resolution Value"; + throw Isis::iException::Message(Isis::iException::User, message, _FILEINFO_); + } + } + else if(sType == "RANGE") { + dMinRes = ui.GetDouble("MINRES"); + dMaxRes = ui.GetDouble("MAXRES"); + if(dMinRes < 0 || dMaxRes < 0 || dMinRes > dMaxRes) { + std::string message = "Invalid Resolution Range"; + throw Isis::iException::Message(Isis::iException::User, message, _FILEINFO_); + } + } + cnetValidMeas = new CnetRefByResolution(pvlDefFile, sSerialNumFile, GetResolutionType(sType), dResValue, dMinRes, dMaxRes); + cnetValidMeas->FindCnetRef(origNet, newNet); + } + + // Process Reference by Interest + else if(sCriteria == "INTEREST") { + if(!bDefFile) { + std::string msg = "Interest Option must have a DefFile"; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + std::string sOverlapListFile = ""; + if(ui.WasEntered("LIMIT")) { + if(ui.GetBoolean("LIMIT")) { + sOverlapListFile = Filename(ui.GetFilename("OVERLAPLIST")).Expanded(); + } + } + + // Get the InterestOperator set up + InterestOperator *interestOp = InterestOperatorFactory::Create(*pvlDefFile); + interestOp->Operate(origNet, newNet, sSerialNumFile, sOverlapListFile); + + // Write to print.prt and screen interest details + // add operator to print.prt + PvlGroup opGroup = interestOp->Operator(); + Application::Log(opGroup); + if(bLogFile) { + Pvl pvlLog = interestOp->GetLogPvl(); + pvlLog += opGroup; + pvlLog.Write(sLogFile); + } + Application::Log(interestOp->GetStdOptions()); + Application::Log(interestOp->GetStatistics()); + } + + // Write the new control network out + newNet.Write(ui.GetFilename("TO")); + + if(cnetValidMeas) { + Pvl pvlLog = cnetValidMeas->GetLogPvl(); + if(bLogFile) { + pvlLog.Write(sLogFile); + } + Application::Log(cnetValidMeas->GetStdOptions()); + Application::Log(cnetValidMeas->GetStatistics()); + + // clean up + delete cnetValidMeas; + } + + } // REFORMAT THESE ERRORS INTO ISIS TYPES AND RETHROW + catch(Isis::iException &e) { + throw; + } + catch(geos::util::GEOSException *exc) { + string message = "GEOS Exception: " + (iString)exc->what(); + delete exc; + throw Isis::iException::Message(Isis::iException::User, message, _FILEINFO_); + } + catch(std::exception const &se) { + string message = "std::exception: " + (iString)se.what(); + throw Isis::iException::Message(Isis::iException::User, message, _FILEINFO_); + } + catch(...) { + string message = "Other Error"; + throw Isis::iException::Message(Isis::iException::User, message, _FILEINFO_); + } +} + +/** + * Return the enumerated ResolutionType for a given string + * + * @author Sharmila Prasad (6/4/2010) + * + * @param psType + * + * @return ResolutionType + */ +ResolutionType GetResolutionType(std::string psType) { + if(psType == "LOW") + return Low; + else if(psType == "HIGH") + return High; + else if(psType == "MEAN") + return Mean; + else if(psType == "NEAREST") + return Nearest; + else if(psType == "RANGE") + return Range; + + return High; +} diff --git a/isis/src/base/apps/cnetref/cnetref.xml b/isis/src/base/apps/cnetref/cnetref.xml new file mode 100644 index 0000000000000000000000000000000000000000..dd6fb23856c3aea9845b4449954b93d8082a98e4 --- /dev/null +++ b/isis/src/base/apps/cnetref/cnetref.xml @@ -0,0 +1,530 @@ + + + + + + The application cnetref finds the best reference for a Control Point based + on criteria like Emission Angle or Incidence Angle or Resolution or Interest + + + + The application cnetref finds the best reference for a Control Point based + on a particular Criteria. There are four different Criterias'. The + CRITERIA's are:
    1. Emission
    2. Incidence
    3. Interest +
    4. Resolution
    + + The application first validates each measure for the following common + properties. These properties can be user defined in a DEFFILE file + else defaults will be used. The DEFFILE is optional for Emission, Incidence + and Resolution Criteria. Following is the format for the Pvl DEFFILE file + with the defaults:
    + Group = Operator
    + Name = None (for Emission, Incidence, Resolution) (Required) OR
    + Name = StandardDeviation/GradientOperator (for Interest) (Required)
    + MinDN = Isis::ValidMinimum(Optional)
    + MaxDN = Isis::ValidMaximum(Optional)
    + MinEmission = 0(Optional)
    + MaxEmission = 135(Optional)
    + MinIncidence = 0(Optional)
    + MaxIncidence = 135(Optional)
    + MinResolution = 0(Optional)
    + MaxResolution = DOUBLE_MAX (Optional)
    + PixelsFromEdge= 0(Optional)
    + MetersFromEdge= 0(Optional)
    + EndGroup

    + Non-Tie Points and Points with no Measures will not be + processed and will be copied from the Original Control Net to the output. + Also Points originally Ignored will not be processed and will remain + Ignored. If the measure does not pass the validity test, then it will also + be Ignored. If the number of Valid Measures in a Point is less than 2, then + the Point is Ignored.

    + The Reference can be chosen based on the following Criteria:
    + 1. EMISSION : Of all the valid Measures in a Control Point, the Measure with the least + Emission Angle will be chosen as the Reference.

    + 2. INCIDENCE: Of all the valid Measures in a Control Point, the + Measure with the least Incidence Angle will be chosen as the + Reference.

    + 3. RESOLUTION: Of all the valid Measures in a Control Point, the Measure + with the best Resolution TYPE will be chosen as the Reference.
    + The Resolution can be of the following types:
    + a. HIGH - The Measure with the Highest Resolution will be chosen as the + Reference.
    + b. LOW - The Measure with the Least Resolution will be chosen as the + Reference.
    + c. MEAN - The Mean Resolution is calculated for all the images, within + each Contol Point, the Measure closest to the Mean Resolution will be + chosen as the Reference.
    + d. NEAREST - The Measure with the Resolution closest to this User defined + value in RESVALUE will be chosen as the Reference.
    + e. RANGE - The first Measure in the MINRES - MAXRES Range will be chosen as + the Reference.

    + 4. INTEREST: Of all the valid Measures in a Control Point, + the Measure with the best interest will be chosen as the reference. This + option uses an interest operator to find the most interesting area near + each point of a control network. The movement of the Control Point can be + limited to the Overlaps by enabling "LIMIT" and entering the list in + "OVERLAPLIST".
    Interest Algorithm could be:
    + 1. Standard Deviation
    + 2. Gradient
    + + For this option, the DEFFILE includes additional keywords relevant for the + Interest Operator plugin. It defines the algorithm(Name) to be used to + calculate the interest, the box size (Samples, Lines) and the distance + (DeltaSamp, DeltaLine) the algorithm is allowed to move the point from the + current position. It defines the minimum interest (MinimumInterest) value + for the interest to be considered a best interest. If the point must be + static then set the DeltaSamp and DeltaLine to zero.

    + Example:
    + Group = Operator
    + Name = StandardDeviation (Required)
    + Samples = 10 (Required)
    + Lines = 10 (Required)
    + DeltaLine = 50 (Required)
    + DeltaSamp = 50 (Required)
    + MinimumInterest = 0.00001 (Required)
    + MinDN = Isis::ValidMinimum(Optional)
    + MaxDN = Isis::ValidMaximum(Optional)
    + MinEmission = 0 (Optional)
    + MaxEmission = 135 (Optional)
    + MinIncidence = 0(Optional)
    + MaxIncidence = 135(Optional)
    + MinResolution = 0(Optional)
    + MaxResolution = DOUBLE_MAX (Optional)
    + PixelsFromEdge= 0(Optional)
    + MetersFromEdge= 0(Optional)
    + EndGroup

    + If the "Required" parameters are not entered or misspelt, then the + application will throw an error. If "Optional" parameters are not entered + or misspelt, then their default values will be used.

    + + The interest operator reads in a chip of size Delta Samples and Lines from + each measurement(cube) in a point. If the Overlap list is included then + the overlap polygon is taken into consideration when the chip reads the + cube. For each pixel in the chip, it extracts a sub chip of box size + (Samples, Lines) around the pixel. It first checks the pixel for valid DN + value and then checks for the valid emission angle. If the pixel passes the + above tests, then the interest is calculated for the box around the pixel + using the chosen algorithm. This way it calculates the interest for all the + pixels in the chosen area (chip) around the measurement and the best + interest (highest value) is chosen among them. This way the best interest is + calculated for all the measurements in a point.
    + The application then selects the best interest of all the valid measures + in the point and chooses it as the reference. It then moves all the other + unreferenced valid measures to the chosen reference point by mapping the + reference lat, lon to sample, line in the unreferenced measurement. If + interest is not calculated for a measure because it is invalid or if the interest calculated itself is invalid, then + the measure is ignored. This causes the Control Measure to have the sample + and line to be set to "Null". If the number of valid measures in the + control point is less than 2 then the point is also ignored. It then creates + a new control network using these new "more interesting" control points. +

    + Note:
    1.If measures with no camera is encountered, then the + application is halted and no ouput control network is generated. +
    2. The values Samples, Lines, DeltaLine, DeltaSamp, MinimumInterest + for the Operator are entirely dependent on the images in the Control Net. + Recommended preprocessing would be to run "gradient" filter or "svfilter" + and run "hist" to get the image stats and set the values for the Operator + accordingly.
    +

    The entire Control Net processing can be logged in an output LOG + file

    +
    + + + Control Networks + + + + + Original version + + + Tweaked to compile and run with current version of Isis + + + Added support for image overlap files, new optional parameter "OVERLAPLIST" + + + "OVERLAPLIST" is now a required parameter. + + + Fixed Memory Leaks, Changed Deletion of cubes to use an iterator + + + If a control measure fails SetUniversalGround it is now ignored. + + + Interest operator parameters are now placed into the print file. + + + Added Emission Angle criteria in the interest operator plugin for the + best interest point to be considered. Also Check that the best interest + point has DN value in the Valid Min and Max DN range. + + + Logging and documentation-specify output log file for the results to be + sent to else printed to print.prt. If images with no camera is + encountered, the application is closed. + + + Make the overlap list optional incase a control network has no overlap + list. Added a checkbox to indicate whether the overlap list is available or + not and modified the app accordingly + + + Renamed to cnetref + + + Calculate interest for Control Points with no Reference point and Control + Points with Measures less than 2. Include Min and Max Incidence Angle + filter and make parameters NETWORKID and DESCRIPTION optional.. + + + Using an overlap list should be much more accurate and restrictive now. + Added MINRES and MAXRES parameters. Fixed potential segmentation fault. + Restored program's history. + + + Find reference based on Emission, Incidence angles or interest or + Resolution. Added new parameters to accomodate the new options + + + Added documentation and tests + + + Added documentation, display error for Interest option with no DefFile. + + + Use Standard Options Pixels/Meters from Edge + + + + + + + filename + input + + List of Input cubes in the control network + + + Use this parameter to specify the cube filenames which are associated with + the control network. + + + *.lis + + + + + filename + input + + Input control network + + + This file must contain control network with valid points and + measurments + + + *.net + + + + + filename + output + + Output control network + + + This file will contain the new adjusted control network + + + + + filename + None + output + Optional output log file + + Use this parameter to specify the file the detailed log has to be + printed to. + + + *.* + + + + + + + None + string + + Name of the output control network + + + The ID or name of this particular control network. This string + should be unique. + + + + + string + None + + The description of the output control network. + + + A string describing purpose of this control network. + + + + + + + string + + EMISSION + + Criteria in choosing the best reference in a Control Point + + + This parameter lets the user choose one of the four ways to choose the + best reference in a Control Point + + + + + + + + + + + + + + + filename + input + None + + PVL file containing the description of the Validity Keywords and/or + operator plugin if Interest is chosen + + + PVL file containing the description of the Validity Keywords and/or + operator plugin if Interest is chosen + + + * + + + + + + + + boolean + false + + Limit the movement of all measurements to be within their overlaps + + + Limit the movement of all measurements to be within their defined + overlaps. The application makes sure that when enabled, even if the + point moves it will be in the defined overlap area. Uncheck LIMIT if + there is no overlap list example control network from seedgrid + application or if it is ok if the point moves beyond the overlap + area. + + + OVERLAPLIST + + + + + filename + None + input + This is the list of image overlaps corresponding to this control + net + + Use this parameter to select the filename which contains the + overlap list. You can obtain this file by running "findimageoverlaps." + + + * + + + + + + + string + HIGH + Choose the Resolution type + + This parameter lets the user choose the different Resolution choices + available + + + + + + + + + + + + + + + + + double + 0 + Resolution Number + + This parameter holds the Resolution value in number and will find + the measure closest to this value. + + + + + double + 0 + + References Image Minimum Resolution + + + Any images with resolutions less than MINRES m/pix will not be made + reference images. + + + + + double + 0 + + References Image Maximum Resolution + + + Any images with resolutions greater than MAXRES m/pix will not be made + reference images. The units of this parameter should be + + + + +
    diff --git a/isis/src/base/apps/cnetref/tsts/Makefile b/isis/src/base/apps/cnetref/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cnetref/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cnetref/tsts/emission/Makefile b/isis/src/base/apps/cnetref/tsts/emission/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9880ae0495a0c5854b93569fcdf8350beefba027 --- /dev/null +++ b/isis/src/base/apps/cnetref/tsts/emission/Makefile @@ -0,0 +1,16 @@ +APPNAME = cnetref + +truth.pvl.IGNORELINES = UserName Created LastModified DateTime + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) -1 $(INPUT)/*.cub > $(OUTPUT)/cube.lis; + $(APPNAME) fromlist=$(OUTPUT)/cube.lis \ + network=$(INPUT)/autoseed.net \ + deffile=$(INPUT)/deffile.def \ + criteria=emission \ + to=$(OUTPUT)/truth.pvl \ + networkid=DefaultTruth \ + Description=RefByEmission > /dev/null; + $(RM) $(OUTPUT)/cube.lis; diff --git a/isis/src/base/apps/cnetref/tsts/incidence/Makefile b/isis/src/base/apps/cnetref/tsts/incidence/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f8b6e9d66f05b4470bc390a87ad92fa3754e56e1 --- /dev/null +++ b/isis/src/base/apps/cnetref/tsts/incidence/Makefile @@ -0,0 +1,17 @@ +APPNAME = cnetref + +truth.pvl.IGNORELINES = UserName Created LastModified DateTime + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) -1 $(INPUT)/*.cub > $(OUTPUT)/cube.lis; + $(APPNAME) fromlist=$(OUTPUT)/cube.lis \ + network=$(INPUT)/autoseed.net \ + deffile=$(INPUT)/deffile.def \ + criteria=incidence \ + log=out.log \ + to=$(OUTPUT)/truth.pvl \ + networkid=DefaultTruth \ + Description=RefByIncidence > /dev/null; + $(RM) $(OUTPUT)/cube.lis; diff --git a/isis/src/base/apps/cnetref/tsts/interestNoOverlaps/Makefile b/isis/src/base/apps/cnetref/tsts/interestNoOverlaps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c8be1087d6fb15c687c86241bf2f506654654d49 --- /dev/null +++ b/isis/src/base/apps/cnetref/tsts/interestNoOverlaps/Makefile @@ -0,0 +1,17 @@ +APPNAME = cnetref + +truth.pvl.IGNORELINES = UserName Created LastModified DateTime + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) -1 $(INPUT)/*.cub > $(OUTPUT)/cube.lis; + $(APPNAME) fromlist=$(OUTPUT)/cube.lis \ + network=$(INPUT)/autoseed.net \ + deffile=$(INPUT)/deffile.def \ + criteria=interest \ + limit=false \ + to=$(OUTPUT)/truth.pvl \ + networkid=DefaultTruth \ + Description=Testing > /dev/null; + $(RM) $(OUTPUT)/cube.lis; diff --git a/isis/src/base/apps/cnetref/tsts/interestOverlaps/Makefile b/isis/src/base/apps/cnetref/tsts/interestOverlaps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..dd07c6993643099a67dd2732f1372df86da6ca1c --- /dev/null +++ b/isis/src/base/apps/cnetref/tsts/interestOverlaps/Makefile @@ -0,0 +1,18 @@ +APPNAME = cnetref + +truth.pvl.IGNORELINES = UserName Created LastModified DateTime + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) -1 $(INPUT)/*.cub > $(OUTPUT)/cube.lis; + $(APPNAME) fromlist=$(OUTPUT)/cube.lis \ + network=$(INPUT)/autoseed.net \ + deffile=$(INPUT)/deffile.def \ + criteria=interest \ + limit=true \ + overlaplist=$(INPUT)/overlaps.lis \ + to=$(OUTPUT)/truth.pvl \ + networkid=DefaultTruth \ + Description=Testing > /dev/null; + $(RM) $(OUTPUT)/cube.lis; diff --git a/isis/src/base/apps/cnetref/tsts/resolutionMean/Makefile b/isis/src/base/apps/cnetref/tsts/resolutionMean/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..57359ca9030c61481986c821b9e0fdd909263438 --- /dev/null +++ b/isis/src/base/apps/cnetref/tsts/resolutionMean/Makefile @@ -0,0 +1,17 @@ +APPNAME = cnetref + +truth.pvl.IGNORELINES = UserName Created LastModified DateTime + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) -1 $(INPUT)/*.cub > $(OUTPUT)/cube.lis; + $(APPNAME) fromlist=$(OUTPUT)/cube.lis \ + network=$(INPUT)/autoseed.net \ + deffile=$(INPUT)/deffile.def \ + criteria=resolution \ + type=mean \ + to=$(OUTPUT)/truth.pvl \ + networkid=DefaultTruth \ + Description=RefByIncidence > /dev/null; + $(RM) $(OUTPUT)/cube.lis; diff --git a/isis/src/base/apps/cnetref/tsts/resolutionRange/Makefile b/isis/src/base/apps/cnetref/tsts/resolutionRange/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..782a35a55374aa177e925b6f7b20440c521797f5 --- /dev/null +++ b/isis/src/base/apps/cnetref/tsts/resolutionRange/Makefile @@ -0,0 +1,19 @@ +APPNAME = cnetref + +truth.pvl.IGNORELINES = UserName Created LastModified DateTime + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) -1 $(INPUT)/*.cub > $(OUTPUT)/cube.lis; + $(APPNAME) fromlist=$(OUTPUT)/cube.lis \ + network=$(INPUT)/autoseed.net \ + deffile=$(INPUT)/deffile.def \ + criteria=resolution \ + type=range \ + minres=200 \ + maxres=300 \ + to=$(OUTPUT)/truth.pvl \ + networkid=DefaultTruth \ + Description=RefByIncidence > /dev/null; + $(RM) $(OUTPUT)/cube.lis; diff --git a/isis/src/base/apps/cnettable/Makefile b/isis/src/base/apps/cnettable/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cnettable/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cnettable/assets/dataFiles/cnettableDataFile.csv b/isis/src/base/apps/cnettable/assets/dataFiles/cnettableDataFile.csv new file mode 100644 index 0000000000000000000000000000000000000000..604b581217057d3b6c1bdda112d92ab7f9d36cc5 --- /dev/null +++ b/isis/src/base/apps/cnettable/assets/dataFiles/cnettableDataFile.csv @@ -0,0 +1,21 @@ +ControlPointId,PointType,Ignored,Held,Invalid,UniversalLatitude,UniversalLongitude,Radius,Filename,Sample,Line,PixelValue,RightAscension,Declination,PlanetocentricLatitude,PlanetographicLatitude,PositiveEast360Longitude,PositiveEast180Longitude,PositiveWest360Longitude,PositiveWest180Longitude,BodyFixedCoordinateX,BodyFixedCoordinateY,BodyFixedCoordinateZ,LocalRadius,SampleResolution,LineResolution,SpacecraftPositionX,SpacecraftPositionY,SpacecraftPositionZ,SpacecraftAzimuth,SlantDistance,TargetCenterDistance,SubSpacecraftLatitude,SubSpacecraftLongitude,SpacecraftAltitude,OffNadirAngle,SubSpacecraftGroundAzimuth,SunPositionX,SunPositionY,SunPositionZ,SubSolarAzimuth,SolarDistance,SubSolarLatitude,SubSolarLongitude,SubSolarGroundAzimuth,Phase,Incidence,Emission,NorthAzimuth,EphemerisTime,UTC,LocalSolarTime,SolarLongitude,ZScoreMin,ZScoreMax,SampleError,LineError,ErrorMagnitude,Type,IsMeasured,IsValidated,Ignore,GoodnessOfFit,Error, +test001,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,382.612173,22.40249662,0.00331381,258.2155979,62.00735029,-85.22661477,-85.22661477,7.173346579,7.173346579,352.8266534,-7.173346579,143.205695,18.02340939,-1728.473269,1734489.134,186.9825039,186.9825039,205.446225,90.91444936,-2455.068712,151.2001694,732.8901186,2465.326747,-84.77142699,23.87043833,724.9522055,3.596264623,64.43250904,131706310.9,70619731.51,3224549.405,91.06299127,0.999207544,1.236072536,28.19980647,1.713665062,84.23685187,86.78129929,5.115008653,71.49947324,-182174920.9,1994-03-24T23:50:18.9050328,10.59823601,127.0208232,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test001,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,252.9700211,60.9426833,0.0049703,258.6935842,63.85536126,-85.2266147,-85.2266147,7.173321361,7.173321361,352.8266786,-7.173321361,143.2056812,18.02334364,-1728.472981,1734488.845,188.3225803,188.3225803,217.052067,54.34043824,-2462.013934,139.7412446,738.1426356,2472.16041,-84.80715236,14.05547681,734.3846913,1.714527132,51.54785836,142092325.2,46513002.91,3175614.909,92.28377282,0.999647351,1.216775827,18.12552426,0.907548326,84.87975621,86.53103956,2.44408553,81.78221193,-182103311.6,1994-03-25T19:43:48.2160328,11.26985314,129.0179102,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test002,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,306.5299454,45.28711781,0.00321958,258.3502415,63.16451346,-85.22661477,-85.22661477,13.11779026,13.11779026,346.8822097,-13.11779026,140.7309371,32.79518131,-1730.463639,1736486.431,186.1959371,186.1959371,205.446225,90.91444936,-2455.068712,145.5760583,729.8071186,2465.326747,-84.77142699,23.87043833,724.9522055,2.474994538,58.80817417,131706310.9,70619731.51,3224549.405,91.08495449,0.999207512,1.236072536,28.19980647,1.242855612,84.58754298,86.6278448,3.514914032,76.62961398,-182174920.9,1994-03-24T23:50:18.9050328,10.99453225,127.0208232,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test002,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,173.8973355,68.56283822,0.00487755,258.3362552,65.00598002,-85.22661539,-85.22661539,13.11777521,13.11777521,346.8822248,-13.11777521,140.7308582,32.79512396,-1730.46279,1736485.578,187.7343624,187.7343624,217.052067,54.34043824,-2462.013934,98.71499828,735.8370768,2472.16041,-84.80715236,14.05547681,734.3846913,1.008380692,10.52205266,142092325.2,46513002.91,3175614.909,92.27229481,0.999647336,1.216775827,18.12552426,0.416987753,85.035696,86.4622855,1.435664674,87.30851451,-182103311.6,1994-03-25T19:43:48.2160328,11.66615006,129.0179102,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test003,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,227.7456282,60.26222121,0.00396184,258.2155586,64.33439321,-85.22661709,-85.22661709,19.06221775,19.06221775,340.9377823,-19.06221775,136.7463646,47.25171066,-1732.600141,1738630.364,185.4899225,185.4899225,205.446225,90.91444936,-2455.068712,127.0295222,727.0398485,2465.326747,-84.77142699,23.87043833,724.9522055,1.478961864,40.26118089,131706310.9,70619731.51,3224549.405,90.95371348,0.999207491,1.236072536,28.19980647,0.758582675,84.82591699,86.5239592,2.097359945,81.0500158,-182174920.9,1994-03-24T23:50:18.9050328,11.39082742,127.0208232,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test003,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,93.7628528,67.96964813,0.00394784,257.649533,66.14194383,-85.2266149,-85.2266149,19.06223617,19.06223617,340.9377638,-19.06223617,136.7466168,47.25184705,-1732.602731,1738632.968,187.2281105,187.2281105,217.052067,54.34043824,-2462.013934,44.63147114,733.8527897,2472.16041,-84.80715236,14.05547681,734.3846913,1.430748466,311.4527277,142092325.2,46513002.91,3175614.909,92.36662114,0.999647332,1.216775827,18.12552426,359.0616926,85.07437985,86.44469382,2.034595909,93.22624257,-182103311.6,1994-03-25T19:43:48.2160328,12.06244746,129.0179102,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test004,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,147.0740384,67.11860657,0.0216343,257.7751556,65.50278531,-85.22661591,-85.22661591,25.00670704,25.00670704,334.993293,-25.00670704,131.258518,61.22555933,-1734.464185,1740500.899,184.9749726,184.9749726,205.446225,90.91444936,-2455.068712,75.05654052,725.0214687,2465.326747,-84.77142699,23.87043833,724.9522055,1.11831367,347.1571028,131706310.9,70619731.51,3224549.405,91.12147081,0.999207479,1.236072536,28.19980647,0.26608178,84.94843608,86.47076889,1.584132948,88.04584674,-182174920.9,1994-03-24T23:50:18.9050328,11.7871267,127.0208232,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test004,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,13.52126659,59.12556159,0.028667,256.5970237,67.24414654,-85.22661433,-85.22661433,25.0066739,25.0066739,334.9933261,-25.0066739,131.25876,61.22557974,-1734.466339,1740503.064,186.913821,186.913821,217.052067,54.34043824,-2462.013934,27.37651346,732.6209115,2472.16041,-84.80715236,14.05547681,734.3846913,2.465533393,288.2760332,142092325.2,46513002.91,3175614.909,92.21959093,0.999647338,1.216775827,18.12552426,353.1073267,84.99482088,86.47845745,3.503073999,98.10893579,-182103311.6,1994-03-25T19:43:48.2160328,12.45874331,129.0179102,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test005,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,343.9006523,118.8509716,0.00399211,260.9220057,62.86290612,-84.73194709,-84.73194709,11.88903171,11.88903171,348.1109683,-11.88903171,156.0649683,32.85684572,-1729.694331,1737031.469,186.0838185,186.0838185,205.446225,90.91444936,-2455.068712,172.8562327,729.3676626,2465.326747,-84.77142699,23.87043833,724.9522055,2.607814383,86.0897808,131706310.9,70619731.51,3224549.405,90.8218779,0.999207422,1.236072536,28.19980647,1.480888486,85.65310394,86.18086007,3.702506418,75.10891194,-182174920.9,1994-03-24T23:50:18.9050328,10.91261502,127.0208232,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test005,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,195.9408292,147.2894464,0.00481693,261.1549431,64.93055411,-84.73194692,-84.73194692,11.88901988,11.88901988,348.1109801,-11.88901988,156.0649215,32.85680223,-1729.69368,1737030.816,187.5639981,187.5639981,217.052067,54.34043824,-2462.013934,197.9551569,735.1693229,2472.16041,-84.80715236,14.05547681,734.3846913,0.49929662,109.7653679,142092325.2,46513002.91,3175614.909,92.23431939,0.999647238,1.216775827,18.12552426,0.572896094,86.1728333,85.98058965,0.710613392,86.03492216,-182103311.6,1994-03-25T19:43:48.2160328,11.58423304,129.0179102,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test006,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,265.6597682,136.2545061,0.0047437,260.9807334,64.03326032,-84.7319466,-84.7319466,17.27663215,17.27663215,342.7233679,-17.27663215,152.4850865,47.42560075,-1731.904277,1739250.791,185.3277318,185.3277318,205.446225,90.91444936,-2455.068712,177.2239988,726.4041313,2465.326747,-84.77142699,23.87043833,724.9522055,1.446560044,90.45782865,131706310.9,70619731.51,3224549.405,90.93075998,0.999207397,1.236072536,28.19980647,0.999259196,85.9264602,86.06420429,2.050667879,79.06897411,-182174920.9,1994-03-24T23:50:18.9050328,11.27178838,127.0208232,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test006,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,115.8214851,149.1357432,0.00482613,260.681686,66.08535787,-84.73194702,-84.73194702,17.27665799,17.27665799,342.723342,-17.27665799,152.4853037,47.42574372,-1731.907125,1739253.65,187.0076895,187.0076895,217.052067,54.34043824,-2462.013934,345.4317003,732.9888351,2472.16041,-84.80715236,14.05547681,734.3846913,0.719175039,254.0346819,142092325.2,46513002.91,3175614.909,92.29448563,0.999647231,1.216775827,18.12552426,0.078131326,86.24628325,85.94996621,1.022256703,91.38030006,-182103311.6,1994-03-25T19:43:48.2160328,11.94340892,129.0179102,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test007,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,185.3155531,146.3040213,0.0127408,260.7788855,65.21358428,-84.73194685,-84.73194685,22.66430032,22.66430032,337.3356997,-22.66430032,147.4417885,61.56832147,-1732.883764,1740234.432,184.9962046,184.9962046,205.446225,90.91444936,-2455.068712,195.8530621,725.1046889,2465.326747,-84.77142699,23.87043833,724.9522055,0.281222298,109.0881598,131706310.9,70619731.51,3224549.405,91.11399515,0.999207382,1.236072536,28.19980647,0.508704733,86.09473738,85.99327195,0.398398999,85.55380161,-182174920.9,1994-03-24T23:50:18.9050328,11.63096626,127.0208232,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test007,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,35.50547212,143.4345432,0.0193527,259.8834974,67.21795706,-84.73194707,-84.73194707,22.66429271,22.66429271,337.3357073,-22.66429271,147.4419105,61.56834942,-1732.885171,1740235.845,186.8778039,186.8778039,217.052067,54.34043824,-2462.013934,357.0125578,732.47974,2472.16041,-84.80715236,14.05547681,734.3846913,1.871564902,260.2498681,142092325.2,46513002.91,3175614.909,92.15505086,0.999647234,1.216775827,18.12552426,355.450959,86.2112123,85.96592267,2.659206861,96.43092749,-182103311.6,1994-03-25T19:43:48.2160328,12.30258456,129.0179102,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test008,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,380.8975242,192.1647328,0.00506414,263.4266842,62.52042935,-84.23727954,-84.23727954,10.87150317,10.87150317,349.1284968,-10.87150317,171.2677578,32.89263903,-1728.096589,1736874.317,186.2666686,186.2666686,205.446225,90.91444936,-2455.068712,193.428373,730.0843553,2465.326747,-84.77142699,23.87043833,724.9522055,3.215163645,106.6633092,131706310.9,70619731.51,3224549.405,91.15648635,0.999207332,1.236072536,28.19980647,1.718529188,86.7149995,85.73583293,4.566053747,74.54296594,-182174920.9,1994-03-24T23:50:18.9050328,10.84477978,127.0208232,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test008,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,217.9077564,225.7180125,0.00480681,263.9416908,64.80275987,-84.23727882,-84.23727882,10.87148867,10.87148867,349.1285113,-10.87148867,171.2677354,32.89258979,-1728.096062,1736873.789,187.688495,187.688495,217.052067,54.34043824,-2462.013934,238.5227938,735.6572967,2472.16041,-84.80715236,14.05547681,734.3846913,1.524516675,150.3357372,142092325.2,46513002.91,3175614.909,92.30766047,0.999647141,1.216775827,18.12552426,0.728691575,87.30577549,85.50089824,2.170167053,85.13012791,-182103311.6,1994-03-25T19:43:48.2160328,11.51639763,129.0179102,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test009,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,303.1098747,211.5320858,0.00490115,263.6555573,63.6859747,-84.23727636,-84.23727636,15.79799395,15.79799395,344.2020061,-15.79799395,167.9620506,47.52211802,-1729.658314,1738443.984,185.6514952,185.6514952,205.446225,90.91444936,-2455.068712,207.3433381,727.673143,2465.326747,-84.77142699,23.87043833,724.9522055,2.242378571,120.5791825,131706310.9,70619731.51,3224549.405,91.29969696,0.999207305,1.236072536,28.19980647,1.239288407,87.01678275,85.60863337,3.180789641,77.96687093,-182174920.9,1994-03-24T23:50:18.9050328,11.1732125,127.0208232,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test009,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,138.0120268,229.5388305,0.0057342,263.6674903,65.96608713,-84.23727683,-84.23727683,15.79802758,15.79802758,344.2019724,-15.79802758,167.9620445,47.52222279,-1729.658681,1738444.351,187.2734081,187.2734081,217.052067,54.34043824,-2462.013934,285.3277423,734.0303367,2472.16041,-84.80715236,14.05547681,734.3846913,1.405952648,195.4061815,142092325.2,46513002.91,3175614.909,92.23210753,0.999647132,1.216775827,18.12552426,0.234373778,87.40732857,85.45947663,1.999544723,90.11583057,-182103311.6,1994-03-25T19:43:48.2160328,11.84483355,129.0179102,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test010,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,223.3004373,224.0739849,0.0485699,263.6617735,64.86636346,-84.23727709,-84.23727709,20.72454903,20.72454903,339.275451,-20.72454903,163.3281999,61.79656866,-1730.376899,1739166.216,185.3517963,185.3517963,205.446225,90.91444936,-2455.068712,235.766086,726.4984539,2465.326747,-84.77142699,23.87043833,724.9522055,1.467754386,149.0032487,131706310.9,70619731.51,3224549.405,91.23651821,0.999207288,1.236072536,28.19980647,0.750768371,87.2208508,85.52304821,2.080821156,83.49580149,-182174920.9,1994-03-24T23:50:18.9050328,11.5016495,127.0208232,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, +test010,Tie,0,0,0,-1.79769313486231e+308,-1.79769313486231e+308,-1.79769313486231e+308,.cub,57.78396796,226.3387214,0.0473951,263.1048042,67.11724123,-84.23727629,-84.23727629,20.72458055,20.72458055,339.2754195,-20.72458055,163.3281389,61.79664827,-1730.376371,1739165.689,187.1751654,187.1751654,217.052067,54.34043824,-2462.013934,319.7068792,733.6452679,2472.16041,-84.80715236,14.05547681,734.3846913,2.023707399,224.8798019,142092325.2,46513002.91,3175614.909,92.03372034,0.999647132,1.216775827,18.12552426,357.3933457,87.40765217,85.4606517,2.877237107,95.50233756,-182103311.6,1994-03-25T19:43:48.2160328,12.17327042,129.0179102,-1.79769313486231e+308,-1.79769313486231e+308,0,0,0,2,1,0,0,-1.79769313486231e+308,N/A, diff --git a/isis/src/base/apps/cnettable/assets/images/cnettableGUI.jpg b/isis/src/base/apps/cnettable/assets/images/cnettableGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..01fbaf2cba06565a8a13a9186b9f27bf5e110c51 Binary files /dev/null and b/isis/src/base/apps/cnettable/assets/images/cnettableGUI.jpg differ diff --git a/isis/src/base/apps/cnettable/assets/thumbs/cnettableGUI.jpg b/isis/src/base/apps/cnettable/assets/thumbs/cnettableGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..24dbe9e2b23a6f7788b1e0f85f356d66fafe94aa Binary files /dev/null and b/isis/src/base/apps/cnettable/assets/thumbs/cnettableGUI.jpg differ diff --git a/isis/src/base/apps/cnettable/cnettable.cpp b/isis/src/base/apps/cnettable/cnettable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b89027e235fe131624b87619bbe50c64a718efd2 --- /dev/null +++ b/isis/src/base/apps/cnettable/cnettable.cpp @@ -0,0 +1,215 @@ +#include "Isis.h" + +#include "CameraPointInfo.h" +#include "ControlMeasure.h" +#include "ControlNet.h" +#include "ControlPoint.h" +#include "Filename.h" +#include "iException.h" +#include "iString.h" +#include "Progress.h" +#include "PvlGroup.h" +#include "PvlKeyword.h" +#include "PvlObject.h" +#include "SerialNumberList.h" +#include "TextFile.h" +#include "UserInterface.h" + +#include +#include + +#include + +using namespace std; +using namespace Isis; + +void Write(PvlGroup * point, ControlMeasure & cm); + +// Allows for column names to be written on the first pass +bool isFirst; +bool append; + +TextFile * txt = NULL; + +// For control measure related data and labels +QString measureInfo; +QString measureLabels; + +void IsisMain() { + isFirst = true; + append = false; + bool outside = false; + bool errors = false; + measureInfo = ""; + measureLabels = ""; + + Progress prog; + + // Get user entered information + UserInterface &ui = Application::GetUserInterface(); + ControlNet cnet(ui.GetFilename("CNET")); + SerialNumberList serials(ui.GetFilename("FROMLIST")); + append = ui.GetBoolean("APPEND"); + + if (cnet.Size() == 0) { + string msg = "Your control network must contain at least one point"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + prog.SetMaximumSteps(cnet.Size()); + + // If append is true, output will be appended or a new file created + if (append) { + // Check to see if its a new file or we open an existing file + Filename file(ui.GetFilename("TO")); + if (!file.Exists()) { + // It is new, so we aren't appending + append = false; + } + txt = new TextFile(ui.GetFilename("TO"), "append"); + } + // Without append, if the files exists it will be overwritten + else { + txt = new TextFile(ui.GetFilename("TO"), "overwrite"); + } + + PvlGroup * grp = NULL; + CameraPointInfo camPoint; + + outside = ui.GetBoolean("ALLOWOUTSIDE"); + errors = ui.GetBoolean("ALLOWERRORS"); + + // Loop through all points in controlnet + for (int i = 0; i < cnet.Size(); i++) { + ControlPoint & cpoint = cnet[i]; + + if (isFirst && !append) { + measureLabels += "ControlPointId,"; + measureLabels += "PointType,"; + measureLabels += "Ignored,"; + measureLabels += "Held,"; + measureLabels += "Invalid,"; + measureLabels += "UniversalLatitude,"; + measureLabels += "UniversalLongitude,"; + measureLabels += "Radius,"; + } + + // Always add data + measureInfo.clear(); + measureInfo += QString(cpoint.Id().c_str()) + ","; + measureInfo += QString(cpoint.PointTypeToString().c_str()) + ","; + measureInfo += iString(cpoint.Ignore()).ToQt() + ","; + measureInfo += iString(cpoint.Held()).ToQt() + ","; + measureInfo += iString(cpoint.Invalid()).ToQt() + ","; + measureInfo += iString(cpoint.UniversalLatitude()).ToQt() + ","; + measureInfo += iString(cpoint.UniversalLongitude()).ToQt() + ","; + measureInfo += iString(cpoint.Radius()).ToQt() + ","; + + // Loop through all measures in controlpoint + for (int j = 0; j < cpoint.Size(); j++) { + + ControlMeasure & cmeasure = cpoint[j]; + + // Set and then get CameraPointInfo information + camPoint.SetCube(serials.Filename(cmeasure.CubeSerialNumber())); + + grp = camPoint.SetImage(cmeasure.Sample(), cmeasure.Line(), outside, errors); + // Shouldn't ever happen, but, being safe... + if (grp == NULL) { + string msg = "You shouldn't have gotten here. Errors in CameraPointInfo class"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + Write(grp, cmeasure); + delete grp; + grp = NULL; + } + + // Making progress! + prog.CheckStatus(); + } + + // All done, clean up + prog.CheckStatus(); + if (txt != NULL) { + delete txt; + txt = NULL; + } +} + +// Write each PvlGroup out to file +void Write(PvlGroup * point, ControlMeasure & cm) { + + // QStrings are used QString here because of ControlMeasure returning + // QStrings. There is some monkey motion involving ingesting doubles, + // this is necessary as iString will accept doubles but QString won't. + + QString output = ""; + QVector < QString > dataNames; + + // Do we have errors? + int maxCount = 0; + bool errors = point->HasKeyword("Error"); + if (errors) { + maxCount = point->Keywords() - 1; + } + else { + maxCount = point->Keywords(); + } + + // If its first and not appending, write the column labels + if (isFirst && !append) { + // point information + for (int i = 0; i < maxCount; i++) { + if ((*point)[i].Size() == 3) { + output += QString((*point)[i].Name().c_str()) + "X,"; + output += QString((*point)[i].Name().c_str()) + "Y,"; + output += QString((*point)[i].Name().c_str()) + "Z,"; + } + else { + output += QString((*point)[i].Name().c_str()) + ","; + } + } + + // control measure information + dataNames = cm.GetMeasureDataNames(); + for (int i = 0; i < dataNames.size(); i++) { + output += dataNames[i] + ","; + } + if (errors) output += QString((*point)[maxCount].Name().c_str()); + isFirst = false; + measureLabels += output; + txt->PutLine(measureLabels.toStdString()); + } + output.clear(); + measureLabels.clear(); + + // Write out date values + // point information + for (int i = 0; i < maxCount; i++) { + if ((*point)[i].Size() == 3) { + output += QString((*point)[i][0]) + ","; + output += QString((*point)[i][1]) + ","; + output += QString((*point)[i][2]) + ","; + } + else { + output += QString((*point)[i][0]) + ","; + } + } + + dataNames = cm.GetMeasureDataNames(); + for (int i = 0; i < dataNames.size(); i++) { + output += iString(cm.GetMeasureData(dataNames[i])).ToQt() + ","; + } + + if (errors) output += QString((*point)[maxCount][0]); + + // Meseaure info comes first + QString pri = ""; + pri += measureInfo; + pri += output; + + txt->PutLine(pri.toStdString()); + + output.clear(); + pri.clear(); +} diff --git a/isis/src/base/apps/cnettable/cnettable.xml b/isis/src/base/apps/cnettable/cnettable.xml new file mode 100644 index 0000000000000000000000000000000000000000..877c2527b5f800253a771f40eb38434a657f8ea7 --- /dev/null +++ b/isis/src/base/apps/cnettable/cnettable.xml @@ -0,0 +1,279 @@ + + + + + Application to get Excel compatible statistics + + + This application takes a control net and outputs the same data avalible from + campt for every control measure in the control net. It also outputs data + about the measure and point. This data is formated as a flat file and is + comma seperated so it can be imported to Excel. The columns titles in the + file are: + + + + + + +
    +
      +
    • ControlPointId
    • +
    • PointType
    • +
    • Ignored
    • +
    • Held
    • +
    • Invalid
    • +
    • UniversalLatitude
    • +
    • UniversalLongitude
    • +
    • Radius
    • +
    • Filename
    • +
    • Sample
    • +
    • Line
    • +
    • PixelValue
    • +
    • Declination
    • +
    • PlanetocentricLatitude
    • +
    • PlanetographicLatitude
    • +
    • PositiveEast360Longitude
    • +
    • PositiveEast180Longitude
    • +
    • PositiveWest360Longitude
    • +
    • PositiveWest180Longitude
    • +
    • BodyFixedCoordinateX
    • +
    • BodyFixedCoordinateY
    • +
    • BodyFixedCoordinateZ
    • +
    • LocalRadius
    • +
    • SampleResolution
    • +
    • LineResolution
    • +
    • SpacecraftPositionX
    • +
    • SpacecraftPositionY
    • +
    • SpacecraftPositionZ
    • +
    • SpacecraftAzimuth
    • +
    • SlantDistance
    • +
    • TargetCenterDistance
    • +
    • SubSpacecraftLatitude
    • +
    +
    +
      +
    • SubSpacecraftLongitude
    • +
    • SpacecraftAltitude
    • +
    • OffNadirAngle
    • +
    • SubSpacecraftGroundAzimuth
    • +
    • SunPositionX
    • +
    • SunPositionY
    • +
    • SunPositionZ
    • +
    • SubSolarAzimuth
    • +
    • SolarDistance
    • +
    • SubSolarLatitude
    • +
    • SubSolarLongitude
    • +
    • SubSolarGroundAzimuth
    • +
    • Phase
    • +
    • Incidence
    • +
    • Emission
    • +
    • NorthAzimuth
    • +
    • EphemerisTime
    • +
    • UTC
    • +
    • LocalSolarTime
    • +
    • SolarLongitude
    • +
    • ZScoreMin
    • +
    • ZScoreMax
    • +
    • SampleError
    • +
    • LineError
    • +
    • ErrorMagnitude
    • +
    • Type
    • +
    • IsMeasured
    • +
    • IsValidated
    • +
    • Ignore
    • +
    • GoodnessOfFit
    • +
    • Error
    • +
    +
    +
    + + + + Original version + + + Added ALLOWOUTSIDE option + default behavior not modified at all. + + + Change to CameraPointInfo added two parameters to output and modified + two Output now had PositiveEast360Longitude and PositiveWest180Longitude. + Also made append option more forgiving so that it will create a file if + none exists. + + + Added option to allow for errors so that instead of crashing the program + continues and reports the errors in the output file. + + + Updated and added to documentation. + + + Gave cnettable the ability to compile + + + + + Control Networks + + + + + + campt + + + + + + + + + filename + input + + List of cubes associated with control net + + + Use this parameter to select the filename of a list of cubes the + cubes used to create the control net. + + + *.txt *.lis *.lst *.list + + + + + filename + input + + A control net + + + The control net from which to derive statistics. + + + *.net *.cnet + + + + + filename + output + + Text file containing the control net statistics + + + This file will contain the statistics of all the control measures in + the control net. + + + *.txt *.csv + + + + + boolean + false + + Append output to "TO" file + + + If checked this option allows file output to be appended to a file or + create a new file. If the file already exists and append is off the + program will overwrite the existing file. + + + + + + + boolean + false + + Allow sample/line values outside of the images + + + When checked sample/line values that are outside of the images (but + close) will be extrapolated. For example a sample of -0.5 would be + valid. If this is not checked a sample of -0.5 is not allowed. + + + + + + + boolean + false + + Allow errors to occur without halting execution. + + + If errors occur such as values not having an intersection with the + body or sample line locations outside of the cube with ALLOWOUTSIDE + not checked the program will continue and report the error and reason + to the file. If no errors occur "N/A" is put into the column, + otherwise, the reason for the error is written to the file. + + + + + + + + + + Usage of cnettable application + + + This is an example of how to use cnettable to produce a flatfile + or csv file for excel or other uses. The required elements are a list + of cubes and a corresponding control network. The easiest way to get + this is to run findimageoverlaps on a list of cubes and then autoseed + this list with the overlaps. + + + + + fromlist=cubeList.lst cnet=testNet.net to=output.csv + + + These arguments will produce a flatfile containing infomation on all + the points in the control net. + + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to take a list of + cubes a control network and output to a text file. + + + + + + + + + + An small example file of the output of the application. + + + This file contains the output of a run of cnettable on a very small + control network. It shows all the expected data for the program and + the format the data is in. + + + + + + +
    diff --git a/isis/src/base/apps/cnettable/tsts/Makefile b/isis/src/base/apps/cnettable/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cnettable/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cnettable/tsts/allowErrors/Makefile b/isis/src/base/apps/cnettable/tsts/allowErrors/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bd030799a50d6d3820049a20668205819adac618 --- /dev/null +++ b/isis/src/base/apps/cnettable/tsts/allowErrors/Makefile @@ -0,0 +1,15 @@ +APPNAME = cnettable + +include $(ISISROOT)/make/isismake.tsts + +commands: + find $(INPUT)/*.cub > $(INPUT)/cubeList.lst; \ + $(APPNAME) fromlist=$(INPUT)/cubeList.lst \ + cnet=$(INPUT)/testNet.net \ + to=$(OUTPUT)/cnetstats.txt \ + allowErrors = true \ + > /dev/null; + rm -f $(INPUT)/cubeList.lst > /dev/null; + cat $(OUTPUT)/cnetstats.txt | sed s/,\[^,]\*\.cub,/,.cub,/ \ + > $(OUTPUT)/output.txt + rm -f $(OUTPUT)/cnetstats.txt > /dev/null; diff --git a/isis/src/base/apps/cnettable/tsts/append/Makefile b/isis/src/base/apps/cnettable/tsts/append/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d8a6a2ca0aa8fc55fe6b7a3bfe997f277ae85faa --- /dev/null +++ b/isis/src/base/apps/cnettable/tsts/append/Makefile @@ -0,0 +1,15 @@ +APPNAME = cnettable + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/appendTo.txt $(OUTPUT); \ + find $(INPUT)/*.cub > $(INPUT)/cubeList.lst; \ + $(APPNAME) fromlist=$(INPUT)/cubeList.lst \ + cnet=$(INPUT)/testNet.net \ + to=$(OUTPUT)/appendTo.txt \ + append=true > /dev/null; + rm -f $(INPUT)/cubeList.lst > /dev/null; + cat $(OUTPUT)/appendTo.txt | sed s/,\[^,]\*\.cub,/,.cub,/ \ + > $(OUTPUT)/output.txt + rm -f $(OUTPUT)/appendTo.txt diff --git a/isis/src/base/apps/cnettable/tsts/default/Makefile b/isis/src/base/apps/cnettable/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d3a4305f0b9e81752ac0170c0e86029640bf4f9c --- /dev/null +++ b/isis/src/base/apps/cnettable/tsts/default/Makefile @@ -0,0 +1,14 @@ +APPNAME = cnettable + +include $(ISISROOT)/make/isismake.tsts + +commands: + find $(INPUT)/*.cub > $(INPUT)/cubeList.lst; \ + $(APPNAME) fromlist=$(INPUT)/cubeList.lst \ + cnet=$(INPUT)/testNet.net \ + to=$(OUTPUT)/cnetstats.txt \ + > /dev/null; + rm -f $(INPUT)/cubeList.lst > /dev/null; + cat $(OUTPUT)/cnetstats.txt | sed s/,\[^,]\*\.cub,/,.cub,/ \ + > $(OUTPUT)/output.txt + rm -f $(OUTPUT)/cnetstats.txt > /dev/null; diff --git a/isis/src/base/apps/coreg/Makefile b/isis/src/base/apps/coreg/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/coreg/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/coreg/assets/image/lunar1.jpg b/isis/src/base/apps/coreg/assets/image/lunar1.jpg new file mode 100755 index 0000000000000000000000000000000000000000..b350336ae4f93c3ddcdb8b0d2f9dee7828994614 Binary files /dev/null and b/isis/src/base/apps/coreg/assets/image/lunar1.jpg differ diff --git a/isis/src/base/apps/coreg/assets/image/lunar2.jpg b/isis/src/base/apps/coreg/assets/image/lunar2.jpg new file mode 100755 index 0000000000000000000000000000000000000000..2c65959637228dbef9d4581133fc54073ca27e6e Binary files /dev/null and b/isis/src/base/apps/coreg/assets/image/lunar2.jpg differ diff --git a/isis/src/base/apps/coreg/assets/image/out.jpg b/isis/src/base/apps/coreg/assets/image/out.jpg new file mode 100755 index 0000000000000000000000000000000000000000..bb754e5c2c2b02a404a122de914619dab314e15a Binary files /dev/null and b/isis/src/base/apps/coreg/assets/image/out.jpg differ diff --git a/isis/src/base/apps/coreg/assets/patternMatch.doc b/isis/src/base/apps/coreg/assets/patternMatch.doc new file mode 100755 index 0000000000000000000000000000000000000000..9faee55705968d37974a754b2d1df0fcfa73f943 Binary files /dev/null and b/isis/src/base/apps/coreg/assets/patternMatch.doc differ diff --git a/isis/src/base/apps/coreg/assets/thumb/lunar1.jpg b/isis/src/base/apps/coreg/assets/thumb/lunar1.jpg new file mode 100755 index 0000000000000000000000000000000000000000..a808a169f24f6a5c8c57cf3375bffef0df9afe17 Binary files /dev/null and b/isis/src/base/apps/coreg/assets/thumb/lunar1.jpg differ diff --git a/isis/src/base/apps/coreg/assets/thumb/lunar2.jpg b/isis/src/base/apps/coreg/assets/thumb/lunar2.jpg new file mode 100755 index 0000000000000000000000000000000000000000..cace936e0946f706a2e6181e550faed1335aff5d Binary files /dev/null and b/isis/src/base/apps/coreg/assets/thumb/lunar2.jpg differ diff --git a/isis/src/base/apps/coreg/assets/thumb/out.jpg b/isis/src/base/apps/coreg/assets/thumb/out.jpg new file mode 100755 index 0000000000000000000000000000000000000000..fd953b2fe2d5f6c8a5166d05c1f4bfd27ab002d5 Binary files /dev/null and b/isis/src/base/apps/coreg/assets/thumb/out.jpg differ diff --git a/isis/src/base/apps/coreg/coreg.cpp b/isis/src/base/apps/coreg/coreg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8c1c45a4d269a149cc38da6e5f00cc8cecd900c4 --- /dev/null +++ b/isis/src/base/apps/coreg/coreg.cpp @@ -0,0 +1,275 @@ +#define GUIHELPERS + +#include "Isis.h" +#include "PvlGroup.h" +#include "UserInterface.h" +#include "Cube.h" +#include "Chip.h" +#include "Progress.h" +#include "iException.h" +#include "AutoReg.h" +#include "AutoRegFactory.h" +#include "Statistics.h" +#include "ControlNet.h" +#include "SerialNumber.h" +#include "ControlMeasure.h" +#include "iTime.h" + +using namespace std; +using namespace Isis; + +//helper button functins in the code +void helperButtonLog(); + +map GuiHelpers(){ + map helper; + helper ["helperButtonLog"] = (void*) helperButtonLog; + return helper; +} + +void IsisMain() { + // Get user interface + UserInterface &ui = Application::GetUserInterface(); + + // Make sure the correct parameters are entered + if (ui.WasEntered("TO")) { + if (ui.GetString("TRANSFORM") == "WARP") { + if (!ui.WasEntered("CNETFILE")) { + string msg = "A Control Net file must be entered if the TO parameter is "; + msg += "entered"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + } + + // Open the first cube. It will be matched to the second input cube. + Cube trans; + CubeAttributeInput &attTrans = ui.GetInputAttribute("FROM"); + vector bandTrans = attTrans.Bands(); + trans.SetVirtualBands(bandTrans); + trans.Open(ui.GetFilename("FROM"),"r"); + + + // Open the second cube, it is held in place. We will be matching the + // first to this one by attempting to compute a sample/line translation + Cube match; + CubeAttributeInput &attMatch = ui.GetInputAttribute("MATCH"); + vector bandMatch = attMatch.Bands(); + match.SetVirtualBands(bandMatch); + match.Open(ui.GetFilename("MATCH"),"r"); + + // Input cube Lines and Samples must be the same and each must have only + // one band + if ((trans.Lines() != match.Lines()) || + (trans.Samples() != match.Samples())) { + string msg = "Input Cube Lines and Samples must be equal!"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + if (trans.Bands() != 1 || match.Bands() != 1) { + string msg = "Input Cubes must have only one band!"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Get serial number + string serialTrans = SerialNumber::Compose(trans, true); + string serialMatch = SerialNumber::Compose(match, true); + +// This still precludes band to band registrations. + if (serialTrans == serialMatch) { + string sTrans = Filename(trans.Filename()).Name(); + string sMatch = Filename(match.Filename()).Name(); + if (sTrans == sMatch) { + string msg = "Cube Serial Numbers must be unique - FROM=" + serialTrans + + ", MATCH=" + serialMatch; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + serialTrans = sTrans; + serialMatch = sMatch; + } + + + // We need to get a user definition of how to auto correlate around each + // of the control points. + Pvl regdef; + regdef.Read(ui.GetFilename("REGDEF")); + AutoReg *ar = AutoRegFactory::Create(regdef); + + // We want to create a grid of control points that is N rows by M columns. + // Get row and column variables, if not entered, default to 1% of the input + // image size + int rows, cols; + if (ui.WasEntered("ROWS")) { + rows = ui.GetInteger("ROWS"); + } + else { + rows = (int)((trans.Lines() - 1) / ar->SearchChip()->Lines() + 1); + } + if (ui.WasEntered("COLUMNS")) { + cols = ui.GetInteger("COLUMNS"); + } + else { + cols = (int)((trans.Samples() - 1) / ar->SearchChip()->Samples() + 1); + } + + // Display the progress...10% 20% etc. + Progress prog; + prog.SetMaximumSteps(rows * cols); + prog.CheckStatus(); + + // Calculate spacing for the grid of points + double lSpacing = (double)trans.Lines() / rows; + double sSpacing = (double)trans.Samples() / cols; + + // Initialize control point network + ControlNet cn; + cn.SetType(ControlNet::ImageToImage); + cn.SetUserName(Application::UserName()); + cn.SetCreatedDate(iTime::CurrentLocalTime()); + + // Loop through grid of points and get statistics to compute + // translation values + Statistics sStats, lStats; + for (int r=0; rPatternChip()->TackCube(samp, line); + ar->PatternChip()->Load(match); + ar->SearchChip()->TackCube(samp, line); + ar->SearchChip()->Load(trans); + + // Set up ControlMeasure for cube to translate + ControlMeasure cmTrans; + cmTrans.SetCubeSerialNumber(serialTrans); + cmTrans.SetCoordinate(samp, line, ControlMeasure::Unmeasured); + cmTrans.SetChooserName("coreg"); + cmTrans.SetReference(false); + + // Set up ControlMeasure for the pattern/Match cube + ControlMeasure cmMatch; + cmMatch.SetCubeSerialNumber(serialMatch); + cmMatch.SetCoordinate(samp, line, ControlMeasure::Automatic); + cmMatch.SetChooserName("coreg"); + cmMatch.SetReference(true); + + // Match found + if (ar->Register()==AutoReg::Success) { + double sDiff = samp - ar->CubeSample(); + double lDiff = line - ar->CubeLine(); + sStats.AddData(&sDiff,(unsigned int)1); + lStats.AddData(&lDiff,(unsigned int)1); + cmTrans.SetCoordinate(ar->CubeSample(), ar->CubeLine(), + ControlMeasure::Automatic); + cmTrans.SetError(sDiff, lDiff); + cmTrans.SetGoodnessOfFit(ar->GoodnessOfFit()); + } + + // Add the measures to a control point + string str = "Row " + iString(r) + " Column " + iString(c); + ControlPoint cp(str); + cp.SetType(ControlPoint::Tie); + cp.Add(cmTrans); + cp.Add(cmMatch); + if (!cmTrans.IsMeasured()) cp.SetIgnore(true); + cn.Add(cp); + prog.CheckStatus(); + } + } + + // Write translation to log + PvlGroup results("Translation"); + double sMin = (int)(sStats.Minimum() * 100.0) / 100.0; + double sTrans = (int)(sStats.Average() * 100.0) / 100.0; + double sMax = (int)(sStats.Maximum() * 100.0) / 100.0; + double sDev = (int)(sStats.StandardDeviation() * 100.0) / 100.0; + double lMin = (int)(lStats.Minimum() * 100.0) / 100.0; + double lTrans = (int)(lStats.Average() * 100.0) / 100.0; + double lMax = (int)(lStats.Maximum() * 100.0) / 100.0; + double lDev = (int)(lStats.StandardDeviation() * 100.0) / 100.0; + + results += PvlKeyword ("SampleMinimum", sMin); + results += PvlKeyword ("SampleAverage", sTrans); + results += PvlKeyword ("SampleMaximum", sMax); + results += PvlKeyword ("SampleStandardDeviation", sDev); + results += PvlKeyword ("LineMinimum", lMin); + results += PvlKeyword ("LineAverage", lTrans); + results += PvlKeyword ("LineMaximum", lMax); + results += PvlKeyword ("LineStandardDeviation", lDev); + Application::Log(results); + + Pvl arPvl = ar->RegistrationStatistics(); + + for(int i = 0; i < arPvl.Groups(); i++) { + Application::Log(arPvl.Group(i)); + } + + // add the auto registration information to print.prt + PvlGroup autoRegTemplate = ar->RegTemplate(); + Application::Log(autoRegTemplate); + + // If none of the points registered, throw an error + if (sStats.TotalPixels() < 1) { + string msg = "Coreg was unable to register any points. Check your algorithm definition."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Don't need the cubes opened anymore + trans.Close(); + match.Close(); + + // If a cnet file was entered, write the ControlNet pvl to the file + if (ui.WasEntered("CNETFILE")) { + cn.Write(ui.GetFilename("CNETFILE")); + } + + // If flatfile was entered, create the flatfile + // The flatfile is comma seperated and can be imported into an excel + // spreadsheet + if (ui.WasEntered("FLATFILE")) { + string fFile = Filename(ui.GetFilename("FLATFILE")).Expanded(); + ofstream os; + os.open(fFile.c_str(),ios::out); + os << "Sample,Line,TranslatedSample,TranslatedLine," << + "SampleDifference,LineDifference,GoodnessOfFit" << endl; + for (int i=0; iExec("translate",params); + } + else { + string params = "from=" + ui.GetFilename("FROM") + " to=" + + ui.GetFilename("TO") + " cube=" + ui.GetFilename("MATCH") + " control=" + + ui.GetFilename("CNETFILE") + " interp=" + ui.GetString("INTERP") + + " degree=" + iString(ui.GetInteger("DEGREE")); + iApp->Exec("warp",params); + + } + } +} + +//Helper function to output the regdeft file to log. +void helperButtonLog () { + UserInterface &ui = Application::GetUserInterface(); + string file(ui.GetFilename("REGDEF")); + Pvl p; + p.Read(file); + Application::GuiLog(p); +} +//...........end of helper function ........ diff --git a/isis/src/base/apps/coreg/coreg.xml b/isis/src/base/apps/coreg/coreg.xml new file mode 100644 index 0000000000000000000000000000000000000000..12b64b9e098980910193219a4a01c8cc57161cbd --- /dev/null +++ b/isis/src/base/apps/coreg/coreg.xml @@ -0,0 +1,437 @@ + + + + + + Subpixel registration of a pair of images + + + + This program co-regsisters two images using a constant sample/line translation. This implies of course that the + internal geometry of the both images be nearly the same so that the translation can be computed. That is, this + program will not work if the translation varies significantly throughout the image. However, there are still useful + capabilities in this program if this condition is not meet. If the condition of near constant translation is met then + the translation can be computed to sub-pixel accuracy. The basic principle behind this program is to compute + an average translation by computing local translations spaced evenly throughout the image. The number and + spacing of local translations is user defined. This allows for many output options including 1) directly creating the + translated image, 2) creating a control network which can be used in other programs (e.g., qnet, warp), especially + if the translation is not constant across the image, or 3) creating a flat-field file usable in spreadsheets or plotting + packages to visualize magnitude and direction of varying translations. +

    + NOTE: This program can utilize many different techniques for computing the translation. It is recommend that + you read "Automatic Registration in Isis 3.0". It is essential for under understanding how to create a "registration + definition" file and how to size your search and pattern chips. We will continue with the discussion of functionality + of this program assuming the reader has a fundamental knowledge of Automatic Registration. For the brave we + give an example of a defintion file (REGDEF): +

    +
    +         Object = AutoRegistration
    +           Group = Algorithm
    +             Name         = MaximumCorrelation
    +             Tolerance    = 0.7
    +           EndGroup
    +
    +           Group = PatternChip
    +             Samples = 20
    +             Lines   = 20
    +             ValidMinimum = 1400
    +             ValidPercent = 75
    +           EndGroup
    +
    +           Group = SearchChip
    +             Samples = 90
    +             Lines   = 90
    +             ValidMinimum = 1400
    +             ValidPercent = 75
    +           EndGroup
    +         EndObject
    +     
    +

    + You will provide two input cubes, one which will be translated (FROM) and the other is held fixed (MATCH). + The images must have the same number of samples and lines and can have only one band (use cube + attributes if necessary). A sparse grid will be defined across the held image using the parameters ROWS + and COLUMNS. If the user does not provide values for the sparse grid size it will be automatically computed + as follows: COLUMNS = (image samples - 1) / search chip samples + 1. Similarly for ROWS. Conceptually, + the sparse grid defined by ROWS and COLUMNS will be laid on top of both images with even spacing between + the rows (or columns) and but no row will touch the top or bottom of the image. That is, the grid is internal to the + image. +

    +

    + At each grid intersection we will compute a translation. This is done by centering the search chip at the grid + intersection for the image to be translated (FROM) and centering the pattern chip at the grid intersection for the + held image (MATCH). The pattern chip is walked through the search chip to find the best registration (if any). + Again the details of how this is done is described in the document "Automatic Registation in Isis 3.0". The local + translation is recorded at all grid intersections that had a successful registration. It will be written to the control + network and/or flat-file if requested. The average of the local translations is then used to compute an overall + sub-pixel translation which can be applied to the output image (TO). +

    + +

    + Some tips to improve odds of a successful registration. In general don't go too small with the pattern chip size, + 20x20 is probably a good starting point. Also, the larger the translation, the larger the search chip size will need + to be. So if your translation is only a couple of pixels keep the search chip slightly bigger than the pattern + (e.g., 25x25 vs 20x20). However if the translation is large you will need to expand the seach area. For example, + if the translation is roughly 45 pixels and your pattern is 20x20 the search area should be 20+2*45 or 110x110. +

    +
    + + + Registration and Pattern Matching + + + + coreg2 + coregpr + coregpr2 + + + + + autoregtemplate + warp + translate + + + + Automatic Registration in Isis 3.0 + + patternMatch.doc + assets/ + + + + + + + + Original Version + + + Ported to Isis3.0 + + + Added warp option and fixed bug in control net creation + + + Fixed appTest + + + Fixed appTest to comply with changes made to the ControlMeasure class. + + + Added error reporting when the registration was a failure. + + + Set the MATCH file as the reference image so it can be used in + subsequent processing. Implemented use of unique serial numbers + for each image. Issues still remain with handling band-to-band + registrations within files. One alternative is to extract bands to + separate files as a fallback approach is to use filenames as the + serial number. This solution/alterntive is unique to coreg, however. + + + Modified call for current time to point to Time class, instead of Application class + + + Modified to reflect changes to the SerialNumber class + + + Updated to properly check AutoReg::Register()'s return status + + + Added two new optional arguments to AutoReg: WindowSize and + DistanceTolerance. These two arguments affect how AutoReg gathers and + compares data for surface modeling and accuracy. Added more statistics + to the Translation group, including min/max and standard deviation of + line/sample changes. Added the AutoReg statistics to be displayed as + well. + + + Auto registration parameters are now placed into the print file. + + + Auto registration parameters now placed into the print file before + potential throwing of exceptions. + + + + + + + cube + input + + Input Image to be Translated + + + This cube will be translated to match the MATCH cube. + + + *.cub + + + + + cube + input + + The Held Input Image + + + This cube will be held. The FROM cube will be translated to match this cube. + + + *.cub + + + + + filename + input + + The Auto Registration template + + + The template to use with the AutoReg class. Default will be maximum correlation function + with a tolerance of 0.7, a search cube of 50x50 pixels, and a pattern cube of 20x20 pixels. + There will also be other templates available in the default directory. + + + + helperButtonLog + View file in log area + This helper button will display the regdef file in the log area + $ISIS3DATA/base/icons/view_text.png + + + + *.def + + $base/templates/autoreg/coreg.maxcor.p2020.s5050.def + $base/templates/autoreg + + + + + + cube + output + + Output Cube + + + Output cube containing the translated or warped data. + + None + + *.cub + + + + + string + + Tranformation Type + + + The tranformation type to use on the output file. The options are TRANSLATE or WARP. + If WARP is selected, the CNETFILE and DEGREE parameters are required. + Defaults to TRANSLATE. + + TRANSLATE + + + + + + + integer + + Degree for Warp Transformation + + + The degree to be used in the warp transformation for the linear regression + model. Defaults to 1. + + 1 + + + + string + + Interpolation used for Transformation + + + This will be the interpolation type used to get the output file in either the + translate or warp application. Defaults to NEARESTNEIGHBOR. + + CUBICCONVOLUTION + + + + + + + + + + + + filename + output + + Pvl file of ControlNet + + + This file will contain the ControlNet created in the coreg application. The data + will be in Pvl format. This option is required if the WARP option is selected for + the output file. + + None + + *.txt *.lis *.lst + + + + + filename + output + + Text file of coreg data + + + This file will contain the data collected from the coreg application. The data + will be comma separated and contain the sample, line position in the first input + cube, the sample, line position found in the search cube, and the sample difference + and line difference between to two. + + None + + *.txt *.lis *.lst + + + + + integer + + Number of Rows of Points to use. + + + The number of rows of points to use in the coreg process. If not entered, + it will default to ROWS = (image lines - 1) / search chip lines + 1. + + Automatic + 1 + + + + integer + + Number of Columns of Points to use. + + + The number of columns of points to use in the coreg process. If not entered, + it will default to COLUMNS = (image samples - 1) / search chip samples + 1. + + Automatic + 1 + + + + + + + + + Coregistration of 2 Images + + This example shows the coreg application. The rows and columns parameters are left as default. +
    +Sample,Line,TranslatedSample,TranslatedLine,SampleDifference,LineDifference,GoodnessOfFit
    +211.875,164.283,200,133,-11.8751,-31.2829,0.991597
    +211.766,429.437,200,398,-11.7661,-31.4369,0.995987
    +        
    + The above text file is the ffile.txt file created when coreg is ran. The flat file is comma seperated + and can easily be imported into excel. +
    + + from=./lunar1.cub match=./lunar2.cub t=out.cub flatfile=ffile.txt + + + Just run coreg on 2 images. + + + + + + First Input image for coreg + This is the 800 by 800 input image to be translated for the coreg example. + + + FROM + + + Second Input image for coreg + This is the 800 by 800 input image to be held for the coreg example. + + + MATCH + + + + + + Output image for coreg + This is the 800 by 800 output image that results. + + + TO + + + +
    +
    + + +
    diff --git a/isis/src/base/apps/coreg/tsts/Makefile b/isis/src/base/apps/coreg/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/coreg/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/coreg/tsts/cnet/Makefile b/isis/src/base/apps/coreg/tsts/cnet/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cc52e835fd383a3230c61f44258f80ad8633d1e3 --- /dev/null +++ b/isis/src/base/apps/coreg/tsts/cnet/Makefile @@ -0,0 +1,17 @@ +APPNAME = coreg + +# tail -1330 testTmp/tempcnet1.txt > tempcnet.txt 2>&1 > /dev/null; + +# This test has been set up so that the all but one points are ignored due to goodness of fit. +# Ignored points are not written to the flat file. + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/CRU_000004_1200_IR10_0.equi.cub \ + match=$(INPUT)/CRU_000004_1200_RED4_0.equi.cub \ + regdef=$(INPUT)/coregtemp.def \ + to=$(OUTPUT)/coregTruth.cub \ + cnet=$(OUTPUT)/coregTruthCnet.pvl \ + flatfile=$(OUTPUT)/coregTruthFlatFile.txt \ + interp=n > /dev/null; diff --git a/isis/src/base/apps/cosi/Makefile b/isis/src/base/apps/cosi/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cosi/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cosi/cosi.cpp b/isis/src/base/apps/cosi/cosi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..41aaad73c90ca2dd201fc047bba7a9b5c76487d9 --- /dev/null +++ b/isis/src/base/apps/cosi/cosi.cpp @@ -0,0 +1,46 @@ +#include + +#include "Isis.h" +#include "ProcessByLine.h" +#include "Camera.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +Camera *cam; +double maxinc; +void divide(Buffer &in, Buffer &out); + +void IsisMain () { + + ProcessByLine p; + Cube *icube = p.SetInputCube("FROM"); + cam = icube->Camera(); + maxinc = Application::GetUserInterface().GetDouble("MAXINC"); + p.SetOutputCube("TO"); + p.StartProcess(divide); + p.EndProcess(); +} + +void divide(Buffer &in, Buffer &out) { + for (int i=0; iSetImage(i+1,in.Line())) { + if (IsSpecial(in[i])) { + out[i] = in[i]; + } + else { + double incidence = cam->IncidenceAngle(); + if (abs(incidence) >= maxinc) { + out[i] = Isis::Null; + } + else { + out[i] = in[i] / cos(incidence*Isis::PI/180.0); + } + } + } + else { + out[i] = Isis::Null; + } + } +} diff --git a/isis/src/base/apps/cosi/cosi.xml b/isis/src/base/apps/cosi/cosi.xml new file mode 100644 index 0000000000000000000000000000000000000000..301dcde082deba330d9c55db4a95084c247afdbd --- /dev/null +++ b/isis/src/base/apps/cosi/cosi.xml @@ -0,0 +1,79 @@ + + + + + + Apply simple photometric model + + + + This program applies a basic photometric normalization to an image by dividing each pixel by the cosine of the incidence angle. It uses the camera + model to compute the incidence angle at each pixel in the cube. The corresponding input pixel value is then divided by the cosine of the incidence angle. If the + absolute value of the incidence angle is 90 or greater then a Null pixel will be output. + + + + + Original version + + + Converted to ISIS3 + + + Removed references to CubeInfo + + + + + Radiometric and Photometric Correction + + + + + + cube + input + + Input camera cube + + + An Isis cube with a supported camera model and initialized with SPICE. + + + *.cub + + + + + cube + output + + Output Isis cube + + + The name of the output Isis cube. This cube will contain the input cube divided by the cosine of the + incidence angle. + + + *.cub + + + + + + + double + 90.0 + + Maximum incidence angle + + + Pixels which have an absolute value of indicence angle at or above this value will be set to NULL in the output cube + + 90.0 + 0.0 + + + + + diff --git a/isis/src/base/apps/cosi/tsts/Makefile b/isis/src/base/apps/cosi/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cosi/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cosi/tsts/default/Makefile b/isis/src/base/apps/cosi/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..468d3046071656c8d6b8e7688e4fae931f9beb3c --- /dev/null +++ b/isis/src/base/apps/cosi/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = cosi + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/input.cub TO=$(OUTPUT)/truth.cub+Real > /dev/null; diff --git a/isis/src/base/apps/crop/Makefile b/isis/src/base/apps/crop/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/crop/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/crop/assets/image/cropgui.jpg b/isis/src/base/apps/crop/assets/image/cropgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d0ab6e5cd2b28240434e6513c420fc856d9ebc7c Binary files /dev/null and b/isis/src/base/apps/crop/assets/image/cropgui.jpg differ diff --git a/isis/src/base/apps/crop/assets/image/peaks.1.jpg b/isis/src/base/apps/crop/assets/image/peaks.1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6c268f816dae78ca33bf7bbc84977dcc85af11a0 Binary files /dev/null and b/isis/src/base/apps/crop/assets/image/peaks.1.jpg differ diff --git a/isis/src/base/apps/crop/assets/image/peaks.crop.jpg b/isis/src/base/apps/crop/assets/image/peaks.crop.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8ad03154c21c4b6422281c9d45c6b34bd60c51f3 Binary files /dev/null and b/isis/src/base/apps/crop/assets/image/peaks.crop.jpg differ diff --git a/isis/src/base/apps/crop/assets/thumb/cropgui.jpg b/isis/src/base/apps/crop/assets/thumb/cropgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8e76cc388ab0f15a0d647a8d9b5ad4873e52a606 Binary files /dev/null and b/isis/src/base/apps/crop/assets/thumb/cropgui.jpg differ diff --git a/isis/src/base/apps/crop/assets/thumb/peaks.1.jpg b/isis/src/base/apps/crop/assets/thumb/peaks.1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c7f2111661ef12bc01c2d23ce06ebdcf2edd8273 Binary files /dev/null and b/isis/src/base/apps/crop/assets/thumb/peaks.1.jpg differ diff --git a/isis/src/base/apps/crop/assets/thumb/peaks.crop.jpg b/isis/src/base/apps/crop/assets/thumb/peaks.crop.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a8e971ce49d76edc784990932d0a629eee80ec88 Binary files /dev/null and b/isis/src/base/apps/crop/assets/thumb/peaks.crop.jpg differ diff --git a/isis/src/base/apps/crop/crop.cpp b/isis/src/base/apps/crop/crop.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ddb7e6f50b1bb0aa5fb28e6919ec0e804be1f00c --- /dev/null +++ b/isis/src/base/apps/crop/crop.cpp @@ -0,0 +1,214 @@ +#include "Isis.h" +#include "Cube.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "LineManager.h" +#include "Filename.h" +#include "iException.h" +#include "Projection.h" +#include "AlphaCube.h" +#include "Table.h" +#include "SubArea.h" + +using namespace std; +using namespace Isis; + +// Globals and prototypes +int ss,sl,sb; +int ns,nl,nb; +int sinc,linc; +Cube cube; +LineManager *in = NULL; + +void crop (Buffer &out); + +void IsisMain() { + ProcessByLine p; + + // Open the input cube + UserInterface &ui = Application::GetUserInterface(); + string from = ui.GetAsString("FROM"); + CubeAttributeInput inAtt(from); + cube.SetVirtualBands(inAtt.Bands()); + from = ui.GetFilename("FROM"); + cube.Open(from); + + // Determine the sub-area to extract + ss = ui.GetInteger("SAMPLE"); + sl = ui.GetInteger("LINE"); + sb = 1; + + int origns = cube.Samples(); + int orignl = cube.Lines(); + int es = cube.Samples(); + if (ui.WasEntered("NSAMPLES")) es = ui.GetInteger("NSAMPLES") + ss - 1; + int el = cube.Lines(); + if (ui.WasEntered("NLINES")) el = ui.GetInteger("NLINES") + sl - 1; + int eb = cube.Bands(); + + sinc = ui.GetInteger("SINC"); + linc = ui.GetInteger("LINC"); + + // Make sure starting positions fall within the cube + if (ss > cube.Samples()) { + cube.Close(); + string msg = "[SAMPLE] exceeds number of samples in the [FROM] cube"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + if (sl > cube.Lines()) { + cube.Close(); + string msg = "[LINE] exceeds number of lines in the [FROM] cube"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Make sure the number of elements do not fall outside the cube + if (es > cube.Samples()) { + cube.Close(); + string msg = "[SAMPLE+NSAMPLES-1] exceeds number of "; + msg += "samples in the [FROM] cube"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + if (el > cube.Lines()) { + cube.Close(); + string msg = "[LINE+NLINES-1] exceeds number of "; + msg += "lines in the [FROM] cube"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Determine the size of the output cube and then update the image size + ns = (es - ss + 1) / sinc; + nl = (el - sl + 1) / linc; + nb = eb; + if (ns == 0) ns = 1; + if (nl == 0) nl = 1; + es = ss + (ns - 1) * sinc; + el = sl + (nl - 1) * linc; + + // Allocate the output file and make sure things get propogated nicely + p.SetInputCube("FROM"); + p.PropagateTables(false); + Cube *ocube = p.SetOutputCube ("TO",ns,nl,nb); + p.ClearInputCubes(); + + // propagate tables manually + Pvl &inLabels = *cube.Label(); + + // Loop through the labels looking for object = Table + for(int labelObj = 0; labelObj < inLabels.Objects(); labelObj++) { + PvlObject &obj = inLabels.Object(labelObj); + + if(obj.Name() != "Table") continue; + + // If we're not propagating spice data, dont propagate the following tables... + if(!ui.GetBoolean("PROPSPICE")) { + if((iString)obj["Name"][0] == "InstrumentPointing") continue; + if((iString)obj["Name"][0] == "InstrumentPosition") continue; + if((iString)obj["Name"][0] == "BodyRotation") continue; + if((iString)obj["Name"][0] == "SunPosition") continue; + } + + // Read the table into a table object + Table table(obj["Name"], from); + + // We are not going to bother with line/sample associations; they apply + // only to the alpha cube at this time. I'm leaving this code here for the + // equations in case we try our hand at modifying these tables at a later date. + + /* Deal with associations, sample first + if(table.IsSampleAssociated()) { + int numDeleted = 0; + for(int samp = 0; samp < cube.Samples(); samp++) { + // This tests checks to see if we would include this sample. + // samp - (ss-1)) / sinc must be a whole number less than ns. + if((samp - (ss-1)) % sinc != 0 || (samp - (ss-1)) / sinc >= ns || (samp - (ss-1)) < 0) { + table.Delete(samp-numDeleted); + numDeleted ++; + } + } + } + + // Deal with line association + if(table.IsLineAssociated()) { + int numDeleted = 0; + for(int line = 0; line < cube.Lines(); line++) { + // This tests checks to see if we would include this line. + // line - (sl-1)) / linc must be a whole number less than nl. + if((line - (sl-1)) % linc != 0 || (line - (sl-1)) / linc >= nl || (line - (sl-1)) < 0) { + table.Delete(line-numDeleted); + numDeleted ++; + } + } + }*/ + + // Write the table + ocube->Write(table); + } + + Pvl &outLabels = *ocube->Label(); + if(!ui.GetBoolean("PROPSPICE") && outLabels.FindObject("IsisCube").HasGroup("Kernels")) { + PvlGroup &kerns = outLabels.FindObject("IsisCube").FindGroup("Kernels"); + + string tryKey = "NaifIkCode"; + if(kerns.HasKeyword("NaifFrameCode")) { + tryKey = "NaifFrameCode"; + } + + if(kerns.HasKeyword(tryKey)) { + PvlKeyword ikCode = kerns[tryKey]; + kerns = PvlGroup("Kernels"); + kerns += ikCode; + } + } + + // Create a buffer for reading the input cube + in = new LineManager(cube); + + // Crop the input cube + p.StartProcess(crop); + + delete in; + in = NULL; + + // Construct a label with the results + PvlGroup results("Results"); + results += PvlKeyword ("InputLines", orignl); + results += PvlKeyword ("InputSamples", origns); + results += PvlKeyword ("StartingLine", sl); + results += PvlKeyword ("StartingSample", ss); + results += PvlKeyword ("EndingLine", el); + results += PvlKeyword ("EndingSample", es); + results += PvlKeyword ("LineIncrement", linc); + results += PvlKeyword ("SampleIncrement", sinc); + results += PvlKeyword ("OutputLines", nl); + results += PvlKeyword ("OutputSamples", ns); + + // Update the Mapping, Instrument, and AlphaCube groups in the output + // cube label + SubArea s; + s.SetSubArea(orignl,origns,sl,ss,el,es,linc,sinc); + s.UpdateLabel(&cube,ocube,results); + + // Cleanup + p.EndProcess(); + cube.Close(); + + // Write the results to the log + Application::Log(results); +} + +// Line processing routine +void crop (Buffer &out) { + // Read the input line + int iline = sl + (out.Line() - 1) * linc; + in->SetLine(iline,sb); + cube.Read(*in); + + // Loop and move appropriate samples + for (int i=0; i + + + + Crops a cube + + + + This program can be used to crop or select a sub-area from a cube. + The + crop parameter selection requires that the area of interest be contiguous. + That is, the program will not allow non-continuous cropping such as lines + 1-5, 10-30, and 80-100. + + The contiguous area can however be sub-sampled by specifing pixel + increments (or skips). For example every third line (1, 4, 7, 10, ...) + can be written to + the output cube using a line increment (LINC) of three. + + + + Trim and Mask + + + + + Original version + + + Converted to Isis 3.0 + + + Added examples + + + Removed crop from the Utility category + + + Make images smaller + + + Added red rectangle to input image of example to illustrate crop area. + + + Moved images to /assets/image directory and thumbnails to /assets/thumb directory. + + + Fixed problem with isiscvs not checking in the thumb and image directories. + + + Added extraction labels + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Replaced extraction group with AlphaCube group and propagated other + labels. + + + Added LINC and SINC parameters and set defaults for all parameters + + + Fixed to allow input band selection + + + Modified to adjust the upper left corner x and y values in the mapping group + of the output cube if the input cube is projected + + + Removed references to CubeInfo + + + Added spice propagation option PROPSPICE. Fixed description of NLINES, NSAMPLES + and now line associated and sample associated tables are modified when crop is run. + + + Changed default of PROPSPICE to true. Sample/Line associated tables are no longer modified + due to conflicts with other programs, such as pad, which doesn't know what data values + to add to the tables. + + + When an invalid projection exists the proper error should now be thrown. + + + Now uses the SubArea class to produce output cube labels + with corrected Mapping, Instrument, and AlphaCube groups. + + + + + dsk2dsk + sfrom + + + + + + cube + input + + Input cube + + + The cube which will be cropped. + + + *.cub + + + + + cube + output + + Output cropped cube + + + The smaller output cube containing the results of the crop. + + + *.cub + + + + + + + integer + Starting Sample + 1 + + The starting sample to extract. It must be inside + the cube. + + + 1 + + + + integer + Number of Samples + All samples + + This defines how many samples will be taken from the input cube, + if SINC is 1. The number of samples actually taken from the input + cube is NSAMPLES/SINC. + + + 1 + + + + integer + Sample increment + 1 + + A sample increment to use when extracting from the input cube. + This effectively skips samples. For example if SINC=2 and SAMPLE=1 + the output cube would contain samples 1,3,5,7, and so on. Note that + this reduces the size of the output cube as specified by NSAMPLES. + That is, if NSAMPLES=200 and SINC=2, the output cube will have 100 + samples. + + + 1 + + + + + + integer + Starting Line + 1 + + The starting line to extract. It must be inside + the cube. + + + 1 + + + + integer + Number of Lines + All lines + + This defines how many lines will be taken from the input cube, + if LINC is 1. The number of lines actually taken from the input + cube is NLINES/LINC. + + + 1 + + + + integer + Line increment + 1 + + A line increment to use when extracting from the input cube. + This effectively skips lines. For example if LINC=2 and LINE=5 + the output cube would contain lines 5,7,9,11 and so on. Note that + this reduces the size of the output cube as specified by NLINES. + That is, if NLINES=200 and LINC=2, the output cube will have 100 + lines. + + + 1 + + + + + + boolean + true + + Propagate SPICE blobs + + + The spice information for a cube is less for a cropped cube. This + prevents the propagation of the larger amount of spice blobs. + + + *.cub + + + + + + + + 200x300 sub-area + + Extracting a 200x300 sub-area + + + f=peaks.cub t=crop.cub samp=100 line=200 nsamp=200 nline=300 + + + In this example crop will extract a 200x300 sub-area that starts at sample 100 and line 200 + + + + + + Input image for crop + This is the input image for the 200x300 example of crop. The area to be "cropped" is shown in red. + + + FROM + + + + + + Output image for crop + This is the output image for the 200x300 example of crop + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a 200 pixel by 300 pixel crop of the input image. + + + + + + + diff --git a/isis/src/base/apps/crop/tsts/Makefile b/isis/src/base/apps/crop/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/crop/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/crop/tsts/skip_S1_L1/Makefile b/isis/src/base/apps/crop/tsts/skip_S1_L1/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e5d211836869054c2bd1df4b705d99906e7c0be0 --- /dev/null +++ b/isis/src/base/apps/crop/tsts/skip_S1_L1/Makefile @@ -0,0 +1,13 @@ +APPNAME = crop + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cropTruth1.cub \ + sample= 1 \ + nsamples= 10 \ + sinc=1 \ + line= 3 \ + nlines= 1 \ + linc=1 > /dev/null; diff --git a/isis/src/base/apps/crop/tsts/skip_S2_L3/Makefile b/isis/src/base/apps/crop/tsts/skip_S2_L3/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f374cba9c2b81a7859901bcb12d0de6540e16e87 --- /dev/null +++ b/isis/src/base/apps/crop/tsts/skip_S2_L3/Makefile @@ -0,0 +1,13 @@ +APPNAME = crop + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cropTruth2.cub \ + sample= 50 \ + nsamples= 50 \ + sinc=2 \ + line= 50 \ + nlines= 50 \ + linc=3 > /dev/null; diff --git a/isis/src/base/apps/crop/tsts/skip_S5_L5/Makefile b/isis/src/base/apps/crop/tsts/skip_S5_L5/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fc345f3f032c77919f7780598f43cd62c2697914 --- /dev/null +++ b/isis/src/base/apps/crop/tsts/skip_S5_L5/Makefile @@ -0,0 +1,13 @@ +APPNAME = crop + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cropTruth3.cub \ + sample= 5 \ + nsamples= 10 \ + sinc=5 \ + line= 5 \ + nlines= 10 \ + linc=5 > /dev/null; diff --git a/isis/src/base/apps/crop/tsts/tables/Makefile b/isis/src/base/apps/crop/tsts/tables/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2312d8ae7f6680dcfdff544094afa2d197c5d947 --- /dev/null +++ b/isis/src/base/apps/crop/tsts/tables/Makefile @@ -0,0 +1,16 @@ +APPNAME = crop + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) PROPSPICE=false FROM=$(INPUT)/h1235_0001_bl2.cub TO=$(OUTPUT)/h1235_0001_bl2.cub > /dev/null; + catlab FROM=$(OUTPUT)/h1235_0001_bl2.cub > $(OUTPUT)/nospice.pvl; + $(APPNAME) FROM=$(INPUT)/h1235_0001_bl2.cub TO=$(OUTPUT)/h1235_0001_bl2.cub \ + PROPSPICE=TRUE > /dev/null; + catlab FROM=$(OUTPUT)/h1235_0001_bl2.cub > $(OUTPUT)/spice.pvl; + $(RM) $(OUTPUT)/h1235_0001_bl2.cub; + $(APPNAME) FROM=$(INPUT)/PSP_001365_2720_RED4_0.cub LINE=500 NLINES=30 \ + TO=$(OUTPUT)/hirise.cub LINC=3 > /dev/null; + tabledump FROM=$(OUTPUT)/hirise.cub NAME="HiRISE Ancillary" \ + to=$(OUTPUT)/lineAssocTbl.txt > /dev/null; + $(RM) $(OUTPUT)/hirise.cub; diff --git a/isis/src/base/apps/cropspecial/Makefile b/isis/src/base/apps/cropspecial/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cropspecial/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cropspecial/assets/images/allspecial.jpg b/isis/src/base/apps/cropspecial/assets/images/allspecial.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a4b3e0fc757dedd3ed3830d7a44ead28e046c57 Binary files /dev/null and b/isis/src/base/apps/cropspecial/assets/images/allspecial.jpg differ diff --git a/isis/src/base/apps/cropspecial/assets/images/cropallgui.jpg b/isis/src/base/apps/cropspecial/assets/images/cropallgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..357e43a21261fcadf6700db74534659cad312375 Binary files /dev/null and b/isis/src/base/apps/cropspecial/assets/images/cropallgui.jpg differ diff --git a/isis/src/base/apps/cropspecial/assets/images/defaultgui.jpg b/isis/src/base/apps/cropspecial/assets/images/defaultgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6bbed53e770fd225d631587e3c254dcdf8e081a4 Binary files /dev/null and b/isis/src/base/apps/cropspecial/assets/images/defaultgui.jpg differ diff --git a/isis/src/base/apps/cropspecial/assets/images/nonulls.jpg b/isis/src/base/apps/cropspecial/assets/images/nonulls.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3323290175ef7580ddda72698e9684a8b51d2a97 Binary files /dev/null and b/isis/src/base/apps/cropspecial/assets/images/nonulls.jpg differ diff --git a/isis/src/base/apps/cropspecial/assets/images/nospecial.jpg b/isis/src/base/apps/cropspecial/assets/images/nospecial.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d5b4e593ff1505f8cbbb1c92a2dc8ef349f51ae7 Binary files /dev/null and b/isis/src/base/apps/cropspecial/assets/images/nospecial.jpg differ diff --git a/isis/src/base/apps/cropspecial/assets/thumbs/allspecial.jpg b/isis/src/base/apps/cropspecial/assets/thumbs/allspecial.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c570fbc034e71487ded0d587693dfeea1e8d78ca Binary files /dev/null and b/isis/src/base/apps/cropspecial/assets/thumbs/allspecial.jpg differ diff --git a/isis/src/base/apps/cropspecial/assets/thumbs/cropallgui.jpg b/isis/src/base/apps/cropspecial/assets/thumbs/cropallgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df1a7ef95e9a2b3bb887af1aea5945e54f612aee Binary files /dev/null and b/isis/src/base/apps/cropspecial/assets/thumbs/cropallgui.jpg differ diff --git a/isis/src/base/apps/cropspecial/assets/thumbs/defaultgui.jpg b/isis/src/base/apps/cropspecial/assets/thumbs/defaultgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a2ffb9cbffc4bc0a4631802ba00b933e6959d865 Binary files /dev/null and b/isis/src/base/apps/cropspecial/assets/thumbs/defaultgui.jpg differ diff --git a/isis/src/base/apps/cropspecial/assets/thumbs/nonulls.jpg b/isis/src/base/apps/cropspecial/assets/thumbs/nonulls.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da31ce75ba13ae1b2e11c2e89e4e6f570144598c Binary files /dev/null and b/isis/src/base/apps/cropspecial/assets/thumbs/nonulls.jpg differ diff --git a/isis/src/base/apps/cropspecial/assets/thumbs/nospecial.jpg b/isis/src/base/apps/cropspecial/assets/thumbs/nospecial.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f1dfe566ee5ab364e00a8adc660bd5e0cadf1f4 Binary files /dev/null and b/isis/src/base/apps/cropspecial/assets/thumbs/nospecial.jpg differ diff --git a/isis/src/base/apps/cropspecial/cropspecial.cpp b/isis/src/base/apps/cropspecial/cropspecial.cpp new file mode 100644 index 0000000000000000000000000000000000000000..320a185d7878e0e3e20e197a01ef52ee42cb0666 --- /dev/null +++ b/isis/src/base/apps/cropspecial/cropspecial.cpp @@ -0,0 +1,160 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "Pixel.h" +#include "LineManager.h" +#include "SpecialPixel.h" +#include "Cube.h" +#include "Table.h" +#include "Pvl.h" +#include "PvlKeyword.h" +#include "SubArea.h" + +using namespace std; +using namespace Isis; + +int minSample, maxSample, numSamples; +int minLine, maxLine, numLines; +int curBand, numBands; +bool cropNulls, cropHrs, cropLrs, cropHis, cropLis; +LineManager *in; +Cube cube; + +void FindPerimeter (Buffer &in); +void SpecialRemoval (Buffer &out); + + +void IsisMain() { + maxSample = 0; + maxLine = 0; + curBand = 1; + + // Open the input cube + UserInterface &ui = Application::GetUserInterface(); + string from = ui.GetAsString("FROM"); + CubeAttributeInput inAtt(from); + cube.SetVirtualBands(inAtt.Bands()); + from = ui.GetFilename("FROM"); + cube.Open(from); + + cropNulls = ui.GetBoolean("NULL"); + cropHrs = ui.GetBoolean("HRS"); + cropLrs = ui.GetBoolean("LRS"); + cropHis = ui.GetBoolean("HIS"); + cropLis = ui.GetBoolean("LIS"); + + minSample = cube.Samples() + 1; + minLine = cube.Lines() + 1; + numBands = cube.Bands(); + + // Setup the input cube + ProcessByLine p1; + p1.SetInputCube("FROM"); + p1.Progress()->SetText("Finding Perimeter"); + + // Start the first pass + p1.StartProcess(FindPerimeter); + p1.EndProcess(); + + if (minSample == cube.Samples() + 1) { + cube.Close(); + string msg = "There are no valid pixels in the [FROM] cube"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + numSamples = maxSample - (minSample - 1); + numLines = maxLine - (minLine - 1); + + // Setup the output cube + ProcessByLine p2; + p2.SetInputCube("FROM"); + p2.PropagateTables(false); + p2.Progress()->SetText("Removing Special Pixels"); + Cube *ocube = p2.SetOutputCube("TO", numSamples, numLines, numBands); + p2.ClearInputCubes(); + + // propagate tables manually + Pvl &inLabels = *cube.Label(); + + // Loop through the labels looking for object = Table + for(int labelObj = 0; labelObj < inLabels.Objects(); labelObj++) { + PvlObject &obj = inLabels.Object(labelObj); + + if(obj.Name() != "Table") continue; + + // Read the table into a table object + Table table(obj["Name"], from); + + ocube->Write(table); + } + + // Construct a label with the results + PvlGroup results("Results"); + results += PvlKeyword ("InputLines", cube.Lines()); + results += PvlKeyword ("InputSamples", cube.Samples()); + results += PvlKeyword ("StartingLine", minLine); + results += PvlKeyword ("StartingSample", minSample); + results += PvlKeyword ("EndingLine", maxLine); + results += PvlKeyword ("EndingSample", maxSample); + results += PvlKeyword ("OutputLines", numLines); + results += PvlKeyword ("OutputSamples", numSamples); + + // Create a buffer for reading the input cube + in = new LineManager(cube); + + // Start the second pass + p2.StartProcess(SpecialRemoval); + + // Update the Mapping, Instrument, and AlphaCube groups in the output + // cube label + SubArea s; + s.SetSubArea(cube.Lines(),cube.Samples(),minLine,minSample,minLine+numLines-1, + minSample+numSamples-1,1.0,1.0); + s.UpdateLabel(&cube,ocube,results); + + p2.EndProcess(); + cube.Close(); + + delete in; + in = NULL; + + // Write the results to the log + Application::Log(results); +} + +// Process each line to find the min and max lines and samples +void FindPerimeter (Buffer &in) { + for (int i = 0; i < in.size(); i++) { + // Do nothing until we find a valid pixel, or a pixel we do not want to crop off + if ((Pixel::IsValid(in[i])) || (Pixel::IsNull(in[i]) && !cropNulls) || + (Pixel::IsHrs(in[i]) && !cropHrs) || (Pixel::IsLrs(in[i]) && !cropLrs) || + (Pixel::IsHis(in[i]) && !cropHis) || (Pixel::IsLis(in[i]) && !cropLis)) { + // The current line has a valid pixel and is greater than max, so make it the new max line + if (in.Line() > maxLine) maxLine = in.Line(); + + // This is the first line to contain a valid pixel, so it's the min line + if (in.Line() < minLine) minLine = in.Line(); + + int cur_sample = i + 1; + + // We process by line, so the min sample is the valid pixel with the lowest index in all line arrays + if (cur_sample < minSample) minSample = cur_sample; + + // Conversely, the max sample is the valid pixel with the highest index + if (cur_sample > maxSample) maxSample = cur_sample; + } + } +} + +// Using the min and max values, create a new cube without the extra specials +void SpecialRemoval (Buffer &out) { + int iline = minLine + (out.Line() - 1); + in->SetLine(iline, curBand); + cube.Read(*in); + + // Loop and move appropriate samples + for (int i = 0; i < out.size(); i++) { + out[i] = (*in)[(minSample - 1) + i]; + } + + if (out.Line() == numLines) curBand++; +} diff --git a/isis/src/base/apps/cropspecial/cropspecial.xml b/isis/src/base/apps/cropspecial/cropspecial.xml new file mode 100644 index 0000000000000000000000000000000000000000..23052697b312ccd88e017f8b45933447cea2c744 --- /dev/null +++ b/isis/src/base/apps/cropspecial/cropspecial.xml @@ -0,0 +1,242 @@ + + + + + Crops specified special pixels from a cube + + + + This program automatically crops as many of the special pixels in a cube as + possible, without removing any valid data. The user can specify which of + the five special pixel types the program should attempt to crop and which + should be retained in the output cube. Labels are duplicated from the input + to the output cube. + + + + Trim and Mask + + + + + crop + trim + + + + + + Original version + + + Now uses the SubArea class to produce output cube labels + with corrected Mapping, Instrument, and AlphaCube groups. + + + Changed Progress to tell the user when the program is finding the + perimeter and when it is removing special pixels from the image. + + + + + + + cube + input + + Input cube + + + Input cube to be cropped. + + + *.cub + + + + + cube + output + + Output cropped cube + + + The resultant cropped cube. + + + *.cub + + + + + + + boolean + + Crop NULL pixels + + + This option will cause the program to consider NULL pixels when + cropping pixels for the output cube. + + TRUE + + + + boolean + + Crop high representation saturation (HRS) pixels + + + This option will cause the program to consider high representation + saturation (HRS) pixels when cropping pixels for the output cube. + + FALSE + + + + boolean + + Crop low representation saturation (LRS) pixels + + + This option will cause the program to consider low representation + saturation (LRS) pixels when cropping pixels for the output cube. + + FALSE + + + + boolean + + Crop high instrument saturation (HIS) pixels + + + This option will cause the program to consider high instrument + saturation (HIS) pixels when cropping pixels for the output cube. + + FALSE + + + + boolean + + Crop low instrument saturation (LIS) pixels + + + This option will cause the program to consider low instrument + saturation (LIS) pixels when cropping pixels for the output cube. + + FALSE + + + + + + + Crop NULL pixels + + Cropping the cube with default settings selected. + + + from=allspecial.cub+1 to=nonulls.cub + + + In this example, cropspecial will extract a sub-area from a cube + surrounded in special pixels with only the NULL pixel type selected. + + + + + + Input image for cropspecial + The original, 82x361 image. NULL, HRS, LRS, HIS, and + LIS pixels are shown in blue, light green, yellow, pink, and + light blue, respectively. NULL SPACE is shown here in black. + + + FROM + + + + + + Output image for cropspecial + This is the 82x315 output image that results. The NULL + pixels at the bottom have been removed, but the NULL pixels + surrounded by saturation pixels have not been removed as doing + so would result in the loss of pixels not selected for cropping. + + + TO + + + + + + + Example GUI + Screenshot of GUI with the default parameter settings, +ready to perform a crop on the NULL pixels contained within the first band of +the input cube. + + + + + + + + + Crop all special pixels + + Cropping the cube with all special pixels selected. + + + from=allspecial.cub+1 to=nospecial.cub hrs=yes lrs=yes + his=yes lis=yes + + + In this example, cropspecial will extract a sub-area from a cube + surrounded in special pixels with all pixel types selected. + + + + + + Input image for cropspecial + The original, 82x361 image. NULL, HRS, LRS, HIS, and + LIS pixels are shown in blue, light green, yellow, pink, and + light blue, respectively. NULL SPACE is shown here in black. + + + FROM + + + + + + Output image for cropspecial + This is the 22x173 output image that results. Some HRS, + HIS, and NULL pixels are still present due to the rectangular + dimensions of the cube, but their occurence has been minimized. + + + TO + + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform +a crop on all special pixels contained within the first band of the input cube. + + + + + + + + + diff --git a/isis/src/base/apps/cropspecial/tsts/4band/Makefile b/isis/src/base/apps/cropspecial/tsts/4band/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c648a1902fd14126fe8d5e987a66140cd91983da --- /dev/null +++ b/isis/src/base/apps/cropspecial/tsts/4band/Makefile @@ -0,0 +1,8 @@ +APPNAME = cropspecial + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/4band.cub+1-4 to=$(OUTPUT)/4crop.cub \ + HRS=yes LRS=yes HIS=yes LIS=yes \ + > /dev/null; diff --git a/isis/src/base/apps/cropspecial/tsts/Makefile b/isis/src/base/apps/cropspecial/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cropspecial/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cropspecial/tsts/all_special/Makefile b/isis/src/base/apps/cropspecial/tsts/all_special/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..44875fe76e09058900e76c5885f4de7a599c297b --- /dev/null +++ b/isis/src/base/apps/cropspecial/tsts/all_special/Makefile @@ -0,0 +1,9 @@ +APPNAME = cropspecial + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/allspecial.cub+1 to=$(OUTPUT)/nospecial.cub \ + HRS=yes LRS=yes HIS=yes LIS=yes \ + > /dev/null; + diff --git a/isis/src/base/apps/cropspecial/tsts/default/Makefile b/isis/src/base/apps/cropspecial/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d1dee205a626654e59ee749ac362cabb2cd2f7fe --- /dev/null +++ b/isis/src/base/apps/cropspecial/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = cropspecial + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/small01.cub+1 to=$(OUTPUT)/test.cub \ + > /dev/null; diff --git a/isis/src/base/apps/cropspecial/tsts/error/Makefile b/isis/src/base/apps/cropspecial/tsts/error/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..34698b9e100b25fd027cfc817c0c0e46ab1a83bd --- /dev/null +++ b/isis/src/base/apps/cropspecial/tsts/error/Makefile @@ -0,0 +1,11 @@ +APPNAME = cropspecial + +include $(ISISROOT)/make/isismake.tsts + +commands: + if [ `$(APPNAME) from=$(INPUT)/allnull.cub to=$(OUTPUT)/fail.cub \ + -preference=$(ISISROOT)/src/base/objs/Preference/TestPreferences \ + >& $(OUTPUT)/error.txt` ]; \ + then \ + true; \ + fi; diff --git a/isis/src/base/apps/cropspecial/tsts/keep_nulls/Makefile b/isis/src/base/apps/cropspecial/tsts/keep_nulls/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1dfb26654e6ed59680c3fd495bc2b1b0008a3f8c --- /dev/null +++ b/isis/src/base/apps/cropspecial/tsts/keep_nulls/Makefile @@ -0,0 +1,8 @@ +APPNAME = cropspecial + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/allspecial.cub+1 to=$(OUTPUT)/keptnulls.cub \ + NULL=no HRS=yes LRS=yes HIS=yes LIS=yes \ + > /dev/null; diff --git a/isis/src/base/apps/cropspecial/tsts/no_changes/Makefile b/isis/src/base/apps/cropspecial/tsts/no_changes/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5d0597f26052db9a8c1bb1204e53c4b0f33a139a --- /dev/null +++ b/isis/src/base/apps/cropspecial/tsts/no_changes/Makefile @@ -0,0 +1,7 @@ +APPNAME = cropspecial + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/original.cub to=$(OUTPUT)/test02.cub \ + > /dev/null; diff --git a/isis/src/base/apps/cropspecial/tsts/one_pixel/Makefile b/isis/src/base/apps/cropspecial/tsts/one_pixel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..98adbac5ab41b277e338cca8acb8228f2a479795 --- /dev/null +++ b/isis/src/base/apps/cropspecial/tsts/one_pixel/Makefile @@ -0,0 +1,7 @@ +APPNAME = cropspecial + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/onepixel.cub to=$(OUTPUT)/success.cub \ + > /dev/null; diff --git a/isis/src/base/apps/cubeatt/Makefile b/isis/src/base/apps/cubeatt/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cubeatt/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cubeatt/assets/image/cubeattGui1.jpg b/isis/src/base/apps/cubeatt/assets/image/cubeattGui1.jpg new file mode 100755 index 0000000000000000000000000000000000000000..1d5dd2ce6eb1759409c1b0f71afb18e8011ee87d Binary files /dev/null and b/isis/src/base/apps/cubeatt/assets/image/cubeattGui1.jpg differ diff --git a/isis/src/base/apps/cubeatt/assets/image/cubeattGui2.jpg b/isis/src/base/apps/cubeatt/assets/image/cubeattGui2.jpg new file mode 100755 index 0000000000000000000000000000000000000000..7b79539b31952175dab01cdb2b76492ac7583dce Binary files /dev/null and b/isis/src/base/apps/cubeatt/assets/image/cubeattGui2.jpg differ diff --git a/isis/src/base/apps/cubeatt/assets/image/cubeattGui3.jpg b/isis/src/base/apps/cubeatt/assets/image/cubeattGui3.jpg new file mode 100755 index 0000000000000000000000000000000000000000..856e4612236455f9956a83279fd87eb24c14c22d Binary files /dev/null and b/isis/src/base/apps/cubeatt/assets/image/cubeattGui3.jpg differ diff --git a/isis/src/base/apps/cubeatt/assets/image/peaks.jpg b/isis/src/base/apps/cubeatt/assets/image/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..ef1a24efc0554596f440e9e349fa223994594094 Binary files /dev/null and b/isis/src/base/apps/cubeatt/assets/image/peaks.jpg differ diff --git a/isis/src/base/apps/cubeatt/assets/image/peaks_scaled.jpg b/isis/src/base/apps/cubeatt/assets/image/peaks_scaled.jpg new file mode 100755 index 0000000000000000000000000000000000000000..5aaa5e76025737d04c26e3142f464e65cd46ab33 Binary files /dev/null and b/isis/src/base/apps/cubeatt/assets/image/peaks_scaled.jpg differ diff --git a/isis/src/base/apps/cubeatt/assets/thumb/cubeattGui1.jpg b/isis/src/base/apps/cubeatt/assets/thumb/cubeattGui1.jpg new file mode 100755 index 0000000000000000000000000000000000000000..b93cc8d5237856d278a69efa089577e5a9399802 Binary files /dev/null and b/isis/src/base/apps/cubeatt/assets/thumb/cubeattGui1.jpg differ diff --git a/isis/src/base/apps/cubeatt/assets/thumb/cubeattGui2.jpg b/isis/src/base/apps/cubeatt/assets/thumb/cubeattGui2.jpg new file mode 100755 index 0000000000000000000000000000000000000000..4c3264edcc70cdae425a6e9be34badc3b13699a4 Binary files /dev/null and b/isis/src/base/apps/cubeatt/assets/thumb/cubeattGui2.jpg differ diff --git a/isis/src/base/apps/cubeatt/assets/thumb/cubeattGui3.jpg b/isis/src/base/apps/cubeatt/assets/thumb/cubeattGui3.jpg new file mode 100755 index 0000000000000000000000000000000000000000..35005c6b08a2f66c91e5a2fff31d2ef1a8fafe13 Binary files /dev/null and b/isis/src/base/apps/cubeatt/assets/thumb/cubeattGui3.jpg differ diff --git a/isis/src/base/apps/cubeatt/assets/thumb/peaks.jpg b/isis/src/base/apps/cubeatt/assets/thumb/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..d2d9cfe5f9049bb36047091aba8740119f7cca35 Binary files /dev/null and b/isis/src/base/apps/cubeatt/assets/thumb/peaks.jpg differ diff --git a/isis/src/base/apps/cubeatt/assets/thumb/peaks_scaled.jpg b/isis/src/base/apps/cubeatt/assets/thumb/peaks_scaled.jpg new file mode 100755 index 0000000000000000000000000000000000000000..5ff85a0a84761a759536147686f91f4f3db1f702 Binary files /dev/null and b/isis/src/base/apps/cubeatt/assets/thumb/peaks_scaled.jpg differ diff --git a/isis/src/base/apps/cubeatt/cubeatt.cpp b/isis/src/base/apps/cubeatt/cubeatt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39916ae38d2ba02fa8d65f9da11748577871ec16 --- /dev/null +++ b/isis/src/base/apps/cubeatt/cubeatt.cpp @@ -0,0 +1,33 @@ +#include "Isis.h" +#include "ProcessByLine.h" + +using namespace std; +using namespace Isis; + +void cubeatt (Buffer &in, Buffer &out); + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Should we propagate tables + if (!Application::GetUserInterface().GetBoolean("PROPTABLES")) { + p.PropagateTables(false); + } + + // Setup the input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube ("TO" ); + + p.StartProcess(cubeatt); + p.EndProcess(); +} + +// Line processing routine +void cubeatt (Buffer &in, Buffer &out) +{ + // Loop and copy pixels in the line. + for (int i=0; i + + + + Cube attribute editor + + + + Copies the input cube to the output cube using the specified attributes. + + + + Utility + + + + + Original version + + + Added examples + + + Added ability to optionally not propagate tables + + + + + + + cube + input + + Input file + + + The input cube. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube with attribute modifications. + + + *.cub + + + + + + + boolean + true + + Propagate tables + + + This option allows the user to select if tables will be propagated to the output cube + + + + + + + + cubeatt example + + Example of the cubeatt program. + + + from=peaks.cub+1 to=peaks_band1.cub + + Copy the first band of peaks.cub into peaks_band1.cub. + + + + + Input image + This is the input image, peaks.cub. + + + FROM + + + + + Example output + + This is the output image which consists of just the first band of peaks. + Notice, it is impossible to tell them apart. + + + TO + + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform this example + + + + + + + + cubeatt example + + Example of the cubeatt program. + + + from=peaks.cub to=peaks_8bit.cub+8bit+0.0:255.0 + + Copy an 8bit version of peaks.cub into peaks_8bit.cub. + + + + + Input image + This is the input image, peaks.cub. + + + FROM + + + + + Example output + + This is the output image which is an 8-bit version of the original which is 32-bits. + Again, it is impossible to tell them apart. + + + TO + + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform this example + + + + + + + + cubeatt example + + Example of the cubeatt program. + + + from=peaks.cub+1 to=peaks_8bit.cub+8bit+75.0:125.0 + + Copy an 8bit version of the first band in peaks.cub into peaks_cropped.cub that has a output range from 75 to 125. + + + + + Input image + This is the input image, peaks.cub. + + + FROM + + + + + Example output + + This is the output image which is an 8-bit version of the first band of the original which is 32-bits. + The range of the output image has been limited to values between 75 and 125. + + + TO + + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform this example + + + + + + + diff --git a/isis/src/base/apps/cubeatt/tsts/Makefile b/isis/src/base/apps/cubeatt/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cubeatt/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cubeatt/tsts/change/Makefile b/isis/src/base/apps/cubeatt/tsts/change/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..07c1f43c437bcff7d0147c112a6644a62a3be4d0 --- /dev/null +++ b/isis/src/base/apps/cubeatt/tsts/change/Makefile @@ -0,0 +1,7 @@ +APPNAME = cubeatt + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cubeattTruth2.cub+8bit+0.0:1.0 > /dev/null; diff --git a/isis/src/base/apps/cubeatt/tsts/noChange/Makefile b/isis/src/base/apps/cubeatt/tsts/noChange/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a82d15622a156c2cc6ffac27af2777924053423b --- /dev/null +++ b/isis/src/base/apps/cubeatt/tsts/noChange/Makefile @@ -0,0 +1,7 @@ +APPNAME = cubeatt + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/cubeattTruth1.cub > /dev/null; diff --git a/isis/src/base/apps/cubeavg/Makefile b/isis/src/base/apps/cubeavg/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cubeavg/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cubeavg/cubeavg.cpp b/isis/src/base/apps/cubeavg/cubeavg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a4fbc7c01a8c152dcd86458f7e75403f599c4e9 --- /dev/null +++ b/isis/src/base/apps/cubeavg/cubeavg.cpp @@ -0,0 +1,160 @@ +#include "Isis.h" +#include "ProcessBySpectra.h" +#include "Statistics.h" +#include "Application.h" +#include "PvlGroup.h" +#include "PvlSequence.h" + +using namespace std; +using namespace Isis; + +void cubeavg (vector &in, + vector &out); + +void removekeywords ( PvlGroup & pvlg ); + +void compute (vector centers, + vector widths, + Cube *ocube ); + +void IsisMain() { + ProcessBySpectra p; + p.SetType( ProcessBySpectra::PerPixel ); + Cube *icube = p.SetInputCube("FROM"); + Cube *ocube = p.SetOutputCube("TO", icube->Samples(), icube->Lines(), 1); + + //Get user parameters and sets outputcube's BandBin + UserInterface &ui = Application::GetUserInterface(); + if(ui.GetString("BANDBIN") == "COMPUTE") { + if( icube->HasGroup("BandBin") ) { + PvlGroup &pvlg = icube->GetGroup("BandBin"); + removekeywords( pvlg ); + if(pvlg.HasKeyword("Center")) { + bool hasWidth = pvlg.HasKeyword("Width"); + PvlKeyword &pvlCenter = pvlg.FindKeyword("Center"); + PvlKeyword * pvlWidth = NULL; + if(hasWidth) { + pvlWidth = & pvlg.FindKeyword("Width"); + } + std::vector centers; + centers.resize(icube->Bands()); + std::vector widths; + widths.resize(icube->Bands()); + for( int i=0; iHasGroup("BandBin")) { + pvlg = PvlGroup("BandBin"); + icube->PutGroup(pvlg); + } + else { + pvlg = ocube->GetGroup("BandBin"); + removekeywords(pvlg); + } + string Units = ""; + PvlKeyword pvlCenter; + if(pvlg.HasKeyword("Center")) { + pvlCenter = pvlg.FindKeyword("Center"); + Units = pvlCenter.Unit(); + pvlg.DeleteKeyword("Center"); + } + + pvlCenter = PvlKeyword("Center"); + pvlCenter.SetValue(ui.GetAsString("CENTER"), Units); + pvlg.AddKeyword(pvlCenter); + PvlKeyword pvlWidth; + if( pvlg.HasKeyword("Width") ) { + pvlWidth = pvlg.FindKeyword("Width"); + Units = pvlWidth.Unit(); + pvlg.DeleteKeyword("Width"); + } + + pvlWidth = PvlKeyword("Width"); + pvlWidth.SetValue(ui.GetAsString("WIDTH"), Units); + pvlg.AddKeyword(pvlWidth); + //Destroys the old and adds the new BandBin Group + if( ocube->HasGroup("BandBin") ) { + ocube->DeleteGroup("BandBin"); + } + ocube->PutGroup(pvlg); + } + + else if(ui.GetString("BANDBIN") == "DELETE") { + if(ocube->HasGroup("BandBin")) { + ocube->DeleteGroup("BandBin"); + } + } + + p.StartProcess(cubeavg); + p.EndProcess(); +} + +// Band processing routine +void cubeavg ( vector &in, vector &out ) { + Statistics sts; + sts.AddData( (*in[0]).DoubleBuffer() , (*in[0]).size() ); + (*out[0]) = sts.Average(); +} + +/** + * Removes the PvlKeywords that can't be processed + * + * @param pvlg the group from which the keywords are removed + */ +void removekeywords ( PvlGroup & pvlg ) { + if( pvlg.HasKeyword("OriginalBand") ) { + pvlg.DeleteKeyword("OriginalBand"); + } + if( pvlg.HasKeyword("Name") ) { + pvlg.DeleteKeyword("Name"); + } +} + +//BandBin Computeing +void compute( vector centers, vector widths, + Cube *ocube ) { + PvlGroup &pvlg = ocube->GetGroup("BandBin"); + PvlKeyword &pvlCenter = pvlg.FindKeyword("Center"); + string centerUnit = pvlCenter.Unit(); + bool hasWidth = pvlg.HasKeyword("Width"); + double large = centers[0] + widths[0]/2; + double small = centers[0] - widths[0]/2; + for( int i=1; i (double)centers[i] - (double)widths[i]/2.0 ) { + small = (double)centers[i] - (double)widths[i]/2.0; + } + } + pvlCenter.SetValue( iString( (large-small)/2 + small ), centerUnit ); + if( hasWidth ) { + PvlKeyword &pvlWidth = pvlg.FindKeyword("Width"); + pvlWidth.SetValue( large-small, pvlWidth.Unit() ); + } + else { + PvlKeyword pvlWidth = PvlKeyword("Width"); + pvlWidth.SetValue( large-small, centerUnit ); + pvlg.AddKeyword(pvlWidth); + } + +} diff --git a/isis/src/base/apps/cubeavg/cubeavg.xml b/isis/src/base/apps/cubeavg/cubeavg.xml new file mode 100644 index 0000000000000000000000000000000000000000..f782021e58816a6515a53e847ded33972d2dafbb --- /dev/null +++ b/isis/src/base/apps/cubeavg/cubeavg.xml @@ -0,0 +1,131 @@ + + + + + Averages all bands from the input cube + + + Averages every pixel with it's corresponding pixels throughout each given + band, resulting in a spectral average cube. Cube attributes must be used to + specify specific bands from the original cube. + + + + Math and Statistics + + + + + Original version + + + Fix output cube to only having one band. + + + Removed references to CubeInfo + + + + + + + cube + input + + Input Cube + + + The input cube. All pixels in this cube will be averaged by + corresponding pixels in the output cube. + + + *.cub + + + + + cube + real + output + + Output cube + + + The output spectral average cube. + + + *.cub + + + + + + + string + DELETE + How to handle the BandBin Group in the ouput cube + + When creating a single band spectral average cube from a multiband + cube, the BandBin Group must be altered in some manner to represent + the new single band cube. The keywords which are always removed from + the output cube include "OriginalBand" and "Name". + + + + + + + + + double + The new Center value of the output cube's BandBin + + Sets the output cube's BandBin Center to the specified value. + + + + double + The new Width value of the output cube's BandBin + + Sets the output cube's BandBin Width to the specified value. + + + + + + + + diff --git a/isis/src/base/apps/cubeavg/tsts/Makefile b/isis/src/base/apps/cubeavg/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cubeavg/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cubeavg/tsts/default/Makefile b/isis/src/base/apps/cubeavg/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b225d5d81fdadb850dccbb990f0a3618bee8a199 --- /dev/null +++ b/isis/src/base/apps/cubeavg/tsts/default/Makefile @@ -0,0 +1,17 @@ +APPNAME = cubeavg + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/isis3vis.cub \ + TO=$(OUTPUT)/delete.cub \ + > /dev/null; + $(APPNAME) FROM=$(INPUT)/isis3vis.cub \ + TO=$(OUTPUT)/compute.cub \ + BANDBIN=compute \ + > /dev/null; + $(APPNAME) FROM=$(INPUT)/isis3vis.cub \ + TO=$(OUTPUT)/user.cub \ + BANDBIN=user \ + CENTER=7.0 WIDTH=0.01 \ + > /dev/null; diff --git a/isis/src/base/apps/cubeavg/tsts/includeWidths/Makefile b/isis/src/base/apps/cubeavg/tsts/includeWidths/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b843d8b8a9270f7f60d9ce7e697a80c933e51a37 --- /dev/null +++ b/isis/src/base/apps/cubeavg/tsts/includeWidths/Makefile @@ -0,0 +1,17 @@ +APPNAME = cubeavg + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/hirdrgen_color_test.cub \ + TO=$(OUTPUT)/delete.cub \ + > /dev/null; + $(APPNAME) FROM=$(INPUT)/hirdrgen_color_test.cub \ + TO=$(OUTPUT)/compute.cub \ + BANDBIN=compute \ + > /dev/null; + $(APPNAME) FROM=$(INPUT)/hirdrgen_color_test.cub \ + TO=$(OUTPUT)/user.cub \ + BANDBIN=user \ + CENTER=650 WIDTH=150 \ + > /dev/null; diff --git a/isis/src/base/apps/cubediff/Column.cpp b/isis/src/base/apps/cubediff/Column.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd56b10891d8b5bb2e4d6bcfc8f5187a2f9b4bc9 --- /dev/null +++ b/isis/src/base/apps/cubediff/Column.cpp @@ -0,0 +1,152 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2007/08/09 18:24:24 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "Column.h" +#include "iException.h" + +namespace Isis{ + + /** + * Constructor. Sets the precision for decimal-aligned columns to 4 + */ + Column::Column(){ + p_precision = 4; + p_width = 0; + p_name = ""; + SetAlignment(Column::NoAlign); + SetType(Column::NoType); + } + + /** + * Constructor with parameter + * + * @param name The name of the column, used as the header + * @param width The width (in characters) to make the column + * @param type The type of information the column is to represent + * @param align The alignment, within the column, the data is to conform to + */ + Column::Column( std::string name, int width, Column::Type type, Column::Align align) { + //Set the parameters with function calls, to make use of pre-existing error checks + SetWidth(width); + SetName(name); + SetType(type); + SetAlignment(align); + + p_precision = 4; + } + + /** + * Sets the Column name, or header + * + * @param name The name of the Column + */ + void Column::SetName (std::string name) { + if (p_width != 0 && name.length() > p_width) { + std::string message = "Name[" + name + "] is wider than width"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + p_name = name; + } + + /** + * Sets the width of the Column, in text columns + * + * @param width The number of text columns the Column will hold + */ + void Column::SetWidth (unsigned int width) { + if (p_name.size() > 0 && p_name.size() > width) { + std::string message = "Width is insufficient to contain name["; + message += p_name + "]"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + p_width = width; + } + + /** + * Sets the data type of the Column + * + * @param type The data type for the Column + */ + void Column::SetType (Column::Type type) { + if (p_align == Column::Decimal && + (type == Column::Integer || type == Column::String)) { + std::string message = "Integer or string type is not sensible if "; + message += "alignment is Decimal."; + throw iException::Message(iException::User,message,_FILEINFO_); + } + p_type = type; + } + + /** + * Sets the alignment of the Column + * + * The text in the Column will be aligned according to this parameter, + * which is Right, Left, or, possible only with real-number values, + * aligned by the decimal point + * + * @param alignment The alignment of the text in the Column + */ + void Column::SetAlignment (Column::Align alignment) { + if (alignment == Column::Decimal && + (p_type == Column::Integer || p_type == Column::String)) { + std::string message = "Decimal alignment does not make sense for "; + message += "integer or string values."; + throw iException::Message(iException::Programmer,message,_FILEINFO_); + } + p_align = alignment; + } + + /** + * Sets the precision of the Column, for real number values + * + * This sets the number of digits after the decimal point, for decimal aligned + * values. If the Column's alignment is anything else, an error is thrown. + * + * @param precision The number of digits after the decimal point to be shown + */ + void Column::SetPrecision(unsigned int precision) { + if (DataType() != Column::Real && + DataType() != Column::Pixel) { + std::string message = "Setting precision only makes sense for Decimal Alignment"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + p_precision = precision; + } + + /** + * Returns the type of data this column will contain + * + * @return Column::Type The data type of this column + */ + Column::Type Column::DataType() { + + if (p_type == 0) { + std::string message = "Type has not been set yet!"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + + return p_type; + } +} diff --git a/isis/src/base/apps/cubediff/Column.h b/isis/src/base/apps/cubediff/Column.h new file mode 100644 index 0000000000000000000000000000000000000000..35f5c87c0d7d7594ca99f60d18abe3ec7fbd23c0 --- /dev/null +++ b/isis/src/base/apps/cubediff/Column.h @@ -0,0 +1,78 @@ +#if !defined(Column_h) +#define Column_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2007/08/09 18:24:24 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +namespace Isis { + /** + * @brief Format ascii tables + * + * This class takes in a series of string vectors and writes them out to a + * file as a table. Formatting options are up to the user. + * + * @ingroup Utility + * + * @author 2007-05-01 Brendan George + * + * @internal + * @history 2007-06-18 Brendan George Fixed error message outputs and + * unitTest + */ + class Column { + public: + + enum Align { NoAlign = 0, + Right = 1, + Left = 2, + Decimal = 3 }; + enum Type { NoType = 0, + Integer = 1, + Real = 2, + String = 3, + Pixel = 4 }; + Column (); + Column (std::string name, int width, Column::Type type, Align align=Column::Right); + void SetName (std::string name); + void SetWidth (unsigned int width); + void SetType (Column::Type type); + void SetAlignment (Column::Align alignment); + void SetPrecision (unsigned int precision); + + std::string Name () {return p_name;}; + unsigned int Width (){return p_width;}; + Column::Type DataType (); + Column::Align Alignment (){return p_align;}; + unsigned int Precision (){return p_precision;}; + + private: + std::string p_name; + unsigned int p_width; + Column::Type p_type; + Column::Align p_align; + unsigned int p_precision; + }; +}; + +#endif diff --git a/isis/src/base/apps/cubediff/Makefile b/isis/src/base/apps/cubediff/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cubediff/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cubediff/WriteTabular.cpp b/isis/src/base/apps/cubediff/WriteTabular.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a272024364e5a00b17dc39fdadbddf22dcd1832 --- /dev/null +++ b/isis/src/base/apps/cubediff/WriteTabular.cpp @@ -0,0 +1,348 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2007/08/09 18:24:24 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include + +#include "WriteTabular.h" +#include "iString.h" +#include "Message.h" +#include "iException.h" +#include "SpecialPixel.h" + +namespace Isis { + + /** + * Constructor + * @param filename The name of the file where the table will be written + */ + WriteTabular::WriteTabular( std::ostream &strm ) : p_outfile (strm) { + p_rows = 0; + p_delimiter = ","; + p_curCol = 0; + } + + /** + * Constructor + * @param filename The name of the target file to contain the table, once + * formatted + * @param cols The Column headers, containing information about the Columns + */ + WriteTabular::WriteTabular( std::ostream &strm, std::vector cols) : p_outfile(strm) { + p_rows = 0; + p_delimiter = ","; + p_curCol = 0; + SetColumns (cols); + } + + /** + * Sets the vector of Columns and writes out the first row of the file. + * + * @param cols A vector of Columns, setting the format of the table + */ + void WriteTabular::SetColumns(std::vector cols ){ + for (unsigned int index=0; index < cols.size(); index++) { + Column thisCol = cols[index]; + std::string thisTitle = thisCol.Name(); + + if (thisTitle.length() > thisCol.Width()) { + std::string message = "Column header [" + thisTitle + "] is wider " + + "than the set width for column [" + iString((int)index) + "]"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + + int iteration = 0; + while (thisTitle.length() < thisCol.Width()) { + if (thisCol.Alignment() == Column::Left) { + thisTitle += " "; + } + else if (thisCol.Alignment() == Column::Right || + thisCol.Alignment() == Column::Decimal) { + thisTitle = " " + thisTitle; + } + else { + std::string message = "Alignment is improperly set"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + iteration++; + }//end while + + p_cols.push_back(thisCol); + p_outfile << thisTitle; + if (index < (cols.size()-1)) { + p_outfile << p_delimiter; + } + }//end for + p_outfile << "\n"; + }//end function + + /** + * Writes a blank space in the next column in the current row + */ + void WriteTabular::Write() { + Column thisCol = p_cols[p_curCol]; + + std::string item = ""; + + std::stringstream tempStream; + tempStream.width(thisCol.Width()); + tempStream.fill(' '); + tempStream << item; + item = tempStream.str(); + + if (p_curCol == 0) { + p_rows++; + } + + if (p_curCol < (p_cols.size()-1)) { + item += p_delimiter; + p_curCol++; + } + else { + item += "\n"; + p_curCol = 0; + } + p_outfile << item; + } + + /** + * Add an integer value to the next column in this row + * + * @param item The integer value to put in this column. + */ + void WriteTabular::Write(int item){ + Column thisCol = p_cols[p_curCol]; + if (thisCol.DataType() != Column::Integer && + thisCol.DataType() != Column::Pixel) { + if (thisCol.DataType() == Column::Real || + thisCol.DataType() == Column::Pixel) { + Write((double)item); + return; + } + std::string message = "Wrong data type for this Column"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + iString thisItem(item); + if (thisItem.length() > thisCol.Width()) { + thisItem = "*"; + while (thisItem.length() < thisCol.Width()) { + thisItem += "*"; + } + } + std::stringstream tempStream; + tempStream.width(thisCol.Width()); + tempStream.fill(' '); + + if (thisCol.Alignment() == Column::Left) { + tempStream.setf(std::ios::left); + } + else tempStream.setf(std::ios::right); + + tempStream << thisItem; + thisItem = tempStream.str(); + + if (p_curCol == 0) { + p_rows++; + } + + if (p_curCol < (p_cols.size()-1)) { + thisItem += p_delimiter; + p_curCol++; + } + else { + thisItem += "\n"; + p_curCol = 0; + } + p_outfile << thisItem.c_str(); + } + + /** + * Writes a string to the next column in the current row + * + * @param item The string to write out + */ + void WriteTabular::Write(std::string item){ + Column thisCol = p_cols[p_curCol]; + if (thisCol.DataType() != Column::String && + thisCol.DataType() != Column::Pixel) { + std::string message = "Wrong data type for this Column"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + if (item.length() > thisCol.Width()) { + item = "*"; + while (item.length() < thisCol.Width()) { + item += "*"; + } + } + std::stringstream tempStream; + tempStream.width(thisCol.Width()); + tempStream.fill(' '); + + if (thisCol.Alignment() == Column::Left) { + tempStream.setf(std::ios::left); + } + else tempStream.setf(std::ios::right); + + tempStream << item; + item = tempStream.str(); + + if (p_curCol == 0) { + p_rows++; + } + + if (p_curCol < (p_cols.size()-1)) { + item += p_delimiter; + p_curCol++; + } + else { + item += "\n"; + p_curCol = 0; + } + p_outfile << item; + } + + /** + * Writes a floating-point value out to the next column in the current row + * + * @param item The value to be printed out + */ + void WriteTabular::Write(double item){ + Column thisCol = p_cols[p_curCol]; + if (thisCol.DataType() != Column::Real && + thisCol.DataType() != Column::Pixel) { + std::string message = "Wrong data type for this Column"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + + //Check for special pixels, if it's a pixel column + if (thisCol.DataType() == Column::Pixel && IsSpecial(item)) { + if (IsNullPixel(item)) { + Write("Null"); + return; + } + if (IsHisPixel(item)) { + Write("His"); + return; + } + if (IsHrsPixel(item)) { + Write("Hrs"); + return; + } + if (IsLisPixel(item)) { + Write("Lis"); + return; + } + if (IsLrsPixel(item)) { + Write("Lrs"); + return; + } + } + + iString thisItem(item); + + + if (thisCol.Alignment() == Column::Decimal) { + + //Format and round the number + + //First, split the number at the decimal point + iString tempString = thisItem; + iString intPart = tempString.Token("."); + //Make the fractional portion appear as such, so the iomanipulators + //handle it properly + if (tempString != "") { + tempString = "0." + tempString; + } + else tempString = "0.0"; + + //Put the fractional portion into a stringstream, and use + //stream manipulators to round it properly + std::stringstream b; + b << std::showpoint + << std::setprecision(thisCol.Precision()) + << tempString.ToDouble(); + + //if the rounding causes a rollover (i.e. the decimal portion is greater + //than 0.95) increment the integer portion + if (iString(b.str()).ToDouble() >= 1) { + intPart = iString(intPart.ToInteger() + 1); + } + + //Put it back into an iString, for easier manipulation + tempString = b.str(); + tempString.Token("."); + //Add any zeros necessary to pad the number + while (tempString.size() < thisCol.Precision()) { + tempString += "0"; + } + + //Put the number back together, adding the decimal point in the right location + thisItem = intPart + "." + tempString; + } + std::stringstream tempStream; + tempStream.width(thisCol.Width()); + tempStream.fill(' '); + + if (thisCol.Alignment() == Column::Left) { + tempStream.setf(std::ios::left); + } + else tempStream.setf(std::ios::right); + + tempStream << thisItem; + thisItem = tempStream.str(); + + if (p_curCol == 0) { + p_rows++; + } + + //If the number is too wide for the column, replace with a string of stars + if (thisItem.length() > thisCol.Width()) { + thisItem = "*"; + while (thisItem.length() < thisCol.Width()) { + thisItem += "*"; + } + } + + if (p_curCol < (p_cols.size()-1)) { + thisItem += p_delimiter; + p_curCol++; + } + else { + thisItem += "\n"; + p_curCol = 0; + } + p_outfile << thisItem; + + } + + /** + * Sets the string to be put between columns for this table + * + * @param delim The string to separate columns + */ + void WriteTabular::SetDelimiter( std::string delim ) { + p_delimiter = delim; + } + +} diff --git a/isis/src/base/apps/cubediff/WriteTabular.h b/isis/src/base/apps/cubediff/WriteTabular.h new file mode 100644 index 0000000000000000000000000000000000000000..c5d435cdb4fca354db4601881cae3bb1d5ba1182 --- /dev/null +++ b/isis/src/base/apps/cubediff/WriteTabular.h @@ -0,0 +1,65 @@ +#if !defined(NewClass_h) +#define NewClass_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2007/08/09 18:24:24 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#include "Column.h" + +namespace Isis { + /** + * @brief Format ascii tables + * + * This class takes in a series of string vectors and writes them out to a + * file as a table. Formatting options are up to the user. + * + * @ingroup Utility + * + * @author 2007-05-01 Brendan George + */ + class WriteTabular { + public: + // Constructor and Destructor + WriteTabular(std::ostream &strm, std::vector cols ); + WriteTabular(std::ostream &strm ); + + void SetColumns( std::vector cols ); + void Write(); + void Write (int item); + void Write (std::string item); + void Write (double item); + void SetDelimiter(std::string delim); + + int Columns() {return p_cols.size();}; + int Rows() {return p_rows;}; + + private: + std::string p_delimiter; + std::ostream &p_outfile; + unsigned int p_rows; + std::vector p_cols; + unsigned int p_curCol; + + }; +} +#endif diff --git a/isis/src/base/apps/cubediff/assets/images/compareGui.jpg b/isis/src/base/apps/cubediff/assets/images/compareGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fc0ff1ee2aa20c4b866b6bad85ead3a55a77b23e Binary files /dev/null and b/isis/src/base/apps/cubediff/assets/images/compareGui.jpg differ diff --git a/isis/src/base/apps/cubediff/assets/images/compareLog.jpg b/isis/src/base/apps/cubediff/assets/images/compareLog.jpg new file mode 100644 index 0000000000000000000000000000000000000000..acb2bcac649efda8f612a2e6e4fe443eec67ebf6 Binary files /dev/null and b/isis/src/base/apps/cubediff/assets/images/compareLog.jpg differ diff --git a/isis/src/base/apps/cubediff/assets/images/isistruth1.jpg b/isis/src/base/apps/cubediff/assets/images/isistruth1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dbfa567f722d4623addaa61d7d6a07b8bbce60e0 Binary files /dev/null and b/isis/src/base/apps/cubediff/assets/images/isistruth1.jpg differ diff --git a/isis/src/base/apps/cubediff/assets/images/isistruth2.jpg b/isis/src/base/apps/cubediff/assets/images/isistruth2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5c02d3ccd20b655ae57ddabb29246ab1e7693bc4 Binary files /dev/null and b/isis/src/base/apps/cubediff/assets/images/isistruth2.jpg differ diff --git a/isis/src/base/apps/cubediff/assets/thumbs/compareGui.jpg b/isis/src/base/apps/cubediff/assets/thumbs/compareGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..828f053cded21f302664af5b33ddcacdccdcd151 Binary files /dev/null and b/isis/src/base/apps/cubediff/assets/thumbs/compareGui.jpg differ diff --git a/isis/src/base/apps/cubediff/assets/thumbs/compareLog.jpg b/isis/src/base/apps/cubediff/assets/thumbs/compareLog.jpg new file mode 100644 index 0000000000000000000000000000000000000000..230a644aafd1533db1c640f9a0adc3c93b1a7c0b Binary files /dev/null and b/isis/src/base/apps/cubediff/assets/thumbs/compareLog.jpg differ diff --git a/isis/src/base/apps/cubediff/assets/thumbs/isistruth1.jpg b/isis/src/base/apps/cubediff/assets/thumbs/isistruth1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..26873295fd5823a26ecd6b0339c6fced6e8d0963 Binary files /dev/null and b/isis/src/base/apps/cubediff/assets/thumbs/isistruth1.jpg differ diff --git a/isis/src/base/apps/cubediff/assets/thumbs/isistruth2.jpg b/isis/src/base/apps/cubediff/assets/thumbs/isistruth2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..856f99645bfc02919291c12723389d44b7a29621 Binary files /dev/null and b/isis/src/base/apps/cubediff/assets/thumbs/isistruth2.jpg differ diff --git a/isis/src/base/apps/cubediff/cubediff.cpp b/isis/src/base/apps/cubediff/cubediff.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a6dc21a3ef31329581f9d54bf7aa71b3c6d17b18 --- /dev/null +++ b/isis/src/base/apps/cubediff/cubediff.cpp @@ -0,0 +1,312 @@ +#include "Isis.h" + +#include +#include +#include +#include + +#include "ProcessByLine.h" + +#include "Statistics.h" +#include "Pvl.h" +#include "iException.h" +#include "WriteTabular.h" +#include "iString.h" +#include "Pixel.h" + +using namespace std; +using namespace Isis; + +void compare (vector &in, vector &out); + +void diffTable (ofstream &target, int precision); + +// This is only used for the difference table +struct Difference { + int lineNum; + int sampNum; + double cube1Val; + double cube2Val; +}; + +double tolerance; +bool filesEqual = true; +bool firstDifferenceFound = false; // Set to true when first DN value difference is found +int sample,line,band,spCount,diffCount,colWidth; +Statistics stats; +bool doTable; +unsigned int sigFigAccuracy = DBL_DIG; // DBL_DIG is maximum accuracy for a double +vector diffset; +int sigFigLine = 0; +int sigFigSample = 0; +int sigFigBand = 0; + +int gMaxDiffLine=0, gMaxDiffSample=0, gMaxDiffBand=0; +double gMaxDiff; + +void IsisMain() { + // Set up the two input cubes + ProcessByLine p; + p.SetInputCube("FROM"); + p.SetInputCube("FROM2", SizeMatch); + + // Read tolerance value + UserInterface &ui = Application::GetUserInterface(); + if (ui.WasEntered ("TOLERANCE")) { + tolerance = ui.GetDouble("TOLERANCE"); + } + else { + tolerance = DBL_EPSILON; + } + + // See if we should output the difference table + if (ui.GetBoolean("OUTPUTDIFFS")){ + doTable = true; + diffCount = ui.GetInteger("COUNT"); + if (!ui.WasEntered("TO")) { + string message = "A target file is required for difference output"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + + } + + // Compare the cubes + filesEqual = true; + spCount = 0; + stats.Reset(); + colWidth = 0; + gMaxDiff=tolerance; + p.StartProcess(compare); + + // Write to log indicating if two files are filesEqual. + PvlGroup results("Results"); + if (filesEqual) { + results += PvlKeyword ("Compare","Identical"); + } + else { + results += PvlKeyword ("Compare","Different"); + results += PvlKeyword ("Sample",sample); + results += PvlKeyword ("Line",line); + results += PvlKeyword ("Band",band); + if(stats.TotalPixels() < 1) { + results += PvlKeyword ("AverageDifference",0); + results += PvlKeyword ("StandardDeviation",0); + results += PvlKeyword ("Variance",0); + results += PvlKeyword ("MinimumDifference",0); + results += PvlKeyword ("MaximumDifference",0); + } else { + results += PvlKeyword ("AverageDifference",(double)stats.Average()); + results += PvlKeyword ("StandardDeviation",(double)stats.StandardDeviation()); + results += PvlKeyword ("Variance",(double)stats.Variance()); + results += PvlKeyword ("MinimumDifference",(double)stats.Minimum()); + results += PvlKeyword ("MaximumDifference",(double)stats.Maximum()); + results += PvlKeyword ("MaxDifferenceSample",(int)gMaxDiffSample); + results += PvlKeyword ("MaxDifferenceLine",(int)gMaxDiffLine); + results += PvlKeyword ("MaxDifferenceBand",(int)gMaxDiffBand); + } + results += PvlKeyword ("ValidPixelDifferences",stats.TotalPixels()); + results += PvlKeyword ("SpecialPixelDifferences",spCount); + results += PvlKeyword ("SigFigAccuracy", (int)sigFigAccuracy); + results += PvlKeyword ("SigFigMaxDifferenceSample", (int)sigFigSample); + results += PvlKeyword ("SigFigMaxDifferenceLine", (int)sigFigLine); + results += PvlKeyword ("SigFigMaxDifferenceBand", (int)sigFigBand); + } + Application::Log(results); + + // Output a file if the user request it + if (ui.WasEntered ("TO")) { + Pvl lab; + lab.AddGroup(results); + lab.Write (ui.GetFilename("TO","txt")); + } + if (doTable) { + string filename = Filename(ui.GetFilename("TO","txt")).Expanded(); + ofstream ofile(filename.c_str(),ios_base::app); + diffTable(ofile, ui.GetInteger("PRECISION")); + } + + p.EndProcess(); + filesEqual = true; +} + +void compare (vector &in,vector &out) { + Buffer &input1 = *in[0]; + Buffer &input2 = *in[1]; + int inputSize = input1.size(); + double MaxDiffTemp; + + for (int index = 0; index < inputSize; index ++) { + bool pixelDifferent = false; + bool pixelSpecial = false; + + // First check if there is a special pixel in either cube + if(Pixel::IsSpecial(input1[index]) || Pixel::IsSpecial(input2[index])) { + pixelSpecial = true; + + // We have special pixels, if they are both special compare them. + if(Pixel::IsSpecial(input1[index]) && Pixel::IsSpecial(input2[index])) { + if(input1[index] != input2[index]) { + spCount ++; + pixelDifferent = true; + } + } + // At least one is special, but not both, so they must be different + else { + spCount ++; + pixelDifferent = true; + } + } + // We don't have any special pixels, run against tolerance + else { + MaxDiffTemp = abs(input1[index] - input2[index]); + if(MaxDiffTemp > tolerance) { + // This pixel is different. + pixelDifferent = true; + + // Add the difference in dn to the stats object + stats.AddData(MaxDiffTemp); + + // Store line, sample and band of max difference + if (MaxDiffTemp > gMaxDiff) { + gMaxDiff = MaxDiffTemp; + gMaxDiffLine = input1.Line(index); + gMaxDiffSample = input1.Sample(index); + gMaxDiffBand = input1.Band(index); + } + } + } + + // If pixels different & neither are special, calculate the significant figure difference + if(pixelDifferent && !pixelSpecial) { + unsigned int accuracy = 0; + + // Check positive/negative and ensure both positive + if((input1[index] < 0 && input2[index] > 0) || + (input1[index] > 0 && input2[index] < 0)) { + accuracy = 1; + } + else { + double in1 = abs(input1[index]); + double in2 = abs(input2[index]); + int in1log = (int)floor(log10(in1)); + int in2log = (int)floor(log10(in2)); + + // Check for zeros + if(input1[index] == 0 || input2[index] == 0) { + accuracy = 0; + } + // Check for different decimal places + else if(in1log != in2log) { + accuracy = 0; + } + else { + // int values of log of original - log of difference = # sig fig accuracy + // *The difference can not equal zero because pixelDifferent flag is set to true + accuracy = in1log - (int)floor(log10(abs(in1 - in2))); + } + } + + if(accuracy < sigFigAccuracy) { + sigFigSample = input1.Sample(index); + sigFigLine = input1.Line(index); + sigFigBand = input1.Band(index); + sigFigAccuracy = accuracy; + } + } + + if(pixelDifferent) { + filesEqual = false; + + if (!firstDifferenceFound) { + firstDifferenceFound = true; + sample = input1.Sample(index); + line = input1.Line(index); + band = input1.Band(index); + } + } + + // If the user indicated that we should make the table, add this entry + if (pixelDifferent && doTable) { + if ((int)diffset.size() < diffCount) { + Difference currDiff; + currDiff.lineNum = input1.Line(index); + currDiff.sampNum = input1.Sample(index); + currDiff.cube1Val = input1[index]; + currDiff.cube2Val = input2[index]; + diffset.push_back(currDiff); + + // Check the character lengths of the values + int val1Length = iString((int)currDiff.cube1Val).length(); + int val2Length = iString((int)currDiff.cube2Val).length(); + if (val1Length < colWidth) { + colWidth = val1Length; + } + if (val2Length < colWidth) { + colWidth = val2Length; + } + } + } + } +} + +//Function to prepare the table to append to the +void diffTable(ofstream &target, int precision) { + vector temp; + + //Make a list of all samples present + for (unsigned int i=0; i samps; + samps.push_back(temp[0]); + for (unsigned int i=1; i cols; + //Add the first Column + Column first("Line#", 7, Column::Integer); + cols.push_back(first); + + for (unsigned int i=0; i + + + Compare two cubes for differences + + + + This program compares two cube files pixel by pixel, with results written + to the log and/or user specified output file. + + + + Utility + System + + + + + Original version + + + Add user parameter, IGNORESPECIAL, which indicates whether special + pixel values in either file are ignored in the comparison. + + + Add example. + + + Make images smaller + + + Added the band number to the logged information + + + Fixed multipal run bug where once the inputs were reported as different + any files entered after that would aldo be reported as different. + + + Modified schema location from astogeology... to isis.astrogeology... + + + Modified filename parameters to be cube parameters where necessary + + + Changed default extension handling mechanism + + + Modified results pvl to not include the results group + + + Changed the IGNORESPECIAL from a string to a bool. + + + Modified to output statistical data about the differences + + + Added ValidPixelDifferences to output + + + Documentation fixes + + + Documentation correction-Description said program + exited at first difference. This is no longer the case, + all pixels are compared and statistics are collected. + + + Added tabular output option. Option allows the program to + collect and print out a table of the differences found + + + Changed name from compare to cubediff + + + Fixed problems with the special pixel comparisons: + changed IGNORESPECIAL to only ignore the case where one pixel has a DN value and the other pixel is special, + fixed a problem where the special pixel difference would never be the first difference, + fixed a comparison of DN value differences before checking if the pixel is special. + Added significant figure reports for testing purposes. + + + Removed IGNORESPECIAL + + + Updated example images + + + Fixed bug where sig. fig. accuracy would report "1" when it should report "0" + + + Integrated WriteTabular and Column (tabular output objects) as + application-specific classes + + + Changed output, if no valid pixel differences, output zero instead of + NULL8 + + + Incuded keywords MaxDifference Line, Sample and Band in the output to + indicate the line, sample, band where the max cube difference occured + + + + + + + cube + input + + First cube for comparison + + + The file specification for the first input cube. This cube will + be compared to the cube given in "FROM2". + + + *.cub + + + + cube + input + + Second cube for comparison + + + The file specification for the second input cube. This cube will + be compared to the cube given in "FROM". + + + *.cub + + + + filename + output + Text file + None + + A text file in label format which will contain the results of + this compare. This file can be used in conjunction with the + "getkey" program to pass the results to another program. + + + + + + + double + Tolerance value + + DBL_EPSILON + + + This parameter allows a tolerance when comparing values. If the + difference between pixel values is less than or equal to + TOLERANCE,the values are considered to be equal. The default + value, DBL_EPSILON, is machine specific, but a possible value + is 2.2204460492503131e-16. It is defined in float.h. + + + + + + + boolean + Output table of differences + This determines if the differences will be output to a + table. If it is checked, the options below will be opened up and + used to determine the specifics of the table to which the data will + be written. The differences are written out as a table, where the + columns represent the sample number, once for each image, and the + rows represent the line number, with the data being the DN at that + point. + + false + + PRECISION + COUNT + + + + integer + The decimal precision of the output values + + This number determines how many digits past the decimal point + will be displayed for the compared values in the output table. + + 3 + + OUTPUTDIFFS + + + + integer + Number of differences to be displayed + + This indicates the number of differences to be displayed. The + count is made from left to right, top to bottom. Differences on + the top row are considered first, then the second row, and so + on. + + 100 + + OUTPUTDIFFS + + + + + + + + + Different + + Compare isisTruth.cub band one against band two + + + cubediff from=isisTruth.cub+1 from2=isisTruth.cub+2 + + Compare isisTruth.cub band one against band two + + + + + + First input image for compare + This is the first input image for the compare example. + + + FROM + + + + Second input image for compare + This is the second input image for the compare example. + + + FROM2 + + + + + + The output log + This is the default output compare log. Use the TO parameter for a text file output. + + + + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform the compare operation + + + + + + + + + diff --git a/isis/src/base/apps/cubediff/tsts/Makefile b/isis/src/base/apps/cubediff/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cubediff/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cubediff/tsts/default/Makefile b/isis/src/base/apps/cubediff/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bb0b1c335c8711564cdd7a59d5503ba002c4ea46 --- /dev/null +++ b/isis/src/base/apps/cubediff/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = cubediff + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + from2=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/cubediffTruth1.txt > /dev/null; diff --git a/isis/src/base/apps/cubediff/tsts/sigFigAccuracy/Makefile b/isis/src/base/apps/cubediff/tsts/sigFigAccuracy/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b18cccb7701c1ef448d5d9d6f00580fe92360743 --- /dev/null +++ b/isis/src/base/apps/cubediff/tsts/sigFigAccuracy/Makefile @@ -0,0 +1,9 @@ +APPNAME = cubediff + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/in1.cub \ + from2=$(INPUT)/in2.cub \ + to = $(OUTPUT)/truth.txt \ + > /dev/null; diff --git a/isis/src/base/apps/cubediff/tsts/tolSpecial/Makefile b/isis/src/base/apps/cubediff/tsts/tolSpecial/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..48e474a4833fe5b2bfc4b7567cfbd97154e62c57 --- /dev/null +++ b/isis/src/base/apps/cubediff/tsts/tolSpecial/Makefile @@ -0,0 +1,9 @@ +APPNAME = cubediff + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + from2=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/cubediffTruth2.txt \ + tolerance=1 > /dev/null; diff --git a/isis/src/base/apps/cubediff/tsts/withTable/Makefile b/isis/src/base/apps/cubediff/tsts/withTable/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3c8e5ed6f30190392a36c6f2ee11f89231444dcc --- /dev/null +++ b/isis/src/base/apps/cubediff/tsts/withTable/Makefile @@ -0,0 +1,10 @@ +APPNAME = cubediff + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/cubediffTest1.cub \ + from2=$(INPUT)/cubediffTest2.cub \ + to=$(OUTPUT)/cubediffTruth3.txt \ + outputdiffs=true \ + count=20 > /dev/null; diff --git a/isis/src/base/apps/cubefunc/Makefile b/isis/src/base/apps/cubefunc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cubefunc/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cubefunc/assets/image/9700r.jpg b/isis/src/base/apps/cubefunc/assets/image/9700r.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68a7d23d3bf19d80bc4fb947dbaf9f07ce0e9b26 Binary files /dev/null and b/isis/src/base/apps/cubefunc/assets/image/9700r.jpg differ diff --git a/isis/src/base/apps/cubefunc/assets/image/IoCubefunc.jpg b/isis/src/base/apps/cubefunc/assets/image/IoCubefunc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0c4ec177c22242a8acc94f2a889e6cb83ad34d64 Binary files /dev/null and b/isis/src/base/apps/cubefunc/assets/image/IoCubefunc.jpg differ diff --git a/isis/src/base/apps/cubefunc/assets/image/IoCubefuncGui.jpg b/isis/src/base/apps/cubefunc/assets/image/IoCubefuncGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b3ebd747534a76fa0c795507deee030f62df4869 Binary files /dev/null and b/isis/src/base/apps/cubefunc/assets/image/IoCubefuncGui.jpg differ diff --git a/isis/src/base/apps/cubefunc/assets/thumb/9700r.jpg b/isis/src/base/apps/cubefunc/assets/thumb/9700r.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3f847cebb8c3affd2c562c9b665a338c9d5cdbc7 Binary files /dev/null and b/isis/src/base/apps/cubefunc/assets/thumb/9700r.jpg differ diff --git a/isis/src/base/apps/cubefunc/assets/thumb/IoCubefunc.jpg b/isis/src/base/apps/cubefunc/assets/thumb/IoCubefunc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..901f04d88c69f92ffb56cfd91256311b3c0b182e Binary files /dev/null and b/isis/src/base/apps/cubefunc/assets/thumb/IoCubefunc.jpg differ diff --git a/isis/src/base/apps/cubefunc/assets/thumb/IoCubefuncGui.jpg b/isis/src/base/apps/cubefunc/assets/thumb/IoCubefuncGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3b149ef802297754d748c8783db491ee57c659cd Binary files /dev/null and b/isis/src/base/apps/cubefunc/assets/thumb/IoCubefuncGui.jpg differ diff --git a/isis/src/base/apps/cubefunc/cubefunc.cpp b/isis/src/base/apps/cubefunc/cubefunc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6e47a45db4ff0fdbbd5c580c2df714442b1ed1eb --- /dev/null +++ b/isis/src/base/apps/cubefunc/cubefunc.cpp @@ -0,0 +1,199 @@ +#include +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void cubefunc (Buffer &in, + Buffer &out); + +double bad=0; +double y; + +enum function { + COS, + SIN, + TAN, + ACOS, + ASIN, + ATAN, + INV, + SQRT, + POW10, + EXP, + XTOY, + LOG10, + LN, + ABS +} Function; + + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + + UserInterface &ui = Application::GetUserInterface(); + + // Which function is it to be? + string func = ui.GetString ("FUNCTION"); + if (func == "COS") Function = COS; + if (func == "SIN") Function = SIN; + if (func == "TAN") Function = TAN; + if (func == "ACOS") Function = ACOS; + if (func == "ASIN") Function = ASIN; + if (func == "ATAN") Function = ATAN; + if (func == "INV") Function = INV; + if (func == "SQRT") Function = SQRT; + if (func == "POW10") Function = POW10; + if (func == "EXP") Function = EXP; + if (func == "XTOY") Function = XTOY; + if (func == "LOG10") Function = LOG10; + if (func == "LN") Function = LN; + if (func == "ABS") Function = ABS; + + if (Function == XTOY) { + if (ui.WasEntered ("Y")) { + y = ui.GetDouble("Y"); + } + else { + string message = "For the XTOY function, you must enter a value for y"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + } + + // Start the processing + p.StartProcess(cubefunc); + + if (bad != 0) { + PvlGroup results ("Results"); + string message = "Invalid input pixels converted to Isis NULL values"; + results += PvlKeyword ("Error", message); + results += PvlKeyword ("Count",bad); + Application::Log (results); + } + p.EndProcess(); +} + +// Line processing routine +void cubefunc (Buffer &in, + Buffer &out) +{ + + // Loop for each pixel in the line. + for (int i=0; i (2*PI)) { + out[i] = NULL8; + bad++; + } + out[i] = cos (in[i]); + break; + case SIN: + if (in[i] < (-(2*PI)) || in[i] > (2*PI)) { + out[i] = NULL8; + bad++; + } + out[i] = sin (in[i]); + break; + case TAN: + // Check for invalid input values. Check within a certain + // tolerance since the radiance value will probably never be + // exactly 90, 270, -90 or -270 degrees due to round off. + // First convert input value from radians to degrees. + deg = in[i] * (180./PI); + if ( abs(abs(in[i]) - 90.0) <= .0001 || + abs(abs(in[i]) - 270.0) <= .0001) { + out[i] = NULL8; + bad++; + } + else { + out[i] = tan (in[i]); + } + break; + case ACOS: + if (in[i] < -1.0 || in[i] > 1.0) { + out[i] = NULL8; + bad++; + } + else { + out[i] = acos (in[i]); + } + break; + case ASIN: + if (in[i] < -1.0 || in[i] > 1.0) { + out[i] = NULL8; + bad++; + } + else { + out[i] = asin (in[i]); + } + break; + case ATAN: + out[i] = atan (in[i]); + break; + case INV: + if (in[i] == 0) { + out[i] = NULL8; + bad++; + } + else { + out[i] = 1 / in[i]; + } + break; + case SQRT: + if (in[i] <= 0) { + out[i] = NULL8; + bad++; + } + else { + out[i] = sqrt (in[i]); + } + break; + case POW10: + out[i] = pow (10,in[i]); + break; + case EXP: + out[i] = exp (in[i]); + break; + case XTOY: + out[i] = pow (in[i],y); + break; + case LOG10: + if (in[i] <= 0) { + out[i] = NULL8; + bad++; + } + else { + out[i] = log10 (in[i]); + } + break; + case LN: + if (in[i] <= 0) { + out[i] = NULL8; + bad++; + } + else { + out[i] = log (in[i]); + } + break; + case ABS: + out[i] = abs (in[i]); + break; + } + } + } +} diff --git a/isis/src/base/apps/cubefunc/cubefunc.xml b/isis/src/base/apps/cubefunc/cubefunc.xml new file mode 100644 index 0000000000000000000000000000000000000000..1cc124d482cc4ba5e75d11a8175e6370d6462075 --- /dev/null +++ b/isis/src/base/apps/cubefunc/cubefunc.xml @@ -0,0 +1,309 @@ + + + + + + This program will apply a chosen function to the input cube + + + + This program will apply the chosen function to the input cube. + The following functions with their corresponding restrictions are available: + NOTE: Trig functions requiring angles as the input must be in radians. +
    +    	FUNCTION       RESTRICTIONS
    +	cos (x)
    +	sin (x)
    +	tan (x)        x cannot equal: 90, 270, -90, -270,
    +                                       pi/2, 3pi/2, -pi/2, -3pi/2
    +	arccos(x)      -1.0 < x < 1.0
    +	arcsin(x)      -1.0 < x < 1.0
    +	arctan(x)
    +	1.0 / x        x cannot equal 0.
    +	sqrt (x)       x must be greater than or equal to 0.
    +	10 ^ x
    +	e ^ x
    +	x ^ y          x is the input cube, y is an input constant
    +	log (x)        x > 0
    +	ln (x)         x > 0
    +	abs(x)
    +
    +
    + + + + Original version + + + If input pixel is a special pixel, output the input value instead + of the NULL value. + + + Add example. + + + Removed from Utility category. + + + Make images smaller. Move "constants" group below "functions" group. + + + Added to liens: + 1. Add degree and radian radio buttons. + 2. Move constants group below functions goup. + + + Fixed problem with isiscvs not checking in the thumb and image directories. + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Add error checking for cos/sin function. Print number invalid input pixels. + + + Documentation fixes + + + Fixed appTest + + + Fixed output to contain valid pvl + + + + + Add degree and radian radio buttons. + Move constants group below functions goup. + + + + Math and Statistics + + + + + algebra + poly + + + + + + + cube + input + + Input file (X value) + + + Cube that is used as input to chosen function (x value). + NOTE: For trig functions requiring angles, input must be in radians. + + + *.cub + + + + + cube + real + output + + Output file + + + Cube containing the result of the function. + + + *.cub + + + + + + + string + Function to apply to input cube + COS + + This indicates the function to apply to the input cube. + + + + + + + + + + + + + + + + + + + + + + + + double + y value for XTOY function + + y value which is only used when FUNCTION=XTOY. + + + + + + + + + X to Y + + This example shows the use of the "x to y" function. + + + fr=../IN/9700r.cub t=OUT/cubefunc fu=xtoy y=3 + + + You have to use "fr" for the FROM parameter because the parameter FUNCTION starts with an "f", also. + + + + + + Input image for cubefunc + This is the input image for the cubefunc example. + + + FROM + + + + + + Output image for cubefunc + This is the "X to Y" output image that results. + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform +a cubefunc operation on the input image. + + + + + + + +
    diff --git a/isis/src/base/apps/cubefunc/tsts/Makefile b/isis/src/base/apps/cubefunc/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cubefunc/tsts/abs/Makefile b/isis/src/base/apps/cubefunc/tsts/abs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..22850256c0abcb39509ebcb5f64fcfd23e9517b5 --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/abs/Makefile @@ -0,0 +1,8 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cubefuncTruth14.cub \ + function=abs > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/acos/Makefile b/isis/src/base/apps/cubefunc/tsts/acos/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..11daffe877d5eeb0d0b5fdb09c44d041e5e335b3 --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/acos/Makefile @@ -0,0 +1,8 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cubefuncTruth4.cub \ + function=acos > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/asin/Makefile b/isis/src/base/apps/cubefunc/tsts/asin/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cd505ff0d59022c04fd718de292c76a2cf85ac0b --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/asin/Makefile @@ -0,0 +1,8 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cubefuncTruth5.cub \ + function=asin > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/atan/Makefile b/isis/src/base/apps/cubefunc/tsts/atan/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5907fcadf67c1cad241ee7ea98c20b9d2cfade77 --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/atan/Makefile @@ -0,0 +1,8 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cubefuncTruth6.cub \ + function=atan > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/cos/Makefile b/isis/src/base/apps/cubefunc/tsts/cos/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6623ce06ea899a1e7ea966cd7e8f1ac0fb713c7b --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/cos/Makefile @@ -0,0 +1,16 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + crop from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/tempCrop.cub \ + sample=1 \ + nsamples=13 \ + sinc=1 \ + nlines=13 \ + line=1 \ + linc=1 > /dev/null; + $(APPNAME) from=$(OUTPUT)/tempCrop.cub \ + to=$(OUTPUT)/cubefuncTruth1.cub \ + function=cos > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/exp/Makefile b/isis/src/base/apps/cubefunc/tsts/exp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fbf3122d0464e38f546ecff20e0f421d4528c8cc --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/exp/Makefile @@ -0,0 +1,8 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cubefuncTruth10.cub \ + function=exp > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/inv/Makefile b/isis/src/base/apps/cubefunc/tsts/inv/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1f329070c4b77126c58def54e5e7dc1b2b7a4cd2 --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/inv/Makefile @@ -0,0 +1,8 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cubefuncTruth7.cub \ + function=inv > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/ln/Makefile b/isis/src/base/apps/cubefunc/tsts/ln/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bad83b0e454e69a6abf446c4e32ca1dd20f1b823 --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/ln/Makefile @@ -0,0 +1,8 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cubefuncTruth13.cub \ + function=ln > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/log10/Makefile b/isis/src/base/apps/cubefunc/tsts/log10/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e9828e0dcb6a1a6c18594e4fd6850a79b94e9142 --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/log10/Makefile @@ -0,0 +1,8 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cubefuncTruth12.cub \ + function=log10 > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/pow10/Makefile b/isis/src/base/apps/cubefunc/tsts/pow10/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..00251457437688a967fd9e6b3d3ee0c84b22a51a --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/pow10/Makefile @@ -0,0 +1,8 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cubefuncTruth9.cub \ + function=pow10 > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/sin/Makefile b/isis/src/base/apps/cubefunc/tsts/sin/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9f882c82b70e93d1cc659cbad0b3642ce4267241 --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/sin/Makefile @@ -0,0 +1,16 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + crop from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/tempCrop.cub \ + sample=1 \ + nsamples=13 \ + sinc=1 \ + nlines=13 \ + line=1 \ + linc=1 > /dev/null; + $(APPNAME) from=$(OUTPUT)/tempCrop.cub \ + to=$(OUTPUT)/cubefuncTruth2.cub \ + function=sin > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/sqrt/Makefile b/isis/src/base/apps/cubefunc/tsts/sqrt/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ba435cf299eb7e1d90c1b645c61ab128895b443d --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/sqrt/Makefile @@ -0,0 +1,8 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cubefuncTruth8.cub \ + function=sqrt > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/tan/Makefile b/isis/src/base/apps/cubefunc/tsts/tan/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e0b51be819137fcec961877b09348920c51bc3ed --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/tan/Makefile @@ -0,0 +1,16 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + crop from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/tempCrop.cub \ + sample=1 \ + nsamples=13 \ + sinc=1 \ + nlines=13 \ + line=1 \ + linc=1 > /dev/null; + $(APPNAME) from=$(OUTPUT)/tempCrop.cub \ + to=$(OUTPUT)/cubefuncTruth3.cub \ + function=tan > /dev/null; diff --git a/isis/src/base/apps/cubefunc/tsts/xtoy/Makefile b/isis/src/base/apps/cubefunc/tsts/xtoy/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..aa40869fb1d16a46d4e06ee360de8446796f1aa0 --- /dev/null +++ b/isis/src/base/apps/cubefunc/tsts/xtoy/Makefile @@ -0,0 +1,9 @@ +APPNAME = cubefunc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/cubefuncTruth11.cub \ + function=xtoy \ + y=123.45> /dev/null; diff --git a/isis/src/base/apps/cubeit/Makefile b/isis/src/base/apps/cubeit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cubeit/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cubeit/cubeit.cpp b/isis/src/base/apps/cubeit/cubeit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..862765c06d2a4093158d38d8ff8a4297aef2c1e7 --- /dev/null +++ b/isis/src/base/apps/cubeit/cubeit.cpp @@ -0,0 +1,155 @@ +#define GUIHELPERS + +#include "Isis.h" +#include "ProcessByLine.h" +#include "ProcessMosaic.h" +#include "iException.h" +#include "FileList.h" +#include "TextFile.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void NullBand (Buffer &out); + +//helper button function in the code +void helperButtonLog(); + +map GuiHelpers(){ + map helper; + helper ["helperButtonLog"] = (void*) helperButtonLog; + return helper; +} + +void IsisMain() { + // Get the list of cubes to stack + Process p; + UserInterface &ui = Application::GetUserInterface(); + FileList cubeList(ui.GetFilename("LIST")); + + // Loop through the list + int nsamps(0), nlines(0), nbands(0); + PvlGroup outBandBin("BandBin"); + try { + for (unsigned int i=0; i bands = inatt.Bands(); + cube.SetVirtualBands(bands); + cube.Open(cubeList[i]); + if (i == 0) { + nsamps = cube.Samples(); + nlines = cube.Lines(); + nbands = cube.Bands(); + } + else { + // Make sure they are all the same size + if ((nsamps != cube.Samples()) || (nlines != cube.Lines())) { + string msg = "Spatial dimensions of cube [" + + cubeList[i] + "] does not match other cubes in list"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + // Get the total number of bands + nbands += cube.Bands(); + } + + // Build up the band bin group + PvlObject &isiscube = cube.Label()->FindObject("IsisCube"); + if (isiscube.HasGroup("BandBin")) { + PvlGroup &inBandBin = isiscube.FindGroup("BandBin"); + for (int key=0; keySetText("Allocating cube"); + p2.StartProcess(NullBand); + + // Add the band bin group if necessary + if (outBandBin.Keywords() > 0) { + ocube->PutGroup(outBandBin); + } + p2.EndProcess(); + + // Now loop and mosaic in each cube + int sband = 1; + for (unsigned int i=0; iSetText("Adding band " + iString((int)i+1) + + " of " + iString(nbands)); + m.SetOutputCube("TO"); + CubeAttributeInput attrib(cubeList[i]); + Cube *icube = m.SetInputCube(cubeList[i],attrib); + m.StartProcess(1,1,sband,input); + sband += icube->Bands(); + m.EndProcess(); + } +} + +// Line processing routine +void NullBand (Buffer &out) { + for (int i=0; i + + + + Stacks cubes in individual files into one cube + + + + This program will stack a series of cubes into a single cube. It + requires a file containing a list of cubes to stack and the order + of the file is used to generate the stacking order. Each cube + must have the same spatial dimensions (e.g., samples and lines). + The BandBin group will be constructed. + + + + Utility + + + + + explode + + + + + + Original version + + + Changed List parameter to have filename type, and added support + for Attributes on tthe cubes in the file list. + + + Modified to allow the user to pick which cube labels are propagated (using the + PROPLAB keyword), rather than just using the first input cube (this is still + the default). And added a helper button + + + Modified so that the cube list does not need to contain the full directory path for PROPLAB option + + + Removed references to CubeInfo + + + + + + + filename + input + + A text file containing a list of cubes + + + Each file in this list, one per line, will be added to + the output cube in the order they appear. + + + *.lis + + + + helperButtonLog + View file in log area + This helper button will display the input file in the log area + $ISIS3DATA/base/icons/view_text.png + + + + + + cube + output + + Output cube name + + + The name of cube containing the stacked data. + + + + + + + cube + + Input cube to propagate labels from + + + The input cube to propagate the labels from. By default, it will propagate the labels + from the first input cube in the list. + + First Cube in List + + + + diff --git a/isis/src/base/apps/cubeit/tsts/Makefile b/isis/src/base/apps/cubeit/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cubeit/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cubeit/tsts/default/Makefile b/isis/src/base/apps/cubeit/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cff017abf0f87a61b6963870aa473836aaf83777 --- /dev/null +++ b/isis/src/base/apps/cubeit/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = cubeit + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) list=$(INPUT)/inputList.lis \ + to=$(OUTPUT)/cubeitTruth1.cub > /dev/null; diff --git a/isis/src/base/apps/cubenorm/Makefile b/isis/src/base/apps/cubenorm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/cubenorm/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/cubenorm/assets/image/after.jpg b/isis/src/base/apps/cubenorm/assets/image/after.jpg new file mode 100644 index 0000000000000000000000000000000000000000..74c744175f12cb0beccd316ed805d1ef2bb519c7 Binary files /dev/null and b/isis/src/base/apps/cubenorm/assets/image/after.jpg differ diff --git a/isis/src/base/apps/cubenorm/assets/image/before.jpg b/isis/src/base/apps/cubenorm/assets/image/before.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c361ce160e6d201f7e581286ef9064adb8efda2e Binary files /dev/null and b/isis/src/base/apps/cubenorm/assets/image/before.jpg differ diff --git a/isis/src/base/apps/cubenorm/assets/image/colnorm.jpg b/isis/src/base/apps/cubenorm/assets/image/colnorm.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4c839b143020d61d52ff70ebc38cab556bb69114 Binary files /dev/null and b/isis/src/base/apps/cubenorm/assets/image/colnorm.jpg differ diff --git a/isis/src/base/apps/cubenorm/assets/image/cubenorm.jpg b/isis/src/base/apps/cubenorm/assets/image/cubenorm.jpg new file mode 100755 index 0000000000000000000000000000000000000000..0b0c94c82cec612e037e66afbeb0478eead8950b Binary files /dev/null and b/isis/src/base/apps/cubenorm/assets/image/cubenorm.jpg differ diff --git a/isis/src/base/apps/cubenorm/assets/thumb/thumb_after.jpg b/isis/src/base/apps/cubenorm/assets/thumb/thumb_after.jpg new file mode 100644 index 0000000000000000000000000000000000000000..72fce6dcb359bb94ee8c87c70a711ad2ab9eb137 Binary files /dev/null and b/isis/src/base/apps/cubenorm/assets/thumb/thumb_after.jpg differ diff --git a/isis/src/base/apps/cubenorm/assets/thumb/thumb_before.jpg b/isis/src/base/apps/cubenorm/assets/thumb/thumb_before.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b22e9b8be9cff807a9de57c32aa4ea683fa03fc6 Binary files /dev/null and b/isis/src/base/apps/cubenorm/assets/thumb/thumb_before.jpg differ diff --git a/isis/src/base/apps/cubenorm/assets/thumb/thumb_colnorm.jpg b/isis/src/base/apps/cubenorm/assets/thumb/thumb_colnorm.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a9780fbbba92a4acb249678b059b87ab88934097 Binary files /dev/null and b/isis/src/base/apps/cubenorm/assets/thumb/thumb_colnorm.jpg differ diff --git a/isis/src/base/apps/cubenorm/assets/thumb/thumb_cubenorm.jpg b/isis/src/base/apps/cubenorm/assets/thumb/thumb_cubenorm.jpg new file mode 100755 index 0000000000000000000000000000000000000000..59ce784757b2581fc1daa32d7c10e258b82aeccd Binary files /dev/null and b/isis/src/base/apps/cubenorm/assets/thumb/thumb_cubenorm.jpg differ diff --git a/isis/src/base/apps/cubenorm/cubenorm.cpp b/isis/src/base/apps/cubenorm/cubenorm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..907ebcc7feb4a8d003124c24c2cb8b189db4acb1 --- /dev/null +++ b/isis/src/base/apps/cubenorm/cubenorm.cpp @@ -0,0 +1,504 @@ +#include "Isis.h" + +// system include files go first +#include +#include +#include +#include +#include + +// Isis specific include files go next +#include "ProcessByTile.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" +#include "Pvl.h" +#include "Statistics.h" + +//Application specific includes +#include "staticStats.h" + +using namespace std; +using namespace Isis; +using namespace PIRL; + +// These global vectors are used to keep track of info for columns or rows +// of image data. For example, a 100 sample x 200 line x 2 band cube will +// have a vectors of 200 columns when processing in the column direction +// (100 samples x 2 bands). Likewise, the vectors will have 400 rows when +// processing in the line direction (200 lines x 2 bands) +vector st; +vector band; +vector element; +vector median; +vector average; +vector normalizer; +int rowcol; // how many rows or cols per band +bool normalizeUsingAverage; // mult/sub using average or median? + +// Size of the cube +int totalLines; +int totalSamples; +int totalBands; + +string direction; + +// function prototypes +void getStats(Buffer &in); +void multiply(Buffer &in, Buffer &out); +void subtract(Buffer &in, Buffer &out); +void pvlOut(const string &pv); +void tableOut(const string &pv); +void PVLIn(const Isis::Filename & filename); +void tableIn(const Isis::Filename & filename); +void subSame(); +void multSame(); + +// Main Program +void IsisMain() { + // ERROR CHECK: The user must specify at least the TO or STATS + // parameters. + UserInterface &ui = Application::GetUserInterface(); + if (!(ui.WasEntered("TO")) && !(ui.WasEntered("STATS"))) { + string msg = "User must specify a TO and/or STATS file."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // We will be processing by tile. This is nice since we change change the + // shape of our buffer to be either a row or column + ProcessByTile p; + + // Setup the input cube; + // Obtain information from the input file + Cube *icube = p.SetInputCube("FROM"); + totalSamples = icube->Samples(); + totalLines = icube->Lines(); + totalBands = icube->Bands(); + + // Setup the tile size based on the direction of normalization + direction = ui.GetString("DIRECTION"); + if (direction == "COLUMN") { + p.SetTileSize(1, totalLines); + rowcol = totalSamples; + } + else { + p.SetTileSize(totalSamples, 1); + rowcol = totalLines; + } + + // Now get the statistics for each row or column + normalizeUsingAverage = ui.GetString("NORMALIZER") == "AVERAGE"; + + //gather statistics + if (ui.GetString("STATSOURCE") == "CUBE"){ + p.StartProcess(getStats); + } + else if (ui.GetString("STATSOURCE") == "TABLE"){ + tableIn(ui.GetFilename("FROMSTATS")); + } + else{ + PVLIn(ui.GetFilename("FROMSTATS")); + } + + //check to make sure the first vector has as many elements as the last + // vector, and that there is a vector element for each row/col + if ((band.size() != (unsigned int)(rowcol*totalBands)) || + (st.size() != (unsigned int)(rowcol*totalBands))){ + string message = "You have entered an invalid input file " + + ui.GetFilename("FROMSTATS"); + throw iException::Message(Isis::iException::Io, message, + _FILEINFO_); + } + + //If a STATS file was specified then create statistics file + if (ui.WasEntered("STATS")) { + string op = ui.GetString("FORMAT"); + if (op == "PVL") pvlOut(ui.GetFilename("STATS")); + if (op == "TABLE") tableOut(ui.GetFilename("STATS")); + } + + // If an output file was specified then normalize the cube + if (ui.WasEntered ("TO")) { + // Before creating a normalized cube check to see if there + // are any column averages less than or equal to zero. + if (ui.GetString("MODE") == "MULTIPLY") { + for (unsigned int i=0; i pixels; + for (int i=0; i 0) { + results += PvlKeyword("Mean",st[i].Average()); + results += PvlKeyword("Median",median[i]); + results += PvlKeyword("Std",st[i].StandardDeviation()); + results += PvlKeyword("Minimum",st[i].Minimum()); + results += PvlKeyword("Maximum",st[i].Maximum()); + } + else { + results += PvlKeyword("Mean",0.0); + results += PvlKeyword("Median",0.0); + results += PvlKeyword("Std",0.0); + results += PvlKeyword("Minimum",0.0); + results += PvlKeyword("Maximum",0.0); + } + } + + Pvl t; + t.AddGroup(results); + t.Write(StatFile); +} + +//******************************************************** +// Create Tabular output of statistics +//******************************************************* +void tableOut(const string &StatFile) { + // Open output file + // TODO check status and throw error + ofstream out; + out.open(StatFile.c_str(),std::ios::out); + + // Output a header + out << std::setw(8) << "Band"; + out << std::setw(8) << "RowCol"; + out << std::setw(15) << "ValidPoints"; + out << std::setw(15) << "Average"; + out << std::setw(15) << "Median"; + out << std::setw(15) << "StdDev"; + out << std::setw(15) << "Minimum"; + out << std::setw(15) << "Maximum"; + out << endl; + + // Print out the table results + for (unsigned int i=0; i 0) { + out << std::setw(15) << st[i].Average(); + out << std::setw(15) << median[i]; + //Make sure the table's SD is 0 for RowCols with 1 or less valid pixels + if( st[i].ValidPixels() > 1 ) { + out << std::setw(15) << st[i].StandardDeviation(); + } + else { + out << std::setw(15) << 0; + } + out << std::setw(15) << st[i].Minimum(); + out << std::setw(15) << st[i].Maximum(); + } + else { + out << std::setw(15) << 0; + out << std::setw(15) << 0; + out << std::setw(15) << 0; + out << std::setw(15) << 0; + out << std::setw(15) << 0; + } + out << endl; + } + out.close(); +} + +//******************************************************** +// Gather statistics from a PVL input file +//******************************************************* +void PVLIn(const Isis::Filename &filename){ + Pvl pvlFileIn; + pvlFileIn.Read(filename.Name()); + PvlGroup results = pvlFileIn.FindGroup("Results"); + PvlObject::PvlKeywordIterator itr = results.Begin(); + + while (itr != results.End()){ + StaticStats newStat; + band.push_back((*itr)[0]); + itr++; + element.push_back((*itr)[0]); + itr++; + newStat.setValidPixels((*itr)[0]); + itr++; + newStat.setMean((*itr)[0]); + itr++; + median.push_back((*itr)[0]); + itr++; + newStat.setStandardDeviation((*itr)[0]); + itr++; + newStat.setMinimum((*itr)[0]); + itr++; + newStat.setMaximum((*itr)[0]); + itr++; + st.push_back(newStat); + + // Determine the normalizer + if (normalizeUsingAverage) { + normalizer.push_back(newStat.Average()); + } + else { + normalizer.push_back(median[median.size()-1]); + } + } +} + +//******************************************************** +// Gather statistics from a table input file +//******************************************************* +void tableIn(const Isis::Filename & filename){ + ifstream in; + string expanded(filename.Expanded()); + in.open(expanded.c_str(),std::ios::in); + + + if (!in){ + string message = "Error opening " + filename.Expanded(); + throw iException::Message(Isis::iException::Io, message, + _FILEINFO_); + } + + //skip the header (106 bytes) + in.seekg(106); + + + //read it + StaticStats newStat; + iString inString; + while (in >> inString){ + band.push_back(inString); + in>> inString; + element.push_back(inString); + in>> inString; + newStat.setValidPixels(inString); + in >> inString; + newStat.setMean(inString); + in >> inString; + median.push_back(inString); + in >> inString; + newStat.setStandardDeviation(inString); + in >> inString; + newStat.setMinimum(inString); + in >> inString; + newStat.setMaximum(inString); + st.push_back(newStat); + //Make sure Standard Deviation is not < 0 when reading in from a table + if( newStat.StandardDeviation() < 0 ) { + newStat.setStandardDeviation( 0 ); + } + // Determine the normalizer + if (normalizeUsingAverage) { + normalizer.push_back(newStat.Average()); + } + else { + normalizer.push_back(median[median.size()-1]); + } + } + in.close(); +} + +//******************************************************** +// Compute coefficients such that when we subtract the average or median +// of the output image stays the same +void subSame() { + // Loop for each band + for (int iband=1; iband<=totalBands; iband++) { + double sumAverage = 0.0; + double sumValidPixels = 0; + for (int i=0; i + + + + + Normalize columns or lines in a cube + + + +

    + The program accomplishes the fairly straightforward task of taking an input + cube and outputting normalized values. These values may be represented as + a table, PVL (parameter value language), or an entire output cube. +

    + Normalization may be done with respect to lines or with respect to columns. + If the user were to normalize by line, the program would take a pass through + the data in order to determine statistics for each line. Cubenorm will then + pass through each pixel again and normalize each one based on the line in + which that pixel is located. +

    + The normalization itself may be thought of as applying either a multiplicative + correction or a subtractative correction. Consider the average of a column + of data. Each pixel may be normalized by subtracting a normalization factor + or multiplying by a normalization factor. Additionally, the user may decide + to use a normalization factor based on the median instead of the average. + + + + + Original version (as colnorm) + + + Added options for subtractative corrections + + + Added process by line option and rename to cubenorm + + + Modified unit test to take new options in to account + + + Major reworking and bug fixes + + + Specialized to run using input files. + + + Incorporate UA cubenorm_plus version functionality + + + Changed a single valid pixel's RowCol's Standard Deviation to 0 instead of + Isis:Null. When reading in a table file, all Standard Deviations less + than 0 are considered 0. + + + Removed references to CubeInfo + + + Fixed check in getstats method that sees whether you are processing by + line or column. + + + Removed redundancy of having static global variables + + + + + Math and Statistics + Radiometric and Photometric Correction + + + + + ratio + poly + stats + + + + + + + cube + input + + Input cube + + + Use this parameter to select input file + + + *.cub + + + + + cube + real + output + + No Output file will be created + + + Optional output cube + + + Output file with input columns divided by the column average + + + + + filename + output + + No Output file will be created + + + Optional stats file + + + Statistical output of each column + (band #, column #, valid pixels, average, median, std, min, max) + + + + + string + TABLE + Format type of STATS file (TABLE or PVL) + + Specify the format type of the statistics file, either + use tabular or PVL style format. + + + + + + + + + + + string + CUBE + Input source of statistics to apply to FROM cube + +

    + This option is intended to be used when the statistics come from + a source other than the input cube (default). cubenorm initial + derives all its statistics from the input cube and applies it as + specified by the user in the same run. This works for most + conditions but does not works so well with abrupt changes + in brightness such as craters or poles. +

    +

    + With this option, it is now possible to have the statistics come + a file in a format compatable with the STATS output file. This can + be a TABLE or PVL formatted input file. This allows statistics + from other cubenorm runs to be used as input statistics source. + It also allows intermediate processing on the FROM stats to + apply additional smoothing or culling techniques. +

    +
    + + + + + + + + filename + input + Optional statistics input file source + +

    + This optional file provides the statistics that are applied to the input + FROM file. Its format must be TABLE or PVL and consistant with + the STATS file output format. +

    +

    + If this option is utilized, the statistics gathering step is bypassed. +

    +
    + *.txt +
    + + + + + string + COLUMN + Direction in which statistics and operations operate + + This is the direction in which normalization occurs. If the user chooses + to process by column, they intend to take in an entire column of data + and normalize based on the average or median of that column for each + pixel in that column. If they choose to process by line, they intend to + do the same for each pixel, but with respect to lines. + + + + + + + + + string + MEDIAN + + Apply normalization using average or median + + + This option is used to select if column or line is normalized using its average or median + + + + + + + + + string + DIVIDE + + Apply coefficients through subtraction or division + + + This option is used to select select how normalization coefficients are applied, either subtracting or dividing by + the average or median. + + + + + + + + + boolean + TRUE + Preserve the input image median/average + + This option is used to preserve the average/median of the input image. If turned off, the output image + average of the data will be one (unity) for the DIVIDE mode or zero for the SUBTRACT mode. + + + + + + + + + Before and after example of sample column normalization + + The image example shows before and after results from applying the + cubenorm program (MGS/MOC image was used in the example). The + cubenorm program is useful to cosmetically correct the horizontal + stripping pattern seen in push-broom imaging systems such as MGS/MOC + and MRO/HiRISE. +

    + In this example, the MODEOPT=AVERAGE option was chosen to normalize + the sample columns of the image. The MODEOPT=MEDIAN is recommended + for most applications because the normalization results are less + sensitive to scene variations. + + + from=moc.cub to=out.cub modeopt=average + + Perform sample column normalization with the average option + + + + + Input image + + This input image image is a MGS/MOC narrow-angle camera image. + Note the vertical stripping of the push-broom system due to the + varying sensitivity of the detectors in the push-broom array. + + + FROM + + + + + Output image + + The output image has been cosmetically corrected for the vertical stripping pattern + seen in the raw MGS/MOC image input file. + + + TO + + + + + + Example GUI + Screen shot of cubenorm GUI + + + + + + + Example of table output of sample column statistics + + In this example, the user requested tabular output of the sample + column statistics. Tabluated are the band number, sample column number, number of + valid pixels, average, median, standard deviation, minimum, and maximum for each + sample column. Note that the user did not specify a TO parameter so only the + statistics table file is created. Tabulated output is shown below. +

    +Band SampCol ValidPoints  Average  Median  StdDev   Minimum  Maximum
    +   1       1        6016  151.862     153    8.278      101       171
    +   1       2        6016  150.537     152  8.36067      100       169
    +   1       3        6016  149.479     151  8.336186       97       170
    +   1       4        6016  154.333     156  8.63899       97       176
    +   1       5        6016  151.366     153  8.61287      100       172
    +   1       6        6016  152.868     154  8.76716       98       173
    +   1       7        6016  152.182     154  8.71654       97       172
    +   1       8        6016  152.165     154   8.7582       98       173
    +   1       9        6016  151.945     153  8.67002       93       175
    +   1      10        6016   152.28     154  8.64981       97       173
    +   1      11        6016  152.035     153  8.54126       99       171
    +   1      12        6016   152.57     154  8.65598       99       172
    +   1      13        6016  152.515     154  8.6498        94       174
    +   1      14        6016  152.811     154  8.69562       92       174
    +   1      15        6016  152.425     154 8.60978        93       171
    +      
    +
    + + from=moc.cub stats=output.dat statsopt=table + + Create a table file of sample column averages. + + +
    +
    + +
    diff --git a/isis/src/base/apps/cubenorm/staticStats.cpp b/isis/src/base/apps/cubenorm/staticStats.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f1bb0ad586fe700cde9ecb27f54f3317b47ef9ec --- /dev/null +++ b/isis/src/base/apps/cubenorm/staticStats.cpp @@ -0,0 +1,66 @@ +/* StaticStats + +PIRL CVS ID: $Id: staticStats.cpp,v 1.1 2007/01/11 20:59:17 kbecker Exp $ + +Copyright (C) 2005, 2006 Arizona Board of Regents on behalf of the +Planetary Image Research Laboratory, Lunar and Planetary Laboratory at +the University of Arizona. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License, version 2.1, +as published by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ +#include "staticStats.h" + +using namespace PIRL; + + const char* const + StaticStats::ID = + "PIRL::StaticStats ($Revision: 1.1 $ $Date: 2007/01/11 20:59:17 $)"; + StaticStats::StaticStats(double meanIn, double stdDevIn, int validPixelsIn, + double minimumIn, double maximumIn){ + myMean = meanIn; + myStandardDeviation = stdDevIn; + myValidPixels = validPixelsIn; + myMinimum = minimumIn; + myMaximum = maximumIn; + } + double StaticStats::Average(){ + return myMean; + } + void StaticStats::setMean(double meanIn){ + myMean = meanIn; + } + double StaticStats::StandardDeviation(){ + return myStandardDeviation; + } + void StaticStats::setStandardDeviation(double standardDeviationIn){ + myStandardDeviation = standardDeviationIn; + } + int StaticStats::ValidPixels(){ + return myValidPixels; + } + void StaticStats::setValidPixels(int validPixelsIn){ + myValidPixels = validPixelsIn; + } + double StaticStats::Minimum(){ + return myMinimum; + } + void StaticStats::setMinimum(double minimumIn){ + myMinimum = minimumIn; + } + double StaticStats::Maximum(){ + return myMaximum; + } + void StaticStats::setMaximum(double maximumIn){ + myMaximum = maximumIn; + } diff --git a/isis/src/base/apps/cubenorm/staticStats.h b/isis/src/base/apps/cubenorm/staticStats.h new file mode 100644 index 0000000000000000000000000000000000000000..e4a7bd4371a7cf4f9c142dbafb1a457f0dec0045 --- /dev/null +++ b/isis/src/base/apps/cubenorm/staticStats.h @@ -0,0 +1,178 @@ +/* StaticStats + +PIRL CVS ID: $Id: staticStats.h,v 1.1 2007/01/11 20:59:17 kbecker Exp $ + +Copyright (C) 2005, 2006 Arizona Board of Regents on behalf of the +Planetary Image Research Laboratory, Lunar and Planetary Laboratory at +the University of Arizona. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License, version 2.1, +as published by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +#ifndef staticStats_h +#define staticStats_h + +namespace PIRL +{ +/** A StaticStats instance allows the user to set statistics for a cube + + This class exists to extend the functionality of the ISIS stats class, which + can construct a Stats object, but can only gather statistics from a cube + as opposed to an input pvl or table, both of which are features of the + StaticStats class. + + The use of this class is considered somewhat limited by the author. It cannot + be emphasized enough that the contents of a cub ARE NOT CHANGED via the + mutators of this class. Rather, the class allows the user to change PERCEIVED + VALUES for the class. + + This class can only be used to impose artificial statistics. For example, + the class was created so that a user might gather statistics using the normal + statistics class, write those statistics in a table, and then use those table + values to create a StaticStats instance so that statistics from the cube would + not have to be gathered over and over again. + + @author Drew Davidson, UA/PIRL + + $Revision: 1.1 $ +*/ +class StaticStats{ +public: + +/*============================================================================== + Constants +==============================================================================*/ +//! Class identification name with source code version and date. +static const char* const + ID; + +/*============================================================================== + Constructors +==============================================================================*/ + /** Constructs a default StaticStats. + + The staticStats has no statistics, they should be set via the mutator + methods below + */ + StaticStats(){}; + + /** Constructs a StaticStats with given statistics. + + The staticStats is given an initial set of statistics. + + @param initialMean + The initial mean DN for pixels in the cub + + @param initialStandardDeviation + The initial DN standard deviation for pixels in the cub + + @param initialValidPixels + The initial number of valid pixels in the cub + + @param initialMinimum + The initial minimum DN value in the cub + + @param initialMaximum + The initial maximum DN value in the cub + */ + StaticStats(double initialMean, + double initialStandardDeviation, + int initialValidPixels, + double initialMinimum, + double initialMaximum); + +/*============================================================================== + Accessors +==============================================================================*/ + /** Gets the perceived mean pixel DN value. + + @return DN mean for the cub + */ + double Average(); + + /** Gets the perceived standard deviation for all pixel DN values. + + @return DN standard deviaton for the cub + */ + double StandardDeviation(); + + /** Gets the perceived number of valid pixels. + + @return Number of valid pixels in the cub + */ + int ValidPixels(); + + /** Gets the perceived minimum DN value. + + @return Lowest pixel DN in the cub + */ + double Minimum(); + + /** Gets the perceived maximum DN value. + + @return Highest pixel DN in the cub + */ + double Maximum(); + +/*============================================================================== + Mutators +==============================================================================*/ + /** Sets the perceived mean DN value. + + @param newMean New mean DN value + */ + void setMean(double newMean); + + /** Sets the perceived standard deviation of DN values in the cub. + + @param newStandardDeviation New standard deviation for the cub + */ + void setStandardDeviation(double newStandardDeviation); + + /** Sets the perceived count of valid pixels. + + @param newValidPixels New count of valid pixels in the cub + */ + void setValidPixels(int newValidPixelCount); + + /** Sets the perceived maximum DN in the cub + + @param newMaximum New maximum DN value + */ + void setMaximum(double newMaximum); + + /** Sets the perceived minimum DN in the cub + + @param newMinimum New minimum DN value + */ + void setMinimum(double newMinimum); + +private: + //! Perceived mean DN + double myMean; + + //! Perceived DN standard deviation + double myStandardDeviation; + + //! Perceived minimum DN + double myMinimum; + + //! Perceived maximum DN + double myMaximum; + + //! Perceived valid pixel count + int myValidPixels; +}; +}/* End namespace PIRL */ +#endif diff --git a/isis/src/base/apps/cubenorm/tsts/Makefile b/isis/src/base/apps/cubenorm/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/cubenorm/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/cubenorm/tsts/avgFalse/Makefile b/isis/src/base/apps/cubenorm/tsts/avgFalse/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3a2567dba453c4c3204a598af714d2a8b53a42e5 --- /dev/null +++ b/isis/src/base/apps/cubenorm/tsts/avgFalse/Makefile @@ -0,0 +1,17 @@ +APPNAME = cubenorm + +include $(ISISROOT)/make/isismake.tsts + +commands: + crop from=$(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/cropTemp.cub \ + sample = 8 \ + nsamples = 6 \ + sinc = 1 \ + line = 8 \ + nlines = 6 \ + linc = 1 > /dev/null; + $(APPNAME) from= $(OUTPUT)/cropTemp.cub \ + to=$(OUTPUT)/cubenormTruth2.cub \ + normalizer = average \ + preserve = false > /dev/null; diff --git a/isis/src/base/apps/cubenorm/tsts/avgTrue/Makefile b/isis/src/base/apps/cubenorm/tsts/avgTrue/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..824bb0661cb40b796ddef04df058d0cdc11b60a8 --- /dev/null +++ b/isis/src/base/apps/cubenorm/tsts/avgTrue/Makefile @@ -0,0 +1,17 @@ +APPNAME = cubenorm + +include $(ISISROOT)/make/isismake.tsts + +commands: + crop from=$(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/cropTemp.cub \ + sample = 8 \ + nsamples = 6 \ + sinc = 1 \ + line = 8 \ + nlines = 6 \ + linc = 1 > /dev/null; + $(APPNAME) from= $(OUTPUT)/cropTemp.cub \ + to=$(OUTPUT)/cubenormTruth1.cub \ + normalizer = average \ + preserve = true > /dev/null; diff --git a/isis/src/base/apps/cubenorm/tsts/medFalse/Makefile b/isis/src/base/apps/cubenorm/tsts/medFalse/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2e502e4467dbd4719eb85c7c4535fb10d896f731 --- /dev/null +++ b/isis/src/base/apps/cubenorm/tsts/medFalse/Makefile @@ -0,0 +1,17 @@ +APPNAME = cubenorm + +include $(ISISROOT)/make/isismake.tsts + +commands: + crop from=$(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/cropTemp.cub \ + sample = 8 \ + nsamples = 6 \ + sinc = 1 \ + line = 8 \ + nlines = 6 \ + linc = 1 > /dev/null; + $(APPNAME) from= $(OUTPUT)/cropTemp.cub \ + to=$(OUTPUT)/cubenormTruth4.cub \ + normalizer = median \ + preserve = false > /dev/null; diff --git a/isis/src/base/apps/cubenorm/tsts/medTrue/Makefile b/isis/src/base/apps/cubenorm/tsts/medTrue/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6e9150debdd37781c2cc4871b33e7aca9bbe2c2a --- /dev/null +++ b/isis/src/base/apps/cubenorm/tsts/medTrue/Makefile @@ -0,0 +1,17 @@ +APPNAME = cubenorm + +include $(ISISROOT)/make/isismake.tsts + +commands: + crop from=$(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/cropTemp.cub \ + sample = 8 \ + nsamples = 6 \ + sinc = 1 \ + line = 8 \ + nlines = 6 \ + linc = 1 > /dev/null; + $(APPNAME) from= $(OUTPUT)/cropTemp.cub \ + to=$(OUTPUT)/cubenormTruth3.cub \ + normalizer = median \ + preserve = true > /dev/null; diff --git a/isis/src/base/apps/ddd2isis/Makefile b/isis/src/base/apps/ddd2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/ddd2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/ddd2isis/ddd2isis.cpp b/isis/src/base/apps/ddd2isis/ddd2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b961b8dc293a753918a41e6ef740e4834f510888 --- /dev/null +++ b/isis/src/base/apps/ddd2isis/ddd2isis.cpp @@ -0,0 +1,99 @@ +#include "Isis.h" +#include "ProcessImport.h" +#include "UserInterface.h" +#include "SpecialPixel.h" +#include "Filename.h" + +using namespace std; +using namespace Isis; + +void IsisMain () { + UserInterface &ui = Application::GetUserInterface (); + ProcessImport p; + iString from = ui.GetFilename("FROM"); + EndianSwapper swp("MSB"); + int nsamples = 0, nlines = 0, nbands = 1; + + union { + char readChars[4]; + long readLong; + float readFloat; + } readBytes; + + ifstream fin; + fin.open(from.c_str(), ios::in | ios::binary); + if (!fin.is_open()) { + string msg = "Cannot open input file [" + from + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + +/** + * 0-rel byte offset value + * 0 32-bit integer magic number + * 4 32-bit integer number of image lines + * 8 32-bit integer number of bytes per image line + * 12 32-bit integer number of bits per image elements + * 16 32-bit integer currently unused + * 20 32-bit integer currently unused + * 24 ASCII label up to 1000 characters long + * The label is NUL-terminated + * + */ + + // Verify the magic number + fin.seekg(0); + fin.read(readBytes.readChars, 4); + readBytes.readFloat = swp.Float(readBytes.readChars); + + if(readBytes.readLong != 0x67B) { + string msg = "Input file [" + from + "] does not appear to be in ddd format"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + fin.read(readBytes.readChars, 4); + readBytes.readFloat = swp.Float(readBytes.readChars); + nlines = (int)readBytes.readLong; + + fin.read(readBytes.readChars, 4); + readBytes.readFloat = swp.Float(readBytes.readChars); + nsamples = (int)readBytes.readLong; + + fin.read(readBytes.readChars, 4); + readBytes.readFloat = swp.Float(readBytes.readChars); + + if(fin.fail() || fin.eof()) { + string msg = "An error ocurred when reading the input file [" + from + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + fin.close(); + + switch (readBytes.readLong) { + case 8: + p.SetPixelType(Isis::UnsignedByte); + break; + case 16: + p.SetPixelType(Isis::UnsignedWord); + break; + case 32: + p.SetPixelType(Isis::Real); + break; + default: + iString msg = "Unsupported bit per pixel count [" + iString((int)readBytes.readLong) + "]"; + throw iException::Message(iException::Io, msg, _FILEINFO_); + } + + nsamples /= (readBytes.readLong / 8); + + p.SetDimensions(nsamples,nlines,nbands); + p.SetFileHeaderBytes(1024); + p.SetByteOrder(Isis::Msb); + p.SetInputFile (ui.GetFilename("FROM")); + p.SetOutputCube("TO"); + + p.StartProcess (); + p.EndProcess (); + + return; +} + diff --git a/isis/src/base/apps/ddd2isis/ddd2isis.xml b/isis/src/base/apps/ddd2isis/ddd2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..49582c7ddf5ac7db10f1cf7c1ae4e97974c917bf --- /dev/null +++ b/isis/src/base/apps/ddd2isis/ddd2isis.xml @@ -0,0 +1,54 @@ + + + + + + Import msss ddd file into Isis format + + + + This program will import a ddd image into an Isis cube. The ddd format files are created by Malin Space Science Systems. + + + + + Original version + + + + + Import and Export + + + + + + filename + input + + Input ddd file + + + Use this parameter to select the ddd filename. + + + *.ddd + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + diff --git a/isis/src/base/apps/ddd2isis/tsts/Makefile b/isis/src/base/apps/ddd2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/ddd2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/ddd2isis/tsts/default/Makefile b/isis/src/base/apps/ddd2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a1ac8f27297b69f98b7d719b691b7fe4275918df --- /dev/null +++ b/isis/src/base/apps/ddd2isis/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = ddd2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/vis1flat.ddd TO=$(OUTPUT)/vis1flat.cub > /dev/null; diff --git a/isis/src/base/apps/decorstretch/Makefile b/isis/src/base/apps/decorstretch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/decorstretch/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/decorstretch/decorstretch.cpp b/isis/src/base/apps/decorstretch/decorstretch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36ab6524ed154ac13a90e20f95c062dfec210d01 --- /dev/null +++ b/isis/src/base/apps/decorstretch/decorstretch.cpp @@ -0,0 +1,114 @@ +#include "Isis.h" +#include "tnt_array2d.h" +#include "PrincipalComponentAnalysis.h" +#include "ProcessBySpectra.h" +#include "Statistics.h" +#include "GaussianStretch.h" +#include + +using namespace std; +using namespace Isis; + +void GetData(Buffer &in); +void Transform (Buffer &in, Buffer &out); +void NormalizeAndInvert (Buffer &in, Buffer &out); + +PrincipalComponentAnalysis pca(0); +vector stretches; + +string tmpFilename = "Temporary_DecorrelationStretch_Transform.cub"; + +void IsisMain() +{ + ProcessByBrick p; + Cube *icube = p.SetInputCube("FROM"); + int numDimensions = icube->Bands(); + p.SetBrickSize(128, 128, numDimensions); + + // The output cube with no attributes and real pixel type + Isis::CubeAttributeOutput cao; + cao.PixelType(Isis::Real); + + p.SetOutputCube(tmpFilename, cao, icube->Samples(), icube->Lines(), icube->Bands()); + + // Get the data for the transform matrix + pca = Isis::PrincipalComponentAnalysis(numDimensions); + ProcessByBrick p2; + p2.SetBrickSize(128, 128, numDimensions); + p2.SetInputCube("FROM"); + p2.Progress()->SetText("Computing Transform"); + p2.StartProcess(GetData); + p2.EndProcess(); + pca.ComputeTransform(); + + p.Progress()->SetText("Transforming Cube"); + p.StartProcess(Transform); + p.EndProcess(); + + Isis::CubeAttributeInput cai; + + Cube *icube2 = p.SetInputCube(tmpFilename, cai); + for (int i=0; iHistogram(i+1)) )); + } + p.SetOutputCube("TO"); + + p.SetBrickSize(128, 128, numDimensions); + p.Progress()->SetText("Stretching Cube"); + p.StartProcess(NormalizeAndInvert); + + for (int i=0; i pre(1, in.BandDimension()); + for (int k=0;k post = pca.Transform(pre); + + for (int k=0; k pre(1, in.BandDimension()); + for (int k=0;kAverage())/bandStats[k]->StandardDeviation(); + pre[0][k] = stretches[k]->Map(in[index]); + } + + TNT::Array2D post = pca.Inverse(pre); + + for (int k=0; k + + + Apply a Decorrelation Stretch to a cube + + + + This programs applies a decorrelation stretch to a cube. + + + + Math and Statistics + + + + + ipca + + + + + + Original version + + + Documentation fixes + + + Removed references to CubeInfo + + + + + + + cube + input + + Input file to stretch + + + The input cube which will have the decorrelation stretch applied. + + + *.cub + + + + + cube + real + output + + Output cube + + + The resultant cube containing the image after being stretched. + + + *.cub + + + + + diff --git a/isis/src/base/apps/decorstretch/tsts/Makefile b/isis/src/base/apps/decorstretch/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/decorstretch/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/decorstretch/tsts/default/Makefile b/isis/src/base/apps/decorstretch/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6c609eaf33eb27d0c78837a9026d4ca4b9b69a0a --- /dev/null +++ b/isis/src/base/apps/decorstretch/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = decorstretch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/test.cub \ + to=$(OUTPUT)/decorstretchTruth.cub > /dev/null; diff --git a/isis/src/base/apps/deltack/Makefile b/isis/src/base/apps/deltack/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0f3da14e6601d573271b8392ee6a140c09834e07 --- /dev/null +++ b/isis/src/base/apps/deltack/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = deltack + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/deltack/deltack.cpp b/isis/src/base/apps/deltack/deltack.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9b1e3c83a9b9132b9482a3320554e9062a2be80 --- /dev/null +++ b/isis/src/base/apps/deltack/deltack.cpp @@ -0,0 +1,135 @@ +#include "Isis.h" +#include "Process.h" +#include "BundleAdjust.h" +#include "Table.h" +#include "iException.h" +#include "Sensor.h" +#include "History.h" + +using namespace std; +using namespace Isis; + +double GetRadius(std::string filename, double lat, double lon); + +void IsisMain() { + // Create a serial number list + UserInterface &ui = Application::GetUserInterface(); + string filename = ui.GetFilename("FROM"); + SerialNumberList serialNumberList; + serialNumberList.Add(filename); + + // Get the coordinate for updating the camera pointing + // We will want to make the camera pointing match the lat/lon at this + // line sample + double samp1 = ui.GetDouble("SAMP1"); + double line1 = ui.GetDouble("LINE1"); + double lat1 = ui.GetDouble("LAT1"); + double lon1 = ui.GetDouble("LON1"); + double rad1; + if (ui.WasEntered("RAD1")) { + rad1 = ui.GetDouble("RAD1"); + } + else { + rad1 = GetRadius(ui.GetFilename("FROM"),lat1,lon1); + } + + // In order to use the bundle adjustment class we will need a control + // network + ControlMeasure m; + m.SetCubeSerialNumber(serialNumberList.SerialNumber(0)); + m.SetCoordinate(samp1,line1); + m.SetType(ControlMeasure::Manual); + + ControlPoint p; + p.SetUniversalGround(lat1,lon1,rad1); + p.SetId("Point1"); + p.SetType(ControlPoint::Ground); + p.Add(m); + + ControlNet cnet; + cnet.SetType(ControlNet::ImageToGround); + cnet.Add(p); + + // See if they wanted to solve for twist + if (ui.GetBoolean("TWIST")) { + double samp2 = ui.GetDouble("SAMP2"); + double line2 = ui.GetDouble("LINE2"); + double lat2 = ui.GetDouble("LAT2"); + double lon2 = ui.GetDouble("LON2"); + double rad2; + if (ui.WasEntered("RAD2")) { + rad2 = ui.GetDouble("RAD2"); + } + else { + rad2 = GetRadius(ui.GetFilename("FROM"),lat2,lon2); + } + + ControlMeasure m; + m.SetCubeSerialNumber(serialNumberList.SerialNumber(0)); + m.SetCoordinate(samp2,line2); + m.SetType(ControlMeasure::Manual); + + ControlPoint p; + p.SetUniversalGround(lat2,lon2,rad2); + p.SetId("Point2"); + p.SetType(ControlPoint::Ground); + p.Add(m); + + cnet.Add(p); + } + + // Bundle adjust to solve for new pointing + try { + BundleAdjust b(cnet,serialNumberList); + b.SetSolveTwist(ui.GetBoolean("TWIST")); + double tol = ui.GetDouble("TOL"); + int maxIterations = ui.GetInteger("MAXITS"); + b.Solve(tol,maxIterations); + + Cube c; + c.Open(filename,"rw"); + + //check for existing polygon, if exists delete it + if (c.Label()->HasObject("Polygon")){ + c.Label()->DeleteObject("Polygon"); + } + + Table cmatrix = b.Cmatrix(0); + + // Write out a description in the spice table + //PvlKeyword description("Description"); + //description = "Camera pointing updated via deltack application"; + //cmatrix.Label().FindObject("Table",Pvl::Traverse).AddKeyword(description); + + // Update the cube history + c.Write(cmatrix); + History h("IsisCube"); + c.Read(h); + h.AddEntry(); + c.Write(h); + c.Close(); + PvlGroup gp( "DeltackResults" ); + gp += PvlKeyword("Status","Camera pointing updated"); + Application::Log( gp ); + } + catch (iException &e) { + string msg = "Unable to update camera pointing for [" + filename + "]"; + throw iException::Message(Isis::iException::Camera,msg,_FILEINFO_); + } + +} + +// Compute the radius at the lat/lon +double GetRadius(std::string filename, double lat, double lon) { + Pvl lab(filename); + Sensor sensor(lab); + sensor.SetUniversalGround(lat,lon); + double radius = sensor.LocalRadius(); + if (IsSpecial(radius)) { + string msg = "Could not determine radius from DEM at lat/lon ["; + msg += iString(lat) + "," + iString(lon) + "]"; + throw iException::Message(Isis::iException::Camera,msg,_FILEINFO_); + } + return radius; +} + diff --git a/isis/src/base/apps/deltack/deltack.xml b/isis/src/base/apps/deltack/deltack.xml new file mode 100644 index 0000000000000000000000000000000000000000..55bcdae5d8c84555921d6d8aff10fb852d08f49f --- /dev/null +++ b/isis/src/base/apps/deltack/deltack.xml @@ -0,0 +1,198 @@ + + + + Update camera pointing for a single image + + + +

    + This program can be used to update camera pointing (SPICE) for a single cube. The user must supply a latitude/longitude for a single sample/line coordinate in the image. The right ascension + and declination of the camera will be adjusted to match this request. In order for this program to work properly, the cube must have been initialized with the "spiceinit" program using + ATTACH="YES". Additionally, a second latitude/longitude and sample/line can be given to adjust for camera twist. +

    + +

    + The camera pointing is updated using an iterative least-squares bundle adjustment. The number of iterations and tolerance for convergence are input parameters to this program. Solving for the + right ascension and declination only is similar to a translation of the image. Solving for the twist includes both translation and rotation. +

    +
    + + + Control Networks + + + + + jigsaw + + + + + + Original version + + + Added inclusion of TWIST to SAMP2,LINE2,LAT2,LON2,RAD2. + Without this inclusion, the AML was requiring these parameters + even if TWIST was false. + + + Added pvl status report for a successful update. + + + Added check to see if cube has existing polygon, if so delete it. + + + + + + + cube + input + + Input camera cube + + + The file specification for the input cube. The cube will have + camera pointing updated. + + + *.cub + + + + + + + Number of iterations + Maximum number of iterations to try for convergence to tolerance before stopping + integer + 5 + + + + Tolerance + + Tolerance in pixels. When the bundle adjustment error drops below this value the solution has converged and + the camera pointing will be updated. If the solution does not converge in MAXITS then the camera pointing will + not be updated. + + double + 0.5 + + + + boolean + Solve for camera twist + False + + In addition to right ascension and declination, If this parameter is set, the program will solve for the camera twist. This requires input of a second ground coordinate (SAMP2,LINE2) and + (LAT2,LON2) + + + LINE2 + SAMP2 + LAT2 + LON2 + RAD2 + + + + + + + double + Sample coordinate + The sample coordinate for ground point #1 (LAT1,LON1) + + + + double + Line coordinate + The line coordinate for ground point #1 (LAT1,LON1) + + + + double + Latitude + Planetocentric latitude at the image coordinate (SAMP1,LINE1) + -90.0 + 90.0 + + + + double + Longitude + Planetocentric longitude at the image coordinate (SAMP1,LINE1) + 0.0 + 360.0 + + + + double + Radius + Computed + + Radius in meters at the image coordinate (SAMP1,LINE1). It will be automatically computed using the shape model that + was initialized during the "spiceinit" program, either an ellipsoid or a DEM. + + 0.0 + + + + double + Sample coordinate + The sample coordinate for ground point #2 (LAT2,LON2) + + TWIST + + + + + double + Line coordinate + The line coordinate for ground point #2 (LAT2,LON2) + + TWIST + + + + + double + Latitude + Planetocentric latitude at the image coordinate (SAMP2,LINE2) + -90.0 + 90.0 + + TWIST + + + + + double + Longitude + Planetocentric longitude at the image coordinate (SAMP2,LINE2) + 0.0 + 360.0 + + TWIST + + + + + double + Radius + Computed + + Radius in meters at the image coordinate (SAMP2,LINE2). It will be automatically computed using the shape model that + was initialized during the "spiceinit" program, either an ellipsoid or a DEM. + + 0.0 + + TWIST + + + + + +
    diff --git a/isis/src/base/apps/deltack/tsts/Makefile b/isis/src/base/apps/deltack/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/deltack/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/deltack/tsts/singlePoint/Makefile b/isis/src/base/apps/deltack/tsts/singlePoint/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0e5c1ce85d03480ed6122cb932219d99949a5a67 --- /dev/null +++ b/isis/src/base/apps/deltack/tsts/singlePoint/Makefile @@ -0,0 +1,16 @@ +APPNAME = deltack +#This file tests the single point (don't solve for twist) option + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(CP) $(INPUT)/*.cub $(OUTPUT) + $(APPNAME) from=$(OUTPUT)/I20042001RDR_driftcosi.cub \ + maxits=20 \ + tol=0.5 \ + twist=false \ + samp1=21. \ + line1=1177. \ + lat1=32.53 \ + lon1=79.72 > /dev/null; + $(RM) print.prt < /dev/null; diff --git a/isis/src/base/apps/deltack/tsts/twist/Makefile b/isis/src/base/apps/deltack/tsts/twist/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..379de2af41479389fd606a829325e16d68a9932b --- /dev/null +++ b/isis/src/base/apps/deltack/tsts/twist/Makefile @@ -0,0 +1,20 @@ +APPNAME = deltack +#This file tests the twist (2-point) option + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(CP) $(INPUT)/*.cub $(OUTPUT) + $(APPNAME) from=$(OUTPUT)/I08526015RDR_band9.cub \ + maxits=25 \ + tol=0.4194172 \ + twist=true \ + samp1=58.5 \ + line1=11603. \ + lat1=-6.3533854373815 \ + lon1=354.86255739295 \ + samp2=99.25 \ + line2=8044.75 \ + lat2=-0.3270664209085 \ + lon2=355.70986410595 > /dev/null; + $(RM) print.prt < /dev/null; diff --git a/isis/src/base/apps/deriv/Makefile b/isis/src/base/apps/deriv/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/deriv/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/deriv/assets/image/deriv.horz.jpg b/isis/src/base/apps/deriv/assets/image/deriv.horz.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3b8c39936513d0cbd728b006b7b723ad1f6c654 Binary files /dev/null and b/isis/src/base/apps/deriv/assets/image/deriv.horz.jpg differ diff --git a/isis/src/base/apps/deriv/assets/image/deriv.vert.jpg b/isis/src/base/apps/deriv/assets/image/deriv.vert.jpg new file mode 100644 index 0000000000000000000000000000000000000000..330bc2cec758b2103bb863e28613234e96b03759 Binary files /dev/null and b/isis/src/base/apps/deriv/assets/image/deriv.vert.jpg differ diff --git a/isis/src/base/apps/deriv/assets/image/derivExample.jpg b/isis/src/base/apps/deriv/assets/image/derivExample.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7edb13cef722fd0de115bdd0b7fd4b610228aead Binary files /dev/null and b/isis/src/base/apps/deriv/assets/image/derivExample.jpg differ diff --git a/isis/src/base/apps/deriv/assets/image/derivHorzGui.jpg b/isis/src/base/apps/deriv/assets/image/derivHorzGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..064f338d0666310c5bcdc2957609a77b6a10c61e Binary files /dev/null and b/isis/src/base/apps/deriv/assets/image/derivHorzGui.jpg differ diff --git a/isis/src/base/apps/deriv/assets/image/derivVertGui.jpg b/isis/src/base/apps/deriv/assets/image/derivVertGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..803e91e621af690a49ad7b77c446067bd2f21c77 Binary files /dev/null and b/isis/src/base/apps/deriv/assets/image/derivVertGui.jpg differ diff --git a/isis/src/base/apps/deriv/assets/image/peaks.4.jpg b/isis/src/base/apps/deriv/assets/image/peaks.4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b0ae6226b663d73379a35cb4376afe7750711943 Binary files /dev/null and b/isis/src/base/apps/deriv/assets/image/peaks.4.jpg differ diff --git a/isis/src/base/apps/deriv/assets/thumb/deriv.horz.jpg b/isis/src/base/apps/deriv/assets/thumb/deriv.horz.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7e36519abdb58ffd7e2e8537e5c59ab98279c4a0 Binary files /dev/null and b/isis/src/base/apps/deriv/assets/thumb/deriv.horz.jpg differ diff --git a/isis/src/base/apps/deriv/assets/thumb/deriv.vert.jpg b/isis/src/base/apps/deriv/assets/thumb/deriv.vert.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a4fabda1523c966674e367ecc8e2f67ed5c34014 Binary files /dev/null and b/isis/src/base/apps/deriv/assets/thumb/deriv.vert.jpg differ diff --git a/isis/src/base/apps/deriv/assets/thumb/derivHorzGui.jpg b/isis/src/base/apps/deriv/assets/thumb/derivHorzGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6de70bcd75104b6ca45bd0ad7e11ae80a0f27134 Binary files /dev/null and b/isis/src/base/apps/deriv/assets/thumb/derivHorzGui.jpg differ diff --git a/isis/src/base/apps/deriv/assets/thumb/derivVertGui.jpg b/isis/src/base/apps/deriv/assets/thumb/derivVertGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..61244281a7dcbf0c67c0fc5335457b558f1be30e Binary files /dev/null and b/isis/src/base/apps/deriv/assets/thumb/derivVertGui.jpg differ diff --git a/isis/src/base/apps/deriv/assets/thumb/peaks.4.jpg b/isis/src/base/apps/deriv/assets/thumb/peaks.4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db35c783931b3d40113de16690ce299fddc8187c Binary files /dev/null and b/isis/src/base/apps/deriv/assets/thumb/peaks.4.jpg differ diff --git a/isis/src/base/apps/deriv/deriv.cpp b/isis/src/base/apps/deriv/deriv.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4600e6319b37e098e25664272c698664d52d8e0c --- /dev/null +++ b/isis/src/base/apps/deriv/deriv.cpp @@ -0,0 +1,45 @@ +#include "Isis.h" +#include "ProcessByBoxcar.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void Deriv (Buffer &in, double &v); + +void IsisMain() { + + ProcessByBoxcar p; + + UserInterface &ui = Application::GetUserInterface(); + + // Open the input cube + p.SetInputCube ("FROM"); + + // Allocate the output cube + p.SetOutputCube ("TO"); + + // Which deriv (horizontal or vetical)? + string derivDir = ui.GetString ("DIRECTION"); + // Set boxcar size depending on the derivative direction + if (derivDir == "HORZ") { + p.SetBoxcarSize (2,1); + } + else if (derivDir == "VERT") { + p.SetBoxcarSize (1,2); + } + + p.StartProcess (Deriv); + p.EndProcess (); + +} + +// Derivative process +void Deriv (Buffer &in,double &v) { + if (IsSpecial(in[0]) || IsSpecial(in[1])) { + v = Isis::Null; + return; + } + v = in[0] - in[1]; + +} diff --git a/isis/src/base/apps/deriv/deriv.xml b/isis/src/base/apps/deriv/deriv.xml new file mode 100644 index 0000000000000000000000000000000000000000..fb71930d51e719e1d67f7f7c3a002a3956a28a79 --- /dev/null +++ b/isis/src/base/apps/deriv/deriv.xml @@ -0,0 +1,220 @@ + + + + + + Apply horizontal or vertical derivative + + + +

    + This program will apply a horizontal or vertical derivative to a cube. + This will highlight edges in the image created by groups of contrasting + DN values. The horizontal derivative utilizes a two sample by one line + boxcar convolution for its solution, and will highlight horizontal linear + changes. The vertical derivative utilizes a one sample by two line boxcar + convolution for the output, and will highlight vertical linear changes. + Please refer to the following 2 by 2 pixel example image: +

    + + +

    + In this image, the horizontal derivative for A would be: +

    +
    +        A_NewDN = A - B
    +    
    +

    + The vertical derivative for A would be: +

    +
    +        A_NewDN = A - C
    +    
    +

    + NOTE: If this program needs to do calculations where special pixels + are involved, it will simply output NULL. If this causes undesireable + results, you should run the image through the stretch program to change + all special pixels to valid data. For example, if you have a number of + HRS pixels, you might want to stretch those to 255 prior to running the + deriv filter. +

    +
    + + + + Original version + + + Fixed application name in xml file, misnamed as gradient. + + + Added examples. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Modified to handle special pixels + + + Updated xml documentation with examples + + + + + Filters + + + + + + cube + input + + Input cube + + + Use this parameter to select the filename. All bands within the file + will have the derivative applied. + + + *.cub + + + + + cube + real + output + + Output cube + + + This is the output file. + + + + + + + string + Direction of derivative + HORZ + + This chooses the derivative direction. The possibilities + are: HORZ which uses a 2x1 kernel and VERT which uses a 1x2 + kernel. + + + + + + + + + + + + Horizontal + + Use horizontal derivative option. + + + f=peaks.cub t=deriv.horz d=h + + + In this example the derivative direction is horizontal. + + + + + + Input image for deriv + This is the input image for the horizontal direction option of deriv. + + + FROM + + + + + + Output image for deriv + This is the output image for the horizontal example of deriv. The horizontal features fade and vertical features are enhanced. + + + TO + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a horizontal derivative of the input image. + + + + + + + + Vertical + + Use vertical derivative option. + + + f=peaks.cub t=deriv.vert d=v + + + In this example the derivative direction is vertical. + + + + + + Input image for deriv + This is the input image for the vertical direction option of deriv. + + + FROM + + + + + + Output image for deriv + This is the output image for the vertical example of deriv. The vertical features fade and horizontal features are enhanced. + + + TO + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a vertical derivative of the input image. + + + + + + + +
    diff --git a/isis/src/base/apps/deriv/tsts/Makefile b/isis/src/base/apps/deriv/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/deriv/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/deriv/tsts/horz/Makefile b/isis/src/base/apps/deriv/tsts/horz/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7e24ca2356a6f38e205694abac52f484d660bece --- /dev/null +++ b/isis/src/base/apps/deriv/tsts/horz/Makefile @@ -0,0 +1,8 @@ +APPNAME = deriv + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/derivTruth1.cub \ + direction=horz > /dev/null; diff --git a/isis/src/base/apps/deriv/tsts/vert/Makefile b/isis/src/base/apps/deriv/tsts/vert/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..70dea04eb8e7e46c687404078dd34cda7243f7e3 --- /dev/null +++ b/isis/src/base/apps/deriv/tsts/vert/Makefile @@ -0,0 +1,8 @@ +APPNAME = deriv + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/derivTruth2.cub \ + direction=vert > /dev/null; diff --git a/isis/src/base/apps/deriv/work/deriv.html b/isis/src/base/apps/deriv/work/deriv.html new file mode 100644 index 0000000000000000000000000000000000000000..96595ed869e99130a573fc597bcffd068c7f27fa --- /dev/null +++ b/isis/src/base/apps/deriv/work/deriv.html @@ -0,0 +1,946 @@ + + + + + + USGS: ISIS deriv Application Documentation + + + + + + + + + + + + + + + + + + USGS +
    +

    + Isis 3 Application Documentation

    +
    +

    deriv

    +

    + Apply horizontal or vertical derivative +

    +

    + + Description +
    + + Categories +
    + + Groups +
    + + Examples +
    + + History +
    +

    + +
    +

    + Description +

    +
    +

    + This program will apply a horizontal or vertical derivative to a cube. + This will highlight edges in the image created by groups of contrasting + DN values. The horizontal derivative utilizes a two sample by one line + boxcar convolution for its solution, and will highlight horizontal linear + changes. The vertical derivative utilizes a one sample by two line boxcar + convolution for the output, and will highlight vertical linear changes. + Please refer to the following 2 by 2 pixel example image: +

    + + +

    + In this image, the horizontal derivative for A would be: +

    +
    +        A_NewDN = A - B
    +    
    +

    + The vertical derivative for A would be: +

    +
    +        A_NewDN = A - C
    +    
    +

    + NOTE: If this program needs to do calculations where special pixels + are involved, it will simply output NULL. If this causes undesireable + results, you should run the image through the stretch program to change + all special pixels to valid data. For example, if you have a number of + HRS pixels, you might want to stretch those to 255 prior to running the + deriv filter. +

    +
    + +
    +

    + Categories +

    +
      +
    • Filters
    • +
    + +
    +

    + Parameter Groups +

    +

    Files

    + + + + + + + + + + +
    + Name + + Description +
    FROM + Input cube +
    TO + Output cube +
    +

    Derivative Direction

    + + + + + + + +
    + Name + + Description +
    DIRECTIONDirection of derivative
    + +
    +

    +Files: + FROM

    +
    + + + + + + + + + + +
    + Type + cube
    + File Mode + input
    + Filter + + *.cub +
    +

    + Description +

    + Use this parameter to select the filename. All bands within the file + will have the derivative applied. +
    + +
    +

    +Files: + TO

    +
    + + + + + + + + + + +
    + Type + cube
    + File Mode + output
    + Pixel Type + real
    +

    + Description +

    + This is the output file. +
    + +
    +

    +Derivative Direction: + DIRECTION

    +
    + + + + + + + + + + +
    + Type + string
    + Default + HORZ
    + Option List: + + + + + + + + + + + +
    + Option + Brief + Description + Exclusions + Inclusions
    HORZHorizontal derivative (2x1) + The horizontal derivative uses a 2x1 kernel. +
    VERTVertical derivative (1x2) + The vertical derivative uses a 1 x 2 kernel. +
    +
    +

    + Description +

    + This chooses the derivative direction. The possibilities + are: HORZ which uses a 2x1 kernel and VERT which uses a 1x2 + kernel. +
    + +
    +

    + Examples +

    +
    +

    + Example 1

    +

    Horizontal

    +

    + Description +

    +
    + Use horizontal derivative option. +
    +

    + Command Line +

    +
    +deriv f=peaks.cub t=deriv.horz d=h + +
    +
    + In this example the derivative direction is horizontal. +
    +
    +

    + GUI Screenshot +

    +
    + + + + +
    + +
    Derivative Gui
    +
    +

    Example Gui

    +
    Screenshot of GUI with parameters filled in to perform a horizontal derivative of the input image.
    +
    +
    +

    + Input Image +

    +
    + + + + +
    + +
    Input image
    +
    +

    Input image for deriv

    +

    + + Parameter Name: + FROM
    +

    +
    This is the input image for the horizontal direction option of deriv. +
    +
    +
    +

    + Output Image +

    +
    + + + + +
    + +
    Output image showing results of the deriv application with direction: horizontal.
    +
    +

    Output image for deriv

    +

    + + Parameter Name: + TO
    +

    +
    This is the output image for the horizontal example of deriv. The horizontal features fade and vertical features are enhanced. +
    +
    +
    +
    +

    + Example 2

    +

    Vertical

    +

    + Description +

    +
    + Use vertical derivative option. +
    +

    + Command Line +

    +
    +deriv f=peaks.cub t=deriv.vert d=v + +
    +
    + In this example the derivative direction is vertical. +
    +
    +

    + GUI Screenshot +

    +
    + + + + +
    + +
    Derivative Gui
    +
    +

    Example Gui

    +
    Screenshot of GUI with parameters filled in to perform a vertical derivative of the input image.
    +
    +
    +

    + Input Image +

    +
    + + + + +
    + +
    Input image
    +
    +

    Input image for deriv

    +

    + + Parameter Name: + FROM
    +

    +
    This is the input image for the vertical direction option of deriv. +
    +
    +
    +

    + Output Image +

    +
    + + + + +
    + +
    Output image showing results of the deriv application with direction: vertical.
    +
    +

    Output image for deriv

    +

    + + Parameter Name: + TO
    +

    +
    This is the output image for the vertical example of deriv. The vertical features fade and horizontal features are enhanced. +
    +
    +
    + +
    +

    + History +

    +

    +All history entries are shown, including those marked hidden +

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    Tracie Sucharski2002-12-24 + Original version +
    Tracie Sucharski2003-01-28 + Fixed application name in xml file, misnamed as gradient. +
    K Teal Thompson2003-04-10 + Added examples. +
    Kim Sides2003-05-13 + Added application test +
    Stuart Sides2003-05-16 + Modified schema location from astogeology... to isis.astrogeology..." +
    Stuart Sides2003-07-29 + Modified filename parameters to be cube parameters where necessary +
    Brendan George2005-11-07 + Modified to handle special pixels +
    Jac Shinaman2007-02-08 + Updated xml documentation with examples +
    +
    + footer will appear here + + + diff --git a/isis/src/base/apps/deriv/work/derivExample.ai b/isis/src/base/apps/deriv/work/derivExample.ai new file mode 100644 index 0000000000000000000000000000000000000000..8b0a14ce25d0e406986e87f0bdcbd984e6b9ed2b --- /dev/null +++ b/isis/src/base/apps/deriv/work/derivExample.ai @@ -0,0 +1,439 @@ +%PDF-1.4 %âãÏÓ +1 0 obj<> endobj 2 0 obj<> endobj 5 0 obj<>/ArtBox[256.0 346.0 356.0 446.0]/MediaBox[0.0 0.0 612.0 792.0]/Thumb 18 0 R/TrimBox[0.0 0.0 612.0 792.0]/Resources<>/ColorSpace<>/ProcSet[/PDF/ImageC]/Properties<>>>/ExtGState<>>>/Type/Page/LastModified(D:20070301174302-06'00')>> endobj 6 0 obj<> endobj 7 0 obj<> endobj 8 0 obj<>stream +%!PS-Adobe-3.0 +%%Creator: Adobe Illustrator(R) 12.0 +%%AI8_CreatorVersion: 12.0.0 +%%For: (Astrogeology, Flagstaff Science Center) (U. S. Geological Survey) +%%Title: (derivExample.jpg) +%%CreationDate: 3/1/2007 5:43 PM +%%BoundingBox: 256 346 356 446 +%%HiResBoundingBox: 256 346 356 446 +%%DocumentProcessColors: Black +%AI5_FileFormat 8.0 +%AI12_BuildNumber: 198 +%AI3_ColorUsage: Color +%AI7_ImageSettings: 0 +%%CMYKCustomColor: 1 1 1 1 ([Registration]) +%AI3_TemplateBox: 306.5 395.5 306.5 395.5 +%AI3_TileBox: 12 12 600 780 +%AI3_DocumentPreview: None +%AI5_ArtSize: 612 792 +%AI5_RulerUnits: 2 +%AI9_ColorModel: 2 +%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 +%AI5_TargetResolution: 800 +%AI5_NumLayers: 1 +%AI9_OpenToView: -293 837 1 1215 899 26 0 0 -1221 167 0 0 1 1 1 0 1 +%AI5_OpenViewLayers: 7 +%%PageOrigin:0 0 +%AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 +%AI9_Flatten: 1 +%AI12_CMSettings: 00.MS +%%EndComments + +endstream endobj 9 0 obj<>stream +%%BoundingBox: 256 346 356 446 +%%HiResBoundingBox: 256 346 356 446 +%AI7_Thumbnail: 128 128 8 +%%BeginData: 11022 Hex Bytes +%0000330000660000990000CC0033000033330033660033990033CC0033FF +%0066000066330066660066990066CC0066FF009900009933009966009999 +%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 +%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 +%3333663333993333CC3333FF3366003366333366663366993366CC3366FF +%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 +%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 +%6600666600996600CC6600FF6633006633336633666633996633CC6633FF +%6666006666336666666666996666CC6666FF669900669933669966669999 +%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 +%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF +%9933009933339933669933999933CC9933FF996600996633996666996699 +%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 +%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF +%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 +%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 +%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF +%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC +%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 +%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 +%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 +%000011111111220000002200000022222222440000004400000044444444 +%550000005500000055555555770000007700000077777777880000008800 +%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB +%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF +%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF +%524C455259FD3D7D52FD3F7D5252FD3DA87D7D7DFD3DA87D7D7DA8FD3DFF +%A8A8A8FD3DFF7D52A8FD04FFA8FD37FFA8A87DA8FD3CFF7D7D7DA8FD3DFF +%A8A8A8FD3CFFA97D7DA8FD3CFFA8A884AFFD3CFFA87D7DA8FD3DFF84A8A8 +%FD3CFFA87D52A8FD06FFA8FD35FFA8A87DFD3DFFA87D7DA8FD3DFFA8A8A8 +%FD3CFFA87D59A8FD3CFFA8A87DFD3DFFA87D7DA8FD3DFFA8A8A8FD3CFFA8 +%7D7DA8FD3CFFA8A87DA8FD14FFA8FD0FFFA8FD17FF847D7DA8FD3DFFA8A8 +%A8FD3CFFA97D7DA8FD3CFFA8A87EA9FD28FFAFFD13FFA87D7DA8FD3DFF84 +%A8A8FD3CFFA87D53A8FD16FFA8FD07FFA8FFFFFFA8FD19FFA8A87DFD13FF +%A8FD13FFA8FD07FFA8FD0DFFA87D7DA8FD1CFFA87DFD1FFFA8A8A8FD15FF +%A8AFA8A8A8FFFD07A8FFA8FD18FFA87D59A8FD1CFF7D52A8FD1DFFA8A87D +%FD15FFA87E7D7D527D537D527D527D527D7DA8A8FD05FFA8FD11FFA87D7D +%A8FD1BFFA85227A8A8FD1DFFA8A8A8FD15FFA8A97D5227272752527D527D +%52522752527DA8FD14FFA87D7DA8FD14FFA8FD06FFA8272753A8FD1CFFA8 +%A87DA8FD10FFA8FFFFFFA8FFFFA85227F852A8FFA8FFA8FFA87D2827F852 +%7DFFFFFFA8FD0FFF847D7DA8FD1BFF7D2727527DFD1DFFA8A8A8FD17FFA8 +%A8272752FD07FFA8A82727277DA8FD12FFA97D7DA8FD18FFAFFFA87DF827 +%277DFD1CFFA8A87EA9FD18FF7D52F852A8FD07FFA87DF827277DFD12FFA8 +%7D7DA8FD1AFFA85227272752FD1DFF84A8A8FD17FFA8A8272752A9FD08FF +%7D52272752A8FD11FFA87D53A8FD1AFF27522727F85284FD05FFA8FD15FF +%A8A87DFD19FF7D27F852A8FD08FFA85227F85252FD11FFA87D7DA8FD19FF +%A852527D272727A8FD1CFFA8A8A8FD17FFA8A8272752FD09FFA8A8272727 +%7DFD11FFA87D59A8FD19FF7D27A8A852F82752A8AFFD19FFA8A87DFD19FF +%7D27F852A8FD08FFA87D27F85252FD11FFA87D7DA8FD19FF5259A8FF7D27 +%F87DA8FD1BFFA8A8A8FD17FFA8A8272752FD09FFA87D2727527DA8FD10FF +%A87D7DA8FD14FFA8FFFFFFA8527DFFA8A82727277DA8FD19FFA8A87DA8FD +%18FF7D27F852A8FFFFFFA8FD04FFA82727F87DA8FFA8FD0FFF847D7DA8FD +%17FFA87D52FD04FF7D272752FD1BFFA8A8A8FD17FFA8A8272752FD09FF52 +%2727527DFD12FFA97D7DA8FD17FFA8527DFD04FF5252F8277DFD19FFA8A8 +%7EA9FD18FF7D52F8527DFFA8FFA8FFA8A87D52F8527DA8FD12FFA87D7DA8 +%FD17FF7D277DFD04FFA85227217DFD1AFF84A8A8FD17FFA8A82727275252 +%7D7D7D5252272727527DFD14FFA87D53A8FD16FFA85327A8FD04FFA87DF8 +%2752FD19FFA8A87DFD19FF7D27F827275227522727F827F82852A8FD14FF +%A87D7DA8FD16FFA8527DFD06FFA8272052A8FD19FFA8A8A8FD17FFA8A827 +%2752A8FD04FFA8A87D522727527DA8FD12FFA87D59A8FD16FF7D527DFD06 +%FFA8282727A8A8FD17FFA8A87DFD19FF7D27F852A8FD05FFA8A87D52F827 +%277D7DFD11FFA87D7DA8FD15FFA87D27FD047DA87D7E7D52272752A8FD18 +%FFA8A8A8FD17FFA8A8272752FD09FFA87D27272752A8FD10FFA87D7DA8FD +%14FFA8A852272728272727522752FD04277DFD17FFA8A87DA8FD18FF7D27 +%F852A8FFFFFFA8FD05FF8452F82727A8FD10FF847D7DA8FD15FF52527DA8 +%7DA87DA87DA87D7D5227277DFD18FFA8A8A8FD17FFA8A8272752FD0BFF52 +%2727277DFD10FFA97D7DA8FD14FFA82752FD09FFA87D272727A8FD16FFA8 +%A87EA9FD18FF7D52F852A8FD09FFA87D27272152A8FD0FFFA87D7DA8FD14 +%FFA8277DFD0AFFA85227527DFD17FF84A8A8FD17FFA8A8272752A9FD0AFF +%7D27272752FD10FFA87D53A8FD14FF52527DFFFFFFA8FD07FF5227F87DA8 +%FD15FFA8A87DFD19FF7D27F852A8FD09FFA87D2727277DFD10FFA87D7DA8 +%FD13FFA8527DFD0CFF7D272752A8FD16FFA8A8A8FD17FFA8A8272752FD0B +%FF522727277DFD10FFA87D59A8FD12FFA87D27A8A8FD0BFF7D27F85252FD +%15FFA8A87DFD19FF7D27F852A8FD08FFA87D52F82727FD11FFA87D7DA8FD +%12FFA85252FD0EFF274B2752A8FD15FFA8A8A8FD17FFA8A8272752FD09FF +%7D52F82752A8FD11FFA87D7DA8FD0CFFA8FFFFFFA8FF522728FD0DFFA852 +%2727277DA8FFFFFFA8FFFFFFA8FD0BFFA8A87DA8FD17FFA85227F8527DFD +%04A8FFA8A87D52F827527DA8FD11FF847D7DA8FD11FF7D522052A8FD0CFF +%A8FD042752A8A8FD13FFA8A8A8FD17FF7D7D2727277D7D7E7DA87D7D5252 +%272752A8A8FD12FFA97D7DA8FD0FFFA97D525252287D7DA8FD08FFA87DFD +%07527DA8FD11FFA8A87EA9FD10FFAFFFFFFFA8A87D59FD0D527D7DA8A8FF +%FFFFA8FD0FFFA87D7DA8FD11FFA8FFFFFFA8FD0BFFA8FD07FFA8FD13FF84 +%A8A8FD15FFA8FFA8FD05FFA8FFFFFFA8FD1AFFA87D53A8FD16FFA8FD07FF +%A8FD07FFA8FFFFFFA8FD11FFA8A87DFD13FFA8FFFFFFA8FD0BFFA8FD19FF +%A87D7DA8FD3DFFA8A8A8FD3CFFA87D59A8FD3CFFA8A87DFD1BFFA8FD21FF +%A87D7DA8FD3DFFA8A8A8FD3CFFA87D7DA8FD3CFFA8A87DA8FD3CFF847D7D +%A8FD3DFFA8A8A8FD3CFFA97D7DA8FD3CFFA8A87EA9FD3CFFA87D7DA8FD3D +%FF84A8A8FD3CFFA87D53A8FD3CFFA8A87DFD3DFFA87D7DA8FD3DFFA8A8A8 +%FD3CFFA87D59A8FD3CFFA8A87DFD3DFFA87D7DA8FD3DFFA8A8A8FD3CFFA8 +%7D7DA8FD3CFFA8A87DA8FD3CFF847D7DA8FD3DFFA8A8A8FD3CFFA97D7DA8 +%FD3CFFA8A8A8FD3DFFA87D7DA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF +%A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF +%A8FFA8FFA8FFA8FFA8FFA8FFA8A87DA8A8FFA8FFA8FFA8FFA8FFA8FFA8FF +%A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF +%A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFAFA853527DA8A87DA87DA87DA87D +%A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87D +%A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87D7D52A8A8A87DA87D +%A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87D +%A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87D527D7DA8 +%84FD3BA87D7D7DFD3DA85252FD04A8FFA8AFA8FFA8A9A8FFA8A9A8FFA8A9 +%A8FFA8A9A8FFA8A9A8FFA8A9A8FFA8A9A8FFA8A9A8FFA8A9A8FFA8A9A8FF +%A8A9A8FFA8A9A8FFA8A9A8FFA87E7DFD04A8FFA8A9A8FFA8A9A8FFA8A9A8 +%FFA8A9A8FFA8A9A8FFA8A9A8FFA8A9A8FFA8A9A8FFA8A9A8FFA8A9A8FFA8 +%A9A8FFA8A9A8FFA8A9A8FFA8AFA8FF7D7D7DA8FD3DFFA8A8A8FD3CFFA97D +%59A8FD08FFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8 +%FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8A87D +%A8FD08FFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FF +%FFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFF847D7DA8 +%FD3DFFA8A8A8FD3CFFA97D7DA8FD3CFFA8A87DA8FD3CFFA87D7DA8FD3DFF +%84A8A8FD3CFFA87D53A8FD3CFFA8A87DFD3DFFA87D7DA8FD3DFFA8A8A8FD +%3CFFA87D59A8FD26FFAFFD15FFA8A87DFD3DFFA87D7DA8FD3DFFA8A8A8FD +%3CFFA87D7DA8FD1CFFA8FFFFFFA8FFFFFFA8FD17FFA8A87DA8FD10FFA8FD +%0FFFA8FD0BFFA8FD0FFF847D7DA8FD3DFFA8A8A8FD3CFFA97D7DA8FD3CFF +%A8A87EA9FD3CFFA87D7DA8FD3DFF84A8A8FD3CFFA87D53A8FD1AFFA8A87D +%7D7DA8A8FD05FFA8FD15FFA8A87DFD15FFA8A8A8FFA8FFA8FFA8FFA8FFA8 +%FFA8FD07FFA8FD11FFA87D7DA8FD17FFA8A8527D527D527D527D52A8A8A8 +%7DA8FD16FFA8A8A8FD15FFA8A87D7D527D527D527D7D7D537D7D7D7EA8A9 +%FD14FFA87D59A8FD16FFA87D522727527DA87D7D5227277D525252FD15FF +%A8A87DFD15FFA8A87D7D2727F8FD04275228522727275252A8A8FD13FFA8 +%7D7DA8FD15FFA87D27277DFD07FFA87D2727527DFD16FFA8A8A8FD17FFA8 +%7D272727A8A8FFA8FFA8A87D7D2727277D7EFD12FFA87D7DA8FD10FFA8FF +%FFFF7D52F8527DFD09FFA87D272752FD15FFA8A87DA8FD14FFA8FFFFA87D +%27F852A8FD07FFA87D2727F85252FD11FF847D7DA8FD13FFA87D27277DFD +%0BFFA87D277DFD16FFA8A8A8FD17FFA8A8272752FD09FFA8A8272727527D +%FD10FFA97D7DA8FD12FFA8A8272727A8FD0CFF7D5252FD15FFA8A87EA9FD +%18FF7D52F852A8FFFFFFA8FD05FFA87D2727F852A8FD0FFFA87D7DA8FD12 +%FFA85227F87DFD0EFF5252FD16FF84A8A8FD17FFA8A8272752A9FD0AFFA8 +%52272727A8A8FD0EFFA87D53A8FD0EFFA8FFFFFF592720277DFD0BFFA8FF +%FF7D27FD15FFA8A87DFD13FFA8FD05FF7D27F852A8FD0BFF5352F82727A8 +%FD0EFFA87D7DA8FD11FFA87D272752A8FD0EFF847DFD16FFA8A8A8FD17FF +%A9A8272752FD0CFFA8522727277DFD0EFFA87D59A8FD11FF7D2727277DA8 +%FD0FFFA8FD15FFA8A87DFD19FF7D27F852A8FD0CFF7D2727F852A8FD0DFF +%A87D7DA8FD11FF5252F8277DA9FD26FFA8A8A8FD17FFA8A8272752FD0DFF +%7D52272752A8FD0DFFA87D7DA8FD10FFA852272727A8A8FD05FFA8FD1FFF +%A8A87DA8FD14FFA8FFFFAF7D52F852A8FD07FFA8FD04FFA85227F8527DFD +%0DFF847D7DA8FD11FF27272752A8FD27FFA8A8A8FD17FFA8A8272752FD0D +%FFA87D272727A8FD0DFFA97D7DA8FD10FFA852272727A8A8FD25FFA8A87E +%A9FD18FF7D52F852A8FD0CFFA85327F8277DFD0DFFA87D7DA8FD10FFA827 +%272752A8FD27FF84A8A8FD17FFA8A8272752AFFD0CFFA87D272727A8FD0D +%FFA87D53A8FD0AFFA8FD05FF7DFD0427A8A8FD17FFA8FD0DFFA8A87DFD19 +%FF7D27F852A8FD09FFA8FFFFA85227F8277DFD0DFFA87D7DA8FD10FFA827 +%522752A8FD27FFA8A8A8FD17FFA8A8272752FD0DFFA87D272727A8FD0DFF +%A87D59A8FD10FFA8FD0427A8A8FD25FFA8A87DFD19FF7D27F852A8FD0CFF +%A85227F8277DFD0DFFA87D7DA8FD11FF522721527DFD27FFA8A8A8FD17FF +%A8A8272752FD0DFF7D52272752A9FD0DFFA87D7DA8FD10FFA8522727277D +%A8FD09FFA8FD1BFFA8A87DA8FD18FF7D27F852A8FD07FFA8FD04FF7E2727 +%F852A8FD0DFF847D7DA8FD11FF7D52205252A8FD26FFA8A8A8FD17FFA8A8 +%272752FD0DFF7D2727527DFD0EFFA97D7DA8FD11FFA8522727527DFD11FF +%A8FD13FFA8A87EA9FD18FF7D52F852A8FD0BFF7D52F82728A8FD0EFFA87D +%7DA8FD11FFA87D2727277DFD0EFFA8A8A8FD15FF84A8A8FD17FFA8A82727 +%52A9FD0BFF7D2727277DA8FD0EFFA87D53A8FD12FFA87D272727A8FFFFA8 +%FFFFFFA8FFFFFFA8FFA87D52A9FD06FFA8FD0DFFA8A87DFD13FFA8FD05FF +%7D27F852A8FFA8FFFFFFA8FFFFFFA87D2727F853A8FD0FFFA87D7DA8FD13 +%FFA85227277DFD0CFFA87DA8FD16FFA8A8A8FD17FFA8A8272752FD0BFF52 +%2727527DFD10FFA87D59A8FD14FF7D27F85252A8A8FD07FFA8A8527EAFFD +%15FFA8A87DFD19FF7D27F852A8FD07FFA87D272727527DFD11FFA87D7DA8 +%FD15FF7D52F82728A8A8FD05FFA87D277DFD18FFA8A8A8FD17FFA87D2727 +%27A8A8FD04FFA87D7D2727277DA8FD12FFA87D7DA8FD14FFA8A87D522727 +%5252527D7D7D527D527DA8FFFFFFA8FD13FFA8A87DA8FD14FFA8A9A87D2E +%27F827527D537D7D7D52522752527DA8FD13FF847D7DA8FD17FF7D7D2727 +%202727522752277DFD1AFFA8A8A8FD15FFA8A85252275227522727275227 +%52277D7DA8FD15FFA97D7DA8FD18FFA8A87D7D527D597D7EFD1BFFA8A87E +%A9FD14FFFD05A8A9FD09A8FFA8FD17FFA87D7DA8FD3DFF84A8A8FD3CFFA8 +%7D53A8FD16FFA8FD0BFFA8FFFFFFA8FFFFFFA8FD11FFA8A87DFD13FFA8FD +%07FFA8FD0BFFA8FD15FFA87D7DA8FD3DFFA8A8A8FD3CFFA87D59A8FD3CFF +%A8A87DFD3DFFA87D7DA8FD3DFFA8A8A8FD3CFFA87D7DA8FD3CFFA8A87DA8 +%FD3CFF847D7DA8FD3DFFA8A8A8FD3CFFA97D7DA8FD3CFFA8A87EA9FD3CFF +%A87D7DA8FD3DFF84A8A8FD3CFFA87D53A8FD3CFFA8A87DFD3DFFA87D7DA8 +%FD3DFFA8A8A8FD3CFFA87D59A8FD3CFFA8A87DFD3DFFA87D7DA8FD3DFFA8 +%A8A8FD3CFFA87D7DA8FD04FFA8FD37FFA8A87DA8FD3CFF847D7DA8FD3DFF +%A8A8A8FD3CFFA87D7DA8FD3CFFA8A8A8FD3DFFA87D7D7DFD3DA87DFD3FA8 +%52277D7D7D537D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D52 +%7D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D +%7D527D5252527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D52 +%7D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D +%7D527D7D7D527D5252 +%%EndData + +endstream endobj 10 0 obj<>stream +%AI12_CompressedDataxœí½ tkÉuøÓR«» -©µ$–- À @àa! î$Vîwòs±<’ A|~÷wŽìÌ8–ºw¤±b{ìDYìä$';“Å>GîU±ä3'¶Ç¶<Çž9ãÈqbå$vlIm©ÿÿ\‘ªzûCÕ{õüq'Çl}x¯Þ½U·î½uï­ºïvÚ+½“Ùbšíõ»«åvgg˜cS•"7dE—­Óù|µ\áà%û²Ãêõ¹Øjr:˜Z®³\9W, ¡{üÝ|Þ> ž+²Å|ñðžË˧Ë•ÔÁu%“c Öf –sXíknëŠÛG-s™TÞºRåî²÷Ôj®’g°,ËåîF_L–ò¬û¸tèú +pGRÐÆïñz| 3`í +ø­‰yØ"T¬²¹Âa¨øâÕ××oõÀ?ðÿ@?¼?•[fËF"ÅLõt6Á3l¹ýäÊCÖP>•9÷'§û’±\ž£>MU¬ADƒÉi¯/ªæòÙ…êišôðÑuX+§A§Ñwt} 9} +.­°• +è €Hžßš ƒ(ž¢–ŒðŸ}{™=Ì¡©Øu°WY@!@4?Óïî³úûà§ü]l +úŒšy}ðý c2ÂMyÌìÝûÂu¡X`…ÁNr••Ü‚Î÷ƒÇ}ÂååjžåÖ +¹ +è;mê|1ËæÅkèqÄ `„è?¯ü)´XMq‡lÌL1_­ Þ +2â=@ιÔ=N€W@²Xb «ÅuÔÍ^ß ßô@ù¼}Öàà Õ×0ôz}>pµ@ÀçE8½\‚@ê'À„,r¹Ã\aHìÝ@2Îå²ò, ø¬AþÀTüÿ îTØ‚ØsÀ!áyÅ|3îùˆ5ZȆ‹§úeÄÃ`ž €÷€twåèQ- Ã@’`²\®[n/ð÷‚ÉD¾ +nƹbµ4]8(ZnÛyO¤*G€›ÙB¶ ¤‘¿Æÿ´ò€«s¹»âEw*Wr€\åR€Üº˜>f3ð¼pAþ¶RÍUXP H3®°Xà»ÉUËGÖÕb1/uUh Ü’z ØŒæ=ƒDjŒCn¾w‡Sù|îK•Žr|Ì} áY´+DuFõ- Yýï <йXŬˆñeÊOKpù±®¥Jð2lS´¤é„=kbnÑÕhá.›/–Xùºt%n¤¸qù\ùT¦‰âŠôМ¢;è'øÿøÿTRšORœÝzƒ4S"´F[¡k2ؾ$МJÍØÛk¨3ù{pÁ«Ü˳@{f Å +è—utlÐ>UÍWvVÏBꔵº@›•4S¤FŒu~ðÿÀ¯Ëâo¯u~õ +77ïÁ_3àÛ1¸ö‚5`·nï2Ö¬ÜÁ%k3 0ðã¶Ü¶z@àÔ[0BE_HåÁòÃò½I¤y8ëö­ ‡«5:ð/$ã’ š£ìª¢fý€ø& N¤—áoòì +Aݯ`Ú«$ B§EÛ˜)p=é/ÀɆ?sHžw¿ÀX=ÓঠóZ¥¶hÕ¶Î¥ +‡U`eXÅdj|ÀL1Ï2 ,aðÌ u±Z)U+ÖåT¨œÜ"Ú[eëHxÈÛ§zhžŠÉè©cƒÖWIS\Öš&›Ð@ ÝÆ·(ÅY˹Ój>¥R7Ü>*$Âö-[ʹeä<ìr©XÑâK•¢½vš*Ÿˆê‡ZJe³ÂÅaØMëdµR”ÆÍ +·ìÛól6W=U +ìJ…ƒF +vb[ Œ˜Àe¶b…Ò-ys~nµüxííYáQÈOóТ~ä'ñ î¦òU±Å @)åýʽ’„z’ãR¡5Ý8e+©,`ÉVôÂÛp/\*‡~Lù=Ó“÷FGþÿ¦Ç°Ü*s—ùk)E#Z)V¹ ‹BÑïáÁie¸§0ž.Øêï-)À+È{Æ#‚»ïÅÝÃèˆÍQXÀ^Ùé|O Kì?nl/䲕£ÿ~‡&t7²t±,²9ö Âï?P Rô“ßSC¬Ç{k¥ËÙÿ( uk×¨Ö CQ3* +» è +w—µ®²/V¬Ñl®’Jçò¹Š¨Íúûúü}Ä8•Õkå$[×°é!ÇJ£èó|ArcŸ®aS%\ÃN¤e®2œ®ç@خ¥ +åR +LIæ@žËZËr¬‹Q‘W¤½5W.Â}a’EV½~ë“p"ŠÕ +€^”Â’HŠ‘LÆz EÈ8në½Ëf* ÛéT>UÈÔ©%Í3™|®Æ C/Z†*+ñðêúdr:‘â€Ìøå•jºÌVbÅB¥¼ #³ì=$%‘¹ŠwY®ƒ¹eù 4‚£\æ(Áry\ÕnÜèe9Êà@FOÓl–d"ƒPÁÐTÀ¦'Ÿ+°VxÌâD8£Ö f’l*gŠ\–Íb$ÛêY(VÔ÷U!fÀ.ÑÄŠ5Î¥²9È2pO‰:kÃ̪p¶×gœ¶ÎÁ®À]Iø’|ƒ§xd©ûˆQtQ-Õ¢@¯U™^r¸\lCâ*s]%¾E=£Y¬O¬m=¥ÃÓ÷iŠ;)Üüª«ÑÊæ™S7蛓”2PNa‡Ù×Ü+në›¶†‹@«d­;ö•ÅÄŽÃz×–ÓµB.–qUÕ`.ñâ ¡™¦Ñ)x^D¦‘ËrewªPPî"ÔADª…Œ¿# ƒæÅ’[a<àp€ÅR¶jÔ¢l#SÔ¡ hu§Ðb ßD­„q˜Jew¨RÈ""Ò9ȉ¢PâÛäÙ»l^×A¡â.í­•$m›l^1í ‘%ÁÆfëøœ¢½’…±4­3\±dÔAÔit\LÂUNSp¨S5x˜e¸Ë©Ó(Ãeݰ0Hk7Vr@£r&S(ë “oTÊgîé‘¶*r‡î»4ŽôÐå9â Ig h™R‰s##H·k°•ÒÅ2@ ›+ ú° Z©\RxŽÐN‰;í  z×,T˜¼S¬±]ÓÌé=q³Tönê¢ +¹7 ^o +VD¹¬ƒµþ¬ú*ÀºXáí}](4U-h}Ç5=¬“4?ChÊÕ5ÅŽ½ÄÜ`Ü °J5 Æ‹¶íQ*Ër¬ļ7ƒ,A#ýM²A5 ì!°*ïê›W¿%î ([+FAEÒ•óìAEObÕʺ¢TÃFÕ  ŠzUé§K{ØSr1j[J3ê@\±·¯ØÛ,{=3: >4bƒ6ñ/Ø ++‹ØµÄ’u<Ã|ªD± Åzñ’À/A©<+A4l(BÄY<°U©XÎÌl¦ tTä~РY‘ƒ.ƒ À¥Mò-Óð@¸AcQ÷•Š=6„‹ ‚™*ófMÛ¢Á|K ÓÂ.ƒnË,[Î4 ¬²G@ˬ®ló«1e;Õ;ÄË?h—ƒ'æÕV`?AóJ­•6 yéæÛÊ*Ȩ¥Bÿ`íhÐ0ËŸm£“âr%/q©¤·œÂv`¹!lКdye<”â)È=,§Ž:ëö‰@rº§%õ|Äb>Ï"X½¹+ áÑÇI±µzË”ž3‰Õ!¾TÅHt8àäpeÂãtF›–Or%  +ú&’GÀ<À=Är¦˜†`•cƒ‹B‚?ìæYç£o!bôM×XQEêÛ…a|.,Äç–Uñ9šÓt„Þ:å0P „vª¨ y¨YSc@ô†àUŽ,å£5W@‘M¸±”¬‰ã$HÈD$–CäŠ\,' §J|´<'íᢋömXkò‰·¶EÔóÅB1sÄOÙHñ…t »#‚ˆs©{:õÁG×Ê,¨U•û¬Ûa9ØŒbÍt:RÄ'œ’¾· Ù×ÌÇZ‘ãøØÈŽ¹À;‘ü‰bp›Ïjƒvìj¢˜ÏI1‚ câ@²qÿõ6¨9a6WÐ[!Å1GØ2ÔWÕ8 £ä1… ÒD™tä 8!ÙÁèò3 y(ùo2]¼k0< õÀеzT=MR¹¼ž1'>ÓµÁ¦a’›³">±ÊåNçó¶¡4Çô‘@ÃÉ”B£˜ j«DÍÑáb!käÈZ™&p|«òN®}õ([+ÌS©±VÁŒ±–…,=ë GlÁZNÝ…I”é±V(EÖT^ÒU"1iGÍm:‚Ÿj`÷ŠUk ®ÈË«u„šw˜‹IN…ÈeȤG €A­•"‘a­9´ø¤¬ùÔ=¸{—*•§óòY®fŽ`÷¦ dÙË`xlÀUлâŒ>W¶V '0ãÅM=‡.WRLAcó74Ëä$K ]§ry1°ºLr•ŠÜÉœl2«b#O¡Iô8G U%BÓ·<ôiÄ 0¯7Á}ÞYÐ7ÃEÒ +£„~gY«üÌ‘uY>7P›sú!ãýI½A­TR…lŠ“q±¢I„ѳV9 EºÁ~­6™áŠéT…Ï$¦`C¸œá¹0@eQáŸÕ£ž°æO2@«˜_•|`J¾ë,j”«’'îó #Œi`jQÕjƒ¥jJa'ë=)móÒ¬Â<ǯ*ŽpP`à*'9”úD@#Ñ¡‚9©_ÕÝ&/­NÔð»šÎæú¦2Í( Nü™ }¿CCMZåÁ«@ùi9:¬Gœ‡d,θ*ž¶ÚA~¹K^›t³ÞUd’jÒ!2>ÿžUoZn£^(/Aÿvr%<=ì‹°P/ Èα¾ÈI`|qŒÉv­L ŸcƒSÇò (èößé?½3Ò»+lø™¬â±©$渱T!ž_?N‡öç—&']ïîð¸w=iÏV£M$<µ³ëí™(ôÙÂŽ¥@Ùß±ä_O{sÞYö¯VB‘ƒÁøÉTûòh*rÀlIw}ÎÑåþ#[wiõÌæ::ž²93îN›+™Ý¶¹|±›}ª G¯l¹ýsƒ6çØh©S@sTñ•#%Ðé™S¡Ó©åðmfÆí)÷o+¥º&`„å`¬°ê³nu4€T^4E¹oÜNù0P«Î±¸­+Pö•çE¸Á¸c¸ýüŒçÁ³[qèseŽ.ßáv‡‹Œ'°bGEX!qÜ»Ø<šsa±î†¦ˆXû}Ç kšÛó87 5bëBÈѾVÊÏá°–Û÷úC$¬ScK…u V„!86ÙÅyV®º?dïé±íã°21f|„€µ¿½#8|0È34f¸­&¶ZÂŽµ-Vê\ÌÍ/c±ÆÛ‹s¬¢Ü ÄÝ3sy‘׸ŒobuÔQ8Þ¶áïì«tƒÇźyê€, Ntwk¦6°:Ï#¬@ªÒQ5Ö]nw=½LÀ:”ì[Ëzd¬ñ^ïêë€ç`¥uÄæàÊCÎ2kb`¢ظn¸åî±-/kß‘£;ÄÆñXŽ]çÈð©b¬rjS}ígýÕyV&6»"`íoïì ö°n%!CÇŠ««Øá¶Å;F»æØ£5,ÖøRpDá©®^›ûˆÇÝ9‰ANS¹ÍQîžp!"÷ÔaJžöõ”€u ¤Å:7½°+`ÝêµkÆ +Ð ô¹ÝwdĪáÞ 1s§Kx¬ÓmÕàÜV&ˆÅº˜g§d¬pnÔˆgÝg%ë¶“Y™;«â±Îú÷æb±q+œ›ÕéÜ4q¸+óý«û$¬fÙÄcëm_Í&{†V€F;Üõ½Ñ2ëºM–HXç™Þñ+@GA.Œ%ò×êëqÛê\ˆ€u§ŸÙMí;VÄišá.¬åN†:\X¬{{›I"Ö";n?Äah âyf?:Á9¶æmÛ¬,Mã°rÜBo»€5íwh„Ç9Øõ#¬7ÕV‰«5ÔWõ‡ˆÕU‡uqÔ~¶ÝœXG9 VçPqË%`=쑱B wl·ñË»/´åVëŠe&º°‡X{ëWÙ…ÞŽ‚8°†+Z +G£Çn„Í=êÒèÅî¬SÐPþŽ¡ð¬Z/²ÎÑàÂ6Äê©ÇÚßÙ6º55°ÎØd¬ 2³|¡Å#~¸ãCKn ‘‹£ÑëøÚÜœšÂ`rŠh•–U"¬¼ë«œÚ|C…´hrÔ7¨vÙüÙÓþnÀ„g¬%ÝåGÌçä»ÕØJ0Ñ‘Å(ß Î>¸3ÊÌMø}èn½¾¿3ÎÌ-pwy†¾3ÉÌegûI‡™yÛFt7Ê,f¦—Iw“ÌJø¤"­¾Á¶‹YYo·‘Չy;én³f;sËwµë᪶¡A½ÖšbÖ×l£ü]­¸¶g˜õÃÞqÜ]žhÛsÌFÇà$éñf£?&ÝM0wÚvIw™ÝÍ;=Ñêì 0»Ç.ÒÝAfomØOº;Á$û“ƒò]-§%9¯»g¶ðxÊîÜ÷Íî¦Û½¡®½™héïìRÛ áñLÑ»pâËîfÞ­ãÙ.üݾ½ÂêðHå‘h¾rÂÖí˜Y@w}Ýcö)õÝI›{jbŒ¿«Õ‚¾JÞ6˜9–ïB¢…{{–•>š=»ê Ë ¼ä=¸€kj¨à>6„sOtÜÛ9á©t‡c«ã[‘;±­ÕÈ舠—™X8ä΄Ã!ϬSéâíwæaü¡&ÂzCè–+êâ?’zqÄ%Hõª>Õ!‰ú ‘ûaÂf‡ÀÐ 2pyˆÂ£Ðnk²v#Î v[/Òj7Šà=„Ö¬v“}O­Ú­|âo…€ûú (¥zN«?PшvƒPºD½·f›¶;:»¸‡èþ{ŽŠÎQ‘—ðö*Ü çÍ©·­¤Øô`má™ 2Ð#ꩪÃË4“a¼•7¦±úHiª›ëú{ÂD‹=/ ™¶ùɃ§)È»¸´g«Dáqóùz‚ gN>3Õ zY i߇Br÷4¡!c@¹Ýê` +D{¬I_yP’0ÒžOÓ]Smq§vqLµÍ)|u¸Ûìú¸A{°I×)„^Xk‚_ÂkdÓ@uæ–b}=Ù®PË’v€ñ6$aßÈ^«Šš²d’¶ð€#ø·$È ¡…\³ÐÈy’£2‚UL£C´þÖ8 `6×{̓#¨éMݘ7ÏòñQªnQ²E‰±NÍJå mnõjVªºÃ&–)퉮Í-½•ŠæhÜ¢ªcG6*YÎðüvc§†ŽöBhTK fïG#Bk/‡¶Úº¨âÐØ…ºÙ4<é«Úa'ˆ}º¬wÒWÉÄ>)b¨[ä€2õ±Xyc<±dÁñæwÌâQ<¿žJ¢—ÅÄ;&öb«c‰(.O?—¯Îl4O™‰TŸË'ÛÐM¦óéçòñ[ß-HçÓÏ哺Ét>§n.ŸEJ]l2€UÈåS¨ÎæÒùôsù,rêbsé|d¬0—ÏBL]4™Î§ŸË§aÆÓùôsù,RNa“é|ú¹|B0¥ùt>ý\>åž´ÝÐÙÜŽàÑèyuB&îä}¢ëLÿ uŸ¤ ÑaFU®¢: E:ܪ´¡I»ÛµmlL*q¢ÛÖR©RØ3P´¤Ò,þõçØT™ô¢|J ê 5Wá@¡õFŸG©G¨“Á'[6ªA»e˜Ì€ïS]ø!R·dHxbŸ(]:¤R«ªä½ú3Pt|»5u¾„à‚î/ýrSçK¢(ÖL ¦7ïEõÝ^Ù“6ÈQÛi7vÔÈyþÀ%L»£;bbvG +3›ô;ê M@Ê¢ÈÅR11Ü­„Áœ/Q8TŽŠš:B×ç<4M*EÚWÔXš 3ŽÝi5tÚWÕŸê¤×T[²M:AL»›M89ÓO§D{k&b0ré3hSMk„v°KQ‰CÚD)l šM¯l\g©Så£&£+­Ì)Ü«ê¯P39…F6Y2Æ¥ê“úä}÷(KL¡0³U9rº'ï—19£ä-£“÷¦r +ÉwÚ9Ï  ÀgÓÐ$Pn (œ-@¼ÿ®%§+è@3Hø1I4o눦Í2hŽhþ&‰¦Žó/¼T£:œ22äUö$Ôë{Ê8•X{ü= )‹†‘îABî¥IÄ<œjÚ” ¨Ê¸¡œ‹v5!—k¼KŠrÀ+«%èL7‰&h‘6Jê5œ%ÍÆ +v½‘lb²¡Ü’£. Š§ëöðûžF{§pH3Q­y©ö=ÇíNcaúvˇ®(™¡Ázj*ÀÑ@¢žìx¨}ZrZ],ˆÆN;žnìC:uQØit¤ÂÅ‚4¬*hCR™‹‘]¤4=rHB§OuÑ¥SHÍž|ŸÌDo,úÉ~¦¢7:}²çâêJ½­h£70-ÊðØ5]ôæt†"zcx Îß1dïh:z#DÕgZvXðt¦‡“Ààvó +íûéLóÑ8ñšèrcÅT>œÁ–º&z#n}«Ef¦Ñ˜((.«ú‡Èóà!(²ƒôiµ!í©7¤K³ú©±²h‹AH’!=ÛükÏÆ‡–: ÀÐú!þñµr2«U§Í6øÚ35Cƒñ9Z‘ÆVw¢n½¡Kñ3ûÚ3ÌÞJñkAJf§âKÃGg)XÚ‰±NMž9rj(ÆR|NŒÜB…Ù­Ý“× 8‚nåÛ\±´ä½ƒ†™y¼²¡=¶×pfn@kuf^ã‡aMeæé†mafÝÙÁ¦3ó,Ô©‹Meæ)uš"9¯Õ™yÊ]« æ‰`äQ›™§r£Lç‰PgæYnc“ó´sÓlfžÌÐRòLÎ3™g°lQæ­5½ÊÀõ;j‹2oúè%€fã«¡!â4›7 4ò–‰Ä³ºM/ý|©5ú—Æ€¨^¿a°YŒ©½ìFÇ…·ð-æÊÖ|¿*Þñë¿à˜"A#Œ|¸{¬G+Ѱ> ét€™@¨<>Ú`~—Aˆ¸G@uºûŒJ‚H¯Á±h3½Ìù”ØyÅ•hÀT‡ù‹-yÕ1Ôœ<ŠPa4:Ým ˆÊã¶è¿¢7ü‰V¿ lÖëÞ‰cô¢,½ó`„š—EÈ[£õ¼uÝn˜µŒMœ0©Ó6Zš$»Ñº$Ù%É&IÖÛÖÛš$Y¨I²JK’d! –$ÉÂL:º]ãÓèÔ“&{áØíUãÓPZyLruá5I-¤×·ÓÉ#mRžfY#æ 5™”§ ©ÂLºÇ‘”G$Zk“òè6$›NÊSùžõÇSZ•”§Dcê¥üæ’òäCzFccIy +‹‘wq‰Fcº¬ãÁ™xû½°Hoi_—Ü\Šß‰ö¥Žõ[x”g¶ ´3ýý#EÔYŠªÏZ…¡£³l¶´¯Pnpg‚Ï¥«ßRS¨Þ< u»Gg $¬Ä㣰[šWš›KñÖ +UF~½†ƒPYiݾÜ1+­¯Ø€5gë ö&m=³Ã^›+²¼as­ï­ÀZë«¶žÕÉ~ø-Û…m½³É>äFmž ëÓhñDÙiq¯Fvg×I»Kx%™Åì7‹P­´ÜÝQT–‰U§ÝÙÓË'„8ÇŽ^ ½½^- I» õ/°ö·«r³´iw{úÉ~q[n¸Bíè8·%aÕf„é³±íj2½4©hKË +¬š´»áüÚkßQÏÄFO‰˜ìØÚÒK»;dˆX™Øî9Ù¯óijž¶“ýR:XãÌ+W>œi×`µ(“ýl;íýk$"»ôÆ:Ý¥™W(·½?ú&±@p¡šÕo*´[lgiÚµ-ŽÚ4. M¹jòD™áG]g¢Š žuÙ5 ¬ÁÛàŒÏ÷jŒÛDשöp¾:+„TLä)ƒTš‹…¢¦×„þ»¨iúćT»¸Ö¤¬ßì£8ÑÕªòz¸X”…MdX^rúºÛLžèÒ©gXmE{v°ÉÊzJR©@©|OŠÊzÔ#T¿ïY{ò“ 3Bí‘tbŸ„ª^· mRô‰WFEõèI5ØÁõÉ"ÞÄ­m ±×E‹"I¶E‰}$¢µ8±g§ZÈÕJMìà NÜŠP0j³‰}¸¬>ò¾gÉ}æ1NìSL•¥n*ÜOìÃù&J†nQbŸñ±ë–$öéÖ&öQ…»›OìÃeõñ£iibŸÞ©¡&öÕóP6nÑÍao(±·œX¤w?´,±§gñÛ«M%ö©ú$dõ)Cª-JìÃeõ ©$­LìÃÍ¡&@ÜŠÄ>\VŸÈÐM@3´¢¨7‹M%öÑä{¶ ±—Õ×¢”2I4êÄ>ÑZ؇ۅ‚V&öáðq–&öá„\RmUb.«Ï¢ó  ƒÄ>²iEb.«O‡nEb.«O­Z’؇Ëÿ±^›C¤ˆ9Qû²FõOìÓôIô±»¸´>âP¹.}ÈÁÚšC}”9}¤2žÄ4'¼É1mTËS3äòoB ?¼ÉÑT?\Á6 m­ã*~zÉsʽµi£ªžÔ¤:Ò®èz:MpÆ{}Ò;×IQÀ¶O‘ýr½´¤"KµlªS’ʰL/¶OeºÕ߀þT¿Åß1xâ‘ý%‹˜…§q™êÏ6ф͈Åÿ̵j¸ø.ÿ¦¾þŸ©SªÁ ÅÿšŠrÐÿÒ êÿ5¸á‹ÿ5šªø¯: ó›-þgå© ëÿQ¾¦—\ü¯Ž¡©Î:š.þg1ñn;°L´7ÈÊõf¶e9¥YMr“Ƹ5•n?´ÔŠl¢YªóF9˜6t·ÉÓÝpâiNPC4F9}MŸü/ÍbVÏÆhC‘GWh A1"·š¬&{½; +ö5¾ò© (6•Ä3›_І”?j…<‚–µB¯'höpé&RYïU§Ì»M×íÝ¢kº£xˆœ&ï6´™­’XÅ Hn‘»›;ʧ¦òtw³y·šî[µÔ–QÞmºl¾¦Ñ iÖÏfÒ­MWh ïvKw Ô¦cSu‹’-ðk…¼—%y¬o¾€E(ÌÃ\™ã|•!apfp æ®Â ›3ãž)†a”gèöÏ v(=é.M…oª9®ìí䔂ª.M׿$ÿkƒ[Ä”@®ºïîU2ˆºøßˆï\†OSrÎ*[íŽ^"â±—ˆ•‰,¬±4]Þ™d†”ˆ˜Õ+MZQ`UçÈ•ÛXEfO‘ÇÎ:N¥áj2óä|@@áQr>ȱA†”ˆØßÞ±|êÛ#åîêeæ•jZ“ˆwí¯±v³ö#R> ›ˆ ˆçº‰ÃåÊkc6"VÛÄnïªj^ÙA?ú&Ì@ãßÉžR4uìUO †íúÛÏö¢›‹švâV„ªiß‘À} 3‡v&5樽±ŸÖ-¦±*§ÑLªýyñ#Æ—Õ†,f;i;‚;I:Ÿ¦·\G ?#¤°Á”²G°1wp‹Ü'` ‹sCuœ…œóÓ‰Â4Šƒ[Ä °Ö)ÜŽ˜;¸E$•Úþµ4•×Cô¾L§Ç”x¨ç*(>:¡™8¦;Bly#ŠzÉv¦Î€>Yˆi¥Ã†gàiûvo·Hn†Éghåd¿ú£¸jÕå¨W]{QS±i ¹bL´ïÙÝrÕUÁj<#*º³®ïq‹/k¤p“£­Ù&Úêmô¬Ž*í3Oƒ)‰ íkŽóÀ”Äf#Ò0Qû +ÒúSªt´1ùþI˜M”x Œ2žVR›ƒSûÞúÍ¡´ïÌ(úK£lR±zÒi›~ŸÄð{è0ŠØè‹º0ç:!½tÞýOãÓ„_N‚%¤lÔuu´1ɆO—Çe{{Àßd¥:C{Ž/RG——hð*s™^i3¯b WÏkÓôɬ©®ê“:Dª—”(.Ò:y‰jõßXn)o@eㆅ¨sK9\žÖñ0Í(ÉL Š_¤u ¢êš͘÷i‡I“MDÍhÔÑ K +™"šNf\]3Ñl$ç#ª7½r™hòÅpwƒ)‰´ùˆF¦ºAJ¢Lý|DSqèÆ Ê ÝPJ¢ª:ùˆª£½æSigÉ"e¯6”’¨XtóE˦Á”DÚ|D~!h8%3$læ’Ž'M“’ˆ1WÖpãBvš&åá1+”úñ+Ô Ûµ®X!9l×Òb…Úð©X!fCòq+Tûž­X¡…âmp-(Vhtò¾EÅ +Ñ@·š(V¨î‹cACOð=2ÊXÖ)x¨ï +[(ÞjEUð"¡¬ù„²¾Õ +_ðÐìÑÞ êW;T„í̤Õ<Ô!rk¾à!vªZóV+eÁCýÃ+Æ•) êÄRªÎ¦ +êZó³–VÔ[ƒ #P´ý‚‡úg¥Ô§»C—Zp%))xˆKlÅaXMÁC} ¶èå{¶¤î‰œ!Ù²(bµC­Ö`&6êIŸœÓdÁCS/Ïj¼à!®còò×L*I*IU¦Œ¦N!uв~µCC -xH¼o¶à¡>1c¥é‚‡ê>i ªÓ|ÁCI‚°Õ-Ú7'5ZðP?;Fˆ§5_ðP±˜a¨)ÍM³õ«Šhš.x(çkáìzÃN•Ff0jœmA°:Í<Ô¯vØ +-€ +Rm}7_ðPŠE®SØ|ʹڡÉTrÁC“©$õO¹ß<­r£šI¹Ð¯v¨ãߘ+xØ‚ô8š‚‡ú¶¾ël¶à¡ºcZ‡²S[ð°S½‘‚‡(ëÅæ]\eÁC}(Š:…È£ +Ïi3ÚTrµCÚćNÝj‡˜ÝDbÁCóéq­ªö¬¨vh!%þ›-x¨oJY _7EYð®N!Ev0MyARðK½SØDÁC}(jÖDÁC ÍÆ¸Æ)l¼à!f_Šæ-ñf ê‡Á¤à}³q‰W¸e­É‚‡šaj¼{ÍܘK¼Jr´Þ½Â¸m®à¡þ®¨’hM¢h®à¡¾Å(¸QÍ<Ô³Óet‚¸Çt«òŽG +êïøð¦z +ênº¡”ß–<Ó­v¨Ùj¼à!):J|ÑLcÉ}‚Ùêã<¦Ë€¨Ö +¶n»]ÓžRwš_) ÞÌʬ y´apM+Õš“.鼿&‰RÅU%MÈ LP",»Œš¹Ùw”t@ù RVª­H*BK²aŽ[ÎMx*#3“ÞàÆŠ¯{¬-‚šÀ”.”M´šHq¶Îg— ŽlÝ{SG6÷èñ¤sxìlÐ92¼¼å\Í™hôØÃD{‡˜ØìR„‰ssL|i°—™›^H2s§‡Ìbž=bVæýƒÌêtnY+0ëL‰çúÞh•Ùè]·3w\kf7ݶÈìím0Ée…Ù÷ov3ûóö%Žã¢®¼SæªÞÂ:WMíåî.h$,W`ªiwo.;µ8µ0x0±¾{çÐÖÓÕ¹™èç¡9Ø™X‰Ïtt¶µ zìíùLçt`°k1}¼éómUW)°°¦…OÀ›Œ­®v2l\K±ºD˜›9¨:A?Êe˜ã:gë m2… +‹C!½†€"Õ3fdÏÁq ½NâXš€cÓ9âïž`b¡Ù;ÈÌ0ñÅ…Órû^æÓÚ„cgQçhpa›ñÄ’6˜!¹ÄD×’¨þ!ãYd]©’ÅÈ"æâ*ÙÍ~*Giƒ“W#‰pFºlŽ‘…€­×Ó½Ó€#¶ŽHÐcs9&&൛s©m éÀ ðÞ¸­wÒŸµ¹æ7§l=gí`¸©³ ÀÚ|}QŸ*ÑoOØ;Î¥<^8®äÄðœC‹úæƒàÛJÉë:<ßÖÏÄ=ÆsÒæFû;O+ cw{ÐO¨!í·c¶<4åàtŸ9áO§ðsÈÞ ö +?ç *ÑÌÉÙ BÓ7ÍLžçÊ“³»@T…®Ž 8äÊ1Œ:7RáQñF¸W¾á ÝYG7š±i|Ød‡“âC‹^éÆ˜´Î<ã‰öÈ×”¨ãa—â†u|Úͯž®°¶í8 v‡o·|\÷–½è§|Í~&&dàId;‚k1lÒìo6„ TŠA Xç‚@3-‚ÉM,z`DÚůžgàÊ‚ÛÃO'±í÷̯œøÁã«` +ÚGÚá]'Àà>e<[s2möE4û`öûïôF<©‘®¡ÃB÷Zl$8V2´˜ß\Rz·¸M7ßÜ ¨Duàj€*¶ðtàŠúÁuÌ—ƒñØD7»™Î +e<Á7½"C¯úœWg5fŸšžö9òI˜ˆ‰8´J$:¤”ì–^ì…ôr"ÀÏ5ðm“ñ¦ç¦àÛ¶—7Œ=é=ߨà´Ì\:åGßäðƒ°*†•Ë à*¥*Õ„*ßfà¬|Á«×Yi¯ +´¥†=]ppvÁÝ +[È"Ûƒ„,¿+=hü0Ç8ßÓ.Ô^íc ÿøF4K:¶g¡pCÁ¶ó¥HÙò xü«Œë6@Ã#&Ãë&N†|µÂÐN†f&ĸ¿¹+½¤D‚±«„‘YœÇÁPìF‘:aê°ûÁÀ/õk¦(:(ÏoC0ø‰.5áhtÂ䨇±«%Õë™Q¶³“è«)UŸ—Þm²­i'w¢©iÄ7< ‰ñ˜©ÈJZÂUP·sÀu¦[d&¶ZÒ¾rÙÀ|ö+ÊèV AË®žjãý±XÂx,–;@£1ދ厂*ãý±Xî|¬Si¼?Ë ÁÙÝN²åÞˆÑÞ-F (@6c¯CMöÇl¯ –MHž7$µ¢[-8$‹8äϵ¹g >á„&ļÞ+ÿИåö@0Øg ö¬žåjžå¹Üa®`Æú°å¶grÚë]+d‹1ŽeWÙ+‘b¦zÊ*Ö!«gr%<=ì‹°™b–µºÄ#muáQU,Ï +úƒýwúOïŒôîÇŠ~&[éKâùõãth~irÒUðî{׃‘öl†G#á©]Ät˜€-²ä‡á:Š ÆO¦Ú—GS‘fkLaç#+¸»´zC_S0žÓis%³Û6—/¶b³O•áhà•-Þ¾â]uPª~9‚ªÙCDÆþXg¸¹c7QÏûñåÍþ…p¶ …1'<å, qgl°ý$ݘðï ß™+ŒoîLNõÛÒˆÁeïíŒ{'ð=^[{âdÏd…(qþ>ð ónÁ™j@õm |ì©Ø¡i—¬Öçî¿yíÈÎ$Z!&Ó%äL¢Ÿ@…nsÈ‹yáÑL1Jfî>’M-秤öÏH7z•7DAàÑÌz”÷JáCé!¯âFŠtúÇ×fU" Œ{H>>mèªslÄF7î¡:Ò&;кޮƒ.Ö„ÞàÄ ºDÊh޿ŭ'ÁM¬‰JØ©‹¿ô*ÂMƾâU§Ânbß‘=ݱ¼ÿ@œ'K]­Ðse·V0Š)…Êš eîSùÄ¡Á5U~wE'xeC‚áms6׉!»«ÙðèAØÝKKMÈiXèèèDI!ÀvÃMÍŒ(0îtR\óòÝ2’õ8ñoÏ…íJaFOŠT:|}%¯€+>’qAR)ÚµÂ!öéØË³€Ð´3°Ù6 Ñì my§Ñݦíuéxûãµ×¡ã!n =F{ ‘}×Çg¯ós³à~Ìö:BLöÇl¯[”oy}|öz©þxìu~nVÏ^‡ëMŸE¬nÙÄv+Å^+œ›f·[)öZù“sÍm·Rìµ" Ýäv+ "Á8 %£…¬2L2K+l¥ZBMú’!ö0W˜KÝcÐz­ü ø~ Z½¾ Õ××~ôÁ«siËm;jmõ:¬s$é™ä*‘\¦’+RÜ=뺶9?·6±YùÖIÐzØj}b’ 9¸å@ª$ìiÒr›±NÂÍàç"ü8„|WÀõ{ð× øv þ½` Xç­Û»Œ5k÷–…‘ÄryvH9ªåT¹‡eí쬥8v2ŸßÙ™^™^±ú­ñµiëL"^ÞÙɲwswwv*GÕÓ4üÅåîF_L–ò¬û¸tè€øã¿'fØ8—ºgÝâº-‘Ê××o ú­»V/à>ëæ¾úͨÿåv`l+ä·N4†Hª’‚màcoNßžý±—^½ÿ·î¿ü +åßßÊ¿úÊ+÷ïÓ¶¿ÿ¹ÏÏüÔ£ëÚeí¦vCùwùë¿~qssMÛü¦V»üé¿yQ»¹¬]×hÿ®Þxó‚º1ÿÄK/×j×µ+z$¿ül{CÛüò²öÊ«µ‹óš ZÕÞø +„EÝþªvÿ>˜ 3øyóW ‘©Çþ>÷2l~qMäú·¯Ì`€_F㨙˜ô7ß¼®Ý˜@rsýÊ+u¿‚7nj$мùèòÆÍüu!öš¿'7¸©Ý¯ÇÁ·¸‚¸(p\ÝüR»xpS»~t8BA޾;¨G7—õ4¬ß5D°¯Ÿ^Ë2„Ãq]ãÿ]‚lbpð‚ë+é+"Ó£Úõ·j0"­Åñvè +öæ†çžwÁCÏõpÀ¶7jÿ1÷çàó²…ÇåÅÕ7æ³?ø…W>ó×ÿÆ_ÿÌOù›­²=aÎÁPÿîû_—/0X´ã_ÿ£·žøT,µëø€µô{5ÕS8PÄ­Ýúá‡5šù¸º<Sð…çoÝ¿]úÃû[¾×U#Áà”½~TûúG?Üs~#UÝ8D¾õ±÷}þêúÌøÏ=w{à¿*Ûcù +öý3O>ÿü¿¼ª]ÜÓJÀñä+W<ȧnÿ##±þÄ·úé§’W<»ÐáxÿËðêeíoèɽ CÞ­]þ‚ãwFžîù¦)Z}øâç>hYSê?ï^ƒN,¦j/¼ï¹̯•”8>ÿèü.wŸ}êVù>­ÀR]ûwûåÚWŸÿÀ¯ )Çqssu Ä/þÜÿõ¹‚xù¸ù_ú]?˜¾mý]œÎ'ÍùKèêågŸxvþ?+û†ÇqÁ|´ùaË_ù"n$àxfóŸý‹_ú¥/,}äÓûßPé üœ¿ññß õû¶Ì]\RÏLJÿjÿØX÷‡nÝžü h(èÎyíê*¹;r³ùÄG³™wä»Þ}÷×>Ûõ̧Øÿ¬lÅñ§ÖŸºzøðÁwîì™Â,R¤9é +ª©G¿á}ßÓûÎêḮýÌ­ Ç5äí >ó±à·¨iõÄ«'Áï×>õ쇾l°Ö>Úý?û÷úg¿ô¥Åg?öêq<ñcµ+0ÓWk£Ï?sª/ƒµÿëÓ¿uš\þïO°@//ÁõüûÎÝgž^R´ÇéÝüÄwÁ”Cÿ#ÏÝB‹ãÖ+ˆcÁJúù;Šƒã;ŽŸ¨?‚Êí²vtû©N‹ãÉ—oà_O>÷ôËäqÜ2~òÓÿþºv_ÏC€Ôü韠^œ×Þyøèò¼öío×Tu6Üyí¿~ëÚ£®ýÙ;àUÆÇO¯š@üï]ð&ßhŒ]_‘ç|7QíZ˜µïÖj$Ý~syůP5áà˜ï¡¯×‚–Àâ€|´,4r‘·ÇqE°}®PS8¨ ë +40„ eEi’ÖÛ»×hŠoÎÁUh,_©†Aô ôþ06µîß_âøKÿãø"¼›ú•üÈ×¾óãüþ®þ×Üÿùæ[o½ýöëoRþ}í•—¾öÖWÞ|›¶ýk¯ÿÊÑá¯~ù˯¿ýÖkoPþ}å¥Ï}õõ×_{“¶ýÛo|5÷ãæfÐê«H+Qÿ]_}á%´x@/òï­×¯‘î£üÐ_¹ojàï+¯ÃNQpÇýÏ]ƒÅ»F‡»yó5лsú8Ü8zú^¿ýfͳcü«+é&6à¦]ù ŒÐkÞ@”åüê +ô:Ž7´·êåüŠGs-ú5WªQbqð¿ðsŠXO71 yu­°ˆ8  È÷ìü†Âç„ßÎÏ!U¯/.øË×——Wú8ø …†°j4´ªÉvËU}{ ŽKZ††ÆŸ×00ã¸&ÒÂt rs©bcK—µëßx5Ù|á—¿Uûí_4GíÛ_}ûçß~ûµ/¿öÚ[¿ýŸ ÕŠÂM:8€-ö;™çºÊ÷UÎúY¶`8Ž‹ÚŸ¿ýE惟øÈ÷ûÆümß?þ¯\ÿÊÇo½„ì|`ÿó±Û +7Re·#søÿmÿÀÈwÕÒ‡µï&Þ¹Ý8­n®€Åÿµ>ñ¹Þ¤¾©U-ÏNâýZžê_|¿¥zSC#]tó¥w.Dÿ€€þwýÕ>ý +’@h½ã¯>ýñ¯aq GóÑüÓüßjïò<¸Î^Õj*ÒàlŸë7?öÄ¢ž@_ârü£| ‹:*7:Ÿ·|í»H­_A>¾ºBΑrÙ«óÏ¡)ôÆ_{ÿËðÿy—'÷ô3I,ôû÷¾ÿ¹Oÿ: +þK”à÷d¹"Å–^½©ñ .ÏôIKèâêF$¥bp¤ÿæÏ}úÿÀ bq£ *à€Ø—>ðìÄ%Ç9ŒæþÒ'žÿþoðŒPðS}uIRì¥XF¯®18Ðð«ß÷‰Oüεº¸¾æ£¯WWdùÐÒê²öð3Ï|xöZœCÍ|\ÖþÃ'?üÑ×kתƛ^š½—`Щ=U”Âx]{×÷ôG~R؇‘ô :\m8çWCzß—¤û*hfÏžy.…´& ,䨇߃"¯§wëøªöö'oÛ¡ù¾øÓÞ„—þÙïIY'jq<¨•ŸUˆnšyò¹¿w˜Î½¾w}sï×ÞE˯­€_o|øÖK5d2\Ö~£íÙOüߺ6Ã[ÍÒöÚ9Úh¨]ýÄ¿‹–F²œCŽx·öú'Ÿz ’LøŽ<ùì öÄòÐ×òÓþÅõoó&„B +ëÖÁs°XüüGŸúl .W_ÝúÈç`õp\¾úÁ[ŸúÛ¿ûàò_Ýšúæõ%ܸ¾"êv„þ⇞~ßÖ¿ùÃw¾ù¯^|þ‰‘tu®€‡Ãq^û?nßz²ÝÛÞQúoý¨ñ?Y{œvÛÑ߇Ë>­ ú}ô[?rïä…ø5a!Ñã+@ ‡¿ýëÿößÿî×ïwû7ÿN´"ômj°l<¼¨½ûèîvÖ]ò6¸Ž]r£6*.Þ©Õ¾g°Çr~Í[º 3çÈð«]©\e ŽsÀ`1³×ók¸î 3N‡Ñß{4Îð—8þÇãÀq¬f\úÚ/¿IpÜñ@Ûßâ%—Ô±‰7ÞâÊ?°ÞýèO]˜9}`ÿÛ_»F6>õßÅÏýؾòòýÏݧý{ù(ÿêgïž¾ýËŸ_@çá!9ËíÍ)áð¸"ý‹‘(Ú7ƒþVÏJ…Ë­öPh2“©ž.+)ØV}Bq.$CGG{{ÑkáR‡ì*—Êå!¶Ãrê.kM +[·¬‡[®9ÖZ>*¾¯À‡¤@ïAÿÔcð +endstream endobj 11 0 obj<> endobj 12 0 obj[/Separation/Black/DeviceCMYK<>] endobj 13 0 obj<>/Height 100/Type/XObject/Decode[1.0 0.0]>>stream +H‰ìWypUÕ?˽oIÂN +…ØÔé¨h[*`‰)Ɖ¤,e—MÖaI‚-e1 d+ˆÐ68 +e/›¢R’€ˆt¡.€#‘a­(„²¼wï=çô;÷=yÞ½ïÝüÛñ LîrÎý}ßïÛ~g jR8e‚ w?rÏLH ìrƒ`Þ +\6A%†"°p¹‰}ŒÿÙ]AÂ-XclÄù9ª` +wë +bÕ¸²¿êvuhK).ÊA:% »†9Œ+Âb×ÎH)Å¥ táAîÕ¸z 0·faFKpq¶¡ f¸"ªð±~@¶ûÀ TŒÁz"·0¼ +Wõ§ÍÀ€‡|1¯]þŽàÊ_÷‰ Þ‹U¸dÁýÞ3Šd9ZŽàЧ9±¾œÀ®†-íŠ,¸Ä%´„Q@sƒiJ¬>ÌuËܰÚEÞ€E¦Qð‰(&£} y`rn~1âL|Ð…n6ƒÆûjµC ±eBpAQ|_L²‚^^×AZèÑU…¤`£`˜%Í ¨* +O,¹iÞË+‹’4¯™~qP A¾ª¼ZŸlÜæªN~ÐõÑÎìµlpŠ>ø»aÆ{iëj4N”/pùŹ5å¤óÃë_^ê4dêÃȺÍE'PsÁq»—.ònâ§½’WSœ¥êêÅ%W/J³zc‡#Ýûi*ëôÆ6„EûÂeV¸U2ž º{ŠñØÁöñã²Ù,)l6eP]añ £Ô­˜GÍŽÚOׇ"“¬&=å×G¾NÍÌq‰R[0O…§†²nq㨠4n&#ã­Å;gþ+åp‡f1VšeîÖ÷OÂé»,Ñ6“!2dHÛ‹Jÿ4¡è®è—™XÅ0W..ÈóÇfLŒÏ÷Ù:èøàúa[C­Ó­/s¡ð…ŠÒ?äÛ‘ õ"òSƒC~ïGl&‚côó²åS£d±?õµŽóPôÞÏ¿Ìè²UõkfÛ Q'”†Á™^ýçXu‹Ôß§X[“Cô+Gø!å_öbOíÅÔu\ oWºþU]Â%?IAbF14YÛ¶ˆÑ»Ú”÷¼#F&/Í¢­xãrûô—;Z6Ø£ÔþlÑ íµâ†ìeÑcÌ1ú )´¯à™?UG–aî‹…ÂÉæú4±–M +ý$ñÁw[»f¬¦x$(ðT>¹FÙùLœ‰LýQ*5t¿†Þ®ðÿõ)×¾Ô¬žÃ¸Š˜îp¶iÊ«±«ý;ó@7U®1öS&­r_/À ŠêV¬Ïîl°íÉYgÞNBºEå¹ó)ÉnQn”,”ù }ô­‘ c‡R×÷735á…®g(36³í™nQêò³±,EMI;¥-ÏqöEhÈ»;ëx*Õ££ƒ=ozÌñ¡9j"+R]T©)˜G¦rºgNÍåÉÛèKFÁ”ààÛ'B*É`¾ Ï^Kz·‡0T«”Œò…aP`[²jWÌõÁSQ1û\›?fú¢¯ ¢¢ S{ïk•È„+§}£ (è„‘Ž…Òä¡üƲ?“gvêüüô6½ç¬1>Ë+Љ}q×^M'Æ'rÁ¸(jz?—ž  Õ‘± J¾>tú¤ šF[pFýÉ .DçösrC÷¢&äojäÉÒÍsÛƒ)÷Ô¢Ö±£+oPÚ2È‘WoPZïŸU*YQÌN É¥‡‚ÐàQM•ØD=R/ç¸Hw¨V +_}BN_0L͆‚’§!Q^J!(bæ˜AˆÇòZªø€J”`ÃZy¤}ªR†(|ÖÂ"dmt2˜ Ý#°TÙÒ ËŒuñÉïôÁÐo +³å!4õǯ4þ%Ù¡ ©¤=—q¹÷ÁV’;8Z|õãÞLP‡A'ÆÀ†O¾U‹L1.pNï}Xq@‘ÿ×Î÷O/štÌz6÷«áÓ… +p ĉ! y eMJåáçu-ö=i‹bYµáåJÉôÆÓFÝ£y4®RtOªÛ*%^ýëš¼—¤1Ž"FÚ™àâ\[yÒ!î7õ÷º'ɦi"ÏWÖÉ…Â1§#codÃ_lšælÂ#Þ°E1|þË;­÷ù +óþ¸Ê¥¾tGG¡ÁgöðçžI…a¡LÚ˜¾a»èëàAcÿÏü3Ìyé†ÒCÕ耳õë'ûþ^3ÆóËÔ¡dC~Á!®±Dh8VOŽÊ1T=¦¶Ë®ÇìQL ´Gµ¦ÞÇÆšï'Êj‰Ñ-ïGiò/,ã‘r±båþÕã5ŠIƒÿ.³[‚ÒÒ¢Q‚~+‡ÕæêR\Ê©×+»ÅTU£’ËS4¬Ê‡lý×9 r|ZVD©>HŽÆ„Šn.Ï–A_ûwÏÊY‘Œ±ûùÅÁ~«ì3`íñõ­M±a©ËèYÉógZýÒ—8 vvÞ‘6ÿSYЙxmù3±á‹l™“"ë·+SÞÏ‘¶Y€É™gÉvÁï–®ßaò‚ŸÏ›õÁ*=ò/Â@¬¶übÛ0Ï7V9¾OŒ>u‚à¶J7K«ïÕ‘kkï +üädäbüûÓÝ,ˆ¥yµ=,šÿ\ßòí¦"¤¢Á›Æ€Áôãæïb߀Øï¢Àhµ7°·.VÿfûÁÌú™‰õ';°²`f7ßñÔÈ ì„Üþøýá+;"Qb1` ÔB&É_, ¶"¨„CdJ [~±ýa`þÇü‹‰Øoõÿ2ÿ5ü°×ÈĬu%>0j˨-ÃÇ–®Ò_Ì^.‘`ã^GFPS„HõÀÈ0û±ö0îeÜçnk ËÿvÆIÀ~$aÅ0ðÿ4ã)c&Ph-¿g1ú¸~aûÇø—è ûŸ1Gá Ë¢50°0ÃŽ©a +endstream endobj 14 0 obj<>stream +H‰Ò÷I¬L-RÐ÷u6PprqVà*ä2P0·4R034RÐ1ŠR¹Âò€âF¦f +Æ&f +†` —Ðw6PH/æÒJÍI,É,KuÎÏÉ/ÊÌM-)ÊLV(Êä©A 3%9—Kß3×@Á%Ÿ+ËÕhs ¾"§ +endstream endobj 15 0 obj<> endobj 16 0 obj[/Indexed/DeviceRGB 255 17 0 R] endobj 17 0 obj<>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> +endstream endobj 18 0 obj<>stream +8;Z]]_$PWG%#&-aEM)Z_SfHnK*%'tW[0?#ETZI.!g/B(:9dTi?!!)pqHnq`?ZF&M5 +A1qSl1lg$G0, +endstream endobj 19 0 obj<>stream + + + + + application/pdf + + + derivExample + + + + + Adobe Illustrator CS2 + 2007-03-01T17:43:03-06:00 + 2007-03-01T17:43:03-07:00 + 2007-03-01T17:43:03-07:00 + + + + 256 + 256 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A6h+X3kDQ7/Rpnaa5Xjcs uzRjoiH+Q+OFDJ/+VX6ByP8ApF30/nj/AOqeNrTY/K3y/wD8tF3/AMHH/wBU8bWnf8qu0D/lou/+ Dj/6p42tO/5VdoH/AC0Xf/Bx/wDVPG1p3/KrtA/5aLv/AIOP/qnja07/AJVdoH/LRd/8HH/1Txta d/yq7QP+Wi7/AODj/wCqeNrTv+VXaB/y0Xf/AAcf/VPG1p3/ACq7QP8Alou/+Dj/AOqeNrTv+VXa B/y0Xf8Awcf/AFTxtad/yq7QP+Wi7/4OP/qnja07/lV2gf8ALRd/8HH/ANU8bWnf8qu0D/lou/8A g4/+qeNrTv8AlV2gf8tF3/wcf/VPG1pKvMf5c6Da2SOJ7o1kA+1H/K3+QPDG1d5c/LnQbmzdjPdC khH2o/5V/wAg+ONqmv8Ayq3QP+Wi7/4OP/qnja07/lV2gf8ALRd/8HH/ANU8bWnf8qu0D/lou/8A g4/+qeNrTv8AlV2gf8tF3/wcf/VPG1p3/KrtA/5aLv8A4OP/AKp42tO/5VdoH/LRd/8ABx/9U8bW nf8AKrtA/wCWi7/4OP8A6p42tO/5VdoH/LRd/wDBx/8AVPG1p3/KrtA/5aLv/g4/+qeNrTv+VXaB /wAtF3/wcf8A1Txtad/yq7QP+Wi7/wCDj/6p42tO/wCVXaB/y0Xf/Bx/9U8bWnf8qu0D/lou/wDg 4/8Aqnja07/lVugf8tF3/wAHH/1TxtaYx+YH5e6FYaNDIk103K4Vd2jPVHP8g8MVZN+WB/51644/ 8tb/APJqPEqGYAcV3+WBLY6bYq3virt8Vdvirt8Vdvirt8Vdvirt8Vdvirt8Vdvirt8VSLzjvpkQ P+/l/wCINhClvyiANOkp/v5v+IriVCeH2wK7fFXb4q7fFXb4q7fFXb4q7fFXb4q7fFXb4q7fFXb4 q4jx6Yqw380fh8vW/wDzFp/yakwhBb/K4f8AOv3AG3+lv/ybjxKhmJAPXAlwFMVdirsVcemKuxV1 cVdXFXYq7FXYq7FXYq7FUi84D/cbF/xmX/iDYQpd5QP+42U/8XMP+EXEqE9wK7FXYq7FXVxV2KtB tqnbFWwQehrirgR9PhirsVdXFXYq7FXYqw780v8AlH7f/mLT/k3JhCC78rv+OBcf8xb/APJuPEqG Y98CXYq7FXYq7virROxPhirnKgfEQB4nFWlaoqRxPTfFW6mgPSuKt4q7FXYq7FXYqkfnD/jmRf8A GZf+INhClb5Q/wCOXL/xnb/iC4lQn3fArsVdirjTqcVaJFDTfFXClB44q4gU8cVaUACi7Yq6gBrT fxxVuu+zD5Yq0xAPh74quHTFXYq7FWHfmj/yj9v/AMxaf8m5MIQXfld/xwLj/mLf/k3HiVDMe+BL sVdirsVaqAdz1xVphUUHfFXjn/OQf5kz+Vrayt7My/WJXikPozPAeDCcdVU13Txwq9M8t65Brdi9 xASAkpjNSTuFU9wv82BU36mvUdvniq4Yq7FXYq7FXYqkfnD/AI5kX/GZf+INhClb5Q/45cv/ABnb /iC4lQn3fArsVdiq1xUdaYql+sWd3dWTxWdw9vNtRoyVP2geoK9hirxb8x/MPnbybJLcPNd3kMca ygfXDECJJTEBQNJ88KEj8jeffzF87iV9Ht7wpByD01Km6cCf7wxf79GKaZnLpH5xL/dw3jt4fpGM bf8AI3FCSzfnB5x8p3g/xLoUyWcbLHJcPqSzbtST7EaSnZAcUvSPIn5q+WPONp61k/pz1VWi4ytR nd0T4mjjG/DArNNhQNuexOKrsVdirsVYd+aP/KP2/wDzFp/ybkwhBd+V3/HAuP8AmLf/AJNx4lQz HvgS7FXYq7FWiPpxVa7Knxs1FHUYq+N/zh1+4816zbX8Ks+nRW6QHnIWX1leV/suENeMnWmFQ9d/ 5xp82jU9Ev8ATZXeS6W5luQ7u7n0xHAlKsPFvHFXtg22pWnfAq4GoxV2KuxV2KuxVI/OH/HMi/4z L/xBsIUrfKH/ABy5f+M7f8QXEqE+74FdirsVabpirqAYq8f/AOci4oj5Tv5CimQQWwDkCoH1te+F WI/84l8RbaiP8ub9VtipfR1N+u+BWG/mZ5L0rXfKWqQm2t1u0t5pY52gjd+awOq0J40I5bGuKvlf yxq2peSPPVrphnlEC3tkZljkaJCvNZCCiFwRSTCr7H8s6xDrOi22ox/Ym58a1J+CRk6kKf2fDAqa Yq7FXYqw780f+Uft/wDmLT/k3JhCC78rv+OBcf8AMW//ACbjxKhmPfAl2KuxV2KtEntirEvzQ8xj QfJuoagsoiuIRAUJDkUe4RD9jf8AaPfFXlNt+V6N5AMctqWv/wBK8g7NAX9H6tSnOnTl2rhQ83/I fzVceX/MN4skgijktJDxPNhyaWHeiH/IxCS+y6UwK2OmKuxV2KuxV2KpH5w/45kX/GZf+INhClb5 Q/45cv8Axnb/AIguJUJ93wK7FXYq49MVa7DFXkX/ADkV/wAohqP/ABhtv+oxcKsP/wCcS6/VdRoA T6k3X5W2Kl9GBv5tsCpd5jmWLy5qk70CxWc7saVFFiYmoGKvizzJM+p/mlC1sitHcXlkiFRx6rEm 3KlN8KRyfX/5cWkln5OsLWUcXj9XqQT8U8jdRt3wFDJ8VdirsVYd+aP/ACj9v/zFp/ybkwhBd+V3 /HAuP+Yt/wDk3HiVDMe+BLsVdirsVdirwj8075vMH5mWPlKECNLuzIeV/hIaCS4kNGBfY+l/LhV7 nwUim9MCvir82tAuvLHma2tleOWSWySSpJYUaWQfypv8GEqH1z5G1n9L+VrG/wCPAz+r8NKU4zOn Srfy+OBWQDpirsVdirsVdiqR+cP+OZF/xmX/AIg2EKVvlD/jly/8Z2/4guJUJ93wK7FXYq49MVa7 DFXkX/ORX/KIaj/xhtv+oxcKvHPyS/MOPycLuJ4TMZvUaoUN9r0h/PH/AL7xUvWZv+cirOFAz2Uh qafDEv8AGfGkPM/Pf5/3vnCzfy9DZxwwXThGkeNlcLLG0TUImkFf3m3w4pplf5F/k/aG1i12e5k5 LNDNEiOKVgmk2YGLvx7HFX0JGixIIlqVHc9d98Cqo6Yq7FXYqw780f8AlH7f/mLT/k3JhCC78rv+ OBcf8xb/APJuPEqGY98CXYq7FXYqgtX1CPT7CW8kUskPHkFAJ+JgvcjxxV85+X/zH0Kx/MDVdc1C C6Y2eq38aJAkZqjc0WoeQfFWTffCh6EP+cjPJpHMWOo/y/3UHz/3/gS8e/PrztoPnAWd3aRXUJh9 OIiVY1+z6zfsvJ/vzCoZ/wD842eaGls7fQHjANra3EvqKOpa7B6lv+Lf5cVe84FdirsVdirsVSPz h/xzIv8AjMv/ABBsIUrfKH/HLl/4zt/xBcSoT7vgV2KuxVx6Yq12GKvIv+civ+UQ1H/jDbf9Ri4V YZ/ziZGJLfUSf55v1W2BS+jDCteppirzn8xfyg0zXtHvXS5njuQjSx8nQJySFlWtInNPHCr5sS91 f8uvNgsgLe4W1nt5Xb43JChZtt4f9+eGKvq78r/OZ82eVLbU/S9KVufqLx4rtNIg4jnIekfjgVmA rTfrirsVdirDvzR/5R+3/wCYtP8Ak3JhCC78rv8AjgXH/MW//JuPEqGY98CXYq7FXYq8x/PjVXXy uNEtmJvdVr6EahW5fVpoZH23bZf5R88IVMPIHkbR4vKemPe2g+tT20E09ZJVJd4U5Eiq0+LtTG0M iXyZ5ZG5sqHpvJL/AM142lJvNH5daJe2McVrZjmsoc1kmOwVh2ZvHG0PmH8oNTm8t/mNYwXcnotN JBayVCjaa4hah9TjTb6cUl9nW1xFcQLNEweNq8WBBBoadR8sCquKuxV2KuxVI/OH/HMi/wCMy/8A EGwhSt8of8cuX/jO3/EFxKhPu+BXYq7FXHpirXYYq8i/5yK/5RDUf+MNt/1GLhVh3/OJBb6tqQGw 5zbH5W2BS+jqAHbrTFWmGx/m7H37Yq+SP+cl1RfPT8CPXeguCDXpbwBajtthUPSP+cV1mXyzqHPe P916ZA2P724rQ98CvcRirsVdirDvzR/5R+3/AOYtP+TcmEILvyu/44Fx/wAxb/8AJuPEqGY98CXE 0xVoMCOu/hiqjcXUFqnq3EyRR+MjBB4dT88VeFv5ktvOf5v6dpUs8TWmkXWpwnhIjggxOFqU4Ff7 kdzhQ9ztbeGG1hgjIMcKLGhB24qAB3OBKuaU3NRiqyrE7/D/AJR/Vir4s/MqzttB/Mye7spVZLS4 s5YUHQMkMUleTF/2h3wqH0v+TPnGDXvJlo808X11PUEsYkQuC08oSqqFpULttvirPg3UE7jAq7wr irsVdiqR+cP+OZF/xmX/AIg2EKVvlD/jly/8Z2/4guJUJ93wK7FXYq0xoK9u+KurUbbe+KvGP+cj dStovLl9bO6c2t7Y0LgHa7Hb6MKsQ/5xW1TT7S31A3NxFbkvNT1ZFStRb/zEeGKl9F/pfSmFVvoP ColQ/wAcCsb86/mP5d0HQrq8TU7KW5jRxBD9ahVjIImdAAS1SSuwpir5W1y9178yfPIu1tJmt7qe 2heaCMzoquscJPKNIxt6eFX1H+U3kyLyr5UgslDCY8/XZ1ZC1JpGX4HZuNA+BWbDpirsVdirDvzR /wCUft/+YtP+TcmEILvyu/44Fx/zFv8A8m48SoZj3wJaPh44qtIAYUX6cVY75v8ALmra3afVrTVv qNSakW6TbclYChZenHFXn2j/AJAz6Hrp1/TvMBXUpXkmnkFmG5SShgx4tM6j+8bouFXqWhWup21j 6d/dm8mVv7wxLDUcQPsr71OBUxKjpyp3piqB1iDU7i3VbG7NlIHBZ/SWWq0O1G+jFXkWt/8AON6a 3qE1/qOumWaXiXP1QruiBB9idR9lfDCqb+UPyc1Lyk3+4vzATAzxu0Is1P8AdsWpyeWQ7lzir02x iuUtl+tTetPvykKhK7mnwjbpgVEgGtSa+GKt4q7FUj84f8cyL/jMv/EGwhSt8of8cuX/AIzt/wAQ XEqE+74FdirsVaZeWxO3cYqg9QjvJLV1s5/q8woA4QSdx+y3tirzXzf+Tmo+b5n/AEtrx9CRAjRm zUfCrmVRySWM/aOFUo0j/nHSXRVZdL8wm2VyS3+hepUmlf7ydv5Rjap9/wAqu82wx8V82F6mu2nR eH/GQ42hK7v/AJx5h1YL+m9a+uw8g5h+qmH4lHEHlHOp+zUYpZb5O/Kfyj5ViSOwteUqsrmTnNsy OzqeLSSdOWBWaBTUgbKMVXjpirsVdirDvzR/5R+3/wCYtP8Ak3JhCC78rv8AjgXH/MW//JuPEqGY 98CXH5Yq0Q1dt8VdxHWm+KupTtirYr4UxVqldyu+KuINa0+jFWgp5FiaginHtirdKdF69cVca+Fc VbA/2sVdirsVSPzh/wAcyL/jMv8AxBsIUrfKH/HLl/4zt/xBcSoT7vgV2KuxV1NwfDFWiPDavU4q 6h6dR44q1QgfzYqupvXFWqHFWihrUGnifHFXFTtv064quxV2KuxVh35o/wDKP2//ADFp/wAm5MIQ Xfld/wAcC4/5i3/5Nx4lQzHvgS7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FUj84f8cyL/AIzL/wAQ bCFK3yh/xy5f+M7f8QXEqE+74FdirsVdirsVdirsVdirsVdirsVdirsVdirDvzR/5R+3/wCYtP8A k3JhCC78rv8AjgXH/MW//JuPEqGY98CXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqkfnD/jmRf8Zl /wCINhClb5Q/45cv/Gdv+ILiVCfd8CuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVh35o/8o/b/wDM Wn/JuTCEFKvy58yWFtoU4aOU1umOwX/faf5Q8MSrKv8AF+m1/upv+BX/AJqxpNu/xhplf7qb/gU/ 5qxpbd/jDTP99Tf8Cn/NWNLbv8YaZ/vqb/gU/wCasaW3f4w0z/fU3/Ap/wA1Y0tu/wAYaZ/vqb/g U/5qxpbd/jDTP99Tf8Cn/NWNLbv8YaZ/vqb/AIFP+asaW3f4w0z/AH1N/wACn/NWNLbv8YaZ/vqb /gU/5qxpbd/jDTP99Tf8Cn/NWNLbv8YaZ/vqb/gU/wCasaW3f4w0z/fU3/Ap/wA1Y0tu/wAYaZ/v qb/gU/5qxpbSfzT5p06XTowI5hSYdl/lb/KxQt8q+adOj02QGOb++PZf5F/ysVTr/F+m1/upv+BX /mrGk27/ABhpn++pv+BT/mrGlt3+MNM/31N/wKf81Y0tu/xhpn++pv8AgU/5qxpbd/jDTP8AfU3/ AAKf81Y0tu/xhpn++pv+BT/mrGlt3+MNM/31N/wKf81Y0tu/xhpn++pv+BT/AJqxpbd/jDTP99Tf 8Cn/ADVjS27/ABhpn++pv+BT/mrGlt3+MNM/31N/wKf81Y0tu/xhpn++pv8AgU/5qxpbd/jDTP8A fU3/AAKf81Y0ttf4w0z/AH1N/wACn/NWNLbFfzH8y6fc6FAiRyil0p3C/wC+5P8AKPjiEO/Lny1p 11oM5aSYUumGxX/faf5J8cSrKh5P0xR/ez/8En/NONppr/CGl9fVn3/yk/5pxtad/hDS/wDfs/8A wSf8042tO/whpf8Av2f/AIJP+acbWnf4Q0v/AH7P/wAEn/NONrTv8IaX/v2f/gk/5pxtad/hDS/9 +z/8En/NONrTv8IaX/v2f/gk/wCacbWnf4Q0v/fs/wDwSf8ANONrTv8ACGl/79n/AOCT/mnG1p3+ ENL/AN+z/wDBJ/zTja07/CGl/wC/Z/8Agk/5pxtad/hDS/8Afs//AASf8042tO/whpf+/Z/+CT/m nG1pJ/NPlXTY9OjIkm/vh3T+Vv8AJxQ7yr5V02TTZP3kwpMe6/yr/k4qnH+D9Mqf3s3/AASf8042 mnf4Q0v/AH7P/wAEn/NONrTv8IaX/v2f/gk/5pxtad/hDS/9+z/8En/NONrTv8IaX/v2f/gk/wCa cbWnf4Q0v/fs/wDwSf8ANONrTv8ACGl/79n/AOCT/mnG1p3+ENL/AN+z/wDBJ/zTja07/CGl/wC/ Z/8Agk/5pxtad/hDS/8Afs//AASf8042tO/whpf+/Z/+CT/mnG1p3+ENL/37P/wSf8042tO/whpf +/Z/+CT/AJpxtabHlDTK/wB7P/wSf8042tMV/Mby1Y22hQMskprdKNyv++3/AMkeGIQmv5Whv8P3 G/8Ax9v/AMm48SoZkK0364Eu3xV2+Ku3xV304q7fFXb4q7fFXYq7fFXb4q7fFXb4q7fFUj831/Rs X/GZf+IthClb5Pr+jJd/93N/xBcSoTz4uXtgVdvirt8Vd9OKu3xV2Ku3xV2+Ku+nFXb4q76cVdvi rt8VdirDvzR/5R+3/wCYtP8Ak3JhCC78rv8AjgXH/MW//JuPEqGY98CXYq7FXYq0QO+Kt9vDFVrF gNt8VbOxqTt4Yq1U1oBQeOKrhWm5r74q7FXYq7FXYqkfnD/jmRf8Zl/4g2EKVvlD/jly/wDGdv8A iC4lQn3fArsVdirRpUbYq1v40AxVuo69Tirtz3pirqg964q4+FOmKu38aYq7Y9TXFW8VdirsVYd+ aP8Ayj9v/wAxaf8AJuTCEF35Xf8AHAuP+Yt/+TceJUMx74EuxV2KuxVqoJ328MVWPKiKTIwRB1dj Qe25xVLZvNfleAgS6zYw13HO5hH62xVfB5k8vXUhSDUrSeg5ExzxtTt+y3viqNe4hjQtLIqR9pGI C1+Z2xVfDLFLEskUiyxmtHQgg0NNiMVX4q7FXYq7FUj84f8AHMi/4zL/AMQbCFK3yh/xy5f+M7f8 QXEqE+74FdirsVdiqlPNFDGzysqqP5iFHXxOKocarpYZV+twhiK09Ra/rxVf+lNMpvdwj/non9cV W/pPSx0uoT/z0X+uKoiOeKTdJVcdgpB/Viq4n228cVcAuKrsVdirsVYd+aP/ACj9v/zFp/ybkwhB d+V3/HAuP+Yt/wDk3HiVDMe+BLsVdvvt8sVdXFUi82ebdJ8r6ZJqOqScIhTgKO1auqH7CyU+2O2K vCdQ84eevzJ1yaw8rrd6fpMkkluuoQXxUAwM04b0GNs3xpxHtX2phVnui/kc9rG66lrP6TcklWuL bkQKCgHKaTpQ/fjaKX6l+St3IijTdffTnqCz28BQkb1B4zJ7fdja08280+bfPvl2W00LVorp7b63 Db/pV7/kXa4UvQwqZG+FXI3bt74pp7r+Wtw8/knTpWdpWb1quxJJpPIO++JVk4wK7FXYq7FUj84f 8cyL/jMv/EGwhSt8of8AHLl/4zt/xBcSoT7vgV2KuxVp+nWmKoTUrD69amDn6fKnx05UoQelR4Yq 8B/PDQfMWhW9zqdhrVyixQxMsMLvD/eXJTZlk22bwwqGJflZoHnfz41wy+Zr+yEAcUM0s1eHp+M0 X+/cVerj8kvNPCn+M7zlXrwk6f8ASTjasX1vyT+bXleOXUrbW9R1aC2HNoDdm3Uoq+ox+K4k/k49 MVb8k/8AOQ62V2NI8zW0sF16sMbyS3UlyQJWJLfBE/RXXblir3bQtd0zW9Oi1HTpPVtpuXB+LLXi xQ7Oqn7SntgVMcVdirsVYd+aP/KP2/8AzFp/ybkwhBd+V3/HAuP+Yt/+TceJUMx74EuOKuriqnLN HEjSSHii9Tuepp2xV8t/nz5+l8w6gPLmnPKpgubuCUrK4U+jKhWqMqD/AHUe+2FQ9h/JDyfDonki wmlhikvbpY7v1vTQSD1raIH4wWJ6Gprvir0ViR2wK41J2xV51+cPk6HWfLJvYYYkuLCYX7yemhcr bwSftkqfD+mFU0/KBz/yr7S1Y/EPXrXfrcy4FZkTuMVb7jFXYq7FUj84f8cyL/jMv/EGwhSt8of8 cuX/AIzt/wAQXEqE+74FdirsVcad8VaqAPliryL/AJyHC/4Q1CQqDSG2H/T2uFWHf84kM5g1LkST ym6mva2wKX0XwYj7RGKrLu1guoJLeaJJI5FKOrqGUhhQ1B67HFXzL/zkB+WR0/VU1rTVjt4Zkllb 0Io4uP1aKIVqrAnep6YVRn/OOn5kCzSTy9qM0s5lmtoLGSSSRxynllLcU4uF3kFdxXFS+lR0GBXY q7FWHfmj/wAo/b/8xaf8m5MIQXfld/xwLj/mLf8A5Nx4lQzHvgS49MVaBBGKsU/NHV5dI8j6lfwv 6bxejR/i25XEa/skH9rFXyV5Tin1z8z1+sVuPrlzeSgMaj4o5ZDTnWn04V6Ps7y9ALfQtNtkUIkN rDGwFBQpGoptt2wKme3TFVpJ6rviqHvbOG9s7i0mFbe5jeJxt0dSpoCCOh8MVQ+iaNa6RYRWNoCt vDXgDxH2mLn7IUdW8MVTI4q7rirsVdiqR+cP+OZF/wAZl/4g2EKVvlD/AI5cv/Gdv+ILiVCfd8Cu xV2KuxVrb78VeRf85EV/wfqKDvDbf9Ri4VYf/wA4kk+jqWwHxTdPlbYqX0YwqNj92BXHcmnUYqxn 8xdFstU8oasLmFZJYrC89AlVJVmhO6lgadBir460uWXQPPVhHBI8TQ3to7rU9mRxXhSvXCr7f0K6 a70TT7pjyae2hlZt9y8Yau+/fAqOxV2KsO/NH/lH7f8A5i0/5NyYQgu/K7/jgXH/ADFv/wAm48So Zj3wJcTQE4q0GqB74q8u/wCciZyn5fXaAf3np/hcwHFXgH5KJy/MjTlP7ZuDt/zDTHCpfZVkAtnA vhGn/ERgVXpvXFXDFXE4q6mKtMaUxV1ASG8On04q3irsVSPzh/xzIv8AjMv/ABBsIUrfKH/HLl/4 zt/xBcSoT7vgV2KuxVx6Yq12GKvIv+civ+UQ1H/jDbf9Ri4VYh/ziV/vNqX+vN+q2wKX0b3xVo1r iqXeY1B8v6mf+XSf/k22Kvibzht+Y1zT/f1p/wAmo8KRyfZ3kj/lDtBPjp1p/wAmFwIT3FXd8VYd +aP/ACj9v/zFp/ybkwhBd+V3/HAuP+Yt/wDk3HiVDMe+BLsVa23A7Yq85/PyxNz+XGouDRo/R6nb 4rqH2OKvmv8AKq++qfmNYMwr6DXKmgrX/R5V8RhUvs/SpBLplnONvUgjan+sgP8AHAqLXpirZNMV dTFWiD2xVwJNQcVcFAxVvFXYqkfnD/jmRf8AGZf+INhClb5Q/wCOXL/xnb/iC4lQn3fArsVdirj0 xVrsMVeRf85Ff8ohqP8Axhtv+oxcKsQ/5xK/3m1L/Xm/VbYFL6N74q0x/HbFUn83SCHyrrMp39Gx uXoPaFjir4q1O4+v/mFbFRx+uXdpHvtT+7T3wr0fbXle39Dy1pENa+lZW6V/1YlGBU0xV2KsO/NH /lH7f/mLT/k3JhCC78rv+OBcf8xb/wDJuPEqGY98CXYq7FUt8xaSdX0a5088SJ+GzllX4JFfcrv+ zir4z85aHqflHzxdXVxC0UEl7e/V5FVyCquy1BkCgikgwq+rvyt8yWGt+StKe3mEjwW8FvMtU5CS O3jLKQhNKcsCsuLb+I8Birex7YqgtW1S10/T5bu4cRpGrMFYqGcqpbggYirGmwxVA+XNZOrW/wBd hSVLaQj0/VUKfhZlboWHVfHFU7/aOKuG5+WKt4q7FUj84f8AHMi/4zL/AMQbCFK3yh/xy5f+M7f8 QXEqE+74FdirsVcemKreQpvsB3OKvIv+cij/AM6hqFBX9xa0p/zGLhViH/OJJrb6kKEfHN1+VtgU vo0Gvt88VaZgATUCg6+HucVeJf8AOQfn+wsLJNGhu1N3Pb3kM8cZiehlij4cgTyWofwwq81/IbyN qWuayNXkgraWd1ZTCVxKgZUlfnwKLxanp774qX1xGioiogoqgKo8ANhgVvFXYqw780f+Uft/+YtP +TcmEILvyu/44Fx/zFv/AMm48SoZj3wJdirsVdirzD85vyrs/NWjCe25xajbMzRGNJJ2Yzyxc6IH UfZQ9sVeGeVfPfnX8stVm0iexuH0u3uZ3czRC2V/hMCtyeKQqCY1p8XthV9DeXvze8l6mr+pq2m2 rqTRWv4CSBx33K/zYFTO/wDzK8m2qAx6zp07EgcVvYAQDXfZm8MVYdY6x5j8+aukFxZz6doCMl0C 0ZlikEZWKSETcIT8XN9w23hhQ9N0zTrTTLKOzs4+EEdeAqzU5MWO7Fj1bxwJRa7VJ6nFWwTXFW8V diqR+cP+OZF/xmX/AIg2EKVvlD/jly/8Z2/4guJUJ93wK7FXYq0w29+2KqU8sMURa4lWKP8AmchQ N/EkYq8M/wCcifM9gdHurC1uIZ2a2t9o5UY1W73HEVPRcKsP/wCccfN2neXVvl1KSG2MhlK/WJlg ry9ClOY3+wcVL39fzJ8msnP9Nacd6cfrsH3/AGsCvP8Azt+e00FhPbeXbBdQvpKxRtaXCzsvOM0f 01ikqFegw0rzfQ/y683fmRraa55lS7tI5JoA0Utk6goCIpPjT6v+zCKmm2Kvo/yR5I0nyjoyaZpy 8QtfUkq/x1d3GzvJSnqHvgVkeKuxV2KsO/NH/lH7f/mLT/k3JhCC78rv+OBcf8xb/wDJuPEqGY98 CXYq7FXYqtbY16+AxViPmj8r/JvmMyvqdh6ss4HOX1Z1/b9TokiD7RxVgaf84weVbeTla3Hpkihb hM21em9wfDCqb2P/ADj95RiYtfD66SCFX9/FTpv8E3zxV6RpuladpdolpYRejbxBgicmf7TFiKsW O5OBUWp2+zT2xVsbnftireKuxV2KpH5w/wCOZF/xmX/iDYQpW+UP+OXL/wAZ2/4guJUJ93wK7FXY q01ex3xVCanp8WoWpt5DQGm+/Yg9iPDFWF6r+SvkzVpjLqcH1gsKMOc6VHIsPsSr+0cKoMf84+/l zy5fUe1P726/6r4FXj8g/wAvwPgs6D/jJcn/AJnYqmem/k3+XenTC5t9LpcKP7z17k9CG6GUjsMV ZXp9na2UItrWP0YU+ypLNWpJO7EnqcVRHI8iKbClDiq/FXYq7FWHfmj/AMo/b/8AMWn/ACbkwhBd +V3/ABwLj/mLf/k3HiVDMe+BLsVdirsVdQYq6gxV2KuxV1B4Yq7FXYq7FXYq7FUj84f8cyL/AIzL /wAQbCFK3yh/xy5f+M7f8QXEqE+74FdirsVdirqDwxV1BirqDFXYq6gxV1B4Yq7FXYq7FXYqw780 f+Uft/8AmLT/AJNyYQgu/K7/AI4Fx/zFv/ybjxKhmPfAl2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2 KpH5w/45kX/GZf8AiDYQpW+UP+OXL/xnb/iC4lQn3fArsVdirsVdirsVdirsVdirsVdirsVdirsV Yd+aP/KP2/8AzFp/ybkwhBd+VxA8v3BPT62//JuPEqGYVGBLeKuxV2KuxV2KuxV2KuxV2KuxV2Ku xV2KpF5xIGmRf8Zl/wCINhClrygP9xkv/Gdv+ILiVCfDxwK7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FWG/miQfL1v/zFp/yakwhBYz5B/MLRLDRZo3huW5XLNssZ6xoP5x4Yqyf/AJWn5fr/ALz3f/AR /wDVTGltofmj5e6/V7vf/Ii/6qY0tt/8rR8v/wDLPd/8BH/1Uxpbd/ytHy//AMs93/wEf/VTGlt3 /K0fL/8Ayz3f/AR/9VMaW3f8rR8v/wDLPd/8BH/1Uxpbd/ytHy//AMs93/wEf/VTGlt3/K0fL/8A yz3f/AR/9VMaW3f8rR8v/wDLPd/8BH/1Uxpbd/ytHy//AMs93/wEf/VTGlt3/K0fL/8Ayz3f/AR/ 9VMaW3f8rR8v/wDLPd/8BH/1Uxpbd/ytHy//AMs93/wEf/VTGlt3/K0fL/8Ayz3f/AR/9VMaW0p8 yfmRoFzYpGILoUlDbpH/ACsP9+HxxpW/Lv5kaDa2Lo0F0ayk7JH/ACr/AMWDwxpU1/5WjoFK/V7v /gI/+qmNLbv+Vo+X/wDlnu/+Aj/6qY0tu/5Wj5f/AOWe7/4CP/qpjS27/laPl/8A5Z7v/gI/+qmN Lbv+Vo+X/wDlnu/+Aj/6qY0tu/5Wj5f/AOWe7/4CP/qpjS27/laPl/8A5Z7v/gI/+qmNLbv+Vo+X /wDlnu/+Aj/6qY0tu/5Wj5f/AOWe7/4CP/qpjS27/laPl/8A5Z7v/gI/+qmNLbv+Vo+X/wDlnu/+ Aj/6qY0tu/5Wj5f/AOWe7/4CP/qpjS27/laPl/8A5Z7v/gI/+qmNLbR/NHy9T/ee7/4CL/qpjS2x n8wfzA0TUNGhijhuV43KtVljHRHHZz44gK//2Q== + + + + + + uuid:29C09F13AEC6DB11BC0AA54CE310CD49 + uuid:cd800517-969b-4ba6-bcf4-3c4578b73623 + + uuid:57055BE5A0C6DB11AB4DF0E013A21B3B + uuid:210105194FB6DB118741A18F31A55BD8 + + + + 1 + Dot Gain 20% + + + + Adobe PDF library 7.77 + + + + + + + + + + + + + + + + + + + + + + + + + +endstream endobj xref +0 20 +0000000003 00000 f +0000000016 00000 n +0000000076 00000 n +0000000004 00001 f +0000000000 00000 f +0000000126 00000 n +0000000630 00000 n +0000000701 00000 n +0000000870 00000 n +0000001850 00000 n +0000013060 00000 n +0000031943 00000 n +0000032055 00000 n +0000032217 00000 n +0000035399 00000 n +0000035592 00000 n +0000035767 00000 n +0000035814 00000 n +0000036327 00000 n +0000036600 00000 n +trailer +<<0EDAAA5837D3B440B2D05AEDC709E61F>]>> +startxref +56291 +%%EOF diff --git a/isis/src/base/apps/desmear/Makefile b/isis/src/base/apps/desmear/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/desmear/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/desmear/desmear.cpp b/isis/src/base/apps/desmear/desmear.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da237d45a70e03e774957ae601334e8d64f91017 --- /dev/null +++ b/isis/src/base/apps/desmear/desmear.cpp @@ -0,0 +1,82 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void desmear (Buffer &in, Buffer &out); +double smearScale; //Declare global variable + +void IsisMain() { + + // We will be processing by line + ProcessByLine p; + + // Setup the input and output cubes + Cube *icube = p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + + // Get exposure duration and tranfer time + // Override the lable values if the user entered a value + double expTime,xferTime; + UserInterface &ui = Application::GetUserInterface(); + if (ui.WasEntered ("DURATION")) { + expTime = ui.GetDouble ("DURATION"); + } + else { + PvlGroup grp = icube->GetGroup("ISIS_INSTRUMENT"); + expTime = grp["EXPOSURE_DURATION"]; + } + + if (ui.WasEntered ("TRANSFER")) { + xferTime = ui.GetDouble ("TRANSFER"); + } + else { + PvlGroup grp = icube->GetGroup("ISIS_INSTRUMENT"); + xferTime = grp["TRANSFER_TIME"]; + } + + // Calculate the smear scale + smearScale = xferTime / expTime / icube->Lines(); + + // Start the processing + p.StartProcess(desmear); + p.EndProcess(); +} + +// Line processing routine +void desmear (Buffer &in, Buffer &out) { + //make an array that is size of number of samples and fill with zeros. + static vector smear; + if (in.Line() == 1) { + smear.resize(in.size()); + for (int i=0; i + + + + Remove frame transfer smear + + + + This program removes the frame transfer smear from a CCD + camera. Transfer smear is the build up of residual enegy as the data is read + from the detector, line by line. The current algorithm is written to remove smear for a + CCD that reads data at the top of the detector. No visual examples have + been included because, the difference between the input and output is only a + few DN values. + + + + Radiometric and Photometric Correction + Mars Exploration Rover + + + + + Original version, algorithm from Andrew E. Johnson + (aej@robotics.jpl.nasa.gov). + + + Converted to Isis 3.0 + + + Documentation fixes + + + Removed references to CubeInfo + + + + + + + cube + input + + Input file to be corrected + + + The input cube that will be corrected for CCD smear. + + + *.cub *.lbl + + + + + cube + real + output + + Output cube + + + The smear corrected output cube + + + *.cub + + + + + + + double + + From labels + + Exposure duration of input file. + + The exposure duration value to be used in the smear calculation. + Exposure duration is the value of time between the opening and closing + of a instrument aperture.

    + If NO value is entered by the user, the value will be filled + with the exposure duration keyword from the Instrument group

    + The exposure duration value must be in the same units as the transfer time. +
    +
    + + + double + + From labels + + Frame transfer time + + Time required to transfer data from from active imaging area.

    + If NO value is entered by the user, the value will be filled + with the transfer time keyword from the Instrument group.

    + The transfer time value must be in the same units as the exposure duration +
    +
    +
    +
    +
    diff --git a/isis/src/base/apps/desmear/tsts/Makefile b/isis/src/base/apps/desmear/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/desmear/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/desmear/tsts/case01/Makefile b/isis/src/base/apps/desmear/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..912b76de0169d661041931bd0ff88e26c285fcf2 --- /dev/null +++ b/isis/src/base/apps/desmear/tsts/case01/Makefile @@ -0,0 +1,10 @@ +APPNAME = desmear + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/DesmearTest.cub \ + to=$(OUTPUT)/DesmearTruth.cub \ + duration=4961.28 \ + transfer=10.24 \ + > /dev/null; diff --git a/isis/src/base/apps/desmear/tsts/case02/Makefile b/isis/src/base/apps/desmear/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cd03cd924ff1cfd6b0d36b89df1251330f712696 --- /dev/null +++ b/isis/src/base/apps/desmear/tsts/case02/Makefile @@ -0,0 +1,9 @@ +APPNAME = desmear + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/DesmearTest.cub \ + to=$(OUTPUT)/DesmearTruth.cub \ + transfer=10.24 \ + > /dev/null; diff --git a/isis/src/base/apps/desmear/tsts/case03/Makefile b/isis/src/base/apps/desmear/tsts/case03/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..62da2d355994073186e60281da83f1236e755bd7 --- /dev/null +++ b/isis/src/base/apps/desmear/tsts/case03/Makefile @@ -0,0 +1,9 @@ +APPNAME = desmear + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/DesmearTest.cub \ + to=$(OUTPUT)/DesmearTruth.cub \ + duration=4961.28 \ + > /dev/null; diff --git a/isis/src/base/apps/divfilter/Makefile b/isis/src/base/apps/divfilter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/divfilter/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/divfilter/assets/image/divfilter.jpg b/isis/src/base/apps/divfilter/assets/image/divfilter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ff30ec21068e56ed7eedb9fd946fc06268c28fa0 Binary files /dev/null and b/isis/src/base/apps/divfilter/assets/image/divfilter.jpg differ diff --git a/isis/src/base/apps/divfilter/assets/image/divfilterExample.jpg b/isis/src/base/apps/divfilter/assets/image/divfilterExample.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d0d2454063d11dbd6a883116d2ee0d58194ea66 Binary files /dev/null and b/isis/src/base/apps/divfilter/assets/image/divfilterExample.jpg differ diff --git a/isis/src/base/apps/divfilter/assets/image/divfilterGui.jpg b/isis/src/base/apps/divfilter/assets/image/divfilterGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f668f96b968f4c4af1f2245df138648776653052 Binary files /dev/null and b/isis/src/base/apps/divfilter/assets/image/divfilterGui.jpg differ diff --git a/isis/src/base/apps/divfilter/assets/image/peaks.4.jpg b/isis/src/base/apps/divfilter/assets/image/peaks.4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b0ae6226b663d73379a35cb4376afe7750711943 Binary files /dev/null and b/isis/src/base/apps/divfilter/assets/image/peaks.4.jpg differ diff --git a/isis/src/base/apps/divfilter/assets/thumb/divfilter.jpg b/isis/src/base/apps/divfilter/assets/thumb/divfilter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e0667f069816a8e427701e5dde12bd568e60181d Binary files /dev/null and b/isis/src/base/apps/divfilter/assets/thumb/divfilter.jpg differ diff --git a/isis/src/base/apps/divfilter/assets/thumb/divfilterGui.jpg b/isis/src/base/apps/divfilter/assets/thumb/divfilterGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..88a9345626192234f8d5306e61ebff1dabb33ce8 Binary files /dev/null and b/isis/src/base/apps/divfilter/assets/thumb/divfilterGui.jpg differ diff --git a/isis/src/base/apps/divfilter/assets/thumb/peaks.4.jpg b/isis/src/base/apps/divfilter/assets/thumb/peaks.4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db35c783931b3d40113de16690ce299fddc8187c Binary files /dev/null and b/isis/src/base/apps/divfilter/assets/thumb/peaks.4.jpg differ diff --git a/isis/src/base/apps/divfilter/divfilter.cpp b/isis/src/base/apps/divfilter/divfilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fcc0c4e1fe7a0f5646ecbc60fca434bbcefd8134 --- /dev/null +++ b/isis/src/base/apps/divfilter/divfilter.cpp @@ -0,0 +1,66 @@ +#include "Isis.h" +#include "ProcessByQuickFilter.h" +#include "UserInterface.h" + +using namespace std; +using namespace Isis; + +// Globals and prototypes +bool propagate; +void divfilter (Buffer &in, Buffer &out, QuickFilter &filter); + +// The divfilter main routine +void IsisMain() { + ProcessByQuickFilter p; + + // Open the input cube + p.SetInputCube("FROM"); + + // Setup the output cube + p.SetOutputCube("TO"); + + //Set up boxcar variables (minimum) + UserInterface &ui = Application::GetUserInterface(); + int lines = ui.GetInteger("LINES"); + int samples = ui.GetInteger("SAMPLES"); + int minimum; + if (ui.GetString("MINOPT") == "PERCENTAGE") { + int size = lines * samples; + double perc = ui.GetInteger("MINIMUM") / 100; + minimum = (int) (size * perc); + } + else { + minimum = ui.GetInteger("MINIMUM"); + } + + // Find out how to handle special pixels + propagate = ui.GetBoolean ("PROPAGATE"); + + // Process each line + p.StartProcess(divfilter); // Line processing function + p.EndProcess(); // Cleanup +} + +// Line processing routine +void divfilter (Buffer &in, Buffer &out, QuickFilter &filter) { + for (int i=0; i + + + + + Apply a spatial high pass filter to a cube (divide) + + + +

    + This program divides the pixel being processed by a low pass filter. + This has the general effect of highlighting the edges of grouped + contrasted DN values in the image, and therefore, feature changes will be + emphasized. Predominant changes will be emphasized with larger boxcars, + and smaller changes can be searched for using smaller boxcars. +

    +

    + This is done by convolving an NxM boxcar through the data, where + N and M are odd integers. In other words, the average DN value of the + boxcar is divided into its middle pixel DN value. Please refer to the + following diagram: +

    + + +

    + Thus, P(output) = P(input) / lowPassFilter, or P(s,l) = P(s,l) / + average(s,l,N,M) where P is the target pixel, s and l are the sample and + line position in the boxcar, N and M are the size of the boxcar (in this + case 3x3) and average(s,l,N,M) is the average of the NxM centered box. +

    +

    + For details on the box filtering see the following references: +

    +      M. J. McDonnell, Box-Filtering Techniques, Computer Graphics
    +      and Image Processing, Vol. 17, 1981, pages 65-70
    +
    +      E. M. Eliason and L. A. Soderblom, An Array Processing System
    +      for Lunar Geochemical and Geophysical Data,
    +      Porc. Lunar Sci. Conf. (8th) , 1977, pages 1163-1170.
    +    
    +

    +
    + + + Filters + + + + + highpass + lowpass + trimfilter + svfilter + noisfilter + + + + + + Original version + + + Ported to Isis 3.0 + + + Add example. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Updated application test to fix errors + + + Modified filename parameters to be cube parameters where necessary + + + Added Minopt parameter + + + Updated xml documentation with examples and new GUI configuration + + + + + boxfilter + + + + + + cube + input + + Input file + + + Input cube to filter + + + *.cub + + + + cube + real + output + + Output cube + + + The resultant filtered cube + + + + + + + integer + + Number of samples in boxcar + + + + This is the total number of samples in the boxcar. + It must be odd and can not exceed twice the number of samples + in the cube. In general, due to the computational algorithm, + the size of the boxcar does not cause the program to operate + significantly slower. (See Eliason/Soderblom document) + + + + + 1 + + + + integer + + Number of lines in boxcar + + + This is the total number of lines in the boxcar. + It must be odd and can not exceed twice the number of lines + in the cube. In general, due to the computational algorithm, + the size of the boxcar does not cause the program to operate + significantly slower. (See Eliason/Soderblom document) + + + 1 + + + + + + double + + Valid minimum pixel + + + Valid minimum pixel value that will be used in boxcar computation. If + a pixel value is less than LOW then it will not be used when + computing boxcar statistics. + + + Use all pixels + + + HIGH + + + + + double + + Valid maximum pixel + + + Valid maximum pixel value that will be used in boxcar computation. If + a pixel value is greater than HIGH then it will not be used when + computing boxcar statistics. + + + Use all pixels + + + LOW + + + + + string + + COUNT + + + Sets minimum to be either a count or a percentage + + + This parameter determines whether the minimum + parameter is to be interpreted as a count of pixels, or a + percentage of all pixels in the boxcar. + + + + + + + + + + integer + + Minimum boxcar pixel count + + + This is the minimum number of valid pixels which must occur inside the + NxM boxcar for filtering to occur. For example, 3x5 boxcar has 15 pixels + inside. If MINIMUM=10 then the filter will occur if there are 10 or + greater valid pixels. A valid pixel is one that is not special (NULL, LIS, + etc) and is in the range defined by LOW to HIGH. + + + 1 + + 1 + + + + + + boolean + TRUE + Propagate special pixels + + This option is used to define how special pixels are handled. If the + center pixel of the boxcar(input) is a special pixel, the output pixel + will contain the same special pixel, or set to NULL depending on the + value of this parameter. + + + + + + + 101x101 + + Use a 101x101 boxcar + + + f=peaks.cub:4 t=divfilter s=101 li=101 + + + In this example the boxcar size is 101 by 101. + + + + + + Input image for divfilter + This is the input image for the divfilter example. + + + FROM + + + + + + Output image for divfilter + This is the output image for this example of divfilter. It is the same as running lowpass and dividing the input image by the lowpass output using the ratio application. + + + TO + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a divide filter of the input image with a boxcar of 101x101. + + + + + + +
    diff --git a/isis/src/base/apps/divfilter/tsts/Makefile b/isis/src/base/apps/divfilter/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/divfilter/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/divfilter/tsts/default/Makefile b/isis/src/base/apps/divfilter/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2a324f85b5dfdf565e36fc4e678cb6eb1b12f464 --- /dev/null +++ b/isis/src/base/apps/divfilter/tsts/default/Makefile @@ -0,0 +1,13 @@ +APPNAME = divfilter + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/divFilterTruth1.cub \ + samples= 11 \ + lines= 11 \ + low= -1e-20 \ + high= 1e+20 \ + minimum= 85 \ + propagate= True > /dev/null; diff --git a/isis/src/base/apps/dstripe/Makefile b/isis/src/base/apps/dstripe/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/dstripe/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/dstripe/assets/image/dstripegui.jpg b/isis/src/base/apps/dstripe/assets/image/dstripegui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a6d2ddde3c9251015ddb962fde98e11fdac900dd Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/image/dstripegui.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/image/input.jpg b/isis/src/base/apps/dstripe/assets/image/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a72ccd6ff47f556e3ed7a2244931aa244df29e66 Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/image/input.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/image/inputHist.jpg b/isis/src/base/apps/dstripe/assets/image/inputHist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ae5501636433b5a9f60d4080c3312356d16a79d2 Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/image/inputHist.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/image/low.jpg b/isis/src/base/apps/dstripe/assets/image/low.jpg new file mode 100644 index 0000000000000000000000000000000000000000..493d8d0acf67bb952193075ee0b57352dbd5f8d2 Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/image/low.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/image/lowHist.jpg b/isis/src/base/apps/dstripe/assets/image/lowHist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4470cf6248a294d9a08a0d8b898459bfa0af1c8b Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/image/lowHist.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/image/noise.jpg b/isis/src/base/apps/dstripe/assets/image/noise.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3d475aad949a639deb35d81fe239c750f33bf13b Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/image/noise.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/image/noiseHist.jpg b/isis/src/base/apps/dstripe/assets/image/noiseHist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d570ebff0c24b22495ee02e3c64c0963df199cff Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/image/noiseHist.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/image/output.jpg b/isis/src/base/apps/dstripe/assets/image/output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..321133140408a755a80a24514ef2f3d53c784332 Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/image/output.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/image/outputHist.jpg b/isis/src/base/apps/dstripe/assets/image/outputHist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3b7dfe46b94db1c2ceeb757b5cc0d4800df20b4a Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/image/outputHist.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/thumb/dstripegui.jpg b/isis/src/base/apps/dstripe/assets/thumb/dstripegui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6557d8c2109beabc8d8784b157025b1a5f30f35f Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/thumb/dstripegui.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/thumb/input.jpg b/isis/src/base/apps/dstripe/assets/thumb/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac65ae6a38cba2834635911474663d7ae415f41f Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/thumb/input.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/thumb/inputHist.jpg b/isis/src/base/apps/dstripe/assets/thumb/inputHist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..caf1e865b292b108d06a9197a6f58335cfaedc02 Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/thumb/inputHist.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/thumb/low.jpg b/isis/src/base/apps/dstripe/assets/thumb/low.jpg new file mode 100644 index 0000000000000000000000000000000000000000..834faf64101d2fc3b4c9021b15cc8fd9dfd74d8d Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/thumb/low.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/thumb/lowHist.jpg b/isis/src/base/apps/dstripe/assets/thumb/lowHist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..53ba81e4c0bf88830b119073dd18c7db92ddde6a Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/thumb/lowHist.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/thumb/noise.jpg b/isis/src/base/apps/dstripe/assets/thumb/noise.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1ef5b87a28a1cba555c3523cab4dae10375b13d7 Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/thumb/noise.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/thumb/noiseHist.jpg b/isis/src/base/apps/dstripe/assets/thumb/noiseHist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..728fb431db9af29e45e37286f62660551b53ad25 Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/thumb/noiseHist.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/thumb/output.jpg b/isis/src/base/apps/dstripe/assets/thumb/output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0d13d4308bfa0f2a55525832bc09f7516e4a8aaf Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/thumb/output.jpg differ diff --git a/isis/src/base/apps/dstripe/assets/thumb/outputHist.jpg b/isis/src/base/apps/dstripe/assets/thumb/outputHist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..98a2eac62e5d49502dc506a11099c68f6c9d63c0 Binary files /dev/null and b/isis/src/base/apps/dstripe/assets/thumb/outputHist.jpg differ diff --git a/isis/src/base/apps/dstripe/dstripe.cpp b/isis/src/base/apps/dstripe/dstripe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f3ffda93feb2df0f65dfb9ede8d2f90c0dffe671 --- /dev/null +++ b/isis/src/base/apps/dstripe/dstripe.cpp @@ -0,0 +1,117 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "Application.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void difference (vector &input, vector &output); + +void IsisMain() { + ProcessByLine p; + Cube *icube = p.SetInputCube("FROM"); + UserInterface &ui = Application::GetUserInterface(); + int highLines, highSamples, lowLines, lowSamples; + + // Get the boxcar sizes to be used by the low and highpass filters + // All numbers have to be odd. If nothing is entered into the UI, + // NS and/or NL are used. + if(ui.GetString("MODE") == "VERTICAL") { + if(ui.WasEntered("VHNS")) { + highSamples = ui.GetInteger("VHNS"); + } + else { + highSamples = icube->Samples(); + if(highSamples % 2 == 0) highSamples -= 1; + } + + if(ui.WasEntered("VLNL")) { + lowLines = ui.GetInteger("VLNL"); + } + else { + lowLines = icube->Lines(); + if(lowLines % 2 == 0) lowLines -= 1; + } + + lowSamples = ui.GetInteger("VLNS"); + highLines = ui.GetInteger("VHNL"); + } + else { + if(ui.WasEntered("HHNL")) { + highLines = ui.GetInteger("HHNL"); + } + else { + highLines = icube->Lines(); + if(highLines % 2 == 0) highLines -= 1; + } + + if(ui.WasEntered("HLNS")) { + lowSamples = ui.GetInteger("HLNS"); + } + else { + lowSamples = icube->Samples(); + if(lowSamples % 2 == 0) lowSamples -= 1; + } + + highSamples = ui.GetInteger("HHNS"); + lowLines = ui.GetInteger("HLNL"); + } + + // Algorithm: lowpass(from, temp) -> hipass(temp, noise) -> to = from-noise + + // Run lowpass filter on input + string lowParams = ""; + lowParams += "from= " + ui.GetFilename("FROM"); + lowParams += " to= dstripe.temporary.cub "; + lowParams += " samples= " + iString(lowSamples); + lowParams += " lines= " + iString(lowLines); + + Isis::iApp->Exec("lowpass", lowParams); + + // Make a copy of the lowpass filter results if the user wants it + if(!ui.GetBoolean("DELETENOISE")) { + string lowParams = ""; + lowParams += "from= " + ui.GetFilename("FROM"); + lowParams += " to= " + ui.GetFilename("LPFNOISE"); + lowParams += " samples= " + iString(lowSamples); + lowParams += " lines= " + iString(lowLines); + Isis::iApp->Exec("lowpass", lowParams); + } + + // Run highpass filter after lowpass is done, i.e. highpass(lowpass(input)) + string highParams = ""; + highParams += "from= dstripe.temporary.cub "; + highParams += " to= " + ui.GetFilename("NOISE") + " "; + highParams += " samples= " + iString(highSamples); + highParams += " lines= " + iString(highLines); + + Isis::iApp->Exec("highpass", highParams); + remove("dstripe.temporary.cub"); + + // Take the difference (FROM-NOISE) and write it to output + p.SetInputCube("NOISE"); + p.SetOutputCube("TO"); + p.StartProcess(difference); + p.EndProcess(); + if(ui.GetBoolean("DELETENOISE")) { + string noiseFile(Filename(ui.GetFilename("NOISE")).Expanded()); + remove(noiseFile.c_str()); + } +} + +// Subtracts noise from the input buffer, resulting in a cleaner output image +void difference(vector &input, vector &output) { + Buffer& from = *input[0]; + Buffer& noise = *input[1]; + Buffer& to = *output[0]; + + for(int i = 0; i < from.size(); i++) { + if(IsSpecial(from[i]) || IsSpecial(noise[i])) { + to[i] = from[i]; + } + else { + to[i] = from[i] - noise[i]; + } + } +} diff --git a/isis/src/base/apps/dstripe/dstripe.xml b/isis/src/base/apps/dstripe/dstripe.xml new file mode 100644 index 0000000000000000000000000000000000000000..2e2bd891c617a540499f34a22df72ad059349897 --- /dev/null +++ b/isis/src/base/apps/dstripe/dstripe.xml @@ -0,0 +1,352 @@ + + + + + + Remove horizontal or vertical stripes/noise from a cube + + + + This program uses a combination of lowpass and highpass filters to remove horizontal or vertical stripes in a cube. The steps + behind the noise removal technique are: +
    +       output = input - noise
    +       where noise = highpass(lowpass(input))
    +    
    + +

    + Suppose an input image had vertical striping noise, + like in the example below. The noise can be removed or suppressed by + applying a sequence of lowpass and highpass filters. The idea is to + create an image containing only the noise and subtract that noise image + from the original. +

    + +

    + First, we apply a tall (1xNL) lowpass filter to the input image. This + produces an image that is essentially a column average. The high + frequency information has been suppressed and the vertical noise is + left behind. Note however, the average of the lowpass filter + matches the original input so we can not subtract the noise quite yet. +

    + +

    + Second, we appy a (NSx1) highpass filter to the lowpass image. This + effectively suppress the albedo information in the noise leaving only the + noise behind. Note that the noise (third) histogram is centered + about zero. +

    + +

    + Finally, the noise image is subtracted from the original input image + resulting in the desired noise-free image. All the steps the program + goes through (along with their respective histograms) are illustrated + below: +

    + + Input image + After lowpass + After highpass + Output image

    + Input histogram + Lowpass histogram + Highpass histogram + Output histogram

    + From left to right: Input, Lowpass, Highpass, Output +
    + + + Filters + + + + + highpass + lowpass + cubenorm + + + + + + Original version + + + Ported to Isis 3.0 + + + Changed destriping algorithm + + + Removed references to CubeInfo + + + + + + + cube + input + + Input file with striping + + + Name of the input cube which has horizontal or vertical striping + + + *.cub + + + + + + + cube + output + + Output destriped cube + + + The resultant cube which will have suppressed or removed striping + + + *.cub + + + + + + + + + string + VERTICAL + Type of noise + + This allows the user to specify which kind of striping noise needs + to be removed. + + + + + + + + + + + + integer + Number of lines + Vertical Lowpass Number of Lines + + This is the number of the lines to be used by lowpass + + 1 + + + + + integer + 1 + Vertical Lowpass Number of Samples + + This is the number of the samples to be used by lowpass + + 1 + + + + + integer + 1 + Vertical Highpass Number of Lines + + This is the number of the lines to be used by highpass + + 1 + + + + + integer + Number of samples + Vertical Highpass Number of Samples + + This is the number of the samples to be used by highpass + + 1 + + + + + + + integer + 1 + Horizontal Lowpass Number of Lines + + This is the number of the lines to be used by lowpass + + 1 + + + + + integer + Number of samples + Horizontal Lowpass Number of Samples + + This is the number of the samples to be used by lowpass + + 1 + + + + integer + Number of lines + Horizontal Highpass Number of Lines + + This is the number of the lines to be used by highpass + + 1 + + + + + integer + 1 + Horizontal Highpass Number of Samples + + This is the number of the samples to be used by highpass + + 1 + + + + + + + boolean + TRUE + Delete the noise file + + This will delete the noise file after the image is processed. + + + LPFNOISE + NOISE + + + + + cube + input + lowpass.noise.cub + + Lowpass filter noise file + + + The results of running lowpass(input) + + + *.cub + + + + + cube + input + dstripe.noise.cub + + Temporary work file + + + The results of running highpass(lowpass(input)) + + + *.cub + + + + + + + + + Vertical stripe removal + + This example shows the results of removing vertical striping noise from an image. + + + + from=../LO_4090_h1.cub to=../result.cub + + + Using default settings to remove striping noise from input file + + + + + + Input image for dstripe + This is a Lunar Orbitor image with vertical striping. + + + FROM + + + + Noise image from dstripe + This is a result of the low and highpass filters of the input image. + + + NOISE + + + + + + Output image from destriping + This is the output image that results. + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform + a destriping operation on the input image. + + + + + + +
    diff --git a/isis/src/base/apps/dstripe/tsts/Makefile b/isis/src/base/apps/dstripe/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/dstripe/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/dstripe/tsts/default/Makefile b/isis/src/base/apps/dstripe/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d474d51b3b6f977352098587bfcfd94e3e2d743a --- /dev/null +++ b/isis/src/base/apps/dstripe/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = dstripe + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/dstrTruth1.cub > /dev/null; diff --git a/isis/src/base/apps/editlab/Makefile b/isis/src/base/apps/editlab/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/editlab/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/editlab/editlab.cpp b/isis/src/base/apps/editlab/editlab.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3ebc9163ecb011154d8638f5c1b6bd6ade1efb3 --- /dev/null +++ b/isis/src/base/apps/editlab/editlab.cpp @@ -0,0 +1,107 @@ +#include "Isis.h" +#include "Pvl.h" +#include "Cube.h" +#include "Blob.h" +#include "History.h" +#include +#include +#include + +using namespace Isis; +using namespace std; + +void IsisMain(){ + + // Open the input cube + UserInterface &ui = Application::GetUserInterface(); + Cube cube; + cube.Open(ui.GetFilename("FROM"), "rw"); + + // Extract label from cube file + Pvl *label = cube.Label(); + + // Get user entered option & create IsisCube Object + string option = ui.GetString("OPTION"); + PvlObject &o = label->FindObject("IsisCube"); + + // Add Template File + if(option=="ADDTEMP") { + string tempfile = ui.GetFilename("TEMPFILE"); + Pvl tempobj(tempfile); + for(int i=0; i + + + Modifies cube labels + + + This program will allow the user to modify cube file labels. Modifications include adding, deleting or modifying + keywords in a group, adding and deleting entire groups, and adding template files. Adding a + group will add a new, empty group to the label, and you will have to rerun the program to add any keywords + you want in the group individually. A way around this is creating a template file of groups and keywords you + would like to add and then adding the template file to the label. When a group is deleted, all the keywords + inside the group are deleted also. + + + + Utility + + + + + catlab + + + + + labels + + + + + Original version + + + Fixed appTest + + + Fixed xml issues + + + Documentation fixes + + + Added Comment allocation and fixed documentation. + + + + + + + cube + input + + Cube file containing the label to be modified + + + The cube file containing the label to be modified. + + + *.cub + + + + + + string + Options for modifying label + + A list of the different types of modifications allowed on the label. + + ADDKEY + + + + + + + + + + + + + string + Group to modify + + Group that is being added, deleted, or modified. + + + + string + Keyword to modify + + Keyword that is being added, deleted, or modified. + + + + string + Value of Keyword being modified + + The value of the Keyword being added or modified. + + + + string + none + Units of Keyword being modified + + The units associated with the Keyword being added or modified. + + + + filename + input + Template file being added to label + + Adds the PvlGroups defined within the template file to the + cube's labels. + + + + string + none + Comment to be added to the change + + When adding or modifying a PvlGroup or PvlKeyword, then this comment + is added to that altered PvlGroup or PvlKeyword. + + + + + + + + Adding a group + + This example uses the editlab application to add a new group to a previously blank label. The new + group created will be empty. + + + from=new.cub option=addg grpname=NewGroup + + + Run the editlab application to add a group to a label + + + + + + +
    
    +        Starting Label
    +        
    +Object = Label
    +  Bytes = 65536
    +End_Object
    +
    +Object = IsisCube
    +  Object = Core
    +    /* Location of the core
    +    StartByte   = 65537
    +    Format      = Tile
    +    TileSamples = 128
    +    TileLines   = 128
    +
    +    Group = Dimensions
    +      Samples = 1024
    +      Lines   = 1024
    +      Bands   = 7
    +    End_Group
    +
    +    Group = Pixels
    +      Type       = Real
    +      ByteOrder  = LSB
    +      Base       = 0.0
    +      Multiplier = 1.0
    +    End_Group
    +  End_Object
    +End_Object
    +End
    +        
    +
    +
    + + + + Label after the command line is ran +
    +Object = Label
    +  Bytes = 65536
    +End_Object
    +
    +Object = IsisCube
    +  Object = Core
    +    /* Location of the core
    +    StartByte   = 65537
    +    Format      = Tile
    +    TileSamples = 128
    +    TileLines   = 128
    +
    +    Group = Dimensions
    +      Samples = 1024
    +      Lines   = 1024
    +      Bands   = 7
    +    End_Group
    +
    +    Group = Pixels
    +      Type       = Real
    +      ByteOrder  = LSB
    +      Base       = 0.0
    +      Multiplier = 1.0
    +    End_Group
    +  End_Object
    +
    +  Group = NewGroup
    +  End_Group
    +End_Object
    +End
    +      
    +
    +
    +
    +
    + + Adding a keyword + + This example uses the editlab application to add a keyword to the empty group created in the last example. + + + from=new.cub option=addkey grpname=NewGroup keyword=Keyword value=new + + + Run the editlab application to add a keyword to an existing group + + + + + + +
    +Object = Label
    +  Bytes = 65536
    +End_Object
    +
    +Object = IsisCube
    +  Object = Core
    +    /* Location of the core
    +    StartByte   = 65537
    +    Format      = Tile
    +    TileSamples = 128
    +    TileLines   = 128
    +
    +    Group = Dimensions
    +      Samples = 1024
    +      Lines   = 1024
    +      Bands   = 7
    +    End_Group
    +
    +    Group = Pixels
    +      Type       = Real
    +      ByteOrder  = LSB
    +      Base       = 0.0
    +      Multiplier = 1.0
    +    End_Group
    +  End_Object
    +
    +  Group = NewGroup
    +    Keyword = new
    +  End_Group
    +End_Object
    +End
    +        
    +
    +
    +
    +
    + + Modifying a keyword + + This example uses the editlab application to modify the keyword created in the previous example to change its value. + + + from=new.cub option=modkey grpname=NewGroup keyword=Keyword value=old + + + Run the editlab application to modify a preexisting keyword + + + + + + +
    +Object = Label
    +  Bytes = 65536
    +End_Object
    +
    +Object = IsisCube
    +  Object = Core
    +    /* Location of the core
    +    StartByte   = 65537
    +    Format      = Tile
    +    TileSamples = 128
    +    TileLines   = 128
    +
    +    Group = Dimensions
    +      Samples = 1024
    +      Lines   = 1024
    +      Bands   = 7
    +    End_Group
    +
    +    Group = Pixels
    +      Type       = Real
    +      ByteOrder  = LSB
    +      Base       = 0.0
    +      Multiplier = 1.0
    +    End_Group
    +  End_Object
    +
    +  Group = NewGroup
    +    Keyword = old
    +  End_Group
    +End_Object
    +End
    +        
    +
    +
    +
    +
    + + Adding a template file + + This example uses the editlab application to add more than one group (containing keywords) at a time + by using a template file containing only groups and keywords to the label. + + + from=new.cub option=addtemp tempfile=template1.txt + + + Run the editlab application to add a template file to the label + + + + + + +
    +Object = Label
    +  Bytes = 65536
    +End_Object
    +
    +Object = IsisCube
    +  Object = Core
    +    /* Location of the core
    +    StartByte   = 65537
    +    Format      = Tile
    +    TileSamples = 128
    +    TileLines   = 128
    +
    +    Group = Dimensions
    +      Samples = 1024
    +      Lines   = 1024
    +      Bands   = 7
    +    End_Group
    +
    +    Group = Pixels
    +      Type       = Real
    +      ByteOrder  = LSB
    +      Base       = 0.0
    +      Multiplier = 1.0
    +    End_Group
    +  End_Object
    +
    +  Group = NewGroup
    +    Keyword = old
    +  End_Group
    +
    +  Group = test
    +    Key = insertme
    +  End_Group
    +
    +  Group = TwoKeys
    +    Key1 = (1, 2, 3)
    +    Key2 = "a b c"
    +  End_Group
    +End_Object
    +End
    +        
    +
    +
    +
    +
    + + Deleting a keyword + + This example uses the editlab application to erase a keyword added by the template file in example 4. + + + from=new.cub option=delkey grpname=TwoKeys keyword=Key1 + + + Run the editlab application to delete a keyword + + + + + + +
    +Object = Label
    +  Bytes = 65536
    +End_Object
    +
    +Object = IsisCube
    +  Object = Core
    +    /* Location of the core
    +    StartByte   = 65537
    +    Format      = Tile
    +    TileSamples = 128
    +    TileLines   = 128
    +
    +    Group = Dimensions
    +      Samples = 1024
    +      Lines   = 1024
    +      Bands   = 7
    +    End_Group
    +
    +    Group = Pixels
    +      Type       = Real
    +      ByteOrder  = LSB
    +      Base       = 0.0
    +      Multiplier = 1.0
    +    End_Group
    +  End_Object
    +
    +  Group = NewGroup
    +    Keyword = old
    +  End_Group
    +
    +  Group = test
    +    Key = insertme
    +  End_Group
    +
    +  Group = TwoKeys
    +    Key2 = "a b c"
    +  End_Group
    +End_Object
    +End
    +        
    +
    +
    +
    +
    + + Deleting a group + + This example uses the editlab application to delete a group from a label. Deleting a group will also + delete any keywords inside of the group. + + + from=new.cub option=delg grpname=TwoKeys + + + Run the editlab application to delete a group + + + + + + + template1.txt +
    +Group = test
    +  Key = insertme
    +End_Group
    +
    +Group = TwoKeys
    +  Key1 = ( 1, 2, 3)
    +  Key2 = "a b c"
    +End_Group
    +        
    +
    +
    + + + + Label +
    +Object = Label
    +  Bytes = 65536
    +End_Object
    +
    +Object = IsisCube
    +  Object = Core
    +    /* Location of the core
    +    StartByte   = 65537
    +    Format      = Tile
    +    TileSamples = 128
    +    TileLines   = 128
    +
    +    Group = Dimensions
    +      Samples = 1024
    +      Lines   = 1024
    +      Bands   = 7
    +    End_Group
    +
    +    Group = Pixels
    +      Type       = Real
    +      ByteOrder  = LSB
    +      Base       = 0.0
    +      Multiplier = 1.0
    +    End_Group
    +  End_Object
    +
    +  Group = NewGroup
    +    Keyword = old
    +  End_Group
    +
    +  Group = test
    +    Key = insertme
    +  End_Group
    +End_Object
    +End
    +        
    +
    +
    +
    +
    +
    + +
    diff --git a/isis/src/base/apps/editlab/tsts/Makefile b/isis/src/base/apps/editlab/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/editlab/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/editlab/tsts/delKey/Makefile b/isis/src/base/apps/editlab/tsts/delKey/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e37a6f0713794559c4eb6e73e9a985d1942dee0b --- /dev/null +++ b/isis/src/base/apps/editlab/tsts/delKey/Makefile @@ -0,0 +1,17 @@ +APPNAME = editlab +editlabTruth2.txt.IGNORELINES=ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + makecube \ + to=$(OUTPUT)/tempCube.cub \ + samples=1 \ + lines=13 \ + bands=13 > /dev/null; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=addg grpname=NewGroup ; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=addkey grpname=NewGroup keyword=Key1 value=null ; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=addkey grpname=NewGroup keyword=Key2 value=value ; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=delkey grpname=NewGroup keyword=Key1; + catlab from=$(OUTPUT)/tempCube.cub >& $(OUTPUT)/tempLab1.txt; + head -n 30 $(OUTPUT)/tempLab1.txt > $(OUTPUT)/editlabTruth2.txt; diff --git a/isis/src/base/apps/editlab/tsts/delg/Makefile b/isis/src/base/apps/editlab/tsts/delg/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..818f024097764c6826a6269ac6311eba59721f1c --- /dev/null +++ b/isis/src/base/apps/editlab/tsts/delg/Makefile @@ -0,0 +1,17 @@ +APPNAME = editlab +editlabTruth3.txt.IGNORELINES=ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + makecube \ + to=$(OUTPUT)/tempCube.cub \ + samples=1 \ + lines=13 \ + bands=13 > /dev/null; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=addg grpname=NewGroup ; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=addkey grpname=NewGroup keyword=Key1 value=null ; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=addkey grpname=NewGroup keyword=Key2 value=value ; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=delg grpname=NewGroup; + catlab from=$(OUTPUT)/tempCube.cub >& $(OUTPUT)/tempLab1.txt; + head -n 26 $(OUTPUT)/tempLab1.txt > $(OUTPUT)/editlabTruth3.txt; diff --git a/isis/src/base/apps/editlab/tsts/modkey/Makefile b/isis/src/base/apps/editlab/tsts/modkey/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4ca42e5f0a10475a8d2f31729ef2bddd5a5ee58b --- /dev/null +++ b/isis/src/base/apps/editlab/tsts/modkey/Makefile @@ -0,0 +1,17 @@ +APPNAME = editlab +editlabTruth1.txt.IGNORELINES=ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + makecube \ + to=$(OUTPUT)/tempCube.cub \ + samples=1 \ + lines=13 \ + bands=13 > /dev/null; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=addg grpname=NewGroup ; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=addkey grpname=NewGroup keyword=Key1 value=null ; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=addkey grpname=NewGroup keyword=Key2 value=value ; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=modkey grpname=NewGroup keyword=Key2 value=value units=meters; + catlab from=$(OUTPUT)/tempCube.cub >& $(OUTPUT)/tempLab1.txt; + head -n 31 $(OUTPUT)/tempLab1.txt > $(OUTPUT)/editlabTruth1.txt; diff --git a/isis/src/base/apps/editlab/tsts/modkey2/Makefile b/isis/src/base/apps/editlab/tsts/modkey2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e60bb8fea374b2f17ba422b635b17e1746e42214 --- /dev/null +++ b/isis/src/base/apps/editlab/tsts/modkey2/Makefile @@ -0,0 +1,18 @@ +APPNAME = editlab +editlabTruth3.txt.IGNORELINES=ByteOrder +tempLab3.txt.IGNORELINES=Bytes ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + makecube \ + to=$(OUTPUT)/tempCube.cub \ + samples=1 \ + lines=13 \ + bands=13 > /dev/null; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=addg grpname=NewGroup comment="New Group"; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=addkey grpname=NewGroup keyword=Key1 value=null comment="New Keyword"; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=addkey grpname=NewGroup keyword=Key2 value=value ; + $(APPNAME) from=$(OUTPUT)/tempCube.cub option=modkey grpname=NewGroup keyword=Key2 value=value units=meters comment="Hello World"; + catlab from=$(OUTPUT)/tempCube.cub >& $(OUTPUT)/tempLab3.txt; + head -n 31 $(OUTPUT)/tempLab3.txt > $(OUTPUT)/editlabTruth3.txt; diff --git a/isis/src/base/apps/edrget/Makefile b/isis/src/base/apps/edrget/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..246f0c3b5696faae7e2ce077d1c971669cb5d849 --- /dev/null +++ b/isis/src/base/apps/edrget/Makefile @@ -0,0 +1,12 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +BINS := $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps + diff --git a/isis/src/base/apps/edrget/edrget.cpp b/isis/src/base/apps/edrget/edrget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..992847b763353833a459587373adaf493a94c79d --- /dev/null +++ b/isis/src/base/apps/edrget/edrget.cpp @@ -0,0 +1,93 @@ +#include "Isis.h" + +#include +#include + +#include "httpget.h" +#include "ftpget.h" +#include "UserInterface.h" +#include "iString.h" +#include "iException.h" + +using namespace Isis; +using namespace std; + +void IsisMain() { + + // Get the file name from the GUI + UserInterface &ui = Application::GetUserInterface(); + iString guiURL = ui.GetString("URL"); + iString guiPath; + if (ui.WasEntered("TOPATH")) { + guiPath = ui.GetString("TOPATH"); + } + QUrl qurl(guiURL.c_str()); + //test if scheme is ftp and set port + if (qurl.scheme().toLower() == "ftp") { + qurl.setPort(21); + + if (ui.IsInteractive()) { + string parameters = "URL=" + guiURL; + if (ui.WasEntered("TOPATH")) { + parameters += " TOPATH=" + guiPath; + } + iApp->Exec("edrget", parameters); + } + else { + + FtpGet getter; + QObject::connect(&getter, SIGNAL(done()), QCoreApplication::instance(), SLOT(quit())); + //a false getFile return means no error and we sould execute the get. + if(!getter.getFile(qurl,guiPath)) QCoreApplication::instance()->exec(); + //if error occurred throw could not acquire + if (getter.error()) { + QString localFileName; + if (ui.WasEntered("TOPATH")){ + localFileName += guiPath.c_str(); + localFileName += "/"; + } + localFileName += QFileInfo(qurl.path()).fileName(); + string localFileNameStr(localFileName.toStdString()); + remove(localFileNameStr.c_str()); + iString msg = "Could not acquire [" + guiURL + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + } + //test is scheme is http and set port + else if (qurl.scheme().toLower() == "http") { + qurl.setPort(80); + + if (ui.IsInteractive()) { + string parameters = "URL=" + guiURL; + if (ui.WasEntered("TOPATH")) { + parameters += " TOPATH=" + guiPath; + } + iApp->Exec("edrget", parameters); + } + else { + HttpGet getter; + QObject::connect(&getter, SIGNAL(done()), QCoreApplication::instance(), SLOT(quit())); + //a false getFile return means no error and we sould execute the get. + if (!getter.getFile(qurl,guiPath)) QCoreApplication::instance()->exec(); + //if error occurred then throw could not acquire + if (getter.error()) { + QString localFileName; + if (ui.WasEntered("TOPATH")){ + localFileName += guiPath.c_str(); + localFileName += "/"; + } + string localFileNameStr(localFileName.toStdString()); + remove(localFileNameStr.c_str()); + iString msg = "Could not acquire [" + guiURL + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + } + //if scheme is not ftp or http throw error + else { + iString msg = "Scheme [" + qurl.scheme().toStdString() + "] not found, must be 'ftp' or 'http'"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } +} + diff --git a/isis/src/base/apps/edrget/edrget.xml b/isis/src/base/apps/edrget/edrget.xml new file mode 100644 index 0000000000000000000000000000000000000000..7541344f0c9d993eb179f0fbd98b6256187f5ee6 --- /dev/null +++ b/isis/src/base/apps/edrget/edrget.xml @@ -0,0 +1,70 @@ + + + + + Download network file using FTP or HTTP protocol. + + + + When the Uniform Resouce Locator (URL) of a desired file is entered, edrget will use + the FTP or HTTP protocol to download the requested file. The URL must contain the scheme, + domain, path, and filename.

    + URL Example:

    + ftp://host.gov/directory/sub_directory/image_name.QUB

    + or

    + http://host.gov/directory/sub_directory/image_name.QUB +
    + + + Import and Export + + + + + Original version + + + Added TOPATH parameter + + + Changed output to default to current working directory + + + Added an application test + + + + + + + + string + Uniform Resouce Locator (URL) of the desired file. + +

    + This is the Uniform Resource Locator (URL) for the network file to downloaded. The URL + must contain the scheme, domain name, path, and file name.

    + URL Example:

    + ftp://host.gov/directory/sub_directory/image_name.QUB

    + or

    + http://host.gov/directory/sub_directory/image_name.QUB +

    +
    +
    + + + string + The path to the output file + + This path describes where the output file is to be located. The + output filename will be derived from the URL. + + + Current Working Directory + + + +
    +
    + +
    diff --git a/isis/src/base/apps/edrget/ftpget.cpp b/isis/src/base/apps/edrget/ftpget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e0e99ff41ff558faa2f1a9b884ee09257100cef --- /dev/null +++ b/isis/src/base/apps/edrget/ftpget.cpp @@ -0,0 +1,113 @@ +#include +#include +#include + +#include "ftpget.h" +#include "iString.h" +#include "iException.h" +#include "Progress.h" +#include "Application.h" + +using namespace std; + +namespace Isis { + + FtpGet::FtpGet(QObject *parent) : QObject(parent) { + //conncet the Qftp done signal to the ftpDone function + connect(&p_ftp, SIGNAL(done(bool)), this, SLOT(ftpDone(bool))); + //connect the Qftp progress signal to the ftpProgress function(ISIS progress) + connect(&p_ftp, SIGNAL(dataTransferProgress(qint64,qint64)), + this, SLOT(ftpProgress(qint64,qint64))); + } + //************************************** + // getFile function will check URL, if URL is good function will connect, + // login, and get the file. This function returns P_error. + bool FtpGet::getFile(const QUrl &url, string topath) { + //next four if check the URL and return true is there is error. + if (!url.isValid()) { + string msg ="invalid URL"; + iException::Message(iException::User,msg,_FILEINFO_); + p_error = true; + return p_error; + } + if (url.scheme().toLower() != "ftp") { + string msg ="URL must start with 'ftp:'"; + iException::Message(iException::User,msg,_FILEINFO_); + p_error = true; + return p_error; + } + if (url.path().isEmpty()) { + string msg ="URL has no path"; + iException::Message(iException::User,msg,_FILEINFO_); + p_error = true; + return p_error; + } + + QString localFileName; + if (topath.size() != 0){ + localFileName += topath.c_str(); + localFileName += "/"; + } + localFileName += QFileInfo(url.path()).fileName(); + if (localFileName.isEmpty()) { + string msg ="URL has no filename"; + iException::Message(iException::User,msg,_FILEINFO_); + p_error = true; + return p_error; + } + // check local file. + p_file.setFileName(localFileName); + if (!p_file.open(QIODevice::WriteOnly)) { + string msg ="Cannot open output file"; + iException::Message(iException::User,msg,_FILEINFO_); + p_error = true; + return p_error; + } + + p_ftp.connectToHost(url.host(), url.port()); + p_ftp.login(); + p_ftp.get(url.path(), &p_file); + p_lastDone = -1; + p_error = false; + return p_error; + } + + void FtpGet::ftpDone(bool error) { + if (error) { + p_error = true; + iString msg =p_ftp.errorString().toStdString(); + msg.Remove("\n"); + iException::Message(iException::User,msg,_FILEINFO_); + } + else{ + p_error = false; + } + if (!p_error) { + p_file.close(); + // this was added because final size may not match progress size so + // you do not get 100% processed + if(!Application::GetUserInterface().IsInteractive()){ + cout<<"100% Processed" << endl; + } + } + emit done(); + return; + } + // ftpProgress uses the ISIS progress class to track progress + void FtpGet::ftpProgress(qint64 done, qint64 total) { + + if (total == 0) return; + if (total == -1) return; + if (p_error) return; + if (p_lastDone < 0) { + p_progress.SetText(string("Downloading File ") + p_file.fileName().toStdString() ); + p_progress.SetMaximumSteps(total); + p_progress.CheckStatus(); + p_lastDone = 1; + } + while (p_lastDone <= done) { + p_progress.CheckStatus(); + p_lastDone++; + } + } +} diff --git a/isis/src/base/apps/edrget/ftpget.h b/isis/src/base/apps/edrget/ftpget.h new file mode 100644 index 0000000000000000000000000000000000000000..fb4895120568dda67378d1e44f00b499357a9eb3 --- /dev/null +++ b/isis/src/base/apps/edrget/ftpget.h @@ -0,0 +1,40 @@ +#ifndef FTPGET_H +#define FTPGET_H + +#include +#include +#include "Progress.h" + +class QUrl; +namespace Isis{ + + class FtpGet : public QObject + { + Q_OBJECT + + public: + FtpGet(QObject *parent = 0); + + bool getFile(const QUrl &url, std::string topath); + + bool error() const{return p_error;}; + + + + signals: + void done(); + + private slots: + void ftpDone(bool error); + void ftpProgress(qint64 done, qint64 total); + + private: + QFtp p_ftp; + QFile p_file; + bool p_error; + int p_lastDone; + Progress p_progress; + + }; +} +#endif diff --git a/isis/src/base/apps/edrget/httpget.cpp b/isis/src/base/apps/edrget/httpget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b960b9d851bceeb7f7498b07d85f37ac2a3ccfc0 --- /dev/null +++ b/isis/src/base/apps/edrget/httpget.cpp @@ -0,0 +1,120 @@ +#include +#include +#include + +#include "httpget.h" +#include "iString.h" +#include "iException.h" +#include "Progress.h" + + +using namespace std; + +namespace Isis { + + HttpGet::HttpGet(QObject *parent) : QObject(parent) { + //connect the QHttp done signal to the httpDone function + connect(&p_http, SIGNAL(done(bool)), this, SLOT(httpDone(bool))); + //connect the QHttp progress signal to the httpProgress function(Isis progress) + connect(&p_http, SIGNAL(dataReadProgress(int,int)), + this, SLOT(httpProgress(int,int))); + } + //********************************************** + // getFile function will check URL, if URL is good the function will connect, + // login, and get the file. This function returns p_error + bool HttpGet::getFile(const QUrl &url, string topath) { + // The next four ifs will check the URL and return error is bad + if (!url.isValid()) { + string msg ="invalid URL"; + iException::Message(iException::User,msg,_FILEINFO_); + p_error = true; + return p_error; + } + if (url.scheme().toLower() != "http") { + string msg ="URL must start with 'http:'"; + iException::Message(iException::User,msg,_FILEINFO_); + p_error = true; + return p_error; + } + if (url.path().isEmpty()) { + string msg ="URL has no path"; + iException::Message(iException::User,msg,_FILEINFO_); + p_error = true; + return p_error; + } + + QString localFileName; + if (topath.size() != 0){ + localFileName += topath.c_str(); + localFileName += "/"; + } + localFileName += QFileInfo(url.path()).fileName(); + if (localFileName.isEmpty()) { + string msg ="URL has no filename"; + iException::Message(iException::User,msg,_FILEINFO_); + p_error = true; + return p_error; + } + // check the local file. + p_file.setFileName(localFileName); + if (!p_file.open(QIODevice::WriteOnly)) { + string msg ="Cannot open output file"; + iException::Message(iException::User,msg,_FILEINFO_); + p_error = true; + return p_error; + } + p_http.setHost(url.host(), url.port()); + p_http.get(url.path(), &p_file); + + p_lastDone = -1; + p_error = false; + return p_error; + } + + void HttpGet::httpDone(bool error) + { + map errLUT; + errLUT [204] = "No content"; + errLUT [301] = "Moved Permanently"; + errLUT [302] = "Moved Temporarily"; + errLUT [400] = "Bad Request"; + errLUT [401] = "Unauthorized"; + errLUT [403] = "Forbidden"; + errLUT [404] = "File Not Found"; + errLUT [500] = "Internal server Error"; + errLUT [502] = "Bad GateWay"; + errLUT [503] = "service Unavailable"; + + if (error) { + p_error = true; + string msg =p_http.errorString().toStdString(); + iException::Message(iException::User,msg,_FILEINFO_); + } + else if (p_http.lastResponse().statusCode() != 200 && p_http.lastResponse().statusCode() != 0) { + p_error = true; + string msg ="error code: [" + errLUT[p_http.lastResponse().statusCode()] + "]"; + iException::Message(iException::User,msg,_FILEINFO_); + } + else{ + p_error = false; + } + if (!p_error) p_file.close(); + emit done(); + return; + } + // This function setsup and useses Isis progress classs to track progress. + void HttpGet::httpProgress(int done, int total) { + if (total == 0) return; + if (p_error) return; + if (p_lastDone < 0) { + p_progress.SetText(string("Downloading File ") + p_file.fileName().toStdString() ); + p_progress.SetMaximumSteps(total); + p_progress.CheckStatus(); + p_lastDone = 1; + } + while (p_lastDone <= done) { + p_progress.CheckStatus(); + p_lastDone++; + } + } +} diff --git a/isis/src/base/apps/edrget/httpget.h b/isis/src/base/apps/edrget/httpget.h new file mode 100644 index 0000000000000000000000000000000000000000..3f868d8b71c90e846b9ff84e5416d9790968c644 --- /dev/null +++ b/isis/src/base/apps/edrget/httpget.h @@ -0,0 +1,39 @@ +#ifndef HTTPGET_H +#define HTTPGET_H + +#include +#include +#include "Progress.h" + +class QUrl; +namespace Isis{ + + class HttpGet : public QObject + { + Q_OBJECT + + public: + HttpGet(QObject *parent = 0); + + bool getFile(const QUrl &url, std::string topath); + + bool error() const{return p_error;}; + + + signals: + void done(); + + private slots: + void httpDone(bool error); + void httpProgress(int done, int total); + + private: + QHttp p_http; + QFile p_file; + bool p_error; + int p_lastDone; + Progress p_progress; + + }; +} +#endif diff --git a/isis/src/base/apps/edrget/tsts/Makefile b/isis/src/base/apps/edrget/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/edrget/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/edrget/tsts/ftp/Makefile b/isis/src/base/apps/edrget/tsts/ftp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..df4126889dce8987647d7f27fe95b82723933a6a --- /dev/null +++ b/isis/src/base/apps/edrget/tsts/ftp/Makefile @@ -0,0 +1,6 @@ +APPNAME = edrget + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) URL=ftp://pdsimage2.wr.usgs.gov/cdroms/viking_orbiter/vo_1004/f253sxx/f253s05.imq TOPATH=$(OUTPUT) > /dev/null; diff --git a/isis/src/base/apps/edrget/tsts/http/Makefile b/isis/src/base/apps/edrget/tsts/http/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8c655e399087178c0d7dfa4b5939110c34c1202b --- /dev/null +++ b/isis/src/base/apps/edrget/tsts/http/Makefile @@ -0,0 +1,8 @@ +APPNAME = edrget + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) URL=http://pds-imaging.jpl.nasa.gov/data/mro/mars_reconnaissance_orbiter/marci/mrom_0209/calib/vis1flat.ddd TOPATH=$(OUTPUT) > /dev/null; + ddd2isis from=$(OUTPUT)/vis1flat.ddd to=$(OUTPUT)/vis1flat.cub > /dev/null; + $(RM) $(OUTPUT)/vis1flat.ddd > /dev/null; diff --git a/isis/src/base/apps/enlarge/Makefile b/isis/src/base/apps/enlarge/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/enlarge/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/enlarge/assets/images/enlargeTotalPeaks.jpg b/isis/src/base/apps/enlarge/assets/images/enlargeTotalPeaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..54c40a33ad04286535da5eed862142359a7c35c6 Binary files /dev/null and b/isis/src/base/apps/enlarge/assets/images/enlargeTotalPeaks.jpg differ diff --git a/isis/src/base/apps/enlarge/assets/images/peaks.jpg b/isis/src/base/apps/enlarge/assets/images/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..dcce3323b71913370521f8b5be90c4d51cf6131c Binary files /dev/null and b/isis/src/base/apps/enlarge/assets/images/peaks.jpg differ diff --git a/isis/src/base/apps/enlarge/assets/images/reducedPeaks.jpg b/isis/src/base/apps/enlarge/assets/images/reducedPeaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..97346d1e3c84cc03c186e57dc1a797dc4f828247 Binary files /dev/null and b/isis/src/base/apps/enlarge/assets/images/reducedPeaks.jpg differ diff --git a/isis/src/base/apps/enlarge/assets/images/restoredPeaks.jpg b/isis/src/base/apps/enlarge/assets/images/restoredPeaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..815cff9f89bbd98ca5d1c8bfe3d70663023971a5 Binary files /dev/null and b/isis/src/base/apps/enlarge/assets/images/restoredPeaks.jpg differ diff --git a/isis/src/base/apps/enlarge/assets/images/scaleGui.jpg b/isis/src/base/apps/enlarge/assets/images/scaleGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ec00235cf6011d6ffab2d32a16b1afcd8a12857a Binary files /dev/null and b/isis/src/base/apps/enlarge/assets/images/scaleGui.jpg differ diff --git a/isis/src/base/apps/enlarge/assets/images/totalGui.jpg b/isis/src/base/apps/enlarge/assets/images/totalGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..53e5004d0d30257b607bc442324e843dadee3922 Binary files /dev/null and b/isis/src/base/apps/enlarge/assets/images/totalGui.jpg differ diff --git a/isis/src/base/apps/enlarge/assets/thumbs/enlargeTotalPeaks.jpg b/isis/src/base/apps/enlarge/assets/thumbs/enlargeTotalPeaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6b5d2ea0909a05d9e10ba1781d138221a5b989d2 Binary files /dev/null and b/isis/src/base/apps/enlarge/assets/thumbs/enlargeTotalPeaks.jpg differ diff --git a/isis/src/base/apps/enlarge/assets/thumbs/peaks.jpg b/isis/src/base/apps/enlarge/assets/thumbs/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..3879ff7fbd1a341b5e9cf7baa338eabb511bfb47 Binary files /dev/null and b/isis/src/base/apps/enlarge/assets/thumbs/peaks.jpg differ diff --git a/isis/src/base/apps/enlarge/assets/thumbs/reducedPeaks.jpg b/isis/src/base/apps/enlarge/assets/thumbs/reducedPeaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3b1a913b668ab2bc1563a38cdf1cdd1414d87ede Binary files /dev/null and b/isis/src/base/apps/enlarge/assets/thumbs/reducedPeaks.jpg differ diff --git a/isis/src/base/apps/enlarge/assets/thumbs/restoredPeaks.jpg b/isis/src/base/apps/enlarge/assets/thumbs/restoredPeaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e33e735634650b6157fc9ab30613f5d8be4bf70b Binary files /dev/null and b/isis/src/base/apps/enlarge/assets/thumbs/restoredPeaks.jpg differ diff --git a/isis/src/base/apps/enlarge/assets/thumbs/scaleGui.jpg b/isis/src/base/apps/enlarge/assets/thumbs/scaleGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bf3ef7975dc69d368537f1747bba4015e0c24aba Binary files /dev/null and b/isis/src/base/apps/enlarge/assets/thumbs/scaleGui.jpg differ diff --git a/isis/src/base/apps/enlarge/assets/thumbs/totalGui.jpg b/isis/src/base/apps/enlarge/assets/thumbs/totalGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..65010f59ad8d583172d0901eb956b80e5c902c9a Binary files /dev/null and b/isis/src/base/apps/enlarge/assets/thumbs/totalGui.jpg differ diff --git a/isis/src/base/apps/enlarge/enlarge.cpp b/isis/src/base/apps/enlarge/enlarge.cpp new file mode 100644 index 0000000000000000000000000000000000000000..419129bcac472c3bf87b09c5d1f5aa77042608e6 --- /dev/null +++ b/isis/src/base/apps/enlarge/enlarge.cpp @@ -0,0 +1,117 @@ +#include "Isis.h" + +#include "ProcessRubberSheet.h" +#include "enlarge.h" +#include "iException.h" +#include "AlphaCube.h" +#include "SubArea.h" + +using namespace std; +using namespace Isis; + +Cube cube; + +void IsisMain() { + ProcessRubberSheet p; + + // Open the input cube + Cube *icube = p.SetInputCube ("FROM"); + + // Input number of samples, lines, and bands + int ins = icube->Samples(); + int inl = icube->Lines(); + int inb = icube->Bands(); + + // Output samples and lines + int ons; + int onl; + + // Scaling factors + double sscale; + double lscale; + + UserInterface &ui = Application::GetUserInterface(); + if (ui.GetString("MODE") == "SCALE") { + // Retrieve the provided scaling factors + sscale = ui.GetDouble("SSCALE"); + lscale = ui.GetDouble("LSCALE"); + + // Calculate the output size. If there is a fractional pixel, round up + ons = (int)ceil (ins * sscale); + onl = (int)ceil (inl * lscale); + } + else { + // Retrieve the provided sample/line dimensions in the output + ons = ui.GetInteger("ONS"); + onl = ui.GetInteger("ONL"); + + // Calculate the scaling factors + sscale = (double)ons / (double)ins; + lscale = (double)onl / (double)inl; + } + + // Ensure that the calculated number of output samples and lines is greater + // than the input + if (ons < ins || onl < inl) { + string msg = "Number of output samples/lines must be greater than or equal"; + msg = msg + " to the input samples/lines."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Set up the transform object with the calculated scale and number of + // output pixels + Transform *transform = new Enlarge(sscale, lscale, ons, onl); + + string from = ui.GetFilename("FROM"); + cube.Open(from); + + // Allocate the output file, the number of bands does not change in the output + Cube *ocube = p.SetOutputCube ("TO", ons, onl, inb); + + // Set up the interpolator + Interpolator *interp; + if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { + interp = new Interpolator(Interpolator::NearestNeighborType); + } + else if (ui.GetString("INTERP") == "BILINEAR") { + interp = new Interpolator(Interpolator::BiLinearType); + } + else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { + interp = new Interpolator(Interpolator::CubicConvolutionType); + } + else { + string msg = "Unknown value for INTERP [" + + ui.GetString("INTERP") + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + p.StartProcess(*transform, *interp); + + // Construct a label with the results + PvlGroup results("Results"); + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("StartingLine", "1"); + results += PvlKeyword ("StartingSample", "1"); + results += PvlKeyword ("EndingLine", inl); + results += PvlKeyword ("EndingSample", ins); + results += PvlKeyword ("LineIncrement", 1./lscale); + results += PvlKeyword ("SampleIncrement", 1./sscale); + results += PvlKeyword ("OutputLines", onl); + results += PvlKeyword ("OutputSamples", ons); + + // Update the Mapping, Instrument, and AlphaCube groups in the output + // cube label + SubArea s; + s.SetSubArea(cube.Lines(),cube.Samples(),1,1,cube.Lines(),cube.Samples(), + 1./lscale,1./sscale); + s.UpdateLabel(&cube,ocube,results); + + p.EndProcess(); + + delete transform; + delete interp; + + // Write the results to the log + Application::Log(results); +} + diff --git a/isis/src/base/apps/enlarge/enlarge.h b/isis/src/base/apps/enlarge/enlarge.h new file mode 100644 index 0000000000000000000000000000000000000000..04ca31c65838156ef1aec9022fa70339d60d1c04 --- /dev/null +++ b/isis/src/base/apps/enlarge/enlarge.h @@ -0,0 +1,55 @@ +#ifndef enlarge_h +#define enlarge_h + +#include "Transform.h" + +#include +#include + +class Enlarge : public Isis::Transform { + private: + int p_outputSamples; // Number of samples for output + int p_outputLines; // Number of lines for output + + double p_sampleScale; + double p_lineScale; + + public: + // constructor + Enlarge (const double sampleScale, const double lineScale, + const int outputSamples, const int outputLines){ + + // Save off the sample and line magnification + p_sampleScale = sampleScale; + p_lineScale = lineScale; + + p_outputSamples = outputSamples; + p_outputLines = outputLines; + } + + // destructor + ~Enlarge () {}; + + // Implementations for parent's pure virtual members + // Convert the requested output samp/line to an input samp/line + bool Xform (double &inSample, double &inLine, + const double outSample, const double outLine) { + inSample = (outSample - 0.5) / p_sampleScale + 0.5; + inLine = (outLine - 0.5) / p_lineScale + 0.5; + return true; + } + + // Return the output number of samples + int OutputSamples () const { + return p_outputSamples; + } + + // Return the output number of lines + int OutputLines () const { + return p_outputLines; + } + +}; + +#endif + diff --git a/isis/src/base/apps/enlarge/enlarge.xml b/isis/src/base/apps/enlarge/enlarge.xml new file mode 100644 index 0000000000000000000000000000000000000000..229f1c442e9f1cd141874816488dfd7971f378ac --- /dev/null +++ b/isis/src/base/apps/enlarge/enlarge.xml @@ -0,0 +1,401 @@ + + + + + + Enlarge the pixel dimensions of an image + + + + This program will enlarge a cube by a given scalar of the original or to + specific dimensions. The user can specify to perform the enlargement by + cubic convolution, nearest neighbor, or bi-linear interpolation. + + + + + Original version + + + Fixed documentation error. The application name was rotate + instead of enlarge. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Fixed compiler error with uninitialized variable after adding -O1 flag + + + Modified filename parameters to be cube parameters where necessary + + + Added example + + + Fixed application test + + + Program now updates output file's mapping keywords + + + Fixed typo in the user documentation + + + Removed references to CubeInfo + + + Fixed problems with the way the Alpha Cube was handled + + + Changed the parameter names smag/lmag to sscale/lscale for consistancy + with reduce. + + + The "Scale" keyword in the Projection group in the labels is now being + updated if this program is run on a projected cube. + + + Now uses the SubArea class to produce output cube labels + with corrected Mapping, Instrument, and AlphaCube groups. + + + Added functionality for enlarging to a total number of pixels. + + + Updated example. + + + + + Geometry + + + + + + cube + input + + Input cube to enlarge + + + Use this parameter to select the filename. All bands within the file + will be enlarged unless a specific band is specified. + + + *.cub + + + + + output + cube + + Output cube + + + This file will contain the results of the enlargement. + + + + + + + string + + CUBICCONVOLUTION + + Type of interpolation + + This is the type of interpolation to be performed on the input. + + + + + + + + + + string + + Scale up the image or enlarge to specific dimensions + + SCALE + + Select between enlarging the image to a multiple of the original (by a + scaling factor) or to specific dimensions (in terms of total + number of pixels). + + + + + + + + + double + Sample magnification factor + + This determines new size of the cube in the sample direction only. + The number of samples will be multiplied by this number. + + 1.0 + 1.0 + + + + double + Line magnification factor + + This determines new size of the cube in the line direction only. + The number of linees will be multiplied by this number. + + 1.0 + 1.0 + + + + integer + 1 + Number of samples in output + + The number of samples desired in the output cube. This value + must be greater than or equal to the number of samples in the input + image. + + + + + integer + 1 + Number of lines in output + + The number of lines desired in the output cube. This value + must be greater than or equal to the number of lines in the input + image. + + + + + + + + + Enlarge the number of samples by a scaling factor of 2, while leaving + the number of lines the same. + + + Here, the 1024 x 1024 image "peaks.cub" has had the application "reduce" + applied to it in order to produce a 512 x 1024 image called + "reducedPeaks.cub". In this example, the reduced image, + reducedPeaks.cub, will be enlarged by a factor of 2 along the sample + dimension in an attempt to restore it back to its original form. + + + + from=reducedPeaks.cub + to=restoredPeaks.cub + sscale=2.0 + + + In order to double the number of sample pixels, the sample scale is + set to 2.0, and the line scale remains at its default of 1.0. Since + no mode or interpolation has been specified, the application will + default to scale and cube convolution interpolation, respectively. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform an enlargement + of the samples by scaling. + + + + + + + + + + Input image for reduce + + + This is the original image, before being reduced, that the enlarge + application will attempt to replicate. It is important to realize + that this image has been scaled down to fit in a web browser. At + full size, the image would be 1024 x 1024 pixels. + + + + + + Input image for enlarge, output from reduce + + + This is the reduced image, containing half its original number of + samples, that enlarge will attempt to restore. Though it + has also been scaled down to fit in a web browser, at full size it + would be 512 x 1024 pixels. For more information, see the + documentation for the "reduce" application. + + + FROM + + + + + + + Output image from enlarge + + + The enlarged image. Despite the fact that half the samples were + lost as a result of the reduction, the two images (peaks.cub and + restoredPeaks.cub) look nearly identical due to the cubic + convolution interpolation that was applied. Again scaled down for + web browsers, at full size, the image would be 1024 x 1024 pixels. + + + TO + + + + + + + Enlarge the number of samples to 768, and keep the number of lines at + 1024 + + + Here the mode has been set to enlarge to a total number of pixels along + the sample and line dimensions, with all other parameters kept at their + default settings. + + + + from=reducedPeaks.cub + to=enlargeTotalPeaks.cub + mode=total + ons=768 + onl=1024 + + + In order to enlarge to specific dimensions, the mode is set here to + "total". Also, because total lines and samples do not have default + values, the output number of lines must still be specified, even + though they will be unchanged. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform a sample + enlargement to a total number of pixels. + + + + + + + + + + Input image for enlarge + + + This is the same input image, reducedPeaks.cub, that was enlarged in + the last example. + + + FROM + + + + + + + Output image from enlarge + + + The enlarged image. Though it has been scaled down so that it can + be viewed in a web browser, the essential change can still be + observed. The horizontal enlargement is noticable, and the output + cube has 3/2 the number of samples as the input cube. + + + TO + + + + + + diff --git a/isis/src/base/apps/enlarge/tsts/Makefile b/isis/src/base/apps/enlarge/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/enlarge/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/enlarge/tsts/default/Makefile b/isis/src/base/apps/enlarge/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..45f0740951b0d26ac1397ae90f6855838e056a66 --- /dev/null +++ b/isis/src/base/apps/enlarge/tsts/default/Makefile @@ -0,0 +1,10 @@ +APPNAME = enlarge + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/enlargeTruth.cub \ + sscale=1.0 \ + lscale=1.5 \ + interp=nearestneighbor > /dev/null; diff --git a/isis/src/base/apps/enlarge/tsts/total/Makefile b/isis/src/base/apps/enlarge/tsts/total/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2c9aadfcf8e3d2fb0779788ecf322d47004579a4 --- /dev/null +++ b/isis/src/base/apps/enlarge/tsts/total/Makefile @@ -0,0 +1,21 @@ +APPNAME = enlarge + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/total.cub \ + mode=total \ + ons=126 \ + onl=189 \ + interp=nearestneighbor > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/scale.cub \ + sscale=1.0 \ + lscale=1.5 \ + interp=nearestneighbor > /dev/null; + cubediff from=$(OUTPUT)/total.cub \ + from2=$(OUTPUT)/scale.cub \ + to=$(OUTPUT)/comparisonTruth.txt > /dev/null; + rm -f $(OUTPUT)/total.cub; + rm -f $(OUTPUT)/scale.cub; diff --git a/isis/src/base/apps/equalizer/Makefile b/isis/src/base/apps/equalizer/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/equalizer/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/equalizer/assets/FromList.lst b/isis/src/base/apps/equalizer/assets/FromList.lst new file mode 100644 index 0000000000000000000000000000000000000000..69b819d0149e996bb9efd0d8e338614673dc9c44 --- /dev/null +++ b/isis/src/base/apps/equalizer/assets/FromList.lst @@ -0,0 +1,3 @@ +$odyssey/testData/I00824006RDR.lev2.cub +$odyssey/testData/I01523019RDR.lev2.cub +$odyssey/testData/I02609002RDR.lev2.cub diff --git a/isis/src/base/apps/equalizer/assets/HoldList.lst b/isis/src/base/apps/equalizer/assets/HoldList.lst new file mode 100644 index 0000000000000000000000000000000000000000..784f727940606e1089e64b1628d86dd33a6a1f14 --- /dev/null +++ b/isis/src/base/apps/equalizer/assets/HoldList.lst @@ -0,0 +1 @@ +$odyssey/testData/I01523019RDR.lev2.cub diff --git a/isis/src/base/apps/equalizer/assets/Input.lst b/isis/src/base/apps/equalizer/assets/Input.lst new file mode 100644 index 0000000000000000000000000000000000000000..176f1401d247e15c955e239fc16dd14e46b22cda --- /dev/null +++ b/isis/src/base/apps/equalizer/assets/Input.lst @@ -0,0 +1,2 @@ +$odyssey/testData/I00824006RDR.lev2.cub +$odyssey/testData/I02609002RDR.lev2.cub diff --git a/isis/src/base/apps/equalizer/assets/Output.lst b/isis/src/base/apps/equalizer/assets/Output.lst new file mode 100644 index 0000000000000000000000000000000000000000..b1bd28a8580b5ffa15cc1843fd8461c462beceb5 --- /dev/null +++ b/isis/src/base/apps/equalizer/assets/Output.lst @@ -0,0 +1,2 @@ +I00824006RDR.lev2.cub +I02609002RDR.lev2.cub diff --git a/isis/src/base/apps/equalizer/assets/image/EqualizedMosaic.jpg b/isis/src/base/apps/equalizer/assets/image/EqualizedMosaic.jpg new file mode 100755 index 0000000000000000000000000000000000000000..be7f6d5566fb535b415f573ac71f7a8bb5d2c19d Binary files /dev/null and b/isis/src/base/apps/equalizer/assets/image/EqualizedMosaic.jpg differ diff --git a/isis/src/base/apps/equalizer/assets/image/applyGui.jpg b/isis/src/base/apps/equalizer/assets/image/applyGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..4ff582b09c824f8b8f109444b26f10e1e00dd7bc Binary files /dev/null and b/isis/src/base/apps/equalizer/assets/image/applyGui.jpg differ diff --git a/isis/src/base/apps/equalizer/assets/image/bothGui.jpg b/isis/src/base/apps/equalizer/assets/image/bothGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8e22c0451faaf89eaf7d357a67e4ab7db6901078 Binary files /dev/null and b/isis/src/base/apps/equalizer/assets/image/bothGui.jpg differ diff --git a/isis/src/base/apps/equalizer/assets/image/calcGui.jpg b/isis/src/base/apps/equalizer/assets/image/calcGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8c6103cb41f3ec8cc1a76d80a303a88ef607db9c Binary files /dev/null and b/isis/src/base/apps/equalizer/assets/image/calcGui.jpg differ diff --git a/isis/src/base/apps/equalizer/assets/image/nonEqualizedMosaic.jpg b/isis/src/base/apps/equalizer/assets/image/nonEqualizedMosaic.jpg new file mode 100755 index 0000000000000000000000000000000000000000..68e6f0d1b1693ef8eabe4b048a9b48c5b8cc9365 Binary files /dev/null and b/isis/src/base/apps/equalizer/assets/image/nonEqualizedMosaic.jpg differ diff --git a/isis/src/base/apps/equalizer/assets/stats.pvl b/isis/src/base/apps/equalizer/assets/stats.pvl new file mode 100644 index 0000000000000000000000000000000000000000..9671d0891c2100cc87c67b0dfeaa13cc248f2849 --- /dev/null +++ b/isis/src/base/apps/equalizer/assets/stats.pvl @@ -0,0 +1,216 @@ +Object = EqualizationInformation + Group = General + TotalOverlaps = 20 + ValidOverlaps = 20 + InvalidOverlaps = 0 + Weighted = false + MinCount = 1000 + End_Group + + # Formula: newDN = (oldDN - AVERAGE) * GAIN + AVERAGE + OFFSET + # BandN = (GAIN, OFFSET, AVERAGE) + Group = Normalization + FileName = $odyssey/testData/I00824006RDR.lev2.cub + Band1 = (0.80247733802282, -6.41865351231352e-05, 3.75633639030183e-04) + Band2 = (0.79065929400895, -6.36729218508168e-05, 3.73453901670211e-04) + Band3 = (0.78618517163023, -4.66441642261209e-05, 4.26489334143704e-04) + Band4 = (0.80950153969313, -2.96070328146754e-05, 4.2359022492798e-04) + Band5 = (0.82650392553234, -1.12353065258622e-05, 4.31185103699393e-04) + Band6 = (0.8253543915921, -2.06852217478284e-05, 4.7886084539562e-04) + Band7 = (0.82955469420605, -3.11067700568501e-05, 5.0695775944272e-04) + Band8 = (0.83879933286938, -4.33281550348315e-05, 5.2504181330742e-04) + Band9 = (0.84149321645672, -5.07250317590132e-05, 5.26586798911814e-04) + Band10 = (1.1365072636781, -6.00857909632202e-05, 1.68162009248859e-04) + End_Group + + # Formula: newDN = (oldDN - AVERAGE) * GAIN + AVERAGE + OFFSET + # BandN = (GAIN, OFFSET, AVERAGE) + Group = Normalization + FileName = $odyssey/testData/I01523019RDR.lev2.cub + Band1 = (1.0, 9.58308385427109e-21, 3.09460986870763e-04) + Band2 = (1.0, 9.58308385427109e-21, 3.08373709744676e-04) + Band3 = (1.0, 1.91661677085422e-20, 3.91940207887308e-04) + Band4 = (1.0, 0.0, 4.06942925710849e-04) + Band5 = (1.0, 0.0, 4.31869449957304e-04) + Band6 = (1.0, 0.0, 4.69190692046412e-04) + Band7 = (1.0, 0.0, 4.8588750909486e-04) + Band8 = (1.0, -9.58308385427109e-21, 4.90828757009813e-04) + Band9 = (1.0, -9.58308385427109e-21, 4.84059968314066e-04) + Band10 = (1.0, -4.79154192713554e-21, 1.12636583098266e-04) + End_Group + + # Formula: newDN = (oldDN - AVERAGE) * GAIN + AVERAGE + OFFSET + # BandN = (GAIN, OFFSET, AVERAGE) + Group = Normalization + FileName = $odyssey/testData/I02609002RDR.lev2.cub + Band1 = (1.9316157478611, 1.59619509035933e-04, 1.42658743858439e-04) + Band2 = (1.932336336529, 1.57588763433619e-04, 1.43649318131491e-04) + Band3 = (1.64004090444, 1.68659640333886e-04, 2.0777327887805e-04) + Band4 = (1.4812058780968, 1.5840520307998e-04, 2.3290378091814e-04) + Band5 = (1.3704711365784, 1.52642678257089e-04, 2.64447123203191e-04) + Band6 = (1.3362394642735, 1.60068644704082e-04, 2.94844891883319e-04) + Band7 = (1.3283742214144, 1.64982211514812e-04, 3.06951459636527e-04) + Band8 = (1.3294589731373, 1.65523872953224e-04, 3.12038023078655e-04) + Band9 = (1.3061529800122, 1.56102076817381e-04, 3.18235155137053e-04) + Band10 = (2.0915517131497, 6.24923543888896e-05, 5.97723994078917e-05) + End_Group +End_Object + +Object = OverlapStatistics + File1 = I00824006RDR.lev2.cub + File2 = I01523019RDR.lev2.cub + Width = 64 + Height = 319 + SamplingPercent = 100.0 + ValidOverlap = (true, true, true, true, true, true, true, true, true, + true) + Covariance = (8.66056545026253e-10, 8.79691266418622e-10, + 1.7306613800184e-09, 1.4901003597905e-09, + 1.2430121256273e-09, 1.24513415685067e-09, + 1.2019991465147e-09, 1.12244198420848e-09, + 8.28253514809114e-10, 1.14487524951049e-10) + Correlation = (0.84446586832133, 0.84071818387007, 0.93428674174491, + 0.92786599008347, 0.91780444725396, 0.91534858031389, + 0.91707228771614, 0.9156221382966, 0.88334206684856, + 0.86168808623994) + ValidPixels = (2249, 2255, 2260, 2271, 2278, 2289, 2297, 2311, 2316, + 2328) + InvalidPixels = (18167, 18161, 18156, 18145, 18138, 18127, 18119, + 18105, 18100, 18088) + TotalPixels = (20416, 20416, 20416, 20416, 20416, 20416, 20416, + 20416, 20416, 20416) + LinearRegression1 = (5.6168050315509e-05, 0.67766472206161) + LinearRegression2 = (6.07798326404386e-05, 0.66472164571919) + LinearRegression3 = (6.72734842615686e-05, 0.73452238241056) + LinearRegression4 = (7.66068355766436e-05, 0.75110894760145) + LinearRegression5 = (9.3672383455217e-05, 0.75856897852644) + LinearRegression6 = (9.71720565706477e-05, 0.75548697059967) + LinearRegression7 = (9.06720964419351e-05, 0.76076162120122) + LinearRegression8 = (7.89309612919495e-05, 0.76802323876364) + LinearRegression9 = (8.50505765965028e-05, 0.74332635706391) + LinearRegression10 = (-5.6533773156427e-05, 0.97931476903654) + + Group = File1 + StartSample = 20 + EndSample = 83 + StartLine = 45 + EndLine = 363 + Average = (3.73383224474887e-04, 3.7119233288478e-04, + 4.29104530627003e-04, 4.26748440202013e-04, + 4.34524483808163e-04, 4.82008171946973e-04, + 5.09027302016625e-04, 5.27031740917426e-04, + 5.28981498849642e-04, 1.7171758019398e-04) + StandardDeviation = (3.57491471264317e-05, 3.63785370066425e-05, + 4.85404204860908e-05, 4.45406234813996e-05, + 4.04799664068043e-05, 4.05970600547168e-05, + 3.9749144135714e-05, 3.82291613558296e-05, + 3.33804262105241e-05, 1.08122961176451e-05) + Variance = (1.27800152026726e-09, 1.32339795474365e-09, + 2.3561724209665e-09, 1.9838671401118e-09, + 1.63862768029601e-09, 1.64812128508628e-09, + 1.57999445952177e-09, 1.46146877797005e-09, + 1.11425285399624e-09, 1.16905747335643e-10) + End_Group + + Group = File2 + StartSample = 1 + EndSample = 64 + StartLine = 1 + EndLine = 319 + Average = (3.09196689351751e-04, 3.07519411033963e-04, + 3.82460366400882e-04, 3.97141407387338e-04, + 4.232891772823e-04, 4.61322950199145e-04, + 4.77920531959775e-04, 4.83703585882594e-04, + 4.78256467090628e-04, 1.1163178923076e-04) + StandardDeviation = (2.8687880422605e-05, 2.87630283867503e-05, + 3.81617588108608e-05, 3.6055703287085e-05, + 3.34568511406412e-05, 3.35069618018889e-05, + 3.29740891084544e-05, 3.20665950414257e-05, + 2.80894022185903e-05, 1.22882530747417e-05) + Variance = (8.22994483141681e-10, 8.27311801977005e-10, + 1.45631983553831e-09, 1.30001373952631e-09, + 1.11936088824702e-09, 1.12271648919324e-09, + 1.08729055253229e-09, 1.02826651755079e-09, + 7.89014516997744e-10, 1.510011636289e-10) + End_Group +End_Object + +Object = OverlapStatistics + File1 = I01523019RDR.lev2.cub + File2 = I02609002RDR.lev2.cub + Width = 65 + Height = 296 + SamplingPercent = 100.0 + ValidOverlap = (true, true, true, true, true, true, true, true, true, + true) + Covariance = (5.58756800724361e-10, 5.82310526027186e-10, + 1.18578607531577e-09, 1.13902454895633e-09, + 1.04356301495808e-09, 1.07215170833875e-09, + 1.05036891384437e-09, 9.93322613206676e-10, + 7.86718829792647e-10, 4.21511262764834e-11) + Correlation = (0.90252767464965, 0.90513415882084, 0.94772980182853, + 0.95123170119078, 0.95028361199231, 0.94839747471242, + 0.94766534375721, 0.94396751653567, 0.92923235260106, + 0.77943298767523) + ValidPixels = (6647, 6650, 6663, 6670, 6684, 6689, 6702, 6710, 6723, + 6732) + InvalidPixels = (12593, 12590, 12577, 12570, 12556, 12551, 12538, + 12530, 12517, 12508) + TotalPixels = (19240, 19240, 19240, 19240, 19240, 19240, 19240, + 19240, 19240, 19240) + LinearRegression1 = (4.57040524375986e-06, 0.46723975803625) + LinearRegression2 = (5.47489277860364e-06, 0.46841439645373) + LinearRegression3 = (-6.00999842051768e-06, 0.57786961243635) + LinearRegression4 = (-1.51151737389437e-05, 0.64220086839856) + LinearRegression5 = (-2.19894244082222e-05, 0.69339921624679) + LinearRegression6 = (-2.54302508359853e-05, 0.70975113373715) + LinearRegression7 = (-2.71462374211098e-05, 0.71340238953764) + LinearRegression8 = (-2.45121397038829e-05, 0.71003884708685) + LinearRegression9 = (-1.7100813314973e-05, 0.71142689012767) + LinearRegression10 = (1.21301130259497e-05, 0.37265776541641) + + Group = File1 + StartSample = 19 + EndSample = 83 + StartLine = 1 + EndLine = 296 + Average = (3.08187250749969e-04, 3.06749571704733e-04, + 3.85306641514519e-04, 4.00476179748384e-04, + 4.26134767985569e-04, 4.63872247294689e-04, + 4.80939020640598e-04, 4.86312500252694e-04, + 4.81684740355405e-04, 1.18950173128981e-04) + StandardDeviation = (3.45813159533572e-05, 3.52583677417874e-05, + 4.52989613541061e-05, 4.21144465675126e-05, + 3.87942773357081e-05, 3.88664677932248e-05, + 3.83710470548738e-05, 3.74027992347272e-05, + 3.32540568023897e-05, 1.06352940988774e-05) + Variance = (1.19586741306592e-09, 1.24315249581512e-09, + 2.0519958997608e-09, 1.77362660968787e-09, + 1.50499595399984e-09, 1.51060231872178e-09, + 1.47233725208734e-09, 1.39896939059331e-09, + 1.10583229381656e-09, 1.13109480569617e-10) + End_Group + + Group = File2 + StartSample = 1 + EndSample = 65 + StartLine = 424 + EndLine = 719 + Average = (1.48567741714037e-04, 1.49160808271114e-04, + 2.16647001180633e-04, 2.42070976668404e-04, + 2.7349208972848e-04, 3.03803602590607e-04, + 3.15956809125786e-04, 3.2078862729947e-04, + 3.25582663538024e-04, 5.64578187400918e-05) + StandardDeviation = (1.79027925153587e-05, 1.8246496262199e-05, + 2.76206289925269e-05, 2.84325408035962e-05, + 2.83072560233297e-05, 2.90864540618525e-05, + 2.88857209333813e-05, 2.81338499272853e-05, + 2.54595421143384e-05, 5.08488221066329e-06) + Variance = (3.20509979847984e-10, 3.32934625846442e-10, + 7.62899145942815e-10, 8.0840937654816e-10, + 8.01300743570335e-10, 8.46021809892255e-10, + 8.34384873841183e-10, 7.91513511731013e-10, + 6.4818828467177e-10, 2.585602709632e-11) + End_Group +End_Object +End \ No newline at end of file diff --git a/isis/src/base/apps/equalizer/assets/thumb/EqualizedMosaic.jpg b/isis/src/base/apps/equalizer/assets/thumb/EqualizedMosaic.jpg new file mode 100755 index 0000000000000000000000000000000000000000..be7f6d5566fb535b415f573ac71f7a8bb5d2c19d Binary files /dev/null and b/isis/src/base/apps/equalizer/assets/thumb/EqualizedMosaic.jpg differ diff --git a/isis/src/base/apps/equalizer/assets/thumb/applyGui.jpg b/isis/src/base/apps/equalizer/assets/thumb/applyGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..7ece9b66ffb19ac47970763f97a2cfe4b750dc98 Binary files /dev/null and b/isis/src/base/apps/equalizer/assets/thumb/applyGui.jpg differ diff --git a/isis/src/base/apps/equalizer/assets/thumb/bothGui.jpg b/isis/src/base/apps/equalizer/assets/thumb/bothGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..42d7c9e1106c0a64e0738ce8d668d1b6b9f38bb6 Binary files /dev/null and b/isis/src/base/apps/equalizer/assets/thumb/bothGui.jpg differ diff --git a/isis/src/base/apps/equalizer/assets/thumb/calcGui.jpg b/isis/src/base/apps/equalizer/assets/thumb/calcGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..b88b060ba7c461cdc11eb6d3b5270e5e303835c7 Binary files /dev/null and b/isis/src/base/apps/equalizer/assets/thumb/calcGui.jpg differ diff --git a/isis/src/base/apps/equalizer/assets/thumb/nonEqualizedMosaic.jpg b/isis/src/base/apps/equalizer/assets/thumb/nonEqualizedMosaic.jpg new file mode 100755 index 0000000000000000000000000000000000000000..68e6f0d1b1693ef8eabe4b048a9b48c5b8cc9365 Binary files /dev/null and b/isis/src/base/apps/equalizer/assets/thumb/nonEqualizedMosaic.jpg differ diff --git a/isis/src/base/apps/equalizer/equalizer.cpp b/isis/src/base/apps/equalizer/equalizer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe3d9cbb208073d68f820058b4784195fd40aa86 --- /dev/null +++ b/isis/src/base/apps/equalizer/equalizer.cpp @@ -0,0 +1,513 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "FileList.h" +#include "Filename.h" +#include "OverlapStatistics.h" +#include "LineManager.h" +#include "MultivariateStatistics.h" +#include "iString.h" +#include "OverlapNormalization.h" +#include "CubeAttribute.h" +#include "tnt/tnt_array2d.h" +#include "jama/jama_svd.h" +#include + +using namespace Isis; + +Isis::Statistics GatherStatistics(Cube &icube, const int band, + double sampPercent, std::string maxCubeStr); +void ApplyViaObject(Buffer &in, Buffer &out); +void ApplyViaFile(Buffer &in, Buffer &out); + +std::vector g_overlapList; +std::vector g_oNormList; +std::vector normIndices; +std::vector gains, offsets, avgs; +int g_imageIndex, g_maxCube, g_maxBand; + +void IsisMain() { + // Get the list of cubes to mosaic + FileList imageList; + UserInterface &ui = Application::GetUserInterface(); + imageList.Read(ui.GetFilename("FROMLIST")); + if (imageList.size() < 1) { + std::string msg = "The list file [" + ui.GetFilename("FROMLIST") + + "] does not contain any data"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Make sure the user enters a "OUTSTATS" file if the CALCULATE option + // is selected + std::string processOpt = ui.GetString("PROCESS"); + if (processOpt == "CALCULATE") { + if (!ui.WasEntered("OUTSTATS")) { + std::string msg = "If the CALCULATE option is selected, you must enter"; + msg += " an OUTSTATS file"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + // Make sure number of bands and projection parameters match for all cubes + for (unsigned int i=0; i hold; + if (ui.WasEntered("HOLD")) { + FileList holdList; + holdList.Read(ui.GetFilename("HOLD")); + + // Make sure each file in the holdlist matches a file in the fromlist + for (int i=0; i<(int)holdList.size(); i++) { + bool matched = false; + for (int j=0; j<(int)imageList.size(); j++) { + if (holdList[i] == imageList[j]) { + matched = true; + hold.push_back(j); + break; + } + } + if (!matched) { + std::string msg = "The hold list file [" + holdList[i] + + "] does not match a file in the from list"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + } + + // Read to list if one was entered + FileList outList; + if (ui.WasEntered("TOLIST")) { + outList.Read(ui.GetFilename("TOLIST")); + + // Make sure each file in the tolist matches a file in the fromlist + if (outList.size() != imageList.size()) { + std::string msg = "Each input file in the FROM LIST must have a "; + msg += "corresponding output file in the TO LIST."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Make sure that all output files do not have the same names as their + // corresponding input files + for (unsigned i = 0; i < outList.size(); i++) { + if (outList[i].compare(imageList[i]) == 0) { + std::string msg = "The to list file [" + outList[i] + + "] has the same name as its corresponding from list file."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + } + + // Test to ensure sampling percent in bound + double sampPercent = ui.GetDouble("PERCENT"); + if (sampPercent <= 0.0 || sampPercent > 100.0) { + string msg = "The sampling percent must be a decimal (0.0, 100.0]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + int mincnt = ui.GetInteger("MINCOUNT"); + bool wtopt = ui.GetBoolean("WEIGHT"); + if (processOpt != "APPLY") { + // Loop through all the input cubes, calculating statistics for each cube to use later + iString maxCubeStr ((int)imageList.size()); + for (int band=1; band<=g_maxBand; band++) { + std::vector statsList; + for (int img=0; img<(int)imageList.size(); img++) { + Process p; + const CubeAttributeInput att; + const std::string inp = imageList[img]; + Cube *icube = p.SetInputCube(inp, att); + + // Add a Statistics object to the list for every band of every input cube + g_imageIndex = img; + Statistics stats = GatherStatistics(*icube, band, sampPercent, maxCubeStr); + statsList.push_back(stats); + p.EndProcess(); + } + + // Create a separate OverlapNormalization object for every band + OverlapNormalization *oNorm = new OverlapNormalization (statsList); + for (int h=0; h<(int)hold.size(); h++) oNorm->AddHold(hold[h]); + g_oNormList.push_back(oNorm); + } + + // A list for keeping track of which input cubes are known to overlap another + std::vector doesOverlapList; + for (unsigned int i=0; i= mincnt) { + g_oNormList[band-1]->AddOverlap(oStats.GetMStats(band).X(), i, + oStats.GetMStats(band).Y(), j, weight); + doesOverlapList[i] = true; + doesOverlapList[j] = true; + } + } + } + } + } + + // Print an error if one or more of the images does not overlap another + { + std::string badFiles = ""; + for (unsigned int img=0; imgSolve(sType); + } + } + + // Print gathered statistics to the gui and the print file + int validCnt = 0; + int invalidCnt = 0; + if (processOpt != "APPLY") { + PvlGroup results("Results"); + + // Compute the number valid and invalid overlaps + for (unsigned int o=0; oGain(img)); + iString base (g_oNormList[band-1]->Offset(img)); + iString avg (g_oNormList[band-1]->Average(img)); + iString bandNum (band); + std::string bandStr = "Band" + bandNum; + PvlKeyword bandStats(bandStr); + bandStats += mult; + bandStats += base; + bandStats += avg; + results += bandStats; + } + } + + // Write the results to the log + Application::Log(results); + } + + // Setup the output text file if the user requested one + if (ui.WasEntered("OUTSTATS")) { + PvlObject equ("EqualizationInformation"); + PvlGroup gen("General"); + gen += PvlKeyword("TotalOverlaps", validCnt+invalidCnt); + gen += PvlKeyword("ValidOverlaps", validCnt); + gen += PvlKeyword("InvalidOverlaps", invalidCnt); + std::string weightStr = "false"; + if (wtopt) weightStr = "true"; + gen += PvlKeyword("Weighted", weightStr); + gen += PvlKeyword("MinCount", mincnt); + equ.AddGroup(gen); + for (unsigned int img=0; imgGain(img)); + iString base (g_oNormList[band-1]->Offset(img)); + iString avg (g_oNormList[band-1]->Average(img)); + iString bandNum (band); + std::string bandStr = "Band" + bandNum; + PvlKeyword bandStats(bandStr); + bandStats += mult; + bandStats += base; + bandStats += avg; + norm += bandStats; + } + equ.AddGroup(norm); + } + + // Write the equalization and overlap statistics to the file + std::string out = Filename(ui.GetFilename("OUTSTATS")).Expanded(); + std::ofstream os; + os.open(out.c_str(),std::ios::app); + Pvl p; + p.SetTerminator(""); + p.AddObject(equ); + os << p << std::endl; + for (unsigned int i=0; i (unsigned)equalInfo.Groups()-1) { + std::string msg = "Each input file in the FROM LIST must have a "; + msg += "corresponding input file in the INPUT STATISTICS."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Check that each file in the FROM LIST is present in the INPUT STATISTICS + for (unsigned i = 0; i < imageList.size(); i++) { + std::string fromFile = imageList[i]; + bool foundFile = false; + for (int j = 1; j < equalInfo.Groups(); j++) { + PvlGroup &normalization = equalInfo.Group(j); + std::string normFile = normalization["Filename"][0]; + if (fromFile == normFile) { + + // Store the index in INPUT STATISTICS file corresponding to the + // current FROM LIST file + normIndices.push_back(j); + foundFile = true; + } + } + if (!foundFile) { + std::string msg = "The from list file [" + fromFile + + "] does not have any corresponding file in the stats list."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + } + + // Apply the correction to the images if the user wants this done + if (processOpt != "CALCULATE") { + iString maxCubeStr ((int)imageList.size()); + for (int img=0; img<(int)imageList.size(); img++) { + // Set up for progress bar + ProcessByLine p; + iString curCubeStr (img+1); + p.Progress()->SetText("Equalizing Cube " + curCubeStr + " of " + maxCubeStr); + + // Open input cube + CubeAttributeInput att; + const std::string inp = imageList[img]; + Cube *icube = p.SetInputCube(inp, att); + + // Establish the output file depending upon whether or not a to list + // was entered + std::string out; + if (ui.WasEntered("TOLIST")) { + out = outList[img]; + } + else { + Filename file = imageList[img]; + out = file.Path() + "/" + file.Basename() + ".equ." + file.Extension(); + } + + // Allocate output cube + CubeAttributeOutput outAtt; + p.SetOutputCube(out,outAtt,icube->Samples(),icube->Lines(),icube->Bands()); + + // Apply gain/offset to the image + g_imageIndex = img; + if (processOpt == "APPLY") { + + // Apply correction based on pre-determined statistics information + Pvl inStats (ui.GetFilename("INSTATS")); + PvlObject &equalInfo = inStats.FindObject("EqualizationInformation"); + PvlGroup &normalization = equalInfo.Group(normIndices[g_imageIndex]); + gains.clear(); + offsets.clear(); + avgs.clear(); + + // Get and store the modifiers for each band + for (int band = 1; band < normalization.Keywords(); band++) { + gains.push_back(normalization[band][0]); + offsets.push_back(normalization[band][1]); + avgs.push_back(normalization[band][2]); + } + p.StartProcess(ApplyViaFile); + } + else { + + // Apply correction based on the statistics gathered in this run + p.StartProcess(ApplyViaObject); + } + p.EndProcess(); + } + } + + // Clean-up for batch list runs + for (unsigned int o=0; o icube.Bands())) { + string msg = "Invalid band in method [GatherStatistics]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Construct a line buffer manager and a statistics object + Isis::LineManager line (icube); + + + Isis::Progress progress; + progress.SetText(statMsg); + + // Calculate the number of steps for the Progress object, and add an extra + // step if the total lines and incrementer do not divide evenly + int maxSteps = icube.Lines() / linc; + if (icube.Lines() % linc != 0) maxSteps += 1; + progress.SetMaximumSteps(maxSteps); + progress.CheckStatus(); + + // Add data to Statistics object by line + Isis::Statistics stats; + int i=1; + while (i<=icube.Lines()) { + line.SetLine(i,band); + icube.Read(line); + stats.AddData (line.DoubleBuffer(), line.size()); + + // Make sure we consider the last line + if (i+linc > icube.Lines() && i != icube.Lines()) { + i = icube.Lines(); + progress.AddSteps(1); + } + else i += linc; // Increment the current line by our incrementer + + progress.CheckStatus(); + } + + return stats; +} + +// Apply the equalization to the cubes with Overlap Normalization +void ApplyViaObject(Buffer &in, Buffer &out) { + int band = in.Band(); + for (int i=0; iEvaluate(in[i],g_imageIndex); + } +} + +// Apply the equalization to the cubes with INPUT STATISTICS +void ApplyViaFile(Buffer &in, Buffer &out) { + int band = in.Band(); + double gain = gains[band-1]; + double offset = offsets[band-1]; + double avg = avgs[band-1]; + for (int i=0; i + + + + + Tone matches map projected cubes + + + +

    + This program can be used to tonematch or equalize the brightness and/or + contrast of a list of input cubes prior to mosaicking. All the input + cubes, which can include mosaics, must be in a common map projection as + this program will use the mapping information to gather statistics in + overlapping areas. This statistic gathering is done on a band-by-band + basis. The statistics are used in a least squares solution to + determine multiplicative (GAIN or MULT) and additive (OFFSET or BASE) + corrections for each image. In addition to simply calculating corrective + factors and applying said factors to each image in one run of the + program, the user has the option to stop the processing and examine the + gathered statistics in a text file. The program can then be run again, + using the file containing those statistics as an input, to apply + correction to any or all of the images without the need to recalculate + corrective factors. The actual equation to be used for equalization on + each band in each cube is: +

    +            newdn(s,l,b)   =   (olddn(s,l,b) - avg(b)) * GAIN(b) + avg(b) + OFFSET(b)
    +        
    + where +
    +            s = sample index
    +            l = line index
    +            b = band index
    +        
    +

    + +

    + Prior to equalizing, the user can choose whether to adjust the brightness and/or contrast of the cubes. + The default is to adjust both, however, if the brightness (average) of all the cubes is the same, + then simply adjusting the contrast may suffice. Likewise, if the standard deviation of all the + cubes is similar, then a contrast adjustment is not necessary. Adjusting for contrast only implies + the OFFSET values will be held to zero. Similarly, adjusting for + brightness implies the GAIN values will be held to one. +

    + +

    + The OFFSET and GAIN values are computed independently for each image, therefore we have two + least squares computations with N unknowns, where N is the number of cubes to be equalized. + The overlaps, M, between all the cubes are computed, and in some cases + M < N. This implies an underdetermined system, and the program + will report an error if this occurs. You can hold one or more images + to alleviate this problem. Holding an image forces GAIN and OFFSET to + 1.0 and 0.0 for that image, respectively. +

    + +

    + If the the user chooses to apply correction to the images, then a list + of output file names can be specified with the TOLIST parameter. If no + TOLIST is specified, the equalized cubes will be named the same as the + input cubes with the addition of a '.equ' prior to the '.cub' + extension, and placed in the same directories as their input files. +

    + +

    + For the sake of efficiency, the user may choose to set the "sampling + percent" to be less than its default value of 100.0. By doing so, the + program will likely perform its statistic gathering noticeably faster, + but at the risk of losing accuracy in the results. It should + be noted that the user also runs the risk of encountering an error if + decreasing the sampling percent results in the amount of valid data in + the calculated overlaps being less than the minimum set by the + MINCOUNT parameter (default value of 1000). Sampling percent must be + a decimal value between 0.0 (exclusive) and 100.0 (inclusive). +

    +
    + + + Mosaicking + + + + b4equal + equalizer + + + + + Original version + + + Ported to Isis 3.0 + + + Changed categoryItem to Photometry and Radiometry + + + Added application test + + + Made SD default contrast mode (PCA may have errors) + + + Fixed memory leak + + + Modified to solve system using QRD which is faster the SVD + + + Removed references to CubeInfo + + + Modified call LeastSquares Solve due to change to LeastSquares + Solve method. + + + Added user feedback during statistic gathering, modified existing progress + information, and moved error checking on number of bands and projection + parameters to be done prior to statistic gathering + + + Refactored for use with the new OverlapNormalization class, thus removing + the option to use the broken PCA contrast mode; the PVL output has been + modified to print all normalization information for a cube in one group + with OverlapStatistics information coming last in the file; added an + option to decrease the percentage of lines sampled in statistic gathering + + + Added a TOLIST parameter, allowing the user to specify a unique output + file name and location for each input file. The default is now to + place each output file in the same directory as its input file, not in + the current working directory. + + + Added functionality allowing the user to run the program applying + corrections based off of previously gathered statistics obtained from + the program's output PVL file. The output PVL has also been changed + from "PVL" to "OUTSTATS". Results will now be placed into the print + file. + + + Updated documentation and examples to reflect the most recent changes to + using the program. + + + + + + + filename + input + + List of cubes to equalize + + + A list of map projected cubes to equalize. The Mapping groups + must match in order to do the equalization. + + + + + filename + input + + List of filenames to hold + + + List of cubes that are to be held in the equalization. + An additive and a multiplicative factor of 0 and 1 will be applied + to all cubes that were held. All cubes listed in this file must + also be contained in FROMLIST. + + None + + *.txt *.lis *.lst + + + + + filename + input + + List of the equalized cubes to be created + + + This list of output files must contain a file name to correspond to + each input file in the FROMLIST. Input files will be associated + with output files by index, so that the equalized product of the + first file in the FROMLIST will be written to the name and location + of the first file in the TOLIST, and so on. Each output file will + be written to the exact location with the exact name specified, + unless the location and name happen to be identical to those of its + corresponding input file, in which case an error will be thrown. If + this list is not specified, but the APPLY option is still selected, + the output files will be placed in the directories of their input + files, and named the same with the exception of an added ".equ" + extension (e.g. "foobar.cub" becomes "foobar.equ.cub"). + + Automatic + + + + filename + output + + Output text file containing thorough equalization-related + statistics + + + This file will contain the statistics of all of the overlapping areas + in every band along with the computed equalizing factors + (OFFSET and GAIN). Specifying this output file is optional. + + None + + *.txt *.pvl *.lis *.lst + + + + + filename + input + + Input text file containing thorough equalization-related + statistics, used for applying correction + + + This file must contain the statistics of all of the overlapping + areas in every band along with the computed equalizing factors + (OFFSET and GAIN) for every image in the FROMLIST. + + + *.txt *.pvl *.lis *.lst + + + + + + + string + + Calculate statistics, apply correction, or do both + + + This option allows the user to decide whether they want to do the + equalization calculations and then go on to apply correction + afterwards, apply correction to the images off of previously + gathered statistics, or do the calculations but not apply + correction. If the APPLY option is not selected, you must + specify an OUTSTATS file. If it is selected you can still + optionally specify an OUTSTATS file and the GAIN/OFFSET values + will be applied to each input cube. The names and locations of + the output cubes are specified by the TOLIST file. + + BOTH + + + + + + + + + + + + string + + Algorithm type used to adjust the pixel values. + + + Choose the fit option to select the algorithm to use to + adjust the pixel values. The BRIGHTNESS mode will equalize + using only an offset (the gain will be set to 1.0), and the + CONTRAST mode will equalize using only a gain (the offset will + be set to 0.0). The BOTH option will equalize using both an + offset and a gain. In most cases this option will give + you the best results. + + BOTH + + + + + + + + + integer + + Minimum number of points in overlapping area required to be used + in the solution + + + If the number of points in the overlapping area meets or exceeds + this value, the area will go into the least-squares solution as + a "known". Otherwise it will not be included in the + calculations. + + 1000 + + + + boolean + + Whether or not overlaps should be weighted + + + This option allows the user to decide whether they want to + weight the least squares solution based on how large the overlap + area is, or if they want no weighting at all. If this parameter + is set to "true", then larger overlapping areas will have more + of an impact on the corrective factors than smaller overlaps. + + FALSE + + + + double + + Percentage of the lines to consider when gathering overall cube + statistics and overlap statistics + + + The percentage of the lines in each area to consider in the + process-by-line solutions for finding overall cube statistics + and overlap statistics. This value must be a decimal value + between 0.0 (exclusive) and 100.0 (inclusive). + + 100.0 + + + + + + + Calculate Statistics and Apply Correction + + This example shows the most typical use of the equalizer application. + The defaults are to perform both calculation and adjustment for both the + gain and offset. + + + fromlist= FromList.lst holdlist= HoldList.lst + + + Specify a list of images to equalize along with a holding list that enables the necessary + calculations to be performed. All other options are at default + values. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to calculate the gain + and offset, and then apply corrections. Because the TOLIST + parameter is set to its default value of "Automatic", each output + image will be placed into the directory of its corresponding input + image. Also, because the OUTSTATS parameter is set to its default + value of "None", a record of the calculations performed will not + be written anywhere but to the print file. + + + + + + + + + Mosaic of the input images for equalizer + + This is a a small section of the input images for the equalizer example mosaicked together. + + + FROMLIST + + + + + + Click here to see the list of input images to be equalized + + This list contains the names of three files to calculate + statistics upon, and then equalize. The file names are + separated by new lines. + + + + Click here to see the list of input images to be held + + This list contains the name of one file from the FROMLIST to + be held during calculations. When multiple images are held, + their file names are likewise separated by new lines. + + + + + + + Mosaic of the output images for equalizer + + This is a small section of the equalized output images mosaicked together. + + + TOLIST + + + + + + Calculate Statistics + + This example shows the use of the equalizer application for calculating + equalization statistics and writing them to a file, and not applying the + correction to the input images. + + + fromlist= FromList.lst holdlist=/HoldList.lst + outstats= stats.pvl process= calculate + + + In addition to specifying a fromlist and a holdlist, we must also + specify a location to write the output statistics pvl, and set the + process type to "calculate". Since no output images will be created, + we do not (and can not), specify a tolist. All other options are at + default values. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to calculate + equalization statistics on a set of input images. + + + + + + + + + Mosaic of the input images for equalizer + + This is a a small section of the input images for the equalizer example mosaicked together. + + + FROMLIST + + + + + + Click here to see the list of images to calculate statistics upon + + This list contains the names of three files to calculate + statistics upon. The file names are + separated by new lines. + + + + Click here to see the list of input images to be held + + This list contains the name of one file from the FROMLIST to + be held during calculations. When multiple images are held, + their file names are likewise separated by new lines. + + + + Click here to see the output text file containing statistics for equalizing + + This pvl contains thorough equalization-related statistics + that can be used for applying correction to any or all images + used to generate this file. + + + + + + + Apply Correction + + This example shows the use of the equalizer application for applying + correction to a subset of the images used to produce a specified input + statistics file. + + + fromlist= Input.lst tolist= Output.lst instats= + stats.pvl process= apply + + + Specify a fromlist that is a sublist of the fromlist from Example 2. + Because calculations have already been performed, no holdlist is + specified, and since we want to place the output images in a specific + location with specific names, a tolist is specified. Finally, we set + the value of the instats parameter to be the output statistics file + generated in Example 2, and set the process to "apply". All other + options are at default values. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to apply correction to a + subset of the images used to produce a specified input statistics + file. + + + + + + + + + Click here to see the list of images to be equalized + + This list contains the names of two files to equalize. Both + file names appear in the FROMLIST file from the previous + example, and both file names have calculated gain and offset + coefficients calculated for them in the INSTATS file. Since we + do not wish to create a new file for the held image, however, + we chose not to include it in this new list. The file names + are separated by new lines. + + + + Click here to see the list of images to write after equalization + + This list contains the names of two files to be written as + outputs from the equalization process. The index of each file + name corresponds to the index of a file from this example's + FROMLIST file. Here, the output images retain their original + names, but are written to the current directory. + + + + Click here to see the input text file containing statistics for equalizing + + This pvl contains thorough equalization-related statistics for + applying correction to any or all images used to generate this + file. In this example, two of the three files used to + generate these statistics have been selected for equalization. + + + + + + + Mosaic of the output images for equalizer + + This is a small section of the equalized output images and the + held image from Example 2 mosaicked together. Note that since we + only chose to omit the held image from Example 2 when + applying correction, that the results are the same as those in + Example 1. + + + TOLIST + + + + +
    diff --git a/isis/src/base/apps/equalizer/tsts/Makefile b/isis/src/base/apps/equalizer/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/equalizer/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/equalizer/tsts/apply/Makefile b/isis/src/base/apps/equalizer/tsts/apply/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..aba3d8f6a31c96b6b7e3ea11fe9873d7ce36905e --- /dev/null +++ b/isis/src/base/apps/equalizer/tsts/apply/Makefile @@ -0,0 +1,12 @@ +APPNAME = equalizer + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) fromlist=$(INPUT)/FromList.lst \ + tolist=$(INPUT)/ToList.lst \ + instats=$(INPUT)/instats.pvl \ + process=apply \ + > /dev/null; + $(MV) I00824006RDR.lev2.equ.cub $(OUTPUT)/equalizerTruth1.cub; + $(MV) I01523019RDR.lev2.equ.cub $(OUTPUT)/equalizerTruth2.cub; diff --git a/isis/src/base/apps/equalizer/tsts/calculate/Makefile b/isis/src/base/apps/equalizer/tsts/calculate/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8bf0918556245cd64ad32aea24b5f4cf13e186d7 --- /dev/null +++ b/isis/src/base/apps/equalizer/tsts/calculate/Makefile @@ -0,0 +1,10 @@ +APPNAME = equalizer + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) fromlist=$(INPUT)/FromList.lst \ + holdlist=$(INPUT)/HoldList.lst \ + outstats=$(OUTPUT)/outstats.pvl \ + process=calculate \ + > /dev/null; diff --git a/isis/src/base/apps/equalizer/tsts/case01/Makefile b/isis/src/base/apps/equalizer/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2aab2210b1b54de8c9f7c046d455f9e127d497b4 --- /dev/null +++ b/isis/src/base/apps/equalizer/tsts/case01/Makefile @@ -0,0 +1,12 @@ +APPNAME = equalizer + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) fromlist=$(INPUT)/FromList.lst \ + holdlist=$(INPUT)/HoldList.lst \ + tolist=$(INPUT)/ToList.lst \ + > /dev/null; + $(MV) I00824006RDR.lev2.equ.cub $(OUTPUT)/equalizerTruth1.cub; + $(MV) I01523019RDR.lev2.equ.cub $(OUTPUT)/equalizerTruth2.cub; + $(MV) I02609002RDR.lev2.equ.cub $(OUTPUT)/equalizerTruth3.cub; diff --git a/isis/src/base/apps/equalizer/tsts/default/Makefile b/isis/src/base/apps/equalizer/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2aab2210b1b54de8c9f7c046d455f9e127d497b4 --- /dev/null +++ b/isis/src/base/apps/equalizer/tsts/default/Makefile @@ -0,0 +1,12 @@ +APPNAME = equalizer + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) fromlist=$(INPUT)/FromList.lst \ + holdlist=$(INPUT)/HoldList.lst \ + tolist=$(INPUT)/ToList.lst \ + > /dev/null; + $(MV) I00824006RDR.lev2.equ.cub $(OUTPUT)/equalizerTruth1.cub; + $(MV) I01523019RDR.lev2.equ.cub $(OUTPUT)/equalizerTruth2.cub; + $(MV) I02609002RDR.lev2.equ.cub $(OUTPUT)/equalizerTruth3.cub; diff --git a/isis/src/base/apps/errors/Makefile b/isis/src/base/apps/errors/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/errors/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/errors/assets/errors.log b/isis/src/base/apps/errors/assets/errors.log new file mode 100644 index 0000000000000000000000000000000000000000..8b59daec4a1aa120e4251bd4a406c9befb8fffaf --- /dev/null +++ b/isis/src/base/apps/errors/assets/errors.log @@ -0,0 +1,40 @@ +Object = phocube + IsisVersion = "3.1.14beta | 2007-08-23" + ProgramVersion = 2006-09-21 + ProgramPath = /usgs/pkgs/isis3nightly/isis/bin + ExecutionDateTime = 2007-11-05T11:51:17 + HostName = blackflag + UserName = smkoechle + Description = "Creates phase, incidence, and/or emmision angle bands + for a cube" + + Group = UserParameters + FROM = /usgs/cpkgs/isis3/testData/isis/src/cassini/apps/ciss2isis/tsts/narrowAngle/truth/N1472853667_1.truth.cub + TO = out.cub + PHASE = TRUE + EMISSION = TRUE + INCIDENCE = TRUE + LATITUDE = TRUE + LONGITUDE = TRUE + End_Group + + Group = Error + Program = phocube + Class = "CAMERA ERROR" + Code = 6 + Message = "Unable to initialize camera model from group [Instrument]" + File = CameraFactory.cpp + Line = 82 + End_Group + + Group = Error + Program = phocube + Class = "PVL ERROR" + Code = 3 + Message = "Keyword [InstrumentPosition] does not exist in [Group = + Kernels]" + File = PvlContainer.cpp + Line = 75 + End_Group +End_Object +End diff --git a/isis/src/base/apps/errors/assets/run.log b/isis/src/base/apps/errors/assets/run.log new file mode 100644 index 0000000000000000000000000000000000000000..8ffad8178e81d34011193afeb4c793efa62b3b8e --- /dev/null +++ b/isis/src/base/apps/errors/assets/run.log @@ -0,0 +1,81 @@ +Object = stats + IsisVersion = "3.1.14beta | 2007-08-23" + ProgramVersion = 2006-01-23 + ProgramPath = /usgs/pkgs/isis3nightly/isis/bin + ExecutionDateTime = 2007-11-05T11:38:41 + HostName = blackflag + UserName = smkoechle + Description = "Generates statistics about a cube" + + Group = UserParameters + FROM = /usgs/cpkgs/isis3/data/mro/testData/ctx_pmoi_i_00003.bottom.cub + End_Group + + Group = Results + From = /usgs/cpkgs/isis3/data/mro/testData/ctx_pmoi_i_00003.bottom.cub + Average = 831.548116 + StandardDeviation = 135.62724726194 + Variance = 18394.750199851 + Median = 861.0 + Mode = 978.0 + Skew = -0.65145945069103 + Minimum = 426.0 + Maximum = 1103.0 + Sum = 207887029.0 + TotalPixels = 250000 + ValidPixels = 250000 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 + End_Group + + Group = Accounting + ConnectTime = 00:00:00.0 + CpuTime = 00:00:00.1 + End_Group +End_Object + + +Object = phocube + IsisVersion = "3.1.14beta | 2007-08-23" + ProgramVersion = 2006-09-21 + ProgramPath = /usgs/pkgs/isis3nightly/isis/bin + ExecutionDateTime = 2007-11-05T11:51:17 + HostName = blackflag + UserName = smkoechle + Description = "Creates phase, incidence, and/or emmision angle bands + for a cube" + + Group = UserParameters + FROM = /usgs/cpkgs/isis3/testData/isis/src/cassini/apps/ciss2isis/tsts/narrowAngle/truth/N1472853667_1.truth.cub + TO = out.cub + PHASE = TRUE + EMISSION = TRUE + INCIDENCE = TRUE + LATITUDE = TRUE + LONGITUDE = TRUE + End_Group + + Group = Error + Program = phocube + Class = "CAMERA ERROR" + Code = 6 + Message = "Unable to initialize camera model from group [Instrument]" + File = CameraFactory.cpp + Line = 82 + End_Group + + Group = Error + Program = phocube + Class = "PVL ERROR" + Code = 3 + Message = "Keyword [InstrumentPosition] does not exist in [Group = + Kernels]" + File = PvlContainer.cpp + Line = 75 + End_Group +End_Object + + diff --git a/isis/src/base/apps/errors/errors.cpp b/isis/src/base/apps/errors/errors.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9bbe4cba01e2f151141e7706bfd23327007513f4 --- /dev/null +++ b/isis/src/base/apps/errors/errors.cpp @@ -0,0 +1,41 @@ +#include "Isis.h" + +#include + +using namespace std; +using namespace Isis; + +void IsisMain() { + + UserInterface &ui = Application::GetUserInterface(); + bool append = ui.GetBoolean("APPEND"); + Pvl input (ui.GetFilename("FROM")); + Pvl output; + + // Check to see if output file exists + Filename outFile = ui.GetFilename("TO"); + if (outFile.exists()&&!append) { + string msg = "Output file [" + outFile.Expanded() + "] already exists."; + msg += " Append option set to False."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + int numErrors = 0; + // Search for errors and add to output + for (int i =0; i < input.Objects(); i++) { + PvlObject o = input.Object(i); + if (o.HasGroup("Error")) { + output.AddObject(o); + numErrors++; + } + } + PvlKeyword errors("TotalErrors",numErrors); + output.AddKeyword(errors); + // write output to file + if (!append) { + output.Write(outFile.Expanded()); + } else { + output.Append(outFile.Expanded()); + } + cout << errors << endl; +} diff --git a/isis/src/base/apps/errors/errors.xml b/isis/src/base/apps/errors/errors.xml new file mode 100644 index 0000000000000000000000000000000000000000..26d1d210b0bc3e64d05cbcfc0811ba229440d28c --- /dev/null +++ b/isis/src/base/apps/errors/errors.xml @@ -0,0 +1,118 @@ + + + + Parses errors from a SessionLog file + + + + This program will take a SessionLog file as an input, parse for the error groups and output a new file that + contains Session Information that have errors. + + + + Utility + + + + + Original Version + + + Converted from Isis 2 to Isis 3 + + + Added PvlKeyword to top of print file that says how many errors the + print file contains. This value is also printed to the screen. + + + + + + + filename + input + + Session Log file in Pvl format + + + + print.prt + + + + The file is a default session log file output by Isis 3. This file is in PVL format. + + + + + filename + output + + Output file to contain errors. + + + + errors.prt + + + + This file will be in Pvl format and contain the Session Logs from Isis 3 program runs that had errors. + + + + + + boolean + + false + + + Should output file be appended + + + This option allows the user to decide whether to append the output file or not. + + + + + + + + Parsing errors out of a SessionLog file + + This example shows how to get the error sessions from a session log file + + + + from=run.log to error.log + + + Running errors in the command line mode with the both parameters "FROM" + and "TO" set. + + + + + + Input to errors + + + This is the input file to errors generated by running random isis applications. By default this + filename is print.prt + + FROM + + + + Output from errors + + + This is the output captured in "error.log". This file contains error sessions from the input log. + By default this filename is errors.prt + + TO + + + + + diff --git a/isis/src/base/apps/errors/tsts/Makefile b/isis/src/base/apps/errors/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/errors/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/errors/tsts/default/Makefile b/isis/src/base/apps/errors/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..db30cbf91add4578cda34a5f57ceab0ddcfcb868 --- /dev/null +++ b/isis/src/base/apps/errors/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = errors + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/run.log \ + to=$(OUTPUT)/errors.pvl > /dev/null; diff --git a/isis/src/base/apps/explode/Makefile b/isis/src/base/apps/explode/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/explode/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/explode/explode.cpp b/isis/src/base/apps/explode/explode.cpp new file mode 100644 index 0000000000000000000000000000000000000000..818f5ab4167447995afd20c96ba6b1acfcde4e1a --- /dev/null +++ b/isis/src/base/apps/explode/explode.cpp @@ -0,0 +1,63 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "iException.h" +#include "Filename.h" + +using namespace std; +using namespace Isis; + +void CopyBand (Buffer &in, Buffer &out); + +void IsisMain() { + // Get the cube to explode + Process p; + Cube *icube = p.SetInputCube("FROM"); + int samps = icube->Samples(); + int lines = icube->Lines(); + int bands = icube->Bands(); + string infile = icube->Filename(); + + // We the output filename so we can add attributes and extensions + UserInterface &ui = Application::GetUserInterface(); + string outbase = ui.GetFilename("TO"); + CubeAttributeOutput &outatt = ui.GetOutputAttribute("TO"); + + // Loop and extract each band + for (int band=1; band<=bands; band++) { + int pband = icube->PhysicalBand(band); + iString sband(pband); + + ProcessByLine p2; + Progress *prog = p2.Progress(); + prog->SetText("Exploding band " + sband); + + CubeAttributeInput inatt("+" + sband); + p2.SetInputCube(infile,inatt); + + string outfile = outbase + ".band"; + if (pband / 1000 == 0) { + outfile += "0"; + if (pband / 100 == 0) { + outfile += "0"; + if (pband / 10 == 0) { + outfile += "0"; + } + } + } + outfile += sband + ".cub"; + p2.SetOutputCube(outfile,outatt,samps,lines,1); + + p2.StartProcess(CopyBand); + p2.EndProcess(); + } + + // Cleanup + p.EndProcess(); +} + +// Line processing routine +void CopyBand (Buffer &in, Buffer &out) { + for (int i=0; i + + + + Extracts each band of a cube into a separate one band file + + + + This program extracts each band of the input cube into a separate one band file. Given the output base name of + "base", each output cube will be named base.band#.cub. The appropiate + BandBin group will be created. + + + + + cubeit + + + + + Utility + + + + + Original version + + + Fixed percent processed message and added leading zeros to + output cubes + + + Documentation fixes + + + Removed references to CubeInfo + + + + + + + cube + input + + Input cube to be exploded + + + Each band in this cube will be written as a separate cube. + + + *.cub + + + + + cube + output + + Output base cube name + + + The base name of the output cubes. For example, if TO=base, then each output cube will be + base.band#.cub + + + + + diff --git a/isis/src/base/apps/explode/tsts/Makefile b/isis/src/base/apps/explode/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/explode/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/explode/tsts/case01/Makefile b/isis/src/base/apps/explode/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e58baa1d0db1a9ecb50cffdc798811c611d52577 --- /dev/null +++ b/isis/src/base/apps/explode/tsts/case01/Makefile @@ -0,0 +1,7 @@ +APPNAME = explode + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/explTruth1 > /dev/null; diff --git a/isis/src/base/apps/fakecube/Makefile b/isis/src/base/apps/fakecube/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/fakecube/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/fakecube/fakecube.cpp b/isis/src/base/apps/fakecube/fakecube.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aab25e682afe9cc4f6b2421d8801874ba9b09bf2 --- /dev/null +++ b/isis/src/base/apps/fakecube/fakecube.cpp @@ -0,0 +1,77 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void SumLineSample (Buffer &in, Buffer &out); +void LineNumber (Buffer &in, Buffer &out); +void SampleNumber (Buffer &in, Buffer &out); +void CheckerBoard (Buffer &in, Buffer &out); + +int size; + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + UserInterface &ui= Application::GetUserInterface(); + + // Setup the input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + + // Start the processing + string option = ui.GetString("OPTION"); + if (option == "GRADIENT") { + p.StartProcess(SumLineSample); + } + if (option == "LINEWEDGE") { + p.StartProcess(LineNumber); + } + if (option == "SAMPLEWEDGE") { + p.StartProcess(SampleNumber); + } + if (option == "CHECKERBOARD") { + if(ui.WasEntered("SIZE")){ + size = ui.GetInteger("SIZE"); + } + else { + size = 5; + } + p.StartProcess(CheckerBoard); + } + + // End the processing + p.EndProcess(); +} + +// Line processing routines +void SumLineSample (Buffer &in, Buffer &out) { + for (int i=0; i=size && in.Line()%(2*size)>=size) || + (i%(2*size) + + + + Create geometric testing cubes + + + + This program will create a geometric testing cube by using line and sample numbers from the input cube. The pixels in the + output cube will equal the sum of the line and sample numbers, the line number, the sample number, or will create + a checkerboard pattern (5x5 is the default) depending on what pixel option is chosen. This is more of a tool for + programmers developing camera models or other geometric software than the average user. + + + + System + + + + + makecube + + + + + + Original version + + + Documentation fixes + + + + + + + cube + input + + Input cube + + + The input cube whose parameters will be used to create the output cube. + + + *.cub + + + + + cube + output + + Output cube + + + The output cube created with specified pixel values. + + + *.cub + + + + + + string + Options for output cube pixel values + + A list of the possible options for pixel values in the output cube. + + GRADIENT + + + + + + + + + + + integer + input + Size of Checkerboard Squares + + The size, in pixels, of the Checkerboard tiles. Default value is 5x5. + + + + + + diff --git a/isis/src/base/apps/fakecube/tsts/Makefile b/isis/src/base/apps/fakecube/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/fakecube/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/fakecube/tsts/checkerboard/Makefile b/isis/src/base/apps/fakecube/tsts/checkerboard/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..86efd88ec3e45369f2bcc4fd685bcff889a48ae7 --- /dev/null +++ b/isis/src/base/apps/fakecube/tsts/checkerboard/Makefile @@ -0,0 +1,8 @@ +APPNAME = fakecube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/fakecubeTruth4.cub \ + option=checkerboard > /dev/null; diff --git a/isis/src/base/apps/fakecube/tsts/gradient/Makefile b/isis/src/base/apps/fakecube/tsts/gradient/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..217e4060562fe7c41de59c42b6a122677844f19e --- /dev/null +++ b/isis/src/base/apps/fakecube/tsts/gradient/Makefile @@ -0,0 +1,8 @@ +APPNAME = fakecube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/fakecubeTruth1.cub \ + option=gradient > /dev/null; diff --git a/isis/src/base/apps/fakecube/tsts/linewedge/Makefile b/isis/src/base/apps/fakecube/tsts/linewedge/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cf4c889079c646b2690f58fd2cbbbeddfc367e2e --- /dev/null +++ b/isis/src/base/apps/fakecube/tsts/linewedge/Makefile @@ -0,0 +1,8 @@ +APPNAME = fakecube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/fakecubeTruth2.cub \ + option=linewedge > /dev/null; diff --git a/isis/src/base/apps/fakecube/tsts/samplewedge/Makefile b/isis/src/base/apps/fakecube/tsts/samplewedge/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a3aafb3ec08c49668f7c8c69a0061d70d1d4a85f --- /dev/null +++ b/isis/src/base/apps/fakecube/tsts/samplewedge/Makefile @@ -0,0 +1,8 @@ +APPNAME = fakecube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1\ + to=$(OUTPUT)/fakecubeTruth3.cub \ + option=samplewedge > /dev/null; diff --git a/isis/src/base/apps/fft/Makefile b/isis/src/base/apps/fft/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/fft/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/fft/assets/image/fftGui.jpg b/isis/src/base/apps/fft/assets/image/fftGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5fbe8daf1f9eddeb7a7b07761a2c6c60463cf5ac Binary files /dev/null and b/isis/src/base/apps/fft/assets/image/fftGui.jpg differ diff --git a/isis/src/base/apps/fft/assets/image/fftMag.jpg b/isis/src/base/apps/fft/assets/image/fftMag.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8e1a458108ce7762030cfdd471a4130a40203cfe Binary files /dev/null and b/isis/src/base/apps/fft/assets/image/fftMag.jpg differ diff --git a/isis/src/base/apps/fft/assets/image/fftPhase.jpg b/isis/src/base/apps/fft/assets/image/fftPhase.jpg new file mode 100755 index 0000000000000000000000000000000000000000..d3c7bd16841b082a327f78ce4ec46aa65f59243a Binary files /dev/null and b/isis/src/base/apps/fft/assets/image/fftPhase.jpg differ diff --git a/isis/src/base/apps/fft/assets/image/peaks.jpg b/isis/src/base/apps/fft/assets/image/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..ef1a24efc0554596f440e9e349fa223994594094 Binary files /dev/null and b/isis/src/base/apps/fft/assets/image/peaks.jpg differ diff --git a/isis/src/base/apps/fft/assets/thumb/fftGui.jpg b/isis/src/base/apps/fft/assets/thumb/fftGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3339e828879cfe8d487ef1559ec1f6d94349e3a3 Binary files /dev/null and b/isis/src/base/apps/fft/assets/thumb/fftGui.jpg differ diff --git a/isis/src/base/apps/fft/assets/thumb/fftMag.jpg b/isis/src/base/apps/fft/assets/thumb/fftMag.jpg new file mode 100755 index 0000000000000000000000000000000000000000..9fadc798dcbde8a778524e78f150f8bea70ff099 Binary files /dev/null and b/isis/src/base/apps/fft/assets/thumb/fftMag.jpg differ diff --git a/isis/src/base/apps/fft/assets/thumb/fftPhase.jpg b/isis/src/base/apps/fft/assets/thumb/fftPhase.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8f1ecda713eafd78a89a483c236c7b4aa31598ae Binary files /dev/null and b/isis/src/base/apps/fft/assets/thumb/fftPhase.jpg differ diff --git a/isis/src/base/apps/fft/assets/thumb/peaks.jpg b/isis/src/base/apps/fft/assets/thumb/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..d2d9cfe5f9049bb36047091aba8740119f7cca35 Binary files /dev/null and b/isis/src/base/apps/fft/assets/thumb/peaks.jpg differ diff --git a/isis/src/base/apps/fft/fft.cpp b/isis/src/base/apps/fft/fft.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6f3be2186bb5409d028dde430957f2fc1e03b840 --- /dev/null +++ b/isis/src/base/apps/fft/fft.cpp @@ -0,0 +1,166 @@ +#include "Isis.h" +#include +#include "FourierTransform.h" +#include "ProcessByTile.h" +#include "Statistics.h" +#include "AlphaCube.h" + +using namespace std; +using namespace Isis; + +void FFT1 (vector &in, vector &out); +void FFT2 (vector &in, vector &out); +void getMinMax(Buffer &in); + +FourierTransform fft; +string tmpMagFilename = "Temporary_IFFT_Magnitude.cub"; +string tmpPhaseFilename = "Temporary_IFFT_Phase.cub"; +double HPixel = 0.0, LPixel = 0.0, NPixel = 0.0; + +Statistics stats; + +void IsisMain() +{ + // We will be processing by sample first + ProcessByTile sProc; + + // Setup the input and output cubes + Cube *icube = sProc.SetInputCube("FROM"); + int numSamples = fft.NextPowerOfTwo(icube->Samples()); + int numLines = fft.NextPowerOfTwo(icube->Lines()); + int numBands = icube->Bands(); + + sProc.SetTileSize(1, numLines); + + // create an AlphaCube containing the resizing information + // which will be used during the inverse + AlphaCube aCube(icube->Samples(),icube->Lines(), + icube->Samples(),icube->Lines()); + + UserInterface &ui = Application::GetUserInterface(); + + string replacement = ui.GetString("REPLACEMENT"); + if (replacement == "ZEROES") { + HPixel = 0.0; + LPixel = 0.0; + NPixel = 0.0; + } + else if(replacement == "MINMAX") { + sProc.Progress()->SetText("Getting Statistics"); + sProc.StartProcess(getMinMax); + LPixel = stats.Minimum(); + HPixel = stats.Maximum(); + NPixel = 0.0; + } + sProc.Progress()->SetText("First pass"); + + // The output cube with no attributes and real pixel type + Isis::CubeAttributeOutput cao; + cao.PixelType(Isis::Real); + + sProc.SetOutputCube (tmpMagFilename, cao, numSamples, numLines, numBands); + sProc.SetOutputCube (tmpPhaseFilename, cao, numSamples, numLines, numBands); + + // Start the sample processing + sProc.StartProcess(FFT1); + sProc.EndProcess(); + + // Then process by line + ProcessByTile lProc; + lProc.SetTileSize(numSamples, 1); + + lProc.Progress()->SetText("Second pass"); + + // Setup the input and output cubes + Isis::CubeAttributeInput cai; + + lProc.SetInputCube(tmpMagFilename, cai); + lProc.SetInputCube(tmpPhaseFilename, cai); + + Cube *ocube = lProc.SetOutputCube("MAGNITUDE"); + lProc.SetOutputCube("PHASE"); + + //Start the line proccessing + lProc.StartProcess(FFT2); + + // Add or update the AlphaCube group + aCube.UpdateGroup(*ocube->Label()); + + // Stop the process and remove the temporary files + lProc.EndProcess(); + + remove(tmpMagFilename.c_str()); + remove(tmpPhaseFilename.c_str()); +} + +// Processing routine for the fft with one input cube +void FFT1 (vector &in, vector &out) +{ + Buffer &image = *in[0]; + + int n = image.size(); + std::vector< std::complex > input(n); + + // copy the input data into a complex vector + for (int i=0; i(image[i]); + } + + // perform the fourier transform + std::vector< std::complex > output = fft.Transform(input); + n = output.size(); + + Buffer &realCube = *out[0]; + Buffer &imagCube = *out[1]; + + // copy the data into the two output cubes so that it is centered at the origin + for (int i=0; i &in, vector &out) +{ + // Set the input cubes + Buffer &inReal = *in[0]; + Buffer &inImag = *in[1]; + + // copy the input buffer into a complex vector + int n = inReal.size(); + std::vector< std::complex > input(n); + + for (int i=0; i(inReal[i], inImag[i]); + } + + // perform the fourier transform + std::vector< std::complex > output = fft.Transform(input); + n = output.size(); + + Buffer &magCube = *out[0]; + Buffer &phaseCube = *out[1]; + + // copy the data into the two output cubes so that it is centered at the origin + for (int i=0; i + + + Apply a Fourier Transform on a cube + + + + This programs takes a single input cube, applies a Fourier Transform, + and stores the result in two bands of an output cube containing the magnitude and + phase angle data. If the original image has dimensions that are not powers + of two, it is automatically padded with zeroes. These images can then be + used in the ifft program to recover the original. + + + + Fourier Domain + + + + + ifft + + + + + + Original version + + + Documentation fixes + + + Removed references to CubeInfo + + + Documentation fixes: Created images for the GUI screenshots, + which were missing. + + + + + + + cube + input + + Input file to apply the transform to + + + The input cube on which the Fourier transform is applied. + + + *.cub + + + + + cube + real + output + + Magnitude output cube + + + The resultant cube containing the image magnitude data. + + + *.cub + + + + + cube + real + output + + Phase output cube + + + The resultant cube containing the image phase angle data.. + + + *.cub + + + + + + + + string + + ZEROES + + Replacement value + + This option specifies what special pixels will be replaced with. + + + + + + + + + + + + fft example + + Example of the Fourier transform. + + + from=peaks.cub magnitude=peaks_magnitude.cub phase=peaks_phase.cub + + Compute the Fourier transform of peaks.cub and store the results in peaks_magnitude.cub and peaks_phase.cub + + + + + Input image for fft + This is the input image, peaks.cub. + + + FROM + + + + + Example magnitude output + This is the magnitude output of the transform of peaks.cub. + + + MAGNITUDE + + + + Example phase output + This is the phase output of the transform of peaks.cub. + + + PHASE + + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform the fft application + + + + + + + + diff --git a/isis/src/base/apps/fft/tsts/Makefile b/isis/src/base/apps/fft/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/fft/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/fft/tsts/case01/Makefile b/isis/src/base/apps/fft/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3f86ee0cfc98881f0d33bb0efddcea5604e83fa1 --- /dev/null +++ b/isis/src/base/apps/fft/tsts/case01/Makefile @@ -0,0 +1,8 @@ +APPNAME = fft + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/testImage.cub \ + magnitude=$(OUTPUT)/fftMagTruth.cub \ + phase= $(OUTPUT)/fftPhaseTruth.cub > /dev/null; diff --git a/isis/src/base/apps/fillgap/Makefile b/isis/src/base/apps/fillgap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7b486932c1dd0c9d42d7e4d40e74cf578e1977b8 --- /dev/null +++ b/isis/src/base/apps/fillgap/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = fillgap + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.jpeg b/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..911eb3f72e4356b389e6c0de532efb48c3534bbb Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.jpeg differ diff --git a/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.line.gui.jpeg b/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.line.gui.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..6050e3045e7796564480ee59f6e635587a66e121 Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.line.gui.jpeg differ diff --git a/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.line.jpeg b/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.line.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..48dad28ef730e77ac7666bb9a7e5c0c331ee107e Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.line.jpeg differ diff --git a/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.linesamp.gui.jpeg b/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.linesamp.gui.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..ab487a601e2050aeb385d24a1c29c3b5ffadcb82 Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.linesamp.gui.jpeg differ diff --git a/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.linesamp.jpeg b/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.linesamp.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..ef99e6fcfde01df21f6845d9d46dc7341db5c632 Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/image/N1506393614_2.sp.linesamp.jpeg differ diff --git a/isis/src/base/apps/fillgap/assets/image/fillgapGui.JPG b/isis/src/base/apps/fillgap/assets/image/fillgapGui.JPG new file mode 100755 index 0000000000000000000000000000000000000000..796072ecb936de20c673b8584220bf9974a051ff Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/image/fillgapGui.JPG differ diff --git a/isis/src/base/apps/fillgap/assets/image/peaks-fixed.JPG b/isis/src/base/apps/fillgap/assets/image/peaks-fixed.JPG new file mode 100755 index 0000000000000000000000000000000000000000..7c9720eb68eafaa45eb657f5a3aeb6d02191fa9a Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/image/peaks-fixed.JPG differ diff --git a/isis/src/base/apps/fillgap/assets/image/peaks-horizline.JPG b/isis/src/base/apps/fillgap/assets/image/peaks-horizline.JPG new file mode 100755 index 0000000000000000000000000000000000000000..1cc289c891f526aca745ac5b92fccd79ba919f47 Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/image/peaks-horizline.JPG differ diff --git a/isis/src/base/apps/fillgap/assets/image/warningMessage.JPG b/isis/src/base/apps/fillgap/assets/image/warningMessage.JPG new file mode 100755 index 0000000000000000000000000000000000000000..0629233296f774864ddbceb008eb9b758d8dced9 Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/image/warningMessage.JPG differ diff --git a/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.line.gui.thumb.jpeg b/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.line.gui.thumb.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7925a4f7a9cc91c0b137d90471c6c48c76e59be5 Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.line.gui.thumb.jpeg differ diff --git a/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.line.thumb.jpeg b/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.line.thumb.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..299f44335a1538174d802c68f62f14a0a2afeb14 Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.line.thumb.jpeg differ diff --git a/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.linesamp.gui.thumb.jpeg b/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.linesamp.gui.thumb.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..29e0982d087f1818bf520cba8437f18b3b255f95 Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.linesamp.gui.thumb.jpeg differ diff --git a/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.linesamp.thumb.jpeg b/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.linesamp.thumb.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5546d1afb686dcd65a4f03c79b896b68674c4a42 Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.linesamp.thumb.jpeg differ diff --git a/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.thumb.jpeg b/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.thumb.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5326e714f8aa65f9659c0a392a38f2012cb4a216 Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/thumb/N1506393614_2.sp.thumb.jpeg differ diff --git a/isis/src/base/apps/fillgap/assets/thumb/fillgapGui.JPG b/isis/src/base/apps/fillgap/assets/thumb/fillgapGui.JPG new file mode 100755 index 0000000000000000000000000000000000000000..e341ee04e444f043f1f20f5aaae89ff67b9cc31a Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/thumb/fillgapGui.JPG differ diff --git a/isis/src/base/apps/fillgap/assets/thumb/peaks-fixed.JPG b/isis/src/base/apps/fillgap/assets/thumb/peaks-fixed.JPG new file mode 100755 index 0000000000000000000000000000000000000000..215e5d151dddca25c585c4d3db73c7b9df6f9dc0 Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/thumb/peaks-fixed.JPG differ diff --git a/isis/src/base/apps/fillgap/assets/thumb/peaks-horizline.JPG b/isis/src/base/apps/fillgap/assets/thumb/peaks-horizline.JPG new file mode 100755 index 0000000000000000000000000000000000000000..649686e4201031f53e7f0d9d79ff6705cc981ce6 Binary files /dev/null and b/isis/src/base/apps/fillgap/assets/thumb/peaks-horizline.JPG differ diff --git a/isis/src/base/apps/fillgap/fillgap.cpp b/isis/src/base/apps/fillgap/fillgap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e940de840b6853c629482dd85ae3a2455b48ce8 --- /dev/null +++ b/isis/src/base/apps/fillgap/fillgap.cpp @@ -0,0 +1,122 @@ +#include "Isis.h" +#include +#include "ProcessBySample.h" +#include "ProcessByLine.h" +#include "ProcessBySpectra.h" +#include "NumericalApproximation.h" +#include "SpecialPixel.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +static NumericalApproximation::InterpType iType(NumericalApproximation::CubicNatural); + +void fill(Buffer &in, Buffer &out); + +//Global variables +int numSpecPixKept; + +void IsisMain() { + // initialize global variables + numSpecPixKept = 0; + + UserInterface &ui = Application::GetUserInterface(); + + // set spline interpolation to user requested type + string splineType = ui.GetString("INTERP"); + if (splineType == "LINEAR") { + iType = NumericalApproximation::Linear; + } + else if (splineType == "AKIMA") { + iType = NumericalApproximation::Akima; + } + else { + iType = NumericalApproximation::CubicNatural; + } + + //Set null direction to the user defined direction + string Dir = ui.GetString("DIRECTION"); + if(Dir == "SAMPLE"){ + ProcessBySample p; + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + p.StartProcess(fill); + p.EndProcess(); + } + else if (Dir == "LINE") { + ProcessByLine p; + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + p.StartProcess(fill); + p.EndProcess(); + } + else if (Dir == "BAND") { + ProcessBySpectra p; + //Check number of bands to see if this will be allowed. + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + p.StartProcess(fill); + p.EndProcess(); + } + // if any pixels were not filled, let user know by adding message to the log + if (numSpecPixKept > 0) { + PvlGroup mLog("Messages"); + mLog+=PvlKeyword("Warning", + "Unable to fill " + iString(numSpecPixKept) + " special pixels."); + Application::Log(mLog); + } + return; +} + +/** + * @brief Fill in gaps of image using an interpolation on the DN + * values. + * + * @param in Input Buffer + * @param out Output Buffer + * @internal + * @history 2009-04-21 Jeannie Walldren - Added a try/catch + * statement to the Evaluate() method. The only + * reason for Evaluate to throw an error should be + * when (j+1) is outside the spline's domain. This + * happens when there is at least one special pixel + * at an endpoint of the buffer. Rather than + * extrapolating, we keep the original value. If + * these pixels are not in a corner, the user can + * fill these by running the app again in a different + * direction. Otherwise, a box filter may be used. + * The global variable numSpecPixKept is incremented so we + * can keep a count of how many pixels were not + * filled by this app. + */ +void fill(Buffer &in, Buffer &out) { + + // Fill the data set with valid pixel values + NumericalApproximation spline(iType); + for (int i=0; i < in.size(); i++) { + if (!IsSpecial(in[i])) { + spline.AddData((double) (i+1),in[i]); + } + } + + // loop through output buffer + for (int j = 0 ; j < out.size() ; j++) { + // if the input pixel is valid, copy it + if (!IsSpecial(in[j])) { + out[j] = in[j]; + } + // otherwise, try to interpolate from the valid values + else{ + try{ + out[j] = spline.Evaluate((double) (j+1)); + } + // if Evaluate() fails, copy the input value and increment numSpecPixKept + catch (iException &e){ + out[j] = in[j]; + numSpecPixKept++; + } + } + } + return; +} diff --git a/isis/src/base/apps/fillgap/fillgap.xml b/isis/src/base/apps/fillgap/fillgap.xml new file mode 100644 index 0000000000000000000000000000000000000000..1789f74e42b19da5b9a34f0dede898a831a7f7be --- /dev/null +++ b/isis/src/base/apps/fillgap/fillgap.xml @@ -0,0 +1,322 @@ + + + + Compute interpolations to replace special pixels. + + + + This program will fill in the gaps of a cube (i.e. replace special pixels + with DN values) by using an interpolation scheme and a direction specified + by the user. + +

    Note: This application will not extrapolate DN + values beyond the endpoints of a data set. For example, if you choose to + fill gaps that run across lines, then any special pixel values in the + first or last vertical column of the image will not be filled. If any of + these are not in a corner, you can run fillgap again using the output of + the first run as input and SAMPLE as the DIRECTION parameter. Corner + pixels can be filled by using the + specpix application or the + lowpass filter application. +

    +
    + + + Math and Statistics + + + + + based off slither - first version of fillgap + + + Changed INTERP option CUBIC's name to CUBICCONVOLUTION to correlate with + other apps using the INTERP param. + + + Removed references to DataInterp class and replaced them with + NumericalApproximation class. + + + Added an exception catch so the application may continue if the + interpolation fails for some pixel. Added a message to the log to inform + users how many pixels were not filled. Updated user documentation to + explain what they may do if this occurs. Changed the INTERP parameter + CUBICCONVOLUTION back to CUBIC since this application uses a cubic spline, + not cubic convolution. Added test cases and documentation examples. + + + + + + + cube + input + + Input file. + + + Input file to be filled. + + + *.cub + + + + + cube + output + + Output file. + + + Output cube. + + + *.cub + + + + + + string + CUBIC + Interpolation type to be used on the line and sample transform + + fillgap provides 3 different interpolation options. The + interpolation option chosen is used to compute a continuous (or + piecewise continous) interpolation so that each line and sample + has a transform location that maps the output line and sample + to a shifted input line and sample. These interpolations provide + this mapping. This is done by collecting the known DN values for + each line or sample column and using the chosen interpolation scheme + to approximate the missing DN values (special pixels). + + + + + + + + + + + + string + + SAMPLE + + Direction of bad pixels + + This is the direction of the special pixels across the image. If the special pixels run through the bands of the image data, + try both directions to see which works best. + + + + + + + + + + + + Fill horizontal gaps of peaks image + + This example shows the fillgap application using the default parameters + SAMPLE and CUBIC. This will fill horizontal gaps in data using a + cubic spline on the DN values of each vertical column of samples. + + + from=../IN/peaks-h-null.cub to=OUT/output.cub interp=cubic direction=sample + + + fillgap gui example + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform + a fillgap operation on the input image. + + + + + + + + Input image for fillgap + This is the input image for the fillgap example with null horizontal line. + + + FROM + + + + + Output image for fillgap + This is the output image that results after a cubic interpolation to fill the null data gaps. + + + TO + + + + + Fill gaps of Cassini ISS image + + This example shows the fillgap application using the LINE and CUBIC + parameters. This will fill vertical gaps in data using a cubic spline + on the DN values of each horizontal line. + + + from=../IN/N1506393614_2.sp.cub + to=OUT/N1506393614_2.sp.line.cub interp=cubic direction=line + + + fillgap gui example + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform + a fillgap operation on the input image. + + + + + + + + Input image for fillgap + + This is a Cassini ISS image that has been altered to include each + type of special pixels on an edge of the image. + + + FROM + + + + + Output image for fillgap + + This is the output image that results after a cubic interpolation to + fill the special pixel data gaps. Notice the special pixels that + move across samples and touch edges are not filled. This + includes the block of null pixels at the top left corner of the + image. This happens because the valid data only does not exist on + both sides of these gaps and extrapolation is not permited. However, + the special pixels that touch the upper and lower edges are filled + since these gaps move across lines. + + + TO + + + + + Fill gaps of Cassini ISS image + + This example shows the fillgap application on the output of Example 2. + Here we use the SAMPLE parameter to fill the remaining horizontal gaps in + data using the DN values of each vertical column of samples. + + + from=../IN/N1506393614_2.sp.line.cub + to=OUT/N1506393614_2.sp.linesamp.cub interp=cubic direction=sample + + + fillgap gui example + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform + a fillgap operation on the input image. + + + + + + + + Input image for fillgap + + This is a Cassini ISS image that has been altered to include each + type of special pixels on an edge of the image. Some of these + pixels have already been filled by a previous run of fill gap (see + Example 2). + + + FROM + + + + + Output image for fillgap + + This is the output image that results after a cubic interpolation to + fill the special pixel data gaps. Notice all special pixels have + been filled except the top left corner of the image. Special pixels + in the corners of an image can not be filled by the fillgap + application since they are beyond the endpoints of any known data + values (i.e. DNs values of samples and lines). + + + TO + + + + +
    + diff --git a/isis/src/base/apps/fillgap/tsts/Makefile b/isis/src/base/apps/fillgap/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/fillgap/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/fillgap/tsts/bandakima/Makefile b/isis/src/base/apps/fillgap/tsts/bandakima/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fea76699f13f0cb78c66bde616bd90e8034670a0 --- /dev/null +++ b/isis/src/base/apps/fillgap/tsts/bandakima/Makefile @@ -0,0 +1,9 @@ +APPNAME = fillgap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/CM_1540484434_1_001.ir.addedSpecPix.cub \ + to= $(OUTPUT)/bandakimaresults.cub \ + direction=band \ + interp=akima > /dev/null; diff --git a/isis/src/base/apps/fillgap/tsts/bandcubic/Makefile b/isis/src/base/apps/fillgap/tsts/bandcubic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b3ad3d098fcdcd05f10184476b91cf9f88574612 --- /dev/null +++ b/isis/src/base/apps/fillgap/tsts/bandcubic/Makefile @@ -0,0 +1,8 @@ +APPNAME = fillgap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/CM_1540484434_1_001.ir.addedSpecPix.cub \ + to= $(OUTPUT)/bandcubicresults.cub \ + direction=band > /dev/null; diff --git a/isis/src/base/apps/fillgap/tsts/bandlinear/Makefile b/isis/src/base/apps/fillgap/tsts/bandlinear/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8aef046b3dc4f5b50bdae01fd9c93c1107c0d71a --- /dev/null +++ b/isis/src/base/apps/fillgap/tsts/bandlinear/Makefile @@ -0,0 +1,9 @@ +APPNAME = fillgap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/CM_1540484434_1_001.ir.addedSpecPix.cub \ + to= $(OUTPUT)/bandlinearresults.cub \ + direction=band \ + interp=linear > /dev/null; diff --git a/isis/src/base/apps/fillgap/tsts/gapsOnEdges/Makefile b/isis/src/base/apps/fillgap/tsts/gapsOnEdges/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e67c15082bf6a177a0f02531a75df163730da4f3 --- /dev/null +++ b/isis/src/base/apps/fillgap/tsts/gapsOnEdges/Makefile @@ -0,0 +1,8 @@ +APPNAME = fillgap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/N1506393614_2.addedSpecPix.cub \ + to= $(OUTPUT)/specPixlinecubicresults.cub \ + direction=line > /dev/null; diff --git a/isis/src/base/apps/fillgap/tsts/horzakima/Makefile b/isis/src/base/apps/fillgap/tsts/horzakima/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c2b5d1768354d3eac314412dea1d29458a84b469 --- /dev/null +++ b/isis/src/base/apps/fillgap/tsts/horzakima/Makefile @@ -0,0 +1,8 @@ +APPNAME = fillgap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/peaks.cub \ + to= $(OUTPUT)/filled.cub \ + interp=akima > /dev/null; diff --git a/isis/src/base/apps/fillgap/tsts/horzcubic/Makefile b/isis/src/base/apps/fillgap/tsts/horzcubic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ce21d8a2a9f24a27a8f4187f1e73eff1576b7ad2 --- /dev/null +++ b/isis/src/base/apps/fillgap/tsts/horzcubic/Makefile @@ -0,0 +1,7 @@ +APPNAME = fillgap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/peaks.cub \ + to= $(OUTPUT)/filled.cub > /dev/null; diff --git a/isis/src/base/apps/fillgap/tsts/horzlinear/Makefile b/isis/src/base/apps/fillgap/tsts/horzlinear/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..42219dcf9be440007fd18b0da9d99a1f279abe50 --- /dev/null +++ b/isis/src/base/apps/fillgap/tsts/horzlinear/Makefile @@ -0,0 +1,8 @@ +APPNAME = fillgap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/peaks.cub \ + to= $(OUTPUT)/filled.cub \ + interp=linear > /dev/null; diff --git a/isis/src/base/apps/fillgap/tsts/vertakima/Makefile b/isis/src/base/apps/fillgap/tsts/vertakima/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f2331ce76c81022b144c31dc331b2e6eb0879c35 --- /dev/null +++ b/isis/src/base/apps/fillgap/tsts/vertakima/Makefile @@ -0,0 +1,9 @@ +APPNAME = fillgap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/peaks.cub \ + to= $(OUTPUT)/filled.cub \ + interp=akima \ + direction= line> /dev/null; diff --git a/isis/src/base/apps/fillgap/tsts/vertcubic/Makefile b/isis/src/base/apps/fillgap/tsts/vertcubic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e6f3b11496e8c69d557f9ca529b4ed06f6a14e72 --- /dev/null +++ b/isis/src/base/apps/fillgap/tsts/vertcubic/Makefile @@ -0,0 +1,8 @@ +APPNAME = fillgap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/peaks.cub \ + to= $(OUTPUT)/filled.cub \ + direction=line > /dev/null; diff --git a/isis/src/base/apps/fillgap/tsts/vertlinear/Makefile b/isis/src/base/apps/fillgap/tsts/vertlinear/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d6682bc474f136ff083d6b1d6e98840db4daf8c --- /dev/null +++ b/isis/src/base/apps/fillgap/tsts/vertlinear/Makefile @@ -0,0 +1,9 @@ +APPNAME = fillgap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/peaks.cub \ + to= $(OUTPUT)/filled.cub \ + interp=linear \ + direction=line > /dev/null; diff --git a/isis/src/base/apps/findgaps/Makefile b/isis/src/base/apps/findgaps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/findgaps/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/findgaps/assets/images/I11971007RDR_lev1.jpg b/isis/src/base/apps/findgaps/assets/images/I11971007RDR_lev1.jpg new file mode 100755 index 0000000000000000000000000000000000000000..fe91b4b03a5c00eba3cedab82b21f5c12935f8f6 Binary files /dev/null and b/isis/src/base/apps/findgaps/assets/images/I11971007RDR_lev1.jpg differ diff --git a/isis/src/base/apps/findgaps/findgaps.cpp b/isis/src/base/apps/findgaps/findgaps.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2c9ac5aa5d5cf3765ee6534149eea13de5b9ea72 --- /dev/null +++ b/isis/src/base/apps/findgaps/findgaps.cpp @@ -0,0 +1,92 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iString.h" + +#include "Statistics.h" +#include "MultivariateStatistics.h" + +using namespace std; +using namespace Isis; + +void FindGaps ( Buffer &in ); + +// The Correlation Tollerance variable +double corTol; +// Vector to hold the previous line +std::vector previousLine; +// The PvlGroup for storing results +PvlGroup pvl("Gap"); +Pvl toDisplay; +bool inGap = false; +int lineNum; // Used when gaps go to the end of the band + + +void IsisMain() { + // Processing by line + ProcessByLine p; + + // Setup the input cube and lastLine array + Cube *icube = p.SetInputCube( "FROM" ); + previousLine.resize(icube->Samples()); + lineNum = icube->Lines(); + + // Gets the Correlation Tollerance + UserInterface &ui = Application::GetUserInterface(); + corTol = ui.GetDouble("CORTOL"); + + // Starts the find gaps process + p.StartProcess( FindGaps ); + //In case the last gap runs to the end of the cube + if ( inGap ) { + pvl.AddKeyword( PvlKeyword( "ToEndOfBand", lineNum ) ); + } + toDisplay.Write( ui.GetFilename("TO") ); + toDisplay.Clear(); + inGap = false; + p.EndProcess(); +} + +/** + * Processes the current line with the previous, and acts + * accordingly, posting bad results in Log. + * @param in + */ +void FindGaps ( Buffer &in ) { + // Copys line 1 into previousLine since it is the top of the Band + if ( in.Line() == 1 ) { + for (int i=0; i + + + Finds the gaps in a given Cube. + + + + This program will find any gaps in a Cube and display their beggining and final lines as well as their band. + These values will be placed into the file defined by the TO parameter. + + + + Utility + + + + + Original version + + + Removed references to CubeInfo + + + + + + + cube + input + + Input cube file. + + + Input cube file to be checked for line gaps. + + + *.cub + + + + filename + output + + The text to append Gap info + + + The text file in which all of the information about the gaps found in + the input cube is written. + + + *.txt *.prt *.pvl + + + + + + + double + 0.7 + Correlation Tolerance + + This parameter specifies the tolerance of the correlation coefficient + when running FindGaps. Default = 0.7 + + + + + + + + Finds Image Gaps + + This example shows how findgaps works on the cube + I11971007RDR_lev1.cub. + + + + FROM=I11971007RDR_lev1.cub + TO=results.txt + + Searches I11971007RDR_lev1.cub for gaps based on the default + Correlation Tolerance of CORTOL=0.7 + + + + + + The image + + This is the image I11971007RDR_lev1.cub within which + line gaps are being found. + + + FROM + + + + + + results.txt + +

    In the case of no gaps, the TO output file + parameter will be empty.

    +

    When there are gaps in the cube image, then there + is a pvl display in the TO file. In this example, + that file is results.txt as shown here. This group + displays the band these gaps were found in, the starting + line for the particular gap, the correlation coefficient + that initiated the finding of that gap, as well as the + last line of the given gap. +

    +
    +
    +
    + +
    +
    + +
    diff --git a/isis/src/base/apps/findgaps/tsts/Makefile b/isis/src/base/apps/findgaps/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/findgaps/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/findgaps/tsts/endOfBandGap/Makefile b/isis/src/base/apps/findgaps/tsts/endOfBandGap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..eeb4464c1f85df3d478d7c94ba6c08e12be2d9ae --- /dev/null +++ b/isis/src/base/apps/findgaps/tsts/endOfBandGap/Makefile @@ -0,0 +1,7 @@ +APPNAME = findgaps + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/peaksGap.cub \ + to=$(OUTPUT)/results.txt > /dev/null; diff --git a/isis/src/base/apps/findgaps/tsts/realData/Makefile b/isis/src/base/apps/findgaps/tsts/realData/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ca23cb8b74d38f92f595b65e8bc0d2b0b8b12f04 --- /dev/null +++ b/isis/src/base/apps/findgaps/tsts/realData/Makefile @@ -0,0 +1,7 @@ +APPNAME = findgaps + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/I11971007RDR_lev1.cub \ + to=$(OUTPUT)/results.pvl > /dev/null; diff --git a/isis/src/base/apps/findimageoverlaps/Makefile b/isis/src/base/apps/findimageoverlaps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/findimageoverlaps/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/findimageoverlaps/findimageoverlaps.cpp b/isis/src/base/apps/findimageoverlaps/findimageoverlaps.cpp new file mode 100644 index 0000000000000000000000000000000000000000..88dce5735f13ae318902bace7120fb4ab9834183 --- /dev/null +++ b/isis/src/base/apps/findimageoverlaps/findimageoverlaps.cpp @@ -0,0 +1,88 @@ +#include "Isis.h" +#include "SerialNumberList.h" +#include "ImageOverlapSet.h" +#include "FileList.h" +#include "SerialNumber.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + SerialNumberList serialNumbers(true); + + FileList images(ui.GetFilename("FROMLIST")); + // list of sns/filenames sorted by serial number + vector< pair > sortedList; + + // We want to sort the input data by serial number so that the same + // results are produced every time this program is run with the same + // images. This is a modified insertion sort. + for(unsigned int image = 0; image < images.size(); image++) { + unsigned int insertPos = 0; + string sn = SerialNumber::Compose(images[image]); + + for(insertPos = 0; insertPos < sortedList.size(); insertPos++) { + if(sn.compare(sortedList[insertPos].first) < 0) break; + } + + pair newPair = pair(sn, images[image]); + sortedList.insert(sortedList.begin() + insertPos, newPair); + } + + // Add the serial numbers in sorted order now + for(unsigned int i = 0; i < sortedList.size(); i++) { + serialNumbers.Add(sortedList[i].second); + } + + // Now we want the ImageOverlapSet to calculate our overlaps + ImageOverlapSet overlaps(true); + + // The following line was replaced to allow checking of the overlap size + //overlaps.FindImageOverlaps(serialNumbers, Filename(ui.GetFilename("TO")).Expanded()); + + overlaps.FindImageOverlaps(serialNumbers); + + // Error if the overlaps are empty + if( overlaps.Size() == serialNumbers.Size() ) { + std::cerr << "No Overlaps Calculated" << std::endl; + string msg = "No overlaps were calculated from the input cubes in the [FROMLIST]."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + overlaps.WriteImageOverlaps(Filename(ui.GetFilename("TO")).Expanded()); + + // This will only occur when "CONTINUE" was true, so we can assume "ERRORS" was + // an entered parameter. + if(overlaps.Errors().size() != 0 && ui.WasEntered("ERRORS")) { + Pvl outFile; + + bool filenamesOnly = !ui.GetBoolean("DETAILED"); + + vector errorList = overlaps.Errors(); + + for(unsigned int err = 0; err < errorList.size(); err++) { + if(!filenamesOnly) { + outFile += errorList[err]; + } + else if(errorList[err].HasKeyword("Filenames")) { + PvlGroup origError = errorList[err]; + PvlGroup err("ImageOverlapError"); + + for(int keyword = 0; keyword < origError.Keywords(); keyword++) { + if(origError[keyword].Name() == "Filenames") { + err += origError[keyword]; + } + } + + outFile += err; + } + } + + outFile.Write(Filename(ui.GetFilename("ERRORS")).Expanded()); + } + + PvlGroup results("Results"); + results += PvlKeyword("ErrorCount", (BigInt)overlaps.Errors().size()); + Application::Log(results); +} diff --git a/isis/src/base/apps/findimageoverlaps/findimageoverlaps.xml b/isis/src/base/apps/findimageoverlaps/findimageoverlaps.xml new file mode 100644 index 0000000000000000000000000000000000000000..bd4882c7e64808fab97d846e0ec727667a310230 --- /dev/null +++ b/isis/src/base/apps/findimageoverlaps/findimageoverlaps.xml @@ -0,0 +1,98 @@ + + + + + Writes the image overlaps in a control net to a file + + + + This program writes the image overlaps, in a given control net, to a file for use + by other control net programs. By using this program, the image overlaps in a control + net could be calculated once (this is a slow process) for many program runs, + speeding up the process. + + + + Control Networks + + + + + Original version + + + Added the "DETAILED" and "ERRORS" parameters. + + + Added the number of errors to the results output + + + Uses different method call to ImageOverlapSet for optimization + + + The input list will be internally sorted by serial number so that + one list of input images will always produce the same results regardless + of the sort order. + + + Added an error when no new overlaps are calculated. (i.e. All overlaps + contain only a single Serial Number) + + + + + + + filename + input + + List of Input cubes in the control network + + + Use this parameter to specify the cube filenames which are associated with + the control network. + + + *.lis + + + + + filename + output + + Output overlap list + + + This file will contain image overlap polygons for the control network + + + + + filename + output + No Error Output + + Errors generated when making the overlap list + + + This file will contain the errors that occurred while calculating the image overlaps. + + + + + + + boolean + + Output detailed error information + + + This will cause the error file to contain more detailed information about the errors. If this + is true, only filenames will be reported in the errors file. + + false + + + + diff --git a/isis/src/base/apps/findimageoverlaps/tsts/Makefile b/isis/src/base/apps/findimageoverlaps/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/findimageoverlaps/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/findimageoverlaps/tsts/default/Makefile b/isis/src/base/apps/findimageoverlaps/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..11d23c5302b7ca60e6a059ebca8dd29e8cc347f7 --- /dev/null +++ b/isis/src/base/apps/findimageoverlaps/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = findimageoverlaps + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/cubes.lis; + $(APPNAME) FROM=$(OUTPUT)/cubes.lis TO=$(OUTPUT)/overlaps.txt > /dev/null; + $(RM) $(OUTPUT)/cubes.lis; diff --git a/isis/src/base/apps/findrx/Makefile b/isis/src/base/apps/findrx/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/findrx/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/findrx/findrx.cpp b/isis/src/base/apps/findrx/findrx.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b4f5a4bb584bcf0a876752240723a6bbb1202ff --- /dev/null +++ b/isis/src/base/apps/findrx/findrx.cpp @@ -0,0 +1,112 @@ +#include "Isis.h" +#include "PvlGroup.h" +#include "UserInterface.h" +#include "Cube.h" +#include "Chip.h" +#include "Progress.h" +#include "iException.h" +#include "AutoReg.h" +#include "AutoRegFactory.h" +#include "Brick.h" + +using namespace std; +using namespace Isis; + +void IsisMain () +{ + // Import cube data & PVL information + Cube cube; + UserInterface &ui = Application::GetUserInterface(); + cube.Open(ui.GetFilename("FROM"),"rw"); + Pvl* regdef; + // If regdef was supplied by the user, use it. else, use the template. + if (ui.WasEntered("REGDEF")) { + regdef = new Pvl(ui.GetFilename("REGDEF")); + } + else { + regdef = new Pvl("$base/templates/autoreg/findrx.def"); + } + PvlGroup &reseaus = cube.Label()->FindGroup("Reseaus",Pvl::Traverse); + + // If the Keyword sizes don't match up, throw errors. + int nres = reseaus["Line"].Size(); + if (nres != reseaus["Sample"].Size()) { + string msg = "Sample size incorrect [Sample size " + + iString(reseaus["Sample"].Size()) + " != " + " Line size " + + iString(reseaus["Line"].Size()) + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg, _FILEINFO_); + } + if (nres != reseaus["Type"].Size()) { + string msg = "Type size incorrect [Type size " + + iString(reseaus["Type"].Size()) + " != " + " Line size " + + iString(reseaus["Line"].Size()) + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg, _FILEINFO_); + } + if (nres != reseaus["Valid"].Size()) { + string msg = "Valid size incorrect [Valid size " + + iString(reseaus["Valid"].Size()) + " != " + " Line size " + + iString(reseaus["Line"].Size()) + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg, _FILEINFO_); + } + + // Auto Registration + AutoReg *ar = AutoRegFactory::Create(*regdef); + Cube pattern; + pattern.Open(reseaus["Template"], "r"); + ar->PatternChip()->TackCube(5.0,5.0); + + // Display the progress...10% 20% etc. + Progress prog; + prog.SetMaximumSteps(nres); + prog.CheckStatus(); + + + //If the mark reseaus option is set...then create a brick. + Brick* white = NULL; + if (ui.GetBoolean("MARK") == true) { + white = new Brick(1,1,1, Isis::UnsignedByte); + (*white)[0] = Isis::Hrs; + } + + double percent = ar->PatternValidPercent(); + + // And the loop... + for (int res=0; resSearchChip()->TackCube(reseaus["Sample"][res], reseaus["Line"][res]); + ar->SearchChip()->Load(cube); + ar->PatternChip()->Load(pattern, 0, 1.0, res+1); + int type = iString(reseaus["Type"][res]); + // If the reseaus is in the center (type 5) use full percent value + if (type== 5) ar->SetPatternValidPercent(percent); + // else if the reseaus is on an edge (type 2,4,6, or 8) use half percent value + else if (type%2 == 0) ar->SetPatternValidPercent(percent/2.0); + // else the reseaus on a corner (type 1,3,7, or 9) use a quarter percent value + else ar->SetPatternValidPercent(percent/4.0); + if (ar->Register()==AutoReg::Success) { + reseaus["Sample"][res] = ar->CubeSample(); + reseaus["Line"][res] = ar->CubeLine(); + reseaus["Valid"][res] = 1; + } + else { + reseaus["Valid"][res] = 0; + } + + // And if the reseaus are to be marked...mark em + if (white != NULL) { + double line = reseaus["Line"][res]; + double sample = reseaus["Sample"][res]; + white->SetBasePosition(int(sample), int(line), 1); + cube.Write(*white); + } + prog.CheckStatus(); + + } + + // Change status to "Refined", corrected! + reseaus["Status"] = "Refined"; + + pattern.Close(); + cube.Close(); +} diff --git a/isis/src/base/apps/findrx/findrx.xml b/isis/src/base/apps/findrx/findrx.xml new file mode 100644 index 0000000000000000000000000000000000000000..0759c8d3698206fcf5e859e62268f4e4a6db6b7f --- /dev/null +++ b/isis/src/base/apps/findrx/findrx.xml @@ -0,0 +1,92 @@ + + + + + Find and refine reseau points in a cube + + + + This program will read in a cube and refine the positions of the Reseau points. + It will also modify the cube's label so the Reseaus are matched with sub-pixel accuracy. + The new reseau coordinate set is then set to "Refined", and the validity of the pixels that + have nothing wrong will be set to 1. + + + + Viking + Voyager + Mariner + + + + + Original version + + + Moved from utilities into mission categories + + + Modified the registration algorithm on edge and corner reseaus. + + + Changed call to Chip::Load because a scale factor was added to the + method. + + + Documentation fixes + + + Updated to properly check AutoReg::Register()'s return status + + + + + + + cube + input + + Input file to be read + + + The cube to be used to extract Reseau points from. + + + *.cub + + + + + filename + input + + The Auto Registration template + + + The template to use with the AutoReg class. Default will be maximum correlation function + with a tolerance of 0.7, a search cube of 21x21 pixels, and a pattern cube of 9x9 pixels. + + + *.def + + $base/templates/AutoReg/findrx.def + + + + + + boolean + + Mark the reseaus with a centered white pixel? + + + This option will enable marking onto the cube file, writing a tiny white pixel in the center + of the refined reseau. This is mostly used for testing purposes, but it can also be + used for verification. + + false + + + + + diff --git a/isis/src/base/apps/findrx/tsts/Makefile b/isis/src/base/apps/findrx/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/findrx/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/findrx/tsts/default/Makefile b/isis/src/base/apps/findrx/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..256088041acf4d03b2823814b90338655de2b10a --- /dev/null +++ b/isis/src/base/apps/findrx/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = findrx + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/f387a06.cub $(OUTPUT)/f387a06.cub; + $(APPNAME) from=$(OUTPUT)/f387a06.cub > /dev/null; + catlab from=$(OUTPUT)/f387a06.cub > $(OUTPUT)/findrxTruth.pvl 2>&1; diff --git a/isis/src/base/apps/fits2isis/Makefile b/isis/src/base/apps/fits2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/fits2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/fits2isis/assets/images/gui.jpg b/isis/src/base/apps/fits2isis/assets/images/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5dfdef60cee0e3c4b94b76f274e67738c2bbbc4a Binary files /dev/null and b/isis/src/base/apps/fits2isis/assets/images/gui.jpg differ diff --git a/isis/src/base/apps/fits2isis/assets/thumbs/gui.jpg b/isis/src/base/apps/fits2isis/assets/thumbs/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bfc2f6b304ce49019a17c30f2f933496477f6f63 Binary files /dev/null and b/isis/src/base/apps/fits2isis/assets/thumbs/gui.jpg differ diff --git a/isis/src/base/apps/fits2isis/fits2isis.cpp b/isis/src/base/apps/fits2isis/fits2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87b1d3eab65b80fe9b2ba1366edce5099a716e29 --- /dev/null +++ b/isis/src/base/apps/fits2isis/fits2isis.cpp @@ -0,0 +1,198 @@ +#include "Isis.h" + +#include "Cube.h" +#include "iException.h" +#include "iString.h" +#include "OriginalLabel.h" +#include "ProcessImport.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "PvlKeyword.h" +#include "UserInterface.h" + +#include +#include +#include + +using namespace std; +using namespace Isis; + +void IsisMain() { + + UserInterface &ui = Application::GetUserInterface(); + + string from = ui.GetFilename("FROM"); + + // Setup to read headers/labels + ifstream input; + input.open(from.c_str(), ios::in | ios::binary); + + // Check stream open status + if (!input.is_open()) { + string msg = "Cannot open input file [" + from + "]"; + throw Isis::iException::Message(Isis::iException::Io, msg, _FILEINFO_); + } + + char reading[81]; + iString line = ""; + unsigned int place = 0; + PvlGroup labels("OriginalLabels"); + + // Load first line + input.seekg(0); + input.read(reading, 80); + reading[80] = '\0'; + line = reading; + place += 80; + + // Read in and place in PvlKeywords and a PvlGroup + while (line.substr(0,3) != "END") { + // Check for blank lines + if (line.substr(0,1) != " " && line.substr(0,1) != "/") { + // Name of keyword + PvlKeyword label(line.Token(" =")); + // Remove up to beginning of data + line.TrimHead(" ='"); + line.TrimTail(" "); + if (label.Name() == "COMMENT" || label.Name() == "HISTORY") { + label += line; + } + else { + // Access the data without the comment if there is one + iString value = line.Token("/"); + // Clear to end of data, including single quotes + value.TrimTail(" '"); + label += value; + line.TrimHead(" "); + // If the remaining line string has anything, it is comments. + if (line.size() > 0) { + label.AddComment(line); + // A possible format for units, other possiblites exist. + if (line != line.Token("[")) { + label.SetUnits(line.Token("[").Token("]")); + } + } + } + labels += label; + } + // Load next line + input.seekg(place); + input.read(reading, 80); + reading[80] = '\0'; + place += 80; + line = reading; + } + + // Done with stream + input.close(); + + // Its possible they could have this instead of T, in which case we won't even try + if (labels["SIMPLE"][0] == "F") { + string msg = "The file [" + ui.GetFilename("FROM") + "] does not conform to the FITS standards"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + ProcessImport pfits; + + pfits.SetInputFile(ui.GetFilename("FROM")); + + // Header size will be a multiple of 2880 + int multiple = (int)((place + 2881)/2880); + pfits.SetFileHeaderBytes(multiple * 2880); + pfits.SaveFileHeader(); + + // Find pixel type, there are several unsupported possiblites + Isis::PixelType type; + string msg = ""; + switch (labels["BITPIX"][0].ToInteger()) { + case 8: + type = Isis::UnsignedByte; + break; + case 16: + type = Isis::SignedWord; + break; + case 32: + msg = "Signed 32 bit integer (int) pixel type is not supported at this time"; + throw iException::Message(iException::User, msg, _FILEINFO_); + break; + case 64: + msg = "Signed 64 bit integer (long) pixel type is not supported at this time"; + throw iException::Message(iException::User, msg, _FILEINFO_); + break; + case -32: + type = Isis::Real; + break; + case -64: + msg = "64 bit floating point (double) pixel type is not supported at this time"; + throw iException::Message(iException::User, msg, _FILEINFO_); + break; + default: + msg = "Unknown pixel type [" + labels["BITPIX"][0] + "] cannot be imported"; + throw iException::Message(iException::User, msg, _FILEINFO_); + break; + } + + pfits.SetPixelType(type); + + // It is possible to have a NAXIS value of 0 meaning no data, the file could include + // xtensions with data, however, those aren't supported as of Oct '09 + if (labels["NAXIS"][0].ToInteger() == 2) { + pfits.SetDimensions(labels["NAXIS1"][0], labels["NAXIS2"][0], 1); + } + else if (labels["NAXIS"][0].ToInteger() == 3) { + pfits.SetDimensions(labels["NAXIS1"][0], labels["NAXIS2"][0], labels["NAXIS3"][0]); + } + else { + string msg = "NAXIS count of [" + labels["NAXIS"][0] + "] is not supported at this time"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + // Base and multiplier + if (labels.HasKeyword("BZERO")) { + pfits.SetBase(labels["BZERO"][0]); + } + if (labels.HasKeyword("BSCALE")) { + pfits.SetMultiplier(labels["BSCALE"][0]); + } + + // Byte order + pfits.SetByteOrder(Isis::Msb); + + // Limited section of standardized keywords that could exist + bool instGrp = false; + PvlGroup inst("Instrument"); + if (labels.HasKeyword("DATE-OBS")) { + instGrp = true; + inst += PvlKeyword("StartTime", labels["DATE-OBS"][0]); + } + if (labels.HasKeyword("OBJECT")) { + instGrp = true; + inst += PvlKeyword("Target", labels["OBJECT"][0]); + } + if (labels.HasKeyword("INSTRUME")) { + instGrp = true; + inst += PvlKeyword("InstrumentId", labels["INSTRUME"][0]); + } + if (labels.HasKeyword("OBSERVER")) { + instGrp = true; + inst += PvlKeyword("SpacecraftName", labels["OBSERVER"][0]); + } + + Cube * output = pfits.SetOutputCube("TO"); + + // Add instrument group if any relevant data exists + Pvl * lbls = output->Label(); + if (instGrp) { + lbls->FindObject("IsisCube") += inst; + } + + // Save original labels + Pvl pvl; + pvl += labels; + OriginalLabel originals(pvl); + output->Write(originals); + + // Process... + pfits.StartProcess(); + pfits.EndProcess(); +} diff --git a/isis/src/base/apps/fits2isis/fits2isis.xml b/isis/src/base/apps/fits2isis/fits2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..a3528fbd136dfae3e5f67ffd88e46ca319659395 --- /dev/null +++ b/isis/src/base/apps/fits2isis/fits2isis.xml @@ -0,0 +1,99 @@ + + + + + + Import fits files into Isis format + + + This program will import fits (Flexible Image Transport System) files into + Isis format. Only simple fits files are accepted. Extensions are not + support and files with no initial data, NAXIS = 0 , implying extensions with + data, are not supported either. Some common header data is transfered to + Isis labels. Primary image data is transfered completely and reliably. + + + + + Original version + + + + + + isis2fits + + + + + Import and Export + + + + + + filename + input + + A fits file to be converted to an isis cube + + + Use this parameter to select the filename of a fits file to be + converted to a cube. Currently extensions and files with no initial + data, NAXIS = 0, are not supported. + + + *.fits + + + + + cube + output + + Output file converted to cube format + + + The cube output file, containing image data and applicable headers. + + + *.cub + + + + + + + + + Usage of this import application + + + This example shows how to import a fits file to the isis cube format. + + + + from=fitsFile.fits to=imported.cub + + + The command line arguments to import a file to cube format. + + + + + + + The application's gui + + + The gui for the application, with parameters set to import a fits + file to a cube. + + + + + + + + + diff --git a/isis/src/base/apps/fits2isis/tsts/Makefile b/isis/src/base/apps/fits2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/fits2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/fits2isis/tsts/default/Makefile b/isis/src/base/apps/fits2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ff2bf1cd351ea223b647c5744531d0e48f9bdb3f --- /dev/null +++ b/isis/src/base/apps/fits2isis/tsts/default/Makefile @@ -0,0 +1,13 @@ +APPNAME = fits2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/WFPC2u5780205r_c0fx.fits \ + to=$(OUTPUT)/fitsTruth.cub \ + > /dev/null; + raw2isis from=$(INPUT)/WFPC2u5780205r_c0fx.fits \ + to=$(OUTPUT)/rawTruth.cub \ + SAMPLES=200 LINES=200 BANDS=4 SKIP=23040 \ + BITTYPE=REAL BYTEORDER=MSB \ + > /dev/null; diff --git a/isis/src/base/apps/flip/Makefile b/isis/src/base/apps/flip/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/flip/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/flip/assets/image/peaks.jpg b/isis/src/base/apps/flip/assets/image/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..0cce398dd933f62a1b4b8699083e8e65e30a8950 Binary files /dev/null and b/isis/src/base/apps/flip/assets/image/peaks.jpg differ diff --git a/isis/src/base/apps/flip/assets/image/peaksFlip.jpg b/isis/src/base/apps/flip/assets/image/peaksFlip.jpg new file mode 100755 index 0000000000000000000000000000000000000000..ede9a60984f722e84f5c8ece06abc3a8aac6bd3a Binary files /dev/null and b/isis/src/base/apps/flip/assets/image/peaksFlip.jpg differ diff --git a/isis/src/base/apps/flip/assets/thumb/peaks.jpg b/isis/src/base/apps/flip/assets/thumb/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..61fbd0ece55529a0dd6986d41700a0e2db24c53f Binary files /dev/null and b/isis/src/base/apps/flip/assets/thumb/peaks.jpg differ diff --git a/isis/src/base/apps/flip/assets/thumb/peaksFlip.jpg b/isis/src/base/apps/flip/assets/thumb/peaksFlip.jpg new file mode 100755 index 0000000000000000000000000000000000000000..96e66c7f179b8b135c82d4d80fd1c62ed356c967 Binary files /dev/null and b/isis/src/base/apps/flip/assets/thumb/peaksFlip.jpg differ diff --git a/isis/src/base/apps/flip/flip.cpp b/isis/src/base/apps/flip/flip.cpp new file mode 100644 index 0000000000000000000000000000000000000000..edcf61f7701438ca208029e691d4b7fd67bb50d0 --- /dev/null +++ b/isis/src/base/apps/flip/flip.cpp @@ -0,0 +1,32 @@ +#include "Isis.h" +#include "ProcessBySample.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void flip (Buffer &in, Buffer &out); + +void IsisMain() { + // We will be processing by line + ProcessBySample p; + + // Setup the input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + + // Start the processing + p.StartProcess(flip); + p.EndProcess(); +} + +// Line processing routine +void flip (Buffer &in, Buffer &out) { + // Loop and flip pixels in the line. + int index = in.size() - 1; + for (int i=0; i + + + Flip a cube from top-to-bottom + + + + This program will flip a cube from top-to-bottom. By flipping the cube + the geometric integrity of the cube is destroyed. Therefore, any + geometric, mapping, or instrument related labels will be marked as + invalid. + + + + Geometry + + + + + rotate + mirror + + + + + + Original version + + + Added example + + + + + + + cube + input + + Input file to be flipped + + + The cube to be flipped. All bands will be flipped from + top-to-bottom. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the flipped data. + + + *.cub + + + + + + + + Io flipped + + This example shows the simple but indispensable flip application. There are no defaults. + + + f=../IN/peaks.cub t=OUT/peaksFlip.cub + + + Just flip an image. + + + + + + Input image for flip + This is the 800 by 800 input image for the flip example. + + + FROM + + + + + + Output image for flip + This is the 800 by 800 output image that results. + + + TO + + + + + + + diff --git a/isis/src/base/apps/flip/tsts/Makefile b/isis/src/base/apps/flip/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/flip/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/flip/tsts/case01/Makefile b/isis/src/base/apps/flip/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8135ce9fe512252293f8cc40e175c68bf5c515dc --- /dev/null +++ b/isis/src/base/apps/flip/tsts/case01/Makefile @@ -0,0 +1,7 @@ +APPNAME = flip + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/flipTruth.cub > /dev/null; diff --git a/isis/src/base/apps/footprintinit/Makefile b/isis/src/base/apps/footprintinit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/footprintinit/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/footprintinit/footprintinit.cpp b/isis/src/base/apps/footprintinit/footprintinit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..76307f2ccb9f3b47f6a4ddff8d39fbea56527be2 --- /dev/null +++ b/isis/src/base/apps/footprintinit/footprintinit.cpp @@ -0,0 +1,138 @@ +#include "Isis.h" + +#include "iException.h" +#include "ImagePolygon.h" +#include "PolygonTools.h" +#include "Process.h" +#include "Progress.h" +#include "PvlGroup.h" +#include "SerialNumber.h" + + +using namespace std; +using namespace Isis; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + Cube cube; + cube.Open( ui.GetFilename("FROM"), "rw" ); + + // Make sure cube has been run through spiceinit + try { + cube.Camera(); + } catch ( iException &e ) { + string msg = "Spiceinit must be run before initializing the polygon"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + Progress prog; + prog.SetMaximumSteps(1); + prog.CheckStatus (); + + std::string sn = SerialNumber::Compose(cube); + + ImagePolygon poly; + if( ui.WasEntered("MAXEMISSION") ) { + poly.Emission( ui.GetDouble("MAXEMISSION") ); + } + if( ui.WasEntered("MAXINCIDENCE") ) { + poly.Incidence( ui.GetDouble("MAXINCIDENCE") ); + } + if( ui.GetString("LIMBTEST") == "ELLIPSOID" ) { + poly.EllipsoidLimb( true ); + } + + // Reduce the increment size to find a valid polygon + int sinc = ui.GetInteger("SINC"); + int linc = ui.GetInteger("LINC"); + bool precision = ui.GetBoolean("INCREASEPRECISION"); + while( true ) { + try { + poly.Create(cube, sinc, linc); + break; + } catch( iException &e ) { + if( precision && sinc > 1 && linc > 1 ) { + sinc = sinc * 2 / 3; + linc = linc * 2 / 3; + e.Clear(); + } + else { + e.Report(); + return; // Prevents infinite loops caused by **SPICE ERROR** + } + } + } + + + if( ui.GetBoolean("TESTXY") ) { + Pvl cubeLab( ui.GetFilename("FROM") ); + PvlGroup inst = cubeLab.FindGroup("Instrument", Pvl::Traverse); + string target = inst["TargetName"]; + PvlGroup radii = Projection::TargetRadii(target); + + Pvl map( ui.GetFilename("MAP") ); + PvlGroup & mapping = map.FindGroup("MAPPING"); + + if( !mapping.HasKeyword("TargetName") ) + mapping += Isis::PvlKeyword("TargetName", target); + if( !mapping.HasKeyword("EquatorialRadius") ) + mapping += Isis::PvlKeyword("EquatorialRadius",(string)radii["EquatorialRadius"]); + if( !mapping.HasKeyword("PolarRadius") ) + mapping += Isis::PvlKeyword("PolarRadius",(string)radii["PolarRadius"]); + if( !mapping.HasKeyword("LatitudeType") ) + mapping += Isis::PvlKeyword("LatitudeType","Planetocentric"); + if( !mapping.HasKeyword("LongitudeDirection") ) + mapping += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + if( !mapping.HasKeyword("LongitudeDomain") ) + mapping += Isis::PvlKeyword("LongitudeDomain",360); + if( !mapping.HasKeyword("CenterLatitude") ) + mapping += Isis::PvlKeyword("CenterLatitude",0); + if( !mapping.HasKeyword("CenterLongitude") ) + mapping += Isis::PvlKeyword("CenterLongitude",0); + + while( true ) { + try { + Projection *proj= ProjectionFactory::Create(map, true); + geos::geom::MultiPolygon *xyPoly = PolygonTools::LatLonToXY(*poly.Polys(), proj); + + delete proj; + proj = NULL; + delete xyPoly; + xyPoly = NULL; + + break; + } catch( iException &e ) { + if( precision && sinc > 1 && linc > 1 ) { + sinc = sinc * 2 / 3; + linc = linc * 2 / 3; + poly.Create(cube, sinc, linc); + e.Clear(); + } + else { + e.Report(); + return; // Prevents infinite loops caused by **SPICE ERROR** + } + } + } + + } + + + + cube.BlobDelete("Polygon",sn); + cube.Write(poly); + + if( precision ) { + PvlGroup results("Results"); + results.AddKeyword( PvlKeyword( "SINC", sinc ) ); + results.AddKeyword( PvlKeyword( "LINC", linc ) ); + Application::Log( results ); + } + + Process p; + p.SetInputCube("FROM"); + p.WriteHistory(cube); + + cube.Close(); + prog.CheckStatus (); +} diff --git a/isis/src/base/apps/footprintinit/footprintinit.xml b/isis/src/base/apps/footprintinit/footprintinit.xml new file mode 100644 index 0000000000000000000000000000000000000000..e5c69524434444a52c97452e82ab01464a1774a5 --- /dev/null +++ b/isis/src/base/apps/footprintinit/footprintinit.xml @@ -0,0 +1,277 @@ + + + + This program stores a polygon representing the Lat/Lon footprint of the + image. + + + + This program creates a latitude/longitude geometric polygon that determines the footprint of the image. + This footprint is used in other programs such as autoseed. + + + + Control Networks + + + + + Original version + + + Changed input from a list of cube files to a single cube and added appTest. + + + Fixed application test + + + Added call to propagate and modify the history blob + + + Added error check to insure spiceinit has been run. + + + Moved from Geometry category to Control Network category + + + Moved Control Network category to Control Networks Category (Control Network category is invalid) and updated program description. + + + Changed name from polyinit to footprint init + + + Updated to work with Geos3.0.0 + + + Deletes old footprint (generated off cubes serial number) if its found. + New name for blob is just Footprint. + + + PIXINC parameter was removed, ImagePolygon now uses a new method of + finding footprints + + + PIXINC re-implemented. This functionality is crucial. Existing polygons will no + longer be deleted if this program fails. + + + Changed default PIXINC to 100, added test cases. + + + Added the cross test. + + + Added EMISSION and INCIDENCE + + + Changed param EMISSION to MAXEMISSION, and INCIDENCE to MAXINCIDENCE. + + + Added LIMBTEST parameter, and fixed multiple tests, including multiple + PIXINC coverage. + + + Replaced PIXINC with SAMPINC and LINEINC. + + + Changed the maximum value of MAXEMISSION and MAXINCIDENCE to 180. + Added TESTXY and an app test for it. + + + Changed SAMPINC and LINEINC to SINC and LINC for consistancy with + camstats. + + + Added the INCREASEPRECISION parameter. + + + Added a results group when using INCREASEPRECISION which privides the + final SINC and LINC used for the footprint. + + + Prevented an infinite loop caused by Naif error handling. + + + + + + + + + cube + input + + Input cube + + + The cube to initialize polygons. + + + *.cub + + + + + + + + + boolean + FALSE + Allow automatic adjustments to fix invalid polygons + + Enabeling this option will allow the automatic reduction of the SINC + and LINC parameters whenever their current values result in an + invalid polygon. In addition, a results group will be created with + the keywords SINC/LINC which reveal what SINC/LINC values were + actually used for the creation of the footprint. + + NOTE: This parameter can result in a drastic increase in running time + as well as a change to user input values. + + + + + integer + 1 + 100 + + The accuracy of the footprint in the sample direction (larger is less + accurate) + + + This is approximately how many samples in the input image + to skip for every point stored in the footprint. + + + + + integer + 1 + 100 + + The accuracy of the footprint in the line direction (larger is less + accurate) + + + This is approximately how many lines in the input image + to skip for every point stored in the footprint. + + + + + double + 0.0 + 180.0 + Ignore Emission + + The maximum valid emission angle + + + When this value is provided, footprintinit will only consider points + with an emission angle less than or equal to the provided value. + + There should never be an emission angle above 90. However, + planet features can cause abnormalities. + + + + + double + 0.0 + 180.0 + Ignore Incidence + + The maximum valid incidence angle + + + When this value is provided, footprintinit will only consider points + with an incidence angle less than or equal to the provided value. + + There should never be an incidence angle above 90. However, + planet features can cause abnormalities. + + + + + + + + + string + ELLIPSOID + Defines how limb images are to be handled + + This parameter is used to specify how limb images are to be handled. + + + + + + + + + + + + + boolean + FALSE + Tests the footprint's XY projection + + Tests the ability to project the footprint from lat/lon to x/y + coordinates. If the test fails, an error will be thrown, and the + lat/lon footprint will not be written to the input cube. + + + MAP + + + + filename + input + + File containing mapping parameters + + $base/templates/maps + $base/templates/maps/sinusoidal.map + + A file containing the desired XY mapping parameters. This + file can be a simple label file, hand produced or created via + the "maptemplate" program. It can also be an existing cube label + which contains a Mapping group. In the later case the input cube + will be transformed into the same map projection, resolution, etc. + + + + PrintMap + View MapFile + + This helper button will cat out the mapping group of the given mapfile to the session log + of the application + + $ISIS3DATA/base/icons/labels.png + + + + *.map *.cub + + + + + + + + diff --git a/isis/src/base/apps/footprintinit/tsts/Makefile b/isis/src/base/apps/footprintinit/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/footprintinit/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/footprintinit/tsts/boundary/Makefile b/isis/src/base/apps/footprintinit/tsts/boundary/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ad24ced08d9d99c00ac3eddcd2a5b6d3ab43b996 --- /dev/null +++ b/isis/src/base/apps/footprintinit/tsts/boundary/Makefile @@ -0,0 +1,15 @@ +APPNAME = footprintinit + +include $(ISISROOT)/make/isismake.tsts + +# cp so I don't destroy the input cube +commands: + $(CP) $(INPUT)/EN0108821505M.cal.cub $(OUTPUT)/EN0108821505M.cal.cub; + $(APPNAME) from=$(OUTPUT)/EN0108821505M.cal.cub \ + sinc=3000 linc=3000 > /dev/null; + $$ISISROOT/bin/blobdump \ + from=$(OUTPUT)/EN0108821505M.cal.cub \ + to=$(OUTPUT)/EN0108821505M.txt \ + name="footprint" \ + type=Polygon > /dev/null; + rm $(OUTPUT)/EN0108821505M.cal.cub; diff --git a/isis/src/base/apps/footprintinit/tsts/cross/Makefile b/isis/src/base/apps/footprintinit/tsts/cross/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..33af3b7b5272aaa0d294c91e0d008d3d6959174b --- /dev/null +++ b/isis/src/base/apps/footprintinit/tsts/cross/Makefile @@ -0,0 +1,15 @@ +APPNAME = footprintinit + +include $(ISISROOT)/make/isismake.tsts + +# cp so I don't destroy the input cube +commands: + $(CP) $(INPUT)/f174s47.cub $(OUTPUT)/f174s47.cub; + $(APPNAME) from=$(OUTPUT)/f174s47.cub \ + sinc=100 linc=100 > /dev/null; + $$ISISROOT/bin/blobdump \ + from=$(OUTPUT)/f174s47.cub \ + to=$(OUTPUT)/f174s47.txt \ + name=footprint \ + type=Polygon > /dev/null; + rm $(OUTPUT)/f174s47.cub diff --git a/isis/src/base/apps/footprintinit/tsts/default/Makefile b/isis/src/base/apps/footprintinit/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e83298b2ffea5f1880b20e03f54e98a5d9183151 --- /dev/null +++ b/isis/src/base/apps/footprintinit/tsts/default/Makefile @@ -0,0 +1,14 @@ +APPNAME = footprintinit + +include $(ISISROOT)/make/isismake.tsts + +# cp so I don't destroy the input cube +commands: + $(CP) $(INPUT)/ab102401.cub $(OUTPUT)/ab102401.cub; + $(APPNAME) from=$(OUTPUT)/ab102401.cub sinc=1 linc=1 > /dev/null; + $$ISISROOT/bin/blobdump \ + from=$(OUTPUT)/ab102401.cub \ + to=$(OUTPUT)/ab102401.txt \ + name=footprint \ + type=Polygon > /dev/null; + rm $(OUTPUT)/ab102401.cub diff --git a/isis/src/base/apps/footprintinit/tsts/limb/Makefile b/isis/src/base/apps/footprintinit/tsts/limb/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..236680b52d62807ee0d3b3fec33f1da3efeb1df1 --- /dev/null +++ b/isis/src/base/apps/footprintinit/tsts/limb/Makefile @@ -0,0 +1,26 @@ +APPNAME = footprintinit + +include $(ISISROOT)/make/isismake.tsts + +# cp so I don't destroy the input cube +commands: + $(CP) $(INPUT)/CM_1504753137_1.ir.cub \ + $(OUTPUT)/CM_1504753137_1.ir.cub; + $(APPNAME) from=$(OUTPUT)/CM_1504753137_1.ir.cub \ + sinc=5 linc=5 > /dev/null; + $$ISISROOT/bin/blobdump \ + from=$(OUTPUT)/CM_1504753137_1.ir.cub \ + to=$(OUTPUT)/CM_1504753137_1.txt \ + name=footprint \ + type=Polygon > /dev/null; + $(CP) $(INPUT)/CM_1504753137_1.ir.cub \ + $(OUTPUT)/CM_1504753137_1.2.ir.cub; + $(APPNAME) from=$(OUTPUT)/CM_1504753137_1.2.ir.cub \ + sinc=5 linc=5 maxemission=50.0 maxincidence=50.0 > /dev/null; + $$ISISROOT/bin/blobdump \ + from=$(OUTPUT)/CM_1504753137_1.2.ir.cub \ + to=$(OUTPUT)/CM_1504753137_1.2.txt \ + name=footprint \ + type=Polygon > /dev/null; + rm $(OUTPUT)/CM_1504753137_1.ir.cub + rm $(OUTPUT)/CM_1504753137_1.2.ir.cub diff --git a/isis/src/base/apps/footprintinit/tsts/pole/Makefile b/isis/src/base/apps/footprintinit/tsts/pole/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6924caa1abc50e1453910fc954278cdd1c3c48fa --- /dev/null +++ b/isis/src/base/apps/footprintinit/tsts/pole/Makefile @@ -0,0 +1,15 @@ +APPNAME = footprintinit + +include $(ISISROOT)/make/isismake.tsts + +# cp so I don't destroy the input cube +commands: + $(CP) $(INPUT)/N1500056057_2.cub $(OUTPUT)/N1500056057_2.cub; + $(APPNAME) from=$(OUTPUT)/N1500056057_2.cub sinc=10 linc=10 \ + > /dev/null; + $$ISISROOT/bin/blobdump \ + from=$(OUTPUT)/N1500056057_2.cub \ + to=$(OUTPUT)/N1500056057_2.txt \ + name=footprint \ + type=Polygon > /dev/null; + rm $(OUTPUT)/N1500056057_2.cub diff --git a/isis/src/base/apps/footprintinit/tsts/poleMultiBoundary/Makefile b/isis/src/base/apps/footprintinit/tsts/poleMultiBoundary/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d9540c6369f9b056f0a5dc0faeb8aae51ce834f5 --- /dev/null +++ b/isis/src/base/apps/footprintinit/tsts/poleMultiBoundary/Makefile @@ -0,0 +1,15 @@ +APPNAME = footprintinit + +include $(ISISROOT)/make/isismake.tsts + +# cp so I don't destroy the input cube +commands: + $(CP) $(INPUT)/e1202081.cub $(OUTPUT)/e1202081.cub; + $(APPNAME) from=$(OUTPUT)/e1202081.cub sinc=17 linc=17 \ + > /dev/null; + $$ISISROOT/bin/blobdump \ + from=$(OUTPUT)/e1202081.cub \ + to=$(OUTPUT)/e1202081.txt \ + name=footprint \ + type=Polygon > /dev/null; + rm $(OUTPUT)/e1202081.cub diff --git a/isis/src/base/apps/footprintinit/tsts/precision/Makefile b/isis/src/base/apps/footprintinit/tsts/precision/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..616012d40d681c1fdcd8665b23e8c05c436d8ced --- /dev/null +++ b/isis/src/base/apps/footprintinit/tsts/precision/Makefile @@ -0,0 +1,15 @@ +APPNAME = footprintinit + +include $(ISISROOT)/make/isismake.tsts + +# cp so I don't destroy the input cube +commands: + $(CP) $(INPUT)/N1466508085_1.cub $(OUTPUT)/N1466508085_1.cub; + $(APPNAME) from=$(OUTPUT)/N1466508085_1.cub \ + testxy=true increaseprecision=true > /dev/null; + $$ISISROOT/bin/blobdump \ + from=$(OUTPUT)/N1466508085_1.cub \ + to=$(OUTPUT)/N1466508085_1.txt \ + name=footprint \ + type=Polygon > /dev/null; + rm $(OUTPUT)/N1466508085_1.cub diff --git a/isis/src/base/apps/footprintinit/tsts/pushframe/Makefile b/isis/src/base/apps/footprintinit/tsts/pushframe/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..72b602a21032533bb8de608476601729543e7e59 --- /dev/null +++ b/isis/src/base/apps/footprintinit/tsts/pushframe/Makefile @@ -0,0 +1,15 @@ +APPNAME = footprintinit + +include $(ISISROOT)/make/isismake.tsts + +# cp so I don't destroy the input cube +commands: + $(CP) $(INPUT)/V30027015RDR.even.cub $(OUTPUT)/V30027015RDR.even.cub; + $(APPNAME) from=$(OUTPUT)/V30027015RDR.even.cub sinc=65 linc=65 \ + > /dev/null; + $$ISISROOT/bin/blobdump \ + from=$(OUTPUT)/V30027015RDR.even.cub \ + to=$(OUTPUT)/V30027015RDR.even.txt \ + name=footprint \ + type=Polygon > /dev/null; + rm $(OUTPUT)/V30027015RDR.even.cub diff --git a/isis/src/base/apps/footprintinit/tsts/skip/Makefile b/isis/src/base/apps/footprintinit/tsts/skip/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..abb2cecf26ea096239e33fbb4a8c7e11231d144b --- /dev/null +++ b/isis/src/base/apps/footprintinit/tsts/skip/Makefile @@ -0,0 +1,15 @@ +APPNAME = footprintinit + +include $(ISISROOT)/make/isismake.tsts + +# cp so I don't destroy the input cube +commands: + $(CP) $(INPUT)/EN0108821505M.cal.cub $(OUTPUT)/EN0108821505M.cal.cub; + $(APPNAME) from=$(OUTPUT)/EN0108821505M.cal.cub \ + sinc=3 linc=3 > /dev/null; + $$ISISROOT/bin/blobdump \ + from=$(OUTPUT)/EN0108821505M.cal.cub \ + to=$(OUTPUT)/EN0108821505M.txt \ + name=footprint \ + type=Polygon > /dev/null; + rm $(OUTPUT)/EN0108821505M.cal.cub; diff --git a/isis/src/base/apps/footprintinit/tsts/step/Makefile b/isis/src/base/apps/footprintinit/tsts/step/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9d0ace7f0fa592490ca60374f48e7d7abc73427c --- /dev/null +++ b/isis/src/base/apps/footprintinit/tsts/step/Makefile @@ -0,0 +1,16 @@ +APPNAME = footprintinit + +include $(ISISROOT)/make/isismake.tsts + +# cp so I don't destroy the input cube +commands: + $(CP) $(INPUT)/PSP_001365_2720_RED4_0.cub $(OUTPUT)/long.cub; + $(APPNAME) from=$(OUTPUT)/long.cub linc=1500 > /dev/null; + $$ISISROOT/bin/blobdump from=$(OUTPUT)/long.cub \ + to=$(OUTPUT)/long.txt name=footprint type=Polygon > /dev/null; + rm $(OUTPUT)/long.cub + $(CP) $(INPUT)/PSP_001365_2720_RED4_0.cub $(OUTPUT)/wide.cub; + $(APPNAME) from=$(OUTPUT)/wide.cub sinc=1500 >/dev/null; + $$ISISROOT/bin/blobdump from=$(OUTPUT)/wide.cub \ + to=$(OUTPUT)/wide.txt name=footprint type=Polygon > /dev/null; + rm $(OUTPUT)/wide.cub diff --git a/isis/src/base/apps/footprintinit/tsts/testxy/Makefile b/isis/src/base/apps/footprintinit/tsts/testxy/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fef5f9a3180addb4bb5bcb899f208032b7676e2f --- /dev/null +++ b/isis/src/base/apps/footprintinit/tsts/testxy/Makefile @@ -0,0 +1,15 @@ +APPNAME = footprintinit + +include $(ISISROOT)/make/isismake.tsts + +# cp so I don't destroy the input cube +commands: + $(CP) $(INPUT)/f843a02.cub $(OUTPUT)/f843a02.cub; + $(APPNAME) from=$(OUTPUT)/f843a02.cub \ + testxy=true map=$(INPUT)/map.pvl > /dev/null; + $$ISISROOT/bin/blobdump \ + from=$(OUTPUT)/f843a02.cub \ + to=$(OUTPUT)/f843a02.txt \ + name=footprint \ + type=Polygon > /dev/null; + rm $(OUTPUT)/f843a02.cub diff --git a/isis/src/base/apps/footprintmerge/Makefile b/isis/src/base/apps/footprintmerge/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/footprintmerge/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/footprintmerge/footprintmerge.cpp b/isis/src/base/apps/footprintmerge/footprintmerge.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ade5be017b551529aa659b02a623b0da7bacc16 --- /dev/null +++ b/isis/src/base/apps/footprintmerge/footprintmerge.cpp @@ -0,0 +1,167 @@ +#include "Isis.h" + +#include + +#include "FileList.h" +#include "Progress.h" +#include "iException.h" +#include "SerialNumber.h" +#include "PolygonTools.h" +#include "ImagePolygon.h" +#include "Process.h" +#include "Pvl.h" + +#include "geos/geom/Geometry.h" +#include "geos/geom/MultiPolygon.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + FileList imageList; + imageList.Read(ui.GetFilename ("FROMLIST")); + if (imageList.size() < 1) { + std::string msg = "The list file [" + ui.GetFilename("FROMLIST") + + "] does not contain any data"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + Progress prog; + prog.SetText ("Merging footprints"); + prog.SetMaximumSteps(imageList.size()); + prog.CheckStatus (); + + // For this first loop union all image polygons + vector allPolys; + vector files; + bool conv360 = false; + + for (unsigned int img=0; imgPolys()->getNumGeometries() > 1) conv360 = true; + + allPolys.push_back(PolygonTools::CopyMultiPolygon(poly->Polys())); + + files.push_back(imageList[img]); + + prog.CheckStatus (); + + } + + // If any islands are on the 0/360 boundary convert to -180/180 and merge + // any polys that were split on the boundary. + if (conv360) { + for (unsigned int i=0; igetNumGeometries() > 1 || + m->getCoordinates()->minCoordinate()->x > 180.) { + geos::geom::MultiPolygon *poly = + PolygonTools::To180((geos::geom::MultiPolygon *)allPolys[i]); + allPolys[i] = poly; + } + } + } + + // Create union poly + geos::geom::GeometryCollection *polyCollection = + Isis::globalFactory.createGeometryCollection(allPolys); + geos::geom::Geometry *unionPoly = polyCollection->buffer(0); + + + // How many polygons are in unionPoly + vector islandPolys; + + if (unionPoly->getGeometryTypeId() == geos::geom::GEOS_POLYGON) { + // There are no islands, all cubes are in a single cluster + std::cout<<"NO ISLANDS, ALL CUBES OVERLAP"<getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) { + geos::geom::MultiPolygon *multi = (geos::geom::MultiPolygon *) unionPoly; + for (unsigned int i=0; igetNumGeometries(); ++i) { + islandPolys.push_back(multi->getGeometryN(i)->clone()); + } + } + + // Intersect each input poly (the first of each cube) with each poly + // from the unionPoly, and keep track of which images are in each + // unionPoly. + + prog.SetText ("Intersecting footprints"); + prog.SetMaximumSteps(allPolys.size()); + prog.CheckStatus (); + + typedef std::vector islandFiles; + std::vector< islandFiles > islands; + islands.resize(islandPolys.size()); + for (unsigned int i=0; iintersects(islandPolys[p])) { + islands[p].push_back(files[i]); + } + } + prog.CheckStatus (); + } + + + string mode = ui.GetString("MODE"); + + // print out island statistics + // Brief + if (mode=="BRIEF") { + PvlGroup results("Results"); + results += PvlKeyword("NumberOfIslands",(int)islandPolys.size()); + Application::Log(results); + } + else if (mode=="FULL") { + string out = ui.GetFilename("TO"); + PvlObject results("Results"); + for (unsigned int p=0; p + + + Find footprint islands, given a list of cubes + + + + This program will take a list of cubes, merge the cube footprints and find + those cubes that are islands. + + + + Geometry + + + + Original version + + Added handling of cubes crossing 0/360 boundary + + + Fixed progress printing. + + + + + + + filename + input + + List of Input cubes + + + The list of cubes used to find footprint islands. + + + *.lis *.lst *.txt + + + + filename + output + Text file output + + Text file used if MODE=Full. The filenames are listed for each footprint island. + + + + + string + + BRIEF + + + Amount of information written out about each footprint island. + + + Indicates whether detailed information about which images are contained in each footprint + island are printed or simply how many footprint islands there are. + + + + + + + + + diff --git a/isis/src/base/apps/footprintmerge/tsts/360Boundary/Makefile b/isis/src/base/apps/footprintmerge/tsts/360Boundary/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bbba831c878e839171f4008019ce0bc65e6c2ac5 --- /dev/null +++ b/isis/src/base/apps/footprintmerge/tsts/360Boundary/Makefile @@ -0,0 +1,15 @@ +APPNAME = footprintmerge + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/fromList.lis; + $(APPNAME) fromlist=$(OUTPUT)/fromList.lis \ + to=$(OUTPUT)/islands.txt mode=FULL > /dev/null;> /dev/null; + $(RM) $(OUTPUT)/fromList.lis; + $(SED) -e 's+\([^b]*\)\(m[0-9]*.lev1.crop.cub\)+\2X+g' \ + output/islands.txt | $(SED) -e 's+)++' | tr "X" "\n" \ + > $(OUTPUT)/islands2.txt; + $(SED) -e 's+Files *=.*-++' $(OUTPUT)/islands2.txt | \ + $(SED) -e 's+/.*-++g' | $(SED) -e 's+,++g' > $(OUTPUT)/islands.pvl; + $(RM) $(OUTPUT)/islands.txt $(OUTPUT)/islands2.txt > /dev/null; diff --git a/isis/src/base/apps/footprintmerge/tsts/Makefile b/isis/src/base/apps/footprintmerge/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/footprintmerge/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/footprintmerge/tsts/default/Makefile b/isis/src/base/apps/footprintmerge/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bc93b29f0fb7b29a205e6a28e00e2429852535f9 --- /dev/null +++ b/isis/src/base/apps/footprintmerge/tsts/default/Makefile @@ -0,0 +1,16 @@ +APPNAME = footprintmerge + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/fromList.lis; + $(APPNAME) fromlist=$(OUTPUT)/fromList.lis \ + to=$(OUTPUT)/islands.txt mode=FULL > /dev/null; + $(RM) $(OUTPUT)/fromList.lis; + $(SED) -e 's+\([^b]*\)\(I[0-9]*.lev1.crop.cub\)+\2X+g' \ + output/islands.txt | $(SED) -e 's+)++' | tr "X" "\n" \ + > $(OUTPUT)/islands2.txt; + $(SED) -e 's+Files *=.*-++' $(OUTPUT)/islands2.txt | \ + $(SED) -e 's+/.*-++g' | $(SED) -e 's+,++g' | $(SED) -e 's+.*/++'\ + > $(OUTPUT)/islands.pvl; + $(RM) $(OUTPUT)/islands.txt $(OUTPUT)/islands2.txt > /dev/null; diff --git a/isis/src/base/apps/fx/Makefile b/isis/src/base/apps/fx/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/fx/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/fx/assets/image/band1.jpg b/isis/src/base/apps/fx/assets/image/band1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c1711cdc92817114e8745c837f4a60072a49b6ff Binary files /dev/null and b/isis/src/base/apps/fx/assets/image/band1.jpg differ diff --git a/isis/src/base/apps/fx/assets/image/band2.jpg b/isis/src/base/apps/fx/assets/image/band2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2916bf3e0e4ced06f0240257434b059146376d5c Binary files /dev/null and b/isis/src/base/apps/fx/assets/image/band2.jpg differ diff --git a/isis/src/base/apps/fx/assets/image/fxgui.jpg b/isis/src/base/apps/fx/assets/image/fxgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6e8c8fbef51f6438c804c3773364d08b73bbce35 Binary files /dev/null and b/isis/src/base/apps/fx/assets/image/fxgui.jpg differ diff --git a/isis/src/base/apps/fx/assets/image/sum.jpg b/isis/src/base/apps/fx/assets/image/sum.jpg new file mode 100644 index 0000000000000000000000000000000000000000..59dfa606191ed33dcccec3839ca51267fa29e4ea Binary files /dev/null and b/isis/src/base/apps/fx/assets/image/sum.jpg differ diff --git a/isis/src/base/apps/fx/assets/thumb/band1.jpg b/isis/src/base/apps/fx/assets/thumb/band1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fee7a61c04fadae43be07a215ebcc6dff8019233 Binary files /dev/null and b/isis/src/base/apps/fx/assets/thumb/band1.jpg differ diff --git a/isis/src/base/apps/fx/assets/thumb/band2.jpg b/isis/src/base/apps/fx/assets/thumb/band2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c957a0b37ae8a301f67526709bdf10df9132e0af Binary files /dev/null and b/isis/src/base/apps/fx/assets/thumb/band2.jpg differ diff --git a/isis/src/base/apps/fx/assets/thumb/fxgui.jpg b/isis/src/base/apps/fx/assets/thumb/fxgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..592ddda900eeaa75222b6285dafdf2a71dfb5605 Binary files /dev/null and b/isis/src/base/apps/fx/assets/thumb/fxgui.jpg differ diff --git a/isis/src/base/apps/fx/assets/thumb/sum.jpg b/isis/src/base/apps/fx/assets/thumb/sum.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fc546324fcce9ff2796ddc80d147fbc38dba0109 Binary files /dev/null and b/isis/src/base/apps/fx/assets/thumb/sum.jpg differ diff --git a/isis/src/base/apps/fx/fx.cpp b/isis/src/base/apps/fx/fx.cpp new file mode 100644 index 0000000000000000000000000000000000000000..466fb6f15519d309916ac7747badaabbcb97d987 --- /dev/null +++ b/isis/src/base/apps/fx/fx.cpp @@ -0,0 +1,113 @@ +/** + * @file + * $Revision: 1.8 $ + * $Date: 2010/04/08 15:28:20 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Isis.h" + +#include + +#include "iString.h" +#include "CubeCalculator.h" +#include "CubeInfixToPostfix.h" +#include "FileList.h" +#include "ProcessByLine.h" + + +using namespace std; +using namespace Isis; + +Isis::CubeCalculator c; + +// Prototypes +void Evaluate(vector &input, vector &output); + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + ProcessByLine p; + QVector cubes; + Cube *outCube; + + if(ui.GetString("MODE") == "CUBES") { + // Require atleast one file to be specified + cubes.push_back( p.SetInputCube("F1", Isis::AllMatchOrOne) ); + if(ui.WasEntered("F2")) cubes.push_back( p.SetInputCube("F2", Isis::AllMatchOrOne) ); + if(ui.WasEntered("F3")) cubes.push_back( p.SetInputCube("F3", Isis::AllMatchOrOne) ); + if(ui.WasEntered("F4")) cubes.push_back( p.SetInputCube("F4", Isis::AllMatchOrOne) ); + if(ui.WasEntered("F5")) cubes.push_back( p.SetInputCube("F5", Isis::AllMatchOrOne) ); + outCube = p.SetOutputCube("TO"); + } + else if(ui.GetString("MODE") == "LIST") { + string inputFilename = ui.GetFilename("FROMLIST"); + FileList list(inputFilename); + + // Run through file list and set its entries as input cubes + for(int i = 0; i < (int)list.size(); i++) { + CubeAttributeInput att(list[i]); + cubes.push_back( p.SetInputCube(list[i], att, Isis::AllMatchOrOne) ); + } + outCube = p.SetOutputCube("TO"); + } + else { + int lines = ui.GetInteger("LINES"); + int samples = ui.GetInteger("SAMPLES"); + int bands = ui.GetInteger("BANDS"); + outCube = p.SetOutputCube("TO", samples, lines, bands); + } + + CubeInfixToPostfix infixToPostfix; + c.PrepareCalculations(infixToPostfix.Convert(ui.GetString("EQUATION")), cubes, outCube); + p.StartProcess(Evaluate); + p.EndProcess(); +} + +/** + * Take in the input buffer, apply the user-defined equation to + * it, then write the results to the output buffer + * + * @param input The input buffer vector + * @param output The output buffer + */ +void Evaluate(vector &input, vector &output) { + Buffer& outBuffer = *output[0]; + + QVector inputCopy; + + for(int i = 0; i < (int)input.size(); i++) { + inputCopy.push_back(input[i]); + } + + QVector results = c.RunCalculations(inputCopy, + outBuffer.Line(), outBuffer.Band()); + + // If final result is a scalar, set all pixels to that value. + if(results.size() == 1) { + for(int i = 0; i < (int)outBuffer.size(); i++) { + outBuffer[i] = results[0]; + } + } + // Final result is a valid vector, write to output buffer + else { + for(int i = 0; i < (int)results.size(); i++) { + outBuffer[i] = results[i]; + } + } + +} diff --git a/isis/src/base/apps/fx/fx.xml b/isis/src/base/apps/fx/fx.xml new file mode 100644 index 0000000000000000000000000000000000000000..61081b975fefb75e7af1f789ddbef5881af1091c --- /dev/null +++ b/isis/src/base/apps/fx/fx.xml @@ -0,0 +1,612 @@ + + + + + Generalized arithmetic operations using multiple cube files + + + + FX allows general arithmetic operations to be performed on an arbitrary + number of input cubes. It works by loading whatever input files are + specified, if any, then applying a user defined equation to those files + and then writing the results to an output cube. For instance, if the user + wanted to isolate all pixels in a cube that had a DN greater than 100, + then an equation like "f1 * (f1 > 100)" could be applied to the cube. + +

    + The equation parser is case insensitive and all braces get converted to + parenthesis. Whitespace is ignored. Currently, you must explicitly + state all multiplication operations (e.g. 5x will not work, but 5*x will). + The modulus (%), AND and OR operators are not implemented yet. +

    + +

    + The following table shows all currently supported scalars/special tokens. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SCALARS
    ScalarDescriptionExample
    F#File operatorf3 denotes third file
    # or #.# or .#Any integer or double.12, 3.14, .007 are all valid.
    bandCurrent band numberf1 * band
    lineCurrent line numberline + f1
    sampleCurrent sample numbersample / line + f1
    piPi (3.14159...)f1 > (e^pi)
    eEuler's number (2.71828...)f1 == ln(e)
    + +

    + The following table shows all currently supported operators sorted + by precedence (0 = highest precedence). All examples are valid + equations that assume one or two files (F1, F2) are loaded. All angles + are in radians, not degrees. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OPERATORS
    PrecedenceOperatorDescriptionExample
    0{ [ ( ) ] }Parenthesis, brackets, or bracesf2*(f1+[30-{line/pi}])
    1--Negative sign--f1 + f2
    2>Greater thanf1 > f2
    3<Less than(f1 < f2) / f2
    4<=Less than or equal.505 <= f1
    5>=Greater than or equalf1 * (f1 >= 101)
    6==Equal tof1 == (f2/2)
    7!=Not equal tof1 != f2
    8absAbsolute valueabs(f2 - f1)
    9minMinimum of Two DNsf1 + min(5, f2) + min(f2, f3)
    10lineminMinimum of DNs on the current linef1 + linemin(f2)
    11cubeminMinimum of a Cubef1 + mincube(f2)
    12maxMaximum20 * max(f1)
    13linemmaxMinimum of DNs on the current linef1 + linemax(f2)
    14cubemaxMinimum of a Cubef1 + maxcube(f2)
    15sinSinef1 * sin(123/321)
    16cosCosinecos(.02*50)
    17tanTangenttan(f1/f2)
    18cscCosecant12.3 + csc(f1)
    19secSecantsin(pi/60) + (sec(f2))^2
    20cotCotangentline + cot(f1) - 42
    21asinArcsine0.006 ^ asin(f1*5)
    22acosArccosineacos(1/[2*pi])
    23atanArctangentatan(f1/e)
    24atan2Arctangent2atan2(--10 5.5)
    25sinhHyperbolic sine55 + sinh(f2)
    26coshHyperbolic cosinecosh(sample^pi)
    27tanhHyperbolic tangenttanh(f1)
    28log or lnNatural logln(abs(1/[f2-f1]))
    29log10Log base 1099 + log10(f1-160)
    30sqrtSquare rootsqrt(abs[1000 - f2])
    31<<Left shift. Note: pixel shift, not bitwisef1 << 250
    32>>Right shift. Note: pixel shift, not bitwisef2 + (f1 >> 500)
    33^Exponentf1 ^ 3
    34*Multiplication10 * f1
    35/Divisionf2 / f1
    36+Addition123 + 0.004 + f1
    37-Subtraction10 - (--f1)
    + +
    + + + Math and Statistics + + + + + algebra + + + + + + Original version + + + Converted to Isis 3 + + + Added single line and sample functionality + + + Upgraded to work with new Calculator classes + + + Renamed parameter FILELIST to FROMLIST + + + Updated documentation to reflect the units of the trig functions. + + + Min, max capabilities have been expanded to include line and cube + min/max. + + + + + + + cube + input + Input file + + Input cube file + + + *.cub + + + + + cube + input + None + Input file + + Input cube file + + + *.cub + + + + + cube + input + None + Input file + + Input cube file + + + *.cub + + + + + cube + input + None + Input file + + Input cube file + + + *.cub + + + + + cube + input + None + Input file + + Input cube file + + + *.cub + + + + + + + cube + real + output + + Output cube + + + The resultant cube containing the data after it has processed by the equation. + + + *.cub + + + + + string + Image processing equation + + This equation will be parsed and used to perform the specified calculations. + + + + + + + string + CUBES + File I/O options + + There is a choice to simply specify input cubes directly, use a list of input cubes in a text file, or to create output data only. + + + + + + + + + + + + + + filename + input + + Input list file + + + This file contains a list of all the cube files to be processed + + + *.txt + + + + + + + integer + 1 + Number of lines + + This is the number of the lines the output cube will have + + 1 + + + + integer + 1 + Number of samples + + This is the number of the samples the output cube will have + + 1 + + + + integer + 1 + Number of bands + + This is the number of the bands the output cube will have + + 1 + + + + + + + + + Add two images + + In this example, two images will be added to each other + + + + f1=../isisTruth.cub+1 f2=../isisTruth.cub+2 to=../result.cub equation=f1+f2 + + + Add Band 1 and Band 2 using default settings + + + + + + Band 1 + This is an input image for the FX example. + + + F1 + + + + Band 2 + This is an input image for the FX example. + + + F2 + + + + + + Output image + This is the 500 by 500 output image of the results. + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a calculation on the input image. + + + + + + + +
    diff --git a/isis/src/base/apps/fx/tsts/Makefile b/isis/src/base/apps/fx/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/fx/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/fx/tsts/cubestats/Makefile b/isis/src/base/apps/fx/tsts/cubestats/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c506bca3fc76d65d5eea54e863eb76eb9a41e9b9 --- /dev/null +++ b/isis/src/base/apps/fx/tsts/cubestats/Makefile @@ -0,0 +1,13 @@ +APPNAME = fx + +include $(ISISROOT)/make/isismake.tsts +commands: + $(APPNAME) f1=$(INPUT)/in1.cub \ + f2=$(INPUT)/in2.cub \ + to=$(OUTPUT)/result.cub \ + equation="cubemax(f1)-cubemin(f2)+linemin(f1)-linemin(f2)" \ + > /dev/null; \ + $(APPNAME) f1=$(INPUT)/in1.cub \ + f2=$(INPUT)/in2.cub \ + to=$(OUTPUT)/result.cub \ + equation="max(f1,f2)+min(f1,f2)" > /dev/null; diff --git a/isis/src/base/apps/fx/tsts/default/Makefile b/isis/src/base/apps/fx/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a13ef88c2cd47ba271a49b24ac03bc87ae97e15c --- /dev/null +++ b/isis/src/base/apps/fx/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = fx + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) f1=$(INPUT)/isisTruth.cub+1 \ + f2=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/CUBEresult.cub \ + equation="--f1+f2/cos(1/2)" > /dev/null; diff --git a/isis/src/base/apps/fx/tsts/filelist/Makefile b/isis/src/base/apps/fx/tsts/filelist/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..33ae2be6dbd14e36bd63d00d60c871d45da107dd --- /dev/null +++ b/isis/src/base/apps/fx/tsts/filelist/Makefile @@ -0,0 +1,11 @@ +APPNAME = fx + +include $(ISISROOT)/make/isismake.tsts + +commands: + ls $(INPUT)/* > $(OUTPUT)/list.txt + $(APPNAME) fromlist=$(OUTPUT)/list.txt \ + mode=list \ + equation=f1+f2+f3 \ + to=$(OUTPUT)/LISTresult.cub > /dev/null; + rm $(OUTPUT)/list.txt; diff --git a/isis/src/base/apps/fx/tsts/operators/Makefile b/isis/src/base/apps/fx/tsts/operators/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d19a9627c48a0111575bfc662ba939dfb7d151bc --- /dev/null +++ b/isis/src/base/apps/fx/tsts/operators/Makefile @@ -0,0 +1,13 @@ +APPNAME = fx + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) f1=$(INPUT)/peaks.cub+1 \ + f2=$(INPUT)/peaks.cub+2 \ + to=$(OUTPUT)/max2.cub \ + equation="max(150, max(f1,f2))" > /dev/null; + $(APPNAME) f1=$(INPUT)/peaks.cub+1 \ + f2=$(INPUT)/peaks.cub+2 \ + to=$(OUTPUT)/min2.cub \ + equation="min(25, min(f1,f2))" > /dev/null; diff --git a/isis/src/base/apps/fx/tsts/outputonly/Makefile b/isis/src/base/apps/fx/tsts/outputonly/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6ec8738a5ba1ad70ccadc2b09ebaf42fb423ed51 --- /dev/null +++ b/isis/src/base/apps/fx/tsts/outputonly/Makefile @@ -0,0 +1,11 @@ +APPNAME = fx + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) to=$(OUTPUT)/OUTPUTONLYresult.cub \ + mode=outputonly \ + lines=100 \ + samples=100 \ + bands=2 \ + equation=line+sample+band > /dev/null; diff --git a/isis/src/base/apps/fx/tsts/singleLine/Makefile b/isis/src/base/apps/fx/tsts/singleLine/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b205a55b72e55bfe00c21627a65d248e6d218609 --- /dev/null +++ b/isis/src/base/apps/fx/tsts/singleLine/Makefile @@ -0,0 +1,9 @@ +APPNAME = fx + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) f1=$(INPUT)/in1.cub \ + f2=$(INPUT)/in2.cub \ + to=$(OUTPUT)/CUBEresult.cub \ + equation=f1+f2 > /dev/null; diff --git a/isis/src/base/apps/gauss/Makefile b/isis/src/base/apps/gauss/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/gauss/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/gauss/assets/images/gauss3x3.jpg b/isis/src/base/apps/gauss/assets/images/gauss3x3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bfaf949b97cc29c412e8958de8bf453429027627 Binary files /dev/null and b/isis/src/base/apps/gauss/assets/images/gauss3x3.jpg differ diff --git a/isis/src/base/apps/gauss/assets/images/gauss3x3gui.jpg b/isis/src/base/apps/gauss/assets/images/gauss3x3gui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..0b9eb07de55385886953692a0b595041436f931a Binary files /dev/null and b/isis/src/base/apps/gauss/assets/images/gauss3x3gui.jpg differ diff --git a/isis/src/base/apps/gauss/assets/images/gauss5x5.jpg b/isis/src/base/apps/gauss/assets/images/gauss5x5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..319b4e28438fccade0d5b83269f01d3a170481f5 Binary files /dev/null and b/isis/src/base/apps/gauss/assets/images/gauss5x5.jpg differ diff --git a/isis/src/base/apps/gauss/assets/images/gauss5x5gui.jpg b/isis/src/base/apps/gauss/assets/images/gauss5x5gui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8002f86bfcd8a53657896f4fa231708bb8c85b1c Binary files /dev/null and b/isis/src/base/apps/gauss/assets/images/gauss5x5gui.jpg differ diff --git a/isis/src/base/apps/gauss/assets/images/peaks.jpg b/isis/src/base/apps/gauss/assets/images/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..22ee658b0c230aec89f3564c1e4b3de9ec49df12 Binary files /dev/null and b/isis/src/base/apps/gauss/assets/images/peaks.jpg differ diff --git a/isis/src/base/apps/gauss/assets/thumbs/gauss3x3.jpg b/isis/src/base/apps/gauss/assets/thumbs/gauss3x3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7ef564465bca8010db0f2232454bf9dab33c9aa9 Binary files /dev/null and b/isis/src/base/apps/gauss/assets/thumbs/gauss3x3.jpg differ diff --git a/isis/src/base/apps/gauss/assets/thumbs/gauss3x3gui.jpg b/isis/src/base/apps/gauss/assets/thumbs/gauss3x3gui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..0b9eb07de55385886953692a0b595041436f931a Binary files /dev/null and b/isis/src/base/apps/gauss/assets/thumbs/gauss3x3gui.jpg differ diff --git a/isis/src/base/apps/gauss/assets/thumbs/gauss5x5.jpg b/isis/src/base/apps/gauss/assets/thumbs/gauss5x5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a4d906bf4820cc497df30869a0c4dcffd4970a5f Binary files /dev/null and b/isis/src/base/apps/gauss/assets/thumbs/gauss5x5.jpg differ diff --git a/isis/src/base/apps/gauss/assets/thumbs/gauss5x5gui.jpg b/isis/src/base/apps/gauss/assets/thumbs/gauss5x5gui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8002f86bfcd8a53657896f4fa231708bb8c85b1c Binary files /dev/null and b/isis/src/base/apps/gauss/assets/thumbs/gauss5x5gui.jpg differ diff --git a/isis/src/base/apps/gauss/assets/thumbs/peaks.jpg b/isis/src/base/apps/gauss/assets/thumbs/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e0df3d4fb0ebc3096c3a238f04077f4b59898268 Binary files /dev/null and b/isis/src/base/apps/gauss/assets/thumbs/peaks.jpg differ diff --git a/isis/src/base/apps/gauss/gauss.cpp b/isis/src/base/apps/gauss/gauss.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48b12b54ecbe32ac6772ad94e7eec66df0d7b412 --- /dev/null +++ b/isis/src/base/apps/gauss/gauss.cpp @@ -0,0 +1,78 @@ +#include +#include "Isis.h" +#include "ProcessByBoxcar.h" +#include "Pvl.h" +#include "SpecialPixel.h" +#include "LineManager.h" +#include "Filename.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void useFilter (Buffer &in, double &v); +void setFilter (int size, double stdDev); +double *coefs; +void IsisMain() { + + ProcessByBoxcar p; + p.SetInputCube ("FROM"); + p.SetOutputCube ("TO"); + + //Set up the user interface + UserInterface &ui = Application::GetUserInterface(); + + //Get the standard deviation from the user + double stdDev = ui.GetDouble("STDDEV"); + + //Get the length of each side of the kernel from the user + // (Note: kernel is always square) + int size = ui.GetInteger("SIZE"); + + //Set the Boxcar size based on the input size + p.SetBoxcarSize (size,size); + + //Reference a pointer to an array of kernel data values + coefs = new double[size*size]; + setFilter (size,stdDev); + + p.StartProcess(useFilter); + p.EndProcess (); + + delete [] coefs; +} + +void setFilter (int size, double stdDev){ + //Iterate through the input kernel's data values to fill the coefs array + const double PI=3.141592653589793; + int i =0; + cout << exp((double)1.0) << endl; + for (double y= -(size/2) ; y <= (size/2) ; y++){ + for (double x=-(size/2) ; x <= (size/2) ; x++){ + /* + Assign gaussian weights based on the following equation + x^2+y^2 + -- ----------- + G(x,y) = 1 2(stdDev)^2 + --------------- e^ + 2(pi)(stdDev)^2 + */ + + coefs[i] = (x * x ) + (y * y); + coefs[i] = (coefs[i] ) / (-2 * (stdDev * stdDev)); + coefs[i] = exp (coefs[i]); + coefs[i] = (1 / (2 * PI * stdDev * stdDev) ) * coefs [i]; + i++; + } + } +} + + +void useFilter (Buffer &in, double &v){ + v = 0; + for (int i= 0 ; i < in.size() ; i++){ + if (!IsSpecial(in[i])){ + v += in[i] * coefs[i] ; + } + } +} diff --git a/isis/src/base/apps/gauss/gauss.xml b/isis/src/base/apps/gauss/gauss.xml new file mode 100644 index 0000000000000000000000000000000000000000..1c99acba96d873cb28903a8600d27482fc3eeaa7 --- /dev/null +++ b/isis/src/base/apps/gauss/gauss.xml @@ -0,0 +1,276 @@ + + + + + + Filter a cube through a kernel using Gaussian weight + + + + This program calculates weight based on the bell-shaped Gaussian + curve. The weight is then applied to an image kernel in such a way as to + create a filter that will move a weighted average through the image. The + end result is a blurred image with reduced detail and noise. The Gaussian + function that determines the weight for all of the values in the kernel is + as follows +
    +                                                  /   x^2+y^2   \
    +                                               - |  -----------  |
    +                G(x,y) =           1              \ 2(STDDEV)^2 /
    +      			    --------------- e^ 
    +			    2(pi)(STDDEV)^2 
    +  
    + This formula creates a kernel that then runs through the image. The center of + the kernel is at (0,0). This means that a 3x3 boxcar will be of the form +
    +        The kernel coordinates	          
    +  (-2,-2) (-1,-2) (0,-2) (1,-2) (2,-2)
    +  (-2,-1) (-1,-1) (0,-1) (1,-1)	(2,-1)	
    +  (-2, 0) (-1, 0) (0, 0) (1, 0) (2, 0)       
    +  (-2, 1) (-1, 1) (0, 1) (1, 1) (2, 1)
    +  (-2, 2) (-1, 2) (0, 2) (1, 2) (2, 2)
    +  
    +          The kernel values (approx)
    +       1   4   7   4   1
    +       4   16  26  16  4
    +       7   26  41  26  7     x 1/273
    +       4   16  26  16  4
    +       1   4   7   4   1 
    +  
    +
    + + + + kernfilter + + + + + Original version + + + + Added application test + + + + Added examples + + + + Fixed bug in boxcar size + + + + Documentation fixes + + + + + Filters + + + + + + cube + input + + Input cube to be filtered + + + Use this parameter to select the filename. All bands within the file + will be filtered. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the filter, a blurred version + of the input file. + + + + + + + integer + + 3 + + + Size of one side of the boxcar + + This is the user specified size of the boxcar that + will move through the image. The boxcar must be square, so the default + value of 3 will result in a 3 x 3 boxcar. A value of five would result + in a 5 x 5 boxcar moving through the image. + + + + + + + double + + 1.0 + + 0 + Standard Deviation + + At the most basic level, standard deviation can be thought of in this + context as the intensity of the blur being applied to the image. The + higher this value, the more noise and detail will be removed. + At a deeper level, standard deviation is described as the average + distance from any single measurement of a set to the mean of that set. + + + + + + + + + Using a 3 x 3 boxcar + + + This example shows the use of the default standard deviation (1.0) and the + default boxcar size (3). Since the boxcar must be square in this program, + this means that a 3 x 3 boxcar will be used. + + + + from= peaks.cub + to=gauss3x3.cub + size=3 + STDDEV= 1.0 + + + This example uses all of the default values specified by the program + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform Gaussian + smoothing with a 3 x 3 boxcar. + + + + + + + + + + Input image before gauss. + + + This is the image as it was taken originally. + + + FROM + + + + + + + Output image after gauss + + + This is the image after the gauss filter. Edges of the image are + now much softer. Detail and noise has been removed. + + + TO + + + + + + + Using a 5 x 5 boxcar + + + This example shows the use of a larger standard deviation (2.0) and the + larger boxcar (5). As with the last example, the single value of 5 will + be applied to both the line size and sample size of the boxcar. + + + + from= peaks.cub + to=bigblur.cub + size=5 + STDDEV= 2.0 + + + This example will create a more dramatic blur, as everything is larger + than in the first example + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform Gaussian + smoothing with a 5 x 5 boxcar and 2.0 as the standard deviation. + + + + + + + + + + Input image before gauss. + + + This is the image as it was taken originally. + + + FROM + + + + + + + Output image after gauss + + + This is the image after the gauss filter. Edges of the image are + now much softer. The blur is much more noticeable on account both of + the larger boxcar and the larger standard deviation. + + + TO + + + + +
    diff --git a/isis/src/base/apps/gauss/tsts/Makefile b/isis/src/base/apps/gauss/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/gauss/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/gauss/tsts/case01/Makefile b/isis/src/base/apps/gauss/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5d1adec319f6bff5b8d16af1f4e4b41f59827b78 --- /dev/null +++ b/isis/src/base/apps/gauss/tsts/case01/Makefile @@ -0,0 +1,9 @@ +APPNAME = gauss + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)//isisTruth.cub \ + to=$(OUTPUT)/gaussTruth2.cub \ + stddev = 2.0 \ + size = 5 > /dev/null; diff --git a/isis/src/base/apps/gauss/tsts/default/Makefile b/isis/src/base/apps/gauss/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6683541bb57b3e170d4709cf1b41cf14c47bee13 --- /dev/null +++ b/isis/src/base/apps/gauss/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = gauss + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)//isisTruth.cub \ + to=$(OUTPUT)/gaussTruth1.cub > /dev/null; diff --git a/isis/src/base/apps/gaussstretch/Makefile b/isis/src/base/apps/gaussstretch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/gaussstretch/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/gaussstretch/gaussstretch.cpp b/isis/src/base/apps/gaussstretch/gaussstretch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8fe2c069131723843140cccecf88e5e82f2795d --- /dev/null +++ b/isis/src/base/apps/gaussstretch/gaussstretch.cpp @@ -0,0 +1,40 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "Statistics.h" +#include "GaussianStretch.h" + +using namespace std; +using namespace Isis; + +void gauss (Buffer &in, Buffer &out); + +vector stretch; + +void IsisMain() +{ + ProcessByLine p; + Cube *icube = p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + double gsigma = Isis::Application::GetUserInterface().GetDouble("GSIGMA"); + + for (int i=0; i< icube->Bands(); i++) { + Histogram hist = *(icube->Histogram(i+1)); + double mean = (hist.Maximum() + hist.Minimum())/2.0; + double stdev = (hist.Maximum() - hist.Minimum())/(2.0*gsigma); + stretch.push_back( new GaussianStretch( hist, mean, stdev) ); + } + + p.StartProcess(gauss); + for (int i=0; i< icube->Bands(); i++) delete stretch[i]; + stretch.clear(); + p.EndProcess(); +} + +// Processing routine for the pca with one input cube +void gauss (Buffer &in, Buffer &out){ + for (int i=0; iMap(in[i]); + } +} + diff --git a/isis/src/base/apps/gaussstretch/gaussstretch.xml b/isis/src/base/apps/gaussstretch/gaussstretch.xml new file mode 100644 index 0000000000000000000000000000000000000000..a00dd99e7630ec126a1a49994224be311c5d9ac7 --- /dev/null +++ b/isis/src/base/apps/gaussstretch/gaussstretch.xml @@ -0,0 +1,81 @@ + + + + Apply a Gaussian Stretch to a cube. + + + + This programs applies a gaussian stretch to a cube. + + + + Math and Statistics + + + + + stretch + decorstretch + + + + + + Original version + + + Fixed memory leakage + + + Removed references to CubeInfo + + + + + + + cube + input + + Input file to stretch + + + The input cube which will have the gaussian stretch applied. + + + *.cub + + + + + cube + real + output + + Output cube + + + The resultant cube containing the image after being stretched. + + + *.cub + + + + + + + double + + gsigma + + + The nonuniformity of the output image's histogram. + For values less than 1.0, the distribution will be closer to uniform. + + 3.0 + 0.0 + + + + diff --git a/isis/src/base/apps/gaussstretch/tsts/Makefile b/isis/src/base/apps/gaussstretch/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/gaussstretch/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/gaussstretch/tsts/default/Makefile b/isis/src/base/apps/gaussstretch/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2d6950328b6f0874abb49142e740c28dac7c0472 --- /dev/null +++ b/isis/src/base/apps/gaussstretch/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = gaussstretch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)//ab102401.cub \ + to= $(OUTPUT)/gaussstretchTruth.cub > /dev/null; diff --git a/isis/src/base/apps/getkey/Makefile b/isis/src/base/apps/getkey/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/getkey/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/getkey/getkey.cpp b/isis/src/base/apps/getkey/getkey.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4e3c3432d05017190320277e96d53de3b41b616 --- /dev/null +++ b/isis/src/base/apps/getkey/getkey.cpp @@ -0,0 +1,127 @@ +#define GUIHELPERS + +#include "Isis.h" + +#include +#include +#include "Process.h" +#include "Pvl.h" +#include "SessionLog.h" + +using namespace std; +using namespace Isis; + +//helper button functins in the code +void helperButtonLog(); + +map GuiHelpers(){ + map helper; + helper ["helperButtonLog"] = (void*) helperButtonLog; + return helper; +} +void IsisMain() { + // Set Preferences to always turn off Terminal Output + PvlGroup &grp = Isis::Preference::Preferences().FindGroup("SessionLog", Isis::Pvl::Traverse); + grp["TerminalOutput"].SetValue("Off"); + + // Use a regular Process + Process p; + + // Get the input file from the user interface + UserInterface &ui = Application::GetUserInterface(); + string labelFile = ui.GetFilename("FROM"); + + // Open the file ... it must be a label-type file + Pvl lab; + lab.Read(labelFile); + bool recursive = ui.GetBoolean("RECURSIVE"); + + // Set up the requested object + PvlKeyword key; + if (ui.WasEntered("OBJNAME")) { + string obj = ui.GetString("OBJNAME"); + + // Get the keyword from the entered group + if (ui.WasEntered("GRPNAME")) { + PvlObject object = lab.FindObject(obj,Pvl::Traverse); + string grp = ui.GetString("GRPNAME"); + key = object.FindGroup(grp,Pvl::Traverse)[ui.GetString("KEYWORD")]; + } + // Find the keyword in the object + else { + if(recursive){ + key = lab.FindObject(obj,Pvl::Traverse).FindKeyword(ui.GetString("KEYWORD"),Pvl::Traverse); + } else { + key = lab.FindObject(obj,Pvl::Traverse)[ui.GetString("KEYWORD")]; + } + } + } + + // Set up the requested group + else if (ui.WasEntered("GRPNAME")) { + string grp = ui.GetString("GRPNAME"); + key = lab.FindGroup(grp,Pvl::Traverse)[ui.GetString("KEYWORD")]; + } + + // Find the keyword in the label, outside of any object or group + else { + if(recursive){ + key = lab.FindKeyword(ui.GetString("KEYWORD"),Pvl::Traverse); + } else { + key = lab[ui.GetString("KEYWORD")]; + } + } + + iString value; + if (ui.WasEntered("KEYINDEX")) { + int i = ui.GetInteger("KEYINDEX"); + + // Make sure they requested a value inside the range of the list + if (key.Size() < i) { + string msg = "The value entered for [KEYINDEX] is out of the array "; + msg += "bounds for the keyword [" + ui.GetString("KEYWORD") + "]"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + // Get the keyword value + else value = key[i-1]; + } + else { + // Push the whole list into a iString and clean it up before returning it + if (key.Size() > 1) { + ostringstream os; + os << key; + iString temp = os.str(); + temp.Token("("); + value = temp.Token(")"); + value = value.ConvertWhiteSpace(); + value = value.Compress(); + } + // Just get the keyword value since it isnt a list + else value = (string)key; + } + + if (ui.GetBoolean("UPPER")) value.UpCase(); + + // Construct a label with the results + PvlGroup results("Results"); + results += PvlKeyword ("From", labelFile); + results += PvlKeyword (ui.GetString("KEYWORD"),value); + if (ui.IsInteractive()) { + Application::GuiLog(results); + } + else { + cout << value << endl; + } + // Write the results to the log but not the terminal + SessionLog::TheLog().AddResults(results); +} + +//Helper function to output the input file to log. +void helperButtonLog () { + UserInterface &ui = Application::GetUserInterface(); + string file(ui.GetFilename("FROM")); + Pvl p; + p.Read(file); + Application::GuiLog(p); +} +//...........end of helper function LogMap ........ diff --git a/isis/src/base/apps/getkey/getkey.xml b/isis/src/base/apps/getkey/getkey.xml new file mode 100644 index 0000000000000000000000000000000000000000..8cdf84f39a877c3547437d5920056149bdcc3f17 --- /dev/null +++ b/isis/src/base/apps/getkey/getkey.xml @@ -0,0 +1,161 @@ + + + + Outputs the value of a requested keyword + + + + This program will output the value of a requested keyword. + Its general use is + within batch jobs, perl programs, or other scripting languages. It allows + the script writer to easily obtain values from cube labels or other + label-like files such as those output by programs like stats, percent, etc. + + + + Scripting + + + + + Original version + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Change parameter from GROUP to GRPNAME because of conflicts in the + print and history files (keyword named GROUP in a GROUP). Added + OBJNAME and UPPER parameters. + + + Fixed application test + + + Added KEYINDEX param and fixed bug with list keywords. Also modified + to output to the UI session log rather than the terminal window if the UI is + open. + + + Fixed bug that did not allow you to get a keyword that was not in a group + or object and reworked code to avoid the repetition of code + + + Added helper button to the FROM parameter to output the file. + + + Added recursive search option + + + Changed preferences to not output to terminal, and added results + group to session log. + + + Made UPPER equal to FALSE by default + + + + + + + filename + input + + Filename of a label file + + + The file specification containing the input label. + + + + helperButtonLog + View file in log area + This helper button will display the input file in the log area + $ISIS3DATA/base/icons/view_text.png + + + + *.cub + + + + + + + string + + Object name containing the group or keyword + + Root + + Enter the name of the Object which contains the group or keyword. + If the keyword is not in an Object then ignore this parameter. + The name is case insensitive. + + + + + string + + Group name containing the keyword + + Root + + Enter the name of the Group which contains the keyword. + + + + + string + + Keyword name + + + Enter the name of the keyword. + + + + + integer + + Index in keyword to return + + + If the keyword is a list, you may enter an integer value for the index of the keyword + value you would like to retrieve. The default is 'All' and will return the entire list of + keyword values. + + All + 1 + + + + + + boolean + False + + Convert results to uppercase + + + If set this parameter causes all character output to be + in uppercase. + + + + boolean + False + + Recursively searches for keyword + + + If set it will search recursively, however if an object name is specified it will recursively + search for that object and then recursively search inside only that object. + + + + + diff --git a/isis/src/base/apps/getkey/tsts/Makefile b/isis/src/base/apps/getkey/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/getkey/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/getkey/tsts/baseKeyword/Makefile b/isis/src/base/apps/getkey/tsts/baseKeyword/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c19b15da1bd2cf5bfcee782f3acd86d6df8b8d99 --- /dev/null +++ b/isis/src/base/apps/getkey/tsts/baseKeyword/Makefile @@ -0,0 +1,8 @@ +APPNAME = getkey + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + grpname=pixels \ + keyword=base > $(OUTPUT)/standardOutTruth2.txt; diff --git a/isis/src/base/apps/getkey/tsts/dimKeyword/Makefile b/isis/src/base/apps/getkey/tsts/dimKeyword/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b1ec6a5f01330a254eeb51888b4d028091a8539c --- /dev/null +++ b/isis/src/base/apps/getkey/tsts/dimKeyword/Makefile @@ -0,0 +1,8 @@ +APPNAME = getkey + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + grpname=Dimensions \ + keyword=Lines > $(OUTPUT)/standardOutTruth1.txt; diff --git a/isis/src/base/apps/getkey/tsts/objName/Makefile b/isis/src/base/apps/getkey/tsts/objName/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..85f9c8e15ebed52a0e86202c476409527eacc9a7 --- /dev/null +++ b/isis/src/base/apps/getkey/tsts/objName/Makefile @@ -0,0 +1,8 @@ +APPNAME = getkey + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + objname=core upper=true \ + keyword=format > $(OUTPUT)/standardOutTruth3.txt; diff --git a/isis/src/base/apps/getkey/tsts/recursiveKeyword/Makefile b/isis/src/base/apps/getkey/tsts/recursiveKeyword/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8185d9ca9980d0e068a6e18f8cf40b161505d7cf --- /dev/null +++ b/isis/src/base/apps/getkey/tsts/recursiveKeyword/Makefile @@ -0,0 +1,8 @@ +APPNAME = getkey + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + keyword=Lines recursive=true\ + > $(OUTPUT)/standardOutTruth4.txt; diff --git a/isis/src/base/apps/getsn/Makefile b/isis/src/base/apps/getsn/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/getsn/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/getsn/getsn.cpp b/isis/src/base/apps/getsn/getsn.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed514e477650098c348bce7ee7e5d684775d6906 --- /dev/null +++ b/isis/src/base/apps/getsn/getsn.cpp @@ -0,0 +1,65 @@ +#include "Isis.h" + +#include +#include +#include + +#include "Pvl.h" +#include "Cube.h" +#include "Blob.h" +#include "History.h" +#include "SerialNumber.h" +#include "SessionLog.h" +#include "ObservationNumber.h" +#include "Preference.h" + +using namespace Isis; +using namespace std; + +void IsisMain() { + // Set Preferences to always turn off Terminal Output + PvlGroup &grp = Isis::Preference::Preferences().FindGroup("SessionLog", Isis::Pvl::Traverse); + grp["TerminalOutput"].SetValue("Off"); + + // Open the input cube + UserInterface &ui = Application::GetUserInterface(); + Cube cube; + string from = ui.GetFilename("FROM"); + cube.Open(from, "r"); + + // Determine if output should be written base on parameters + bool WriteFile = ui.GetBoolean("FILE"); + bool WriteSN = ui.GetBoolean("SN"); + bool WriteObservation = ui.GetBoolean("OBSERVATION"); + + // Extract label from cube file + Pvl *label = cube.Label(); + + PvlGroup sn("Results"); + + if(WriteFile) sn += PvlKeyword("Filename",from); + if(WriteSN) sn += PvlKeyword("SerialNumber",SerialNumber::Compose(*label,ui.GetBoolean("DEFAULT"))); + if(WriteObservation) sn += PvlKeyword("ObservationNumber",ObservationNumber::Compose(*label,ui.GetBoolean("DEFAULT"))); + + if(ui.WasEntered("TO")) { + // Create a serial number and observation number for this cube & put it in a pvlgroup for output + Pvl pvl; + pvl.AddGroup( sn ); + if( ui.GetBoolean("APPEND") ) + pvl.Append( ui.GetFilename("TO") ); + else + pvl.Write( ui.GetFilename("TO") ); + + // Construct a label with the results + if (ui.IsInteractive()) { + Application::GuiLog(sn); + } + } + else { + if(WriteFile) cout << from << endl; + if(WriteSN) cout << SerialNumber::Compose(*label,ui.GetBoolean("DEFAULT")) << endl; + if(WriteObservation) cout << ObservationNumber::Compose(*label,ui.GetBoolean("DEFAULT")) << endl; + } + // Write the results to the log but not the terminal + SessionLog::TheLog().AddResults(sn); +} diff --git a/isis/src/base/apps/getsn/getsn.xml b/isis/src/base/apps/getsn/getsn.xml new file mode 100644 index 0000000000000000000000000000000000000000..39052c118677c3fd10dcc8f565ed6e3c4bd50687 --- /dev/null +++ b/isis/src/base/apps/getsn/getsn.xml @@ -0,0 +1,140 @@ + + + + Prints Image Serial Number + + + This program will print the serial number for an image. + + + + Control Networks + + + + + Original version + + + Fixed up, finished documentation and checked in + + + Changed category from Utility to Control Networks + + + Added application test: default + + + Augmented observation number and added TO file with APPEND option + + + Added booleans for which keywords to get. If TO parameter is not entered + output will go to console. Added results group to SessionLog and GuiLog + (if applicable) + + + The print.prt file will now properly contain the results when getsn is run from + the command line; before the results group was always empty. The "TerminalOutput" user + preference no longer affects the output of this program. The default values of "FILE" and + "OBSERVATION" have been changed to FALSE. + + + + + + + + cube + input + + Cube file to get the serial number for + + + The cube file containing the label the serial number is to be created for. + + + *.cub + + + + filename + output + + The text to append result Pvl + + + No Output file will be created + + + The text file in which the Result Pvl created is either appended or + written to. + + + *.txt *.prt *.pvl + + + + boolean + TRUE + Appends results on output file + + Appends the created Results Pvl to the TO parameter output file. If + this is set to false, then it write the results to the output file + instead. + + + + + + + boolean + FALSE + Allows serial number to default to the file name + + Within the Result Pvl, if the serial number is not know, then Unknown + is displayed in the keyword SerialNumber. If this parameter is set to + TRUE, then is displays the input cube's filename is displayed in the + keyword SerialNumber instead. + + + + + + + boolean + False + + Get the Filename + + + If this boolean is not checked then the filename will not be part of + the output. + + + + boolean + True + + Get the Serial Number + + + If this boolean is not checked then the Serial Number will not be + part of the output. + + + + boolean + False + + Get the Observation Number + + + If this boolean is not checked then the Observation Number will not + be part of the output. + + + + + + + diff --git a/isis/src/base/apps/getsn/tsts/ConsoleOutput/Makefile b/isis/src/base/apps/getsn/tsts/ConsoleOutput/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ca18c6c526b0b02469a51325d4a3895c307687bc --- /dev/null +++ b/isis/src/base/apps/getsn/tsts/ConsoleOutput/Makefile @@ -0,0 +1,13 @@ +APPNAME = getsn + +peaks.txt.IGNORELINES = Filename +hirise.txt.IGNORELINES = Filename + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/peaks.cub \ + FILE=false OBSERVATION=false \ + >& $(OUTPUT)/peaks.txt; + $(APPNAME) FROM=$(INPUT)/hirise.cub \ + FILE=FALSE OBSERVATION=TRUE >& $(OUTPUT)/hirise.txt; diff --git a/isis/src/base/apps/getsn/tsts/Makefile b/isis/src/base/apps/getsn/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/getsn/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/getsn/tsts/default/Makefile b/isis/src/base/apps/getsn/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2e1fec900297176c9654b7c3329c5aeaff40188d --- /dev/null +++ b/isis/src/base/apps/getsn/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME = getsn + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/peaks.cub \ + TO=$(OUTPUT)/peaks.pvl FILE=TRUE OBSERVATION=TRUE \ + APPEND=false; + $(APPNAME) FROM=$(INPUT)/hirise.cub \ + TO= $(OUTPUT)/hirise.pvl FILE=TRUE OBSERVATION=TRUE \ + APPEND=false; diff --git a/isis/src/base/apps/gradient/Makefile b/isis/src/base/apps/gradient/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/gradient/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/gradient/assets/images/peaks.jpg b/isis/src/base/apps/gradient/assets/images/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..b4eb82b1a0db7623e1601de6e7332b4c1e276a21 Binary files /dev/null and b/isis/src/base/apps/gradient/assets/images/peaks.jpg differ diff --git a/isis/src/base/apps/gradient/assets/images/roberts.jpg b/isis/src/base/apps/gradient/assets/images/roberts.jpg new file mode 100755 index 0000000000000000000000000000000000000000..1687f369a41dd48201f0fae014160b5ba02103e1 Binary files /dev/null and b/isis/src/base/apps/gradient/assets/images/roberts.jpg differ diff --git a/isis/src/base/apps/gradient/assets/images/robertsGui.jpg b/isis/src/base/apps/gradient/assets/images/robertsGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..6f2f1491536aa20e71034c5ab12d43c9c9b880fc Binary files /dev/null and b/isis/src/base/apps/gradient/assets/images/robertsGui.jpg differ diff --git a/isis/src/base/apps/gradient/assets/images/sobel.jpg b/isis/src/base/apps/gradient/assets/images/sobel.jpg new file mode 100755 index 0000000000000000000000000000000000000000..2d7da0971a7f69ac671df5764b7e8d0baaceabde Binary files /dev/null and b/isis/src/base/apps/gradient/assets/images/sobel.jpg differ diff --git a/isis/src/base/apps/gradient/assets/images/sobelGui.jpg b/isis/src/base/apps/gradient/assets/images/sobelGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..69a39ffc40b8d3ea97e5e26033fc302ba272ff2a Binary files /dev/null and b/isis/src/base/apps/gradient/assets/images/sobelGui.jpg differ diff --git a/isis/src/base/apps/gradient/assets/thumbs/peaks.jpg b/isis/src/base/apps/gradient/assets/thumbs/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..292bd8e82e2690a41f4032744f0c18796e5bb639 Binary files /dev/null and b/isis/src/base/apps/gradient/assets/thumbs/peaks.jpg differ diff --git a/isis/src/base/apps/gradient/assets/thumbs/roberts.jpg b/isis/src/base/apps/gradient/assets/thumbs/roberts.jpg new file mode 100755 index 0000000000000000000000000000000000000000..5e5933e9e31499dcff398e7c9c6d8bc51fa1b3cf Binary files /dev/null and b/isis/src/base/apps/gradient/assets/thumbs/roberts.jpg differ diff --git a/isis/src/base/apps/gradient/assets/thumbs/robertsGui.jpg b/isis/src/base/apps/gradient/assets/thumbs/robertsGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..5a1153a6ba79949cfd50a6f6896c7582a3e1ad14 Binary files /dev/null and b/isis/src/base/apps/gradient/assets/thumbs/robertsGui.jpg differ diff --git a/isis/src/base/apps/gradient/assets/thumbs/sobel.jpg b/isis/src/base/apps/gradient/assets/thumbs/sobel.jpg new file mode 100755 index 0000000000000000000000000000000000000000..45dbb1b7a27beaabfe24851289ce404c4c2afc7c Binary files /dev/null and b/isis/src/base/apps/gradient/assets/thumbs/sobel.jpg differ diff --git a/isis/src/base/apps/gradient/assets/thumbs/sobelGui.jpg b/isis/src/base/apps/gradient/assets/thumbs/sobelGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..e5affc62f4a9e937eaffc97b0111b1226a2a1f94 Binary files /dev/null and b/isis/src/base/apps/gradient/assets/thumbs/sobelGui.jpg differ diff --git a/isis/src/base/apps/gradient/gradient.cpp b/isis/src/base/apps/gradient/gradient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38bbe118669b02f3ac05534bfddee60c1e95aa2b --- /dev/null +++ b/isis/src/base/apps/gradient/gradient.cpp @@ -0,0 +1,72 @@ +#include "Isis.h" +#include "ProcessByBoxcar.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void robertGradient (Buffer &in, double &v); +void sobelGradient (Buffer &in, double &v); + +void IsisMain() { + + ProcessByBoxcar p; + + UserInterface &ui = Application::GetUserInterface(); + + // Open the input cube + p.SetInputCube ("FROM"); + + // Allocate the output cube + p.SetOutputCube ("TO"); + + // Which gradient? + string gradType = ui.GetString ("GRADTYPE"); + // Set boxcar size depending on the gradient type + if (gradType == "SOBEL") { + p.SetBoxcarSize (3,3); + p.StartProcess (sobelGradient); + } + else if (gradType == "ROBERTS") { + p.SetBoxcarSize (2,2); + p.StartProcess (robertGradient); + } + + p.EndProcess (); + +} + +// Sobel gradient filter +void sobelGradient (Buffer &in,double &v) { + + bool specials = false; + for (int i=0; i + + + + + Apply Sobel or Roberts gradient to a cube + + + + This program will apply a Sobel or Roberts gradient filter to a cube. + These gradient filters will highlight edges of the image. The output + contains the estimated, absolute magnitude of the spatial gradient of the + input cube. + NOTE: Any time a calculation must be done where one or more values are + special pixels, the output will simply be NULL. If this causes unexpected + results, you may need to run stretch to change input special pixels to + something that is appropriate for calculation. For example, if the image + contains a number of HIS values, you may want to stretch these to 255 + prior to running the gradient filter. + + + + + Original version + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Added examples + + + Modified to handle Special Pixels + + + + + Filters + + + + + + cube + input + + Input cube + + + Use this parameter to select the filename. All bands within the file + will have the gradient applied. + + + *.cub + + + + + cube + output + real + + Output cube + + + This file will contain the estimated absolute magnitude of the + gradient. + + + + + + + string + Type of gradient (Sobel, Roberts) + + SOBEL + + + This chooses the gradient type. The possibilities + are: Sobel which uses a 3 x 3 kernal or Roberts which uses a + 2 x 2 kernel. + + + + + + + + + + + + + Applying a sobel filter + + + The use of the Sobel gradient here creates an output image which helps + to highlight the edges. + + + + from= peaks.cub + to=sobelPeaks.cub + gradtype=sobel + + + This example shows the use of the sobel filter in order to highlight + edges + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to filter using a sobel + configuration + + + + + + + + + + Input image before the filter. + + + This is the image as it was taken originally. + + + FROM + + + + + + + Output image after the gradient was applied + + + As you can see, sharp edges on the image have been emphasized, while + areas of more constant DNs have been de-emphasized. + + + TO + + + + + + Applying a roberts filter + + + + + + + from= peaks.cub + to=robertsPeaks.cub + gradtype=roberts + + + This example shows the use of the roberts filter in order to highlight + edges + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to filter using a roberts + gradient + + + + + + + + + + Input image before the filter. + + + This is the image as it was taken originally. + + + FROM + + + + + + + Output image after the roberts gradient + + + The use of the Roberts gradient here creates an output image which + helps to highlight the edges. Since the Roberts filter uses a smaller + boxcar, less of the image is taken into consideration at each processing + step and thus the image can be created faster. The tradeoff is that images + that have had the Roberts gradient applied tend be effected more by noise + in the image. + + + TO + + + + + + diff --git a/isis/src/base/apps/gradient/tsts/Makefile b/isis/src/base/apps/gradient/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/gradient/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/gradient/tsts/roberts/Makefile b/isis/src/base/apps/gradient/tsts/roberts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..dfb1511aa2db3e8a575866883d7a6542f1d6785b --- /dev/null +++ b/isis/src/base/apps/gradient/tsts/roberts/Makefile @@ -0,0 +1,8 @@ +APPNAME = gradient + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/gradTruth2.cub \ + gradType=Roberts > /dev/null; diff --git a/isis/src/base/apps/gradient/tsts/sobel/Makefile b/isis/src/base/apps/gradient/tsts/sobel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..04b04f3f0984ad97eedde50c9db4690033f1d2cb --- /dev/null +++ b/isis/src/base/apps/gradient/tsts/sobel/Makefile @@ -0,0 +1,8 @@ +APPNAME = gradient + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/gradTruth1.cub \ + gradType=Sobel > /dev/null; diff --git a/isis/src/base/apps/greyscale/Makefile b/isis/src/base/apps/greyscale/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/greyscale/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/greyscale/assets/images/greyscaleGuiEx1.jpg b/isis/src/base/apps/greyscale/assets/images/greyscaleGuiEx1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1cb375bc6f2300e58198fe8615727da0c2abcad3 Binary files /dev/null and b/isis/src/base/apps/greyscale/assets/images/greyscaleGuiEx1.jpg differ diff --git a/isis/src/base/apps/greyscale/assets/images/greyscaleGuiEx2.jpg b/isis/src/base/apps/greyscale/assets/images/greyscaleGuiEx2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..007030db01e99090e4658fc04bf73586aaa5b78c Binary files /dev/null and b/isis/src/base/apps/greyscale/assets/images/greyscaleGuiEx2.jpg differ diff --git a/isis/src/base/apps/greyscale/assets/images/greyscaleOutputEx1.jpg b/isis/src/base/apps/greyscale/assets/images/greyscaleOutputEx1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1ce799b17954586189800429de85d3f203422c29 Binary files /dev/null and b/isis/src/base/apps/greyscale/assets/images/greyscaleOutputEx1.jpg differ diff --git a/isis/src/base/apps/greyscale/assets/images/greyscaleOutputEx2.jpg b/isis/src/base/apps/greyscale/assets/images/greyscaleOutputEx2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a8b2cc865bdc996f59ced658761f4e0f475b5b6 Binary files /dev/null and b/isis/src/base/apps/greyscale/assets/images/greyscaleOutputEx2.jpg differ diff --git a/isis/src/base/apps/greyscale/assets/thumbs/greyscaleGuiEx1Thumb.jpg b/isis/src/base/apps/greyscale/assets/thumbs/greyscaleGuiEx1Thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7bdf8e531ac3ec082b36eb3e65540392bf67cd40 Binary files /dev/null and b/isis/src/base/apps/greyscale/assets/thumbs/greyscaleGuiEx1Thumb.jpg differ diff --git a/isis/src/base/apps/greyscale/assets/thumbs/greyscaleGuiEx2Thumb.jpg b/isis/src/base/apps/greyscale/assets/thumbs/greyscaleGuiEx2Thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c563728622852f19d0937c03e6a96044ec5c1398 Binary files /dev/null and b/isis/src/base/apps/greyscale/assets/thumbs/greyscaleGuiEx2Thumb.jpg differ diff --git a/isis/src/base/apps/greyscale/assets/thumbs/greyscaleOutputEx1Thumb.jpg b/isis/src/base/apps/greyscale/assets/thumbs/greyscaleOutputEx1Thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3abd5b375315debb3238333c4103745b5b94195c Binary files /dev/null and b/isis/src/base/apps/greyscale/assets/thumbs/greyscaleOutputEx1Thumb.jpg differ diff --git a/isis/src/base/apps/greyscale/assets/thumbs/greyscaleOutputEx2Thumb.jpg b/isis/src/base/apps/greyscale/assets/thumbs/greyscaleOutputEx2Thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..699bb7ecb889e7f7f6fa03b8fd918ff66b0be3c5 Binary files /dev/null and b/isis/src/base/apps/greyscale/assets/thumbs/greyscaleOutputEx2Thumb.jpg differ diff --git a/isis/src/base/apps/greyscale/greyscale.cpp b/isis/src/base/apps/greyscale/greyscale.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b3367ad887cd86515457a54d7678a706143100a --- /dev/null +++ b/isis/src/base/apps/greyscale/greyscale.cpp @@ -0,0 +1,69 @@ +#include "Isis.h" +#include "ProcessByBrick.h" +#include "ProcessByLine.h" +#include "ProcessBySample.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +// Glocal declarations +void GreyScale(Buffer &out); +double dn1; +double dn2; + +void IsisMain() { + // Create a process by line and ui objects + UserInterface &ui = Application::GetUserInterface(); + + // Get the values for the output cube + dn1 = ui.GetDouble("BEGINDN"); + dn2 = ui.GetDouble("ENDDN"); + + // Need to pick good min/maxs to ensure the user's value + // doesn't get saturated + CubeAttributeOutput &att = ui.GetOutputAttribute("TO"); + if (IsValidPixel(dn1) && IsValidPixel(dn2)) { + if (dn1 <= dn2) { + att.Minimum(dn1); + att.Maximum(dn2); + } + else { + att.Minimum(dn2); + att.Maximum(dn1); + } + } + else { + throw iException::Message(iException::User,"Must enter valid pixel DN values.", _FILEINFO_); + } + + // Get the size of the cube and create the cube + int samps = ui.GetInteger("SAMPLES"); + int lines = ui.GetInteger("LINES"); + + // Create a ProcessByBrick pointer + ProcessByBrick *p; + // Determine whether to process by line or by sample + if (ui.GetString("DIRECTION") == "HORIZONTAL") { + p = new ProcessByLine; + // we will only process 1 line at a time + p->SetBrickSize (samps,1,1); + } + else { + p = new ProcessBySample; + // we will only process 1 sample at a time + p->SetBrickSize (1,lines,1); + } + //Make the cube + p->SetOutputCube (ui.GetFilename("TO"),att,samps,lines); + p->StartProcess(GreyScale); + p->EndProcess(); + +} + +void GreyScale (Buffer &out) { + int size = out.size(); + for (int i=0; i + + Generate a grey scale cube + + + This program can be used to generate an output cube of user specified + dimensions. The pixel values of each line or sample evenly increment or + decrement from value1 input to value2 input. + Note: Vertical scaling can take twice as long to process, + however this is insignificant for output images less than 10,000 + lines/samples. + + + + Utility + + + + + Original version with examples. + + + + + + + cube + output + real + Output cube + + The file name of the output cube to be created. + + *.cub + + + + + string + + Direction of the grey scaling of given DN values. + + + The direction options allow the user to choose whether to scale the + pixel values horizontally or vertically. + + + HORIZONTAL + + + + + + + + double + + 0.0 + + DN Value of each beginning pixel + + This is the user specified DN value to output to the first pixel of + each line (or row) if scaling horizontally or the first pixel of each + sample (or column) if scaling vertically. + + + + double + + 0.0 + + DN Value of each end pixel + + This is the user specified DN value to output to the last pixel of + each line (or row) if scaling horizontally or the last pixel of each + sample (or column) if scaling vertically. + + + + + + integer + + 1 + + Number of samples in the cube + + The number of samples to be allocated in the output cube. This + integer value must be at least 1. + + 1 + + + integer + + 1 + + Number of line in the cube + + The number of lines to be allocated in the ouput cube. This integer + value must be at least 1. + + 1 + + + + + + + Create horizontally grey scaled cube. + + This example demonstrates how to use greyscale to + create a cube with pixel values from BEGINDN to ENDDN horizontally. + + + + to=../OUT/output.cub direction=horizontal begindn=1 enddn=25 samples=49 + lines=20 + + + Run greyscale to create a cube with the given + parameters. + + + + + + Example GUI + + Screenshot of GUI with parameters filled in to perform + greyscale application. DIRECTION + parameter HORIZONTAL is chosen as default. + + + + + + + + Output cube + + This is an example of the the output image with the given + parameters. It is a 20 line by 49 sample cube with the first + samples of each line equal to 1. Subsequent samples increment by + 0.5 until the last sample, which is equal to 25. + + + + TO + + + + + + Create vertically grey scaled cube. + + This example demonstrates how to use greyscale to + create a cube with pixel values from BEGINDN to ENDDN vertically. + + + + to=../OUT/output.cub direction=vertical begindn=50 enddn=25 samples=20 + lines=49 + + + Run greyscale to create a cube with the given + parameters. + + + + + + Example GUI + + Screenshot of GUI with parameters filled in to perform + greyscale application. + + + + + + + + Output cube + + This is an example of the the output image with the given + parameters. It is a 49 line by 20 sample cube with the a DN of 50 + for the pixels in the first line. Subsequent lines decrement by a + pixel value 0.5208 until the last line, which has a DN of 25. + + + + TO + + + + + + + diff --git a/isis/src/base/apps/greyscale/tsts/Makefile b/isis/src/base/apps/greyscale/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/greyscale/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/greyscale/tsts/horizontal/Makefile b/isis/src/base/apps/greyscale/tsts/horizontal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..466ec009c9d2e6997027a6090c08d32b0168c51d --- /dev/null +++ b/isis/src/base/apps/greyscale/tsts/horizontal/Makefile @@ -0,0 +1,11 @@ +APPNAME = greyscale + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) to=$(OUTPUT)/output.cub \ + begindn=0 \ + enddn=100 \ + samp=11 \ + lin=3 \ + > /dev/null; diff --git a/isis/src/base/apps/greyscale/tsts/vertical/Makefile b/isis/src/base/apps/greyscale/tsts/vertical/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8628175844731900d49bb8fc2e19e41c401f02a9 --- /dev/null +++ b/isis/src/base/apps/greyscale/tsts/vertical/Makefile @@ -0,0 +1,12 @@ +APPNAME = greyscale + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) to=$(OUTPUT)/output.cub \ + dir=vert \ + begindn=33 \ + enddn=7 \ + samp=6 \ + lin=15 \ + > /dev/null; diff --git a/isis/src/base/apps/grid/Makefile b/isis/src/base/apps/grid/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/grid/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/grid/grid.cpp b/isis/src/base/apps/grid/grid.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c8e2d34c8fa0ae7337901a7f3ae6f035c7a3e528 --- /dev/null +++ b/isis/src/base/apps/grid/grid.cpp @@ -0,0 +1,270 @@ +#include "Isis.h" + +#include + +#include "ProcessByLine.h" +#include "Projection.h" +#include "ProjectionFactory.h" +#include "Camera.h" +#include "CameraFactory.h" +#include "GroundGrid.h" +#include "UniversalGroundMap.h" + +using namespace std; +using namespace Isis; + +void imageGrid(Buffer &in, Buffer &out); +void groundGrid(Buffer &in, Buffer &out); + +void createGroundImage(Camera *cam, Projection *proj); + +bool outline, ticks, diagonalTicks; +int baseLine, baseSample, lineInc, sampleInc, tickSize; +double baseLat, baseLon, latInc, lonInc; + +int inputSamples, inputLines; +GroundGrid *latLonGrid; + +void IsisMain() { + latLonGrid = NULL; + + // We will be processing by line + ProcessByLine p; + Cube *icube = p.SetInputCube("FROM"); + + UserInterface &ui = Application::GetUserInterface(); + string mode = ui.GetString("MODE"); + + outline = ui.GetBoolean("OUTLINE"); + ticks = ui.GetBoolean("TICKS"); + + if(ticks) { + tickSize = ui.GetInteger("TICKSIZE") / 2; + diagonalTicks = ui.GetBoolean("DIAGONALTICKS"); + } + + inputSamples = icube->Samples(); + inputLines = icube->Lines(); + + // Line & sample based grid + if(mode == "IMAGE") { + p.SetOutputCube("TO"); + baseLine = ui.GetInteger("BASELINE"); + baseSample = ui.GetInteger("BASESAMPLE"); + lineInc = ui.GetInteger("LINC"); + sampleInc = ui.GetInteger("SINC"); + p.StartProcess(imageGrid); + p.EndProcess(); + } + // Lat/Lon based grid + else { + CubeAttributeOutput oatt("+32bit"); + p.SetOutputCube(ui.GetFilename("TO"), oatt, icube->Samples(), + icube->Lines(), icube->Bands()); + + baseLat = ui.GetDouble("BASELAT"); + baseLon = ui.GetDouble("BASELON"); + latInc = ui.GetDouble("LATINC"); + lonInc = ui.GetDouble("LONINC"); + + UniversalGroundMap *gmap = new UniversalGroundMap(*icube); + latLonGrid = new GroundGrid(gmap, ticks, icube->Samples(), icube->Lines()); + + Progress progress; + progress.SetText("Calculating Grid"); + + latLonGrid->CreateGrid(baseLat, baseLon, latInc, lonInc, &progress); + + p.StartProcess(groundGrid); + p.EndProcess(); + + delete latLonGrid; + latLonGrid = NULL; + + delete gmap; + gmap = NULL; + } +} + +bool imageDrawLine(int line) { + return (line % lineInc == baseLine % lineInc); +} + +bool imageDrawSample(int sample) { + return (sample % sampleInc == baseSample % sampleInc); +} + +// Line processing routine +void imageGrid(Buffer &in, Buffer &out) { + for(int samp = 1; samp <= in.size(); samp ++) { + out[samp - 1] = in[samp - 1]; + + if(!ticks) { + if(imageDrawSample(samp) || imageDrawLine(in.Line())) + out[samp - 1] = Isis::Hrs; + } + // ticks! + else { + // tickSize is the width or height divided by 2, so integer rounding + // takes care of the current sample/line while doing +/- tickSize + // creates the appropriate width and height. + + // Vertical/Horizontal Ticks + if(!diagonalTicks) { + // horizontal test + for(int sampleTest = samp - tickSize; + (sampleTest <= samp + tickSize) && (out[samp-1] != Isis::Hrs); + sampleTest ++) { + if(imageDrawLine(in.Line()) && imageDrawSample(sampleTest)) { + out[samp - 1] = Isis::Hrs; + } + } + + // vertical test + for(int lineTest = in.Line() - tickSize; + (lineTest <= in.Line() + tickSize) && (out[samp-1] != Isis::Hrs); + lineTest ++) { + if(imageDrawLine(lineTest) && imageDrawSample(samp)) { + out[samp-1] = Isis::Hrs; + } + } + } + // Diagonal Ticks + else { + // top left to bottom right + int sampleTest = samp - tickSize; + int lineTest = in.Line() - tickSize; + + while((out[samp-1] != Isis::Hrs) && + (lineTest <= in.Line() + tickSize) && + (sampleTest <= samp + tickSize)) { + if(imageDrawLine(lineTest) && imageDrawSample(sampleTest)) { + out[samp-1] = Isis::Hrs; + } + + sampleTest ++; + lineTest ++; + } + + // top right to bottom left + sampleTest = samp + tickSize; + lineTest = in.Line() - tickSize; + + while((out[samp-1] != Isis::Hrs) && + (lineTest <= in.Line() + tickSize) && + (sampleTest >= samp - tickSize)) { + if(imageDrawLine(lineTest) && imageDrawSample(sampleTest)) { + out[samp-1] = Isis::Hrs; + } + + sampleTest --; + lineTest ++; + } + } + } + } + + // draw outline + if(outline) { + if(in.Line() == 1 || in.Line() == inputLines) { + for(int i = 0; i < in.size(); i++) { + out[i] = Isis::Hrs; + } + } + else { + out[0] = Isis::Hrs; + out[out.size()-1] = Isis::Hrs; + } + } +} + +// Line processing routine +void groundGrid(Buffer &in, Buffer &out) { + for(int samp = 1; samp <= in.SampleDimension(); samp++) { + if(!ticks) { + if(latLonGrid->PixelOnGrid(samp - 1, in.Line() - 1)) { + out[samp-1] = Isis::Hrs; + } + else { + out[samp-1] = in[samp-1]; + } + } + else { + // We need to check the grids for overlaps near current point + out[samp-1] = in[samp-1]; + + // tickSize is the width or height divided by 2, so integer rounding + // takes care of the current sample/line while doing +/- tickSize + // creates the appropriate width and height. + + // Vertical/Horizontal Ticks + if(!diagonalTicks) { + // horizontal test + for(int sampleTest = samp - 1 - tickSize; + (sampleTest < samp + tickSize) && (out[samp-1] != Isis::Hrs); + sampleTest ++) { + if(latLonGrid->PixelOnGrid(sampleTest, in.Line() - 1, true) && + latLonGrid->PixelOnGrid(sampleTest, in.Line() - 1, false)) { + out[samp-1] = Isis::Hrs; + } + } + + // vertical test + for(int lineTest = in.Line() - 1 - tickSize; + (lineTest < in.Line() + tickSize) && (out[samp-1] != Isis::Hrs); + lineTest ++) { + if(latLonGrid->PixelOnGrid(samp - 1, lineTest, true) && + latLonGrid->PixelOnGrid(samp - 1, lineTest, false)) { + out[samp-1] = Isis::Hrs; + } + } + } + // Diagonal ticks + else { + // top left to bottom right + int sampleTest = samp - 1 - tickSize; + int lineTest = in.Line() - 1 - tickSize; + + + while((out[samp-1] != Isis::Hrs) && (lineTest < in.Line() + tickSize) && + (sampleTest < samp + tickSize)) { + if(latLonGrid->PixelOnGrid(sampleTest, lineTest, true) && + latLonGrid->PixelOnGrid(sampleTest, lineTest, false)) { + out[samp-1] = Isis::Hrs; + } + + sampleTest ++; + lineTest ++; + } + + // top right to bottom left + sampleTest = samp - 1 + tickSize; + lineTest = in.Line() - 1 - tickSize; + + while((out[samp-1] != Isis::Hrs) && (lineTest < in.Line() + tickSize) && + (sampleTest >= samp - 1 - tickSize)) { + if(latLonGrid->PixelOnGrid(sampleTest, lineTest, true) && + latLonGrid->PixelOnGrid(sampleTest, lineTest, false)) { + out[samp-1] = Isis::Hrs; + } + + sampleTest --; + lineTest ++; + } + } + } + } + + // draw outline + if(outline) { + if(in.Line() == 1 || in.Line() == inputLines) { + for(int i = 0; i < in.size(); i++) { + out[i] = Isis::Hrs; + } + } + else { + out[0] = Isis::Hrs; + out[out.size()-1] = Isis::Hrs; + } + } +} diff --git a/isis/src/base/apps/grid/grid.xml b/isis/src/base/apps/grid/grid.xml new file mode 100644 index 0000000000000000000000000000000000000000..d0f66cce11317cfef1d7e7c9beeab6b2062c0ecf --- /dev/null +++ b/isis/src/base/apps/grid/grid.xml @@ -0,0 +1,257 @@ + + + + + Add a grid to the input image. + + + + Superimpose a grid on an input image using input from the user. The grid can + defined in terms of latitude and longitude, or simply lines and samples. For + example, if you wanted to draw a grid that has an intersection at line 23, + sample 17, with vertical lines every 30 pixels and horizontal lines every + 40 pixels, your parameters would be: BASELINE = 23, BASESAMPLE = 17, + SINC = 30, and LINC = 40.



    + If you wanted to draw a grid on a map projection that was based on latitude + and longitude, GROUND would be selected instead. And suppose you wanted the + grid to have an intersection at LAT 50, LON 60, with lines drawn every two + and a half degrees latitude and every three degrees longitude. Your parameters + would be: BASELAT = 50, BASELON = 60, LATINC = 2.5, and LONINC = 3. +
    + + + Utility + Map Projection + + + + + Original version + + + Added category: Map Projection + + + Fixed problems with mapping outside of the projection space and with 0lat/0lon boundaries. + + + Removed references to CubeInfo + + + Added outline option + + + Changed how mode=ground works + + + Added TICKS options + + + + + + + cube + input + + Input cube + + + Use this parameter to select the input file. + + + *.cub + + + + cube + output + + Output cube + + + This file will contain the grid. + + + *.cub + + + + + + + string + IMAGE + Grid options + + This allows the user to decide which grid option to use. + + + + + + + + + + boolean + false + Draw ticks instead of lines + + Draw ticks at lat, lon line intersections instead of lines + + + DIAGONALTICKS + TICKSIZE + + + + + boolean + false + Outline the image + + This will draw grid lines at the very edges of the image + + + + + + + integer + 1 + Starting line + + Starting line of grid. This, along with BASESAMPLE will give the + program a starting point to draw the grid with. + + 1 + + + + integer + 1 + Starting sample + + Starting sample of grid. This, along with BASELINE will give the + program a starting point to draw the grid with. + + 1 + + + + integer + 100 + Line increment + + This defines the number of lines between gridlines + + 1 + + + + integer + 100 + Sample increment + + This defines the number of samples between gridlines + + 1 + + + + + + double + 0.0 + Starting latitude + + This is a latitude line the grid will lie on. If it is not in the image, + then it is a latitude line the grid would lie on if the image were larger. + This is not a minimum latitude for the grid. + + -90.0 + + + + double + 0.0 + Starting longitude + + This is a longitude line the grid will lie on. If it is not in the image, + then it is a longitude line the grid would lie on if the image were larger. + This is not a minimum longitude for the grid. + + -360.0 + + + + double + 1.0 + Latitude increment + + This defines the latitudinal spacing between gridlines + + 0.0 + + + + double + 1.0 + Longitude increment + + This defines the longitudinal spacing between gridlines + + 0.0 + + + + + + boolean + false + Draw tick marks diagonally + + Instead of drawing the tick marks vertically and horizonally, creating a '+', + draw the tick marks diagonally creating an 'x' + + + + + integer + 5 + Size of tickmarks + + This defines the width and height (which are always equal) of the tick marks in pixels. + + 1 + + + + + +
    diff --git a/isis/src/base/apps/grid/tsts/Makefile b/isis/src/base/apps/grid/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/grid/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/grid/tsts/ground/Makefile b/isis/src/base/apps/grid/tsts/ground/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d9ddfe7d9236158c5e65a1bc882f337737bdd445 --- /dev/null +++ b/isis/src/base/apps/grid/tsts/ground/Makefile @@ -0,0 +1,14 @@ +APPNAME = grid + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.map.cub \ + to=$(OUTPUT)/groundTruth1.cub \ + mode=ground > /dev/null; + $(APPNAME) from=$(INPUT)/ab102401.map.cub \ + to=$(OUTPUT)/groundTruth2.cub \ + mode=ground ticks=true > /dev/null; + $(APPNAME) from=$(INPUT)/ab102401.map.cub \ + to=$(OUTPUT)/groundTruth3.cub \ + mode=ground ticks=true diagonal=true > /dev/null; diff --git a/isis/src/base/apps/grid/tsts/image/Makefile b/isis/src/base/apps/grid/tsts/image/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1d45a2dd2d9565d1ce06584ca137557435e3aef3 --- /dev/null +++ b/isis/src/base/apps/grid/tsts/image/Makefile @@ -0,0 +1,11 @@ +APPNAME = grid + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/peaks.cub \ + to=$(OUTPUT)/imageTruth1.cub > /dev/null; + $(APPNAME) from=$(INPUT)/peaks.cub ticks=yes \ + to=$(OUTPUT)/imageTruth2.cub > /dev/null; + $(APPNAME) from=$(INPUT)/peaks.cub ticks=yes diagonal=yes \ + to=$(OUTPUT)/imageTruth3.cub > /dev/null; diff --git a/isis/src/base/apps/grid/tsts/world/Makefile b/isis/src/base/apps/grid/tsts/world/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8a6758a5ecc08ab24f4aa7b4d09f66a8a896cf81 --- /dev/null +++ b/isis/src/base/apps/grid/tsts/world/Makefile @@ -0,0 +1,11 @@ +APPNAME = grid + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/world.cub TO=$(OUTPUT)/truth1.cub \ + LATINC=45 LONINC=45 MODE=GROUND > /dev/null; + $(APPNAME) FROM=$(INPUT)/world.cub TO=$(OUTPUT)/truth2.cub \ + LATINC=45 LONINC=45 MODE=GROUND ticks=true > /dev/null; + $(APPNAME) FROM=$(INPUT)/world.cub TO=$(OUTPUT)/truth3.cub \ + LATINC=45 LONINC=45 MODE=GROUND ticks=true diagonal=true > /dev/null; diff --git a/isis/src/base/apps/handmos/Makefile b/isis/src/base/apps/handmos/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/handmos/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/handmos/assets/Band.jpg b/isis/src/base/apps/handmos/assets/Band.jpg new file mode 100644 index 0000000000000000000000000000000000000000..00da9784ff43cdb28283db1c7333e7cb2e505e78 Binary files /dev/null and b/isis/src/base/apps/handmos/assets/Band.jpg differ diff --git a/isis/src/base/apps/handmos/assets/Beneath.jpg b/isis/src/base/apps/handmos/assets/Beneath.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db11367d8666e07383f180238c34c75cfaf01705 Binary files /dev/null and b/isis/src/base/apps/handmos/assets/Beneath.jpg differ diff --git a/isis/src/base/apps/handmos/assets/OnTop.jpg b/isis/src/base/apps/handmos/assets/OnTop.jpg new file mode 100644 index 0000000000000000000000000000000000000000..24546949941162d28d3e241b39c88cecacc843d6 Binary files /dev/null and b/isis/src/base/apps/handmos/assets/OnTop.jpg differ diff --git a/isis/src/base/apps/handmos/handmos.cpp b/isis/src/base/apps/handmos/handmos.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c81c774fb06dcfe77bf59d15dc8349bdce4ec17a --- /dev/null +++ b/isis/src/base/apps/handmos/handmos.cpp @@ -0,0 +1,142 @@ +#include "Isis.h" +#include "ProcessMosaic.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void CreateMosaic (Buffer &buf); + +/** + * Handmos Application- Allows to hand place an image on the + * mosaic with input, mosaic and band priorities. Band priority allows the + * user the option to place a pixel on the mosaic based on the pixel in the + * chosen band. The band can be specified by band number or Keyword as it + * appears in BandBin group of the PVL label. Also has the ability to track the + * origin by adding a band to mosaic at the time of creation. As input images + * are placed on the mosaic, the are stored as records in the table "InputImages" + * in the mosaic. Ability to copy HS, LS, NULL values from input onto the mosaic. + * + */ +void IsisMain() { + // See if we need to create the output file + UserInterface &ui = Application::GetUserInterface(); + + int ns,nl,nb; + + ProcessMosaic p; + + bool bTrack = ui.GetBoolean("TRACK"); + p.SetTrackFlag(bTrack); + + if (ui.GetString("CREATE") == "YES") { + ns = ui.GetInteger("NSAMPLES"); + nl = ui.GetInteger("NLINES"); + nb = ui.GetInteger("NBANDS"); + + // Create the origin band if the Track Flag is set + if (bTrack) { + nb += 1; + } + p.SetCreateFlag(true); + + ProcessByLine bl; + + bl.Progress()->SetText("Initializing base mosaic"); + bl.SetInputCube("FROM"); + bl.SetOutputCube("MOSAIC",ns,nl,nb); + bl.ClearInputCubes(); + bl.StartProcess(CreateMosaic); + bl.EndProcess(); + } + + // Set the input cube for the process object + p.SetBandBinMatch(ui.GetBoolean("MATCHBANDBIN")); + p.Progress()->SetText("Mosaicking"); + + // Set up the mosaic priority, either the input cube will be + // placed ontop of the mosaic or beneath it + ui = Application::GetUserInterface(); + MosaicPriority priority; + string sType; + if (ui.GetString("PRIORITY") == "BENEATH") { + priority = mosaic; + } + else if (ui.GetString("PRIORITY") == "ONTOP") { + priority = input; + } + else { + priority = band; + sType = ui.GetString("TYPE"); + if (sType=="BANDNUMBER") { + p.SetBandNumber(ui.GetInteger("NUMBER")); + } + else { + //keyname & key value + p.SetBandKeyWord(ui.GetString("KEYNAME"), ui.GetString("KEYVALUE")); + } + // Band Criteria + BandCriteria eCriteria = Lesser; + if (ui.GetString("CRITERIA") == "GREATER") + eCriteria = Greater; + p.SetBandCriteria(eCriteria); + } + + //set priority + p.SetPriority(priority); + + // Get the value for HS, LS, NULL flags whether to transfer the special pixels + // onto the mosaic. Holds good for "ontop" and "band" priorities only + if (priority == input || priority == band) { + p.SetHighSaturationFlag(ui.GetBoolean("HIGHSATURATION")); + p.SetLowSaturationFlag (ui.GetBoolean("LOWSATURATION")); + p.SetNullFlag(ui.GetBoolean("NULL")); + } + + // Get the starting line/sample/band to place the input cube + int outSample = ui.GetInteger ("OUTSAMPLE") - ui.GetInteger ("INSAMPLE") + 1; + int outLine = ui.GetInteger ("OUTLINE") - ui.GetInteger ("INLINE") + 1; + int outBand = ui.GetInteger ("OUTBAND") - ui.GetInteger ("INBAND") + 1; + + // Set the input mosaic + p.SetInputCube ("FROM"); + + // Set the output mosaic + Cube* to = p.SetOutputCube ("MOSAIC"); + + p.WriteHistory(*to); + + // Place the input in the mosaic + //p.StartProcess(outSample, outLine, outBand, priority); + p.StartProcess(outSample, outLine, outBand); + + if (bTrack != p.GetTrackFlag()) { + ui.Clear("TRACK"); + ui.PutBoolean("TRACK", p.GetTrackFlag()); + } + p.EndProcess(); + + // Log the changes to NBANDS and to TRACK if any + PvlObject hist = Isis::iApp->History(); + Isis::iApp->Log(hist.FindGroup("UserParameters")); + PvlGroup imgPosition("ImageLocation"); + int iStartLine = p.GetInputStartLine(); + int iStartSample = p.GetInputStartSample(); + imgPosition += PvlKeyword("File", ui.GetFilename("FROM")); + imgPosition += PvlKeyword("StartSample", iStartSample); + imgPosition += PvlKeyword("StartLine", iStartLine); + Application::Log(imgPosition); +} +/** + * Initialize the mosaic to defaults + * + * @author sprasad (10/14/2009) + * + * @param buf + */ +void CreateMosaic (Buffer &buf) { + for (int i=0; i + + + + Hand place a cube into a mosaic + + + Mosaicking + + + +

    This application allows the user to specify a (sample,line,band) position + in a mosaic and places an input cube at that position. If a portion of + the input cube falls outside of the dimension of the mosaic, it will be + clipped. The line, sample, band size of the mosaic can be set at the time + of creation. This application regardless of any priority and flags set, + will always place an input pixel on a NULL mosaic pixel. This application + also has the ability to track the pixel origin. +

    +

    Tracking can be set at the time of Mosaic creation + only and cannot be turned on after the mosaic is created. But the tracking + will be turned off for multiband ONTOP and BENEATH priority even though it + was turned on while creating the mosaic. Tracking for multiband input with + ONTOP priority is possible only if all the Special Pixel Flags are set to + True else the Tracking will be turned off. ONTOP priority basically places + all the valid input pixels onto the mosaic unless the special pixel flags + are turned on or if mosaic has a NULL pixel. In a multi band scenario, a + pixel origin in particular line and sample will not be the same in all the + different bands, which means we have to keep track of every pixel in every + band. i.e. the size of the tracking bands will be the same as the number + of bands in the mosaic.i.e the number of bands will be doubled.

    +

    + WARNING: If Tracking is turned on in a mosaic, any subsequent + applications that modify "dn" values will corrupt + the Tracking band. It may be necessary to remove + the Tracking band from the mosaic and then add it + back after all the processing is complete. See + "crop" and "cubeit". +

    +

    Priority BAND can track origin for multi band input image based on a + specified band using LESSER or GREATER than criteria. Each pixel in the + specified band is compared to the corresponding pixel in the chosen band + in the mosaic based on the chosen criteria. This comparison true or false + is used for all the other bands whether the input pixel is copied onto the + mosaic and hence the origin for that pixel is stored. Band can be chosen + by choosing the TYPE, BANDNUMBER or KEYWORD. If BANDNUMBER is chosen then + the band number can be entered in the NUMBER field. If KEYWORD is chosen + then PVL key name and value from the BANDBIN group can be entered in the + KEYNAME and KEYVALUE fields.

    +

    For example, for a multi band input with BAND priority, if the BAND + chosen is Emission Angle band(EMA), if input pixels are (30,30,30) in + EMA Band for some sample, line and the corresponding pixels in the EMA + band in the mosaic has (75, 75, 75) and the criteria is GREATER than, + then since input pixels are not GREATER than corresponding mosaic + pixels, then the input pixels are not copied to the mosaic, so also the + corresponding pixels in all the other bands in the input. Hence the + origin for those pixels remains unchanged. If LESSER than was the + criteria, then all the corresponding pixels in all the input bands will + be copied to the mosaic and the origin for those pixels is the current + input image. +

    +

    There are options like MATCHBANDIN, if set requires the specfied input + bands to match the mosaic bands and the bands can be anywhere in the + mosaic but must be contiguous for multi-band. If MATCHBANDIN is not set + then any input image can be placed on the mosaic within it's boundaries. +

    +

    Options HIGHSATURATION, LOWSATURATION and NULL if + set will cause the the input pixels with these values to be copied to the + mosaic for ONTOP and BAND priorities regardless of the CRITERIA for the + BAND priority. These options are not supported for BENEATH priority.

    +

    Currently Tracking can be viewed in the Advanced Tool Tracking option + of the qview application. Following are the Tracking info:

    +

    Index : Zero based and is in the order in which the image was + placed on the mosaic. No origin is represented as -1.

    +

    FileName: File name of input image

    +

    Serial Number:Serial Number of the input image

    +

    Following are the values for the origin band depending on the pixel type + + + + + +
    Pixel Type

    (bits)
    Default

    (No Origin)
    Start ValueMax ValueTotal Images

    Supported
    32-16777216-167772151677721633549932
    16-32768-3276732767 65535
    801255255
    +

    +

    Following is the table for Special Pixel options, input, mosaic + pixels and the resulting output for different priorities. +
    Tags: F(FALSE), T(TRUE), V(VALID), HS(HIGH SATURATION), LS(LOW SATURATION), + S(SPECIAL PIXEL HS, LS, NULL), N(NULL), I(INPUT), M(MOSAIC), HL(HS,LS) +
    +

    +
  • + + + + +
    Priority Beneath
    Priority Beneath + + + + +
    BENEATH
    InputMosaic Output
    S,VNI
    S,VHL,VM






    +
  • + + + + +
    Priority OnTop
    Priority OnTop + + + + + + + + +
    ONTOP
    OptionsImages
    HSLSNULLInputMosaicOutput
    F F FVS,VI
    F F F S HL,VM
    F F F S,V N I
    T OR T OR TV S,VI
    T OR T OR TSS,VI (H,L,N)
    +





    +
  • + + + + +
    Priority Band
    Priority Band + + + + + + + + + + +
    BAND
    OptionsImages
    HSLSNULLInputMosaicOutput
    F FF VVCriteria based
    F F FVS I
    F F F S HL,VM
    F F FS,VNI
    T OR T OR T S S,V I(H,L,N)
    T OR T ORT VVCriteria based
    T OR T OR T V SI
    +
    + + + + + + Original version + + + Modified filename parameters to be cube parameters where necessary + + + Added option to intialize the base mosaic + + + Updated progress text and made output create use input cube attributes + + + Added the MATCHBANDBIN option that checks to make sure the input + cube bandbin group matches the mosaic bandbin group. The default is true. + + + Added history entry to the output cube + + + Expanded upon position parameters + + + Parameter "INPUT" now called "PRIORITY" to be consistent with the mapmos app + + + Added option "TRACK" to track pixel origin. Also added new priority called + BAND where specified input and mosaic band is compared for moving input + to mosaic and to track the pixel origin. Added parameter "TYPE" to choose + Band "NUMBER" or PVL "KEYWORD" from the BandBin group. If "BANDNUMBER" is + chosen, then "NUMBER" is activated to enter band number. If "KEYWORD" + is chosen then parameter "KEYNAME" and "KEYVALUE" are activated to enter + key name and value from the BandBin group for band comparison. Band + comparison "CRITERIA" are "LESSER" or "GREATER" than. Also there are + options "HIGHSATURATION", "LOWSATURATION" and "NULL", set to true will + cause HS, LS and NULL input pixels to be copied to the mosaic regardless + of the priorities and criteria. These options are not supported for "BENEATH" priority. + + + Always place an input pixel over a NULL mosaic pixel. + Track the origin for multiband ONTOP priority if all the Special Pixel flags are set. + Store the Serial numbers of the input mosaic in the mosaic along with the file name. + + + + + mosaic + + + + + + cube + input + + Cube to be placed in the mosaic + + + This is the cube which will be placed into the mosaic + + + *.cub + + + + + cube + output + + Mosaic output cube + + + The mosaic cube which will have the input cube placed + into it. This cube must exist. If you are creating a new + mosaic, you can utilize the "makecube" program to generate + the base mosaic. + + + *.cub + + + + + string + + ONTOP + + The priority of pixel placement + + This parameter is used to select one of three ways to mosaic the + pixels in areas of overlap. + + + + + + + + + + + + + string + + + BANDNUM + + + Indicate the Band name or number to be used for comparison + + The pixels in this band will be used for comparison between input + image and the mosaic for a decision to be made in copying image into + the mosaic. + + + + + + + + + integer + 1 + Enter the Band Number + The band number should match that in the + "OriginalBand" of "BandBin" Group + + + + string + OriginalBand + Enter the Key name as it appears in the PVL + The entered key name must match the key name in the + "BandBin" + + + + + string + 1 + Enter the value associated with the "KEYNAME" + This value must match the value associated with the key + name entered in the KEYNAME + + + + + string + LESSER + The criteria (Lesser or Greater) of pixel placement in a chosen band + + This parameter is used to select one of two ways to mosaic the + pixels in areas of overlap when doing by band comparison. + + + + + + + + + + + + integer + This sample in the input cube will be placed + at OUTSAMPLE in the mosaic. + + + This is a sample in the input image. This sample in the input cube will be placed at + OUTSAMPLE in the mosaic. + + 1 + + + + integer + This line in the input cube will be placed + at OUTLINE in the mosaic. + + + This is a line in the input image. This line in the input cube will be placed at + OUTLINE in the mosaic. + + 1 + + + + integer + This band in the input cube will be placed + at OUTBAND in the mosaic. + + + This is a band in the input image. This band in the input cube will be placed at + OUTBAND in the mosaic. + + 1 + + + + integer + The INSAMPLE sample will be placed at this sample in the mosaic + + This parameter is used to select the starting sample where + the input cube will be placed. The sample INSAMPLE will be placed at + this sample in the output mosaic. + + 1 + + + + integer + The INLINE line will be placed at this line in the mosaic + + This parameter is used to select the starting line where + the input cube will be placed. The line INLINE will be placed at + this line in the output mosaic. + + 1 + + + + integer + The INBAND band will be placed at this band in the mosaic + + This parameter is used to select the starting band where + the input cube will be placed. The band INBAND will be placed at + this band in the output mosaic. + + 1 + + + + + + boolean + Enforce BandBin Group Match + + This option causes the application to fail if the input bandbin group does not + match the mosaic bandbin group. + + TRUE + + + boolean + FALSE + Copy Input HS (Instrument and Representation) values + + This option causes High Saturation values (both Instrument and + Representation) in the input image to be automatically copied to the + mosaic irrespective of the priority + + + + boolean + FALSE + Copy Input LS (Instrument and Representation) values + + This option causes Low Saturation values (both Instrument and + Representation) in the input image to be automatically copied to the + mosaic irrespective of the priority + + + + boolean + FALSE + Copy Input NULL values + + This option causes NULL values in the input image to be automatically + copied to the mosaic irrespective of the priority + + + + + + + string + NO + Create the output mosaic + + This parameter is used to specify if the mosaic needs to be created. + + + + + + + + + + + boolean + FALSE + + Track the mosaic origin + + + If selected the application will track the mosaic origin. Once + origin is tracked, the tracker cannot be turned off. + + + + + integer + 1 + The number of samples to allocate in the mosaic + + This parameter is used to select the number of samples + in the output mosaic. + + + + + integer + 1 + The number of lines to allocate in the mosaic + + This parameter is used to select the number of lines + in the output mosaic. + + + + integer + 1 + The number of bands to allocate in the mosaic + + This parameter is used to select the number of bands + in the output mosaic. + + + + + + diff --git a/isis/src/base/apps/handmos/tsts/Makefile b/isis/src/base/apps/handmos/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/handmos/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/handmos/tsts/band/Makefile b/isis/src/base/apps/handmos/tsts/band/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5c37ce028f9b6e8907e6c2fd18750e9c45fff8b5 --- /dev/null +++ b/isis/src/base/apps/handmos/tsts/band/Makefile @@ -0,0 +1,26 @@ +APPNAME = handmos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.lev2.cub \ + mosaic=$(OUTPUT)/handmosTruth2.cub \ + priority=BAND \ + insample=1 \ + inline=1 \ + inband=1 \ + outsample=1 \ + outline=1 \ + outband=1 \ + nlines=1000 \ + nsamples=1000 \ + nbands=5 \ + create=yes \ + track=true \ + type=KEYWORD \ + keyname=FilterName \ + keyvalue=RED \ + criteria=LESSER \ + highsaturation=false \ + lowsaturation=false \ + null=false > /dev/null; diff --git a/isis/src/base/apps/handmos/tsts/beneath/Makefile b/isis/src/base/apps/handmos/tsts/beneath/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..77b69c2821b11ae3ae573316ea564c937f54281a --- /dev/null +++ b/isis/src/base/apps/handmos/tsts/beneath/Makefile @@ -0,0 +1,19 @@ +APPNAME = handmos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + mosaic=$(OUTPUT)/handmosTruth2.cub \ + priority=beneath \ + insample=1 \ + inline=1 \ + inband=1 \ + outsample=1 \ + outline=2 \ + outband=2 \ + nlines=10 \ + nsamples=10 \ + nbands=5 \ + track=yes \ + create=yes > /dev/null; diff --git a/isis/src/base/apps/handmos/tsts/ontop/Makefile b/isis/src/base/apps/handmos/tsts/ontop/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c10945d1feb8b9b7f1fb6f9ccaac7f9a3efe8d45 --- /dev/null +++ b/isis/src/base/apps/handmos/tsts/ontop/Makefile @@ -0,0 +1,16 @@ +APPNAME = handmos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + mosaic=$(OUTPUT)/handmosTruth1.cub \ + priority=ontop \ + outsample=1 \ + outline=2 \ + outband=1 \ + create=yes \ + track=yes \ + nsamples=10 \ + nlines=20 \ + nbands=2 > /dev/null; diff --git a/isis/src/base/apps/highpass/Makefile b/isis/src/base/apps/highpass/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/highpass/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/highpass/assets/image/2400r.hpf21x21all.jpg b/isis/src/base/apps/highpass/assets/image/2400r.hpf21x21all.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a85a470d5a29e4f785707162f3124571facfb699 Binary files /dev/null and b/isis/src/base/apps/highpass/assets/image/2400r.hpf21x21all.jpg differ diff --git a/isis/src/base/apps/highpass/assets/image/2400r.hpf7x7all.jpg b/isis/src/base/apps/highpass/assets/image/2400r.hpf7x7all.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ca63c1fd4af1f30acac45eb65458a5492ea9340f Binary files /dev/null and b/isis/src/base/apps/highpass/assets/image/2400r.hpf7x7all.jpg differ diff --git a/isis/src/base/apps/highpass/assets/image/2400r.jpg b/isis/src/base/apps/highpass/assets/image/2400r.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5882fe865aafa6d47ab02dc66ef53a6fca952e45 Binary files /dev/null and b/isis/src/base/apps/highpass/assets/image/2400r.jpg differ diff --git a/isis/src/base/apps/highpass/assets/image/highpass21x21allGui.jpg b/isis/src/base/apps/highpass/assets/image/highpass21x21allGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..865ac342eb217e289114a267641c7a606f5fb4ff Binary files /dev/null and b/isis/src/base/apps/highpass/assets/image/highpass21x21allGui.jpg differ diff --git a/isis/src/base/apps/highpass/assets/image/highpass7x7allGui.jpg b/isis/src/base/apps/highpass/assets/image/highpass7x7allGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7839ff67a3df2967120a2b6c5b5a941681445431 Binary files /dev/null and b/isis/src/base/apps/highpass/assets/image/highpass7x7allGui.jpg differ diff --git a/isis/src/base/apps/highpass/assets/thumb/2400r.hpf21x21all.jpg b/isis/src/base/apps/highpass/assets/thumb/2400r.hpf21x21all.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a20aaaef1cf35338a17b1a5ee7007dcffa844dda Binary files /dev/null and b/isis/src/base/apps/highpass/assets/thumb/2400r.hpf21x21all.jpg differ diff --git a/isis/src/base/apps/highpass/assets/thumb/2400r.hpf7x7all.jpg b/isis/src/base/apps/highpass/assets/thumb/2400r.hpf7x7all.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aed53e2647a1ea03036db1c86bde836aa93a041c Binary files /dev/null and b/isis/src/base/apps/highpass/assets/thumb/2400r.hpf7x7all.jpg differ diff --git a/isis/src/base/apps/highpass/assets/thumb/2400r.jpg b/isis/src/base/apps/highpass/assets/thumb/2400r.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a305f16d1a630fd303a9a54a2f10de74a079b395 Binary files /dev/null and b/isis/src/base/apps/highpass/assets/thumb/2400r.jpg differ diff --git a/isis/src/base/apps/highpass/assets/thumb/highpass21x21allGui.jpg b/isis/src/base/apps/highpass/assets/thumb/highpass21x21allGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a7a5b68d29e8ba5c974547b5165c39502a4aa520 Binary files /dev/null and b/isis/src/base/apps/highpass/assets/thumb/highpass21x21allGui.jpg differ diff --git a/isis/src/base/apps/highpass/assets/thumb/highpass7x7allGui.jpg b/isis/src/base/apps/highpass/assets/thumb/highpass7x7allGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a0f2a4eb0e21500c1f2e557129c445d1331e9393 Binary files /dev/null and b/isis/src/base/apps/highpass/assets/thumb/highpass7x7allGui.jpg differ diff --git a/isis/src/base/apps/highpass/highpass.cpp b/isis/src/base/apps/highpass/highpass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fda3285d647863fb570bbd45be6c9769f0fca17c --- /dev/null +++ b/isis/src/base/apps/highpass/highpass.cpp @@ -0,0 +1,76 @@ +#include "Isis.h" +#include "ProcessByQuickFilter.h" +#include "UserInterface.h" + +using namespace std; +using namespace Isis; + +// Globals and prototypes +bool propagate; +double addback; +void highpass (Buffer &in, Buffer &out, QuickFilter &filter); + +// The highpass main routine +void IsisMain() { + ProcessByQuickFilter p; + + // Open the input cube + p.SetInputCube("FROM"); + + // Setup the output cube + p.SetOutputCube("TO"); + + // Find out how to handle special pixels + UserInterface &ui = Application::GetUserInterface(); + propagate = ui.GetBoolean ("PROPAGATE"); + + // Get the addback + addback = ui.GetDouble ("ADDBACK") / 100.0; + + //Set the boxcar parameters + int lines = ui.GetInteger("LINES"); + int samples = ui.GetInteger("SAMPLES"); + double low = -DBL_MAX; + double high = DBL_MAX; + int minimum; + if (ui.WasEntered("LOW")) { + low = ui.GetDouble("LOW"); + } + if (ui.WasEntered("HIGH")) { + high = ui.GetDouble("HIGH"); + } + if (ui.GetString("MINOPT") == "PERCENTAGE") { + int size = lines * samples; + double perc = ui.GetDouble("MINIMUM") / 100; + minimum = (int) (size * perc); + } + else { + minimum = (int)ui.GetDouble("MINIMUM"); + } + p.SetFilterParameters(samples, lines, low, high, minimum); + + // Process each line + p.StartProcess(highpass); // Line processing function + p.EndProcess(); // Cleanup +} + +// Line processing routine +void highpass (Buffer &in, Buffer &out, QuickFilter &filter) { + for (int i=0; i + + + + + Apply a spatial high pass filter to a cube + + + + This program applies a high pass filter to a cube. That is, it filters + the cube data by suppressing low frequency data (e.g., albedo) and allows + high frequency data (e.g., structure) to pass through. + This is done by convolving an NxM boxcar through the data, where N and M + are odd integers. The average of the boxcar is subtracted from the + middle pixel. The result of the subtraction is the high frequency + information. Thus, output(i,j) = input(i,j) - average(i,j,N,M) where + i and j are the sample and line position in the cube, N and M are the + size of the boxcar, and average(i,j,N,M) is the average of the NxM centered + at i,j. A small boxcar (e.g, 3x3) will allow fine + details to pass thru and will significantly suppress the albedo. A large + boxcar (e.g, 101x101) will enhance larger features and allow more albedo + information to pass through. In general, features which are half the size + of the boxcar will pass through the filter. + + + + Filters + + + + + sharpen + lowpass + trimfilter + svfilter + + + + + + Original version + + + + Ported to Isis 3.0 + + + + Add examples. + + + + Make images smaller + + + + Add move images to /image and /thumb directory. + + + Fixed problem with isiscvs not checking in the thumb and image directories. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Added addback parameter + + + + + boxfilter + + + + + + cube + input + + Input file + + + Input cube to filter + + + *.cub + + + + cube + real + output + + Output highpass cube + + + The resultant filtered cube + + + + + + + integer + + Number of samples in boxcar + + + + This is the total number of samples in the boxcar. + It must be odd and can not exceed twice the number of samples + in the cube. In general, the size of the boxcar does not + cause the program to operate significantly slower. + + + + + 1 + + + + integer + + Number of lines in boxcar + + + + This is the total number of lines in the boxcar. + It must be odd and can not exceed twice the number of lines + in the cube. In general, the size of the boxcar does not + cause the program to operate significantly + slower. + + + 1 + + + + string + + COUNT + + + Sets minimum to be either a count or a percentage + + + This parameter determines whether the minimum + parameter is to be interpreted as a count of pixels, or a + percentage of all pixels in the boxcar. + + + + + + + + + + double + + Minimum boxcar pixel count + + + + This is the minimum number of valid pixels which must occur inside the + NxM boxcar for filtering to occur. For example, 3x5 boxcar has 15 + pixels inside. If MINIMUM=10 then the filter will occur if there are + 10 or greater valid pixels. A valid pixel is one that is not special + (NULL, LIS, etc) and is in the range defined by LOW to HIGH. + + + + 1 + + + 1 + + + + + + double + + Valid minimum pixel + + + + Valid minimum pixel value that will be used in boxcar computation. If + a pixel value is less than LOW then it will not be used when + computing boxcar statistics. + + + + Use all pixels + + + + HIGH + + + + + double + + Valid maximum pixel + + + + Valid maximum pixel value that will be used in boxcar computation. If + a pixel value is greater than HIGH then it will not be used when + computing boxcar statistics. + + + + Use all pixels + + + + LOW + + + + + boolean + TRUE + Propagate special pixels + + + This option is used to define how special pixels are handled. If the + center pixel of the boxcar is a special pixel it will be propagated + or set to NULL depending on the value of this parameter. + + + + + double + 0.0 + Percentage of input pixel to add back to the filter + + This option is used to specify how much of the input pixel is + added to the filter result. A value of 100 implies the entire input + pixel will be added back to the filter which is equivalent to the + sharpen program. Recall that highpass filters + suppress albedo and therefore you are essentially selecting + a percentage of albedo to addback. + + 0.0 + 100.0 + + + + + + + 7 by 7 + Use a 7 by 7 pixel filter and use all pixels. + + + from=2400r to=2400r.hpf7x7all samp=7 line=7 + The highpass box filter is selected 7 pixels wide by 7 pixels long and parameters 'low' and 'high' default to 'use all pixels'. + + + + + Input image for highpass + This is the input image for the 7x7 example of highpass. + + + FROM + + + + + Output image 7x7 example of highpass + This is the output image for highpass. Notice the smoothing of abedo typical of high pass filtering, which leaves terrain more visible. This smaller filter leaves smaller features visible. + + + TO + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform the 7x7 filter - with low, high, min default - highpass operation + + + + + + + + + 21 by 21 + Use a 21 by 21 pixel filter and use all pixels. + + + from=2400r to=2400r.hpf21x21all samp=21 line=21 + The boxcar filter is selected 21 pixels wide by 21 pixels long and parameters 'low' and 'high' default to 'use all pixels'. + + + + + Input image for highpass + This is the input image for the 21x21 example of highpass. + + + FROM + + + + + Output image 21x21 example of highpass + This is the output image for highpass. This larger filter leaves larger features visible. + + + TO + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform the 21x21 filter - with low, high, min default - highpass operation + + + + + + + + + diff --git a/isis/src/base/apps/highpass/tsts/Makefile b/isis/src/base/apps/highpass/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/highpass/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/highpass/tsts/addback/Makefile b/isis/src/base/apps/highpass/tsts/addback/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2e87b981d4a7afec57ae310390e27d826515cc51 --- /dev/null +++ b/isis/src/base/apps/highpass/tsts/addback/Makefile @@ -0,0 +1,10 @@ +APPNAME = highpass + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/highTruth1.cub \ + samples=5 \ + lines=9 \ + addback=.5 > /dev/null; diff --git a/isis/src/base/apps/highpass/tsts/default/Makefile b/isis/src/base/apps/highpass/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5c7d42d0bdce138258a4ea66f989c467e68f5b92 --- /dev/null +++ b/isis/src/base/apps/highpass/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = highpass + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/highTruth2.cub \ + samples=9 \ + lines=5 > /dev/null; diff --git a/isis/src/base/apps/hist/Makefile b/isis/src/base/apps/hist/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/hist/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/hist/hist.cpp b/isis/src/base/apps/hist/hist.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7976d6ccecc9e345e2af1045dfb94c9dbf9d9c5 --- /dev/null +++ b/isis/src/base/apps/hist/hist.cpp @@ -0,0 +1,200 @@ +#include "Isis.h" + +#include +#include +#include + +#include "Process.h" +#include "Histogram.h" +#include "UserInterface.h" +#include "Progress.h" +#include "LineManager.h" +#include "QHistogram.h" +#include "HistogramToolWindow.h" +#include "HistogramItem.h" +#include "PlotToolCurve.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + Process p; + Cube *icube = p.SetInputCube("FROM"); + + // Setup the histogram + UserInterface &ui = Application::GetUserInterface(); + Histogram hist(*icube,1,p.Progress()); + if (ui.WasEntered("MINIMUM")) { + hist.SetValidRange(ui.GetDouble("MINIMUM"),ui.GetDouble("MAXIMUM")); + } + if (ui.WasEntered("NBINS")) { + hist.SetBins(ui.GetInteger("NBINS")); + } + + // Loop and accumulate histogram + p.Progress()->SetText("Gathering Histogram"); + p.Progress()->SetMaximumSteps(icube->Lines()); + p.Progress()->CheckStatus(); + LineManager line(*icube); + for (int i=1; i<=icube->Lines(); i++) { + line.SetLine(i); + icube->Read(line); + hist.AddData(line.DoubleBuffer(),line.size()); + p.Progress()->CheckStatus(); + } + + if(!ui.IsInteractive() || ui.WasEntered("TO")) { + // Write the results + + if (!ui.WasEntered("TO")) { + string msg = "The [TO] parameter must be entered"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + string outfile = ui.GetFilename("TO"); + ofstream fout; + fout.open (outfile.c_str()); + + fout << "Cube: " << ui.GetFilename("FROM") << endl; + fout << "Band: " << icube->Bands() << endl; + fout << "Average: " << hist.Average() << endl; + fout << "Std Deviation: " << hist.StandardDeviation() << endl; + fout << "Variance: " << hist.Variance() << endl; + fout << "Median: " << hist.Median() << endl; + fout << "Mode: " << hist.Mode() << endl; + fout << "Skew: " << hist.Skew() << endl; + fout << "Minimum: " << hist.Minimum() << endl; + fout << "Maximum: " << hist.Maximum() << endl; + fout << endl; + fout << "Total Pixels: " << hist.TotalPixels() << endl; + fout << "Valid Pixels: " << hist.ValidPixels() << endl; + fout << "Null Pixels: " << hist.NullPixels() << endl; + fout << "Lis Pixels: " << hist.LisPixels() << endl; + fout << "Lrs Pixels: " << hist.LrsPixels() << endl; + fout << "His Pixels: " << hist.HisPixels() << endl; + fout << "Hrs Pixels: " << hist.HrsPixels() << endl; + + // Write histogram in tabular format + fout << endl; + fout << endl; + fout << "DN,Pixels,CumulativePixels,Percent,CumulativePercent" << endl; + + Isis::BigInt total = 0; + double cumpct = 0.0; + + for (int i=0; i 0) { + total += hist.BinCount(i); + double pct = (double)hist.BinCount(i) / hist.ValidPixels() * 100.; + cumpct += pct; + + fout << hist.BinMiddle(i) << ","; + fout << hist.BinCount(i) << ","; + fout << total << ","; + fout << pct << ","; + fout << cumpct << endl; + } + } + fout.close(); + } + // If we are in gui mode, create a histogram plot + if (ui.IsInteractive()) { + // Set the title for the dialog + string title; + if (ui.WasEntered("TITLE")) { + title = ui.GetString("TITLE"); + } + else { + title = "Histogram Plot for " + Filename(ui.GetAsString("FROM")).Name(); + } + + // Create the QHistogram, set the title & load the Isis::Histogram into it + + Qisis::HistogramToolWindow *plot = new Qisis::HistogramToolWindow(title.c_str(), ui.TheGui()); + + // Set the xaxis title if they entered one + if (ui.WasEntered("XAXIS")) { + string xaxis(ui.GetString("XAXIS")); + plot->setAxisLabel(QwtPlot::xBottom,xaxis.c_str()); + } + + // Set the yLeft axis title if they entered one + if (ui.WasEntered("Y1AXIS")) { + string yaxis(ui.GetString("Y1AXIS")); + plot->setAxisLabel(QwtPlot::yLeft,yaxis.c_str()); + } + + // Set the yRight axis title if they entered one + if (ui.WasEntered("Y2AXIS")) { + string y2axis(ui.GetString("Y2AXIS")); + plot->setAxisLabel(QwtPlot::yRight,y2axis.c_str()); + } + + //Transfer data from histogram to the plotcurve + std::vector xarray,yarray,y2array; + double cumpct = 0.0; + for (int i=0; i 0) { + xarray.push_back(hist.BinMiddle(i)); + yarray.push_back(hist.BinCount(i)); + + double pct = (double)hist.BinCount(i) / hist.ValidPixels() * 100.; + cumpct += pct; + y2array.push_back(cumpct); + } + } + + Qisis::HistogramItem *histCurve = new Qisis::HistogramItem(); + histCurve->setColor(Qt::darkCyan); + histCurve->setTitle("Frequency"); + + Qisis::PlotToolCurve *cdfCurve = new Qisis::PlotToolCurve(); + cdfCurve->setStyle(QwtPlotCurve::Lines); + cdfCurve->setTitle("Percentage"); + + QPen *pen = new QPen(Qt::red); + pen->setWidth(2); + histCurve->setYAxis(QwtPlot::yLeft); + cdfCurve->setYAxis(QwtPlot::yRight); + cdfCurve->setPen(*pen); + + //These are all variables needed in the following for loop. + //---------------------------------------------- + QwtArray intervals(xarray.size()); + QwtArray values(yarray.size()); + double maxYValue = DBL_MIN; + double minYValue = DBL_MAX; + // --------------------------------------------- + + for(unsigned int y = 0; y < yarray.size(); y++) { + + intervals[y] = QwtDoubleInterval(xarray[y], xarray[y] + hist.BinSize()); + + values[y] = yarray[y]; + if(values[y] > maxYValue) maxYValue = values[y]; + if(values[y] < minYValue) minYValue = values[y]; + } + + histCurve->setData(QwtIntervalData(intervals, values)); + cdfCurve->setData(&xarray[0],&y2array[0],xarray.size()); + + plot->add(histCurve); + plot->add(cdfCurve); + plot->fillTable(); + + plot->setScale(QwtPlot::yLeft,0,maxYValue); + plot->setScale(QwtPlot::xBottom,hist.Minimum(),hist.Maximum()); + + QLabel *label = new QLabel(" Average = " + QString::number(hist.Average()) + '\n' + + "\n Minimum = " + QString::number(hist.Minimum()) + '\n' + + "\n Maximum = " + QString::number(hist.Maximum()) + '\n' + + "\n Stand. Dev.= " + QString::number(hist.StandardDeviation()) + '\n' + + "\n Variance = " + QString::number(hist.Variance()) + '\n' + + "\n Median = " + QString::number(hist.Median()) + '\n' + + "\n Mode = " + QString::number(hist.Mode()) +'\n' + + "\n Skew = " + QString::number(hist.Skew()), plot); + plot->getDockWidget()->setWidget(label); + + plot->showWindow(); + } + p.EndProcess(); +} diff --git a/isis/src/base/apps/hist/hist.xml b/isis/src/base/apps/hist/hist.xml new file mode 100644 index 0000000000000000000000000000000000000000..113fa06f82ff78854dc5ab89516be3098e4c61fb --- /dev/null +++ b/isis/src/base/apps/hist/hist.xml @@ -0,0 +1,197 @@ + + + + Generates a histogram table of cube in text format + + + + This program reads a single band from a cube and creates a tabular + representation of the histogram. If a band specification is not + given for the input file then the program will default to using the + first band. The output results can then be viewed in a graphical + form by using your favorite spreadsheet (e.g., Excel) or other + graphing package (e.g., IDL, GNU plotutils). + + + + Math and Statistics + + + + + Original version + + + Add example + + + Make images smaller + + + TO parameter is now always output. Add FORMAT parameter. + + + Added thumb and image directories. + + + Fixed problem with isiscvs not checking in the thumb and image directories. + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Changed default extension handling mechansim + + + Fixed a bug for the text output option, where a c string was going out of bounds. + + + Removed postscript capabilities due to camgraph difficulties with + 64-bit compiling. + + + Added truth file to fix appTest + + + Added NBINS, MINIMUM, and MAXIMUM parameters + + + Added plot of histogram in ui mode, and added parameters to set values on the + plot + + + Histogram object no longer has SetRange, updated to use SetValidRange + + + Removed references to CubeInfo + + + Changed the plot window to the new HistogramToolWindow + + + + + histplane + + + + + + cube + input + + Single plane of a cube to get statistics from + + + The file specification for the input cube. The histogram will be + calculated for one plane only. The default plane is one (1). + + + *.cub + + + + filename + output + + Output text file + + + Output text file containing the tabular representation + of the histogram. + + None + + *.txt + + + + + + + + double + Computed + + Minimum DN value in histogram + + + Minimum DN value in histogram. If not entered it will automatically be computed. + + + MAXIMUM + + + + + double + Computed + + Maximum DN value in histogram + + + Maximum DN value in histogram. If not entered it will automatically be computed. + + + + + integer + Computed + + Bins in the histogram + + + Number of bins in the histogram. If not entered it will automatically be computed. + + + + + + + string + + Plot Title + + + This will be the title for the plot of the histogram. The plot will only be shown in ui mode. + + Default + + + string + + X-Axis Title + + + This will be the title for the x axis, which represents the pixel value (or DN), in the plot of the histogram. The plot will only be shown in ui mode. + + Default + + + string + + Left Y-Axis Title + + + This will be the title for the y axis to the left of the histogram plot, which represents the frequency of the pixel value. + The plot will only be shown in ui mode. + + Default + + + string + + Right Y-Axis Title + + + This will be the title for the y axis to the right of the histogram plot, which represents the percentage of pixel seen so far. + The plot will only be shown in ui mode. + + Default + + + + diff --git a/isis/src/base/apps/hist/tsts/Makefile b/isis/src/base/apps/hist/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/hist/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/hist/tsts/default/Makefile b/isis/src/base/apps/hist/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..92b0a4cfd2ce87feb2714cdd76192e9a4fc49642 --- /dev/null +++ b/isis/src/base/apps/hist/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = hist +histTruth.txt.IGNORELINES = Cube +TEMP = $(OUTPUT)/histTruth.txt + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to= $(TEMP) > /dev/null; diff --git a/isis/src/base/apps/histeq/Makefile b/isis/src/base/apps/histeq/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/histeq/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/histeq/assets/image/FROMparameter.jpg b/isis/src/base/apps/histeq/assets/image/FROMparameter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f3fdc2f55b0e3059c95f4b7d5eee42628ba15651 Binary files /dev/null and b/isis/src/base/apps/histeq/assets/image/FROMparameter.jpg differ diff --git a/isis/src/base/apps/histeq/assets/image/TOparameter.jpg b/isis/src/base/apps/histeq/assets/image/TOparameter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da60f9a509ed2121f79384237c3c2c0e7ef5d73d Binary files /dev/null and b/isis/src/base/apps/histeq/assets/image/TOparameter.jpg differ diff --git a/isis/src/base/apps/histeq/assets/image/band6plot.jpg b/isis/src/base/apps/histeq/assets/image/band6plot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..05f906a2c266291eeabf1b6f8899d924db901e27 Binary files /dev/null and b/isis/src/base/apps/histeq/assets/image/band6plot.jpg differ diff --git a/isis/src/base/apps/histeq/assets/image/exampleAfter.jpg b/isis/src/base/apps/histeq/assets/image/exampleAfter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2e7cba14e6c55da8ff721f019558ecf82947d831 Binary files /dev/null and b/isis/src/base/apps/histeq/assets/image/exampleAfter.jpg differ diff --git a/isis/src/base/apps/histeq/assets/image/exampleBefore.jpg b/isis/src/base/apps/histeq/assets/image/exampleBefore.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4710a0f170fd695c8622d7b764a2e8e2aea2877a Binary files /dev/null and b/isis/src/base/apps/histeq/assets/image/exampleBefore.jpg differ diff --git a/isis/src/base/apps/histeq/assets/image/histeqgui.jpg b/isis/src/base/apps/histeq/assets/image/histeqgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..19c68f5f5b84c9084d84e14e4c879837469acf34 Binary files /dev/null and b/isis/src/base/apps/histeq/assets/image/histeqgui.jpg differ diff --git a/isis/src/base/apps/histeq/assets/image/toplot.jpg b/isis/src/base/apps/histeq/assets/image/toplot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da3dd14e72c3614a3b0f0e73b7c0ab2a19143b31 Binary files /dev/null and b/isis/src/base/apps/histeq/assets/image/toplot.jpg differ diff --git a/isis/src/base/apps/histeq/assets/thumb/FROMparameter.jpg b/isis/src/base/apps/histeq/assets/thumb/FROMparameter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d2036bfeb323b7f90b11f50d679bf3cc4a1c9cd0 Binary files /dev/null and b/isis/src/base/apps/histeq/assets/thumb/FROMparameter.jpg differ diff --git a/isis/src/base/apps/histeq/assets/thumb/TOparameter.jpg b/isis/src/base/apps/histeq/assets/thumb/TOparameter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8d5d6e54187af5da8a499760eacb290e6386f7dc Binary files /dev/null and b/isis/src/base/apps/histeq/assets/thumb/TOparameter.jpg differ diff --git a/isis/src/base/apps/histeq/assets/thumb/band6plot.jpg b/isis/src/base/apps/histeq/assets/thumb/band6plot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..467bb0e8fb6b058e584f29fa27e9da96927f4e6e Binary files /dev/null and b/isis/src/base/apps/histeq/assets/thumb/band6plot.jpg differ diff --git a/isis/src/base/apps/histeq/assets/thumb/exampleAfter.jpg b/isis/src/base/apps/histeq/assets/thumb/exampleAfter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ca2509cce4cb497b2e953e337daf4f4cb874ef33 Binary files /dev/null and b/isis/src/base/apps/histeq/assets/thumb/exampleAfter.jpg differ diff --git a/isis/src/base/apps/histeq/assets/thumb/exampleBefore.jpg b/isis/src/base/apps/histeq/assets/thumb/exampleBefore.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d0adafe758a906ac58d2008314cf0bfcbf30f33d Binary files /dev/null and b/isis/src/base/apps/histeq/assets/thumb/exampleBefore.jpg differ diff --git a/isis/src/base/apps/histeq/assets/thumb/histeqgui.jpg b/isis/src/base/apps/histeq/assets/thumb/histeqgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..73fa5c56f390b28bc42108bcde63d8679394d779 Binary files /dev/null and b/isis/src/base/apps/histeq/assets/thumb/histeqgui.jpg differ diff --git a/isis/src/base/apps/histeq/assets/thumb/toplot.jpg b/isis/src/base/apps/histeq/assets/thumb/toplot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9a8837480fb2964aee09317b7605a26be9fdede6 Binary files /dev/null and b/isis/src/base/apps/histeq/assets/thumb/toplot.jpg differ diff --git a/isis/src/base/apps/histeq/histeq.cpp b/isis/src/base/apps/histeq/histeq.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5bc4cad0a44757b3ddd662f91df78c1aef2f7d20 --- /dev/null +++ b/isis/src/base/apps/histeq/histeq.cpp @@ -0,0 +1,72 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "Statistics.h" +#include "Stretch.h" +#include "Histogram.h" + +using namespace std; +using namespace Isis; + +Stretch stretch; +void remap(Buffer &in, Buffer &out); + +void IsisMain() { + + // Setup the input and output cubes + ProcessByLine p; // used for getting histograms from input cubes + Cube *icube = p.SetInputCube("FROM", Isis::OneBand); + p.SetOutputCube ("TO"); + + // Histogram parameters + UserInterface &ui = Application::GetUserInterface(); + double minimum = ui.GetDouble("MINPER"); + double maximum = ui.GetDouble("MAXPER"); + int increment = ui.GetInteger("INCREMENT"); + + // Histograms from input cubes + Histogram *from = icube->Histogram(); + Histogram *match = icube->Histogram(); + + double fromMin = from->Percent(minimum); + double fromMax = from->Percent(maximum); + int fromBins = from->Bins(); + double data[fromBins]; + double slope = (fromMax - fromMin) / (fromBins - 1); + + // Set "match" to have the same data range and number of bins as "to" + match->SetBins(fromBins); + match->SetValidRange(fromMin, fromMax); + for (int i = 0; i < fromBins; i++) { + data[i] = fromMin + (slope * i); + } + match->AddData(data, fromBins); + + stretch.ClearPairs(); + double lastPer = from->Percent(minimum); + stretch.AddPair(lastPer, match->Percent(minimum)); + for (double i = increment+minimum; i < maximum; i += increment) { + double curPer = from->Percent(i); + if (lastPer < curPer) { + if(abs(lastPer - curPer) > DBL_EPSILON) { + stretch.AddPair(curPer, match->Percent(i)); + lastPer = curPer; + } + } + } + double curPer = from->Percent(maximum); + if (lastPer < curPer && abs(lastPer - curPer) > DBL_EPSILON) { + stretch.AddPair(curPer, match->Percent(maximum)); + } + + // Start the processing + p.StartProcess(remap); + p.EndProcess(); +} + +// Adjust FROM cumulative distribution to be flatter +void remap(Buffer &in, Buffer &out) { + for (int i = 0; i < in.size(); i++) { + out[i] = stretch.Map(in[i]); + } +} // end remap . diff --git a/isis/src/base/apps/histeq/histeq.xml b/isis/src/base/apps/histeq/histeq.xml new file mode 100644 index 0000000000000000000000000000000000000000..78d001c865607c279cb6d5baf2a6d018f691a39a --- /dev/null +++ b/isis/src/base/apps/histeq/histeq.xml @@ -0,0 +1,184 @@ + + + + + Apply histogram equalization to a cube. + + + + This program equalizes the histogram of an input cube (defined by FROM), and outputs the results to a file (defined by TO).



    + By equalizing the input file's histogram, the resulting cumulative distribution becomes linear instead of curved. The following + is an illustration of what happens to an input file. The blue line represents the histogram and the red line is the cumulative + distribution. On the left is the histogram and cumulative distribution of an unmodified image, while the figure on the right shows + how the both the histogram and distribution are altered. +

    + Before equalization + After equalization

    + The blue line represents the input file's histogram and the red line represents its cumulative distribution function. + +
    + + + Math and Statistics + + + + + histmatch + stretch + + + + + + Original version + + + Histogram object no longer has SetRange, updated to use SetValidRange + + + Removed references to CubeInfo + + + + + + + cube + input + + Input file to be equalized + + + This file will have its cumulative distribution reshaped to be more linear. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing a linearized image + + + *.cub + + + + + + + double + 0.5 + Minimum percentage + + Minimum DN cut-off value at the cumulative percent of the histogram + + + 0.0 + + MAXPER + + + + + double + 99.5 + Maximum percentage + + Maximum DN cut-off value at the cumulative percent of the histogram + + + 100.0 + + + + integer + 1 + Percentage increment + + Percentage increment for the histogram + + + 1 + + MAXPER + + + + + + + + + + Histogram equalization + + This example shows the results of histogram equalization on a single band of an image. + + + + from=../peaks.cub+6 to=../result.cub + + + Use histogram equalization to the make the input cube's sixth band distribution function linear. + + + + + + Input image for histeq + This is band 6 of the input image for this example. + + + FROM + + + + Band 6 histogram + This is the input image's cumulative distribution for band 6. + + + + + + + + Output image for histogram equalization + This is the output image that results. + + + TO + + + + Resulting cumulative distribution + This is the output image's cumulative distribution. + + + + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform + a histogram equalization operation with the input image. + + + + + + + +
    diff --git a/isis/src/base/apps/histeq/tsts/Makefile b/isis/src/base/apps/histeq/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/histeq/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/histeq/tsts/test/Makefile b/isis/src/base/apps/histeq/tsts/test/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..820935591a75225512e3d47b7853d8e762f57f65 --- /dev/null +++ b/isis/src/base/apps/histeq/tsts/test/Makefile @@ -0,0 +1,10 @@ +APPNAME = histeq + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/histeqTruth.cub \ + minper=0.5 \ + maxper=99.5 \ + increment=1 > /dev/null; diff --git a/isis/src/base/apps/histmatch/Makefile b/isis/src/base/apps/histmatch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/histmatch/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/histmatch/assets/image/CDFTOparameter.jpg b/isis/src/base/apps/histmatch/assets/image/CDFTOparameter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6fb5eeae6a81f210b4c14d07fe5cb6aeaa80d798 Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/CDFTOparameter.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/image/FROMparameter.jpg b/isis/src/base/apps/histmatch/assets/image/FROMparameter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f0c4788251bf346994e021130fa7fceb87187b1b Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/FROMparameter.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/image/MATCHparameter.jpg b/isis/src/base/apps/histmatch/assets/image/MATCHparameter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d7a5f81593227f9836b130350ac3529866dbebc2 Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/MATCHparameter.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/image/MODETOparameter.jpg b/isis/src/base/apps/histmatch/assets/image/MODETOparameter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4fcc3459a226e9ff11c2d5a816a19bae5dcbe347 Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/MODETOparameter.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/image/band1plot.jpg b/isis/src/base/apps/histmatch/assets/image/band1plot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5cab94939bf75df3f4ff1b9387cc54b9e1ae4db8 Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/band1plot.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/image/band6plot.jpg b/isis/src/base/apps/histmatch/assets/image/band6plot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d5154e149656b9e4a6f04b51801d492c551ec439 Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/band6plot.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/image/cdfplot.jpg b/isis/src/base/apps/histmatch/assets/image/cdfplot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1f2eef7ec0e8063c66773ab803007641040f0100 Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/cdfplot.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/image/exampleBand1.jpg b/isis/src/base/apps/histmatch/assets/image/exampleBand1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d629de6144652fd03b17884ae6841c1649be21fd Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/exampleBand1.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/image/exampleBand6.jpg b/isis/src/base/apps/histmatch/assets/image/exampleBand6.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7d50c8183766b04983d7d755fb5824c330d29b2a Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/exampleBand6.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/image/exampleCDF.jpg b/isis/src/base/apps/histmatch/assets/image/exampleCDF.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f00f293f221f5de7c902b7381464b01bd9c191eb Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/exampleCDF.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/image/exampleMode.jpg b/isis/src/base/apps/histmatch/assets/image/exampleMode.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c93b66c4ceaa3126c087537d1eb2aa33fe81a99a Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/exampleMode.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/image/histmatchgui.jpg b/isis/src/base/apps/histmatch/assets/image/histmatchgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7770620cc94851dca9bf12ba45358324bdc298fc Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/histmatchgui.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/image/modeplot.jpg b/isis/src/base/apps/histmatch/assets/image/modeplot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..161bd99f739cf77deaa328e5e7f3e25cf9495698 Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/image/modeplot.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/thumb/CDFTOparameter.jpg b/isis/src/base/apps/histmatch/assets/thumb/CDFTOparameter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cd4f0e4b80d3309c9722f18ef6ccafd3efd13e83 Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/thumb/CDFTOparameter.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/thumb/FROMparameter.jpg b/isis/src/base/apps/histmatch/assets/thumb/FROMparameter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..de5da5368a15bb2d40808c94cdff32e3be07d50a Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/thumb/FROMparameter.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/thumb/MATCHparameter.jpg b/isis/src/base/apps/histmatch/assets/thumb/MATCHparameter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ad51586bd6747deb5a81b1ddc218527b89da4efd Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/thumb/MATCHparameter.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/thumb/MODETOparameter.jpg b/isis/src/base/apps/histmatch/assets/thumb/MODETOparameter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..585447df9cea56674d0465b7c3a3f169fc04921d Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/thumb/MODETOparameter.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/thumb/band1plot.jpg b/isis/src/base/apps/histmatch/assets/thumb/band1plot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db035f3c72e95f4963a3c2030e1ff63cd8ba6041 Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/thumb/band1plot.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/thumb/band6plot.jpg b/isis/src/base/apps/histmatch/assets/thumb/band6plot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..529ec3242c8549a5194045c5ce4736192f474842 Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/thumb/band6plot.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/thumb/cdfplot.jpg b/isis/src/base/apps/histmatch/assets/thumb/cdfplot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3f06e49a124c42cf822b15ea037bce6551793f37 Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/thumb/cdfplot.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/thumb/histmatchgui.jpg b/isis/src/base/apps/histmatch/assets/thumb/histmatchgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7570f597de734e68f4624583f09c10bf3f19d3c5 Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/thumb/histmatchgui.jpg differ diff --git a/isis/src/base/apps/histmatch/assets/thumb/modeplot.jpg b/isis/src/base/apps/histmatch/assets/thumb/modeplot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ad5e180f86f2fcb14cbb44ff37a34f9eaec867ea Binary files /dev/null and b/isis/src/base/apps/histmatch/assets/thumb/modeplot.jpg differ diff --git a/isis/src/base/apps/histmatch/histmatch.cpp b/isis/src/base/apps/histmatch/histmatch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..953ed0f3c9b5e9785938479a0e9a44016757ed1d --- /dev/null +++ b/isis/src/base/apps/histmatch/histmatch.cpp @@ -0,0 +1,70 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "Statistics.h" +#include "Stretch.h" +#include "Histogram.h" + +using namespace std; +using namespace Isis; + +Stretch stretch; + +void remap(vector &in, vector &out); + +void IsisMain() { + // Setup the input and output cubes along with histograms + ProcessByLine p; + Cube *mcube = p.SetInputCube("MATCH", Isis::OneBand); + Histogram *match = mcube->Histogram(); + p.ClearInputCubes(); + Cube *icube = p.SetInputCube("FROM", Isis::OneBand); + Histogram* from = icube->Histogram(); + p.SetOutputCube ("TO"); + + // Histogram specifications + UserInterface &ui = Application::GetUserInterface(); + double minimum = ui.GetDouble("MINPER"); + double maximum = ui.GetDouble("MAXPER"); + + stretch.ClearPairs(); + + // CDF mode selected + if (ui.GetString("STRETCH") == "CDF") { + int increment = ui.GetInteger("INCREMENT"); + double lastPer = from->Percent(minimum); + stretch.AddPair(lastPer, match->Percent(minimum)); + for (double i = increment+minimum; i < maximum; i += increment) { + double curPer = from->Percent(i); + if (lastPer < curPer && abs(lastPer - curPer) > DBL_EPSILON) { + stretch.AddPair(curPer, match->Percent(i)); + lastPer = curPer; + } + } + double curPer = from->Percent(maximum); + if (lastPer < curPer && abs(lastPer - curPer) > DBL_EPSILON) { + stretch.AddPair(curPer, match->Percent(maximum)); + } + } + + // Modal mode is selected + else { + stretch.AddPair(from->Percent(minimum), match->Percent(minimum)); + stretch.AddPair(from->Mode(), match->Mode()); + stretch.AddPair(from->Percent(maximum), match->Percent(maximum)); + } + + // Start the processing + p.StartProcess(remap); + p.EndProcess(); +} + +// Adjust FROM histogram to resemble MATCH's histogram +void remap(vector &in, vector &out) { + Buffer &from = *in[0]; + Buffer &to = *out[0]; + + for (int i = 0; i < from.size(); i++) { + to[i] = stretch.Map(from[i]); + } +} // end remap diff --git a/isis/src/base/apps/histmatch/histmatch.xml b/isis/src/base/apps/histmatch/histmatch.xml new file mode 100644 index 0000000000000000000000000000000000000000..5aee6af7d0535f4ca7e0e3a4e4b424ec021cfcd8 --- /dev/null +++ b/isis/src/base/apps/histmatch/histmatch.xml @@ -0,0 +1,319 @@ + + + + + Match histograms of 2 cubes + + + + This program takes in two input images, FROM and MATCH, and uses their histograms to compute stretch pairs. The data + in the stretch depends on which matching algorithm is chosen. If Culmulative Distribution Function (CDF) is chosen, + the histogram data will be stored into stretch pairs at regular intervals, the default being every one percent between + 0.5 and 99.5 percent. If MODE is chosen, only the histogram data at the endpoints and mode are stored. The + pixels from the input image are remapped based on the data in the stretch pairs and the results are written to + a new cube file. This is useful for tone matching two images. The following figures + illustrate what is happening. Band 1 is FROM, Band 6 is MATCH, and CDF and Mode are two different output cubes. The + blue line is the histogram and the red line is the cumulative distribution. +

    + Band 1 image + Output of CDF algorithm +

    + Band 6 image + Output of Mode algorithm +

    + Notice how the endpoints, mode, and overall shape of Band 1's histogram is now roughly equivalent to Band 6. +
    + + + Math and Statistics + + + + + equalizer + tonematch + + + + + + Original version + + + Included ability to histmatch input cubes of different sizes + + + Removed references to CubeInfo + + + + + + + cube + input + + Input file to be altered + + + This file will have its histogram reshaped to resemble MATCH's histogram + + + *.cub + + + + + cube + input + + Input file to be matched + + + This file's histogram will be matched by FROM + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the altered input file + + + *.cub + + + + + + + string + CDF + Stretch mode + + This parameter specifies how the histogram will be stretched. The options are to stretch by + by percentage (CDF), or by mode (Mode). + + + + + + + + + + + + double + 0.5 + Minimum percentage + + Minimum cut-off value for the histogram + + + 0.0 + + MAXPER + + + + + double + 99.5 + Maximum percentage + + Maximum cut-off value for the histogram + + + 100.0 + + + + integer + 1 + Percentage increment + + Percentage increment for the histogram + + + 1 + + MAXPER + + + + + + + + + + + Peaks histogram matching with CDF + + This example shows the results of histogram matching using the cumulative distribution function. + + + + from=../peaks.cub+1 match=../peaks.cub+6 stretch=cdf to=../result.cub + + + Use CDF matching to adjust Band 1's histogram to resemble Band 6's histogram + + + + + + Input image for histmatch + This is the input image for the histmatch example. + + + FROM + + + + Band 1 histogram + This is the input image's histogram. + + + + + + Match image for histmatch + This is the match image for the histmatch example (i.e. the other input's histogram will be matched to this image's histogram). + + + MATCH + + + + Band 6 histogram + This is the input image's histogram. + + + + + + + + Output image for CDF matching + This is the output image that results. + + + TO + + + + CDF histogram + This is the output image's histogram. + + + + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform +a histogram matching operation with the input images. + + + + + + + + Peaks histogram matching with mode + + This example shows the results of histogram matching using the match mode function. + + + + from=../peaks.cub+1 match=../peaks.cub+6 stretch=mode to=../result.cub + + + Use mode matching to adjust Band 1's histogram to resemble Band 6's histogram + + + + + + Input image for histmatch + This is the input image for the histmatch example. + + + FROM + + + + Band 1 histogram + This is the input image's histogram. + + + + + + Match image for histmatch + This is the match image for the histmatch example (i.e. the other input's histogram will be matched to this image's histogram). + + + MATCH + + + + Band 6 histogram + This is the input image's histogram. + + + + + + + + + Output image for mode matching + This is the output image that results. + + + TO + + + + Mode histogram + This is the output image's histogram. + + + + + + + + + +
    diff --git a/isis/src/base/apps/histmatch/tsts/Makefile b/isis/src/base/apps/histmatch/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/histmatch/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/histmatch/tsts/cdf/Makefile b/isis/src/base/apps/histmatch/tsts/cdf/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..accb24568f886edc7fb4ef5742736384e813c6e0 --- /dev/null +++ b/isis/src/base/apps/histmatch/tsts/cdf/Makefile @@ -0,0 +1,13 @@ +APPNAME = histmatch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + match=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/histmatchTruth1.cub \ + stretch=cdf \ + minper=0.5 \ + maxper=99.5 \ + increment=1 > /dev/null; + diff --git a/isis/src/base/apps/histmatch/tsts/mode/Makefile b/isis/src/base/apps/histmatch/tsts/mode/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bf14fcc4c98e105322b39fc42bf3e71b45cab6f9 --- /dev/null +++ b/isis/src/base/apps/histmatch/tsts/mode/Makefile @@ -0,0 +1,11 @@ +APPNAME = histmatch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + match=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/histmatchTruth2.cub \ + stretch=mode \ + minper=0.5 \ + maxper=99.5 > /dev/null; diff --git a/isis/src/base/apps/hsv2rgb/Makefile b/isis/src/base/apps/hsv2rgb/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/hsv2rgb/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/hsv2rgb/assets/image/blue.jpg b/isis/src/base/apps/hsv2rgb/assets/image/blue.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b9dd2e0b6fd50184dd51527f3eee7bcee48c5eab Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/image/blue.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/assets/image/green.jpg b/isis/src/base/apps/hsv2rgb/assets/image/green.jpg new file mode 100644 index 0000000000000000000000000000000000000000..34784e65043ab23b022e9ced86ea7cbaa8bbd787 Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/image/green.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/assets/image/hsv2rgbgui.JPG b/isis/src/base/apps/hsv2rgb/assets/image/hsv2rgbgui.JPG new file mode 100644 index 0000000000000000000000000000000000000000..3a6c1feefaa5eb0e0b4461fae07b97deed415f99 Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/image/hsv2rgbgui.JPG differ diff --git a/isis/src/base/apps/hsv2rgb/assets/image/hue.jpg b/isis/src/base/apps/hsv2rgb/assets/image/hue.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e2f0b36e75da6eaae19871907163f8056335f5fb Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/image/hue.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/assets/image/red.jpg b/isis/src/base/apps/hsv2rgb/assets/image/red.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0d280ca84582f95a2009810b40f182b5f069850f Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/image/red.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/assets/image/sat.jpg b/isis/src/base/apps/hsv2rgb/assets/image/sat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3c4c214707ef23662a1d536f486770155ba4b7dd Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/image/sat.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/assets/image/val.jpg b/isis/src/base/apps/hsv2rgb/assets/image/val.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3fe35a0543b6ca0eddaac7a5212676dda6bb66ba Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/image/val.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/assets/thumb/blue.jpg b/isis/src/base/apps/hsv2rgb/assets/thumb/blue.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4c014e1f442ad20993cc6d0717dbbdf1d85d00be Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/thumb/blue.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/assets/thumb/green.jpg b/isis/src/base/apps/hsv2rgb/assets/thumb/green.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68739b348f1681e0681b9d6fb508aa80b9f06b9b Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/thumb/green.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/assets/thumb/hsv2rgbgui.jpg b/isis/src/base/apps/hsv2rgb/assets/thumb/hsv2rgbgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..408287c4a1e3e938d9aa0b47bf2bbe0f0d64335a Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/thumb/hsv2rgbgui.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/assets/thumb/hue.jpg b/isis/src/base/apps/hsv2rgb/assets/thumb/hue.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7161d20dcc93f678d8f1bb0d98f34e647b40184d Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/thumb/hue.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/assets/thumb/red.jpg b/isis/src/base/apps/hsv2rgb/assets/thumb/red.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c747b8b0598baae11b7fc664ea5a48e466a68f7a Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/thumb/red.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/assets/thumb/sat.jpg b/isis/src/base/apps/hsv2rgb/assets/thumb/sat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bb5c86b8c06c526e43c0c57c1734f361b64e1ac6 Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/thumb/sat.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/assets/thumb/val.jpg b/isis/src/base/apps/hsv2rgb/assets/thumb/val.jpg new file mode 100644 index 0000000000000000000000000000000000000000..540878ac810c43626a4fae9a85e66e677549941d Binary files /dev/null and b/isis/src/base/apps/hsv2rgb/assets/thumb/val.jpg differ diff --git a/isis/src/base/apps/hsv2rgb/hsv2rgb.cpp b/isis/src/base/apps/hsv2rgb/hsv2rgb.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c8aa4af9251f11a2669f2eb95c5fceada333d663 --- /dev/null +++ b/isis/src/base/apps/hsv2rgb/hsv2rgb.cpp @@ -0,0 +1,146 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +#include "QColor" +#include "Histogram.h" +#include "Stretch.h" + +using namespace std; +using namespace Isis; + +void convert(vector &in, + vector &out); + +Stretch hueStretch, satStretch, valStretch; +double valueScalar; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + valueScalar = ui.GetDouble("SCALAR"); + + // Clear out stretch pairs to handle multiple runs + hueStretch.ClearPairs(); + satStretch.ClearPairs(); + valStretch.ClearPairs(); + + // Handle special pixels + hueStretch.SetNull(0.0); + hueStretch.SetLis(0.0); + hueStretch.SetLrs(0.0); + hueStretch.SetHrs(360.0); + hueStretch.SetHis(360.0); + satStretch.SetNull(0.0); + satStretch.SetLis(0.0); + satStretch.SetLrs(0.0); + satStretch.SetHrs(1.0); + satStretch.SetHis(1.0); + valStretch.SetNull(0.0); + valStretch.SetLis(0.0); + valStretch.SetLrs(0.0); + valStretch.SetHrs(1.0); + valStretch.SetHis(1.0); + + // Start the processing + ProcessByLine p; + p.SetInputCube("HUE", Isis::OneBand); + p.SetInputCube("SATURATION", Isis::OneBand); + p.SetInputCube("VALUE", Isis::OneBand); + + p.SetOutputCube("RED"); + p.SetOutputCube("GREEN"); + p.SetOutputCube("BLUE"); + + p.StartProcess(convert); + p.EndProcess(); +} + +// Line processing routine +// This works by building an HSV QColor from the input buffers. This is +// converted to RGB format, then the RGB data is sent to the output file buffers. +void convert (vector &in, + vector &out) { + // Input file buffers + Buffer &hue = *in[0]; + Buffer &saturation = *in[1]; + Buffer &value = *in[2]; + + // Output file buffers + Buffer &red = *out[0]; + Buffer &green = *out[1]; + Buffer &blue = *out[2]; + + for (int i = 0; i < hue.size(); i++) { + // Convert range: [0, 360] -> [0, 1] + + /** + * HSV Stores colors in terms of hue, saturation, and value. The hue determines the color, + * which is an angle around the color wheel. However, QColor::fromHsvF() in the qt library expects a + * percentage around the color wheel and not an angle. For example, 0% means the origin and + * 50% means 180 degrees around the circle. The hue is in degrees and we went it in percentages, so to convert + * this value we divide by 360 degrees. The basic colors are: 0 degrees = RED, + * 60 degrees = YELLOW, 120 degrees = GREEN, 180 degrees = CYAN, 240 degrees = BLUE and + * 300 degrees = PURPLE. + * The saturation is how much grey is in the color (intensity of the color). A saturation value of zero means it's perfect, + * while a saturation value of 1 would cause any color to become pure grey. As an example, the color RGB(255,0,0) + * is pure so the saturation would be zero. The value is how bright the color is. A value of 0 is always black, + * and 100 is the color (if not saturated). + * In brief, + * HUE = COLOR (degrees around the color wheel) + * SATURATION = INTENSITY (0-1, 0 being no color/grey) + * VALUE = BRIGHTNESS (0 being black) + * + * For more information, see + * http://en.wikipedia.org/wiki/Color_spaces + */ + + // Make sure hue[i] is in the 0 - 360 degree range because the colors may have been + // shifted by the user. For example, they may have had all 0-360 degree values and + // added 90 degrees to shift the colors. Well, 360 degrees + 90 degrees = 450 degrees. + // 450 degrees on the color wheel is the same as 90 degrees on the color wheel, and + // this will verify the inputs are valid. + double hueVal = hueStretch.Map(hue[i]); + + // while hue is less than 0 degrees, increase it (example: -10 degrees would become 350 degrees) + while(hueVal < 0) { + hueVal += 360; + } + + // while hue is greater than 360 degrees, decrease it (example: 450 degrees would become 90 degrees) + while(hueVal > 360) { + hueVal -= 360; + } + + // QColor::fromHsvF expects a percentage around the circle and not degrees, so we divide by 360. + hueVal /= 360.0; + + double sat = satStretch.Map(saturation[i]); + + // Saturation should be between zero and one + if(sat < 0) { + sat = 0; + } + else if(sat > 1) { + sat = 1; + } + + double val = valStretch.Map(value[i]); + + // Value should be between zero and one before valueScalar is applied + if(val < 0) { + val = 0; + } + else if(val > 1) { + val = 1; + } + + val *= valueScalar; + + QColor hsv = QColor::fromHsvF(hueVal, sat, val); + QColor rgb = hsv.toRgb(); + + red[i] = rgb.redF(); + green[i] = rgb.greenF(); + blue[i] = rgb.blueF(); + } +} diff --git a/isis/src/base/apps/hsv2rgb/hsv2rgb.xml b/isis/src/base/apps/hsv2rgb/hsv2rgb.xml new file mode 100644 index 0000000000000000000000000000000000000000..1c3eeb8444b18395864e6991e8db680af3dc1f71 --- /dev/null +++ b/isis/src/base/apps/hsv2rgb/hsv2rgb.xml @@ -0,0 +1,233 @@ + + + + + Convert HSV to RGB + + + + This program takes in three input images, representing Hue, Saturation, and Value, then outputs Red, + Green, and Blue files respectively. It works by creating an HSV pixel from pixels in the Hue, Saturation, + and Value files, converting it to RGB format, then writing the data to the Red, Green, and Blue files.

    + + HSV Stores colors in terms of hue, saturation, and value. The hue determines the color, + which is an angle around the color wheel. The basic colors are: 0 degrees = RED, + 60 degrees = YELLOW, 120 degrees = GREEN, 180 degrees = CYAN, 240 degrees = BLUE and + 300 degrees = PURPLE. + The saturation is how much grey is in the color (intensity of the color). A saturation value of zero means it's perfect, + while a saturation value of 1 would cause any color to become pure grey. As an example, the color RGB(255,0,0) + is pure so the saturation would be zero. The value is how bright the color is. A value of 0 is always black, + and 100 is the color (if not saturated).
    + In brief,
    + HUE = COLOR (degrees around the color wheel)
    + SATURATION = INTENSITY (0-1, 0 being no color/grey)
    + VALUE = BRIGHTNESS (0 being black)

    + + For more information, see
    + http://en.wikipedia.org/wiki/Color_spaces +
    + + + Math and Statistics + + + + + rgb2hsv + + + + + + Original version + + + Added comment explaining what HSV is and what the code is doing. Also, added code for boundary cases. + + + + + + + cube + input + + Input file to be converted + + + This file will be converted from Hue to Red + + + *.cub + + + + + cube + input + + Input file to be converted + + + This file will be converted from Saturation to Green + + + *.cub + + + + + cube + input + + Input file to be converted + + + This file will be converted from Value to Blue + + + *.cub + + + + + + + cube + real + output + + Output cube + + + The resultant Hue cube + + + *.cub + + + + + cube + real + output + + Output cube + + + The resultant Saturation cube + + + *.cub + + + + + cube + real + output + + Output cube + + + The resultant Value cube + + + *.cub + + + + + + + double + 1.0 + VALUE DN multiplier + + This value can be used to alter the DNs of the VALUE image + + 0.0 + + + + + + + Convert RGB image to HSV + + This example shows the results of converting RGB images to HSV format. + + + + red=../peaks.cub+5 green=../peaks.cub+4 blue=../peaks.cub+3 hue=../hue.cub saturation=../sat.cub value=../val.cub + + + Convert Hue, Saturation, and Value into their respective Red, Green, and Blue images. + + + + + + Input image for hsv2rgb + This is the input image for the hsv2rgb example. + + + HUE + + + Input image for hsv2rgb + This is the input image for the hsv2rgb example. + + + SATURATION + + + Input image for hsv2rgb + This is the input image for the hsv2rgb example. + + + VALUE + + + + + + Output image + This is the output image that results from converting Hue to Red. + + + RED + + + + Output image + This is the output image that results from converting Saturation to Green. + + + GREEN + + + + Output image + This is the output image that results from converting Value to Blue. + + + BLUE + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform + a conversion from HSV to RGB. + + + + + + + + +
    diff --git a/isis/src/base/apps/hsv2rgb/tsts/Makefile b/isis/src/base/apps/hsv2rgb/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/hsv2rgb/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/hsv2rgb/tsts/default/Makefile b/isis/src/base/apps/hsv2rgb/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..757fae36ba6c274fc42fd699898d702d08cc6f73 --- /dev/null +++ b/isis/src/base/apps/hsv2rgb/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME = hsv2rgb + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) hue=$(INPUT)/hueTruth.cub \ + saturation=$(INPUT)/satTruth.cub \ + value=$(INPUT)/valTruth.cub \ + red=$(OUTPUT)/redTruth.cub \ + green=$(OUTPUT)/greenTruth.cub \ + blue=$(OUTPUT)/blueTruth.cub > /dev/null; diff --git a/isis/src/base/apps/ifft/Makefile b/isis/src/base/apps/ifft/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/ifft/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/ifft/assets/image/ifftGui.jpg b/isis/src/base/apps/ifft/assets/image/ifftGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..526765b684d8d12a3df4654ff01fff7fbeba017f Binary files /dev/null and b/isis/src/base/apps/ifft/assets/image/ifftGui.jpg differ diff --git a/isis/src/base/apps/ifft/assets/image/peaks.jpg b/isis/src/base/apps/ifft/assets/image/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..ef1a24efc0554596f440e9e349fa223994594094 Binary files /dev/null and b/isis/src/base/apps/ifft/assets/image/peaks.jpg differ diff --git a/isis/src/base/apps/ifft/assets/thumb/ifftGui.jpg b/isis/src/base/apps/ifft/assets/thumb/ifftGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c5d8cd6613f2d22085fea3271562a1b9a42a09a2 Binary files /dev/null and b/isis/src/base/apps/ifft/assets/thumb/ifftGui.jpg differ diff --git a/isis/src/base/apps/ifft/assets/thumb/ifftMag.jpg b/isis/src/base/apps/ifft/assets/thumb/ifftMag.jpg new file mode 100755 index 0000000000000000000000000000000000000000..9fadc798dcbde8a778524e78f150f8bea70ff099 Binary files /dev/null and b/isis/src/base/apps/ifft/assets/thumb/ifftMag.jpg differ diff --git a/isis/src/base/apps/ifft/assets/thumb/ifftPhase.jpg b/isis/src/base/apps/ifft/assets/thumb/ifftPhase.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8f1ecda713eafd78a89a483c236c7b4aa31598ae Binary files /dev/null and b/isis/src/base/apps/ifft/assets/thumb/ifftPhase.jpg differ diff --git a/isis/src/base/apps/ifft/assets/thumb/peaks.jpg b/isis/src/base/apps/ifft/assets/thumb/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..d2d9cfe5f9049bb36047091aba8740119f7cca35 Binary files /dev/null and b/isis/src/base/apps/ifft/assets/thumb/peaks.jpg differ diff --git a/isis/src/base/apps/ifft/ifft.cpp b/isis/src/base/apps/ifft/ifft.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10753b3ee0430e2539f1a26b724112a704ed7caf --- /dev/null +++ b/isis/src/base/apps/ifft/ifft.cpp @@ -0,0 +1,132 @@ +#include "Isis.h" +#include +#include "FourierTransform.h" +#include "ProcessByTile.h" +#include "AlphaCube.h" + +using namespace std; +using namespace Isis; + +void IFFT1 (vector &in, vector &out); +void IFFT2 (vector &in, vector &out); + +FourierTransform fft; +string tmpMagFilename = "Temporary_IFFT_Magnitude.cub"; +string tmpPhaseFilename = "Temporary_IFFT_Phase.cub"; + +void IsisMain() { + // We will be processing by line first + ProcessByTile lProc; + lProc.Progress()->SetText("First pass"); + + // Get the original cubes dimensions + UserInterface &ui = Application::GetUserInterface(); + Pvl lab; + lab.Read(ui.GetFilename("MAGNITUDE")); + AlphaCube acube(lab); + int initSamples = acube.BetaSamples(); + int initLines = acube.BetaLines(); + + // Setup the input and output cubes + Cube *magCube = lProc.SetInputCube("MAGNITUDE"); + Cube *phaseCube = lProc.SetInputCube("PHASE"); + + int numSamples = magCube->Samples(); + int numLines = magCube->Lines(); + int numBands = magCube->Bands(); + + // error checking for valid input cubes + // i.e. the dimensions of the magnitude and phase cubes + // are the same and are powers of two + if (!fft.IsPowerOfTwo(numSamples) || !fft.IsPowerOfTwo(numLines) + || magCube->Samples()!=phaseCube->Samples() || magCube->Lines()!=phaseCube->Lines()) { + cerr << "Invalid Cubes: the dimensions of both cubes must be equal powers of 2." << endl; + return; + } + + lProc.SetTileSize(numSamples, 1); + + Isis::CubeAttributeOutput cao; + + lProc.SetOutputCube (tmpMagFilename, cao, numSamples, numLines, numBands); + lProc.SetOutputCube (tmpPhaseFilename, cao, numSamples, numLines, numBands); + + // Start the line processing + lProc.StartProcess(IFFT2); + lProc.EndProcess(); + + // Then process by sample + ProcessByTile sProc; + sProc.Progress()->SetText("Second pass"); + sProc.SetTileSize(1, numLines); + + // Setup the input and output cubes + Isis::CubeAttributeInput cai; + + sProc.SetInputCube(tmpMagFilename, cai); + sProc.SetInputCube(tmpPhaseFilename, cai); + + // the final output cube is cropped back to the original size + sProc.SetOutputCube("TO", initSamples, initLines, numBands); + + //Start the sample proccessing + sProc.StartProcess(IFFT1); + sProc.EndProcess(); + + remove(tmpMagFilename.c_str()); + remove(tmpPhaseFilename.c_str()); +} + +// Processing routine for the inverse fft +void IFFT1 (vector &in, vector &out) +{ + Buffer &inReal = *in[0]; + Buffer &inImag = *in[1]; + + int n = inReal.size(); + vector< complex > input(n); + + // copy and rearrange the data to fit the algorithm + // the image is centered at zero, the array begins at zero + for (int i=0; i(inReal[i+n/2], inImag[i+n/2]); + input[i+n/2] = complex(inReal[i], inImag[i]); + } + + // compute the inverse fft + vector< complex > output = fft.Inverse(input); + + Buffer &image = *out[0]; + // and copy the result to the output cube + for ( int i=0; i &in, vector &out) +{ + Buffer &mag = *in[0]; + Buffer &phase = *in[1]; + + int n = mag.size(); + vector< complex > input(n); + + // copy and rearrange the data to fit the algorithm + // the image is centered at zero, the array begins at zero + for (int i=0; i(polar(mag[i+n/2], phase[i+n/2])); + input[i+n/2] = complex(polar(mag[i], phase[i])); + } + + // compute the inverse fft + vector< complex > output = fft.Inverse(input); + + Buffer &realCube = *out[0]; + Buffer &imagCube = *out[1]; + // and copy the result to the output cubes + for ( int i=0; i + + + Apply an Inverse Fourier Transform on a magnitude/phase pair of cubes + + + + This program accepts two cubes, most likely acquired from the fft program, + containing the magnitude and phase angle data of a Fourier transformed + image and returns the inverse. + + + + Fourier Domain + + + + + fft + + + + + + Original version + + + Documentation fixes + + + Removed references to CubeInfo + + + Fixed documentation: example GUI screenshots were missing, + they should now exist. The name of the GUI screenshot was incorrect, + "fft" was changed to "ifft." + + + + + + + cube + input + + Magnitude input cube + + + The input cube containing the image magnitude data. + + + *.cub + + + + + cube + input + + Phase input cube + + + The input cube containing the image phase angle data. + + + *.cub + + + + + cube + output + + Output cube. + + + The result of the inverse transform. + + + *.cub + + + + + + + + + ifft example + + Example of the inverse Fourier transform. + + + magnitude=peaks_magnitude.cub phase=peaks_phase.cub to=peaks.cub + + Compute the inverse Fourier transform of peaks_magnitude.cub and peaks_phase.cub and store the result in peaks.cub . + + + + + + Example magnitude output + This is the magnitude output of the transform of peaks.cub. + + + MAGNITUDE + + + + Example phase output + This is the phase output of the transform of peaks.cub. + + + PHASE + + + + + + Example output + This is the output image, peaks.cub. + + + FROM + + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform the ifft application + + + + + + + + diff --git a/isis/src/base/apps/ifft/tsts/Makefile b/isis/src/base/apps/ifft/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/ifft/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/ifft/tsts/default/Makefile b/isis/src/base/apps/ifft/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ba5c70fb022b3c463180f6b2039f25ea5d8498cc --- /dev/null +++ b/isis/src/base/apps/ifft/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME = ifft + +# 7.2e-15 +ifftTruth.cub.TOLERANCE = .0000000000000072 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) magnitude=$(INPUT)/testMag.cub \ + phase=$(INPUT)/testPhase.cub \ + to=$(OUTPUT)/ifftTruth.cub > /dev/null; diff --git a/isis/src/base/apps/interestcube/Makefile b/isis/src/base/apps/interestcube/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/interestcube/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/interestcube/assets/images/InterestGUI.jpg b/isis/src/base/apps/interestcube/assets/images/InterestGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f75a92300fae67268031d15e92200e40776843bb Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/images/InterestGUI.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/images/ab102401.jpg b/isis/src/base/apps/interestcube/assets/images/ab102401.jpg new file mode 100644 index 0000000000000000000000000000000000000000..192416d75a243d479d2ae948625a24eeb09ad04a Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/images/ab102401.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/images/forstner.jpg b/isis/src/base/apps/interestcube/assets/images/forstner.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aa9360d9539bcaa54f7486251d4936c426581fd1 Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/images/forstner.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/images/gradient.jpg b/isis/src/base/apps/interestcube/assets/images/gradient.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cb28584bcf78cfef45c707bd51bac90387828c86 Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/images/gradient.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/images/large.jpg b/isis/src/base/apps/interestcube/assets/images/large.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a93597725aecbb72f453c1f41949c74c6402647d Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/images/large.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/images/moravec.jpg b/isis/src/base/apps/interestcube/assets/images/moravec.jpg new file mode 100644 index 0000000000000000000000000000000000000000..32d8fef7c9c1f19fd9987695f6baebd880587237 Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/images/moravec.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/images/stddev.jpg b/isis/src/base/apps/interestcube/assets/images/stddev.jpg new file mode 100644 index 0000000000000000000000000000000000000000..beba7a3c692d4fc07a958bcf3c7877769c4b5753 Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/images/stddev.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/inputFor.pvl b/isis/src/base/apps/interestcube/assets/inputFor.pvl new file mode 100644 index 0000000000000000000000000000000000000000..8c28afb214c3b39cf54746fa290e46cba5134123 --- /dev/null +++ b/isis/src/base/apps/interestcube/assets/inputFor.pvl @@ -0,0 +1,12 @@ +Object = InterestOperator + Group = Operator + Name = Forstner + DeltaSamp = 0 + DeltaLine = 0 + Samples = 3 + Lines = 3 + MinimumDN = 0.0 + MaximumDN = 1.0 + MinimumInterest = 0.0 + End_Group +End_Object diff --git a/isis/src/base/apps/interestcube/assets/inputGrad.pvl b/isis/src/base/apps/interestcube/assets/inputGrad.pvl new file mode 100644 index 0000000000000000000000000000000000000000..03d0c2dd4a854e56db6524e4d9a8bded2ca43942 --- /dev/null +++ b/isis/src/base/apps/interestcube/assets/inputGrad.pvl @@ -0,0 +1,12 @@ +Object = InterestOperator + Group = Operator + Name = Gradient + DeltaSamp = 0 + DeltaLine = 0 + Samples = 3 + Lines = 3 + MinimumDN = 0.0 + MaximumDN = 1.0 + MinimumInterest = 0.0 + End_Group +End_Object diff --git a/isis/src/base/apps/interestcube/assets/inputLarge.pvl b/isis/src/base/apps/interestcube/assets/inputLarge.pvl new file mode 100644 index 0000000000000000000000000000000000000000..94aa25920b48eb301f6b02547e6617ab059686d8 --- /dev/null +++ b/isis/src/base/apps/interestcube/assets/inputLarge.pvl @@ -0,0 +1,12 @@ +Object = InterestOperator + Group = Operator + Name = StandardDeviation + DeltaSamp = 0 + DeltaLine = 0 + Samples = 15 + Lines = 15 + MinimumDN = 0.0 + MaximumDN = 1.0 + MinimumInterest = 0.0 + End_Group +End_Object diff --git a/isis/src/base/apps/interestcube/assets/inputMor.pvl b/isis/src/base/apps/interestcube/assets/inputMor.pvl new file mode 100644 index 0000000000000000000000000000000000000000..10bedc69b9ac2bb14ef89c12f57d6a0118ca5976 --- /dev/null +++ b/isis/src/base/apps/interestcube/assets/inputMor.pvl @@ -0,0 +1,12 @@ +Object = InterestOperator + Group = Operator + Name = Moravec + DeltaSamp = 0 + DeltaLine = 0 + Samples = 3 + Lines = 3 + MinimumDN = 0.0 + MaximumDN = 1.0 + MinimumInterest = 0.0 + End_Group +End_Object diff --git a/isis/src/base/apps/interestcube/assets/inputStd.pvl b/isis/src/base/apps/interestcube/assets/inputStd.pvl new file mode 100644 index 0000000000000000000000000000000000000000..d57551d4facf0b33adbd84e0472a25d160d2a2d0 --- /dev/null +++ b/isis/src/base/apps/interestcube/assets/inputStd.pvl @@ -0,0 +1,12 @@ +Object = InterestOperator + Group = Operator + Name = StandardDeviation + DeltaSamp = 0 + DeltaLine = 0 + Samples = 3 + Lines = 3 + MinimumDN = 0.0 + MaximumDN = 1.0 + MinimumInterest = 0.0 + End_Group +End_Object diff --git a/isis/src/base/apps/interestcube/assets/thumbs/InterestGUI.jpg b/isis/src/base/apps/interestcube/assets/thumbs/InterestGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9fc869b8a6fab3f29763313898763116cdb3b896 Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/thumbs/InterestGUI.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/thumbs/ab102401.jpg b/isis/src/base/apps/interestcube/assets/thumbs/ab102401.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0d7a23022cb5a805a1c41101e8cbec6a134e55e5 Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/thumbs/ab102401.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/thumbs/forstner.jpg b/isis/src/base/apps/interestcube/assets/thumbs/forstner.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5cc9325ef3efa5936e2ad56168c4be945ce61a73 Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/thumbs/forstner.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/thumbs/gradient.jpg b/isis/src/base/apps/interestcube/assets/thumbs/gradient.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3edbe8ba10c924b14fdc307ad59f55124b839ea0 Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/thumbs/gradient.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/thumbs/large.jpg b/isis/src/base/apps/interestcube/assets/thumbs/large.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7f2edda0240dc472175a3407be27e83f89e4418e Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/thumbs/large.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/thumbs/moravec.jpg b/isis/src/base/apps/interestcube/assets/thumbs/moravec.jpg new file mode 100644 index 0000000000000000000000000000000000000000..718e621de5e23dd1a56e7dafbdb4fa3ecd933492 Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/thumbs/moravec.jpg differ diff --git a/isis/src/base/apps/interestcube/assets/thumbs/stddev.jpg b/isis/src/base/apps/interestcube/assets/thumbs/stddev.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bdfb2b302b1c52a75c1b73032780169badd30198 Binary files /dev/null and b/isis/src/base/apps/interestcube/assets/thumbs/stddev.jpg differ diff --git a/isis/src/base/apps/interestcube/interestcube.cpp b/isis/src/base/apps/interestcube/interestcube.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bb664c952db2cf4b40e2e4caf69e7c0a243c57a9 --- /dev/null +++ b/isis/src/base/apps/interestcube/interestcube.cpp @@ -0,0 +1,73 @@ +#include "Isis.h" +#include "InterestOperator.h" +#include "InterestOperatorFactory.h" +#include "ProcessByBrick.h" +#include "Pixel.h" +#include "Cube.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void Operate(Isis::Buffer &in, Isis::Buffer &out); + +InterestOperator *iop; +Cube cube; +int boxcarLines, boxcarSamples; +UniversalGroundMap *unvGMap; + +void IsisMain() { + // We will be processing by line + ProcessByBrick p; + p.SetBrickSize(1,1,1); + p.SetOutputBrickSize(1,1,1); + UserInterface &ui = Application::GetUserInterface(); + + // Basic settings + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + Pvl pvl = Pvl(ui.GetFilename("PVL")); + + cube.Open(ui.GetFilename("FROM")); + + try { + // Get info from the operator group + // Set the pvlkeywords that need to be set to zero + PvlGroup &op = pvl.FindGroup("Operator",Pvl::Traverse); + boxcarSamples = op["Samples"]; + boxcarLines = op["Lines"]; + op["DeltaLine"]=0; + op["DeltaSamp"]=0; + op["MinimumInterest"]=0.0; + Application::Log(op); + } catch (iException &e) { + std::string msg = "Improper format for InterestOperator PVL ["+pvl.Filename()+"]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + iop = InterestOperatorFactory::Create(pvl); + + // Get the universal ground map of this cube + unvGMap = new UniversalGroundMap(cube); + + // Start the processing + p.StartProcess(Operate); + p.EndProcess(); + + delete unvGMap; +} + +// Call Operate once per pixel to get the interest for every pixel in the input cube. +void Operate(Isis::Buffer &in, Isis::Buffer &out) { + try { + int sample = in.Sample(); + int line = in.Line(); + + iop->Operate(cube, *unvGMap, sample, line); + + out[0] = iop->InterestAmount(); + + } catch (iException &e) { + e.Report(); + } +} diff --git a/isis/src/base/apps/interestcube/interestcube.xml b/isis/src/base/apps/interestcube/interestcube.xml new file mode 100644 index 0000000000000000000000000000000000000000..e8252c48178278a7e034a18d11d84077dbee85fc --- /dev/null +++ b/isis/src/base/apps/interestcube/interestcube.xml @@ -0,0 +1,468 @@ + + + + + + Used to test Interest Operators + + + + This program will use an interest operator specified by the user + to evaluate the interest of an entire cube and output the interest + in a cube full of interest values. It uses the same PVL format + used for Interest Operator. Note: forstner operator output will + need to be manually stretched to see visual results, due to the + wide range of values it creates. + + + + + Original version + + + Renamed app from "Interest" -> "interest" + + + Renamed app from "interest" -> "interestcube" + + + Create a universal ground map of the input cube to be passed onto the + Interest Operator to calculate the Emission Angle + + + + + Filters + + + + + + cube + input + + Input cube + + + Use this parameter to select the input cube. + + + *.cub + + + + + filename + input + + Input pvl + + + Use this parameter to select the pvl file that gives the program parameters. + Note: to make the program function properly the delta keywords and valid interest + keyword will be changed to a value of 0. + + + + + cube + real + output + + Output cube + + + This cube will contain the results of the Interest Operator. + + + + + + + + + Using interestcube with forstner operator + + + The use of Interst to ingest an Isis 3 cube and output a cube with interest values. + + + + from= ab102401.cub + pvl= input.pvl + to= out.cub + + + This example shows the use of interestcube to create an Isis3 cube of interest + values from a + standard Isis 3 cube. This example will use a 3x3 boxcar using the ForstnerOperator. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters + + + + + + + + + + Input Isis 3 cube. + + + The input cube that the Interest Operator is to run on. + + + FROM + + + + + + + Input pvl file. + + + This is the pvl file that defines how the program is to operate. + + PVL + + + + + + + Output image after processing. + + + The interest cube image after processing. To view a forstner image you MUST manually + stretch the image. This image has been stretched from 0 to 1.67854e-27. Keep in mind + if you dont do this, the data in the cube will be valid, it will just display all white in qview. + + + TO + + + + + + + Using interestcube with gradient operator + + + The use of Interst to ingest an Isis 3 cube and output a cube with interest values. + + + + from= ab102401.cub + pvl= input.pvl + to= out.cub + + + This example shows the use of interestcube to create an Isis3 cube of interest + values from a + standard Isis 3 cube. This example will use a 3x3 boxcar using the Gradient Operator. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters + + + + + + + + + + Input Isis 3 cube. + + + The input cube that the Interest Operator is to run on. + + + FROM + + + + + + + Input pvl file. + + + This is the pvl file that defines how the program is to operate. + + PVL + + + + + + + Output image after processing. + + + The interest cube image after processing. + + + TO + + + + + + + Using interestcube with Moravec operator + + + The use of Interst to ingest an Isis 3 cube and output a cube with interest values. + + + + from= ab102401.cub + pvl= input.pvl + to= out.cub + + + This example shows the use of interestcube to create an Isis3 cube of interest + values from a + standard Isis 3 cube. This example will use a 3x3 boxcar using the Moravec Operator. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters + + + + + + + + + + Input Isis 3 cube. + + + The input cube that the Interest Operator is to run on. + + + FROM + + + + + + + Input pvl file. + + + This is the pvl file that defines how the program is to operate. + + PVL + + + + + + + Output image after processing. + + + The interest cube image after processing. + + + TO + + + + + + + Using interestcube with Standard Deviation operator + + + The use of Interst to ingest an Isis 3 cube and output a cube with interest values. + + + + from= ab102401.cub + pvl= input.pvl + to= out.cub + + + This example shows the use of interestcube to create an Isis3 cube of interest + values from a + standard Isis 3 cube. This example will use a 3x3 boxcar using the Standard Deviation Operator. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters + + + + + + + + + + Input Isis 3 cube. + + + The input cube that the Interest Operator is to run on. + + + FROM + + + + + + + Input pvl file. + + + This is the pvl file that defines how the program is to operate. + + PVL + + + + + + + Output image after processing. + + + The interest cube image after processing. + + + TO + + + + + + + Using interestcube with a Large Boxcar + + + The use of Interst to ingest an Isis 3 cube and output a cube with interest values. This + uses StandardDeviationOperator and a large boxcar to show the blurring affect of using + a larger boxcar. + + + + from= ab102401.cub + pvl= input.pvl + to= out.cub + + + This example shows the use of interestcube to create an Isis3 cube of + interest values from a standard Isis 3 cube. This example will use a 15x15 + boxcar using the StandardDeviationOperator. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters + + + + + + + + + + Input Isis 3 cube. + + + The input cube that the Interest Operator is to run on. + + + FROM + + + + + + + Input pvl file. + + + This is the pvl file that defines how the program is to operate. + + PVL + + + + + + + Output image after processing. + + + The interest cube image after processing. You can see how the interest + areas are slightly blured due to the large boxcar size. + + + TO + + + + + + diff --git a/isis/src/base/apps/interestcube/tsts/Makefile b/isis/src/base/apps/interestcube/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/interestcube/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/interestcube/tsts/forstner/Makefile b/isis/src/base/apps/interestcube/tsts/forstner/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a2656ec3f28d2ded64b706df6eadc5b0f836d762 --- /dev/null +++ b/isis/src/base/apps/interestcube/tsts/forstner/Makefile @@ -0,0 +1,9 @@ +APPNAME = interestcube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/ab102401.cub \ + PVL=$(INPUT)/input.pvl \ + TO=$(OUTPUT)/Forstner.cub \ + > /dev/null; diff --git a/isis/src/base/apps/interestcube/tsts/gradient/Makefile b/isis/src/base/apps/interestcube/tsts/gradient/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..69ba6e38e09c4f6204172a513ab72f88418ac903 --- /dev/null +++ b/isis/src/base/apps/interestcube/tsts/gradient/Makefile @@ -0,0 +1,9 @@ +APPNAME = interestcube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/ab102401.cub \ + PVL=$(INPUT)/input.pvl \ + TO=$(OUTPUT)/GradientTruth.cub \ + > /dev/null; diff --git a/isis/src/base/apps/interestcube/tsts/moravec/Makefile b/isis/src/base/apps/interestcube/tsts/moravec/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..315e9595d30e6f5e75395fa9407b9c7133e22445 --- /dev/null +++ b/isis/src/base/apps/interestcube/tsts/moravec/Makefile @@ -0,0 +1,9 @@ +APPNAME = interestcube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/ab102401.cub \ + PVL=$(INPUT)/input.pvl \ + TO=$(OUTPUT)/MoravecTruth.cub \ + > /dev/null; diff --git a/isis/src/base/apps/interestcube/tsts/standarddeviation/Makefile b/isis/src/base/apps/interestcube/tsts/standarddeviation/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f1b67e0b2e5c5523b19a9e95bb958b550f252021 --- /dev/null +++ b/isis/src/base/apps/interestcube/tsts/standarddeviation/Makefile @@ -0,0 +1,9 @@ +APPNAME = interestcube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/ab102401.cub \ + PVL=$(INPUT)/input.pvl \ + TO=$(OUTPUT)/StandardDeviationTruth.cub \ + > /dev/null; diff --git a/isis/src/base/apps/isis2ascii/Makefile b/isis/src/base/apps/isis2ascii/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/isis2ascii/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/isis2ascii/assets/image/f332s28.jpg b/isis/src/base/apps/isis2ascii/assets/image/f332s28.jpg new file mode 100644 index 0000000000000000000000000000000000000000..112512e5ef0dc4bdaedf906c5c5d868e786bba75 Binary files /dev/null and b/isis/src/base/apps/isis2ascii/assets/image/f332s28.jpg differ diff --git a/isis/src/base/apps/isis2ascii/assets/image/isis2asciiGui.jpg b/isis/src/base/apps/isis2ascii/assets/image/isis2asciiGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c81aa17936613c1c28f2c6139f498398f0f41b23 Binary files /dev/null and b/isis/src/base/apps/isis2ascii/assets/image/isis2asciiGui.jpg differ diff --git a/isis/src/base/apps/isis2ascii/assets/image/isis2asciiTxt.jpg b/isis/src/base/apps/isis2ascii/assets/image/isis2asciiTxt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fed26390764c241069e1a0b6ace595971da3e54d Binary files /dev/null and b/isis/src/base/apps/isis2ascii/assets/image/isis2asciiTxt.jpg differ diff --git a/isis/src/base/apps/isis2ascii/assets/thumb/f332s28.jpg b/isis/src/base/apps/isis2ascii/assets/thumb/f332s28.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8a49c02a1335a9fc5d7abb4224fc6132f4ea32dd Binary files /dev/null and b/isis/src/base/apps/isis2ascii/assets/thumb/f332s28.jpg differ diff --git a/isis/src/base/apps/isis2ascii/assets/thumb/isis2asciiGui.jpg b/isis/src/base/apps/isis2ascii/assets/thumb/isis2asciiGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4a8b9913497bf7c2a6e2e120681cabb731cc8b8f Binary files /dev/null and b/isis/src/base/apps/isis2ascii/assets/thumb/isis2asciiGui.jpg differ diff --git a/isis/src/base/apps/isis2ascii/assets/thumb/isis2asciiTxt.jpg b/isis/src/base/apps/isis2ascii/assets/thumb/isis2asciiTxt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..35a901d1aafed1f5fd78621f038103bffd5032d1 Binary files /dev/null and b/isis/src/base/apps/isis2ascii/assets/thumb/isis2asciiTxt.jpg differ diff --git a/isis/src/base/apps/isis2ascii/isis2ascii.cpp b/isis/src/base/apps/isis2ascii/isis2ascii.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b19a711674733d10a474e9ea0c3f9bcb9a6b00b --- /dev/null +++ b/isis/src/base/apps/isis2ascii/isis2ascii.cpp @@ -0,0 +1,55 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "Filename.h" + +using namespace std; +using namespace Isis; + +// Global declarations +void isis2ascii (Buffer &in); +ofstream fout; + +void IsisMain() { + // Create a process by line object + ProcessByLine p; + + // Get the size of the cube + Cube *icube = p.SetInputCube("FROM"); + + // Open output text file + UserInterface &ui = Application::GetUserInterface(); + string to = ui.GetFilename("TO","txt"); + fout.open (to.c_str()); + + // Print header if needed + if (ui.GetBoolean("HEADER")) { + fout << "Input Cube: " << icube->Filename () << endl; + fout << "Samples:Lines:Bands: " << icube->Samples () << ":" << + icube->Lines () << ":" << icube->Bands () << endl; + } + + // List the cube + p.StartProcess(isis2ascii); + p.EndProcess(); + + fout.close (); +} + +void isis2ascii (Buffer &in) { + for (int i=0; i + + Export cube to an ascii file + + + This program will print the cube data to an ascii file. Special pixels will be represented + as NULL, LIS, LRS, HIS and HRS. If you do not want special pixels in your ascii output, + run the program "stretch" to replace their value. If there are multiple bands in the cube, + they will be output in band sequential format. Beware: The output file will be roughly + 3 times as big as the input. + + + + Import and Export + + + + list + cube2ascii + + + + + Original version + + + Fixed bug-was writing LRS for LIS values. + + + Add example + + + Remove from Utility category. + + + Make images smaller. + + + Add /image and /thumb directory. + + + Added-lien:Use IsisString class when outputing pixel values. + + + Fixed problem with isiscvs not checking in the thumb and image directories. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Changed default extension handling mechanism + + + Documentation fixes + + + Removed references to CubeInfo + + + + + + + + cube + input + Input cube + + The file name of the input cube to be listed. + + *.cub + + + filename + output + Output ascii file + + The file name of the ascii output file. + + *.txt + + + + + boolean + Print header + + If set to yes, a brief header will be printed to + the ascii file which will include the cube name + and dimensions. + + + YES + + + + + + + + Use IsisString class when outputing pixel values. + + + + + + Header default + Demonstrate the isis2ascii application with header + + + f=../IN/f332s28.cub t=OUT/isis2ascii.txt + Convert Viking ISIS image to ascii file. Let header default to yes. + + + + + Input image for isis2ascii + This is the input image f332s28.cub to be converted to ascii. + + + FROM + + + + + Example output ascii text from isis2ascii run + This is the output ascii text file isis2ascii.txt with the header. + + + TO + + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform +the isis2ascii application + + + + + + + + + + + diff --git a/isis/src/base/apps/isis2ascii/tsts/Makefile b/isis/src/base/apps/isis2ascii/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/isis2ascii/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/isis2ascii/tsts/case01/Makefile b/isis/src/base/apps/isis2ascii/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..edc204a3eb764c9b5ccb21ec4d5b33da99d0c5b5 --- /dev/null +++ b/isis/src/base/apps/isis2ascii/tsts/case01/Makefile @@ -0,0 +1,9 @@ +APPNAME = isis2ascii + +include $(ISISROOT)/make/isismake.tsts + +isis2asciiTruth.txt.SKIPLINES = 1 + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/isis2asciiTruth.txt > /dev/null; diff --git a/isis/src/base/apps/isis2fits/Makefile b/isis/src/base/apps/isis2fits/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/isis2fits/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/isis2fits/isis2fits.cpp b/isis/src/base/apps/isis2fits/isis2fits.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42188ef2bf313f40b7c38e18560408569c61e77f --- /dev/null +++ b/isis/src/base/apps/isis2fits/isis2fits.cpp @@ -0,0 +1,248 @@ +//************************************************************************ +// See Full documentation in isis2fits.xml +//************************************************************************ +#include "Isis.h" + +#include +#include + +#include "iException.h" +#include "iString.h" +#include "ProcessExport.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "PvlKeyword.h" +#include "PvlSequence.h" +#include "UserInterface.h" + +using namespace std; +using namespace Isis; + +// Global variables +int headerBytes = 0; + +string FitsKeyword(string keyword, bool isVal, Isis::iString value, Isis::iString unit = ""); + +string WritePvl(string fitsKey, string group, iString key, Cube *icube, bool isString); + +// Main program +void IsisMain(){ + + // Create an object for exporting Isis data + ProcessExport p; + // Open the input cube + Cube *icube = p.SetInputCube("FROM"); + + // Conform to the Big-Endian format for FITS + if(IsLsb()) p.SetOutputEndian(Isis::Msb); + + // Generate the name of the fits file and open it + UserInterface &ui = Application::GetUserInterface(); + + // specify the bits per pixel + string bitpix; + if (ui.GetString ("BITTYPE") == "8BIT") bitpix = "8"; + else if (ui.GetString ("BITTYPE") == "16BIT") bitpix = "16"; + else if (ui.GetString ("BITTYPE") == "32BIT") bitpix = "-32"; + else { + string msg = "Pixel type of [" + ui.GetString("BITTYPE") + "] is unsupported"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + // Determine bit size and calculate number of bytes to write + // for each line. + if (bitpix == "8") p.SetOutputType(Isis::UnsignedByte); + if (bitpix == "16") p.SetOutputType(Isis::SignedWord); + if (bitpix == "-32") p.SetOutputType(Isis::Real); + + // determine core base and multiplier, set up the stretch + PvlGroup pix = icube->Label()->FindObject("IsisCube").FindObject("Core").FindGroup("Pixels"); + double scale = pix["Multiplier"][0].ToDouble(); + double base = pix["Base"][0].ToDouble(); + + if (ui.GetString("STRETCH") != "NONE" && bitpix != "-32") { + if (ui.GetString("STRETCH") == "LINEAR") { + p.SetInputRange(); + } + else if (ui.GetString("STRETCH") == "MANUAL") { + p.SetInputRange(ui.GetDouble("MINIMUM"), ui.GetDouble("MAXIMUM")); + } + + // create a proper scale so pixels look like 32bit data. + scale = ((p.GetInputMaximum() - p.GetInputMinimum()) * + (p.GetOutputMaximum() - p.GetOutputMinimum())); + + // round off after 14 decimals to avoid system architecture differences + scale = ((floor(scale * 1e14)) / 1e14); + + // create a proper zero point so pixels look like 32bit data. + base = -1.0 * (scale * p.GetOutputMinimum()) + p.GetInputMinimum(); + // round off after 14 decimals to avoid system architecture differences + base = ((floor(base * 1e14)) / 1e14); + } + + + ////////////////////////////////////////// + // Write the minimal fits header // + ////////////////////////////////////////// + string header; + + // specify that this file conforms to simple fits standard + header += FitsKeyword("SIMPLE", true, "T"); + + + // specify the bits per pixel + header += FitsKeyword("BITPIX", true, bitpix); + + // specify the number of data axes (2: samples by lines) + int axes = 2; + if (icube->Bands() > 1) { + axes = 3; + } + + header += FitsKeyword("NAXIS", true, iString(axes)); + + // specify the limit on data axis 1 (number of samples) + header += FitsKeyword("NAXIS1", true, iString(icube->Samples())); + + // specify the limit on data axis 2 (number of lines) + header += FitsKeyword("NAXIS2", true, iString(icube->Lines())); + + if (axes == 3){ + header += FitsKeyword("NAXIS3", true, iString(icube->Bands())); + } + + header += FitsKeyword("BZERO", true, base); + + header += FitsKeyword("BSCALE", true, scale); + + // Sky and All cases + if (ui.GetString("INFO") == "SKY" || ui.GetString("INFO") == "ALL") { + iString msg = "cube has not been skymapped"; + PvlGroup map; + + if (icube->HasGroup("mapping")) { + map = icube->GetGroup("mapping"); + msg = (string)map["targetname"]; + } + // If we have sky we want it + if (msg == "Sky") { + double midRa = 0, midDec = 0; + + midRa = ((double)map["MaximumLongitude"] + + (double)map["MinimumLongitude"])/2; + + midDec = ((double)map["MaximumLatitude"] + + (double)map["MinimumLatitude"])/2; + + header += FitsKeyword("OBJCTRA", true, iString(midRa)); + + // Specify the Declination + header += FitsKeyword("OBJCTDEC", true, iString(midDec)); + + } + + if (ui.GetString("INFO") == "ALL") { + header += WritePvl("INSTRUME","Instrument","InstrumentId", icube, true); + header += WritePvl("OBSERVER","Instrument","SpacecraftName", icube, true); + header += WritePvl("OBJECT ","Instrument","TargetName", icube, true); + // StartTime is sometimes middle of the exposure and somtimes beginning, + // so StopTime can't be calculated off of exposure reliably. + header += WritePvl("DATE-OBS","Instrument","StartTime", icube, true); + // Some cameras don't have StopTime + if (icube->HasGroup("Instrument")) { + PvlGroup inst = icube->GetGroup("Instrument"); + if (inst.HasKeyword("StopTime")) { + header += WritePvl("TIME_END","Instrument","StopTime", icube, true); + } + if (inst.HasKeyword("ExposureDuration")) { + header += WritePvl("EXPTIME","Instrument","ExposureDuration", icube, false); + } + } + } + // If we were set on SKY and Sky doesn't exist + else if (msg != "Sky") { + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + // signal the end of the header + header += FitsKeyword("END", false, ""); + + // fill the rest of the fits header with space so to conform with the fits header + // size of 2880 bytes + for (int i = header.length() % 2880 ; i < 2880 ; i++) header += " "; + + // open the cube for writing + string to = ui.GetFilename("TO","fits"); + ofstream fout; + fout.open (to.c_str (), ios::out|ios::binary); + if (!fout.is_open ()) { + string msg = "Cannot open fits output file"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + fout.seekp(0); + fout.write(header.c_str(),header.length()); + // write the raw cube data + p.StartProcess (fout); + + // Finish off data area to a number n % 2880 == 0 is true + // 2880 is the size of the data blocks + int count = 2880 - (fout.tellp() % 2880); + for (int i = 0; i < count; i++) { + // Write nul characters as needed. ascii 0, hex 00... + fout.write("\0", 1); + } + fout.close(); + p.EndProcess(); +} + +string FitsKeyword(string key, bool isValue, Isis::iString value, Isis::iString unit) { + // pad the keyword with space + for (int i = key.length() ; i < 8 ; i++) + key += " "; + + // add the value indicator (or lack thereof) + if (isValue) + key += "= "; + else + key += " "; + + // right-justify the value + if (value.length() < 70){ + // pad the left part of the value with space + for (int i = value.length() ; i < 20 ; i++) + key += " "; + + // add the actual value + key += value; + if (isValue) { + key += " / "; + if (unit != "") { + key += "[" + unit + "]"; + } + } + + // finish the line by padding the rest of the space + for (int i = key.length() ; i < 80 ; i++) + key += " "; + } + + // record the total length of the header + headerBytes += key.length(); + return key; +} + +string WritePvl(string fitsKey, string group, iString key, Cube *icube, bool isString) { + if(icube->HasGroup(group)){ + PvlGroup theGroup = icube->GetGroup(group); + iString name = (string)theGroup[key]; + if (isString) { + name = "'" + name + "'"; + } + iString unit = theGroup[key].Unit(); + return FitsKeyword(fitsKey, true, name, unit); + } + return NULL; +} diff --git a/isis/src/base/apps/isis2fits/isis2fits.xml b/isis/src/base/apps/isis2fits/isis2fits.xml new file mode 100644 index 0000000000000000000000000000000000000000..1e07788d43cf064e0f3cf6da8fbccd97a98ab7c5 --- /dev/null +++ b/isis/src/base/apps/isis2fits/isis2fits.xml @@ -0,0 +1,288 @@ + + + + + + Exports a cube to fits format + + + + This program will export an Isis cube to fits format. It is recommended + that the image be output in 32-bit per pixel format. The user may also + choose to output into an 8-bit, 16-bit unsigned, or 16-bit signed image but + in order to ensure that the range of pixels is not truncated when going to + a less precise format, it is recommended that the output file be stretched + using a linear stretch. Special pixels are mapped in the following manner; + Low Saturation values and Null are made black and High Saturation values + are made white. + + + + + Original version + + + Added code to export multiple bands + + + Added minpercent and maxpercent options + + + Updated documentation to follow current standards + + + Removed references to CubeInfo + + + Made SkyMap and All options work, added more keywords to ALL option, + removed unsigned 16 bit option, made file total come out to a sum evenly + divisible by 2880 as specified in the standard. + + + + + + Import and Export + + + + + isis2jpg + isis2tiff + isis2raw + + + + + + + cube + input + + Input cube to export + + + Use this parameter to select the filename and band to export. For + example, file.cub+5 will select band 5 + + + *.cub + + + + + filename + output + + Output fits file + + + Use this parameter to specify the name of the output fits file. If you + do not include an extension of ".fits" it will be added automatically. + + + + + + + string + + 32BIT + + Bit type of output file + + Bit type of output: + 8 bit (0=black, 255=white) + 16 bit unsigned (0=black, 65535=white) + 16 bit signed (-32767=black, 32768=white) + 32 bit (1.17549435e-38=black, 3.40282347e+38=white) + + + + + + + + + + + + string + + LINEAR + + Type of stretch + + This parameter is used to select one of four ways to stretch + (or map) output pixels. They are NONE, LINEAR, or MANUAL. It is + recommended that output data that is less precise than the input data + from whence it came (i.e. 32-bit data being output as 8-bit data) be + stretched. + + + + + + + + + + + double + Minimum pixel value + + The minimum input pixel value which will be mapped to black. + + + MAXIMUM + + + + + double + Maximum pixel value + + The maximum input pixel value which will be mapped to white. + + + MINIMUM + + + + + double + Minimum Percent + + The percentage of data in the histogram used to compute the minimum pixel value in the stretch. + + 0.5 + + MAXPERCENT + + + + + double + Maximum Percent + + The percentage of data in the histogram used to compute the maximum pixel value in the stretch. + + 99.5 + + MINPERCENT + + + + + + + string + NOMINAL + Level of information in the header (nominal, projection) + + This parameter is used to determine how much information will appear + in the FITS header. Minimally, the header will include the information + necessary to conform to the FITS header, which conveniently also + allows it to be read by a FITS file reader. This is automatically read + from the cube label. + + + + + + + + + + + diff --git a/isis/src/base/apps/isis2fits/tsts/8bit/Makefile b/isis/src/base/apps/isis2fits/tsts/8bit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..907af578be867e1634872d4be9b7e14694ab98e3 --- /dev/null +++ b/isis/src/base/apps/isis2fits/tsts/8bit/Makefile @@ -0,0 +1,14 @@ +APPNAME = isis2fits + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/isis2fitsTruth4.fits \ + bittype= 8BIT > /dev/null; + raw2isis from=$(OUTPUT)/isis2fitsTruth4.fits \ + to=$(OUTPUT)/isis2fitsTruth4.cub SAMPLES=126 \ + LINES=126 BANDS=2 SKIP=2880 BITTYPE=UNSIGNEDBYTE \ + BYTEORDER=LSB > /dev/null; + dd bs=2880 count=1 if=$(OUTPUT)/isis2fitsTruth4.fits > $(OUTPUT)/labels.txt 2> /dev/null; + $(RM) $(OUTPUT)/isis2fitsTruth4.fits; > /dev/null; diff --git a/isis/src/base/apps/isis2fits/tsts/Makefile b/isis/src/base/apps/isis2fits/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/isis2fits/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/isis2fits/tsts/default/Makefile b/isis/src/base/apps/isis2fits/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6c497f7ed63acaf8e063fe7f7059b4b172204492 --- /dev/null +++ b/isis/src/base/apps/isis2fits/tsts/default/Makefile @@ -0,0 +1,12 @@ +APPNAME = isis2fits + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2fitsTruth1.fits > /dev/null; + raw2isis from=$(OUTPUT)/isis2fitsTruth1.fits \ + to=$(OUTPUT)/isis2fitsTruth1.cub BITTYPE=REAL SAMPLES=126 \ + LINES=126 BANDS=1 SKIP=2880 BYTEORDER=MSB > /dev/null; + dd bs=2880 count=1 if=$(OUTPUT)/isis2fitsTruth1.fits > $(OUTPUT)/labels.txt 2> /dev/null; + $(RM) $(OUTPUT)/isis2fitsR\Truth1.fits; > /dev/null; diff --git a/isis/src/base/apps/isis2fits/tsts/manual/Makefile b/isis/src/base/apps/isis2fits/tsts/manual/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a8c485a93a3ec947d31b3f6a81c1d503e94a8e02 --- /dev/null +++ b/isis/src/base/apps/isis2fits/tsts/manual/Makefile @@ -0,0 +1,17 @@ +APPNAME = isis2fits + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2fitsTruth7.fits \ + bittype= 16BIT \ + stretch= manual \ + minimum = 0 \ + maximum = 65535 > /dev/null; + raw2isis from=$(OUTPUT)/isis2fitsTruth7.fits \ + to=$(OUTPUT)/truth.cub \ + SAMPLES=126 LINES=126 BANDS=1 SKIP=2880 \ + BITTYPE=UNSIGNEDWORD BYTEORDER=MSB > /dev/null; + dd bs=2880 count=1 if=$(OUTPUT)/isis2fitsTruth7.fits > $(OUTPUT)/labels.txt 2> /dev/null; + $(RM) $(OUTPUT)/isis2fitsTruth7.fits; > /dev/null; diff --git a/isis/src/base/apps/isis2fits/tsts/multiBand/Makefile b/isis/src/base/apps/isis2fits/tsts/multiBand/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c6f5eb16076d7c736edec7c4ada7872bccd9fe85 --- /dev/null +++ b/isis/src/base/apps/isis2fits/tsts/multiBand/Makefile @@ -0,0 +1,15 @@ +APPNAME = isis2fits + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isis2fitsTruthMultiBand.cub \ + to=$(OUTPUT)/isis2fitsTruth6.fits \ + bittype= 16BIT > /dev/null; + raw2isis from=$(OUTPUT)/isis2fitsTruth6.fits \ + to=$(OUTPUT)/truth.cub \ + SAMPLES=640 LINES=768 BANDS=3 SKIP=2880 \ + BITTYPE=SIGNEDWORD BYTEORDER=MSB > /dev/null; + dd bs=2880 count=1 if=$(OUTPUT)/isis2fitsTruth6.fits > \ + $(OUTPUT)/labels.txt 2> /dev/null; + $(RM) $(OUTPUT)/isis2fitsTruth6.fits; > /dev/null; diff --git a/isis/src/base/apps/isis2fits/tsts/noStretch/Makefile b/isis/src/base/apps/isis2fits/tsts/noStretch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ca4eba310769965043ea3a84557a50483a1ba00a --- /dev/null +++ b/isis/src/base/apps/isis2fits/tsts/noStretch/Makefile @@ -0,0 +1,15 @@ +APPNAME = isis2fits + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2fitsTruth5.fits \ + bittype= 8BIT \ + stretch= none > /dev/null; + raw2isis from=$(OUTPUT)/isis2fitsTruth5.fits \ + to=$(OUTPUT)/truth.cub \ + SAMPLES=126 LINES=126 BANDS=1 SKIP=2880 \ + BITTYPE=UNSIGNEDBYTE BYTEORDER=MSB > /dev/null; + dd bs=2880 count=1 if=$(OUTPUT)/isis2fitsTruth5.fits > $(OUTPUT)/labels.txt 2> /dev/null; + $(RM) $(OUTPUT)/ifif2fitsTruth5.fits; > /dev/null; diff --git a/isis/src/base/apps/isis2fits/tsts/signed16/Makefile b/isis/src/base/apps/isis2fits/tsts/signed16/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..62b50810048c22773b5de0eb2be57702412c38d7 --- /dev/null +++ b/isis/src/base/apps/isis2fits/tsts/signed16/Makefile @@ -0,0 +1,14 @@ +APPNAME = isis2fits + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isis2fitsTruth.cub \ + to=$(OUTPUT)/isis2fitsTruth2.fits \ + bittype= 16BIT > /dev/null; + raw2isis from=$(OUTPUT)/isis2fitsTruth2.fits \ + to=$(OUTPUT)/truth.cub \ + SAMPLES=640 LINES=768 BANDS=1 SKIP=2880 \ + BITTYPE=SIGNEDWORD BYTEORDER=MSB > /dev/null; + dd bs=2880 count=1 if=$(OUTPUT)/isis2fitsTruth2.fits > $(OUTPUT)/labels.txt 2> /dev/null; + $(RM) $(OUTPUT)/isis2fitsTruth2.fits > /dev/null; diff --git a/isis/src/base/apps/isis2gml/Makefile b/isis/src/base/apps/isis2gml/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/isis2gml/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/isis2gml/isis2gml.cpp b/isis/src/base/apps/isis2gml/isis2gml.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03dd5cf898764b2033faceafcf1b915c0180e4b7 --- /dev/null +++ b/isis/src/base/apps/isis2gml/isis2gml.cpp @@ -0,0 +1,60 @@ +#include "Isis.h" + +#include + +#include "geos/geom/MultiPolygon.h" +#include "UserInterface.h" +#include "Filename.h" +#include "Cube.h" +#include "ImagePolygon.h" +#include "PolygonTools.h" + +using namespace std; +using namespace Isis; + +void IsisMain(){ + + + UserInterface &ui = Application::GetUserInterface(); + + Cube cube; + cube.Open(ui.GetFilename("FROM")); + ImagePolygon poly; + poly.Create(cube); + + geos::geom::MultiPolygon *mPolygon = poly.Polys(); + + std::string polyString; + + if(ui.WasEntered("LABEL")) { + string fid = ui.GetString("LABEL"); + polyString = PolygonTools::ToGML(mPolygon, fid); + } + else { + polyString = PolygonTools::ToGML(mPolygon); + } + + string outfile; + ofstream fout; + if (ui.WasEntered("TO")) { + outfile = ui.GetFilename("TO"); + } + else { + Filename inputFile = ui.GetFilename("FROM"); + inputFile.RemoveExtension(); + inputFile.AddExtension("gml"); + outfile = inputFile.Name(); + } + fout.open (outfile.c_str()); + + fout << polyString << endl; + + // fout.open(Filename(outfile).Expanded().c_str(),ios::out); + fout.close(); + + + +} + + + diff --git a/isis/src/base/apps/isis2gml/isis2gml.xml b/isis/src/base/apps/isis2gml/isis2gml.xml new file mode 100644 index 0000000000000000000000000000000000000000..1fd4603e3422b7202b41ff275ab23d2355b405e7 --- /dev/null +++ b/isis/src/base/apps/isis2gml/isis2gml.xml @@ -0,0 +1,73 @@ + + + + + + output a GML polygon from an ISIS cube + + + + This program calculates a lat. lon polygon and outputs a graphical markup + language(GML) file. the input to this program can be in camera space (level1) or + a map projected image (level2). the output is a lat. lon. polygon with a GML header. + The user can use the label parameter to add a value to the ID tag in the header. + The ID tag is used by some GIS packages to produce a text label for the footprint. + + + + + Original version + + + + + Import and Export + + + + + + cube + input + + Input file + + + Input cube to use in polygon generation + + + *.cub *.CUB + + + + filename + output + + GML formatted polygon + + None + + Use this parameter to specify the name of the output image. the output file + is a lon. lat. polygon with a geographic markup language (GML) header. + + + *.gml *.GML + + + + + + string + + Added to the header in ID tag + + + This value is placed in the GML header within theID tags. The information within + the ID tag is used by arcmap to allows the user to utilize a labeling switch that displays + the ID of the footprint. + + + + + + diff --git a/isis/src/base/apps/isis2gml/tsts/Makefile b/isis/src/base/apps/isis2gml/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/isis2gml/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/isis2gml/tsts/case01/Makefile b/isis/src/base/apps/isis2gml/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..28ff0b7e707536f879965ec25f291223916ffc01 --- /dev/null +++ b/isis/src/base/apps/isis2gml/tsts/case01/Makefile @@ -0,0 +1,10 @@ +APPNAME = isis2gml + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(CP) $(INPUT)/ab102401.cub $(OUTPUT)/ab102401.cub; + $(APPNAME) from=$(OUTPUT)/ab102401.cub \ + to=$(OUTPUT)/ab102401gml.txt \ + label= "appTest" > /dev/null; + $(RM) $(OUTPUT)/ab102401.cub diff --git a/isis/src/base/apps/isis2pds/Makefile b/isis/src/base/apps/isis2pds/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/isis2pds/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/isis2pds/assets/images/gui.jpg b/isis/src/base/apps/isis2pds/assets/images/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..86854e508baa1daed07450857dd56eac982b11c5 Binary files /dev/null and b/isis/src/base/apps/isis2pds/assets/images/gui.jpg differ diff --git a/isis/src/base/apps/isis2pds/assets/images/input.jpg b/isis/src/base/apps/isis2pds/assets/images/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..40636f44140a48df90d975881767e6b55afae4f1 Binary files /dev/null and b/isis/src/base/apps/isis2pds/assets/images/input.jpg differ diff --git a/isis/src/base/apps/isis2pds/assets/images/output.jpg b/isis/src/base/apps/isis2pds/assets/images/output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..40636f44140a48df90d975881767e6b55afae4f1 Binary files /dev/null and b/isis/src/base/apps/isis2pds/assets/images/output.jpg differ diff --git a/isis/src/base/apps/isis2pds/assets/thumbs/gui.jpg b/isis/src/base/apps/isis2pds/assets/thumbs/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9df50b3b9daf0b671d7b81af02d9e8d0173001aa Binary files /dev/null and b/isis/src/base/apps/isis2pds/assets/thumbs/gui.jpg differ diff --git a/isis/src/base/apps/isis2pds/assets/thumbs/input.jpg b/isis/src/base/apps/isis2pds/assets/thumbs/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a1794a0a7c6938675da4b42003ad51cc8387c3b7 Binary files /dev/null and b/isis/src/base/apps/isis2pds/assets/thumbs/input.jpg differ diff --git a/isis/src/base/apps/isis2pds/assets/thumbs/output.jpg b/isis/src/base/apps/isis2pds/assets/thumbs/output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a1794a0a7c6938675da4b42003ad51cc8387c3b7 Binary files /dev/null and b/isis/src/base/apps/isis2pds/assets/thumbs/output.jpg differ diff --git a/isis/src/base/apps/isis2pds/isis2pds.cpp b/isis/src/base/apps/isis2pds/isis2pds.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1f37388a1d5d27780d7d99af521c135ae8904c4 --- /dev/null +++ b/isis/src/base/apps/isis2pds/isis2pds.cpp @@ -0,0 +1,130 @@ +#include "Isis.h" +#include "ProcessExportPds.h" + +using namespace std; +using namespace Isis; + +enum Pixtype { NONE, NEG, BOTH }; + +void setRangeAndPixels( UserInterface &ui, ProcessExportPds &p, + double &min, double &max, Pixtype ptype ); +void IsisMain() { + // Set the processing object + ProcessExportPds p; + + // Setup the input cube + p.SetInputCube("FROM"); + + UserInterface &ui = Application::GetUserInterface(); + + if (ui.GetString ("STRETCH") == "LINEAR") { + if (ui.GetString ("BITTYPE") != "32BIT") + p.SetInputRange(); + } + if (ui.GetString ("STRETCH") == "MANUAL") + p.SetInputRange(ui.GetDouble("MINIMUM"), ui.GetDouble("MAXIMUM")); + + double min = -DBL_MAX; + double max = DBL_MAX; + + if (ui.GetString("BITTYPE") == "8BIT") { + p.SetOutputType(Isis::UnsignedByte); + min = 0.0; + max = 255.0; + setRangeAndPixels( ui, p, min, max, BOTH ); + } + else if (ui.GetString("BITTYPE") == "S16BIT") { + p.SetOutputType(Isis::SignedWord); + min = -32768.0; + max = 32767.0; + setRangeAndPixels( ui, p, min, max, NEG ); + } + else if (ui.GetString("BITTYPE") == "U16BIT") { + p.SetOutputType(Isis::UnsignedWord); + min = 0.0; + max = 65535.0; + setRangeAndPixels( ui, p, min, max, BOTH ); + } + else { + p.SetOutputType(Isis::Real); + p.SetOutputNull(Isis::NULL4); + p.SetOutputLrs(Isis::LOW_REPR_SAT4); + p.SetOutputLis(Isis::LOW_INSTR_SAT4); + p.SetOutputHrs(Isis::HIGH_REPR_SAT4); + p.SetOutputHis(Isis::HIGH_INSTR_SAT4); + setRangeAndPixels( ui, p, min, max, NONE ); + } + + if (ui.GetString("ENDIAN") == "MSB") + p.SetOutputEndian(Isis::Msb); + else if (ui.GetString("ENDIAN") == "LSB") + p.SetOutputEndian(Isis::Lsb); + + if (ui.GetString("LABTYPE") == "FIXED") + p.SetExportType ( ProcessExportPds::Fixed ); + + //Set the resolution to Kilometers + p.SetPdsResolution( ProcessExportPds::Kilometer ); + + p.StandardPdsLabel( ProcessExportPds::Image); + + Filename outFile(ui.GetFilename("TO", "img")); + string outFilename(outFile.Expanded()); + ofstream oCube(outFilename.c_str()); + p.OutputLabel(oCube); + p.StartProcess(oCube); + oCube.close(); + p.EndProcess(); + + //Records what it did to the print.prt file + PvlGroup results( "DNs Used" ); + results += PvlKeyword( "Null", p.OutputNull() ); + results += PvlKeyword( "LRS", p.OutputLrs() ); + results += PvlKeyword( "LIS", p.OutputLis() ); + results += PvlKeyword( "HIS", p.OutputHis() ); + results += PvlKeyword( "HRS", p.OutputHrs() ); + results += PvlKeyword( "ValidMin", min ); + results += PvlKeyword( "ValidMax", max ); + Application::Log( results ); + + return; +} + +//Sets up special pixels and valid pixel ranges +void setRangeAndPixels( UserInterface &ui, ProcessExportPds &p, double &min, double &max, Pixtype ptype ) { + if( ptype == NEG ) { + if ( ui.GetBoolean("NULL") ) { + p.SetOutputNull(min++); + } + if ( ui.GetBoolean("LRS") ) { + p.SetOutputLrs(min++); + } + if ( ui.GetBoolean("LIS") ) { + p.SetOutputLis(min++); + } + if ( ui.GetBoolean("HIS") ) { + p.SetOutputHis(min++); + } + if ( ui.GetBoolean("HRS") ) { + p.SetOutputHrs(min++); + } + } + else if( ptype == BOTH ) { + if ( ui.GetBoolean("NULL") ) { + p.SetOutputNull(min++); + } + if ( ui.GetBoolean("LRS") ) { + p.SetOutputLrs(min++); + } + if ( ui.GetBoolean("LIS") ) { + p.SetOutputLis(min++); + } + if ( ui.GetBoolean("HRS") ) { + p.SetOutputHrs(max--); + } + if ( ui.GetBoolean("HIS") ) { + p.SetOutputHis(max--); + } + } + p.SetOutputRange(min,max); +} diff --git a/isis/src/base/apps/isis2pds/isis2pds.xml b/isis/src/base/apps/isis2pds/isis2pds.xml new file mode 100644 index 0000000000000000000000000000000000000000..bf96dc4af323d799ef1aafe5aa7e3a2dbbd26ca5 --- /dev/null +++ b/isis/src/base/apps/isis2pds/isis2pds.xml @@ -0,0 +1,386 @@ + + + + + Convert from cube to pds format + + + + Program to convert cubes to pds image files. + + + + Import and Export + + + + + + Original version + + + Added the Label Type capability (param) + + + + + + + cube + input + + Input cube to be converted + + + The cube to be converted to pds format. + + + *.cub + + + + + filename + output + + Output pds image + + + The resulting pds file. + + + *.img + + + + + + + string + STREAM + Label type of output file + + Changes the type of pds label exported. + + + + + + + + string + + 32BIT + + Bit type of output file + + Bit type of output: + 8 bit (0=black, 255=white) + 16 bit unsigned (0=black, 65535=white) + 16 bit signed (-32767=black, 32768=white) + 32 bit (1.17549435e-38=black, 3.40282347e+38=white) + + + + + + + + + + boolean + true + Dedicates the minimum DN value for null pixels. + + If set to true, the minimum value of the raw output data will be + reserved for null pixels. The actual value used for null pixels will + be denoted in the print.prt file as well as displayed onscreen. + + + + boolean + false + Dedicates a DN value for LRS pixels. + + If set to true, then an output DN value is set aside for the LRS input pixels. + The actual DN value used for LRS pixels will be denoted in the print.prt + file as well as displayed onscreen. + + + + boolean + false + Dedicates a DN value for LIS pixels. + + If set to true, then an output DN value is set aside for the LIS input pixels. + The actual DN value used for LIS pixels will be denoted in the print.prt + file as well as displayed onscreen. + + + + boolean + false + Dedicates a DN value for HIS pixels. + + If set to true, then an output DN value is set aside for the HIS input pixels. + The actual DN value used for HIS pixels will be denoted in the print.prt + file as well as displayed onscreen. + + + + boolean + false + Dedicates a DN value for HRS pixels. + + If set to true, then an output DN value is set aside for the HRS input pixels. + The actual DN value used for HRS pixels will be denoted in the print.prt + file as well as displayed onscreen. + + + + + + + string + + NONE + + Type of stretch + + This parameter is used to select one of three ways to stretch + (or map) the input pixels. They are NONE, LINEAR, or MANUAL. + + + + + + + + + + + double + Minimum pixel value + + The minimum input pixel value which will be mapped to black. + + + MAXIMUM + + + + + double + Maximum pixel value + + The maximum input pixel value which will be mapped to white. + + + MINIMUM + + + + + double + Minimum Percent + + The percentage of data in the histogram used to compute the minimum + pixel value in the stretch. + + 0.5 + + MAXPERCENT + + + + + double + Maximum Percent + + The percentage of data in the histogram used to compute the maximum + pixel value in the stretch. + + 99.5 + + MINPERCENT + + + + + + + string + + LSB + + Endianness of the output bytes + + This parameter is used to select one whether the output will be + streamed starting with the most significant byte (MSB) or starting + with the least significant bytes (LSB). The choice should be made by + the user depending upon the format read by the system architecture + from which they plan to read the raw data. + + + + + + + + + + + + + convert cube to pds format + + + Converting a cube to a pds format image. + + + + from=ab102401.lev2.cub to=ab102401.lev2.img + + + In this example isis2pds will convert a cube to a pds + format image. + + + + + + Input cube image + + + This is the input cube for the example of isis2pds. + + + FROM + + + + + + Output pds image + + + This is the exact same image with exact same DNs, but in + the pds format. + + + TO + + + + + + + Example GUI + + + Screenshot of GUI with FROM and TO files selected. + + + + + + + + diff --git a/isis/src/base/apps/isis2pds/tsts/8bit/Makefile b/isis/src/base/apps/isis2pds/tsts/8bit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fd96680c1a01f4fbac02829c0a55b01ec8428bde --- /dev/null +++ b/isis/src/base/apps/isis2pds/tsts/8bit/Makefile @@ -0,0 +1,20 @@ +APPNAME = isis2pds + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/8bittruth.cub to=$(OUTPUT)/8bitdefault.img \ + bittype=8bit > /dev/null; + catlab from=$(OUTPUT)/8bitdefault.img to=$(OUTPUT)/8bitdefaultlabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/8bitdefault.img to=$(OUTPUT)/8bitdefault.cub > /dev/null; + $(RM) $(OUTPUT)/8bitdefault.img > /dev/null; + $(APPNAME) from=$(INPUT)/8bittruth.cub to=$(OUTPUT)/8bitnonull.img \ + bittype=8bit null=no > /dev/null; + catlab from=$(OUTPUT)/8bitnonull.img to=$(OUTPUT)/8bitnonulllabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/8bitnonull.img to=$(OUTPUT)/8bitnonull.cub > /dev/null; + $(RM) $(OUTPUT)/8bitnonull.img > /dev/null; + $(APPNAME) from=$(INPUT)/8bittruth.cub to=$(OUTPUT)/8bitspecialpixels.img \ + bittype=8bit lrs=yes lis=yes his=yes hrs=yes > /dev/null; + catlab from=$(OUTPUT)/8bitspecialpixels.img to=$(OUTPUT)/8bitspecialpixelslabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/8bitspecialpixels.img to=$(OUTPUT)/8bitspecialpixels.cub > /dev/null; + $(RM) $(OUTPUT)/8bitspecialpixels.img > /dev/null; diff --git a/isis/src/base/apps/isis2pds/tsts/Makefile b/isis/src/base/apps/isis2pds/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/isis2pds/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/isis2pds/tsts/default/Makefile b/isis/src/base/apps/isis2pds/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5ce37ac90dcfdef12141b1ff4f52bcf0d4aad657 --- /dev/null +++ b/isis/src/base/apps/isis2pds/tsts/default/Makefile @@ -0,0 +1,20 @@ +APPNAME = isis2pds + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.cub to=$(OUTPUT)/ab102401.img > /dev/null; + catlab from=$(OUTPUT)/ab102401.img to=$(OUTPUT)/labels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/ab102401.img to=$(OUTPUT)/ab102401.cub > /dev/null; + dd if=$(OUTPUT)/ab102401.img \ + bs=`getkey from=$(OUTPUT)/ab102401.img keyword=^IMAGE` \ + count=1 >& $(OUTPUT)/TEMP.txt > $(OUTPUT)/labelsEOL.txt; + $(RM) $(OUTPUT)/ab102401.img > /dev/null; + $(APPNAME) from=$(INPUT)/ab102401.cub labtype=fixed to=$(OUTPUT)/ab102401Fixed.img > /dev/null; + catlab from=$(OUTPUT)/ab102401Fixed.img to=$(OUTPUT)/labelsFixed.pvl > /dev/null; + pds2isis from=$(OUTPUT)/ab102401Fixed.img to=$(OUTPUT)/ab102401Fixed.cub > /dev/null; + dd if=$(OUTPUT)/ab102401Fixed.img \ + bs=`getkey from=$(OUTPUT)/ab102401Fixed.img keyword=^IMAGE` \ + count=1 >& $(OUTPUT)/TEMP.txt > $(OUTPUT)/labelsFixedEOL.txt; + $(RM) $(OUTPUT)/ab102401Fixed.img > /dev/null; + $(RM) $(OUTPUT)/TEMP.txt > /dev/null; diff --git a/isis/src/base/apps/isis2pds/tsts/defaultMSB/Makefile b/isis/src/base/apps/isis2pds/tsts/defaultMSB/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bd1cca26a9bd0cfbc2ca38e0a10186eaef8eea3a --- /dev/null +++ b/isis/src/base/apps/isis2pds/tsts/defaultMSB/Makefile @@ -0,0 +1,15 @@ +APPNAME = isis2pds + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.cub to=$(OUTPUT)/ab102401.img \ + endian=msb > /dev/null; + catlab from=$(OUTPUT)/ab102401.img to=$(OUTPUT)/labels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/ab102401.img to=$(OUTPUT)/ab102401.cub > /dev/null; + $(RM) $(OUTPUT)/ab102401.img > /dev/null; + $(APPNAME) from=$(INPUT)/ab102401.cub to=$(OUTPUT)/ab102401Fixed.img \ + labtype=fixed endian=msb > /dev/null; + catlab from=$(OUTPUT)/ab102401Fixed.img to=$(OUTPUT)/labelsFixed.pvl > /dev/null; + pds2isis from=$(OUTPUT)/ab102401Fixed.img to=$(OUTPUT)/ab102401Fixed.cub > /dev/null; + $(RM) $(OUTPUT)/ab102401Fixed.img > /dev/null; diff --git a/isis/src/base/apps/isis2pds/tsts/linear/Makefile b/isis/src/base/apps/isis2pds/tsts/linear/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9d03bdda23e1b67314bcf6723fca718245bcdeb9 --- /dev/null +++ b/isis/src/base/apps/isis2pds/tsts/linear/Makefile @@ -0,0 +1,50 @@ +APPNAME = isis2pds + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/8bittruth.cub to=$(OUTPUT)/8bitlineardefault.img \ + bittype=8bit stretch=linear > /dev/null; + catlab from=$(OUTPUT)/8bitlineardefault.img to=$(OUTPUT)/8bitlineardefaultlabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/8bitlineardefault.img to=$(OUTPUT)/8bitlineardefault.cub > /dev/null; + $(RM) $(OUTPUT)/8bitlineardefault.img > /dev/null; + $(APPNAME) from=$(INPUT)/8bittruth.cub to=$(OUTPUT)/8bitlinearnonull.img \ + bittype=8bit null=no stretch=linear minpercent=5.0 maxpercent=45.0 > /dev/null; + catlab from=$(OUTPUT)/8bitlinearnonull.img to=$(OUTPUT)/8bitlinearnonulllabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/8bitlinearnonull.img to=$(OUTPUT)/8bitlinearnonull.cub > /dev/null; + $(RM) $(OUTPUT)/8bitlinearnonull.img > /dev/null; + $(APPNAME) from=$(INPUT)/8bittruth.cub to=$(OUTPUT)/8bitlinearspecialpixels.img \ + bittype=8bit lrs=yes lis=yes his=yes hrs=yes stretch=linear minpercent=45.5 maxpercent=65.2 > /dev/null; + catlab from=$(OUTPUT)/8bitlinearspecialpixels.img to=$(OUTPUT)/8bitlinearspecialpixelslabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/8bitlinearspecialpixels.img to=$(OUTPUT)/8bitlinearspecialpixels.cub > /dev/null; + $(RM) $(OUTPUT)/8bitlinearspecialpixels.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/s16bitlineardefault.img \ + bittype=s16bit stretch=linear > /dev/null; + catlab from=$(OUTPUT)/s16bitlineardefault.img to=$(OUTPUT)/s16bitlineardefaultlabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/s16bitlineardefault.img to=$(OUTPUT)/s16bitlineardefault.cub > /dev/null; + $(RM) $(OUTPUT)/s16bitlineardefault.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/s16bitlinearnonull.img \ + bittype=s16bit null=no stretch=linear minpercent=2.0 maxpercent=5.0 > /dev/null; + catlab from=$(OUTPUT)/s16bitlinearnonull.img to=$(OUTPUT)/s16bitlinearnonulllabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/s16bitlinearnonull.img to=$(OUTPUT)/s16bitlinearnonull.cub > /dev/null; + $(RM) $(OUTPUT)/s16bitlinearnonull.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/s16bitlinearspecialpixels.img \ + bittype=s16bit lrs=yes lis=yes his=yes hrs=yes stretch=linear minpercent=45.0 maxpercent=55.0 > /dev/null; + catlab from=$(OUTPUT)/s16bitlinearspecialpixels.img to=$(OUTPUT)/s16bitlinearspecialpixelslabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/s16bitlinearspecialpixels.img to=$(OUTPUT)/s16bitlinearspecialpixels.cub > /dev/null; + $(RM) $(OUTPUT)/s16bitlinearspecialpixels.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/u16bitlineardefault.img \ + bittype=u16bit stretch=linear > /dev/null; + catlab from=$(OUTPUT)/u16bitlineardefault.img to=$(OUTPUT)/u16bitlineardefaultlabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/u16bitlineardefault.img to=$(OUTPUT)/u16bitlineardefault.cub > /dev/null; + $(RM) $(OUTPUT)/u16bitlineardefault.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/u16bitlinearnonull.img \ + bittype=u16bit null=no stretch=linear minpercent=90.0 maxpercent=95.0 > /dev/null; + catlab from=$(OUTPUT)/u16bitlinearnonull.img to=$(OUTPUT)/u16bitlinearnonulllabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/u16bitlinearnonull.img to=$(OUTPUT)/u16bitlinearnonull.cub > /dev/null; + $(RM) $(OUTPUT)/u16bitlinearnonull.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/u16bitlinearspecialpixels.img \ + bittype=u16bit lrs=yes lis=yes his=yes hrs=yes stretch=linear minpercent=1.0 maxpercent=99.0 > /dev/null; + catlab from=$(OUTPUT)/u16bitlinearspecialpixels.img to=$(OUTPUT)/u16bitlinearspecialpixelslabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/u16bitlinearspecialpixels.img to=$(OUTPUT)/u16bitlinearspecialpixels.cub > /dev/null; + $(RM) $(OUTPUT)/u16bitlinearspecialpixels.img > /dev/null; diff --git a/isis/src/base/apps/isis2pds/tsts/manual/Makefile b/isis/src/base/apps/isis2pds/tsts/manual/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c01d83fc926327f9640aa7339bce59b1094b0aea --- /dev/null +++ b/isis/src/base/apps/isis2pds/tsts/manual/Makefile @@ -0,0 +1,50 @@ +APPNAME = isis2pds + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/8bittruth.cub to=$(OUTPUT)/8bitmanualdefault.img \ + bittype=8bit stretch=manual minimum=0 maximum=255 > /dev/null; + catlab from=$(OUTPUT)/8bitmanualdefault.img to=$(OUTPUT)/8bitmanualdefaultlabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/8bitmanualdefault.img to=$(OUTPUT)/8bitmanualdefault.cub > /dev/null; + $(RM) $(OUTPUT)/8bitmanualdefault.img > /dev/null; + $(APPNAME) from=$(INPUT)/8bittruth.cub to=$(OUTPUT)/8bitmanualnonull.img \ + bittype=8bit null=no stretch=manual minimum=0 maximum=255 > /dev/null; + catlab from=$(OUTPUT)/8bitmanualnonull.img to=$(OUTPUT)/8bitmanualnonulllabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/8bitmanualnonull.img to=$(OUTPUT)/8bitmanualnonull.cub > /dev/null; + $(RM) $(OUTPUT)/8bitmanualnonull.img > /dev/null; + $(APPNAME) from=$(INPUT)/8bittruth.cub to=$(OUTPUT)/8bitmanualspecialpixels.img \ + bittype=8bit lrs=yes lis=yes his=yes hrs=yes stretch=manual minimum=0 maximum=255 > /dev/null; + catlab from=$(OUTPUT)/8bitmanualspecialpixels.img to=$(OUTPUT)/8bitmanualspecialpixelslabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/8bitmanualspecialpixels.img to=$(OUTPUT)/8bitmanualspecialpixels.cub > /dev/null; + $(RM) $(OUTPUT)/8bitmanualspecialpixels.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/s16bitmanualdefault.img \ + bittype=s16bit stretch=manual minimum=-32768 maximum=32767 > /dev/null; + catlab from=$(OUTPUT)/s16bitmanualdefault.img to=$(OUTPUT)/s16bitmanualdefaultlabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/s16bitmanualdefault.img to=$(OUTPUT)/s16bitmanualdefault.cub > /dev/null; + $(RM) $(OUTPUT)/s16bitmanualdefault.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/s16bitmanualnonull.img \ + bittype=s16bit null=no stretch=manual minimum=-32768 maximum=32767 > /dev/null; + catlab from=$(OUTPUT)/s16bitmanualnonull.img to=$(OUTPUT)/s16bitmanualnonulllabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/s16bitmanualnonull.img to=$(OUTPUT)/s16bitmanualnonull.cub > /dev/null; + $(RM) $(OUTPUT)/s16bitmanualnonull.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/s16bitmanualspecialpixels.img \ + bittype=s16bit lrs=yes lis=yes his=yes hrs=yes stretch=manual minimum=-32768 maximum=32767 > /dev/null; + catlab from=$(OUTPUT)/s16bitmanualspecialpixels.img to=$(OUTPUT)/s16bitmanualspecialpixelslabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/s16bitmanualspecialpixels.img to=$(OUTPUT)/s16bitmanualspecialpixels.cub > /dev/null; + $(RM) $(OUTPUT)/s16bitmanualspecialpixels.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/u16bitmanualdefault.img \ + bittype=u16bit stretch=manual minimum=0 maximum=65535 > /dev/null; + catlab from=$(OUTPUT)/u16bitmanualdefault.img to=$(OUTPUT)/u16bitmanualdefaultlabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/u16bitmanualdefault.img to=$(OUTPUT)/u16bitmanualdefault.cub > /dev/null; + $(RM) $(OUTPUT)/u16bitmanualdefault.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/u16bitmanualnonull.img \ + bittype=u16bit null=no stretch=manual minimum=0 maximum=65535 > /dev/null; + catlab from=$(OUTPUT)/u16bitmanualnonull.img to=$(OUTPUT)/u16bitmanualnonulllabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/u16bitmanualnonull.img to=$(OUTPUT)/u16bitmanualnonull.cub > /dev/null; + $(RM) $(OUTPUT)/u16bitmanualnonull.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/u16bitmanualspecialpixels.img \ + bittype=u16bit lrs=yes lis=yes his=yes hrs=yes stretch=manual minimum=0 maximum=65535 > /dev/null; + catlab from=$(OUTPUT)/u16bitmanualspecialpixels.img to=$(OUTPUT)/u16bitmanualspecialpixelslabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/u16bitmanualspecialpixels.img to=$(OUTPUT)/u16bitmanualspecialpixels.cub > /dev/null; + $(RM) $(OUTPUT)/u16bitmanualspecialpixels.img > /dev/null; diff --git a/isis/src/base/apps/isis2pds/tsts/signed16/Makefile b/isis/src/base/apps/isis2pds/tsts/signed16/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..128697f96aeed28f12007e49d27de26488584b32 --- /dev/null +++ b/isis/src/base/apps/isis2pds/tsts/signed16/Makefile @@ -0,0 +1,20 @@ +APPNAME = isis2pds + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/s16bitdefault.img \ + bittype=s16bit > /dev/null; + catlab from=$(OUTPUT)/s16bitdefault.img to=$(OUTPUT)/s16bitdefaultlabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/s16bitdefault.img to=$(OUTPUT)/s16bitdefault.cub > /dev/null; + $(RM) $(OUTPUT)/s16bitdefault.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/s16bitnonull.img \ + bittype=s16bit null=no > /dev/null; + catlab from=$(OUTPUT)/s16bitnonull.img to=$(OUTPUT)/s16bitnonulllabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/s16bitnonull.img to=$(OUTPUT)/s16bitnonull.cub > /dev/null; + $(RM) $(OUTPUT)/s16bitnonull.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/s16bitspecialpixels.img \ + bittype=s16bit lrs=yes lis=yes his=yes hrs=yes > /dev/null; + catlab from=$(OUTPUT)/s16bitspecialpixels.img to=$(OUTPUT)/s16bitspecialpixelslabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/s16bitspecialpixels.img to=$(OUTPUT)/s16bitspecialpixels.cub > /dev/null; + $(RM) $(OUTPUT)/s16bitspecialpixels.img > /dev/null; diff --git a/isis/src/base/apps/isis2pds/tsts/signed16MSB/Makefile b/isis/src/base/apps/isis2pds/tsts/signed16MSB/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5362b4ef3edc17c8bfab733e9823d6433a67d479 --- /dev/null +++ b/isis/src/base/apps/isis2pds/tsts/signed16MSB/Makefile @@ -0,0 +1,20 @@ +APPNAME = isis2pds + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/s16bitmsbdefault.img \ + bittype=s16bit endian=msb > /dev/null; + catlab from=$(OUTPUT)/s16bitmsbdefault.img to=$(OUTPUT)/s16bitmsbdefaultlabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/s16bitmsbdefault.img to=$(OUTPUT)/s16bitmsbdefault.cub > /dev/null; + $(RM) $(OUTPUT)/s16bitmsbdefault.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/s16bitmsbnonull.img \ + bittype=s16bit null=no endian=msb > /dev/null; + catlab from=$(OUTPUT)/s16bitmsbnonull.img to=$(OUTPUT)/s16bitmsbnonulllabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/s16bitmsbnonull.img to=$(OUTPUT)/s16bitmsbnonull.cub > /dev/null; + $(RM) $(OUTPUT)/s16bitmsbnonull.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/s16bitmsbspecialpixels.img \ + bittype=s16bit lrs=yes lis=yes his=yes hrs=yes endian=msb > /dev/null; + catlab from=$(OUTPUT)/s16bitmsbspecialpixels.img to=$(OUTPUT)/s16bitmsbspecialpixelslabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/s16bitmsbspecialpixels.img to=$(OUTPUT)/s16bitmsbspecialpixels.cub > /dev/null; + $(RM) $(OUTPUT)/s16bitmsbspecialpixels.img > /dev/null; diff --git a/isis/src/base/apps/isis2pds/tsts/usigned16/Makefile b/isis/src/base/apps/isis2pds/tsts/usigned16/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f03ba89c76b1a7982ad67772d408f714585003d8 --- /dev/null +++ b/isis/src/base/apps/isis2pds/tsts/usigned16/Makefile @@ -0,0 +1,20 @@ +APPNAME = isis2pds + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/u16bitdefault.img \ + bittype=u16bit > /dev/null; + catlab from=$(OUTPUT)/u16bitdefault.img to=$(OUTPUT)/u16bitdefaultlabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/u16bitdefault.img to=$(OUTPUT)/u16bitdefault.cub > /dev/null; + $(RM) $(OUTPUT)/u16bitdefault.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/u16bitnonull.img \ + bittype=u16bit null=no > /dev/null; + catlab from=$(OUTPUT)/u16bitnonull.img to=$(OUTPUT)/u16bitnonulllabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/u16bitnonull.img to=$(OUTPUT)/u16bitnonull.cub > /dev/null; + $(RM) $(OUTPUT)/u16bitnonull.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/u16bitspecialpixels.img \ + bittype=u16bit lrs=yes lis=yes his=yes hrs=yes > /dev/null; + catlab from=$(OUTPUT)/u16bitspecialpixels.img to=$(OUTPUT)/u16bitspecialpixelslabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/u16bitspecialpixels.img to=$(OUTPUT)/u16bitspecialpixels.cub > /dev/null; + $(RM) $(OUTPUT)/u16bitspecialpixels.img > /dev/null; diff --git a/isis/src/base/apps/isis2pds/tsts/usigned16MSB/Makefile b/isis/src/base/apps/isis2pds/tsts/usigned16MSB/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0ee3a7680cb5232be347a1e4941d641e98f5328b --- /dev/null +++ b/isis/src/base/apps/isis2pds/tsts/usigned16MSB/Makefile @@ -0,0 +1,20 @@ +APPNAME = isis2pds + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/u16bitmsbdefault.img \ + bittype=u16bit endian=msb > /dev/null; + catlab from=$(OUTPUT)/u16bitmsbdefault.img to=$(OUTPUT)/u16bitmsbdefaultlabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/u16bitmsbdefault.img to=$(OUTPUT)/u16bitmsbdefault.cub > /dev/null; + $(RM) $(OUTPUT)/u16bitmsbdefault.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/u16bitmsbnonull.img \ + bittype=u16bit null=no endian=msb > /dev/null; + catlab from=$(OUTPUT)/u16bitmsbnonull.img to=$(OUTPUT)/u16bitmsbnonulllabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/u16bitmsbnonull.img to=$(OUTPUT)/u16bitmsbnonull.cub > /dev/null; + $(RM) $(OUTPUT)/u16bitmsbnonull.img > /dev/null; + $(APPNAME) from=$(INPUT)/s16bittruth.cub to=$(OUTPUT)/u16bitmsbspecialpixels.img \ + bittype=u16bit lrs=yes lis=yes his=yes hrs=yes endian=msb > /dev/null; + catlab from=$(OUTPUT)/u16bitmsbspecialpixels.img to=$(OUTPUT)/u16bitmsbspecialpixelslabels.pvl > /dev/null; + pds2isis from=$(OUTPUT)/u16bitmsbspecialpixels.img to=$(OUTPUT)/u16bitmsbspecialpixels.cub > /dev/null; + $(RM) $(OUTPUT)/u16bitmsbspecialpixels.img > /dev/null; diff --git a/isis/src/base/apps/isis2raw/Makefile b/isis/src/base/apps/isis2raw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/isis2raw/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/isis2raw/isis2raw.cpp b/isis/src/base/apps/isis2raw/isis2raw.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f388869ea78add518f5ee0896fdbfdaa342d2747 --- /dev/null +++ b/isis/src/base/apps/isis2raw/isis2raw.cpp @@ -0,0 +1,181 @@ +//************************************************************************ +// See Full documentation in isis2raw.xml +//************************************************************************ +#include "Isis.h" + +#include +#include + + +#include "ProcessExport.h" +#include "UserInterface.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +enum Pixtype { NONE, NEG, BOTH }; + +void checkRange( UserInterface &ui, double &min, double &max ); +void setRangeAndPixels( UserInterface &ui, ProcessExport &p, + double &min, double &max, Pixtype ptype ); + +// Main program +void IsisMain() { + // Create an object for exporting Isis data + ProcessExport p; + + // Open the input cube + p.SetInputCube("FROM"); + + UserInterface &ui = Application::GetUserInterface(); + + // Applies the input to output stretch options + if (ui.GetString ("STRETCH") == "LINEAR") { + if (ui.GetString ("BITTYPE") != "32BIT") + p.SetInputRange(); + } + if (ui.GetString ("STRETCH") == "MANUAL") + p.SetInputRange(ui.GetDouble("MINIMUM"), ui.GetDouble("MAXIMUM")); + + // Determine bit size, output range, and calculate number of bytes to write + // for each line. + double min = -DBL_MAX; + double max = DBL_MAX; + if (ui.GetString ("BITTYPE") == "8BIT") { + p.SetOutputType(Isis::UnsignedByte); + min = 0.0; + max = 255.0; + checkRange( ui, min, max ); + setRangeAndPixels( ui, p, min, max, BOTH ); + } + else if (ui.GetString ("BITTYPE") == "S16BIT") { + p.SetOutputType(Isis::SignedWord); + min = -32768.0; + max = 32767.0; + checkRange( ui, min, max ); + setRangeAndPixels( ui, p, min, max, NEG ); + } + else if (ui.GetString ("BITTYPE") == "U16BIT") { + p.SetOutputType(Isis::UnsignedWord); + min = 0.0; + max = 65535.0; + checkRange( ui, min, max ); + setRangeAndPixels( ui, p, min, max, BOTH ); + } + else if (ui.GetString ("BITTYPE") == "32BIT") { + p.SetOutputType(Isis::Real); + checkRange( ui, min, max ); + setRangeAndPixels( ui, p, min, max, NONE ); + } + + // Set the output endianness + if (ui.GetString("ENDIAN") == "MSB") + p.SetOutputEndian(Isis::Msb); + else if (ui.GetString("ENDIAN") == "LSB") + p.SetOutputEndian(Isis::Lsb); + // Open the cube for writing + string to = ui.GetFilename("TO","raw"); + ofstream fout; + fout.open (to.c_str (),ios::out|ios::binary); + if (!fout.is_open ()) { + string msg = "Cannot open raw output file"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + // Set the Output Storage Format + if ( Isis::iString( ui.GetString("STORAGEORDER") ).DownCase() == "bil" ) { + p.SetFormat( ProcessExport::BIL ); + } + else if ( Isis::iString( ui.GetString("STORAGEORDER") ).DownCase() == "bip" ) { + p.SetFormat( ProcessExport::BIP ); + } + + // Write the raw cube data + p.StartProcess (fout); + + fout.close(); + p.EndProcess(); + + // Records what output values were used, then sends it to the print.prt file + // as well as the terminal. + PvlGroup results( "DNs Used" ); + results += PvlKeyword( "Null", p.OutputNull() ); + results += PvlKeyword( "LRS", p.OutputLrs() ); + results += PvlKeyword( "LIS", p.OutputLis() ); + results += PvlKeyword( "HIS", p.OutputHis() ); + results += PvlKeyword( "HRS", p.OutputHrs() ); + results += PvlKeyword( "ValidMin", min ); + results += PvlKeyword( "ValidMax", max ); + Application::Log( results ); + + return; +} + +// Validates provided range +void checkRange( UserInterface &ui, double &min, double &max ) { + if ( ui.WasEntered("OMIN") ) { + if ( ui.GetDouble("OMIN") < min ) { + string message = "OMIN [" + iString(min) + "] is too small for the provided BITTYPE ["; + message += ui.GetString("BITTYPE") + "]"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + else { + min = ui.GetDouble("OMIN"); + } + } + if ( ui.WasEntered("OMAX") ) { + if ( ui.GetDouble("OMAX") > max ) { + string message = "OMAX [" + iString(max) + "] is too large for the provided BITTYPE ["; + message += ui.GetString("BITTYPE") + "]"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + else { + max = ui.GetDouble("OMAX"); + } + } + if( min >= max ) { + string message = "OMIN [" + iString(min) + "] cannot be greater than or equal to OMAX ["; + message += iString(max) + "]"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } +} + +// Sets up special pixels and valid pixel ranges +void setRangeAndPixels( UserInterface &ui, ProcessExport &p, double &min, double &max, Pixtype ptype ) { + if( ptype == NEG ) { + if ( ui.GetBoolean("NULL") ) { + p.SetOutputNull(min++); + } + if ( ui.GetBoolean("LRS") ) { + p.SetOutputLrs(min++); + } + if ( ui.GetBoolean("LIS") ) { + p.SetOutputLis(min++); + } + if ( ui.GetBoolean("HIS") ) { + p.SetOutputHis(min++); + } + if ( ui.GetBoolean("HRS") ) { + p.SetOutputHrs(min++); + } + } + else if( ptype == BOTH ) { + if ( ui.GetBoolean("NULL") ) { + p.SetOutputNull(min++); + } + if ( ui.GetBoolean("LRS") ) { + p.SetOutputLrs(min++); + } + if ( ui.GetBoolean("LIS") ) { + p.SetOutputLis(min++); + } + if ( ui.GetBoolean("HRS") ) { + p.SetOutputHrs(max--); + } + if ( ui.GetBoolean("HIS") ) { + p.SetOutputHis(max--); + } + } + p.SetOutputRange(min,max); +} diff --git a/isis/src/base/apps/isis2raw/isis2raw.xml b/isis/src/base/apps/isis2raw/isis2raw.xml new file mode 100644 index 0000000000000000000000000000000000000000..a9afc9fcb9d85a8e809bbb493c2e699be2438ebc --- /dev/null +++ b/isis/src/base/apps/isis2raw/isis2raw.xml @@ -0,0 +1,421 @@ + + + + + + Exports a cube to raw format + + + + This program will export an Isis cube to a greyscale raw formatted file. + The raw image may be output into an 8-bit, 16-bit unsigned, 16-bit signed + or 32-bit raw image. This raw image can be in BSQ, BIL, or BIP format, and + can include or exclude Null, Lrs, Lis, His, and/or Hrs specific DN values. + If no special pixel parameters are selected, then the special pixels are + mapped in the following manner; Low Saturation values and Null values are + made black and High Saturation values are made white. + In order to ensure acceptable contrast in the output file, three stretch + options are given 1) no stretch 2) linear, and 3) manual. + A custom maximum and minimum DN value can be specified for 8-bit as well as + 16-bit unsigned and 16-bit signed raw outputs. For example, if a range of + 0 to 1023 is selected in a 16-bit unsigned raw image, the DNs are stretched + to an effective 10-bit format. + + + + + Original version + + + Ported to Isis 3.0 + + + Correction made to number of bytes for writing data and changed + max for unsigned 16-bit data from 65536 to 65535. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Changed default extension handling mechanism + + + Rewrote to support changes in underlying ProcessExport class + + + Added code to export multiple bands + + + Modified to allow histogram percentage to be selected for + linear stretch option + + + Updated documentation to follow current standards + + + Fixed problem where the valid data range overlapped the null value. + + + Created options to ouput BIL and BIP formats, making BSQ the default, as + well as added preserve special pixel (NULL) option. + + + Created the options LRS, LIS, HIS, HRS, as well as OMIN and OMAX. Also + remade the GUI, and redid much of the documentation. + + + Clarified some documentation and updated comments. + + + + + Import and Export + + + + + isis2std + isis2fits + + + + + + + cube + input + + Input cube to export + + + Use this parameter to select the filename and band to export. For + example, file.cub+5 will select band 5 + + + *.cub + + + + + filename + output + + Output raw file + + + Use this parameter to specify the name of the output raw file. + If you do not include an extension of .raw it will be added. + + + + + + + string + + 32BIT + + Bit type of output file + + Bit type of output: + 8 bit (0=black, 255=white) + 16 bit unsigned (0=black, 65535=white) + 16 bit signed (-32767=black, 32768=white) + 32 bit (1.17549435e-38=black, 3.40282347e+38=white) + + + + + + + + + + double + + The minimum output DN value including special pixels. + + + If left blank, the minimum DN value used will default to the smallest + value possible for the provided bittype. Otherwise, the provided + value will be the minimum DN used (including special pixels). + + + NULL + + + + double + + The maximum output DN value including special pixels. + + + If left blank, the maximum DN value used will default to the largest + value possible for the provided bittype. Otherwise the provided + value will be the maximum DN used (including special pixels). + + + NULL + + + + boolean + true + Dedicates the minimum DN value for null pixels. + + If set to true, the minimum value of the raw output data will be + reserved for null pixels. The actual value used for null pixels will + be denoted in the print.prt file as well as displayed onscreen. + + + + boolean + false + Dedicates a DN value for LRS pixels. + + If set to true, then an output DN value is set aside for the LRS input pixels. + The actual DN value used for LRS pixels will be denoted in the print.prt + file as well as displayed onscreen. + + + + boolean + false + Dedicates a DN value for LIS pixels. + + If set to true, then an output DN value is set aside for the LIS input pixels. + The actual DN value used for LIS pixels will be denoted in the print.prt + file as well as displayed onscreen. + + + + boolean + false + Dedicates a DN value for HIS pixels. + + If set to true, then an output DN value is set aside for the HIS input pixels. + The actual DN value used for HIS pixels will be denoted in the print.prt + file as well as displayed onscreen. + + + + boolean + false + Dedicates a DN value for HRS pixels. + + If set to true, then an output DN value is set aside for the HRS input pixels. + The actual DN value used for HRS pixels will be denoted in the print.prt + file as well as displayed onscreen. + + + + + + + string + + LINEAR + + Type of stretch + + This parameter is used to select one of three ways to stretch + (or map) the input pixels. They are NONE, LINEAR, or MANUAL. + + + + + + + + + + + double + Minimum pixel value + + The minimum input pixel value which will be mapped to black. + + + MAXIMUM + + + + + double + Maximum pixel value + + The maximum input pixel value which will be mapped to white. + + + MINIMUM + + + + + double + Minimum Percent + + The percentage of data in the histogram used to compute the minimum + pixel value in the stretch. + + 0.5 + + MAXPERCENT + + + + + double + Maximum Percent + + The percentage of data in the histogram used to compute the maximum + pixel value in the stretch. + + 99.5 + + MINPERCENT + + + + + + + string + + LSB + + Endianness of the output bytes + + This parameter is used to select one whether the output will be + streamed starting with the most significant byte (MSB) or starting + with the least significant bytes (LSB). The choice should be made by + the user depending upon the format read by the system architecture + from which they plan to read the raw data. + + + + + + + + string + + BSQ + + Storage order of output file. + + Sets the storage order of the raw ouput file to either BSQ, BIL, or + BIP. + + + + + + + + + + + diff --git a/isis/src/base/apps/isis2raw/tsts/8bit/Makefile b/isis/src/base/apps/isis2raw/tsts/8bit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5ce055a926b945d5e61610144fab3c7e367d9eb9 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/8bit/Makefile @@ -0,0 +1,15 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth4.raw \ + bittype= 8BIT > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth4NoNull.raw \ + null=no \ + bittype= 8BIT > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth4NullLrsLis.raw \ + bittype= 8BIT lrs=true lis=true > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/8bitBIL/Makefile b/isis/src/base/apps/isis2raw/tsts/8bitBIL/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a92a69c7909d25103ef7364a4bce59731288058b --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/8bitBIL/Makefile @@ -0,0 +1,13 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth4.raw \ + storageorder=bil \ + bittype= 8BIT > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2rawTruth4MinMax.raw \ + storageorder=bil bittype= 8BIT \ + omin=40 omax=125 > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/8bitBIP/Makefile b/isis/src/base/apps/isis2raw/tsts/8bitBIP/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4cd3e2f549974639e6bca991aae39cb38ac7bcb8 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/8bitBIP/Makefile @@ -0,0 +1,9 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth4.raw \ + storageorder=bip \ + bittype= 8BIT > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/Makefile b/isis/src/base/apps/isis2raw/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/isis2raw/tsts/default/Makefile b/isis/src/base/apps/isis2raw/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..247356b4d015f9b5e0f7afcf10a16e03594fc387 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2rawTruth1.raw > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/defaultBIL/Makefile b/isis/src/base/apps/isis2raw/tsts/defaultBIL/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ca5b970445a1f5bcc3a4a455d1eccd90c09388d1 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/defaultBIL/Makefile @@ -0,0 +1,9 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2rawTruth1.raw \ + storageorder=bil \ + > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/defaultBIP/Makefile b/isis/src/base/apps/isis2raw/tsts/defaultBIP/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..777df318293d2d54f6af336caed8b9af5942fe57 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/defaultBIP/Makefile @@ -0,0 +1,9 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2rawTruth1.raw \ + storageorder=bip \ + > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/manual/Makefile b/isis/src/base/apps/isis2raw/tsts/manual/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9a0530327f95583b849a5a0547da6976dca54289 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/manual/Makefile @@ -0,0 +1,25 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth7.raw \ + bittype= U16BIT \ + stretch= manual \ + minimum=0 \ + maximum=65535 > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth7NoNull.raw \ + null=no \ + bittype= U16BIT \ + stretch= manual \ + minimum = 0 \ + maximum = 65535 > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2rawTruth7HrsHis.raw \ + null=no hrs=yes his=yes \ + bittype= U16BIT \ + stretch= manual \ + minimum = 0 \ + maximum = 65535 > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/manualBIL/Makefile b/isis/src/base/apps/isis2raw/tsts/manualBIL/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4a9bec0527d332f81ec555512714cc476e92cd52 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/manualBIL/Makefile @@ -0,0 +1,12 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth7.raw \ + storageorder=bil \ + bittype= U16BIT \ + stretch= manual \ + minimum = 0 \ + maximum = 65535 > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/manualBIP/Makefile b/isis/src/base/apps/isis2raw/tsts/manualBIP/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d4306a0041c5e7fa5b19a80c2b1072f06e5e9525 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/manualBIP/Makefile @@ -0,0 +1,20 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth7.raw \ + storageorder=bip \ + bittype= U16BIT \ + stretch= manual \ + minimum = 0 \ + maximum = 65535 > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth7All.raw \ + storageorder=bip \ + bittype= U16BIT \ + lrs=yes lis=yes his=yes hrs=yes \ + stretch= manual \ + minimum = 0 \ + maximum = 65535 > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/multiBand/Makefile b/isis/src/base/apps/isis2raw/tsts/multiBand/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a57d142cb1fb90cfe73dec9e5203f7e549f9c5c9 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/multiBand/Makefile @@ -0,0 +1,12 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/isis2rawTruth6.raw \ + bittype= S16BIT > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/isis2rawTruth6NoNull.raw \ + null=no \ + bittype= S16BIT > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/multiBandBIL/Makefile b/isis/src/base/apps/isis2raw/tsts/multiBandBIL/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..621774713ecd0bcfd23bd359ccc9d19f235d594f --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/multiBandBIL/Makefile @@ -0,0 +1,14 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/isis2rawTruth6.raw \ + storageorder=bil \ + bittype= S16BIT > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/isis2rawTruth6LrsHis.raw \ + storageorder=bil \ + lrs=yes his=yes \ + bittype= S16BIT > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/multiBandBIP/Makefile b/isis/src/base/apps/isis2raw/tsts/multiBandBIP/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cc78547db2ae4e7344aa24fc501d57492df6e2d9 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/multiBandBIP/Makefile @@ -0,0 +1,9 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/isis2rawTruth6.raw \ + storageorder=bip \ + bittype= S16BIT > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/noStretch/Makefile b/isis/src/base/apps/isis2raw/tsts/noStretch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..15570db6916e762356cf64aa2defc607b5919e09 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/noStretch/Makefile @@ -0,0 +1,20 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth5.raw \ + bittype= 8BIT \ + stretch= none > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth5NoNull.raw \ + null=no \ + bittype= 8BIT \ + stretch= none > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2rawTruth5AllAndOMinOMax.raw \ + null=no lrs=yes lis=yes his=yes hrs=yes \ + omin=1 omax=200 \ + bittype= 8BIT \ + stretch= none > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/noStretchBIL/Makefile b/isis/src/base/apps/isis2raw/tsts/noStretchBIL/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..480eb5eab5ed59c4af70aad9cbdc940f762697ec --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/noStretchBIL/Makefile @@ -0,0 +1,15 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth5.raw \ + storageorder=bil \ + bittype= 8BIT \ + stretch= none > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth5NoNullLisHrs.raw \ + storageorder=bil \ + bittype= 8BIT null=no lis=yes hrs=yes \ + stretch= none > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/noStretchBIP/Makefile b/isis/src/base/apps/isis2raw/tsts/noStretchBIP/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f28171d0963a0c520fe2aa9d17b94dc0224efa7e --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/noStretchBIP/Makefile @@ -0,0 +1,10 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth5.raw \ + storageorder=bip \ + bittype= 8BIT \ + stretch= none > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/signed16/Makefile b/isis/src/base/apps/isis2raw/tsts/signed16/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e77a1e1fe426b7f775cc7a6df7c3a622218ef116 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/signed16/Makefile @@ -0,0 +1,14 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2rawTruth2.raw \ + bittype= S16BIT \ + endian= MSB > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2rawTruth2NoNull.raw \ + null=no \ + bittype= S16BIT \ + endian= MSB > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/signed16BIL/Makefile b/isis/src/base/apps/isis2raw/tsts/signed16BIL/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3201ac4b2919c441293a19bfbd8fad6f75370a99 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/signed16BIL/Makefile @@ -0,0 +1,10 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2rawTruth2.raw \ + storageorder=bil \ + bittype= S16BIT \ + endian= MSB > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/signed16BIP/Makefile b/isis/src/base/apps/isis2raw/tsts/signed16BIP/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d244efd699ec9768e17eb903d4a17ff526abdc11 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/signed16BIP/Makefile @@ -0,0 +1,16 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2rawTruth2.raw \ + storageorder=bip \ + bittype= S16BIT \ + endian= MSB > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2rawTruth2OMinNoNullHrs.raw \ + storageorder=bip \ + bittype= S16BIT \ + null=no hrs=yes omin=-5000 \ + endian= MSB > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/u16bit/Makefile b/isis/src/base/apps/isis2raw/tsts/u16bit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b89e436131c5c8545759e93f29cfa24b23f05770 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/u16bit/Makefile @@ -0,0 +1,16 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth3.raw \ + bittype= U16BIT > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth3NoNull.raw \ + null=no \ + bittype= U16BIT > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth3NoNullOMax.raw \ + null=no omax=12000 \ + bittype= U16BIT > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/u16bitBIL/Makefile b/isis/src/base/apps/isis2raw/tsts/u16bitBIL/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d40c42ba45d7f98b9cb1a07279ee4ce66ee22892 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/u16bitBIL/Makefile @@ -0,0 +1,9 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth3.raw \ + storageorder=bil \ + bittype= U16BIT > /dev/null; diff --git a/isis/src/base/apps/isis2raw/tsts/u16bitBIP/Makefile b/isis/src/base/apps/isis2raw/tsts/u16bitBIP/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..896d109d635cecf9517d3333021687d226b137d1 --- /dev/null +++ b/isis/src/base/apps/isis2raw/tsts/u16bitBIP/Makefile @@ -0,0 +1,13 @@ +APPNAME = isis2raw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2rawTruth3.raw \ + storageorder=bip \ + bittype= U16BIT > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2rawTruth3OMinOMaxLis.raw \ + storageorder=bip omin=0 omax=15 lis=yes \ + bittype= U16BIT > /dev/null; diff --git a/isis/src/base/apps/isis2std/Makefile b/isis/src/base/apps/isis2std/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/isis2std/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/isis2std/isis2std.cpp b/isis/src/base/apps/isis2std/isis2std.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98bfd5c3e964084b844edce5a89d61426c33f945 --- /dev/null +++ b/isis/src/base/apps/isis2std/isis2std.cpp @@ -0,0 +1,577 @@ +#include "Isis.h" +#include "ProcessExport.h" +#include "JP2Encoder.h" + +#include "UserInterface.h" +#include "Filename.h" +#include +#include + +using namespace std; +using namespace Isis; +QImage *qimage; +JP2Encoder *JP2_encoder; +char **jp2buf; +Cube *icube; +Isis::PixelType jp2type; +int datamin; +int datamax; + +// Line-by-Line qimage output prototype +void checkDataSize (Isis::BigInt line, Isis::BigInt samp, iString mode); +void toGreyscaleImage (Buffer &in); +void toRGBImage (vector &in); +void toARGBImage (vector &in); +void toJP2 (Buffer &in); +void toJP2RGB (vector &in); +void toJP2ARGB (vector &in); + +// Main program +void IsisMain() { + // See if qts support the users desired output format + UserInterface &ui = Application::GetUserInterface(); + iString format = ui.GetString("FORMAT"); + format.DownCase(); + int quality = ui.GetInteger("QUALITY"); + + iString mode = ui.GetString("MODE"); + + // Create an object for exporting image data + ProcessExport p; + + if (format.Equal("jp2")) { + // Setup the required extension and world file + string extension(""),world(""); + extension = "jp2"; + world = "j2w"; + + // Single band cubes will be greyscale + if (mode == "GRAYSCALE") { + // Open the input cube + icube = p.SetInputCube("FROM",Isis::OneBand); + + // Apply the input to output stretch options + p.SetInputRange(); + p.SetFormat(ProcessExport::BIL); + + jp2buf = new char* [1]; + // Determine bit size and output range + if (ui.GetString("BITTYPE") == "8BIT") { + jp2type = Isis::UnsignedByte; + jp2buf[0] = new char[icube->Samples()]; + p.SetOutputType(Isis::UnsignedByte); + p.SetOutputRange(1.0,255.0); + p.SetOutputNull(0.0); + JP2_encoder = new JP2Encoder(ui.GetFilename("TO"),icube->Samples(), + icube->Lines(),icube->Bands(),Isis::UnsignedByte); + datamin = 0; + datamax = 255; + } else if (ui.GetString("BITTYPE") == "S16BIT") { + jp2type = Isis::SignedWord; + for (int i=0; iBands(); i++) { + jp2buf[i] = new char[icube->Samples()*2]; + } + p.SetOutputType(Isis::SignedWord); + p.SetOutputNull(-32768.0); + p.SetOutputRange(-32752.0,32767.0); + JP2_encoder = new JP2Encoder(ui.GetFilename("TO"),icube->Samples(), + icube->Lines(),icube->Bands(),Isis::SignedWord); + datamin = -32752; + datamax = 32767; + } else if (ui.GetString("BITTYPE") == "U16BIT") { + jp2type = Isis::UnsignedWord; + for (int i=0; iBands(); i++) { + jp2buf[i] = new char[icube->Samples()*2]; + } + p.SetOutputType(Isis::UnsignedWord); + p.SetOutputNull(0.0); + p.SetOutputRange(3.0,65522.0); + JP2_encoder = new JP2Encoder(ui.GetFilename("TO"),icube->Samples(), + icube->Lines(),icube->Bands(),Isis::UnsignedWord); + datamin = 3; + datamax = 65522; + } + JP2_encoder->OpenFile(); + p.StartProcess(toJP2); + } + // If RGB, create a 24-bit color image + // (1st band -> red, 2nd band -> green, 3rd band -> blue) + else if (mode == "RGB") { + Cube *redcube = p.SetInputCube("RED", Isis::OneBand); + p.SetInputCube("GREEN", Isis::OneBand); + p.SetInputCube("BLUE", Isis::OneBand); + if (ui.GetString("STRETCH") == "MANUAL") { + p.SetInputRange(ui.GetDouble("RMIN"), ui.GetDouble("RMAX"), 0); + p.SetInputRange(ui.GetDouble("GMIN"), ui.GetDouble("GMAX"), 1); + p.SetInputRange(ui.GetDouble("BMIN"), ui.GetDouble("BMAX"), 2); + } + else { + p.SetInputRange(); + ui.Clear("MINIMUM"); + ui.Clear("MAXIMUM"); + ui.PutDouble("RMIN", p.GetInputMinimum(0)); + ui.PutDouble("RMAX", p.GetInputMaximum(0)); + ui.PutDouble("GMIN", p.GetInputMinimum(1)); + ui.PutDouble("GMAX", p.GetInputMaximum(1)); + ui.PutDouble("BMIN", p.GetInputMinimum(2)); + ui.PutDouble("BMAX", p.GetInputMaximum(2)); + } + p.SetFormat(ProcessExport::BIL); + jp2buf = new char* [3]; + // Determine bit size and output range + if (ui.GetString("BITTYPE") == "8BIT") { + jp2type = Isis::UnsignedByte; + for (int i=0; i<3; i++) { + jp2buf[i] = new char[redcube->Samples()]; + } + p.SetOutputType(Isis::UnsignedByte); + p.SetOutputRange(1.0,255.0); + p.SetOutputNull(0.0); + JP2_encoder = new JP2Encoder(ui.GetFilename("TO"),redcube->Samples(), + redcube->Lines(),3,Isis::UnsignedByte); + datamin = 0; + datamax = 255; + } else if (ui.GetString("BITTYPE") == "S16BIT") { + jp2type = Isis::SignedWord; + for (int i=0; i<3; i++) { + jp2buf[i] = new char[redcube->Samples()*2]; + } + p.SetOutputType(Isis::SignedWord); + p.SetOutputNull(-32768.0); + p.SetOutputRange(-32752.0,32767.0); + JP2_encoder = new JP2Encoder(ui.GetFilename("TO"),redcube->Samples(), + redcube->Lines(),3,Isis::SignedWord); + datamin = -32752; + datamax = 32767; + } else if (ui.GetString("BITTYPE") == "U16BIT") { + jp2type = Isis::UnsignedWord; + for (int i=0; i<3; i++) { + jp2buf[i] = new char[redcube->Samples()*2]; + } + p.SetOutputType(Isis::UnsignedWord); + p.SetOutputNull(0.0); + p.SetOutputRange(3.0,65522.0); + JP2_encoder = new JP2Encoder(ui.GetFilename("TO"),redcube->Samples(), + redcube->Lines(),3,Isis::UnsignedWord); + datamin = 3; + datamax = 65522; + } + JP2_encoder->OpenFile(); + p.StartProcess(toJP2RGB); + } else if (mode == "ARGB") { + Cube *alphacube = p.SetInputCube("ALPHA", Isis::OneBand); + p.SetInputCube("RED", Isis::OneBand); + p.SetInputCube("GREEN", Isis::OneBand); + p.SetInputCube("BLUE", Isis::OneBand); + if (ui.GetString("STRETCH") == "MANUAL") { + p.SetInputRange(ui.GetDouble("AMIN"), ui.GetDouble("AMAX"), 0); + p.SetInputRange(ui.GetDouble("RMIN"), ui.GetDouble("RMAX"), 1); + p.SetInputRange(ui.GetDouble("GMIN"), ui.GetDouble("GMAX"), 2); + p.SetInputRange(ui.GetDouble("BMIN"), ui.GetDouble("BMAX"), 3); + } + else { + p.SetInputRange(); + ui.Clear("MINIMUM"); + ui.Clear("MAXIMUM"); + ui.PutDouble("AMIN", p.GetInputMinimum(0)); + ui.PutDouble("AMAX", p.GetInputMaximum(0)); + ui.PutDouble("RMIN", p.GetInputMinimum(1)); + ui.PutDouble("RMAX", p.GetInputMaximum(1)); + ui.PutDouble("GMIN", p.GetInputMinimum(2)); + ui.PutDouble("GMAX", p.GetInputMaximum(2)); + ui.PutDouble("BMIN", p.GetInputMinimum(3)); + ui.PutDouble("BMAX", p.GetInputMaximum(3)); + } + p.SetFormat(ProcessExport::BIL); + jp2buf = new char* [4]; + // Determine bit size and output range + if (ui.GetString("BITTYPE") == "8BIT") { + jp2type = Isis::UnsignedByte; + for (int i=0; i<4; i++) { + jp2buf[i] = new char[alphacube->Samples()]; + } + p.SetOutputType(Isis::UnsignedByte); + p.SetOutputRange(1.0,255.0); + p.SetOutputNull(0.0); + JP2_encoder = new JP2Encoder(ui.GetFilename("TO"),alphacube->Samples(), + alphacube->Lines(),4,Isis::UnsignedByte); + datamin = 0; + datamax = 255; + } else if (ui.GetString("BITTYPE") == "S16BIT") { + jp2type = Isis::SignedWord; + for (int i=0; i<4; i++) { + jp2buf[i] = new char[alphacube->Samples()*2]; + } + p.SetOutputType(Isis::SignedWord); + p.SetOutputNull(-32768.0); + p.SetOutputRange(-32752.0,32767.0); + JP2_encoder = new JP2Encoder(ui.GetFilename("TO"),alphacube->Samples(), + alphacube->Lines(),4,Isis::SignedWord); + datamin = -32752; + datamax = 32767; + } else if (ui.GetString("BITTYPE") == "U16BIT") { + jp2type = Isis::UnsignedWord; + for (int i=0; i<4; i++) { + jp2buf[i] = new char[alphacube->Samples()*2]; + } + p.SetOutputType(Isis::UnsignedWord); + p.SetOutputNull(0.0); + p.SetOutputRange(3.0,65522.0); + JP2_encoder = new JP2Encoder(ui.GetFilename("TO"),alphacube->Samples(), + alphacube->Lines(),4,Isis::UnsignedWord); + datamin = 3; + datamax = 65522; + } + JP2_encoder->OpenFile(); + p.StartProcess(toJP2ARGB); + } + // Create a world file if it has a map projection + Filename fname(ui.GetFilename("TO")); + fname.RemoveExtension(); + fname.AddExtension(world); + p.CreateWorldFile(fname.Expanded()); + + p.EndProcess(); + delete JP2_encoder; + } else { + QList list = QImageWriter::supportedImageFormats(); + QList::Iterator it = list.begin(); + bool supported = false; + while (it != list.end()) { + if (*it == QString(format.c_str())) supported = true; + ++it; + } + + if (!supported) { + string msg = "The installation of Trolltech/Qt does not support "; + msg += "your selected format ["+format+"]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Setup the required extension and world file + string extension(""),world(""); + if (format == "png") { + extension = "png"; + world = "pgw"; + } + else if (format == "jpeg") { + extension = "jpg"; + world = "jgw"; + } + else if (format == "tiff") { + extension = "tif"; + world = "tfw"; + } + else if (format == "gif") { + extension = "gif"; + world = "gfw"; + } + else if (format == "bmp") { + extension = "bmp"; + world = "bpw"; + } + + // Cubes with less than three bands will be greyscale + if (mode == "GRAYSCALE") { + Cube *icube = p.SetInputCube("FROM", Isis::OneBand); + checkDataSize(icube->Lines(),icube->Samples(),mode); + qimage = new QImage(icube->Samples(),icube->Lines(), QImage::Format_Indexed8); + qimage->setNumColors(256); + QVector colors; + // create the color table (black = 0 to white = 255) + for (int i = 0; i<256; i++) { + colors.push_back(qRgb(i,i,i)); + } + qimage->setColorTable(colors); + p.SetInputRange(); + p.SetOutputRange(1.0,255.0); + p.SetOutputNull(0.0); + p.StartProcess(toGreyscaleImage); + } + // If RGB, create a 24-bit color image + // (1st band -> red, 2nd band -> green, 3rd band -> blue) + else if (mode == "RGB") { + Cube *redcube = p.SetInputCube("RED", Isis::OneBand); + checkDataSize(redcube->Lines(),redcube->Samples(),mode); + p.SetInputCube("GREEN", Isis::OneBand); + p.SetInputCube("BLUE", Isis::OneBand); + qimage = new QImage(redcube->Samples(),redcube->Lines(),QImage::Format_RGB32); + if (ui.GetString("STRETCH") == "MANUAL") { + p.SetInputRange(ui.GetDouble("RMIN"), ui.GetDouble("RMAX"), 0); + p.SetInputRange(ui.GetDouble("GMIN"), ui.GetDouble("GMAX"), 1); + p.SetInputRange(ui.GetDouble("BMIN"), ui.GetDouble("BMAX"), 2); + } + else { + p.SetInputRange(); + ui.Clear("MINIMUM"); + ui.Clear("MAXIMUM"); + ui.PutDouble("RMIN", p.GetInputMinimum(0)); + ui.PutDouble("RMAX", p.GetInputMaximum(0)); + ui.PutDouble("GMIN", p.GetInputMinimum(1)); + ui.PutDouble("GMAX", p.GetInputMaximum(1)); + ui.PutDouble("BMIN", p.GetInputMinimum(2)); + ui.PutDouble("BMAX", p.GetInputMaximum(2)); + } + p.SetOutputRange(1.0,255.0); + p.SetOutputNull(0.0); + p.StartProcess(toRGBImage); + } + else if (mode == "ARGB") { + Cube *alpha = p.SetInputCube("ALPHA", Isis::OneBand); + checkDataSize(alpha->Lines(),alpha->Samples(),mode); + p.SetInputCube("RED", Isis::OneBand); + p.SetInputCube("GREEN", Isis::OneBand); + p.SetInputCube("BLUE", Isis::OneBand); + qimage = new QImage(alpha->Samples(),alpha->Lines(),QImage::Format_ARGB32); + if (ui.GetString("STRETCH") == "MANUAL") { + p.SetInputRange(ui.GetDouble("AMIN"), ui.GetDouble("AMAX"), 0); + p.SetInputRange(ui.GetDouble("RMIN"), ui.GetDouble("RMAX"), 1); + p.SetInputRange(ui.GetDouble("GMIN"), ui.GetDouble("GMAX"), 2); + p.SetInputRange(ui.GetDouble("BMIN"), ui.GetDouble("BMAX"), 3); + } + else { + p.SetInputRange(); + ui.Clear("MINIMUM"); + ui.Clear("MAXIMUM"); + ui.PutDouble("AMIN", p.GetInputMinimum(0)); + ui.PutDouble("AMAX", p.GetInputMaximum(0)); + ui.PutDouble("RMIN", p.GetInputMinimum(1)); + ui.PutDouble("RMAX", p.GetInputMaximum(1)); + ui.PutDouble("GMIN", p.GetInputMinimum(2)); + ui.PutDouble("GMAX", p.GetInputMaximum(2)); + ui.PutDouble("BMIN", p.GetInputMinimum(3)); + ui.PutDouble("BMAX", p.GetInputMaximum(3)); + } + p.SetOutputRange(1.0,255.0); + p.SetOutputNull(0.0); + p.StartProcess(toARGBImage); + } + + // Get the name of the file and write it + Filename fname(ui.GetFilename("TO")); + fname.AddExtension(extension); + string filename(fname.Expanded()); + + // The return status is wrong for JPEG images, so the code will always + // continue. + if(!qimage->save(filename.c_str(),format.c_str(),quality)) { + delete qimage; + iString err = "Unable to save ["; + err += filename.c_str(); + err += "] to the disk"; + throw iException::Message(iException::User, err, _FILEINFO_); + } + + // Create a world file if it has a map projection + fname.RemoveExtension(); + fname.AddExtension(world); + p.CreateWorldFile(fname.Expanded()); + p.EndProcess(); + + delete qimage; + } +} + +// Write a line of data to the greyscale qimage object +void toGreyscaleImage (Buffer &in) { + // Loop for each column and load the pixel from in[i] which will + // be in the range of [0,255] + for (int i=0; i 255) dn = 255; + qimage->setPixel(i, in.Line()-1, dn); + // Since the plausable "exception" thrown by setPixel cannot be caught, + // the following if statement does it informally. + if( !qimage->valid(i,in.Line()-1) ) { + string msg = "QT has detected your file size as exceeding 2GB."; + msg += " While your image might be under 2GB, your image labels are more"; + msg += " than likely pushing the file size over 2GB."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } +} + +// Check to see if the QImage will be larger than 2GB +// error if it will be +void checkDataSize (Isis::BigInt line, Isis::BigInt samp, iString mode){ + Isis::BigInt maxSize = (Isis::BigInt)2*1024*1024*1024; //2GB limit + Isis::BigInt size = 0; + if(mode == "GRAYSCALE") { + size = line*samp; + } else if(mode == "RGB") { + size = (line*samp)*3; + } else if(mode == "ARGB") { + size = (line*samp)*4; + } + if (size >= maxSize) { + double inGB = (double)size / (1024*1024*1024); + string msg = "Cube exceeds max size of 2GB. Qimage cannot support "; + msg += "that much raw data. Your cube is "+(iString)inGB+" GB."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + return; +} + +// Write a line of data to the rgb qimage object +void toRGBImage (vector &in) { + Buffer &red = *in[0]; + Buffer &green = *in[1]; + Buffer &blue = *in[2]; + + // Set magick pointer to the desired row and construct a Color + QRgb *line = (QRgb *) qimage->scanLine(red.Line()-1); + + // Loop for each column and load the pixel from in[i] which will + // be in the range of [0,255] + for (int i=0; i 255) redDN = 255; + + int greenDN = (int)green[i]; + if (greenDN < 0) greenDN = 0; + else if (greenDN > 255) greenDN = 255; + + int blueDN = (int)blue[i]; + if (blueDN < 0) blueDN = 0; + else if (blueDN > 255) blueDN = 255; + + line[i] = qRgb(redDN, greenDN, blueDN); + } +} + +// Write a line of data to the argb qimage object +void toARGBImage (vector &in) { + Buffer &alpha = *in[0]; + Buffer &red = *in[1]; + Buffer &green = *in[2]; + Buffer &blue = *in[3]; + + // Set magick pointer to the desired row and construct a Color + QRgb *line = (QRgb *) qimage->scanLine(red.Line()-1); + + // Loop for each column and load the pixel from in[i] which will + // be in the range of [0,255] + for (int i=0; i 255) redDN = 255; + + int greenDN = (int)green[i]; + if (greenDN < 0) greenDN = 0; + else if (greenDN > 255) greenDN = 255; + + int blueDN = (int)blue[i]; + if (blueDN < 0) blueDN = 0; + else if (blueDN > 255) blueDN = 255; + + int alphaDN = (int)alpha[i]; + if (alphaDN < 0) alphaDN = 0; + else if (alphaDN > 255) alphaDN = 255; + + line[i] = qRgba(redDN, greenDN, blueDN, alphaDN); + } +} + +// Write a line of data to the JP2 object +void toJP2 (Buffer &in) { + int dn; + for (int i=0; iSamples(); i++) { + dn = ((int)in[i] < datamin) ? datamin : (int)in[i]; + dn = ((int)in[i] > datamax) ? datamax : (int)in[i]; + if (jp2type == Isis::UnsignedByte) { + ((unsigned char*)jp2buf[0])[i] = (unsigned char)dn; + } else if (jp2type == Isis::SignedWord) { + ((short int*)jp2buf[0])[i] = (short int)dn; + } else if (jp2type == Isis::UnsignedWord) { + ((short unsigned int*)jp2buf[0])[i] = (short unsigned int)dn; + } + } + if (jp2type == Isis::UnsignedByte) { + JP2_encoder->Write((unsigned char**)jp2buf); + } else { + JP2_encoder->Write((short int**)jp2buf); + } +} + +// Write a line of data to the JP2 RGB object +void toJP2RGB (vector &in) { + Buffer &red = *in[0]; + Buffer &green = *in[1]; + Buffer &blue = *in[2]; + + int reddn; + int greendn; + int bluedn; + for (int i=0; i datamax) ? datamax : (int)red[i]; + greendn = ((int)green[i] < datamin) ? datamin : (int)green[i]; + greendn = ((int)green[i] > datamax) ? datamax : (int)green[i]; + bluedn = ((int)blue[i] < datamin) ? datamin : (int)blue[i]; + bluedn = ((int)blue[i] > datamax) ? datamax : (int)blue[i]; + if (jp2type == Isis::UnsignedByte) { + ((unsigned char*)jp2buf[0])[i] = (unsigned char)reddn; + ((unsigned char*)jp2buf[1])[i] = (unsigned char)greendn; + ((unsigned char*)jp2buf[2])[i] = (unsigned char)bluedn; + } else if (jp2type == Isis::SignedWord) { + ((short int*)jp2buf[0])[i] = (short int)reddn; + ((short int*)jp2buf[1])[i] = (short int)greendn; + ((short int*)jp2buf[2])[i] = (short int)bluedn; + } else if (jp2type == Isis::UnsignedWord) { + ((short unsigned int*)jp2buf[0])[i] = (short unsigned int)reddn; + ((short unsigned int*)jp2buf[1])[i] = (short unsigned int)greendn; + ((short unsigned int*)jp2buf[2])[i] = (short unsigned int)bluedn; + } + } + if (jp2type == Isis::UnsignedByte) { + JP2_encoder->Write((unsigned char**)jp2buf); + } else { + JP2_encoder->Write((short int**)jp2buf); + } +} + +// Write a line of data to the JP2 ARGB object +void toJP2ARGB (vector &in) { + Buffer &alpha = *in[0]; + Buffer &red = *in[1]; + Buffer &green = *in[2]; + Buffer &blue = *in[3]; + + int reddn; + int greendn; + int bluedn; + int alphadn; + for (int i=0; i datamax) ? datamax : (int)red[i]; + greendn = ((int)green[i] < datamin) ? datamin : (int)green[i]; + greendn = ((int)green[i] > datamax) ? datamax : (int)green[i]; + bluedn = ((int)blue[i] < datamin) ? datamin : (int)blue[i]; + bluedn = ((int)blue[i] > datamax) ? datamax : (int)blue[i]; + alphadn = ((int)alpha[i] < datamin) ? datamin : (int)alpha[i]; + alphadn = ((int)alpha[i] > datamax) ? datamax : (int)alpha[i]; + if (jp2type == Isis::UnsignedByte) { + ((unsigned char*)jp2buf[0])[i] = (unsigned char)reddn; + ((unsigned char*)jp2buf[1])[i] = (unsigned char)greendn; + ((unsigned char*)jp2buf[2])[i] = (unsigned char)bluedn; + ((unsigned char*)jp2buf[3])[i] = (unsigned char)alphadn; + } else if (jp2type == Isis::SignedWord) { + ((short int*)jp2buf[0])[i] = (short int)reddn; + ((short int*)jp2buf[1])[i] = (short int)greendn; + ((short int*)jp2buf[2])[i] = (short int)bluedn; + ((short int*)jp2buf[3])[i] = (short int)alphadn; + } else if (jp2type == Isis::UnsignedWord) { + ((short unsigned int*)jp2buf[0])[i] = (short unsigned int)reddn; + ((short unsigned int*)jp2buf[1])[i] = (short unsigned int)greendn; + ((short unsigned int*)jp2buf[2])[i] = (short unsigned int)bluedn; + ((short unsigned int*)jp2buf[3])[i] = (short unsigned int)alphadn; + } + } + if (jp2type == Isis::UnsignedByte) { + JP2_encoder->Write((unsigned char**)jp2buf); + } else { + JP2_encoder->Write((short int**)jp2buf); + } +} diff --git a/isis/src/base/apps/isis2std/isis2std.xml b/isis/src/base/apps/isis2std/isis2std.xml new file mode 100644 index 0000000000000000000000000000000000000000..dcaeb3fbb0c4561c310e018f801d358cf9faa6a4 --- /dev/null +++ b/isis/src/base/apps/isis2std/isis2std.xml @@ -0,0 +1,582 @@ + + + + + + Exports a cube to PNG, JPEG, TIFF, JPEG2000 format + + + +

    + This program will export an Isis cube to one of several popular standard + formats. The formats may include PNG, JPEG, TIFF, BMP, GIF, and JP2. + Not all formats are available as the program implementation depends on the + Qt library by TrollTech. The JPEG2000 (JP2) format does not depend on the + Qt library for support. Support for JP2 is handled internally by the ISIS3 + library. This program requires the input cube have exactly one band. + Therefore, you must input a cube with exactly one band or a multi-band + cube with a band specifier (e.g., file.cub+4). In addition if the cube + has Mapping labels, the program will produce a world file for use in Arc + and/or other GIS type packages. The file will have an extension that + uses the first and last letters for the image extenstion and a "w". For + example, tif produces a world file extension of tfw. +

    + +

    + In order to ensure acceptable contrast in + the output file, three stretch options are given 1) linear, + 2) piecewise-linear, and 3) manual. + Special pixels are mapped in the following manner, Low Saturation values + and Null are made black and High Saturation values are made white. + Please note: there is currently a 2GB filesize limit on the output image. + This limit does not apply to output JPEG2000 files. JPEG2000 files can + be output as 8-bit, signed 16-bit, or unsigned 16-bit files. +

    +
    + + + + Original version + + + Added application test + + + Added two new modes (rgb and argb) and updated the appTest. + + + Added MIN and MAX percent options + + + Added seperate MINIMUM and MAXIMUM parameters for all channels. + + + Modified to use Filename class, and added appropriate appTest + + + Modified to give an error if write fails. Memory leak fixed. + + + Modified so that ISIS Null pixels are written as zeros in the output cube + and low data in the input is written as a one + + + Added a check to see that raw image data will be less than 4GB. + Throw exception if it is too big. + + + Removed references to CubeInfo + + + Added QUALITY parameter to set compression levels + + + Fixed checkDataSize() since Qimage has a maximum size of 2 GB, not 4GB. + Added some QT error catching. + + + Documentation Change + + + Added support for JPEG2000 files. + + + + + Import and Export + + + + + isis2raw + isis2fits + + + + + dform + isis2tif + isis2jpg + isis2gisworld + + + + + + cube + input + + Input cube to export + + + Use this parameter to select the filename and band to export. For + example, file.cub+5 will select band 5 + + + *.cub + + + + + cube + input + + Input cube to export as the alpha channel + + + Use this parameter to select the filename and band to export. For + example, file.cub+5 will select band 5 + + + *.cub + + + + + cube + input + + Input cube to export as the red channel + + + Use this parameter to select the filename and band to export. For + example, file.cub+5 will select band 5 + + + *.cub + + + + + cube + input + + Input cube to export as the green channel + + + Use this parameter to select the filename and band to export. For + example, file.cub+5 will select band 5 + + + *.cub + + + + + cube + input + + Input cube to export as the blue channel + + + Use this parameter to select the filename and band to export. For + example, file.cub+5 will select band 5 + + + *.cub + + + + + filename + output + + Output file + + + Use this parameter to specify the name of the output image. + Don not include an extension as one will be automatically added. + + + + + string + GRAYSCALE + Image mode + + This parameter specifies the image mode. If GRAYSCALE, a single one-band cube is used. + If RGB, three one-band cubes are used. + + + + + + + + + + + + string + + PNG + + Format of output image + + This parameter is used to select the output format. It can + be one of PNG, BMP, JPEG, TIF, GIF, or JP2. Note that not all + formats are available. It will depend on your installation + of the Qt libraries. + + + + + + + + + + + + + integer + Specify output image quality + 100 + + This parameter allows the user to specify level of quality + (compression) for the output image. Some output image types may + not utilize this parameter. The range is from 100 (no + compression and highest quality) to 0 (highest compression and + reduced quality). A value of -1 can be given to use the default + settings. + + -1 + 100 + + + string + + 8BIT + + Bit type of output file + + Bit type of output: + 8 bit (0=black, 255=white) + 16 bit unsigned (0=black, 65535=white) + 16 bit signed (-32767=black, 32768=white) + + + + + + + + + + + + string + + LINEAR + + Type of stretch + + This parameter is used to select one of three ways to stretch + (or map) output pixels. The are LINEAR, PIECEWISE, or MANUAL. + + + + + + + + + + + double + Minimum pixel value + + The minimum input pixel value which will be mapped to black. + + + MAXIMUM + + + + + double + Maximum pixel value + + The maximum input pixel value which will be mapped to white. + + + MINIMUM + + + + + double + Minimum pixel value format the alpha channel + + The minimum input pixel value which will be mapped to black. + + + AMAX + + + + + double + Maximum pixel value for the alpha channel + + The maximum input pixel value which will be mapped to white. + + + AMIN + + + + + double + Minimum pixel value for the red channel + + The minimum input pixel value which will be mapped to black. + + + RMAX + + + + + double + Maximum pixel value for the red channel + + The maximum input pixel value which will be mapped to white. + + + RMIN + + + + + double + Minimum pixel value for the green channel + + The minimum input pixel value which will be mapped to black. + + + GMAX + + + + + double + Maximum pixel value for the green channel + + The maximum input pixel value which will be mapped to white. + + + GMIN + + + + + double + Minimum pixel value for the blue channel + + The minimum input pixel value which will be mapped to black. + + + BMAX + + + + + double + Maximum pixel value for the blue channel + + The maximum input pixel value which will be mapped to white. + + + BMIN + + + + + double + Minimum Percent + + The percentage of data in the histogram used to compute the minimum pixel value in the stretch. + + 0.5 + + MAXPERCENT + + + + + double + Maximum Percent + + The percentage of data in the histogram used to compute the maximum pixel value in the stretch. + + 99.5 + + MINPERCENT + + + + +
    diff --git a/isis/src/base/apps/isis2std/tsts/Makefile b/isis/src/base/apps/isis2std/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/isis2std/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/isis2std/tsts/grayscaleBMP/Makefile b/isis/src/base/apps/isis2std/tsts/grayscaleBMP/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ecb3b6d26fef5d001299aea53d5df1a9ee8d446f --- /dev/null +++ b/isis/src/base/apps/isis2std/tsts/grayscaleBMP/Makefile @@ -0,0 +1,13 @@ +APPNAME = isis2std + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2stdTruth2.bmp \ + mode=grayscale \ + format=bmp \ + stretch=linear > /dev/null; + std2isis FROM=$(OUTPUT)/isis2stdTruth2.bmp \ + TO=$(OUTPUT)/isis2stdTruth2.cub >/dev/null; + rm -f $(OUTPUT)/isis2stdTruth2.bmp; diff --git a/isis/src/base/apps/isis2std/tsts/grayscalePNG/Makefile b/isis/src/base/apps/isis2std/tsts/grayscalePNG/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8f2b526002d1dbc2ae66a31427fecba481f0152c --- /dev/null +++ b/isis/src/base/apps/isis2std/tsts/grayscalePNG/Makefile @@ -0,0 +1,13 @@ +APPNAME = isis2std + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2stdTruth1.png \ + mode=grayscale \ + format=png \ + stretch=linear > /dev/null; + std2isis FROM=$(OUTPUT)/isis2stdTruth1.png \ + TO=$(OUTPUT)/isis2stdTruth1.cub > /dev/null; + rm -f $(OUTPUT)/isis2stdTruth1.png; diff --git a/isis/src/base/apps/isis2std/tsts/manualStretch/Makefile b/isis/src/base/apps/isis2std/tsts/manualStretch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7ca8e41e86dc047191620dbb57b9de66dfa27b51 --- /dev/null +++ b/isis/src/base/apps/isis2std/tsts/manualStretch/Makefile @@ -0,0 +1,15 @@ +APPNAME = isis2std + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2stdTruth3.png \ + mode=grayscale \ + format=png \ + stretch=manual \ + minimum = -1e20 \ + maximum = 1e20 > /dev/null; + std2isis FROM=$(OUTPUT)/isis2stdTruth3.png \ + TO=$(OUTPUT)/isis2stdTruth3.cub > /dev/null; + rm -f $(OUTPUT)/isis2stdTruth3.png; diff --git a/isis/src/base/apps/isis2std/tsts/piecewise/Makefile b/isis/src/base/apps/isis2std/tsts/piecewise/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..52e1cc88760f0581d8402eafac399588bd5cbff0 --- /dev/null +++ b/isis/src/base/apps/isis2std/tsts/piecewise/Makefile @@ -0,0 +1,14 @@ +APPNAME = isis2std + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/isis2stdTruth4.png \ + mode=grayscale \ + format=png \ + stretch=piecewise > /dev/null; + std2isis FROM=$(OUTPUT)/isis2stdTruth4.png \ + MODE=grayscale \ + TO=$(OUTPUT)/isis2stdTruth4.cub > /dev/null; + rm -f $(OUTPUT)/isis2stdTruth4.png; diff --git a/isis/src/base/apps/isis2std/tsts/rgb/Makefile b/isis/src/base/apps/isis2std/tsts/rgb/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..93d37e3f9ffaeca433f9710066bd7ec05fb5e105 --- /dev/null +++ b/isis/src/base/apps/isis2std/tsts/rgb/Makefile @@ -0,0 +1,15 @@ +APPNAME = isis2std + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) red=$(INPUT)/isisTruth.cub+1 \ + green=$(INPUT)/isisTruth.cub+1 \ + blue=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/isis2stdTruth5.png \ + mode=rgb \ + format=png \ + stretch=linear > /dev/null; + std2isis FROM=$(OUTPUT)/isis2stdTruth5.png \ + TO=$(OUTPUT)/isis2stdTruth5.cub > /dev/null; + rm -rf $(OUTPUT)/isis2stdTruth5.png; diff --git a/isis/src/base/apps/isis2std/tsts/toobig/Makefile b/isis/src/base/apps/isis2std/tsts/toobig/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fa61d8979a190576c84f9c45f6d94f6cb66a5089 --- /dev/null +++ b/isis/src/base/apps/isis2std/tsts/toobig/Makefile @@ -0,0 +1,16 @@ +APPNAME = isis2std + +include $(ISISROOT)/make/isismake.tsts + +commands: + if [ `$(APPNAME) from=$(INPUT)/large.lbl \ + to=$(OUTPUT)/isis2stdTruth1.png \ + mode=grayscale \ + format=png \ + stretch=linear \ + -preference=$(ISISROOT)/src/base/objs/Preference/TestPreferences \ + >& $(OUTPUT)/error.txt` ]; \ + then \ + true; \ + fi; \ + diff --git a/isis/src/base/apps/isisui/Makefile b/isis/src/base/apps/isisui/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/isisui/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/isisui/isisui.cpp b/isis/src/base/apps/isisui/isisui.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1670155d1fb2fc9b3a2ae0bfb43895a9ee9f5cb8 --- /dev/null +++ b/isis/src/base/apps/isisui/isisui.cpp @@ -0,0 +1,21 @@ +#include "Application.h" +#include "UserInterface.h" + +using namespace std; +using namespace Isis; + +void interface (); + +int main (int argc, char *argv[]) { + int i_argc(argc-1); + Application app(i_argc,&argv[1]); + return app.Exec(interface); +} + +void interface () { + PvlObject hist = Isis::iApp->History(); + PvlGroup up = hist.FindGroup("UserParameters"); + Pvl pvl; + pvl.AddGroup(up); + cout << pvl << endl; +} diff --git a/isis/src/base/apps/isisui/isisui.xml b/isis/src/base/apps/isisui/isisui.xml new file mode 100644 index 0000000000000000000000000000000000000000..dc71e6b1e42b5cdc378bd6381b3f0580864850b5 --- /dev/null +++ b/isis/src/base/apps/isisui/isisui.xml @@ -0,0 +1,158 @@ + + + + + Outputs the command line of any ISIS application + + + +

    + This program allows its user to output a validated command line for any + ISIS application. The parameters will be validated using the application's + xml file. Command line arguments will be used to initialize the + application's parameters. +

    +

    + If the GUI flag is not present on the command line, the + parameters will be validated and the command line will be output if no + errors were detected. +

    +

    + If the GUI flag is present on the command line, the GUI parameters fields + will be initilized using the command line arguments. The user will then + be able to change parameter values and supply values for ones not on the + command line. When the GUI is told to process the parameters, a validation + check is done. If there were errors, a message will be displayed and the + user will be allowed to correct the problem. If the validation succeeds + the command line will be output, and the GUI will be taken down. +

    +
    + + + Scripting + + + + + Original version + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Added modifications to apptest by Kim + + + Documentation fixes + + + Changed the call to Application to provide compatability withg Qt + startup requirements. + + + + + + + + string + + An ISIS application + + + The ISIS application you need the command line for. + Note: This must be the first command line option! + + + + + boolean + + Flag for starting the Isis GUI + + + If this flag is present anywhere on the command line, the Isis GUI + will be started. All application parameters from the other arguments + will be inserted into the correct fields. + + + + + string + + Arguments to the application named in arg1 + + + These arguments are specific to the application named in arg1. Their + formats and values are dependant on the application. + + + + + + + + + Display GUI for the program crop. + + + Display the GUI for the application "crop". Since there are no + parameter arguments for crop the fields will be initially empty. + + + + crop GUI + + + This example deminstrates how to get the GUI for the ISIS application + "crop" to be displayed. The parameters for crop will initially be + empty. + + + + + + + Display GUI for program ratio. + + + Display the GUI for the application "ratio". The arguments "num", + "den" and "to" will be used to fill in the corresponding parameter + values when the GUI is displayed. + + + + ratio GUI num=$WORK/numerator.cub:3 + den=denominated.cub:1 to=result.cub + + + This example deminstrates how to get the GUI for the ISIS application + "ratio" to be displayed. The parameters for ratio will initially be + set to the values from the command line. + + + + + + + Check the command line argument to ratio for validity without the GUI. + + + The argument "num" will be filled in when the GUI is displayed. + + + + ratio num=$WORK/numerator.cub:3 + + + This example deminstrates how to validate the parameters given on + the command line. No GUI will be displayed. This example will fail + with an error message since values were not specified for all the + required parameters. It will also set the exicution status to a non + zero (failes) value. + + + + +
    + diff --git a/isis/src/base/apps/isisui/tsts/Makefile b/isis/src/base/apps/isisui/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/isisui/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/isisui/tsts/circle/Makefile b/isis/src/base/apps/isisui/tsts/circle/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..61010336e5b40ffabbb95f643227e8a49c99cdcb --- /dev/null +++ b/isis/src/base/apps/isisui/tsts/circle/Makefile @@ -0,0 +1,7 @@ +APPNAME = isisui + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) circle from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/circle.cub sample=10 line=15 rad=27 > $(OUTPUT)/standardOutTruth3.pvl; diff --git a/isis/src/base/apps/isisui/tsts/gradient/Makefile b/isis/src/base/apps/isisui/tsts/gradient/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..eedf6671c60f9211c0b68c1a5590407e3b3ac1ca --- /dev/null +++ b/isis/src/base/apps/isisui/tsts/gradient/Makefile @@ -0,0 +1,9 @@ +APPNAME = isisui + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) gradient \ + from=$(INPUT)/isisTruth.cub \ + to=isisTruthSample.cub \ + gradtype=sobel > $(OUTPUT)/standardOutTruth2.pvl; diff --git a/isis/src/base/apps/isisui/tsts/ratio/Makefile b/isis/src/base/apps/isisui/tsts/ratio/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f17a4925964e8decfd2519a01d8e01af6bcdb2b9 --- /dev/null +++ b/isis/src/base/apps/isisui/tsts/ratio/Makefile @@ -0,0 +1,7 @@ +APPNAME = isisui + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) ratio num=numerator den=denominator \ + to=$(OUTPUT)/output.txt > $(OUTPUT)/standardOutTruth1.pvl; diff --git a/isis/src/base/apps/jigsaw/Makefile b/isis/src/base/apps/jigsaw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/jigsaw/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/jigsaw/jigsaw.cpp b/isis/src/base/apps/jigsaw/jigsaw.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c89984411cf5c9763594af30606d8655e087b17 --- /dev/null +++ b/isis/src/base/apps/jigsaw/jigsaw.cpp @@ -0,0 +1,133 @@ +#include "Isis.h" +#include "Process.h" +#include "BundleAdjust.h" +#include "Table.h" +#include "iException.h" +#include "CubeAttribute.h" +#include "iTime.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + + // Get the control network and image list + UserInterface &ui = Application::GetUserInterface(); + std::string cnetFile = ui.GetFilename("CNET"); + std::string cubeList = ui.GetFilename("FROMLIST"); + + // Get the held list if entered and prep for bundle adjustment + BundleAdjust *b = NULL; + + if (ui.WasEntered("HELDLIST")) { + std::string heldList = ui.GetFilename("HELDLIST"); + b = new BundleAdjust(cnetFile,cubeList,heldList); + } + else { + b = new BundleAdjust(cnetFile,cubeList); + } + + b->SetObservationMode(ui.GetBoolean("OBSERVATIONS")); + b->SetSolutionMethod(ui.GetString("METHOD")); + b->SetSolveRadii(ui.GetBoolean("RADIUS")); + + b->SetCkDegree(ui.GetInteger("CKDEGREE")); + b->SetSolveCamDegree(ui.GetInteger("SOLVEDEGREE")); + std::string camsolve = ui.GetString("CAMSOLVE"); + if (camsolve == "NONE") { + b->SetSolveCmatrix ( BundleAdjust::None ); + } + else if (camsolve == "ANGLES") { + b->SetSolveCmatrix ( BundleAdjust::AnglesOnly ); + } + else if (camsolve == "VELOCITIES") { + b->SetSolveCmatrix ( BundleAdjust::AnglesVelocity ); + } + else if (camsolve == "ACCELERATIONS") { + b->SetSolveCmatrix ( BundleAdjust::AnglesVelocityAcceleration ); + } + else { + b->SetSolveCmatrix ( BundleAdjust::All ); + } + + b->SetSolveTwist( ui.GetBoolean("TWIST")); + + std::string spsolve = ui.GetString("SPSOLVE"); + if (spsolve == "NONE") { + b->SetSolveSpacecraftPosition( BundleAdjust::Nothing ); + } + else if (spsolve == "POSITION") { + b->SetSolveSpacecraftPosition ( BundleAdjust::PositionOnly ); + } + else if (spsolve == "VELOCITIES") { + b->SetSolveSpacecraftPosition ( BundleAdjust::PositionVelocity ); + } + else { + b->SetSolveSpacecraftPosition ( BundleAdjust::PositionVelocityAcceleration ); + } + + // Check to make sure user entered something to adjust... Or can just points be in solution? + if (camsolve == "NONE" && spsolve == "NONE") { + string msg = "Must either solve for camera pointing or spacecraft position"; + throw iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + double tol = ui.GetDouble("TOL"); + int maxIterations = ui.GetInteger("MAXITS"); + + // Bundle adjust the network + try { + b->Solve(tol,maxIterations); + b->ControlNet()->Write(ui.GetFilename("ONET")); + PvlGroup gp( "JigsawResults" ); + + // Update the cube pointing if requested + if (ui.GetBoolean("UPDATE")) { + + for (int i=0; iImages(); i++) { + Process p; + CubeAttributeInput inAtt; + Cube *c = p.SetInputCube(b->Filename(i), inAtt, ReadWrite); + //check for existing polygon, if exists delete it + if (c->Label()->HasObject("Polygon")) { + c->Label()->DeleteObject("Polygon"); + } + + //check for CameraStatistics Table, if exists, delete + for (int iobj=0; iobjLabel()->Objects(); iobj++) { + PvlObject obj = c->Label()->Object(iobj); + if (obj.Name() != "Table") continue; + if (obj["Name"][0] != iString("CameraStatistics")) continue; + c->Label()->DeleteObject(iobj); + break; + } + + // Get Kernel group and add or replace LastModifiedInstrumentPointing + // keyword. + Table cmatrix = b->Cmatrix(i); + std::string jigComment = "Jigged = "+ Isis::iTime::CurrentLocalTime(); + cmatrix.Label().AddComment(jigComment); + Table spvector = b->SpVector(i); + spvector.Label().AddComment(jigComment); + c->Write(cmatrix); + c->Write(spvector); + p.WriteHistory(*c); + } + gp += PvlKeyword("Status", "Camera pointing updated"); + } + else { + gp += PvlKeyword("Status", "Camera pointing NOT updated"); + } + Application::Log( gp ); + } + + catch (iException &e) { + + b->ControlNet()->Write(ui.GetFilename("ONET")); + string msg = "Unable to bundle adjust network [" + cnetFile + "]"; + throw iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + delete b; + +} diff --git a/isis/src/base/apps/jigsaw/jigsaw.xml b/isis/src/base/apps/jigsaw/jigsaw.xml new file mode 100644 index 0000000000000000000000000000000000000000..20d71508b93326ac2fa78ec5dfaaa8fe2dab0879 --- /dev/null +++ b/isis/src/base/apps/jigsaw/jigsaw.xml @@ -0,0 +1,381 @@ + + + + Improves camera pointing + + + + This program takes as input a control network and list of level 1 cubes. It uses the control network to solve for new + camera pointing for each of the cubes. This helps eliminate mismatches in mosaics of multiple images. + + + + Control Networks + + + + + deltack + qnet + + + + + + Original version + + + Changed category to Control Networks and corrected XML bugs + + + Revised iteration report to list the errors and sigmas from the same iteration. Previous version reported errors from previous iteration and sigmas from current iteration. + + + Cleaned the Bundle Adjust memory leak and fixed the app tests. + + + Added date to the Jigged comment in the spice tables. + + + If updating pointing, delete the CameraStatistics table from labels. + + + Modified program to write history to input cubes. + + + + + + + + filename + input + + Cube list + + + This file contains a list of all cubes in the network + + + *.txt *.lis + + + + + filename + none + input + + Held list + + + This file contains a list of all cubes whose pointing angles will be held in the adjustment. + + + *.txt *.lis + + + + + filename + input + + Input control network + + + This file is a control network generated from programs such as autoseed or qnet + + + *.net + + + + + filename + output + + Output control network + + + This file will contain the update control network with residuals for each measurement. + + + *.net + + + + + + + Keep instances of the same observation in different cube files dependent + + This option will solve for spice on all cubes with a matching observation number as though they were a single image. + For most missions the default observation number is the serial number of the cube file so that a single cube is an observation. + However all Lunar Orbiter missions have defined observation numbers that are different from their serial numbers, so that the 3 + subframes of a Lunar Orbiter High Resolution frame will be treated as a single observation if this option is on. Otherwise each + subframe will be adjusted independently. + + boolean + + No + + + + + Solve for local radii of points + + Select this option to solve for the local radius of each control + point. If this button is not turned on, the radii of the points + will not change from the cube's shape model. + + boolean + + No + + + + + Update cube label + + This option will write the results of the solution to each cube in the FROMLIST. The pointing is written in the form of a SPICE + blob which is attached to the cube. This only occurs if the solution converged to the requested tolerance within the + the requested number of iterations. If this option is turned off, then only the output control network with the latitude/longitude/radius + for each point in the solution and and the point residuals is created. + + boolean + + Yes + + + + + string + Matrix solution method to use + + QRD + + +

    + Enter the desired method to use to solve the matrix. Methods will + vary in speed and accuracy. The default, QRD, is the preferred + method, unless the matrix is close to singular or the system being + solved has more than 2000 unknowns. A matrix might be close to + singular if some of the points are very close to each other, or if + some of the images have camera angles that are nearly identical. In + the case of a nearly singular matrix, the SVD method wil work the + best. For larger bundle adjustments involving more than 2000 + unknowns, the SPARSE option will work the best. To determine the + number of unknowns use the following formula: +

    +

    + Total # Unknowns = observCount * (camUnknowns + spUnknowns) + controlPt*ptUnknowns, +

    +
    +            where, observCount = the number of images or observations
    +
    +                   camUnknowns = 2, if CAMSOLVE=ANGLES and TWIST is not checked
    +                               = 3, if CAMSOLVE=ANGLES and TWIST is checked
    +                               = 4, if CAMSOLVE=VELOCITIES and TWIST is not checked                                     
    +                               = 5, if CAMSOLVE=VELOCITIES and TWIST is checked
    +                               = 6, if CAMSOLVE=ACCELERATIONS and TWIST is not checked
    +                               = 7, if CAMSOLVE=ACCELERATIONS and TWIST is checked
    +                               = SOLVEDEGREE * 2 if TWIST is not checked
    +                               = SOLVEDEGREE * 3 if TWIST is checked
    +
    +                    spUnknowns = 0, if SPSOLVE=NONE
    +                               = 3, if SPSOLVE=POSITION
    +                               = 6, if SPSOLVE=VELOCITIES
    +                               = 9, if SPSOLVE=ACCELERATIONS
    +
    +                     controlPt = The number of control points in the network
    +
    +                    ptUnknowns = 2, if RADIUS is not checked in the Solve Options box
    +                               = 3, if RADIUS is checked in the Solve Options box
    +        
    +
    + + + + + +
    +
    + + + + iterations + + Number of iterations + integer + + 5 + + + + + tolerance + Tolerance in pixels + double + + 0.5 + + + + + + + integer + + 2 + + + Degree of polynomial fit to original camera angles + + + The degree of the polynomial fit to the original camera angles + and used to generate apriori camera angles for the first + iteration. + + + + integer + + 2 + + + The degree of the polynomial being fit to in the bundle adjustment + + + The degree of the polynomial being fit to in the bundle adjust + solution. This polynomial can be different from the one used to + generate the apriori camera angles used in the first iteration. + In the case of an instrument with a jitter problem, a higher + degree polynomial fit to each of the camera angles might provide + a better solution (smaller errors). + + + + string + Sets which, if any, camera pointing factors to include in the bundle adjustment" + + ANGLES + + + This parameter is used to specify which camera pointing factors to fit in the adjustment. At least one item must be selected in this group or the spacecraft group, or the application will have nothing to adjust. + + + + + + + + + + + + + + + + Solve for twist? + + If this option is on, the twist angle will be adjusted in the bundle adjustment solution. + + boolean + + Yes + + + + + + + string + Sets which, if any, spacecraft position factors to include in the adjustment + + NONE + + + This parameter is used to specify which spacecraft position factors to fit in the adjustment. + + + + + + + + + + + + + +
    +
    diff --git a/isis/src/base/apps/jigsaw/tsts/Makefile b/isis/src/base/apps/jigsaw/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/jigsaw/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/jigsaw/tsts/case01/Makefile b/isis/src/base/apps/jigsaw/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3684f18000c939f710ab28a5bb5f4df404265834 --- /dev/null +++ b/isis/src/base/apps/jigsaw/tsts/case01/Makefile @@ -0,0 +1,20 @@ +APPNAME = jigsaw + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(CP) $(INPUT)/*.cub $(OUTPUT) > /dev/null; + $(LS) -1 $(OUTPUT)/*.cub > $(OUTPUT)/cube.lis; + $(APPNAME) fromlist=$(OUTPUT)/cube.lis \ + cnet=$(INPUT)/redPntreg.net \ + onet=$(OUTPUT)/case01OutNet.pvl \ + observations=yes \ + method=qrd \ + tol=1.64742389 \ + solvedegree=3 \ + camsolve=all \ + twist=no | grep -v "100% Processed" | \ + grep -v "jigsaw" > $(OUTPUT)/case01OutLog.pvl; + $(RM) $(OUTPUT)/cube.lis > /dev/null; + cathist from=$(OUTPUT)/PSP_002733_1880_RED4.crop.cub > $(OUTPUT)/PSP4.pvl; + cathist from=$(OUTPUT)/PSP_002733_1880_RED5.crop.cub > $(OUTPUT)/PSP5.pvl; diff --git a/isis/src/base/apps/jigsaw/tsts/case2/Makefile b/isis/src/base/apps/jigsaw/tsts/case2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a26674057ef4cdb3b6c2e00270231ba8cb67e7dd --- /dev/null +++ b/isis/src/base/apps/jigsaw/tsts/case2/Makefile @@ -0,0 +1,19 @@ +APPNAME = jigsaw +#This test exercises the held image option, SVD solution method, and spsolve=position. + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) -1 $(INPUT)/*.cub > $(OUTPUT)/cub.lis; + $(LS) -1 $(INPUT)/e0400710.lev1.cub > $(OUTPUT)/held.lis; + + $(APPNAME) fromlist=$(OUTPUT)/cub.lis \ + heldlist=$(OUTPUT)/held.lis \ + cnet=$(INPUT)/mocVik.net \ + onet=$(OUTPUT)/case2OutNet.pvl \ + maxits=10 \ + tol=0.908 \ + update=no \ + spsolve=position | grep -v "100% Processed" | \ + grep -v "jigsaw" > $(OUTPUT)/case2OutLog.pvl; + $(RM) $(OUTPUT)/cub.lis $(OUTPUT)/held.lis > /dev/null; diff --git a/isis/src/base/apps/kernfilter/Makefile b/isis/src/base/apps/kernfilter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/kernfilter/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/kernfilter/assets/images/kernDerivative.jpg b/isis/src/base/apps/kernfilter/assets/images/kernDerivative.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bf7334eeb12669e56cc090359c64e24db12eb5e2 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/images/kernDerivative.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/images/kernDerivativeGui.jpg b/isis/src/base/apps/kernfilter/assets/images/kernDerivativeGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..596ef73dffcecdab67cbeff846e344d4879d7215 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/images/kernDerivativeGui.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/images/kernHighpass.jpg b/isis/src/base/apps/kernfilter/assets/images/kernHighpass.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0da5619d47691e445af707a83f3b70d1e9a5d687 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/images/kernHighpass.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/images/kernHighpassGui.jpg b/isis/src/base/apps/kernfilter/assets/images/kernHighpassGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..146f9ae28bbbd147f647f0c3d6daf2df833ba8f4 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/images/kernHighpassGui.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/images/kernSmooth.jpg b/isis/src/base/apps/kernfilter/assets/images/kernSmooth.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c3c63367b6c51b092110a1da9ed96d8bfdc324d5 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/images/kernSmooth.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/images/kernSmoothGui.jpg b/isis/src/base/apps/kernfilter/assets/images/kernSmoothGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..6503cbc7323b84525f57def5d6cb5880101d40a7 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/images/kernSmoothGui.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/images/peaks.jpg b/isis/src/base/apps/kernfilter/assets/images/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..22ee658b0c230aec89f3564c1e4b3de9ec49df12 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/images/peaks.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/thumbs/kernDerivative.jpg b/isis/src/base/apps/kernfilter/assets/thumbs/kernDerivative.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8b0b83e27de5f40ca0cfab938dc5e3545584f019 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/thumbs/kernDerivative.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/thumbs/kernDerivativeGui.jpg b/isis/src/base/apps/kernfilter/assets/thumbs/kernDerivativeGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..59833f54c4f07c24f794ff368c5dbaa1cacfd1d5 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/thumbs/kernDerivativeGui.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/thumbs/kernHighpass.jpg b/isis/src/base/apps/kernfilter/assets/thumbs/kernHighpass.jpg new file mode 100644 index 0000000000000000000000000000000000000000..722ba88550f2bdb7e28c79607258071d95b092d1 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/thumbs/kernHighpass.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/thumbs/kernHighpassGui.jpg b/isis/src/base/apps/kernfilter/assets/thumbs/kernHighpassGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..146f9ae28bbbd147f647f0c3d6daf2df833ba8f4 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/thumbs/kernHighpassGui.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/thumbs/kernSmooth.jpg b/isis/src/base/apps/kernfilter/assets/thumbs/kernSmooth.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b1da8bb3bb49f7e352f4c4f6920940f68c250a15 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/thumbs/kernSmooth.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/thumbs/kernSmoothGui.jpg b/isis/src/base/apps/kernfilter/assets/thumbs/kernSmoothGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..6503cbc7323b84525f57def5d6cb5880101d40a7 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/thumbs/kernSmoothGui.jpg differ diff --git a/isis/src/base/apps/kernfilter/assets/thumbs/peaks.jpg b/isis/src/base/apps/kernfilter/assets/thumbs/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e0df3d4fb0ebc3096c3a238f04077f4b59898268 Binary files /dev/null and b/isis/src/base/apps/kernfilter/assets/thumbs/peaks.jpg differ diff --git a/isis/src/base/apps/kernfilter/kernfilter.cpp b/isis/src/base/apps/kernfilter/kernfilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..290bb03c667d2cf1ec4a993e0bff983a98a4b45f --- /dev/null +++ b/isis/src/base/apps/kernfilter/kernfilter.cpp @@ -0,0 +1,87 @@ +#include "Isis.h" + +#include "iException.h" +#include "iString.h" +#include "ProcessByBoxcar.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "SpecialPixel.h" + +#include + +using namespace std; +using namespace Isis; + +void filter (Buffer &in, double &v); +vector coefs; +double weight; + +void IsisMain() { + + // Get information from the input kernel + UserInterface &ui = Application::GetUserInterface(); + Pvl pvl(ui.GetFilename("KERNEL")); + + // Access the Kernel group section of the input file + const PvlGroup &kern = pvl.FindGroup("KERNEL"); + + int lines = kern["lines"]; + int samples = kern["samples"]; + + // Error check kernel input for impossible boxcar sizes + if (lines <= 0) { + iString msg = "Your kernel must specify lines count greater than 0"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + if (samples <= 0) { + iString msg = "Your kernel must specify samples count greater than 0"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Error check kernel for proper amount of data - lines*samples + if (lines*samples != kern["data"].Size()) { + iString msg = "Your kernel does not specify the correct amount of data, must"; + msg += " be equal to lines * samples ["; + msg += iString(lines * samples); + msg += "] pieces of data"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + ProcessByBoxcar p; + + // Allocate cubes + p.SetInputCube ("FROM"); + p.SetOutputCube ("TO"); + p.SetBoxcarSize (samples,lines); + + // Iterate through the input kernel's data values to fill the coefs array + for (int i = 0 ; i < kern["data"].Size() ; i ++) { + coefs.push_back(kern["data"][i]); + } + + // Weight for multiplication of resultant immidately before completion + weight = kern["weight"]; + + p.StartProcess(filter); + p.EndProcess (); +} + + +//! The filter depends on the user input kernel +void filter (Buffer &in, double &result) { + result = 0.0; + for (int i= 0; i < in.size() && result != Isis::Null; i++) { + if (!IsSpecial(in[i])) { + result += in[i] * coefs[i] ; + } + else { + // If a special pixel is encountered with the boxcar, resultant pixel is nulled + result = Isis::Null; + } + } + + // If the result isn't null, finish the processing + if (result != Isis::Null) { + result *= weight; + } +} diff --git a/isis/src/base/apps/kernfilter/kernfilter.xml b/isis/src/base/apps/kernfilter/kernfilter.xml new file mode 100644 index 0000000000000000000000000000000000000000..3f61ed020f4e80ff5e8da91cd4ff3e6c3b0a24ef --- /dev/null +++ b/isis/src/base/apps/kernfilter/kernfilter.xml @@ -0,0 +1,392 @@ + + + + + + Filter a cube through a kernel + + + + This program uses a kernel gathered from an input file to filter a cube. + The intent of the program is to allow a flexible, user-defined kernel to + be applied to an image. This program is not recommended for cubes with + significant numbers of special pixels as it will create more special pixels. + A group of pre-made kernels has been provided, but the procedure to + create a custom kernel is outlined below. +

    A kernel follows + the rules and regulations of the Isis PVL (parameter value language). This + means that several keywords must be inserted into the text document which + will become the custom kernel. Any text editor should allow you to create a + kernel, though the program will only read files with the .txt extension. In + addition, there are some specifications that must be met.

    A sample + kernel file will appear in the form +

     
    +    Group=Kernel 
    +      Samples=2 
    +      Lines=1 
    +      Weight=1 
    +      Data= (1, -1)
    +    EndGroup
    +    
    + The "group" keyword should equal Kernel (Group=Kernel). This lets the + program know that it is the users intent that the text file is used as a + kernel. +

    + The "lines" and "samples" keywords should match the amount of data that + is supplied in the data keyword. In this example, there are 2 samples + worth of data and 1 line worth. The keywords above thus reflect these + values. +

    + The "weight" is applied to all of the values in the kernel. It is + often set to a fraction that allows for averaging, but it is a value + that is used differently by each type of filter simulated by the + kernel. Since the above filter uses no averaging, the weight is simply 1. +

    + The "data" defines a set of multiplicative constants. These multiplicative + constants are the weights that the kernfilter will use on the input image. + In our example, assume that the DNs being examined are 10 and 20. The + first DN (10) would be multiplied by the first weight (1). The second DN + (20) would be multiplied by the second weight (-1). The two products (10 + and -20) would then be added together and the resultant sum (-10) would + be output. The set of data should be enclosed in parentheses. For + organizational purposes, one may insert as much or as little white space + as they desire but they must separate each constant with a comma. +

    + Finally, the document should be finished with the keyword "EndGroup" to + signify that no more information is provided. + + + + + Original version + + + Added application test + + + Added examples + + + Moved kernel files to the $base/templates/kernels folder + + + Added error checking for kernel input, modified special pixel handling to + null resultant pixel, added example, added application test, changed + pixel type to real. + + + + + Filters + + + + + + cube + input + + Input cube to be filtered + + + Use this parameter to select the filename. All bands within the file + will be filtered. + + + *.cub + + + + + cube + real + output + + Output cube + + + This file will contain the results of the filter + + + *.cub + + + + + filename + input + $base/templates/kernels/ + + The kernel that describes the filter to be applied + + + Use this parameter to select the file to be used as the kernel. + The input kernel is by default found in the "kernels" directory and + includes several examples that can be used to filter images. + + + *.txt + + + + + + + + + + Using the highpassCircle5x5.txt kernel + + + This example assumes that a kernel named "highpassCircle5x5.txt" (which + is provided with the program) exists in the "kernels" file that is + created by default. The program does not actually run a highpass + algorithm on the cube. Instead, it weighs the pixels with a common + algorithm that adds all of the weighted pixel values together and + outputs that sum as the center pixel of the boxcar. The weights, which + are provided by the user-specified parameter "kernel" define the + characteristics of that final sum. In this example, the kernel + "highpassCircle5x5.txt" (which is provided with the program) is + selected. The kernel weights are as follows: +

    +        0  -1  -1  -1   0
    +       -1  -1  -1  -1  -1
    +       -1  -1  24  -1  -1     x .04
    +       -1  -1  -1  -1  -1
    +        0  -1  -1  -1   0 
    +      
    + Thus, the highpass filter is simulated. The center pixel will be + multiplied by 24. Then this value will be added to the values of its + surrounding pixels (all of these values will either have a sign change + since they were multiplied by -1 in this filter or they will be 0, since + 0 and -1 are the only weight values that the filter holds, except for the + center pixel). Finally, after all of the addition has been done, the final + sum of all of the weights that were multiplied by either 24, or -1, or 0, + will be multiplied by .04, which equals 1/25. The reason all of the pixels + are multiplied by 1/25 is that there are 25 spots in the 5 by 5 kernel, + and thus the image will be normalized. +
    + + + from= peaks.cub to=highpass.cub kernel=highpassCircle5x5.txt + + + The kernfilter program has been loaded with a kernel that will + simulate a circular highpass filter with a 5 x 5 boxcar. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to simulate the highpass + filter with a 5 x 5 circular boxcar. + + + + + + + + + + Input image before kernfilter. + + + This is the unfiltered image. Note the low frequency data (albedo) + in the image. The highpass filter that this kernel mimics is + intended to filter this type of data out. + + + FROM + + + + + + + Output image after kernfilter + + + The filtered image. Just as an actual 5 x 5 circular highpass + filter would do, this kernel has removed albedo, allowing the user + to see more terrain. Since a 5x5 filter is considered relatively small, + features which are considered relatively small will still be visible. + + + TO + + + + + + + Using the smoothPyramid5x5.txt kernel + + + This example assumes that a kernel named "smoothPyramid5x5.txt" (which + is provided with the program) exists in the "kernels" file that is created + by default. The program simulates a smoothing algorithm that takes an + average of the DNs in the boxcar. The kernel weights pixels that are + nearest to the center higher than those at the edges of the boxcar. + The kernel weights are as follows +
     
    +          1  2  3  2 1 
    +          2  4  6  4  2
    +            3  6  9  6  3      x  1/81 
    +          2  4  6  4  2 
    +          1  2  3  2  1
    +        
    + The pixels in the boxcar are assigned weights that inversely reflect + their distance from the center of the boxcar. The pixel at the very + center will be multiplied by 9 and then added to all of the values that + were multiplied by the other weights in the boxcar. Note that all of the + weights add up to 81. This is why the final output is divided by 81; it + allows the center pixel to be an average of the weights. Thus, the blur + appears as though a smoothing algorithm applying weight in a pyramidal + fashion had been applied. +
    + + + from= peaks.cub to=smooth.cub + kernel=smoothPyramid5x5.txt + + + This example has loaded the smoothPyramid5x5.txt kernel, which will + smooth the input image using weights that are dispersed in a pyramidal + fashion. The boxcar is 5 x 5. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform the smoothing + filter with a 5 x 5 boxcar. + + + + + + + + + + Input image before kernfilter. + + + This is the image as it was taken originally with no smoothing. + + + FROM + + + + + + + Output image after kernfilter + + + The image after the filter. Although possibly hard to detect, everything + about the pictures is a little blurred, and smoother, than in the + original. A larger filter size would further increase this effect. + + + TO + + +
    + + + + Using the derivativeNWtoSE2x2.txt kernel + + + This example assumes that a kernel named "derivativeNWtoSE2x2.txt" + (which is provided with the program) exists in the "kernels" file that + is created by default. This program serves the purpose of bringing out + areas of high contrast. It does so by finding the difference of 2 pixels + on a diagonal from each other. The weights are as follows +
     
    +          1   0 
    +          0  -1  x 1.0
    +        
    + The top left pixel receives the value of itself minus the pixel down + right of itself. The other two pixesl do not matter. Anywhere where is + significant change from the top left to the bottom right then shows it + with brighter or darker pixels than the surrounding gray where there was + little difference and the DNs are at or close to zero. +
    + + + from=peaks.cub to=derivative.cub kernel=derivativeNWtoSE2x2.txt + + + The kernfilter program has been loaded with a kernel that will find + the difference between 2 diagonal pixels. + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform the + derivative from NW to SE with a 2x2 boxcar. + + + + + + + + + + Input image before kernfilter. + + + This is the image as it was taken originally. + + + FROM + + + + + + + Output image after kernfilter + + + The processed image now appears to have a light source in the + northwest and shadows and bright spots in areas of significant + contrast in the original. + + + TO + + +
    + +
    diff --git a/isis/src/base/apps/kernfilter/tsts/Makefile b/isis/src/base/apps/kernfilter/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/kernfilter/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/kernfilter/tsts/derivative/Makefile b/isis/src/base/apps/kernfilter/tsts/derivative/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0a248b5e07b2e6881b49bf7b27320302d59a17ce --- /dev/null +++ b/isis/src/base/apps/kernfilter/tsts/derivative/Makefile @@ -0,0 +1,8 @@ +APPNAME = kernfilter + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub to=$(OUTPUT)/truth.cub \ + kernel=$(INPUT)/derivativeNWtoSE2x2.txt> /dev/null; + diff --git a/isis/src/base/apps/kernfilter/tsts/emboss/Makefile b/isis/src/base/apps/kernfilter/tsts/emboss/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d424a780e076b273c7b2c3a5c7e4f6e0ef2263eb --- /dev/null +++ b/isis/src/base/apps/kernfilter/tsts/emboss/Makefile @@ -0,0 +1,8 @@ +APPNAME = kernfilter + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/kernfilterTruth1.cub \ + kernel=$(INPUT)/emboss3x3.txt > /dev/null; diff --git a/isis/src/base/apps/kernfilter/tsts/highpass/Makefile b/isis/src/base/apps/kernfilter/tsts/highpass/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5f144634e5a3ecf7977cd34ea327ac36dff9eeb8 --- /dev/null +++ b/isis/src/base/apps/kernfilter/tsts/highpass/Makefile @@ -0,0 +1,8 @@ +APPNAME = kernfilter + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/kernfilterTruth2.cub \ + kernel=$(INPUT)/highpassCircle5x5.txt > /dev/null; diff --git a/isis/src/base/apps/kuwahara/Makefile b/isis/src/base/apps/kuwahara/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/kuwahara/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/kuwahara/assets/images/kuwa.jpg b/isis/src/base/apps/kuwahara/assets/images/kuwa.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7c1da3e312ad03427d0f00dbfae438b6d1c93391 Binary files /dev/null and b/isis/src/base/apps/kuwahara/assets/images/kuwa.jpg differ diff --git a/isis/src/base/apps/kuwahara/assets/images/kuwaGUI.jpg b/isis/src/base/apps/kuwahara/assets/images/kuwaGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b2c88890d5d117cb1c4893a363d903e8077acb52 Binary files /dev/null and b/isis/src/base/apps/kuwahara/assets/images/kuwaGUI.jpg differ diff --git a/isis/src/base/apps/kuwahara/assets/images/kuwaharaDiagram.gif b/isis/src/base/apps/kuwahara/assets/images/kuwaharaDiagram.gif new file mode 100644 index 0000000000000000000000000000000000000000..4d519ca5a72733289f5d9ec3163913cea9533a41 Binary files /dev/null and b/isis/src/base/apps/kuwahara/assets/images/kuwaharaDiagram.gif differ diff --git a/isis/src/base/apps/kuwahara/assets/images/peaks.jpg b/isis/src/base/apps/kuwahara/assets/images/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..29b1866cf57e5e81f5e4f16f00f86b90f1fe1c96 Binary files /dev/null and b/isis/src/base/apps/kuwahara/assets/images/peaks.jpg differ diff --git a/isis/src/base/apps/kuwahara/assets/thumbs/kuwa.jpg b/isis/src/base/apps/kuwahara/assets/thumbs/kuwa.jpg new file mode 100644 index 0000000000000000000000000000000000000000..720a51f6c8431969c4a8796cd289b82833d38330 Binary files /dev/null and b/isis/src/base/apps/kuwahara/assets/thumbs/kuwa.jpg differ diff --git a/isis/src/base/apps/kuwahara/assets/thumbs/kuwaGUI.jpg b/isis/src/base/apps/kuwahara/assets/thumbs/kuwaGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5e168e1fe75538919244851e5592db630845ec3d Binary files /dev/null and b/isis/src/base/apps/kuwahara/assets/thumbs/kuwaGUI.jpg differ diff --git a/isis/src/base/apps/kuwahara/assets/thumbs/peaks.jpg b/isis/src/base/apps/kuwahara/assets/thumbs/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1f47412ad2bf401fb8944ebf3e1822f2a05534ca Binary files /dev/null and b/isis/src/base/apps/kuwahara/assets/thumbs/peaks.jpg differ diff --git a/isis/src/base/apps/kuwahara/kuwahara.cpp b/isis/src/base/apps/kuwahara/kuwahara.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fbb129df99703568f7733e512c91152d00f54485 --- /dev/null +++ b/isis/src/base/apps/kuwahara/kuwahara.cpp @@ -0,0 +1,81 @@ +#include "Isis.h" +#include "ProcessByBoxcar.h" +#include "Statistics.h" + +using namespace std; +using namespace Isis; + +void kuwahara (Buffer &in, double &v); + +// Filter size +int g_samples; +int g_lines; + +void IsisMain () { + + // Get parameters from user + ProcessByBoxcar p; + p.SetInputCube ("FROM"); + p.SetOutputCube ("TO"); + + // Get user input boxcar size + UserInterface &ui = Application::GetUserInterface(); + g_samples = ui.GetInteger("SAMPLES"); + g_lines = ui.GetInteger("LINES"); + p.SetBoxcarSize(g_samples, g_lines); + + // Start processing + p.StartProcess(kuwahara); + p.EndProcess(); +} + +void kuwahara (Buffer &in, double &result) { + + // Find subunit size + int subSamp = 1 + (int) (g_samples / 2); + int subLine = 1 + (int) (g_lines / 2); + const int numStats = 4; + Statistics stats[ numStats ]; + + // Load up statistics from each subunit grouping + int indexTop = 0; // indexTop leads the upper two quadrants + int indexBottom = (g_samples * (subLine - 1)); // indexBottom leads the bottom two quadrants + for (int i = 0 ; i < subLine ; i ++ ) { + stats[0].AddData(&in[ indexTop ], subSamp); // Upper left + stats[1].AddData(&in[ (indexTop + (subSamp - 1)) ], subSamp); // Upper right + stats[2].AddData(&in[ indexBottom ], subSamp); // Lower left + stats[3].AddData(&in[ (indexBottom + (subSamp - 1)) ], subSamp); // Lower right + indexTop += g_samples; + indexBottom += g_samples; + } + + // Set first information to results by defualt + double minimum = stats[0].Variance(); + result = stats[0].Average(); + + // Find subgroup with smallest variance, set its mean to result + for (int i = 1; i < numStats; i ++) { + if (IsSpecial(minimum)) { + minimum = stats[i].Variance(); + result = stats[i].Average(); + } + else { + if (IsValidPixel(stats[i].Variance())) { + + // Problems caused in this if between computers because of rounding errors. + // Cases where there are two equal variances will cause this and can be fixed + // by checking equality of the doubles with a powerful methods along with && < + if (stats[i].Variance() < minimum) { + minimum = stats[i].Variance(); + result = stats[i].Average(); + } + } + } + } + + // If the program is through without a valid output, its probabaly null, + // make sure its null + if (IsSpecial(minimum)) { + result = Isis::Null; + } +} diff --git a/isis/src/base/apps/kuwahara/kuwahara.xml b/isis/src/base/apps/kuwahara/kuwahara.xml new file mode 100644 index 0000000000000000000000000000000000000000..749e4a30e55af0b856a30660358682aa0eb344a4 --- /dev/null +++ b/isis/src/base/apps/kuwahara/kuwahara.xml @@ -0,0 +1,172 @@ + + + + + Filter a cube, smoothing but preserving edges + + + Kuwahara is a edge preserving smoothing filter. This is accomplished through + examining the four quadrants surrounding a pixel, selecting the one with the + smallest variance, and using its average as the resultant pixel value. In + the case where two or more variances are equivalent, the average from the + first quadrant encountered with an equivalent variance will be used. + + + + Original version + + + Added examples, test + + + Fixed images in documentation + + + Made ostruthdata for samson only to handle problem with rounding errors + + + + + Filters + + + + + + cube + input + + Input cube to be smoothed + + + Use this parameter to select the input cube. All bands within the file + will be filtered. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the filter. + + + *.cub + + + + + + + integer + 5 + + The number of samples, width, of the boxcar + + + This parameter sets the width, or number of samples, to have the + filter process. This must be an odd number. The larger this is the + larger the details that will be smoothed. A wide and short filter will + do mostly horizantal smoothing, a tall and narrow filter mostly + vertical. + + + 1 + + + + integer + 5 + + The size of the filter boxcar + + + This parameter sets the number of lines to be processed by the filter. + This must be an odd number. Larger sizes will smooth larger features. + A wide and short filter will do mostly horizantal smoothing, a tall + and narrow filter mostly vertical. + + + 1 + + + + + + + + Example of usage of the kuwahara filter to smooth and perserve edges. + + + Kuwahara filter is put to use here, smoothing while preserving edges. Here + is a image which shows the exact quadrants used in a 5x5. Each quadrant is + then a 3x3 with some overlap on the next. +
    +          
    +        
    +
    + + + from=peaks.cub to=smooth.cub samples=5 lines=5 + + + This example will filter the image using a 5x5 boxcar with subunit + size of 3x3. The size in this case is unnecessray since 5 is default, + but for other sizes a different, odd numbed, could be placed there. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform the kuwahara + filter with a 5x5 boxcar on the image peaks.cub. + + + + + + + + + + Input image before kuwahara filter + + + This is the image as it was taken originally. + + + FROM + + + + + + + Output image after being smoother by kuwahara filter. + + + As you can observe, the image has been smoothed, but still retains + the edges present in the original image. + + + TO + + + +
    +
    +
    diff --git a/isis/src/base/apps/kuwahara/tsts/Makefile b/isis/src/base/apps/kuwahara/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/kuwahara/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/kuwahara/tsts/default/Makefile b/isis/src/base/apps/kuwahara/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..06b4524ae510c7ebce4aaa049e5c2c9733f5dd49 --- /dev/null +++ b/isis/src/base/apps/kuwahara/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME = kuwahara + +include $(ISISROOT)/make/isismake.tsts + +#Separate ostruthdata for samson needed due to rounding errors +#The rounding errors are in variances which are equal, which can +#then lead to significantly different DNs. Read code for further detail + +commands: + $(APPNAME) from=$(INPUT)/peaks.cub \ + to=$(OUTPUT)/filtered.cub > /dev/null; diff --git a/isis/src/base/apps/lineeq/Makefile b/isis/src/base/apps/lineeq/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/lineeq/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/lineeq/assets/images/ex1input1.jpg b/isis/src/base/apps/lineeq/assets/images/ex1input1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..272fc90df186471748cf93373a44b3e0f8c7bfc6 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex1input1.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex1input2.jpg b/isis/src/base/apps/lineeq/assets/images/ex1input2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e971a968f69a29b269f3704fb799b4f60269d15b Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex1input2.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex1input3.jpg b/isis/src/base/apps/lineeq/assets/images/ex1input3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..93714318c9f1bcdf4cd68c0f6fca321d28c88ff3 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex1input3.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex1interface.jpg b/isis/src/base/apps/lineeq/assets/images/ex1interface.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e1653f1483d6d107198f62f0fdbae3415f26a7b5 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex1interface.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex1output.jpg b/isis/src/base/apps/lineeq/assets/images/ex1output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e82757b0be8996ada421aaef01e4436ab36154b6 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex1output.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex2input1.jpg b/isis/src/base/apps/lineeq/assets/images/ex2input1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e697ba9046c3699ba6ef55298bffd53f3626fb64 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex2input1.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex2input2.jpg b/isis/src/base/apps/lineeq/assets/images/ex2input2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..440182bdd37b50685507c223dbe09321105b40bf Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex2input2.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex2input3.jpg b/isis/src/base/apps/lineeq/assets/images/ex2input3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..91b18c0b2e74b52da25b40170c71053140107901 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex2input3.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex2interface.jpg b/isis/src/base/apps/lineeq/assets/images/ex2interface.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1e5588cdbd9009a26ef8e105f5ba52b25d8f873f Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex2interface.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex2output.jpg b/isis/src/base/apps/lineeq/assets/images/ex2output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1b391d5b2367e7fd4cb2f67edc53d2c2f7b39308 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex2output.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex3input.jpg b/isis/src/base/apps/lineeq/assets/images/ex3input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9830b16ddcde4156ccff6cefa8bbe7bf07c5ac72 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex3input.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex3interface1.jpg b/isis/src/base/apps/lineeq/assets/images/ex3interface1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0ce71344a5db0bf0958400b185afdb3d52e047d0 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex3interface1.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex3interface2.jpg b/isis/src/base/apps/lineeq/assets/images/ex3interface2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..90361751c968ea0d996976087fe473c420957e4c Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex3interface2.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex3interface3.jpg b/isis/src/base/apps/lineeq/assets/images/ex3interface3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8b8f5eb8f57c6e6c21b7b60f3ba5e84d542ead5f Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex3interface3.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex3output1.jpg b/isis/src/base/apps/lineeq/assets/images/ex3output1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..302f440b417d6415a86d0955aa5fc53525a51532 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex3output1.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex3output2.jpg b/isis/src/base/apps/lineeq/assets/images/ex3output2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..66469872a30458d0c35d128f246b8fc491684e9a Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex3output2.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/images/ex3output3.jpg b/isis/src/base/apps/lineeq/assets/images/ex3output3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8f37d1d8b97433a3dd1edfc46d2cbc4d2eed5774 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/images/ex3output3.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex1input1.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex1input1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a392c9965dbac7c5896d84c4e8a5e4847e663a4e Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex1input1.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex1input2.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex1input2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c7dea722e9dd19f8c623a7b7b87ae88266ea896c Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex1input2.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex1input3.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex1input3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..799f764dda0396c87b70aee684a94687e820fac0 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex1input3.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex1interface.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex1interface.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6ba3fc08b0d27b05ed66ac3dd4e856f78013ac8b Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex1interface.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex1output.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex1output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0a773319fc85da7f78bc3f23a83c1d1b5d0e0c89 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex1output.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex2input1.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex2input1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3b4e436cbeabc34fbf5e03f792d210309ef48147 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex2input1.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex2input2.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex2input2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..176e081dca9ed14ecacb9e5d842a615fc8e6bf40 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex2input2.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex2input3.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex2input3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c52bba715b473dbcf674452b9b59a136170928c0 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex2input3.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex2interface.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex2interface.jpg new file mode 100644 index 0000000000000000000000000000000000000000..32990affdc357767fe2e25d6d954c43a858089fa Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex2interface.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex2output.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex2output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..962c6d051df232eb55c6db3435108414ae89fa20 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex2output.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex3input.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex3input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4b771ac28093a39d6f1f7dfb1f11989b0d640d69 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex3input.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex3interface1.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex3interface1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..148a25e49c7f696774604d6e738a8ec2025c2713 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex3interface1.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex3interface2.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex3interface2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..44e74a325ae059e72e79bef7395074ff4e56f40e Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex3interface2.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex3interface3.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex3interface3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5f717497c55ea0cfda688803d4b3a6dcd6d9c4d2 Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex3interface3.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex3output1.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex3output1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0fbbaf01604605e8983cd06fd3fad46fe81e3d5f Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex3output1.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex3output2.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex3output2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d1e5f3cc20ed1fbee9f5f0f97c553a6a0c9f07db Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex3output2.jpg differ diff --git a/isis/src/base/apps/lineeq/assets/thumbs/ex3output3.jpg b/isis/src/base/apps/lineeq/assets/thumbs/ex3output3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..040e840747245f704a078491e5a4666f67f78f2d Binary files /dev/null and b/isis/src/base/apps/lineeq/assets/thumbs/ex3output3.jpg differ diff --git a/isis/src/base/apps/lineeq/lineeq.cpp b/isis/src/base/apps/lineeq/lineeq.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22f8a6211910a53fbd70ec4b84651db030e711a2 --- /dev/null +++ b/isis/src/base/apps/lineeq/lineeq.cpp @@ -0,0 +1,136 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "QuickFilter.h" +#include "TextFile.h" +#include "Statistics.h" + +using namespace Isis; + +void apply(Buffer &in, Buffer &out); +void gatherAverages(Buffer &in); + +std::vector cubeAverage; +std::vector< double * > lineAverages; +int numIgnoredLines; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + ProcessByLine p; + Cube *icube = p.SetInputCube("FROM"); + numIgnoredLines = 0; + + cubeAverage.resize(icube->Bands()); + lineAverages.resize(icube->Bands()); + + for(int i = 0; i < icube->Bands(); i++) { + cubeAverage[i] = 0; + lineAverages[i] = NULL; + } + + int boxcarSize; + + if(ui.GetString("BOXTYPE").compare("NONE") == 0) { + boxcarSize = (int)(icube->Lines() * 0.10); + } + else if(ui.GetString("BOXTYPE").compare("ABSOLUTE") == 0) { + boxcarSize = ui.GetInteger("BOXSIZE"); + } + else if(ui.GetString("BOXTYPE").compare("PERCENTAGE") == 0) { + boxcarSize = (int)(((double)ui.GetInteger("BOXSIZE") / 100.0) * icube->Lines()); + } + + // Boxcar must be odd size + if(boxcarSize % 2 != 1) { + boxcarSize ++; + } + + PvlGroup data("lineeq"); + data += PvlKeyword("BoxcarSize", boxcarSize, "lines"); + data += PvlKeyword("OutputCsv", ui.GetBoolean("AVERAGES")); + + TextFile *csvOutput = NULL; + if(ui.GetBoolean("AVERAGES")) { + csvOutput = new TextFile(ui.GetFilename("CSV"), "overwrite", ""); + csvOutput->PutLine("Average,SmoothedAvg"); + data += PvlKeyword("CsvFile", ui.GetFilename("CSV")); + } + + Application::Log(data); + + for(int band = 0; band < icube->Bands(); band ++) { + lineAverages[band] = new double[icube->Lines()]; + } + + p.Progress()->SetText("Gathering line averages"); + p.StartProcess(gatherAverages); + + // Now filter the bands + p.Progress()->SetText("Smoothing line averages"); + p.Progress()->SetMaximumSteps((icube->Bands() + 1) * icube->Lines()); + p.Progress()->CheckStatus(); + QuickFilter filter(icube->Lines(), boxcarSize, 1); + + if(icube->Lines() <= numIgnoredLines) { + throw iException::Message(iException::User, "Image does not contain any valid data.", _FILEINFO_); + } + + for(int band = 0; band < icube->Bands(); band ++) { + cubeAverage[band] /= (icube->Lines() - numIgnoredLines); + filter.AddLine(lineAverages[band]); + + for(int line = 0; line < icube->Lines(); line ++) { + p.Progress()->CheckStatus(); + + double filteredLine = filter.Average(line); + + if(csvOutput != NULL) { + csvOutput->PutLine((iString)lineAverages[band][line] + (iString)"," + (iString)filteredLine); + } + + lineAverages[band][line] = filteredLine; + } + + filter.RemoveLine(lineAverages[band]); + } + + if(csvOutput != NULL) { + delete csvOutput; // This closes the file automatically + csvOutput = NULL; + } + + p.SetOutputCube("TO"); + p.Progress()->SetText("Applying Equalization"); + p.StartProcess(apply); + + for(int band = 0; band < icube->Bands(); band ++) { + delete [] lineAverages[band]; + lineAverages[band] = NULL; + } + + p.EndProcess(); +} + +void gatherAverages(Buffer &in) { + Statistics lineStats; + lineStats.AddData(in.DoubleBuffer(), in.size()); + + double average = lineStats.Average(); + + lineAverages[in.Band() - 1][in.Line() - 1] = average; + + // The cube average will finish being calculated before the correction is applied. + if(!IsSpecial(average)) { + cubeAverage[in.Band() - 1] += average; + } + else { + numIgnoredLines ++; + } +} + +void apply(Buffer &in, Buffer &out) { + for(int sample = 0; sample < in.size(); sample ++) { + out[sample] = in[sample] * cubeAverage[in.Band() - 1] / lineAverages[in.Band() - 1][in.Line() - 1]; + } +} + + diff --git a/isis/src/base/apps/lineeq/lineeq.xml b/isis/src/base/apps/lineeq/lineeq.xml new file mode 100644 index 0000000000000000000000000000000000000000..eb576abefb53c65b708370d6316301d7ac050eb9 --- /dev/null +++ b/isis/src/base/apps/lineeq/lineeq.xml @@ -0,0 +1,353 @@ + + + + + This program will normalize a cube based on line averages. + + + + This program will normalize a cube based on line averages.

    + + This is useful for linescan camera images where the signal drifts over time. It can also + be used for correcting for photometric changes when part of the image was taken during the day and + the other part was taken at night.

    + + The boxcar size should be somewhere between 0% and 200%, where 200% will give you the same image back + and 0% will remove all albedo and clean up all noise. The reason for the boxcar size being 200% is because the boxcar + folds at the border, meaning at line zero it's only incorporating 50% of the lines and at the center it's incorporating all of them. The + 200% boxcar makes every pixel incorporates a boxcar of all of the data, causing only negligable change in the equation.

    + + The normalization is achieved by collecting all of the line averages for any given band. A lowpass filter + is then run on these averages. Finally, the lines are normalized with their smoothed average. The + CSV output option will output a CSV file (readable by most spreadsheet programs such as Excel) + with the line averages before and after smoothing. Using this data, graphing the line averages will + reveal and identify problem data. +
    + + + Radiometric and Photometric Correction + + + + + Original version + + + Added options and expanded examples + + + Fixed bug where batchlists failed after a few runs + + + Fixed problem with gaps in the images causing the program to fail + + + Removed references to CubeInfo + + + + + + + + cube + input + + Cube to normalize + + + Specify the cube to be normalized. + + + + + cube + output + + Normalized cube + + + Specify the output (normalized) cube. + + + + + filename + output + No Output + + CSV formatted file of line averages output + + + Specify the CSV file to output the line averages to. + + *.csv + + + + + + + string + NONE + + Boxcar height specified in pixels of percentage + + + When overriding the default boxcar size, you can enter the new value as a percentage of the image height + or as an absolute size. + + + + + + + + + + + + integer + + Boxcar size for smoothing + + + This will override the default boxcar size when smoothing the line averages. The larger this size is, the less the image is affected. + The smaller the boxcar, the larger the effect. If entering an absolute line size, it must be odd (any even number will automatically be + rounded up). + + + + + boolean + false + + Output a CSV formatted file of the line averages + + + Output a CSV formatted file of the line averages and the smoothed averages. + + CSV + + + + + + + + + Normalizing a cube + + This shows how to normalize a cube using this program. The input is valid data with introduced noise. + + + from=input.cub to=output.cub boxtype=absolute boxsize=1 + This is the command line to run this program, with a small boxcar, on input.cub. + + + + + Running this program on input.cub + + This screen shot shows how to run this program using a small boxcar on + input.cub. + + + TO + + + + + + Noise + + This shows the noise that was introduced into the input image. It's values change line by line. This was introduced to input.cub by using fx and adding to the valid data. + + + FROM + + + Original Data + + This is the original image, before anything was done to it. + + + FROM + + + Input Data + + This is the original image with the noise added in. + + + FROM + + + + + Output Image + + This shows the image after this program was run. Notice the image data is restored, but all albedo was lost. + + + TO + + + + + + Identifying a problem cube + + This program does not properly handle all cubes. When the line averages spike, this program smoothes them, + but bad data could cause these spikes and this program will try to correct bad data incorrectly inthe areas with the spikes. + + + from=I07762023RDR_CN.cub to=I07762023RDR_CN.norm.cub csv=I07762023RDR_CN.norm.csv boxtype=percentage boxsize=2 averages=yes + This is the command line to run this program, with a small boxcar, on I07762023RDR_CN.norm.cub and output a CSV file. + + + + + Running this program on I07762023RDR_CN.cub with CSV output + + This screen shot shows how to run this program on + I07762023RDR_CN.cub and output the line averages as CSV. + + + TO + + + + + + CSV Graph + + This shows the graph of the averages from the CSV file. Notice there is a large spike on the far left hand side of the data. This should be investigated further. + + + CSV + + + CSV Graph (a closer look) + + This shows the graph of the averages from the CSV file zoomed into the left side. Notice the smoothed average (pink) is significantly off from the averages (blue). + This tells us that the data in this region did not normalize properly. + + + CSV + + + The cube + + This shows the first 1000 lines of the image before this program was run. Notice the bright area in this data corrosponds to the spike on the CSV graph. + + + FROM + + + + + Output Image + + This shows the first 1000 lines of the image after this program was run. Notice the resulting effects of this incorrect normalization. A smaller boxcar would + balance this area, except for the lines with the bad data, but would also destroy any valid albedo. + + + TO + + + + + + Deciding on a boxcar size + + This shows how the boxcar size affects the output of this program. + + + from=input.cub to=output.cub boxtype=percentage boxsize=?? + This is the command line to run this program in this example, where ?? becomes a relative boxcar size. + + + + + Running this program on input.cub with a 5% boxcar size + + This screen shot shows how to run this program using a 5% boxcar on input.cub. + + + BOXSIZE + + + + + Running this program on input.cub with a 20% boxcar size + + This screen shot shows how to run this program using a 20% boxcar on input.cub. + + + BOXSIZE + + + + + Running this program on input.cub with a 50% boxcar size + + This screen shot shows how to run this program using a 50% boxcar on input.cub. + + + BOXSIZE + + + + + + Input Data + + This is the original image. Notice it's very bright at the top and very dark at the bottom. + + + FROM + + + + + Output Image + + This shows the image after this program was run with a very small boxcar. Notice the loss of albedo. + + + TO + + + Output Image + + This shows the image after this program was run with a small boxcar. Notice less of the data was properly normalized and there's more albedo. + + + TO + + + Output Image + + This shows the image after this program was run with a larger boxcar. The albedo change from the last example to this one is minimal, but much more data was lost. + + + TO + + + + + +
    diff --git a/isis/src/base/apps/lineeq/tsts/Makefile b/isis/src/base/apps/lineeq/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/lineeq/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/lineeq/tsts/boxcar/Makefile b/isis/src/base/apps/lineeq/tsts/boxcar/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..37ae6cf8fcb4c154a062c551feed1950b759ed7c --- /dev/null +++ b/isis/src/base/apps/lineeq/tsts/boxcar/Makefile @@ -0,0 +1,8 @@ +APPNAME = lineeq + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/peaks.cub \ + TO=$(OUTPUT)/truth.cub AVERAGES=yes CSV=$(OUTPUT)/truth.txt \ + boxsize=29 boxtype=percent > /dev/null; diff --git a/isis/src/base/apps/lineeq/tsts/default/Makefile b/isis/src/base/apps/lineeq/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..094b36dc5fda41c6f02d3d9ee137a918c7515c8a --- /dev/null +++ b/isis/src/base/apps/lineeq/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = lineeq + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/I08124021RDR_CN.cub \ + TO=$(OUTPUT)/truth.cub AVERAGES=yes CSV=$(OUTPUT)/truth.txt \ + > /dev/null; diff --git a/isis/src/base/apps/lowpass/Makefile b/isis/src/base/apps/lowpass/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/lowpass/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/lowpass/assets/images/3x3gui.jpg b/isis/src/base/apps/lowpass/assets/images/3x3gui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..351ca5d74c05db5c6e4d390dc8ac19dd1a34a52f Binary files /dev/null and b/isis/src/base/apps/lowpass/assets/images/3x3gui.jpg differ diff --git a/isis/src/base/apps/lowpass/assets/images/3x3lowpass.jpg b/isis/src/base/apps/lowpass/assets/images/3x3lowpass.jpg new file mode 100755 index 0000000000000000000000000000000000000000..7a7e38a18c8d8a7facd11f4c4abffe1cf711b33f Binary files /dev/null and b/isis/src/base/apps/lowpass/assets/images/3x3lowpass.jpg differ diff --git a/isis/src/base/apps/lowpass/assets/images/bigLowpass.jpg b/isis/src/base/apps/lowpass/assets/images/bigLowpass.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8f7880580b52f6c23207deb7dad6ca43054ede76 Binary files /dev/null and b/isis/src/base/apps/lowpass/assets/images/bigLowpass.jpg differ diff --git a/isis/src/base/apps/lowpass/assets/images/bigLowpassGui.jpg b/isis/src/base/apps/lowpass/assets/images/bigLowpassGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..1cc78b5d0fe9ff1981b669bc5ab856d4cf63970b Binary files /dev/null and b/isis/src/base/apps/lowpass/assets/images/bigLowpassGui.jpg differ diff --git a/isis/src/base/apps/lowpass/assets/images/peaks.jpg b/isis/src/base/apps/lowpass/assets/images/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..b4eb82b1a0db7623e1601de6e7332b4c1e276a21 Binary files /dev/null and b/isis/src/base/apps/lowpass/assets/images/peaks.jpg differ diff --git a/isis/src/base/apps/lowpass/assets/thumbs/3x3gui.jpg b/isis/src/base/apps/lowpass/assets/thumbs/3x3gui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..6d0138805e08a9606aa5ef0dd8a6a9729381fc49 Binary files /dev/null and b/isis/src/base/apps/lowpass/assets/thumbs/3x3gui.jpg differ diff --git a/isis/src/base/apps/lowpass/assets/thumbs/3x3lowpass.jpg b/isis/src/base/apps/lowpass/assets/thumbs/3x3lowpass.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8b3dda53990753fde0709fa1a56cc833b66eed41 Binary files /dev/null and b/isis/src/base/apps/lowpass/assets/thumbs/3x3lowpass.jpg differ diff --git a/isis/src/base/apps/lowpass/assets/thumbs/bigLowpass.jpg b/isis/src/base/apps/lowpass/assets/thumbs/bigLowpass.jpg new file mode 100755 index 0000000000000000000000000000000000000000..5a1a613a00d9bb99744fda8e167df28fab07cd54 Binary files /dev/null and b/isis/src/base/apps/lowpass/assets/thumbs/bigLowpass.jpg differ diff --git a/isis/src/base/apps/lowpass/assets/thumbs/bigLowpassGui.jpg b/isis/src/base/apps/lowpass/assets/thumbs/bigLowpassGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8d7a203a3b57076db55f653e34b95abf010ae867 Binary files /dev/null and b/isis/src/base/apps/lowpass/assets/thumbs/bigLowpassGui.jpg differ diff --git a/isis/src/base/apps/lowpass/assets/thumbs/peaks.jpg b/isis/src/base/apps/lowpass/assets/thumbs/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..292bd8e82e2690a41f4032744f0c18796e5bb639 Binary files /dev/null and b/isis/src/base/apps/lowpass/assets/thumbs/peaks.jpg differ diff --git a/isis/src/base/apps/lowpass/lowpass.cpp b/isis/src/base/apps/lowpass/lowpass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9fc187605ff733c4c7e23cc1d579d7f36994e730 --- /dev/null +++ b/isis/src/base/apps/lowpass/lowpass.cpp @@ -0,0 +1,288 @@ +#include "Isis.h" +#include "ProcessByQuickFilter.h" +#include "UserInterface.h" + +using namespace std; +using namespace Isis; + +// Which pixel types to filter +bool filterNull; +bool filterLis; +bool filterLrs; +bool filterHis; +bool filterHrs; +bool propagate; + +// Prototype +void FilterAll (Buffer &in, Buffer &out, QuickFilter &filter); +void FilterValid (Buffer &in, Buffer &out, QuickFilter &filter); +void FilterInvalid (Buffer &in, Buffer &out, QuickFilter &filter); + +void IsisMain() { + //Set up ProcessByQuickFilter + ProcessByQuickFilter p; + + // Obtain input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + + // Find out which special pixels are to be filtered + UserInterface &ui = Application::GetUserInterface(); + filterNull = ui.GetBoolean ("NULL"); + filterLis = ui.GetBoolean ("LIS"); + filterLrs = ui.GetBoolean ("LRS"); + filterHis = ui.GetBoolean ("HIS"); + filterHrs = ui.GetBoolean ("HRS"); + propagate = (ui.GetString("REPLACEMENT") == "CENTER"); + + //Set the Boxcar Parameters + int lines = ui.GetInteger("LINES"); + int samples = ui.GetInteger("SAMPLES"); + double low = -DBL_MAX; + double high = DBL_MAX; + int minimum; + if (ui.WasEntered("LOW")) { + low = ui.GetDouble("LOW"); + } + if (ui.WasEntered("HIGH")) { + high = ui.GetDouble("HIGH"); + } + if (ui.GetString("MINOPT") == "PERCENTAGE") { + int size = lines * samples; + double perc = ui.GetDouble("MINIMUM") / 100; + minimum = (int) (size * perc); + } + else { + minimum = (int)ui.GetDouble("MINIMUM"); + } + + p.SetFilterParameters(samples, lines, low, high, minimum); + + //Start the appropriate filter method + if (ui.GetString("FILTER") == "ALL"){ + p.StartProcess(FilterAll); + p.EndProcess(); + } + else if(ui.GetString("FILTER") == "INSIDE") { + p.StartProcess(FilterValid); + p.EndProcess(); + } + else if (ui.GetString("FILTER") == "OUTSIDE") { + p.StartProcess(FilterInvalid); + p.EndProcess(); + } +} + +//Function to loop through the line, and determine the +//average value of the pixels around each valid pixel, writing that +//average to the output at the pixel index +void FilterValid (Buffer &in, Buffer &out, QuickFilter &filter) { + + //Loop through each pixel in the line + for (int i=0; i=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + if (in.Line()==57 && i==60) { + cout<< "Count: " << filter.Count(i) << "Average:" <=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else if ((IsLrsPixel(in[i])) && (filterLrs)) { + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else if ((IsHisPixel(in[i])) && (filterHis)) { + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else if ((IsHrsPixel(in[i])) && (filterHrs)) { + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else { + out[i] = in[i]; + } + } + //If the pixel is Non-Special, run the filter, unless the + //center is not valid, as determined by Low and High + else{ + if (in[i]filter.High()){ + out[i] = in[i]; + } + else{ + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + } + } +} + +//Function to loop through each pixel in a line and find the average +//of the surrounding pixels, and write it to the output, if the +//center pixel does not meet the requirements for validity +void FilterInvalid (Buffer &in, Buffer &out, QuickFilter &filter) { + for (int i=0; i=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else if ((IsLisPixel(in[i])) && (filterLis)) { + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else if ((IsLrsPixel(in[i])) && (filterLrs)) { + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else if ((IsHisPixel(in[i])) && (filterHis)) { + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else if ((IsHrsPixel(in[i])) && (filterHrs)) { + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else { + out[i] = in[i]; + } + } + //If the pixel is not Special, check if it is outside the + //valid range, as determined by Low and High, if so, run the + //average filter + else { + if (in[i]>=filter.Low() && in[i]<=filter.High()){ + out[i] = in[i]; + } + else{ + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + } + } +} + +//Function to run the Average filter on all pixels, regardless +//of their value +void FilterAll (Buffer &in, Buffer &out, QuickFilter &filter) { + for (int i=0; i=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else if ((IsLisPixel(in[i])) && (filterLis)) { + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else if ((IsLrsPixel(in[i])) && (filterLrs)) { + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else if ((IsHisPixel(in[i])) && (filterHis)) { + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else if ((IsHrsPixel(in[i])) && (filterHrs)) { + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + else { + out[i] = in[i]; + } + } + //If the Pixel is non-Special, run the average filter, unless there + //aren't enough valid pixels for filtering and the center pixel value + // is to be propagated + else { + if (filter.Count(i)>=filter.MinimumPixels() || !propagate){ + out[i] = filter.Average(i); + } + else { + out[i] = in[i]; + } + } + } +} + diff --git a/isis/src/base/apps/lowpass/lowpass.xml b/isis/src/base/apps/lowpass/lowpass.xml new file mode 100644 index 0000000000000000000000000000000000000000..9b6feaf484346b4f132b92f4db2843455e2b02f3 --- /dev/null +++ b/isis/src/base/apps/lowpass/lowpass.xml @@ -0,0 +1,541 @@ + + + + + + Apply lowpass or blurring filter to a cube + + + + This program applies a lowpass or blurring filter to a cube. An NxM boxcar is + moved through the cube and average of the boxcar at each position is computed. + This average, which effectively blurs the data, is written to the + output cube. The user has the ability to choose which input pixels are filtered + including 1) all pixels, 2) pixels within a user specified range, 3) pixels + outside a user specified range, and 4) special pixels. In general, the larger + the boxcar the more the output cube is blurred. For example, a 101x101 boxcar + will cause more blurring than a 3x3 boxcar. + + + + Filters + + + + + highpass + trimfilter + sdfilter + varfilter + + + + + boxfilter + + + + + Original version + + + Ported to Isis 3.0 + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Added examples + + + Modified user interface + + + Fixed appTest parameters and documentation + + + Added Minopt parameter, modified user interface + + + Reorganized user interface + + + + + + + cube + input + + Input file + + + Input cube to filter + + + *.cub + + + + cube + output + + Output lowpass cube + + + The resultant filtered cube + + + + + + + integer + + Number of samples in boxcar + + + + This is the total number of samples in the boxcar. It must be odd and + can not exceed twice the number of samples in the cube. In general, the + size of the boxcar does not cause the program to operate significantly + slower. + + + + + 1 + + + + integer + + Number of lines in boxcar + + + + This is the total number of lines in the boxcar. It must be odd and + can not exceed twice the number of lines in the cube. In general, the + size of the boxcar does not cause the program to operate significantly + slower. + + + + + 1 + + + + + + double + + Minimum valid DN + + + Valid minimum pixel value that will be used in boxcar computation. If + a pixel value is less than LOW then it will not be used when computing + the average. + + + Use all pixels + + + HIGH + + + + + double + + Maximum valid DN + + + Valid maximum pixel value that will be used in boxcar computation. If + a pixel value is greater than HIGH then it will not be used when + computing the average. + + + Use all pixels + + + LOW + + + + + string + + COUNT + + + Sets minimum to be either a count or a percentage + + + This parameter determines whether the minimum + parameter is to be interpreted as a count of pixels, or a + percentage of all pixels in the boxcar. + + + + + + + + + + double + 1 + + Minimum boxcar pixels required for filter + + + This option is the minimum number of valid pixels + required in a boxcar for filtering to begin. + + + + + string + + CENTER + + + Replacement if minimum not met + + + This determines what to put in the center pixel, + in the event that there aren't enough valid, non-special + pixels in the boxcar to meet the minimum. The + default is to replace it with the current value, + and the other option is to replace it with NULL. + + + + + + + + + + + + + string + ALL + + Which pixels to filter + + + These options choose which pixels to filter. The options are ALL, + VALID and INVALID. If the first is chosen, the filter will be run on + all pixels inside the LOW-HIGH range, and all Specials declared valid. + If the second option is chosen, the filter is only run when the center + pixel is valid, and the third option only runs the filter when the + center is invalid. Regardless of which option is chosen, the average is only + calculated from values between LOW and HIGH. + + + + + + + + + + + + + + + + + boolean + TRUE + + Filter NULL Pixels + + + If the center pixel of a boxcar is NULL, and this box is checked, + the pixel will be overwritten with the average value of the boxcar + as a whole. If this box is not checked, the pixel will be left alone. + + + + + boolean + TRUE + + Filter HRS Pixels + + + If the center pixel of a boxcar is HRS, and this box is checked, + the pixel will be overwritten with the average value of the boxcar + as a whole. If this box is not checked, the pixel will be treated according + to the REPLACEMENT parameter. + + + + + boolean + TRUE + + Filter HIS Pixels + + + If the center pixel of a boxcar is HIS, and this box is checked, + the pixel will be overwritten with the average value of the boxcar + as a whole. If this box is not checked, the pixel will be treated according + to the REPLACEMENT parameter. + + + + + boolean + TRUE + + Filter LRS Pixels + + + If the center pixel of a boxcar is LRS, and this box is checked, + the pixel will be overwritten with the average value of the boxcar + as a whole. If this box is not checked, the pixel will be treated according + to the REPLACEMENT parameter. + + + + + boolean + TRUE + + Filter LIS Pixels + + + If the center pixel of a boxcar is LIS, and this box is checked, + the pixel will be overwritten with the average value of the boxcar + as a whole. If this box is not checked, the pixel will treated according + to the REPLACEMENT parameter. + + + + + + + + + Running a 3x3 boxcar on all pixels + + + The lowpass filter + + + + from= peaks.cub + to=3x3lowpass.cub + samples=3 + lines=3 + + + This configuration creates a relatively small filter, resulting in a + slight amount of blurring. + + + + + + + + Example GUI + + + Screenshot of the GUI set to filter all pixels for the image using + a three by three boxcar. Note that as many of the default + parameters as are allowed are being used. + + + + + + + + + + Input image before the lowpass filter. + + + Here we see the original cube. The areas of greatest interest are + those with a great deal of contrast such as edges. + + + FROM + + + + + + + Output image after lowpass + + + After the filter, the entire image is somewhat softer. The difference + may be hard to detect on uniform areas, but the sections of the + image that previously were sharply contrasted are now blurred. As + this particular configuration has been set for a small filter, the + results are obtained quickly and are more subtle than a large filter. + + + TO + + + + + + + Running a 21x21 boxcar on all pixels + + + The lowpass filter is used again here, but at a much more intense level + + + + from= peaks.cub + to=bigLowpass.cub + samples=21 + lines=21 + + + This configuration creates a relatively large filter, resulting in a + great amount of blurring. + + + + + + + + Example GUI + + + Screenshot of the GUI set to filter all pixels for the image using + a 21 by 21 boxcar. This configuration will be slightly slower than + in the previous example, due to the increased boxcar size. + + + + + + + + + + Input image before the lowpass filter. + + + Here we see the original cube. The areas of greatest interest are + those with a great deal of contrast such as edges. + + + FROM + + + + + + + Output image after lowpass + + + As seen here, the 21 by 21 boxcar blurs the image to a great extent. + In fact, there seems to be little purpose for ever using a square + boxcar this large, except for the purpose of illustrating the effect + of the lowpass. + + + TO + + + + + diff --git a/isis/src/base/apps/lowpass/tsts/Makefile b/isis/src/base/apps/lowpass/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/lowpass/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/lowpass/tsts/highLowFilter/Makefile b/isis/src/base/apps/lowpass/tsts/highLowFilter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f23c53e1d530dd030d8ac296ed19d063872c2961 --- /dev/null +++ b/isis/src/base/apps/lowpass/tsts/highLowFilter/Makefile @@ -0,0 +1,12 @@ +APPNAME = lowpass + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/lowTruth2.cub \ + lines=7 \ + samples=9 \ + low=0 \ + high=255 \ + filter=outside > /dev/null; diff --git a/isis/src/base/apps/lowpass/tsts/insideFilter/Makefile b/isis/src/base/apps/lowpass/tsts/insideFilter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5d8f4ea4354826519aa9e3cf8ca557f6a8329c7d --- /dev/null +++ b/isis/src/base/apps/lowpass/tsts/insideFilter/Makefile @@ -0,0 +1,10 @@ +APPNAME = lowpass + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/lowTruth4.cub \ + lines=7 \ + samples=9 \ + filter=inside > /dev/null; diff --git a/isis/src/base/apps/lowpass/tsts/regularPass/Makefile b/isis/src/base/apps/lowpass/tsts/regularPass/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bdf6af8bb4f83be6c2dc8d1c8424905fb02e9d71 --- /dev/null +++ b/isis/src/base/apps/lowpass/tsts/regularPass/Makefile @@ -0,0 +1,9 @@ +APPNAME = lowpass + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/lowTruth1.cub \ + lines=7 \ + samples=9 > /dev/null; diff --git a/isis/src/base/apps/lowpass/tsts/specialPixels/Makefile b/isis/src/base/apps/lowpass/tsts/specialPixels/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7250b282dcebdfd1569839dc5af438633060a088 --- /dev/null +++ b/isis/src/base/apps/lowpass/tsts/specialPixels/Makefile @@ -0,0 +1,17 @@ +APPNAME = lowpass + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/lowTruth3.cub \ + lines=7 \ + samples=9 \ + filter=inside \ + null=false \ + lis=false \ + lrs=false \ + his=false \ + hrs=false \ + low=0 \ + high=255 > /dev/null; diff --git a/isis/src/base/apps/makecube/Makefile b/isis/src/base/apps/makecube/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/makecube/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/makecube/assets/image/makecube.jpg b/isis/src/base/apps/makecube/assets/image/makecube.jpg new file mode 100644 index 0000000000000000000000000000000000000000..013659b67afa51231c540b59ce250ee36597909f Binary files /dev/null and b/isis/src/base/apps/makecube/assets/image/makecube.jpg differ diff --git a/isis/src/base/apps/makecube/assets/image/makecubeGui.jpg b/isis/src/base/apps/makecube/assets/image/makecubeGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fd24dfbc1321d4097e84aeee9b80772c1c6344db Binary files /dev/null and b/isis/src/base/apps/makecube/assets/image/makecubeGui.jpg differ diff --git a/isis/src/base/apps/makecube/assets/thumb/makecube.jpg b/isis/src/base/apps/makecube/assets/thumb/makecube.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6ba65554483ffafdeb023ecab6392858aaf0ce68 Binary files /dev/null and b/isis/src/base/apps/makecube/assets/thumb/makecube.jpg differ diff --git a/isis/src/base/apps/makecube/assets/thumb/makecubeGui.jpg b/isis/src/base/apps/makecube/assets/thumb/makecubeGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c70f84ca7cd6517d2a6f90d2d384c012d8701298 Binary files /dev/null and b/isis/src/base/apps/makecube/assets/thumb/makecubeGui.jpg differ diff --git a/isis/src/base/apps/makecube/makecube.cpp b/isis/src/base/apps/makecube/makecube.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c82ed280d975e0146d8c86e4962fb76e67684e6 --- /dev/null +++ b/isis/src/base/apps/makecube/makecube.cpp @@ -0,0 +1,75 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +// Glocal declarations +void makecube (Buffer &out); +double value; + +void IsisMain() { + // Create a process by line object + ProcessByLine p; + + // Get the value to put in the cube + UserInterface &ui = Application::GetUserInterface(); + string pixels = ui.GetString("PIXELS"); + if (pixels == "NULL") { + value = NULL8; + } + else if (pixels == "LIS") { + value = LOW_INSTR_SAT8; + } + else if (pixels == "LRS") { + value = LOW_REPR_SAT8; + } + else if (pixels == "HIS") { + value = HIGH_INSTR_SAT8; + } + else if (pixels == "HRS") { + value = HIGH_REPR_SAT8; + } + else { + value = ui.GetDouble("VALUE"); + } + + // Need to pick good min/maxs to ensure the user's value + // doesn't get saturated + CubeAttributeOutput &att = ui.GetOutputAttribute("TO"); + if (IsValidPixel(value)) { + if (value == 0.0) { + att.Minimum(value); + att.Maximum(value+1.0); + } + if (value < 0.0) { + att.Minimum(value); + att.Maximum(-value); + } + else { + att.Minimum(-value); + att.Maximum(value); + } + } + else { + att.Minimum(0.0); + att.Maximum(1.0); + } + + // Get the size of the cube and create the cube + int samps = ui.GetInteger("SAMPLES"); + int lines = ui.GetInteger("LINES"); + int bands = ui.GetInteger("BANDS"); + p.SetOutputCube (ui.GetFilename("TO"),att,samps,lines,bands); + + // Make the cube + p.StartProcess(makecube); + p.EndProcess(); +} + +void makecube (Buffer &out) { + for (int i=0; i + + Generate a cube with a constant value + + + This program can be used to generate an output cube of user specified + dimensions with a constant value for each of the pixels. In general, + it is more useful as a development tool than as a standard image + processing tool. For example, a person developing software to compute + statistics on a cube can used this program to create the degenerate + case. + + + + Utility + + + + zero + + + + + Original version + + + + Ported to Isis 3.0 + + + + Add example + + + + Make images smaller. + + + Fixed problem with isiscvs not checking in the thumb and image directories. + + + + Added application test + + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + + Modified XML file to default output pixel type to real + + + + + + + cube + output + real + Output cube + + The file name of the output cube to be created. + + *.cub + + + + + + string + + VALUE + + Type of value to output + + This is the value to output in all pixels in the output image. The + value can be one of the standard Isis special pixel values (NULL, LIS, + LRS, HIS, HRS) or a user specified constant. + + + + + + + + + + + + + double + + 0.0 + + Value to output for all pixels + + This is the user specified value to output in all pixels in the output cube. + + + + + + + integer + Number of samples in the cube + + The number of samples to be allocated in the output cube + + 1 + + + + integer + Number of line in the cube + + The number of lines to be allocated in the ouput cube + + 1 + + + + integer + Number of bands in the cube + + The number of bands to be allocated in the output cube + + 1 + + + + + + + default value + let parameter PIXELS default to value. + + + t=makecube.cub v=100. s=800 l=800 b=1 + Run makecube letting parameter PIXELS default to value and setting parameter VALUE to 100. + + + + + + + Output image Io example of makecube + This is the output image makecube.cub. + + + TO + + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform the makecube operation + + + + + + + + diff --git a/isis/src/base/apps/makecube/tsts/Makefile b/isis/src/base/apps/makecube/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/makecube/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/makecube/tsts/his/Makefile b/isis/src/base/apps/makecube/tsts/his/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f9b8db6a04692c0e23ec8a30f76c350a9f13deeb --- /dev/null +++ b/isis/src/base/apps/makecube/tsts/his/Makefile @@ -0,0 +1,10 @@ +APPNAME = makecube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) to=$(OUTPUT)/makecubeTruth3.cub \ + pixels=his \ + samples=1 \ + lines=1 \ + bands=1 > /dev/null; diff --git a/isis/src/base/apps/makecube/tsts/hrs/Makefile b/isis/src/base/apps/makecube/tsts/hrs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9eb1c1701de1e7e7069cb8f1313ade728167dc45 --- /dev/null +++ b/isis/src/base/apps/makecube/tsts/hrs/Makefile @@ -0,0 +1,10 @@ +APPNAME = makecube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) to=$(OUTPUT)/makecubeTruth5.cub \ + pixels=hrs \ + samples=1 \ + lines=1 \ + bands=1 > /dev/null; diff --git a/isis/src/base/apps/makecube/tsts/lis/Makefile b/isis/src/base/apps/makecube/tsts/lis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..614a081f8fc523805a62c806a59a8dfc3bab35ac --- /dev/null +++ b/isis/src/base/apps/makecube/tsts/lis/Makefile @@ -0,0 +1,10 @@ +APPNAME = makecube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) to=$(OUTPUT)/makecubeTruth2.cub \ + pixels=lis \ + samples=3 \ + lines=5 \ + bands=7 > /dev/null; diff --git a/isis/src/base/apps/makecube/tsts/lrs/Makefile b/isis/src/base/apps/makecube/tsts/lrs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..870af5113bd643a5af2df8d6f05edfd77ce8d265 --- /dev/null +++ b/isis/src/base/apps/makecube/tsts/lrs/Makefile @@ -0,0 +1,10 @@ +APPNAME = makecube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) to=$(OUTPUT)/makecubeTruth4.cub \ + pixels=lrs \ + samples=1 \ + lines=1 \ + bands=1 > /dev/null; diff --git a/isis/src/base/apps/makecube/tsts/null/Makefile b/isis/src/base/apps/makecube/tsts/null/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..13f49c581383d86b97196a7ac8249c818820883a --- /dev/null +++ b/isis/src/base/apps/makecube/tsts/null/Makefile @@ -0,0 +1,10 @@ +APPNAME = makecube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) to=$(OUTPUT)/makecubeTruth1.cub \ + pixels=null \ + samples=1 \ + lines=1 \ + bands=1 > /dev/null; diff --git a/isis/src/base/apps/makecube/tsts/value/Makefile b/isis/src/base/apps/makecube/tsts/value/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..82d2f6b8b77893621a60b2436a05d201bbfd4270 --- /dev/null +++ b/isis/src/base/apps/makecube/tsts/value/Makefile @@ -0,0 +1,11 @@ +APPNAME = makecube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) to=$(OUTPUT)/makecubeTruth6.cub \ + pixels=value \ + value=1 \ + samples=1 \ + lines=1 \ + bands=1 > /dev/null; diff --git a/isis/src/base/apps/makeflat/Makefile b/isis/src/base/apps/makeflat/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/makeflat/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/makeflat/assets/images/PSP_004398_1610_RED5_0.corr.crop.jpg b/isis/src/base/apps/makeflat/assets/images/PSP_004398_1610_RED5_0.corr.crop.jpg new file mode 100644 index 0000000000000000000000000000000000000000..665de2e3b956f7c10553d8c0dc9bf67981fe3fb1 Binary files /dev/null and b/isis/src/base/apps/makeflat/assets/images/PSP_004398_1610_RED5_0.corr.crop.jpg differ diff --git a/isis/src/base/apps/makeflat/assets/images/PSP_004398_1610_RED5_0.raw.crop.jpg b/isis/src/base/apps/makeflat/assets/images/PSP_004398_1610_RED5_0.raw.crop.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3e614cca8d96021855b2d9c3cf5a640fb6438dfc Binary files /dev/null and b/isis/src/base/apps/makeflat/assets/images/PSP_004398_1610_RED5_0.raw.crop.jpg differ diff --git a/isis/src/base/apps/makeflat/assets/images/linescan_gui.jpg b/isis/src/base/apps/makeflat/assets/images/linescan_gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..74693f851ad1f6c6ae737234817d97f00ca8a547 Binary files /dev/null and b/isis/src/base/apps/makeflat/assets/images/linescan_gui.jpg differ diff --git a/isis/src/base/apps/makeflat/assets/images/linescan_raw.jpg b/isis/src/base/apps/makeflat/assets/images/linescan_raw.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fb90330104e4ad6a3e42c5ac493a2950ab682ab1 Binary files /dev/null and b/isis/src/base/apps/makeflat/assets/images/linescan_raw.jpg differ diff --git a/isis/src/base/apps/makeflat/assets/thumbs/PSP_004398_1610_RED5_0.corr.crop.thumb.jpg b/isis/src/base/apps/makeflat/assets/thumbs/PSP_004398_1610_RED5_0.corr.crop.thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7106c2cc80afd1daf3ad7f5edff7d554747afc5d Binary files /dev/null and b/isis/src/base/apps/makeflat/assets/thumbs/PSP_004398_1610_RED5_0.corr.crop.thumb.jpg differ diff --git a/isis/src/base/apps/makeflat/assets/thumbs/PSP_004398_1610_RED5_0.raw.crop.thumb.jpg b/isis/src/base/apps/makeflat/assets/thumbs/PSP_004398_1610_RED5_0.raw.crop.thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..521db4a3b0467c0c835a283dc7879036c5d6eed8 Binary files /dev/null and b/isis/src/base/apps/makeflat/assets/thumbs/PSP_004398_1610_RED5_0.raw.crop.thumb.jpg differ diff --git a/isis/src/base/apps/makeflat/assets/thumbs/linescan_gui_thumb.jpg b/isis/src/base/apps/makeflat/assets/thumbs/linescan_gui_thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f326aaec807817482a95c168e3f320db2f79a10b Binary files /dev/null and b/isis/src/base/apps/makeflat/assets/thumbs/linescan_gui_thumb.jpg differ diff --git a/isis/src/base/apps/makeflat/assets/thumbs/linescan_raw_thumb.jpg b/isis/src/base/apps/makeflat/assets/thumbs/linescan_raw_thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1ac95bcef7e4a81e1b2620ac50bba5121803571d Binary files /dev/null and b/isis/src/base/apps/makeflat/assets/thumbs/linescan_raw_thumb.jpg differ diff --git a/isis/src/base/apps/makeflat/makeflat.cpp b/isis/src/base/apps/makeflat/makeflat.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63a072bff94fc18e0cec99da77142bf4f21fcb3b --- /dev/null +++ b/isis/src/base/apps/makeflat/makeflat.cpp @@ -0,0 +1,903 @@ +#include "Isis.h" + +#include + +#include "ProcessByLine.h" +#include "FileList.h" +#include "Histogram.h" +#include "LineManager.h" + +using namespace Isis; +using namespace std; + +// This method is used for creating the temp file on all camery types +void CreateTemporaryData(Buffer &in); + +// This method is used for creating the final flat field on all camera types +void ProcessTemporaryData(Buffer &in); + +// This method resets the current line scan camera temp data to NULL +void CreateNullData(); + +// This returns true if a file is excluded +bool Excluded(int fileNum); + +// This returns true if a framelet is excluded and gives the standard deviation +bool Excluded(int fileNum, int frameletNum, double &stdev); + +// This method populates the framelet exclusion list given +// a cube. *Uses currImage. +bool CheckFramelets(string progress, Cube &theCube); + +// This method resets the global variables for another run +void ResetGlobals(); + +/** + * This enum holds the supported camera types. + * + * The variable cameraType will be one of these values, which + * will represent the current camera type. + */ +enum CameraType { + LineScan, + PushFrame, + Framing +}; + +/** + * The number of samples in the temp file + * will always equal that of the input cube, + * but the lines will vary. This variable stores + * the number of lines in the temp file; it will + * vary drastically depending on user-entered options + */ +BigInt tempFileLength; + +/** + * This will keep track of which files are excluded. The + * int is the file number in the input list (0 = first file), + * and the boolean is whether or not it's excluded (always true). + * Files that arent excluded will not be added to this map in + * order to increase efficiency. + */ +map excludedFiles; + +/** + * This will keep track of which framelets are excluded. The + * pair is the key, the first number being the file + * in the input list (0 = first), the second being the framelet + * in the file (0 = first). The double is the standard deviation + * of the framelet. Framelets that arent excluded will not be added + * to this map in order to increase efficiency. + */ +map, double> excludedFramelets; + +/** + * This object will be used to keep track of exclusions found during + * the creating of the temporary file. The main method will add an object + * onto this list for every pass, with basic keywords such as filename, and + * the CreateTemporaryData will add a group for every exclusion found. The main + * method will trim objects with no exclusion groups. + */ +vector excludedDetails; + +/** + * This is used for the line scan camera temporary data. Because + * the line scan temporary data creation is done by frame column, + * the data in the previous columns of data needs to be stored until + * a frame is complete. The outputTmpAverages keeps track of the + * averages of each column. + */ +vector outputTmpAverages; + +/** + * This is closely tied with outputTmpAverages, except it keeps track + * of valid pixel counts used in the averages. + */ +vector outputTmpCounts; + +/** + * This keeps track of the averages of the input framelets for framing + * and push frame cameras. For framing cameras, the average is in framelet + * zero. This is necessary in order to normalize the temporary data (second pass) + * with the statistics collected on the first pass. + */ +vector< vector > inputFrameletAverages; + +/** + * This keeps the statistics for each frame in a line scan camera. This is collected + * during the second pass of the data because in a line scan camera, all of the frame + * DNs are read before being written to the temporary file (which is possible because + * only one line of data is written per frame). + */ +Statistics inputFrameStats; + +/** + * This is the standard deviation tolerance. For framing cameras, this is the maximum + * standard deviation of an image before it is excluded. For push frame cameras, this is + * the maximum standard deviation of a framelet. For framing cameras, this is the maximum + * standard deviation of an input image. For line scan cameras, this is the maximum + * standard deviation of a frame. + */ +double maxStdev; + +/** + * This variable is used in two ways. During pass 2, where the temporary file is being + * created, this is the temporary file. During pass 3, where the final output is being + * created, this is the final output. + */ +Cube *ocube = NULL; + +/** + * This is a line manager that is always associated with ocube. + */ +LineManager *oLineMgr = NULL; + +/** + * This is the number of samples in the input images, temporary file,and final output + * cubes (one in the same!). + */ +int numOutputSamples; + +/** + * This is the number of lines per frame. For line scans, this is how many lines + * that are combined into one section for the standard deviation tolerance. For + * push frame cameras, this is the number of lines per framelet. For framing + * cameras, this ends up being the height of the image (1 framelet). + */ +int numFrameLines; + +/** + * This keeps track of special pixel counts for pass 3 of line scan cameras. + * This is the count of total valid input DNs for each column of data that is + * in the temporary data (sum in the line direction of band 2 of the temporary + * file). This is used for the final weighted average calculation. + */ +vector numInputDns; + +/** + * This keeps track of which camera type we're processing. See CameraType. + */ +CameraType cameraType; + +/** + * Since in framing and push frame cameras we don't know if the temporary cube has been + * initialized, and the operations all depend on both the input data and current + * temporary data, this boolean keeps track of whether or not the temporary cube has been + * initialized. + */ +bool cubeInitialized; + +/** + * This is the image that is currently being processed. This is necessary in order for + * the processing methods to determine exclusions and pre-calculated statistics of each + * image. + */ +unsigned int currImage; + +/** + * This is the main method. Makeflat runs in three steps: + * + * 1) Calculate statistics + * - For all cameras, this checks for one band and matching + * sample counts. + * - For framing cameras, this checks the standard deviation of + * the images and records the averages of each image + * - For push frame cameras, this calls CheckFramelets for each + * image. + * + * 2) Create the temporary file, collect more detailed statistics + * - For all cameras, this generates the temporary file and calculates + * the final exclusion list + * - For framing/push frame cameras, the temporary file is + * 2 bands, where the first is a sum of DNs from each image/framelet + * and the second band is a count of valid DNs that went into each sum + * + * 3) Create the final flat field file + * - For all cameras, this processes the temporary file to create the final flat + * field file. + */ +void IsisMain() { + // Initialize variables + ResetGlobals(); + + UserInterface &ui = Application::GetUserInterface(); + maxStdev = ui.GetDouble("STDEVTOL"); + + if(ui.GetString("IMAGETYPE") == "FRAMING") { + cameraType = Framing; + + // framing cameras need to figure this out automatically + // during step 1 + numFrameLines = -1; + } + else if(ui.GetString("IMAGETYPE") == "LINESCAN") { + cameraType = LineScan; + numFrameLines = ui.GetInteger("NUMLINES"); + } + else { + cameraType = PushFrame; + numFrameLines = ui.GetInteger("FRAMELETHEIGHT"); + } + + FileList inList(ui.GetFilename("FROMLIST")); + Progress progress; + + tempFileLength = 0; + numOutputSamples = 0; + + /** + * Line scan progress is based on the input list, whereas + * the other cameras take much longer and are based on the + * images themselves. Prepare the progress if we're doing + * line scan. + */ + if(cameraType == LineScan) { + progress.SetText("Calculating Number of Image Lines"); + progress.SetMaximumSteps(inList.size()); + progress.CheckStatus(); + } + + /** + * For a push frame camera, the temp file is one framelet. + * Technically this is the same for the framing, but we + * don't know the height of a framelet yet. + */ + if(cameraType == PushFrame) { + tempFileLength = numFrameLines; + } + + /** + * Start pass 1, use global currImage so that methods called + * know the image we're processing. + */ + for(currImage = 0; currImage < inList.size(); currImage++) { + /** + * Read the current cube into memory + */ + Cube tmp; + tmp.Open(Filename(inList[currImage]).Expanded()); + + /** + * If we haven't determined how many samples the output + * should have, we can do so now + */ + if(numOutputSamples == 0 && tmp.Bands() == 1) { + numOutputSamples = tmp.Samples(); + } + + /** + * Try and validate the image, quick tests first! + * + * (imageValid &= means imageValid = imageValid && ...) + */ + bool imageValid = true; + + // Only single band images are acceptable + imageValid &= (tmp.Bands() == 1); + + // Sample sizes must always match + imageValid &= (numOutputSamples == tmp.Samples()); + + // For push frame cameras, there must be valid all framelets + if(cameraType == PushFrame) { + imageValid &= (tmp.Lines() % numFrameLines == 0); + } + + // For framing cameras, we need to figure out the size... + // setTempFileLength is used to revert if the file + // is decided to be invalid + bool setTempFileLength = false; + if(cameraType == Framing) { + if(tempFileLength == 0 && imageValid) { + tempFileLength = tmp.Lines(); + numFrameLines = tempFileLength; + setTempFileLength = true; + } + + imageValid &= (tempFileLength == tmp.Lines()); + } + + // Statistics are necessary at this point for push frame and framing cameras + // because the framing camera standard deviation tolerance is based on + // entire images, and push frame framelet exclusion stats can not be collected + // during pass 2 cleanly + if((cameraType == Framing || cameraType == PushFrame) && imageValid) { + string prog = "Calculating Standard Deviation " + iString((int)currImage+1) + "/"; + prog += iString((int)inList.size()) + " (" + Filename(inList[currImage]).Name() + ")"; + + if(cameraType == Framing) { + Statistics *stats = tmp.Statistics(1, prog); + imageValid &= !IsSpecial(stats->StandardDeviation()); + imageValid &= !IsSpecial(stats->Average()); + imageValid &= stats->StandardDeviation() <= maxStdev; + + vector fileStats; + fileStats.push_back(stats->Average()); + inputFrameletAverages.push_back(fileStats); + + delete stats; + } + else if(cameraType == PushFrame) { + imageValid &= CheckFramelets(prog, tmp); + } + + if(setTempFileLength && !imageValid) { + tempFileLength = 0; + } + } + + // The line scan camera needs to actually count the number of lines in each image to know + // how many total frames there are before beginning pass 2. + if(imageValid && (cameraType == LineScan)) { + int lines = (tmp.Lines() / numFrameLines); + + // partial frame? + if(tmp.Lines() % numFrameLines != 0) { + lines ++; + } + + tempFileLength += lines; + } + else if(!imageValid) { + excludedFiles.insert(pair(currImage, true)); + } + + tmp.Close(); + + if(cameraType == LineScan) { + progress.CheckStatus(); + } + } + + /** + * If the number of output samples could not be determined, we never + * found a legitimate cube. + */ + if(numOutputSamples <= 0) { + string msg = "No valid input cubes were found"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + /** + * If theres no temp file length, which is based off of valid data in + * the input cubes, then we havent found any valid data. + */ + if(tempFileLength <= 0) { + string msg = "No valid input data was found"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + /** + * ocube is now the temporary file (for pass 2). + */ + ocube = new Cube(); + ocube->SetDimensions(numOutputSamples, tempFileLength, 2); + PvlGroup &prefs = Preference::Preferences().FindGroup("DataDirectory", Pvl::Traverse); + iString outTmpName = (string)prefs["Temporary"][0] + "/"; + outTmpName += Filename(ui.GetFilename("TO")).Basename() + ".tmp.cub"; + ocube->Create(outTmpName); + oLineMgr = new LineManager(*ocube); + oLineMgr->SetLine(1); + + ProcessByBrick p; + int excludedCnt = 0; + + if(cameraType == LineScan) { + outputTmpAverages.resize(numOutputSamples); + outputTmpCounts.resize(numOutputSamples); + numInputDns.resize(numOutputSamples); + } + + cubeInitialized = false; + for(currImage = 0; currImage < inList.size(); currImage++) { + if(Excluded(currImage)) { + excludedCnt ++; + continue; + } + + PvlObject currFile("Exclusions"); + currFile += PvlKeyword("Filename", inList[currImage]); + currFile += PvlKeyword("Tolerance", maxStdev); + + if(cameraType == LineScan) { + currFile += PvlKeyword("FrameLines", numFrameLines); + } + else if(cameraType == PushFrame) { + currFile += PvlKeyword("FrameletLines", numFrameLines); + } + + excludedDetails.push_back(currFile); + + CubeAttributeInput inAtt; + + // This needs to be set constantly because ClearInputCubes + // seems to be removing the input brick size. + if(cameraType == LineScan) { + p.SetBrickSize(1, numFrameLines, 1); + } + else if(cameraType == Framing || cameraType == PushFrame) { + p.SetBrickSize(numOutputSamples, 1, 1); + } + + p.SetInputCube(inList[currImage], inAtt); + iString progText = "Calculating Averages " + iString((int)currImage+1); + progText += "/" + iString((int)inList.size()); + progText += " (" + Filename(inList[currImage]).Name() + ")"; + p.Progress()->SetText(progText); + + p.StartProcess(CreateTemporaryData); + p.EndProcess(); + p.ClearInputCubes(); + + if(excludedDetails[excludedDetails.size()-1].Groups() == 0) { + excludedDetails.resize(excludedDetails.size()-1); + } + } + + /** + * Pass 2 completed. The processing methods were responsible for writing + * the entire temporary cube. + */ + if(oLineMgr) { + delete oLineMgr; + oLineMgr = NULL; + } + + if(ocube) { + ocube->Close(); + delete ocube; + } + + /** + * ocube is now the final output + */ + ocube = new Cube(); + + if(cameraType == LineScan) { + ocube->SetDimensions(numOutputSamples, 1, 1); + } + else if(cameraType == Framing || cameraType == PushFrame) { + ocube->SetDimensions(numOutputSamples, tempFileLength, 1); + } + + ocube->Create(Filename(ui.GetFilename("TO")).Expanded()); + oLineMgr = new LineManager(*ocube); + oLineMgr->SetLine(1); + + // We now have the necessary temp file, let's go ahead and combine it into + // the final output! + p.SetInputBrickSize(numOutputSamples, 1, 2); + p.SetOutputBrickSize(numOutputSamples, 1, 1); + + cubeInitialized = false; + CubeAttributeInput inAtt; + p.Progress()->SetText("Calculating Final Flat Field"); + p.SetInputCube(outTmpName, inAtt); + p.StartProcess(ProcessTemporaryData); + p.EndProcess(); + + if(cameraType == LineScan) { + ocube->Write(*oLineMgr); + } + + if(oLineMgr) { + delete oLineMgr; + oLineMgr = NULL; + } + + if(ocube) { + ocube->Close(); + delete ocube; + ocube = NULL; + } + + /** + * Build a list of excluded files + */ + PvlGroup excludedFiles("ExcludedFiles"); + for(currImage = 0; currImage < inList.size(); currImage++) { + if(Excluded(currImage)) { + excludedFiles += PvlKeyword("File", inList[currImage]); + } + } + + // log the results + Application::Log(excludedFiles); + + if(ui.WasEntered("EXCLUDE")) { + Pvl excludeFile; + + // Find excluded files + excludeFile.AddGroup(excludedFiles); + + for(unsigned int i = 0; i < excludedDetails.size(); i++) { + excludeFile.AddObject(excludedDetails[i]); + } + + excludeFile.Write(Filename(ui.GetFilename("EXCLUDE")).Expanded()); + } + + remove(outTmpName.c_str()); + + // Clean up settings + ResetGlobals(); +} + +/** + * This method initializes all of the global variables + */ +void ResetGlobals() { + tempFileLength = 0; + numOutputSamples = 0; + numFrameLines = 0; + currImage = 0; + maxStdev = 0.0; + excludedFiles.clear(); + excludedDetails.clear(); + outputTmpAverages.clear(); + outputTmpCounts.clear(); + inputFrameletAverages.clear(); + inputFrameStats.Reset(); + numInputDns.clear(); + excludedFramelets.clear(); + + cubeInitialized = false; + cameraType = LineScan; + + if(ocube) { + delete ocube; + ocube = NULL; + } + + if(oLineMgr) { + delete oLineMgr; + oLineMgr = NULL; + } +} + +/** + * This method performs pass1 on one image. It analyzes each framelet's + * statistics and populates the necessary global variable. + * + * @param progress Progress message + * @param theCube Current cube that needs processing + * + * @return bool True if the file contains a valid framelet + */ +bool CheckFramelets(string progress, Cube &theCube) { + bool foundValidFramelet = false; + LineManager mgr(theCube); + Progress prog; + prog.SetText(progress); + prog.SetMaximumSteps(theCube.Lines()); + prog.CheckStatus(); + + vector frameletAvgs; + // We need to store off the framelet information, because if no good + // framelets were found then no data should be added to the + // global variable for framelets, just files. + vector< pair > excludedFrameletsTmp; + Statistics frameletStats; + + for(int line = 1; line <= theCube.Lines(); line++) { + if((line-1) % numFrameLines == 0) { + frameletStats.Reset(); + } + + mgr.SetLine(line); + theCube.Read(mgr); + frameletStats.AddData(mgr.DoubleBuffer(), mgr.size()); + + if((line-1) % numFrameLines == numFrameLines-1) { + if(IsSpecial(frameletStats.StandardDeviation()) || + frameletStats.StandardDeviation() > maxStdev) { + excludedFrameletsTmp.push_back( + pair((line-1)/numFrameLines, frameletStats.StandardDeviation()) + ); + } + else { + foundValidFramelet = true; + } + + frameletAvgs.push_back(frameletStats.Average()); + } + + prog.CheckStatus(); + } + + inputFrameletAverages.push_back(frameletAvgs); + + if(foundValidFramelet) { + for(unsigned int i = 0; i < excludedFrameletsTmp.size(); i++) { + excludedFramelets.insert(pair< pair, double>( + pair(currImage, excludedFrameletsTmp[i].first), + excludedFrameletsTmp[i].second + ) + ); + } + + } + + return foundValidFramelet; +} + +/** + * This method is the pass 2 processing routine. A ProcessByBrick + * will call this method for sets of data (depending on the camera + * type) and this method is responsible for writing the entire output + * temporary cube. + * + * @param in Input raw image data, not including excluded files + */ +void CreateTemporaryData(Buffer &in) { + /** + * Line scan cameras process by frame columns. + */ + if(cameraType == LineScan) { + // The statistics of every column of data need to be known + // before we can write to the temp file. Gather stats for this + // column. + Statistics inputColStats; + + for(int i = 0; i < in.size(); i++) { + inputColStats.AddData(in[i]); + + // We'll also need the stats for the entire frame in order to + // normalize and in order to decide whether or not we want + // to toss out the frame + inputFrameStats.AddData(in[i]); + } + + // Store off the column stats + outputTmpAverages[in.Sample()-1] = inputColStats.Average(); + outputTmpCounts[in.Sample()-1] = inputColStats.ValidPixels(); + + // Test if this is the last column and we've got all of our stats + if(in.Sample() == numOutputSamples) { + // Decide if we want this data + if(IsSpecial(inputFrameStats.StandardDeviation()) || + inputFrameStats.StandardDeviation() > maxStdev) { + // We don't want this data... + // CreateNullData is a helper method for this case that + // nulls out the stats + CreateNullData(); + + // Record the exclusion + PvlGroup currExclusion("ExcludedLines"); + currExclusion += PvlKeyword("FrameStartLine", iString(in.Line())); + currExclusion += PvlKeyword("ValidPixels", iString(inputFrameStats.ValidPixels())); + + if(!IsSpecial(inputFrameStats.StandardDeviation())) + currExclusion += PvlKeyword("StandardDeviation", inputFrameStats.StandardDeviation()); + else + currExclusion += PvlKeyword("StandardDeviation", "N/A"); + + excludedDetails[excludedDetails.size()-1].AddGroup(currExclusion); + } + + // Let's write our data... CreateNullData took care of nulls for us + // Band 1 is our normalized average + oLineMgr->SetLine(oLineMgr->Line(),1); + for(int i = 0; i < (int)outputTmpAverages.size(); i++) { + if(!IsSpecial(outputTmpAverages[i])) { + (*oLineMgr)[i] = outputTmpAverages[i] / inputFrameStats.Average(); + } + else { + (*oLineMgr)[i] = Isis::Null; + } + } + + ocube->Write(*oLineMgr); + oLineMgr->SetLine(oLineMgr->Line(),2); + + // band 2 is our valid dn counts + for(int i = 0; i < (int)outputTmpCounts.size(); i++) { + (*oLineMgr)[i] = outputTmpCounts[i]; + numInputDns[i] += (int)(outputTmpCounts[i] + 0.5); + } + + ocube->Write(*oLineMgr); + (*oLineMgr) ++; + + inputFrameStats.Reset(); + } + } + else if(cameraType == Framing || cameraType == PushFrame) { + // Framing cameras and push frames are treated identically; + // the framelet size for a framelet in the framing camera + // is the entire image! + int framelet = (in.Line()-1) / numFrameLines; + double stdev; + bool excluded = Excluded(currImage, framelet, stdev); + + if(excluded && ((in.Line()-1) % numFrameLines == 0)) { + PvlGroup currExclusion("ExcludedFramelet"); + currExclusion += PvlKeyword("FrameletStartLine", iString(in.Line())); + currExclusion += PvlKeyword("FrameletNumber", (in.Line()-1) / numFrameLines); + + if(!IsSpecial(stdev)) { + currExclusion += PvlKeyword("StandardDeviation", + stdev); + } + else { + currExclusion += PvlKeyword("StandardDeviation", + "N/A"); + } + + excludedDetails[excludedDetails.size()-1].AddGroup(currExclusion); + } + + // Since this is a line by line iterative process, we need to get the current + // data in the temp file + oLineMgr->SetLine(((in.Line() - 1) % numFrameLines) + 1, 1); + + if(!excluded || !cubeInitialized) { + ocube->Read(*oLineMgr); + } + + if(!cubeInitialized) { + for(int i = 0; i < oLineMgr->size(); i++) { + (*oLineMgr)[i] = Isis::Null; + } + } + + vector isValidData; + + if(!excluded || !cubeInitialized) { + isValidData.resize(in.size()); + + for(int samp = 0; samp < in.size(); samp++) { + if(IsSpecial((*oLineMgr)[samp]) && !IsSpecial(in[samp])) { + (*oLineMgr)[samp] = 0.0; + } + + if(!IsSpecial(in[samp])) { + isValidData[samp] = true; + (*oLineMgr)[samp] += in[samp] / inputFrameletAverages[currImage][framelet]; + } + else { + isValidData[samp] = false; + } + } + } + + if(!excluded || !cubeInitialized) { + ocube->Write(*oLineMgr); + } + + oLineMgr->SetLine(oLineMgr->Line(), 2); + + if(!excluded || !cubeInitialized) { + ocube->Read(*oLineMgr); + } + + if(!cubeInitialized) { + for(int i = 0; i < oLineMgr->size(); i++) { + (*oLineMgr)[i] = Isis::Null; + } + + if(ocube->Lines() == oLineMgr->Line()) + cubeInitialized = true; + } + + if(!excluded || !cubeInitialized) { + for(int i = 0; i < (int)isValidData.size(); i++) { + if(IsSpecial((*oLineMgr)[i])) { + (*oLineMgr)[i] = 0.0; + } + + if(isValidData[i]) { + (*oLineMgr)[i] ++; + } + } + } + + if(!excluded || !cubeInitialized) { + ocube->Write(*oLineMgr); + } + } +} + +/** + * This method is the pass 3 processing routine. This compresses + * the temporary file into the final flat file. ocube is the final + * out file, the Buffer argument is the temp file. + * + * @param in Line of data in the temporary file generated in pass 2 + */ +void ProcessTemporaryData(Buffer &in) { + if(!cubeInitialized) { + for(int i = 0; i < (*oLineMgr).size(); i++) { + (*oLineMgr)[i] = Isis::Null; + } + } + + if(cameraType == LineScan) { + cubeInitialized = true; + + for(int i = 0; i < (*oLineMgr).size(); i++) { + int avgIndex = in.Index(i+1, in.Line(), 1); + int validIndex = in.Index(i+1, in.Line(), 2); + + if(!IsSpecial(in[avgIndex]) && !IsSpecial(in[validIndex])) { + if(IsSpecial((*oLineMgr)[i])) { + (*oLineMgr)[i] = 0.0; + } + + (*oLineMgr)[i] += in[avgIndex] * (int)(in[validIndex] + 0.5) / (double)numInputDns[i]; + } + } + } + else if(cameraType == Framing || cameraType == PushFrame) { + oLineMgr->SetLine(((in.Line() - 1) % numFrameLines) + 1); + + for(int i = 0; i < (*oLineMgr).size(); i++) { + int sumIndex = in.Index(i+1, in.Line(), 1); + int validIndex = in.Index(i+1, in.Line(), 2); + + if(!IsSpecial(in[sumIndex]) && !IsSpecial(in[validIndex])) { + (*oLineMgr)[i] = in[sumIndex] / in[validIndex]; + } + } + + ocube->Write(*oLineMgr); + + if(ocube->Lines() == oLineMgr->Line()) + cubeInitialized = true; + } +} + +/** + * This is a helper method for line scan cameras. It removes the + * statistics from the global variables that contain the current + * frame's data. + */ +void CreateNullData() { + for(int i = 0; i < (int)outputTmpAverages.size(); i++) { + outputTmpAverages[i] = Isis::Null; + outputTmpCounts[i] = 0; + } +} + +/** + * This method tests if a file was excluded. + * + * @param fileNum Zero-indexed file from the FROMLIST (often just currFile) + * + * @return bool True if file was excluded + */ +bool Excluded(int fileNum) { + map::iterator it = excludedFiles.find(fileNum); + + if(it == excludedFiles.end()) { + return false; + } + else { + return it->second; + } +} + +/** + * This method tests if a framelet in a file was excluded. + * + * @param fileNum Zero-indexed file from the FROMLIST (often just currFile) + * @param frameletNum Framelet to test in the current file + * @param stdev This will be set to the standard deviation of the framelet + * if the framelet was excluded + * + * @return bool True if the framelet was excluded + */ +bool Excluded(int fileNum, int frameletNum, double &stdev) { + if(Excluded(fileNum)) return true; + + map< pair, double>::iterator it = excludedFramelets.find(pair(fileNum,frameletNum)); + + if(it == excludedFramelets.end()) { + return false; + } + else { + stdev = it->second; + return true; + } +} diff --git a/isis/src/base/apps/makeflat/makeflat.xml b/isis/src/base/apps/makeflat/makeflat.xml new file mode 100644 index 0000000000000000000000000000000000000000..523be6b5dca0b15244ece3654f3b5945b07bd057 --- /dev/null +++ b/isis/src/base/apps/makeflat/makeflat.xml @@ -0,0 +1,264 @@ + + + + + + Create a flat-field image for line-scan instruments + + + +

    + This program creates flat-field images for line scan, push frame, and framing instruments. + All input cubes should have the same number of samples; any images in the list that do not + have the same number of samples as the first image will not be used. The names of the cube + files used to create the flat-field image must be entered using an ASCII file (FROMLIST) with + one filename per line (any line beginning with a '#' or '//' is treated as a comment). The + specific equation for each camera type is below. +

    +
      +
    • Line Scan
    • +

      + A frame is a NUMLINES line section of data. The equation for the final single line, single + band, flat field file is: +
      + Sum( Sum(FrameColumn) / Average(Frame) * ValidPixels(FrameColumn) ) / + TotalColumnValidPixels
      +

      + +
    • Push Frame
    • +

      + The equation for the final single framelet, single band flat field file is:
      Average( + PixelInFramelet1, PixelInFramelet2, PixelInFramelet3, ... ) +

      +
    • Framing
    • +

      + The equation for the final single framelet, single band flat field file is:
      Average( + PixelInCube1, PixelInCube2, PixelInCube3, ... ) +

      +
    +

    + Warning: This program creates potentially large temporary files +

    +
    + + + + Original version, Adapted from Isis2 version of makeflat. + + + Removed references to CubeInfo . + + + Changed algorithm and added support for framing and push frame cameras. + + + + + Math and Statistics + Radiometric and Photometric Correction + + + + + + filename + input + + List of input cubes + + + Use this parameter to select the file which contains a list of + cube filenames to be used to create the flat file. + + + *.lis + + + + + cube + real + output + + Output flat field cube + + + Output flat field cube + + + + + filename + None + output + + Output PVL-formatted file of all excluded files and sections of data + + + Output PVL-formatted file of all excluded files and sections of data. + + + + + + + double + + This is the maximum standard deviation + + + For a framing camera, this is the maximum standard deviation of each image. For a push + frame camera, this is the maximum standard deviation of each framelet. For a line scan + camera, this is the maximum standard deviation of NUMLINES lines. Data that exceeds + this standard deviation will be ignored. + + + + + + + string + LINESCAN + + This is the type of camera which took the image. + + + Line scan cameras collect a cube a single line of data at a time. Push frame cameras collect + multiple lines of cube data at once. Framing cameras collect an entire cube of data at + once. + + + + + + + + + + + + integer + + This is the the number of lines to consider when doing statistics + + + A single line often does not have enough data in it to perform good tolerance + calculations. The tolerance calculations will be performed on this many lines as + a time, and if found to be invalid, this many lines will be excluded from the output + flat file calculations at a time. + + + + + + + integer + + This is the height of each framelet in the image. + + + Push frame images consist of framelets. The framelet size needs to be + known in order to make a flat field file for a push frame camera. + + + + + + + + Line Scan Cubes + + This program was run on 65 hirise images to produce a flat file, and one of the images was + calibrated with the flat file. + + + fromlist=files.lis to=flat.linescan.cub exclude=exclude.txt stdevtol=30 + numlines=100 + + + This is a typical run for makeflat. files.lis is a list file generated by a "ls *.cub > + files.lis" command. The files inside of files.lis are between 20,000 lines and 200,000 + lines of data (variable length). The file flat.linescan.cub is the flat-field output given + these cubes and the file exclude.txt is a detailed output of what was excluded. + + + + + + + This is a typical run for the linescan mode + + + This is a typical run for makeflat. files.lis is a list file generated by a "ls *.cub > + files.lis" command. The files inside of files.lis are between 20,000 lines and 200,000 + lines of data (variable length). The file flat.linescan.cub is the flat-field output given + these cubes and the file exclude.txt is a detailed output of what was excluded. + + + IMAGETYPE + + + + + + This is a section of one of the inputs listed in files.lis + + + This is the input to makeflat. Notice the vertical lines persistent throughout the + image and the dark area on the right-hand side. + + + FROMLIST + + + + + + This is input that has been calibrated + + + This is the same section of image data as before, except calibrated with the + flat-field file that was generated by dividing by the flat field file. The vertical + lines and darkness have completely gone away. + + + + + + + +
    diff --git a/isis/src/base/apps/makeflat/tsts/Makefile b/isis/src/base/apps/makeflat/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/makeflat/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/makeflat/tsts/framing/Makefile b/isis/src/base/apps/makeflat/tsts/framing/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1843df5fdafcbab40c3224c5b1ba217403ad444c --- /dev/null +++ b/isis/src/base/apps/makeflat/tsts/framing/Makefile @@ -0,0 +1,8 @@ +APPNAME = makeflat + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) fromlist=$(INPUT)/fromList.lis \ + to=$(OUTPUT)/framingFlatTruth.cub STDEV=190 \ + IMAGETYPE=FRAMING EXCLUDE=$(OUTPUT)/framingFlatTruth.txt> /dev/null; diff --git a/isis/src/base/apps/makeflat/tsts/linescan/Makefile b/isis/src/base/apps/makeflat/tsts/linescan/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4a049bccaa2d5e20ed28e0106071799ab9ae1031 --- /dev/null +++ b/isis/src/base/apps/makeflat/tsts/linescan/Makefile @@ -0,0 +1,11 @@ +APPNAME = makeflat + +linescanFlatTruth.cub.TOLERANCE = 0.0000002 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) fromlist=$(INPUT)/fromList.lis \ + to=$(OUTPUT)/linescanFlatTruth.cub STDEV=190 \ + IMAGETYPE=LINESCAN NUMLINES=10 \ + EXCLUDE=$(OUTPUT)/linescanFlatTruth.txt > /dev/null; diff --git a/isis/src/base/apps/makeflat/tsts/pushframe/Makefile b/isis/src/base/apps/makeflat/tsts/pushframe/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..745a8865aa8eebdc40b00590ae8f2bec839166f8 --- /dev/null +++ b/isis/src/base/apps/makeflat/tsts/pushframe/Makefile @@ -0,0 +1,9 @@ +APPNAME = makeflat + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) fromlist=$(INPUT)/fromList.lis \ + to=$(OUTPUT)/pushFrameFlatTruth.cub STDEV=150 \ + IMAGETYPE=PUSHFRAME FRAMELETHEIGHT=50 EXCLUDE=$(OUTPUT)/pushFrame.txt \ + > /dev/null; diff --git a/isis/src/base/apps/map2cam/Makefile b/isis/src/base/apps/map2cam/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/map2cam/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/map2cam/map2cam.cpp b/isis/src/base/apps/map2cam/map2cam.cpp new file mode 100644 index 0000000000000000000000000000000000000000..efdc63c4b13a513da6cf108f9ee4e412cd959414 --- /dev/null +++ b/isis/src/base/apps/map2cam/map2cam.cpp @@ -0,0 +1,118 @@ +#include "Isis.h" + +#include "Camera.h" +#include "ProcessRubberSheet.h" + +#include "map2cam.h" + +using namespace std; +using namespace Isis; + +// Global variables +Cube *mcube; +Camera *outcam; +void BandChange (const int band); + +void IsisMain() { + // Open the input camera cube that we will be matching and create + // the camera object + Process p; + mcube = p.SetInputCube("MATCH"); + outcam = mcube->Camera(); + + // Open the input projection cube and get the projection information + ProcessRubberSheet rub; + Cube *icube = rub.SetInputCube("FROM"); + Projection *inmap = icube->Projection(); + + // Set up for rubbersheeting + Transform *transform = new map2cam (icube->Samples(), + icube->Lines(), + inmap, + mcube->Samples(), + mcube->Lines(), + outcam); + + // Allocate the output cube but don't propogate any labels from the map + // file. Instead propagate from the camera file + rub.PropagateLabels(false); + rub.SetOutputCube ("TO", transform->OutputSamples(), + transform->OutputLines(), + icube->Bands()); + UserInterface &ui = Application::GetUserInterface(); + rub.PropagateLabels(ui.GetFilename("MATCH")); + + // Set up the interpolator + Interpolator *interp = NULL; + if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { + interp = new Interpolator(Interpolator::NearestNeighborType); + } + else if (ui.GetString("INTERP") == "BILINEAR") { + interp = new Interpolator(Interpolator::BiLinearType); + } + else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { + interp = new Interpolator(Interpolator::CubicConvolutionType); + } + + // See if the camera is band dependent and account for it + if (!outcam->IsBandIndependent()) { + rub.BandChange(BandChange); + } + + // Warp the cube + rub.StartProcess(*transform, *interp); + rub.EndProcess(); + + // Cleanup + delete transform; + delete interp; +} + +// Transform object constructor +map2cam::map2cam (const int inputSamples, const int inputLines, + Projection *inmap, + const int outputSamples, const int outputLines, + Camera *outcam) { + p_inputSamples = inputSamples; + p_inputLines = inputLines; + p_inmap = inmap; + + p_outputSamples = outputSamples; + p_outputLines = outputLines; + p_outcam = outcam; +} + +// Transform method mapping output line/samps to lat/lons to input line/samps +bool map2cam::Xform (double &inSample, double &inLine, + const double outSample, const double outLine) { + // See if the output image coordinate converts to lat/lon + if (!p_outcam->SetImage(outSample,outLine)) return false; + + // Get the universal lat/lon and see if it can be converted to input line/samp + double lat = p_outcam->UniversalLatitude(); + double lon = p_outcam->UniversalLongitude(); + if (!p_inmap->SetUniversalGround(lat,lon)) return false; + + // Make sure the point is inside the input image + if (p_inmap->WorldX() < 0.5) return false; + if (p_inmap->WorldX() < 0.5) return false; + if (p_inmap->WorldY() > p_inputSamples + 0.5) return false; + if (p_inmap->WorldY() > p_inputLines + 0.5) return false; + + // Everything is good + inSample = p_inmap->WorldX(); + inLine = p_inmap->WorldY(); + return true; +} + +int map2cam::OutputSamples () const { + return p_outputSamples; +} + +int map2cam::OutputLines () const { + return p_outputLines; +} + +void BandChange (const int band) { + outcam->SetBand(mcube->PhysicalBand(band)); +} diff --git a/isis/src/base/apps/map2cam/map2cam.h b/isis/src/base/apps/map2cam/map2cam.h new file mode 100644 index 0000000000000000000000000000000000000000..8763feed61c20254d28472c10eb2d322049c2caf --- /dev/null +++ b/isis/src/base/apps/map2cam/map2cam.h @@ -0,0 +1,30 @@ +#ifndef cam2map_h +#define cam2map_h + +#include "Transform.h" + +class map2cam : public Isis::Transform { + private: + Isis::Camera *p_outcam; + Isis::Projection *p_inmap; + int p_inputSamples; + int p_inputLines; + int p_outputSamples; + int p_outputLines; + + public: + // constructor + map2cam (const int inputSamples, const int inputLines, Isis::Projection *inmap, + const int outputSamples, const int outputLines, Isis::Camera *outcam); + + // destructor + ~map2cam () {}; + + // Implementations for parent's pure virtual members + bool Xform (double &inSample, double &inLine, + const double outSample, const double outLine); + int OutputSamples () const; + int OutputLines () const; +}; + +#endif diff --git a/isis/src/base/apps/map2cam/map2cam.xml b/isis/src/base/apps/map2cam/map2cam.xml new file mode 100644 index 0000000000000000000000000000000000000000..7ad7ffe722e29afd2624a135f04fe6519f18d384 --- /dev/null +++ b/isis/src/base/apps/map2cam/map2cam.xml @@ -0,0 +1,135 @@ + + + + + Convert map projected image to a raw camera image + + + + This program will take as input an image in a map project and + geometrically transform it into a raw instrument image. This allows + for example a Viking base map to be converted to a MOC raw geometry + image. + + + + Map Projection + + + + + Original version + + + Converted to Isis 3.0 + + + Fixed a bug in BandChange, added appTest + + + Fixed appTest to reflect changes made to all camera models + + + Fixed typo in user documentation + + + Removed references to CubeInfo + + + + + lev2tolev1 + base2l1 + base + + + + + + cube + input + + Input map projected cube to geometrically transform + + + The specification of the input cube to be projected. The cube must + contain a valid Mapping group in the labels. + + + *.cub + + + + + cube + input + + Raw instrument cube to match + + + This cube defines the raw instrument geometry to be matched. The + output file will have the same labels (Kernel and Instrument + group). Note the Band group will represent data from the + raw camera and the content of the cube may not match. For example, + using the MOLA base as the FROM file and a MOC Wide Angle Red cube + as the match, will have labels which indicate geometry for the MOC + WA red camera but the pixels will contain MOLA elevations. + + + *.cub + + + + + cube + output + + Output raw instrument cube + + + This cube will contain data whose geometric properties are identical + to those of the MATCH cube. + + + *.cub + + + + + + + string + + CUBICCONVOLUTION + + Type of interpolation + + This is the type of interpolation to be performed on the input. + + + + + + + + + + diff --git a/isis/src/base/apps/map2cam/tsts/Makefile b/isis/src/base/apps/map2cam/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/map2cam/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/map2cam/tsts/case01/Makefile b/isis/src/base/apps/map2cam/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bfa99bee4d49da61cec8d16fdac66894e6b133fc --- /dev/null +++ b/isis/src/base/apps/map2cam/tsts/case01/Makefile @@ -0,0 +1,9 @@ +APPNAME = map2cam + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/ab102401.lev2.cub \ + match= $(INPUT)/ab102401.cub \ + to=$(OUTPUT)/map2camTruth1.cub \ + interp=nearestneighbor> /dev/null; diff --git a/isis/src/base/apps/map2cam/tsts/case02/Makefile b/isis/src/base/apps/map2cam/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..db0cf71353392f40aa381ba462a2250c2a5d6269 --- /dev/null +++ b/isis/src/base/apps/map2cam/tsts/case02/Makefile @@ -0,0 +1,9 @@ +APPNAME = map2cam + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/ab102402.lev2.cub \ + match= $(INPUT)/ab102401.cub \ + to=$(OUTPUT)/map2camTruth2.cub \ + interp=nearestneighbor> /dev/null; diff --git a/isis/src/base/apps/map2map/Makefile b/isis/src/base/apps/map2map/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/map2map/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/map2map/map2map.cpp b/isis/src/base/apps/map2map/map2map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e628acec57ebf74a1a88e37fa8baefed0118ae1 --- /dev/null +++ b/isis/src/base/apps/map2map/map2map.cpp @@ -0,0 +1,600 @@ +#define GUIHELPERS + +#include "Isis.h" +#include "ProcessRubberSheet.h" +#include "ProjectionFactory.h" +#include "Projection.h" +#include "map2map.h" + +using namespace std; +using namespace Isis; + +void PrintMap (); +void LoadMapRange(); + +map GuiHelpers(){ + map helper; + helper ["PrintMap"] = (void*) PrintMap; + helper ["LoadMapRange"] = (void*) LoadMapRange; + return helper; +} + +void IsisMain() { + // We will be warping a cube + ProcessRubberSheet p; + + // Get the map projection file provided by the user + UserInterface &ui = Application::GetUserInterface(); + Pvl userPvl(ui.GetFilename("MAP")); + PvlGroup &userMappingGrp = userPvl.FindGroup("Mapping",Pvl::Traverse); + + // Open the input cube and get the projection + Cube *icube = p.SetInputCube ("FROM"); + + // Get the mapping group + PvlGroup fromMappingGrp = icube->GetGroup("Mapping"); + Projection *inproj = icube->Projection(); + PvlGroup outMappingGrp = fromMappingGrp; + + // If the default range is FROM, then wipe out any range data in user mapping file + if(ui.GetString("DEFAULTRANGE").compare("FROM") == 0 && !ui.GetBoolean("MATCHMAP")) { + if(userMappingGrp.HasKeyword("MinimumLatitude")) { + userMappingGrp.DeleteKeyword("MinimumLatitude"); + } + + if(userMappingGrp.HasKeyword("MaximumLatitude")) { + userMappingGrp.DeleteKeyword("MaximumLatitude"); + } + + if(userMappingGrp.HasKeyword("MinimumLongitude")) { + userMappingGrp.DeleteKeyword("MinimumLongitude"); + } + + if(userMappingGrp.HasKeyword("MaximumLongitude")) { + userMappingGrp.DeleteKeyword("MaximumLongitude"); + } + } + + // Deal with user overrides entered in the GUI. Do this by changing the user's mapping group, which + // will then overlay anything in the output mapping group. + if(ui.WasEntered("MINLAT") && !ui.GetBoolean("MATCHMAP")) { + userMappingGrp.AddKeyword( PvlKeyword("MinimumLatitude", ui.GetDouble("MINLAT")), Pvl::Replace ); + } + + if(ui.WasEntered("MAXLAT") && !ui.GetBoolean("MATCHMAP")) { + userMappingGrp.AddKeyword( PvlKeyword("MaximumLatitude", ui.GetDouble("MAXLAT")), Pvl::Replace ); + } + + if(ui.WasEntered("MINLON") && !ui.GetBoolean("MATCHMAP")) { + userMappingGrp.AddKeyword( PvlKeyword("MinimumLongitude", ui.GetDouble("MINLON")), Pvl::Replace ); + } + + if(ui.WasEntered("MAXLON") && !ui.GetBoolean("MATCHMAP")) { + userMappingGrp.AddKeyword( PvlKeyword("MaximumLongitude", ui.GetDouble("MAXLON")), Pvl::Replace ); + } + + /** + * If the user is changing from positive east to positive west, or vice-versa, the output minimum is really + * the input maximum. However, the user mapping group must be left unaffected (an input minimum must be the + * output minimum). To accomplish this, we swap the minimums/maximums in the output group ahead of time. This + * causes the minimums and maximums to correlate to the output minimums and maximums. That way when we copy + * the user mapping group into the output group a mimimum overrides a minimum and a maximum overrides a maximum. + */ + bool sameDirection = true; + if(userMappingGrp.HasKeyword("LongitudeDirection")) { + if(((string)userMappingGrp["LongitudeDirection"]).compare(fromMappingGrp["LongitudeDirection"]) != 0) { + sameDirection = false; + } + } + + // Since the out mapping group came from the from mapping group, which came from a valid cube, + // we can assume both min/max lon exists if min longitude exists. + if(!sameDirection && outMappingGrp.HasKeyword("MinimumLongitude")) { + double minLon = outMappingGrp["MinimumLongitude"]; + double maxLon = outMappingGrp["MaximumLongitude"]; + + outMappingGrp["MaximumLongitude"] = minLon; + outMappingGrp["MinimumLongitude"] = maxLon; + } + + if(ui.GetString("PIXRES").compare("FROM") == 0 && !ui.GetBoolean("MATCHMAP")) { + // Resolution will be in fromMappingGrp and outMappingGrp at this time + // delete from user mapping grp + if(userMappingGrp.HasKeyword("Scale")) { + userMappingGrp.DeleteKeyword("Scale"); + } + + if(userMappingGrp.HasKeyword("PixelResolution")) { + userMappingGrp.DeleteKeyword("PixelResolution"); + } + } + else if(ui.GetString("PIXRES").compare("MAP") == 0 || ui.GetBoolean("MATCHMAP")) { + // Resolution will be in userMappingGrp - delete all others + if(outMappingGrp.HasKeyword("Scale")) { + outMappingGrp.DeleteKeyword("Scale"); + } + + if(outMappingGrp.HasKeyword("PixelResolution")) { + outMappingGrp.DeleteKeyword("PixelResolution"); + } + + if(fromMappingGrp.HasKeyword("Scale")); { + fromMappingGrp.DeleteKeyword("Scale"); + } + + if(fromMappingGrp.HasKeyword("PixelResolution")) { + fromMappingGrp.DeleteKeyword("PixelResolution"); + } + } + else if(ui.GetString("PIXRES").compare("MPP") == 0) { + // Resolution specified - delete all and add to outMappingGrp + if(outMappingGrp.HasKeyword("Scale")) { + outMappingGrp.DeleteKeyword("Scale"); + } + + if(outMappingGrp.HasKeyword("PixelResolution")) { + outMappingGrp.DeleteKeyword("PixelResolution"); + } + + if(fromMappingGrp.HasKeyword("Scale")) { + fromMappingGrp.DeleteKeyword("Scale"); + } + + if(fromMappingGrp.HasKeyword("PixelResolution")) { + fromMappingGrp.DeleteKeyword("PixelResolution"); + } + + if(userMappingGrp.HasKeyword("Scale")) { + userMappingGrp.DeleteKeyword("Scale"); + } + + if(userMappingGrp.HasKeyword("PixelResolution")) { + userMappingGrp.DeleteKeyword("PixelResolution"); + } + + outMappingGrp.AddKeyword(PvlKeyword("PixelResolution", ui.GetDouble("RESOLUTION"), "meters/pixel"), Pvl::Replace); + } + else if(ui.GetString("PIXRES").compare("PPD") == 0) { + // Resolution specified - delete all and add to outMappingGrp + if(outMappingGrp.HasKeyword("Scale")) { + outMappingGrp.DeleteKeyword("Scale"); + } + + if(outMappingGrp.HasKeyword("PixelResolution")) { + outMappingGrp.DeleteKeyword("PixelResolution"); + } + + if(fromMappingGrp.HasKeyword("Scale")) { + fromMappingGrp.DeleteKeyword("Scale"); + } + + if(fromMappingGrp.HasKeyword("PixelResolution")) { + fromMappingGrp.DeleteKeyword("PixelResolution"); + } + + if(userMappingGrp.HasKeyword("Scale")) { + userMappingGrp.DeleteKeyword("Scale"); + } + + if(userMappingGrp.HasKeyword("PixelResolution")) { + userMappingGrp.DeleteKeyword("PixelResolution"); + } + + outMappingGrp.AddKeyword(PvlKeyword("Scale", ui.GetDouble("RESOLUTION"), "pixels/degree"), Pvl::Replace); + } + + // Rotation will NOT Propagate + if(outMappingGrp.HasKeyword("Rotation")) { + outMappingGrp.DeleteKeyword("Rotation"); + } + + + /** + * The user specified map template file overrides what ever is in the + * cube's mapping group. + */ + for(int keyword = 0; keyword < userMappingGrp.Keywords(); keyword ++) { + outMappingGrp.AddKeyword(userMappingGrp[keyword], Pvl::Replace); + } + + /** + * Now, we have to deal with unit conversions. We convert only if the following are true: + * 1) We used values from the input cube + * 2) The values are longitudes or latitudes + * 3) The map file or user-specified information uses a different measurement system than + * the input cube for said values. + * + * The data is corrected for: + * 1) Positive east/positive west + * 2) Longitude domain + * 3) planetographic/planetocentric. + */ + + // First, the longitude direction + if(!sameDirection) { + PvlGroup longitudes = inproj->MappingLongitudes(); + + for(int index = 0; index < longitudes.Keywords(); index ++) { + if(!userMappingGrp.HasKeyword(longitudes[index].Name())) { + // use the from domain because that's where our values are coming from + if(((string)userMappingGrp["LongitudeDirection"]).compare("PositiveEast") == 0) { + outMappingGrp[longitudes[index].Name()] = + Projection::ToPositiveEast(outMappingGrp[longitudes[index].Name()], outMappingGrp["LongitudeDomain"]); + } + else { + outMappingGrp[longitudes[index].Name()] = + Projection::ToPositiveWest(outMappingGrp[longitudes[index].Name()], outMappingGrp["LongitudeDomain"]); + } + } + } + } + + // The minimum/maximum longitudes should be in order now. However, if the user entered a + // maximum that was lower than the minimum, or a minimum that was higher than the maximum this + // may still fail. Let it throw an error when we instantiate the projection. + + // Second, longitude domain + if(userMappingGrp.HasKeyword("LongitudeDomain")) { // user set a new domain? + if((int)userMappingGrp["LongitudeDomain"] != (int)fromMappingGrp["LongitudeDomain"]) { // new domain different? + + PvlGroup longitudes = inproj->MappingLongitudes(); + + for(int index = 0; index < longitudes.Keywords(); index ++) { + if(!userMappingGrp.HasKeyword(longitudes[index].Name())) { + if((int)userMappingGrp["LongitudeDomain"] == 180) { + outMappingGrp[longitudes[index].Name()] = Projection::To180Domain(outMappingGrp[longitudes[index].Name()]); + } + else { + outMappingGrp[longitudes[index].Name()] = Projection::To360Domain(outMappingGrp[longitudes[index].Name()]); + } + } + } + + } + } + + // Third, planetographic/planetocentric + if(userMappingGrp.HasKeyword("LatitudeType")) { // user set a new domain? + if(((string)userMappingGrp["LatitudeType"]).compare(fromMappingGrp["LatitudeType"]) != 0) { // new lat type different? + + PvlGroup latitudes = inproj->MappingLatitudes(); + + for(int index = 0; index < latitudes.Keywords(); index ++) { + if(!userMappingGrp.HasKeyword(latitudes[index].Name())) { + if(((string)userMappingGrp["LatitudeType"]).compare("Planetographic") == 0) { + outMappingGrp[latitudes[index].Name()] = Projection::ToPlanetographic( + (double)fromMappingGrp[latitudes[index].Name()], + (double)fromMappingGrp["EquatorialRadius"], + (double)fromMappingGrp["PolarRadius"]); + } + else { + outMappingGrp[latitudes[index].Name()] = Projection::ToPlanetocentric( + (double)fromMappingGrp[latitudes[index].Name()], + (double)fromMappingGrp["EquatorialRadius"], + (double)fromMappingGrp["PolarRadius"]); + } + } + } + + } + } + + // If MinLon/MaxLon out of order, we weren't able to calculate the correct values + if((double)outMappingGrp["MinimumLongitude"] >= (double)outMappingGrp["MaximumLongitude"]) { + if(!ui.WasEntered("MINLON") || !ui.WasEntered("MAXLON")) { + string msg = "Unable to determine the correct [MinimumLongitude,MaximumLongitude]."; + msg += " Please specify these values in the [MINLON,MAXLON] parameters"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + } + + int samples,lines; + Pvl mapData; + // Copy to preserve cube labels so we can match cube size + if (userPvl.HasObject("IsisCube")) { + mapData = userPvl; + mapData.FindObject("IsisCube").DeleteGroup("Mapping"); + mapData.FindObject("IsisCube").AddGroup(outMappingGrp); + } + else { + mapData.AddGroup(outMappingGrp); + } + + // *NOTE: The UpperLeftX,UpperLeftY keywords will not be used in the CreateForCube + // method, and they will instead be recalculated. This is correct. + Projection *outproj = ProjectionFactory::CreateForCube(mapData,samples,lines, + ui.GetBoolean("MATCHMAP")); + + // Set up the transform object which will simply map + // output line/samps -> output lat/lons -> input line/samps + Transform *transform = new map2map (icube->Samples(), + icube->Lines(), + icube->Projection(), + samples, + lines, + outproj, + ui.GetBoolean("TRIM")); + + // Allocate the output cube and add the mapping labels + Cube *ocube = p.SetOutputCube ("TO", transform->OutputSamples(), + transform->OutputLines(), + icube->Bands()); + + PvlGroup cleanOutGrp = outproj->Mapping(); + + // ProjectionFactory::CreateForCube updated mapData to have the correct + // upperleftcornerx, upperleftcornery, scale and resolution. Use these + // updated numbers. + cleanOutGrp.AddKeyword(mapData.FindGroup("Mapping",Pvl::Traverse)["UpperLeftCornerX"], Pvl::Replace); + cleanOutGrp.AddKeyword(mapData.FindGroup("Mapping",Pvl::Traverse)["UpperLeftCornerY"], Pvl::Replace); + cleanOutGrp.AddKeyword(mapData.FindGroup("Mapping",Pvl::Traverse)["Scale"], Pvl::Replace); + cleanOutGrp.AddKeyword(mapData.FindGroup("Mapping",Pvl::Traverse)["PixelResolution"], Pvl::Replace); + + ocube->PutGroup(cleanOutGrp); + + // Set up the interpolator + Interpolator *interp; + if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { + interp = new Interpolator(Interpolator::NearestNeighborType); + } + else if (ui.GetString("INTERP") == "BILINEAR") { + interp = new Interpolator(Interpolator::BiLinearType); + } + else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { + interp = new Interpolator(Interpolator::CubicConvolutionType); + } + else { + string msg = "Unknow value for INTERP [" + ui.GetString("INTERP") + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + // Warp the cube + p.StartProcess(*transform, *interp); + p.EndProcess(); + + Application::Log(cleanOutGrp); + + // Cleanup + delete transform; + delete interp; +} + +// Transform object constructor +map2map::map2map (const int inputSamples, const int inputLines, Projection *inmap, + const int outputSamples, const int outputLines, Projection *outmap, + bool trim) { + p_inputSamples = inputSamples; + p_inputLines = inputLines; + p_inmap = inmap; + + p_outputSamples = outputSamples; + p_outputLines = outputLines; + p_outmap = outmap; + + p_trim = trim; + + p_inputWorldSize = 0; + bool wrapPossible = inmap->IsEquatorialCylindrical(); + + if(inmap->IsEquatorialCylindrical()) { + // Figure out how many samples 360 degrees is + wrapPossible = wrapPossible && inmap->SetUniversalGround(0, 0); + int worldStart = (int)(inmap->WorldX() + 0.5); + wrapPossible = wrapPossible && inmap->SetUniversalGround(0, 180); + int worldEnd = (int)(inmap->WorldX() + 0.5); + + p_inputWorldSize = abs(worldEnd - worldStart)*2; + } +} + +// Transform method mapping output line/samps to lat/lons to input line/samps +bool map2map::Xform (double &inSample, double &inLine, + const double outSample, const double outLine) { + // See if the output image coordinate converts to lat/lon + if (!p_outmap->SetWorld(outSample,outLine)) return false; + + // See if we should trim + if ((p_trim) && (p_outmap->HasGroundRange())) { + if (p_outmap->Latitude() < p_outmap->MinimumLatitude()) return false; + if (p_outmap->Latitude() > p_outmap->MaximumLatitude()) return false; + if (p_outmap->Longitude() < p_outmap->MinimumLongitude()) return false; + if (p_outmap->Longitude() > p_outmap->MaximumLongitude()) return false; + } + + // Get the universal lat/lon and see if it can be converted to input line/samp + double lat = p_outmap->UniversalLatitude(); + double lon = p_outmap->UniversalLongitude(); + if (!p_inmap->SetUniversalGround(lat,lon)) return false; + + inSample = p_inmap->WorldX(); + inLine = p_inmap->WorldY(); + + if(p_inputWorldSize != 0) { + // Try to correct the sample if we can, + // this is the simplest way to code the + // translation although it probably could + // be done in one "if" + while(inSample < 0.5) { + inSample += p_inputWorldSize; + } + + while(inSample > p_inputSamples + 0.5) { + inSample -= p_inputWorldSize; + } + } + + // Make sure the point is inside the input image + if (inSample < 0.5) return false; + if (inLine < 0.5) return false; + if (inSample > p_inputSamples + 0.5) return false; + if (inLine > p_inputLines + 0.5) return false; + + // Everything is good + return true; +} + +int map2map::OutputSamples () const { + return p_outputSamples; +} + +int map2map::OutputLines () const { + return p_outputLines; +} + + +// Helper function to print out mapfile to session log +void PrintMap() { + UserInterface &ui = Application::GetUserInterface(); + + // Get mapping group from map file + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + //Write map file out to the log + Isis::Application::GuiLog(userGrp); +} + +void LoadMapRange() { + UserInterface &ui = Application::GetUserInterface(); + + // Get map file + Pvl userMap; + + try { + userMap.Read(ui.GetFilename("MAP")); + } + catch (iException &e) { + e.Clear(); + } + + // Get input cube + Pvl fromMap; + + try { + fromMap.Read(ui.GetFilename("FROM")); + } + catch (iException &e) { + e.Clear(); + } + + // Try to get the mapping groups + PvlGroup fromMapping("Mapping"); + + try { + fromMapping = fromMap.FindGroup("Mapping", Pvl::Traverse); + } + catch (iException &e) { + e.Clear(); + } + + PvlGroup userMapping("Mapping"); + + try { + userMapping = userMap.FindGroup("Mapping", Pvl::Traverse); + } + catch (iException &e) { + e.Clear(); + } + + // Do conversions on from map + + // Longitude conversions first + if(userMapping.HasKeyword("LongitudeDirection")) { + if(((string)userMapping["LongitudeDirection"]).compare(fromMapping["LongitudeDirection"]) != 0) { + double minLon = fromMapping["MinimumLongitude"]; + double maxLon = fromMapping["MaximumLongitude"]; + int domain = fromMapping["LongitudeDomain"]; + + if(userMapping.HasKeyword("LongitudeDomain")) { + domain = userMapping["LongitudeDomain"]; + } + + if((string)userMapping["LongitudeDirection"] == "PositiveEast") { + fromMapping["MaximumLongitude"] = Projection::ToPositiveEast(minLon, domain); + fromMapping["MinimumLongitude"] = Projection::ToPositiveEast(maxLon, domain); + } + else if((string)userMapping["LongitudeDirection"] == "PositiveWest") { + fromMapping["MaximumLongitude"] = Projection::ToPositiveWest(minLon, domain); + fromMapping["MinimumLongitude"] = Projection::ToPositiveWest(maxLon, domain); + } + } + } + + // Latitude conversions now + if(userMapping.HasKeyword("LatitudeType")) { // user set a new domain? + if(((string)userMapping["LatitudeType"]).compare(fromMapping["LatitudeType"]) != 0) { // new lat type different? + if(((string)userMapping["LatitudeType"]).compare("Planetographic") == 0) { + fromMapping["MinimumLatitude"] = Projection::ToPlanetographic( + (double)fromMapping["MinimumLatitude"], + (double)fromMapping["EquatorialRadius"], + (double)fromMapping["PolarRadius"]); + fromMapping["MaximumLatitude"] = Projection::ToPlanetographic( + (double)fromMapping["MaximumLatitude"], + (double)fromMapping["EquatorialRadius"], + (double)fromMapping["PolarRadius"]); + } + else { + fromMapping["MinimumLatitude"] = Projection::ToPlanetocentric( + (double)fromMapping["MinimumLatitude"], + (double)fromMapping["EquatorialRadius"], + (double)fromMapping["PolarRadius"]); + fromMapping["MaximumLatitude"] = Projection::ToPlanetocentric( + (double)fromMapping["MaximumLatitude"], + (double)fromMapping["EquatorialRadius"], + (double)fromMapping["PolarRadius"]); + } + } + } + + // Failed at longitudes, use our originals! + if((double)fromMapping["MinimumLongitude"] >= (double)fromMapping["MaximumLongitude"]) { + try { + fromMapping["MinimumLongitude"] = fromMap.FindGroup("Mapping", Pvl::Traverse)["MinimumLongitude"]; + fromMapping["MaximumLongitude"] = fromMap.FindGroup("Mapping", Pvl::Traverse)["MaximumLongitude"]; + } + catch (iException &e) { + e.Clear(); + } + } + + // Overlay lat/lons in map file (if DEFAULTRANGE=MAP) + if(ui.GetString("DEFAULTRANGE") == "MAP") { + if(userMapping.HasKeyword("MinimumLatitude")) { + fromMapping["MinimumLatitude"] = userMapping["MinimumLatitude"]; + } + + if(userMapping.HasKeyword("MaximumLatitude")) { + fromMapping["MaximumLatitude"] = userMapping["MaximumLatitude"]; + } + + if(userMapping.HasKeyword("MinimumLongitude")) { + fromMapping["MinimumLongitude"] = userMapping["MinimumLongitude"]; + } + + if(userMapping.HasKeyword("MaximumLongitude")) { + fromMapping["MaximumLongitude"] = userMapping["MaximumLongitude"]; + } + } + + if(ui.WasEntered("MINLAT")) { + ui.Clear("MINLAT"); + } + + if(ui.WasEntered("MAXLAT")) { + ui.Clear("MAXLAT"); + } + + if(ui.WasEntered("MINLON")) { + ui.Clear("MINLON"); + } + + if(ui.WasEntered("MAXLON")) { + ui.Clear("MAXLON"); + } + + ui.PutDouble("MINLAT", fromMapping["MinimumLatitude"]); + ui.PutDouble("MAXLAT", fromMapping["MaximumLatitude"]); + ui.PutDouble("MINLON", fromMapping["MinimumLongitude"]); + ui.PutDouble("MAXLON", fromMapping["MaximumLongitude"]); +} diff --git a/isis/src/base/apps/map2map/map2map.h b/isis/src/base/apps/map2map/map2map.h new file mode 100644 index 0000000000000000000000000000000000000000..0fdf1098e6cbaca7f1d2cdd187f4f6a435920a40 --- /dev/null +++ b/isis/src/base/apps/map2map/map2map.h @@ -0,0 +1,33 @@ +#ifndef map2map_h +#define map2map_h + +#include "Transform.h" + +class map2map : public Isis::Transform { + private: + Isis::Projection *p_inmap; + Isis::Projection *p_outmap; + int p_inputSamples; + int p_inputLines; + bool p_trim; + int p_outputSamples; + int p_outputLines; + int p_inputWorldSize; + + public: + // constructor + map2map (const int inputSamples, const int inputLines, Isis::Projection *inmap, + const int outputSamples, const int outputLines, Isis::Projection *outmap, + bool trim); + + // destructor + ~map2map () {}; + + // Implementations for parent's pure virtual members + bool Xform (double &inSample, double &inLine, + const double outSample, const double outLine); + int OutputSamples () const; + int OutputLines () const; +}; + +#endif diff --git a/isis/src/base/apps/map2map/map2map.xml b/isis/src/base/apps/map2map/map2map.xml new file mode 100644 index 0000000000000000000000000000000000000000..0702de777003f781dc21099e7df3c5429d585044 --- /dev/null +++ b/isis/src/base/apps/map2map/map2map.xml @@ -0,0 +1,390 @@ + + + + + Change a cube's map projection + + + + This program will alter the projection of a cube which is already in a map + projection. Pixels are physically moved using either a nearest neighbor, + bilinear, or cubic convolution interpolator. Usage examples of this + program include: +
    +      1.  Converting from Sinusodial to Mercator or any other
    +          supported projection
    +      2.  No projection change but altering projection parameters
    +          such as center longitude or standard parallels
    +      3.  No projection change but altering pixel resolution
    +      4.  No projection change but altering latitude/longitude window
    +      5.  No projection change but altering latitude types, longitude
    +          domains, or longitude direction
    +    
    + +
    + + + Map Projection + + + + + Original version + + + Converted to Isis 3.0 + + + Modified schema location from astogeology... to isis.astrogeology... + + + Fixed compiler error with uninitialized variable after adding -O1 flag + + + Modified filename parameters to be cube parameters where necessary + + + Added appTest + + + Depricated CubeProjection and ProjectionManager to ProjectionFactory + + + Fixed typo in user documentation + + + Expanded options, fixed conversions when switching measurement systems (such as from planetographic to planetocentric) + + + Fixed bug with changing resolutions + + + Rewrote resolution handling code to be simpler and fix yet another bug. + + + Fixed method of getting cube specific projection group parameters, such as the scale and resolution. + + + Fixed bug trimming longitudes + + + Fixed bug when TRIM option was used and most if not all data was being + NULLed. + + + Fixed bug where user-entered resolutions could be ignored + + + Added the MATCHMAP option. + + + Removed references to CubeInfo + + + The rotation keyword will no longer automatically propagate + + + Added helper button and improved error message + + + Changed MATCHMAP to default off and added exclusions. If MATCHMAP is true, + the ground range and pixel resolution can not be set because they are to be + taken from the map file. + + + Moved the MATCHMAP parameter to the "FILES" parameter group. Fixed a problem with this + program that caused null output images when the input longitude domain was inconsistent + with the input longitude range in equatorial cylindrical projections. + + + Changed the parameters SLAT, ELAT, SLON, ELON to MINLAT, MAXLAT, MINLON, + MAXLON in correlation with autimos. + + + Added a default path as well as a helper function for the MAP parameter. + + + + + nuproj + newmap + lev2tolev2 + + + + + + cube + input + + Input cube to remap + + + The specification of the input cube to be remapped. The cube must + contain a valid Mapping group in the labels. + + + *.cub + + + + + filename + input + + File containing mapping parameters + + $base/templates/maps + $base/templates/maps/sinusoidal.map + + A file containing the desired output mapping parameters. This + file can be a simple label file, hand produced or created via + the "maptemplate" program. It can also be an existing cube label + which contains a Mapping group. In the later case the input cube + will be transformed into the same map projection, resolution, etc. + + + + PrintMap + View MapFile + + This helper button will cat out the mapping group of the given mapfile to the session log + of the application + + $ISIS3DATA/base/icons/labels.png + + + + *.map *.cub + + + + + cube + output + + Newly mapped cube + + + This file will contain the results of the remapping. + + + *.cub + + + + boolean + FALSE + Match number of Lines and Samples + + This makes the number of lines, number of samples, resolution + and ground range of the output cube match the MAP file. + + + PIXRES + RESOLUTION + DEFAULTRANGE + MINLAT + MAXLAT + MINLON + MAXLON + + + + + + + string + Defines how the pixel resolution in the output map file is obtained + FROM + + This parameter is used to specify how the pixel resolution is obtained for the output map + projected cube. + + + + + + + + + + + + double + Pixel resolution + + Specifies the resolution in either meters per pixel or pixels per degree + + 0.0 + + + + + + string + Defines how the default ground range is determined + FROM + + This parameter is used to specify how the default latitude/longitude ground range for the output map projected image + is obtained. The ground range can be obtained from the camera or map file. Note the user can overide the default using the MINLAT, MAXLAT, MINLON, MAXLON parameters. + The purpose of the ground range is to define the coverage of the map projected image. Essentially, the ground range and + pixel resolution are used to compute the size (samples and line) of the output image. + + + + + + + + LoadMapRange + Calculate Latitude/Longitude Ranges + + This helper button will calculate and convert the latitudes and + longitudes it finds in the input file if DEFAULTRANGE=FROM. If the + default range is MAP, this will copy the latitudes/longitudes from + the map files and calculate the unfound ones from the input cube. + + $ISIS3DATA/base/icons/exec.png + + + + + + double + Minimum Latitude + Use default range + + The minimum latitude of the ground range. If this is entered by the user it will override the default input cube or map value. + + + -90.0 + 90.0 + + + + double + Maximum Latitude + Use default range + + The maximum latitude of the ground range. If this is entered by the user it will override the default input cube or map value. + + -90.0 + 90.0 + MINLAT + + + + double + Minimum Longitude + Use default range + + The minimum longitude of the ground range. If this is entered by the user it will override the default input cube or map value. + + + + + double + Maximum Longitude + Use default range + + The maximum longitude of the ground range. If this is entered by the user it will override the default input cube or map value. + + MINLON + + + + boolean + FALSE + + Trim pixels outside ground range + + + If this option is selected, pixels outside the latitude/longtiude + range will be trimmed or set to null. + This is useful for certain projections whose lines of latitude and + longitude are not parallel to image lines and sample columns. + + + + + + + string + + CUBICCONVOLUTION + + Type of interpolation + + This is the type of interpolation to be performed on the input. + + + + + + + + + +
    diff --git a/isis/src/base/apps/map2map/tsts/Makefile b/isis/src/base/apps/map2map/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/map2map/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/map2map/tsts/default/Makefile b/isis/src/base/apps/map2map/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b8a833c3b14cbbd4a064548abbf8fe3bc52e9de9 --- /dev/null +++ b/isis/src/base/apps/map2map/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = map2map + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.lev2.cub \ + map=$(INPUT)/ab102402.lev2.cub \ + to=$(OUTPUT)/map2mapTruth.cub \ + defaultrange=map INTERP=NEARESTNEIGHBOR > /dev/null; diff --git a/isis/src/base/apps/map2map/tsts/projection/Makefile b/isis/src/base/apps/map2map/tsts/projection/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5dad3916a0366513c850417f2ee0c66166ef9822 --- /dev/null +++ b/isis/src/base/apps/map2map/tsts/projection/Makefile @@ -0,0 +1,15 @@ +APPNAME = map2map + +labels.txt.IGNORELINES = Bytes ByteOrder +# This tolerance is so high because it's ObliqueCylindrical and +# the interpolation causes pixel differences. +map2mapTruth.cub.TOLERANCE = 0.000001 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/ab102401.cub \ + MAP=$(INPUT)/oblique.map \ + TO=$(OUTPUT)/map2mapTruth.cub \ + > /dev/null; + catlab FROM=$(OUTPUT)/map2mapTruth.cub >& $(OUTPUT)/labels.txt; diff --git a/isis/src/base/apps/map2map/tsts/units/Makefile b/isis/src/base/apps/map2map/tsts/units/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1b4d170dd2a2a1c88eb01c40d14942658512d1a0 --- /dev/null +++ b/isis/src/base/apps/map2map/tsts/units/Makefile @@ -0,0 +1,10 @@ +APPNAME = map2map + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/lub0428b.cub \ + MAP=$(INPUT)/mapfile.map \ + TO=$(OUTPUT)/map2mapTruth.cub \ + MAXLON=-109 > /dev/null; + catlab FROM=$(OUTPUT)/map2mapTruth.cub >& $(OUTPUT)/labels.pvl; diff --git a/isis/src/base/apps/mapgrid/Makefile b/isis/src/base/apps/mapgrid/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/mapgrid/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/mapgrid/assets/image/lambertGrid.JPG b/isis/src/base/apps/mapgrid/assets/image/lambertGrid.JPG new file mode 100755 index 0000000000000000000000000000000000000000..8595bd478d3dc675a9db08f9c8148259c6e5ba3a Binary files /dev/null and b/isis/src/base/apps/mapgrid/assets/image/lambertGrid.JPG differ diff --git a/isis/src/base/apps/mapgrid/assets/image/sinusoidalGrid.JPG b/isis/src/base/apps/mapgrid/assets/image/sinusoidalGrid.JPG new file mode 100755 index 0000000000000000000000000000000000000000..e744562c97bf1cd336691d9f15823bc7b08085a2 Binary files /dev/null and b/isis/src/base/apps/mapgrid/assets/image/sinusoidalGrid.JPG differ diff --git a/isis/src/base/apps/mapgrid/assets/thumb/lambertGrid.JPG b/isis/src/base/apps/mapgrid/assets/thumb/lambertGrid.JPG new file mode 100755 index 0000000000000000000000000000000000000000..fa571a87bfc828a5d0028f33f45e57b6c5dee32d Binary files /dev/null and b/isis/src/base/apps/mapgrid/assets/thumb/lambertGrid.JPG differ diff --git a/isis/src/base/apps/mapgrid/assets/thumb/sinusoidalGrid.JPG b/isis/src/base/apps/mapgrid/assets/thumb/sinusoidalGrid.JPG new file mode 100755 index 0000000000000000000000000000000000000000..81ec09c69f303378159b75719f269854522a5630 Binary files /dev/null and b/isis/src/base/apps/mapgrid/assets/thumb/sinusoidalGrid.JPG differ diff --git a/isis/src/base/apps/mapgrid/mapgrid.cpp b/isis/src/base/apps/mapgrid/mapgrid.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4fa00ccf0c169a0c2258987d92e7459377c289fc --- /dev/null +++ b/isis/src/base/apps/mapgrid/mapgrid.cpp @@ -0,0 +1,252 @@ +#include "Isis.h" +#include "UserInterface.h" +#include "iException.h" +#include "ProjectionFactory.h" +#include "Progress.h" +#include "Pvl.h" +#include + +using namespace std; +using namespace Isis; + +void StartNewLine(std::ofstream&); +void AddPointToLine(std::ofstream&, double, double); +void EndLine(std::ofstream&); +void CheckContinuous(double latlon, double latlon_start, double X, double Y, double lastX, double lastY, double maxChange, std::ofstream &os); + +void IsisMain() { + // Get user interface + UserInterface &ui = Application::GetUserInterface(); + + // Get necessary variables from the user + double latStart = ui.GetDouble("STARTLAT"); + double lonStart = ui.GetDouble("STARTLON"); + double latEnd = ui.GetDouble("ENDLAT"); + double lonEnd = ui.GetDouble("ENDLON"); + double latSpacing = ui.GetDouble("LATSPACING"); + double lonSpacing = ui.GetDouble("LONSPACING"); + double latInc = ui.GetDouble("LATINCREMENT"); + double lonInc = ui.GetDouble("LONINCREMENT"); + + // Get mapfile, add values for range and create projection + string mapFile = ui.GetFilename("MAPFILE"); + Pvl p(mapFile); + PvlGroup &mapping = p.FindGroup("Mapping",Pvl::Traverse); + + if(mapping.HasKeyword("MinimumLatitude")) { + mapping.DeleteKeyword("MinimumLatitude"); + } + + if(mapping.HasKeyword("MaximumLatitude")) { + mapping.DeleteKeyword("MaximumLatitude"); + } + + if(mapping.HasKeyword("MinimumLongitude")) { + mapping.DeleteKeyword("MinimumLongitude"); + } + + if(mapping.HasKeyword("MaximumLongitude")) { + mapping.DeleteKeyword("MaximumLongitude"); + } + + mapping += PvlKeyword("MinimumLatitude",latStart); + mapping += PvlKeyword("MaximumLatitude",latEnd); + mapping += PvlKeyword("MinimumLongitude",lonStart); + mapping += PvlKeyword("MaximumLongitude",lonEnd); + + Projection *proj; + try { + proj = ProjectionFactory::Create(p); + } + catch (iException &e) { + string msg = "Cannot create grid - MapFile [" + mapFile + + "] does not contain necessary information to create a projection"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + + // Write grid to well known text output + string out = Filename(ui.GetFilename("TO")).Expanded(); + std::ofstream os; + os.open(out.c_str(),std::ios::out); + + // Display the progress...10% 20% etc. + Progress prog; + int steps = (int)(abs((latEnd - latStart) / latSpacing) + + abs((lonEnd - lonStart) / lonSpacing) + 0.5) + 3; + prog.SetMaximumSteps(steps); + prog.CheckStatus(); + + /** + * Initialize document. GML is XML-based, so we need the necessary XML headers. These + * are necessary for the GML file to be recognized. + */ + os << "" << endl; + os << "" << endl; + + /** + * Draw the interior longitude lines by looping through the longitude + * range and drawing across each latitude line using the longitude increment. The first + * and last line will be skipped for now. + */ + for (double j=lonStart+lonSpacing; jSetGround(k,j); + AddPointToLine(os, proj->XCoord(), proj->YCoord()); + } + + EndLine(os); + prog.CheckStatus(); + } + + /** + * Draw the exterior longitude boundary lines. This happens by drawing just the first and + * last longitude lines. + */ + for (double r=lonStart; r<=lonEnd; r+=(lonEnd-lonStart)) { + StartNewLine(os); + for (double s=latStart; s<=latEnd; s+=lonInc) { + proj->SetGround(s,r); + AddPointToLine(os, proj->XCoord(), proj->YCoord()); + } + EndLine(os); + prog.CheckStatus(); + } + + /** + * Draw the interior latitude lines by looping through the latitude + * range and drawing across each longitude line using the latitude increment. The first + * and last line will be skipped for now. + */ + for (double i=latStart+latSpacing; iSetGround(i,l); + AddPointToLine(os, proj->XCoord(), proj->YCoord()); + } + EndLine(os); + prog.CheckStatus(); + } + + /** + * Draw the exterior latitude boundary lines. This happens by drawing just the first and + * last longitude lines. + */ + for (double m=latStart; m<=latEnd; m+=(latEnd-latStart)) { + StartNewLine(os); + + for (double n=lonStart; n<=lonEnd; n+=latInc) { + proj->SetGround(m,n); + AddPointToLine(os, proj->XCoord(), proj->YCoord()); + } + + EndLine(os); + prog.CheckStatus(); + } + + /** + * Draw the bounding box using a series of lines. + */ + if (ui.GetBoolean("BOUNDED")) { + double minX,maxX,minY,maxY; + proj->XYRange(minX,maxX,minY,maxY); + + StartNewLine(os); + AddPointToLine(os, minX, minY); + AddPointToLine(os, minX, maxY); + EndLine(os); + + StartNewLine(os); + AddPointToLine(os, minX, maxY); + AddPointToLine(os, maxX, maxY); + EndLine(os); + + StartNewLine(os); + AddPointToLine(os, maxX, minY); + AddPointToLine(os, maxX, maxY); + EndLine(os); + + StartNewLine(os); + AddPointToLine(os, minX, minY); + AddPointToLine(os, maxX, minY); + EndLine(os); + } + + os << "" << endl; + + // add mapping to print.prt + PvlGroup projMapping = proj->Mapping(); + Application::Log(projMapping); +} + +/** + * This will prepare a new line start in GML. This should be called every time a new line is + * started and generates unique IDs for each line. + * + * @param os output file stream + */ +void StartNewLine(std::ofstream &os) { + static int lineID = 0; + + os << "" << endl; + os << " " << endl; + os << " " << lineID << "" << endl; + os << " " << "" << ""; + + lineID ++; +} + +/** + * This will add a point to a line started with StartNewLine. StartNewLine must be + * called before using this method, and EndLine after all of the points in the line have + * been added. + * + * @param os output file stream + * @param x x coordinate + * @param y y coordinate + */ +void AddPointToLine(std::ofstream &os, const double x, const double y) { + os << x << "," << y << " "; +} + +/** + * This will end a line in GML. This should be called after each line has the necessary points + * added using AddPointToLine. + * + * @param os output file stream + */ +void EndLine(std::ofstream &os) { + os << "" << "" << "" << endl; + os << " " << endl; + os << "" << endl; +} + +/** + * This function was created to deal with potential discontinuities in mapping patterns in order to not + * connect them. It will create a new line if there is more than a maxChange difference in the points. + * This was coded for ObliqueCylindrical. + * + * @param latlon Current latitude or longitude value + * @param latlon_start Initial latitude or longitude value of this line + * @param X X coordinate of this point + * @param Y Y coordinate of this point + * @param lastX Previous X coordinate of this point + * @param lastY Previous Y coordinate of this point + * @param maxChange Maximum distance between these two points + * @param os Output file stream + */ +/*void CheckContinuous(double latlon, double latlon_start, double X, double Y, double lastX, double lastY, double maxChange, std::ofstream &os) { + if(latlon != latlon_start) { + if(sqrt(pow(lastX - X,2) + (pow(lastX - X,2))) > maxChange) { + EndLine(os); + StartNewLine(os); + } + } +}*/ diff --git a/isis/src/base/apps/mapgrid/mapgrid.xml b/isis/src/base/apps/mapgrid/mapgrid.xml new file mode 100644 index 0000000000000000000000000000000000000000..35c20f268100171c4dcc491c9cab833656159b06 --- /dev/null +++ b/isis/src/base/apps/mapgrid/mapgrid.xml @@ -0,0 +1,271 @@ + + + + + + Draws a grid of Latitude/Longitude lines for a projection + + + + This program will draw a grid of latitude and longitude lines for a + projected mapping. The mapfile should contain all necessary + keywords and values to create the specific projection. If you are unsure + of what keywords are necessary, a template file can be created + for the projection using the maptemplate application. The output + is a GML file that can be plotted using qgis. + + + + Map Projection + + + + + Original version + + + Fixed application test for all systems + + + Fixed bug in xml and made appTest test larger lat/lon increments and spacings to reduce the size of truth files + + + Modified mapgrid so the boundary lat lines will always be drawn + + + Depricated CubeProjection and ProjectionManager to ProjectionFactory + + + Changed output to be in GML format, fixed bug with bounded option + + + Fixed bug with include files. + + + Mapping group parameters are now placed into the print file. + + + + + + + filename + input + + Map File + + + This file contains the mapping projection information necessary to + make the grid. This can be a text file or a cube. + + + *.txt *.cub + + + + + filename + output + + Grid Output + + + The resultant grid. The output is a GML file that can be plotted using qgis. + + + *.gml + + + + + + + double + + Starting Latitude + + + This is the starting value for the latitude lines in the grid. + + + + + double + + Starting Longitude + + + This is the starting value for the longitude lines in the grid. + + + + + double + + Ending Latitude + + + This is the ending value for the latitude lines in the grid. + + + + + double + + Ending Longitude + + + This is the ending value for the longitude lines in the grid. + + + + + double + + Value for Spacing the Latitude Lines + + + This value will determine how far apart the latitude + lines are spaced. + + 10.0 + + + + double + + Value for Spacing the Longitude Lines + + + This value will determine how far apart the longitude + lines are spaced. + + 10.0 + + + + double + + Incrementing value for the Latitude Lines + + + This value will determine how smooth the latitude lines are drawn. + A large value here will create a more rough, jagged line, while a very + small value will create a more smooth, curved line. + + 0.01 + + + + double + + Incrementing value for the Longitude lines + + + This value will determine how smooth the longitude lines are drawn. + A large value here will create a more rough, jagged line, while a very + small value will create a more smooth, curved line. + + 0.01 + + + + boolean + + Draw Boundary Lines on Grid + + + If this option is selected, boundry lines will be drawn + around the projection grid. If the option is not selected, + no boundry lines will be drawn. + + TRUE + + + + + + + + Sinusoidal Map Grid + + This example shows the qgis display of a sinusoidal projection created by this application. + The following mapfile was used in the mapgrid application to create the grid. +
    +Group = Mapping
    +  ProjectionName     = Sinusoidal
    +  TargetName         = MARS
    +  EquatorialRadius   = 3396190.0 <meters>
    +  PolarRadius        = 3376200.0 <meters>
    +  LatitudeType       = Planetocentric
    +  LongitudeDirection = PositiveEast
    +  LongitudeDomain    = 360
    +  CenterLongitude    = 180.0
    +End_Group
    +End
    +         
    +
    + + mapfile=mapFile1.txt startlat=-90 endlat=90 startlon=0 endlon=360 to=sinuGrid.txt + + + Create a sinusoidal projection map grid. + + + + + + Output image as it appears in qgis for mapgrid + + This is the output image that results. + + + TO + + +
    + + + Lambert Confromal Map Grid + + This example shows the qgis display of a lambert conformal projection created by this application. + The following mapfile was used in the this application to create the grid. +
    +Group = Mapping
    +  ProjectionName         = LambertConformal
    +  TargetName             = MARS
    +  EquatorialRadius       = 3396190.0 <meters>
    +  PolarRadius            = 3376200.0 <meters>
    +  LatitudeType           = Planetocentric
    +  LongitudeDirection     = PositiveEast
    +  LongitudeDomain        = 360
    +  CenterLongitude        = 20.0
    +  CenterLatitude         = 40.0
    +  FirstStandardParallel  = 32.0
    +  SecondStandardParallel = 43.0
    +End_Group
    +End
    +         
    +
    + + mapfile=mapFile2.txt startlat=20 endlat=60 startlon=0 endlon=40 to=lambGrid.txt + + + Create a lambert conformal projection map grid. + + + + + + Output image as it appears in qgis + + This is the output image that results + + + TO + + +
    +
    + +
    diff --git a/isis/src/base/apps/mapgrid/tsts/Makefile b/isis/src/base/apps/mapgrid/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/mapgrid/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/mapgrid/tsts/case01/Makefile b/isis/src/base/apps/mapgrid/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..32335a1b2432c28b9070395c878de4e4e4c7e87f --- /dev/null +++ b/isis/src/base/apps/mapgrid/tsts/case01/Makefile @@ -0,0 +1,15 @@ +APPNAME = mapgrid + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) mapfile=$(INPUT)/mapFile1.txt \ + startlat=-90 \ + endlat=90 \ + startlon=0 \ + endlon=360 \ + latspacing=25 \ + lonspacing=25 \ + latinc=5 \ + loninc=5 \ + to=$(OUTPUT)/mapgridTruth.txt > /dev/null; diff --git a/isis/src/base/apps/mapgrid/tsts/case02/Makefile b/isis/src/base/apps/mapgrid/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3797c44b128cd41422c4c68889c70d843765fc44 --- /dev/null +++ b/isis/src/base/apps/mapgrid/tsts/case02/Makefile @@ -0,0 +1,15 @@ +APPNAME = mapgrid + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) mapfile=$(INPUT)/mapFile2.txt \ + startlat=20 \ + endlat=60 \ + startlon=0 \ + endlon=40 \ + latspacing=25 \ + lonspacing=25 \ + latinc=5 \ + loninc=5 \ + to=$(OUTPUT)/mapgridTruth2.txt > /dev/null; diff --git a/isis/src/base/apps/maplab/Makefile b/isis/src/base/apps/maplab/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/maplab/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/maplab/assets/dataFiles/maplabTruth11.txt b/isis/src/base/apps/maplab/assets/dataFiles/maplabTruth11.txt new file mode 100644 index 0000000000000000000000000000000000000000..d6fb5f0804f7c5f0771e923b6d7c39a62d4ec010 --- /dev/null +++ b/isis/src/base/apps/maplab/assets/dataFiles/maplabTruth11.txt @@ -0,0 +1,121 @@ +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 + End_Group + + Group = Pixels + Type = Real + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 + End_Group + + Group = Archive + DataSetId = MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0 + ProductId = AB-1-024/01 + ProducerId = MGS_MOC_TEAM + ProductCreationTime = 1999-01-15T20:40:59 + SoftwareName = "makepds 1.3" + UploadId = moc_p024_v1.sasf + ImageNumber = 7293-024/01 + ImageKeyId = 56181-024/01 + End_Group + + Group = BandBin + FilterName = RED + OriginalBand = 1 + Center = 0.6134 + Width = 5.0e-02 + End_Group + + Group = Kernels + NaifFrameCode = -94032 + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = Table + Instrument = $mgs/kernels/ik/moc20.ti + SpacecraftClock = $mgs/kernels/sclk/MGS_SCLKSCET.00060.tsc + Frame = Null + InstrumentAddendum = $mgs/kernels/iak/mocAddendum002.ti + InstrumentPointing = Table + InstrumentPosition = Table + ShapeModel = Null + End_Group + + Group = Radiometry + CalibrationKernel = /usgs/cpkgs/isis3/data/mgs/calibration/moccal.ker.001 + CoefficientFile = $MGS/calibration/mocRedWA.coef + + /* Radiometric equation in moccal + /* r = (pixel - z + off) / a - g / ex - dc + a = 16.03 + off = 25.0 + ex = 100.0 + z = 27.67658 + dc = 1.33691e-03 + g = 0.123262 + + /* Reflectance = r * iof, where iof = (s * s) / w0 + w0 = 3.991 + s = 1.4234269469347 + iof = 0.50767834459028 + End_Group + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679821639 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.76690271209 + MaximumLatitude = 34.444196777763 + MinimumLongitude = 219.72404560653 + MaximumLongitude = 236.18955082624 + UpperLeftCornerX = -480000.0 + UpperLeftCornerY = 2042000.0 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + End_Group + + Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 + End_Group +End_Object diff --git a/isis/src/base/apps/maplab/assets/dataFiles/maplabTruth12.txt b/isis/src/base/apps/maplab/assets/dataFiles/maplabTruth12.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d469e5ec3f6f43a10ec57f70daed7b8ebe4bfd9 --- /dev/null +++ b/isis/src/base/apps/maplab/assets/dataFiles/maplabTruth12.txt @@ -0,0 +1,121 @@ +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 + End_Group + + Group = Pixels + Type = Real + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 + End_Group + + Group = Archive + DataSetId = MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0 + ProductId = AB-1-024/01 + ProducerId = MGS_MOC_TEAM + ProductCreationTime = 1999-01-15T20:40:59 + SoftwareName = "makepds 1.3" + UploadId = moc_p024_v1.sasf + ImageNumber = 7293-024/01 + ImageKeyId = 56181-024/01 + End_Group + + Group = BandBin + FilterName = RED + OriginalBand = 1 + Center = 0.6134 + Width = 5.0e-02 + End_Group + + Group = Kernels + NaifFrameCode = -94032 + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = Table + Instrument = $mgs/kernels/ik/moc20.ti + SpacecraftClock = $mgs/kernels/sclk/MGS_SCLKSCET.00060.tsc + Frame = Null + InstrumentAddendum = $mgs/kernels/iak/mocAddendum002.ti + InstrumentPointing = Table + InstrumentPosition = Table + ShapeModel = Null + End_Group + + Group = Radiometry + CalibrationKernel = /usgs/cpkgs/isis3/data/mgs/calibration/moccal.ker.001 + CoefficientFile = $MGS/calibration/mocRedWA.coef + + /* Radiometric equation in moccal + /* r = (pixel - z + off) / a - g / ex - dc + a = 16.03 + off = 25.0 + ex = 100.0 + z = 27.67658 + dc = 1.33691e-03 + g = 0.123262 + + /* Reflectance = r * iof, where iof = (s * s) / w0 + w0 = 3.991 + s = 1.4234269469347 + iof = 0.50767834459028 + End_Group + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679821639 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.76690271209 + MaximumLatitude = 34.444196777763 + MinimumLongitude = 219.72404560653 + MaximumLongitude = 236.18955082624 + UpperLeftCornerX = -480000.00000057 + UpperLeftCornerY = 2042000.0 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + End_Group + + Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 + End_Group +End_Object diff --git a/isis/src/base/apps/maplab/assets/dataFiles/maplabTruth21.txt b/isis/src/base/apps/maplab/assets/dataFiles/maplabTruth21.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9bf0fd305be3cbd7d24d892920d6ee53be7a167 --- /dev/null +++ b/isis/src/base/apps/maplab/assets/dataFiles/maplabTruth21.txt @@ -0,0 +1,121 @@ +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 + End_Group + + Group = Pixels + Type = Real + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 + End_Group + + Group = Archive + DataSetId = MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0 + ProductId = AB-1-024/01 + ProducerId = MGS_MOC_TEAM + ProductCreationTime = 1999-01-15T20:40:59 + SoftwareName = "makepds 1.3" + UploadId = moc_p024_v1.sasf + ImageNumber = 7293-024/01 + ImageKeyId = 56181-024/01 + End_Group + + Group = BandBin + FilterName = RED + OriginalBand = 1 + Center = 0.6134 + Width = 5.0e-02 + End_Group + + Group = Kernels + NaifFrameCode = -94032 + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = Table + Instrument = $mgs/kernels/ik/moc20.ti + SpacecraftClock = $mgs/kernels/sclk/MGS_SCLKSCET.00060.tsc + Frame = Null + InstrumentAddendum = $mgs/kernels/iak/mocAddendum002.ti + InstrumentPointing = Table + InstrumentPosition = Table + ShapeModel = Null + End_Group + + Group = Radiometry + CalibrationKernel = /usgs/cpkgs/isis3/data/mgs/calibration/moccal.ker.001 + CoefficientFile = $MGS/calibration/mocRedWA.coef + + /* Radiometric equation in moccal + /* r = (pixel - z + off) / a - g / ex - dc + a = 16.03 + off = 25.0 + ex = 100.0 + z = 27.67658 + dc = 1.33691e-03 + g = 0.123262 + + /* Reflectance = r * iof, where iof = (s * s) / w0 + w0 = 3.991 + s = 1.4234269469347 + iof = 0.50767834459028 + End_Group + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679821639 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.76690271209 + MaximumLatitude = 34.444196777763 + MinimumLongitude = 219.72404560653 + MaximumLongitude = 236.18955082624 + UpperLeftCornerX = -87500.0 + UpperLeftCornerY = 22701.0 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + End_Group + + Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 + End_Group +End_Object diff --git a/isis/src/base/apps/maplab/assets/dataFiles/maplabTruth22.txt b/isis/src/base/apps/maplab/assets/dataFiles/maplabTruth22.txt new file mode 100644 index 0000000000000000000000000000000000000000..57aeb0a9be6a7fd6efb7dc98652b0fdbad48e14b --- /dev/null +++ b/isis/src/base/apps/maplab/assets/dataFiles/maplabTruth22.txt @@ -0,0 +1,121 @@ +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 + End_Group + + Group = Pixels + Type = Real + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 + End_Group + + Group = Archive + DataSetId = MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0 + ProductId = AB-1-024/01 + ProducerId = MGS_MOC_TEAM + ProductCreationTime = 1999-01-15T20:40:59 + SoftwareName = "makepds 1.3" + UploadId = moc_p024_v1.sasf + ImageNumber = 7293-024/01 + ImageKeyId = 56181-024/01 + End_Group + + Group = BandBin + FilterName = RED + OriginalBand = 1 + Center = 0.6134 + Width = 5.0e-02 + End_Group + + Group = Kernels + NaifFrameCode = -94032 + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = Table + Instrument = $mgs/kernels/ik/moc20.ti + SpacecraftClock = $mgs/kernels/sclk/MGS_SCLKSCET.00060.tsc + Frame = Null + InstrumentAddendum = $mgs/kernels/iak/mocAddendum002.ti + InstrumentPointing = Table + InstrumentPosition = Table + ShapeModel = Null + End_Group + + Group = Radiometry + CalibrationKernel = /usgs/cpkgs/isis3/data/mgs/calibration/moccal.ker.001 + CoefficientFile = $MGS/calibration/mocRedWA.coef + + /* Radiometric equation in moccal + /* r = (pixel - z + off) / a - g / ex - dc + a = 16.03 + off = 25.0 + ex = 100.0 + z = 27.67658 + dc = 1.33691e-03 + g = 0.123262 + + /* Reflectance = r * iof, where iof = (s * s) / w0 + w0 = 3.991 + s = 1.4234269469347 + iof = 0.50767834459028 + End_Group + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679821639 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.76690271209 + MaximumLatitude = 34.444196777763 + MinimumLongitude = 219.72404560653 + MaximumLongitude = 236.18955082624 + UpperLeftCornerX = -11051573.293228 + UpperLeftCornerY = 363329.51075901 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + End_Group + + Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 + End_Group +End_Object diff --git a/isis/src/base/apps/maplab/assets/dataFiles/origLabel1.txt b/isis/src/base/apps/maplab/assets/dataFiles/origLabel1.txt new file mode 100644 index 0000000000000000000000000000000000000000..e13686d867ee882a8da141cca3830a7e40f96f7d --- /dev/null +++ b/isis/src/base/apps/maplab/assets/dataFiles/origLabel1.txt @@ -0,0 +1,101 @@ +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 + End_Group + + Group = Pixels + Type = Real + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 + End_Group + + Group = Archive + DataSetId = MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0 + ProductId = AB-1-024/01 + ProducerId = MGS_MOC_TEAM + ProductCreationTime = 1999-01-15T20:40:59 + SoftwareName = "makepds 1.3" + UploadId = moc_p024_v1.sasf + ImageNumber = 7293-024/01 + ImageKeyId = 56181-024/01 + End_Group + + Group = BandBin + FilterName = RED + OriginalBand = 1 + Center = 0.6134 + Width = 5.0e-02 + End_Group + + Group = Kernels + NaifFrameCode = -94032 + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = Table + Instrument = $mgs/kernels/ik/moc20.ti + SpacecraftClock = $mgs/kernels/sclk/MGS_SCLKSCET.00060.tsc + Frame = Null + InstrumentAddendum = $mgs/kernels/iak/mocAddendum002.ti + InstrumentPointing = Table + InstrumentPosition = Table + ShapeModel = Null + End_Group + + Group = Radiometry + CalibrationKernel = /usgs/cpkgs/isis3/data/mgs/calibration/moccal.ker.001 + CoefficientFile = $MGS/calibration/mocRedWA.coef + + /* Radiometric equation in moccal + /* r = (pixel - z + off) / a - g / ex - dc + a = 16.03 + off = 25.0 + ex = 100.0 + z = 27.67658 + dc = 1.33691e-03 + g = 0.123262 + + /* Reflectance = r * iof, where iof = (s * s) / w0 + w0 = 3.991 + s = 1.4234269469347 + iof = 0.50767834459028 + End_Group + + Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 + End_Group +End_Object diff --git a/isis/src/base/apps/maplab/assets/dataFiles/origLabel2.txt b/isis/src/base/apps/maplab/assets/dataFiles/origLabel2.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d469e5ec3f6f43a10ec57f70daed7b8ebe4bfd9 --- /dev/null +++ b/isis/src/base/apps/maplab/assets/dataFiles/origLabel2.txt @@ -0,0 +1,121 @@ +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 + End_Group + + Group = Pixels + Type = Real + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 + End_Group + + Group = Archive + DataSetId = MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0 + ProductId = AB-1-024/01 + ProducerId = MGS_MOC_TEAM + ProductCreationTime = 1999-01-15T20:40:59 + SoftwareName = "makepds 1.3" + UploadId = moc_p024_v1.sasf + ImageNumber = 7293-024/01 + ImageKeyId = 56181-024/01 + End_Group + + Group = BandBin + FilterName = RED + OriginalBand = 1 + Center = 0.6134 + Width = 5.0e-02 + End_Group + + Group = Kernels + NaifFrameCode = -94032 + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = Table + Instrument = $mgs/kernels/ik/moc20.ti + SpacecraftClock = $mgs/kernels/sclk/MGS_SCLKSCET.00060.tsc + Frame = Null + InstrumentAddendum = $mgs/kernels/iak/mocAddendum002.ti + InstrumentPointing = Table + InstrumentPosition = Table + ShapeModel = Null + End_Group + + Group = Radiometry + CalibrationKernel = /usgs/cpkgs/isis3/data/mgs/calibration/moccal.ker.001 + CoefficientFile = $MGS/calibration/mocRedWA.coef + + /* Radiometric equation in moccal + /* r = (pixel - z + off) / a - g / ex - dc + a = 16.03 + off = 25.0 + ex = 100.0 + z = 27.67658 + dc = 1.33691e-03 + g = 0.123262 + + /* Reflectance = r * iof, where iof = (s * s) / w0 + w0 = 3.991 + s = 1.4234269469347 + iof = 0.50767834459028 + End_Group + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679821639 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.76690271209 + MaximumLatitude = 34.444196777763 + MinimumLongitude = 219.72404560653 + MaximumLongitude = 236.18955082624 + UpperLeftCornerX = -480000.00000057 + UpperLeftCornerY = 2042000.0 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + End_Group + + Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 + End_Group +End_Object diff --git a/isis/src/base/apps/maplab/assets/images/maplabEx11Gui.jpg b/isis/src/base/apps/maplab/assets/images/maplabEx11Gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e4aa4797e7299f9cb6ae38fffae2d3cb5fccc46c Binary files /dev/null and b/isis/src/base/apps/maplab/assets/images/maplabEx11Gui.jpg differ diff --git a/isis/src/base/apps/maplab/assets/images/maplabEx12Gui.jpg b/isis/src/base/apps/maplab/assets/images/maplabEx12Gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f05b97ec8562b05fffa78d8111e1501a2bec18c1 Binary files /dev/null and b/isis/src/base/apps/maplab/assets/images/maplabEx12Gui.jpg differ diff --git a/isis/src/base/apps/maplab/assets/images/maplabEx21Gui.jpg b/isis/src/base/apps/maplab/assets/images/maplabEx21Gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5227b341fe0c6a779dce956f0e7f1bab35cfe657 Binary files /dev/null and b/isis/src/base/apps/maplab/assets/images/maplabEx21Gui.jpg differ diff --git a/isis/src/base/apps/maplab/assets/images/maplabEx22Gui.jpg b/isis/src/base/apps/maplab/assets/images/maplabEx22Gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ec4c168d7ff2565727adc692beaa9ab13a322a1f Binary files /dev/null and b/isis/src/base/apps/maplab/assets/images/maplabEx22Gui.jpg differ diff --git a/isis/src/base/apps/maplab/assets/thumbs/maplabEx11Thumb.jpg b/isis/src/base/apps/maplab/assets/thumbs/maplabEx11Thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3b1ec2dc6b430b793249963732e089855dce919a Binary files /dev/null and b/isis/src/base/apps/maplab/assets/thumbs/maplabEx11Thumb.jpg differ diff --git a/isis/src/base/apps/maplab/assets/thumbs/maplabEx12Thumb.jpg b/isis/src/base/apps/maplab/assets/thumbs/maplabEx12Thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8d5a4c85fbe78d1374b5b3d58e1578fa10166b1d Binary files /dev/null and b/isis/src/base/apps/maplab/assets/thumbs/maplabEx12Thumb.jpg differ diff --git a/isis/src/base/apps/maplab/assets/thumbs/maplabEx21Thumb.jpg b/isis/src/base/apps/maplab/assets/thumbs/maplabEx21Thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e5d5e8688a304d3b779c9c521b3f88e1e2aeb696 Binary files /dev/null and b/isis/src/base/apps/maplab/assets/thumbs/maplabEx21Thumb.jpg differ diff --git a/isis/src/base/apps/maplab/assets/thumbs/maplabEx22Thumb.jpg b/isis/src/base/apps/maplab/assets/thumbs/maplabEx22Thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5209d70999e29bbed231d499f14c0eb17f00b941 Binary files /dev/null and b/isis/src/base/apps/maplab/assets/thumbs/maplabEx22Thumb.jpg differ diff --git a/isis/src/base/apps/maplab/maplab.cpp b/isis/src/base/apps/maplab/maplab.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dcaeb001c0341a7c2a97a105ce3aa3a48ab539bc --- /dev/null +++ b/isis/src/base/apps/maplab/maplab.cpp @@ -0,0 +1,153 @@ +#include "Isis.h" +#include +#include +#include +#include "Pvl.h" +#include "Cube.h" +#include "History.h" +#include "ProjectionFactory.h" + +using namespace Isis; +using namespace std; + +void IsisMain(){ + // Access input parameters (user interface) + UserInterface &ui = Application::GetUserInterface(); + + // Open the input cube + Cube cube; + cube.Open(ui.GetFilename("FROM"), "rw"); + + //Get the map projection file provided by the user + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &mapGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + // Error checking to ensure the map projection file provided contains + // information pertaining to a target, body radius, and longitude direction + if (!mapGrp.HasKeyword("TargetName")) { + string msg = "The given MAP [" + userMap.Name() + + "] does not have the TargetName keyword."; + throw iException::Message( iException::User, msg, _FILEINFO_ ); + } + else if (!mapGrp.HasKeyword("EquatorialRadius") || + !mapGrp.HasKeyword("PolarRadius")) { + string msg = "The given MAP [" + userMap.Name() + + "] does not have the EquatorialRadius and PolarRadius keywords."; + throw iException::Message( iException::User, msg, _FILEINFO_ ); + } + else if (!mapGrp.HasKeyword("LongitudeDomain")) { + string msg = "The given MAP [" + userMap.Name() + + "] does not have the LongitudeDomain keyword."; + throw iException::Message( iException::User, msg, _FILEINFO_ ); + } + + //Read in line and sample inputs + double line = ui.GetDouble("LINE"); + double samp = ui.GetDouble("SAMPLE"); + + // Get user entered option + string option = ui.GetString("COORDINATES"); + + //Given x,y coordinates + if(option=="XY") { + //find values for x and y at the origin (upperleftcorner) + double x = ui.GetDouble("X"); + double y = ui.GetDouble("Y"); + //Get Resolution and Scale + double res = 0.0; + double scale = 0.0; + Projection *proj = ProjectionFactory::Create(userMap,false); + if( mapGrp.HasKeyword("PixelResolution") ) { + double localRadius = proj->LocalRadius( proj->TrueScaleLatitude() ); + res = mapGrp.FindKeyword("PixelResolution"); + scale = (2.0 * Isis::PI * localRadius) / (360.0 * res); + } + else if( mapGrp.HasKeyword("Scale") ) { + double localRadius = proj->LocalRadius( proj->TrueScaleLatitude() ); + scale = mapGrp.FindKeyword("Scale"); + res = (2.0 * Isis::PI * localRadius) / (360.0 * scale); + } + else { + string msg = "The given MAP [" + userMap.Name() + + "] does not have the PixelResolution or Scale keywords."; + throw iException::Message( iException::User, msg, _FILEINFO_ ); + } + x = x - res*(samp - 0.5); + y = y + res*(line - 0.5); + //add origen values to Mapping Group + mapGrp.AddKeyword(PvlKeyword("UpperLeftCornerX",x,"meters"), Pvl::Replace); + mapGrp.AddKeyword(PvlKeyword("UpperLeftCornerY",y,"meters"), Pvl::Replace); + if( not mapGrp.HasKeyword("PixelResolution") ) { + mapGrp.AddKeyword(PvlKeyword("PixelResolution",res,"meters")); + } + if( not mapGrp.HasKeyword("Scale") ) { + mapGrp.AddKeyword(PvlKeyword("Scale",scale,"pixels/degree")); + } + } + //Given latitude,longitude coordinates + else { + //get lat and lon from user interface + double lat = ui.GetDouble("LAT"); + double lon = ui.GetDouble("LONG"); + //create projection using input map + Projection *proj = ProjectionFactory::Create(userMap,false); + // feed lat, lon into projection + proj->SetGround(lat,lon); + //find origen values for x and y + double x = proj->XCoord(); + double y = proj->YCoord(); + //Get Resolution and Scale + double res = 0.0; + double scale = 0.0; + if( mapGrp.HasKeyword("PixelResolution") ) { + double localRadius = proj->LocalRadius( proj->TrueScaleLatitude() ); + res = mapGrp.FindKeyword("PixelResolution"); + scale = (2.0 * Isis::PI * localRadius) / (360.0 * res); + } + else if( mapGrp.HasKeyword("Scale") ) { + double localRadius = proj->LocalRadius( proj->TrueScaleLatitude() ); + scale = mapGrp.FindKeyword("Scale"); + res = (2.0 * Isis::PI * localRadius) / (360.0 * scale); + } + else { + string msg = "The given MAP[" + userMap.Name() + + "] does not have the PixelResolution or Scale keywords."; + throw iException::Message( iException::User, msg, _FILEINFO_ ); + } + x = x - res*(samp - 0.5); + y = y + res*(line - 0.5); + //add origen values to Mapping Group + mapGrp.AddKeyword(PvlKeyword("UpperLeftCornerX",x,"meters"), Pvl::Replace); + mapGrp.AddKeyword(PvlKeyword("UpperLeftCornerY",y,"meters"), Pvl::Replace); + if( not mapGrp.HasKeyword("PixelResolution") ) { + mapGrp.AddKeyword(PvlKeyword("PixelResolution",res,"meters")); + } + if( not mapGrp.HasKeyword("Scale") ) { + mapGrp.AddKeyword(PvlKeyword("Scale",scale,"pixels/degree")); + } + } + // Output the mapping group used to the Gui session log + Application::GuiLog(userMap); + // Extract label from cube file + Pvl *label = cube.Label(); + PvlObject &o = label->FindObject("IsisCube"); + //Add Mapping Group to input cube + if (o.HasGroup("Mapping")){ + o.DeleteGroup("Mapping"); + } + o.AddGroup(mapGrp); + + //keep track of change to labels in history + History hist = History("IsisCube"); + try { + cube.Read(hist); + } + catch(iException &e) { + e.Clear(); + } + hist.AddEntry(); + cube.Write(hist); + + cube.Close(); +} diff --git a/isis/src/base/apps/maplab/maplab.xml b/isis/src/base/apps/maplab/maplab.xml new file mode 100644 index 0000000000000000000000000000000000000000..ac3beecb6bc7a2fd50e73cfe38e2bacce2299f19 --- /dev/null +++ b/isis/src/base/apps/maplab/maplab.xml @@ -0,0 +1,541 @@ + + + + + + Add "Mapping" group to the labels of a cube + + + +

    + The maplab application will take in a cube and a map file. The user will + then need to choose to enter either latitude/longitude or x/y coordinates + that correspond to a given sample/line. This application will then modify + the input cube's labels to include a Mapping Group with projection + information. +

    + +

    + The map file provided as input must contain information pertaining to a + target, body radius, and a longitude direction. In terms of keywords, this + means that all of the following must appear in the map file in order to + run this program: +

    + +
      +
    • TargetName
    • +
    • EquatorialRadius
    • +
    • PolarRadius
    • +
    • LongitudeDomain
    • +
    + +

    + It should also be noted that when selecting a sample and line for + relating coordinates to a pixel, that position (0.5, 0.5) is the + top-left corner of the top-left pixel in the image. By extension, (1.0, + 1.0) is the center of the top-left pixel, and (1.5, 1.5) is the + top-left corner of the pixel one sample to the right and one line down. +

    +
    + + + Import and Export + Map Projection + + + + + Original version + + + The input map will now use pixels/degree if no pixel resolution is found. + If neither are present, throws an error. Both PixelResolution and Scale + (pixels/degree) keywords will be in the output. + + + Added error checking to ensure that the provided map file has all the + necessary keywords for later processing, and enhanced documentation to + discuss necessary keywords and pixel coordinates. + + + + + + + cube + input + + Input file to be modified + + + The cube whose label will be appended to include Mapping Group + information. + + + *.cub + + + + + filename + input + + Input map + + + File containing mapping parameters. + + + *.map + + + + + + + double + Sample position in the cube + + Some sample position in the cube that will correspond to a known + x-coordinate or latitude. In ISIS, the furthest left part of the + first sample is defined as 0.5. + + + + double + Line position in the cube + + Some line position in the cube that will correspond to a known + y-coordinate or longitude. In ISIS, the top of the first line is + defined as 0.5. + + + + string + Options for coordinate systems + + A list of the different types of coordinates allowed by the + application. + + XY + + + + + + + double + Distance from projection to sample + + Distance from in meters from the projection origin to the given + sample value of the cube. + + + + double + Distance from projection to line + + Distance from in meters from the projection origin to the given + line value of the cube. + + + + double + Latitude + + Latitude for the given sample value of the cube. + + + + double + Longitude + + Longitude for the given line value of the cube. + + + + + + + + Mapping Group added with corresponding x/y coordinates + + This example shows the Mapping Group added to the labels using x and y + positions of the corresponding sample and line positions. XY is the + default for COORDINATES. + + + maplab from=../IN/inputCube.cub map=../IN/inputMap.map + sample=85.0 line=23.0 x=-395500.0 y=2019500.0 + + + Run the maplab application to add a new Mapping Group to the labels + using x/y coordinates. + + + + + Click here to see the original label + + For this example, the original label did not contain a Mapping + Group. + + + + Click here to see the new label in its entirety + + + After the command line is run, the label includes a Mapping Group. + +
     
    +Object = IsisCube ...
    +
    +  Group = Mapping
    +    ProjectionName     = Sinusoidal
    +    CenterLongitude    = 227.95679821639
    +    TargetName         = Mars
    +    EquatorialRadius   = 3396190.0 <meters>
    +    PolarRadius        = 3376200.0 <meters>
    +    LatitudeType       = Planetocentric
    +    LongitudeDirection = PositiveEast
    +    LongitudeDomain    = 360
    +    MinimumLatitude    = 10.76690271209
    +    MaximumLatitude    = 34.444196777763
    +    MinimumLongitude   = 219.72404560653
    +    MaximumLongitude   = 236.18955082624
    +    UpperLeftCornerX   = -480000.0 <meters>
    +    UpperLeftCornerY   = 2042000.0 <meters>
    +    PixelResolution    = 1000.0 <meters/pixel>
    +    Scale              = 59.274697523306 <pixels/degree>
    +    TrueScaleLatitude  = 0.0
    +  End_Group
    +  ...
    +End_Object
    +            
    +
    +
    +
    + + + + Example Gui + + Screenshot of GUI with parameters filled in to perform the maplab + application. Input files, SAMPLE, and LINE are always required. + The radio button XY is chosen to input x and y input values that + correspond to the given sample and line values, respectively. + + + + + +
    + + Mapping Group added with corresponding latitude/longitude + + This example shows the Mapping Group added to the labels using the + latitude and longitude corresponding to the sample and line. XY is the + default for COORDINATES. + + + maplab from=../IN/inputCube.cub map=../IN/inputMap.map + sample=85.0 line=23.0 coordinates=latlong lat=34.070186510964 + long=219.90185944016 + + + Run the maplab application to add a new Mapping Group to the labels + using latitude/longitude coordinates. + + + + + Click here to see the original label + + For this example, the original label did not contain a Mapping + Group. + + + + Click here to see new label in its entirety + + + After the command line is run, the label includes a Mapping Group. + +
     
    +Object = IsisCube 
    +  ...
    +  Group = Mapping
    +    ProjectionName     = Sinusoidal
    +    CenterLongitude    = 227.95679821639
    +    TargetName         = Mars
    +    EquatorialRadius   = 3396190.0 <meters>
    +    PolarRadius        = 3376200.0 <meters>
    +    LatitudeType       = Planetocentric
    +    LongitudeDirection = PositiveEast
    +    LongitudeDomain    = 360
    +    MinimumLatitude    = 10.76690271209
    +    MaximumLatitude    = 34.444196777763
    +    MinimumLongitude   = 219.72404560653
    +    MaximumLongitude   = 236.18955082624
    +    UpperLeftCornerX   = -480000.00000057 <meters>
    +    UpperLeftCornerY   = 2042000.0 <meters>
    +    PixelResolution    = 1000.0 <meters/pixel>
    +    Scale              = 59.274697523306 <pixels/degree>
    +    TrueScaleLatitude  = 0.0
    +  End_Group
    +  ...
    +End_Object
    +            
    +
    +
    +
    + + + + Example Gui + + Screenshot of GUI with parameters filled in to perform the maplab + application. Input files, SAMPLE, and LINE are always required. + The radio button LATLONG is chosen to input latitude and longitude + input values that correspond to the given sample and line values, + respectively. + + + + + +
    + + Mapping Group revised with x/y coordinates + + This example shows the original Mapping Group replaced with new values + for UpperLeftCornerX and UpperLeftCornerY after maplab application is + run using the x/y coordinates of the sample and line. XY is the default for COORDINATES. + + + maplab from=../IN/inputCube.cub map=../IN/inputMap.map + sample=85.0 line=23.0 x=-3000.0 y=201.0 + + + Run the maplab application to revise the existing Mapping Group in the + labels using x/y coordinates. + + + + + Click here to see the original label + + + For this example, the original label already contained a Mapping + Group. + +
    +Object = IsisCube 
    +  ...
    +  Group = Mapping
    +    ProjectionName     = Sinusoidal
    +    CenterLongitude    = 227.95679821639
    +    TargetName         = Mars
    +    EquatorialRadius   = 3396190.0 <meters>
    +    PolarRadius        = 3376200.0 <meters>
    +    LatitudeType       = Planetocentric
    +    LongitudeDirection = PositiveEast
    +    LongitudeDomain    = 360
    +    MinimumLatitude    = 10.76690271209
    +    MaximumLatitude    = 34.444196777763
    +    MinimumLongitude   = 219.72404560653
    +    MaximumLongitude   = 236.18955082624
    +    UpperLeftCornerX   = -480000.00000057 <meters>
    +    UpperLeftCornerY   = 2042000.0 <meters>
    +    PixelResolution    = 1000.0 <meters/pixel>
    +    Scale              = 59.274697523306 <pixels/degree>
    +    TrueScaleLatitude  = 0.0
    +  End_Group
    +  ...
    +End_Object
    +            
    +
    +
    + + Click here to see new label in its entirety + + + After the command line is run, the original Mapping Group is + revised. + +
     
    +Object = IsisCube ...
    +
    +  Group = Mapping
    +    ProjectionName     = Sinusoidal
    +    CenterLongitude    = 227.95679821639
    +    TargetName         = Mars
    +    EquatorialRadius   = 3396190.0 <meters>
    +    PolarRadius        = 3376200.0 <meters>
    +    LatitudeType       = Planetocentric
    +    LongitudeDirection = PositiveEast
    +    LongitudeDomain    = 360
    +    MinimumLatitude    = 10.76690271209
    +    MaximumLatitude    = 34.444196777763
    +    MinimumLongitude   = 219.72404560653
    +    MaximumLongitude   = 236.18955082624 
    +    UpperLeftCornerX   = -87500.0 <meters>
    +    UpperLeftCornerY   = 22701.0 <meters>
    +    PixelResolution    = 1000.0 <meters/pixel>
    +    Scale              = 59.274697523306 <pixels/degree>
    +    TrueScaleLatitude  = 0.0
    +  End_Group
    +  ...
    +End_Object
    +            
    +
    +
    +
    + + + + Example Gui + + Screenshot of GUI with parameters filled in to perform the maplab + application. Input files, SAMPLE, and LINE are always required. + The radio button XY is chosen to input x and y input values that + correspond to the given sample and line values, respectively. + + + + + +
    + + Mapping Group revised with known latitude/longitude + + This example shows the original Mapping Group replaced with new values + for UpperLeftCornerX and UpperLeftCornerY after maplab application is + run using the latitude and longitude of the sample and line. XY is the default for COORDINATES. + + + maplab from=../IN/inputCube.cub map=../IN/inputMap.map + sample=85.0 line=23.0 coordinates=latlong lat=5.75 long=42.0 + + + Run the maplab application to replace the existing Mapping Group in the labels using latitude/longitude coordinates. + + + + + Click here to see original label in its entirety + + + For this example, the original label already contained a mapping + group. + +
    +Object = IsisCube 
    +  ...
    +  Group = Mapping
    +    ProjectionName     = Sinusoidal
    +    CenterLongitude    = 227.95679821639
    +    TargetName         = Mars
    +    EquatorialRadius   = 3396190.0 <meters>
    +    PolarRadius        = 3376200.0 <meters>
    +    LatitudeType       = Planetocentric
    +    LongitudeDirection = PositiveEast
    +    LongitudeDomain    = 360
    +    MinimumLatitude    = 10.76690271209
    +    MaximumLatitude    = 34.444196777763
    +    MinimumLongitude   = 219.72404560653
    +    MaximumLongitude   = 236.18955082624
    +    UpperLeftCornerX   = -480000.00000057 <meters>
    +    UpperLeftCornerY   = 2042000.0 <meters>
    +    PixelResolution    = 1000.0 <meters/pixel>
    +    Scale              = 59.274697523306 <pixels/degree>
    +    TrueScaleLatitude  = 0.0
    +  End_Group
    +  ...
    +End_Object
    +            
    +
    +
    + + Click here to see new label in its entirety + + + After the command line is run, the original Mapping Group is + replaced with the new one that contains updated keyword values. + +
     
    +Object = IsisCube 
    +  ...
    +  Group = Mapping
    +    ProjectionName     = Sinusoidal
    +    CenterLongitude    = 227.95679821639
    +    TargetName         = Mars
    +    EquatorialRadius   = 3396190.0 <meters>
    +    PolarRadius        = 3376200.0 <meters>
    +    LatitudeType       = Planetocentric
    +    LongitudeDirection = PositiveEast
    +    LongitudeDomain    = 360
    +    MinimumLatitude    = 10.76690271209
    +    MaximumLatitude    = 34.444196777763
    +    MinimumLongitude   = 219.72404560653
    +    MaximumLongitude   = 236.18955082624 
    +    UpperLeftCornerX   = -11051573.293228 <meters>
    +    UpperLeftCornerY   = 363329.51075901 <meters> 
    +    PixelResolution    = 1000.0 <meters/pixel>
    +    Scale              = 59.274697523306 <pixels/degree>
    +    TrueScaleLatitude  = 0.0
    +  End_Group
    +  ...
    +End_Object
    +            
    +
    +
    +
    + + + + Example Gui + + Screenshot of GUI with parameters filled in to perform the maplab + application. Input files, SAMPLE, and LINE are always required. + The radio button LATLONG is chosen to input latitude and longitude + input values that correspond to the given sample and line values, + respectively. + + + + + +
    +
    +
    diff --git a/isis/src/base/apps/maplab/tsts/Makefile b/isis/src/base/apps/maplab/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/maplab/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/maplab/tsts/case01/Makefile b/isis/src/base/apps/maplab/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..27712249c665b94377d8c8f7fdb36558fd735446 --- /dev/null +++ b/isis/src/base/apps/maplab/tsts/case01/Makefile @@ -0,0 +1,27 @@ +APPNAME = maplab + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/maplabInput.cub $(OUTPUT)/maplabOutput11.cub + catlab from=$(OUTPUT)/maplabOutput11.cub >& $(OUTPUT)/tempLab.txt; + head -n 101 $(OUTPUT)/tempLab.txt > $(OUTPUT)/origLabel1.txt; + $(APPNAME) from= $(OUTPUT)/maplabOutput11.cub \ + map = $(INPUT)/mapFile.map \ + x = -395500.0 \ + y = 2019500.0 \ + line = 23.0 \ + sample = 85.0; + catlab from=$(OUTPUT)/maplabOutput11.cub >& $(OUTPUT)/tempLab.txt; + head -n 121 $(OUTPUT)/tempLab.txt > $(OUTPUT)/maplabTruth11.txt; + cp $(INPUT)/maplabInput.cub $(OUTPUT)/maplabOutput12.cub + $(APPNAME) from= $(OUTPUT)/maplabOutput12.cub \ + map = $(INPUT)/mapFile.map \ + coor = latlon \ + lat = 34.070186510964 \ + lon = 219.90185944016 \ + line = 23.0 \ + sample = 85.0 ; + catlab from=$(OUTPUT)/maplabOutput12.cub >& $(OUTPUT)/tempLab.txt; + head -n 121 $(OUTPUT)/tempLab.txt > $(OUTPUT)/maplabTruth12.txt; + rm $(OUTPUT)/tempLab.txt diff --git a/isis/src/base/apps/maplab/tsts/case02/Makefile b/isis/src/base/apps/maplab/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b6ba26ca453385bb41a421860b019dd3046cbac --- /dev/null +++ b/isis/src/base/apps/maplab/tsts/case02/Makefile @@ -0,0 +1,27 @@ +APPNAME = maplab + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/maplabInput2.cub $(OUTPUT)/maplabOutput21.cub + catlab from=$(OUTPUT)/maplabOutput21.cub >& $(OUTPUT)/tempLab.txt; + head -n 121 $(OUTPUT)/tempLab.txt > $(OUTPUT)/origLabel2.txt; + $(APPNAME) from= $(OUTPUT)/maplabOutput21.cub \ + map = $(INPUT)/mapFile.map \ + x = -3000.0 \ + y = 201.0 \ + line = 23.0 \ + sample = 85.0 ; + catlab from=$(OUTPUT)/maplabOutput21.cub >& $(OUTPUT)/tempLab.txt; + head -n 121 $(OUTPUT)/tempLab.txt > $(OUTPUT)/maplabTruth21.txt; + cp $(INPUT)/maplabInput2.cub $(OUTPUT)/maplabOutput22.cub + $(APPNAME) from= $(OUTPUT)/maplabOutput22.cub \ + map = $(INPUT)/mapFile.map \ + c = latlon \ + lat = 5.75 \ + lon = 42.0 \ + line = 23.0 \ + sample = 85.0; + catlab from=$(OUTPUT)/maplabOutput22.cub >& $(OUTPUT)/tempLab.txt; + head -n 121 $(OUTPUT)/tempLab.txt > $(OUTPUT)/maplabTruth22.txt; + rm $(OUTPUT)/tempLab.txt diff --git a/isis/src/base/apps/maplab/tsts/case03/Makefile b/isis/src/base/apps/maplab/tsts/case03/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ec5d04cb09a398dda70b1e9658f500c6ac526839 --- /dev/null +++ b/isis/src/base/apps/maplab/tsts/case03/Makefile @@ -0,0 +1,27 @@ +APPNAME = maplab + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/maplabInput3.cub $(OUTPUT)/maplabOutput31.cub + catlab from=$(OUTPUT)/maplabOutput31.cub >& $(OUTPUT)/tempLab.txt; + head -n 121 $(OUTPUT)/tempLab.txt > $(OUTPUT)/origLabel3.txt; + $(APPNAME) from= $(OUTPUT)/maplabOutput31.cub \ + map = $(INPUT)/mapFile.map \ + x = -3000.0 \ + y = 201.0 \ + line = 23.0 \ + sample = 85.0 ; + catlab from=$(OUTPUT)/maplabOutput31.cub >& $(OUTPUT)/tempLab.txt; + head -n 121 $(OUTPUT)/tempLab.txt > $(OUTPUT)/maplabTruth31.txt; + cp $(INPUT)/maplabInput3.cub $(OUTPUT)/maplabOutput32.cub + $(APPNAME) from= $(OUTPUT)/maplabOutput32.cub \ + map = $(INPUT)/mapFile.map \ + c = latlon \ + lat = 5.75 \ + lon = 42.0 \ + line = 23.0 \ + sample = 85.0; + catlab from=$(OUTPUT)/maplabOutput32.cub >& $(OUTPUT)/tempLab.txt; + head -n 121 $(OUTPUT)/tempLab.txt > $(OUTPUT)/maplabTruth32.txt; + rm $(OUTPUT)/tempLab.txt diff --git a/isis/src/base/apps/mapmos/Makefile b/isis/src/base/apps/mapmos/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/mapmos/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/mapmos/assets/Band.jpg b/isis/src/base/apps/mapmos/assets/Band.jpg new file mode 100644 index 0000000000000000000000000000000000000000..00da9784ff43cdb28283db1c7333e7cb2e505e78 Binary files /dev/null and b/isis/src/base/apps/mapmos/assets/Band.jpg differ diff --git a/isis/src/base/apps/mapmos/assets/Beneath.jpg b/isis/src/base/apps/mapmos/assets/Beneath.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db11367d8666e07383f180238c34c75cfaf01705 Binary files /dev/null and b/isis/src/base/apps/mapmos/assets/Beneath.jpg differ diff --git a/isis/src/base/apps/mapmos/assets/OnTop.jpg b/isis/src/base/apps/mapmos/assets/OnTop.jpg new file mode 100644 index 0000000000000000000000000000000000000000..24546949941162d28d3e241b39c88cecacc843d6 Binary files /dev/null and b/isis/src/base/apps/mapmos/assets/OnTop.jpg differ diff --git a/isis/src/base/apps/mapmos/mapmos.cpp b/isis/src/base/apps/mapmos/mapmos.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe30bb25b9329fe30922e3ef90a66ed573af8639 --- /dev/null +++ b/isis/src/base/apps/mapmos/mapmos.cpp @@ -0,0 +1,107 @@ +#include "Isis.h" +#include "ProcessMapMosaic.h" +#include "PvlGroup.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + // Get the user interface + UserInterface &ui = Application::GetUserInterface(); + + ProcessMapMosaic m; + + // Get the MatchBandBin Flag + m.SetBandBinMatch(ui.GetBoolean("MATCHBANDBIN")); + + // Get the track flag + bool bTrack = ui.GetBoolean("TRACK"); + m.SetTrackFlag(bTrack); + + // Get the output projection set up properly + if (ui.GetBoolean("CREATE")) { + Cube inCube; + inCube.Open(ui.GetFilename("FROM")); + + // Set the create flag + m.SetCreateFlag(true); + + // Use the input projection as a starting point for the mosaic + PvlGroup mapGroup = inCube.Label()->FindGroup("Mapping", Pvl::Traverse); + inCube.Close(); + + mapGroup.AddKeyword(PvlKeyword("MinimumLatitude", ui.GetDouble("MINLAT")), Pvl::Replace); + mapGroup.AddKeyword(PvlKeyword("MaximumLatitude", ui.GetDouble("MAXLAT")), Pvl::Replace); + mapGroup.AddKeyword(PvlKeyword("MinimumLongitude", ui.GetDouble("MINLON")), Pvl::Replace); + mapGroup.AddKeyword(PvlKeyword("MaximumLongitude", ui.GetDouble("MAXLON")), Pvl::Replace); + + CubeAttributeOutput oAtt = ui.GetOutputAttribute("MOSAIC"); + + m.SetOutputCube(ui.GetFilename("FROM"), mapGroup, oAtt, ui.GetFilename("MOSAIC")); + } + else { + m.SetOutputCube(ui.GetFilename("MOSAIC")); + } + + // Set up the mosaic priority, either the input cube will be + // placed ontop of the mosaic or beneath it + MosaicPriority priority; + string sType; + if (ui.GetString("PRIORITY") == "BENEATH") { + priority = mosaic; + } + else if (ui.GetString("PRIORITY") == "ONTOP") { + priority = input; + } + else { + priority = band; + sType = ui.GetString("TYPE"); + if (sType=="BANDNUMBER") { + m.SetBandNumber(ui.GetInteger("NUMBER")); + } + else { + // Key Name & Value + m.SetBandKeyWord(ui.GetString("KEYNAME"), ui.GetString("KEYVALUE")); + } + // Band Criteria + BandCriteria eCriteria = Lesser; + if (ui.GetString("CRITERIA") == "GREATER") + eCriteria = Greater; + m.SetBandCriteria(eCriteria); + } + + // Set priority + m.SetPriority(priority); + + if (priority == input || priority == band) { + m.SetHighSaturationFlag(ui.GetBoolean("HIGHSATURATION")); + m.SetLowSaturationFlag (ui.GetBoolean("LOWSATURATION")); + m.SetNullFlag(ui.GetBoolean("NULL")); + } + + // Start Process + if(!m.StartProcess(ui.GetFilename("FROM"))) { + // Logs the cube if it falls outside of the given mosaic + PvlGroup outsiders("Outside"); + outsiders += PvlKeyword("File", ui.GetFilename("FROM")); + Application::Log(outsiders); + } + else { + // Logs the input file location in the mosaic + PvlGroup imgPosition("ImageLocation"); + int iStartLine = m.GetInputStartLine(); + int iStartSample = m.GetInputStartSample(); + imgPosition += PvlKeyword("File", ui.GetFilename("FROM")); + imgPosition += PvlKeyword("StartSample", iStartSample); + imgPosition += PvlKeyword("StartLine", iStartLine); + Application::Log(imgPosition); + } + + if (bTrack != m.GetTrackFlag()) { + ui.Clear("TRACK"); + ui.PutBoolean("TRACK", m.GetTrackFlag()); + } + + m.EndProcess(); +} + diff --git a/isis/src/base/apps/mapmos/mapmos.xml b/isis/src/base/apps/mapmos/mapmos.xml new file mode 100644 index 0000000000000000000000000000000000000000..d29fb25640bb6fb4b784dffe35084b2d066cd9f1 --- /dev/null +++ b/isis/src/base/apps/mapmos/mapmos.xml @@ -0,0 +1,516 @@ + + + + + Create a mosaic using map projected cubes + + + + +

    + This program allows the user to create a mosaic using map projected cubes. An individual cube can be placed in a pre-existing mosaic. + An option exists to create the mosaic by allowing the user to specify the latitude/longitude range for the output mosaic. + Note that the input cube and mosaic must have the same ProjectionName, PixelResolution, EquatorialRadius, PolarRadius, LatitudeType, + and LongitudeDirection as well as projection specific keywords (e.g., CenterLatitude, CenterLongitude). This application regardless of any + priority and flags set, will always place an input pixel on a NULL mosaic pixel. This application also has the ability to track the pixel origin. +

    +

    Tracking can be set at the time of Mosaic creation + only and cannot be turned on after the mosaic is created. But the tracking + will be turned off for multiband ONTOP and BENEATH priority even though it + was turned on while creating the mosaic. Tracking for multiband input with + ONTOP priority is possible only if all the Special Pixel Flags are set to + True else the Tracking will be turned off. ONTOP priority basically places + all the valid input pixels onto the mosaic unless the special pixel flags + are turned on or if mosaic has a NULL pixel. In a multi band scenario, a + pixel origin in particular line and sample will not be the same in all the + different bands, which means we have to keep track of every pixel in every + band. i.e. the size of the tracking bands will be the same as the number + of bands in the mosaic.i.e the number of bands will be doubled.

    +

    WARNING: If Tracking is turned on in a mosaic, any subsequent + applications that modify "dn" values will corrupt + the Tracking band. It may be necessary to remove + the Tracking band from the mosaic and then add it + back after all the processing is complete. See + "crop" and "cubeit". +

    +

    Priority BAND can track origin for multi band input image based on a + specified band using LESSER or GREATER than criteria. Each pixel in the + specified band is compared to the corresponding pixel in the chosen band + in the mosaic based on the chosen criteria. This comparison true or false + is used for all the other bands whether the input pixel is copied onto the + mosaic and hence the origin for that pixel is stored. Band can be chosen + by choosing the TYPE, BANDNUMBER or KEYWORD. If BANDNUMBER is chosen then + the band number can be entered in the NUMBER field. If KEYWORD is chosen + then PVL key name and value from the BANDBIN group can be entered in the + KEYNAME and KEYVALUE fields.

    +

    For example, for a multi band input with BAND priority, if the BAND + chosen is Emission Angle band(EMA), if input pixels are (30,30,30) in + EMA Band for some sample, line and the corresponding pixels in the EMA + band in the mosaic has (75, 75, 75) and the criteria is GREATER than, + then since input pixels are not GREATER than corresponding mosaic + pixels, then the input pixels are not copied to the mosaic, so also the + corresponding pixels in all the other bands in the input. Hence the + origin for those pixels remains unchanged. If LESSER than was the + criteria, then all the corresponding pixels in all the input bands will + be copied to the mosaic and the origin for those pixels is the current + input image. +

    +

    There are options like MATCHBANDIN, if set requires the specfied input + bands to match the mosaic bands and the bands can be anywhere in the + mosaic but must be contiguous for multi-band. If MATCHBANDIN is not set + then any input image can be placed on the mosaic within it's boundaries. +

    +

    Options HIGHSATURATION, LOWSATURATION and NULL if + set will cause the the input pixels with these values to be copied to the + mosaic for ONTOP and BAND priorities regardless of the CRITERIA for the + BAND priority. These options are not supported for BENEATH priority.

    +

    Currently Tracking can be viewed in the Advanced Tool Tracking option + of the qview application. Following are the Tracking info:

    +

    Index : Zero based and is in the order in which the image was + placed on the mosaic. No origin is represented as -1.

    +

    FileName: File name of input image

    +

    Serial Number:Serial Number of the input image

    +

    Following are the values for the origin band depending on the pixel type + + + + + +
    Pixel Type

    (bits)
    Default

    (No Origin)
    Start ValueMax ValueTotal Images

    Supported
    32-16777216-167772151677721633549932
    16-32768-3276732767 65535
    801255255
    +

    +

    Following is the table for Special Pixel options, input, mosaic + pixels and the resulting output for different priorities. +
    Tags: F(FALSE), T(TRUE), V(VALID), HS(HIGH SATURATION), LS(LOW SATURATION), + S(SPECIAL PIXEL HS, LS, NULL), N(NULL), I(INPUT), M(MOSAIC), HL(HS,LS) +
    +

    +
  • + + + + +
    Priority Beneath
    Priority Beneath + + + + +
    BENEATH
    InputMosaic Output
    S,VNI
    S,VHL,VM






    +
  • + + + + +
    Priority OnTop
    Priority OnTop + + + + + + + + +
    ONTOP
    OptionsImages
    HSLSNULLInputMosaicOutput
    F F FVS,VI
    F F F S HL,VM
    F F F S,V N I
    T OR T OR TV S,VI
    T OR T OR TSS,VI (H,L,N)
    +





    +
  • + + + + +
    Priority Band
    Priority Band + + + + + + + + + + +
    BAND
    OptionsImages
    HSLSNULLInputMosaicOutput
    F FF VVCriteria based
    F F FVS I
    F F F S HL,VM
    F F FS,VNI
    T OR T OR T S S,V I(H,L,N)
    T OR T ORT VVCriteria based
    T OR T OR T V SI
    +
    + + + + + Mosaicking + + + + + Original version + + + Converted to Isis 3.0 + + + Modified to not propagate input labels to the output mosaic + + + Fixed bug with mapping groups not properly initialized or copied + + + Added appTest + + + Depricated CubeProjection and ProjectionManager to ProjectionFactory + + + Added the MATCHBANDBIN option that checks to make sure the input + cube bandbin group matches the mosaic bandbin group. The default is true. + + + This program now utilizes ProcessMapMosaic + + + If the given cube falls outside the provided the mosaic, it will now be + logged. (Removed some unused header files.) + + + Changed the parameters SLAT, ELAT, SLON, ELON to MINLAT, MAXLAT, MINLON, + MAXLON in correlation with autimos. + + + Added option "TRACK" to track pixel origin. Also added new priority called + BAND where specified input and mosaic band is compared for moving input + to mosaic and to track the pixel origin. Added parameter "TYPE" to choose + Band "NUMBER" or PVL "KEYWORD" from the BandBin group. If "BANDNUMBER" is + chosen, then "NUMBER" is activated to enter band number. If "KEYWORD" + is chosen then parameter "KEYNAME" and "KEYVALUE" are activated to enter + key name and value from the BandBin group for band comparison. Band + comparison "CRITERIA" are "LESSER" or "GREATER" than. Also there are + options "HIGHSATURATION", "LOWSATURATION" and "NULL", set to true will + cause HS, LS and NULL input pixels to be copied to the mosaic regardless + of the priorities and criteria. These options are not supported for "BENEATH" priority. + + + + + mosaic + + + + + + cube + input + + Cube to place in the mosaic + + + This is the cube which will be placed into the mosaic. It must have a Mapping group which sufficiently matches the mosaic. + + + *.cub + + + + + cube + output + + Mosaic output cube + + + The mosaic cube which will have the input cube placed into it. + + + *.cub + + + + + string + + ONTOP + + The priority of pixel placement + + This parameter is used to select one of two ways to mosaic the + pixels in areas of overlap. + + + + + + + + + + + + string + + + BANDNUM + + + Indicate the Band name or number to be used for comparison + + The pixels in this band will be used for comparison between input + image and the mosaic for a decision to be made in copying image into + the mosaic. + + + + + + + + + integer + 1 + Enter the Band Number + The band number should match that in the + "OriginalBand" of "BandBin" Group + + + + string + OriginalBand + Enter the Key name as it appears in the PVL + The entered key name must match the key name in the + "BandBin" + + + + + string + 1 + Enter the value associated with the "KEYNAME" + This value must match the value associated with the key + name entered in the KEYNAME + + + + + string + LESSER + The criteria (Lesser or Greater) of pixel placement in a chosen band + + This parameter is used to select one of two ways to mosaic the + pixels in areas of overlap when doing by band comparison. + + + + + + + + + + + + boolean + + NO + + Create the output mosaic + + This parameter is used to specify if the mosaic needs to be created. + + + MINLAT + MAXLAT + MINLON + MAXLON + TRACK + + + + + boolean + FALSE + Track the mosaic origin + + If selected the application will track the mosaic origin. Once + origin is tracked, the tracker cannot be turned off. + + + + + double + -90.0 + Minimum Latitude + + This parameter specifies the minimum latitude to determine the bounding box of the mosaic + + + CREATE + + + + + double + 90.0 + Maximum Latitude + + This parameter specifies the maximum latitude to determine the bounding box of the mosaic + + + MINLAT + + + CREATE + + + + + double + Minimum Longitude + + This parameter specifies the minimum longitude to determine the bounding box of the mosaic + + + CREATE + + + + + double + Maximum Longitude + + This parameter specifies the maximum longitude to determine the bounding box of the mosaic + + + MINLON + + + CREATE + + + + + + + boolean + Enforce BandBin Group Match + + This option causes the application to fail if the input bandbin group does not + match the mosaic bandbin group. + + TRUE + + + boolean + FALSE + Copy Input HS (Instrument and Representation) values + + This option causes High Saturation values (both Instrument and + Representation) in the input image to be automatically copied to the + mosaic irrespective of the priority + + + + boolean + FALSE + Copy Input LS (Instrument and Representation) values + + This option causes Low Saturation values (both Instrument and + Representation) in the input image to be automatically copied to the + mosaic irrespective of the priority + + + + boolean + FALSE + Copy Input NULL values + + This option causes NULL values in the input image to be automatically + copied to the mosaic irrespective of the priority + + + + + diff --git a/isis/src/base/apps/mapmos/tsts/720deg/Makefile b/isis/src/base/apps/mapmos/tsts/720deg/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..277718cabeb401f88c8fe29d1e427ce5a36a7346 --- /dev/null +++ b/isis/src/base/apps/mapmos/tsts/720deg/Makefile @@ -0,0 +1,8 @@ +APPNAME = mapmos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/input.cub MOSAIC=$(OUTPUT)/mosaic.cub \ + CREATE=YES TRACK=YES MINLAT=-75 MAXLAT=-72 MINLON=0 MAXLON=720 \ + HIGHSATURATION=TRUE LOWSATURATION=TRUE NULL=TRUE > /dev/null; diff --git a/isis/src/base/apps/mapmos/tsts/Makefile b/isis/src/base/apps/mapmos/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/mapmos/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/mapmos/tsts/band/Makefile b/isis/src/base/apps/mapmos/tsts/band/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d4747977907d292b4380121cb6376b7016c1e695 --- /dev/null +++ b/isis/src/base/apps/mapmos/tsts/band/Makefile @@ -0,0 +1,21 @@ +APPNAME = mapmos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.lev2.cub \ + mosaic=$(OUTPUT)/mapmosTruth1.cub \ + create=true \ + track=true \ + priority=BAND \ + type=KEYWORD \ + keyname=FilterName \ + keyvalue=RED \ + criteria=LESSER \ + minlat=10.765 \ + maxlat=34.445 \ + minlon=219.720 \ + maxlon=236.190 \ + highsaturation=false \ + lowsaturation=false \ + null=false > /dev/null; diff --git a/isis/src/base/apps/mapmos/tsts/map/Makefile b/isis/src/base/apps/mapmos/tsts/map/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3af4ee2add073400362f3e2312e9867778604b07 --- /dev/null +++ b/isis/src/base/apps/mapmos/tsts/map/Makefile @@ -0,0 +1,28 @@ +APPNAME = mapmos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.lev2.cub \ + mosaic=$(OUTPUT)/mapmosTruth2.cub \ + create=true \ + track=true \ + match=false \ + minlat=10.765 \ + maxlat=34.445 \ + minlon=219.720 \ + maxlon=236.190 \ + highsaturation=true \ + lowsaturation=true \ + null=true > /dev/null; + + map2map from=$(INPUT)/ab102402.lev2.cub \ + map=$(INPUT)/ab102401.lev2.cub \ + to=$(OUTPUT)/map.cub \ + defaultrange=map \ + inter=near > /dev/null; + + $(APPNAME) from=$(OUTPUT)/map.cub \ + mosaic=$(OUTPUT)/mapmosTruth2.cub match=false > /dev/null; + + diff --git a/isis/src/base/apps/mapmos/tsts/params/Makefile b/isis/src/base/apps/mapmos/tsts/params/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c7ee11a18f8498994bb3f19efb46b3d9d5ba1135 --- /dev/null +++ b/isis/src/base/apps/mapmos/tsts/params/Makefile @@ -0,0 +1,16 @@ +APPNAME = mapmos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.lev2.cub \ + mosaic=$(OUTPUT)/mapmosTruth1.cub \ + create=true \ + track=true \ + minlat=10.765 \ + maxlat=34.445 \ + minlon=219.720 \ + maxlon=236.190 \ + highsaturation=true \ + lowsaturation=true \ + null=true > /dev/null; diff --git a/isis/src/base/apps/mappt/Makefile b/isis/src/base/apps/mappt/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/mappt/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/mappt/mappt.cpp b/isis/src/base/apps/mappt/mappt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ec93fe1a6ef0fd75ba6c750ce6795caaec53759 --- /dev/null +++ b/isis/src/base/apps/mappt/mappt.cpp @@ -0,0 +1,323 @@ +#define GUIHELPERS + +#include "Isis.h" + +#include +#include + +#include "Brick.h" +#include "Filename.h" +#include "iException.h" +#include "iString.h" +#include "Process.h" +#include "Projection.h" +#include "ProjectionFactory.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void PrintMap (); + +map GuiHelpers(){ + map helper; + helper ["PrintMap"] = (void*) PrintMap; + return helper; +} + +void IsisMain() { + // Use a regular Process + Process p; + + // Open the input cube and initialize the projection + Cube *icube = p.SetInputCube("FROM"); + Projection *proj = icube->Projection(); + + // Get the coordinate + UserInterface &ui = Application::GetUserInterface(); + + // Get the sample/line position if we have an image point + if (ui.GetString("TYPE") == "IMAGE") { + double samp = ui.GetDouble("SAMPLE"); + double line = ui.GetDouble("LINE"); + proj->SetWorld(samp,line); + } + + // Get the lat/lon position if we have a ground point + else if (ui.GetString("TYPE") == "GROUND") { + double lat = ui.GetDouble("LATITUDE"); + double lon = ui.GetDouble("LONGITUDE"); + + // Make sure we have a valid latitude value + if (fabs(lat) > 90.0) { + string msg = "Invalid value for LATITUDE [" + + iString(lat) + "] outside range of "; + msg += "[-90,90]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + iString coordsys = ui.GetString("COORDSYS"); + coordsys.UpCase(); + + // All of these ifs will finish by setting the ground in the projection, + // there are 4 options, Universal, InputFileSystem, Mapfile, and + // Userdefined. + + // Positive East, 0-360, Planetocentric + if (coordsys == "UNIVERSAL") { + proj->SetUniversalGround(lat, lon); + } + + // Use the coordinate system of the input file + else if (coordsys == "INPUTFILESYS") { + proj->SetGround(lat, lon); + } + + // Use the mapping group from a given file + else if (coordsys == "MAP") { + Filename mapFile = ui.GetFilename("MAP"); + + // Does it exist? + if (!mapFile.Exists()) { + string msg = "Filename ["+ ui.GetFilename("MAP") +"] does not exist"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + // Load it up into a new projection + Pvl mapPvl; + mapPvl.Read(mapFile.Expanded()); + Projection * altmap = ProjectionFactory::CreateFromCube(mapPvl); + + // Set lat and lon in its system + altmap->SetGround(lat, lon); + + // Set universal in input cube from universal from given + // mapping/projection + proj->SetUniversalGround( + altmap->UniversalLatitude(), altmap->UniversalLongitude()); + + // I think this is right, no cube owns it, and the factory doesn't. + delete altmap; + altmap = NULL; + } + + // User defined coordinate system, 8 possible combinations + // we only have to make changes for some of them. + // Convert from given system to universal and then set. + else if (coordsys == "USERDEFINED") { + double lat2 = lat; + double lon2 = lon; + + if (ui.GetString("LATTYPE") == "PLANETOGRAPHIC") { + lat2 = proj->ToPlanetocentric(lat); + } + + if (ui.GetString("LONDOM") == "180") { + lon2 = proj->To360Domain(lon); + } + + if (ui.GetString("LONDIR") == "POSITIVEWEST") { + // Use lon2, we know its already in 0-360 + lon2 = proj->ToPositiveEast(lon2, 360); + } + + proj->SetUniversalGround(lat2, lon2); + } + } + + // Get the x/y position if we have a projection point + else { + double x = ui.GetDouble("X"); + double y = ui.GetDouble("Y"); + proj->SetCoordinate(x,y); + } + + // Create Brick on samp, line to get the dn value of the pixel + Brick b(1,1,1,icube->PixelType()); + int intSamp = (int)(proj->WorldX()+0.5); + int intLine = (int)(proj->WorldY()+0.5); + b.SetBasePosition(intSamp,intLine,1); + icube->Read(b); + + // Log the position + if (proj->IsGood()) { + PvlGroup results("Results"); + results += PvlKeyword("Filename", + Filename(ui.GetFilename("FROM")).Expanded()); + results += PvlKeyword("Sample",proj->WorldX()); + results += PvlKeyword("Line",proj->WorldY()); + results += PvlKeyword("PixelValue",PixelToString(b[0])); + results += PvlKeyword("X",proj->XCoord()); + results += PvlKeyword("Y",proj->YCoord()); + + // Put together all the keywords for different coordinate systems. + PvlKeyword centLat = + PvlKeyword("PlanetocentricLatitude",proj->UniversalLatitude()); + + PvlKeyword graphLat = + PvlKeyword("PlanetographicLatitude", + proj->ToPlanetographic(proj->UniversalLatitude())); + + PvlKeyword pE360 = + PvlKeyword("PositiveEast360Longitude",proj->UniversalLongitude()); + + PvlKeyword pW360 = + PvlKeyword("PositiveWest360Longitude", + proj->ToPositiveWest(proj->UniversalLongitude(),360)); + + PvlKeyword pE180 = + PvlKeyword("PositiveEast180Longitude", + proj->To180Domain(proj->UniversalLongitude())); + + PvlKeyword pW180 = + PvlKeyword("PositiveWest180Longitude", + proj->To180Domain(proj->ToPositiveEast( + proj->UniversalLongitude(),360))); + + // Input map coordinate system location + // Latitude + if (proj->IsPlanetocentric()) { + centLat.AddComment("Input map coordinate system"); + results += centLat; + } + else { + graphLat.AddComment("Input map coordinate system"); + results += graphLat; + } + + // Longitude + if (proj->IsPositiveEast()) { + if (proj->Has360Domain()) { + results += pE360; + } + else { + results += pE180; + } + } + else { + if (proj->Has360Domain()) { + results += pW360; + } + else { + results += pW180; + } + } + + // Non input corrdinate system locations + // Latitude + if (proj->IsPlanetocentric()) { + graphLat.AddComment("Location in other coordinate systems"); + results += graphLat; + } + else { + centLat.AddComment("Location in other coordinate systems"); + results += centLat; + } + + // Longitude + if (proj->IsPositiveEast()) { + if (proj->Has360Domain()) { + results += pW360; + results += pE180; + results += pW180; + } + else { + results += pE360; + results += pW360; + results += pW180; + } + } + else { + if (proj->Has360Domain()) { + results += pE360; + results += pE180; + results += pW180; + } + else { + results += pE360; + results += pE180; + results += pW360; + } + } + + Application::Log(results); + + // Write an output label file if necessary + if (ui.WasEntered("TO")) { + // Get user params from ui + string outFile = Filename(ui.GetFilename("TO")).Expanded(); + bool exists = Filename(outFile).Exists(); + bool append = ui.GetBoolean("APPEND"); + + // Write the pvl group out to the file + if (ui.GetString("FORMAT") == "PVL") { + Pvl temp; + temp.AddGroup(results); + if (append) { + temp.Append(outFile); + } + else { + temp.Write(outFile); + } + } + + // Create a flatfile of the same data + // The flatfile is comma delimited and can be imported into Excel + else { + ofstream os; + bool writeHeader = false; + if (append) { + os.open(outFile.c_str(),ios::app); + if (!exists) { + writeHeader = true; + } + } + else { + os.open(outFile.c_str(),ios::out); + writeHeader = true; + } + + if(writeHeader) { + for(int i = 0; i < results.Keywords(); i++) { + os << results[i].Name(); + + if(i < results.Keywords()-1) { + os << ","; + } + } + os << endl; + } + + for(int i = 0; i < results.Keywords(); i++) { + os << (string)results[i]; + + if(i < results.Keywords()-1) { + os << ","; + } + } + os << endl; + } + } + else if(ui.GetString("FORMAT") == "FLAT") { + string msg = "Flat file must have a name."; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + } + else { + string msg = "Could not project requested position"; + throw iException::Message(iException::Projection,msg,_FILEINFO_); + } +} + +// Helper function to print out mapfile to session log +void PrintMap() { + UserInterface &ui = Application::GetUserInterface(); + + // Get mapping group from map file + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + //Write map file out to the log + Isis::Application::GuiLog(userGrp); +} diff --git a/isis/src/base/apps/mappt/mappt.xml b/isis/src/base/apps/mappt/mappt.xml new file mode 100644 index 0000000000000000000000000000000000000000..456fe0e473b1e019e18a775a6df0fdac015df077 --- /dev/null +++ b/isis/src/base/apps/mappt/mappt.xml @@ -0,0 +1,511 @@ + + + + + Outputs latitude/longitude at line/sample or reverse + + + + This program requires the user supply a cube in a map projection. + The user must also enter one of the following coordinates: +
    +      line/sample
    +      latitude/longitude
    +      x/y
    +    
    + The program will then compute the other two coordinates. For example, + entering a line/sample will cause the program to compute a latitude/longitude + and x/y. The output can be sent to a text file using the TO parameter and can + be read in a script via the "getkey" program. + + Example output: +
    +      Group = Results
    +        Filename                 = /home/mboyd/mapped.cub
    +        Sample                   = 400.0
    +        Line                     = 400.0
    +        PixelValue               = Null
    +        X                        = 36094.582198722
    +        Y                        = -2602604.7032335
    +
    +        # Input map coordinate system
    +        PlanetocentricLatitude   = -85.828401770565
    +        PositiveEast180Longitude = 26.807891885122
    +
    +        # Location in other coordinate systems
    +        PlanetographicLatitude   = -85.828401770565
    +        PositiveEast360Longitude = 26.807891885122
    +        PositiveWest360Longitude = 333.19210811488
    +        PositiveWest180Longitude = -26.807891885122
    +      End_Group
    +    
    +
    + + + Map Projection + + + + + Original version + + + Modified results pvl to not include the results group + + + Added application test + + + Changed name to mappt and made ui look like skypt and campt + + + Changed flatfile output so it duplicates PVL data. User now + required to entered a flatfile name. + + + Removed references to CubeInfo + + + Added pixel value to the output group + + + Modified output to include all coordinate systems for latitude and + longitude and clearly declare the input files coordinate system. Improved + documentation. + + + Added many parameters accesible when inputing a lat lon, all under + coordinate system. These parameters are to select the input coordinate + system being used. Updated documentation to match. + + + + + + + cube + input + + Filename of a cube + + + Input cube which must have a Mapping group in the labels. + + + *.cub + + + + + filename + output + Text file + None + + A text file which will contain the results of this program. This file can + be used in conjunction with the "getkey" program in order to pass + the results to another program when developing scripts if the PVL + format is selected. + + + + string + + Output Format + + + Format type for output file. Pvl format is default. + + PVL + + + + + + + + boolean + + Append Output to File + + + If this option is selected, the output from the application will be appended to the file. + If it is not selected, any information in the TO file will be overwritten. + + TRUE + + + + + + string + Coordinate selection + IMAGE + + + + + + + This parameter is used to select the type of coordinate which will be used to + compute the other two remaining coordinates. + + + + + double + + Sample Position + + + This is the sample position used to compute information about the camera state at the pixel. + + + + + double + + Line Position + + + This is the line position used to compute information about the camera state at the pixel. + + + + + double + + Latitude Value + + + This is the latitude value used to compute the other coordinate values. The latitude + will be interpreted as either Planetographic or Planetocentric + latitude depending on the option selected under coordinate system. + + + + + double + + Longitude value + + + This is the longitude value used to compute the other coordinate values. The longitude + will be interpreted as either PositiveEast or PositiveWest longitude + and -180 to 180 or 0 to 360 domain depending on the option selected + under coordinate system. + + + + + double + + X coordinate + + + This is the x coordinate value used to compute the other coordinate values. It + will be a projection X value in meters. + + + + + double + + Y coordinate + + + This is the y coordinate value used to compute the other coordinate values. It + will be a projection Y value in meters. + + + + + + + string + + The coordinate system of the input latitude and longitude. + + INPUTFILESYS + + This is the coordinate system the input latitude and longitude will be + interpreted in. There are eight possible options with the variation of + planetocentric or planetographic, positive east or west, 180 to -180 + range or 0 to 360. + + + + + + + + + + + + + + filename + input + + File containing mapping parameters + + + This file can be a cube or a simple hand produced map file. This file + must contain a maping group and is how the coordinate system will be + determined if selected. + + + + PrintMap + View MapFile + + This helper button will cat out the mapping group of the given mapfile to the session log + of the application + + $ISIS3DATA/base/icons/labels.png + + + + *.map *.cub + + + + + string + + Latitude type + + + The latitude type for the projection. It can either be Planetocentric or Planetographic. + PLANETOCENTRIC is the default. + + + PLANETOCENTRIC + + + + + + + + + string + + Longitude Direction + + + The longitude direction for the projection. It can have a direction of Positive East + or Positive West. POSITIVEEAST is the default. + + + POSITIVEEAST + + + + + + + + + string + + Longitude Domain + + + The longitude domain for the projection. It can either have a domain + of 180 or 360. 360 is the default. + + + 360 + + + + + + + + +
    diff --git a/isis/src/base/apps/mappt/tsts/Makefile b/isis/src/base/apps/mappt/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/mappt/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/mappt/tsts/coordsys/Makefile b/isis/src/base/apps/mappt/tsts/coordsys/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b6102915a76477108b06700568b6427a7c1614cc --- /dev/null +++ b/isis/src/base/apps/mappt/tsts/coordsys/Makefile @@ -0,0 +1,16 @@ +APPNAME = mappt + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/I00824006RDR.lev2.cub \ + to=$(OUTPUT)/mappt.pvl \ + append=false \ + type=ground \ + coordsys=userdefined \ + lattype=planetographic \ + londir=positivewest \ + londom=180 \ + latitude=-1.527843650235 \ + longitude=7.8016320748916 \ + > /dev/null; diff --git a/isis/src/base/apps/mappt/tsts/ground/Makefile b/isis/src/base/apps/mappt/tsts/ground/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c233de220cc041cd1a5c0967b48ba1bbeb63be8b --- /dev/null +++ b/isis/src/base/apps/mappt/tsts/ground/Makefile @@ -0,0 +1,11 @@ +APPNAME = mappt + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/I00824006RDR.lev2.cub \ + to=$(OUTPUT)/mappt2.pvl \ + append=false \ + type=ground \ + latitude=-1.7798488125312 \ + longitude=352.13074447388 > /dev/null; diff --git a/isis/src/base/apps/mappt/tsts/image/Makefile b/isis/src/base/apps/mappt/tsts/image/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b85a2b6999826bd11a44e93416a775b44b5849aa --- /dev/null +++ b/isis/src/base/apps/mappt/tsts/image/Makefile @@ -0,0 +1,10 @@ +APPNAME = mappt + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/I00824006RDR.lev2.cub \ + append=false \ + type=image \ + sample=41 \ + line=181 > $(OUTPUT)/mappt1.pvl; diff --git a/isis/src/base/apps/mappt/tsts/projection/Makefile b/isis/src/base/apps/mappt/tsts/projection/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4ba3c0fb2323eb66e418766c8ee77c9394971a7e --- /dev/null +++ b/isis/src/base/apps/mappt/tsts/projection/Makefile @@ -0,0 +1,11 @@ +APPNAME = mappt + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/I00824006RDR.lev2.cub \ + to=$(OUTPUT)/mappt3.pvl \ + append=false \ + type=projection \ + x=-51500 \ + y=-105500 > /dev/null; diff --git a/isis/src/base/apps/mapsize/Makefile b/isis/src/base/apps/mapsize/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/mapsize/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/mapsize/mapsize.cpp b/isis/src/base/apps/mapsize/mapsize.cpp new file mode 100644 index 0000000000000000000000000000000000000000..873abf3e08d6ba33cd99f6d40e11cff5687437f3 --- /dev/null +++ b/isis/src/base/apps/mapsize/mapsize.cpp @@ -0,0 +1,69 @@ +#include "Isis.h" +#include "Process.h" +#include "ProjectionFactory.h" +#include "Projection.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + Process p; + + // Get the output map projection file and create an output projection object + UserInterface &ui = Application::GetUserInterface(); + Pvl lab; + lab.Read(ui.GetFilename("MAP")); + + int samples,lines; + Projection *outmap = ProjectionFactory::CreateForCube(lab,samples,lines); + + // Obtain x/y min/max distances in meters + double xmin,xmax,ymin,ymax; + outmap->XYRange(xmin,xmax,ymin,ymax); + double xdist = xmax - xmin; + double ydist = ymax - ymin; + double scale, width, height; + double inchesPerMeter = 39.37; + + // See if the user specified inches or scale + if (ui.GetString("OPTION") == "SCALE") { + scale = ui.GetDouble("SCALE"); + width = xdist / scale * inchesPerMeter; + height = ydist / scale * inchesPerMeter; + } + else { + width = ui.GetDouble("WIDTH"); + height = ui.GetDouble("HEIGHT"); + double xscale = xdist / width * inchesPerMeter; + double yscale = ydist / height * inchesPerMeter; + scale = max(xscale,yscale); + // Recompute as one is likely to be reduced + width = xdist / scale * inchesPerMeter; + height = ydist / scale * inchesPerMeter; + } + + // Create a label and log it + PvlGroup results("Results"); + results += PvlKeyword("Map",ui.GetFilename("MAP")); + results += PvlKeyword("Scale",scale); + results += PvlKeyword("Width",width,"inches"); + results += PvlKeyword("Height",height,"inches"); + results += PvlKeyword("Samples",samples); + results += PvlKeyword("Lines",lines); + results += PvlKeyword("RealSize", ((Isis::BigInt)lines * samples * 4) / 1024.0, "KB"); + results += PvlKeyword("SignedWordSize", ((Isis::BigInt)lines * samples * 2) / 1024.0, "KB"); + results += PvlKeyword("UnsignedByteSize", ((Isis::BigInt)lines * samples) / 1024.0, "KB"); + Application::Log(results); + + // Write the output file if requested + if (ui.WasEntered("TO")) { + Pvl temp; + temp.AddGroup(results); + temp.AddGroup(lab.FindGroup("Mapping",Pvl::Traverse)); + temp.Write(ui.GetFilename("TO","txt")); + } + + Application::Log(lab.FindGroup("Mapping",Pvl::Traverse)); + + p.EndProcess(); +} diff --git a/isis/src/base/apps/mapsize/mapsize.xml b/isis/src/base/apps/mapsize/mapsize.xml new file mode 100644 index 0000000000000000000000000000000000000000..d84f9f146168ce57398e7cbb4eb85b085d4c530a --- /dev/null +++ b/isis/src/base/apps/mapsize/mapsize.xml @@ -0,0 +1,189 @@ + + + + + + Compute size or scale of map + + + + This application outputs the size of a map in inches given the scale + (e.g., 1:1000000) or given the size in inches outputs the scale. Also, + the size of an output cube, number of samples and lines, will be + computed. This can be used prior to running programs such as map2map or + cam2map to ensure the output image is not too large. The mapping parameters + used to calculate the information above are also output. + + + + Map Projection + + + + + Original version + + + Converted to Isis 3.0 + + + Fixed compiler warning + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Fixed problem with application test due to compiler optimization + + + Modified filename parameters to be cube parameters where necessary + + + Changed default extension handling mechanism + + + Modified to create Results as an object instead of group in the PVL + output. + + + Added units of inches to the output width and height + + + Added output of map size in Kilobytes + + + Added application test + + + Depricated CubeProjection and ProjectionManager to ProjectionFactory + + + Mofidied to output the mapping group used to calculate the results. + + + Casted file size calculations to a Isis::BigInt to fix an integer overflow problem + + + + + size + + + + + + filename + input + + Label file containing a valid Mapping group + + + This file must contain a valid mapping group. It can come + from the labels of a cube, a hand-generated mapping group, or + from the program "mapinit". + + *.map *.cub + + + filename + output + + Text file output + + None + + This file will contain the size and scale of the map in + a standard label format. + + *.txt + + + + + + string + Define map size using scale or paper size + + This parameter is used to indicate if the user will + define the map size with either the map scale or the + size of the paper in inches. + + SCALE + + + + + + + + double + + The scale of the map + + + Map scales are a unitless representation of how many times + the body was was reduced to fit on the piece of paper (map). + Thus a 1:10000 implies that reduction was by 10000. It + also implies that 1 inch on the map = 10000 inches on the + body. Because the scale is unitless, 1 foot on the map + would be 10000 feet on the body. When entering the value for + scale only enter the portion after the colon as one is always + assumed (i.e., SCALE=10000 implies 1:10000). + + + + + double + + Width of the paper in inches + + + This defines the maximum width of your map in inches. Note + that the results of the computation will likely reduce one + of width or height in order to preserve the aspect ratio of + the map. + + + + + double + + Height of the paper in inches + + + This defines the maximum height of your map in inches. Note + that the results of the computation will likely reduce one + of width or height in order to preserve the aspect ratio of + the map. + + WIDTH + SCALE + + + + diff --git a/isis/src/base/apps/mapsize/tsts/Makefile b/isis/src/base/apps/mapsize/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/mapsize/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/mapsize/tsts/default/Makefile b/isis/src/base/apps/mapsize/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2eb6c0310cf923b68c3c2a2f7c975b11c815b193 --- /dev/null +++ b/isis/src/base/apps/mapsize/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = mapsize + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) map=$(INPUT)/I00824006RDR.lev2.cub \ + option=scale \ + scale=1000 > $(OUTPUT)/mapsize1.pvl; diff --git a/isis/src/base/apps/mapsize/tsts/paper/Makefile b/isis/src/base/apps/mapsize/tsts/paper/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a241ca7de3a8d65f5c48488387376b1ba0d03d42 --- /dev/null +++ b/isis/src/base/apps/mapsize/tsts/paper/Makefile @@ -0,0 +1,9 @@ +APPNAME = mapsize + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) map=$(INPUT)/I00824006RDR.lev2.cub \ + option=paper \ + height=100 \ + width=38 > $(OUTPUT)/mapsize2.pvl; diff --git a/isis/src/base/apps/maptemplate/Makefile b/isis/src/base/apps/maptemplate/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/maptemplate/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/maptemplate/maptemplate.cpp b/isis/src/base/apps/maptemplate/maptemplate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c8b749f31d54fcee8db406d75df5651f6f44f63 --- /dev/null +++ b/isis/src/base/apps/maptemplate/maptemplate.cpp @@ -0,0 +1,628 @@ +#define GUIHELPERS + +#include "Isis.h" +#include "PvlGroup.h" +#include "UserInterface.h" +#include "iException.h" +#include "Spice.h" +#include "FileList.h" +#include "ProjectionFactory.h" +#include "Cube.h" +#include "iString.h" +#include "SpecialPixel.h" +#include "Camera.h" +#include +#include + +using namespace std; +using namespace Isis; + + +//functions in the code +void addProject(PvlGroup &mapping); +void addTarget(PvlGroup &mapping); +void addRange(PvlGroup &mapping); +void calcRange(double &minLat, double &maxLat, + double &minLon, double &maxLon); +void addResolution(PvlGroup &mapping); +double calcResolution(); + +//helper button functins in the code +void helperButtonLogMap(); +void helperButtonLoadMap (); +void helperButtonLogTargDef(); +void helperButtonLoadTargDef(); +void helperButtonLogRadius(); +void helperButtonCalcRange (); +double helperButtonCalcResolution (); + +map GuiHelpers(){ + map helper; + helper ["helperButtonLogMap"] = (void*) helperButtonLogMap; + helper ["helperButtonLoadMap"] = (void*) helperButtonLoadMap; + helper ["helperButtonLogTargDef"] = (void*) helperButtonLogTargDef; + helper ["helperButtonLoadTargDef"] = (void*) helperButtonLoadTargDef; + helper ["helperButtonLogRadius"] = (void*) helperButtonLogRadius; + helper ["helperButtonCalcRange"] = (void*) helperButtonCalcRange; + helper ["helperButtonCalcResolution"] = (void*) helperButtonCalcResolution; + return helper; +} + +void IsisMain() { +// Make the mapping pvl group and add info to it. + PvlGroup mapping("Mapping"); + addProject(mapping); + addTarget(mapping); + addRange(mapping); + addResolution(mapping); + + // Get map file name form GUI and write the mapping group pvl + // to the output file, add .map extension if the + // user didnt enter an extension + UserInterface &ui = Application::GetUserInterface(); + Filename out = ui.GetFilename("MAP"); + string output = ui.GetFilename("MAP"); + if (out.Extension() == "") { + output += ".map"; + } + Pvl p; + p.AddGroup(mapping); + p.Write(output); +} + +//Helper function to output map file to log. +void helperButtonLogMap () { + UserInterface &ui = Application::GetUserInterface(); + string mapFile(ui.GetFilename("MAP")); + Pvl p; + p.Read(mapFile); + PvlGroup t = p.FindGroup("mapping",Pvl::Traverse); + string Ostring = "***** Output of [" + mapFile + "] *****"; + Application::GuiLog(Ostring); + Application::GuiLog(t); +} +//...........end of helper function LogMap ........ + +//Helper 2 function to update GUI with map file values. +void helperButtonLoadMap () { + UserInterface &ui = Application::GetUserInterface(); + string mapFile(ui.GetFilename("MAP")); + Pvl p; + p.Read(mapFile); + PvlGroup t = p.FindGroup("mapping",Pvl::Traverse); +//Projection Stuff + ui.Clear("CLON"); + ui.Clear("CLAT"); + ui.Clear("SCALEFACTOR"); + ui.Clear("PAR1"); + ui.Clear("PAR2"); + ui.Clear("PLAT"); + ui.Clear("PLON"); + ui.Clear("PROT"); + + if (t.HasKeyword("ProjectionName")) { + iString projIn = (string)t["ProjectionName"]; + projIn.UpCase(); + ui.Clear("PROJECTION"); + ui.PutAsString("PROJECTION",projIn); + } + if (t.HasKeyword("CenterLongitude")) { + double clonIn = t["CenterLongitude"]; + ui.Clear("CLON"); + ui.PutDouble("CLON",clonIn); + } + if (t.HasKeyword("CenterLatitude")) { + double clatIn = t["CenterLatitude"]; + ui.Clear("CLAT"); + ui.PutDouble("CLAT",clatIn); + } + if (t.HasKeyword("ScaleFactor")) { + double scaleFactorIn = t["ScaleFactor"]; + ui.Clear("SCALEFACTOR"); + ui.PutDouble("SCALEFACTOR",scaleFactorIn); + } + if (t.HasKeyword("FirstStandardParallel")) { + double par1In = t["FirstStandardParallel"]; + ui.Clear("PAR1"); + ui.PutDouble("PAR1",par1In); + } + if (t.HasKeyword("SecondStandardParallel")) { + double par2In = t["SecondStandardParallel"]; + ui.Clear("PAR2"); + ui.PutDouble("PAR2",par2In); + } + if (t.HasKeyword("PoleLatitude")) { + double pLatIn = t["PoleLatitude"]; + ui.Clear("PLAT"); + ui.PutDouble("PLAT",pLatIn); + } + if (t.HasKeyword("PoleLongitude")) { + double pLonIn = t["PoleLongitude"]; + ui.Clear("PLON"); + ui.PutDouble("PLON",pLonIn); + } + if (t.HasKeyword("PoleRotation")) { + double pRotIn = t["PoleRotation"]; + ui.Clear("PROT"); + ui.PutDouble("PROT",pRotIn); + } + +//Target Parameters stuff + string use = "IMAGE"; + ui.Clear("TARGOPT"); + ui.PutAsString("TARGOPT",use); + ui.Clear("TARGDEF"); + ui.Clear("TARGETNAME"); + ui.Clear("LATTYPE"); + ui.Clear("LONDIR"); + ui.Clear("EQRADIUS"); + ui.Clear("POLRADIUS"); + + if (t.HasKeyword("TargetName")) { + string use = "USER"; + ui.Clear("TARGOPT"); + ui.PutAsString("TARGOPT",use); + string tNameIn = t["TargetName"]; + ui.Clear("TARGETNAME"); + ui.PutAsString("TARGETNAME",tNameIn); + + iString LTIn = (string)t["LatitudeType"]; + LTIn.UpCase(); + ui.Clear("LATTYPE"); + ui.PutAsString("LATTYPE",LTIn); + + iString LDIn = (string)t["LongitudeDirection"]; + LDIn.UpCase(); + ui.Clear("LONDIR"); + ui.PutAsString("LONDIR",LDIn); + + string LDomIn = t["LongitudeDomain"]; + ui.Clear("LONDOM"); + ui.PutAsString("LONDOM",LDomIn); + + string EQIn = t["EquatorialRadius"]; + ui.Clear("EQRADIUS"); + ui.PutAsString("EQRADIUS",EQIn); + string PRIn = t["PolarRadius"]; + ui.Clear("POLRADIUS"); + ui.PutAsString("POLRADIUS",PRIn); + } +//Ground Range Parameter stuff + ui.Clear("MINLAT"); + ui.Clear("MAXLAT"); + ui.Clear("MINLON"); + ui.Clear("MAXLON"); + string useR = "IMAGE"; + ui.Clear("RNGOPT"); + ui.PutAsString("RNGOPT",useR); + + if (t.HasKeyword("MinimumLatitude")) { + double minlatIn = t["MinimumLatitude"]; + string useR = "USER"; + ui.Clear("RNGOPT"); + ui.PutAsString("RNGOPT",useR); + ui.Clear("MINLAT"); + ui.PutDouble("MINLAT",minlatIn); + double maxlatIn = t["MaximumLatitude"]; + ui.Clear("MAXLAT"); + ui.PutDouble("MAXLAT",maxlatIn); + double minlonIn = t["MinimumLongitude"]; + ui.Clear("MINLON"); + ui.PutDouble("MINLON",minlonIn); + double maxlonIn = t["MaximumLongitude"]; + ui.Clear("MAXLON"); + ui.PutDouble("MAXLON",maxlonIn); + } +//Resolution Parameter stuff + if (t.HasKeyword("PixelResolution")) { + string useM = "MPP"; + ui.Clear("RESOPT"); + ui.PutAsString("RESOPT",useM); + double pixresIn = t["PixelResolution"]; + ui.Clear("RESOLUTION"); + ui.PutDouble("RESOLUTION",pixresIn); + } + if (t.HasKeyword("Scale")) { + string useM = "PPD"; + ui.Clear("RESOPT"); + ui.PutAsString("RESOPT",useM); + double Mscale = t["Scale"]; + ui.Clear("RESOLUTION"); + ui.PutDouble("RESOLUTION",Mscale); + } +} +//----------End Helper function to load map file into GUI ----------- + +//helper function to output targdef to log +void helperButtonLogTargDef (){ + UserInterface &ui = Application::GetUserInterface(); + string targetFile(ui.GetFilename("TARGDEF")); + Pvl p; + p.Read(targetFile); + PvlGroup t = p.FindGroup("mapping",Pvl::Traverse); + string Ostring = "***** Output of [" + targetFile + "] *****"; + Application::GuiLog(Ostring); + Application::GuiLog(t); +} +//------------End Helper function to display targdef info to log ----- + +//helper function to load target def. to GUI +void helperButtonLoadTargDef() { + UserInterface &ui = Application::GetUserInterface(); + string targetFile(ui.GetFilename("TARGDEF")); + +// test if targdef was entered + Pvl p; + p.Read(targetFile); + PvlGroup t = p.FindGroup("mapping",Pvl::Traverse); +//Load the targdef values into the GUI + string tOpt = "USER"; + ui.Clear("TARGOPT"); + ui.PutAsString("TARGOPT",tOpt); + if (t.HasKeyword("TargetName")) { + string tNameIn = t["TargetName"]; + ui.Clear("TARGETNAME"); + ui.PutAsString("TARGETNAME",tNameIn); + } + if (t.HasKeyword("LatitudeType")) { + iString LTIn = (string)t["LatitudeType"]; + LTIn.UpCase(); + ui.Clear("LATTYPE"); + ui.PutAsString("LATTYPE",LTIn); + } + if (t.HasKeyword("LongitudeDirection")) { + iString LDIn = (string)t["LongitudeDirection"]; + LDIn.UpCase(); + ui.Clear("LONDIR"); + ui.PutAsString("LONDIR",LDIn); + } + if (t.HasKeyword("LongitudeDomain")) { + string LDomIn = t["LongitudeDomain"]; + ui.Clear("LONDOM"); + ui.PutAsString("LONDOM",LDomIn); + } + if (t.HasKeyword("EquatorialRadius")) { + string EQIn = t["EquatorialRadius"]; + ui.Clear("EQRADIUS"); + ui.PutAsString("EQRADIUS",EQIn); + } + if (t.HasKeyword("PolarRadius")) { + string PRIn = t["PolarRadius"]; + ui.Clear("POLRADIUS"); + ui.PutAsString("POLRADIUS",PRIn); + } +} +//-----------end Helper Function to Load target def into GUI -------- + +//Helper function to show system radius in log. +void helperButtonLogRadius() { + UserInterface &ui = Application::GetUserInterface(); + iString targetName = ui.GetString("TARGETNAME"); + Pvl tMap; +//call function to get system radius + PvlGroup tGrp = Projection::TargetRadii(targetName); + tMap.AddGroup(tGrp); + string Ostring = "***** System radii for " + targetName + "*****"; +//writh to log string(Ostring and mapping group + Application::GuiLog(Ostring); + Application::GuiLog(tMap); +} +//-----------end ot log radius helper function--------- + +//Helper function to run calcRange function. +void helperButtonCalcRange () { + UserInterface &ui = Application::GetUserInterface(); + double minLat; + double maxLat; + double minLon; + double maxLon; +// Run the function calcRange of calculate range info + calcRange(minLat,maxLat,minLon,maxLon); +// Write ranges to the GUI + string use = "USER"; + ui.Clear("RNGOPT"); + ui.PutAsString("RNGOPT",use); + ui.Clear("MINLAT"); + ui.PutDouble("MINLAT",minLat); + ui.Clear("MAXLAT"); + ui.PutDouble("MAXLAT",maxLat); + ui.Clear("MINLON"); + ui.PutDouble("MINLON",minLon); + ui.Clear("MAXLON"); + ui.PutDouble("MAXLON",maxLon); +} +//--------------End Helper function to run calcRange ---------------- + +//Helper function to run calcResolution function. +double helperButtonCalcResolution(){ + UserInterface &ui = Application::GetUserInterface(); +// Call calcResolution which will return a double + double Res = calcResolution(); +//update the GUI with the new resolution + string resUse = "MPP"; + ui.Clear("RESOPT"); + ui.PutAsString("RESOPT",resUse); + ui.Clear("RESOLUTION"); + ui.PutDouble("RESOLUTION",Res); + return Res; +} +//..............End Helper function to run calcResolution + +// Function to Add the projection information to the Mapping PVL +void addProject(PvlGroup &mapping) { + UserInterface &ui = Application::GetUserInterface(); + iString projName = ui.GetString("PROJECTION"); +//setup a look up table for projection names + map projLUT; + projLUT ["SINUSOIDAL"] = "Sinusoidal"; + projLUT ["MERCATOR"] = "Mercator"; + projLUT ["TRANSVERSEMERCATOR"] = "TransverseMercator"; + projLUT ["ORTHOGRAPHIC"] = "Orthographic"; + projLUT ["POLARSTEREOGRAPHIC"] = "PolarStereographic"; + projLUT ["SIMPLECYLINDRICAL"] = "SimpleCylindrical"; + projLUT ["EQUIRECTANGULAR"] = "Equirectangular"; + projLUT ["LAMBERTCONFORMAL"] = "LambertConformal"; + projLUT ["OBLIQUECYLINDRICAL"] = "ObliqueCylindrical"; + +// Add Projection keywords to the mappping PVL + mapping += PvlKeyword("ProjectionName",projLUT[projName]); + if (ui.WasEntered("CLON")) { + double clonOut = ui.GetDouble("CLON"); + mapping += PvlKeyword("CenterLongitude",clonOut); + } + if (ui.WasEntered("CLAT")) { + double clatOut = ui.GetDouble("CLAT"); + mapping += PvlKeyword("CenterLatitude",clatOut); + } + if (ui.WasEntered("SCALEFACTOR")) { + double scaleFactorOut = ui.GetDouble("SCALEFACTOR"); + mapping += PvlKeyword("ScaleFactor",scaleFactorOut); + } + if (ui.WasEntered("PAR1")) { + double par1 = ui.GetDouble("PAR1"); + mapping += PvlKeyword("FirstStandardParallel",par1); + } + if (ui.WasEntered("PAR2")) { + double par2 = ui.GetDouble("PAR2"); + mapping += PvlKeyword("SecondStandardParallel",par2); + } + if (ui.WasEntered("PLAT")) { + double plat = ui.GetDouble("PLAT"); + mapping += PvlKeyword("PoleLatitude",plat); + } + if (ui.WasEntered("PLON")) { + double plon = ui.GetDouble("PLON"); + mapping += PvlKeyword("PoleLongitude",plon); + } + if (ui.WasEntered("PROT")) { + double prot = ui.GetDouble("PROT"); + mapping += PvlKeyword("PoleRotation",prot); + } +} + +// Function to Add the target information to the Mapping PVL +void addTarget(PvlGroup &mapping) { + UserInterface &ui = Application::GetUserInterface(); + if (ui.GetString("TARGOPT") == "SYSTEM") { + string targetFile(ui.GetFilename("TARGDEF")); + Pvl p; + p.Read(targetFile); + PvlGroup t = p.FindGroup("mapping"); + if (t.HasKeyword("TargetName")) { + mapping += t["TargetName"]; + } + if (t.HasKeyword("EquatorialRadius")) { + mapping += t["EquatorialRadius"]; + } + if (t.HasKeyword("PolarRadius")) { + mapping += t["PolarRadius"]; + } + if (t.HasKeyword("LatitudeType")) { + mapping += t["LatitudeType"]; + } + if (t.HasKeyword("LongitudeDirection")) { + mapping += t["LongitudeDirection"]; + } + } +// if TARGOPT is user and no radii enter the run TargetRadii to get +// the system radii for target name. + else if (ui.GetString("TARGOPT") == "USER") { + iString targetName = ui.GetString("TARGETNAME"); + PvlGroup grp = Projection::TargetRadii(targetName); + double equatorialRad = grp["EquatorialRadius"]; + double polarRad = grp["PolarRadius"]; +// if radii were entered in GUI then set radii to entered value + if (ui.WasEntered("EQRADIUS")) { + equatorialRad = ui.GetDouble("EQRADIUS"); + } + if (ui.WasEntered("POLRADIUS")) { + polarRad = ui.GetDouble("POLRADIUS"); + } + iString latType = ui.GetString("LATTYPE"); + if (latType == "PLANETOCENTRIC") { + latType = "Planetocentric"; + } + else if (latType == "PLANETOGRAPHIC") { + latType = "Planetographic"; + } + iString lonDir = ui.GetString("LONDIR"); + if (lonDir == "POSITIVEEAST") { + lonDir = "PositiveEast"; + } + else if (lonDir == "POSITIVEWEST") { + lonDir = "PositiveWest"; + } + iString lonDom = ui.GetString("LONDOM"); +//Add targdef values to the mapping pvl + mapping += PvlKeyword("TargetName",targetName); + mapping += PvlKeyword("EquatorialRadius",equatorialRad, "meters"); + mapping += PvlKeyword("PolarRadius",polarRad, "meters"); + mapping += PvlKeyword("LatitudeType",latType); + mapping += PvlKeyword("LongitudeDirection",lonDir); + mapping += PvlKeyword("LongitudeDomain",lonDom); + } +} + +// Function to add the range information to the mapping PVL +void addRange(PvlGroup &mapping) { + UserInterface &ui = Application::GetUserInterface(); +//Use the values that have been entered in the GUI + if (ui.GetString("RNGOPT") == "USER") { + double minLat = ui.GetDouble("MINLAT"); + mapping += PvlKeyword("MinimumLatitude",minLat); + double maxLat = ui.GetDouble("MAXLAT"); + mapping += PvlKeyword("MaximumLatitude",maxLat); + double minLon = ui.GetDouble("MINLON"); + mapping += PvlKeyword("MinimumLongitude",minLon); + double maxLon = ui.GetDouble("MAXLON"); + mapping += PvlKeyword("MaximumLongitude",maxLon); + } + else if (ui.GetString("RNGOPT") == "CALC") { +// calculate range values using function calcRange and fromlist + double minLat; + double maxLat; + double minLon; + double maxLon; +//Call calcRange to calculate min and max ground range values + calcRange(minLat,maxLat,minLon,maxLon); + mapping += PvlKeyword("MinimumLatitude",minLat); + mapping += PvlKeyword("MaximumLatitude",maxLat); + mapping += PvlKeyword("MinimumLongitude",minLon); + mapping += PvlKeyword("MaximumLongitude",maxLon); + } +} + +// Function to add the resolution information to the mapping PVL +void addResolution(PvlGroup &mapping) { +// Use values that have been entered in GUI + UserInterface &ui = Application::GetUserInterface(); + if (ui.GetString("RESOPT") == "PPD") { + double res = ui.GetDouble("RESOLUTION"); + mapping += PvlKeyword("Scale",iString(res),"pixels/degree"); + } + else if (ui.GetString("RESOPT") == "MPP") { + double res = ui.GetDouble("RESOLUTION"); + mapping += PvlKeyword("PixelResolution",iString(res),"meters/pixel"); + } + else if (ui.GetString("RESOPT") == "CALC") { +// run the function to calculate the resolution + double Res = calcResolution(); + mapping += PvlKeyword("PixelResolution",Res,"meters/pixel"); + } +} + +// Function to calculate the ground range from multiple inputs (list of images) +void calcRange(double &minLat, double &maxLat, + double &minLon, double &maxLon) { + UserInterface &ui = Application::GetUserInterface(); + FileList flist(ui.GetFilename("FROMLIST")); + minLat = DBL_MAX; + maxLat = -DBL_MAX; + minLon = DBL_MAX; + maxLon = -DBL_MAX; + //set up PVL of mapping info from GUI:: need to do this so we use the + // most current info from GUI to calculate the range + Pvl userMap; + PvlGroup userGrp("Mapping"); + if (ui.GetString("TARGOPT") == "SYSTEM") { + userMap.Read(ui.GetFilename("TARGDEF")); + } + else if (ui.GetString("TARGOPT") == "USER") { + userGrp += PvlKeyword("TargetName", ui.GetString("TARGETNAME")); + iString targetName = ui.GetString("TARGETNAME"); + PvlGroup grp = Projection::TargetRadii(targetName); + double equatorialRad = grp["EquatorialRadius"]; + double polarRad = grp["PolarRadius"]; + +// if radii were entered in GUI then set radii to entered value + if (ui.WasEntered("EQRADIUS")) { + equatorialRad = ui.GetDouble("EQRADIUS"); + } + if (ui.WasEntered("POLRADIUS")) { + polarRad = ui.GetDouble("POLRADIUS"); + } + if (ui.GetString("LATTYPE") == "PLANETOCENTRIC") { + string latType = "Planetocentric"; + userGrp += PvlKeyword("LatitudeType", latType); + } + else if (ui.GetString("LATTYPE") == "PLANETOGRAPHIC") { + string latType = "Planetographic"; + userGrp += PvlKeyword("LatitudeType", latType); + } + if (ui.GetString("LONDIR") == "POSITIVEEAST") { + string lonD = "PositiveEast"; + userGrp += PvlKeyword("LongitudeDirection", lonD); + } + else if (ui.GetString("LONDIR") == "POSITIVEWEST") { + string lonD = "PositiveWest"; + userGrp += PvlKeyword("LongitudeDirection", lonD); + } + userGrp += PvlKeyword("LongitudeDomain", ui.GetString("LONDOM")); + userGrp += PvlKeyword("EquatorialRadius", equatorialRad); + userGrp += PvlKeyword("PolarRadius", polarRad); + userMap.AddGroup(userGrp); + } + + for (int i=0; i<(int)flist.size(); i++) { +// Get the mapping group from the camera + double camMinLat; + double camMaxLat; + double camMinLon; + double camMaxLon; + Cube c; + c.Open(flist[i]); + Camera *cam=c.Camera(); + Pvl defaultMap; + cam->BasicMapping(defaultMap); + PvlGroup &defaultGrp = defaultMap.FindGroup("Mapping"); +//Move any defaults that are not in the user map + for (int k=0; kGroundRange(camMinLat,camMaxLat,camMinLon,camMaxLon,userMap); + if (camMinLat < minLat) { + minLat = camMinLat; + } + if (camMaxLat > maxLat) { + maxLat = camMaxLat; + } + if (camMinLon < minLon) { + minLon = camMinLon; + } + if (camMaxLon > maxLon) { + maxLon = camMaxLon; + } + } +} + +// Function to calculate the resolution for images in FROMLIST +// value will be in meters +double calcResolution() { + UserInterface &ui = Application::GetUserInterface(); + FileList flist(ui.GetFilename("FROMLIST")); + double sumRes = 0.0; + double highRes = DBL_MAX; + double lowRes = -DBL_MAX; +// Loop through the from list at get high and low camera resolution + for (int i=0; i<(int)flist.size(); i++) { + Cube c; + c.Open(flist[i]); + Camera *cam = c.Camera(); + double camLowRes = cam->LowestImageResolution(); + double camHighRes = cam->HighestImageResolution(); + if (camLowRes > lowRes) lowRes = camLowRes; + if (camHighRes < highRes) highRes = camHighRes; + sumRes = sumRes + (camLowRes + camHighRes) / 2.0; + } +//user input (RESCALCOPT) at GUI will determain what is output +// highest, lowest, or avg + if (ui.GetString("RESCALCOPT") == "HIGH") return highRes; + if (ui.GetString("RESCALCOPT") == "LOW") return lowRes; + return(sumRes / flist.size()); +} + + diff --git a/isis/src/base/apps/maptemplate/maptemplate.xml b/isis/src/base/apps/maptemplate/maptemplate.xml new file mode 100644 index 0000000000000000000000000000000000000000..f45241eb15643d4624d94e71867599a101caabcd --- /dev/null +++ b/isis/src/base/apps/maptemplate/maptemplate.xml @@ -0,0 +1,943 @@ + + + + + + Create mapping group template for a projection + + + + This program creates a map group template for map projections. Choose a projection and complete + the highlighted fields in the projection parameters area. An exsiting target definition file can be used + or the user can input target information. If a target name is specified and no value is entered for radius, + the system radii will be used. The helper button located by the radial fields will display the system radii + for the chosen target in the log area. Using the RNGOPT parameter, the user can specify whether they + want no ground range values put into the map file, or if they want the application to calculate them + using the FROMLIST files, or whether they want to enter the values themselves. There is a helper + button next to the RNGOPT parameter that will fill in the range parameters with the calculated values. + The RESOPT parameter works very similar to the RNGOPT parameter. The user can enter a resolution + in pixel resolution(MPP) or scale(PPD). The resolution can also be calculated using the FROMLIST. + If the calculation option is chosen, the user can choose to calculate the highest resolution, the lowest + resolution, or an average resolution. All the calculated values will be in pixel resolution which is meters + per pixel. There is also a helper button on this option that will automatically fill in the resolution value in + the gui. The output templates can be used in applications that use projections, such as cam2map, map2map, + mapsize, skymap, etc. The output file will automatically have the '.map' extension appended to the filename. + + + + + Original Version + + + Added .map extension to TO file and fixed bug with spaces in the projection name + + + Depricated CubeProjection and ProjectionManager to ProjectionFactory + + + Redid GUI, added code to calculate ground range and resolution using FROMLIST, and + added helper buttons + + + Added oblique cylindrical projection + + + Fixed a problem that occurred when using "TARGOPT=USER", "RNGOPT=CALC" and not entering "EQRADIUS" or "POLRADIUS" + + + + + + cam2map + map2map + mapsize + skymap + + + + + Map Projection + + + + + + filename + output + + Output text file containing mapping template + + + This file will contain the mapping group template. If this file currently exists, the application will write over + the file. The '.map' extension will automatically be appended to the entered filename if you do not type + in an extension. + + + + helperButtonLogMap + View map file in log area + This helper button will display the current map file in the log area + $ISIS3DATA/base/icons/view_text.png + + + helperButtonLoadMap + Load Map File values into the GUI + + This helper button will take the values currently in the mapfile and + load them into their correct locations in the gui + + $ISIS3DATA/base/icons/exec.png + + + + *.map + + + + + filename + input + list of images used when calculation option is selected + + Input list of images used when calculation option is selected + + + A list of file names that will be used by the caluclation option for the ground range and resolution + parameters. It is also used when a user selects the helper button for the two parameters. + + + *.lis + + + + + + + string + + Name of Projection to create mapping group for + + + This is the name of the projection for the mapping group being + created. + + + SINUSOIDAL + + + + + + + + + + + + + + + + + + double + + Center Longitude + + + The center longitude to use for the mapping group. + + + + + double + + Center Latitude + + + The center latitude to use for the mapping group. + + + + + double + + Scale Factor + + + The scale factor to use for the mapping group. + + + + + double + + First Standard Parallel + + + The first standard parallel to use for the mapping group. + + + + + double + + Second Standard Parallel + + + The second standard parallel to use for the mapping group. + + + + + double + + Pole Latitude + + + The pole latitude to use for the mapping group. + + + + + double + + Pole Longitude + + + The pole longitude to use for the mapping group. + + + + + double + + Pole Rotation + + + The pole rotation to use for the mapping group. + + + + + + + string + + Target Selection Options + + + This option decides how the target information will be created. The default is IMAGE. The + other options include SYSTEM and USER. The IMAGE option will not add any target information + to the map file, allowing the target information from the image to be used. The SYSTEM option + will retrieve the target information from the system defaults, and the USER option allows the user + to specify their own target information. + + + IMAGE + + + + + + + + + + filename + + $ISIS3DATA/base/templates/targets/ + + + Name of the Target Definition File + + + This is the Target Definition file that will be used for the projection. + + + + helperButtonLogTargDef + View TARGDEF file in log area + This helper button will display the selected target def file in the log area + $ISIS3DATA/base/icons/view_text.png + + + helperButtonLoadTargDef + Load values from TARGDEF into GUI + + This helper button will take the values currently in the target def file and + load them into their correct locations in the gui + + $ISIS3DATA/base/icons/exec.png + + + + + + string + + Name of the Target + + + This is the name of the Target (your planet of interest) for the projection. + + + + + string + + Latitude type + + + The latitude type for the projection. It can either be Planetocentric or Planetographic. + PLANETOCENTRIC is the default. + + + PLANETOCENTRIC + + + + + + + + + string + + Longitude Direction + + + The longitude direction for the projection. It can have a direction of Positive East + or Positive West. POSITIVEEAST is the default. + + + POSITIVEEAST + + + + + + + + + string + + Longitude Domain + + + The longitude domain for the projection. It can either have a domain of 180 or 360. + 360 is the default. + + + 360 + + + + + + + + + double + + Equatorial Radius + + IAU Default + + The equatorial radius value to put in the maptemplate. If this value is left blank, the system default will be used + + + + helperButtonLogRadius + Show the system default radius for TARGETNAME in log area + + This button will display the system radii values for the target name in the log area + + $ISIS3DATA/base/icons/view_text.png + + + + + + double + + Polar Radius + + IAU Default + + The polar radius value to put in the maptemplate. If this value is left blank, the system default will be used. + + + + + + + string + + Ground Range Selection Options + + + This option decides how the ground range information will be created. IMAGE is the default value. The + other options are USER and CALC. The IMAGE option does not write any ground range information to the + map file, allowing the range to be calculated from the image at the time of projection. The USER option allows + the user to enter their own values for the ground range, and the CALC option will calculate the ground range + using the files listed in the FROMLIST. + + + IMAGE + + + + helperButtonCalcRange + Calculate Ranges using FROMLIST + + This button will calculate the latitude and longitude range using the files in the FROMLIST. + The ranges will be calculated using the target information in the GUI. If no target information + is entered, then the camera defaults will be used. + + $ISIS3DATA/base/icons/exec.png + + + + + + + + + + + + + double + + Minimum Latitude + + + The mimimum latitude value in the mapping template will be set to this user entered value. + + + + + double + + Maximum Latitude + + + The maximum latitude value in the mapping template will be set to this user entered value. + + + + + double + + Minimum Longitude + + + The minimum longitude value in the mapping template will be set to this user entered value. + + + + + double + + Maximum Longitude + + + The maximum longitude value in the mapping template will be set to this user entered value. + + + + + + + string + + Resolution Selection Options + + + This option decides how the resolution information will be created. The default is IMAGE. The other + options are MPP, PPD and CALC. The IMAGE option does not write any ground range information to the + map file, allowing the range to be calculated from the image at the time of projection. The MPP and PPD option allow + the user to enter their own values for the ground range and select the appropriate units. The CALC option will + calculate the ground range using the files listed in the FROMLIST. + + + IMAGE + + + + helperButtonCalcResolution + Calculate Pixel Resolution using FROMLIST + + This button will calculate the resolution value using the files in the FROMLIST. The output from this calculation + will be in meters/pixel which is Pixel Resolution in the map file. + + $ISIS3DATA/base/icons/exec.png + + + + + + + + + + + + double + + Resolution + + + The values used for resolution in the mapping template. The units are specified by the user as pixels per degree (PPD) + or meters per pixel (MPP). + + + + + string + + Select highest value, lowest value, or average value + + + This option decides how resolution information will be calculated. The defualt is HIGH. + The other options are LOW and AVERAGE. The HIGH option gets the highest + resolution from the list of images, the LOW option gets the lowest resolution, and the + AVERAGE option calculates the average resolution from all of the files in the FROMLIST. + All options output the resolution in meters per pixel. + + + HIGH + + + + + + + + + + + + + Sinusoidal Map Template + + This example shows how the maptemplate application works. The settings are all default for + this example, other than the output filename and center longitude which are entered in. +
    +Group = Mapping
    +  ProjectionName     = Sinusoidal
    +  CenterLongitude    = 0.0
    +End_Group
    +End
    +        
    + The above output is the text file resulting when the following command line is run. +
    + + map=out.txt clon=0.0 + + + Just run maptemplate with an output file name and center longitude. + + +
    + + Lambert Conformal Map Template + + This example shows how the maptemplate application works. For this example, the output file, projection type, + center latitude, center longitude, first and second standard parallel, target option, and target name are entered. + The rest of the settings are left in their default state. +
    +Group = Mapping
    +  ProjectionName     = LambertConformal
    +  CenterLongitude    = 0.0
    +  CenterLatitude     = 90.0
    +  StandardParallel1  = 45.0
    +  StandardParallel2  = 55.0
    +  TargetName         = Mars
    +  EquatorialRadius   = 3396190.0 <meters>
    +  PolarRadius        = 3376200.0 <meters>
    +  LatitudeType       = Planetocentric
    +  LongitudeDirection = PositiveEast
    +  LongitudeDomain    = 360
    +End_Group
    +        
    + The above output is the text file resulting when the following command line is run. +
    + + map=out.txt projection=LambertConformal clon=0.0 clat=90.0 par1=45.0 par2=55.0 targopt=user targetname=MARS + + + Just run maptemplate with the output file, projection type, center latitude, center longitude, + first and second standard parallel, target option, and target name. + + +
    +
    +
    + diff --git a/isis/src/base/apps/maptemplate/tsts/Makefile b/isis/src/base/apps/maptemplate/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/maptemplate/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/maptemplate/tsts/lambert/Makefile b/isis/src/base/apps/maptemplate/tsts/lambert/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..83869c72c675be3388d81488f9aa5568bcafe8a8 --- /dev/null +++ b/isis/src/base/apps/maptemplate/tsts/lambert/Makefile @@ -0,0 +1,7 @@ +APPNAME = maptemplate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) projection=LambertConformal clon=0.0 clat=90.0 par1=45.0 par2=55.0 \ + map=$(OUTPUT)/maptemplateTruth.txt > /dev/null; diff --git a/isis/src/base/apps/maptemplate/tsts/mercator/Makefile b/isis/src/base/apps/maptemplate/tsts/mercator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9551e63c1e25b6112c7fd8a2822e5fe83a93c5f2 --- /dev/null +++ b/isis/src/base/apps/maptemplate/tsts/mercator/Makefile @@ -0,0 +1,7 @@ +APPNAME = maptemplate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) projection=Mercator clon=0.0 clat=90.0 resopt=mpp resolution=1 \ + map=$(OUTPUT)/maptemplateTruth.txt > /dev/null; diff --git a/isis/src/base/apps/maptemplate/tsts/oblique/Makefile b/isis/src/base/apps/maptemplate/tsts/oblique/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..368f9686f9e9565b0504c690e56030783e946ec3 --- /dev/null +++ b/isis/src/base/apps/maptemplate/tsts/oblique/Makefile @@ -0,0 +1,7 @@ +APPNAME = maptemplate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) map=$(OUTPUT)/maptemplateTruth.txt PLAT=45.0 PLON=180.0 PROT=0.0 \ + PROJECTION=OBLIQUECYLINDRICAL > /dev/null; diff --git a/isis/src/base/apps/maptemplate/tsts/simple/Makefile b/isis/src/base/apps/maptemplate/tsts/simple/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..585565bc1309c3c089783afd810a3ab5954f358d --- /dev/null +++ b/isis/src/base/apps/maptemplate/tsts/simple/Makefile @@ -0,0 +1,7 @@ +APPNAME = maptemplate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) projection=SimpleCylindrical Rngopt=user minlat=0 maxlat=180 minlon=0 maxlon=180 \ + clon=0.0 map=$(OUTPUT)/maptemplateTruth.txt > /dev/null; diff --git a/isis/src/base/apps/maptemplate/tsts/sinusoidal/Makefile b/isis/src/base/apps/maptemplate/tsts/sinusoidal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..010bcf62c2613ac2bba76ed0c27516377d00d49e --- /dev/null +++ b/isis/src/base/apps/maptemplate/tsts/sinusoidal/Makefile @@ -0,0 +1,7 @@ +APPNAME = maptemplate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) clon=0.0 map=$(OUTPUT)/maptemplateTruth.txt \ + targopt=user targetname=MARS > /dev/null; diff --git a/isis/src/base/apps/maptrim/Makefile b/isis/src/base/apps/maptrim/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/maptrim/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/maptrim/maptrim.cpp b/isis/src/base/apps/maptrim/maptrim.cpp new file mode 100644 index 0000000000000000000000000000000000000000..468f83d32c69dc60761a55d72eacee5a3bfbc3e1 --- /dev/null +++ b/isis/src/base/apps/maptrim/maptrim.cpp @@ -0,0 +1,160 @@ +#include "Isis.h" + +#include "ProcessByLine.h" +#include "LineManager.h" +#include "ProjectionFactory.h" +#include "Projection.h" +#include "iException.h" +#include "Application.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void trim(Buffer &in,Buffer &out); +void getSize(Buffer &in); + +double slat, elat, slon, elon; +int smallestLine, biggestLine, smallestSample, biggestSample; +Projection *proj; + +void IsisMain() { + // Get the projection + UserInterface &ui = Application::GetUserInterface (); + Pvl pvl(ui.GetFilename("FROM")); + proj = ProjectionFactory::CreateFromCube(pvl); + + // Determine ground range to crop and/or trim + if (ui.WasEntered ("MINLAT")) { + slat = ui.GetDouble ("MINLAT"); + elat = ui.GetDouble ("MAXLAT"); + slon = ui.GetDouble ("MINLON"); + elon = ui.GetDouble ("MAXLON"); + } + else if (proj->HasGroundRange()) { + slat = proj->MinimumLatitude(); + elat = proj->MaximumLatitude(); + slon = proj->MinimumLongitude(); + elon = proj->MaximumLongitude(); + } + else { + string msg = "Latitude and longitude range not defined in projection"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + string mode = ui.GetString("MODE"); + + if(mode != "TRIM") { + smallestLine = smallestSample = INT_MAX; + biggestLine = biggestSample = -INT_MAX; + + ProcessByLine p; + p.SetInputCube("FROM"); + p.StartProcess(getSize); + p.EndProcess(); + + int samples = biggestSample - smallestSample + 1; + int lines = biggestLine - smallestLine + 1; + + // Run external crop + string cropParams = ""; + cropParams += "from=\"" + ui.GetFilename("FROM") + "\""; + if(mode == "CROP") { + cropParams += " to=\"" + ui.GetAsString("TO") + "\""; + } + else { + cropParams += " to=TEMPORARYcropped.cub "; + } + + cropParams += " sample= " + iString(smallestSample); + cropParams += " nsamples= " + iString(samples); + cropParams += " line= " + iString(smallestLine); + cropParams += " nlines= " + iString(lines); + + try { + Isis::iApp->Exec("crop", cropParams); + } + catch(iException &e) { + string msg = "Could not execute crop with params: [" + cropParams + "]"; + throw Isis::iException::Message(Isis::iException::Programmer, msg, + _FILEINFO_); + } + if(mode == "BOTH") { + delete proj; + proj = NULL; + Pvl pvl("TEMPORARYcropped.cub"); + proj = ProjectionFactory::CreateFromCube(pvl); + } + } + + // Trim image if necessary + if(mode != "CROP") { + ProcessByLine p; + CubeAttributeInput att; + if(mode == "BOTH") { + p.SetInputCube("TEMPORARYcropped.cub", att); + } + else { //if its trim + p.SetInputCube("FROM"); + } + p.SetOutputCube("TO"); + p.StartProcess(trim); + p.EndProcess(); + if(mode == "BOTH") remove("TEMPORARYcropped.cub"); + } + + // Add mapping to print.prt + PvlGroup mapping = proj->Mapping(); + Application::Log(mapping); + + delete proj; + proj = NULL; +} + +// Size up the cropped area in terms of lines and samples +void getSize(Buffer &in) { + double lat, lon; + for (int i = 0; i < in.size(); i++) { + proj->SetWorld ((double)in.Sample(i),(double)in.Line(i)); + lat = proj->Latitude(); + lon = proj->Longitude(); + + // Skip past pixels outside of lat/lon range + if (lat < slat || lat > elat || lon < slon || lon > elon) { + continue; + } + else { + if(in.Line(i) < smallestLine) { + smallestLine = in.Line(i); + } + if(in.Line(i) > biggestLine) { + biggestLine = in.Line(i); + } + if(in.Sample(i) < smallestSample) { + smallestSample = in.Sample(i); + } + if(in.Sample(i) > biggestSample) { + biggestSample = in.Sample(i); + } + } + } +} + +// Line processing routine +void trim(Buffer &in, Buffer &out) { + // Loop for each pixel in the line. Find lat/lon of pixel, if outside + // of range, set to NULL. + double lat,lon; + for (int i = 0; i < in.size(); i++) { + proj->SetWorld ((double)in.Sample(i),(double)in.Line(i)); + lat = proj->Latitude(); + lon = proj->Longitude(); + if (lat < slat || lat > elat || lon < slon || lon > elon) { + out[i] = Isis::Null; + } + else { + out[i] = in[i]; + } + } +} + diff --git a/isis/src/base/apps/maptrim/maptrim.xml b/isis/src/base/apps/maptrim/maptrim.xml new file mode 100644 index 0000000000000000000000000000000000000000..675317db9480c1ec5d643fc48315eebd16f61e08 --- /dev/null +++ b/isis/src/base/apps/maptrim/maptrim.xml @@ -0,0 +1,185 @@ + + + + + + Trim edges of a map projected image + + + + Trim the edges of a map projected image to the exact latitude and longitude + boundaries given in the user parameters or by default the lat/lon range + in the labels. Any pixels outside this lat/lon range will be set to + the Null value. + + + + Map Projection + Trim and Mask + + + + + Original version + + + Changed brief description, added error check for no values + entered for slat,elat,slon,elon. + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Added application test + + + Added cropping and crop+trim ability; modified apptest + + + Fixed parameter names + + + Mapping group parameters are now placed into the print file. + + + Modified call to crop to handle from and to parameters with spaces in + directories. + + + + + trimsinu + + + + + + cube + input + + Input cube to trim + + + Use this parameter to select the filename. All band within the file + will be trimmed. + + + *.cub + + + + cube + output + + Output cube + + + This file will contain the results of the trimmed cube. + + + *.cub + + + + + + + string + TRIM + Maptrim options + + This allows the user to decide which trimming options to use. Normally, + all pixels outside the lat/lon ranges are nulled. There is now a choice + to crop out a part of a map with or without nulled pixels outside the + lat/lon range. + + + + + + + + + + + + + + double + + Minimum latitude in labels + + Starting latitude + + Starting latitude of range to exclude from trim. Any pixels less than + this latitude will be set to Null. + + + MAXLAT + + + + + double + + Maximum latitude in labels + + Ending latitude + + Ending latitude of range exclude from trim. Any pixels greater than + this latitude will be set to Null. + + + + + double + + Minimum longitude in labels + + Starting longitude + + Starting longitude of range to exclude from trim. Any pixels less than + this longitude will be set to Null. + + + MAXLON + + + + + double + + Maximum longitude in labels + + Ending longitude + + Ending longitude of range exclude from trim. Any pixels greater than + this longitude will be set to Null. + + + + + + diff --git a/isis/src/base/apps/maptrim/tsts/Makefile b/isis/src/base/apps/maptrim/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/maptrim/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/maptrim/tsts/cropAndTrim/Makefile b/isis/src/base/apps/maptrim/tsts/cropAndTrim/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b1585594336694ce1de900342b2a5bdb10ec947a --- /dev/null +++ b/isis/src/base/apps/maptrim/tsts/cropAndTrim/Makefile @@ -0,0 +1,9 @@ +APPNAME = maptrim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.map.cub \ + to=$(OUTPUT)/cropAndTrimTruth.cub \ + mode=both \ + minlat=15 maxlat=20 minlon=222 maxlon=230> /dev/null; diff --git a/isis/src/base/apps/maptrim/tsts/cropOnly/Makefile b/isis/src/base/apps/maptrim/tsts/cropOnly/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0ad10287eb5b4ca30d894666622a27aa10bd68f9 --- /dev/null +++ b/isis/src/base/apps/maptrim/tsts/cropOnly/Makefile @@ -0,0 +1,9 @@ +APPNAME = maptrim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.map.cub \ + to=$(OUTPUT)/cropOnlyTruth.cub \ + mode=crop \ + minlat=15 maxlat=20 minlon=222 maxlon=230 > /dev/null; diff --git a/isis/src/base/apps/maptrim/tsts/default/Makefile b/isis/src/base/apps/maptrim/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..342a165c8e117586551c5dc7afd7fe63ef3c4eae --- /dev/null +++ b/isis/src/base/apps/maptrim/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = maptrim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.map.cub \ + to=$(OUTPUT)/trimOnlyTruth.cub \ + minlat=15 maxlat=20 minlon=222 maxlon=230> /dev/null; diff --git a/isis/src/base/apps/mask/Makefile b/isis/src/base/apps/mask/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/mask/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/mask/mask.cpp b/isis/src/base/apps/mask/mask.cpp new file mode 100644 index 0000000000000000000000000000000000000000..17f7e7fd36fdfeeb127997ce7ace698a10847f8f --- /dev/null +++ b/isis/src/base/apps/mask/mask.cpp @@ -0,0 +1,106 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void mask (vector &in, + vector &out); + +enum which_special {NONE, NULLP, ALL} spixels; +enum range_preserve {INSIDE,OUTSIDE} preserve; + +double minimum,maximum; +bool masked; + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + masked= false; + + // Setup the input and output cubes + UserInterface &ui = Application::GetUserInterface(); + + if (!ui.WasEntered("MASK")) + ui.PutFilename("MASK", ui.GetFilename("FROM")); + + printf("MASK=%s", ui.GetFilename("MASK").c_str()); + + p.SetInputCube("FROM"); + p.SetInputCube("MASK",OneBand); + p.SetOutputCube ("TO"); + + + // Get min/max info + minimum = VALID_MIN8; + maximum = VALID_MAX8; + if (ui.WasEntered ("MINIMUM")) minimum = ui.GetDouble ("MINIMUM"); + if (ui.WasEntered ("MAXIMUM")) maximum = ui.GetDouble ("MAXIMUM"); + + // Will we preserve inside or outside of min/max range + preserve = INSIDE; + string Preserve; + if (ui.WasEntered ("PRESERVE")) Preserve = ui.GetString ("PRESERVE"); + if (Preserve == "OUTSIDE") preserve = OUTSIDE; + + // How are special pixels handled? + spixels = NULLP; + string Spixels; + if (ui.WasEntered ("SPIXELS")) Spixels = ui.GetString ("SPIXELS"); + if (Spixels == "NONE") spixels = NONE; + if (Spixels == "ALL") spixels = ALL; + + // Start the processing + p.StartProcess(mask); + p.EndProcess(); + + // Report if no masking occurred + if (!masked) { + string message = "No mask was performed-the output file is the same as "; + message += "the input file."; + throw iException::Message(iException::User,message,_FILEINFO_); + } + +} + +// Line processing routine + void mask (vector &in, + vector &out) + { + + Buffer &inp = *in[0]; + Buffer &mask = *in[1]; + Buffer &outp = *out[0]; + + // Loop for each pixel in the line. + for (int i=0; i= minimum && mask[i] <= maximum)) + outp[i] = inp[i]; + else if (preserve == OUTSIDE && (mask[i] < minimum || mask[i] > maximum)) + outp[i] = inp[i]; + else { + outp[i] = NULL8; + masked = true; + } + } + } + + } diff --git a/isis/src/base/apps/mask/mask.xml b/isis/src/base/apps/mask/mask.xml new file mode 100644 index 0000000000000000000000000000000000000000..d496af9276f4562b9e3980441a1287a381dc121b --- /dev/null +++ b/isis/src/base/apps/mask/mask.xml @@ -0,0 +1,194 @@ + + + + + + Set pixels to NULL using a mask cube + + + + This program masks (or NULLs) pixels in an input cube. The input cube is + NULLed using a mask cube. This is done by specifying a minimum/maximum + pixel range in the mask cube. Pixels which fall outside the range in + the mask will be set to NULL in the output cube. Pixels inside the range + will be propagated from the input cube to the output. An option exists to + reverse the masking process so that pixels outside the range are preserved, + and pixels inside the range are NULLed. + + + + + Original version + + + + Ported to Isis 3.0 + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Set Internal Default for "MASK" to be "FROM" + + + + + Trim and Mask + + + + + + cube + input + + Input cube to mask + + + Use this parameter to select the filename. All bands within the file + will be masked. + + + *.cub + + + + + cube + input + + Mask cube + + + Use this parameter to select the filename to be used as the mask. + If this parameter is not explicitly entered, it will default to the + same filename as FROM + + + FROM + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the masked cube + + + + + + + double + + ISIS minimum + + + MAXIMUM + + Minimum value of range to mask + + This defines the minimum range of valid data in the mask cube. + + + + + double + + ISIS maximum + + + MINIMUM + + Maximum value of range to mask + + This defines the maximum range of valid data in the mask cube. + + + + + string + + INSIDE + + Indicates whether to preserve pixels inside or outside of range. + + This parameter indicates whether the pixels chosen to mask are within the range given + or outside of the range given. If INSIDE, pixels inside of given range will be masked. + If OUTSIDE, pixels outside the range will be masked. + + + + + + + + + + + string + + NULL + + Special pixels to include as mask + + This indicates which special pixel values are to be included as valid + pixels in the mask. For example, a NULL in the mask cube will cause + the output to be NULL if the NULL or ALL option is selected. If NONE + was selected, then the input pixel would be propagated to the output + cube. + + + + + + + + + + + + + diff --git a/isis/src/base/apps/mask/tsts/Makefile b/isis/src/base/apps/mask/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/mask/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/mask/tsts/all/Makefile b/isis/src/base/apps/mask/tsts/all/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ba68a0e1d6c25228b3b2318234cd0dcb387d76ea --- /dev/null +++ b/isis/src/base/apps/mask/tsts/all/Makefile @@ -0,0 +1,12 @@ +APPNAME = mask + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + mask=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/maskTruth2.cub \ + minimum=0 \ + maximum=1000 \ + preserve=outside \ + spixels=all > /dev/null; diff --git a/isis/src/base/apps/mask/tsts/none/Makefile b/isis/src/base/apps/mask/tsts/none/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d2593e2c8967b9237c7841ae6dd92f17a7c18338 --- /dev/null +++ b/isis/src/base/apps/mask/tsts/none/Makefile @@ -0,0 +1,12 @@ +APPNAME = mask + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + mask=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/maskTruth3.cub \ + minimum=-20 \ + maximum=10 \ + preserve=outside \ + spixels=none > /dev/null; diff --git a/isis/src/base/apps/mask/tsts/null/Makefile b/isis/src/base/apps/mask/tsts/null/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..618b1bb603c35509f183bf9059ae3037f08b86b0 --- /dev/null +++ b/isis/src/base/apps/mask/tsts/null/Makefile @@ -0,0 +1,11 @@ +APPNAME = mask + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + mask=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/maskTruth1.cub \ + minimum=0 \ + maximum=1000 \ + preserve=inside> /dev/null; diff --git a/isis/src/base/apps/mat2cnet/Makefile b/isis/src/base/apps/mat2cnet/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/mat2cnet/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/mat2cnet/assets/controlnet.net b/isis/src/base/apps/mat2cnet/assets/controlnet.net new file mode 100644 index 0000000000000000000000000000000000000000..9fe3a1b14ee66ee2103aabb65770cfe0bb441cea --- /dev/null +++ b/isis/src/base/apps/mat2cnet/assets/controlnet.net @@ -0,0 +1,249 @@ +Object = ControlNetwork + NetworkId = TestNet01 + NetworkType = ImageToGround + TargetName = Titan + UserName = jwalldren + Created = 2009-11-05T11:28:47 + LastModified = 2009-11-05T11:28:47 + Description = "Default Test Network" + + Object = ControlPoint + PointType = Tie + PointId = 1001 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467436709.122 + MeasureType = ValidatedManual + Sample = 893.0 + Line = 616.0 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467443189.122 + MeasureType = ValidatedManual + Sample = 799.25 + Line = 701.21 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467454012.125 + MeasureType = ValidatedManual + Sample = 569.01 + Line = 807.23 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 1002 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467436709.122 + MeasureType = ValidatedManual + Sample = 963.5 + Line = 216.5 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467443189.122 + MeasureType = ValidatedManual + Sample = 836.48 + Line = 284.28 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467454012.125 + MeasureType = ValidatedManual + Sample = 548.19 + Line = 400.6 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 1003 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467436709.122 + MeasureType = ValidatedManual + Sample = 348.5 + Line = 583.5 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467443189.122 + MeasureType = ValidatedManual + Sample = 235.74 + Line = 692.39 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 1004 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467436709.122 + MeasureType = ValidatedManual + Sample = 781.0 + Line = 466.0 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467443189.122 + MeasureType = ValidatedManual + Sample = 663.99 + Line = 552.76 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467454012.125 + MeasureType = ValidatedManual + Sample = 408.5 + Line = 672.5 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 1005 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467453442.125 + MeasureType = ValidatedManual + Sample = 82.25 + Line = 202.48 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467454012.125 + MeasureType = ValidatedManual + Sample = 1007.5 + Line = 210.5 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 1006 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467453442.125 + MeasureType = ValidatedManual + Sample = 63.51 + Line = 405.49 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467454012.125 + MeasureType = ValidatedManual + Sample = 989.0 + Line = 412.0 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 1007 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467453442.125 + MeasureType = ValidatedManual + Sample = 21.86 + Line = 557.84 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467454012.125 + MeasureType = ValidatedManual + Sample = 950.0 + Line = 563.0 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/mat2cnet/assets/controlnet_rand.net b/isis/src/base/apps/mat2cnet/assets/controlnet_rand.net new file mode 100644 index 0000000000000000000000000000000000000000..4e8448fdfa71ad11cf354b55775bea66afdbe958 --- /dev/null +++ b/isis/src/base/apps/mat2cnet/assets/controlnet_rand.net @@ -0,0 +1,252 @@ +Object = ControlNetwork + NetworkId = TestNet02 + NetworkType = ImageToGround + TargetName = Titan + UserName = jwalldren + Created = 2009-11-05T11:30:04 + LastModified = 2009-11-05T11:30:04 + Description = "Rand Test Network" + + Object = ControlPoint + PointType = Ground + PointId = 1001 + Latitude = 11.406981823073 + Longitude = 349.54385587931 + Radius = 1736163.0 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467436709.122 + MeasureType = ValidatedManual + Sample = 893.0 + Line = 616.0 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467443189.122 + MeasureType = ValidatedManual + Sample = 799.25 + Line = 701.21 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467454012.125 + MeasureType = ValidatedManual + Sample = 569.01 + Line = 807.23 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 1002 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467436709.122 + MeasureType = ValidatedManual + Sample = 963.5 + Line = 216.5 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467443189.122 + MeasureType = ValidatedManual + Sample = 836.48 + Line = 284.28 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467454012.125 + MeasureType = ValidatedManual + Sample = 548.19 + Line = 400.6 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 1003 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467436709.122 + MeasureType = ValidatedManual + Sample = 348.5 + Line = 583.5 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467443189.122 + MeasureType = ValidatedManual + Sample = 235.74 + Line = 692.39 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 1004 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467436709.122 + MeasureType = ValidatedManual + Sample = 781.0 + Line = 466.0 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467443189.122 + MeasureType = ValidatedManual + Sample = 663.99 + Line = 552.76 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467454012.125 + MeasureType = ValidatedManual + Sample = 408.5 + Line = 672.5 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 1005 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467453442.125 + MeasureType = ValidatedManual + Sample = 82.25 + Line = 202.48 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467454012.125 + MeasureType = ValidatedManual + Sample = 1007.5 + Line = 210.5 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 1006 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467453442.125 + MeasureType = ValidatedManual + Sample = 63.51 + Line = 405.49 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467454012.125 + MeasureType = ValidatedManual + Sample = 989.0 + Line = 412.0 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 1007 + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467453442.125 + MeasureType = ValidatedManual + Sample = 21.86 + Line = 557.84 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Cassini-Huygens/ISSNA/1/1467454012.125 + MeasureType = ValidatedManual + Sample = 950.0 + Line = 563.0 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + Diameter = 0.0 + Reference = True + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/mat2cnet/assets/images/mat2cnetGuiEx1.jpg b/isis/src/base/apps/mat2cnet/assets/images/mat2cnetGuiEx1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ea531f7358f6bc4955fb2a3f5c358b58d5d4670f Binary files /dev/null and b/isis/src/base/apps/mat2cnet/assets/images/mat2cnetGuiEx1.jpg differ diff --git a/isis/src/base/apps/mat2cnet/assets/images/mat2cnetGuiEx2.jpg b/isis/src/base/apps/mat2cnet/assets/images/mat2cnetGuiEx2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1483ab592bc1c0b2a69602293c29909b78349bf6 Binary files /dev/null and b/isis/src/base/apps/mat2cnet/assets/images/mat2cnetGuiEx2.jpg differ diff --git a/isis/src/base/apps/mat2cnet/assets/match.mat b/isis/src/base/apps/mat2cnet/assets/match.mat new file mode 100644 index 0000000000000000000000000000000000000000..bc43a41a2e961f3a516ff427a70972fcd7a2971f --- /dev/null +++ b/isis/src/base/apps/mat2cnet/assets/match.mat @@ -0,0 +1,19 @@ +Matchpoint total = 17 +Point ID FSC LINE SAMP CLASS DIAMETER +1001 1467436731 616.00 893.00 T 0.0000 +1001 1467443211 701.21 799.25 M 0.0000 +1001 1467454094 807.23 569.01 M 0.0000 +1002 1467436731 216.50 963.50 T 0.0000 +1002 1467443211 284.28 836.48 M 0.0000 +1002 1467454094 400.60 548.19 M 0.0000 +1003 1467436731 583.50 348.50 T 0.0000 +1003 1467443211 692.39 235.74 M 0.0000 +1004 1467436731 466.00 781.00 T 0.0000 +1004 1467443211 552.76 663.99 M 0.0000 +1004 1467454094 672.50 408.50 M 0.0000 +1005 1467453524 202.48 82.25 M 0.0000 +1005 1467454094 210.50 1007.50 T 0.0000 +1006 1467453524 405.49 63.51 M 0.0000 +1006 1467454094 412.00 989.00 T 0.0000 +1007 1467453524 557.84 21.86 M 0.0000 +1007 1467454094 563.00 950.00 T 0.0000 diff --git a/isis/src/base/apps/mat2cnet/assets/rand.ppp b/isis/src/base/apps/mat2cnet/assets/rand.ppp new file mode 100644 index 0000000000000000000000000000000000000000..561cd898daf16a7f1762595b392b29b0e46779e7 --- /dev/null +++ b/isis/src/base/apps/mat2cnet/assets/rand.ppp @@ -0,0 +1,7 @@ + 0.1140698182307315E+02 0.3495438558793123E+03 0.1736163000000000E+04 1001 + 0.1162847079486373E+02 0.3495477663321510E+03 0.1736107000000000E+04 1008 + 0.2439629743280037E+07 41141 JULIAN_DATE&FDS + 0.4226172669674684E+04 -0.1070978171806175E+04 0.7780212484250762E+03 SXSYSZ + -0.1316941846870119E+02 0.1143097971413563E+02 -0.7340058975862854E+02 C1C2C3 + 0.2675956282355995E+03 0.6775737366804856E+02 0.8754866479024430E+00 PLANET + diff --git a/isis/src/base/apps/mat2cnet/assets/randlog.txt b/isis/src/base/apps/mat2cnet/assets/randlog.txt new file mode 100644 index 0000000000000000000000000000000000000000..5d1d975974ff7ed5aa8aac19de71f7804da9bbda --- /dev/null +++ b/isis/src/base/apps/mat2cnet/assets/randlog.txt @@ -0,0 +1 @@ + 0.1162847079486373E+02 0.3495477663321510E+03 0.1736107000000000E+04 1008 diff --git a/isis/src/base/apps/mat2cnet/assets/thumbs/mat2cnetGuiThumbEx1.jpg b/isis/src/base/apps/mat2cnet/assets/thumbs/mat2cnetGuiThumbEx1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ad331b70cb81beabc8652bceefac1e3de3b34428 Binary files /dev/null and b/isis/src/base/apps/mat2cnet/assets/thumbs/mat2cnetGuiThumbEx1.jpg differ diff --git a/isis/src/base/apps/mat2cnet/assets/thumbs/mat2cnetGuiThumbEx2.jpg b/isis/src/base/apps/mat2cnet/assets/thumbs/mat2cnetGuiThumbEx2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8c7b9926a1d93a7b24913e350fb064c8b2734a42 Binary files /dev/null and b/isis/src/base/apps/mat2cnet/assets/thumbs/mat2cnetGuiThumbEx2.jpg differ diff --git a/isis/src/base/apps/mat2cnet/mat2cnet.cpp b/isis/src/base/apps/mat2cnet/mat2cnet.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8147742e9e26a744cfa033479244c4234d56d550 --- /dev/null +++ b/isis/src/base/apps/mat2cnet/mat2cnet.cpp @@ -0,0 +1,458 @@ +#include "Isis.h" + +#include + +#include "ControlNet.h" +#include "ControlPoint.h" +#include "FileList.h" +#include "ID.h" +#include "iException.h" +#include "Process.h" +#include "Pvl.h" +#include "SerialNumberList.h" +#include "TextFile.h" + +using namespace std; +using namespace Isis; + +std::map snMap; +//std::map fscMap; + +void IsisMain() { + // The following steps can take a significant amount of time, so + // set up a progress object, incrementing at 1%, to keep the user informed + Isis::PvlGroup &uip = Isis::Preference::Preferences().FindGroup("UserInterface"); + uip["ProgressBarPercent"] = 1; + UserInterface &ui = Application::GetUserInterface(); + Progress progress; + + // Prepare the ISIS2 list of file names + FileList list2(ui.GetFilename("LIST2")); + + // Prepare the ISIS3 SNs, pass the progress object to SerialNumberList + SerialNumberList snl(ui.GetFilename("LIST3"), true, &progress); + progress.CheckStatus(); + + if (list2.size() != (unsigned)snl.Size()) { + iString msg = "Invalid input file number of lines. The ISIS 2 file list ["; + msg += ui.GetAsString("LIST2") + "] must contain the same number of lines "; + msg += "as the ISIS 3 file list [" + ui.GetAsString("LIST3") + "]"; + throw Isis::iException::Message (Isis::iException::User, msg, _FILEINFO_); + } + + progress.SetText("Mapping Isis 2 fsc numbers to Isis 3 serial numbers."); + progress.SetMaximumSteps(list2.size()); + // Setup a map between ISIS2 image number (fsc) and ISIS3 sn + for (unsigned int f=0; f((int)fsc, sn)); + } + progress.CheckStatus(); + + // Create a new control network + ControlNet cnet; + cnet.SetType (ControlNet::ImageToGround); + cnet.SetTarget (ui.GetString("TARGET")); + cnet.SetNetworkId(ui.GetString("NETWORKID")); + cnet.SetUserName(Isis::Application::UserName()); + cnet.SetDescription(ui.GetString("DESCRIPTION")); + cnet.SetCreatedDate(Isis::Application::DateTime()); + + // Open the match point file + TextFile mpFile (ui.GetFilename("MATCH")); + iString currLine; + int inTotalMeas = 0; + + // Read the first line with the number of measurments + mpFile.GetLine (currLine); + currLine.Token("="); + currLine.Token(" "); + try{ + inTotalMeas = int(currLine); + } + catch(Isis::iException &e) { + throw iException::Message(iException::User, "Invalid match point file header for [" + + ui.GetAsString("MATCH") + + "]. First line does not contain number of measurements." + , _FILEINFO_); + } + + // Read line 2, the column header line + mpFile.GetLine (currLine); + currLine.ConvertWhiteSpace(); + currLine.Compress(); + while (currLine!= "") { + iString label = currLine.Token(" "); + // this line should contain only text labels, + double error = 0; + try { + error = label; + // if we are able to convert label to a double, we have an error + throw iException::Message(iException::User, "Invalid match point file header for [" + + ui.GetAsString("MATCH") + + "]. Second line does not contain proper non-numerical column labels." + , _FILEINFO_); + } + catch ( Isis::iException e ) { + // if this line does not contain a double, continue + if (error == 0) { + e.Clear();// not really an error, this is text value, as expected + continue; + } + // if this line contains numeric data, throw an error + else{ + throw e; + } + } + } + + // Reset the progress object for feedback about conversion processing + progress.SetText("Converting match point file"); + progress.SetMaximumSteps(inTotalMeas); + + int line = 2; + while (mpFile.GetLine(currLine)) { + line ++; + + // Update the Progress object + try { + progress.CheckStatus(); + } + catch ( Isis::iException e ) { + string msg = "\"Matchpoint total\" keyword at the top of the match point file ["; + msg += ui.GetAsString("MATCH") + "] equals [" + iString(inTotalMeas); + msg += "] and is likely incorrect. Number of measures in match point file exceeds this value at line ["; + msg += iString(line) + "]."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + + // Declare the Point and Measure + ControlPoint *cpoint; + ControlMeasure cmeasure; + + // Section the match point line into the important pieces + currLine.ConvertWhiteSpace(); + currLine.Compress(); + string pid = ""; + iString fsc = ""; + double lineNum, sampNum, diam; + string matClass = ""; + try{ + pid = currLine.Token(" "); // ID of the point + fsc = currLine.Token(" "); // FSC of the Isis 2 cube + lineNum = currLine.Token(" "); // line number + sampNum = currLine.Token(" "); // sample number + matClass = currLine.Token(" "); // Match Point Class + diam = currLine.Token(" "); // Diameter, in case of a crater + } + catch (iException &e){ + iString msg = "Invalid value(s) in match point file ["; + msg += ui.GetAsString("MATCH") + "] at line [" + iString(line); + msg += "]. Verify line, sample, diameter values are doubles."; + throw Isis::iException::Message (Isis::iException::User, msg, _FILEINFO_); + } + + // Set the coordinate and serial number for this measure + cmeasure.SetCoordinate(sampNum,lineNum); + + cmeasure.SetCubeSerialNumber(snMap[(int)fsc]); + + if(snMap[(int)fsc].empty()) { + std::string msg = "None of the images specified in the ISIS 2 file list ["; + msg += ui.GetAsString("LIST2"); + msg += "] have an IMAGE_NUMBER or IMAGE_ID that matches the FSC [" + fsc; + msg += "], from the match point file [" + ui.GetAsString("MATCH"); + msg += "] at line [" + iString(line) + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + //Set the Measure Type + if (iString::Equal(matClass,"T")) { + cmeasure.SetReference(true); + cmeasure.SetType(ControlMeasure::ValidatedManual); + } + else if (iString::Equal(matClass,"M")) { + cmeasure.SetType(ControlMeasure::ValidatedManual); + } + else if (iString::Equal(matClass,"S")) { + cmeasure.SetType(ControlMeasure::ValidatedAutomatic); + } + else if (iString::Equal(matClass,"U") && + (cmeasure.Sample() != 0.0) && (cmeasure.Line() != 0.0)) { + cmeasure.SetType(ControlMeasure::Estimated); + } + else if (iString::Equal(matClass,"U")) { + cmeasure.SetType(ControlMeasure::Unmeasured); + } + else { + iString msg = "Unknown measurment type [" + matClass + "] "; + msg += "in match point file [" + ui.GetAsString("MATCH") + "] "; + msg += "at line [" + iString(line) + "]"; + throw Isis::iException::Message (Isis::iException::User, msg, _FILEINFO_); + } + + //Set Diameter + try { + //Check to see if the column was, in fact, a double + cmeasure.SetDiameter(diam); + } + catch (iException &e) { + //If we get here, diam was not a double, + // but the error is not important otherwise + e.Clear(); + } + + //Find the point that matches the PointID, create point if it does not exist + try { + cpoint = cnet.Find(pid); + } + catch (iException &e) { + // point not found in control net, but this is not an error, so clear exception + e.Clear(); + // add point to control net, default point type is "Tie" + e.Clear(); + cnet.Add(ControlPoint(pid)); + cpoint = cnet.Find(pid); + } + + //Add the measure + try { + cpoint->Add(cmeasure); + } + catch (iException &e) { + iString msg = "Invalid match point file [" + ui.GetAsString("MATCH") + "]"; + msg += ". Repeated PointID/FSC combination [" + pid + ", " + fsc; + msg += "] in match point file at line [" + iString(line) + "]."; + throw Isis::iException::Message (Isis::iException::User, msg, _FILEINFO_); + } + } + + // Update the Progress object + try { + progress.CheckStatus(); + } + catch ( Isis::iException e ) { + string msg = "\"Matchpoint total\" keyword at the top of the match point file ["; + msg += ui.GetAsString("MATCH") + "] equals [" + iString(inTotalMeas); + msg += "] and is likely incorrect. Number of measures in match point file exceeds this value at line ["; + msg += iString(line) + "]."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + + // 10/5/2009 - Jeannie Walldren ////////////////////////////// + // Added RAND PPP file as input ////////////////////////////// + + // Open the RAND PPP file + if (ui.GetBoolean("INPUTPPP")) { + int numRandOnly = 0; + vector randOnlyIDs; + TextFile randFile(ui.GetFilename("PPP")); + progress.SetText("Converting RAND PPP file"); + randFile.GetLine(currLine); + int inTotalLine = (int) (randFile.Size()/(currLine.size())); + progress.SetMaximumSteps(inTotalLine); + randFile.Rewind(); + + line = 0; + while (randFile.GetLine(currLine)) { + line ++; + + // Update the Progress object + try { + progress.CheckStatus(); + } + catch ( Isis::iException e ) { + iString msg = "RAND PPP file may not be valid. Line count calculated ["; + msg += iString(inTotalLine) + "] for RAND PPP file [" + ui.GetAsString("PPP"); + msg += "] appears invalid at line [" + iString(line) + "]."; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Declare the Point + ControlPoint *cpoint = NULL; + + // if end of valid data, break, stop processing + if (currLine.find("JULIAN") != string::npos) { + // Since Progress MaximumSteps was approximated using the number of lines in the RAND PPP file, + // we need to subtract the number of lines left from the Progress steps + // since the following lines are not going to be processed + progress.AddSteps(line-inTotalLine); // line < inTotalLine, so this is negative + break; + } + + // break columns into substrings since some files have colunms that can't be tokenized easily. + // This is because some files have columns running into each other without spaces separating them + + // column 1 = latitude, begins the line and is 24 characters + double lat; + iString col1 = currLine.substr(0,24); + // remove any white space from beginning of string + //col1.ConvertWhiteSpace(); + //col1.TrimHead(" "); + try{ + // convert to double + lat = col1; + } + catch (Isis::iException &e){ + iString msg = "Invalid value(s) in RAND PPP file ["; + msg += ui.GetAsString("PPP") + "] at line [" + iString(line); + msg += "]. Verify latitude value is a double."; + throw Isis::iException::Message (Isis::iException::User, msg, _FILEINFO_); + } + + // column 2 = longitude, begins at 25th char and is 24 characters + double lon; + iString col2 = currLine.substr(24,24); + // remove any white space from beginning of string + //col2.TrimHead(" "); + try{ + // convert to double + lon = col2; + } + catch (Isis::iException &e){ + iString msg = "Invalid value(s) in RAND PPP file ["; + msg += ui.GetAsString("PPP") + "] at line [" + iString(line); + msg += "]. Verify longitude value is a double."; + throw Isis::iException::Message (Isis::iException::User, msg, _FILEINFO_); + } + + // column 3 = radius, begins at 49th char and is 24 characters + double rad; + iString col3 = currLine.substr(48,24); + // remove any white space from beginning of string + //col3.TrimHead(" "); + try{ + // convert to double and convert km to meters + rad = col3; + rad = rad*1000; + } + catch (Isis::iException &e){ + iString msg = "Invalid value(s) in RAND PPP file ["; + msg += ui.GetAsString("PPP") + "] at line [" + iString(line); + msg += "]. Verify radius value is a double."; + throw Isis::iException::Message (Isis::iException::User, msg, _FILEINFO_); + } + + // column 4 = point id, begins at 73rd char and is 7 characters + iString pid = currLine.substr(72); + // remove any white space from beginning of string + pid.TrimHead(" "); + if (pid.length() > 7) { + iString msg = "Invalid value(s) in RAND PPP file ["; + msg += ui.GetAsString("PPP") + "] at line [" + iString(line); + msg += "]. Point ID [" + pid + "] has more than 7 characters."; + throw Isis::iException::Message (Isis::iException::User, msg, _FILEINFO_); + } + + //Find the point that matches the PointID, create it if it does not exist + try { + cpoint = cnet.Find(pid); + // if the point exists in the matchpoint file and rand file, set it to ground + if(ui.GetString("POINTTYPE") == "GROUND") { + cpoint->SetType(ControlPoint::Ground); + } + } + catch (iException &e) { + // point not found in control net means it was not in the matchpoint file, + // but this is not an error, so clear exception + e.Clear(); + // do not add the point to the control net, but save off the currLine for output log + numRandOnly++; + randOnlyIDs.push_back(currLine); + } + + if(cpoint != NULL) { + //Add the lat,lon,rad to point + try { + cpoint->SetUniversalGround(lat,lon,rad); + } + catch (iException &e) { + iString msg = "Unable to set universal ground point to control network from line ["; + msg += iString(line) + "] of RAND PPP file [" + ui.GetAsString("PPP") + "]"; + throw Isis::iException::Message (Isis::iException::User, msg, _FILEINFO_); + } + } + } + // Update the Progress object + try { + progress.CheckStatus(); + } + catch ( Isis::iException e ) { + iString msg = "RAND PPP file may not be valid. Line count calculated ["; + msg += iString(inTotalLine) + "] for RAND PPP file [" + ui.GetAsString("PPP"); + msg += "] appears invalid at line [" + iString(line) + "]."; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Write results to Logs + // Summary group is created with the counts of RAND PPP only points + PvlGroup summaryGroup = PvlGroup("Summary"); + summaryGroup.AddKeyword(PvlKeyword("RandOnlyPoints", numRandOnly)); + + bool log; + Filename logFile; + // if a filename was entered, use it to create the log + if (ui.WasEntered("PPPLOG")) { + log = true; + logFile = ui.GetFilename("PPPLOG"); + } + // if no filename was entered, but there were some RAND PPP only points, + // create an log named "randOnlyPoints" in the current directory + else if (numRandOnly > 0) { + log = true; + logFile = "randOnlyPoints.log"; + } + // if all RAND PPP points are found in the MATCH file and no log file is named, + // only output summary to application log + else { + log = false; + } + + if (log) { + // Write details in error log + Pvl results; + results.SetName("Results"); + results.AddGroup(summaryGroup); + if (numRandOnly > 0) { + // if there are any RAND PPP only points, + // add comment to the summary log to alert user + summaryGroup.AddComment("Some Point IDs in the RAND PPP file have no measures in the MATCH file."); + summaryGroup.AddComment("These Point IDs are contained in [" + logFile.Name() + "]."); + TextFile outlog(logFile.Expanded(), "overwrite", randOnlyIDs); + } + else{ + // if there are no RAND PPP only points and user wanted to create a log, + // add comment to the summary log to alert user + summaryGroup.AddComment("All Point IDs in the RAND PPP file have measures in the MATCH file."); + summaryGroup.AddComment("No RAND PPP log was created."); + } + } + // Write summary to application log + Application::Log(summaryGroup); + + } + // Write the control network out + cnet.Write(ui.GetFilename("CNET")); + + +} diff --git a/isis/src/base/apps/mat2cnet/mat2cnet.xml b/isis/src/base/apps/mat2cnet/mat2cnet.xml new file mode 100644 index 0000000000000000000000000000000000000000..c2d82e067342e9c9f0ff2a63f70651799d0e2aea --- /dev/null +++ b/isis/src/base/apps/mat2cnet/mat2cnet.xml @@ -0,0 +1,460 @@ + + + + + Converts an Isis2 match point file to an Isis3 control network file. + + + +

    + This program converts an Isis2 match point file to an Isis3 control + network file. It requires a list file of Isis 2 cubes and corresponding + list file of Isis 3 cubes. There should be the same number of cubes in + each list and they should be listed in corresponding order. This + application also requires a match point file, an output Control Network + pvl name, a network ID, a target and a description. The user may also + choose whether to input a RAND PPP file containing latitude, longitude + and radius for each corresponding point ID and to create an output RAND + PPP log. This program converst the radius values in these files from km + to meters before adding them to the output control network. If a RAND + PPP file is not entered, all the points in the MATCH file will be set to + type TIE. If a RAND PPP is input, then any points not found in this file + will still be set to TIE and the user may choose whether to set points + found in both the RAND and MATCH files to GROUND or TIE. Any points + found in the RAND file without measurements in the MATCH file will not be + included in the output control net. The corresponding lines from the + RAND PPP file for these points will be copied to the RAND PPP log. +

    +
    + + + Control Networks + Import and Export + + + + + Original version + + + Now IMAGE_NUMBER will be used before IMAGE_ID for matching files + + + Fixed bug where serial numbers were not correct. + + + Error message added for missing FSC's + + + Added exception message when the given MATCH file's "Matchpoint total" + keyword is less than the number of actual Match Points in the file. + + + Added RAND input parameter and updated documentation. Added exception + messages for invalid match point file headers and values. Added 1% + Progress updates to show potentially slower steps. Added appTests for + RAND parameter and to catch errors. Added examples to xml file. + + + Modify code to allow use of particular types of edited RAND files. + Updated description of RAND parameter to reflect this change. + + + Convert RAND radius values from kilometers to meters. Added option to + + + Added option to create RAND only points (no measures in the matchpoint + file) as GROUND points. + + + Modified error messages to output filename typed in by user rather than + entire path. + + + Changed CONTROL parameter name to CNET for consistency with other ISIS3 + programs. Added INPUTPPP parameter. Changed parameter name from RAND to + PPP for more precise description and modified POINTTYPE parameter usage. + Added results to GUI log and added output PPPLOG parameter. + + + + + + + + + filename + input + + List of Isis2 input cubes in the match point file. + + + A text file containing one column of Isis 2 cube file names. Every + file used in the match point file should be represented in this list. + The cubes must be available for the program to open and must be in the + same order as the Isis 3 cubes in LIST3. An error will be thrown if + the number of files in this list does not match the number of files in + LIST2, or if the IMAGE_ID and IMAGE_NUMBER keywords are not found in + any Isis 2 cube. + + + *.lis *.txt *.lst + + + + + filename + input + + Isis2 match point file + + + Use this parameter to specify the Isis2 match point file to be + converted to an Isis3 control network file. This file must contain a + two line header. The first line of the header must have the + "Matchpoint Total" keyword and a value for the number of measures in + the match point file. The second line of the header should be text + labels for each column. The match point file has 7 columns: PointID, + FSC, LINE, SAMP, CLASS, DIAMETER, and Comments. The Point ID is + made up of alphanumeric characters, FSC is an integer, LINE and SAMP + must be doubles. CLASS is used to determine the measure type. Valid + values include T (set to reference measure, validated manual), M + (validated manual), S (validated automatic), or U (if line/samp=0/0, + set unmeasured, otherwise set estimated). The DIAMETER column is + used in the case of a crater. Comments are not read in to this + application. A match point file may only have one line for a + particular PointID/FSC combination, otherwise an error will be thrown + since there is no way to determine which line contains correct values. + + + *.mat *.dat *.txt *.tbl + + + + + boolean + Input a RAND PPP file + + This parameter indicates whether a RAND PPP (Pole, Point, Picture) + file will be input. Valid RAND PPP files for mat2cnet are detailed + in the PPP parameter description. + + FALSE + + PPP + POINTTYPE + PPPLOG + + + + + filename + input + + RAND PPP file containing latitude, longitude, and radius values for + given Point IDs. + + + Use this parameter to specify the RAND PPP file to assign lat/lon/rad + values associated with corresponding point IDs from the MATCH file. + These files do not contain headers and have 4 unlabeled columns: + LATITUDE, LONGITUDE, RADIUS, and PointID. The lines of original RAND + PPP files have exactly 79 characters, and columns are right justified + with specific lengths, namely, 24, 24, 24, and 7. The only edited + RAND PPP files that are valid for this program are those that have a + single space added between the RADIUS and the PointID. LATITUDE, + LONGITUDE, and RADIUS values must be doubles and PointID is + alphanumeric. If this file contains a Point ID that does not exist + in the match point file, it will not be added to the ControlNet + output and the corresponding lines from the RAND PPP file will be + copied to the PPPLOG output file. + + + *.ppp *.dat + + + INPUTPPP + + + + + string + GROUND + + ControlPoint type for points found in RAND PPP and MATCH files. + + + This parameter determines the ControlPoint type to which points will + be set if they are found in the RAND PPP file and have corresponding + measurements in the MATCH file. This parameter defaults to GROUND. + Note: All points from the MATCH file not found in + the RAND PPP file will be set to TIE and all points from the RAND PPP + file not found in the MATCH file will be omitted from the output + Control Network. + + + + + + + + + + INPUTPPP + + + + + + + + filename + input + + List of Isis3 input cubes in the match point file. + + + A text file containing one column of Isis 3 cube file names. Every + file used in the match point file should be represented in this list. + The cubes must be available for the program to open and must be in the + same order as the Isis 2 cubes in LIST2. An error will be thrown if + the number of files in this list does not match the number of files in + LIST2. + + + *.lis *.txt *.lst + + + + + filename + output + + Isis3 output control network file + + + Use this parameter to specify the file name of the output Isis3 + control network. + + + *.net *.pvl *.ctl *.cnet + + + + + + + + string + + The description of this output control network. + + + A string describing this control network. + + + + + string + + Name of the output control network + + + The ID or name of this particular control network. This string + should be unique. + + + + + string + + The target body of the control network. + + + The targeted planet or body for the control points and measures in + this control network. + + + + + + + + filename + output + No Log Output + + Optional RAND PPP log file. + + + This file will contain the Point IDs of all control points that were + found in the RAND PPP file but had no measurements in the MATCH file. + + + *.log *.txt + + + INPUTPPP + + + + + + + + + Create control net from match point file + + This example demonstrates how to use the mat2cnet + application to create a control network from a match point file. In + this case, no RAND PPP file is used. + + + + list2=../IN/isis2cubes.lis match=../IN/matchpointfile.mat + list3=../IN/isis3cubes.lis control=../OUT/controlnet.net + description="Default Test Network" networkid= TestNet01 target=Titan + + + Run the mat2cnet application to create a ControlNet + file from a match point file with corresponding Isis2 cubelist and + Isis3 cubelist + + + + + + Example Gui + + Screenshot of GUI with parameters filled in to perform the + mat2cnet application. The RAND PPP parameter is left + as the default of "None". + + + + + + + + Example of match point file. + + This text file is an example of a valid match point file with proper + header and columns. + + + MATCH + + + + Example of control net file. + + This pvl file is an example of the output control network created + from the given match point file. Notice the NetworkId, TargetName, + and Description are assigned the values from the command line. + + + CONTROL + + + + + + + Create control net from match point file and RAND PPP file + + This example demonstrates how to use the mat2cnet + application to create a control network from a match point file and + corresponding RAND PPP file. + + + + list2=../IN/isis2cubes.lis match=../IN/matchpt.mat inputppp=true + ppp=../IN/rand.ppp list3=../IN/isis3cubes.lis + control=../OUT/control.net description="RAND PPP Test Network" + networkid= TestNet02 target=Titan + + + Run the mat2cnet application to create a ControlNet + file from a match point file with corresponding Isis2 cubelist, Isis3 + cubelist, RAND PPP file with a default point type of ground. + + + + + + Example Gui + + Screenshot of GUI with parameters filled in to perform the + mat2cnet application with a RAND PPP file. + + + + + + + + Example of match point file. + + This text file is an example of a valid match point file with proper + header and columns. + + + MATCH + + + + Example of RAND PPP file. + + This text file is an example of a valid RAND PPP file. + Notice that there are 2 points in this file to add. + + + PPP + + + + Example of control net file. + + This pvl file is an example of the output control network created + from the given match point file and RAND PPP file. Notice the + following: the first point in the RAND PPP file has 3 measures in + the MATCH file and is written to the control network as type GROUND + and the second point in the RAND PPP file is not contained in the + Control Network since there are no measures with this ID in the + MATCH file. + + + CONTROL + + + + Example of RAND PPP output log file. + + This text file is an example of the output RAND PPP log created when + there are points in the RAND PPP file that do not have measures in + the MATCH file. + + + CONTROL + + + + + +
    diff --git a/isis/src/base/apps/mat2cnet/tsts/Makefile b/isis/src/base/apps/mat2cnet/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/mat2cnet/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/mat2cnet/tsts/case01/Makefile b/isis/src/base/apps/mat2cnet/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a635aa6cacff0bc145d36e1b2c9003a4741d5429 --- /dev/null +++ b/isis/src/base/apps/mat2cnet/tsts/case01/Makefile @@ -0,0 +1,16 @@ +APPNAME = mat2cnet + +include $(ISISROOT)/make/isismake.tsts + +commands: + ls $(INPUT)/Isis2_cube*.cub >& $(OUTPUT)/cub2.lis; + ls $(INPUT)/Isis3_cube*.cub >& $(OUTPUT)/cub3.lis; + $(APPNAME) list2=$(OUTPUT)/cub2.lis \ + match=$(INPUT)/pts.mat \ + list3=$(OUTPUT)/cub3.lis \ + cnet=$(OUTPUT)/mat2cnetTruth1.pvl \ + description="Default Test Network" \ + networkid=TestNet01 \ + target=Titan > /dev/null; + rm -f $(OUTPUT)/cub2.lis; + rm -f $(OUTPUT)/cub3.lis; diff --git a/isis/src/base/apps/mat2cnet/tsts/errors/Makefile b/isis/src/base/apps/mat2cnet/tsts/errors/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4dde3c47e1b6d74c72976dc2176549aed41998be --- /dev/null +++ b/isis/src/base/apps/mat2cnet/tsts/errors/Makefile @@ -0,0 +1,81 @@ +.IGNORE: + +APPNAME = mat2cnet + +include $(ISISROOT)/make/isismake.tsts + +commands: + ls $(INPUT)/Isis3_cube*.cub >& $(OUTPUT)/cub3.lis; + $(APPNAME) list2=$(INPUT)/cub2.lis \ + match=$(INPUT)/match.mat \ + list3=$(OUTPUT)/cub3.lis \ + cnet=$(OUTPUT)/out.pvl \ + description="Isis2 list has different number of lines from Isis3 list" \ + networkid=TestNet01 \ + target=Titan 2> $(OUTPUT)/error1.txt > /dev/null; + ls $(INPUT)/Isis2_cube*.cub >& $(OUTPUT)/cub2.lis; + $(APPNAME) list2=$(OUTPUT)/cub2.lis \ + match=$(INPUT)/match_noMatchptKeywd.mat \ + list3=$(OUTPUT)/cub3.lis \ + cnet=$(OUTPUT)/out.pvl \ + description="Invalid MATCH file header format - missing number of measurements" \ + networkid=TestNet02 \ + target=Titan 2>> $(OUTPUT)/error1.txt > /dev/null; + $(APPNAME) list2=$(OUTPUT)/cub2.lis \ + match=$(INPUT)/match_noColumnLabels.mat \ + list3=$(OUTPUT)/cub3.lis \ + cnet=$(OUTPUT)/out.pvl \ + description="Invalid MATCH file header format - second line not labels" \ + networkid=TestNet03 \ + target=Titan 2>> $(OUTPUT)/error1.txt > /dev/null; + $(APPNAME) list2=$(OUTPUT)/cub2.lis \ + match=$(INPUT)/match_invalidKeyword.mat \ + list3=$(OUTPUT)/cub3.lis \ + cnet=$(OUTPUT)/out.pvl \ + description="Invalid MATCH file - Matchpoint total less than number of measurements found" \ + networkid=TestNet04 \ + target=Titan 2>> $(OUTPUT)/error1.txt > /dev/null; + $(APPNAME) list2=$(OUTPUT)/cub2.lis \ + match=$(INPUT)/match_invalidMeasType.mat \ + list3=$(OUTPUT)/cub3.lis \ + cnet=$(OUTPUT)/out.pvl \ + description="Invalid MATCH file - unknown measurement type" \ + networkid=TestNet05 \ + target=Titan 2>> $(OUTPUT)/error1.txt > /dev/null; + $(APPNAME) list2=$(OUTPUT)/cub2.lis \ + match=$(INPUT)/match_repeatedPointID.mat \ + list3=$(OUTPUT)/cub3.lis \ + cnet=$(OUTPUT)/out.pvl \ + description="Invalid MATCH file - repeated pointID/fsc combination" \ + networkid=TestNet06 \ + target=Titan 2>> $(OUTPUT)/error1.txt > /dev/null; + $(APPNAME) list2=$(OUTPUT)/cub2.lis \ + match=$(INPUT)/match_invalidLineSamp.mat \ + list3=$(OUTPUT)/cub3.lis \ + cnet=$(OUTPUT)/out.pvl \ + description="Invalid MATCH file - sample/line/diameter not a double" \ + networkid=TestNet07 \ + target=Titan 2>> $(OUTPUT)/error1.txt > /dev/null; + $(APPNAME) list2=$(OUTPUT)/cub2.lis \ + match=$(INPUT)/match.mat \ + inputppp=true \ + ppp=$(INPUT)/rand_invalidLineCount.ppp \ + list3=$(OUTPUT)/cub3.lis \ + cnet=$(OUTPUT)/out.pvl \ + description="Invalid RAND file - line count less than points found" \ + networkid=TestNet09 \ + target=Titan 2>> $(OUTPUT)/error1.txt > /dev/null; + $(APPNAME) list2=$(OUTPUT)/cub2.lis \ + match=$(INPUT)/match.mat \ + inputppp=true \ + ppp=$(INPUT)/rand_invalidLatLonRad.ppp \ + list3=$(OUTPUT)/cub3.lis \ + cnet=$(OUTPUT)/out.pvl \ + description="Invalid RAND file - lat/lon/rad not a double" \ + networkid=TestNet10 \ + target=Titan 2>> $(OUTPUT)/error1.txt > /dev/null; + cat $(OUTPUT)/error1.txt | sed s+/usgs/cpkgs/isis3/testData/isis/src/base/apps/mat2cnet/tsts/errors/++g > $(OUTPUT)/error.txt; + rm -f $(OUTPUT)/error1.txt; + rm -f $(OUTPUT)/out.pvl; + rm -f $(OUTPUT)/cub2.lis; + rm -f $(OUTPUT)/cub3.lis; diff --git a/isis/src/base/apps/mat2cnet/tsts/pointtype/Makefile b/isis/src/base/apps/mat2cnet/tsts/pointtype/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3b8875a1bc5246c65205596c35910575de47809e --- /dev/null +++ b/isis/src/base/apps/mat2cnet/tsts/pointtype/Makefile @@ -0,0 +1,20 @@ +APPNAME = mat2cnet + +include $(ISISROOT)/make/isismake.tsts + +commands: + ls $(INPUT)/Isis2_cube*.cub >& $(OUTPUT)/cub2.lis; + ls $(INPUT)/Isis3_cube*.cub >& $(OUTPUT)/cub3.lis; + $(APPNAME) list2=$(OUTPUT)/cub2.lis \ + match=$(INPUT)/pts.mat \ + inputppp=true \ + ppp=$(INPUT)/rand.ppp \ + list3=$(OUTPUT)/cub3.lis \ + cnet=$(OUTPUT)/mat2cnetTruth3.pvl \ + pointtype=Tie \ + description="PointTypeTie Test Network" \ + networkid=TestNet03 \ + target=Titan > /dev/null; + mv randOnlyPoints.log $(OUTPUT)/randOnlyPoints.txt; + rm -f $(OUTPUT)/cub2.lis; + rm -f $(OUTPUT)/cub3.lis; diff --git a/isis/src/base/apps/mat2cnet/tsts/rand/Makefile b/isis/src/base/apps/mat2cnet/tsts/rand/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..90e223947a360aa378cdbac5a01d95332b04b038 --- /dev/null +++ b/isis/src/base/apps/mat2cnet/tsts/rand/Makefile @@ -0,0 +1,19 @@ +APPNAME = mat2cnet + +include $(ISISROOT)/make/isismake.tsts + +commands: + ls $(INPUT)/Isis2_cube*.cub >& $(OUTPUT)/cub2.lis; + ls $(INPUT)/Isis3_cube*.cub >& $(OUTPUT)/cub3.lis; + $(APPNAME) list2=$(OUTPUT)/cub2.lis \ + match=$(INPUT)/match.mat \ + inputppp=true \ + ppp=$(INPUT)/rand.ppp \ + list3=$(OUTPUT)/cub3.lis \ + cnet=$(OUTPUT)/mat2cnetTruth2.pvl \ + description="Rand Test Network - Default Ground Point Type" \ + networkid=TestNet02 \ + target=Titan \ + ppplog=$(OUTPUT)/randppp.txt > /dev/null; + rm -f $(OUTPUT)/cub2.lis; + rm -f $(OUTPUT)/cub3.lis; diff --git a/isis/src/base/apps/median/Makefile b/isis/src/base/apps/median/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/median/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/median/assets/images/15x15gui.jpg b/isis/src/base/apps/median/assets/images/15x15gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6d4e3e9a45ca2ff7ea7a0ec3db58bd1769d1ba0d Binary files /dev/null and b/isis/src/base/apps/median/assets/images/15x15gui.jpg differ diff --git a/isis/src/base/apps/median/assets/images/15x15median.jpg b/isis/src/base/apps/median/assets/images/15x15median.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6d3888b9939db70b5c5e896fa83b9c2f2ca77c8b Binary files /dev/null and b/isis/src/base/apps/median/assets/images/15x15median.jpg differ diff --git a/isis/src/base/apps/median/assets/images/3x3gui.jpg b/isis/src/base/apps/median/assets/images/3x3gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..133e4f3adcc66e9869b8761f07df01c86660ae9a Binary files /dev/null and b/isis/src/base/apps/median/assets/images/3x3gui.jpg differ diff --git a/isis/src/base/apps/median/assets/images/3x3median.jpg b/isis/src/base/apps/median/assets/images/3x3median.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f6112e8bd32244b7c8618c0a3e3ea20aaa36c87e Binary files /dev/null and b/isis/src/base/apps/median/assets/images/3x3median.jpg differ diff --git a/isis/src/base/apps/median/assets/images/input.jpg b/isis/src/base/apps/median/assets/images/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8ad824f8b8b6b3168fba1fd50b6de37eb5bdbc7c Binary files /dev/null and b/isis/src/base/apps/median/assets/images/input.jpg differ diff --git a/isis/src/base/apps/median/assets/thumbs/15x15gui.jpg b/isis/src/base/apps/median/assets/thumbs/15x15gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1710abf0f0d6e37e75314733497175eb5657f0fe Binary files /dev/null and b/isis/src/base/apps/median/assets/thumbs/15x15gui.jpg differ diff --git a/isis/src/base/apps/median/assets/thumbs/15x15median.jpg b/isis/src/base/apps/median/assets/thumbs/15x15median.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ccfd950fcfe0a48c99dc66ce867926298ed147b5 Binary files /dev/null and b/isis/src/base/apps/median/assets/thumbs/15x15median.jpg differ diff --git a/isis/src/base/apps/median/assets/thumbs/3x3gui.jpg b/isis/src/base/apps/median/assets/thumbs/3x3gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6d619cc6fa98c7335bdb8ca36269e272699563bf Binary files /dev/null and b/isis/src/base/apps/median/assets/thumbs/3x3gui.jpg differ diff --git a/isis/src/base/apps/median/assets/thumbs/3x3median.jpg b/isis/src/base/apps/median/assets/thumbs/3x3median.jpg new file mode 100644 index 0000000000000000000000000000000000000000..57b8abc9e3547f8f2cf2674de0071c9290446191 Binary files /dev/null and b/isis/src/base/apps/median/assets/thumbs/3x3median.jpg differ diff --git a/isis/src/base/apps/median/assets/thumbs/input.jpg b/isis/src/base/apps/median/assets/thumbs/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c60ac95b9cdaa5da49f7335ba4f6c208e3aee70c Binary files /dev/null and b/isis/src/base/apps/median/assets/thumbs/input.jpg differ diff --git a/isis/src/base/apps/median/median.cpp b/isis/src/base/apps/median/median.cpp new file mode 100644 index 0000000000000000000000000000000000000000..abb89b1ef5b788aba7856bad0e7e12a5ea599123 --- /dev/null +++ b/isis/src/base/apps/median/median.cpp @@ -0,0 +1,265 @@ +#include "Isis.h" +#include "ProcessByBoxcar.h" +#include "SpecialPixel.h" +#include +#include + +using namespace std; +using namespace Isis; + +bool filterNull; +bool filterHrs; +bool filterHis; +bool filterLrs; +bool filterLis; +double low; +double high; +bool propagate; +unsigned int minimum; + +void FilterAll(Buffer &in, double &v); +void FilterValid(Buffer &in, double &v); +void FilterInvalid(Buffer &in, double &v); + +void IsisMain(){ + //Set up ProcessByBoxcar + ProcessByBoxcar p; + + //Obtain input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + + //Set up Boxcar size + UserInterface &ui = Application::GetUserInterface(); + int samples = ui.GetInteger("SAMPLES"); + int lines = ui.GetInteger("LINES"); + p.SetBoxcarSize(samples, lines); + + //Determine which pixels are valid, and how many are + //necessary for processing + filterNull = ui.GetBoolean("NULL"); + filterHrs = ui.GetBoolean("HRS"); + filterLrs = ui.GetBoolean("LRS"); + filterHis = ui.GetBoolean("HIS"); + filterLis = ui.GetBoolean("LIS"); + if (ui.GetString("MINOPT") == "PERCENTAGE") { + int size = lines * samples; + double perc = ui.GetDouble("MINIMUM") / 100; + minimum = (int) (size * perc); + } + else { + minimum = (int) ui.GetDouble("MINIMUM"); + } + low = -DBL_MAX; + high = DBL_MAX; + if (ui.WasEntered("LOW")){ + low = ui.GetDouble("LOW"); + } + if (ui.WasEntered("HIGH")){ + high = ui.GetDouble("HIGH"); + } + + //Determine what to do if there are too few + //non-Special pixels + propagate = (ui.GetString("REPLACEMENT") == "CENTER"); + + //Check for filter style, and process accordingly + if (ui.GetString("FILTER") == "ALL"){ + p.StartProcess(FilterAll); + p.EndProcess(); + } + else if (ui.GetString("FILTER") == "INSIDE"){ + p.StartProcess(FilterValid); + p.EndProcess(); + } + else if (ui.GetString("FILTER") == "OUTSIDE"){ + p.StartProcess(FilterInvalid); + p.EndProcess(); + } +} + +//Function which loops through every pixel in the boxcar, +//and outputs the median value to the center pixel, if +//the center pixel is valid. +void FilterValid(Buffer &in, double &v){ + double centerPixel = in[(in.size()-1)/2]; + + //Check if the center pixel is a Special Pixel type to be + //filtered. If not, ignore the pixel and move on + if (IsSpecial(centerPixel) ){ + if ((IsNullPixel(centerPixel)) && (!filterNull)) { + v = centerPixel; + return; + } + else if ((IsLisPixel(centerPixel)) && (!filterLis)) { + v = centerPixel; + return; + } + else if ((IsLrsPixel(centerPixel)) && (!filterLrs)) { + v = centerPixel; + return; + } + else if ((IsHisPixel(centerPixel)) && (!filterHis)) { + v = centerPixel; + return; + } + else if ((IsHrsPixel(centerPixel)) && (!filterHrs)) { + v = centerPixel; + return; + } + } + else if (centerPixelhigh){ + v = centerPixel; + return; + } + + //Build a vector containing the non-Special pixel values + //from the input buffer. If there are not enough to meet + //the minimum requirements, write a user-selected value + //to the center. If there are, sort the vector and write + //the median value to the center. + std::vector boxdata(0); + for (int i=0; i=low && in[i]<=high){ + boxdata.push_back(in[i]); + } + else{ + continue; + } + } + if (boxdata.size()=low && centerPixel<=high){ + v = centerPixel; + return; + } + + //Build a vector of non-Special pixel values from the + //input boxcar, then sort and find the median value. + //If there aren't enough to meet the minimum requirements, + //write a user-selected value to the center pixel. + std::vector boxdata(0); + + for (int i=0; i=low && in[i]<=high){ + boxdata.push_back(in[i]); + } + else{ + continue; + } + } + if (boxdata.size() boxdata(0); + + for (int i=0; i=low && in[i]<=high){ + boxdata.push_back(in[i]); + } + else{ + continue; + } + } + if (boxdata.size() + + + + + Set pixels to median of surrounding pixel values + + + + This program accepts a user-defined boxcar and loops + through the input image. It finds the median pixel + value in the boxcar, and sets the output center pixel + to that median value. This will acheive a + "blurring" effect, similar to the lowpass filter. + + + + Filters + + + + + Original version + + + Added Minopt parameter, modified user interface + + + Modified user interface + + + + + + + cube + input + + Input Cube + + + This is the cube from which we will gather our data. + + *.cub + + + + cube + output + + Output Cube + + + This is the cube to which we will write the modified + data. + + *.cub + + + + + + integer + + Number of samples in Boxcar + + + This will determine how many samples the boxcar will + have. This value must be odd and cannot exceed + twice the number of samples in the cube. Note that + the larger the boxcar size, the slower the program + will run. The size of the boxcar will also have an + impact on the blurring effect. The larger the boxcar, + the greater the blurring. + + 1 + + + + + integer + + Number of lines in Boxcar + + + This will determine how many lines the boxcar will + have. This value must be odd and cannot exceed + twice the number of lines in the cube. Note that + the larger the boxcar size, the slower the program + will run. The size of the boxcar will also have an + impact on the blurring effect. The larger the boxcar, + the greater the blurring. + + 1 + + + + + + + double + + The minimum value of a valid pixel + + + This value indicates the minimum value of a valid + pixel. If a pixel holds a value below the minimum + value, it will either be filtered or skipped over, + depending on user input in the "Filter Style" + area. + + Use all + HIGH + + + + double + + The maximum value of a valid pixel + + + This value indicates the maximum value of a valid + pixel. If a pixel holds a value over the maximum + value, it will either be excluded or included, + depending on user input in the "Filter Style" + area. + + Use all + LOW + + + + string + + COUNT + + + Sets minimum to be either a count or a percentage + + + This parameter determines whether the minimum + parameter is to be interpreted as a count of pixels, or a + percentage of all pixels in the boxcar. + + + + + + + + + + double + 1 + + Minimum boxcar pixels required for filter + + + This is the minimum number of valid pixels + required in a boxcar for filtering to begin. + + + + + string + + CENTER + + + Replacement value if minimum number of pixels + does not exist + + + This determines what to put in the center pixel, + if there are not enough valid pixels in the boxcar + to meet the minimum requirement. The default is to + replace it with the current value, and the other option + will replace it with NULL. + + + + + + + + + + + + + string + + ALL + + + The style of filtration + + + These options determine which pixels are to be included in the filtering + process. ALL filters all pixels, regardless of value, VALID only filters + those pixels with values between LOW and HIGH, and INVALID only + filters those pixels with values outside LOW and HIGH. Note that these + only determine which Non-Special pixels to filter. Also, the median will + only be calculated from pixel values between LOW and HIGH. + + + + + + + + + + + + + + + boolean + TRUE + + Filter NULL Pixels + + + This determines whether NULL pixels are considered valid for the + purposes of filtering. This, along with the user input in the + "Filter Style" section, will determine whether NULL pixels are + included in the filter. + + + + + boolean + TRUE + + Filter HRS Pixels + + + This determines whether HRS pixels are considered valid for the + purposes of filtering. This, along with the user input in the + "Filter Style" section, will determine whether HRS pixels are + included in the filter. + + + + + boolean + TRUE + + Filter HIS Pixels + + + This determines whether HIS pixels are considered valid for the + purposes of filtering. This, along with the user input in the + "Filter Style" section, will determine whether HIS pixels are + included in the filter. + + + + + boolean + TRUE + + Filter LRS Pixels + + + This determines whether LRS pixels are considered valid for the + purposes of filtering. This, along with the user input in the + "Filter Style" section, will determine whether LRS pixels are + included in the filter. + + + + + boolean + TRUE + + Filter LIS Pixels + + + This determines whether LIS pixels are considered valid for the + purposes of filtering. This, along with the user input in the + "Filter Style" section, will determine whether LIS pixels are + included in the filter. + + + + + + + + + Running median with a 3x3 boxcar + + + This demonstrates running the median program on a sample + cube using a 3x3 boxcar. + + + + from= peaks.cub + to=3x3median.cub + samples=3 + lines=3 + + + This demonstrates the commands necessary to run median on + a file named "peaks.cub" with a 3x3 boxcar. The small size of the boxcar + will only produce a slight blur. + + + + + + + + Example GUI + + + Screenshot of the GUI set to filter all pixels for the image + using a 3x3 boxcar. + + + + + + + + + + Input image before medain filter + + + This is the original cube. The areas of greatest interest are + those with a great deal of contrast such as edges. + + + FROM + + + + + + + Output of 3x3 boxcar median filter + + + This is the image after the filter. You may notice that the whole + image is slightly softer, particularly around areas of sharp + contrast. Due to the small size of the boxcar, the effect is + subtle and difficult to notice. + + + TO + + + + + + + Running median with a 15x15 boxcar + + + This demonstrates running the median program on a sample + cube using a 15x15 boxcar. + + + + from= peaks.cub + to=15x15median.cub + samples=15 + lines=15 + + + This demonstrates the commands necessary to run median on + a file named "peaks.cub" with a 15x15 boxcar. The large size + of the boxcar produces a marked blurring effect. + + + + + + + + Example GUI + + + Screenshot of the GUI set to filter all pixels for the image + using a 15x15 boxcar. + + + + + + + + + + Input image before medain filter + + + This is the original cube. The areas of greatest interest are + those with a great deal of contrast such as edges. + + + FROM + + + + + + + Output of 3x3 boxcar median filter + + + This is the output image for a 15x15 boxcar. You will notice + the entire image is noticeably blurrier. It is now virtually + impossible to make out any but the largest of features. + + + TO + + + + + diff --git a/isis/src/base/apps/median/tsts/Makefile b/isis/src/base/apps/median/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/median/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/median/tsts/case01/Makefile b/isis/src/base/apps/median/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f0cd26e464b14e9d263e34bc61904fe58f6bede5 --- /dev/null +++ b/isis/src/base/apps/median/tsts/case01/Makefile @@ -0,0 +1,9 @@ +APPNAME = median + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/medianTruth.cub \ + samples=3 \ + lines=3> /dev/null; diff --git a/isis/src/base/apps/minmax/Makefile b/isis/src/base/apps/minmax/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/minmax/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/minmax/assets/images/max2x2.jpg b/isis/src/base/apps/minmax/assets/images/max2x2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fbb50e017fefad9ecb9ce8f6893a6b33b38133d4 Binary files /dev/null and b/isis/src/base/apps/minmax/assets/images/max2x2.jpg differ diff --git a/isis/src/base/apps/minmax/assets/images/max2x2gui.jpg b/isis/src/base/apps/minmax/assets/images/max2x2gui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..74adb74edc3e06fa1497c08555513e5ef517daa9 Binary files /dev/null and b/isis/src/base/apps/minmax/assets/images/max2x2gui.jpg differ diff --git a/isis/src/base/apps/minmax/assets/images/min3x3.jpg b/isis/src/base/apps/minmax/assets/images/min3x3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..294913e044e1ecb2aa9968703cf5609446865f4c Binary files /dev/null and b/isis/src/base/apps/minmax/assets/images/min3x3.jpg differ diff --git a/isis/src/base/apps/minmax/assets/images/min3x3gui.jpg b/isis/src/base/apps/minmax/assets/images/min3x3gui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..66ac06b69c4223a4acdf49870dbff58ac18d4e4e Binary files /dev/null and b/isis/src/base/apps/minmax/assets/images/min3x3gui.jpg differ diff --git a/isis/src/base/apps/minmax/assets/images/peaks.jpg b/isis/src/base/apps/minmax/assets/images/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..22ee658b0c230aec89f3564c1e4b3de9ec49df12 Binary files /dev/null and b/isis/src/base/apps/minmax/assets/images/peaks.jpg differ diff --git a/isis/src/base/apps/minmax/assets/thumbs/max2x2.jpg b/isis/src/base/apps/minmax/assets/thumbs/max2x2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2e1edd1d0dc90269df11d8d055767d917c184d4f Binary files /dev/null and b/isis/src/base/apps/minmax/assets/thumbs/max2x2.jpg differ diff --git a/isis/src/base/apps/minmax/assets/thumbs/max2x2gui.jpg b/isis/src/base/apps/minmax/assets/thumbs/max2x2gui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..74adb74edc3e06fa1497c08555513e5ef517daa9 Binary files /dev/null and b/isis/src/base/apps/minmax/assets/thumbs/max2x2gui.jpg differ diff --git a/isis/src/base/apps/minmax/assets/thumbs/min3x3.jpg b/isis/src/base/apps/minmax/assets/thumbs/min3x3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e88ed499ba28219820ebc278bd44149304735965 Binary files /dev/null and b/isis/src/base/apps/minmax/assets/thumbs/min3x3.jpg differ diff --git a/isis/src/base/apps/minmax/assets/thumbs/min3x3gui.jpg b/isis/src/base/apps/minmax/assets/thumbs/min3x3gui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..66ac06b69c4223a4acdf49870dbff58ac18d4e4e Binary files /dev/null and b/isis/src/base/apps/minmax/assets/thumbs/min3x3gui.jpg differ diff --git a/isis/src/base/apps/minmax/assets/thumbs/peaks.jpg b/isis/src/base/apps/minmax/assets/thumbs/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e0df3d4fb0ebc3096c3a238f04077f4b59898268 Binary files /dev/null and b/isis/src/base/apps/minmax/assets/thumbs/peaks.jpg differ diff --git a/isis/src/base/apps/minmax/minmax.cpp b/isis/src/base/apps/minmax/minmax.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4536708fc44d0457cbfc4feb4f5b1cbadde2cfc --- /dev/null +++ b/isis/src/base/apps/minmax/minmax.cpp @@ -0,0 +1,78 @@ +#include +#include "Isis.h" +#include "ProcessByBoxcar.h" +#include "SpecialPixel.h" +#include "LineManager.h" +#include "Filename.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void minimumFilter (Buffer &in, double &v); +void maximumFilter (Buffer &in, double &v); + +void IsisMain() { + ProcessByBoxcar p; + + UserInterface &ui = Application::GetUserInterface(); + + // Open the input cube + p.SetInputCube ("FROM"); + + // Allocate the output cube + p.SetOutputCube ("TO"); + + // Get dimensions of the boxcar + int nSamples = ui.GetInteger ("SAMPLES"); + int nLines = ui.GetInteger ("LINES"); + + //Set dimensions of the boxcar + p.SetBoxcarSize (nSamples,nLines); + + // Set which filter is being used + string filterType = ui.GetString ("FILTER"); + + if (filterType == "MIN") { + p.StartProcess (minimumFilter); + } + else if (filterType == "MAX") { + p.StartProcess (maximumFilter); + } + p.EndProcess (); + +} + +// Minimum DN filter +void minimumFilter (Buffer &in,double &v) { + + v = DBL_MAX; /*initialize v to the BIGGEST DN possible for + Isis, ensuring that it will be replaced so + long as there are valid pixels in the boxcar*/ + for (int i=0; i= in[i]){ + v = in[i]; + } + } + } + +} + + +// Maximum DN filter +void maximumFilter (Buffer &in,double &v) { + + v = -(DBL_MAX); /*Initialize v to the SMALLEST DN possible for + Isis, ensuring that it will be replaced so + long as there are valid pixels in the boxcar*/ + + for (int i=0; i + + + + + Apply a minimum or maximum filter to a cube + + + + This program will apply a minimum or maximum filter to a cube. + Using the "max" option, the pixel with the highest DN in the NxM size boxcar will be + output. Using the "min" option, the pixel with the lowest DN in the NxM boxcar + will be output. With either option, more extreme DNs will be more + noticeable in the output image. +

    + The boxcar will be N samples long by M lines high. Assuming a 3 x 3 boxcar +

    +    		V1  V2  V3
    +		V4  V5  V6
    +		V7  V8  V9
    +    
    + the program will first substitute an extremely high or low internal value for ISIS. + This essentially zeroes out the process in such a way that one of the values in the + current boxcar will be supplied as the output pixel, instead of an output pixel from + a previous boxcar. Assume that the MAX option is being used on the model boxcar shown + above.This value is then compared to the first pixel in the boxcar. This would be + the value substituted for "V1". If V1 is greater than the internal value (this will + be the case unless V1 is a special pixel) then the new output pixel will tenatively + be set to V1. V1 is then compared to V2, and the greater pixel is again set to the + temporary maximum. This process continues until the temporary maximum is compared to + all of the values in the boxcar, at which point it is set as the output value. +
    + + + + Original version + + + + Added application test + + + + Added examples + + + + + Filters + + + + + + cube + input + + Input cube + + + Use this parameter to select the filename. All bands within the file + will have the filter applied. + + + *.cub + + + + + cube + + output + real + + Output cube + + + This file will contain the filtered output. + + + + + + + integer + 3 + + Boxcar Lines + + + Use this parameter to select the number of lines in the boxcar. + Higher values take longer, and intensify the results in the vertical + direction. The default value is three. + + 1 + + + + integer + 3 + + Boxcar Samples + + + Use this parameter to select the number of samples in the boxcar. + Higher values take longer, and intensify the results in the horizontal + direction. The default value is three. + + 1 + + + + + + string + MIN + Type of filter (minimum, maximum) + + Use this parameter to choose the filter type. The possibilities + include min, which finds the lowest DN in the boxcar and max, + which finds the highest DN in the boxcar. + + + + + + + + + + + + + + Minimum 3x3 + + + Use the minimum option to enlarge dark areas (low DN pixels) and shrink + light areas (high DN pixels). + + + + from= peaks.cub + to=darkcube.cub + lines=3 + samples=3 + filter=min + + + In this example the "lines" and "samples" are both 3, making a 3 x 3 + boxcar. The minimum filter is selected, so as to essentially darken the + output. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform the minimum + filter with a 3 x 3 boxcar. + + + + + + + + + + Input image before minmax. + + + This is the image as it was taken originally. Take note of the size + of areas with high DNs, such as on top of mountains and in the lower + right corner of the image. + + + FROM + + + + + + + Output image after minmax + + + The filtered image. A side-effect of the program is a slight blur to + the image, but notice the change in the details described above. + the mountain tops have lost some area, while the dark region at the + base has expanded. Also note the reduced intensity of the brightness + in the lower right corner. + + + TO + + + + + + + Maximum 2x2 + + + Use the maximum option to enlarge bright areas (pixels with high DNs) and + shrink dark areas (pixels with low DNs). + + + + from= peaks.cub + to=lightcube.cub + lines=2 + samples=2 + filter=max + + + In this example both the "lines" and "samples" options are set to 2. This + will make the program run faster than the 3 x 3 boxcar featured in + example 1. The effect of the filter will also be somewhat less dramatic + than with a 3 x 3 boxcar. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform the maximum + filter with a 2 x 2 boxcar. + + + + + + + + + + Input image before minmax. + + + This is the image as it was taken originally. Take note of the size + of areas with high DNs. In particular, notice the man-made lights + in the lower right corner of the image and the bright spots on top + of the mountain. + + + FROM + + + + + + + Output image after minmax + + + The filtered image. Just as in example 1, the image is blurred + slightly. Unlike the first example, bright areas are now enlarged and + the brightness that would have been shrunk using the minimum filter + is now expanded. Again, note the peaks of the mountains and the + man-made lights in the lower right corner. + + + TO + + + + + + +
    diff --git a/isis/src/base/apps/minmax/tsts/Makefile b/isis/src/base/apps/minmax/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/minmax/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/minmax/tsts/max/Makefile b/isis/src/base/apps/minmax/tsts/max/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f10fc43e96cb14457df60e2880e20c3317cafce3 --- /dev/null +++ b/isis/src/base/apps/minmax/tsts/max/Makefile @@ -0,0 +1,10 @@ +APPNAME = minmax + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/minmaxTruth2.cub \ + filter=max \ + samples=4 \ + lines=5 > /dev/null; diff --git a/isis/src/base/apps/minmax/tsts/min/Makefile b/isis/src/base/apps/minmax/tsts/min/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e76d5ede49633e23a5527111b90259494cc41baa --- /dev/null +++ b/isis/src/base/apps/minmax/tsts/min/Makefile @@ -0,0 +1,10 @@ +APPNAME = minmax + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/minmaxTruth1.cub \ + filter=min \ + samples=3 \ + lines=3 > /dev/null; diff --git a/isis/src/base/apps/mirror/Makefile b/isis/src/base/apps/mirror/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/mirror/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/mirror/assets/image/9700r.jpg b/isis/src/base/apps/mirror/assets/image/9700r.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68a7d23d3bf19d80bc4fb947dbaf9f07ce0e9b26 Binary files /dev/null and b/isis/src/base/apps/mirror/assets/image/9700r.jpg differ diff --git a/isis/src/base/apps/mirror/assets/image/IoMirror.jpg b/isis/src/base/apps/mirror/assets/image/IoMirror.jpg new file mode 100644 index 0000000000000000000000000000000000000000..de721ae6e7430dd6af33b721cedc7ac955682292 Binary files /dev/null and b/isis/src/base/apps/mirror/assets/image/IoMirror.jpg differ diff --git a/isis/src/base/apps/mirror/assets/image/IoMirrorGui.jpg b/isis/src/base/apps/mirror/assets/image/IoMirrorGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..20d0b02ec19b0cd1ef70837a7ae638c0c25f68f9 Binary files /dev/null and b/isis/src/base/apps/mirror/assets/image/IoMirrorGui.jpg differ diff --git a/isis/src/base/apps/mirror/assets/thumb/9700r.jpg b/isis/src/base/apps/mirror/assets/thumb/9700r.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3f847cebb8c3affd2c562c9b665a338c9d5cdbc7 Binary files /dev/null and b/isis/src/base/apps/mirror/assets/thumb/9700r.jpg differ diff --git a/isis/src/base/apps/mirror/assets/thumb/IoMirror.jpg b/isis/src/base/apps/mirror/assets/thumb/IoMirror.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ea30346e385fb33823cdc0b9399488f09a1b4b0e Binary files /dev/null and b/isis/src/base/apps/mirror/assets/thumb/IoMirror.jpg differ diff --git a/isis/src/base/apps/mirror/assets/thumb/IoMirrorGui.jpg b/isis/src/base/apps/mirror/assets/thumb/IoMirrorGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9336a5bff93aa427318ee7bb09ff9dd7ec576ae4 Binary files /dev/null and b/isis/src/base/apps/mirror/assets/thumb/IoMirrorGui.jpg differ diff --git a/isis/src/base/apps/mirror/mirror.cpp b/isis/src/base/apps/mirror/mirror.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c5d7fef30d58cfdc488fb0b26b3e545f8edf99a --- /dev/null +++ b/isis/src/base/apps/mirror/mirror.cpp @@ -0,0 +1,32 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void mirror (Buffer &in, Buffer &out); + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + + // Start the processing + p.StartProcess(mirror); + p.EndProcess(); +} + +// Line processing routine +void mirror (Buffer &in, Buffer &out) { + // Loop and flip pixels in the line. + int index = in.size() - 1; + for (int i=0; i + + + + Flip a cube from left-to-right + + + + This program will flip a cube from left-to-right. By flipping the cube + the geometric integrity of the cube is destroyed. Therefore, any + geometric, mapping, or instrument related labels will be marked as + invalid. + + + + Geometry + + + + + rotate + flip + + + + + + Original version + + + Converted to Isis 3.0 + + + Add example + + + Removed mirror from the Utility category and + added "rotate" under See Also. + + + Make images smaller. + + + Fixed problem with isiscvs not checking in the thumb and image directories. + + + Added application test + + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + + + + + + cube + input + + Input file to be flipped + + + The cube to be flipped. All bands will be flipped from + left-to-right. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the flipped data. + + + *.cub + + + + + + + + Io mirrored + + This example shows the simple but indispensable mirror application. There are no defaults. + + + f=../IN/9700r.cub t=OUT/mirror.cub + + + Just mirror an Io image. + + + + + + Input image for mirror + This is the 800 by 800 input image for the mirror example. + + + FROM + + + + + + Output image for mirror + This is the 800 by 800 output image that results. + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform +a mirror operation on the input image. + + + + + + + + diff --git a/isis/src/base/apps/mirror/tsts/Makefile b/isis/src/base/apps/mirror/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/mirror/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/mirror/tsts/case01/Makefile b/isis/src/base/apps/mirror/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..74be3e7f2bfcf86350c6be80c73ab66fd09fe01b --- /dev/null +++ b/isis/src/base/apps/mirror/tsts/case01/Makefile @@ -0,0 +1,7 @@ +APPNAME = mirror + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/mirTruth.cub > /dev/null; diff --git a/isis/src/base/apps/mode/Makefile b/isis/src/base/apps/mode/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/mode/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/mode/assets/images/15x15gui.jpg b/isis/src/base/apps/mode/assets/images/15x15gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..10bd4cf7b16c5b2b42c96ddce374ade7c210c6c9 Binary files /dev/null and b/isis/src/base/apps/mode/assets/images/15x15gui.jpg differ diff --git a/isis/src/base/apps/mode/assets/images/15x15mode.jpg b/isis/src/base/apps/mode/assets/images/15x15mode.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ca6d6f17d6918ce8d2022b8004c58b1e0fe3e3bc Binary files /dev/null and b/isis/src/base/apps/mode/assets/images/15x15mode.jpg differ diff --git a/isis/src/base/apps/mode/assets/images/3x3gui.jpg b/isis/src/base/apps/mode/assets/images/3x3gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5a96b28609eca86362a49667c8738ba79a0f600f Binary files /dev/null and b/isis/src/base/apps/mode/assets/images/3x3gui.jpg differ diff --git a/isis/src/base/apps/mode/assets/images/3x3mode.jpg b/isis/src/base/apps/mode/assets/images/3x3mode.jpg new file mode 100644 index 0000000000000000000000000000000000000000..18f351211e7f1acbf237bf4f1053e6a38decf6dc Binary files /dev/null and b/isis/src/base/apps/mode/assets/images/3x3mode.jpg differ diff --git a/isis/src/base/apps/mode/assets/images/input.jpg b/isis/src/base/apps/mode/assets/images/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5c89716b1617440e6d51dddfc88c7b5c48e1c34f Binary files /dev/null and b/isis/src/base/apps/mode/assets/images/input.jpg differ diff --git a/isis/src/base/apps/mode/assets/thumbs/15x15gui.jpg b/isis/src/base/apps/mode/assets/thumbs/15x15gui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8c74a2a893e776ecc61d6fe4ff0ccba51b23240c Binary files /dev/null and b/isis/src/base/apps/mode/assets/thumbs/15x15gui.jpg differ diff --git a/isis/src/base/apps/mode/assets/thumbs/15x15mode.jpg b/isis/src/base/apps/mode/assets/thumbs/15x15mode.jpg new file mode 100755 index 0000000000000000000000000000000000000000..cc475eaf023009c92859b753a4d01826413e9f2f Binary files /dev/null and b/isis/src/base/apps/mode/assets/thumbs/15x15mode.jpg differ diff --git a/isis/src/base/apps/mode/assets/thumbs/3x3gui.jpg b/isis/src/base/apps/mode/assets/thumbs/3x3gui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..920c83cd92f6da345d338e768aaa8c4c506e4682 Binary files /dev/null and b/isis/src/base/apps/mode/assets/thumbs/3x3gui.jpg differ diff --git a/isis/src/base/apps/mode/assets/thumbs/3x3mode.jpg b/isis/src/base/apps/mode/assets/thumbs/3x3mode.jpg new file mode 100755 index 0000000000000000000000000000000000000000..bcad91cc6d170c0b2442e850bd465d3031a72d60 Binary files /dev/null and b/isis/src/base/apps/mode/assets/thumbs/3x3mode.jpg differ diff --git a/isis/src/base/apps/mode/assets/thumbs/input.jpg b/isis/src/base/apps/mode/assets/thumbs/input.jpg new file mode 100755 index 0000000000000000000000000000000000000000..569a32613d0b172f393cd6ae75b9674dc12b010e Binary files /dev/null and b/isis/src/base/apps/mode/assets/thumbs/input.jpg differ diff --git a/isis/src/base/apps/mode/mode.cpp b/isis/src/base/apps/mode/mode.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0bdc8b3e6ac98d8b1a3ba84cc16cbad4a00ce5e6 --- /dev/null +++ b/isis/src/base/apps/mode/mode.cpp @@ -0,0 +1,319 @@ +#include "Isis.h" +#include "ProcessByBoxcar.h" +#include "SpecialPixel.h" +#include +#include + +using namespace std; +using namespace Isis; + +bool filterNull; +bool filterHrs; +bool filterHis; +bool filterLrs; +bool filterLis; +bool propagate; +double low; +double high; +unsigned int minimum; + +void FilterAll(Buffer &in, double &v); +void FilterValid(Buffer &in, double &v); +void FilterInvalid(Buffer &in, double &v); + +void IsisMain(){ + //Set up ProcessByBoxcar + ProcessByBoxcar p; + + //Obtain input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + + //Set up Boxcar size + UserInterface &ui = Application::GetUserInterface(); + int samples = ui.GetInteger("SAMPLES"); + int lines = ui.GetInteger("LINES"); + p.SetBoxcarSize(samples, lines); + + //Determine which pixels are valid, and how many are + //necessary for processing + filterNull = ui.GetBoolean("NULL"); + filterHrs = ui.GetBoolean("HRS"); + filterLrs = ui.GetBoolean("LRS"); + filterHis = ui.GetBoolean("HIS"); + filterLis = ui.GetBoolean("LIS"); + if (ui.GetString("MINOPT") == "PERCENTAGE") { + int size = lines * samples; + double perc = ui.GetDouble("MINIMUM") / 100; + minimum = (int) (size * perc); + } + else { + minimum = (int) ui.GetDouble("MINIMUM"); + } + low = -DBL_MAX; + high = DBL_MAX; + if (ui.WasEntered("LOW")){ + low = ui.GetDouble("LOW"); + } + if (ui.WasEntered("HIGH")){ + high = ui.GetDouble("HIGH"); + } + + //Determine what to do if there are too few + //non-Special pixels + propagate = (ui.GetString("REPLACEMENT") == "CENTER"); + + + //Check for filter style, and process accordingly + if (ui.GetString("PIXELS") == "ALL"){ + p.StartProcess(FilterAll); + p.EndProcess(); + } + else if (ui.GetString("PIXELS") == "INSIDE"){ + p.StartProcess(FilterValid); + p.EndProcess(); + } + else if (ui.GetString("PIXELS") == "OUTSIDE"){ + p.StartProcess(FilterInvalid); + p.EndProcess(); + } +} + +//Function which loops through every pixel int the boxcar, +//and outputs the mode value to the center pixel, if +//the center pixel is valid +void FilterValid(Buffer &in, double &v){ + double centerPixel = in[(in.size()-1)/2]; + + //Check if the center pixel is valid + //Valid is defined as a Special Pixel declared as a + //valid type, or a normal value between low and high. + //If the center pixel does not meet these requirements, + //write the original value to the center and move on + if ( IsSpecial(centerPixel) ){ + if ((IsNullPixel(centerPixel)) && (!filterNull)) { + v = centerPixel; + return; + } + else if ((IsLisPixel(centerPixel)) && (!filterLis)) { + v = centerPixel; + return; + } + else if ((IsLrsPixel(centerPixel)) && (!filterLrs)) { + v = centerPixel; + return; + } + else if ((IsHisPixel(centerPixel)) && (!filterHis)) { + v = centerPixel; + return; + } + else if ((IsHrsPixel(centerPixel)) && (!filterHrs)) { + v = centerPixel; + return; + } + } + else if (centerPixelhigh){ + v = centerPixel; + } + + //Gather all non-special pixels into a vector and determine + //the mode, provided there are enough for filtering + std::vector boxdata(0); + + for (int i=0; i=low && in[i]<=high){ + boxdata.push_back(in[i]); + } + else{ + continue; + } + } + if (boxdata.size()maxCount){ + modeVal = boxdata[i-1]; + maxCount = count; + } + count = 1; + } + } + v = modeVal; +} + + +//Function to loop through the boxcar and find and write +//the mode value to the center pixel, but only if the +//center pixel is invalid +void FilterInvalid(Buffer &in, double &v){ + double centerPixel = in[(in.size()-1)/2]; + + //Check if the center pixel is valid + //Valid is defined as a Special Pixel declared as a + //valid type, or a normal value between low and high. + //If the center is valid, write the original value to the + //center, and move the boxcar + if (IsSpecial(centerPixel)){ + if ((IsNullPixel(centerPixel)) && (!filterNull)) { + v = centerPixel; + return; + } + else if ((IsLisPixel(centerPixel)) && (!filterLis)) { + v = centerPixel; + return; + } + else if ((IsLrsPixel(centerPixel)) && (!filterLrs)) { + v = centerPixel; + return; + } + else if ((IsHisPixel(centerPixel)) && (!filterHis)) { + v = centerPixel; + return; + } + else if ((IsHrsPixel(centerPixel)) && (!filterHrs)) { + v = centerPixel; + return; + } + } + else if (centerPixel>=low && centerPixel<=high){ + v = centerPixel; + } + + //Now, build a vector containing non-Special pixels, + //and, if there are enough, process the vector to + //determine the mode. If there aren't enough, write + //a user selected value to the center. + std::vector boxdata(0); + + for (int i=0; i=low && in[i]<=high){ + boxdata.push_back(in[i]); + } + else{ + continue; + } + } + if (boxdata.size()maxCount){ + modeVal = boxdata[i-1]; + maxCount = count; + } + count = 1; + } + } + v = modeVal; +} + +//Function to process the boxcar and determine the mode, +//regardless of validity of the center pixel +void FilterAll(Buffer &in, double &v){ + double centerPixel = in[(in.size()-1)/2]; + + //Check if the center pixel is valid + //Valid is defined as a Special Pixel declared as a + //valid type, or a normal value between low and high. + //If the center is valid, write the original value to the + //center, and move the boxcar + if (IsSpecial(centerPixel)){ + if ((IsNullPixel(centerPixel)) && (!filterNull)) { + v = centerPixel; + return; + } + else if ((IsLisPixel(centerPixel)) && (!filterLis)) { + v = centerPixel; + return; + } + else if ((IsLrsPixel(centerPixel)) && (!filterLrs)) { + v = centerPixel; + return; + } + else if ((IsHisPixel(centerPixel)) && (!filterHis)) { + v = centerPixel; + return; + } + else if ((IsHrsPixel(centerPixel)) && (!filterHrs)) { + v = centerPixel; + return; + } + } + + //Now, build a vector containing non-Special pixels, + //and, if there are enough, process the vector to + //determine the mode. If there aren't enough, write + //a user selected value to the center. + std::vector boxdata(0); + + for (int i=0; i=low && in[i]<=high){ + boxdata.push_back(in[i]); + } + else{ + continue; + } + } + if (boxdata.size()maxCount){ + modeVal = boxdata[i-1]; + maxCount = count; + } + count = 1; + } + } + v = modeVal; +} diff --git a/isis/src/base/apps/mode/mode.xml b/isis/src/base/apps/mode/mode.xml new file mode 100644 index 0000000000000000000000000000000000000000..65f7d480d05a2f4f9e11f1f2511193b2bb050f82 --- /dev/null +++ b/isis/src/base/apps/mode/mode.xml @@ -0,0 +1,496 @@ + + + + + + Set pixels to mode of surrounding pixel values + + + + This program accepts a user-defined boxcar and loops + through the input image. It finds the mode pixel + value in the boxcar, and sets the center pixel value + to that mode value. If the boxcar is poly-modal, the + filter writes the lowest of the mode values to the center + + + + Filters + + + + + Original version + + + Added Minopt parameter, modified user interface. + + + Modified user interface + + + + + + + cube + input + + Input Cube + + + This is the cube from which we will gather our data. + + *.cub + + + + cube + output + + Output Cube + + + This is the cube to which we will write the modified + data. + + *.cub + + + + + + integer + + Number of samples in Boxcar + + + This will determine how many samples the boxcar will + have. The number must be an odd integer, and size + often has a noticeable impact on time. It will + also have an impact on the blurring effect. The + larger the boxcar, the greater the blurring. The user + will have to discover other effects on their own. + + 1 + + + + + integer + + Number of lines in Boxcar + + + This will determine how many lines the boxcar will + have. The number must be an odd integer, and size + often has a noticeable impact on time. It will + also have an impact on the blurring effect. The + larger the boxcar, the greater the blurring. The user + will have to discover other effects on their own. + + 1 + + + + + + + double + + The minimum value of a valid pixel + + + This value indicates the minimum value of a valid + pixel. If a pixel holds a value below the minimum + value, it will either be excluded or included, + depending on user input in the "Filter Style" + area. + + Use all + HIGH + + + + double + + The maximum value of a valid pixel + + + This value indicates the maximum value of a valid + pixel. If a pixel holds a value over the maximum + value, it will either be excluded or included, + depending on user input in the "Filter Style" + area. + + Use all + LOW + + + + string + + COUNT + + + Sets minimum to be either a count or a percentage + + + This parameter determines whether the minimum + parameter is to be interpreted as a count of pixels, or a + percentage of all pixels in the boxcar. + + + + + + + + + + double + 1 + + Minimum boxcar pixels required for filter + + + This option is the minimum number of valid pixels + required in a boxcar for filtering to begin. + + + + + string + + CENTER + + + Replacement if minimum not met + + + This determines what to put in the center pixel, + in the event that there aren't enough non-special + pixels in the boxcar to meet the minimum. The + default is to replace it with the current value, + and the other option is to replace it with NULL. + + + + + + + + + + + + + string + + ALL + + + The style of filtration + + + These options determine which pixels are to be included in the + filtering process. ALL filters all pixels, regardless of value, VALID + only filters those pixels with values between LOW and HIGH, and + INVALID only filters those pixels with values outside LOW and + HIGH. Note that these only determine which Non-Special pixels to + filter. Also, the median will only be calculated from pixel values + between LOW and HIGH. + + + + + + + + + + + + + + + + + boolean + TRUE + + Filter Null Pixels + + + If the center of the boxcar is Null, and this box is checked, the pixel + will be overwritten with the mode value of the boxcar as a whole. If + this box is left unchecked, the pixel will be left alone. + + + + + boolean + TRUE + + Filter Hrs Pixels + + + If the center of the boxcar is Hrs, and this box is checked, the pixel + will be overwritten with the mode value of the boxcar as a whole. If + this box is left unchecked, the pixel will be left alone. + + + + + boolean + TRUE + + Filter His Pixels + + + If the center of the boxcar is His, and this box is checked, the pixel + will be overwritten with the mode value of the boxcar as a whole. If + this box is left unchecked, the pixel will be left alone. + + + + + boolean + TRUE + + Filter Lrs Pixels + + + If the center of the boxcar is Lrs, and this box is checked, the pixel + will be overwritten with the mode value of the boxcar as a whole. If + this box is left unchecked, the pixel will be left alone. + + + + + boolean + TRUE + + Filter Lis Pixels + + + If the center of the boxcar is Lis, and this box is checked, the pixel + will be overwritten with the mode value of the boxcar as a whole. If + this box is left unchecked, the pixel will be left alone. + + + + + + + + + Running mode with a 3x3 boxcar + + + This demonstrates running the mode program on a sample + cube. + + + + from= peaks.cub + to=3x3mode.cub + samples=3 + lines=3 + + + This demonstrates the commands necessary to run mode on + a file named "peaks.cub" with a 3x3 boxcar. The small size + will not produce much difference. + + + + + + + + Example GUI + + + Screenshot of the GUI set to filter all pixels for the image + using a 3x3 boxcar. + + + + + + + + + + Input image before mode filter + + + This is the original cube. The areas of greatest interest are + those with a great deal of contrast such as edges. + + + FROM + + + + + + + Output of 3x3 boxcar mode filter + + + This is the image after the filter. You may notice that the whole + image is slightly softer, particularly around areas of sharp + contrast. Due to the small size of the boxcar, the effect is + subtle and difficult to notice. + + + TO + + + + + + + Running mode with a 15x15 boxcar + + + This demonstrates running the mode program on a sample + cube. + + + + from= peaks.cub + to=15x15mode.cub + samples=15 + lines=15 + + + This demonstrates the commands necessary to run mode on + a file named "peaks.cub" with a 15x15 boxcar. The large size + of the boxcar produces a marked effect. + + + + + + + + Example GUI + + + Screenshot of the GUI set to filter all pixels for the image + using a 15x15 boxcar. + + + + + + + + + + Input image before mode filter + + + This is the original cube. The areas of greatest interest are + those with a great deal of contrast such as edges. + + + FROM + + + + + + + Output of 15x15 boxcar mode filter + + + This is the output image for a 15x15 boxcar. You will notice + the entire image is noticeably blurrier. It is now virtually + impossible to make out any but the largest of features. + + + TO + + + + + diff --git a/isis/src/base/apps/mode/tsts/Makefile b/isis/src/base/apps/mode/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/mode/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/mode/tsts/all/Makefile b/isis/src/base/apps/mode/tsts/all/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..30f8bbbf54a3bd3e181e79d26e826a302727dd29 --- /dev/null +++ b/isis/src/base/apps/mode/tsts/all/Makefile @@ -0,0 +1,10 @@ +APPNAME = mode + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/modeTruth1.cub \ + samples=3 \ + lines=3 \ + minimum=1 > /dev/null; diff --git a/isis/src/base/apps/mode/tsts/inside/Makefile b/isis/src/base/apps/mode/tsts/inside/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3b6328560254c7e2c4104a17eea7a366bc70add5 --- /dev/null +++ b/isis/src/base/apps/mode/tsts/inside/Makefile @@ -0,0 +1,13 @@ +APPNAME = mode + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/modeTruth2.cub \ + samples=13 \ + lines=13 \ + pixels=INSIDE \ + low=60 \ + high=150 \ + minimum=1 > /dev/null; diff --git a/isis/src/base/apps/mosrange/Makefile b/isis/src/base/apps/mosrange/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/mosrange/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/mosrange/mosrange.cpp b/isis/src/base/apps/mosrange/mosrange.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d167f7bf9f5f52f909b2a501d560f86172b0c9f7 --- /dev/null +++ b/isis/src/base/apps/mosrange/mosrange.cpp @@ -0,0 +1,222 @@ +#include +#include "Isis.h" +#include "FileList.h" +#include "Cube.h" +#include "Process.h" +#include "Camera.h" +#include "Pvl.h" +#include "Statistics.h" + +using namespace std; +using namespace Isis; + + template inline T MIN(const T &A, const T &B) { + if ( A < B ) { return (A); } + else { return (B); } + } + + template inline T MAX(const T &A, const T &B) { + if ( A > B ) { return (A); } + else { return (B); } + } + +inline double SetFloor(double value, const int precision) { + double scale = pow(10.0, precision); + value = floor(value * scale) / scale; + return (value); +} + +inline double SetRound(double value, const int precision) { + double scale = pow(10.0, precision); + value = rint(value * scale) / scale; + return (value); +} + +inline double SetCeil(double value, const int precision) { + double scale = pow(10.0, precision); + value = ceil(value * scale) / scale; + return (value); +} + +inline double Scale (const double pixres, const double polarRadius, + const double equiRadius, const double trueLat = 0.0) { + double lat = trueLat * Isis::PI / 180.0; + double a = polarRadius * cos(lat); + double b = equiRadius * sin(lat); + double localRadius = equiRadius * polarRadius / sqrt(a*a + b*b); + return (localRadius / pixres * pi_c() / 180.0); +} + +void IsisMain() { + Process p; + + // Get the list of names of input CCD cubes to stitch together + FileList flist; + UserInterface &ui = Application::GetUserInterface(); + flist.Read(ui.GetFilename("FROMLIST")); + if (flist.size() < 1) { + string msg = "The list file[" + ui.GetFilename("FROMLIST") + + " does not contain any filenames"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + string projection("Equirectangular"); + if(ui.WasEntered("MAP")) { + Pvl mapfile(ui.GetFilename("MAP")); + projection = (string) mapfile.FindGroup("Mapping")["ProjectionName"]; + } + + if(ui.WasEntered("PROJECTION")) { + projection = ui.GetString("PROJECTION"); + } + + // Gather other user inputs to projection + string lattype = ui.GetString("LATTYPE"); + string londir = ui.GetString("LONDIR"); + string londom = ui.GetString("LONDOM"); + int digits = ui.GetInteger("PRECISION"); + + // Fix them for mapping group + lattype = (lattype == "PLANETOCENTRIC") ? "Planetocentric" : "Planetographic"; + londir = (londir == "POSITIVEEAST") ? "PositiveEast" : "PositiveWest"; + + Progress prog; + prog.SetMaximumSteps(flist.size()); + prog.CheckStatus(); + + Statistics scaleStat; + Statistics longitudeStat; + Statistics latitudeStat; + Statistics equiRadStat; + Statistics poleRadStat; + PvlObject fileset("FileSet"); + + // Save major equitorial and polar radii for last occuring + double eqRad; + double eq2Rad; + double poleRad; + + string target("Unknown"); + for (unsigned int i = 0 ; i < flist.size() ; i++) { + // Set the input image, get the camera model, and a basic mapping + // group + Cube cube; + cube.Open(flist[i]); + + int lines = cube.Lines(); + int samples = cube.Samples(); + + + PvlObject fmap("File"); + fmap += PvlKeyword("Name",flist[i]); + fmap += PvlKeyword("Lines", lines); + fmap += PvlKeyword("Samples", samples); + + Camera *cam = cube.Camera(); + Pvl mapping; + cam->BasicMapping(mapping); + PvlGroup &mapgrp = mapping.FindGroup("Mapping"); + mapgrp.AddKeyword(PvlKeyword("ProjectionName",projection),Pvl::Replace); + mapgrp.AddKeyword(PvlKeyword("LatitudeType",lattype),Pvl::Replace); + mapgrp.AddKeyword(PvlKeyword("LongitudeDirection",londir),Pvl::Replace); + mapgrp.AddKeyword(PvlKeyword("LongitudeDomain",londom),Pvl::Replace); + + // Get the radii + double radii[3]; + cam->Radii(radii); + + eqRad = radii[0] * 1000.0; + eq2Rad = radii[1] * 1000.0; + poleRad = radii[2] * 1000.0; + + target = cam->Target(); + equiRadStat.AddData(&eqRad, 1); + poleRadStat.AddData(&poleRad, 1); + + // Get resolution + double lowres = cam->LowestImageResolution(); + double hires = cam->HighestImageResolution(); + scaleStat.AddData(&lowres, 1); + scaleStat.AddData(&hires, 1); + + double pixres = (lowres+hires)/2.0; + double scale = Scale(pixres, poleRad, eqRad); + mapgrp.AddKeyword(PvlKeyword("PixelResolution",pixres),Pvl::Replace); + mapgrp.AddKeyword(PvlKeyword("Scale",scale,"pixels/degree"),Pvl::Replace); + mapgrp += PvlKeyword("MinPixelResolution",lowres,"meters"); + mapgrp += PvlKeyword("MaxPixelResolution",hires,"meters"); + + // Get the universal ground range + double minlat,maxlat,minlon,maxlon; + cam->GroundRange(minlat,maxlat,minlon,maxlon,mapping); + mapgrp.AddKeyword(PvlKeyword("MinimumLatitude",minlat),Pvl::Replace); + mapgrp.AddKeyword(PvlKeyword("MaximumLatitude",maxlat),Pvl::Replace); + mapgrp.AddKeyword(PvlKeyword("MinimumLongitude",minlon),Pvl::Replace); + mapgrp.AddKeyword(PvlKeyword("MaximumLongitude",maxlon),Pvl::Replace); + + fmap.AddGroup(mapgrp); + fileset.AddObject(fmap); + + longitudeStat.AddData(&minlon, 1); + longitudeStat.AddData(&maxlon, 1); + latitudeStat.AddData(&minlat, 1); + latitudeStat.AddData(&maxlat, 1); + + p.ClearInputCubes(); + prog.CheckStatus(); + } + +// Construct the output mapping group with statistics + PvlGroup mapping("Mapping"); + double avgPixRes((scaleStat.Minimum()+scaleStat.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); + + mapping += PvlKeyword("ProjectionName",projection); + mapping += PvlKeyword("TargetName", target); + mapping += PvlKeyword("EquatorialRadius",eqRad,"meters"); + mapping += PvlKeyword("PolarRadius",poleRad,"meters"); + mapping += PvlKeyword("LatitudeType",lattype); + mapping += PvlKeyword("LongitudeDirection",londir); + mapping += PvlKeyword("LongitudeDomain",londom); + mapping += PvlKeyword("PixelResolution", SetRound(avgPixRes, digits), "meters/pixel"); + mapping += PvlKeyword("Scale", SetRound(scale, digits), "pixels/degree"); + mapping += PvlKeyword("MinPixelResolution",scaleStat.Minimum(),"meters"); + mapping += PvlKeyword("MaxPixelResolution",scaleStat.Maximum(),"meters"); + mapping += PvlKeyword("CenterLongitude", SetRound(avgLon,digits)); + mapping += PvlKeyword("CenterLatitude", SetRound(avgLat,digits)); + mapping += PvlKeyword("MinimumLatitude", MAX(SetFloor(latitudeStat.Minimum(),digits), -90.0)); + mapping += PvlKeyword("MaximumLatitude", MIN(SetCeil(latitudeStat.Maximum(),digits), 90.0)); + mapping += PvlKeyword("MinimumLongitude",MAX(SetFloor(longitudeStat.Minimum(),digits), -180.0)); + mapping += PvlKeyword("MaximumLongitude",MIN(SetCeil(longitudeStat.Maximum(),digits), 360.0)); + + PvlKeyword clat("PreciseCenterLongitude", avgLon); + clat.AddComment("Actual Parameters without precision applied"); + mapping += clat; + mapping += PvlKeyword("PreciseCenterLatitude", avgLat); + mapping += PvlKeyword("PreciseMinimumLatitude", latitudeStat.Minimum()); + mapping += PvlKeyword("PreciseMaximumLatitude", latitudeStat.Maximum()); + mapping += PvlKeyword("PreciseMinimumLongitude",longitudeStat.Minimum()); + mapping += PvlKeyword("PreciseMaximumLongitude",longitudeStat.Maximum()); + + + Application::GuiLog(mapping); + + // Write the output file if requested + if (ui.WasEntered("TO")) { + Pvl temp; + temp.AddGroup(mapping); + temp.Write(ui.GetFilename("TO","map")); + } + + if (ui.WasEntered("LOG")) { + Pvl temp; + temp.AddObject(fileset); + temp.Write(ui.GetFilename("LOG","log")); + } + + p.EndProcess(); +} diff --git a/isis/src/base/apps/mosrange/mosrange.xml b/isis/src/base/apps/mosrange/mosrange.xml new file mode 100644 index 0000000000000000000000000000000000000000..3898a701c53018e37fa6ef1a3e5face91c4cd199 --- /dev/null +++ b/isis/src/base/apps/mosrange/mosrange.xml @@ -0,0 +1,281 @@ + + + + + Compute the lat/lon range of a set camera images for mosaicking + + + + 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 the extents of the latitude/longitude ranges of + the image set. + + mosrange provides better control over the values of the latitude/longitude + ranges by providing a PRECISION parameter. This parameter specifies the + maximum nuber of digits precision for many of the Mapping group parameters + used to project images. + + Its primary use is to provide a quick, simple and batchable means of + creating map files for projections. + + An example of the output generated is: +
    +Group = Mapping
    +  ProjectionName          = Equirectangular
    +  TargetName              = Moon
    +  EquatorialRadius        = 2440000.0  <meters>   
    +  PolarRadius             = 2440000.0 <meters>
    +  LatitudeType            = Planetocentric
    +  LongitudeDirection      = PositiveEast
    +  LongitudeDomain         = 360
    +  PixelResolution         = 505.3668 <meters/pixel>
    +  Scale                   = 84.2676 <pixels/degree>
    +  MinPixelResolution      = 483.45317995544 <meters>
    +  MaxPixelResolution      = 527.28051834369 <meters>
    +  CenterLongitude         = 165.9728
    +  CenterLatitude          = -13.6612
    +  MinimumLatitude         = -21.5164
    +  MaximumLatitude         = -5.806
    +  MinimumLongitude        = 133.7863
    +  MaximumLongitude        = 198.1593
    +
    +  # Actual Parameters without precision applied
    +  PreciseCenterLongitude  = 165.97281458717
    +  PreciseCenterLatitude   = -13.661167089917
    +  PreciseMinimumLatitude  = -21.516314016725
    +  PreciseMaximumLatitude  = -5.806020163109
    +  PreciseMinimumLongitude = 133.78639979231
    +  PreciseMaximumLongitude = 198.15922938202
    +End_Group
    +End
    + 
    +
    + + + Map Projection + + + + + Original version + + + Removed references to CubeInfo due to refactor + + + Added parameters LATTYPE, LONDIR and LONDOM; Now computes pixel Scale + in pixels/degree; added additional parameters to the output map file so + it is more compliant with projection requirements based upon input + parameters and established mapping group keywords. + + + Added TargetName to output map file. + + + + + + + filename + input + + Input cube file list to compute range for + + + Use this parameter to select the filename of a cube with + camera labels. + + + *.lis + + + + + filename + input + $base/templates/maps + None + *.map *.cub + + An existing MAP file that will be used to determine the name of the + projection + + + If this file is given, the ProjectionName keyword is used to + determine the type of projection desired. If you know the type + already as well as the proper spelling required by ISIS, then you + may use PROJECTION as an alternative to this file. + + + + + filename + output + None + *.map + + Output map projection file generated from the list + + + This file will contain a map projection file suitable for projecting + the given set of images. This file will contain all the parameters + suitable for using directly in cam2map. + + + + + filename + output + None + + Writes the specifics for each file to this file + + + Each input file will have its geometry computed and the results can + be written to this file for a looksee. + + + + + + string + None + None + + Name of projection you want to create + + + Use this named projection as the type of projection you wish to + create. It should be the complete valid name as required by the + cam2map application. This name can also be provided in the MAP + parameter if you do not know the proper spelling/format required for + ISIS projections. + + + + + string + + Latitude type + + + The latitude type for the projection. It can either be Planetocentric or Planetographic. + PLANETOCENTRIC is the default. + + + PLANETOCENTRIC + + + + + + + + + string + + Longitude Direction + + + The longitude direction for the projection. It can have a direction of Positive East + or Positive West. POSITIVEEAST is the default. + + + POSITIVEEAST + + + + + + + + + string + + Longitude Domain + + + The longitude domain for the projection. It can either have a domain of 180 or 360. + 360 is the default. + + + 360 + + + + + + + + + integer + 12 + + Digits of precision to use for latitude/longitude specifications + + +

    + This parameter provides some control over how the Latitude and + Longitude min/max values are written to the map file. Note that + this is useful for creating easy values to use in subsequent + applications that may require these values. If these values are not + specified, about 12 digits of precision will be used. +

    +

    + Note that you can use a negative number which has the effect of + rounding the whole integral number. A value of 0 will produce + an integral whole number, effectively removing the decimal + portion of the numbers. A positive number will truncate up + (maximums using the ceil function) or down (minimums using the + floor function) range values such as MinimumLatitude and + MaximumLatitude. The pixel resolution is rounded using same + technique (with the rint fuction). +

    +
    +
    +
    +
    +
    diff --git a/isis/src/base/apps/mosrange/tsts/Makefile b/isis/src/base/apps/mosrange/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/mosrange/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/mosrange/tsts/default/Makefile b/isis/src/base/apps/mosrange/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..001d32b8c63820858696bde1f8b7fde4fed16ee7 --- /dev/null +++ b/isis/src/base/apps/mosrange/tsts/default/Makefile @@ -0,0 +1,15 @@ +APPNAME = mosrange + +mosrange_equi.txt.IGNORELINES = MinPixelResolution MaxPixelResolution \ + PreciseCenterLongitude PreciseCenterLatitude \ + PreciseMinimumLatitude PreciseMaximumLatitude \ + PreciseMinimumLongitude PreciseMaximumLongitude + + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROMLIST=$(INPUT)/files.lis \ + MAP=$(ISIS3DATA)/base/templates/maps/equirectangular.map \ + TO=$(OUTPUT)/mosrange_equi.map PRECISION=4 > /dev/null; + /bin/mv $(OUTPUT)/mosrange_equi.map $(OUTPUT)/mosrange_equi.txt diff --git a/isis/src/base/apps/mvstats/Makefile b/isis/src/base/apps/mvstats/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/mvstats/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/mvstats/mvstats.cpp b/isis/src/base/apps/mvstats/mvstats.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6bd08612625f6282fc06f6b1778b291c880d4b03 --- /dev/null +++ b/isis/src/base/apps/mvstats/mvstats.cpp @@ -0,0 +1,174 @@ +#include "Isis.h" + +#include +#include + +#include "ProcessByLine.h" + +#include "Pvl.h" +#include "MultivariateStatistics.h" + +using namespace std; +using namespace Isis; + +std::vector< vector > covariance; +std::vector< vector > correlation; +MultivariateStatistics stats; + +void MakeStats(vector &in, vector &out); +void WriteText(int size, string filename); +void WriteCube(Buffer &inout); + +void IsisMain() { + + //Check to see if an output file was specified + UserInterface &ui = Application::GetUserInterface(); + if (!ui.WasEntered("CUBE") && !ui.WasEntered("FLATFILE")){ + string message = "At least one output file must be entered"; + throw iException::Message (iException::User, message, _FILEINFO_); + } + + string file = ui.GetFilename("FROM"); + + //Use a Process to get the number of bands in the input cube + Process q; + Cube *icube = q.SetInputCube("FROM"); + int bands = icube->Bands(); + + //Check to see if the input cube has enough bands + if (bands < 2){ + string message = "Input band must have at least two bands!"; + throw iException::Message (iException::User, message, _FILEINFO_); + } + + //Set the matrices according to the number of bands in the input cube + covariance.resize(bands); + correlation.resize(bands); + for (int i=0; iPhysicalBand(i))); + CubeAttributeInput band_b ("d+" + iString(icube->PhysicalBand(j))); + + //Set Input files and process, to accumulate the statistics + p.SetInputCube(file, band_a); + p.SetInputCube(file, band_b); + Progress* progress = p.Progress(); + progress->SetText(progText); + p.StartProcess(MakeStats); + p.EndProcess(); + + //If the bands are the same, use the Variance of one, and a Correlation + //of 1, for speed and simplicity + if (i == j){ + covariance[i-1][j-1] = stats.X().Variance(); + correlation[i-1][j-1] = 1.0; + } + //Otherwise, set the matrix to the appropriate value + else{ + covariance[i-1][j-1] = stats.Covariance(); + correlation[i-1][j-1] = stats.Correlation(); + } + } + } + //Mirror the matrices to create a full representation, instead + //of half-matrices + for (int i=0; iPutGroup(bandBin); + p.EndProcess(); + } +} + +//Function to gather the data and feed them to a +//MultivariateStatistics container +void MakeStats(vector &in, vector &out){ + double *x = in[0]->DoubleBuffer(); + double *y = in[1]->DoubleBuffer(); + + stats.AddData(x, y, in[0]->size()); +} + +//Function to generate a flatfile to represent the matrices +void WriteText(int size, string filename){ + ofstream outputFile; + outputFile.open(filename.c_str()); + string line = " "; + outputFile << "Correlation:" << endl << endl; + for (int i=0; i + + + Generate multivariate Statistics for a cube + + + + This application generates the correlation and covariance for a single cube which can be used + to evaluate the similarity and/or disimilarity between bands of a cube. Each band of the cube + is compared against every other band in the cube, generating a covariance matrix and a correlation + matrix, which are output to CUBE and/or FLATFILE. + + + + Math and Statistics + + + + + Original version + + + Removed references to CubeInfo + + + + + + + cube + input + + Input cube + + + The input file to draw the statistics from. It must contain at least + two bands. + + + *.cub + + + + + cube + real + output + + Output cube containing the correlation and covariance matrices + + + None + + + This output cube is a two band cube containing the correlation and covariance + matrices. The dimensions of this cube will be NxNx2, where N is the number of bands in + the input cube. The first band will contain the correlation matrix, and the second will contain + the covariance matrix. + + + *.cub + + + + + filename + output + + Output text file containing the correlation and covariance matrices + + + None + + + This text file will contain the correlation and covariance matrices. + + + + + diff --git a/isis/src/base/apps/mvstats/tsts/Makefile b/isis/src/base/apps/mvstats/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/mvstats/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/mvstats/tsts/cube/Makefile b/isis/src/base/apps/mvstats/tsts/cube/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8b163b07ab0bab4243b01ecc6fd41abe7406f6e6 --- /dev/null +++ b/isis/src/base/apps/mvstats/tsts/cube/Makefile @@ -0,0 +1,7 @@ +APPNAME = mvstats + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + cube=$(OUTPUT)/mvstatsTruth.cub > /dev/null; diff --git a/isis/src/base/apps/mvstats/tsts/flat/Makefile b/isis/src/base/apps/mvstats/tsts/flat/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e6164332145f337c644984a49ad2256586dc0647 --- /dev/null +++ b/isis/src/base/apps/mvstats/tsts/flat/Makefile @@ -0,0 +1,7 @@ +APPNAME = mvstats + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + flatfile=$(OUTPUT)/mvstats.txt > /dev/null; diff --git a/isis/src/base/apps/nocam2map/Makefile b/isis/src/base/apps/nocam2map/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/nocam2map/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/nocam2map/nocam2map.cpp b/isis/src/base/apps/nocam2map/nocam2map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90af67ec9d9032e5799b42636f3c7575b1678d3b --- /dev/null +++ b/isis/src/base/apps/nocam2map/nocam2map.cpp @@ -0,0 +1,957 @@ +#define GUIHELPERS + +#include "Isis.h" +#include "Constants.h" +#include "naif/SpiceUsr.h" +#include "Brick.h" +#include "PolynomialBivariate.h" +#include "LeastSquares.h" +#include "ProcessRubberSheet.h" +#include "iString.h" +#include "Projection.h" +#include "ProjectionFactory.h" +#include "Statistics.h" +#include "TextFile.h" +#include "nocam2map.h" + +using namespace std; +using namespace Isis; + +void PrintMap (); +void ComputePixRes(); +void LoadMapRes(); +void ComputeInputRange(); +void LoadMapRange(); + +map GuiHelpers(){ + map helper; + helper ["PrintMap"] = (void*) PrintMap; + helper ["ComputePixRes"] = (void*) ComputePixRes; + helper ["LoadMapRes"] = (void*) LoadMapRes; + helper ["ComputeInputRange"] = (void*) ComputeInputRange; + helper ["LoadMapRange"] = (void*) LoadMapRange; + return helper; +} + + +void IsisMain() { + //Create a process to create the input cubes + Process p; + //Create the input cubes, matching sample/lines + Cube *inCube = p.SetInputCube ("FROM"); + Cube *latCube = p.SetInputCube("LATCUB", SpatialMatch); + Cube *lonCube = p.SetInputCube("LONCUB", SpatialMatch); + + //A 1x1 brick to read in the latitude and longitude DN values from + //the specified cubes + Brick latBrick(1,1,1, latCube->PixelType()); + Brick lonBrick(1,1,1, lonCube->PixelType()); + + UserInterface &ui = Application::GetUserInterface(); + + //Set the sample and line increments + int sinc = (int)(inCube->Samples() * 0.10); + if(ui.WasEntered("SINC")) { + sinc = ui.GetInteger("SINC"); + } + + int linc = (int)(inCube->Lines() * 0.10); + if(ui.WasEntered("LINC")) { + linc = ui.GetInteger("LINC"); + } + + //Set the degree of the polynomial to use in our functions + int degree = ui.GetInteger("DEGREE"); + + //We are using a polynomial with two variables + PolynomialBivariate sampFunct(degree); + PolynomialBivariate lineFunct(degree); + + //We will be solving the function using the least squares method + LeastSquares sampSol(sampFunct); + LeastSquares lineSol(lineFunct); + + //Setup the variables for solving the stereographic projection + //x = cos(latitude) * sin(longitude - lon_center) + //y = cos(lat_center) * sin(latitude) - sin(lat_center) * cos(latitude) * cos(longitude - lon_center) + + //Get the center lat and long from the input cubes + double lat_center = latCube->Statistics()->Average() * PI/180.0; + double lon_center = lonCube->Statistics()->Average() * PI/180.0; + + + /** + * Loop through lines and samples projecting the latitude and longitude at those + * points to stereographic x and y and adding these points to the LeastSquares + * matrix. + */ + for(int i = 1; i <= inCube->Lines(); i+= linc) { + for(int j = 1; j <= inCube->Samples(); j+= sinc) { + latBrick.SetBasePosition(j, i, 1); + latCube->Read(latBrick); + if(IsSpecial(latBrick.at(0))) continue; + double lat = latBrick.at(0) * PI/180.0; + lonBrick.SetBasePosition(j, i, 1); + lonCube->Read(lonBrick); + if(IsSpecial(lonBrick.at(0))) continue; + double lon = lonBrick.at(0) * PI/180.0; + + //Project lat and lon to x and y using a stereographic projection + double k = 2/(1 + sin(lat_center) * sin(lat) + cos(lat_center)*cos(lat)*cos(lon - lon_center)); + double x = k * cos(lat) * sin(lon - lon_center); + double y = k * (cos(lat_center) * sin(lat)) - (sin(lat_center) * cos(lat) * cos(lon - lon_center)); + + //Add x and y to the least squares matrix + vector data; + data.push_back(x); + data.push_back(y); + sampSol.AddKnown(data, j); + lineSol.AddKnown(data, i); + + //If the sample increment goes past the last sample in the line, we want to + //always read the last sample.. + if(j != inCube->Samples() && j + sinc > inCube->Samples()) { + j = inCube->Samples() - sinc; + } + } + //If the line increment goes past the last line in the cube, we want to + //always read the last line.. + if(i != inCube->Lines() && i + linc > inCube->Lines()) { + i = inCube->Lines() - linc; + } + } + + //Solve the least squares functions using QR Decomposition + sampSol.Solve(LeastSquares::QRD); + lineSol.Solve(LeastSquares::QRD); + + //If the user wants to save the residuals to a file, create a file and write + //the column titles to it. + TextFile oFile; + if(ui.WasEntered("RESIDUALS")) { + oFile.Open(ui.GetFilename("RESIDUALS"), "overwrite"); + oFile.PutLine("Sample,\tLine,\tX,\tY,\tSample Error,\tLine Error\n"); + } + + //Gather the statistics for the residuals from the least squares solutions + Statistics sampErr; + Statistics lineErr; + vector sampResiduals = sampSol.Residuals(); + vector lineResiduals = lineSol.Residuals(); + for(int i = 0; i < (int)sampResiduals.size(); i++) { + sampErr.AddData(sampResiduals[i]); + lineErr.AddData(lineResiduals[i]); + } + + //If a residuals file was specified, write the previous data, and the errors to the file. + if(ui.WasEntered("RESIDUALS")) { + for(int i = 0; i < sampSol.Rows(); i++) { + vector data = sampSol.GetInput(i); + iString tmp = ""; + tmp += iString(sampSol.GetExpected(i)); + tmp += ",\t"; + tmp += iString(lineSol.GetExpected(i)); + tmp += ",\t"; + tmp += iString(data[0]); + tmp += ",\t"; + tmp += iString(data[1]); + tmp += ",\t"; + tmp += iString(sampResiduals[i]); + tmp += ",\t"; + tmp += iString(lineResiduals[i]); + oFile.PutLine(tmp + "\n"); + } + } + oFile.Close(); + + //Records the error to the log + PvlGroup error( "Error" ); + error += PvlKeyword( "Degree", degree ); + error += PvlKeyword( "NumberOfPoints", (int)sampResiduals.size() ); + error += PvlKeyword( "SampleMinimumError", sampErr.Minimum() ); + error += PvlKeyword( "SampleAverageError", sampErr.Average() ); + error += PvlKeyword( "SampleMaximumError", sampErr.Maximum() ); + error += PvlKeyword( "SampleStdDeviationError", sampErr.StandardDeviation() ); + error += PvlKeyword( "LineMinimumError", lineErr.Minimum() ); + error += PvlKeyword( "LineAverageError", lineErr.Average() ); + error += PvlKeyword( "LineMaximumError", lineErr.Maximum() ); + error += PvlKeyword( "LineStdDeviationError", lineErr.StandardDeviation() ); + Application::Log( error ); + + //Close the input cubes for cleanup + p.EndProcess(); + + //If we want to warp the image, then continue, otherwise return + if(!ui.GetBoolean("NOWARP")) { + //Creates the mapping group + Pvl mapFile; + mapFile.Read(ui.GetFilename("MAP")); + PvlGroup &mapGrp = mapFile.FindGroup("Mapping",Pvl::Traverse); + + //Reopen the lat and long cubes + latCube = new Cube(); + latCube->SetVirtualBands(ui.GetInputAttribute("LATCUB").Bands()); + latCube->Open(ui.GetFilename("LATCUB")); + + lonCube = new Cube(); + lonCube->SetVirtualBands(ui.GetInputAttribute("LONCUB").Bands()); + lonCube->Open(ui.GetFilename("LONCUB")); + + PvlKeyword targetName; + + //If the user entered the target name + if(ui.WasEntered("TARGET")) { + targetName = PvlKeyword("TargetName", ui.GetString("TARGET")); + } + //Else read the target name from the input cube + else { + Pvl fromFile; + fromFile.Read(ui.GetFilename("FROM")); + targetName = fromFile.FindKeyword("TargetName", Pvl::Traverse); + } + + mapGrp.AddKeyword(targetName, Pvl::Replace); + + PvlKeyword equRadius; + PvlKeyword polRadius; + + + //If the user entered the equatorial and polar radii + if(ui.WasEntered("EQURADIUS") && ui.WasEntered("POLRADIUS")) { + equRadius = PvlKeyword("EquatorialRadius", ui.GetDouble("EQURADIUS")); + polRadius = PvlKeyword("PolarRadius", ui.GetDouble("POLRADIUS")); + } + //Else read them from the pck + else { + Filename pckFile("$base/kernels/pck/pck?????.tpc"); + pckFile.HighestVersion(); + + string pckFilename = pckFile.Expanded(); + + furnsh_c(pckFilename.c_str()); + + string target = targetName[0]; + SpiceInt code; + SpiceBoolean found; + + bodn2c_c (target.c_str(), &code, &found); + + if (!found) { + string msg = "Could not convert Target [" + target + + "] to NAIF code"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + SpiceInt n; + SpiceDouble radii[3]; + + bodvar_c(code,"RADII",&n,radii); + + equRadius = PvlKeyword("EquatorialRadius", radii[0] * 1000); + polRadius = PvlKeyword("PolarRadius", radii[2] * 1000); + } + + mapGrp.AddKeyword(equRadius, Pvl::Replace); + mapGrp.AddKeyword(polRadius, Pvl::Replace); + + + //If the latitude type is not in the mapping group, copy it from the input + if(!mapGrp.HasKeyword("LatitudeType")) { + if(ui.GetString("LATTYPE") == "PLANETOCENTRIC") { + mapGrp.AddKeyword(PvlKeyword("LatitudeType","Planetocentric"), Pvl::Replace); + } + else { + mapGrp.AddKeyword(PvlKeyword("LatitudeType","Planetographic"), Pvl::Replace); + } + } + + //If the longitude direction is not in the mapping group, copy it from the input + if(!mapGrp.HasKeyword("LongitudeDirection")) { + if(ui.GetString("LONDIR") == "POSITIVEEAST") { + mapGrp.AddKeyword(PvlKeyword("LongitudeDirection","PositiveEast"), Pvl::Replace); + } + else { + mapGrp.AddKeyword(PvlKeyword("LongitudeDirection","PositiveWest"), Pvl::Replace); + } + } + + //If the longitude domain is not in the mapping group, assume it is 360 + if(!mapGrp.HasKeyword("LongitudeDomain")) { + mapGrp.AddKeyword(PvlKeyword("LongitudeDomain","360"), Pvl::Replace); + } + + //If the default range is to be computed, use the input lat/long cubes to determine the range + if(ui.GetString("DEFAULTRANGE") == "COMPUTE") { + //NOTE - When computing the min/max longitude this application does not account for the + //longitude seam if it exists. Since the min/max are calculated from the statistics of + //the input longitude cube and then converted to the mapping group's domain they may be + //invalid for cubes containing the longitude seam. + + Statistics *latStats = latCube->Statistics(); + Statistics *lonStats = lonCube->Statistics(); + + double minLat = latStats->Minimum(); + double maxLat = latStats->Maximum(); + + bool isOcentric = ((std::string)mapGrp.FindKeyword("LatitudeType")) == "Planetocentric"; + + if(isOcentric) { + if(ui.GetString("LATTYPE") != "PLANETOCENTRIC") { + minLat = Projection::ToPlanetocentric(minLat, (double)equRadius, (double)polRadius); + maxLat = Projection::ToPlanetocentric(maxLat, (double)equRadius, (double)polRadius); + } + } + else { + if(ui.GetString("LATTYPE") == "PLANETOCENTRIC") { + minLat = Projection::ToPlanetographic(minLat, (double)equRadius, (double)polRadius); + maxLat = Projection::ToPlanetographic(maxLat, (double)equRadius, (double)polRadius); + } + } + + int lonDomain = (int)mapGrp.FindKeyword("LongitudeDomain"); + double minLon = lonDomain == 360 ? Projection::To360Domain(lonStats->Minimum()) : Projection::To180Domain(lonStats->Minimum()); + double maxLon = lonDomain == 360 ? Projection::To360Domain(lonStats->Maximum()) : Projection::To180Domain(lonStats->Maximum()); + + bool isPosEast = ((std::string)mapGrp.FindKeyword("LongitudeDirection")) == "PositiveEast"; + + if(isPosEast) { + if(ui.GetString("LONDIR") != "POSITIVEEAST") { + minLon = Projection::ToPositiveEast(minLon, lonDomain); + maxLon = Projection::ToPositiveEast(maxLon, lonDomain); + } + } + else { + if(ui.GetString("LONDIR") == "POSITIVEEAST") { + minLon = Projection::ToPositiveWest(minLon, lonDomain); + maxLon = Projection::ToPositiveWest(maxLon, lonDomain); + } + } + + if(minLon > maxLon) { + double temp = minLon; + minLon = maxLon; + maxLon = temp; + } + + mapGrp.AddKeyword(PvlKeyword("MinimumLatitude", minLat),Pvl::Replace); + mapGrp.AddKeyword(PvlKeyword("MaximumLatitude", maxLat),Pvl::Replace); + mapGrp.AddKeyword(PvlKeyword("MinimumLongitude", minLon),Pvl::Replace); + mapGrp.AddKeyword(PvlKeyword("MaximumLongitude", maxLon),Pvl::Replace); + } + + //If the user decided to enter a ground range then override + if (ui.WasEntered("MINLAT")) { + mapGrp.AddKeyword(PvlKeyword("MinimumLatitude", + ui.GetDouble("MINLAT")),Pvl::Replace); + } + + if (ui.WasEntered("MAXLAT")) { + mapGrp.AddKeyword(PvlKeyword("MaximumLatitude", + ui.GetDouble("MAXLAT")),Pvl::Replace); + } + + if (ui.WasEntered("MINLON")) { + mapGrp.AddKeyword(PvlKeyword("MinimumLongitude", + ui.GetDouble("MINLON")),Pvl::Replace); + } + + if (ui.WasEntered("MAXLON")) { + mapGrp.AddKeyword(PvlKeyword("MaximumLongitude", + ui.GetDouble("MAXLON")),Pvl::Replace); + } + + //If the pixel resolution is to be computed, compute the pixels/degree from the input + if (ui.GetString("PIXRES") == "COMPUTE") { + latBrick.SetBasePosition(1,1,1); + latCube->Read(latBrick); + + lonBrick.SetBasePosition(1,1,1); + lonCube->Read(lonBrick); + + //Read the lat and long at the upper left corner + double a = latBrick.at(0) * PI/180.0; + double c = lonBrick.at(0) * PI/180.0; + + latBrick.SetBasePosition(latCube->Samples(),latCube->Lines(),1); + latCube->Read(latBrick); + + lonBrick.SetBasePosition(lonCube->Samples(),lonCube->Lines(),1); + lonCube->Read(lonBrick); + + //Read the lat and long at the lower right corner + double b = latBrick.at(0) * PI/180.0; + double d = lonBrick.at(0) * PI/180.0; + + //Determine the angle between the two points + double angle = acos(cos(a) * cos(b) * cos(c - d) + sin(a) * sin(b)); + //double angle = acos((cos(a1) * cos(b1) * cos(b2)) + (cos(a1) * sin(b1) * cos(a2) * sin(b2)) + (sin(a1) * sin(a2))); + angle *= 180/PI; + + //Determine the number of pixels between the two points + double pixels = sqrt(pow(latCube->Samples() -1.0, 2.0) + pow(latCube->Lines() -1.0, 2.0)); + + //Add the scale in pixels/degree to the mapping group + mapGrp.AddKeyword(PvlKeyword("Scale", + pixels/angle, "pixels/degree"), + Pvl::Replace); + if (mapGrp.HasKeyword("PixelResolution")) { + mapGrp.DeleteKeyword("PixelResolution"); + } + } + + + // If the user decided to enter a resolution then override + if (ui.GetString("PIXRES") == "MPP") { + mapGrp.AddKeyword(PvlKeyword("PixelResolution", + ui.GetDouble("RESOLUTION"), "meters/pixel"), + Pvl::Replace); + if (mapGrp.HasKeyword("Scale")) { + mapGrp.DeleteKeyword("Scale"); + } + } + else if (ui.GetString("PIXRES") == "PPD") { + mapGrp.AddKeyword(PvlKeyword("Scale", + ui.GetDouble("RESOLUTION"), "pixels/degree"), + Pvl::Replace); + if (mapGrp.HasKeyword("PixelResolution")) { + mapGrp.DeleteKeyword("PixelResolution"); + } + } + + //Create a projection using the map file we created + int samples,lines; + Projection *outmap = ProjectionFactory::CreateForCube(mapFile,samples,lines,false); + + //Write the map file to the log + Application::GuiLog(mapGrp); + + //Create a process rubber sheet + ProcessRubberSheet r; + + //Set the input cube + inCube = r.SetInputCube("FROM"); + + double tolerance = ui.GetDouble("TOLERANCE") * outmap->Resolution(); + + //Create a new transform object + Transform *transform = new nocam2map (sampSol, lineSol, outmap, + latCube, lonCube, + ui.GetString("LATTYPE") == "PLANETOCENTRIC", + ui.GetString("LONDIR") == "POSITIVEEAST", + tolerance, ui.GetInteger("ITERATIONS"), + inCube->Samples(), inCube->Lines(), + samples, lines); + + //Allocate the output cube and add the mapping labels + Cube *oCube = r.SetOutputCube ("TO", transform->OutputSamples(), + transform->OutputLines(), + inCube->Bands()); + oCube->PutGroup(mapGrp); + + //Determine which interpolation to use + Interpolator *interp = NULL; + if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { + interp = new Interpolator(Interpolator::NearestNeighborType); + } + else if (ui.GetString("INTERP") == "BILINEAR") { + interp = new Interpolator(Interpolator::BiLinearType); + } + else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { + interp = new Interpolator(Interpolator::CubicConvolutionType); + } + + //Warp the cube + r.StartProcess(*transform, *interp); + r.EndProcess(); + + // add mapping to print.prt + PvlGroup mapping = outmap->Mapping(); + Application::Log(mapping); + + //Clean up + delete latCube; + delete lonCube; + + delete outmap; + delete transform; + delete interp; + } +} + + +// Transform object constructor +nocam2map::nocam2map (LeastSquares sample, LeastSquares line, Projection *outmap, + Cube *latCube, Cube *lonCube, + bool isOcentric, bool isPosEast, + double tolerance, int iterations, + const int inputSamples, const int inputLines, + const int outputSamples, const int outputLines) { + + p_sampleSol = &sample; + p_lineSol = &line; + p_outmap = outmap; + p_inputSamples = inputSamples; + p_inputLines = inputLines; + p_outputSamples = outputSamples; + p_outputLines = outputLines; + p_latCube = latCube; + p_lonCube = lonCube; + p_isOcentric = isOcentric; + p_isPosEast = isPosEast; + p_tolerance = tolerance; + p_iterations = iterations; + p_latCenter = p_latCube->Statistics()->Average() * PI/180.0; + p_lonCenter = p_lonCube->Statistics()->Average() * PI/180.0; + p_radius = p_outmap->LocalRadius(p_latCenter); +} + + + +// Transform method mapping output line/samps to lat/lons to input line/samps +bool nocam2map::Xform (double &inSample, double &inLine, + const double outSample, const double outLine) { + if (!p_outmap->SetWorld(outSample,outLine)) return false; + + if(outSample > p_outputSamples) return false; + if(outLine > p_outputLines) return false; + + //Get the known latitude and longitudes from the projection + //Convert to the input's latitude/longitude domain if necessary + double lat_known, lon_known; + + if(p_outmap->IsPlanetocentric()) { + if(!p_isOcentric) lat_known = p_outmap->ToPlanetographic(p_outmap->Latitude()); + else lat_known = p_outmap->Latitude(); + } + else { + if(p_isOcentric) lat_known = p_outmap->ToPlanetocentric(p_outmap->Latitude()); + else lat_known = p_outmap->Latitude(); + } + + if(p_outmap->IsPositiveEast()) { + if(!p_isPosEast) lon_known = p_outmap->ToPositiveWest(p_outmap->Longitude(), 360); + else lon_known = p_outmap->Longitude(); + } + else { + if(p_isPosEast) lon_known = p_outmap->ToPositiveEast(p_outmap->Longitude(), 360); + else lon_known = p_outmap->Longitude(); + } + + lat_known *= PI/180.0; + lon_known *= PI/180.0; + + //Project the known lat/long to x/y using the stereographic projection + double k_known = 2/(1 + sin(p_latCenter) * sin(lat_known) + cos(p_latCenter)*cos(lat_known)*cos(lon_known - p_lonCenter)); + double x_known = k_known * cos(lat_known) * sin(lon_known - p_lonCenter); + double y_known = k_known * (cos(p_latCenter) * sin(lat_known)) - (sin(p_latCenter) * cos(lat_known) * cos(lon_known - p_lonCenter)); + + vector data_known; + data_known.push_back(x_known); + data_known.push_back(y_known); + + //Get the sample/line guess from the least squares solutions + double sample_guess = p_sampleSol->Evaluate(data_known); + double line_guess = p_lineSol->Evaluate(data_known); + + //If the sample/line guess is out of bounds return false + if (sample_guess < -1.5) return false; + if (line_guess < -1.5) return false; + if (sample_guess > p_inputSamples + 1.5) return false; + if (line_guess > p_inputLines + 1.5) return false; + + if (sample_guess < 0.5) sample_guess = 1; + if (line_guess < 0.5) line_guess = 1; + if (sample_guess > p_inputSamples + 0.5) sample_guess = p_inputSamples; + if (line_guess > p_inputLines + 0.5) line_guess = p_inputLines; + + //Create a bilinear interpolator + Interpolator interp(Interpolator::BiLinearType); + + //Create a 2x2 buffer to read the lat and long cubes + Portal latPortal(interp.Samples(), interp.Lines(), + p_latCube->PixelType() , + interp.HotSample(), interp.HotLine()); + + Portal lonPortal(interp.Samples(), interp.Lines(), + p_lonCube->PixelType() , + interp.HotSample(), interp.HotLine()); + + //Set the buffers positions to the sample/line guess and read from the lat/long cubes + latPortal.SetPosition (sample_guess, line_guess, 1); + p_latCube->Read(latPortal); + + lonPortal.SetPosition (sample_guess, line_guess, 1); + p_lonCube->Read(lonPortal); + + //Get the lat/long guess from the interpolator + double lat_guess = interp.Interpolate(sample_guess, line_guess, latPortal.DoubleBuffer()) * PI/180.0; + double lon_guess = interp.Interpolate(sample_guess, line_guess, lonPortal.DoubleBuffer()) * PI/180.0; + + //Project the lat/long guess to x/y using the stereographic projection + double k_guess = 2/(1 + sin(p_latCenter) * sin(lat_guess) + cos(p_latCenter)*cos(lat_guess)*cos(lon_guess - p_lonCenter)); + double x_guess = k_guess * cos(lat_guess) * sin(lon_guess - p_lonCenter); + double y_guess = k_guess * (cos(p_latCenter) * sin(lat_guess)) - (sin(p_latCenter) * cos(lat_guess) * cos(lon_guess - p_lonCenter)); + + //Calculate the difference between the known x/y to the x/y from our least squares solutions + double x_diff = abs(x_guess - x_known) * p_radius; + double y_diff = abs(y_guess - y_known) * p_radius; + + //If the difference is above the tolerance, correct it until it is below the tolerance or we have iterated through a set amount of times + int iteration = 0; + while(x_diff > p_tolerance || y_diff > p_tolerance) { + if(iteration++ >= p_iterations) return false; + + //Create a 1st order polynomial function + PolynomialBivariate sampFunct(1); + PolynomialBivariate lineFunct(1); + + //Create a least squares solution + LeastSquares sampConverge(sampFunct); + LeastSquares lineConverge(lineFunct); + + //Add the points around the line/sample guess point to the least squares matrix + for(int i = (int)(line_guess + 0.5) -1; i <= (int)(line_guess + 0.5) + 1; i++) { + //If the line is out of bounds, then skip it + if (i < 1 || i > p_inputLines) continue; + for(int j = (int)(sample_guess + 0.5) -1; j <= (int)(sample_guess + 0.5) + 1; j++) { + //If the sample is out of bounds, then skip it + if(j < 1 || j > p_inputSamples) continue; + + latPortal.SetPosition (j, i, 1); + p_latCube->Read(latPortal); + if(IsSpecial(latPortal.at(0))) continue; + double n_lat = latPortal.at(0) * PI/180.0; + + lonPortal.SetPosition (j, i, 1); + p_lonCube->Read(lonPortal); + if(IsSpecial(lonPortal.at(0))) continue; + double n_lon = lonPortal.at(0) * PI/180.0; + + //Conver the lat/lon to x/y using the stereographic projection + double n_k = 2/(1 + sin(p_latCenter) * sin(n_lat) + cos(p_latCenter)*cos(n_lat)*cos(n_lon - p_lonCenter)); + double n_x = n_k * cos(n_lat) * sin(n_lon - p_lonCenter); + double n_y = n_k * (cos(p_latCenter) * sin(n_lat)) - (sin(p_latCenter) * cos(n_lat) * cos(n_lon - p_lonCenter)); + + //Add the points to the least squares solution + vector data; + data.push_back(n_x); + data.push_back(n_y); + sampConverge.AddKnown(data, j); + lineConverge.AddKnown(data, i); + } + } + //TODO: What if solve can't and throws an error? + + //Solve the least squares functions + sampConverge.Solve(LeastSquares::QRD); + lineConverge.Solve(LeastSquares::QRD); + + //Try to solve the known data with our new function + sample_guess = sampConverge.Evaluate(data_known); + line_guess = lineConverge.Evaluate(data_known); + + //If the new sample/line is out of bounds return false + if (sample_guess < -1.5) return false; + if (line_guess < -1.5) return false; + if (sample_guess > p_inputSamples + 1.5) return false; + if (line_guess > p_inputLines + 1.5) return false; + + if (sample_guess < 0.5) sample_guess = 1; + if (line_guess < 0.5) line_guess = 1; + if (sample_guess > p_inputSamples + 0.5) sample_guess = p_inputSamples; + if (line_guess > p_inputLines + 0.5) line_guess = p_inputLines; + + //Set the buffers positions to the sample/line guess and read from the lat/long cubes + latPortal.SetPosition(sample_guess, line_guess, 1); + p_latCube->Read(latPortal); + + lonPortal.SetPosition(sample_guess, line_guess, 1); + p_lonCube->Read(lonPortal); + + //Get the lat/long guess from the interpolator + lat_guess = interp.Interpolate(sample_guess, line_guess, latPortal.DoubleBuffer()) * PI/180.0; + lon_guess = interp.Interpolate(sample_guess, line_guess, lonPortal.DoubleBuffer()) * PI/180.0; + + //Project the lat/long guess to x/y using the stereographic projection + k_guess = 2/(1 + sin(p_latCenter) * sin(lat_guess) + cos(p_latCenter)*cos(lat_guess)*cos(lon_guess - p_lonCenter)); + x_guess = k_guess * cos(lat_guess) * sin(lon_guess - p_lonCenter); + y_guess = k_guess * (cos(p_latCenter) * sin(lat_guess)) - (sin(p_latCenter) * cos(lat_guess) * cos(lon_guess - p_lonCenter)); + + + //Calculate the difference between the known x/y to the x/y from our least squares solutions + x_diff = abs(x_guess - x_known) * p_radius; + y_diff = abs(y_guess - y_known) * p_radius; + } + + + //Set the input sample/line to the sample/line we've determined to be the closest fit + inSample = sample_guess; + inLine = line_guess; + return true; +} + +int nocam2map::OutputSamples () const { + return p_outputSamples; +} + +int nocam2map::OutputLines () const { + return p_outputLines; +} + +// Helper function to print out mapfile to session log +void PrintMap() { + UserInterface &ui = Application::GetUserInterface(); + + // Get mapping group from map file + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + //Write map file out to the log + Isis::Application::GuiLog(userGrp); +} + +//Helper function to get camera resolution. +void ComputePixRes () { + Process p; + UserInterface &ui = Application::GetUserInterface(); + Cube *latCube = p.SetInputCube("LATCUB"); + Cube *lonCube = p.SetInputCube("LONCUB"); + Brick latBrick(1,1,1,latCube->PixelType()); + Brick lonBrick(1,1,1,lonCube->PixelType()); + latBrick.SetBasePosition(1,1,1); + latCube->Read(latBrick); + + lonBrick.SetBasePosition(1,1,1); + lonCube->Read(lonBrick); + + double a = latBrick.at(0) * PI/180.0; + double c = lonBrick.at(0) * PI/180.0; + + latBrick.SetBasePosition(latCube->Samples(),latCube->Lines(),1); + latCube->Read(latBrick); + + lonBrick.SetBasePosition(lonCube->Samples(),lonCube->Lines(),1); + lonCube->Read(lonBrick); + + double b = latBrick.at(0) * PI/180.0; + double d = lonBrick.at(0) * PI/180.0; + + double angle = acos(cos(a) * cos(b) * cos(c - d) + sin(a) * sin(b)); + angle *= 180/PI; + + double pixels = sqrt(pow(latCube->Samples() -1.0, 2.0) + pow(latCube->Lines() -1.0, 2.0)); + + p.EndProcess(); + + ui.Clear("RESOLUTION"); + ui.PutDouble("RESOLUTION", pixels/angle); + + ui.Clear("PIXRES"); + ui.PutAsString("PIXRES","PPD"); +} + +// Helper function to get mapping resolution. +void LoadMapRes () { + UserInterface &ui = Application::GetUserInterface(); + + // Get mapping group from map file + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + // Set resolution + if (userGrp.HasKeyword("Scale")) { + ui.Clear("RESOLUTION"); + ui.PutDouble("RESOLUTION",userGrp["Scale"]); + ui.Clear("PIXRES"); + ui.PutAsString("PIXRES","PPD"); + } + else if (userGrp.HasKeyword("PixelResolution")) { + ui.Clear("RESOLUTION"); + ui.PutDouble("RESOLUTION",userGrp["PixelResolution"]); + ui.Clear("PIXRES"); + ui.PutAsString("PIXRES","MPP"); + } + else { + string msg = "No resolution value found in [" + ui.GetFilename("MAP") + "]"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } +} + +//Helper function to compute input range. +void ComputeInputRange () { + Process p; + Cube *latCub = p.SetInputCube("LATCUB"); + Cube *lonCub = p.SetInputCube("LONCUB"); + + UserInterface &ui = Application::GetUserInterface(); + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + Statistics *latStats = latCub->Statistics(); + Statistics *lonStats = lonCub->Statistics(); + + double minLat = latStats->Minimum(); + double maxLat = latStats->Maximum(); + + int lonDomain = userGrp.HasKeyword("LongitudeDomain") ? (int)userGrp.FindKeyword("LongitudeDomain") : 360; + double minLon = lonDomain == 360 ? Projection::To360Domain(lonStats->Minimum()) : Projection::To180Domain(lonStats->Minimum()); + double maxLon = lonDomain == 360 ? Projection::To360Domain(lonStats->Maximum()) : Projection::To180Domain(lonStats->Maximum()); + + if(userGrp.HasKeyword("LatitudeType")) { + bool isOcentric = ((std::string)userGrp.FindKeyword("LatitudeType")) == "Planetocentric"; + + double equRadius; + double polRadius; + + //If the user entered the equatorial and polar radii + if(ui.WasEntered("EQURADIUS") && ui.WasEntered("POLRADIUS")) { + equRadius = ui.GetDouble("EQURADIUS"); + polRadius = ui.GetDouble("POLRADIUS"); + } + //Else read them from the pck + else { + Filename pckFile("$base/kernels/pck/pck?????.tpc"); + pckFile.HighestVersion(); + + string pckFilename = pckFile.Expanded(); + + furnsh_c(pckFilename.c_str()); + + string target; + + //If user entered target + if(ui.WasEntered("TARGET")) { + target = ui.GetString("TARGET"); + } + //Else read the target name from the input cube + else { + Pvl fromFile; + fromFile.Read(ui.GetFilename("FROM")); + target = (string)fromFile.FindKeyword("TargetName", Pvl::Traverse); + } + + SpiceInt code; + SpiceBoolean found; + + bodn2c_c (target.c_str(), &code, &found); + + if (!found) { + string msg = "Could not convert Target [" + target + + "] to NAIF code"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + SpiceInt n; + SpiceDouble radii[3]; + + bodvar_c(code,"RADII",&n,radii); + + equRadius = radii[0] * 1000; + polRadius = radii[2] * 1000; + } + + if(isOcentric) { + if(ui.GetString("LATTYPE") != "PLANETOCENTRIC") { + minLat = Projection::ToPlanetocentric(minLat, (double)equRadius, (double)polRadius); + maxLat = Projection::ToPlanetocentric(maxLat, (double)equRadius, (double)polRadius); + } + } + else { + if(ui.GetString("LATTYPE") == "PLANETOCENTRIC") { + minLat = Projection::ToPlanetographic(minLat, (double)equRadius, (double)polRadius); + maxLat = Projection::ToPlanetographic(maxLat, (double)equRadius, (double)polRadius); + } + } + } + + if(userGrp.HasKeyword("LongitudeDirection")) { + bool isPosEast = ((std::string)userGrp.FindKeyword("LongitudeDirection")) == "PositiveEast"; + + if(isPosEast) { + if(ui.GetString("LONDIR") != "POSITIVEEAST") { + minLon = Projection::ToPositiveEast(minLon, lonDomain); + maxLon = Projection::ToPositiveEast(maxLon, lonDomain); + + if(minLon > maxLon) { + double temp = minLon; + minLon = maxLon; + maxLon = temp; + } + } + } + else { + if(ui.GetString("LONDIR") == "POSITIVEEAST") { + minLon = Projection::ToPositiveWest(minLon, lonDomain); + maxLon = Projection::ToPositiveWest(maxLon, lonDomain); + + if(minLon > maxLon) { + double temp = minLon; + minLon = maxLon; + maxLon = temp; + } + } + } + } + + // Set ground range parameters in UI + ui.Clear("MINLAT"); + ui.PutDouble("MINLAT", minLat); + ui.Clear("MAXLAT"); + ui.PutDouble("MAXLAT", maxLat); + ui.Clear("MINLON"); + ui.PutDouble("MINLON", minLon); + ui.Clear("MAXLON"); + ui.PutDouble("MAXLON", maxLon); + + p.EndProcess(); + + // Set default ground range param to camera + ui.Clear("DEFAULTRANGE"); + ui.PutAsString("DEFAULTRANGE","COMPUTE"); +} + +//Helper function to get ground range from map file. +void LoadMapRange() { + UserInterface &ui = Application::GetUserInterface(); + + // Get map file + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + // Set ground range keywords that are found in mapfile + int count = 0; + ui.Clear("MINLAT"); + ui.Clear("MAXLAT"); + ui.Clear("MINLON"); + ui.Clear("MAXLON"); + if (userGrp.HasKeyword("MinimumLatitude")) { + ui.PutDouble("MINLAT",userGrp["MinimumLatitude"]); + count++; + } + if (userGrp.HasKeyword("MaximumLatitude")) { + ui.PutDouble("MAXLAT",userGrp["MaximumLatitude"]); + count++; + } + if (userGrp.HasKeyword("MinimumLongitude")) { + ui.PutDouble("MINLON",userGrp["MinimumLongitude"]); + count++; + } + if (userGrp.HasKeyword("MaximumLongitude")) { + ui.PutDouble("MAXLON",userGrp["MaximumLongitude"]); + count++; + } + + // Set default ground range param to map + ui.Clear("DEFAULTRANGE"); + ui.PutAsString("DEFAULTRANGE","MAP"); + + if (count < 4) { + string msg = "One or more of the values for the ground range was not found"; + msg += " in [" + ui.GetFilename("MAP") + "]"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } +} diff --git a/isis/src/base/apps/nocam2map/nocam2map.h b/isis/src/base/apps/nocam2map/nocam2map.h new file mode 100644 index 0000000000000000000000000000000000000000..245c729a2cb40cd0a28da8974cc8c46f39e2502b --- /dev/null +++ b/isis/src/base/apps/nocam2map/nocam2map.h @@ -0,0 +1,44 @@ +#ifndef nocam2map_h +#define nocam2map_h + +#include "Transform.h" + +class nocam2map : public Isis::Transform { + private: + Isis::LeastSquares *p_sampleSol; + Isis::LeastSquares *p_lineSol; + Isis::Projection *p_outmap; + Isis::Cube *p_latCube; + Isis::Cube *p_lonCube; + bool p_isOcentric; + bool p_isPosEast; + int p_inputSamples; + int p_inputLines; + int p_outputSamples; + int p_outputLines; + double p_latCenter; + double p_lonCenter; + double p_radius; + double p_tolerance; + int p_iterations; + + public: + // constructor + nocam2map (Isis::LeastSquares sample, Isis::LeastSquares line, Isis::Projection *outmap, + Isis::Cube *latCube, Isis::Cube *lonCube, + bool isOcentric ,bool isPosEast, + double tolerance, int iterations, + const int inputSamples, const int inputLines, + const int outputSamples, const int outputLines); + + // destructor + ~nocam2map () {}; + + // Implementations for parent's pure virtual members + bool Xform (double &inSample, double &inLine, + const double outSample, const double outLine); + int OutputSamples () const; + int OutputLines () const; +}; + +#endif diff --git a/isis/src/base/apps/nocam2map/nocam2map.xml b/isis/src/base/apps/nocam2map/nocam2map.xml new file mode 100644 index 0000000000000000000000000000000000000000..6732bc03a45b064ae50653f5901dcc04c56b9230 --- /dev/null +++ b/isis/src/base/apps/nocam2map/nocam2map.xml @@ -0,0 +1,618 @@ + + + + + + Map project a cube without a camera model + + + +

    + This program will map project a raw instrument cube without a camera + model. However, the lack of a camera model requires latitude/longitude + information at each pixel in the raw cube. This must be facilitated + through a latitude image and longitude image with the same size as the raw + instrument cube. +

    + +

    + The procedure to project the input cube is output driven. That is, we + create an output map cube (as specified by the user) and at each output + pixel, compute its projected latitude/longitude using the projection + parameters. Using this coordinate we must search for that position in + the two input cubes (latitude/longitude). If found, we will have a + sub-pixel location that has a 1-1 correspondence with the raw instrument + pixel. An interpolator (nearest neighbor, bilinear, or cubic convolution) + is then used to compute a value for the output pixel. +

    + +

    + Therefore the root of the problem is finding the latitude/longitude in the + two input cubes as it is a 2-dimensional search. We do this by first + creating two polynomial functions of a user-specified order (DEGREE), one + for sample and one for line. These functions, f(lat,long) = sample and + g(lat,long) = line, are dervied using a least-squares computation by + collecting a sparse set of control points (line,samp)-to-(lat,long). The + sparseness is controlled by the SINC and LINC. Unfortunately the + polynomial is not accurate enough to supply the mapping to sub-pixel + accuracy. The level of errors (between control points and the equations + derived) can be written to the RESIDUAL file for examination. +

    + +

    + To achieve sub-pixel accuracy, we use the polynomials to get us close + (generally within 6 pixels). Using this estimated location, two affine + transforms are computed by collecting a small 3x3 window of control + points. These equations are used to further refine the estimated location. + We iterate this process until our estimated sample/line is within an + acceptable tolerance (TOLERANCE) of latitude/longitude values contained in + the two cubes (LATCUB/LONCUB) or until the number of iterations is + exceeded (ITERATIONS). +

    + +

    + Defining the output map is controlled as follows: +

      +
    • ProjectionName - Should be specified by the map file
    • +
    • TargetName - Will be searched for in the FROM cube or can be + specified by the user. +
    • +
    • EquatorialRadius and PolarRadius- Will be automatically computed + from NAIF kernels or can be specified by the user. +
    • +
    • LatitudeType - Will be read from the map if available, + otherwise will be set to the latitude type of the LATCUB
    • +
    • LongitudeDirection - Will be read from the map if available, + otherwise will be set to the longitude direction of the LONCUB
    • +
    • LongitudeDomain - 0-360 by default.
    • +
    • MinimumLatitude - Can be computed from the LATCUB, read from the map + file or user specified.
    • +
    • MaximumLatitude - Can be computed from the LATCUB, read from + the map or user specified.
    • +
    • MinimumLongitude - Can be computed from the LONCUB, read from + the map or user specified.
    • +
    • MaximumLongitude - Can be computed from the LONCUB, read from + the map or user specified.
    • +
    • Scale or PixelResolution - Can be computed1 from the + input, read from the map, or user specified in either meters/pixel + (PixelResolution) or pixels/degree (Scale)
    • +
    +

    + +
    +1To compute the scale we find the number of pixels from point (1, 1) to point (nsamples, nlines) in the input cube:
    +  sqrt[(nsamples-1)2 + (nlines-1)2]
    + And the angle across this line:
    +  acos(cos(latitude_point1) * cos(latitude_point2) * cos(longitude_point1 - longitude_point2) + sin(latitude_point1) * sin(latitude_point2))
    + The scale is equal to the number of pixels divided by the angle in pixels per degree.
    +      
    + +
    + + + Map Projection + + + + + Original Version + + + Fixed parameter names + + + The min/max longitude/latitude are now converted from the input domain to + the map file's domain if necessary. + + + Mapping group parameters are now placed into the print file. + + + + + + + cube + input + + Input cube to be mapped + + + This will specify the raw instrument cube to be mapped. + + + *.cub + + + + + cube + input + + Input cube to read latitude values + + + The DN values from this cube will be used as the latitude values for + the input cube, samples and lines must match the FROM cube. + + + *.cub + + + + + string + + PLANETOCENTRIC + + The latitude type + + Specify the latitude type, either in planetographic or planetocentric + coordinates. + + + + + + + + + cube + input + + Input cube to read longitude values + + + The DN values from this cube will be used as the longitude values for + the input cube, samples and lines must match the FROM cube. + + + *.cub + + + + + string + + POSITIVEEAST + + The longitude direction + + Specify the longitude direction, either positive east or positive + west. + + + + + + + + + cube + output + + Newly mapped cube + + + This file will contain the results of the remapping. + + + *.cub + + + + + + + integer + + 3 + + Degree of polynomial functions + + The order of the polynomial functions to compute sample/line from + latitude/longitude. + + + + + integer + + Computed + + Sample Increment + + The number of samples skipped over when adding points to the + polynomial functions. + + + + + integer + + Computed + + Line Increment + + The number of lines skipped over when adding points to the + polynomial functions. + + + + + filename + output + + none + + File to write residuals to + + If a file is specified, residuals for each point (line, sample) + are written to the file for examination. + + + + + boolean + false + Specify whether or not to warp the image + + If set to true, the image will not be processed and warped, and will + only calculate the polynomial fit with errors. + + + TO + MAP + PIXRES + RESOLUTION + TARGET + EQURADIUS + POLRADIUS + DEFAULTRANGE + MINLAT + MAXLAT + MINLON + MAXLON + TOLERANCE + ITERATIONS + INTERP + + + + + + + filename + input + + File containing mapping parameters + + $base/templates/maps + $base/templates/maps/sinusoidal.map + + A file containing the desired output mapping parameters in PVL form. This + file can be a simple hand produced label file. It can also be an existing cube label + which contains a Mapping group. You can produce map file using the "maptemplate" program. + + + + PrintMap + View MapFile + + This helper button will cat out the mapping group of the given mapfile to the session log + of the application + + $ISIS3DATA/base/icons/labels.png + + + + *.map *.cub + + + + + string + Defines how the pixel resolution in the output map file is obtained + COMPUTE + + This parameter is used to specify how the pixel resolution is obtained for the output map + projected cube. + + + + + ComputePixRes + Compute Pixel Resolution + This helper button will compute the pixel + resolution from the input + $ISIS3DATA/base/icons/exec.png + + + LoadMapRes + Load Map File Resolution + This helper button will load the default resolution from the map file + + + + + + + + + + + + + + + + double + Pixel resolution + + Specifies the resolution in either meters per pixel or pixels per degree + + 0.0 + + + + string + Read from FROM cube + The target planet to map from/to + + This will specify the target planet to map from/to, i.e. Mars, Venus, + etc. + + + + + double + Read from PCK file + Equatorial radius of target + + The equatorial radius can be read using the NAIF routines to get + the radius from the specified target planet, or read from the user. + + 0.0 + + POLRADIUS + + + + + double + Read from PCK file + Polar radius of target + + The polar radius can be read using the NAIF routines to get + the radius from the specified target planet, or read from the user. + + 0.0 + + EQURADIUS + + + + + + + string + Defines how the default ground range is determined + COMPUTE + + This parameter is used to specify how the default latitude/longitude ground range for the output map projected image + is obtained. The ground range can be obtained from the camera or map file. Note the user can overide the default using the MINLAT, MAXLAT, MINLON, MAXLON parameters. + The purpose of the ground range is to define the coverage of the map projected image. Essentially, the ground range and + pixel resolution are used to compute the size (samples and line) of the output image. + + + + + ComputeInputRange + Compute Input Ground range + This helper button will load the default ground range + from the input + $ISIS3DATA/base/icons/exec.png + + + LoadMapRange + Load Map File Ground Range + This helper button will load the default ground range from the map file + + + + + + + + + + + + double + Starting latitude + Use default range + + The minimum latitude of the ground range. If this is entered by the user it will override the default camera or map value. By default, + planetocentric latitudes are assumed unless the MAP file specifies otherwise. + + + -90.0 + 90.0 + + + + double + Ending latitude + Use default range + + The maximum latitude of the ground range. If this is entered by the user it will override the default camera or map value. + By default, planetocentric latitudes are assumed unless the MAP file specifies otherwise. + + -90.0 + 90.0 + MINLAT + + + + double + Starting longitude + Use default range + + The minimum longitude of the ground range. If this is entered by the user it will override the default camera or map value. + By default, positive east longitudes in the range of 0 to 360 are assumed unless the MAP file specifies otherwise. + + + + + double + Ending longitude + Use default range + + The maximum longitude of the ground range. If this is entered by the user it will override the default camera or map value. + By default, positive east longitudes in the range of 0 to 360 are assumed unless the MAP file specifies otherwise. + + MINLON + + + + + + double + Geometric tolerance in pixels + + 1.0 + + + When computing the sample/line to be mapped from input->output, the + sample and line are determined from the polynomial fit function. The + transform then calculates the pixel differences in stereographically + projected latitude/longitude from the input at sample/line to + the output's stereographically projected latitude/longitude. If this + difference is greater than the tolerance, then an affine + transformation is iteratively used until the difference is less than + the tolerance or is set to null after a set number of iterations. + + 0.0 + + + + integer + + 10 + + The number of iterations to meet tolerance + + If the tolerance has not been met in the number of iterations + specified, then the pixel is not mapped to the output. + + 1 + + + + + + string + + CUBICCONVOLUTION + + Type of interpolation + + This is the type of interpolation to be performed on the input. + + + + + + + + + + + + +
    diff --git a/isis/src/base/apps/nocam2map/tsts/Makefile b/isis/src/base/apps/nocam2map/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/nocam2map/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/nocam2map/tsts/default/Makefile b/isis/src/base/apps/nocam2map/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..34cec14afa011beb955436308c8e73f627dc5914 --- /dev/null +++ b/isis/src/base/apps/nocam2map/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME = nocam2map + +nocam2maptruth.cub.TOLERANCE = .0002 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/frt_61b2_trdr.cub+400 \ + latcub=$(INPUT)/frt_61b2_ddr.cub+4 \ + loncub=$(INPUT)/frt_61b2_ddr.cub+5 \ + to=$(OUTPUT)/nocam2maptruth.cub > /dev/null; diff --git a/isis/src/base/apps/noisefilter/Makefile b/isis/src/base/apps/noisefilter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/noisefilter/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/noisefilter/assets/image/f332s28.jpg b/isis/src/base/apps/noisefilter/assets/image/f332s28.jpg new file mode 100644 index 0000000000000000000000000000000000000000..def4a89c7442234c6038c46e20cec79d8e92869c Binary files /dev/null and b/isis/src/base/apps/noisefilter/assets/image/f332s28.jpg differ diff --git a/isis/src/base/apps/noisefilter/assets/image/nzfltr.jpg b/isis/src/base/apps/noisefilter/assets/image/nzfltr.jpg new file mode 100644 index 0000000000000000000000000000000000000000..26b7f2a8eb2ecd84d0656540569bf6848c32263a Binary files /dev/null and b/isis/src/base/apps/noisefilter/assets/image/nzfltr.jpg differ diff --git a/isis/src/base/apps/noisefilter/assets/image/nzfltrGui.jpg b/isis/src/base/apps/noisefilter/assets/image/nzfltrGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4bd0af047b11700da86acdd375bd86079bdf48f1 Binary files /dev/null and b/isis/src/base/apps/noisefilter/assets/image/nzfltrGui.jpg differ diff --git a/isis/src/base/apps/noisefilter/assets/thumb/f332s28.jpg b/isis/src/base/apps/noisefilter/assets/thumb/f332s28.jpg new file mode 100644 index 0000000000000000000000000000000000000000..63ff66320941aa6e20e53e9c866b62db71b11aa7 Binary files /dev/null and b/isis/src/base/apps/noisefilter/assets/thumb/f332s28.jpg differ diff --git a/isis/src/base/apps/noisefilter/assets/thumb/nzfltr.jpg b/isis/src/base/apps/noisefilter/assets/thumb/nzfltr.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bb98ac9c3ce3046525d501054319e862fc217377 Binary files /dev/null and b/isis/src/base/apps/noisefilter/assets/thumb/nzfltr.jpg differ diff --git a/isis/src/base/apps/noisefilter/assets/thumb/nzfltrGui.jpg b/isis/src/base/apps/noisefilter/assets/thumb/nzfltrGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ebdb1b5d907a93b947fe62ee62c6823a4ed4679d Binary files /dev/null and b/isis/src/base/apps/noisefilter/assets/thumb/nzfltrGui.jpg differ diff --git a/isis/src/base/apps/noisefilter/noisefilter.cpp b/isis/src/base/apps/noisefilter/noisefilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8dbabbdf8c215a2e6c766e13627ded0a33908824 --- /dev/null +++ b/isis/src/base/apps/noisefilter/noisefilter.cpp @@ -0,0 +1,187 @@ +#include "Isis.h" +#include "ProcessByQuickFilter.h" +#include "UserInterface.h" + + +using namespace std; +using namespace Isis; + +// Globals and prototypes +void RemoveNoiseViaStd (Buffer &in, Buffer &out, QuickFilter &filter); +void RemoveNoiseViaDn (Buffer &in, Buffer &out, QuickFilter &filter); + +double tolmin; +double tolmax; +double flattol; +bool nullIsNoise; +bool hisIsNoise; +bool hrsIsNoise; +bool lisIsNoise; +bool lrsIsNoise; +int brightPixelsReplaced; +int darkPixelsReplaced; +int specialPixelsReplaced; +bool replaceWithAverage; + +// The noisefilter main routine + +void IsisMain() { + // Open the input cube + ProcessByQuickFilter p; + Cube *icube = p.SetInputCube("FROM"); + + // Setup the output cube + p.SetOutputCube("TO"); + + // Read tolerances + UserInterface &ui = Application::GetUserInterface(); + tolmin = ui.GetDouble ("TOLMIN"); + tolmax = ui.GetDouble ("TOLMAX"); + + // Will noise pixels be replaced with boxcar average or Null? + replaceWithAverage = true; + if (ui.GetString("REPLACE") == "NULL") replaceWithAverage = false; + + // Find out how to handle special pixels + nullIsNoise = ui.GetBoolean ("NULLISNOISE"); + hisIsNoise = ui.GetBoolean ("HISISNOISE"); + hrsIsNoise = ui.GetBoolean ("HRSISNOISE"); + lisIsNoise = ui.GetBoolean ("LISISNOISE"); + lrsIsNoise = ui.GetBoolean ("LRSISNOISE"); + + // Process each line + brightPixelsReplaced = 0; + darkPixelsReplaced = 0; + specialPixelsReplaced = 0; + if (ui.GetString("TOLDEF") == "STDDEV") { + flattol = ui.GetDouble("FLATTOL"); + p.StartProcess(RemoveNoiseViaStd); + } + else { + p.StartProcess(RemoveNoiseViaDn); + } + + // Generate a results group and log it + PvlGroup results("Results"); + results += PvlKeyword("DarkPixelsReplaced",darkPixelsReplaced); + results += PvlKeyword("BrightPixelsReplaced",brightPixelsReplaced); + results += PvlKeyword("SpecialPixelsReplaced",specialPixelsReplaced); + int pixelsReplaced = darkPixelsReplaced + brightPixelsReplaced + specialPixelsReplaced; + results += PvlKeyword("TotalPixelsReplaced",pixelsReplaced); + double pct = ((double)pixelsReplaced/ + ((double)icube->Samples()*(double)icube->Lines())) * 100.; + pct = (int) (pct * 10.0) / 10.0; + results += PvlKeyword("PercentChanged",pct); + Application::Log(results); + p.EndProcess(); +} + +// Standard deviation line processing routine +void RemoveNoiseViaStd (Buffer &in, Buffer &out, QuickFilter &filter) { + for (int i=0; i 0.0) ? tolmax : tolmin; + if (sqrDiff > tol * tol * filter.Variance(i)) noisy = true; + + // If we have noise replace it + if (noisy) { + out[i] = (replaceWithAverage) ? goodAvg : NULL8; + (diff > 0.0) ? brightPixelsReplaced++ : darkPixelsReplaced++; + } + + // Not noisy so copy it + else { + out[i] = in[i]; + } + } + + return; +} + +// DN noise filter line processing routine +void RemoveNoiseViaDn (Buffer &in, Buffer &out, QuickFilter &filter) { + for (int i=0; i 0.0) ? tolmax : tolmin; + if (abs(diff) > tol) noisy = true; + + // If we have noise replace it + if (noisy) { + out[i] = (replaceWithAverage) ? goodAvg : NULL8; + (diff > 0.0) ? brightPixelsReplaced++ : darkPixelsReplaced++; + } + + // Not noisy so copy it + else { + out[i] = in[i]; + } + } + + return; +} diff --git a/isis/src/base/apps/noisefilter/noisefilter.xml b/isis/src/base/apps/noisefilter/noisefilter.xml new file mode 100644 index 0000000000000000000000000000000000000000..0c2743fecdf4ee88093c90176747b307b4d66f07 --- /dev/null +++ b/isis/src/base/apps/noisefilter/noisefilter.xml @@ -0,0 +1,442 @@ + + + + + + Apply a noise removal filter to a cube + + + + This program applies a noise filter to a cube. Pixel values that + are considered to be noise will be replaced with either the average + of the boxcar or the Isis NULL value. The criteria for determining + whether a pixel is noise or not is given by the TOLMIN and TOLMAX + parameters. If the difference between the input pixel and the average + of the boxcar is greater than the tolerance given, the pixel is + considered to be noise and is replaced. If the STDDEV option is + chosen, then TOLMIN and TOLMAX indicate the tolerance in number of + standard deviations between the input pixel and the boxcar average + that determines whether the pixel is noise. The number of pixels + replaced and the corresponding percentage is output. + + + + Filters + + + + + lowpass + highpass + trimfilter + divfilter + svfilter + + + + + + Original version + + + Ported to Isis 3.0 + + + Add example. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Fixed compiler error with uninitialized variable after adding -O1 flag + + + Modified filename parameters to be cube parameters where necessary + + + Separated standard deviation and average noise filter options into two routines. Fixed problem + filtering special pixels. Modified explanations for TOLMIN and TOLMAX. + + + Modified results pvl to not include the results group + + + Added a flattol parameter - it replaces the tolmin parameter in isis2 boxfilter + + + Removed references to CubeInfo + + + + + boxfilter + + + + + + cube + input + + Input file + + + Input cube to filter + + + *.cub + + + + cube + output + + Output noisefilter cube + + + The resultant filtered cube + + + + + + + string + DN + + Defines the meaning of TOLMIN and TOLMAX + + + If DN is chosen TOLMIN and TOLMAX are in dn units. If STDDEV is + chosen, TOLMIN and TOLMAX are number of standard deviations. + + + + + + + + double + + Scaled tolerance value + + + Minimum tolerance value used in the STDDEV filter. If the difference + between the original pixel, and the average value of the noise filter is + less than the FLATTOL then the output pixel will remain unchanged + from the input pixel. Without this safeguard, very uniform inage areas + (low standard deviation) will be excessively smoothed, creating areas + of constant DN. + + 0.0 + 0.0 + + + + double + + Dark noise tolerance + + + If you are attempting to remove black speckle or other dark noise then you should be modifying this + parameter. When a pixel is being checked for noise, a difference between the pixel and boxcar + average is computed. If this difference is negative then TOLMIN will be used to determine if we + have noise, hence dark noise will be removed by modifying TOLMIN. + + For the DN option, if the absolute value of the difference (pixel - average) is less than TOLMIN, then + the input pixel is preserved. Otherwise it is considered noisy and will be replaced. + For the STDDEV option, if the absolute value of the difference is less than TOLMIN * standard deviation + of the boxcar then the input pixel is preserved. Otherwise it is considered noisy and will be replaced. + + In general, a high tolerance means fewer pixels will be replaced and lower tolerance will cause more + pixels to be replaced. Too small of a tolerance can actually replace real/good data. For the STDDEV option, + you might try TOLMIN=3 as a starting point. For the DN option, try TOLMIN=2. + + 0.0 + 20 + + + double + + Bright noise tolerance + + + If you are attempting to remove white speckle or other bright noise then you should be modifying this + parameter. When a pixel is being checked for noise, a difference between the pixel and boxcar + average is computed. If this difference is positive then TOLMAX will be used to determine if we + have noise, hence white noise will be removed by modifying TOLMAX. + + For the DN option, if the difference (pixel - average) is less than TOLMAX, then the input pixel is + preserved. Otherwise it is considered noisy and will be replaced. + For the STDDEV option, if the difference is less than TOLMAX * standard deviation of the boxcar then the + input pixel + is preserved. Otherwise it is considered noisy and will be replaced. + + In general, a high tolerance means fewer pixels will be replaced and lower tolerance will cause more + pixels to be replaced. Too small of a tolerance can actually replace real/good data. For the STDDEV option, + you might try TOLMAX=3 as a starting point. For the DN option, try TOLMAX=2. + + 0.0 + 20 + + + + string + + AVERAGE + + + Value to replace noise + + + This is the value that is used to replace pixels which are + considered to be noise. + + + + + + + + + + + integer + + Number of samples in boxcar + + + + This is the total number of samples in the boxcar. + It must be odd and can not exceed twice the number of samples + in the cube. In general, the size of the boxcar does not + cause the program to operate significantly slower. + + The shape of the filter can be used to control types of noise to remove. For example, a 3x3 or 5x5 boxcar + can be used to remove speckle or salt and pepper noise. A 1 sample x 5 line boxcar with REPLACE=NULL + could be used to remove dropped or noisy lines of data. Then use the lowpass program with a 3x3 boxcar + to fill in the NULLed data. + + + + + 1 + + + + integer + + Number of lines in boxcar + + + + This is the total number of lines in the boxcar. + It must be odd and can not exceed twice the number of lines + in the cube. In general, the size of the boxcar does not + cause the program to operate significantly + slower. + + The shape of the filter can be used to control types of noise to remove. For example, a 3x3 or 5x5 boxcar + can be used to remove speckle or salt and pepper noise. A 1 sample x 5 line boxcar with REPLACE=NULL + could be used to remove dropped or noisy lines of data. Then use the lowpass program with a 3x3 boxcar + to fill in the NULLed data. + + + + + 1 + + + + + + double + + Valid minimum pixel + + + Valid minimum pixel value that will be used in boxcar computation. If + a pixel value is less than LOW then it will not be used when + computing boxcar statistics. + + + Use all pixels + + + HIGH + + + + + double + + Valid maximum pixel + + + Valid maximum pixel value that will be used in boxcar computation. If + a pixel value is greater than HIGH then it will not be used when + computing boxcar statistics. + + + Use all pixels + + + LOW + + + + + integer + + Minimum boxcar pixel count + + + This is the minimum number of valid pixels which must occur inside the + NxM boxcar for filtering to occur. For example, 3x5 boxcar has 15 pixels + inside. If MINIMUM=10 then the filter will occur if there are 10 or + greater valid pixels. A valid pixel is one that is not special (NULL, LIS, + etc) and is in the range defined by LOW to HIGH. + + + 1 + + 1 + + + + + + boolean + FALSE + Null is noise + + This option is used to define how NULL pixels are handled. If this + parameter is set to TRUE, then NULL pixels will be considered to be + noise and will be replaced. If FALSE, the NULL will be propagated + to the output. + + + + boolean + FALSE + HIS is noise + + This option is used to define how HIS (High Instrument Saturation) + pixels are handled. If this parameter is set to TRUE, then HIS + pixels will be considered to be noise and will be replaced. If + FALSE, the HIS will be propagated to the output. + + + + boolean + FALSE + HRS is noise + + This option is used to define how HRS (High Representation Saturation) + pixels are handled. If this parameter is set to TRUE, then HRS + pixels will be considered to be noise and will be replaced. If + FALSE, the HRS will be propagated to the output. + + + + boolean + FALSE + HIS is noise + + This option is used to define how LIS (Low Instrument Saturation) + pixels are handled. If this parameter is set to TRUE, then LIS + pixels will be considered to be noise and will be replaced. If + FALSE, the LIS will be propagated to the output. + + + + boolean + FALSE + HRS is noise + + This option is used to define how LRS (Low Representation Saturation) + pixels are handled. If this parameter is set to TRUE, then LRS + pixels will be considered to be noise and will be replaced. If + FALSE, the LRS will be propagated to the output. + + + + + + + Header default + Demonstrate the noisefilter application with header + + + f=f332s28.cub t=nzfltr tolmin=5 tolmax=50 samples=11 lines=11 + Run a noise filter on a Viking image. (Let toldef default to DN.) + + + + + Input image for noisefilter + This is the input image f332s28.cub. It has noise in the form of small black rectangles. + + + FROM + + + + + Output image for the noisefilter example + This is the output image for the noisefilter application. The black rectangles are gone. + + + TO + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform +the noisefilter application + + + + + + + diff --git a/isis/src/base/apps/noisefilter/tsts/Makefile b/isis/src/base/apps/noisefilter/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/noisefilter/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/noisefilter/tsts/average/Makefile b/isis/src/base/apps/noisefilter/tsts/average/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0ed3e33dcb7edf57557e88367a45453abe6c667e --- /dev/null +++ b/isis/src/base/apps/noisefilter/tsts/average/Makefile @@ -0,0 +1,18 @@ +APPNAME = noisefilter + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/nsFilTruth1.cub \ + toldef= dn \ + tolmin= 100 \ + tolmax= 110 \ + replace= average \ + samples= 21 \ + lines= 21 \ + nullisnoise= true \ + hisisnoise= true \ + hrsisnoise= true \ + lisisnoise= true \ + lrsisnoise= true > /dev/null; diff --git a/isis/src/base/apps/noisefilter/tsts/null/Makefile b/isis/src/base/apps/noisefilter/tsts/null/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d02208ba95d63ffe7e1e94f795f1ef5a41611b1d --- /dev/null +++ b/isis/src/base/apps/noisefilter/tsts/null/Makefile @@ -0,0 +1,13 @@ +APPNAME = noisefilter + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/nsFilTruth2.cub \ + toldef= stddev \ + tolmin= 1.25 \ + tolmax= 1.25 \ + replace= null \ + samples= 21 \ + lines= 21 > /dev/null; diff --git a/isis/src/base/apps/noproj/Makefile b/isis/src/base/apps/noproj/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/noproj/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/noproj/noproj.cpp b/isis/src/base/apps/noproj/noproj.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8741921e3dad995713b41c4774077c28be5c8b32 --- /dev/null +++ b/isis/src/base/apps/noproj/noproj.cpp @@ -0,0 +1,368 @@ +#define GUIHELPERS +#include "Isis.h" +#include "Pvl.h" + +#include "Process.h" + +#include "Blob.h" +#include "History.h" +#include "CameraDetectorMap.h" +#include "Application.h" +#include "CameraFocalPlaneMap.h" +#include "PvlObject.h" +#include "AlphaCube.h" +#include +#include +#include + +using namespace Isis; +using namespace std; + +void LoadMatchSummingMode (); +void LoadInputSummingMode (); + +map GuiHelpers(){ + map helper; + helper ["LoadMatchSummingMode"] = (void*) LoadMatchSummingMode; + helper ["LoadInputSummingMode"] = (void*) LoadInputSummingMode; + return helper; +} + +void IsisMain(){ + + // Create a process so we can output the noproj'd labels without overwriting + Process p; + + // Open the user interface and get the input file and the ideal specs file + UserInterface &ui = Application::GetUserInterface(); + Cube *mcube,*icube; + + // If a MATCH cube is entered, make sure to SetInputCube it first to get the SPICE blobs + // from it propagated to the TO labels + + // Until polygon blobs are detached without "/" don't propagate them + p.PropagatePolygons ( false ); + + if ((ui.WasEntered ("MATCH"))) { + mcube = p.SetInputCube("MATCH"); + icube = p.SetInputCube("FROM"); + } + else{ + mcube = icube = p.SetInputCube("FROM"); + } + + Camera *incam = mcube->Camera(); + + // Extract Instrument groups from input labels for the output match and noproj'd cubes + PvlGroup inst = mcube->GetGroup("Instrument"); + PvlGroup fromInst = icube->GetGroup("Instrument"); + std::string groupName = (string) inst["SpacecraftName"] + "/"; + groupName += (string) inst.FindKeyword("InstrumentId"); + + // Get Ideal camera specifications + Filename specs; + if ((ui.WasEntered ("SPECS"))) { + specs = ui.GetFilename("SPECS"); + } + else { + specs = "$base/applications/noprojInstruments???.pvl"; + specs.HighestVersion(); + } + Pvl idealSpecs( specs.Expanded() ); + PvlObject obSpecs = idealSpecs.FindObject("IdealInstrumentsSpecifications"); + + PvlGroup idealGp = obSpecs.FindGroup(groupName); + double transx,transy,transl,transs; + transx = transy = transl = transs = 0.; + if (idealGp.HasKeyword("TransX")) transx = idealGp["TransX"]; + if (idealGp.HasKeyword("TransY")) transy = idealGp["TransY"]; + if (idealGp.HasKeyword("ItransL")) transl = idealGp["ItransL"]; + if (idealGp.HasKeyword("ItransS")) transs = idealGp["ItransS"]; + int detectorSamples = mcube->Samples(); + if (idealGp.HasKeyword("DetectorSamples")) detectorSamples = idealGp["DetectorSamples"]; + int numberLines = mcube->Lines(); + int numberBands = mcube->Bands(); + + if (idealGp.HasKeyword("DetectorLines")) numberLines = idealGp["DetectorLines"]; + + int xDepend = incam->FocalPlaneMap()->FocalPlaneXDependency(); + + // Get output summing mode + if (ui.GetString("SOURCE") == "FROMMATCH") { + LoadMatchSummingMode(); + } + else if (ui.GetString("SOURCE") == "FROMINPUT") { + LoadInputSummingMode(); + } + + double pixPitch = incam->PixelPitch()*ui.GetDouble("SUMMINGMODE"); + detectorSamples /= (int) (ui.GetDouble("SUMMINGMODE")); + // Get the user options + int sampleExpansion = int((ui.GetDouble("SAMPEXP")/100.)*detectorSamples + .5); + int lineExpansion = int((ui.GetDouble("LINEEXP")/100.)*numberLines + .5); + string instType; + double exposure; + + // Adjust translations for summing mode + transl /= ui.GetDouble("SUMMINGMODE"); + transs /= ui.GetDouble("SUMMINGMODE"); + + detectorSamples += sampleExpansion; + numberLines += lineExpansion; + + // Determine whether this ideal camera is a line scan or framing camera and + // set the instrument id and exposure + int detectorLines; + int expandFlag; + + if (incam->DetectorMap()->LineRate() != 0.0) { + instType= "LINESCAN"; + // Isis3 line rate is always in seconds so convert to milliseconds for the + // Ideal instrument + exposure = incam->DetectorMap()->LineRate()*1000.; + detectorLines = 1; + expandFlag = 1; + } + else { + instType = "FRAMING"; + detectorLines = numberLines; + expandFlag = 0; + // Framing cameras don't need exposure time + } + + // Adjust focal plane translations with line expansion for scanners since + // the CCD is only 1 line + if (expandFlag) { + transl += lineExpansion/2; + + if (xDepend == CameraFocalPlaneMap::Line) { + transx -= lineExpansion/2.*pixPitch*expandFlag; + } + else { + transy -= lineExpansion/2.*pixPitch*expandFlag; + } + } + + // Get the start time for parent line 1 + AlphaCube alpha(*(icube->Label())); + double sample = alpha.BetaSample(.5); + double line = alpha.BetaLine(.5); + incam->SetImage(sample,line); + double et = incam->EphemerisTime(); + + // Get the output file name and set its attributes + CubeAttributeOutput cao; + + // Can we do a regular label? Didn't work on 12-15-2006 + cao.Label(Isis::DetachedLabel); + cao.Set("PropagateRange"); + cao.Set("PropagatePixelType"); + + // Determine the output image size from + // 1) the idealInstrument pvl if there or + // 2) the input size expanded by user specified percentage + Cube *ocube = p.SetOutputCube("match.cub",cao,1, 1, 1); + + // Extract the times and the target from the instrument group + string startTime = inst["StartTime"]; + string stopTime; + if (inst.HasKeyword("StopTime")) stopTime = (string) inst["StopTime"]; + + string target = inst["TargetName"]; + + // rename the instrument groups + inst.SetName("OriginalInstrument"); + fromInst.SetName("OriginalInstrument"); + + // add it back to the IsisCube object under a new group name + ocube->PutGroup(inst); + + // and remove the version from the IsisCube Object + ocube->DeleteGroup("Instrument"); + + // Now rename the group back to the Instrument group and clear out old keywords + inst.SetName("Instrument"); + inst.Clear(); + + // Add keywords for the "Ideal" instrument + Isis::PvlKeyword key("SpacecraftName", "IdealSpacecraft" ); + inst.AddKeyword( key); + + key.SetName("InstrumentId"); + key.SetValue( "IdealCamera" ); + inst.AddKeyword( key); + + key.SetName("TargetName"); + key.SetValue( target ); + inst.AddKeyword( key ); + + key.SetName("SampleDetectors"); + key.SetValue( Isis::iString( detectorSamples )); + inst.AddKeyword( key); + + key.SetName("LineDetectors"); + key.SetValue( Isis::iString( detectorLines )); + inst.AddKeyword( key); + + key.SetName("InstrumentType" ); + key.SetValue( instType ); + inst.AddKeyword( key); + + key.SetName("FocalLength"); + key.SetValue( Isis::iString( incam->FocalLength()), "millimeters" ); + inst.AddKeyword( key ); + + key.SetName("PixelPitch"); + key.SetValue( Isis::iString( incam->PixelPitch()* + ui.GetDouble("SUMMINGMODE")), "millimeters" ); + inst.AddKeyword( key ); + + key.SetName("EphemerisTime"); + key.SetValue( Isis::iString( et ), "seconds" ); + inst.AddKeyword( key ); + + key.SetName("StartTime"); + key.SetValue( startTime ); + inst.AddKeyword( key ); + + if (stopTime != "") { + key.SetName("StopTime"); + key.SetValue( stopTime ); + inst.AddKeyword( key ); + } + + key.SetName("FocalPlaneXDependency"); + key.SetValue( incam->FocalPlaneMap()->FocalPlaneXDependency() ); + inst.AddKeyword( key ); + + if (transx != 0) { + key.SetName("TransX0"); + key.SetValue( transx ); + inst.AddKeyword( key ); + } + + if (transy != 0) { + key.SetName("TransY0"); + key.SetValue( transy ); + inst.AddKeyword( key ); + } + + if (transs != 0) { + key.SetName("TransS0"); + key.SetValue( transs ); + inst.AddKeyword( key ); + } + + if (transl != 0) { + key.SetName("TransL0"); + key.SetValue( transl ); + inst.AddKeyword( key ); + } + + key.SetName("TransX"); + key.SetValue( incam->FocalPlaneMap()->SignMostSigX() ); + inst.AddKeyword( key ); + + key.SetName("TransY"); + key.SetValue( incam->FocalPlaneMap()->SignMostSigY() ); + inst.AddKeyword( key ); + + if (instType == "LINESCAN") { + key.SetName("ExposureDuration"); + key.SetValue( Isis::iString( incam->DetectorMap()->LineRate()*1000.), "milliseconds" ); + inst.AddKeyword( key ); + } + + key.SetName("MatchedCube"); + key.SetValue( mcube->Filename() ); + inst.AddKeyword( key ); + + ocube->PutGroup(inst); + + p.EndProcess(); + +// Now adjust the label to fake the true size of the image to match without +// taking all the space it would require for the image data + Pvl label; + label.Read("match.lbl"); + PvlGroup &dims = label.FindGroup("Dimensions",Pvl::Traverse); + dims["Lines"] = numberLines; + dims["Samples"] = detectorSamples; + dims["Bands"] = numberBands; + label.Write("match.lbl"); + +// And run cam2cam to apply the transformation + string parameters; + parameters += " FROM= " + ui.GetFilename("FROM"); + parameters += " MATCH= " + string("match.cub"); + parameters += " TO= " + ui.GetFilename("TO"); + parameters += " INTERP=" + ui.GetString("INTERP"); + Isis::iApp ->Exec("cam2cam",parameters); + +// Cleanup by deleting the match files + remove("match.History.IsisCube"); + remove("match.lbl"); + remove("match.cub"); + remove("match.OriginalLabel.IsisCube"); + remove("match.Table.BodyRotation"); + remove("match.Table.HiRISE Ancillary"); + remove("match.Table.HiRISE Calibration Ancillary"); + remove("match.Table.HiRISE Calibration Image"); + remove("match.Table.InstrumentPointing"); + remove("match.Table.InstrumentPosition"); + remove("match.Table.SunPosition"); + +// Finally finish by adding the OriginalInstrument group to the TO cube + Cube toCube; + toCube.Open(ui.GetFilename("TO"), "rw"); +// Extract label and create cube object + Pvl *toLabel = toCube.Label(); + PvlObject &o = toLabel->FindObject("IsisCube"); + o.DeleteGroup( "OriginalInstrument" ); + o.AddGroup(fromInst); + toCube.Close(); +} + + // Helper function to get output summing mode from cube to MATCH +void LoadMatchSummingMode () { + string file; + UserInterface &ui = Application::GetUserInterface(); + + // Get camera from cube to match + if ((ui.GetString ("SOURCE") =="FROMMATCH") && (ui.WasEntered("MATCH"))) { + file = ui.GetFilename("MATCH"); + } + else { + file = ui.GetFilename("FROM"); + } + + // Open the input cube and get the camera object + Cube c; + c.Open(file); + Camera *cam = c.Camera(); + + ui.Clear("SUMMINGMODE"); + ui.PutDouble("SUMMINGMODE",cam->DetectorMap()->SampleScaleFactor()); + + ui.Clear("SOURCE"); + ui.PutAsString("SOURCE", "FROMUSER"); +} + + +// Helper function to get output summing mode from input cube (FROM) +void LoadInputSummingMode () { + UserInterface &ui = Application::GetUserInterface(); + + // Get camera from cube to match + string file = ui.GetFilename("FROM"); + // Open the input cube and get the camera object + Cube c; + c.Open(file); + Camera *cam = c.Camera(); + + ui.Clear("SUMMINGMODE"); + ui.PutDouble("SUMMINGMODE",cam->DetectorMap()->SampleScaleFactor()); + + ui.Clear("SOURCE"); + ui.PutAsString("SOURCE", "FROMUSER"); +} diff --git a/isis/src/base/apps/noproj/noproj.xml b/isis/src/base/apps/noproj/noproj.xml new file mode 100644 index 0000000000000000000000000000000000000000..f3fb9dcb00efe46755c43de053a773757ed2deea --- /dev/null +++ b/isis/src/base/apps/noproj/noproj.xml @@ -0,0 +1,256 @@ + + + + + + Removes camera distortions in a raw level 1 cube creating an ideal version of the cube. + + + + This program will modify the cube labels for the Ideal camera. + The original Instrument group is renamed OriginalInstrument and a new + instrument group is created for the Ideal Camera. The cube data + is modified when this program runs cam2cam, creating the noproj'd + output cube with camera distortions removed. + + + + + Original version + + + Corrected for case where original instrument has negative affine coefficients + + + Added INTERP option, fixed SPECS parameter to allow user to override the default and enter a file, and updated the documentation + + + Changed category to Cameras + + + Corrected order of SetInputCube calls to set the MATCH cube first if is entered so that the labels on the cube to match are propagated from it and not the from cube + + + Turned off propagation of the polygon blobs because the file name contains "/" from + the serial number and unix does not allow "/". Also added a remove of the match file + OriginalInstrument group written by cam2cam before writing the input OriginalInstrument. + hijitreg reads the input CcdId from this group. + + + Removed references to CubeInfo + + + Completed applying summing mode to ideal camera by applying it to the sample/line translations. + + + Fixed setting of et to correspond to first line of parent (Alpha cube) + + + + + Cameras + + + + + cam2cam + + + + + noproj + + + + + + cube + input + + Input cube + + + This cube will have the camera distortions removed based on the correction for the MATCH file and output to the TO file. + + + *.cub + + + + + cube + input + + Match cube + + + Instrument cube to match + + + This is the level 1 cube whose labels will be converted to the Ideal instrument and used as the cube to match. It must have only one band so use the input attributes to select the band to match. For example, + themis.cub+5 + + + *.cub + + + + + filename + input + + Ideal camera specifications file + + + SystemDefault + + + This file contains the specifications for the "ideal" camera based on the original instrument. If no value is entered, the default + specs file will be read from "$base/applications/noprojInstruments???.pvl", where ??? indicates the highest version of the file. + + + *.pvl + + + $base/applications/ + + + + + cube + output + + Output cube + + + This file will be a copy of the input cube with the labels modified for the Ideal Camera + cubes. + + + + + + + string + Defines how the summing mode in the output noproj'd file is obtained + FROMMATCH + + This parameter is used to specify how the summing mode is obtained for the output + noproj'd cube. The pixel pitch of the output file will be set to the summing mode times the pixel + pitch of the input file. The output pixel pitch is written to the labels of the noproj'd cube. + Note:: The user can override the default using the USER parameter. + + + + LoadMatchSummingMode + Load Output Summing Mode from Match file + This helper button will load the default summing mode from the match camera + $ISIS3DATA/base/icons/exec.png + + + LoadInputSummingMode + Load Output Summing Mode From Input file + This helper button will load the output summing mode from the input (FROM) camera + + + + + + + + + + + + double + Summing Mode + + Specifies the summing mode to multiply times the input file (FROM) camera pixel pitch (mm/pix) to determine the + output noproj'd file pixel pitch (pixel size in mm). This value is written to the output file labels + + 1.0 + + + + + + string + + CUBICCONVOLUTION + + Type of interpolation + + This is the type of interpolation to be performed on the input in cam2cam. + + + + + + + + + double + + 0.0 + + Sample expansion percentage + + This parameter expands the size of the output file in samples beyond the default size to prevent cropping of the + undistorted image. The undistorted image may be larger than the raw distorted image. + + + + + double + + 0.0 + + Line expansion percentage + + This parameter expands the size of the output file in lines beyond the default size to prevent cropping of the + undistorted image. The undistorted image may be larger than the raw distorted image. + + + + + + diff --git a/isis/src/base/apps/noproj/tsts/Makefile b/isis/src/base/apps/noproj/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/noproj/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/noproj/tsts/default/Makefile b/isis/src/base/apps/noproj/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7a84a9e606889086a9a4ece8b5a582307d3bac06 --- /dev/null +++ b/isis/src/base/apps/noproj/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = noproj +#This file exercises the default options + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/PSP_001414_1780_RED5.balance.cropped.cub \ + to=$(OUTPUT)/PSP_001414_1780_RED5.balance.cropped.noproj.cub > /dev/null; + $(RM) print.prt > /dev/null; diff --git a/isis/src/base/apps/noproj/tsts/expand/Makefile b/isis/src/base/apps/noproj/tsts/expand/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..09e31f0fe19848acb24271d8f05e12075e6de147 --- /dev/null +++ b/isis/src/base/apps/noproj/tsts/expand/Makefile @@ -0,0 +1,10 @@ +APPNAME = noproj +#This test exercises the expand options + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/f387a06.findrx.cub \ + to=$(OUTPUT)/vik.noproj.expanded.cub \ + sampexp=10 lineexp=5 > /dev/null; + $(RM) print.prt > /dev/null; diff --git a/isis/src/base/apps/noproj/tsts/match/Makefile b/isis/src/base/apps/noproj/tsts/match/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1fb04767d63b29c2277682b54692adbf3bcb4c3b --- /dev/null +++ b/isis/src/base/apps/noproj/tsts/match/Makefile @@ -0,0 +1,10 @@ +APPNAME = noproj +# This file exercises the match file option + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/PSP_001414_1780_RED4.balance.cropped.cub \ + match=$(INPUT)/PSP_001414_1780_RED5.balance.cropped.cub \ + to=$(OUTPUT)/PSP_001414_1780_RED4.balance.cropped.noproj.cub > /dev/null; + $(RM) print.prt > /dev/null; diff --git a/isis/src/base/apps/noproj/tsts/sumuser/Makefile b/isis/src/base/apps/noproj/tsts/sumuser/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8dfb31e518111135e3fa1d8964c0511808361640 --- /dev/null +++ b/isis/src/base/apps/noproj/tsts/sumuser/Makefile @@ -0,0 +1,10 @@ +APPNAME = noproj +#This file exercises the user sum option + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/PSP_001414_1780_RED5.balance.cropped.cub \ + to=$(OUTPUT)/PSP_001414_1780_RED5.balance.cropped.noproj.sum2.cub \ + source=fromuser sum=2 > /dev/null; + $(RM) print.prt > /dev/null; diff --git a/isis/src/base/apps/noseam/Makefile b/isis/src/base/apps/noseam/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/noseam/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/noseam/assets/cubes.lis b/isis/src/base/apps/noseam/assets/cubes.lis new file mode 100644 index 0000000000000000000000000000000000000000..29a2c43943159ba6b611382680bc23c3b9d8413b --- /dev/null +++ b/isis/src/base/apps/noseam/assets/cubes.lis @@ -0,0 +1,3 @@ +cube1.cub +cube2.cub +cube3.cub diff --git a/isis/src/base/apps/noseam/assets/images/cube1.jpg b/isis/src/base/apps/noseam/assets/images/cube1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e58ee74562b3091503529e9c6eaea99d4f8c492a Binary files /dev/null and b/isis/src/base/apps/noseam/assets/images/cube1.jpg differ diff --git a/isis/src/base/apps/noseam/assets/images/cube2.jpg b/isis/src/base/apps/noseam/assets/images/cube2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..be87b7148e3c858df9e5276e15c8f66eac84338e Binary files /dev/null and b/isis/src/base/apps/noseam/assets/images/cube2.jpg differ diff --git a/isis/src/base/apps/noseam/assets/images/cube3.jpg b/isis/src/base/apps/noseam/assets/images/cube3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..37e71a4195bc2e76b4faf7a6892a4e6f58ca5782 Binary files /dev/null and b/isis/src/base/apps/noseam/assets/images/cube3.jpg differ diff --git a/isis/src/base/apps/noseam/assets/images/original.jpg b/isis/src/base/apps/noseam/assets/images/original.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b247db761c34927bf612ff585e921c30ae4d395 Binary files /dev/null and b/isis/src/base/apps/noseam/assets/images/original.jpg differ diff --git a/isis/src/base/apps/noseam/assets/images/result.jpg b/isis/src/base/apps/noseam/assets/images/result.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cae3ffd11643a854d2d32ca7316fb9e4d3d8d9c7 Binary files /dev/null and b/isis/src/base/apps/noseam/assets/images/result.jpg differ diff --git a/isis/src/base/apps/noseam/noseam.cpp b/isis/src/base/apps/noseam/noseam.cpp new file mode 100644 index 0000000000000000000000000000000000000000..edae3b4341366831871c2fa89e68f84c491f4ad9 --- /dev/null +++ b/isis/src/base/apps/noseam/noseam.cpp @@ -0,0 +1,93 @@ +#include "Isis.h" +#include "Application.h" +#include "FileList.h" +#include "Cube.h" +#include "Preference.h" + +#include +#include + +using namespace std; +using namespace Isis; + +void IsisMain() { + + //Get user parameters + UserInterface &ui = Application::GetUserInterface(); + FileList cubes; + cubes.Read(ui.GetFilename("FROMLIST")); + + int hns = ui.GetInteger("HNS"); + int hnl = ui.GetInteger("HNL"); + int lns = ui.GetInteger("LNS"); + int lnl = ui.GetInteger("LNL"); + string match = ui.GetAsString("MATCHBANDBIN"); + + //Sets upt the pathName to be used for most application calls + Filename inFile = Isis::Filename( cubes[0] ); + + Pvl &pref = Preference::Preferences(); + string pathName = (string)pref.FindGroup("DataDirectory")["Temporary"] + "/"; + + /** + * Creates a mosaic from the original images. It is placed here + * so that the failure MATCHBANDBIN causes does not leave + * highpasses cubes lying around! + */ + string parameters = "FROMLIST=" + ui.GetFilename("FROMLIST") + + " MOSAIC=" + pathName + "OriginalMosaic.cub" + + " MATCHBANDBIN=" + match; + Isis::iApp ->Exec("automos",parameters); + + //Creates the highpass cubes from the cubes FileList + std::ofstream highPassList; + highPassList.open( "HighPassList.lis" ); + for ( unsigned i=0; iExec("algebra",parameters); + + //Will remove all of the temp files by default + if ( ui.GetBoolean("REMOVETEMP") ) { + string file("HighPassList.lis"); + remove( file.c_str() ); + file = pathName+"HighpassMosaic.cub"; + remove( file.c_str() ); + file = pathName+"LowpassMosaic.cub"; + remove( file.c_str() ); + file = pathName+"OriginalMosaic.cub"; + remove( file.c_str() ); + + for ( unsigned i=0; i + + + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://isis.astrogeology.usgs.gov/Schemas/Application/application.xsd"> + + Creates a mosaic with little to no seams using a list of map projected + cubes + + + This program uses a text-based list of cubes, all in the same map projection + and equivalent projection parameters (PixelResolution, CenterLongitude, + LatitudeSystem, etc), to generate a seamless mosaic. The size of the + mosaic is determined automatically by examining each listed cube. + + + + Mosaicking + + + + + Original version + + + This program was using the input folder as a temporary folder, instead of looking + up the user's preferences to find the correct temporary folder. This program will now + use the correct temporary folder. + + + + + + + + filename + input + + List of cubes to mosaic + + + A list of map projected cubes to mosaic seamlessly. The Mapping + groups must match in order to mosaic the cubes. + + + *.txt *.lis *.lst + + + + cube + output + + Mosaic output cube + + + The resulting mosaic, which will be created from the listed cubes. + + + *.cub + + + + + + + integer + + Number of samples in high frequency data boxcar + + + This is the total number of samples in the high frequency data boxcar. + It must be odd and can not exceed twice the number of samples in the + input cubes. In general, the size of the boxcar does not cause the + program to operate significantly slower. + + + 1 + + + integer + + Number of lines in high frequency data boxcar + + This is the total number of lines in the high frequency + data boxcar. It must be odd and can not exceed twice the number of + lines in the input cubes. In general, the size of the boxcar does + not cause the program to operate significantly slower. + + + 1 + + + integer + + Number of samples in low frequency data boxcar + + + This is the total number of samples in the low frequency data boxcar. + It must be odd and can not exceed twice the number of samples in the + input cubes. In general, the size of the boxcar does not cause the + program to operate significantly slower. + + + 1 + + + integer + + Number of lines in low frequency data boxcar + + + This is the total number of lines in the low frequency data boxcar. It + must be odd and can not exceed twice the number of lines in the input + cubes. In general, the size of the boxcar does not cause the program + to operate significantly slower. + + + 1 + + + + + iString(match) + boolean + Enforce BandBin Group Match + + This option causes the application to fail if the input bandbin group does not + match the mosaic bandbin group. + + TRUE + + + + + + boolean + TRUE + Destroy intermediate data + + Multiple cube images as well as lists are created durring the + production of the final seamless mosaic. If this parameter is changed + to false, those temporary cubes and lists will not be destroyed. + + + + + + + + + + No Seam Result + + This example shows how noseam works upon a small mosaic and + compares that result to an automos output. + + + + FROMLIST=cubes.lis + TO=final.cub HNS=73 HNL=73 LNS=73 LNL=73 + + Runs noseam with a 73x73 highpass filter and a 73x73 lowpass + filter. Choosing the same dimensions will preserve the + original image and only reduce the presence of seams in the + final mosaic. + + + + + + cubes.lis + + This is a simple file that lists all of the cubes to mosaic. + This list as well as the cubes to be mosaiced must + be within the current directory when noseam is executed. + + FROMLIST + + + + + + First listed cube + + This is the first cube listed in cubes.lis + + + + + Second listed cube + + This is the second cube listed in cubes.lis + + + + + Third listed cube + + This is the third cube listed in cubes.lis + + + + + + + + The resulting mosaic + + This is the resulting mosaic final.cub. + + + TO + + + Automos result (NOT AN OUTPUT OF NOSEAM) + + This is the same mosaic created from automos. Notice + the difference between this image and final.cub. The + seams that exist between the original images are nearly + invisible in final.cub. However, those same seams are + ugly in this image, automos.cub. + + + + + + + + + + diff --git a/isis/src/base/apps/noseam/tsts/Makefile b/isis/src/base/apps/noseam/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/noseam/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/noseam/tsts/default/Makefile b/isis/src/base/apps/noseam/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b6782cb2a8aa75a440879abb84cf1544d9129658 --- /dev/null +++ b/isis/src/base/apps/noseam/tsts/default/Makefile @@ -0,0 +1,10 @@ +APPNAME = noseam + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/* > $(OUTPUT)/cubes.lis; + $(APPNAME) FROMLIST=$(OUTPUT)/cubes.lis \ + TO=$(OUTPUT)/result.cub \ + HNS=73 HNL=73 LNS=73 LNL=73 > /dev/null; + $(RM) $(OUTPUT)/cubes.lis; diff --git a/isis/src/base/apps/outline/Makefile b/isis/src/base/apps/outline/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/outline/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/outline/outline.cpp b/isis/src/base/apps/outline/outline.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f6f6196c2c439c76bffe30f1b255571abf3fb55 --- /dev/null +++ b/isis/src/base/apps/outline/outline.cpp @@ -0,0 +1,116 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +// Line processing routine +void outline (Buffer &in, Buffer &out); + +double *lastLine; +double bdn; +bool bimage; +bool bclear; +int nl; + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and output cubes + Cube *icube = p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + + // Get user parameters + UserInterface &ui = Application::GetUserInterface(); + bdn = ui.GetDouble ("BOUNDARY"); + bimage = ui.GetBoolean("EDGES"); + bclear = ui.GetBoolean("CLEAR"); + + // Allocate space for a work buffer + lastLine = new double[icube->Samples()]; + nl = icube->Lines(); + + // Start the processing + p.StartProcess(outline); + p.EndProcess(); + + // Cleanup + delete [] lastLine; +} + + +// Line processing routine +void outline (Buffer &in,Buffer &out) +{ + // Handle things differently for the 1st line + if (in.Line() == 1) { + for (int i=1; i + + + + + Outlines contiguous regions in a cube + + + + This program will draw boundaries or outline contigous regions in a cube. By + contiguous regions we mean those which are all of the same pixel value. + + + + + Original version + + + + Ported to Isis 3.0 + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Added modifications to apptest by Kim + + + Modified filename parameters to be cube parameters where necessary + + + Removed references to CubeInfo + + + + + Trim and Mask + + + + + + cube + input + + Input cube to outline + + + Use this parameter to select the filename. All bands within the file + will be outlined. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the outlined cube. + + + *.cub + + + + + + + double + Boundary pixel value + + This defines pixel value which will be placed at the boundary of + contiguous regions. This value should not occur in the input cube. + + + + + boolean + TRUE + Clear pixels inside boundaries + + Setting this option to true will case all pixels found inside the + boundaries to be set to NULL. Otherwise the pixels will be left + alone. + + + + + boolean + TRUE + Set pixels at edges of cube + + Setting this option to true will case all pixels around the edge of + the cube to be set to the boundary pixel value. Otherwise they will + be left alone or set to NULL. + + + + + + diff --git a/isis/src/base/apps/outline/tsts/Makefile b/isis/src/base/apps/outline/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/outline/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/outline/tsts/clear/Makefile b/isis/src/base/apps/outline/tsts/clear/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b9d42229df429769e1111225dae1af98951c2036 --- /dev/null +++ b/isis/src/base/apps/outline/tsts/clear/Makefile @@ -0,0 +1,10 @@ +APPNAME = outline + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/outlineTruth2.cub \ + boundary=1001.0 \ + clear=yes \ + edges=yes > /dev/null; diff --git a/isis/src/base/apps/outline/tsts/noClear/Makefile b/isis/src/base/apps/outline/tsts/noClear/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..aa76ec129d6c6bb72cc1ce27e30db6812163870c --- /dev/null +++ b/isis/src/base/apps/outline/tsts/noClear/Makefile @@ -0,0 +1,10 @@ +APPNAME = outline + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/outlineTruth1.cub \ + boundary=1001.0 \ + clear=no \ + edges=no > /dev/null; diff --git a/isis/src/base/apps/overlapstats/Makefile b/isis/src/base/apps/overlapstats/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/overlapstats/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/overlapstats/assets/cubes.lis b/isis/src/base/apps/overlapstats/assets/cubes.lis new file mode 100644 index 0000000000000000000000000000000000000000..0df844a25fa57a2225f33b048a67eaa490e6eb89 --- /dev/null +++ b/isis/src/base/apps/overlapstats/assets/cubes.lis @@ -0,0 +1,3 @@ +cube.1.cub +cube.2.cub +cube.3.cub diff --git a/isis/src/base/apps/overlapstats/assets/image/cube.1.jpg b/isis/src/base/apps/overlapstats/assets/image/cube.1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..89070468926ff88b9dbdf723107e18aff1a51944 Binary files /dev/null and b/isis/src/base/apps/overlapstats/assets/image/cube.1.jpg differ diff --git a/isis/src/base/apps/overlapstats/assets/image/cube.2.jpg b/isis/src/base/apps/overlapstats/assets/image/cube.2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e59ad18134d2a590e55d3e5f8c2530a34cebb968 Binary files /dev/null and b/isis/src/base/apps/overlapstats/assets/image/cube.2.jpg differ diff --git a/isis/src/base/apps/overlapstats/assets/image/cube.3.jpg b/isis/src/base/apps/overlapstats/assets/image/cube.3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bb7cd9652b89e48fa784a30a6fb1dae9deb64c21 Binary files /dev/null and b/isis/src/base/apps/overlapstats/assets/image/cube.3.jpg differ diff --git a/isis/src/base/apps/overlapstats/assets/print.prt b/isis/src/base/apps/overlapstats/assets/print.prt new file mode 100644 index 0000000000000000000000000000000000000000..a3c68cd08944451d1e0341788ef7c6adc0e86fc8 --- /dev/null +++ b/isis/src/base/apps/overlapstats/assets/print.prt @@ -0,0 +1,20 @@ +Group = Results + ThicknessMinimum = 0.05948606716346617 + ThicknessMaximum = 0.06408276921322625 + ThicknessAverage = 0.06178441818834621 + ThicknessStandardDeviation = 0.003250359190479414 + ThicknessVariance = 1.056483486713399e-05 + ThicknessSum = 0.1235688363766924 + AreaMinimum = 46045158354.94140 + AreaMaximum = 49893721108.36636 + AreaAverage = 47969439731.65388 + AreaStandardDeviation = 2721344820.768736 + AreaVariance = 7.405717633524826e+18 + AreaSum = 95938879463.30775 + SerialNumberMinimum = 2.0 + SerialNumberMaximum = 2.0 + SerialNumberAverage = 2.0 + SerialNumberStandardDeviation = 0.0 + SerialNumberVariance = 0.0 + SerialNumberSum = 4.0 +End_Group diff --git a/isis/src/base/apps/overlapstats/assets/stats.txt b/isis/src/base/apps/overlapstats/assets/stats.txt new file mode 100644 index 0000000000000000000000000000000000000000..23bbbcb08e69ac7a8315a559a9bde297cd572a9f --- /dev/null +++ b/isis/src/base/apps/overlapstats/assets/stats.txt @@ -0,0 +1,7 @@ + Thickness Area SN Count +Minimum 0.05948606716346617 46045158354.94140 2.000000000000000 +Maximum 0.06408276921322625 49893721108.36636 2.000000000000000 +Average 0.06178441818834621 47969439731.65388 2.000000000000000 +StandardDeviation 0.003250359190479414 2721344820.768736 0.000000000000000 +Variance 1.056483486713399e-05 7.405717633524826e+18 0.000000000000000 +Sum 0.1235688363766924 95938879463.30775 4.000000000000000 \ No newline at end of file diff --git a/isis/src/base/apps/overlapstats/assets/thumb/thumb.1.jpg b/isis/src/base/apps/overlapstats/assets/thumb/thumb.1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f0df7b4207597b1d9a826f6a68e614924904494d Binary files /dev/null and b/isis/src/base/apps/overlapstats/assets/thumb/thumb.1.jpg differ diff --git a/isis/src/base/apps/overlapstats/assets/thumb/thumb.2.jpg b/isis/src/base/apps/overlapstats/assets/thumb/thumb.2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fe663ec41fc8c13ca1aa5ad375b59f6caefc9bc9 Binary files /dev/null and b/isis/src/base/apps/overlapstats/assets/thumb/thumb.2.jpg differ diff --git a/isis/src/base/apps/overlapstats/assets/thumb/thumb.3.jpg b/isis/src/base/apps/overlapstats/assets/thumb/thumb.3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1f86d416127a8d995c9ef1cc90389df81588dbc2 Binary files /dev/null and b/isis/src/base/apps/overlapstats/assets/thumb/thumb.3.jpg differ diff --git a/isis/src/base/apps/overlapstats/overlapstats.cpp b/isis/src/base/apps/overlapstats/overlapstats.cpp new file mode 100644 index 0000000000000000000000000000000000000000..32dfe4bea0f7a82e033ce5fb78c2efc73d352ac3 --- /dev/null +++ b/isis/src/base/apps/overlapstats/overlapstats.cpp @@ -0,0 +1,299 @@ +#include "Isis.h" + +#include +#include + +#include "SerialNumberList.h" +#include "ImageOverlapSet.h" +#include "ImageOverlap.h" +#include "Statistics.h" +#include "PvlGroup.h" +#include "Pvl.h" +#include "Projection.h" +#include "ProjectionFactory.h" +#include "PolygonTools.h" +#include "Progress.h" + +using namespace std; +using namespace Isis; + +bool full = false; +bool tab = false; + +std::string FormatString( double input, int head, int tail ); + +void IsisMain() { + + UserInterface &ui = Application::GetUserInterface(); + SerialNumberList serialNumbers(ui.GetFilename("FROMLIST")); + + // Find all the overlaps between the images in the FROMLIST + // The overlap polygon coordinates are in Lon/Lat order + ImageOverlapSet overlaps; + overlaps.ReadImageOverlaps(ui.GetFilename("OVERLAPLIST")); + + // Progress + Progress progress; + progress.SetMaximumSteps( overlaps.Size() ); + progress.CheckStatus(); + + // Sets up the no overlap list + set nooverlap; + for ( int i = 0; i < serialNumbers.Size(); i ++ ) { + nooverlap.insert( serialNumbers.SerialNumber(i) ); + } + + // Create the output + + stringstream output (stringstream::in | stringstream::out); + output.precision(16); + output.setf(ios::showpoint); + + string delim = ""; + string pretty = ""; // Makes tab tables look pretty, ignored in CSV + bool singleLine = false; + if ( ui.WasEntered("DETAIL") ) { + if ( ui.GetString("TABLETYPE") == "CSV" ) { + delim = ","; + singleLine = ui.GetBoolean("SINGLELINE"); + // This line was removed because reability (ios::showpoint) was more + // important than an extra decimal place of precision. + //output.setf(ios::scientific,ios::floatfield); + } + else if ( ui.GetString("TABLETYPE") == "TAB" ) { + delim = "\t"; + pretty = "\t"; + + tab = true; + } + + full = ( ui.GetString("DETAIL") == "FULL" ); + } + + bool firstFullOutput = true; + + stringstream errors (stringstream::in | stringstream::out); + int errorNum = 0; + + // Extracts the stats of each overlap and adds to the table + Statistics thickness; + Statistics area; + Statistics sncount; + int overlapnum = 0;//Makes sure there are overlaps + for ( int index = 0; index < overlaps.Size(); index ++ ) { + + if ( overlaps[index]->Size() > 1 ) { + overlapnum++; + + // Removes the overlapping Serial Numbers for the nooverlap set + for ( int i = 0; i < overlaps[index]->Size(); i ++ ) { + nooverlap.erase( (*overlaps[index])[i] ); + } + + // Sets up the serial number stats + sncount.AddData( overlaps[index]->Size() ); + + // Sets up the thickness stats by doing A over E + const geos::geom::MultiPolygon *mpLatLon = overlaps[index]->Polygon(); + + // Construct a Projection for converting between Lon/Lat and X/Y + Pvl cubeLab(serialNumbers.Filename(0)); + PvlGroup inst = cubeLab.FindGroup("Instrument", Pvl::Traverse); + string target = inst["TargetName"]; + PvlGroup radii = Projection::TargetRadii(target); + Isis::Pvl maplab; + maplab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = maplab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",(string)radii["EquatorialRadius"]); + mapGroup += Isis::PvlKeyword("PolarRadius",(string)radii["PolarRadius"]); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetocentric"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",360); + mapGroup += Isis::PvlKeyword("CenterLatitude",0); + mapGroup += Isis::PvlKeyword("CenterLongitude",0); + mapGroup += Isis::PvlKeyword("ProjectionName","Sinusoidal"); + Projection *proj = Isis::ProjectionFactory::Create(maplab); + + // Sets up the thickness and area stats + try { + geos::geom::MultiPolygon *mpXY = PolygonTools::LatLonToXY( *mpLatLon, proj ); + + double thicknessValue = PolygonTools::Thickness( mpXY ); + thickness.AddData( thicknessValue ); + + double areaValue = mpXY->getArea(); + area.AddData( areaValue ); + + if( full ) { + if( firstFullOutput ) { + output << "Overlap ID"; + output << delim << "Thickness"; + output << delim << pretty << "Area"; + output << delim << pretty << pretty << "Image Count"; + output << delim << "Serial Numbers in Overlap"; + output << delim << "Image Files in Overlap"; + output << endl; + firstFullOutput = false; + } + output << index << pretty; + output << delim << thicknessValue; + if( tab ) { + output << delim << FormatString( areaValue, 18, 4 ); + } else { + output << delim << areaValue; + } + output << delim << overlaps[index]->Size() << pretty; + output << delim << (*overlaps[index])[0]; + output << delim << serialNumbers.Filename( (*overlaps[index])[0] ); + for( int sn=1; sn < overlaps[index]->Size(); sn ++ ) { + if( !singleLine ) { + output << endl << pretty << delim << pretty << delim << pretty << delim; + output << pretty << pretty; + } + output << delim << pretty << (*overlaps[index])[sn]; + output << delim << serialNumbers.Filename( (*overlaps[index])[sn] ); + } + output << endl; + } + + delete mpXY; + mpXY = NULL; + + } catch ( iException &e ) { + + if( ui.WasEntered("ERRORS") ) { + + if( errorNum > 0 ) { + errors << endl; + } + errorNum ++; + + errors << e.PvlErrors().Group(0).FindKeyword("Message")[0]; + for (int serNum = 0; serNum < overlaps[index]->Size(); serNum++) { + if( serNum == 0 ) { + errors << ": "; + } else { + errors << ", "; + } + errors << (*overlaps[index])[serNum]; + } + } + + e.Clear(); + + progress.CheckStatus(); + continue; + } + + } + + progress.CheckStatus(); + + } + + // Checks if there were overlaps to output results from + if ( overlapnum == 0 ) { + std::string msg = "The overlap file ["; + msg += Filename(ui.GetFilename("OVERLAPLIST")).Name(); + msg += "] does not contain any overlaps across the provided cubes ["; + msg += Filename(ui.GetFilename("FROMLIST")).Name() + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + + //Create and Log the BRIEF description + PvlGroup brief("Results"); + + brief += PvlKeyword( "ThicknessMinimum", thickness.Minimum() ); + brief += PvlKeyword( "ThicknessMaximum", thickness.Maximum() ); + brief += PvlKeyword( "ThicknessAverage", thickness.Average() ); + brief += PvlKeyword( "ThicknessStandardDeviation", thickness.StandardDeviation() ); + brief += PvlKeyword( "ThicknessVariance", thickness.Variance() ); + + brief += PvlKeyword( "AreaMinimum", area.Minimum() ); + brief += PvlKeyword( "AreaMaximum", area.Maximum() ); + brief += PvlKeyword( "AreaAverage", area.Average() ); + brief += PvlKeyword( "AreaStandardDeviation", area.StandardDeviation() ); + brief += PvlKeyword( "AreaVariance", area.Variance() ); + + brief += PvlKeyword( "ImageStackMinimum", sncount.Minimum() ); + brief += PvlKeyword( "ImageStackMaximum", sncount.Maximum() ); + brief += PvlKeyword( "ImageStackAverage", sncount.Average() ); + brief += PvlKeyword( "ImageStackStandardDeviation", sncount.StandardDeviation() ); + brief += PvlKeyword( "ImageStackVariance", sncount.Variance() ); + + brief += PvlKeyword( "PolygonCount", overlaps.Size() ); + + // Add non-overlapping cubes to the output + if ( !nooverlap.empty() ) { + for ( set::iterator itt = nooverlap.begin(); itt != nooverlap.end(); itt ++ ) { + brief += PvlKeyword( "NoOverlap", serialNumbers.Filename(*itt) ); + } + } + + Application::Log( brief ); + + + //Log the ERRORS file + if( ui.WasEntered("ERRORS") ) { + string errorname = ui.GetFilename("ERRORS"); + std::ofstream errorsfile; + errorsfile.open( errorname.c_str() ); + errorsfile << errors.str(); + errorsfile.close(); + } + + //Log error num in print.prt if there were errors + if( errorNum > 0 ) { + PvlGroup grp( "OverlapStats" ); + PvlKeyword key( "ErrorNumber", iString(errorNum) ); + grp.AddKeyword( key ); + Application::Log( grp ); + } + + // Display FULL output + if( full ) { + string outname = ui.GetFilename("TO"); + std::ofstream outfile; + outfile.open( outname.c_str() ); + outfile << output.str(); + outfile.close(); + if(outfile.fail()) { + iString msg = "Unable to write the statistics to [" + ui.GetFilename("TO") + "]"; + throw iException::Message(iException::Io, msg, _FILEINFO_); + } + } + +} + + +/** + * Takes a string and formats the length of that string around the decimal + * point. + * + * @param input The input double to be formatted + * @param head The desired character length for the double prior to the + * decimal point. It will be filled with " " (white space) + * @param tail The desired character length for the double after the decimal + * point. It will be filled with "0". + * + * @return std::string The formatted double for display + */ +std::string FormatString( double input, int head, int tail ) { + + iString result( input ); + + int point = result.find_first_of("."); + iString resultHead( result.substr(0,point) ); + iString resultTail( result.substr(point+1,result.size()-point-1) ); + + for( int place = resultHead.size(); place < head; place ++ ) { + resultHead = " " + resultHead; + } + + for( int place = resultTail.size(); place < tail; place ++ ) { + resultTail = resultTail + "0"; + } + + return resultHead + "." + resultTail; +} diff --git a/isis/src/base/apps/overlapstats/overlapstats.xml b/isis/src/base/apps/overlapstats/overlapstats.xml new file mode 100644 index 0000000000000000000000000000000000000000..75592d1d19d3a0346c646ef7d6eb32bf6a843350 --- /dev/null +++ b/isis/src/base/apps/overlapstats/overlapstats.xml @@ -0,0 +1,278 @@ + + + + + Calculates the statistics of overlapping cube regions + + +

    + Taking a list of cubes and an image overlap list file from + "findimageoverlaps", this application determines the statistics on all + overlapping polygons of those provided images, and displays those values + in the print.prt file. Note that the units of Area is square meters, and + Image is images per polygon. +

    +

    + In addition, if there are any cubes within the list that do not overlap with + any other cube in the list, those cube's filenames and Serial Numbers will + included at the end if the output given to the print.prt file. +

    +
    + + + Control Networks + + + + + Original version + + + Fixed the formatting for a tab tabletype, improved documentation, and + added an example. + + + The output file TO must now be specified. + + + Added support for image overlap files, which is what "OVERLAPLIST" needs to + be. This is a required parameter obtained from running "findimageoverlaps." + + + Added error throwing when there are no overlaps among the cubes provided + and other small bug fixes. + + + Added the ERRORS flat file. + + + Added the DETAILS FULL output option. BRIEF is now what the application + use to result in. + + + Altered the DETAILS FULL and BRIEF options based off of user input. Now, + the statistical data will always be placed in the print.prt file, and the + TO file will only be used for the detailed output of the overlaps. + + + Added the SINGLELINE parameter and changed the keywords SerialNumber* to + ImageStack* + + + Removed the *Sum keywords from the BRIEF output, and added PolygonCount. + + + + + + + + + filename + input + + List of Input cubes + + + The filename which contains a list of input cubes. + + + *.lis + + + + + filename + input + + This is the list of image overlaps corresponding to this control net + + + Use this parameter to select the filename which contains the + overlap list. You can obtain this file by running "findimageoverlaps." + + + * + + + + + + + + + string + + BRIEF + + Output data content + + Determines how much detail is given. + + + + + + + + + filename + output + + Output stats file + + + The table file of the detailed stats of each overlap. + + + + + string + + CSV + + Output data format + + The resultant statistics of the overlaps will be formatted + in accordance to the following option. + + + + + + + + + boolean + TRUE + + Place all Serial Numbers on the same CVS line + + + When True, places all Serial Numbers and Filenames on the same line + in the output CVS file. When False, Serial Numbers and Filenames + are placed in columns for readability. + + + + + filename + output + No Error Output + + Errors generated when calculating the overlap stats + + + This file will contain the errors that occurred while calculating the overlap stats. + + + + + + + + + + + Overlapping Statistics + + Get the overlapping statistics of the following cubes. + + + from=cubes.lis overlpalist=overlaps.dat + + In this example overlapstats will calculate the statistics of the thickness, + area, and serial number count of the overlapping polygons that the cubes + provided in cubes.lis create, and output those results into the + print.prt file. + + + + + + The list of cubes to use + + This is the input list of cubes to use to create the overlap which + the statistics will be ran on. + + FROMLIST + + + The resultant stats + + The stats of overlapstats will be displayed and sent to print.prt. + + + + + + + First image + This is the first input image for the overlapstats to use + + + + + Second image + This is the second input image + + + + + Third image + This is the third input image + + + + + + + + + +
    diff --git a/isis/src/base/apps/overlapstats/tsts/Makefile b/isis/src/base/apps/overlapstats/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/overlapstats/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/overlapstats/tsts/default/Makefile b/isis/src/base/apps/overlapstats/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4926c9ed269fc77a60b818bc6660480cd1141398 --- /dev/null +++ b/isis/src/base/apps/overlapstats/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME = overlapstats + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) from=$(OUTPUT)/list.lis \ + OVERLAPLIST=$(INPUT)/overlaps.lis \ + | grep -v "Processed" | grep -v "Working" \ + > $(OUTPUT)/brief.pvl; + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/overlapstats/tsts/full/Makefile b/isis/src/base/apps/overlapstats/tsts/full/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c0032bdb3f0e641e37f564381c23f3caba0409f4 --- /dev/null +++ b/isis/src/base/apps/overlapstats/tsts/full/Makefile @@ -0,0 +1,25 @@ +APPNAME = overlapstats + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + $(APPNAME) from=$(OUTPUT)/list.lis \ + to=$(OUTPUT)/csv.txt OVERLAPLIST=$(INPUT)/overlaps.lis \ + DETAIL=full SINGLELINE=false > /dev/null; + sed -e 's:/[a-zA-Z/0-9]*.lev1.cub:PATH:g' $(OUTPUT)/csv.txt \ + > $(OUTPUT)/csvNoPaths.txt; + $(RM) $(OUTPUT)/csv.txt; + $(APPNAME) from=$(OUTPUT)/list.lis \ + to=$(OUTPUT)/tab.txt OVERLAPLIST=$(INPUT)/overlaps.lis \ + DETAIL=full TABLETYPE=tab > /dev/null; + sed -e 's:/[a-zA-Z/0-9]*.lev1.cub:PATH:g' $(OUTPUT)/tab.txt \ + > $(OUTPUT)/tabNoPaths.txt; + $(RM) $(OUTPUT)/tab.txt; + $(APPNAME) from=$(OUTPUT)/list.lis \ + to=$(OUTPUT)/csvDefault.txt OVERLAPLIST=$(INPUT)/overlaps.lis \ + DETAIL=full > /dev/null; + sed -e 's:/[a-zA-Z/0-9]*.lev1.cub:PATH:g' $(OUTPUT)/csvDefault.txt \ + > $(OUTPUT)/csvDefaultNoPaths.txt; + $(RM) $(OUTPUT)/csvDefault.txt; + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/overlapstats/tsts/nooverlap/Makefile b/isis/src/base/apps/overlapstats/tsts/nooverlap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6f0a4fa4133ba0a49d50a41d25ac0ce45ecee963 --- /dev/null +++ b/isis/src/base/apps/overlapstats/tsts/nooverlap/Makefile @@ -0,0 +1,17 @@ +APPNAME = overlapstats + +error.txt.IGNORELINES = Processed + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/list.lis; + if [ `$(APPNAME) from=$(OUTPUT)/list.lis \ + OVERLAPLIST=$(INPUT)/overlaps.lis \ + >& $(OUTPUT)/temp.txt` ]; then \ + true; \ + fi; \ + $(CAT) $(OUTPUT)/temp.txt | cut -f 1-2 -d "]" \ + > $(OUTPUT)/error.txt; + $(RM) $(OUTPUT)/temp.txt; + $(RM) $(OUTPUT)/list.lis; diff --git a/isis/src/base/apps/pad/Makefile b/isis/src/base/apps/pad/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/pad/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/pad/pad.cpp b/isis/src/base/apps/pad/pad.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0bdd2e35ec46118478e4d9ba55aff57a38f39514 --- /dev/null +++ b/isis/src/base/apps/pad/pad.cpp @@ -0,0 +1,75 @@ +#include "Isis.h" +#include "ProcessMosaic.h" +#include "ProcessByLine.h" +#include "AlphaCube.h" +#include "SpecialPixel.h" +#include "Projection.h" +#include "SubArea.h" + +using namespace std; +using namespace Isis; + +void CreateBase (Buffer &buf); + +void IsisMain() { + // We will be use a mosaic technique so get the size of the input file + ProcessMosaic p; + Cube *icube = p.SetInputCube ("FROM"); + int ins = icube->Samples(); + int inl = icube->Lines(); + int inb = icube->Bands(); + + // Retrieve the padding parameters + UserInterface &ui = Application::GetUserInterface(); + int leftPad = ui.GetInteger("LEFT"); + int rightPad = ui.GetInteger("RIGHT"); + int topPad = ui.GetInteger("TOP"); + int bottomPad = ui.GetInteger("BOTTOM"); + + // Compute the output size + int ns = ins + leftPad + rightPad; + int nl = inl + topPad + bottomPad; + int nb = inb; + + // We need to create the output file + ProcessByLine bl; + bl.SetInputCube("FROM"); // Do this to match pixelType + bl.SetOutputCube("TO",ns,nl,nb); + bl.ClearInputCubes(); // Now get rid of it + bl.Progress()->SetText("Creating pad"); + bl.StartProcess(CreateBase); + bl.EndProcess(); + + // Place the input in the file we just created + Cube *ocube = p.SetOutputCube ("TO"); + p.Progress()->SetText("Inserting cube"); + p.StartProcess(leftPad+1, topPad+1, 1, input); + + // Construct a label with the results + PvlGroup results("Results"); + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("LeftPad", leftPad); + results += PvlKeyword ("RightPad", rightPad); + results += PvlKeyword ("TopPad", topPad); + results += PvlKeyword ("BottomPad", bottomPad); + results += PvlKeyword ("OutputLines", nl); + results += PvlKeyword ("OutputSamples", ns); + + // Update the Mapping, Instrument, and AlphaCube groups in the + // output cube label + SubArea s; + s.SetSubArea(inl,ins,1-topPad,1-leftPad,inl+bottomPad,ins+rightPad,1.0,1.0); + s.UpdateLabel(icube,ocube,results); + + p.EndProcess(); + + // Write the results to the log + Application::Log(results); +} + +void CreateBase (Buffer &buf) { + for (int i=0; i + + + + Add NULL padding around a cube + + + + This program allows the user to specify NULL padding to be + placed around the input cube. + + + + Utility + + + + + Original version + + + Added AlphaCube group and updating processing text + + + Removed references to CubeInfo + + + Now uses the SubArea class to produce output cube labels + with corrected Mapping, Instrument, and AlphaCube groups. + + + + + + + cube + input + + Cube to pad + + + This is the cube which will be padded with NULLs + + + *.cub + + + + + cube + output + + The resultant cube + + + This cube will contain the padded input file + + + *.cub + + + + + + + integer + Number of pixels to pad on the left side + 0 + 0 + + This is the number of pixels to pad on the left side of the cube + + + + + integer + Number of pixels to pad on the right side + 0 + 0 + + This is the number of pixels to pad on the right side of the cube + + + + + integer + Number of pixels to pad on the top edge + 0 + 0 + + This is the number of pixels to pad on the top edge of the cube + + + + + integer + Number of pixels to pad on the bottom edge + 0 + 0 + + This is the number of pixels to pad on the bottom edge of the cube + + + + + diff --git a/isis/src/base/apps/pad/tsts/Makefile b/isis/src/base/apps/pad/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/pad/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/pad/tsts/case01/Makefile b/isis/src/base/apps/pad/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..444b02cbbe36f268e926a7181380b71402217ce6 --- /dev/null +++ b/isis/src/base/apps/pad/tsts/case01/Makefile @@ -0,0 +1,11 @@ +APPNAME = pad + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/padTruth1.cub \ + left=0 \ + right=100 \ + top=100 \ + bottom=0 > /dev/null; diff --git a/isis/src/base/apps/pad/tsts/case02/Makefile b/isis/src/base/apps/pad/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3cb6af81a830c7c2b1079711043ac1d1805c9fef --- /dev/null +++ b/isis/src/base/apps/pad/tsts/case02/Makefile @@ -0,0 +1,11 @@ +APPNAME = pad + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/padTruth2.cub \ + left=0 \ + right=0 \ + top=10 \ + bottom=0 > /dev/null; diff --git a/isis/src/base/apps/pad/tsts/case03/Makefile b/isis/src/base/apps/pad/tsts/case03/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5dc742ce4ca38de3698377a4160c28cff3d0a0d9 --- /dev/null +++ b/isis/src/base/apps/pad/tsts/case03/Makefile @@ -0,0 +1,11 @@ +APPNAME = pad + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/padTruth3.cub \ + left=50 \ + right=50 \ + top=50 \ + bottom=50 > /dev/null; diff --git a/isis/src/base/apps/pca/Makefile b/isis/src/base/apps/pca/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/pca/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/pca/pca.cpp b/isis/src/base/apps/pca/pca.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9f8a1c5d7e3c282fd8182f643b9c33f0134ef8f9 --- /dev/null +++ b/isis/src/base/apps/pca/pca.cpp @@ -0,0 +1,145 @@ +#include "Isis.h" +#include "tnt_array2d.h" +#include "PrincipalComponentAnalysis.h" +#include "ProcessBySpectra.h" +#include "Statistics.h" +#include "Table.h" +#include "TableField.h" +#include "TableRecord.h" + +using namespace std; +using namespace Isis; + +void PCA(Buffer &in); +void Transform (Buffer &in, Buffer &out); +void Inverse (Buffer &in, Buffer &out); + +PrincipalComponentAnalysis pca(0); + +int numDimensions; + +void IsisMain() +{ + UserInterface &ui = Application::GetUserInterface(); + + ProcessByBrick p; + Cube *icube = p.SetInputCube("FROM"); + p.SetBrickSize(128, 128, icube->Bands()); + + // The output cube with no attributes and real pixel type + Isis::CubeAttributeOutput cao; + cao.PixelType(Isis::Real); + + // Start the sample processing + if (ui.GetString("MODE") == "TRANSFORM") { + Cube *ocube = p.SetOutputCube (ui.GetAsString("TO"), cao, icube->Samples(), icube->Lines(), icube->Bands()); + numDimensions = icube->Bands(); + pca = Isis::PrincipalComponentAnalysis(numDimensions); + ProcessByBrick p2; + p2.SetBrickSize(128, 128, icube->Bands()); + p2.SetInputCube("FROM"); + p2.Progress()->SetText("Computing Transform"); + p2.StartProcess(PCA); + p2.EndProcess(); + pca.ComputeTransform(); + TNT::Array2D transform = pca.TransformMatrix(); + + // Add a table to the output cube that contains the transform matrix + // This allows us to invert the cube back from pc space + Isis::TableField field("Columns", Isis::TableField::Double, transform.dim2()); + Isis::TableRecord record; + record += field; + Isis::Table table("Transform Matrix", record); + for (int i=0; i row; + for (int j=0; jSetText("Transforming Cube"); + p.StartProcess(Transform); + ocube->Write(table); + p.EndProcess(); + } + else if (ui.GetString("MODE") == "INVERSE") { + if (!(icube->HasTable("Transform Matrix")) ) { + std::string m="The input cube has not been transformed into its principal components"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + Isis::Table table("Transform Matrix"); + icube->Read(table); + numDimensions = table.Records(); + TNT::Array2D transform(numDimensions, numDimensions); + for (int i=0; i row = table[i]["Columns"]; + for (int j=0; jSamples(), icube->Lines(), numDimensions); + Pvl *label = ocube->Label(); + // remove the transform matrix table from the cube + for (int i=0; i< label->Objects(); i++) { + if (label->Object(i).HasKeyword("Name") + && label->Object(i)["Name"].IsEquivalent("Transform Matrix")) label->DeleteObject(i); + } + p.Progress()->SetText("Inverting Cube"); + p.StartProcess(Inverse); + p.EndProcess(); + } + else { + std::string m="Invalid option for MODE [" + ui.GetString("MODE") + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } +} + +// Processing routine for the pca with one input cube +void Transform (Buffer &in, Buffer &out){ + for (int i=0; i pre(1, in.BandDimension()); + for (int k=0;k post = pca.Transform(pre); + + for (int k=0; k pre(1, in.BandDimension()); + for (int k=0;kin.size()) pre[0][k] = 0.0; + else pre[0][k] = in[index]; + } + + TNT::Array2D post = pca.Inverse(pre); + + for (int k=0; k + + + Apply Principal Component Analysis on a cube + + + + This programs converts a cube into principal component space or + converts a cube back from principal component space. + + + + Math and Statistics + + + + + decorstretch + fft + ifft + + + + + + Original version + + + Documentation fixes + + + Removed references to CubeInfo + + + + + + + cube + input + + Input file to transform + + + The input cube which will be transformed into principal component space. + + + *.cub + + + + + cube + real + output + + Output cube + + + The resultant cube containing the image in principal component space. + + + *.cub + + + + + + + + string + + TRANSFORM + + Transform mode + + This option is used to specify a forward or inverse transform. + + + + + + + + + diff --git a/isis/src/base/apps/pca/tsts/Makefile b/isis/src/base/apps/pca/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/pca/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/pca/tsts/inverse/Makefile b/isis/src/base/apps/pca/tsts/inverse/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f5fc4a39bda84f2107ce3546bbcad1aab688aaac --- /dev/null +++ b/isis/src/base/apps/pca/tsts/inverse/Makefile @@ -0,0 +1,14 @@ +APPNAME = pca + +pcaInverseTruth.cub.TOLERANCE = 0.00000000001 +pcaTransformTruth.cub.TOLERANCE = 0.00000001 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/test.cub \ + to= $(OUTPUT)/pcaTransformTruth.cub \ + mode=transform > /dev/null; + $(APPNAME) from= $(OUTPUT)/pcaTransformTruth.cub \ + to= $(OUTPUT)/pcaInverseTruth.cub \ + mode=inverse > /dev/null; diff --git a/isis/src/base/apps/pca/tsts/transform/Makefile b/isis/src/base/apps/pca/tsts/transform/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..98878f34c5ff737e833286de68ec5957698e3da5 --- /dev/null +++ b/isis/src/base/apps/pca/tsts/transform/Makefile @@ -0,0 +1,10 @@ +APPNAME = pca + +pcaTransformTruth.cub.TOLERANCE = .00000001 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/test.cub \ + to= $(OUTPUT)/pcaTransformTruth.cub \ + mode=transform > /dev/null; diff --git a/isis/src/base/apps/pds2isis/Makefile b/isis/src/base/apps/pds2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/pds2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/pds2isis/assets/images/out.jpg b/isis/src/base/apps/pds2isis/assets/images/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9382183c255d5cb5f43ec094072151dae34437d6 Binary files /dev/null and b/isis/src/base/apps/pds2isis/assets/images/out.jpg differ diff --git a/isis/src/base/apps/pds2isis/assets/images/pds2isisGUI.jpg b/isis/src/base/apps/pds2isis/assets/images/pds2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..be7f8e39e3d53823ff87bb49bd0d7dd620cefa01 Binary files /dev/null and b/isis/src/base/apps/pds2isis/assets/images/pds2isisGUI.jpg differ diff --git a/isis/src/base/apps/pds2isis/assets/thumbs/out.jpg b/isis/src/base/apps/pds2isis/assets/thumbs/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..964463f99e605faf50e11f7719840ee0be5ebc3c Binary files /dev/null and b/isis/src/base/apps/pds2isis/assets/thumbs/out.jpg differ diff --git a/isis/src/base/apps/pds2isis/assets/thumbs/pds2isisGUI.jpg b/isis/src/base/apps/pds2isis/assets/thumbs/pds2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..344ccdd6518455bb5cfd518aaec3d862ef6f375a Binary files /dev/null and b/isis/src/base/apps/pds2isis/assets/thumbs/pds2isisGUI.jpg differ diff --git a/isis/src/base/apps/pds2isis/pds2isis.cpp b/isis/src/base/apps/pds2isis/pds2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f5c85f1b8f3d19e1816c582b24782d20b472075 --- /dev/null +++ b/isis/src/base/apps/pds2isis/pds2isis.cpp @@ -0,0 +1,76 @@ +#include "Isis.h" +#include "ProcessImportPds.h" + +#include "UserInterface.h" +#include "Filename.h" + +using namespace std; +using namespace Isis; + +void IsisMain () +{ + ProcessImportPds p; + Pvl label; + UserInterface &ui = Application::GetUserInterface(); + + string labelFile = ui.GetFilename("FROM"); + string imageFile(""); + if (ui.WasEntered("IMAGE")) { + imageFile = ui.GetFilename("IMAGE"); + } + + p.SetPdsFile (labelFile, imageFile, label); + Cube *ocube = p.SetOutputCube ("TO"); + + // Get user entered special pixel ranges + if (ui.GetBoolean("SETNULLRANGE")) { + p.SetNull(ui.GetDouble("NULLMIN"),ui.GetDouble("NULLMAX")); + } + if (ui.GetBoolean("SETHRSRANGE")) { + p.SetHRS(ui.GetDouble("HRSMIN"),ui.GetDouble("HRSMAX")); + } + if (ui.GetBoolean("SETHISRANGE")) { + p.SetHIS(ui.GetDouble("HISMIN"),ui.GetDouble("HISMAX")); + } + if (ui.GetBoolean("SETLRSRANGE")) { + p.SetLRS(ui.GetDouble("LRSMIN"),ui.GetDouble("LRSMAX")); + } + if (ui.GetBoolean("SETLISRANGE")) { + p.SetLIS(ui.GetDouble("LISMIN"),ui.GetDouble("LISMAX")); + } + + // Export the cube + p.StartProcess (); + + // Get as many of the other labels as we can + Pvl otherLabels; + p.TranslatePdsProjection(otherLabels); + if (p.IsIsis2()) { + p.TranslateIsis2Labels (otherLabels); + } + else { + p.TranslatePdsLabels (otherLabels); + } + + if (otherLabels.HasGroup("Mapping") && + (otherLabels.FindGroup("Mapping").Keywords() > 0)) { + ocube->PutGroup(otherLabels.FindGroup("Mapping")); + } + if (otherLabels.HasGroup("Instrument") && + (otherLabels.FindGroup("Instrument").Keywords() > 0)) { + ocube->PutGroup(otherLabels.FindGroup("Instrument")); + } + if (otherLabels.HasGroup("BandBin") && + (otherLabels.FindGroup("BandBin").Keywords() > 0)) { + ocube->PutGroup(otherLabels.FindGroup("BandBin")); + } + if (otherLabels.HasGroup("Archive") && + (otherLabels.FindGroup("Archive").Keywords() > 0)) { + ocube->PutGroup(otherLabels.FindGroup("Archive")); + } + + p.EndProcess (); + + return; +} + diff --git a/isis/src/base/apps/pds2isis/pds2isis.xml b/isis/src/base/apps/pds2isis/pds2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..3c67e6606988710278c3fc2f06993ed89be9befd --- /dev/null +++ b/isis/src/base/apps/pds2isis/pds2isis.xml @@ -0,0 +1,412 @@ + + + + + Import PDS image cube into Isis format cube + + +

    This program will import a PDS image into an Isis cube.

    +

    + The special pixel ranges that may be entered, can align back-to-back. + i.e. Null Range = ( 0.0 3.0 ) and LIS Range = ( 3.0, 5.0 ) + When this is done, certain special pixels take precedence over others in + the following order: + Null + HRS + LRS + HIS + LIS + Therefore, in the above example, the actual raw value of 3.0 would be + translated into a Null pixel, since Null is listed before LIS in the + priority list. +

    +
    + + + + Original version + + + Wrote for Isis 3. + + + Modified schema location from astrogeology... to isis.astrogeology..." + + + Fixed Makefile + + + Converted to use new IsisImport instead of IsisPdsImport + + + Converted to use the new IsisImportPds class and added + import labels to the output cube. + + + Documentation fixes + + + Added ability to transfers Isis2 instrument and bandbin + information. + + + Added LatitudeType2 group to translation table to handle CTX cubes. + Additonal changes to projection translation tables for other possible + values for Longitude direction, latitude type. If the min or max + longitude values are greater than 180, change longitude domain to 360. + Only call TranslateIsis2Labels if pds file is an Isis2 cube. + + + Added support for copying some PDS labels, if they exist, into the output. + + + Added special pixel ranges. Added examples. + + + Removed references to CubeInfo + + + Fixed problem with special pixel range functionality and documentation. + Added HIS and LIS range options. + + + + + Import and Export + + + + + + + + filename + input + + Input PDS file + + + Use this parameter to select the PDS filename. This file + must contain the PDS labels, however the image data can + be detached and will be automatically obtained from the + PDS image pointer keyword. If the pointer is incorrect then + use the IMAGE parameter to specify the file containing the + binary image data. + + + *.lbl *.img + + + + + filename + input + + Detached data file + + + Use this parameter if the pointer to the image data in the + detached label (FROM) is incorrrect. + + + Cube data embedded with label or file pointer in label file. + + + *.img + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + + + + + boolean + + NO + + Pixel values in the given range are converted to Null + + If this option is used, the input raw pixels inside and including the + NULLMIN and NULLMAX will be converted to Null pixels. Otherwise pixels + in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit + real will cause 0 and 255 to be actual values. If left as 8-bit then 0 + will be NULL and 255 will be HRS. + + + NULLMIN + NULLMAX + + + + double + Minimum Null value + + Minimum Null value. Anything from this value to NULLMAX will be + converted to Null. + + + SETNULLRANGE + + + + double + Maximum Null value + + Maximum Null value. Anything from this value to NULLMIN will be + converted to Null. + + + SETNULLRANGE + + + + + boolean + + NO + + Pixel values in the given range are converted to HRS + + If this option is used, the input raw pixels inside and including the + HRSMIN and HRSMAX will be converted to HRS pixels. Otherwise pixels + in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit + real will cause 0 and 255 to be actual values. If left as 8-bit then 0 + will be NULL and 255 will be HRS. + + + HRSMIN + HRSMAX + + + + double + Minimum HRS value + + Minimum HRS value. Anything from this value to HRSMAX will be + converted to HRS. + + + SETHRSRANGE + + + + double + Maximum HRS value + + Maximum HRS value. Anything from this value to HRSMIN will be + converted to HRS. + + + SETHRSRANGE + + + + + boolean + + NO + + Pixel values in the given range are converted to HIS + + If this option is used, the input raw pixels inside and including the + HISMIN and HISMAX will be converted to HIS pixels. Otherwise pixels + in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit + real will cause 0 and 255 to be actual values. If left as 8-bit then 0 + will be NULL and 255 will be HRS. + + + HISMIN + HISMAX + + + + double + Minimum HIS value + + Minimum HIS value. Anything from this value to HISMAX will be + converted to HIS. + + + SETHISRANGE + + + + double + Maximum HIS value + + Maximum HIS value. Anything from this value to HISMIN will be + converted to HIS. + + + SETHISRANGE + + + + + boolean + + NO + + Pixel values in the given range are converted to LRS + + If this option is used, the input raw pixels inside and including the + LRSMIN and LRSMAX will be converted to LRS pixels. Otherwise pixels + in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit + real will cause 0 and 255 to be actual values. If left as 8-bit then 0 + will be NULL and 255 will be HRS. + + + LRSMIN + LRSMAX + + + + double + Minimum LRS value + + Minimum LRS value. Anything from this value to LRSMAX will be + converted to LRS. + + + SETLRSRANGE + + + + double + Maximum LRS value + + Maximum LRS value. Anything from this value to LRSMIN will be + converted to LRS. + + + SETLRSRANGE + + + + + boolean + + NO + + Pixel values in the given range are converted to LIS + + If this option is used, the input raw pixels inside and including the + LISMIN and LISMAX will be converted to LIS pixels. Otherwise pixels + in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit + real will cause 0 and 255 to be actual values. If left as 8-bit then 0 + will be NULL and 255 will be HRS. + + + LISMIN + LISMAX + + + + double + Minimum LIS value + + Minimum LIS value. Anything from this value to LISMAX will be + converted to LIS. + + + SETLISRANGE + + + + double + Maximum LIS value + + Maximum LIS value. Anything from this value to LISMIN will be + converted to LIS. + + + SETLISRANGE + + + + + + + + + + + Using pds2isis with default parameters + + + The use of pds2isis to ingest PDS data and output Isis3 cubes. + + + + from= input.img + to= out.cub + + + This example shows the use of pds2isis create an Isis3 cube. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters + + + + + + + + + + PDS format input file. + + + This is the PDS labels and data + + FROM + + + + + + + Final output image after the conversion + + + Converts from PDS format to a Isis3 cube. + + + TO + + + + + +
    diff --git a/isis/src/base/apps/pds2isis/tsts/Makefile b/isis/src/base/apps/pds2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/pds2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/pds2isis/tsts/default/Makefile b/isis/src/base/apps/pds2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5200ff8582904e580e094c1a1049a2b85eebc26c --- /dev/null +++ b/isis/src/base/apps/pds2isis/tsts/default/Makefile @@ -0,0 +1,10 @@ +APPNAME = pds2isis + +labels.txt.IGNORELINES = Bytes StartByte ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.img \ + to=$(OUTPUT)/pds2isisTruth.cub > /dev/null; + catlab from=$(OUTPUT)/pds2isisTruth.cub >& $(OUTPUT)/labels.txt; diff --git a/isis/src/base/apps/pds2isis/tsts/specialPixels/Makefile b/isis/src/base/apps/pds2isis/tsts/specialPixels/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c5bef798d2f66426f78f7f74189a7c307ced3707 --- /dev/null +++ b/isis/src/base/apps/pds2isis/tsts/specialPixels/Makefile @@ -0,0 +1,16 @@ +APPNAME = pds2isis + +labels.txt.IGNORELINES = Bytes StartByte ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.img \ + to=$(OUTPUT)/pds2isisTruth.cub+32bit \ + setnullrange=yes nullmin=15.0 nullmax=45.0 \ + sethrsrange=yes hrsmin=220.0 hrsmax=250.0 \ + sethisrange=yes hismin=190.0 hismax=219.0 \ + setlrsrange=yes lrsmin=96.0 lrsmax=125.0 \ + setlisrange=yes lismin=65.0 lismax=95.0 \ + > /dev/null; + catlab from=$(OUTPUT)/pds2isisTruth.cub >& $(OUTPUT)/labels.txt; diff --git a/isis/src/base/apps/percent/Makefile b/isis/src/base/apps/percent/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/percent/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/percent/assets/image/f332s28.jpg b/isis/src/base/apps/percent/assets/image/f332s28.jpg new file mode 100644 index 0000000000000000000000000000000000000000..112512e5ef0dc4bdaedf906c5c5d868e786bba75 Binary files /dev/null and b/isis/src/base/apps/percent/assets/image/f332s28.jpg differ diff --git a/isis/src/base/apps/percent/assets/image/mPercentTxt.JPG b/isis/src/base/apps/percent/assets/image/mPercentTxt.JPG new file mode 100644 index 0000000000000000000000000000000000000000..59404ababf92f05a270b2eb02245fc40befb2a30 Binary files /dev/null and b/isis/src/base/apps/percent/assets/image/mPercentTxt.JPG differ diff --git a/isis/src/base/apps/percent/assets/image/percentGui.jpg b/isis/src/base/apps/percent/assets/image/percentGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df0df2050d59f14f309fa5b9f50b381e0add9dd6 Binary files /dev/null and b/isis/src/base/apps/percent/assets/image/percentGui.jpg differ diff --git a/isis/src/base/apps/percent/assets/image/percentTxt.jpg b/isis/src/base/apps/percent/assets/image/percentTxt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a9a4e2d482d59e77d07f9252ccc9a2238c39808d Binary files /dev/null and b/isis/src/base/apps/percent/assets/image/percentTxt.jpg differ diff --git a/isis/src/base/apps/percent/assets/thumb/f332s28.jpg b/isis/src/base/apps/percent/assets/thumb/f332s28.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8a49c02a1335a9fc5d7abb4224fc6132f4ea32dd Binary files /dev/null and b/isis/src/base/apps/percent/assets/thumb/f332s28.jpg differ diff --git a/isis/src/base/apps/percent/assets/thumb/mPercentTxt.JPG b/isis/src/base/apps/percent/assets/thumb/mPercentTxt.JPG new file mode 100644 index 0000000000000000000000000000000000000000..f285a5b2bfef4f14e8f4bbe70457d34687b31979 Binary files /dev/null and b/isis/src/base/apps/percent/assets/thumb/mPercentTxt.JPG differ diff --git a/isis/src/base/apps/percent/assets/thumb/percentGui.jpg b/isis/src/base/apps/percent/assets/thumb/percentGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..60d39588c1ef98c77655104b82134377cea5c207 Binary files /dev/null and b/isis/src/base/apps/percent/assets/thumb/percentGui.jpg differ diff --git a/isis/src/base/apps/percent/assets/thumb/percentTxt.jpg b/isis/src/base/apps/percent/assets/thumb/percentTxt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b2c9446d6b9429f143c053a342393e9ccaeee0b3 Binary files /dev/null and b/isis/src/base/apps/percent/assets/thumb/percentTxt.jpg differ diff --git a/isis/src/base/apps/percent/percent.cpp b/isis/src/base/apps/percent/percent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd8e7b4ad60a293b0e6c2457d69bd8e454a4fa5a --- /dev/null +++ b/isis/src/base/apps/percent/percent.cpp @@ -0,0 +1,52 @@ +#include "Isis.h" + +#include +#include + +#include "Process.h" +#include "Pvl.h" +#include "PvlFormat.h" +#include "Histogram.h" +#include "iString.h" + + +using namespace std; +using namespace Isis; + +void IsisMain() { + // Use a regular Process + Process p; + + // Open the input cube + Cube *icube = p.SetInputCube("FROM",OneBand); + + // Get the desired percentage(s) + UserInterface &ui = Application::GetUserInterface(); + string sPercentage; + sPercentage = ui.GetString("PERCENTAGE"); + vector tokens; + iString::Split(',', sPercentage, tokens, true); + PvlGroup results("Results"); + PvlKeyword kwPercent("Percentage"); + PvlKeyword kwValue("Value"); + + for(unsigned int i = 0; iHistogram(); + double value = hist->Percent(percentage); + kwPercent += percentage; + kwValue += value; + } + results += kwPercent; + results += kwValue; + + // Log the results + Application::Log(results); + // Write an output file if requested + if (ui.WasEntered("TO")) { + Pvl temp; + temp.AddGroup(results); + temp.Write(ui.GetFilename("TO","txt")); + } +} diff --git a/isis/src/base/apps/percent/percent.xml b/isis/src/base/apps/percent/percent.xml new file mode 100644 index 0000000000000000000000000000000000000000..f0e5e4a49c109c74e693c767dd158c4477f7a3ba --- /dev/null +++ b/isis/src/base/apps/percent/percent.xml @@ -0,0 +1,174 @@ + + + + Obtains the DN value at a percent in a histogram + + + + This program will output the DN value at a cumulative + percentage in a histogram. For example, requesting + the 50% DN will output the median. Values such as + the 0.5% and 99.5% are good for selecting minimums and + maximums which do not include outliers. The histogram + will be obtained from a single band in the input cube and + is identified using the band specifier (e.g., file.cub:5). + In general, this program is used + within batch jobs, perl programs, or other scripting + languages. The value(s) will be written to the output + text file specified by the parameter TO and it can + be extracted using the "getkey" program. If multiple + percents were requested, the values are printed to the + text file in the same order as the requested percents + and are comma delimited. + + + + Scripting + + + + + getkey + + + + + + Original version + + + Add example + + + Make images smaller. + + + Fixed problem with isiscvs not checking in the thumb and image directories. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Updated application test due to compiler optimizations + + + Modified filename parameters to be cube parameters where necessary + + + Change default extension handling mechanism + + + Modified results pvl to not include the results group + + + Fixed appTest to comply to changes in String + + + Removed references to CubeInfo + + + + + + + cube + input + + Filename of a cube + + + Compute the histogram using this cube file. The program + operates on only one band and therefore a band specifier + is required (e.g., file.cub:3) + + + *.cub + + + + + filename + output + Text file + None + + A text file in label format which will contain + the results of this program. This file can + be used inconjunction with the "getkey" program + in order to pass the results to another program. + + + + + + + string + + Histogram percentage to return + + + This parameter indicates the cumulative percentage + to examine in the histogram. The DN value at that + percentage will be output by this program. For example, + PERCENTAGE=50 will return the median of the image. + When entering multiple percentages, be sure they are + comma delimited. + + 0.0 + 100.0 + + + + + + + percent.txt + Use text file output + + + f=../IN/f332s28.cub t=OUT/percent.txt p=50 + Set TO parameter to percent.txt + + + + + Input image for percent + This is the input image f332s28.cub + + + FROM + + + + + + Output text file + Output text file shown in editor giving results of + the percent application. + + + TO + + + + Results of the percent application when multiple percentages are requested. + + + + + + + + Example GUI + Screenshot of GUI with parameters filled in to perform the percent operation + + + + + + + + diff --git a/isis/src/base/apps/percent/tsts/Makefile b/isis/src/base/apps/percent/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/percent/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/percent/tsts/case01_99/Makefile b/isis/src/base/apps/percent/tsts/case01_99/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3c56eb8fcdfccefefd2e718618cad8c5d0c21358 --- /dev/null +++ b/isis/src/base/apps/percent/tsts/case01_99/Makefile @@ -0,0 +1,8 @@ +APPNAME = percent + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/p99.txt \ + percentage=99 > /dev/null; diff --git a/isis/src/base/apps/percent/tsts/case02_50/Makefile b/isis/src/base/apps/percent/tsts/case02_50/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f03ca76c53f9cfc6bcc96c2c3ed86b39a209f2eb --- /dev/null +++ b/isis/src/base/apps/percent/tsts/case02_50/Makefile @@ -0,0 +1,8 @@ +APPNAME = percent + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/p50.txt \ + percentage=50 > /dev/null; diff --git a/isis/src/base/apps/percent/tsts/case03_.1/Makefile b/isis/src/base/apps/percent/tsts/case03_.1/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6e898a19188d4f74b027f034404457a59066aa3c --- /dev/null +++ b/isis/src/base/apps/percent/tsts/case03_.1/Makefile @@ -0,0 +1,8 @@ +APPNAME = percent + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/ppoint1.txt \ + percentage=.1 > /dev/null; diff --git a/isis/src/base/apps/percent/tsts/case04_mult/Makefile b/isis/src/base/apps/percent/tsts/case04_mult/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..37ee911f627219b12da650f26e4e55c02f200900 --- /dev/null +++ b/isis/src/base/apps/percent/tsts/case04_mult/Makefile @@ -0,0 +1,8 @@ +APPNAME = percent + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub+1 \ + to=$(OUTPUT)/multiple.pvl \ + percentage=.1,99.5,50.0 > /dev/null; diff --git a/isis/src/base/apps/phocube/Makefile b/isis/src/base/apps/phocube/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/phocube/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/phocube/phocube.cpp b/isis/src/base/apps/phocube/phocube.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a7823b09f90f1628bf54533207952c2c7340125 --- /dev/null +++ b/isis/src/base/apps/phocube/phocube.cpp @@ -0,0 +1,175 @@ +#include "Isis.h" +#include "Camera.h" +#include "ProcessByBrick.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" + + +using namespace std; +using namespace Isis; + +// Global variables +Camera *cam; +int nbands; +bool phase, emission, incidence, latitude, longitude, pixelResolution, + lineResolution, sampleResolution, detectorResolution, northAzimuth, + sunAzimuth, spacecraftAzimuth, offnadirAngle; + +void phocube (Buffer &out); + +void IsisMain() { + // Get the camera information + Process p1; + Cube *icube = p1.SetInputCube("FROM",OneBand); + cam = icube->Camera(); + + // We will be processing by brick. + ProcessByBrick p; + + // Find out which bands are to be created + UserInterface &ui = Application::GetUserInterface(); + + nbands = 0; + if ((phase = ui.GetBoolean("PHASE"))) nbands++; + if ((emission = ui.GetBoolean("EMISSION"))) nbands++; + if ((incidence = ui.GetBoolean("INCIDENCE"))) nbands++; + if ((latitude = ui.GetBoolean("LATITUDE"))) nbands++; + if ((longitude = ui.GetBoolean("LONGITUDE"))) nbands++; + if ((pixelResolution = ui.GetBoolean("PIXELRESOLUTION"))) nbands++; + if ((lineResolution = ui.GetBoolean("LINERESOLUTION"))) nbands++; + if ((sampleResolution = ui.GetBoolean("SAMPLERESOLUTION"))) nbands++; + if ((detectorResolution = ui.GetBoolean("DETECTORRESOLUTION"))) nbands++; + if ((northAzimuth = ui.GetBoolean("NORTHAZIMUTH"))) nbands++; + if ((sunAzimuth = ui.GetBoolean("SUNAZIMUTH"))) nbands++; + if ((spacecraftAzimuth = ui.GetBoolean("SPACECRAFTAZIMUTH"))) nbands++; + if ((offnadirAngle = ui.GetBoolean("OFFNADIRANGLE"))) nbands++; + + if (nbands < 1) { + string message = "At least one photometry parameter must be entered" + "[PHASE, EMISSION, INCIDENCE, LATITUDE, LONGITUDE]"; + throw iException::Message (iException::User, message, _FILEINFO_); + } + + // Create a bandbin group for the output label + PvlKeyword name("Name"); + if (phase) name += "Phase Angle"; + if (emission) name += "Emission Angle"; + if (incidence) name += "Incidence Angle"; + if (latitude) name += "Latitude"; + if (longitude) name += "Longitude"; + if (pixelResolution) name += "Pixel Resolution"; + if (lineResolution) name += "Line Resolution"; + if (sampleResolution) name += "Sample Resolution"; + if (detectorResolution) name += "Detector Resolution"; + if (northAzimuth) name += "North Azimuth"; + if (sunAzimuth) name += "Sun Azimuth"; + if (spacecraftAzimuth) name += "Spacecraft Azimuth"; + if (offnadirAngle) name += "OffNadir Angle"; + PvlGroup bandBin("BandBin"); + bandBin += name; + + // Create the output cube. Note we add the input cube to expedite propagation + // of input cube elements (label, blobs, etc...). It *must* be cleared + // prior to systematic processing. + (void) p.SetInputCube("FROM", OneBand); + Cube *ocube = p.SetOutputCube("TO",icube->Samples(), icube->Lines(), nbands); + p.SetBrickSize(64,64,nbands); + p.ClearInputCubes(); // Toss the input file as stated above + + // Start the processing + p.StartProcess(phocube); + + // Add the bandbin group to the output label. If a BandBin group already + // exists, remove all existing keywords and add the keywords for this app. + // Otherwise, just put the group in. + PvlObject &cobj = ocube->Label()->FindObject("IsisCube"); + if (cobj.HasGroup("BandBin")) { + PvlGroup &bb = cobj.FindGroup("BandBin"); + bb.Clear(); + PvlContainer::PvlKeywordIterator k = bandBin.Begin(); + while (k != bandBin.End()) { + bb += *k; + ++k; + } + } + else { + ocube->PutGroup(bandBin); + } + + p.EndProcess(); +} + +void phocube (Buffer &out) { + + for (int i=0; i<64; i++) { + for (int j=0; j<64; j++) { + int index = i * 64 + j; + double samp = out.Sample(index); + double line = out.Line(index); + cam->SetImage(samp,line); + + if (cam->HasSurfaceIntersection()) { + if (phase) { + out[index] = cam->PhaseAngle(); + index += 64 * 64; + } + if (emission) { + out[index] = cam->EmissionAngle(); + index += 64 * 64; + } + if (incidence) { + out[index] = cam->IncidenceAngle(); + index += 64 * 64; + } + if (latitude) { + out[index] = cam->UniversalLatitude(); + index += 64 * 64; + } + if (longitude) { + out[index] = cam->UniversalLongitude(); + index += 64 * 64; + } + if (pixelResolution) { + out[index] = cam->PixelResolution(); + index += 64 * 64; + } + if (lineResolution) { + out[index] = cam->LineResolution(); + index += 64 * 64; + } + if (sampleResolution) { + out[index] = cam->SampleResolution(); + index += 64 * 64; + } + if (detectorResolution) { + out[index] = cam->SampleResolution(); + index += 64 * 64; + } + if (northAzimuth) { + out[index] = cam->NorthAzimuth(); + index += 64 * 64; + } + if (sunAzimuth) { + out[index] = cam->SunAzimuth(); + index += 64 * 64; + } + if (spacecraftAzimuth) { + out[index] = cam->SpacecraftAzimuth(); + index += 64 * 64; + } + if (offnadirAngle) { + out[index] = cam->OffNadirAngle(); + index += 64 * 64; + } + } + // Trim outerspace + else { + for (int b=0; b + + + + + Creates phase, incidence, and/or emmision angle bands for a cube + + + + This program creates a cube where the bands represent the photometry phase, + emission and/or incidence angles. Only the desired bands will be created. + + + + lev1geoplane + levgeoplane + geoback + + + + Add resolution to possible outputs + Convert to a IsisProcessBySpectra when it gets written + + + + + Original version + + + Converted to Isis 3.0, and made it create a cube rather than adding + backplanes. + + + Modified filename parameters to be cube parameters where necessary + + + Fixed problem where the program through an error when it tried to propagate + the pixel type from the input file. + + + Added the bandbin group to the cube labels. + + + Fixed a bug with switched samples and lines + + + Moved into Photometry and Radiometry category + + + Modified to use ProcessByBrick instead of ProcessByLine to make faster + + + Documentation fixes + + + Removed references to CubeInfo + + + Added new parameters: PIXELRESOLUTION, LINERESOLUTION, + SAMPLERESOLUTION, DETECTORRESOLUTION, NORTHAZIMUTH, + SUNAZIMUTH, SPACECRAFTAZIMUTH, OFFNADIRANGLE + + + Fixed a bug that occurred when processing band-dependant cubes + + + Added the propagation of the input cube labels, objects, blobs, etc..., so + the pedigree of the input source is retained. + + + Set the defaults for PIXELRESOLUTION, LINERESOLUTION, + SAMPLERESOLUTION, DETECTORRESOLUTION, NORTHAZIMUTH, + SUNAZIMUTH, SPACECRAFTAZIMUTH, OFFNADIRANGLE to FALSE + + + + + Radiometric and Photometric Correction + Cameras + + + + + + cube + input + + Input cube + + + Use this parameter to select the input filename. + + + *.cub + + + + + cube + real + output + + Output cube + + + This file will contain the phase and/or emission and/or incidence + angles. + + + + + + + boolean + TRUE + Create a phase angle band. + + If this parameter is true then a phase angle band will be created + + + + boolean + TRUE + Create an emission angle band. + + If this parameter is true then an emission angle band will be created + + + + boolean + TRUE + Create an incidience angle band. + + If this parameter is true then an incidence angle band will be created + + + + boolean + TRUE + Create a latitude band. + + If this parameter is true then a latitude band will be created + + + + boolean + TRUE + Create a longitude band. + + If this parameter is true then a longitude band will be created + + + + boolean + FALSE + Create a pixel resolution band. + + If this parameter is true then a pixel resolution band will be created + + + + boolean + FALSE + Create a line resolution band. + + If this parameter is true then a line resolution band will be created + + + + boolean + FALSE + Create a sample resolution band. + + If this parameter is true then a sample resolution band will be + created + + + + boolean + FALSE + Create a detector resolution band. + + If this parameter is true then a detector resolution band will be + created + + + + boolean + FALSE + Create a north azimuth band. + + If this parameter is true then a north azimuth band will be created + + + + boolean + FALSE + Create a sun azimuth band. + + If this parameter is true then a sun azimuth band will be + created + + + + boolean + FALSE + Create a spacecraft azimuth band. + + If this parameter is true then a spacecraft azimuth band will be + created + + + + boolean + FALSE + Create a offNadir angle band. + + If this parameter is true then a offNadir angle band will be created + + + + + diff --git a/isis/src/base/apps/phocube/tsts/Makefile b/isis/src/base/apps/phocube/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/phocube/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/phocube/tsts/default/Makefile b/isis/src/base/apps/phocube/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e362d68a9dfe793327febd0224f87b0acf203185 --- /dev/null +++ b/isis/src/base/apps/phocube/tsts/default/Makefile @@ -0,0 +1,23 @@ +APPNAME = phocube + +# 1.52587890625e-05 +phocubeTruth.cub.TOLERANCE = .0000153 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.cub \ + to=$(OUTPUT)/phocubeTruth.cub \ + phase=true \ + emission=true \ + incidence=true \ + latitude=true \ + longitude=true \ + pixelresolution=true \ + lineresolution=true \ + sampleresolution=true \ + detectorresolution=true \ + northazimuth=true \ + sunazimuth=true \ + spacecraftazimuth=true \ + offnadirangle=true > /dev/null; diff --git a/isis/src/base/apps/phohillier/Hillier.cpp b/isis/src/base/apps/phohillier/Hillier.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b38cc6fbcee0d2b5cfac4eaa4cdc27f3cc0d2fa7 --- /dev/null +++ b/isis/src/base/apps/phohillier/Hillier.cpp @@ -0,0 +1,366 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/02/25 18:39:05 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include +#include + + +#include "Camera.h" +#include "Hillier.h" +#include "DbProfile.h" +#include "PvlObject.h" +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" + +using namespace std; + +namespace Isis { + + /** + * @brief Construct from PVL and Cube file + * + * @author Kris Becker - 2/21/2010 + * + * @param pvl Photometric parameter files + * @param cube Input cube file + */ + Hillier::Hillier (PvlObject &pvl, Cube &cube) { + _camera = cube.Camera(); + init(pvl, cube); + } + /** + * @brief Compute photometric DN at given line/sample/band + * + * This routine applies the photometric angles to the equation + * and returns the calibration coefficient at the given cube + * location. + * + * The return parameter is the photometric standard/photometric + * correction coefficient at the given pixel location. + * + * @author Kris Becker - 2/21/2010 + * + * @param line Line of cube image to compute photometry + * @param sample Sample of cube image to compute photometry + * @param band Band of cube image to compute photometry + * + * @return double Photometric correction at cube loation + */ + double Hillier::Compute(const double &line, const double &sample, int band) { + + // Update band if necessary + if (_camera->Band() != band) { + _camera->SetBand(band); + } + if (!_camera->SetImage(sample, line)) return (Null); + + double i = _camera->IncidenceAngle(); + double e = _camera->EmissionAngle(); + double g = _camera->PhaseAngle(); + if (i >= 90.0) return (Null); + + return(photometry(i, e, g, band)); + } + + /** + * @brief Method to get photometric property given angles + * + * This routine computes the photometric property at the given + * cube location after ensuring a proper parameter container is + * found for the specified band. + * + * @author Kris Becker - 2/21/2010 + * + * @param i Incidence angle at cube location + * @param e Emission angle at cube location + * @param g Phase angle at cube location + * @param band Band number in cube (actually is band index) for + * lookup purposes + * + * @return double Returns photometric correction using + * parameters + */ + double Hillier::photometry(double i, double e, double g, int band) const { + // Test for valid band + if ((band <= 0) || (band > (int) _bandpho.size())) { + std::string mess = "Provided band " + iString(band) + " out of range."; + throw iException::Message(iException::Programmer, mess, _FILEINFO_); + } + double ph = photometry(_bandpho[band-1], i, e, g); + return (_bandpho[band-1].phoStd/ph); + } + + /** + * @brief Performs actual photometric correction calculations + * + * This routine computes photometric correction using parameters + * for the Hillier-Buratti-Hill equation. + * + * @author Kris Becker - 2/21/2010 + * + * @param parms Container of band-specific Hillier parameters + * @param i Incidence angle in degrees + * @param e Emission angle in degrees + * @param g Phase angle in degrees + * + * @return double Photometric correction parameter + */ + double Hillier::photometry(const Parameters &parms, double i, double e, + double g) const { + + // Ensure problematic values are adjusted + if (i == 0.0) i = 10.E-12; + if (e == 0.0) e = 10.E-12; + + // Convert to radians + i *= rpd_c(); + e *= rpd_c(); + g *= parms.phaUnit; // Apply unit normalizer + + // Compute Lommel-Seeliger components + double mu = cos(e); + double mu0 = cos(i); + + double alpha = g; + double alpha2 = g * g; + + // Simple Hillier photometric polynomial equation with exponential opposition + // surge term. + double rcal = (mu0/(mu+mu0)) * (parms.b0 * exp(-parms.b1*alpha) + parms.a0 + + (parms.a1 * alpha) + (parms.a2 * alpha2) + + (parms.a3 * alpha * alpha2) + + (parms.a4 * alpha2 * alpha2)); + return (rcal); + } + + + /** + * @brief Return parameters used for all bands + * + * Method creates keyword vectors of band specific parameters + * used in the photometric correction. + * + * @author Kris Becker - 2/22/2010 + * + * @param pvl Output PVL container write keywords + */ + void Hillier::Report(PvlContainer &pvl) { + pvl += PvlKeyword("Algorithm", "Hillier"); + pvl += PvlKeyword("IncRef", _iRef, "degrees"); + pvl += PvlKeyword("EmaRef", _eRef, "degrees"); + pvl += PvlKeyword("PhaRef", _gRef, "degrees"); + PvlKeyword units("HillierUnits"); + PvlKeyword phostd("PhotometricStandard"); + PvlKeyword bbc("BandBinCenter"); + PvlKeyword bbct("BandBinCenterTolerance"); + PvlKeyword bbn("BandNumber"); + PvlKeyword b0("B0"); + PvlKeyword b1("B1"); + PvlKeyword a0("A0"); + PvlKeyword a1("A1"); + PvlKeyword a2("A2"); + PvlKeyword a3("A3"); + PvlKeyword a4("A4"); + for (unsigned int i = 0 ; i < _bandpho.size() ; i++) { + Parameters &p = _bandpho[i]; + units.AddValue(p.units); + phostd.AddValue(p.phoStd); + bbc.AddValue(p.wavelength); + bbct.AddValue(p.tolerance); + bbn.AddValue(p.band); + b0.AddValue(p.b0); + b1.AddValue(p.b1); + a0.AddValue(p.a0); + a1.AddValue(p.a1); + a2.AddValue(p.a2); + a3.AddValue(p.a3); + a4.AddValue(p.a4); + } + pvl += units; + pvl += phostd; + pvl += bbc; + pvl += bbct; + pvl += bbn; + pvl += b0; + pvl += b1; + pvl += a0; + pvl += a1; + pvl += a2; + pvl += a3; + pvl += a4; + return; + } + + + /** + * @brief Determine Hillier parameters given a wavelength + * + * This method determines the set of Hillier parameters to use + * for a given wavelength. It iterates through all band + * profiles as read from the PVL file and computes the + * difference between the "wavelength" parameter and the + * BandBinCenter keyword. The absolute value of this value is + * checked against the BandBinCenterTolerance paramter and if it + * is less than or equal to it, a Parameter container is + * returned. + * + * @author Kris Becker - 2/22/2010 + * + * @param wavelength Wavelength used to find parameter set + * + * @return Hillier::Parameters Container of valid values. If + * not found, a value of iProfile = -1 is returned. + */ + Hillier::Parameters Hillier::findParameters(const double wavelength) const { + for (unsigned int i = 0 ; i < _profiles.size() ; i++) { + const DbProfile &p = _profiles[i]; + if (p.exists("BandBinCenter")) { + double p_center = ConfKey(p, "BandBinCenter", Null); + double tolerance = ConfKey(p, "BandBinCenterTolerance", 1.0E-6); + if (fabs(wavelength-p_center) <= fabs(tolerance)) { + Parameters pars = extract(p); + pars.iProfile = i; + pars.wavelength = wavelength; + pars.tolerance = tolerance; + return (pars); + } + } + } + + // Not found if we reach here + return (Parameters()); + } + + /** + * @brief Extracts necessary Hillier parameters from profile + * + * Given a profile read from the input PVL file, this method + * extracts needed parameters (from Keywords) in the PVL profile + * and creates a container of the converted values. + * + * @author Kris Becker - 2/22/2010 + * + * @param p Profile to extract/convert + * + * @return Hillier::Parameters Container of extracted values + */ + Hillier::Parameters Hillier::extract(const DbProfile &p) const { + Parameters pars; + pars.b0 = ConfKey(p, "B0", 0.0); + pars.b1 = ConfKey(p, "B1", 0.0); + pars.a0 = ConfKey(p, "A0", 0.0); + pars.a1 = ConfKey(p, "A1", 0.0); + pars.a2 = ConfKey(p, "A2", 0.0); + pars.a3 = ConfKey(p, "A3", 0.0); + pars.a4 = ConfKey(p, "A4", 0.0); + pars.wavelength = ConfKey(p, "BandBinCenter", Null); + pars.tolerance = ConfKey(p, "BandBinCenterTolerance", Null); + // Determine equation units - defaults to Radians + pars.units = ConfKey(p,"HillierUnits", iString("Radians")); + pars.phaUnit = (iString::Equal(pars.units, "Degrees")) ? 1.0 : rpd_c(); + return (pars); + } + + /** + * @brief Initialize class from input PVL and Cube files + * + * This method is typically called at class instantiation time, + * but is reentrant. It reads the parameter PVL file and + * extracts Photometric model and Normalization models from it. + * The cube is needed to match all potential profiles for each + * band. + * + * @param pvl Input PVL parameter files + * @param cube Input cube file to correct + * + * @author Kris Becker - 2/22/2010 + * @history 2010-02-25 Kris Becker Added check for valid incidence angle + */ + void Hillier::init(PvlObject &pvl, Cube &cube) { + + // Make it reentrant + _profiles.clear(); + _bandpho.clear(); + + // Interate over all Photometric groups + _normProf = DbProfile(pvl.FindObject("NormalizationModel").FindGroup("Algorithm",Pvl::Traverse)); + _iRef = ConfKey(_normProf, "IncRef", 30.0); + _eRef = ConfKey(_normProf, "EmaRef", 0.0); + _gRef = ConfKey(_normProf, "PhaRef", _iRef); + + // Check for valid incidence angle + if (_iRef > fabs(90.0)) { + ostringstream mess; + mess << "Invalid incidence angle (" << _iRef + << " >= 90.0) provided in PVL config file " << pvl.Filename(); + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + + PvlObject &phoObj = pvl.FindObject("PhotometricModel"); + DbProfile phoProf = DbProfile(phoObj); + PvlObject::PvlGroupIterator algo = phoObj.BeginGroup(); + while (algo != phoObj.EndGroup()) { + if (iString::Equal(algo->Name(), "Algorithm")) { + _profiles.push_back(DbProfile(phoProf,DbProfile(*algo))); + } + ++algo; + } + + Pvl *label = cube.Label(); + PvlKeyword center = label->FindGroup("BandBin",Pvl::Traverse)["Center"]; + string errs(""); + for (int i = 0; i < cube.Bands() ; i++) { + Parameters parms = findParameters(center[i]); + if (parms.IsValid()) { + parms.band = i+1; + _camera->SetBand(i+1); + parms.phoStd = photometry(parms, _iRef, _eRef, _gRef); + _bandpho.push_back(parms); + } + else { // Appropriate photometric parameters not found + ostringstream mess; + mess << "Band " << i+1 << " with wavelength Center = " << center[i] + << " does not have PhotometricModel Algorithm group/profile"; + iException &e = iException::Message(iException::User, mess.str(), _FILEINFO_); + errs += e.Errors() + "\n"; + e.Clear(); + } + } + + // Check for errors and throw them all at the same time + if (!errs.empty()) { + errs += " --> Errors in the input PVL file \"" + pvl.Filename() + "\""; + throw iException::Message(iException::User, errs, _FILEINFO_); + } + + return; + } + +} // namespace Isis + + diff --git a/isis/src/base/apps/phohillier/Hillier.h b/isis/src/base/apps/phohillier/Hillier.h new file mode 100644 index 0000000000000000000000000000000000000000..9b70a70836babddece60a18732bb8516e6e10773 --- /dev/null +++ b/isis/src/base/apps/phohillier/Hillier.h @@ -0,0 +1,149 @@ +#if !defined(Hillier_h) +#define Hillier_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/02/24 09:54:18 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "iString.h" +#include "Camera.h" +#include "DbProfile.h" +#include "SpecialPixel.h" + +namespace Isis { + +/** Implement templatized MIN fumnction */ + template inline T MIN(const T &A, const T &B) { + if ( A < B ) { return (A); } + else { return (B); } + } + + /** Implement templatized MAX function */ + template inline T MAX(const T &A, const T &B) { + if ( A > B ) { return (A); } + else { return (B); } + } + + + class PvlObject; + class Camera; + + /** + * @brief An implementation of the Hillier photometric function + * + * This class implements the Hillier-Buratti-Hill photometric + * equation as outline in thier paper "Multispectral Photometry + * of the Moon and Absolute Calibration of the Clementine UV/VIS + * Camera", published in Icaris v141, pg. 205-255 (1999). + * + * @author 2010-02-15 Kris Becker + * @history 2010-02-24 Kris Becker - Changed include paths by adding "naif" to NAIF + * includes + * + */ + class Hillier { + public: + /** + * @brief Create Hilier photometric object + * + */ + Hillier (PvlObject &pvl, Cube &cube); + + //! Destructor + virtual ~Hillier() {}; + + void setCamera(Camera *cam) { _camera = cam; } + double Compute(const double &line, const double &sample, int band = 1); + double photometry(double i, double e, double g, int band = 1) const; + void Report(PvlContainer &pvl); + + private: + /** + * @brief Container for band photometric correction parameters + * + * @author Kris Becker - 2/21/2010 + */ + struct Parameters { + Parameters() : b0(0.0), b1(0.0), a0(0.0), a1(0.0), a2(0.0), a3(0.0), + a4(0.0), wavelength(0.0), tolerance(0.0), + units("Degrees"), phaUnit(1.0), band(0), phoStd(0.0), + iProfile(-1) { } + ~Parameters() { } + bool IsValid() const { return (iProfile != -1); } + double b0, b1, a0, a1, a2, a3, a4; // _profiles; + std::vector _bandpho; + Camera *_camera; + double _iRef; //!< Incidence refernce angle + double _eRef; // Emission reference angle + double _gRef; // Phase reference angle + + double photometry(const Parameters &parms, double i, double e, + double g) const; + + Parameters findParameters(const double wavelength) const; + Parameters extract(const DbProfile &profile) const; + void init(PvlObject &pvl, Cube &cube); + + /** + * @brief Helper method to initialize parameters + * + * This method will check the existance of a keyword and extract the value + * if it exists to the passed parameter (type). If it doesn't exist, the + * default values is returned. + * + * @param T Templated variable type + * @param conf Parameter profile container + * @param keyname Name of keyword to get a value from + * @param defval Default value it keyword/value doesn't exist + * @param index Optional index of the value for keyword arrays + * + * @return T Return type + */ + template + T ConfKey(const DbProfile &conf, const std::string &keyname, + const T &defval,int index = 0) const { + if (!conf.exists(keyname)) { return (defval); } + if (conf.count(keyname) < index) { return (defval); } + iString iValue(conf.value(keyname, index)); + T value = iValue; // This makes it work with a string? + return (value); + } + }; + +}; + +#endif + diff --git a/isis/src/base/apps/phohillier/Makefile b/isis/src/base/apps/phohillier/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/phohillier/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/phohillier/phohillier.cpp b/isis/src/base/apps/phohillier/phohillier.cpp new file mode 100644 index 0000000000000000000000000000000000000000..500d41abf3177cde70204cbabceba65e67dcbf95 --- /dev/null +++ b/isis/src/base/apps/phohillier/phohillier.cpp @@ -0,0 +1,75 @@ +// $Id: phohillier.cpp,v 1.1 2010/02/24 04:05:19 kbecker Exp $ +#include "Isis.h" + +#include +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "Hillier.h" +#include "Pvl.h" +#include "Cube.h" + +#include "PvlGroup.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +// Global variables +Hillier *pho; + +void hillier (Buffer &in, Buffer &out); + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Set up the input cube and get camera information + Cube *icube = p.SetInputCube("FROM"); + + // Create the output cube + Cube *ocube = p.SetOutputCube("TO"); + + // Set up the user interface + UserInterface &ui = Application::GetUserInterface(); + // Get the name of the parameter file + Pvl par(ui.GetFilename("PHOPAR")); + auto_ptr photom = auto_ptr (new Hillier(par, *icube)); + pho = photom.get(); + + // Start the processing + p.StartProcess(hillier); + + PvlGroup photo("Photometry"); + pho->Report(photo); + ocube->PutGroup(photo); + Application::Log(photo); + p.EndProcess(); +} + +/** + * @brief Apply Hillier photometric correction + * + * Short function dispatched for each line to apply the Hillier photometrc + * correction function. + * + * @author kbecker (2/20/2010) + * + * @param in Buffer containing input data + * @param out Buffer of photometrically corrected data + */ +void hillier(Buffer &in, Buffer &out) { + + for (int i=0; iCompute(in.Line(i), in.Sample(i), in.Band(i)); + out[i] = (IsSpecial(ph) ? Null : in[i] * ph); + } + } + return; +} + diff --git a/isis/src/base/apps/phohillier/phohillier.xml b/isis/src/base/apps/phohillier/phohillier.xml new file mode 100644 index 0000000000000000000000000000000000000000..54431ff9cb0181943dcb4747fdaf7da4c93dd08f --- /dev/null +++ b/isis/src/base/apps/phohillier/phohillier.xml @@ -0,0 +1,245 @@ + + + + + + Apply Hillier photometric correction to multiband cubes + + + +

    + phohillier implements a photometric correction based upon a paper + titled "Multispectral Photometry of the Moon and Absolute Calibration of + Clementine UV/Vis Camera" by Hillier, Burratti and Hill, published in Icarus + 141, 205-225 (1999). The equation for I/F photometric correction from + this source is: +

    +
    +      I/F = (mu0/(mu+mu0)*F(phase)
    +
    +              where:
    +                  mu0 = cos(incidence)
    +                  mu   = cos(emission)
    +                  F(phase) = b0*e(-b1*phase) + a0 + a1*phase + a2*phase^2 + 
    +                                      a3*phase^3 + a4*phase^4
    +    
    +

    + The equation described there utilizes the Lommel-Seeliger function to + account for scattering dependance on incidence and emission angles. Lunar + Reflectance approximately follows this function and this is the dependence + expected for signly scattered light. Thus is should be a good + approximation for dark objects such as the Moon where singly scattered + light dominates reflectance. The phase function is a fourth order + polynomial with an exponential term to better account for opposition + surge. +

    +

    + This application provides features that allow multiband cubes to be + photometrically corrected with a properly formatted PVL input file much + like that of ISIS program photomet. This application restricts + much of the options available to the more sophiscated photomet + application. Below is an example input parameter file for this + application: +

    +
    +Object = NormalizationModel 
    +  Group = Algorithm 
    +    Name = Albedo 
    +    PhotoModel = Hillier
    +    Incref=30.0
    +    Emaref=0.0
    +    Pharef=30.0
    +  EndGroup 
    +EndObject 
    +
    +Object = PhotometricModel 
    +  HillierUnits = Degrees
    +  Group = Algorithm
    +    Name = Hillier
    +    FilterName = "Filter1"
    +    BandBinCenter = 100.1
    +    B0 = 0.0432753
    +    B1 = 0.0644091
    +    A0 = -0.0207532
    +    A1 = 0.00165219
    +    A2 = -3.94007e-05
    +    A3  = 4.19325e-07
    +    A4 = -1.69163e-09
    +  EndGroup
    +
    +  Group = Algorithm
    +    Name = Hillier
    +    FilterName = "Filter2"
    +    BandBinCenter = 112.5
    +    B0 = 0.0332283
    +    B1 = 0.00667452
    +    A0 = -0.0258405
    +    A1 = -9.04379e-05
    +    A2 = 7.59709e-06
    +    A3 = -1.06395e-07
    +    A4 = 5.18268e-10
    +  EndGroup
    +
    +  Group = Algorithm
    +    Name = Hillier
    +    FilterName = "Filter8"
    +    BandBinCenter = 545.3
    +    BandBinCenterTolerance = 1.0E-2
    +    B0 = 0.0347020
    +    B1 = 0.0211712
    +    A0 = -0.0244440
    +    A1 = 0.000388924
    +    A2 = 4.72860e-07
    +    A3 = -5.00731e-08
    +    A4 = 3.07309e-10
    +  EndGroup
    +EndObject
    +  
    +

    + The NormalizationModel object will (currently) always apply an Albedo + normalization. The value of the Name parameter is ignored here. Also + ignored is the value if PhotoModel as it is always "Hillier". The Incref, + Emaref and Pharef are the incidence, emission and phase angles to be used + as the photometric standard. It will be used to normalize the photometric + correction parameter to these angles. The equation used to create the + photometrically corrected I/F dn is: +

    +
    +          odn = idn * (phostd  / ph)
    +         
    +              where phostd is the Hillier photometry at the given Incref, 
    +                                     Emaref and Pharef angles
    +                         ph        is the photometric correction for the 
    +                                     incidence, emission and phase at each pixel
    +      
    +

    + In the above example, parameters B0-B1 and A0-A4 are the parameters for + the Hillier equation. Additional parameters area needed in order to apply + a specific set of parameters in an Algorithm group to selected bands. The + set of parameters, B0-B1, A0-A4, within an Algorithm group are applied to + a band if (ABS(Center-BandBinCenter) <= ABS(BandBinCenterTolerance)). + The "Center" parameter in the above equality comes from the Center keyword + in the BandBin group of the input cube file specified in the FROM + parameter. This keyword must exist in the input cube or an error is + generated and the program aborts. BandBinCenter and + BandBinCenterTolerance are contained in each Algorithm group. Only + BandBinCenter is required. If BandBinCenterTolerance is not present in an + Algorithm group a value of 1.0E-6 is used. All input bands in the FROM + file must be matched to at least one of the Algorithm parameters otherwise + an error is generated and the application is aborted. +

    +

    + The parameter HillierUnits is provided to specify if the phase angle is in + units of degrees or radians. It does not have to exist in any group or + even in the top Object section. If it does not exist, "Radians" is the + default. +

    +

    + An additional feature of the PVL structure is that any keyword that exists + in the Object section of the PhotometricModel Object is propagated to each + Algorithm group when it is read in unless the keyword already exists in + the Algorithm group. If a keyword exists in both the PhotometricModel + object and an Algorithm group, the keyword in the Algorithm group has + precedence. +

    +

    + Below is an example of a small PVL file that will process all bands that + have a center wavelength of 100.0 to 900.0 (units do not matter as long as + the PVL ALgorithm groups contain the same units as the BandBin Center + keyword in the input cube file). The units of phase is provided in + Radians for this particular example and is overridden from the keyword in + the PhotometricModel object: +

    +
    +Object = NormalizationModel 
    +  Group = Algorithm 
    +    Name = Albedo 
    +    PhotoModel = Hillier
    +    Incref=30.0
    +    Emaref=0.0
    +    Pharef=30.0
    +  EndGroup 
    +EndObject 
    +      
    +Object = PhotometricModel 
    +  HillierUnits = Degrees
    +  Group = Algorithm
    +    Name = Hillier
    +    FilterName = "AllFilters"
    +    BandBinCenter = 500.0
    +    BandBinCenterTolerance = 400.0
    +    HillierUnits = Radians
    +    B0 = 0.0347020
    +    B1 = 0.0211712
    +    A0 = -0.0244440
    +    A1 = 0.000388924
    +    A2 = 4.72860e-07
    +    A3 = -5.00731e-08
    +    A4 = 3.07309e-10
    +  EndGroup
    +EndObject      
    +    
    +

    + Additional consequences of the photometric correction processing is any + incidence angle greater than i90 degrees is set to the ISIS special Null + pixel value. And, of course, any ISIS special pixel encountered on input + is propagated to the output TO file without modification. +

    +
    + + + + Original version. + + + + + Radiometric and Photometric Correction + Cameras + + + + + + cube + input + + Input cube + + + Use this parameter to select the input filename. + + + *.cub + + + + + cube + real + output + + Output cube + + + This file will contain the photometrically corrected image data after + being corrected by with Hillier algorithm. + + + + + filename + input + + Pvl file + + + This file will contain the parameters B0-B1, A0-A4 to use when + applying the Hellier photometric correction. See the main program + documentation for a full description. + + *.pvl + + + +
    diff --git a/isis/src/base/apps/phohillier/tsts/Makefile b/isis/src/base/apps/phohillier/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/phohillier/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/phohillier/tsts/projectedUV/Makefile b/isis/src/base/apps/phohillier/tsts/projectedUV/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1a52606260f4d04b06e3cb5a2308804a71feea6f --- /dev/null +++ b/isis/src/base/apps/phohillier/tsts/projectedUV/Makefile @@ -0,0 +1,8 @@ +APPNAME = phohillier + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/projectedUV.cub \ + to=$(OUTPUT)/projectedUV.pho.cub \ + phopar=$(INPUT)/hillier.pvl > /dev/null; diff --git a/isis/src/base/apps/photemplate/Makefile b/isis/src/base/apps/photemplate/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/photemplate/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/photemplate/photemplate.cpp b/isis/src/base/apps/photemplate/photemplate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f752a9b69f18173880d95eb658cbdbbde08e8232 --- /dev/null +++ b/isis/src/base/apps/photemplate/photemplate.cpp @@ -0,0 +1,492 @@ + +#include "Isis.h" +#include "PvlGroup.h" +#include "UserInterface.h" +#include "iString.h" + +using namespace std; +using namespace Isis; + + +//functions in the code +void addPhoModel(Pvl &pvl); +void addAtmosModel(Pvl &pvl); +void addNormalModel(Pvl &pvl); + +void IsisMain() { + //The PVL to be written out + Pvl p; + + //Add the different models to the PVL + addPhoModel(p); + addAtmosModel(p); + addNormalModel(p); + + // Get the output file name from the GUI and write the pvl + // to the file. If no extension is given, '.pvl' will be used. + UserInterface &ui = Application::GetUserInterface(); + Filename out = ui.GetFilename("PVL"); + string output = ui.GetFilename("PVL"); + if (out.Extension() == "") { + output += ".pvl"; + } + + p.Write(output); +} + +//Function to add photometric model to the PVL +void addPhoModel(Pvl &pvl) { + //Create an object for the photometric model + PvlObject phoModel("PhotometricModel"); + //Create an algorithm group + PvlGroup phoAlgo("Algorithm"); + + UserInterface &ui = Application::GetUserInterface(); + + //Get the photometric model and any parameters specific to that + //model and write it to the algorithm group + + //Hapke Henyey Greenstein Photometric Model + if (ui.GetString("PHOTOMETRIC") == "HAPKEHEN") { + phoAlgo.AddKeyword(PvlKeyword("Name", "Hapkehen")); + + double theta = ui.GetDouble("THETA"); + phoAlgo.AddKeyword(PvlKeyword("Theta", theta)); + + double wh = ui.GetDouble("WH"); + phoAlgo.AddKeyword(PvlKeyword("Wh", wh)); + + double hg1 = ui.GetDouble("HG1"); + phoAlgo.AddKeyword(PvlKeyword("Hg1", hg1)); + + double hg2 = ui.GetDouble("HG2"); + phoAlgo.AddKeyword(PvlKeyword("Hg2", hg2)); + + double hh = ui.GetDouble("HH"); + phoAlgo.AddKeyword(PvlKeyword("Hh", hh)); + + double b0 = ui.GetDouble("B0"); + phoAlgo.AddKeyword(PvlKeyword("B0", b0)); + } + //Lunar Lambert Photometric Model + else if(ui.GetString("PHOTOMETRIC") == "LUNARLAMBERT") { + phoAlgo.AddKeyword(PvlKeyword("Name", "LunarLambert")); + + double l = ui.GetDouble("L"); + phoAlgo.AddKeyword(PvlKeyword("L", l)); + } + //Minnaert Photometric Model + else if(ui.GetString("PHOTOMETRIC") == "MINNAERT") { + phoAlgo.AddKeyword(PvlKeyword("Name", "Minnaert")); + + double k = ui.GetDouble("K"); + phoAlgo.AddKeyword(PvlKeyword("K", k)); + } + //Lambert Photometric Model + else if(ui.GetString("PHOTOMETRIC") == "LAMBERT") { + phoAlgo.AddKeyword(PvlKeyword("Name", "Lambert")); + } + //Lommel Seeliger Photometric Model + else if(ui.GetString("PHOTOMETRIC") == "LOMMELSEELIGER") { + phoAlgo.AddKeyword(PvlKeyword("Name", "LommelSeeliger")); + } + //Lunar Lambert McEwen Photometric Model + else if(ui.GetString("PHOTOMETRIC") == "LUNARLAMBERTMCEWEN") { + phoAlgo.AddKeyword(PvlKeyword("Name", "LunarLambertMcEwen")); + } + + //Add the algorithm group to the photometric model object and add it to the PVL + phoModel.AddGroup(phoAlgo); + pvl.AddObject(phoModel); +} + +//Function to add atmospheric model to the PVL +void addAtmosModel(Pvl &pvl) { + UserInterface &ui = Application::GetUserInterface(); + + //If the normalization model is one with an atmospheric model + //then create an atmospheric model and add it to the PVL. + if((ui.GetString("NORMALIZATION") == "ATMALBEDO" | + ui.GetString("NORMALIZATION") == "ATMSHADE" || + ui.GetString("NORMALIZATION") == "ATMTOPO")) { + + //Create an object for the atmospheric model + PvlObject atmosModel("AtmosphericModel"); + //Create an algorithm group + PvlGroup atmosAlgo("Algorithm"); + + //Get the atmospheric model and any parameters specific to that + //model and write it to the algorithm group + + //Anisotropic 1 Atmospheric Model + if (ui.GetString("ATMOSPHERIC") == "ANISOTROPIC1") { + atmosAlgo.AddKeyword(PvlKeyword("Name", "Anisotropic1")); + + bool nulneg = ui.GetBoolean("NULNEG"); + + //if NULNEG is checked add it to the group, otherwise the + //default is to leave it out + if(nulneg) { + atmosAlgo.AddKeyword(PvlKeyword("Nulneg", "YES")); + } + + double tau = ui.GetDouble("TAU"); + atmosAlgo.AddKeyword(PvlKeyword("Tau", tau)); + + double tauref = ui.GetDouble("TAUREF"); + atmosAlgo.AddKeyword(PvlKeyword("Tauref", tauref)); + + double wha = ui.GetDouble("WHA"); + atmosAlgo.AddKeyword(PvlKeyword("Wha", wha)); + + //if WHAREF was entered add it to the group, otherwise the + //default is to leave it out + if(ui.WasEntered("WHAREF")) { + double wharef = ui.GetDouble("WHAREF"); + atmosAlgo.AddKeyword(PvlKeyword("Wharef", wharef)); + } + + double bha = ui.GetDouble("BHA"); + atmosAlgo.AddKeyword(PvlKeyword("Bha", bha)); + + //if BHAREF was entered add it to the group, otherwise the + //default is to leave it out + if(ui.WasEntered("BHAREF")) { + double bharef = ui.GetDouble("BHAREF"); + atmosAlgo.AddKeyword(PvlKeyword("Bharef", bharef)); + } + + double hnorm = ui.GetDouble("HNORM"); + atmosAlgo.AddKeyword(PvlKeyword("Hnorm", hnorm)); + } + //Anisotropic 2 Atmospheric Model + else if(ui.GetString("ATMOSPHERIC") == "ANISOTROPIC2") { + atmosAlgo.AddKeyword(PvlKeyword("Name", "Anisotropic2")); + + bool nulneg = ui.GetBoolean("NULNEG"); + + //if NULNEG is checked add it to the group, otherwise the + //default is to leave it out + if(nulneg) { + atmosAlgo.AddKeyword(PvlKeyword("Nulneg", "Yes")); + } + + double tau = ui.GetDouble("TAU"); + atmosAlgo.AddKeyword(PvlKeyword("Tau", tau)); + + double tauref = ui.GetDouble("TAUREF"); + atmosAlgo.AddKeyword(PvlKeyword("Tauref", tauref)); + + double wha = ui.GetDouble("WHA"); + atmosAlgo.AddKeyword(PvlKeyword("Wha", wha)); + + //if WHAREF was entered add it to the group, otherwise the + //default is to leave it out + if(ui.WasEntered("WHAREF")) { + double wharef = ui.GetDouble("WHAREF"); + atmosAlgo.AddKeyword(PvlKeyword("Wharef", wharef)); + } + + double bha = ui.GetDouble("BHA"); + atmosAlgo.AddKeyword(PvlKeyword("Bha", bha)); + + //if BHAREF was entered add it to the group, otherwise the + //default is to leave it out + if(ui.WasEntered("BHAREF")) { + double bharef = ui.GetDouble("BHAREF"); + atmosAlgo.AddKeyword(PvlKeyword("Bharef", bharef)); + } + + double hnorm = ui.GetDouble("HNORM"); + atmosAlgo.AddKeyword(PvlKeyword("Hnorm", hnorm)); + } + //Hapke 1 Atmospheric Model + else if(ui.GetString("ATMOSPHERIC") == "HAPKEATM1") { + atmosAlgo.AddKeyword(PvlKeyword("Name", "HapkeAtm1")); + + bool nulneg = ui.GetBoolean("NULNEG"); + + //if NULNEG is checked add it to the group, otherwise the + //default is to leave it out + if(nulneg) { + atmosAlgo.AddKeyword(PvlKeyword("Nulneg", "Yes")); + } + + double tau = ui.GetDouble("TAU"); + atmosAlgo.AddKeyword(PvlKeyword("Tau", tau)); + + double tauref = ui.GetDouble("TAUREF"); + atmosAlgo.AddKeyword(PvlKeyword("Tauref", tauref)); + + double wha = ui.GetDouble("WHA"); + atmosAlgo.AddKeyword(PvlKeyword("Wha", wha)); + + //if WHAREF was entered add it to the group, otherwise the + //default is to leave it out + if(ui.WasEntered("WHAREF")) { + double wharef = ui.GetDouble("WHAREF"); + atmosAlgo.AddKeyword(PvlKeyword("Wharef", wharef)); + } + + double hga = ui.GetDouble("HGA"); + atmosAlgo.AddKeyword(PvlKeyword("Hga", hga)); + + //if HGAREF was entered add it to the group, otherwise the + //default is to leave it out + if(ui.WasEntered("HGAREF")) { + double hgaref = ui.GetDouble("HGAREF"); + atmosAlgo.AddKeyword(PvlKeyword("Hgaref", hgaref)); + } + + double hnorm = ui.GetDouble("HNORM"); + atmosAlgo.AddKeyword(PvlKeyword("Hnorm", hnorm)); + } + //Hapke 2 Atmospheric Model + else if(ui.GetString("ATMOSPHERIC") == "HAPKEATM2") { + atmosAlgo.AddKeyword(PvlKeyword("Name", "HapkeAtm2")); + + bool nulneg = ui.GetBoolean("NULNEG"); + + //if NULNEG is checked add it to the group, otherwise the + //default is to leave it out + if(nulneg) { + atmosAlgo.AddKeyword(PvlKeyword("Nulneg", "Yes")); + } + + double tau = ui.GetDouble("TAU"); + atmosAlgo.AddKeyword(PvlKeyword("Tau", tau)); + + double tauref = ui.GetDouble("TAUREF"); + atmosAlgo.AddKeyword(PvlKeyword("Tauref", tauref)); + + double wha = ui.GetDouble("WHA"); + atmosAlgo.AddKeyword(PvlKeyword("Wha", wha)); + + //if WHAREF was entered add it to the group, otherwise the + //default is to leave it out + if(ui.WasEntered("WHAREF")) { + double wharef = ui.GetDouble("WHAREF"); + atmosAlgo.AddKeyword(PvlKeyword("Wharef", wharef)); + } + + double hga = ui.GetDouble("HGA"); + atmosAlgo.AddKeyword(PvlKeyword("Hga", hga)); + + //if HGAREF was entered add it to the group, otherwise the + //default is to leave it out + if(ui.WasEntered("HGAREF")) { + double hgaref = ui.GetDouble("HGAREF"); + atmosAlgo.AddKeyword(PvlKeyword("Hgaref", hgaref)); + } + + double hnorm = ui.GetDouble("HNORM"); + atmosAlgo.AddKeyword(PvlKeyword("Hnorm", hnorm)); + } + //Isotropic 1 Atmospheric Model + else if(ui.GetString("ATMOSPHERIC") == "ISOTROPIC1") { + atmosAlgo.AddKeyword(PvlKeyword("Name", "Isotropic1")); + + bool nulneg = ui.GetBoolean("NULNEG"); + + //if NULNEG is checked add it to the group, otherwise the + //default is to leave it out + if(nulneg) { + atmosAlgo.AddKeyword(PvlKeyword("Nulneg", "Yes")); + } + + double tau = ui.GetDouble("TAU"); + atmosAlgo.AddKeyword(PvlKeyword("Tau", tau)); + + double tauref = ui.GetDouble("TAUREF"); + atmosAlgo.AddKeyword(PvlKeyword("Tauref", tauref)); + + double wha = ui.GetDouble("WHA"); + atmosAlgo.AddKeyword(PvlKeyword("Wha", wha)); + + //if WHAREF was entered add it to the group, otherwise the + //default is to leave it out + if(ui.WasEntered("WHAREF")) { + double wharef = ui.GetDouble("WHAREF"); + atmosAlgo.AddKeyword(PvlKeyword("Wharef", wharef)); + } + + double hnorm = ui.GetDouble("HNORM"); + atmosAlgo.AddKeyword(PvlKeyword("Hnorm", hnorm)); + } + //Isotropic 2 Atmospheric Model + else if(ui.GetString("ATMOSPHERIC") == "ISOTROPIC2") { + atmosAlgo.AddKeyword(PvlKeyword("Name", "Isotropic2")); + + bool nulneg = ui.GetBoolean("NULNEG"); + + //if NULNEG is checked add it to the group, otherwise the + //default is to leave it out + if(nulneg) { + atmosAlgo.AddKeyword(PvlKeyword("Nulneg", "Yes")); + } + + double tau = ui.GetDouble("TAU"); + atmosAlgo.AddKeyword(PvlKeyword("Tau", tau)); + + double tauref = ui.GetDouble("TAUREF"); + atmosAlgo.AddKeyword(PvlKeyword("Tauref", tauref)); + + double wha = ui.GetDouble("WHA"); + atmosAlgo.AddKeyword(PvlKeyword("Wha", wha)); + + //if WHAREF was entered add it to the group, otherwise the + //default is to leave it out + if(ui.WasEntered("WHAREF")) { + double wharef = ui.GetDouble("WHAREF"); + atmosAlgo.AddKeyword(PvlKeyword("Wharef", wharef)); + } + + double hnorm = ui.GetDouble("HNORM"); + atmosAlgo.AddKeyword(PvlKeyword("Hnorm", hnorm)); + } + + //Add the algorithm group to the atmospheric model object and add it to the PVL + atmosModel.AddGroup(atmosAlgo); + pvl.AddObject(atmosModel); + } +} + +//Function to add normalization model to the PVL +void addNormalModel(Pvl &pvl) { + //Create an object for the normalization model + PvlObject normalModel("NormalizationModel"); + //Create an algorithm group + PvlGroup normalAlgo("Algorithm"); + + UserInterface &ui = Application::GetUserInterface(); + + //Get the normalization model and any parameters specific to that + //model and write it to the algorithm group + + //Albedo Normalization Model + if (ui.GetString("NORMALIZATION") == "ALBEDO") { + normalAlgo.AddKeyword(PvlKeyword("Name", "Albedo")); + + double incref = ui.GetDouble("INCREF"); + normalAlgo.AddKeyword(PvlKeyword("Incref", incref)); + + double incmat = ui.GetDouble("INCMAT"); + normalAlgo.AddKeyword(PvlKeyword("Incmat", incmat)); + + double thresh = ui.GetDouble("THRESH"); + normalAlgo.AddKeyword(PvlKeyword("Thresh", thresh)); + + double albedo = ui.GetDouble("ALBEDO"); + normalAlgo.AddKeyword(PvlKeyword("Albedo", albedo)); + } + //Mixed Normalization Model + else if(ui.GetString("NORMALIZATION") == "MIXED") { + normalAlgo.AddKeyword(PvlKeyword("Name", "Mixed")); + + double incref = ui.GetDouble("INCREF"); + normalAlgo.AddKeyword(PvlKeyword("Incref", incref)); + + double incmat = ui.GetDouble("INCMAT"); + normalAlgo.AddKeyword(PvlKeyword("Incmat", incmat)); + + double thresh = ui.GetDouble("THRESH"); + normalAlgo.AddKeyword(PvlKeyword("Thresh", thresh)); + + double albedo = ui.GetDouble("ALBEDO"); + normalAlgo.AddKeyword(PvlKeyword("Albedo", albedo)); + } + //Moon Albedo Normalization Model + else if(ui.GetString("NORMALIZATION") == "MOONALBEDO") { + normalAlgo.AddKeyword(PvlKeyword("Name", "MoonAlbedo")); + + double d = ui.GetDouble("D"); + normalAlgo.AddKeyword(PvlKeyword("D", d)); + + double e = ui.GetDouble("E"); + normalAlgo.AddKeyword(PvlKeyword("E", e)); + + double f = ui.GetDouble("F"); + normalAlgo.AddKeyword(PvlKeyword("F", f)); + + double g2 = ui.GetDouble("G2"); + normalAlgo.AddKeyword(PvlKeyword("G2", g2)); + + double h = ui.GetDouble("H"); + normalAlgo.AddKeyword(PvlKeyword("H", h)); + + double xmul = ui.GetDouble("XMUL"); + normalAlgo.AddKeyword(PvlKeyword("Xmul", xmul)); + + double wl = ui.GetDouble("WL"); + normalAlgo.AddKeyword(PvlKeyword("Wl", wl)); + + double bsh1 = ui.GetDouble("BSH1"); + normalAlgo.AddKeyword(PvlKeyword("Bsh1", bsh1)); + + double xb1 = ui.GetDouble("XB1"); + normalAlgo.AddKeyword(PvlKeyword("Xb1", xb1)); + + double xb2 = ui.GetDouble("XB2"); + normalAlgo.AddKeyword(PvlKeyword("Xb2", xb2)); + } + //Shade Normalization Model + else if(ui.GetString("NORMALIZATION") == "SHADE") { + normalAlgo.AddKeyword(PvlKeyword("Name", "Shade")); + + double incref = ui.GetDouble("INCREF"); + normalAlgo.AddKeyword(PvlKeyword("Incref", incref)); + + double albedo = ui.GetDouble("ALBEDO"); + normalAlgo.AddKeyword(PvlKeyword("Albedo", albedo)); + } + //Topographic Normalization Model + else if(ui.GetString("NORMALIZATION") == "TOPO") { + normalAlgo.AddKeyword(PvlKeyword("Name", "Topo")); + + double incref = ui.GetDouble("INCREF"); + normalAlgo.AddKeyword(PvlKeyword("Incref", incref)); + + double thresh = ui.GetDouble("THRESH"); + normalAlgo.AddKeyword(PvlKeyword("Thresh", thresh)); + + double albedo = ui.GetDouble("ALBEDO"); + normalAlgo.AddKeyword(PvlKeyword("Albedo", albedo)); + } + //Albedo Atmospheric Normalization Model + else if(ui.GetString("NORMALIZATION") == "ATMALBEDO") { + normalAlgo.AddKeyword(PvlKeyword("Name", "AlbedoAtm")); + + double incref = ui.GetDouble("INCREF"); + normalAlgo.AddKeyword(PvlKeyword("Incref", incref)); + } + else if(ui.GetString("NORMALIZATION") == "ATMSHADE") { + normalAlgo.AddKeyword(PvlKeyword("Name", "ShadeAtm")); + + double incref = ui.GetDouble("INCREF"); + normalAlgo.AddKeyword(PvlKeyword("Incref", incref)); + + double albedo = ui.GetDouble("ALBEDO"); + normalAlgo.AddKeyword(PvlKeyword("Albedo", albedo)); + } + //Topographic Atmospheric Normalization Model + else if(ui.GetString("NORMALIZATION") == "ATMTOPO") { + normalAlgo.AddKeyword(PvlKeyword("Name", "TopoAtm")); + + double incref = ui.GetDouble("INCREF"); + normalAlgo.AddKeyword(PvlKeyword("Incref", incref)); + + double albedo = ui.GetDouble("ALBEDO"); + normalAlgo.AddKeyword(PvlKeyword("Albedo", albedo)); + } + //No Normalization + else if(ui.GetString("NORMALIZATION") == "NONORMALIZATION") { + normalAlgo.AddKeyword(PvlKeyword("Name", "NoNormalization")); + } + + //Add the algorithm group to the normalization model object and add it to the PVL + normalModel.AddGroup(normalAlgo); + pvl.AddObject(normalModel); +} + + + diff --git a/isis/src/base/apps/photemplate/photemplate.xml b/isis/src/base/apps/photemplate/photemplate.xml new file mode 100644 index 0000000000000000000000000000000000000000..f891d69e6d0b38a80c7c10b8a4ff979dd9e96a6f --- /dev/null +++ b/isis/src/base/apps/photemplate/photemplate.xml @@ -0,0 +1,1294 @@ + + + + + + Create a PVL template with photometric algorithms and parameters to be used + for photometric correction + + + +
    +     This program creates a PVL template to be used in photomet for photometric 
    +     correction. There are three types of correction that can be applied in
    +     photomet:
    +  
    +      1) Photometric
    +      2) Atmospheric
    +      3) Normalization
    +      
    +     Photometric correction applies to the surface of an image. Atmospheric 
    +     correction applies to the atmosphere through which an image was acquired. 
    +     Normalization is the method in which the photometric and atmospheric 
    +     corrections are applied. 
    +      
    +     The photomet program requires at least that the user specify a photometric 
    +     option and a normalization option. The atmospheric correction is only valid 
    +     if one of the following normalization models is being used: AlbedoAtm,
    +     ShadeAtm, TopoAtm. 
    +
    +     Example output files: 
    +      Example 1:
    +
    +      Object = PhotometricModel 
    +       Group = Algorithm
    +          Name = Lambert
    +        EndGroup
    +      EndObject
    +      Object = NormalizationModel
    +        Group = Algorithm
    +          Name = NoNormalization
    +        EndGroup
    +      EndObject
    +      
    +      Example 2:
    +      
    +      Object = PhotometricModel
    +        Group = Algorithm
    +          Name = Minnaert
    +          K = .5
    +        EndGroup
    +      EndObject
    +      Object = NormalizationModel
    +        Group = Algorithm
    +          Name = Albedo
    +          Incref = 0.0
    +          Incmat = 0.0
    +          Albedo = 1.0
    +          Thresh = 30.0
    +        EndGroup
    +      EndObject
    +      
    +      Example 3:
    +      
    +      Object = PhotometricModel
    +        Group  = Algorithm
    +          Name = Moonpr
    +        EndGroup
    +      EndObject
    +      Object = NormalizationModel
    +        Group = Algorithm
    +          Name = MoonAlbedo
    +          D = 0.0
    +          E = -0.222
    +          F = 0.5
    +          G2 = 0.39
    +          H = 0.062
    +          Bsh1 = 2.31
    +        EndGroup
    +      EndObject
    +      
    +      Example 4:
    +      
    +      Object = PhotometricModel
    +        Group  = Algorithm
    +          Name = HapkeHen
    +          Wh = 0.52
    +          Hh = 0.0
    +          B0 = 0.0
    +          Theta = 30.0
    +          Hg1 = .213
    +          Hg2 = 1.0
    +        EndGroup
    +      EndObject
    +      Object = AtmosphericModel
    +        Group = Algorithm
    +          Name = HapkeAtm2
    +          Hnorm = .003
    +          Tau = 0.28
    +          Tauref = 0.0
    +          Wha = .95
    +          Hga = 0.68
    +        EndGroup
    +      EndObject
    +      Object = NormalizationModel
    +        Group = Algorithm
    +          Name = AlbedoAtm
    +          Incref = 0.0
    +        EndGroup
    +      EndObject
    +
    +    
    +
    + + + + Original version + + + + + + photomet + + + + + Radiometric and Photometric Correction + + + + + + filename + output + + Output PVL containing the photometric algorithms to use + + + Use this parameter to select the output filename. If the file already + exists it will be overwritten. The '.pvl' extension will + automatically be appended to the entered filename if you do not type + in an extension. + + + *.pvl + + + + + + + string + + Photometric model to be used + + + This is the name of the surface photometric function model + + + LAMBERT + + + + + + + + + + + + + + + double + + Macroscopic Roughness Angle + + + 0.0 + + + The Hapke macroscopic roughness component. + + 0.0 + 90.0 + + + + double + + Single Scattering Albedo + + + 0.5 + + + The Hapke single scattering albedo component. + + 0.0 + 1.0 + + + + double + + Hapke Henyey Greenstein Coefficient + + + 0.0 + + + The Hapke Henyey Greenstein coefficient for single particle phase + function. + + -1.0 + 1.0 + + + + double + + Hapke Henyey Greenstein Coefficient + + + 0.0 + + + The Hapke Henyey Greenstein coefficient for single particle phase + function. + + 0.0 + 1.0 + + + + double + + Hapke Opposition Surge + + + 0.0 + + + The Hapke opposition surge component. + + 0.0 + + + + double + + Hapke Opposition Surge + + + 0.0 + + + The Hapke opposition surge component. + + 0.0 + + + + double + + Lunar-Lambert Function Weight + + + 1.0 + + + The Lunar-Lambert function weight. + + + + + double + + Minnaert Function Exponent + + + 1.0 + + + The Minnaert function exponent. + + 0.0 + + + + + + string + + Normalization model to be used + + + This is the name of the normalization model to be performed + + + NONORMALIZATION + + + + + + + + + + + + + + + + + + double + + Reference Incidence Angle + + + 0.0 + + + The reference incidence angle to which the image will be normalized. + + 0.0 + 90.0 + + + + double + + Incidence Angle + + + 0.0 + + + This specifies the incidence angle where albedo normalization + transition to incidence normalization. + + 0.0 + 90.0 + + + + double + + Amplification Threshold + + + 30.0 + + + This sets upper limit on amount of amplification in regions of small + incidence angle. + + + + + double + + Albedo + + + 1.0 + + + The albedo to which the image will be normalized. + + + + + double + + Albedo Normalization Parameter + + + 0.14 + + + The albedo dependent phase function normalization parameter. + + + + + double + + Albedo Normalization Parameter + + + -0.4179 + + + The albedo dependent phase function normalization parameter. + + + + + double + + Albedo Normalization Parameter + + + 0.55 + + + The albedo dependent phase function normalization parameter. + + + + + double + + Albedo Normalization Parameter + + + 0.02 + + + The albedo dependent phase function normalization parameter. + + + + + double + + Albedo Normalization Parameter + + + 0.048 + + + The albedo dependent phase function normalization parameter. + + + + + double + + Radiance to Reflectance/Calibration Factor + + + 1.0 + + + This is used to convert radiance to reflectance or apply a calibration + factor. + + + + + double + + Wavelength + + + 1.0 + + + The wavelength in micrometers of the image being normalized. + + + + + double + + Albedo Normalization Parameter + + + 0.08 + + + The albedo dependent phase function normalization parameter. + + + + + double + + Albedo Normalization Parameter + + + -0.0817 + + + The albedo dependent phase function normalization parameter. + + + + + double + + Albedo Normalization Parameter + + + 0.0081 + + + The albedo dependent phase function normalization parameter. + + + + + + + string + + Atmospheric model to be used + + + This is the name of the atmospheric photometric function model. This + can only be used with the three atmospheric normalization models: + AlbedoAtm, ShadeAtm, and TopoAtm. + + + ANISOTROPIC1 + + + + + + + + + + + + + + + boolean + + Set negative values to NULL + + + FALSE + + + This determines if negative values after removal of atmospheric + effects will be set to NULL. + + + + + double + + Optical Depth of Atmosphere + + + 0.28 + + + The normal optical depth of the atmosphere. + + 0.0 + + + + double + + Reference Value of Tau + + + 0.0 + + + The reference value of Tau to which the image will be normalized. + + 0.0 + + + + double + + Henyey Greenstein Coefficient + + + 0.68 + + + The coefficient of single particle Henyey Greenstein phase + function. + + -1.0 + 1.0 + + + + double + + Reference Value of Hga + + HGA + + The reference value to Hga to which the image will be + normalized. + + -1.0 + 1.0 + + + + double + + Single Scattering Albedo + + + 0.95 + + + The single scattering albedo of atmospheric particles. + + 0.0 + 1.0 + + + + double + + Reference Value of Wha + + WHA + + The reference value to Wha to which the image will be normalized. + + 0.0 + 1.0 + + + + double + + Legendre Coefficient + + + 0.85 + + + The coefficient of the single particle Legendre phase function. + + -1.0 + 1.0 + + + + double + + Reference Value of Bha + + BHA + + The reference value to Bha to which the image will be + normalized. + + -1.0 + 1.0 + + + + double + + Atmospheric Shell Thickness + + + 0.003 + + + The atmospheric shell thickness normalized to the planet + radius. + + 0.0 + + + +
    diff --git a/isis/src/base/apps/photemplate/tsts/Makefile b/isis/src/base/apps/photemplate/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/photemplate/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/photemplate/tsts/atmos/Makefile b/isis/src/base/apps/photemplate/tsts/atmos/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..458dc980ac3cb5e1ccc0ddc4dab48431196fdac4 --- /dev/null +++ b/isis/src/base/apps/photemplate/tsts/atmos/Makefile @@ -0,0 +1,10 @@ +APPNAME = photemplate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) pvl=$(OUTPUT)/anisotropic.pvl normalization=atmalbedo > /dev/null; + $(APPNAME) pvl=$(OUTPUT)/hapkeatm.pvl normalization=atmalbedo \ + atmospheric=hapkeatm1 > /dev/null; + $(APPNAME) pvl=$(OUTPUT)/isotropic.pvl normalization=atmalbedo \ + atmospheric=isotropic1 > /dev/null; diff --git a/isis/src/base/apps/photemplate/tsts/default/Makefile b/isis/src/base/apps/photemplate/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d6e45e49fc0cf1b896b16493da0d5889fdaf9cac --- /dev/null +++ b/isis/src/base/apps/photemplate/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = photemplate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) pvl=$(OUTPUT)/default.pvl > /dev/null; diff --git a/isis/src/base/apps/photemplate/tsts/normal/Makefile b/isis/src/base/apps/photemplate/tsts/normal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f756b9ba37e9938ea0b510a3cc4f84f59fa120d8 --- /dev/null +++ b/isis/src/base/apps/photemplate/tsts/normal/Makefile @@ -0,0 +1,8 @@ +APPNAME = photemplate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) pvl=$(OUTPUT)/albedo.pvl normalization=albedo > /dev/null; + $(APPNAME) pvl=$(OUTPUT)/mixed.pvl normalization=mixed > /dev/null; + $(APPNAME) pvl=$(OUTPUT)/moonalbedo.pvl normalization=moonalbedo > /dev/null; diff --git a/isis/src/base/apps/photomet/Makefile b/isis/src/base/apps/photomet/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/photomet/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/photomet/assets/images/gui1.jpg b/isis/src/base/apps/photomet/assets/images/gui1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..120f0b91ca90a0e064de7fbb718f8e1d90948f92 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/images/gui1.jpg differ diff --git a/isis/src/base/apps/photomet/assets/images/gui2.jpg b/isis/src/base/apps/photomet/assets/images/gui2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1dcbda6def8ea796e3f5be7928dbae7ede079a8f Binary files /dev/null and b/isis/src/base/apps/photomet/assets/images/gui2.jpg differ diff --git a/isis/src/base/apps/photomet/assets/images/gui3.jpg b/isis/src/base/apps/photomet/assets/images/gui3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..216fb90dce64888cfcba8a9a6916bde44480c65b Binary files /dev/null and b/isis/src/base/apps/photomet/assets/images/gui3.jpg differ diff --git a/isis/src/base/apps/photomet/assets/images/gui4.jpg b/isis/src/base/apps/photomet/assets/images/gui4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6da08b58322d7fe03c0a867698e8fda59eb33e8a Binary files /dev/null and b/isis/src/base/apps/photomet/assets/images/gui4.jpg differ diff --git a/isis/src/base/apps/photomet/assets/images/input.jpg b/isis/src/base/apps/photomet/assets/images/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..05cbb536327d3627be748c0ac5ebf355aa156493 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/images/input.jpg differ diff --git a/isis/src/base/apps/photomet/assets/images/output1.jpg b/isis/src/base/apps/photomet/assets/images/output1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db86d10a4b8d981972b126228d2c6589ec05f275 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/images/output1.jpg differ diff --git a/isis/src/base/apps/photomet/assets/images/output2.jpg b/isis/src/base/apps/photomet/assets/images/output2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d05dda19e22ba9eceb11632b780383849fc589b4 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/images/output2.jpg differ diff --git a/isis/src/base/apps/photomet/assets/images/output3.jpg b/isis/src/base/apps/photomet/assets/images/output3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..86795ee1d3dcaf616cfb0e2f615ea0ddfee7dd48 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/images/output3.jpg differ diff --git a/isis/src/base/apps/photomet/assets/images/output4.jpg b/isis/src/base/apps/photomet/assets/images/output4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d322731121133a615c997eb40bc1faed9006c885 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/images/output4.jpg differ diff --git a/isis/src/base/apps/photomet/assets/input.pvl b/isis/src/base/apps/photomet/assets/input.pvl new file mode 100755 index 0000000000000000000000000000000000000000..171907b5b7d598985d58a84aef6a69dc3224a8a3 --- /dev/null +++ b/isis/src/base/apps/photomet/assets/input.pvl @@ -0,0 +1,23 @@ +Object = NormalizationModel + Group = Algorithm + Name = Mixed +# PhotoModel = HapkeHen + Incmat=87.0 + Albedo=0.05 + Incref=0.0 +# Emaref=0.0 +# Pharef=0.0 + Thresh=10E30 + EndGroup +EndObject +Object = PhotometricModel + Group = Algorithm + Name = HapkeHen + Wh=0.278906221 + Hh=0.0438 + B0=1.0 + Theta=10.0 + HG1=-0.229315607 + HG2=0.0 + EndGroup +EndObject diff --git a/isis/src/base/apps/photomet/assets/thumbs/gui1thumb.jpg b/isis/src/base/apps/photomet/assets/thumbs/gui1thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d8029fff4a055e5277eedef1da794e2df24b2f1a Binary files /dev/null and b/isis/src/base/apps/photomet/assets/thumbs/gui1thumb.jpg differ diff --git a/isis/src/base/apps/photomet/assets/thumbs/gui2thumb.jpg b/isis/src/base/apps/photomet/assets/thumbs/gui2thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e7f209fd5bc0f263714d0d5844a4822921d3b884 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/thumbs/gui2thumb.jpg differ diff --git a/isis/src/base/apps/photomet/assets/thumbs/gui3thumb.jpg b/isis/src/base/apps/photomet/assets/thumbs/gui3thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e602eb6aef4b15b2ded25cb69887a4a0982bd03b Binary files /dev/null and b/isis/src/base/apps/photomet/assets/thumbs/gui3thumb.jpg differ diff --git a/isis/src/base/apps/photomet/assets/thumbs/gui4thumb.jpg b/isis/src/base/apps/photomet/assets/thumbs/gui4thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fb3a9009b2e1e9259acc483aabb264973d670a35 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/thumbs/gui4thumb.jpg differ diff --git a/isis/src/base/apps/photomet/assets/thumbs/inputthumb.jpg b/isis/src/base/apps/photomet/assets/thumbs/inputthumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3e777293c605196a4af4cd8d6776227a86359f90 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/thumbs/inputthumb.jpg differ diff --git a/isis/src/base/apps/photomet/assets/thumbs/output1thumb.jpg b/isis/src/base/apps/photomet/assets/thumbs/output1thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2668f7c2668c49175470d8d145041530a2405636 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/thumbs/output1thumb.jpg differ diff --git a/isis/src/base/apps/photomet/assets/thumbs/output2thumb.jpg b/isis/src/base/apps/photomet/assets/thumbs/output2thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..69f3b82de4eaa8f082f04fbbd23771f23c11ab50 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/thumbs/output2thumb.jpg differ diff --git a/isis/src/base/apps/photomet/assets/thumbs/output3thumb.jpg b/isis/src/base/apps/photomet/assets/thumbs/output3thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cee590606f4303f631a5fbe86e1410aed0a3e1f6 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/thumbs/output3thumb.jpg differ diff --git a/isis/src/base/apps/photomet/assets/thumbs/output4thumb.jpg b/isis/src/base/apps/photomet/assets/thumbs/output4thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..29125c334ebb43a025db2f985fb869fb2234e0e3 Binary files /dev/null and b/isis/src/base/apps/photomet/assets/thumbs/output4thumb.jpg differ diff --git a/isis/src/base/apps/photomet/photomet.cpp b/isis/src/base/apps/photomet/photomet.cpp new file mode 100644 index 0000000000000000000000000000000000000000..223420cbf2a48aa5693ab8b0190c9aa504704e77 --- /dev/null +++ b/isis/src/base/apps/photomet/photomet.cpp @@ -0,0 +1,113 @@ +#include "Isis.h" +#include +#include "Camera.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "Photometry.h" +#include "Pvl.h" +#include "Cube.h" + +#include "PvlGroup.h" +#include "iException.h" + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) + +using namespace std; +using namespace Isis; + +// Global variables +Camera *cam; +Cube *icube; +Photometry *pho; +double maxema; +double maxinc; + +void photomet (Buffer &in, Buffer &out); + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Set up the input cube and get camera information + icube = p.SetInputCube("FROM"); + cam = icube->Camera(); + + // Create the output cube + p.SetOutputCube("TO"); + + // Set up the user interface + UserInterface &ui = Application::GetUserInterface(); + // Get the name of the parameter file + Pvl par(ui.GetFilename("PHOPAR")); + // Set value for maximum emission/incidence angles chosen by user + maxema = ui.GetDouble("MAXEMISSION"); + maxinc = ui.GetDouble("MAXINCIDENCE"); + + // Get the BandBin Center from the image + PvlGroup pvlg = icube->GetGroup("BandBin"); + double wl; + if (pvlg.HasKeyword("Center")) { + PvlKeyword &wavelength = pvlg.FindKeyword("Center"); + wl = wavelength[0]; + } else { + wl = 1.0; + } + + // Create the photometry object and set the wavelength + PvlGroup &algo = par.FindObject("NormalizationModel").FindGroup("Algorithm",Pvl::Traverse); + if (!algo.HasKeyword("Wl")) { + algo.AddKeyword(Isis::PvlKeyword("Wl",wl)); + } + pho = new Photometry(par); + pho->SetPhotomWl(wl); + + // Start the processing + p.StartProcess(photomet); + p.EndProcess(); +} + +/** + * Perform photometric correction + * + * @param in Buffer containing input DN values + * @param out Buffer containing output DN values + * @author Janet Barrett + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified to set off + * target pixels to null. Added check for new maxinc + * and maxema parameters. + */ +void photomet (Buffer &in, Buffer &out) { + + double pha,inc,ema,mult,base; + for (int i=0; iSetImage(in.Sample(i),in.Line(i))) { + out[i] = NULL8; + } + // otherwise, compute angle values + else{ + pha = cam->PhaseAngle(); + inc = cam->IncidenceAngle(); + ema = cam->EmissionAngle(); + + // if invalid angles, set to null + if (inc >= 90.0 || ema >= 90.0) { + out[i] = NULL8; + } + // if angles greater than max allowed by user, set to null + else if (inc > maxinc || ema > maxema) { + out[i] = NULL8; + } + // otherwise, do photometric correction + else { + pho->Compute(pha,inc,ema,in[i],out[i],mult,base); + } + } + } +} diff --git a/isis/src/base/apps/photomet/photomet.xml b/isis/src/base/apps/photomet/photomet.xml new file mode 100644 index 0000000000000000000000000000000000000000..88f7edae499102a7d819a91489127b9c7d465fc8 --- /dev/null +++ b/isis/src/base/apps/photomet/photomet.xml @@ -0,0 +1,788 @@ + + + + + + Perform photometric corrections on a cube + + + + This program performs photometric corrections on a cube. It can be used + to normalize an image for mosaicking. The user must input the cube with a + pvl containing the corresponding photometric parameters. Examples of sample + pvl files are shown below. There are three aspects of photometric correction + that need to be considered when running the photomet program: + +
    +    1) Surface photometric function model type
    +    2) Atmospheric photometric function model type
    +    3) Type of normalization to be performed
    +    
    + + The types of surface photometric function model types currently available + in photomet are: +
    +    HapkeHen        : Hapke-Henyey-Greenstein photometric model. Derive model 
    +                      albedo using complete Hapke model with Henyey-Greenstein 
    +		      single-particle phase function whose coefficients are 
    +		      Hg1 and Hg2, plus single scattering albedo Wh, opposition
    +		      surge parameters Hh and B0, and macroscopic roughness
    +		      Theta.
    +    Lambert         : Simple photometric model which predicts that light
    +                      incident on a surface is scattered uniformly in all
    +		      directions; the total amount of reflected light depends
    +		      on the incidence angle of the illumination. This function
    +		      does not depend upon the outgoing light direction.
    +    LommelSeeliger  : This model takes into account the radiance that results
    +                      from single scattering (scattering of collimated
    +		      incident light) and does not take into account the
    +		      radiance that results from multiple scattering (scattering
    +		      of diffuse light which has made its way indirectly to
    +		      the same position by being scattered one or more times).
    +		      This model depends on the incidence and emission angles.
    +    LunarLambert    : This model combines a weighted sum of the LommelSeeliger
    +                      and Lambert models. Given a suitable value for the
    +		      LunarLambert function weight, L, this model fits the true
    +		      reflectance behavior of many planetary surfaces equally
    +		      well as the Hapke model. This model also depends on the
    +		      incidence and emission angles.
    +    Minnaert        : This model expands upon the Lambert function by introducing
    +                      constant, K, that is used to describe the roughness of a
    +		      surface. When the K constant is set to 1.0, then the 
    +		      Minnaert model is equivalent to the Lambert model.
    +    LunarLambertMcEwen : This model was developed specifically for use with the
    +                      Moon. This model was designed to be used in conjunction
    +		      with the MoonAlbedo normalization model.
    +    
    + + The types of atmospheric photometric function model types currently + available in photomet are: + +
    +    Anisotropic1    : Uses Chandrasekhar's solution for anisotropic scattering
    +                      described by a one term Legendre polynomial. This model
    +		      uses first order scattering approximation.
    +    Anisotropic2    : Uses Chandrasekhar's solution for anisotropic scattering
    +                      described by a one term Legendre polynomial. This model
    +		      uses second order scattering approximation. It is slower
    +		      but more accurate than Anisotropic1.
    +    HapkeAtm1       : Provides an approximation for strongly anisotropic
    +                      scattering that is similar to Hapke's model for a planetary
    +		      surface. The Chandrasekhar solution for isotropic
    +		      scattering is used for the multiple scattering terms, and
    +		      a correction is made to the singly scattered light for
    +		      anisotropic particle phase function. A one term Henyey
    +		      Greenstein function is used. This model uses a first
    +		      order scattering approximation.
    +    HapkeAtm2       : Provides an approximation for strongly anisotropic
    +                      scattering that is similar to Hapke's model for a planetary
    +		      surface. The Chandrasekhar solution for isotropic
    +		      scattering is used for the multiple scattering terms, and
    +		      a correction is made to the singly scattered light for
    +		      anisotropic particle phase function. A one term Henyey
    +		      Greenstein function is used. This model uses a second
    +		      order scattering approximation. It is slower but more
    +		      accurate than HapkeAtm1.
    +    Isotropic1      : Uses Chandrasekhar's solution for isotropic scattering.
    +                      This model uses first order scattering approximation.
    +    Isotropic2      : Uses Chandrasekhar's solution for isotropic scattering.
    +                      This model uses second order scattering approximation.
    +		      It is slower but more accurate than Isotropic1.
    +    
    + + The types of normalization models currently available in photomet are: + +
    +    Albedo          : Normalization without atmosphere. Each pixel is divided by 
    +                      the model photometric function evaluated at the geometry
    +                      of that pixel, then multiplied by the function at reference
    +		      geometry with incidence and phase angles equal to Incref
    +		      and emission angle 0. This has the effect of removing
    +		      brightness variations due to incidence angle and showing
    +		      relative albedo variations with the same contrast
    +		      everywhere. If topographic shading is present, it will be
    +		      amplified more in regions of low incidence angle and will
    +		      not appear uniform.
    +    AlbedoAtm       : Normalization with atmosphere. For each pixel, a model of 
    +                      atmospheric scattering is subtracted and a surface model
    +                      is divided out, both evaluated at the actual geometry of
    +		      the pixel. Then the resulting value is multiplied by the 
    +		      surface function at reference conditions is added. In 
    +		      normal usage, the reference condition has normal incidence
    +		      (Incref=0) and no atmosphere (Tauref=0) but in some cases
    +		      it may be desirable to normalize images to a different
    +		      incidence angle or a finite optical depth to obtain a more
    +		      uniform appearance. As with the Albedo model, if 
    +		      topographic shading is present, it will be amplified more at
    +		      high incidence angles and will not appear uniform.
    +    Mixed           : Normalization without atmosphere. Used to do albedo 
    +                      normalization over most of the planet, but near the 
    +                      terminator it will normalize topographic contrast to avoid
    +		      the seams that can occur with the usual albedo normalization.
    +		      The two effects will be joined seamlessly at incidence 
    +		      angle Incmat. Incmat must be adjusted to give the best
    +		      equalization of contrast at all incidence angles. The
    +		      Albedo parameter must also be adjusted so the topographically
    +		      normalized regions at high incidence angle are set to an
    +		      albedo compatible with the albedo-normalized data at lower
    +		      incidence.
    +    MoonAlbedo      : Normalization without atmosphere. This model was designed
    +                      specifically for use on Lunar data. It will compute 
    +                      normalized albedo for the Moon, normalized to 0 degrees
    +		      emission angle and 30 degrees illumination and phase angles.
    +		      The LunarLambertMcEwen photometric function was designed to 
    +                      be used with this normalization model.
    +    NoNormalization : Normalization without atmosphere. No normalization is 
    +                      performed. Only photometric correction is performed.
    +    Shade           : Normalization without atmosphere. The surface photometric 
    +                      function is evaluated at the geometry of the image in order
    +                      to calculate a shaded relief image of the ellipsoid (and
    +		      in the future the DEM). The radiance of the model surface
    +		      is set to Albedo at incidence angle Incref and zero phase.
    +		      The image data is not used.
    +    ShadeAtm        : Normalization with atmosphere. The surface photometric 
    +                      function is used to simulate an image by relief shading,
    +                      just like the Shade model, but the effects of atmospheric
    +		      scattering are also included in the calculation.
    +    Topo            : Normalization without atmosphere. Used to normalize 
    +                      topographic shading to uniform contrast regardless of 
    +                      incidence angle. Such a normalization would exagerate
    +		      albedo variations at large incidence angles, so this model
    +		      is used as part of a three step process in which (1) the
    +		      image is temporarily normalized for albedo; (2) a highpass
    +		      divide filter is used to remove regional albedo variations;
    +		      and (3) the image is renormalized with the Topo mode to 
    +		      undo the first normalization and equalize topographic 
    +		      shading. The reference state in the first step MUST have
    +		      Incref=0 because this is waht is undone in the final step.
    +		      If there are no significant albedo variations, step (2)
    +		      can be skipped but step (1) must not be.
    +    TopoAtm         : Normalization with atmosphere. As with the Topo model, 
    +                      this option is used in the final step of a three step
    +		      process: (1) normalize with the AlbedoAtm model, Incref=0,
    +		      and Tauref=0 to temporarily remove atmosphere and normalize
    +		      albedo variations; (2) use highpass divide filter to remove
    +		      albedo variations; and (3) normalize with the TopoAtm model
    +		      to undo the temporary normalization and equalize topographic
    +		      shading.
    +    
    + + As you can see above, the only normalization models that make use of atmospheric + correction are: AlbedoAtm, ShadeAtm, and TopoAtm. Atmospheric correction is not + applied by any of the other normalization models. If you specify an atmospheric + model in a PVL along with a normalization model that does not do atmospheric + correction, then the atmospheric model will be ignored. + + Each of the above photometric, atmospheric, and normalization models has specific + parameters that apply to them. Here is a list of the models and their related + parameters (in parentheses): + +
    +    HapkeHen (B0,Hg1,Hg2,Hh,Theta,Wh)
    +    Lambert
    +    LommelSeeliger
    +    LunarLambert (L)
    +    Minnaert (K)
    +    LunarLambertMcEwen
    +  
    +    Anisotropic1 (Bha,Bharef,Hnorm,Nulneg,Tau,Tauref,Wha,Wharef)
    +    Anisotropic2 (Bha,Bharef,Hnorm,Nulneg,Tau,Tauref,Wha,Wharef)
    +    HapkeAtm1 (Hga,Hgaref,Hnorm,Nulneg,Tau,Tauref,Wha,Wharef)
    +    HapkeAtm2 (Hga,Hgaref,Hnorm,Nulneg,Tau,Tauref,Wha,Wharef)
    +    Isotropic1 (Hnorm,Nulneg,Tau,Tauref,Wha,Wharef)
    +    Isotropic2 (Hnorm,Nulneg,Tau,Tauref,Wha,Wharef)
    +  
    +    Albedo (Albedo,Incmat,Incref,Thresh)
    +    AlbedoAtm (Incref)
    +    Mixed (Albedo,Incmat,Incref,Thresh)
    +    MoonAlbedo (Bsh1,D,E,F,G2,H,Wl,Xb1,Xb2,Xmul)
    +    NoNormalization
    +    Shade (Albedo,Incref)
    +    ShadeAtm (Albedo,Incref)
    +    Topo (Albedo,Incref,Thresh)
    +    TopoAtm (Albedo,Incref)
    +    
    + + Here is a description of each parameter along with a valid range + of values and the default for that parameter: + +
    +    Photometric parameters:
    +    -----------------------
    +    B0:     Hapke opposition surge component: 0 <= value : default is 0.0
    +    Bh:     Hapke Legendre coefficient for single particle phase function:
    +            -1 <= value <= 1 : default is 0.0
    +    Ch:     Hapke Legendre coefficient for single particle phase function:
    +            -1 <= value <= 1 : default is 0.0
    +    Hg1:    Hapke Henyey Greenstein coefficient for single particle phase
    +            function: -1 < value < 1 : default is 0.0
    +    Hg2:    Hapke Henyey Greenstein coefficient for single particle phase
    +            function: 0 <= value <= 1 : default is 0.0
    +    Hh:     Hapke opposition surge component: 0 <= value : default is 0.0
    +    K:      Minnaert function exponent: 0 <= value : default is 1.0
    +    L:      Lunar-Lambert function weight: no limit : default is 1.0
    +    Theta:  Hapke macroscopic roughness component: 0 <= value <= 90 :
    +            default is 0.0
    +    Wh:     Hapke single scattering albedo component: 0 < value <= 1 : 
    +            default is 0.5
    +  
    +    Atmospheric parameters:
    +    -----------------------
    +    Bha    : Coefficient of the single particle Legendre phase function:
    +             -1 <= value <= 1 : default is 0.85
    +    Bharef : Reference value of Bha to which the image will be
    +             normalized: -1 <= value <= 1 : default is Bha
    +    Hga    : Coefficient of single particle Henyey Greenstein phase
    +             function: -1 < value < 1 : default is 0.68
    +    Hgaref : Reference value of Hga to which the image will be
    +             normalized: -1 < value < 1 : default is Hga
    +    Hnorm  : Atmospheric shell thickness normalized to the planet radius:
    +             0 <= value : default is .003
    +    Nulneg : Determines if negative values after removal of atmospheric
    +             effects will be set to NULL: YES or NO : default is NO
    +    Tau    : Normal optical depth of the atmosphere: 0 <= value : default 
    +             is 0.28
    +    Tauref : Reference value of Tau to which the image will be
    +             normalized: 0 <= value : default is 0.0
    +    Wha    : Single scattering albedo of atmospheric particles: 
    +             0 < value <= 1 : default is 0.95
    +    Wharef : Reference value of Wha to which the image will be
    +             normalized: 0 < value <= 1 : default is Wha
    +  
    +    Normalization parameters:
    +    -------------------------
    +    Albedo : Albedo to which the image will be normalized: no limit : 
    +             default is 1.0
    +    Bsh1   : Albedo dependent phase function normalization parameter: 
    +             0 <= value : default is 0.08
    +    D      : Albedo dependent phase function normalization parameter: no 
    +             limit : default is 0.14
    +    E      : Albedo dependent phase function normalization parameter: no 
    +             limit : default is -0.4179
    +    F      : Albedo dependent phase function normalization parameter: no 
    +             limit : default is 0.55
    +    G2     : Albedo dependent phase function normalization parameter: no 
    +             limit : default is 0.02
    +    H      : Albedo dependent phase function normalization parameter: no 
    +             limit : default is 0.048
    +    Incmat : Specifies incidence angle where albedo normalization transitions 
    +             to incidence normalization: 0 <= value < 90 : default is 0.0
    +    Incref : Reference incidence angle to which the image will be normalized:
    +             0 <= value < 90 : default is 0.0
    +    Thresh : Sets upper limit on amount of amplification in regions of small
    +             incidence angle: no limit : default is 30.0
    +    Wl     : Wavelength in micrometers of the image being normalized: no 
    +             limit : default is 1.0
    +    Xb1    : Albedo dependent phase function normalization parameter: no 
    +             limit : default is -0.0817
    +    Xb2    : Albedo dependent phase function normalization parameter: no 
    +             limit : default is 0.0081
    +    Xmul   : Used to convert radiance to reflectance or apply a calibration 
    +             fudge factor: no limit : default is 1.0
    +    
    + + Here are some example PVL files: +
    +    Example 1:
    +  
    +    Object = PhotometricModel
    +      Group = Algorithm
    +        Name = Lambert
    +      EndGroup
    +    EndObject
    +    Object = NormalizationModel
    +      Group = Algorithm
    +        Name = NoNormalization
    +      EndGroup
    +    EndObject
    +  
    +    --------------------------------
    +    Example 2:
    +  
    +    Object = PhotometricModel
    +      Group = Algorithm
    +        Name = Minnaert
    +	K = .5
    +      EndGroup
    +    EndObject
    +    Object = NormalizationModel
    +      Group = Algorithm
    +        Name = Albedo
    +	Incref = 0.0
    +	Incmat = 0.0
    +	Albedo = 1.0
    +	Thresh = 30.0
    +      EndGroup
    +    EndObject
    +  
    +    --------------------------------
    +    Example 3:
    +  
    +    Object = PhotometricModel
    +      Group  = Algorithm
    +        Name = HapkeHen
    +	Wh = 0.52
    +	Hh = 0.0
    +	B0 = 0.0
    +	Theta = 30.0
    +	Hg1 = .213
    +	Hg2 = 1.0
    +      EndGroup
    +    EndObject
    +    Object = AtmosphericModel
    +      Group = Algorithm
    +        Name = HapkeAtm2
    +	Hnorm = .003
    +	Tau = 0.28
    +	Tauref = 0.0
    +	Wha = .95
    +	Hga = 0.68
    +      EndGroup
    +    EndObject
    +    Object = NormalizationModel
    +      Group = Algorithm
    +        Name = AlbedoAtm
    +	Incref = 0.0
    +      EndGroup
    +    EndObject
    +
    +    --------------------------------
    +    Example 4 (Used to process Clementine UVVIS filter "a" data):
    +  
    +    Object = PhotometricModel
    +      Group  = Algorithm
    +        Name = LunarLambertMcEwen
    +      EndGroup
    +    EndObject
    +    Object = NormalizationModel
    +      Group = Algorithm
    +        Name = MoonAlbedo
    +	D = 0.0
    +	E = -0.222
    +	F = 0.5
    +	G2 = 0.39
    +	H = 0.062
    +	Bsh1 = 2.31
    +      EndGroup
    +    EndObject
    +  
    +    --------------------------------
    +    Example 5 (Used to process Clementine UVVIS filter "b" data):
    +  
    +    Object = PhotometricModel
    +      Group  = Algorithm
    +        Name = LunarLambertMcEwen
    +      EndGroup
    +    EndObject
    +    Object = NormalizationModel
    +      Group = Algorithm
    +        Name = MoonAlbedo
    +	D = 0.0
    +	E = -0.218
    +	F = 0.5
    +	G2 = 0.4
    +	H = 0.054
    +	Bsh1 = 1.6
    +      EndGroup
    +    EndObject
    +  
    +    --------------------------------
    +    Example 6 (Used to process Clementine UVVIS filter "cde" data):
    +  
    +    Object = PhotometricModel
    +      Group  = Algorithm
    +        Name = LunarLambertMcEwen
    +      EndGroup
    +    EndObject
    +    Object = NormalizationModel
    +      Group = Algorithm
    +        Name = MoonAlbedo
    +	D = 0.0
    +	E = -0.226
    +	F = 0.5
    +	G2 = 0.36
    +	H = 0.052
    +	Bsh1 = 1.35
    +      EndGroup
    +    EndObject
    +  
    +  
    + +
    + + + photomet + + + + + Original version - based on Tammy Becker's + photom/photompr programs which were later + converted to Randy Kirk's photomet + + + Added code to acquire the BandBin Center keyword from the + input image. This value is needed in case the user chooses + the MoonAlbedo normalization method. + + + Removed references to CubeInfo + + + Added MAXEMISSION and MAXINCIDENCE parameters. Modified code to set + off-target pixels to NULL. Added appTests for new parameters. Added user + documentation examples. + + + + + Radiometric and Photometric Correction + Cameras + + + + + + cube + input + + Input cube + + + Use this parameter to select the input filename. + + + *.cub + + + + cube + real + output + + Output cube + + + This file will contain the of the photometric + correction. + + + + filename + input + + Pvl file + + + This file will contain the photometric parameters to use + when doing the photometric correction. + + + *.pvl + + + + + + double + Maximum emisson angle + + The maximum number of degrees allowed for the emission angle. This + number must be between 0.0 and 90.0. + + 0.0 + 90.0 + 90.0 + + + double + Maximum incidence angle + + The maximum number of degrees allowed for the incidence angle. This + number must be between 0.0 and 90.0. + + 0.0 + 90.0 + 90.0 + + + + + + + Photometric corrections with any valid angles + + This example shows the photometric correction of a cube by using + photomet application with the default parameter values kept for the + maximum emission and incidence angles. + + + + photomet from=input.cub phopar=input.pvl to=output.cub + + Run photomet with default maximum angles + + + + + Example GUI + + Screenshot of GUI version of the application. Notice the default + values of 90.0 are left alone for the MAXEMISSION and + MAXINCIDENCE parameters. + + + + + + + + Example input PVL + + Pvl file including the input photometric parameters for the input + cube. + + + PHOPAR + + + + + + Example input cube + + Screenshot of the input image before photometric correction has been + performed. + + + + FROM + + + + + + Example output cube + + Screenshot of the output image after photometric correction. Notice + many features on the surface are easier to view due to the + normalization of the pixels. + + + + TO + + + + + + Photometric corrections using maximum emission angle parameter + + This example shows the photometric correction of a cube by using + photomet application with the maximum emission angle set to 75.0 and the + default parameter value kept for the maximum incidence angle. + + + + photomet from=input.cub phopar=input.pvl to=output.cub maxemission=75.0 + + + Run photomet with maximum emission angle less than the default value + of 90 degrees. + + + + + + Example GUI + + Screenshot of GUI version of the application. Notice the + MAXEMISSION parameter is changed from the default value of 90.0. + + + + + + + + Example input PVL + + Pvl file including the input photometric parameters for the input + cube. + + + PHOPAR + + + + + + Example input cube + + Screenshot of the input image before photometric correction has been + performed. + + + + FROM + + + + + + Example output cube + + Screenshot of the output image after photometric correction. Notice + there are more blackened areas than in the Example 1 output image. + This happens since the pixel values have been set to null where the + emission angles are greater than 75. + + + + TO + + + + + + Photometric corrections using maximum incidence angle parameter + + This example shows the photometric correction of a cube by using + photomet application with the maximum incidence angle set to 85.0 and the + default parameter value kept for the maximum emission angle. + + + + photomet from=input.cub phopar=input.pvl to=output.cub maxincidence=85.0 + + + Run photomet with maximum incidence angle less than the default value + of 90 degrees. + + + + + + Example GUI + + Screenshot of GUI version of the application. Notice the + MAXINCIDENCE parameter is changed from the default value of 90.0. + + + + + + + + Example input PVL + + Pvl file including the input photometric parameters for the input + cube. + + + PHOPAR + + + + + + Example input cube + + Screenshot of the input image before photometric correction has been + performed. + + + + FROM + + + + + + Example output cube + + Screenshot of the output image after photometric correction. Notice + there are different areas of valid pixels from Examples 1 and 2 + output images. This happens since the pixel values have been set to + null where the incidence angles are greater than 85, but the + emission angle parameter is kept at default. + + + + TO + + + + + + Photometric corrections using maximum emission and incidence angle parameters + + This example shows the photometric correction of a cube by using + photomet application with the maximum emission angle set to 75.0 and the + maximum incidence angle set to 85.0. + + + + photomet from=input.cub phopar=input.pvl to=output.cub maxemission=75.0 maxincidence=85.0 + + + Run photomet with maximum emission and incidence angles less than the + default values of 90 degrees. + + + + + + Example GUI + + Screenshot of GUI version of the application. Notice the + MAXEMISSION and MAXINCIDENCE parameters are changed from the + default values of 90.0. + + + + + + + + Example input PVL + + Pvl file including the input photometric parameters for the input + cube. + + + PHOPAR + + + + + + Example input cube + + Screenshot of the input image before photometric correction has been + performed. + + + + FROM + + + + + + Example output cube + + Screenshot of the output image after photometric correction. Notice + this output image contains the overlapping valid pixels from + Examples 2 and 3. + + + + TO + + + + + + +
    diff --git a/isis/src/base/apps/photomet/tsts/Makefile b/isis/src/base/apps/photomet/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/photomet/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/photomet/tsts/clemMaxemiMaxinc/Makefile b/isis/src/base/apps/photomet/tsts/clemMaxemiMaxinc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1ff2f9ea36798fca1e18c3ba62b3d32aebd41b8a --- /dev/null +++ b/isis/src/base/apps/photomet/tsts/clemMaxemiMaxinc/Makefile @@ -0,0 +1,10 @@ +APPNAME = photomet + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/lub2303j.191.lev1.cub \ + to=$(OUTPUT)/lub2303j.191.lev1.phot.cub \ + phopar=$(INPUT)/clem.pvl \ + maxe=4.0 \ + maxi=5.0 > /dev/null; diff --git a/isis/src/base/apps/photomet/tsts/clemMaxemission/Makefile b/isis/src/base/apps/photomet/tsts/clemMaxemission/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f4794958811e06f1619c7303f39cd78edfb6b554 --- /dev/null +++ b/isis/src/base/apps/photomet/tsts/clemMaxemission/Makefile @@ -0,0 +1,9 @@ +APPNAME = photomet + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/lub2303j.191.lev1.cub \ + to=$(OUTPUT)/lub2303j.191.lev1.phot.cub \ + phopar=$(INPUT)/clem.pvl \ + maxemission=4.0 > /dev/null; diff --git a/isis/src/base/apps/photomet/tsts/clemMaxincidence/Makefile b/isis/src/base/apps/photomet/tsts/clemMaxincidence/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..999b6dfd5991db0eb5169f64b1d921c43ce60c2e --- /dev/null +++ b/isis/src/base/apps/photomet/tsts/clemMaxincidence/Makefile @@ -0,0 +1,9 @@ +APPNAME = photomet + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/lub2303j.191.lev1.cub \ + to=$(OUTPUT)/lub2303j.191.lev1.phot.cub \ + phopar=$(INPUT)/clem.pvl \ + maxincidence=5.0 > /dev/null; diff --git a/isis/src/base/apps/photomet/tsts/clementine/Makefile b/isis/src/base/apps/photomet/tsts/clementine/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7b0c6dcf75b708eb818154c18c3c5f35802c0264 --- /dev/null +++ b/isis/src/base/apps/photomet/tsts/clementine/Makefile @@ -0,0 +1,8 @@ +APPNAME = photomet + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/lub2303j.191.lev1.cub \ + to=$(OUTPUT)/lub2303j.191.lev1.phot.cub \ + phopar=$(INPUT)/clem.pvl > /dev/null; diff --git a/isis/src/base/apps/photomet/tsts/messMaxemiMaxinc/Makefile b/isis/src/base/apps/photomet/tsts/messMaxemiMaxinc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..04beb3f5ce41303546dfee42bf8e1388c89874a2 --- /dev/null +++ b/isis/src/base/apps/photomet/tsts/messMaxemiMaxinc/Makefile @@ -0,0 +1,10 @@ +APPNAME = photomet + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/EN0031257484M.iof.cub \ + to=$(OUTPUT)/EN0031257484M.phot.cub \ + phopar=$(INPUT)/pvlfile.txt \ + maxe=75.0 \ + maxi=75.0 > /dev/null; diff --git a/isis/src/base/apps/photomet/tsts/messMaxemission/Makefile b/isis/src/base/apps/photomet/tsts/messMaxemission/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c5414512643e7af1f97109bfe01a3679bc212961 --- /dev/null +++ b/isis/src/base/apps/photomet/tsts/messMaxemission/Makefile @@ -0,0 +1,9 @@ +APPNAME = photomet + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/EN0031257484M.iof.cub \ + to=$(OUTPUT)/EN0031257484M.phot.cub \ + phopar=$(INPUT)/pvlfile.txt \ + maxemission=75 > /dev/null; diff --git a/isis/src/base/apps/photomet/tsts/messMaxincidence/Makefile b/isis/src/base/apps/photomet/tsts/messMaxincidence/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..78888da1672fc6f589026b4dac607b52c08135dc --- /dev/null +++ b/isis/src/base/apps/photomet/tsts/messMaxincidence/Makefile @@ -0,0 +1,9 @@ +APPNAME = photomet + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/EN0031257484M.iof.cub \ + to=$(OUTPUT)/EN0031257484M.phot.cub \ + phopar=$(INPUT)/pvlfile.txt \ + maxincidence=75 > /dev/null; diff --git a/isis/src/base/apps/photomet/tsts/messenger/Makefile b/isis/src/base/apps/photomet/tsts/messenger/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b15d9a6ee7332fae7554a4e8fbed11d8734aaa93 --- /dev/null +++ b/isis/src/base/apps/photomet/tsts/messenger/Makefile @@ -0,0 +1,8 @@ +APPNAME = photomet + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/EN0031257484M.iof.cub \ + to=$(OUTPUT)/EN0031257484M.phot.cub \ + phopar=$(INPUT)/pvlfile.txt > /dev/null; diff --git a/isis/src/base/apps/photrim/Makefile b/isis/src/base/apps/photrim/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/photrim/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/photrim/photrim.cpp b/isis/src/base/apps/photrim/photrim.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5b9776b12d23b22a10c29238cba31b9aadfde01a --- /dev/null +++ b/isis/src/base/apps/photrim/photrim.cpp @@ -0,0 +1,85 @@ +#include "Isis.h" +#include "Camera.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +// Global variables +Camera *cam; +Cube *icube; +double minPhase; +double maxPhase; +double minEmission; +double maxEmission; +double minIncidence; +double maxIncidence; +int lastBand; + +void photrim (Buffer &in, Buffer &out); + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and get the camera model + icube = p.SetInputCube("FROM"); + cam = icube->Camera(); + + // Create the output cube + p.SetOutputCube ("TO"); + + // Get the trim angles + UserInterface &ui = Application::GetUserInterface(); + + minPhase = ui.GetDouble ("MINPHASE"); + maxPhase = ui.GetDouble ("MAXPHASE"); + minEmission = ui.GetDouble ("MINEMISSION"); + maxEmission = ui.GetDouble ("MAXEMISSION"); + minIncidence = ui.GetDouble ("MININCIDENCE"); + maxIncidence = ui.GetDouble ("MAXINCIDENCE"); + + // Start the processing + lastBand = 0; + p.StartProcess(photrim); + p.EndProcess(); +} + + +// Line processing routine +void photrim (Buffer &in, Buffer &out) { + // See if there is a change in band which would change the camera model + if (in.Band() != lastBand) { + lastBand = in.Band(); + cam->SetBand(icube->PhysicalBand(lastBand)); + } + + // Loop for each pixel in the line. + double samp,phase,emission,incidence; + double line = in.Line(); + for (int i=0; iSetImage(samp,line); + if (cam->HasSurfaceIntersection()) { + if (((phase = cam->PhaseAngle()) < minPhase) || (phase > maxPhase)) { + out[i] = Isis::NULL8; + } + else if (((emission = cam->EmissionAngle()) < minEmission) || + (emission > maxEmission)) { + out[i] = Isis::NULL8; + } + else if (((incidence = cam->IncidenceAngle()) < minIncidence) || + (incidence > maxIncidence)) { + out[i] = Isis::NULL8; + } + else { + out[i] = in[i]; + } + } + // Trim outerspace + else { + out[i] = Isis::NULL8; + } + } +} diff --git a/isis/src/base/apps/photrim/photrim.xml b/isis/src/base/apps/photrim/photrim.xml new file mode 100644 index 0000000000000000000000000000000000000000..d1ac0a6b8207fdb6404256feb47c6eecb32deeb0 --- /dev/null +++ b/isis/src/base/apps/photrim/photrim.xml @@ -0,0 +1,157 @@ + + + + + + Trims pixels outside of phase, incidence, and emission angles + + + + This program trims pixels outside of user specified phase, incidence and + emission angles. It is meant to work specifically on camera based cubes. + The phase angle is the angle between the sun vector to a pixel and the + instrument vector to the same pixel. The incidence angle is the angle + between the sun vector to a point and the normal at that point. The + emission angle is the angle between the instrument vector to a point and the + normal at that point. + + If the instrument is directly between the point and the sun the phase, + incidence and emission angles are all zero. If the instrument is looking + down the normal and the sun is not then the phase, incidence and emission + angles are greater than 0 but less than or equal to 90. If any of the angles + is greater than 90 then the sun is not hitting the point or the instrument + can not see the point. + + + + trimangle + + + + + Original version + + + Converted trimandle to Isis 3.0, and made it trim only on phase, incidence + and emission angles. + + + Modified filename parameters to be cube parameters where necessary + + + Removed references to CubeInfo + + + + + Trim and Mask + Cameras + + + + + + cube + input + + Input cube to trim + + + Use this parameter to select the filename. All bands within the file + will be trimmed. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the trim. + + + + + + + double + 0.0 + Minimum phase angle to trim + + Pixels which have a phase angle less than this value will be + trimmed. + + 0.0 + 180.0 + MAXPHASE + + + double + 180.0 + Maximum phase angle to trim + + Pixels which have a phase angle greater than this value will be + trimmed. + + 0.0 + 180.0 + MINPHASE + + + + double + 0.0 + Minimum emission angle to trim + + Pixels which have an emission angle less than this value will be + trimmed. + + 0.0 + 90.0 + MAXEMISSION + + + 90.0 + double + Maximum emission angle to trim + + Pixels which have a emission angle greater than this value will be + trimmed. + + 0.0 + 90.0 + MINEMISSION + + + + double + 0.0 + Minimum incidence angle to trim + + Pixels which have an incidence angle less than this value will be + trimmed. + + 0.0 + 180.0 + MAXINCIDENCE + + + double + 90.0 + Maximum incidence angle to trim + + Pixels which have a incidence angle greater than this value will be + trimmed. + + 0.0 + 180.0 + MININCIDENCE + + + + diff --git a/isis/src/base/apps/photrim/tsts/Makefile b/isis/src/base/apps/photrim/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/photrim/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/photrim/tsts/base/Makefile b/isis/src/base/apps/photrim/tsts/base/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fb2ea8e09a00d974d95a844f56ac7e2de2a45c4d --- /dev/null +++ b/isis/src/base/apps/photrim/tsts/base/Makefile @@ -0,0 +1,13 @@ +APPNAME = photrim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/ab102401.cub \ + to= $(OUTPUT)/PhotrimTruth1.cub \ + minphase=0.0 \ + maxphase=180.0 \ + minemission=0.0 \ + maxemission=90.0 \ + minincidence=0.0 \ + maxincidence=90.0 > /dev/null; diff --git a/isis/src/base/apps/photrim/tsts/emission/Makefile b/isis/src/base/apps/photrim/tsts/emission/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..07533bd3413ed30ce276b76fc5edd25af4b02d47 --- /dev/null +++ b/isis/src/base/apps/photrim/tsts/emission/Makefile @@ -0,0 +1,13 @@ +APPNAME = photrim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/ab102401.cub \ + to= $(OUTPUT)/PhotrimTruth3.cub \ + minphase=0.0 \ + maxphase=180.0 \ + minemission=22.5 \ + maxemission=67.5 \ + minincidence=0.0 \ + maxincidence=90.0 > /dev/null; diff --git a/isis/src/base/apps/photrim/tsts/incidence/Makefile b/isis/src/base/apps/photrim/tsts/incidence/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1a8d13fc15e54b6ef588afadbd83490dd141c4eb --- /dev/null +++ b/isis/src/base/apps/photrim/tsts/incidence/Makefile @@ -0,0 +1,13 @@ +APPNAME = photrim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/ab102401.cub \ + to= $(OUTPUT)/PhotrimTruth4.cub \ + minphase=0.0 \ + maxphase=180.0 \ + minemission=0.0 \ + maxemission=90.0 \ + minincidence=22.5 \ + maxincidence=67.5 > /dev/null; diff --git a/isis/src/base/apps/photrim/tsts/phase/Makefile b/isis/src/base/apps/photrim/tsts/phase/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f7a1c9a913b6329101db65cee9e841656ee73719 --- /dev/null +++ b/isis/src/base/apps/photrim/tsts/phase/Makefile @@ -0,0 +1,13 @@ +APPNAME = photrim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/ab102401.cub \ + to= $(OUTPUT)/PhotrimTruth2.cub \ + minphase=45.0 \ + maxphase=135.0 \ + minemission=0.0 \ + maxemission=90.0 \ + minincidence=0.0 \ + maxincidence=90.0 > /dev/null; diff --git a/isis/src/base/apps/pointreg/Makefile b/isis/src/base/apps/pointreg/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/pointreg/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/pointreg/assets/IN/autoRegTemplate.def b/isis/src/base/apps/pointreg/assets/IN/autoRegTemplate.def new file mode 100755 index 0000000000000000000000000000000000000000..a65de71948e8b9fc954bca196710fa832b65659b --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/IN/autoRegTemplate.def @@ -0,0 +1,20 @@ + Object = AutoRegistration + Group = Algorithm + Name = MaximumCorrelation + Tolerance = 0.9 + EndGroup + + Group = PatternChip + Samples = 15 + Lines = 15 + MinimumZScore = 1.5 + ValidPercent = 80 + EndGroup + + Group = SearchChip + Samples = 25 + Lines = 25 + EndGroup + EndObject + + diff --git a/isis/src/base/apps/pointreg/assets/IN/controlNet.net b/isis/src/base/apps/pointreg/assets/IN/controlNet.net new file mode 100644 index 0000000000000000000000000000000000000000..7a613129d0dcc78a5d719e4865bfa1851ce5bfb1 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/IN/controlNet.net @@ -0,0 +1,321 @@ +Object = ControlNetwork + NetworkId = NiliFossae + NetworkType = ImageToGround + TargetName = Mars + UserName = tsuchars + Created = Null + LastModified = Null + Description = "NiliFossae Jitter - use spicefit" + + Object = ControlPoint + PointType = Tie + PointId = PSP755600001 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2042.3350730536 + Line = 71.29440261681 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 42.124752494031 + Line = 70.982648480001 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600002 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2002.639916173 + Line = 66.57377716384 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Unmeasured + Sample = 2.4415896384206 + Line = 66.243611121053 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600003 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2029.6922678382 + Line = 169.76283611677 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 29.492607315035 + Line = 169.44015966286 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600004 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2017.0482456316 + Line = 268.23033341812 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 16.85914095714 + Line = 267.8967346471 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600005 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2044.1054109109 + Line = 371.41814410624 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 43.914972221782 + Line = 371.0923469903 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600006 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2004.403169377 + Line = 366.69783071947 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 4.2245219795274 + Line = 366.35299756514 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600007 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2031.4609997924 + Line = 469.88532934139 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Unmeasured + Sample = 31.281169631201 + Line = 469.54860990834 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600008 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2018.8154240193 + Line = 568.35251457654 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 18.646136218309 + Line = 568.00487282638 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600009 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2045.8782485386 + Line = 671.53938906605 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 45.707486236206 + Line = 671.19986103717 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600010 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2006.1688073063 + Line = 666.81907567928 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 6.0099094607153 + Line = 666.46051161202 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/pointreg/assets/IN/controlNet2.net b/isis/src/base/apps/pointreg/assets/IN/controlNet2.net new file mode 100644 index 0000000000000000000000000000000000000000..5381f17bb350046970513a430f8a3094cb2ca7c2 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/IN/controlNet2.net @@ -0,0 +1,471 @@ +Object = ControlNetwork + NetworkId = "Default cnetadd test" + NetworkType = ImageToImage + TargetName = Mercury + UserName = jwalldren + Created = 2010-03-18T08:58:12 + LastModified = 2010-03-18T09:00:04 + Description = Test + + Object = ControlPoint + PointType = Tie + PointId = 0000001 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 651.97003024903 + Line = 12.216544898526 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 985.83359606539 + Line = 301.85268062912 + ErrorLine = -0.84256775766687 + ErrorSample = -2.335783753835 + ErrorMagnitude = 2.483104140172 + ZScore = (-2.0034478613635, 2.2620851616904) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98643155177487 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 537.37603601737 + Line = 666.87097797601 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-03-18T09:00:05 + ChooserName = "Application cnetadd" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000002 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 599.11852932624 + Line = 6.3895258304361 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 937.52281672183 + Line = 296.9651781907 + ErrorLine = -0.42552192462102 + ErrorSample = -2.3056060471066 + ErrorMagnitude = 2.3445443379872 + ZScore = (-1.6694637829536, 3.0018517053317) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98816135664775 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 492.84553389656 + Line = 663.65648508611 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-03-18T09:00:05 + ChooserName = "Application cnetadd" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000003 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 651.39051715658 + Line = 39.015402638171 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 984.42099675797 + Line = 327.59962581525 + ErrorLine = -0.7178460434136 + ErrorSample = -2.3307959319554 + ErrorMagnitude = 2.4388342744976 + ZScore = (-1.9655398870161, 2.7089591848142) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98144883722171 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 535.51105609178 + Line = 691.89621568813 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-03-18T09:00:05 + ChooserName = "Application cnetadd" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000004 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 598.69665165384 + Line = 33.295458756966 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 936.11490929155 + Line = 323.01474763996 + ErrorLine = -0.50219682629228 + ErrorSample = -2.1643728084314 + ErrorMagnitude = 2.2218711272743 + ZScore = (-1.9377958814932, 3.281699600531) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98392430568853 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 491.11023610326 + Line = 688.7661282315 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-03-18T09:00:05 + ChooserName = "Application cnetadd" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000005 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 545.76896108632 + Line = 27.450073761743 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 887.64556536396 + Line = 318.02175246376 + ErrorLine = 0.013100271611108 + ErrorSample = -2.1122133561236 + ErrorMagnitude = 2.1122539806811 + ZScore = (-1.7826764336141, 2.9099620790137) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98660994076081 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 446.49817289766 + Line = 685.53552614927 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-03-18T09:00:05 + ChooserName = "Application cnetadd" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000006 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 492.61600601607 + Line = 21.479938293483 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 839.10242479023 + Line = 313.1427280157 + ErrorLine = 0.30296399328051 + ErrorSample = -2.2420871737804 + ErrorMagnitude = 2.2624637181743 + ZScore = (-2.0434711253274, 4.4599620077926) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.97672753158462 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 401.68230110927 + Line = 682.20473198547 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-03-18T09:00:05 + ChooserName = "Application cnetadd" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000007 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 439.2467442986 + Line = 15.387890985786 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 790.45059234978 + Line = 308.07642445756 + ErrorLine = 0.66575537569639 + ErrorSample = -2.5018478613854 + ErrorMagnitude = 2.5889134674197 + ZScore = (-2.3118534152149, 2.0955505085493) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98273189889574 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 356.67030041236 + Line = 678.7760540263 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-03-18T09:00:05 + ChooserName = "Application cnetadd" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000008 + Ignore = True + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 385.67168330894 + Line = 9.1791310309534 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Estimated + Sample = 738.81177770483 + Line = 303.92161240047 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + ZScore = (-1.7560215125654, 2.3684067593322) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + Ignore = True + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 311.47106411062 + Line = 675.25393216829 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-03-18T09:00:05 + ChooserName = "Application cnetadd" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000009 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 331.90409027176 + Line = 2.8614265038939 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 692.07507992819 + Line = 297.58156056399 + ErrorLine = 1.3999920671355 + ErrorSample = -2.6159945594508 + ErrorMagnitude = 2.9670533064167 + ZScore = (-1.70394396103, 1.9289612953385) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98429149084156 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 266.09571933301 + Line = 671.6450764237 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-03-18T09:00:05 + ChooserName = "Application cnetadd" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000010 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 649.96902270705 + Line = 65.402139906388 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 982.02028107944 + Line = 353.13967032571 + ErrorLine = -0.76529600043153 + ErrorSample = -2.1189906515796 + ErrorMagnitude = 2.2529534726128 + ZScore = (-2.1045268293299, 3.2193995278892) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.97632158687133 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 532.91669801489 + Line = 716.60996864502 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-03-18T09:00:05 + ChooserName = "Application cnetadd" + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/pointreg/assets/IN/fileList.lis b/isis/src/base/apps/pointreg/assets/IN/fileList.lis new file mode 100644 index 0000000000000000000000000000000000000000..93e5a6b15da358f137223e64aa955adb2807a58f --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/IN/fileList.lis @@ -0,0 +1,2 @@ +PSP_007556_2010_RED4.balance.cub +PSP_007556_2010_RED5.balance.cub diff --git a/isis/src/base/apps/pointreg/assets/IN/fileList2.lis b/isis/src/base/apps/pointreg/assets/IN/fileList2.lis new file mode 100644 index 0000000000000000000000000000000000000000..6faf55a8508213ab2b5be0ad6b494f696b97edfa --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/IN/fileList2.lis @@ -0,0 +1,7 @@ +tsts/registerNewOnly/input/EN0131771118M.cal.cub +tsts/registerNewOnly/input/EN0131771123M.cub +tsts/registerNewOnly/input/EN0131771213M.cal.cub +tsts/registerNewOnly/input/EN0131771303M.cub +tsts/registerNewOnly/input/EN0131771313M.cal.cub +tsts/registerNewOnly/input/EN0131771393M.cub +tsts/registerNewOnly/input/EN0131771488M.cal.cub diff --git a/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasured.log b/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasured.log new file mode 100644 index 0000000000000000000000000000000000000000..d1e7039dcfc87cd18d929f0383383d65d8492b3a --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasured.log @@ -0,0 +1,31 @@ +pointreg: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed Group = Points + Ignored = 8 +End_Group + +Group = Measures + Validated = 0 + Registered = 0 + Unregistered = 7 + Unmeasured = 2 +End_Group + +Group = AutoRegStatistics + Total = 7 + Successful = 0 + Failure = 7 +End_Group + +Group = PatternChip1 + PatternNotEnoughData = 0 + PatternZScoreNotMet = 0 + FitChipNoData = 1 + FitChipToleranceNotMet = 4 +End_Group + +Group = SurfaceModel + SurfaceModelNotEnoughData = 0 + SurfaceModelSolutionInvalid = 0 + SurfaceModelToleranceNotMet = 0 + SurfaceModelDistanceInvalid = 2 +End_Group diff --git a/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasured.net b/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasured.net new file mode 100644 index 0000000000000000000000000000000000000000..f2315f1b659d068faa07a2b8d936ab68cc9b745f --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasured.net @@ -0,0 +1,46 @@ +Object = ControlNetwork + NetworkId = NiliFossae + NetworkType = ImageToGround + TargetName = Mars + UserName = jwalldren + Created = 2008-11-17T14:07:55 + LastModified = Null + Description = "NiliFossae Jitter - use spicefit" + + Object = ControlPoint + PointType = Tie + PointId = PSP755600002 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2002.639916173 + Line = 66.57377716384 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600007 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2031.4609997924 + Line = 469.88532934139 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasured.txt b/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasured.txt new file mode 100644 index 0000000000000000000000000000000000000000..d957bf37540caa9e869aa0ca877fd73fc1ef2088 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasured.txt @@ -0,0 +1,20 @@ +Sample,Line,TranslatedSample,TranslatedLine,SampleDifference,LineDifference,ZScoreMin,ZScoreMax,GoodnessOfFit +-1.79769e+308 +2002.64,66.5738,2002.64,66.5738,0,0,0,0,0 +0,0,2002.64,66.5738,0,0,0,0,0 +2029.69,169.763,2029.69,169.763,0,0,0,0,0 +29.4926,169.44,2029.69,169.763,0,0,-1.83868,2.17246,0 +2017.05,268.23,2017.05,268.23,0,0,0,0,0 +16.8591,267.897,2017.05,268.23,0,0,-1.89724,1.96297,0 +2044.11,371.418,2044.11,371.418,0,0,0,0,0 +43.915,371.092,2044.11,371.418,0.999821,-0.99752,-1.70574,2.77737,0.897049 +2004.4,366.698,2004.4,366.698,0,0,0,0,0 +4.22452,366.353,2004.4,366.698,-0.999476,-2.9947,-2.08732,1.95111,0.6901 +2031.46,469.885,2031.46,469.885,0,0,0,0,0 +0,0,2031.46,469.885,0,0,0,0,0 +2018.82,568.353,2018.82,568.353,0,0,0,0,0 +18.6461,568.005,2018.82,568.353,1.00211,-0.996154,-2.9134,3.01147,0.867769 +2045.88,671.539,2045.88,671.539,0,0,0,0,0 +45.7075,671.2,2045.88,671.539,0,0,-2.08163,2.02437,0 +2006.17,666.819,2006.17,666.819,0,0,0,0,0 +6.00991,666.461,2006.17,666.819,1.00256,-0.99605,-1.901,2.43346,0.872862 diff --git a/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasuredRegIgn.log b/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasuredRegIgn.log new file mode 100644 index 0000000000000000000000000000000000000000..f31b00ae064fbbd86e51511397921c3a99e2de3c --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasuredRegIgn.log @@ -0,0 +1,31 @@ +pointreg: Working +0% Processed 10% Processed Group = Points + Ignored = 0 +End_Group + +Group = Measures + Validated = 0 + Registered = 1 + Unregistered = 0 + Unmeasured = 2 +End_Group + +Group = AutoRegStatistics + Total = 1 + Successful = 1 + Failure = 0 +End_Group + +Group = PatternChip1 + PatternNotEnoughData = 0 + PatternZScoreNotMet = 0 + FitChipNoData = 0 + FitChipToleranceNotMet = 0 +End_Group + +Group = SurfaceModel + SurfaceModelNotEnoughData = 0 + SurfaceModelSolutionInvalid = 0 + SurfaceModelToleranceNotMet = 0 + SurfaceModelDistanceInvalid = 0 +End_Group diff --git a/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasuredRegIgn.net b/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasuredRegIgn.net new file mode 100644 index 0000000000000000000000000000000000000000..8a260f11bc284bb3d072052c67461b295cf0afc3 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasuredRegIgn.net @@ -0,0 +1,296 @@ +Object = ControlNetwork + NetworkId = NiliFossae + NetworkType = ImageToGround + TargetName = Mars + UserName = jwalldren + Created = 2008-11-17T13:49:19 + LastModified = Null + Description = "NiliFossae Jitter - use spicefit" + + Object = ControlPoint + PointType = Tie + PointId = PSP755600001 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2042.3350730536 + Line = 71.29440261681 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Automatic + Sample = 40.982541075274 + Line = 73.347661016967 + ErrorLine = -2.3650125369658 + ErrorSample = 1.142211418757 + ErrorMagnitude = 2.626391293228 + ZScore = (-1.8126794102863, 1.9209675846147) + DateTime = 2008-11-17T13:49:21 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.95303076679148 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600002 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2002.639916173 + Line = 66.57377716384 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600003 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2029.6922678382 + Line = 169.76283611677 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 29.492607315035 + Line = 169.44015966286 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600004 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2017.0482456316 + Line = 268.23033341812 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 16.85914095714 + Line = 267.8967346471 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600005 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2044.1054109109 + Line = 371.41814410624 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 43.914972221782 + Line = 371.0923469903 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600006 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2004.403169377 + Line = 366.69783071947 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 4.2245219795274 + Line = 366.35299756514 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600007 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2031.4609997924 + Line = 469.88532934139 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600008 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2018.8154240193 + Line = 568.35251457654 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 18.646136218309 + Line = 568.00487282638 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600009 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2045.8782485386 + Line = 671.53938906605 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 45.707486236206 + Line = 671.19986103717 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600010 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2006.1688073063 + Line = 666.81907567928 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 6.0099094607153 + Line = 666.46051161202 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasuredRegIgn.txt b/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasuredRegIgn.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7b35d734f8f44ef7ae3de64349d17abd917e1b4 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/discardIgnoredAndUnmeasuredRegIgn.txt @@ -0,0 +1,20 @@ +Sample,Line,TranslatedSample,TranslatedLine,SampleDifference,LineDifference,ZScoreMin,ZScoreMax,GoodnessOfFit +-1.79769e+308 +2042.34,71.2944,2042.34,71.2944,0,0,0,0,0 +40.9825,73.3477,2042.34,71.2944,1.14221,-2.36501,-1.81268,1.92097,0.953031 +2002.64,66.5738,2002.64,66.5738,0,0,0,0,0 +2029.69,169.763,2029.69,169.763,0,0,0,0,0 +29.4926,169.44,2029.69,169.763,0,0,0,0,0 +2017.05,268.23,2017.05,268.23,0,0,0,0,0 +16.8591,267.897,2017.05,268.23,0,0,0,0,0 +2044.11,371.418,2044.11,371.418,0,0,0,0,0 +43.915,371.092,2044.11,371.418,0,0,0,0,0 +2004.4,366.698,2004.4,366.698,0,0,0,0,0 +4.22452,366.353,2004.4,366.698,0,0,0,0,0 +2031.46,469.885,2031.46,469.885,0,0,0,0,0 +2018.82,568.353,2018.82,568.353,0,0,0,0,0 +18.6461,568.005,2018.82,568.353,0,0,0,0,0 +2045.88,671.539,2045.88,671.539,0,0,0,0,0 +45.7075,671.2,2045.88,671.539,0,0,0,0,0 +2006.17,666.819,2006.17,666.819,0,0,0,0,0 +6.00991,666.461,2006.17,666.819,0,0,0,0,0 diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputIgnored.log b/isis/src/base/apps/pointreg/assets/OUT/outputIgnored.log new file mode 100644 index 0000000000000000000000000000000000000000..d1e7039dcfc87cd18d929f0383383d65d8492b3a --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputIgnored.log @@ -0,0 +1,31 @@ +pointreg: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed Group = Points + Ignored = 8 +End_Group + +Group = Measures + Validated = 0 + Registered = 0 + Unregistered = 7 + Unmeasured = 2 +End_Group + +Group = AutoRegStatistics + Total = 7 + Successful = 0 + Failure = 7 +End_Group + +Group = PatternChip1 + PatternNotEnoughData = 0 + PatternZScoreNotMet = 0 + FitChipNoData = 1 + FitChipToleranceNotMet = 4 +End_Group + +Group = SurfaceModel + SurfaceModelNotEnoughData = 0 + SurfaceModelSolutionInvalid = 0 + SurfaceModelToleranceNotMet = 0 + SurfaceModelDistanceInvalid = 2 +End_Group diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputIgnored.net b/isis/src/base/apps/pointreg/assets/OUT/outputIgnored.net new file mode 100644 index 0000000000000000000000000000000000000000..152a19016e819bfecdfbda6285e4c71901e60d02 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputIgnored.net @@ -0,0 +1,313 @@ +Object = ControlNetwork + NetworkId = NiliFossae + NetworkType = ImageToGround + TargetName = Mars + UserName = jwalldren + Created = 2008-11-17T13:52:13 + LastModified = Null + Description = "NiliFossae Jitter - use spicefit" + + Object = ControlPoint + PointType = Tie + PointId = PSP755600001 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2042.3350730536 + Line = 71.29440261681 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 42.124752494031 + Line = 70.982648480001 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600002 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2002.639916173 + Line = 66.57377716384 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600003 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2029.6922678382 + Line = 169.76283611677 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 29.492607315035 + Line = 169.44015966286 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + ZScore = (-1.8386807274838, 2.1724636532686) + DateTime = 2008-11-17T13:52:15 + ChooserName = "Application pointreg" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600004 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2017.0482456316 + Line = 268.23033341812 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 16.85914095714 + Line = 267.8967346471 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + ZScore = (-1.8972422750631, 1.9629665173588) + DateTime = 2008-11-17T13:52:17 + ChooserName = "Application pointreg" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600005 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2044.1054109109 + Line = 371.41814410624 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 43.914972221782 + Line = 371.0923469903 + ErrorLine = -0.99751961792953 + ErrorSample = 0.99982077616259 + ErrorMagnitude = 1.4123338743373 + ZScore = (-1.7057391259327, 2.7773719438275) + DateTime = 2008-11-17T13:52:19 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.89704936538897 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600006 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2004.403169377 + Line = 366.69783071947 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 4.2245219795274 + Line = 366.35299756514 + ErrorLine = -2.9947043089342 + ErrorSample = -0.99947579425683 + ErrorMagnitude = 3.1570881776179 + ZScore = (-2.0873207330015, 1.9511073043332) + DateTime = 2008-11-17T13:52:21 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.69010025955735 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600007 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2031.4609997924 + Line = 469.88532934139 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600008 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2018.8154240193 + Line = 568.35251457654 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 18.646136218309 + Line = 568.00487282638 + ErrorLine = -0.99615432829137 + ErrorSample = 1.0021104799336 + ErrorMagnitude = 1.4129928732186 + ZScore = (-2.9134019235018, 3.0114744584951) + DateTime = 2008-11-17T13:52:23 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.86776856882073 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600009 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2045.8782485386 + Line = 671.53938906605 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 45.707486236206 + Line = 671.19986103717 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + ZScore = (-2.0816308453769, 2.0243659911865) + DateTime = 2008-11-17T13:52:25 + ChooserName = "Application pointreg" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600010 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2006.1688073063 + Line = 666.81907567928 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 6.0099094607153 + Line = 666.46051161202 + ErrorLine = -0.99605030622365 + ErrorSample = 1.0025627266965 + ErrorMagnitude = 1.4132403311148 + ZScore = (-1.9010021304113, 2.4334629495309) + DateTime = 2008-11-17T13:52:27 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.87286215825049 + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputIgnored.txt b/isis/src/base/apps/pointreg/assets/OUT/outputIgnored.txt new file mode 100644 index 0000000000000000000000000000000000000000..d957bf37540caa9e869aa0ca877fd73fc1ef2088 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputIgnored.txt @@ -0,0 +1,20 @@ +Sample,Line,TranslatedSample,TranslatedLine,SampleDifference,LineDifference,ZScoreMin,ZScoreMax,GoodnessOfFit +-1.79769e+308 +2002.64,66.5738,2002.64,66.5738,0,0,0,0,0 +0,0,2002.64,66.5738,0,0,0,0,0 +2029.69,169.763,2029.69,169.763,0,0,0,0,0 +29.4926,169.44,2029.69,169.763,0,0,-1.83868,2.17246,0 +2017.05,268.23,2017.05,268.23,0,0,0,0,0 +16.8591,267.897,2017.05,268.23,0,0,-1.89724,1.96297,0 +2044.11,371.418,2044.11,371.418,0,0,0,0,0 +43.915,371.092,2044.11,371.418,0.999821,-0.99752,-1.70574,2.77737,0.897049 +2004.4,366.698,2004.4,366.698,0,0,0,0,0 +4.22452,366.353,2004.4,366.698,-0.999476,-2.9947,-2.08732,1.95111,0.6901 +2031.46,469.885,2031.46,469.885,0,0,0,0,0 +0,0,2031.46,469.885,0,0,0,0,0 +2018.82,568.353,2018.82,568.353,0,0,0,0,0 +18.6461,568.005,2018.82,568.353,1.00211,-0.996154,-2.9134,3.01147,0.867769 +2045.88,671.539,2045.88,671.539,0,0,0,0,0 +45.7075,671.2,2045.88,671.539,0,0,-2.08163,2.02437,0 +2006.17,666.819,2006.17,666.819,0,0,0,0,0 +6.00991,666.461,2006.17,666.819,1.00256,-0.99605,-1.901,2.43346,0.872862 diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasured.log b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasured.log new file mode 100644 index 0000000000000000000000000000000000000000..d1e7039dcfc87cd18d929f0383383d65d8492b3a --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasured.log @@ -0,0 +1,31 @@ +pointreg: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed Group = Points + Ignored = 8 +End_Group + +Group = Measures + Validated = 0 + Registered = 0 + Unregistered = 7 + Unmeasured = 2 +End_Group + +Group = AutoRegStatistics + Total = 7 + Successful = 0 + Failure = 7 +End_Group + +Group = PatternChip1 + PatternNotEnoughData = 0 + PatternZScoreNotMet = 0 + FitChipNoData = 1 + FitChipToleranceNotMet = 4 +End_Group + +Group = SurfaceModel + SurfaceModelNotEnoughData = 0 + SurfaceModelSolutionInvalid = 0 + SurfaceModelToleranceNotMet = 0 + SurfaceModelDistanceInvalid = 2 +End_Group diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasured.net b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasured.net new file mode 100644 index 0000000000000000000000000000000000000000..9a6e5909263f1247fe418119b84169d0a0787f91 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasured.net @@ -0,0 +1,333 @@ +Object = ControlNetwork + NetworkId = NiliFossae + NetworkType = ImageToGround + TargetName = Mars + UserName = jwalldren + Created = 2008-11-17T13:50:42 + LastModified = Null + Description = "NiliFossae Jitter - use spicefit" + + Object = ControlPoint + PointType = Tie + PointId = PSP755600001 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2042.3350730536 + Line = 71.29440261681 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 42.124752494031 + Line = 70.982648480001 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600002 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2002.639916173 + Line = 66.57377716384 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Unmeasured + Sample = Null + Line = Null + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600003 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2029.6922678382 + Line = 169.76283611677 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 29.492607315035 + Line = 169.44015966286 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + ZScore = (-1.8386807274838, 2.1724636532686) + DateTime = 2008-11-17T13:50:44 + ChooserName = "Application pointreg" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600004 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2017.0482456316 + Line = 268.23033341812 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 16.85914095714 + Line = 267.8967346471 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + ZScore = (-1.8972422750631, 1.9629665173588) + DateTime = 2008-11-17T13:50:46 + ChooserName = "Application pointreg" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600005 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2044.1054109109 + Line = 371.41814410624 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 43.914972221782 + Line = 371.0923469903 + ErrorLine = -0.99751961792953 + ErrorSample = 0.99982077616259 + ErrorMagnitude = 1.4123338743373 + ZScore = (-1.7057391259327, 2.7773719438275) + DateTime = 2008-11-17T13:50:48 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.89704936538897 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600006 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2004.403169377 + Line = 366.69783071947 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 4.2245219795274 + Line = 366.35299756514 + ErrorLine = -2.9947043089342 + ErrorSample = -0.99947579425683 + ErrorMagnitude = 3.1570881776179 + ZScore = (-2.0873207330015, 1.9511073043332) + DateTime = 2008-11-17T13:50:50 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.69010025955735 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600007 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2031.4609997924 + Line = 469.88532934139 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Unmeasured + Sample = Null + Line = Null + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600008 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2018.8154240193 + Line = 568.35251457654 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 18.646136218309 + Line = 568.00487282638 + ErrorLine = -0.99615432829137 + ErrorSample = 1.0021104799336 + ErrorMagnitude = 1.4129928732186 + ZScore = (-2.9134019235018, 3.0114744584951) + DateTime = 2008-11-17T13:50:52 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.86776856882073 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600009 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2045.8782485386 + Line = 671.53938906605 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 45.707486236206 + Line = 671.19986103717 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + ZScore = (-2.0816308453769, 2.0243659911865) + DateTime = 2008-11-17T13:50:54 + ChooserName = "Application pointreg" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600010 + Ignore = True + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2006.1688073063 + Line = 666.81907567928 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 6.0099094607153 + Line = 666.46051161202 + ErrorLine = -0.99605030622365 + ErrorSample = 1.0025627266965 + ErrorMagnitude = 1.4132403311148 + ZScore = (-1.9010021304113, 2.4334629495309) + DateTime = 2008-11-17T13:50:56 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.87286215825049 + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasured.txt b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasured.txt new file mode 100644 index 0000000000000000000000000000000000000000..d957bf37540caa9e869aa0ca877fd73fc1ef2088 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasured.txt @@ -0,0 +1,20 @@ +Sample,Line,TranslatedSample,TranslatedLine,SampleDifference,LineDifference,ZScoreMin,ZScoreMax,GoodnessOfFit +-1.79769e+308 +2002.64,66.5738,2002.64,66.5738,0,0,0,0,0 +0,0,2002.64,66.5738,0,0,0,0,0 +2029.69,169.763,2029.69,169.763,0,0,0,0,0 +29.4926,169.44,2029.69,169.763,0,0,-1.83868,2.17246,0 +2017.05,268.23,2017.05,268.23,0,0,0,0,0 +16.8591,267.897,2017.05,268.23,0,0,-1.89724,1.96297,0 +2044.11,371.418,2044.11,371.418,0,0,0,0,0 +43.915,371.092,2044.11,371.418,0.999821,-0.99752,-1.70574,2.77737,0.897049 +2004.4,366.698,2004.4,366.698,0,0,0,0,0 +4.22452,366.353,2004.4,366.698,-0.999476,-2.9947,-2.08732,1.95111,0.6901 +2031.46,469.885,2031.46,469.885,0,0,0,0,0 +0,0,2031.46,469.885,0,0,0,0,0 +2018.82,568.353,2018.82,568.353,0,0,0,0,0 +18.6461,568.005,2018.82,568.353,1.00211,-0.996154,-2.9134,3.01147,0.867769 +2045.88,671.539,2045.88,671.539,0,0,0,0,0 +45.7075,671.2,2045.88,671.539,0,0,-2.08163,2.02437,0 +2006.17,666.819,2006.17,666.819,0,0,0,0,0 +6.00991,666.461,2006.17,666.819,1.00256,-0.99605,-1.901,2.43346,0.872862 diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasuredRegIgn.log b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasuredRegIgn.log new file mode 100644 index 0000000000000000000000000000000000000000..f31b00ae064fbbd86e51511397921c3a99e2de3c --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasuredRegIgn.log @@ -0,0 +1,31 @@ +pointreg: Working +0% Processed 10% Processed Group = Points + Ignored = 0 +End_Group + +Group = Measures + Validated = 0 + Registered = 1 + Unregistered = 0 + Unmeasured = 2 +End_Group + +Group = AutoRegStatistics + Total = 1 + Successful = 1 + Failure = 0 +End_Group + +Group = PatternChip1 + PatternNotEnoughData = 0 + PatternZScoreNotMet = 0 + FitChipNoData = 0 + FitChipToleranceNotMet = 0 +End_Group + +Group = SurfaceModel + SurfaceModelNotEnoughData = 0 + SurfaceModelSolutionInvalid = 0 + SurfaceModelToleranceNotMet = 0 + SurfaceModelDistanceInvalid = 0 +End_Group diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasuredRegIgn.net b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasuredRegIgn.net new file mode 100644 index 0000000000000000000000000000000000000000..88b0f1f5406994bd465f42709df4c2cdb809dd85 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasuredRegIgn.net @@ -0,0 +1,316 @@ +Object = ControlNetwork + NetworkId = NiliFossae + NetworkType = ImageToGround + TargetName = Mars + UserName = jwalldren + Created = 2008-11-17T13:51:32 + LastModified = Null + Description = "NiliFossae Jitter - use spicefit" + + Object = ControlPoint + PointType = Tie + PointId = PSP755600001 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2042.3350730536 + Line = 71.29440261681 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Automatic + Sample = 40.982541075274 + Line = 73.347661016967 + ErrorLine = -2.3650125369658 + ErrorSample = 1.142211418757 + ErrorMagnitude = 2.626391293228 + ZScore = (-1.8126794102863, 1.9209675846147) + DateTime = 2008-11-17T13:51:34 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.95303076679148 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600002 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2002.639916173 + Line = 66.57377716384 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Unmeasured + Sample = Null + Line = Null + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600003 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2029.6922678382 + Line = 169.76283611677 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 29.492607315035 + Line = 169.44015966286 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600004 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2017.0482456316 + Line = 268.23033341812 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 16.85914095714 + Line = 267.8967346471 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600005 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2044.1054109109 + Line = 371.41814410624 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 43.914972221782 + Line = 371.0923469903 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600006 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2004.403169377 + Line = 366.69783071947 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 4.2245219795274 + Line = 366.35299756514 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600007 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2031.4609997924 + Line = 469.88532934139 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Unmeasured + Sample = Null + Line = Null + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600008 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2018.8154240193 + Line = 568.35251457654 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 18.646136218309 + Line = 568.00487282638 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600009 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2045.8782485386 + Line = 671.53938906605 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 45.707486236206 + Line = 671.19986103717 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600010 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2006.1688073063 + Line = 666.81907567928 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 6.0099094607153 + Line = 666.46051161202 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasuredRegIgn.txt b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasuredRegIgn.txt new file mode 100644 index 0000000000000000000000000000000000000000..966eebbe1d6bff7577043e9c7c9e5eff8f6a3305 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredAndUnmeasuredRegIgn.txt @@ -0,0 +1,22 @@ +Sample,Line,TranslatedSample,TranslatedLine,SampleDifference,LineDifference,ZScoreMin,ZScoreMax,GoodnessOfFit +-1.79769e+308 +2042.34,71.2944,2042.34,71.2944,0,0,0,0,0 +40.9825,73.3477,2042.34,71.2944,1.14221,-2.36501,-1.81268,1.92097,0.953031 +2002.64,66.5738,2002.64,66.5738,0,0,0,0,0 +0,0,2002.64,66.5738,0,0,0,0,0 +2029.69,169.763,2029.69,169.763,0,0,0,0,0 +29.4926,169.44,2029.69,169.763,0,0,0,0,0 +2017.05,268.23,2017.05,268.23,0,0,0,0,0 +16.8591,267.897,2017.05,268.23,0,0,0,0,0 +2044.11,371.418,2044.11,371.418,0,0,0,0,0 +43.915,371.092,2044.11,371.418,0,0,0,0,0 +2004.4,366.698,2004.4,366.698,0,0,0,0,0 +4.22452,366.353,2004.4,366.698,0,0,0,0,0 +2031.46,469.885,2031.46,469.885,0,0,0,0,0 +0,0,2031.46,469.885,0,0,0,0,0 +2018.82,568.353,2018.82,568.353,0,0,0,0,0 +18.6461,568.005,2018.82,568.353,0,0,0,0,0 +2045.88,671.539,2045.88,671.539,0,0,0,0,0 +45.7075,671.2,2045.88,671.539,0,0,0,0,0 +2006.17,666.819,2006.17,666.819,0,0,0,0,0 +6.00991,666.461,2006.17,666.819,0,0,0,0,0 diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredRegIgn.log b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredRegIgn.log new file mode 100644 index 0000000000000000000000000000000000000000..f31b00ae064fbbd86e51511397921c3a99e2de3c --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredRegIgn.log @@ -0,0 +1,31 @@ +pointreg: Working +0% Processed 10% Processed Group = Points + Ignored = 0 +End_Group + +Group = Measures + Validated = 0 + Registered = 1 + Unregistered = 0 + Unmeasured = 2 +End_Group + +Group = AutoRegStatistics + Total = 1 + Successful = 1 + Failure = 0 +End_Group + +Group = PatternChip1 + PatternNotEnoughData = 0 + PatternZScoreNotMet = 0 + FitChipNoData = 0 + FitChipToleranceNotMet = 0 +End_Group + +Group = SurfaceModel + SurfaceModelNotEnoughData = 0 + SurfaceModelSolutionInvalid = 0 + SurfaceModelToleranceNotMet = 0 + SurfaceModelDistanceInvalid = 0 +End_Group diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredRegIgn.net b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredRegIgn.net new file mode 100644 index 0000000000000000000000000000000000000000..d5fe3987f6792e1efe9ac7c3dcbdf176e18035f3 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredRegIgn.net @@ -0,0 +1,296 @@ +Object = ControlNetwork + NetworkId = NiliFossae + NetworkType = ImageToGround + TargetName = Mars + UserName = jwalldren + Created = 2008-11-17T13:52:56 + LastModified = Null + Description = "NiliFossae Jitter - use spicefit" + + Object = ControlPoint + PointType = Tie + PointId = PSP755600001 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2042.3350730536 + Line = 71.29440261681 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Automatic + Sample = 40.982541075274 + Line = 73.347661016967 + ErrorLine = -2.3650125369658 + ErrorSample = 1.142211418757 + ErrorMagnitude = 2.626391293228 + ZScore = (-1.8126794102863, 1.9209675846147) + DateTime = 2008-11-17T13:52:58 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.95303076679148 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600002 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2002.639916173 + Line = 66.57377716384 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600003 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2029.6922678382 + Line = 169.76283611677 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 29.492607315035 + Line = 169.44015966286 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600004 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2017.0482456316 + Line = 268.23033341812 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 16.85914095714 + Line = 267.8967346471 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600005 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2044.1054109109 + Line = 371.41814410624 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 43.914972221782 + Line = 371.0923469903 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600006 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2004.403169377 + Line = 366.69783071947 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 4.2245219795274 + Line = 366.35299756514 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600007 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2031.4609997924 + Line = 469.88532934139 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600008 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2018.8154240193 + Line = 568.35251457654 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 18.646136218309 + Line = 568.00487282638 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600009 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2045.8782485386 + Line = 671.53938906605 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 45.707486236206 + Line = 671.19986103717 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600010 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2006.1688073063 + Line = 666.81907567928 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 6.0099094607153 + Line = 666.46051161202 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredRegIgn.txt b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredRegIgn.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7b35d734f8f44ef7ae3de64349d17abd917e1b4 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputIgnoredRegIgn.txt @@ -0,0 +1,20 @@ +Sample,Line,TranslatedSample,TranslatedLine,SampleDifference,LineDifference,ZScoreMin,ZScoreMax,GoodnessOfFit +-1.79769e+308 +2042.34,71.2944,2042.34,71.2944,0,0,0,0,0 +40.9825,73.3477,2042.34,71.2944,1.14221,-2.36501,-1.81268,1.92097,0.953031 +2002.64,66.5738,2002.64,66.5738,0,0,0,0,0 +2029.69,169.763,2029.69,169.763,0,0,0,0,0 +29.4926,169.44,2029.69,169.763,0,0,0,0,0 +2017.05,268.23,2017.05,268.23,0,0,0,0,0 +16.8591,267.897,2017.05,268.23,0,0,0,0,0 +2044.11,371.418,2044.11,371.418,0,0,0,0,0 +43.915,371.092,2044.11,371.418,0,0,0,0,0 +2004.4,366.698,2004.4,366.698,0,0,0,0,0 +4.22452,366.353,2004.4,366.698,0,0,0,0,0 +2031.46,469.885,2031.46,469.885,0,0,0,0,0 +2018.82,568.353,2018.82,568.353,0,0,0,0,0 +18.6461,568.005,2018.82,568.353,0,0,0,0,0 +2045.88,671.539,2045.88,671.539,0,0,0,0,0 +45.7075,671.2,2045.88,671.539,0,0,0,0,0 +2006.17,666.819,2006.17,666.819,0,0,0,0,0 +6.00991,666.461,2006.17,666.819,0,0,0,0,0 diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasured.log b/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasured.log new file mode 100644 index 0000000000000000000000000000000000000000..d1e7039dcfc87cd18d929f0383383d65d8492b3a --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasured.log @@ -0,0 +1,31 @@ +pointreg: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed Group = Points + Ignored = 8 +End_Group + +Group = Measures + Validated = 0 + Registered = 0 + Unregistered = 7 + Unmeasured = 2 +End_Group + +Group = AutoRegStatistics + Total = 7 + Successful = 0 + Failure = 7 +End_Group + +Group = PatternChip1 + PatternNotEnoughData = 0 + PatternZScoreNotMet = 0 + FitChipNoData = 1 + FitChipToleranceNotMet = 4 +End_Group + +Group = SurfaceModel + SurfaceModelNotEnoughData = 0 + SurfaceModelSolutionInvalid = 0 + SurfaceModelToleranceNotMet = 0 + SurfaceModelDistanceInvalid = 2 +End_Group diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasured.net b/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasured.net new file mode 100644 index 0000000000000000000000000000000000000000..c38b2f2afbf464a407396f79542da045b6c7b4fd --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasured.net @@ -0,0 +1,66 @@ +Object = ControlNetwork + NetworkId = NiliFossae + NetworkType = ImageToGround + TargetName = Mars + UserName = jwalldren + Created = 2008-11-17T13:53:50 + LastModified = Null + Description = "NiliFossae Jitter - use spicefit" + + Object = ControlPoint + PointType = Tie + PointId = PSP755600002 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2002.639916173 + Line = 66.57377716384 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Unmeasured + Sample = Null + Line = Null + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600007 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2031.4609997924 + Line = 469.88532934139 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Unmeasured + Sample = Null + Line = Null + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasured.txt b/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasured.txt new file mode 100644 index 0000000000000000000000000000000000000000..d957bf37540caa9e869aa0ca877fd73fc1ef2088 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasured.txt @@ -0,0 +1,20 @@ +Sample,Line,TranslatedSample,TranslatedLine,SampleDifference,LineDifference,ZScoreMin,ZScoreMax,GoodnessOfFit +-1.79769e+308 +2002.64,66.5738,2002.64,66.5738,0,0,0,0,0 +0,0,2002.64,66.5738,0,0,0,0,0 +2029.69,169.763,2029.69,169.763,0,0,0,0,0 +29.4926,169.44,2029.69,169.763,0,0,-1.83868,2.17246,0 +2017.05,268.23,2017.05,268.23,0,0,0,0,0 +16.8591,267.897,2017.05,268.23,0,0,-1.89724,1.96297,0 +2044.11,371.418,2044.11,371.418,0,0,0,0,0 +43.915,371.092,2044.11,371.418,0.999821,-0.99752,-1.70574,2.77737,0.897049 +2004.4,366.698,2004.4,366.698,0,0,0,0,0 +4.22452,366.353,2004.4,366.698,-0.999476,-2.9947,-2.08732,1.95111,0.6901 +2031.46,469.885,2031.46,469.885,0,0,0,0,0 +0,0,2031.46,469.885,0,0,0,0,0 +2018.82,568.353,2018.82,568.353,0,0,0,0,0 +18.6461,568.005,2018.82,568.353,1.00211,-0.996154,-2.9134,3.01147,0.867769 +2045.88,671.539,2045.88,671.539,0,0,0,0,0 +45.7075,671.2,2045.88,671.539,0,0,-2.08163,2.02437,0 +2006.17,666.819,2006.17,666.819,0,0,0,0,0 +6.00991,666.461,2006.17,666.819,1.00256,-0.99605,-1.901,2.43346,0.872862 diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasuredRegIgn.log b/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasuredRegIgn.log new file mode 100644 index 0000000000000000000000000000000000000000..f31b00ae064fbbd86e51511397921c3a99e2de3c --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasuredRegIgn.log @@ -0,0 +1,31 @@ +pointreg: Working +0% Processed 10% Processed Group = Points + Ignored = 0 +End_Group + +Group = Measures + Validated = 0 + Registered = 1 + Unregistered = 0 + Unmeasured = 2 +End_Group + +Group = AutoRegStatistics + Total = 1 + Successful = 1 + Failure = 0 +End_Group + +Group = PatternChip1 + PatternNotEnoughData = 0 + PatternZScoreNotMet = 0 + FitChipNoData = 0 + FitChipToleranceNotMet = 0 +End_Group + +Group = SurfaceModel + SurfaceModelNotEnoughData = 0 + SurfaceModelSolutionInvalid = 0 + SurfaceModelToleranceNotMet = 0 + SurfaceModelDistanceInvalid = 0 +End_Group diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasuredRegIgn.net b/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasuredRegIgn.net new file mode 100644 index 0000000000000000000000000000000000000000..5aba81dafd45653f6c101cd69ea20743c0cd531b --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasuredRegIgn.net @@ -0,0 +1,316 @@ +Object = ControlNetwork + NetworkId = NiliFossae + NetworkType = ImageToGround + TargetName = Mars + UserName = jwalldren + Created = 2008-11-17T14:00:00 + LastModified = Null + Description = "NiliFossae Jitter - use spicefit" + + Object = ControlPoint + PointType = Tie + PointId = PSP755600001 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2042.3350730536 + Line = 71.29440261681 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Automatic + Sample = 40.982541075274 + Line = 73.347661016967 + ErrorLine = -2.3650125369658 + ErrorSample = 1.142211418757 + ErrorMagnitude = 2.626391293228 + ZScore = (-1.8126794102863, 1.9209675846147) + DateTime = 2008-11-17T14:00:02 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.95303076679148 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600002 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2002.639916173 + Line = 66.57377716384 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Unmeasured + Sample = Null + Line = Null + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600003 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2029.6922678382 + Line = 169.76283611677 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 29.492607315035 + Line = 169.44015966286 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600004 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2017.0482456316 + Line = 268.23033341812 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 16.85914095714 + Line = 267.8967346471 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600005 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2044.1054109109 + Line = 371.41814410624 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 43.914972221782 + Line = 371.0923469903 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600006 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2004.403169377 + Line = 366.69783071947 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 4.2245219795274 + Line = 366.35299756514 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600007 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2031.4609997924 + Line = 469.88532934139 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Unmeasured + Sample = Null + Line = Null + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600008 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2018.8154240193 + Line = 568.35251457654 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 18.646136218309 + Line = 568.00487282638 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600009 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2045.8782485386 + Line = 671.53938906605 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 45.707486236206 + Line = 671.19986103717 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = PSP755600010 + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED4/2 + MeasureType = Estimated + Sample = 2006.1688073063 + Line = 666.81907567928 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MRO/HIRISE/889336232:10964/RED5/2 + MeasureType = Estimated + Sample = 6.0099094607153 + Line = 666.46051161202 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-06-19T15:31:04 + ChooserName = "Application autoseed" + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasuredRegIgn.txt b/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasuredRegIgn.txt new file mode 100644 index 0000000000000000000000000000000000000000..966eebbe1d6bff7577043e9c7c9e5eff8f6a3305 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/outputUnmeasuredRegIgn.txt @@ -0,0 +1,22 @@ +Sample,Line,TranslatedSample,TranslatedLine,SampleDifference,LineDifference,ZScoreMin,ZScoreMax,GoodnessOfFit +-1.79769e+308 +2042.34,71.2944,2042.34,71.2944,0,0,0,0,0 +40.9825,73.3477,2042.34,71.2944,1.14221,-2.36501,-1.81268,1.92097,0.953031 +2002.64,66.5738,2002.64,66.5738,0,0,0,0,0 +0,0,2002.64,66.5738,0,0,0,0,0 +2029.69,169.763,2029.69,169.763,0,0,0,0,0 +29.4926,169.44,2029.69,169.763,0,0,0,0,0 +2017.05,268.23,2017.05,268.23,0,0,0,0,0 +16.8591,267.897,2017.05,268.23,0,0,0,0,0 +2044.11,371.418,2044.11,371.418,0,0,0,0,0 +43.915,371.092,2044.11,371.418,0,0,0,0,0 +2004.4,366.698,2004.4,366.698,0,0,0,0,0 +4.22452,366.353,2004.4,366.698,0,0,0,0,0 +2031.46,469.885,2031.46,469.885,0,0,0,0,0 +0,0,2031.46,469.885,0,0,0,0,0 +2018.82,568.353,2018.82,568.353,0,0,0,0,0 +18.6461,568.005,2018.82,568.353,0,0,0,0,0 +2045.88,671.539,2045.88,671.539,0,0,0,0,0 +45.7075,671.2,2045.88,671.539,0,0,0,0,0 +2006.17,666.819,2006.17,666.819,0,0,0,0,0 +6.00991,666.461,2006.17,666.819,0,0,0,0,0 diff --git a/isis/src/base/apps/pointreg/assets/OUT/registerNewOnly.log b/isis/src/base/apps/pointreg/assets/OUT/registerNewOnly.log new file mode 100644 index 0000000000000000000000000000000000000000..0211c71799aa322709f723caeb6eb4053b44d641 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/registerNewOnly.log @@ -0,0 +1,45 @@ +pointreg: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed Group = Points + Ignored = 1 +End_Group + +Group = Measures + Validated = 0 + Registered = 4 + Unregistered = 5 + Unmeasured = 0 +End_Group + +Group = AutoRegStatistics + Total = 9 + Successful = 4 + Failure = 5 +End_Group + +Group = PatternChipFailures + PatternNotEnoughValidData = 1 + PatternZScoreNotMet = 2 +End_Group + +Group = FitChipFailures + FitChipNoData = 0 + FitChipToleranceNotMet = 0 +End_Group + +Group = SurfaceModelFailures + SurfaceModelNotEnoughValidData = 0 + SurfaceModelSolutionInvalid = 0 + SurfaceModelEccentricityRatioNotMet = 2 + SurfaceModelDistanceInvalid = 0 +End_Group + +Group = AutoRegistration + Algorithm = MaximumCorrelation + Tolerance = 0.9 + PatternSamples = 15 + PatternLines = 15 + MinimumZScore = 1.5 + ValidPercent = 80 + SearchSamples = 25 + SearchLines = 25 +End_Group diff --git a/isis/src/base/apps/pointreg/assets/OUT/registerNewOnly.net b/isis/src/base/apps/pointreg/assets/OUT/registerNewOnly.net new file mode 100644 index 0000000000000000000000000000000000000000..d061912f14ec0496f3c036544c07f2a649171efc --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/registerNewOnly.net @@ -0,0 +1,488 @@ +Object = ControlNetwork + NetworkId = "Default cnetadd test" + NetworkType = ImageToImage + TargetName = Mercury + UserName = jwalldren + Created = 2010-03-18T15:58:19 + LastModified = 2010-03-18T15:58:20 + Description = Test + + Object = ControlPoint + PointType = Tie + PointId = 0000001 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 651.97003024903 + Line = 12.216544898526 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 985.83359606539 + Line = 301.85268062912 + ErrorLine = -0.84256775766687 + ErrorSample = -2.335783753835 + ErrorMagnitude = 2.483104140172 + ZScore = (-2.0034478613635, 2.2620851616904) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98643155177487 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 537.37603601737 + Line = 666.87097797601 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + ZScore = (-2.1757062330938, 1.7198892329013) + DateTime = 2010-03-18T15:58:20 + ChooserName = "Application pointreg" + Ignore = True + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000002 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 599.11852932624 + Line = 6.3895258304361 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 937.52281672183 + Line = 296.9651781907 + ErrorLine = -0.42552192462102 + ErrorSample = -2.3056060471066 + ErrorMagnitude = 2.3445443379872 + ZScore = (-1.6694637829536, 3.0018517053317) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98816135664775 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 492.84553389656 + Line = 663.65648508611 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + ZScore = (-0.93673609107144, 2.9187213029442) + DateTime = 2010-03-18T15:58:20 + ChooserName = "Application pointreg" + Ignore = True + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000003 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 651.39051715658 + Line = 39.015402638171 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 984.42099675797 + Line = 327.59962581525 + ErrorLine = -0.7178460434136 + ErrorSample = -2.3307959319554 + ErrorMagnitude = 2.4388342744976 + ZScore = (-1.9655398870161, 2.7089591848142) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98144883722171 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 535.51105609178 + Line = 691.89621568813 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + ZScore = (-2.0624640853015, 1.9044963162636) + DateTime = 2010-03-18T15:58:20 + ChooserName = "Application pointreg" + Ignore = True + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000004 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 598.69665165384 + Line = 33.295458756966 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 936.11490929155 + Line = 323.01474763996 + ErrorLine = -0.50219682629228 + ErrorSample = -2.1643728084314 + ErrorMagnitude = 2.2218711272743 + ZScore = (-1.9377958814932, 3.281699600531) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98392430568853 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Automatic + Sample = 492.93959134525 + Line = 686.7247079002 + ErrorLine = 2.0414203313002 + ErrorSample = -1.829355241993 + ErrorMagnitude = 2.7411562469974 + ZScore = (-1.8053573913747, 3.6941447265008) + DateTime = 2010-03-18T15:58:20 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.95933356739263 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000005 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 545.76896108632 + Line = 27.450073761743 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 887.64556536396 + Line = 318.02175246376 + ErrorLine = 0.013100271611108 + ErrorSample = -2.1122133561236 + ErrorMagnitude = 2.1122539806811 + ZScore = (-1.7826764336141, 2.9099620790137) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98660994076081 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Automatic + Sample = 448.07813884887 + Line = 683.39088270037 + ErrorLine = 2.1446434488973 + ErrorSample = -1.5799659512102 + ErrorMagnitude = 2.6637920207632 + ZScore = (-1.9003143809838, 2.6847840031923) + DateTime = 2010-03-18T15:58:20 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.97332111563125 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000006 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 492.61600601607 + Line = 21.479938293483 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 839.10242479023 + Line = 313.1427280157 + ErrorLine = 0.30296399328051 + ErrorSample = -2.2420871737804 + ErrorMagnitude = 2.2624637181743 + ZScore = (-2.0434711253274, 4.4599620077926) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.97672753158462 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Automatic + Sample = 403.61219141834 + Line = 680.04523729693 + ErrorLine = 2.1594946885375 + ErrorSample = -1.9298903090695 + ErrorMagnitude = 2.896186098106 + ZScore = (-2.5359408722569, 1.9921906863269) + DateTime = 2010-03-18T15:58:20 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.9758029563125 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000007 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 439.2467442986 + Line = 15.387890985786 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 790.45059234978 + Line = 308.07642445756 + ErrorLine = 0.66575537569639 + ErrorSample = -2.5018478613854 + ErrorMagnitude = 2.5889134674197 + ZScore = (-2.3118534152149, 2.0955505085493) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98273189889574 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 356.67030041236 + Line = 678.7760540263 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + ZScore = (-1.4622831906697, 2.2612666599493) + DateTime = 2010-03-18T15:58:20 + ChooserName = "Application pointreg" + Ignore = True + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000008 + Ignore = True + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 385.67168330894 + Line = 9.1791310309534 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Estimated + Sample = 738.81177770483 + Line = 303.92161240047 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + ZScore = (-1.7560215125654, 2.3684067593322) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + Ignore = True + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 311.47106411062 + Line = 675.25393216829 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-03-18T09:00:05 + ChooserName = "Application cnetadd" + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000009 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 331.90409027176 + Line = 2.8614265038939 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 692.07507992819 + Line = 297.58156056399 + ErrorLine = 1.3999920671355 + ErrorSample = -2.6159945594508 + ErrorMagnitude = 2.9670533064167 + ZScore = (-1.70394396103, 1.9289612953385) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.98429149084156 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Estimated + Sample = 266.09571933301 + Line = 671.6450764237 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2010-03-18T15:58:20 + ChooserName = "Application pointreg" + Ignore = True + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = 0000010 + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771118:976000 + MeasureType = Estimated + Sample = 649.96902270705 + Line = 65.402139906388 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = 2008-12-24T10:59:15 + ChooserName = "Application autoseed" + Reference = True + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771213:976000 + MeasureType = Automatic + Sample = 982.02028107944 + Line = 353.13967032571 + ErrorLine = -0.76529600043153 + ErrorSample = -2.1189906515796 + ErrorMagnitude = 2.2529534726128 + ZScore = (-2.1045268293299, 3.2193995278892) + DateTime = 2010-03-18T08:58:13 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.97632158687133 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = MeSSEnGeR/MDIS-NAC/1/0131771303:976000 + MeasureType = Automatic + Sample = 534.8287486994 + Line = 714.44103329103 + ErrorLine = 2.168935353985 + ErrorSample = -1.9120506845132 + ErrorMagnitude = 2.8914042245791 + ZScore = (-2.0452953253288, 2.0756816017994) + DateTime = 2010-03-18T15:58:20 + ChooserName = "Application pointreg" + GoodnessOfFit = 0.96041684223308 + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/apps/pointreg/assets/OUT/registerNewOnly.txt b/isis/src/base/apps/pointreg/assets/OUT/registerNewOnly.txt new file mode 100644 index 0000000000000000000000000000000000000000..db3c4a801db603574dcbad535192c06358ba81e9 --- /dev/null +++ b/isis/src/base/apps/pointreg/assets/OUT/registerNewOnly.txt @@ -0,0 +1,29 @@ +PointId,OriginalMeasurementSample,OriginalMeasurementLine,RegisteredMeasurementSample,RegisteredMeasurementLine,SampleDifference,LineDifference,ZScoreMin,ZScoreMax,GoodnessOfFit +-1.79769e+308 +0000001,651.97,12.2165,651.97,12.2165,0,0,0,0,0 +0000001,985.834,301.853,985.834,301.853,-2.33578,-0.842568,-2.00345,2.26209,0.986432 +0000001,537.376,666.871,537.376,666.871,0,0,-2.17571,1.71989,0 +0000002,599.119,6.38953,599.119,6.38953,0,0,0,0,0 +0000002,937.523,296.965,937.523,296.965,-2.30561,-0.425522,-1.66946,3.00185,0.988161 +0000002,492.846,663.656,492.846,663.656,0,0,-0.936736,2.91872,0 +0000003,651.391,39.0154,651.391,39.0154,0,0,0,0,0 +0000003,984.421,327.6,984.421,327.6,-2.3308,-0.717846,-1.96554,2.70896,0.981449 +0000003,535.511,691.896,535.511,691.896,0,0,-2.06246,1.9045,0 +0000004,598.697,33.2955,598.697,33.2955,0,0,0,0,0 +0000004,936.115,323.015,936.115,323.015,-2.16437,-0.502197,-1.9378,3.2817,0.983924 +0000004,491.11,688.766,492.94,686.725,-1.82936,2.04142,-1.80536,3.69414,0.959334 +0000005,545.769,27.4501,545.769,27.4501,0,0,0,0,0 +0000005,887.646,318.022,887.646,318.022,-2.11221,0.0131003,-1.78268,2.90996,0.98661 +0000005,446.498,685.536,448.078,683.391,-1.57997,2.14464,-1.90031,2.68478,0.973321 +0000006,492.616,21.4799,492.616,21.4799,0,0,0,0,0 +0000006,839.102,313.143,839.102,313.143,-2.24209,0.302964,-2.04347,4.45996,0.976728 +0000006,401.682,682.205,403.612,680.045,-1.92989,2.15949,-2.53594,1.99219,0.975803 +0000007,439.247,15.3879,439.247,15.3879,0,0,0,0,0 +0000007,790.451,308.076,790.451,308.076,-2.50185,0.665755,-2.31185,2.09555,0.982732 +0000007,356.67,678.776,356.67,678.776,0,0,-1.46228,2.26127,0 +0000009,331.904,2.86143,331.904,2.86143,0,0,0,0,0 +0000009,692.075,297.582,692.075,297.582,-2.61599,1.39999,-1.70394,1.92896,0.984291 +0000009,266.096,671.645,266.096,671.645,0,0,0,0,0 +0000010,649.969,65.4021,649.969,65.4021,0,0,0,0,0 +0000010,982.02,353.14,982.02,353.14,-2.11899,-0.765296,-2.10453,3.2194,0.976322 +0000010,532.917,716.61,534.829,714.441,-1.91205,2.16894,-2.0453,2.07568,0.960417 diff --git a/isis/src/base/apps/pointreg/assets/images/discardIgnoredAndUnmeasuredGui.jpg b/isis/src/base/apps/pointreg/assets/images/discardIgnoredAndUnmeasuredGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2dbf0065fcbd348f6ff4b693cc985a479cd4e6c4 Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/images/discardIgnoredAndUnmeasuredGui.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/images/discardIgnoredAndUnmeasuredRegIgnoreGui.jpg b/isis/src/base/apps/pointreg/assets/images/discardIgnoredAndUnmeasuredRegIgnoreGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c41a451dae68cb429b446389e8d9bed6033aaa7a Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/images/discardIgnoredAndUnmeasuredRegIgnoreGui.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/images/outputIgnoredAndUnmeasuredGui.jpg b/isis/src/base/apps/pointreg/assets/images/outputIgnoredAndUnmeasuredGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3a3f9b4ae58d1af3657a33479569746719443b73 Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/images/outputIgnoredAndUnmeasuredGui.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/images/outputIgnoredAndUnmeasuredRegIgnoreGui.jpg b/isis/src/base/apps/pointreg/assets/images/outputIgnoredAndUnmeasuredRegIgnoreGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..420aecef074c16bfee15b7f539885a5c83fe126e Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/images/outputIgnoredAndUnmeasuredRegIgnoreGui.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/images/outputIgnoredGui.jpg b/isis/src/base/apps/pointreg/assets/images/outputIgnoredGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..88aa4822e141d06509ce1cb5464972d1be912874 Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/images/outputIgnoredGui.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/images/outputIgnoredRegIgnoreGui.jpg b/isis/src/base/apps/pointreg/assets/images/outputIgnoredRegIgnoreGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cb56fbed7967c2258669a09ec8afded0675a7d06 Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/images/outputIgnoredRegIgnoreGui.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/images/outputUnmeasuredGui.jpg b/isis/src/base/apps/pointreg/assets/images/outputUnmeasuredGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b964df8ea962521d92764149a8ca9326608b1105 Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/images/outputUnmeasuredGui.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/images/outputUnmeasuredRegIgnoreGui.jpg b/isis/src/base/apps/pointreg/assets/images/outputUnmeasuredRegIgnoreGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ed1f00a393f274852f779a37f31133ed5c4c71e3 Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/images/outputUnmeasuredRegIgnoreGui.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/images/registerNewOnlyGui.jpg b/isis/src/base/apps/pointreg/assets/images/registerNewOnlyGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..81bb714026ef387972b5e400b2e97d4684c4a4fa Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/images/registerNewOnlyGui.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/thumbs/discardIgnoredAndUnmeasuredGuiThumb.jpg b/isis/src/base/apps/pointreg/assets/thumbs/discardIgnoredAndUnmeasuredGuiThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68ef41176f385b00591a4341f048a1a6fa187711 Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/thumbs/discardIgnoredAndUnmeasuredGuiThumb.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/thumbs/discardIgnoredAndUnmeasuredRegIgnoreGuiThumb.jpg b/isis/src/base/apps/pointreg/assets/thumbs/discardIgnoredAndUnmeasuredRegIgnoreGuiThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bcc3a321dc5c29cc33e723065cd15a0570d69036 Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/thumbs/discardIgnoredAndUnmeasuredRegIgnoreGuiThumb.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/thumbs/outputIgnoredAndUnmeasuredGuiThumb.jpg b/isis/src/base/apps/pointreg/assets/thumbs/outputIgnoredAndUnmeasuredGuiThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..916d9480663ce8dd9d1440e673dd99e5f602831a Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/thumbs/outputIgnoredAndUnmeasuredGuiThumb.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/thumbs/outputIgnoredAndUnmeasuredRegIgnoreGuiThumb.jpg b/isis/src/base/apps/pointreg/assets/thumbs/outputIgnoredAndUnmeasuredRegIgnoreGuiThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4f3ea8d1f41431948ecdd2fa9aab7fe8bb034e15 Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/thumbs/outputIgnoredAndUnmeasuredRegIgnoreGuiThumb.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/thumbs/outputIgnoredGuiThumb.jpg b/isis/src/base/apps/pointreg/assets/thumbs/outputIgnoredGuiThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..87ae2fd410c4826b3eb310dd96675b133d817609 Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/thumbs/outputIgnoredGuiThumb.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/thumbs/outputIgnoredRegIgnoreGuiThumb.jpg b/isis/src/base/apps/pointreg/assets/thumbs/outputIgnoredRegIgnoreGuiThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e826525a3485e985f366803edc06fee719106c8a Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/thumbs/outputIgnoredRegIgnoreGuiThumb.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/thumbs/outputUnmeasuredGuiThumb.jpg b/isis/src/base/apps/pointreg/assets/thumbs/outputUnmeasuredGuiThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..219cbb1e42fed8086c9e57e76706975872162988 Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/thumbs/outputUnmeasuredGuiThumb.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/thumbs/outputUnmeasuredRegIgnoreGuiThumb.jpg b/isis/src/base/apps/pointreg/assets/thumbs/outputUnmeasuredRegIgnoreGuiThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..746c158e79b2eeeafa0c5a6cbb75a091aaa13c61 Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/thumbs/outputUnmeasuredRegIgnoreGuiThumb.jpg differ diff --git a/isis/src/base/apps/pointreg/assets/thumbs/registerNewOnlyThumb.jpg b/isis/src/base/apps/pointreg/assets/thumbs/registerNewOnlyThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4a7c03c7aad57de9cfeff1f5fa85b6a7319166bb Binary files /dev/null and b/isis/src/base/apps/pointreg/assets/thumbs/registerNewOnlyThumb.jpg differ diff --git a/isis/src/base/apps/pointreg/pointreg.cpp b/isis/src/base/apps/pointreg/pointreg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a84b34d9979720d7f3b748666f265aa9fe253df5 --- /dev/null +++ b/isis/src/base/apps/pointreg/pointreg.cpp @@ -0,0 +1,365 @@ +#define GUIHELPERS + +#include "Isis.h" + +#include "UserInterface.h" +#include "AutoReg.h" +#include "AutoRegFactory.h" +#include "Camera.h" +#include "Chip.h" +#include "ControlMeasure.h" +#include "ControlNet.h" +#include "Cube.h" +#include "CubeManager.h" +#include "iException.h" +#include "iTime.h" +#include "Progress.h" +#include "SerialNumberList.h" + +using namespace std; +using namespace Isis; + +void PrintTemp (); + +map GuiHelpers(){ + map helper; + helper ["PrintTemp"] = (void*) PrintTemp; + return helper; +} + +void IsisMain() { + + // Get user interface + UserInterface &ui = Application::GetUserInterface(); + + //Determine which points/measures to register + string registerPoints = ui.GetString("POINTS"); + string registerMeasures = ui.GetString("MEASURES"); + + // Open the files list in a SerialNumberList for + // reference by SerialNumber + SerialNumberList files(ui.GetFilename("FILES")); + + // Create a ControlNet from the input file + ControlNet inNet(ui.GetFilename("CNET")); + + if (inNet.Size() <= 0) { + std::string msg = "Input control network [" + ui.GetFilename("CNET") + "] "; + msg += "contains no points"; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + + // Create an AutoReg from the template file + Pvl pvl(ui.GetFilename("TEMPLATE")); + AutoReg *ar = AutoRegFactory::Create(pvl); + + // Create the output ControlNet + ControlNet outNet; + outNet.SetType(inNet.Type()); + outNet.SetUserName(Application::UserName()); + outNet.SetDescription(inNet.Description()); + outNet.SetCreatedDate(iTime::CurrentLocalTime()); + outNet.SetTarget(inNet.Target()); + outNet.SetNetworkId(inNet.NetworkId()); + + Progress progress; + progress.SetText("Registering Points"); + progress.SetMaximumSteps(inNet.Size()); + progress.CheckStatus(); + + int ignored=0, unmeasured=0, registered=0, unregistered=0, notintersected=0, validated=0; + + CubeManager cubeMgr; + cubeMgr.SetNumOpenCubes(50); + + // Register the points and create a new + // ControlNet containing the refined measurements + for (int i=0; iPatternChip()->TackCube(patternCM.Sample(), patternCM.Line()); + ar->PatternChip()->Load(patternCube); + + if (patternCM.IsValidated()) validated++; + if (!patternCM.IsMeasured()) continue; + if(!patternCM.IsReference()) { + patternCM.SetReference(true); + patternCM.SetChooserName("Application pointreg"); + patternCM.SetDateTime(); + } + // add reference measure + outPoint.Add(patternCM); + + // reset goodMeasureCount for this point before looping measures + int goodMeasureCount = 0; + // Register all the unvalidated measurements + for (int j = 0; j < inPoint.Size(); j++) { + // don't register the reference, go to next measure + if (j == inPoint.ReferenceIndex()){ + if (!inPoint[j].Ignore()) goodMeasureCount++; + continue; + } + // if the measurement is valid, keep it as is and go to next measure + if (inPoint[j].IsValidated()) { + validated++; + outPoint.Add(inPoint[j]); + if (!inPoint[j].Ignore()) goodMeasureCount++; + continue; + } + // if the point is unmeasured, add to output only if necessary and go to next measure + if (!inPoint[j].IsMeasured()) { + unmeasured++; + if (ui.GetBoolean("OUTPUTUNMEASURED")) { + outPoint.Add(inPoint[j]); + } + continue; + } + // if user chose not to reprocess successful measures, keep registered measure as is and go to next measure + if (registerMeasures == "ESTIMATED" && inPoint[j].Type() != ControlMeasure::Estimated) { + outPoint.Add(inPoint[j]); + if (!inPoint[j].Ignore()) goodMeasureCount++; + continue; + } + + ControlMeasure searchCM = inPoint[j]; + + // refresh pattern cube pointer to ensure it stays valid + Cube &patternCube = *cubeMgr.OpenCube(files.Filename(patternCM.CubeSerialNumber())); + Cube &searchCube = *cubeMgr.OpenCube(files.Filename(searchCM.CubeSerialNumber())); + + ar->SearchChip()->TackCube(searchCM.Sample(), searchCM.Line()); + + try { + ar->SearchChip()->Load(searchCube,*(ar->PatternChip()),patternCube); + + // If the measurements were correctly registered + // Write them to the new ControlNet + AutoReg::RegisterStatus res = ar->Register(); + + double score1, score2; + ar->ZScores(score1, score2); + searchCM.SetZScores(score1, score2); + + if (res == AutoReg::Success) { + // Check to make sure the newly calculated measure position is on the + // surface of the planet + Camera* cam = searchCube.Camera(); + bool foundLatLon = cam->SetImage(ar->CubeSample(), ar->CubeLine()); + + if (foundLatLon) { + registered++; + searchCM.SetType(ControlMeasure::Automatic); + searchCM.SetError(searchCM.Sample() - ar->CubeSample(), searchCM.Line() - ar->CubeLine()); + searchCM.SetCoordinate(ar->CubeSample(),ar->CubeLine()); + searchCM.SetGoodnessOfFit(ar->GoodnessOfFit()); + searchCM.SetChooserName("Application pointreg"); + searchCM.SetDateTime(); + searchCM.SetIgnore(false); + outPoint.Add(searchCM); + goodMeasureCount++; + } + else { + notintersected++; + searchCM.SetType(ControlMeasure::Estimated); + searchCM.SetChooserName("Application pointreg"); + searchCM.SetDateTime(); + searchCM.SetIgnore(true); + outPoint.Add(searchCM); + } + } + // Else use the original marked as "Estimated" + else { + unregistered++; + searchCM.SetType(ControlMeasure::Estimated); + + if(res == AutoReg::FitChipToleranceNotMet) { + searchCM.SetError(inPoint[j].Sample() - ar->CubeSample(), inPoint[j].Line() - ar->CubeLine()); + searchCM.SetGoodnessOfFit(ar->GoodnessOfFit()); + } + searchCM.SetChooserName("Application pointreg"); + searchCM.SetDateTime(); + searchCM.SetIgnore(true); + outPoint.Add(searchCM); + } + } + catch (iException &e) { + e.Clear(); + unregistered++; + searchCM.SetType(ControlMeasure::Estimated); + searchCM.SetChooserName("Application pointreg"); + searchCM.SetDateTime(); + searchCM.SetIgnore(true); + outPoint.Add(searchCM); + } + } + + // Jeff Anderson put in this test (Dec 2, 2008) to allow for control + // points to be good so long as at least two measure could be + // registered. When a measure can't be registered to the reference then + // that measure is set to be ignored where in the past the whole point + // was ignored + if (goodMeasureCount < 2) { + if (!outPoint.Held() && outPoint.Type() != ControlPoint::Ground) { + outPoint.SetIgnore(true); + } + } + // Otherwise, ignore=false. This is already set at the beginning of the registration process + + // Check to see if the control point has now been assigned + // to "ignore". If not, add it to the network. If so, only + // add it to the output if the OUTPUTIGNORED parameter is selected + // 2008-11-14 Jeannie Walldren + if (!outPoint.Ignore()) { + outNet.Add(outPoint); + } + else{ + ignored++; + if (ui.GetBoolean("OUTPUTIGNORED")) outNet.Add(outPoint); + } + } + } + + // If flatfile was entered, create the flatfile + // The flatfile is comma seperated and can be imported into an excel + // spreadsheet + if (ui.WasEntered("FLATFILE")) { + string fFile = Filename(ui.GetFilename("FLATFILE")).Expanded(); + ofstream os; + os.open(fFile.c_str(),ios::out); + os << "PointId,OriginalMeasurementSample,OriginalMeasurementLine," << + "RegisteredMeasurementSample,RegisteredMeasurementLine,SampleDifference," << + "LineDifference,ZScoreMin,ZScoreMax,GoodnessOfFit" << endl; + os << NULL8 << endl; + for (int i=0; iRegistrationStatistics(); + + for(int i = 0; i < arPvl.Groups(); i++) { + Application::Log(arPvl.Group(i)); + } + + // add the auto registration information to print.prt + PvlGroup autoRegTemplate = ar->RegTemplate(); + Application::Log(autoRegTemplate); + + outNet.Write(ui.GetFilename("TO")); + + delete ar; +} + +// Helper function to print out template to session log +void PrintTemp() { + UserInterface &ui = Application::GetUserInterface(); + + // Get template pvl + Pvl userTemp; + userTemp.Read(ui.GetFilename("TEMPLATE")); + + //Write template file out to the log + Isis::Application::GuiLog(userTemp); +} diff --git a/isis/src/base/apps/pointreg/pointreg.xml b/isis/src/base/apps/pointreg/pointreg.xml new file mode 100644 index 0000000000000000000000000000000000000000..6401c94b62d1f33f6110fff5c38662a9620b6453 --- /dev/null +++ b/isis/src/base/apps/pointreg/pointreg.xml @@ -0,0 +1,924 @@ + + + + Point Registration + + + + This program takes a control network and a registration algorithm and + returns a refined control network based on the algorithm. + + + + Control Networks + + + + + autoregtemplate + coreg + + + + Automatic Registration in Isis 3.0 + + + + + + + Original Version + + + Modified call to get current time to use Time class, instead of + Application class + + + Fixed typos, changed category to Control Networks and removed example + + + Fixed memory leak, progress, updated to work with AutoReg change + + + Added option to process ignored points (new parameters PROCESSIGNORED and + PROCESSVALID), Added FlatFile output parameter. Renamed IGNORED + parameter to OUTPUTIGNORED Renamed UNMEASURED parameter to + OUTPUTUNMEASURED. + + + Fixed pointreg to modify ChooserName and DateTime of measures it alters + + + Changed PROCESSIGNORED parameter name to REGISTERIGNOREDONLY. Removed + PROCESSVALID parameter since "valid" points are only processed if + REGISTERIGNOREDONLY is false. Changed extension filters for CNET, + TEMPLATE and TO from (*.txt *.lis *.lst) to *.net, *.def, and *.net, + respectively. Fixed bug in program so ignored control points only are + included in the output when the OUTPUTIGNORED parameter is selected. And + valid points are always included in the output. + + + Added examples to xml file. Fixed bug so that, when registering ignored + points, any unmeasured ControlMeasure is omitted if OUTPUTUNMEASURED=no. + Added appTest cases for new parameters. + + + Added PointId to the FlatFile output + + + Modified to allow control points to have measures which can't be + registered to not be ignored. The point is not ignored so long as at + least two measures can be registered. + + + Modified to set successfully registered measures to Ignore=False and + Ignore=True otherwise. + + + Modified code that sets point's "Ignore" Keyword to "True" only if it is + neither a ground point nor a held point. Modified app test truth files to + reflect changes. + + + Modified flatfile parameter to output the lines and samples of the + original and registered measurements, rather than the original and + reference measurements. Modified app test truth files to + reflect changes. + + + This program now uses CubeManager to more properly balance + memory usage and run time. This program should run faster + because it is leaving more cubes in memory instead of opening + and closing them each time. + + + Auto registration parameters are now placed into the print file. + + + Added REGISTERNEWONLY parameter to allow user to choose to keep + previously registered points unchanged. If checked, this will only + process new points that do not have ChooserName = "Application + pointreg". + + + Template now defaults to a def file containing all keywords with their + default values (except for ValidMinimum and ValidMaximum). + + + Parameter REGISTERNEWONLY will now only process new points that have + MeasureType = Estimated + + + Groups PointsToRegister and MeasuresToRegister have been condensed into + WhatToRegister with radio buttons allowing the user to specify whether + to process non-ignored, ignored, or all Control Points, and estimated or + all Control Measures. + + + Added a validity test for ensuring newly registered measure has a computable lat-lon position. + + + + + + + filename + input + + Input File List + + + This file contains all the files used in the control network. + + + *.txt *.lis *.lst *.list + + + + + filename + input + + Input ControlNet + + + This file contains the initial control network. + + + *.net + + + + + filename + input + + Auto Regestration Template + + + This is the auto regestration template file which contains all the information + on the registration algorithm to be used. The default template + contains every keyword AutoReg will accept set to their default + values, or common example values where defaults do not exist. + + + + PrintTemp + View Template + + This helper button will print the template to the session log + of the application + + $ISIS3DATA/base/icons/labels.png + + + + *.def + + + + + + + filename + output + + Resulting ControlNet + + + This is the output ControlNet file containing the registered information. + + + *.net + + + + + filename + output + + Text file of pointreg data + + + This file will contain data collected from the pointreg application. + The data will be comma separated and contain a line for each + measurement of all non-ignored points in the output control net. + This will include the point id, orignal sample position, original + line position, new sample position, new line position, sample + difference, line difference, minimum z-score, maximum z-score, and + goodness of fit. + + None + + *.txt *.lis *.lst *.list + + + + + boolean + + Keep Ignored ControlPoints + + + Specifies if Ignored ControlPoints will remain in the ControlNet. + + True + + + + boolean + + Keep Unmeasured ControlMeasures + + + Specifies if Unmeasured ControlMeasures will remain in the ControlNet. + + True + + + + + + string + + How to handle "Ignored" points + + + If this parameter is set to IGNORED, ignored points will be + reprocessed. It may set them to "valid" if they are acceptable in a + new tolerance range. If this parameter is set to the default value of + NOTIGNORED, only the "valid" or "non-ignored" points will be + registered. Otherwise, if it is set to ALL, every point will be + registered. Note that if certain Control Points will not be + processed, it implies that all their measures will not be + processed as well. + + NONIGNORED + + + + + + + + + string + + Which types of measures should be processed + + + If this parameter is set to ESTIMATED, only measures that have not + been successfully registered by a prior run of the pointreg + application will be processed. However, if this parameter is set to + its default of ALL, every measure, including those that have been run + through pointreg successfully, will be reprocessed. A measure is + presumed to have been "successfully registered" if the value of its + MeasureType keyword is not "Estimated", as this value will be set to + "Automatic" if registration succeeds. + + ALL + + + + + + + + + + + + Default registration settings include ignored and unmeasured points in + the output control net. + + + In this example, the pointreg application is used to register valid, i.e. + "non-ignored", points from two images and output a new control network + that includes ignored control points and unmeasured control measures. + + + + files=../IN/fileList.lis cnet=../IN/controlNet.net + template=../IN/autoRegTemplate.def + to=../OUT/outputIgnoredAndUnmeasured.net + flatfile=../OUT/outputIgnoredAndUnmeasured.txt + + + This example shows the use of pointreg with the OUTPUTIGNORED and + OUTPUTUNMEASURED parameters left with the default values of "True" and + REGISTERIGNOREDONLY with the default value of "False". This implies + that only "non-ignored" points will be registered but all control + points and control measures will be included in the output. + + + + + + + Example GUI + + + Screen shot of GUI with parameters filled in to perform point + registration that includes ignored control points and unmeasured + control measures in the output but does not register the ignore + points. + + + + + + + + + View Input File List + + + Input text file containing a list of all files in the control + network. All cubes in this list should be located in the same + directory that the application is run in. + + + FILES + + + + + View Entire Input ControlNet + + + Input text file containing the initial control network. There are + 10 control points, one is passed in as an ignored point and two + are unmeasured. + + + CNET + + + + + View Auto Registration Template + + + Input auto registration template file in PVL format containing the + registration algorithm information to be used to register the + points. + + + TEMPLATE + + + + + View resulting ControlNet + + + Output control network file containing the registered information. + Notice that all ignored points and unmeasured control measures are + kept in this network. + + + TO + + + + + View resulting flat file + + + Output flat file containing the data collected from the pointreg + application. + + + TO + + + + + View resulting application log. + + + This log is output to the screeen and contains a count of the + following: "ignore" points upon completion; validated, registered, + unregistered and unmeasured ControlMeasures; successful and failed + registrations; PatternChip and SurfaceModel statistics. + + + + + + + Register "ignored" points in a control network and include ignored and + unmeasured points in the output control net. + + + In this example, the pointreg application is used to register "ignore" + points from two images and output a new control network that includes + valid and ignored points and unmeasured control measures. + + + + files=../IN/fileList.lis cnet=../IN/controlNet.net + template=../IN/autoRegTemplate.def + to=../OUT/outputIgnoredAndUnmeasuredRegIgnored.net + flatfile=../OUT/outputIgnoredAndUnmeasuredRegIgnored.txt + registerignoredonly=yes + + + This example shows the use of pointreg with the OUTPUTIGNORED, + OUTPUTUNMEASURED and REGISTERIGNOREDONLY parameters as "True". This + implies that only "ignored" points will be registered but all control + points and control measures will be included in the output. + + + + + + + Example GUI + + + Screen shot of GUI with parameters filled in to perform ignored + point registration that includes ignored control points and + unmeasured control measures in the output but does not register + the "valid" points. + + + + + + + + + View Input File List + + + Input text file containing a list of all files in the control + network. All cubes in this list should be located in the same + directory that the application is run in. + + + FILES + + + + + View Entire Input ControlNet + + + Input text file containing the initial control network. There are + 10 control points, one is passed in as an ignored point and two + are unmeasured. + + + CNET + + + + + View Auto Registration Template + + + Input auto registration template file in PVL format containing the + registration algorithm information to be used to register the + points. + + + TEMPLATE + + + + + View resulting ControlNet + + + Output control network file containing the registered information. + Notice that all ignored points and unmeasured control measures are + kept in this network. + + + TO + + + + + View resulting flat file + + + Output flat file containing the data collected from the pointreg + application. + + + TO + + + + + View resulting application log. + + + This log is output to the screeen and contains a count of the + following: "ignore" points upon completion; validated, registered, + unregistered and unmeasured ControlMeasures; successful and failed + registrations; PatternChip and SurfaceModel statistics. + + + + + + + Register "valid" points in a control network and omit ignored points and + unmeasured measures from the output control net. + + + In this example, the pointreg application is used to register "valid" + points from two images and output a new control network that omits + ignored control points and unmeasured control measures. + + + + files=../IN/fileList.lis cnet=../IN/controlNet.net + template=../IN/autoRegTemplate.def + to=../OUT/discardIgnoredAndUnmeasured.net + flatfile=../OUT/discardIgnoredAndUnmeasured.txt + outputignored=no outputunmeasured=no + + + This example shows the use of pointreg with the OUTPUTIGNORED, + OUTPUTUNMEASURED and REGISTERIGNOREDONLY parameters set to "False". + This implies that only "valid" points will be registered and + included inthe output control network. + + + + + + + Example GUI + + + Screen shot of GUI with parameters filled in to perform point + registration that omits ignored control points and unmeasured + control measures from the output. + + + + + + + + + View Input File List + + + Input text file containing a list of all files in the control + network. All cubes in this list should be located in the same + directory that the application is run in. + + + FILES + + + + + View Entire Input ControlNet + + + Input text file containing the initial control network. There are + 10 control points, one is passed in as an ignored point and two + are unmeasured. + + + CNET + + + + + View Auto Registration Template + + + Input auto registration template file in PVL format containing the + registration algorithm information to be used to register the + points. + + + TEMPLATE + + + + + View resulting ControlNet + + + Output control network file containing the registered information. + Notice that all ignored points and unmeasured control measures are + omitted from this network. + + + TO + + + + + View resulting flat file + + + Output flat file containing the data collected from the pointreg + application. + + + TO + + + + + View resulting application log. + + + This log is output to the screeen and contains a count of the + following: "ignore" points upon completion; validated, registered, + unregistered and unmeasured ControlMeasures; successful and failed + registrations; PatternChip and SurfaceModel statistics. + + + + + + + Register "ignored" points in a control network and omit ignored and + unmeasured points in the output control net. + + + In this example, the pointreg application is used to register "ignore" + points from two images and output a new control network that omits + ignored control points and unmeasured control measures. + + + + files=../IN/fileList.lis cnet=../IN/controlNet.net + template=../IN/autoRegTemplate.def + to=../OUT/discardIgnoredAndUnmeasuredRegIgnored.net + flatfile=../OUT/discardIgnoredAndUnmeasuredRegIgnored.txt + outputignored=no outputunmeasured=no registerignoredonly=yes + + + This example shows the use of pointreg with the OUTPUTIGNORED and + OUTPUTUNMEASURED parameters set to "False" and REGISTERIGNOREDONLY + set to "True". This implies that only "ignored" points will be + registered while ignored control points and unmeasured control + measures are omitted from the output. + + + + + + + Example GUI + + + Screen shot of GUI with parameters filled in to perform ignored + point registration that omits ignored control points and + unmeasured control measures from the output. + + + + + + + + + View Input File List + + + Input text file containing a list of all files in the control + network. All cubes in this list should be located in the same + directory that the application is run in. + + + FILES + + + + + View Entire Input ControlNet + + + Input text file containing the initial control network. There are + 10 control points, one is passed in as an ignored point and two + are unmeasured. + + + CNET + + + + + View Auto Registration Template + + + Input auto registration template file in PVL format containing the + registration algorithm information to be used to register the + points. + + + TEMPLATE + + + + + View resulting ControlNet + + + Output control network file containing the registered information. + Notice that all ignored points and unmeasured control measures are + omitted from this network. + + + TO + + + + + View resulting flat file + + + Output flat file containing the data collected from the pointreg + application. + + + TO + + + + + View resulting application log. + + + This log is output to the screeen and contains a count of the + following: "ignore" points upon completion; validated, registered, + unregistered and unmeasured ControlMeasures; successful and failed + registrations; PatternChip and SurfaceModel statistics. + + + + + + + Register "new" measures in a control network only and leave previously + processed as they are in the output control net. + + + In this example, the pointreg application is used to register only "new" + measures that have been added to the control net after a prior run in + pointreg. + + + + files=../IN/fileList.lis cnet=../IN/controlNet.net + template=../IN/autoRegTemplate.def + to=../OUT/registerNewOnly.net + flatfile=../OUT/registerNewOnly.txt + registernewonly=yes + + + This example shows the use of pointreg with the REGISTERNEWONLY set + to "True". This implies that only "new" measurements will be + registered while measures that have been previously registered are + not reprocessed. + + + + + + + Example GUI + + + Screen shot of GUI with parameters filled in to perform new + measure registration only. + + + + + + + + + View Input File List + + + Input text file containing a list of all files in the control + network. All cubes in this list should be located in the same + directory that the application is run in. + + + FILES + + + + + View Entire Input ControlNet + + + Input text file containing the initial control network. There are + 10 control points, each with the first as reference, the second + previously run through pointreg, and the third added with + cnetadd. + + + CNET + + + + + View Auto Registration Template + + + Input auto registration template file in PVL format containing the + registration algorithm information to be used to register the + points. + + + TEMPLATE + + + + + View resulting ControlNet + + + Output control network file containing the registered information. + Notice that all middle points have not been changed, but the third + points have now been registered by pointreg. + + + TO + + + + + View resulting flat file + + + Output flat file containing the data collected from the pointreg + application. + + + TO + + + + + View resulting application log. + + + This log is output to the screeen and contains a count of the + following: "ignore" points upon completion; validated, registered, + unregistered and unmeasured ControlMeasures; successful and failed + registrations; PatternChip and SurfaceModel statistics. + + + + + + diff --git a/isis/src/base/apps/pointreg/tsts/Makefile b/isis/src/base/apps/pointreg/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/pointreg/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/pointreg/tsts/case01/Makefile b/isis/src/base/apps/pointreg/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59c0e431fc51d54eb375933592f088b6edf3ed58 --- /dev/null +++ b/isis/src/base/apps/pointreg/tsts/case01/Makefile @@ -0,0 +1,15 @@ +APPNAME = pointreg + +redPointregLog.txt.IGNORELINES = Processed + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/cub.lis; + $(APPNAME) files=$(OUTPUT)/cub.lis \ + cnet=$(INPUT)/red.net \ + template=$(INPUT)/autoRegTemplate.def \ + to=$(OUTPUT)/redOutputCnet.pvl \ + flatfile=$(OUTPUT)/redFlatFile.txt \ + points=nonignored > $(OUTPUT)/redPointregLog.txt; + $(RM) $(OUTPUT)/cub.lis; diff --git a/isis/src/base/apps/pointreg/tsts/outIgnoredRegIgnored/Makefile b/isis/src/base/apps/pointreg/tsts/outIgnoredRegIgnored/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..629010df2106bb6e89dd214f6521945367ba8a9f --- /dev/null +++ b/isis/src/base/apps/pointreg/tsts/outIgnoredRegIgnored/Makefile @@ -0,0 +1,15 @@ +APPNAME = pointreg + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/cub.lis; + $(APPNAME) files=$(OUTPUT)/cub.lis \ + cnet=$(INPUT)/red.net \ + template=$(INPUT)/autoRegTemplate.def \ + to=$(OUTPUT)/redOutputCnet.pvl \ + flatfile=$(OUTPUT)/redFlatFile.txt \ + outputunmeasured=no \ + points=ignored >& $(OUTPUT)/redPointregLog.txt \ + > /dev/null; + $(RM) $(OUTPUT)/cub.lis; diff --git a/isis/src/base/apps/pointreg/tsts/outIgnoredUnmeasRegIgnored/Makefile b/isis/src/base/apps/pointreg/tsts/outIgnoredUnmeasRegIgnored/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bf45082601d95fb4314f8e7a5a4856bac3337aad --- /dev/null +++ b/isis/src/base/apps/pointreg/tsts/outIgnoredUnmeasRegIgnored/Makefile @@ -0,0 +1,15 @@ +APPNAME = pointreg + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/cub.lis; + $(APPNAME) files=$(OUTPUT)/cub.lis \ + cnet=$(INPUT)/red.net \ + template=$(INPUT)/autoRegTemplate.def \ + to=$(OUTPUT)/redOutputCnet.pvl \ + flatfile=$(OUTPUT)/redFlatFile.txt \ + points=ignored \ + measures=estimated >& $(OUTPUT)/redPointregLog.txt \ + > /dev/null; + $(RM) $(OUTPUT)/cub.lis; diff --git a/isis/src/base/apps/pointreg/tsts/outUnmeasRegIgnored/Makefile b/isis/src/base/apps/pointreg/tsts/outUnmeasRegIgnored/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..000889e83bdf7399337f65b867f0869baad728ee --- /dev/null +++ b/isis/src/base/apps/pointreg/tsts/outUnmeasRegIgnored/Makefile @@ -0,0 +1,15 @@ +APPNAME = pointreg + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/cub.lis; + $(APPNAME) files=$(OUTPUT)/cub.lis \ + cnet=$(INPUT)/red.net \ + template=$(INPUT)/autoRegTemplate.def \ + to=$(OUTPUT)/redOutputCnet.pvl \ + flatfile=$(OUTPUT)/redFlatFile.txt \ + outputignored=no \ + points=ignored >& $(OUTPUT)/redPointregLog.txt \ + > /dev/null; + $(RM) $(OUTPUT)/cub.lis; diff --git a/isis/src/base/apps/pointreg/tsts/outputIgnoredOnly/Makefile b/isis/src/base/apps/pointreg/tsts/outputIgnoredOnly/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2735c5b1a108131e31b36752911d2ec4141a6e03 --- /dev/null +++ b/isis/src/base/apps/pointreg/tsts/outputIgnoredOnly/Makefile @@ -0,0 +1,15 @@ +APPNAME = pointreg + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/cub.lis; + $(APPNAME) files=$(OUTPUT)/cub.lis \ + cnet=$(INPUT)/red.net \ + template=$(INPUT)/autoRegTemplate.def \ + to=$(OUTPUT)/redOutputCnet.pvl \ + flatfile=$(OUTPUT)/redFlatFile.txt \ + outputunmeasured=no \ + points=nonignored >& $(OUTPUT)/redPointregLog.txt \ + > /dev/null; + $(RM) $(OUTPUT)/cub.lis; diff --git a/isis/src/base/apps/pointreg/tsts/outputUnmeasuredOnly/Makefile b/isis/src/base/apps/pointreg/tsts/outputUnmeasuredOnly/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..60dae0d72c8ec87b7318a6ec09f8549c7258a7c6 --- /dev/null +++ b/isis/src/base/apps/pointreg/tsts/outputUnmeasuredOnly/Makefile @@ -0,0 +1,15 @@ +APPNAME = pointreg + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/cub.lis; + $(APPNAME) files=$(OUTPUT)/cub.lis \ + cnet=$(INPUT)/red.net \ + template=$(INPUT)/autoRegTemplate.def \ + to=$(OUTPUT)/redOutputCnet.pvl \ + flatfile=$(OUTPUT)/redFlatFile.txt \ + outputignored=no \ + points=nonignored >& $(OUTPUT)/redPointregLog.txt \ + > /dev/null; + $(RM) $(OUTPUT)/cub.lis; diff --git a/isis/src/base/apps/pointreg/tsts/registerIgnoredOnly/Makefile b/isis/src/base/apps/pointreg/tsts/registerIgnoredOnly/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..682eb168eff0436e8c4b74733930314da74a7a63 --- /dev/null +++ b/isis/src/base/apps/pointreg/tsts/registerIgnoredOnly/Makefile @@ -0,0 +1,16 @@ +APPNAME = pointreg + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/cub.lis; + $(APPNAME) files=$(OUTPUT)/cub.lis \ + cnet=$(INPUT)/red.net \ + template=$(INPUT)/autoRegTemplate.def \ + to=$(OUTPUT)/redOutputCnet.pvl \ + flatfile=$(OUTPUT)/redFlatFile.txt \ + outputignored=no \ + outputunmeasured=no \ + points=ignored >& $(OUTPUT)/redPointregLog.txt \ + > /dev/null; + $(RM) $(OUTPUT)/cub.lis; diff --git a/isis/src/base/apps/pointreg/tsts/registerNewOnly/Makefile b/isis/src/base/apps/pointreg/tsts/registerNewOnly/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1df1e0353b6f100ba2c29662a5e0d0e2268061d2 --- /dev/null +++ b/isis/src/base/apps/pointreg/tsts/registerNewOnly/Makefile @@ -0,0 +1,16 @@ +APPNAME = pointreg + +outnet.pvl.IGNORELINES = DateTime + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/cub.lis; + $(APPNAME) files=$(OUTPUT)/cub.lis \ + cnet=$(INPUT)/inputcontrol.net \ + template=$(INPUT)/autoRegTemplate.def \ + to=$(OUTPUT)/outnet.pvl \ + flatfile=$(OUTPUT)/flatfile.txt \ + measures=estimated \ + > /dev/null; + $(RM) $(OUTPUT)/cub.lis; diff --git a/isis/src/base/apps/pointreg/tsts/registerValidOnly/Makefile b/isis/src/base/apps/pointreg/tsts/registerValidOnly/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0e697ae641d5dae036ed84ad098b5a6422d594c1 --- /dev/null +++ b/isis/src/base/apps/pointreg/tsts/registerValidOnly/Makefile @@ -0,0 +1,15 @@ +APPNAME = pointreg + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/cub.lis; + $(APPNAME) files=$(OUTPUT)/cub.lis \ + cnet=$(INPUT)/red.net \ + template=$(INPUT)/autoRegTemplate.def \ + to=$(OUTPUT)/redOutputCnet.pvl \ + flatfile=$(OUTPUT)/redFlatFile.txt \ + outputignored=no \ + outputunmeasured=no >& $(OUTPUT)/redPointregLog.txt \ + > /dev/null; + $(RM) $(OUTPUT)/cub.lis; diff --git a/isis/src/base/apps/poly/Makefile b/isis/src/base/apps/poly/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/poly/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/poly/poly.cpp b/isis/src/base/apps/poly/poly.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3bc2e27f94585104d31fe26ac9ae52d1d3b6ce3a --- /dev/null +++ b/isis/src/base/apps/poly/poly.cpp @@ -0,0 +1,62 @@ +#include +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void poly (Buffer &in, Buffer &out); + +double coefficients[8]; +double add; +int order; + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + + // Get user parameters + UserInterface &ui = Application::GetUserInterface(); + coefficients[0] = ui.GetDouble ("MULT1"); + coefficients[1] = ui.GetDouble ("MULT2"); + coefficients[2] = ui.GetDouble ("MULT3"); + coefficients[3] = ui.GetDouble ("MULT4"); + coefficients[4] = ui.GetDouble ("MULT5"); + coefficients[5] = ui.GetDouble ("MULT6"); + coefficients[6] = ui.GetDouble ("MULT7"); + coefficients[7] = ui.GetDouble ("MULT8"); + add = ui.GetDouble ("ADD"); + + // Determine the order + for (order=7; order>=0; order--) { + if (coefficients[order] != 0.0) break; + } + order += 1; + + // Start the processing + p.StartProcess(poly); + p.EndProcess(); +} + +// Line processing routine +void poly (Buffer &in, Buffer &out) { + // Loop for each pixel in the line. + for (int i = 0; i < in.size(); i++) { + if (IsSpecial(in[i])) { + out[i] = in[i]; + } + else { + out[i] = add; + for (int j = 1; j <= order; j++) { + out[i] += pow(in[i], j) * coefficients[j-1]; + } + } + } + +} diff --git a/isis/src/base/apps/poly/poly.xml b/isis/src/base/apps/poly/poly.xml new file mode 100644 index 0000000000000000000000000000000000000000..c30bdadea8d9acaa287aed446be10335152fb57f --- /dev/null +++ b/isis/src/base/apps/poly/poly.xml @@ -0,0 +1,188 @@ + + + + + + Perform polynomial algebra on cube + + + + This program will perform polynomial algebra on a cube up to the eighth + order. The equation used: + out = (in * mult1) + (in**2 * mult2) + ... +(in**8 *mult8) + add + + + + + Original version + + + + Ported to Isis 3.0 + + + Initialize the value of order to 0. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Added modifications to apptest by Kim + + + Modified filename parameters to be cube parameters where necessary + + + Removed exceptions and corrected math logic. + + + + + + Math and Statistics + + + + algebra + ratio + + + + + + + cube + input + + First Input cube + + + Use this parameter to select the filename. All bands selected from + the file will have the polynomial applied. + + + *.cub + + + + + cube + real + output + + Output cube + + + This file will contain the results of the polynomial. + + + + + + + double + + 1.0 + + Multiplicative constant for first order term + + This defines the multiplicative constant for the first order term. + + + + + double + + 0.0 + + Multiplicative constant second order term + + This defines the multiplicative constant for the second order term. + + + + + double + + 0.0 + + Multiplicative constant for third order term + + This defines the multiplicative constant for the third order term. + + + + + double + + 0.0 + + Multiplicative constant for fourth order term + + This defines the multiplicative constant for the fourth order term. + + + + + double + + 0.0 + + Multiplicative constant for fifth order term + + This defines the multiplicative constant for the fifth order term. + + + + + double + + 0.0 + + Multiplicative constant for sixth order term + + This defines the multiplicative constant for the sixth order term. + + + + + double + + 0.0 + + Multiplicative constant for seventh order term + + This defines the multiplicative constant for the seventh order term. + + + + + double + + 0.0 + + Multiplicative constant for eighth order term + + This defines the multiplicative constant for the eighth order term. + + + + + double + + 0.0 + + + Additive constant + + + Constant that is added to product. + + + + + + diff --git a/isis/src/base/apps/poly/tsts/Makefile b/isis/src/base/apps/poly/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/poly/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/poly/tsts/add/Makefile b/isis/src/base/apps/poly/tsts/add/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..51a8336529f4d2f04e8eadbcadd3ae2b064dee90 --- /dev/null +++ b/isis/src/base/apps/poly/tsts/add/Makefile @@ -0,0 +1,11 @@ +APPNAME = poly + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/polyTruth3.cub \ + mult1=1 \ + mult2=2 \ + mult3=3 \ + add=7 > /dev/null; diff --git a/isis/src/base/apps/poly/tsts/mult3/Makefile b/isis/src/base/apps/poly/tsts/mult3/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8a93dd82125445e047eae2d19febaff6cd956e6a --- /dev/null +++ b/isis/src/base/apps/poly/tsts/mult3/Makefile @@ -0,0 +1,10 @@ +APPNAME = poly + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/polyTruth1.cub \ + mult1=1 \ + mult2=1 \ + mult3=1 > /dev/null; diff --git a/isis/src/base/apps/poly/tsts/mult8/Makefile b/isis/src/base/apps/poly/tsts/mult8/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c78cb4f943ea82c2f31e10fa385ef6ebea08ce07 --- /dev/null +++ b/isis/src/base/apps/poly/tsts/mult8/Makefile @@ -0,0 +1,15 @@ +APPNAME = poly + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/polyTruth2.cub \ + mult1=.5 \ + mult2=.6 \ + mult3=.7 \ + mult4=.8 \ + mult5=.9 \ + mult6=1.0 \ + mult7=1.1 \ + mult8=1.2 > /dev/null; diff --git a/isis/src/base/apps/pvldiff/Makefile b/isis/src/base/apps/pvldiff/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/pvldiff/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/pvldiff/assets/images/ex1interface.jpg b/isis/src/base/apps/pvldiff/assets/images/ex1interface.jpg new file mode 100644 index 0000000000000000000000000000000000000000..69126319aa720dd392403b720c2d904e9222408e Binary files /dev/null and b/isis/src/base/apps/pvldiff/assets/images/ex1interface.jpg differ diff --git a/isis/src/base/apps/pvldiff/assets/images/ex1output.jpg b/isis/src/base/apps/pvldiff/assets/images/ex1output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da0e87a371736d920d83b72ae85ff7405806b2eb Binary files /dev/null and b/isis/src/base/apps/pvldiff/assets/images/ex1output.jpg differ diff --git a/isis/src/base/apps/pvldiff/assets/images/ex2interface.jpg b/isis/src/base/apps/pvldiff/assets/images/ex2interface.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7031fefb7f60fff5d7e34851c38ff9dca9f274b9 Binary files /dev/null and b/isis/src/base/apps/pvldiff/assets/images/ex2interface.jpg differ diff --git a/isis/src/base/apps/pvldiff/assets/images/ex2output.jpg b/isis/src/base/apps/pvldiff/assets/images/ex2output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..47d7547fd2767aa64ad3bc314a084bda56be5140 Binary files /dev/null and b/isis/src/base/apps/pvldiff/assets/images/ex2output.jpg differ diff --git a/isis/src/base/apps/pvldiff/assets/pvl1.pvl b/isis/src/base/apps/pvldiff/assets/pvl1.pvl new file mode 100644 index 0000000000000000000000000000000000000000..2c7b75f9d8b4750554b221398150311db080c6d0 --- /dev/null +++ b/isis/src/base/apps/pvldiff/assets/pvl1.pvl @@ -0,0 +1,4 @@ +Group = Architecture + Type = FruitBowl97 + Size = 5.773 +End_Group diff --git a/isis/src/base/apps/pvldiff/assets/pvl2.pvl b/isis/src/base/apps/pvldiff/assets/pvl2.pvl new file mode 100644 index 0000000000000000000000000000000000000000..da265c4f0c84b916196b539c1eedf2c722e0b418 --- /dev/null +++ b/isis/src/base/apps/pvldiff/assets/pvl2.pvl @@ -0,0 +1,4 @@ +Group = Architecture + Type = FruitBowl97 + Size = 5.774 +End_Group diff --git a/isis/src/base/apps/pvldiff/assets/thumbs/ex1interface.jpg b/isis/src/base/apps/pvldiff/assets/thumbs/ex1interface.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d421c97da4996b4e1a0a418dae74c306c6e8289d Binary files /dev/null and b/isis/src/base/apps/pvldiff/assets/thumbs/ex1interface.jpg differ diff --git a/isis/src/base/apps/pvldiff/assets/thumbs/ex1output.jpg b/isis/src/base/apps/pvldiff/assets/thumbs/ex1output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..240d5941e225e71f8abbffeacb28740312124708 Binary files /dev/null and b/isis/src/base/apps/pvldiff/assets/thumbs/ex1output.jpg differ diff --git a/isis/src/base/apps/pvldiff/assets/thumbs/ex2interface.jpg b/isis/src/base/apps/pvldiff/assets/thumbs/ex2interface.jpg new file mode 100644 index 0000000000000000000000000000000000000000..171cdafd2e8fb12d68d81fe8d685205a5a2be0da Binary files /dev/null and b/isis/src/base/apps/pvldiff/assets/thumbs/ex2interface.jpg differ diff --git a/isis/src/base/apps/pvldiff/assets/thumbs/ex2output.jpg b/isis/src/base/apps/pvldiff/assets/thumbs/ex2output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..038b1a6342c48dd40ffd76f60d4c7517f346ad73 Binary files /dev/null and b/isis/src/base/apps/pvldiff/assets/thumbs/ex2output.jpg differ diff --git a/isis/src/base/apps/pvldiff/assets/tolerance.pvl b/isis/src/base/apps/pvldiff/assets/tolerance.pvl new file mode 100644 index 0000000000000000000000000000000000000000..de4f25b949590bcd36c204a0069a7bc81672747e --- /dev/null +++ b/isis/src/base/apps/pvldiff/assets/tolerance.pvl @@ -0,0 +1,8 @@ +Group = Tolerances + Size = 0.002 +End_Group + +Group = IgnoreKeys +End_Group + +End diff --git a/isis/src/base/apps/pvldiff/pvldiff.cpp b/isis/src/base/apps/pvldiff/pvldiff.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10f2a6af99ca229b82ebfcb281830972a801bf57 --- /dev/null +++ b/isis/src/base/apps/pvldiff/pvldiff.cpp @@ -0,0 +1,206 @@ +#include "Isis.h" + +#include +#include + +#include "PvlContainer.h" +#include "Pvl.h" +#include "iException.h" + + +using namespace std; +using namespace Isis; + +bool filesMatch; +iString differenceReason; +PvlGroup tolerances; +PvlGroup ignorekeys; + +void CompareKeywords(const PvlKeyword &pvl1, const PvlKeyword &pvl2); +void CompareObjects(const PvlObject &pvl1, const PvlObject &pvl2); +void CompareGroups(const PvlGroup &pvl1, const PvlGroup &pvl2); + +void IsisMain () +{ + UserInterface &ui = Application::GetUserInterface(); + + tolerances = PvlGroup(); + ignorekeys = PvlGroup(); + differenceReason = ""; + filesMatch = true; + + const Pvl file1(ui.GetFilename("FROM")); + const Pvl file2(ui.GetFilename("FROM2")); + + if(ui.WasEntered("DIFF")) { + Pvl diffFile(ui.GetFilename("DIFF")); + + if(diffFile.HasGroup("Tolerances")) { + tolerances = diffFile.FindGroup("Tolerances"); + } + + if(diffFile.HasGroup("IgnoreKeys")) { + ignorekeys = diffFile.FindGroup("IgnoreKeys"); + } + } + + CompareObjects(file1, file2); + + PvlGroup differences("Results"); + if(filesMatch) { + differences += PvlKeyword("Compare", "Identical"); + } + else { + differences += PvlKeyword("Compare", "Different"); + differences += PvlKeyword("Reason", differenceReason); + } + + Application::Log(differences); + + if(ui.WasEntered("TO")) { + Pvl out; + out.AddGroup(differences); + out.Write(ui.GetFilename("TO")); + } + + differenceReason = ""; +} + +void CompareKeywords(const PvlKeyword &pvl1, const PvlKeyword &pvl2) { + if(pvl1.Name().compare( pvl2.Name() ) != 0) { + filesMatch = false; + differenceReason = "Keyword '" + pvl1.Name() + "' does not match keyword '" + pvl2.Name() + "'"; + } + + if(pvl1.Size() != pvl2.Size()) { + filesMatch = false; + differenceReason = "Keyword '" + pvl1.Name() + "' size does not match."; + return; + } + + if (tolerances.HasKeyword(pvl1.Name()) && + tolerances[pvl1.Name()].Size() > 1 && + pvl1.Size() != tolerances[pvl1.Name()].Size()) { + string msg = "Size of keyword '" + pvl1.Name() + "' does not match with "; + msg += "its number of tolerances in the DIFF file."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + if (ignorekeys.HasKeyword(pvl1.Name()) && + ignorekeys[pvl1.Name()].Size() > 1 && + pvl1.Size() != ignorekeys[pvl1.Name()].Size()) { + string msg = "Size of keyword '" + pvl1.Name() + "' does not match with "; + msg += "its number of ignore keys in the DIFF file."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + for(int i = 0; i < pvl1.Size() && filesMatch; i++) { + iString val1 = pvl1[i]; + iString val2 = pvl2[i]; + iString unit1 = pvl1.Unit(i); + iString unit2 = pvl2.Unit(i); + + int ignoreIndex = 0; + if (ignorekeys.HasKeyword(pvl1.Name()) && ignorekeys[pvl1.Name()].Size() > 1) { + ignoreIndex = i; + } + + try { + if(!ignorekeys.HasKeyword(pvl1.Name()) || + ignorekeys[pvl1.Name()][ignoreIndex] == "false") { + + if(!unit1.Equal(unit2)) { + filesMatch = false; + differenceReason = "Keyword '" + pvl1.Name() + "': units do not match."; + return; + } + + double tolerance = 0.0; + double difference = abs((double)val1 - (double)val2); + + if(tolerances.HasKeyword(pvl1.Name())) { + tolerance = (tolerances[pvl1.Name()].Size() == 1) ? + tolerances[pvl1.Name()][0] : tolerances[pvl1.Name()][i]; + } + + if(difference > tolerance) { + filesMatch = false; + if (pvl1.Size() == 1) { + differenceReason = "Keyword '" + pvl1.Name() + "': difference is " + + iString(difference); + } + else { + differenceReason = "Keyword '" + pvl1.Name() + "' at index " + + iString(i) + ": difference is " + iString(difference); + } + differenceReason += " (tolerance is " + iString(tolerance) + ")"; + } + } + } + catch(iException e) { + iException::Clear(); + + if(!val1.Equal(val2)) { + filesMatch = false; + differenceReason = "Keyword '" + pvl1.Name() + "': values do not match."; + } + } + } +} + +void CompareObjects(const PvlObject &pvl1, const PvlObject &pvl2) { + if(pvl1.Name().compare( pvl2.Name() ) != 0) { + filesMatch = false; + differenceReason = "Object " + pvl1.Name() + " does not match " + pvl2.Name(); + } + + if(pvl1.Keywords() != pvl2.Keywords()) { + filesMatch = false; + differenceReason = "Object " + pvl1.Name() + " has varying keyword counts."; + } + + if(pvl1.Groups() != pvl2.Groups()) { + filesMatch = false; + differenceReason = "Object " + pvl1.Name() + " has varying group counts."; + } + + if(pvl1.Objects() != pvl2.Objects()) { + filesMatch = false; + differenceReason = "Object " + pvl1.Name() + " has varying object counts."; + } + + if(!filesMatch) { + return; + } + + for(int keyword = 0; keyword < pvl1.Keywords() && filesMatch; keyword++) { + CompareKeywords(pvl1[keyword], pvl2[keyword]); + } + + for(int object = 0; object < pvl1.Objects() && filesMatch; object++) { + CompareObjects(pvl1.Object(object), pvl2.Object(object)); + } + + for(int group = 0; group < pvl1.Groups() && filesMatch; group++) { + CompareGroups(pvl1.Group(group), pvl2.Group(group)); + } + + if(!filesMatch && pvl1.Name().compare("Root") != 0) { + differenceReason = "Object " + pvl1.Name() + ": " + differenceReason; + } +} + +void CompareGroups(const PvlGroup &pvl1, const PvlGroup &pvl2) { + if(pvl1.Keywords() != pvl2.Keywords()) { + filesMatch = false; + return; + } + + for(int keyword = 0; keyword < pvl1.Keywords() && filesMatch; keyword++) { + CompareKeywords(pvl1[keyword], pvl2[keyword]); + } + + if(!filesMatch) { + differenceReason = "Group " + pvl1.Name() + ": " + differenceReason; + } +} diff --git a/isis/src/base/apps/pvldiff/pvldiff.xml b/isis/src/base/apps/pvldiff/pvldiff.xml new file mode 100644 index 0000000000000000000000000000000000000000..7cfad6f709146979c3f2c7bff346433d76e4a3b5 --- /dev/null +++ b/isis/src/base/apps/pvldiff/pvldiff.xml @@ -0,0 +1,191 @@ + + + + + Compare two pvl files + + + This program will compare two PVL files with or without a tolerance. + The purpose of this program is for application tests, that output a Pvl formatted file, to be able + to specify tolerances in numerical values of keywords. + + + + + Original version + + + Added capabilities for unique tolerances and ignore keys for individual + array elements within keywords + + + + + System + + + + + + filename + input + + Input PVL file 1 + + + + + *.pvl *.txt + + + + + filename + input + + Input PVL file 2 + + + + + *.pvl *.txt + + + + + filename + input + None + + Input PVL tolerance file + + + This is used to specify tolerances between the two input file. If this file is not specified, the two Pvl files must match exactly. + See Isis Application and Category Test How-to for information about the tolerance file. + + + *.pvl *.txt *.pvl.DIFF + + + + + filename + output + None + + Differences + + + This will output the differences to a text file. + + + *.txt + + + + + + + + Basic Comparison + + This example will cover doing a basic difference between two pvl files and how to interpret the results. + + + from=pvl1.pvl from2=pvl2.pvl + Differencing pvl1.pvl and pvl2.pvl + + + + + Running this program with pvl1.pvl and pvl2.pvl + + This shows how to run this program to compare the two pvl files pvl1.pvl and pvl2.pvl. + + + + + + + + pvl1.pvl + + This is the file used in the input parameter FROM. It will be compared with pvl2.pvl. + + FROM + + + pvl2.pvl + + This is the file used in the input parameter FROM2. It will be compared with pvl1.pvl. + + FROM2 + + + + + The results from comparing pvl1.pvl and pvl2.pvl + + This is the output after running this program on pvl1.pvl and pvl2.pvl. Since the input pvl files differed, it shows the first difference encountered. + Notice it also says exactly where the difference was found and, if numerical, the tolerance. + + + + + + + Basic Comparison With Tolerance + + This example will cover doing a basic difference between two pvl files with a tolerance file. + + + from=pvl1.pvl from2=pvl2.pvl diff=tolerance.pvl + Differencing pvl1.pvl and pvl2.pvl + + + + + Running this program with pvl1.pvl and pvl2.pvl with tolerance + + This shows how to run this program to compare the two pvl files pvl1.pvl and pvl2.pvl using a tolerance file. + + + + + + + + pvl1.pvl + + This is the file used in the input parameter FROM. It will be compared with pvl2.pvl. + + FROM + + + pvl2.pvl + + This is the file used in the input parameter FROM2. It will be compared with pvl1.pvl. + + FROM2 + + + tolerance.pvl + + This is the file used in the input parameter DIFF. It specifies the tolerance for the two files. + + DIFF + + + + + The results from comparing pvl1.pvl and pvl2.pvl + + This is the output after running this program on pvl1.pvl and pvl2.pvl. The input pvl files differed, + but not more than specified by the tolerance so the results came back identicle. + + + + + + + diff --git a/isis/src/base/apps/pvldiff/tsts/Makefile b/isis/src/base/apps/pvldiff/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/pvldiff/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/pvldiff/tsts/default/Makefile b/isis/src/base/apps/pvldiff/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fb081d9011330171153bc4f70cc3b692b9ed9fa8 --- /dev/null +++ b/isis/src/base/apps/pvldiff/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME = pvldiff + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/pvl1.pvl FROM2=$(INPUT)/pvl2.pvl \ + TO=$(OUTPUT)/diff_simp.pvl > /dev/null; + $(APPNAME) FROM=$(INPUT)/pvl2.pvl FROM2=$(INPUT)/pvl3.pvl \ + TO=$(OUTPUT)/diff_units.pvl > /dev/null; + $(APPNAME) FROM=$(INPUT)/pvl4.pvl FROM2=$(INPUT)/pvl5.pvl \ + TO=$(OUTPUT)/diff_complex.pvl > /dev/null; diff --git a/isis/src/base/apps/pvldiff/tsts/tolerance/Makefile b/isis/src/base/apps/pvldiff/tsts/tolerance/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..405926ae5af45e03ee7f51be87dab949ec282928 --- /dev/null +++ b/isis/src/base/apps/pvldiff/tsts/tolerance/Makefile @@ -0,0 +1,7 @@ +APPNAME = pvldiff + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/pvl1.pvl FROM2=$(INPUT)/pvl2.pvl \ + DIFF=$(INPUT)/tolerance.pvl TO=$(OUTPUT)/diff.txt > /dev/null; diff --git a/isis/src/base/apps/ratio/Makefile b/isis/src/base/apps/ratio/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/ratio/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/ratio/ratio.cpp b/isis/src/base/apps/ratio/ratio.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6634f00120b1742feade7092ff320617bfddd12 --- /dev/null +++ b/isis/src/base/apps/ratio/ratio.cpp @@ -0,0 +1,44 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void ratio (vector &in, + vector &out); + +void IsisMain() { + ProcessByLine p; + p.SetInputCube("NUMERATOR"); + p.SetInputCube("DENOMINATOR"); + p.SetOutputCube ("TO"); + p.StartProcess(ratio); + p.EndProcess(); +} + +// Line processing routine +void ratio (vector &in, + vector &out) { + Buffer &num = *in[0]; + Buffer &den = *in[1]; + Buffer &rat = *out[0]; + + // Loop for each pixel in the line. Check + // for special pixels and if any are found the + // output will be set to NULL. + for (int i=0; i + + + + Divide two cubes + + + + This program divides two cubes. It operates in one of two manners: 1) the + denominator cube must have the same number of bands as the numerator cube + or 2) the denominator cube must have exactly one band. In the former case, + corresponding bands are divided, for example, band one is divided by + band one, band two by band two, and so on. In the later case, all bands + in the numerator cube are divided by the single band in the denominator + cube. + Special pixels values are handled identically in both cases. Whenever a + special pixel occurs, in either the numerator or denominator, the output + pixel is set to NULL. Likewise, if the denominator is zero, the output + is set to NULL. + + + + Math and Statistics + + + + + Original version + + + Converted to Isis 3.0 + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Changed NUM, DEN and To from type filename to type cube + + + Modified filename parameters to be cube parameters where necessary + + + + + + ratio + cosi + + + + + + cube + input + + Numerator cube + + + The numerator cube. All pixels in this cube will be divided by + corresponding pixels in the denominator cube. + + + *.cub + + + + + cube + input + + Denominator cube + + + The denominator cube. The number of bands in this cube must + match the numerator cube or be exactly one. In the former case, + a band-by-band division occurs. In the later, each numerator + band is divided by the single denominator band. + + + *.cub + + + + + cube + real + output + + Output cube + + + The output cube containing the results of the ratio. A NULL + pixel will be output when either of the numerator or denominator + pixels is special. Similarly, a NULL will be output if the + denominator pixel is zero. + + + *.cub + + + + + + + + Dividing one band by one band + + This example presents dividing one band in a cube by a single band. + In this case, we divide band 5 by band 4 in peaks.cub and + generate a single band + output cube. Note that the file (peaks.cub) does not have to be + the same name for NUMERATOR and DENOMINATOR so long as the + spatial size (samples and lines) match between the given files. + + + + numerator=peaks.cub:5 denominator=peaks.cub:4 to=ratio.cub + + + + + + + Dividing multiple bands by one band + + This example presents dividing all bands in a cube by an individual + band. In this case, the seven bands in peaks.cub are divided + by band 4 and the results output to ratio.cub. + + + + numerator=peaks.cub denominator=peaks.cub:4 to=ratio.cub + + + + + + + + diff --git a/isis/src/base/apps/ratio/tsts/Makefile b/isis/src/base/apps/ratio/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/ratio/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/ratio/tsts/default/Makefile b/isis/src/base/apps/ratio/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bdd998c05094a9702b5e604d1f0d5ba1d9a0ca48 --- /dev/null +++ b/isis/src/base/apps/ratio/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = ratio + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) num=$(INPUT)/isisTruth.cub+1 \ + den=$(INPUT)/isisTruth.cub+2 \ + to=$(OUTPUT)/ratioTruth1.cub > /dev/null; diff --git a/isis/src/base/apps/raw2isis/Makefile b/isis/src/base/apps/raw2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/raw2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/raw2isis/assets/images/out.jpg b/isis/src/base/apps/raw2isis/assets/images/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..96d6beda2091f34813e3f3535fd08f3d2103baee Binary files /dev/null and b/isis/src/base/apps/raw2isis/assets/images/out.jpg differ diff --git a/isis/src/base/apps/raw2isis/assets/images/raw2isisGUI.jpg b/isis/src/base/apps/raw2isis/assets/images/raw2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fb934a02f22d2077ee2d1cb2239b7224e0018c0f Binary files /dev/null and b/isis/src/base/apps/raw2isis/assets/images/raw2isisGUI.jpg differ diff --git a/isis/src/base/apps/raw2isis/assets/input.raw b/isis/src/base/apps/raw2isis/assets/input.raw new file mode 100644 index 0000000000000000000000000000000000000000..cc2d90fd0c2ab4df698017137c5a7a918b2d03eb Binary files /dev/null and b/isis/src/base/apps/raw2isis/assets/input.raw differ diff --git a/isis/src/base/apps/raw2isis/assets/thumbs/out.jpg b/isis/src/base/apps/raw2isis/assets/thumbs/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b30538ad169cea18b123ce148969f1dbcf5d8a0a Binary files /dev/null and b/isis/src/base/apps/raw2isis/assets/thumbs/out.jpg differ diff --git a/isis/src/base/apps/raw2isis/assets/thumbs/raw2isisGUI.jpg b/isis/src/base/apps/raw2isis/assets/thumbs/raw2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..381b79a7eff3a2df37bddde6acf43f991ee5d3e2 Binary files /dev/null and b/isis/src/base/apps/raw2isis/assets/thumbs/raw2isisGUI.jpg differ diff --git a/isis/src/base/apps/raw2isis/raw2isis.cpp b/isis/src/base/apps/raw2isis/raw2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d31fda728f9728a177092734dc8bbc0c0d8ed6ca --- /dev/null +++ b/isis/src/base/apps/raw2isis/raw2isis.cpp @@ -0,0 +1,44 @@ +//************************************************************************ +// See Full documentation in raw2isis.xml +//************************************************************************ +#include "Isis.h" +#include "ProcessImport.h" + +#include "UserInterface.h" +#include "Filename.h" + +using namespace std; +using namespace Isis; + +// Line-by-Line from raw file +void raw2isis (Buffer &out); + +void IsisMain () +{ + ProcessImport p; + + UserInterface &ui = Application::GetUserInterface (); + p.SetDimensions(ui.GetInteger("SAMPLES"),ui.GetInteger("LINES"), + ui.GetInteger("BANDS")); + p.SetFileHeaderBytes(ui.GetInteger("SKIP")); + p.SetPixelType(PixelTypeEnumeration(ui.GetString("BITTYPE"))); + p.SetByteOrder(ByteOrderEnumeration(ui.GetString("BYTEORDER"))); + p.SetInputFile (ui.GetFilename("FROM")); + p.SetOutputCube("TO"); + + if (ui.GetBoolean("SETNULLRANGE")) { + p.SetNull(ui.GetDouble("NULLMIN"),ui.GetDouble("NULLMAX")); + } + if (ui.GetBoolean("SETHRSRANGE")) { + p.SetHRS(ui.GetDouble("HRSMIN"),ui.GetDouble("HRSMAX")); + } + if (ui.GetBoolean("SETLRSRANGE")) { + p.SetLRS(ui.GetDouble("LRSMIN"),ui.GetDouble("LRSMAX")); + } + + p.StartProcess (); + p.EndProcess (); + + return; +} + diff --git a/isis/src/base/apps/raw2isis/raw2isis.xml b/isis/src/base/apps/raw2isis/raw2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..bc831a3d406d4d6defe02339ca5698975038231e --- /dev/null +++ b/isis/src/base/apps/raw2isis/raw2isis.xml @@ -0,0 +1,406 @@ + + + + + + Import raw cube into Isis format + + + + This program will import a raw image into an Isis cube. Bytes will be swapped if + necessary and there is an option to create special pixels. + + + + + Original version + + + + Ported to Isis 3.0 + + + Move from Utility to Import/Export category. + + + Move from Import/Export to Import and Export category. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Modified to use the new IsisImport object, which simplified the code. + + + Modified call to StartProcess to match new IsisImport class. + + + Modified due to refactor of IsisImport class + + + Updated documentation + + + Updated application test + + + Added ability to change special pixel ranges. Added example. + + + Added the UNSIGNEDWORD option for param BITTYPE. + + + + + Import and Export + + + + + + filename + input + + Input raw file + + + Use this parameter to select the raw filename. If multi-band, it + is assumed to be in band sequential order. + + + *.raw + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + + + + integer + Number of samples in raw image + + This defines the number of samples in the raw image. + + + + + integer + Number of lines in raw image + + This defines the number of lines in the raw image. + + + + + integer + + 1 + + Number of bands in raw image + + This defines the number of bands in the raw image. If + greater than 1, the image is assumed to be in band sequential + order. + + + + + integer + + 0 + + Number of bytes to skip before reading data + + This defines the number of bytes to skip before the actual image + data is read. This would be for raw images with header data. + + + + + + + string + + UNSIGNEDBYTE + + Bit type of input data + + Bit type of data: + 8 bit, + 16 bit signed, or + 32 bit + + + + + + + + + + + string + + LSB + + Byte order of data + + Indicates the byte order of the data. Options are LSB (Least + Significant Byte firs) or MSB (Most Significant Byte first). + + + + + + + + + + + boolean + + NO + + Create special pixel values + + If this option is used input raw pixels below minimum and + above maximum will be converted to LRS and HRS respectively. Otherwise + pixels in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit real will + cause 0 and 255 to be actual values. If left as 8-bit then 0 will + be NULL and 255 will be HRS. + + + NULLMIN + NULLMAX + + + + + double + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + SETNULLRANGE + + + + double + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + SETNULLRANGE + + + + + boolean + + NO + + Create special pixel values + + If this option is used input raw pixels below minimum and + above maximum will be converted to LRS and HRS respectively. Otherwise + pixels in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit real will + cause 0 and 255 to be actual values. If left as 8-bit then 0 will + be NULL and 255 will be HRS. + + + HRSMIN + HRSMAX + + + + + double + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + SETHRSRANGE + + + + double + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + SETHRSRANGE + + + + + boolean + + NO + + Create special pixel values + + If this option is used input raw pixels below minimum and + above maximum will be converted to LRS and HRS respectively. Otherwise + pixels in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit real will + cause 0 and 255 to be actual values. If left as 8-bit then 0 will + be NULL and 255 will be HRS. + + + LRSMIN + LRSMAX + + + + + double + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + SETLRSRANGE + + + + double + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + SETLRSRANGE + + + + + + + + + Using raw2isis with default parameters + + + The use of raw2isis to ingest raw data and output Isis3 cubes. + + + + from= input.raw + to= out.cub + samples=126 + lines=126 + bands=2 + bittype=real + + + This example shows the use of raw2isis create an Isis3 cube. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters + + + + + + + + + + Raw input file. + + + This is the raw data + + FROM + + + + + + + Final output image after the conversion + + + Converts from PDS format to a Isis3 cube. + + + TO + + + + + diff --git a/isis/src/base/apps/raw2isis/tsts/Makefile b/isis/src/base/apps/raw2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/raw2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/raw2isis/tsts/case01/Makefile b/isis/src/base/apps/raw2isis/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..970045160432f64078af45ee773a08dd66101b5c --- /dev/null +++ b/isis/src/base/apps/raw2isis/tsts/case01/Makefile @@ -0,0 +1,13 @@ +APPNAME = raw2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.dat \ + to=$(OUTPUT)/raw2isisTruth1.cub \ + samples=126 \ + lines=126 \ + bands=2 \ + skip=0 \ + bittype=real \ + byteorder=lsb > /dev/null; diff --git a/isis/src/base/apps/raw2isis/tsts/case02/Makefile b/isis/src/base/apps/raw2isis/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..051f24b752d0a3dea791a6abfa0877577b260084 --- /dev/null +++ b/isis/src/base/apps/raw2isis/tsts/case02/Makefile @@ -0,0 +1,22 @@ +APPNAME = raw2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.dat \ + to=$(OUTPUT)/raw2isisTruth2.cub \ + samples=126 \ + lines=126 \ + bands=2 \ + skip=0 \ + bittype=real \ + byteorder=lsb \ + SETHRSRANGE=yes \ + HRSMIN=20 \ + HRSMAX=200 \ + SETLRSRANGE=yes \ + LRSMIN=-1e20 \ + LRSMAX=-1e18 \ + SETNULLRANGE=yes \ + NULLMIN=-1e-20 \ + NULLMAX=-1e-22 > /dev/null; diff --git a/isis/src/base/apps/raw2isis/tsts/u16bit/Makefile b/isis/src/base/apps/raw2isis/tsts/u16bit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7b647c3d1d0cd99e9bdc784e90ba1a8edfc9a9cf --- /dev/null +++ b/isis/src/base/apps/raw2isis/tsts/u16bit/Makefile @@ -0,0 +1,8 @@ +APPNAME = raw2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isis2rawTruth3.raw to=$(OUTPUT)/raw2isisTruth.cub \ + samples=126 lines=126 bittype=unsignedword \ + > /dev/null; diff --git a/isis/src/base/apps/reduce/Makefile b/isis/src/base/apps/reduce/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/reduce/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/reduce/assets/images/peaks.jpg b/isis/src/base/apps/reduce/assets/images/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..dcce3323b71913370521f8b5be90c4d51cf6131c Binary files /dev/null and b/isis/src/base/apps/reduce/assets/images/peaks.jpg differ diff --git a/isis/src/base/apps/reduce/assets/images/scale.jpg b/isis/src/base/apps/reduce/assets/images/scale.jpg new file mode 100755 index 0000000000000000000000000000000000000000..783fea8f4c1c10e9d974dac7b787c2d6685ab915 Binary files /dev/null and b/isis/src/base/apps/reduce/assets/images/scale.jpg differ diff --git a/isis/src/base/apps/reduce/assets/images/scaleGui.jpg b/isis/src/base/apps/reduce/assets/images/scaleGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..15eb27c7dc47f9be978f265e75c263b4321c63c5 Binary files /dev/null and b/isis/src/base/apps/reduce/assets/images/scaleGui.jpg differ diff --git a/isis/src/base/apps/reduce/assets/images/total.jpg b/isis/src/base/apps/reduce/assets/images/total.jpg new file mode 100644 index 0000000000000000000000000000000000000000..024ad360e11d185fa928e6c1ddf9d6a1c62a1adc Binary files /dev/null and b/isis/src/base/apps/reduce/assets/images/total.jpg differ diff --git a/isis/src/base/apps/reduce/assets/images/totalGui.jpg b/isis/src/base/apps/reduce/assets/images/totalGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..532e2d28ef5fc47fa6a41870acebcde253d4b3eb Binary files /dev/null and b/isis/src/base/apps/reduce/assets/images/totalGui.jpg differ diff --git a/isis/src/base/apps/reduce/assets/thumbs/peaks.jpg b/isis/src/base/apps/reduce/assets/thumbs/peaks.jpg new file mode 100755 index 0000000000000000000000000000000000000000..3879ff7fbd1a341b5e9cf7baa338eabb511bfb47 Binary files /dev/null and b/isis/src/base/apps/reduce/assets/thumbs/peaks.jpg differ diff --git a/isis/src/base/apps/reduce/assets/thumbs/scale.jpg b/isis/src/base/apps/reduce/assets/thumbs/scale.jpg new file mode 100755 index 0000000000000000000000000000000000000000..5fbe960ba791ab2d05c1022868160baa75a3bade Binary files /dev/null and b/isis/src/base/apps/reduce/assets/thumbs/scale.jpg differ diff --git a/isis/src/base/apps/reduce/assets/thumbs/scaleGui.jpg b/isis/src/base/apps/reduce/assets/thumbs/scaleGui.jpg new file mode 100755 index 0000000000000000000000000000000000000000..c80e81128e0f55ab854b457163bdcdf3268a565c Binary files /dev/null and b/isis/src/base/apps/reduce/assets/thumbs/scaleGui.jpg differ diff --git a/isis/src/base/apps/reduce/assets/thumbs/total.jpg b/isis/src/base/apps/reduce/assets/thumbs/total.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d576f09dbafdce094bd54c7a7b19551de852c398 Binary files /dev/null and b/isis/src/base/apps/reduce/assets/thumbs/total.jpg differ diff --git a/isis/src/base/apps/reduce/assets/thumbs/totalGui.jpg b/isis/src/base/apps/reduce/assets/thumbs/totalGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5f9af11b87f72cf5ddc83886a2dab462700deb6f Binary files /dev/null and b/isis/src/base/apps/reduce/assets/thumbs/totalGui.jpg differ diff --git a/isis/src/base/apps/reduce/reduce.cpp b/isis/src/base/apps/reduce/reduce.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1ec4ed4a5e7f548c10aaff1f2ae179b514cc92b --- /dev/null +++ b/isis/src/base/apps/reduce/reduce.cpp @@ -0,0 +1,287 @@ +#include "Isis.h" +#include "AlphaCube.h" +#include "iException.h" +#include "iString.h" +#include "LineManager.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "SubArea.h" + +#include + +using namespace std; +using namespace Isis; + +void average (Buffer &out); +void nearest (Buffer &out); + +Cube * cube; +LineManager *in; +double sscale,lscale; +double vper; +int ins,inl,inb; +int ons,onl; +double line; +int iline; +int sb; +string replaceMode; +std::vector bands; + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + cube = new Cube; + + // To propogate labels, set input cube, + // this cube will be cleared after output cube is set. + p.SetInputCube("FROM"); + + // Setup the input and output cubes + UserInterface &ui = Application::GetUserInterface(); + replaceMode = ui.GetAsString("VPER_REPLACE"); + CubeAttributeInput cai(ui.GetAsString("FROM")); + bands = cai.Bands(); + + string from = ui.GetFilename ("FROM"); + cube->Open(from); + + ins = cube->Samples(); + inl = cube->Lines(); + inb = bands.size(); + + if (inb == 0) { + inb = cube->Bands(); + for (int i = 1; i<=inb; i++) { + bands.push_back((iString)i); + } + } + + string alg = ui.GetString("ALGORITHM"); + vper = ui.GetDouble ("VALIDPER")/100.; + + if (ui.GetString("MODE") == "TOTAL") { + ons = ui.GetInteger ("ONS"); + onl = ui.GetInteger ("ONL"); + sscale = (double)ins / (double)ons; + lscale = (double)inl / (double)onl; + } + else { + sscale = ui.GetDouble ("SSCALE"); + lscale = ui.GetDouble ("LSCALE"); + ons = (int)ceil ((double)ins/sscale); + onl = (int)ceil ((double)inl/lscale); + } + + if (ons > ins || onl > inl) { + string msg = "Number of output samples/lines must be less than or equal"; + msg = msg + " to the input samples/lines."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Allocate output file + Cube *ocube = NULL; + try { + ocube = p.SetOutputCube ("TO",ons,onl,inb); + // Our processing routine only needs 1 + // the original set was for info about the cube only + p.ClearInputCubes(); + } catch (iException &e) { + // If there is a problem, catch it and close the cube so it isn't open next time around + cube->Close(); + throw e; + } + + // Create all necessary buffers + in = new LineManager (*cube); + + // Start the processing + line = 1.0; + iline = 1; + sb = 0; + if (alg == "AVERAGE") p.StartProcess(average); + if (alg == "NEAREST") p.StartProcess(nearest); + + // Construct a label with the results + PvlGroup results("Results"); + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("StartingLine", "1"); + results += PvlKeyword ("StartingSample", "1"); + results += PvlKeyword ("EndingLine", inl); + results += PvlKeyword ("EndingSample", ins); + results += PvlKeyword ("LineIncrement", lscale); + results += PvlKeyword ("SampleIncrement", sscale); + results += PvlKeyword ("OutputLines", onl); + results += PvlKeyword ("OutputSamples", ons); + + // Update the Mapping, Instrument, and AlphaCube groups in the output + // cube label + SubArea s; + s.SetSubArea(inl,ins,1,1,inl,ins,lscale,sscale); + s.UpdateLabel(cube,ocube,results); + + // Cleanup + p.EndProcess(); + delete in; + cube->Close(); + + // Write the results to the log + Application::Log(results); +} + +// Line processing routine for averaging algorithm +void average (Buffer &out) { + static double *sinctab; + static double *sum; + static double *npts; + static double *sum2; + static double *npts2; + + double rline = (double)out.Line() * lscale; + + if (out.Line() == 1 && out.Band() == 1) { + sinctab = new double[ons]; + sum = new double[ons]; + npts = new double[ons]; + sum2 = new double[ons]; + npts2 = new double[ons]; + + // Fill sinctab and Initialize buffers for first band + for (int osamp=0; osampSetLine(iline,(iString::ToInteger(bands[sb]))); + cube->Read(*in); + } + int isamp = 1; + for (int osamp=0; osamp ins) continue; + + if (IsValidPixel( (*in)[isamp-1])) { + sum[osamp] += (*in)[isamp-1] * (1.0 - sdel); + npts[osamp] += (1.0 - sdel); + if (osamp+1 < ons) { + sum[osamp+1] += (*in)[isamp-1] * sdel; + npts[osamp+1] += sdel; + } + } + isamp++; + } + iline++; + } + + if (iline <= inl) { + in->SetLine(iline,(iString::ToInteger(bands[sb]))); + cube->Read(*in); + } + double ldel = (double)iline - rline; + double ldel2 = 1.0 - ldel; + int isamp = 1; + for (int osamp=0; osamp ins) continue; + if (IsValidPixel( (*in)[isamp-1])) { + sum[osamp] += (*in)[isamp-1] * (1.0 - sdel) * ldel2; + npts[osamp] += (1.0 - sdel) * ldel2; + if (osamp+1 < ons) { + sum[osamp+1] += (*in)[isamp-1] * sdel * ldel2; + npts[osamp+1] += sdel * ldel2; + } + sum2[osamp] += (*in)[isamp-1] * (1.0 - sdel) * ldel; + npts2[osamp] += (1.0 - sdel) * ldel; + if (osamp+1 < ons) { + sum2[osamp+1] += (*in)[isamp-1] * sdel * ldel; + npts2[osamp+1] += sdel * ldel; + } + } + isamp++; + } + + if (iline < inl) iline++; + + double npix = sscale * lscale; + for (int osamp=0; osamp npix * vper ) { + out[osamp] = sum[osamp] / npts[osamp]; + } + else { + if(replaceMode == "NEAREST") { + out[osamp] = (*in)[(int)(sinctab[osamp]+0.5) - 1]; + }else{ + out[osamp] = Isis::Null; + } + } + sum[osamp] = sum2[osamp]; + npts[osamp] = npts2[osamp]; + sum2[osamp] = 0.0; + npts2[osamp] = 0.0; + } + + if (out.Line() == onl && out.Band() != inb) { + sb++; + iline = 1; + for (int osamp=0; osampSetLine(readLine,(iString::ToInteger(bands[sb]))); + cube->Read(*in); + + // Scale down buffer + for (int osamp=0; osamp + + + + + Reduce the pixel dimensions of an image + + + + This program will reduce a cube to a given proportion of the original or to + specific dimensions. The user can specify to perform the reduction by + either averaging pixels or using the nearest-neighbor algorithm. The user + also has the option of filling all special pixels that can't be resolved by + the VALIDPER value with NULL or the nearest-neighbor value. + + + + + Original version + + + + Ported to Isis 3.0, Separated magcube into reduce and enlarge. + + + Read in ons/onl as integers not doubles. + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Fixed propagation bug + + + Forget to change ons/onl minimum inclusive values from 1.0 to 1 during the + 2003-5-13 change. + + + Added example + + + Fixed bug in average algorithm, forgot to divide Vper by 100. + + + Fixed problems when program ran in batchlist + + + Program now updates output file's mapping keywords + + + Changed so if it failed VPER the output cube would get null values. + Now processes cube bands from user input correctly + + + Removed references to CubeInfo + + + Added radio button for VPER options to allow original functionaliy. + + + The "Scale" keyword in the Projection group in the labels is now being + updated if this program is run on a projected cube. + + + Added keyword REDUCTION_TYPE to allow for clear switching between ons, onl + and sscale, lscale. Fixed problem involving cube remaning open after an + exception. + + + Now uses the SubArea class to produce output cube labels + with corrected Mapping, Instrument, and AlphaCube groups. + + + Improved documentation, changed parameter names, and updated examples. + + + Updated documentation and changed parameters STOTAL and LTOTAL back to ONS + and ONL, respectively. + + + + + Geometry + + + + + + cube + input + + Input cube to reduce + + + Use this parameter to select the filename. All bands within the file + will be scaled down. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the shrunken cube. + + + *.cub + + + + + + + string + Algorithm used to reduce image (Average,Nearest neighbor) + AVERAGE + + This chooses the algorithm used to reduce the image. The possibilities + are: average or nearest-beighbor. + + + + + + + + + string + + Scale down the image or reduce to specific dimensions + + SCALE + + Select between reducing the image to a proportion of the original (by + a scaling factor inverse) or to specific dimensions (in terms of total + number of pixels). + + + + + + + + + double + 1.0 + 1.0 + Sample scaling factor inverse + + This is the scaling factor inverse for the sample direction. For + example, SSCALE=4 will reduce the number of samples by 1/4th. + + + + + double + 1.0 + 1.0 + Line scaling factor inverse + + This is the scaling factor inverse for the line direction. For + example, LSCALE=4 will reduce the number of lines by 1/4th. + + + + + integer + 1 + Number of samples in output + + The number of samples desired in the output cube. This value + must be less than or equal to the number of samples in the input + image. + + + + + integer + 1 + Number of lines in output + + The number of lines desired in the output cube. This value + must be less than or equal to the number of lines in the input + image. + + + + + double + 50 + Valid percentage + + This parameter specifies what percentage of the pixels need to be + valid (non-special pixels). For example, scaling down by a factor + of two results in a 2x2 window (four pixels) being reduced to one + pixel. If VALIDPER is set at 50, then at least two pixels of the four + must be valid (50%). If this criteria is met, the resulting value + of the output pixel will be the average of the valid input pixels. + Otherwise the output pixel will be set to the input pixel which is + closest to the center of the window. + + + + + string + Replacement method when VALIDPER fails + NULL + + When the set VALIDPER variable is not met, this is how the pixel with + be filled. + + + + + + + + + + + + + Reduce the number of samples by a factor inverse of 2, while leaving the + number of lines the same + + + Essentially the opposite of enlarge, this configuration for reduce takes + an image and scales down the samples, keeping all parameters, except the + sample scale, at their default settings. + + + + from=peaks.cub + to=reducedPeaks.cub + sscale=2.0 + + + In this example the sample scale factor inverse is 2. Note that this implies + that the image will be scaled down by a factor of 2, not scaled up. No + line scale is specified since the default is 1.0. Since the default + mode of reduction is scale, the mode parameter does not need to be + specified. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform a sample + reduction by scaling. + + + + + + + + + + Input image for reduce + + + This is the image as it was taken originally. + + + FROM + + + + + + + Output image for reduce + + + The reduced image. Though it has been scaled down so that it can + be viewed in a web browser, the essential change can still be + observed. The vertical distortion is noticable, and the output cube + is 1/2 the size of the input cube. + + + TO + + + + + + + Reduce the number of samples to 150, and the number of lines to 250 + + + Here the mode has been set to reduce to a total number of pixels along + the sample and line dimensions, with all other parameters kept at their + default settings. + + + + from=peaks.cub + to=totalPeaks.cub + mode=total + ons=150 + onl=250 + + + In order to reduce to specific dimensions, the mode is set here to + "total". + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform a sample and + line reduction to a total number of pixels. + + + + + + + + + + Input image for reduce + + + This is the image as it was taken originally. + + + FROM + + + + + + + Output image for reduce + + + The reduced image. Though it has been scaled down so that it can + be viewed in a web browser, the essential change can still be + observed. The vertical and horizontal distortion is noticable, and + the output cube has 1/3 the number of samples and 1/2 the number of + lines as the input cube. + + + TO + + + + + diff --git a/isis/src/base/apps/reduce/tsts/Makefile b/isis/src/base/apps/reduce/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/reduce/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/reduce/tsts/averageOn/Makefile b/isis/src/base/apps/reduce/tsts/averageOn/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..66e0bb06fa1f3b1c1ad8e87c87e9e8a103b42c87 --- /dev/null +++ b/isis/src/base/apps/reduce/tsts/averageOn/Makefile @@ -0,0 +1,22 @@ +APPNAME = reduce + +labels3.txt.IGNORELINES = ByteOrder StartByte Bytes +labels6.txt.IGNORELINES = ByteOrder StartByte Bytes + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/peaks.cub \ + to= $(OUTPUT)/reduceTruth3.cub \ + algorithm=average \ + mode=total \ + ons=100 \ + onl=100 > /dev/null; + catlab from=$(OUTPUT)/reduceTruth3.cub > $(OUTPUT)/labels3.txt; + $(APPNAME) from= $(OUTPUT)/reduceTruth3.cub \ + to= $(OUTPUT)/reduceTruth6.cub \ + algorithm=average \ + mode=total \ + ons=50 \ + onl=50 > /dev/null; + catlab from=$(OUTPUT)/reduceTruth6.cub > $(OUTPUT)/labels6.txt; diff --git a/isis/src/base/apps/reduce/tsts/averageScale/Makefile b/isis/src/base/apps/reduce/tsts/averageScale/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5b27cd133a985fb2486df2ecb51f058dc7017457 --- /dev/null +++ b/isis/src/base/apps/reduce/tsts/averageScale/Makefile @@ -0,0 +1,10 @@ +APPNAME = reduce + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/reduceTruth1.cub \ + algorithm=average \ + sscale=1 \ + lscale=1 > /dev/null; diff --git a/isis/src/base/apps/reduce/tsts/averageScale2/Makefile b/isis/src/base/apps/reduce/tsts/averageScale2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..33cece021b1f049e73d34c2157ac6679615cfa0b --- /dev/null +++ b/isis/src/base/apps/reduce/tsts/averageScale2/Makefile @@ -0,0 +1,10 @@ +APPNAME = reduce + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/peaks.cub \ + to= $(OUTPUT)/reduceTruth5.cub \ + algorithm=average \ + sscale=7 \ + lscale=7 > /dev/null; diff --git a/isis/src/base/apps/reduce/tsts/nearest/Makefile b/isis/src/base/apps/reduce/tsts/nearest/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..569afa80f49d1a3f89af4d745bed0f48660b0b40 --- /dev/null +++ b/isis/src/base/apps/reduce/tsts/nearest/Makefile @@ -0,0 +1,10 @@ +APPNAME = reduce + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/reduceTruth2.cub \ + algorithm=nearest \ + sscale=3 \ + lscale=4 > /dev/null; diff --git a/isis/src/base/apps/reduce/tsts/nearestneighbor/Makefile b/isis/src/base/apps/reduce/tsts/nearestneighbor/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..37c631efa3b9ca3fd5a999db01117f72afaae92a --- /dev/null +++ b/isis/src/base/apps/reduce/tsts/nearestneighbor/Makefile @@ -0,0 +1,11 @@ +APPNAME = reduce + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/reduceTruth4.cub \ + algorithm=nearestneighbor \ + mode=total \ + ons=4 \ + onl=3 > /dev/null; diff --git a/isis/src/base/apps/remrx/Makefile b/isis/src/base/apps/remrx/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/remrx/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/remrx/assets/image/IoRemrxBilinear.JPG b/isis/src/base/apps/remrx/assets/image/IoRemrxBilinear.JPG new file mode 100755 index 0000000000000000000000000000000000000000..e6801b8d940670aa76e5153737e3774804b06e44 Binary files /dev/null and b/isis/src/base/apps/remrx/assets/image/IoRemrxBilinear.JPG differ diff --git a/isis/src/base/apps/remrx/assets/image/IoRemrxGui.JPG b/isis/src/base/apps/remrx/assets/image/IoRemrxGui.JPG new file mode 100755 index 0000000000000000000000000000000000000000..29ac49e52e6b1c9d8675516635071d48c88b490a Binary files /dev/null and b/isis/src/base/apps/remrx/assets/image/IoRemrxGui.JPG differ diff --git a/isis/src/base/apps/remrx/assets/image/IoRemrxNull.JPG b/isis/src/base/apps/remrx/assets/image/IoRemrxNull.JPG new file mode 100755 index 0000000000000000000000000000000000000000..38c566d67bdb101fc7ec90247e3d24cb454b386d Binary files /dev/null and b/isis/src/base/apps/remrx/assets/image/IoRemrxNull.JPG differ diff --git a/isis/src/base/apps/remrx/assets/image/inputRemrx.JPG b/isis/src/base/apps/remrx/assets/image/inputRemrx.JPG new file mode 100755 index 0000000000000000000000000000000000000000..1c75f16c46a81024953d66c8fce3cf940323a48c Binary files /dev/null and b/isis/src/base/apps/remrx/assets/image/inputRemrx.JPG differ diff --git a/isis/src/base/apps/remrx/assets/thumb/IoRemrxBilinear.JPG b/isis/src/base/apps/remrx/assets/thumb/IoRemrxBilinear.JPG new file mode 100755 index 0000000000000000000000000000000000000000..e6801b8d940670aa76e5153737e3774804b06e44 Binary files /dev/null and b/isis/src/base/apps/remrx/assets/thumb/IoRemrxBilinear.JPG differ diff --git a/isis/src/base/apps/remrx/assets/thumb/IoRemrxGui.JPG b/isis/src/base/apps/remrx/assets/thumb/IoRemrxGui.JPG new file mode 100755 index 0000000000000000000000000000000000000000..29ac49e52e6b1c9d8675516635071d48c88b490a Binary files /dev/null and b/isis/src/base/apps/remrx/assets/thumb/IoRemrxGui.JPG differ diff --git a/isis/src/base/apps/remrx/assets/thumb/IoRemrxNull.JPG b/isis/src/base/apps/remrx/assets/thumb/IoRemrxNull.JPG new file mode 100755 index 0000000000000000000000000000000000000000..38c566d67bdb101fc7ec90247e3d24cb454b386d Binary files /dev/null and b/isis/src/base/apps/remrx/assets/thumb/IoRemrxNull.JPG differ diff --git a/isis/src/base/apps/remrx/assets/thumb/inputRemrx.JPG b/isis/src/base/apps/remrx/assets/thumb/inputRemrx.JPG new file mode 100755 index 0000000000000000000000000000000000000000..1c75f16c46a81024953d66c8fce3cf940323a48c Binary files /dev/null and b/isis/src/base/apps/remrx/assets/thumb/inputRemrx.JPG differ diff --git a/isis/src/base/apps/remrx/remrx.cpp b/isis/src/base/apps/remrx/remrx.cpp new file mode 100644 index 0000000000000000000000000000000000000000..85da656957c16b68933697eae1de46ae482e7010 --- /dev/null +++ b/isis/src/base/apps/remrx/remrx.cpp @@ -0,0 +1,210 @@ +#include "Isis.h" + +#include +#include + +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "Pvl.h" +#include "UserInterface.h" +#include "Brick.h" +#include "Statistics.h" + +using namespace std; +using namespace Isis; + +void cpy(Buffer &in, Buffer &out); +void remrx (Buffer &in, Buffer &out); +static int sdim, ldim; +static bool resvalid; +static string action; + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and output cubes + Cube *icube = p.SetInputCube("FROM"); + PvlKeyword &status = icube->GetGroup("RESEAUS")["STATUS"]; + UserInterface &ui = Application::GetUserInterface(); + string in = ui.GetFilename("FROM"); + + // Check reseau status and make sure it is not nominal or removed + if ((string)status == "Nominal") { + string msg = "Input file [" + in + + "] appears to have nominal reseau status. You must run findrx first."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + if ((string)status == "Removed") { + string msg = "Input file [" + in + + "] appears to already have reseaus removed."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + status = "Removed"; + + p.SetOutputCube ("TO"); + + // Start the processing + p.StartProcess(cpy); + p.EndProcess(); + + // Get the user entered dimensions + sdim = ui.GetInteger("SDIM"); + ldim = ui.GetInteger("LDIM"); + + // Get other user entered options + string out= ui.GetFilename("TO"); + resvalid = ui.GetBoolean("RESVALID"); + action = ui.GetString("ACTION"); + + // Open the output cube + Cube cube; + cube.Open(out, "rw"); + + PvlGroup &res = cube.Label()->FindGroup("RESEAUS",Pvl::Traverse); + + // Get reseau line, sample, type, and valid Keywords + PvlKeyword lines = res.FindKeyword("LINE"); + PvlKeyword samps = res.FindKeyword("SAMPLE"); + PvlKeyword type = res.FindKeyword("TYPE"); + PvlKeyword valid = res.FindKeyword("VALID"); + int numres = lines.Size(); + + Brick brick(sdim,ldim,1,cube.PixelType()); + for (int res=0; res (2*sdev)) array[s][l] = avg; + } + // Walk bottom edge & replace data outside of 2devs with the avg + for (int s = 0; s < sdim; s++) { + int l = ldim-1; + double diff = fabs(array[s][l] - avg); + if (diff > (2*sdev)) array[s][l] = avg; + } + // Walk left edge & replace data outside of 2devs with the avg + for (int l = 0; l < ldim; l++) { + int s = 0; + double diff = fabs(array[s][l] - avg); + if (diff > (2*sdev)) array[s][l] = avg; + } + // Walk right edge & replace data outside of 2devs with the avg + for (int l = 0; l < ldim; l++) { + int s = sdim-1; + double diff = fabs(array[s][l] - avg); + if (diff > (2*sdev)) array[s][l] = avg; + } + srand(0); + double dn, gdn1, gdn2; + for (int l = 0; l < ldim; l++) { + int c = l * sdim; //count + // Top Edge Reseau + if ((int)type[res] == 2 && l < (ldim / 2)) continue; + // Bottom Edge Reseau + if ((int)type[res] == 8 && l > (ldim / 2 + 1)) continue; + for (int s = 0; s < sdim; s++, c++) { + // Left Edge Reseau + if ((int)type[res] == 4 && s < (sdim / 2)) continue; + // Right Edge Reseau + if ((int)type[res] == 6 && s > (sdim / 2 + 1)) continue; + double sum = 0.0; + int gline1 = 0; + int gline2 = ldim - 1; + gdn1 = array[s][gline1]; + gdn2 = array[s][gline2]; + + // Linear Interpolation to get pixel value + dn = gdn2 + (l - gline2) * (gdn1 - gdn2) / (gline1 - gline2); + sum += dn; + + int gsamp1 = 0; + int gsamp2 = sdim - 1; + gdn1 = array[gsamp1][l]; + gdn2 = array[gsamp2][l]; + + // Linear Interpolation to get pixel value + dn = gdn2 + (s - gsamp2) * (gdn1 - gdn2) / (gsamp1 - gsamp2); + sum += dn; + dn = sum / 2; + int rdm = rand(); + double drandom = rdm / (double)RAND_MAX; + double offset = 0.0; + if (drandom < .333) offset = -1.0; + if (drandom > .666) offset = 1.0; + brick[c] = dn + offset; + } + } + } + } + cube.Write(brick); + } + cube.Close(); + +} + +// Copy the input cube to the output cube +void cpy(Buffer &in, Buffer &out) { + for (int i=0; i + + + + Removes Reseaus from an image + + + + This program will remove Reseaus from Viking, Voyager, and Mariner images. + The Reseaus are removed using either bilinear interpolation of the + surrounding pixels or by simply putting NULLs in the portion of the + image around the Reseau location of the input image. The ACTION + parameter is used to tell the program which of these two actions to + take. The user should input the size of the box around the Reseau that + will be modified. SDIM and LDIM are the sample and line dimensions of + the box around the reseau. RESVALID is used to determine whether the + program will check the reseau valid flag for nominal reseaux before + removing the reseau. If RESVALID is NO, the program will not check + the reseau valid flag for nominal reseaux and all the reseaux will be + removed except invalid nominal positions. If RESVALID is YES, the + program will check the reseau valid flag that is output from the + findrx program. If the flag is 0, the program will not remove that + reseau. If the flag is 1, the reseau will be removed. If the flag is + -1, indicating an invalid nominal position, the reseau will not be + removed in any case. The output cube file can be written over the + input file or a new output cube can be created. To overwrite the input + file, the TO parameter should be set to blank, " ". The "findrx" + program, which writes the Reseau locations, Reseau type, and a valid + flag to the cube file label, must be run before "remrx". + + + + Viking + Voyager + Mariner + + + + + findrx + + + + + + Original version + + + Added truth file for gala + + + Modified appTest input path (viking testData areas split) + + + Removed references to CubeInfo + + + + + + + cube + input + + Input file reseaus will be removed from + + + The cube the reseaus will be removed from. All reseaus in the cube + will be removed. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the data with reseaus removed. + + + *.cub + + + + + + + integer + + Samples to remove around each reseau + + + The number of samples to remove around each reseau. Defaults to 9.0 + + 9 + + + + + integer + + Lines to remove around each reseau + + + The number of lines to remove around each reseau. Defaults to 9.0 + + 9 + + + + + + + string + + The way the reseaus will be removed + + + There are 2 options for removing the Reseaus. The program + can replace pixels inside the SDIM x LDIM box with Null or + bilinear interpolation. Defaults to BILINEAR. + + BILINEAR + + + + + + + + boolean + + Check Reseau Valid Flag? + + + If this parameter is TRUE, the reseau valid flag will be + checked before the reseau is removed. If the reseau + valid flag is a 0 or -1, the reseau will not be removed. + If the reseau valid flag is a 1, the reseau will be + removed. Reseaus with a valid flag=-1 are never removed. + This flag indicates an invalid nominal position. + If RESVALID is FALSE, the reseau valid flag will not be + checked for nominals and all the reseaus will be removed, + except the invalid nominals. Defaults to FALSE. + + FALSE + + + + + + + Reseaus replaced with Bilinear Interpolation + + This example shows the remrx application with the BILINEAR action option. The SDIM and LDIM default to 9, + and RESVALID defaults to false. + + + f=../inputRemrx.cub t=out-bilinear.cub + + + Uses bilinear interpolation to fill in missing data around each reseau. + + + + + + Input image for mirror + This is the 800 by 800 input image for the remrx examples. + + + FROM + + + + + + Output image for bilinear interpolation remrx + This is the 800 by 800 output image that results. + + + TO + + + + + + + Example Gui + + Screenshot of GUI with parameters filled in to perform a bilinear interpolation remrx operation on the input image. + + + + + + + + + Reseaus replaced with Nulls + + This example shows the remrx application with the NULL action option, using the same input image as the above + example. The SDIM and LDIM default to 9, and RESVALID defaults to false. + + + f=../inputRemrx.cub t=out-null.cub + + + Nulls out 9x9 boxes around each reseau. + + + + + + Output image for null remrx + This is the 800 by 800 output image that results. + + + TO + + + + + + + diff --git a/isis/src/base/apps/remrx/tsts/Makefile b/isis/src/base/apps/remrx/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/remrx/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/remrx/tsts/bilinear/Makefile b/isis/src/base/apps/remrx/tsts/bilinear/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46ec117490a208bbf38bc984b6b6ef2a48ab528b --- /dev/null +++ b/isis/src/base/apps/remrx/tsts/bilinear/Makefile @@ -0,0 +1,11 @@ +APPNAME = remrx + +# 2.0 +remrxTruth-bilinear.cub.TOLERANCE = 2.01 + +include $(ISISROOT)/make/isismake.tsts + +commands: + crop from=$(INPUT)/f387a06.cub to=$(OUTPUT)/f387a06.crop.cub > /dev/null; + editlab from=$(OUTPUT)/f387a06.crop.cub option=modkey grpname=Reseaus keyword=Status value=Calculated > /dev/null; + $(APPNAME) from=$(OUTPUT)/f387a06.crop.cub to=$(OUTPUT)/remrxTruth-bilinear.cub action=bilinear > /dev/null; diff --git a/isis/src/base/apps/remrx/tsts/null/Makefile b/isis/src/base/apps/remrx/tsts/null/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f77dc82d158c9554fadccae898c989686567d2ea --- /dev/null +++ b/isis/src/base/apps/remrx/tsts/null/Makefile @@ -0,0 +1,8 @@ +APPNAME = remrx + +include $(ISISROOT)/make/isismake.tsts + +commands: + crop from=$(INPUT)/f387a06.cub to=$(OUTPUT)/f387a06.crop.cub > /dev/null; + editlab from=$(OUTPUT)/f387a06.crop.cub option=modkey grpname=Reseaus keyword=Status value=Calculated > /dev/null; + $(APPNAME) from=$(OUTPUT)/f387a06.crop.cub to=$(OUTPUT)/remrxTruth-null.cub action=null > /dev/null; diff --git a/isis/src/base/apps/rgb2hsv/Makefile b/isis/src/base/apps/rgb2hsv/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/rgb2hsv/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/rgb2hsv/assets/image/hue.jpg b/isis/src/base/apps/rgb2hsv/assets/image/hue.jpg new file mode 100644 index 0000000000000000000000000000000000000000..66f9c3a7cee33bcebea19723f89412c3c574f0de Binary files /dev/null and b/isis/src/base/apps/rgb2hsv/assets/image/hue.jpg differ diff --git a/isis/src/base/apps/rgb2hsv/assets/image/rgb.jpg b/isis/src/base/apps/rgb2hsv/assets/image/rgb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6f34628cd93d4ff7d577e327e034c58af1b5ca35 Binary files /dev/null and b/isis/src/base/apps/rgb2hsv/assets/image/rgb.jpg differ diff --git a/isis/src/base/apps/rgb2hsv/assets/image/rgb2hsvgui.jpg b/isis/src/base/apps/rgb2hsv/assets/image/rgb2hsvgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..493f6861bab2422c81271e2ccec5767f0667806a Binary files /dev/null and b/isis/src/base/apps/rgb2hsv/assets/image/rgb2hsvgui.jpg differ diff --git a/isis/src/base/apps/rgb2hsv/assets/image/sat.jpg b/isis/src/base/apps/rgb2hsv/assets/image/sat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..21c3d8cdd1eccbd3edb23ff8fd000a6336b4e3c1 Binary files /dev/null and b/isis/src/base/apps/rgb2hsv/assets/image/sat.jpg differ diff --git a/isis/src/base/apps/rgb2hsv/assets/image/val.jpg b/isis/src/base/apps/rgb2hsv/assets/image/val.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2250c684226dbdfa77a49eaa557f79579f2c61f3 Binary files /dev/null and b/isis/src/base/apps/rgb2hsv/assets/image/val.jpg differ diff --git a/isis/src/base/apps/rgb2hsv/assets/thumb/hue.jpg b/isis/src/base/apps/rgb2hsv/assets/thumb/hue.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f224078c3b8e58a93b51026f467c3d3440bc830 Binary files /dev/null and b/isis/src/base/apps/rgb2hsv/assets/thumb/hue.jpg differ diff --git a/isis/src/base/apps/rgb2hsv/assets/thumb/rgb.jpg b/isis/src/base/apps/rgb2hsv/assets/thumb/rgb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d593b1728e9bc68f407d7a0acf379efef0907fd Binary files /dev/null and b/isis/src/base/apps/rgb2hsv/assets/thumb/rgb.jpg differ diff --git a/isis/src/base/apps/rgb2hsv/assets/thumb/rgb2hsvgui.jpg b/isis/src/base/apps/rgb2hsv/assets/thumb/rgb2hsvgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2f0451be721f9d5b0dca611aa471a8201d5feb2f Binary files /dev/null and b/isis/src/base/apps/rgb2hsv/assets/thumb/rgb2hsvgui.jpg differ diff --git a/isis/src/base/apps/rgb2hsv/assets/thumb/sat.jpg b/isis/src/base/apps/rgb2hsv/assets/thumb/sat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c7e8fac1c2c66aaf10925646618f0d52f9fd6c79 Binary files /dev/null and b/isis/src/base/apps/rgb2hsv/assets/thumb/sat.jpg differ diff --git a/isis/src/base/apps/rgb2hsv/assets/thumb/val.jpg b/isis/src/base/apps/rgb2hsv/assets/thumb/val.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0e056bef8f0642ddee8b6006392eae52a74de2c4 Binary files /dev/null and b/isis/src/base/apps/rgb2hsv/assets/thumb/val.jpg differ diff --git a/isis/src/base/apps/rgb2hsv/rgb2hsv.cpp b/isis/src/base/apps/rgb2hsv/rgb2hsv.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a2c6eab757ab0472fe00fa66db0bb3029a48c2b --- /dev/null +++ b/isis/src/base/apps/rgb2hsv/rgb2hsv.cpp @@ -0,0 +1,143 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +#include "QColor" +#include "Histogram.h" +#include "Stretch.h" + +using namespace std; +using namespace Isis; + +void convert(vector &in, + vector &out); + +Stretch redStretch, greenStretch, blueStretch; + +void IsisMain() { + // Open input cubes + ProcessByLine p; + Cube* redCube = p.SetInputCube("RED", Isis::OneBand); + Cube* greenCube = p.SetInputCube("GREEN", Isis::OneBand); + Cube* blueCube = p.SetInputCube("BLUE", Isis::OneBand); + + // Clear out stretch pairs for multiple runs + redStretch.ClearPairs(); + greenStretch.ClearPairs(); + blueStretch.ClearPairs(); + + // Get information from the GUI to build stretch pairs. + // "Automatic" uses histogram percentages for uses in the stretch pairs + // "Manual" uses pixels values to build the stretch pairs + double rMin, rMax, gMin, gMax, bMin, bMax; + UserInterface &ui = Application::GetUserInterface(); + + // Automatic is selected + if (ui.GetString("MODE") == "AUTOMATIC") { + Histogram* redHist = redCube->Histogram(); + Histogram* greenHist = greenCube->Histogram(); + Histogram* blueHist = blueCube->Histogram(); + + rMin = redHist->Percent(ui.GetDouble("RMINPER")); + rMax = redHist->Percent(ui.GetDouble("RMAXPER")); + gMin = greenHist->Percent(ui.GetDouble("GMINPER")); + gMax = greenHist->Percent(ui.GetDouble("GMAXPER")); + bMin = blueHist->Percent(ui.GetDouble("BMINPER")); + bMax = blueHist->Percent(ui.GetDouble("BMAXPER")); + // Manual is selected + } else { + rMin = ui.GetDouble("RMIN"); + rMax = ui.GetDouble("RMAX"); + gMin = ui.GetDouble("GMIN"); + gMax = ui.GetDouble("GMAX"); + bMin = ui.GetDouble("BMIN"); + bMax = ui.GetDouble("BMAX"); + } + + // Map minimum values to zero + redStretch.AddPair(rMin, 0.0); + greenStretch.AddPair(gMin, 0.0); + blueStretch.AddPair(bMin, 0.0); + + // Map maximum values to one + redStretch.AddPair(rMax, 1.0); + greenStretch.AddPair(gMax, 1.0); + blueStretch.AddPair(bMax, 1.0); + + // Handle special pixels + redStretch.SetNull(0.0); + redStretch.SetLis(0.0); + redStretch.SetLrs(0.0); + redStretch.SetHrs(1.0); + redStretch.SetHis(1.0); + greenStretch.SetNull(0.0); + greenStretch.SetLis(0.0); + greenStretch.SetLrs(0.0); + greenStretch.SetHrs(1.0); + greenStretch.SetHis(1.0); + blueStretch.SetNull(0.0); + blueStretch.SetLis(0.0); + blueStretch.SetLrs(0.0); + blueStretch.SetHrs(1.0); + blueStretch.SetHis(1.0); + + // Start the processing + p.SetOutputCube ("HUE"); + p.SetOutputCube ("SATURATION"); + p.SetOutputCube ("VALUE"); + + p.StartProcess(convert); + p.EndProcess(); +} + +// Line processing routine +// This works by creating an RGB QColor from 3 qreals representing Red, Green, +// and Blue. This is converted into HSV format, and the data from this is +// sent to the output buffers. +void convert (vector &in, + vector &out) { + + // Input file buffers + Buffer &red = *in[0]; + Buffer &green = *in[1]; + Buffer &blue = *in[2]; + + // Output file buffers + Buffer &hue = *out[0]; + Buffer &saturation = *out[1]; + Buffer &value = *out[2]; + + for (int i = 0; i < red.size(); i++) { + qreal r = redStretch.Map(red[i]); + qreal g = greenStretch.Map(green[i]); + qreal b = blueStretch.Map(blue[i]); + + QColor rgb; + rgb.setRgbF(r, g, b); + QColor hsv = rgb.toHsv(); + + /** + * HSV Stores colors in terms of hue, saturation, and value. The hue determines the color, + * which is an angle around the color wheel. However, hsv.hueF() in the qt library returns a + * percentage around the color wheel and not an angle. For example, 0% means the origin and + * 50% means 180 degrees around the circle. We want the hue to be in degrees, so to convert + * this percentage we multiple by 360 degrees. The basic colors are: 0 degrees = RED, + * 60 degrees = YELLOW, 120 degrees = GREEN, 180 degrees = CYAN, 240 degrees = BLUE and + * 300 degrees = PURPLE. + * The saturation is how much grey is in the color (intensity of the color). A saturation value of zero means it's perfect, + * while a saturation value of 1 would cause any color to become pure grey. As an example, the color RGB(255,0,0) + * is pure so the saturation would be zero. The value is how bright the color is. A value of 0 is always black, + * and 100 is the color (if not saturated). + * In brief, + * HUE = COLOR (degrees around the color wheel) + * SATURATION = INTENSITY (0-1, 0 being no color/grey) + * VALUE = BRIGHTNESS (0 being black) + * + * For more information, see + * http://en.wikipedia.org/wiki/Color_spaces + */ + hue[i] = hsv.hueF() * 360.0; // Hue values range from 0.0 - 360.0 + saturation[i] = hsv.saturationF(); + value[i] = hsv.valueF(); + } +} diff --git a/isis/src/base/apps/rgb2hsv/rgb2hsv.xml b/isis/src/base/apps/rgb2hsv/rgb2hsv.xml new file mode 100644 index 0000000000000000000000000000000000000000..66c0acc6f2bb1808ea3310a62b742ee2f15f3414 --- /dev/null +++ b/isis/src/base/apps/rgb2hsv/rgb2hsv.xml @@ -0,0 +1,392 @@ + + + + + Convert RGB to HSV + + + + This program takes in three input images, representing Red, Green, and Blue, then outputs Hue, Saturation, + and Value files respectively. It works by creating an RGB pixel from pixels in the Red, Green, and Blue + files, converting it to HSV format, then writing the data to the Hue, Saturation, and Value files.

    + + NOTE: The original input file dn range is compressed down to a value between 0.0 and 1.0 When it comes back out + through hsv2rgb, it remains in the range of 0.0 to 1.0 We currently do not have the capability to return the dn values + to their original value.

    + + HSV Stores colors in terms of hue, saturation, and value. The hue determines the color, + which is an angle around the color wheel. The basic colors are: 0 degrees = RED, + 60 degrees = YELLOW, 120 degrees = GREEN, 180 degrees = CYAN, 240 degrees = BLUE and + 300 degrees = PURPLE.
    + The saturation is how much grey is in the color (intensity of the color). A saturation value of zero means it's a perfect color, + while a saturation value of 1 would cause any color to become pure grey. As an example, the color RGB(255,0,0) + is pure so the saturation would be zero. The value is how bright the color is. A value of 0 is always black, + and 100 is the color (if not saturated).

    + In brief,
    + HUE = COLOR (degrees around the color wheel)
    + SATURATION = INTENSITY (0-1, 0 being no color/grey)
    + VALUE = BRIGHTNESS (0 being black)

    + + For more information, see
    + http://en.wikipedia.org/wiki/Color_spaces +
    + + + Math and Statistics + + + + + hsv2rgb + + + + + + Original version + + + Added comment explaining what HSV is and what the code is doing + + + Added documentation explaining why running images through rgb2hsv and + then running it back through hsv2rgb gives a different result that the original. + + + Removed references to CubeInfo + + + + + + + cube + input + + Input file to be converted + + + This file will be converted from Red to Hue + + + *.cub + + + + + cube + input + + Input file to be converted + + + This file will be converted from Green to Saturation + + + *.cub + + + + + cube + input + + Input file to be converted + + + This file will be converted from Blue to Value + + + *.cub + + + + + + + cube + real + output + + Output cube + + + The resultant Hue cube + + + *.cub + + + + + cube + real + output + + Output cube + + + The resultant Saturation cube + + + *.cub + + + + + cube + real + output + + Output cube + + + The resultant Value cube + + + *.cub + + + + + + + string + Automatic + Histogram parameters + + This determines which values will be used for minimum and maximum cut-off limits + + + + + + + + + + + + double + 0.5 + Minumim percentage + + Minimum cut-off value for the histogram + + 0.0 + + RMAXPER + + + + + double + 99.5 + Maximum percentage + + Maximum cut-off value for the histogram + + 100.0 + + + + double + 0.5 + Minumim percentage + + Minimum cut-off value for the histogram + + 0.0 + + GMAXPER + + + + + double + 99.5 + Maximum percentage + + Maximum cut-off value for the histogram + + 100.0 + + + + double + 0.5 + Minumim percentage + + Minimum cut-off value for the histogram + + 0.0 + + BMAXPER + + + + + double + 99.5 + Maximum percentage + + Maximum cut-off value for the histogram + + 100.0 + + + + + + double + Minumim pixel value + + Minimum cut-off pixel value + + 0.0 + + RMAX + + + + + double + Maximum pixel value + + Maximum cut-off pixel value + + 255.0 + + + + double + Minumim pixel value + + Minimum cut-off pixel value + + 0.0 + + GMAX + + + + + double + Maximum pixel value + + Maximum cut-off pixel value + + 255.0 + + + + double + Minumim pixel value + + Minimum cut-off pixel value + + 0.0 + + RMAX + + + + + double + Maximum pixel value + + Maximum cut-off pixel value + + 255.0 + + + + + + + + Convert RGB image to HSV + + This example shows the results of converting RGB images to HSV format. + + + + red=../peaks.cub+5 green=../peaks.cub+4 blue=../peaks.cub+3 hue=../hue.cub saturation=../sat.cub value=../val.cub mode=automatic + + + Convert Red, Green, and Blue images into their respective Hue, Saturation, and Value images. + + + + + + Input image for rgb2hsv + This is the color input image for the rgb2hsv example. + + + + + + + + Output image + This is the output image that results from converting Red to Hue. + + + HUE + + + + Output image + This is the output image that results from converting Green to Saturation. + + + SATURATION + + + + Output image + This is the output image that results from converting Blue to Value. + + + VALUE + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform + a conversion from RGB to HSV using the different bands of peaks.cub. + + + + + + +
    diff --git a/isis/src/base/apps/rgb2hsv/tsts/Makefile b/isis/src/base/apps/rgb2hsv/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/rgb2hsv/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/rgb2hsv/tsts/auto/Makefile b/isis/src/base/apps/rgb2hsv/tsts/auto/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..699b3345605f4c68dd32027804e5b57eafc5c6ff --- /dev/null +++ b/isis/src/base/apps/rgb2hsv/tsts/auto/Makefile @@ -0,0 +1,12 @@ +APPNAME = rgb2hsv + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) red=$(INPUT)/isisTruth.cub+5 \ + green=$(INPUT)/isisTruth.cub+4 \ + blue=$(INPUT)/isisTruth.cub+3 \ + hue=$(OUTPUT)/rgb2hsvTruth1.cub \ + saturation=$(OUTPUT)/rgb2hsvTruth2.cub \ + value=$(OUTPUT)/rgb2hsvTruth3.cub \ + mode=automatic > /dev/null; diff --git a/isis/src/base/apps/rgb2hsv/tsts/manual/Makefile b/isis/src/base/apps/rgb2hsv/tsts/manual/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a2ed56fba951b17d59d43941e6b36b928c9424aa --- /dev/null +++ b/isis/src/base/apps/rgb2hsv/tsts/manual/Makefile @@ -0,0 +1,18 @@ +APPNAME = rgb2hsv + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) red=$(INPUT)/isisTruth.cub+5 \ + green=$(INPUT)/isisTruth.cub+4 \ + blue=$(INPUT)/isisTruth.cub+3 \ + hue=$(OUTPUT)/rgb2hsvTruth4.cub \ + saturation=$(OUTPUT)/rgb2hsvTruth5.cub \ + value=$(OUTPUT)/rgb2hsvTruth6.cub \ + mode=manual \ + rmin=10 \ + rmax=250 \ + gmin=10 \ + gmax=250 \ + bmin=10 \ + bmax=250 > /dev/null; diff --git a/isis/src/base/apps/rotate/Makefile b/isis/src/base/apps/rotate/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/rotate/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/rotate/rotate.cpp b/isis/src/base/apps/rotate/rotate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..40efcdba27cf7651d3e4828b4162e3c636ca58a3 --- /dev/null +++ b/isis/src/base/apps/rotate/rotate.cpp @@ -0,0 +1,50 @@ +#include "Isis.h" +#include "ProcessRubberSheet.h" + +#include "rotate.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + ProcessRubberSheet p; + + // Open the input cube + Cube *icube = p.SetInputCube ("FROM"); + + // Set up the transform object + UserInterface &ui = Application::GetUserInterface(); + Transform *transform = new Rotate(icube->Samples(), icube->Lines(), + ui.GetDouble("DEGREES")); + + // Determine the output size + int samples = transform->OutputSamples(); + int lines = transform->OutputLines(); + + // Allocate the output file + p.SetOutputCube ("TO", samples, lines, icube->Bands()); + + // Set up the interpolator + Interpolator *interp; + if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { + interp = new Interpolator(Interpolator::NearestNeighborType); + } + else if (ui.GetString("INTERP") == "BILINEAR") { + interp = new Interpolator(Interpolator::BiLinearType); + } + else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { + interp = new Interpolator(Interpolator::CubicConvolutionType); + } + else { + string msg = "Unknow value for INTERP [" + + ui.GetString("INTERP") + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + p.StartProcess(*transform, *interp); + p.EndProcess(); + + delete transform; + delete interp; +} + diff --git a/isis/src/base/apps/rotate/rotate.h b/isis/src/base/apps/rotate/rotate.h new file mode 100644 index 0000000000000000000000000000000000000000..aee19f28b342d8f4d27315c2d042a149e30047f1 --- /dev/null +++ b/isis/src/base/apps/rotate/rotate.h @@ -0,0 +1,110 @@ +#ifndef rotate_h +#define rotate_h + +#include "Transform.h" +#include +#include + +class Rotate : public Isis::Transform { + private: + double p_degrees; // The degree of rotation + double p_radians; // p_degrees converted to radians + double p_cosRad; // The cosine of p_radians + double p_sinRad; // The sine of p_radians + int p_outputSamples; // Number of samples for output + int p_outputLines; // Number of lines for output + double p_minSamp; // The minimum sample after rotation + double p_minLine; // The minimum line after rotation + double p_maxSamp; // The maximum sample after rotation + double p_maxLine; // The maximum line after rotation + + + public: + // constructor + Rotate (const double inputSamples, const double inputLines, + const double rotation) { + // Angles for SIN & COS are measured positive counter-clockwise + // but the program is assuming positive clockwise, so use the negative angle + + // Setup private data for calculating where a pixel in the output comes from + double PI = acos (-1.0); + + p_degrees = -rotation; + p_radians = p_degrees * PI / 180.0; + + p_cosRad = cos (p_radians); + p_sinRad = sin (p_radians); + + // Rotate the corners of the input to find the output size + double samples[4]; + double lines[4]; + + // Rotate (1,1) = (0.5,0.5) + samples[0] = 0.5 * p_sinRad + 0.5 * p_cosRad; + lines[0] = 0.5 * p_cosRad - 0.5 * p_sinRad; + // Rotate (ns,1) = (ns+0.5, .5) + samples[1] = 0.5 * p_sinRad + (inputSamples+0.5) * p_cosRad; + lines[1] = 0.5 * p_cosRad - (inputSamples+0.5) * p_sinRad; + // Rotate (1,nl) = (.5, nl+0.5) + samples[2] = (inputLines+0.5) * p_sinRad + 0.5 * p_cosRad; + lines[2] = (inputLines+0.5) * p_cosRad - 0.5 * p_sinRad; + // Rotate (ns,nl) = (ns+0.5, nl+0.5) + samples[3] = (inputLines+0.5) * p_sinRad + (inputSamples+0.5) * p_cosRad; + lines[3] = (inputLines+0.5) * p_cosRad - (inputSamples+0.5) * p_sinRad; + + // Find the min and max samp and line + p_minSamp = samples[0]; + for (int i=1; i<=3; i++) if (samples[i] < p_minSamp) p_minSamp = samples[i]; + p_maxSamp = samples[0]; + for (int i=1; i<=3; i++) if (samples[i] > p_maxSamp) p_maxSamp = samples[i]; + p_minLine = lines[0]; + for (int i=1; i<=3; i++) if (lines[i] < p_minLine) p_minLine = lines[i]; + p_maxLine = lines[0]; + for (int i=1; i<=3; i++) if (lines[i] > p_maxLine) p_maxLine = lines[i]; + + // Calculate the output size. If there is a fractional pixel, round up + p_outputSamples = (int)ceil (p_maxSamp - p_minSamp); + p_outputLines = (int)ceil (p_maxLine - p_minLine); + + if ((p_degrees == 90.0) || (p_degrees == -90)) { + p_outputSamples = (int)inputLines; + p_outputLines = (int)inputSamples; + } + if ((p_degrees == 180.0) || (p_degrees == -180.0)) { + p_outputSamples = (int)inputSamples; + p_outputLines = (int)inputLines; + } + } + + // destructor + ~Rotate () {}; + + // Implementations for parent's pure virtual members + // Convert the requested output samp/line to an input samp/line + bool Xform (double &inSample, double &inLine, + const double outSample, const double outLine) { + // First calculate the rotated input position (uses equation of a line) + double inRotSamp = outSample - 0.5 + p_minSamp; + double inRotLine = outLine - 0.5 + p_minLine; + + // Now unrotate the position from above to get the original input position + // inSample = (-inRotLine * p_sinRad) + (inRotSamp * p_cosRad); + inSample = (inRotSamp * p_cosRad) - (inRotLine * p_sinRad); + inLine = (inRotLine * p_cosRad) + (inRotSamp * p_sinRad); + + return true; + } + + // Return the output number of samples + int OutputSamples () const { + return p_outputSamples; + } + + // Return the output number of lines + int OutputLines () const { + return p_outputLines; + } +}; + +#endif + diff --git a/isis/src/base/apps/rotate/rotate.xml b/isis/src/base/apps/rotate/rotate.xml new file mode 100644 index 0000000000000000000000000000000000000000..4a001181b1f9a76e81f73b73e5225593ab53dc53 --- /dev/null +++ b/isis/src/base/apps/rotate/rotate.xml @@ -0,0 +1,122 @@ + + + + + + Rotates a cube any number of degrees + + + + This program will rotate a cube any number of degrees. The rotation will + not clip any pixels from the input (i.e., the output cube will be made + large enough to contain all of the input cube). Pixels outside of the input + cube will be set to NULL. + + + + + Original version + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Fixed compiler error with uninitialized variable after adding -O1 flag + + + Modified filename parameters to be cube parameters where necessary + + + Fixed typo in user documentation + + + Removed references to CubeInfo + + + + + Geometry + + + + + + cube + input + + Input cube to rotate + + + Use this parameter to select the filename. All bands within the file + will be rotated unless a specific band is specified. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the rotation. + + + + + + + double + Number of degrees of rotation + + This defines the number of degrees the cube will be rotated. + The angle is measured positive clockwize. + + -360.0 + 360.0 + + + + string + + CUBICCONVOLUTION + + Type of interpolation + + This is the type of interpolation to be performed on the input. + + + + + + + + + + + + diff --git a/isis/src/base/apps/rotate/tsts/Makefile b/isis/src/base/apps/rotate/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/rotate/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/rotate/tsts/case01/Makefile b/isis/src/base/apps/rotate/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fb186e690638ebb4164cd2bebdee957ac05192b5 --- /dev/null +++ b/isis/src/base/apps/rotate/tsts/case01/Makefile @@ -0,0 +1,9 @@ +APPNAME = rotate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/rotateTruth1.cub \ + degrees=90 \ + interp=nearestneighbor > /dev/null; diff --git a/isis/src/base/apps/rotate/tsts/case02/Makefile b/isis/src/base/apps/rotate/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..57d29d90c414857cf4f439c3a61ba7f11c075406 --- /dev/null +++ b/isis/src/base/apps/rotate/tsts/case02/Makefile @@ -0,0 +1,9 @@ +APPNAME = rotate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/rotateTruth2.cub \ + degrees=112 \ + interp=nearestneighbor > /dev/null; diff --git a/isis/src/base/apps/seedgrid/Makefile b/isis/src/base/apps/seedgrid/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/seedgrid/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/seedgrid/seedgrid.cpp b/isis/src/base/apps/seedgrid/seedgrid.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78594c3256282eb7e50beed1d985bc9117d0af15 --- /dev/null +++ b/isis/src/base/apps/seedgrid/seedgrid.cpp @@ -0,0 +1,226 @@ +#define GUIHELPERS + +#include "Isis.h" + +#include "ControlNet.h" +#include "ID.h" +#include "Progress.h" + +using namespace std; +using namespace Isis; + +void PrintMap (); + +map GuiHelpers(){ + map helper; + helper ["PrintMap"] = (void*) PrintMap; + return helper; +} + +void IsisMain() { + + // Get the map projection file provided by the user + UserInterface &ui = Application::GetUserInterface(); + + ControlNet cnet; + + double equatorialRadius = 0.0; + + string spacing = ui.GetString("SPACING"); + if (spacing == "METER") { + Pvl userMap; + userMap.Read(ui.GetFilename("PROJECTION")); + PvlGroup &mapGroup = userMap.FindGroup("Mapping", Pvl::Traverse); + + // Construct a Projection for converting between Lon/Lat and X/Y + // Note: Should this be an option to include this in the program? + string target; + if (ui.WasEntered("TARGET")) { + target = ui.GetString("TARGET"); + } + else if (mapGroup.HasKeyword("TargetName")) { + target = mapGroup.FindKeyword("TargetName")[0]; + ui.PutAsString("TARGET", target); + } + else { + string msg = "A target must be specified either by the [TARGET] parameter "; + msg += "or included as a value for keyword [TargetName] in the projection file."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + PvlGroup radii = Projection::TargetRadii(target); + + mapGroup.AddKeyword(PvlKeyword("TargetName", target), Pvl::Replace); + mapGroup.AddKeyword(PvlKeyword("EquatorialRadius", (string) radii["EquatorialRadius"])); + mapGroup.AddKeyword(PvlKeyword("PolarRadius", (string) radii["PolarRadius"])); + + if (!ui.WasEntered("PROJECTION")) { + mapGroup.AddKeyword(PvlKeyword("LatitudeType","Planetocentric")); + mapGroup.AddKeyword(PvlKeyword("LongitudeDirection","PositiveEast")); + mapGroup.AddKeyword(PvlKeyword("LongitudeDomain",360)); + mapGroup.AddKeyword(PvlKeyword("CenterLatitude",0)); + mapGroup.AddKeyword(PvlKeyword("CenterLongitude",0)); + } + + mapGroup.AddKeyword(PvlKeyword("MinimumLatitude", ui.GetDouble("MINLAT")),Pvl::Replace); + mapGroup.AddKeyword(PvlKeyword("MaximumLatitude", ui.GetDouble("MAXLAT")),Pvl::Replace); + mapGroup.AddKeyword(PvlKeyword("MinimumLongitude", ui.GetDouble("MINLON")),Pvl::Replace); + mapGroup.AddKeyword(PvlKeyword("MaximumLongitude", ui.GetDouble("MAXLON")),Pvl::Replace); + + Projection *proj = Isis::ProjectionFactory::Create(userMap); + + // Convert the Lat/Lon range to an X/Y range. + double minX; + double minY; + double maxX; + double maxY; + bool foundRange = proj->XYRange(minX, maxX, minY, maxY); + if (!foundRange) { + string msg = "Cannot convert Lat/Long range to an X/Y range."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Create the control net to store the points in. + cnet.SetType (ControlNet::ImageToGround); + cnet.SetTarget (target); + string networkId = ui.GetString("NETWORKID"); + cnet.SetNetworkId(networkId); + cnet.SetUserName(Isis::Application::UserName()); + cnet.SetDescription(ui.GetString("DESCRIPTION")); + + // Set up an automatic id generator for the point ids + ID pointId = ID(ui.GetString("POINTID")); + + double xStepSize = ui.GetDouble("XSTEP"); + double yStepSize = ui.GetDouble("YSTEP"); + + equatorialRadius = radii["EquatorialRadius"]; + + Progress gridStatus; + + int maxSteps = 0; + double x = minX; + while (x <= maxX) { + double y = minY; + while (y <= maxY) { + maxSteps++; + y += yStepSize; + } + x += xStepSize; + } + + if (maxSteps > 0) { + gridStatus.SetMaximumSteps(maxSteps); + gridStatus.SetText("Seeding Grid"); + gridStatus.CheckStatus(); + } + + x = minX; + while (x <= maxX) { + double y = minY; + while (y <= maxY) { + proj->SetCoordinate(x,y); + if (!proj->IsSky() && proj->Latitude() < ui.GetDouble("MAXLAT") && + proj->Longitude() < ui.GetDouble("MAXLON") && + proj->Latitude() > ui.GetDouble("MINLAT") && + proj->Longitude() > ui.GetDouble("MINLON")) { + ControlPoint control; + control.SetId (pointId.Next()); + control.SetIgnore (true); + control.SetUniversalGround(proj->Latitude(), proj->Longitude(), equatorialRadius); + cnet.Add(control); + } + y += yStepSize; + gridStatus.CheckStatus(); + } + x += xStepSize; + } + } + else { + + if (!ui.WasEntered("TARGET")) { + string msg = "A target must be specified by the [TARGET] parameter "; + msg += "or included as a value for keyword [TargetName] in the projection file."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + string target = ui.GetString("TARGET"); + PvlGroup radii = Projection::TargetRadii(target); + equatorialRadius = radii["EquatorialRadius"]; + + // Create the control net to store the points in. + cnet.SetType (ControlNet::ImageToGround); + cnet.SetTarget (target); + string networkId = ui.GetString("NETWORKID"); + cnet.SetNetworkId(networkId); + cnet.SetUserName(Isis::Application::UserName()); + cnet.SetDescription(ui.GetString("DESCRIPTION")); + + // Set up an automatic id generator for the point ids + ID pointId = ID(ui.GetString("POINTID")); + + double minLat = ui.GetDouble("MINLAT"); + double maxLat = ui.GetDouble("MAXLAT"); + double latStep = ui.GetDouble("LATSTEP"); + + double minLon = ui.GetDouble("MINLON"); + double maxLon = ui.GetDouble("MAXLON"); + double lonStep = ui.GetDouble("LONSTEP"); + + Progress gridStatus; + + int maxSteps = 0; + double lon = minLon; + while (lon <= maxLon) { + double lat = minLat; + while (lat <= maxLat) { + maxSteps++; + lat += latStep; + } + lat = minLat; + lon += lonStep; + } + + if (maxSteps > 0) { + gridStatus.SetMaximumSteps(maxSteps); + gridStatus.SetText("Seeding Grid"); + gridStatus.CheckStatus(); + } + + lon = minLon; + while (lon <= maxLon) { + double lat = minLat; + while (lat <= maxLat) { + ControlPoint control; + control.SetId (pointId.Next()); + control.SetIgnore (true); + control.SetUniversalGround(lat, lon, equatorialRadius); + cnet.Add(control); + + lat += latStep; + gridStatus.CheckStatus(); + } + lon += lonStep; + } + } + + PvlGroup results ("Results"); + results += PvlKeyword("EquatorialRadius", equatorialRadius); + results += PvlKeyword("NumberControlPoints", cnet.Size()); + Application::Log(results); + + cnet.Write(ui.GetFilename("TO")); +} + +// Helper function to print out mapfile to session log +void PrintMap() { + UserInterface &ui = Application::GetUserInterface(); + + // Get mapping group from map file + Pvl userMap; + userMap.Read(ui.GetFilename("PROJECTION")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + //Write map file out to the log + Isis::Application::GuiLog(userGrp); +} diff --git a/isis/src/base/apps/seedgrid/seedgrid.xml b/isis/src/base/apps/seedgrid/seedgrid.xml new file mode 100644 index 0000000000000000000000000000000000000000..96d7cf3bbd9438e26fe4335a658748512db49711 --- /dev/null +++ b/isis/src/base/apps/seedgrid/seedgrid.xml @@ -0,0 +1,312 @@ + + + + + + Creates a control network for a Lat/Lon range + + + +

    + This program creates a control network for a latitude/longitude range on a + specified target planet using a specified projection type to do the + seeding. The control network generated will have no control measures, but + will instead have a known latitude and longitude for each control point. +

    +
    + + + Control Networks + + + + + Original version + + + Fixed error when calculating X/Y range and added application test. + + + Added parameter allowing user to enter in projection type to use in seeding process. + + + Changed means of entering projection type to be a map file so as to allow + for more customization and accepted projection types. + + + Added option to use lat/lon spacing when seeding points; fixed bug causing + points to be seeded outside the lat/lon range; added a default projection + type and reinstated the TARGET parameter so the user does not need to edit + a projection file in order to run the program. + + + Added progress bar. + + + + + + + + + string + + Target planet for the Lat/Lon range + + + This is the planet on which the Lat/Lon range resides. The target + can be specified in one of two ways: by typing the name of a planet + for this parameter, or by including a value for the keyword TargetName + in the PROJECTION file, which will set the value of this parameter at + runtime, and show up in the print file. If the user specifies both, + then the value for the TARGET parameter will be used. If neither is + specified, the program will throw an error. + + From PROJECTION file + + + + filename + input + + File containing mapping parameters + + $base/templates/maps + $base/templates/maps/sinusoidal.map + + A file containing the mapping parameters in PVL form. This + file can be a hand produced label file. It can also be an existing cube label + which contains a Mapping group. By default, the program will use a + standard map template for a Sinusoidal projection. If the keyword + TargetName is not in this projection file, then the user must specify + a value for the TARGET parameter. If the TargetName keyword is used, + then the program will set the value of the TARGET parameter to the + value of the keyword. You can produce map files using the + "maptemplate" program. + + + + PrintMap + View MapFile + + This helper button will cat out the mapping group of the given mapfile to the session log + of the application + + $ISIS3DATA/base/icons/labels.png + + + + *.map *.cub + + + + + double + + Minimum Latitude + + + This is the minimum latitude for the Lat/Lon range. + + + + + double + + Maximum Latitude + + + This is the maximum latitude for the Lat/Lon range. + + + + + double + + Minimum Longitude + + + This is the minimum longitude for the Lat/Lon range. + + + + + double + + Maximum Longitude + + + This is the maximum longitude for the Lat/Lon range. + + + + + + + string + + Whether the generated control points should be spaced by a meter + increment, or by a latitude/longitude increment. + + + This option allows the user to specify the type of spacing the + program will use when generating the control points. Selecting + METER spacing will use a projection to attempt to place control + points every XSTEP meters within the longitude range, and every + YSTEP meters within the latitude range. Conversely, LATLON spacing + will simply place control points every LATSTEP and LONSTEP within + the range. + + METER + + + + + + + + double + + Step Size in the x direction in meters. + + + Points will be placed on the grid in the longitude range in the + step descriped here in meters. + + + + + double + + Step Size in the y direction in meters. + + + Points will be placed on the grid in the latitude range in the step + descriped here in meters. + + + + + double + + Step Size in the north/south direction. + + + Points will be placed on the grid in the latitude range in the + step descriped here in degrees latitude. + + + + + double + + Step Size in the east/west direction. + + + Points will be placed on the grid in the longitude range in the + step descriped here in degrees longitude. + + + + + + + + + string + + Name of this control network + + + The ID or name of this particular control network. This string + should be unique. + + + + + string + + The pattern to be used to create point ids. + + + A string with one and only one set of question marks ("?"). + This string will be used to create unique IDs for each control + point created by this program. The question marks will be replaced + with a number beginning with zero. For example the pattern + "User????" would create point IDs "User0001" through + "User9999". Note: Make sure there are enough "?"s for all the control + points that may be created during this run. If all question marks are + exausted the program will throw an error. + + + + + string + + The description of the network. + + + A string describing purpose of this control network. + + + + + + + + filename + output + + Output control network + + + This file will contain the control network + + + + + + +
    diff --git a/isis/src/base/apps/seedgrid/tsts/Makefile b/isis/src/base/apps/seedgrid/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/seedgrid/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/seedgrid/tsts/default/Makefile b/isis/src/base/apps/seedgrid/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fb6678a504cffe1d902ccdc706a54da2d9d86cff --- /dev/null +++ b/isis/src/base/apps/seedgrid/tsts/default/Makefile @@ -0,0 +1,10 @@ +APPNAME = seedgrid + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) projection=$(INPUT)/sinusoidal.map minlat=40 maxlat=50 \ + minlon=280 maxlon=290 xstep=100000 ystep=100000 \ + networkid=NET001 pointid=PT?? description="Test control network" \ + to=$(OUTPUT)/outnet.pvl \ + > /dev/null; diff --git a/isis/src/base/apps/seedgrid/tsts/latlon/Makefile b/isis/src/base/apps/seedgrid/tsts/latlon/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..56b5b173d6263cd1c84a730cdc9a2b9b1ff1d5a3 --- /dev/null +++ b/isis/src/base/apps/seedgrid/tsts/latlon/Makefile @@ -0,0 +1,10 @@ +APPNAME = seedgrid + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) target=moon minlat=-10.6 maxlat=-7.3 spacing=latlon \ + minlon=14.3 maxlon=16.6 latstep=0.35 lonstep=0.71 \ + networkid=NET001 pointid=PT?? description="Test control network" \ + to=$(OUTPUT)/outnet.pvl \ + > /dev/null; diff --git a/isis/src/base/apps/segment/Makefile b/isis/src/base/apps/segment/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/segment/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/segment/assets/image/peaks.jpg b/isis/src/base/apps/segment/assets/image/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..97bdcb75713953dadd6c71d181a18d600b72b365 Binary files /dev/null and b/isis/src/base/apps/segment/assets/image/peaks.jpg differ diff --git a/isis/src/base/apps/segment/assets/image/peaks.segment1.jpg b/isis/src/base/apps/segment/assets/image/peaks.segment1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e1eb68250fb628427168aef63ad111ec4c406610 Binary files /dev/null and b/isis/src/base/apps/segment/assets/image/peaks.segment1.jpg differ diff --git a/isis/src/base/apps/segment/assets/image/peaks.segment2.jpg b/isis/src/base/apps/segment/assets/image/peaks.segment2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9c0690d793561c08bb947521b02591d138c724c6 Binary files /dev/null and b/isis/src/base/apps/segment/assets/image/peaks.segment2.jpg differ diff --git a/isis/src/base/apps/segment/assets/image/peaks.segment3.jpg b/isis/src/base/apps/segment/assets/image/peaks.segment3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1920ed52de12a22474085a1a7ad249404e6c4a2f Binary files /dev/null and b/isis/src/base/apps/segment/assets/image/peaks.segment3.jpg differ diff --git a/isis/src/base/apps/segment/segment.cpp b/isis/src/base/apps/segment/segment.cpp new file mode 100644 index 0000000000000000000000000000000000000000..968b18e5afc916f8ab6412edf0b9440d2a0310aa --- /dev/null +++ b/isis/src/base/apps/segment/segment.cpp @@ -0,0 +1,47 @@ +#include "Isis.h" +#include "Application.h" +#include "Cube.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + + //Get user parameters + UserInterface &ui = Application::GetUserInterface(); + Filename inFile = ui.GetFilename("FROM"); + int numberOfLines = ui.GetInteger("NL"); + int lineOverlap = ui.GetInteger("OVERLAP"); + + //Throws exception if user is dumb + if ( lineOverlap >= numberOfLines ) { + throw iException::Message( iException::User, "The Line Overlap (OVERLAP) must be less than the Number of Lines (LN).", _FILEINFO_ ); + } + + //Opens the cube + Cube cube; + cube.Open( inFile.Expanded() ); + + //Loops through, cropping as desired + int cropNum = 1; + int startLine = 1; + bool hasReachedEndOfCube = false; + while ( startLine <= cube.Lines() && not hasReachedEndOfCube ) { + //! Sets up the proper paramaters for running the crop program + string parameters = "FROM=" + inFile.Expanded() + + " TO=" + inFile.Path() + "/" + inFile.Basename() + ".segment" + iString(cropNum) + ".cub" + + " LINE=" + iString(startLine) + " NLINES="; + + if ( startLine + numberOfLines > cube.Lines() ) { + parameters += iString( cube.Lines() - ( startLine - 1 ) ); + hasReachedEndOfCube = true; + } + else { + parameters += iString(numberOfLines); + } + Isis::iApp ->Exec("crop",parameters); + //The starting line for next crop + startLine = 1 + cropNum * ( numberOfLines - lineOverlap ); + cropNum++; + } +} diff --git a/isis/src/base/apps/segment/segment.xml b/isis/src/base/apps/segment/segment.xml new file mode 100644 index 0000000000000000000000000000000000000000..19408fd061ffdcb380d6a739868b2742fa840bf5 --- /dev/null +++ b/isis/src/base/apps/segment/segment.xml @@ -0,0 +1,128 @@ + + + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://isis.astrogeology.usgs.gov/Schemas/Application/application.xsd"> + + Divides a cube object into multiple output cubes in the line direction. + + + This program takes an input cube and divides it into multiple output cubes in the line direction. + The total number of lines in these output cubes, as well as the number of lines these output cubes overlap, are be determined by user given parameters. + If the overlap parameter is greater than the total line number parameter, then a User Errror will be thrown. + If the final segment does not end on the same line that the input cube ends, then the final segment will be smaller than the other segments. + In other words, the final segment will simply be created to the end of the original cube, not being filled with null lines. +

    Note: The output cubes (which will here on be referred to as segments) will be created in the naming form of (InputCubeName).segment(#).cub +
    i.e. peaks.segment1.cub, peaks.segment2.cub, peaks.segment3.cub, peaks.segment4.cub, etc

    +
    + + + Utility + + + + + Original version + + + + + + + + cube + input + + Input cube file. + + + Input cube to be segmented. + + + *.cub + + + + + + + + integer + Number of Lines for each new cube segment + + Specifies the total number of lines each segment will contain. + This parameter must always be specified. + + + + + integer + Number of Overlapping Lines for each new cube + + Specifies the total number of lines of overlap each segment will have with the previous segment as well as the next segment. + This parameter must always be specified. + + + + + + + + + Segmented Peaks + + This example shows how segment works on peaks.cub, a cube of Flagstaff's peaks. It also demonstrates the automatic resizing of the final segment. + + + + FROM=peaks.cub NL=531 OVERLAP=88 + + Creates segments from peaks.cub which have a total of 531 lines each, and overlap by 88 lines. + + + + + + The original image + + This is the input image peaks.cub + + + FROM + + + + + + The first segment. + + This is the first segment created from peaks.cub +

    It has the same sample width and band depth as peaks.cub, and has a total number of lines equal to the NL parameter, which is 531 in this example.

    +
    + + + + The second segment. + + This is the second segment created from peaks.cub +

    Like peaks.segment1.cub, it has 531 lines and the same sample width and band depth as peaks.cub. + The first 88 lines of this cube (peaks.segment2.cub) are identical to the last 88 lines of its previous cube (peaks.segment1.cub). + In the same manner, the last 88 lines of peaks.segment2.cub are identical to the first 88 lines of peaks.segment3.cub

    +
    + + + + The third segment. + + This is the third segment created from peaks.cub +

    Notice how this segment is smaller than the other 2 segements. This is due to the fact that it reached the end of peaks.cub, nevertheless, it still has the same + sample width and band depth as peaks.cub +
    This shortening of the segment will only happen in the final segment created from the input cube.

    +
    + + +
    + + +
    +
    + +
    diff --git a/isis/src/base/apps/segment/tsts/Makefile b/isis/src/base/apps/segment/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/segment/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/segment/tsts/boundry/Makefile b/isis/src/base/apps/segment/tsts/boundry/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..84feadd50701b3856eec6858a47dc5166afa7edf --- /dev/null +++ b/isis/src/base/apps/segment/tsts/boundry/Makefile @@ -0,0 +1,8 @@ +APPNAME = segment + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/peaks.cub $(OUTPUT)/out.cub; + $(APPNAME) from=$(OUTPUT)/out.cub \ + NL=531 OVERLAP=88 > /dev/null; diff --git a/isis/src/base/apps/segment/tsts/default/Makefile b/isis/src/base/apps/segment/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..749130f4ecd24807fd186b9e2e5679330086037f --- /dev/null +++ b/isis/src/base/apps/segment/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = segment + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/peaks.cub $(OUTPUT)/out.cub; + $(APPNAME) from=$(OUTPUT)/out.cub \ + NL=256 OVERLAP=64 > /dev/null; diff --git a/isis/src/base/apps/shade/Makefile b/isis/src/base/apps/shade/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/shade/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/shade/assets/image/292.jpg b/isis/src/base/apps/shade/assets/image/292.jpg new file mode 100644 index 0000000000000000000000000000000000000000..50607118e7ac08f6bd1796d217b81debdfb7bdcd Binary files /dev/null and b/isis/src/base/apps/shade/assets/image/292.jpg differ diff --git a/isis/src/base/apps/shade/assets/image/GUI.jpg b/isis/src/base/apps/shade/assets/image/GUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..48237ef4f20c05872e319bfcceca973c39c0b917 Binary files /dev/null and b/isis/src/base/apps/shade/assets/image/GUI.jpg differ diff --git a/isis/src/base/apps/shade/assets/image/Vallis_Marinaris.jpg b/isis/src/base/apps/shade/assets/image/Vallis_Marinaris.jpg new file mode 100644 index 0000000000000000000000000000000000000000..914f12ed69d23b025c3a6853ba41565ac6df3bc9 Binary files /dev/null and b/isis/src/base/apps/shade/assets/image/Vallis_Marinaris.jpg differ diff --git a/isis/src/base/apps/shade/assets/thumb/292.thumb.jpg b/isis/src/base/apps/shade/assets/thumb/292.thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..671aff5cb393513b62d41174530048c13d06ba3a Binary files /dev/null and b/isis/src/base/apps/shade/assets/thumb/292.thumb.jpg differ diff --git a/isis/src/base/apps/shade/assets/thumb/GUI.thumb.jpg b/isis/src/base/apps/shade/assets/thumb/GUI.thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..82ee40faa634cd078e801155eb2a91a754939015 Binary files /dev/null and b/isis/src/base/apps/shade/assets/thumb/GUI.thumb.jpg differ diff --git a/isis/src/base/apps/shade/assets/thumb/Vallis_Marinaris.thumb.jpg b/isis/src/base/apps/shade/assets/thumb/Vallis_Marinaris.thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9bb2ae2826250e8e99d6ebcc4c1161fa0b28d4c1 Binary files /dev/null and b/isis/src/base/apps/shade/assets/thumb/Vallis_Marinaris.thumb.jpg differ diff --git a/isis/src/base/apps/shade/shade.cpp b/isis/src/base/apps/shade/shade.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c25c322aacec0ca3a25d2f006363344ae0f8ba41 --- /dev/null +++ b/isis/src/base/apps/shade/shade.cpp @@ -0,0 +1,128 @@ +#include +#include "Isis.h" +#include "ProcessByBoxcar.h" +#include "Constants.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +double pixelResolution; +double saz; +double zenith; + +void shade (Buffer &in, double &v); + +void IsisMain() { + + const double DEG2RAD = PI/180.0; + ProcessByBoxcar p; + + UserInterface &ui = Application::GetUserInterface(); + + // Open the input cube + Cube *inCube = p.SetInputCube ("FROM"); + + // Allocate the output cube + p.SetOutputCube ("TO"); + + p.SetBoxcarSize(3,3); + + // Read user parameters + // This parameter as used by the algorithm is 0-360 with 0 at 3 o'clock, + // increasing in the clockwise direction. The value taken in from the user is + // 0-360 with 0 at 12 o'clock increasing in the clockwise direction. + saz = ui.GetDouble ("AZIMUTH"); + saz += 270; + if (saz > 360) saz -= 360; + saz *= DEG2RAD; + + // This parameter as used by the algorithm is 0-90 as the angle to the light source, + // this means 90 is at the horizon and 0 is directly overhead. + zenith = ui.GetDouble ("ZENITH"); + zenith *= DEG2RAD; + + // Get from labels or from user + if (ui.WasEntered("PIXELRESOL")) { + pixelResolution = ui.GetDouble ("PIXELRESOL"); + } + else { + if (inCube->Label()->FindObject("IsisCube").HasGroup("Mapping")) { + pixelResolution = inCube->Label()->FindObject("IsisCube").FindGroup("Mapping")["PixelResolution"]; + } + else { + string msg = "The file [" + ui.GetFilename("FROM") + "] does not have a mapping group," + + " you must enter a Pixel Resolution"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + p.StartProcess (shade); + p.EndProcess (); + +} + +// Shade processing routine +void shade (Buffer &in,double &v) { + + // first we just check to make sure that we don't have any special pixels + bool specials = false; + for (int i=0; i + + + + + Create shaded-relief cube from topographic cube + + + + This program will create a shaded-relief cube from a topographic cube. It uses the sun angle (azimuth) + as well as the solar elevation (zenith) to compute the correct shading on the output cube. + + + + + Original version + + + Changed category from filter to photometry. + + + Changed user parameter names and now read pixel resolution + from labels. + + + Added application test + + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Algorithm change and input parameter change. + + + Reversed slopes to be correct. Changed azimuth to be 0 degrees is 12 + o'clock rotating clockwise. Updated documentation to match. + + + + + + 2007-05-31 Deborah Lee Soltesz: find out why IsisGUIBuilder doesn't + read this file and display it correctly. + + + + + Radiometric and Photometric Correction + + + + + + cube + input + + Input cube + + + Use this parameter to select the input filename. All bands within the file + will have the shade applied. + + + *.cub + + + + + cube + real + output + + Output cube + + + This file will contain the shaded output image. + + + + + + + double + Sun azimuth + + 90.0 + + 0 + 360 + + The direction of sun with 0 degrees at the 12:00, north position, + rotating clockwise. Ranging from 0 to 359.9. + + + + double + Sun angle + + 45.0 + + 0 + 90 + + The Sun Angle is the elevation at which the sun is relative to the + planet horizon. 90 degrees is at the horizon, 0 is directly overhead. + + + + + + + double + Automatic + Pixel resolution + + The pixel resolution of the image. This parameter will default to + the value from the labels or may be used to increase or decrease the + apparent steepness. If no mapping group exists, the user must enter a + pixel resolution. Greater than the image's pixel resolution will level + and smooth, and less than will make steep and sharpen. + + + + + + + + + Shading Vallis Marinaris + + Creating a shaded relief of Vallis Marinaris with a 22 degree azimuth + and a 45 degree zenith + + + from=vallis_marinaris.cub to=22.cub azimuth=22 + + + In this example shade will create a shaded relief of Vallis Marinaris + with a 22 solar azimuth and a 45 degree zenith + + + + + + Input image for shade + + This is the input image used in the creation of our shaded relief. + + + FROM + + + + + + Output image for shade + This is the output image that resulted. + + + TO + + + + + + + Example Gui + + Screenshot of the GUI with parameters filled in to perform a 22 + azimuth shade on our input image. + + + + + + + + + + diff --git a/isis/src/base/apps/shade/tsts/173.10/Makefile b/isis/src/base/apps/shade/tsts/173.10/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6b2ca37ffd583c35d47dd1b6d4266b3ff99d613f --- /dev/null +++ b/isis/src/base/apps/shade/tsts/173.10/Makefile @@ -0,0 +1,7 @@ +APPNAME = shade + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/128_vallis_marinaris.cub to=$(OUTPUT)/shadeTruth.cub azimuth=173 zenith=10 PIXELRESOL=926 > /dev/null; + diff --git a/isis/src/base/apps/shade/tsts/173.40/Makefile b/isis/src/base/apps/shade/tsts/173.40/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7667e7b7c91df4eec5e7fd9d15519946c47073dd --- /dev/null +++ b/isis/src/base/apps/shade/tsts/173.40/Makefile @@ -0,0 +1,7 @@ +APPNAME = shade + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/128_vallis_marinaris.cub to=$(OUTPUT)/shadeTruth.cub azimuth=173 zenith=40 PIXELRESOL=926 > /dev/null; + diff --git a/isis/src/base/apps/shade/tsts/173.80/Makefile b/isis/src/base/apps/shade/tsts/173.80/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..07286e30423c4edcdae6638d060123652face59a --- /dev/null +++ b/isis/src/base/apps/shade/tsts/173.80/Makefile @@ -0,0 +1,7 @@ +APPNAME = shade + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/128_vallis_marinaris.cub to=$(OUTPUT)/shadeTruth.cub azimuth=173 zenith=80 PIXELRESOL=926 > /dev/null; + diff --git a/isis/src/base/apps/shade/tsts/73.37/Makefile b/isis/src/base/apps/shade/tsts/73.37/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..861f90367346ead079e885252b27b82e4d139c96 --- /dev/null +++ b/isis/src/base/apps/shade/tsts/73.37/Makefile @@ -0,0 +1,7 @@ +APPNAME = shade + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/128_vallis_marinaris.cub to=$(OUTPUT)/shadeTruth.cub azimuth=73 zenith=37 PIXELRESOL=926 > /dev/null; + diff --git a/isis/src/base/apps/shade/tsts/73.45/Makefile b/isis/src/base/apps/shade/tsts/73.45/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b0ced189f1e7b0febc253f539b3bb989c84aa640 --- /dev/null +++ b/isis/src/base/apps/shade/tsts/73.45/Makefile @@ -0,0 +1,7 @@ +APPNAME = shade + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/128_vallis_marinaris.cub to=$(OUTPUT)/shadeTruth.cub azimuth=73 zenith=45 PIXELRESOL=926 > /dev/null; + diff --git a/isis/src/base/apps/shade/tsts/73.53/Makefile b/isis/src/base/apps/shade/tsts/73.53/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5a118f55daddee04d71014f564466273a3faf834 --- /dev/null +++ b/isis/src/base/apps/shade/tsts/73.53/Makefile @@ -0,0 +1,7 @@ +APPNAME = shade + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/128_vallis_marinaris.cub to=$(OUTPUT)/shadeTruth.cub azimuth=73 zenith=53 PIXELRESOL=926 > /dev/null; + diff --git a/isis/src/base/apps/shade/tsts/Makefile b/isis/src/base/apps/shade/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/shade/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/sharpen/Makefile b/isis/src/base/apps/sharpen/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/sharpen/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/sharpen/assets/image/peaks.4.jpg b/isis/src/base/apps/sharpen/assets/image/peaks.4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8225c3b35c062bd2198328e68a07b5c649fd4eb5 Binary files /dev/null and b/isis/src/base/apps/sharpen/assets/image/peaks.4.jpg differ diff --git a/isis/src/base/apps/sharpen/assets/image/sharpen.jpg b/isis/src/base/apps/sharpen/assets/image/sharpen.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7498baa671e16735508565a9239124e4b84d1057 Binary files /dev/null and b/isis/src/base/apps/sharpen/assets/image/sharpen.jpg differ diff --git a/isis/src/base/apps/sharpen/assets/image/sharpenGui.jpg b/isis/src/base/apps/sharpen/assets/image/sharpenGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c05ca91c15baa4a4af46c5a8fbd54ed5d15a5fa8 Binary files /dev/null and b/isis/src/base/apps/sharpen/assets/image/sharpenGui.jpg differ diff --git a/isis/src/base/apps/sharpen/assets/thumb/peaks.4.jpg b/isis/src/base/apps/sharpen/assets/thumb/peaks.4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..799ba9235183d87f0072afe76397eb0ffa38d650 Binary files /dev/null and b/isis/src/base/apps/sharpen/assets/thumb/peaks.4.jpg differ diff --git a/isis/src/base/apps/sharpen/assets/thumb/sharpen.jpg b/isis/src/base/apps/sharpen/assets/thumb/sharpen.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6f0ea9a3d3113793b60457780857a48c6c7a9d34 Binary files /dev/null and b/isis/src/base/apps/sharpen/assets/thumb/sharpen.jpg differ diff --git a/isis/src/base/apps/sharpen/assets/thumb/sharpenGui.jpg b/isis/src/base/apps/sharpen/assets/thumb/sharpenGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5527f7ed591f3156d9fb024bc017a8cca26ff7bd Binary files /dev/null and b/isis/src/base/apps/sharpen/assets/thumb/sharpenGui.jpg differ diff --git a/isis/src/base/apps/sharpen/sharpen.cpp b/isis/src/base/apps/sharpen/sharpen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d7264a9883edf1934eb69d42933f6898abc3eb85 --- /dev/null +++ b/isis/src/base/apps/sharpen/sharpen.cpp @@ -0,0 +1,52 @@ +#include "Isis.h" +#include "ProcessByQuickFilter.h" +#include "UserInterface.h" + +using namespace std; +using namespace Isis; + +// Globals and prototypes +bool propagate; +void sharpen (Buffer &in, Buffer &out, QuickFilter &filter); + +// The sharpen main routine +void IsisMain() { + ProcessByQuickFilter p; + + // Open the input cube + p.SetInputCube("FROM"); + + // Setup the output cube + p.SetOutputCube("TO"); + + // Find out how to handle special pixels + UserInterface &ui = Application::GetUserInterface(); + propagate = ui.GetBoolean ("PROPAGATE"); + + // Process each line + p.StartProcess(sharpen); // Line processing function + p.EndProcess(); // Cleanup +} + +// Line processing routine +void sharpen (Buffer &in, Buffer &out, QuickFilter &filter) { + for (int i=0; i + + + + + Sharpen the features in a cube + + + + This program sharpens the edges in the image. The method for sharpening + is done by applying a high pass filter to a cube and adding the filter + results back to the original image. In general, you will sharpen small + features with smaller boxcars and larger features with larger boxcars. + + + + Filters + + + + + highpass + + + + + + Original version + + + + Ported to Isis 3.0 + + + + Add example. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Removed addback option and put it in the highpass program + + + + + boxfilter + + + + + + cube + input + + Input file + + + Input cube to filter + + + *.cub + + + + cube + output + + Output highpass cube + + + The resultant filtered cube + + + + + + + integer + 3 + + Number of samples in boxcar + + + + This is the total number of samples in the boxcar. + It must be odd and can not exceed twice the number of samples + in the cube. In general, the size of the boxcar does not + cause the program to operate significantly slower. + + + + + 1 + + + + integer + 3 + + Number of lines in boxcar + + + + This is the total number of lines in the boxcar. + It must be odd and can not exceed twice the number of lines + in the cube. In general, the size of the boxcar does not + cause the program to operate significantly + slower. + + + + + 1 + + + + + + double + + Valid minimum pixel + + + Valid minimum pixel value that will be used in boxcar computation. If + a pixel value is less than LOW then it will not be used when + computing boxcar statistics. + + + Use all pixels + + + HIGH + + + + + double + + Valid maximum pixel + + + Valid maximum pixel value that will be used in boxcar computation. If + a pixel value is greater than HIGH then it will not be used when + computing boxcar statistics. + + + Use all pixels + + + LOW + + + + + integer + + Minimum boxcar pixel count + + + This is the minimum number of valid pixels which must occur inside the + NxM boxcar for filtering to occur. For example, 3x5 boxcar has 15 pixels + inside. If MINIMUM=10 then the filter will occur if there are 10 or + greater valid pixels. A valid pixel is one that is not special (NULL, LIS, + etc) and is in the range defined by LOW to HIGH. + + + 1 + + 1 + + + + + + boolean + TRUE + Propagate special pixels + + This option is used to define how special pixels are handled. If the + center pixel of the boxcar is a special pixel it will be propagated + or set to NULL depending on the value of this parameter. + + + + + + + 3x3 + + Use a 3x3 boxcar + + + f=peaks.cub:4 t=sharpen + + + In this example the boxcar size is the default 3 by 3. + + + + + + Input image for sharpen + This is the input image for the sharpen example. + + + FROM + + + + + + Output image for sharpen + This is the output image for this example of sharpen. Notice the edges of features are sharper. It is the same as running highpass and adding the highpass output back to the input image. + + + TO + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a "sharpen"ing of the input image with the default boxcar of 3x3. + + + + + + + diff --git a/isis/src/base/apps/sharpen/tsts/Makefile b/isis/src/base/apps/sharpen/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/sharpen/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/sharpen/tsts/default/Makefile b/isis/src/base/apps/sharpen/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..65decb4fc00ea00daf458d43d8814da8da1c1cc7 --- /dev/null +++ b/isis/src/base/apps/sharpen/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = sharpen + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/sharpenTruth.cub \ + samp=5 \ + line=5 > /dev/null; diff --git a/isis/src/base/apps/skymap/Makefile b/isis/src/base/apps/skymap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/skymap/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/skymap/skymap.cpp b/isis/src/base/apps/skymap/skymap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..837bc3ca328b22b8036fdeb99cad4b5e9449d52d --- /dev/null +++ b/isis/src/base/apps/skymap/skymap.cpp @@ -0,0 +1,380 @@ +#define GUIHELPERS + +#include "Isis.h" + +#include "Camera.h" +#include "ProjectionFactory.h" +#include "ProcessRubberSheet.h" + +#include "iException.h" + +using namespace std; +using namespace Isis; + +void PrintMap (); +void LoadMapRes (); +void LoadCameraRes (); +void LoadMapRange (); +void LoadCameraRange (); + +map GuiHelpers(){ + map helper; + helper ["PrintMap"] = (void*) PrintMap; + helper ["LoadMapRes"] = (void*) LoadMapRes; + helper ["LoadCameraRes"] = (void*) LoadCameraRes; + helper ["LoadMapRange"] = (void*) LoadMapRange; + helper ["LoadCameraRange"] = (void*) LoadCameraRange; + return helper; +} + +class sky2map : public Transform { + private: + Camera *p_incam; + Projection *p_outmap; + int p_inputSamples; + int p_inputLines; + bool p_trim; + int p_outputSamples; + int p_outputLines; + + public: + // constructor + sky2map (const int inputSamples, const int inputLines, Camera *incam, + const int outputSamples, const int outputLines, Projection *outmap, + bool trim); + + // destructor + ~sky2map () {}; + + // Implementations for parent's pure virtual members + bool Xform (double &inSample, double &inLine, + const double outSample, const double outLine); + int OutputSamples () const; + int OutputLines () const; +}; + +void BandChange (const int band); +Cube *icube; +Camera *incam; + +void IsisMain() { + // Get the camera model established from the input file. We want to have + // TargetName = Sky in the labels so make it happpen + ProcessRubberSheet p; + + UserInterface &ui = Application::GetUserInterface(); + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + // Open the input cube, get the camera object, and the cam map projection + // Note: The default target info is positive west, planetocentric, 360 + icube = p.SetInputCube ("FROM"); + incam = icube->Camera(); + + // Pvl lab(ui.GetFilename("FROM")); + // PvlGroup &inst = lab.FindGroup("Instrument",Pvl::Traverse); + //inst["TargetName"] = "Sky"; + + // Add the default mapping info to the user entered mapping group + userGrp.AddKeyword(PvlKeyword("TargetName","Sky"),Pvl::Replace); + userGrp.AddKeyword(PvlKeyword("EquatorialRadius",1.0),Pvl::Replace); + userGrp.AddKeyword(PvlKeyword("PolarRadius",1.0),Pvl::Replace); + userGrp.AddKeyword(PvlKeyword("LatitudeType","Planetocentric"),Pvl::Replace); + userGrp.AddKeyword(PvlKeyword("LongitudeDirection","PositiveWest"),Pvl::Replace); + userGrp.AddKeyword(PvlKeyword("LongitudeDomain","360"),Pvl::Replace); + if (userGrp.HasKeyword("PixelResolution")) { + userGrp.DeleteKeyword("PixelResolution"); + } + + if (ui.GetString("DEFAULTRANGE") == "CAMERA") { + // Get the default ra/dec range + double minRa,maxRa,minDec,maxDec; + incam->RaDecRange(minRa,maxRa,minDec,maxDec); + userGrp.AddKeyword(PvlKeyword("MinimumLongitude",minRa),Pvl::Replace); + userGrp.AddKeyword(PvlKeyword("MaximumLongitude",maxRa),Pvl::Replace); + userGrp.AddKeyword(PvlKeyword("MinimumLatitude",minDec),Pvl::Replace); + userGrp.AddKeyword(PvlKeyword("MaximumLatitude",maxDec),Pvl::Replace); + } + if (ui.GetString("DEFAULTSCALE") == "CAMERA") { + double res = incam->RaDecResolution(); + userGrp.AddKeyword(PvlKeyword("Scale",1.0/res),Pvl::Replace); + } + + // Override computed range with the users request + if (ui.WasEntered("SRA")) { + userGrp.AddKeyword(PvlKeyword("MinimumLongitude",ui.GetDouble("SRA")),Pvl::Replace); + } + if (ui.WasEntered("ERA")) { + userGrp.AddKeyword(PvlKeyword("MaximumLongitude",ui.GetDouble("ERA")),Pvl::Replace); + } + if (ui.WasEntered("SDEC")){ + userGrp.AddKeyword(PvlKeyword("MinimumLatitude",ui.GetDouble("SDEC")),Pvl::Replace); + } + if (ui.WasEntered("EDEC")){ + userGrp.AddKeyword(PvlKeyword("MaximumLatitude",ui.GetDouble("EDEC")),Pvl::Replace); + } + + // Get the resolution from the user if they decided to enter it + if (ui.GetString("DEFAULTSCALE") == "USER") { + userGrp.AddKeyword(PvlKeyword("Scale",ui.GetDouble("SCALE")),Pvl::Replace); + } + + // Create the projection + int samples,lines; + Projection *proj = ProjectionFactory::CreateForCube(userMap,samples,lines); + + // Output the mapping group used to the gui session log + Application::GuiLog(userGrp); + + // Create the transform object which maps + // output line/samp -> output lat/lon (dec/ra) -> input line/samp + Transform *xform = new sky2map (icube->Samples(),icube->Lines(),incam, + samples,lines,proj, + ui.GetBoolean("Trim")); + + // Create the output cube and add the projection group + Cube *ocube = p.SetOutputCube("TO",xform->OutputSamples(), + xform->OutputLines(), + icube->Bands()); + ocube->PutGroup(userGrp); + + // Set up the interpolator + Interpolator *interp = NULL; + if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { + interp = new Interpolator(Interpolator::NearestNeighborType); + } + else if (ui.GetString("INTERP") == "BILINEAR") { + interp = new Interpolator(Interpolator::BiLinearType); + } + else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { + interp = new Interpolator(Interpolator::CubicConvolutionType); + } + + // If we need to deal with band dependent camera models, register + // our function to handle that + if (!incam->IsBandIndependent()) { + p.BandChange(BandChange); + } + + // See if center of input image projects. If it does, force tile + // containing this center to be processed in ProcessRubberSheet. + + double centerSamp = icube->Samples () / 2.; + double centerLine = icube->Lines () / 2.; + incam->SetImage(centerSamp,centerLine); + if (proj->SetGround(incam->Declination(), + incam->RightAscension())) { + p.ForceTile (proj->WorldX(),proj->WorldY ()); + } + + // Create an alpha cube group for the output cube + if (!ocube->HasGroup("AlphaCube")) { + PvlGroup alpha("AlphaCube"); + alpha += PvlKeyword("AlphaSamples",icube->Samples()); + alpha += PvlKeyword("AlphaLines",icube->Lines()); + alpha += PvlKeyword("AlphaStartingSample",0.5); + alpha += PvlKeyword("AlphaStartingLine",0.5); + alpha += PvlKeyword("AlphaEndingSample",icube->Samples()+0.5); + alpha += PvlKeyword("AlphaEndingLine",icube->Lines()+0.5); + alpha += PvlKeyword("BetaSamples",icube->Samples()); + alpha += PvlKeyword("BetaLines",icube->Lines()); + ocube->PutGroup(alpha); + } + + // Warp the cube + p.StartProcess(*xform, *interp); + p.EndProcess(); + + // add mapping to print.prt + PvlGroup mapping = proj->Mapping(); + Application::Log(mapping); + + // Cleanup + delete xform; + delete interp; +} + +void BandChange (const int band) { + incam->SetBand(band); +} + +sky2map::sky2map (const int inputSamples, const int inputLines, + Camera *incam, const int outputSamples, + const int outputLines, Projection *outmap, + bool trim) { + p_inputSamples = inputSamples; + p_inputLines = inputLines; + p_incam = incam; + + p_outputSamples = outputSamples; + p_outputLines = outputLines; + p_outmap = outmap; + + p_trim = trim; +} + +// Transform method mapping output line/samps to lat/lons to input line/samps +bool sky2map::Xform (double &inSample, double &inLine, + const double outSample, const double outLine) { + // See if the output image coordinate converts to lat/lon + if (!p_outmap->SetWorld(outSample,outLine)) return false; + + // See if we should trim + if ((p_trim) && (p_outmap->HasGroundRange())) { + if (p_outmap->Latitude() < p_outmap->MinimumLatitude()) return false; + if (p_outmap->Latitude() > p_outmap->MaximumLatitude()) return false; + if (p_outmap->Longitude() < p_outmap->MinimumLongitude()) return false; + if (p_outmap->Longitude() > p_outmap->MaximumLongitude()) return false; + } + + // Get the lat/lon and see if it can be converted to input line/samp + double lat = p_outmap->Latitude(); + double lon = p_outmap->Longitude(); + + if (!p_incam->SetRightAscensionDeclination(lon,lat)) return false; + + // Make sure the point is inside the input image + if (p_incam->Sample() < 0.5) return false; + if (p_incam->Line() < 0.5) return false; + if (p_incam->Sample() > p_inputSamples + 0.5) return false; + if (p_incam->Line() > p_inputLines + 0.5) return false; + + // Everything is good + inSample = p_incam->Sample(); + inLine = p_incam->Line(); + return true; +} + +int sky2map::OutputSamples () const { + return p_outputSamples; +} + +int sky2map::OutputLines () const { + return p_outputLines; +} + +// Helper function to print out mapfile to session log +void PrintMap() { + UserInterface &ui = Application::GetUserInterface(); + + // Get mapping group from map file + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + //Write map file out to the log + Isis::Application::GuiLog(userGrp); +} + +// Helper function to get mapping resolution. +void LoadMapRes () { + UserInterface &ui = Application::GetUserInterface(); + + // Get mapping group from map file + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + // Set resolution + if (userGrp.HasKeyword("Scale")) { + ui.Clear("SCALE"); + ui.PutDouble("SCALE",userGrp["Scale"]); + } + else { + string msg = "Mapfile [" + ui.GetFilename("MAP") + + "] does not have [SCALE] keyword to load"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } +} + +//Helper function to get camera resolution. +void LoadCameraRes () { + UserInterface &ui = Application::GetUserInterface(); + + // Open the input cube, get the camera object, and the cam map projection + Cube c; + c.Open(ui.GetFilename("FROM")); + Camera *cam = c.Camera(); + double res = cam->RaDecResolution(); + + ui.Clear("SCALE"); + ui.PutDouble("SCALE",1.0 / res); +} + +//Helper function to get ground range from map file. +void LoadMapRange() { + UserInterface &ui = Application::GetUserInterface(); + + ui.Clear("SRA"); + ui.Clear("ERA"); + ui.Clear("SDEC"); + ui.Clear("EDEC"); + + // Get map file + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + // Set ground range keywords that are found in mapfile + int count = 0; + if (userGrp.HasKeyword("MinimumLongitude")) { + ui.PutDouble("SRA",userGrp["MinimumLongitude"]); + count++; + } + if (userGrp.HasKeyword("MaximumLongitude")) { + ui.PutDouble("ERA",userGrp["MaximumLongitude"]); + count++; + } + if (userGrp.HasKeyword("MinimumLatitude")) { + ui.PutDouble("SDEC",userGrp["MinimumLatitude"]); + count++; + } + if (userGrp.HasKeyword("MaximumLatitude")) { + ui.PutDouble("EDEC",userGrp["MaximumLatitude"]); + count++; + } + + // Set default ground range param to map + ui.Clear("DEFAULTRANGE"); + ui.PutAsString("DEFAULTRANGE","MAP"); + + if (count < 4) { + string msg = "One or more of the values for the sky range was not found"; + msg += " in [" + ui.GetFilename("MAP") + "]"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } +} + +//Helper function to load camera range. +void LoadCameraRange () { + UserInterface &ui = Application::GetUserInterface(); + + // Open the input cube, get the camera object, and the cam map projection + Cube c; + c.Open(ui.GetFilename("FROM")); + Camera *cam = c.Camera(); + + // Make the target info match the user mapfile + double minra,maxra,mindec,maxdec; + cam->RaDecRange(minra,maxra,mindec,maxdec); + + // Set ground range parameters in UI + ui.Clear("SRA"); + ui.PutDouble("SRA",minra); + ui.Clear("ERA"); + ui.PutDouble("ERA",maxra); + ui.Clear("SDEC"); + ui.PutDouble("SDEC",mindec); + ui.Clear("EDEC"); + ui.PutDouble("EDEC",maxdec); + + // Set default ground range param to camera + ui.Clear("DEFAULTRANGE"); + ui.PutAsString("DEFAULTRANGE","CAMERA"); +} + + + + + diff --git a/isis/src/base/apps/skymap/skymap.xml b/isis/src/base/apps/skymap/skymap.xml new file mode 100644 index 0000000000000000000000000000000000000000..c44b5ff822bd2e0fbcf5bf601a7363a035d02e82 --- /dev/null +++ b/isis/src/base/apps/skymap/skymap.xml @@ -0,0 +1,383 @@ + + + + + + Convert camera image to a skymap projection + + + + This program converts a cube in camera coordinates to a map projection. It differs from the application "cam2map" in that it maps camera + ra/dec (right acsension/declination) to map projection longitude/latitude. The program is useful for inflight geometric and optical distortion + calibration of a camera when star images are collected. The input cube labels must have an Instrument Group and + Kernels Group. That is, the program "spiceinit" should be run on the input cube prior to "skymap". + +

    + This program will pick appropriate defaults for most parameters. In particular for the MAP parameter, it will generate the following: +

    +
    +  Group = Mapping
    +    TargetName             = "Sky"
    +    EquatorialRadius       = 1.0
    +    PolarRadius            = 1.0
    +
    +    LatitudeType           = Planetocentric
    +    LongitudeDirection     = PositiveEast
    +    LongitudeDomain        = 360
    +
    +    MinimumLatitude        = Computed from the input camera cube or map file
    +    MaximumLatitude        = Computed from the input camera cube or map file
    +    MinimumLongitude       = Computed from the input camera cube or map file
    +    MaximumLongitude       = Computed from the input camera cube or map file
    +
    +    ProjectionName         = Projection name in the map file
    +    Scale                 = Computed from the input camera cube or map file
    +  EndGroup
    +    
    + + Note that although the map projection group reflects latitude/longitude, those values are synomous with declination/right ascension. + +

    + Note that an important concept here is a Mapping group can come from any PVL file. You can use an existing map projected cube + as input for the MAP user parameter. Because the cube has PVL labels and contains the Mapping group, you will essentially force + the input camera cube to have the same mapping parameters or match the existing cube. Information about map projections and + the Mapping group can be found in the Isis user documentation. +

    + +

    + Finally, the user has the option to override the pixel resolution and the ground range (latitude/longitude). These changes can be + facilitied through the parameters SCALE, SRA, ERA, SDEC, and EDEC. +

    +
    + + + Map Projection + Cameras + + + + + Original version + + + Fixed bug with program not using all keywords in + the user MAP file + + + Fixed bug with garbage pixels being produced + at extremities of the projected image edges. + + + Fixed bug, full mapping group was not written to + cube labels. Also, updated documentation to correctly + state that the RESOLUTION parameter is the IFOV of + the camera . + + + Added application test + + + Check to see if center of input image projects, if it does, force the tile containing center + to be processed in ProcessRubberSheet. + + + Redid UI to match cam2map + + + Depricated CubeProjection and ProjectionManager to ProjectionFactory + + + Moved helper buttons and refined helper error checking + + + Fixed typo in user documentation + + + Removed references to CubeInfo + + + Mapping group parameters are now placed into the print file. + + + + + + + cube + input + + Input cube to project + + + The specification of the input cube to be projected. The cube must + contain a valid Instrument and Kernel group in the labels. + + + *.cub + + + + + filename + input + + File containing mapping parameters + + $base/templates/maps + $base/templates/maps/simplecylindrical.map + + A file containing the desired output mapping parameters in PVL form. This + file can be a simple hand produced label file. It can also be an existing cube label + which contains a Mapping group. + + + *.map *.cub + + + + PrintMap + View MapFile + + This helper button will cat out the mapping group of the given mapfile to the session log + of the application + + $ISIS3DATA/base/icons/labels.png + + + + + + cube + output + + Newly mapped cube + + + This file will contain the sky as a map projected image. + + + *.cub + + + + + + + string + Defines how the scale in the output map file is obtained + CAMERA + + This parameter is used to specify how the scale is obtained for the output map + projected cube. + + + + LoadCameraRes + Load Camera Scale + This helper button will load the default scale from the camera + $ISIS3DATA/base/icons/exec.png + + + LoadMapRes + Load Map File Scale + This helper button will load the default scale from the map file + + + + + + + + + + + + + double + Scale in pixels per degree + + The number of pixels per degrees (RA/DEC). By default, + the program attempts to compute this value as 1 / IFOV of the camera. + Note you will typically need to convert + IFOV in milli-or-micro radians to degrees. + Alternatively, you can entered the scale in the MAP file in + pixels per degrees (1 / IFOV). That is, +
    +              Group = Mapping
    +                ...
    +                Scale = 17000.0
    +              End_Group
    +              End_Group
    +            
    +
    + 0.0 +
    +
    + + + + string + Defines how the default sky range is determined + CAMERA + + This parameter is used to specify how the default ra/dec ground range for the output map projected image + is obtained. Note the user can overide the default using the SRA, ERA, SDEC, EDEC parameters. + + + + LoadCameraRange + Load Camera Sky Range + This helper button will load the default sky range from the camera + $ISIS3DATA/base/icons/exec.png + + + LoadMapRange + Load Map File Sky Range + This helper button will load the default sky range from the map file + + + + + + + + + + + double + Starting right ascension + Use default range + + The starting right ascension of the sky map. If not entered it will be read computed from the CAMERA or read from the MAP file, depending + on the option chosen for DEFAULTRANGE. If this value is entered, it will override the default value. + + 0.0 + 360.0 + + + + double + Ending right ascension + Use default range + + The ending right ascension of the sky map. If not entered it will be read computed from the CAMERA or read from the MAP file, depending + on the option chosen for DEFAULTRANGE. If this value is entered, it will override the default value. + + 0.0 + 360.0 + SRA + + + + double + Starting declination + Use default range + + The starting declination of the sky map. If not entered it will be read computed from the CAMERA or read from the MAP file, depending + on the option chosen for DEFAULTRANGE. If this value is entered, it will override the default value. + + -90.0 + 90.0 + + + + double + Ending declination + Use default range + + The ending declination of the sky map. If not entered it will be read computed from the CAMERA or read from the MAP file, depending + on the option chosen for DEFAULTRANGE. If this value is entered, it will override the default value. + + -90.0 + 90.0 + SDEC + + + + boolean + FALSE + + Trim pixels outside sky range + + + If this option is selected, pixels outside the ra/dec + range be trimmed or set to null. + This is useful for certain projections whose lines of latitude and + longitude are not parallel to image lines and sample columns. + + + + + + + string + + CUBICCONVOLUTION + + Type of interpolation + + This is the type of interpolation to be performed on the input. + + + + + + + + +
    +
    diff --git a/isis/src/base/apps/skymap/tsts/Makefile b/isis/src/base/apps/skymap/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/skymap/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/skymap/tsts/user/Makefile b/isis/src/base/apps/skymap/tsts/user/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fa43a7c4127b9d1a889fb1203b94661f02369a8f --- /dev/null +++ b/isis/src/base/apps/skymap/tsts/user/Makefile @@ -0,0 +1,11 @@ +APPNAME = skymap +skymapTruth.cub.TOLERANCE = 0.000001 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/ab102401.cub \ + to= $(OUTPUT)/skymapTruth.cub \ + defaultscale=user \ + scale=0.25 \ + interp=bilinear> /dev/null; diff --git a/isis/src/base/apps/skypt/Makefile b/isis/src/base/apps/skypt/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/skypt/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/skypt/skypt.cpp b/isis/src/base/apps/skypt/skypt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f7a3e08b58063b61fd67c54e6fb898c4d16a1bbe --- /dev/null +++ b/isis/src/base/apps/skypt/skypt.cpp @@ -0,0 +1,123 @@ +#include "Isis.h" +#include "Camera.h" +#include "iException.h" +#include "Brick.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + // Get user interface + UserInterface &ui = Application::GetUserInterface(); + + // Get input cube and get camera model for it + string channel = ui.GetFilename("FROM"); + Cube cube; + cube.Open(channel); + Camera *cam = cube.Camera(); + + // Get the type of conversion that we are doing + string type = ui.GetString("TYPE"); + double samp,line; + + // Do conversion from samp/line to ra/dec + if (type == "IMAGE") { + // Get users sample & line values and do a setImage for the camera + samp = ui.GetDouble("SAMPLE"); + line = ui.GetDouble("LINE"); + cam->SetImage(samp,line); + } + // Do conversion from ra/dec to samp/line + else { + double ra = ui.GetDouble("RA"); + double dec = ui.GetDouble("DEC"); + if (!cam->SetRightAscensionDeclination(ra,dec)) { + string msg = "Invalid Ra/Dec coordinate"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + samp = cam->Sample(); + line = cam->Line(); + } + + // Create Brick on samp, line to get the dn value of the pixel + Brick b(3,3,1,cube.PixelType()); + int intSamp = (int)(samp+0.5); + int intLine = (int)(line+0.5); + b.SetBasePosition(intSamp,intLine,1); + cube.Read(b); + + // Create group with sky position + PvlGroup sp("SkyPoint"); + { + sp += PvlKeyword("Filename",Filename(channel).Expanded()); + sp += PvlKeyword("Sample",cam->Sample()); + sp += PvlKeyword("Line",cam->Line()); + sp += PvlKeyword("RightAscension",cam->RightAscension()); + sp += PvlKeyword("Declination",cam->Declination()); + sp += PvlKeyword("EphemerisTime",cam->EphemerisTime()); + sp += PvlKeyword("PixelValue",PixelToString(b[0])); + } + //Write the group to the screen + Application::Log(sp); + + // Write an output label file if necessary + if (ui.WasEntered("TO")) { + // Get user params from ui + string outFile = Filename(ui.GetFilename("TO")).Expanded(); + bool exists = Filename(outFile).Exists(); + bool append = ui.GetBoolean("APPEND"); + + // Write the pvl group out to the file + if (ui.GetString("FORMAT") == "PVL") { + Pvl temp; + temp.SetTerminator(""); + temp.AddGroup(sp); + if (append) { + temp.Append(ui.GetAsString("TO")); + } + else { + temp.Write(ui.GetAsString("TO")); + } + } + // Create a flatfile of the same data + // The flatfile is comma delimited and can be imported into Excel + else { + ofstream os; + bool writeHeader = false; + if (append) { + os.open(outFile.c_str(),ios::app); + if (!exists) { + writeHeader = true; + } + } + else { + os.open(outFile.c_str(),ios::out); + writeHeader = true; + } + + if(writeHeader) { + for(int i = 0; i < sp.Keywords(); i++) { + os << sp[i].Name(); + + if(i < sp.Keywords()-1) { + os << ","; + } + } + os << endl; + } + + for(int i = 0; i < sp.Keywords(); i++) { + os << (string)sp[i]; + + if(i < sp.Keywords()-1) { + os << ","; + } + } + os << endl; + } + } + else if(ui.GetString("FORMAT") == "FLAT") { + string msg = "Flat file must have a name."; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } +} diff --git a/isis/src/base/apps/skypt/skypt.xml b/isis/src/base/apps/skypt/skypt.xml new file mode 100644 index 0000000000000000000000000000000000000000..8ead7ad4888c1bc2d347838573c2443b47374024 --- /dev/null +++ b/isis/src/base/apps/skypt/skypt.xml @@ -0,0 +1,210 @@ + + + + + Converts between sample/line and ra/ dec positions + + + + This program requires the user supply a "level 1" cube. That is, a + cube in raw camera geometry. + The user must also enter one of the following coordinates: +
    +     sample/line
    +      ra/dec
    +    
    + The program will then compute the other coordinates and the ephemeris + time and pixel dn value. + +

    + Hint: If you would like to use this program for multiple points, look into the + -batchlist option. +

    +
    + + + Cameras + + + + + Original version + + + Modified to output pvl and flat format files and added append option + + + Added check for valid samp/line and ra/dec positions + + + Do not check error on SetImage, because there might not be an intersection + on the planet when dealing with sky images. + + + Changed flatfile output so it duplicates PVL data. User now + required to enter a flatfile name. + + + + + + + cube + input + + Filename of a cube + + + Input cube with appropriate camera labels + (Instrument and kernel groups) + + + *.cub + + + + + filename + output + + Output List + + + The output list will be a text file and will contain the filename, + sample, line, ra, dec, et, and dn values. The values will be written out + in pvl or flat format, depending on what the user selects for the FORMAT + parameter. + + None + + + + string + + Output Format + + + Format type for output file. Pvl format is default. + + PVL + + + + + + + + boolean + + Append Output to File + + + If this option is selected, the output from the application will be appended to the file. + If it is not selected, any information in the TO file will be overwritten. This option is + selected by default. + + TRUE + + + + + + string + Coordinate selection + IMAGE + + + + + + This parameter is used to select the type of coordinate which will be used to + compute the other two remaining coordinates. + + + + + double + + Sample position to report + + + This is the sample position used to compute information about the camera state at the pixel. + + + + + double + + Line position to report + + + This is the line position used to compute information about the camera state at the pixel. + + + + + double + + Right Ascension + + + This is the right ascension value used to compute information about the camera state at the pixel. + + + + + double + + Declination + + + This is the declination value used to compute information about the camera state at the pixel. + + + + + +
    diff --git a/isis/src/base/apps/skypt/tsts/Makefile b/isis/src/base/apps/skypt/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/skypt/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/skypt/tsts/default/Makefile b/isis/src/base/apps/skypt/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c4e5edf4f37379a1de3632eeaf0e37655b356285 --- /dev/null +++ b/isis/src/base/apps/skypt/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = skypt + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/m0402852.cub \ + to=$(OUTPUT)/skypt.pvl \ + sample = 10.0 \ + line = 10.0> /dev/null; diff --git a/isis/src/base/apps/skypt/tsts/flat/Makefile b/isis/src/base/apps/skypt/tsts/flat/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bdfb411addaa539b63920d9d6289042bb8a89369 --- /dev/null +++ b/isis/src/base/apps/skypt/tsts/flat/Makefile @@ -0,0 +1,18 @@ +APPNAME = skypt + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/m0402852.cub \ + to=$(OUTPUT)/skyptTemp.txt \ + format=flat \ + type=sky \ + ra=322.34523648672 \ + dec=53.787370722722 > /dev/null; + $(APPNAME) from=$(INPUT)/lub0428b.253.cub \ + format=flat SAMP=15 LINE=15 \ + TO=$(OUTPUT)/skyptTemp2.txt > /dev/null; + cut -d , -f 2- $(OUTPUT)/skyptTemp.txt >& $(OUTPUT)/skypt_1.txt; + cut -d , -f 2- $(OUTPUT)/skyptTemp2.txt >& $(OUTPUT)/skypt_2.txt; + rm $(OUTPUT)/skyptTemp.txt; + rm $(OUTPUT)/skyptTemp2.txt; diff --git a/isis/src/base/apps/skyrange/Makefile b/isis/src/base/apps/skyrange/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/skyrange/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/skyrange/skyrange.cpp b/isis/src/base/apps/skyrange/skyrange.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b127e8c0f8d5cdeff43799ea8ad0b16c423b3b24 --- /dev/null +++ b/isis/src/base/apps/skyrange/skyrange.cpp @@ -0,0 +1,66 @@ +#include "Isis.h" +#include "Process.h" +#include "Camera.h" +#include "Pvl.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + // Set the input image, get the camera model + Process p; + Cube *icube = p.SetInputCube("FROM"); + Camera *cam = icube->Camera(); + + // Get the ra/dec range and resolution + double minRa,maxRa,minDec,maxDec; + cam->RaDecRange(minRa,maxRa,minDec,maxDec); + double res = cam->RaDecResolution(); + + // Get the center ra/dec + cam->SetImage(icube->Samples()/2.0,icube->Lines()/2.0); + double centerRa = cam->RightAscension(); + double centerDec = cam->Declination(); + + // Compute the rotation + cam->SetRightAscensionDeclination(centerRa,centerDec+2.0*res); + double x = cam->Sample() - icube->Samples()/2.0; + double y = cam->Line() - icube->Lines()/2.0; + double rot = atan2(-y,x) * 180.0 / Isis::PI; + rot = 90.0 - rot; + if (rot < 0.0) rot += 360.0; + + // Setup and log results + PvlGroup results("Range"); + results += PvlKeyword("MinimumRightAscension",minRa,"degrees"); + results += PvlKeyword("MaximumRightAscension",maxRa,"degrees"); + results += PvlKeyword("MinimumDeclination",minDec,"degrees"); + results += PvlKeyword("MaximumDeclination",maxDec,"degrees"); + results += PvlKeyword("MinimumRightAscension",Projection::ToHMS(minRa),"hms"); + results += PvlKeyword("MaximumRightAscension",Projection::ToHMS(maxRa),"hms"); + results += PvlKeyword("MinimumDeclination",Projection::ToDMS(minDec),"dms"); + results += PvlKeyword("MaximumDeclination",Projection::ToDMS(maxDec),"dms"); + results += PvlKeyword("Resolution",res,"degrees/pixel"); + Application::Log(results); + + // Setup and log orientation + PvlGroup orient("Orientation"); + orient += PvlKeyword("CenterSample",icube->Samples()/2.0); + orient += PvlKeyword("CenterLine",icube->Lines()/2.0); + orient += PvlKeyword("CenterRightAscension",centerRa,"degrees"); + orient += PvlKeyword("CenterDeclination",centerDec,"degrees"); + orient += PvlKeyword("CelestialNorthClockAngle",rot,"degrees"); + orient += PvlKeyword("Resolution",res,"degrees/pixel"); + Application::Log(orient); + + // Write the output file if requested + UserInterface ui = Application::GetUserInterface(); + if (ui.WasEntered("TO")) { + Pvl temp; + temp.AddGroup(results); + temp.AddGroup(orient); + temp.Write(ui.GetFilename("TO","txt")); + } + + p.EndProcess(); +} diff --git a/isis/src/base/apps/skyrange/skyrange.xml b/isis/src/base/apps/skyrange/skyrange.xml new file mode 100644 index 0000000000000000000000000000000000000000..250f3b381138414f2545b56947a9173922fe4c2e --- /dev/null +++ b/isis/src/base/apps/skyrange/skyrange.xml @@ -0,0 +1,69 @@ + + + + + Compute the ra/dec range of a camera image + + + + This program will report the ra/dec range of a camera image. It will also compute the ra/dec at the center of the cube, the pixel resolution in + degrees per pixel, and an orientation angle to celestial north (90 declination) in the image plane. This angle, CelestialNorthClockAngle, is + from the center of the image off of the Y-axis (12 o'clock) in a clockwise direction. + + + + Cameras + + + + + Original version + + + Added computation of CelestialNorthClockAngle and center ra/dec + + + Added application test + + + Fixed appTest to comply to changes in String + + + Fixed appTest to comply with changes made to all camera model + + + Removed references to CubeInfo + + + + + + + cube + input + + Input cube to compute range + + + Use this parameter to select the filename of a cube with + camera labels. + + + *.cub + + + + + filename + output + None + + Output label + + + This file will contain the ra/dec range of the cube + + + + + diff --git a/isis/src/base/apps/skyrange/tsts/Makefile b/isis/src/base/apps/skyrange/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/skyrange/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/skyrange/tsts/default/Makefile b/isis/src/base/apps/skyrange/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2eabd81036de6fdf223e6d79c13fa213562c4213 --- /dev/null +++ b/isis/src/base/apps/skyrange/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME = skyrange + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/m0402852.sky.cub \ + to=$(OUTPUT)/skyrange.txt > /dev/null; + $(MV) $(OUTPUT)/skyrange.txt $(OUTPUT)/skyrange.pvl; + $(APPNAME) from=$(INPUT)/lna3056k.cub \ + to=$(OUTPUT)/skyrange2.txt > /dev/null; + $(MV) $(OUTPUT)/skyrange2.txt $(OUTPUT)/skyrange2.pvl; diff --git a/isis/src/base/apps/slither/ControlByRow.h b/isis/src/base/apps/slither/ControlByRow.h new file mode 100644 index 0000000000000000000000000000000000000000..edbc1ece693f152434d04a8555e79226a0c52d49 --- /dev/null +++ b/isis/src/base/apps/slither/ControlByRow.h @@ -0,0 +1,298 @@ +#ifndef ControlByRow_h +#define ControlByRow_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:21 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "ControlMeasure.h" +#include "Statistics.h" +#include "CollectorMap.h" +#include "iString.h" +#include + +namespace Isis { + +/** + * @brief Container for point collection + */ +struct PointData { + ControlMeasure refPoint; + ControlMeasure chpPoint; +}; + +/** + * @brief Less than test for Control point group + * + * This function tests the reference line numbers and returns true if the first + * point reference line is less than the second. + * + * @param p1 First PointData set to compare + * @param p2 Second PointData set to compare + * + * @return bool If first point reference line is less than the second + */ +inline bool PointLess(const PointData &p1, const PointData &p2) { + return (p1.refPoint.Line() < p2.refPoint.Line()); +} + +/** + * @brief Equality test for Control point group + * + * This function tests the reference line numbers for equality and returns true + * if the line references are equivalent, according to an approximation using an + * epsilon of 1.0e-6. + * + * @param p1 First PointData set to compare + * @param p2 Second PointData set to compare + * + * @return bool If the reference point lines are (approximately) equivalent + */ +inline bool PointEqual(const PointData &p1, const PointData &p2) { + return (gsl_fcmp(p1.refPoint.Line(), p2.refPoint.Line(), 1.0E-6) == 0); +} + +/** + * @brief Collector for Control points within the same row for analysis + * + * This class is designed to be used as a Functor object collecting control net + * file and collapsing all column measures into on row. This is primarily used + * for analysis of coregistration results with one or more columns specified + * in the search/pattern chip strategy. + * + */ +class ControlByRow { + public: + /** + * @brief Structure to return control point statistics for row + * + * This structure contains the row statistics of merged control points. + * This will eventually be used to compute the spline interpolations for + * line and sample offsets. + * + */ + struct RowPoint { + RowPoint() : refLine(0.0), refSamp(0.0), chpLine(0.0), chpSamp(0.0), + total(0), count(0) { } + double refLine; //!< Reference line (row) + double refSamp; //!< Reference sample + double chpLine; //!< Registered line + double chpSamp; //!< Registered sample + int total; //!< Total points in row + int count; //!< Valid points found + + Statistics rSStats; + Statistics cLStats; + Statistics cSStats; + Statistics cLOffset; + Statistics cSOffset; + Statistics GOFStats; + }; + + public: + /** + * @brief Default constructor + */ + ControlByRow() { + _minGOF = DBL_MIN; + _maxGOF = DBL_MAX; + } + + /** + * @brief Constructor that sets the maximum goodness of fit tolerance + * @param maxGOF Value that specifies the maximum goodness of fit which is + * typically never expected to exceed 1.0 for a good fit. + */ + ControlByRow(double maxGOF) { + _minGOF = DBL_MIN; + _maxGOF = maxGOF; + } + + /** + * @brief Constructor that sets the maximum goodness of fit tolerance + * @param minGOF Value of minimum goodness of fit. Allows user selectable + * adjustment to coregistration minimum tolerance + * @param maxGOF Value that specifies the maximum goodness of fit which is + * typically never expected to exceed 1.0 for a good fit. + */ + ControlByRow(double minGOF, double maxGOF) { + _minGOF = minGOF; + _maxGOF = maxGOF; + } + + /** + * @brief Destructor + */ + ~ControlByRow() { } + + /** + * @brief Determines the number of points (rows) found valid + * + * The number returned is really the number of unique rows of coregistration + * chips gleened from the control net. + * + * @return unsigned int Row/line count + */ + inline unsigned int size() const { return (_rowList.size()); } + + /** + * @brief Set the minimum acceptable goodness of fit value + * + * This sets the minimum (absolute) value used to gleen valid points from + * the control net data. + * + * @param minGOF Minimum goodness of fit tolerance + */ + void setMinGOF(double minGOF) { _minGOF = minGOF; } + + /** + * @brief Set the maximum acceptable goodness of fit value + * + * This sets the maximum (absolute) value used to gleen valid points from + * the control net data. This is intended to use to exclude wild points + * that exceed the level of reasonable tolerance. This is typically 1.0 for + * most coregistration algorithms. + * + * @param maxGOF Maximum goodness of fit tolerance + */ + void setMaxGOF(double maxGOF) { _maxGOF = maxGOF; } + + /** + * @brief Operator used to add a point to the data set + * + * This method provides support for the STL for_each algorithm. This allows + * this class to be used as a functor object. + * + * @param p Point to tested for acceptance in the list + */ + void operator() (const PointData &p) { + addPoint(p); + return; + } + + /** + * @brief Formal method of adding a control point to the data set + * + * This method will add the provided point to the collection of rows (or + * lines of points). + * + * @param p Point to add to the list + */ + void addPoint(const PointData &p) { + if (_rowList.exists(p.refPoint.Line())) { + PointList &r = _rowList.get(p.refPoint.Line()); + r.push_back(p); + } + else { + PointList pl; + pl.push_back(p); + _rowList.add(p.refPoint.Line(),pl); + } + return; + } + + /** + * @brief Returns a point at the ith location + * + * Traverses the list of points after computing the merge statistics for the + * ith row. + * + * @param i Index of point to return + * + * @return RowPoint Structure containing the (statistically) merged row + */ + RowPoint operator[](int i) const { + try { + return (computeStats(_rowList.getNth(i))); + } catch (iException &oor) { + std::string msg = "Requested value (" + iString(i) + ") not found"; + throw iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + + private: + typedef std::vector PointList; //!< Composite list + typedef CollectorMap CNetRow; /** + * Nifty templated collector class works just + * nicely for merging rows of correlations + */ + double _minGOF; //!< Minimum acceptable goodness of fit + double _maxGOF; //!< Maximum acceptable goodness of fit + CNetRow _rowList; //!< Collection of merged rows/lines + + /** + * @brief Convenience method for adding point to Statistics class + * + * The interface to the Isis Statistics class requires the value to be added + * by address. This method expedites the addition of values from say a + * function or method. + * + * @param value Value to add to Statistics class + * @param stats Statistics class to add the data point to + */ + inline void addToStats(double value, Statistics &stats) const { + stats.AddData(&value, 1); + return; + } + + /** + * @brief All important method that computes statistics for a row + * + * This method computes the statistics for a potentially merged row of + * coregistration chips. It applies the minimum and maximum goodness of fit + * tolerance checks and add valid points to each statistical component of + * the merge. + * + * @param cols List of column chip registrations + * + * @return RowPoint Structure containing the statistics for row/line of + * merged registration columns + */ + RowPoint computeStats(const std::vector &cols) const { + RowPoint rp; + rp.refLine = cols[0].refPoint.Line(); + for (unsigned int i = 0; i < cols.size() ; i++) { + double regGOF(cols[i].chpPoint.GoodnessOfFit()); + if (fabs(regGOF) > _maxGOF) continue; + if (fabs(regGOF) < _minGOF) continue; + (rp.count)++; + addToStats(cols[i].refPoint.Sample(), rp.rSStats); + addToStats(cols[i].chpPoint.Line(), rp.cLStats); + addToStats(cols[i].chpPoint.Sample(), rp.cSStats); + addToStats(cols[i].chpPoint.LineError(), rp.cLOffset); + addToStats(cols[i].chpPoint.SampleError(), rp.cSOffset); + addToStats(cols[i].chpPoint.GoodnessOfFit(), rp.GOFStats); + } + + rp.total = cols.size(); + rp.refSamp = rp.rSStats.Average(); + rp.chpLine = rp.cLStats.Average(); + rp.chpSamp = rp.cSStats.Average(); + return (rp); + } + +}; + + +} // namespace Isis + +#endif diff --git a/isis/src/base/apps/slither/Makefile b/isis/src/base/apps/slither/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bc027256feb3e521df30715e97cc149dfe4ca5d4 --- /dev/null +++ b/isis/src/base/apps/slither/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = slither + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/slither/SlitherTransform.cpp b/isis/src/base/apps/slither/SlitherTransform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6ddf8164ea0f0fa09dbd7a62c7ec0dfed9b4ab11 --- /dev/null +++ b/isis/src/base/apps/slither/SlitherTransform.cpp @@ -0,0 +1,302 @@ +#include +#include +#include +#include +#include + +#include "Cube.h" +#include "ControlNet.h" +#include "NumericalApproximation.h" +#include "Statistics.h" +#include + +#include "SlitherTransform.h" + +using namespace std; +namespace Isis { + + /** + * @brief Constructor where all the business is taking place + * + * This constructor accepts a cube to be transformed and the control net file + * generated after matching it to a reference image. It is assumed that the + * control net has the reference image identified via the ControlMeasure class. + * + * It computes the interpolations for line and samples from the control net + * registration data. This interpolation preserves lines whole, shifting them + * up and/or down and left or right. + * + * @param cube Input cube to be transformed + * @param cnet Control net that will be used to compute the spline offsets + * @param lInterp Type of spline to compute for line offsets + * @param sInterp Type of spline to compute for sample offsets + * @see NumericalApproximation + */ + SlitherTransform::SlitherTransform(Cube &cube, ControlNet &cnet, + InterpType lInterp, InterpType sInterp) : + _rows(), _badRows(), + _pntsTotal(0), _pntsUsed(0), _pntsTossed(0), + _iDir(1.0), + _outputLines(cube.Lines()), + _outputSamples(cube.Samples()), + _lineOffset(0.0), _sampOffset(0.0) { + + // Collect the points from the control file + _lineSpline.SetInterpType(lInterp); + _sampSpline.SetInterpType(sInterp); + vector points; + for (int i=0; i < cnet.Size(); i++) { + ControlPoint &cp = cnet[i]; + _pntsTotal++; + if (!cp.Ignore()) { + if (cp.Size() != 2) { +// cout << "Point " << i << " doesn't have two measures but " +// << cp.Size() << endl; + _pntsTossed++; + } + else { + // Determine reference image assuming first one is the reference + // if it is not expressly identified + int snIndex(0), mnIndex(1); + if (!cp[snIndex].IsReference()) { + snIndex = 1; + mnIndex = 0; + } + // Add the point set to the list + PointData p; + p.refPoint = cp[snIndex]; + p.chpPoint = cp[mnIndex]; + points.push_back(p); + _pntsUsed++; + } + } + } + + // Points must be sorted and then collapsed into one column + sort(points.begin(), points.end(), PointLess); + ControlByRow pts = for_each(points.begin(), points.end(), + ControlByRow(1.0)); + + // Now retrieve the collapsed points identifying good ones and bad ones + _rows.clear(); + _badRows.clear(); + for (unsigned int n = 0 ; n < pts.size() ; n++) { + RowPoint p = pts[n]; + if (p.count > 0) { + _rows.push_back(p); + } + else { + _badRows.push_back(p); + } + } + + // Add the points to the spline interpolators. It is important to use + // the offsets only in this case so the reverse tranform can be provided + // as well. + for (unsigned int n = 0 ; n < _rows.size() ; n++) { + RowPoint rp = _rows[n]; + _lineSpline.AddData(rp.refLine, rp.cLOffset.Average()); + _sampSpline.AddData(rp.refLine, rp.cSOffset.Average()); + } + } + + /** + * @brief Convert the requested output samp/line to an input samp/line + * + * Computes the incoming line and sample for the given output line and + * sample. These coordinates are determined entirely by the interpolations of + * the control net coregistrations upon instantiation of this object. + * + * @param inSample Returns the input sample coordinate for this outSample, + * outLine + * @param inLine Returns the input line coordinate for this outSample, + * outLine + * @param outSample Current sample pixel location requested + * @param outLine Current line location requested + * + * @return bool Always returns true as the value will always be provided + */ + bool SlitherTransform::Xform (double &inSample, double &inLine, + const double outSample, const double outLine) { + inLine = getLineXform(outLine); + inSample = getSampXform(outLine, outSample); + return (true); + } + + /** + * @brief Computes statistics for each line in the output image + * + * This method computes (gathers, really) the statistics as determined via the + * application of the interpolation from the transform. For every valid line, + * sample, it accumulates the line offsets as provided via the tranform. + * + * @return Statistics Provides the statistics class that contains the + * statistics information + * @see Statistics + * @history 2008-11-05 Jeannie Walldren - removed const from + * method so that _lineSpline is not const. + * + */ + Statistics SlitherTransform::LineStats() { + Statistics stats; + for (int line = 0 ; line < _outputLines ; line++) { + double outLine(line+1), inLine; + inLine = getLineXform(outLine); + if ((inLine >= 1.0) && (inLine <= _outputLines)) { + outLine = getOffset(outLine, _lineSpline); + stats.AddData(&outLine, 1); + } + } + return (stats); + } + + /** + * @brief Computes statistics for samples in the output image + * + * This method computes (gathers, really) the statistics as determined via the + * application of the interpolation from the transform. For every valid line, + * sample, it accumulates the sample offsets as provided via the tranform. + + * + * @return Statistics Provides the statistics class that contains the + * statistics information + * @see Statistics + * @history 2008-11-05 Jeannie Walldren - removed const from + * method so that _sampSpline is not const. + * + */ + Statistics SlitherTransform::SampleStats() { + Statistics stats; + for (int line = 0 ; line < _outputLines ; line++) { + double outLine(line+1), inLine; + inLine = getLineXform(outLine); + if ((inLine >= 1.0) && (inLine <= _outputLines)) { + double outSamp = getOffset(outLine, _sampSpline); + stats.AddData(&outSamp, 1); + } + } + return (stats); + } + + /** + * @brief Provides detailed information and statistics for the current transform + * + * This method produces a large volume of information pertaining to the computed + * transform. This information is written to the provided stream and assumes + * the caller has created a valid stream. + * + * @param out Output stream to write data to + * + * @return std::ostream& Returns the output stream + */ + std::ostream &SlitherTransform::dumpState(std::ostream &out) { + + std::ios::fmtflags oldFlags = out.flags(); + out.setf(std::ios::fixed); + + out << "# General line, sample statistics\n"; + out << setw(10) << "Axis" + << setw(10) << "Spline" + << setw(12) << "Average" + << setw(12) << "StdDev" + << setw(12) << "Minimum" + << setw(12) << "Maximum" + << endl; + + + Statistics lstats = LineStats(); + double lStd(lstats.StandardDeviation()); + out << setw(10) << "Line" + << setw(10) << _lineSpline.Name() + << setw(12) << setprecision(4) << lstats.Average() + << setw(12) << setprecision(4) << ((IsSpecial(lStd)) ? 0.0 : lStd) + << setw(12) << setprecision(4) << lstats.Minimum() + << setw(12) << setprecision(4) << lstats.Maximum() + << endl; + + Statistics sstats = SampleStats(); + double sStd(sstats.StandardDeviation()); + out << setw(10) << "Sample" + << setw(10) << _sampSpline.Name() + << setw(12) << setprecision(4) << sstats.Average() + << setw(12) << setprecision(4) << ((IsSpecial(sStd)) ? 0.0 : sStd) + << setw(12) << setprecision(4) << sstats.Minimum() + << setw(12) << setprecision(4) << sstats.Maximum() + << endl; + + + + int allPoints(numberPointsUsed() + numberBadPoints()); + out << "\n\n" << setw(10) << "BadRows" << setw(10) << numberBadRows() + << " (Rows with no valid points)\n"; + out << setw(10) << "Points" << setw(10) << numberPointsUsed() + << " of " << allPoints << " (Points with 2 measures)\n"; + out << setw(10) << "AllPoints" << setw(10) << totalPoints() + << " (Including ignored points)\n"; + + + out << "\n\n# Statistics of collapsed column registrations for each row\n"; + // Write headers + out << setw(10) << "FromLine" + << setw(10) << "FromSamp" + << setw(10) << "MatchLine" + << setw(10) << "MatchSamp" + << setw(12) << "LineOffset" + << setw(12) << "SampOffset" + << setw(12) << "LineStdDev" + << setw(12) << "SampStdDev" + << setw(10) << "RegGOFAvg" + << setw(10) << "ValidCols" + << setw(10) << "TotalCols" + << endl; + + RowList::const_iterator rItr; + for (rItr = _rows.begin() ; rItr != _rows.end() ; ++rItr) { + double clStd(rItr->cLOffset.StandardDeviation()); + double csStd(rItr->cSOffset.StandardDeviation()); + out << setw(10) << setprecision(2) << rItr->chpLine + << setw(10) << setprecision(2) << rItr->chpSamp + << setw(10) << setprecision(2) << rItr->refLine + << setw(10) << setprecision(2) << rItr->refSamp + << setw(12) << setprecision(4) << rItr->cLOffset.Average() + << setw(12) << setprecision(4) << rItr->cSOffset.Average() + << setw(12) << setprecision(4) << (IsSpecial(clStd) ? 0.0 : clStd) + << setw(12) << setprecision(4) << (IsSpecial(csStd) ? 0.0 : csStd) + << setw(10) << setprecision(4) << rItr->GOFStats.Average() + << setw(10) << setprecision(0) << rItr->count + << setw(10) << setprecision(0) << rItr->total + << endl; + } + + out << "\n\n# Map of each output line and sample with relative offsets\n"; + // Write headers + out << setw(10) << "InLine" + << setw(10) << "InSamp" + << setw(10) << "OutLine" + << setw(10) << "OutSamp" + << setw(12) << "LineOffset" + << setw(12) << "SampOffset" + << endl; + + double outSamp(OutputSamples()/2); + for (int line = 1 ; line <= OutputLines() ; line++) { + double outLine(line), inLine, inSamp; + double sampOffset, lineOffset; + + Xform(inSamp, inLine, outSamp, outLine); + sampOffset = getOffset(outLine, _sampSpline); + lineOffset = getOffset(outLine, _lineSpline); + + out << setw(10) << setprecision(2) << inLine + << setw(10) << setprecision(2) << inSamp + << setw(10) << setprecision(2) << outLine + << setw(10) << setprecision(2) << outSamp + << setw(12) << setprecision(4) << lineOffset + << setw(12) << setprecision(4) << sampOffset + << endl; + } + + out.setf(oldFlags); + return (out); + } +} diff --git a/isis/src/base/apps/slither/SlitherTransform.h b/isis/src/base/apps/slither/SlitherTransform.h new file mode 100644 index 0000000000000000000000000000000000000000..11cdd90abbdcb879e1662e2bec6f894d547a9d34 --- /dev/null +++ b/isis/src/base/apps/slither/SlitherTransform.h @@ -0,0 +1,291 @@ +#ifndef SlitherTransform_h +#define SlitherTransform_h + +#include +#include +#include +#include "ControlByRow.h" +#include "ControlNet.h" +#include "NumericalApproximation.h" +#include "PvlGroup.h" +#include "Transform.h" + +namespace Isis { + +class SlitherTransform : public Transform { + /** + * @author 2006-06-22 Kris Becker + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Updated references to + * DataInterp with NumericalApproximation. Removed + * const from LineStats() and SampleStats(), + * getOffset(), getLineXform(), and getSampXform() + * since calling NumericalApproximation::Evaluate() + * changes class variables. + * + */ + + public: + typedef NumericalApproximation::InterpType InterpType; + SlitherTransform(Cube &cube, ControlNet &cnet, + InterpType lInterp = NumericalApproximation::CubicNatural, + InterpType sInterp = NumericalApproximation::CubicNatural); + + /** + * @brief Destructor + * + * All cleanup is automagically handled! + */ + virtual ~SlitherTransform() { } + + /** + * @brief Number of points used in computation of transform + * + * This method returns the number of row points used in the computation of + * the spline interpolation fits. + * + * @return int Number of row point data sets used in sample/line + * interopolations + */ + inline int size() const { return (_rows.size()); } + + /** + * @brief Sets forward transform direction + * + * This is the normal expected operation. The forward transform direction + * implies the transform is applied to the search image, not the pattern, + * or reference, image used to create the control network. + * + * The search image is typically the FROM parameter in co-registration + * applications. + */ + inline void setForward() { _iDir = 1.0; } + + /** + * @brief Sets reverse transform direction + * + * The reverse transform direction implies the transform is applied to the + * pattern, or reference, image, not the search image used to create the + * control network. + * + * The reference image is the MATCH parameter in co-registration + * applications. + */ + inline void setReverse() { _iDir = -1.0; } + + /** + * @brief Total points in control net file + * + * This method reports to the caller the total number of points in the + * control net file. This includes ignored points as well that are + * automatically excluded. Points that do not have exactly 2 measures are + * excluded as well. + * + * @return int Number of points used + */ + inline int totalPoints() const { return(_pntsTotal); } + + /** + * @brief Number of points used from the input control net file + * + * This method reports to the caller the number of points used when read + * from the control point file. This count does not include ingored + * points or bad points. + * + * @return int Number of points used + */ + inline int numberPointsUsed() const { return(_pntsUsed); } + + /** + * @brief Number of points tossed on input to this class + * + * This method reports to the caller the number of points excluded when + * read from the control point file that exceeded a certain cnet line. + * + * @return int Number of points excluded + */ + inline int numberBadPoints() const { return(_pntsTossed); } + + /** + * @brief Number of bad rows detected in control net + * + * This method reports to the caller the number of bad rows detected after + * merging chip column registrations for each row. This will typically + * indicate the goodness of fit excluded all the points in that row by + * constraints imposed by the merging function. + * + * @return int Number of bad rows detected + * @see ControlByRow + */ + inline int numberBadRows() const { return(_badRows.size()); } + + // Implementations for parent's pure virtual members + bool Xform (double &inSample, double &inLine, + const double outSample, const double outLine); + + /** + * @brief Determine the number of samples in the output image + * + * This method returns the number of samples that will result in the image + * created from this transform. Default behavior is to use the same + * number of samples as the input image. + * + * @return int Number of samples in output image + */ + int OutputSamples () const { return _outputSamples; }; + + /** + * @brief Determine the number of lines in the output image + * + * This method returns the number of lines that will result in the image + * created from this transform. Default behavior is to use the same + * number of lines as the input image. + * + * @return int Number of lines in output image + */ + int OutputLines () const { return _outputLines; }; + + /** + * @brief Add an additional offset to the line output translation + * + * This method provides the users of this class to shift the image an + * additional number of lines than are determined by the control net + * registration information provides. + * + * This is mostly useful when the registration had an initial starting + * offset as opposed to the assumption of generally spatially registering + * images. + * + * Negative values shifts the image down in the output image. Positive + * values shift the image up. + * + * This method can be called at any time during the processing to change + * the relative shift. It does not affect the size of the output image, + * only the placement of the samples. + * + * @param lineOffset Additional offset to shift lines in output image + */ + void addLineOffset(double lineOffset) { + _lineOffset = lineOffset; + return; + } + + /** + * @brief Add an additional offset to the sample output transform + * + * This method provides the users of this class to shift the image an + * additional number of samples than are determined by the control net + * registration information provides. + * + * This is mostly useful when the registration had an initial starting + * offset as opposed to the assumption of generally spatially registering + * images. + * + * Negative values shifts the image right in the output image. Positive + * values shift the image left. + * + * This method can be called at any time during the processing to change + * the relative shift. It does not affect the size of the output image, + * only the placement of the samples. + * + * @param sampOffset Additional offset to shift samples in output image + */ + void addSampleOffset(double sampOffset) { + _sampOffset = sampOffset; + return; + } + + Statistics LineStats(); + Statistics SampleStats(); + + std::ostream &dumpState(std::ostream &out); + + private: + typedef ControlByRow::RowPoint RowPoint; + typedef std::vector RowList; + RowList _rows; //!< Collected row points + RowList _badRows; //!< Collects bad row points + int _pntsTotal; //!< Total number points in control + int _pntsUsed; //!< Total number points not ignored + int _pntsTossed; //!< Total number points tossed + double _iDir; //!< Interpolation direction + + NumericalApproximation _lineSpline; //!< Line spline interpolation + NumericalApproximation _sampSpline; //!< Sample spline interpolation + + int _outputLines; //!< Number output lines + int _outputSamples; //!< Number output samples + + double _lineOffset; //!< Additional spatial line offset + double _sampOffset; //!< Additional spatial sample offset + + /** + * @brief Compute the relative shift of the given axis + * + * This method computes the relative shift at the given location, + * typically the line, additionally incorporating the user selected + * direction, forward or reverse. + * + * To acheive the actual location, the input element (sample, line) + * location and the user specified offset must be additionally applied. + * + * @param x Coordinate of the value to get interpolation for + * @param interp Interpolation computed for the axis + * + * @return double Relative shift at the specified coordinate + * @see getLineXform + * @see getSampXform + * @history 2008-11-05 Jeannie Walldren - removed const from + * interp parameter since call to Evaluate() will + * fill values of class variables + */ + inline double getOffset(const double &x, NumericalApproximation &interp) const { + return (_iDir * interp.Evaluate(x,NumericalApproximation::NearestEndpoint)); + } + + /** + * @brief Compute the line transform given output line + * + * This method computes the absolute input line from the image given the + * requested output line. It uses interpolation functions precomputed + * from the input control net file provided by a coregistration + * application, typically. + * + * @param line Output line coordinate to compute input line for + * + * @return double Input line coordinate at the output line coordinate + * @history 2008-11-05 Jeannie Walldren - removed const from + * method so that _lineSpline is not const. + */ + inline double getLineXform(const double line) { + return (line - getOffset(line, _lineSpline) + _lineOffset); + } + + /** + * @brief Compute the sample transform given output line, sample + * + * This method computes the absolute input line from the image given the + * requested output line. It uses interpolation functions precomputed + * from the input control net file provided by a coregistration + * application, typically. + * + * @param line Output line coordinate to compute input sample for + * @param samp Output sample coordinate to compute input sample for + * + * @return double Input sample coordinate at the output line, sample + * coordinate + * @history 2008-11-05 Jeannie Walldren - removed const from + * method so that _sampSpline is not const. + */ + inline double getSampXform(const double line, const double samp){ + return (samp - getOffset(line, _sampSpline) + _sampOffset); + } + + + }; + +} +#endif + + diff --git a/isis/src/base/apps/slither/slither.cpp b/isis/src/base/apps/slither/slither.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50abc742cadc22529f0d3559bb74857387eda65e --- /dev/null +++ b/isis/src/base/apps/slither/slither.cpp @@ -0,0 +1,98 @@ +#include "Isis.h" + +#include +#include + +#include "ControlNet.h" +#include "Filename.h" +#include "NumericalApproximation.h" +#include "ProcessRubberSheet.h" +#include "SlitherTransform.h" +#include "UserInterface.h" +#include "iTime.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + // Warp an image + ProcessRubberSheet p; + + // Open the input cube + Cube *icube = p.SetInputCube ("FROM"); + + // Get the control point file + UserInterface &ui = Application::GetUserInterface(); + string cfile = ui.GetFilename("CONTROL"); + ControlNet cn(cfile); + + // Set default type to Cubic spline interpolation + NumericalApproximation::InterpType iType(NumericalApproximation::CubicNatural); + string splineType = ui.GetString("SPLINE"); + if (splineType == "LINEAR") { + iType = NumericalApproximation::Linear; + } + else if (splineType == "POLYNOMIAL") { + iType = NumericalApproximation::Polynomial; + } + else if (splineType == "AKIMA") { + iType = NumericalApproximation::Akima; + } + + // Get the sample and line shifts + double sampleOffset = ui.GetDouble("SAMPLEOFFSET"); + double lineOffset = ui.GetDouble("LINEOFFSET"); + + // Set up the transform object + SlitherTransform transform(*icube, cn, iType, iType); + transform.addLineOffset(lineOffset); + transform.addSampleOffset(sampleOffset); + string splineDir = ui.GetString("DIRECTION"); + if (splineDir == "REVERSE") { + transform.setReverse(); + } + + // Dump the transform statistics + if (ui.WasEntered("RESULTS")) { + // Get the control point file + string rFile = Filename(ui.GetFilename("RESULTS")).Expanded(); + ofstream os; + os.open(rFile.c_str(),ios::out); + os << "# Slither Transform Results\n" + << "# RunDate: " << iTime::CurrentLocalTime() << endl + << "# FROM: " << icube->Filename() << endl + << "# CNETFILE: " << cfile << endl << endl; + + transform.dumpState(os); + } + + // Allocate the output file, same size as input + p.SetOutputCube ("TO",transform.OutputSamples(), + transform.OutputLines(), + icube->Bands()); + + // Set up the interpolator + Interpolator *interp; + if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { + interp = new Interpolator(Interpolator::NearestNeighborType); + } + else if (ui.GetString("INTERP") == "BILINEAR") { + interp = new Interpolator(Interpolator::BiLinearType); + } + else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { + interp = new Interpolator(Interpolator::CubicConvolutionType); + } + else { + string msg = "Unknown value for INTERP [" + + ui.GetString("INTERP") + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Create the output file + p.StartProcess(transform, *interp); + + // All done!! + p.EndProcess(); + delete interp; +} + diff --git a/isis/src/base/apps/slither/slither.xml b/isis/src/base/apps/slither/slither.xml new file mode 100644 index 0000000000000000000000000000000000000000..c2b5364950aa70f60b632bd44f0b8f37b50f66aa --- /dev/null +++ b/isis/src/base/apps/slither/slither.xml @@ -0,0 +1,355 @@ + + + + + + Computes a transformation to shift entire lines or samples + + + +

    + slither computes an image transformation that shifts lines up or down + and samples left or right preserving whole lines and samples. The + transform is computed from a control net file. These control net files are + typically generated by Isis applications such as coreg and + hijitreg. +

    +

    + The transform used to generate the output file is computed by + statistically merging all the column coregistration results into one + column for each row. The important values in the control net file used + are the line and sample offsets. These are relative shifts in line and + sample at each coregistration chip center. See coreg or + hijitreg for details on registration chips. +

    +

    + The offsets computed are relative shifts in line and sample using a + user selectable interpolation scheme via the SPLINE parameter. + The type of spline selected is then used to compute the interpolation + for both the line and sample offsets. They are computed independanty + and applied independantly as well for each output line and sample + position requested during the tranform operation. +

    +

    + The parameters LINEOFFSET and SAMPLEOFFSET can be used + to shift the entire translation spatially in line and sample, respectively. + This is indicated when the initial starting point in the coregistration + application were not spatially registered, defined as the line and + sample chip coordinates in both images where the same when they + were correlated. Typically, hijitreg is the beneficiary of these + parameters. +

    +

    + slither computes either a forward of reverse transform, meaning the + results can be applied to the either image used in computing the + coregistration values. The forward transform is typical, applying + slither to the file provided in the FROM parameter of the + coregistration applications. +

    +

    + For further analysis, a rather large volume of data is created in the + RESULTS file if provided by the user. This file will contain statistics + for the control points used and also for each line in the output + image. Offsets for every line and the center sample is computed + and written to this file, so it will have at least as many lines of data as + the input image. It is really suited for plotting the resulting transform + for verification and analysis. +

    +
    + + + + Original version + + + Documentation fixes + + + Modified call to get current time to point to Time class, instead + of Application class + + + Fixed typo in user documentation + + + Removed references to CubeInfo + + + Removed references to DataInterp class and replaced them with + NumericalApproximation class. + + + + + Geometry + + + + + + cube + input + + Input cube to slither + + + Use this parameter to select the filename. All bands within the file + will be slithered unless a specific band is specified. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the slither transform + + + + + filename + + Control Net file + + +

    + This file will contain the control net used to compute the translation. + It will typically come from the coreg or hijitreg + application but could come from other sources. +

    +

    + There are some restrictions/requirements as to the content and + form of this file. First, there must only be two measures per + control point. If there are any more or less than two they are + silently ignored. This will typically result in failure as each + interpolation option requires a minimum number of points. (If + one point does not satisfy this requirement, typically none of + them will and slither will terminate with an error indicating not + enough points.) +

    +

    + Secondly, one of the measures should be identified as the + reference image. The reference image is typically the image that + was provided in the MATCH parameter to coreg or + hijitreg. If this is not the case, slither assumes the first + point is the reference image. It has no other way to determine + this. +

    +

    + This is important because of the way control points are combined + into a single column at each row. Typically, applications such as + coreg and hijitreg will compute coregistration + chips at the same line for each column. The line numbers are + used to determine which columns are combined for each row. + If the correct lines cannot be determined (with robust equvialence + checking considering roundoff), then chances are good that the + translation will not work properly. For example, if the reference + image was erroneously selected to be the FROM parameter from + the registration applications, then it would compare translated + (shifted) lines and conclude that every chip is a unique row. + This would result in as many rows as chips and, by definition, + this would cause the interpolation to fail. +

    +

    + Unfortunately, this is mostly programmer controlled so when these + types of problems occur, they should be reported to the Isis + Support. +

    +
    + + *.net + +
    + + + filename + + Dump of line/sample interpolation and statistics + + + This file is optional and if specifed, will contain a dump of the + determination of the collapse of the columns at each row and + the statistics at each row. It also contains the absolute line and + sample mapping for each line and (center) sample of each line as well + as relative line and sample offsets at each line. + + None + + *.txt + + + +
    + + + + string + CUBIC + Interpolation type to be used on the line and sample transform + + slither provides 4 different (spline) interpolation options. The + interpolation option chosen is used to compute a continuous (or + piecewise continous) interpolation so that each line and sample + has a transform location that maps the output line and sample + to a shifted input line and sample. These interpolations provide + this mapping. + + + + + + + + + + + string + FORWARD + Direction of the transform + + This parameter provides the ability to apply the transform to + either the FROM or MATCH images used to compute the + control net correlation. FORWARD is used for the FROM + image and REVERSE is when the MATCH, or the reference, + image is provided in the FROM parameter to slither. + + + + + + + + + double + 0.0 + Number lines to add to each shift + +

    + In some cases, an initial offset was added to start the image registration. + This parameter allows for this shift to be applied to the transform. This is + also equivalent to the Isis translate transform application that + shifts the image spatially. +

    +

    + Negative values shifts the image down. Positive values shifts the + image up. +

    +
    +
    + + double + 0.0 + Number samples to add to each shift + +

    + In some cases, an initial offset was added to start the image registration. + This parameter allows for this shift to be applied to the transform. This is + also equivalent to the Isis translate transform application that + shifts the image spatially. +

    +

    + Note that negative values shift the image to the right. Positive values + shift the image left. +

    +
    +
    +
    + + + + string + + CUBICCONVOLUTION + + Type of interpolation + + This is the type of interpolation to be performed on the input. + + + + + + + + +
    +
    + diff --git a/isis/src/base/apps/slither/tsts/Makefile b/isis/src/base/apps/slither/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/slither/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/slither/tsts/default/Makefile b/isis/src/base/apps/slither/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bce45c08b8853ae967bf62dbd8049ccb50d23ac9 --- /dev/null +++ b/isis/src/base/apps/slither/tsts/default/Makefile @@ -0,0 +1,14 @@ +APPNAME = slither + +include $(ISISROOT)/make/isismake.tsts + +PSP_001392_2490_IR11_BG13.slither.txt.IGNORELINES = RunDate: FROM CNETFILE + +commands: + $(APPNAME) from=$(INPUT)/PSP_001392_2490_IR11.balance.cub \ + to=$(OUTPUT)/PSP_001392_2490_IR11.slither.cub \ + control=$(INPUT)/PSP_001392_2490_IR11_BG13.net \ + results=$(OUTPUT)/PSP_001392_2490_IR11_BG13.slither.txt \ + direction=reverse spline=cubic \ + lineoffset=0 sampleoffset = 0 \ + interp=cubicconvolution > /dev/null diff --git a/isis/src/base/apps/slpmap/Makefile b/isis/src/base/apps/slpmap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/slpmap/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/slpmap/assets/image/angle.jpg b/isis/src/base/apps/slpmap/assets/image/angle.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0944952afe5c14071e5874bfbb36c16f71d97c34 Binary files /dev/null and b/isis/src/base/apps/slpmap/assets/image/angle.jpg differ diff --git a/isis/src/base/apps/slpmap/assets/image/angleGUI.jpg b/isis/src/base/apps/slpmap/assets/image/angleGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5af7864bc019d6bc261b80d441f0f290025f8c96 Binary files /dev/null and b/isis/src/base/apps/slpmap/assets/image/angleGUI.jpg differ diff --git a/isis/src/base/apps/slpmap/assets/image/vallis_marinaris.jpg b/isis/src/base/apps/slpmap/assets/image/vallis_marinaris.jpg new file mode 100644 index 0000000000000000000000000000000000000000..defdea485ca13f6e3da2fe959fedbc635520724d Binary files /dev/null and b/isis/src/base/apps/slpmap/assets/image/vallis_marinaris.jpg differ diff --git a/isis/src/base/apps/slpmap/assets/thumb/angleGUI_thumb.jpg b/isis/src/base/apps/slpmap/assets/thumb/angleGUI_thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a7f23c5b96d11a4dc28d754248981c9325d86380 Binary files /dev/null and b/isis/src/base/apps/slpmap/assets/thumb/angleGUI_thumb.jpg differ diff --git a/isis/src/base/apps/slpmap/assets/thumb/angle_thumb.jpg b/isis/src/base/apps/slpmap/assets/thumb/angle_thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..74b154effcf81724d416ba73d8d733cb58722e16 Binary files /dev/null and b/isis/src/base/apps/slpmap/assets/thumb/angle_thumb.jpg differ diff --git a/isis/src/base/apps/slpmap/assets/thumb/vallis_marinaris_thumb.jpg b/isis/src/base/apps/slpmap/assets/thumb/vallis_marinaris_thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..889e1cd92d0bc17c34a7fada9ba4df03488cbf10 Binary files /dev/null and b/isis/src/base/apps/slpmap/assets/thumb/vallis_marinaris_thumb.jpg differ diff --git a/isis/src/base/apps/slpmap/slpmap.cpp b/isis/src/base/apps/slpmap/slpmap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b635479cd73d4530b29dafd25aef33753e0a916 --- /dev/null +++ b/isis/src/base/apps/slpmap/slpmap.cpp @@ -0,0 +1,198 @@ +#include +#include "Isis.h" +#include "ProcessByBoxcar.h" +#include "Camera.h" +#include "Projection.h" + +using namespace std; +using namespace Isis; + +bool degrees; + +double resolution[2]; + +void createSlpCube (Buffer &in, double &v); +void createAspectCube (Buffer &in, double &v); + +void IsisMain() { + ProcessByBoxcar p; + + UserInterface &ui = Application::GetUserInterface(); + + degrees = ui.GetBoolean("DEGREES"); + + // as ProcessByBoxcar only allows one input cube and one + // output cube, two seperate process must be done + Cube *icube = p.SetInputCube ("FROM"); + p.SetBoxcarSize( 3, 3 ); + p.SetOutputCube ("TO"); + + if(ui.GetString("OUTPUT") == "SLOPE" ) { + // For slope we need a resolution + // Try to use the camera first + try { + Camera *cam = icube->Camera(); + + // Really we should be doing this at every point in the image... but for now, + // the center will work. + if(!cam->SetImage(icube->Samples()/2,icube->Lines()/2)) { + // Get into the catch(...) + throw iException::Message(iException::Programmer,"",_FILEINFO_); + } + + // Convert resolution to the DN value's unit (easier) + resolution[0] = cam->SampleResolution() / ui.GetDouble("CONVERSION");; + resolution[1] = cam->LineResolution() / ui.GetDouble("CONVERSION");; + } + catch (iException &e) { + // Failed at getting the camera, reset our exception and try again with the projection + e.Clear(); + + Projection *proj = icube->Projection(); + + if(!proj->SetWorld(icube->Samples()/2,icube->Lines()/2)) { + iString message = "Failed to SetWorld at the center of the image"; + throw iException::Message(iException::Programmer,message,_FILEINFO_); + } + + // Convert resolution to the DN value's unit (easier) + resolution[0] = proj->Resolution() / ui.GetDouble("CONVERSION"); + resolution[1] = proj->Resolution() / ui.GetDouble("CONVERSION"); + } + + p.StartProcess (createSlpCube); + } + else { + p.StartProcess (createAspectCube); + } + + p.EndProcess(); +} + + +/** + * http://webhelp.esri.com/arcgisdesktop/9.3/index.cfm?TopicName=How%20Slope%20(3D%20Analyst)%20works + * + * "Conceptually, the Slope function fits a plane to the z-values of a 3 x 3 + * cell neighborhood around the processing or center cell. The slope value of + * this plane is calculated using the average maximum technique (see + * References). The direction the plane faces is the aspect for the processing + * cell. The lower the slope value, the flatter the terrain; the higher the + * slope value, the steeper the terrain." + * + * @param in Input cube data (3x3 matrix) + * @param v Output value + */ +void createSlpCube( Buffer &in, double &v ) { + const double &a = in[0]; + const double &b = in[1]; + const double &c = in[2]; + const double &d = in[3]; + //const double &e = in[4]; + const double &f = in[5]; + const double &g = in[6]; + const double &h = in[7]; + const double &i = in[8]; + + // If anything we're actually calculating with is special, fail + if(Isis::IsSpecial(a) || + Isis::IsSpecial(b) || + Isis::IsSpecial(c) || + Isis::IsSpecial(f) || + Isis::IsSpecial(g) || + Isis::IsSpecial(h) || + Isis::IsSpecial(i)) { + v = Isis::Null; + return; + } + + // [dz/dx] = ((c + 2f + i) - (a + 2d + g)) / (8 * x_cell_size) + double changeInX = ((c + 2*f + i) - (a + 2*d + g)) / (8 * resolution[0]); + + // [dz/dy] = ((g + 2h + i) - (a + 2b + c)) / (8 * y_cell_size) + double changeInY = ((g + 2*h + i) - (a + 2*b + c)) / (8 * resolution[0]); + + double changeMag = sqrt(changeInX*changeInX + changeInY*changeInY); + + double slopeRadians = atan(changeMag); + + if(!degrees) { + v = slopeRadians; + } + else { + v = slopeRadians * 180.0 / Isis::PI; + } +} + + +/** + * http://webhelp.esri.com/arcgisdesktop/9.3/index.cfm?TopicName=How%20Aspect%20(3D%20Analyst)%20works + * + * "Conceptually, the Aspect function fits a plane to the z-values of a 3 x 3 + * cell neighborhood around the processing or center cell. The direction the + * plane faces is the aspect for the processing cell." + * + * @param in Input cube data (3x3 matrix) + * @param v Output value + */ +void createAspectCube( Buffer &in, double &v ) { + const double &a = in[0]; + const double &b = in[1]; + const double &c = in[2]; + const double &d = in[3]; + //const double &e = in[4]; + const double &f = in[5]; + const double &g = in[6]; + const double &h = in[7]; + const double &i = in[8]; + + // If anything we're actually calculating with is special, fail + if(Isis::IsSpecial(a) || + Isis::IsSpecial(b) || + Isis::IsSpecial(c) || + Isis::IsSpecial(f) || + Isis::IsSpecial(g) || + Isis::IsSpecial(h) || + Isis::IsSpecial(i)) { + v = Isis::Null; + return; + } + + // [dz/dx] = ((c + 2f + i) - (a + 2d + g)) / 8 + double changeInX = ((c + 2*f + i) - (a + 2*d + g)) / 8; + + // [dz/dy] = ((g + 2h + i) - (a + 2b + c)) / 8 + double changeInY = ((g + 2*h + i) - (a + 2*b + c)) / 8; + + // aspect = 57.29578 * atan2 ([dz/dy], -[dz/dx]) = in degrees + double aspectRadians = atan2(changeInY, -changeInX); + + + /* + The aspect value is then converted to compass direction values (0-360 degrees), according to the following rule: + if aspect < 0 + cell = 90.0 - aspect + else if aspect > 90.0 + cell = 360.0 - aspect + 90.0 + else + cell = 90.0 - aspect + */ + + if(aspectRadians < 0) { + v = Isis::PI / 2.0 - aspectRadians; + } + else if(aspectRadians > Isis::PI / 2.0) { + v = Isis::PI * 2.0 - aspectRadians + Isis::PI / 2.0; + } + else { + v = Isis::PI / 2.0 - aspectRadians; + } + + if(!degrees) { + v = aspectRadians; + } + else { + v = aspectRadians * 180.0 / Isis::PI; + } + +} diff --git a/isis/src/base/apps/slpmap/slpmap.xml b/isis/src/base/apps/slpmap/slpmap.xml new file mode 100644 index 0000000000000000000000000000000000000000..35542d2413da77586c7d7add111160a30ab1f431 --- /dev/null +++ b/isis/src/base/apps/slpmap/slpmap.xml @@ -0,0 +1,161 @@ + + + + + + Creates cubes that have slope data or aspect data + + + + This program takes a cube in which the DN values represent elevations. This program + will calculate either the slope at every point, or the direction of the slope at + every point in radians or degrees. These directions are relative to the image (not + relative to north), which can be different in various projections and cameras. + + + + + Original version + + + Changed slope and aspect algorithms + + + + + Radiometric and Photometric Correction + + + + + + cube + input + + Input cube + + + Use this parameter to select input cube. All bands of the cube within the file + will have the shade applied. + + + *.cub + + + + + cube + real + output + + Output cube + + + Output cube for your process. + + + + + + + string + Type of output requested + SLOPE + + This determines the type of output that will be created. + + + + + + + + + boolean + Output in degrees + false + + When set to true, the output image will be in degrees. If this is false, + the output image will be in radians. + + + + + double + Conversion factor (resolution to meters) + 1.0 + + Since the slope algorithm depends on cancelling out the units, the + conversion factor from the input unit to meters should be set. For + example, if the input image DN values mean kilometers, then this + value should be 1000 because there are 1000m in one kilometer. + + + + + + + + + Creating an aspect cube + + This example creates an aspect (shows the direction of the slope) cube of Vallis Marinaris + + + from=vallis_marinaris.cub to=aspect.cub output=aspect + + In this examples we will create an aspect cube. + + + + + + Image of Vallis Marinaris + + This is our input image of Vallis Marinaris. The DN values are the angle, in radians, the slope is facing relative to the image. + + + FROM + + + + + + The cube holding angle data + + This is the cube that holds the angle data. + + + TO + + + + + + + Example Gui + Screenshot of the GUI with parameters filled in to create a steepest slope cube. + + + + + + + + + diff --git a/isis/src/base/apps/slpmap/tsts/Makefile b/isis/src/base/apps/slpmap/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/slpmap/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/slpmap/tsts/angle/Makefile b/isis/src/base/apps/slpmap/tsts/angle/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..99d968bc4362a46d42ed6735deec650f6acb781b --- /dev/null +++ b/isis/src/base/apps/slpmap/tsts/angle/Makefile @@ -0,0 +1,7 @@ +APPNAME = slpmap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/128_vallis_marinaris.cub to=$(OUTPUT)/slpmapTruth.cub output=aspect > /dev/null; + diff --git a/isis/src/base/apps/slpmap/tsts/slope/Makefile b/isis/src/base/apps/slpmap/tsts/slope/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..938e4c8aff771f2fa9bf2b1cddca0228b3d7899a --- /dev/null +++ b/isis/src/base/apps/slpmap/tsts/slope/Makefile @@ -0,0 +1,6 @@ +APPNAME = slpmap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/128_vallis_marinaris.cub to=$(OUTPUT)/slpmapTruth.cub > /dev/null; diff --git a/isis/src/base/apps/specadd/Makefile b/isis/src/base/apps/specadd/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/specadd/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/specadd/specadd.cpp b/isis/src/base/apps/specadd/specadd.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be639ac32bde008279216bb9cdf25ab6d8f62312 --- /dev/null +++ b/isis/src/base/apps/specadd/specadd.cpp @@ -0,0 +1,35 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +void specadd (vector &in, vector &out); + +void IsisMain() { + ProcessByLine p; + + // Setup the input and output cubes + p.SetInputCube("FROM"); + p.SetInputCube("MATCH"); + p.SetOutputCube ("TO" ); + + p.StartProcess(specadd); + p.EndProcess(); +} + +// Line processing routine +void specadd (vector &in, vector &out) +{ + Buffer &from = *in[0]; + Buffer &match = *in[1]; + Buffer &to = *out[0]; + + // copy the original image unless it's a special pixel + // in which case the information is copied from the match cube + for (int i=0; i + + + Adds special pixels from a match cube to an input cube + + + + Adds the special pixel information from the match cube to the input cube and outputs the result. + + + + Utility + + + + + Original version + + + Documentation fixes + + + + + + + cube + input + + Input file + + + The input cube. + + + *.cub + + + + + cube + input + + Input match file + + + The input cube containing the special pixels. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the match cube's special pixel information. + + + *.cub + + + + + diff --git a/isis/src/base/apps/specadd/tsts/Makefile b/isis/src/base/apps/specadd/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/specadd/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/specadd/tsts/default/Makefile b/isis/src/base/apps/specadd/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..274386008858cc10dd9d57d3123f47a1cf9b4c76 --- /dev/null +++ b/isis/src/base/apps/specadd/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = specadd + +include $(ISISROOT)/make/isismake.tsts + +commands: + makecube to=$(OUTPUT)/makecube.cub value=0.0 samples=126 lines=126 bands=2 > /dev/null; + $(APPNAME) from=$(OUTPUT)/makecube.cub \ + match= $(INPUT)/isisTruth.cub \ + to= $(OUTPUT)/specaddTruth.cub > /dev/null; diff --git a/isis/src/base/apps/specdivfilter/Makefile b/isis/src/base/apps/specdivfilter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/specdivfilter/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/specdivfilter/assets/images/cubeform.jpg b/isis/src/base/apps/specdivfilter/assets/images/cubeform.jpg new file mode 100644 index 0000000000000000000000000000000000000000..755a7b7824321efb191296ca0b8917d78e1e76e3 Binary files /dev/null and b/isis/src/base/apps/specdivfilter/assets/images/cubeform.jpg differ diff --git a/isis/src/base/apps/specdivfilter/assets/images/div15gui.jpg b/isis/src/base/apps/specdivfilter/assets/images/div15gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f223c26120af8528d9dddd8e3397fd09dd1a34be Binary files /dev/null and b/isis/src/base/apps/specdivfilter/assets/images/div15gui.jpg differ diff --git a/isis/src/base/apps/specdivfilter/assets/images/div61gui.jpg b/isis/src/base/apps/specdivfilter/assets/images/div61gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..385c6845e8f8ff95baeff92e7d4c4481bf1d1f66 Binary files /dev/null and b/isis/src/base/apps/specdivfilter/assets/images/div61gui.jpg differ diff --git a/isis/src/base/apps/specdivfilter/assets/images/postdiv.jpg b/isis/src/base/apps/specdivfilter/assets/images/postdiv.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4c4155bfabf78c20a596472c38722b182a48fc2f Binary files /dev/null and b/isis/src/base/apps/specdivfilter/assets/images/postdiv.jpg differ diff --git a/isis/src/base/apps/specdivfilter/assets/images/postdiv61.jpg b/isis/src/base/apps/specdivfilter/assets/images/postdiv61.jpg new file mode 100644 index 0000000000000000000000000000000000000000..66615e857ce9ee77481c3523cc4f60dc3dd0be0b Binary files /dev/null and b/isis/src/base/apps/specdivfilter/assets/images/postdiv61.jpg differ diff --git a/isis/src/base/apps/specdivfilter/assets/images/prediv.jpg b/isis/src/base/apps/specdivfilter/assets/images/prediv.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e36fab94f5de57e63c9f272cc2fd07aa267c48aa Binary files /dev/null and b/isis/src/base/apps/specdivfilter/assets/images/prediv.jpg differ diff --git a/isis/src/base/apps/specdivfilter/assets/thumbs/div15gui.jpg b/isis/src/base/apps/specdivfilter/assets/thumbs/div15gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f8fe4bcd2b7985c045b4512818241ec63ff8ca34 Binary files /dev/null and b/isis/src/base/apps/specdivfilter/assets/thumbs/div15gui.jpg differ diff --git a/isis/src/base/apps/specdivfilter/assets/thumbs/div61gui.jpg b/isis/src/base/apps/specdivfilter/assets/thumbs/div61gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bcebdd955feea340e3ac169118a1773a417db10c Binary files /dev/null and b/isis/src/base/apps/specdivfilter/assets/thumbs/div61gui.jpg differ diff --git a/isis/src/base/apps/specdivfilter/assets/thumbs/postdiv.jpg b/isis/src/base/apps/specdivfilter/assets/thumbs/postdiv.jpg new file mode 100644 index 0000000000000000000000000000000000000000..83c04774d904784856554bf34e4bbe27a8266049 Binary files /dev/null and b/isis/src/base/apps/specdivfilter/assets/thumbs/postdiv.jpg differ diff --git a/isis/src/base/apps/specdivfilter/assets/thumbs/postdiv61.jpg b/isis/src/base/apps/specdivfilter/assets/thumbs/postdiv61.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fff6bf58a9a83ce7f1a9df7120574e5be4ff89fd Binary files /dev/null and b/isis/src/base/apps/specdivfilter/assets/thumbs/postdiv61.jpg differ diff --git a/isis/src/base/apps/specdivfilter/assets/thumbs/prediv.jpg b/isis/src/base/apps/specdivfilter/assets/thumbs/prediv.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c0b658ca8938ac055d6037769f118ea5cc2a530a Binary files /dev/null and b/isis/src/base/apps/specdivfilter/assets/thumbs/prediv.jpg differ diff --git a/isis/src/base/apps/specdivfilter/specdivfilter.cpp b/isis/src/base/apps/specdivfilter/specdivfilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f399c4a3c9ada5e380f6e7ff0f550544c04867d5 --- /dev/null +++ b/isis/src/base/apps/specdivfilter/specdivfilter.cpp @@ -0,0 +1,68 @@ +#include "Isis.h" + +#include "ProcessBySpectra.h" +#include "QuickFilter.h" +#include "UserInterface.h" + +using namespace std; +using namespace Isis; + +// Which pixel types to filter +int bands; +double low ; +double high; + +// Prototype +void Filter (Buffer &in, Buffer &out); + +void IsisMain() { + //Set up ProcessBySpectra + ProcessBySpectra p; + + //Obtain input cube, get bands dimension from input cube and user input number bands + Cube *icube = p.SetInputCube("FROM"); + int maxBands = (2 * icube->Bands()) - 1; + UserInterface &ui = Application::GetUserInterface(); + bands = ui.GetInteger("BANDS"); + + //Check for cases of too many bands + if (bands > maxBands) { + iString msg = "Parameter bands [" + iString(bands) + "] exceeds maximum allowable size " + + "of [" + iString(maxBands) + "] for cube [" + icube->Filename() + "]"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + //Set the Boxcar Parameters + low = -DBL_MAX; + high = DBL_MAX; + + if (ui.WasEntered("LOW")) { + low = ui.GetDouble("LOW"); + } + if (ui.WasEntered("HIGH")) { + high = ui.GetDouble("HIGH"); + } + + //Obtain output cube + p.SetOutputCube("TO"); + + //Start the filter method + p.StartProcess(Filter); + p.EndProcess(); + +} + +/** + * Function to loop through the bands, and determine the + * average value of the pixels around each valid pixel, writing that + * average to the output at the pixel index + */ +void Filter (Buffer &in, Buffer &out) { + Isis::QuickFilter filter(in.size(), bands, 1); + filter.SetMinMax(low, high); + filter.AddLine(in.DoubleBuffer()); + + for (int i = 0; i < in.size(); i ++) { + out[i] = in[i] / filter.Average(i); + } +} diff --git a/isis/src/base/apps/specdivfilter/specdivfilter.xml b/isis/src/base/apps/specdivfilter/specdivfilter.xml new file mode 100644 index 0000000000000000000000000000000000000000..93666bfddd28c8d3cbcc23c21f671f8f29bebf5a --- /dev/null +++ b/isis/src/base/apps/specdivfilter/specdivfilter.xml @@ -0,0 +1,285 @@ + + + + + + Apply a spectral division filter + + + + This program applies a spectral division filter to a cube. A spectral filter + works between bands as opposed to a spacial operation on a single band. As a + division filter, it divides the original pixel by the average. + + + + Filters + + + + + speclowpass + spechighpass + + + + + + boxfilter + + + + + Original version + + + Modified documentation, added error checking for the number of bands, and + added examples + + + + + + + cube + input + + Input file + + + Input cube to filter + + + *.cub + + + + cube + real + output + + Filtered output cube + + + The resultant filtered cube + + + *.cub + + + + + + + integer + + Number of bands in boxcar + + + + This is the total number of bands in the boxcar. It must be odd and + can not exceed twice the number of bands in the cube. In general, the + size of the boxcar does not cause the program to operate significantly + slower. + + + 1 + + + + + + double + + Minimum valid DN + + + Valid minimum pixel value that will be used in boxcar computation. If + a pixel value is less than LOW then it will not be used when computing + the average. + + + Use all pixels + + + HIGH + + + + + double + + Maximum valid DN + + + Valid maximum pixel value that will be used in boxcar computation. If + a pixel value is greater than HIGH then it will not be used when + computing the average. + + + Use all pixels + + + LOW + + + + + + + + + Example of usage of the spectral division filter. + + + This example shows a spectral division filter being applied to the image + with a 15 depth boxcar. This cube has 256 bands so 15 is relatively + small. No averaging is done between bands, the divisoin filter more + increases differences between bands. Here is an image which highlights + which pixels a single pass would influence. The image shows a 9x9 dot + instead of a single pixel highlighted to make it more visible. In this + picture the boxcar would be seven or more bands, with the output pixel + being one of the visible pixels. Depending on how large the boxcar was + many of the values taken in could not be original, at a minimum, one + value will be mirrored since there are only six available bands. +
    +              
    +        
    +
    + + + from=/work1/mboyd/CM_1514302573_1.cub to=/work1/mboyd/postlow.cub + bands=15 + + + This example will filter the image using 15 bands and no limits on + high or low. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform the + specdivision filter with a 15 band boxcar on the image + CM_1514302573_1.ir.cub. + + + + + + + + + + Input image spectral graph before specdivfilter + + + This is the spectral plot of the center point of the image, (32, + 32), and shows all bands, 1- 256. No filter has been applied, and + the graph clearly shows how the value of line 32 sample 32 differs + from band to band. + + + FROM + + + + + + + Output image spectral graph after being filtered + + + This is the image after the filter. First note the change in scale, + everything has been amplified. Even in the apparent flat area small + differences have been amplified. + + + TO + + +
    + + + + Example of usage of the spectral division filter. + + + This example shows a spectral division filter being applied to the image + with a 61 depth boxcar. This cube has 256 bands so 61 takes in over a + fifth. In this case an image begins to show through, however, this is + not because of average but because of amplificatino of differences from + the original. + + + + from=/work1/mboyd/CM_1514302573_1.cub to=/work1/mboyd/postlow.cub + bands=61 + + + This example will filter the image using 61 bands and no limits on + high or low. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform the + spechighpass filter with a 61 band boxcar on the image + CM_1514302573_1.ir.cub. + + + + + + + + + + Input image spectral graph before spectral division filter + + + This is the spectral plot of the center point of the image, (32, + 32), and shows all bands, 1- 256. No averaging or amplification has + been applied. + + + FROM + + + + + + + Output image spectral graph after being filtered + + + This is the image after the filter. The amplification is clear + immediately from the change in scale necessary to show the new + values. All differences have been amplified, but smaller differences + have increased more significantly than large differences. + + + TO + + + +
    + +
    diff --git a/isis/src/base/apps/specdivfilter/tsts/Makefile b/isis/src/base/apps/specdivfilter/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/specdivfilter/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/specdivfilter/tsts/default/Makefile b/isis/src/base/apps/specdivfilter/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..02d6fdbe1309f6b8f662d3ad829c35f26764151d --- /dev/null +++ b/isis/src/base/apps/specdivfilter/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = specdivfilter + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/vims.cub \ + to=$(OUTPUT)/specdivfilterTruth.cub bands= 9 > /dev/null; diff --git a/isis/src/base/apps/spechighpass/Makefile b/isis/src/base/apps/spechighpass/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/spechighpass/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/spechighpass/assets/images/cubeform.jpg b/isis/src/base/apps/spechighpass/assets/images/cubeform.jpg new file mode 100644 index 0000000000000000000000000000000000000000..755a7b7824321efb191296ca0b8917d78e1e76e3 Binary files /dev/null and b/isis/src/base/apps/spechighpass/assets/images/cubeform.jpg differ diff --git a/isis/src/base/apps/spechighpass/assets/images/post63.jpg b/isis/src/base/apps/spechighpass/assets/images/post63.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1379cf34ece485c3600259c31bfe7ffab20de1a5 Binary files /dev/null and b/isis/src/base/apps/spechighpass/assets/images/post63.jpg differ diff --git a/isis/src/base/apps/spechighpass/assets/images/postSHP.jpg b/isis/src/base/apps/spechighpass/assets/images/postSHP.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a6285749afdba9a4fca47b6be0d1c562970329d3 Binary files /dev/null and b/isis/src/base/apps/spechighpass/assets/images/postSHP.jpg differ diff --git a/isis/src/base/apps/spechighpass/assets/images/preSHP.jpg b/isis/src/base/apps/spechighpass/assets/images/preSHP.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0cd920b105386971af987b16a56d38155e4166e8 Binary files /dev/null and b/isis/src/base/apps/spechighpass/assets/images/preSHP.jpg differ diff --git a/isis/src/base/apps/spechighpass/assets/images/specHgui.jpg b/isis/src/base/apps/spechighpass/assets/images/specHgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8117e9107c453e4180204f7b2ef81b14474af354 Binary files /dev/null and b/isis/src/base/apps/spechighpass/assets/images/specHgui.jpg differ diff --git a/isis/src/base/apps/spechighpass/assets/images/specHgui2.jpg b/isis/src/base/apps/spechighpass/assets/images/specHgui2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aa44c27d2c2be1175a33592b7af95ea6826c0cd5 Binary files /dev/null and b/isis/src/base/apps/spechighpass/assets/images/specHgui2.jpg differ diff --git a/isis/src/base/apps/spechighpass/assets/thumbs/post63.jpg b/isis/src/base/apps/spechighpass/assets/thumbs/post63.jpg new file mode 100644 index 0000000000000000000000000000000000000000..129f5da467038caf5405e8d263afd82fecf4c99d Binary files /dev/null and b/isis/src/base/apps/spechighpass/assets/thumbs/post63.jpg differ diff --git a/isis/src/base/apps/spechighpass/assets/thumbs/postSHP.jpg b/isis/src/base/apps/spechighpass/assets/thumbs/postSHP.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d77a25627537e7812151868ef1ddbc3a5f13c764 Binary files /dev/null and b/isis/src/base/apps/spechighpass/assets/thumbs/postSHP.jpg differ diff --git a/isis/src/base/apps/spechighpass/assets/thumbs/preSHP.jpg b/isis/src/base/apps/spechighpass/assets/thumbs/preSHP.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2b79b3b7ab60cf6749024095512e26ed3742361 Binary files /dev/null and b/isis/src/base/apps/spechighpass/assets/thumbs/preSHP.jpg differ diff --git a/isis/src/base/apps/spechighpass/assets/thumbs/specHgui.jpg b/isis/src/base/apps/spechighpass/assets/thumbs/specHgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..307631c99f46c3598015a2ee0ca359724af177b4 Binary files /dev/null and b/isis/src/base/apps/spechighpass/assets/thumbs/specHgui.jpg differ diff --git a/isis/src/base/apps/spechighpass/assets/thumbs/specHgui2.jpg b/isis/src/base/apps/spechighpass/assets/thumbs/specHgui2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f00e3f3c87e84a52158e0cbbc8d8a926237abe21 Binary files /dev/null and b/isis/src/base/apps/spechighpass/assets/thumbs/specHgui2.jpg differ diff --git a/isis/src/base/apps/spechighpass/spechighpass.cpp b/isis/src/base/apps/spechighpass/spechighpass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43db9b2a32ac27278169d2251fa29f213f784c11 --- /dev/null +++ b/isis/src/base/apps/spechighpass/spechighpass.cpp @@ -0,0 +1,71 @@ +#include "Isis.h" +#include "ProcessBySpectra.h" +#include "UserInterface.h" +#include "QuickFilter.h" + +#include + +using namespace std; +using namespace Isis; + +// Which pixel types to filter +int bands; +double low ; +double high; + +// Prototype +void Filter (Buffer &in, Buffer &out); + +void IsisMain() { + //Set up ProcessBySpectra + ProcessBySpectra p; + + //Obtain input cube, get bands dimension from input cube and user input number bands + Cube *icube = p.SetInputCube("FROM"); + int cubeBands = icube->Bands(); + UserInterface &ui = Application::GetUserInterface(); + bands = ui.GetInteger("BANDS"); + + //Check for cases of too many bands + if (bands >= (2 * cubeBands)) { + iString msg = "Parameter bands [" + iString(bands) + "] exceeds maximum allowable size " + + "of [" + iString((cubeBands * 2) - 1) + "] for cube [" + icube->Filename() + "]"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + //Set the Boxcar Parameters + low = -DBL_MAX; + high = DBL_MAX; + + if (ui.WasEntered("LOW")) { + low = ui.GetDouble("LOW"); + } + if (ui.WasEntered("HIGH")) { + high = ui.GetDouble("HIGH"); + } + + //Obtain output cube + p.SetOutputCube("TO"); + + //Start the filter method + p.StartProcess(Filter); + p.EndProcess(); + +} + +/** + * Function to loop through the bands, and determine the average + * value of the pixels around each valid pixel, writing that + * average to the output at the pixel index + */ +void Filter (Buffer &in, Buffer &out) { + QuickFilter *filter = new QuickFilter(in.size(), bands, 1); + filter->SetMinMax(low, high); + filter->AddLine(in.DoubleBuffer()); + + for (int i=0; i < in.size(); i++) { + out[i] = in[i] - filter->Average(i); + } + delete filter; + filter = NULL; +} diff --git a/isis/src/base/apps/spechighpass/spechighpass.xml b/isis/src/base/apps/spechighpass/spechighpass.xml new file mode 100644 index 0000000000000000000000000000000000000000..5fd8612ed96e4e26392123e8e1f3dbb5c1c166da --- /dev/null +++ b/isis/src/base/apps/spechighpass/spechighpass.xml @@ -0,0 +1,286 @@ + + + + + + Apply a spectral high pass filter to a cube + + + + This program applies a spectral high pass filter to a cube. The spectral + component means that this will be a high pass amongst the bands of an image + as opposed to averaging the lines and samples on the spacial plane with high + pass. A highpass filter involves subtracting a lowpass, the average, from + the original value. + + + + Filters + + + + + speclowpass + specdivfilter + + + + + + boxfilter + + + + + Original version + + + Added examples, modified documentation about boxcar size, added exception + handling for too many bands + + + + + + + cube + input + + Input file + + + Input cube to filter + + + *.cub + + + + cube + real + output + + Output spechighpass cube + + + The resultant filtered cube + + + *.cub + + + + + + + integer + + Number of bands in boxcar + + + This is the total number of bands in the boxcar. It must be odd and + can not exceed twice the number of bands in the cube. In general, the + size of the boxcar does not cause the program to operate significantly + slower. + + + 1 + + + + + + double + + Minimum valid DN + + + Valid minimum pixel value that will be used in boxcar computation. If + a pixel value is less than LOW then it will not be used when computing + the average. + + + Use all pixels + + + HIGH + + + + + double + + Maximum valid DN + + + Valid maximum pixel value that will be used in boxcar computation. If + a pixel value is greater than HIGH then it will not be used when + computing the average. + + + Use all pixels + + + LOW + + + + + + + + + Example of usage of the spectral highpass filter. + + + This example shows a spectral highpass filter being applied to the image + with a 15 depth boxcar. This cube has 256 bands so 15 is relatively + small. Although no averaging is done within a single band, the averaging + of the pixels of many bands will cause some averaging and smoothing of + the image if there is much difference between bands. Here is an image + which highlights which pixels a single pass would average. The image + shows a 9x9 dot instead of a single pixel highlighted to make it more + visible. In this picture the boxcar would be seven or more bands, with + the output pixel being one of the visible pixels. Depending on how large + the boxcar was many of the values taken in could not be original, at a + minimum, one value will be mirrored since there are only six available + bands. +
    +              
    +        
    +
    + + + from=/work1/salley/CM_1514302573_1.cub to=/work1/mboyd/postSHP.cub + bands=15 + + + This example will filter the image using 15 bands and no limits on + high or low. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform the + spechighpass filter with a 15 band boxcar on the image + CM_1514302573_1.ir.cub. + + + + + + + + + + Input image spectral graph before spechighpass filter + + + This is the spectral plot of the center point of the image, (32, + 32), and shows all bands, 1- 256. No averaging has been applied, + this is clear partialy because of th extreme peaks visible in the + first half. The peaks are related to values which differ + significantly from the bands around them. + + + FROM + + + + + + + Output image spectral graph after being filtered + + + This is the image after the filter. Although there are still sharp + peaks, everything has been brought closer to zero. In the before + image nearly all values are above zero, now the values are on either + side of zero and are smaller. + + + TO + + +
    + + + + Example of usage of the spectral highpass filter. + + + In this example the spechighpass filter is used to filter an image using + a boxcar of size 63 and a high tolerance of .075 on a photo with 256 + bands. + + + + from=/work1/salley/CM_1514302573_1.ir.cub to=/work1/mboyd/post63.cub + bands=63 high=.075 + + + This example will filter the image using 63 bands and a high limit of + 0.075. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform the + spechighpass filter with a 63 band boxcar on the image + CM_1516302573_1.ir.cub. + + + + + + + + + + Input image spectral graph before spechighpass filter + + + This is the spectral graph of the input image at location (32, 32), + notice the sharp peaks and all values greater than zero. + + + FROM + + + + + + + Output image after being filtered + + + In this image the differences is that everything has been lowered + except for the values already at zero. Some values which were + positive are now negative as well. + + + TO + + + + +
    +
    diff --git a/isis/src/base/apps/spechighpass/tsts/Makefile b/isis/src/base/apps/spechighpass/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/spechighpass/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/spechighpass/tsts/default/Makefile b/isis/src/base/apps/spechighpass/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3671159da1589709948215e18d2672ac58f9fd0d --- /dev/null +++ b/isis/src/base/apps/spechighpass/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = spechighpass + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/vims.cub \ + to=$(OUTPUT)/spechighpassTruth.cub bands= 9 > /dev/null; diff --git a/isis/src/base/apps/speclowpass/Makefile b/isis/src/base/apps/speclowpass/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/speclowpass/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/speclowpass/assets/images/cubeform.jpg b/isis/src/base/apps/speclowpass/assets/images/cubeform.jpg new file mode 100644 index 0000000000000000000000000000000000000000..755a7b7824321efb191296ca0b8917d78e1e76e3 Binary files /dev/null and b/isis/src/base/apps/speclowpass/assets/images/cubeform.jpg differ diff --git a/isis/src/base/apps/speclowpass/assets/images/gui2.jpg b/isis/src/base/apps/speclowpass/assets/images/gui2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a4edf223d48cad4f0fd14286a31f1d893d8841ec Binary files /dev/null and b/isis/src/base/apps/speclowpass/assets/images/gui2.jpg differ diff --git a/isis/src/base/apps/speclowpass/assets/images/post61.jpg b/isis/src/base/apps/speclowpass/assets/images/post61.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fae5f7074751ca5c6b5f35f20d5a24d329d5525d Binary files /dev/null and b/isis/src/base/apps/speclowpass/assets/images/post61.jpg differ diff --git a/isis/src/base/apps/speclowpass/assets/images/postlow.jpg b/isis/src/base/apps/speclowpass/assets/images/postlow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..216baeecaace0f7683971f52d1eebf8b6e7545bc Binary files /dev/null and b/isis/src/base/apps/speclowpass/assets/images/postlow.jpg differ diff --git a/isis/src/base/apps/speclowpass/assets/images/prelow.jpg b/isis/src/base/apps/speclowpass/assets/images/prelow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e36fab94f5de57e63c9f272cc2fd07aa267c48aa Binary files /dev/null and b/isis/src/base/apps/speclowpass/assets/images/prelow.jpg differ diff --git a/isis/src/base/apps/speclowpass/assets/images/slowpassgui.jpg b/isis/src/base/apps/speclowpass/assets/images/slowpassgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..36e9d5810f5235ffa36df3964f0ac6800e53516d Binary files /dev/null and b/isis/src/base/apps/speclowpass/assets/images/slowpassgui.jpg differ diff --git a/isis/src/base/apps/speclowpass/assets/thumbs/gui2.jpg b/isis/src/base/apps/speclowpass/assets/thumbs/gui2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3252b6c28e1ea0ae822fa1a2aad215fa14e78c0 Binary files /dev/null and b/isis/src/base/apps/speclowpass/assets/thumbs/gui2.jpg differ diff --git a/isis/src/base/apps/speclowpass/assets/thumbs/post61.jpg b/isis/src/base/apps/speclowpass/assets/thumbs/post61.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cfc526261a7cc50858ce894399ade5a4901282fc Binary files /dev/null and b/isis/src/base/apps/speclowpass/assets/thumbs/post61.jpg differ diff --git a/isis/src/base/apps/speclowpass/assets/thumbs/postlow.jpg b/isis/src/base/apps/speclowpass/assets/thumbs/postlow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c0b658ca8938ac055d6037769f118ea5cc2a530a Binary files /dev/null and b/isis/src/base/apps/speclowpass/assets/thumbs/postlow.jpg differ diff --git a/isis/src/base/apps/speclowpass/assets/thumbs/prelow.jpg b/isis/src/base/apps/speclowpass/assets/thumbs/prelow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7655717ef894aae23bcb448dd96aa2b078ee548e Binary files /dev/null and b/isis/src/base/apps/speclowpass/assets/thumbs/prelow.jpg differ diff --git a/isis/src/base/apps/speclowpass/assets/thumbs/slowpassgui.jpg b/isis/src/base/apps/speclowpass/assets/thumbs/slowpassgui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9b1fbe681ccd03cea18c2952ea4c72ce167f576b Binary files /dev/null and b/isis/src/base/apps/speclowpass/assets/thumbs/slowpassgui.jpg differ diff --git a/isis/src/base/apps/speclowpass/speclowpass.cpp b/isis/src/base/apps/speclowpass/speclowpass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e362bb2ea851d9720d7abd4fc3da8d25915df65 --- /dev/null +++ b/isis/src/base/apps/speclowpass/speclowpass.cpp @@ -0,0 +1,68 @@ +#include "Isis.h" +#include "ProcessBySpectra.h" +#include "UserInterface.h" +#include "QuickFilter.h" + +using namespace std; +using namespace Isis; + +// Which pixel types to filter +int bands; +double low ; +double high; + +// Prototype +void Filter (Buffer &in, Buffer &out); + +void IsisMain() { + // Set up ProcessBySpectra + ProcessBySpectra p; + + // Obtain input cube, get bands dimension from input cube and user input number bands + Cube *icube = p.SetInputCube("FROM"); + int maxBands = (2 * icube->Bands()) - 1; + UserInterface &ui = Application::GetUserInterface(); + bands = ui.GetInteger("BANDS"); + + // Check for cases of too many bands + if (bands > maxBands) { + iString msg = "Parameter bands [" + iString(bands) + "] exceeds maximum allowable size " + + "of [" + iString(maxBands) + "] for cube [" + icube->Filename() + "]"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + // Set the Boxcar Parameters + low = -DBL_MAX; + high = DBL_MAX; + + if (ui.WasEntered("LOW")) { + low = ui.GetDouble("LOW"); + } + if (ui.WasEntered("HIGH")) { + high = ui.GetDouble("HIGH"); + } + + // Obtain output cube + p.SetOutputCube("TO"); + + // Start the filter method + p.StartProcess(Filter); + p.EndProcess(); + +} + +/** + * Function to loop through the bands, and determine the + * average value of the pixels around each valid pixel, writing that + * average to the output at the pixel index + */ +void Filter (Buffer &in, Buffer &out) { + Isis::QuickFilter filter(in.size(), bands, 1); + filter.SetMinMax(low, high); + filter.AddLine(in.DoubleBuffer()); + + for (int i = 0; i < in.size(); i ++) { + out[i] = filter.Average(i); + } +} + diff --git a/isis/src/base/apps/speclowpass/speclowpass.xml b/isis/src/base/apps/speclowpass/speclowpass.xml new file mode 100644 index 0000000000000000000000000000000000000000..2def04ac7f34e0ed2def399826d49566f87c5653 --- /dev/null +++ b/isis/src/base/apps/speclowpass/speclowpass.xml @@ -0,0 +1,291 @@ + + + + + + Apply spectral low pass filter to a cube + + + + This program applies a spectral low pass filter to a cube. A spectral filter + works between bands as opposed to a spacial operation on a single band. + Lowpass filter means it will be subtracting the average from the original + pixel. + + + + Filters + + + + + spechighpass + specdivfilter + + + + + boxfilter + + + + + Original version + + + Modified documentation, added exception handling for too many bands, modified + examples + + + + + + + cube + input + + Input file + + + Input cube to filter + + + *.cub + + + + cube + output + + Filtered output cube + + + The resultant filtered cube + + + *.cub + + + + + + + integer + + Number of bands in boxcar + + + This is the total number of bands in the boxcar. It must be odd and + can not exceed twice the number of bands in the cube. In general, the + size of the boxcar does not cause the program to operate significantly + slower. + + + 1 + + + + + + double + + Minimum valid DN + + + Valid minimum pixel value that will be used in boxcar computation. If + a pixel value is less than LOW then it will not be used when computing + the average. + + + Use all pixels + + + HIGH + + + + + double + + Maximum valid DN + + + Valid maximum pixel value that will be used in boxcar computation. If + a pixel value is greater than HIGH then it will not be used when + computing the average. + + + Use all pixels + + + LOW + + + + + + + + + Example of usage of the spectral lowpass filter. + + + This example shows a spectral lowpass filter being applied to the image + with a 5 depth boxcar. This cube has 256 bands so 5 is relatively small. + Although no averaging is done within a single band, the averaging of the + pixels of many bands will cause some averaging and smoothing of the + image if there is much difference between bands. Here is an image which + highlights which pixels a single pass would average. The image shows a + 9x9 dot instead of a single pixel highlighted to make it more visible. + In this picture the boxcar would be seven or more bands, with the output + pixel being one of the visible pixels. Depending on how large the boxcar + was many of the values taken in could not be original, at a minimum, one + value will be mirrored since there are only six available bands. +
    +              
    +        
    +
    + + + from=/work1/mboyd/CM_1514302573_1.cub to=/work1/mboyd/postlow.cub + bands=5 + + + This example will filter the image using 5 bands and no limits on high + or low. + + + + + + + + Example GUI + + + Screenshot of the GUI wit +h parameters set to perform the + spechighpass filter with a 5 band boxcar on the image + CM_1514302573_1.ir.cub. + + + + + + + + + + Input image spectral graph before speclowpass filter + + + This is the spectral plot of the center point of the image, (32, + 32), and shows all bands, 1- 256. No averaging has been applied, + this is clear partialy because of th extreme peaks visible in the + first half. The peaks are related to values which differ + significantly from the bands around them. + + + FROM + + + + + + + Output image spectral graph after being filtered + + + This is the image after the filter. Although there are still peaks, + everything has been smoothed. In the before image the peaks were + sharp where as now they are more curved. Differences have been + leveled out to some extent. + + + TO + + +
    + + + + Example of usage of the spectral lowpass filter. + + + This example shows a spectral lowpass filter being applied to the image + with a 61 depth boxcar. This cube has 256 bands so 61 takes in over a + fifth. Although no averaging is done within a single band, the averaging + of the pixels of many bands will cause some averaging and smoothing of + the image if there is much difference between bands. In this case a + blurry image begins to show through. + + + + from=/work1/mboyd/CM_1514302573_1.cub to=/work1/mboyd/postlow.cub + bands=61 + + + This example will filter the image using 61 bands and no limits on + high or low. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to perform the + spechighpass filter with a 61 band boxcar on the image + CM_1514302573_1.ir.cub. + + + + + + + + + + Input image spectral graph before speclowpass filter + + + This is the spectral plot of the center point of the image, (32, + 32), and shows all bands, 1- 256. No averaging has been applied, + this is clear partialy because of th extreme peaks visible in the + first half. The peaks are related to values which differ + significantly from the bands around them. + + + FROM + + + + + + + Output image spectral graph after being filtered + + + This is the image after the filter. As is very clear, the averaging + has turned sharp peaks into a smooth slope and small bumps into + nothing. All bands in the image are now muchmore similar to each + ohter than they were before. Also note that the scale has changed + significantly. + + + TO + + + +
    + +
    diff --git a/isis/src/base/apps/speclowpass/tsts/Makefile b/isis/src/base/apps/speclowpass/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/speclowpass/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/speclowpass/tsts/default/Makefile b/isis/src/base/apps/speclowpass/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..90df4e416a0f4b97288f244274d0052c1bf173f0 --- /dev/null +++ b/isis/src/base/apps/speclowpass/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = speclowpass + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/vims.cub \ + to=$(OUTPUT)/speclowpassTruth.cub bands= 9 > /dev/null; diff --git a/isis/src/base/apps/specpix/Makefile b/isis/src/base/apps/specpix/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/specpix/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/specpix/specpix.cpp b/isis/src/base/apps/specpix/specpix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa4c9350b2d3f62abd844b9d0a7e10d9777b148a --- /dev/null +++ b/isis/src/base/apps/specpix/specpix.cpp @@ -0,0 +1,216 @@ +#include "Isis.h" + +#include +#include +#include + +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +enum SpecPix { + NULLP, + LRS, + HRS, + LIS, + HIS, + NONE +}; + +// Define class for checking the input ranges to make sure +// there is no overlap. If there is any overlap, exit with +// user error. +struct spRange { + double min; + double max; + SpecPix specPix; +}; +vector rngList; +int numRange; + +// Line processing routine +void specpix (Buffer &in, Buffer &out); + +bool Descending (const spRange &r1,const spRange &r2); +int nnull,nlis,nlrs,nhis,nhrs; + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + nnull = nlis = nlrs = nhis = nhrs = 0; + + // Setup the input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + + spRange temp; + // Read range values from user + UserInterface &ui = Application::GetUserInterface(); + + temp.min = 0; + temp.max = 0; + if (ui.WasEntered ("NULLMIN")) temp.min = ui.GetDouble ("NULLMIN"); + if (ui.WasEntered ("NULLMAX")) temp.max = ui.GetDouble ("NULLMAX"); + + if (temp.min != 0 || temp.max != 0) { + nnull = 0; + temp.specPix = NULLP; + rngList.push_back (temp); + temp.min = 0; + temp.max = 0; + temp.specPix = NONE; + } + + if (ui.WasEntered ("LRSMIN")) temp.min = ui.GetDouble ("LRSMIN"); + if (ui.WasEntered ("LRSMAX")) temp.max = ui.GetDouble ("LRSMAX"); + if (temp.min != 0 || temp.max != 0) { + nlrs = 0; + temp.specPix = LRS; + rngList.push_back (temp); + temp.min = 0; + temp.max = 0; + temp.specPix = NONE; + } + + if (ui.WasEntered ("HRSMIN")) temp.min = ui.GetDouble ("HRSMIN"); + if (ui.WasEntered ("HRSMAX")) temp.max = ui.GetDouble ("HRSMAX"); + if (temp.min != 0 || temp.max != 0) { + nhrs = 0; + temp.specPix = HRS; + rngList.push_back (temp); + temp.min = 0; + temp.max = 0; + temp.specPix = NONE; + } + + if (ui.WasEntered ("LISMIN")) temp.min = ui.GetDouble ("LISMIN"); + if (ui.WasEntered ("LISMAX")) temp.max = ui.GetDouble ("LISMAX"); + if (temp.min != 0 || temp.max != 0) { + nlis = 0; + temp.specPix = LIS; + rngList.push_back (temp); + temp.min = 0; + temp.max = 0; + temp.specPix = NONE; + } + + if (ui.WasEntered ("HISMIN")) temp.min = ui.GetDouble ("HISMIN"); + if (ui.WasEntered ("HISMAX")) temp.max = ui.GetDouble ("HISMAX"); + if (temp.min != 0 || temp.max != 0) { + nhis = 0; + temp.specPix = HIS; + rngList.push_back (temp); + temp.min = 0; + temp.max = 0; + temp.specPix = NONE; + } + + // If more than one range was entered, + // make sure there is no overlap in ranges between differing special + // pixel values. First sort on the min value in descending order. + // Then compare each min to the max in the next set of ranges. If + // the min is less than the next max, there is overlap between those + // two sets of ranges. + numRange = rngList.size(); + if (numRange > 1) { + vector sortList(numRange); + copy (rngList.begin(), rngList.end(), sortList.begin()); + sort (sortList.begin(),sortList.end(),Descending); + for (int i=0; i= rngList[rng].min && in[i] <= rngList[rng].max) { + out[i] = NULL8; + nnull++; + } + break; + + case LRS: + if (in[i] >= rngList[rng].min && in[i] <= rngList[rng].max) { + out[i] = LOW_REPR_SAT8; + nlrs++; + } + break; + + case HRS: + if (in[i] >= rngList[rng].min && in[i] <= rngList[rng].max) { + out[i] = HIGH_REPR_SAT8; + nhrs++; + } + break; + + case LIS: + if (in[i] >= rngList[rng].min && in[i] <= rngList[rng].max) { + out[i] = LOW_INSTR_SAT8; + nlis++; + } + break; + + case HIS: + if (in[i] >= rngList[rng].min && in[i] <= rngList[rng].max) { + out[i] = HIGH_INSTR_SAT8; + nhis++; + } + break; + + case NONE: + break; + } + } + } +} + +bool Descending (const spRange &r1,const spRange &r2) +{ + if (r1.min > r2.min) { + return true; + } + else + return false; +} diff --git a/isis/src/base/apps/specpix/specpix.xml b/isis/src/base/apps/specpix/specpix.xml new file mode 100644 index 0000000000000000000000000000000000000000..c9df1f15d91d4284f3343da27351e665a0c221a0 --- /dev/null +++ b/isis/src/base/apps/specpix/specpix.xml @@ -0,0 +1,247 @@ + + + + + + Replace user specified pixels with Isis special pixel values + + + + This program will replace the user specified pixels to Isis special pixel + values. Overlap between the ranges of differing special pixel values is + not allowed. Each special pixel range must be unique. + + + + + Original version + + + + Ported to Isis 3.0 + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Added modifications to apptest by Kim + + + Modified filename parameters to be cube parameters where necessary + + + Modified results pvl to not include the results group + + + + + + Utility + + + + + stretch + + + + + + + cube + input + + Input cube + + + Use this parameter to select the input filename. All bands within the + file will be checked for replacement of pixels. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the cube with specified pixels replaced with + Isis special pixel values. + + + *.cub + + + + + + + Do not create NULL pixels + double + The minimum value for NULL + + This defines the minimum value of the defined range of pixels to + be replaced with the Isis Null value. + + + NULLMAX + + + NULLMAX + + + + + Do not create NULL pixels + double + The maximum value for NULL + + This defines the maximum value of the defined range of pixels to + be replaced with the Isis Null value. + + + NULLMIN + + + NULLMIN + + + + + Do not create LRS pixels + double + The minimum value for LRS + + This defines the minimum value of the defined range of pixels to + be replaced with the Isis LRS value. + + + LRSMAX + + + LRSMAX + + + + + Do not create LRS pixels + double + The maximum value for LRS + + This defines the maximum value of the defined range of pixels to + be replaced with the Isis LRS value. + + + LRSMIN + + + LRSMIN + + + + + Do not create HRS pixels + double + The minimum value for HRS + + This defines the minimum value of the defined range of pixels to + be replaced with the Isis HRS value. + + + HRSMAX + + + HRSMAX + + + + + Do not create HRS pixels + double + The maximum value for HRS + + This defines the maximum value of the defined range of pixels to + be replaced with the Isis HRS value. + + + HRSMIN + + + HRSMIN + + + + + Do not create LIS pixels + double + The minimum value for LIS + + This defines the minimum value of the defined range of pixels to + be replaced with the Isis LIS value. + + + LISMAX + + + LISMAX + + + + + Do not create LIS pixels + double + The maximum value for LIS + + This defines the maximum value of the defined range of pixels to + be replaced with the Isis LIS value. + + + LISMIN + + + LISMIN + + + + + Do not create HIS pixels + double + The minimum value for HIS + + This defines the minimum value of the defined range of pixels to + be replaced with the Isis HIS value. + + + HISMAX + + + HISMAX + + + + + Do not create HIS pixels + double + The maximum value for HIS + + This defines the maximum value of the defined range of pixels to + be replaced with the Isis HIS value. + + + HISMIN + + + HISMIN + + + + + + diff --git a/isis/src/base/apps/specpix/tsts/Makefile b/isis/src/base/apps/specpix/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/specpix/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/specpix/tsts/all/Makefile b/isis/src/base/apps/specpix/tsts/all/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d1c0dbc9243d80c6fb2f251b88528196746c76a0 --- /dev/null +++ b/isis/src/base/apps/specpix/tsts/all/Makefile @@ -0,0 +1,17 @@ +APPNAME = specpix + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/specpixTruth6.cub \ + nullmin=1 \ + nullmax=2 \ + lrsmin=3 \ + lrsmax=4 \ + hrsmin=5 \ + hrsmax=6 \ + lismin=7 \ + lismax=8 \ + hismin=9 \ + hismax=10 > /dev/null; diff --git a/isis/src/base/apps/specpix/tsts/his/Makefile b/isis/src/base/apps/specpix/tsts/his/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ec4b08d117fd39651f66459d65d8d1065229fca8 --- /dev/null +++ b/isis/src/base/apps/specpix/tsts/his/Makefile @@ -0,0 +1,9 @@ +APPNAME = specpix + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/specpixTruth5.cub \ + hismin=1 \ + hismax=100 > /dev/null; diff --git a/isis/src/base/apps/specpix/tsts/hrs/Makefile b/isis/src/base/apps/specpix/tsts/hrs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9d4a672471076445c57a5a57e04b7378b33759ca --- /dev/null +++ b/isis/src/base/apps/specpix/tsts/hrs/Makefile @@ -0,0 +1,9 @@ +APPNAME = specpix + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/specpixTruth3.cub \ + hrsmin=1 \ + hrsmax=100 > /dev/null; diff --git a/isis/src/base/apps/specpix/tsts/lis/Makefile b/isis/src/base/apps/specpix/tsts/lis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..40b19e59c57eeaf84fc9c118a6b30b7d92c4833d --- /dev/null +++ b/isis/src/base/apps/specpix/tsts/lis/Makefile @@ -0,0 +1,9 @@ +APPNAME = specpix + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/specpixTruth4.cub \ + lismin=1 \ + lismax=100 > /dev/null; diff --git a/isis/src/base/apps/specpix/tsts/lrs/Makefile b/isis/src/base/apps/specpix/tsts/lrs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7c5fbdaf199688b043d21f4b6b92005bd19bcabd --- /dev/null +++ b/isis/src/base/apps/specpix/tsts/lrs/Makefile @@ -0,0 +1,9 @@ +APPNAME = specpix + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/specpixTruth2.cub \ + lrsmin=1 \ + lrsmax=100 > /dev/null; diff --git a/isis/src/base/apps/specpix/tsts/null/Makefile b/isis/src/base/apps/specpix/tsts/null/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8f398c767c211851c354427d387adf5719da5d75 --- /dev/null +++ b/isis/src/base/apps/specpix/tsts/null/Makefile @@ -0,0 +1,9 @@ +APPNAME = specpix + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/specpixTruth1.cub \ + nullmin=1 \ + nullmax=100 > /dev/null; diff --git a/isis/src/base/apps/spicefit/Makefile b/isis/src/base/apps/spicefit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/spicefit/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/spicefit/spicefit.cpp b/isis/src/base/apps/spicefit/spicefit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a07cc01335f41cd5b01f66117663fe5d96284bca --- /dev/null +++ b/isis/src/base/apps/spicefit/spicefit.cpp @@ -0,0 +1,48 @@ +#include "Isis.h" +#include "Cube.h" +#include "Table.h" +#include "Camera.h" +#include "iException.h" +#include "CameraDetectorMap.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + try { + // Open the cube + Cube cube; + cube.Open(ui.GetFilename("FROM"),"rw"); + + //check for existing polygon, if exists delete it + if (cube.Label()->HasObject("Polygon")){ + cube.Label()->DeleteObject("Polygon"); + } + + // Get the camera, interpolate to a parabola + Camera *cam = cube.Camera(); + if (cam->DetectorMap()->LineRate() == 0.0) { + string msg = "[" + ui.GetFilename("FROM") + "] is not a line scan camera"; + throw iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + cam->InstrumentRotation()->SetPolynomial(); + + // Get the instrument pointing keyword from the kernels group and update its value to table. + Isis::PvlGroup kernels = cube.Label()->FindGroup("Kernels",Isis::Pvl::Traverse); + + // Write out the "Table" label to the tabled kernels in the kernels group + kernels["InstrumentPointing"] = "Table"; + cube.PutGroup(kernels); + + // Pull out the pointing cache as a table and write it + Table cmatrix = cam->InstrumentRotation()->Cache("InstrumentPointing"); + cmatrix.Label().AddComment("Smoothed using spicefit"); + cube.Write(cmatrix); + cube.Close(); + } + catch (iException &e) { + string msg = "Unable to fit pointing for [" + ui.GetFilename("FROM") + "]"; + throw iException::Message(Isis::iException::User,msg,_FILEINFO_); + } +} diff --git a/isis/src/base/apps/spicefit/spicefit.xml b/isis/src/base/apps/spicefit/spicefit.xml new file mode 100644 index 0000000000000000000000000000000000000000..d7fdeb67db22862c7f5bc6897d5e692da182e1ca --- /dev/null +++ b/isis/src/base/apps/spicefit/spicefit.xml @@ -0,0 +1,55 @@ + + + + Fit a function to camera pointing + + + + This program requires a cube be initialized with "spiceinit". It will + then look at the InstrumentPointing table for the cube and use a least + square solution to compute a fit of the right ascension, declination, + and twist to a parabola. This should reduce "noisy" + pointing data. To restore the original pointing just rerun "spiceinit". + +

    + Note that this program should be used on line scan cameras. It will not work + on framing cameras. +

    +
    + + + Cameras + + + + + Original version + + + Added check to see if cube has existing polygon, if so delete it. + + + Added code to write InstrumentPointing keyword value as table in kernels + group in case the kernels are not already attached. + + + + + + + cube + input + + Cube to update + + + The file specification for the input cube. The pointing + for this cube will be fit to a parabola. + + + *.cub + + + + +
    diff --git a/isis/src/base/apps/spicefit/tsts/Makefile b/isis/src/base/apps/spicefit/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/spicefit/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/spicefit/tsts/default/Makefile b/isis/src/base/apps/spicefit/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7cdd9a3d2991b00a86b3a20732f258f9dce5484e --- /dev/null +++ b/isis/src/base/apps/spicefit/tsts/default/Makefile @@ -0,0 +1,16 @@ +APPNAME = spicefit + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(CP) $(INPUT)/moc2isisTruth1.cub $(OUTPUT)/moc2isisTruth.cub; + $(APPNAME) FROM= $(OUTPUT)/moc2isisTruth.cub > /dev/null; + tabledump FROM= $(OUTPUT)/moc2isisTruth.cub \ + TO= $(OUTPUT)/instramentpointing.txt NAME=InstrumentPointing > /dev/null; + tabledump FROM= $(OUTPUT)/moc2isisTruth.cub \ + TO= $(OUTPUT)/instramentposition.txt NAME=InstrumentPosition > /dev/null; + tabledump FROM= $(OUTPUT)/moc2isisTruth.cub \ + TO= $(OUTPUT)/botdrotation.txt NAME=BodyRotation > /dev/null; + tabledump FROM= $(OUTPUT)/moc2isisTruth.cub \ + TO= $(OUTPUT)/sunposition.txt NAME=SunPosition > /dev/null; + $(RM) $(OUTPUT)/moc2isisTruth.cub; diff --git a/isis/src/base/apps/spiceinit/Makefile b/isis/src/base/apps/spiceinit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/spiceinit/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/spiceinit/spiceinit.cpp b/isis/src/base/apps/spiceinit/spiceinit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3236c51d0506cf1e9155b33fc1a41f0926a3ae1 --- /dev/null +++ b/isis/src/base/apps/spiceinit/spiceinit.cpp @@ -0,0 +1,409 @@ +#include "Isis.h" + +#include + +#include "Process.h" +#include "Filename.h" +#include "PvlTranslationManager.h" +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "KernelDb.h" +#include "Table.h" + +using namespace std; +using namespace Isis; + +bool TryKernels(Cube *icube, Process &p, + Kernel lk, Kernel pck, + Kernel targetSpk, Kernel ck, + Kernel fk, Kernel ik, + Kernel sclk, Kernel spk, + Kernel iak, Kernel dem, + Kernel exk); + +void GetUserEnteredKernel(const string ¶m, Kernel &kernel); + +void IsisMain() { + // Open the input cube + Process p; + UserInterface &ui = Application::GetUserInterface(); + CubeAttributeInput cai; + Cube *icube = p.SetInputCube(ui.GetFilename("FROM"), cai, ReadWrite); + + // Make sure at least one CK & SPK quality was selected + if (!ui.GetBoolean("CKPREDICTED") && !ui.GetBoolean("CKRECON") && !ui.GetBoolean("CKSMITHED") && !ui.GetBoolean("CKNADIR")) { + string msg = "At least one CK quality must be selected"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + if (!ui.GetBoolean("SPKPREDICTED") && !ui.GetBoolean("SPKRECON") && !ui.GetBoolean("SPKSMITHED")) { + string msg = "At least one SPK quality must be selected"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Make sure it is not projected + Projection *proj = NULL; + try { + proj = icube->Projection(); + } catch (iException &e) { + proj = NULL; + e.Clear(); + } + + if (proj != NULL) { + string msg = "Can not initialize SPICE for a map projected cube"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + Pvl lab = *icube->Label(); + + // if cube has existing polygon delete it + if (icube->Label()->HasObject("Polygon")) { + icube->Label()->DeleteObject("Polygon"); + } + + // Set up for getting the mission name + // Get the directory where the system missions translation table is. + string transFile = p.MissionData("base", "translations/MissionName2DataDir.trn"); + + // Get the mission translation manager ready + PvlTranslationManager missionXlater (lab, transFile); + + // Get the mission name so we can search the correct DB's for kernels + string mission = missionXlater.Translate ("MissionName"); + + // Get system base kernels + unsigned int allowed = 0; + unsigned int allowedCK = 0; + unsigned int allowedSPK = 0; + if (ui.GetBoolean("CKPREDICTED")) allowedCK |= spiceInit::kernelTypeEnum("PREDICTED"); + if (ui.GetBoolean("CKRECON")) allowedCK |= spiceInit::kernelTypeEnum("RECONSTRUCTED"); + if (ui.GetBoolean("CKSMITHED")) allowedCK |= spiceInit::kernelTypeEnum("SMITHED"); + if (ui.GetBoolean("CKNADIR")) allowedCK |= spiceInit::kernelTypeEnum("NADIR"); + if (ui.GetBoolean("SPKPREDICTED")) allowedSPK |= spiceInit::kernelTypeEnum("PREDICTED"); + if (ui.GetBoolean("SPKRECON")) allowedSPK |= spiceInit::kernelTypeEnum("RECONSTRUCTED"); + if (ui.GetBoolean("SPKSMITHED")) allowedSPK |= spiceInit::kernelTypeEnum("SMITHED"); + KernelDb baseKernels (allowed); + KernelDb ckKernels (allowedCK); + KernelDb spkKernels (allowedSPK); + + baseKernels.LoadSystemDb(mission); + ckKernels.LoadSystemDb(mission); + spkKernels.LoadSystemDb(mission); + + Kernel lk, pck, targetSpk, fk, ik, sclk, spk, iak, dem, exk; + std::priority_queue< Kernel > ck; + lk = baseKernels.LeapSecond(lab); + pck = baseKernels.TargetAttitudeShape(lab); + targetSpk = baseKernels.TargetPosition(lab); + ik = baseKernels.Instrument(lab); + sclk = baseKernels.SpacecraftClock(lab); + iak = baseKernels.InstrumentAddendum(lab); + fk = ckKernels.Frame(lab); + ck = ckKernels.SpacecraftPointing(lab); + spk = spkKernels.SpacecraftPosition(lab); + + if (ui.GetBoolean("CKNADIR")) { + // Only add nadir if no spacecraft pointing found + std::vector kernels; + kernels.push_back("Nadir"); + ck.push(Kernel((spiceInit::kernelTypes)0, kernels)); + } + + // Get user defined kernels and override ones already found + GetUserEnteredKernel("LS", lk); + GetUserEnteredKernel("PCK", pck); + GetUserEnteredKernel("TSPK", targetSpk); + GetUserEnteredKernel("FK", fk); + GetUserEnteredKernel("IK", ik); + GetUserEnteredKernel("SCLK", sclk); + GetUserEnteredKernel("SPK", spk); + GetUserEnteredKernel("IAK", iak); + GetUserEnteredKernel("EXTRA", exk); + + // Get shape kernel + if (ui.GetString ("SHAPE") == "USER") { + GetUserEnteredKernel("MODEL", dem); + } else if (ui.GetString("SHAPE") == "SYSTEM") { + dem = baseKernels.Dem(lab); + } + + bool kernelSuccess = false; + + if (ck.size() == 0 && !ui.WasEntered("CK")) { + throw iException::Message(iException::Camera, + "No Camera Kernel found for the image ["+ui.GetFilename("FROM") + +"]", + _FILEINFO_); + } + else if(ui.WasEntered("CK")) { + // ck needs to be array size 1 and empty kernel objects + while(ck.size()) ck.pop(); + ck.push(Kernel()); + } + + while(ck.size() != 0 && !kernelSuccess) { + Kernel realCkKernel = ck.top(); + ck.pop(); + + if (ui.WasEntered("CK")) { + ui.GetAsString("CK", realCkKernel.kernels); + } + + // Merge SpacecraftPointing and Frame into ck + for (int i = 0; i < fk.size(); i++) { + realCkKernel.push_back(fk[i]); + } + + kernelSuccess = TryKernels(icube, p, lk, pck, targetSpk, + realCkKernel, fk, ik, sclk, spk, iak, dem, exk); + } + + if(!kernelSuccess) { + throw iException::Message(iException::Camera, + "Unable to initialize camera model", + _FILEINFO_); + } + + p.EndProcess(); +} + +/** + * If the user entered the parameter param, then + * kernel is replaced by the user's values and + * quality is reset to 0. + * + * @param param + * @param kernel + */ +void GetUserEnteredKernel(const string ¶m, Kernel &kernel) { + UserInterface &ui = Application::GetUserInterface(); + + if (ui.WasEntered(param)) { + kernel = Kernel(); + // NOTE: This is using GetAsString so that vars like $mgs can be used. + ui.GetAsString(param, kernel.kernels); + } +} + +bool TryKernels(Cube *icube, Process &p, + Kernel lk, Kernel pck, + Kernel targetSpk, Kernel ck, + Kernel fk, Kernel ik, Kernel sclk, + Kernel spk, Kernel iak, + Kernel dem, Kernel exk) { + Pvl lab = *icube->Label(); + + // Add the new kernel files to the existing kernels group + PvlKeyword lkKeyword("LeapSecond"); + PvlKeyword pckKeyword("TargetAttitudeShape"); + PvlKeyword targetSpkKeyword("TargetPosition"); + PvlKeyword ckKeyword("InstrumentPointing"); + PvlKeyword ikKeyword("Instrument"); + PvlKeyword sclkKeyword("SpacecraftClock"); + PvlKeyword spkKeyword("InstrumentPosition"); + PvlKeyword iakKeyword("InstrumentAddendum"); + PvlKeyword demKeyword("ShapeModel"); + PvlKeyword exkKeyword("Extra"); + + for (int i=0; iGetGroup("Kernels"); + PvlGroup currentKernels = originalKernels; + currentKernels.AddKeyword(lkKeyword, Pvl::Replace); + currentKernels.AddKeyword(pckKeyword, Pvl::Replace); + currentKernels.AddKeyword(targetSpkKeyword, Pvl::Replace); + currentKernels.AddKeyword(ckKeyword, Pvl::Replace); + currentKernels.AddKeyword(ikKeyword, Pvl::Replace); + currentKernels.AddKeyword(sclkKeyword, Pvl::Replace); + currentKernels.AddKeyword(spkKeyword, Pvl::Replace); + currentKernels.AddKeyword(iakKeyword, Pvl::Replace); + currentKernels.AddKeyword(demKeyword, Pvl::Replace); + + // report qualities + PvlKeyword spkQuality("InstrumentPositionQuality"); + spkQuality.AddValue(spiceInit::kernelTypeEnum(spk.kernelType)); + currentKernels.AddKeyword(spkQuality, Pvl::Replace); + + PvlKeyword ckQuality("InstrumentPointingQuality"); + ckQuality.AddValue(spiceInit::kernelTypeEnum(ck.kernelType)); + currentKernels.AddKeyword(ckQuality, Pvl::Replace); + + if (!exkKeyword.IsNull()) { + currentKernels.AddKeyword(exkKeyword, Pvl::Replace); + } + else if( currentKernels.HasKeyword("EXTRA") ) { + currentKernels.DeleteKeyword( "EXTRA" ); + } + + // Get rid of old keywords from previously inited cubes + if (currentKernels.HasKeyword("SpacecraftPointing")) { + currentKernels.DeleteKeyword("SpacecraftPointing"); + } + if (currentKernels.HasKeyword("SpacecraftPosition")) { + currentKernels.DeleteKeyword("SpacecraftPosition"); + } + if (currentKernels.HasKeyword("ElevationModel")) { + currentKernels.DeleteKeyword("ElevationModel"); + } + if (currentKernels.HasKeyword("Frame")) { + currentKernels.DeleteKeyword("Frame"); + } + if (currentKernels.HasKeyword("StartPadding")) { + currentKernels.DeleteKeyword("StartPadding"); + } + if (currentKernels.HasKeyword("EndPadding")) { + currentKernels.DeleteKeyword("EndPadding"); + } + + UserInterface &ui = Application::GetUserInterface(); + // Add any time padding the user specified to the spice group + if(ui.GetDouble("STARTPAD") > DBL_EPSILON) { + currentKernels.AddKeyword(PvlKeyword("StartPadding", ui.GetDouble("STARTPAD"), "seconds")); + } + + if(ui.GetDouble("ENDPAD") > DBL_EPSILON) { + currentKernels.AddKeyword(PvlKeyword("EndPadding", ui.GetDouble("ENDPAD"), "seconds")); + } + + currentKernels.AddKeyword(PvlKeyword("CameraVersion",CameraFactory::CameraVersion(lab)), Pvl::Replace); + + // Add the modified Kernels group to the input cube labels + icube->PutGroup(currentKernels); + + // Create the camera so we can get blobs if necessary + try { + Camera *cam; + try { + cam = icube->Camera(); + Application::Log(currentKernels); + } catch (iException &e) { + Pvl errPvl = e.PvlErrors(); + + if(errPvl.Groups() > 0) { + currentKernels += PvlKeyword("Error", errPvl.Group(errPvl.Groups()-1)["Message"][0]); + } + + Application::Log(currentKernels); + icube->PutGroup(originalKernels); + throw e; + } + if (ui.GetBoolean("ATTACH")) { + Table ckTable = cam->InstrumentRotation()->Cache("InstrumentPointing"); + ckTable.Label() += PvlKeyword("Description", "Created by spiceinit"); + ckTable.Label() += PvlKeyword("Kernels"); + + for (int i=0; iWrite(ckTable); + + Table spkTable = cam->InstrumentPosition()->Cache("InstrumentPosition"); + spkTable.Label() += PvlKeyword("Description", "Created by spiceinit"); + spkTable.Label() += PvlKeyword("Kernels"); + for (int i=0; iWrite(spkTable); + + Table bodyTable = cam->BodyRotation()->Cache("BodyRotation"); + bodyTable.Label() += PvlKeyword("Description", "Created by spiceinit"); + bodyTable.Label() += PvlKeyword("Kernels"); + for (int i=0; iSolarLongitude()); + icube->Write(bodyTable); + + Table sunTable = cam->SunPosition()->Cache("SunPosition"); + sunTable.Label() += PvlKeyword("Description", "Created by spiceinit"); + sunTable.Label() += PvlKeyword("Kernels"); + for (int i=0; iWrite(sunTable); + + // Save original kernels in keyword before changing to Table + PvlKeyword origCk = currentKernels["InstrumentPointing"]; + PvlKeyword origSpk = currentKernels["InstrumentPosition"]; + PvlKeyword origTargPos = currentKernels["TargetPosition"]; + + currentKernels["InstrumentPointing"] = "Table"; + for (int i=0; iPutGroup(currentKernels); + } + //modify Kernels group only + else { + Pvl *label = icube->Label(); + int i=0; + while (i < label->Objects()) { + PvlObject currObj = label->Object(i); + if (currObj.IsNamed("Table")) { + if (currObj["Name"][0] == iString("InstrumentPointing")) { + label->DeleteObject(i); + } else if (currObj["Name"][0] == iString("InstrumentPosition")) { + label->DeleteObject(i); + } else if (currObj["Name"][0] == iString("BodyRotation")) { + label->DeleteObject(i); + } else if (currObj["Name"][0] == iString("SunPosition")) { + label->DeleteObject(i); + } else { + i++; + } + } else { + i++; + } + } + } + + p.WriteHistory(*icube); + } catch (iException &e) { + e.Clear(); + icube->PutGroup(originalKernels); + return false; + } + + return true; +} diff --git a/isis/src/base/apps/spiceinit/spiceinit.xml b/isis/src/base/apps/spiceinit/spiceinit.xml new file mode 100644 index 0000000000000000000000000000000000000000..228341f3374cf9023793da9b6a3df9333d3fdf21 --- /dev/null +++ b/isis/src/base/apps/spiceinit/spiceinit.xml @@ -0,0 +1,603 @@ + + + + + Determine SPICE kernels for a camera cube + + + +

    + Cubes which have supported camera models in the ISIS system require spacecraft position, pointing, body shape and orientation, sun position, and much + more information in order to compute ground positions (latitude/longitude) and photometric viewing angles. This information is stored in SPICE kernels. + This program attempts to search the ISIS data areas in order to discern the SPICE kernels required for the camera cube. +

    + +

    + The program examines the "SpacecraftName", "InstrumentId", "TargetName", "StartTime", and "StopTime" keywords in the cube label to determine the kernels to use. It + attempts to find kernels files for the following keywords and writes them to the Kernels group: +

    + +
      +
    • Leap Second (LS)
    • +
    • Spacecraft Clock (SCLK)
    • +
    • Target Position (TSPK)
    • +
    • Target AttitudeShape (PCK)
    • +
    • Instrument (IK)
    • +
    • Instrument Addendum (IAK)
    • +
    • Frame (FK)
    • +
    • Spacecraft Position (SPK)
    • +
    • Instrument Pointing (CK)
    • +
    • Shape Model (DEM)
    • +
    + + If you are unfamilar with SPICE terminology it is recommended you read the NAIF required reading at http://naif.jpl.nasa.gov/naif/doc_C.html + +

    + The program modifies the kernels group and writes the name of the SPICE files that need to be loaded by the camera models. It has the option of pre-reading the + data from the SPICE kernels and loading it as a binary table attached to the cube. This can faciliate faster load times and allows the instrument pointing to be easily updated. +

    +

    + Please note: Kernel Files specified that reside in the current working directory will not have their paths expanded. This is to allow variables like $msg/ to work correctly. +

    +
    + + + Cameras + + + + + Original Version + + + Complete rewrite under Isis 3.0 conversion. + + + Modified to use an existing "Kernels" group instead of creating a + new one. This was because the mission specific import program + (e.g., moc2isis) was modified to create the "kernels" group and + put the "NaifFrameCode" into it. + + + Added new parameter "TEST". This parameter controls the + testing of the final kernel list. If false the kernels will not be + tested for completness by createing a camera model. + + + Added elevation model DEM capabilities. + + + Completed capabilities to search for kernels of different qualities + such as PREDICTED, NADIR, RECONSTRUCTED, and C-SMITHED. + + + Added fix for framing cameras, so they would not need a stop time in + the instrument group of the labels. + + + Added appTest + + + Added support for multiple files within the kernels + + + Added a progress bar + + + Fixed the xml description + + + Changed the mission translation file name + + + Changed the appTest to comply with changes in the String class. + + + Modified to write InstrumentPointing, InstrumentPosition, SunPosition, and BodyRotation information to + SPICE tables in the cube. + + + Added call to modify the history of the cube + + + Modifed to remove label entries for spice tables, if ATTACH is unchecked, + and the input cube already has them. + + + Combined Frame and InstrumentPointing. Changed to support new version of KernelDb. Cleaned up the code. + + + Fixed problem where the allowed kernels were being set improperly. + + + Fixed so that when no spacecraft pointing is found, but frame kernels are, and Nadir is allowed it still adds the Nadir keyword. + + + Added a check to see if the cube had an existing polygon, if so delete it. + + + Fixed Smithed enum, changed from C-Smithed. + + + Added error handling logic. If the user chose to use Nadir CK and + another type, and the system found a file where the image falls in a gap + (no pointing is available) Nadir would never be calculated. Fixed. + + + Added time padding options + + + Added additional explanation of time padding options + + + Split the CK parameter into FK and CK, they are still combined in the label as + InstrumentPointing. + + + All found CK kernels will now be tested before giving an error + + + Fixed the propagation of the EXTRA Kernel. + + + Removed references to CubeInfo + + + Fixed documentation + + + Furthered documentation. + + + Added CK check and throw more appropriate error + + + Added the removal of StartPadding and EndPadding keywords from previous + spiceinit runs, and added some double inited tests. NOTE: Whenever + adding new keywords, run spiceinit twice on the same cube in your test, + dumping out both labels to verify that the keyword is not being + duplicated. + + + If spice is put into a Table, append the kernel name to the Kernel group + keyword to keep track of original spice kernels. + + + Added CameraVersion into the Kernel labels + + + Error messages from the camera are now reported + + + Fixed handling of user-entered CK kernels + + + + + levinit + naiflab + spicelab + + + + + + cube + input + + The input file cube to have "kernel" labels added to it + + + The input file which will have a new "kernel" group added to its labels. + + *.cub + + + + boolean + TRUE + + Attach SPICE data to cube + + + This option attaches tables to the cube which contain the instrument position (SPK) and orientation (CK), as well as the sun position and body/target orientation. + This is the prefered initialization option as it allows the pointing to be updated by further programs. + + + + + + + + boolean + FALSE + + Use smithed pointing kernels if available + + + Allow the use of pointing kernels marked as c-smithed. + If this parameters is turned on, c-smithed kernels may be used to + cover the time requirements of the image. At least one of the + parameters "CKPREDICTED", "CKNADIR", "CKRECON", "CKSMITHED" + must be entered. + + + + + boolean + TRUE + + Use reconstructed pointing kernels if available + + + Allow the use of pointing kernels marked as reconstructed. + If this parameters is turned on, reconstructed kernels may be used to + cover the time requirements of the image. At least one of the + parameters "CKPREDICTED", "CKNADIR", "CKRECON", "CKSMITHED" + must be entered. + + + + + boolean + FALSE + + Use predicted pointing kernels if available + + + Allow the use of pointing kernels marked as predicted. + If this parameters is turned on, predicted kernels may be used to + cover the time requirements of the image. At least one of the + parameters "CKPREDICTED", "CKNADIR", "CKRECON", "CKSMITHED" + must be entered. + + + + + boolean + FALSE + + Compute nadir pointing if no other kernels exist + + + This option will create nadir pointing data if the other kernel types do not exist or do not cover the + time range of the input cube. At least one of the + parameters "CKPREDICTED", "CKNADIR", "CKRECON", "CKSMITHED" + must be entered. + + + + + + + boolean + FALSE + + Use smithed position kernels if available + + + Allow the use of position kernels marked as smithed. + If this parameters is turned on, smithed kernels may be used to( + cover the time requirements of the image. At least one of the + parameters "SPKPREDICTED", "SPKRECON", "SPKSMITHED" + must be entered. + + + + + boolean + TRUE + + Use reconstructed position kernels if available + + + Allow the use of position kernels marked as reconstructed. + If this parameters is turned on, reconstructed kernels may be used to + cover the time requirements of the image. At least one of the + parameters "SPKPREDICTED", "SPKRECON", "SPKSMITHED" + must be entered. + + + + + boolean + FALSE + + Use predicted pointing kernels if available + + + Allow the use of position kernels marked as predicted. + If this parameters is turned on, predicted kernels may be used to + cover the time requirements of the image. At least one of the + parameters "SPKPREDICTED", "SPKRECON", "SPKSMITHED" + must be entered. + + + + + + + + + + filename + none + input + + User defined leap second kernel file. + + + Naif kernel file to be used for the leap second in place of the + automated leap second kernel. The LS kernel will be referenced in the + keyword LeapSecond by the resulting Kernel group. + + $base/kernels/lsk/ + *.tls + + + + filename + none + input + + User defined target attitude and shape kernel file. + + + Naif kernel file to be used for the target attitude and shape in place + of the automated attitude and shape kernel. The PCK kernel will be + referenced in the keyword TargetAttitudeShape by the resulting Kernel + group. + + + $BASE/kernels/pck/ + + *.tpc + + + + filename + none + input + + User defined target position kernel file. + + + Naif kernel file to be used for the target position in place of the + automated position kernel. The TSPK kernel will be referenced in the + keyword TargetPosition by the resulting Kernel group. + + + $BASE/kernels/spk/ + + *.bsp + + + + filename + none + input + + User defined instrument kernel file. + + + Naif kernel file to be used for the instrument in place of the + automated instrument kernel. The IK kernel will be referenced in the + keyword Instrument by the resulting Kernel group. + + *.ti + $ISIS3DATA + + + + filename + none + input + + User defined spacecraft clock kernel file. + + + Naif kernel file to be used for the spacecraft clock in place of the + automated spacecraft clock kernel. The SCLK kernel will be referenced + in the keyword Instrument by the resulting Kernel group. + + *.tsc + $ISIS3DATA + + + + filename + none + input + + User defined spacecraft pointing kernel file. + + + Naif kernel file to be used for the spacecraft pointing in place of + the automated spacecraft pointing kernel. The CK kernel will be referenced + in the keyword InstrumentPointing by the resulting Kernel group. + + *.bc + $ISIS3DATA + + + + filename + none + input + + User defined frames kernel file. + + + Naif kernel file to be used for the instrument frame in place of the + automated frames kernel. The FK kernel will be referenced in the + keyword InstrumentPointing by the resulting Kernel group. + Note: If you enter a filename for CK some instruments may require a + frame kernel as well. + + *.tf + $ISIS3DATA + + + + + filename + none + input + + User defined spacecraft position kernel file. + + + Naif kernel file to be used for the spacecraft position in place of + the automated spacecraft position kernel. The SPK kernel will be + referenced in the keyword InstrumentPosition by the resulting Kernel + group. + + *.bsp + $ISIS3DATA + + + + filename + none + input + + User defined instrument addendum kernel file. + + + Naif formatted kernel file to be used for the ISIS specific instrument + addendum kernel, in place of the automated. The IAK kernel will be + referenced in the keyword InstrumentAddendum by the resulting Kernel + group. + + *.ti + $ISIS3DATA + + + + filename + none + input + + User defined extra kernel file. + + + Optional extra naif formatted kernel file. The EXTRA kernel will be + referenced in the keyword Extra by the resulting Kernel group. + + $ISIS3DATA + + + + + + string + SYSTEM + + Select the definition of the shape model + + + ISIS camera models can use a shape model (a projected ISIS cube that defines the radii for a global or regional area). You can choose + to select a shape model or to use the definition of the ellipsoid found in the planetary constants (PCK) file. + + + + + + + + + + cube + input + + User defined ISIS cube shape model. + + + A map projected ISIS cube which contains the radii of the target. The file can cover more than the input cube (FROM) but must minimally cover the data in the input cube. + + $base//dems/ + *.cub + + + + + + double + 0.0 + + Time padding (in seconds) to load from the kernels before the start time of the image + + + When the kernels for an image are loaded, by default only what the image requires is loaded. + By setting this option, the loaded kernels start at the specified amount of time before the + image start time. This option should always be zero for framing cameras. + + 0.0 + + + double + 0.0 + + Time padding (in seconds) to load from the kernels after the end time of the image + + + When the kernels for an image are loaded, by default only what the image requires is loaded. + By setting this option, the loaded kernels end at the specified amount of time after the + image end time. This option should always be zero for framing cameras. + + 0.0 + + + +
    diff --git a/isis/src/base/apps/spiceinit/tsts/Makefile b/isis/src/base/apps/spiceinit/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/spiceinit/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/spiceinit/tsts/default/Makefile b/isis/src/base/apps/spiceinit/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..78371582a9a39b58057aa2929f2fb39dc9737806 --- /dev/null +++ b/isis/src/base/apps/spiceinit/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME = spiceinit + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/spiceinitTruth.cub $(OUTPUT)/ > /dev/null; + $(APPNAME) from=$(OUTPUT)/spiceinitTruth.cub > /dev/null; + catlab from=$(OUTPUT)/spiceinitTruth.cub > $(OUTPUT)/labels.pvl; + $(APPNAME) from=$(OUTPUT)/spiceinitTruth.cub > /dev/null; + catlab from=$(OUTPUT)/spiceinitTruth.cub > $(OUTPUT)/labelsTwice.pvl; + rm $(OUTPUT)/spiceinitTruth.cub; diff --git a/isis/src/base/apps/spiceinit/tsts/multipleCK/Makefile b/isis/src/base/apps/spiceinit/tsts/multipleCK/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ff913a473ff4227d808f97e5c3023a8a9586fb43 --- /dev/null +++ b/isis/src/base/apps/spiceinit/tsts/multipleCK/Makefile @@ -0,0 +1,9 @@ +APPNAME = spiceinit + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/lub5120p.063.lev1.cub $(OUTPUT)/spiceinitTruth.cub > /dev/null; + $(APPNAME) from=$(OUTPUT)/spiceinitTruth.cub ATTACH=NO CKREC=TRUE CKSMITH=true > /dev/null; + catlab from=$(OUTPUT)/spiceinitTruth.cub > $(OUTPUT)/labels.pvl; + rm $(OUTPUT)/spiceinitTruth.cub; diff --git a/isis/src/base/apps/spiceinit/tsts/nadirCKgap/Makefile b/isis/src/base/apps/spiceinit/tsts/nadirCKgap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9038e35a8a59a6af5263709e16d22691de54eda1 --- /dev/null +++ b/isis/src/base/apps/spiceinit/tsts/nadirCKgap/Makefile @@ -0,0 +1,12 @@ +APPNAME = spiceinit + +labels.txt.IGNORELINES = ByteOrder StartByte Bytes + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/m1301260.cub $(OUTPUT)/nadirTruth.cub; + $(APPNAME) from=$(OUTPUT)/nadirTruth.cub attach=no cknadir=yes \ + tspk='$$base/kernels/spk/de405.bsp' > /dev/null; + catlab from=$(OUTPUT)/nadirTruth.cub > $(OUTPUT)/labels.txt; + rm $(OUTPUT)/nadirTruth.cub; diff --git a/isis/src/base/apps/spiceinit/tsts/padding/Makefile b/isis/src/base/apps/spiceinit/tsts/padding/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..78b70ec82e3409a86f2f903ee061f1a407775ead --- /dev/null +++ b/isis/src/base/apps/spiceinit/tsts/padding/Makefile @@ -0,0 +1,16 @@ +APPNAME = spiceinit + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/v1545949478_1.cub $(OUTPUT)/v1545949478_1.cub; + $(APPNAME) FROM=$(OUTPUT)/v1545949478_1.cub \ + STARTPAD=1.1 ENDPAD=0.5 ATTACH=FALSE \ + fk='$$cassini/kernels/fk/cas_v40_usgs.tf' > /dev/null; + catlab FROM=$(OUTPUT)/v1545949478_1.cub > $(OUTPUT)/labels.pvl; + $(APPNAME) FROM=$(OUTPUT)/v1545949478_1.cub \ + STARTPAD=1.1 ENDPAD=0.5 ATTACH=FALSE \ + sclk='$$cassini/kernels/sclk/cas00132.tsc' \ + fk='$$cassini/kernels/fk/cas_v40_usgs.tf' > /dev/null; + catlab FROM=$(OUTPUT)/v1545949478_1.cub > $(OUTPUT)/labelsTwice.pvl; + rm $(OUTPUT)/v1545949478_1.cub; diff --git a/isis/src/base/apps/stats/Makefile b/isis/src/base/apps/stats/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/stats/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/stats/assets/peaks3_stats.log b/isis/src/base/apps/stats/assets/peaks3_stats.log new file mode 100644 index 0000000000000000000000000000000000000000..5c8b6e4e0b9c000627f8120ad11e329a89430ee3 --- /dev/null +++ b/isis/src/base/apps/stats/assets/peaks3_stats.log @@ -0,0 +1,20 @@ +Gathering statistics +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Gathering histogram +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Average: 48.6321 +Std Deviation: 14.9684 +Variance: 224.053 +Median: 47.0317 +Mode: 38.9517 +Skew: 0.320739 +Minimum: 15 +Maximum: 212 + +Total Pixels: 1.04858e+06 +Valid Pixels: 1.04858e+06 +Null Pixels: 0 +Lis Pixels: 0 +Lrs Pixels: 0 +His Pixels: 0 +Hrs Pixels: 0 diff --git a/isis/src/base/apps/stats/stats.cpp b/isis/src/base/apps/stats/stats.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b13910e550138eab8b05a1960cf44e9c44551df --- /dev/null +++ b/isis/src/base/apps/stats/stats.cpp @@ -0,0 +1,108 @@ +#include "Isis.h" + +#include + +#include "Cube.h" +#include "Process.h" +#include "Histogram.h" +#include "Pvl.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + Process p; + + // Get the histogram + Cube *icube = p.SetInputCube("FROM"); + + double validMin = Isis::ValidMinimum; + double validMax = Isis::ValidMaximum; + + if(ui.WasEntered("VALIDMIN")) { + validMin = ui.GetDouble("VALIDMIN"); + } + + if(ui.WasEntered("VALIDMAX")) { + validMax = ui.GetDouble("VALIDMAX"); + } + + Histogram *stats = icube->Histogram(1, validMin, validMax); + + // Construct a label with the results + PvlGroup results("Results"); + results += PvlKeyword ("From", icube->Filename()); + if (stats->ValidPixels() != 0) { + results += PvlKeyword("Average",stats->Average()); + results += PvlKeyword ("StandardDeviation", stats->StandardDeviation()); + results += PvlKeyword ("Variance", stats->Variance()); + // These statistics only worked on a histogram + results += PvlKeyword ("Median", stats->Median()); + results += PvlKeyword ("Mode", stats->Mode()); + results += PvlKeyword ("Skew", stats->Skew()); + results += PvlKeyword ("Minimum", stats->Minimum()); + results += PvlKeyword ("Maximum", stats->Maximum()); + results += PvlKeyword ("Sum", stats->Sum()); + } + results += PvlKeyword ("TotalPixels", stats->TotalPixels()); + results += PvlKeyword ("ValidPixels", stats->ValidPixels()); + results += PvlKeyword ("OverValidMaximumPixels", stats->OverRangePixels()); + results += PvlKeyword ("UnderValidMinimumPixels", stats->UnderRangePixels()); + results += PvlKeyword ("NullPixels", stats->NullPixels()); + results += PvlKeyword ("LisPixels", stats->LisPixels()); + results += PvlKeyword ("LrsPixels", stats->LrsPixels()); + results += PvlKeyword ("HisPixels", stats->HisPixels()); + results += PvlKeyword ("HrsPixels", stats->HrsPixels()); + + // Write the results to the output file if the user specified one + if (ui.WasEntered("TO")) { + string outFile = Filename(ui.GetFilename("TO")).Expanded(); + bool exists = Filename(outFile).Exists(); + bool append = ui.GetBoolean("APPEND"); + ofstream os; + bool writeHeader = false; + //write the results in the requested format. + if (ui.GetString("FORMAT") == "PVL") { + Pvl temp; + temp.AddGroup(results); + if (append) { + temp.Append(outFile); + } + else { + temp.Write(outFile); + } + } else { + //if the format was not PVL, write out a flat file. + if (append) { + os.open(outFile.c_str(),ios::app); + if (!exists) { + writeHeader = true; + } + }else { + os.open(outFile.c_str(),ios::out); + writeHeader = true; + } + } + if(writeHeader) { + for(int i = 0; i < results.Keywords(); i++) { + os << results[i].Name(); + if(i < results.Keywords()-1) { + os << ","; + } + } + os << endl; + } + for(int i = 0; i < results.Keywords(); i++) { + os << (string)results[i]; + if(i < results.Keywords()-1) { + os << ","; + } + } + os << endl; + } + + delete stats; + // Write the results to the log + Application::Log(results); +} diff --git a/isis/src/base/apps/stats/stats.xml b/isis/src/base/apps/stats/stats.xml new file mode 100644 index 0000000000000000000000000000000000000000..07a25794167190e6732d6d17b28af1e375ae02fe --- /dev/null +++ b/isis/src/base/apps/stats/stats.xml @@ -0,0 +1,241 @@ + + + + Generates statistics about a cube + + + + This program computes statistics for + the pixels in a single band. If the band specification (e.g., file.cub:3) + is not given the program will default to the first band. The statistics + calculated include: +
    +        Average
    +        Standard deviation
    +        Variance
    +        Median
    +        Mode
    +        Skew
    +        Minimum
    +        Maximum
    +        Total pixels
    +        Valid pixels
    +        Null pixels
    +        Low instrument saturation pixels
    +        Low representation saturation pixels
    +        High instrument saturation pixels
    +        High representation saturation pixels
    +
    + The statistics will be output to the + logging device. Additionally, if the user specifies a file using the + TO parameter, the statistics + be written to the file in a standard label format + which can then be read using + the getkey proram. +
    + + + Math and Statistics + + + + + Original version written as "histo" + + + Changed name to "stats" and added logging mechanism + + + Added TO parameter which allows the user to create an output file that can + be read using the getkey program + + + Tested for bands which contain only special pixels in order to prevent + divide by zero errors. + + + Added the name of the input cube to the log and label file + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Made changes to application test truth files to reflect -O1 optimization + + + Added modifications to apptest by Kim + + + Modified filename parameters to be cube parameters where necessary + + + Modified results pvl to not include the results group + + + Fixed appTest to comply to changes in iString + + + Added Above Range, Below Range reports + + + Removed references to CubeInfo + + + A bug where the VALIDMIN,VALIDMAX were ignored was fixed; + these should always be used. + + + Added the Format option for the output file. + + + + + average + avg_sd + bandstats + + + + + + cube + input + + Single band of a cube to get statistics from + + + The file specification for the input cube. The statistics will be + calculated for one band only. The default band is one but can be + overridden using the band specifier (e.g., file.cub:3). + + + *.cub + + + + + filename + output + + Output file to contain statistics + + + No Output file will be created + + + This ascii file will contain the statistics of the individual + band. It is written in such a format that the values can be + read using the getkey program. This is useful for when developing + scripts. + + + *.txt + + + + + string + + Output Format + + + Format type for output file. Pvl format is default. + + PVL + + + + + + + boolean + + Append Output to File + + + If this option is selected, the output from the application will be appended to the file. + If it is not selected, any information in the TO file will be overwritten. + + TRUE + + + + + + + double + + Minimum DN valid to count as valid + + + No minimum DN value + + + The statistics will exclude any DN values below this value + + + + + double + + Maximum DN valid to count as valid + + + No maximum DN value + + + The statistics will exclude any DN values above this value + + + + + + + + Calculating statistics for a band in a cube + + This example shows the statistics gathered from a single band of + a cube. + + + + from=peaks.cub:3 > peaks3_stats.log + + + Running stats in the command line mode with the only parameter "FROM" + set to the third band of the cube peaks.cub. + + + + + + Output from stats + + + This is the output captured in "peaks3_stats.log" by the + redirection of standard out. + + + + + + +
    diff --git a/isis/src/base/apps/stats/tsts/Makefile b/isis/src/base/apps/stats/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/stats/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/stats/tsts/default/Makefile b/isis/src/base/apps/stats/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3a32cfc20053759d345015cbc669b075b379e01c --- /dev/null +++ b/isis/src/base/apps/stats/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = stats + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/stats.pvl > /dev/null; + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + validmin=-20 validmax=20 to=$(OUTPUT)/stats2.pvl > /dev/null; diff --git a/isis/src/base/apps/stats/tsts/format/Makefile b/isis/src/base/apps/stats/tsts/format/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..db34fc6b1c4e36f5336fa59e7f0ddb6e30bebfa6 --- /dev/null +++ b/isis/src/base/apps/stats/tsts/format/Makefile @@ -0,0 +1,9 @@ +APPNAME = stats + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/tmp.txt format=flat > /dev/null; + sed -e 's:/[a-zA-Z/0-9]*isisTruth.cub:PATH:g' $(OUTPUT)/tmp.txt > $(OUTPUT)/stats.txt; + $(RM) $(OUTPUT)/tmp.txt; diff --git a/isis/src/base/apps/std2isis/Makefile b/isis/src/base/apps/std2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/std2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/std2isis/assets/images/argb.png b/isis/src/base/apps/std2isis/assets/images/argb.png new file mode 100644 index 0000000000000000000000000000000000000000..925989f6f1e508d8023fbd63f6fdd1890ea03373 Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/images/argb.png differ diff --git a/isis/src/base/apps/std2isis/assets/images/autoGui.jpg b/isis/src/base/apps/std2isis/assets/images/autoGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dafb4f06229f7a68ec3d71d7ed0aa59e4c82533c Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/images/autoGui.jpg differ diff --git a/isis/src/base/apps/std2isis/assets/images/colorGui.jpg b/isis/src/base/apps/std2isis/assets/images/colorGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..505d90c594c479ab01f721c982ce866df9bfdec7 Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/images/colorGui.jpg differ diff --git a/isis/src/base/apps/std2isis/assets/images/gray.png b/isis/src/base/apps/std2isis/assets/images/gray.png new file mode 100644 index 0000000000000000000000000000000000000000..447fe941a36847b1def40d45537413e5dd9e6114 Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/images/gray.png differ diff --git a/isis/src/base/apps/std2isis/assets/images/grayGui.jpg b/isis/src/base/apps/std2isis/assets/images/grayGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..10e269b5c16782a18d8130851d6a77bade1fe5aa Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/images/grayGui.jpg differ diff --git a/isis/src/base/apps/std2isis/assets/images/gray_argb.png b/isis/src/base/apps/std2isis/assets/images/gray_argb.png new file mode 100644 index 0000000000000000000000000000000000000000..934d22d3f10c0c51628363aeb24881e5b2811a1a Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/images/gray_argb.png differ diff --git a/isis/src/base/apps/std2isis/assets/images/input.png b/isis/src/base/apps/std2isis/assets/images/input.png new file mode 100644 index 0000000000000000000000000000000000000000..2afaa483c96dd95b891ca79506e5cef4e5bd96a6 Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/images/input.png differ diff --git a/isis/src/base/apps/std2isis/assets/images/rgb.png b/isis/src/base/apps/std2isis/assets/images/rgb.png new file mode 100644 index 0000000000000000000000000000000000000000..a42e34324386905aa31c2a7deae6a7abff717617 Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/images/rgb.png differ diff --git a/isis/src/base/apps/std2isis/assets/thumbs/argb.png b/isis/src/base/apps/std2isis/assets/thumbs/argb.png new file mode 100644 index 0000000000000000000000000000000000000000..4aae3d756ae5e986c742062ea320241c2667e4cb Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/thumbs/argb.png differ diff --git a/isis/src/base/apps/std2isis/assets/thumbs/autoGui.jpg b/isis/src/base/apps/std2isis/assets/thumbs/autoGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..557714c6d0f86d36d6b5398d7f4958c71de0426b Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/thumbs/autoGui.jpg differ diff --git a/isis/src/base/apps/std2isis/assets/thumbs/colorGui.jpg b/isis/src/base/apps/std2isis/assets/thumbs/colorGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f53ff62f098b2df9a342c8de2e137820cfb52ddb Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/thumbs/colorGui.jpg differ diff --git a/isis/src/base/apps/std2isis/assets/thumbs/gray.png b/isis/src/base/apps/std2isis/assets/thumbs/gray.png new file mode 100644 index 0000000000000000000000000000000000000000..5f3ee127eb43c66beff1551b4f8a350a72e783ae Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/thumbs/gray.png differ diff --git a/isis/src/base/apps/std2isis/assets/thumbs/grayGui.jpg b/isis/src/base/apps/std2isis/assets/thumbs/grayGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b8fc0d6f3c28945ddb0816329b249872b3715c04 Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/thumbs/grayGui.jpg differ diff --git a/isis/src/base/apps/std2isis/assets/thumbs/gray_argb.png b/isis/src/base/apps/std2isis/assets/thumbs/gray_argb.png new file mode 100644 index 0000000000000000000000000000000000000000..8f36c53f44f2241ba3d75b64580441ea8b14f0c2 Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/thumbs/gray_argb.png differ diff --git a/isis/src/base/apps/std2isis/assets/thumbs/input.png b/isis/src/base/apps/std2isis/assets/thumbs/input.png new file mode 100644 index 0000000000000000000000000000000000000000..df4e76c14901af2065006fd8265d25591bff0f8c Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/thumbs/input.png differ diff --git a/isis/src/base/apps/std2isis/assets/thumbs/rgb.png b/isis/src/base/apps/std2isis/assets/thumbs/rgb.png new file mode 100644 index 0000000000000000000000000000000000000000..a097662050cd2a3ad5b2b68ca6c2f04a0d30c5ab Binary files /dev/null and b/isis/src/base/apps/std2isis/assets/thumbs/rgb.png differ diff --git a/isis/src/base/apps/std2isis/std2isis.cpp b/isis/src/base/apps/std2isis/std2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..155cb13d848dd3d8c1bf3337abcd21132a4fcf0e --- /dev/null +++ b/isis/src/base/apps/std2isis/std2isis.cpp @@ -0,0 +1,251 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "ProcessImport.h" +#include "SpecialPixel.h" +#include "UserInterface.h" +#include "JP2Decoder.h" +#include + +using namespace std; +using namespace Isis; + +QImage *qimage; +int line; +int band; + +//Initialize values to make special pixels invalid +double null_min = DBL_MAX; +double null_max = DBL_MIN; +double hrs_min = DBL_MAX; +double hrs_max = DBL_MIN; +double lrs_min = DBL_MAX; +double lrs_max = DBL_MIN; + +void toGrayCube (Buffer &out); +void toRGBCube (Buffer &out); +void toARGBCube (Buffer &out); + +double TestSpecial(const double pixel); + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + ProcessByLine p; + + + // Set special pixel ranges + if (ui.GetBoolean("SETNULLRANGE")) { + null_min = ui.GetDouble("NULLMIN"); + null_max = ui.GetDouble("NULLMAX"); + } + if (ui.GetBoolean("SETHRSRANGE")) { + hrs_min = ui.GetDouble("HRSMIN"); + hrs_max = ui.GetDouble("HRSMAX"); + } + if (ui.GetBoolean("SETLRSRANGE")) { + lrs_min = ui.GetDouble("LRSMIN"); + lrs_max = ui.GetDouble("LRSMAX"); + } + + qimage = new QImage(iString(ui.GetFilename("FROM"))); + + line = 0; + band = 0; + + // qimage is NULL on failure + if(qimage->isNull()) { + delete qimage; + qimage = NULL; + + // Determine if input file is a JPEG2000 file + try { + JP2Decoder *JP2_decoder; + JP2_decoder = new JP2Decoder(iString(ui.GetFilename("FROM"))); + JP2_decoder->OpenFile(); + int nsamps = JP2_decoder->GetSampleDimension(); + int nlines = JP2_decoder->GetLineDimension(); + int nbands = JP2_decoder->GetBandDimension(); + int pixelbytes = JP2_decoder->GetPixelBytes(); + bool is_signed = JP2_decoder->GetSignedData(); + delete JP2_decoder; + ProcessImport jp; + jp.SetDimensions(nsamps,nlines,nbands); + if (pixelbytes == 1) { + jp.SetPixelType(Isis::UnsignedByte); + } else if (pixelbytes == 2) { + if (is_signed) { + jp.SetPixelType(Isis::SignedWord); + } else { + jp.SetPixelType(Isis::UnsignedWord); + } + } else { + throw iException::Message(iException::User, + "The file [" + ui.GetFilename("FROM") + "] contains unsupported data type.", + _FILEINFO_); + } + jp.SetInputFile(iString(ui.GetFilename("FROM"))); + jp.SetOutputCube("TO"); + jp.SetOrganization(ProcessImport::JP2); + jp.StartProcess(); + jp.EndProcess(); + } + catch (Isis::iException &e) { + throw iException::Message(iException::User, + "The file [" + ui.GetFilename("FROM") + "] does not contain a recognized image format.", + _FILEINFO_); + } + } else { + + string mode = ui.GetString("MODE"); + if (mode == "AUTO") { + if (qimage->isGrayscale()) + mode = "GRAYSCALE"; + else if (qimage->hasAlphaChannel()) + mode = "ARGB"; + else + mode = "RGB"; + } + + if (mode == "GRAYSCALE") { + Cube *outCube = p.SetOutputCube("TO", qimage->width(), qimage->height()); + Pvl *label = outCube->Label(); + PvlGroup bandBin ("BandBin"); + PvlKeyword name ("Name"); + name += "Gray"; + bandBin += name; + label->AddGroup(bandBin); + p.StartProcess(toGrayCube); + } + else if (mode == "RGB") { + Cube *outCube = p.SetOutputCube("TO", qimage->width(), qimage->height(), 3); + Pvl *label = outCube->Label(); + PvlGroup bandBin ("BandBin"); + PvlKeyword name ("Name"); + name += "Red"; + name += "Green"; + name += "Blue"; + bandBin += name; + label->AddGroup(bandBin); + p.StartProcess(toRGBCube); + } + else { + Cube *outCube = p.SetOutputCube("TO", qimage->width(), qimage->height(), 4); + Pvl *label = outCube->Label(); + PvlGroup bandBin ("BandBin"); + PvlKeyword name ("Name"); + name += "Red"; + name += "Green"; + name += "Blue"; + name += "Alpha"; + bandBin += name; + label->AddGroup(bandBin); + p.StartProcess(toARGBCube); + } + + delete qimage; + qimage = NULL; + p.EndProcess(); + } +} + +void toGrayCube (Buffer &out) { + for(int sample = 0; sample < out.SampleDimension(); sample ++) { + double pixel = qGray(qimage->pixel(sample, line)); + out[sample] = TestSpecial(pixel); + } + + line ++; +} + +void toRGBCube (Buffer &out) { + if (band == 0) { + for(int sample = 0; sample < out.SampleDimension(); sample ++) { + double pixel = qRed(qimage->pixel(sample, line)); + out[sample] = TestSpecial(pixel); + } + } + else if (band == 1) { + for(int sample = 0; sample < out.SampleDimension(); sample ++) { + double pixel = qGreen(qimage->pixel(sample, line)); + out[sample] = TestSpecial(pixel); + } + } + else if (band == 2) { + for(int sample = 0; sample < out.SampleDimension(); sample ++) { + double pixel = qBlue(qimage->pixel(sample, line)); + out[sample] = TestSpecial(pixel); + } + } + else { + string msg = "RGB cubes must have exactly three bands."; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + line++; + if (line == qimage->height()) { + line = 0; + band++; + } +} + +void toARGBCube (Buffer &out) { + if (band == 0) { + for(int sample = 0; sample < out.SampleDimension(); sample ++) { + double pixel = qRed(qimage->pixel(sample, line)); + out[sample] = TestSpecial(pixel); + } + } + else if (band == 1) { + for(int sample = 0; sample < out.SampleDimension(); sample ++) { + double pixel = qGreen(qimage->pixel(sample, line)); + out[sample] = TestSpecial(pixel); + } + } + else if (band == 2) { + for(int sample = 0; sample < out.SampleDimension(); sample ++) { + double pixel = qBlue(qimage->pixel(sample, line)); + out[sample] = TestSpecial(pixel); + } + } + else if (band == 3) { + for(int sample = 0; sample < out.SampleDimension(); sample ++) { + double pixel = qAlpha(qimage->pixel(sample, line)); + out[sample] = TestSpecial(pixel); + } + } + else { + string msg = "ARGB cubes must have exactly four bands."; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + line++; + if (line == qimage->height()) { + line = 0; + band++; + } +} + +/** + * Tests the pixel. If it is valid it will return the dn value, + * otherwise it will return the Isis special pixel value that + * corresponds to it + * + * @param pixel The double precision value that represents a + * pixel. + * @return double The double precision value representing the + * pixel will return as a valid dn or changed to an isis + * special pixel. + */ + double TestSpecial(const double pixel){ + if (pixel <= null_max && pixel >= null_min){ + return Isis::NULL8; + } + else if (pixel <= hrs_max && pixel >= hrs_min){ + return Isis::HIGH_REPR_SAT8; + } + else if (pixel <= lrs_max && pixel >= lrs_min){ + return Isis::LOW_REPR_SAT8; + } + else { + return pixel; + } + } diff --git a/isis/src/base/apps/std2isis/std2isis.xml b/isis/src/base/apps/std2isis/std2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..516b80f52527e827deac6ad591bfa5a0b8fd36d1 --- /dev/null +++ b/isis/src/base/apps/std2isis/std2isis.xml @@ -0,0 +1,455 @@ + + + + + + Imports a cube from PNG, JPEG, JP2, BMP or TIFF format + + + + This program will import several standard image formats to an Isis cube. + The input image formats may include PNG, JPEG, JP2, TIFF, BMP, and GIF. Not all + formats are available as the program implementation depends on the Qt + library by TrollTech. This is not true of JPEG2000 files (JP2). It has + support in the ISIS3 library. By default, the number of bands in the output cube + will be one, three, and four when the input image is all gray, RGB, + and RGB with an alpha channel, respectively. The user can, however, specify + the color mode manually. The JP2 file can have any number of bands up to + 16384. The output from a JP2 file will be a multi-spectral ISIS3 image file. + + + + + Original version + + + Added special pixel ranges and updated example images + + + Added support for RGB and ARGB imports. + + + Added AUTO option for automatically determining MODE. + + + Changed example and added two new examples. + + + Added support for JPEG2000 files. + + + + + Import and Export + + + + + isis2std + + + + + + + filename + input + + Input image file to import + + + Use this parameter to select the filename to import. + + + *.PNG *.JPG* .JPEG *.BMP *.TIF *.TIFF *.GIF *.JP2 + + + + + cube + output + + Output image + + + Use this parameter to specify the name of the output cube. + + real + + + + + + string + AUTO + Mode for determining color model + + This parameter specifies the image mode for the output cube. If + GRAYSCALE, a single one-band cube will be created. If RGB, a + three-band cube is created. Finally, if ARGB is selected, then + a four-band cube will be created where the four bands correspond + to first Red, second Green, third Blue, and last Alpha. + + + + + + + + + + + + + boolean + + NO + + Create special pixel values + + If this option is used input raw pixels below minimum and + above maximum will be converted to LRS and HRS respectively. Otherwise + pixels in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit real will + cause 0 and 255 to be actual values. If left as 8-bit then 0 will + be NULL and 255 will be HRS. + + + NULLMIN + NULLMAX + + + + + double + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + SETNULLRANGE + + + + double + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + SETNULLRANGE + + + + + boolean + + NO + + Create special pixel values + + If this option is used input raw pixels below minimum and + above maximum will be converted to LRS and HRS respectively. Otherwise + pixels in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit real will + cause 0 and 255 to be actual values. If left as 8-bit then 0 will + be NULL and 255 will be HRS. + + + HRSMIN + HRSMAX + + + + + double + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + SETHRSRANGE + + + + double + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + SETHRSRANGE + + + + + boolean + + NO + + Create special pixel values + + If this option is used input raw pixels below minimum and + above maximum will be converted to LRS and HRS respectively. Otherwise + pixels in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit real will + cause 0 and 255 to be actual values. If left as 8-bit then 0 will + be NULL and 255 will be HRS. + + + LRSMIN + LRSMAX + + + + + double + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + SETLRSRANGE + + + + double + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + SETLRSRANGE + + + + + + + + + Converting an image to an Isis Cube in Automatic mode + + + This example will show the conversion from a color PNG image to a cube, + automatically determining the color mode. Here, the output image will + be a four-band ARGB cube, because the input image is both in color, and + has an alpha channel. + + + from=input.png to=argb.cub + + Convert the PNG to an Isis Cube, with the default option of + automatically determining the color mode + + + + + + + + Example GUI + + + Screenshot of the GUI for std2isis, ready to convert the image + input.png to the Isis Cube argb.cub, with mode left at its default + of AUTOMATIC. + + + + + + + + + Input Image + + The input image, a color PNG in this example. + + + + + + + + Output Isis Cube with Grayscale + + The four-band ARGB output image viewed in black-and-white with a + grayscale. + + + + + Output Isis Cube with RGB + + The same four-band ARGB output image viewed in color with RGB + filtering (Band 1 = Red, Band 2 = Green, Band 3 = Blue). Note that + the image here appears brighter than the original, because qview has + auto-stretched the DN values, and can be adjusted back with qview's + "stretch" tool. The actual data, however, has not been changed. + + + + + Output Isis Cube with RGA + + The same four-band ARGB output image viewed in color with RGB + filtering as in the previous image, but here Band 4 (the alpha + channel) is viewed through the Blue filter. + + + + + + + + + Converting an image to an Isis Cube in Grayscale mode + + + This example will show the conversion from a color PNG image to a cube, + with the color mode set to GRAYSCALE, meaning that the output image will + be a single-band black-and-white cube. + + + from=input.png to=gray.cub mode=grayscale + + Convert the image input.png to the Isis Cube gray.cub. In order to + get a single-band black-and-white image, we set the mode equal to + GRAYSCALE. + + + + + + + + Example GUI + + + Screenshot of the GUI for std2isis, ready to convert the image + input.png to the Isis Cube gray.cub with mode set to GRAYSCALE. + + + + + + + + + Input Image + + The input image, in this example, the same color PNG from the + previous example. + + + + + + + + Output Isis Cube + + The is the output Isis Cube peaks.cub generated from this example. + + + + + + + + + Converting an image to an Isis Cube in RGB mode + + + This example will show the conversion from a color PNG image to a cube, + with the color mode set to RGB, meaning that the output image will + be a three-band color cube. + + + from=input.png to=rgb.cub mode=rgb + + Convert the image input.png to the Isis Cube rgb.cub. In order to + get a three-band color image, we set the mode equal to + RGB. + + + + + + + + Example GUI + + + Screenshot of the GUI for std2isis, ready to convert the image + input.png to the Isis Cube rgb.cub with mode set to RGB. + + + + + + + + + Input Image + + The input image, in this example, the same color PNG from the + first example. + + + + + + + + Output Isis Cube with Grayscale + + The three-band RGB output image viewed in black-and-white with a + grayscale. + + + + + Output Isis Cube with RGB + + The same three-band RGB output image viewed in color with RGB + filtering (Band 1 = Red, Band 2 = Green, Band 3 = Blue). Once + again, the output image appears to be brighter than the original due + to qview's auto-stretching, but can be adjusted in qview with the + "stretch" tool. + + + + + + + diff --git a/isis/src/base/apps/std2isis/tsts/Makefile b/isis/src/base/apps/std2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/std2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/std2isis/tsts/argb/Makefile b/isis/src/base/apps/std2isis/tsts/argb/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..085fee43238527aded6ea69c2e51d3a6a89e1302 --- /dev/null +++ b/isis/src/base/apps/std2isis/tsts/argb/Makefile @@ -0,0 +1,8 @@ +APPNAME = std2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/in.jpg TO=$(OUTPUT)/out.cub \ + mode=argb \ + > /dev/null; diff --git a/isis/src/base/apps/std2isis/tsts/default/Makefile b/isis/src/base/apps/std2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3876f953934c78be37e58a9867abd2e5ca14cfb9 --- /dev/null +++ b/isis/src/base/apps/std2isis/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = std2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/in.png TO=$(OUTPUT)/out.cub \ + > /dev/null; diff --git a/isis/src/base/apps/std2isis/tsts/grayscale/Makefile b/isis/src/base/apps/std2isis/tsts/grayscale/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b0dbe3194608d8bd037ba76e49bb4973752165fc --- /dev/null +++ b/isis/src/base/apps/std2isis/tsts/grayscale/Makefile @@ -0,0 +1,8 @@ +APPNAME = std2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/in.png TO=$(OUTPUT)/out.cub \ + mode=grayscale \ + > /dev/null; diff --git a/isis/src/base/apps/std2isis/tsts/special/Makefile b/isis/src/base/apps/std2isis/tsts/special/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1f8abd063b70eaa72b6e53ef4e607a3db7ba6795 --- /dev/null +++ b/isis/src/base/apps/std2isis/tsts/special/Makefile @@ -0,0 +1,10 @@ +APPNAME = std2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/in.png TO=$(OUTPUT)/out.cub \ + mode=grayscale \ + setnullrange=yes nullmin=100 nullmax=240 sethrsrange=yes \ + hrsmin=200 hrsmax=260 setlrsrange=yes lrsmin=0 lrsmax=100 \ + > /dev/null; diff --git a/isis/src/base/apps/stretch/Makefile b/isis/src/base/apps/stretch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/stretch/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/stretch/assets/image/binStrGui.jpg b/isis/src/base/apps/stretch/assets/image/binStrGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b5299eaac7576ca4afbdd78244588af850c997f4 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/binStrGui.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/binaryStretchChart.jpg b/isis/src/base/apps/stretch/assets/image/binaryStretchChart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7cd9dd30ed455e9266ff00aae32ff51000a9e069 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/binaryStretchChart.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/darkStrGui.jpg b/isis/src/base/apps/stretch/assets/image/darkStrGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c5ab1e65fc03979690f4f598795a62b1d9a139c0 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/darkStrGui.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/darkStretchChart.jpg b/isis/src/base/apps/stretch/assets/image/darkStretchChart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6fcee8d82ec52d309965639a12759f6b3a133ab8 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/darkStretchChart.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/invStrGui.jpg b/isis/src/base/apps/stretch/assets/image/invStrGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6027d5cf20b5d1abd5f7d188dad0a7522d557791 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/invStrGui.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/inverseStretchChart.jpg b/isis/src/base/apps/stretch/assets/image/inverseStretchChart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..49301eefe796710d4b323fe2870ae1478c1e7b92 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/inverseStretchChart.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/lightStrGui.jpg b/isis/src/base/apps/stretch/assets/image/lightStrGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e53a9ebda3b83c8eef133b4a55ec90780c7c6e25 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/lightStrGui.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/lightStretchChart.jpg b/isis/src/base/apps/stretch/assets/image/lightStretchChart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c0294d813a09572d0fd2eedd80695c799c9784f4 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/lightStretchChart.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/peaks.jpg b/isis/src/base/apps/stretch/assets/image/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b0ae6226b663d73379a35cb4376afe7750711943 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/peaks.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/specPixStrGui.jpg b/isis/src/base/apps/stretch/assets/image/specPixStrGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b98a21e16b0dbdfac5f328e50205288e876340fb Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/specPixStrGui.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/stretchBin.jpg b/isis/src/base/apps/stretch/assets/image/stretchBin.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a87a42ccbef671cfb24e5e5db5b8ac4557146c7f Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/stretchBin.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/stretchDark.jpg b/isis/src/base/apps/stretch/assets/image/stretchDark.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1670d705aca3b92294e7428610d2d7b0a61ed6d4 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/stretchDark.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/stretchInv.jpg b/isis/src/base/apps/stretch/assets/image/stretchInv.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b6c0f8b64de3b4527a03c2c568a087e38b788f64 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/stretchInv.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/stretchLight.jpg b/isis/src/base/apps/stretch/assets/image/stretchLight.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1265a7a90a2233c34de678f1e2047e657f1709aa Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/stretchLight.jpg differ diff --git a/isis/src/base/apps/stretch/assets/image/stretchSpecPix.jpg b/isis/src/base/apps/stretch/assets/image/stretchSpecPix.jpg new file mode 100644 index 0000000000000000000000000000000000000000..998ad84062315ea2e9b80602db910334702740c8 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/image/stretchSpecPix.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/binStrGui.jpg b/isis/src/base/apps/stretch/assets/thumb/binStrGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8f3ceb2e271f01216f496b49c631742326631604 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/binStrGui.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/binaryStretchChart.jpg b/isis/src/base/apps/stretch/assets/thumb/binaryStretchChart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..98b833344297c04654d1400ce0afd0010e474069 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/binaryStretchChart.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/darkStrGui.jpg b/isis/src/base/apps/stretch/assets/thumb/darkStrGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..60a4dfc224981dd958818ffae37c1473e35c2a9c Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/darkStrGui.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/darkStretchChart.jpg b/isis/src/base/apps/stretch/assets/thumb/darkStretchChart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ba2916e189b29a27c4f60c95023fd2a8ef5a2f31 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/darkStretchChart.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/invStrGui.jpg b/isis/src/base/apps/stretch/assets/thumb/invStrGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9974542ed4f3eae12499d8edc0f1605f9593e5c8 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/invStrGui.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/inverseStretchChart.jpg b/isis/src/base/apps/stretch/assets/thumb/inverseStretchChart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..97e4d91c119d63bd05a9234b1804f8d467ebcf88 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/inverseStretchChart.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/lightStrGui.jpg b/isis/src/base/apps/stretch/assets/thumb/lightStrGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c39712dc5295b54f72eecd20ac5ea2b357ec1f16 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/lightStrGui.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/lightStretchChart.jpg b/isis/src/base/apps/stretch/assets/thumb/lightStretchChart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..574a3481ef7b00a24061764636b719401146f5a9 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/lightStretchChart.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/peaks.jpg b/isis/src/base/apps/stretch/assets/thumb/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db35c783931b3d40113de16690ce299fddc8187c Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/peaks.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/specPixStrThumb.jpg b/isis/src/base/apps/stretch/assets/thumb/specPixStrThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c066d96115d85f9087406053635e2f2d31d08279 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/specPixStrThumb.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/stretchBin.jpg b/isis/src/base/apps/stretch/assets/thumb/stretchBin.jpg new file mode 100644 index 0000000000000000000000000000000000000000..73820d9867da3866a036419b2af8c4c5b76993ab Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/stretchBin.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/stretchDark.jpg b/isis/src/base/apps/stretch/assets/thumb/stretchDark.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c6c3d066facd96bc3ef73acff01852c2bdb26a25 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/stretchDark.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/stretchInv.jpg b/isis/src/base/apps/stretch/assets/thumb/stretchInv.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7b5c0c25d22f8344f62812994e397e5746174af0 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/stretchInv.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/stretchLight.jpg b/isis/src/base/apps/stretch/assets/thumb/stretchLight.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a5a41c568c7566bf127477683060aa1310bcada0 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/stretchLight.jpg differ diff --git a/isis/src/base/apps/stretch/assets/thumb/stretchSpecPix.jpg b/isis/src/base/apps/stretch/assets/thumb/stretchSpecPix.jpg new file mode 100644 index 0000000000000000000000000000000000000000..998ad84062315ea2e9b80602db910334702740c8 Binary files /dev/null and b/isis/src/base/apps/stretch/assets/thumb/stretchSpecPix.jpg differ diff --git a/isis/src/base/apps/stretch/stretch.cpp b/isis/src/base/apps/stretch/stretch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..044fc91e320de7d1c19cd54694b646ddbdc92e94 --- /dev/null +++ b/isis/src/base/apps/stretch/stretch.cpp @@ -0,0 +1,85 @@ +#include "Isis.h" +#include "TextFile.h" +#include "Statistics.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "Stretch.h" +#include "PvlGroup.h" +#include "PvlKeyword.h" + +using namespace std; +using namespace Isis; + +void stretch (Buffer &in, Buffer &out); +Stretch str; +Statistics stats; + +void IsisMain() { + ProcessByLine p; + Cube* inCube = p.SetInputCube("FROM"); + + UserInterface &ui = Application::GetUserInterface(); + + string pairs; + + // first just get the pairs from where ever and worry about + // whether they are dn values or %'s later + if (ui.GetBoolean("READFILE")) { + Filename pairsFileName = ui.GetFilename("INPUTFILE"); + TextFile pairsFile; + pairsFile.SetComment("#"); + pairsFile.Open(pairsFileName.Expanded()); + + // concat all non-comment lines into one string (pairs) + string line = ""; + while (pairsFile.GetLine(line, true)) { + pairs += " " + line; + } + pairs += line; + } + else { + if (ui.WasEntered("PAIRS")) + pairs = ui.GetString("PAIRS"); + } + + if (ui.GetBoolean("USEPERCENTAGES")) + str.Parse(pairs, inCube->Histogram()); + else + str.Parse(pairs); + + // Setup new mappings for special pixels if necessary + if (ui.WasEntered("NULL")) + str.SetNull(StringToPixel(ui.GetString("NULL"))); + if (ui.WasEntered("LIS")) + str.SetLis(StringToPixel(ui.GetString("LIS"))); + if (ui.WasEntered("LRS")) + str.SetLrs(StringToPixel(ui.GetString("LRS"))); + if (ui.WasEntered("HIS")) + str.SetHis(StringToPixel(ui.GetString("HIS"))); + if (ui.WasEntered("HRS")) + str.SetHrs(StringToPixel(ui.GetString("HRS"))); + + p.SetOutputCube ("TO"); + + // Start the processing + p.StartProcess(stretch); + p.EndProcess(); + + PvlKeyword dnPairs = PvlKeyword("StretchPairs"); + dnPairs.AddValue(str.Text()); + + PvlGroup results = PvlGroup("Results"); + results.AddKeyword(dnPairs); + + Application::Log(results); + +} + +// Line processing routine +void stretch (Buffer &in, Buffer &out) +{ + for (int i=0; i + + + + + Remaps pixel values in a cube + + + + This program stretchs or remaps pixels values in a cube. Note that the same + stretch is applied to all bands within the cube. The underlying method for + remapping pixels is defined by a set of stretch pairs and is best described + using an example: +
    +      0:0
    +      255:1
    +    
    + A stretch pair is two numbers separated by a colon. In this case, 0:0 and + 255:1 comprise two stretch pairs. A pair is used to identify the mapping + of input pixels to output pixels where the colon is a delimiter + (i.e., input:output). Our first pair indicates input pixel values + of 0 will be mapped to an output 0, while the second pair indicates input + pixel values of 255 will be mapped to 1. All inputs between 0 and 255 will + be mapped linearly (e.g., 127.5 will be mapped to 0.5). Therefore, + the output cube + will only have pixel values between 0 and 1. Those input pixels below + 0 will be mapped to LRS and above 255 to HRS. This mapping to special pixels + can be overridden. Because multiple pairs are allowed, + many different types of remappings can be accomplished. For example: +
    +      Inverse Stretch
    +      0:255
    +      255:0
    +
    +      Piece-wise Linear Stretch
    +      20:0.0
    +      50:0.5
    +      125:1.0
    +
    +      Saw-tooth Stretch
    +      0:0.0
    +      50:1.0
    +      100:0.0
    +      200:1.0
    +
    +      Binary stretch
    +      0:0.0
    +      49.9999:0.0
    +      50:1.0.0
    +      79.9999:1.0
    +      80:0.0
    +      255:0.0
    +    
    + If you are having difficulty visualizing these stretches simply plot the + input:output pairs on graph paper and connect the dots or see some + of the examples. Note that the + input value of each pair is in ascending order. As a reminder, + all input pixel values less + than the input value for the first pair are mapped to LRS. Likewise, + all pixel values greater than the input value for the last pair are mapped + to HRS. +
    + + + Utility + + + + + specpix + + + + + + Original version + + + + Ported to Isis 3.0 + + + + Add examples + + + + Make images smaller. Adjust binary stretch example. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Made changes to application test truth files to reflect -O1 optimization + + + Modified filename parameters to be cube parameters where necessary + + + Fixed application test + + + Modified stretch parameters (except PAIRS) to accept string instead of + double so that special pixels may be set to other special pixel values. + + + Users can pass a file containing stretch pairs as well as inputing them + manually as before. Also, the input side of stretch pairs can optionally + be percentages instead of dn values. + + + Added support for stretch files not ending in a newline. Also did some + code refactoring to eliminate duplicate code. + + + + + + + cube + input + + Input cube + + + Input cube to stretch + + + *.cub + + + + + cube + real + output + + Output stretched cube + + + The resultant stretched cube + + + + + + + boolean + False + Percentage mode for pairs + + If true the input side of the pairs are interpreted as percentages. + The dn value which is used is the dn value at the specified percentage + of the input cube's histogram + + + + + boolean + False + Input pairs from file + + Selects the method of pair data input. If true then read pairs from a + file. Otherwise read the stretch pairs from the "PAIRS" parameter + + + INPUTFILE + + + PAIRS + + + + + string + Stretch pairs manual input + + A string must be entered in the form of + + Where the input values are in ascending order (increasing). There is + no limit to the number of pairs although each pair must be separated + by a space. The stretch that is entered will be applied to all bands + in the cube. By default "No Stretch" is applied which allows users + to remap only special pixels if desired. + + + No Stretch + + + + + filename + input + The file name where pairs are stored + + Read pairs from this file instead of entering them manually. Commented + lines are ignored and defined as beginning with a '#'. Pairs must be + separated by white space which may be new lines. +
    +            # example 1 of a file containing stretch pairs
    +            0:0 1:10 15:255
    +          
    +
    +            # example 2 of a file containing stretch pairs
    +            0:0
    +            1:10
    +            # this is a comment inside a file containing stretch pairs
    +            15:255
    +          
    +
    +
    + + + string + + Replace NULL pixels with another special pixel value or a double value + + + Double or alternate special pixel value used to replace all NULL + special pixels. For example all NULL pixels can be replaced with + -100.0. By default, the NULL special pixels will be left unchanged. + + + NULL + + + + + string + + Replace LIS pixels with another special pixel value or a double value + + + Double or alternate special pixel value used to replace all LIS special pixels. For example + all LIS pixels can be replaced with 0.0. By default, the LIS + special pixels will be left unchanged. + + + + LIS + + + + + string + + Replace LRS pixels with another special pixel value or a double value + + + Double or alternate special pixel value used to replace all LRS special pixels. For example + all LRS pixels can be replaced with 0.0. By default, the LRS + special pixels will be left unchanged. + + + LRS + + + + + string + + Replace HIS pixels with another special pixel value or a double value + + + Double or alternate special pixel value used to replace all HIS special pixels. For example + all HIS pixels can be replaced with 500.0. By default, the HIS + special pixels will be left unchanged. + + + + HIS + + + + + string + + Replace HRS pixels with another special pixel value or a double value + + + Double or alternate special pixel value used to replace all HRS special pixels. For example + all HRS pixels can be replaced with 500.0. By default, the HRS + special pixels will be left unchanged. + + + HRS + + +
    + +
    + + + + run stretch + + This example shows a stretch operation using a binary type of stretch. + + + f=../IN/peaks.cub:4 t=OUT/stretchBin p=\"0.:0 101.9:0 102.:255 200.:255 200.1:0. 255.:0.\" + + + stretch a Terra image. Use binary type of stretch. + + + + + + Input image for stretch + This is the input image for the stretch examples. + + + FROM + + + Explanation image for stretch + This is a graph demonstrating the binary stretch. + + + + + + + + Output image for stretch + This is the output image that results from a binary type of stretch + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a stretch operation on the input image. + + + + + + + + run stretch + + This example shows the result of stretching dark data. + + + f=../IN/peaks.cub:4 t=OUT/stretchDark p=\"0.:0 50.:255 255.:255.\" + + + stretch the dark data in a Terra image. + + + + + + Input image for stretch + This is the input image for the stretch examples. + + + FROM + + + Explanation image for stretch + This is a graph demonstrating dark data enhancement. + + + + + + + + Output image for stretch + This is the output image that results from a dark data enhancement + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a stretch operation on the input image. + + + + + + + + run stretch + + This example shows the result of stretching light data. + + + f=../IN/peaks.cub:4 t=OUT/stretchLight p=\"0.:0 84.:0 255.:255.\" + + + stretch the light data in a Terra image. + + + + + + Input image for stretch + This is the input image for the stretch examples. + + + FROM + + + Explanation image for stretch + This is a graph demonstrating light data enhancement. + + + + + + + + Output image for stretch + This is the output image that results from a light data enhancement + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a stretch operation on the input image. + + + + + + + + run stretch + + This example shows a stretch operation using a inverse type of stretch. + + + f=../IN/peaks.cub:4 t=OUT/stretchInv p=\"0.:255 255.:0.\" + + + stretch a Terra image. Use inverse type of stretch. + + + + + + Input image for stretch + This is the input image for the stretch examples. + + + FROM + + + Explanation image for stretch + This is a graph demonstrating the inverse stretch. + + + + + + + + Output image for stretch + This is the output image that results from an inverse type of stretch + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform an inverse stretch operation on the input image. + + + + + + + + run stretch + + This example shows how to input non-double parameters for the special + pixel values. + + + f=peaks.cub:4 t=stretch NULL=lis Lis=LR Lr=hi his=Hr + Hr=n + + + stretch a Terra image. Input non-double parameters. + + + + + + Input image for stretch + This is the input image for the stretch examples. + + + FROM + + + + + + Output image for stretch + This is the output image that results from swapping + special pixel values. Notice that there is no visible change since + all special pixel values have the same value. + + + TO + + + + + + + Example Gui + Screenshot of GUI with non-double values filled in to + the special pixel parameters. + + + + + + + +
    diff --git a/isis/src/base/apps/stretch/tsts/Makefile b/isis/src/base/apps/stretch/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/stretch/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/stretch/tsts/case01/Makefile b/isis/src/base/apps/stretch/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b158f6d3391544ee3e1eb0dd1845968229b50105 --- /dev/null +++ b/isis/src/base/apps/stretch/tsts/case01/Makefile @@ -0,0 +1,13 @@ +APPNAME = stretch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/stretchTruth1.cub \ + pairs="0:255 255:0" \ + null=500 \ + lis=700 \ + lrs=800 \ + his=900 \ + hrs=1000 > /dev/null; diff --git a/isis/src/base/apps/stretch/tsts/case02/Makefile b/isis/src/base/apps/stretch/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cddf694f2a3f4eb91440386bd3ed9ebeb23696cb --- /dev/null +++ b/isis/src/base/apps/stretch/tsts/case02/Makefile @@ -0,0 +1,12 @@ +APPNAME = stretch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth2.cub \ + to=$(OUTPUT)/stretchTruth2.cub \ + null="hrs" \ + lis="NULL" \ + lrs="Lis" \ + his="lRs" \ + hrs="HiS" > /dev/null; diff --git a/isis/src/base/apps/stretch/tsts/case03/Makefile b/isis/src/base/apps/stretch/tsts/case03/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a7d22b5e7877b57d78ce431cd9b91459b1515557 --- /dev/null +++ b/isis/src/base/apps/stretch/tsts/case03/Makefile @@ -0,0 +1,12 @@ +APPNAME = stretch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/stretchTruth2.cub \ + to=$(OUTPUT)/stretchTruth3.cub \ + null="HRS" \ + lis="N" \ + lrs="LIS" \ + his="LRS" \ + hrs="HIS" > /dev/null; diff --git a/isis/src/base/apps/stretch/tsts/readfile/Makefile b/isis/src/base/apps/stretch/tsts/readfile/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8ed5a5049e220eb49f2cff227c0a41fbcbe97771 --- /dev/null +++ b/isis/src/base/apps/stretch/tsts/readfile/Makefile @@ -0,0 +1,14 @@ +APPNAME = stretch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/peaks.cub \ + to=$(OUTPUT)/stretchTruthFile.cub \ + r=true \ + i=$(INPUT)/pairsFile \ + null=500 \ + lis=700 \ + lrs=800 \ + his=900 \ + hrs=1000 > /dev/null; diff --git a/isis/src/base/apps/svfilter/Makefile b/isis/src/base/apps/svfilter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/svfilter/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/svfilter/assets/image/peaks.jpg b/isis/src/base/apps/svfilter/assets/image/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b0ae6226b663d73379a35cb4376afe7750711943 Binary files /dev/null and b/isis/src/base/apps/svfilter/assets/image/peaks.jpg differ diff --git a/isis/src/base/apps/svfilter/assets/image/svfilter.sd.jpg b/isis/src/base/apps/svfilter/assets/image/svfilter.sd.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4c018c5b040ce02aed56141e1c6c8b6ae2c6a603 Binary files /dev/null and b/isis/src/base/apps/svfilter/assets/image/svfilter.sd.jpg differ diff --git a/isis/src/base/apps/svfilter/assets/image/svfilter.var.jpg b/isis/src/base/apps/svfilter/assets/image/svfilter.var.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df15af504d11953bab6476c45381ef14b5b3b9d6 Binary files /dev/null and b/isis/src/base/apps/svfilter/assets/image/svfilter.var.jpg differ diff --git a/isis/src/base/apps/svfilter/assets/image/svfilterSdGui.jpg b/isis/src/base/apps/svfilter/assets/image/svfilterSdGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a062493fbc9f1719d22ce523cab5ff2be9c1493f Binary files /dev/null and b/isis/src/base/apps/svfilter/assets/image/svfilterSdGui.jpg differ diff --git a/isis/src/base/apps/svfilter/assets/image/svfilterVarGui.jpg b/isis/src/base/apps/svfilter/assets/image/svfilterVarGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2fd626e80bcfbc8b2abc05c2e9cec54b92306393 Binary files /dev/null and b/isis/src/base/apps/svfilter/assets/image/svfilterVarGui.jpg differ diff --git a/isis/src/base/apps/svfilter/assets/thumb/peaks.jpg b/isis/src/base/apps/svfilter/assets/thumb/peaks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db35c783931b3d40113de16690ce299fddc8187c Binary files /dev/null and b/isis/src/base/apps/svfilter/assets/thumb/peaks.jpg differ diff --git a/isis/src/base/apps/svfilter/assets/thumb/svfilter.sd.jpg b/isis/src/base/apps/svfilter/assets/thumb/svfilter.sd.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c476633ee60f9e599e9bd8ba6df22ca17cf931bc Binary files /dev/null and b/isis/src/base/apps/svfilter/assets/thumb/svfilter.sd.jpg differ diff --git a/isis/src/base/apps/svfilter/assets/thumb/svfilter.var.jpg b/isis/src/base/apps/svfilter/assets/thumb/svfilter.var.jpg new file mode 100644 index 0000000000000000000000000000000000000000..de73a1deabfa47329670dbf1247011545820820e Binary files /dev/null and b/isis/src/base/apps/svfilter/assets/thumb/svfilter.var.jpg differ diff --git a/isis/src/base/apps/svfilter/assets/thumb/svfilterSdGui.jpg b/isis/src/base/apps/svfilter/assets/thumb/svfilterSdGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3ef508b0743e155420b5866c960df1fdf661ebcf Binary files /dev/null and b/isis/src/base/apps/svfilter/assets/thumb/svfilterSdGui.jpg differ diff --git a/isis/src/base/apps/svfilter/assets/thumb/svfilterVarGui.jpg b/isis/src/base/apps/svfilter/assets/thumb/svfilterVarGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9062405d0cfe0a5b8c111bb9886bfb4bc8de2252 Binary files /dev/null and b/isis/src/base/apps/svfilter/assets/thumb/svfilterVarGui.jpg differ diff --git a/isis/src/base/apps/svfilter/svfilter.cpp b/isis/src/base/apps/svfilter/svfilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc6574d063c9611daef38a579169f9ebeb465457 --- /dev/null +++ b/isis/src/base/apps/svfilter/svfilter.cpp @@ -0,0 +1,55 @@ +#include "Isis.h" +#include "ProcessByQuickFilter.h" +#include "UserInterface.h" + +using namespace std; +using namespace Isis; + +// Globals and prototypes +bool propagate; +bool stdDev; +void svfilter (Buffer &in, Buffer &out, QuickFilter &filter); + +// The svfilter main routine +void IsisMain() { + ProcessByQuickFilter p; + + // Open the input cube + p.SetInputCube("FROM"); + + // Setup the output cube + p.SetOutputCube("TO"); + + // Find out how to handle special pixels + UserInterface &ui = Application::GetUserInterface(); + propagate = ui.GetBoolean ("PROPAGATE"); + string filt = ui.GetString ("FILTER"); + stdDev = false; + if (filt == "STDDEV") stdDev = true; + + // Process each line + p.StartProcess(svfilter); // Line processing function + p.EndProcess(); // Cleanup +} + +// Line processing routine +void svfilter (Buffer &in, Buffer &out, QuickFilter &filter) { + for (int i=0; i + + + + + Apply a variance or standard deviation filter to a cube + + + + This program applies either a variance or standard deviation filter to a + cube. The standard deviation filter is simply the square root of the + variance and is selected by setting the FILTER parameter to STDDEV. + + + + Filters + + + + + lowpass + highpass + trimfilter + divfilter + noisfilter + + + + + + Original version + + + + Ported to Isis 3.0 + + + + Fixed bug which disallowed the standard deviation filter + + + + Add examples. + + + + Make images smaller. + + + + Fixed problem with isiscvs not checking in the thumb and image directories. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + + + + boxfilter + + + + + + cube + input + + Input file + + + Input cube to filter + + + *.cub + + + + cube + real + output + + Output svfilter cube + + + The resultant filtered cube + + + + + + + string + VARIANCE + + Filter type + + + The output of the filter operation is either the variance value or + the standard deviation value. + + + + + + + + + + + integer + + Number of samples in boxcar + + + + This is the total number of samples in the boxcar. + It must be odd and can not exceed twice the number of samples + in the cube. In general, the size of the boxcar does not + cause the program to operate significantly slower. + + + + + 1 + + + + integer + + Number of lines in boxcar + + + + This is the total number of lines in the boxcar. + It must be odd and can not exceed twice the number of lines + in the cube. In general, the size of the boxcar does not + cause the program to operate significantly + slower. + + + + + 1 + + + + + + double + + Valid minimum pixel + + + Valid minimum pixel value that will be used in boxcar computation. If + a pixel value is less than LOW then it will not be used when + computing boxcar statistics. + + + Use all pixels + + + HIGH + + + + + double + + Valid maximum pixel + + + Valid maximum pixel value that will be used in boxcar computation. If + a pixel value is greater than HIGH then it will not be used when + computing boxcar statistics. + + + Use all pixels + + + LOW + + + + + integer + + Minimum boxcar pixel count + + + This is the minimum number of valid pixels which must occur inside the + NxM boxcar for filtering to occur. For example, 3x5 boxcar has 15 pixels + inside. If MINIMUM=10 then the filter will occur if there are 10 or + greater valid pixels. A valid pixel is one that is not special (NULL, LIS, + etc) and is in the range defined by LOW to HIGH. + + + 1 + + 1 + + + + + + boolean + TRUE + Propagate special pixels + + This option is used to define how special pixels are handled. If the + center pixel of the boxcar is a special pixel it will be propagated + or set to NULL depending on the value of this parameter. + + + + + + + + run svfilter + + This example shows an svfilter operation using standard deviation. + + + fr=../IN/peaks.cub:4 t=OUT/svfilter.sd fi=s s=5 li=5 + + + svfilter a Terra image. Use STDDEV filter (fi=s) + + + + + + Input image for svfilter + This is the input image for the svfilter examples. + + + FROM + + + + + + Output image for svfilter + This is the output image that results from STDDEV filter. + + + TO + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform +an svfilter operation on the input image. + + + + + + + + + run svfilter + + This example shows an svfilter operation using variance. + + + fr=../IN/peaks.cub:4 t=OUT/svfilter.var fi=v s=5 li=5 + + + svfilter a Terra image. Use VARIANCE filter. (fi=v) + + + + + + Input image for svfilter + This is the input image for the svfilter examples. + + + FROM + + + + + + Output image for svfilter + This is the output image that results from VARIANCE filter. + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform +an svfilter operation on the input image. + + + + + + + diff --git a/isis/src/base/apps/svfilter/tsts/Makefile b/isis/src/base/apps/svfilter/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/svfilter/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/svfilter/tsts/stddev/Makefile b/isis/src/base/apps/svfilter/tsts/stddev/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0d02492cb0b86534af7bbd092c0d4ff5ade0e2dd --- /dev/null +++ b/isis/src/base/apps/svfilter/tsts/stddev/Makefile @@ -0,0 +1,10 @@ +APPNAME = svfilter + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/svFilTruth2.cub \ + filter=stddev \ + samples= 21 \ + lines= 31 > /dev/null; diff --git a/isis/src/base/apps/svfilter/tsts/variance/Makefile b/isis/src/base/apps/svfilter/tsts/variance/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..263ebfddf46fb71b3c8ac10f4aa7f22290815ee5 --- /dev/null +++ b/isis/src/base/apps/svfilter/tsts/variance/Makefile @@ -0,0 +1,9 @@ +APPNAME = svfilter + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/svFilTruth1.cub \ + samples= 21 \ + lines= 31 > /dev/null; diff --git a/isis/src/base/apps/table2cube/Makefile b/isis/src/base/apps/table2cube/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/table2cube/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/table2cube/assets/images/out.jpg b/isis/src/base/apps/table2cube/assets/images/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2c3095145cb0af35216518411f1c39586b84a423 Binary files /dev/null and b/isis/src/base/apps/table2cube/assets/images/out.jpg differ diff --git a/isis/src/base/apps/table2cube/assets/images/table2cubeGUI.jpg b/isis/src/base/apps/table2cube/assets/images/table2cubeGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bcc4c736abf8073ccef4108c3b0691be7b4045c8 Binary files /dev/null and b/isis/src/base/apps/table2cube/assets/images/table2cubeGUI.jpg differ diff --git a/isis/src/base/apps/table2cube/assets/thumbs/out.jpg b/isis/src/base/apps/table2cube/assets/thumbs/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..659ce250ec380c5610789d984973ec92d0e6d57b Binary files /dev/null and b/isis/src/base/apps/table2cube/assets/thumbs/out.jpg differ diff --git a/isis/src/base/apps/table2cube/assets/thumbs/table2cubeGUI.jpg b/isis/src/base/apps/table2cube/assets/thumbs/table2cubeGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a672a8b97389f9cf4d3ebb111bdefa5d9c3054de Binary files /dev/null and b/isis/src/base/apps/table2cube/assets/thumbs/table2cubeGUI.jpg differ diff --git a/isis/src/base/apps/table2cube/table2cube.cpp b/isis/src/base/apps/table2cube/table2cube.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d5aa3ebe9c3702cc96c9896400c8bcf0950d71d --- /dev/null +++ b/isis/src/base/apps/table2cube/table2cube.cpp @@ -0,0 +1,73 @@ +#include "Isis.h" +#include "Table.h" +#include "ProcessByLine.h" +#include "iString.h" +#include +#include + +using namespace std; +using namespace Isis; + +Table *table; +iString field; +int startRecord; +int numRecords; +int startElement; +int numElements; + +void readTable(Isis::Buffer &outcube); + +void IsisMain() { + ProcessByBrick p; + UserInterface &ui = Application::GetUserInterface(); + + // Get Parameters + table = new Table(ui.GetString("TABLENAME")); + table->Read(ui.GetFilename("FROM")); + + field = ui.GetString("FIELD"); + startRecord = ui.GetInteger("STARTREC"); + startElement = ui.GetInteger("STARTELEM"); + + if(ui.WasEntered("NUMREC")) { + numRecords = ui.GetInteger("NUMREC"); + } + else { + numRecords = table->Records() - (startRecord - 1); + } + + if(ui.WasEntered("NUMELEM")) { + numElements = ui.GetInteger("NUMELEM"); + } + else { + numElements = (*table)[startRecord][field].Size() - (startElement - 1); + } + + p.SetOutputCube("TO", numElements, numRecords); + p.SetBrickSize(numElements, numRecords, 1); + p.StartProcess(readTable); + p.EndProcess(); + + delete table; +} + +void readTable(Isis::Buffer &outcube) { + for(int record = startRecord; record < startRecord + numRecords; record ++) { + for(int element = startElement; element < startElement + numElements; element ++) { + int index = (numElements * (record-1)) + (element - startElement); + + if((*table)[record-1][field].IsReal()){ + std::vector data = (*table)[record-1][field]; + outcube[index] = data.at(element-1); + } + else if((*table)[record-1][field].IsInteger()){ + std::vector data = (*table)[record-1][field]; + outcube[index] = data.at(element-1); + } + else if((*table)[record-1][field].IsDouble()){ + std::vector data = (*table)[record-1][field]; + outcube[index] = data.at(element-1); + } + } + } +} diff --git a/isis/src/base/apps/table2cube/table2cube.xml b/isis/src/base/apps/table2cube/table2cube.xml new file mode 100644 index 0000000000000000000000000000000000000000..5b0d053e34d9e50b70819fac0942d11b3896b40c --- /dev/null +++ b/isis/src/base/apps/table2cube/table2cube.xml @@ -0,0 +1,167 @@ + + + + + Converts a table to a cube + + + + Import and Export + + + + This program converts a single field of a table into a cube. + The table records will become lines in the output cube, and the table field data will become samples. + So, a field with an array of size three and twenty records will produce a 3 sample by 20 line cube. + + + + + Original Version + + + + + + + filename + input + + Input file name + + + Specify the input file containing table data. + + + + + cube + output + + Output file name + + + Specify the output file, which will be a cube populated with the data from the table. + + + *.cub + + real + + + + + + string + + Table Name + + + Specify the table name inside of the table input file (FROM). + + + + + string + + Field Name + + + Specify the field name inside of the cube to gather the data from. The size of the array inside of + this field will be the same as the number of samples in the output cube (unless otherwise specified). + + + + + integer + 1 + + Starting Record + + + Specify the starting record inside of the table. Use this if you want to skip initial data. One Based. + + + + + integer + All + + Number of records + + + Specify the number of records to convert, this starts with the first record specified by STARTREC. One Based. + + + + + integer + 1 + + Starting element in field + + + Specify the starting element in the field. For example, if you have an array of size three but only + want the last element this should be set to three. One Based. + + + + + integer + All + + Number of elements in field + + + Specify the number of elements in the field to convert into the output cube, this starts with the first + record specified by STARTELEM. One Based. + + + + + + + + + Converting a table to a cube using table2cube + + + Converting a table to a cube using table2cube. + + + + + from=out.tbl to=out.cub tablename=Example field=Data + + + In this example table2cube will convert the table "Example," field "Data" from out.tbl to out.cub + + + + + + + Convert table to cube + + In this example table2cube will convert the table "Example," field "Data" from out.tbl to out.cub + . + + + + + + + + Image after conversion + + This is the table from out.tbl after being converted to an Isis cube. The file "out.tbl" was constructed by making a + 500 by 500 table of the mathematical equation: element mod row (effectively x % y). + + + TO + + + + + + diff --git a/isis/src/base/apps/table2cube/tsts/Makefile b/isis/src/base/apps/table2cube/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/table2cube/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/table2cube/tsts/default/Makefile b/isis/src/base/apps/table2cube/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..54a040eb444c066648060f143d075251918a2f84 --- /dev/null +++ b/isis/src/base/apps/table2cube/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = table2cube + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/AEB_000001_0000_RED0_1.cub \ + to=$(OUTPUT)/table.truth.cub tablename="HiRISE Calibration Ancillary" \ + field=DarkPixels \ + > /dev/null; diff --git a/isis/src/base/apps/tabledump/Makefile b/isis/src/base/apps/tabledump/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/tabledump/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/tabledump/tabledump.cpp b/isis/src/base/apps/tabledump/tabledump.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13807e81b75715819ec4ba79eb3449f402e057b7 --- /dev/null +++ b/isis/src/base/apps/tabledump/tabledump.cpp @@ -0,0 +1,185 @@ +#define GUIHELPERS + +#include "Isis.h" +#include "Table.h" +#include "Filename.h" +#include "iString.h" +#include + +using namespace Isis; +using namespace std; + +int pos = 0; +string previousFile = ""; + +void helperButtonGetTableList(); + +map GuiHelpers(){ + map helper; + helper ["helperButtonGetTableList"] = (void*) helperButtonGetTableList; + return helper; +} + +void IsisMain(){ + // Gather parameters from the UserInterface + UserInterface &ui = Application::GetUserInterface(); + Filename file = ui.GetFilename("FROM"); + string tableName = ui.GetString("NAME"); + Table table(tableName, file.Expanded()); + + // Set the character to separate the entries + string delimit; + if (ui.GetString("DELIMIT") == "COMMA") { + delimit = ","; + } + else if (ui.GetString("DELIMIT") == "SPACE") { + delimit = " "; + } + else { + delimit = ui.GetString("CUSTOM"); + } + + // Open the file and output the column headings + stringstream ss (stringstream::in | stringstream::out); + + for (int i=0; i< table[0].Fields(); i++) { + for (int j=0; j 1) { + title += "(" + iString(j) + ")"; + } + if (i == table[0].Fields()-1 && j == table[0][i].Size()-1) { + // We've reached the last field, omit the delimiter + ss << title; + } + else{ + ss << title + delimit; + } + } + } + + // Loop through for each record + for (int i=0; i currField = table[i][j]; + for (int k=0; k<(int)currField.size(); k++) { + // check to see that we aren't on either the last field, or + // (if we are), we aren't on the last element of the field + if (j < table[i].Fields()-1 || + k < (int)currField.size()-1) { + ss << currField[k] << delimit; + } + else { + ss << currField[k]; + } + } + } + else if (table[i][j].IsDouble()) { + vector currField = table[i][j]; + for (int k=0; k<(int)currField.size(); k++) { + // check to see that we aren't on either the last field, or + // (if we are), we aren't on the last element of the field + if (j < table[i].Fields()-1 || + k < (int)currField.size()-1) { + ss << currField[k] << delimit; + } + else { + ss << currField[k]; + } + } + } + } + } // End Field loop + } // End Record loop + + if(ui.WasEntered("TO")) { + string outfile(Filename(ui.GetFilename("TO")).Expanded()); + ofstream outFile(outfile.c_str()); + outFile << ss.str(); + outFile.close(); + } + else if (ui.IsInteractive()){ + std::string log = ss.str(); + Application::GuiLog(log); + } + else { + cout << ss.str() << endl; + } +} + +// Function to find the available table names and put them into the GUI +void helperButtonGetTableList() { + string list; + bool match = false; + + UserInterface &ui = Application::GetUserInterface(); + string currentFile = ui.GetFilename("FROM"); + const Pvl label (Filename(currentFile).Expanded()); + + // Check to see if the "FILE" parameter has changed since last press + if (currentFile != previousFile) { + ui.Clear("NAME"); + pos = 0; + previousFile = currentFile; + } + + // Look for tables + int cnt = 0; + while (!match) { + // If we've gone through all objects and found nothing, throw an exception + if (cnt >= label.Objects()) { + pos = 0; + string msg = "Parameter [FROM] has no tables."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + // When the end of the objects is hit, display "NAME" parameter as blank + if (pos >= label.Objects()) { + list = ""; + match = true; + pos = 0; // Prepare to start over again + } + // When we find a table, fetch its name to stick in the "NAME" parameter + else if (label.Object(pos).Name() == "Table") { + list = label.Object(pos)["Name"][0].c_str(); + match = true; + pos++; + } + // If all else fails, keep looking for tables + else { + pos++; + cnt++; + } + } + + ui.Clear("NAME"); + ui.PutString("NAME",list); +} diff --git a/isis/src/base/apps/tabledump/tabledump.xml b/isis/src/base/apps/tabledump/tabledump.xml new file mode 100644 index 0000000000000000000000000000000000000000..8ee8208e8bb927ff6e55ac89775487aba1916632 --- /dev/null +++ b/isis/src/base/apps/tabledump/tabledump.xml @@ -0,0 +1,167 @@ + + + + + Program to output a selected table to a file + + + +

    + This program takes a cube with one or more table blobs in it, and, through + input provided by the user, outputs a selected table to an ASCII file, + with formatting determined by user input. +

    + +

    + Helper button has been provided in the GUI mode for the NAME + parameter. The helper button will sequentially fill in the name of + each table when pressed, clear the field to blank after the last table + has been reached, and then wrap back to the beginning. +

    +
    + + + Import and Export + + + + + Original version + + + Fixed helper button + + + Changed category from Utility to Import and Export + + + Changed TO parameter to function like other applications in ISIS. + It now defaults to console output when no TO file is enterd. + + + Fixed string representation and display. + + + Changed helper button to only place one table name into the + NAME parameter each time it is pressed + + + + + + + cube + input + + Input Cube + + + This is the cube containing the table to be output. + + *.cub + + + + filename + output + + Output file + + + This is the output file where the table will be written. + + + No Output file will be created + + *.txt + + + + + + string + + The name of the table + + + This is the name of the table to be output. The name is found + in the labels, in the relevant object, as the value of the + Keyword "Name." This value is set by the program creating + the table, and is standardized to certain conventions. + + + + helperButtonGetTableList + Retrieve Table names + + This button will, each time it is pressed, generate the + name of a table in the input cube and put it in the + appropriate field in the GUI, clearing the field to blank + and wrapping back to the top after the last table is hit. + + $ISIS3DATA/base/icons/exec.png + + + + + + string + + The character to be inserted between table entries + + + This option will determine which character will be used to + separate table entries, with the default option as a comma. + The other options are space, to separate with a single + space, or "OTHER," which allows the user to input whatever + they wish as the delimiter character. + + COMMA + + + + + + + + string + User-defined delimiter + + This parameter is only used if the user has selected "OTHER" + as a delimiter. The user then enters something into this + parameter to use as a delimiter. + + + + +
    diff --git a/isis/src/base/apps/tabledump/tsts/Makefile b/isis/src/base/apps/tabledump/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/tabledump/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/tabledump/tsts/consoleOutput/Makefile b/isis/src/base/apps/tabledump/tsts/consoleOutput/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..529e0b7122dff00238b82630d1d7c57ee43171cf --- /dev/null +++ b/isis/src/base/apps/tabledump/tsts/consoleOutput/Makefile @@ -0,0 +1,8 @@ +APPNAME =tabledump + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/blobTruth.cub \ + name="HiRISE Ancillary" \ + > $(OUTPUT)/tabledump2.txt; diff --git a/isis/src/base/apps/tabledump/tsts/default/Makefile b/isis/src/base/apps/tabledump/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a139b189dfded3b91b7770b63e60383389550da5 --- /dev/null +++ b/isis/src/base/apps/tabledump/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME =tabledump + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/blobTruth.cub \ + to=$(OUTPUT)/tabledump1.txt \ + name="HiRISE Ancillary" > /dev/null; + $(APPNAME) from=$(INPUT)/input.cub \ + to=$(OUTPUT)/stringcheck.txt \ + name=CameraStatistics > /dev/null; diff --git a/isis/src/base/apps/tabledump/tsts/other/Makefile b/isis/src/base/apps/tabledump/tsts/other/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9a6469dafd9b1a5d70788e1b9b703e82d659235d --- /dev/null +++ b/isis/src/base/apps/tabledump/tsts/other/Makefile @@ -0,0 +1,10 @@ +APPNAME =tabledump + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/blobTruth.cub \ + to=$(OUTPUT)/tabledump2.txt \ + delimit=OTHER \ + custom="!TEST!" \ + name="HiRISE Calibration Image" > /dev/null; diff --git a/isis/src/base/apps/tonematch/Makefile b/isis/src/base/apps/tonematch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/tonematch/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/tonematch/tonematch.cpp b/isis/src/base/apps/tonematch/tonematch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58ce002bc37754d57351613c9019abfad5027fcc --- /dev/null +++ b/isis/src/base/apps/tonematch/tonematch.cpp @@ -0,0 +1,75 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "MultivariateStatistics.h" +#include "OverlapStatistics.h" +#include "UserInterface.h" +#include "iException.h" + +using namespace std; +using namespace Isis; +void getStats (vector &in, vector &out); +void toneMatch (Buffer &in, Buffer &out); + +MultivariateStatistics stats; +double base,mult; + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Get the user interface + UserInterface &ui = Application::GetUserInterface(); + + // If the user selected pOverlap, get the projected overlap statistics + if (ui.GetBoolean("POVERLAP")) { + // Set up the overlap statistics object + Cube from,match; + from.Open(ui.GetFilename("FROM")); + match.Open(ui.GetFilename("MATCH")); + OverlapStatistics oStats(from,match); + + //Make sure the projections overlap + if (!oStats.HasOverlap()) { + string msg = "Input Cubes do not appear to overlap"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + // Get mvstat data for the overlapping area + stats = oStats.GetMStats(1); + } + + // If the user didnt select pOverlap, get the stats of the entire cubes + else { + // Setup the input cubes to match + p.SetInputCube("FROM",Isis::OneBand); + p.SetInputCube("MATCH",Isis::OneBand); + + // Get the statistics from the cubes + p.StartProcess(getStats); + } + + // compute the linear regression fit of the mvstats data + stats.LinearRegression(base,mult); + + // Apply the correction + p.ClearInputCubes(); + p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + p.StartProcess(toneMatch); + p.EndProcess(); +} + +void getStats (vector &in, vector &out) { + stats.AddData(in[0]->DoubleBuffer(),in[1]->DoubleBuffer(),in[0]->size()); +} + +void toneMatch (Buffer &in, Buffer &out) { + for (int i=0; i + + + + Matches the tone of two images + + + + This application is very similar to the equalizer application, but is only used on two images. + Tonematch collects statistics on each individual cube. It then uses this data to find a linear + regression model between the input cube and the match cube. The linear regression is + applied to the input cube, creating the output cube (whose tone is equal to that of the match cube). + + + + Radiometric and Photometric Correction + + + + + equalizer + + + + + + Original version + + + Documented and refactored + + + Added appTest and poverlap option + + + Moved to Photometry and Radiometry group in documentation + + + + + + + cube + input + + Input cube + + + The pixels of the input cube will be altered using the base and multiplier found + in the linear regression to make the tone of the output and match cubes equal. + + + *.cub + + + + + cube + input + + Match Cube + + + The match cube will be used to find the tone that the output cube should have. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the tonematched image. + + + *.cub + + + + + + + boolean + + Projection Overlap + + + This parameter allows the user to match the tone of the entire images, or just match the overlapping + area of the cubes. If this option is chosen, both cubes must have the same projection parameters and + must be overlapping. + + FALSE + + + + diff --git a/isis/src/base/apps/tonematch/tsts/Makefile b/isis/src/base/apps/tonematch/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/tonematch/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/tonematch/tsts/default/Makefile b/isis/src/base/apps/tonematch/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c3d3e9e216c8eb3dc8e3160168fb6f350e08adde --- /dev/null +++ b/isis/src/base/apps/tonematch/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = tonematch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/I00824006RDR.lev2.cub+1 \ + match=$(INPUT)/I00824006RDR.lev2.cub+1 \ + to=$(OUTPUT)/tonematchTruth1.cub > /dev/null; diff --git a/isis/src/base/apps/tonematch/tsts/poverlap/Makefile b/isis/src/base/apps/tonematch/tsts/poverlap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..da1ae7def477e7832af6040c7732c62b000f284f --- /dev/null +++ b/isis/src/base/apps/tonematch/tsts/poverlap/Makefile @@ -0,0 +1,9 @@ +APPNAME = tonematch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/I00824006RDR.lev2.cub+1 \ + match=$(INPUT)/I01523019RDR.lev2.cub+1 \ + to=$(OUTPUT)/tonematchTruth2.cub \ + poverlap=true > /dev/null; diff --git a/isis/src/base/apps/translate/Makefile b/isis/src/base/apps/translate/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/translate/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/translate/translate.cpp b/isis/src/base/apps/translate/translate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7a3ed5a410896e5fca6d203925ef9b9d17ea54e --- /dev/null +++ b/isis/src/base/apps/translate/translate.cpp @@ -0,0 +1,47 @@ +#include "Isis.h" +#include "ProcessRubberSheet.h" + +#include "translate.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + ProcessRubberSheet p; + + // Open the input cube + Cube *icube = p.SetInputCube ("FROM"); + + // Set up the transform object + UserInterface &ui = Application::GetUserInterface(); + Transform *transform = new Translate(icube->Samples(), icube->Lines(), + ui.GetDouble("STRANS"), + ui.GetDouble("LTRANS")); + + // Allocate the output file, same size as input + p.SetOutputCube ("TO",icube->Samples(),icube->Lines(),icube->Bands()); + + // Set up the interpolator + Interpolator *interp; + if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { + interp = new Interpolator(Interpolator::NearestNeighborType); + } + else if (ui.GetString("INTERP") == "BILINEAR") { + interp = new Interpolator(Interpolator::BiLinearType); + } + else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { + interp = new Interpolator(Interpolator::CubicConvolutionType); + } + else { + string msg = "Unknow value for INTERP [" + + ui.GetString("INTERP") + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + p.StartProcess(*transform, *interp); + p.EndProcess(); + + delete transform; + delete interp; +} + diff --git a/isis/src/base/apps/translate/translate.h b/isis/src/base/apps/translate/translate.h new file mode 100644 index 0000000000000000000000000000000000000000..df9e28f28e3781496ab85135f96fa79841f03f80 --- /dev/null +++ b/isis/src/base/apps/translate/translate.h @@ -0,0 +1,52 @@ +#ifndef Translate_h +#define Translate_h + +#include "Transform.h" +#include +#include + +class Translate : public Isis::Transform { + private: + int p_outputSamples; + int p_outputLines; + + double p_sampleTrans; + double p_lineTrans; + + public: + // constructor + Translate (const double inputSamples, const double inputLines, + const double sampleTrans, const double lineTrans){ + // Save off the sample and line translation + p_sampleTrans = sampleTrans; + p_lineTrans = lineTrans; + + p_outputSamples = (int) inputSamples; + p_outputLines = (int) inputLines; + } + + // destructor + ~Translate () {}; + + // Implementations for parent's pure virtual members + // Convert the requested output samp/line to an input samp/line + bool Xform (double &inSample, double &inLine, + const double outSample, const double outLine) { + inSample = outSample - p_sampleTrans; + inLine = outLine - p_lineTrans; + return true; + } + + // Return the output number of samples + int OutputSamples () const { + return p_outputSamples; + } + + // Return the output number of lines + int OutputLines () const { + return p_outputLines; + } +}; + +#endif + diff --git a/isis/src/base/apps/translate/translate.xml b/isis/src/base/apps/translate/translate.xml new file mode 100644 index 0000000000000000000000000000000000000000..f5b8d87e0f627790f44741582deb51019f727f2a --- /dev/null +++ b/isis/src/base/apps/translate/translate.xml @@ -0,0 +1,127 @@ + + + + + + Translate an image by given sample and line translation values + + + + This program will translate an image any amount in both the sample and line + directions. + + + + + Original version + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Fixed compiler error with uninitialized variable after adding -O1 flag + + + Modified filename parameters to be cube parameters where necessary + + + Fixed typo in user documentation + + + Removed references to CubeInfo + + + + + Geometry + + + + + + cube + input + + Input cube to translate + + + Use this parameter to select the filename. All bands within the file + will be translated unless a specific band is specified. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the translation. + + + + + + + double + Sample translation value + + This determines translation in the sample direction. + + + + + double + Line translation value + + This determines translation in the line direction. + + + + + + + string + + CUBICCONVOLUTION + + Type of interpolation + + This is the type of interpolation to be performed on the input. + + + + + + + + + + + + diff --git a/isis/src/base/apps/translate/tsts/Makefile b/isis/src/base/apps/translate/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/translate/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/translate/tsts/default/Makefile b/isis/src/base/apps/translate/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a6e5cda600639e88837a4e42b0aabfdc16fac601 --- /dev/null +++ b/isis/src/base/apps/translate/tsts/default/Makefile @@ -0,0 +1,10 @@ +APPNAME = translate + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/translateTruth1.cub \ + strans=10.5 \ + ltrans=-10.5 \ + interp=nearestneighbor > /dev/null; diff --git a/isis/src/base/apps/trim/Makefile b/isis/src/base/apps/trim/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/trim/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/trim/assets/image/lo.crp.jpg b/isis/src/base/apps/trim/assets/image/lo.crp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8356237537f151db77f17544f5172a69363e1d87 Binary files /dev/null and b/isis/src/base/apps/trim/assets/image/lo.crp.jpg differ diff --git a/isis/src/base/apps/trim/assets/image/lo.trm.jpg b/isis/src/base/apps/trim/assets/image/lo.trm.jpg new file mode 100644 index 0000000000000000000000000000000000000000..efc7de6ff175e9228b558b31594d7c3d5655aa6f Binary files /dev/null and b/isis/src/base/apps/trim/assets/image/lo.trm.jpg differ diff --git a/isis/src/base/apps/trim/assets/image/trimGui.jpg b/isis/src/base/apps/trim/assets/image/trimGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c7272a56f7c08359e03835815156d578df3496fe Binary files /dev/null and b/isis/src/base/apps/trim/assets/image/trimGui.jpg differ diff --git a/isis/src/base/apps/trim/assets/thumb/lo.crp.jpg b/isis/src/base/apps/trim/assets/thumb/lo.crp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8ba33c59dfd64f04080461eb4a18c17ccd02a576 Binary files /dev/null and b/isis/src/base/apps/trim/assets/thumb/lo.crp.jpg differ diff --git a/isis/src/base/apps/trim/assets/thumb/lo.trm.jpg b/isis/src/base/apps/trim/assets/thumb/lo.trm.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ec3a4378e9ff1402ac3ac7b642dac5ea8f282a8c Binary files /dev/null and b/isis/src/base/apps/trim/assets/thumb/lo.trm.jpg differ diff --git a/isis/src/base/apps/trim/assets/thumb/trimGui.jpg b/isis/src/base/apps/trim/assets/thumb/trimGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ed10af5674f60f731f94c6a51da02e22464b184b Binary files /dev/null and b/isis/src/base/apps/trim/assets/thumb/trimGui.jpg differ diff --git a/isis/src/base/apps/trim/trim.cpp b/isis/src/base/apps/trim/trim.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4caeb6cc5f86bf8df2b12c8b6643ef831402f8ed --- /dev/null +++ b/isis/src/base/apps/trim/trim.cpp @@ -0,0 +1,75 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +// Line processing routine +void trim (Buffer &in, Buffer &out); + +int top,bottom,lleft,rright; + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and output cubes + Cube *icube = p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + + // Override the defaults if the user entered a value + UserInterface &ui = Application::GetUserInterface(); + top = ui.GetInteger ("TOP"); + bottom = ui.GetInteger ("BOTTOM"); + lleft = ui.GetInteger ("LEFT"); + rright = ui.GetInteger ("RIGHT"); + + // Will anything be trimmed from the cube? + bool notrim = false; + if (top == 0 && bottom == 0 && lleft == 0 && rright == 0) { + notrim = true; + } + + // Adjust bottom and right + bottom = icube->Lines() - bottom; + rright = icube->Samples() - rright; + + // Start the processing + p.StartProcess(trim); + p.EndProcess(); + + //The user didn't trim anything + if (notrim == true) { + string message = "No trimming was done-output equals input file"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + +} + + +// Line processing routine + void trim (Buffer &in,Buffer &out) + { + + // Test for line trim and NULL full line + if (in.Line () <= top || in.Line () > bottom) { + for (int i=0; i rright) { + out[i] = NULL8; + } + else { + out[i] = in[i]; + } + } + } +} + + diff --git a/isis/src/base/apps/trim/trim.xml b/isis/src/base/apps/trim/trim.xml new file mode 100644 index 0000000000000000000000000000000000000000..4ec74416df03b41818d819894fa57dbfbe4dae00 --- /dev/null +++ b/isis/src/base/apps/trim/trim.xml @@ -0,0 +1,200 @@ + + + + + + Trim edges of input cube + + + + This program will trim (set to NULL) edge pixels of the input cube defined + by the parameters TOP, BOTTOM, LEFT and RIGHT, which indicate the + number of pixels to trim from edges of the cube. Note that this program + does not change the dimensions of the cube. The program "crop" allows + a section of a cube to be output. + + + + + Original version + + + Ported to Isis 3.0 + + + Add example. + + + Make images smaller + + + Fixed problem with isiscvs not checking in the thumb and image directories. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Removed references to CubeInfo + + + + + Trim and Mask + + + + + crop + + + + + + + cube + input + + Input cube to trim + + + Use this parameter to select the filename. All bands within the file + will be trimmed. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the trimmed cube. + + + *.cub + + + + + + + integer + + 0 + + Number of lines to trim at top of cube + + This defines the number of lines that will be set to NULL + at the top of the cube. + + + 0 + + + + + integer + + 0 + + Number of lines to trim at bottom of cube + + This defines the number of lines that will be set to NULL + at the bottom of the cube. + + + 0 + + + + + integer + + 0 + + Number of samples to trim at left side of cube + + This defines the number of samples that will be set to NULL + at the left side of the cube. + + + 0 + + + + + integer + + 0 + + Number of samples to trim at right side of cube + + This defines the number of samples that will be set to NULL + at the right side of the cube. + + + 0 + + + + + + + + + trim Lunar Orbiter + + This example shows a trim operation. + + + f=../IN/lo.crp.cub to=OUT/lo.trm top=240 l=53 r=48 + + + trim 3 sides of a Lunar Orbiter image. + + + + + + Input image for trim + This is the input image for the trim example +. + + + FROM + + + + + + Output image for trim + This is the output image that results. + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a trim operation on the input image. + + + + + + + + diff --git a/isis/src/base/apps/trim/tsts/Makefile b/isis/src/base/apps/trim/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/trim/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/trim/tsts/case01/Makefile b/isis/src/base/apps/trim/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0614fc92fdc3477f8541abe504ba8ebd4f52753c --- /dev/null +++ b/isis/src/base/apps/trim/tsts/case01/Makefile @@ -0,0 +1,11 @@ +APPNAME = trim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/trimTruth1.cub \ + top=0 \ + bottom=10 \ + left=3 \ + right=1 > /dev/null; diff --git a/isis/src/base/apps/trim/tsts/case02/Makefile b/isis/src/base/apps/trim/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c030978bfa825242f2b49c7ce85cb03146c4b2c6 --- /dev/null +++ b/isis/src/base/apps/trim/tsts/case02/Makefile @@ -0,0 +1,13 @@ +.IGNORE: + +APPNAME = trim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/trimTruth2.cub \ + top=0 \ + bottom=0 \ + left=0 \ + right=0 > $(OUTPUT)/error.txt 2>&1; diff --git a/isis/src/base/apps/trimfilter/Makefile b/isis/src/base/apps/trimfilter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/trimfilter/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/trimfilter/assets/image/lo880.crp.jpg b/isis/src/base/apps/trimfilter/assets/image/lo880.crp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ed6a8d0d820fa21fe3c82326a727a6efc02582a4 Binary files /dev/null and b/isis/src/base/apps/trimfilter/assets/image/lo880.crp.jpg differ diff --git a/isis/src/base/apps/trimfilter/assets/image/trimfilterGui.jpg b/isis/src/base/apps/trimfilter/assets/image/trimfilterGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..00168a81967ea5bafc788b44326abf643bbb8ff9 Binary files /dev/null and b/isis/src/base/apps/trimfilter/assets/image/trimfilterGui.jpg differ diff --git a/isis/src/base/apps/trimfilter/assets/image/trmfltr.jpg b/isis/src/base/apps/trimfilter/assets/image/trmfltr.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c4b1b2e4e9a068b293b6f694f3c9e79cc91514ac Binary files /dev/null and b/isis/src/base/apps/trimfilter/assets/image/trmfltr.jpg differ diff --git a/isis/src/base/apps/trimfilter/assets/thumb/lo880.crp.jpg b/isis/src/base/apps/trimfilter/assets/thumb/lo880.crp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..31ea622b355b4edc6ddadea419bcc25c2098d9fb Binary files /dev/null and b/isis/src/base/apps/trimfilter/assets/thumb/lo880.crp.jpg differ diff --git a/isis/src/base/apps/trimfilter/assets/thumb/trimfilterGui.jpg b/isis/src/base/apps/trimfilter/assets/thumb/trimfilterGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..13a43442296f11d5c4c74f81d0c10138a09bf198 Binary files /dev/null and b/isis/src/base/apps/trimfilter/assets/thumb/trimfilterGui.jpg differ diff --git a/isis/src/base/apps/trimfilter/assets/thumb/trmfltr.jpg b/isis/src/base/apps/trimfilter/assets/thumb/trmfltr.jpg new file mode 100644 index 0000000000000000000000000000000000000000..18931399c1cd26abbb5ab66d1f23cac99a8ff056 Binary files /dev/null and b/isis/src/base/apps/trimfilter/assets/thumb/trmfltr.jpg differ diff --git a/isis/src/base/apps/trimfilter/trimfilter.cpp b/isis/src/base/apps/trimfilter/trimfilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4c3c5d4d41d76cb05e76964c49ccc306eeb4554 --- /dev/null +++ b/isis/src/base/apps/trimfilter/trimfilter.cpp @@ -0,0 +1,63 @@ +#include "Isis.h" +#include "ProcessByQuickFilter.h" +#include "UserInterface.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +// prototypes and globals +bool trimmed; +void trimfilter (Buffer &in, Buffer &out, QuickFilter &filter); + +// The trimfilter main routine +void IsisMain() { + ProcessByQuickFilter p; + + // Open the input cube + p.SetInputCube("FROM"); + + // Setup the output cube + p.SetOutputCube("TO"); + + //Set up boxcar variables (minimum) + UserInterface &ui = Application::GetUserInterface(); + int lines = ui.GetInteger("LINES"); + int samples = ui.GetInteger("SAMPLES"); + double low = -DBL_MAX; + double high = DBL_MAX; + int minimum; + if (ui.GetString("MINOPT") == "PERCENTAGE") { + int size = lines * samples; + double perc = ui.GetDouble("MINIMUM") / 100; + minimum = (int) (size * perc); + } + else { + minimum = (int) ui.GetDouble("MINIMUM"); + } + p.SetFilterParameters(samples, lines, low, high, minimum); + + // Process each line + trimmed = false; + p.StartProcess(trimfilter); // Line processing function + p.EndProcess(); // Cleanup + + // If trimming did not occur tell the user + if (!trimmed) { + string msg = "Your selected parameters did not trim any data from the cube"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } +} + +// Line processing routine +void trimfilter (Buffer &in, Buffer &out, QuickFilter &filter) { + for (int i=0; i= filter.MinimumPixels()) { + out[i] = in[i]; + } + else { + trimmed = true; + out[i] = NULL8; + } + } +} diff --git a/isis/src/base/apps/trimfilter/trimfilter.xml b/isis/src/base/apps/trimfilter/trimfilter.xml new file mode 100644 index 0000000000000000000000000000000000000000..3833356c3ce9fe542113b946ec29b649d84fd169 --- /dev/null +++ b/isis/src/base/apps/trimfilter/trimfilter.xml @@ -0,0 +1,278 @@ + + + + + + Apply a trim filter to a cube + + + + This program convolves an NxM boxcar through a cube and trims (or NULLs) + pixels. A pixel at the center of the boxcar is trimmed in the output cube + if the number of valid pixels inside the boxcar is less than a user + specified minimum. Valid pixels are defined as those which are 1) not + special pixels and 2) inside the range of the LOW and HIGH parameters. + This is a very powerful trimming tool although much + thought must be put into the parameters in order to obtain the optimal + trimming results. + + + + Filters + Trim and Mask + + + + + lowpass + highpass + sdfilter + varfilter + + + + + + Original version + + + + Ported to Isis 3.0 + + + + Add example + + + + Make images smaller. + + + Fixed problem with isiscvs not checking in the thumb and image directories. + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Added Minopt parameter + + + + + boxfilter + + + + + + cube + input + + Input file + + + Input cube to filter + + + *.cub + + + + cube + output + + Output trimmed cube + + + The resultant trimmed cube + + + + + + + integer + + Number of samples in boxcar + + + + This is the total number of samples in the boxcar. + It must be odd and can not exceed twice the number of samples + in the cube. In general, the size of the boxcar does not + cause the program to operate significantly slower. + + + + + 1 + + + + integer + + Number of lines in boxcar + + + + This is the total number of lines in the boxcar. + It must be odd and can not exceed twice the number of lines + in the cube. In general, the size of the boxcar does not + cause the program to operate significantly + slower. + + + + + 1 + + + + + + double + + Valid minimum pixel + + + Valid minimum pixel value that will be used in boxcar computation. If + a pixel value is less than LOW then it will not be used when + computing boxcar counts. + + + Use all pixels + + + HIGH + + + + + double + + Valid maximum pixel + + + Valid maximum pixel value that will be used in boxcar computation. If + a pixel value is greater than HIGH then it will not be used when + computing boxcar counts. + + + Use all pixels + + + LOW + + + + + string + + COUNT + + + Sets minimum to be either a count or a percentage + + + This parameter determines whether the minimum + parameter is to be interpreted as a count of pixels, or a + percentage of all pixels in the boxcar. + + + + + + + + + + double + + Minimum boxcar pixel count + + + This is the minimum number of valid pixels which must occur inside the + NxM boxcar in order to preserve the output pixel. + For example, a 3x5 boxcar has 15 pixels + inside. If MINIMUM=10 then the trimming will occur if there are 9 or + less valid pixels. A valid pixel is one that is not special (NULL, LIS, + etc) and is in the range defined by LOW to HIGH. + + + 1 + + 1 + + + + + + + run a trim filter + + This example shows a trimfilter operation. + + + f=../IN/lo880.crp.cub t=OUT/trmfltr s=1 li=301 high=241 min=95 + + + trimfilter a Lunar Orbiter image. + + + + + + Input image for trimfilter + This is the input image for the trimfilter example. + + + FROM + + + + + + Output image for trimfilter + This is the output image that results. + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a trimfilter operation on the input image. + + + + + + + + diff --git a/isis/src/base/apps/trimfilter/tsts/Makefile b/isis/src/base/apps/trimfilter/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/trimfilter/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/trimfilter/tsts/default/Makefile b/isis/src/base/apps/trimfilter/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cdca305ac7af58e76c1ce761d553d673b3aadfd0 --- /dev/null +++ b/isis/src/base/apps/trimfilter/tsts/default/Makefile @@ -0,0 +1,10 @@ +APPNAME = trimfilter + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/trimFilterTruth.cub \ + samples=5 \ + lines=5 \ + minimum=8 > /dev/null; diff --git a/isis/src/base/apps/uncrop/Makefile b/isis/src/base/apps/uncrop/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/uncrop/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/uncrop/tsts/Makefile b/isis/src/base/apps/uncrop/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/uncrop/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/uncrop/tsts/default/Makefile b/isis/src/base/apps/uncrop/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a78a5e6df873a04ba050d2e976572011c00d6e38 --- /dev/null +++ b/isis/src/base/apps/uncrop/tsts/default/Makefile @@ -0,0 +1,23 @@ +APPNAME = uncrop + +include $(ISISROOT)/make/isismake.tsts + +commands: + makecube \ + to=$(OUTPUT)/parent.cub \ + pixels=null \ + samples=100 \ + lines=100 \ + bands=2 > /dev/null; + crop \ + from= $(INPUT)/isisTruth.cub \ + to=$(OUTPUT)/child.cub \ + sample=10 \ + nsamples=20 \ + sinc=1 \ + line=10 \ + nlines=20 \ + linc=1 > /dev/null; + $(APPNAME) from=$(OUTPUT)/child.cub \ + parent=$(OUTPUT)/parent.cub \ + combine=crop > /dev/null; \ diff --git a/isis/src/base/apps/uncrop/uncrop.cpp b/isis/src/base/apps/uncrop/uncrop.cpp new file mode 100644 index 0000000000000000000000000000000000000000..292aa10dd75b03bc054bc554e8edfd35c702120c --- /dev/null +++ b/isis/src/base/apps/uncrop/uncrop.cpp @@ -0,0 +1,39 @@ +#include "Isis.h" +#include "ProcessMosaic.h" +#include "AlphaCube.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + ProcessMosaic p; + p.SetBandBinMatch(false); + + // Set the input cube for the process object + p.SetInputCube ("FROM"); + + // Set up the mosaic priority + UserInterface &ui = Application::GetUserInterface(); + string combineMethod = ui.GetString ("COMBINE"); + MosaicPriority priority; + if (combineMethod == "PARENT") { + priority = mosaic; + } + else { + priority = input; + } + + // Get the extraction label from the input file + Pvl lab; + lab.Read(ui.GetFilename("FROM")); + AlphaCube acube(lab); + int outSample = (int) (acube.AlphaSample(0.5) + 0.5); + int outLine = (int) (acube.AlphaLine(0.5) + 0.5); + int outBand = 1; + + p.SetOutputCube ("PARENT"); + + p.StartProcess(outSample, outLine, outBand, priority); + p.EndProcess(); +} + diff --git a/isis/src/base/apps/uncrop/uncrop.xml b/isis/src/base/apps/uncrop/uncrop.xml new file mode 100644 index 0000000000000000000000000000000000000000..29832792720966d509a53bddd4044310059b19e3 --- /dev/null +++ b/isis/src/base/apps/uncrop/uncrop.xml @@ -0,0 +1,109 @@ + + + + + Puts a sub-cube back into its parent cube + + + + This program reverses the effect of crop. That is, it puts a cropped cube back + into a parent cube. The sub or child cube must have an AlphaCube label. + Note: The filename and size of the parent cube is not checked for correctness. + + + + Trim and Mask + + + + + Original version + + + Changed category from Utility to Trim and Mask + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Modified filename parameters to be cube parameters where necessary + + + Replaced extraction group with AlphaCube group + + + Documentation fixes + + + + + mosaic + + + + + + cube + input + + Child cube + + + The sub-cube, possibly created by crop. This cube must contain a valid + AlphaCube label. + + + *.cub + + + + + cube + output + + Parent output cube + + + The output cube. Normally, this would be the cube where the sub-cube + came from, although this is not necessary. + + + *.cub + + + + + + + string + + CROP + + How to combine the crop and parent pixels + + This parameter is used to select one of two ways to combine the + crop and parent pixels in areas of overlap. + + + + + + + + + + diff --git a/isis/src/base/apps/vicar2isis/Makefile b/isis/src/base/apps/vicar2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/vicar2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/vicar2isis/assets/images/out.jpg b/isis/src/base/apps/vicar2isis/assets/images/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..32814dd5402a5664b1cac201962762b80416d6b9 Binary files /dev/null and b/isis/src/base/apps/vicar2isis/assets/images/out.jpg differ diff --git a/isis/src/base/apps/vicar2isis/assets/images/vicar2isisGUI.jpg b/isis/src/base/apps/vicar2isis/assets/images/vicar2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..14a2cdcaaa50ebc483f81b050ca8f8b23770882c Binary files /dev/null and b/isis/src/base/apps/vicar2isis/assets/images/vicar2isisGUI.jpg differ diff --git a/isis/src/base/apps/vicar2isis/assets/thumbs/out.jpg b/isis/src/base/apps/vicar2isis/assets/thumbs/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..de5cb64e28befe1e2487302bc9be96a895ba440b Binary files /dev/null and b/isis/src/base/apps/vicar2isis/assets/thumbs/out.jpg differ diff --git a/isis/src/base/apps/vicar2isis/assets/thumbs/vicar2isisGUI.jpg b/isis/src/base/apps/vicar2isis/assets/thumbs/vicar2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6b0503cc05e1675a3bd29f442ef15a08357f4f27 Binary files /dev/null and b/isis/src/base/apps/vicar2isis/assets/thumbs/vicar2isisGUI.jpg differ diff --git a/isis/src/base/apps/vicar2isis/tsts/Makefile b/isis/src/base/apps/vicar2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/vicar2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/vicar2isis/tsts/default/Makefile b/isis/src/base/apps/vicar2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fa8ce379ab3413c324ae51eef06658353e028820 --- /dev/null +++ b/isis/src/base/apps/vicar2isis/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = vicar2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/appTest.img \ + to=$(OUTPUT)/vicar2isisTruth.cub > /dev/null; diff --git a/isis/src/base/apps/vicar2isis/vicar2isis.cpp b/isis/src/base/apps/vicar2isis/vicar2isis.cpp new file mode 100755 index 0000000000000000000000000000000000000000..b684bcbb2657faeda8916b6c051f584751a34b91 --- /dev/null +++ b/isis/src/base/apps/vicar2isis/vicar2isis.cpp @@ -0,0 +1,34 @@ +#include "Isis.h" +#include "ProcessImportVicar.h" +#include "UserInterface.h" +#include "Pvl.h" + +using namespace std; +using namespace Isis; + +void IsisMain () +{ + UserInterface &ui = Application::GetUserInterface (); + ProcessImportVicar p; + + // Set Special Pixel ranges + if (ui.GetBoolean("SETNULLRANGE")) { + p.SetNull(ui.GetDouble("NULLMIN"),ui.GetDouble("NULLMAX")); + } + if (ui.GetBoolean("SETHRSRANGE")) { + p.SetHRS(ui.GetDouble("HRSMIN"),ui.GetDouble("HRSMAX")); + } + if (ui.GetBoolean("SETLRSRANGE")) { + p.SetLRS(ui.GetDouble("LRSMIN"),ui.GetDouble("LRSMAX")); + } + + Pvl vicLab; + p.SetVicarFile(ui.GetFilename ("FROM"),vicLab); + p.SetOutputCube("TO"); + + p.StartProcess (); + p.EndProcess (); + + return; +} + diff --git a/isis/src/base/apps/vicar2isis/vicar2isis.xml b/isis/src/base/apps/vicar2isis/vicar2isis.xml new file mode 100755 index 0000000000000000000000000000000000000000..c0b2b73eac10c7f0d713e3b29b468cc6ea3e9174 --- /dev/null +++ b/isis/src/base/apps/vicar2isis/vicar2isis.xml @@ -0,0 +1,244 @@ + + + + + + Import Vicar image file into Isis format + + + + This program will import a Vicar image file into an Isis cube. No + translation of Vicar labels are done. + + + + + Original version + + + Modified due to IsisImport refactor + + + Added appTest + + + Added special pixel ranges and example + + + + + Import and Export + + + + + + filename + input + + Input Vicar file + + + Use this parameter to select the Vicar filename. If multi-band, it + is assumed to be in band sequential order. + + + *.img *.IMG *.vic + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + + + boolean + + NO + + Create special pixel values + + If this option is used input raw pixels below minimum and + above maximum will be converted to LRS and HRS respectively. Otherwise + pixels in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit real will + cause 0 and 255 to be actual values. If left as 8-bit then 0 will + be NULL and 255 will be HRS. + + + NULLMIN + NULLMAX + + + + + double + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + SETNULLRANGE + + + + double + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + SETNULLRANGE + + + + + boolean + + NO + + Create special pixel values + + If this option is used input raw pixels below minimum and + above maximum will be converted to LRS and HRS respectively. Otherwise + pixels in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit real will + cause 0 and 255 to be actual values. If left as 8-bit then 0 will + be NULL and 255 will be HRS. + + + HRSMIN + HRSMAX + + + + + double + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + SETHRSRANGE + + + + double + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + SETHRSRANGE + + + + + boolean + + NO + + Create special pixel values + + If this option is used input raw pixels below minimum and + above maximum will be converted to LRS and HRS respectively. Otherwise + pixels in the input raw file will be left unchanged in most cases. For + example, importing a raw 8-bit file and outputing to a 16-bit or 32-bit real will + cause 0 and 255 to be actual values. If left as 8-bit then 0 will + be NULL and 255 will be HRS. + + + LRSMIN + LRSMAX + + + + + double + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + SETLRSRANGE + + + + double + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + SETLRSRANGE + + + + + + + + + Converting an vicar file to an Isis Cube + + + This example will show the conversion from a vicar file to a cube. + + + FROM=input.img TO=out.cub + Convert the image input.img to the Isis Cube out.cub + + + + + Convert the image input.img to the Isis Cube out.cub + + The is the GUI for vicar2isis when converting the ascii file input.txt to the Isis Cube out.cub + + + + + + + + + + Vicar input file. + + + This is the vicar data + + FROM + + + + + + Output Isis Cube + + The is the output Isis Cube peaks.cub generated from this example. + + + + + + + diff --git a/isis/src/base/apps/warp/Makefile b/isis/src/base/apps/warp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/base/apps/warp/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/base/apps/warp/WarpTransform.cpp b/isis/src/base/apps/warp/WarpTransform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5e2f393f73161915749bf22f908ff7c41c42d41 --- /dev/null +++ b/isis/src/base/apps/warp/WarpTransform.cpp @@ -0,0 +1,137 @@ +#include +#include + +#include "WarpTransform.h" + +namespace Isis { + WarpTransform::WarpTransform(BasisFunction &basisLine, + BasisFunction &basisSamp, bool weighted, std::vector &inputLine, + std::vector &inputSample, std::vector &outputLine, + std::vector &outputSample, int inputLines, int inputSamples, + int outputLines, int outputSamples) { + // Determine the size of the output cube if necessary + // We do this by solving for output position given an input position + // then walk the edge of the input file to find the maximum output + // line/sample + if ((outputLines == 0) || (outputSamples == 0)) { + LeastSquares lsqOutputLine(basisLine); + LeastSquares lsqOutputSamp(basisSamp); + std::vector known; + known.resize(2); + for (int i=0; i<(int)inputLine.size(); i++) { + known[0] = inputLine[i]; + known[1] = inputSample[i]; + lsqOutputLine.AddKnown(known,outputLine[i]); + lsqOutputSamp.AddKnown(known,outputSample[i]); + } + + lsqOutputLine.Solve(); + lsqOutputSamp.Solve(); + + outputLines = 0; + outputSamples = 0; + // Walk top and bottom edge + for (int samp=1; samp<=inputSamples; samp++) { + known[0] = 1.0; + known[1] = samp; + int oline = (int) (lsqOutputLine.Evaluate(known) + 0.5); + int osamp = (int) (lsqOutputSamp.Evaluate(known) + 0.5); + if (oline > outputLines) outputLines = oline; + if (osamp > outputSamples) outputSamples = osamp; + + known[0] = inputLines; + known[1] = samp; + oline = (int) (lsqOutputLine.Evaluate(known) + 0.5); + osamp = (int) (lsqOutputSamp.Evaluate(known) + 0.5); + if (oline > outputLines) outputLines = oline; + if (osamp > outputSamples) outputSamples = osamp; + } + + // Walk left and right edge + for (int line=1; line<=inputLines; line++) { + known[0] = line; + known[1] = 1.0; + int oline = (int) (lsqOutputLine.Evaluate(known) + 0.5); + int osamp = (int) (lsqOutputSamp.Evaluate(known) + 0.5); + if (oline > outputLines) outputLines = oline; + if (osamp > outputSamples) outputSamples = osamp; + + known[0] = line; + known[1] = inputSamples; + oline = (int) (lsqOutputLine.Evaluate(known) + 0.5); + osamp = (int) (lsqOutputSamp.Evaluate(known) + 0.5); + if (oline > outputLines) outputLines = oline; + if (osamp > outputSamples) outputSamples = osamp; + } + } + + p_outputLines = outputLines; + p_outputSamples = outputSamples; + + // Create the equations for the control points using a least squares fit + p_lsqInputSamp = new LeastSquares(basisSamp); + p_lsqInputLine = new LeastSquares(basisLine); + std::vector known; + known.resize(2); + for (int i=0; i<(int)inputLine.size(); i++) { + known[0] = outputLine[i]; + known[1] = outputSample[i]; + p_lsqInputLine->AddKnown(known,inputLine[i]); + p_lsqInputSamp->AddKnown(known,inputSample[i]); + } + + p_lsqInputLine->Solve(); + p_lsqInputSamp->Solve(); + + p_weighted = weighted; + if (weighted) { + p_outputLine = outputLine; + p_outputSample = outputSample; + } + } + + WarpTransform::~WarpTransform() { + if (p_lsqInputLine != NULL) delete p_lsqInputLine; + if (p_lsqInputSamp != NULL) delete p_lsqInputSamp; + } + + + // Convert the requested output samp/line to an input samp/line + bool WarpTransform::Xform (double &inSample, double &inLine, + const double outSample, const double outLine) { + if (p_weighted) { + for (int i=0; i<(int) p_outputLine.size(); i++) { + double dist = (outLine - p_outputLine[i]) * + (outLine - p_outputLine[i]) + + (outSample - p_outputSample[i]) * + (outSample - p_outputSample[i]); + dist = sqrt(dist); + double weight = 1.0; + if (dist >= 0.001) weight = 1.0 / dist; + p_lsqInputLine->Weight(i,weight); + p_lsqInputSamp->Weight(i,weight); + } + p_lsqInputLine->Solve(); + p_lsqInputSamp->Solve(); + } + + static std::vector vars; + if (vars.size() != 2) vars.resize(2); + vars[0] = outLine; + vars[1] = outSample; + inLine = p_lsqInputLine->Evaluate(vars); + inSample = p_lsqInputSamp->Evaluate(vars); + return true; + } + + PvlGroup WarpTransform::Residuals () { + PvlGroup errs("Residuals"); + for (int i=0; iKnowns(); i++) { + PvlKeyword p("POINT"+iString(i+1)); + p += p_lsqInputLine->Residual(i); + p += p_lsqInputSamp->Residual(i); + errs += p; + } + return errs; + } +} diff --git a/isis/src/base/apps/warp/WarpTransform.h b/isis/src/base/apps/warp/WarpTransform.h new file mode 100644 index 0000000000000000000000000000000000000000..b090e3ba780c14ca44bdb99b333200971feb5188 --- /dev/null +++ b/isis/src/base/apps/warp/WarpTransform.h @@ -0,0 +1,41 @@ +#ifndef WarpTransform_h +#define WarpTransform_h + +#include +#include "Transform.h" +#include "BasisFunction.h" +#include "LeastSquares.h" +#include "PvlGroup.h" + +namespace Isis { +class WarpTransform : public Transform { + public: + WarpTransform(Isis::BasisFunction &basisLine, + Isis::BasisFunction &basisSamp, bool weighted, + std::vector &inputLine, std::vector &inputSample, + std::vector &outputLine, std::vector &outputSample, + int inputLines, int inputSamples, int outputLines, int outputSamples); + ~WarpTransform(); + + // Implementations for parent's pure virtual members + bool Xform (double &inSample, double &inLine, + const double outSample, const double outLine); + int OutputSamples () const { return p_outputSamples; }; + int OutputLines () const { return p_outputLines; }; + Isis::PvlGroup Residuals(); + + private: + int p_outputSamples; + int p_outputLines; + Isis::LeastSquares *p_lsqInputLine; + Isis::LeastSquares *p_lsqInputSamp; + + std::vector p_outputLine; + std::vector p_outputSample; + bool p_weighted; + }; + +} +#endif + + diff --git a/isis/src/base/apps/warp/assets/image/warp_example1.jpg b/isis/src/base/apps/warp/assets/image/warp_example1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3738765a5a0459a755627a777acddca337c8e11e Binary files /dev/null and b/isis/src/base/apps/warp/assets/image/warp_example1.jpg differ diff --git a/isis/src/base/apps/warp/assets/image/warp_example2.jpg b/isis/src/base/apps/warp/assets/image/warp_example2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a8a772007c46bb5570307ac34a0694ab186715e Binary files /dev/null and b/isis/src/base/apps/warp/assets/image/warp_example2.jpg differ diff --git a/isis/src/base/apps/warp/assets/image/warp_from.jpg b/isis/src/base/apps/warp/assets/image/warp_from.jpg new file mode 100644 index 0000000000000000000000000000000000000000..67c11031a8584784c0e05a3ec724551ee21437be Binary files /dev/null and b/isis/src/base/apps/warp/assets/image/warp_from.jpg differ diff --git a/isis/src/base/apps/warp/assets/thumb/warp_example1.jpg b/isis/src/base/apps/warp/assets/thumb/warp_example1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..16f9716e3ea90c5047d3dee8028e1fb9bdf93974 Binary files /dev/null and b/isis/src/base/apps/warp/assets/thumb/warp_example1.jpg differ diff --git a/isis/src/base/apps/warp/assets/thumb/warp_example2.jpg b/isis/src/base/apps/warp/assets/thumb/warp_example2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..652086945806e44c01038ff7b2f7ba665bb66abb Binary files /dev/null and b/isis/src/base/apps/warp/assets/thumb/warp_example2.jpg differ diff --git a/isis/src/base/apps/warp/assets/thumb/warp_from.jpg b/isis/src/base/apps/warp/assets/thumb/warp_from.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e1f46f44113fc855d2c14b4f817de7848f56d0d2 Binary files /dev/null and b/isis/src/base/apps/warp/assets/thumb/warp_from.jpg differ diff --git a/isis/src/base/apps/warp/assets/warp_example1.net b/isis/src/base/apps/warp/assets/warp_example1.net new file mode 100644 index 0000000000000000000000000000000000000000..1c144a9367c53ec2ad2717b252927e8625c54ae5 --- /dev/null +++ b/isis/src/base/apps/warp/assets/warp_example1.net @@ -0,0 +1,126 @@ +Object = ControlNetwork + NetworkId = "" + NetworkType = ImageToImage + TargetName = "" + UserName = "" + Created = "" + LastModified = "" + Description = "" + + Object = ControlPoint + PointType = Tie + PointId = "1" + + Group = ControlMeasure + SerialNumber = "M1" + MeasureType = Estimated + Sample = 1 + Line = 1 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + + Group = ControlMeasure + SerialNumber = "M2" + MeasureType = Estimated + Sample = 1 + Line = 20 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = "2" + + Group = ControlMeasure + SerialNumber = "M1" + MeasureType = Estimated + Sample = 100 + Line = 1 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + + Group = ControlMeasure + SerialNumber = "M2" + MeasureType = Estimated + Sample = 200 + Line = 1 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = "3" + + Group = ControlMeasure + SerialNumber = "M1" + MeasureType = Estimated + Sample = 1 + Line = 1000 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + + Group = ControlMeasure + SerialNumber = "M2" + MeasureType = Estimated + Sample = 800 + Line = 1000 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = "4" + + Group = ControlMeasure + SerialNumber = "M1" + MeasureType = Estimated + Sample = 100 + Line = 1000 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + + Group = ControlMeasure + SerialNumber = "M2" + MeasureType = Estimated + Sample = 1000 + Line = 800 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + End_Object + End_Object +End \ No newline at end of file diff --git a/isis/src/base/apps/warp/assets/warp_example2.net b/isis/src/base/apps/warp/assets/warp_example2.net new file mode 100644 index 0000000000000000000000000000000000000000..de48b366910eeb765febd700db67ff21dbb371be --- /dev/null +++ b/isis/src/base/apps/warp/assets/warp_example2.net @@ -0,0 +1,184 @@ +Object = ControlNetwork + NetworkId = "" + NetworkType = ImageToImage + TargetName = "" + UserName = "" + Created = "" + LastModified = "" + Description = "" + + Object = ControlPoint + PointType = Tie + PointId = "1" + + Group = ControlMeasure + SerialNumber = "M1" + MeasureType = Estimated + Sample = 1 + Line = 1 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + + Group = ControlMeasure + SerialNumber = "M2" + MeasureType = Estimated + Sample = 1 + Line = 1 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = "2" + + Group = ControlMeasure + SerialNumber = "M1" + MeasureType = Estimated + Sample = 100 + Line = 1 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + + Group = ControlMeasure + SerialNumber = "M2" + MeasureType = Estimated + Sample = 1000 + Line = 1 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = "3" + + Group = ControlMeasure + SerialNumber = "M1" + MeasureType = Estimated + Sample = 1 + Line = 500 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + + Group = ControlMeasure + SerialNumber = "M2" + MeasureType = Estimated + Sample = 250 + Line = 500 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = "4" + + Group = ControlMeasure + SerialNumber = "M1" + MeasureType = Estimated + Sample = 100 + Line = 500 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + + Group = ControlMeasure + SerialNumber = "M2" + MeasureType = Estimated + Sample = 750 + Line = 500 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = "5" + + Group = ControlMeasure + SerialNumber = "M1" + MeasureType = Estimated + Sample = 1 + Line = 1000 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + + Group = ControlMeasure + SerialNumber = "M2" + MeasureType = Estimated + Sample = 1 + Line = 1000 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + End_Object + + Object = ControlPoint + PointType = Tie + PointId = "6" + + Group = ControlMeasure + SerialNumber = "M1" + MeasureType = Estimated + Sample = 100 + Line = 1000 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + + Group = ControlMeasure + SerialNumber = "M2" + MeasureType = Estimated + Sample = 1000 + Line = 1000 + ErrorLine = 0.0 + ErrorSample = 0.0 + ErrorMagnitude = 0.0 + DateTime = "" + ChooserName = "" + End_Group + End_Object + End_Object +End \ No newline at end of file diff --git a/isis/src/base/apps/warp/tsts/Makefile b/isis/src/base/apps/warp/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/base/apps/warp/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/warp/tsts/user_nearest/Makefile b/isis/src/base/apps/warp/tsts/user_nearest/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..68bbc04480e5b532d37cfe9b41e28be4b4115cd6 --- /dev/null +++ b/isis/src/base/apps/warp/tsts/user_nearest/Makefile @@ -0,0 +1,11 @@ +APPNAME = warp + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/testCube.cub \ + to=$(OUTPUT)/warpTruth.cub \ + control=$(INPUT)/testCnet.txt \ + interp=nearestneighbor \ + osize=user \ + onl=200 ons=200 > /dev/null; diff --git a/isis/src/base/apps/warp/warp.cpp b/isis/src/base/apps/warp/warp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f134da939c5beef919ca5f32b39bf3649bf37be9 --- /dev/null +++ b/isis/src/base/apps/warp/warp.cpp @@ -0,0 +1,112 @@ +#include "Isis.h" + +#include +#include + +#include "ProcessRubberSheet.h" +#include "WarpTransform.h" +#include "PolynomialBivariate.h" +#include "UserInterface.h" +#include "ControlNet.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + // Warp an image + ProcessRubberSheet p; + + // Get the control point file + UserInterface &ui = Application::GetUserInterface(); + string cfile = ui.GetFilename("CONTROL"); + ControlNet cn(cfile); + + vector inputLine,inputSample,outputLine,outputSample; + for (int i=0; iLines(),icube->Samples(), + onl,ons); + + // Allocate the output file, same size as input + p.SetOutputCube ("TO",transform->OutputSamples(), + transform->OutputLines(), + icube->Bands()); + + // Set up the interpolator + Interpolator *interp; + if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { + interp = new Interpolator(Interpolator::NearestNeighborType); + } + else if (ui.GetString("INTERP") == "BILINEAR") { + interp = new Interpolator(Interpolator::BiLinearType); + } + else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { + interp = new Interpolator(Interpolator::CubicConvolutionType); + } + else { + string msg = "Unknow value for INTERP [" + + ui.GetString("INTERP") + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + p.StartProcess(*transform, *interp); + PvlGroup results = transform->Residuals(); + Application::Log(results); + p.EndProcess(); + + delete transform; + delete interp; + delete basisLine; + delete basisSamp; +} + diff --git a/isis/src/base/apps/warp/warp.xml b/isis/src/base/apps/warp/warp.xml new file mode 100644 index 0000000000000000000000000000000000000000..31edac55c152e123f3a9b3cc29275b632221382b --- /dev/null +++ b/isis/src/base/apps/warp/warp.xml @@ -0,0 +1,344 @@ + + + + + + Warp an image to another using control points + + + + This program warps images using a control net. + + + + + Original version + + + Converted to Isis 3.0 + + + Finished documentation and code + + + Added appTest + + + Added error checking for control networks + + + Fixed typo in user documentation + + + Removed references to CubeInfo + + + Updating documentation and adding examples + + + + + random + warp2 + + + + Geometry + + + + + + cube + input + + Input cube to warp + + + Use this parameter to select the filename. All bands within the file + will be warped unless a specific band is specified. + + + *.cub + + + + + cube + output + + Output cube + + + This file will contain the results of the warping. + + + + + filename + input + + Control Net file + + + This file will contain the control net used to find the translation. + + + *.net + + + + + + + integer + 1 + Order of polynomial + + The order of the polynomial to be used in the linear regression fit. + + 1 + + + + boolean + true + Weight the control points using distance + + The control points will be weighted based on distance if this option is selected. + If it is not selected, all control points will have a weight of 1, reguardless of distance. + + + + + string + Output cube size + MATCH + + This option determines how the size of the output cube is found. The choices are MATCH, + COMPUTE, and USER. The MATCH option matches the output cube size to the size of the + cube entered in the CUBE parameter. The COMPUTE option calculates the output cube + size from the control net file. The USER parameter allows the user to set the output cube + size by entering the sample and line values in the ONS and ONL parameters. The MATCH + option is the default. + + + + + + + + + + filename + input + Match Output cube to this Cube's Size + + The output cube will have the same dimensions as the cube entered here. + + + *.cub + + + + + integer + Output Lines + + The number of lines in the output cube. + + 1 + + + + integer + Output Samples + + The number of samples in the output cube. + + 1 + + + + + + string + + CUBICCONVOLUTION + + Type of interpolation + + This is the type of interpolation to be performed on the input. + + + + + + + + + + + + + Warp Example 1 + + Warp Example 1 + + + warp from=warp_from.cub to=warp_example1.cub control=warp_example1.net osize=user onl=1000 ons=1000 + + + This warp command will warp the from cube (warp_from.cub) which is a + 100Sx1000L image, to a 1000Sx1000L image and match the points from the + control points in warp_example1.net. + See the control net input file for more details. + + + + + Input image for warp + This is the input image for the warp examples. + + + FROM + + + + + + Output image for warp + This is the output image for this example of warp. + The control net file link below contains the points required to + create this kind of a warp output. + + + TO + + + + + + + Control net input file. + + + This is the require input for the CONTROL parameter. User can edit + this file to fit individual needs. In each control point there are + two measures. Measure 1 is the point on the from file you would + like to map to measure 2. + + + + + + + + + Warp Example 2 + + Warp Example 2 + + + warp from=warp_from.cub to=warp_example2.cub + control=warp_example2.net osize=user onl=1000 ons=1000 + + + This warp command will warp the from cube (warp_from.cub) which is a + 100Sx1000L image, to a 1000Sx1000L image and match the points from the + control points in warp_example1.net. + See the control net input file for more details. + + + + + Input image for warp + This is the input image for the warp examples. + + + FROM + + + + + + Output image for warp + This is the output image for this example of warp. + The control net file link below contains the points required to + create this kind of a warp output. + + + TO + + + + + + + Control net input file. + + + This is the require input for the CONTROL parameter. User can edit + this file to fit individual needs. In each control point there are + two measures. Measure 1 is the point on the from file you would + like to map to measure 2. + + + + + + + + + + + diff --git a/isis/src/base/objs/AdaptiveGruen/AdaptiveGruen.cpp b/isis/src/base/objs/AdaptiveGruen/AdaptiveGruen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6329d54a07cd4dae2425222419645a2794b61117 --- /dev/null +++ b/isis/src/base/objs/AdaptiveGruen/AdaptiveGruen.cpp @@ -0,0 +1,36 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/09 23:42:41 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "AdaptiveGruen.h" + +/** + * @brief AdaptiveGruen algorithm entry point for the plugin + * + * @param pvl Input registration config file containing algorithm parameters + * @return Isis::AutoReg* Returns a pointer to the plugin registration object + */ +extern "C" Isis::AutoReg *AdaptiveGruenPlugin (Isis::Pvl &pvl) { + return new Isis::AdaptiveGruen(pvl); +} + + diff --git a/isis/src/base/objs/AdaptiveGruen/AdaptiveGruen.h b/isis/src/base/objs/AdaptiveGruen/AdaptiveGruen.h new file mode 100644 index 0000000000000000000000000000000000000000..9bc613e12782c4684d5434d1e4b90ddb97098e87 --- /dev/null +++ b/isis/src/base/objs/AdaptiveGruen/AdaptiveGruen.h @@ -0,0 +1,78 @@ +#if !defined(AdaptiveGruen_h) +#define AdaptiveGruen_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/09 23:42:41 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Gruen.h" + +namespace Isis { + class Pvl; + + /** + * @brief Gruen (adaptive) pattern matching + * + * The AdaptiveGruen pattern/search chip registration algorithm is derived + * from the Gruen class. It is adaptive in that it uses an Affine transform + * to load the subsearch chip from the search chip. The Affine transform is + * iteratively minimized to converge on an cummulative affine solution that + * best matches the pattern chip. + * + * @ingroup PatternMatching + * + * @see Gruen AutoReg MinimumGruen + * + * @author 2009-09-09 Kris Becker + * + * @internal + */ + class AdaptiveGruen : public Gruen { + public: + /** + * @brief Construct a AdaptiveGruen search algorithm + * + * This will construct an AdaptiveGruen search algorithm. It is + * recommended that you use a AutoRegFactory class as opposed to this + * constructor + * + * @param pvl A Pvl object that contains a valid automatic registration + * definition + */ + AdaptiveGruen (Pvl &pvl) : Gruen(pvl) { } + + /** Destructor for AdaptiveGruen */ + virtual ~AdaptiveGruen() {} + + /** + * AdaptiveGruen is adaptive + */ + virtual bool IsAdaptive() { return (true); } + + protected: + /** Return name of Algorithm */ + virtual std::string AlgorithmName() const {return ("AdaptiveGruen");} + + + }; +}; + +#endif diff --git a/isis/src/base/objs/AdaptiveGruen/AdaptiveGruen.truth b/isis/src/base/objs/AdaptiveGruen/AdaptiveGruen.truth new file mode 100644 index 0000000000000000000000000000000000000000..818d106548721a623b34d245ac22db9216fc5523 --- /dev/null +++ b/isis/src/base/objs/AdaptiveGruen/AdaptiveGruen.truth @@ -0,0 +1,22 @@ +Object = AutoRegistration + Group = Algorithm + Name = AdaptiveGruen + Tolerance = 100.0 + AffineTranslationTolerance = 0.2 + AffineScaleTolerance = 0.7 + MaximumIterations = 30 + End_Group + + Group = PatternChip + Samples = 15 + Lines = 15 + End_Group + + Group = SearchChip + Samples = 30 + Lines = 30 + End_Group +End_Object +End +Register = 0 +Position = 512.195 512.085 diff --git a/isis/src/base/objs/AdaptiveGruen/AutoReg.plugin b/isis/src/base/objs/AdaptiveGruen/AutoReg.plugin new file mode 100644 index 0000000000000000000000000000000000000000..a715aee322cb902a71bb29db0066bd351c66162f --- /dev/null +++ b/isis/src/base/objs/AdaptiveGruen/AutoReg.plugin @@ -0,0 +1,5 @@ +Group = AdaptiveGruen + Library = AdaptiveGruen + Routine = AdaptiveGruenPlugin +End_Group + diff --git a/isis/src/base/objs/AdaptiveGruen/Makefile b/isis/src/base/objs/AdaptiveGruen/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ddbf72eef9fb5f79634c7f1aeafc520f12fe53d3 --- /dev/null +++ b/isis/src/base/objs/AdaptiveGruen/Makefile @@ -0,0 +1,6 @@ +INCS = AdaptiveGruen.h +SRCS = AdaptiveGruen.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/base/objs/AdaptiveGruen/unitTest.cpp b/isis/src/base/objs/AdaptiveGruen/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e996f57f51260d5694137fd56e0dedbabbb2247 --- /dev/null +++ b/isis/src/base/objs/AdaptiveGruen/unitTest.cpp @@ -0,0 +1,72 @@ +#include +#include + +#include "AutoReg.h" +#include "AutoRegFactory.h" +#include "Chip.h" +#include "Cube.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + try { + PvlGroup alg("Algorithm"); + alg += PvlKeyword("Name","AdaptiveGruen"); + alg += PvlKeyword("Tolerance",100.0); + alg += PvlKeyword("AffineTranslationTolerance",0.2); + alg += PvlKeyword("AffineScaleTolerance",0.7); + alg += PvlKeyword("MaximumIterations",30); + + PvlGroup pchip("PatternChip"); + pchip += PvlKeyword("Samples",15); + pchip += PvlKeyword("Lines",15); + + PvlGroup schip("SearchChip"); + schip += PvlKeyword("Samples",30); + schip += PvlKeyword("Lines",30); + + PvlObject o("AutoRegistration"); + o.AddGroup(alg); + o.AddGroup(pchip); + o.AddGroup(schip); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl; + + AutoReg *ar = AutoRegFactory::Create(pvl); + + Cube p; + p.Open("$messenger/testData/EW0131770376G.equi.cub"); + + Cube s; + s.Open("$messenger/testData/EW0131770381F.equi.cub"); + + ar->SearchChip()->TackCube(512.0, 512.0); + ar->SearchChip()->Load(s); + ar->PatternChip()->TackCube(512.0, 512.0); + ar->PatternChip()->Load(p); + + std::cout << "Register = " << ar->Register() << std::endl; + std::cout << "Position = " << ar->CubeSample() << " " << + ar->CubeLine() << std::endl; + + +#if defined(FULL_DISCLOSURE) + Pvl pstat = ar->RegistrationStatistics(); + std::cout << "\n\n" << pstat << std::endl; +#endif + + + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/Affine/Affine.cpp b/isis/src/base/objs/Affine/Affine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c31db79a67c0eebc584c9ce9639afba37d09486 --- /dev/null +++ b/isis/src/base/objs/Affine/Affine.cpp @@ -0,0 +1,315 @@ +/** + * @file + * $Revision: 1.7 $ + * $Date: 2009/12/22 02:09:54 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "jama/jama_svd.h" + +#include "Affine.h" +#include "PolynomialBivariate.h" +#include "LeastSquares.h" +#include "iException.h" +#include "Constants.h" + +using namespace std; + +namespace Isis { + /** + * Constructs an Affine transform. The default transform is + * the identity. + */ + Affine::Affine () { + Identity(); + p_x = p_y = p_xp = p_yp = 0.0; + } + + /** + * @brief Create Affine transform from matrix + * + * This constructor creates the affine transform from a forward matrix. The + * input matrix is checked for the proper dimensions (3x3) and is then + * inverted to complete the inverse functionality. + * + * The input matrix must be invertable or an exception will be thrown! + * + * @param a Forward affine matrix + */ + Affine::Affine(const Affine::AMatrix &a) { + checkDims(a); + p_matrix = a.copy(); + p_invmat = invert(p_matrix); + p_x = p_y = p_xp = p_yp = 0.0; + } + + //! Destroys the Affine object + Affine::~Affine() {} + + /** + * @brief Return an Affine identity matrix + * + * @return Affine::AMatrix The identity matrix + */ + Affine::AMatrix Affine::getIdentity() { + AMatrix ident(3,3, 0.0); + for (int i = 0 ; i < ident.dim2() ; i++) { + ident[i][i] = 1.0; + } + return (ident); + } + + /** + * Set the forward and inverse affine transform to the identity. + * That is, xp = x and yp = y for all (x,y). + */ + void Affine::Identity() { + p_matrix = getIdentity(); + p_invmat = getIdentity(); + } + + /** + * Given a set of coordinate pairs (n >= 3), compute the affine + * transform that best fits the points. If given exactly three + * coordinates that are not colinear, the fit will be guarenteed + * to be exact through the points. + * + * @param x The transformation x coordinates + * @param y The transformation y coordinates + * @param xp The transformation xp coordinates + * @param yp The transformation yp coordinates + * @param n The number of coordiante pairs + * + * @throws Isis::iException::Math - Affine transform not invertible + */ + void Affine::Solve (const double x[], const double y[], + const double xp[], const double yp[], int n) { + // We must solve two least squares equations + PolynomialBivariate xpFunc(1); + PolynomialBivariate ypFunc(1); + LeastSquares xpLSQ(xpFunc); + LeastSquares ypLSQ(ypFunc); + + // Push the knowns into the least squares class + for (int i=0; i coord(2); + coord[0] = x[i]; + coord[1] = y[i]; + xpLSQ.AddKnown(coord,xp[i]); + ypLSQ.AddKnown(coord,yp[i]); + } + + // Solve for A,B,C,D,E,F + xpLSQ.Solve(); + ypLSQ.Solve(); + + // Construct our affine matrix + p_matrix[0][0] = xpFunc.Coefficient(1); // A + p_matrix[0][1] = xpFunc.Coefficient(2); // B + p_matrix[0][2] = xpFunc.Coefficient(0); // C + p_matrix[1][0] = ypFunc.Coefficient(1); // D + p_matrix[1][1] = ypFunc.Coefficient(2); // E + p_matrix[1][2] = ypFunc.Coefficient(0); // F + p_matrix[2][0] = 0.0; + p_matrix[2][1] = 0.0; + p_matrix[2][2] = 1.0; + + // invert the matrix + p_invmat = invert(p_matrix); + } + + /** + * Apply a translation to the current affine transform + * + * @param tx translatation to add to x' + * @param ty translation to add to y' + */ + void Affine::Translate (double tx, double ty) { + AMatrix trans = getIdentity(); + + trans[0][2] = tx; + trans[1][2] = ty; + p_matrix = TNT::matmult(trans,p_matrix); + + trans[0][2] = -tx; + trans[1][2] = -ty; + p_invmat = TNT::matmult(p_invmat,trans); + } + + /** + * Apply a translation to the current affine transform + * + * @param angle degrees of counterclockwise rotation + */ + void Affine::Rotate(double angle) { + AMatrix rot = getIdentity(); + + double angleRadians = angle * Isis::PI / 180.0; + rot[0][0] = cos(angleRadians); + rot[0][1] = -sin(angleRadians); + rot[1][0] = sin(angleRadians); + rot[1][1] = cos(angleRadians); + p_matrix = TNT::matmult(rot,p_matrix); + + angleRadians = -angleRadians; + rot[0][0] = cos(angleRadians); + rot[0][1] = -sin(angleRadians); + rot[1][0] = sin(angleRadians); + rot[1][1] = cos(angleRadians); + p_invmat = TNT::matmult(p_invmat,rot); + } + + /** + * Apply a scale to the current affine transform + * + * @param scaleFactor The scale factor + */ + void Affine::Scale (double scaleFactor) { + AMatrix scale = getIdentity(); + scale[0][0] = scaleFactor; + scale[1][1] = scaleFactor; + p_matrix = TNT::matmult(scale,p_matrix); + + scale[0][0] = scaleFactor; + scale[1][1] = scaleFactor; + p_invmat = TNT::matmult(p_invmat,scale); + } + + /** + * Compute (xp,yp) given (x,y). Use the methods xp() and yp() to + * obtain the results. + * + * @param x The transformation x factor + * @param y The transformation y factor + */ + void Affine::Compute(double x, double y) { + p_x = x; + p_y = y; + p_xp = p_matrix[0][0] * x + p_matrix[0][1] * y + p_matrix[0][2]; + p_yp = p_matrix[1][0] * x + p_matrix[1][1] * y + p_matrix[1][2]; + } + + /** + * Compute (x,y) given (xp,yp). Use the methods x() and y() to + * obtain the results. + * + * @param xp The inverse transformation xp factor + * @param yp The inverse transformation yp factor + */ + void Affine::ComputeInverse(double xp, double yp) { + p_xp = xp; + p_yp = yp; + p_x = p_invmat[0][0] * xp + p_invmat[0][1] * yp + p_invmat[0][2]; + p_y = p_invmat[1][0] * xp + p_invmat[1][1] * yp + p_invmat[1][2]; + } + + /** + * Return the affine coeffients for the entered variable (1 or 2). The coefficients + * are returned in a 3-dimensional vector + * + * @param var The coefficient vector index (1 or 2) + */ + vector Affine::Coefficients( int var ) { + int index = var-1; + vector coef; + coef.push_back(p_matrix[index][0]); + coef.push_back(p_matrix[index][1]); + coef.push_back(p_matrix[index][2]); + return coef; + } + + /** + * Return the inverse affine coeffients for the entered variable (1 or 2). + * The coefficients are returned in a 3-dimensional vector + * + * @param var The inverse coefficient vector index + */ + vector Affine::InverseCoefficients( int var ) { + int index = var-1; + vector coef; + coef.push_back(p_invmat[index][0]); + coef.push_back(p_invmat[index][1]); + coef.push_back(p_invmat[index][2]); + return coef; + } + + /** + * @brief Checks affine matrix to ensure it is a 3x3 standard form transform + * + * @param am Affine matrix to validate + */ + void Affine::checkDims(const AMatrix &am) const throw (iException &) { + if ((am.dim1() != 3) && (am.dim2() != 3)) { + ostringstream mess; + mess << "Affine matrices must be 3x3 - this one is " << am.dim1() + << "x" << am.dim2(); + throw iException::Message(iException::Programmer, mess.str(), _FILEINFO_); + } + return; + } + + /** + * @brief Compute the inverse of a matrix + * + * This method will compute the inverse of an affine matrix for purposes of + * forward and inverse Affine computations. + * + * @param a Matrix to invert + * + * @return Affine::AMatrix The inverted matrix + */ + Affine::AMatrix Affine::invert(const AMatrix &a) const throw (iException &) { + // Now compute the inverse affine matrix using singular value + // decomposition A = USV'. So invA = V invS U'. Where ' represents + // the transpose of a matrix and invS is S with the recipricol of the + // diagonal elements + JAMA::SVD svd(a); + + AMatrix V; + svd.getV(V); + + // The inverse of S is 1 over each diagonal element of S + AMatrix invS; + svd.getS(invS); + for (int i=0; i +#include "tnt/tnt_array2d.h" +#include "iException.h" + +namespace Isis { +/** + * @brief Affine basis function + * + * An affine transform in two-dimensional space is defined as + * + * @code + * x' = Ax + By + C + * y' = Dx + Ey + F + * @endcode + * + * This routine allows the programmer to define three or more + * mappings from (x,y) to (x',y') and will solve for A,B,C,D,E,F. + * + * If the above coefficients can be computed then the inverse of + * the affine transform exists and will be computed such that + * + * @code + * x = A'x' + B'y' + C' + * y = D'x' + E'y' + F' + * @endcode + * + * Alternatively (or in combination), translations and rotations + * can be applied to create a transform. + * + * @see http://www.gnome.org/~mathieu/libart/libart-affine-transformation-matrices.html + * + * @ingroup Math + * + * @author 2005-03-24 Jeff Anderson + * + * @internal + * @todo Allow the programmer to apply scale and shear. + * @todo Write multiplaction method (operator*) for Affine * Affine. + * + * @history 2006-08-03 Tracie Sucharski, Added Scale method + * @history 2007-07-12 Debbie A. Cook, Added methods Coefficients + * and InverseCoefficients + * @history 2008-06-18 Christopher Austin - Added documentation + * @history 2008-10-29 Steven Lambright - Corrected usage of std::vector, + * problem pointed out by "novas0x2a" (Support Forum + * Member) + * @history 2009-07-24 Kris Becker Introduced the AMatrix typedef; added new + * constructor that accepts an AMatrix; added static method to return + * an Affine identity matrix; added methods to retrieve forward and + * inverse AMatrixs; added new method that inverts the matrix. + * + */ + + class Affine { + public: + typedef TNT::Array2D AMatrix; + Affine (); + Affine(const AMatrix &a); + ~Affine (); + void Solve (const double x[], const double y[], + const double xp[], const double yp[], int n); + static AMatrix getIdentity(); + void Identity (); + void Translate (double tx, double ty); + void Rotate(double rot); + void Scale(double scaleFactor); + + void Compute(double x, double y); + + //! Returns the computed x' + double xp() const { return p_xp; }; + + //! Returns the computed y' + double yp() const { return p_yp; }; + + void ComputeInverse(double xp, double yp); + + //! Returns the computed x + double x() const { return p_x; }; + + //! Returns the computed y + double y() const { return p_y; }; + + std::vector Coefficients( int var ); + std::vector InverseCoefficients( int var ); + //! Returns the forward Affine matrix + AMatrix Forward() const { return (p_matrix.copy()); } + //! Returns the inverse Affine matrix + AMatrix Inverse() const { return (p_invmat.copy()); } + + private: + AMatrix p_matrix; //!< Affine forward matrix + AMatrix p_invmat; //!< Affine inverse matrix + + double p_x; //!< x value of the (x,y) coordinate + double p_y; //!< y value of the (x,y) coordinate + double p_xp; //!< x' value of the (x',y') coordinate + double p_yp; //!< y' value of the (x',y') coordinate + + void checkDims(const AMatrix &am) const throw (iException &); + AMatrix invert(const AMatrix &a) const throw (iException &); + }; +}; + +#endif + diff --git a/isis/src/base/objs/Affine/Affine.truth b/isis/src/base/objs/Affine/Affine.truth new file mode 100644 index 0000000000000000000000000000000000000000..7f4a137baea8878fb4eaa53bb2b0e5d13c54d20d --- /dev/null +++ b/isis/src/base/objs/Affine/Affine.truth @@ -0,0 +1,77 @@ + +1.0 +-1.0 +0.0 +0.0 +--- +-1.0 +0.0 +0.0 +1.0 +--- +Forward: 1.0, 1.0 +3.0 +3.0 +Inverse: 3.0,3.0 +1.0 +1.0 +--- +Forward: 3.0, 3.0 +1.0 +1.0 +Inverse: 1.0,1.0 +3.0 +3.0 +--- +Forward: 1.0, 3.0 +3.0 +1.0 +Inverse: 3.0,1.0 +1.0 +3.0 +--- +Forward: 3.0, 1.0 +1.0 +3.0 +Inverse: 1.0,3.0 +3.0 +1.0 +--- +-1.0 +0.0 +4.0 +--- +0.0 +-1.0 +4.0 +--- +-1.0 +-0.0 +4.0 +--- +0.0 +-1.0 +4.0 +--- +Forward Matrix +3 3 +-1.0 0.0 4.0 +0.0 -1.0 4.0 +0.0 0.0 1.0 + + +Inverse Matrix +3 3 +-1.0 -0.0 4.0 +0.0 -1.0 4.0 +0.0 0.0 1.0 + + +Matrix Constructor +Forward: 1.0, 3.0 +3.0 +1.0 +Inverse: 3.0,1.0 +1.0 +3.0 +--- diff --git a/isis/src/base/objs/Affine/Affine_Darwin_powerpc.truth b/isis/src/base/objs/Affine/Affine_Darwin_powerpc.truth new file mode 100644 index 0000000000000000000000000000000000000000..6a3b70365481d02ce998caf971c838f097dafd33 --- /dev/null +++ b/isis/src/base/objs/Affine/Affine_Darwin_powerpc.truth @@ -0,0 +1,77 @@ + +1.0 +-1.0 +0.0 +0.0 +--- +-1.0 +0.0 +0.0 +1.0 +--- +Forward: 1.0, 1.0 +3.0 +3.0 +Inverse: 3.0,3.0 +1.0 +1.0 +--- +Forward: 3.0, 3.0 +1.0 +1.0 +Inverse: 1.0,1.0 +3.0 +3.0 +--- +Forward: 1.0, 3.0 +3.0 +1.0 +Inverse: 3.0,1.0 +1.0 +3.0 +--- +Forward: 3.0, 1.0 +1.0 +3.0 +Inverse: 1.0,3.0 +3.0 +1.0 +--- +-1.0 +-0.0 +4.0 +--- +-0.0 +-1.0 +4.0 +--- +-1.0 +0.0 +4.0 +--- +0.0 +-1.0 +4.0 +--- +Forward Matrix +3 3 +-1.0 -0.0 4.0 +-0.0 -1.0 4.0 +0.0 0.0 1.0 + + +Inverse Matrix +3 3 +-1.0 0.0 4.0 +0.0 -1.0 4.0 +0.0 0.0 1.0 + + +Matrix Constructor +Forward: 1.0, 3.0 +3.0 +1.0 +Inverse: 3.0,1.0 +1.0 +3.0 +--- diff --git a/isis/src/base/objs/Affine/Affine_Linux_i686_RedHat5_4.truth b/isis/src/base/objs/Affine/Affine_Linux_i686_RedHat5_4.truth new file mode 100644 index 0000000000000000000000000000000000000000..17d7027354988c2624546cdaa6cb2bfcb06db702 --- /dev/null +++ b/isis/src/base/objs/Affine/Affine_Linux_i686_RedHat5_4.truth @@ -0,0 +1,77 @@ + +1.0 +-1.0 +0.0 +0.0 +--- +-1.0 +0.0 +0.0 +1.0 +--- +Forward: 1.0, 1.0 +3.0 +3.0 +Inverse: 3.0,3.0 +1.0 +1.0 +--- +Forward: 3.0, 3.0 +1.0 +1.0 +Inverse: 1.0,1.0 +3.0 +3.0 +--- +Forward: 1.0, 3.0 +3.0 +1.0 +Inverse: 3.0,1.0 +1.0 +3.0 +--- +Forward: 3.0, 1.0 +1.0 +3.0 +Inverse: 1.0,3.0 +3.0 +1.0 +--- +-1.0 +0.0 +4.0 +--- +-0.0 +-1.0 +4.0 +--- +-1.0 +-0.0 +4.0 +--- +-0.0 +-1.0 +4.0 +--- +Forward Matrix +3 3 +-1.0 0.0 4.0 +-0.0 -1.0 4.0 +0.0 0.0 1.0 + + +Inverse Matrix +3 3 +-1.0 -0.0 4.0 +-0.0 -1.0 4.0 +-0.0 0.0 1.0 + + +Matrix Constructor +Forward: 1.0, 3.0 +3.0 +1.0 +Inverse: 3.0,1.0 +1.0 +3.0 +--- diff --git a/isis/src/base/objs/Affine/Affine_Linux_i686_RedHat5_5.truth b/isis/src/base/objs/Affine/Affine_Linux_i686_RedHat5_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..17d7027354988c2624546cdaa6cb2bfcb06db702 --- /dev/null +++ b/isis/src/base/objs/Affine/Affine_Linux_i686_RedHat5_5.truth @@ -0,0 +1,77 @@ + +1.0 +-1.0 +0.0 +0.0 +--- +-1.0 +0.0 +0.0 +1.0 +--- +Forward: 1.0, 1.0 +3.0 +3.0 +Inverse: 3.0,3.0 +1.0 +1.0 +--- +Forward: 3.0, 3.0 +1.0 +1.0 +Inverse: 1.0,1.0 +3.0 +3.0 +--- +Forward: 1.0, 3.0 +3.0 +1.0 +Inverse: 3.0,1.0 +1.0 +3.0 +--- +Forward: 3.0, 1.0 +1.0 +3.0 +Inverse: 1.0,3.0 +3.0 +1.0 +--- +-1.0 +0.0 +4.0 +--- +-0.0 +-1.0 +4.0 +--- +-1.0 +-0.0 +4.0 +--- +-0.0 +-1.0 +4.0 +--- +Forward Matrix +3 3 +-1.0 0.0 4.0 +-0.0 -1.0 4.0 +0.0 0.0 1.0 + + +Inverse Matrix +3 3 +-1.0 -0.0 4.0 +-0.0 -1.0 4.0 +-0.0 0.0 1.0 + + +Matrix Constructor +Forward: 1.0, 3.0 +3.0 +1.0 +Inverse: 3.0,1.0 +1.0 +3.0 +--- diff --git a/isis/src/base/objs/Affine/Affine_Linux_i686_SUSE10_1.truth b/isis/src/base/objs/Affine/Affine_Linux_i686_SUSE10_1.truth new file mode 100644 index 0000000000000000000000000000000000000000..17d7027354988c2624546cdaa6cb2bfcb06db702 --- /dev/null +++ b/isis/src/base/objs/Affine/Affine_Linux_i686_SUSE10_1.truth @@ -0,0 +1,77 @@ + +1.0 +-1.0 +0.0 +0.0 +--- +-1.0 +0.0 +0.0 +1.0 +--- +Forward: 1.0, 1.0 +3.0 +3.0 +Inverse: 3.0,3.0 +1.0 +1.0 +--- +Forward: 3.0, 3.0 +1.0 +1.0 +Inverse: 1.0,1.0 +3.0 +3.0 +--- +Forward: 1.0, 3.0 +3.0 +1.0 +Inverse: 3.0,1.0 +1.0 +3.0 +--- +Forward: 3.0, 1.0 +1.0 +3.0 +Inverse: 1.0,3.0 +3.0 +1.0 +--- +-1.0 +0.0 +4.0 +--- +-0.0 +-1.0 +4.0 +--- +-1.0 +-0.0 +4.0 +--- +-0.0 +-1.0 +4.0 +--- +Forward Matrix +3 3 +-1.0 0.0 4.0 +-0.0 -1.0 4.0 +0.0 0.0 1.0 + + +Inverse Matrix +3 3 +-1.0 -0.0 4.0 +-0.0 -1.0 4.0 +-0.0 0.0 1.0 + + +Matrix Constructor +Forward: 1.0, 3.0 +3.0 +1.0 +Inverse: 3.0,1.0 +1.0 +3.0 +--- diff --git a/isis/src/base/objs/Affine/Makefile b/isis/src/base/objs/Affine/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..048ec2faccabb82bef651799c1c664345037ea9c --- /dev/null +++ b/isis/src/base/objs/Affine/Makefile @@ -0,0 +1,5 @@ +INCS = Affine.h +SRCS = Affine.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Affine/unitTest.cpp b/isis/src/base/objs/Affine/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50207d23bb82ece55d060c99c5b6b7ece69a9cd0 --- /dev/null +++ b/isis/src/base/objs/Affine/unitTest.cpp @@ -0,0 +1,132 @@ +#include +#include + +#include "Affine.h" +#include "Preference.h" +#include "tnt/tnt_array2d_utils.h" + +using namespace std; +using namespace TNT; + +int main () { + typedef Isis::Affine::AMatrix AMatrix; + Isis::Preference::Preferences(true); + + Isis::Affine a; + + // Test translate + a.Translate (1.0,-1.0); + a.Compute(0.0,0.0); + std::cout << setprecision(1) << std::endl; + std::cout << std::fixed << a.xp() << std::endl; + std::cout << std::fixed << a.yp() << std::endl; + a.ComputeInverse(a.xp(),a.yp()); + std::cout << std::fixed << a.x() << std::endl; + std::cout << std::fixed << a.y() << std::endl; + std::cout << "---" << std::endl; + + // Test rotate + a.Identity(); + a.Rotate(90.0); + a.Compute(0.0,1.0); + std::cout << std::fixed << a.xp() << std::endl; + std::cout << std::fixed << a.yp() << std::endl; + a.ComputeInverse(a.xp(),a.yp()); + std::cout << std::fixed << a.x() << std::endl; + std::cout << std::fixed << a.y() << std::endl; + std::cout << "---" << std::endl; + + // Test solve (1,1)->(3,3) (3,3)->(1,1), (1,3)->(3,1) + double x[] = { 1.0, 3.0, 1.0 }; + double y[] = { 1.0, 3.0, 3.0 }; + double xp[] = { 3.0, 1.0, 3.0 }; + double yp[] = { 3.0, 1.0, 1.0 }; + + a.Solve(x,y,xp,yp,3); + std::cout << "Forward: 1.0, 1.0\n"; + a.Compute(1.0,1.0); + std::cout << std::fixed << a.xp() << std::endl; + std::cout << std::fixed << a.yp() << std::endl; + std::cout << "Inverse: " << a.xp() << "," << a.yp() << std::endl; + a.ComputeInverse(a.xp(),a.yp()); + std::cout << std::fixed << a.x() << std::endl; + std::cout << std::fixed << a.y() << std::endl; + std::cout << "---" << std::endl; + + std::cout << "Forward: 3.0, 3.0\n"; + a.Compute(3.0,3.0); + std::cout << std::fixed << a.xp() << std::endl; + std::cout << std::fixed << a.yp() << std::endl; + std::cout << "Inverse: " << a.xp() << "," << a.yp() << std::endl; + a.ComputeInverse(a.xp(),a.yp()); + std::cout << std::fixed << a.x() << std::endl; + std::cout << std::fixed << a.y() << std::endl; + std::cout << "---" << std::endl; + + std::cout << "Forward: 1.0, 3.0\n"; + a.Compute(1.0,3.0); + std::cout << std::fixed << a.xp() << std::endl; + std::cout << std::fixed << a.yp() << std::endl; + std::cout << "Inverse: " << a.xp() << "," << a.yp() << std::endl; + a.ComputeInverse(a.xp(),a.yp()); + std::cout << std::fixed << a.x() << std::endl; + std::cout << std::fixed << a.y() << std::endl; + std::cout << "---" << std::endl; + + std::cout << "Forward: 3.0, 1.0\n"; + a.Compute(3.0,1.0); + std::cout << std::fixed << a.xp() << std::endl; + std::cout << std::fixed << a.yp() << std::endl; + std::cout << "Inverse: " << a.xp() << "," << a.yp() << std::endl; + a.ComputeInverse(a.xp(),a.yp()); + std::cout << std::fixed << a.x() << std::endl; + std::cout << std::fixed << a.y() << std::endl; + std::cout << "---" << std::endl; + + // Test Coefficients + vector xcoef = a.Coefficients(1); + std::cout << std::fixed << xcoef[0] << std::endl; + std::cout << std::fixed << xcoef[1] << std::endl; + std::cout << std::fixed << xcoef[2] << std::endl; + std::cout << "---" << std::endl; + + vector ycoef = a.Coefficients(2); + std::cout << std::fixed << ycoef[0] << std::endl; + std::cout << std::fixed << ycoef[1] << std::endl; + std::cout << std::fixed << ycoef[2] << std::endl; + std::cout << "---" << std::endl; + + // Test InverseCoefficients + vector xpcoef = a.InverseCoefficients(1); + std::cout << std::fixed << xpcoef[0] << std::endl; + std::cout << std::fixed << xpcoef[1] << std::endl; + std::cout << std::fixed << xpcoef[2] << std::endl; + std::cout << "---" << std::endl; + + vector ypcoef = a.InverseCoefficients(2); + std::cout << std::fixed << ypcoef[0] << std::endl; + std::cout << std::fixed << ypcoef[1] << std::endl; + std::cout << std::fixed << ypcoef[2] << std::endl; + std::cout << "---" << std::endl; + + // Test AMatrix elements + AMatrix forward = a.Forward(); + std::cout << "Forward Matrix\n" << forward << std::endl; + AMatrix inverse = a.Inverse(); + std::cout << "\nInverse Matrix\n" << inverse << std::endl; + + // Matrix constructor + std::cout << "\nMatrix Constructor\n"; + Isis::Affine b(forward); + std::cout << "Forward: 1.0, 3.0\n"; + b.Compute(1.0,3.0); + std::cout << std::fixed << b.xp() << std::endl; + std::cout << std::fixed << b.yp() << std::endl; + std::cout << "Inverse: " << b.xp() << "," << b.yp() << std::endl; + a.ComputeInverse(b.xp(),b.yp()); + std::cout << std::fixed << b.x() << std::endl; + std::cout << std::fixed << b.y() << std::endl; + std::cout << "---" << std::endl; + + +} diff --git a/isis/src/base/objs/Albedo/Albedo.cpp b/isis/src/base/objs/Albedo/Albedo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e3afdb24ba58ac2d8f8580eaa75e3bb969f847e --- /dev/null +++ b/isis/src/base/objs/Albedo/Albedo.cpp @@ -0,0 +1,137 @@ +#include "Albedo.h" +#include "SpecialPixel.h" +#include "iException.h" + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) + +namespace Isis { + Albedo::Albedo (Pvl &pvl, PhotoModel &pmodel) : NormModel(pvl,pmodel) { + PvlGroup &algorithm = pvl.FindObject("NormalizationModel").FindGroup("Algorithm", Pvl::Traverse); + + SetNormIncref(0.0); + SetNormIncmat(0.0); + SetNormThresh(30.0); + SetNormAlbedo(1.0); + + // Get value from user + if (algorithm.HasKeyword("Incref")) { + SetNormIncref(algorithm["Incref"]); + } + + if (algorithm.HasKeyword("Incmat")) { + SetNormIncmat(algorithm["Incmat"]); + } + + if (algorithm.HasKeyword("Thresh")) { + SetNormThresh(algorithm["Thresh"]); + } + + if (algorithm.HasKeyword("Albedo")) { + SetNormAlbedo(algorithm["Albedo"]); + } + + // Calculate normalization at standard conditions + GetPhotoModel()->SetStandardConditions(true); + p_normPsurfref = GetPhotoModel()->CalcSurfAlbedo(p_normIncref, p_normIncref, 0.0); + GetPhotoModel()->SetStandardConditions(false); + } + + void Albedo::NormModelAlgorithm (double phase, double incidence, + double emission, double dn, double &albedo, double &mult, + double &base) + { + double psurf; + double result; + + // code for scaling each pixel + psurf = GetPhotoModel()->CalcSurfAlbedo(phase, incidence, emission); + + // thresh is a parameter limiting how much we amplify the dns + if (p_normPsurfref > psurf*p_normThresh) { + result = NULL8; + albedo = NULL8; + mult = 0.0; + base = 0.0; + } + else { + if (psurf == 0.0) { + std::string msg = "Divide by zero error"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + else { + result = dn * p_normPsurfref / psurf; + albedo = result; + mult = p_normPsurfref / psurf; + base = 0.0; + } + } + } + + /** + * Set the normalization function parameter. This is the + * reference incidence angle to which the image photometry will + * be normalized. This parameter is limited to values that are + * >=0 and <90. + * + * @param incref Normalization function parameter, default + * is 0.0 + */ + void Albedo::SetNormIncref (const double incref) { + if (incref < 0.0 || incref >= 90.0) { + std::string msg = "Invalid value of normalization incref [" + + iString(incref) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_normIncref = incref; + } + + /** + * Set the normalization function parameter. This + * parameter is limited to values that are >=0 and <90. + * + * @param incmat Normalization function parameter, default is 0.0 + */ + void Albedo::SetNormIncmat (const double incmat) { + if (incmat < 0.0 || incmat >= 90.0) { + std::string msg = "Invalid value of normalization incmat [" + + iString(incmat) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_normIncmat = incmat; + } + + /** + * Set the normalization function parameter. This is + * the albedo that the image will be normalized to have. To + * construct mosaics, the same value of albedo should be used + * for all images to achieve a uniform result. + * + * @param albedo Normalization function parameter + */ + void Albedo::SetNormAlbedo (const double albedo) { + p_normAlbedo = albedo; + } + + /** + * Set the normalization function parameter. It is + * used to amplify variations in the input image in regions + * of small incidence angle where the shading in the input + * image is weak. This parameter sets the upper limit on the + * amount of amplification that will be attempted. If it is + * set too low, low incidence areas of the image may appear + * bland. If it is set too high, then low incidence areas of + * the image may contain amplified noise rather than useful + * shading information. + * + * @param thresh Normalization function parameter, default + * is 30.0 + */ + void Albedo::SetNormThresh (const double thresh) { + p_normThresh = thresh; + } +} + +extern "C" Isis::NormModel *AlbedoPlugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel) { + return new Isis::Albedo(pvl,pmodel); +} diff --git a/isis/src/base/objs/Albedo/Albedo.h b/isis/src/base/objs/Albedo/Albedo.h new file mode 100644 index 0000000000000000000000000000000000000000..2ec949dd467798850171dbd736b85e1324c46213 --- /dev/null +++ b/isis/src/base/objs/Albedo/Albedo.h @@ -0,0 +1,79 @@ +#if !defined(Albedo_h) +#define Albedo_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/06/18 17:26:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "NormModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief Albedo normalization + * + * Consistent dividing out of photometric model at given an- + * gles and putting it back in at reference incidence but zero + * phase. Let the reference incidence default to zero. For + * Hapke model only, the photometric function multiplied back + * in will be modified to take out opposition effect. This + * requires saving the actual value of B0 while temporarily + * setting it to zero in the common block to compute the over- + * all normalization. + * + * + * @author 1998-12-21 Randy Kirk + * + * @internal + * @history 2007-08-15 Steven Lambright - Refactored code + * @history 2008-03-07 Janet Barrett - Changed name of Incmatch + * parmater to Incmat + * @history 2008-06-18 Christopher Austin - Fixed documentation errors + */ + class Albedo : public NormModel { + public: + Albedo (Pvl &pvl, PhotoModel &pmodel); + virtual ~Albedo() {}; + + protected: + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double dn, double &albedo, double &mult, double &base); + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double deminc, double demema, double dn, double &albedo, + double &mult, double &base) {}; + + private: + //! Set parameters needed for albedo normalization + void SetNormIncref(const double incref); + void SetNormIncmat(const double incmat); + void SetNormThresh(const double thresh); + void SetNormAlbedo(const double albedo); + + double p_normPsurfref; + double p_normIncref; + double p_normThresh; + double p_normIncmat; + double p_normAlbedo; + }; +}; + +#endif diff --git a/isis/src/base/objs/Albedo/Albedo.truth b/isis/src/base/objs/Albedo/Albedo.truth new file mode 100644 index 0000000000000000000000000000000000000000..18f0da115ac21c0d14eca106af8d57db776acd8d --- /dev/null +++ b/isis/src/base/objs/Albedo/Albedo.truth @@ -0,0 +1,24 @@ +UNIT TEST for Albedo normalization function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = NormalizationModel + Group = Algorithm + Name = Albedo + End_Group +End_Object +End + +Test phase=0.0, incidence=0.0, emission=0.0, dn=.0800618902 ... +Normalization value = 0.0800619 + +Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0797334611 ... +Normalization value = 0.128657 + +Test phase=180, incidence=90, emission=90, dn=.0794225037 ... +Normalization value = -1.79769e+308 + diff --git a/isis/src/base/objs/Albedo/Makefile b/isis/src/base/objs/Albedo/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8784b56ec6d278a85adf6ae2c1437ec845e1509b --- /dev/null +++ b/isis/src/base/objs/Albedo/Makefile @@ -0,0 +1,5 @@ +INCS = Albedo.h +SRCS = Albedo.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Albedo/NormModel.plugin b/isis/src/base/objs/Albedo/NormModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..214ffd9052e1c527ec7538a33f9d932ff612ea6c --- /dev/null +++ b/isis/src/base/objs/Albedo/NormModel.plugin @@ -0,0 +1,4 @@ +Group = Albedo + Library = Albedo + Routine = AlbedoPlugin +End_Group diff --git a/isis/src/base/objs/Albedo/unitTest.cpp b/isis/src/base/objs/Albedo/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9fa63f17b57feb0629d52a97d31310d71c2deb88 --- /dev/null +++ b/isis/src/base/objs/Albedo/unitTest.cpp @@ -0,0 +1,60 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "NormModel.h" +#include "NormModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + double result; + double mult; + double base; + + std::cout << "UNIT TEST for Albedo normalization function" << std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup algn("Algorithm"); + algn += PvlKeyword("Name","Albedo"); + + PvlObject on("NormalizationModel"); + on.AddGroup(algn); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(on); + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + NormModel *nm = NormModelFactory::Create(pvl,*pm); + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0, dn=.0800618902 ..." << std::endl; + nm->CalcNrmAlbedo(0.0,0.0,0.0,.0800618902,result,mult,base); + std::cout << "Normalization value = " << result << std::endl << std::endl; + + std::cout << "Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0797334611 ..." << std::endl; + nm->CalcNrmAlbedo(86.7207248,51.7031305,38.9372914,.0797334611,result,mult,base); + std::cout << "Normalization value = " << result << std::endl << std::endl; + + std::cout << "Test phase=180, incidence=90, emission=90, dn=.0794225037 ..." << std::endl; + nm->CalcNrmAlbedo(180.0,90.0,90.0,.0794225037,result,mult,base); + std::cout << "Normalization value = " << result << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/AlbedoAtm/AlbedoAtm.cpp b/isis/src/base/objs/AlbedoAtm/AlbedoAtm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..484218f69cbe2ce61f2c88a190d08820baa22f1c --- /dev/null +++ b/isis/src/base/objs/AlbedoAtm/AlbedoAtm.cpp @@ -0,0 +1,154 @@ +#include +#include "AlbedoAtm.h" +#include "NumericalApproximation.h" +#include "iException.h" + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) + +namespace Isis { + /** + * Constructs AlbedoAtm object using a Pvl, PhotoModel, and + * AtmosModel + * @param pvl + * @param pmodel + * @param amodel + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Modified references + * to NumericalMethods class and replaced Isis::PI with + * PI since this is in Isis namespace. + */ + AlbedoAtm::AlbedoAtm (Pvl &pvl, PhotoModel &pmodel, AtmosModel &amodel) : + NormModel(pvl,pmodel,amodel) { + PvlGroup &algo = pvl.FindObject("NormalizationModel") + .FindGroup("Algorithm",Pvl::Traverse); + // Set default value + SetNormIncref(0.0); + // Get value from user + if (algo.HasKeyword("Incref")) { + SetNormIncref(algo["Incref"]); + } + + // First-time setup: + // Calculate normalization at standard conditions + GetPhotoModel()->SetStandardConditions(true); + p_normPsurfref = GetPhotoModel()->CalcSurfAlbedo(p_normIncref, p_normIncref,0.0); + GetPhotoModel()->SetStandardConditions(false); + + // Get reference hemispheric albedo + GetAtmosModel()->GenerateAhTable(); + + p_normAhref = (GetAtmosModel()->AtmosAhSpline()).Evaluate(p_normIncref, NumericalApproximation::Extrapolate); + + p_normMunotref = cos((PI/180.0)*p_normIncref); + + // Now calculate atmosphere at standard conditions + GetAtmosModel()->SetStandardConditions(true); + GetAtmosModel()->CalcAtmEffect(p_normIncref,p_normIncref,0.0, + &p_normPstdref,&p_normTransref, + &p_normTrans0ref,&p_normSbar); + GetAtmosModel()->SetStandardConditions(false); + } + + /** + * @param phase Value of phase angle. + * @param incidence Value of incidence angle. + * @param emission Value of emission angle. + * @param dn + * @param albedo + * @param mult + * @param base + * @internal + * @history 2008-11-05 Jeannie Walldren - Modified references + * to NumericalMethods class and replaced Isis::PI with + * PI since this is in Isis namespace. + */ + void AlbedoAtm::NormModelAlgorithm (double phase, double incidence, + double emission, double dn, double &albedo, double &mult, double &base) + { + double psurf; + double ahInterp; + double munot; + double pstd; + double trans; + double trans0; + double rho; + double dpo; + double q; + double dpm; + double firsterm; + double secondterm; + double thirdterm; + double fourthterm; + double fifthterm; + + psurf = GetPhotoModel()->CalcSurfAlbedo(phase,incidence, + emission); + + ahInterp = (GetAtmosModel()->AtmosAhSpline()).Evaluate(incidence, NumericalApproximation::Extrapolate); + + munot = cos(incidence*(PI/180.0)); + GetAtmosModel()->CalcAtmEffect(phase,incidence,emission,&pstd,&trans,&trans0,&p_normSbar); + + // With model at actual geometry, calculate rho from dn + dpo = dn - pstd; + dpm = (psurf - ahInterp * munot) * trans0; + q = ahInterp * munot * trans + GetAtmosModel()->AtmosAb() * p_normSbar * dpo + dpm; + + if (dpo <= 0.0 && GetAtmosModel()->AtmosNulneg()) { + rho = 0.0; + } + else { + firsterm = GetAtmosModel()->AtmosAb() * p_normSbar; + secondterm = dpo * dpm; + thirdterm = firsterm * secondterm; + fourthterm = pow(q,2.0) - 4.0 * thirdterm; + + if (fourthterm < 0.0) { + std::string msg = "Square root of negative encountered"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + else { + fifthterm = q + sqrt(fourthterm); + } + + rho = 2 * dpo / fifthterm; + } + + // Now use rho and reference geometry to calculate output dnout + if ((1.0-rho*GetAtmosModel()->AtmosAb()*p_normSbar) <= 0.0) { + std::string msg = "Divide by zero encountered"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + else { + albedo = p_normPstdref + rho * (p_normAhref * p_normMunotref * + p_normTransref / (1.0 - rho * GetAtmosModel()->AtmosAb() * + p_normSbar) + (p_normPsurfref - p_normAhref * + p_normMunotref) * p_normTrans0ref); + } + } + + /** + * Set the normalization function parameter. This is the + * reference incidence angle to which the image photometry will + * be normalized. This parameter is limited to values that are + * >=0 and <90. + * + * @param incref Normalization function parameter, default + * is 0.0 + */ + void AlbedoAtm::SetNormIncref (const double incref) { + if (incref < 0.0 || incref >= 90.0) { + std::string msg = "Invalid value of normalization incref [" + + iString(incref) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_normIncref = incref; + } +} + +extern "C" Isis::NormModel *AlbedoAtmPlugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel, Isis::AtmosModel &amodel) { + return new Isis::AlbedoAtm(pvl,pmodel,amodel); +} diff --git a/isis/src/base/objs/AlbedoAtm/AlbedoAtm.h b/isis/src/base/objs/AlbedoAtm/AlbedoAtm.h new file mode 100644 index 0000000000000000000000000000000000000000..d4090407fadf2b2c93e50a76978e77ed800cf63d --- /dev/null +++ b/isis/src/base/objs/AlbedoAtm/AlbedoAtm.h @@ -0,0 +1,76 @@ +#ifndef AlbedoAtm_h +#define AlbedoAtm_h +/** + * @file + * $Revision: 1.7 $ + * $Date: 2009/05/11 21:53:32 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "NormModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief Albedo normalization with atmosphere + * + * @ingroup RadiometricAndPhotometricCorrection + * @author 1998-12-21 Randy Kirk + * + * @internal + * @history 2007-08-15 Steven Lambright - Refactored code and fixed unit test + * @history 2008-06-18 Christopher Austin - Fixed documentation errors + * @history 2008-11-05 Jeannie Walldren - Modified references + * to NumericalMethods class. + * @history 2008-11-07 Jeannie Walldren - Fixed documentation. + * @history 2009-05-11 Janet Barrett - Fixed so that the NormModelAlgorithm + * supporting DEM input is the empty function. DEM input is not yet + * supported. + * + */ + class AlbedoAtm : public NormModel { + public: + AlbedoAtm (Pvl &pvl, PhotoModel &pmodel, AtmosModel &amodel); + //! Empty Destructor + virtual ~AlbedoAtm() {}; + + protected: + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double dn, double &albedo, double &mult, double &base); + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double deminc, double demema, double dn, double &albedo, + double &mult, double &base) {}; + + private: + //! Set parameters needed for albedo normalization + void SetNormIncref(const double incref); + + double p_normPsurfref; + double p_normIncref; + double p_normPstdref; + double p_normAhref; + double p_normMunotref; + double p_normTransref; + double p_normTrans0ref; + double p_normSbar; + }; +}; + +#endif diff --git a/isis/src/base/objs/AlbedoAtm/AlbedoAtm.truth b/isis/src/base/objs/AlbedoAtm/AlbedoAtm.truth new file mode 100644 index 0000000000000000000000000000000000000000..66b1a80826ecd10eb5baa275e4b2c65160e5af27 --- /dev/null +++ b/isis/src/base/objs/AlbedoAtm/AlbedoAtm.truth @@ -0,0 +1,38 @@ +UNIT TEST for AlbedoAtm normalization function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = AtmosphericModel + Group = Algorithm + Name = Anisotropic1 + Bha = 0.85 + Tau = 0.28 + Wha = 0.95 + Hga = 0.68 + Tauref = 0.0 + Hnorm = 0.003 + End_Group +End_Object + +Object = NormalizationModel + Group = Algorithm + Name = AlbedoAtm + Incref = 0.0 + Thresh = 30.0 + End_Group +End_Object +End + +Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0800618902 ... +Normalization value = -0.0385293 + +Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0797334611 ... +Normalization value = -0.0392226 + +Test phase=86.7187773, incidence=51.7060221, emission=38.9331391, dn=.0794225037 ... +Normalization value = -0.0398726 + diff --git a/isis/src/base/objs/AlbedoAtm/Makefile b/isis/src/base/objs/AlbedoAtm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..07b2ba71e44df7c67e52a171fdce75410c93182e --- /dev/null +++ b/isis/src/base/objs/AlbedoAtm/Makefile @@ -0,0 +1,5 @@ +INCS = AlbedoAtm.h +SRCS = AlbedoAtm.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/AlbedoAtm/NormModel.plugin b/isis/src/base/objs/AlbedoAtm/NormModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..3b99585494838e5bdbf5d63befec827e468228b1 --- /dev/null +++ b/isis/src/base/objs/AlbedoAtm/NormModel.plugin @@ -0,0 +1,4 @@ +Group = AlbedoAtm + Library = AlbedoAtm + Routine = AlbedoAtmPlugin +End_Group diff --git a/isis/src/base/objs/AlbedoAtm/unitTest.cpp b/isis/src/base/objs/AlbedoAtm/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f284ab899cb6d21be779c52b3c0f15175c185576 --- /dev/null +++ b/isis/src/base/objs/AlbedoAtm/unitTest.cpp @@ -0,0 +1,84 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "AtmosModel.h" +#include "AtmosModelFactory.h" +#include "AlbedoAtm.h" +#include "AtmosModel.h" +#include "NormModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + double result; + double mult; + double base; + + std::cout << "UNIT TEST for AlbedoAtm normalization function" << + std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup alga("Algorithm"); + alga += PvlKeyword("Name","Anisotropic1"); + alga += PvlKeyword("Bha","0.85"); + alga += PvlKeyword("Tau","0.28"); + alga += PvlKeyword("Wha","0.95"); + alga += PvlKeyword("Hga","0.68"); + alga += PvlKeyword("Tauref","0.0"); + alga += PvlKeyword("Hnorm","0.003"); + + PvlObject oa("AtmosphericModel"); + oa.AddGroup(alga); + + PvlGroup algn("Algorithm"); + algn += PvlKeyword("Name","AlbedoAtm"); + algn += PvlKeyword("Incref","0.0"); + algn += PvlKeyword("Thresh","30.0"); + + PvlObject on("NormalizationModel"); + on.AddGroup(algn); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(oa); + pvl.AddObject(on); + + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + AtmosModel *am = AtmosModelFactory::Create(pvl,*pm); + AlbedoAtm *nm = (AlbedoAtm*)NormModelFactory::Create(pvl,*pm,*am); + + std::cout << "Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, " << + "dn=.0800618902 ..." << std::endl; + nm->CalcNrmAlbedo(86.7207248,51.7031305,38.9372914,.0800618902,result,mult,base); + std::cout << "Normalization value = " << result << std::endl << std::endl; + + std::cout << "Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, " << + "dn=.0797334611 ..." << std::endl; + nm->CalcNrmAlbedo(86.7207248,51.7031305,38.9372914,.0797334611,result,mult,base); + std::cout << "Normalization value = " << result << std::endl << std::endl; + + std::cout << "Test phase=86.7187773, incidence=51.7060221, emission=38.9331391, " << + "dn=.0794225037 ..." << std::endl; + nm->CalcNrmAlbedo(86.7187773,51.7060221,38.9331391,.0794225037,result,mult,base); + std::cout << "Normalization value = " << result << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/AlphaCube/AlphaCube.cpp b/isis/src/base/objs/AlphaCube/AlphaCube.cpp new file mode 100644 index 0000000000000000000000000000000000000000..002e98813ec89cc7018917cccad6f4ebf66ac038 --- /dev/null +++ b/isis/src/base/objs/AlphaCube/AlphaCube.cpp @@ -0,0 +1,177 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "AlphaCube.h" + +using namespace std; +namespace Isis { + //! Constructs an AlphaCube object using a PVL object. + AlphaCube::AlphaCube (Isis::Pvl &pvl) { + Isis::PvlObject &isiscube = pvl.FindObject("IsisCube"); + if (isiscube.HasGroup("AlphaCube")) { + Isis::PvlGroup &alpha = isiscube.FindGroup("AlphaCube"); + p_alphaSamples = alpha["AlphaSamples"]; + p_alphaLines = alpha["AlphaLines"]; + p_alphaStartingSample = alpha["AlphaStartingSample"]; + p_alphaStartingLine = alpha["AlphaStartingLine"]; + p_alphaEndingSample = alpha["AlphaEndingSample"]; + p_alphaEndingLine = alpha["AlphaEndingLine"]; + p_betaSamples = alpha["BetaSamples"]; + p_betaLines = alpha["BetaLines"]; + } + else { + Isis::PvlGroup &dims = isiscube.FindGroup("Dimensions",Isis::Pvl::Traverse); + p_alphaSamples = dims["Samples"]; + p_alphaLines = dims["Lines"]; + p_alphaStartingSample = 0.5; + p_alphaStartingLine = 0.5; + p_alphaEndingSample = (double) p_alphaSamples + 0.5; + p_alphaEndingLine = (double) p_alphaLines + 0.5; + p_betaSamples = p_alphaSamples; + p_betaLines = p_alphaLines; + } + + ComputeSlope(); + } + + /** Constructs an AlphaCube object with a basic mapping from corner-to-corner, + * beta 0.5,0.5 maps to alpha 0.5,0.5 and beta ns+0.5,nl+0.5 maps to alpha + * ns+0.5, nl+0.5. + */ + AlphaCube::AlphaCube (int alphaSamples, int alphaLines, + int betaSamples, int betaLines, + double alphaSs, double alphaSl, + double alphaEs, double alphaEl) { + p_alphaSamples = alphaSamples; + p_alphaLines = alphaLines; + p_alphaStartingSample = alphaSs; + p_alphaStartingLine = alphaSl; + p_alphaEndingSample = alphaEs; + p_alphaEndingLine = alphaEl; + + p_betaSamples = betaSamples; + p_betaLines = betaLines; + + ComputeSlope(); + } + + /** Constructs an AlphaCube object given alphaSamples, alphaLines, + * betaSamples and betaLines. + */ + AlphaCube::AlphaCube (int alphaSamples, int alphaLines, + int betaSamples, int betaLines) { + p_alphaSamples = alphaSamples; + p_alphaLines = alphaLines; + p_alphaStartingSample = 0.5; + p_alphaStartingLine = 0.5; + p_alphaEndingSample = (double) alphaSamples + 0.5; + p_alphaEndingLine = (double) alphaLines + 0.5; + + p_betaSamples = betaSamples; + p_betaLines = betaLines; + + ComputeSlope(); + } + +/** + * Merges two AlphaCube objects. This facilities combinations of programs + * crop-enlarge, crop-crop, reduce-pad, etc. + * + * @param add The AlphaCube object to be merged. + */ + void AlphaCube::Rehash (AlphaCube &add) { + double sl = AlphaLine(add.AlphaLine(0.5)); + double ss = AlphaSample(add.AlphaSample(0.5)); + double el = AlphaLine(add.AlphaLine(add.BetaLines()+0.5)); + double es = AlphaSample(add.AlphaSample(add.BetaSamples()+0.5)); + + p_alphaStartingLine = sl; + p_alphaStartingSample = ss; + p_alphaEndingLine = el; + p_alphaEndingSample = es; + p_betaLines = add.BetaLines(); + p_betaSamples = add.BetaSamples(); + + ComputeSlope(); + } + +/** + * Writes or update the Alpha keywords (AlphaLines, AlphaSamples, + * AlphaStartingSamples, etc) in the proper group in a PVL object. It chooses + * first to write and AlphaGroup if the Mapping group exists. + * If not then is will write the keywords in the Instrument group if it exists. + * Otherwise it will write to the AlphaCube group. + * + * @param &pvl The PVL object to write to. + * + */ + void AlphaCube::UpdateGroup (Isis::Pvl &pvl) { + // If we have a mapping group we do not want to update the alpha cube + // group as it represents the dimensions and sub-area of the raw instrument + // cube + Isis::PvlObject &cube = pvl.FindObject("IsisCube"); + if (cube.HasGroup("Mapping")) return; + + // Add the labels to the pvl + if (cube.HasGroup("AlphaCube")) { + AlphaCube temp(pvl); + temp.Rehash(*this); + *this = temp; + + Isis::PvlGroup &alpha = cube.FindGroup("AlphaCube"); + alpha["AlphaSamples"] = p_alphaSamples; + alpha["AlphaLines"] = p_alphaLines; + alpha["AlphaStartingSample"] = p_alphaStartingSample; + alpha["AlphaStartingLine"] = p_alphaStartingLine; + alpha["AlphaEndingSample"] = p_alphaEndingSample; + alpha["AlphaEndingLine"] = p_alphaEndingLine; + alpha["BetaSamples"] = p_betaSamples; + alpha["BetaLines"] = p_betaLines; + } + else { + Isis::PvlGroup alpha("AlphaCube"); + alpha += Isis::PvlKeyword("AlphaSamples",p_alphaSamples); + alpha += Isis::PvlKeyword("AlphaLines",p_alphaLines); + alpha += Isis::PvlKeyword("AlphaStartingSample",p_alphaStartingSample); + alpha += Isis::PvlKeyword("AlphaStartingLine",p_alphaStartingLine); + alpha += Isis::PvlKeyword("AlphaEndingSample",p_alphaEndingSample); + alpha += Isis::PvlKeyword("AlphaEndingLine",p_alphaEndingLine); + alpha += Isis::PvlKeyword("BetaSamples",p_betaSamples); + alpha += Isis::PvlKeyword("BetaLines",p_betaLines); + cube.AddGroup(alpha); + } + } + + /** + * Computes the line and sample slopes. (Starting and ending + * alpha lines/samples divided by the number of beta lines/samples). + * + * @internal + * @todo Why the +0.5 and -0.5? + */ + void AlphaCube::ComputeSlope () { + p_lineSlope = double (p_alphaEndingLine - p_alphaStartingLine) / + double ((p_betaLines + 0.5) - 0.5); + p_sampSlope = double (p_alphaEndingSample - p_alphaStartingSample) / + double ((p_betaSamples + 0.5) - 0.5); + } +} diff --git a/isis/src/base/objs/AlphaCube/AlphaCube.h b/isis/src/base/objs/AlphaCube/AlphaCube.h new file mode 100644 index 0000000000000000000000000000000000000000..8bbb5311d9b8b5f2fe4f194030a899f0e9f2df7a --- /dev/null +++ b/isis/src/base/objs/AlphaCube/AlphaCube.h @@ -0,0 +1,109 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#if !defined(AlphaCube_h) +#define AlphaCube_h + +#include "Pvl.h" + +namespace Isis { +/** + * @brief This class is used to rewrite the "alpha" keywords out of the + * AlphaCube group or Instrument group. + * + * This class allows programmers to map cube pixel positions back to the first + * cube they came from.This is critical for camera models or radiometric models + * in order to map input cube pixels to camera detector position. + * The alpha keywords are automatically generated in programs like crop, pad, + * reduce, and enlarge. + * + * @ingroup LowLevelCubeIO + * + * @author 2004-02-13 Jeff Anderson + * + * @internal + * @history 2004-02-13 Jeff Anderson - Added another constructor and + * refactored UpdateGroup method. + * @history 2004-06-03 Jeff Anderson - Fixed bug in UpdateGroup which + * occured when a cube label did not already have a AlphaCube group. + * @history 2005-02-14 Leah Dahmer - Modified file to support Doxygen + * documentation. + * + * @todo 2005-04-06 Add coded example. + */ + class AlphaCube { + public: + AlphaCube (Isis::Pvl &pvl); + AlphaCube (int alphaSamples, int alphaLines, + int betaSamples, int betaLines); + AlphaCube (int alphaSamples, int alphaLines, + int betaSamples, int betaLines, + double alphaSs, double alphaSl, + double alphaEs, double alphaEl); + //! Destroys the AlphaCube object. + ~AlphaCube () {}; + + //! Returns the number of lines in the alpha cube. + inline int AlphaLines () const { return p_alphaLines; }; + //! Returns the number of samples in the alpha cube. + inline int AlphaSamples () const { return p_alphaSamples; }; + //! Returns the number of lines in the beta cube. + inline int BetaLines () const { return p_betaLines; }; + //! Returns the number of samples in the beta cube. + inline int BetaSamples () const { return p_betaSamples; }; + //! Returns an alpha line given a beta line. + inline double AlphaLine(double betaLine) { + return p_lineSlope * (betaLine - 0.5) + p_alphaStartingLine; + } + //! Returns an alpha sample given a beta sample. + inline double AlphaSample(double betaSample) { + return p_sampSlope * (betaSample - 0.5) + p_alphaStartingSample; + } + //! Returns a beta line given an alpha line. + inline double BetaLine(double alphaLine) { + return (alphaLine - p_alphaStartingLine) / p_lineSlope + 0.5; + } + //! Returns a beta sample given an alpha sample. + inline double BetaSample(double alphaSample) { + return (alphaSample - p_alphaStartingSample) / p_sampSlope + 0.5; + } + + void UpdateGroup (Isis::Pvl &pvl); + + void Rehash (AlphaCube &alphaCube); + + private: + void ComputeSlope(); + int p_alphaLines; /**< The number of alpha lines in the cube. */ + int p_alphaSamples; /**< The number of alpha samples in the cube.*/ + int p_betaLines; /**< The number of beta lines in the cube. */ + int p_betaSamples; /**< The number of beta samples in the cube. */ + double p_alphaStartingLine; /**< The starting alpha line. */ + double p_alphaStartingSample; /**< The starting alpha sample. */ + double p_alphaEndingLine; /**< The ending alpha line. */ + double p_alphaEndingSample; /**< The ending alpha sample. */ + double p_lineSlope; /**< The slope of the line. */ + double p_sampSlope; /**< The slope of the sample set. */ + }; +}; + +#endif diff --git a/isis/src/base/objs/AlphaCube/AlphaCube.truth b/isis/src/base/objs/AlphaCube/AlphaCube.truth new file mode 100644 index 0000000000000000000000000000000000000000..2c53b6f69fa3bff97117d3b20e23fa4133f667b0 --- /dev/null +++ b/isis/src/base/objs/AlphaCube/AlphaCube.truth @@ -0,0 +1,78 @@ +1st Test Alpha +4 +8 +2 +3 +3 +5 +1.5 +2.5 +3.5 +5.5 + +1st Test Beta +2 +3 +0 +-1 +3 +6 + +2nd Alpha Test +2 +3 +1.75 +1.75 +2.25 +3.25 +1.5 +1.5 +2.5 +3.5 + +2nd Beta Test +2 +4 +-0.5 +-0.5 +1.5 +3.5 + +3rd Test Alpha +4 +8 +2.75 +3.75 +3.25 +5.25 +2.5 +3.5 +3.5 +5.5 + +3rd Test Beta +2 +4 +-2.5 +-4.5 +3.5 +9.5 + +Object = IsisCube + Group = Dimensions + Samples = 4 + Lines = 8 + End_Group + + Group = AlphaCube + AlphaSamples = 4 + AlphaLines = 8 + AlphaStartingSample = 2.5 + AlphaStartingLine = 3.5 + AlphaEndingSample = 3.5 + AlphaEndingLine = 5.5 + BetaSamples = 2 + BetaLines = 4 + End_Group +End_Object +End diff --git a/isis/src/base/objs/AlphaCube/Makefile b/isis/src/base/objs/AlphaCube/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..15776d77b25ba31c13d454d39114675429655632 --- /dev/null +++ b/isis/src/base/objs/AlphaCube/Makefile @@ -0,0 +1,5 @@ +INCS = AlphaCube.h +SRCS = AlphaCube.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/AlphaCube/unitTest.cpp b/isis/src/base/objs/AlphaCube/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..66052a0021e5a3929482457c0346fd16651ce513 --- /dev/null +++ b/isis/src/base/objs/AlphaCube/unitTest.cpp @@ -0,0 +1,95 @@ +#include +#include "AlphaCube.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + Isis::AlphaCube c(4,8,2,3,1.5,2.5,3.5,5.5); + cout << "1st Test Alpha" << endl; + cout << c.AlphaSamples() << endl; + cout << c.AlphaLines() << endl; + cout << c.AlphaSample(1.0) << endl; + cout << c.AlphaLine(1.0) << endl; + cout << c.AlphaSample(c.BetaSamples()) << endl; + cout << c.AlphaLine(c.BetaLines()) << endl; + cout << c.AlphaSample(0.5) << endl; + cout << c.AlphaLine(0.5) << endl; + cout << c.AlphaSample(c.BetaSamples()+0.5) << endl; + cout << c.AlphaLine(c.BetaLines()+0.5) << endl; + cout << endl; + + cout << "1st Test Beta" << endl; + cout << c.BetaSamples() << endl; + cout << c.BetaLines() << endl; + cout << c.BetaSample(1.0) << endl; + cout << c.BetaLine(1.0) << endl; + cout << c.BetaSample(c.AlphaSamples()) << endl; + cout << c.BetaLine(c.AlphaLines()) << endl; + cout << endl; + + Isis::AlphaCube d(2,3,2,4,1.5,1.5,2.5,3.5); + cout << "2nd Alpha Test" << endl; + cout << d.AlphaSamples() << endl; + cout << d.AlphaLines() << endl; + cout << d.AlphaSample(1.0) << endl; + cout << d.AlphaLine(1.0) << endl; + cout << d.AlphaSample(d.BetaSamples()) << endl; + cout << d.AlphaLine(d.BetaLines()) << endl; + cout << d.AlphaSample(0.5) << endl; + cout << d.AlphaLine(0.5) << endl; + cout << d.AlphaSample(d.BetaSamples()+0.5) << endl; + cout << d.AlphaLine(d.BetaLines()+0.5) << endl; + cout << endl; + + cout << "2nd Beta Test" << endl; + cout << d.BetaSamples() << endl; + cout << d.BetaLines() << endl; + cout << d.BetaSample(1.0) << endl; + cout << d.BetaLine(1.0) << endl; + cout << d.BetaSample(d.AlphaSamples()) << endl; + cout << d.BetaLine(d.AlphaLines()) << endl; + cout << endl; + + c.Rehash(d); + cout << "3rd Test Alpha" << endl; + cout << c.AlphaSamples() << endl; + cout << c.AlphaLines() << endl; + cout << c.AlphaSample(1.0) << endl; + cout << c.AlphaLine(1.0) << endl; + cout << c.AlphaSample(c.BetaSamples()) << endl; + cout << c.AlphaLine(c.BetaLines()) << endl; + cout << c.AlphaSample(0.5) << endl; + cout << c.AlphaLine(0.5) << endl; + cout << c.AlphaSample(c.BetaSamples()+0.5) << endl; + cout << c.AlphaLine(c.BetaLines()+0.5) << endl; + cout << endl; + + cout << "3rd Test Beta" << endl; + cout << c.BetaSamples() << endl; + cout << c.BetaLines() << endl; + cout << c.BetaSample(1.0) << endl; + cout << c.BetaLine(1.0) << endl; + cout << c.BetaSample(c.AlphaSamples()) << endl; + cout << c.BetaLine(c.AlphaLines()) << endl; + cout << endl; + + try { + Isis::Pvl lab; + lab.AddObject(Isis::PvlObject("IsisCube")); + Isis::PvlObject &isiscube = lab.FindObject("IsisCube"); + isiscube.AddGroup(Isis::PvlGroup("Dimensions")); + Isis::PvlGroup &dims = isiscube.FindGroup("Dimensions"); + dims += Isis::PvlKeyword("Samples",4); + dims += Isis::PvlKeyword("Lines",8); + c.UpdateGroup(lab); + cout << lab << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } + + return 0; +} diff --git a/isis/src/base/objs/Anisotropic1/Anisotropic1.cpp b/isis/src/base/objs/Anisotropic1/Anisotropic1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9bf0ff4eb0ffd6e6ba65f259b98d841f262eae39 --- /dev/null +++ b/isis/src/base/objs/Anisotropic1/Anisotropic1.cpp @@ -0,0 +1,272 @@ +#include +#include "Anisotropic1.h" +#include "AtmosModel.h" +#include "iException.h" +#include "iString.h" + +using std::max; + +namespace Isis { + Anisotropic1::Anisotropic1 (Pvl &pvl, PhotoModel &pmodel) : AtmosModel(pvl,pmodel) { + + // Set default values + p_atmosAlpha0_0 = 0.0; + p_atmosAlpha1_0 = 0.0; + p_atmosBeta0_0 = 0.0; + p_atmosBeta1_0 = 0.0; + p_atmosDelta_0 = 0.0; + p_atmosDelta_1 = 0.0; + p_atmosDen = 0.0; + p_atmosE2 = 0.0; + p_atmosE3 = 0.0; + p_atmosE4 = 0.0; + p_atmosE5 = 0.0; + p_atmosFac = 0.0; + p_atmosHnorm = 0.003; + p_atmosP0 = 0.0; + p_atmosP1 = 0.0; + p_atmosQ0 = 0.0; + p_atmosQ02p02 = 0.0; + p_atmosQ1 = 0.0; + p_atmosQ12p12 = 0.0; + p_atmosWha2 = 0.0; + p_atmosWham = 0.0; + p_atmosX0_0 = 0.0; + p_atmosX0_1 = 0.0; + p_atmosY0_0 = 0.0; + p_atmosY0_1 = 0.0; + + } + + /** + * Set the Atmospheric function parameter. This is the + * atmospheric shell thickness normalized to the planet radius + * and is used to modify angles to get more accurate path + * lengths near the terminator (ratio of scale height to the + * planetary radius). This parameter is limited to values that + * are >=0. + * + * @param hnorm Atmospheric function parameter, default is 0.003 + */ + void Anisotropic1::SetAtmosHnorm (const double hnorm) { + if (hnorm < 0.0) { + std::string msg = "Invalid value of Atmospheric hnorm [" + + iString(hnorm) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosHnorm = hnorm; + } + + /** + * Anisotropic atmospheric scattering with P1 single-particle + * phase fn, in the second approximation. This subroutine goes + * through much of the derivation twice, once for the axisymmetric + * (m=0) and once for the m=1 parts of scattered light. + * + * @param phase Value of the phase angle. + * @param incidence Value of the incidence angle. + * @param emission Value of the emission angle. + * + * @history 1998-12-21 Randy Kirk - USGS, Flagstaff - Original + * code + * @history 1999-03-12 K Teal Thompson Port to Unix/ISIS; + * declare vars; add implicit none. + * @history 2007-02-20 Janet Barrett - Imported from Isis2 + * pht_atm_functions to Isis3. + * @history 2008-11-05 Jeannie Walldren - Replaced + * NumericalMethods::r8expint() with AtmosModel::En(). + * Replaced Isis::PI with PI since this is in Isis + * namespace. + */ + void Anisotropic1::AtmosModelAlgorithm (double phase, double incidence, double emission) + { + double hpsq1; + double munot,munotp; + double maxval; + double mu,mup; + double xx; + double emunot,emu; + double gmunot,gmu; + double sum,prod; + double cosazss; + double xmunot_0,ymunot_0; + double xmu_0,ymu_0; + double xmunot_1,ymunot_1; + double xmu_1,ymu_1; + double cxx,cyy; + double xystuff; + + if (p_atmosBha == 0.0) { + p_atmosBha = 1.0e-6; + } + + if (p_atmosTau == 0.0) { + p_pstd = 0.0; + p_trans = 1.0; + p_trans0 = 1.0; + p_sbar = 0.0; + return; + } + + if (p_atmosWha == 1.0) { + std::string msg = "Anisotropic conservative case not implemented yet"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + if (TauOrWhaChanged()) { + // preparation includes exponential integrals e sub 2 through 5 + p_atmosWha2 = 0.5 * p_atmosWha; + p_atmosWham = 1.0 - p_atmosWha; + p_atmosE2 = AtmosModel::En(2,p_atmosTau); + p_atmosE3 = AtmosModel::En(3,p_atmosTau); + p_atmosE4 = AtmosModel::En(4,p_atmosTau); + p_atmosE5 = AtmosModel::En(5,p_atmosTau); + // first, get the required quantities for the axisymmetric m=0 part + // zeroth moments of (uncorrected) x and y times characteristic fn + p_atmosX0_0 = p_atmosWha2 * (1.0 + (1.0/3.0) * p_atmosBha * + p_atmosWham); + p_atmosY0_0 = p_atmosWha2 * (p_atmosE2 + p_atmosBha * p_atmosWham * + p_atmosE4); + // higher-order correction term for x and y + p_atmosDelta_0 = (1.0 - (p_atmosX0_0 + p_atmosY0_0) - (1.0 - p_atmosWha * + (1.0 + (1.0/3.0) * p_atmosBha * p_atmosWham)) / (1.0 - + (p_atmosX0_0 - p_atmosY0_0))) / (p_atmosWha * (0.5 - p_atmosE3 + + p_atmosBha * p_atmosWham * (0.25 - p_atmosE5))); + + // moments of (corrected) x and y + p_atmosAlpha0_0 = 1.0 + p_atmosDelta_0 * (0.5 - p_atmosE3); + p_atmosAlpha1_0 = 0.5 + p_atmosDelta_0 * ((1.0/3.0) - p_atmosE4); + p_atmosBeta0_0 = p_atmosE2 + p_atmosDelta_0 * (0.5 - p_atmosE3); + p_atmosBeta1_0 = p_atmosE3 + p_atmosDelta_0 * ((1.0/3.0) - p_atmosE4); + // gamma will be a weighted sum of m=0 x and y functions + // but unlike before, call the weights q1 and p1, and we also + // need additional weights q0 and p0 + p_atmosFac = 2.0 - p_atmosWha * p_atmosAlpha0_0; + p_atmosDen = pow(p_atmosFac,2.0) - pow(p_atmosWha*p_atmosBeta0_0,2.0); + p_atmosQ0 = p_atmosBha * p_atmosWha * p_atmosWham * (p_atmosFac * + p_atmosAlpha1_0 - p_atmosWha * p_atmosBeta0_0 * p_atmosBeta1_0) / + p_atmosDen; + p_atmosP0 = p_atmosBha * p_atmosWha * p_atmosWham * (-p_atmosFac * + p_atmosBeta1_0 - p_atmosWha * p_atmosBeta0_0 * p_atmosAlpha1_0) / + p_atmosDen; + p_atmosQ02p02 = p_atmosQ0 * p_atmosQ0 - p_atmosP0 * p_atmosP0; + p_atmosQ1 = (2.0 * p_atmosWham * p_atmosFac) / p_atmosDen; + p_atmosP1 = (2.0 * p_atmosWham * p_atmosWha * p_atmosBeta0_0) / + p_atmosDen; + p_atmosQ12p12 = p_atmosQ1 * p_atmosQ1 - p_atmosP1 * p_atmosP1; + // sbar is total diffuse illumination and comes from moments + p_sbar = 1.0 - 2.0 * (p_atmosQ1 * p_atmosAlpha1_0 + p_atmosP1 * + p_atmosBeta1_0); + // we're not done yet! still have to calculate the m=1 portion + // zeroth moments of (uncorrected) x and y times characteristic fn + p_atmosX0_1 = 0.5 * p_atmosWha2 * p_atmosBha * (1.0 - (1.0/3.0)); + p_atmosY0_1 = 0.5 * p_atmosWha2 * p_atmosBha * (p_atmosE2 - p_atmosE4); + // higher-order correction term for x and y + p_atmosDelta_1 = (1.0 - (p_atmosX0_1 + p_atmosY0_1) - (1.0 - + (1.0/3.0) * p_atmosWha * p_atmosBha) / (1.0 - (p_atmosX0_1 - + p_atmosY0_1))) / (p_atmosWha2 * p_atmosBha * ((0.5 - 0.25) - + (p_atmosE3 - p_atmosE5))); + // moments of (corrected) x and y are not needed for m=1, so we're done + SetOldTau(p_atmosTau); + SetOldWha(p_atmosWha); + } + + // correct the path lengths for planetary curvature + hpsq1 = pow((1.0+p_atmosHnorm),2.0) - 1.0; + + if (incidence == 90.0) { + munot = 0.0; + } + else { + munot = cos((PI/180.0)*incidence); + } + + maxval = max(1.0e-30,hpsq1+munot*munot); + munotp = p_atmosHnorm / (sqrt(maxval) - munot); + munotp = max(munotp,p_atmosTau/69.0); + if (emission == 90.0) { + mu = 0.0; + } + else { + mu = cos((PI/180.0)*emission); + } + + maxval = max(1.0e-30,hpsq1+mu*mu); + mup = p_atmosHnorm / (sqrt(maxval) - mu); + mup = max(mup,p_atmosTau/69.0); + // build the x and y functions of mu0 and mu + maxval = max(1.0e-30,munotp); + xx = -p_atmosTau / maxval; + + if (xx < -69.0) { + emunot = 0.0; + } + else if (xx > 69.0) { + emunot = 1.0e30; + } + else { + emunot = exp(-p_atmosTau/munotp); + } + + maxval = max(1.0e-30,mup); + xx = -p_atmosTau / maxval; + + if (xx < -69.0) { + emu = 0.0; + } + else if (xx > 69.0) { + emu = 1.0e30; + } + else { + emu = exp(-p_atmosTau/mup); + } + + // first for m=0 + xmunot_0 = 1.0 + p_atmosDelta_0 * munotp * (1.0 - emunot); + ymunot_0 = emunot + p_atmosDelta_0 * munotp * (1.0 - emunot); + xmu_0 = 1.0 + p_atmosDelta_0 * mup * (1.0 - emu); + ymu_0 = emu + p_atmosDelta_0 * mup * (1.0 - emu); + + // then for m=1 + xmunot_1 = 1.0 + p_atmosDelta_1 * munotp * (1.0 - emunot); + ymunot_1 = emunot + p_atmosDelta_1 * munotp * (1.0 - emunot); + xmu_1 = 1.0 + p_atmosDelta_1 * mup * (1.0 - emu); + ymu_1 = emu + p_atmosDelta_1 * mup * (1.0 - emu); + + // gamma1 functions come from x and y with m=0 + gmunot = p_atmosP1 * xmunot_0 + p_atmosQ1 * ymunot_0; + gmu = p_atmosP1 * xmu_0 + p_atmosQ1 * ymu_0; + + // purely atmos term uses x and y of both orders and is complex + sum = munot + mu; + prod = munot * mu; + cxx = 1.0 - p_atmosQ0 * sum + (p_atmosQ02p02 - p_atmosBha * + p_atmosQ12p12) * prod; + cyy = 1.0 + p_atmosQ0 * sum + (p_atmosQ02p02 - p_atmosBha * + p_atmosQ12p12) * prod; + + if (phase == 90.0) { + cosazss = 0.0 - munot * mu; + } + else { + cosazss = cos((PI/180.0)*phase) - munot * mu; + } + + xystuff = cxx * xmunot_0 * xmu_0 - cyy * ymunot_0 * + ymu_0 - p_atmosP0 * sum * (xmu_0 * ymunot_0 + ymu_0 * + xmunot_0) + cosazss * p_atmosBha * (xmu_1 * + xmunot_1 - ymu_1 * ymunot_1); + p_pstd = 0.25 * p_atmosWha * munotp / (munotp + mup) * xystuff; + + // xmitted surface term uses gammas from m=0 + p_trans = gmunot * gmu; + + // finally, never-scattered term is given by pure attenuation + p_trans0 = emunot * emu; + } +} + +extern "C" Isis::AtmosModel *Anisotropic1Plugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel) { + return new Isis::Anisotropic1(pvl,pmodel); +} diff --git a/isis/src/base/objs/Anisotropic1/Anisotropic1.h b/isis/src/base/objs/Anisotropic1/Anisotropic1.h new file mode 100644 index 0000000000000000000000000000000000000000..e50f97e07d38ea827efc5b6be4f27d833244c81f --- /dev/null +++ b/isis/src/base/objs/Anisotropic1/Anisotropic1.h @@ -0,0 +1,90 @@ +#if !defined(Anisotropic1_h) +#define Anisotropic1_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/11/05 23:36:30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "AtmosModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief + * + * + * @ingroup RadiometricAndPhotometricCorrection + * @author 1998-12-21 Randy Kirk + * + * @internal + * @history 1998-12-21 Randy Kirk - USGS, Flagstaff - Original + * code. + * @history 2007-02-20 Janet Barrett - Imported from Isis2. + * @history 2007-08-15 Steven Lambright - Refactored code + * @history 2008-03-07 Janet Barrett - Moved code to set standard + * conditions to the AtmosModel class + * @history 2008-06-18 Christopher Austin - Fixed documentation error + * @history 2008-11-05 Jeannie Walldren - Replaced reference to + * NumericalMethods::r8expint() with AtmosModel::En(). + * Added documentation from Isis2. + */ + class Anisotropic1 : public AtmosModel { + public: + Anisotropic1 (Pvl &pvl, PhotoModel &pmodel); + virtual ~Anisotropic1() {}; + + protected: + virtual void AtmosModelAlgorithm (double phase, double incidence, + double emission); + + private: + void SetAtmosHnorm(const double hnorm); + + double p_atmosE2; + double p_atmosE3; + double p_atmosE4; + double p_atmosE5; + double p_atmosDelta_0; + double p_atmosDelta_1; + double p_atmosAlpha0_0; + double p_atmosAlpha1_0; + double p_atmosBeta0_0; + double p_atmosBeta1_0; + double p_atmosWha2; + double p_atmosWham; + double p_atmosX0_0; + double p_atmosY0_0; + double p_atmosX0_1; + double p_atmosY0_1; + double p_atmosFac; + double p_atmosDen; + double p_atmosQ0; + double p_atmosQ1; + double p_atmosP0; + double p_atmosP1; + double p_atmosQ02p02; + double p_atmosQ12p12; + double p_atmosHnorm; + }; +}; + +#endif diff --git a/isis/src/base/objs/Anisotropic1/Anisotropic1.truth b/isis/src/base/objs/Anisotropic1/Anisotropic1.truth new file mode 100644 index 0000000000000000000000000000000000000000..c3cffecb25bf852e3e0a374ed4bb929bfd849569 --- /dev/null +++ b/isis/src/base/objs/Anisotropic1/Anisotropic1.truth @@ -0,0 +1,36 @@ +UNIT TEST for Anisotropic1 atmospheric function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = AtmosphericModel + Group = Algorithm + Name = Anisotropic1 + Tau = 0.28 + Bha = 0.85 + Hnorm = 0.003 + End_Group +End_Object +End + +Test phase=0.0, incidence=0.0, emission=0.0 (standard conditions) ... +Pstd = 0 +Trans = 1 +Trans0 = 1 +Sbar = 0 + +Test phase=86.7226722, incidence=51.7002388, emission=38.9414439 ... +Pstd = 0.0983183 +Trans = 0.764393 +Trans0 = 0.444706 +Sbar = 0.130632 + +Test phase=180.0, incidence=90.0, emission=90.0 ... +Pstd = 0.0266486 +Trans = 0.159184 +Trans0 = 5.19719e-07 +Sbar = 0.130632 + diff --git a/isis/src/base/objs/Anisotropic1/AtmosModel.plugin b/isis/src/base/objs/Anisotropic1/AtmosModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..6b8b990b24554e0be59ddb0d9aff10b84a67b99f --- /dev/null +++ b/isis/src/base/objs/Anisotropic1/AtmosModel.plugin @@ -0,0 +1,4 @@ +Group = Anisotropic1 + Library = Anisotropic1 + Routine = Anisotropic1Plugin +End_Group diff --git a/isis/src/base/objs/Anisotropic1/Makefile b/isis/src/base/objs/Anisotropic1/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..155f0cafec0d7aeb8937fa4ef6df0a979cef15ef --- /dev/null +++ b/isis/src/base/objs/Anisotropic1/Makefile @@ -0,0 +1,5 @@ +INCS = Anisotropic1.h +SRCS = Anisotropic1.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Anisotropic1/unitTest.cpp b/isis/src/base/objs/Anisotropic1/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd81aab969a5388d821bf020b2f12fe996fcaaa4 --- /dev/null +++ b/isis/src/base/objs/Anisotropic1/unitTest.cpp @@ -0,0 +1,76 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "AtmosModel.h" +#include "AtmosModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + double pstd; + double trans; + double trans0; + double sbar; + + std::cout << "UNIT TEST for Anisotropic1 atmospheric function" << + std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup alga("Algorithm"); + alga += PvlKeyword("Name","Anisotropic1"); + alga += PvlKeyword("Tau", 0.28); + alga += PvlKeyword("Bha", 0.85); + alga += PvlKeyword("Hnorm", 0.003); + + PvlObject oa("AtmosphericModel"); + oa.AddGroup(alga); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(oa); + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + AtmosModel *am = AtmosModelFactory::Create(pvl,*pm); + + am->SetStandardConditions(true); + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 (standard conditions) ..." << std::endl; + am->CalcAtmEffect(0.0,0.0,0.0,&pstd,&trans,&trans0,&sbar); + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + am->SetStandardConditions(false); + + std::cout << "Test phase=86.7226722, incidence=51.7002388, emission=38.9414439 ..." << std::endl; + am->CalcAtmEffect(86.7226722,51.7002388,38.9414439,&pstd,&trans,&trans0,&sbar); + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << std::endl; + am->CalcAtmEffect(180.0,90.0,90.0,&pstd,&trans,&trans0,&sbar); + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/Anisotropic2/Anisotropic2.cpp b/isis/src/base/objs/Anisotropic2/Anisotropic2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f8bf2daa9c81c5a1b6cd2a2ad6d7206b910d78f6 --- /dev/null +++ b/isis/src/base/objs/Anisotropic2/Anisotropic2.cpp @@ -0,0 +1,356 @@ +#include +#include "Anisotropic2.h" +#include "AtmosModel.h" +#include "Constants.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "iString.h" + +using std::min; +using std::max; + +namespace Isis { + Anisotropic2::Anisotropic2 (Pvl &pvl, PhotoModel &pmodel) : AtmosModel(pvl,pmodel) { + + // Set default value + SetAtmosHnorm(0.003); + + // Get value from user + PvlGroup &algorithm = pvl.FindObject("AtmosphericModel").FindGroup("Algorithm",Pvl::Traverse); + if (algorithm.HasKeyword("Hnorm")) { + SetAtmosHnorm(algorithm["Hnorm"]); + } + } + + /** + * Set the Atmospheric function parameter. This is the + * atmospheric shell thickness normalized to the planet radius + * and is used to modify angles to get more accurate path + * lengths near the terminator (ratio of scale height to the + * planetary radius). This parameter is limited to values that + * are >=0. + * + * @param hnorm Atmospheric function parameter, default is 0.003 + */ + void Anisotropic2::SetAtmosHnorm (const double hnorm) { + if (hnorm < 0.0) { + std::string msg = "Invalid value of Atmospheric hnorm [" + iString(hnorm) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosHnorm = hnorm; + } + + /** + * Anisotropic atmospheric scattering with P1 single-particle + * phase fn, in the second approximation. This subroutine goes + * through much of the derivation twice, once for the axisymmetric + * (m=0) and once for the m=1 parts of scattered light. + * + * @param phase Value of the phase angle. + * @param incidence Value of the incidence angle. + * @param emission Value of the emission angle. + * + * @history 1998-12-21 Randy Kirk - USGS, Flagstaff - Original + * code + * @history 1999-03-12 K Teal Thompson Port to Unix/ISIS; + * declare vars; add implicit none. + * @history 2007-02-20 Janet Barrett - Imported from Isis2 + * pht_atm_functions to Isis3. + * @history 2008-11-05 Jeannie Walldren - Replaced + * NumericalMethods::r8expint() with AtmosModel::En(), + * NumericalMethods::G11Prime() with + * AtmosModel::G11Prime(), and NumericalMethods::r8ei() + * with AtmosModel::Ei(). Replaced Isis::PI with PI + * since this is in Isis namespace. + */ + void Anisotropic2::AtmosModelAlgorithm (double phase, double incidence, double emission) + { + double xx; + double munot,mu; + double emunot,emu; + double munotp,mup; + double gmunot,gmu; + double hpsq1; + double f1munot,f2munot,f3munot; + double f1mmunot,f2mmunot,f3mmunot; + double maxval; + double f1mu,f2mu,f3mu; + double f1mmu,f2mmu,f3mmu; + double sum; + double prod; + double cosazss; + double xystuff; + double xmunot_0,ymunot_0; + double xmu_0,ymu_0; + double cxx,cyy; + double xmunot_1,ymunot_1; + double xmu_1,ymu_1; + + if (p_atmosBha == 0.0) { + p_atmosBha = 1.0e-6; + } + + if (p_atmosTau == 0.0) { + p_pstd = 0.0; + p_trans = 1.0; + p_trans0 = 1.0; + p_sbar = 0.0; + return; + } + + if (p_atmosWha == 1.0) { + std::string msg = "Anisotropic conservative case not implemented yet"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + if (TauOrWhaChanged()) { + // preparation includes exponential integrals e sub 2 through 5 + p_wha2 = 0.5 * p_atmosWha; + p_wham = 1.0 - p_atmosWha; + p_e1 = AtmosModel::En(1,p_atmosTau); + p_e1_2 = AtmosModel::En(1,2.0*p_atmosTau); + p_e2 = AtmosModel::En(2,p_atmosTau); + p_e3 = AtmosModel::En(3,p_atmosTau); + p_e4 = AtmosModel::En(4,p_atmosTau); + p_e5 = AtmosModel::En(5,p_atmosTau); + + // chandra's gmn functions require fm and fn at mu=-1 + xx = -p_atmosTau; + if (xx < -69.0) { + p_em = 0.0; + } + else if (xx > 69.0) { + p_em = 1.0e30; + } + else { + p_em = exp(xx); + } + + p_f1m = log(2.0) - p_em * p_e1 + p_e1_2; + p_f2m = -1.0 * (p_f1m + p_em * p_e2 - 1.0); + p_f3m = -1.0 * (p_f2m + p_em * p_e3 - 0.5); + p_f4m = -1.0 * (p_f3m + p_em * p_e4 - (1.0/3.0)); + p_g12 = (p_atmosTau * p_e1 * p_e2 + p_f1m + p_f2m) * 0.5; + p_g13 = (p_atmosTau * p_e1 * p_e3 + p_f1m + p_f3m) * (1.0/3.0); + p_g14 = (p_atmosTau * p_e1 * p_e4 + p_f1m + p_f4m) * 0.25; + p_g32 = (p_atmosTau * p_e3 * p_e2 + p_f3m + p_f2m) * 0.25; + p_g33 = (p_atmosTau * p_e3 * p_e3 + p_f3m + p_f3m) * 0.2; + p_g34 = (p_atmosTau * p_e3 * p_e4 + p_f3m * p_f4m) * (1.0/6.0); + + // chandra's g'mn functions require g'11 and f at mu=+1 + xx = p_atmosTau; + if (xx < -69.0) { + p_e = 0.0; + } + else if (xx > 69.0) { + p_e = 1.0e30; + } + else { + p_e = exp(xx); + } + + p_f1 = Eulgam() + log(p_atmosTau) + p_e * p_e1; + p_f2 = p_f1 + p_e * p_e2 - 1.0; + p_f3 = p_f2 + p_e * p_e3 - 0.5; + p_f4 = p_f3 + p_e * p_e4 - (1.0/3.0); + p_g11p = AtmosModel::G11Prime(p_atmosTau); + p_g12p = (p_atmosTau * (p_e1 - p_g11p) + p_em * (p_f1 + p_f2)) * 0.25; + p_g13p = (p_atmosTau * (0.5 * p_e1 - p_g12p) + p_em * (p_f1 + p_f3)) * 0.2; + p_g14p = (p_atmosTau * ((1.0/3.0) * p_e1 - p_g13p) + p_em * (p_f1 + p_f4)) * (1.0/6.0); + p_g32p = (p_atmosTau * (p_e1 - p_g13p) + p_em * (p_f3 + p_f2)) * (1.0/6.0); + p_g33p = (p_atmosTau * (0.5 * p_e1 - p_g32p) + p_em * (p_f3 + p_f3)) * 0.142857; + p_g34p = (p_atmosTau * ((1.0/3.0) * p_e1 - p_g33p) + p_em * (p_f3 + p_f4)) * 0.125; + + // first, get the required quantities for the axisymmetric m=0 part + // zeroth moments of (uncorrected) x and y times characteristic fn + p_x0_0 = p_wha2 * (1.0 + (1.0/3.0) * p_atmosBha * p_wham + p_wha2 * (p_g12 + p_atmosBha * + p_wham * (p_g14 + p_g32) + pow(p_atmosBha, 2.0) * pow(p_wham,2.0) * p_g34)); + p_y0_0 = p_wha2 * (p_e2 + p_atmosBha * p_wham * p_e4 + p_wha2 * (p_g12p + + p_atmosBha * p_wham * (p_g14p + p_g32p) + + pow(p_atmosBha, 2.0) * pow(p_wham,2.0) * p_g34p)); + + // higher-order correction term for x and y + p_delta_0 = (1.0 - (p_x0_0 + p_y0_0) - (1.0 - p_atmosWha * (1.0 + (1.0/3.0) * p_atmosBha * + p_wham)) / (1.0 - (p_x0_0 - p_y0_0))) / (p_atmosWha * (0.5 - p_e3 + p_atmosBha * p_wham * (0.25 - p_e5))); + + // moments of (corrected) x and y + p_alpha0_0 = 1.0 + p_wha2 * (p_g12 + p_atmosBha * p_wham * p_g32) + p_delta_0 * (0.5 - p_e3); + p_alpha1_0 = 0.5 + p_wha2 * (p_g13 + p_atmosBha * p_wham * p_g33) + p_delta_0 * ((1.0/3.0) - p_e4); + p_beta0_0 = p_e2 + p_wha2 * (p_g12p + p_atmosBha * p_wham * p_g32p) + p_delta_0 * (0.5 - p_e3); + p_beta1_0 = p_e3 + p_wha2 * (p_g13p + p_atmosBha * p_wham * p_g33p) + p_delta_0 * ((1.0/3.0) - p_e4); + + // gamma will be a weighted sum of m=0 x and y functions + // but unlike before, call the weights q1 and p1, and we also + // need additional weights q0 and p0 + p_fac = 2.0 - p_atmosWha * p_alpha0_0; + p_den = pow(p_fac,2.0) - pow((p_atmosWha*p_beta0_0),2.0); + p_q0 = p_atmosBha * p_atmosWha * p_wham * (p_fac * p_alpha1_0 - p_atmosWha * p_beta0_0 * p_beta1_0) / p_den; + p_p0 = p_atmosBha * p_atmosWha * p_wham * (-p_fac * p_beta1_0 - p_atmosWha * p_beta0_0 * p_alpha1_0) / p_den; + p_q02p02 = p_q0 * p_q0 - p_p0 * p_p0; + p_q1 = (2.0 * p_wham * p_fac) / p_den; + p_p1 = (2.0 * p_wham * p_atmosWha * p_beta0_0) / p_den; + p_q12p12 = p_q1 * p_q1 - p_p1 * p_p1; + + // sbar is total diffuse illumination and comes from moments + p_sbar = 1.0 - 2.0 * (p_q1 * p_alpha1_0 + p_p1 * p_beta1_0); + + // we're not done yet! still have to calculate the m=1 portion + // zeroth moments of (uncorrected) x and y times characteristic fn + p_x0_1 = 0.5 * p_wha2 * p_atmosBha * (1.0 - (1.0/3.0) + 0.5 * p_wha2 * p_atmosBha * + (p_g12 - (p_g14 + p_g32) + p_g34)); + p_y0_1 = 0.5 * p_wha2 * p_atmosBha * (p_e2 - p_e4 + 0.5 * p_wha2 * p_atmosBha * + (p_g12p - (p_g14p + p_g32p) + p_g34p)); + + // higher-order correction term for x and y + p_delta_1 = (1.0 - (p_x0_1 + p_y0_1) - (1.0 - (1.0/3.0) * p_atmosWha * p_atmosBha) / + (1.0 - (p_x0_1 - p_y0_1))) / (p_wha2 * p_atmosBha * + ((0.5 - 0.25) - (p_e3 - p_e5))); + + // moments of (corrected) x and y are not needed for m=1, so we're done + SetOldTau(p_atmosTau); + SetOldWha(p_atmosWha); + } + + // correct the path lengths for planetary curvature + hpsq1 = pow((1.0+p_atmosHnorm),2.0) - 1.0; + + if (incidence == 90.0) { + munot = 0.0; + } + else { + munot = cos((PI/180.0)*incidence); + } + + maxval = max(1.0e-30,hpsq1+munot*munot); + munotp = p_atmosHnorm / (sqrt(maxval) - munot); + munotp = max(munotp,p_atmosTau/69.0); + + if (emission == 90.0) { + mu = 0.0; + } + else { + mu = cos((PI/180.0)*emission); + } + + maxval = max(1.0e-30,hpsq1+mu*mu); + mup = p_atmosHnorm / (sqrt(maxval) - mu); + mup = max(mup,p_atmosTau/69.0); + + // build the x and y functions of mu0 and mu + maxval = max(1.0e-30,munotp); + xx = -p_atmosTau / maxval; + if (xx < -69.0) { + emunot = 0.0; + } + else if (xx > 69.0) { + emunot = 1.0e30; + } + else { + emunot = exp(-p_atmosTau/munotp); + } + + maxval = max(1.0e-30,mup); + xx = -p_atmosTau / maxval; + if (xx < -69.0) { + emu = 0.0; + } + else if (xx > 69.0) { + emu = 1.0e30; + } + else { + emu = exp(-p_atmosTau/mup); + } + + // in the second approximation the x and y include the f1, f3 functions + xx = munotp; + if (fabs(xx-1.0) < 1.0e-10) { + f1munot = p_f1; + f1mmunot = xx * (log(1.0+1.0/xx) - p_e1 * emunot + + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); + } + else if (xx > 0.0) { + f1munot = xx * (log(xx/(1.0-xx)) + p_e1 / emunot + + AtmosModel::Ei(p_atmosTau*(1.0/xx-1.0))); + f1mmunot = xx * (log(1.0+1.0/xx) - p_e1 * emunot + + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); + } + else { + std::string msg = "Negative length of planetary curvature encountered"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + + f2munot = munotp * (f1munot + p_e2 / emunot - 1); + f2mmunot = -munotp * (f1mmunot + p_e2 * emunot - 1); + f3munot = munotp * (f2munot + p_e3 / emunot - 0.5); + f3mmunot = -munotp * (f2mmunot + p_e3 * emunot - 0.5); + xx = mup; + + if (fabs(xx-1.0) < 1.0e-10) { + f1mu = p_f1; + f1mmu = xx * (log(1.0+1.0/xx) - p_e1 * emu + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); + } + else if (xx > 0.0) { + f1mu = xx * (log(xx/(1.0-xx)) + p_e1 / emu + AtmosModel::Ei(p_atmosTau*(1.0/xx-1.0))); + f1mmu = xx * (log(1.0+1.0/xx) - p_e1 * emu + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); + } + else { + std::string msg = "Negative length of planetary curvature encountered"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + + f2mu = mup * (f1mu + p_e2 / emu - 1); + f2mmu = -mup * (f1mmu + p_e2 * emu - 1); + f3mu = mup * (f2mu + p_e3 / emu - 0.5); + f3mmu = -mup * (f2mmu + p_e3 * emu - 0.5); + + // first for m=0 + xmunot_0 = 1.0 + p_wha2 * (f1mmunot + p_atmosBha * p_wham * f3mmunot) + p_delta_0 * munotp * (1.0 - emunot); + ymunot_0 = emunot * (1.0 + p_wha2 * (f1munot + p_atmosBha * p_wham * f3munot)) + + p_delta_0 * munotp * (1.0 - emunot); + xmu_0 = 1.0 + p_wha2 * (f1mmu + p_atmosBha * p_wham * f3mmu) + p_delta_0 * mup * (1.0 - emu); + ymu_0 = emu * (1.0 + p_wha2 * (f1mu + p_atmosBha * p_wham * f3mu)) + p_delta_0 * mup * (1.0 - emu); + + // then for m=1 + xmunot_1 = 1.0 + 0.5 * p_wha2 * p_atmosBha * (f1mmunot - f3mmunot) + p_delta_1 * munotp * (1.0 - emunot); + ymunot_1 = emunot * (1.0 + 0.5 * p_wha2 * p_atmosBha * + (f1munot - f3munot)) + p_delta_1 * munotp * (1.0 - emunot); + xmu_1 = 1.0 + 0.5 * p_wha2 * p_atmosBha * (f1mmu - f3mmu) + p_delta_1 * mup * (1.0 - emu); + ymu_1 = emu * (1.0 + 0.5 * p_wha2 * p_atmosBha * (f1mu - f3mu)) + p_delta_1 * mup * (1.0 - emu); + + // gamma1 functions come from x and y with m=0 + gmunot = p_p1 * xmunot_0 + p_q1 * ymunot_0; + gmu = p_p1 * xmu_0 + p_q1 * ymu_0; + + // purely atmos term uses x and y of both orders and is complex + sum = munot + mu; + prod = munot * mu; + cxx = 1.0 - p_q0 * sum + (p_q02p02 - p_atmosBha * p_q12p12) * prod; + cyy = 1.0 + p_q0 * sum + (p_q02p02 - p_atmosBha * p_q12p12) * prod; + + if (phase == 90.0) { + cosazss = 0.0 - munot * mu; + } + else { + cosazss = cos((PI/180.0)*phase) - munot * mu; + } + + xystuff = cxx * xmunot_0 * xmu_0 - cyy * ymunot_0 * + ymu_0 - p_p0 * sum * (xmu_0 * ymunot_0 + ymu_0 * xmunot_0) + cosazss * p_atmosBha * (xmu_1 * + xmunot_1 - ymu_1 * ymunot_1); + p_pstd = 0.25 * p_atmosWha * munotp / (munotp + mup) * xystuff; + + // xmitted surface term uses gammas from m=0 + p_trans = gmunot * gmu; + + // finally, never-scattered term is given by pure attenuation + p_trans0 = emunot * emu; + } +} + +extern "C" Isis::AtmosModel *Anisotropic2Plugin (Isis::Pvl &pvl, + Isis::PhotoModel &pmodel) { + + return new Isis::Anisotropic2(pvl,pmodel); +} diff --git a/isis/src/base/objs/Anisotropic2/Anisotropic2.h b/isis/src/base/objs/Anisotropic2/Anisotropic2.h new file mode 100644 index 0000000000000000000000000000000000000000..6f319ef32691029bea20e7481100fa2aa4ba0b89 --- /dev/null +++ b/isis/src/base/objs/Anisotropic2/Anisotropic2.h @@ -0,0 +1,89 @@ +#if !defined(Anisotropic2_h) +#define Anisotropic2_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/11/05 23:36:47 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "AtmosModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief + * + * + * @ingroup RadiometricAndPhotometricCorrection + * @author 1998-12-21 Randy Kirk + * + * @internal + * @history 1998-12-21 Randy Kirk - USGS, Flagstaff - Original + * code. + * @history 2007-02-20 Janet Barrett - Imported from Isis2. + * @history 2007-08-15 Steven Lambright - Refactored code + * @history 2008-03-07 Janet Barrett - Moved code to set standard + * conditions to the AtmosModel class + * @history 2008-06-18 Christopher Austin - Fixed documentation error + * @history 2008-11-05 Jeannie Walldren - Replaced references + * to NumericalMethods::r8expint() with + * AtmosModel::En(), NumericalMethods::G11Prime() + * with AtmosModel::G11Prime(), and + * NumericalMethods::r8ei() with AtmosModel::Ei(). + * Added documentation from Isis2. + */ + class Anisotropic2 : public AtmosModel { + public: + Anisotropic2 (Pvl &pvl, PhotoModel &pmodel); + virtual ~Anisotropic2() {}; + + protected: + virtual void AtmosModelAlgorithm (double phase, double incidence, + double emission); + + private: + void SetAtmosHnorm(const double hnorm); + + double p_atmosHnorm; + + double p_wha2; + double p_wham; + double p_e1,p_e1_2,p_e2,p_e3,p_e4,p_e5; + double p_em; + double p_e; + double p_f1m,p_f2m,p_f3m,p_f4m; + double p_g12,p_g13,p_g14; + double p_g32,p_g33,p_g34; + double p_f1,p_f2,p_f3,p_f4; + double p_g11p,p_g12p,p_g13p,p_g14p; + double p_g32p,p_g33p,p_g34p; + double p_x0_0,p_y0_0; + double p_x0_1,p_y0_1; + double p_delta_0,p_delta_1; + double p_alpha0_0,p_alpha1_0; + double p_beta0_0,p_beta1_0; + double p_fac; + double p_den; + double p_p0,p_q0,p_p1,p_q1,p_q02p02,p_q12p12; + }; +}; + +#endif diff --git a/isis/src/base/objs/Anisotropic2/Anisotropic2.truth b/isis/src/base/objs/Anisotropic2/Anisotropic2.truth new file mode 100644 index 0000000000000000000000000000000000000000..44f0e98764ba3c539c407f55aa8c5bec2edf669f --- /dev/null +++ b/isis/src/base/objs/Anisotropic2/Anisotropic2.truth @@ -0,0 +1,34 @@ +UNIT TEST for Anisotropic2 atmospheric function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = AtmosphericModel + Group = Algorithm + Name = Anisotropic2 + Tau = 0.28 + End_Group +End_Object +End + +Test phase=0.0, incidence=0.0, emission=0.0 (standard conditions) ... +Pstd = 0 +Trans = 1 +Trans0 = 1 +Sbar = 0 + +Test phase=86.7226722, incidence=51.7002388, emission=38.9414439 ... +Pstd = 0.10248 +Trans = 0.731663 +Trans0 = 0.444706 +Sbar = 0.167394 + +Test phase=180.0, incidence=90.0, emission=90.0 ... +Pstd = 0.0328246 +Trans = 0.145965 +Trans0 = 5.19719e-07 +Sbar = 0.167394 + diff --git a/isis/src/base/objs/Anisotropic2/AtmosModel.plugin b/isis/src/base/objs/Anisotropic2/AtmosModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..6da347a4307fa18c6788dc2f7ba356670133f797 --- /dev/null +++ b/isis/src/base/objs/Anisotropic2/AtmosModel.plugin @@ -0,0 +1,4 @@ +Group = Anisotropic2 + Library = Anisotropic2 + Routine = Anisotropic2Plugin +End_Group diff --git a/isis/src/base/objs/Anisotropic2/Makefile b/isis/src/base/objs/Anisotropic2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ed6dd0bc1560a8c1e9da1f9801b8bd6a45a7956d --- /dev/null +++ b/isis/src/base/objs/Anisotropic2/Makefile @@ -0,0 +1,5 @@ +INCS = Anisotropic2.h +SRCS = Anisotropic2.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Anisotropic2/unitTest.cpp b/isis/src/base/objs/Anisotropic2/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1bebd39b17b906507e644729c2923507fdc8c3ef --- /dev/null +++ b/isis/src/base/objs/Anisotropic2/unitTest.cpp @@ -0,0 +1,78 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "AtmosModel.h" +#include "AtmosModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Anisotropic2.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + double pstd; + double trans; + double trans0; + double sbar; + + std::cout << "UNIT TEST for Anisotropic2 atmospheric function" << std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup alga("Algorithm"); + alga += PvlKeyword("Name", "Anisotropic2"); + alga += PvlKeyword("Tau", 0.28); + + PvlObject oa("AtmosphericModel"); + oa.AddGroup(alga); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(oa); + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + AtmosModel *am = AtmosModelFactory::Create(pvl,*pm); + + am->SetStandardConditions(true); + am->CalcAtmEffect(0.0,0.0,0.0,&pstd,&trans,&trans0,&sbar); + am->SetStandardConditions(false); + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 (standard conditions) ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + + am->SetAtmosTau(.28); + am->CalcAtmEffect(86.7226722,51.7002388,38.9414439,&pstd,&trans,&trans0,&sbar); + + std::cout << "Test phase=86.7226722, incidence=51.7002388, emission=38.9414439 ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + + am->CalcAtmEffect(180.0,90.0,90.0,&pstd,&trans,&trans0,&sbar); + + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/Application/Application.cpp b/isis/src/base/objs/Application/Application.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8db0dfb5451694c59ce3e5f3660d7d2adcf0e94c --- /dev/null +++ b/isis/src/base/objs/Application/Application.cpp @@ -0,0 +1,1201 @@ +#include "IsisDebug.h" + +#include +#include +#include +#include +#include +extern int errno; +#include +#include +#include +#include +#include + +#include "Application.h" +#include "UserInterface.h" +#include "Gui.h" +#include "Constants.h" +#include "Message.h" +#include "SessionLog.h" +#include "System.h" +#include "Preference.h" +#include "iException.h" +#include "CubeManager.h" +#include "Filename.h" + +/** + * @file + * $Revision: 1.22 $ + * $Date: 2010/06/29 23:42:18 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { + Application *iApp = NULL; + + /** + * Constuctor for the Application object  + * + * @param argc Number of arguments in argv[]. This must be passed by + * reference!! + * + * @param *argv[] An array containing the command line arguments + * + * @throws Isis::iException::Io - FileOpen error + */ + Application::Application(int &argc, char *argv[]) { + // Init socket communications + p_socket = -1; + p_childSocket = -1; + p_socketFile = ""; + p_ui = NULL; + + // Child pid and caught status + p_childPid = -1; + p_childCaught = false; + + // Save the application name + p_appName = argv[0]; + + // Get the starting wall clock time + p_datetime = DateTime(&p_startTime); + + // Init + p_startClock = 0; + p_startDirectIO = 0; + p_startPageFaults = 0; + p_startProcessSwaps = 0; + p_BatchlistPass = 0; + + // try to use US locale for numbers so we don't end up printing "," instead + // of "." where it might count. + setlocale(LC_NUMERIC, "en_US"); + + // Get the starting cpu time, direct I/Os, page faults, and swaps + p_startClock = clock(); + p_startDirectIO = DirectIO(); + p_startPageFaults = PageFaults(); + p_startProcessSwaps = ProcessSwaps(); + + // Create user interface and log + try { + Isis::Filename f = std::string(argv[0]) + ".xml"; + + // Create preferences + Isis::Preference::Preferences(f.Name() == "unitTest.xml"); + + if(!f.Exists()) { + f = "$ISISROOT/bin/xml/" + f.Name(); + if(!f.Exists()) { + std::string message = Isis::Message::FileOpen(f.Expanded()); + throw Isis::iException::Message(Isis::iException::Io, message, _FILEINFO_); + } + } + std::string xmlfile = f.Expanded(); + + p_ui = new Isis::UserInterface(xmlfile, argc, argv); + if(!p_ui->IsInteractive()) { + new QCoreApplication(argc, argv); + + // Add the Qt plugin directory to the library path + Isis::Filename qtpluginpath("$ISISROOT/3rdParty/plugins"); + QCoreApplication::addLibraryPath(qtpluginpath.Expanded().c_str()); + } + + } + catch(Isis::iException &e) { + exit(e.Report()); + } + + iApp = this; + } + + //! Destroys the Application object + Application::~Application() { + if(HasParent()) { + SendParentData("DONE", ""); + close(p_childSocket); + } + + if(p_socket >= 0) { + close(p_socket); + remove(p_socketFile.c_str()); + } + + if(p_ui) { + delete p_ui; + } + } + + /** + * Executes a function + * + * @param *funct + * + * @return int Status of the function execution + */ + int Application::Exec(void (*funct)()) { + int status = 0; + try { + if(p_ui->IsInteractive()) { + p_ui->TheGui()->Exec(funct); + } + else { + if(p_ui->BatchListSize() > 0) { + for(int i = 0; i < p_ui->BatchListSize(); i++) { + try { + p_ui->SetBatchList(i); + + if(i != 0) { + p_datetime = DateTime(&p_startTime); + p_startClock = clock(); + p_startDirectIO = DirectIO(); + p_startPageFaults = PageFaults(); + p_startProcessSwaps = ProcessSwaps(); + SessionLog::TheLog(true); + } + + funct(); + Application::FunctionCleanup(); + p_BatchlistPass++; + } + catch(Isis::iException &e) { + p_ui->SetErrorList(i); + status = Application::FunctionError(e); + if(p_ui->AbortOnError()) { + for(int j = (i + 1); j < p_ui->BatchListSize(); j++) { + p_ui->SetErrorList(j); + p_BatchlistPass++; + } + break; + } + } + } + } + else { + p_ui->SaveHistory(); + // The gui checks everything but not the command line mode so + // verify if necessary. Batchlist verifies on SetBatchList + p_ui->VerifyAll(); + funct(); + Application::FunctionCleanup(); + } + } + } + catch(Isis::iException &e) { + status = Application::FunctionError(e); + } + +#if 0 + catch(std::exception &e) { + std::string message = e.what(); + Isis::iExceptionSystem i(message, _FILEINFO_); + status = i.Report(); + } + catch(...) { + std::string message = "Unknown error expection"; + Isis::iExceptionSystem i(message, _FILEINFO_); + status = i.Report(); + } +#endif + + return status; + } + + /** + * Creates an application history PvlObject + * + * @return PvlObject + */ + PvlObject Application::History() { + PvlObject history(p_ui->ProgramName()); + history += Isis::PvlKeyword("IsisVersion", Isis::version); + history += Isis::PvlKeyword("ProgramVersion", p_ui->Version()); + QString path = QCoreApplication::applicationDirPath(); + history += Isis::PvlKeyword("ProgramPath", path); + history += Isis::PvlKeyword("ExecutionDateTime", p_datetime); + history += Isis::PvlKeyword("HostName", HostName()); + history += Isis::PvlKeyword("UserName", UserName()); + history += Isis::PvlKeyword("Description", p_ui->Brief()); + + // Add the user parameters + Isis::Pvl pvl; + p_ui->CommandLine(pvl); + history.AddGroup(pvl.FindGroup("UserParameters")); + + return history; + } + + /** + * Creates accounting PvlGroup + * + * @return PvlGroup Accounting Group + */ + PvlGroup Application::Accounting() { + // Grab the ending time to compute connect time + time_t endTime = time(NULL); + double seconds = difftime(endTime, p_startTime); + int minutes = (int)(seconds / 60.0); + seconds = seconds - minutes * 60.0; + int hours = minutes / 60; + minutes = minutes - hours * 60; + char temp[80]; + sprintf(temp, "%02d:%02d:%04.1f", hours, minutes, seconds); + std::string conTime = temp; + + // Grab the ending cpu time to compute total cpu time + clock_t endClock = clock(); + seconds = (double(endClock) - (double)p_startClock) / CLOCKS_PER_SEC; + minutes = (int)(seconds / 60.0); + seconds = seconds - minutes * 60.0; + hours = minutes / 60; + minutes = minutes - hours * 60; + sprintf(temp, "%02d:%02d:%04.1f", hours, minutes, seconds); + std::string cpuTime = temp; + + // Add this information to the log + PvlGroup acct("Accounting"); + acct += Isis::PvlKeyword("ConnectTime", conTime); + acct += Isis::PvlKeyword("CpuTime", cpuTime); + + // Not sure if these are really valuable. If deemed so then + // uncomment and complete private methods (DirectIO, Pagefaults, and + // ProcessSwaps). + //int directIO = DirectIO(); + //int pageFaults = PageFaults(); + //int processSwaps = ProcessSwaps(); + //acct += Isis::PvlKeyword("DirectIo",directIO); + //acct += Isis::PvlKeyword("PageFaults",pageFaults); + //acct += Isis::PvlKeyword("ProcessSwaps",processSwaps); + + return acct; + } + + /** + * Returns the current number of I/O's + * + * @return int The current number of I/O's + */ + int Application::DirectIO() { + return 0 - p_startDirectIO; + } + + /** + * Returns the current number of faults + * + * @return The current number of page faults + */ + int Application::PageFaults() { + return 0 - p_startPageFaults; + } + + /** + * Returns the current number of swaps + * + * @return The current number of process swaps + */ + int Application::ProcessSwaps() { + return 0 - p_startProcessSwaps; + } + + /** + * Writes Pvl results to sessionlog and printfile. + * + * @param results PvlGroup of results to add to the session log + */ + void Application::Log(PvlGroup &results) { + // Add it to the log file + static bool blankLine = false; + SessionLog::TheLog().AddResults(results); + + // See if the log file will be written to the terminal/gui + if(SessionLog::TheLog().TerminalOutput()) return; + + // See if we should write the info to our parents gui + if(HasParent()) { + std::ostringstream ostr; + if(blankLine) ostr << std::endl; + ostr << results << std::endl; + std::string data = ostr.str(); + SendParentData(std::string("LOG"), data); + } + + // Otherwise see if we need to write to our gui + else if(iApp->GetUserInterface().IsInteractive()) { + std::ostringstream ostr; + if(blankLine) ostr << std::endl; + ostr << results << std::endl; + iApp->GetUserInterface().TheGui()->Log(ostr.str()); + iApp->GetUserInterface().TheGui()->ShowLog(); + } + + // Otherwise its command line mode + else { + if(blankLine) std::cout << std::endl; + std::cout << results << std::endl; + } + blankLine = true; + } + + /** + * Writes the Pvl results to the sessionlog, but not to the printfile + * + * @param results Pvl containing the results to add to the session log + */ + void Application::GuiLog(Pvl &results) { + // See if we should write the info to our parents gui + if(HasParent()) { + std::ostringstream ostr; + ostr << results << std::endl; + std::string data = ostr.str(); + SendParentData(std::string("LOG"), data); + } + + // Otherwise see if we need to write to our gui + else if(iApp->GetUserInterface().IsInteractive()) { + std::ostringstream ostr; + ostr << results << std::endl; + iApp->GetUserInterface().TheGui()->Log(ostr.str()); + iApp->GetUserInterface().TheGui()->ShowLog(); + } + } + + /** + * Writes the PvlGroup results to the sessionlog, but not to the printfile + * + * @param results PvlGroup containing the results to add to the session log + */ + void Application::GuiLog(PvlGroup &results) { + // See if we should write the info to our parents gui + if(HasParent()) { + std::ostringstream ostr; + ostr << results << std::endl; + std::string data = ostr.str(); + SendParentData(std::string("LOG"), data); + } + + // Otherwise see if we need to write to our gui + else if(iApp->GetUserInterface().IsInteractive()) { + std::ostringstream ostr; + ostr << results << std::endl; + iApp->GetUserInterface().TheGui()->Log(ostr.str()); + iApp->GetUserInterface().TheGui()->ShowLog(); + } + } + + /** + * Writes the results to the sessionlog, but not to the printfile + * + * @param results string containing the results to add to the session log + */ + void Application::GuiLog(std::string &results) { + // See if we should write the info to our parents gui + if(HasParent()) { + SendParentData(std::string("LOG"), results); + } + + // Otherwise see if we need to write to our gui + else if(iApp->GetUserInterface().IsInteractive()) { + iApp->GetUserInterface().TheGui()->Log(results); + iApp->GetUserInterface().TheGui()->ShowLog(); + } + } + + /** + * Returns the UserInterface object + * + * @return A pointer to the UserInterface object + */ + Isis::UserInterface &Application::GetUserInterface() { + return *iApp->p_ui; + } + + /** + * Returns whether the application has a parent or not + * + * @return bool Returns true if it has a parent, and false if it does not + */ + bool Application::HasParent() { + if(iApp == NULL) return false; + if(iApp->p_ui == NULL) return false; + if(iApp->p_ui->ParentId() == 0) return false; + return true; + } + + /** + * Sends errors to the parent + * + * @param &errors A PvlObject of the errors + */ + void Application::SendParentErrors(Isis::PvlObject &errors) { + for(int i = 0; i < errors.Groups(); i++) { + std::ostringstream ostr; + ostr << errors.Group(i) << std::endl; + std::string data = ostr.str(); + SendParentData(std::string("ERROR"), data); + } + } + + /** + * Sends data from the child to the parent + * + * @param code + * + * @param &message The message the child is sending to the parent + * + * @throws Isis::iException::System - Unable to connect to the parent + * @throws Isis::iException::System - Unable to send to the parent + */ + int Application::p_childSocket = -1; + void Application::SendParentData(const std::string code, const std::string &message) { + // See if we need to connect to the parent + if(p_childSocket < 0) { + std::string socketFile = "/tmp/isis_" + Isis::iString(iApp->GetUserInterface().ParentId()); + sockaddr_un socketName; + socketName.sun_family = AF_UNIX; + strcpy(socketName.sun_path, socketFile.c_str()); + p_childSocket = socket(PF_UNIX, SOCK_STREAM, 0); + if(p_childSocket == -1) { + std::string msg = "Unable to create child-to-parent socket [" + + socketFile + "]"; + std::cout << msg << std::endl; + throw Isis::iException::Message(Isis::iException::System, + msg, _FILEINFO_); + } + + errno = 0; + int len = strlen(socketName.sun_path) + sizeof(socketName.sun_family); + int status = connect(p_childSocket, (struct sockaddr *)&socketName, len); + if(status == -1) { + std::string msg = "Unable to connect to parent [" + + Isis::iString(iApp->GetUserInterface().ParentId()) + "] errno = " + + iString(errno); + std::cout << msg << std::endl; + throw Isis::iException::Message(Isis::iException::System, + msg, _FILEINFO_); + } + } + + // Have connection so build data string and send it + std::string data = code; + data += char(27); + if(message != "") { + data += message; + data += char(27); + } + + if(send(p_childSocket, data.c_str(), data.size(), 0) < 0) { + std::string msg = "Unable to send to parent [" + + Isis::iString(iApp->GetUserInterface().ParentId()) + "]"; + std::cout << msg << std::endl; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + } + + /** + * Cleans up after the function by writing the log, saving the history, and + * either sending the log to the parent if it has one, printing the log data + * to the terminal or showing the log in the gui. + */ + void Application::FunctionCleanup() { + CubeManager::CleanUp(); + + SessionLog::TheLog().Write(); + + if(SessionLog::TheLog().TerminalOutput()) { + if(HasParent()) { + std::ostringstream ostr; + ostr << SessionLog::TheLog() << std::endl; + std::string data = ostr.str(); + SendParentData(std::string("LOG"), data); + } + else if(p_ui->IsInteractive()) { + std::ostringstream ostr; + ostr << SessionLog::TheLog() << std::endl; + p_ui->TheGui()->Log(ostr.str()); + p_ui->TheGui()->ShowLog(); + } + else { + std::cout << SessionLog::TheLog() << std::endl; + } + } + + // If debugging flag on write debugging log + if(p_ui->GetInfoFlag()) { + std::string filename = p_ui->GetInfoFileName(); + Pvl log; + iString app = (iString)QCoreApplication::applicationDirPath() + "/" + (iString)p_appName; + if(p_BatchlistPass == 0) { + std::stringstream ss ; + ss << SessionLog::TheLog(); + ss.clear(); + ss >> log; + PvlGroup uname = Isis::GetUnameInfo(); + PvlGroup env = Isis::GetEnviromentInfo(); + log.AddGroup(uname); + log.AddGroup(env); + } + + // Write to file + if(filename.compare("") != 0) { + + if(p_BatchlistPass == 0) { + std::ofstream debugingLog(filename.c_str()); + if(!debugingLog.good()) { + std::string msg = "Error opening debugging log file [" + filename + "]"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + debugingLog << log << std::endl; + debugingLog << "\n############### User Preferences ################\n" << std::endl; + debugingLog << Preference::Preferences(); + debugingLog << "\n############## System Disk Space ################\n" << std::endl; + debugingLog << SystemDiskSpace() << std::endl; + debugingLog << "\n############ Executable Information #############\n" << std::endl; + debugingLog << GetLibraryDependencies(app) << std::endl; + debugingLog.close(); + } + else { + std::ofstream debugingLog(filename.c_str(), std::ios_base::app); + debugingLog << SessionLog::TheLog() << std::endl; + debugingLog.close(); + } + } + else { // Write to std out + if(p_BatchlistPass == 0) { + std::cout << log << std::endl; + std::cout << "\n############### User Preferences ################\n" << std::endl; + std::cout << Preference::Preferences(); + std::cout << "\n############## System Disk Space ################\n" << std::endl; + std::cout << SystemDiskSpace() << std::endl; + std::cout << "\n############ Executable Information #############\n" << std::endl; + std::cout << GetLibraryDependencies(app) << std::endl; + } + else { + std::cout << SessionLog::TheLog() << std::endl; + } + } + } + + + } + + /** + * Adds the error to the session log, sends the error to the parent if it has + * one, loads the error message into the gui or prints it to the command line, + * gets the error type and returns it. + * + * @param e The Isis::iException + * + * @return int The Error Type + */ + int Application::FunctionError(Isis::iException &e) { + Pvl errors = e.PvlErrors(); + SessionLog::TheLog().AddError(errors); + SessionLog::TheLog().Write(); + + if(HasParent()) { + SendParentErrors(errors); + } + else if(p_ui->IsInteractive()) { + if(e.IsPvlFormat()) { + std::ostringstream ostr; + ostr << errors << std::endl; + p_ui->TheGui()->LoadMessage(ostr.str()); + } + else { + p_ui->TheGui()->LoadMessage(e.Errors()); + } + } + else if(SessionLog::TheLog().TerminalOutput()) { + std::cerr << SessionLog::TheLog() << std::endl; + } + else if(e.IsPvlFormat()) { + std::cerr << errors << std::endl; + } + else { + std::cerr << e.Errors() << std::endl; + } + + // If debugging flag on write debugging log + if(p_ui->GetInfoFlag()) { + std::string filename = p_ui->GetInfoFileName(); + Pvl log; + iString app = (iString)QCoreApplication::applicationDirPath() + "/" + (iString)p_appName; + if(p_BatchlistPass == 0) { + std::stringstream ss ; + ss << SessionLog::TheLog(); + ss.clear(); + ss >> log; + PvlGroup uname = Isis::GetUnameInfo(); + PvlGroup env = Isis::GetEnviromentInfo(); + log.AddGroup(uname); + log.AddGroup(env); + } + + // Write to file + if(filename.compare("") != 0) { + if(p_BatchlistPass == 0) { + std::ofstream debugingLog(filename.c_str()); + if(!debugingLog.good()) { + std::string msg = "Error opening debugging log file [" + filename + "]"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + debugingLog << log << std::endl; + debugingLog << "\n############### User Preferences ################\n" << std::endl; + debugingLog << Preference::Preferences(); + debugingLog << "\n############ System Disk Space #############\n" << std::endl; + debugingLog << SystemDiskSpace() << std::endl; + debugingLog << "\n############ Executable Information #############\n" << std::endl; + debugingLog << GetLibraryDependencies(app) << std::endl; + debugingLog.close(); + } + else { + std::ofstream debugingLog(filename.c_str(), std::ios_base::app); + debugingLog << SessionLog::TheLog() << std::endl; + debugingLog.close(); + } + } + else { // Write to std out + if(p_BatchlistPass == 0) { + std::cout << log << std::endl; + std::cout << "\n############### User Preferences ################\n" << std::endl; + std::cout << Preference::Preferences(); + std::cout << "\n############ System Disk Space #############\n" << std::endl; + std::cout << SystemDiskSpace() << std::endl; + std::cout << "\n############ Executable Information #############\n" << std::endl; + std::cout << GetLibraryDependencies(app) << std::endl; + } + else { + std::cout << SessionLog::TheLog() << std::endl; + } + } + } + + int errorType = (int)e.Type(); + e.Clear(); + return errorType; + } + + /** + * Loads the error message into the gui, but does not write it to the session + * log. + * + * @param e The Isis::iException + */ + void Application::GuiReportError(Isis::iException &e) { + Pvl errors = e.PvlErrors(); + if(e.Type() == Isis::iException::Cancel) { + e.Clear(); + p_ui->TheGui()->ProgressText("Stopped"); + } + if(e.IsPvlFormat()) { + std::ostringstream ostr; + ostr << errors << std::endl; + p_ui->TheGui()->LoadMessage(ostr.str()); + } + else { + p_ui->TheGui()->LoadMessage(e.Errors()); + } + + if(p_ui->TheGui()->ShowWarning()) exit(0); + p_ui->TheGui()->ProgressText("Error"); + e.Clear(); + } + + /** + * Returns the name of the application. Returns 'Unknown' if the application + * or gui equal NULL + * + * @return string The application name + */ + QString Application::p_appName("Unknown"); + std::string Application::Name() { + return p_appName.toStdString(); + } + + /** + * Updates the progress bar in the gui. + * + * @param text Progress text + * + * @param print + */ + void Application::UpdateProgress(const std::string &text, bool print) { + if(HasParent()) { + std::string msg = p_ui->ProgramName() + ": " + text; + SendParentData(std::string("PROGRESSTEXT"), msg); + } + else if(p_ui->IsInteractive()) { + p_ui->TheGui()->ProgressText(text); + } + else if(print) { + std::string msg = p_ui->ProgramName() + ": " + text; + std::cout << msg << std::endl; + } + } + + /** + * Updates the progress bar percent. + * + * @param percent The percent of the application that is complete + * + * @param print + */ + void Application::UpdateProgress(int percent, bool print) { + if(HasParent()) { + std::string data = Isis::iString(percent); + SendParentData(std::string("PROGRESS"), data); + } + else if(p_ui->IsInteractive()) { + p_ui->TheGui()->Progress(percent); + } + else if(print) { + if(percent < 100) { + std::cout << percent << "% Processed\r" << std::flush; + } + else { + std::cout << percent << "% Processed" << std::endl; + } + } + } + + /** + * Processes the gui events. If the event is cancel, it throws a cancel + * exception + * + * @throws Isis::iException::Cancel - The event was cancelled + */ + void Application::ProcessGuiEvents() { + if(p_ui->IsInteractive()) { + bool cancel = p_ui->TheGui()->ProcessEvents(); + if(cancel) { + + // We need to catch our child if we are canceling, throw our own error if + // the return status isn't zero, blocking wait. + if(!p_childCaught) { + int status = 0; + waitpid(p_childPid, &status, 0); + p_childCaught = true; + if(status) { + std::string msg = "Program execution canceled, child returned nonzero status [" + + (iString)status + "]"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + } + throw Isis::iException::Message(Isis::iException::Cancel, "", _FILEINFO_); + } + } + } + + /** + * Executes the program passed in with the given string of parameters. + * + * @param &program The program name to be run + * + * @param ¶meters A string of the parameters and their values to be run + * with the application name passed in + * + * @throws Isis::iException::System - Unable to execute the command + */ + void Application::Exec(const std::string &program, const std::string ¶meters) { + // Setup the command line + Isis::Filename bin(program); + if(!bin.Exists()) { + bin = "$ISISROOT/bin/" + program; + } + //Isis::Filename bin("$ISISROOT/bin/"+program); + std::string command = bin.Expanded() + " " + parameters; + + // If we are interactive we must do an asychronous execute + // so we can watch our socket + if(p_ui->IsInteractive()) { + p_pid = getpid(); + p_childCaught = false; + // fork and save off our child + if((p_childPid = fork()) == -1) { + std::string msg = "Unable to execute command [" + command + "]"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + + // Parent code + if(p_childPid != 0) { + EstablishConnections(); + ParentFork(command, program); + ProcessGuiEvents(); + + // ParentFork only returns after the child has returned success + // we should be safe to pick up a finished child at this point + // `man 2 wait` for more info, this is a blocking wait for specific pid. + // Odds are if we make it to here, we were successful, but, we'll + // still be verifying that. + if(!p_childCaught) { + int status = 0; + waitpid(p_childPid, &status, 0); + p_childCaught = true; + if(status) { + std::string msg = "Child process return status was nonzero, something went wrong"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + } + + // Child code + } + else { + ChildFork(command); + } + } + // Handle command line programs invoked by GUI programs + else if(HasParent()) { + SendParentData("DISCONNECT", ""); + close(p_childSocket); + p_childSocket = -1; + command += " -pid=" + Isis::iString((int)p_ui->ParentId()); + Isis::System(command); + SendParentData("RECONNECT", ""); + } + // Otherwise just execute the command and wait for it to finish + else { + Isis::System(command); + } + } + + /** + * Establishes a connection by creating a new socket, getting the process id + * number and creating a unique filename that it binds to the socket. + * It then sets up the socket to listen. + * + * @throws Isis::iException::System - Unable to create the socket + * @throws Isis::iException::System - Unable to bind the socket to the filename + * @throws Isis::iException::System - Unable to listen to the socket + */ + void Application::EstablishConnections() { + if(p_socket != -1) return; + + // Create a socket + if((p_socket = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) { + std::string msg = "Unable to create socket"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + + // Get the process id and create a unique filename + p_socketFile = "/tmp/isis_" + Isis::iString((int)p_pid); + + // Bind the file to the socket + p_socketName.sun_family = AF_UNIX; + strcpy(p_socketName.sun_path, p_socketFile.c_str()); + int len = strlen(p_socketName.sun_path) + sizeof(p_socketName.sun_family); + if(bind(p_socket, (struct sockaddr *)&p_socketName, len) == -1) { + std::string msg = "Unable to bind to socket [" + p_socketFile + "]"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + + // Set up to listen to the socket + if(listen(p_socket, 5) == -1) { + std::string msg = "Unable to listen to socket [" + p_socketFile + "]"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + } + + /** + * Runs the entered command line and returns the status to the parent + * + * @param commandLine The command line to be run + */ + void Application::ChildFork(const std::string &commandLine) { + // The child fork doesn't have the socket + p_socket = -1; + + // Append the pid as an argument + std::string command = commandLine + " -pid=" + Isis::iString((int)p_pid); + + // Run the command + int status = system(command.c_str()); + + int childSocket = socket(PF_UNIX, SOCK_STREAM, 0); + if(childSocket == -1) { + std::cout << "couldn't create socket to parent fork" << std::endl << std::flush; + exit(255); + } + + sockaddr_un socketName; + socketName.sun_family = AF_UNIX; + iString socketFile = "/tmp/isis_" + Isis::iString((int)p_pid); + strcpy(socketName.sun_path, socketFile.c_str()); + + int len = strlen(socketName.sun_path) + sizeof(socketName.sun_family); + if(connect(childSocket, (struct sockaddr *)&socketName, len) == -1) { + std::cout << "couldn't connect to parent fork" << std::endl << std::flush; + exit(255); + } + + if(status != 0) { + char terminate[10] = "TERMINATE"; + terminate[9] = 27; // escape character + if(send(childSocket, terminate, sizeof(terminate), 0) < 0) { + std::cout << "couldn't send terminate to parent fork" << std::endl << std::flush; + exit(255); + } + } + else { + char success[8] = "SUCCESS"; + success[7] = 27; // escape character + if(send(childSocket, success, sizeof(success), 0) < 0) { + std::cout << "couldn't send success to parent fork" << std::endl << std::flush; + exit(255); + } + } + + close(childSocket); + exit(0); + } + + /** + * + * + * @param &command The command to run + * + * @param &program The program name currently running + * + * @throws Isis::iException::System - Unable to execute the command + * @throws Isis::iException::System - Unknown command on the socket + */ + void Application::ParentFork(const std::string &command, const std::string &program) { + // Try to accept a connection from the program our child fork executed. If + // the program we ran failed to start then we are waiting for the connection + // in the child fork + p_buffer = ""; + p_queue.clear(); + int status = -21; // Magic number hopefully not going to appear in a return status + int childForkDone = false; + while(!childForkDone) { + int childSocket = -1; + while(childSocket == -1) { + + // verify the child hasn't had any problems, + // should only be exiting here if there were problems + // nonblocking wait + if(!p_childCaught) { + waitpid(p_childPid, &status, WNOHANG); + if(status != -21) { + p_childCaught = true; + if(status == 255) { + std::string msg = "Error in connection between processes"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + } + } + errno = 0; + socklen_t len = sizeof(p_socketName); + childSocket = accept(p_socket, (struct sockaddr *)&p_socketName, &len); + if(childSocket == -1) { + if(errno != EINTR) { + std::cout << "accept errno = " << errno << std::endl << std::flush; + std::string msg = "Unable to accept socket connection [" + + p_socketFile + "] from child process"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + } + } + + // Looks like we are the parent so we must wait for input to come from + // the child. + bool done = false; + while(!done) { + WaitForCommand(childSocket); + + // Again, check for problems, such as with socket communication + // there is a possibility we could catch a successful run here + // nonblocking wait + if(!p_childCaught) { + waitpid(p_childPid, &status, WNOHANG); + if(status != -21) { + p_childCaught = true; + if(status == 255) { + std::string msg = "Error in connection between processes"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + } + } + + while(p_queue.size() > 0) { + if(p_queue[0] == "DONE") { + p_queue.erase(p_queue.begin()); + done = true; + } + else if(p_queue[0] == "DISCONNECT") { + p_queue.erase(p_queue.begin()); + done = true; + } + else if(p_queue[0] == "RECONNECT") { + p_queue.erase(p_queue.begin()); + } + else if(p_queue[0] == "SUCCESS") { + p_queue.erase(p_queue.begin()); + done = true; + childForkDone = true; + } + else if(p_queue[0] == "TERMINATE") { + // Should only happen if child fork could not fire off the process + p_queue.erase(p_queue.begin()); + std::string msg = "Unable to execute command [" + command + "]"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + else if(p_queue[0] == "ERROR") { + p_queue.erase(p_queue.begin()); + while(p_queue.size() == 0) WaitForCommand(childSocket); + std::stringstream str; + str << p_queue[0]; + p_queue.erase(p_queue.begin()); + + Isis::Pvl error; + str >> error; + + for(int i = 0; i < error.Groups(); i++) { + Isis::PvlGroup &g = error.Group(i); + std::string eclass = g["Class"]; + std::string emsg = g["Message"]; + int ecode = g["Code"]; + std::string efile = g["File"]; + int eline = g["Line"]; + + Isis::iException::Message((Isis::iException::errType)ecode, + emsg, (char *)efile.c_str(), eline); + } + } + else if(p_queue[0] == "PROGRESSTEXT") { + p_queue.erase(p_queue.begin()); + while(p_queue.size() == 0) WaitForCommand(childSocket); + p_ui->TheGui()->ProgressText(p_queue[0]); + p_ui->TheGui()->Progress(0); + p_queue.erase(p_queue.begin()); + } + else if(p_queue[0] == "PROGRESS") { + p_queue.erase(p_queue.begin()); + while(p_queue.size() == 0) WaitForCommand(childSocket); + p_ui->TheGui()->Progress(Isis::iString(p_queue[0]).ToInteger()); + p_queue.erase(p_queue.begin()); + } + else if(p_queue[0] == "LOG") { + p_queue.erase(p_queue.begin()); + while(p_queue.size() == 0) WaitForCommand(childSocket); + + std::stringstream str; + str << p_queue[0]; + p_queue.erase(p_queue.begin()); + + p_ui->TheGui()->Log(str.str()); + } + else { + std::string msg = "Unknown command [" + p_queue[0]; + msg += "] on socket [" + p_socketFile + "]"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + ProcessGuiEvents(); + // Last check for any bad return status from child + if(!p_childCaught) { + waitpid(p_childPid, &status, WNOHANG); + if(status != -21) { + p_childCaught = true; + if(status == 255) { + std::string msg = "Error in connection between processes"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + } + } + } + } + close(childSocket); + } + } + + /** + * Trys to accept a connection from the child socket. When it does accept the + * connection it receives the command from the child and pushes it into a + * buffer which is then pushed onto the queue. + * + * @param childSocket The child socket to establish connection to + * + * @throws Isis::iException::System - Unable to read from the socket + */ + void Application::WaitForCommand(int childSocket) { + + // Now we are ready to receive commands from our child (like in real + // life) so receive the command + int bytes; + char buf[1024*1024]; + if((bytes = recv(childSocket, &buf, 1024 * 1024, 0)) < 0) { + std::string msg = "Unable to read from socket [" + p_socketFile + "]"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + + // Push everything onto our string buffer + for(int i = 0; i < bytes; i++) p_buffer += buf[i]; + + // Move esc delimited strings to our command queue + std::string::size_type pos; + while((pos = p_buffer.find(27)) != std::string::npos) { + p_queue.push_back(p_buffer.substr(0, pos)); + p_buffer.erase(0, pos + 1); + } + } + + /** + * Returns the date and time as a string. + * + * @param *curtime + * + * @return string The date and time + */ + std::string Application::DateTime(time_t *curtime) { + time_t startTime = time(NULL); + if(curtime != 0) *curtime = startTime; + struct tm *tmbuf = localtime(&startTime); + char timestr[80]; + strftime(timestr, 80, "%Y-%m-%dT%H:%M:%S", tmbuf); + return(std::string) timestr; + } + + /** + * Returns the user name. Returns 'Unknown' if it cannot find the user name. + * + * @return string User Name + */ + std::string Application::UserName() { + std::string user = "Unknown"; + char *userPtr = getenv("USER"); + if(userPtr != NULL) user = userPtr; + return user; + } + + /** + * Returns the host name. Returns 'Unknown' if it cannot find the host name. + * + * @return string Host Name + */ + std::string Application::HostName() { + std::string host = "Unknown"; + char *hostPtr = getenv("HOST"); + if(hostPtr == NULL) hostPtr = getenv("HOSTNAME"); + if(hostPtr != NULL) host = hostPtr; + return host; + } + +} //end namespace isis + diff --git a/isis/src/base/objs/Application/Application.h b/isis/src/base/objs/Application/Application.h new file mode 100644 index 0000000000000000000000000000000000000000..30071f36c5bce6c3af9ce3cd90409fb4b35df990 --- /dev/null +++ b/isis/src/base/objs/Application/Application.h @@ -0,0 +1,167 @@ +#if !defined(Application_h) +#define Application_h + +/** + * @file + * $Revision: 1.16 $ + * $Date: 2010/06/29 23:42:18 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "Pvl.h" +#include "UserInterface.h" + +namespace Isis { + class Gui; + class Progress; + + /** + * + * + * @internal + * @history 2005-12-16 Elizabeth Miller - added documentation and -BATCHLIST + * capabilities + * @history 2006-02-13 Elizabeth Miller - Added GuiHelper Capabilities + * @history 2006-02-16 Jeff Anderson - Fixed race condition on sockets + * between communicating ISIS programs + * @history 2006-02-17 Fixed bug with application name being unknown if + * the user interface threw an error + * @history 2006-02-27 Elizabeth Miller - Added GuiLog and GuiReportError + * methods + * @history 2006-07-28 Jeff Anderson - Fixed another race condition with + * sockets between communicating ISIS programs. Also + * updated progress to output name of the program + * @history 2006-08-30 Jeff Anderson - Create a + * QCoreApplication if in command line + * mode. + * @history 2007-10-04 Steven Koechle - Added output capability for + * debugging log for -info flag + * @history 2008-01-04 Jeannie Walldren - Changed + * description of Log method + * @history 2008-01-09 Steven Lambright - Fixed Memory Leak + * @history 2008-04-16 Steven Lambright - Added parameter check that was + * removed from UserInterface + * @history 2008-06-18 Christopher Austin - Fixed documentation error + * @history 2008-06-19 Steven Lambright - Added CubeManager::CleanUp call to + * clean up cubes in memory after calling IsisMain. + * @history 2008-06-24 Steven Koechle - Added Preferences to Debugging Log. + * @history 2008-07-08 Steven Lambright - Singletons now destroy themselves + * instead of Application deleting them + * @history 2008-07-08 Steven Lambright - p_ui is no longer static, which + * fixes issues with the mac unit tests. + * @history 2009-11-19 Kris Becker - Made argc pass by reference since Qt's + * QApplication/QCoreApplication requires it + * @history 2010-03-17 Stuart Sides - Added the location of the Qt plugins + * into the library path + * @history 2010-06-29 Steven Lambright - Added a setlocale to english for + * numeric values + */ + class Application { + public: + Application(int &argc, char *argv[]); + ~Application(); + + int Exec(void (*funct)()); + PvlGroup Accounting(); + PvlObject History(); + + static UserInterface &GetUserInterface(); + static void Log(PvlGroup &results); + static void GuiLog(Pvl &results); + static void GuiLog(PvlGroup &results); + static void GuiLog(std::string &results); + static std::string Name(); + + void RegisterGuiHelpers(std::map helpers) { + p_guiHelpers = helpers; + }; + void *GetGuiHelper(std::string helper) { + return p_guiHelpers[helper]; + }; + + void GuiReportError(Isis::iException &e); + + void Exec(const std::string &program, const std::string ¶meters); + + static std::string UserName(); + static std::string HostName(); + static std::string DateTime(time_t *curtime = 0); + + private: + int p_BatchlistPass; + int DirectIO(); + int PageFaults(); + int ProcessSwaps(); + + time_t p_startTime; + clock_t p_startClock; + std::string p_datetime; + int p_startDirectIO; + int p_startPageFaults; + int p_startProcessSwaps; + pid_t p_childPid; + bool p_childCaught; + + UserInterface *p_ui; //! p_queue; + std::map p_guiHelpers; + + static QString p_appName; + }; + + extern Application *iApp; +}; + +#endif diff --git a/isis/src/base/objs/Application/Application.truth b/isis/src/base/objs/Application/Application.truth new file mode 100644 index 0000000000000000000000000000000000000000..5c8db90b9f7edcb084b6a32194b0cb6b64a96730 --- /dev/null +++ b/isis/src/base/objs/Application/Application.truth @@ -0,0 +1,99 @@ +Testing Isis::Application Class ... + +Group = Accounting + ConnectTime = 00:00:01.0 + CpuTime = 00:00:00.0 +End_Group + +Object = unittest + IsisVersion = "3.0.16 beta | 2006-03-22" + ProgramVersion = 2006-03-30 + ExecutionDateTime = 2006-03-30T10:53:42 + HostName = orkin + UserName = janderso + Description = "Unit test for Application class" + + Group = UserParameters + FROM = unitTest.cub + TO = /tmp/isisprocess_01.cub + TO2 = /tmp/isisprocess_02.cub + TO3 = /tmp/isisprocess_03.cub + TO4 = /tmp/isisprocess_04.cub + End_Group +End_Object + +Can't test Gui methods + GuiLog(Pvl &results) + GuiLog(PvlGroup &results) + GuiLog(std::string &results) + GuiReportErrorLog(iException &e) + +GuiHelpers ok + +In myFunct + +**PROGRAMMER ERROR** testing an error + +Object = unittest + IsisVersion = "3.0.16 beta | 2006-03-22" + ProgramVersion = 2006-03-30 + ExecutionDateTime = 2006-03-30T10:53:42 + HostName = orkin + UserName = janderso + Description = "Unit test for Application class" + + Group = UserParameters + FROM = unitTest.cub + TO = /tmp/isisprocess_01.cub + TO2 = /tmp/isisprocess_02.cub + TO3 = /tmp/isisprocess_03.cub + TO4 = /tmp/isisprocess_04.cub + End_Group + + Group = Accounting + ConnectTime = 00:00:01.0 + CpuTime = 00:00:00.0 + End_Group + + Group = Accounting + ConnectTime = 00:00:01.0 + CpuTime = 00:00:00.1 + End_Group +End_Object + +Object = unittest + IsisVersion = "3.0.16 beta | 2006-03-22" + ProgramVersion = 2006-03-30 + ExecutionDateTime = 2006-03-30T10:53:42 + HostName = orkin + UserName = janderso + Description = "Unit test for Application class" + + Group = UserParameters + FROM = unitTest.cub + TO = /tmp/isisprocess_01.cub + TO2 = /tmp/isisprocess_02.cub + TO3 = /tmp/isisprocess_03.cub + TO4 = /tmp/isisprocess_04.cub + End_Group + + Group = Accounting + ConnectTime = 00:00:01.0 + CpuTime = 00:00:00.0 + End_Group + + Group = Accounting + ConnectTime = 00:00:01.0 + CpuTime = 00:00:00.1 + End_Group + + Group = Error + Program = unitTest + Class = "PROGRAMMER ERROR" + Code = 2 + Message = "testing an error" + File = unitTest.cpp + Line = 16 + End_Group +End_Object +End diff --git a/isis/src/base/objs/Application/Makefile b/isis/src/base/objs/Application/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c7050201505107fdfc441c17010ff31a22e0217d --- /dev/null +++ b/isis/src/base/objs/Application/Makefile @@ -0,0 +1,5 @@ +INCS = Application.h +SRCS = Application.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Application/unitTest.cpp b/isis/src/base/objs/Application/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46b76a8d27d645c709c704d05e0e91ae91d855e8 --- /dev/null +++ b/isis/src/base/objs/Application/unitTest.cpp @@ -0,0 +1,64 @@ +#include +#include +#include "Application.h" +#include "iException.h" +#include "Preference.h" +#include "PvlGroup.h" +#include "PvlObject.h" +#include "Pvl.h" + +void myFunct() { + std::cout << "In myFunct" << std::endl; +} + +void myError() { + std::string msg = "testing an error"; + throw Isis::iException::Message(Isis::iException::Programmer, msg, _FILEINFO_); +} + +using namespace std; +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + std::cout << "Testing Isis::Application Class ... " << std::endl; + std::cout << std::endl; + Isis::Application a(argc, argv); + + Isis::PvlGroup acct = a.Accounting(); + a.Log(acct); + std::cout << std::endl; + + Isis::PvlObject hist = a.History(); + std::cout << hist << std::endl; + std::cout << std::endl; + + std::cout << "Can't test Gui methods" << std::endl; + std::cout << " GuiLog(Pvl &results)" << std::endl; + std::cout << " GuiLog(PvlGroup &results)" << std::endl; + std::cout << " GuiLog(std::string &results)" << std::endl; + std::cout << " GuiReportErrorLog(iException &e)" << std::endl; + std::cout << std::endl; + + std::map helpers; + helpers["helper"] = (void *) myFunct; + a.RegisterGuiHelpers(helpers); + if(a.GetGuiHelper("helper") == (void *) myFunct) { + std::cout << "GuiHelpers ok" << std::endl; + } + else { + std::cout << "GuiHelpers bad" << std::endl; + } + std::cout << std::endl; + + a.Exec(myFunct); + std::cout << std::endl; + + a.Exec(myError); + std::cout << std::endl; + + Isis::Pvl p("print.prt"); + std::cout << p << std::endl; + + remove("print.prt"); + return 0; +} diff --git a/isis/src/base/objs/Application/unitTest.exclude b/isis/src/base/objs/Application/unitTest.exclude new file mode 100644 index 0000000000000000000000000000000000000000..0fb6a5c297a0279fec903965a35d41c7fb643986 --- /dev/null +++ b/isis/src/base/objs/Application/unitTest.exclude @@ -0,0 +1,9 @@ +ProgramPath +DateTime +User +HostName +IsisVersion +Connect +Cpu +Program = + diff --git a/isis/src/base/objs/Application/unitTest.xml b/isis/src/base/objs/Application/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..0739a86801e03891ef5f9903c829e573ab9f0d83 --- /dev/null +++ b/isis/src/base/objs/Application/unitTest.xml @@ -0,0 +1,95 @@ + + + + Unit test for Application class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + unitTest.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisprocess_01.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisprocess_02.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisprocess_03.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisprocess_04.cub + + + + diff --git a/isis/src/base/objs/AtmosModel/AtmosModel.cpp b/isis/src/base/objs/AtmosModel/AtmosModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..167d906eb2acc453b92964fd0ad014dcff8d04aa --- /dev/null +++ b/isis/src/base/objs/AtmosModel/AtmosModel.cpp @@ -0,0 +1,951 @@ +#include +#include +#include "Pvl.h" +#include "iString.h" +#include "AtmosModel.h" +#include "NumericalApproximation.h" +#include "NumericalAtmosApprox.h" +#include "PhotoModel.h" +#include "Minnaert.h" +#include "LunarLambert.h" +#include "Plugin.h" +#include "iException.h" +#include "Filename.h" + +using namespace std; + +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) +namespace Isis { + /** + * Create an AtmosModel object. Because this is a pure virtual + * class you can not create an AtmosModel class directly. Instead, + * see the @b Isis::AtmosModelFactory class. + * + * @param pvl @b Isis::Pvl object containing a valid AtmosModel + * specification + * @param pmodel PhotoModel object containing valud AtmosModel + * data + * + * @see atmosphericModels.doc + * @internal + * @history 2008-11-05 Jeannie Walldren - Replaced arrays with + * vectors + * + */ + AtmosModel::AtmosModel (Pvl &pvl, PhotoModel &pmodel) { + p_atmosAlgorithmName = "Unknown"; + p_atmosPM = &pmodel; + + p_atmosIncTable.resize(91); + p_atmosAhTable.resize(91); + p_atmosHahgtTable.resize(91); + p_atmosHahgt0Table.resize(91); + p_atmosAb = 0.0; + p_atmosCosphi = 0.0; + p_atmosAtmSwitch = 0; + p_atmosEulgam = 0.5772156; + p_atmosHahgsb = 0.0; + p_atmosHga = 0.68; + p_atmosInc = 0.0; + p_atmosMunot = 0.0; + p_atmosNinc = 91; + p_atmosPhi = 0.0; + p_atmosSini = 0.0; + p_atmosTau = 0.28; + p_atmosTauref = 0.0; + p_atmosTauold = -1.0; + p_atmosWha = 0.95; + p_atmosWhaold = 1.0e30; + p_atmosBha = 0.85; + p_pstd = 0.0; + p_sbar = 0.0; + p_trans = 0.0; + p_trans0 = 0.0; + p_standardConditions = false; + + PvlGroup &algorithm = pvl.FindObject("AtmosphericModel").FindGroup("Algorithm",Pvl::Traverse); + + if (algorithm.HasKeyword("Nulneg")) { + SetAtmosNulneg( ((string)algorithm["Nulneg"]).compare("YES") == 0 ); + } + else { + p_atmosNulneg = false; + } + + if (algorithm.HasKeyword("Tau")) { + SetAtmosTau( algorithm["Tau"] ); + } + p_atmosTausave = p_atmosTau; + + if (algorithm.HasKeyword("Tauref")) { + SetAtmosTauref( algorithm["Tauref"] ); + } + + if (algorithm.HasKeyword("Wha")) { + SetAtmosWha( algorithm["Wha"] ); + } + p_atmosWhasave = p_atmosWha; + + if (algorithm.HasKeyword("Wharef")) { + SetAtmosWharef( algorithm["Wharef"] ); + } else { + p_atmosWharef = p_atmosWha; + } + + if (algorithm.HasKeyword("Hga")) { + SetAtmosHga( algorithm["Hga"] ); + } + p_atmosHgasave = p_atmosHga; + + if (algorithm.HasKeyword("Hgaref")) { + SetAtmosHgaref( algorithm["Hgaref"] ); + } else { + p_atmosHgaref = p_atmosHga; + } + + if (algorithm.HasKeyword("Bha")) { + SetAtmosBha( algorithm["Bha"] ); + } + p_atmosBhasave = p_atmosBha; + + if (algorithm.HasKeyword("Bharef")) { + SetAtmosBharef( algorithm["Bharef"] ); + } else { + p_atmosBharef = p_atmosBha; + } + + if (algorithm.HasKeyword("Inc")) { + SetAtmosInc( algorithm["Inc"] ); + } + + if (algorithm.HasKeyword("Phi")) { + SetAtmosPhi( algorithm["Phi"] ); + } + } + + + /** + * Perform Chandra and Van de Hulst's series approximation + * for the g'11 function needed in second order scattering + * theory. + * + * @param tau normal optical depth of atmosphere + * @returns @b double Value of the g'11 function evaluated + * at the given @b tau + * @internal + * @history 1998-12-21 Randy Kirk, USGS - Flagstaff - Original + * code in Isis2 pht_am_functions + * @history 1999-03-12 K Teal Thompson - Port to Unix/ISIS; + * declare vars; c add implicit none. + * @history 2007-02-20 Janet Barrett - Imported from Isis2 to + * Isis3 in NumericalMethods class. + * @history 2008-11-05 Jeannie Walldren - Moved this method from + * NumericalMethods class. + * + */ + double AtmosModel::G11Prime(double tau) { + double sum; + int icnt; + double fac; + double term; + double tol; + double fi; + double elog; + double eulgam; + double e1_2; + double result; + + tol = 1.0e-6; + eulgam = 0.5772156; + + sum = 0.0; + icnt = 1; + fac = -tau; + term = fac; + while (fabs(term) > fabs(sum)*tol) { + sum = sum + term; + icnt = icnt + 1; + fi = (double) icnt; + fac = fac * (-tau) / fi; + term = fac / (fi * fi); + } + elog = log(MAX(1.0e-30,tau)) + eulgam; + e1_2 = sum + PI * PI / 12.0 + 0.5 * + pow(elog,2.0); + result = 2.0 * (AtmosModel::En(1,tau) + + elog * AtmosModel::En(2,tau) + - tau * e1_2); + return(result); + } + + /** + * This routine computes the exponential integral, + * @a Ei(x). This is defined as + * @f[ + * Ei(x) = - \int_{-x}^{\infty} + * \frac{e^{-t}}{t}\mathrm{d}t + * = \int_{-\infty}^{x} + * \frac{e^{t}}{t}\mathrm{d}t + * @f] + * for @a x > 0. + * + * For small @a x, this method uses the power series, + * @f[ + * Ei(x) = \gamma + \ln x + \frac{x}{1*1!} + \frac{x^2}{2*2!} + * + ... + * @f] where @f$ \gamma = 0.5772156649... @f$ is Euler's + * constant, and for large @a x, the asymptotic series is + * used, + * @f[ + * Ei(x) \sim \frac{e^x}{x} (1 + \frac{1!}{x} + + * \frac{2!}{x^2} + ...) + * @f] + * + * @see mathworld.wolfram.com/ExponentialIntegral.html + + * @param x Value at which the exponential integral will be + * computed, @a x > 0.0 + * @returns @b double The exponential integral for the given + * @a x. + * @throws Isis::iException::Programmer "Invalid arguments. + * Definition requires x > 0.0." + * @throws Isis::iException::Math "Power series failed to + * converge" + * @internal + * @history 1999-08-11 K Teal Thompson - Original + * version named pht_r8ei in Isis2. + * @history 2007-02-20 Janet Barrett - Imported to Isis3 in + * NumericalMethods class named r8ei(). + * @history 2008-11-05 Jeannie Walldren - Renamed and modified + * input parameters. Added documentation. + */ + double AtmosModel::Ei (double x) throw (iException &){ + //static double r8ei(double x) in original NumericalMethods class + // This method was derived from an algorithm in the text + // Numerical Recipes in C: The Art of Scientific Computing + // Section 6.3 by Flannery, Press, Teukolsky, and Vetterling + double result; + double fpmin; // close to smallest representable floating-point number + double euler; // Euler's constant, lower-case gamma + double epsilon; // desired relative error (tolerance) + int maxit; // maximum number of iterations allowed + double sum,fact,term,prev; + + fpmin = 1.0e-30; + maxit = 100; + epsilon = 6.0e-8; + euler = 0.57721566; + + if (x <= 0.0) { + throw iException::Message(iException::Programmer, + "AtmosModel::Ei() - Invalid argument. Definition requires x > 0.0. Entered x = " + + iString(x), + _FILEINFO_); + } + if (x < fpmin) { //special case: avoid failure of convergence test because underflow + result = log(x) + euler; + } + else if (x <= -log(epsilon)) { //Use power series + sum = 0.0; + fact = 1.0; + for (int k=1; k<=maxit; k++) { + fact = fact * x / k; + term = fact / k; + sum = sum + term; + if (term < epsilon*sum) { + result = sum + log(x) + euler; + return(result); + } + } + throw iException::Message(iException::Math, + "AtmosModel::Ei() - Power series failed to converge in " + + iString(maxit) + " iterations. Unable to calculate exponential integral.", + _FILEINFO_); + } + else { // Use asymptotic series + sum = 0.0; + term = 1.0; + for (int k=1; k<=maxit; k++) { + prev = term; + term = term * k / x; + if (term < epsilon) { + result = exp(x) * (1.0 + sum) / x; + return(result); + } + else { + if (term < prev) { // still converging: add new term + sum = sum + term; + } + else { // diverging: subtract previous term and exit + sum = sum - prev; + result = exp(x) * (1.0 + sum) / x; + return(result); + } + } + } + result = exp(x) * (1.0 + sum) / x; + } + return(result); + } + + /** + * This routine evaluates the generalized exponential integral, + * @a En(x). This is defined as + * @f[ + * E_n(x) = \int_{1}^{\infty} \frac{e^{-xt}}{t^n}\mathrm{d}t + * \mathrm{ for } x \in \mathbb{R }, n \in \mathbb{Z } + * \mathrm{such that } x \ge 0.0, n \ge 0 + * @f] + * Notice that if @a x = 0, then the equation is not defined + * for @a n = 0 or @a n = 1, as these will result in @f$ + * E_n(x) = \infty @f$. + * + * This method uses the following for cases: + *
      + *
    • For n > 1 and x = 0.0, + * @f[ + * E_n(0) = \frac{1}{n-1} + * @f] + * + *
    • For n = 0 and x > 0.0, + * @f[ + * E_0(x) = \frac{e^{-x}}{x} + * @f] + * + *
    • For @f$ x >\sim 1.0 @f$, Lentz's continued fraction + * algorithm is used, + * @f[ + * E_n(x) = e^{-x}(\frac{1}{x + n - \frac{1*n}{x + n + 2 - + * \frac{2(n+1)}{x + n + 4 - ...}}}) + * @f] + * + *
    • For @f$ 0.0 < x <\sim 1.0 @f$, series representation is + * used, + * @f[ + * E_n(x) = \frac{(-x)^{n-1}}{(n-1)!}[- \ln x + \psi (n)] - + * \sum_{m=0, m \neq n-1}^{\infty}\frac{(-x)^m}{(m-n+1)m!} + * @f] where @f$ \psi (1) = \gamma @f$ and @f$ \psi (n) = - + * \gamma + \sum_{m=1}^{n-1} \frac{1}{m}@f$ and @f$ \gamma = + * 0.5772156649... @f$ is Euler's constant. + *
    + * + * The parameter @a n is of type @b unsigned @b int since @a n + * cannot be negative. + * + * The routine allows fast evaluation of + * @a En(x) to any accuracy, @f$\epsilon@f$, + * within the reach of your machine's word length for + * floating-point numbers. The only modification required for + * increased accuracy is to supply Euler's constant with enough + * significant digits. + * + * @see mathworld.wolfram.com/En-Function.html + * + * @param n Integer value at which the exponential integral + * will be evaluated (n >= 0) + * @param x The exponential integral En(x) will be evaluated + * @returns @b double Value of the exponential integral for + * the give n and x. + * @throws Isis::iException::Programmer "Invalid arguments. + * Definition requires (x > 0.0 and n >=0 ) or (x >= + * 0.0 and n > 1)." + * @throws Isis::iException::Math "Continued fraction failed to + * converge" + * @throws Isis::iException::Math "Series representation failed to converge" + * @internal + * @history 1999-08-10 K Teal Thompson - Original version in + * named pht_r8expint Isis2. + * @history 2007-02-20 Janet Barrett - Imported to Isis3 in + * NumericalMethods class named r8expint(). + * @history 2008-11-05 Jeannie Walldren - Renamed and modified + * input parameters. Added documentation. + */ + double AtmosModel::En (unsigned int n, double x) throw (iException &){ + //static double r8expint(int n, double x) in original NumericalMethods class + // This method was derived from an algorithm in the text + // Numerical Recipes in C: The Art of Scientific Computing + // Section 6.3 by Flannery, Press, Teukolsky, and Vetterling + int nm1; + double result; + double a,b,c,d,h; + double delta; + double fact; + double psi; + double fpmin; // close to smallest representable floating-point number + double maxit; // maximum number of iterations allowed + double epsilon; // desired relative error (tolerance) + double euler; // Euler's constant, gamma + + fpmin = 1.0e-30; + maxit = 100; + epsilon = 1.0e-7; + euler = 0.5772156649; + + nm1 = n - 1; + if (n < 0 || x < 0.0 || (x == 0.0 && (n == 0 || n == 1))) { + iString msg = "AtmosModel::En() - Invalid arguments. "; + msg+= "Definition requires (x > 0.0 and n >=0 ) or (x >= 0.0 and n > 1). "; + msg+= "Entered x = " + iString(x) + " and n = " + iString((int) n); + throw iException::Message(iException::Programmer,msg, + _FILEINFO_); + } + else if (n == 0) { // special case, this implies x > 0 by logic above + result = exp(-x) / x; + } + else if (x == 0.0) { // special case, this implies n > 1 + result = 1.0 / nm1; + } + else if (x > 1.0) { // Lentz's algorithm, this implies n > 0 + b = x + n; + c = 1.0 / fpmin; + d = 1.0 / b; + h = d; + for (int i=1; i<=maxit; i++) { + a = -i * (nm1 + i); + b = b + 2.0; + d = 1.0 / (a * d + b); + c = b + a / c; + delta = c * d; + h = h * delta; + if (fabs(delta-1.0) < epsilon) { + result = h * exp(-x); + return(result); + } + } + throw iException::Message(iException::Math, + "AtmosModel::En() - Continued fraction failed to converge in " + + iString(maxit) + " iterations. Unable to calculate exponential integral.", + _FILEINFO_); + } + else { // evaluate series + if (nm1 != 0) { + result = 1.0 / nm1; + } + else { + result = -log(x) - euler; + } + fact = 1.0; + for (int i=1; i<=maxit; i++) { + fact = -fact * x / i; + if (i != nm1) { + delta = -fact / (i - nm1); + } + else { + psi = -euler; + for (int ii=1; ii<=nm1; ii++) { + psi = psi + 1.0 / ii; + } + delta = fact * (-log(x) + psi); + } + result = result + delta; + if (fabs(delta) < fabs(result)*epsilon) { + return(result); + } + } + throw iException::Message(iException::Math, + "AtmosModel::En() - Series representation failed to converge in " + + iString(maxit) + " iterations. Unable to calculate exponential integral.", + _FILEINFO_); + } + return(result); + } + + /** + * Calculate the atmospheric scattering effect using photometric angle + * information + * + * @param pha phase angle + * @param inc incidence angle + * @param ema emission angle + * @param pstd pure atmospheric-scattering term + * @param trans transmission of surface reflected light through + * the atmosphere overall + * @param trans0 transmission of surface reflected light + * through the atmosphere with no scatterings in the + * atmosphere + * @param sbar illumination of the ground by the sky + * @throw Isis::iException::User "Invalid photometric angles" + */ + void AtmosModel::CalcAtmEffect(double pha, double inc, double ema, + double *pstd, double *trans, double *trans0, double *sbar) { + + // Check validity of photometric angles + //if (pha > 180.0 || inc > 90.0 || ema > 90.0 || pha < 0.0 || + // inc < 0.0 || ema < 0.0) { + // string msg = "Invalid photometric angles"; + // throw iException::Message(iException::Programmer,msg,_FILEINFO_); + //} + + // Apply atmospheric function + AtmosModelAlgorithm(pha,inc,ema); + *pstd = p_pstd; + *trans = p_trans; + *trans0 = p_trans0; + *sbar = p_sbar; + } + + /** + * Used to calculate atmosphere at standard conditions + */ + void AtmosModel::SetStandardConditions(bool standard) { + p_standardConditions = standard; + if (p_standardConditions) { + p_atmosBhasave = p_atmosBha; + p_atmosBha = p_atmosBharef; + p_atmosHgasave = p_atmosHga; + p_atmosHga = p_atmosHgaref; + p_atmosTausave = p_atmosTau; + p_atmosTau = p_atmosTauref; + p_atmosWhasave = p_atmosWha; + p_atmosWha = p_atmosWharef; + } else { + p_atmosBha = p_atmosBhasave; + p_atmosHga = p_atmosHgasave; + p_atmosTau = p_atmosTausave; + p_atmosWha = p_atmosWhasave; + } + } + + /** + * This method computes the values of the atmospheric Ah + * table and sets the properties of the atmospheric Ah spline. + * It obtains the hemispheric albedo by integrating the + * photometric function times mu over mu = 0 to 1 and then over + * phi = 0 to 2*pi to calculate the hemispheric reflectance Ah + * needed for the photometric model with atmosphere. The + * Trapezoid rule is applied to the table of Ah to obtain + * bihemispheric albedo Ab. The parameter @a p_atmosAtmSwitch is + * set to 0 to integrate Ah. + * + * @internal + * @history 1998-12-21 Randy Kirk - USGS, Flagstaff - Original + * specs + * @history 1999-01-15 K Teal Thompson - Original code + * @history 2000-12-29 Randy Kirk - Modified /hide_inc/ so phi + * gets passed, etc. moved factors to outside + * integration + * @history 2006-05-30 Randy Kirk - Added code to report the + * directional hemispheric albedo that relates to + * thermal balance for simulating Themis images + * @history 2007-02-20 Janet Barrett - Imported to Isis3 from + * Isis2 pht_get_ah_table + * @history 2008-11-05 Jeannie Walldren - Modified references to + * NumericalMethods and replaced r8qromb() with + * NumericalAtmosApprox::RombergsMethod(). Changed + * name from PhtGetAhTable(). + */ + void AtmosModel::GenerateAhTable() { + int inccnt; //for loop incidence angle count, 1:ninc + double fun_temp;//temporary variable for integral + double factor; //factor for integration: 1 except at ends of interval where it's 1/2 + double yp1,yp2; //first derivatives of first and last x values of @a p_atmosIncTable + + NumericalAtmosApprox::IntegFunc sub; + sub = NumericalAtmosApprox::OuterFunction; + + p_atmosAb = 0.0; + + //Create NumericalAtmosApprox object here for RombergsMethod used in for loop + NumericalAtmosApprox qromb; + + for (inccnt=0; inccntAlgorithmName(); + phtName.UpCase(); + if (p_atmosInc == 90.0) { + p_atmosAhTable[inccnt] = 0.0; + } + else if (phtName == "LAMBERT") { + p_atmosAhTable[inccnt] = 1.0; + } + else if (phtName == "LOMMELSEELIGER") { + p_atmosAhTable[inccnt] = 2.0 * log((1.0/p_atmosMunot)/p_atmosMunot); + } + else if (phtName == "MINNAERT") { + p_atmosAhTable[inccnt] = (pow(p_atmosMunot,((Minnaert*)p_atmosPM)->PhotoK()))/((Minnaert*)p_atmosPM)->PhotoK(); + } + else if (phtName == "LUNARLAMBERT") { + p_atmosAhTable[inccnt] = 2.0 * ((LunarLambert*)p_atmosPM)->PhotoL() * + log((1.0+p_atmosMunot)/p_atmosMunot) + 1.0 - + ((LunarLambert*)p_atmosPM)->PhotoL(); + } + else { + // numerically integrate the other photometric models + // outer integral is over phi from 0 to pi rad = 180 deg + p_atmosAtmSwitch = 0; + // integrate AtmosModel function from 0 to 180 + fun_temp = qromb.RombergsMethod(this,sub,0,180); + // the correct normalization with phi in degrees is: + p_atmosAhTable[inccnt] = fun_temp / (90.0*p_atmosMunot); + } + // Let's get our estimate of Ab by integrating (summing) + // A (i)sinicosi over our A table + if ((inccnt == 0) || (inccnt == p_atmosNinc-1)) { + factor = 0.5; + } + else { + factor = 1.0; + } + + p_atmosAb = p_atmosAb + p_atmosAhTable[inccnt] * p_atmosMunot * p_atmosSini * factor; + } + + factor = 2.0 * PI/180.0; + p_atmosAb = p_atmosAb * factor; + + // set up clamped cubic spline + yp1 = 1.0e30; + yp2 = 1.0e30; + p_atmosAhSpline.Reset(); + p_atmosAhSpline.SetInterpType(NumericalApproximation::CubicClamped); + p_atmosAhSpline.AddData(p_atmosIncTable,p_atmosAhTable); + p_atmosAhSpline.SetCubicClampedEndptDeriv(yp1,yp2); + } + + /** + * This method computes the values of the atmospheric Hahg and + * Hahg0 tables and sets the properties of the atmospheric Hahg + * and Hahg0 splines. It integrates functions involving the + * single particle phase function (assumed to be Hapke + * Henyey-Greenstein) over mu = 0 to 1 and then over phi = 0 to + * 2*pi to calculate the corrections needed for the anisotropic + * photometric model with atmosphere. The Trapezoid rule is + * applied to the table of Ah to obtain bihemispheric albedo Ab. + * The parameter @a p_atmosAtmSwitch is set to 1, 2, 3 to + * evaluate the 3 required integrals. + * + * @internal + * @history 1998-12-21 Randy Kirk - USGS, Flagstaff - Original + * specs + * @history 1999-01-15 K Teal Thompson - Original code + * @history 2006-07-07 Randy Kirk - Modify get_ah_table to get + * other integrals + * @history 2000-12-29 Randy Kirk - Modified /hide_inc/ so phi + * gets passed, etc. moved factors to outside + * integration + * @history 2007-02-20 Janet Barrett - Imported to Isis3 from + * Isis2 pht_get_ah_table + * @history 2008-11-05 Jeannie Walldren - Modified references to + * NumericalMethods and replaced r8qromb() with + * NumericalAtmosApprox::RombergsMethod(). Changed + * name from GetHahgTables(). + */ + void AtmosModel::GenerateHahgTables() { + int inccnt; // for loop incidence angle count,1:ninc + double fun_temp; // temporary variable for integral + double hahgsb_temp; // save increment to hahgsb + double factor; // factor for integration: 1 except at ends of interval where it's 1/2 + double yp1,yp2; // derivatives of endpoints of data set + + NumericalAtmosApprox::IntegFunc sub; + sub = NumericalAtmosApprox::OuterFunction; + + p_atmosHahgsb = 0.0; + NumericalAtmosApprox qromb; + + for (inccnt = 0; inccnt < p_atmosNinc; inccnt++) { + p_atmosInc = (double) inccnt; + p_atmosIncTable[inccnt] = p_atmosInc; + p_atmosMunot = cos((PI/180.0)*p_atmosInc); + p_atmosSini = sin((PI/180.0)*p_atmosInc); + + p_atmosAtmSwitch = 1; + + qromb.Reset(); + fun_temp = qromb.RombergsMethod(this,sub,0,180); + + p_atmosHahgtTable[inccnt] = fun_temp * AtmosWha() / 360.0; + p_atmosAtmSwitch = 2; + + fun_temp = qromb.RombergsMethod(this,sub,0,180); + + hahgsb_temp = fun_temp * AtmosWha() / 360.0; + + if ((inccnt == 0) || (inccnt == p_atmosNinc-1)) { + factor = 0.5; + } + else { + factor = 1.0; + } + + p_atmosHahgsb = p_atmosHahgsb + p_atmosSini * factor * hahgsb_temp; + if (p_atmosInc == 0.0) { + p_atmosHahgt0Table[inccnt] = 0.0; + } + else { + p_atmosAtmSwitch = 3; + fun_temp = qromb.RombergsMethod(this,sub,0,180); + p_atmosHahgt0Table[inccnt] = fun_temp * AtmosWha() * p_atmosMunot / (360.0 * p_atmosSini); + } + } + + factor = 2.0 * PI/180.0; + p_atmosHahgsb = p_atmosHahgsb * factor; + + // set up clamped cubic splines + yp1 = 1.0e30; + yp2 = 1.0e30; + p_atmosHahgtSpline.Reset(); + p_atmosHahgtSpline.SetInterpType(NumericalApproximation::CubicClamped); + p_atmosHahgtSpline.AddData(p_atmosIncTable,p_atmosHahgtTable); + p_atmosHahgtSpline.SetCubicClampedEndptDeriv(yp1,yp2); + + p_atmosHahgt0Spline.Reset(); + p_atmosHahgt0Spline.SetInterpType(NumericalApproximation::CubicClamped); + p_atmosHahgt0Spline.AddData(p_atmosIncTable,p_atmosHahgt0Table); + p_atmosHahgt0Spline.SetCubicClampedEndptDeriv(yp1,yp2); + } + + /** + * Set the switch that controls the function that will be + * integrated. This method is only used for testing the + * methods in this class. This parameter is limited to the + * values 0, 1, 2, and 3. + * + * @param atmswitch Internal atmospheric function parameter, + * there is no default + * @throw Isis::iException::User "Invalid value of atmospheric + * atmswitch" + */ + void AtmosModel::SetAtmosAtmSwitch (const int atmswitch) { + if (atmswitch < 0 || atmswitch > 3) { + string msg = "Invalid value of atmospheric atmswitch [" + iString(atmswitch) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosAtmSwitch = atmswitch; + } + + /** + * Set the Anisotropic Atmospheric function parameter. This is + * the coefficient of the single particle Legendre phase + * function. This parameter is limited to values that are >=-1 + * and <=1. + * + * @param bha Anisotropic atmospheric function parameter, + * default is 0.85 + * @throw Isis::iException::User "Invalid value of atmospheric + * bha" + */ + void AtmosModel::SetAtmosBha (const double bha) { + if (bha < -1.0 || bha > 1.0) { + string msg = "Invalid value of Anisotropic atmospheric bha [" + + iString(bha) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosBha = bha; + } + + /** + * Set the Atmospheric function parameter. This specifies the + * reference value of Bha to which the image will be normalized. + * If no value is given, then this parameter defaults to the + * value provided for Bha. This parameter is limited to values + * that are >=-1 and <=1. + * + * @param bharef Atmospheric function parameter, no default + * @throw Isis::iException::User "Invalid value of atmospheric + * bharef" + */ + void AtmosModel::SetAtmosBharef (const double bharef) { + if (bharef < -1.0 || bharef > 1.0) { + string msg = "Invalid value of Atmospheric bharef [" + iString(bharef) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosBharef = bharef; + } + + /** + * Set the Hapke atmospheric function parameter. This is the + * coefficient of the single particle Henyey-Greenstein phase + * function. This parameter is limited to values that are >-1 + * and <1. + * + * @param hga Hapke atmospheric function parameter, + * default is 0.68 + * @throw Isis::iException::User "Invalid value of atmospheric + * hga" + */ + void AtmosModel::SetAtmosHga (const double hga) { + if (hga <= -1.0 || hga >= 1.0) { + string msg = "Invalid value of Hapke atmospheric hga [" + iString(hga) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosHga = hga; + } + + /** + * Set the Atmospheric function parameter. This specifies the + * reference value of Hga to which the image will be normalized. + * If no value is given, then this parameter defaults to the + * value provided for Hga. This parameter is limited to values + * that are >-1 and <1. + * + * @param hgaref Hapke atmospheric function parameter, no default + * @throw Isis::iException::User "Invalid value of atmospheric + * hgaref" + */ + void AtmosModel::SetAtmosHgaref (const double hgaref) { + if (hgaref <= -1.0 || hgaref >= 1.0) { + string msg = "Invalid value of Atmospheric hgaref [" + iString(hgaref) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosHgaref = hgaref; + } + + /** + * Set the incidence angle. This method is only used for + * testing the methods in this class. This parameter is + * limited to values >=0 and <=90. + * + * @param inc Internal atmospheric function parameter, + * there is no default + * @throw Isis::iException::User "Invalid value of atmospheric + * inc" + */ + void AtmosModel::SetAtmosInc (const double inc) { + if (inc < 0.0 || inc > 90.0) { + string msg = "Invalid value of atmospheric inc [" + iString(inc) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosInc = inc; + p_atmosMunot = cos(inc*PI/180.0); + p_atmosSini = sin(inc*PI/180.0); + } + + /** + * Set the Atmospheric function parameter. This determines + * if negative values after removal of atmospheric effects + * will be set to NULL. This parameter is limited to values + * of YES or NO. + * + * @param nulneg Atmospheric function parameter, default is NO + * @throw Isis::iException::User "Invalid value of atmospheric + * nulneg" + * + */ + void AtmosModel::SetAtmosNulneg (const string nulneg) { + iString temp(nulneg); + temp = temp.UpCase(); + + if (temp != "NO" && temp != "YES") { + string msg = "Invalid value of Atmospheric nulneg [" + temp + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + SetAtmosNulneg( temp.compare("YES") == 0 ); + } + + /** + * Set the azimuth angle. This method is only used for + * testing the methods in this class. This parameter is + * limited to values >=0 and <=360. + * + * @param phi Internal atmospheric function parameter, + * there is no default + * @throw Isis::iException::User "Invalid value of atmospheric + * phi" + * + */ + void AtmosModel::SetAtmosPhi (const double phi) { + if (phi < 0.0 || phi > 360.0) { + string msg = "Invalid value of atmospheric phi [" + iString(phi) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosPhi = phi; + p_atmosCosphi = cos(phi*PI/180.0); + } + + /** + * Set the Atmospheric function parameter. This specifies the + * normal optical depth of the atmosphere. This parameter is + * limited to values that are >=0. + * + * @param tau Atmospheric function parameter, default is 0.28 + * @throw Isis::iException::User "Invalid value of atmospheric + * tau" + */ + void AtmosModel::SetAtmosTau (const double tau) { + if (tau < 0.0) { + string msg = "Invalid value of Atmospheric tau [" + iString(tau) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosTau = tau; + } + + /** + * Set the Atmospheric function parameter. This specifies the + * reference optical depth of the atmosphere to which the image + * will be normalized. This parameter is limited to values that + * are >=0. + * + * @param tauref Atmospheric function parameter, default is 0.0 + * @throw Isis::iException::User "Invalid value of atmospheric + * tauref" + */ + void AtmosModel::SetAtmosTauref (const double tauref) { + if (tauref < 0.0) { + string msg = "Invalid value of Atmospheric tauref [" + iString(tauref) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosTauref = tauref; + } + + /** + * Set the Atmospheric function parameter. This is the single- + * scattering albedo of atmospheric particles. This parameter + * is limited to values that are >0 and <=1. + * + * @param wha Atmospheric function parameter, default is 0.95 + * @throw Isis::iException::User "Invalid value of atmospheric + * wha" + * + */ + void AtmosModel::SetAtmosWha (const double wha) { + if (wha <= 0.0 || wha > 1.0) { + string msg = "Invalid value of Atmospheric wha [" + iString(wha) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosWha = wha; + } + + /** + * Set the Atmospheric function parameter. This is the reference + * single-scattering albedo of atmospheric particles to which + * the image will be normalized. This parameter is limited to + * values that are >0 and <=1. + * + * @param wharef Atmospheric function parameter, no default + * @throw Isis::iException::User "Invalid value of atmospheric + * wharef" + */ + void AtmosModel::SetAtmosWharef (const double wharef) { + if (wharef <= 0.0 || wharef > 1.0) { + string msg = "Invalid value of Atmospheric wharef [" + iString(wharef) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosWharef = wharef; + } + + /** + * Checks whether tau or wha have changed. + * @return @b bool True if either have changed. + */ + bool AtmosModel::TauOrWhaChanged() const { + return (AtmosTau() != p_atmosTauold) || (AtmosWha() != p_atmosWhaold); + } +} diff --git a/isis/src/base/objs/AtmosModel/AtmosModel.h b/isis/src/base/objs/AtmosModel/AtmosModel.h new file mode 100644 index 0000000000000000000000000000000000000000..33bde5c45ae4c4ec7bbe23ab2ec16cc168bb6dd1 --- /dev/null +++ b/isis/src/base/objs/AtmosModel/AtmosModel.h @@ -0,0 +1,240 @@ +#ifndef AtmosModel_h +#define AtmosModel_h +/** + * @file + * $Revision: 1.10 $ + * $Date: 2008/11/07 23:48:13 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "PhotoModel.h" +#include "NumericalApproximation.h" +#include "NumericalAtmosApprox.h" + +using namespace std; +namespace Isis { + class Pvl; + +/** + * @brief Isotropic atmos scattering model + * + * @ingroup RadiometricAndPhotometricCorrection + * @author 1998-12-21 Randy Kirk + * + * @internal + * @history 2007-02-20 Janet Barrett - Imported from Isis2. + * @history 2007-07-31 Steven Lambright - Fixed unit test + * @history 2007-08-15 Steven Lambright - Refactored + * @history 2008-03-07 Janet Barrett - Added code to set standard + * conditions. Also added bharef, hgaref, tauref, + * and wharef variables and supporting methods. + * @history 2008-06-18 Christopher Austin - Fixed much documentation + * @history 2008-07-09 Steven Lambright - Fixed unit test + * @history 2008-11-05 Jeannie Walldren - Moved numerical + * methods and functions to NumericalMethods and + * NumericalAtmosApprox classes. Moved G11Prime(), + * Ei(), and En() from NumericalMethods into this + * class. Added splines to protected variables and + * removed second derivative vector protected + * variables (p_atmosAhTable2, p_atmosHahgtTable2, + * p_atmosHahgt0Table2) that are no longer needed. + * Replaced arrays with vectors in protected + * variables. Added documentation from Isis2 files. + * Removed "Isis::" and "std::" in AtmosModel.cpp + * since that file uses std and Isis namespaces. + * @history 2008-11-07 Jeannie Walldren - Fixed documentation + */ + class AtmosModel { + public: + AtmosModel (Pvl &pvl, PhotoModel &pmodel); + //! Empty destructor + virtual ~AtmosModel() {}; + + // These methods were moved here from the NumericalMethods class + static double G11Prime(double tau); + static double Ei(double x) throw (iException &); + static double En(unsigned int n, double x) throw (iException &); + // Calculate atmospheric scattering effect + void CalcAtmEffect(double pha, double inc, double ema, double *pstd, + double *trans, double *trans0, double *sbar); + // Used to calculate atmosphere at standard conditions + virtual void SetStandardConditions(bool standard); + // Obtain hemispheric and bihemispheric albedo by integrating the photometric function + void GenerateAhTable(); + // Perform integration for Hapke Henyey-Greenstein atmosphere correction + void GenerateHahgTables(); + // Set parameters needed for atmospheric correction + void SetAtmosAtmSwitch (const int atmswitch); + void SetAtmosBha (const double bha ); + void SetAtmosBharef (const double bharef); + void SetAtmosHga (const double hga ); + void SetAtmosHgaref (const double hgaref); + void SetAtmosInc (const double inc ); + void SetAtmosNulneg (const string nulneg); + void SetAtmosPhi (const double phi ); + void SetAtmosTau (const double tau ); + void SetAtmosTauref (const double tauref); + void SetAtmosWha (const double wha ); + void SetAtmosWharef (const double wharef); + + //! Return atmospheric algorithm name + string AlgorithmName () const { return p_atmosAlgorithmName; }; + + //! Return atmospheric Bha value + double AtmosBha () const { return p_atmosBha; }; + //! Return atmospheric Tau value + double AtmosTau () const { return p_atmosTau; }; + //! Return atmospheric Wha value + double AtmosWha () const { return p_atmosWha; }; + //! Return atmospheric Hga value + double AtmosHga () const { return p_atmosHga; }; + //! Return atmospheric Bharef value + double AtmosBharef () const { return p_atmosBharef; }; + //! Return atmospheric Hgaref value + double AtmosHgaref () const { return p_atmosHgaref; }; + //! Return atmospheric Tauref value + double AtmosTauref () const { return p_atmosTauref; }; + //! Return atmospheric Wharef value + double AtmosWharef () const { return p_atmosWharef; }; + //! Return atmospheric Nulneg value + bool AtmosNulneg () const { return p_atmosNulneg; }; + //! Return atmospheric Ab value + double AtmosAb () const { return p_atmosAb; }; + //! Return atmospheric Hahgsb value + double AtmosHahgsb () const { return p_atmosHahgsb; }; + //! Return atmospheric Ninc value + int AtmosNinc () const { return p_atmosNinc; }; + + //! Return atmospheric IncTable value + vector AtmosIncTable () { return p_atmosIncTable; }; + //! Return atmospheric AhTable value + vector AtmosAhTable () { return p_atmosAhTable; }; + //! Return atmospheric HahgtTable value + vector AtmosHahgtTable () { return p_atmosHahgtTable; }; + //! Return atmospheric Hahgt0Table value + vector AtmosHahgt0Table () { return p_atmosHahgt0Table; }; + + /** + * If GenerateAhTable() has been called this returns a clamped + * cubic spline of the data set (@a p_atmosIncTable, + * @a p_atmosAhTable) with first derivatives of the endpoints + * equal to 1.0e30. Otherwise, it is a natural cubic spline with + * an empty data set. + * + * @returns @b NumericalApproximation Cubic spline + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + */ + NumericalApproximation AtmosAhSpline() {return p_atmosAhSpline;}; + /** + * If GenerateHahgTables() has been called this returns a + * clamped cubic spline of the data set (@a p_atmosIncTable, + * @a p_atmosHahgtTable) with first derivatives of the endpoints + * equal to 1.0e30. Otherwise, it is a natural cubic spline with + * an empty data set. + * + * @returns @b NumericalApproximation Cubic spline + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + */ + NumericalApproximation AtmosHahgtSpline() {return p_atmosHahgtSpline;}; + /** + * If GenerateHahgTables() has been called this returns a + * clamped cubic spline of the data set (@a p_atmosIncTable, + * @a p_atmosHahgt0Table) with first derivatives of the + * endpoints equal to 1.0e30. Otherwise, it is a natural cubic + * spline with an empty data set. + * + * @returns @b NumericalApproximation Cubic spline + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + */ + NumericalApproximation AtmosHahgt0Spline() {return p_atmosHahgt0Spline;}; + + protected: + virtual void AtmosModelAlgorithm (double phase, double incidence, double emission) = 0; + + void SetAlgorithmName(string name) { p_atmosAlgorithmName = name; } + void SetAtmosNulneg(bool nulneg) { p_atmosNulneg = nulneg; } + void SetOldTau(double tau) { p_atmosTauold = tau; } + void SetOldWha(double wha) { p_atmosWhaold = wha; } + + PhotoModel *GetPhotoModel() const { return p_atmosPM; } + bool StandardConditions() const { return p_standardConditions; } + bool TauOrWhaChanged() const; + double Eulgam() const { return p_atmosEulgam; } + + int p_atmosAtmSwitch; + int p_atmosNinc; + + double p_atmosBha; + double p_atmosBharef; + double p_atmosBhasave; + double p_atmosHgaref; + double p_atmosHgasave; + double p_atmosTauref; + double p_atmosTausave; + double p_atmosWharef; + double p_atmosWhasave; + + double p_pstd; //!Pure atmospheric-scattering term. + double p_trans; //!Transmission of surface reflected light through the atmosphere overall. + double p_trans0; //!Transmission of surface reflected light through the atmosphere with no scatterings in the atmosphere. + double p_sbar; //!Illumination of the ground by the sky. + double p_atmosHga; + double p_atmosTau; + double p_atmosWha; + double p_atmosAb; + vector p_atmosIncTable; + vector p_atmosAhTable; + double p_atmosHahgsb; + vector p_atmosHahgtTable; + vector p_atmosHahgt0Table; + double p_atmosInc; + double p_atmosPhi; + double p_atmosMunot; + double p_atmosSini; + double p_atmosCosphi; + double p_atmosEulgam; + + //! Spline object for the atmospheric Ah Table. Properties are set in GenerateAhTable(). + NumericalApproximation p_atmosAhSpline; + //! Spline object for the atmospheric Hahg Table. Properties are set in GenerateHahgTables(). + NumericalApproximation p_atmosHahgtSpline; + //! Spline object for the atmospheric Hahg0 Table. Properties are set in GenerateHahgTables(). + NumericalApproximation p_atmosHahgt0Spline; + + private: + bool p_standardConditions; + + string p_atmosAlgorithmName; + + PhotoModel *p_atmosPM; + + bool p_atmosNulneg; + + double p_atmosTauold; + double p_atmosWhaold; + friend class NumericalAtmosApprox; + }; +}; + +#endif diff --git a/isis/src/base/objs/AtmosModel/AtmosModel.truth b/isis/src/base/objs/AtmosModel/AtmosModel.truth new file mode 100644 index 0000000000000000000000000000000000000000..fc634692fa61956c47aac47354e2225a32498b51 --- /dev/null +++ b/isis/src/base/objs/AtmosModel/AtmosModel.truth @@ -0,0 +1,581 @@ +UNIT TEST for Isis::AtmosModel + +Testing missing AtmosphericModel object ... +**PVL ERROR** Unable to find object [AtmosphericModel] + +Testing missing Algorithm group ... +**PVL ERROR** Unable to find group [Algorithm] + +Testing missing Name keyword ... +**PVL ERROR** Keyword [Name] does not exist in [Group = Algorithm] + +Testing supported atmospheric model ... + +Testing atmospheric model get methods ... +AlgorithmName = Unknown +AtmosTau = 0.28 +AtmosWha = 0.98 +AtmosHga = 0.68 +AtmosNulneg = 0 +AtmosNinc = 91 + +Testing atmospheric model get methods in standard conditions... +AlgorithmName = Unknown +AtmosTau = 0 +AtmosWha = 0.95 +AtmosHga = 0.68 +AtmosNulneg = 0 +AtmosNinc = 91 + +Testing boundary conditions of atmospheric model set methods ... +**USER ERROR** Invalid value of Atmospheric tau [-1.0] +**USER ERROR** Invalid value of Atmospheric wha [0.0] +**USER ERROR** Invalid value of Atmospheric wha [2.0] +**USER ERROR** Invalid value of Hapke atmospheric hga [-1.0] +**USER ERROR** Invalid value of Hapke atmospheric hga [1.0] + +Testing atmospheric model InrFunc2Bint method ... +Results from InrFunc2Bint = -5.26033e-07 + + +Results from InrFunc2Bint = -0.177426 + + +Testing atmospheric model r8trapzd method ... +Results from r8trapzd = 35.1618 for i = 1 +Results from r8trapzd = 17.5809 for i = 2 +Results from r8trapzd = 17.5809 for i = 3 +Results from r8trapzd = 17.5809 for i = 4 +Results from r8trapzd = 17.5809 for i = 5 +Results from r8trapzd = 17.5809 for i = 6 +Results from r8trapzd = 17.5809 for i = 7 +Results from r8trapzd = 17.5809 for i = 8 +Results from r8trapzd = 17.5809 for i = 9 + +Testing atmospheric model OutrFunc2Bint method ... +Results from OutrFunc2Bint = 0.195344 + + +Testing atmospheric model r8qromb method ... +Results from r8qromb = 35.1618 + + +Testing atmospheric model GenerateAhTable method ... +Results from GenerateAhTable = +Ab = 0.999898 +i IncTable(i) = 0 0 +i IncTable(i) = 1 1 +i IncTable(i) = 2 2 +i IncTable(i) = 3 3 +i IncTable(i) = 4 4 +i IncTable(i) = 5 5 +i IncTable(i) = 6 6 +i IncTable(i) = 7 7 +i IncTable(i) = 8 8 +i IncTable(i) = 9 9 +i IncTable(i) = 10 10 +i IncTable(i) = 11 11 +i IncTable(i) = 12 12 +i IncTable(i) = 13 13 +i IncTable(i) = 14 14 +i IncTable(i) = 15 15 +i IncTable(i) = 16 16 +i IncTable(i) = 17 17 +i IncTable(i) = 18 18 +i IncTable(i) = 19 19 +i IncTable(i) = 20 20 +i IncTable(i) = 21 21 +i IncTable(i) = 22 22 +i IncTable(i) = 23 23 +i IncTable(i) = 24 24 +i IncTable(i) = 25 25 +i IncTable(i) = 26 26 +i IncTable(i) = 27 27 +i IncTable(i) = 28 28 +i IncTable(i) = 29 29 +i IncTable(i) = 30 30 +i IncTable(i) = 31 31 +i IncTable(i) = 32 32 +i IncTable(i) = 33 33 +i IncTable(i) = 34 34 +i IncTable(i) = 35 35 +i IncTable(i) = 36 36 +i IncTable(i) = 37 37 +i IncTable(i) = 38 38 +i IncTable(i) = 39 39 +i IncTable(i) = 40 40 +i IncTable(i) = 41 41 +i IncTable(i) = 42 42 +i IncTable(i) = 43 43 +i IncTable(i) = 44 44 +i IncTable(i) = 45 45 +i IncTable(i) = 46 46 +i IncTable(i) = 47 47 +i IncTable(i) = 48 48 +i IncTable(i) = 49 49 +i IncTable(i) = 50 50 +i IncTable(i) = 51 51 +i IncTable(i) = 52 52 +i IncTable(i) = 53 53 +i IncTable(i) = 54 54 +i IncTable(i) = 55 55 +i IncTable(i) = 56 56 +i IncTable(i) = 57 57 +i IncTable(i) = 58 58 +i IncTable(i) = 59 59 +i IncTable(i) = 60 60 +i IncTable(i) = 61 61 +i IncTable(i) = 62 62 +i IncTable(i) = 63 63 +i IncTable(i) = 64 64 +i IncTable(i) = 65 65 +i IncTable(i) = 66 66 +i IncTable(i) = 67 67 +i IncTable(i) = 68 68 +i IncTable(i) = 69 69 +i IncTable(i) = 70 70 +i IncTable(i) = 71 71 +i IncTable(i) = 72 72 +i IncTable(i) = 73 73 +i IncTable(i) = 74 74 +i IncTable(i) = 75 75 +i IncTable(i) = 76 76 +i IncTable(i) = 77 77 +i IncTable(i) = 78 78 +i IncTable(i) = 79 79 +i IncTable(i) = 80 80 +i IncTable(i) = 81 81 +i IncTable(i) = 82 82 +i IncTable(i) = 83 83 +i IncTable(i) = 84 84 +i IncTable(i) = 85 85 +i IncTable(i) = 86 86 +i IncTable(i) = 87 87 +i IncTable(i) = 88 88 +i IncTable(i) = 89 89 +i IncTable(i) = 90 90 +i AhTable(i) = 0 1 +i AhTable(i) = 1 1 +i AhTable(i) = 2 1 +i AhTable(i) = 3 1 +i AhTable(i) = 4 1 +i AhTable(i) = 5 1 +i AhTable(i) = 6 1 +i AhTable(i) = 7 1 +i AhTable(i) = 8 1 +i AhTable(i) = 9 1 +i AhTable(i) = 10 1 +i AhTable(i) = 11 1 +i AhTable(i) = 12 1 +i AhTable(i) = 13 1 +i AhTable(i) = 14 1 +i AhTable(i) = 15 1 +i AhTable(i) = 16 1 +i AhTable(i) = 17 1 +i AhTable(i) = 18 1 +i AhTable(i) = 19 1 +i AhTable(i) = 20 1 +i AhTable(i) = 21 1 +i AhTable(i) = 22 1 +i AhTable(i) = 23 1 +i AhTable(i) = 24 1 +i AhTable(i) = 25 1 +i AhTable(i) = 26 1 +i AhTable(i) = 27 1 +i AhTable(i) = 28 1 +i AhTable(i) = 29 1 +i AhTable(i) = 30 1 +i AhTable(i) = 31 1 +i AhTable(i) = 32 1 +i AhTable(i) = 33 1 +i AhTable(i) = 34 1 +i AhTable(i) = 35 1 +i AhTable(i) = 36 1 +i AhTable(i) = 37 1 +i AhTable(i) = 38 1 +i AhTable(i) = 39 1 +i AhTable(i) = 40 1 +i AhTable(i) = 41 1 +i AhTable(i) = 42 1 +i AhTable(i) = 43 1 +i AhTable(i) = 44 1 +i AhTable(i) = 45 1 +i AhTable(i) = 46 1 +i AhTable(i) = 47 1 +i AhTable(i) = 48 1 +i AhTable(i) = 49 1 +i AhTable(i) = 50 1 +i AhTable(i) = 51 1 +i AhTable(i) = 52 1 +i AhTable(i) = 53 1 +i AhTable(i) = 54 1 +i AhTable(i) = 55 1 +i AhTable(i) = 56 1 +i AhTable(i) = 57 1 +i AhTable(i) = 58 1 +i AhTable(i) = 59 1 +i AhTable(i) = 60 1 +i AhTable(i) = 61 1 +i AhTable(i) = 62 1 +i AhTable(i) = 63 1 +i AhTable(i) = 64 1 +i AhTable(i) = 65 1 +i AhTable(i) = 66 1 +i AhTable(i) = 67 1 +i AhTable(i) = 68 1 +i AhTable(i) = 69 1 +i AhTable(i) = 70 1 +i AhTable(i) = 71 1 +i AhTable(i) = 72 1 +i AhTable(i) = 73 1 +i AhTable(i) = 74 1 +i AhTable(i) = 75 1 +i AhTable(i) = 76 1 +i AhTable(i) = 77 1 +i AhTable(i) = 78 1 +i AhTable(i) = 79 1 +i AhTable(i) = 80 1 +i AhTable(i) = 81 1 +i AhTable(i) = 82 1 +i AhTable(i) = 83 1 +i AhTable(i) = 84 1 +i AhTable(i) = 85 1 +i AhTable(i) = 86 1 +i AhTable(i) = 87 1 +i AhTable(i) = 88 1 +i AhTable(i) = 89 1 +i AhTable(i) = 90 0 + +Testing atmospheric model GenerateHahgTables method ... +Results from GenerateHahgTables = +Hahgsb = -0.085266 +i IncTable(i) = 0 0 +i IncTable(i) = 1 1 +i IncTable(i) = 2 2 +i IncTable(i) = 3 3 +i IncTable(i) = 4 4 +i IncTable(i) = 5 5 +i IncTable(i) = 6 6 +i IncTable(i) = 7 7 +i IncTable(i) = 8 8 +i IncTable(i) = 9 9 +i IncTable(i) = 10 10 +i IncTable(i) = 11 11 +i IncTable(i) = 12 12 +i IncTable(i) = 13 13 +i IncTable(i) = 14 14 +i IncTable(i) = 15 15 +i IncTable(i) = 16 16 +i IncTable(i) = 17 17 +i IncTable(i) = 18 18 +i IncTable(i) = 19 19 +i IncTable(i) = 20 20 +i IncTable(i) = 21 21 +i IncTable(i) = 22 22 +i IncTable(i) = 23 23 +i IncTable(i) = 24 24 +i IncTable(i) = 25 25 +i IncTable(i) = 26 26 +i IncTable(i) = 27 27 +i IncTable(i) = 28 28 +i IncTable(i) = 29 29 +i IncTable(i) = 30 30 +i IncTable(i) = 31 31 +i IncTable(i) = 32 32 +i IncTable(i) = 33 33 +i IncTable(i) = 34 34 +i IncTable(i) = 35 35 +i IncTable(i) = 36 36 +i IncTable(i) = 37 37 +i IncTable(i) = 38 38 +i IncTable(i) = 39 39 +i IncTable(i) = 40 40 +i IncTable(i) = 41 41 +i IncTable(i) = 42 42 +i IncTable(i) = 43 43 +i IncTable(i) = 44 44 +i IncTable(i) = 45 45 +i IncTable(i) = 46 46 +i IncTable(i) = 47 47 +i IncTable(i) = 48 48 +i IncTable(i) = 49 49 +i IncTable(i) = 50 50 +i IncTable(i) = 51 51 +i IncTable(i) = 52 52 +i IncTable(i) = 53 53 +i IncTable(i) = 54 54 +i IncTable(i) = 55 55 +i IncTable(i) = 56 56 +i IncTable(i) = 57 57 +i IncTable(i) = 58 58 +i IncTable(i) = 59 59 +i IncTable(i) = 60 60 +i IncTable(i) = 61 61 +i IncTable(i) = 62 62 +i IncTable(i) = 63 63 +i IncTable(i) = 64 64 +i IncTable(i) = 65 65 +i IncTable(i) = 66 66 +i IncTable(i) = 67 67 +i IncTable(i) = 68 68 +i IncTable(i) = 69 69 +i IncTable(i) = 70 70 +i IncTable(i) = 71 71 +i IncTable(i) = 72 72 +i IncTable(i) = 73 73 +i IncTable(i) = 74 74 +i IncTable(i) = 75 75 +i IncTable(i) = 76 76 +i IncTable(i) = 77 77 +i IncTable(i) = 78 78 +i IncTable(i) = 79 79 +i IncTable(i) = 80 80 +i IncTable(i) = 81 81 +i IncTable(i) = 82 82 +i IncTable(i) = 83 83 +i IncTable(i) = 84 84 +i IncTable(i) = 85 85 +i IncTable(i) = 86 86 +i IncTable(i) = 87 87 +i IncTable(i) = 88 88 +i IncTable(i) = 89 89 +i IncTable(i) = 90 90 +i HahgtTable(i) = 0 0.0927882 +i HahgtTable(i) = 1 0.0927897 +i HahgtTable(i) = 2 0.0926801 +i HahgtTable(i) = 3 0.0922811 +i HahgtTable(i) = 4 0.0919356 +i HahgtTable(i) = 5 0.0920154 +i HahgtTable(i) = 6 0.09237 +i HahgtTable(i) = 7 0.0924426 +i HahgtTable(i) = 8 0.0925301 +i HahgtTable(i) = 9 0.0927414 +i HahgtTable(i) = 10 0.0928035 +i HahgtTable(i) = 11 0.0928777 +i HahgtTable(i) = 12 0.0928562 +i HahgtTable(i) = 13 0.0927912 +i HahgtTable(i) = 14 0.0929185 +i HahgtTable(i) = 15 0.093057 +i HahgtTable(i) = 16 0.0932062 +i HahgtTable(i) = 17 0.0933533 +i HahgtTable(i) = 18 0.0935115 +i HahgtTable(i) = 19 0.0936916 +i HahgtTable(i) = 20 0.093894 +i HahgtTable(i) = 21 0.094081 +i HahgtTable(i) = 22 0.0943062 +i HahgtTable(i) = 23 0.0944237 +i HahgtTable(i) = 24 0.0945789 +i HahgtTable(i) = 25 0.0948219 +i HahgtTable(i) = 26 0.0949008 +i HahgtTable(i) = 27 0.0950871 +i HahgtTable(i) = 28 0.0952767 +i HahgtTable(i) = 29 0.0954295 +i HahgtTable(i) = 30 0.0956298 +i HahgtTable(i) = 31 0.0958376 +i HahgtTable(i) = 32 0.0961333 +i HahgtTable(i) = 33 0.0963426 +i HahgtTable(i) = 34 0.0965614 +i HahgtTable(i) = 35 0.0967807 +i HahgtTable(i) = 36 0.0969975 +i HahgtTable(i) = 37 0.0972265 +i HahgtTable(i) = 38 0.0974282 +i HahgtTable(i) = 39 0.0976286 +i HahgtTable(i) = 40 0.097849 +i HahgtTable(i) = 41 0.098026 +i HahgtTable(i) = 42 0.0983025 +i HahgtTable(i) = 43 0.0984128 +i HahgtTable(i) = 44 0.0984969 +i HahgtTable(i) = 45 0.0985603 +i HahgtTable(i) = 46 0.0985962 +i HahgtTable(i) = 47 0.0986019 +i HahgtTable(i) = 48 0.0985743 +i HahgtTable(i) = 49 0.0985016 +i HahgtTable(i) = 50 0.0981902 +i HahgtTable(i) = 51 0.098033 +i HahgtTable(i) = 52 0.097828 +i HahgtTable(i) = 53 0.0975764 +i HahgtTable(i) = 54 0.0972561 +i HahgtTable(i) = 55 0.0968645 +i HahgtTable(i) = 56 0.0964032 +i HahgtTable(i) = 57 0.095861 +i HahgtTable(i) = 58 0.0952282 +i HahgtTable(i) = 59 0.0944953 +i HahgtTable(i) = 60 0.0936543 +i HahgtTable(i) = 61 0.0926872 +i HahgtTable(i) = 62 0.0915888 +i HahgtTable(i) = 63 0.0903436 +i HahgtTable(i) = 64 0.0889356 +i HahgtTable(i) = 65 0.0873557 +i HahgtTable(i) = 66 0.0855805 +i HahgtTable(i) = 67 0.0835888 +i HahgtTable(i) = 68 0.0813711 +i HahgtTable(i) = 69 0.0789007 +i HahgtTable(i) = 70 0.0761522 +i HahgtTable(i) = 71 0.0731 +i HahgtTable(i) = 72 0.0697142 +i HahgtTable(i) = 73 0.0659646 +i HahgtTable(i) = 74 0.061814 +i HahgtTable(i) = 75 0.0572283 +i HahgtTable(i) = 76 0.0521709 +i HahgtTable(i) = 77 0.0465849 +i HahgtTable(i) = 78 0.0404319 +i HahgtTable(i) = 79 0.0336589 +i HahgtTable(i) = 80 0.026218 +i HahgtTable(i) = 81 0.018064 +i HahgtTable(i) = 82 0.00917859 +i HahgtTable(i) = 83 -0.000461522 +i HahgtTable(i) = 84 -0.0107416 +i HahgtTable(i) = 85 -0.021546 +i HahgtTable(i) = 86 -0.0325029 +i HahgtTable(i) = 87 -0.0430034 +i HahgtTable(i) = 88 -0.052268 +i HahgtTable(i) = 89 -0.0598731 +i HahgtTable(i) = 90 -0.0660967 +i Hahgt0Table(i) = 0 0 +i Hahgt0Table(i) = 1 0.183398 +i Hahgt0Table(i) = 2 0.184652 +i Hahgt0Table(i) = 3 0.18459 +i Hahgt0Table(i) = 4 0.184491 +i Hahgt0Table(i) = 5 0.184482 +i Hahgt0Table(i) = 6 0.185425 +i Hahgt0Table(i) = 7 0.185348 +i Hahgt0Table(i) = 8 0.185338 +i Hahgt0Table(i) = 9 0.185338 +i Hahgt0Table(i) = 10 0.185447 +i Hahgt0Table(i) = 11 0.185436 +i Hahgt0Table(i) = 12 0.186154 +i Hahgt0Table(i) = 13 0.186379 +i Hahgt0Table(i) = 14 0.186915 +i Hahgt0Table(i) = 15 0.187235 +i Hahgt0Table(i) = 16 0.187655 +i Hahgt0Table(i) = 17 0.187964 +i Hahgt0Table(i) = 18 0.188358 +i Hahgt0Table(i) = 19 0.188741 +i Hahgt0Table(i) = 20 0.1891 +i Hahgt0Table(i) = 21 0.18959 +i Hahgt0Table(i) = 22 0.190036 +i Hahgt0Table(i) = 23 0.190499 +i Hahgt0Table(i) = 24 0.191015 +i Hahgt0Table(i) = 25 0.191582 +i Hahgt0Table(i) = 26 0.192163 +i Hahgt0Table(i) = 27 0.192775 +i Hahgt0Table(i) = 28 0.193384 +i Hahgt0Table(i) = 29 0.194042 +i Hahgt0Table(i) = 30 0.194717 +i Hahgt0Table(i) = 31 0.195453 +i Hahgt0Table(i) = 32 0.196211 +i Hahgt0Table(i) = 33 0.196989 +i Hahgt0Table(i) = 34 0.197781 +i Hahgt0Table(i) = 35 0.198584 +i Hahgt0Table(i) = 36 0.199389 +i Hahgt0Table(i) = 37 0.200202 +i Hahgt0Table(i) = 38 0.201015 +i Hahgt0Table(i) = 39 0.201825 +i Hahgt0Table(i) = 40 0.202628 +i Hahgt0Table(i) = 41 0.203422 +i Hahgt0Table(i) = 42 0.204203 +i Hahgt0Table(i) = 43 0.204968 +i Hahgt0Table(i) = 44 0.205713 +i Hahgt0Table(i) = 45 0.206433 +i Hahgt0Table(i) = 46 0.207124 +i Hahgt0Table(i) = 47 0.20778 +i Hahgt0Table(i) = 48 0.208396 +i Hahgt0Table(i) = 49 0.208963 +i Hahgt0Table(i) = 50 0.209475 +i Hahgt0Table(i) = 51 0.209922 +i Hahgt0Table(i) = 52 0.210296 +i Hahgt0Table(i) = 53 0.210586 +i Hahgt0Table(i) = 54 0.210779 +i Hahgt0Table(i) = 55 0.210862 +i Hahgt0Table(i) = 56 0.210453 +i Hahgt0Table(i) = 57 0.210269 +i Hahgt0Table(i) = 58 0.209931 +i Hahgt0Table(i) = 59 0.209421 +i Hahgt0Table(i) = 60 0.208721 +i Hahgt0Table(i) = 61 0.207808 +i Hahgt0Table(i) = 62 0.206662 +i Hahgt0Table(i) = 63 0.205258 +i Hahgt0Table(i) = 64 0.203571 +i Hahgt0Table(i) = 65 0.201573 +i Hahgt0Table(i) = 66 0.199236 +i Hahgt0Table(i) = 67 0.196529 +i Hahgt0Table(i) = 68 0.193417 +i Hahgt0Table(i) = 69 0.189868 +i Hahgt0Table(i) = 70 0.185844 +i Hahgt0Table(i) = 71 0.181308 +i Hahgt0Table(i) = 72 0.176222 +i Hahgt0Table(i) = 73 0.170547 +i Hahgt0Table(i) = 74 0.164243 +i Hahgt0Table(i) = 75 0.157272 +i Hahgt0Table(i) = 76 0.149598 +i Hahgt0Table(i) = 77 0.141185 +i Hahgt0Table(i) = 78 0.132006 +i Hahgt0Table(i) = 79 0.122039 +i Hahgt0Table(i) = 80 0.111276 +i Hahgt0Table(i) = 81 0.0997268 +i Hahgt0Table(i) = 82 0.0874385 +i Hahgt0Table(i) = 83 0.0745089 +i Hahgt0Table(i) = 84 0.0610982 +i Hahgt0Table(i) = 85 0.0475965 +i Hahgt0Table(i) = 86 0.034556 +i Hahgt0Table(i) = 87 0.0227539 +i Hahgt0Table(i) = 88 0.0130628 +i Hahgt0Table(i) = 89 0.00567603 +i Hahgt0Table(i) = 90 0 + +Results from r8trapzd = 0.0781374 for interval (a,b) = (0,0.8) + +Results from r8trapzd = 0.0488359 for interval (a,b) = (0,0.5) + +Results from r8trapzd = 0.0195344 for interval (a,b) = (0,0.2) + +Results from r8trapzd = 0.0488359 for interval (a,b) = (0.3,0.8) + +Results from r8trapzd = 0.0195344 for interval (a,b) = (0.3,0.5) + +Results from r8trapzd = 0.0195344 for interval (a,b) = (0.6,0.8) + +Test En ... +Results from En(1,0.28) = 0.957308 + Actual value = 0.957308 + +Results from En(1,0.733615937) = 0.35086 + Actual value = 0.35086 + +Test Ei ... +Results from Ei(0.234) = -0.626785 + Actual value = -0.626785 + + Results from Ei(1.5) = 3.30129 + Actual value = 3.30129 + +Results from Ei(2.6) = 7.57611 + Actual value = 7.57611 + +Results from Ei(0.01583) = -3.55274 + Actual value = -3.55274 + +Test G11Prime ... +Results from G11Prime(0.28) = 0.79134 + Actual value = 0.79134 + +Results from G11Prime(1.5836) = 0.217167 + Actual value = 0.217167 + + +x n G11Prime(x) Ei(x) En(x) +0.5 0 0.685535 0.45422 1.21306 +0.5 1 0.685535 0.45422 0.559774 +0.5 2 0.685535 0.45422 0.326644 +1 0 0.41451 1.89512 0.367879 +1 1 0.41451 1.89512 0.219384 +1 2 0.41451 1.89512 0.148496 +1.5 0 0.238472 3.30129 0.148753 +1.5 1 0.238472 3.30129 0.10002 +1.5 2 0.238472 3.30129 0.0731008 +EXCEPTIONS: +**PROGRAMMER ERROR** AtmosModel::Ei() - Invalid argument. Definition requires x > 0.0. Entered x = 0.0 +**PROGRAMMER ERROR** AtmosModel::En() - Invalid arguments. Definition requires (x > 0.0 and n >=0 ) or (x >= 0.0 and n > 1). Entered x = 0.0 and n = 1 +**PROGRAMMER ERROR** AtmosModel::En() - Invalid arguments. Definition requires (x > 0.0 and n >=0 ) or (x >= 0.0 and n > 1). Entered x = -1.0 and n = 0 + ************************************************ + diff --git a/isis/src/base/objs/AtmosModel/Makefile b/isis/src/base/objs/AtmosModel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1ac158c60db8d61b09fb39494034779b1f0307c6 --- /dev/null +++ b/isis/src/base/objs/AtmosModel/Makefile @@ -0,0 +1,6 @@ +INCS = AtmosModel.h NumericalAtmosApprox.h +SRCS = AtmosModel.cpp NumericalAtmosApprox.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/base/objs/AtmosModel/NumericalAtmosApprox.cpp b/isis/src/base/objs/AtmosModel/NumericalAtmosApprox.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e9750d797d7df8292d18c7292f270f19511ede8 --- /dev/null +++ b/isis/src/base/objs/AtmosModel/NumericalAtmosApprox.cpp @@ -0,0 +1,340 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/11/07 23:48:13 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "AtmosModel.h" +#include "NumericalAtmosApprox.h" +#include "NumericalApproximation.h" +#include "iException.h" +#include "iString.h" + +using namespace std; +namespace Isis { + /** + * This variation on the NumericalApproximation method + * integrates a specified AtmosModel function rather than an + * interpolated function based on a data set. It returns the + * integral of the given function from a to b for the given + * AtmosModel. Integration is performed by Romberg's method for + * Numerical Integration of order 2K, where, e.g., K=2 is + * simpson's rule. This is a generalization of the trapezoidal + * rule. Romberg Integration uses a series of refinements on + * the extended (or composite) trapezoidal rule. This method + * calls a polynomial interpolation (Neville's algorithm) to + * extrapolate successive refinements. + * + * @param am Pointer to AtmosModel object + * @param sub Enumerated value of atmospheric function to be + * integrated + * @param a Lower limit of integration + * @param b Upper limit of integration + * @return @b double Integral approximation of the function + * on the interval (a, b) + * @throws Isis::iException::Programmer "Failed to converge." + * @throws Isis::iException::Programmer "Caught an error" (from + * RefineExtendedTrap(), Constructor, Evaluate(), or + * PolynomialNevilleErrorEstimate() method) + * @see mathworld.wolfram.com/RombergIntegration.html + * @see RefineExtendedTrap() + * @internal + * @history 1999-08-11 K Teal Thompson - Original version in + * Isis2. + * @history 2000-12-29 Randy Kirk - Add absolute error + * tolerance. + * @history 2007-02-20 Janet Barrett - Imported to Isis3 in + * AtmosModel class. Original name r8qromb(). + * @history 2008-11-05 Jeannie Walldren - Renamed, moved to new + * class, and changed i/o parameters. + */ + double NumericalAtmosApprox::RombergsMethod (AtmosModel *am, IntegFunc sub, double a, double b) throw (iException &){ + // This method was derived from an algorithm in the text + // Numerical Recipes in C: The Art of Scientific Computing + // Section 4.3 by Flannery, Press, Teukolsky, and Vetterling + int maxits = 20; // maximium number of iterations allowed to converge + double dss = 0; // error estimate for + double h[maxits+1]; // relative stepsizes for trap + double trap[maxits+1]; // successive trapeziodal approximations + double epsilon; // desired fractional accuracy + double epsilon2; // desired fractional accuracy + double ss; // result + + epsilon = 1.0e-4; + epsilon2 = 1.0e-6; + + h[0] = 1.0; + try{ + NumericalApproximation interp(NumericalApproximation::PolynomialNeville); + for (int i=0; i= 4) { + interp.AddData(5, &h[i-4], &trap[i-4]); + ss = interp.Evaluate(0.0,NumericalApproximation::Extrapolate); + dss = interp.PolynomialNevilleErrorEstimate()[0]; + interp.Reset(); + // we work only until our necessary accuracy is achieved + if (fabs(dss) <= epsilon*fabs(ss)) return ss; + if (fabs(dss) <= epsilon2) return ss; + } + trap[i+1] = trap[i]; + h[i+1] = 0.25 * h[i]; + // This is a key step: the factor is 0.25d0 even though + // the stepsize is decreased by 0.5d0. This makes the + // extraplolation a polynomial in h-squared as allowed + // by the equation from Numerical Recipes 4.2.1 pg.132, + // not just a polynomial in h. + } + } + catch (iException e){ // catch error from RefineExtendedTrap, Constructor, Evaluate, PolynomialNevilleErrorEstimate + throw e.Message(e.Type(), + "NumericalAtmosApprox::RombergsMethod() - Caught the following error: ", + _FILEINFO_); + } + throw iException::Message(iException::Programmer, + "NumericalAtmosApprox::RombergsMethod() - Failed to converge in " + + iString(maxits) + " iterations.", + _FILEINFO_); + } + + /** + * This variation on the NumericalApproximation method + * integrates a specified AtmosModel function rather than an + * interpolated function based on a data set. This routine + * computes the @a nth stage of refinement of an + * extended trapezoidal rule. This method is used by + * RombergsMethod() to integrate. When called with @a n = 1, the + * method returns the crudest estimate of the integral. + * Subsequent calls with @a n = 2, 3, ... (in sequential order) + * will improve the accuracy by adding + * 2@a n-2 additional interior points. This method + * can be used to integrate by the extended trapeziodal rule if + * you know the number of steps you want to take. + * + * @param am Pointer to AtmosModel object + * @param sub Enumerated value of atmospheric function to be + * integrated + * @param a Lower limit of integration + * @param b Upper limit of integration + * @param s Previous value of refinement + * @param n Number of partitions to use when integrating + * @return @b double Integral (refined) approximation of the function + * on the interval (a, b) + * @throws Isis::iException::Programmer "Caught an error" (from + * InrFunc2Bint() or OutrFunc2Bint() method) + * @see RombergsMethod() + * @internal + * @history 1999-08-11 K Teal Thompson - Original version. + * @history 2007-02-20 Janet Barrett - Imported to Isis3 in AtmosModel class. Original name r8trapzd(). + * @history 2008-11-05 Jeannie Walldren - Renamed, moved to new + * class, and changed i/o parameters. + */ + double NumericalAtmosApprox::RefineExtendedTrap(AtmosModel *am, IntegFunc sub, double a, double b, double s, unsigned int n) throw (iException &){ + // This method was derived from an algorithm in the text + // Numerical Recipes in C: The Art of Scientific Computing + // Section 4.2 by Flannery, Press, Teukolsky, and Vetterling + try{ + if (n == 1) { + double begin; + double end; + if (sub == InnerFunction) { + begin = InrFunc2Bint(am,a); + end = InrFunc2Bint(am,b); + } + else { + begin = OutrFunc2Bint(am,a); + end = OutrFunc2Bint(am,b); + } + return (0.5 * (b - a) * (begin + end)); + } + else { + int it; + double delta,tnm,x,sum; + it = (int)(pow(2.0,(double)(n-2))); + tnm = it; + delta = (b - a) / tnm; // spacing of the points to be added + x = a + 0.5 * delta; + sum = 0.0; + for (int i=0; ip_atmosPhi = phi; + am->p_atmosCosphi = cos((PI/180.0)*phi); + + NumericalAtmosApprox qromb; + try{ + result = qromb.RombergsMethod(am,sub,1.0e-6,1.0); + return result; + } + catch (iException e){ // catch exception from RombergsMethod() + throw e.Message(e.Type(), + "NumericalAtmosApprox::OutrFunc2Bint() - Caught the following error: ", + _FILEINFO_); + } + } + + /** + * Inner function to be integrated. This function is the inner + * integrand with all its parameters except cos(ema) hidden. For + * atmSwitch=0 this integrand is mu times the photometric angle, + * giving the hemispheric albedo for the outer integral. + * atmSwitch of 1, 2, 3, give the 3 integrals over the + * atmospheric single- particle phase function used in the + * Hapke/Henyey-Greenstein atmospheric model. + * + * @param am Pointer to AtmosModel object + * @param mu Angle at which the function will be integrated + * @return @b double Value of the function evaluated at the + * given @a mu + * @throws Isis::iException::Programmer "Invalid value of + * atmospheric switch used as argument to this + * function" + * @internal + * @history 1999-03-15 Randy Kirk - Original version in Isis2. + * @history 2000-07-07 Randy Kirk - Add other integrals besides + * Ah. + * @history 2000-12-29 Randy Kirk - Modified /hide_inc/ so phi + * gets passed, etc. Moved factors to outside + * integration. + * @history 2007-07-20 Janet Barrett - Imported to Isis3 in AtmosModel class. + * @history 2008-11-05 Jeannie Walldren - Moved to new class and + * replaced Isis::PI with PI since this is in Isis + * namespace. + */ + double NumericalAtmosApprox::InrFunc2Bint(AtmosModel *am, double mu) { + double ema; //pass in mu, get emission angle + double sine; //sin(ema) + double alpha; + double phase; //angle between sun and camera + double result; + double phasefn;//Henyey-Greenstein phase fn + double xx; //temp var to calculate emunot, emu + double emunot; //exp(-tau/munot) + double emu; //exp(-tau/mu) + double tfac; //factor that occurs in the integrals for transmission + + // calculate the phase angle + // also calculate any of the other redundant parameters + ema = acos(mu) * (180.0/PI); + sine = sin(ema*(PI/180.0)); + if ((am->p_atmosAtmSwitch == 0) || (am->p_atmosAtmSwitch == 2)) { // Reflection phase <= 90 + alpha = am->p_atmosSini * sine * am->p_atmosCosphi + + am->p_atmosMunot * mu; + } + else { // Transmission phase <= 90 + alpha = am->p_atmosSini * sine * am->p_atmosCosphi - + am->p_atmosMunot * mu; + } + phase = acos(alpha) * (180.0/PI); + // now evaluate the integrand; all needed parameters + // have been hidden separately and passed to it in COMMON. + if (am->p_atmosAtmSwitch == 0) { + // integrand for hemispheric albedo + result = mu * am->p_atmosPM->CalcSurfAlbedo(phase,am->p_atmosInc,ema); + } + else { + phasefn = (1.0 - am->AtmosHga() * am->AtmosHga()) /pow((1.0+2.0*am->AtmosHga()*alpha+am->AtmosHga()*am->AtmosHga()),1.5); + xx = -am->AtmosTau() / max(am->p_atmosMunot,1.0e-30); + if (xx < -69.0) { + emunot = 0.0; + } + else if (xx > 69.0) { + emunot = 1.0e30; + } + else { + emunot = exp(xx); + } + xx = -am->AtmosTau() / max(mu,1.0e-30); + + if (xx < -69.0) { + emu = 0.0; + } + else if (xx > 69.0) { + emu = 1.0e30; + } + else { + emu = exp(xx); + } + if (mu == am->p_atmosMunot) { + tfac = am->AtmosTau() * emunot / (am->p_atmosMunot * am->p_atmosMunot); + } + else { + tfac = (emunot - emu) / (am->p_atmosMunot - mu); + } + if (am->p_atmosAtmSwitch == 1) { + result = mu * (phasefn - 1.0) * tfac; + } + else if (am->p_atmosAtmSwitch == 2) { + result = am->p_atmosMunot * mu * (phasefn - 1.0) * (1.0 - emunot * emu) / (am->p_atmosMunot + mu); + } + else if (am->p_atmosAtmSwitch == 3) { + result = -sine * am->p_atmosCosphi * (phasefn - 1.0) * tfac; + } + else { + string msg = "NumericalAtmosApprox::InrFunc2Bint() - Invalid value of atmospheric "; + msg += "switch used as argument to this function"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + return result; + } +}//end NumericalAtmosApprox.cpp diff --git a/isis/src/base/objs/AtmosModel/NumericalAtmosApprox.h b/isis/src/base/objs/AtmosModel/NumericalAtmosApprox.h new file mode 100644 index 0000000000000000000000000000000000000000..2f5c2c4e1c06e5a0100fa7f88bf727f9f8e1706e --- /dev/null +++ b/isis/src/base/objs/AtmosModel/NumericalAtmosApprox.h @@ -0,0 +1,72 @@ +#ifndef NUMERICALATMOSAPPROX_H +#define NUMERICALATMOSAPPROX_H +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/11/07 23:48:13 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "NumericalApproximation.h" +using namespace std; +namespace Isis { + class AtmosModel; +/** + * This class extends @b Isis::NumericalApproximation. It was + * created to handle numerical integration methods for specific + * atmospheric functions in the @b Isis::AtmosModel class. + * Rather than using a data set to interpolate a function, these + * methods can take in a pointer to an AtmosModel object and an + * enumerated value for the specific function that needs to be + * integrated. + * + * @ingroup Math and RadiometricAndPhotometricCorrection + * + * @author 2008-11-05 Jeannie Walldren + * @internal + * @history 2008-11-05 Jeannie Walldren - Original Version. + * @history 2008-11-07 Jeannie Walldren - Fixed documentation + */ + class NumericalAtmosApprox : public NumericalApproximation{ + public: + //! Uses @b Isis::NumericalApproximation constructor + NumericalAtmosApprox(const NumericalApproximation::InterpType &itype=CubicNatural):NumericalApproximation(itype){}; + //! Empty destructor. + virtual ~NumericalAtmosApprox(){}; + + /** + * This enum defines function to be integrated by Romberg's + * method. + */ + enum IntegFunc { OuterFunction, //!< Indicates that Romberg's method will integrate the function OutrFunc2Bint() + InnerFunction //!< Indicates that Romberg's method will integrate the function InrFunc2Bint() + }; + double RombergsMethod (AtmosModel *am, IntegFunc sub, double a, double b) throw (iException &); + double RefineExtendedTrap(AtmosModel *am, IntegFunc sub, double a, double b, double s, unsigned int n) throw (iException &); + + static double OutrFunc2Bint(AtmosModel *am, double phi); + static double InrFunc2Bint(AtmosModel *am, double mu); + + }; +}; +#endif + + diff --git a/isis/src/base/objs/AtmosModel/unitTest.cpp b/isis/src/base/objs/AtmosModel/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c34f5e3187b30bf0b8e2c9597b8a2a4acc85a14 --- /dev/null +++ b/isis/src/base/objs/AtmosModel/unitTest.cpp @@ -0,0 +1,431 @@ +#include +#include +#include "NumericalApproximation.h" +#include "NumericalAtmosApprox.h" +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "AtmosModel.h" +#include "AtmosModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Anisotropic1.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; +void doit(Pvl &lab, PhotoModel &pm); + +int main () { + Isis::Preference::Preferences(true); + cout << "UNIT TEST for Isis::AtmosModel" << endl << endl; + + Pvl lab; + lab.AddObject(PvlObject("PhotometricModel")); + lab.FindObject("PhotometricModel").AddGroup(PvlGroup("Algorithm")); + lab.FindObject("PhotometricModel").FindGroup("Algorithm").AddKeyword(PvlKeyword("Name","Lambert"));// HapkeHen + PhotoModel *pm = PhotoModelFactory::Create(lab); + + cout << "Testing missing AtmosphericModel object ..." << endl; + doit(lab,*pm); + + lab.AddObject(PvlObject("AtmosphericModel")); + cout << "Testing missing Algorithm group ..." << endl; + doit(lab,*pm); + + lab.FindObject("AtmosphericModel").AddGroup(PvlGroup("Algorithm")); + cout << "Testing missing Name keyword ..." << endl; + doit(lab,*pm); + + lab.FindObject("AtmosphericModel").FindGroup("Algorithm").AddKeyword(PvlKeyword("Name","Anisotropic1"), Pvl::Replace); + cout << "Testing supported atmospheric model ..." << endl; + doit(lab,*pm); + + AtmosModel *am = AtmosModelFactory::Create(lab,*pm); + + try { + am->SetAtmosWha(0.98); + cout << "Testing atmospheric model get methods ..." << endl; + cout << "AlgorithmName = " << am->AlgorithmName() << endl; + cout << "AtmosTau = " << am->AtmosTau() << endl; + cout << "AtmosWha = " << am->AtmosWha() << endl; + cout << "AtmosHga = " << am->AtmosHga() << endl; + cout << "AtmosNulneg = " << am->AtmosNulneg() << endl; + cout << "AtmosNinc = " << am->AtmosNinc() << endl; + + cout << endl; + + am->SetStandardConditions(true); + cout << "Testing atmospheric model get methods in standard conditions..." << endl; + cout << "AlgorithmName = " << am->AlgorithmName() << endl; + cout << "AtmosTau = " << am->AtmosTau() << endl; + cout << "AtmosWha = " << am->AtmosWha() << endl; + cout << "AtmosHga = " << am->AtmosHga() << endl; + cout << "AtmosNulneg = " << am->AtmosNulneg() << endl; + cout << "AtmosNinc = " << am->AtmosNinc() << endl; + am->SetStandardConditions(false); + + am->SetAtmosWha(0.95); + } + catch (iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing boundary conditions of atmospheric model set methods ..." << endl; + try { + am->SetAtmosTau(-1.0); + } + catch (iException &e) { + e.Report(false); + } + + try { + am->SetAtmosWha(0.0); + } + catch (iException &e) { + e.Report(false); + } + + try { + am->SetAtmosWha(2.0); + } + catch (iException &e) { + e.Report(false); + } + + try { + am->SetAtmosHga(-1.0); + } + catch (iException &e) { + e.Report(false); + } + + try { + am->SetAtmosHga(1.0); + } + catch (iException &e) { + e.Report(false); + } + + cout << endl; + + cout << "Testing atmospheric model InrFunc2Bint method ..." + << endl; + try { + am->SetAtmosAtmSwitch(1); + am->SetAtmosInc(0.0); + am->SetAtmosPhi(0.0); + am->SetAtmosHga(.68); + am->SetAtmosTau(.28); + double result = NumericalAtmosApprox::InrFunc2Bint(am,1.0e-6); + cout << "Results from InrFunc2Bint = " << result << + endl << endl; + } + catch (iException &e) { + e.Report(false); + } + cout << endl; + + try { + am->SetAtmosAtmSwitch(2); + am->SetAtmosInc(3.0); + am->SetAtmosPhi(78.75); + am->SetAtmosHga(.68); + am->SetAtmosTau(.28); + double result = NumericalAtmosApprox::InrFunc2Bint(am,.75000025); + cout << "Results from InrFunc2Bint = " << result << + endl << endl; + } + catch (iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing atmospheric model r8trapzd method ..." + << endl; + try { + am->SetAtmosAtmSwitch(1); + am->SetAtmosInc(0.0); + am->SetAtmosPhi(0.0); + am->SetAtmosHga(.68); + am->SetAtmosTau(.28); + double ss = 0; + NumericalAtmosApprox nam; + for (int i = 1; i < 10; i++) { + ss = nam.RefineExtendedTrap(am,NumericalAtmosApprox::OuterFunction,0.0,180.0,ss,i); + cout << "Results from r8trapzd = " << ss << " for i = " << i << endl; + ss = 0; + } + cout << endl; + } + catch (iException &e) { + e.Report(false); + } + + cout << "Testing atmospheric model OutrFunc2Bint method ..." + << endl; + try { + am->SetAtmosAtmSwitch(1); + am->SetAtmosInc(0.0); + am->SetAtmosPhi(0.0); + am->SetAtmosHga(.68); + am->SetAtmosTau(.28); + double result = NumericalAtmosApprox::OutrFunc2Bint(am,0.0); + cout << "Results from OutrFunc2Bint = " << result << + endl << endl; + } + catch (iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing atmospheric model r8qromb method ..." + << endl; + try { + am->SetAtmosAtmSwitch(1); + am->SetAtmosInc(0.0); + am->SetAtmosPhi(0.0); + am->SetAtmosHga(.68); + am->SetAtmosTau(.28); + double ss; + NumericalAtmosApprox nam; + ss = nam.RombergsMethod(am,NumericalAtmosApprox::OuterFunction,0.,180.); + cout << "Results from r8qromb = " << ss << + endl << endl; + } + catch (iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing atmospheric model GenerateAhTable method ..." + << endl; + try { + am->GenerateAhTable(); + + cout << "Results from GenerateAhTable = " << endl; + cout << "Ab = " << am->AtmosAb() << endl; + int ninc = am->AtmosNinc(); + vector inctable; + inctable = am->AtmosIncTable(); + for (int i=0; i ahtable; + ahtable = am->AtmosAhTable(); + for (int i=0; iSetAtmosWha(.95); + am->SetAtmosInc(0.0); + am->SetAtmosPhi(0.0); + am->SetAtmosHga(.68); + am->SetAtmosTau(.28); + am->GenerateHahgTables(); + cout << "Results from GenerateHahgTables = " << endl; + cout << "Hahgsb = " << am->AtmosHahgsb() << endl; + int ninc = am->AtmosNinc(); + vector inctable; + inctable = am->AtmosIncTable(); + for (int i=0; i hahgttable; + hahgttable = am->AtmosHahgtTable(); + for (int i=0; i hahgt0table; + hahgt0table = am->AtmosHahgt0Table(); + for (int i=0; iSetAtmosAtmSwitch(1); + am->SetAtmosInc(0.0); + am->SetAtmosPhi(0.0); + am->SetAtmosHga(.68); + am->SetAtmosTau(.28); + double ss = 0; + + NumericalAtmosApprox nam; + for(double a = 0.0; a < 0.8; a+=.3) { + for(double b = 0.8; b > a; b-=.3) { + ss = 0; + ss = nam.RefineExtendedTrap(am,NumericalAtmosApprox::OuterFunction,a,b,ss,10); + cout << "Results from r8trapzd = " << ss << " for interval (a,b) = (" + << a << "," << b << ")" << endl << endl; + } + } + + + }catch (iException &error){ + error.Report(false); + } + // Exponential integrals and G11Prime + cout << "Test En ..." << endl; + try { + int n = 1; + double x = .28; + double result; + + result = AtmosModel::En(n,x); + cout << "Results from En(1,0.28) = " << result << endl; + cout << " Actual value = " << 0.957308 << endl + << endl; + } + catch (iException &e) { + e.Report(); + } + + try { + int n = 1; + double x = .733615937; + double result; + + result = AtmosModel::En(n,x); + cout << "Results from En(1,0.733615937) = " << result << endl; + cout << " Actual value = " << 0.35086 << endl + << endl; + } + catch (iException &e) { + e.Report(); + } + + cout << "Test Ei ..." << endl; + try { + double x = .234; + double result; + + result = AtmosModel::Ei(x); + cout << "Results from Ei(0.234) = " << result << endl; + cout << " Actual value = " << -0.626785 << endl + << endl; + } + catch (iException &e) { + e.Report(); + } + + try { + double x = 1.5; + double result; + + result = AtmosModel::Ei(x); + cout << " Results from Ei(1.5) = " << result << endl; + cout << " Actual value = " << 3.30129 << endl + << endl; + } + catch (iException &e) { + e.Report(); + } + + try { + double x = 2.6; + double result; + + result = AtmosModel::Ei(x); + cout << "Results from Ei(2.6) = " << result << endl; + cout << " Actual value = " << 7.57611 << endl + << endl; + } + catch (iException &e) { + e.Report(); + } + + try { + double x = .01583; + double result; + + result = AtmosModel::Ei(x); + cout << "Results from Ei(0.01583) = " << result << endl; + cout << " Actual value = " << -3.55274 << endl + << endl; + } + catch (iException &e) { + e.Report(); + } + + cout << "Test G11Prime ..." << endl; + try { + double tau = .28; + double result; + + result = AtmosModel::G11Prime(tau); + cout << "Results from G11Prime(0.28) = " << result << endl; + cout << " Actual value = " << 0.79134 << endl + << endl; + } + catch (iException &e) { + e.Report(); + } + + try { + double tau = 1.5836; + double result; + + result = AtmosModel::G11Prime(tau); + cout << "Results from G11Prime(1.5836) = " << result << endl; + cout << " Actual value = " << 0.217167 << endl + << endl; + } + catch (iException &e) { + e.Report(); + } + cout << endl; + cout << "x\tn\tG11Prime(x)\tEi(x)\tEn(x)" << endl; + for(double x = .5; x < 1.75; x+=.5) { + for(int n = 0; n < 3; n++) { + cout << x << "\t" << n << "\t"; + cout << AtmosModel::G11Prime(x) << "\t"; + if(x == 1) cout << "\t"; + cout << AtmosModel::Ei(x) << "\t"; + cout << AtmosModel::En(n, x) << endl; + } + } + cout << "EXCEPTIONS:" << endl; + try{AtmosModel::Ei(0.0);} // require x > 0 + catch(iException e){ e.Report(); } + try{AtmosModel::En(1,0.0);} // require (n>=0 & x>0) or (n>1 & x>=0) + catch(iException e){ e.Report(); } + try{AtmosModel::En(0,-1.0);}// require (n>=0 & x>0) or (n>1 & x>=0) + catch(iException e){ e.Report(); } + + cout << "\t************************************************" << endl; + cout << endl; +} + +void doit(Pvl &lab, PhotoModel &pm) { + try { + //AtmosModel *am = AtmosModelFactory::Create(lab,pm); + AtmosModelFactory::Create(lab,pm); + } + catch (iException &error) { + error.Report(false); + } + + cout << endl; +} diff --git a/isis/src/base/objs/AtmosModelFactory/AtmosModelFactory.cpp b/isis/src/base/objs/AtmosModelFactory/AtmosModelFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a759be96524db258502df32c9d4c106f1654d77 --- /dev/null +++ b/isis/src/base/objs/AtmosModelFactory/AtmosModelFactory.cpp @@ -0,0 +1,82 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/18 18:53:56 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "AtmosModelFactory.h" +#include "AtmosModel.h" +#include "Plugin.h" +#include "iException.h" +#include "Filename.h" + +namespace Isis { + /** + * Create an AtmosModel object using a PVL specification. + * An example of the PVL required for this is: + * + * @code + * Object = AtmosphericModel + * Group = Algorithm + * Name = Isotropic1 + * Tau = 0.7 + * Tauref = 0.0 + * Wha = 0.5 + * Wharef = 0.0 + * Hnorm = 0.003 + * Nulneg = NO + * EndGroup + * EndObject + * @endcode + * + * There are many other options that can be set via the pvl and are + * described in other documentation (see below). + * + * @param pvl The pvl object containing the specification + * @param pmodel The PhotoModel objects contining the data + * + * @return A pointer to the new AtmosModel + * + * @see atmosphericModels.doc + **/ + AtmosModel *AtmosModelFactory::Create(Pvl &pvl, PhotoModel &pmodel) { + + // Get the algorithm name to create + PvlGroup &algo = pvl.FindObject("AtmosphericModel") + .FindGroup("Algorithm",Pvl::Traverse); + std::string algorithm = algo["Name"]; + + // Open the factory plugin file + Plugin *p = new Plugin; + Filename f("AtmosModel.plugin"); + if (f.Exists()) { + p->Read("AtmosModel.plugin"); + } + else { + p->Read("$ISISROOT/lib/AtmosModel.plugin"); + } + + // Get the algorithm specific plugin and return it + AtmosModel * (*plugin) (Pvl &pvl, PhotoModel &pmodel); + plugin = (AtmosModel * (*)(Pvl &pvl, PhotoModel &pmodel)) + p->GetPlugin(algorithm); + return (*plugin)(pvl,pmodel); + } +} // end namespace isis diff --git a/isis/src/base/objs/AtmosModelFactory/AtmosModelFactory.h b/isis/src/base/objs/AtmosModelFactory/AtmosModelFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..64693cb1ea756b6ad1c8d0c42d8ec1c7312e7407 --- /dev/null +++ b/isis/src/base/objs/AtmosModelFactory/AtmosModelFactory.h @@ -0,0 +1,78 @@ +#ifndef AtmosModelFactory_h +#define AtmosModelFactory_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/18 18:53:56 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { + class Pvl; + class PhotoModel; + class AtmosModel; + + + /** + * This class is used to create AtmosModel objects. Typically, applications + *which perform atmospheric corrections need to use different types of + *atmospheric function such as Isotropic1, Anisotropic1, HapkeAtm1, etc. If this + *factory is given a Pvl object which contains an AtmosModel definition, it will + *create that specific instance of the class. For example, + * + * @code + * Object = AtmosphericModel Group = Algorithm + * Name = Isotropic1 ... + * EndGroup ... + *EndObject End + * @endcode + * + * Will create an Isotropic 1st order object (which is derived from AtmosModel). + * The simplest way to create an AtmosModel class is to use the static Create + * method + * + * @code + * Pvl p("myatmosmodel.pvl"); + * AtmosModel *ar = AtmosModelFactory::Create(p); + * @endcode + * + * @ingroup PatternMatching + * + * @author 2006-01-23 Janet Barrett + * + * @internal + * @history 2008-06-18 Christopher Austin - Fixed documentation errors + */ + class AtmosModelFactory { + public: + static AtmosModel *Create(Pvl &pvl, PhotoModel &pmodel); + + private: + /** + * Constructor (its private so you can't use it). Use the Create Method + * instead. + */ + AtmosModelFactory() {}; + + //! Destroys the AtmosModelFactory + ~AtmosModelFactory() {}; + }; +}; + +#endif diff --git a/isis/src/base/objs/AtmosModelFactory/AtmosModelFactory.truth b/isis/src/base/objs/AtmosModelFactory/AtmosModelFactory.truth new file mode 100644 index 0000000000000000000000000000000000000000..094db867b3f063641bf532719b5d59df88832edd --- /dev/null +++ b/isis/src/base/objs/AtmosModelFactory/AtmosModelFactory.truth @@ -0,0 +1 @@ +All testing deferred to AtmosModel and it's extended classes. diff --git a/isis/src/base/objs/AtmosModelFactory/Makefile b/isis/src/base/objs/AtmosModelFactory/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..acb7bf94f1c979cf2badde0c53cf181d48b75859 --- /dev/null +++ b/isis/src/base/objs/AtmosModelFactory/Makefile @@ -0,0 +1,5 @@ +INCS = AtmosModelFactory.h +SRCS = AtmosModelFactory.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/AtmosModelFactory/unitTest.cpp b/isis/src/base/objs/AtmosModelFactory/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..33b1d2f235cf91e39d9e75b1c89ef2ee63fa1d41 --- /dev/null +++ b/isis/src/base/objs/AtmosModelFactory/unitTest.cpp @@ -0,0 +1,12 @@ +#include +#include +#include "Preference.h" + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + cout << "All testing deferred to AtmosModel and it's extended classes." << endl; + + return 0; +} diff --git a/isis/src/base/objs/AutoReg/AutoReg.cpp b/isis/src/base/objs/AutoReg/AutoReg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c66aea2b18f109887d330fa4de608fd6d8b62347 --- /dev/null +++ b/isis/src/base/objs/AutoReg/AutoReg.cpp @@ -0,0 +1,1203 @@ +#include "AutoReg.h" +#include "Chip.h" +#include "Filename.h" +#include "Histogram.h" +#include "LeastSquares.h" +#include "iException.h" +#include "Interpolator.h" +#include "Matrix.h" +#include "Plugin.h" +#include "PolynomialBivariate.h" +#include "Pvl.h" + +namespace Isis { + /** + * Create AutoReg object. Because this is a pure virtual class you can + * not create an AutoReg class directly. Instead, see the AutoRegFactory + * class. + * + * @param pvl A pvl object containing a valid AutoReg specification + * + * @see patternMatch.doc under the coreg application + */ + AutoReg::AutoReg (Pvl &pvl) { + p_template = pvl.FindObject("AutoRegistration"); + + // Set default parameters + p_patternChip.SetSize(3,3); + p_searchChip.SetSize(5,5); + p_fitChip.SetSize(5,5); + p_reducedPatternChip.SetSize(3,3); + p_reducedSearchChip.SetSize(5,5); + p_reducedFitChip.SetSize(5,5); + + SetPatternValidPercent(50.0); + SetPatternZScoreMinimum(1.0); + SetTolerance(Isis::Null); + + SetSubPixelAccuracy(true); + SetEccentricityTesting(false); + SetResidualTesting(false); + SetSurfaceModelDistanceTolerance(1.5); + SetSurfaceModelWindowSize(5); + + SetSurfaceModelEccentricityRatio(2); // 2:1 + SetSurfaceModelResidualTolerance(0.1); + SetReductionFactor(1); + + // Clear statistics + //TODO: Delete these after control net refactor. + p_Total = 0; + p_Success = 0; + p_PatternChipNotEnoughValidData = 0; + p_PatternZScoreNotMet = 0; + p_FitChipNoData = 0; + p_FitChipToleranceNotMet = 0; + p_SurfaceModelNotEnoughValidData = 0; + p_SurfaceModelSolutionInvalid = 0; + p_SurfaceModelDistanceInvalid = 0; + p_SurfaceModelEccentricityRatioNotMet = 0; + p_SurfaceModelResidualToleranceNotMet = 0; + + p_sampMovement = 0.; + p_lineMovement = 0.; + + Init(); + Parse(pvl); + } + + /** + * Initialize AutoReg object private variables. Fill fit chip, reduced pattern + * chip and reduced search chip with nulls. + * + */ + void AutoReg::Init(){ + // Set computed parameters to NULL so we don't use values from a previous + // run + p_ZScore1 = Isis::Null; + p_ZScore2 = Isis::Null; + p_goodnessOfFit = Isis::Null; + p_surfaceModelEccentricity = Isis::Null; + p_surfaceModelEccentricityRatio = Isis::Null; + p_surfaceModelAvgResidual = Isis::Null; + + p_bestSamp = 0; + p_bestLine = 0; + p_bestFit = Isis::Null; + + // -------------------------------------------------- + // Nulling out the fit chip + // -------------------------------------------------- + for (int line = 1; line <= p_fitChip.Lines(); line++) { + for (int samp = 1; samp <= p_fitChip.Samples(); samp++) { + p_fitChip.SetValue(samp,line,Isis::Null); + } + } + // -------------------------------------------------- + // Nulling out the reduced pattern chip + // -------------------------------------------------- + for (int line = 1; line <= p_reducedPatternChip.Lines(); line++) { + for (int samp = 1; samp <= p_reducedPatternChip.Samples(); samp++) { + p_reducedPatternChip.SetValue(samp,line,Isis::Null); + } + } + // -------------------------------------------------- + // Nulling out the reduced search chip + // -------------------------------------------------- + for (int line = 1; line <= p_reducedSearchChip.Lines(); line++) { + for (int samp = 1; samp <= p_reducedSearchChip.Samples(); samp++) { + p_reducedSearchChip.SetValue(samp,line,Isis::Null); + } + } + + } + + //! Destroy AutoReg object + AutoReg::~AutoReg() { + + } + + /** + * Initialize parameters in the AutoReg class using a PVL specification. + * An example of the PVL required for this is: + * + * @code + * Object = AutoRegistration + * Group = Algorithm + * Name = MaximumCorrelation + * Tolerance = 0.7 + * EndGroup + * + * Group = PatternChip + * Samples = 21 + * Lines = 21 + * EndGroup + * + * Group = SearchChip + * Samples = 51 + * Lines = 51 + * EndGroup + * EndObject + * @endcode + * + * There are many other options that can be set via the pvl and are + * described in other documentation (see below). + * + * @see patternMatch.doc under the coreg + * application + * + * @param pvl The pvl object containing the specification + * @internal + * @history 2010-06-15 Jeannie Walldren - Added ability to read + * ChipInterpolator keyword from the Algorithm group. + **/ + void AutoReg::Parse(Pvl &pvl) { + try { + // Get info from Algorithm group + PvlGroup &algo = pvl.FindGroup("Algorithm", Pvl::Traverse); + SetTolerance(algo["Tolerance"]); + if (algo.HasKeyword("ChipInterpolator")) { + SetChipInterpolator((std::string)algo["ChipInterpolator"]); + } + + if (algo.HasKeyword("SubpixelAccuracy")) { + SetSubPixelAccuracy((std::string)algo["SubpixelAccuracy"] == "True"); + } + + if (algo.HasKeyword("ReductionFactor")) { + SetReductionFactor((int)algo["ReductionFactor"]); + } + + // Setup the pattern chip + PvlGroup &pchip = pvl.FindGroup("PatternChip",Pvl::Traverse); + PatternChip()->SetSize((int)pchip["Samples"],(int)pchip["Lines"]); + + double minimum = Isis::ValidMinimum; + double maximum = Isis::ValidMaximum; + if (pchip.HasKeyword("ValidMinimum")) minimum = pchip["ValidMinimum"]; + if (pchip.HasKeyword("ValidMaximum")) maximum = pchip["ValidMaximum"]; + PatternChip()->SetValidRange(minimum,maximum); + + if (pchip.HasKeyword("MinimumZScore")) { + SetPatternZScoreMinimum((double)pchip["MinimumZScore"]); + } + + // Setup the search chip + PvlGroup &schip = pvl.FindGroup("SearchChip",Pvl::Traverse); + SearchChip()->SetSize((int)schip["Samples"],(int)schip["Lines"]); + + minimum = Isis::ValidMinimum; + maximum = Isis::ValidMaximum; + if (schip.HasKeyword("ValidMinimum")) minimum = schip["ValidMinimum"]; + if (schip.HasKeyword("ValidMaximum")) maximum = schip["ValidMaximum"]; + SearchChip()->SetValidRange(minimum,maximum); + + // What percentage of the pattern chip should be valid + if (pchip.HasKeyword("ValidPercent")) { + SetPatternValidPercent((double)pchip["ValidPercent"]); + } + + PvlObject ar = pvl.FindObject("AutoRegistration"); + if(ar.HasGroup("SurfaceModel")) { + PvlGroup &smodel = ar.FindGroup("SurfaceModel", Pvl::Traverse); + if(smodel.HasKeyword("DistanceTolerance")) { + SetSurfaceModelDistanceTolerance((double)smodel["DistanceTolerance"]); + } + + if(smodel.HasKeyword("WindowSize")) { + SetSurfaceModelWindowSize((int)smodel["WindowSize"]); + } + + // What kind of eccentricity ratio will we tolerate? + if(smodel.HasKeyword("EccentricityRatio")) { + SetEccentricityTesting(true); + SetSurfaceModelEccentricityRatio((double)smodel["EccentricityRatio"]); + } + + // What kind of average residual will we tolerate? + if(smodel.HasKeyword("ResidualTolerance")) { + SetResidualTesting(true); + SetSurfaceModelResidualTolerance((double)smodel["ResidualTolerance"]); + } + } + + } catch (iException &e) { + std::string msg = "Improper format for AutoReg PVL ["+pvl.Filename()+"]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + return; + } + + /** + * If the sub-pixel accuracy is enabled, the Register() method will attempt to + * match the pattern chip to the search chip at sub-pixel accuracy, otherwise it + * will be registered at whole pixel accuracy. + * + * @param on Set the state of registration accuracy. The + * default is sub-pixel accuracy is on + */ + void AutoReg::SetSubPixelAccuracy(bool on) { + p_subpixelAccuracy = on; + } + + /** + * Set the amount of data in the pattern chip that must be valid. For + * example, a 21x21 pattern chip has 441 pixels. If percent is 75 then + * at least 330 pixels pairs must be valid in order for a comparision + * between the pattern and search sub-region to occur. That is, both + * the pattern pixel and search pixel must be valid to be counted. Pixels + * are considered valid based on the min/max range specified on each of + * the Chips (see Chip::SetValidRange method). + * + * If the pattern chip reduction option is used this percentage will + * apply to all reduced patterns. Additionally, the pattern sampling + * effects the pixel count. For example if pattern sampling is 50% then + * only 220 pixels in the 21x21 pattern are considered so 165 must be + * valid. + * + * @param percent Percentage of valid data between 0 and 100, + * default is 50% if never invoked + */ + void AutoReg::SetPatternValidPercent(const double percent) { + if ((percent <= 0.0) || (percent > 100.0)) { + std::string msg = "Invalid value of PatternValidPercent [" + + iString(percent) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_patternValidPercent = percent; + } + + + /** + * Set the minimum pattern zscore. This option is used to + * ignore pattern chips which are bland (low standard + * deviation). If the minimum or maximum pixel value in the + * pattern chip does not meet the minimum zscore value (see a + * statisitcs book for definition of zscore) then invalid + * registration will occur. + * + * @param minimum The minimum zscore value for the pattern chip. + * Default is 1.0 + */ + void AutoReg::SetPatternZScoreMinimum (double minimum) { + if(minimum <= 0.0) { + std::string msg = "MinimumZScore must be greater than 0"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_minimumPatternZScore = minimum; + } + + + /** + * Set the tolerance for an acceptable goodness of fit + * + * @param tolerance This tolerance is used to test against the goodness + * of fit returned by the MatchAlgorith method after + * a surface model has been fit. See TestGoodnessOfFit + */ + void AutoReg::SetTolerance(const double tolerance) { + p_tolerance = tolerance; + } + + /** + * Sets the Chip class interpolator type to be used to load pattern and search + * chips. + * Acceptable values for the interpolator parameter include: + *
      + *
    • NearestNeighborType
    • + *
    • BiLinearType
    • + *
    • CubicConvolutionType
    • + *
    + * + * @param interpolator Name of interpolator type to be used. This is taken from + * the Pvl's ChipInterpolator keyword value. + * @author Jeannie Walldren + * @internal + * @history 2010-06-15 Jeannie Walldren - Original version. + */ + void AutoReg::SetChipInterpolator(const string interpolator) { + + Isis::Interpolator::interpType itype; + if (interpolator == "NearestNeighborType") { + itype = Isis::Interpolator::NearestNeighborType; + } + else if (interpolator == "BiLinearType") { + itype = Isis::Interpolator::BiLinearType; + } + else if (interpolator == "CubicConvolutionType") { + itype = Isis::Interpolator::CubicConvolutionType; + } + else { + throw iException::Message(iException::User, + "Invalid Interpolator type. Cannot use [" + + interpolator + "] to load chip", + _FILEINFO_); + } + + // Set pattern and search chips to use this interpolator type when reading data from cube + p_patternChip.SetReadInterpolator(itype); + p_searchChip.SetReadInterpolator(itype); + p_reducedPatternChip.SetReadInterpolator(itype); + p_reducedSearchChip.SetReadInterpolator(itype); + + } + + /** + * Set the surface model window size. The pixels in this window + * will be used to fit a surface model in order to compute + * sub-pixel accuracy. In some cases the default (3x3) and + * produces erroneous sub-pixel accuracy values. + * + * @param size The size of the window must be three or greater + * and odd. + */ + void AutoReg::SetSurfaceModelWindowSize (int size) { + if(size % 2 != 1 || size < 3) { + std::string msg = "WindowSize must be an odd number greater than or equal to 3"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_windowSize = size; + } + + + /** + * A 1:1 ratio represents a perfect circle. Allowing the user + * to set this ratio lets them determine which points to throw + * out if the surface model gets too elliptical. + * + * @param eccentricityRatio Eccentricity ratio. Must be greater than or equal + * to 1. + */ + void AutoReg::SetSurfaceModelEccentricityRatio(double eccentricityRatio){ + if(eccentricityRatio < 1){ + std::string msg = "EccentricityRatio must be 1 or larger."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_surfaceModelEccentricityRatioTolerance = eccentricityRatio; + p_surfaceModelEccentricityTolerance = sqrt(eccentricityRatio*eccentricityRatio -1)/ eccentricityRatio; + } + + /** + * Set the maximum average residual allowed from the surface + * model. Changing this tolerance allows the user to throw out + * points whose surfaces cannot be modeled well. The average + * rersidual is derived from the least squares solution fitting + * a surface model to a set of known data points, and computed + * by summing the absolute values of all the residuals (computed + * z minus actual z) and dividing by the number of residuals. + * + * @param residualTolerance Residual tolerance. Must be greater than 0. + */ + void AutoReg::SetSurfaceModelResidualTolerance(double residualTolerance){ + if (residualTolerance < 0){ + std::string msg = "ResidualTolerance must be 0 or larger."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_surfaceModelResidualTolerance = residualTolerance; + } + + /** + * Set a distance the surface model solution is allowed to move + * away from the best whole pixel fit in the fit chip. + * + * @param distance The distance allowed to move in pixels. Must + * be greater than 0. + */ + void AutoReg::SetSurfaceModelDistanceTolerance (double distance) { + if(distance <= 0.0) { + std::string msg = "DistanceTolerance must be greater than 0"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_distanceTolerance = distance; + } + + + /** + * Set the reduction factor used to speed up the pattern + * matching algorithm. + * + * @param factor Reduction factor. Must be greater than or equal to 1. + */ + void AutoReg::SetReductionFactor(int factor){ + if(factor < 1) { + std::string msg = "ReductionFactor must be 1 or greater."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_reduceFactor = factor; + } + + + /** + * This method reduces the given chip by the given reduction + * factor. Used to speed up the match algorithm. + * + * @param chip Chip to be reduced + * @param reductionFactor Factor by which to reduce chip. + * + * @return @b Chip Reduced chip object + */ + Chip AutoReg::Reduce(Chip &chip, int reductionFactor){ + Chip rChip((int)chip.Samples()/reductionFactor, + (int)chip.Lines()/reductionFactor); + if((int)rChip.Samples() < 1 || (int)rChip.Lines() < 1 ) { + return chip; + } + + // ---------------------------------- + // Fill the reduced Chip with nulls. + // ---------------------------------- + for (int line = 1; line <= rChip.Lines(); line++) { + for (int samp = 1; samp <= rChip.Samples(); samp++) { + rChip.SetValue(samp,line,Isis::Null); + } + } + + Statistics stats; + for(int l = 1; l <= rChip.Lines(); l++) { + int istartLine = (l -1) * reductionFactor + 1; + int iendLine = istartLine + reductionFactor - 1; + for(int s = 1; s <= rChip.Samples(); s++) { + + int istartSamp = (s -1) * reductionFactor + 1; + int iendSamp = istartSamp + reductionFactor - 1; + + stats.Reset(); + for(int line = istartLine; line < iendLine; line++ ) { + for(int sample = istartSamp; sample < iendSamp; sample++ ) { + stats.AddData(chip.GetValue(sample, line)); + } + } + rChip.SetValue(s,l,stats.Average()); + } + } + return rChip; + } + + + /** + * Walk the pattern chip through the search chip to find the best registration + * + * @return @b AutoReg::RegisterStatus Returns the status of the registration. + * + */ + AutoReg::RegisterStatus AutoReg::Register() { + // The search chip must be bigger than the pattern chip by N pixels in + // both directions for a successful surface model + int N = p_windowSize / 2 + 1; + + if (p_searchChip.Samples() < p_patternChip.Samples() + N) { + std::string msg = "Search chips samples ["; + msg += iString(p_searchChip.Samples()) + "] must be at "; + msg += "least [" +iString(N) + "] pixels wider than the pattern chip samples ["; + msg += iString(p_patternChip.Samples()) + "] for successful surface modeling"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + if (p_searchChip.Lines() < p_patternChip.Lines() + N) { + std::string msg = "Search chips lines ["; + msg += iString(p_searchChip.Lines()) + "] must be at "; + msg += "least [" +iString(N) + "] pixels taller than the pattern chip lines ["; + msg += iString(p_patternChip.Lines()) + "] for successful surface modeling"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + Init(); + p_Total++; + + // See if the pattern chip has enough good data + if (!p_patternChip.IsValid(p_patternValidPercent)) { + p_PatternChipNotEnoughValidData++; + p_status = PatternChipNotEnoughValidData; + return PatternChipNotEnoughValidData; + } + + if(!ComputeChipZScore(p_patternChip)) { + p_PatternZScoreNotMet++; + p_status = PatternZScoreNotMet; + return PatternZScoreNotMet; + } + + // ------------------------------------------------------------------ + // Prep for walking the search chip by computing the starting sample + // and line for the search. Also compute the sample and line + // increment for sparse walking + // ------------------------------------------------------------------ + int startSamp = (p_patternChip.Samples() - 1) / 2 + 1; + int startLine = (p_patternChip.Lines() - 1) / 2 + 1; + int endSamp = p_searchChip.Samples()-startSamp+1; + int endLine = p_searchChip.Lines()-startLine+1; + + // ---------------------------------------------------------------------- + // Before we attempt to apply the reduction factor, we need to make sure + // we won't produce a chip of a bad size. + // ---------------------------------------------------------------------- + if(p_patternChip.Samples()/p_reduceFactor < 2 || p_patternChip.Lines() / p_reduceFactor < 2) { + std::string msg = "Reduction factor is too large"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Establish the center search tack point as best pixel to start for the + // adaptive algorithm prior to reduction. + int bestSearchSamp = p_searchChip.TackSample(); + int bestSearchLine = p_searchChip.TackLine(); + + + // --------------------------------------------------------------------- + // if the reduction factor is still not equal to one, then we go ahead + // with the reduction of the chips and call Match to get the first + // estimate of the best line/sample. + // --------------------------------------------------------------------- + if(p_reduceFactor != 1) { + { //Do not remove this brace. It keeps startSamp, startLine, endSamp, and endLine in the + //proper scope. + + p_reducedPatternChip.SetSize((int)p_patternChip.Samples()/p_reduceFactor, + (int)p_patternChip.Lines()/p_reduceFactor); + + // ---------------------------------- + // Fill the reduced Chip with nulls. + // ---------------------------------- + for (int line = 1; line <= p_reducedPatternChip.Lines(); line++) { + for (int samp = 1; samp <= p_reducedPatternChip.Samples(); samp++) { + p_reducedPatternChip.SetValue(samp,line,Isis::Null); + } + } + + p_reducedPatternChip = Reduce(p_patternChip, p_reduceFactor); + if(!ComputeChipZScore(p_reducedPatternChip)){ + p_PatternZScoreNotMet++; + p_status = PatternZScoreNotMet; + return PatternZScoreNotMet; + } + + p_reducedSearchChip = Reduce(p_searchChip, p_reduceFactor); + int startSamp = (p_reducedPatternChip.Samples() - 1) / 2 + 1; + int startLine = (p_reducedPatternChip.Lines() - 1) / 2 + 1; + int endSamp = p_reducedSearchChip.Samples() - startSamp + 1; + int endLine = p_reducedSearchChip.Lines() - startLine + 1; + + Match(p_reducedSearchChip, p_reducedPatternChip, p_reducedFitChip, startSamp, endSamp, startLine, endLine); + if (p_bestFit == Isis::Null) { + p_FitChipNoData++; + p_status = FitChipNoData; + return FitChipNoData; + } + } + + // ------------------------------------------------------ + // p_bestSamp and p_bestLine are set in Match() which is + // called above. + // ----------------------------------------------------- + int bs = (p_bestSamp -1) * p_reduceFactor + ((p_reduceFactor -1)/2) + 1; + int bl = (p_bestLine -1) * p_reduceFactor + ((p_reduceFactor -1)/2) + 1; + + // --------------------------------------------------------------- + // Now we grow our window size according to the reduction factor. + // And we grow around were the first call Match() told us was the + // best line/sample. + // --------------------------------------------------------------- + int newstartSamp = bs - p_reduceFactor - p_windowSize -1; + int newendSamp = bs + p_reduceFactor + p_windowSize +1; + int newstartLine = bl - p_reduceFactor - p_windowSize -1; + int newendLine = bl + p_reduceFactor + p_windowSize +1; + + if(newstartLine < startLine) newstartLine = startLine; + if(newendSamp > endSamp) newendSamp = endSamp; + if(newstartSamp < startSamp) newstartSamp = startSamp; + if(newendLine > endLine) newendLine = endLine; + + startSamp = newstartSamp; + endSamp = newendSamp; + startLine = newstartLine; + endLine = newendLine; + // We have found a good pixel in the reduction chip, but we + // don't want to use it's position, so reset in prep. for + // non-adaptive registration. Save it off for the adaptive algorithm. + bestSearchSamp = bs; + bestSearchLine = bl; + p_bestSamp = 0; + p_bestLine = 0; + p_bestFit = Isis::Null; + } + + // If the algorithm is adaptive then it expects the pattern and search chip + // to be closely registered. Within a few pixels. So let it take over + // doing the sub-pixel accuracy computation + if (IsAdaptive()) { + p_status = AdaptiveRegistration(p_searchChip, p_patternChip, p_fitChip, + startSamp, startLine, endSamp, endLine, bestSearchSamp, + bestSearchLine); + if(p_status == AutoReg::Success) { + p_searchChip.SetChipPosition(p_chipSample,p_chipLine); + p_cubeSample = p_searchChip.CubeSample(); + p_cubeLine = p_searchChip.CubeLine(); + p_goodnessOfFit = p_bestFit; + p_Success++; + } + return p_status; + } + + // Not adaptive continue with slower search traverse + Match(p_searchChip, p_patternChip, p_fitChip, startSamp, endSamp, startLine, endLine); + + // Check to see if we went through the fit chip and never got a fit at + // any location. + if (p_bestFit == Isis::Null) { + p_FitChipNoData++; + p_status = FitChipNoData; + return FitChipNoData; + } + + // ----------------------------------------------------------------- + // We had a location in the fit chip. Save the values even if they + // may not meet tolerances. This is also saves the value in the + // event the user does not want a surface model fit + // ---------------------------------------------------------------- + p_goodnessOfFit = p_bestFit; + p_searchChip.SetChipPosition(p_bestSamp, p_bestLine); + p_cubeSample = p_searchChip.CubeSample(); + p_cubeLine = p_searchChip.CubeLine(); + + // Now see if we satisified the goodness of fit tolerance + if (!CompareFits(p_bestFit,Tolerance())) { + p_FitChipToleranceNotMet++; + p_status = FitChipToleranceNotMet; + return FitChipToleranceNotMet; + } + + // Try to fit a model for sub-pixel accuracy if necessary + if (p_subpixelAccuracy && !IsIdeal(p_bestFit)) { + std::vector samps,lines,fits; + for (int line = p_bestLine-p_windowSize/2; line <= p_bestLine+p_windowSize/2; line++) { + if (line < 1) continue; + if (line > p_fitChip.Lines()) continue; + for (int samp = p_bestSamp-p_windowSize/2; samp <= p_bestSamp+p_windowSize/2; samp++) { + if (samp < 1) continue; + if (samp > p_fitChip.Samples()) continue; + if (p_fitChip.GetValue(samp,line) == Isis::Null) continue; + samps.push_back((double) samp); + lines.push_back((double) line); + fits.push_back(p_fitChip.GetValue(samp,line)); + } + } + + // ----------------------------------------------------------- + // Make sure we have enough data for a surface fit. That is, + // we are not too close to the edge of the fit chip + // ----------------------------------------------------------- + if ((int)samps.size() < p_windowSize*p_windowSize * 2 / 3 + 1) { + p_SurfaceModelNotEnoughValidData++; + p_status = SurfaceModelNotEnoughValidData; + return SurfaceModelNotEnoughValidData; + } + + // ------------------------------------------------------------------- + // Now that we know we have enough data to model the surface we call + // ModelSurface to get the sub-pixel accuracy we are looking for. + // ------------------------------------------------------------------- + if(!ModelSurface(samps, lines, fits)) { + return p_status; + } + + // --------------------------------------------------------------------- + // See if the surface model solution moved too far from our whole pixel + // solution + // --------------------------------------------------------------------- + p_sampMovement = std::fabs(p_bestSamp - p_chipSample); + p_lineMovement = std::fabs(p_bestLine - p_chipLine); + if (p_sampMovement > p_distanceTolerance || + p_lineMovement > p_distanceTolerance) { + p_SurfaceModelDistanceInvalid++; + p_status = SurfaceModelDistanceInvalid; + return SurfaceModelDistanceInvalid; + } + + // Ok we have subpixel fits in chip space so convert to cube space + p_searchChip.SetChipPosition(p_chipSample,p_chipLine); + p_cubeSample = p_searchChip.CubeSample(); + p_cubeLine = p_searchChip.CubeLine(); + } + + p_Success++; + p_status = Success; + return Success; + } + + + /** + * This method computes the given Chip's Z-Score. If this value is less than the + * minimum pattern Z-Score or greater than the negative of the minimum pattern + * Z-Score, the method will return false. Otherwise, it returns true. + * + * @param chip Chip object whose Z-Score is calculated + * + * @return @b bool Indicates whether Z-Score calculated lies between the minimum + * and Pattern Z-Score and its negative. + */ + bool AutoReg::ComputeChipZScore(Chip &chip){ + Statistics patternStats; + for (int i = 0; i < chip.Samples(); i++) { + double pixels[chip.Lines()]; + for (int j = 0; j < chip.Lines(); j++) { + pixels[j] = chip.GetValue(i+1,j+1); + } + patternStats.AddData(pixels, chip.Lines()); + } + + // If it does not pass, return + p_ZScore1 = patternStats.ZScore(patternStats.Minimum()); + p_ZScore2 = patternStats.ZScore(patternStats.Maximum()); + + if (p_ZScore2 < p_minimumPatternZScore || + p_ZScore1 > -1*p_minimumPatternZScore) { + return false; + } + else { + return true; + } + } + + + /** + * Here we walk from start sample to end sample and start line to end line, and + * compare the pattern chip against the search chip to find the + * best line/sample. + * + * + * @param sChip Search chip + * @param pChip Pattern chip + * @param fChip Fit chip + * @param startSamp Start sample + * @param endSamp End sample + * @param startLine Start line + * @param endLine End line + * + */ + void AutoReg::Match(Chip &sChip, Chip &pChip, Chip &fChip, int startSamp, int endSamp, int startLine, int endLine){ + // Sanity check. Should have been caught by the two previous tests + if (startSamp == endSamp && startLine == endLine) { + std::string msg = "Sanity check, this shouldn't happen!"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + // Ok create a fit chip whose size is the same as the search chip + // and then fill it with nulls + fChip.SetSize(sChip.Samples(),sChip.Lines()); + for (int line = 1; line <= fChip.Lines(); line++) { + for (int samp = 1; samp <= fChip.Samples(); samp++) { + fChip.SetValue(samp,line,Isis::Null); + } + } + + // Create a chip the same size as the pattern chip. + Chip subsearch(pChip.Samples(), pChip.Lines()); + + for (int line = startLine; line <= endLine; line++) { + for (int samp = startSamp; samp <= endSamp; samp++) { + // Extract the subsearch chip and make sure it has enough valid data + sChip.Extract(samp,line, subsearch); + + if (!subsearch.IsValid(p_patternValidPercent)) continue; + + // Try to match the two subchips + double fit = MatchAlgorithm(pChip, subsearch); + + // If we had a fit save off information about that fit + if (fit != Isis::Null) { + fChip.SetValue(samp,line,fit); + if ((p_bestFit == Isis::Null) || CompareFits(fit,p_bestFit)) { + p_bestFit = fit; + p_bestSamp = samp; + p_bestLine = line; + } + } + } + } + } + + + /** + * We will model a 2-d surface as: + * + * z = a + b*x + c*y + d*x**2 + e*x*y + f*y**2 + * + * Then the partial derivatives are two lines: + * + * dz/dx = b + 2dx + ey + * dz/dy = c + ex + 2fy + * + * We will have a local min/max where dz/dx and dz/dy = 0. + * Solve using that condition using linear algebra yields: + * + * xlocal = (ce - 2bf) / (4df - ee) + * ylocal = (be - 2cd) / (4df - ee) + * + * These will be stored in p_chipSample and p_chipLine respectively. + * + * @param x vector of x (sample) values + * @param y vector of y (line) values + * @param z vector of z (goodness-of-fit) values + * @return @b bool Indicates whether the surface model solution is valid + * with residual tolerance and eccentricity ratio is met. + */ + bool AutoReg::ModelSurface(std::vector &x, + std::vector &y, + std::vector &z) { + PolynomialBivariate p(2); + LeastSquares lsq(p); + for (int i = 0; i < (int)x.size(); i++) { + std::vector xy; + xy.push_back(x[i]); + xy.push_back(y[i]); + lsq.AddKnown(xy,z[i]); + } + try { + lsq.Solve(); + } catch (iException &e) { + e.Clear(); + p_status = SurfaceModelSolutionInvalid; + p_SurfaceModelSolutionInvalid++; + return false; + } + + double a = p.Coefficient(0); + double b = p.Coefficient(1); + double c = p.Coefficient(2); + double d = p.Coefficient(3); + double e = p.Coefficient(4); + double f = p.Coefficient(5); + + //---------------------------------------------------------- + // Compute eccentricity + // For more information see: + // http://mathworld.wolfram.com/Ellipse.html + // Make sure delta matrix determinant is not equal to zero. + // The general quadratic curve + // dx^2+2exy+fy^2+2bx+2cy+a=0 + // is an ellipse when, after defining + // Delta = |d e/2 b| + // |e/2 f/2 c/2| + // |b c/2 a| + // J = |d e/2| + // |e/2 f/e| + // I = d + (f/2) + // Delta!=0, J>0, and Delta/I<0. Also assume the ellipse is + // nondegenerate (i.e., it is not a circle, so a!=c, and we have already + // established is not a point, since J=ac-b^2!=0) + // --------------------------------------------------------- + if (p_testEccentricity) { + bool canComputeEccentricity = true; + + Matrix delta(3, 3); + delta[0][0] = d; delta[0][1] = e/2; delta[0][2] = b/2; + delta[1][0] = e/2; delta[1][1] = f; delta[1][2] = c/2; + delta[2][0] = b/2; delta[2][1] = c/2; delta[2][2] = a; + if(delta.Determinant() == 0) { + canComputeEccentricity = false; + } + + //Make sure J matrix is greater than zero. + Matrix J(2, 2); + J[0][0] = d; J[0][1] = e/2; + J[1][0] = e/2; J[1][1] = f; + if(J.Determinant() <= 0) { + canComputeEccentricity = false; + } + + double I = d + (f); + if(delta.Determinant() / I >= 0) { + canComputeEccentricity = false; + } + + if (canComputeEccentricity) { + // If the eccentricity can be computed, go ahead and do so + // Begin by calculating the semi-axis lengths + double eA = sqrt((2*(d*(c/2)*(c/2) + f*(b/2)*(b/2) + a*(e/2)*(e/2) - 2*(e/2)*(b/2)*(c/2) - d*f*a)) / + (((e/2)*(e/2) - d*f) * (sqrt((d - f)*(d -f) + 4*(e/2)*(e/2)) - (d + f)))); + + double eB = sqrt((2*(d*(c/2)*(c/2) + f*(b/2)*(b/2) + a*(e/2)*(e/2) - 2*(e/2)*(b/2)*(c/2) - d*f*a)) / + (((e/2)*(e/2) - d*f) * (-sqrt((d - f)*(d -f) + 4*(e/2)*(e/2)) - (d + f)))); + + // Ensure that eA is always the semi-major axis, and eB the semi-minor + if(eB > eA) { + double tempVar = eB; + eB = eA; + eA = tempVar; + } + + // Calculate eccentricity + p_surfaceModelEccentricity = sqrt(eA*eA - eB*eB)/eA; + } + else { + // If the eccentricity cannot be computed, assume it to be 0 + p_surfaceModelEccentricity = 0; + } + + p_surfaceModelEccentricityRatio = sqrt(1.0 / (1.0 - p_surfaceModelEccentricity*p_surfaceModelEccentricity)); + + // Ensure that the eccentricity is less than or equal to the tolerance + if(p_surfaceModelEccentricity > p_surfaceModelEccentricityTolerance) { + p_status = SurfaceModelEccentricityRatioNotMet; + p_SurfaceModelEccentricityRatioNotMet++; + return false; + } + } + + // Check if the user wants to test against the average residual + if (p_testResidual) { + // Compare the z computed with z actuals + double meanAbsError = 0; + for (int i = 0; i < (int) lsq.Residuals().size(); i++) { + // Aggregate the absolute values of the residuals + meanAbsError += fabs(lsq.Residual(i)); + } + + // The average residual, or mean absolute error + meanAbsError = meanAbsError / lsq.Residuals().size(); + + p_surfaceModelAvgResidual = meanAbsError; + + // Ensure the average residual is within the tolerance + if (meanAbsError > p_surfaceModelResidualTolerance) { + p_status = SurfaceModelResidualToleranceNotMet; + p_SurfaceModelResidualToleranceNotMet++; + return false; + } + } + + // Compute the determinant + double det = 4.0*d*f - e*e; + if (det == 0.0){ + p_status = SurfaceModelSolutionInvalid; + p_SurfaceModelSolutionInvalid++; + return false; + } + + // Compute our chip position to sub-pixel accuracy + p_chipSample = (c*e - 2.0*b*f) / det; + p_chipLine = (b*e - 2.0*c*d) / det; + std::vector temp; + temp.push_back(p_chipSample); + temp.push_back(p_chipLine); + p_goodnessOfFit = lsq.Evaluate(temp); + return true; + } + + + /** + * This virtual method must return if the 1st fit is equal to or better + * than the second fit. + * + * @param fit1 1st goodness of fit + * @param fit2 2nd goodness of fit + * @return @b bool Indicates whether the first fit is as good or better than the + * second + */ + bool AutoReg::CompareFits (double fit1, double fit2) { + return(std::fabs(fit1-IdealFit()) <= std::fabs(fit2-IdealFit())); + } + + /** + * Returns true if the fit parameter is arbitrarily close to the ideal fit + * value. + * @param fit Fit value to be compared to the ideal fit + * @return @b bool Indicates whether the fit is ideal + */ + bool AutoReg::IsIdeal(double fit) { + return( std::fabs(IdealFit() - fit) < 0.00001 ); + } + + #if 0 + /** + * This returns an AutoRegItem for each measure. + * + */ + AutoRegItem AutoReg::RegisterInformation(){ + AutoRegItem item; + item.setSearchFile(p_searchChip.Filename()); + item.setPatternFile(p_patternChip.Filename()); + //item.setStatus(p_status); + item.setGoodnessOfFit(p_goodnessOfFit); + item.setEccentricity(p_surfaceModelEccentricity); + item.setZScoreOne(p_ZScore1); + item.setZScoreTwo(p_ZScore2); + + /*if(p_goodnessOfFit != Isis::Null)item.setGoodnessOfFit(p_goodnessOfFit); + if(p_surfaceModelEccentricity != Isis::Null) item.setEccentricity(p_surfaceModelEccentricity); + if(p_ZScore1 != Isis::Null)item.setZScoreOne(p_ZScore1); + if(p_ZScore2 != Isis::Null)item.setZScoreTwo(p_ZScore2);*/ + + // Set the autoRegItem's change in line/sample numbers. + if(p_status == Success) { + item.setDeltaSample(p_searchChip.TackSample() - p_searchChip.CubeSample()); + item.setDeltaLine(p_searchChip.TackLine() - p_searchChip.CubeLine()); + } else { + item.setDeltaSample(Isis::Null); + item.setDeltaLine(Isis::Null); + } + + return item; + } + #endif + + + /** + * This returns the cumulative registration statistics. That + * is, the Register() method accumulates statistics regard the + * errors each time is called. Invoking this method returns a + * PVL summary of those statisitics + * + * @author janderson (3/26/2009) + * + * @return @b Pvl + */ + Pvl AutoReg::RegistrationStatistics() { + Pvl pvl; + PvlGroup stats("AutoRegStatistics"); + stats += Isis::PvlKeyword("Total", p_Total); + stats += Isis::PvlKeyword("Successful", p_Success); + stats += Isis::PvlKeyword("Failure", p_Total - p_Success); + pvl.AddGroup(stats); + + PvlGroup grp("PatternChipFailures"); + grp += PvlKeyword("PatternNotEnoughValidData", p_PatternChipNotEnoughValidData); + grp += PvlKeyword("PatternZScoreNotMet", p_PatternZScoreNotMet); + pvl.AddGroup(grp); + + PvlGroup fit("FitChipFailures"); + fit += PvlKeyword("FitChipNoData", p_FitChipNoData); + fit += PvlKeyword("FitChipToleranceNotMet", p_FitChipToleranceNotMet); + pvl.AddGroup(fit); + + PvlGroup model("SurfaceModelFailures"); + model += PvlKeyword("SurfaceModelNotEnoughValidData", p_SurfaceModelNotEnoughValidData); + model += PvlKeyword("SurfaceModelSolutionInvalid", p_SurfaceModelSolutionInvalid); + model += PvlKeyword("SurfaceModelEccentricityRatioNotMet", p_SurfaceModelEccentricityRatioNotMet); + model += PvlKeyword("SurfaceModelDistanceInvalid", p_SurfaceModelDistanceInvalid); + model += PvlKeyword("SurfaceModelResidualToleranceNotMet", p_SurfaceModelResidualToleranceNotMet); + pvl.AddGroup(model); + + return (AlgorithmStatistics(pvl)); + } + + /** + * This virtual method must be written for adaptive pattern + * matching algorithms. Adaptive algorithms are assumed to + * compute the registration to sub-pixel accuracy and stay + * within the defined window. A status should be returned + * indicating success for subpixel computation or failure and + * the reason why via the enumeration, RegisterStatus. If the + * status is returned is success, the programmer needs to set + * the sub-pixel chip coordinates using the protected methods + * SetChipSample(), SetChipLine(). + * + * For those algorithms that need it, the best sample and line in the search + * chip is provided. This is either the initial tack sample and line in the + * search chip or it is the centered sample and line after the reduction + * algorithm is applied (KJB, 2009-08-26). + * + * @author janderson (6/2/2009) + * + * @param sChip Search chip + * @param pChip Pattern chip + * @param fChip Fit chip + * @param startSamp Defines the starting sample of the window + * the adaptive algorithm should remain inside + * this boundary. + * @param startLine Defines the starting line of the window + * the adaptive algorithm should remain inside + * this boundary. + * @param endSamp Defines the ending sample of the window + * the adaptive algorithm should remain inside + * this boundary. + * @param endLine Defines the ending line of the window + * the adaptive algorithm should remain inside + * this boundary. + * @param bestSamp Best sample + * @param bestLine Best line + * + * @return @b AutoReg::RegisterStatus Status of match + */ + AutoReg::RegisterStatus AutoReg::AdaptiveRegistration(Chip &sChip, + Chip &pChip, + Chip &fChip, + int startSamp, + int startLine, + int endSamp, + int endLine, + int bestSamp, + int bestLine) { + std::string msg = "Programmer needs to write their own virtual AdaptiveRegistration method"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + return Success; + } + + /** + * This function returns the keywords that this object was + * created from. + * + * @return @b PvlGroup The keywords this object used in + * initialization + */ + PvlGroup AutoReg::RegTemplate() { + PvlGroup reg("AutoRegistration"); + + PvlGroup &algo = p_template.FindGroup("Algorithm", Pvl::Traverse); + reg += PvlKeyword("Algorithm", algo["Name"][0]); + reg += PvlKeyword("Tolerance", algo["Tolerance"][0]); + if (algo.HasKeyword("SubpixelAccuracy")) { + reg += PvlKeyword("SubpixelAccuracy", algo["SubpixelAccuracy"][0]); + } + if (algo.HasKeyword("ReductionFactor")) { + reg += PvlKeyword("ReductionFactor", algo["ReductionFactor"][0]); + } + + PvlGroup &pchip = p_template.FindGroup("PatternChip",Pvl::Traverse); + reg += PvlKeyword("PatternSamples", pchip["Samples"][0]); + reg += PvlKeyword("PatternLines", pchip["Lines"][0]); + if (pchip.HasKeyword("ValidMinimum")) { + reg += PvlKeyword("PatternMinimum", pchip["ValidMinimum"][0]); + } + if (pchip.HasKeyword("ValidMaximum")) { + reg += PvlKeyword("PatternMaximum", pchip["ValidMaximum"][0]); + } + if (pchip.HasKeyword("MinimumZScore")) { + reg += PvlKeyword("MinimumZScore", pchip["MinimumZScore"][0]); + } + if (pchip.HasKeyword("ValidPercent")) { + SetPatternValidPercent((double)pchip["ValidPercent"]); + reg += PvlKeyword("ValidPercent", pchip["ValidPercent"][0]); + } + + PvlGroup &schip = p_template.FindGroup("SearchChip",Pvl::Traverse); + reg += PvlKeyword("SearchSamples", schip["Samples"][0]); + reg += PvlKeyword("SearchLines", schip["Lines"][0]); + if (schip.HasKeyword("ValidMinimum")) { + reg += PvlKeyword("SearchMinimum", schip["ValidMinimum"][0]); + } + if (schip.HasKeyword("ValidMaximum")) { + reg += PvlKeyword("SearchMaximum", schip["ValidMaximum"][0]); + } + + if(p_template.HasGroup("SurfaceModel")) { + PvlGroup &smodel = p_template.FindGroup("SurfaceModel", Pvl::Traverse); + if(smodel.HasKeyword("DistanceTolerance")) { + reg += PvlKeyword("DistanceTolerance", smodel["DistanceTolerance"][0]); + } + + if(smodel.HasKeyword("WindowSize")) { + reg += PvlKeyword("WindowSize", smodel["WindowSize"][0]); + } + + if(smodel.HasKeyword("EccentricityRatio")) { + reg += PvlKeyword("EccentricityRatio", smodel["EccentricityRatio"][0]); + } + + if(smodel.HasKeyword("ResidualTolerance")) { + reg += PvlKeyword("ResidualTolerance", smodel["ResidualTolerance"][0]); + } + } + + return reg; + } +} diff --git a/isis/src/base/objs/AutoReg/AutoReg.h b/isis/src/base/objs/AutoReg/AutoReg.h new file mode 100644 index 0000000000000000000000000000000000000000..976fb233c49ec2777eb7edadb9fba29b49156e57 --- /dev/null +++ b/isis/src/base/objs/AutoReg/AutoReg.h @@ -0,0 +1,449 @@ +/** + * @file + * $Revision: 1.27 $ + * $Date: 2010/06/15 19:37:51 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef AutoReg_h +#define AutoReg_h + + +#include +#include + +#include "Chip.h" +#include "Statistics.h" +//#include "AutoRegItem.h" + +namespace Isis { + /** + * @brief Auto Registration class + * + * Create AutoReg object. Because this is a pure virtual class you can + * not create an AutoReg class directly. Instead, see the AutoRegFactory + * class. + * + * @ingroup PatternMatching + * + * @see AutoRegFactory MaximumCorrelation MinimumDifference + * + * @internal + * @history 2006-01-11 Jacob Danton Added idealFit variable, option for sub-pixel + * accuracy, new CompareFit method, an arbitrarily + * chosen EPSILON value, a minimum standard deviation + * cutoff for the pattern chip, and created a unitTest + * @history 2006-02-13 Jacob Danton Added shrinking pattern and sampling option for the pattern chip. + * @history 2006-05-15 Jeff Anderson Moved ZScoreMinimum from + * Algorithm group to the + * PatternChip group + * @history 2006-05-22 Jacob Danton Added statistics reporting + * @history 2006-06-28 Brendan George Added copy constructor + * (private member function) + * @history 2008-06-23 Steven Lambright Fixed naming and some documentation + * fixes, added ZScores + * @history 2008-08-13 Noah Hilt Added two new optional arguments to AutoReg: WindowSize and + DistanceTolerance. These two arguments affect how AutoReg gathers and + * compares data for surface modeling and accuracy and should be contained + * inside the group "SurfaceModel" in the Pvl. Also changed the Pvl returned + * by RegistrationStatistics so that group names do not contain spaces and + * the Pvl only contains groups. + * @history 2008-11-18 Steven Koechle - Changed all keywords *NotEnoughData + * to *NotEnoughValidData + * @history 2009-03-17 Tracie Sucharski - Added method to return fit chip + * @history 2009-03-26 Jeff Anderson - Removed pattern chip + * reduction as it was broken, added skewness check + * for the fit chip, cleaned up the + * RegistrationStatistics method and added setters + * methods where appropriate + * @history 2009-03-30 Jeff Anderson - Modified code to reset + * parameters (goodness of fit and skewness) for + * successive calls to Register method. Also check + * to see if skewness is null. + * @history 2009-05-08 Stacy Alley - Took out the skewness + * test and added the ellipse eccentricity test in + * the ModelSurface method. Also added the 'reduce' + * option to speed up the pattern matching process. + * @history 2009-06-02 Stacy Alley - ModelSurface method now + * returns a bool instead of an int. The p_status + * is set within this method now. The Match method + * now takes another arg... fChip, passed in from + * Register. Also took out a redundant test, + * 'CompareFits' after the ModelSurface call. Also + * changed all the Chips in this header file from + * pointers to non-pointers. + * Saved all the reduced chips and have + * methods to return them so they can be views from + * Qnet. + * @history 2009-06-02 Jeff Anderson - Added + * AdaptiveRegistration virtual methods + * @history 2009-08-07 Travis Addair - Added functionality + * allowing it and all its sublcasses to return + * their auto registration template parameters + * @history 2009-08-25 Kris Becker - Correct calls to abs instead of the + * proper fabs. + * @history 2009-08-26 Kris Becker - Added chip parameters to Adaptive + * method to coorespond to the Match method. Also added best + * search sample and line parameters to Adaptive method. Also + * needed way to relate best fit value. + * @history 2009-09-02 Kris Becker - Set the default valid minimum and + * maximum values for pattern and search chips to + * Isis::ValidMinimum and Isis::ValidMaximum, respectively, as + * opposed to -DBL_MAX and _DBL_MAX. This modification has the + * net effect of excluding special pixels from a valid test. Also + * fix a bug whereby the extracted subsearch chip valid percent + * was divided by 100 - it instead should be passed in as is with + * the pattern chip test. + * @history 2009-09-07 Kris Becker - Set the goodness of fit + * when successful Adaptive algorithm. + * @history 2010-02-22 Tracie Sucharski - Added return + * methods for settings. + * @history 2010-03-16 Travis Addair - Added option to skip + * eccentricity testing, and made it so that the + * eccentricity is assumed to be 0 when it cannot + * otherwise be computed. + * @history 2010-03-18 Travis Addair - Added optional surface + * model validity test to ensure that the average + * residual of the least squares solution is within + * a tolerance. + * @history 2010-03-19 Travis Addair - Changed eccentricity + * and residual tests to be disabled by default. + * Including the keyword EccentricityRatio or + * ResidualTolerance in the Pvl that constructs an + * AutoReg object will enable the respective test. + * @history 2010-03-26 Travis Addair - Added methods + * Eccentricity() and AverageResidual() to retrieve + * the last computed value for those variables + * @history 2010-04-08 Travis Addair - Added methods + * EccentricityRatio() and + * EccentricityRatioTolerance() to retrieve an + * eccentricity value as the antecedent in an A:1 + * ratio. + * @history 2010-06-15 Jeannie Walldren - Modified code to read in an + * Interpolator type from the pvl and set the pattern and search + * chips' Read() methods to use this Interpolator type. Updated + * documentation and unitTest. + * + */ + class Pvl; + class AutoRegItem; + + class AutoReg { + public: + AutoReg (Pvl &pvl); + + virtual ~AutoReg(); + + /** + * Enumeration of the Register() method's return status. All of the + * enumerations describe a failure to register except "Success". These status + * values can be used to provide the user with more specific feedback on why + * registration did not succeed. + */ + enum RegisterStatus{ + Success, //!< Success + PatternChipNotEnoughValidData, //!< Not enough valid data in pattern chip + FitChipNoData, //!< Fit chip did not have any valid data + FitChipToleranceNotMet, //!< Goodness of fit tolerance not satisfied + SurfaceModelNotEnoughValidData, //!< Not enough points to fit a surface model for sub-pixel accuracy + SurfaceModelSolutionInvalid, //!< Could not model surface for sub-pixel accuracy + SurfaceModelDistanceInvalid, //!< Surface model moves registration more than one pixel + PatternZScoreNotMet, //!< Pattern data max or min does not pass the z-score test + SurfaceModelEccentricityRatioNotMet, //!< Ellipse eccentricity of the surface model not satisfied + SurfaceModelResidualToleranceNotMet, //!< Average residual of the surface model not satisfied + AdaptiveAlgorithmFailed //!< Error occured in Adaptive algorithm + }; + + //! Return pointer to pattern chip + inline Chip *PatternChip () { return &p_patternChip; }; + + //! Return pointer to search chip + inline Chip *SearchChip() { return &p_searchChip; }; + + //! Return pointer to fit chip + inline Chip *FitChip() { return &p_fitChip; }; + + //! Return pointer to reduced pattern chip + inline Chip *ReducedPatternChip() { return &p_reducedPatternChip; }; + + //! Return pointer to reduced search chip + inline Chip *ReducedSearchChip() { return &p_reducedSearchChip; }; + + //! Return pointer to reduced fix chip + inline Chip *ReducedFitChip() { return &p_reducedFitChip; }; + + void SetSubPixelAccuracy(bool on); + void SetPatternValidPercent(const double percent); + void SetTolerance(double tolerance); + void SetChipInterpolator(const string interpolator); + void SetSurfaceModelWindowSize (int size); + void SetSurfaceModelDistanceTolerance (double distance); + void SetReductionFactor (int reductionFactor); + void SetPatternZScoreMinimum(double minimum); + void SetSurfaceModelEccentricityRatio(double ratioTolerance); + void SetSurfaceModelResidualTolerance(double residualTolerance); + + /** + * Determine if eccentricity tests should be performed during registration + * @param test Indicates whether to perform test + */ + inline void SetEccentricityTesting(bool test) { p_testEccentricity = test; }; + + /** + * Determine if residual tests should be performed during registration + * @param test Indicates whether to perform test + */ + inline void SetResidualTesting(bool test) { p_testResidual = test; }; + + //! Return pattern valid percent + double PatternValidPercent() const { return p_patternValidPercent; }; + + //! Return match algorithm tolerance + inline double Tolerance () const { return p_tolerance; }; + + //! Return distance tolerance + double DistanceTolerance () const { return p_distanceTolerance; }; + + //! Return eccentricity tolerance represented as the A component in an A;1 ratio + double EccentricityRatioTolerance () const { return p_surfaceModelEccentricityRatioTolerance; }; + + //! Return residual tolerance + double ResidualTolerance () const { return p_surfaceModelResidualTolerance; }; + + /** + * Return the distance point moved + * + * @param sampDistance Sample movement + * @param lineDistance Line movement + */ + void Distance(double &sampDistance,double &lineDistance) { + sampDistance = p_sampMovement; + lineDistance = p_lineMovement; + } + + AutoReg::RegisterStatus Register(); + + //! Return the goodness of fit of the match algorithm + inline double GoodnessOfFit () const { return p_goodnessOfFit; }; + + //! Return the eccentricity of the surface model, null if not calculated + inline double Eccentricity() const { return p_surfaceModelEccentricity; }; + + //! Return the eccentricity of the surface model as the A component of an of an A:1 ratio + inline double EccentricityRatio() const { return p_surfaceModelEccentricityRatio; }; + + //! Return the average residual of the surface model, null if not calculated + inline double AverageResidual() const { return p_surfaceModelAvgResidual; }; + + inline bool IsIdeal(double fit); + + //! Return the search chip sample that best matched + inline double ChipSample() const { return p_chipSample; }; + + //! Return the search chip line that best matched + inline double ChipLine() const { return p_chipLine; }; + + //! Return the search chip cube sample that best matched + inline double CubeSample() const { return p_cubeSample; }; + + //! Return the search chip cube line that best matched + inline double CubeLine() const { return p_cubeLine; }; + + //! Return minimumPatternZScore + double MinimumZScore() const { return p_minimumPatternZScore; }; + + /** + * Return the ZScores of the pattern chip + * + * @param score1 First Z Score + * @param score2 Second Z Score + */ + void ZScores(double &score1, double &score2) const { + score1=p_ZScore1; + score2=p_ZScore2; + } + + //! Return eccentricity tolerance + double EccentricityTolerance() const { + return p_surfaceModelEccentricityTolerance; + }; + + Pvl RegistrationStatistics(); + + /** + * Return if the algorithm is an adaptive pattern matching + * technique + */ + virtual bool IsAdaptive() { return false; } + + /** + * Returns the name of the algorithm. + * + * + * @return std::string + */ + virtual std::string AlgorithmName() const = 0; + + PvlGroup RegTemplate(); + + protected: + /** + * Sets the search chip subpixel sample that matches the pattern + * tack sample. + * + * + * @param sample Value to set for search chip subpixel sample + */ + inline void SetChipSample(double sample){ p_chipSample = sample; }; + + /** + * Sets the search chip subpixel line that matches the pattern + * tack line. + * + * + * @param line Value to set for search chip subpixel line + */ + inline void SetChipLine(double line){ p_chipLine = line; }; + + /** + * Sets the goodness of fit for adaptive algorithms + * + * @param fit Fit value to set + */ + inline void SetGoodnessOfFit(double fit){ p_bestFit = fit; }; + + virtual AutoReg::RegisterStatus AdaptiveRegistration(Chip &sChip, + Chip &pChip, + Chip &fChip, + int startSamp, + int startLine, + int endSamp, + int endLine, + int bestSamp, + int bestLine); + void Parse(Pvl &pvl); + virtual bool CompareFits(double fit1, double fit2); + bool ModelSurface(std::vector &x, std::vector &y, + std::vector &z); + Chip Reduce(Chip &chip, int reductionFactor); + + /** + * Returns the ideal (perfect) fit that could be returned by the + * MatchAlgorithm. + * + * + * @return double + */ + virtual double IdealFit() const = 0; + + /** + * Given two identically sized chips return a double that + * indicates how well they match. For example, a correlation + * match algorithm would return a correlation coefficient + * ranging from -1 to 1. + * + * + * @param pattern + * @param subsearch + * + * @return double + */ + virtual double MatchAlgorithm (Chip &pattern, Chip &subsearch) = 0; + + PvlObject p_template; //! +#include +#include "AutoReg.h" +#include "AutoRegFactory.h" +#include "Chip.h" +#include "Cube.h" +#include "Preference.h" +#include "Pvl.h" +#include "PvlGroup.h" + +using namespace std; +using namespace Isis; + +AutoReg *p_ar; + +int main () { + Isis::Preference::Preferences(true); + void Doit(Isis::PvlObject &obj); + void DoRegister(); + + cout << "Unit test for Isis::AutoReg ..." << endl << endl; + + cout << "---------------------------------" << endl; + cout << "Test for missing Algorithm Group" << endl; + cout << "---------------------------------" << endl; + PvlObject obj("AutoRegistration"); + Doit(obj); + cout << endl; + + cout << "------------------------------" << endl; + cout << "Test for missing Name Keyword" << endl; + cout << "------------------------------" << endl; + obj.AddGroup(Isis::PvlGroup("Algorithm")); + Isis::PvlGroup &mg = obj.FindGroup("Algorithm"); + Doit(obj); + cout << endl; + + cout << "------------------------------" << endl; + cout << "Test for invalid Name Keyword" << endl; + cout << "------------------------------" << endl; + mg += Isis::PvlKeyword("Name", "MaxCor"); + Doit(obj); + cout << endl; + + cout << "-----------------------------------" << endl; + cout << "Test for missing Tolerance Keyword" << endl; + cout << "-----------------------------------" << endl; + mg["Name"] = "MaximumCorrelation"; + Doit(obj); + cout << endl; + + cout << "-----------------------------------" << endl; + cout << "Test for missing PatternChip Group" << endl; + cout << "-----------------------------------" << endl; + mg += Isis::PvlKeyword("Tolerance",0.3); + Doit(obj); + cout << endl; + + cout << "-----------------------------------" << endl; + cout << "Test for wrong ChipInterpolator Keyword value" << endl; + cout << "-----------------------------------" << endl; + mg += Isis::PvlKeyword("ChipInterpolator","None"); + Doit(obj); + mg["ChipInterpolator"] = "BiLinearType"; + cout << endl; + + obj.AddGroup(Isis::PvlGroup("PatternChip")); + Isis::PvlGroup &pc = obj.FindGroup("PatternChip"); + pc += Isis::PvlKeyword("Lines", 90); + pc += Isis::PvlKeyword("Samples", 90); + + cout << "-------------------------------" << endl; + cout << "Test for missing Lines Keyword" << endl; + cout << "-------------------------------" << endl; + pc.DeleteKeyword("Lines"); + Doit(obj); + cout << endl; + + cout << "---------------------------------" << endl; + cout << "Test for missing Samples Keyword" << endl; + cout << "---------------------------------" << endl; + pc += Isis::PvlKeyword("Lines", 90); + pc.DeleteKeyword("Samples"); + Doit(obj); + cout << endl; + + cout << "---------------------------------" << endl; + cout << "Test for invalid Lines Keyword" << endl; + cout << "---------------------------------" << endl; + pc += Isis::PvlKeyword("Samples", 90); + pc["Lines"] = -90; + Doit(obj); + cout << endl; + + cout << "---------------------------------" << endl; + cout << "Test for invalid Samples Keyword" << endl; + cout << "---------------------------------" << endl; + pc["Lines"] = 90; + pc["Samples"] = -90; + Doit(obj); + cout << endl; + + cout << "----------------------------------" << endl; + cout << "Test for missing SearchChip group" << endl; + cout << "----------------------------------" << endl; + pc["Samples"] = 90; + Doit(obj); + cout << endl; + + obj.AddGroup(Isis::PvlGroup("SearchChip")); + Isis::PvlGroup &sc = obj.FindGroup("SearchChip"); + sc += Isis::PvlKeyword("Lines", 150); + sc += Isis::PvlKeyword("Samples", 150); + + cout << "-------------------------------" << endl; + cout << "Test for missing Lines Keyword" << endl; + cout << "-------------------------------" << endl; + sc.DeleteKeyword("Lines"); + Doit(obj); + cout << endl; + + cout << "---------------------------------" << endl; + cout << "Test for missing Samples Keyword" << endl; + cout << "---------------------------------" << endl; + sc += Isis::PvlKeyword("Lines", 150); + sc.DeleteKeyword("Samples"); + Doit(obj); + cout << endl; + + sc += Isis::PvlKeyword("Samples", 150); + Doit(obj); + cout << endl; + + cout << "-------------------------------------------" << endl; + cout << "Testing Error = PatternNotEnoughValidData" << endl; + cout << "-------------------------------------------" << endl; + p_ar->PatternChip()->SetValidRange(0.009, 0.01); + p_ar->SetPatternValidPercent(100); + DoRegister(); + //Reset the range and the valid percent + p_ar->PatternChip()->SetValidRange(0, 1); + p_ar->SetPatternValidPercent(50); + Doit(obj); + + cout << "\n------------------------------------" << endl; + cout << "Testing Error = PatternZScoreNotMet" << endl; + cout << "------------------------------------" << endl; + p_ar->SetPatternZScoreMinimum(9.0); + DoRegister(); + //Reset the Pattern ZScore Minimum + p_ar->SetPatternZScoreMinimum(1.0); + Doit(obj); + + cout << "\n------------------------------" << endl; + cout << "Testing Error = FitChipNoData" << endl; + cout << "------------------------------" << endl; + for (int line=1; line<=p_ar->SearchChip()->Lines(); line++) { + for (int samp=1; samp<=p_ar->SearchChip()->Samples(); samp++) { + p_ar->SearchChip()->SetValue(samp,line,Isis::Null); + } + } + DoRegister(); + Doit(obj); + + cout << "\n----------------------------------------" << endl; + cout << "Testing Error = FitChipToleranceNotMet" << endl; + cout << "----------------------------------------" << endl; + p_ar->SetTolerance(0.9); + DoRegister(); + //Reset the Tolerance + p_ar->SetTolerance(0.3); + Doit(obj); + + cout << "\n-----------------------------------------------" << endl; + cout << "Testing Error = SurfaceModelNotEnoughValidData" << endl; + cout << "-----------------------------------------------" << endl; + p_ar->SetSurfaceModelWindowSize(39); + DoRegister(); + //Reset the surface model Window size + p_ar->SetSurfaceModelWindowSize(5); + Doit(obj); + + cout << "\n----------------------------------------------------" << endl; + cout << "Testing Error = SurfaceModelEccentricityRatioNotMet" << endl; + cout << "----------------------------------------------------" << endl; + p_ar->SetSurfaceModelEccentricityRatio(1); + DoRegister(); + //Reset the surface model Eccentricity ratio + p_ar->SetSurfaceModelEccentricityRatio(2); + Doit(obj); + + cout << "\n----------------------------------------------------" << endl; + cout << "Testing Error = SurfaceModelResidualToleranceNotMet" << endl; + cout << "----------------------------------------------------" << endl; + p_ar->SetSurfaceModelResidualTolerance(0.01); + DoRegister(); + //Reset the surface model residual tolerance + p_ar->SetSurfaceModelResidualTolerance(0.1); + Doit(obj); + + cout << "\n---------------------------------------------" << endl; + cout << "Testing Error = SurfaceModelDistanceInvalid" << endl; + cout << "---------------------------------------------" << endl; + p_ar->SetSurfaceModelDistanceTolerance(.01); + DoRegister(); + //Reset the surface model distance tolerance + p_ar->SetSurfaceModelDistanceTolerance(1.5); + Doit(obj); + + cout << "\n----------------" << endl; + cout << "Testing Success" << endl; + cout << "----------------" << endl; + DoRegister(); + + delete p_ar; + return 0; + +} + +void Doit (Isis::PvlObject &obj) { + try { + Pvl lab; + lab.AddObject(obj); + p_ar = AutoRegFactory::Create(lab); + Cube c; + c.Open("$base/testData/search.cub"); + p_ar->SearchChip()->TackCube(75.0,75.0); + p_ar->SearchChip()->Load(c); + Cube d; + d.Open("$base/testData/pattern.cub"); + p_ar->PatternChip()->TackCube(45.0,45.0); + p_ar->PatternChip()->Load(d); + p_ar->SetEccentricityTesting(true); + p_ar->SetResidualTesting(true); + } + catch (Isis::iException &error) { + error.Clear(); + iString err = error.what(); + + // We need to get rid of the contents of the second [] on each line to ensure + // file paths do not persist. + iString thisLine; + iString formattedErr; + + while((thisLine = err.Token("\n")) != "") { + formattedErr += thisLine.Token("["); + + if(!thisLine.empty()) { + formattedErr += "[" + thisLine.Token("]") + "]"; + } + + if(!thisLine.empty() && thisLine.find('[') != string::npos) { + formattedErr += thisLine.Token("[") + "[]"; + thisLine.Token("]"); + formattedErr += thisLine; + } + else { + formattedErr += thisLine; + } + + formattedErr += "\n"; + } + + + std::cerr << formattedErr; + } +} + +void DoRegister(){ + AutoReg::RegisterStatus status = p_ar->Register(); + if(status == AutoReg::Success) { + std::cout << "Position = " << p_ar->CubeSample() << " " << p_ar->CubeLine() << std::endl; + } + Pvl regstats = p_ar->RegistrationStatistics(); + std::cout << regstats << std::endl; +} diff --git a/isis/src/base/objs/AutoRegFactory/AutoRegFactory.cpp b/isis/src/base/objs/AutoRegFactory/AutoRegFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..123bd9912ffc752ebc37e6fe2fa6a7f5f9e0f65c --- /dev/null +++ b/isis/src/base/objs/AutoRegFactory/AutoRegFactory.cpp @@ -0,0 +1,81 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/19 23:35:38 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "AutoRegFactory.h" +#include "AutoReg.h" +#include "Plugin.h" +#include "iException.h" +#include "Filename.h" + +namespace Isis { + /** + * Create an AutoReg object using a PVL specification. + * An example of the PVL required for this is: + * + * @code + * Object = AutoRegistration + * Group = Algorithm + * Name = MaximumCorrelation + * Tolerance = 0.7 + * EndGroup + * + * Group = PatternChip + * Samples = 21 + * Lines = 21 + * EndGroup + * + * Group = SearchChip + * Samples = 51 + * Lines = 51 + * EndGroup + * EndObject + * @endcode + * + * There are many other options that can be set via the pvl and are + * described in other documentation (see below). + * + * @param pvl The pvl object containing the specification + * + * @see automaticRegistration.doc + **/ + AutoReg *AutoRegFactory::Create(Pvl &pvl) { + // Get the algorithm name to create + PvlGroup &algo = pvl.FindGroup("Algorithm",Pvl::Traverse); + std::string algorithm = algo["Name"]; + + // Open the factory plugin file + Plugin p; + Filename f("AutoReg.plugin"); + if (f.Exists()) { + p.Read("AutoReg.plugin"); + } + else { + p.Read("$ISISROOT/lib/AutoReg.plugin"); + } + + // Get the algorithm specific plugin and return it + AutoReg * (*plugin) (Pvl &pvl); + plugin = (AutoReg * (*)(Pvl &pvl)) p.GetPlugin(algorithm); + return (*plugin)(pvl); + } +} // end namespace isis diff --git a/isis/src/base/objs/AutoRegFactory/AutoRegFactory.h b/isis/src/base/objs/AutoRegFactory/AutoRegFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..2a7a2ddc076655f0be79ee9493bfc2a14415eea1 --- /dev/null +++ b/isis/src/base/objs/AutoRegFactory/AutoRegFactory.h @@ -0,0 +1,83 @@ +#ifndef AutoRegFactory_h +#define AutoRegFactory_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/06/19 23:35:38 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +namespace Isis { + class Pvl; + class AutoReg; + + /** + * This class is used to create AutoReg objects. Typically applications which + * need use autoregistration would like to use different techniques such as + * MaximumCorrelation or MinimumDifference. If this factory is given a Pvl + * object which contains a AutoReg definition it will create that specific + * instance of the class. For example, + * + * @code + * Object = AutoReg + * Group = Algorithm + * Name = MinimumDifference + * ... + * EndGroup + * ... + * EndObject + * End + * @endcode + * + * Will create a MinimumDifference object (which is derived from AutoReg). + * The simplest way to create an AutoReg class is to use the static Create + * method + * + * @code + * Pvl p("myautoreg.pvl"); + * AutoReg *ar = AutoRegFactory::Create(p); + * @endcode + * + * @ingroup PatternMatching + * + * @author 2005-05-04 Jeff Anderson + * + * @internal + * @history 2006-03-27 Jacob Danton Added unitTest + * @history 2008-06-18 Christopher Austin Fixed documentation errors + * @history 2008-06-19 Steven Lambright Fixed memory leak + */ + class AutoRegFactory { + public: + static AutoReg *Create(Pvl &pvl); + + private: + /** + * Constructor (its private so you can't use it). Use the Create Method + * instead. + */ + AutoRegFactory() {}; + + //! Destroys the AutoRegFactory + ~AutoRegFactory() {}; + }; +}; + +#endif diff --git a/isis/src/base/objs/AutoRegFactory/AutoRegFactory.truth b/isis/src/base/objs/AutoRegFactory/AutoRegFactory.truth new file mode 100644 index 0000000000000000000000000000000000000000..049fd031d45a2f90b1dd522d985de3252d7ef5d0 --- /dev/null +++ b/isis/src/base/objs/AutoRegFactory/AutoRegFactory.truth @@ -0,0 +1 @@ +All testing differed to AutoReg and it's extended classes. diff --git a/isis/src/base/objs/AutoRegFactory/Makefile b/isis/src/base/objs/AutoRegFactory/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..152c9c627d4566301a683fdc10ab6224dfc168e3 --- /dev/null +++ b/isis/src/base/objs/AutoRegFactory/Makefile @@ -0,0 +1,5 @@ +INCS = AutoRegFactory.h +SRCS = AutoRegFactory.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/AutoRegFactory/unitTest.cpp b/isis/src/base/objs/AutoRegFactory/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d8d749aeff1abb2d0ca92bf416eb27af3c0e3a2 --- /dev/null +++ b/isis/src/base/objs/AutoRegFactory/unitTest.cpp @@ -0,0 +1,12 @@ +#include +#include +#include "Preference.h" + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + cout << "All testing differed to AutoReg and it's extended classes." << endl; + + return 0; +} diff --git a/isis/src/base/objs/BandManager/BandManager.cpp b/isis/src/base/objs/BandManager/BandManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..574d70cab1614e366b47a3ec8adf76f96a6ea2ff --- /dev/null +++ b/isis/src/base/objs/BandManager/BandManager.cpp @@ -0,0 +1,72 @@ + + +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/18 19:05:48 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "BandManager.h" + +using namespace std; +namespace Isis { + + /** + * Constructs a BandManager object + * + * @param cube The cube this buffer manager will be associated with. + * + * @param reverse Modifies the order of progression BandManager + * takes through the cube. By default, progresses + * samples first then lines. If reverse = true, then + * the buffer progresses lines first, then samples. + */ + + BandManager::BandManager(const Isis::Cube &cube, const bool reverse) : + Isis::BufferManager(cube.Samples(),cube.Lines(), + cube.Bands(),1,1,cube.Bands(), + cube.PixelType(), reverse ) { + } + + /** + * Positions the buffer at the requested line and returns a status indicator + * if the set was succesful or not + * + * @param sample The sample number within a band (1-based). + * @param line The line number within a band (1-based). Defaults to 1 + * + * @return bool Status indicator of the set being successful or not + */ + + bool BandManager::SetBand (const int sample, const int line) { + if (sample < 1) { + string message = "Invalid value for argument [sample]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + if (line < 1) { + string message = "Invalid value for argument [line]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + int map = (line - 1) * MaxBands() + sample - 1; + return setpos(map); + } + +} // end namespace isis diff --git a/isis/src/base/objs/BandManager/BandManager.h b/isis/src/base/objs/BandManager/BandManager.h new file mode 100644 index 0000000000000000000000000000000000000000..1f70dc59800660943690b72c4a33d746102a6864 --- /dev/null +++ b/isis/src/base/objs/BandManager/BandManager.h @@ -0,0 +1,62 @@ +#ifndef BandManager_h +#define BandManager_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/18 19:05:48 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "BufferManager.h" +#include "Cube.h" + +namespace Isis { +/** + * @brief Buffer manager, for moving through a cube in bands + * + * This class is used as a manager for moving through a cube one + * band buffer at a time. A band buffer is defined as a one + * dimensional sub-area of a cube. That is, the number of + * bands by 1 sample by 1 line (1,1,nb). The manager moves this + * (1,1,nb) shape through the cube sequentially accessing all + * the band buffers in the first sample before proceeding to the + * second line. + * + * @ingroup LowLevelCubeIO + * + * @author 2007-12-06 Christopher Austin + * + * @internal + * @history 2008-06-18 Christopher Austin - Fixed documentation errors + * + */ + class BandManager : public Isis::BufferManager { + + public: + // Constructors and Destructors + BandManager(const Isis::Cube &cube, const bool reverse=false); + + //! Destroys the SampleManager object + ~BandManager() {}; + + bool SetBand(const int sample, const int line=1 ); + }; +}; + +#endif + diff --git a/isis/src/base/objs/BandManager/BandManager.truth b/isis/src/base/objs/BandManager/BandManager.truth new file mode 100644 index 0000000000000000000000000000000000000000..45938e969062407e69084fb433b3797b7fd62a35 --- /dev/null +++ b/isis/src/base/objs/BandManager/BandManager.truth @@ -0,0 +1,31768 @@ +Buffer Size: 1 1 2 + + Current sample, line, band is: 1 1 1 + Current sample, line, band is: 2 1 1 + Current sample, line, band is: 3 1 1 + Current sample, line, band is: 4 1 1 + Current sample, line, band is: 5 1 1 + Current sample, line, band is: 6 1 1 + Current sample, line, band is: 7 1 1 + Current sample, line, band is: 8 1 1 + Current sample, line, band is: 9 1 1 + Current sample, line, band is: 10 1 1 + Current sample, line, band is: 11 1 1 + Current sample, line, band is: 12 1 1 + Current sample, line, band is: 13 1 1 + Current sample, line, band is: 14 1 1 + Current sample, line, band is: 15 1 1 + Current sample, line, band is: 16 1 1 + Current sample, line, band is: 17 1 1 + Current sample, line, band is: 18 1 1 + Current sample, line, band is: 19 1 1 + Current sample, line, band is: 20 1 1 + Current sample, line, band is: 21 1 1 + Current sample, line, band is: 22 1 1 + Current sample, line, band is: 23 1 1 + Current sample, line, band is: 24 1 1 + Current sample, line, band is: 25 1 1 + Current sample, line, band is: 26 1 1 + Current sample, line, band is: 27 1 1 + Current sample, line, band is: 28 1 1 + Current sample, line, band is: 29 1 1 + Current sample, line, band is: 30 1 1 + Current sample, line, band is: 31 1 1 + Current sample, line, band is: 32 1 1 + Current sample, line, band is: 33 1 1 + Current sample, line, band is: 34 1 1 + Current sample, line, band is: 35 1 1 + Current sample, line, band is: 36 1 1 + Current sample, line, band is: 37 1 1 + Current sample, line, band is: 38 1 1 + Current sample, line, band is: 39 1 1 + Current sample, line, band is: 40 1 1 + Current sample, line, band is: 41 1 1 + Current sample, line, band is: 42 1 1 + Current sample, line, band is: 43 1 1 + Current sample, line, band is: 44 1 1 + Current sample, line, band is: 45 1 1 + Current sample, line, band is: 46 1 1 + Current sample, line, band is: 47 1 1 + Current sample, line, band is: 48 1 1 + Current sample, line, band is: 49 1 1 + Current sample, line, band is: 50 1 1 + Current sample, line, band is: 51 1 1 + Current sample, line, band is: 52 1 1 + Current sample, line, band is: 53 1 1 + Current sample, line, band is: 54 1 1 + Current sample, line, band is: 55 1 1 + Current sample, line, band is: 56 1 1 + Current sample, line, band is: 57 1 1 + Current sample, line, band is: 58 1 1 + Current sample, line, band is: 59 1 1 + Current sample, line, band is: 60 1 1 + Current sample, line, band is: 61 1 1 + Current sample, line, band is: 62 1 1 + Current sample, line, band is: 63 1 1 + Current sample, line, band is: 64 1 1 + Current sample, line, band is: 65 1 1 + Current sample, line, band is: 66 1 1 + Current sample, line, band is: 67 1 1 + Current sample, line, band is: 68 1 1 + Current sample, line, band is: 69 1 1 + Current sample, line, band is: 70 1 1 + Current sample, line, band is: 71 1 1 + Current sample, line, band is: 72 1 1 + Current sample, line, band is: 73 1 1 + Current sample, line, band is: 74 1 1 + Current sample, line, band is: 75 1 1 + Current sample, line, band is: 76 1 1 + Current sample, line, band is: 77 1 1 + Current sample, line, band is: 78 1 1 + Current sample, line, band is: 79 1 1 + Current sample, line, band is: 80 1 1 + Current sample, line, band is: 81 1 1 + Current sample, line, band is: 82 1 1 + Current sample, line, band is: 83 1 1 + Current sample, line, band is: 84 1 1 + Current sample, line, band is: 85 1 1 + Current sample, line, band is: 86 1 1 + Current sample, line, band is: 87 1 1 + Current sample, line, band is: 88 1 1 + Current sample, line, band is: 89 1 1 + Current sample, line, band is: 90 1 1 + Current sample, line, band is: 91 1 1 + Current sample, line, band is: 92 1 1 + Current sample, line, band is: 93 1 1 + Current sample, line, band is: 94 1 1 + Current sample, line, band is: 95 1 1 + Current sample, line, band is: 96 1 1 + Current sample, line, band is: 97 1 1 + Current sample, line, band is: 98 1 1 + Current sample, line, band is: 99 1 1 + Current sample, line, band is: 100 1 1 + Current sample, line, band is: 101 1 1 + Current sample, line, band is: 102 1 1 + Current sample, line, band is: 103 1 1 + Current sample, line, band is: 104 1 1 + Current sample, line, band is: 105 1 1 + Current sample, line, band is: 106 1 1 + Current sample, line, band is: 107 1 1 + Current sample, line, band is: 108 1 1 + Current sample, line, band is: 109 1 1 + Current sample, line, band is: 110 1 1 + Current sample, line, band is: 111 1 1 + Current sample, line, band is: 112 1 1 + Current sample, line, band is: 113 1 1 + Current sample, line, band is: 114 1 1 + Current sample, line, band is: 115 1 1 + Current sample, line, band is: 116 1 1 + Current sample, line, band is: 117 1 1 + Current sample, line, band is: 118 1 1 + Current sample, line, band is: 119 1 1 + Current sample, line, band is: 120 1 1 + Current sample, line, band is: 121 1 1 + Current sample, line, band is: 122 1 1 + Current sample, line, band is: 123 1 1 + Current sample, line, band is: 124 1 1 + Current sample, line, band is: 125 1 1 + Current sample, line, band is: 126 1 1 + Current sample, line, band is: 1 2 1 + Current sample, line, band is: 2 2 1 + Current sample, line, band is: 3 2 1 + Current sample, line, band is: 4 2 1 + Current sample, line, band is: 5 2 1 + Current sample, line, band is: 6 2 1 + Current sample, line, band is: 7 2 1 + Current sample, line, band is: 8 2 1 + Current sample, line, band is: 9 2 1 + Current sample, line, band is: 10 2 1 + Current sample, line, band is: 11 2 1 + Current sample, line, band is: 12 2 1 + Current sample, line, band is: 13 2 1 + Current sample, line, band is: 14 2 1 + Current sample, line, band is: 15 2 1 + Current sample, line, band is: 16 2 1 + Current sample, line, band is: 17 2 1 + Current sample, line, band is: 18 2 1 + Current sample, line, band is: 19 2 1 + Current sample, line, band is: 20 2 1 + Current sample, line, band is: 21 2 1 + Current sample, line, band is: 22 2 1 + Current sample, line, band is: 23 2 1 + Current sample, line, band is: 24 2 1 + Current sample, line, band is: 25 2 1 + Current sample, line, band is: 26 2 1 + Current sample, line, band is: 27 2 1 + Current sample, line, band is: 28 2 1 + Current sample, line, band is: 29 2 1 + Current sample, line, band is: 30 2 1 + Current sample, line, band is: 31 2 1 + Current sample, line, band is: 32 2 1 + Current sample, line, band is: 33 2 1 + Current sample, line, band is: 34 2 1 + Current sample, line, band is: 35 2 1 + Current sample, line, band is: 36 2 1 + Current sample, line, band is: 37 2 1 + Current sample, line, band is: 38 2 1 + Current sample, line, band is: 39 2 1 + Current sample, line, band is: 40 2 1 + Current sample, line, band is: 41 2 1 + Current sample, line, band is: 42 2 1 + Current sample, line, band is: 43 2 1 + Current sample, line, band is: 44 2 1 + Current sample, line, band is: 45 2 1 + Current sample, line, band is: 46 2 1 + Current sample, line, band is: 47 2 1 + Current sample, line, band is: 48 2 1 + Current sample, line, band is: 49 2 1 + Current sample, line, band is: 50 2 1 + Current sample, line, band is: 51 2 1 + Current sample, line, band is: 52 2 1 + Current sample, line, band is: 53 2 1 + Current sample, line, band is: 54 2 1 + Current sample, line, band is: 55 2 1 + Current sample, line, band is: 56 2 1 + Current sample, line, band is: 57 2 1 + Current sample, line, band is: 58 2 1 + Current sample, line, band is: 59 2 1 + Current sample, line, band is: 60 2 1 + Current sample, line, band is: 61 2 1 + Current sample, line, band is: 62 2 1 + Current sample, line, band is: 63 2 1 + Current sample, line, band is: 64 2 1 + Current sample, line, band is: 65 2 1 + Current sample, line, band is: 66 2 1 + Current sample, line, band is: 67 2 1 + Current sample, line, band is: 68 2 1 + Current sample, line, band is: 69 2 1 + Current sample, line, band is: 70 2 1 + Current sample, line, band is: 71 2 1 + Current sample, line, band is: 72 2 1 + Current sample, line, band is: 73 2 1 + Current sample, line, band is: 74 2 1 + Current sample, line, band is: 75 2 1 + Current sample, line, band is: 76 2 1 + Current sample, line, band is: 77 2 1 + Current sample, line, band is: 78 2 1 + Current sample, line, band is: 79 2 1 + Current sample, line, band is: 80 2 1 + Current sample, line, band is: 81 2 1 + Current sample, line, band is: 82 2 1 + Current sample, line, band is: 83 2 1 + Current sample, line, band is: 84 2 1 + Current sample, line, band is: 85 2 1 + Current sample, line, band is: 86 2 1 + Current sample, line, band is: 87 2 1 + Current sample, line, band is: 88 2 1 + Current sample, line, band is: 89 2 1 + Current sample, line, band is: 90 2 1 + Current sample, line, band is: 91 2 1 + Current sample, line, band is: 92 2 1 + Current sample, line, band is: 93 2 1 + Current sample, line, band is: 94 2 1 + Current sample, line, band is: 95 2 1 + Current sample, line, band is: 96 2 1 + Current sample, line, band is: 97 2 1 + Current sample, line, band is: 98 2 1 + Current sample, line, band is: 99 2 1 + Current sample, line, band is: 100 2 1 + Current sample, line, band is: 101 2 1 + Current sample, line, band is: 102 2 1 + Current sample, line, band is: 103 2 1 + Current sample, line, band is: 104 2 1 + Current sample, line, band is: 105 2 1 + Current sample, line, band is: 106 2 1 + Current sample, line, band is: 107 2 1 + Current sample, line, band is: 108 2 1 + Current sample, line, band is: 109 2 1 + Current sample, line, band is: 110 2 1 + Current sample, line, band is: 111 2 1 + Current sample, line, band is: 112 2 1 + Current sample, line, band is: 113 2 1 + Current sample, line, band is: 114 2 1 + Current sample, line, band is: 115 2 1 + Current sample, line, band is: 116 2 1 + Current sample, line, band is: 117 2 1 + Current sample, line, band is: 118 2 1 + Current sample, line, band is: 119 2 1 + Current sample, line, band is: 120 2 1 + Current sample, line, band is: 121 2 1 + Current sample, line, band is: 122 2 1 + Current sample, line, band is: 123 2 1 + Current sample, line, band is: 124 2 1 + Current sample, line, band is: 125 2 1 + Current sample, line, band is: 126 2 1 + Current sample, line, band is: 1 3 1 + Current sample, line, band is: 2 3 1 + Current sample, line, band is: 3 3 1 + Current sample, line, band is: 4 3 1 + Current sample, line, band is: 5 3 1 + Current sample, line, band is: 6 3 1 + Current sample, line, band is: 7 3 1 + Current sample, line, band is: 8 3 1 + Current sample, line, band is: 9 3 1 + Current sample, line, band is: 10 3 1 + Current sample, line, band is: 11 3 1 + Current sample, line, band is: 12 3 1 + Current sample, line, band is: 13 3 1 + Current sample, line, band is: 14 3 1 + Current sample, line, band is: 15 3 1 + Current sample, line, band is: 16 3 1 + Current sample, line, band is: 17 3 1 + Current sample, line, band is: 18 3 1 + Current sample, line, band is: 19 3 1 + Current sample, line, band is: 20 3 1 + Current sample, line, band is: 21 3 1 + Current sample, line, band is: 22 3 1 + Current sample, line, band is: 23 3 1 + Current sample, line, band is: 24 3 1 + Current sample, line, band is: 25 3 1 + Current sample, line, band is: 26 3 1 + Current sample, line, band is: 27 3 1 + Current sample, line, band is: 28 3 1 + Current sample, line, band is: 29 3 1 + Current sample, line, band is: 30 3 1 + Current sample, line, band is: 31 3 1 + Current sample, line, band is: 32 3 1 + Current sample, line, band is: 33 3 1 + Current sample, line, band is: 34 3 1 + Current sample, line, band is: 35 3 1 + Current sample, line, band is: 36 3 1 + Current sample, line, band is: 37 3 1 + Current sample, line, band is: 38 3 1 + Current sample, line, band is: 39 3 1 + Current sample, line, band is: 40 3 1 + Current sample, line, band is: 41 3 1 + Current sample, line, band is: 42 3 1 + Current sample, line, band is: 43 3 1 + Current sample, line, band is: 44 3 1 + Current sample, line, band is: 45 3 1 + Current sample, line, band is: 46 3 1 + Current sample, line, band is: 47 3 1 + Current sample, line, band is: 48 3 1 + Current sample, line, band is: 49 3 1 + Current sample, line, band is: 50 3 1 + Current sample, line, band is: 51 3 1 + Current sample, line, band is: 52 3 1 + Current sample, line, band is: 53 3 1 + Current sample, line, band is: 54 3 1 + Current sample, line, band is: 55 3 1 + Current sample, line, band is: 56 3 1 + Current sample, line, band is: 57 3 1 + Current sample, line, band is: 58 3 1 + Current sample, line, band is: 59 3 1 + Current sample, line, band is: 60 3 1 + Current sample, line, band is: 61 3 1 + Current sample, line, band is: 62 3 1 + Current sample, line, band is: 63 3 1 + Current sample, line, band is: 64 3 1 + Current sample, line, band is: 65 3 1 + Current sample, line, band is: 66 3 1 + Current sample, line, band is: 67 3 1 + Current sample, line, band is: 68 3 1 + Current sample, line, band is: 69 3 1 + Current sample, line, band is: 70 3 1 + Current sample, line, band is: 71 3 1 + Current sample, line, band is: 72 3 1 + Current sample, line, band is: 73 3 1 + Current sample, line, band is: 74 3 1 + Current sample, line, band is: 75 3 1 + Current sample, line, band is: 76 3 1 + Current sample, line, band is: 77 3 1 + Current sample, line, band is: 78 3 1 + Current sample, line, band is: 79 3 1 + Current sample, line, band is: 80 3 1 + Current sample, line, band is: 81 3 1 + Current sample, line, band is: 82 3 1 + Current sample, line, band is: 83 3 1 + Current sample, line, band is: 84 3 1 + Current sample, line, band is: 85 3 1 + Current sample, line, band is: 86 3 1 + Current sample, line, band is: 87 3 1 + Current sample, line, band is: 88 3 1 + Current sample, line, band is: 89 3 1 + Current sample, line, band is: 90 3 1 + Current sample, line, band is: 91 3 1 + Current sample, line, band is: 92 3 1 + Current sample, line, band is: 93 3 1 + Current sample, line, band is: 94 3 1 + Current sample, line, band is: 95 3 1 + Current sample, line, band is: 96 3 1 + Current sample, line, band is: 97 3 1 + Current sample, line, band is: 98 3 1 + Current sample, line, band is: 99 3 1 + Current sample, line, band is: 100 3 1 + Current sample, line, band is: 101 3 1 + Current sample, line, band is: 102 3 1 + Current sample, line, band is: 103 3 1 + Current sample, line, band is: 104 3 1 + Current sample, line, band is: 105 3 1 + Current sample, line, band is: 106 3 1 + Current sample, line, band is: 107 3 1 + Current sample, line, band is: 108 3 1 + Current sample, line, band is: 109 3 1 + Current sample, line, band is: 110 3 1 + Current sample, line, band is: 111 3 1 + Current sample, line, band is: 112 3 1 + Current sample, line, band is: 113 3 1 + Current sample, line, band is: 114 3 1 + Current sample, line, band is: 115 3 1 + Current sample, line, band is: 116 3 1 + Current sample, line, band is: 117 3 1 + Current sample, line, band is: 118 3 1 + Current sample, line, band is: 119 3 1 + Current sample, line, band is: 120 3 1 + Current sample, line, band is: 121 3 1 + Current sample, line, band is: 122 3 1 + Current sample, line, band is: 123 3 1 + Current sample, line, band is: 124 3 1 + Current sample, line, band is: 125 3 1 + Current sample, line, band is: 126 3 1 + Current sample, line, band is: 1 4 1 + Current sample, line, band is: 2 4 1 + Current sample, line, band is: 3 4 1 + Current sample, line, band is: 4 4 1 + Current sample, line, band is: 5 4 1 + Current sample, line, band is: 6 4 1 + Current sample, line, band is: 7 4 1 + Current sample, line, band is: 8 4 1 + Current sample, line, band is: 9 4 1 + Current sample, line, band is: 10 4 1 + Current sample, line, band is: 11 4 1 + Current sample, line, band is: 12 4 1 + Current sample, line, band is: 13 4 1 + Current sample, line, band is: 14 4 1 + Current sample, line, band is: 15 4 1 + Current sample, line, band is: 16 4 1 + Current sample, line, band is: 17 4 1 + Current sample, line, band is: 18 4 1 + Current sample, line, band is: 19 4 1 + Current sample, line, band is: 20 4 1 + Current sample, line, band is: 21 4 1 + Current sample, line, band is: 22 4 1 + Current sample, line, band is: 23 4 1 + Current sample, line, band is: 24 4 1 + Current sample, line, band is: 25 4 1 + Current sample, line, band is: 26 4 1 + Current sample, line, band is: 27 4 1 + Current sample, line, band is: 28 4 1 + Current sample, line, band is: 29 4 1 + Current sample, line, band is: 30 4 1 + Current sample, line, band is: 31 4 1 + Current sample, line, band is: 32 4 1 + Current sample, line, band is: 33 4 1 + Current sample, line, band is: 34 4 1 + Current sample, line, band is: 35 4 1 + Current sample, line, band is: 36 4 1 + Current sample, line, band is: 37 4 1 + Current sample, line, band is: 38 4 1 + Current sample, line, band is: 39 4 1 + Current sample, line, band is: 40 4 1 + Current sample, line, band is: 41 4 1 + Current sample, line, band is: 42 4 1 + Current sample, line, band is: 43 4 1 + Current sample, line, band is: 44 4 1 + Current sample, line, band is: 45 4 1 + Current sample, line, band is: 46 4 1 + Current sample, line, band is: 47 4 1 + Current sample, line, band is: 48 4 1 + Current sample, line, band is: 49 4 1 + Current sample, line, band is: 50 4 1 + Current sample, line, band is: 51 4 1 + Current sample, line, band is: 52 4 1 + Current sample, line, band is: 53 4 1 + Current sample, line, band is: 54 4 1 + Current sample, line, band is: 55 4 1 + Current sample, line, band is: 56 4 1 + Current sample, line, band is: 57 4 1 + Current sample, line, band is: 58 4 1 + Current sample, line, band is: 59 4 1 + Current sample, line, band is: 60 4 1 + Current sample, line, band is: 61 4 1 + Current sample, line, band is: 62 4 1 + Current sample, line, band is: 63 4 1 + Current sample, line, band is: 64 4 1 + Current sample, line, band is: 65 4 1 + Current sample, line, band is: 66 4 1 + Current sample, line, band is: 67 4 1 + Current sample, line, band is: 68 4 1 + Current sample, line, band is: 69 4 1 + Current sample, line, band is: 70 4 1 + Current sample, line, band is: 71 4 1 + Current sample, line, band is: 72 4 1 + Current sample, line, band is: 73 4 1 + Current sample, line, band is: 74 4 1 + Current sample, line, band is: 75 4 1 + Current sample, line, band is: 76 4 1 + Current sample, line, band is: 77 4 1 + Current sample, line, band is: 78 4 1 + Current sample, line, band is: 79 4 1 + Current sample, line, band is: 80 4 1 + Current sample, line, band is: 81 4 1 + Current sample, line, band is: 82 4 1 + Current sample, line, band is: 83 4 1 + Current sample, line, band is: 84 4 1 + Current sample, line, band is: 85 4 1 + Current sample, line, band is: 86 4 1 + Current sample, line, band is: 87 4 1 + Current sample, line, band is: 88 4 1 + Current sample, line, band is: 89 4 1 + Current sample, line, band is: 90 4 1 + Current sample, line, band is: 91 4 1 + Current sample, line, band is: 92 4 1 + Current sample, line, band is: 93 4 1 + Current sample, line, band is: 94 4 1 + Current sample, line, band is: 95 4 1 + Current sample, line, band is: 96 4 1 + Current sample, line, band is: 97 4 1 + Current sample, line, band is: 98 4 1 + Current sample, line, band is: 99 4 1 + Current sample, line, band is: 100 4 1 + Current sample, line, band is: 101 4 1 + Current sample, line, band is: 102 4 1 + Current sample, line, band is: 103 4 1 + Current sample, line, band is: 104 4 1 + Current sample, line, band is: 105 4 1 + Current sample, line, band is: 106 4 1 + Current sample, line, band is: 107 4 1 + Current sample, line, band is: 108 4 1 + Current sample, line, band is: 109 4 1 + Current sample, line, band is: 110 4 1 + Current sample, line, band is: 111 4 1 + Current sample, line, band is: 112 4 1 + Current sample, line, band is: 113 4 1 + Current sample, line, band is: 114 4 1 + Current sample, line, band is: 115 4 1 + Current sample, line, band is: 116 4 1 + Current sample, line, band is: 117 4 1 + Current sample, line, band is: 118 4 1 + Current sample, line, band is: 119 4 1 + Current sample, line, band is: 120 4 1 + Current sample, line, band is: 121 4 1 + Current sample, line, band is: 122 4 1 + Current sample, line, band is: 123 4 1 + Current sample, line, band is: 124 4 1 + Current sample, line, band is: 125 4 1 + Current sample, line, band is: 126 4 1 + Current sample, line, band is: 1 5 1 + Current sample, line, band is: 2 5 1 + Current sample, line, band is: 3 5 1 + Current sample, line, band is: 4 5 1 + Current sample, line, band is: 5 5 1 + Current sample, line, band is: 6 5 1 + Current sample, line, band is: 7 5 1 + Current sample, line, band is: 8 5 1 + Current sample, line, band is: 9 5 1 + Current sample, line, band is: 10 5 1 + Current sample, line, band is: 11 5 1 + Current sample, line, band is: 12 5 1 + Current sample, line, band is: 13 5 1 + Current sample, line, band is: 14 5 1 + Current sample, line, band is: 15 5 1 + Current sample, line, band is: 16 5 1 + Current sample, line, band is: 17 5 1 + Current sample, line, band is: 18 5 1 + Current sample, line, band is: 19 5 1 + Current sample, line, band is: 20 5 1 + Current sample, line, band is: 21 5 1 + Current sample, line, band is: 22 5 1 + Current sample, line, band is: 23 5 1 + Current sample, line, band is: 24 5 1 + Current sample, line, band is: 25 5 1 + Current sample, line, band is: 26 5 1 + Current sample, line, band is: 27 5 1 + Current sample, line, band is: 28 5 1 + Current sample, line, band is: 29 5 1 + Current sample, line, band is: 30 5 1 + Current sample, line, band is: 31 5 1 + Current sample, line, band is: 32 5 1 + Current sample, line, band is: 33 5 1 + Current sample, line, band is: 34 5 1 + Current sample, line, band is: 35 5 1 + Current sample, line, band is: 36 5 1 + Current sample, line, band is: 37 5 1 + Current sample, line, band is: 38 5 1 + Current sample, line, band is: 39 5 1 + Current sample, line, band is: 40 5 1 + Current sample, line, band is: 41 5 1 + Current sample, line, band is: 42 5 1 + Current sample, line, band is: 43 5 1 + Current sample, line, band is: 44 5 1 + Current sample, line, band is: 45 5 1 + Current sample, line, band is: 46 5 1 + Current sample, line, band is: 47 5 1 + Current sample, line, band is: 48 5 1 + Current sample, line, band is: 49 5 1 + Current sample, line, band is: 50 5 1 + Current sample, line, band is: 51 5 1 + Current sample, line, band is: 52 5 1 + Current sample, line, band is: 53 5 1 + Current sample, line, band is: 54 5 1 + Current sample, line, band is: 55 5 1 + Current sample, line, band is: 56 5 1 + Current sample, line, band is: 57 5 1 + Current sample, line, band is: 58 5 1 + Current sample, line, band is: 59 5 1 + Current sample, line, band is: 60 5 1 + Current sample, line, band is: 61 5 1 + Current sample, line, band is: 62 5 1 + Current sample, line, band is: 63 5 1 + Current sample, line, band is: 64 5 1 + Current sample, line, band is: 65 5 1 + Current sample, line, band is: 66 5 1 + Current sample, line, band is: 67 5 1 + Current sample, line, band is: 68 5 1 + Current sample, line, band is: 69 5 1 + Current sample, line, band is: 70 5 1 + Current sample, line, band is: 71 5 1 + Current sample, line, band is: 72 5 1 + Current sample, line, band is: 73 5 1 + Current sample, line, band is: 74 5 1 + Current sample, line, band is: 75 5 1 + Current sample, line, band is: 76 5 1 + Current sample, line, band is: 77 5 1 + Current sample, line, band is: 78 5 1 + Current sample, line, band is: 79 5 1 + Current sample, line, band is: 80 5 1 + Current sample, line, band is: 81 5 1 + Current sample, line, band is: 82 5 1 + Current sample, line, band is: 83 5 1 + Current sample, line, band is: 84 5 1 + Current sample, line, band is: 85 5 1 + Current sample, line, band is: 86 5 1 + Current sample, line, band is: 87 5 1 + Current sample, line, band is: 88 5 1 + Current sample, line, band is: 89 5 1 + Current sample, line, band is: 90 5 1 + Current sample, line, band is: 91 5 1 + Current sample, line, band is: 92 5 1 + Current sample, line, band is: 93 5 1 + Current sample, line, band is: 94 5 1 + Current sample, line, band is: 95 5 1 + Current sample, line, band is: 96 5 1 + Current sample, line, band is: 97 5 1 + Current sample, line, band is: 98 5 1 + Current sample, line, band is: 99 5 1 + Current sample, line, band is: 100 5 1 + Current sample, line, band is: 101 5 1 + Current sample, line, band is: 102 5 1 + Current sample, line, band is: 103 5 1 + Current sample, line, band is: 104 5 1 + Current sample, line, band is: 105 5 1 + Current sample, line, band is: 106 5 1 + Current sample, line, band is: 107 5 1 + Current sample, line, band is: 108 5 1 + Current sample, line, band is: 109 5 1 + Current sample, line, band is: 110 5 1 + Current sample, line, band is: 111 5 1 + Current sample, line, band is: 112 5 1 + Current sample, line, band is: 113 5 1 + Current sample, line, band is: 114 5 1 + Current sample, line, band is: 115 5 1 + Current sample, line, band is: 116 5 1 + Current sample, line, band is: 117 5 1 + Current sample, line, band is: 118 5 1 + Current sample, line, band is: 119 5 1 + Current sample, line, band is: 120 5 1 + Current sample, line, band is: 121 5 1 + Current sample, line, band is: 122 5 1 + Current sample, line, band is: 123 5 1 + Current sample, line, band is: 124 5 1 + Current sample, line, band is: 125 5 1 + Current sample, line, band is: 126 5 1 + Current sample, line, band is: 1 6 1 + Current sample, line, band is: 2 6 1 + Current sample, line, band is: 3 6 1 + Current sample, line, band is: 4 6 1 + Current sample, line, band is: 5 6 1 + Current sample, line, band is: 6 6 1 + Current sample, line, band is: 7 6 1 + Current sample, line, band is: 8 6 1 + Current sample, line, band is: 9 6 1 + Current sample, line, band is: 10 6 1 + Current sample, line, band is: 11 6 1 + Current sample, line, band is: 12 6 1 + Current sample, line, band is: 13 6 1 + Current sample, line, band is: 14 6 1 + Current sample, line, band is: 15 6 1 + Current sample, line, band is: 16 6 1 + Current sample, line, band is: 17 6 1 + Current sample, line, band is: 18 6 1 + Current sample, line, band is: 19 6 1 + Current sample, line, band is: 20 6 1 + Current sample, line, band is: 21 6 1 + Current sample, line, band is: 22 6 1 + Current sample, line, band is: 23 6 1 + Current sample, line, band is: 24 6 1 + Current sample, line, band is: 25 6 1 + Current sample, line, band is: 26 6 1 + Current sample, line, band is: 27 6 1 + Current sample, line, band is: 28 6 1 + Current sample, line, band is: 29 6 1 + Current sample, line, band is: 30 6 1 + Current sample, line, band is: 31 6 1 + Current sample, line, band is: 32 6 1 + Current sample, line, band is: 33 6 1 + Current sample, line, band is: 34 6 1 + Current sample, line, band is: 35 6 1 + Current sample, line, band is: 36 6 1 + Current sample, line, band is: 37 6 1 + Current sample, line, band is: 38 6 1 + Current sample, line, band is: 39 6 1 + Current sample, line, band is: 40 6 1 + Current sample, line, band is: 41 6 1 + Current sample, line, band is: 42 6 1 + Current sample, line, band is: 43 6 1 + Current sample, line, band is: 44 6 1 + Current sample, line, band is: 45 6 1 + Current sample, line, band is: 46 6 1 + Current sample, line, band is: 47 6 1 + Current sample, line, band is: 48 6 1 + Current sample, line, band is: 49 6 1 + Current sample, line, band is: 50 6 1 + Current sample, line, band is: 51 6 1 + Current sample, line, band is: 52 6 1 + Current sample, line, band is: 53 6 1 + Current sample, line, band is: 54 6 1 + Current sample, line, band is: 55 6 1 + Current sample, line, band is: 56 6 1 + Current sample, line, band is: 57 6 1 + Current sample, line, band is: 58 6 1 + Current sample, line, band is: 59 6 1 + Current sample, line, band is: 60 6 1 + Current sample, line, band is: 61 6 1 + Current sample, line, band is: 62 6 1 + Current sample, line, band is: 63 6 1 + Current sample, line, band is: 64 6 1 + Current sample, line, band is: 65 6 1 + Current sample, line, band is: 66 6 1 + Current sample, line, band is: 67 6 1 + Current sample, line, band is: 68 6 1 + Current sample, line, band is: 69 6 1 + Current sample, line, band is: 70 6 1 + Current sample, line, band is: 71 6 1 + Current sample, line, band is: 72 6 1 + Current sample, line, band is: 73 6 1 + Current sample, line, band is: 74 6 1 + Current sample, line, band is: 75 6 1 + Current sample, line, band is: 76 6 1 + Current sample, line, band is: 77 6 1 + Current sample, line, band is: 78 6 1 + Current sample, line, band is: 79 6 1 + Current sample, line, band is: 80 6 1 + Current sample, line, band is: 81 6 1 + Current sample, line, band is: 82 6 1 + Current sample, line, band is: 83 6 1 + Current sample, line, band is: 84 6 1 + Current sample, line, band is: 85 6 1 + Current sample, line, band is: 86 6 1 + Current sample, line, band is: 87 6 1 + Current sample, line, band is: 88 6 1 + Current sample, line, band is: 89 6 1 + Current sample, line, band is: 90 6 1 + Current sample, line, band is: 91 6 1 + Current sample, line, band is: 92 6 1 + Current sample, line, band is: 93 6 1 + Current sample, line, band is: 94 6 1 + Current sample, line, band is: 95 6 1 + Current sample, line, band is: 96 6 1 + Current sample, line, band is: 97 6 1 + Current sample, line, band is: 98 6 1 + Current sample, line, band is: 99 6 1 + Current sample, line, band is: 100 6 1 + Current sample, line, band is: 101 6 1 + Current sample, line, band is: 102 6 1 + Current sample, line, band is: 103 6 1 + Current sample, line, band is: 104 6 1 + Current sample, line, band is: 105 6 1 + Current sample, line, band is: 106 6 1 + Current sample, line, band is: 107 6 1 + Current sample, line, band is: 108 6 1 + Current sample, line, band is: 109 6 1 + Current sample, line, band is: 110 6 1 + Current sample, line, band is: 111 6 1 + Current sample, line, band is: 112 6 1 + Current sample, line, band is: 113 6 1 + Current sample, line, band is: 114 6 1 + Current sample, line, band is: 115 6 1 + Current sample, line, band is: 116 6 1 + Current sample, line, band is: 117 6 1 + Current sample, line, band is: 118 6 1 + Current sample, line, band is: 119 6 1 + Current sample, line, band is: 120 6 1 + Current sample, line, band is: 121 6 1 + Current sample, line, band is: 122 6 1 + Current sample, line, band is: 123 6 1 + Current sample, line, band is: 124 6 1 + Current sample, line, band is: 125 6 1 + Current sample, line, band is: 126 6 1 + Current sample, line, band is: 1 7 1 + Current sample, line, band is: 2 7 1 + Current sample, line, band is: 3 7 1 + Current sample, line, band is: 4 7 1 + Current sample, line, band is: 5 7 1 + Current sample, line, band is: 6 7 1 + Current sample, line, band is: 7 7 1 + Current sample, line, band is: 8 7 1 + Current sample, line, band is: 9 7 1 + Current sample, line, band is: 10 7 1 + Current sample, line, band is: 11 7 1 + Current sample, line, band is: 12 7 1 + Current sample, line, band is: 13 7 1 + Current sample, line, band is: 14 7 1 + Current sample, line, band is: 15 7 1 + Current sample, line, band is: 16 7 1 + Current sample, line, band is: 17 7 1 + Current sample, line, band is: 18 7 1 + Current sample, line, band is: 19 7 1 + Current sample, line, band is: 20 7 1 + Current sample, line, band is: 21 7 1 + Current sample, line, band is: 22 7 1 + Current sample, line, band is: 23 7 1 + Current sample, line, band is: 24 7 1 + Current sample, line, band is: 25 7 1 + Current sample, line, band is: 26 7 1 + Current sample, line, band is: 27 7 1 + Current sample, line, band is: 28 7 1 + Current sample, line, band is: 29 7 1 + Current sample, line, band is: 30 7 1 + Current sample, line, band is: 31 7 1 + Current sample, line, band is: 32 7 1 + Current sample, line, band is: 33 7 1 + Current sample, line, band is: 34 7 1 + Current sample, line, band is: 35 7 1 + Current sample, line, band is: 36 7 1 + Current sample, line, band is: 37 7 1 + Current sample, line, band is: 38 7 1 + Current sample, line, band is: 39 7 1 + Current sample, line, band is: 40 7 1 + Current sample, line, band is: 41 7 1 + Current sample, line, band is: 42 7 1 + Current sample, line, band is: 43 7 1 + Current sample, line, band is: 44 7 1 + Current sample, line, band is: 45 7 1 + Current sample, line, band is: 46 7 1 + Current sample, line, band is: 47 7 1 + Current sample, line, band is: 48 7 1 + Current sample, line, band is: 49 7 1 + Current sample, line, band is: 50 7 1 + Current sample, line, band is: 51 7 1 + Current sample, line, band is: 52 7 1 + Current sample, line, band is: 53 7 1 + Current sample, line, band is: 54 7 1 + Current sample, line, band is: 55 7 1 + Current sample, line, band is: 56 7 1 + Current sample, line, band is: 57 7 1 + Current sample, line, band is: 58 7 1 + Current sample, line, band is: 59 7 1 + Current sample, line, band is: 60 7 1 + Current sample, line, band is: 61 7 1 + Current sample, line, band is: 62 7 1 + Current sample, line, band is: 63 7 1 + Current sample, line, band is: 64 7 1 + Current sample, line, band is: 65 7 1 + Current sample, line, band is: 66 7 1 + Current sample, line, band is: 67 7 1 + Current sample, line, band is: 68 7 1 + Current sample, line, band is: 69 7 1 + Current sample, line, band is: 70 7 1 + Current sample, line, band is: 71 7 1 + Current sample, line, band is: 72 7 1 + Current sample, line, band is: 73 7 1 + Current sample, line, band is: 74 7 1 + Current sample, line, band is: 75 7 1 + Current sample, line, band is: 76 7 1 + Current sample, line, band is: 77 7 1 + Current sample, line, band is: 78 7 1 + Current sample, line, band is: 79 7 1 + Current sample, line, band is: 80 7 1 + Current sample, line, band is: 81 7 1 + Current sample, line, band is: 82 7 1 + Current sample, line, band is: 83 7 1 + Current sample, line, band is: 84 7 1 + Current sample, line, band is: 85 7 1 + Current sample, line, band is: 86 7 1 + Current sample, line, band is: 87 7 1 + Current sample, line, band is: 88 7 1 + Current sample, line, band is: 89 7 1 + Current sample, line, band is: 90 7 1 + Current sample, line, band is: 91 7 1 + Current sample, line, band is: 92 7 1 + Current sample, line, band is: 93 7 1 + Current sample, line, band is: 94 7 1 + Current sample, line, band is: 95 7 1 + Current sample, line, band is: 96 7 1 + Current sample, line, band is: 97 7 1 + Current sample, line, band is: 98 7 1 + Current sample, line, band is: 99 7 1 + Current sample, line, band is: 100 7 1 + Current sample, line, band is: 101 7 1 + Current sample, line, band is: 102 7 1 + Current sample, line, band is: 103 7 1 + Current sample, line, band is: 104 7 1 + Current sample, line, band is: 105 7 1 + Current sample, line, band is: 106 7 1 + Current sample, line, band is: 107 7 1 + Current sample, line, band is: 108 7 1 + Current sample, line, band is: 109 7 1 + Current sample, line, band is: 110 7 1 + Current sample, line, band is: 111 7 1 + Current sample, line, band is: 112 7 1 + Current sample, line, band is: 113 7 1 + Current sample, line, band is: 114 7 1 + Current sample, line, band is: 115 7 1 + Current sample, line, band is: 116 7 1 + Current sample, line, band is: 117 7 1 + Current sample, line, band is: 118 7 1 + Current sample, line, band is: 119 7 1 + Current sample, line, band is: 120 7 1 + Current sample, line, band is: 121 7 1 + Current sample, line, band is: 122 7 1 + Current sample, line, band is: 123 7 1 + Current sample, line, band is: 124 7 1 + Current sample, line, band is: 125 7 1 + Current sample, line, band is: 126 7 1 + Current sample, line, band is: 1 8 1 + Current sample, line, band is: 2 8 1 + Current sample, line, band is: 3 8 1 + Current sample, line, band is: 4 8 1 + Current sample, line, band is: 5 8 1 + Current sample, line, band is: 6 8 1 + Current sample, line, band is: 7 8 1 + Current sample, line, band is: 8 8 1 + Current sample, line, band is: 9 8 1 + Current sample, line, band is: 10 8 1 + Current sample, line, band is: 11 8 1 + Current sample, line, band is: 12 8 1 + Current sample, line, band is: 13 8 1 + Current sample, line, band is: 14 8 1 + Current sample, line, band is: 15 8 1 + Current sample, line, band is: 16 8 1 + Current sample, line, band is: 17 8 1 + Current sample, line, band is: 18 8 1 + Current sample, line, band is: 19 8 1 + Current sample, line, band is: 20 8 1 + Current sample, line, band is: 21 8 1 + Current sample, line, band is: 22 8 1 + Current sample, line, band is: 23 8 1 + Current sample, line, band is: 24 8 1 + Current sample, line, band is: 25 8 1 + Current sample, line, band is: 26 8 1 + Current sample, line, band is: 27 8 1 + Current sample, line, band is: 28 8 1 + Current sample, line, band is: 29 8 1 + Current sample, line, band is: 30 8 1 + Current sample, line, band is: 31 8 1 + Current sample, line, band is: 32 8 1 + Current sample, line, band is: 33 8 1 + Current sample, line, band is: 34 8 1 + Current sample, line, band is: 35 8 1 + Current sample, line, band is: 36 8 1 + Current sample, line, band is: 37 8 1 + Current sample, line, band is: 38 8 1 + Current sample, line, band is: 39 8 1 + Current sample, line, band is: 40 8 1 + Current sample, line, band is: 41 8 1 + Current sample, line, band is: 42 8 1 + Current sample, line, band is: 43 8 1 + Current sample, line, band is: 44 8 1 + Current sample, line, band is: 45 8 1 + Current sample, line, band is: 46 8 1 + Current sample, line, band is: 47 8 1 + Current sample, line, band is: 48 8 1 + Current sample, line, band is: 49 8 1 + Current sample, line, band is: 50 8 1 + Current sample, line, band is: 51 8 1 + Current sample, line, band is: 52 8 1 + Current sample, line, band is: 53 8 1 + Current sample, line, band is: 54 8 1 + Current sample, line, band is: 55 8 1 + Current sample, line, band is: 56 8 1 + Current sample, line, band is: 57 8 1 + Current sample, line, band is: 58 8 1 + Current sample, line, band is: 59 8 1 + Current sample, line, band is: 60 8 1 + Current sample, line, band is: 61 8 1 + Current sample, line, band is: 62 8 1 + Current sample, line, band is: 63 8 1 + Current sample, line, band is: 64 8 1 + Current sample, line, band is: 65 8 1 + Current sample, line, band is: 66 8 1 + Current sample, line, band is: 67 8 1 + Current sample, line, band is: 68 8 1 + Current sample, line, band is: 69 8 1 + Current sample, line, band is: 70 8 1 + Current sample, line, band is: 71 8 1 + Current sample, line, band is: 72 8 1 + Current sample, line, band is: 73 8 1 + Current sample, line, band is: 74 8 1 + Current sample, line, band is: 75 8 1 + Current sample, line, band is: 76 8 1 + Current sample, line, band is: 77 8 1 + Current sample, line, band is: 78 8 1 + Current sample, line, band is: 79 8 1 + Current sample, line, band is: 80 8 1 + Current sample, line, band is: 81 8 1 + Current sample, line, band is: 82 8 1 + Current sample, line, band is: 83 8 1 + Current sample, line, band is: 84 8 1 + Current sample, line, band is: 85 8 1 + Current sample, line, band is: 86 8 1 + Current sample, line, band is: 87 8 1 + Current sample, line, band is: 88 8 1 + Current sample, line, band is: 89 8 1 + Current sample, line, band is: 90 8 1 + Current sample, line, band is: 91 8 1 + Current sample, line, band is: 92 8 1 + Current sample, line, band is: 93 8 1 + Current sample, line, band is: 94 8 1 + Current sample, line, band is: 95 8 1 + Current sample, line, band is: 96 8 1 + Current sample, line, band is: 97 8 1 + Current sample, line, band is: 98 8 1 + Current sample, line, band is: 99 8 1 + Current sample, line, band is: 100 8 1 + Current sample, line, band is: 101 8 1 + Current sample, line, band is: 102 8 1 + Current sample, line, band is: 103 8 1 + Current sample, line, band is: 104 8 1 + Current sample, line, band is: 105 8 1 + Current sample, line, band is: 106 8 1 + Current sample, line, band is: 107 8 1 + Current sample, line, band is: 108 8 1 + Current sample, line, band is: 109 8 1 + Current sample, line, band is: 110 8 1 + Current sample, line, band is: 111 8 1 + Current sample, line, band is: 112 8 1 + Current sample, line, band is: 113 8 1 + Current sample, line, band is: 114 8 1 + Current sample, line, band is: 115 8 1 + Current sample, line, band is: 116 8 1 + Current sample, line, band is: 117 8 1 + Current sample, line, band is: 118 8 1 + Current sample, line, band is: 119 8 1 + Current sample, line, band is: 120 8 1 + Current sample, line, band is: 121 8 1 + Current sample, line, band is: 122 8 1 + Current sample, line, band is: 123 8 1 + Current sample, line, band is: 124 8 1 + Current sample, line, band is: 125 8 1 + Current sample, line, band is: 126 8 1 + Current sample, line, band is: 1 9 1 + Current sample, line, band is: 2 9 1 + Current sample, line, band is: 3 9 1 + Current sample, line, band is: 4 9 1 + Current sample, line, band is: 5 9 1 + Current sample, line, band is: 6 9 1 + Current sample, line, band is: 7 9 1 + Current sample, line, band is: 8 9 1 + Current sample, line, band is: 9 9 1 + Current sample, line, band is: 10 9 1 + Current sample, line, band is: 11 9 1 + Current sample, line, band is: 12 9 1 + Current sample, line, band is: 13 9 1 + Current sample, line, band is: 14 9 1 + Current sample, line, band is: 15 9 1 + Current sample, line, band is: 16 9 1 + Current sample, line, band is: 17 9 1 + Current sample, line, band is: 18 9 1 + Current sample, line, band is: 19 9 1 + Current sample, line, band is: 20 9 1 + Current sample, line, band is: 21 9 1 + Current sample, line, band is: 22 9 1 + Current sample, line, band is: 23 9 1 + Current sample, line, band is: 24 9 1 + Current sample, line, band is: 25 9 1 + Current sample, line, band is: 26 9 1 + Current sample, line, band is: 27 9 1 + Current sample, line, band is: 28 9 1 + Current sample, line, band is: 29 9 1 + Current sample, line, band is: 30 9 1 + Current sample, line, band is: 31 9 1 + Current sample, line, band is: 32 9 1 + Current sample, line, band is: 33 9 1 + Current sample, line, band is: 34 9 1 + Current sample, line, band is: 35 9 1 + Current sample, line, band is: 36 9 1 + Current sample, line, band is: 37 9 1 + Current sample, line, band is: 38 9 1 + Current sample, line, band is: 39 9 1 + Current sample, line, band is: 40 9 1 + Current sample, line, band is: 41 9 1 + Current sample, line, band is: 42 9 1 + Current sample, line, band is: 43 9 1 + Current sample, line, band is: 44 9 1 + Current sample, line, band is: 45 9 1 + Current sample, line, band is: 46 9 1 + Current sample, line, band is: 47 9 1 + Current sample, line, band is: 48 9 1 + Current sample, line, band is: 49 9 1 + Current sample, line, band is: 50 9 1 + Current sample, line, band is: 51 9 1 + Current sample, line, band is: 52 9 1 + Current sample, line, band is: 53 9 1 + Current sample, line, band is: 54 9 1 + Current sample, line, band is: 55 9 1 + Current sample, line, band is: 56 9 1 + Current sample, line, band is: 57 9 1 + Current sample, line, band is: 58 9 1 + Current sample, line, band is: 59 9 1 + Current sample, line, band is: 60 9 1 + Current sample, line, band is: 61 9 1 + Current sample, line, band is: 62 9 1 + Current sample, line, band is: 63 9 1 + Current sample, line, band is: 64 9 1 + Current sample, line, band is: 65 9 1 + Current sample, line, band is: 66 9 1 + Current sample, line, band is: 67 9 1 + Current sample, line, band is: 68 9 1 + Current sample, line, band is: 69 9 1 + Current sample, line, band is: 70 9 1 + Current sample, line, band is: 71 9 1 + Current sample, line, band is: 72 9 1 + Current sample, line, band is: 73 9 1 + Current sample, line, band is: 74 9 1 + Current sample, line, band is: 75 9 1 + Current sample, line, band is: 76 9 1 + Current sample, line, band is: 77 9 1 + Current sample, line, band is: 78 9 1 + Current sample, line, band is: 79 9 1 + Current sample, line, band is: 80 9 1 + Current sample, line, band is: 81 9 1 + Current sample, line, band is: 82 9 1 + Current sample, line, band is: 83 9 1 + Current sample, line, band is: 84 9 1 + Current sample, line, band is: 85 9 1 + Current sample, line, band is: 86 9 1 + Current sample, line, band is: 87 9 1 + Current sample, line, band is: 88 9 1 + Current sample, line, band is: 89 9 1 + Current sample, line, band is: 90 9 1 + Current sample, line, band is: 91 9 1 + Current sample, line, band is: 92 9 1 + Current sample, line, band is: 93 9 1 + Current sample, line, band is: 94 9 1 + Current sample, line, band is: 95 9 1 + Current sample, line, band is: 96 9 1 + Current sample, line, band is: 97 9 1 + Current sample, line, band is: 98 9 1 + Current sample, line, band is: 99 9 1 + Current sample, line, band is: 100 9 1 + Current sample, line, band is: 101 9 1 + Current sample, line, band is: 102 9 1 + Current sample, line, band is: 103 9 1 + Current sample, line, band is: 104 9 1 + Current sample, line, band is: 105 9 1 + Current sample, line, band is: 106 9 1 + Current sample, line, band is: 107 9 1 + Current sample, line, band is: 108 9 1 + Current sample, line, band is: 109 9 1 + Current sample, line, band is: 110 9 1 + Current sample, line, band is: 111 9 1 + Current sample, line, band is: 112 9 1 + Current sample, line, band is: 113 9 1 + Current sample, line, band is: 114 9 1 + Current sample, line, band is: 115 9 1 + Current sample, line, band is: 116 9 1 + Current sample, line, band is: 117 9 1 + Current sample, line, band is: 118 9 1 + Current sample, line, band is: 119 9 1 + Current sample, line, band is: 120 9 1 + Current sample, line, band is: 121 9 1 + Current sample, line, band is: 122 9 1 + Current sample, line, band is: 123 9 1 + Current sample, line, band is: 124 9 1 + Current sample, line, band is: 125 9 1 + Current sample, line, band is: 126 9 1 + Current sample, line, band is: 1 10 1 + Current sample, line, band is: 2 10 1 + Current sample, line, band is: 3 10 1 + Current sample, line, band is: 4 10 1 + Current sample, line, band is: 5 10 1 + Current sample, line, band is: 6 10 1 + Current sample, line, band is: 7 10 1 + Current sample, line, band is: 8 10 1 + Current sample, line, band is: 9 10 1 + Current sample, line, band is: 10 10 1 + Current sample, line, band is: 11 10 1 + Current sample, line, band is: 12 10 1 + Current sample, line, band is: 13 10 1 + Current sample, line, band is: 14 10 1 + Current sample, line, band is: 15 10 1 + Current sample, line, band is: 16 10 1 + Current sample, line, band is: 17 10 1 + Current sample, line, band is: 18 10 1 + Current sample, line, band is: 19 10 1 + Current sample, line, band is: 20 10 1 + Current sample, line, band is: 21 10 1 + Current sample, line, band is: 22 10 1 + Current sample, line, band is: 23 10 1 + Current sample, line, band is: 24 10 1 + Current sample, line, band is: 25 10 1 + Current sample, line, band is: 26 10 1 + Current sample, line, band is: 27 10 1 + Current sample, line, band is: 28 10 1 + Current sample, line, band is: 29 10 1 + Current sample, line, band is: 30 10 1 + Current sample, line, band is: 31 10 1 + Current sample, line, band is: 32 10 1 + Current sample, line, band is: 33 10 1 + Current sample, line, band is: 34 10 1 + Current sample, line, band is: 35 10 1 + Current sample, line, band is: 36 10 1 + Current sample, line, band is: 37 10 1 + Current sample, line, band is: 38 10 1 + Current sample, line, band is: 39 10 1 + Current sample, line, band is: 40 10 1 + Current sample, line, band is: 41 10 1 + Current sample, line, band is: 42 10 1 + Current sample, line, band is: 43 10 1 + Current sample, line, band is: 44 10 1 + Current sample, line, band is: 45 10 1 + Current sample, line, band is: 46 10 1 + Current sample, line, band is: 47 10 1 + Current sample, line, band is: 48 10 1 + Current sample, line, band is: 49 10 1 + Current sample, line, band is: 50 10 1 + Current sample, line, band is: 51 10 1 + Current sample, line, band is: 52 10 1 + Current sample, line, band is: 53 10 1 + Current sample, line, band is: 54 10 1 + Current sample, line, band is: 55 10 1 + Current sample, line, band is: 56 10 1 + Current sample, line, band is: 57 10 1 + Current sample, line, band is: 58 10 1 + Current sample, line, band is: 59 10 1 + Current sample, line, band is: 60 10 1 + Current sample, line, band is: 61 10 1 + Current sample, line, band is: 62 10 1 + Current sample, line, band is: 63 10 1 + Current sample, line, band is: 64 10 1 + Current sample, line, band is: 65 10 1 + Current sample, line, band is: 66 10 1 + Current sample, line, band is: 67 10 1 + Current sample, line, band is: 68 10 1 + Current sample, line, band is: 69 10 1 + Current sample, line, band is: 70 10 1 + Current sample, line, band is: 71 10 1 + Current sample, line, band is: 72 10 1 + Current sample, line, band is: 73 10 1 + Current sample, line, band is: 74 10 1 + Current sample, line, band is: 75 10 1 + Current sample, line, band is: 76 10 1 + Current sample, line, band is: 77 10 1 + Current sample, line, band is: 78 10 1 + Current sample, line, band is: 79 10 1 + Current sample, line, band is: 80 10 1 + Current sample, line, band is: 81 10 1 + Current sample, line, band is: 82 10 1 + Current sample, line, band is: 83 10 1 + Current sample, line, band is: 84 10 1 + Current sample, line, band is: 85 10 1 + Current sample, line, band is: 86 10 1 + Current sample, line, band is: 87 10 1 + Current sample, line, band is: 88 10 1 + Current sample, line, band is: 89 10 1 + Current sample, line, band is: 90 10 1 + Current sample, line, band is: 91 10 1 + Current sample, line, band is: 92 10 1 + Current sample, line, band is: 93 10 1 + Current sample, line, band is: 94 10 1 + Current sample, line, band is: 95 10 1 + Current sample, line, band is: 96 10 1 + Current sample, line, band is: 97 10 1 + Current sample, line, band is: 98 10 1 + Current sample, line, band is: 99 10 1 + Current sample, line, band is: 100 10 1 + Current sample, line, band is: 101 10 1 + Current sample, line, band is: 102 10 1 + Current sample, line, band is: 103 10 1 + Current sample, line, band is: 104 10 1 + Current sample, line, band is: 105 10 1 + Current sample, line, band is: 106 10 1 + Current sample, line, band is: 107 10 1 + Current sample, line, band is: 108 10 1 + Current sample, line, band is: 109 10 1 + Current sample, line, band is: 110 10 1 + Current sample, line, band is: 111 10 1 + Current sample, line, band is: 112 10 1 + Current sample, line, band is: 113 10 1 + Current sample, line, band is: 114 10 1 + Current sample, line, band is: 115 10 1 + Current sample, line, band is: 116 10 1 + Current sample, line, band is: 117 10 1 + Current sample, line, band is: 118 10 1 + Current sample, line, band is: 119 10 1 + Current sample, line, band is: 120 10 1 + Current sample, line, band is: 121 10 1 + Current sample, line, band is: 122 10 1 + Current sample, line, band is: 123 10 1 + Current sample, line, band is: 124 10 1 + Current sample, line, band is: 125 10 1 + Current sample, line, band is: 126 10 1 + Current sample, line, band is: 1 11 1 + Current sample, line, band is: 2 11 1 + Current sample, line, band is: 3 11 1 + Current sample, line, band is: 4 11 1 + Current sample, line, band is: 5 11 1 + Current sample, line, band is: 6 11 1 + Current sample, line, band is: 7 11 1 + Current sample, line, band is: 8 11 1 + Current sample, line, band is: 9 11 1 + Current sample, line, band is: 10 11 1 + Current sample, line, band is: 11 11 1 + Current sample, line, band is: 12 11 1 + Current sample, line, band is: 13 11 1 + Current sample, line, band is: 14 11 1 + Current sample, line, band is: 15 11 1 + Current sample, line, band is: 16 11 1 + Current sample, line, band is: 17 11 1 + Current sample, line, band is: 18 11 1 + Current sample, line, band is: 19 11 1 + Current sample, line, band is: 20 11 1 + Current sample, line, band is: 21 11 1 + Current sample, line, band is: 22 11 1 + Current sample, line, band is: 23 11 1 + Current sample, line, band is: 24 11 1 + Current sample, line, band is: 25 11 1 + Current sample, line, band is: 26 11 1 + Current sample, line, band is: 27 11 1 + Current sample, line, band is: 28 11 1 + Current sample, line, band is: 29 11 1 + Current sample, line, band is: 30 11 1 + Current sample, line, band is: 31 11 1 + Current sample, line, band is: 32 11 1 + Current sample, line, band is: 33 11 1 + Current sample, line, band is: 34 11 1 + Current sample, line, band is: 35 11 1 + Current sample, line, band is: 36 11 1 + Current sample, line, band is: 37 11 1 + Current sample, line, band is: 38 11 1 + Current sample, line, band is: 39 11 1 + Current sample, line, band is: 40 11 1 + Current sample, line, band is: 41 11 1 + Current sample, line, band is: 42 11 1 + Current sample, line, band is: 43 11 1 + Current sample, line, band is: 44 11 1 + Current sample, line, band is: 45 11 1 + Current sample, line, band is: 46 11 1 + Current sample, line, band is: 47 11 1 + Current sample, line, band is: 48 11 1 + Current sample, line, band is: 49 11 1 + Current sample, line, band is: 50 11 1 + Current sample, line, band is: 51 11 1 + Current sample, line, band is: 52 11 1 + Current sample, line, band is: 53 11 1 + Current sample, line, band is: 54 11 1 + Current sample, line, band is: 55 11 1 + Current sample, line, band is: 56 11 1 + Current sample, line, band is: 57 11 1 + Current sample, line, band is: 58 11 1 + Current sample, line, band is: 59 11 1 + Current sample, line, band is: 60 11 1 + Current sample, line, band is: 61 11 1 + Current sample, line, band is: 62 11 1 + Current sample, line, band is: 63 11 1 + Current sample, line, band is: 64 11 1 + Current sample, line, band is: 65 11 1 + Current sample, line, band is: 66 11 1 + Current sample, line, band is: 67 11 1 + Current sample, line, band is: 68 11 1 + Current sample, line, band is: 69 11 1 + Current sample, line, band is: 70 11 1 + Current sample, line, band is: 71 11 1 + Current sample, line, band is: 72 11 1 + Current sample, line, band is: 73 11 1 + Current sample, line, band is: 74 11 1 + Current sample, line, band is: 75 11 1 + Current sample, line, band is: 76 11 1 + Current sample, line, band is: 77 11 1 + Current sample, line, band is: 78 11 1 + Current sample, line, band is: 79 11 1 + Current sample, line, band is: 80 11 1 + Current sample, line, band is: 81 11 1 + Current sample, line, band is: 82 11 1 + Current sample, line, band is: 83 11 1 + Current sample, line, band is: 84 11 1 + Current sample, line, band is: 85 11 1 + Current sample, line, band is: 86 11 1 + Current sample, line, band is: 87 11 1 + Current sample, line, band is: 88 11 1 + Current sample, line, band is: 89 11 1 + Current sample, line, band is: 90 11 1 + Current sample, line, band is: 91 11 1 + Current sample, line, band is: 92 11 1 + Current sample, line, band is: 93 11 1 + Current sample, line, band is: 94 11 1 + Current sample, line, band is: 95 11 1 + Current sample, line, band is: 96 11 1 + Current sample, line, band is: 97 11 1 + Current sample, line, band is: 98 11 1 + Current sample, line, band is: 99 11 1 + Current sample, line, band is: 100 11 1 + Current sample, line, band is: 101 11 1 + Current sample, line, band is: 102 11 1 + Current sample, line, band is: 103 11 1 + Current sample, line, band is: 104 11 1 + Current sample, line, band is: 105 11 1 + Current sample, line, band is: 106 11 1 + Current sample, line, band is: 107 11 1 + Current sample, line, band is: 108 11 1 + Current sample, line, band is: 109 11 1 + Current sample, line, band is: 110 11 1 + Current sample, line, band is: 111 11 1 + Current sample, line, band is: 112 11 1 + Current sample, line, band is: 113 11 1 + Current sample, line, band is: 114 11 1 + Current sample, line, band is: 115 11 1 + Current sample, line, band is: 116 11 1 + Current sample, line, band is: 117 11 1 + Current sample, line, band is: 118 11 1 + Current sample, line, band is: 119 11 1 + Current sample, line, band is: 120 11 1 + Current sample, line, band is: 121 11 1 + Current sample, line, band is: 122 11 1 + Current sample, line, band is: 123 11 1 + Current sample, line, band is: 124 11 1 + Current sample, line, band is: 125 11 1 + Current sample, line, band is: 126 11 1 + Current sample, line, band is: 1 12 1 + Current sample, line, band is: 2 12 1 + Current sample, line, band is: 3 12 1 + Current sample, line, band is: 4 12 1 + Current sample, line, band is: 5 12 1 + Current sample, line, band is: 6 12 1 + Current sample, line, band is: 7 12 1 + Current sample, line, band is: 8 12 1 + Current sample, line, band is: 9 12 1 + Current sample, line, band is: 10 12 1 + Current sample, line, band is: 11 12 1 + Current sample, line, band is: 12 12 1 + Current sample, line, band is: 13 12 1 + Current sample, line, band is: 14 12 1 + Current sample, line, band is: 15 12 1 + Current sample, line, band is: 16 12 1 + Current sample, line, band is: 17 12 1 + Current sample, line, band is: 18 12 1 + Current sample, line, band is: 19 12 1 + Current sample, line, band is: 20 12 1 + Current sample, line, band is: 21 12 1 + Current sample, line, band is: 22 12 1 + Current sample, line, band is: 23 12 1 + Current sample, line, band is: 24 12 1 + Current sample, line, band is: 25 12 1 + Current sample, line, band is: 26 12 1 + Current sample, line, band is: 27 12 1 + Current sample, line, band is: 28 12 1 + Current sample, line, band is: 29 12 1 + Current sample, line, band is: 30 12 1 + Current sample, line, band is: 31 12 1 + Current sample, line, band is: 32 12 1 + Current sample, line, band is: 33 12 1 + Current sample, line, band is: 34 12 1 + Current sample, line, band is: 35 12 1 + Current sample, line, band is: 36 12 1 + Current sample, line, band is: 37 12 1 + Current sample, line, band is: 38 12 1 + Current sample, line, band is: 39 12 1 + Current sample, line, band is: 40 12 1 + Current sample, line, band is: 41 12 1 + Current sample, line, band is: 42 12 1 + Current sample, line, band is: 43 12 1 + Current sample, line, band is: 44 12 1 + Current sample, line, band is: 45 12 1 + Current sample, line, band is: 46 12 1 + Current sample, line, band is: 47 12 1 + Current sample, line, band is: 48 12 1 + Current sample, line, band is: 49 12 1 + Current sample, line, band is: 50 12 1 + Current sample, line, band is: 51 12 1 + Current sample, line, band is: 52 12 1 + Current sample, line, band is: 53 12 1 + Current sample, line, band is: 54 12 1 + Current sample, line, band is: 55 12 1 + Current sample, line, band is: 56 12 1 + Current sample, line, band is: 57 12 1 + Current sample, line, band is: 58 12 1 + Current sample, line, band is: 59 12 1 + Current sample, line, band is: 60 12 1 + Current sample, line, band is: 61 12 1 + Current sample, line, band is: 62 12 1 + Current sample, line, band is: 63 12 1 + Current sample, line, band is: 64 12 1 + Current sample, line, band is: 65 12 1 + Current sample, line, band is: 66 12 1 + Current sample, line, band is: 67 12 1 + Current sample, line, band is: 68 12 1 + Current sample, line, band is: 69 12 1 + Current sample, line, band is: 70 12 1 + Current sample, line, band is: 71 12 1 + Current sample, line, band is: 72 12 1 + Current sample, line, band is: 73 12 1 + Current sample, line, band is: 74 12 1 + Current sample, line, band is: 75 12 1 + Current sample, line, band is: 76 12 1 + Current sample, line, band is: 77 12 1 + Current sample, line, band is: 78 12 1 + Current sample, line, band is: 79 12 1 + Current sample, line, band is: 80 12 1 + Current sample, line, band is: 81 12 1 + Current sample, line, band is: 82 12 1 + Current sample, line, band is: 83 12 1 + Current sample, line, band is: 84 12 1 + Current sample, line, band is: 85 12 1 + Current sample, line, band is: 86 12 1 + Current sample, line, band is: 87 12 1 + Current sample, line, band is: 88 12 1 + Current sample, line, band is: 89 12 1 + Current sample, line, band is: 90 12 1 + Current sample, line, band is: 91 12 1 + Current sample, line, band is: 92 12 1 + Current sample, line, band is: 93 12 1 + Current sample, line, band is: 94 12 1 + Current sample, line, band is: 95 12 1 + Current sample, line, band is: 96 12 1 + Current sample, line, band is: 97 12 1 + Current sample, line, band is: 98 12 1 + Current sample, line, band is: 99 12 1 + Current sample, line, band is: 100 12 1 + Current sample, line, band is: 101 12 1 + Current sample, line, band is: 102 12 1 + Current sample, line, band is: 103 12 1 + Current sample, line, band is: 104 12 1 + Current sample, line, band is: 105 12 1 + Current sample, line, band is: 106 12 1 + Current sample, line, band is: 107 12 1 + Current sample, line, band is: 108 12 1 + Current sample, line, band is: 109 12 1 + Current sample, line, band is: 110 12 1 + Current sample, line, band is: 111 12 1 + Current sample, line, band is: 112 12 1 + Current sample, line, band is: 113 12 1 + Current sample, line, band is: 114 12 1 + Current sample, line, band is: 115 12 1 + Current sample, line, band is: 116 12 1 + Current sample, line, band is: 117 12 1 + Current sample, line, band is: 118 12 1 + Current sample, line, band is: 119 12 1 + Current sample, line, band is: 120 12 1 + Current sample, line, band is: 121 12 1 + Current sample, line, band is: 122 12 1 + Current sample, line, band is: 123 12 1 + Current sample, line, band is: 124 12 1 + Current sample, line, band is: 125 12 1 + Current sample, line, band is: 126 12 1 + Current sample, line, band is: 1 13 1 + Current sample, line, band is: 2 13 1 + Current sample, line, band is: 3 13 1 + Current sample, line, band is: 4 13 1 + Current sample, line, band is: 5 13 1 + Current sample, line, band is: 6 13 1 + Current sample, line, band is: 7 13 1 + Current sample, line, band is: 8 13 1 + Current sample, line, band is: 9 13 1 + Current sample, line, band is: 10 13 1 + Current sample, line, band is: 11 13 1 + Current sample, line, band is: 12 13 1 + Current sample, line, band is: 13 13 1 + Current sample, line, band is: 14 13 1 + Current sample, line, band is: 15 13 1 + Current sample, line, band is: 16 13 1 + Current sample, line, band is: 17 13 1 + Current sample, line, band is: 18 13 1 + Current sample, line, band is: 19 13 1 + Current sample, line, band is: 20 13 1 + Current sample, line, band is: 21 13 1 + Current sample, line, band is: 22 13 1 + Current sample, line, band is: 23 13 1 + Current sample, line, band is: 24 13 1 + Current sample, line, band is: 25 13 1 + Current sample, line, band is: 26 13 1 + Current sample, line, band is: 27 13 1 + Current sample, line, band is: 28 13 1 + Current sample, line, band is: 29 13 1 + Current sample, line, band is: 30 13 1 + Current sample, line, band is: 31 13 1 + Current sample, line, band is: 32 13 1 + Current sample, line, band is: 33 13 1 + Current sample, line, band is: 34 13 1 + Current sample, line, band is: 35 13 1 + Current sample, line, band is: 36 13 1 + Current sample, line, band is: 37 13 1 + Current sample, line, band is: 38 13 1 + Current sample, line, band is: 39 13 1 + Current sample, line, band is: 40 13 1 + Current sample, line, band is: 41 13 1 + Current sample, line, band is: 42 13 1 + Current sample, line, band is: 43 13 1 + Current sample, line, band is: 44 13 1 + Current sample, line, band is: 45 13 1 + Current sample, line, band is: 46 13 1 + Current sample, line, band is: 47 13 1 + Current sample, line, band is: 48 13 1 + Current sample, line, band is: 49 13 1 + Current sample, line, band is: 50 13 1 + Current sample, line, band is: 51 13 1 + Current sample, line, band is: 52 13 1 + Current sample, line, band is: 53 13 1 + Current sample, line, band is: 54 13 1 + Current sample, line, band is: 55 13 1 + Current sample, line, band is: 56 13 1 + Current sample, line, band is: 57 13 1 + Current sample, line, band is: 58 13 1 + Current sample, line, band is: 59 13 1 + Current sample, line, band is: 60 13 1 + Current sample, line, band is: 61 13 1 + Current sample, line, band is: 62 13 1 + Current sample, line, band is: 63 13 1 + Current sample, line, band is: 64 13 1 + Current sample, line, band is: 65 13 1 + Current sample, line, band is: 66 13 1 + Current sample, line, band is: 67 13 1 + Current sample, line, band is: 68 13 1 + Current sample, line, band is: 69 13 1 + Current sample, line, band is: 70 13 1 + Current sample, line, band is: 71 13 1 + Current sample, line, band is: 72 13 1 + Current sample, line, band is: 73 13 1 + Current sample, line, band is: 74 13 1 + Current sample, line, band is: 75 13 1 + Current sample, line, band is: 76 13 1 + Current sample, line, band is: 77 13 1 + Current sample, line, band is: 78 13 1 + Current sample, line, band is: 79 13 1 + Current sample, line, band is: 80 13 1 + Current sample, line, band is: 81 13 1 + Current sample, line, band is: 82 13 1 + Current sample, line, band is: 83 13 1 + Current sample, line, band is: 84 13 1 + Current sample, line, band is: 85 13 1 + Current sample, line, band is: 86 13 1 + Current sample, line, band is: 87 13 1 + Current sample, line, band is: 88 13 1 + Current sample, line, band is: 89 13 1 + Current sample, line, band is: 90 13 1 + Current sample, line, band is: 91 13 1 + Current sample, line, band is: 92 13 1 + Current sample, line, band is: 93 13 1 + Current sample, line, band is: 94 13 1 + Current sample, line, band is: 95 13 1 + Current sample, line, band is: 96 13 1 + Current sample, line, band is: 97 13 1 + Current sample, line, band is: 98 13 1 + Current sample, line, band is: 99 13 1 + Current sample, line, band is: 100 13 1 + Current sample, line, band is: 101 13 1 + Current sample, line, band is: 102 13 1 + Current sample, line, band is: 103 13 1 + Current sample, line, band is: 104 13 1 + Current sample, line, band is: 105 13 1 + Current sample, line, band is: 106 13 1 + Current sample, line, band is: 107 13 1 + Current sample, line, band is: 108 13 1 + Current sample, line, band is: 109 13 1 + Current sample, line, band is: 110 13 1 + Current sample, line, band is: 111 13 1 + Current sample, line, band is: 112 13 1 + Current sample, line, band is: 113 13 1 + Current sample, line, band is: 114 13 1 + Current sample, line, band is: 115 13 1 + Current sample, line, band is: 116 13 1 + Current sample, line, band is: 117 13 1 + Current sample, line, band is: 118 13 1 + Current sample, line, band is: 119 13 1 + Current sample, line, band is: 120 13 1 + Current sample, line, band is: 121 13 1 + Current sample, line, band is: 122 13 1 + Current sample, line, band is: 123 13 1 + Current sample, line, band is: 124 13 1 + Current sample, line, band is: 125 13 1 + Current sample, line, band is: 126 13 1 + Current sample, line, band is: 1 14 1 + Current sample, line, band is: 2 14 1 + Current sample, line, band is: 3 14 1 + Current sample, line, band is: 4 14 1 + Current sample, line, band is: 5 14 1 + Current sample, line, band is: 6 14 1 + Current sample, line, band is: 7 14 1 + Current sample, line, band is: 8 14 1 + Current sample, line, band is: 9 14 1 + Current sample, line, band is: 10 14 1 + Current sample, line, band is: 11 14 1 + Current sample, line, band is: 12 14 1 + Current sample, line, band is: 13 14 1 + Current sample, line, band is: 14 14 1 + Current sample, line, band is: 15 14 1 + Current sample, line, band is: 16 14 1 + Current sample, line, band is: 17 14 1 + Current sample, line, band is: 18 14 1 + Current sample, line, band is: 19 14 1 + Current sample, line, band is: 20 14 1 + Current sample, line, band is: 21 14 1 + Current sample, line, band is: 22 14 1 + Current sample, line, band is: 23 14 1 + Current sample, line, band is: 24 14 1 + Current sample, line, band is: 25 14 1 + Current sample, line, band is: 26 14 1 + Current sample, line, band is: 27 14 1 + Current sample, line, band is: 28 14 1 + Current sample, line, band is: 29 14 1 + Current sample, line, band is: 30 14 1 + Current sample, line, band is: 31 14 1 + Current sample, line, band is: 32 14 1 + Current sample, line, band is: 33 14 1 + Current sample, line, band is: 34 14 1 + Current sample, line, band is: 35 14 1 + Current sample, line, band is: 36 14 1 + Current sample, line, band is: 37 14 1 + Current sample, line, band is: 38 14 1 + Current sample, line, band is: 39 14 1 + Current sample, line, band is: 40 14 1 + Current sample, line, band is: 41 14 1 + Current sample, line, band is: 42 14 1 + Current sample, line, band is: 43 14 1 + Current sample, line, band is: 44 14 1 + Current sample, line, band is: 45 14 1 + Current sample, line, band is: 46 14 1 + Current sample, line, band is: 47 14 1 + Current sample, line, band is: 48 14 1 + Current sample, line, band is: 49 14 1 + Current sample, line, band is: 50 14 1 + Current sample, line, band is: 51 14 1 + Current sample, line, band is: 52 14 1 + Current sample, line, band is: 53 14 1 + Current sample, line, band is: 54 14 1 + Current sample, line, band is: 55 14 1 + Current sample, line, band is: 56 14 1 + Current sample, line, band is: 57 14 1 + Current sample, line, band is: 58 14 1 + Current sample, line, band is: 59 14 1 + Current sample, line, band is: 60 14 1 + Current sample, line, band is: 61 14 1 + Current sample, line, band is: 62 14 1 + Current sample, line, band is: 63 14 1 + Current sample, line, band is: 64 14 1 + Current sample, line, band is: 65 14 1 + Current sample, line, band is: 66 14 1 + Current sample, line, band is: 67 14 1 + Current sample, line, band is: 68 14 1 + Current sample, line, band is: 69 14 1 + Current sample, line, band is: 70 14 1 + Current sample, line, band is: 71 14 1 + Current sample, line, band is: 72 14 1 + Current sample, line, band is: 73 14 1 + Current sample, line, band is: 74 14 1 + Current sample, line, band is: 75 14 1 + Current sample, line, band is: 76 14 1 + Current sample, line, band is: 77 14 1 + Current sample, line, band is: 78 14 1 + Current sample, line, band is: 79 14 1 + Current sample, line, band is: 80 14 1 + Current sample, line, band is: 81 14 1 + Current sample, line, band is: 82 14 1 + Current sample, line, band is: 83 14 1 + Current sample, line, band is: 84 14 1 + Current sample, line, band is: 85 14 1 + Current sample, line, band is: 86 14 1 + Current sample, line, band is: 87 14 1 + Current sample, line, band is: 88 14 1 + Current sample, line, band is: 89 14 1 + Current sample, line, band is: 90 14 1 + Current sample, line, band is: 91 14 1 + Current sample, line, band is: 92 14 1 + Current sample, line, band is: 93 14 1 + Current sample, line, band is: 94 14 1 + Current sample, line, band is: 95 14 1 + Current sample, line, band is: 96 14 1 + Current sample, line, band is: 97 14 1 + Current sample, line, band is: 98 14 1 + Current sample, line, band is: 99 14 1 + Current sample, line, band is: 100 14 1 + Current sample, line, band is: 101 14 1 + Current sample, line, band is: 102 14 1 + Current sample, line, band is: 103 14 1 + Current sample, line, band is: 104 14 1 + Current sample, line, band is: 105 14 1 + Current sample, line, band is: 106 14 1 + Current sample, line, band is: 107 14 1 + Current sample, line, band is: 108 14 1 + Current sample, line, band is: 109 14 1 + Current sample, line, band is: 110 14 1 + Current sample, line, band is: 111 14 1 + Current sample, line, band is: 112 14 1 + Current sample, line, band is: 113 14 1 + Current sample, line, band is: 114 14 1 + Current sample, line, band is: 115 14 1 + Current sample, line, band is: 116 14 1 + Current sample, line, band is: 117 14 1 + Current sample, line, band is: 118 14 1 + Current sample, line, band is: 119 14 1 + Current sample, line, band is: 120 14 1 + Current sample, line, band is: 121 14 1 + Current sample, line, band is: 122 14 1 + Current sample, line, band is: 123 14 1 + Current sample, line, band is: 124 14 1 + Current sample, line, band is: 125 14 1 + Current sample, line, band is: 126 14 1 + Current sample, line, band is: 1 15 1 + Current sample, line, band is: 2 15 1 + Current sample, line, band is: 3 15 1 + Current sample, line, band is: 4 15 1 + Current sample, line, band is: 5 15 1 + Current sample, line, band is: 6 15 1 + Current sample, line, band is: 7 15 1 + Current sample, line, band is: 8 15 1 + Current sample, line, band is: 9 15 1 + Current sample, line, band is: 10 15 1 + Current sample, line, band is: 11 15 1 + Current sample, line, band is: 12 15 1 + Current sample, line, band is: 13 15 1 + Current sample, line, band is: 14 15 1 + Current sample, line, band is: 15 15 1 + Current sample, line, band is: 16 15 1 + Current sample, line, band is: 17 15 1 + Current sample, line, band is: 18 15 1 + Current sample, line, band is: 19 15 1 + Current sample, line, band is: 20 15 1 + Current sample, line, band is: 21 15 1 + Current sample, line, band is: 22 15 1 + Current sample, line, band is: 23 15 1 + Current sample, line, band is: 24 15 1 + Current sample, line, band is: 25 15 1 + Current sample, line, band is: 26 15 1 + Current sample, line, band is: 27 15 1 + Current sample, line, band is: 28 15 1 + Current sample, line, band is: 29 15 1 + Current sample, line, band is: 30 15 1 + Current sample, line, band is: 31 15 1 + Current sample, line, band is: 32 15 1 + Current sample, line, band is: 33 15 1 + Current sample, line, band is: 34 15 1 + Current sample, line, band is: 35 15 1 + Current sample, line, band is: 36 15 1 + Current sample, line, band is: 37 15 1 + Current sample, line, band is: 38 15 1 + Current sample, line, band is: 39 15 1 + Current sample, line, band is: 40 15 1 + Current sample, line, band is: 41 15 1 + Current sample, line, band is: 42 15 1 + Current sample, line, band is: 43 15 1 + Current sample, line, band is: 44 15 1 + Current sample, line, band is: 45 15 1 + Current sample, line, band is: 46 15 1 + Current sample, line, band is: 47 15 1 + Current sample, line, band is: 48 15 1 + Current sample, line, band is: 49 15 1 + Current sample, line, band is: 50 15 1 + Current sample, line, band is: 51 15 1 + Current sample, line, band is: 52 15 1 + Current sample, line, band is: 53 15 1 + Current sample, line, band is: 54 15 1 + Current sample, line, band is: 55 15 1 + Current sample, line, band is: 56 15 1 + Current sample, line, band is: 57 15 1 + Current sample, line, band is: 58 15 1 + Current sample, line, band is: 59 15 1 + Current sample, line, band is: 60 15 1 + Current sample, line, band is: 61 15 1 + Current sample, line, band is: 62 15 1 + Current sample, line, band is: 63 15 1 + Current sample, line, band is: 64 15 1 + Current sample, line, band is: 65 15 1 + Current sample, line, band is: 66 15 1 + Current sample, line, band is: 67 15 1 + Current sample, line, band is: 68 15 1 + Current sample, line, band is: 69 15 1 + Current sample, line, band is: 70 15 1 + Current sample, line, band is: 71 15 1 + Current sample, line, band is: 72 15 1 + Current sample, line, band is: 73 15 1 + Current sample, line, band is: 74 15 1 + Current sample, line, band is: 75 15 1 + Current sample, line, band is: 76 15 1 + Current sample, line, band is: 77 15 1 + Current sample, line, band is: 78 15 1 + Current sample, line, band is: 79 15 1 + Current sample, line, band is: 80 15 1 + Current sample, line, band is: 81 15 1 + Current sample, line, band is: 82 15 1 + Current sample, line, band is: 83 15 1 + Current sample, line, band is: 84 15 1 + Current sample, line, band is: 85 15 1 + Current sample, line, band is: 86 15 1 + Current sample, line, band is: 87 15 1 + Current sample, line, band is: 88 15 1 + Current sample, line, band is: 89 15 1 + Current sample, line, band is: 90 15 1 + Current sample, line, band is: 91 15 1 + Current sample, line, band is: 92 15 1 + Current sample, line, band is: 93 15 1 + Current sample, line, band is: 94 15 1 + Current sample, line, band is: 95 15 1 + Current sample, line, band is: 96 15 1 + Current sample, line, band is: 97 15 1 + Current sample, line, band is: 98 15 1 + Current sample, line, band is: 99 15 1 + Current sample, line, band is: 100 15 1 + Current sample, line, band is: 101 15 1 + Current sample, line, band is: 102 15 1 + Current sample, line, band is: 103 15 1 + Current sample, line, band is: 104 15 1 + Current sample, line, band is: 105 15 1 + Current sample, line, band is: 106 15 1 + Current sample, line, band is: 107 15 1 + Current sample, line, band is: 108 15 1 + Current sample, line, band is: 109 15 1 + Current sample, line, band is: 110 15 1 + Current sample, line, band is: 111 15 1 + Current sample, line, band is: 112 15 1 + Current sample, line, band is: 113 15 1 + Current sample, line, band is: 114 15 1 + Current sample, line, band is: 115 15 1 + Current sample, line, band is: 116 15 1 + Current sample, line, band is: 117 15 1 + Current sample, line, band is: 118 15 1 + Current sample, line, band is: 119 15 1 + Current sample, line, band is: 120 15 1 + Current sample, line, band is: 121 15 1 + Current sample, line, band is: 122 15 1 + Current sample, line, band is: 123 15 1 + Current sample, line, band is: 124 15 1 + Current sample, line, band is: 125 15 1 + Current sample, line, band is: 126 15 1 + Current sample, line, band is: 1 16 1 + Current sample, line, band is: 2 16 1 + Current sample, line, band is: 3 16 1 + Current sample, line, band is: 4 16 1 + Current sample, line, band is: 5 16 1 + Current sample, line, band is: 6 16 1 + Current sample, line, band is: 7 16 1 + Current sample, line, band is: 8 16 1 + Current sample, line, band is: 9 16 1 + Current sample, line, band is: 10 16 1 + Current sample, line, band is: 11 16 1 + Current sample, line, band is: 12 16 1 + Current sample, line, band is: 13 16 1 + Current sample, line, band is: 14 16 1 + Current sample, line, band is: 15 16 1 + Current sample, line, band is: 16 16 1 + Current sample, line, band is: 17 16 1 + Current sample, line, band is: 18 16 1 + Current sample, line, band is: 19 16 1 + Current sample, line, band is: 20 16 1 + Current sample, line, band is: 21 16 1 + Current sample, line, band is: 22 16 1 + Current sample, line, band is: 23 16 1 + Current sample, line, band is: 24 16 1 + Current sample, line, band is: 25 16 1 + Current sample, line, band is: 26 16 1 + Current sample, line, band is: 27 16 1 + Current sample, line, band is: 28 16 1 + Current sample, line, band is: 29 16 1 + Current sample, line, band is: 30 16 1 + Current sample, line, band is: 31 16 1 + Current sample, line, band is: 32 16 1 + Current sample, line, band is: 33 16 1 + Current sample, line, band is: 34 16 1 + Current sample, line, band is: 35 16 1 + Current sample, line, band is: 36 16 1 + Current sample, line, band is: 37 16 1 + Current sample, line, band is: 38 16 1 + Current sample, line, band is: 39 16 1 + Current sample, line, band is: 40 16 1 + Current sample, line, band is: 41 16 1 + Current sample, line, band is: 42 16 1 + Current sample, line, band is: 43 16 1 + Current sample, line, band is: 44 16 1 + Current sample, line, band is: 45 16 1 + Current sample, line, band is: 46 16 1 + Current sample, line, band is: 47 16 1 + Current sample, line, band is: 48 16 1 + Current sample, line, band is: 49 16 1 + Current sample, line, band is: 50 16 1 + Current sample, line, band is: 51 16 1 + Current sample, line, band is: 52 16 1 + Current sample, line, band is: 53 16 1 + Current sample, line, band is: 54 16 1 + Current sample, line, band is: 55 16 1 + Current sample, line, band is: 56 16 1 + Current sample, line, band is: 57 16 1 + Current sample, line, band is: 58 16 1 + Current sample, line, band is: 59 16 1 + Current sample, line, band is: 60 16 1 + Current sample, line, band is: 61 16 1 + Current sample, line, band is: 62 16 1 + Current sample, line, band is: 63 16 1 + Current sample, line, band is: 64 16 1 + Current sample, line, band is: 65 16 1 + Current sample, line, band is: 66 16 1 + Current sample, line, band is: 67 16 1 + Current sample, line, band is: 68 16 1 + Current sample, line, band is: 69 16 1 + Current sample, line, band is: 70 16 1 + Current sample, line, band is: 71 16 1 + Current sample, line, band is: 72 16 1 + Current sample, line, band is: 73 16 1 + Current sample, line, band is: 74 16 1 + Current sample, line, band is: 75 16 1 + Current sample, line, band is: 76 16 1 + Current sample, line, band is: 77 16 1 + Current sample, line, band is: 78 16 1 + Current sample, line, band is: 79 16 1 + Current sample, line, band is: 80 16 1 + Current sample, line, band is: 81 16 1 + Current sample, line, band is: 82 16 1 + Current sample, line, band is: 83 16 1 + Current sample, line, band is: 84 16 1 + Current sample, line, band is: 85 16 1 + Current sample, line, band is: 86 16 1 + Current sample, line, band is: 87 16 1 + Current sample, line, band is: 88 16 1 + Current sample, line, band is: 89 16 1 + Current sample, line, band is: 90 16 1 + Current sample, line, band is: 91 16 1 + Current sample, line, band is: 92 16 1 + Current sample, line, band is: 93 16 1 + Current sample, line, band is: 94 16 1 + Current sample, line, band is: 95 16 1 + Current sample, line, band is: 96 16 1 + Current sample, line, band is: 97 16 1 + Current sample, line, band is: 98 16 1 + Current sample, line, band is: 99 16 1 + Current sample, line, band is: 100 16 1 + Current sample, line, band is: 101 16 1 + Current sample, line, band is: 102 16 1 + Current sample, line, band is: 103 16 1 + Current sample, line, band is: 104 16 1 + Current sample, line, band is: 105 16 1 + Current sample, line, band is: 106 16 1 + Current sample, line, band is: 107 16 1 + Current sample, line, band is: 108 16 1 + Current sample, line, band is: 109 16 1 + Current sample, line, band is: 110 16 1 + Current sample, line, band is: 111 16 1 + Current sample, line, band is: 112 16 1 + Current sample, line, band is: 113 16 1 + Current sample, line, band is: 114 16 1 + Current sample, line, band is: 115 16 1 + Current sample, line, band is: 116 16 1 + Current sample, line, band is: 117 16 1 + Current sample, line, band is: 118 16 1 + Current sample, line, band is: 119 16 1 + Current sample, line, band is: 120 16 1 + Current sample, line, band is: 121 16 1 + Current sample, line, band is: 122 16 1 + Current sample, line, band is: 123 16 1 + Current sample, line, band is: 124 16 1 + Current sample, line, band is: 125 16 1 + Current sample, line, band is: 126 16 1 + Current sample, line, band is: 1 17 1 + Current sample, line, band is: 2 17 1 + Current sample, line, band is: 3 17 1 + Current sample, line, band is: 4 17 1 + Current sample, line, band is: 5 17 1 + Current sample, line, band is: 6 17 1 + Current sample, line, band is: 7 17 1 + Current sample, line, band is: 8 17 1 + Current sample, line, band is: 9 17 1 + Current sample, line, band is: 10 17 1 + Current sample, line, band is: 11 17 1 + Current sample, line, band is: 12 17 1 + Current sample, line, band is: 13 17 1 + Current sample, line, band is: 14 17 1 + Current sample, line, band is: 15 17 1 + Current sample, line, band is: 16 17 1 + Current sample, line, band is: 17 17 1 + Current sample, line, band is: 18 17 1 + Current sample, line, band is: 19 17 1 + Current sample, line, band is: 20 17 1 + Current sample, line, band is: 21 17 1 + Current sample, line, band is: 22 17 1 + Current sample, line, band is: 23 17 1 + Current sample, line, band is: 24 17 1 + Current sample, line, band is: 25 17 1 + Current sample, line, band is: 26 17 1 + Current sample, line, band is: 27 17 1 + Current sample, line, band is: 28 17 1 + Current sample, line, band is: 29 17 1 + Current sample, line, band is: 30 17 1 + Current sample, line, band is: 31 17 1 + Current sample, line, band is: 32 17 1 + Current sample, line, band is: 33 17 1 + Current sample, line, band is: 34 17 1 + Current sample, line, band is: 35 17 1 + Current sample, line, band is: 36 17 1 + Current sample, line, band is: 37 17 1 + Current sample, line, band is: 38 17 1 + Current sample, line, band is: 39 17 1 + Current sample, line, band is: 40 17 1 + Current sample, line, band is: 41 17 1 + Current sample, line, band is: 42 17 1 + Current sample, line, band is: 43 17 1 + Current sample, line, band is: 44 17 1 + Current sample, line, band is: 45 17 1 + Current sample, line, band is: 46 17 1 + Current sample, line, band is: 47 17 1 + Current sample, line, band is: 48 17 1 + Current sample, line, band is: 49 17 1 + Current sample, line, band is: 50 17 1 + Current sample, line, band is: 51 17 1 + Current sample, line, band is: 52 17 1 + Current sample, line, band is: 53 17 1 + Current sample, line, band is: 54 17 1 + Current sample, line, band is: 55 17 1 + Current sample, line, band is: 56 17 1 + Current sample, line, band is: 57 17 1 + Current sample, line, band is: 58 17 1 + Current sample, line, band is: 59 17 1 + Current sample, line, band is: 60 17 1 + Current sample, line, band is: 61 17 1 + Current sample, line, band is: 62 17 1 + Current sample, line, band is: 63 17 1 + Current sample, line, band is: 64 17 1 + Current sample, line, band is: 65 17 1 + Current sample, line, band is: 66 17 1 + Current sample, line, band is: 67 17 1 + Current sample, line, band is: 68 17 1 + Current sample, line, band is: 69 17 1 + Current sample, line, band is: 70 17 1 + Current sample, line, band is: 71 17 1 + Current sample, line, band is: 72 17 1 + Current sample, line, band is: 73 17 1 + Current sample, line, band is: 74 17 1 + Current sample, line, band is: 75 17 1 + Current sample, line, band is: 76 17 1 + Current sample, line, band is: 77 17 1 + Current sample, line, band is: 78 17 1 + Current sample, line, band is: 79 17 1 + Current sample, line, band is: 80 17 1 + Current sample, line, band is: 81 17 1 + Current sample, line, band is: 82 17 1 + Current sample, line, band is: 83 17 1 + Current sample, line, band is: 84 17 1 + Current sample, line, band is: 85 17 1 + Current sample, line, band is: 86 17 1 + Current sample, line, band is: 87 17 1 + Current sample, line, band is: 88 17 1 + Current sample, line, band is: 89 17 1 + Current sample, line, band is: 90 17 1 + Current sample, line, band is: 91 17 1 + Current sample, line, band is: 92 17 1 + Current sample, line, band is: 93 17 1 + Current sample, line, band is: 94 17 1 + Current sample, line, band is: 95 17 1 + Current sample, line, band is: 96 17 1 + Current sample, line, band is: 97 17 1 + Current sample, line, band is: 98 17 1 + Current sample, line, band is: 99 17 1 + Current sample, line, band is: 100 17 1 + Current sample, line, band is: 101 17 1 + Current sample, line, band is: 102 17 1 + Current sample, line, band is: 103 17 1 + Current sample, line, band is: 104 17 1 + Current sample, line, band is: 105 17 1 + Current sample, line, band is: 106 17 1 + Current sample, line, band is: 107 17 1 + Current sample, line, band is: 108 17 1 + Current sample, line, band is: 109 17 1 + Current sample, line, band is: 110 17 1 + Current sample, line, band is: 111 17 1 + Current sample, line, band is: 112 17 1 + Current sample, line, band is: 113 17 1 + Current sample, line, band is: 114 17 1 + Current sample, line, band is: 115 17 1 + Current sample, line, band is: 116 17 1 + Current sample, line, band is: 117 17 1 + Current sample, line, band is: 118 17 1 + Current sample, line, band is: 119 17 1 + Current sample, line, band is: 120 17 1 + Current sample, line, band is: 121 17 1 + Current sample, line, band is: 122 17 1 + Current sample, line, band is: 123 17 1 + Current sample, line, band is: 124 17 1 + Current sample, line, band is: 125 17 1 + Current sample, line, band is: 126 17 1 + Current sample, line, band is: 1 18 1 + Current sample, line, band is: 2 18 1 + Current sample, line, band is: 3 18 1 + Current sample, line, band is: 4 18 1 + Current sample, line, band is: 5 18 1 + Current sample, line, band is: 6 18 1 + Current sample, line, band is: 7 18 1 + Current sample, line, band is: 8 18 1 + Current sample, line, band is: 9 18 1 + Current sample, line, band is: 10 18 1 + Current sample, line, band is: 11 18 1 + Current sample, line, band is: 12 18 1 + Current sample, line, band is: 13 18 1 + Current sample, line, band is: 14 18 1 + Current sample, line, band is: 15 18 1 + Current sample, line, band is: 16 18 1 + Current sample, line, band is: 17 18 1 + Current sample, line, band is: 18 18 1 + Current sample, line, band is: 19 18 1 + Current sample, line, band is: 20 18 1 + Current sample, line, band is: 21 18 1 + Current sample, line, band is: 22 18 1 + Current sample, line, band is: 23 18 1 + Current sample, line, band is: 24 18 1 + Current sample, line, band is: 25 18 1 + Current sample, line, band is: 26 18 1 + Current sample, line, band is: 27 18 1 + Current sample, line, band is: 28 18 1 + Current sample, line, band is: 29 18 1 + Current sample, line, band is: 30 18 1 + Current sample, line, band is: 31 18 1 + Current sample, line, band is: 32 18 1 + Current sample, line, band is: 33 18 1 + Current sample, line, band is: 34 18 1 + Current sample, line, band is: 35 18 1 + Current sample, line, band is: 36 18 1 + Current sample, line, band is: 37 18 1 + Current sample, line, band is: 38 18 1 + Current sample, line, band is: 39 18 1 + Current sample, line, band is: 40 18 1 + Current sample, line, band is: 41 18 1 + Current sample, line, band is: 42 18 1 + Current sample, line, band is: 43 18 1 + Current sample, line, band is: 44 18 1 + Current sample, line, band is: 45 18 1 + Current sample, line, band is: 46 18 1 + Current sample, line, band is: 47 18 1 + Current sample, line, band is: 48 18 1 + Current sample, line, band is: 49 18 1 + Current sample, line, band is: 50 18 1 + Current sample, line, band is: 51 18 1 + Current sample, line, band is: 52 18 1 + Current sample, line, band is: 53 18 1 + Current sample, line, band is: 54 18 1 + Current sample, line, band is: 55 18 1 + Current sample, line, band is: 56 18 1 + Current sample, line, band is: 57 18 1 + Current sample, line, band is: 58 18 1 + Current sample, line, band is: 59 18 1 + Current sample, line, band is: 60 18 1 + Current sample, line, band is: 61 18 1 + Current sample, line, band is: 62 18 1 + Current sample, line, band is: 63 18 1 + Current sample, line, band is: 64 18 1 + Current sample, line, band is: 65 18 1 + Current sample, line, band is: 66 18 1 + Current sample, line, band is: 67 18 1 + Current sample, line, band is: 68 18 1 + Current sample, line, band is: 69 18 1 + Current sample, line, band is: 70 18 1 + Current sample, line, band is: 71 18 1 + Current sample, line, band is: 72 18 1 + Current sample, line, band is: 73 18 1 + Current sample, line, band is: 74 18 1 + Current sample, line, band is: 75 18 1 + Current sample, line, band is: 76 18 1 + Current sample, line, band is: 77 18 1 + Current sample, line, band is: 78 18 1 + Current sample, line, band is: 79 18 1 + Current sample, line, band is: 80 18 1 + Current sample, line, band is: 81 18 1 + Current sample, line, band is: 82 18 1 + Current sample, line, band is: 83 18 1 + Current sample, line, band is: 84 18 1 + Current sample, line, band is: 85 18 1 + Current sample, line, band is: 86 18 1 + Current sample, line, band is: 87 18 1 + Current sample, line, band is: 88 18 1 + Current sample, line, band is: 89 18 1 + Current sample, line, band is: 90 18 1 + Current sample, line, band is: 91 18 1 + Current sample, line, band is: 92 18 1 + Current sample, line, band is: 93 18 1 + Current sample, line, band is: 94 18 1 + Current sample, line, band is: 95 18 1 + Current sample, line, band is: 96 18 1 + Current sample, line, band is: 97 18 1 + Current sample, line, band is: 98 18 1 + Current sample, line, band is: 99 18 1 + Current sample, line, band is: 100 18 1 + Current sample, line, band is: 101 18 1 + Current sample, line, band is: 102 18 1 + Current sample, line, band is: 103 18 1 + Current sample, line, band is: 104 18 1 + Current sample, line, band is: 105 18 1 + Current sample, line, band is: 106 18 1 + Current sample, line, band is: 107 18 1 + Current sample, line, band is: 108 18 1 + Current sample, line, band is: 109 18 1 + Current sample, line, band is: 110 18 1 + Current sample, line, band is: 111 18 1 + Current sample, line, band is: 112 18 1 + Current sample, line, band is: 113 18 1 + Current sample, line, band is: 114 18 1 + Current sample, line, band is: 115 18 1 + Current sample, line, band is: 116 18 1 + Current sample, line, band is: 117 18 1 + Current sample, line, band is: 118 18 1 + Current sample, line, band is: 119 18 1 + Current sample, line, band is: 120 18 1 + Current sample, line, band is: 121 18 1 + Current sample, line, band is: 122 18 1 + Current sample, line, band is: 123 18 1 + Current sample, line, band is: 124 18 1 + Current sample, line, band is: 125 18 1 + Current sample, line, band is: 126 18 1 + Current sample, line, band is: 1 19 1 + Current sample, line, band is: 2 19 1 + Current sample, line, band is: 3 19 1 + Current sample, line, band is: 4 19 1 + Current sample, line, band is: 5 19 1 + Current sample, line, band is: 6 19 1 + Current sample, line, band is: 7 19 1 + Current sample, line, band is: 8 19 1 + Current sample, line, band is: 9 19 1 + Current sample, line, band is: 10 19 1 + Current sample, line, band is: 11 19 1 + Current sample, line, band is: 12 19 1 + Current sample, line, band is: 13 19 1 + Current sample, line, band is: 14 19 1 + Current sample, line, band is: 15 19 1 + Current sample, line, band is: 16 19 1 + Current sample, line, band is: 17 19 1 + Current sample, line, band is: 18 19 1 + Current sample, line, band is: 19 19 1 + Current sample, line, band is: 20 19 1 + Current sample, line, band is: 21 19 1 + Current sample, line, band is: 22 19 1 + Current sample, line, band is: 23 19 1 + Current sample, line, band is: 24 19 1 + Current sample, line, band is: 25 19 1 + Current sample, line, band is: 26 19 1 + Current sample, line, band is: 27 19 1 + Current sample, line, band is: 28 19 1 + Current sample, line, band is: 29 19 1 + Current sample, line, band is: 30 19 1 + Current sample, line, band is: 31 19 1 + Current sample, line, band is: 32 19 1 + Current sample, line, band is: 33 19 1 + Current sample, line, band is: 34 19 1 + Current sample, line, band is: 35 19 1 + Current sample, line, band is: 36 19 1 + Current sample, line, band is: 37 19 1 + Current sample, line, band is: 38 19 1 + Current sample, line, band is: 39 19 1 + Current sample, line, band is: 40 19 1 + Current sample, line, band is: 41 19 1 + Current sample, line, band is: 42 19 1 + Current sample, line, band is: 43 19 1 + Current sample, line, band is: 44 19 1 + Current sample, line, band is: 45 19 1 + Current sample, line, band is: 46 19 1 + Current sample, line, band is: 47 19 1 + Current sample, line, band is: 48 19 1 + Current sample, line, band is: 49 19 1 + Current sample, line, band is: 50 19 1 + Current sample, line, band is: 51 19 1 + Current sample, line, band is: 52 19 1 + Current sample, line, band is: 53 19 1 + Current sample, line, band is: 54 19 1 + Current sample, line, band is: 55 19 1 + Current sample, line, band is: 56 19 1 + Current sample, line, band is: 57 19 1 + Current sample, line, band is: 58 19 1 + Current sample, line, band is: 59 19 1 + Current sample, line, band is: 60 19 1 + Current sample, line, band is: 61 19 1 + Current sample, line, band is: 62 19 1 + Current sample, line, band is: 63 19 1 + Current sample, line, band is: 64 19 1 + Current sample, line, band is: 65 19 1 + Current sample, line, band is: 66 19 1 + Current sample, line, band is: 67 19 1 + Current sample, line, band is: 68 19 1 + Current sample, line, band is: 69 19 1 + Current sample, line, band is: 70 19 1 + Current sample, line, band is: 71 19 1 + Current sample, line, band is: 72 19 1 + Current sample, line, band is: 73 19 1 + Current sample, line, band is: 74 19 1 + Current sample, line, band is: 75 19 1 + Current sample, line, band is: 76 19 1 + Current sample, line, band is: 77 19 1 + Current sample, line, band is: 78 19 1 + Current sample, line, band is: 79 19 1 + Current sample, line, band is: 80 19 1 + Current sample, line, band is: 81 19 1 + Current sample, line, band is: 82 19 1 + Current sample, line, band is: 83 19 1 + Current sample, line, band is: 84 19 1 + Current sample, line, band is: 85 19 1 + Current sample, line, band is: 86 19 1 + Current sample, line, band is: 87 19 1 + Current sample, line, band is: 88 19 1 + Current sample, line, band is: 89 19 1 + Current sample, line, band is: 90 19 1 + Current sample, line, band is: 91 19 1 + Current sample, line, band is: 92 19 1 + Current sample, line, band is: 93 19 1 + Current sample, line, band is: 94 19 1 + Current sample, line, band is: 95 19 1 + Current sample, line, band is: 96 19 1 + Current sample, line, band is: 97 19 1 + Current sample, line, band is: 98 19 1 + Current sample, line, band is: 99 19 1 + Current sample, line, band is: 100 19 1 + Current sample, line, band is: 101 19 1 + Current sample, line, band is: 102 19 1 + Current sample, line, band is: 103 19 1 + Current sample, line, band is: 104 19 1 + Current sample, line, band is: 105 19 1 + Current sample, line, band is: 106 19 1 + Current sample, line, band is: 107 19 1 + Current sample, line, band is: 108 19 1 + Current sample, line, band is: 109 19 1 + Current sample, line, band is: 110 19 1 + Current sample, line, band is: 111 19 1 + Current sample, line, band is: 112 19 1 + Current sample, line, band is: 113 19 1 + Current sample, line, band is: 114 19 1 + Current sample, line, band is: 115 19 1 + Current sample, line, band is: 116 19 1 + Current sample, line, band is: 117 19 1 + Current sample, line, band is: 118 19 1 + Current sample, line, band is: 119 19 1 + Current sample, line, band is: 120 19 1 + Current sample, line, band is: 121 19 1 + Current sample, line, band is: 122 19 1 + Current sample, line, band is: 123 19 1 + Current sample, line, band is: 124 19 1 + Current sample, line, band is: 125 19 1 + Current sample, line, band is: 126 19 1 + Current sample, line, band is: 1 20 1 + Current sample, line, band is: 2 20 1 + Current sample, line, band is: 3 20 1 + Current sample, line, band is: 4 20 1 + Current sample, line, band is: 5 20 1 + Current sample, line, band is: 6 20 1 + Current sample, line, band is: 7 20 1 + Current sample, line, band is: 8 20 1 + Current sample, line, band is: 9 20 1 + Current sample, line, band is: 10 20 1 + Current sample, line, band is: 11 20 1 + Current sample, line, band is: 12 20 1 + Current sample, line, band is: 13 20 1 + Current sample, line, band is: 14 20 1 + Current sample, line, band is: 15 20 1 + Current sample, line, band is: 16 20 1 + Current sample, line, band is: 17 20 1 + Current sample, line, band is: 18 20 1 + Current sample, line, band is: 19 20 1 + Current sample, line, band is: 20 20 1 + Current sample, line, band is: 21 20 1 + Current sample, line, band is: 22 20 1 + Current sample, line, band is: 23 20 1 + Current sample, line, band is: 24 20 1 + Current sample, line, band is: 25 20 1 + Current sample, line, band is: 26 20 1 + Current sample, line, band is: 27 20 1 + Current sample, line, band is: 28 20 1 + Current sample, line, band is: 29 20 1 + Current sample, line, band is: 30 20 1 + Current sample, line, band is: 31 20 1 + Current sample, line, band is: 32 20 1 + Current sample, line, band is: 33 20 1 + Current sample, line, band is: 34 20 1 + Current sample, line, band is: 35 20 1 + Current sample, line, band is: 36 20 1 + Current sample, line, band is: 37 20 1 + Current sample, line, band is: 38 20 1 + Current sample, line, band is: 39 20 1 + Current sample, line, band is: 40 20 1 + Current sample, line, band is: 41 20 1 + Current sample, line, band is: 42 20 1 + Current sample, line, band is: 43 20 1 + Current sample, line, band is: 44 20 1 + Current sample, line, band is: 45 20 1 + Current sample, line, band is: 46 20 1 + Current sample, line, band is: 47 20 1 + Current sample, line, band is: 48 20 1 + Current sample, line, band is: 49 20 1 + Current sample, line, band is: 50 20 1 + Current sample, line, band is: 51 20 1 + Current sample, line, band is: 52 20 1 + Current sample, line, band is: 53 20 1 + Current sample, line, band is: 54 20 1 + Current sample, line, band is: 55 20 1 + Current sample, line, band is: 56 20 1 + Current sample, line, band is: 57 20 1 + Current sample, line, band is: 58 20 1 + Current sample, line, band is: 59 20 1 + Current sample, line, band is: 60 20 1 + Current sample, line, band is: 61 20 1 + Current sample, line, band is: 62 20 1 + Current sample, line, band is: 63 20 1 + Current sample, line, band is: 64 20 1 + Current sample, line, band is: 65 20 1 + Current sample, line, band is: 66 20 1 + Current sample, line, band is: 67 20 1 + Current sample, line, band is: 68 20 1 + Current sample, line, band is: 69 20 1 + Current sample, line, band is: 70 20 1 + Current sample, line, band is: 71 20 1 + Current sample, line, band is: 72 20 1 + Current sample, line, band is: 73 20 1 + Current sample, line, band is: 74 20 1 + Current sample, line, band is: 75 20 1 + Current sample, line, band is: 76 20 1 + Current sample, line, band is: 77 20 1 + Current sample, line, band is: 78 20 1 + Current sample, line, band is: 79 20 1 + Current sample, line, band is: 80 20 1 + Current sample, line, band is: 81 20 1 + Current sample, line, band is: 82 20 1 + Current sample, line, band is: 83 20 1 + Current sample, line, band is: 84 20 1 + Current sample, line, band is: 85 20 1 + Current sample, line, band is: 86 20 1 + Current sample, line, band is: 87 20 1 + Current sample, line, band is: 88 20 1 + Current sample, line, band is: 89 20 1 + Current sample, line, band is: 90 20 1 + Current sample, line, band is: 91 20 1 + Current sample, line, band is: 92 20 1 + Current sample, line, band is: 93 20 1 + Current sample, line, band is: 94 20 1 + Current sample, line, band is: 95 20 1 + Current sample, line, band is: 96 20 1 + Current sample, line, band is: 97 20 1 + Current sample, line, band is: 98 20 1 + Current sample, line, band is: 99 20 1 + Current sample, line, band is: 100 20 1 + Current sample, line, band is: 101 20 1 + Current sample, line, band is: 102 20 1 + Current sample, line, band is: 103 20 1 + Current sample, line, band is: 104 20 1 + Current sample, line, band is: 105 20 1 + Current sample, line, band is: 106 20 1 + Current sample, line, band is: 107 20 1 + Current sample, line, band is: 108 20 1 + Current sample, line, band is: 109 20 1 + Current sample, line, band is: 110 20 1 + Current sample, line, band is: 111 20 1 + Current sample, line, band is: 112 20 1 + Current sample, line, band is: 113 20 1 + Current sample, line, band is: 114 20 1 + Current sample, line, band is: 115 20 1 + Current sample, line, band is: 116 20 1 + Current sample, line, band is: 117 20 1 + Current sample, line, band is: 118 20 1 + Current sample, line, band is: 119 20 1 + Current sample, line, band is: 120 20 1 + Current sample, line, band is: 121 20 1 + Current sample, line, band is: 122 20 1 + Current sample, line, band is: 123 20 1 + Current sample, line, band is: 124 20 1 + Current sample, line, band is: 125 20 1 + Current sample, line, band is: 126 20 1 + Current sample, line, band is: 1 21 1 + Current sample, line, band is: 2 21 1 + Current sample, line, band is: 3 21 1 + Current sample, line, band is: 4 21 1 + Current sample, line, band is: 5 21 1 + Current sample, line, band is: 6 21 1 + Current sample, line, band is: 7 21 1 + Current sample, line, band is: 8 21 1 + Current sample, line, band is: 9 21 1 + Current sample, line, band is: 10 21 1 + Current sample, line, band is: 11 21 1 + Current sample, line, band is: 12 21 1 + Current sample, line, band is: 13 21 1 + Current sample, line, band is: 14 21 1 + Current sample, line, band is: 15 21 1 + Current sample, line, band is: 16 21 1 + Current sample, line, band is: 17 21 1 + Current sample, line, band is: 18 21 1 + Current sample, line, band is: 19 21 1 + Current sample, line, band is: 20 21 1 + Current sample, line, band is: 21 21 1 + Current sample, line, band is: 22 21 1 + Current sample, line, band is: 23 21 1 + Current sample, line, band is: 24 21 1 + Current sample, line, band is: 25 21 1 + Current sample, line, band is: 26 21 1 + Current sample, line, band is: 27 21 1 + Current sample, line, band is: 28 21 1 + Current sample, line, band is: 29 21 1 + Current sample, line, band is: 30 21 1 + Current sample, line, band is: 31 21 1 + Current sample, line, band is: 32 21 1 + Current sample, line, band is: 33 21 1 + Current sample, line, band is: 34 21 1 + Current sample, line, band is: 35 21 1 + Current sample, line, band is: 36 21 1 + Current sample, line, band is: 37 21 1 + Current sample, line, band is: 38 21 1 + Current sample, line, band is: 39 21 1 + Current sample, line, band is: 40 21 1 + Current sample, line, band is: 41 21 1 + Current sample, line, band is: 42 21 1 + Current sample, line, band is: 43 21 1 + Current sample, line, band is: 44 21 1 + Current sample, line, band is: 45 21 1 + Current sample, line, band is: 46 21 1 + Current sample, line, band is: 47 21 1 + Current sample, line, band is: 48 21 1 + Current sample, line, band is: 49 21 1 + Current sample, line, band is: 50 21 1 + Current sample, line, band is: 51 21 1 + Current sample, line, band is: 52 21 1 + Current sample, line, band is: 53 21 1 + Current sample, line, band is: 54 21 1 + Current sample, line, band is: 55 21 1 + Current sample, line, band is: 56 21 1 + Current sample, line, band is: 57 21 1 + Current sample, line, band is: 58 21 1 + Current sample, line, band is: 59 21 1 + Current sample, line, band is: 60 21 1 + Current sample, line, band is: 61 21 1 + Current sample, line, band is: 62 21 1 + Current sample, line, band is: 63 21 1 + Current sample, line, band is: 64 21 1 + Current sample, line, band is: 65 21 1 + Current sample, line, band is: 66 21 1 + Current sample, line, band is: 67 21 1 + Current sample, line, band is: 68 21 1 + Current sample, line, band is: 69 21 1 + Current sample, line, band is: 70 21 1 + Current sample, line, band is: 71 21 1 + Current sample, line, band is: 72 21 1 + Current sample, line, band is: 73 21 1 + Current sample, line, band is: 74 21 1 + Current sample, line, band is: 75 21 1 + Current sample, line, band is: 76 21 1 + Current sample, line, band is: 77 21 1 + Current sample, line, band is: 78 21 1 + Current sample, line, band is: 79 21 1 + Current sample, line, band is: 80 21 1 + Current sample, line, band is: 81 21 1 + Current sample, line, band is: 82 21 1 + Current sample, line, band is: 83 21 1 + Current sample, line, band is: 84 21 1 + Current sample, line, band is: 85 21 1 + Current sample, line, band is: 86 21 1 + Current sample, line, band is: 87 21 1 + Current sample, line, band is: 88 21 1 + Current sample, line, band is: 89 21 1 + Current sample, line, band is: 90 21 1 + Current sample, line, band is: 91 21 1 + Current sample, line, band is: 92 21 1 + Current sample, line, band is: 93 21 1 + Current sample, line, band is: 94 21 1 + Current sample, line, band is: 95 21 1 + Current sample, line, band is: 96 21 1 + Current sample, line, band is: 97 21 1 + Current sample, line, band is: 98 21 1 + Current sample, line, band is: 99 21 1 + Current sample, line, band is: 100 21 1 + Current sample, line, band is: 101 21 1 + Current sample, line, band is: 102 21 1 + Current sample, line, band is: 103 21 1 + Current sample, line, band is: 104 21 1 + Current sample, line, band is: 105 21 1 + Current sample, line, band is: 106 21 1 + Current sample, line, band is: 107 21 1 + Current sample, line, band is: 108 21 1 + Current sample, line, band is: 109 21 1 + Current sample, line, band is: 110 21 1 + Current sample, line, band is: 111 21 1 + Current sample, line, band is: 112 21 1 + Current sample, line, band is: 113 21 1 + Current sample, line, band is: 114 21 1 + Current sample, line, band is: 115 21 1 + Current sample, line, band is: 116 21 1 + Current sample, line, band is: 117 21 1 + Current sample, line, band is: 118 21 1 + Current sample, line, band is: 119 21 1 + Current sample, line, band is: 120 21 1 + Current sample, line, band is: 121 21 1 + Current sample, line, band is: 122 21 1 + Current sample, line, band is: 123 21 1 + Current sample, line, band is: 124 21 1 + Current sample, line, band is: 125 21 1 + Current sample, line, band is: 126 21 1 + Current sample, line, band is: 1 22 1 + Current sample, line, band is: 2 22 1 + Current sample, line, band is: 3 22 1 + Current sample, line, band is: 4 22 1 + Current sample, line, band is: 5 22 1 + Current sample, line, band is: 6 22 1 + Current sample, line, band is: 7 22 1 + Current sample, line, band is: 8 22 1 + Current sample, line, band is: 9 22 1 + Current sample, line, band is: 10 22 1 + Current sample, line, band is: 11 22 1 + Current sample, line, band is: 12 22 1 + Current sample, line, band is: 13 22 1 + Current sample, line, band is: 14 22 1 + Current sample, line, band is: 15 22 1 + Current sample, line, band is: 16 22 1 + Current sample, line, band is: 17 22 1 + Current sample, line, band is: 18 22 1 + Current sample, line, band is: 19 22 1 + Current sample, line, band is: 20 22 1 + Current sample, line, band is: 21 22 1 + Current sample, line, band is: 22 22 1 + Current sample, line, band is: 23 22 1 + Current sample, line, band is: 24 22 1 + Current sample, line, band is: 25 22 1 + Current sample, line, band is: 26 22 1 + Current sample, line, band is: 27 22 1 + Current sample, line, band is: 28 22 1 + Current sample, line, band is: 29 22 1 + Current sample, line, band is: 30 22 1 + Current sample, line, band is: 31 22 1 + Current sample, line, band is: 32 22 1 + Current sample, line, band is: 33 22 1 + Current sample, line, band is: 34 22 1 + Current sample, line, band is: 35 22 1 + Current sample, line, band is: 36 22 1 + Current sample, line, band is: 37 22 1 + Current sample, line, band is: 38 22 1 + Current sample, line, band is: 39 22 1 + Current sample, line, band is: 40 22 1 + Current sample, line, band is: 41 22 1 + Current sample, line, band is: 42 22 1 + Current sample, line, band is: 43 22 1 + Current sample, line, band is: 44 22 1 + Current sample, line, band is: 45 22 1 + Current sample, line, band is: 46 22 1 + Current sample, line, band is: 47 22 1 + Current sample, line, band is: 48 22 1 + Current sample, line, band is: 49 22 1 + Current sample, line, band is: 50 22 1 + Current sample, line, band is: 51 22 1 + Current sample, line, band is: 52 22 1 + Current sample, line, band is: 53 22 1 + Current sample, line, band is: 54 22 1 + Current sample, line, band is: 55 22 1 + Current sample, line, band is: 56 22 1 + Current sample, line, band is: 57 22 1 + Current sample, line, band is: 58 22 1 + Current sample, line, band is: 59 22 1 + Current sample, line, band is: 60 22 1 + Current sample, line, band is: 61 22 1 + Current sample, line, band is: 62 22 1 + Current sample, line, band is: 63 22 1 + Current sample, line, band is: 64 22 1 + Current sample, line, band is: 65 22 1 + Current sample, line, band is: 66 22 1 + Current sample, line, band is: 67 22 1 + Current sample, line, band is: 68 22 1 + Current sample, line, band is: 69 22 1 + Current sample, line, band is: 70 22 1 + Current sample, line, band is: 71 22 1 + Current sample, line, band is: 72 22 1 + Current sample, line, band is: 73 22 1 + Current sample, line, band is: 74 22 1 + Current sample, line, band is: 75 22 1 + Current sample, line, band is: 76 22 1 + Current sample, line, band is: 77 22 1 + Current sample, line, band is: 78 22 1 + Current sample, line, band is: 79 22 1 + Current sample, line, band is: 80 22 1 + Current sample, line, band is: 81 22 1 + Current sample, line, band is: 82 22 1 + Current sample, line, band is: 83 22 1 + Current sample, line, band is: 84 22 1 + Current sample, line, band is: 85 22 1 + Current sample, line, band is: 86 22 1 + Current sample, line, band is: 87 22 1 + Current sample, line, band is: 88 22 1 + Current sample, line, band is: 89 22 1 + Current sample, line, band is: 90 22 1 + Current sample, line, band is: 91 22 1 + Current sample, line, band is: 92 22 1 + Current sample, line, band is: 93 22 1 + Current sample, line, band is: 94 22 1 + Current sample, line, band is: 95 22 1 + Current sample, line, band is: 96 22 1 + Current sample, line, band is: 97 22 1 + Current sample, line, band is: 98 22 1 + Current sample, line, band is: 99 22 1 + Current sample, line, band is: 100 22 1 + Current sample, line, band is: 101 22 1 + Current sample, line, band is: 102 22 1 + Current sample, line, band is: 103 22 1 + Current sample, line, band is: 104 22 1 + Current sample, line, band is: 105 22 1 + Current sample, line, band is: 106 22 1 + Current sample, line, band is: 107 22 1 + Current sample, line, band is: 108 22 1 + Current sample, line, band is: 109 22 1 + Current sample, line, band is: 110 22 1 + Current sample, line, band is: 111 22 1 + Current sample, line, band is: 112 22 1 + Current sample, line, band is: 113 22 1 + Current sample, line, band is: 114 22 1 + Current sample, line, band is: 115 22 1 + Current sample, line, band is: 116 22 1 + Current sample, line, band is: 117 22 1 + Current sample, line, band is: 118 22 1 + Current sample, line, band is: 119 22 1 + Current sample, line, band is: 120 22 1 + Current sample, line, band is: 121 22 1 + Current sample, line, band is: 122 22 1 + Current sample, line, band is: 123 22 1 + Current sample, line, band is: 124 22 1 + Current sample, line, band is: 125 22 1 + Current sample, line, band is: 126 22 1 + Current sample, line, band is: 1 23 1 + Current sample, line, band is: 2 23 1 + Current sample, line, band is: 3 23 1 + Current sample, line, band is: 4 23 1 + Current sample, line, band is: 5 23 1 + Current sample, line, band is: 6 23 1 + Current sample, line, band is: 7 23 1 + Current sample, line, band is: 8 23 1 + Current sample, line, band is: 9 23 1 + Current sample, line, band is: 10 23 1 + Current sample, line, band is: 11 23 1 + Current sample, line, band is: 12 23 1 + Current sample, line, band is: 13 23 1 + Current sample, line, band is: 14 23 1 + Current sample, line, band is: 15 23 1 + Current sample, line, band is: 16 23 1 + Current sample, line, band is: 17 23 1 + Current sample, line, band is: 18 23 1 + Current sample, line, band is: 19 23 1 + Current sample, line, band is: 20 23 1 + Current sample, line, band is: 21 23 1 + Current sample, line, band is: 22 23 1 + Current sample, line, band is: 23 23 1 + Current sample, line, band is: 24 23 1 + Current sample, line, band is: 25 23 1 + Current sample, line, band is: 26 23 1 + Current sample, line, band is: 27 23 1 + Current sample, line, band is: 28 23 1 + Current sample, line, band is: 29 23 1 + Current sample, line, band is: 30 23 1 + Current sample, line, band is: 31 23 1 + Current sample, line, band is: 32 23 1 + Current sample, line, band is: 33 23 1 + Current sample, line, band is: 34 23 1 + Current sample, line, band is: 35 23 1 + Current sample, line, band is: 36 23 1 + Current sample, line, band is: 37 23 1 + Current sample, line, band is: 38 23 1 + Current sample, line, band is: 39 23 1 + Current sample, line, band is: 40 23 1 + Current sample, line, band is: 41 23 1 + Current sample, line, band is: 42 23 1 + Current sample, line, band is: 43 23 1 + Current sample, line, band is: 44 23 1 + Current sample, line, band is: 45 23 1 + Current sample, line, band is: 46 23 1 + Current sample, line, band is: 47 23 1 + Current sample, line, band is: 48 23 1 + Current sample, line, band is: 49 23 1 + Current sample, line, band is: 50 23 1 + Current sample, line, band is: 51 23 1 + Current sample, line, band is: 52 23 1 + Current sample, line, band is: 53 23 1 + Current sample, line, band is: 54 23 1 + Current sample, line, band is: 55 23 1 + Current sample, line, band is: 56 23 1 + Current sample, line, band is: 57 23 1 + Current sample, line, band is: 58 23 1 + Current sample, line, band is: 59 23 1 + Current sample, line, band is: 60 23 1 + Current sample, line, band is: 61 23 1 + Current sample, line, band is: 62 23 1 + Current sample, line, band is: 63 23 1 + Current sample, line, band is: 64 23 1 + Current sample, line, band is: 65 23 1 + Current sample, line, band is: 66 23 1 + Current sample, line, band is: 67 23 1 + Current sample, line, band is: 68 23 1 + Current sample, line, band is: 69 23 1 + Current sample, line, band is: 70 23 1 + Current sample, line, band is: 71 23 1 + Current sample, line, band is: 72 23 1 + Current sample, line, band is: 73 23 1 + Current sample, line, band is: 74 23 1 + Current sample, line, band is: 75 23 1 + Current sample, line, band is: 76 23 1 + Current sample, line, band is: 77 23 1 + Current sample, line, band is: 78 23 1 + Current sample, line, band is: 79 23 1 + Current sample, line, band is: 80 23 1 + Current sample, line, band is: 81 23 1 + Current sample, line, band is: 82 23 1 + Current sample, line, band is: 83 23 1 + Current sample, line, band is: 84 23 1 + Current sample, line, band is: 85 23 1 + Current sample, line, band is: 86 23 1 + Current sample, line, band is: 87 23 1 + Current sample, line, band is: 88 23 1 + Current sample, line, band is: 89 23 1 + Current sample, line, band is: 90 23 1 + Current sample, line, band is: 91 23 1 + Current sample, line, band is: 92 23 1 + Current sample, line, band is: 93 23 1 + Current sample, line, band is: 94 23 1 + Current sample, line, band is: 95 23 1 + Current sample, line, band is: 96 23 1 + Current sample, line, band is: 97 23 1 + Current sample, line, band is: 98 23 1 + Current sample, line, band is: 99 23 1 + Current sample, line, band is: 100 23 1 + Current sample, line, band is: 101 23 1 + Current sample, line, band is: 102 23 1 + Current sample, line, band is: 103 23 1 + Current sample, line, band is: 104 23 1 + Current sample, line, band is: 105 23 1 + Current sample, line, band is: 106 23 1 + Current sample, line, band is: 107 23 1 + Current sample, line, band is: 108 23 1 + Current sample, line, band is: 109 23 1 + Current sample, line, band is: 110 23 1 + Current sample, line, band is: 111 23 1 + Current sample, line, band is: 112 23 1 + Current sample, line, band is: 113 23 1 + Current sample, line, band is: 114 23 1 + Current sample, line, band is: 115 23 1 + Current sample, line, band is: 116 23 1 + Current sample, line, band is: 117 23 1 + Current sample, line, band is: 118 23 1 + Current sample, line, band is: 119 23 1 + Current sample, line, band is: 120 23 1 + Current sample, line, band is: 121 23 1 + Current sample, line, band is: 122 23 1 + Current sample, line, band is: 123 23 1 + Current sample, line, band is: 124 23 1 + Current sample, line, band is: 125 23 1 + Current sample, line, band is: 126 23 1 + Current sample, line, band is: 1 24 1 + Current sample, line, band is: 2 24 1 + Current sample, line, band is: 3 24 1 + Current sample, line, band is: 4 24 1 + Current sample, line, band is: 5 24 1 + Current sample, line, band is: 6 24 1 + Current sample, line, band is: 7 24 1 + Current sample, line, band is: 8 24 1 + Current sample, line, band is: 9 24 1 + Current sample, line, band is: 10 24 1 + Current sample, line, band is: 11 24 1 + Current sample, line, band is: 12 24 1 + Current sample, line, band is: 13 24 1 + Current sample, line, band is: 14 24 1 + Current sample, line, band is: 15 24 1 + Current sample, line, band is: 16 24 1 + Current sample, line, band is: 17 24 1 + Current sample, line, band is: 18 24 1 + Current sample, line, band is: 19 24 1 + Current sample, line, band is: 20 24 1 + Current sample, line, band is: 21 24 1 + Current sample, line, band is: 22 24 1 + Current sample, line, band is: 23 24 1 + Current sample, line, band is: 24 24 1 + Current sample, line, band is: 25 24 1 + Current sample, line, band is: 26 24 1 + Current sample, line, band is: 27 24 1 + Current sample, line, band is: 28 24 1 + Current sample, line, band is: 29 24 1 + Current sample, line, band is: 30 24 1 + Current sample, line, band is: 31 24 1 + Current sample, line, band is: 32 24 1 + Current sample, line, band is: 33 24 1 + Current sample, line, band is: 34 24 1 + Current sample, line, band is: 35 24 1 + Current sample, line, band is: 36 24 1 + Current sample, line, band is: 37 24 1 + Current sample, line, band is: 38 24 1 + Current sample, line, band is: 39 24 1 + Current sample, line, band is: 40 24 1 + Current sample, line, band is: 41 24 1 + Current sample, line, band is: 42 24 1 + Current sample, line, band is: 43 24 1 + Current sample, line, band is: 44 24 1 + Current sample, line, band is: 45 24 1 + Current sample, line, band is: 46 24 1 + Current sample, line, band is: 47 24 1 + Current sample, line, band is: 48 24 1 + Current sample, line, band is: 49 24 1 + Current sample, line, band is: 50 24 1 + Current sample, line, band is: 51 24 1 + Current sample, line, band is: 52 24 1 + Current sample, line, band is: 53 24 1 + Current sample, line, band is: 54 24 1 + Current sample, line, band is: 55 24 1 + Current sample, line, band is: 56 24 1 + Current sample, line, band is: 57 24 1 + Current sample, line, band is: 58 24 1 + Current sample, line, band is: 59 24 1 + Current sample, line, band is: 60 24 1 + Current sample, line, band is: 61 24 1 + Current sample, line, band is: 62 24 1 + Current sample, line, band is: 63 24 1 + Current sample, line, band is: 64 24 1 + Current sample, line, band is: 65 24 1 + Current sample, line, band is: 66 24 1 + Current sample, line, band is: 67 24 1 + Current sample, line, band is: 68 24 1 + Current sample, line, band is: 69 24 1 + Current sample, line, band is: 70 24 1 + Current sample, line, band is: 71 24 1 + Current sample, line, band is: 72 24 1 + Current sample, line, band is: 73 24 1 + Current sample, line, band is: 74 24 1 + Current sample, line, band is: 75 24 1 + Current sample, line, band is: 76 24 1 + Current sample, line, band is: 77 24 1 + Current sample, line, band is: 78 24 1 + Current sample, line, band is: 79 24 1 + Current sample, line, band is: 80 24 1 + Current sample, line, band is: 81 24 1 + Current sample, line, band is: 82 24 1 + Current sample, line, band is: 83 24 1 + Current sample, line, band is: 84 24 1 + Current sample, line, band is: 85 24 1 + Current sample, line, band is: 86 24 1 + Current sample, line, band is: 87 24 1 + Current sample, line, band is: 88 24 1 + Current sample, line, band is: 89 24 1 + Current sample, line, band is: 90 24 1 + Current sample, line, band is: 91 24 1 + Current sample, line, band is: 92 24 1 + Current sample, line, band is: 93 24 1 + Current sample, line, band is: 94 24 1 + Current sample, line, band is: 95 24 1 + Current sample, line, band is: 96 24 1 + Current sample, line, band is: 97 24 1 + Current sample, line, band is: 98 24 1 + Current sample, line, band is: 99 24 1 + Current sample, line, band is: 100 24 1 + Current sample, line, band is: 101 24 1 + Current sample, line, band is: 102 24 1 + Current sample, line, band is: 103 24 1 + Current sample, line, band is: 104 24 1 + Current sample, line, band is: 105 24 1 + Current sample, line, band is: 106 24 1 + Current sample, line, band is: 107 24 1 + Current sample, line, band is: 108 24 1 + Current sample, line, band is: 109 24 1 + Current sample, line, band is: 110 24 1 + Current sample, line, band is: 111 24 1 + Current sample, line, band is: 112 24 1 + Current sample, line, band is: 113 24 1 + Current sample, line, band is: 114 24 1 + Current sample, line, band is: 115 24 1 + Current sample, line, band is: 116 24 1 + Current sample, line, band is: 117 24 1 + Current sample, line, band is: 118 24 1 + Current sample, line, band is: 119 24 1 + Current sample, line, band is: 120 24 1 + Current sample, line, band is: 121 24 1 + Current sample, line, band is: 122 24 1 + Current sample, line, band is: 123 24 1 + Current sample, line, band is: 124 24 1 + Current sample, line, band is: 125 24 1 + Current sample, line, band is: 126 24 1 + Current sample, line, band is: 1 25 1 + Current sample, line, band is: 2 25 1 + Current sample, line, band is: 3 25 1 + Current sample, line, band is: 4 25 1 + Current sample, line, band is: 5 25 1 + Current sample, line, band is: 6 25 1 + Current sample, line, band is: 7 25 1 + Current sample, line, band is: 8 25 1 + Current sample, line, band is: 9 25 1 + Current sample, line, band is: 10 25 1 + Current sample, line, band is: 11 25 1 + Current sample, line, band is: 12 25 1 + Current sample, line, band is: 13 25 1 + Current sample, line, band is: 14 25 1 + Current sample, line, band is: 15 25 1 + Current sample, line, band is: 16 25 1 + Current sample, line, band is: 17 25 1 + Current sample, line, band is: 18 25 1 + Current sample, line, band is: 19 25 1 + Current sample, line, band is: 20 25 1 + Current sample, line, band is: 21 25 1 + Current sample, line, band is: 22 25 1 + Current sample, line, band is: 23 25 1 + Current sample, line, band is: 24 25 1 + Current sample, line, band is: 25 25 1 + Current sample, line, band is: 26 25 1 + Current sample, line, band is: 27 25 1 + Current sample, line, band is: 28 25 1 + Current sample, line, band is: 29 25 1 + Current sample, line, band is: 30 25 1 + Current sample, line, band is: 31 25 1 + Current sample, line, band is: 32 25 1 + Current sample, line, band is: 33 25 1 + Current sample, line, band is: 34 25 1 + Current sample, line, band is: 35 25 1 + Current sample, line, band is: 36 25 1 + Current sample, line, band is: 37 25 1 + Current sample, line, band is: 38 25 1 + Current sample, line, band is: 39 25 1 + Current sample, line, band is: 40 25 1 + Current sample, line, band is: 41 25 1 + Current sample, line, band is: 42 25 1 + Current sample, line, band is: 43 25 1 + Current sample, line, band is: 44 25 1 + Current sample, line, band is: 45 25 1 + Current sample, line, band is: 46 25 1 + Current sample, line, band is: 47 25 1 + Current sample, line, band is: 48 25 1 + Current sample, line, band is: 49 25 1 + Current sample, line, band is: 50 25 1 + Current sample, line, band is: 51 25 1 + Current sample, line, band is: 52 25 1 + Current sample, line, band is: 53 25 1 + Current sample, line, band is: 54 25 1 + Current sample, line, band is: 55 25 1 + Current sample, line, band is: 56 25 1 + Current sample, line, band is: 57 25 1 + Current sample, line, band is: 58 25 1 + Current sample, line, band is: 59 25 1 + Current sample, line, band is: 60 25 1 + Current sample, line, band is: 61 25 1 + Current sample, line, band is: 62 25 1 + Current sample, line, band is: 63 25 1 + Current sample, line, band is: 64 25 1 + Current sample, line, band is: 65 25 1 + Current sample, line, band is: 66 25 1 + Current sample, line, band is: 67 25 1 + Current sample, line, band is: 68 25 1 + Current sample, line, band is: 69 25 1 + Current sample, line, band is: 70 25 1 + Current sample, line, band is: 71 25 1 + Current sample, line, band is: 72 25 1 + Current sample, line, band is: 73 25 1 + Current sample, line, band is: 74 25 1 + Current sample, line, band is: 75 25 1 + Current sample, line, band is: 76 25 1 + Current sample, line, band is: 77 25 1 + Current sample, line, band is: 78 25 1 + Current sample, line, band is: 79 25 1 + Current sample, line, band is: 80 25 1 + Current sample, line, band is: 81 25 1 + Current sample, line, band is: 82 25 1 + Current sample, line, band is: 83 25 1 + Current sample, line, band is: 84 25 1 + Current sample, line, band is: 85 25 1 + Current sample, line, band is: 86 25 1 + Current sample, line, band is: 87 25 1 + Current sample, line, band is: 88 25 1 + Current sample, line, band is: 89 25 1 + Current sample, line, band is: 90 25 1 + Current sample, line, band is: 91 25 1 + Current sample, line, band is: 92 25 1 + Current sample, line, band is: 93 25 1 + Current sample, line, band is: 94 25 1 + Current sample, line, band is: 95 25 1 + Current sample, line, band is: 96 25 1 + Current sample, line, band is: 97 25 1 + Current sample, line, band is: 98 25 1 + Current sample, line, band is: 99 25 1 + Current sample, line, band is: 100 25 1 + Current sample, line, band is: 101 25 1 + Current sample, line, band is: 102 25 1 + Current sample, line, band is: 103 25 1 + Current sample, line, band is: 104 25 1 + Current sample, line, band is: 105 25 1 + Current sample, line, band is: 106 25 1 + Current sample, line, band is: 107 25 1 + Current sample, line, band is: 108 25 1 + Current sample, line, band is: 109 25 1 + Current sample, line, band is: 110 25 1 + Current sample, line, band is: 111 25 1 + Current sample, line, band is: 112 25 1 + Current sample, line, band is: 113 25 1 + Current sample, line, band is: 114 25 1 + Current sample, line, band is: 115 25 1 + Current sample, line, band is: 116 25 1 + Current sample, line, band is: 117 25 1 + Current sample, line, band is: 118 25 1 + Current sample, line, band is: 119 25 1 + Current sample, line, band is: 120 25 1 + Current sample, line, band is: 121 25 1 + Current sample, line, band is: 122 25 1 + Current sample, line, band is: 123 25 1 + Current sample, line, band is: 124 25 1 + Current sample, line, band is: 125 25 1 + Current sample, line, band is: 126 25 1 + Current sample, line, band is: 1 26 1 + Current sample, line, band is: 2 26 1 + Current sample, line, band is: 3 26 1 + Current sample, line, band is: 4 26 1 + Current sample, line, band is: 5 26 1 + Current sample, line, band is: 6 26 1 + Current sample, line, band is: 7 26 1 + Current sample, line, band is: 8 26 1 + Current sample, line, band is: 9 26 1 + Current sample, line, band is: 10 26 1 + Current sample, line, band is: 11 26 1 + Current sample, line, band is: 12 26 1 + Current sample, line, band is: 13 26 1 + Current sample, line, band is: 14 26 1 + Current sample, line, band is: 15 26 1 + Current sample, line, band is: 16 26 1 + Current sample, line, band is: 17 26 1 + Current sample, line, band is: 18 26 1 + Current sample, line, band is: 19 26 1 + Current sample, line, band is: 20 26 1 + Current sample, line, band is: 21 26 1 + Current sample, line, band is: 22 26 1 + Current sample, line, band is: 23 26 1 + Current sample, line, band is: 24 26 1 + Current sample, line, band is: 25 26 1 + Current sample, line, band is: 26 26 1 + Current sample, line, band is: 27 26 1 + Current sample, line, band is: 28 26 1 + Current sample, line, band is: 29 26 1 + Current sample, line, band is: 30 26 1 + Current sample, line, band is: 31 26 1 + Current sample, line, band is: 32 26 1 + Current sample, line, band is: 33 26 1 + Current sample, line, band is: 34 26 1 + Current sample, line, band is: 35 26 1 + Current sample, line, band is: 36 26 1 + Current sample, line, band is: 37 26 1 + Current sample, line, band is: 38 26 1 + Current sample, line, band is: 39 26 1 + Current sample, line, band is: 40 26 1 + Current sample, line, band is: 41 26 1 + Current sample, line, band is: 42 26 1 + Current sample, line, band is: 43 26 1 + Current sample, line, band is: 44 26 1 + Current sample, line, band is: 45 26 1 + Current sample, line, band is: 46 26 1 + Current sample, line, band is: 47 26 1 + Current sample, line, band is: 48 26 1 + Current sample, line, band is: 49 26 1 + Current sample, line, band is: 50 26 1 + Current sample, line, band is: 51 26 1 + Current sample, line, band is: 52 26 1 + Current sample, line, band is: 53 26 1 + Current sample, line, band is: 54 26 1 + Current sample, line, band is: 55 26 1 + Current sample, line, band is: 56 26 1 + Current sample, line, band is: 57 26 1 + Current sample, line, band is: 58 26 1 + Current sample, line, band is: 59 26 1 + Current sample, line, band is: 60 26 1 + Current sample, line, band is: 61 26 1 + Current sample, line, band is: 62 26 1 + Current sample, line, band is: 63 26 1 + Current sample, line, band is: 64 26 1 + Current sample, line, band is: 65 26 1 + Current sample, line, band is: 66 26 1 + Current sample, line, band is: 67 26 1 + Current sample, line, band is: 68 26 1 + Current sample, line, band is: 69 26 1 + Current sample, line, band is: 70 26 1 + Current sample, line, band is: 71 26 1 + Current sample, line, band is: 72 26 1 + Current sample, line, band is: 73 26 1 + Current sample, line, band is: 74 26 1 + Current sample, line, band is: 75 26 1 + Current sample, line, band is: 76 26 1 + Current sample, line, band is: 77 26 1 + Current sample, line, band is: 78 26 1 + Current sample, line, band is: 79 26 1 + Current sample, line, band is: 80 26 1 + Current sample, line, band is: 81 26 1 + Current sample, line, band is: 82 26 1 + Current sample, line, band is: 83 26 1 + Current sample, line, band is: 84 26 1 + Current sample, line, band is: 85 26 1 + Current sample, line, band is: 86 26 1 + Current sample, line, band is: 87 26 1 + Current sample, line, band is: 88 26 1 + Current sample, line, band is: 89 26 1 + Current sample, line, band is: 90 26 1 + Current sample, line, band is: 91 26 1 + Current sample, line, band is: 92 26 1 + Current sample, line, band is: 93 26 1 + Current sample, line, band is: 94 26 1 + Current sample, line, band is: 95 26 1 + Current sample, line, band is: 96 26 1 + Current sample, line, band is: 97 26 1 + Current sample, line, band is: 98 26 1 + Current sample, line, band is: 99 26 1 + Current sample, line, band is: 100 26 1 + Current sample, line, band is: 101 26 1 + Current sample, line, band is: 102 26 1 + Current sample, line, band is: 103 26 1 + Current sample, line, band is: 104 26 1 + Current sample, line, band is: 105 26 1 + Current sample, line, band is: 106 26 1 + Current sample, line, band is: 107 26 1 + Current sample, line, band is: 108 26 1 + Current sample, line, band is: 109 26 1 + Current sample, line, band is: 110 26 1 + Current sample, line, band is: 111 26 1 + Current sample, line, band is: 112 26 1 + Current sample, line, band is: 113 26 1 + Current sample, line, band is: 114 26 1 + Current sample, line, band is: 115 26 1 + Current sample, line, band is: 116 26 1 + Current sample, line, band is: 117 26 1 + Current sample, line, band is: 118 26 1 + Current sample, line, band is: 119 26 1 + Current sample, line, band is: 120 26 1 + Current sample, line, band is: 121 26 1 + Current sample, line, band is: 122 26 1 + Current sample, line, band is: 123 26 1 + Current sample, line, band is: 124 26 1 + Current sample, line, band is: 125 26 1 + Current sample, line, band is: 126 26 1 + Current sample, line, band is: 1 27 1 + Current sample, line, band is: 2 27 1 + Current sample, line, band is: 3 27 1 + Current sample, line, band is: 4 27 1 + Current sample, line, band is: 5 27 1 + Current sample, line, band is: 6 27 1 + Current sample, line, band is: 7 27 1 + Current sample, line, band is: 8 27 1 + Current sample, line, band is: 9 27 1 + Current sample, line, band is: 10 27 1 + Current sample, line, band is: 11 27 1 + Current sample, line, band is: 12 27 1 + Current sample, line, band is: 13 27 1 + Current sample, line, band is: 14 27 1 + Current sample, line, band is: 15 27 1 + Current sample, line, band is: 16 27 1 + Current sample, line, band is: 17 27 1 + Current sample, line, band is: 18 27 1 + Current sample, line, band is: 19 27 1 + Current sample, line, band is: 20 27 1 + Current sample, line, band is: 21 27 1 + Current sample, line, band is: 22 27 1 + Current sample, line, band is: 23 27 1 + Current sample, line, band is: 24 27 1 + Current sample, line, band is: 25 27 1 + Current sample, line, band is: 26 27 1 + Current sample, line, band is: 27 27 1 + Current sample, line, band is: 28 27 1 + Current sample, line, band is: 29 27 1 + Current sample, line, band is: 30 27 1 + Current sample, line, band is: 31 27 1 + Current sample, line, band is: 32 27 1 + Current sample, line, band is: 33 27 1 + Current sample, line, band is: 34 27 1 + Current sample, line, band is: 35 27 1 + Current sample, line, band is: 36 27 1 + Current sample, line, band is: 37 27 1 + Current sample, line, band is: 38 27 1 + Current sample, line, band is: 39 27 1 + Current sample, line, band is: 40 27 1 + Current sample, line, band is: 41 27 1 + Current sample, line, band is: 42 27 1 + Current sample, line, band is: 43 27 1 + Current sample, line, band is: 44 27 1 + Current sample, line, band is: 45 27 1 + Current sample, line, band is: 46 27 1 + Current sample, line, band is: 47 27 1 + Current sample, line, band is: 48 27 1 + Current sample, line, band is: 49 27 1 + Current sample, line, band is: 50 27 1 + Current sample, line, band is: 51 27 1 + Current sample, line, band is: 52 27 1 + Current sample, line, band is: 53 27 1 + Current sample, line, band is: 54 27 1 + Current sample, line, band is: 55 27 1 + Current sample, line, band is: 56 27 1 + Current sample, line, band is: 57 27 1 + Current sample, line, band is: 58 27 1 + Current sample, line, band is: 59 27 1 + Current sample, line, band is: 60 27 1 + Current sample, line, band is: 61 27 1 + Current sample, line, band is: 62 27 1 + Current sample, line, band is: 63 27 1 + Current sample, line, band is: 64 27 1 + Current sample, line, band is: 65 27 1 + Current sample, line, band is: 66 27 1 + Current sample, line, band is: 67 27 1 + Current sample, line, band is: 68 27 1 + Current sample, line, band is: 69 27 1 + Current sample, line, band is: 70 27 1 + Current sample, line, band is: 71 27 1 + Current sample, line, band is: 72 27 1 + Current sample, line, band is: 73 27 1 + Current sample, line, band is: 74 27 1 + Current sample, line, band is: 75 27 1 + Current sample, line, band is: 76 27 1 + Current sample, line, band is: 77 27 1 + Current sample, line, band is: 78 27 1 + Current sample, line, band is: 79 27 1 + Current sample, line, band is: 80 27 1 + Current sample, line, band is: 81 27 1 + Current sample, line, band is: 82 27 1 + Current sample, line, band is: 83 27 1 + Current sample, line, band is: 84 27 1 + Current sample, line, band is: 85 27 1 + Current sample, line, band is: 86 27 1 + Current sample, line, band is: 87 27 1 + Current sample, line, band is: 88 27 1 + Current sample, line, band is: 89 27 1 + Current sample, line, band is: 90 27 1 + Current sample, line, band is: 91 27 1 + Current sample, line, band is: 92 27 1 + Current sample, line, band is: 93 27 1 + Current sample, line, band is: 94 27 1 + Current sample, line, band is: 95 27 1 + Current sample, line, band is: 96 27 1 + Current sample, line, band is: 97 27 1 + Current sample, line, band is: 98 27 1 + Current sample, line, band is: 99 27 1 + Current sample, line, band is: 100 27 1 + Current sample, line, band is: 101 27 1 + Current sample, line, band is: 102 27 1 + Current sample, line, band is: 103 27 1 + Current sample, line, band is: 104 27 1 + Current sample, line, band is: 105 27 1 + Current sample, line, band is: 106 27 1 + Current sample, line, band is: 107 27 1 + Current sample, line, band is: 108 27 1 + Current sample, line, band is: 109 27 1 + Current sample, line, band is: 110 27 1 + Current sample, line, band is: 111 27 1 + Current sample, line, band is: 112 27 1 + Current sample, line, band is: 113 27 1 + Current sample, line, band is: 114 27 1 + Current sample, line, band is: 115 27 1 + Current sample, line, band is: 116 27 1 + Current sample, line, band is: 117 27 1 + Current sample, line, band is: 118 27 1 + Current sample, line, band is: 119 27 1 + Current sample, line, band is: 120 27 1 + Current sample, line, band is: 121 27 1 + Current sample, line, band is: 122 27 1 + Current sample, line, band is: 123 27 1 + Current sample, line, band is: 124 27 1 + Current sample, line, band is: 125 27 1 + Current sample, line, band is: 126 27 1 + Current sample, line, band is: 1 28 1 + Current sample, line, band is: 2 28 1 + Current sample, line, band is: 3 28 1 + Current sample, line, band is: 4 28 1 + Current sample, line, band is: 5 28 1 + Current sample, line, band is: 6 28 1 + Current sample, line, band is: 7 28 1 + Current sample, line, band is: 8 28 1 + Current sample, line, band is: 9 28 1 + Current sample, line, band is: 10 28 1 + Current sample, line, band is: 11 28 1 + Current sample, line, band is: 12 28 1 + Current sample, line, band is: 13 28 1 + Current sample, line, band is: 14 28 1 + Current sample, line, band is: 15 28 1 + Current sample, line, band is: 16 28 1 + Current sample, line, band is: 17 28 1 + Current sample, line, band is: 18 28 1 + Current sample, line, band is: 19 28 1 + Current sample, line, band is: 20 28 1 + Current sample, line, band is: 21 28 1 + Current sample, line, band is: 22 28 1 + Current sample, line, band is: 23 28 1 + Current sample, line, band is: 24 28 1 + Current sample, line, band is: 25 28 1 + Current sample, line, band is: 26 28 1 + Current sample, line, band is: 27 28 1 + Current sample, line, band is: 28 28 1 + Current sample, line, band is: 29 28 1 + Current sample, line, band is: 30 28 1 + Current sample, line, band is: 31 28 1 + Current sample, line, band is: 32 28 1 + Current sample, line, band is: 33 28 1 + Current sample, line, band is: 34 28 1 + Current sample, line, band is: 35 28 1 + Current sample, line, band is: 36 28 1 + Current sample, line, band is: 37 28 1 + Current sample, line, band is: 38 28 1 + Current sample, line, band is: 39 28 1 + Current sample, line, band is: 40 28 1 + Current sample, line, band is: 41 28 1 + Current sample, line, band is: 42 28 1 + Current sample, line, band is: 43 28 1 + Current sample, line, band is: 44 28 1 + Current sample, line, band is: 45 28 1 + Current sample, line, band is: 46 28 1 + Current sample, line, band is: 47 28 1 + Current sample, line, band is: 48 28 1 + Current sample, line, band is: 49 28 1 + Current sample, line, band is: 50 28 1 + Current sample, line, band is: 51 28 1 + Current sample, line, band is: 52 28 1 + Current sample, line, band is: 53 28 1 + Current sample, line, band is: 54 28 1 + Current sample, line, band is: 55 28 1 + Current sample, line, band is: 56 28 1 + Current sample, line, band is: 57 28 1 + Current sample, line, band is: 58 28 1 + Current sample, line, band is: 59 28 1 + Current sample, line, band is: 60 28 1 + Current sample, line, band is: 61 28 1 + Current sample, line, band is: 62 28 1 + Current sample, line, band is: 63 28 1 + Current sample, line, band is: 64 28 1 + Current sample, line, band is: 65 28 1 + Current sample, line, band is: 66 28 1 + Current sample, line, band is: 67 28 1 + Current sample, line, band is: 68 28 1 + Current sample, line, band is: 69 28 1 + Current sample, line, band is: 70 28 1 + Current sample, line, band is: 71 28 1 + Current sample, line, band is: 72 28 1 + Current sample, line, band is: 73 28 1 + Current sample, line, band is: 74 28 1 + Current sample, line, band is: 75 28 1 + Current sample, line, band is: 76 28 1 + Current sample, line, band is: 77 28 1 + Current sample, line, band is: 78 28 1 + Current sample, line, band is: 79 28 1 + Current sample, line, band is: 80 28 1 + Current sample, line, band is: 81 28 1 + Current sample, line, band is: 82 28 1 + Current sample, line, band is: 83 28 1 + Current sample, line, band is: 84 28 1 + Current sample, line, band is: 85 28 1 + Current sample, line, band is: 86 28 1 + Current sample, line, band is: 87 28 1 + Current sample, line, band is: 88 28 1 + Current sample, line, band is: 89 28 1 + Current sample, line, band is: 90 28 1 + Current sample, line, band is: 91 28 1 + Current sample, line, band is: 92 28 1 + Current sample, line, band is: 93 28 1 + Current sample, line, band is: 94 28 1 + Current sample, line, band is: 95 28 1 + Current sample, line, band is: 96 28 1 + Current sample, line, band is: 97 28 1 + Current sample, line, band is: 98 28 1 + Current sample, line, band is: 99 28 1 + Current sample, line, band is: 100 28 1 + Current sample, line, band is: 101 28 1 + Current sample, line, band is: 102 28 1 + Current sample, line, band is: 103 28 1 + Current sample, line, band is: 104 28 1 + Current sample, line, band is: 105 28 1 + Current sample, line, band is: 106 28 1 + Current sample, line, band is: 107 28 1 + Current sample, line, band is: 108 28 1 + Current sample, line, band is: 109 28 1 + Current sample, line, band is: 110 28 1 + Current sample, line, band is: 111 28 1 + Current sample, line, band is: 112 28 1 + Current sample, line, band is: 113 28 1 + Current sample, line, band is: 114 28 1 + Current sample, line, band is: 115 28 1 + Current sample, line, band is: 116 28 1 + Current sample, line, band is: 117 28 1 + Current sample, line, band is: 118 28 1 + Current sample, line, band is: 119 28 1 + Current sample, line, band is: 120 28 1 + Current sample, line, band is: 121 28 1 + Current sample, line, band is: 122 28 1 + Current sample, line, band is: 123 28 1 + Current sample, line, band is: 124 28 1 + Current sample, line, band is: 125 28 1 + Current sample, line, band is: 126 28 1 + Current sample, line, band is: 1 29 1 + Current sample, line, band is: 2 29 1 + Current sample, line, band is: 3 29 1 + Current sample, line, band is: 4 29 1 + Current sample, line, band is: 5 29 1 + Current sample, line, band is: 6 29 1 + Current sample, line, band is: 7 29 1 + Current sample, line, band is: 8 29 1 + Current sample, line, band is: 9 29 1 + Current sample, line, band is: 10 29 1 + Current sample, line, band is: 11 29 1 + Current sample, line, band is: 12 29 1 + Current sample, line, band is: 13 29 1 + Current sample, line, band is: 14 29 1 + Current sample, line, band is: 15 29 1 + Current sample, line, band is: 16 29 1 + Current sample, line, band is: 17 29 1 + Current sample, line, band is: 18 29 1 + Current sample, line, band is: 19 29 1 + Current sample, line, band is: 20 29 1 + Current sample, line, band is: 21 29 1 + Current sample, line, band is: 22 29 1 + Current sample, line, band is: 23 29 1 + Current sample, line, band is: 24 29 1 + Current sample, line, band is: 25 29 1 + Current sample, line, band is: 26 29 1 + Current sample, line, band is: 27 29 1 + Current sample, line, band is: 28 29 1 + Current sample, line, band is: 29 29 1 + Current sample, line, band is: 30 29 1 + Current sample, line, band is: 31 29 1 + Current sample, line, band is: 32 29 1 + Current sample, line, band is: 33 29 1 + Current sample, line, band is: 34 29 1 + Current sample, line, band is: 35 29 1 + Current sample, line, band is: 36 29 1 + Current sample, line, band is: 37 29 1 + Current sample, line, band is: 38 29 1 + Current sample, line, band is: 39 29 1 + Current sample, line, band is: 40 29 1 + Current sample, line, band is: 41 29 1 + Current sample, line, band is: 42 29 1 + Current sample, line, band is: 43 29 1 + Current sample, line, band is: 44 29 1 + Current sample, line, band is: 45 29 1 + Current sample, line, band is: 46 29 1 + Current sample, line, band is: 47 29 1 + Current sample, line, band is: 48 29 1 + Current sample, line, band is: 49 29 1 + Current sample, line, band is: 50 29 1 + Current sample, line, band is: 51 29 1 + Current sample, line, band is: 52 29 1 + Current sample, line, band is: 53 29 1 + Current sample, line, band is: 54 29 1 + Current sample, line, band is: 55 29 1 + Current sample, line, band is: 56 29 1 + Current sample, line, band is: 57 29 1 + Current sample, line, band is: 58 29 1 + Current sample, line, band is: 59 29 1 + Current sample, line, band is: 60 29 1 + Current sample, line, band is: 61 29 1 + Current sample, line, band is: 62 29 1 + Current sample, line, band is: 63 29 1 + Current sample, line, band is: 64 29 1 + Current sample, line, band is: 65 29 1 + Current sample, line, band is: 66 29 1 + Current sample, line, band is: 67 29 1 + Current sample, line, band is: 68 29 1 + Current sample, line, band is: 69 29 1 + Current sample, line, band is: 70 29 1 + Current sample, line, band is: 71 29 1 + Current sample, line, band is: 72 29 1 + Current sample, line, band is: 73 29 1 + Current sample, line, band is: 74 29 1 + Current sample, line, band is: 75 29 1 + Current sample, line, band is: 76 29 1 + Current sample, line, band is: 77 29 1 + Current sample, line, band is: 78 29 1 + Current sample, line, band is: 79 29 1 + Current sample, line, band is: 80 29 1 + Current sample, line, band is: 81 29 1 + Current sample, line, band is: 82 29 1 + Current sample, line, band is: 83 29 1 + Current sample, line, band is: 84 29 1 + Current sample, line, band is: 85 29 1 + Current sample, line, band is: 86 29 1 + Current sample, line, band is: 87 29 1 + Current sample, line, band is: 88 29 1 + Current sample, line, band is: 89 29 1 + Current sample, line, band is: 90 29 1 + Current sample, line, band is: 91 29 1 + Current sample, line, band is: 92 29 1 + Current sample, line, band is: 93 29 1 + Current sample, line, band is: 94 29 1 + Current sample, line, band is: 95 29 1 + Current sample, line, band is: 96 29 1 + Current sample, line, band is: 97 29 1 + Current sample, line, band is: 98 29 1 + Current sample, line, band is: 99 29 1 + Current sample, line, band is: 100 29 1 + Current sample, line, band is: 101 29 1 + Current sample, line, band is: 102 29 1 + Current sample, line, band is: 103 29 1 + Current sample, line, band is: 104 29 1 + Current sample, line, band is: 105 29 1 + Current sample, line, band is: 106 29 1 + Current sample, line, band is: 107 29 1 + Current sample, line, band is: 108 29 1 + Current sample, line, band is: 109 29 1 + Current sample, line, band is: 110 29 1 + Current sample, line, band is: 111 29 1 + Current sample, line, band is: 112 29 1 + Current sample, line, band is: 113 29 1 + Current sample, line, band is: 114 29 1 + Current sample, line, band is: 115 29 1 + Current sample, line, band is: 116 29 1 + Current sample, line, band is: 117 29 1 + Current sample, line, band is: 118 29 1 + Current sample, line, band is: 119 29 1 + Current sample, line, band is: 120 29 1 + Current sample, line, band is: 121 29 1 + Current sample, line, band is: 122 29 1 + Current sample, line, band is: 123 29 1 + Current sample, line, band is: 124 29 1 + Current sample, line, band is: 125 29 1 + Current sample, line, band is: 126 29 1 + Current sample, line, band is: 1 30 1 + Current sample, line, band is: 2 30 1 + Current sample, line, band is: 3 30 1 + Current sample, line, band is: 4 30 1 + Current sample, line, band is: 5 30 1 + Current sample, line, band is: 6 30 1 + Current sample, line, band is: 7 30 1 + Current sample, line, band is: 8 30 1 + Current sample, line, band is: 9 30 1 + Current sample, line, band is: 10 30 1 + Current sample, line, band is: 11 30 1 + Current sample, line, band is: 12 30 1 + Current sample, line, band is: 13 30 1 + Current sample, line, band is: 14 30 1 + Current sample, line, band is: 15 30 1 + Current sample, line, band is: 16 30 1 + Current sample, line, band is: 17 30 1 + Current sample, line, band is: 18 30 1 + Current sample, line, band is: 19 30 1 + Current sample, line, band is: 20 30 1 + Current sample, line, band is: 21 30 1 + Current sample, line, band is: 22 30 1 + Current sample, line, band is: 23 30 1 + Current sample, line, band is: 24 30 1 + Current sample, line, band is: 25 30 1 + Current sample, line, band is: 26 30 1 + Current sample, line, band is: 27 30 1 + Current sample, line, band is: 28 30 1 + Current sample, line, band is: 29 30 1 + Current sample, line, band is: 30 30 1 + Current sample, line, band is: 31 30 1 + Current sample, line, band is: 32 30 1 + Current sample, line, band is: 33 30 1 + Current sample, line, band is: 34 30 1 + Current sample, line, band is: 35 30 1 + Current sample, line, band is: 36 30 1 + Current sample, line, band is: 37 30 1 + Current sample, line, band is: 38 30 1 + Current sample, line, band is: 39 30 1 + Current sample, line, band is: 40 30 1 + Current sample, line, band is: 41 30 1 + Current sample, line, band is: 42 30 1 + Current sample, line, band is: 43 30 1 + Current sample, line, band is: 44 30 1 + Current sample, line, band is: 45 30 1 + Current sample, line, band is: 46 30 1 + Current sample, line, band is: 47 30 1 + Current sample, line, band is: 48 30 1 + Current sample, line, band is: 49 30 1 + Current sample, line, band is: 50 30 1 + Current sample, line, band is: 51 30 1 + Current sample, line, band is: 52 30 1 + Current sample, line, band is: 53 30 1 + Current sample, line, band is: 54 30 1 + Current sample, line, band is: 55 30 1 + Current sample, line, band is: 56 30 1 + Current sample, line, band is: 57 30 1 + Current sample, line, band is: 58 30 1 + Current sample, line, band is: 59 30 1 + Current sample, line, band is: 60 30 1 + Current sample, line, band is: 61 30 1 + Current sample, line, band is: 62 30 1 + Current sample, line, band is: 63 30 1 + Current sample, line, band is: 64 30 1 + Current sample, line, band is: 65 30 1 + Current sample, line, band is: 66 30 1 + Current sample, line, band is: 67 30 1 + Current sample, line, band is: 68 30 1 + Current sample, line, band is: 69 30 1 + Current sample, line, band is: 70 30 1 + Current sample, line, band is: 71 30 1 + Current sample, line, band is: 72 30 1 + Current sample, line, band is: 73 30 1 + Current sample, line, band is: 74 30 1 + Current sample, line, band is: 75 30 1 + Current sample, line, band is: 76 30 1 + Current sample, line, band is: 77 30 1 + Current sample, line, band is: 78 30 1 + Current sample, line, band is: 79 30 1 + Current sample, line, band is: 80 30 1 + Current sample, line, band is: 81 30 1 + Current sample, line, band is: 82 30 1 + Current sample, line, band is: 83 30 1 + Current sample, line, band is: 84 30 1 + Current sample, line, band is: 85 30 1 + Current sample, line, band is: 86 30 1 + Current sample, line, band is: 87 30 1 + Current sample, line, band is: 88 30 1 + Current sample, line, band is: 89 30 1 + Current sample, line, band is: 90 30 1 + Current sample, line, band is: 91 30 1 + Current sample, line, band is: 92 30 1 + Current sample, line, band is: 93 30 1 + Current sample, line, band is: 94 30 1 + Current sample, line, band is: 95 30 1 + Current sample, line, band is: 96 30 1 + Current sample, line, band is: 97 30 1 + Current sample, line, band is: 98 30 1 + Current sample, line, band is: 99 30 1 + Current sample, line, band is: 100 30 1 + Current sample, line, band is: 101 30 1 + Current sample, line, band is: 102 30 1 + Current sample, line, band is: 103 30 1 + Current sample, line, band is: 104 30 1 + Current sample, line, band is: 105 30 1 + Current sample, line, band is: 106 30 1 + Current sample, line, band is: 107 30 1 + Current sample, line, band is: 108 30 1 + Current sample, line, band is: 109 30 1 + Current sample, line, band is: 110 30 1 + Current sample, line, band is: 111 30 1 + Current sample, line, band is: 112 30 1 + Current sample, line, band is: 113 30 1 + Current sample, line, band is: 114 30 1 + Current sample, line, band is: 115 30 1 + Current sample, line, band is: 116 30 1 + Current sample, line, band is: 117 30 1 + Current sample, line, band is: 118 30 1 + Current sample, line, band is: 119 30 1 + Current sample, line, band is: 120 30 1 + Current sample, line, band is: 121 30 1 + Current sample, line, band is: 122 30 1 + Current sample, line, band is: 123 30 1 + Current sample, line, band is: 124 30 1 + Current sample, line, band is: 125 30 1 + Current sample, line, band is: 126 30 1 + Current sample, line, band is: 1 31 1 + Current sample, line, band is: 2 31 1 + Current sample, line, band is: 3 31 1 + Current sample, line, band is: 4 31 1 + Current sample, line, band is: 5 31 1 + Current sample, line, band is: 6 31 1 + Current sample, line, band is: 7 31 1 + Current sample, line, band is: 8 31 1 + Current sample, line, band is: 9 31 1 + Current sample, line, band is: 10 31 1 + Current sample, line, band is: 11 31 1 + Current sample, line, band is: 12 31 1 + Current sample, line, band is: 13 31 1 + Current sample, line, band is: 14 31 1 + Current sample, line, band is: 15 31 1 + Current sample, line, band is: 16 31 1 + Current sample, line, band is: 17 31 1 + Current sample, line, band is: 18 31 1 + Current sample, line, band is: 19 31 1 + Current sample, line, band is: 20 31 1 + Current sample, line, band is: 21 31 1 + Current sample, line, band is: 22 31 1 + Current sample, line, band is: 23 31 1 + Current sample, line, band is: 24 31 1 + Current sample, line, band is: 25 31 1 + Current sample, line, band is: 26 31 1 + Current sample, line, band is: 27 31 1 + Current sample, line, band is: 28 31 1 + Current sample, line, band is: 29 31 1 + Current sample, line, band is: 30 31 1 + Current sample, line, band is: 31 31 1 + Current sample, line, band is: 32 31 1 + Current sample, line, band is: 33 31 1 + Current sample, line, band is: 34 31 1 + Current sample, line, band is: 35 31 1 + Current sample, line, band is: 36 31 1 + Current sample, line, band is: 37 31 1 + Current sample, line, band is: 38 31 1 + Current sample, line, band is: 39 31 1 + Current sample, line, band is: 40 31 1 + Current sample, line, band is: 41 31 1 + Current sample, line, band is: 42 31 1 + Current sample, line, band is: 43 31 1 + Current sample, line, band is: 44 31 1 + Current sample, line, band is: 45 31 1 + Current sample, line, band is: 46 31 1 + Current sample, line, band is: 47 31 1 + Current sample, line, band is: 48 31 1 + Current sample, line, band is: 49 31 1 + Current sample, line, band is: 50 31 1 + Current sample, line, band is: 51 31 1 + Current sample, line, band is: 52 31 1 + Current sample, line, band is: 53 31 1 + Current sample, line, band is: 54 31 1 + Current sample, line, band is: 55 31 1 + Current sample, line, band is: 56 31 1 + Current sample, line, band is: 57 31 1 + Current sample, line, band is: 58 31 1 + Current sample, line, band is: 59 31 1 + Current sample, line, band is: 60 31 1 + Current sample, line, band is: 61 31 1 + Current sample, line, band is: 62 31 1 + Current sample, line, band is: 63 31 1 + Current sample, line, band is: 64 31 1 + Current sample, line, band is: 65 31 1 + Current sample, line, band is: 66 31 1 + Current sample, line, band is: 67 31 1 + Current sample, line, band is: 68 31 1 + Current sample, line, band is: 69 31 1 + Current sample, line, band is: 70 31 1 + Current sample, line, band is: 71 31 1 + Current sample, line, band is: 72 31 1 + Current sample, line, band is: 73 31 1 + Current sample, line, band is: 74 31 1 + Current sample, line, band is: 75 31 1 + Current sample, line, band is: 76 31 1 + Current sample, line, band is: 77 31 1 + Current sample, line, band is: 78 31 1 + Current sample, line, band is: 79 31 1 + Current sample, line, band is: 80 31 1 + Current sample, line, band is: 81 31 1 + Current sample, line, band is: 82 31 1 + Current sample, line, band is: 83 31 1 + Current sample, line, band is: 84 31 1 + Current sample, line, band is: 85 31 1 + Current sample, line, band is: 86 31 1 + Current sample, line, band is: 87 31 1 + Current sample, line, band is: 88 31 1 + Current sample, line, band is: 89 31 1 + Current sample, line, band is: 90 31 1 + Current sample, line, band is: 91 31 1 + Current sample, line, band is: 92 31 1 + Current sample, line, band is: 93 31 1 + Current sample, line, band is: 94 31 1 + Current sample, line, band is: 95 31 1 + Current sample, line, band is: 96 31 1 + Current sample, line, band is: 97 31 1 + Current sample, line, band is: 98 31 1 + Current sample, line, band is: 99 31 1 + Current sample, line, band is: 100 31 1 + Current sample, line, band is: 101 31 1 + Current sample, line, band is: 102 31 1 + Current sample, line, band is: 103 31 1 + Current sample, line, band is: 104 31 1 + Current sample, line, band is: 105 31 1 + Current sample, line, band is: 106 31 1 + Current sample, line, band is: 107 31 1 + Current sample, line, band is: 108 31 1 + Current sample, line, band is: 109 31 1 + Current sample, line, band is: 110 31 1 + Current sample, line, band is: 111 31 1 + Current sample, line, band is: 112 31 1 + Current sample, line, band is: 113 31 1 + Current sample, line, band is: 114 31 1 + Current sample, line, band is: 115 31 1 + Current sample, line, band is: 116 31 1 + Current sample, line, band is: 117 31 1 + Current sample, line, band is: 118 31 1 + Current sample, line, band is: 119 31 1 + Current sample, line, band is: 120 31 1 + Current sample, line, band is: 121 31 1 + Current sample, line, band is: 122 31 1 + Current sample, line, band is: 123 31 1 + Current sample, line, band is: 124 31 1 + Current sample, line, band is: 125 31 1 + Current sample, line, band is: 126 31 1 + Current sample, line, band is: 1 32 1 + Current sample, line, band is: 2 32 1 + Current sample, line, band is: 3 32 1 + Current sample, line, band is: 4 32 1 + Current sample, line, band is: 5 32 1 + Current sample, line, band is: 6 32 1 + Current sample, line, band is: 7 32 1 + Current sample, line, band is: 8 32 1 + Current sample, line, band is: 9 32 1 + Current sample, line, band is: 10 32 1 + Current sample, line, band is: 11 32 1 + Current sample, line, band is: 12 32 1 + Current sample, line, band is: 13 32 1 + Current sample, line, band is: 14 32 1 + Current sample, line, band is: 15 32 1 + Current sample, line, band is: 16 32 1 + Current sample, line, band is: 17 32 1 + Current sample, line, band is: 18 32 1 + Current sample, line, band is: 19 32 1 + Current sample, line, band is: 20 32 1 + Current sample, line, band is: 21 32 1 + Current sample, line, band is: 22 32 1 + Current sample, line, band is: 23 32 1 + Current sample, line, band is: 24 32 1 + Current sample, line, band is: 25 32 1 + Current sample, line, band is: 26 32 1 + Current sample, line, band is: 27 32 1 + Current sample, line, band is: 28 32 1 + Current sample, line, band is: 29 32 1 + Current sample, line, band is: 30 32 1 + Current sample, line, band is: 31 32 1 + Current sample, line, band is: 32 32 1 + Current sample, line, band is: 33 32 1 + Current sample, line, band is: 34 32 1 + Current sample, line, band is: 35 32 1 + Current sample, line, band is: 36 32 1 + Current sample, line, band is: 37 32 1 + Current sample, line, band is: 38 32 1 + Current sample, line, band is: 39 32 1 + Current sample, line, band is: 40 32 1 + Current sample, line, band is: 41 32 1 + Current sample, line, band is: 42 32 1 + Current sample, line, band is: 43 32 1 + Current sample, line, band is: 44 32 1 + Current sample, line, band is: 45 32 1 + Current sample, line, band is: 46 32 1 + Current sample, line, band is: 47 32 1 + Current sample, line, band is: 48 32 1 + Current sample, line, band is: 49 32 1 + Current sample, line, band is: 50 32 1 + Current sample, line, band is: 51 32 1 + Current sample, line, band is: 52 32 1 + Current sample, line, band is: 53 32 1 + Current sample, line, band is: 54 32 1 + Current sample, line, band is: 55 32 1 + Current sample, line, band is: 56 32 1 + Current sample, line, band is: 57 32 1 + Current sample, line, band is: 58 32 1 + Current sample, line, band is: 59 32 1 + Current sample, line, band is: 60 32 1 + Current sample, line, band is: 61 32 1 + Current sample, line, band is: 62 32 1 + Current sample, line, band is: 63 32 1 + Current sample, line, band is: 64 32 1 + Current sample, line, band is: 65 32 1 + Current sample, line, band is: 66 32 1 + Current sample, line, band is: 67 32 1 + Current sample, line, band is: 68 32 1 + Current sample, line, band is: 69 32 1 + Current sample, line, band is: 70 32 1 + Current sample, line, band is: 71 32 1 + Current sample, line, band is: 72 32 1 + Current sample, line, band is: 73 32 1 + Current sample, line, band is: 74 32 1 + Current sample, line, band is: 75 32 1 + Current sample, line, band is: 76 32 1 + Current sample, line, band is: 77 32 1 + Current sample, line, band is: 78 32 1 + Current sample, line, band is: 79 32 1 + Current sample, line, band is: 80 32 1 + Current sample, line, band is: 81 32 1 + Current sample, line, band is: 82 32 1 + Current sample, line, band is: 83 32 1 + Current sample, line, band is: 84 32 1 + Current sample, line, band is: 85 32 1 + Current sample, line, band is: 86 32 1 + Current sample, line, band is: 87 32 1 + Current sample, line, band is: 88 32 1 + Current sample, line, band is: 89 32 1 + Current sample, line, band is: 90 32 1 + Current sample, line, band is: 91 32 1 + Current sample, line, band is: 92 32 1 + Current sample, line, band is: 93 32 1 + Current sample, line, band is: 94 32 1 + Current sample, line, band is: 95 32 1 + Current sample, line, band is: 96 32 1 + Current sample, line, band is: 97 32 1 + Current sample, line, band is: 98 32 1 + Current sample, line, band is: 99 32 1 + Current sample, line, band is: 100 32 1 + Current sample, line, band is: 101 32 1 + Current sample, line, band is: 102 32 1 + Current sample, line, band is: 103 32 1 + Current sample, line, band is: 104 32 1 + Current sample, line, band is: 105 32 1 + Current sample, line, band is: 106 32 1 + Current sample, line, band is: 107 32 1 + Current sample, line, band is: 108 32 1 + Current sample, line, band is: 109 32 1 + Current sample, line, band is: 110 32 1 + Current sample, line, band is: 111 32 1 + Current sample, line, band is: 112 32 1 + Current sample, line, band is: 113 32 1 + Current sample, line, band is: 114 32 1 + Current sample, line, band is: 115 32 1 + Current sample, line, band is: 116 32 1 + Current sample, line, band is: 117 32 1 + Current sample, line, band is: 118 32 1 + Current sample, line, band is: 119 32 1 + Current sample, line, band is: 120 32 1 + Current sample, line, band is: 121 32 1 + Current sample, line, band is: 122 32 1 + Current sample, line, band is: 123 32 1 + Current sample, line, band is: 124 32 1 + Current sample, line, band is: 125 32 1 + Current sample, line, band is: 126 32 1 + Current sample, line, band is: 1 33 1 + Current sample, line, band is: 2 33 1 + Current sample, line, band is: 3 33 1 + Current sample, line, band is: 4 33 1 + Current sample, line, band is: 5 33 1 + Current sample, line, band is: 6 33 1 + Current sample, line, band is: 7 33 1 + Current sample, line, band is: 8 33 1 + Current sample, line, band is: 9 33 1 + Current sample, line, band is: 10 33 1 + Current sample, line, band is: 11 33 1 + Current sample, line, band is: 12 33 1 + Current sample, line, band is: 13 33 1 + Current sample, line, band is: 14 33 1 + Current sample, line, band is: 15 33 1 + Current sample, line, band is: 16 33 1 + Current sample, line, band is: 17 33 1 + Current sample, line, band is: 18 33 1 + Current sample, line, band is: 19 33 1 + Current sample, line, band is: 20 33 1 + Current sample, line, band is: 21 33 1 + Current sample, line, band is: 22 33 1 + Current sample, line, band is: 23 33 1 + Current sample, line, band is: 24 33 1 + Current sample, line, band is: 25 33 1 + Current sample, line, band is: 26 33 1 + Current sample, line, band is: 27 33 1 + Current sample, line, band is: 28 33 1 + Current sample, line, band is: 29 33 1 + Current sample, line, band is: 30 33 1 + Current sample, line, band is: 31 33 1 + Current sample, line, band is: 32 33 1 + Current sample, line, band is: 33 33 1 + Current sample, line, band is: 34 33 1 + Current sample, line, band is: 35 33 1 + Current sample, line, band is: 36 33 1 + Current sample, line, band is: 37 33 1 + Current sample, line, band is: 38 33 1 + Current sample, line, band is: 39 33 1 + Current sample, line, band is: 40 33 1 + Current sample, line, band is: 41 33 1 + Current sample, line, band is: 42 33 1 + Current sample, line, band is: 43 33 1 + Current sample, line, band is: 44 33 1 + Current sample, line, band is: 45 33 1 + Current sample, line, band is: 46 33 1 + Current sample, line, band is: 47 33 1 + Current sample, line, band is: 48 33 1 + Current sample, line, band is: 49 33 1 + Current sample, line, band is: 50 33 1 + Current sample, line, band is: 51 33 1 + Current sample, line, band is: 52 33 1 + Current sample, line, band is: 53 33 1 + Current sample, line, band is: 54 33 1 + Current sample, line, band is: 55 33 1 + Current sample, line, band is: 56 33 1 + Current sample, line, band is: 57 33 1 + Current sample, line, band is: 58 33 1 + Current sample, line, band is: 59 33 1 + Current sample, line, band is: 60 33 1 + Current sample, line, band is: 61 33 1 + Current sample, line, band is: 62 33 1 + Current sample, line, band is: 63 33 1 + Current sample, line, band is: 64 33 1 + Current sample, line, band is: 65 33 1 + Current sample, line, band is: 66 33 1 + Current sample, line, band is: 67 33 1 + Current sample, line, band is: 68 33 1 + Current sample, line, band is: 69 33 1 + Current sample, line, band is: 70 33 1 + Current sample, line, band is: 71 33 1 + Current sample, line, band is: 72 33 1 + Current sample, line, band is: 73 33 1 + Current sample, line, band is: 74 33 1 + Current sample, line, band is: 75 33 1 + Current sample, line, band is: 76 33 1 + Current sample, line, band is: 77 33 1 + Current sample, line, band is: 78 33 1 + Current sample, line, band is: 79 33 1 + Current sample, line, band is: 80 33 1 + Current sample, line, band is: 81 33 1 + Current sample, line, band is: 82 33 1 + Current sample, line, band is: 83 33 1 + Current sample, line, band is: 84 33 1 + Current sample, line, band is: 85 33 1 + Current sample, line, band is: 86 33 1 + Current sample, line, band is: 87 33 1 + Current sample, line, band is: 88 33 1 + Current sample, line, band is: 89 33 1 + Current sample, line, band is: 90 33 1 + Current sample, line, band is: 91 33 1 + Current sample, line, band is: 92 33 1 + Current sample, line, band is: 93 33 1 + Current sample, line, band is: 94 33 1 + Current sample, line, band is: 95 33 1 + Current sample, line, band is: 96 33 1 + Current sample, line, band is: 97 33 1 + Current sample, line, band is: 98 33 1 + Current sample, line, band is: 99 33 1 + Current sample, line, band is: 100 33 1 + Current sample, line, band is: 101 33 1 + Current sample, line, band is: 102 33 1 + Current sample, line, band is: 103 33 1 + Current sample, line, band is: 104 33 1 + Current sample, line, band is: 105 33 1 + Current sample, line, band is: 106 33 1 + Current sample, line, band is: 107 33 1 + Current sample, line, band is: 108 33 1 + Current sample, line, band is: 109 33 1 + Current sample, line, band is: 110 33 1 + Current sample, line, band is: 111 33 1 + Current sample, line, band is: 112 33 1 + Current sample, line, band is: 113 33 1 + Current sample, line, band is: 114 33 1 + Current sample, line, band is: 115 33 1 + Current sample, line, band is: 116 33 1 + Current sample, line, band is: 117 33 1 + Current sample, line, band is: 118 33 1 + Current sample, line, band is: 119 33 1 + Current sample, line, band is: 120 33 1 + Current sample, line, band is: 121 33 1 + Current sample, line, band is: 122 33 1 + Current sample, line, band is: 123 33 1 + Current sample, line, band is: 124 33 1 + Current sample, line, band is: 125 33 1 + Current sample, line, band is: 126 33 1 + Current sample, line, band is: 1 34 1 + Current sample, line, band is: 2 34 1 + Current sample, line, band is: 3 34 1 + Current sample, line, band is: 4 34 1 + Current sample, line, band is: 5 34 1 + Current sample, line, band is: 6 34 1 + Current sample, line, band is: 7 34 1 + Current sample, line, band is: 8 34 1 + Current sample, line, band is: 9 34 1 + Current sample, line, band is: 10 34 1 + Current sample, line, band is: 11 34 1 + Current sample, line, band is: 12 34 1 + Current sample, line, band is: 13 34 1 + Current sample, line, band is: 14 34 1 + Current sample, line, band is: 15 34 1 + Current sample, line, band is: 16 34 1 + Current sample, line, band is: 17 34 1 + Current sample, line, band is: 18 34 1 + Current sample, line, band is: 19 34 1 + Current sample, line, band is: 20 34 1 + Current sample, line, band is: 21 34 1 + Current sample, line, band is: 22 34 1 + Current sample, line, band is: 23 34 1 + Current sample, line, band is: 24 34 1 + Current sample, line, band is: 25 34 1 + Current sample, line, band is: 26 34 1 + Current sample, line, band is: 27 34 1 + Current sample, line, band is: 28 34 1 + Current sample, line, band is: 29 34 1 + Current sample, line, band is: 30 34 1 + Current sample, line, band is: 31 34 1 + Current sample, line, band is: 32 34 1 + Current sample, line, band is: 33 34 1 + Current sample, line, band is: 34 34 1 + Current sample, line, band is: 35 34 1 + Current sample, line, band is: 36 34 1 + Current sample, line, band is: 37 34 1 + Current sample, line, band is: 38 34 1 + Current sample, line, band is: 39 34 1 + Current sample, line, band is: 40 34 1 + Current sample, line, band is: 41 34 1 + Current sample, line, band is: 42 34 1 + Current sample, line, band is: 43 34 1 + Current sample, line, band is: 44 34 1 + Current sample, line, band is: 45 34 1 + Current sample, line, band is: 46 34 1 + Current sample, line, band is: 47 34 1 + Current sample, line, band is: 48 34 1 + Current sample, line, band is: 49 34 1 + Current sample, line, band is: 50 34 1 + Current sample, line, band is: 51 34 1 + Current sample, line, band is: 52 34 1 + Current sample, line, band is: 53 34 1 + Current sample, line, band is: 54 34 1 + Current sample, line, band is: 55 34 1 + Current sample, line, band is: 56 34 1 + Current sample, line, band is: 57 34 1 + Current sample, line, band is: 58 34 1 + Current sample, line, band is: 59 34 1 + Current sample, line, band is: 60 34 1 + Current sample, line, band is: 61 34 1 + Current sample, line, band is: 62 34 1 + Current sample, line, band is: 63 34 1 + Current sample, line, band is: 64 34 1 + Current sample, line, band is: 65 34 1 + Current sample, line, band is: 66 34 1 + Current sample, line, band is: 67 34 1 + Current sample, line, band is: 68 34 1 + Current sample, line, band is: 69 34 1 + Current sample, line, band is: 70 34 1 + Current sample, line, band is: 71 34 1 + Current sample, line, band is: 72 34 1 + Current sample, line, band is: 73 34 1 + Current sample, line, band is: 74 34 1 + Current sample, line, band is: 75 34 1 + Current sample, line, band is: 76 34 1 + Current sample, line, band is: 77 34 1 + Current sample, line, band is: 78 34 1 + Current sample, line, band is: 79 34 1 + Current sample, line, band is: 80 34 1 + Current sample, line, band is: 81 34 1 + Current sample, line, band is: 82 34 1 + Current sample, line, band is: 83 34 1 + Current sample, line, band is: 84 34 1 + Current sample, line, band is: 85 34 1 + Current sample, line, band is: 86 34 1 + Current sample, line, band is: 87 34 1 + Current sample, line, band is: 88 34 1 + Current sample, line, band is: 89 34 1 + Current sample, line, band is: 90 34 1 + Current sample, line, band is: 91 34 1 + Current sample, line, band is: 92 34 1 + Current sample, line, band is: 93 34 1 + Current sample, line, band is: 94 34 1 + Current sample, line, band is: 95 34 1 + Current sample, line, band is: 96 34 1 + Current sample, line, band is: 97 34 1 + Current sample, line, band is: 98 34 1 + Current sample, line, band is: 99 34 1 + Current sample, line, band is: 100 34 1 + Current sample, line, band is: 101 34 1 + Current sample, line, band is: 102 34 1 + Current sample, line, band is: 103 34 1 + Current sample, line, band is: 104 34 1 + Current sample, line, band is: 105 34 1 + Current sample, line, band is: 106 34 1 + Current sample, line, band is: 107 34 1 + Current sample, line, band is: 108 34 1 + Current sample, line, band is: 109 34 1 + Current sample, line, band is: 110 34 1 + Current sample, line, band is: 111 34 1 + Current sample, line, band is: 112 34 1 + Current sample, line, band is: 113 34 1 + Current sample, line, band is: 114 34 1 + Current sample, line, band is: 115 34 1 + Current sample, line, band is: 116 34 1 + Current sample, line, band is: 117 34 1 + Current sample, line, band is: 118 34 1 + Current sample, line, band is: 119 34 1 + Current sample, line, band is: 120 34 1 + Current sample, line, band is: 121 34 1 + Current sample, line, band is: 122 34 1 + Current sample, line, band is: 123 34 1 + Current sample, line, band is: 124 34 1 + Current sample, line, band is: 125 34 1 + Current sample, line, band is: 126 34 1 + Current sample, line, band is: 1 35 1 + Current sample, line, band is: 2 35 1 + Current sample, line, band is: 3 35 1 + Current sample, line, band is: 4 35 1 + Current sample, line, band is: 5 35 1 + Current sample, line, band is: 6 35 1 + Current sample, line, band is: 7 35 1 + Current sample, line, band is: 8 35 1 + Current sample, line, band is: 9 35 1 + Current sample, line, band is: 10 35 1 + Current sample, line, band is: 11 35 1 + Current sample, line, band is: 12 35 1 + Current sample, line, band is: 13 35 1 + Current sample, line, band is: 14 35 1 + Current sample, line, band is: 15 35 1 + Current sample, line, band is: 16 35 1 + Current sample, line, band is: 17 35 1 + Current sample, line, band is: 18 35 1 + Current sample, line, band is: 19 35 1 + Current sample, line, band is: 20 35 1 + Current sample, line, band is: 21 35 1 + Current sample, line, band is: 22 35 1 + Current sample, line, band is: 23 35 1 + Current sample, line, band is: 24 35 1 + Current sample, line, band is: 25 35 1 + Current sample, line, band is: 26 35 1 + Current sample, line, band is: 27 35 1 + Current sample, line, band is: 28 35 1 + Current sample, line, band is: 29 35 1 + Current sample, line, band is: 30 35 1 + Current sample, line, band is: 31 35 1 + Current sample, line, band is: 32 35 1 + Current sample, line, band is: 33 35 1 + Current sample, line, band is: 34 35 1 + Current sample, line, band is: 35 35 1 + Current sample, line, band is: 36 35 1 + Current sample, line, band is: 37 35 1 + Current sample, line, band is: 38 35 1 + Current sample, line, band is: 39 35 1 + Current sample, line, band is: 40 35 1 + Current sample, line, band is: 41 35 1 + Current sample, line, band is: 42 35 1 + Current sample, line, band is: 43 35 1 + Current sample, line, band is: 44 35 1 + Current sample, line, band is: 45 35 1 + Current sample, line, band is: 46 35 1 + Current sample, line, band is: 47 35 1 + Current sample, line, band is: 48 35 1 + Current sample, line, band is: 49 35 1 + Current sample, line, band is: 50 35 1 + Current sample, line, band is: 51 35 1 + Current sample, line, band is: 52 35 1 + Current sample, line, band is: 53 35 1 + Current sample, line, band is: 54 35 1 + Current sample, line, band is: 55 35 1 + Current sample, line, band is: 56 35 1 + Current sample, line, band is: 57 35 1 + Current sample, line, band is: 58 35 1 + Current sample, line, band is: 59 35 1 + Current sample, line, band is: 60 35 1 + Current sample, line, band is: 61 35 1 + Current sample, line, band is: 62 35 1 + Current sample, line, band is: 63 35 1 + Current sample, line, band is: 64 35 1 + Current sample, line, band is: 65 35 1 + Current sample, line, band is: 66 35 1 + Current sample, line, band is: 67 35 1 + Current sample, line, band is: 68 35 1 + Current sample, line, band is: 69 35 1 + Current sample, line, band is: 70 35 1 + Current sample, line, band is: 71 35 1 + Current sample, line, band is: 72 35 1 + Current sample, line, band is: 73 35 1 + Current sample, line, band is: 74 35 1 + Current sample, line, band is: 75 35 1 + Current sample, line, band is: 76 35 1 + Current sample, line, band is: 77 35 1 + Current sample, line, band is: 78 35 1 + Current sample, line, band is: 79 35 1 + Current sample, line, band is: 80 35 1 + Current sample, line, band is: 81 35 1 + Current sample, line, band is: 82 35 1 + Current sample, line, band is: 83 35 1 + Current sample, line, band is: 84 35 1 + Current sample, line, band is: 85 35 1 + Current sample, line, band is: 86 35 1 + Current sample, line, band is: 87 35 1 + Current sample, line, band is: 88 35 1 + Current sample, line, band is: 89 35 1 + Current sample, line, band is: 90 35 1 + Current sample, line, band is: 91 35 1 + Current sample, line, band is: 92 35 1 + Current sample, line, band is: 93 35 1 + Current sample, line, band is: 94 35 1 + Current sample, line, band is: 95 35 1 + Current sample, line, band is: 96 35 1 + Current sample, line, band is: 97 35 1 + Current sample, line, band is: 98 35 1 + Current sample, line, band is: 99 35 1 + Current sample, line, band is: 100 35 1 + Current sample, line, band is: 101 35 1 + Current sample, line, band is: 102 35 1 + Current sample, line, band is: 103 35 1 + Current sample, line, band is: 104 35 1 + Current sample, line, band is: 105 35 1 + Current sample, line, band is: 106 35 1 + Current sample, line, band is: 107 35 1 + Current sample, line, band is: 108 35 1 + Current sample, line, band is: 109 35 1 + Current sample, line, band is: 110 35 1 + Current sample, line, band is: 111 35 1 + Current sample, line, band is: 112 35 1 + Current sample, line, band is: 113 35 1 + Current sample, line, band is: 114 35 1 + Current sample, line, band is: 115 35 1 + Current sample, line, band is: 116 35 1 + Current sample, line, band is: 117 35 1 + Current sample, line, band is: 118 35 1 + Current sample, line, band is: 119 35 1 + Current sample, line, band is: 120 35 1 + Current sample, line, band is: 121 35 1 + Current sample, line, band is: 122 35 1 + Current sample, line, band is: 123 35 1 + Current sample, line, band is: 124 35 1 + Current sample, line, band is: 125 35 1 + Current sample, line, band is: 126 35 1 + Current sample, line, band is: 1 36 1 + Current sample, line, band is: 2 36 1 + Current sample, line, band is: 3 36 1 + Current sample, line, band is: 4 36 1 + Current sample, line, band is: 5 36 1 + Current sample, line, band is: 6 36 1 + Current sample, line, band is: 7 36 1 + Current sample, line, band is: 8 36 1 + Current sample, line, band is: 9 36 1 + Current sample, line, band is: 10 36 1 + Current sample, line, band is: 11 36 1 + Current sample, line, band is: 12 36 1 + Current sample, line, band is: 13 36 1 + Current sample, line, band is: 14 36 1 + Current sample, line, band is: 15 36 1 + Current sample, line, band is: 16 36 1 + Current sample, line, band is: 17 36 1 + Current sample, line, band is: 18 36 1 + Current sample, line, band is: 19 36 1 + Current sample, line, band is: 20 36 1 + Current sample, line, band is: 21 36 1 + Current sample, line, band is: 22 36 1 + Current sample, line, band is: 23 36 1 + Current sample, line, band is: 24 36 1 + Current sample, line, band is: 25 36 1 + Current sample, line, band is: 26 36 1 + Current sample, line, band is: 27 36 1 + Current sample, line, band is: 28 36 1 + Current sample, line, band is: 29 36 1 + Current sample, line, band is: 30 36 1 + Current sample, line, band is: 31 36 1 + Current sample, line, band is: 32 36 1 + Current sample, line, band is: 33 36 1 + Current sample, line, band is: 34 36 1 + Current sample, line, band is: 35 36 1 + Current sample, line, band is: 36 36 1 + Current sample, line, band is: 37 36 1 + Current sample, line, band is: 38 36 1 + Current sample, line, band is: 39 36 1 + Current sample, line, band is: 40 36 1 + Current sample, line, band is: 41 36 1 + Current sample, line, band is: 42 36 1 + Current sample, line, band is: 43 36 1 + Current sample, line, band is: 44 36 1 + Current sample, line, band is: 45 36 1 + Current sample, line, band is: 46 36 1 + Current sample, line, band is: 47 36 1 + Current sample, line, band is: 48 36 1 + Current sample, line, band is: 49 36 1 + Current sample, line, band is: 50 36 1 + Current sample, line, band is: 51 36 1 + Current sample, line, band is: 52 36 1 + Current sample, line, band is: 53 36 1 + Current sample, line, band is: 54 36 1 + Current sample, line, band is: 55 36 1 + Current sample, line, band is: 56 36 1 + Current sample, line, band is: 57 36 1 + Current sample, line, band is: 58 36 1 + Current sample, line, band is: 59 36 1 + Current sample, line, band is: 60 36 1 + Current sample, line, band is: 61 36 1 + Current sample, line, band is: 62 36 1 + Current sample, line, band is: 63 36 1 + Current sample, line, band is: 64 36 1 + Current sample, line, band is: 65 36 1 + Current sample, line, band is: 66 36 1 + Current sample, line, band is: 67 36 1 + Current sample, line, band is: 68 36 1 + Current sample, line, band is: 69 36 1 + Current sample, line, band is: 70 36 1 + Current sample, line, band is: 71 36 1 + Current sample, line, band is: 72 36 1 + Current sample, line, band is: 73 36 1 + Current sample, line, band is: 74 36 1 + Current sample, line, band is: 75 36 1 + Current sample, line, band is: 76 36 1 + Current sample, line, band is: 77 36 1 + Current sample, line, band is: 78 36 1 + Current sample, line, band is: 79 36 1 + Current sample, line, band is: 80 36 1 + Current sample, line, band is: 81 36 1 + Current sample, line, band is: 82 36 1 + Current sample, line, band is: 83 36 1 + Current sample, line, band is: 84 36 1 + Current sample, line, band is: 85 36 1 + Current sample, line, band is: 86 36 1 + Current sample, line, band is: 87 36 1 + Current sample, line, band is: 88 36 1 + Current sample, line, band is: 89 36 1 + Current sample, line, band is: 90 36 1 + Current sample, line, band is: 91 36 1 + Current sample, line, band is: 92 36 1 + Current sample, line, band is: 93 36 1 + Current sample, line, band is: 94 36 1 + Current sample, line, band is: 95 36 1 + Current sample, line, band is: 96 36 1 + Current sample, line, band is: 97 36 1 + Current sample, line, band is: 98 36 1 + Current sample, line, band is: 99 36 1 + Current sample, line, band is: 100 36 1 + Current sample, line, band is: 101 36 1 + Current sample, line, band is: 102 36 1 + Current sample, line, band is: 103 36 1 + Current sample, line, band is: 104 36 1 + Current sample, line, band is: 105 36 1 + Current sample, line, band is: 106 36 1 + Current sample, line, band is: 107 36 1 + Current sample, line, band is: 108 36 1 + Current sample, line, band is: 109 36 1 + Current sample, line, band is: 110 36 1 + Current sample, line, band is: 111 36 1 + Current sample, line, band is: 112 36 1 + Current sample, line, band is: 113 36 1 + Current sample, line, band is: 114 36 1 + Current sample, line, band is: 115 36 1 + Current sample, line, band is: 116 36 1 + Current sample, line, band is: 117 36 1 + Current sample, line, band is: 118 36 1 + Current sample, line, band is: 119 36 1 + Current sample, line, band is: 120 36 1 + Current sample, line, band is: 121 36 1 + Current sample, line, band is: 122 36 1 + Current sample, line, band is: 123 36 1 + Current sample, line, band is: 124 36 1 + Current sample, line, band is: 125 36 1 + Current sample, line, band is: 126 36 1 + Current sample, line, band is: 1 37 1 + Current sample, line, band is: 2 37 1 + Current sample, line, band is: 3 37 1 + Current sample, line, band is: 4 37 1 + Current sample, line, band is: 5 37 1 + Current sample, line, band is: 6 37 1 + Current sample, line, band is: 7 37 1 + Current sample, line, band is: 8 37 1 + Current sample, line, band is: 9 37 1 + Current sample, line, band is: 10 37 1 + Current sample, line, band is: 11 37 1 + Current sample, line, band is: 12 37 1 + Current sample, line, band is: 13 37 1 + Current sample, line, band is: 14 37 1 + Current sample, line, band is: 15 37 1 + Current sample, line, band is: 16 37 1 + Current sample, line, band is: 17 37 1 + Current sample, line, band is: 18 37 1 + Current sample, line, band is: 19 37 1 + Current sample, line, band is: 20 37 1 + Current sample, line, band is: 21 37 1 + Current sample, line, band is: 22 37 1 + Current sample, line, band is: 23 37 1 + Current sample, line, band is: 24 37 1 + Current sample, line, band is: 25 37 1 + Current sample, line, band is: 26 37 1 + Current sample, line, band is: 27 37 1 + Current sample, line, band is: 28 37 1 + Current sample, line, band is: 29 37 1 + Current sample, line, band is: 30 37 1 + Current sample, line, band is: 31 37 1 + Current sample, line, band is: 32 37 1 + Current sample, line, band is: 33 37 1 + Current sample, line, band is: 34 37 1 + Current sample, line, band is: 35 37 1 + Current sample, line, band is: 36 37 1 + Current sample, line, band is: 37 37 1 + Current sample, line, band is: 38 37 1 + Current sample, line, band is: 39 37 1 + Current sample, line, band is: 40 37 1 + Current sample, line, band is: 41 37 1 + Current sample, line, band is: 42 37 1 + Current sample, line, band is: 43 37 1 + Current sample, line, band is: 44 37 1 + Current sample, line, band is: 45 37 1 + Current sample, line, band is: 46 37 1 + Current sample, line, band is: 47 37 1 + Current sample, line, band is: 48 37 1 + Current sample, line, band is: 49 37 1 + Current sample, line, band is: 50 37 1 + Current sample, line, band is: 51 37 1 + Current sample, line, band is: 52 37 1 + Current sample, line, band is: 53 37 1 + Current sample, line, band is: 54 37 1 + Current sample, line, band is: 55 37 1 + Current sample, line, band is: 56 37 1 + Current sample, line, band is: 57 37 1 + Current sample, line, band is: 58 37 1 + Current sample, line, band is: 59 37 1 + Current sample, line, band is: 60 37 1 + Current sample, line, band is: 61 37 1 + Current sample, line, band is: 62 37 1 + Current sample, line, band is: 63 37 1 + Current sample, line, band is: 64 37 1 + Current sample, line, band is: 65 37 1 + Current sample, line, band is: 66 37 1 + Current sample, line, band is: 67 37 1 + Current sample, line, band is: 68 37 1 + Current sample, line, band is: 69 37 1 + Current sample, line, band is: 70 37 1 + Current sample, line, band is: 71 37 1 + Current sample, line, band is: 72 37 1 + Current sample, line, band is: 73 37 1 + Current sample, line, band is: 74 37 1 + Current sample, line, band is: 75 37 1 + Current sample, line, band is: 76 37 1 + Current sample, line, band is: 77 37 1 + Current sample, line, band is: 78 37 1 + Current sample, line, band is: 79 37 1 + Current sample, line, band is: 80 37 1 + Current sample, line, band is: 81 37 1 + Current sample, line, band is: 82 37 1 + Current sample, line, band is: 83 37 1 + Current sample, line, band is: 84 37 1 + Current sample, line, band is: 85 37 1 + Current sample, line, band is: 86 37 1 + Current sample, line, band is: 87 37 1 + Current sample, line, band is: 88 37 1 + Current sample, line, band is: 89 37 1 + Current sample, line, band is: 90 37 1 + Current sample, line, band is: 91 37 1 + Current sample, line, band is: 92 37 1 + Current sample, line, band is: 93 37 1 + Current sample, line, band is: 94 37 1 + Current sample, line, band is: 95 37 1 + Current sample, line, band is: 96 37 1 + Current sample, line, band is: 97 37 1 + Current sample, line, band is: 98 37 1 + Current sample, line, band is: 99 37 1 + Current sample, line, band is: 100 37 1 + Current sample, line, band is: 101 37 1 + Current sample, line, band is: 102 37 1 + Current sample, line, band is: 103 37 1 + Current sample, line, band is: 104 37 1 + Current sample, line, band is: 105 37 1 + Current sample, line, band is: 106 37 1 + Current sample, line, band is: 107 37 1 + Current sample, line, band is: 108 37 1 + Current sample, line, band is: 109 37 1 + Current sample, line, band is: 110 37 1 + Current sample, line, band is: 111 37 1 + Current sample, line, band is: 112 37 1 + Current sample, line, band is: 113 37 1 + Current sample, line, band is: 114 37 1 + Current sample, line, band is: 115 37 1 + Current sample, line, band is: 116 37 1 + Current sample, line, band is: 117 37 1 + Current sample, line, band is: 118 37 1 + Current sample, line, band is: 119 37 1 + Current sample, line, band is: 120 37 1 + Current sample, line, band is: 121 37 1 + Current sample, line, band is: 122 37 1 + Current sample, line, band is: 123 37 1 + Current sample, line, band is: 124 37 1 + Current sample, line, band is: 125 37 1 + Current sample, line, band is: 126 37 1 + Current sample, line, band is: 1 38 1 + Current sample, line, band is: 2 38 1 + Current sample, line, band is: 3 38 1 + Current sample, line, band is: 4 38 1 + Current sample, line, band is: 5 38 1 + Current sample, line, band is: 6 38 1 + Current sample, line, band is: 7 38 1 + Current sample, line, band is: 8 38 1 + Current sample, line, band is: 9 38 1 + Current sample, line, band is: 10 38 1 + Current sample, line, band is: 11 38 1 + Current sample, line, band is: 12 38 1 + Current sample, line, band is: 13 38 1 + Current sample, line, band is: 14 38 1 + Current sample, line, band is: 15 38 1 + Current sample, line, band is: 16 38 1 + Current sample, line, band is: 17 38 1 + Current sample, line, band is: 18 38 1 + Current sample, line, band is: 19 38 1 + Current sample, line, band is: 20 38 1 + Current sample, line, band is: 21 38 1 + Current sample, line, band is: 22 38 1 + Current sample, line, band is: 23 38 1 + Current sample, line, band is: 24 38 1 + Current sample, line, band is: 25 38 1 + Current sample, line, band is: 26 38 1 + Current sample, line, band is: 27 38 1 + Current sample, line, band is: 28 38 1 + Current sample, line, band is: 29 38 1 + Current sample, line, band is: 30 38 1 + Current sample, line, band is: 31 38 1 + Current sample, line, band is: 32 38 1 + Current sample, line, band is: 33 38 1 + Current sample, line, band is: 34 38 1 + Current sample, line, band is: 35 38 1 + Current sample, line, band is: 36 38 1 + Current sample, line, band is: 37 38 1 + Current sample, line, band is: 38 38 1 + Current sample, line, band is: 39 38 1 + Current sample, line, band is: 40 38 1 + Current sample, line, band is: 41 38 1 + Current sample, line, band is: 42 38 1 + Current sample, line, band is: 43 38 1 + Current sample, line, band is: 44 38 1 + Current sample, line, band is: 45 38 1 + Current sample, line, band is: 46 38 1 + Current sample, line, band is: 47 38 1 + Current sample, line, band is: 48 38 1 + Current sample, line, band is: 49 38 1 + Current sample, line, band is: 50 38 1 + Current sample, line, band is: 51 38 1 + Current sample, line, band is: 52 38 1 + Current sample, line, band is: 53 38 1 + Current sample, line, band is: 54 38 1 + Current sample, line, band is: 55 38 1 + Current sample, line, band is: 56 38 1 + Current sample, line, band is: 57 38 1 + Current sample, line, band is: 58 38 1 + Current sample, line, band is: 59 38 1 + Current sample, line, band is: 60 38 1 + Current sample, line, band is: 61 38 1 + Current sample, line, band is: 62 38 1 + Current sample, line, band is: 63 38 1 + Current sample, line, band is: 64 38 1 + Current sample, line, band is: 65 38 1 + Current sample, line, band is: 66 38 1 + Current sample, line, band is: 67 38 1 + Current sample, line, band is: 68 38 1 + Current sample, line, band is: 69 38 1 + Current sample, line, band is: 70 38 1 + Current sample, line, band is: 71 38 1 + Current sample, line, band is: 72 38 1 + Current sample, line, band is: 73 38 1 + Current sample, line, band is: 74 38 1 + Current sample, line, band is: 75 38 1 + Current sample, line, band is: 76 38 1 + Current sample, line, band is: 77 38 1 + Current sample, line, band is: 78 38 1 + Current sample, line, band is: 79 38 1 + Current sample, line, band is: 80 38 1 + Current sample, line, band is: 81 38 1 + Current sample, line, band is: 82 38 1 + Current sample, line, band is: 83 38 1 + Current sample, line, band is: 84 38 1 + Current sample, line, band is: 85 38 1 + Current sample, line, band is: 86 38 1 + Current sample, line, band is: 87 38 1 + Current sample, line, band is: 88 38 1 + Current sample, line, band is: 89 38 1 + Current sample, line, band is: 90 38 1 + Current sample, line, band is: 91 38 1 + Current sample, line, band is: 92 38 1 + Current sample, line, band is: 93 38 1 + Current sample, line, band is: 94 38 1 + Current sample, line, band is: 95 38 1 + Current sample, line, band is: 96 38 1 + Current sample, line, band is: 97 38 1 + Current sample, line, band is: 98 38 1 + Current sample, line, band is: 99 38 1 + Current sample, line, band is: 100 38 1 + Current sample, line, band is: 101 38 1 + Current sample, line, band is: 102 38 1 + Current sample, line, band is: 103 38 1 + Current sample, line, band is: 104 38 1 + Current sample, line, band is: 105 38 1 + Current sample, line, band is: 106 38 1 + Current sample, line, band is: 107 38 1 + Current sample, line, band is: 108 38 1 + Current sample, line, band is: 109 38 1 + Current sample, line, band is: 110 38 1 + Current sample, line, band is: 111 38 1 + Current sample, line, band is: 112 38 1 + Current sample, line, band is: 113 38 1 + Current sample, line, band is: 114 38 1 + Current sample, line, band is: 115 38 1 + Current sample, line, band is: 116 38 1 + Current sample, line, band is: 117 38 1 + Current sample, line, band is: 118 38 1 + Current sample, line, band is: 119 38 1 + Current sample, line, band is: 120 38 1 + Current sample, line, band is: 121 38 1 + Current sample, line, band is: 122 38 1 + Current sample, line, band is: 123 38 1 + Current sample, line, band is: 124 38 1 + Current sample, line, band is: 125 38 1 + Current sample, line, band is: 126 38 1 + Current sample, line, band is: 1 39 1 + Current sample, line, band is: 2 39 1 + Current sample, line, band is: 3 39 1 + Current sample, line, band is: 4 39 1 + Current sample, line, band is: 5 39 1 + Current sample, line, band is: 6 39 1 + Current sample, line, band is: 7 39 1 + Current sample, line, band is: 8 39 1 + Current sample, line, band is: 9 39 1 + Current sample, line, band is: 10 39 1 + Current sample, line, band is: 11 39 1 + Current sample, line, band is: 12 39 1 + Current sample, line, band is: 13 39 1 + Current sample, line, band is: 14 39 1 + Current sample, line, band is: 15 39 1 + Current sample, line, band is: 16 39 1 + Current sample, line, band is: 17 39 1 + Current sample, line, band is: 18 39 1 + Current sample, line, band is: 19 39 1 + Current sample, line, band is: 20 39 1 + Current sample, line, band is: 21 39 1 + Current sample, line, band is: 22 39 1 + Current sample, line, band is: 23 39 1 + Current sample, line, band is: 24 39 1 + Current sample, line, band is: 25 39 1 + Current sample, line, band is: 26 39 1 + Current sample, line, band is: 27 39 1 + Current sample, line, band is: 28 39 1 + Current sample, line, band is: 29 39 1 + Current sample, line, band is: 30 39 1 + Current sample, line, band is: 31 39 1 + Current sample, line, band is: 32 39 1 + Current sample, line, band is: 33 39 1 + Current sample, line, band is: 34 39 1 + Current sample, line, band is: 35 39 1 + Current sample, line, band is: 36 39 1 + Current sample, line, band is: 37 39 1 + Current sample, line, band is: 38 39 1 + Current sample, line, band is: 39 39 1 + Current sample, line, band is: 40 39 1 + Current sample, line, band is: 41 39 1 + Current sample, line, band is: 42 39 1 + Current sample, line, band is: 43 39 1 + Current sample, line, band is: 44 39 1 + Current sample, line, band is: 45 39 1 + Current sample, line, band is: 46 39 1 + Current sample, line, band is: 47 39 1 + Current sample, line, band is: 48 39 1 + Current sample, line, band is: 49 39 1 + Current sample, line, band is: 50 39 1 + Current sample, line, band is: 51 39 1 + Current sample, line, band is: 52 39 1 + Current sample, line, band is: 53 39 1 + Current sample, line, band is: 54 39 1 + Current sample, line, band is: 55 39 1 + Current sample, line, band is: 56 39 1 + Current sample, line, band is: 57 39 1 + Current sample, line, band is: 58 39 1 + Current sample, line, band is: 59 39 1 + Current sample, line, band is: 60 39 1 + Current sample, line, band is: 61 39 1 + Current sample, line, band is: 62 39 1 + Current sample, line, band is: 63 39 1 + Current sample, line, band is: 64 39 1 + Current sample, line, band is: 65 39 1 + Current sample, line, band is: 66 39 1 + Current sample, line, band is: 67 39 1 + Current sample, line, band is: 68 39 1 + Current sample, line, band is: 69 39 1 + Current sample, line, band is: 70 39 1 + Current sample, line, band is: 71 39 1 + Current sample, line, band is: 72 39 1 + Current sample, line, band is: 73 39 1 + Current sample, line, band is: 74 39 1 + Current sample, line, band is: 75 39 1 + Current sample, line, band is: 76 39 1 + Current sample, line, band is: 77 39 1 + Current sample, line, band is: 78 39 1 + Current sample, line, band is: 79 39 1 + Current sample, line, band is: 80 39 1 + Current sample, line, band is: 81 39 1 + Current sample, line, band is: 82 39 1 + Current sample, line, band is: 83 39 1 + Current sample, line, band is: 84 39 1 + Current sample, line, band is: 85 39 1 + Current sample, line, band is: 86 39 1 + Current sample, line, band is: 87 39 1 + Current sample, line, band is: 88 39 1 + Current sample, line, band is: 89 39 1 + Current sample, line, band is: 90 39 1 + Current sample, line, band is: 91 39 1 + Current sample, line, band is: 92 39 1 + Current sample, line, band is: 93 39 1 + Current sample, line, band is: 94 39 1 + Current sample, line, band is: 95 39 1 + Current sample, line, band is: 96 39 1 + Current sample, line, band is: 97 39 1 + Current sample, line, band is: 98 39 1 + Current sample, line, band is: 99 39 1 + Current sample, line, band is: 100 39 1 + Current sample, line, band is: 101 39 1 + Current sample, line, band is: 102 39 1 + Current sample, line, band is: 103 39 1 + Current sample, line, band is: 104 39 1 + Current sample, line, band is: 105 39 1 + Current sample, line, band is: 106 39 1 + Current sample, line, band is: 107 39 1 + Current sample, line, band is: 108 39 1 + Current sample, line, band is: 109 39 1 + Current sample, line, band is: 110 39 1 + Current sample, line, band is: 111 39 1 + Current sample, line, band is: 112 39 1 + Current sample, line, band is: 113 39 1 + Current sample, line, band is: 114 39 1 + Current sample, line, band is: 115 39 1 + Current sample, line, band is: 116 39 1 + Current sample, line, band is: 117 39 1 + Current sample, line, band is: 118 39 1 + Current sample, line, band is: 119 39 1 + Current sample, line, band is: 120 39 1 + Current sample, line, band is: 121 39 1 + Current sample, line, band is: 122 39 1 + Current sample, line, band is: 123 39 1 + Current sample, line, band is: 124 39 1 + Current sample, line, band is: 125 39 1 + Current sample, line, band is: 126 39 1 + Current sample, line, band is: 1 40 1 + Current sample, line, band is: 2 40 1 + Current sample, line, band is: 3 40 1 + Current sample, line, band is: 4 40 1 + Current sample, line, band is: 5 40 1 + Current sample, line, band is: 6 40 1 + Current sample, line, band is: 7 40 1 + Current sample, line, band is: 8 40 1 + Current sample, line, band is: 9 40 1 + Current sample, line, band is: 10 40 1 + Current sample, line, band is: 11 40 1 + Current sample, line, band is: 12 40 1 + Current sample, line, band is: 13 40 1 + Current sample, line, band is: 14 40 1 + Current sample, line, band is: 15 40 1 + Current sample, line, band is: 16 40 1 + Current sample, line, band is: 17 40 1 + Current sample, line, band is: 18 40 1 + Current sample, line, band is: 19 40 1 + Current sample, line, band is: 20 40 1 + Current sample, line, band is: 21 40 1 + Current sample, line, band is: 22 40 1 + Current sample, line, band is: 23 40 1 + Current sample, line, band is: 24 40 1 + Current sample, line, band is: 25 40 1 + Current sample, line, band is: 26 40 1 + Current sample, line, band is: 27 40 1 + Current sample, line, band is: 28 40 1 + Current sample, line, band is: 29 40 1 + Current sample, line, band is: 30 40 1 + Current sample, line, band is: 31 40 1 + Current sample, line, band is: 32 40 1 + Current sample, line, band is: 33 40 1 + Current sample, line, band is: 34 40 1 + Current sample, line, band is: 35 40 1 + Current sample, line, band is: 36 40 1 + Current sample, line, band is: 37 40 1 + Current sample, line, band is: 38 40 1 + Current sample, line, band is: 39 40 1 + Current sample, line, band is: 40 40 1 + Current sample, line, band is: 41 40 1 + Current sample, line, band is: 42 40 1 + Current sample, line, band is: 43 40 1 + Current sample, line, band is: 44 40 1 + Current sample, line, band is: 45 40 1 + Current sample, line, band is: 46 40 1 + Current sample, line, band is: 47 40 1 + Current sample, line, band is: 48 40 1 + Current sample, line, band is: 49 40 1 + Current sample, line, band is: 50 40 1 + Current sample, line, band is: 51 40 1 + Current sample, line, band is: 52 40 1 + Current sample, line, band is: 53 40 1 + Current sample, line, band is: 54 40 1 + Current sample, line, band is: 55 40 1 + Current sample, line, band is: 56 40 1 + Current sample, line, band is: 57 40 1 + Current sample, line, band is: 58 40 1 + Current sample, line, band is: 59 40 1 + Current sample, line, band is: 60 40 1 + Current sample, line, band is: 61 40 1 + Current sample, line, band is: 62 40 1 + Current sample, line, band is: 63 40 1 + Current sample, line, band is: 64 40 1 + Current sample, line, band is: 65 40 1 + Current sample, line, band is: 66 40 1 + Current sample, line, band is: 67 40 1 + Current sample, line, band is: 68 40 1 + Current sample, line, band is: 69 40 1 + Current sample, line, band is: 70 40 1 + Current sample, line, band is: 71 40 1 + Current sample, line, band is: 72 40 1 + Current sample, line, band is: 73 40 1 + Current sample, line, band is: 74 40 1 + Current sample, line, band is: 75 40 1 + Current sample, line, band is: 76 40 1 + Current sample, line, band is: 77 40 1 + Current sample, line, band is: 78 40 1 + Current sample, line, band is: 79 40 1 + Current sample, line, band is: 80 40 1 + Current sample, line, band is: 81 40 1 + Current sample, line, band is: 82 40 1 + Current sample, line, band is: 83 40 1 + Current sample, line, band is: 84 40 1 + Current sample, line, band is: 85 40 1 + Current sample, line, band is: 86 40 1 + Current sample, line, band is: 87 40 1 + Current sample, line, band is: 88 40 1 + Current sample, line, band is: 89 40 1 + Current sample, line, band is: 90 40 1 + Current sample, line, band is: 91 40 1 + Current sample, line, band is: 92 40 1 + Current sample, line, band is: 93 40 1 + Current sample, line, band is: 94 40 1 + Current sample, line, band is: 95 40 1 + Current sample, line, band is: 96 40 1 + Current sample, line, band is: 97 40 1 + Current sample, line, band is: 98 40 1 + Current sample, line, band is: 99 40 1 + Current sample, line, band is: 100 40 1 + Current sample, line, band is: 101 40 1 + Current sample, line, band is: 102 40 1 + Current sample, line, band is: 103 40 1 + Current sample, line, band is: 104 40 1 + Current sample, line, band is: 105 40 1 + Current sample, line, band is: 106 40 1 + Current sample, line, band is: 107 40 1 + Current sample, line, band is: 108 40 1 + Current sample, line, band is: 109 40 1 + Current sample, line, band is: 110 40 1 + Current sample, line, band is: 111 40 1 + Current sample, line, band is: 112 40 1 + Current sample, line, band is: 113 40 1 + Current sample, line, band is: 114 40 1 + Current sample, line, band is: 115 40 1 + Current sample, line, band is: 116 40 1 + Current sample, line, band is: 117 40 1 + Current sample, line, band is: 118 40 1 + Current sample, line, band is: 119 40 1 + Current sample, line, band is: 120 40 1 + Current sample, line, band is: 121 40 1 + Current sample, line, band is: 122 40 1 + Current sample, line, band is: 123 40 1 + Current sample, line, band is: 124 40 1 + Current sample, line, band is: 125 40 1 + Current sample, line, band is: 126 40 1 + Current sample, line, band is: 1 41 1 + Current sample, line, band is: 2 41 1 + Current sample, line, band is: 3 41 1 + Current sample, line, band is: 4 41 1 + Current sample, line, band is: 5 41 1 + Current sample, line, band is: 6 41 1 + Current sample, line, band is: 7 41 1 + Current sample, line, band is: 8 41 1 + Current sample, line, band is: 9 41 1 + Current sample, line, band is: 10 41 1 + Current sample, line, band is: 11 41 1 + Current sample, line, band is: 12 41 1 + Current sample, line, band is: 13 41 1 + Current sample, line, band is: 14 41 1 + Current sample, line, band is: 15 41 1 + Current sample, line, band is: 16 41 1 + Current sample, line, band is: 17 41 1 + Current sample, line, band is: 18 41 1 + Current sample, line, band is: 19 41 1 + Current sample, line, band is: 20 41 1 + Current sample, line, band is: 21 41 1 + Current sample, line, band is: 22 41 1 + Current sample, line, band is: 23 41 1 + Current sample, line, band is: 24 41 1 + Current sample, line, band is: 25 41 1 + Current sample, line, band is: 26 41 1 + Current sample, line, band is: 27 41 1 + Current sample, line, band is: 28 41 1 + Current sample, line, band is: 29 41 1 + Current sample, line, band is: 30 41 1 + Current sample, line, band is: 31 41 1 + Current sample, line, band is: 32 41 1 + Current sample, line, band is: 33 41 1 + Current sample, line, band is: 34 41 1 + Current sample, line, band is: 35 41 1 + Current sample, line, band is: 36 41 1 + Current sample, line, band is: 37 41 1 + Current sample, line, band is: 38 41 1 + Current sample, line, band is: 39 41 1 + Current sample, line, band is: 40 41 1 + Current sample, line, band is: 41 41 1 + Current sample, line, band is: 42 41 1 + Current sample, line, band is: 43 41 1 + Current sample, line, band is: 44 41 1 + Current sample, line, band is: 45 41 1 + Current sample, line, band is: 46 41 1 + Current sample, line, band is: 47 41 1 + Current sample, line, band is: 48 41 1 + Current sample, line, band is: 49 41 1 + Current sample, line, band is: 50 41 1 + Current sample, line, band is: 51 41 1 + Current sample, line, band is: 52 41 1 + Current sample, line, band is: 53 41 1 + Current sample, line, band is: 54 41 1 + Current sample, line, band is: 55 41 1 + Current sample, line, band is: 56 41 1 + Current sample, line, band is: 57 41 1 + Current sample, line, band is: 58 41 1 + Current sample, line, band is: 59 41 1 + Current sample, line, band is: 60 41 1 + Current sample, line, band is: 61 41 1 + Current sample, line, band is: 62 41 1 + Current sample, line, band is: 63 41 1 + Current sample, line, band is: 64 41 1 + Current sample, line, band is: 65 41 1 + Current sample, line, band is: 66 41 1 + Current sample, line, band is: 67 41 1 + Current sample, line, band is: 68 41 1 + Current sample, line, band is: 69 41 1 + Current sample, line, band is: 70 41 1 + Current sample, line, band is: 71 41 1 + Current sample, line, band is: 72 41 1 + Current sample, line, band is: 73 41 1 + Current sample, line, band is: 74 41 1 + Current sample, line, band is: 75 41 1 + Current sample, line, band is: 76 41 1 + Current sample, line, band is: 77 41 1 + Current sample, line, band is: 78 41 1 + Current sample, line, band is: 79 41 1 + Current sample, line, band is: 80 41 1 + Current sample, line, band is: 81 41 1 + Current sample, line, band is: 82 41 1 + Current sample, line, band is: 83 41 1 + Current sample, line, band is: 84 41 1 + Current sample, line, band is: 85 41 1 + Current sample, line, band is: 86 41 1 + Current sample, line, band is: 87 41 1 + Current sample, line, band is: 88 41 1 + Current sample, line, band is: 89 41 1 + Current sample, line, band is: 90 41 1 + Current sample, line, band is: 91 41 1 + Current sample, line, band is: 92 41 1 + Current sample, line, band is: 93 41 1 + Current sample, line, band is: 94 41 1 + Current sample, line, band is: 95 41 1 + Current sample, line, band is: 96 41 1 + Current sample, line, band is: 97 41 1 + Current sample, line, band is: 98 41 1 + Current sample, line, band is: 99 41 1 + Current sample, line, band is: 100 41 1 + Current sample, line, band is: 101 41 1 + Current sample, line, band is: 102 41 1 + Current sample, line, band is: 103 41 1 + Current sample, line, band is: 104 41 1 + Current sample, line, band is: 105 41 1 + Current sample, line, band is: 106 41 1 + Current sample, line, band is: 107 41 1 + Current sample, line, band is: 108 41 1 + Current sample, line, band is: 109 41 1 + Current sample, line, band is: 110 41 1 + Current sample, line, band is: 111 41 1 + Current sample, line, band is: 112 41 1 + Current sample, line, band is: 113 41 1 + Current sample, line, band is: 114 41 1 + Current sample, line, band is: 115 41 1 + Current sample, line, band is: 116 41 1 + Current sample, line, band is: 117 41 1 + Current sample, line, band is: 118 41 1 + Current sample, line, band is: 119 41 1 + Current sample, line, band is: 120 41 1 + Current sample, line, band is: 121 41 1 + Current sample, line, band is: 122 41 1 + Current sample, line, band is: 123 41 1 + Current sample, line, band is: 124 41 1 + Current sample, line, band is: 125 41 1 + Current sample, line, band is: 126 41 1 + Current sample, line, band is: 1 42 1 + Current sample, line, band is: 2 42 1 + Current sample, line, band is: 3 42 1 + Current sample, line, band is: 4 42 1 + Current sample, line, band is: 5 42 1 + Current sample, line, band is: 6 42 1 + Current sample, line, band is: 7 42 1 + Current sample, line, band is: 8 42 1 + Current sample, line, band is: 9 42 1 + Current sample, line, band is: 10 42 1 + Current sample, line, band is: 11 42 1 + Current sample, line, band is: 12 42 1 + Current sample, line, band is: 13 42 1 + Current sample, line, band is: 14 42 1 + Current sample, line, band is: 15 42 1 + Current sample, line, band is: 16 42 1 + Current sample, line, band is: 17 42 1 + Current sample, line, band is: 18 42 1 + Current sample, line, band is: 19 42 1 + Current sample, line, band is: 20 42 1 + Current sample, line, band is: 21 42 1 + Current sample, line, band is: 22 42 1 + Current sample, line, band is: 23 42 1 + Current sample, line, band is: 24 42 1 + Current sample, line, band is: 25 42 1 + Current sample, line, band is: 26 42 1 + Current sample, line, band is: 27 42 1 + Current sample, line, band is: 28 42 1 + Current sample, line, band is: 29 42 1 + Current sample, line, band is: 30 42 1 + Current sample, line, band is: 31 42 1 + Current sample, line, band is: 32 42 1 + Current sample, line, band is: 33 42 1 + Current sample, line, band is: 34 42 1 + Current sample, line, band is: 35 42 1 + Current sample, line, band is: 36 42 1 + Current sample, line, band is: 37 42 1 + Current sample, line, band is: 38 42 1 + Current sample, line, band is: 39 42 1 + Current sample, line, band is: 40 42 1 + Current sample, line, band is: 41 42 1 + Current sample, line, band is: 42 42 1 + Current sample, line, band is: 43 42 1 + Current sample, line, band is: 44 42 1 + Current sample, line, band is: 45 42 1 + Current sample, line, band is: 46 42 1 + Current sample, line, band is: 47 42 1 + Current sample, line, band is: 48 42 1 + Current sample, line, band is: 49 42 1 + Current sample, line, band is: 50 42 1 + Current sample, line, band is: 51 42 1 + Current sample, line, band is: 52 42 1 + Current sample, line, band is: 53 42 1 + Current sample, line, band is: 54 42 1 + Current sample, line, band is: 55 42 1 + Current sample, line, band is: 56 42 1 + Current sample, line, band is: 57 42 1 + Current sample, line, band is: 58 42 1 + Current sample, line, band is: 59 42 1 + Current sample, line, band is: 60 42 1 + Current sample, line, band is: 61 42 1 + Current sample, line, band is: 62 42 1 + Current sample, line, band is: 63 42 1 + Current sample, line, band is: 64 42 1 + Current sample, line, band is: 65 42 1 + Current sample, line, band is: 66 42 1 + Current sample, line, band is: 67 42 1 + Current sample, line, band is: 68 42 1 + Current sample, line, band is: 69 42 1 + Current sample, line, band is: 70 42 1 + Current sample, line, band is: 71 42 1 + Current sample, line, band is: 72 42 1 + Current sample, line, band is: 73 42 1 + Current sample, line, band is: 74 42 1 + Current sample, line, band is: 75 42 1 + Current sample, line, band is: 76 42 1 + Current sample, line, band is: 77 42 1 + Current sample, line, band is: 78 42 1 + Current sample, line, band is: 79 42 1 + Current sample, line, band is: 80 42 1 + Current sample, line, band is: 81 42 1 + Current sample, line, band is: 82 42 1 + Current sample, line, band is: 83 42 1 + Current sample, line, band is: 84 42 1 + Current sample, line, band is: 85 42 1 + Current sample, line, band is: 86 42 1 + Current sample, line, band is: 87 42 1 + Current sample, line, band is: 88 42 1 + Current sample, line, band is: 89 42 1 + Current sample, line, band is: 90 42 1 + Current sample, line, band is: 91 42 1 + Current sample, line, band is: 92 42 1 + Current sample, line, band is: 93 42 1 + Current sample, line, band is: 94 42 1 + Current sample, line, band is: 95 42 1 + Current sample, line, band is: 96 42 1 + Current sample, line, band is: 97 42 1 + Current sample, line, band is: 98 42 1 + Current sample, line, band is: 99 42 1 + Current sample, line, band is: 100 42 1 + Current sample, line, band is: 101 42 1 + Current sample, line, band is: 102 42 1 + Current sample, line, band is: 103 42 1 + Current sample, line, band is: 104 42 1 + Current sample, line, band is: 105 42 1 + Current sample, line, band is: 106 42 1 + Current sample, line, band is: 107 42 1 + Current sample, line, band is: 108 42 1 + Current sample, line, band is: 109 42 1 + Current sample, line, band is: 110 42 1 + Current sample, line, band is: 111 42 1 + Current sample, line, band is: 112 42 1 + Current sample, line, band is: 113 42 1 + Current sample, line, band is: 114 42 1 + Current sample, line, band is: 115 42 1 + Current sample, line, band is: 116 42 1 + Current sample, line, band is: 117 42 1 + Current sample, line, band is: 118 42 1 + Current sample, line, band is: 119 42 1 + Current sample, line, band is: 120 42 1 + Current sample, line, band is: 121 42 1 + Current sample, line, band is: 122 42 1 + Current sample, line, band is: 123 42 1 + Current sample, line, band is: 124 42 1 + Current sample, line, band is: 125 42 1 + Current sample, line, band is: 126 42 1 + Current sample, line, band is: 1 43 1 + Current sample, line, band is: 2 43 1 + Current sample, line, band is: 3 43 1 + Current sample, line, band is: 4 43 1 + Current sample, line, band is: 5 43 1 + Current sample, line, band is: 6 43 1 + Current sample, line, band is: 7 43 1 + Current sample, line, band is: 8 43 1 + Current sample, line, band is: 9 43 1 + Current sample, line, band is: 10 43 1 + Current sample, line, band is: 11 43 1 + Current sample, line, band is: 12 43 1 + Current sample, line, band is: 13 43 1 + Current sample, line, band is: 14 43 1 + Current sample, line, band is: 15 43 1 + Current sample, line, band is: 16 43 1 + Current sample, line, band is: 17 43 1 + Current sample, line, band is: 18 43 1 + Current sample, line, band is: 19 43 1 + Current sample, line, band is: 20 43 1 + Current sample, line, band is: 21 43 1 + Current sample, line, band is: 22 43 1 + Current sample, line, band is: 23 43 1 + Current sample, line, band is: 24 43 1 + Current sample, line, band is: 25 43 1 + Current sample, line, band is: 26 43 1 + Current sample, line, band is: 27 43 1 + Current sample, line, band is: 28 43 1 + Current sample, line, band is: 29 43 1 + Current sample, line, band is: 30 43 1 + Current sample, line, band is: 31 43 1 + Current sample, line, band is: 32 43 1 + Current sample, line, band is: 33 43 1 + Current sample, line, band is: 34 43 1 + Current sample, line, band is: 35 43 1 + Current sample, line, band is: 36 43 1 + Current sample, line, band is: 37 43 1 + Current sample, line, band is: 38 43 1 + Current sample, line, band is: 39 43 1 + Current sample, line, band is: 40 43 1 + Current sample, line, band is: 41 43 1 + Current sample, line, band is: 42 43 1 + Current sample, line, band is: 43 43 1 + Current sample, line, band is: 44 43 1 + Current sample, line, band is: 45 43 1 + Current sample, line, band is: 46 43 1 + Current sample, line, band is: 47 43 1 + Current sample, line, band is: 48 43 1 + Current sample, line, band is: 49 43 1 + Current sample, line, band is: 50 43 1 + Current sample, line, band is: 51 43 1 + Current sample, line, band is: 52 43 1 + Current sample, line, band is: 53 43 1 + Current sample, line, band is: 54 43 1 + Current sample, line, band is: 55 43 1 + Current sample, line, band is: 56 43 1 + Current sample, line, band is: 57 43 1 + Current sample, line, band is: 58 43 1 + Current sample, line, band is: 59 43 1 + Current sample, line, band is: 60 43 1 + Current sample, line, band is: 61 43 1 + Current sample, line, band is: 62 43 1 + Current sample, line, band is: 63 43 1 + Current sample, line, band is: 64 43 1 + Current sample, line, band is: 65 43 1 + Current sample, line, band is: 66 43 1 + Current sample, line, band is: 67 43 1 + Current sample, line, band is: 68 43 1 + Current sample, line, band is: 69 43 1 + Current sample, line, band is: 70 43 1 + Current sample, line, band is: 71 43 1 + Current sample, line, band is: 72 43 1 + Current sample, line, band is: 73 43 1 + Current sample, line, band is: 74 43 1 + Current sample, line, band is: 75 43 1 + Current sample, line, band is: 76 43 1 + Current sample, line, band is: 77 43 1 + Current sample, line, band is: 78 43 1 + Current sample, line, band is: 79 43 1 + Current sample, line, band is: 80 43 1 + Current sample, line, band is: 81 43 1 + Current sample, line, band is: 82 43 1 + Current sample, line, band is: 83 43 1 + Current sample, line, band is: 84 43 1 + Current sample, line, band is: 85 43 1 + Current sample, line, band is: 86 43 1 + Current sample, line, band is: 87 43 1 + Current sample, line, band is: 88 43 1 + Current sample, line, band is: 89 43 1 + Current sample, line, band is: 90 43 1 + Current sample, line, band is: 91 43 1 + Current sample, line, band is: 92 43 1 + Current sample, line, band is: 93 43 1 + Current sample, line, band is: 94 43 1 + Current sample, line, band is: 95 43 1 + Current sample, line, band is: 96 43 1 + Current sample, line, band is: 97 43 1 + Current sample, line, band is: 98 43 1 + Current sample, line, band is: 99 43 1 + Current sample, line, band is: 100 43 1 + Current sample, line, band is: 101 43 1 + Current sample, line, band is: 102 43 1 + Current sample, line, band is: 103 43 1 + Current sample, line, band is: 104 43 1 + Current sample, line, band is: 105 43 1 + Current sample, line, band is: 106 43 1 + Current sample, line, band is: 107 43 1 + Current sample, line, band is: 108 43 1 + Current sample, line, band is: 109 43 1 + Current sample, line, band is: 110 43 1 + Current sample, line, band is: 111 43 1 + Current sample, line, band is: 112 43 1 + Current sample, line, band is: 113 43 1 + Current sample, line, band is: 114 43 1 + Current sample, line, band is: 115 43 1 + Current sample, line, band is: 116 43 1 + Current sample, line, band is: 117 43 1 + Current sample, line, band is: 118 43 1 + Current sample, line, band is: 119 43 1 + Current sample, line, band is: 120 43 1 + Current sample, line, band is: 121 43 1 + Current sample, line, band is: 122 43 1 + Current sample, line, band is: 123 43 1 + Current sample, line, band is: 124 43 1 + Current sample, line, band is: 125 43 1 + Current sample, line, band is: 126 43 1 + Current sample, line, band is: 1 44 1 + Current sample, line, band is: 2 44 1 + Current sample, line, band is: 3 44 1 + Current sample, line, band is: 4 44 1 + Current sample, line, band is: 5 44 1 + Current sample, line, band is: 6 44 1 + Current sample, line, band is: 7 44 1 + Current sample, line, band is: 8 44 1 + Current sample, line, band is: 9 44 1 + Current sample, line, band is: 10 44 1 + Current sample, line, band is: 11 44 1 + Current sample, line, band is: 12 44 1 + Current sample, line, band is: 13 44 1 + Current sample, line, band is: 14 44 1 + Current sample, line, band is: 15 44 1 + Current sample, line, band is: 16 44 1 + Current sample, line, band is: 17 44 1 + Current sample, line, band is: 18 44 1 + Current sample, line, band is: 19 44 1 + Current sample, line, band is: 20 44 1 + Current sample, line, band is: 21 44 1 + Current sample, line, band is: 22 44 1 + Current sample, line, band is: 23 44 1 + Current sample, line, band is: 24 44 1 + Current sample, line, band is: 25 44 1 + Current sample, line, band is: 26 44 1 + Current sample, line, band is: 27 44 1 + Current sample, line, band is: 28 44 1 + Current sample, line, band is: 29 44 1 + Current sample, line, band is: 30 44 1 + Current sample, line, band is: 31 44 1 + Current sample, line, band is: 32 44 1 + Current sample, line, band is: 33 44 1 + Current sample, line, band is: 34 44 1 + Current sample, line, band is: 35 44 1 + Current sample, line, band is: 36 44 1 + Current sample, line, band is: 37 44 1 + Current sample, line, band is: 38 44 1 + Current sample, line, band is: 39 44 1 + Current sample, line, band is: 40 44 1 + Current sample, line, band is: 41 44 1 + Current sample, line, band is: 42 44 1 + Current sample, line, band is: 43 44 1 + Current sample, line, band is: 44 44 1 + Current sample, line, band is: 45 44 1 + Current sample, line, band is: 46 44 1 + Current sample, line, band is: 47 44 1 + Current sample, line, band is: 48 44 1 + Current sample, line, band is: 49 44 1 + Current sample, line, band is: 50 44 1 + Current sample, line, band is: 51 44 1 + Current sample, line, band is: 52 44 1 + Current sample, line, band is: 53 44 1 + Current sample, line, band is: 54 44 1 + Current sample, line, band is: 55 44 1 + Current sample, line, band is: 56 44 1 + Current sample, line, band is: 57 44 1 + Current sample, line, band is: 58 44 1 + Current sample, line, band is: 59 44 1 + Current sample, line, band is: 60 44 1 + Current sample, line, band is: 61 44 1 + Current sample, line, band is: 62 44 1 + Current sample, line, band is: 63 44 1 + Current sample, line, band is: 64 44 1 + Current sample, line, band is: 65 44 1 + Current sample, line, band is: 66 44 1 + Current sample, line, band is: 67 44 1 + Current sample, line, band is: 68 44 1 + Current sample, line, band is: 69 44 1 + Current sample, line, band is: 70 44 1 + Current sample, line, band is: 71 44 1 + Current sample, line, band is: 72 44 1 + Current sample, line, band is: 73 44 1 + Current sample, line, band is: 74 44 1 + Current sample, line, band is: 75 44 1 + Current sample, line, band is: 76 44 1 + Current sample, line, band is: 77 44 1 + Current sample, line, band is: 78 44 1 + Current sample, line, band is: 79 44 1 + Current sample, line, band is: 80 44 1 + Current sample, line, band is: 81 44 1 + Current sample, line, band is: 82 44 1 + Current sample, line, band is: 83 44 1 + Current sample, line, band is: 84 44 1 + Current sample, line, band is: 85 44 1 + Current sample, line, band is: 86 44 1 + Current sample, line, band is: 87 44 1 + Current sample, line, band is: 88 44 1 + Current sample, line, band is: 89 44 1 + Current sample, line, band is: 90 44 1 + Current sample, line, band is: 91 44 1 + Current sample, line, band is: 92 44 1 + Current sample, line, band is: 93 44 1 + Current sample, line, band is: 94 44 1 + Current sample, line, band is: 95 44 1 + Current sample, line, band is: 96 44 1 + Current sample, line, band is: 97 44 1 + Current sample, line, band is: 98 44 1 + Current sample, line, band is: 99 44 1 + Current sample, line, band is: 100 44 1 + Current sample, line, band is: 101 44 1 + Current sample, line, band is: 102 44 1 + Current sample, line, band is: 103 44 1 + Current sample, line, band is: 104 44 1 + Current sample, line, band is: 105 44 1 + Current sample, line, band is: 106 44 1 + Current sample, line, band is: 107 44 1 + Current sample, line, band is: 108 44 1 + Current sample, line, band is: 109 44 1 + Current sample, line, band is: 110 44 1 + Current sample, line, band is: 111 44 1 + Current sample, line, band is: 112 44 1 + Current sample, line, band is: 113 44 1 + Current sample, line, band is: 114 44 1 + Current sample, line, band is: 115 44 1 + Current sample, line, band is: 116 44 1 + Current sample, line, band is: 117 44 1 + Current sample, line, band is: 118 44 1 + Current sample, line, band is: 119 44 1 + Current sample, line, band is: 120 44 1 + Current sample, line, band is: 121 44 1 + Current sample, line, band is: 122 44 1 + Current sample, line, band is: 123 44 1 + Current sample, line, band is: 124 44 1 + Current sample, line, band is: 125 44 1 + Current sample, line, band is: 126 44 1 + Current sample, line, band is: 1 45 1 + Current sample, line, band is: 2 45 1 + Current sample, line, band is: 3 45 1 + Current sample, line, band is: 4 45 1 + Current sample, line, band is: 5 45 1 + Current sample, line, band is: 6 45 1 + Current sample, line, band is: 7 45 1 + Current sample, line, band is: 8 45 1 + Current sample, line, band is: 9 45 1 + Current sample, line, band is: 10 45 1 + Current sample, line, band is: 11 45 1 + Current sample, line, band is: 12 45 1 + Current sample, line, band is: 13 45 1 + Current sample, line, band is: 14 45 1 + Current sample, line, band is: 15 45 1 + Current sample, line, band is: 16 45 1 + Current sample, line, band is: 17 45 1 + Current sample, line, band is: 18 45 1 + Current sample, line, band is: 19 45 1 + Current sample, line, band is: 20 45 1 + Current sample, line, band is: 21 45 1 + Current sample, line, band is: 22 45 1 + Current sample, line, band is: 23 45 1 + Current sample, line, band is: 24 45 1 + Current sample, line, band is: 25 45 1 + Current sample, line, band is: 26 45 1 + Current sample, line, band is: 27 45 1 + Current sample, line, band is: 28 45 1 + Current sample, line, band is: 29 45 1 + Current sample, line, band is: 30 45 1 + Current sample, line, band is: 31 45 1 + Current sample, line, band is: 32 45 1 + Current sample, line, band is: 33 45 1 + Current sample, line, band is: 34 45 1 + Current sample, line, band is: 35 45 1 + Current sample, line, band is: 36 45 1 + Current sample, line, band is: 37 45 1 + Current sample, line, band is: 38 45 1 + Current sample, line, band is: 39 45 1 + Current sample, line, band is: 40 45 1 + Current sample, line, band is: 41 45 1 + Current sample, line, band is: 42 45 1 + Current sample, line, band is: 43 45 1 + Current sample, line, band is: 44 45 1 + Current sample, line, band is: 45 45 1 + Current sample, line, band is: 46 45 1 + Current sample, line, band is: 47 45 1 + Current sample, line, band is: 48 45 1 + Current sample, line, band is: 49 45 1 + Current sample, line, band is: 50 45 1 + Current sample, line, band is: 51 45 1 + Current sample, line, band is: 52 45 1 + Current sample, line, band is: 53 45 1 + Current sample, line, band is: 54 45 1 + Current sample, line, band is: 55 45 1 + Current sample, line, band is: 56 45 1 + Current sample, line, band is: 57 45 1 + Current sample, line, band is: 58 45 1 + Current sample, line, band is: 59 45 1 + Current sample, line, band is: 60 45 1 + Current sample, line, band is: 61 45 1 + Current sample, line, band is: 62 45 1 + Current sample, line, band is: 63 45 1 + Current sample, line, band is: 64 45 1 + Current sample, line, band is: 65 45 1 + Current sample, line, band is: 66 45 1 + Current sample, line, band is: 67 45 1 + Current sample, line, band is: 68 45 1 + Current sample, line, band is: 69 45 1 + Current sample, line, band is: 70 45 1 + Current sample, line, band is: 71 45 1 + Current sample, line, band is: 72 45 1 + Current sample, line, band is: 73 45 1 + Current sample, line, band is: 74 45 1 + Current sample, line, band is: 75 45 1 + Current sample, line, band is: 76 45 1 + Current sample, line, band is: 77 45 1 + Current sample, line, band is: 78 45 1 + Current sample, line, band is: 79 45 1 + Current sample, line, band is: 80 45 1 + Current sample, line, band is: 81 45 1 + Current sample, line, band is: 82 45 1 + Current sample, line, band is: 83 45 1 + Current sample, line, band is: 84 45 1 + Current sample, line, band is: 85 45 1 + Current sample, line, band is: 86 45 1 + Current sample, line, band is: 87 45 1 + Current sample, line, band is: 88 45 1 + Current sample, line, band is: 89 45 1 + Current sample, line, band is: 90 45 1 + Current sample, line, band is: 91 45 1 + Current sample, line, band is: 92 45 1 + Current sample, line, band is: 93 45 1 + Current sample, line, band is: 94 45 1 + Current sample, line, band is: 95 45 1 + Current sample, line, band is: 96 45 1 + Current sample, line, band is: 97 45 1 + Current sample, line, band is: 98 45 1 + Current sample, line, band is: 99 45 1 + Current sample, line, band is: 100 45 1 + Current sample, line, band is: 101 45 1 + Current sample, line, band is: 102 45 1 + Current sample, line, band is: 103 45 1 + Current sample, line, band is: 104 45 1 + Current sample, line, band is: 105 45 1 + Current sample, line, band is: 106 45 1 + Current sample, line, band is: 107 45 1 + Current sample, line, band is: 108 45 1 + Current sample, line, band is: 109 45 1 + Current sample, line, band is: 110 45 1 + Current sample, line, band is: 111 45 1 + Current sample, line, band is: 112 45 1 + Current sample, line, band is: 113 45 1 + Current sample, line, band is: 114 45 1 + Current sample, line, band is: 115 45 1 + Current sample, line, band is: 116 45 1 + Current sample, line, band is: 117 45 1 + Current sample, line, band is: 118 45 1 + Current sample, line, band is: 119 45 1 + Current sample, line, band is: 120 45 1 + Current sample, line, band is: 121 45 1 + Current sample, line, band is: 122 45 1 + Current sample, line, band is: 123 45 1 + Current sample, line, band is: 124 45 1 + Current sample, line, band is: 125 45 1 + Current sample, line, band is: 126 45 1 + Current sample, line, band is: 1 46 1 + Current sample, line, band is: 2 46 1 + Current sample, line, band is: 3 46 1 + Current sample, line, band is: 4 46 1 + Current sample, line, band is: 5 46 1 + Current sample, line, band is: 6 46 1 + Current sample, line, band is: 7 46 1 + Current sample, line, band is: 8 46 1 + Current sample, line, band is: 9 46 1 + Current sample, line, band is: 10 46 1 + Current sample, line, band is: 11 46 1 + Current sample, line, band is: 12 46 1 + Current sample, line, band is: 13 46 1 + Current sample, line, band is: 14 46 1 + Current sample, line, band is: 15 46 1 + Current sample, line, band is: 16 46 1 + Current sample, line, band is: 17 46 1 + Current sample, line, band is: 18 46 1 + Current sample, line, band is: 19 46 1 + Current sample, line, band is: 20 46 1 + Current sample, line, band is: 21 46 1 + Current sample, line, band is: 22 46 1 + Current sample, line, band is: 23 46 1 + Current sample, line, band is: 24 46 1 + Current sample, line, band is: 25 46 1 + Current sample, line, band is: 26 46 1 + Current sample, line, band is: 27 46 1 + Current sample, line, band is: 28 46 1 + Current sample, line, band is: 29 46 1 + Current sample, line, band is: 30 46 1 + Current sample, line, band is: 31 46 1 + Current sample, line, band is: 32 46 1 + Current sample, line, band is: 33 46 1 + Current sample, line, band is: 34 46 1 + Current sample, line, band is: 35 46 1 + Current sample, line, band is: 36 46 1 + Current sample, line, band is: 37 46 1 + Current sample, line, band is: 38 46 1 + Current sample, line, band is: 39 46 1 + Current sample, line, band is: 40 46 1 + Current sample, line, band is: 41 46 1 + Current sample, line, band is: 42 46 1 + Current sample, line, band is: 43 46 1 + Current sample, line, band is: 44 46 1 + Current sample, line, band is: 45 46 1 + Current sample, line, band is: 46 46 1 + Current sample, line, band is: 47 46 1 + Current sample, line, band is: 48 46 1 + Current sample, line, band is: 49 46 1 + Current sample, line, band is: 50 46 1 + Current sample, line, band is: 51 46 1 + Current sample, line, band is: 52 46 1 + Current sample, line, band is: 53 46 1 + Current sample, line, band is: 54 46 1 + Current sample, line, band is: 55 46 1 + Current sample, line, band is: 56 46 1 + Current sample, line, band is: 57 46 1 + Current sample, line, band is: 58 46 1 + Current sample, line, band is: 59 46 1 + Current sample, line, band is: 60 46 1 + Current sample, line, band is: 61 46 1 + Current sample, line, band is: 62 46 1 + Current sample, line, band is: 63 46 1 + Current sample, line, band is: 64 46 1 + Current sample, line, band is: 65 46 1 + Current sample, line, band is: 66 46 1 + Current sample, line, band is: 67 46 1 + Current sample, line, band is: 68 46 1 + Current sample, line, band is: 69 46 1 + Current sample, line, band is: 70 46 1 + Current sample, line, band is: 71 46 1 + Current sample, line, band is: 72 46 1 + Current sample, line, band is: 73 46 1 + Current sample, line, band is: 74 46 1 + Current sample, line, band is: 75 46 1 + Current sample, line, band is: 76 46 1 + Current sample, line, band is: 77 46 1 + Current sample, line, band is: 78 46 1 + Current sample, line, band is: 79 46 1 + Current sample, line, band is: 80 46 1 + Current sample, line, band is: 81 46 1 + Current sample, line, band is: 82 46 1 + Current sample, line, band is: 83 46 1 + Current sample, line, band is: 84 46 1 + Current sample, line, band is: 85 46 1 + Current sample, line, band is: 86 46 1 + Current sample, line, band is: 87 46 1 + Current sample, line, band is: 88 46 1 + Current sample, line, band is: 89 46 1 + Current sample, line, band is: 90 46 1 + Current sample, line, band is: 91 46 1 + Current sample, line, band is: 92 46 1 + Current sample, line, band is: 93 46 1 + Current sample, line, band is: 94 46 1 + Current sample, line, band is: 95 46 1 + Current sample, line, band is: 96 46 1 + Current sample, line, band is: 97 46 1 + Current sample, line, band is: 98 46 1 + Current sample, line, band is: 99 46 1 + Current sample, line, band is: 100 46 1 + Current sample, line, band is: 101 46 1 + Current sample, line, band is: 102 46 1 + Current sample, line, band is: 103 46 1 + Current sample, line, band is: 104 46 1 + Current sample, line, band is: 105 46 1 + Current sample, line, band is: 106 46 1 + Current sample, line, band is: 107 46 1 + Current sample, line, band is: 108 46 1 + Current sample, line, band is: 109 46 1 + Current sample, line, band is: 110 46 1 + Current sample, line, band is: 111 46 1 + Current sample, line, band is: 112 46 1 + Current sample, line, band is: 113 46 1 + Current sample, line, band is: 114 46 1 + Current sample, line, band is: 115 46 1 + Current sample, line, band is: 116 46 1 + Current sample, line, band is: 117 46 1 + Current sample, line, band is: 118 46 1 + Current sample, line, band is: 119 46 1 + Current sample, line, band is: 120 46 1 + Current sample, line, band is: 121 46 1 + Current sample, line, band is: 122 46 1 + Current sample, line, band is: 123 46 1 + Current sample, line, band is: 124 46 1 + Current sample, line, band is: 125 46 1 + Current sample, line, band is: 126 46 1 + Current sample, line, band is: 1 47 1 + Current sample, line, band is: 2 47 1 + Current sample, line, band is: 3 47 1 + Current sample, line, band is: 4 47 1 + Current sample, line, band is: 5 47 1 + Current sample, line, band is: 6 47 1 + Current sample, line, band is: 7 47 1 + Current sample, line, band is: 8 47 1 + Current sample, line, band is: 9 47 1 + Current sample, line, band is: 10 47 1 + Current sample, line, band is: 11 47 1 + Current sample, line, band is: 12 47 1 + Current sample, line, band is: 13 47 1 + Current sample, line, band is: 14 47 1 + Current sample, line, band is: 15 47 1 + Current sample, line, band is: 16 47 1 + Current sample, line, band is: 17 47 1 + Current sample, line, band is: 18 47 1 + Current sample, line, band is: 19 47 1 + Current sample, line, band is: 20 47 1 + Current sample, line, band is: 21 47 1 + Current sample, line, band is: 22 47 1 + Current sample, line, band is: 23 47 1 + Current sample, line, band is: 24 47 1 + Current sample, line, band is: 25 47 1 + Current sample, line, band is: 26 47 1 + Current sample, line, band is: 27 47 1 + Current sample, line, band is: 28 47 1 + Current sample, line, band is: 29 47 1 + Current sample, line, band is: 30 47 1 + Current sample, line, band is: 31 47 1 + Current sample, line, band is: 32 47 1 + Current sample, line, band is: 33 47 1 + Current sample, line, band is: 34 47 1 + Current sample, line, band is: 35 47 1 + Current sample, line, band is: 36 47 1 + Current sample, line, band is: 37 47 1 + Current sample, line, band is: 38 47 1 + Current sample, line, band is: 39 47 1 + Current sample, line, band is: 40 47 1 + Current sample, line, band is: 41 47 1 + Current sample, line, band is: 42 47 1 + Current sample, line, band is: 43 47 1 + Current sample, line, band is: 44 47 1 + Current sample, line, band is: 45 47 1 + Current sample, line, band is: 46 47 1 + Current sample, line, band is: 47 47 1 + Current sample, line, band is: 48 47 1 + Current sample, line, band is: 49 47 1 + Current sample, line, band is: 50 47 1 + Current sample, line, band is: 51 47 1 + Current sample, line, band is: 52 47 1 + Current sample, line, band is: 53 47 1 + Current sample, line, band is: 54 47 1 + Current sample, line, band is: 55 47 1 + Current sample, line, band is: 56 47 1 + Current sample, line, band is: 57 47 1 + Current sample, line, band is: 58 47 1 + Current sample, line, band is: 59 47 1 + Current sample, line, band is: 60 47 1 + Current sample, line, band is: 61 47 1 + Current sample, line, band is: 62 47 1 + Current sample, line, band is: 63 47 1 + Current sample, line, band is: 64 47 1 + Current sample, line, band is: 65 47 1 + Current sample, line, band is: 66 47 1 + Current sample, line, band is: 67 47 1 + Current sample, line, band is: 68 47 1 + Current sample, line, band is: 69 47 1 + Current sample, line, band is: 70 47 1 + Current sample, line, band is: 71 47 1 + Current sample, line, band is: 72 47 1 + Current sample, line, band is: 73 47 1 + Current sample, line, band is: 74 47 1 + Current sample, line, band is: 75 47 1 + Current sample, line, band is: 76 47 1 + Current sample, line, band is: 77 47 1 + Current sample, line, band is: 78 47 1 + Current sample, line, band is: 79 47 1 + Current sample, line, band is: 80 47 1 + Current sample, line, band is: 81 47 1 + Current sample, line, band is: 82 47 1 + Current sample, line, band is: 83 47 1 + Current sample, line, band is: 84 47 1 + Current sample, line, band is: 85 47 1 + Current sample, line, band is: 86 47 1 + Current sample, line, band is: 87 47 1 + Current sample, line, band is: 88 47 1 + Current sample, line, band is: 89 47 1 + Current sample, line, band is: 90 47 1 + Current sample, line, band is: 91 47 1 + Current sample, line, band is: 92 47 1 + Current sample, line, band is: 93 47 1 + Current sample, line, band is: 94 47 1 + Current sample, line, band is: 95 47 1 + Current sample, line, band is: 96 47 1 + Current sample, line, band is: 97 47 1 + Current sample, line, band is: 98 47 1 + Current sample, line, band is: 99 47 1 + Current sample, line, band is: 100 47 1 + Current sample, line, band is: 101 47 1 + Current sample, line, band is: 102 47 1 + Current sample, line, band is: 103 47 1 + Current sample, line, band is: 104 47 1 + Current sample, line, band is: 105 47 1 + Current sample, line, band is: 106 47 1 + Current sample, line, band is: 107 47 1 + Current sample, line, band is: 108 47 1 + Current sample, line, band is: 109 47 1 + Current sample, line, band is: 110 47 1 + Current sample, line, band is: 111 47 1 + Current sample, line, band is: 112 47 1 + Current sample, line, band is: 113 47 1 + Current sample, line, band is: 114 47 1 + Current sample, line, band is: 115 47 1 + Current sample, line, band is: 116 47 1 + Current sample, line, band is: 117 47 1 + Current sample, line, band is: 118 47 1 + Current sample, line, band is: 119 47 1 + Current sample, line, band is: 120 47 1 + Current sample, line, band is: 121 47 1 + Current sample, line, band is: 122 47 1 + Current sample, line, band is: 123 47 1 + Current sample, line, band is: 124 47 1 + Current sample, line, band is: 125 47 1 + Current sample, line, band is: 126 47 1 + Current sample, line, band is: 1 48 1 + Current sample, line, band is: 2 48 1 + Current sample, line, band is: 3 48 1 + Current sample, line, band is: 4 48 1 + Current sample, line, band is: 5 48 1 + Current sample, line, band is: 6 48 1 + Current sample, line, band is: 7 48 1 + Current sample, line, band is: 8 48 1 + Current sample, line, band is: 9 48 1 + Current sample, line, band is: 10 48 1 + Current sample, line, band is: 11 48 1 + Current sample, line, band is: 12 48 1 + Current sample, line, band is: 13 48 1 + Current sample, line, band is: 14 48 1 + Current sample, line, band is: 15 48 1 + Current sample, line, band is: 16 48 1 + Current sample, line, band is: 17 48 1 + Current sample, line, band is: 18 48 1 + Current sample, line, band is: 19 48 1 + Current sample, line, band is: 20 48 1 + Current sample, line, band is: 21 48 1 + Current sample, line, band is: 22 48 1 + Current sample, line, band is: 23 48 1 + Current sample, line, band is: 24 48 1 + Current sample, line, band is: 25 48 1 + Current sample, line, band is: 26 48 1 + Current sample, line, band is: 27 48 1 + Current sample, line, band is: 28 48 1 + Current sample, line, band is: 29 48 1 + Current sample, line, band is: 30 48 1 + Current sample, line, band is: 31 48 1 + Current sample, line, band is: 32 48 1 + Current sample, line, band is: 33 48 1 + Current sample, line, band is: 34 48 1 + Current sample, line, band is: 35 48 1 + Current sample, line, band is: 36 48 1 + Current sample, line, band is: 37 48 1 + Current sample, line, band is: 38 48 1 + Current sample, line, band is: 39 48 1 + Current sample, line, band is: 40 48 1 + Current sample, line, band is: 41 48 1 + Current sample, line, band is: 42 48 1 + Current sample, line, band is: 43 48 1 + Current sample, line, band is: 44 48 1 + Current sample, line, band is: 45 48 1 + Current sample, line, band is: 46 48 1 + Current sample, line, band is: 47 48 1 + Current sample, line, band is: 48 48 1 + Current sample, line, band is: 49 48 1 + Current sample, line, band is: 50 48 1 + Current sample, line, band is: 51 48 1 + Current sample, line, band is: 52 48 1 + Current sample, line, band is: 53 48 1 + Current sample, line, band is: 54 48 1 + Current sample, line, band is: 55 48 1 + Current sample, line, band is: 56 48 1 + Current sample, line, band is: 57 48 1 + Current sample, line, band is: 58 48 1 + Current sample, line, band is: 59 48 1 + Current sample, line, band is: 60 48 1 + Current sample, line, band is: 61 48 1 + Current sample, line, band is: 62 48 1 + Current sample, line, band is: 63 48 1 + Current sample, line, band is: 64 48 1 + Current sample, line, band is: 65 48 1 + Current sample, line, band is: 66 48 1 + Current sample, line, band is: 67 48 1 + Current sample, line, band is: 68 48 1 + Current sample, line, band is: 69 48 1 + Current sample, line, band is: 70 48 1 + Current sample, line, band is: 71 48 1 + Current sample, line, band is: 72 48 1 + Current sample, line, band is: 73 48 1 + Current sample, line, band is: 74 48 1 + Current sample, line, band is: 75 48 1 + Current sample, line, band is: 76 48 1 + Current sample, line, band is: 77 48 1 + Current sample, line, band is: 78 48 1 + Current sample, line, band is: 79 48 1 + Current sample, line, band is: 80 48 1 + Current sample, line, band is: 81 48 1 + Current sample, line, band is: 82 48 1 + Current sample, line, band is: 83 48 1 + Current sample, line, band is: 84 48 1 + Current sample, line, band is: 85 48 1 + Current sample, line, band is: 86 48 1 + Current sample, line, band is: 87 48 1 + Current sample, line, band is: 88 48 1 + Current sample, line, band is: 89 48 1 + Current sample, line, band is: 90 48 1 + Current sample, line, band is: 91 48 1 + Current sample, line, band is: 92 48 1 + Current sample, line, band is: 93 48 1 + Current sample, line, band is: 94 48 1 + Current sample, line, band is: 95 48 1 + Current sample, line, band is: 96 48 1 + Current sample, line, band is: 97 48 1 + Current sample, line, band is: 98 48 1 + Current sample, line, band is: 99 48 1 + Current sample, line, band is: 100 48 1 + Current sample, line, band is: 101 48 1 + Current sample, line, band is: 102 48 1 + Current sample, line, band is: 103 48 1 + Current sample, line, band is: 104 48 1 + Current sample, line, band is: 105 48 1 + Current sample, line, band is: 106 48 1 + Current sample, line, band is: 107 48 1 + Current sample, line, band is: 108 48 1 + Current sample, line, band is: 109 48 1 + Current sample, line, band is: 110 48 1 + Current sample, line, band is: 111 48 1 + Current sample, line, band is: 112 48 1 + Current sample, line, band is: 113 48 1 + Current sample, line, band is: 114 48 1 + Current sample, line, band is: 115 48 1 + Current sample, line, band is: 116 48 1 + Current sample, line, band is: 117 48 1 + Current sample, line, band is: 118 48 1 + Current sample, line, band is: 119 48 1 + Current sample, line, band is: 120 48 1 + Current sample, line, band is: 121 48 1 + Current sample, line, band is: 122 48 1 + Current sample, line, band is: 123 48 1 + Current sample, line, band is: 124 48 1 + Current sample, line, band is: 125 48 1 + Current sample, line, band is: 126 48 1 + Current sample, line, band is: 1 49 1 + Current sample, line, band is: 2 49 1 + Current sample, line, band is: 3 49 1 + Current sample, line, band is: 4 49 1 + Current sample, line, band is: 5 49 1 + Current sample, line, band is: 6 49 1 + Current sample, line, band is: 7 49 1 + Current sample, line, band is: 8 49 1 + Current sample, line, band is: 9 49 1 + Current sample, line, band is: 10 49 1 + Current sample, line, band is: 11 49 1 + Current sample, line, band is: 12 49 1 + Current sample, line, band is: 13 49 1 + Current sample, line, band is: 14 49 1 + Current sample, line, band is: 15 49 1 + Current sample, line, band is: 16 49 1 + Current sample, line, band is: 17 49 1 + Current sample, line, band is: 18 49 1 + Current sample, line, band is: 19 49 1 + Current sample, line, band is: 20 49 1 + Current sample, line, band is: 21 49 1 + Current sample, line, band is: 22 49 1 + Current sample, line, band is: 23 49 1 + Current sample, line, band is: 24 49 1 + Current sample, line, band is: 25 49 1 + Current sample, line, band is: 26 49 1 + Current sample, line, band is: 27 49 1 + Current sample, line, band is: 28 49 1 + Current sample, line, band is: 29 49 1 + Current sample, line, band is: 30 49 1 + Current sample, line, band is: 31 49 1 + Current sample, line, band is: 32 49 1 + Current sample, line, band is: 33 49 1 + Current sample, line, band is: 34 49 1 + Current sample, line, band is: 35 49 1 + Current sample, line, band is: 36 49 1 + Current sample, line, band is: 37 49 1 + Current sample, line, band is: 38 49 1 + Current sample, line, band is: 39 49 1 + Current sample, line, band is: 40 49 1 + Current sample, line, band is: 41 49 1 + Current sample, line, band is: 42 49 1 + Current sample, line, band is: 43 49 1 + Current sample, line, band is: 44 49 1 + Current sample, line, band is: 45 49 1 + Current sample, line, band is: 46 49 1 + Current sample, line, band is: 47 49 1 + Current sample, line, band is: 48 49 1 + Current sample, line, band is: 49 49 1 + Current sample, line, band is: 50 49 1 + Current sample, line, band is: 51 49 1 + Current sample, line, band is: 52 49 1 + Current sample, line, band is: 53 49 1 + Current sample, line, band is: 54 49 1 + Current sample, line, band is: 55 49 1 + Current sample, line, band is: 56 49 1 + Current sample, line, band is: 57 49 1 + Current sample, line, band is: 58 49 1 + Current sample, line, band is: 59 49 1 + Current sample, line, band is: 60 49 1 + Current sample, line, band is: 61 49 1 + Current sample, line, band is: 62 49 1 + Current sample, line, band is: 63 49 1 + Current sample, line, band is: 64 49 1 + Current sample, line, band is: 65 49 1 + Current sample, line, band is: 66 49 1 + Current sample, line, band is: 67 49 1 + Current sample, line, band is: 68 49 1 + Current sample, line, band is: 69 49 1 + Current sample, line, band is: 70 49 1 + Current sample, line, band is: 71 49 1 + Current sample, line, band is: 72 49 1 + Current sample, line, band is: 73 49 1 + Current sample, line, band is: 74 49 1 + Current sample, line, band is: 75 49 1 + Current sample, line, band is: 76 49 1 + Current sample, line, band is: 77 49 1 + Current sample, line, band is: 78 49 1 + Current sample, line, band is: 79 49 1 + Current sample, line, band is: 80 49 1 + Current sample, line, band is: 81 49 1 + Current sample, line, band is: 82 49 1 + Current sample, line, band is: 83 49 1 + Current sample, line, band is: 84 49 1 + Current sample, line, band is: 85 49 1 + Current sample, line, band is: 86 49 1 + Current sample, line, band is: 87 49 1 + Current sample, line, band is: 88 49 1 + Current sample, line, band is: 89 49 1 + Current sample, line, band is: 90 49 1 + Current sample, line, band is: 91 49 1 + Current sample, line, band is: 92 49 1 + Current sample, line, band is: 93 49 1 + Current sample, line, band is: 94 49 1 + Current sample, line, band is: 95 49 1 + Current sample, line, band is: 96 49 1 + Current sample, line, band is: 97 49 1 + Current sample, line, band is: 98 49 1 + Current sample, line, band is: 99 49 1 + Current sample, line, band is: 100 49 1 + Current sample, line, band is: 101 49 1 + Current sample, line, band is: 102 49 1 + Current sample, line, band is: 103 49 1 + Current sample, line, band is: 104 49 1 + Current sample, line, band is: 105 49 1 + Current sample, line, band is: 106 49 1 + Current sample, line, band is: 107 49 1 + Current sample, line, band is: 108 49 1 + Current sample, line, band is: 109 49 1 + Current sample, line, band is: 110 49 1 + Current sample, line, band is: 111 49 1 + Current sample, line, band is: 112 49 1 + Current sample, line, band is: 113 49 1 + Current sample, line, band is: 114 49 1 + Current sample, line, band is: 115 49 1 + Current sample, line, band is: 116 49 1 + Current sample, line, band is: 117 49 1 + Current sample, line, band is: 118 49 1 + Current sample, line, band is: 119 49 1 + Current sample, line, band is: 120 49 1 + Current sample, line, band is: 121 49 1 + Current sample, line, band is: 122 49 1 + Current sample, line, band is: 123 49 1 + Current sample, line, band is: 124 49 1 + Current sample, line, band is: 125 49 1 + Current sample, line, band is: 126 49 1 + Current sample, line, band is: 1 50 1 + Current sample, line, band is: 2 50 1 + Current sample, line, band is: 3 50 1 + Current sample, line, band is: 4 50 1 + Current sample, line, band is: 5 50 1 + Current sample, line, band is: 6 50 1 + Current sample, line, band is: 7 50 1 + Current sample, line, band is: 8 50 1 + Current sample, line, band is: 9 50 1 + Current sample, line, band is: 10 50 1 + Current sample, line, band is: 11 50 1 + Current sample, line, band is: 12 50 1 + Current sample, line, band is: 13 50 1 + Current sample, line, band is: 14 50 1 + Current sample, line, band is: 15 50 1 + Current sample, line, band is: 16 50 1 + Current sample, line, band is: 17 50 1 + Current sample, line, band is: 18 50 1 + Current sample, line, band is: 19 50 1 + Current sample, line, band is: 20 50 1 + Current sample, line, band is: 21 50 1 + Current sample, line, band is: 22 50 1 + Current sample, line, band is: 23 50 1 + Current sample, line, band is: 24 50 1 + Current sample, line, band is: 25 50 1 + Current sample, line, band is: 26 50 1 + Current sample, line, band is: 27 50 1 + Current sample, line, band is: 28 50 1 + Current sample, line, band is: 29 50 1 + Current sample, line, band is: 30 50 1 + Current sample, line, band is: 31 50 1 + Current sample, line, band is: 32 50 1 + Current sample, line, band is: 33 50 1 + Current sample, line, band is: 34 50 1 + Current sample, line, band is: 35 50 1 + Current sample, line, band is: 36 50 1 + Current sample, line, band is: 37 50 1 + Current sample, line, band is: 38 50 1 + Current sample, line, band is: 39 50 1 + Current sample, line, band is: 40 50 1 + Current sample, line, band is: 41 50 1 + Current sample, line, band is: 42 50 1 + Current sample, line, band is: 43 50 1 + Current sample, line, band is: 44 50 1 + Current sample, line, band is: 45 50 1 + Current sample, line, band is: 46 50 1 + Current sample, line, band is: 47 50 1 + Current sample, line, band is: 48 50 1 + Current sample, line, band is: 49 50 1 + Current sample, line, band is: 50 50 1 + Current sample, line, band is: 51 50 1 + Current sample, line, band is: 52 50 1 + Current sample, line, band is: 53 50 1 + Current sample, line, band is: 54 50 1 + Current sample, line, band is: 55 50 1 + Current sample, line, band is: 56 50 1 + Current sample, line, band is: 57 50 1 + Current sample, line, band is: 58 50 1 + Current sample, line, band is: 59 50 1 + Current sample, line, band is: 60 50 1 + Current sample, line, band is: 61 50 1 + Current sample, line, band is: 62 50 1 + Current sample, line, band is: 63 50 1 + Current sample, line, band is: 64 50 1 + Current sample, line, band is: 65 50 1 + Current sample, line, band is: 66 50 1 + Current sample, line, band is: 67 50 1 + Current sample, line, band is: 68 50 1 + Current sample, line, band is: 69 50 1 + Current sample, line, band is: 70 50 1 + Current sample, line, band is: 71 50 1 + Current sample, line, band is: 72 50 1 + Current sample, line, band is: 73 50 1 + Current sample, line, band is: 74 50 1 + Current sample, line, band is: 75 50 1 + Current sample, line, band is: 76 50 1 + Current sample, line, band is: 77 50 1 + Current sample, line, band is: 78 50 1 + Current sample, line, band is: 79 50 1 + Current sample, line, band is: 80 50 1 + Current sample, line, band is: 81 50 1 + Current sample, line, band is: 82 50 1 + Current sample, line, band is: 83 50 1 + Current sample, line, band is: 84 50 1 + Current sample, line, band is: 85 50 1 + Current sample, line, band is: 86 50 1 + Current sample, line, band is: 87 50 1 + Current sample, line, band is: 88 50 1 + Current sample, line, band is: 89 50 1 + Current sample, line, band is: 90 50 1 + Current sample, line, band is: 91 50 1 + Current sample, line, band is: 92 50 1 + Current sample, line, band is: 93 50 1 + Current sample, line, band is: 94 50 1 + Current sample, line, band is: 95 50 1 + Current sample, line, band is: 96 50 1 + Current sample, line, band is: 97 50 1 + Current sample, line, band is: 98 50 1 + Current sample, line, band is: 99 50 1 + Current sample, line, band is: 100 50 1 + Current sample, line, band is: 101 50 1 + Current sample, line, band is: 102 50 1 + Current sample, line, band is: 103 50 1 + Current sample, line, band is: 104 50 1 + Current sample, line, band is: 105 50 1 + Current sample, line, band is: 106 50 1 + Current sample, line, band is: 107 50 1 + Current sample, line, band is: 108 50 1 + Current sample, line, band is: 109 50 1 + Current sample, line, band is: 110 50 1 + Current sample, line, band is: 111 50 1 + Current sample, line, band is: 112 50 1 + Current sample, line, band is: 113 50 1 + Current sample, line, band is: 114 50 1 + Current sample, line, band is: 115 50 1 + Current sample, line, band is: 116 50 1 + Current sample, line, band is: 117 50 1 + Current sample, line, band is: 118 50 1 + Current sample, line, band is: 119 50 1 + Current sample, line, band is: 120 50 1 + Current sample, line, band is: 121 50 1 + Current sample, line, band is: 122 50 1 + Current sample, line, band is: 123 50 1 + Current sample, line, band is: 124 50 1 + Current sample, line, band is: 125 50 1 + Current sample, line, band is: 126 50 1 + Current sample, line, band is: 1 51 1 + Current sample, line, band is: 2 51 1 + Current sample, line, band is: 3 51 1 + Current sample, line, band is: 4 51 1 + Current sample, line, band is: 5 51 1 + Current sample, line, band is: 6 51 1 + Current sample, line, band is: 7 51 1 + Current sample, line, band is: 8 51 1 + Current sample, line, band is: 9 51 1 + Current sample, line, band is: 10 51 1 + Current sample, line, band is: 11 51 1 + Current sample, line, band is: 12 51 1 + Current sample, line, band is: 13 51 1 + Current sample, line, band is: 14 51 1 + Current sample, line, band is: 15 51 1 + Current sample, line, band is: 16 51 1 + Current sample, line, band is: 17 51 1 + Current sample, line, band is: 18 51 1 + Current sample, line, band is: 19 51 1 + Current sample, line, band is: 20 51 1 + Current sample, line, band is: 21 51 1 + Current sample, line, band is: 22 51 1 + Current sample, line, band is: 23 51 1 + Current sample, line, band is: 24 51 1 + Current sample, line, band is: 25 51 1 + Current sample, line, band is: 26 51 1 + Current sample, line, band is: 27 51 1 + Current sample, line, band is: 28 51 1 + Current sample, line, band is: 29 51 1 + Current sample, line, band is: 30 51 1 + Current sample, line, band is: 31 51 1 + Current sample, line, band is: 32 51 1 + Current sample, line, band is: 33 51 1 + Current sample, line, band is: 34 51 1 + Current sample, line, band is: 35 51 1 + Current sample, line, band is: 36 51 1 + Current sample, line, band is: 37 51 1 + Current sample, line, band is: 38 51 1 + Current sample, line, band is: 39 51 1 + Current sample, line, band is: 40 51 1 + Current sample, line, band is: 41 51 1 + Current sample, line, band is: 42 51 1 + Current sample, line, band is: 43 51 1 + Current sample, line, band is: 44 51 1 + Current sample, line, band is: 45 51 1 + Current sample, line, band is: 46 51 1 + Current sample, line, band is: 47 51 1 + Current sample, line, band is: 48 51 1 + Current sample, line, band is: 49 51 1 + Current sample, line, band is: 50 51 1 + Current sample, line, band is: 51 51 1 + Current sample, line, band is: 52 51 1 + Current sample, line, band is: 53 51 1 + Current sample, line, band is: 54 51 1 + Current sample, line, band is: 55 51 1 + Current sample, line, band is: 56 51 1 + Current sample, line, band is: 57 51 1 + Current sample, line, band is: 58 51 1 + Current sample, line, band is: 59 51 1 + Current sample, line, band is: 60 51 1 + Current sample, line, band is: 61 51 1 + Current sample, line, band is: 62 51 1 + Current sample, line, band is: 63 51 1 + Current sample, line, band is: 64 51 1 + Current sample, line, band is: 65 51 1 + Current sample, line, band is: 66 51 1 + Current sample, line, band is: 67 51 1 + Current sample, line, band is: 68 51 1 + Current sample, line, band is: 69 51 1 + Current sample, line, band is: 70 51 1 + Current sample, line, band is: 71 51 1 + Current sample, line, band is: 72 51 1 + Current sample, line, band is: 73 51 1 + Current sample, line, band is: 74 51 1 + Current sample, line, band is: 75 51 1 + Current sample, line, band is: 76 51 1 + Current sample, line, band is: 77 51 1 + Current sample, line, band is: 78 51 1 + Current sample, line, band is: 79 51 1 + Current sample, line, band is: 80 51 1 + Current sample, line, band is: 81 51 1 + Current sample, line, band is: 82 51 1 + Current sample, line, band is: 83 51 1 + Current sample, line, band is: 84 51 1 + Current sample, line, band is: 85 51 1 + Current sample, line, band is: 86 51 1 + Current sample, line, band is: 87 51 1 + Current sample, line, band is: 88 51 1 + Current sample, line, band is: 89 51 1 + Current sample, line, band is: 90 51 1 + Current sample, line, band is: 91 51 1 + Current sample, line, band is: 92 51 1 + Current sample, line, band is: 93 51 1 + Current sample, line, band is: 94 51 1 + Current sample, line, band is: 95 51 1 + Current sample, line, band is: 96 51 1 + Current sample, line, band is: 97 51 1 + Current sample, line, band is: 98 51 1 + Current sample, line, band is: 99 51 1 + Current sample, line, band is: 100 51 1 + Current sample, line, band is: 101 51 1 + Current sample, line, band is: 102 51 1 + Current sample, line, band is: 103 51 1 + Current sample, line, band is: 104 51 1 + Current sample, line, band is: 105 51 1 + Current sample, line, band is: 106 51 1 + Current sample, line, band is: 107 51 1 + Current sample, line, band is: 108 51 1 + Current sample, line, band is: 109 51 1 + Current sample, line, band is: 110 51 1 + Current sample, line, band is: 111 51 1 + Current sample, line, band is: 112 51 1 + Current sample, line, band is: 113 51 1 + Current sample, line, band is: 114 51 1 + Current sample, line, band is: 115 51 1 + Current sample, line, band is: 116 51 1 + Current sample, line, band is: 117 51 1 + Current sample, line, band is: 118 51 1 + Current sample, line, band is: 119 51 1 + Current sample, line, band is: 120 51 1 + Current sample, line, band is: 121 51 1 + Current sample, line, band is: 122 51 1 + Current sample, line, band is: 123 51 1 + Current sample, line, band is: 124 51 1 + Current sample, line, band is: 125 51 1 + Current sample, line, band is: 126 51 1 + Current sample, line, band is: 1 52 1 + Current sample, line, band is: 2 52 1 + Current sample, line, band is: 3 52 1 + Current sample, line, band is: 4 52 1 + Current sample, line, band is: 5 52 1 + Current sample, line, band is: 6 52 1 + Current sample, line, band is: 7 52 1 + Current sample, line, band is: 8 52 1 + Current sample, line, band is: 9 52 1 + Current sample, line, band is: 10 52 1 + Current sample, line, band is: 11 52 1 + Current sample, line, band is: 12 52 1 + Current sample, line, band is: 13 52 1 + Current sample, line, band is: 14 52 1 + Current sample, line, band is: 15 52 1 + Current sample, line, band is: 16 52 1 + Current sample, line, band is: 17 52 1 + Current sample, line, band is: 18 52 1 + Current sample, line, band is: 19 52 1 + Current sample, line, band is: 20 52 1 + Current sample, line, band is: 21 52 1 + Current sample, line, band is: 22 52 1 + Current sample, line, band is: 23 52 1 + Current sample, line, band is: 24 52 1 + Current sample, line, band is: 25 52 1 + Current sample, line, band is: 26 52 1 + Current sample, line, band is: 27 52 1 + Current sample, line, band is: 28 52 1 + Current sample, line, band is: 29 52 1 + Current sample, line, band is: 30 52 1 + Current sample, line, band is: 31 52 1 + Current sample, line, band is: 32 52 1 + Current sample, line, band is: 33 52 1 + Current sample, line, band is: 34 52 1 + Current sample, line, band is: 35 52 1 + Current sample, line, band is: 36 52 1 + Current sample, line, band is: 37 52 1 + Current sample, line, band is: 38 52 1 + Current sample, line, band is: 39 52 1 + Current sample, line, band is: 40 52 1 + Current sample, line, band is: 41 52 1 + Current sample, line, band is: 42 52 1 + Current sample, line, band is: 43 52 1 + Current sample, line, band is: 44 52 1 + Current sample, line, band is: 45 52 1 + Current sample, line, band is: 46 52 1 + Current sample, line, band is: 47 52 1 + Current sample, line, band is: 48 52 1 + Current sample, line, band is: 49 52 1 + Current sample, line, band is: 50 52 1 + Current sample, line, band is: 51 52 1 + Current sample, line, band is: 52 52 1 + Current sample, line, band is: 53 52 1 + Current sample, line, band is: 54 52 1 + Current sample, line, band is: 55 52 1 + Current sample, line, band is: 56 52 1 + Current sample, line, band is: 57 52 1 + Current sample, line, band is: 58 52 1 + Current sample, line, band is: 59 52 1 + Current sample, line, band is: 60 52 1 + Current sample, line, band is: 61 52 1 + Current sample, line, band is: 62 52 1 + Current sample, line, band is: 63 52 1 + Current sample, line, band is: 64 52 1 + Current sample, line, band is: 65 52 1 + Current sample, line, band is: 66 52 1 + Current sample, line, band is: 67 52 1 + Current sample, line, band is: 68 52 1 + Current sample, line, band is: 69 52 1 + Current sample, line, band is: 70 52 1 + Current sample, line, band is: 71 52 1 + Current sample, line, band is: 72 52 1 + Current sample, line, band is: 73 52 1 + Current sample, line, band is: 74 52 1 + Current sample, line, band is: 75 52 1 + Current sample, line, band is: 76 52 1 + Current sample, line, band is: 77 52 1 + Current sample, line, band is: 78 52 1 + Current sample, line, band is: 79 52 1 + Current sample, line, band is: 80 52 1 + Current sample, line, band is: 81 52 1 + Current sample, line, band is: 82 52 1 + Current sample, line, band is: 83 52 1 + Current sample, line, band is: 84 52 1 + Current sample, line, band is: 85 52 1 + Current sample, line, band is: 86 52 1 + Current sample, line, band is: 87 52 1 + Current sample, line, band is: 88 52 1 + Current sample, line, band is: 89 52 1 + Current sample, line, band is: 90 52 1 + Current sample, line, band is: 91 52 1 + Current sample, line, band is: 92 52 1 + Current sample, line, band is: 93 52 1 + Current sample, line, band is: 94 52 1 + Current sample, line, band is: 95 52 1 + Current sample, line, band is: 96 52 1 + Current sample, line, band is: 97 52 1 + Current sample, line, band is: 98 52 1 + Current sample, line, band is: 99 52 1 + Current sample, line, band is: 100 52 1 + Current sample, line, band is: 101 52 1 + Current sample, line, band is: 102 52 1 + Current sample, line, band is: 103 52 1 + Current sample, line, band is: 104 52 1 + Current sample, line, band is: 105 52 1 + Current sample, line, band is: 106 52 1 + Current sample, line, band is: 107 52 1 + Current sample, line, band is: 108 52 1 + Current sample, line, band is: 109 52 1 + Current sample, line, band is: 110 52 1 + Current sample, line, band is: 111 52 1 + Current sample, line, band is: 112 52 1 + Current sample, line, band is: 113 52 1 + Current sample, line, band is: 114 52 1 + Current sample, line, band is: 115 52 1 + Current sample, line, band is: 116 52 1 + Current sample, line, band is: 117 52 1 + Current sample, line, band is: 118 52 1 + Current sample, line, band is: 119 52 1 + Current sample, line, band is: 120 52 1 + Current sample, line, band is: 121 52 1 + Current sample, line, band is: 122 52 1 + Current sample, line, band is: 123 52 1 + Current sample, line, band is: 124 52 1 + Current sample, line, band is: 125 52 1 + Current sample, line, band is: 126 52 1 + Current sample, line, band is: 1 53 1 + Current sample, line, band is: 2 53 1 + Current sample, line, band is: 3 53 1 + Current sample, line, band is: 4 53 1 + Current sample, line, band is: 5 53 1 + Current sample, line, band is: 6 53 1 + Current sample, line, band is: 7 53 1 + Current sample, line, band is: 8 53 1 + Current sample, line, band is: 9 53 1 + Current sample, line, band is: 10 53 1 + Current sample, line, band is: 11 53 1 + Current sample, line, band is: 12 53 1 + Current sample, line, band is: 13 53 1 + Current sample, line, band is: 14 53 1 + Current sample, line, band is: 15 53 1 + Current sample, line, band is: 16 53 1 + Current sample, line, band is: 17 53 1 + Current sample, line, band is: 18 53 1 + Current sample, line, band is: 19 53 1 + Current sample, line, band is: 20 53 1 + Current sample, line, band is: 21 53 1 + Current sample, line, band is: 22 53 1 + Current sample, line, band is: 23 53 1 + Current sample, line, band is: 24 53 1 + Current sample, line, band is: 25 53 1 + Current sample, line, band is: 26 53 1 + Current sample, line, band is: 27 53 1 + Current sample, line, band is: 28 53 1 + Current sample, line, band is: 29 53 1 + Current sample, line, band is: 30 53 1 + Current sample, line, band is: 31 53 1 + Current sample, line, band is: 32 53 1 + Current sample, line, band is: 33 53 1 + Current sample, line, band is: 34 53 1 + Current sample, line, band is: 35 53 1 + Current sample, line, band is: 36 53 1 + Current sample, line, band is: 37 53 1 + Current sample, line, band is: 38 53 1 + Current sample, line, band is: 39 53 1 + Current sample, line, band is: 40 53 1 + Current sample, line, band is: 41 53 1 + Current sample, line, band is: 42 53 1 + Current sample, line, band is: 43 53 1 + Current sample, line, band is: 44 53 1 + Current sample, line, band is: 45 53 1 + Current sample, line, band is: 46 53 1 + Current sample, line, band is: 47 53 1 + Current sample, line, band is: 48 53 1 + Current sample, line, band is: 49 53 1 + Current sample, line, band is: 50 53 1 + Current sample, line, band is: 51 53 1 + Current sample, line, band is: 52 53 1 + Current sample, line, band is: 53 53 1 + Current sample, line, band is: 54 53 1 + Current sample, line, band is: 55 53 1 + Current sample, line, band is: 56 53 1 + Current sample, line, band is: 57 53 1 + Current sample, line, band is: 58 53 1 + Current sample, line, band is: 59 53 1 + Current sample, line, band is: 60 53 1 + Current sample, line, band is: 61 53 1 + Current sample, line, band is: 62 53 1 + Current sample, line, band is: 63 53 1 + Current sample, line, band is: 64 53 1 + Current sample, line, band is: 65 53 1 + Current sample, line, band is: 66 53 1 + Current sample, line, band is: 67 53 1 + Current sample, line, band is: 68 53 1 + Current sample, line, band is: 69 53 1 + Current sample, line, band is: 70 53 1 + Current sample, line, band is: 71 53 1 + Current sample, line, band is: 72 53 1 + Current sample, line, band is: 73 53 1 + Current sample, line, band is: 74 53 1 + Current sample, line, band is: 75 53 1 + Current sample, line, band is: 76 53 1 + Current sample, line, band is: 77 53 1 + Current sample, line, band is: 78 53 1 + Current sample, line, band is: 79 53 1 + Current sample, line, band is: 80 53 1 + Current sample, line, band is: 81 53 1 + Current sample, line, band is: 82 53 1 + Current sample, line, band is: 83 53 1 + Current sample, line, band is: 84 53 1 + Current sample, line, band is: 85 53 1 + Current sample, line, band is: 86 53 1 + Current sample, line, band is: 87 53 1 + Current sample, line, band is: 88 53 1 + Current sample, line, band is: 89 53 1 + Current sample, line, band is: 90 53 1 + Current sample, line, band is: 91 53 1 + Current sample, line, band is: 92 53 1 + Current sample, line, band is: 93 53 1 + Current sample, line, band is: 94 53 1 + Current sample, line, band is: 95 53 1 + Current sample, line, band is: 96 53 1 + Current sample, line, band is: 97 53 1 + Current sample, line, band is: 98 53 1 + Current sample, line, band is: 99 53 1 + Current sample, line, band is: 100 53 1 + Current sample, line, band is: 101 53 1 + Current sample, line, band is: 102 53 1 + Current sample, line, band is: 103 53 1 + Current sample, line, band is: 104 53 1 + Current sample, line, band is: 105 53 1 + Current sample, line, band is: 106 53 1 + Current sample, line, band is: 107 53 1 + Current sample, line, band is: 108 53 1 + Current sample, line, band is: 109 53 1 + Current sample, line, band is: 110 53 1 + Current sample, line, band is: 111 53 1 + Current sample, line, band is: 112 53 1 + Current sample, line, band is: 113 53 1 + Current sample, line, band is: 114 53 1 + Current sample, line, band is: 115 53 1 + Current sample, line, band is: 116 53 1 + Current sample, line, band is: 117 53 1 + Current sample, line, band is: 118 53 1 + Current sample, line, band is: 119 53 1 + Current sample, line, band is: 120 53 1 + Current sample, line, band is: 121 53 1 + Current sample, line, band is: 122 53 1 + Current sample, line, band is: 123 53 1 + Current sample, line, band is: 124 53 1 + Current sample, line, band is: 125 53 1 + Current sample, line, band is: 126 53 1 + Current sample, line, band is: 1 54 1 + Current sample, line, band is: 2 54 1 + Current sample, line, band is: 3 54 1 + Current sample, line, band is: 4 54 1 + Current sample, line, band is: 5 54 1 + Current sample, line, band is: 6 54 1 + Current sample, line, band is: 7 54 1 + Current sample, line, band is: 8 54 1 + Current sample, line, band is: 9 54 1 + Current sample, line, band is: 10 54 1 + Current sample, line, band is: 11 54 1 + Current sample, line, band is: 12 54 1 + Current sample, line, band is: 13 54 1 + Current sample, line, band is: 14 54 1 + Current sample, line, band is: 15 54 1 + Current sample, line, band is: 16 54 1 + Current sample, line, band is: 17 54 1 + Current sample, line, band is: 18 54 1 + Current sample, line, band is: 19 54 1 + Current sample, line, band is: 20 54 1 + Current sample, line, band is: 21 54 1 + Current sample, line, band is: 22 54 1 + Current sample, line, band is: 23 54 1 + Current sample, line, band is: 24 54 1 + Current sample, line, band is: 25 54 1 + Current sample, line, band is: 26 54 1 + Current sample, line, band is: 27 54 1 + Current sample, line, band is: 28 54 1 + Current sample, line, band is: 29 54 1 + Current sample, line, band is: 30 54 1 + Current sample, line, band is: 31 54 1 + Current sample, line, band is: 32 54 1 + Current sample, line, band is: 33 54 1 + Current sample, line, band is: 34 54 1 + Current sample, line, band is: 35 54 1 + Current sample, line, band is: 36 54 1 + Current sample, line, band is: 37 54 1 + Current sample, line, band is: 38 54 1 + Current sample, line, band is: 39 54 1 + Current sample, line, band is: 40 54 1 + Current sample, line, band is: 41 54 1 + Current sample, line, band is: 42 54 1 + Current sample, line, band is: 43 54 1 + Current sample, line, band is: 44 54 1 + Current sample, line, band is: 45 54 1 + Current sample, line, band is: 46 54 1 + Current sample, line, band is: 47 54 1 + Current sample, line, band is: 48 54 1 + Current sample, line, band is: 49 54 1 + Current sample, line, band is: 50 54 1 + Current sample, line, band is: 51 54 1 + Current sample, line, band is: 52 54 1 + Current sample, line, band is: 53 54 1 + Current sample, line, band is: 54 54 1 + Current sample, line, band is: 55 54 1 + Current sample, line, band is: 56 54 1 + Current sample, line, band is: 57 54 1 + Current sample, line, band is: 58 54 1 + Current sample, line, band is: 59 54 1 + Current sample, line, band is: 60 54 1 + Current sample, line, band is: 61 54 1 + Current sample, line, band is: 62 54 1 + Current sample, line, band is: 63 54 1 + Current sample, line, band is: 64 54 1 + Current sample, line, band is: 65 54 1 + Current sample, line, band is: 66 54 1 + Current sample, line, band is: 67 54 1 + Current sample, line, band is: 68 54 1 + Current sample, line, band is: 69 54 1 + Current sample, line, band is: 70 54 1 + Current sample, line, band is: 71 54 1 + Current sample, line, band is: 72 54 1 + Current sample, line, band is: 73 54 1 + Current sample, line, band is: 74 54 1 + Current sample, line, band is: 75 54 1 + Current sample, line, band is: 76 54 1 + Current sample, line, band is: 77 54 1 + Current sample, line, band is: 78 54 1 + Current sample, line, band is: 79 54 1 + Current sample, line, band is: 80 54 1 + Current sample, line, band is: 81 54 1 + Current sample, line, band is: 82 54 1 + Current sample, line, band is: 83 54 1 + Current sample, line, band is: 84 54 1 + Current sample, line, band is: 85 54 1 + Current sample, line, band is: 86 54 1 + Current sample, line, band is: 87 54 1 + Current sample, line, band is: 88 54 1 + Current sample, line, band is: 89 54 1 + Current sample, line, band is: 90 54 1 + Current sample, line, band is: 91 54 1 + Current sample, line, band is: 92 54 1 + Current sample, line, band is: 93 54 1 + Current sample, line, band is: 94 54 1 + Current sample, line, band is: 95 54 1 + Current sample, line, band is: 96 54 1 + Current sample, line, band is: 97 54 1 + Current sample, line, band is: 98 54 1 + Current sample, line, band is: 99 54 1 + Current sample, line, band is: 100 54 1 + Current sample, line, band is: 101 54 1 + Current sample, line, band is: 102 54 1 + Current sample, line, band is: 103 54 1 + Current sample, line, band is: 104 54 1 + Current sample, line, band is: 105 54 1 + Current sample, line, band is: 106 54 1 + Current sample, line, band is: 107 54 1 + Current sample, line, band is: 108 54 1 + Current sample, line, band is: 109 54 1 + Current sample, line, band is: 110 54 1 + Current sample, line, band is: 111 54 1 + Current sample, line, band is: 112 54 1 + Current sample, line, band is: 113 54 1 + Current sample, line, band is: 114 54 1 + Current sample, line, band is: 115 54 1 + Current sample, line, band is: 116 54 1 + Current sample, line, band is: 117 54 1 + Current sample, line, band is: 118 54 1 + Current sample, line, band is: 119 54 1 + Current sample, line, band is: 120 54 1 + Current sample, line, band is: 121 54 1 + Current sample, line, band is: 122 54 1 + Current sample, line, band is: 123 54 1 + Current sample, line, band is: 124 54 1 + Current sample, line, band is: 125 54 1 + Current sample, line, band is: 126 54 1 + Current sample, line, band is: 1 55 1 + Current sample, line, band is: 2 55 1 + Current sample, line, band is: 3 55 1 + Current sample, line, band is: 4 55 1 + Current sample, line, band is: 5 55 1 + Current sample, line, band is: 6 55 1 + Current sample, line, band is: 7 55 1 + Current sample, line, band is: 8 55 1 + Current sample, line, band is: 9 55 1 + Current sample, line, band is: 10 55 1 + Current sample, line, band is: 11 55 1 + Current sample, line, band is: 12 55 1 + Current sample, line, band is: 13 55 1 + Current sample, line, band is: 14 55 1 + Current sample, line, band is: 15 55 1 + Current sample, line, band is: 16 55 1 + Current sample, line, band is: 17 55 1 + Current sample, line, band is: 18 55 1 + Current sample, line, band is: 19 55 1 + Current sample, line, band is: 20 55 1 + Current sample, line, band is: 21 55 1 + Current sample, line, band is: 22 55 1 + Current sample, line, band is: 23 55 1 + Current sample, line, band is: 24 55 1 + Current sample, line, band is: 25 55 1 + Current sample, line, band is: 26 55 1 + Current sample, line, band is: 27 55 1 + Current sample, line, band is: 28 55 1 + Current sample, line, band is: 29 55 1 + Current sample, line, band is: 30 55 1 + Current sample, line, band is: 31 55 1 + Current sample, line, band is: 32 55 1 + Current sample, line, band is: 33 55 1 + Current sample, line, band is: 34 55 1 + Current sample, line, band is: 35 55 1 + Current sample, line, band is: 36 55 1 + Current sample, line, band is: 37 55 1 + Current sample, line, band is: 38 55 1 + Current sample, line, band is: 39 55 1 + Current sample, line, band is: 40 55 1 + Current sample, line, band is: 41 55 1 + Current sample, line, band is: 42 55 1 + Current sample, line, band is: 43 55 1 + Current sample, line, band is: 44 55 1 + Current sample, line, band is: 45 55 1 + Current sample, line, band is: 46 55 1 + Current sample, line, band is: 47 55 1 + Current sample, line, band is: 48 55 1 + Current sample, line, band is: 49 55 1 + Current sample, line, band is: 50 55 1 + Current sample, line, band is: 51 55 1 + Current sample, line, band is: 52 55 1 + Current sample, line, band is: 53 55 1 + Current sample, line, band is: 54 55 1 + Current sample, line, band is: 55 55 1 + Current sample, line, band is: 56 55 1 + Current sample, line, band is: 57 55 1 + Current sample, line, band is: 58 55 1 + Current sample, line, band is: 59 55 1 + Current sample, line, band is: 60 55 1 + Current sample, line, band is: 61 55 1 + Current sample, line, band is: 62 55 1 + Current sample, line, band is: 63 55 1 + Current sample, line, band is: 64 55 1 + Current sample, line, band is: 65 55 1 + Current sample, line, band is: 66 55 1 + Current sample, line, band is: 67 55 1 + Current sample, line, band is: 68 55 1 + Current sample, line, band is: 69 55 1 + Current sample, line, band is: 70 55 1 + Current sample, line, band is: 71 55 1 + Current sample, line, band is: 72 55 1 + Current sample, line, band is: 73 55 1 + Current sample, line, band is: 74 55 1 + Current sample, line, band is: 75 55 1 + Current sample, line, band is: 76 55 1 + Current sample, line, band is: 77 55 1 + Current sample, line, band is: 78 55 1 + Current sample, line, band is: 79 55 1 + Current sample, line, band is: 80 55 1 + Current sample, line, band is: 81 55 1 + Current sample, line, band is: 82 55 1 + Current sample, line, band is: 83 55 1 + Current sample, line, band is: 84 55 1 + Current sample, line, band is: 85 55 1 + Current sample, line, band is: 86 55 1 + Current sample, line, band is: 87 55 1 + Current sample, line, band is: 88 55 1 + Current sample, line, band is: 89 55 1 + Current sample, line, band is: 90 55 1 + Current sample, line, band is: 91 55 1 + Current sample, line, band is: 92 55 1 + Current sample, line, band is: 93 55 1 + Current sample, line, band is: 94 55 1 + Current sample, line, band is: 95 55 1 + Current sample, line, band is: 96 55 1 + Current sample, line, band is: 97 55 1 + Current sample, line, band is: 98 55 1 + Current sample, line, band is: 99 55 1 + Current sample, line, band is: 100 55 1 + Current sample, line, band is: 101 55 1 + Current sample, line, band is: 102 55 1 + Current sample, line, band is: 103 55 1 + Current sample, line, band is: 104 55 1 + Current sample, line, band is: 105 55 1 + Current sample, line, band is: 106 55 1 + Current sample, line, band is: 107 55 1 + Current sample, line, band is: 108 55 1 + Current sample, line, band is: 109 55 1 + Current sample, line, band is: 110 55 1 + Current sample, line, band is: 111 55 1 + Current sample, line, band is: 112 55 1 + Current sample, line, band is: 113 55 1 + Current sample, line, band is: 114 55 1 + Current sample, line, band is: 115 55 1 + Current sample, line, band is: 116 55 1 + Current sample, line, band is: 117 55 1 + Current sample, line, band is: 118 55 1 + Current sample, line, band is: 119 55 1 + Current sample, line, band is: 120 55 1 + Current sample, line, band is: 121 55 1 + Current sample, line, band is: 122 55 1 + Current sample, line, band is: 123 55 1 + Current sample, line, band is: 124 55 1 + Current sample, line, band is: 125 55 1 + Current sample, line, band is: 126 55 1 + Current sample, line, band is: 1 56 1 + Current sample, line, band is: 2 56 1 + Current sample, line, band is: 3 56 1 + Current sample, line, band is: 4 56 1 + Current sample, line, band is: 5 56 1 + Current sample, line, band is: 6 56 1 + Current sample, line, band is: 7 56 1 + Current sample, line, band is: 8 56 1 + Current sample, line, band is: 9 56 1 + Current sample, line, band is: 10 56 1 + Current sample, line, band is: 11 56 1 + Current sample, line, band is: 12 56 1 + Current sample, line, band is: 13 56 1 + Current sample, line, band is: 14 56 1 + Current sample, line, band is: 15 56 1 + Current sample, line, band is: 16 56 1 + Current sample, line, band is: 17 56 1 + Current sample, line, band is: 18 56 1 + Current sample, line, band is: 19 56 1 + Current sample, line, band is: 20 56 1 + Current sample, line, band is: 21 56 1 + Current sample, line, band is: 22 56 1 + Current sample, line, band is: 23 56 1 + Current sample, line, band is: 24 56 1 + Current sample, line, band is: 25 56 1 + Current sample, line, band is: 26 56 1 + Current sample, line, band is: 27 56 1 + Current sample, line, band is: 28 56 1 + Current sample, line, band is: 29 56 1 + Current sample, line, band is: 30 56 1 + Current sample, line, band is: 31 56 1 + Current sample, line, band is: 32 56 1 + Current sample, line, band is: 33 56 1 + Current sample, line, band is: 34 56 1 + Current sample, line, band is: 35 56 1 + Current sample, line, band is: 36 56 1 + Current sample, line, band is: 37 56 1 + Current sample, line, band is: 38 56 1 + Current sample, line, band is: 39 56 1 + Current sample, line, band is: 40 56 1 + Current sample, line, band is: 41 56 1 + Current sample, line, band is: 42 56 1 + Current sample, line, band is: 43 56 1 + Current sample, line, band is: 44 56 1 + Current sample, line, band is: 45 56 1 + Current sample, line, band is: 46 56 1 + Current sample, line, band is: 47 56 1 + Current sample, line, band is: 48 56 1 + Current sample, line, band is: 49 56 1 + Current sample, line, band is: 50 56 1 + Current sample, line, band is: 51 56 1 + Current sample, line, band is: 52 56 1 + Current sample, line, band is: 53 56 1 + Current sample, line, band is: 54 56 1 + Current sample, line, band is: 55 56 1 + Current sample, line, band is: 56 56 1 + Current sample, line, band is: 57 56 1 + Current sample, line, band is: 58 56 1 + Current sample, line, band is: 59 56 1 + Current sample, line, band is: 60 56 1 + Current sample, line, band is: 61 56 1 + Current sample, line, band is: 62 56 1 + Current sample, line, band is: 63 56 1 + Current sample, line, band is: 64 56 1 + Current sample, line, band is: 65 56 1 + Current sample, line, band is: 66 56 1 + Current sample, line, band is: 67 56 1 + Current sample, line, band is: 68 56 1 + Current sample, line, band is: 69 56 1 + Current sample, line, band is: 70 56 1 + Current sample, line, band is: 71 56 1 + Current sample, line, band is: 72 56 1 + Current sample, line, band is: 73 56 1 + Current sample, line, band is: 74 56 1 + Current sample, line, band is: 75 56 1 + Current sample, line, band is: 76 56 1 + Current sample, line, band is: 77 56 1 + Current sample, line, band is: 78 56 1 + Current sample, line, band is: 79 56 1 + Current sample, line, band is: 80 56 1 + Current sample, line, band is: 81 56 1 + Current sample, line, band is: 82 56 1 + Current sample, line, band is: 83 56 1 + Current sample, line, band is: 84 56 1 + Current sample, line, band is: 85 56 1 + Current sample, line, band is: 86 56 1 + Current sample, line, band is: 87 56 1 + Current sample, line, band is: 88 56 1 + Current sample, line, band is: 89 56 1 + Current sample, line, band is: 90 56 1 + Current sample, line, band is: 91 56 1 + Current sample, line, band is: 92 56 1 + Current sample, line, band is: 93 56 1 + Current sample, line, band is: 94 56 1 + Current sample, line, band is: 95 56 1 + Current sample, line, band is: 96 56 1 + Current sample, line, band is: 97 56 1 + Current sample, line, band is: 98 56 1 + Current sample, line, band is: 99 56 1 + Current sample, line, band is: 100 56 1 + Current sample, line, band is: 101 56 1 + Current sample, line, band is: 102 56 1 + Current sample, line, band is: 103 56 1 + Current sample, line, band is: 104 56 1 + Current sample, line, band is: 105 56 1 + Current sample, line, band is: 106 56 1 + Current sample, line, band is: 107 56 1 + Current sample, line, band is: 108 56 1 + Current sample, line, band is: 109 56 1 + Current sample, line, band is: 110 56 1 + Current sample, line, band is: 111 56 1 + Current sample, line, band is: 112 56 1 + Current sample, line, band is: 113 56 1 + Current sample, line, band is: 114 56 1 + Current sample, line, band is: 115 56 1 + Current sample, line, band is: 116 56 1 + Current sample, line, band is: 117 56 1 + Current sample, line, band is: 118 56 1 + Current sample, line, band is: 119 56 1 + Current sample, line, band is: 120 56 1 + Current sample, line, band is: 121 56 1 + Current sample, line, band is: 122 56 1 + Current sample, line, band is: 123 56 1 + Current sample, line, band is: 124 56 1 + Current sample, line, band is: 125 56 1 + Current sample, line, band is: 126 56 1 + Current sample, line, band is: 1 57 1 + Current sample, line, band is: 2 57 1 + Current sample, line, band is: 3 57 1 + Current sample, line, band is: 4 57 1 + Current sample, line, band is: 5 57 1 + Current sample, line, band is: 6 57 1 + Current sample, line, band is: 7 57 1 + Current sample, line, band is: 8 57 1 + Current sample, line, band is: 9 57 1 + Current sample, line, band is: 10 57 1 + Current sample, line, band is: 11 57 1 + Current sample, line, band is: 12 57 1 + Current sample, line, band is: 13 57 1 + Current sample, line, band is: 14 57 1 + Current sample, line, band is: 15 57 1 + Current sample, line, band is: 16 57 1 + Current sample, line, band is: 17 57 1 + Current sample, line, band is: 18 57 1 + Current sample, line, band is: 19 57 1 + Current sample, line, band is: 20 57 1 + Current sample, line, band is: 21 57 1 + Current sample, line, band is: 22 57 1 + Current sample, line, band is: 23 57 1 + Current sample, line, band is: 24 57 1 + Current sample, line, band is: 25 57 1 + Current sample, line, band is: 26 57 1 + Current sample, line, band is: 27 57 1 + Current sample, line, band is: 28 57 1 + Current sample, line, band is: 29 57 1 + Current sample, line, band is: 30 57 1 + Current sample, line, band is: 31 57 1 + Current sample, line, band is: 32 57 1 + Current sample, line, band is: 33 57 1 + Current sample, line, band is: 34 57 1 + Current sample, line, band is: 35 57 1 + Current sample, line, band is: 36 57 1 + Current sample, line, band is: 37 57 1 + Current sample, line, band is: 38 57 1 + Current sample, line, band is: 39 57 1 + Current sample, line, band is: 40 57 1 + Current sample, line, band is: 41 57 1 + Current sample, line, band is: 42 57 1 + Current sample, line, band is: 43 57 1 + Current sample, line, band is: 44 57 1 + Current sample, line, band is: 45 57 1 + Current sample, line, band is: 46 57 1 + Current sample, line, band is: 47 57 1 + Current sample, line, band is: 48 57 1 + Current sample, line, band is: 49 57 1 + Current sample, line, band is: 50 57 1 + Current sample, line, band is: 51 57 1 + Current sample, line, band is: 52 57 1 + Current sample, line, band is: 53 57 1 + Current sample, line, band is: 54 57 1 + Current sample, line, band is: 55 57 1 + Current sample, line, band is: 56 57 1 + Current sample, line, band is: 57 57 1 + Current sample, line, band is: 58 57 1 + Current sample, line, band is: 59 57 1 + Current sample, line, band is: 60 57 1 + Current sample, line, band is: 61 57 1 + Current sample, line, band is: 62 57 1 + Current sample, line, band is: 63 57 1 + Current sample, line, band is: 64 57 1 + Current sample, line, band is: 65 57 1 + Current sample, line, band is: 66 57 1 + Current sample, line, band is: 67 57 1 + Current sample, line, band is: 68 57 1 + Current sample, line, band is: 69 57 1 + Current sample, line, band is: 70 57 1 + Current sample, line, band is: 71 57 1 + Current sample, line, band is: 72 57 1 + Current sample, line, band is: 73 57 1 + Current sample, line, band is: 74 57 1 + Current sample, line, band is: 75 57 1 + Current sample, line, band is: 76 57 1 + Current sample, line, band is: 77 57 1 + Current sample, line, band is: 78 57 1 + Current sample, line, band is: 79 57 1 + Current sample, line, band is: 80 57 1 + Current sample, line, band is: 81 57 1 + Current sample, line, band is: 82 57 1 + Current sample, line, band is: 83 57 1 + Current sample, line, band is: 84 57 1 + Current sample, line, band is: 85 57 1 + Current sample, line, band is: 86 57 1 + Current sample, line, band is: 87 57 1 + Current sample, line, band is: 88 57 1 + Current sample, line, band is: 89 57 1 + Current sample, line, band is: 90 57 1 + Current sample, line, band is: 91 57 1 + Current sample, line, band is: 92 57 1 + Current sample, line, band is: 93 57 1 + Current sample, line, band is: 94 57 1 + Current sample, line, band is: 95 57 1 + Current sample, line, band is: 96 57 1 + Current sample, line, band is: 97 57 1 + Current sample, line, band is: 98 57 1 + Current sample, line, band is: 99 57 1 + Current sample, line, band is: 100 57 1 + Current sample, line, band is: 101 57 1 + Current sample, line, band is: 102 57 1 + Current sample, line, band is: 103 57 1 + Current sample, line, band is: 104 57 1 + Current sample, line, band is: 105 57 1 + Current sample, line, band is: 106 57 1 + Current sample, line, band is: 107 57 1 + Current sample, line, band is: 108 57 1 + Current sample, line, band is: 109 57 1 + Current sample, line, band is: 110 57 1 + Current sample, line, band is: 111 57 1 + Current sample, line, band is: 112 57 1 + Current sample, line, band is: 113 57 1 + Current sample, line, band is: 114 57 1 + Current sample, line, band is: 115 57 1 + Current sample, line, band is: 116 57 1 + Current sample, line, band is: 117 57 1 + Current sample, line, band is: 118 57 1 + Current sample, line, band is: 119 57 1 + Current sample, line, band is: 120 57 1 + Current sample, line, band is: 121 57 1 + Current sample, line, band is: 122 57 1 + Current sample, line, band is: 123 57 1 + Current sample, line, band is: 124 57 1 + Current sample, line, band is: 125 57 1 + Current sample, line, band is: 126 57 1 + Current sample, line, band is: 1 58 1 + Current sample, line, band is: 2 58 1 + Current sample, line, band is: 3 58 1 + Current sample, line, band is: 4 58 1 + Current sample, line, band is: 5 58 1 + Current sample, line, band is: 6 58 1 + Current sample, line, band is: 7 58 1 + Current sample, line, band is: 8 58 1 + Current sample, line, band is: 9 58 1 + Current sample, line, band is: 10 58 1 + Current sample, line, band is: 11 58 1 + Current sample, line, band is: 12 58 1 + Current sample, line, band is: 13 58 1 + Current sample, line, band is: 14 58 1 + Current sample, line, band is: 15 58 1 + Current sample, line, band is: 16 58 1 + Current sample, line, band is: 17 58 1 + Current sample, line, band is: 18 58 1 + Current sample, line, band is: 19 58 1 + Current sample, line, band is: 20 58 1 + Current sample, line, band is: 21 58 1 + Current sample, line, band is: 22 58 1 + Current sample, line, band is: 23 58 1 + Current sample, line, band is: 24 58 1 + Current sample, line, band is: 25 58 1 + Current sample, line, band is: 26 58 1 + Current sample, line, band is: 27 58 1 + Current sample, line, band is: 28 58 1 + Current sample, line, band is: 29 58 1 + Current sample, line, band is: 30 58 1 + Current sample, line, band is: 31 58 1 + Current sample, line, band is: 32 58 1 + Current sample, line, band is: 33 58 1 + Current sample, line, band is: 34 58 1 + Current sample, line, band is: 35 58 1 + Current sample, line, band is: 36 58 1 + Current sample, line, band is: 37 58 1 + Current sample, line, band is: 38 58 1 + Current sample, line, band is: 39 58 1 + Current sample, line, band is: 40 58 1 + Current sample, line, band is: 41 58 1 + Current sample, line, band is: 42 58 1 + Current sample, line, band is: 43 58 1 + Current sample, line, band is: 44 58 1 + Current sample, line, band is: 45 58 1 + Current sample, line, band is: 46 58 1 + Current sample, line, band is: 47 58 1 + Current sample, line, band is: 48 58 1 + Current sample, line, band is: 49 58 1 + Current sample, line, band is: 50 58 1 + Current sample, line, band is: 51 58 1 + Current sample, line, band is: 52 58 1 + Current sample, line, band is: 53 58 1 + Current sample, line, band is: 54 58 1 + Current sample, line, band is: 55 58 1 + Current sample, line, band is: 56 58 1 + Current sample, line, band is: 57 58 1 + Current sample, line, band is: 58 58 1 + Current sample, line, band is: 59 58 1 + Current sample, line, band is: 60 58 1 + Current sample, line, band is: 61 58 1 + Current sample, line, band is: 62 58 1 + Current sample, line, band is: 63 58 1 + Current sample, line, band is: 64 58 1 + Current sample, line, band is: 65 58 1 + Current sample, line, band is: 66 58 1 + Current sample, line, band is: 67 58 1 + Current sample, line, band is: 68 58 1 + Current sample, line, band is: 69 58 1 + Current sample, line, band is: 70 58 1 + Current sample, line, band is: 71 58 1 + Current sample, line, band is: 72 58 1 + Current sample, line, band is: 73 58 1 + Current sample, line, band is: 74 58 1 + Current sample, line, band is: 75 58 1 + Current sample, line, band is: 76 58 1 + Current sample, line, band is: 77 58 1 + Current sample, line, band is: 78 58 1 + Current sample, line, band is: 79 58 1 + Current sample, line, band is: 80 58 1 + Current sample, line, band is: 81 58 1 + Current sample, line, band is: 82 58 1 + Current sample, line, band is: 83 58 1 + Current sample, line, band is: 84 58 1 + Current sample, line, band is: 85 58 1 + Current sample, line, band is: 86 58 1 + Current sample, line, band is: 87 58 1 + Current sample, line, band is: 88 58 1 + Current sample, line, band is: 89 58 1 + Current sample, line, band is: 90 58 1 + Current sample, line, band is: 91 58 1 + Current sample, line, band is: 92 58 1 + Current sample, line, band is: 93 58 1 + Current sample, line, band is: 94 58 1 + Current sample, line, band is: 95 58 1 + Current sample, line, band is: 96 58 1 + Current sample, line, band is: 97 58 1 + Current sample, line, band is: 98 58 1 + Current sample, line, band is: 99 58 1 + Current sample, line, band is: 100 58 1 + Current sample, line, band is: 101 58 1 + Current sample, line, band is: 102 58 1 + Current sample, line, band is: 103 58 1 + Current sample, line, band is: 104 58 1 + Current sample, line, band is: 105 58 1 + Current sample, line, band is: 106 58 1 + Current sample, line, band is: 107 58 1 + Current sample, line, band is: 108 58 1 + Current sample, line, band is: 109 58 1 + Current sample, line, band is: 110 58 1 + Current sample, line, band is: 111 58 1 + Current sample, line, band is: 112 58 1 + Current sample, line, band is: 113 58 1 + Current sample, line, band is: 114 58 1 + Current sample, line, band is: 115 58 1 + Current sample, line, band is: 116 58 1 + Current sample, line, band is: 117 58 1 + Current sample, line, band is: 118 58 1 + Current sample, line, band is: 119 58 1 + Current sample, line, band is: 120 58 1 + Current sample, line, band is: 121 58 1 + Current sample, line, band is: 122 58 1 + Current sample, line, band is: 123 58 1 + Current sample, line, band is: 124 58 1 + Current sample, line, band is: 125 58 1 + Current sample, line, band is: 126 58 1 + Current sample, line, band is: 1 59 1 + Current sample, line, band is: 2 59 1 + Current sample, line, band is: 3 59 1 + Current sample, line, band is: 4 59 1 + Current sample, line, band is: 5 59 1 + Current sample, line, band is: 6 59 1 + Current sample, line, band is: 7 59 1 + Current sample, line, band is: 8 59 1 + Current sample, line, band is: 9 59 1 + Current sample, line, band is: 10 59 1 + Current sample, line, band is: 11 59 1 + Current sample, line, band is: 12 59 1 + Current sample, line, band is: 13 59 1 + Current sample, line, band is: 14 59 1 + Current sample, line, band is: 15 59 1 + Current sample, line, band is: 16 59 1 + Current sample, line, band is: 17 59 1 + Current sample, line, band is: 18 59 1 + Current sample, line, band is: 19 59 1 + Current sample, line, band is: 20 59 1 + Current sample, line, band is: 21 59 1 + Current sample, line, band is: 22 59 1 + Current sample, line, band is: 23 59 1 + Current sample, line, band is: 24 59 1 + Current sample, line, band is: 25 59 1 + Current sample, line, band is: 26 59 1 + Current sample, line, band is: 27 59 1 + Current sample, line, band is: 28 59 1 + Current sample, line, band is: 29 59 1 + Current sample, line, band is: 30 59 1 + Current sample, line, band is: 31 59 1 + Current sample, line, band is: 32 59 1 + Current sample, line, band is: 33 59 1 + Current sample, line, band is: 34 59 1 + Current sample, line, band is: 35 59 1 + Current sample, line, band is: 36 59 1 + Current sample, line, band is: 37 59 1 + Current sample, line, band is: 38 59 1 + Current sample, line, band is: 39 59 1 + Current sample, line, band is: 40 59 1 + Current sample, line, band is: 41 59 1 + Current sample, line, band is: 42 59 1 + Current sample, line, band is: 43 59 1 + Current sample, line, band is: 44 59 1 + Current sample, line, band is: 45 59 1 + Current sample, line, band is: 46 59 1 + Current sample, line, band is: 47 59 1 + Current sample, line, band is: 48 59 1 + Current sample, line, band is: 49 59 1 + Current sample, line, band is: 50 59 1 + Current sample, line, band is: 51 59 1 + Current sample, line, band is: 52 59 1 + Current sample, line, band is: 53 59 1 + Current sample, line, band is: 54 59 1 + Current sample, line, band is: 55 59 1 + Current sample, line, band is: 56 59 1 + Current sample, line, band is: 57 59 1 + Current sample, line, band is: 58 59 1 + Current sample, line, band is: 59 59 1 + Current sample, line, band is: 60 59 1 + Current sample, line, band is: 61 59 1 + Current sample, line, band is: 62 59 1 + Current sample, line, band is: 63 59 1 + Current sample, line, band is: 64 59 1 + Current sample, line, band is: 65 59 1 + Current sample, line, band is: 66 59 1 + Current sample, line, band is: 67 59 1 + Current sample, line, band is: 68 59 1 + Current sample, line, band is: 69 59 1 + Current sample, line, band is: 70 59 1 + Current sample, line, band is: 71 59 1 + Current sample, line, band is: 72 59 1 + Current sample, line, band is: 73 59 1 + Current sample, line, band is: 74 59 1 + Current sample, line, band is: 75 59 1 + Current sample, line, band is: 76 59 1 + Current sample, line, band is: 77 59 1 + Current sample, line, band is: 78 59 1 + Current sample, line, band is: 79 59 1 + Current sample, line, band is: 80 59 1 + Current sample, line, band is: 81 59 1 + Current sample, line, band is: 82 59 1 + Current sample, line, band is: 83 59 1 + Current sample, line, band is: 84 59 1 + Current sample, line, band is: 85 59 1 + Current sample, line, band is: 86 59 1 + Current sample, line, band is: 87 59 1 + Current sample, line, band is: 88 59 1 + Current sample, line, band is: 89 59 1 + Current sample, line, band is: 90 59 1 + Current sample, line, band is: 91 59 1 + Current sample, line, band is: 92 59 1 + Current sample, line, band is: 93 59 1 + Current sample, line, band is: 94 59 1 + Current sample, line, band is: 95 59 1 + Current sample, line, band is: 96 59 1 + Current sample, line, band is: 97 59 1 + Current sample, line, band is: 98 59 1 + Current sample, line, band is: 99 59 1 + Current sample, line, band is: 100 59 1 + Current sample, line, band is: 101 59 1 + Current sample, line, band is: 102 59 1 + Current sample, line, band is: 103 59 1 + Current sample, line, band is: 104 59 1 + Current sample, line, band is: 105 59 1 + Current sample, line, band is: 106 59 1 + Current sample, line, band is: 107 59 1 + Current sample, line, band is: 108 59 1 + Current sample, line, band is: 109 59 1 + Current sample, line, band is: 110 59 1 + Current sample, line, band is: 111 59 1 + Current sample, line, band is: 112 59 1 + Current sample, line, band is: 113 59 1 + Current sample, line, band is: 114 59 1 + Current sample, line, band is: 115 59 1 + Current sample, line, band is: 116 59 1 + Current sample, line, band is: 117 59 1 + Current sample, line, band is: 118 59 1 + Current sample, line, band is: 119 59 1 + Current sample, line, band is: 120 59 1 + Current sample, line, band is: 121 59 1 + Current sample, line, band is: 122 59 1 + Current sample, line, band is: 123 59 1 + Current sample, line, band is: 124 59 1 + Current sample, line, band is: 125 59 1 + Current sample, line, band is: 126 59 1 + Current sample, line, band is: 1 60 1 + Current sample, line, band is: 2 60 1 + Current sample, line, band is: 3 60 1 + Current sample, line, band is: 4 60 1 + Current sample, line, band is: 5 60 1 + Current sample, line, band is: 6 60 1 + Current sample, line, band is: 7 60 1 + Current sample, line, band is: 8 60 1 + Current sample, line, band is: 9 60 1 + Current sample, line, band is: 10 60 1 + Current sample, line, band is: 11 60 1 + Current sample, line, band is: 12 60 1 + Current sample, line, band is: 13 60 1 + Current sample, line, band is: 14 60 1 + Current sample, line, band is: 15 60 1 + Current sample, line, band is: 16 60 1 + Current sample, line, band is: 17 60 1 + Current sample, line, band is: 18 60 1 + Current sample, line, band is: 19 60 1 + Current sample, line, band is: 20 60 1 + Current sample, line, band is: 21 60 1 + Current sample, line, band is: 22 60 1 + Current sample, line, band is: 23 60 1 + Current sample, line, band is: 24 60 1 + Current sample, line, band is: 25 60 1 + Current sample, line, band is: 26 60 1 + Current sample, line, band is: 27 60 1 + Current sample, line, band is: 28 60 1 + Current sample, line, band is: 29 60 1 + Current sample, line, band is: 30 60 1 + Current sample, line, band is: 31 60 1 + Current sample, line, band is: 32 60 1 + Current sample, line, band is: 33 60 1 + Current sample, line, band is: 34 60 1 + Current sample, line, band is: 35 60 1 + Current sample, line, band is: 36 60 1 + Current sample, line, band is: 37 60 1 + Current sample, line, band is: 38 60 1 + Current sample, line, band is: 39 60 1 + Current sample, line, band is: 40 60 1 + Current sample, line, band is: 41 60 1 + Current sample, line, band is: 42 60 1 + Current sample, line, band is: 43 60 1 + Current sample, line, band is: 44 60 1 + Current sample, line, band is: 45 60 1 + Current sample, line, band is: 46 60 1 + Current sample, line, band is: 47 60 1 + Current sample, line, band is: 48 60 1 + Current sample, line, band is: 49 60 1 + Current sample, line, band is: 50 60 1 + Current sample, line, band is: 51 60 1 + Current sample, line, band is: 52 60 1 + Current sample, line, band is: 53 60 1 + Current sample, line, band is: 54 60 1 + Current sample, line, band is: 55 60 1 + Current sample, line, band is: 56 60 1 + Current sample, line, band is: 57 60 1 + Current sample, line, band is: 58 60 1 + Current sample, line, band is: 59 60 1 + Current sample, line, band is: 60 60 1 + Current sample, line, band is: 61 60 1 + Current sample, line, band is: 62 60 1 + Current sample, line, band is: 63 60 1 + Current sample, line, band is: 64 60 1 + Current sample, line, band is: 65 60 1 + Current sample, line, band is: 66 60 1 + Current sample, line, band is: 67 60 1 + Current sample, line, band is: 68 60 1 + Current sample, line, band is: 69 60 1 + Current sample, line, band is: 70 60 1 + Current sample, line, band is: 71 60 1 + Current sample, line, band is: 72 60 1 + Current sample, line, band is: 73 60 1 + Current sample, line, band is: 74 60 1 + Current sample, line, band is: 75 60 1 + Current sample, line, band is: 76 60 1 + Current sample, line, band is: 77 60 1 + Current sample, line, band is: 78 60 1 + Current sample, line, band is: 79 60 1 + Current sample, line, band is: 80 60 1 + Current sample, line, band is: 81 60 1 + Current sample, line, band is: 82 60 1 + Current sample, line, band is: 83 60 1 + Current sample, line, band is: 84 60 1 + Current sample, line, band is: 85 60 1 + Current sample, line, band is: 86 60 1 + Current sample, line, band is: 87 60 1 + Current sample, line, band is: 88 60 1 + Current sample, line, band is: 89 60 1 + Current sample, line, band is: 90 60 1 + Current sample, line, band is: 91 60 1 + Current sample, line, band is: 92 60 1 + Current sample, line, band is: 93 60 1 + Current sample, line, band is: 94 60 1 + Current sample, line, band is: 95 60 1 + Current sample, line, band is: 96 60 1 + Current sample, line, band is: 97 60 1 + Current sample, line, band is: 98 60 1 + Current sample, line, band is: 99 60 1 + Current sample, line, band is: 100 60 1 + Current sample, line, band is: 101 60 1 + Current sample, line, band is: 102 60 1 + Current sample, line, band is: 103 60 1 + Current sample, line, band is: 104 60 1 + Current sample, line, band is: 105 60 1 + Current sample, line, band is: 106 60 1 + Current sample, line, band is: 107 60 1 + Current sample, line, band is: 108 60 1 + Current sample, line, band is: 109 60 1 + Current sample, line, band is: 110 60 1 + Current sample, line, band is: 111 60 1 + Current sample, line, band is: 112 60 1 + Current sample, line, band is: 113 60 1 + Current sample, line, band is: 114 60 1 + Current sample, line, band is: 115 60 1 + Current sample, line, band is: 116 60 1 + Current sample, line, band is: 117 60 1 + Current sample, line, band is: 118 60 1 + Current sample, line, band is: 119 60 1 + Current sample, line, band is: 120 60 1 + Current sample, line, band is: 121 60 1 + Current sample, line, band is: 122 60 1 + Current sample, line, band is: 123 60 1 + Current sample, line, band is: 124 60 1 + Current sample, line, band is: 125 60 1 + Current sample, line, band is: 126 60 1 + Current sample, line, band is: 1 61 1 + Current sample, line, band is: 2 61 1 + Current sample, line, band is: 3 61 1 + Current sample, line, band is: 4 61 1 + Current sample, line, band is: 5 61 1 + Current sample, line, band is: 6 61 1 + Current sample, line, band is: 7 61 1 + Current sample, line, band is: 8 61 1 + Current sample, line, band is: 9 61 1 + Current sample, line, band is: 10 61 1 + Current sample, line, band is: 11 61 1 + Current sample, line, band is: 12 61 1 + Current sample, line, band is: 13 61 1 + Current sample, line, band is: 14 61 1 + Current sample, line, band is: 15 61 1 + Current sample, line, band is: 16 61 1 + Current sample, line, band is: 17 61 1 + Current sample, line, band is: 18 61 1 + Current sample, line, band is: 19 61 1 + Current sample, line, band is: 20 61 1 + Current sample, line, band is: 21 61 1 + Current sample, line, band is: 22 61 1 + Current sample, line, band is: 23 61 1 + Current sample, line, band is: 24 61 1 + Current sample, line, band is: 25 61 1 + Current sample, line, band is: 26 61 1 + Current sample, line, band is: 27 61 1 + Current sample, line, band is: 28 61 1 + Current sample, line, band is: 29 61 1 + Current sample, line, band is: 30 61 1 + Current sample, line, band is: 31 61 1 + Current sample, line, band is: 32 61 1 + Current sample, line, band is: 33 61 1 + Current sample, line, band is: 34 61 1 + Current sample, line, band is: 35 61 1 + Current sample, line, band is: 36 61 1 + Current sample, line, band is: 37 61 1 + Current sample, line, band is: 38 61 1 + Current sample, line, band is: 39 61 1 + Current sample, line, band is: 40 61 1 + Current sample, line, band is: 41 61 1 + Current sample, line, band is: 42 61 1 + Current sample, line, band is: 43 61 1 + Current sample, line, band is: 44 61 1 + Current sample, line, band is: 45 61 1 + Current sample, line, band is: 46 61 1 + Current sample, line, band is: 47 61 1 + Current sample, line, band is: 48 61 1 + Current sample, line, band is: 49 61 1 + Current sample, line, band is: 50 61 1 + Current sample, line, band is: 51 61 1 + Current sample, line, band is: 52 61 1 + Current sample, line, band is: 53 61 1 + Current sample, line, band is: 54 61 1 + Current sample, line, band is: 55 61 1 + Current sample, line, band is: 56 61 1 + Current sample, line, band is: 57 61 1 + Current sample, line, band is: 58 61 1 + Current sample, line, band is: 59 61 1 + Current sample, line, band is: 60 61 1 + Current sample, line, band is: 61 61 1 + Current sample, line, band is: 62 61 1 + Current sample, line, band is: 63 61 1 + Current sample, line, band is: 64 61 1 + Current sample, line, band is: 65 61 1 + Current sample, line, band is: 66 61 1 + Current sample, line, band is: 67 61 1 + Current sample, line, band is: 68 61 1 + Current sample, line, band is: 69 61 1 + Current sample, line, band is: 70 61 1 + Current sample, line, band is: 71 61 1 + Current sample, line, band is: 72 61 1 + Current sample, line, band is: 73 61 1 + Current sample, line, band is: 74 61 1 + Current sample, line, band is: 75 61 1 + Current sample, line, band is: 76 61 1 + Current sample, line, band is: 77 61 1 + Current sample, line, band is: 78 61 1 + Current sample, line, band is: 79 61 1 + Current sample, line, band is: 80 61 1 + Current sample, line, band is: 81 61 1 + Current sample, line, band is: 82 61 1 + Current sample, line, band is: 83 61 1 + Current sample, line, band is: 84 61 1 + Current sample, line, band is: 85 61 1 + Current sample, line, band is: 86 61 1 + Current sample, line, band is: 87 61 1 + Current sample, line, band is: 88 61 1 + Current sample, line, band is: 89 61 1 + Current sample, line, band is: 90 61 1 + Current sample, line, band is: 91 61 1 + Current sample, line, band is: 92 61 1 + Current sample, line, band is: 93 61 1 + Current sample, line, band is: 94 61 1 + Current sample, line, band is: 95 61 1 + Current sample, line, band is: 96 61 1 + Current sample, line, band is: 97 61 1 + Current sample, line, band is: 98 61 1 + Current sample, line, band is: 99 61 1 + Current sample, line, band is: 100 61 1 + Current sample, line, band is: 101 61 1 + Current sample, line, band is: 102 61 1 + Current sample, line, band is: 103 61 1 + Current sample, line, band is: 104 61 1 + Current sample, line, band is: 105 61 1 + Current sample, line, band is: 106 61 1 + Current sample, line, band is: 107 61 1 + Current sample, line, band is: 108 61 1 + Current sample, line, band is: 109 61 1 + Current sample, line, band is: 110 61 1 + Current sample, line, band is: 111 61 1 + Current sample, line, band is: 112 61 1 + Current sample, line, band is: 113 61 1 + Current sample, line, band is: 114 61 1 + Current sample, line, band is: 115 61 1 + Current sample, line, band is: 116 61 1 + Current sample, line, band is: 117 61 1 + Current sample, line, band is: 118 61 1 + Current sample, line, band is: 119 61 1 + Current sample, line, band is: 120 61 1 + Current sample, line, band is: 121 61 1 + Current sample, line, band is: 122 61 1 + Current sample, line, band is: 123 61 1 + Current sample, line, band is: 124 61 1 + Current sample, line, band is: 125 61 1 + Current sample, line, band is: 126 61 1 + Current sample, line, band is: 1 62 1 + Current sample, line, band is: 2 62 1 + Current sample, line, band is: 3 62 1 + Current sample, line, band is: 4 62 1 + Current sample, line, band is: 5 62 1 + Current sample, line, band is: 6 62 1 + Current sample, line, band is: 7 62 1 + Current sample, line, band is: 8 62 1 + Current sample, line, band is: 9 62 1 + Current sample, line, band is: 10 62 1 + Current sample, line, band is: 11 62 1 + Current sample, line, band is: 12 62 1 + Current sample, line, band is: 13 62 1 + Current sample, line, band is: 14 62 1 + Current sample, line, band is: 15 62 1 + Current sample, line, band is: 16 62 1 + Current sample, line, band is: 17 62 1 + Current sample, line, band is: 18 62 1 + Current sample, line, band is: 19 62 1 + Current sample, line, band is: 20 62 1 + Current sample, line, band is: 21 62 1 + Current sample, line, band is: 22 62 1 + Current sample, line, band is: 23 62 1 + Current sample, line, band is: 24 62 1 + Current sample, line, band is: 25 62 1 + Current sample, line, band is: 26 62 1 + Current sample, line, band is: 27 62 1 + Current sample, line, band is: 28 62 1 + Current sample, line, band is: 29 62 1 + Current sample, line, band is: 30 62 1 + Current sample, line, band is: 31 62 1 + Current sample, line, band is: 32 62 1 + Current sample, line, band is: 33 62 1 + Current sample, line, band is: 34 62 1 + Current sample, line, band is: 35 62 1 + Current sample, line, band is: 36 62 1 + Current sample, line, band is: 37 62 1 + Current sample, line, band is: 38 62 1 + Current sample, line, band is: 39 62 1 + Current sample, line, band is: 40 62 1 + Current sample, line, band is: 41 62 1 + Current sample, line, band is: 42 62 1 + Current sample, line, band is: 43 62 1 + Current sample, line, band is: 44 62 1 + Current sample, line, band is: 45 62 1 + Current sample, line, band is: 46 62 1 + Current sample, line, band is: 47 62 1 + Current sample, line, band is: 48 62 1 + Current sample, line, band is: 49 62 1 + Current sample, line, band is: 50 62 1 + Current sample, line, band is: 51 62 1 + Current sample, line, band is: 52 62 1 + Current sample, line, band is: 53 62 1 + Current sample, line, band is: 54 62 1 + Current sample, line, band is: 55 62 1 + Current sample, line, band is: 56 62 1 + Current sample, line, band is: 57 62 1 + Current sample, line, band is: 58 62 1 + Current sample, line, band is: 59 62 1 + Current sample, line, band is: 60 62 1 + Current sample, line, band is: 61 62 1 + Current sample, line, band is: 62 62 1 + Current sample, line, band is: 63 62 1 + Current sample, line, band is: 64 62 1 + Current sample, line, band is: 65 62 1 + Current sample, line, band is: 66 62 1 + Current sample, line, band is: 67 62 1 + Current sample, line, band is: 68 62 1 + Current sample, line, band is: 69 62 1 + Current sample, line, band is: 70 62 1 + Current sample, line, band is: 71 62 1 + Current sample, line, band is: 72 62 1 + Current sample, line, band is: 73 62 1 + Current sample, line, band is: 74 62 1 + Current sample, line, band is: 75 62 1 + Current sample, line, band is: 76 62 1 + Current sample, line, band is: 77 62 1 + Current sample, line, band is: 78 62 1 + Current sample, line, band is: 79 62 1 + Current sample, line, band is: 80 62 1 + Current sample, line, band is: 81 62 1 + Current sample, line, band is: 82 62 1 + Current sample, line, band is: 83 62 1 + Current sample, line, band is: 84 62 1 + Current sample, line, band is: 85 62 1 + Current sample, line, band is: 86 62 1 + Current sample, line, band is: 87 62 1 + Current sample, line, band is: 88 62 1 + Current sample, line, band is: 89 62 1 + Current sample, line, band is: 90 62 1 + Current sample, line, band is: 91 62 1 + Current sample, line, band is: 92 62 1 + Current sample, line, band is: 93 62 1 + Current sample, line, band is: 94 62 1 + Current sample, line, band is: 95 62 1 + Current sample, line, band is: 96 62 1 + Current sample, line, band is: 97 62 1 + Current sample, line, band is: 98 62 1 + Current sample, line, band is: 99 62 1 + Current sample, line, band is: 100 62 1 + Current sample, line, band is: 101 62 1 + Current sample, line, band is: 102 62 1 + Current sample, line, band is: 103 62 1 + Current sample, line, band is: 104 62 1 + Current sample, line, band is: 105 62 1 + Current sample, line, band is: 106 62 1 + Current sample, line, band is: 107 62 1 + Current sample, line, band is: 108 62 1 + Current sample, line, band is: 109 62 1 + Current sample, line, band is: 110 62 1 + Current sample, line, band is: 111 62 1 + Current sample, line, band is: 112 62 1 + Current sample, line, band is: 113 62 1 + Current sample, line, band is: 114 62 1 + Current sample, line, band is: 115 62 1 + Current sample, line, band is: 116 62 1 + Current sample, line, band is: 117 62 1 + Current sample, line, band is: 118 62 1 + Current sample, line, band is: 119 62 1 + Current sample, line, band is: 120 62 1 + Current sample, line, band is: 121 62 1 + Current sample, line, band is: 122 62 1 + Current sample, line, band is: 123 62 1 + Current sample, line, band is: 124 62 1 + Current sample, line, band is: 125 62 1 + Current sample, line, band is: 126 62 1 + Current sample, line, band is: 1 63 1 + Current sample, line, band is: 2 63 1 + Current sample, line, band is: 3 63 1 + Current sample, line, band is: 4 63 1 + Current sample, line, band is: 5 63 1 + Current sample, line, band is: 6 63 1 + Current sample, line, band is: 7 63 1 + Current sample, line, band is: 8 63 1 + Current sample, line, band is: 9 63 1 + Current sample, line, band is: 10 63 1 + Current sample, line, band is: 11 63 1 + Current sample, line, band is: 12 63 1 + Current sample, line, band is: 13 63 1 + Current sample, line, band is: 14 63 1 + Current sample, line, band is: 15 63 1 + Current sample, line, band is: 16 63 1 + Current sample, line, band is: 17 63 1 + Current sample, line, band is: 18 63 1 + Current sample, line, band is: 19 63 1 + Current sample, line, band is: 20 63 1 + Current sample, line, band is: 21 63 1 + Current sample, line, band is: 22 63 1 + Current sample, line, band is: 23 63 1 + Current sample, line, band is: 24 63 1 + Current sample, line, band is: 25 63 1 + Current sample, line, band is: 26 63 1 + Current sample, line, band is: 27 63 1 + Current sample, line, band is: 28 63 1 + Current sample, line, band is: 29 63 1 + Current sample, line, band is: 30 63 1 + Current sample, line, band is: 31 63 1 + Current sample, line, band is: 32 63 1 + Current sample, line, band is: 33 63 1 + Current sample, line, band is: 34 63 1 + Current sample, line, band is: 35 63 1 + Current sample, line, band is: 36 63 1 + Current sample, line, band is: 37 63 1 + Current sample, line, band is: 38 63 1 + Current sample, line, band is: 39 63 1 + Current sample, line, band is: 40 63 1 + Current sample, line, band is: 41 63 1 + Current sample, line, band is: 42 63 1 + Current sample, line, band is: 43 63 1 + Current sample, line, band is: 44 63 1 + Current sample, line, band is: 45 63 1 + Current sample, line, band is: 46 63 1 + Current sample, line, band is: 47 63 1 + Current sample, line, band is: 48 63 1 + Current sample, line, band is: 49 63 1 + Current sample, line, band is: 50 63 1 + Current sample, line, band is: 51 63 1 + Current sample, line, band is: 52 63 1 + Current sample, line, band is: 53 63 1 + Current sample, line, band is: 54 63 1 + Current sample, line, band is: 55 63 1 + Current sample, line, band is: 56 63 1 + Current sample, line, band is: 57 63 1 + Current sample, line, band is: 58 63 1 + Current sample, line, band is: 59 63 1 + Current sample, line, band is: 60 63 1 + Current sample, line, band is: 61 63 1 + Current sample, line, band is: 62 63 1 + Current sample, line, band is: 63 63 1 + Current sample, line, band is: 64 63 1 + Current sample, line, band is: 65 63 1 + Current sample, line, band is: 66 63 1 + Current sample, line, band is: 67 63 1 + Current sample, line, band is: 68 63 1 + Current sample, line, band is: 69 63 1 + Current sample, line, band is: 70 63 1 + Current sample, line, band is: 71 63 1 + Current sample, line, band is: 72 63 1 + Current sample, line, band is: 73 63 1 + Current sample, line, band is: 74 63 1 + Current sample, line, band is: 75 63 1 + Current sample, line, band is: 76 63 1 + Current sample, line, band is: 77 63 1 + Current sample, line, band is: 78 63 1 + Current sample, line, band is: 79 63 1 + Current sample, line, band is: 80 63 1 + Current sample, line, band is: 81 63 1 + Current sample, line, band is: 82 63 1 + Current sample, line, band is: 83 63 1 + Current sample, line, band is: 84 63 1 + Current sample, line, band is: 85 63 1 + Current sample, line, band is: 86 63 1 + Current sample, line, band is: 87 63 1 + Current sample, line, band is: 88 63 1 + Current sample, line, band is: 89 63 1 + Current sample, line, band is: 90 63 1 + Current sample, line, band is: 91 63 1 + Current sample, line, band is: 92 63 1 + Current sample, line, band is: 93 63 1 + Current sample, line, band is: 94 63 1 + Current sample, line, band is: 95 63 1 + Current sample, line, band is: 96 63 1 + Current sample, line, band is: 97 63 1 + Current sample, line, band is: 98 63 1 + Current sample, line, band is: 99 63 1 + Current sample, line, band is: 100 63 1 + Current sample, line, band is: 101 63 1 + Current sample, line, band is: 102 63 1 + Current sample, line, band is: 103 63 1 + Current sample, line, band is: 104 63 1 + Current sample, line, band is: 105 63 1 + Current sample, line, band is: 106 63 1 + Current sample, line, band is: 107 63 1 + Current sample, line, band is: 108 63 1 + Current sample, line, band is: 109 63 1 + Current sample, line, band is: 110 63 1 + Current sample, line, band is: 111 63 1 + Current sample, line, band is: 112 63 1 + Current sample, line, band is: 113 63 1 + Current sample, line, band is: 114 63 1 + Current sample, line, band is: 115 63 1 + Current sample, line, band is: 116 63 1 + Current sample, line, band is: 117 63 1 + Current sample, line, band is: 118 63 1 + Current sample, line, band is: 119 63 1 + Current sample, line, band is: 120 63 1 + Current sample, line, band is: 121 63 1 + Current sample, line, band is: 122 63 1 + Current sample, line, band is: 123 63 1 + Current sample, line, band is: 124 63 1 + Current sample, line, band is: 125 63 1 + Current sample, line, band is: 126 63 1 + Current sample, line, band is: 1 64 1 + Current sample, line, band is: 2 64 1 + Current sample, line, band is: 3 64 1 + Current sample, line, band is: 4 64 1 + Current sample, line, band is: 5 64 1 + Current sample, line, band is: 6 64 1 + Current sample, line, band is: 7 64 1 + Current sample, line, band is: 8 64 1 + Current sample, line, band is: 9 64 1 + Current sample, line, band is: 10 64 1 + Current sample, line, band is: 11 64 1 + Current sample, line, band is: 12 64 1 + Current sample, line, band is: 13 64 1 + Current sample, line, band is: 14 64 1 + Current sample, line, band is: 15 64 1 + Current sample, line, band is: 16 64 1 + Current sample, line, band is: 17 64 1 + Current sample, line, band is: 18 64 1 + Current sample, line, band is: 19 64 1 + Current sample, line, band is: 20 64 1 + Current sample, line, band is: 21 64 1 + Current sample, line, band is: 22 64 1 + Current sample, line, band is: 23 64 1 + Current sample, line, band is: 24 64 1 + Current sample, line, band is: 25 64 1 + Current sample, line, band is: 26 64 1 + Current sample, line, band is: 27 64 1 + Current sample, line, band is: 28 64 1 + Current sample, line, band is: 29 64 1 + Current sample, line, band is: 30 64 1 + Current sample, line, band is: 31 64 1 + Current sample, line, band is: 32 64 1 + Current sample, line, band is: 33 64 1 + Current sample, line, band is: 34 64 1 + Current sample, line, band is: 35 64 1 + Current sample, line, band is: 36 64 1 + Current sample, line, band is: 37 64 1 + Current sample, line, band is: 38 64 1 + Current sample, line, band is: 39 64 1 + Current sample, line, band is: 40 64 1 + Current sample, line, band is: 41 64 1 + Current sample, line, band is: 42 64 1 + Current sample, line, band is: 43 64 1 + Current sample, line, band is: 44 64 1 + Current sample, line, band is: 45 64 1 + Current sample, line, band is: 46 64 1 + Current sample, line, band is: 47 64 1 + Current sample, line, band is: 48 64 1 + Current sample, line, band is: 49 64 1 + Current sample, line, band is: 50 64 1 + Current sample, line, band is: 51 64 1 + Current sample, line, band is: 52 64 1 + Current sample, line, band is: 53 64 1 + Current sample, line, band is: 54 64 1 + Current sample, line, band is: 55 64 1 + Current sample, line, band is: 56 64 1 + Current sample, line, band is: 57 64 1 + Current sample, line, band is: 58 64 1 + Current sample, line, band is: 59 64 1 + Current sample, line, band is: 60 64 1 + Current sample, line, band is: 61 64 1 + Current sample, line, band is: 62 64 1 + Current sample, line, band is: 63 64 1 + Current sample, line, band is: 64 64 1 + Current sample, line, band is: 65 64 1 + Current sample, line, band is: 66 64 1 + Current sample, line, band is: 67 64 1 + Current sample, line, band is: 68 64 1 + Current sample, line, band is: 69 64 1 + Current sample, line, band is: 70 64 1 + Current sample, line, band is: 71 64 1 + Current sample, line, band is: 72 64 1 + Current sample, line, band is: 73 64 1 + Current sample, line, band is: 74 64 1 + Current sample, line, band is: 75 64 1 + Current sample, line, band is: 76 64 1 + Current sample, line, band is: 77 64 1 + Current sample, line, band is: 78 64 1 + Current sample, line, band is: 79 64 1 + Current sample, line, band is: 80 64 1 + Current sample, line, band is: 81 64 1 + Current sample, line, band is: 82 64 1 + Current sample, line, band is: 83 64 1 + Current sample, line, band is: 84 64 1 + Current sample, line, band is: 85 64 1 + Current sample, line, band is: 86 64 1 + Current sample, line, band is: 87 64 1 + Current sample, line, band is: 88 64 1 + Current sample, line, band is: 89 64 1 + Current sample, line, band is: 90 64 1 + Current sample, line, band is: 91 64 1 + Current sample, line, band is: 92 64 1 + Current sample, line, band is: 93 64 1 + Current sample, line, band is: 94 64 1 + Current sample, line, band is: 95 64 1 + Current sample, line, band is: 96 64 1 + Current sample, line, band is: 97 64 1 + Current sample, line, band is: 98 64 1 + Current sample, line, band is: 99 64 1 + Current sample, line, band is: 100 64 1 + Current sample, line, band is: 101 64 1 + Current sample, line, band is: 102 64 1 + Current sample, line, band is: 103 64 1 + Current sample, line, band is: 104 64 1 + Current sample, line, band is: 105 64 1 + Current sample, line, band is: 106 64 1 + Current sample, line, band is: 107 64 1 + Current sample, line, band is: 108 64 1 + Current sample, line, band is: 109 64 1 + Current sample, line, band is: 110 64 1 + Current sample, line, band is: 111 64 1 + Current sample, line, band is: 112 64 1 + Current sample, line, band is: 113 64 1 + Current sample, line, band is: 114 64 1 + Current sample, line, band is: 115 64 1 + Current sample, line, band is: 116 64 1 + Current sample, line, band is: 117 64 1 + Current sample, line, band is: 118 64 1 + Current sample, line, band is: 119 64 1 + Current sample, line, band is: 120 64 1 + Current sample, line, band is: 121 64 1 + Current sample, line, band is: 122 64 1 + Current sample, line, band is: 123 64 1 + Current sample, line, band is: 124 64 1 + Current sample, line, band is: 125 64 1 + Current sample, line, band is: 126 64 1 + Current sample, line, band is: 1 65 1 + Current sample, line, band is: 2 65 1 + Current sample, line, band is: 3 65 1 + Current sample, line, band is: 4 65 1 + Current sample, line, band is: 5 65 1 + Current sample, line, band is: 6 65 1 + Current sample, line, band is: 7 65 1 + Current sample, line, band is: 8 65 1 + Current sample, line, band is: 9 65 1 + Current sample, line, band is: 10 65 1 + Current sample, line, band is: 11 65 1 + Current sample, line, band is: 12 65 1 + Current sample, line, band is: 13 65 1 + Current sample, line, band is: 14 65 1 + Current sample, line, band is: 15 65 1 + Current sample, line, band is: 16 65 1 + Current sample, line, band is: 17 65 1 + Current sample, line, band is: 18 65 1 + Current sample, line, band is: 19 65 1 + Current sample, line, band is: 20 65 1 + Current sample, line, band is: 21 65 1 + Current sample, line, band is: 22 65 1 + Current sample, line, band is: 23 65 1 + Current sample, line, band is: 24 65 1 + Current sample, line, band is: 25 65 1 + Current sample, line, band is: 26 65 1 + Current sample, line, band is: 27 65 1 + Current sample, line, band is: 28 65 1 + Current sample, line, band is: 29 65 1 + Current sample, line, band is: 30 65 1 + Current sample, line, band is: 31 65 1 + Current sample, line, band is: 32 65 1 + Current sample, line, band is: 33 65 1 + Current sample, line, band is: 34 65 1 + Current sample, line, band is: 35 65 1 + Current sample, line, band is: 36 65 1 + Current sample, line, band is: 37 65 1 + Current sample, line, band is: 38 65 1 + Current sample, line, band is: 39 65 1 + Current sample, line, band is: 40 65 1 + Current sample, line, band is: 41 65 1 + Current sample, line, band is: 42 65 1 + Current sample, line, band is: 43 65 1 + Current sample, line, band is: 44 65 1 + Current sample, line, band is: 45 65 1 + Current sample, line, band is: 46 65 1 + Current sample, line, band is: 47 65 1 + Current sample, line, band is: 48 65 1 + Current sample, line, band is: 49 65 1 + Current sample, line, band is: 50 65 1 + Current sample, line, band is: 51 65 1 + Current sample, line, band is: 52 65 1 + Current sample, line, band is: 53 65 1 + Current sample, line, band is: 54 65 1 + Current sample, line, band is: 55 65 1 + Current sample, line, band is: 56 65 1 + Current sample, line, band is: 57 65 1 + Current sample, line, band is: 58 65 1 + Current sample, line, band is: 59 65 1 + Current sample, line, band is: 60 65 1 + Current sample, line, band is: 61 65 1 + Current sample, line, band is: 62 65 1 + Current sample, line, band is: 63 65 1 + Current sample, line, band is: 64 65 1 + Current sample, line, band is: 65 65 1 + Current sample, line, band is: 66 65 1 + Current sample, line, band is: 67 65 1 + Current sample, line, band is: 68 65 1 + Current sample, line, band is: 69 65 1 + Current sample, line, band is: 70 65 1 + Current sample, line, band is: 71 65 1 + Current sample, line, band is: 72 65 1 + Current sample, line, band is: 73 65 1 + Current sample, line, band is: 74 65 1 + Current sample, line, band is: 75 65 1 + Current sample, line, band is: 76 65 1 + Current sample, line, band is: 77 65 1 + Current sample, line, band is: 78 65 1 + Current sample, line, band is: 79 65 1 + Current sample, line, band is: 80 65 1 + Current sample, line, band is: 81 65 1 + Current sample, line, band is: 82 65 1 + Current sample, line, band is: 83 65 1 + Current sample, line, band is: 84 65 1 + Current sample, line, band is: 85 65 1 + Current sample, line, band is: 86 65 1 + Current sample, line, band is: 87 65 1 + Current sample, line, band is: 88 65 1 + Current sample, line, band is: 89 65 1 + Current sample, line, band is: 90 65 1 + Current sample, line, band is: 91 65 1 + Current sample, line, band is: 92 65 1 + Current sample, line, band is: 93 65 1 + Current sample, line, band is: 94 65 1 + Current sample, line, band is: 95 65 1 + Current sample, line, band is: 96 65 1 + Current sample, line, band is: 97 65 1 + Current sample, line, band is: 98 65 1 + Current sample, line, band is: 99 65 1 + Current sample, line, band is: 100 65 1 + Current sample, line, band is: 101 65 1 + Current sample, line, band is: 102 65 1 + Current sample, line, band is: 103 65 1 + Current sample, line, band is: 104 65 1 + Current sample, line, band is: 105 65 1 + Current sample, line, band is: 106 65 1 + Current sample, line, band is: 107 65 1 + Current sample, line, band is: 108 65 1 + Current sample, line, band is: 109 65 1 + Current sample, line, band is: 110 65 1 + Current sample, line, band is: 111 65 1 + Current sample, line, band is: 112 65 1 + Current sample, line, band is: 113 65 1 + Current sample, line, band is: 114 65 1 + Current sample, line, band is: 115 65 1 + Current sample, line, band is: 116 65 1 + Current sample, line, band is: 117 65 1 + Current sample, line, band is: 118 65 1 + Current sample, line, band is: 119 65 1 + Current sample, line, band is: 120 65 1 + Current sample, line, band is: 121 65 1 + Current sample, line, band is: 122 65 1 + Current sample, line, band is: 123 65 1 + Current sample, line, band is: 124 65 1 + Current sample, line, band is: 125 65 1 + Current sample, line, band is: 126 65 1 + Current sample, line, band is: 1 66 1 + Current sample, line, band is: 2 66 1 + Current sample, line, band is: 3 66 1 + Current sample, line, band is: 4 66 1 + Current sample, line, band is: 5 66 1 + Current sample, line, band is: 6 66 1 + Current sample, line, band is: 7 66 1 + Current sample, line, band is: 8 66 1 + Current sample, line, band is: 9 66 1 + Current sample, line, band is: 10 66 1 + Current sample, line, band is: 11 66 1 + Current sample, line, band is: 12 66 1 + Current sample, line, band is: 13 66 1 + Current sample, line, band is: 14 66 1 + Current sample, line, band is: 15 66 1 + Current sample, line, band is: 16 66 1 + Current sample, line, band is: 17 66 1 + Current sample, line, band is: 18 66 1 + Current sample, line, band is: 19 66 1 + Current sample, line, band is: 20 66 1 + Current sample, line, band is: 21 66 1 + Current sample, line, band is: 22 66 1 + Current sample, line, band is: 23 66 1 + Current sample, line, band is: 24 66 1 + Current sample, line, band is: 25 66 1 + Current sample, line, band is: 26 66 1 + Current sample, line, band is: 27 66 1 + Current sample, line, band is: 28 66 1 + Current sample, line, band is: 29 66 1 + Current sample, line, band is: 30 66 1 + Current sample, line, band is: 31 66 1 + Current sample, line, band is: 32 66 1 + Current sample, line, band is: 33 66 1 + Current sample, line, band is: 34 66 1 + Current sample, line, band is: 35 66 1 + Current sample, line, band is: 36 66 1 + Current sample, line, band is: 37 66 1 + Current sample, line, band is: 38 66 1 + Current sample, line, band is: 39 66 1 + Current sample, line, band is: 40 66 1 + Current sample, line, band is: 41 66 1 + Current sample, line, band is: 42 66 1 + Current sample, line, band is: 43 66 1 + Current sample, line, band is: 44 66 1 + Current sample, line, band is: 45 66 1 + Current sample, line, band is: 46 66 1 + Current sample, line, band is: 47 66 1 + Current sample, line, band is: 48 66 1 + Current sample, line, band is: 49 66 1 + Current sample, line, band is: 50 66 1 + Current sample, line, band is: 51 66 1 + Current sample, line, band is: 52 66 1 + Current sample, line, band is: 53 66 1 + Current sample, line, band is: 54 66 1 + Current sample, line, band is: 55 66 1 + Current sample, line, band is: 56 66 1 + Current sample, line, band is: 57 66 1 + Current sample, line, band is: 58 66 1 + Current sample, line, band is: 59 66 1 + Current sample, line, band is: 60 66 1 + Current sample, line, band is: 61 66 1 + Current sample, line, band is: 62 66 1 + Current sample, line, band is: 63 66 1 + Current sample, line, band is: 64 66 1 + Current sample, line, band is: 65 66 1 + Current sample, line, band is: 66 66 1 + Current sample, line, band is: 67 66 1 + Current sample, line, band is: 68 66 1 + Current sample, line, band is: 69 66 1 + Current sample, line, band is: 70 66 1 + Current sample, line, band is: 71 66 1 + Current sample, line, band is: 72 66 1 + Current sample, line, band is: 73 66 1 + Current sample, line, band is: 74 66 1 + Current sample, line, band is: 75 66 1 + Current sample, line, band is: 76 66 1 + Current sample, line, band is: 77 66 1 + Current sample, line, band is: 78 66 1 + Current sample, line, band is: 79 66 1 + Current sample, line, band is: 80 66 1 + Current sample, line, band is: 81 66 1 + Current sample, line, band is: 82 66 1 + Current sample, line, band is: 83 66 1 + Current sample, line, band is: 84 66 1 + Current sample, line, band is: 85 66 1 + Current sample, line, band is: 86 66 1 + Current sample, line, band is: 87 66 1 + Current sample, line, band is: 88 66 1 + Current sample, line, band is: 89 66 1 + Current sample, line, band is: 90 66 1 + Current sample, line, band is: 91 66 1 + Current sample, line, band is: 92 66 1 + Current sample, line, band is: 93 66 1 + Current sample, line, band is: 94 66 1 + Current sample, line, band is: 95 66 1 + Current sample, line, band is: 96 66 1 + Current sample, line, band is: 97 66 1 + Current sample, line, band is: 98 66 1 + Current sample, line, band is: 99 66 1 + Current sample, line, band is: 100 66 1 + Current sample, line, band is: 101 66 1 + Current sample, line, band is: 102 66 1 + Current sample, line, band is: 103 66 1 + Current sample, line, band is: 104 66 1 + Current sample, line, band is: 105 66 1 + Current sample, line, band is: 106 66 1 + Current sample, line, band is: 107 66 1 + Current sample, line, band is: 108 66 1 + Current sample, line, band is: 109 66 1 + Current sample, line, band is: 110 66 1 + Current sample, line, band is: 111 66 1 + Current sample, line, band is: 112 66 1 + Current sample, line, band is: 113 66 1 + Current sample, line, band is: 114 66 1 + Current sample, line, band is: 115 66 1 + Current sample, line, band is: 116 66 1 + Current sample, line, band is: 117 66 1 + Current sample, line, band is: 118 66 1 + Current sample, line, band is: 119 66 1 + Current sample, line, band is: 120 66 1 + Current sample, line, band is: 121 66 1 + Current sample, line, band is: 122 66 1 + Current sample, line, band is: 123 66 1 + Current sample, line, band is: 124 66 1 + Current sample, line, band is: 125 66 1 + Current sample, line, band is: 126 66 1 + Current sample, line, band is: 1 67 1 + Current sample, line, band is: 2 67 1 + Current sample, line, band is: 3 67 1 + Current sample, line, band is: 4 67 1 + Current sample, line, band is: 5 67 1 + Current sample, line, band is: 6 67 1 + Current sample, line, band is: 7 67 1 + Current sample, line, band is: 8 67 1 + Current sample, line, band is: 9 67 1 + Current sample, line, band is: 10 67 1 + Current sample, line, band is: 11 67 1 + Current sample, line, band is: 12 67 1 + Current sample, line, band is: 13 67 1 + Current sample, line, band is: 14 67 1 + Current sample, line, band is: 15 67 1 + Current sample, line, band is: 16 67 1 + Current sample, line, band is: 17 67 1 + Current sample, line, band is: 18 67 1 + Current sample, line, band is: 19 67 1 + Current sample, line, band is: 20 67 1 + Current sample, line, band is: 21 67 1 + Current sample, line, band is: 22 67 1 + Current sample, line, band is: 23 67 1 + Current sample, line, band is: 24 67 1 + Current sample, line, band is: 25 67 1 + Current sample, line, band is: 26 67 1 + Current sample, line, band is: 27 67 1 + Current sample, line, band is: 28 67 1 + Current sample, line, band is: 29 67 1 + Current sample, line, band is: 30 67 1 + Current sample, line, band is: 31 67 1 + Current sample, line, band is: 32 67 1 + Current sample, line, band is: 33 67 1 + Current sample, line, band is: 34 67 1 + Current sample, line, band is: 35 67 1 + Current sample, line, band is: 36 67 1 + Current sample, line, band is: 37 67 1 + Current sample, line, band is: 38 67 1 + Current sample, line, band is: 39 67 1 + Current sample, line, band is: 40 67 1 + Current sample, line, band is: 41 67 1 + Current sample, line, band is: 42 67 1 + Current sample, line, band is: 43 67 1 + Current sample, line, band is: 44 67 1 + Current sample, line, band is: 45 67 1 + Current sample, line, band is: 46 67 1 + Current sample, line, band is: 47 67 1 + Current sample, line, band is: 48 67 1 + Current sample, line, band is: 49 67 1 + Current sample, line, band is: 50 67 1 + Current sample, line, band is: 51 67 1 + Current sample, line, band is: 52 67 1 + Current sample, line, band is: 53 67 1 + Current sample, line, band is: 54 67 1 + Current sample, line, band is: 55 67 1 + Current sample, line, band is: 56 67 1 + Current sample, line, band is: 57 67 1 + Current sample, line, band is: 58 67 1 + Current sample, line, band is: 59 67 1 + Current sample, line, band is: 60 67 1 + Current sample, line, band is: 61 67 1 + Current sample, line, band is: 62 67 1 + Current sample, line, band is: 63 67 1 + Current sample, line, band is: 64 67 1 + Current sample, line, band is: 65 67 1 + Current sample, line, band is: 66 67 1 + Current sample, line, band is: 67 67 1 + Current sample, line, band is: 68 67 1 + Current sample, line, band is: 69 67 1 + Current sample, line, band is: 70 67 1 + Current sample, line, band is: 71 67 1 + Current sample, line, band is: 72 67 1 + Current sample, line, band is: 73 67 1 + Current sample, line, band is: 74 67 1 + Current sample, line, band is: 75 67 1 + Current sample, line, band is: 76 67 1 + Current sample, line, band is: 77 67 1 + Current sample, line, band is: 78 67 1 + Current sample, line, band is: 79 67 1 + Current sample, line, band is: 80 67 1 + Current sample, line, band is: 81 67 1 + Current sample, line, band is: 82 67 1 + Current sample, line, band is: 83 67 1 + Current sample, line, band is: 84 67 1 + Current sample, line, band is: 85 67 1 + Current sample, line, band is: 86 67 1 + Current sample, line, band is: 87 67 1 + Current sample, line, band is: 88 67 1 + Current sample, line, band is: 89 67 1 + Current sample, line, band is: 90 67 1 + Current sample, line, band is: 91 67 1 + Current sample, line, band is: 92 67 1 + Current sample, line, band is: 93 67 1 + Current sample, line, band is: 94 67 1 + Current sample, line, band is: 95 67 1 + Current sample, line, band is: 96 67 1 + Current sample, line, band is: 97 67 1 + Current sample, line, band is: 98 67 1 + Current sample, line, band is: 99 67 1 + Current sample, line, band is: 100 67 1 + Current sample, line, band is: 101 67 1 + Current sample, line, band is: 102 67 1 + Current sample, line, band is: 103 67 1 + Current sample, line, band is: 104 67 1 + Current sample, line, band is: 105 67 1 + Current sample, line, band is: 106 67 1 + Current sample, line, band is: 107 67 1 + Current sample, line, band is: 108 67 1 + Current sample, line, band is: 109 67 1 + Current sample, line, band is: 110 67 1 + Current sample, line, band is: 111 67 1 + Current sample, line, band is: 112 67 1 + Current sample, line, band is: 113 67 1 + Current sample, line, band is: 114 67 1 + Current sample, line, band is: 115 67 1 + Current sample, line, band is: 116 67 1 + Current sample, line, band is: 117 67 1 + Current sample, line, band is: 118 67 1 + Current sample, line, band is: 119 67 1 + Current sample, line, band is: 120 67 1 + Current sample, line, band is: 121 67 1 + Current sample, line, band is: 122 67 1 + Current sample, line, band is: 123 67 1 + Current sample, line, band is: 124 67 1 + Current sample, line, band is: 125 67 1 + Current sample, line, band is: 126 67 1 + Current sample, line, band is: 1 68 1 + Current sample, line, band is: 2 68 1 + Current sample, line, band is: 3 68 1 + Current sample, line, band is: 4 68 1 + Current sample, line, band is: 5 68 1 + Current sample, line, band is: 6 68 1 + Current sample, line, band is: 7 68 1 + Current sample, line, band is: 8 68 1 + Current sample, line, band is: 9 68 1 + Current sample, line, band is: 10 68 1 + Current sample, line, band is: 11 68 1 + Current sample, line, band is: 12 68 1 + Current sample, line, band is: 13 68 1 + Current sample, line, band is: 14 68 1 + Current sample, line, band is: 15 68 1 + Current sample, line, band is: 16 68 1 + Current sample, line, band is: 17 68 1 + Current sample, line, band is: 18 68 1 + Current sample, line, band is: 19 68 1 + Current sample, line, band is: 20 68 1 + Current sample, line, band is: 21 68 1 + Current sample, line, band is: 22 68 1 + Current sample, line, band is: 23 68 1 + Current sample, line, band is: 24 68 1 + Current sample, line, band is: 25 68 1 + Current sample, line, band is: 26 68 1 + Current sample, line, band is: 27 68 1 + Current sample, line, band is: 28 68 1 + Current sample, line, band is: 29 68 1 + Current sample, line, band is: 30 68 1 + Current sample, line, band is: 31 68 1 + Current sample, line, band is: 32 68 1 + Current sample, line, band is: 33 68 1 + Current sample, line, band is: 34 68 1 + Current sample, line, band is: 35 68 1 + Current sample, line, band is: 36 68 1 + Current sample, line, band is: 37 68 1 + Current sample, line, band is: 38 68 1 + Current sample, line, band is: 39 68 1 + Current sample, line, band is: 40 68 1 + Current sample, line, band is: 41 68 1 + Current sample, line, band is: 42 68 1 + Current sample, line, band is: 43 68 1 + Current sample, line, band is: 44 68 1 + Current sample, line, band is: 45 68 1 + Current sample, line, band is: 46 68 1 + Current sample, line, band is: 47 68 1 + Current sample, line, band is: 48 68 1 + Current sample, line, band is: 49 68 1 + Current sample, line, band is: 50 68 1 + Current sample, line, band is: 51 68 1 + Current sample, line, band is: 52 68 1 + Current sample, line, band is: 53 68 1 + Current sample, line, band is: 54 68 1 + Current sample, line, band is: 55 68 1 + Current sample, line, band is: 56 68 1 + Current sample, line, band is: 57 68 1 + Current sample, line, band is: 58 68 1 + Current sample, line, band is: 59 68 1 + Current sample, line, band is: 60 68 1 + Current sample, line, band is: 61 68 1 + Current sample, line, band is: 62 68 1 + Current sample, line, band is: 63 68 1 + Current sample, line, band is: 64 68 1 + Current sample, line, band is: 65 68 1 + Current sample, line, band is: 66 68 1 + Current sample, line, band is: 67 68 1 + Current sample, line, band is: 68 68 1 + Current sample, line, band is: 69 68 1 + Current sample, line, band is: 70 68 1 + Current sample, line, band is: 71 68 1 + Current sample, line, band is: 72 68 1 + Current sample, line, band is: 73 68 1 + Current sample, line, band is: 74 68 1 + Current sample, line, band is: 75 68 1 + Current sample, line, band is: 76 68 1 + Current sample, line, band is: 77 68 1 + Current sample, line, band is: 78 68 1 + Current sample, line, band is: 79 68 1 + Current sample, line, band is: 80 68 1 + Current sample, line, band is: 81 68 1 + Current sample, line, band is: 82 68 1 + Current sample, line, band is: 83 68 1 + Current sample, line, band is: 84 68 1 + Current sample, line, band is: 85 68 1 + Current sample, line, band is: 86 68 1 + Current sample, line, band is: 87 68 1 + Current sample, line, band is: 88 68 1 + Current sample, line, band is: 89 68 1 + Current sample, line, band is: 90 68 1 + Current sample, line, band is: 91 68 1 + Current sample, line, band is: 92 68 1 + Current sample, line, band is: 93 68 1 + Current sample, line, band is: 94 68 1 + Current sample, line, band is: 95 68 1 + Current sample, line, band is: 96 68 1 + Current sample, line, band is: 97 68 1 + Current sample, line, band is: 98 68 1 + Current sample, line, band is: 99 68 1 + Current sample, line, band is: 100 68 1 + Current sample, line, band is: 101 68 1 + Current sample, line, band is: 102 68 1 + Current sample, line, band is: 103 68 1 + Current sample, line, band is: 104 68 1 + Current sample, line, band is: 105 68 1 + Current sample, line, band is: 106 68 1 + Current sample, line, band is: 107 68 1 + Current sample, line, band is: 108 68 1 + Current sample, line, band is: 109 68 1 + Current sample, line, band is: 110 68 1 + Current sample, line, band is: 111 68 1 + Current sample, line, band is: 112 68 1 + Current sample, line, band is: 113 68 1 + Current sample, line, band is: 114 68 1 + Current sample, line, band is: 115 68 1 + Current sample, line, band is: 116 68 1 + Current sample, line, band is: 117 68 1 + Current sample, line, band is: 118 68 1 + Current sample, line, band is: 119 68 1 + Current sample, line, band is: 120 68 1 + Current sample, line, band is: 121 68 1 + Current sample, line, band is: 122 68 1 + Current sample, line, band is: 123 68 1 + Current sample, line, band is: 124 68 1 + Current sample, line, band is: 125 68 1 + Current sample, line, band is: 126 68 1 + Current sample, line, band is: 1 69 1 + Current sample, line, band is: 2 69 1 + Current sample, line, band is: 3 69 1 + Current sample, line, band is: 4 69 1 + Current sample, line, band is: 5 69 1 + Current sample, line, band is: 6 69 1 + Current sample, line, band is: 7 69 1 + Current sample, line, band is: 8 69 1 + Current sample, line, band is: 9 69 1 + Current sample, line, band is: 10 69 1 + Current sample, line, band is: 11 69 1 + Current sample, line, band is: 12 69 1 + Current sample, line, band is: 13 69 1 + Current sample, line, band is: 14 69 1 + Current sample, line, band is: 15 69 1 + Current sample, line, band is: 16 69 1 + Current sample, line, band is: 17 69 1 + Current sample, line, band is: 18 69 1 + Current sample, line, band is: 19 69 1 + Current sample, line, band is: 20 69 1 + Current sample, line, band is: 21 69 1 + Current sample, line, band is: 22 69 1 + Current sample, line, band is: 23 69 1 + Current sample, line, band is: 24 69 1 + Current sample, line, band is: 25 69 1 + Current sample, line, band is: 26 69 1 + Current sample, line, band is: 27 69 1 + Current sample, line, band is: 28 69 1 + Current sample, line, band is: 29 69 1 + Current sample, line, band is: 30 69 1 + Current sample, line, band is: 31 69 1 + Current sample, line, band is: 32 69 1 + Current sample, line, band is: 33 69 1 + Current sample, line, band is: 34 69 1 + Current sample, line, band is: 35 69 1 + Current sample, line, band is: 36 69 1 + Current sample, line, band is: 37 69 1 + Current sample, line, band is: 38 69 1 + Current sample, line, band is: 39 69 1 + Current sample, line, band is: 40 69 1 + Current sample, line, band is: 41 69 1 + Current sample, line, band is: 42 69 1 + Current sample, line, band is: 43 69 1 + Current sample, line, band is: 44 69 1 + Current sample, line, band is: 45 69 1 + Current sample, line, band is: 46 69 1 + Current sample, line, band is: 47 69 1 + Current sample, line, band is: 48 69 1 + Current sample, line, band is: 49 69 1 + Current sample, line, band is: 50 69 1 + Current sample, line, band is: 51 69 1 + Current sample, line, band is: 52 69 1 + Current sample, line, band is: 53 69 1 + Current sample, line, band is: 54 69 1 + Current sample, line, band is: 55 69 1 + Current sample, line, band is: 56 69 1 + Current sample, line, band is: 57 69 1 + Current sample, line, band is: 58 69 1 + Current sample, line, band is: 59 69 1 + Current sample, line, band is: 60 69 1 + Current sample, line, band is: 61 69 1 + Current sample, line, band is: 62 69 1 + Current sample, line, band is: 63 69 1 + Current sample, line, band is: 64 69 1 + Current sample, line, band is: 65 69 1 + Current sample, line, band is: 66 69 1 + Current sample, line, band is: 67 69 1 + Current sample, line, band is: 68 69 1 + Current sample, line, band is: 69 69 1 + Current sample, line, band is: 70 69 1 + Current sample, line, band is: 71 69 1 + Current sample, line, band is: 72 69 1 + Current sample, line, band is: 73 69 1 + Current sample, line, band is: 74 69 1 + Current sample, line, band is: 75 69 1 + Current sample, line, band is: 76 69 1 + Current sample, line, band is: 77 69 1 + Current sample, line, band is: 78 69 1 + Current sample, line, band is: 79 69 1 + Current sample, line, band is: 80 69 1 + Current sample, line, band is: 81 69 1 + Current sample, line, band is: 82 69 1 + Current sample, line, band is: 83 69 1 + Current sample, line, band is: 84 69 1 + Current sample, line, band is: 85 69 1 + Current sample, line, band is: 86 69 1 + Current sample, line, band is: 87 69 1 + Current sample, line, band is: 88 69 1 + Current sample, line, band is: 89 69 1 + Current sample, line, band is: 90 69 1 + Current sample, line, band is: 91 69 1 + Current sample, line, band is: 92 69 1 + Current sample, line, band is: 93 69 1 + Current sample, line, band is: 94 69 1 + Current sample, line, band is: 95 69 1 + Current sample, line, band is: 96 69 1 + Current sample, line, band is: 97 69 1 + Current sample, line, band is: 98 69 1 + Current sample, line, band is: 99 69 1 + Current sample, line, band is: 100 69 1 + Current sample, line, band is: 101 69 1 + Current sample, line, band is: 102 69 1 + Current sample, line, band is: 103 69 1 + Current sample, line, band is: 104 69 1 + Current sample, line, band is: 105 69 1 + Current sample, line, band is: 106 69 1 + Current sample, line, band is: 107 69 1 + Current sample, line, band is: 108 69 1 + Current sample, line, band is: 109 69 1 + Current sample, line, band is: 110 69 1 + Current sample, line, band is: 111 69 1 + Current sample, line, band is: 112 69 1 + Current sample, line, band is: 113 69 1 + Current sample, line, band is: 114 69 1 + Current sample, line, band is: 115 69 1 + Current sample, line, band is: 116 69 1 + Current sample, line, band is: 117 69 1 + Current sample, line, band is: 118 69 1 + Current sample, line, band is: 119 69 1 + Current sample, line, band is: 120 69 1 + Current sample, line, band is: 121 69 1 + Current sample, line, band is: 122 69 1 + Current sample, line, band is: 123 69 1 + Current sample, line, band is: 124 69 1 + Current sample, line, band is: 125 69 1 + Current sample, line, band is: 126 69 1 + Current sample, line, band is: 1 70 1 + Current sample, line, band is: 2 70 1 + Current sample, line, band is: 3 70 1 + Current sample, line, band is: 4 70 1 + Current sample, line, band is: 5 70 1 + Current sample, line, band is: 6 70 1 + Current sample, line, band is: 7 70 1 + Current sample, line, band is: 8 70 1 + Current sample, line, band is: 9 70 1 + Current sample, line, band is: 10 70 1 + Current sample, line, band is: 11 70 1 + Current sample, line, band is: 12 70 1 + Current sample, line, band is: 13 70 1 + Current sample, line, band is: 14 70 1 + Current sample, line, band is: 15 70 1 + Current sample, line, band is: 16 70 1 + Current sample, line, band is: 17 70 1 + Current sample, line, band is: 18 70 1 + Current sample, line, band is: 19 70 1 + Current sample, line, band is: 20 70 1 + Current sample, line, band is: 21 70 1 + Current sample, line, band is: 22 70 1 + Current sample, line, band is: 23 70 1 + Current sample, line, band is: 24 70 1 + Current sample, line, band is: 25 70 1 + Current sample, line, band is: 26 70 1 + Current sample, line, band is: 27 70 1 + Current sample, line, band is: 28 70 1 + Current sample, line, band is: 29 70 1 + Current sample, line, band is: 30 70 1 + Current sample, line, band is: 31 70 1 + Current sample, line, band is: 32 70 1 + Current sample, line, band is: 33 70 1 + Current sample, line, band is: 34 70 1 + Current sample, line, band is: 35 70 1 + Current sample, line, band is: 36 70 1 + Current sample, line, band is: 37 70 1 + Current sample, line, band is: 38 70 1 + Current sample, line, band is: 39 70 1 + Current sample, line, band is: 40 70 1 + Current sample, line, band is: 41 70 1 + Current sample, line, band is: 42 70 1 + Current sample, line, band is: 43 70 1 + Current sample, line, band is: 44 70 1 + Current sample, line, band is: 45 70 1 + Current sample, line, band is: 46 70 1 + Current sample, line, band is: 47 70 1 + Current sample, line, band is: 48 70 1 + Current sample, line, band is: 49 70 1 + Current sample, line, band is: 50 70 1 + Current sample, line, band is: 51 70 1 + Current sample, line, band is: 52 70 1 + Current sample, line, band is: 53 70 1 + Current sample, line, band is: 54 70 1 + Current sample, line, band is: 55 70 1 + Current sample, line, band is: 56 70 1 + Current sample, line, band is: 57 70 1 + Current sample, line, band is: 58 70 1 + Current sample, line, band is: 59 70 1 + Current sample, line, band is: 60 70 1 + Current sample, line, band is: 61 70 1 + Current sample, line, band is: 62 70 1 + Current sample, line, band is: 63 70 1 + Current sample, line, band is: 64 70 1 + Current sample, line, band is: 65 70 1 + Current sample, line, band is: 66 70 1 + Current sample, line, band is: 67 70 1 + Current sample, line, band is: 68 70 1 + Current sample, line, band is: 69 70 1 + Current sample, line, band is: 70 70 1 + Current sample, line, band is: 71 70 1 + Current sample, line, band is: 72 70 1 + Current sample, line, band is: 73 70 1 + Current sample, line, band is: 74 70 1 + Current sample, line, band is: 75 70 1 + Current sample, line, band is: 76 70 1 + Current sample, line, band is: 77 70 1 + Current sample, line, band is: 78 70 1 + Current sample, line, band is: 79 70 1 + Current sample, line, band is: 80 70 1 + Current sample, line, band is: 81 70 1 + Current sample, line, band is: 82 70 1 + Current sample, line, band is: 83 70 1 + Current sample, line, band is: 84 70 1 + Current sample, line, band is: 85 70 1 + Current sample, line, band is: 86 70 1 + Current sample, line, band is: 87 70 1 + Current sample, line, band is: 88 70 1 + Current sample, line, band is: 89 70 1 + Current sample, line, band is: 90 70 1 + Current sample, line, band is: 91 70 1 + Current sample, line, band is: 92 70 1 + Current sample, line, band is: 93 70 1 + Current sample, line, band is: 94 70 1 + Current sample, line, band is: 95 70 1 + Current sample, line, band is: 96 70 1 + Current sample, line, band is: 97 70 1 + Current sample, line, band is: 98 70 1 + Current sample, line, band is: 99 70 1 + Current sample, line, band is: 100 70 1 + Current sample, line, band is: 101 70 1 + Current sample, line, band is: 102 70 1 + Current sample, line, band is: 103 70 1 + Current sample, line, band is: 104 70 1 + Current sample, line, band is: 105 70 1 + Current sample, line, band is: 106 70 1 + Current sample, line, band is: 107 70 1 + Current sample, line, band is: 108 70 1 + Current sample, line, band is: 109 70 1 + Current sample, line, band is: 110 70 1 + Current sample, line, band is: 111 70 1 + Current sample, line, band is: 112 70 1 + Current sample, line, band is: 113 70 1 + Current sample, line, band is: 114 70 1 + Current sample, line, band is: 115 70 1 + Current sample, line, band is: 116 70 1 + Current sample, line, band is: 117 70 1 + Current sample, line, band is: 118 70 1 + Current sample, line, band is: 119 70 1 + Current sample, line, band is: 120 70 1 + Current sample, line, band is: 121 70 1 + Current sample, line, band is: 122 70 1 + Current sample, line, band is: 123 70 1 + Current sample, line, band is: 124 70 1 + Current sample, line, band is: 125 70 1 + Current sample, line, band is: 126 70 1 + Current sample, line, band is: 1 71 1 + Current sample, line, band is: 2 71 1 + Current sample, line, band is: 3 71 1 + Current sample, line, band is: 4 71 1 + Current sample, line, band is: 5 71 1 + Current sample, line, band is: 6 71 1 + Current sample, line, band is: 7 71 1 + Current sample, line, band is: 8 71 1 + Current sample, line, band is: 9 71 1 + Current sample, line, band is: 10 71 1 + Current sample, line, band is: 11 71 1 + Current sample, line, band is: 12 71 1 + Current sample, line, band is: 13 71 1 + Current sample, line, band is: 14 71 1 + Current sample, line, band is: 15 71 1 + Current sample, line, band is: 16 71 1 + Current sample, line, band is: 17 71 1 + Current sample, line, band is: 18 71 1 + Current sample, line, band is: 19 71 1 + Current sample, line, band is: 20 71 1 + Current sample, line, band is: 21 71 1 + Current sample, line, band is: 22 71 1 + Current sample, line, band is: 23 71 1 + Current sample, line, band is: 24 71 1 + Current sample, line, band is: 25 71 1 + Current sample, line, band is: 26 71 1 + Current sample, line, band is: 27 71 1 + Current sample, line, band is: 28 71 1 + Current sample, line, band is: 29 71 1 + Current sample, line, band is: 30 71 1 + Current sample, line, band is: 31 71 1 + Current sample, line, band is: 32 71 1 + Current sample, line, band is: 33 71 1 + Current sample, line, band is: 34 71 1 + Current sample, line, band is: 35 71 1 + Current sample, line, band is: 36 71 1 + Current sample, line, band is: 37 71 1 + Current sample, line, band is: 38 71 1 + Current sample, line, band is: 39 71 1 + Current sample, line, band is: 40 71 1 + Current sample, line, band is: 41 71 1 + Current sample, line, band is: 42 71 1 + Current sample, line, band is: 43 71 1 + Current sample, line, band is: 44 71 1 + Current sample, line, band is: 45 71 1 + Current sample, line, band is: 46 71 1 + Current sample, line, band is: 47 71 1 + Current sample, line, band is: 48 71 1 + Current sample, line, band is: 49 71 1 + Current sample, line, band is: 50 71 1 + Current sample, line, band is: 51 71 1 + Current sample, line, band is: 52 71 1 + Current sample, line, band is: 53 71 1 + Current sample, line, band is: 54 71 1 + Current sample, line, band is: 55 71 1 + Current sample, line, band is: 56 71 1 + Current sample, line, band is: 57 71 1 + Current sample, line, band is: 58 71 1 + Current sample, line, band is: 59 71 1 + Current sample, line, band is: 60 71 1 + Current sample, line, band is: 61 71 1 + Current sample, line, band is: 62 71 1 + Current sample, line, band is: 63 71 1 + Current sample, line, band is: 64 71 1 + Current sample, line, band is: 65 71 1 + Current sample, line, band is: 66 71 1 + Current sample, line, band is: 67 71 1 + Current sample, line, band is: 68 71 1 + Current sample, line, band is: 69 71 1 + Current sample, line, band is: 70 71 1 + Current sample, line, band is: 71 71 1 + Current sample, line, band is: 72 71 1 + Current sample, line, band is: 73 71 1 + Current sample, line, band is: 74 71 1 + Current sample, line, band is: 75 71 1 + Current sample, line, band is: 76 71 1 + Current sample, line, band is: 77 71 1 + Current sample, line, band is: 78 71 1 + Current sample, line, band is: 79 71 1 + Current sample, line, band is: 80 71 1 + Current sample, line, band is: 81 71 1 + Current sample, line, band is: 82 71 1 + Current sample, line, band is: 83 71 1 + Current sample, line, band is: 84 71 1 + Current sample, line, band is: 85 71 1 + Current sample, line, band is: 86 71 1 + Current sample, line, band is: 87 71 1 + Current sample, line, band is: 88 71 1 + Current sample, line, band is: 89 71 1 + Current sample, line, band is: 90 71 1 + Current sample, line, band is: 91 71 1 + Current sample, line, band is: 92 71 1 + Current sample, line, band is: 93 71 1 + Current sample, line, band is: 94 71 1 + Current sample, line, band is: 95 71 1 + Current sample, line, band is: 96 71 1 + Current sample, line, band is: 97 71 1 + Current sample, line, band is: 98 71 1 + Current sample, line, band is: 99 71 1 + Current sample, line, band is: 100 71 1 + Current sample, line, band is: 101 71 1 + Current sample, line, band is: 102 71 1 + Current sample, line, band is: 103 71 1 + Current sample, line, band is: 104 71 1 + Current sample, line, band is: 105 71 1 + Current sample, line, band is: 106 71 1 + Current sample, line, band is: 107 71 1 + Current sample, line, band is: 108 71 1 + Current sample, line, band is: 109 71 1 + Current sample, line, band is: 110 71 1 + Current sample, line, band is: 111 71 1 + Current sample, line, band is: 112 71 1 + Current sample, line, band is: 113 71 1 + Current sample, line, band is: 114 71 1 + Current sample, line, band is: 115 71 1 + Current sample, line, band is: 116 71 1 + Current sample, line, band is: 117 71 1 + Current sample, line, band is: 118 71 1 + Current sample, line, band is: 119 71 1 + Current sample, line, band is: 120 71 1 + Current sample, line, band is: 121 71 1 + Current sample, line, band is: 122 71 1 + Current sample, line, band is: 123 71 1 + Current sample, line, band is: 124 71 1 + Current sample, line, band is: 125 71 1 + Current sample, line, band is: 126 71 1 + Current sample, line, band is: 1 72 1 + Current sample, line, band is: 2 72 1 + Current sample, line, band is: 3 72 1 + Current sample, line, band is: 4 72 1 + Current sample, line, band is: 5 72 1 + Current sample, line, band is: 6 72 1 + Current sample, line, band is: 7 72 1 + Current sample, line, band is: 8 72 1 + Current sample, line, band is: 9 72 1 + Current sample, line, band is: 10 72 1 + Current sample, line, band is: 11 72 1 + Current sample, line, band is: 12 72 1 + Current sample, line, band is: 13 72 1 + Current sample, line, band is: 14 72 1 + Current sample, line, band is: 15 72 1 + Current sample, line, band is: 16 72 1 + Current sample, line, band is: 17 72 1 + Current sample, line, band is: 18 72 1 + Current sample, line, band is: 19 72 1 + Current sample, line, band is: 20 72 1 + Current sample, line, band is: 21 72 1 + Current sample, line, band is: 22 72 1 + Current sample, line, band is: 23 72 1 + Current sample, line, band is: 24 72 1 + Current sample, line, band is: 25 72 1 + Current sample, line, band is: 26 72 1 + Current sample, line, band is: 27 72 1 + Current sample, line, band is: 28 72 1 + Current sample, line, band is: 29 72 1 + Current sample, line, band is: 30 72 1 + Current sample, line, band is: 31 72 1 + Current sample, line, band is: 32 72 1 + Current sample, line, band is: 33 72 1 + Current sample, line, band is: 34 72 1 + Current sample, line, band is: 35 72 1 + Current sample, line, band is: 36 72 1 + Current sample, line, band is: 37 72 1 + Current sample, line, band is: 38 72 1 + Current sample, line, band is: 39 72 1 + Current sample, line, band is: 40 72 1 + Current sample, line, band is: 41 72 1 + Current sample, line, band is: 42 72 1 + Current sample, line, band is: 43 72 1 + Current sample, line, band is: 44 72 1 + Current sample, line, band is: 45 72 1 + Current sample, line, band is: 46 72 1 + Current sample, line, band is: 47 72 1 + Current sample, line, band is: 48 72 1 + Current sample, line, band is: 49 72 1 + Current sample, line, band is: 50 72 1 + Current sample, line, band is: 51 72 1 + Current sample, line, band is: 52 72 1 + Current sample, line, band is: 53 72 1 + Current sample, line, band is: 54 72 1 + Current sample, line, band is: 55 72 1 + Current sample, line, band is: 56 72 1 + Current sample, line, band is: 57 72 1 + Current sample, line, band is: 58 72 1 + Current sample, line, band is: 59 72 1 + Current sample, line, band is: 60 72 1 + Current sample, line, band is: 61 72 1 + Current sample, line, band is: 62 72 1 + Current sample, line, band is: 63 72 1 + Current sample, line, band is: 64 72 1 + Current sample, line, band is: 65 72 1 + Current sample, line, band is: 66 72 1 + Current sample, line, band is: 67 72 1 + Current sample, line, band is: 68 72 1 + Current sample, line, band is: 69 72 1 + Current sample, line, band is: 70 72 1 + Current sample, line, band is: 71 72 1 + Current sample, line, band is: 72 72 1 + Current sample, line, band is: 73 72 1 + Current sample, line, band is: 74 72 1 + Current sample, line, band is: 75 72 1 + Current sample, line, band is: 76 72 1 + Current sample, line, band is: 77 72 1 + Current sample, line, band is: 78 72 1 + Current sample, line, band is: 79 72 1 + Current sample, line, band is: 80 72 1 + Current sample, line, band is: 81 72 1 + Current sample, line, band is: 82 72 1 + Current sample, line, band is: 83 72 1 + Current sample, line, band is: 84 72 1 + Current sample, line, band is: 85 72 1 + Current sample, line, band is: 86 72 1 + Current sample, line, band is: 87 72 1 + Current sample, line, band is: 88 72 1 + Current sample, line, band is: 89 72 1 + Current sample, line, band is: 90 72 1 + Current sample, line, band is: 91 72 1 + Current sample, line, band is: 92 72 1 + Current sample, line, band is: 93 72 1 + Current sample, line, band is: 94 72 1 + Current sample, line, band is: 95 72 1 + Current sample, line, band is: 96 72 1 + Current sample, line, band is: 97 72 1 + Current sample, line, band is: 98 72 1 + Current sample, line, band is: 99 72 1 + Current sample, line, band is: 100 72 1 + Current sample, line, band is: 101 72 1 + Current sample, line, band is: 102 72 1 + Current sample, line, band is: 103 72 1 + Current sample, line, band is: 104 72 1 + Current sample, line, band is: 105 72 1 + Current sample, line, band is: 106 72 1 + Current sample, line, band is: 107 72 1 + Current sample, line, band is: 108 72 1 + Current sample, line, band is: 109 72 1 + Current sample, line, band is: 110 72 1 + Current sample, line, band is: 111 72 1 + Current sample, line, band is: 112 72 1 + Current sample, line, band is: 113 72 1 + Current sample, line, band is: 114 72 1 + Current sample, line, band is: 115 72 1 + Current sample, line, band is: 116 72 1 + Current sample, line, band is: 117 72 1 + Current sample, line, band is: 118 72 1 + Current sample, line, band is: 119 72 1 + Current sample, line, band is: 120 72 1 + Current sample, line, band is: 121 72 1 + Current sample, line, band is: 122 72 1 + Current sample, line, band is: 123 72 1 + Current sample, line, band is: 124 72 1 + Current sample, line, band is: 125 72 1 + Current sample, line, band is: 126 72 1 + Current sample, line, band is: 1 73 1 + Current sample, line, band is: 2 73 1 + Current sample, line, band is: 3 73 1 + Current sample, line, band is: 4 73 1 + Current sample, line, band is: 5 73 1 + Current sample, line, band is: 6 73 1 + Current sample, line, band is: 7 73 1 + Current sample, line, band is: 8 73 1 + Current sample, line, band is: 9 73 1 + Current sample, line, band is: 10 73 1 + Current sample, line, band is: 11 73 1 + Current sample, line, band is: 12 73 1 + Current sample, line, band is: 13 73 1 + Current sample, line, band is: 14 73 1 + Current sample, line, band is: 15 73 1 + Current sample, line, band is: 16 73 1 + Current sample, line, band is: 17 73 1 + Current sample, line, band is: 18 73 1 + Current sample, line, band is: 19 73 1 + Current sample, line, band is: 20 73 1 + Current sample, line, band is: 21 73 1 + Current sample, line, band is: 22 73 1 + Current sample, line, band is: 23 73 1 + Current sample, line, band is: 24 73 1 + Current sample, line, band is: 25 73 1 + Current sample, line, band is: 26 73 1 + Current sample, line, band is: 27 73 1 + Current sample, line, band is: 28 73 1 + Current sample, line, band is: 29 73 1 + Current sample, line, band is: 30 73 1 + Current sample, line, band is: 31 73 1 + Current sample, line, band is: 32 73 1 + Current sample, line, band is: 33 73 1 + Current sample, line, band is: 34 73 1 + Current sample, line, band is: 35 73 1 + Current sample, line, band is: 36 73 1 + Current sample, line, band is: 37 73 1 + Current sample, line, band is: 38 73 1 + Current sample, line, band is: 39 73 1 + Current sample, line, band is: 40 73 1 + Current sample, line, band is: 41 73 1 + Current sample, line, band is: 42 73 1 + Current sample, line, band is: 43 73 1 + Current sample, line, band is: 44 73 1 + Current sample, line, band is: 45 73 1 + Current sample, line, band is: 46 73 1 + Current sample, line, band is: 47 73 1 + Current sample, line, band is: 48 73 1 + Current sample, line, band is: 49 73 1 + Current sample, line, band is: 50 73 1 + Current sample, line, band is: 51 73 1 + Current sample, line, band is: 52 73 1 + Current sample, line, band is: 53 73 1 + Current sample, line, band is: 54 73 1 + Current sample, line, band is: 55 73 1 + Current sample, line, band is: 56 73 1 + Current sample, line, band is: 57 73 1 + Current sample, line, band is: 58 73 1 + Current sample, line, band is: 59 73 1 + Current sample, line, band is: 60 73 1 + Current sample, line, band is: 61 73 1 + Current sample, line, band is: 62 73 1 + Current sample, line, band is: 63 73 1 + Current sample, line, band is: 64 73 1 + Current sample, line, band is: 65 73 1 + Current sample, line, band is: 66 73 1 + Current sample, line, band is: 67 73 1 + Current sample, line, band is: 68 73 1 + Current sample, line, band is: 69 73 1 + Current sample, line, band is: 70 73 1 + Current sample, line, band is: 71 73 1 + Current sample, line, band is: 72 73 1 + Current sample, line, band is: 73 73 1 + Current sample, line, band is: 74 73 1 + Current sample, line, band is: 75 73 1 + Current sample, line, band is: 76 73 1 + Current sample, line, band is: 77 73 1 + Current sample, line, band is: 78 73 1 + Current sample, line, band is: 79 73 1 + Current sample, line, band is: 80 73 1 + Current sample, line, band is: 81 73 1 + Current sample, line, band is: 82 73 1 + Current sample, line, band is: 83 73 1 + Current sample, line, band is: 84 73 1 + Current sample, line, band is: 85 73 1 + Current sample, line, band is: 86 73 1 + Current sample, line, band is: 87 73 1 + Current sample, line, band is: 88 73 1 + Current sample, line, band is: 89 73 1 + Current sample, line, band is: 90 73 1 + Current sample, line, band is: 91 73 1 + Current sample, line, band is: 92 73 1 + Current sample, line, band is: 93 73 1 + Current sample, line, band is: 94 73 1 + Current sample, line, band is: 95 73 1 + Current sample, line, band is: 96 73 1 + Current sample, line, band is: 97 73 1 + Current sample, line, band is: 98 73 1 + Current sample, line, band is: 99 73 1 + Current sample, line, band is: 100 73 1 + Current sample, line, band is: 101 73 1 + Current sample, line, band is: 102 73 1 + Current sample, line, band is: 103 73 1 + Current sample, line, band is: 104 73 1 + Current sample, line, band is: 105 73 1 + Current sample, line, band is: 106 73 1 + Current sample, line, band is: 107 73 1 + Current sample, line, band is: 108 73 1 + Current sample, line, band is: 109 73 1 + Current sample, line, band is: 110 73 1 + Current sample, line, band is: 111 73 1 + Current sample, line, band is: 112 73 1 + Current sample, line, band is: 113 73 1 + Current sample, line, band is: 114 73 1 + Current sample, line, band is: 115 73 1 + Current sample, line, band is: 116 73 1 + Current sample, line, band is: 117 73 1 + Current sample, line, band is: 118 73 1 + Current sample, line, band is: 119 73 1 + Current sample, line, band is: 120 73 1 + Current sample, line, band is: 121 73 1 + Current sample, line, band is: 122 73 1 + Current sample, line, band is: 123 73 1 + Current sample, line, band is: 124 73 1 + Current sample, line, band is: 125 73 1 + Current sample, line, band is: 126 73 1 + Current sample, line, band is: 1 74 1 + Current sample, line, band is: 2 74 1 + Current sample, line, band is: 3 74 1 + Current sample, line, band is: 4 74 1 + Current sample, line, band is: 5 74 1 + Current sample, line, band is: 6 74 1 + Current sample, line, band is: 7 74 1 + Current sample, line, band is: 8 74 1 + Current sample, line, band is: 9 74 1 + Current sample, line, band is: 10 74 1 + Current sample, line, band is: 11 74 1 + Current sample, line, band is: 12 74 1 + Current sample, line, band is: 13 74 1 + Current sample, line, band is: 14 74 1 + Current sample, line, band is: 15 74 1 + Current sample, line, band is: 16 74 1 + Current sample, line, band is: 17 74 1 + Current sample, line, band is: 18 74 1 + Current sample, line, band is: 19 74 1 + Current sample, line, band is: 20 74 1 + Current sample, line, band is: 21 74 1 + Current sample, line, band is: 22 74 1 + Current sample, line, band is: 23 74 1 + Current sample, line, band is: 24 74 1 + Current sample, line, band is: 25 74 1 + Current sample, line, band is: 26 74 1 + Current sample, line, band is: 27 74 1 + Current sample, line, band is: 28 74 1 + Current sample, line, band is: 29 74 1 + Current sample, line, band is: 30 74 1 + Current sample, line, band is: 31 74 1 + Current sample, line, band is: 32 74 1 + Current sample, line, band is: 33 74 1 + Current sample, line, band is: 34 74 1 + Current sample, line, band is: 35 74 1 + Current sample, line, band is: 36 74 1 + Current sample, line, band is: 37 74 1 + Current sample, line, band is: 38 74 1 + Current sample, line, band is: 39 74 1 + Current sample, line, band is: 40 74 1 + Current sample, line, band is: 41 74 1 + Current sample, line, band is: 42 74 1 + Current sample, line, band is: 43 74 1 + Current sample, line, band is: 44 74 1 + Current sample, line, band is: 45 74 1 + Current sample, line, band is: 46 74 1 + Current sample, line, band is: 47 74 1 + Current sample, line, band is: 48 74 1 + Current sample, line, band is: 49 74 1 + Current sample, line, band is: 50 74 1 + Current sample, line, band is: 51 74 1 + Current sample, line, band is: 52 74 1 + Current sample, line, band is: 53 74 1 + Current sample, line, band is: 54 74 1 + Current sample, line, band is: 55 74 1 + Current sample, line, band is: 56 74 1 + Current sample, line, band is: 57 74 1 + Current sample, line, band is: 58 74 1 + Current sample, line, band is: 59 74 1 + Current sample, line, band is: 60 74 1 + Current sample, line, band is: 61 74 1 + Current sample, line, band is: 62 74 1 + Current sample, line, band is: 63 74 1 + Current sample, line, band is: 64 74 1 + Current sample, line, band is: 65 74 1 + Current sample, line, band is: 66 74 1 + Current sample, line, band is: 67 74 1 + Current sample, line, band is: 68 74 1 + Current sample, line, band is: 69 74 1 + Current sample, line, band is: 70 74 1 + Current sample, line, band is: 71 74 1 + Current sample, line, band is: 72 74 1 + Current sample, line, band is: 73 74 1 + Current sample, line, band is: 74 74 1 + Current sample, line, band is: 75 74 1 + Current sample, line, band is: 76 74 1 + Current sample, line, band is: 77 74 1 + Current sample, line, band is: 78 74 1 + Current sample, line, band is: 79 74 1 + Current sample, line, band is: 80 74 1 + Current sample, line, band is: 81 74 1 + Current sample, line, band is: 82 74 1 + Current sample, line, band is: 83 74 1 + Current sample, line, band is: 84 74 1 + Current sample, line, band is: 85 74 1 + Current sample, line, band is: 86 74 1 + Current sample, line, band is: 87 74 1 + Current sample, line, band is: 88 74 1 + Current sample, line, band is: 89 74 1 + Current sample, line, band is: 90 74 1 + Current sample, line, band is: 91 74 1 + Current sample, line, band is: 92 74 1 + Current sample, line, band is: 93 74 1 + Current sample, line, band is: 94 74 1 + Current sample, line, band is: 95 74 1 + Current sample, line, band is: 96 74 1 + Current sample, line, band is: 97 74 1 + Current sample, line, band is: 98 74 1 + Current sample, line, band is: 99 74 1 + Current sample, line, band is: 100 74 1 + Current sample, line, band is: 101 74 1 + Current sample, line, band is: 102 74 1 + Current sample, line, band is: 103 74 1 + Current sample, line, band is: 104 74 1 + Current sample, line, band is: 105 74 1 + Current sample, line, band is: 106 74 1 + Current sample, line, band is: 107 74 1 + Current sample, line, band is: 108 74 1 + Current sample, line, band is: 109 74 1 + Current sample, line, band is: 110 74 1 + Current sample, line, band is: 111 74 1 + Current sample, line, band is: 112 74 1 + Current sample, line, band is: 113 74 1 + Current sample, line, band is: 114 74 1 + Current sample, line, band is: 115 74 1 + Current sample, line, band is: 116 74 1 + Current sample, line, band is: 117 74 1 + Current sample, line, band is: 118 74 1 + Current sample, line, band is: 119 74 1 + Current sample, line, band is: 120 74 1 + Current sample, line, band is: 121 74 1 + Current sample, line, band is: 122 74 1 + Current sample, line, band is: 123 74 1 + Current sample, line, band is: 124 74 1 + Current sample, line, band is: 125 74 1 + Current sample, line, band is: 126 74 1 + Current sample, line, band is: 1 75 1 + Current sample, line, band is: 2 75 1 + Current sample, line, band is: 3 75 1 + Current sample, line, band is: 4 75 1 + Current sample, line, band is: 5 75 1 + Current sample, line, band is: 6 75 1 + Current sample, line, band is: 7 75 1 + Current sample, line, band is: 8 75 1 + Current sample, line, band is: 9 75 1 + Current sample, line, band is: 10 75 1 + Current sample, line, band is: 11 75 1 + Current sample, line, band is: 12 75 1 + Current sample, line, band is: 13 75 1 + Current sample, line, band is: 14 75 1 + Current sample, line, band is: 15 75 1 + Current sample, line, band is: 16 75 1 + Current sample, line, band is: 17 75 1 + Current sample, line, band is: 18 75 1 + Current sample, line, band is: 19 75 1 + Current sample, line, band is: 20 75 1 + Current sample, line, band is: 21 75 1 + Current sample, line, band is: 22 75 1 + Current sample, line, band is: 23 75 1 + Current sample, line, band is: 24 75 1 + Current sample, line, band is: 25 75 1 + Current sample, line, band is: 26 75 1 + Current sample, line, band is: 27 75 1 + Current sample, line, band is: 28 75 1 + Current sample, line, band is: 29 75 1 + Current sample, line, band is: 30 75 1 + Current sample, line, band is: 31 75 1 + Current sample, line, band is: 32 75 1 + Current sample, line, band is: 33 75 1 + Current sample, line, band is: 34 75 1 + Current sample, line, band is: 35 75 1 + Current sample, line, band is: 36 75 1 + Current sample, line, band is: 37 75 1 + Current sample, line, band is: 38 75 1 + Current sample, line, band is: 39 75 1 + Current sample, line, band is: 40 75 1 + Current sample, line, band is: 41 75 1 + Current sample, line, band is: 42 75 1 + Current sample, line, band is: 43 75 1 + Current sample, line, band is: 44 75 1 + Current sample, line, band is: 45 75 1 + Current sample, line, band is: 46 75 1 + Current sample, line, band is: 47 75 1 + Current sample, line, band is: 48 75 1 + Current sample, line, band is: 49 75 1 + Current sample, line, band is: 50 75 1 + Current sample, line, band is: 51 75 1 + Current sample, line, band is: 52 75 1 + Current sample, line, band is: 53 75 1 + Current sample, line, band is: 54 75 1 + Current sample, line, band is: 55 75 1 + Current sample, line, band is: 56 75 1 + Current sample, line, band is: 57 75 1 + Current sample, line, band is: 58 75 1 + Current sample, line, band is: 59 75 1 + Current sample, line, band is: 60 75 1 + Current sample, line, band is: 61 75 1 + Current sample, line, band is: 62 75 1 + Current sample, line, band is: 63 75 1 + Current sample, line, band is: 64 75 1 + Current sample, line, band is: 65 75 1 + Current sample, line, band is: 66 75 1 + Current sample, line, band is: 67 75 1 + Current sample, line, band is: 68 75 1 + Current sample, line, band is: 69 75 1 + Current sample, line, band is: 70 75 1 + Current sample, line, band is: 71 75 1 + Current sample, line, band is: 72 75 1 + Current sample, line, band is: 73 75 1 + Current sample, line, band is: 74 75 1 + Current sample, line, band is: 75 75 1 + Current sample, line, band is: 76 75 1 + Current sample, line, band is: 77 75 1 + Current sample, line, band is: 78 75 1 + Current sample, line, band is: 79 75 1 + Current sample, line, band is: 80 75 1 + Current sample, line, band is: 81 75 1 + Current sample, line, band is: 82 75 1 + Current sample, line, band is: 83 75 1 + Current sample, line, band is: 84 75 1 + Current sample, line, band is: 85 75 1 + Current sample, line, band is: 86 75 1 + Current sample, line, band is: 87 75 1 + Current sample, line, band is: 88 75 1 + Current sample, line, band is: 89 75 1 + Current sample, line, band is: 90 75 1 + Current sample, line, band is: 91 75 1 + Current sample, line, band is: 92 75 1 + Current sample, line, band is: 93 75 1 + Current sample, line, band is: 94 75 1 + Current sample, line, band is: 95 75 1 + Current sample, line, band is: 96 75 1 + Current sample, line, band is: 97 75 1 + Current sample, line, band is: 98 75 1 + Current sample, line, band is: 99 75 1 + Current sample, line, band is: 100 75 1 + Current sample, line, band is: 101 75 1 + Current sample, line, band is: 102 75 1 + Current sample, line, band is: 103 75 1 + Current sample, line, band is: 104 75 1 + Current sample, line, band is: 105 75 1 + Current sample, line, band is: 106 75 1 + Current sample, line, band is: 107 75 1 + Current sample, line, band is: 108 75 1 + Current sample, line, band is: 109 75 1 + Current sample, line, band is: 110 75 1 + Current sample, line, band is: 111 75 1 + Current sample, line, band is: 112 75 1 + Current sample, line, band is: 113 75 1 + Current sample, line, band is: 114 75 1 + Current sample, line, band is: 115 75 1 + Current sample, line, band is: 116 75 1 + Current sample, line, band is: 117 75 1 + Current sample, line, band is: 118 75 1 + Current sample, line, band is: 119 75 1 + Current sample, line, band is: 120 75 1 + Current sample, line, band is: 121 75 1 + Current sample, line, band is: 122 75 1 + Current sample, line, band is: 123 75 1 + Current sample, line, band is: 124 75 1 + Current sample, line, band is: 125 75 1 + Current sample, line, band is: 126 75 1 + Current sample, line, band is: 1 76 1 + Current sample, line, band is: 2 76 1 + Current sample, line, band is: 3 76 1 + Current sample, line, band is: 4 76 1 + Current sample, line, band is: 5 76 1 + Current sample, line, band is: 6 76 1 + Current sample, line, band is: 7 76 1 + Current sample, line, band is: 8 76 1 + Current sample, line, band is: 9 76 1 + Current sample, line, band is: 10 76 1 + Current sample, line, band is: 11 76 1 + Current sample, line, band is: 12 76 1 + Current sample, line, band is: 13 76 1 + Current sample, line, band is: 14 76 1 + Current sample, line, band is: 15 76 1 + Current sample, line, band is: 16 76 1 + Current sample, line, band is: 17 76 1 + Current sample, line, band is: 18 76 1 + Current sample, line, band is: 19 76 1 + Current sample, line, band is: 20 76 1 + Current sample, line, band is: 21 76 1 + Current sample, line, band is: 22 76 1 + Current sample, line, band is: 23 76 1 + Current sample, line, band is: 24 76 1 + Current sample, line, band is: 25 76 1 + Current sample, line, band is: 26 76 1 + Current sample, line, band is: 27 76 1 + Current sample, line, band is: 28 76 1 + Current sample, line, band is: 29 76 1 + Current sample, line, band is: 30 76 1 + Current sample, line, band is: 31 76 1 + Current sample, line, band is: 32 76 1 + Current sample, line, band is: 33 76 1 + Current sample, line, band is: 34 76 1 + Current sample, line, band is: 35 76 1 + Current sample, line, band is: 36 76 1 + Current sample, line, band is: 37 76 1 + Current sample, line, band is: 38 76 1 + Current sample, line, band is: 39 76 1 + Current sample, line, band is: 40 76 1 + Current sample, line, band is: 41 76 1 + Current sample, line, band is: 42 76 1 + Current sample, line, band is: 43 76 1 + Current sample, line, band is: 44 76 1 + Current sample, line, band is: 45 76 1 + Current sample, line, band is: 46 76 1 + Current sample, line, band is: 47 76 1 + Current sample, line, band is: 48 76 1 + Current sample, line, band is: 49 76 1 + Current sample, line, band is: 50 76 1 + Current sample, line, band is: 51 76 1 + Current sample, line, band is: 52 76 1 + Current sample, line, band is: 53 76 1 + Current sample, line, band is: 54 76 1 + Current sample, line, band is: 55 76 1 + Current sample, line, band is: 56 76 1 + Current sample, line, band is: 57 76 1 + Current sample, line, band is: 58 76 1 + Current sample, line, band is: 59 76 1 + Current sample, line, band is: 60 76 1 + Current sample, line, band is: 61 76 1 + Current sample, line, band is: 62 76 1 + Current sample, line, band is: 63 76 1 + Current sample, line, band is: 64 76 1 + Current sample, line, band is: 65 76 1 + Current sample, line, band is: 66 76 1 + Current sample, line, band is: 67 76 1 + Current sample, line, band is: 68 76 1 + Current sample, line, band is: 69 76 1 + Current sample, line, band is: 70 76 1 + Current sample, line, band is: 71 76 1 + Current sample, line, band is: 72 76 1 + Current sample, line, band is: 73 76 1 + Current sample, line, band is: 74 76 1 + Current sample, line, band is: 75 76 1 + Current sample, line, band is: 76 76 1 + Current sample, line, band is: 77 76 1 + Current sample, line, band is: 78 76 1 + Current sample, line, band is: 79 76 1 + Current sample, line, band is: 80 76 1 + Current sample, line, band is: 81 76 1 + Current sample, line, band is: 82 76 1 + Current sample, line, band is: 83 76 1 + Current sample, line, band is: 84 76 1 + Current sample, line, band is: 85 76 1 + Current sample, line, band is: 86 76 1 + Current sample, line, band is: 87 76 1 + Current sample, line, band is: 88 76 1 + Current sample, line, band is: 89 76 1 + Current sample, line, band is: 90 76 1 + Current sample, line, band is: 91 76 1 + Current sample, line, band is: 92 76 1 + Current sample, line, band is: 93 76 1 + Current sample, line, band is: 94 76 1 + Current sample, line, band is: 95 76 1 + Current sample, line, band is: 96 76 1 + Current sample, line, band is: 97 76 1 + Current sample, line, band is: 98 76 1 + Current sample, line, band is: 99 76 1 + Current sample, line, band is: 100 76 1 + Current sample, line, band is: 101 76 1 + Current sample, line, band is: 102 76 1 + Current sample, line, band is: 103 76 1 + Current sample, line, band is: 104 76 1 + Current sample, line, band is: 105 76 1 + Current sample, line, band is: 106 76 1 + Current sample, line, band is: 107 76 1 + Current sample, line, band is: 108 76 1 + Current sample, line, band is: 109 76 1 + Current sample, line, band is: 110 76 1 + Current sample, line, band is: 111 76 1 + Current sample, line, band is: 112 76 1 + Current sample, line, band is: 113 76 1 + Current sample, line, band is: 114 76 1 + Current sample, line, band is: 115 76 1 + Current sample, line, band is: 116 76 1 + Current sample, line, band is: 117 76 1 + Current sample, line, band is: 118 76 1 + Current sample, line, band is: 119 76 1 + Current sample, line, band is: 120 76 1 + Current sample, line, band is: 121 76 1 + Current sample, line, band is: 122 76 1 + Current sample, line, band is: 123 76 1 + Current sample, line, band is: 124 76 1 + Current sample, line, band is: 125 76 1 + Current sample, line, band is: 126 76 1 + Current sample, line, band is: 1 77 1 + Current sample, line, band is: 2 77 1 + Current sample, line, band is: 3 77 1 + Current sample, line, band is: 4 77 1 + Current sample, line, band is: 5 77 1 + Current sample, line, band is: 6 77 1 + Current sample, line, band is: 7 77 1 + Current sample, line, band is: 8 77 1 + Current sample, line, band is: 9 77 1 + Current sample, line, band is: 10 77 1 + Current sample, line, band is: 11 77 1 + Current sample, line, band is: 12 77 1 + Current sample, line, band is: 13 77 1 + Current sample, line, band is: 14 77 1 + Current sample, line, band is: 15 77 1 + Current sample, line, band is: 16 77 1 + Current sample, line, band is: 17 77 1 + Current sample, line, band is: 18 77 1 + Current sample, line, band is: 19 77 1 + Current sample, line, band is: 20 77 1 + Current sample, line, band is: 21 77 1 + Current sample, line, band is: 22 77 1 + Current sample, line, band is: 23 77 1 + Current sample, line, band is: 24 77 1 + Current sample, line, band is: 25 77 1 + Current sample, line, band is: 26 77 1 + Current sample, line, band is: 27 77 1 + Current sample, line, band is: 28 77 1 + Current sample, line, band is: 29 77 1 + Current sample, line, band is: 30 77 1 + Current sample, line, band is: 31 77 1 + Current sample, line, band is: 32 77 1 + Current sample, line, band is: 33 77 1 + Current sample, line, band is: 34 77 1 + Current sample, line, band is: 35 77 1 + Current sample, line, band is: 36 77 1 + Current sample, line, band is: 37 77 1 + Current sample, line, band is: 38 77 1 + Current sample, line, band is: 39 77 1 + Current sample, line, band is: 40 77 1 + Current sample, line, band is: 41 77 1 + Current sample, line, band is: 42 77 1 + Current sample, line, band is: 43 77 1 + Current sample, line, band is: 44 77 1 + Current sample, line, band is: 45 77 1 + Current sample, line, band is: 46 77 1 + Current sample, line, band is: 47 77 1 + Current sample, line, band is: 48 77 1 + Current sample, line, band is: 49 77 1 + Current sample, line, band is: 50 77 1 + Current sample, line, band is: 51 77 1 + Current sample, line, band is: 52 77 1 + Current sample, line, band is: 53 77 1 + Current sample, line, band is: 54 77 1 + Current sample, line, band is: 55 77 1 + Current sample, line, band is: 56 77 1 + Current sample, line, band is: 57 77 1 + Current sample, line, band is: 58 77 1 + Current sample, line, band is: 59 77 1 + Current sample, line, band is: 60 77 1 + Current sample, line, band is: 61 77 1 + Current sample, line, band is: 62 77 1 + Current sample, line, band is: 63 77 1 + Current sample, line, band is: 64 77 1 + Current sample, line, band is: 65 77 1 + Current sample, line, band is: 66 77 1 + Current sample, line, band is: 67 77 1 + Current sample, line, band is: 68 77 1 + Current sample, line, band is: 69 77 1 + Current sample, line, band is: 70 77 1 + Current sample, line, band is: 71 77 1 + Current sample, line, band is: 72 77 1 + Current sample, line, band is: 73 77 1 + Current sample, line, band is: 74 77 1 + Current sample, line, band is: 75 77 1 + Current sample, line, band is: 76 77 1 + Current sample, line, band is: 77 77 1 + Current sample, line, band is: 78 77 1 + Current sample, line, band is: 79 77 1 + Current sample, line, band is: 80 77 1 + Current sample, line, band is: 81 77 1 + Current sample, line, band is: 82 77 1 + Current sample, line, band is: 83 77 1 + Current sample, line, band is: 84 77 1 + Current sample, line, band is: 85 77 1 + Current sample, line, band is: 86 77 1 + Current sample, line, band is: 87 77 1 + Current sample, line, band is: 88 77 1 + Current sample, line, band is: 89 77 1 + Current sample, line, band is: 90 77 1 + Current sample, line, band is: 91 77 1 + Current sample, line, band is: 92 77 1 + Current sample, line, band is: 93 77 1 + Current sample, line, band is: 94 77 1 + Current sample, line, band is: 95 77 1 + Current sample, line, band is: 96 77 1 + Current sample, line, band is: 97 77 1 + Current sample, line, band is: 98 77 1 + Current sample, line, band is: 99 77 1 + Current sample, line, band is: 100 77 1 + Current sample, line, band is: 101 77 1 + Current sample, line, band is: 102 77 1 + Current sample, line, band is: 103 77 1 + Current sample, line, band is: 104 77 1 + Current sample, line, band is: 105 77 1 + Current sample, line, band is: 106 77 1 + Current sample, line, band is: 107 77 1 + Current sample, line, band is: 108 77 1 + Current sample, line, band is: 109 77 1 + Current sample, line, band is: 110 77 1 + Current sample, line, band is: 111 77 1 + Current sample, line, band is: 112 77 1 + Current sample, line, band is: 113 77 1 + Current sample, line, band is: 114 77 1 + Current sample, line, band is: 115 77 1 + Current sample, line, band is: 116 77 1 + Current sample, line, band is: 117 77 1 + Current sample, line, band is: 118 77 1 + Current sample, line, band is: 119 77 1 + Current sample, line, band is: 120 77 1 + Current sample, line, band is: 121 77 1 + Current sample, line, band is: 122 77 1 + Current sample, line, band is: 123 77 1 + Current sample, line, band is: 124 77 1 + Current sample, line, band is: 125 77 1 + Current sample, line, band is: 126 77 1 + Current sample, line, band is: 1 78 1 + Current sample, line, band is: 2 78 1 + Current sample, line, band is: 3 78 1 + Current sample, line, band is: 4 78 1 + Current sample, line, band is: 5 78 1 + Current sample, line, band is: 6 78 1 + Current sample, line, band is: 7 78 1 + Current sample, line, band is: 8 78 1 + Current sample, line, band is: 9 78 1 + Current sample, line, band is: 10 78 1 + Current sample, line, band is: 11 78 1 + Current sample, line, band is: 12 78 1 + Current sample, line, band is: 13 78 1 + Current sample, line, band is: 14 78 1 + Current sample, line, band is: 15 78 1 + Current sample, line, band is: 16 78 1 + Current sample, line, band is: 17 78 1 + Current sample, line, band is: 18 78 1 + Current sample, line, band is: 19 78 1 + Current sample, line, band is: 20 78 1 + Current sample, line, band is: 21 78 1 + Current sample, line, band is: 22 78 1 + Current sample, line, band is: 23 78 1 + Current sample, line, band is: 24 78 1 + Current sample, line, band is: 25 78 1 + Current sample, line, band is: 26 78 1 + Current sample, line, band is: 27 78 1 + Current sample, line, band is: 28 78 1 + Current sample, line, band is: 29 78 1 + Current sample, line, band is: 30 78 1 + Current sample, line, band is: 31 78 1 + Current sample, line, band is: 32 78 1 + Current sample, line, band is: 33 78 1 + Current sample, line, band is: 34 78 1 + Current sample, line, band is: 35 78 1 + Current sample, line, band is: 36 78 1 + Current sample, line, band is: 37 78 1 + Current sample, line, band is: 38 78 1 + Current sample, line, band is: 39 78 1 + Current sample, line, band is: 40 78 1 + Current sample, line, band is: 41 78 1 + Current sample, line, band is: 42 78 1 + Current sample, line, band is: 43 78 1 + Current sample, line, band is: 44 78 1 + Current sample, line, band is: 45 78 1 + Current sample, line, band is: 46 78 1 + Current sample, line, band is: 47 78 1 + Current sample, line, band is: 48 78 1 + Current sample, line, band is: 49 78 1 + Current sample, line, band is: 50 78 1 + Current sample, line, band is: 51 78 1 + Current sample, line, band is: 52 78 1 + Current sample, line, band is: 53 78 1 + Current sample, line, band is: 54 78 1 + Current sample, line, band is: 55 78 1 + Current sample, line, band is: 56 78 1 + Current sample, line, band is: 57 78 1 + Current sample, line, band is: 58 78 1 + Current sample, line, band is: 59 78 1 + Current sample, line, band is: 60 78 1 + Current sample, line, band is: 61 78 1 + Current sample, line, band is: 62 78 1 + Current sample, line, band is: 63 78 1 + Current sample, line, band is: 64 78 1 + Current sample, line, band is: 65 78 1 + Current sample, line, band is: 66 78 1 + Current sample, line, band is: 67 78 1 + Current sample, line, band is: 68 78 1 + Current sample, line, band is: 69 78 1 + Current sample, line, band is: 70 78 1 + Current sample, line, band is: 71 78 1 + Current sample, line, band is: 72 78 1 + Current sample, line, band is: 73 78 1 + Current sample, line, band is: 74 78 1 + Current sample, line, band is: 75 78 1 + Current sample, line, band is: 76 78 1 + Current sample, line, band is: 77 78 1 + Current sample, line, band is: 78 78 1 + Current sample, line, band is: 79 78 1 + Current sample, line, band is: 80 78 1 + Current sample, line, band is: 81 78 1 + Current sample, line, band is: 82 78 1 + Current sample, line, band is: 83 78 1 + Current sample, line, band is: 84 78 1 + Current sample, line, band is: 85 78 1 + Current sample, line, band is: 86 78 1 + Current sample, line, band is: 87 78 1 + Current sample, line, band is: 88 78 1 + Current sample, line, band is: 89 78 1 + Current sample, line, band is: 90 78 1 + Current sample, line, band is: 91 78 1 + Current sample, line, band is: 92 78 1 + Current sample, line, band is: 93 78 1 + Current sample, line, band is: 94 78 1 + Current sample, line, band is: 95 78 1 + Current sample, line, band is: 96 78 1 + Current sample, line, band is: 97 78 1 + Current sample, line, band is: 98 78 1 + Current sample, line, band is: 99 78 1 + Current sample, line, band is: 100 78 1 + Current sample, line, band is: 101 78 1 + Current sample, line, band is: 102 78 1 + Current sample, line, band is: 103 78 1 + Current sample, line, band is: 104 78 1 + Current sample, line, band is: 105 78 1 + Current sample, line, band is: 106 78 1 + Current sample, line, band is: 107 78 1 + Current sample, line, band is: 108 78 1 + Current sample, line, band is: 109 78 1 + Current sample, line, band is: 110 78 1 + Current sample, line, band is: 111 78 1 + Current sample, line, band is: 112 78 1 + Current sample, line, band is: 113 78 1 + Current sample, line, band is: 114 78 1 + Current sample, line, band is: 115 78 1 + Current sample, line, band is: 116 78 1 + Current sample, line, band is: 117 78 1 + Current sample, line, band is: 118 78 1 + Current sample, line, band is: 119 78 1 + Current sample, line, band is: 120 78 1 + Current sample, line, band is: 121 78 1 + Current sample, line, band is: 122 78 1 + Current sample, line, band is: 123 78 1 + Current sample, line, band is: 124 78 1 + Current sample, line, band is: 125 78 1 + Current sample, line, band is: 126 78 1 + Current sample, line, band is: 1 79 1 + Current sample, line, band is: 2 79 1 + Current sample, line, band is: 3 79 1 + Current sample, line, band is: 4 79 1 + Current sample, line, band is: 5 79 1 + Current sample, line, band is: 6 79 1 + Current sample, line, band is: 7 79 1 + Current sample, line, band is: 8 79 1 + Current sample, line, band is: 9 79 1 + Current sample, line, band is: 10 79 1 + Current sample, line, band is: 11 79 1 + Current sample, line, band is: 12 79 1 + Current sample, line, band is: 13 79 1 + Current sample, line, band is: 14 79 1 + Current sample, line, band is: 15 79 1 + Current sample, line, band is: 16 79 1 + Current sample, line, band is: 17 79 1 + Current sample, line, band is: 18 79 1 + Current sample, line, band is: 19 79 1 + Current sample, line, band is: 20 79 1 + Current sample, line, band is: 21 79 1 + Current sample, line, band is: 22 79 1 + Current sample, line, band is: 23 79 1 + Current sample, line, band is: 24 79 1 + Current sample, line, band is: 25 79 1 + Current sample, line, band is: 26 79 1 + Current sample, line, band is: 27 79 1 + Current sample, line, band is: 28 79 1 + Current sample, line, band is: 29 79 1 + Current sample, line, band is: 30 79 1 + Current sample, line, band is: 31 79 1 + Current sample, line, band is: 32 79 1 + Current sample, line, band is: 33 79 1 + Current sample, line, band is: 34 79 1 + Current sample, line, band is: 35 79 1 + Current sample, line, band is: 36 79 1 + Current sample, line, band is: 37 79 1 + Current sample, line, band is: 38 79 1 + Current sample, line, band is: 39 79 1 + Current sample, line, band is: 40 79 1 + Current sample, line, band is: 41 79 1 + Current sample, line, band is: 42 79 1 + Current sample, line, band is: 43 79 1 + Current sample, line, band is: 44 79 1 + Current sample, line, band is: 45 79 1 + Current sample, line, band is: 46 79 1 + Current sample, line, band is: 47 79 1 + Current sample, line, band is: 48 79 1 + Current sample, line, band is: 49 79 1 + Current sample, line, band is: 50 79 1 + Current sample, line, band is: 51 79 1 + Current sample, line, band is: 52 79 1 + Current sample, line, band is: 53 79 1 + Current sample, line, band is: 54 79 1 + Current sample, line, band is: 55 79 1 + Current sample, line, band is: 56 79 1 + Current sample, line, band is: 57 79 1 + Current sample, line, band is: 58 79 1 + Current sample, line, band is: 59 79 1 + Current sample, line, band is: 60 79 1 + Current sample, line, band is: 61 79 1 + Current sample, line, band is: 62 79 1 + Current sample, line, band is: 63 79 1 + Current sample, line, band is: 64 79 1 + Current sample, line, band is: 65 79 1 + Current sample, line, band is: 66 79 1 + Current sample, line, band is: 67 79 1 + Current sample, line, band is: 68 79 1 + Current sample, line, band is: 69 79 1 + Current sample, line, band is: 70 79 1 + Current sample, line, band is: 71 79 1 + Current sample, line, band is: 72 79 1 + Current sample, line, band is: 73 79 1 + Current sample, line, band is: 74 79 1 + Current sample, line, band is: 75 79 1 + Current sample, line, band is: 76 79 1 + Current sample, line, band is: 77 79 1 + Current sample, line, band is: 78 79 1 + Current sample, line, band is: 79 79 1 + Current sample, line, band is: 80 79 1 + Current sample, line, band is: 81 79 1 + Current sample, line, band is: 82 79 1 + Current sample, line, band is: 83 79 1 + Current sample, line, band is: 84 79 1 + Current sample, line, band is: 85 79 1 + Current sample, line, band is: 86 79 1 + Current sample, line, band is: 87 79 1 + Current sample, line, band is: 88 79 1 + Current sample, line, band is: 89 79 1 + Current sample, line, band is: 90 79 1 + Current sample, line, band is: 91 79 1 + Current sample, line, band is: 92 79 1 + Current sample, line, band is: 93 79 1 + Current sample, line, band is: 94 79 1 + Current sample, line, band is: 95 79 1 + Current sample, line, band is: 96 79 1 + Current sample, line, band is: 97 79 1 + Current sample, line, band is: 98 79 1 + Current sample, line, band is: 99 79 1 + Current sample, line, band is: 100 79 1 + Current sample, line, band is: 101 79 1 + Current sample, line, band is: 102 79 1 + Current sample, line, band is: 103 79 1 + Current sample, line, band is: 104 79 1 + Current sample, line, band is: 105 79 1 + Current sample, line, band is: 106 79 1 + Current sample, line, band is: 107 79 1 + Current sample, line, band is: 108 79 1 + Current sample, line, band is: 109 79 1 + Current sample, line, band is: 110 79 1 + Current sample, line, band is: 111 79 1 + Current sample, line, band is: 112 79 1 + Current sample, line, band is: 113 79 1 + Current sample, line, band is: 114 79 1 + Current sample, line, band is: 115 79 1 + Current sample, line, band is: 116 79 1 + Current sample, line, band is: 117 79 1 + Current sample, line, band is: 118 79 1 + Current sample, line, band is: 119 79 1 + Current sample, line, band is: 120 79 1 + Current sample, line, band is: 121 79 1 + Current sample, line, band is: 122 79 1 + Current sample, line, band is: 123 79 1 + Current sample, line, band is: 124 79 1 + Current sample, line, band is: 125 79 1 + Current sample, line, band is: 126 79 1 + Current sample, line, band is: 1 80 1 + Current sample, line, band is: 2 80 1 + Current sample, line, band is: 3 80 1 + Current sample, line, band is: 4 80 1 + Current sample, line, band is: 5 80 1 + Current sample, line, band is: 6 80 1 + Current sample, line, band is: 7 80 1 + Current sample, line, band is: 8 80 1 + Current sample, line, band is: 9 80 1 + Current sample, line, band is: 10 80 1 + Current sample, line, band is: 11 80 1 + Current sample, line, band is: 12 80 1 + Current sample, line, band is: 13 80 1 + Current sample, line, band is: 14 80 1 + Current sample, line, band is: 15 80 1 + Current sample, line, band is: 16 80 1 + Current sample, line, band is: 17 80 1 + Current sample, line, band is: 18 80 1 + Current sample, line, band is: 19 80 1 + Current sample, line, band is: 20 80 1 + Current sample, line, band is: 21 80 1 + Current sample, line, band is: 22 80 1 + Current sample, line, band is: 23 80 1 + Current sample, line, band is: 24 80 1 + Current sample, line, band is: 25 80 1 + Current sample, line, band is: 26 80 1 + Current sample, line, band is: 27 80 1 + Current sample, line, band is: 28 80 1 + Current sample, line, band is: 29 80 1 + Current sample, line, band is: 30 80 1 + Current sample, line, band is: 31 80 1 + Current sample, line, band is: 32 80 1 + Current sample, line, band is: 33 80 1 + Current sample, line, band is: 34 80 1 + Current sample, line, band is: 35 80 1 + Current sample, line, band is: 36 80 1 + Current sample, line, band is: 37 80 1 + Current sample, line, band is: 38 80 1 + Current sample, line, band is: 39 80 1 + Current sample, line, band is: 40 80 1 + Current sample, line, band is: 41 80 1 + Current sample, line, band is: 42 80 1 + Current sample, line, band is: 43 80 1 + Current sample, line, band is: 44 80 1 + Current sample, line, band is: 45 80 1 + Current sample, line, band is: 46 80 1 + Current sample, line, band is: 47 80 1 + Current sample, line, band is: 48 80 1 + Current sample, line, band is: 49 80 1 + Current sample, line, band is: 50 80 1 + Current sample, line, band is: 51 80 1 + Current sample, line, band is: 52 80 1 + Current sample, line, band is: 53 80 1 + Current sample, line, band is: 54 80 1 + Current sample, line, band is: 55 80 1 + Current sample, line, band is: 56 80 1 + Current sample, line, band is: 57 80 1 + Current sample, line, band is: 58 80 1 + Current sample, line, band is: 59 80 1 + Current sample, line, band is: 60 80 1 + Current sample, line, band is: 61 80 1 + Current sample, line, band is: 62 80 1 + Current sample, line, band is: 63 80 1 + Current sample, line, band is: 64 80 1 + Current sample, line, band is: 65 80 1 + Current sample, line, band is: 66 80 1 + Current sample, line, band is: 67 80 1 + Current sample, line, band is: 68 80 1 + Current sample, line, band is: 69 80 1 + Current sample, line, band is: 70 80 1 + Current sample, line, band is: 71 80 1 + Current sample, line, band is: 72 80 1 + Current sample, line, band is: 73 80 1 + Current sample, line, band is: 74 80 1 + Current sample, line, band is: 75 80 1 + Current sample, line, band is: 76 80 1 + Current sample, line, band is: 77 80 1 + Current sample, line, band is: 78 80 1 + Current sample, line, band is: 79 80 1 + Current sample, line, band is: 80 80 1 + Current sample, line, band is: 81 80 1 + Current sample, line, band is: 82 80 1 + Current sample, line, band is: 83 80 1 + Current sample, line, band is: 84 80 1 + Current sample, line, band is: 85 80 1 + Current sample, line, band is: 86 80 1 + Current sample, line, band is: 87 80 1 + Current sample, line, band is: 88 80 1 + Current sample, line, band is: 89 80 1 + Current sample, line, band is: 90 80 1 + Current sample, line, band is: 91 80 1 + Current sample, line, band is: 92 80 1 + Current sample, line, band is: 93 80 1 + Current sample, line, band is: 94 80 1 + Current sample, line, band is: 95 80 1 + Current sample, line, band is: 96 80 1 + Current sample, line, band is: 97 80 1 + Current sample, line, band is: 98 80 1 + Current sample, line, band is: 99 80 1 + Current sample, line, band is: 100 80 1 + Current sample, line, band is: 101 80 1 + Current sample, line, band is: 102 80 1 + Current sample, line, band is: 103 80 1 + Current sample, line, band is: 104 80 1 + Current sample, line, band is: 105 80 1 + Current sample, line, band is: 106 80 1 + Current sample, line, band is: 107 80 1 + Current sample, line, band is: 108 80 1 + Current sample, line, band is: 109 80 1 + Current sample, line, band is: 110 80 1 + Current sample, line, band is: 111 80 1 + Current sample, line, band is: 112 80 1 + Current sample, line, band is: 113 80 1 + Current sample, line, band is: 114 80 1 + Current sample, line, band is: 115 80 1 + Current sample, line, band is: 116 80 1 + Current sample, line, band is: 117 80 1 + Current sample, line, band is: 118 80 1 + Current sample, line, band is: 119 80 1 + Current sample, line, band is: 120 80 1 + Current sample, line, band is: 121 80 1 + Current sample, line, band is: 122 80 1 + Current sample, line, band is: 123 80 1 + Current sample, line, band is: 124 80 1 + Current sample, line, band is: 125 80 1 + Current sample, line, band is: 126 80 1 + Current sample, line, band is: 1 81 1 + Current sample, line, band is: 2 81 1 + Current sample, line, band is: 3 81 1 + Current sample, line, band is: 4 81 1 + Current sample, line, band is: 5 81 1 + Current sample, line, band is: 6 81 1 + Current sample, line, band is: 7 81 1 + Current sample, line, band is: 8 81 1 + Current sample, line, band is: 9 81 1 + Current sample, line, band is: 10 81 1 + Current sample, line, band is: 11 81 1 + Current sample, line, band is: 12 81 1 + Current sample, line, band is: 13 81 1 + Current sample, line, band is: 14 81 1 + Current sample, line, band is: 15 81 1 + Current sample, line, band is: 16 81 1 + Current sample, line, band is: 17 81 1 + Current sample, line, band is: 18 81 1 + Current sample, line, band is: 19 81 1 + Current sample, line, band is: 20 81 1 + Current sample, line, band is: 21 81 1 + Current sample, line, band is: 22 81 1 + Current sample, line, band is: 23 81 1 + Current sample, line, band is: 24 81 1 + Current sample, line, band is: 25 81 1 + Current sample, line, band is: 26 81 1 + Current sample, line, band is: 27 81 1 + Current sample, line, band is: 28 81 1 + Current sample, line, band is: 29 81 1 + Current sample, line, band is: 30 81 1 + Current sample, line, band is: 31 81 1 + Current sample, line, band is: 32 81 1 + Current sample, line, band is: 33 81 1 + Current sample, line, band is: 34 81 1 + Current sample, line, band is: 35 81 1 + Current sample, line, band is: 36 81 1 + Current sample, line, band is: 37 81 1 + Current sample, line, band is: 38 81 1 + Current sample, line, band is: 39 81 1 + Current sample, line, band is: 40 81 1 + Current sample, line, band is: 41 81 1 + Current sample, line, band is: 42 81 1 + Current sample, line, band is: 43 81 1 + Current sample, line, band is: 44 81 1 + Current sample, line, band is: 45 81 1 + Current sample, line, band is: 46 81 1 + Current sample, line, band is: 47 81 1 + Current sample, line, band is: 48 81 1 + Current sample, line, band is: 49 81 1 + Current sample, line, band is: 50 81 1 + Current sample, line, band is: 51 81 1 + Current sample, line, band is: 52 81 1 + Current sample, line, band is: 53 81 1 + Current sample, line, band is: 54 81 1 + Current sample, line, band is: 55 81 1 + Current sample, line, band is: 56 81 1 + Current sample, line, band is: 57 81 1 + Current sample, line, band is: 58 81 1 + Current sample, line, band is: 59 81 1 + Current sample, line, band is: 60 81 1 + Current sample, line, band is: 61 81 1 + Current sample, line, band is: 62 81 1 + Current sample, line, band is: 63 81 1 + Current sample, line, band is: 64 81 1 + Current sample, line, band is: 65 81 1 + Current sample, line, band is: 66 81 1 + Current sample, line, band is: 67 81 1 + Current sample, line, band is: 68 81 1 + Current sample, line, band is: 69 81 1 + Current sample, line, band is: 70 81 1 + Current sample, line, band is: 71 81 1 + Current sample, line, band is: 72 81 1 + Current sample, line, band is: 73 81 1 + Current sample, line, band is: 74 81 1 + Current sample, line, band is: 75 81 1 + Current sample, line, band is: 76 81 1 + Current sample, line, band is: 77 81 1 + Current sample, line, band is: 78 81 1 + Current sample, line, band is: 79 81 1 + Current sample, line, band is: 80 81 1 + Current sample, line, band is: 81 81 1 + Current sample, line, band is: 82 81 1 + Current sample, line, band is: 83 81 1 + Current sample, line, band is: 84 81 1 + Current sample, line, band is: 85 81 1 + Current sample, line, band is: 86 81 1 + Current sample, line, band is: 87 81 1 + Current sample, line, band is: 88 81 1 + Current sample, line, band is: 89 81 1 + Current sample, line, band is: 90 81 1 + Current sample, line, band is: 91 81 1 + Current sample, line, band is: 92 81 1 + Current sample, line, band is: 93 81 1 + Current sample, line, band is: 94 81 1 + Current sample, line, band is: 95 81 1 + Current sample, line, band is: 96 81 1 + Current sample, line, band is: 97 81 1 + Current sample, line, band is: 98 81 1 + Current sample, line, band is: 99 81 1 + Current sample, line, band is: 100 81 1 + Current sample, line, band is: 101 81 1 + Current sample, line, band is: 102 81 1 + Current sample, line, band is: 103 81 1 + Current sample, line, band is: 104 81 1 + Current sample, line, band is: 105 81 1 + Current sample, line, band is: 106 81 1 + Current sample, line, band is: 107 81 1 + Current sample, line, band is: 108 81 1 + Current sample, line, band is: 109 81 1 + Current sample, line, band is: 110 81 1 + Current sample, line, band is: 111 81 1 + Current sample, line, band is: 112 81 1 + Current sample, line, band is: 113 81 1 + Current sample, line, band is: 114 81 1 + Current sample, line, band is: 115 81 1 + Current sample, line, band is: 116 81 1 + Current sample, line, band is: 117 81 1 + Current sample, line, band is: 118 81 1 + Current sample, line, band is: 119 81 1 + Current sample, line, band is: 120 81 1 + Current sample, line, band is: 121 81 1 + Current sample, line, band is: 122 81 1 + Current sample, line, band is: 123 81 1 + Current sample, line, band is: 124 81 1 + Current sample, line, band is: 125 81 1 + Current sample, line, band is: 126 81 1 + Current sample, line, band is: 1 82 1 + Current sample, line, band is: 2 82 1 + Current sample, line, band is: 3 82 1 + Current sample, line, band is: 4 82 1 + Current sample, line, band is: 5 82 1 + Current sample, line, band is: 6 82 1 + Current sample, line, band is: 7 82 1 + Current sample, line, band is: 8 82 1 + Current sample, line, band is: 9 82 1 + Current sample, line, band is: 10 82 1 + Current sample, line, band is: 11 82 1 + Current sample, line, band is: 12 82 1 + Current sample, line, band is: 13 82 1 + Current sample, line, band is: 14 82 1 + Current sample, line, band is: 15 82 1 + Current sample, line, band is: 16 82 1 + Current sample, line, band is: 17 82 1 + Current sample, line, band is: 18 82 1 + Current sample, line, band is: 19 82 1 + Current sample, line, band is: 20 82 1 + Current sample, line, band is: 21 82 1 + Current sample, line, band is: 22 82 1 + Current sample, line, band is: 23 82 1 + Current sample, line, band is: 24 82 1 + Current sample, line, band is: 25 82 1 + Current sample, line, band is: 26 82 1 + Current sample, line, band is: 27 82 1 + Current sample, line, band is: 28 82 1 + Current sample, line, band is: 29 82 1 + Current sample, line, band is: 30 82 1 + Current sample, line, band is: 31 82 1 + Current sample, line, band is: 32 82 1 + Current sample, line, band is: 33 82 1 + Current sample, line, band is: 34 82 1 + Current sample, line, band is: 35 82 1 + Current sample, line, band is: 36 82 1 + Current sample, line, band is: 37 82 1 + Current sample, line, band is: 38 82 1 + Current sample, line, band is: 39 82 1 + Current sample, line, band is: 40 82 1 + Current sample, line, band is: 41 82 1 + Current sample, line, band is: 42 82 1 + Current sample, line, band is: 43 82 1 + Current sample, line, band is: 44 82 1 + Current sample, line, band is: 45 82 1 + Current sample, line, band is: 46 82 1 + Current sample, line, band is: 47 82 1 + Current sample, line, band is: 48 82 1 + Current sample, line, band is: 49 82 1 + Current sample, line, band is: 50 82 1 + Current sample, line, band is: 51 82 1 + Current sample, line, band is: 52 82 1 + Current sample, line, band is: 53 82 1 + Current sample, line, band is: 54 82 1 + Current sample, line, band is: 55 82 1 + Current sample, line, band is: 56 82 1 + Current sample, line, band is: 57 82 1 + Current sample, line, band is: 58 82 1 + Current sample, line, band is: 59 82 1 + Current sample, line, band is: 60 82 1 + Current sample, line, band is: 61 82 1 + Current sample, line, band is: 62 82 1 + Current sample, line, band is: 63 82 1 + Current sample, line, band is: 64 82 1 + Current sample, line, band is: 65 82 1 + Current sample, line, band is: 66 82 1 + Current sample, line, band is: 67 82 1 + Current sample, line, band is: 68 82 1 + Current sample, line, band is: 69 82 1 + Current sample, line, band is: 70 82 1 + Current sample, line, band is: 71 82 1 + Current sample, line, band is: 72 82 1 + Current sample, line, band is: 73 82 1 + Current sample, line, band is: 74 82 1 + Current sample, line, band is: 75 82 1 + Current sample, line, band is: 76 82 1 + Current sample, line, band is: 77 82 1 + Current sample, line, band is: 78 82 1 + Current sample, line, band is: 79 82 1 + Current sample, line, band is: 80 82 1 + Current sample, line, band is: 81 82 1 + Current sample, line, band is: 82 82 1 + Current sample, line, band is: 83 82 1 + Current sample, line, band is: 84 82 1 + Current sample, line, band is: 85 82 1 + Current sample, line, band is: 86 82 1 + Current sample, line, band is: 87 82 1 + Current sample, line, band is: 88 82 1 + Current sample, line, band is: 89 82 1 + Current sample, line, band is: 90 82 1 + Current sample, line, band is: 91 82 1 + Current sample, line, band is: 92 82 1 + Current sample, line, band is: 93 82 1 + Current sample, line, band is: 94 82 1 + Current sample, line, band is: 95 82 1 + Current sample, line, band is: 96 82 1 + Current sample, line, band is: 97 82 1 + Current sample, line, band is: 98 82 1 + Current sample, line, band is: 99 82 1 + Current sample, line, band is: 100 82 1 + Current sample, line, band is: 101 82 1 + Current sample, line, band is: 102 82 1 + Current sample, line, band is: 103 82 1 + Current sample, line, band is: 104 82 1 + Current sample, line, band is: 105 82 1 + Current sample, line, band is: 106 82 1 + Current sample, line, band is: 107 82 1 + Current sample, line, band is: 108 82 1 + Current sample, line, band is: 109 82 1 + Current sample, line, band is: 110 82 1 + Current sample, line, band is: 111 82 1 + Current sample, line, band is: 112 82 1 + Current sample, line, band is: 113 82 1 + Current sample, line, band is: 114 82 1 + Current sample, line, band is: 115 82 1 + Current sample, line, band is: 116 82 1 + Current sample, line, band is: 117 82 1 + Current sample, line, band is: 118 82 1 + Current sample, line, band is: 119 82 1 + Current sample, line, band is: 120 82 1 + Current sample, line, band is: 121 82 1 + Current sample, line, band is: 122 82 1 + Current sample, line, band is: 123 82 1 + Current sample, line, band is: 124 82 1 + Current sample, line, band is: 125 82 1 + Current sample, line, band is: 126 82 1 + Current sample, line, band is: 1 83 1 + Current sample, line, band is: 2 83 1 + Current sample, line, band is: 3 83 1 + Current sample, line, band is: 4 83 1 + Current sample, line, band is: 5 83 1 + Current sample, line, band is: 6 83 1 + Current sample, line, band is: 7 83 1 + Current sample, line, band is: 8 83 1 + Current sample, line, band is: 9 83 1 + Current sample, line, band is: 10 83 1 + Current sample, line, band is: 11 83 1 + Current sample, line, band is: 12 83 1 + Current sample, line, band is: 13 83 1 + Current sample, line, band is: 14 83 1 + Current sample, line, band is: 15 83 1 + Current sample, line, band is: 16 83 1 + Current sample, line, band is: 17 83 1 + Current sample, line, band is: 18 83 1 + Current sample, line, band is: 19 83 1 + Current sample, line, band is: 20 83 1 + Current sample, line, band is: 21 83 1 + Current sample, line, band is: 22 83 1 + Current sample, line, band is: 23 83 1 + Current sample, line, band is: 24 83 1 + Current sample, line, band is: 25 83 1 + Current sample, line, band is: 26 83 1 + Current sample, line, band is: 27 83 1 + Current sample, line, band is: 28 83 1 + Current sample, line, band is: 29 83 1 + Current sample, line, band is: 30 83 1 + Current sample, line, band is: 31 83 1 + Current sample, line, band is: 32 83 1 + Current sample, line, band is: 33 83 1 + Current sample, line, band is: 34 83 1 + Current sample, line, band is: 35 83 1 + Current sample, line, band is: 36 83 1 + Current sample, line, band is: 37 83 1 + Current sample, line, band is: 38 83 1 + Current sample, line, band is: 39 83 1 + Current sample, line, band is: 40 83 1 + Current sample, line, band is: 41 83 1 + Current sample, line, band is: 42 83 1 + Current sample, line, band is: 43 83 1 + Current sample, line, band is: 44 83 1 + Current sample, line, band is: 45 83 1 + Current sample, line, band is: 46 83 1 + Current sample, line, band is: 47 83 1 + Current sample, line, band is: 48 83 1 + Current sample, line, band is: 49 83 1 + Current sample, line, band is: 50 83 1 + Current sample, line, band is: 51 83 1 + Current sample, line, band is: 52 83 1 + Current sample, line, band is: 53 83 1 + Current sample, line, band is: 54 83 1 + Current sample, line, band is: 55 83 1 + Current sample, line, band is: 56 83 1 + Current sample, line, band is: 57 83 1 + Current sample, line, band is: 58 83 1 + Current sample, line, band is: 59 83 1 + Current sample, line, band is: 60 83 1 + Current sample, line, band is: 61 83 1 + Current sample, line, band is: 62 83 1 + Current sample, line, band is: 63 83 1 + Current sample, line, band is: 64 83 1 + Current sample, line, band is: 65 83 1 + Current sample, line, band is: 66 83 1 + Current sample, line, band is: 67 83 1 + Current sample, line, band is: 68 83 1 + Current sample, line, band is: 69 83 1 + Current sample, line, band is: 70 83 1 + Current sample, line, band is: 71 83 1 + Current sample, line, band is: 72 83 1 + Current sample, line, band is: 73 83 1 + Current sample, line, band is: 74 83 1 + Current sample, line, band is: 75 83 1 + Current sample, line, band is: 76 83 1 + Current sample, line, band is: 77 83 1 + Current sample, line, band is: 78 83 1 + Current sample, line, band is: 79 83 1 + Current sample, line, band is: 80 83 1 + Current sample, line, band is: 81 83 1 + Current sample, line, band is: 82 83 1 + Current sample, line, band is: 83 83 1 + Current sample, line, band is: 84 83 1 + Current sample, line, band is: 85 83 1 + Current sample, line, band is: 86 83 1 + Current sample, line, band is: 87 83 1 + Current sample, line, band is: 88 83 1 + Current sample, line, band is: 89 83 1 + Current sample, line, band is: 90 83 1 + Current sample, line, band is: 91 83 1 + Current sample, line, band is: 92 83 1 + Current sample, line, band is: 93 83 1 + Current sample, line, band is: 94 83 1 + Current sample, line, band is: 95 83 1 + Current sample, line, band is: 96 83 1 + Current sample, line, band is: 97 83 1 + Current sample, line, band is: 98 83 1 + Current sample, line, band is: 99 83 1 + Current sample, line, band is: 100 83 1 + Current sample, line, band is: 101 83 1 + Current sample, line, band is: 102 83 1 + Current sample, line, band is: 103 83 1 + Current sample, line, band is: 104 83 1 + Current sample, line, band is: 105 83 1 + Current sample, line, band is: 106 83 1 + Current sample, line, band is: 107 83 1 + Current sample, line, band is: 108 83 1 + Current sample, line, band is: 109 83 1 + Current sample, line, band is: 110 83 1 + Current sample, line, band is: 111 83 1 + Current sample, line, band is: 112 83 1 + Current sample, line, band is: 113 83 1 + Current sample, line, band is: 114 83 1 + Current sample, line, band is: 115 83 1 + Current sample, line, band is: 116 83 1 + Current sample, line, band is: 117 83 1 + Current sample, line, band is: 118 83 1 + Current sample, line, band is: 119 83 1 + Current sample, line, band is: 120 83 1 + Current sample, line, band is: 121 83 1 + Current sample, line, band is: 122 83 1 + Current sample, line, band is: 123 83 1 + Current sample, line, band is: 124 83 1 + Current sample, line, band is: 125 83 1 + Current sample, line, band is: 126 83 1 + Current sample, line, band is: 1 84 1 + Current sample, line, band is: 2 84 1 + Current sample, line, band is: 3 84 1 + Current sample, line, band is: 4 84 1 + Current sample, line, band is: 5 84 1 + Current sample, line, band is: 6 84 1 + Current sample, line, band is: 7 84 1 + Current sample, line, band is: 8 84 1 + Current sample, line, band is: 9 84 1 + Current sample, line, band is: 10 84 1 + Current sample, line, band is: 11 84 1 + Current sample, line, band is: 12 84 1 + Current sample, line, band is: 13 84 1 + Current sample, line, band is: 14 84 1 + Current sample, line, band is: 15 84 1 + Current sample, line, band is: 16 84 1 + Current sample, line, band is: 17 84 1 + Current sample, line, band is: 18 84 1 + Current sample, line, band is: 19 84 1 + Current sample, line, band is: 20 84 1 + Current sample, line, band is: 21 84 1 + Current sample, line, band is: 22 84 1 + Current sample, line, band is: 23 84 1 + Current sample, line, band is: 24 84 1 + Current sample, line, band is: 25 84 1 + Current sample, line, band is: 26 84 1 + Current sample, line, band is: 27 84 1 + Current sample, line, band is: 28 84 1 + Current sample, line, band is: 29 84 1 + Current sample, line, band is: 30 84 1 + Current sample, line, band is: 31 84 1 + Current sample, line, band is: 32 84 1 + Current sample, line, band is: 33 84 1 + Current sample, line, band is: 34 84 1 + Current sample, line, band is: 35 84 1 + Current sample, line, band is: 36 84 1 + Current sample, line, band is: 37 84 1 + Current sample, line, band is: 38 84 1 + Current sample, line, band is: 39 84 1 + Current sample, line, band is: 40 84 1 + Current sample, line, band is: 41 84 1 + Current sample, line, band is: 42 84 1 + Current sample, line, band is: 43 84 1 + Current sample, line, band is: 44 84 1 + Current sample, line, band is: 45 84 1 + Current sample, line, band is: 46 84 1 + Current sample, line, band is: 47 84 1 + Current sample, line, band is: 48 84 1 + Current sample, line, band is: 49 84 1 + Current sample, line, band is: 50 84 1 + Current sample, line, band is: 51 84 1 + Current sample, line, band is: 52 84 1 + Current sample, line, band is: 53 84 1 + Current sample, line, band is: 54 84 1 + Current sample, line, band is: 55 84 1 + Current sample, line, band is: 56 84 1 + Current sample, line, band is: 57 84 1 + Current sample, line, band is: 58 84 1 + Current sample, line, band is: 59 84 1 + Current sample, line, band is: 60 84 1 + Current sample, line, band is: 61 84 1 + Current sample, line, band is: 62 84 1 + Current sample, line, band is: 63 84 1 + Current sample, line, band is: 64 84 1 + Current sample, line, band is: 65 84 1 + Current sample, line, band is: 66 84 1 + Current sample, line, band is: 67 84 1 + Current sample, line, band is: 68 84 1 + Current sample, line, band is: 69 84 1 + Current sample, line, band is: 70 84 1 + Current sample, line, band is: 71 84 1 + Current sample, line, band is: 72 84 1 + Current sample, line, band is: 73 84 1 + Current sample, line, band is: 74 84 1 + Current sample, line, band is: 75 84 1 + Current sample, line, band is: 76 84 1 + Current sample, line, band is: 77 84 1 + Current sample, line, band is: 78 84 1 + Current sample, line, band is: 79 84 1 + Current sample, line, band is: 80 84 1 + Current sample, line, band is: 81 84 1 + Current sample, line, band is: 82 84 1 + Current sample, line, band is: 83 84 1 + Current sample, line, band is: 84 84 1 + Current sample, line, band is: 85 84 1 + Current sample, line, band is: 86 84 1 + Current sample, line, band is: 87 84 1 + Current sample, line, band is: 88 84 1 + Current sample, line, band is: 89 84 1 + Current sample, line, band is: 90 84 1 + Current sample, line, band is: 91 84 1 + Current sample, line, band is: 92 84 1 + Current sample, line, band is: 93 84 1 + Current sample, line, band is: 94 84 1 + Current sample, line, band is: 95 84 1 + Current sample, line, band is: 96 84 1 + Current sample, line, band is: 97 84 1 + Current sample, line, band is: 98 84 1 + Current sample, line, band is: 99 84 1 + Current sample, line, band is: 100 84 1 + Current sample, line, band is: 101 84 1 + Current sample, line, band is: 102 84 1 + Current sample, line, band is: 103 84 1 + Current sample, line, band is: 104 84 1 + Current sample, line, band is: 105 84 1 + Current sample, line, band is: 106 84 1 + Current sample, line, band is: 107 84 1 + Current sample, line, band is: 108 84 1 + Current sample, line, band is: 109 84 1 + Current sample, line, band is: 110 84 1 + Current sample, line, band is: 111 84 1 + Current sample, line, band is: 112 84 1 + Current sample, line, band is: 113 84 1 + Current sample, line, band is: 114 84 1 + Current sample, line, band is: 115 84 1 + Current sample, line, band is: 116 84 1 + Current sample, line, band is: 117 84 1 + Current sample, line, band is: 118 84 1 + Current sample, line, band is: 119 84 1 + Current sample, line, band is: 120 84 1 + Current sample, line, band is: 121 84 1 + Current sample, line, band is: 122 84 1 + Current sample, line, band is: 123 84 1 + Current sample, line, band is: 124 84 1 + Current sample, line, band is: 125 84 1 + Current sample, line, band is: 126 84 1 + Current sample, line, band is: 1 85 1 + Current sample, line, band is: 2 85 1 + Current sample, line, band is: 3 85 1 + Current sample, line, band is: 4 85 1 + Current sample, line, band is: 5 85 1 + Current sample, line, band is: 6 85 1 + Current sample, line, band is: 7 85 1 + Current sample, line, band is: 8 85 1 + Current sample, line, band is: 9 85 1 + Current sample, line, band is: 10 85 1 + Current sample, line, band is: 11 85 1 + Current sample, line, band is: 12 85 1 + Current sample, line, band is: 13 85 1 + Current sample, line, band is: 14 85 1 + Current sample, line, band is: 15 85 1 + Current sample, line, band is: 16 85 1 + Current sample, line, band is: 17 85 1 + Current sample, line, band is: 18 85 1 + Current sample, line, band is: 19 85 1 + Current sample, line, band is: 20 85 1 + Current sample, line, band is: 21 85 1 + Current sample, line, band is: 22 85 1 + Current sample, line, band is: 23 85 1 + Current sample, line, band is: 24 85 1 + Current sample, line, band is: 25 85 1 + Current sample, line, band is: 26 85 1 + Current sample, line, band is: 27 85 1 + Current sample, line, band is: 28 85 1 + Current sample, line, band is: 29 85 1 + Current sample, line, band is: 30 85 1 + Current sample, line, band is: 31 85 1 + Current sample, line, band is: 32 85 1 + Current sample, line, band is: 33 85 1 + Current sample, line, band is: 34 85 1 + Current sample, line, band is: 35 85 1 + Current sample, line, band is: 36 85 1 + Current sample, line, band is: 37 85 1 + Current sample, line, band is: 38 85 1 + Current sample, line, band is: 39 85 1 + Current sample, line, band is: 40 85 1 + Current sample, line, band is: 41 85 1 + Current sample, line, band is: 42 85 1 + Current sample, line, band is: 43 85 1 + Current sample, line, band is: 44 85 1 + Current sample, line, band is: 45 85 1 + Current sample, line, band is: 46 85 1 + Current sample, line, band is: 47 85 1 + Current sample, line, band is: 48 85 1 + Current sample, line, band is: 49 85 1 + Current sample, line, band is: 50 85 1 + Current sample, line, band is: 51 85 1 + Current sample, line, band is: 52 85 1 + Current sample, line, band is: 53 85 1 + Current sample, line, band is: 54 85 1 + Current sample, line, band is: 55 85 1 + Current sample, line, band is: 56 85 1 + Current sample, line, band is: 57 85 1 + Current sample, line, band is: 58 85 1 + Current sample, line, band is: 59 85 1 + Current sample, line, band is: 60 85 1 + Current sample, line, band is: 61 85 1 + Current sample, line, band is: 62 85 1 + Current sample, line, band is: 63 85 1 + Current sample, line, band is: 64 85 1 + Current sample, line, band is: 65 85 1 + Current sample, line, band is: 66 85 1 + Current sample, line, band is: 67 85 1 + Current sample, line, band is: 68 85 1 + Current sample, line, band is: 69 85 1 + Current sample, line, band is: 70 85 1 + Current sample, line, band is: 71 85 1 + Current sample, line, band is: 72 85 1 + Current sample, line, band is: 73 85 1 + Current sample, line, band is: 74 85 1 + Current sample, line, band is: 75 85 1 + Current sample, line, band is: 76 85 1 + Current sample, line, band is: 77 85 1 + Current sample, line, band is: 78 85 1 + Current sample, line, band is: 79 85 1 + Current sample, line, band is: 80 85 1 + Current sample, line, band is: 81 85 1 + Current sample, line, band is: 82 85 1 + Current sample, line, band is: 83 85 1 + Current sample, line, band is: 84 85 1 + Current sample, line, band is: 85 85 1 + Current sample, line, band is: 86 85 1 + Current sample, line, band is: 87 85 1 + Current sample, line, band is: 88 85 1 + Current sample, line, band is: 89 85 1 + Current sample, line, band is: 90 85 1 + Current sample, line, band is: 91 85 1 + Current sample, line, band is: 92 85 1 + Current sample, line, band is: 93 85 1 + Current sample, line, band is: 94 85 1 + Current sample, line, band is: 95 85 1 + Current sample, line, band is: 96 85 1 + Current sample, line, band is: 97 85 1 + Current sample, line, band is: 98 85 1 + Current sample, line, band is: 99 85 1 + Current sample, line, band is: 100 85 1 + Current sample, line, band is: 101 85 1 + Current sample, line, band is: 102 85 1 + Current sample, line, band is: 103 85 1 + Current sample, line, band is: 104 85 1 + Current sample, line, band is: 105 85 1 + Current sample, line, band is: 106 85 1 + Current sample, line, band is: 107 85 1 + Current sample, line, band is: 108 85 1 + Current sample, line, band is: 109 85 1 + Current sample, line, band is: 110 85 1 + Current sample, line, band is: 111 85 1 + Current sample, line, band is: 112 85 1 + Current sample, line, band is: 113 85 1 + Current sample, line, band is: 114 85 1 + Current sample, line, band is: 115 85 1 + Current sample, line, band is: 116 85 1 + Current sample, line, band is: 117 85 1 + Current sample, line, band is: 118 85 1 + Current sample, line, band is: 119 85 1 + Current sample, line, band is: 120 85 1 + Current sample, line, band is: 121 85 1 + Current sample, line, band is: 122 85 1 + Current sample, line, band is: 123 85 1 + Current sample, line, band is: 124 85 1 + Current sample, line, band is: 125 85 1 + Current sample, line, band is: 126 85 1 + Current sample, line, band is: 1 86 1 + Current sample, line, band is: 2 86 1 + Current sample, line, band is: 3 86 1 + Current sample, line, band is: 4 86 1 + Current sample, line, band is: 5 86 1 + Current sample, line, band is: 6 86 1 + Current sample, line, band is: 7 86 1 + Current sample, line, band is: 8 86 1 + Current sample, line, band is: 9 86 1 + Current sample, line, band is: 10 86 1 + Current sample, line, band is: 11 86 1 + Current sample, line, band is: 12 86 1 + Current sample, line, band is: 13 86 1 + Current sample, line, band is: 14 86 1 + Current sample, line, band is: 15 86 1 + Current sample, line, band is: 16 86 1 + Current sample, line, band is: 17 86 1 + Current sample, line, band is: 18 86 1 + Current sample, line, band is: 19 86 1 + Current sample, line, band is: 20 86 1 + Current sample, line, band is: 21 86 1 + Current sample, line, band is: 22 86 1 + Current sample, line, band is: 23 86 1 + Current sample, line, band is: 24 86 1 + Current sample, line, band is: 25 86 1 + Current sample, line, band is: 26 86 1 + Current sample, line, band is: 27 86 1 + Current sample, line, band is: 28 86 1 + Current sample, line, band is: 29 86 1 + Current sample, line, band is: 30 86 1 + Current sample, line, band is: 31 86 1 + Current sample, line, band is: 32 86 1 + Current sample, line, band is: 33 86 1 + Current sample, line, band is: 34 86 1 + Current sample, line, band is: 35 86 1 + Current sample, line, band is: 36 86 1 + Current sample, line, band is: 37 86 1 + Current sample, line, band is: 38 86 1 + Current sample, line, band is: 39 86 1 + Current sample, line, band is: 40 86 1 + Current sample, line, band is: 41 86 1 + Current sample, line, band is: 42 86 1 + Current sample, line, band is: 43 86 1 + Current sample, line, band is: 44 86 1 + Current sample, line, band is: 45 86 1 + Current sample, line, band is: 46 86 1 + Current sample, line, band is: 47 86 1 + Current sample, line, band is: 48 86 1 + Current sample, line, band is: 49 86 1 + Current sample, line, band is: 50 86 1 + Current sample, line, band is: 51 86 1 + Current sample, line, band is: 52 86 1 + Current sample, line, band is: 53 86 1 + Current sample, line, band is: 54 86 1 + Current sample, line, band is: 55 86 1 + Current sample, line, band is: 56 86 1 + Current sample, line, band is: 57 86 1 + Current sample, line, band is: 58 86 1 + Current sample, line, band is: 59 86 1 + Current sample, line, band is: 60 86 1 + Current sample, line, band is: 61 86 1 + Current sample, line, band is: 62 86 1 + Current sample, line, band is: 63 86 1 + Current sample, line, band is: 64 86 1 + Current sample, line, band is: 65 86 1 + Current sample, line, band is: 66 86 1 + Current sample, line, band is: 67 86 1 + Current sample, line, band is: 68 86 1 + Current sample, line, band is: 69 86 1 + Current sample, line, band is: 70 86 1 + Current sample, line, band is: 71 86 1 + Current sample, line, band is: 72 86 1 + Current sample, line, band is: 73 86 1 + Current sample, line, band is: 74 86 1 + Current sample, line, band is: 75 86 1 + Current sample, line, band is: 76 86 1 + Current sample, line, band is: 77 86 1 + Current sample, line, band is: 78 86 1 + Current sample, line, band is: 79 86 1 + Current sample, line, band is: 80 86 1 + Current sample, line, band is: 81 86 1 + Current sample, line, band is: 82 86 1 + Current sample, line, band is: 83 86 1 + Current sample, line, band is: 84 86 1 + Current sample, line, band is: 85 86 1 + Current sample, line, band is: 86 86 1 + Current sample, line, band is: 87 86 1 + Current sample, line, band is: 88 86 1 + Current sample, line, band is: 89 86 1 + Current sample, line, band is: 90 86 1 + Current sample, line, band is: 91 86 1 + Current sample, line, band is: 92 86 1 + Current sample, line, band is: 93 86 1 + Current sample, line, band is: 94 86 1 + Current sample, line, band is: 95 86 1 + Current sample, line, band is: 96 86 1 + Current sample, line, band is: 97 86 1 + Current sample, line, band is: 98 86 1 + Current sample, line, band is: 99 86 1 + Current sample, line, band is: 100 86 1 + Current sample, line, band is: 101 86 1 + Current sample, line, band is: 102 86 1 + Current sample, line, band is: 103 86 1 + Current sample, line, band is: 104 86 1 + Current sample, line, band is: 105 86 1 + Current sample, line, band is: 106 86 1 + Current sample, line, band is: 107 86 1 + Current sample, line, band is: 108 86 1 + Current sample, line, band is: 109 86 1 + Current sample, line, band is: 110 86 1 + Current sample, line, band is: 111 86 1 + Current sample, line, band is: 112 86 1 + Current sample, line, band is: 113 86 1 + Current sample, line, band is: 114 86 1 + Current sample, line, band is: 115 86 1 + Current sample, line, band is: 116 86 1 + Current sample, line, band is: 117 86 1 + Current sample, line, band is: 118 86 1 + Current sample, line, band is: 119 86 1 + Current sample, line, band is: 120 86 1 + Current sample, line, band is: 121 86 1 + Current sample, line, band is: 122 86 1 + Current sample, line, band is: 123 86 1 + Current sample, line, band is: 124 86 1 + Current sample, line, band is: 125 86 1 + Current sample, line, band is: 126 86 1 + Current sample, line, band is: 1 87 1 + Current sample, line, band is: 2 87 1 + Current sample, line, band is: 3 87 1 + Current sample, line, band is: 4 87 1 + Current sample, line, band is: 5 87 1 + Current sample, line, band is: 6 87 1 + Current sample, line, band is: 7 87 1 + Current sample, line, band is: 8 87 1 + Current sample, line, band is: 9 87 1 + Current sample, line, band is: 10 87 1 + Current sample, line, band is: 11 87 1 + Current sample, line, band is: 12 87 1 + Current sample, line, band is: 13 87 1 + Current sample, line, band is: 14 87 1 + Current sample, line, band is: 15 87 1 + Current sample, line, band is: 16 87 1 + Current sample, line, band is: 17 87 1 + Current sample, line, band is: 18 87 1 + Current sample, line, band is: 19 87 1 + Current sample, line, band is: 20 87 1 + Current sample, line, band is: 21 87 1 + Current sample, line, band is: 22 87 1 + Current sample, line, band is: 23 87 1 + Current sample, line, band is: 24 87 1 + Current sample, line, band is: 25 87 1 + Current sample, line, band is: 26 87 1 + Current sample, line, band is: 27 87 1 + Current sample, line, band is: 28 87 1 + Current sample, line, band is: 29 87 1 + Current sample, line, band is: 30 87 1 + Current sample, line, band is: 31 87 1 + Current sample, line, band is: 32 87 1 + Current sample, line, band is: 33 87 1 + Current sample, line, band is: 34 87 1 + Current sample, line, band is: 35 87 1 + Current sample, line, band is: 36 87 1 + Current sample, line, band is: 37 87 1 + Current sample, line, band is: 38 87 1 + Current sample, line, band is: 39 87 1 + Current sample, line, band is: 40 87 1 + Current sample, line, band is: 41 87 1 + Current sample, line, band is: 42 87 1 + Current sample, line, band is: 43 87 1 + Current sample, line, band is: 44 87 1 + Current sample, line, band is: 45 87 1 + Current sample, line, band is: 46 87 1 + Current sample, line, band is: 47 87 1 + Current sample, line, band is: 48 87 1 + Current sample, line, band is: 49 87 1 + Current sample, line, band is: 50 87 1 + Current sample, line, band is: 51 87 1 + Current sample, line, band is: 52 87 1 + Current sample, line, band is: 53 87 1 + Current sample, line, band is: 54 87 1 + Current sample, line, band is: 55 87 1 + Current sample, line, band is: 56 87 1 + Current sample, line, band is: 57 87 1 + Current sample, line, band is: 58 87 1 + Current sample, line, band is: 59 87 1 + Current sample, line, band is: 60 87 1 + Current sample, line, band is: 61 87 1 + Current sample, line, band is: 62 87 1 + Current sample, line, band is: 63 87 1 + Current sample, line, band is: 64 87 1 + Current sample, line, band is: 65 87 1 + Current sample, line, band is: 66 87 1 + Current sample, line, band is: 67 87 1 + Current sample, line, band is: 68 87 1 + Current sample, line, band is: 69 87 1 + Current sample, line, band is: 70 87 1 + Current sample, line, band is: 71 87 1 + Current sample, line, band is: 72 87 1 + Current sample, line, band is: 73 87 1 + Current sample, line, band is: 74 87 1 + Current sample, line, band is: 75 87 1 + Current sample, line, band is: 76 87 1 + Current sample, line, band is: 77 87 1 + Current sample, line, band is: 78 87 1 + Current sample, line, band is: 79 87 1 + Current sample, line, band is: 80 87 1 + Current sample, line, band is: 81 87 1 + Current sample, line, band is: 82 87 1 + Current sample, line, band is: 83 87 1 + Current sample, line, band is: 84 87 1 + Current sample, line, band is: 85 87 1 + Current sample, line, band is: 86 87 1 + Current sample, line, band is: 87 87 1 + Current sample, line, band is: 88 87 1 + Current sample, line, band is: 89 87 1 + Current sample, line, band is: 90 87 1 + Current sample, line, band is: 91 87 1 + Current sample, line, band is: 92 87 1 + Current sample, line, band is: 93 87 1 + Current sample, line, band is: 94 87 1 + Current sample, line, band is: 95 87 1 + Current sample, line, band is: 96 87 1 + Current sample, line, band is: 97 87 1 + Current sample, line, band is: 98 87 1 + Current sample, line, band is: 99 87 1 + Current sample, line, band is: 100 87 1 + Current sample, line, band is: 101 87 1 + Current sample, line, band is: 102 87 1 + Current sample, line, band is: 103 87 1 + Current sample, line, band is: 104 87 1 + Current sample, line, band is: 105 87 1 + Current sample, line, band is: 106 87 1 + Current sample, line, band is: 107 87 1 + Current sample, line, band is: 108 87 1 + Current sample, line, band is: 109 87 1 + Current sample, line, band is: 110 87 1 + Current sample, line, band is: 111 87 1 + Current sample, line, band is: 112 87 1 + Current sample, line, band is: 113 87 1 + Current sample, line, band is: 114 87 1 + Current sample, line, band is: 115 87 1 + Current sample, line, band is: 116 87 1 + Current sample, line, band is: 117 87 1 + Current sample, line, band is: 118 87 1 + Current sample, line, band is: 119 87 1 + Current sample, line, band is: 120 87 1 + Current sample, line, band is: 121 87 1 + Current sample, line, band is: 122 87 1 + Current sample, line, band is: 123 87 1 + Current sample, line, band is: 124 87 1 + Current sample, line, band is: 125 87 1 + Current sample, line, band is: 126 87 1 + Current sample, line, band is: 1 88 1 + Current sample, line, band is: 2 88 1 + Current sample, line, band is: 3 88 1 + Current sample, line, band is: 4 88 1 + Current sample, line, band is: 5 88 1 + Current sample, line, band is: 6 88 1 + Current sample, line, band is: 7 88 1 + Current sample, line, band is: 8 88 1 + Current sample, line, band is: 9 88 1 + Current sample, line, band is: 10 88 1 + Current sample, line, band is: 11 88 1 + Current sample, line, band is: 12 88 1 + Current sample, line, band is: 13 88 1 + Current sample, line, band is: 14 88 1 + Current sample, line, band is: 15 88 1 + Current sample, line, band is: 16 88 1 + Current sample, line, band is: 17 88 1 + Current sample, line, band is: 18 88 1 + Current sample, line, band is: 19 88 1 + Current sample, line, band is: 20 88 1 + Current sample, line, band is: 21 88 1 + Current sample, line, band is: 22 88 1 + Current sample, line, band is: 23 88 1 + Current sample, line, band is: 24 88 1 + Current sample, line, band is: 25 88 1 + Current sample, line, band is: 26 88 1 + Current sample, line, band is: 27 88 1 + Current sample, line, band is: 28 88 1 + Current sample, line, band is: 29 88 1 + Current sample, line, band is: 30 88 1 + Current sample, line, band is: 31 88 1 + Current sample, line, band is: 32 88 1 + Current sample, line, band is: 33 88 1 + Current sample, line, band is: 34 88 1 + Current sample, line, band is: 35 88 1 + Current sample, line, band is: 36 88 1 + Current sample, line, band is: 37 88 1 + Current sample, line, band is: 38 88 1 + Current sample, line, band is: 39 88 1 + Current sample, line, band is: 40 88 1 + Current sample, line, band is: 41 88 1 + Current sample, line, band is: 42 88 1 + Current sample, line, band is: 43 88 1 + Current sample, line, band is: 44 88 1 + Current sample, line, band is: 45 88 1 + Current sample, line, band is: 46 88 1 + Current sample, line, band is: 47 88 1 + Current sample, line, band is: 48 88 1 + Current sample, line, band is: 49 88 1 + Current sample, line, band is: 50 88 1 + Current sample, line, band is: 51 88 1 + Current sample, line, band is: 52 88 1 + Current sample, line, band is: 53 88 1 + Current sample, line, band is: 54 88 1 + Current sample, line, band is: 55 88 1 + Current sample, line, band is: 56 88 1 + Current sample, line, band is: 57 88 1 + Current sample, line, band is: 58 88 1 + Current sample, line, band is: 59 88 1 + Current sample, line, band is: 60 88 1 + Current sample, line, band is: 61 88 1 + Current sample, line, band is: 62 88 1 + Current sample, line, band is: 63 88 1 + Current sample, line, band is: 64 88 1 + Current sample, line, band is: 65 88 1 + Current sample, line, band is: 66 88 1 + Current sample, line, band is: 67 88 1 + Current sample, line, band is: 68 88 1 + Current sample, line, band is: 69 88 1 + Current sample, line, band is: 70 88 1 + Current sample, line, band is: 71 88 1 + Current sample, line, band is: 72 88 1 + Current sample, line, band is: 73 88 1 + Current sample, line, band is: 74 88 1 + Current sample, line, band is: 75 88 1 + Current sample, line, band is: 76 88 1 + Current sample, line, band is: 77 88 1 + Current sample, line, band is: 78 88 1 + Current sample, line, band is: 79 88 1 + Current sample, line, band is: 80 88 1 + Current sample, line, band is: 81 88 1 + Current sample, line, band is: 82 88 1 + Current sample, line, band is: 83 88 1 + Current sample, line, band is: 84 88 1 + Current sample, line, band is: 85 88 1 + Current sample, line, band is: 86 88 1 + Current sample, line, band is: 87 88 1 + Current sample, line, band is: 88 88 1 + Current sample, line, band is: 89 88 1 + Current sample, line, band is: 90 88 1 + Current sample, line, band is: 91 88 1 + Current sample, line, band is: 92 88 1 + Current sample, line, band is: 93 88 1 + Current sample, line, band is: 94 88 1 + Current sample, line, band is: 95 88 1 + Current sample, line, band is: 96 88 1 + Current sample, line, band is: 97 88 1 + Current sample, line, band is: 98 88 1 + Current sample, line, band is: 99 88 1 + Current sample, line, band is: 100 88 1 + Current sample, line, band is: 101 88 1 + Current sample, line, band is: 102 88 1 + Current sample, line, band is: 103 88 1 + Current sample, line, band is: 104 88 1 + Current sample, line, band is: 105 88 1 + Current sample, line, band is: 106 88 1 + Current sample, line, band is: 107 88 1 + Current sample, line, band is: 108 88 1 + Current sample, line, band is: 109 88 1 + Current sample, line, band is: 110 88 1 + Current sample, line, band is: 111 88 1 + Current sample, line, band is: 112 88 1 + Current sample, line, band is: 113 88 1 + Current sample, line, band is: 114 88 1 + Current sample, line, band is: 115 88 1 + Current sample, line, band is: 116 88 1 + Current sample, line, band is: 117 88 1 + Current sample, line, band is: 118 88 1 + Current sample, line, band is: 119 88 1 + Current sample, line, band is: 120 88 1 + Current sample, line, band is: 121 88 1 + Current sample, line, band is: 122 88 1 + Current sample, line, band is: 123 88 1 + Current sample, line, band is: 124 88 1 + Current sample, line, band is: 125 88 1 + Current sample, line, band is: 126 88 1 + Current sample, line, band is: 1 89 1 + Current sample, line, band is: 2 89 1 + Current sample, line, band is: 3 89 1 + Current sample, line, band is: 4 89 1 + Current sample, line, band is: 5 89 1 + Current sample, line, band is: 6 89 1 + Current sample, line, band is: 7 89 1 + Current sample, line, band is: 8 89 1 + Current sample, line, band is: 9 89 1 + Current sample, line, band is: 10 89 1 + Current sample, line, band is: 11 89 1 + Current sample, line, band is: 12 89 1 + Current sample, line, band is: 13 89 1 + Current sample, line, band is: 14 89 1 + Current sample, line, band is: 15 89 1 + Current sample, line, band is: 16 89 1 + Current sample, line, band is: 17 89 1 + Current sample, line, band is: 18 89 1 + Current sample, line, band is: 19 89 1 + Current sample, line, band is: 20 89 1 + Current sample, line, band is: 21 89 1 + Current sample, line, band is: 22 89 1 + Current sample, line, band is: 23 89 1 + Current sample, line, band is: 24 89 1 + Current sample, line, band is: 25 89 1 + Current sample, line, band is: 26 89 1 + Current sample, line, band is: 27 89 1 + Current sample, line, band is: 28 89 1 + Current sample, line, band is: 29 89 1 + Current sample, line, band is: 30 89 1 + Current sample, line, band is: 31 89 1 + Current sample, line, band is: 32 89 1 + Current sample, line, band is: 33 89 1 + Current sample, line, band is: 34 89 1 + Current sample, line, band is: 35 89 1 + Current sample, line, band is: 36 89 1 + Current sample, line, band is: 37 89 1 + Current sample, line, band is: 38 89 1 + Current sample, line, band is: 39 89 1 + Current sample, line, band is: 40 89 1 + Current sample, line, band is: 41 89 1 + Current sample, line, band is: 42 89 1 + Current sample, line, band is: 43 89 1 + Current sample, line, band is: 44 89 1 + Current sample, line, band is: 45 89 1 + Current sample, line, band is: 46 89 1 + Current sample, line, band is: 47 89 1 + Current sample, line, band is: 48 89 1 + Current sample, line, band is: 49 89 1 + Current sample, line, band is: 50 89 1 + Current sample, line, band is: 51 89 1 + Current sample, line, band is: 52 89 1 + Current sample, line, band is: 53 89 1 + Current sample, line, band is: 54 89 1 + Current sample, line, band is: 55 89 1 + Current sample, line, band is: 56 89 1 + Current sample, line, band is: 57 89 1 + Current sample, line, band is: 58 89 1 + Current sample, line, band is: 59 89 1 + Current sample, line, band is: 60 89 1 + Current sample, line, band is: 61 89 1 + Current sample, line, band is: 62 89 1 + Current sample, line, band is: 63 89 1 + Current sample, line, band is: 64 89 1 + Current sample, line, band is: 65 89 1 + Current sample, line, band is: 66 89 1 + Current sample, line, band is: 67 89 1 + Current sample, line, band is: 68 89 1 + Current sample, line, band is: 69 89 1 + Current sample, line, band is: 70 89 1 + Current sample, line, band is: 71 89 1 + Current sample, line, band is: 72 89 1 + Current sample, line, band is: 73 89 1 + Current sample, line, band is: 74 89 1 + Current sample, line, band is: 75 89 1 + Current sample, line, band is: 76 89 1 + Current sample, line, band is: 77 89 1 + Current sample, line, band is: 78 89 1 + Current sample, line, band is: 79 89 1 + Current sample, line, band is: 80 89 1 + Current sample, line, band is: 81 89 1 + Current sample, line, band is: 82 89 1 + Current sample, line, band is: 83 89 1 + Current sample, line, band is: 84 89 1 + Current sample, line, band is: 85 89 1 + Current sample, line, band is: 86 89 1 + Current sample, line, band is: 87 89 1 + Current sample, line, band is: 88 89 1 + Current sample, line, band is: 89 89 1 + Current sample, line, band is: 90 89 1 + Current sample, line, band is: 91 89 1 + Current sample, line, band is: 92 89 1 + Current sample, line, band is: 93 89 1 + Current sample, line, band is: 94 89 1 + Current sample, line, band is: 95 89 1 + Current sample, line, band is: 96 89 1 + Current sample, line, band is: 97 89 1 + Current sample, line, band is: 98 89 1 + Current sample, line, band is: 99 89 1 + Current sample, line, band is: 100 89 1 + Current sample, line, band is: 101 89 1 + Current sample, line, band is: 102 89 1 + Current sample, line, band is: 103 89 1 + Current sample, line, band is: 104 89 1 + Current sample, line, band is: 105 89 1 + Current sample, line, band is: 106 89 1 + Current sample, line, band is: 107 89 1 + Current sample, line, band is: 108 89 1 + Current sample, line, band is: 109 89 1 + Current sample, line, band is: 110 89 1 + Current sample, line, band is: 111 89 1 + Current sample, line, band is: 112 89 1 + Current sample, line, band is: 113 89 1 + Current sample, line, band is: 114 89 1 + Current sample, line, band is: 115 89 1 + Current sample, line, band is: 116 89 1 + Current sample, line, band is: 117 89 1 + Current sample, line, band is: 118 89 1 + Current sample, line, band is: 119 89 1 + Current sample, line, band is: 120 89 1 + Current sample, line, band is: 121 89 1 + Current sample, line, band is: 122 89 1 + Current sample, line, band is: 123 89 1 + Current sample, line, band is: 124 89 1 + Current sample, line, band is: 125 89 1 + Current sample, line, band is: 126 89 1 + Current sample, line, band is: 1 90 1 + Current sample, line, band is: 2 90 1 + Current sample, line, band is: 3 90 1 + Current sample, line, band is: 4 90 1 + Current sample, line, band is: 5 90 1 + Current sample, line, band is: 6 90 1 + Current sample, line, band is: 7 90 1 + Current sample, line, band is: 8 90 1 + Current sample, line, band is: 9 90 1 + Current sample, line, band is: 10 90 1 + Current sample, line, band is: 11 90 1 + Current sample, line, band is: 12 90 1 + Current sample, line, band is: 13 90 1 + Current sample, line, band is: 14 90 1 + Current sample, line, band is: 15 90 1 + Current sample, line, band is: 16 90 1 + Current sample, line, band is: 17 90 1 + Current sample, line, band is: 18 90 1 + Current sample, line, band is: 19 90 1 + Current sample, line, band is: 20 90 1 + Current sample, line, band is: 21 90 1 + Current sample, line, band is: 22 90 1 + Current sample, line, band is: 23 90 1 + Current sample, line, band is: 24 90 1 + Current sample, line, band is: 25 90 1 + Current sample, line, band is: 26 90 1 + Current sample, line, band is: 27 90 1 + Current sample, line, band is: 28 90 1 + Current sample, line, band is: 29 90 1 + Current sample, line, band is: 30 90 1 + Current sample, line, band is: 31 90 1 + Current sample, line, band is: 32 90 1 + Current sample, line, band is: 33 90 1 + Current sample, line, band is: 34 90 1 + Current sample, line, band is: 35 90 1 + Current sample, line, band is: 36 90 1 + Current sample, line, band is: 37 90 1 + Current sample, line, band is: 38 90 1 + Current sample, line, band is: 39 90 1 + Current sample, line, band is: 40 90 1 + Current sample, line, band is: 41 90 1 + Current sample, line, band is: 42 90 1 + Current sample, line, band is: 43 90 1 + Current sample, line, band is: 44 90 1 + Current sample, line, band is: 45 90 1 + Current sample, line, band is: 46 90 1 + Current sample, line, band is: 47 90 1 + Current sample, line, band is: 48 90 1 + Current sample, line, band is: 49 90 1 + Current sample, line, band is: 50 90 1 + Current sample, line, band is: 51 90 1 + Current sample, line, band is: 52 90 1 + Current sample, line, band is: 53 90 1 + Current sample, line, band is: 54 90 1 + Current sample, line, band is: 55 90 1 + Current sample, line, band is: 56 90 1 + Current sample, line, band is: 57 90 1 + Current sample, line, band is: 58 90 1 + Current sample, line, band is: 59 90 1 + Current sample, line, band is: 60 90 1 + Current sample, line, band is: 61 90 1 + Current sample, line, band is: 62 90 1 + Current sample, line, band is: 63 90 1 + Current sample, line, band is: 64 90 1 + Current sample, line, band is: 65 90 1 + Current sample, line, band is: 66 90 1 + Current sample, line, band is: 67 90 1 + Current sample, line, band is: 68 90 1 + Current sample, line, band is: 69 90 1 + Current sample, line, band is: 70 90 1 + Current sample, line, band is: 71 90 1 + Current sample, line, band is: 72 90 1 + Current sample, line, band is: 73 90 1 + Current sample, line, band is: 74 90 1 + Current sample, line, band is: 75 90 1 + Current sample, line, band is: 76 90 1 + Current sample, line, band is: 77 90 1 + Current sample, line, band is: 78 90 1 + Current sample, line, band is: 79 90 1 + Current sample, line, band is: 80 90 1 + Current sample, line, band is: 81 90 1 + Current sample, line, band is: 82 90 1 + Current sample, line, band is: 83 90 1 + Current sample, line, band is: 84 90 1 + Current sample, line, band is: 85 90 1 + Current sample, line, band is: 86 90 1 + Current sample, line, band is: 87 90 1 + Current sample, line, band is: 88 90 1 + Current sample, line, band is: 89 90 1 + Current sample, line, band is: 90 90 1 + Current sample, line, band is: 91 90 1 + Current sample, line, band is: 92 90 1 + Current sample, line, band is: 93 90 1 + Current sample, line, band is: 94 90 1 + Current sample, line, band is: 95 90 1 + Current sample, line, band is: 96 90 1 + Current sample, line, band is: 97 90 1 + Current sample, line, band is: 98 90 1 + Current sample, line, band is: 99 90 1 + Current sample, line, band is: 100 90 1 + Current sample, line, band is: 101 90 1 + Current sample, line, band is: 102 90 1 + Current sample, line, band is: 103 90 1 + Current sample, line, band is: 104 90 1 + Current sample, line, band is: 105 90 1 + Current sample, line, band is: 106 90 1 + Current sample, line, band is: 107 90 1 + Current sample, line, band is: 108 90 1 + Current sample, line, band is: 109 90 1 + Current sample, line, band is: 110 90 1 + Current sample, line, band is: 111 90 1 + Current sample, line, band is: 112 90 1 + Current sample, line, band is: 113 90 1 + Current sample, line, band is: 114 90 1 + Current sample, line, band is: 115 90 1 + Current sample, line, band is: 116 90 1 + Current sample, line, band is: 117 90 1 + Current sample, line, band is: 118 90 1 + Current sample, line, band is: 119 90 1 + Current sample, line, band is: 120 90 1 + Current sample, line, band is: 121 90 1 + Current sample, line, band is: 122 90 1 + Current sample, line, band is: 123 90 1 + Current sample, line, band is: 124 90 1 + Current sample, line, band is: 125 90 1 + Current sample, line, band is: 126 90 1 + Current sample, line, band is: 1 91 1 + Current sample, line, band is: 2 91 1 + Current sample, line, band is: 3 91 1 + Current sample, line, band is: 4 91 1 + Current sample, line, band is: 5 91 1 + Current sample, line, band is: 6 91 1 + Current sample, line, band is: 7 91 1 + Current sample, line, band is: 8 91 1 + Current sample, line, band is: 9 91 1 + Current sample, line, band is: 10 91 1 + Current sample, line, band is: 11 91 1 + Current sample, line, band is: 12 91 1 + Current sample, line, band is: 13 91 1 + Current sample, line, band is: 14 91 1 + Current sample, line, band is: 15 91 1 + Current sample, line, band is: 16 91 1 + Current sample, line, band is: 17 91 1 + Current sample, line, band is: 18 91 1 + Current sample, line, band is: 19 91 1 + Current sample, line, band is: 20 91 1 + Current sample, line, band is: 21 91 1 + Current sample, line, band is: 22 91 1 + Current sample, line, band is: 23 91 1 + Current sample, line, band is: 24 91 1 + Current sample, line, band is: 25 91 1 + Current sample, line, band is: 26 91 1 + Current sample, line, band is: 27 91 1 + Current sample, line, band is: 28 91 1 + Current sample, line, band is: 29 91 1 + Current sample, line, band is: 30 91 1 + Current sample, line, band is: 31 91 1 + Current sample, line, band is: 32 91 1 + Current sample, line, band is: 33 91 1 + Current sample, line, band is: 34 91 1 + Current sample, line, band is: 35 91 1 + Current sample, line, band is: 36 91 1 + Current sample, line, band is: 37 91 1 + Current sample, line, band is: 38 91 1 + Current sample, line, band is: 39 91 1 + Current sample, line, band is: 40 91 1 + Current sample, line, band is: 41 91 1 + Current sample, line, band is: 42 91 1 + Current sample, line, band is: 43 91 1 + Current sample, line, band is: 44 91 1 + Current sample, line, band is: 45 91 1 + Current sample, line, band is: 46 91 1 + Current sample, line, band is: 47 91 1 + Current sample, line, band is: 48 91 1 + Current sample, line, band is: 49 91 1 + Current sample, line, band is: 50 91 1 + Current sample, line, band is: 51 91 1 + Current sample, line, band is: 52 91 1 + Current sample, line, band is: 53 91 1 + Current sample, line, band is: 54 91 1 + Current sample, line, band is: 55 91 1 + Current sample, line, band is: 56 91 1 + Current sample, line, band is: 57 91 1 + Current sample, line, band is: 58 91 1 + Current sample, line, band is: 59 91 1 + Current sample, line, band is: 60 91 1 + Current sample, line, band is: 61 91 1 + Current sample, line, band is: 62 91 1 + Current sample, line, band is: 63 91 1 + Current sample, line, band is: 64 91 1 + Current sample, line, band is: 65 91 1 + Current sample, line, band is: 66 91 1 + Current sample, line, band is: 67 91 1 + Current sample, line, band is: 68 91 1 + Current sample, line, band is: 69 91 1 + Current sample, line, band is: 70 91 1 + Current sample, line, band is: 71 91 1 + Current sample, line, band is: 72 91 1 + Current sample, line, band is: 73 91 1 + Current sample, line, band is: 74 91 1 + Current sample, line, band is: 75 91 1 + Current sample, line, band is: 76 91 1 + Current sample, line, band is: 77 91 1 + Current sample, line, band is: 78 91 1 + Current sample, line, band is: 79 91 1 + Current sample, line, band is: 80 91 1 + Current sample, line, band is: 81 91 1 + Current sample, line, band is: 82 91 1 + Current sample, line, band is: 83 91 1 + Current sample, line, band is: 84 91 1 + Current sample, line, band is: 85 91 1 + Current sample, line, band is: 86 91 1 + Current sample, line, band is: 87 91 1 + Current sample, line, band is: 88 91 1 + Current sample, line, band is: 89 91 1 + Current sample, line, band is: 90 91 1 + Current sample, line, band is: 91 91 1 + Current sample, line, band is: 92 91 1 + Current sample, line, band is: 93 91 1 + Current sample, line, band is: 94 91 1 + Current sample, line, band is: 95 91 1 + Current sample, line, band is: 96 91 1 + Current sample, line, band is: 97 91 1 + Current sample, line, band is: 98 91 1 + Current sample, line, band is: 99 91 1 + Current sample, line, band is: 100 91 1 + Current sample, line, band is: 101 91 1 + Current sample, line, band is: 102 91 1 + Current sample, line, band is: 103 91 1 + Current sample, line, band is: 104 91 1 + Current sample, line, band is: 105 91 1 + Current sample, line, band is: 106 91 1 + Current sample, line, band is: 107 91 1 + Current sample, line, band is: 108 91 1 + Current sample, line, band is: 109 91 1 + Current sample, line, band is: 110 91 1 + Current sample, line, band is: 111 91 1 + Current sample, line, band is: 112 91 1 + Current sample, line, band is: 113 91 1 + Current sample, line, band is: 114 91 1 + Current sample, line, band is: 115 91 1 + Current sample, line, band is: 116 91 1 + Current sample, line, band is: 117 91 1 + Current sample, line, band is: 118 91 1 + Current sample, line, band is: 119 91 1 + Current sample, line, band is: 120 91 1 + Current sample, line, band is: 121 91 1 + Current sample, line, band is: 122 91 1 + Current sample, line, band is: 123 91 1 + Current sample, line, band is: 124 91 1 + Current sample, line, band is: 125 91 1 + Current sample, line, band is: 126 91 1 + Current sample, line, band is: 1 92 1 + Current sample, line, band is: 2 92 1 + Current sample, line, band is: 3 92 1 + Current sample, line, band is: 4 92 1 + Current sample, line, band is: 5 92 1 + Current sample, line, band is: 6 92 1 + Current sample, line, band is: 7 92 1 + Current sample, line, band is: 8 92 1 + Current sample, line, band is: 9 92 1 + Current sample, line, band is: 10 92 1 + Current sample, line, band is: 11 92 1 + Current sample, line, band is: 12 92 1 + Current sample, line, band is: 13 92 1 + Current sample, line, band is: 14 92 1 + Current sample, line, band is: 15 92 1 + Current sample, line, band is: 16 92 1 + Current sample, line, band is: 17 92 1 + Current sample, line, band is: 18 92 1 + Current sample, line, band is: 19 92 1 + Current sample, line, band is: 20 92 1 + Current sample, line, band is: 21 92 1 + Current sample, line, band is: 22 92 1 + Current sample, line, band is: 23 92 1 + Current sample, line, band is: 24 92 1 + Current sample, line, band is: 25 92 1 + Current sample, line, band is: 26 92 1 + Current sample, line, band is: 27 92 1 + Current sample, line, band is: 28 92 1 + Current sample, line, band is: 29 92 1 + Current sample, line, band is: 30 92 1 + Current sample, line, band is: 31 92 1 + Current sample, line, band is: 32 92 1 + Current sample, line, band is: 33 92 1 + Current sample, line, band is: 34 92 1 + Current sample, line, band is: 35 92 1 + Current sample, line, band is: 36 92 1 + Current sample, line, band is: 37 92 1 + Current sample, line, band is: 38 92 1 + Current sample, line, band is: 39 92 1 + Current sample, line, band is: 40 92 1 + Current sample, line, band is: 41 92 1 + Current sample, line, band is: 42 92 1 + Current sample, line, band is: 43 92 1 + Current sample, line, band is: 44 92 1 + Current sample, line, band is: 45 92 1 + Current sample, line, band is: 46 92 1 + Current sample, line, band is: 47 92 1 + Current sample, line, band is: 48 92 1 + Current sample, line, band is: 49 92 1 + Current sample, line, band is: 50 92 1 + Current sample, line, band is: 51 92 1 + Current sample, line, band is: 52 92 1 + Current sample, line, band is: 53 92 1 + Current sample, line, band is: 54 92 1 + Current sample, line, band is: 55 92 1 + Current sample, line, band is: 56 92 1 + Current sample, line, band is: 57 92 1 + Current sample, line, band is: 58 92 1 + Current sample, line, band is: 59 92 1 + Current sample, line, band is: 60 92 1 + Current sample, line, band is: 61 92 1 + Current sample, line, band is: 62 92 1 + Current sample, line, band is: 63 92 1 + Current sample, line, band is: 64 92 1 + Current sample, line, band is: 65 92 1 + Current sample, line, band is: 66 92 1 + Current sample, line, band is: 67 92 1 + Current sample, line, band is: 68 92 1 + Current sample, line, band is: 69 92 1 + Current sample, line, band is: 70 92 1 + Current sample, line, band is: 71 92 1 + Current sample, line, band is: 72 92 1 + Current sample, line, band is: 73 92 1 + Current sample, line, band is: 74 92 1 + Current sample, line, band is: 75 92 1 + Current sample, line, band is: 76 92 1 + Current sample, line, band is: 77 92 1 + Current sample, line, band is: 78 92 1 + Current sample, line, band is: 79 92 1 + Current sample, line, band is: 80 92 1 + Current sample, line, band is: 81 92 1 + Current sample, line, band is: 82 92 1 + Current sample, line, band is: 83 92 1 + Current sample, line, band is: 84 92 1 + Current sample, line, band is: 85 92 1 + Current sample, line, band is: 86 92 1 + Current sample, line, band is: 87 92 1 + Current sample, line, band is: 88 92 1 + Current sample, line, band is: 89 92 1 + Current sample, line, band is: 90 92 1 + Current sample, line, band is: 91 92 1 + Current sample, line, band is: 92 92 1 + Current sample, line, band is: 93 92 1 + Current sample, line, band is: 94 92 1 + Current sample, line, band is: 95 92 1 + Current sample, line, band is: 96 92 1 + Current sample, line, band is: 97 92 1 + Current sample, line, band is: 98 92 1 + Current sample, line, band is: 99 92 1 + Current sample, line, band is: 100 92 1 + Current sample, line, band is: 101 92 1 + Current sample, line, band is: 102 92 1 + Current sample, line, band is: 103 92 1 + Current sample, line, band is: 104 92 1 + Current sample, line, band is: 105 92 1 + Current sample, line, band is: 106 92 1 + Current sample, line, band is: 107 92 1 + Current sample, line, band is: 108 92 1 + Current sample, line, band is: 109 92 1 + Current sample, line, band is: 110 92 1 + Current sample, line, band is: 111 92 1 + Current sample, line, band is: 112 92 1 + Current sample, line, band is: 113 92 1 + Current sample, line, band is: 114 92 1 + Current sample, line, band is: 115 92 1 + Current sample, line, band is: 116 92 1 + Current sample, line, band is: 117 92 1 + Current sample, line, band is: 118 92 1 + Current sample, line, band is: 119 92 1 + Current sample, line, band is: 120 92 1 + Current sample, line, band is: 121 92 1 + Current sample, line, band is: 122 92 1 + Current sample, line, band is: 123 92 1 + Current sample, line, band is: 124 92 1 + Current sample, line, band is: 125 92 1 + Current sample, line, band is: 126 92 1 + Current sample, line, band is: 1 93 1 + Current sample, line, band is: 2 93 1 + Current sample, line, band is: 3 93 1 + Current sample, line, band is: 4 93 1 + Current sample, line, band is: 5 93 1 + Current sample, line, band is: 6 93 1 + Current sample, line, band is: 7 93 1 + Current sample, line, band is: 8 93 1 + Current sample, line, band is: 9 93 1 + Current sample, line, band is: 10 93 1 + Current sample, line, band is: 11 93 1 + Current sample, line, band is: 12 93 1 + Current sample, line, band is: 13 93 1 + Current sample, line, band is: 14 93 1 + Current sample, line, band is: 15 93 1 + Current sample, line, band is: 16 93 1 + Current sample, line, band is: 17 93 1 + Current sample, line, band is: 18 93 1 + Current sample, line, band is: 19 93 1 + Current sample, line, band is: 20 93 1 + Current sample, line, band is: 21 93 1 + Current sample, line, band is: 22 93 1 + Current sample, line, band is: 23 93 1 + Current sample, line, band is: 24 93 1 + Current sample, line, band is: 25 93 1 + Current sample, line, band is: 26 93 1 + Current sample, line, band is: 27 93 1 + Current sample, line, band is: 28 93 1 + Current sample, line, band is: 29 93 1 + Current sample, line, band is: 30 93 1 + Current sample, line, band is: 31 93 1 + Current sample, line, band is: 32 93 1 + Current sample, line, band is: 33 93 1 + Current sample, line, band is: 34 93 1 + Current sample, line, band is: 35 93 1 + Current sample, line, band is: 36 93 1 + Current sample, line, band is: 37 93 1 + Current sample, line, band is: 38 93 1 + Current sample, line, band is: 39 93 1 + Current sample, line, band is: 40 93 1 + Current sample, line, band is: 41 93 1 + Current sample, line, band is: 42 93 1 + Current sample, line, band is: 43 93 1 + Current sample, line, band is: 44 93 1 + Current sample, line, band is: 45 93 1 + Current sample, line, band is: 46 93 1 + Current sample, line, band is: 47 93 1 + Current sample, line, band is: 48 93 1 + Current sample, line, band is: 49 93 1 + Current sample, line, band is: 50 93 1 + Current sample, line, band is: 51 93 1 + Current sample, line, band is: 52 93 1 + Current sample, line, band is: 53 93 1 + Current sample, line, band is: 54 93 1 + Current sample, line, band is: 55 93 1 + Current sample, line, band is: 56 93 1 + Current sample, line, band is: 57 93 1 + Current sample, line, band is: 58 93 1 + Current sample, line, band is: 59 93 1 + Current sample, line, band is: 60 93 1 + Current sample, line, band is: 61 93 1 + Current sample, line, band is: 62 93 1 + Current sample, line, band is: 63 93 1 + Current sample, line, band is: 64 93 1 + Current sample, line, band is: 65 93 1 + Current sample, line, band is: 66 93 1 + Current sample, line, band is: 67 93 1 + Current sample, line, band is: 68 93 1 + Current sample, line, band is: 69 93 1 + Current sample, line, band is: 70 93 1 + Current sample, line, band is: 71 93 1 + Current sample, line, band is: 72 93 1 + Current sample, line, band is: 73 93 1 + Current sample, line, band is: 74 93 1 + Current sample, line, band is: 75 93 1 + Current sample, line, band is: 76 93 1 + Current sample, line, band is: 77 93 1 + Current sample, line, band is: 78 93 1 + Current sample, line, band is: 79 93 1 + Current sample, line, band is: 80 93 1 + Current sample, line, band is: 81 93 1 + Current sample, line, band is: 82 93 1 + Current sample, line, band is: 83 93 1 + Current sample, line, band is: 84 93 1 + Current sample, line, band is: 85 93 1 + Current sample, line, band is: 86 93 1 + Current sample, line, band is: 87 93 1 + Current sample, line, band is: 88 93 1 + Current sample, line, band is: 89 93 1 + Current sample, line, band is: 90 93 1 + Current sample, line, band is: 91 93 1 + Current sample, line, band is: 92 93 1 + Current sample, line, band is: 93 93 1 + Current sample, line, band is: 94 93 1 + Current sample, line, band is: 95 93 1 + Current sample, line, band is: 96 93 1 + Current sample, line, band is: 97 93 1 + Current sample, line, band is: 98 93 1 + Current sample, line, band is: 99 93 1 + Current sample, line, band is: 100 93 1 + Current sample, line, band is: 101 93 1 + Current sample, line, band is: 102 93 1 + Current sample, line, band is: 103 93 1 + Current sample, line, band is: 104 93 1 + Current sample, line, band is: 105 93 1 + Current sample, line, band is: 106 93 1 + Current sample, line, band is: 107 93 1 + Current sample, line, band is: 108 93 1 + Current sample, line, band is: 109 93 1 + Current sample, line, band is: 110 93 1 + Current sample, line, band is: 111 93 1 + Current sample, line, band is: 112 93 1 + Current sample, line, band is: 113 93 1 + Current sample, line, band is: 114 93 1 + Current sample, line, band is: 115 93 1 + Current sample, line, band is: 116 93 1 + Current sample, line, band is: 117 93 1 + Current sample, line, band is: 118 93 1 + Current sample, line, band is: 119 93 1 + Current sample, line, band is: 120 93 1 + Current sample, line, band is: 121 93 1 + Current sample, line, band is: 122 93 1 + Current sample, line, band is: 123 93 1 + Current sample, line, band is: 124 93 1 + Current sample, line, band is: 125 93 1 + Current sample, line, band is: 126 93 1 + Current sample, line, band is: 1 94 1 + Current sample, line, band is: 2 94 1 + Current sample, line, band is: 3 94 1 + Current sample, line, band is: 4 94 1 + Current sample, line, band is: 5 94 1 + Current sample, line, band is: 6 94 1 + Current sample, line, band is: 7 94 1 + Current sample, line, band is: 8 94 1 + Current sample, line, band is: 9 94 1 + Current sample, line, band is: 10 94 1 + Current sample, line, band is: 11 94 1 + Current sample, line, band is: 12 94 1 + Current sample, line, band is: 13 94 1 + Current sample, line, band is: 14 94 1 + Current sample, line, band is: 15 94 1 + Current sample, line, band is: 16 94 1 + Current sample, line, band is: 17 94 1 + Current sample, line, band is: 18 94 1 + Current sample, line, band is: 19 94 1 + Current sample, line, band is: 20 94 1 + Current sample, line, band is: 21 94 1 + Current sample, line, band is: 22 94 1 + Current sample, line, band is: 23 94 1 + Current sample, line, band is: 24 94 1 + Current sample, line, band is: 25 94 1 + Current sample, line, band is: 26 94 1 + Current sample, line, band is: 27 94 1 + Current sample, line, band is: 28 94 1 + Current sample, line, band is: 29 94 1 + Current sample, line, band is: 30 94 1 + Current sample, line, band is: 31 94 1 + Current sample, line, band is: 32 94 1 + Current sample, line, band is: 33 94 1 + Current sample, line, band is: 34 94 1 + Current sample, line, band is: 35 94 1 + Current sample, line, band is: 36 94 1 + Current sample, line, band is: 37 94 1 + Current sample, line, band is: 38 94 1 + Current sample, line, band is: 39 94 1 + Current sample, line, band is: 40 94 1 + Current sample, line, band is: 41 94 1 + Current sample, line, band is: 42 94 1 + Current sample, line, band is: 43 94 1 + Current sample, line, band is: 44 94 1 + Current sample, line, band is: 45 94 1 + Current sample, line, band is: 46 94 1 + Current sample, line, band is: 47 94 1 + Current sample, line, band is: 48 94 1 + Current sample, line, band is: 49 94 1 + Current sample, line, band is: 50 94 1 + Current sample, line, band is: 51 94 1 + Current sample, line, band is: 52 94 1 + Current sample, line, band is: 53 94 1 + Current sample, line, band is: 54 94 1 + Current sample, line, band is: 55 94 1 + Current sample, line, band is: 56 94 1 + Current sample, line, band is: 57 94 1 + Current sample, line, band is: 58 94 1 + Current sample, line, band is: 59 94 1 + Current sample, line, band is: 60 94 1 + Current sample, line, band is: 61 94 1 + Current sample, line, band is: 62 94 1 + Current sample, line, band is: 63 94 1 + Current sample, line, band is: 64 94 1 + Current sample, line, band is: 65 94 1 + Current sample, line, band is: 66 94 1 + Current sample, line, band is: 67 94 1 + Current sample, line, band is: 68 94 1 + Current sample, line, band is: 69 94 1 + Current sample, line, band is: 70 94 1 + Current sample, line, band is: 71 94 1 + Current sample, line, band is: 72 94 1 + Current sample, line, band is: 73 94 1 + Current sample, line, band is: 74 94 1 + Current sample, line, band is: 75 94 1 + Current sample, line, band is: 76 94 1 + Current sample, line, band is: 77 94 1 + Current sample, line, band is: 78 94 1 + Current sample, line, band is: 79 94 1 + Current sample, line, band is: 80 94 1 + Current sample, line, band is: 81 94 1 + Current sample, line, band is: 82 94 1 + Current sample, line, band is: 83 94 1 + Current sample, line, band is: 84 94 1 + Current sample, line, band is: 85 94 1 + Current sample, line, band is: 86 94 1 + Current sample, line, band is: 87 94 1 + Current sample, line, band is: 88 94 1 + Current sample, line, band is: 89 94 1 + Current sample, line, band is: 90 94 1 + Current sample, line, band is: 91 94 1 + Current sample, line, band is: 92 94 1 + Current sample, line, band is: 93 94 1 + Current sample, line, band is: 94 94 1 + Current sample, line, band is: 95 94 1 + Current sample, line, band is: 96 94 1 + Current sample, line, band is: 97 94 1 + Current sample, line, band is: 98 94 1 + Current sample, line, band is: 99 94 1 + Current sample, line, band is: 100 94 1 + Current sample, line, band is: 101 94 1 + Current sample, line, band is: 102 94 1 + Current sample, line, band is: 103 94 1 + Current sample, line, band is: 104 94 1 + Current sample, line, band is: 105 94 1 + Current sample, line, band is: 106 94 1 + Current sample, line, band is: 107 94 1 + Current sample, line, band is: 108 94 1 + Current sample, line, band is: 109 94 1 + Current sample, line, band is: 110 94 1 + Current sample, line, band is: 111 94 1 + Current sample, line, band is: 112 94 1 + Current sample, line, band is: 113 94 1 + Current sample, line, band is: 114 94 1 + Current sample, line, band is: 115 94 1 + Current sample, line, band is: 116 94 1 + Current sample, line, band is: 117 94 1 + Current sample, line, band is: 118 94 1 + Current sample, line, band is: 119 94 1 + Current sample, line, band is: 120 94 1 + Current sample, line, band is: 121 94 1 + Current sample, line, band is: 122 94 1 + Current sample, line, band is: 123 94 1 + Current sample, line, band is: 124 94 1 + Current sample, line, band is: 125 94 1 + Current sample, line, band is: 126 94 1 + Current sample, line, band is: 1 95 1 + Current sample, line, band is: 2 95 1 + Current sample, line, band is: 3 95 1 + Current sample, line, band is: 4 95 1 + Current sample, line, band is: 5 95 1 + Current sample, line, band is: 6 95 1 + Current sample, line, band is: 7 95 1 + Current sample, line, band is: 8 95 1 + Current sample, line, band is: 9 95 1 + Current sample, line, band is: 10 95 1 + Current sample, line, band is: 11 95 1 + Current sample, line, band is: 12 95 1 + Current sample, line, band is: 13 95 1 + Current sample, line, band is: 14 95 1 + Current sample, line, band is: 15 95 1 + Current sample, line, band is: 16 95 1 + Current sample, line, band is: 17 95 1 + Current sample, line, band is: 18 95 1 + Current sample, line, band is: 19 95 1 + Current sample, line, band is: 20 95 1 + Current sample, line, band is: 21 95 1 + Current sample, line, band is: 22 95 1 + Current sample, line, band is: 23 95 1 + Current sample, line, band is: 24 95 1 + Current sample, line, band is: 25 95 1 + Current sample, line, band is: 26 95 1 + Current sample, line, band is: 27 95 1 + Current sample, line, band is: 28 95 1 + Current sample, line, band is: 29 95 1 + Current sample, line, band is: 30 95 1 + Current sample, line, band is: 31 95 1 + Current sample, line, band is: 32 95 1 + Current sample, line, band is: 33 95 1 + Current sample, line, band is: 34 95 1 + Current sample, line, band is: 35 95 1 + Current sample, line, band is: 36 95 1 + Current sample, line, band is: 37 95 1 + Current sample, line, band is: 38 95 1 + Current sample, line, band is: 39 95 1 + Current sample, line, band is: 40 95 1 + Current sample, line, band is: 41 95 1 + Current sample, line, band is: 42 95 1 + Current sample, line, band is: 43 95 1 + Current sample, line, band is: 44 95 1 + Current sample, line, band is: 45 95 1 + Current sample, line, band is: 46 95 1 + Current sample, line, band is: 47 95 1 + Current sample, line, band is: 48 95 1 + Current sample, line, band is: 49 95 1 + Current sample, line, band is: 50 95 1 + Current sample, line, band is: 51 95 1 + Current sample, line, band is: 52 95 1 + Current sample, line, band is: 53 95 1 + Current sample, line, band is: 54 95 1 + Current sample, line, band is: 55 95 1 + Current sample, line, band is: 56 95 1 + Current sample, line, band is: 57 95 1 + Current sample, line, band is: 58 95 1 + Current sample, line, band is: 59 95 1 + Current sample, line, band is: 60 95 1 + Current sample, line, band is: 61 95 1 + Current sample, line, band is: 62 95 1 + Current sample, line, band is: 63 95 1 + Current sample, line, band is: 64 95 1 + Current sample, line, band is: 65 95 1 + Current sample, line, band is: 66 95 1 + Current sample, line, band is: 67 95 1 + Current sample, line, band is: 68 95 1 + Current sample, line, band is: 69 95 1 + Current sample, line, band is: 70 95 1 + Current sample, line, band is: 71 95 1 + Current sample, line, band is: 72 95 1 + Current sample, line, band is: 73 95 1 + Current sample, line, band is: 74 95 1 + Current sample, line, band is: 75 95 1 + Current sample, line, band is: 76 95 1 + Current sample, line, band is: 77 95 1 + Current sample, line, band is: 78 95 1 + Current sample, line, band is: 79 95 1 + Current sample, line, band is: 80 95 1 + Current sample, line, band is: 81 95 1 + Current sample, line, band is: 82 95 1 + Current sample, line, band is: 83 95 1 + Current sample, line, band is: 84 95 1 + Current sample, line, band is: 85 95 1 + Current sample, line, band is: 86 95 1 + Current sample, line, band is: 87 95 1 + Current sample, line, band is: 88 95 1 + Current sample, line, band is: 89 95 1 + Current sample, line, band is: 90 95 1 + Current sample, line, band is: 91 95 1 + Current sample, line, band is: 92 95 1 + Current sample, line, band is: 93 95 1 + Current sample, line, band is: 94 95 1 + Current sample, line, band is: 95 95 1 + Current sample, line, band is: 96 95 1 + Current sample, line, band is: 97 95 1 + Current sample, line, band is: 98 95 1 + Current sample, line, band is: 99 95 1 + Current sample, line, band is: 100 95 1 + Current sample, line, band is: 101 95 1 + Current sample, line, band is: 102 95 1 + Current sample, line, band is: 103 95 1 + Current sample, line, band is: 104 95 1 + Current sample, line, band is: 105 95 1 + Current sample, line, band is: 106 95 1 + Current sample, line, band is: 107 95 1 + Current sample, line, band is: 108 95 1 + Current sample, line, band is: 109 95 1 + Current sample, line, band is: 110 95 1 + Current sample, line, band is: 111 95 1 + Current sample, line, band is: 112 95 1 + Current sample, line, band is: 113 95 1 + Current sample, line, band is: 114 95 1 + Current sample, line, band is: 115 95 1 + Current sample, line, band is: 116 95 1 + Current sample, line, band is: 117 95 1 + Current sample, line, band is: 118 95 1 + Current sample, line, band is: 119 95 1 + Current sample, line, band is: 120 95 1 + Current sample, line, band is: 121 95 1 + Current sample, line, band is: 122 95 1 + Current sample, line, band is: 123 95 1 + Current sample, line, band is: 124 95 1 + Current sample, line, band is: 125 95 1 + Current sample, line, band is: 126 95 1 + Current sample, line, band is: 1 96 1 + Current sample, line, band is: 2 96 1 + Current sample, line, band is: 3 96 1 + Current sample, line, band is: 4 96 1 + Current sample, line, band is: 5 96 1 + Current sample, line, band is: 6 96 1 + Current sample, line, band is: 7 96 1 + Current sample, line, band is: 8 96 1 + Current sample, line, band is: 9 96 1 + Current sample, line, band is: 10 96 1 + Current sample, line, band is: 11 96 1 + Current sample, line, band is: 12 96 1 + Current sample, line, band is: 13 96 1 + Current sample, line, band is: 14 96 1 + Current sample, line, band is: 15 96 1 + Current sample, line, band is: 16 96 1 + Current sample, line, band is: 17 96 1 + Current sample, line, band is: 18 96 1 + Current sample, line, band is: 19 96 1 + Current sample, line, band is: 20 96 1 + Current sample, line, band is: 21 96 1 + Current sample, line, band is: 22 96 1 + Current sample, line, band is: 23 96 1 + Current sample, line, band is: 24 96 1 + Current sample, line, band is: 25 96 1 + Current sample, line, band is: 26 96 1 + Current sample, line, band is: 27 96 1 + Current sample, line, band is: 28 96 1 + Current sample, line, band is: 29 96 1 + Current sample, line, band is: 30 96 1 + Current sample, line, band is: 31 96 1 + Current sample, line, band is: 32 96 1 + Current sample, line, band is: 33 96 1 + Current sample, line, band is: 34 96 1 + Current sample, line, band is: 35 96 1 + Current sample, line, band is: 36 96 1 + Current sample, line, band is: 37 96 1 + Current sample, line, band is: 38 96 1 + Current sample, line, band is: 39 96 1 + Current sample, line, band is: 40 96 1 + Current sample, line, band is: 41 96 1 + Current sample, line, band is: 42 96 1 + Current sample, line, band is: 43 96 1 + Current sample, line, band is: 44 96 1 + Current sample, line, band is: 45 96 1 + Current sample, line, band is: 46 96 1 + Current sample, line, band is: 47 96 1 + Current sample, line, band is: 48 96 1 + Current sample, line, band is: 49 96 1 + Current sample, line, band is: 50 96 1 + Current sample, line, band is: 51 96 1 + Current sample, line, band is: 52 96 1 + Current sample, line, band is: 53 96 1 + Current sample, line, band is: 54 96 1 + Current sample, line, band is: 55 96 1 + Current sample, line, band is: 56 96 1 + Current sample, line, band is: 57 96 1 + Current sample, line, band is: 58 96 1 + Current sample, line, band is: 59 96 1 + Current sample, line, band is: 60 96 1 + Current sample, line, band is: 61 96 1 + Current sample, line, band is: 62 96 1 + Current sample, line, band is: 63 96 1 + Current sample, line, band is: 64 96 1 + Current sample, line, band is: 65 96 1 + Current sample, line, band is: 66 96 1 + Current sample, line, band is: 67 96 1 + Current sample, line, band is: 68 96 1 + Current sample, line, band is: 69 96 1 + Current sample, line, band is: 70 96 1 + Current sample, line, band is: 71 96 1 + Current sample, line, band is: 72 96 1 + Current sample, line, band is: 73 96 1 + Current sample, line, band is: 74 96 1 + Current sample, line, band is: 75 96 1 + Current sample, line, band is: 76 96 1 + Current sample, line, band is: 77 96 1 + Current sample, line, band is: 78 96 1 + Current sample, line, band is: 79 96 1 + Current sample, line, band is: 80 96 1 + Current sample, line, band is: 81 96 1 + Current sample, line, band is: 82 96 1 + Current sample, line, band is: 83 96 1 + Current sample, line, band is: 84 96 1 + Current sample, line, band is: 85 96 1 + Current sample, line, band is: 86 96 1 + Current sample, line, band is: 87 96 1 + Current sample, line, band is: 88 96 1 + Current sample, line, band is: 89 96 1 + Current sample, line, band is: 90 96 1 + Current sample, line, band is: 91 96 1 + Current sample, line, band is: 92 96 1 + Current sample, line, band is: 93 96 1 + Current sample, line, band is: 94 96 1 + Current sample, line, band is: 95 96 1 + Current sample, line, band is: 96 96 1 + Current sample, line, band is: 97 96 1 + Current sample, line, band is: 98 96 1 + Current sample, line, band is: 99 96 1 + Current sample, line, band is: 100 96 1 + Current sample, line, band is: 101 96 1 + Current sample, line, band is: 102 96 1 + Current sample, line, band is: 103 96 1 + Current sample, line, band is: 104 96 1 + Current sample, line, band is: 105 96 1 + Current sample, line, band is: 106 96 1 + Current sample, line, band is: 107 96 1 + Current sample, line, band is: 108 96 1 + Current sample, line, band is: 109 96 1 + Current sample, line, band is: 110 96 1 + Current sample, line, band is: 111 96 1 + Current sample, line, band is: 112 96 1 + Current sample, line, band is: 113 96 1 + Current sample, line, band is: 114 96 1 + Current sample, line, band is: 115 96 1 + Current sample, line, band is: 116 96 1 + Current sample, line, band is: 117 96 1 + Current sample, line, band is: 118 96 1 + Current sample, line, band is: 119 96 1 + Current sample, line, band is: 120 96 1 + Current sample, line, band is: 121 96 1 + Current sample, line, band is: 122 96 1 + Current sample, line, band is: 123 96 1 + Current sample, line, band is: 124 96 1 + Current sample, line, band is: 125 96 1 + Current sample, line, band is: 126 96 1 + Current sample, line, band is: 1 97 1 + Current sample, line, band is: 2 97 1 + Current sample, line, band is: 3 97 1 + Current sample, line, band is: 4 97 1 + Current sample, line, band is: 5 97 1 + Current sample, line, band is: 6 97 1 + Current sample, line, band is: 7 97 1 + Current sample, line, band is: 8 97 1 + Current sample, line, band is: 9 97 1 + Current sample, line, band is: 10 97 1 + Current sample, line, band is: 11 97 1 + Current sample, line, band is: 12 97 1 + Current sample, line, band is: 13 97 1 + Current sample, line, band is: 14 97 1 + Current sample, line, band is: 15 97 1 + Current sample, line, band is: 16 97 1 + Current sample, line, band is: 17 97 1 + Current sample, line, band is: 18 97 1 + Current sample, line, band is: 19 97 1 + Current sample, line, band is: 20 97 1 + Current sample, line, band is: 21 97 1 + Current sample, line, band is: 22 97 1 + Current sample, line, band is: 23 97 1 + Current sample, line, band is: 24 97 1 + Current sample, line, band is: 25 97 1 + Current sample, line, band is: 26 97 1 + Current sample, line, band is: 27 97 1 + Current sample, line, band is: 28 97 1 + Current sample, line, band is: 29 97 1 + Current sample, line, band is: 30 97 1 + Current sample, line, band is: 31 97 1 + Current sample, line, band is: 32 97 1 + Current sample, line, band is: 33 97 1 + Current sample, line, band is: 34 97 1 + Current sample, line, band is: 35 97 1 + Current sample, line, band is: 36 97 1 + Current sample, line, band is: 37 97 1 + Current sample, line, band is: 38 97 1 + Current sample, line, band is: 39 97 1 + Current sample, line, band is: 40 97 1 + Current sample, line, band is: 41 97 1 + Current sample, line, band is: 42 97 1 + Current sample, line, band is: 43 97 1 + Current sample, line, band is: 44 97 1 + Current sample, line, band is: 45 97 1 + Current sample, line, band is: 46 97 1 + Current sample, line, band is: 47 97 1 + Current sample, line, band is: 48 97 1 + Current sample, line, band is: 49 97 1 + Current sample, line, band is: 50 97 1 + Current sample, line, band is: 51 97 1 + Current sample, line, band is: 52 97 1 + Current sample, line, band is: 53 97 1 + Current sample, line, band is: 54 97 1 + Current sample, line, band is: 55 97 1 + Current sample, line, band is: 56 97 1 + Current sample, line, band is: 57 97 1 + Current sample, line, band is: 58 97 1 + Current sample, line, band is: 59 97 1 + Current sample, line, band is: 60 97 1 + Current sample, line, band is: 61 97 1 + Current sample, line, band is: 62 97 1 + Current sample, line, band is: 63 97 1 + Current sample, line, band is: 64 97 1 + Current sample, line, band is: 65 97 1 + Current sample, line, band is: 66 97 1 + Current sample, line, band is: 67 97 1 + Current sample, line, band is: 68 97 1 + Current sample, line, band is: 69 97 1 + Current sample, line, band is: 70 97 1 + Current sample, line, band is: 71 97 1 + Current sample, line, band is: 72 97 1 + Current sample, line, band is: 73 97 1 + Current sample, line, band is: 74 97 1 + Current sample, line, band is: 75 97 1 + Current sample, line, band is: 76 97 1 + Current sample, line, band is: 77 97 1 + Current sample, line, band is: 78 97 1 + Current sample, line, band is: 79 97 1 + Current sample, line, band is: 80 97 1 + Current sample, line, band is: 81 97 1 + Current sample, line, band is: 82 97 1 + Current sample, line, band is: 83 97 1 + Current sample, line, band is: 84 97 1 + Current sample, line, band is: 85 97 1 + Current sample, line, band is: 86 97 1 + Current sample, line, band is: 87 97 1 + Current sample, line, band is: 88 97 1 + Current sample, line, band is: 89 97 1 + Current sample, line, band is: 90 97 1 + Current sample, line, band is: 91 97 1 + Current sample, line, band is: 92 97 1 + Current sample, line, band is: 93 97 1 + Current sample, line, band is: 94 97 1 + Current sample, line, band is: 95 97 1 + Current sample, line, band is: 96 97 1 + Current sample, line, band is: 97 97 1 + Current sample, line, band is: 98 97 1 + Current sample, line, band is: 99 97 1 + Current sample, line, band is: 100 97 1 + Current sample, line, band is: 101 97 1 + Current sample, line, band is: 102 97 1 + Current sample, line, band is: 103 97 1 + Current sample, line, band is: 104 97 1 + Current sample, line, band is: 105 97 1 + Current sample, line, band is: 106 97 1 + Current sample, line, band is: 107 97 1 + Current sample, line, band is: 108 97 1 + Current sample, line, band is: 109 97 1 + Current sample, line, band is: 110 97 1 + Current sample, line, band is: 111 97 1 + Current sample, line, band is: 112 97 1 + Current sample, line, band is: 113 97 1 + Current sample, line, band is: 114 97 1 + Current sample, line, band is: 115 97 1 + Current sample, line, band is: 116 97 1 + Current sample, line, band is: 117 97 1 + Current sample, line, band is: 118 97 1 + Current sample, line, band is: 119 97 1 + Current sample, line, band is: 120 97 1 + Current sample, line, band is: 121 97 1 + Current sample, line, band is: 122 97 1 + Current sample, line, band is: 123 97 1 + Current sample, line, band is: 124 97 1 + Current sample, line, band is: 125 97 1 + Current sample, line, band is: 126 97 1 + Current sample, line, band is: 1 98 1 + Current sample, line, band is: 2 98 1 + Current sample, line, band is: 3 98 1 + Current sample, line, band is: 4 98 1 + Current sample, line, band is: 5 98 1 + Current sample, line, band is: 6 98 1 + Current sample, line, band is: 7 98 1 + Current sample, line, band is: 8 98 1 + Current sample, line, band is: 9 98 1 + Current sample, line, band is: 10 98 1 + Current sample, line, band is: 11 98 1 + Current sample, line, band is: 12 98 1 + Current sample, line, band is: 13 98 1 + Current sample, line, band is: 14 98 1 + Current sample, line, band is: 15 98 1 + Current sample, line, band is: 16 98 1 + Current sample, line, band is: 17 98 1 + Current sample, line, band is: 18 98 1 + Current sample, line, band is: 19 98 1 + Current sample, line, band is: 20 98 1 + Current sample, line, band is: 21 98 1 + Current sample, line, band is: 22 98 1 + Current sample, line, band is: 23 98 1 + Current sample, line, band is: 24 98 1 + Current sample, line, band is: 25 98 1 + Current sample, line, band is: 26 98 1 + Current sample, line, band is: 27 98 1 + Current sample, line, band is: 28 98 1 + Current sample, line, band is: 29 98 1 + Current sample, line, band is: 30 98 1 + Current sample, line, band is: 31 98 1 + Current sample, line, band is: 32 98 1 + Current sample, line, band is: 33 98 1 + Current sample, line, band is: 34 98 1 + Current sample, line, band is: 35 98 1 + Current sample, line, band is: 36 98 1 + Current sample, line, band is: 37 98 1 + Current sample, line, band is: 38 98 1 + Current sample, line, band is: 39 98 1 + Current sample, line, band is: 40 98 1 + Current sample, line, band is: 41 98 1 + Current sample, line, band is: 42 98 1 + Current sample, line, band is: 43 98 1 + Current sample, line, band is: 44 98 1 + Current sample, line, band is: 45 98 1 + Current sample, line, band is: 46 98 1 + Current sample, line, band is: 47 98 1 + Current sample, line, band is: 48 98 1 + Current sample, line, band is: 49 98 1 + Current sample, line, band is: 50 98 1 + Current sample, line, band is: 51 98 1 + Current sample, line, band is: 52 98 1 + Current sample, line, band is: 53 98 1 + Current sample, line, band is: 54 98 1 + Current sample, line, band is: 55 98 1 + Current sample, line, band is: 56 98 1 + Current sample, line, band is: 57 98 1 + Current sample, line, band is: 58 98 1 + Current sample, line, band is: 59 98 1 + Current sample, line, band is: 60 98 1 + Current sample, line, band is: 61 98 1 + Current sample, line, band is: 62 98 1 + Current sample, line, band is: 63 98 1 + Current sample, line, band is: 64 98 1 + Current sample, line, band is: 65 98 1 + Current sample, line, band is: 66 98 1 + Current sample, line, band is: 67 98 1 + Current sample, line, band is: 68 98 1 + Current sample, line, band is: 69 98 1 + Current sample, line, band is: 70 98 1 + Current sample, line, band is: 71 98 1 + Current sample, line, band is: 72 98 1 + Current sample, line, band is: 73 98 1 + Current sample, line, band is: 74 98 1 + Current sample, line, band is: 75 98 1 + Current sample, line, band is: 76 98 1 + Current sample, line, band is: 77 98 1 + Current sample, line, band is: 78 98 1 + Current sample, line, band is: 79 98 1 + Current sample, line, band is: 80 98 1 + Current sample, line, band is: 81 98 1 + Current sample, line, band is: 82 98 1 + Current sample, line, band is: 83 98 1 + Current sample, line, band is: 84 98 1 + Current sample, line, band is: 85 98 1 + Current sample, line, band is: 86 98 1 + Current sample, line, band is: 87 98 1 + Current sample, line, band is: 88 98 1 + Current sample, line, band is: 89 98 1 + Current sample, line, band is: 90 98 1 + Current sample, line, band is: 91 98 1 + Current sample, line, band is: 92 98 1 + Current sample, line, band is: 93 98 1 + Current sample, line, band is: 94 98 1 + Current sample, line, band is: 95 98 1 + Current sample, line, band is: 96 98 1 + Current sample, line, band is: 97 98 1 + Current sample, line, band is: 98 98 1 + Current sample, line, band is: 99 98 1 + Current sample, line, band is: 100 98 1 + Current sample, line, band is: 101 98 1 + Current sample, line, band is: 102 98 1 + Current sample, line, band is: 103 98 1 + Current sample, line, band is: 104 98 1 + Current sample, line, band is: 105 98 1 + Current sample, line, band is: 106 98 1 + Current sample, line, band is: 107 98 1 + Current sample, line, band is: 108 98 1 + Current sample, line, band is: 109 98 1 + Current sample, line, band is: 110 98 1 + Current sample, line, band is: 111 98 1 + Current sample, line, band is: 112 98 1 + Current sample, line, band is: 113 98 1 + Current sample, line, band is: 114 98 1 + Current sample, line, band is: 115 98 1 + Current sample, line, band is: 116 98 1 + Current sample, line, band is: 117 98 1 + Current sample, line, band is: 118 98 1 + Current sample, line, band is: 119 98 1 + Current sample, line, band is: 120 98 1 + Current sample, line, band is: 121 98 1 + Current sample, line, band is: 122 98 1 + Current sample, line, band is: 123 98 1 + Current sample, line, band is: 124 98 1 + Current sample, line, band is: 125 98 1 + Current sample, line, band is: 126 98 1 + Current sample, line, band is: 1 99 1 + Current sample, line, band is: 2 99 1 + Current sample, line, band is: 3 99 1 + Current sample, line, band is: 4 99 1 + Current sample, line, band is: 5 99 1 + Current sample, line, band is: 6 99 1 + Current sample, line, band is: 7 99 1 + Current sample, line, band is: 8 99 1 + Current sample, line, band is: 9 99 1 + Current sample, line, band is: 10 99 1 + Current sample, line, band is: 11 99 1 + Current sample, line, band is: 12 99 1 + Current sample, line, band is: 13 99 1 + Current sample, line, band is: 14 99 1 + Current sample, line, band is: 15 99 1 + Current sample, line, band is: 16 99 1 + Current sample, line, band is: 17 99 1 + Current sample, line, band is: 18 99 1 + Current sample, line, band is: 19 99 1 + Current sample, line, band is: 20 99 1 + Current sample, line, band is: 21 99 1 + Current sample, line, band is: 22 99 1 + Current sample, line, band is: 23 99 1 + Current sample, line, band is: 24 99 1 + Current sample, line, band is: 25 99 1 + Current sample, line, band is: 26 99 1 + Current sample, line, band is: 27 99 1 + Current sample, line, band is: 28 99 1 + Current sample, line, band is: 29 99 1 + Current sample, line, band is: 30 99 1 + Current sample, line, band is: 31 99 1 + Current sample, line, band is: 32 99 1 + Current sample, line, band is: 33 99 1 + Current sample, line, band is: 34 99 1 + Current sample, line, band is: 35 99 1 + Current sample, line, band is: 36 99 1 + Current sample, line, band is: 37 99 1 + Current sample, line, band is: 38 99 1 + Current sample, line, band is: 39 99 1 + Current sample, line, band is: 40 99 1 + Current sample, line, band is: 41 99 1 + Current sample, line, band is: 42 99 1 + Current sample, line, band is: 43 99 1 + Current sample, line, band is: 44 99 1 + Current sample, line, band is: 45 99 1 + Current sample, line, band is: 46 99 1 + Current sample, line, band is: 47 99 1 + Current sample, line, band is: 48 99 1 + Current sample, line, band is: 49 99 1 + Current sample, line, band is: 50 99 1 + Current sample, line, band is: 51 99 1 + Current sample, line, band is: 52 99 1 + Current sample, line, band is: 53 99 1 + Current sample, line, band is: 54 99 1 + Current sample, line, band is: 55 99 1 + Current sample, line, band is: 56 99 1 + Current sample, line, band is: 57 99 1 + Current sample, line, band is: 58 99 1 + Current sample, line, band is: 59 99 1 + Current sample, line, band is: 60 99 1 + Current sample, line, band is: 61 99 1 + Current sample, line, band is: 62 99 1 + Current sample, line, band is: 63 99 1 + Current sample, line, band is: 64 99 1 + Current sample, line, band is: 65 99 1 + Current sample, line, band is: 66 99 1 + Current sample, line, band is: 67 99 1 + Current sample, line, band is: 68 99 1 + Current sample, line, band is: 69 99 1 + Current sample, line, band is: 70 99 1 + Current sample, line, band is: 71 99 1 + Current sample, line, band is: 72 99 1 + Current sample, line, band is: 73 99 1 + Current sample, line, band is: 74 99 1 + Current sample, line, band is: 75 99 1 + Current sample, line, band is: 76 99 1 + Current sample, line, band is: 77 99 1 + Current sample, line, band is: 78 99 1 + Current sample, line, band is: 79 99 1 + Current sample, line, band is: 80 99 1 + Current sample, line, band is: 81 99 1 + Current sample, line, band is: 82 99 1 + Current sample, line, band is: 83 99 1 + Current sample, line, band is: 84 99 1 + Current sample, line, band is: 85 99 1 + Current sample, line, band is: 86 99 1 + Current sample, line, band is: 87 99 1 + Current sample, line, band is: 88 99 1 + Current sample, line, band is: 89 99 1 + Current sample, line, band is: 90 99 1 + Current sample, line, band is: 91 99 1 + Current sample, line, band is: 92 99 1 + Current sample, line, band is: 93 99 1 + Current sample, line, band is: 94 99 1 + Current sample, line, band is: 95 99 1 + Current sample, line, band is: 96 99 1 + Current sample, line, band is: 97 99 1 + Current sample, line, band is: 98 99 1 + Current sample, line, band is: 99 99 1 + Current sample, line, band is: 100 99 1 + Current sample, line, band is: 101 99 1 + Current sample, line, band is: 102 99 1 + Current sample, line, band is: 103 99 1 + Current sample, line, band is: 104 99 1 + Current sample, line, band is: 105 99 1 + Current sample, line, band is: 106 99 1 + Current sample, line, band is: 107 99 1 + Current sample, line, band is: 108 99 1 + Current sample, line, band is: 109 99 1 + Current sample, line, band is: 110 99 1 + Current sample, line, band is: 111 99 1 + Current sample, line, band is: 112 99 1 + Current sample, line, band is: 113 99 1 + Current sample, line, band is: 114 99 1 + Current sample, line, band is: 115 99 1 + Current sample, line, band is: 116 99 1 + Current sample, line, band is: 117 99 1 + Current sample, line, band is: 118 99 1 + Current sample, line, band is: 119 99 1 + Current sample, line, band is: 120 99 1 + Current sample, line, band is: 121 99 1 + Current sample, line, band is: 122 99 1 + Current sample, line, band is: 123 99 1 + Current sample, line, band is: 124 99 1 + Current sample, line, band is: 125 99 1 + Current sample, line, band is: 126 99 1 + Current sample, line, band is: 1 100 1 + Current sample, line, band is: 2 100 1 + Current sample, line, band is: 3 100 1 + Current sample, line, band is: 4 100 1 + Current sample, line, band is: 5 100 1 + Current sample, line, band is: 6 100 1 + Current sample, line, band is: 7 100 1 + Current sample, line, band is: 8 100 1 + Current sample, line, band is: 9 100 1 + Current sample, line, band is: 10 100 1 + Current sample, line, band is: 11 100 1 + Current sample, line, band is: 12 100 1 + Current sample, line, band is: 13 100 1 + Current sample, line, band is: 14 100 1 + Current sample, line, band is: 15 100 1 + Current sample, line, band is: 16 100 1 + Current sample, line, band is: 17 100 1 + Current sample, line, band is: 18 100 1 + Current sample, line, band is: 19 100 1 + Current sample, line, band is: 20 100 1 + Current sample, line, band is: 21 100 1 + Current sample, line, band is: 22 100 1 + Current sample, line, band is: 23 100 1 + Current sample, line, band is: 24 100 1 + Current sample, line, band is: 25 100 1 + Current sample, line, band is: 26 100 1 + Current sample, line, band is: 27 100 1 + Current sample, line, band is: 28 100 1 + Current sample, line, band is: 29 100 1 + Current sample, line, band is: 30 100 1 + Current sample, line, band is: 31 100 1 + Current sample, line, band is: 32 100 1 + Current sample, line, band is: 33 100 1 + Current sample, line, band is: 34 100 1 + Current sample, line, band is: 35 100 1 + Current sample, line, band is: 36 100 1 + Current sample, line, band is: 37 100 1 + Current sample, line, band is: 38 100 1 + Current sample, line, band is: 39 100 1 + Current sample, line, band is: 40 100 1 + Current sample, line, band is: 41 100 1 + Current sample, line, band is: 42 100 1 + Current sample, line, band is: 43 100 1 + Current sample, line, band is: 44 100 1 + Current sample, line, band is: 45 100 1 + Current sample, line, band is: 46 100 1 + Current sample, line, band is: 47 100 1 + Current sample, line, band is: 48 100 1 + Current sample, line, band is: 49 100 1 + Current sample, line, band is: 50 100 1 + Current sample, line, band is: 51 100 1 + Current sample, line, band is: 52 100 1 + Current sample, line, band is: 53 100 1 + Current sample, line, band is: 54 100 1 + Current sample, line, band is: 55 100 1 + Current sample, line, band is: 56 100 1 + Current sample, line, band is: 57 100 1 + Current sample, line, band is: 58 100 1 + Current sample, line, band is: 59 100 1 + Current sample, line, band is: 60 100 1 + Current sample, line, band is: 61 100 1 + Current sample, line, band is: 62 100 1 + Current sample, line, band is: 63 100 1 + Current sample, line, band is: 64 100 1 + Current sample, line, band is: 65 100 1 + Current sample, line, band is: 66 100 1 + Current sample, line, band is: 67 100 1 + Current sample, line, band is: 68 100 1 + Current sample, line, band is: 69 100 1 + Current sample, line, band is: 70 100 1 + Current sample, line, band is: 71 100 1 + Current sample, line, band is: 72 100 1 + Current sample, line, band is: 73 100 1 + Current sample, line, band is: 74 100 1 + Current sample, line, band is: 75 100 1 + Current sample, line, band is: 76 100 1 + Current sample, line, band is: 77 100 1 + Current sample, line, band is: 78 100 1 + Current sample, line, band is: 79 100 1 + Current sample, line, band is: 80 100 1 + Current sample, line, band is: 81 100 1 + Current sample, line, band is: 82 100 1 + Current sample, line, band is: 83 100 1 + Current sample, line, band is: 84 100 1 + Current sample, line, band is: 85 100 1 + Current sample, line, band is: 86 100 1 + Current sample, line, band is: 87 100 1 + Current sample, line, band is: 88 100 1 + Current sample, line, band is: 89 100 1 + Current sample, line, band is: 90 100 1 + Current sample, line, band is: 91 100 1 + Current sample, line, band is: 92 100 1 + Current sample, line, band is: 93 100 1 + Current sample, line, band is: 94 100 1 + Current sample, line, band is: 95 100 1 + Current sample, line, band is: 96 100 1 + Current sample, line, band is: 97 100 1 + Current sample, line, band is: 98 100 1 + Current sample, line, band is: 99 100 1 + Current sample, line, band is: 100 100 1 + Current sample, line, band is: 101 100 1 + Current sample, line, band is: 102 100 1 + Current sample, line, band is: 103 100 1 + Current sample, line, band is: 104 100 1 + Current sample, line, band is: 105 100 1 + Current sample, line, band is: 106 100 1 + Current sample, line, band is: 107 100 1 + Current sample, line, band is: 108 100 1 + Current sample, line, band is: 109 100 1 + Current sample, line, band is: 110 100 1 + Current sample, line, band is: 111 100 1 + Current sample, line, band is: 112 100 1 + Current sample, line, band is: 113 100 1 + Current sample, line, band is: 114 100 1 + Current sample, line, band is: 115 100 1 + Current sample, line, band is: 116 100 1 + Current sample, line, band is: 117 100 1 + Current sample, line, band is: 118 100 1 + Current sample, line, band is: 119 100 1 + Current sample, line, band is: 120 100 1 + Current sample, line, band is: 121 100 1 + Current sample, line, band is: 122 100 1 + Current sample, line, band is: 123 100 1 + Current sample, line, band is: 124 100 1 + Current sample, line, band is: 125 100 1 + Current sample, line, band is: 126 100 1 + Current sample, line, band is: 1 101 1 + Current sample, line, band is: 2 101 1 + Current sample, line, band is: 3 101 1 + Current sample, line, band is: 4 101 1 + Current sample, line, band is: 5 101 1 + Current sample, line, band is: 6 101 1 + Current sample, line, band is: 7 101 1 + Current sample, line, band is: 8 101 1 + Current sample, line, band is: 9 101 1 + Current sample, line, band is: 10 101 1 + Current sample, line, band is: 11 101 1 + Current sample, line, band is: 12 101 1 + Current sample, line, band is: 13 101 1 + Current sample, line, band is: 14 101 1 + Current sample, line, band is: 15 101 1 + Current sample, line, band is: 16 101 1 + Current sample, line, band is: 17 101 1 + Current sample, line, band is: 18 101 1 + Current sample, line, band is: 19 101 1 + Current sample, line, band is: 20 101 1 + Current sample, line, band is: 21 101 1 + Current sample, line, band is: 22 101 1 + Current sample, line, band is: 23 101 1 + Current sample, line, band is: 24 101 1 + Current sample, line, band is: 25 101 1 + Current sample, line, band is: 26 101 1 + Current sample, line, band is: 27 101 1 + Current sample, line, band is: 28 101 1 + Current sample, line, band is: 29 101 1 + Current sample, line, band is: 30 101 1 + Current sample, line, band is: 31 101 1 + Current sample, line, band is: 32 101 1 + Current sample, line, band is: 33 101 1 + Current sample, line, band is: 34 101 1 + Current sample, line, band is: 35 101 1 + Current sample, line, band is: 36 101 1 + Current sample, line, band is: 37 101 1 + Current sample, line, band is: 38 101 1 + Current sample, line, band is: 39 101 1 + Current sample, line, band is: 40 101 1 + Current sample, line, band is: 41 101 1 + Current sample, line, band is: 42 101 1 + Current sample, line, band is: 43 101 1 + Current sample, line, band is: 44 101 1 + Current sample, line, band is: 45 101 1 + Current sample, line, band is: 46 101 1 + Current sample, line, band is: 47 101 1 + Current sample, line, band is: 48 101 1 + Current sample, line, band is: 49 101 1 + Current sample, line, band is: 50 101 1 + Current sample, line, band is: 51 101 1 + Current sample, line, band is: 52 101 1 + Current sample, line, band is: 53 101 1 + Current sample, line, band is: 54 101 1 + Current sample, line, band is: 55 101 1 + Current sample, line, band is: 56 101 1 + Current sample, line, band is: 57 101 1 + Current sample, line, band is: 58 101 1 + Current sample, line, band is: 59 101 1 + Current sample, line, band is: 60 101 1 + Current sample, line, band is: 61 101 1 + Current sample, line, band is: 62 101 1 + Current sample, line, band is: 63 101 1 + Current sample, line, band is: 64 101 1 + Current sample, line, band is: 65 101 1 + Current sample, line, band is: 66 101 1 + Current sample, line, band is: 67 101 1 + Current sample, line, band is: 68 101 1 + Current sample, line, band is: 69 101 1 + Current sample, line, band is: 70 101 1 + Current sample, line, band is: 71 101 1 + Current sample, line, band is: 72 101 1 + Current sample, line, band is: 73 101 1 + Current sample, line, band is: 74 101 1 + Current sample, line, band is: 75 101 1 + Current sample, line, band is: 76 101 1 + Current sample, line, band is: 77 101 1 + Current sample, line, band is: 78 101 1 + Current sample, line, band is: 79 101 1 + Current sample, line, band is: 80 101 1 + Current sample, line, band is: 81 101 1 + Current sample, line, band is: 82 101 1 + Current sample, line, band is: 83 101 1 + Current sample, line, band is: 84 101 1 + Current sample, line, band is: 85 101 1 + Current sample, line, band is: 86 101 1 + Current sample, line, band is: 87 101 1 + Current sample, line, band is: 88 101 1 + Current sample, line, band is: 89 101 1 + Current sample, line, band is: 90 101 1 + Current sample, line, band is: 91 101 1 + Current sample, line, band is: 92 101 1 + Current sample, line, band is: 93 101 1 + Current sample, line, band is: 94 101 1 + Current sample, line, band is: 95 101 1 + Current sample, line, band is: 96 101 1 + Current sample, line, band is: 97 101 1 + Current sample, line, band is: 98 101 1 + Current sample, line, band is: 99 101 1 + Current sample, line, band is: 100 101 1 + Current sample, line, band is: 101 101 1 + Current sample, line, band is: 102 101 1 + Current sample, line, band is: 103 101 1 + Current sample, line, band is: 104 101 1 + Current sample, line, band is: 105 101 1 + Current sample, line, band is: 106 101 1 + Current sample, line, band is: 107 101 1 + Current sample, line, band is: 108 101 1 + Current sample, line, band is: 109 101 1 + Current sample, line, band is: 110 101 1 + Current sample, line, band is: 111 101 1 + Current sample, line, band is: 112 101 1 + Current sample, line, band is: 113 101 1 + Current sample, line, band is: 114 101 1 + Current sample, line, band is: 115 101 1 + Current sample, line, band is: 116 101 1 + Current sample, line, band is: 117 101 1 + Current sample, line, band is: 118 101 1 + Current sample, line, band is: 119 101 1 + Current sample, line, band is: 120 101 1 + Current sample, line, band is: 121 101 1 + Current sample, line, band is: 122 101 1 + Current sample, line, band is: 123 101 1 + Current sample, line, band is: 124 101 1 + Current sample, line, band is: 125 101 1 + Current sample, line, band is: 126 101 1 + Current sample, line, band is: 1 102 1 + Current sample, line, band is: 2 102 1 + Current sample, line, band is: 3 102 1 + Current sample, line, band is: 4 102 1 + Current sample, line, band is: 5 102 1 + Current sample, line, band is: 6 102 1 + Current sample, line, band is: 7 102 1 + Current sample, line, band is: 8 102 1 + Current sample, line, band is: 9 102 1 + Current sample, line, band is: 10 102 1 + Current sample, line, band is: 11 102 1 + Current sample, line, band is: 12 102 1 + Current sample, line, band is: 13 102 1 + Current sample, line, band is: 14 102 1 + Current sample, line, band is: 15 102 1 + Current sample, line, band is: 16 102 1 + Current sample, line, band is: 17 102 1 + Current sample, line, band is: 18 102 1 + Current sample, line, band is: 19 102 1 + Current sample, line, band is: 20 102 1 + Current sample, line, band is: 21 102 1 + Current sample, line, band is: 22 102 1 + Current sample, line, band is: 23 102 1 + Current sample, line, band is: 24 102 1 + Current sample, line, band is: 25 102 1 + Current sample, line, band is: 26 102 1 + Current sample, line, band is: 27 102 1 + Current sample, line, band is: 28 102 1 + Current sample, line, band is: 29 102 1 + Current sample, line, band is: 30 102 1 + Current sample, line, band is: 31 102 1 + Current sample, line, band is: 32 102 1 + Current sample, line, band is: 33 102 1 + Current sample, line, band is: 34 102 1 + Current sample, line, band is: 35 102 1 + Current sample, line, band is: 36 102 1 + Current sample, line, band is: 37 102 1 + Current sample, line, band is: 38 102 1 + Current sample, line, band is: 39 102 1 + Current sample, line, band is: 40 102 1 + Current sample, line, band is: 41 102 1 + Current sample, line, band is: 42 102 1 + Current sample, line, band is: 43 102 1 + Current sample, line, band is: 44 102 1 + Current sample, line, band is: 45 102 1 + Current sample, line, band is: 46 102 1 + Current sample, line, band is: 47 102 1 + Current sample, line, band is: 48 102 1 + Current sample, line, band is: 49 102 1 + Current sample, line, band is: 50 102 1 + Current sample, line, band is: 51 102 1 + Current sample, line, band is: 52 102 1 + Current sample, line, band is: 53 102 1 + Current sample, line, band is: 54 102 1 + Current sample, line, band is: 55 102 1 + Current sample, line, band is: 56 102 1 + Current sample, line, band is: 57 102 1 + Current sample, line, band is: 58 102 1 + Current sample, line, band is: 59 102 1 + Current sample, line, band is: 60 102 1 + Current sample, line, band is: 61 102 1 + Current sample, line, band is: 62 102 1 + Current sample, line, band is: 63 102 1 + Current sample, line, band is: 64 102 1 + Current sample, line, band is: 65 102 1 + Current sample, line, band is: 66 102 1 + Current sample, line, band is: 67 102 1 + Current sample, line, band is: 68 102 1 + Current sample, line, band is: 69 102 1 + Current sample, line, band is: 70 102 1 + Current sample, line, band is: 71 102 1 + Current sample, line, band is: 72 102 1 + Current sample, line, band is: 73 102 1 + Current sample, line, band is: 74 102 1 + Current sample, line, band is: 75 102 1 + Current sample, line, band is: 76 102 1 + Current sample, line, band is: 77 102 1 + Current sample, line, band is: 78 102 1 + Current sample, line, band is: 79 102 1 + Current sample, line, band is: 80 102 1 + Current sample, line, band is: 81 102 1 + Current sample, line, band is: 82 102 1 + Current sample, line, band is: 83 102 1 + Current sample, line, band is: 84 102 1 + Current sample, line, band is: 85 102 1 + Current sample, line, band is: 86 102 1 + Current sample, line, band is: 87 102 1 + Current sample, line, band is: 88 102 1 + Current sample, line, band is: 89 102 1 + Current sample, line, band is: 90 102 1 + Current sample, line, band is: 91 102 1 + Current sample, line, band is: 92 102 1 + Current sample, line, band is: 93 102 1 + Current sample, line, band is: 94 102 1 + Current sample, line, band is: 95 102 1 + Current sample, line, band is: 96 102 1 + Current sample, line, band is: 97 102 1 + Current sample, line, band is: 98 102 1 + Current sample, line, band is: 99 102 1 + Current sample, line, band is: 100 102 1 + Current sample, line, band is: 101 102 1 + Current sample, line, band is: 102 102 1 + Current sample, line, band is: 103 102 1 + Current sample, line, band is: 104 102 1 + Current sample, line, band is: 105 102 1 + Current sample, line, band is: 106 102 1 + Current sample, line, band is: 107 102 1 + Current sample, line, band is: 108 102 1 + Current sample, line, band is: 109 102 1 + Current sample, line, band is: 110 102 1 + Current sample, line, band is: 111 102 1 + Current sample, line, band is: 112 102 1 + Current sample, line, band is: 113 102 1 + Current sample, line, band is: 114 102 1 + Current sample, line, band is: 115 102 1 + Current sample, line, band is: 116 102 1 + Current sample, line, band is: 117 102 1 + Current sample, line, band is: 118 102 1 + Current sample, line, band is: 119 102 1 + Current sample, line, band is: 120 102 1 + Current sample, line, band is: 121 102 1 + Current sample, line, band is: 122 102 1 + Current sample, line, band is: 123 102 1 + Current sample, line, band is: 124 102 1 + Current sample, line, band is: 125 102 1 + Current sample, line, band is: 126 102 1 + Current sample, line, band is: 1 103 1 + Current sample, line, band is: 2 103 1 + Current sample, line, band is: 3 103 1 + Current sample, line, band is: 4 103 1 + Current sample, line, band is: 5 103 1 + Current sample, line, band is: 6 103 1 + Current sample, line, band is: 7 103 1 + Current sample, line, band is: 8 103 1 + Current sample, line, band is: 9 103 1 + Current sample, line, band is: 10 103 1 + Current sample, line, band is: 11 103 1 + Current sample, line, band is: 12 103 1 + Current sample, line, band is: 13 103 1 + Current sample, line, band is: 14 103 1 + Current sample, line, band is: 15 103 1 + Current sample, line, band is: 16 103 1 + Current sample, line, band is: 17 103 1 + Current sample, line, band is: 18 103 1 + Current sample, line, band is: 19 103 1 + Current sample, line, band is: 20 103 1 + Current sample, line, band is: 21 103 1 + Current sample, line, band is: 22 103 1 + Current sample, line, band is: 23 103 1 + Current sample, line, band is: 24 103 1 + Current sample, line, band is: 25 103 1 + Current sample, line, band is: 26 103 1 + Current sample, line, band is: 27 103 1 + Current sample, line, band is: 28 103 1 + Current sample, line, band is: 29 103 1 + Current sample, line, band is: 30 103 1 + Current sample, line, band is: 31 103 1 + Current sample, line, band is: 32 103 1 + Current sample, line, band is: 33 103 1 + Current sample, line, band is: 34 103 1 + Current sample, line, band is: 35 103 1 + Current sample, line, band is: 36 103 1 + Current sample, line, band is: 37 103 1 + Current sample, line, band is: 38 103 1 + Current sample, line, band is: 39 103 1 + Current sample, line, band is: 40 103 1 + Current sample, line, band is: 41 103 1 + Current sample, line, band is: 42 103 1 + Current sample, line, band is: 43 103 1 + Current sample, line, band is: 44 103 1 + Current sample, line, band is: 45 103 1 + Current sample, line, band is: 46 103 1 + Current sample, line, band is: 47 103 1 + Current sample, line, band is: 48 103 1 + Current sample, line, band is: 49 103 1 + Current sample, line, band is: 50 103 1 + Current sample, line, band is: 51 103 1 + Current sample, line, band is: 52 103 1 + Current sample, line, band is: 53 103 1 + Current sample, line, band is: 54 103 1 + Current sample, line, band is: 55 103 1 + Current sample, line, band is: 56 103 1 + Current sample, line, band is: 57 103 1 + Current sample, line, band is: 58 103 1 + Current sample, line, band is: 59 103 1 + Current sample, line, band is: 60 103 1 + Current sample, line, band is: 61 103 1 + Current sample, line, band is: 62 103 1 + Current sample, line, band is: 63 103 1 + Current sample, line, band is: 64 103 1 + Current sample, line, band is: 65 103 1 + Current sample, line, band is: 66 103 1 + Current sample, line, band is: 67 103 1 + Current sample, line, band is: 68 103 1 + Current sample, line, band is: 69 103 1 + Current sample, line, band is: 70 103 1 + Current sample, line, band is: 71 103 1 + Current sample, line, band is: 72 103 1 + Current sample, line, band is: 73 103 1 + Current sample, line, band is: 74 103 1 + Current sample, line, band is: 75 103 1 + Current sample, line, band is: 76 103 1 + Current sample, line, band is: 77 103 1 + Current sample, line, band is: 78 103 1 + Current sample, line, band is: 79 103 1 + Current sample, line, band is: 80 103 1 + Current sample, line, band is: 81 103 1 + Current sample, line, band is: 82 103 1 + Current sample, line, band is: 83 103 1 + Current sample, line, band is: 84 103 1 + Current sample, line, band is: 85 103 1 + Current sample, line, band is: 86 103 1 + Current sample, line, band is: 87 103 1 + Current sample, line, band is: 88 103 1 + Current sample, line, band is: 89 103 1 + Current sample, line, band is: 90 103 1 + Current sample, line, band is: 91 103 1 + Current sample, line, band is: 92 103 1 + Current sample, line, band is: 93 103 1 + Current sample, line, band is: 94 103 1 + Current sample, line, band is: 95 103 1 + Current sample, line, band is: 96 103 1 + Current sample, line, band is: 97 103 1 + Current sample, line, band is: 98 103 1 + Current sample, line, band is: 99 103 1 + Current sample, line, band is: 100 103 1 + Current sample, line, band is: 101 103 1 + Current sample, line, band is: 102 103 1 + Current sample, line, band is: 103 103 1 + Current sample, line, band is: 104 103 1 + Current sample, line, band is: 105 103 1 + Current sample, line, band is: 106 103 1 + Current sample, line, band is: 107 103 1 + Current sample, line, band is: 108 103 1 + Current sample, line, band is: 109 103 1 + Current sample, line, band is: 110 103 1 + Current sample, line, band is: 111 103 1 + Current sample, line, band is: 112 103 1 + Current sample, line, band is: 113 103 1 + Current sample, line, band is: 114 103 1 + Current sample, line, band is: 115 103 1 + Current sample, line, band is: 116 103 1 + Current sample, line, band is: 117 103 1 + Current sample, line, band is: 118 103 1 + Current sample, line, band is: 119 103 1 + Current sample, line, band is: 120 103 1 + Current sample, line, band is: 121 103 1 + Current sample, line, band is: 122 103 1 + Current sample, line, band is: 123 103 1 + Current sample, line, band is: 124 103 1 + Current sample, line, band is: 125 103 1 + Current sample, line, band is: 126 103 1 + Current sample, line, band is: 1 104 1 + Current sample, line, band is: 2 104 1 + Current sample, line, band is: 3 104 1 + Current sample, line, band is: 4 104 1 + Current sample, line, band is: 5 104 1 + Current sample, line, band is: 6 104 1 + Current sample, line, band is: 7 104 1 + Current sample, line, band is: 8 104 1 + Current sample, line, band is: 9 104 1 + Current sample, line, band is: 10 104 1 + Current sample, line, band is: 11 104 1 + Current sample, line, band is: 12 104 1 + Current sample, line, band is: 13 104 1 + Current sample, line, band is: 14 104 1 + Current sample, line, band is: 15 104 1 + Current sample, line, band is: 16 104 1 + Current sample, line, band is: 17 104 1 + Current sample, line, band is: 18 104 1 + Current sample, line, band is: 19 104 1 + Current sample, line, band is: 20 104 1 + Current sample, line, band is: 21 104 1 + Current sample, line, band is: 22 104 1 + Current sample, line, band is: 23 104 1 + Current sample, line, band is: 24 104 1 + Current sample, line, band is: 25 104 1 + Current sample, line, band is: 26 104 1 + Current sample, line, band is: 27 104 1 + Current sample, line, band is: 28 104 1 + Current sample, line, band is: 29 104 1 + Current sample, line, band is: 30 104 1 + Current sample, line, band is: 31 104 1 + Current sample, line, band is: 32 104 1 + Current sample, line, band is: 33 104 1 + Current sample, line, band is: 34 104 1 + Current sample, line, band is: 35 104 1 + Current sample, line, band is: 36 104 1 + Current sample, line, band is: 37 104 1 + Current sample, line, band is: 38 104 1 + Current sample, line, band is: 39 104 1 + Current sample, line, band is: 40 104 1 + Current sample, line, band is: 41 104 1 + Current sample, line, band is: 42 104 1 + Current sample, line, band is: 43 104 1 + Current sample, line, band is: 44 104 1 + Current sample, line, band is: 45 104 1 + Current sample, line, band is: 46 104 1 + Current sample, line, band is: 47 104 1 + Current sample, line, band is: 48 104 1 + Current sample, line, band is: 49 104 1 + Current sample, line, band is: 50 104 1 + Current sample, line, band is: 51 104 1 + Current sample, line, band is: 52 104 1 + Current sample, line, band is: 53 104 1 + Current sample, line, band is: 54 104 1 + Current sample, line, band is: 55 104 1 + Current sample, line, band is: 56 104 1 + Current sample, line, band is: 57 104 1 + Current sample, line, band is: 58 104 1 + Current sample, line, band is: 59 104 1 + Current sample, line, band is: 60 104 1 + Current sample, line, band is: 61 104 1 + Current sample, line, band is: 62 104 1 + Current sample, line, band is: 63 104 1 + Current sample, line, band is: 64 104 1 + Current sample, line, band is: 65 104 1 + Current sample, line, band is: 66 104 1 + Current sample, line, band is: 67 104 1 + Current sample, line, band is: 68 104 1 + Current sample, line, band is: 69 104 1 + Current sample, line, band is: 70 104 1 + Current sample, line, band is: 71 104 1 + Current sample, line, band is: 72 104 1 + Current sample, line, band is: 73 104 1 + Current sample, line, band is: 74 104 1 + Current sample, line, band is: 75 104 1 + Current sample, line, band is: 76 104 1 + Current sample, line, band is: 77 104 1 + Current sample, line, band is: 78 104 1 + Current sample, line, band is: 79 104 1 + Current sample, line, band is: 80 104 1 + Current sample, line, band is: 81 104 1 + Current sample, line, band is: 82 104 1 + Current sample, line, band is: 83 104 1 + Current sample, line, band is: 84 104 1 + Current sample, line, band is: 85 104 1 + Current sample, line, band is: 86 104 1 + Current sample, line, band is: 87 104 1 + Current sample, line, band is: 88 104 1 + Current sample, line, band is: 89 104 1 + Current sample, line, band is: 90 104 1 + Current sample, line, band is: 91 104 1 + Current sample, line, band is: 92 104 1 + Current sample, line, band is: 93 104 1 + Current sample, line, band is: 94 104 1 + Current sample, line, band is: 95 104 1 + Current sample, line, band is: 96 104 1 + Current sample, line, band is: 97 104 1 + Current sample, line, band is: 98 104 1 + Current sample, line, band is: 99 104 1 + Current sample, line, band is: 100 104 1 + Current sample, line, band is: 101 104 1 + Current sample, line, band is: 102 104 1 + Current sample, line, band is: 103 104 1 + Current sample, line, band is: 104 104 1 + Current sample, line, band is: 105 104 1 + Current sample, line, band is: 106 104 1 + Current sample, line, band is: 107 104 1 + Current sample, line, band is: 108 104 1 + Current sample, line, band is: 109 104 1 + Current sample, line, band is: 110 104 1 + Current sample, line, band is: 111 104 1 + Current sample, line, band is: 112 104 1 + Current sample, line, band is: 113 104 1 + Current sample, line, band is: 114 104 1 + Current sample, line, band is: 115 104 1 + Current sample, line, band is: 116 104 1 + Current sample, line, band is: 117 104 1 + Current sample, line, band is: 118 104 1 + Current sample, line, band is: 119 104 1 + Current sample, line, band is: 120 104 1 + Current sample, line, band is: 121 104 1 + Current sample, line, band is: 122 104 1 + Current sample, line, band is: 123 104 1 + Current sample, line, band is: 124 104 1 + Current sample, line, band is: 125 104 1 + Current sample, line, band is: 126 104 1 + Current sample, line, band is: 1 105 1 + Current sample, line, band is: 2 105 1 + Current sample, line, band is: 3 105 1 + Current sample, line, band is: 4 105 1 + Current sample, line, band is: 5 105 1 + Current sample, line, band is: 6 105 1 + Current sample, line, band is: 7 105 1 + Current sample, line, band is: 8 105 1 + Current sample, line, band is: 9 105 1 + Current sample, line, band is: 10 105 1 + Current sample, line, band is: 11 105 1 + Current sample, line, band is: 12 105 1 + Current sample, line, band is: 13 105 1 + Current sample, line, band is: 14 105 1 + Current sample, line, band is: 15 105 1 + Current sample, line, band is: 16 105 1 + Current sample, line, band is: 17 105 1 + Current sample, line, band is: 18 105 1 + Current sample, line, band is: 19 105 1 + Current sample, line, band is: 20 105 1 + Current sample, line, band is: 21 105 1 + Current sample, line, band is: 22 105 1 + Current sample, line, band is: 23 105 1 + Current sample, line, band is: 24 105 1 + Current sample, line, band is: 25 105 1 + Current sample, line, band is: 26 105 1 + Current sample, line, band is: 27 105 1 + Current sample, line, band is: 28 105 1 + Current sample, line, band is: 29 105 1 + Current sample, line, band is: 30 105 1 + Current sample, line, band is: 31 105 1 + Current sample, line, band is: 32 105 1 + Current sample, line, band is: 33 105 1 + Current sample, line, band is: 34 105 1 + Current sample, line, band is: 35 105 1 + Current sample, line, band is: 36 105 1 + Current sample, line, band is: 37 105 1 + Current sample, line, band is: 38 105 1 + Current sample, line, band is: 39 105 1 + Current sample, line, band is: 40 105 1 + Current sample, line, band is: 41 105 1 + Current sample, line, band is: 42 105 1 + Current sample, line, band is: 43 105 1 + Current sample, line, band is: 44 105 1 + Current sample, line, band is: 45 105 1 + Current sample, line, band is: 46 105 1 + Current sample, line, band is: 47 105 1 + Current sample, line, band is: 48 105 1 + Current sample, line, band is: 49 105 1 + Current sample, line, band is: 50 105 1 + Current sample, line, band is: 51 105 1 + Current sample, line, band is: 52 105 1 + Current sample, line, band is: 53 105 1 + Current sample, line, band is: 54 105 1 + Current sample, line, band is: 55 105 1 + Current sample, line, band is: 56 105 1 + Current sample, line, band is: 57 105 1 + Current sample, line, band is: 58 105 1 + Current sample, line, band is: 59 105 1 + Current sample, line, band is: 60 105 1 + Current sample, line, band is: 61 105 1 + Current sample, line, band is: 62 105 1 + Current sample, line, band is: 63 105 1 + Current sample, line, band is: 64 105 1 + Current sample, line, band is: 65 105 1 + Current sample, line, band is: 66 105 1 + Current sample, line, band is: 67 105 1 + Current sample, line, band is: 68 105 1 + Current sample, line, band is: 69 105 1 + Current sample, line, band is: 70 105 1 + Current sample, line, band is: 71 105 1 + Current sample, line, band is: 72 105 1 + Current sample, line, band is: 73 105 1 + Current sample, line, band is: 74 105 1 + Current sample, line, band is: 75 105 1 + Current sample, line, band is: 76 105 1 + Current sample, line, band is: 77 105 1 + Current sample, line, band is: 78 105 1 + Current sample, line, band is: 79 105 1 + Current sample, line, band is: 80 105 1 + Current sample, line, band is: 81 105 1 + Current sample, line, band is: 82 105 1 + Current sample, line, band is: 83 105 1 + Current sample, line, band is: 84 105 1 + Current sample, line, band is: 85 105 1 + Current sample, line, band is: 86 105 1 + Current sample, line, band is: 87 105 1 + Current sample, line, band is: 88 105 1 + Current sample, line, band is: 89 105 1 + Current sample, line, band is: 90 105 1 + Current sample, line, band is: 91 105 1 + Current sample, line, band is: 92 105 1 + Current sample, line, band is: 93 105 1 + Current sample, line, band is: 94 105 1 + Current sample, line, band is: 95 105 1 + Current sample, line, band is: 96 105 1 + Current sample, line, band is: 97 105 1 + Current sample, line, band is: 98 105 1 + Current sample, line, band is: 99 105 1 + Current sample, line, band is: 100 105 1 + Current sample, line, band is: 101 105 1 + Current sample, line, band is: 102 105 1 + Current sample, line, band is: 103 105 1 + Current sample, line, band is: 104 105 1 + Current sample, line, band is: 105 105 1 + Current sample, line, band is: 106 105 1 + Current sample, line, band is: 107 105 1 + Current sample, line, band is: 108 105 1 + Current sample, line, band is: 109 105 1 + Current sample, line, band is: 110 105 1 + Current sample, line, band is: 111 105 1 + Current sample, line, band is: 112 105 1 + Current sample, line, band is: 113 105 1 + Current sample, line, band is: 114 105 1 + Current sample, line, band is: 115 105 1 + Current sample, line, band is: 116 105 1 + Current sample, line, band is: 117 105 1 + Current sample, line, band is: 118 105 1 + Current sample, line, band is: 119 105 1 + Current sample, line, band is: 120 105 1 + Current sample, line, band is: 121 105 1 + Current sample, line, band is: 122 105 1 + Current sample, line, band is: 123 105 1 + Current sample, line, band is: 124 105 1 + Current sample, line, band is: 125 105 1 + Current sample, line, band is: 126 105 1 + Current sample, line, band is: 1 106 1 + Current sample, line, band is: 2 106 1 + Current sample, line, band is: 3 106 1 + Current sample, line, band is: 4 106 1 + Current sample, line, band is: 5 106 1 + Current sample, line, band is: 6 106 1 + Current sample, line, band is: 7 106 1 + Current sample, line, band is: 8 106 1 + Current sample, line, band is: 9 106 1 + Current sample, line, band is: 10 106 1 + Current sample, line, band is: 11 106 1 + Current sample, line, band is: 12 106 1 + Current sample, line, band is: 13 106 1 + Current sample, line, band is: 14 106 1 + Current sample, line, band is: 15 106 1 + Current sample, line, band is: 16 106 1 + Current sample, line, band is: 17 106 1 + Current sample, line, band is: 18 106 1 + Current sample, line, band is: 19 106 1 + Current sample, line, band is: 20 106 1 + Current sample, line, band is: 21 106 1 + Current sample, line, band is: 22 106 1 + Current sample, line, band is: 23 106 1 + Current sample, line, band is: 24 106 1 + Current sample, line, band is: 25 106 1 + Current sample, line, band is: 26 106 1 + Current sample, line, band is: 27 106 1 + Current sample, line, band is: 28 106 1 + Current sample, line, band is: 29 106 1 + Current sample, line, band is: 30 106 1 + Current sample, line, band is: 31 106 1 + Current sample, line, band is: 32 106 1 + Current sample, line, band is: 33 106 1 + Current sample, line, band is: 34 106 1 + Current sample, line, band is: 35 106 1 + Current sample, line, band is: 36 106 1 + Current sample, line, band is: 37 106 1 + Current sample, line, band is: 38 106 1 + Current sample, line, band is: 39 106 1 + Current sample, line, band is: 40 106 1 + Current sample, line, band is: 41 106 1 + Current sample, line, band is: 42 106 1 + Current sample, line, band is: 43 106 1 + Current sample, line, band is: 44 106 1 + Current sample, line, band is: 45 106 1 + Current sample, line, band is: 46 106 1 + Current sample, line, band is: 47 106 1 + Current sample, line, band is: 48 106 1 + Current sample, line, band is: 49 106 1 + Current sample, line, band is: 50 106 1 + Current sample, line, band is: 51 106 1 + Current sample, line, band is: 52 106 1 + Current sample, line, band is: 53 106 1 + Current sample, line, band is: 54 106 1 + Current sample, line, band is: 55 106 1 + Current sample, line, band is: 56 106 1 + Current sample, line, band is: 57 106 1 + Current sample, line, band is: 58 106 1 + Current sample, line, band is: 59 106 1 + Current sample, line, band is: 60 106 1 + Current sample, line, band is: 61 106 1 + Current sample, line, band is: 62 106 1 + Current sample, line, band is: 63 106 1 + Current sample, line, band is: 64 106 1 + Current sample, line, band is: 65 106 1 + Current sample, line, band is: 66 106 1 + Current sample, line, band is: 67 106 1 + Current sample, line, band is: 68 106 1 + Current sample, line, band is: 69 106 1 + Current sample, line, band is: 70 106 1 + Current sample, line, band is: 71 106 1 + Current sample, line, band is: 72 106 1 + Current sample, line, band is: 73 106 1 + Current sample, line, band is: 74 106 1 + Current sample, line, band is: 75 106 1 + Current sample, line, band is: 76 106 1 + Current sample, line, band is: 77 106 1 + Current sample, line, band is: 78 106 1 + Current sample, line, band is: 79 106 1 + Current sample, line, band is: 80 106 1 + Current sample, line, band is: 81 106 1 + Current sample, line, band is: 82 106 1 + Current sample, line, band is: 83 106 1 + Current sample, line, band is: 84 106 1 + Current sample, line, band is: 85 106 1 + Current sample, line, band is: 86 106 1 + Current sample, line, band is: 87 106 1 + Current sample, line, band is: 88 106 1 + Current sample, line, band is: 89 106 1 + Current sample, line, band is: 90 106 1 + Current sample, line, band is: 91 106 1 + Current sample, line, band is: 92 106 1 + Current sample, line, band is: 93 106 1 + Current sample, line, band is: 94 106 1 + Current sample, line, band is: 95 106 1 + Current sample, line, band is: 96 106 1 + Current sample, line, band is: 97 106 1 + Current sample, line, band is: 98 106 1 + Current sample, line, band is: 99 106 1 + Current sample, line, band is: 100 106 1 + Current sample, line, band is: 101 106 1 + Current sample, line, band is: 102 106 1 + Current sample, line, band is: 103 106 1 + Current sample, line, band is: 104 106 1 + Current sample, line, band is: 105 106 1 + Current sample, line, band is: 106 106 1 + Current sample, line, band is: 107 106 1 + Current sample, line, band is: 108 106 1 + Current sample, line, band is: 109 106 1 + Current sample, line, band is: 110 106 1 + Current sample, line, band is: 111 106 1 + Current sample, line, band is: 112 106 1 + Current sample, line, band is: 113 106 1 + Current sample, line, band is: 114 106 1 + Current sample, line, band is: 115 106 1 + Current sample, line, band is: 116 106 1 + Current sample, line, band is: 117 106 1 + Current sample, line, band is: 118 106 1 + Current sample, line, band is: 119 106 1 + Current sample, line, band is: 120 106 1 + Current sample, line, band is: 121 106 1 + Current sample, line, band is: 122 106 1 + Current sample, line, band is: 123 106 1 + Current sample, line, band is: 124 106 1 + Current sample, line, band is: 125 106 1 + Current sample, line, band is: 126 106 1 + Current sample, line, band is: 1 107 1 + Current sample, line, band is: 2 107 1 + Current sample, line, band is: 3 107 1 + Current sample, line, band is: 4 107 1 + Current sample, line, band is: 5 107 1 + Current sample, line, band is: 6 107 1 + Current sample, line, band is: 7 107 1 + Current sample, line, band is: 8 107 1 + Current sample, line, band is: 9 107 1 + Current sample, line, band is: 10 107 1 + Current sample, line, band is: 11 107 1 + Current sample, line, band is: 12 107 1 + Current sample, line, band is: 13 107 1 + Current sample, line, band is: 14 107 1 + Current sample, line, band is: 15 107 1 + Current sample, line, band is: 16 107 1 + Current sample, line, band is: 17 107 1 + Current sample, line, band is: 18 107 1 + Current sample, line, band is: 19 107 1 + Current sample, line, band is: 20 107 1 + Current sample, line, band is: 21 107 1 + Current sample, line, band is: 22 107 1 + Current sample, line, band is: 23 107 1 + Current sample, line, band is: 24 107 1 + Current sample, line, band is: 25 107 1 + Current sample, line, band is: 26 107 1 + Current sample, line, band is: 27 107 1 + Current sample, line, band is: 28 107 1 + Current sample, line, band is: 29 107 1 + Current sample, line, band is: 30 107 1 + Current sample, line, band is: 31 107 1 + Current sample, line, band is: 32 107 1 + Current sample, line, band is: 33 107 1 + Current sample, line, band is: 34 107 1 + Current sample, line, band is: 35 107 1 + Current sample, line, band is: 36 107 1 + Current sample, line, band is: 37 107 1 + Current sample, line, band is: 38 107 1 + Current sample, line, band is: 39 107 1 + Current sample, line, band is: 40 107 1 + Current sample, line, band is: 41 107 1 + Current sample, line, band is: 42 107 1 + Current sample, line, band is: 43 107 1 + Current sample, line, band is: 44 107 1 + Current sample, line, band is: 45 107 1 + Current sample, line, band is: 46 107 1 + Current sample, line, band is: 47 107 1 + Current sample, line, band is: 48 107 1 + Current sample, line, band is: 49 107 1 + Current sample, line, band is: 50 107 1 + Current sample, line, band is: 51 107 1 + Current sample, line, band is: 52 107 1 + Current sample, line, band is: 53 107 1 + Current sample, line, band is: 54 107 1 + Current sample, line, band is: 55 107 1 + Current sample, line, band is: 56 107 1 + Current sample, line, band is: 57 107 1 + Current sample, line, band is: 58 107 1 + Current sample, line, band is: 59 107 1 + Current sample, line, band is: 60 107 1 + Current sample, line, band is: 61 107 1 + Current sample, line, band is: 62 107 1 + Current sample, line, band is: 63 107 1 + Current sample, line, band is: 64 107 1 + Current sample, line, band is: 65 107 1 + Current sample, line, band is: 66 107 1 + Current sample, line, band is: 67 107 1 + Current sample, line, band is: 68 107 1 + Current sample, line, band is: 69 107 1 + Current sample, line, band is: 70 107 1 + Current sample, line, band is: 71 107 1 + Current sample, line, band is: 72 107 1 + Current sample, line, band is: 73 107 1 + Current sample, line, band is: 74 107 1 + Current sample, line, band is: 75 107 1 + Current sample, line, band is: 76 107 1 + Current sample, line, band is: 77 107 1 + Current sample, line, band is: 78 107 1 + Current sample, line, band is: 79 107 1 + Current sample, line, band is: 80 107 1 + Current sample, line, band is: 81 107 1 + Current sample, line, band is: 82 107 1 + Current sample, line, band is: 83 107 1 + Current sample, line, band is: 84 107 1 + Current sample, line, band is: 85 107 1 + Current sample, line, band is: 86 107 1 + Current sample, line, band is: 87 107 1 + Current sample, line, band is: 88 107 1 + Current sample, line, band is: 89 107 1 + Current sample, line, band is: 90 107 1 + Current sample, line, band is: 91 107 1 + Current sample, line, band is: 92 107 1 + Current sample, line, band is: 93 107 1 + Current sample, line, band is: 94 107 1 + Current sample, line, band is: 95 107 1 + Current sample, line, band is: 96 107 1 + Current sample, line, band is: 97 107 1 + Current sample, line, band is: 98 107 1 + Current sample, line, band is: 99 107 1 + Current sample, line, band is: 100 107 1 + Current sample, line, band is: 101 107 1 + Current sample, line, band is: 102 107 1 + Current sample, line, band is: 103 107 1 + Current sample, line, band is: 104 107 1 + Current sample, line, band is: 105 107 1 + Current sample, line, band is: 106 107 1 + Current sample, line, band is: 107 107 1 + Current sample, line, band is: 108 107 1 + Current sample, line, band is: 109 107 1 + Current sample, line, band is: 110 107 1 + Current sample, line, band is: 111 107 1 + Current sample, line, band is: 112 107 1 + Current sample, line, band is: 113 107 1 + Current sample, line, band is: 114 107 1 + Current sample, line, band is: 115 107 1 + Current sample, line, band is: 116 107 1 + Current sample, line, band is: 117 107 1 + Current sample, line, band is: 118 107 1 + Current sample, line, band is: 119 107 1 + Current sample, line, band is: 120 107 1 + Current sample, line, band is: 121 107 1 + Current sample, line, band is: 122 107 1 + Current sample, line, band is: 123 107 1 + Current sample, line, band is: 124 107 1 + Current sample, line, band is: 125 107 1 + Current sample, line, band is: 126 107 1 + Current sample, line, band is: 1 108 1 + Current sample, line, band is: 2 108 1 + Current sample, line, band is: 3 108 1 + Current sample, line, band is: 4 108 1 + Current sample, line, band is: 5 108 1 + Current sample, line, band is: 6 108 1 + Current sample, line, band is: 7 108 1 + Current sample, line, band is: 8 108 1 + Current sample, line, band is: 9 108 1 + Current sample, line, band is: 10 108 1 + Current sample, line, band is: 11 108 1 + Current sample, line, band is: 12 108 1 + Current sample, line, band is: 13 108 1 + Current sample, line, band is: 14 108 1 + Current sample, line, band is: 15 108 1 + Current sample, line, band is: 16 108 1 + Current sample, line, band is: 17 108 1 + Current sample, line, band is: 18 108 1 + Current sample, line, band is: 19 108 1 + Current sample, line, band is: 20 108 1 + Current sample, line, band is: 21 108 1 + Current sample, line, band is: 22 108 1 + Current sample, line, band is: 23 108 1 + Current sample, line, band is: 24 108 1 + Current sample, line, band is: 25 108 1 + Current sample, line, band is: 26 108 1 + Current sample, line, band is: 27 108 1 + Current sample, line, band is: 28 108 1 + Current sample, line, band is: 29 108 1 + Current sample, line, band is: 30 108 1 + Current sample, line, band is: 31 108 1 + Current sample, line, band is: 32 108 1 + Current sample, line, band is: 33 108 1 + Current sample, line, band is: 34 108 1 + Current sample, line, band is: 35 108 1 + Current sample, line, band is: 36 108 1 + Current sample, line, band is: 37 108 1 + Current sample, line, band is: 38 108 1 + Current sample, line, band is: 39 108 1 + Current sample, line, band is: 40 108 1 + Current sample, line, band is: 41 108 1 + Current sample, line, band is: 42 108 1 + Current sample, line, band is: 43 108 1 + Current sample, line, band is: 44 108 1 + Current sample, line, band is: 45 108 1 + Current sample, line, band is: 46 108 1 + Current sample, line, band is: 47 108 1 + Current sample, line, band is: 48 108 1 + Current sample, line, band is: 49 108 1 + Current sample, line, band is: 50 108 1 + Current sample, line, band is: 51 108 1 + Current sample, line, band is: 52 108 1 + Current sample, line, band is: 53 108 1 + Current sample, line, band is: 54 108 1 + Current sample, line, band is: 55 108 1 + Current sample, line, band is: 56 108 1 + Current sample, line, band is: 57 108 1 + Current sample, line, band is: 58 108 1 + Current sample, line, band is: 59 108 1 + Current sample, line, band is: 60 108 1 + Current sample, line, band is: 61 108 1 + Current sample, line, band is: 62 108 1 + Current sample, line, band is: 63 108 1 + Current sample, line, band is: 64 108 1 + Current sample, line, band is: 65 108 1 + Current sample, line, band is: 66 108 1 + Current sample, line, band is: 67 108 1 + Current sample, line, band is: 68 108 1 + Current sample, line, band is: 69 108 1 + Current sample, line, band is: 70 108 1 + Current sample, line, band is: 71 108 1 + Current sample, line, band is: 72 108 1 + Current sample, line, band is: 73 108 1 + Current sample, line, band is: 74 108 1 + Current sample, line, band is: 75 108 1 + Current sample, line, band is: 76 108 1 + Current sample, line, band is: 77 108 1 + Current sample, line, band is: 78 108 1 + Current sample, line, band is: 79 108 1 + Current sample, line, band is: 80 108 1 + Current sample, line, band is: 81 108 1 + Current sample, line, band is: 82 108 1 + Current sample, line, band is: 83 108 1 + Current sample, line, band is: 84 108 1 + Current sample, line, band is: 85 108 1 + Current sample, line, band is: 86 108 1 + Current sample, line, band is: 87 108 1 + Current sample, line, band is: 88 108 1 + Current sample, line, band is: 89 108 1 + Current sample, line, band is: 90 108 1 + Current sample, line, band is: 91 108 1 + Current sample, line, band is: 92 108 1 + Current sample, line, band is: 93 108 1 + Current sample, line, band is: 94 108 1 + Current sample, line, band is: 95 108 1 + Current sample, line, band is: 96 108 1 + Current sample, line, band is: 97 108 1 + Current sample, line, band is: 98 108 1 + Current sample, line, band is: 99 108 1 + Current sample, line, band is: 100 108 1 + Current sample, line, band is: 101 108 1 + Current sample, line, band is: 102 108 1 + Current sample, line, band is: 103 108 1 + Current sample, line, band is: 104 108 1 + Current sample, line, band is: 105 108 1 + Current sample, line, band is: 106 108 1 + Current sample, line, band is: 107 108 1 + Current sample, line, band is: 108 108 1 + Current sample, line, band is: 109 108 1 + Current sample, line, band is: 110 108 1 + Current sample, line, band is: 111 108 1 + Current sample, line, band is: 112 108 1 + Current sample, line, band is: 113 108 1 + Current sample, line, band is: 114 108 1 + Current sample, line, band is: 115 108 1 + Current sample, line, band is: 116 108 1 + Current sample, line, band is: 117 108 1 + Current sample, line, band is: 118 108 1 + Current sample, line, band is: 119 108 1 + Current sample, line, band is: 120 108 1 + Current sample, line, band is: 121 108 1 + Current sample, line, band is: 122 108 1 + Current sample, line, band is: 123 108 1 + Current sample, line, band is: 124 108 1 + Current sample, line, band is: 125 108 1 + Current sample, line, band is: 126 108 1 + Current sample, line, band is: 1 109 1 + Current sample, line, band is: 2 109 1 + Current sample, line, band is: 3 109 1 + Current sample, line, band is: 4 109 1 + Current sample, line, band is: 5 109 1 + Current sample, line, band is: 6 109 1 + Current sample, line, band is: 7 109 1 + Current sample, line, band is: 8 109 1 + Current sample, line, band is: 9 109 1 + Current sample, line, band is: 10 109 1 + Current sample, line, band is: 11 109 1 + Current sample, line, band is: 12 109 1 + Current sample, line, band is: 13 109 1 + Current sample, line, band is: 14 109 1 + Current sample, line, band is: 15 109 1 + Current sample, line, band is: 16 109 1 + Current sample, line, band is: 17 109 1 + Current sample, line, band is: 18 109 1 + Current sample, line, band is: 19 109 1 + Current sample, line, band is: 20 109 1 + Current sample, line, band is: 21 109 1 + Current sample, line, band is: 22 109 1 + Current sample, line, band is: 23 109 1 + Current sample, line, band is: 24 109 1 + Current sample, line, band is: 25 109 1 + Current sample, line, band is: 26 109 1 + Current sample, line, band is: 27 109 1 + Current sample, line, band is: 28 109 1 + Current sample, line, band is: 29 109 1 + Current sample, line, band is: 30 109 1 + Current sample, line, band is: 31 109 1 + Current sample, line, band is: 32 109 1 + Current sample, line, band is: 33 109 1 + Current sample, line, band is: 34 109 1 + Current sample, line, band is: 35 109 1 + Current sample, line, band is: 36 109 1 + Current sample, line, band is: 37 109 1 + Current sample, line, band is: 38 109 1 + Current sample, line, band is: 39 109 1 + Current sample, line, band is: 40 109 1 + Current sample, line, band is: 41 109 1 + Current sample, line, band is: 42 109 1 + Current sample, line, band is: 43 109 1 + Current sample, line, band is: 44 109 1 + Current sample, line, band is: 45 109 1 + Current sample, line, band is: 46 109 1 + Current sample, line, band is: 47 109 1 + Current sample, line, band is: 48 109 1 + Current sample, line, band is: 49 109 1 + Current sample, line, band is: 50 109 1 + Current sample, line, band is: 51 109 1 + Current sample, line, band is: 52 109 1 + Current sample, line, band is: 53 109 1 + Current sample, line, band is: 54 109 1 + Current sample, line, band is: 55 109 1 + Current sample, line, band is: 56 109 1 + Current sample, line, band is: 57 109 1 + Current sample, line, band is: 58 109 1 + Current sample, line, band is: 59 109 1 + Current sample, line, band is: 60 109 1 + Current sample, line, band is: 61 109 1 + Current sample, line, band is: 62 109 1 + Current sample, line, band is: 63 109 1 + Current sample, line, band is: 64 109 1 + Current sample, line, band is: 65 109 1 + Current sample, line, band is: 66 109 1 + Current sample, line, band is: 67 109 1 + Current sample, line, band is: 68 109 1 + Current sample, line, band is: 69 109 1 + Current sample, line, band is: 70 109 1 + Current sample, line, band is: 71 109 1 + Current sample, line, band is: 72 109 1 + Current sample, line, band is: 73 109 1 + Current sample, line, band is: 74 109 1 + Current sample, line, band is: 75 109 1 + Current sample, line, band is: 76 109 1 + Current sample, line, band is: 77 109 1 + Current sample, line, band is: 78 109 1 + Current sample, line, band is: 79 109 1 + Current sample, line, band is: 80 109 1 + Current sample, line, band is: 81 109 1 + Current sample, line, band is: 82 109 1 + Current sample, line, band is: 83 109 1 + Current sample, line, band is: 84 109 1 + Current sample, line, band is: 85 109 1 + Current sample, line, band is: 86 109 1 + Current sample, line, band is: 87 109 1 + Current sample, line, band is: 88 109 1 + Current sample, line, band is: 89 109 1 + Current sample, line, band is: 90 109 1 + Current sample, line, band is: 91 109 1 + Current sample, line, band is: 92 109 1 + Current sample, line, band is: 93 109 1 + Current sample, line, band is: 94 109 1 + Current sample, line, band is: 95 109 1 + Current sample, line, band is: 96 109 1 + Current sample, line, band is: 97 109 1 + Current sample, line, band is: 98 109 1 + Current sample, line, band is: 99 109 1 + Current sample, line, band is: 100 109 1 + Current sample, line, band is: 101 109 1 + Current sample, line, band is: 102 109 1 + Current sample, line, band is: 103 109 1 + Current sample, line, band is: 104 109 1 + Current sample, line, band is: 105 109 1 + Current sample, line, band is: 106 109 1 + Current sample, line, band is: 107 109 1 + Current sample, line, band is: 108 109 1 + Current sample, line, band is: 109 109 1 + Current sample, line, band is: 110 109 1 + Current sample, line, band is: 111 109 1 + Current sample, line, band is: 112 109 1 + Current sample, line, band is: 113 109 1 + Current sample, line, band is: 114 109 1 + Current sample, line, band is: 115 109 1 + Current sample, line, band is: 116 109 1 + Current sample, line, band is: 117 109 1 + Current sample, line, band is: 118 109 1 + Current sample, line, band is: 119 109 1 + Current sample, line, band is: 120 109 1 + Current sample, line, band is: 121 109 1 + Current sample, line, band is: 122 109 1 + Current sample, line, band is: 123 109 1 + Current sample, line, band is: 124 109 1 + Current sample, line, band is: 125 109 1 + Current sample, line, band is: 126 109 1 + Current sample, line, band is: 1 110 1 + Current sample, line, band is: 2 110 1 + Current sample, line, band is: 3 110 1 + Current sample, line, band is: 4 110 1 + Current sample, line, band is: 5 110 1 + Current sample, line, band is: 6 110 1 + Current sample, line, band is: 7 110 1 + Current sample, line, band is: 8 110 1 + Current sample, line, band is: 9 110 1 + Current sample, line, band is: 10 110 1 + Current sample, line, band is: 11 110 1 + Current sample, line, band is: 12 110 1 + Current sample, line, band is: 13 110 1 + Current sample, line, band is: 14 110 1 + Current sample, line, band is: 15 110 1 + Current sample, line, band is: 16 110 1 + Current sample, line, band is: 17 110 1 + Current sample, line, band is: 18 110 1 + Current sample, line, band is: 19 110 1 + Current sample, line, band is: 20 110 1 + Current sample, line, band is: 21 110 1 + Current sample, line, band is: 22 110 1 + Current sample, line, band is: 23 110 1 + Current sample, line, band is: 24 110 1 + Current sample, line, band is: 25 110 1 + Current sample, line, band is: 26 110 1 + Current sample, line, band is: 27 110 1 + Current sample, line, band is: 28 110 1 + Current sample, line, band is: 29 110 1 + Current sample, line, band is: 30 110 1 + Current sample, line, band is: 31 110 1 + Current sample, line, band is: 32 110 1 + Current sample, line, band is: 33 110 1 + Current sample, line, band is: 34 110 1 + Current sample, line, band is: 35 110 1 + Current sample, line, band is: 36 110 1 + Current sample, line, band is: 37 110 1 + Current sample, line, band is: 38 110 1 + Current sample, line, band is: 39 110 1 + Current sample, line, band is: 40 110 1 + Current sample, line, band is: 41 110 1 + Current sample, line, band is: 42 110 1 + Current sample, line, band is: 43 110 1 + Current sample, line, band is: 44 110 1 + Current sample, line, band is: 45 110 1 + Current sample, line, band is: 46 110 1 + Current sample, line, band is: 47 110 1 + Current sample, line, band is: 48 110 1 + Current sample, line, band is: 49 110 1 + Current sample, line, band is: 50 110 1 + Current sample, line, band is: 51 110 1 + Current sample, line, band is: 52 110 1 + Current sample, line, band is: 53 110 1 + Current sample, line, band is: 54 110 1 + Current sample, line, band is: 55 110 1 + Current sample, line, band is: 56 110 1 + Current sample, line, band is: 57 110 1 + Current sample, line, band is: 58 110 1 + Current sample, line, band is: 59 110 1 + Current sample, line, band is: 60 110 1 + Current sample, line, band is: 61 110 1 + Current sample, line, band is: 62 110 1 + Current sample, line, band is: 63 110 1 + Current sample, line, band is: 64 110 1 + Current sample, line, band is: 65 110 1 + Current sample, line, band is: 66 110 1 + Current sample, line, band is: 67 110 1 + Current sample, line, band is: 68 110 1 + Current sample, line, band is: 69 110 1 + Current sample, line, band is: 70 110 1 + Current sample, line, band is: 71 110 1 + Current sample, line, band is: 72 110 1 + Current sample, line, band is: 73 110 1 + Current sample, line, band is: 74 110 1 + Current sample, line, band is: 75 110 1 + Current sample, line, band is: 76 110 1 + Current sample, line, band is: 77 110 1 + Current sample, line, band is: 78 110 1 + Current sample, line, band is: 79 110 1 + Current sample, line, band is: 80 110 1 + Current sample, line, band is: 81 110 1 + Current sample, line, band is: 82 110 1 + Current sample, line, band is: 83 110 1 + Current sample, line, band is: 84 110 1 + Current sample, line, band is: 85 110 1 + Current sample, line, band is: 86 110 1 + Current sample, line, band is: 87 110 1 + Current sample, line, band is: 88 110 1 + Current sample, line, band is: 89 110 1 + Current sample, line, band is: 90 110 1 + Current sample, line, band is: 91 110 1 + Current sample, line, band is: 92 110 1 + Current sample, line, band is: 93 110 1 + Current sample, line, band is: 94 110 1 + Current sample, line, band is: 95 110 1 + Current sample, line, band is: 96 110 1 + Current sample, line, band is: 97 110 1 + Current sample, line, band is: 98 110 1 + Current sample, line, band is: 99 110 1 + Current sample, line, band is: 100 110 1 + Current sample, line, band is: 101 110 1 + Current sample, line, band is: 102 110 1 + Current sample, line, band is: 103 110 1 + Current sample, line, band is: 104 110 1 + Current sample, line, band is: 105 110 1 + Current sample, line, band is: 106 110 1 + Current sample, line, band is: 107 110 1 + Current sample, line, band is: 108 110 1 + Current sample, line, band is: 109 110 1 + Current sample, line, band is: 110 110 1 + Current sample, line, band is: 111 110 1 + Current sample, line, band is: 112 110 1 + Current sample, line, band is: 113 110 1 + Current sample, line, band is: 114 110 1 + Current sample, line, band is: 115 110 1 + Current sample, line, band is: 116 110 1 + Current sample, line, band is: 117 110 1 + Current sample, line, band is: 118 110 1 + Current sample, line, band is: 119 110 1 + Current sample, line, band is: 120 110 1 + Current sample, line, band is: 121 110 1 + Current sample, line, band is: 122 110 1 + Current sample, line, band is: 123 110 1 + Current sample, line, band is: 124 110 1 + Current sample, line, band is: 125 110 1 + Current sample, line, band is: 126 110 1 + Current sample, line, band is: 1 111 1 + Current sample, line, band is: 2 111 1 + Current sample, line, band is: 3 111 1 + Current sample, line, band is: 4 111 1 + Current sample, line, band is: 5 111 1 + Current sample, line, band is: 6 111 1 + Current sample, line, band is: 7 111 1 + Current sample, line, band is: 8 111 1 + Current sample, line, band is: 9 111 1 + Current sample, line, band is: 10 111 1 + Current sample, line, band is: 11 111 1 + Current sample, line, band is: 12 111 1 + Current sample, line, band is: 13 111 1 + Current sample, line, band is: 14 111 1 + Current sample, line, band is: 15 111 1 + Current sample, line, band is: 16 111 1 + Current sample, line, band is: 17 111 1 + Current sample, line, band is: 18 111 1 + Current sample, line, band is: 19 111 1 + Current sample, line, band is: 20 111 1 + Current sample, line, band is: 21 111 1 + Current sample, line, band is: 22 111 1 + Current sample, line, band is: 23 111 1 + Current sample, line, band is: 24 111 1 + Current sample, line, band is: 25 111 1 + Current sample, line, band is: 26 111 1 + Current sample, line, band is: 27 111 1 + Current sample, line, band is: 28 111 1 + Current sample, line, band is: 29 111 1 + Current sample, line, band is: 30 111 1 + Current sample, line, band is: 31 111 1 + Current sample, line, band is: 32 111 1 + Current sample, line, band is: 33 111 1 + Current sample, line, band is: 34 111 1 + Current sample, line, band is: 35 111 1 + Current sample, line, band is: 36 111 1 + Current sample, line, band is: 37 111 1 + Current sample, line, band is: 38 111 1 + Current sample, line, band is: 39 111 1 + Current sample, line, band is: 40 111 1 + Current sample, line, band is: 41 111 1 + Current sample, line, band is: 42 111 1 + Current sample, line, band is: 43 111 1 + Current sample, line, band is: 44 111 1 + Current sample, line, band is: 45 111 1 + Current sample, line, band is: 46 111 1 + Current sample, line, band is: 47 111 1 + Current sample, line, band is: 48 111 1 + Current sample, line, band is: 49 111 1 + Current sample, line, band is: 50 111 1 + Current sample, line, band is: 51 111 1 + Current sample, line, band is: 52 111 1 + Current sample, line, band is: 53 111 1 + Current sample, line, band is: 54 111 1 + Current sample, line, band is: 55 111 1 + Current sample, line, band is: 56 111 1 + Current sample, line, band is: 57 111 1 + Current sample, line, band is: 58 111 1 + Current sample, line, band is: 59 111 1 + Current sample, line, band is: 60 111 1 + Current sample, line, band is: 61 111 1 + Current sample, line, band is: 62 111 1 + Current sample, line, band is: 63 111 1 + Current sample, line, band is: 64 111 1 + Current sample, line, band is: 65 111 1 + Current sample, line, band is: 66 111 1 + Current sample, line, band is: 67 111 1 + Current sample, line, band is: 68 111 1 + Current sample, line, band is: 69 111 1 + Current sample, line, band is: 70 111 1 + Current sample, line, band is: 71 111 1 + Current sample, line, band is: 72 111 1 + Current sample, line, band is: 73 111 1 + Current sample, line, band is: 74 111 1 + Current sample, line, band is: 75 111 1 + Current sample, line, band is: 76 111 1 + Current sample, line, band is: 77 111 1 + Current sample, line, band is: 78 111 1 + Current sample, line, band is: 79 111 1 + Current sample, line, band is: 80 111 1 + Current sample, line, band is: 81 111 1 + Current sample, line, band is: 82 111 1 + Current sample, line, band is: 83 111 1 + Current sample, line, band is: 84 111 1 + Current sample, line, band is: 85 111 1 + Current sample, line, band is: 86 111 1 + Current sample, line, band is: 87 111 1 + Current sample, line, band is: 88 111 1 + Current sample, line, band is: 89 111 1 + Current sample, line, band is: 90 111 1 + Current sample, line, band is: 91 111 1 + Current sample, line, band is: 92 111 1 + Current sample, line, band is: 93 111 1 + Current sample, line, band is: 94 111 1 + Current sample, line, band is: 95 111 1 + Current sample, line, band is: 96 111 1 + Current sample, line, band is: 97 111 1 + Current sample, line, band is: 98 111 1 + Current sample, line, band is: 99 111 1 + Current sample, line, band is: 100 111 1 + Current sample, line, band is: 101 111 1 + Current sample, line, band is: 102 111 1 + Current sample, line, band is: 103 111 1 + Current sample, line, band is: 104 111 1 + Current sample, line, band is: 105 111 1 + Current sample, line, band is: 106 111 1 + Current sample, line, band is: 107 111 1 + Current sample, line, band is: 108 111 1 + Current sample, line, band is: 109 111 1 + Current sample, line, band is: 110 111 1 + Current sample, line, band is: 111 111 1 + Current sample, line, band is: 112 111 1 + Current sample, line, band is: 113 111 1 + Current sample, line, band is: 114 111 1 + Current sample, line, band is: 115 111 1 + Current sample, line, band is: 116 111 1 + Current sample, line, band is: 117 111 1 + Current sample, line, band is: 118 111 1 + Current sample, line, band is: 119 111 1 + Current sample, line, band is: 120 111 1 + Current sample, line, band is: 121 111 1 + Current sample, line, band is: 122 111 1 + Current sample, line, band is: 123 111 1 + Current sample, line, band is: 124 111 1 + Current sample, line, band is: 125 111 1 + Current sample, line, band is: 126 111 1 + Current sample, line, band is: 1 112 1 + Current sample, line, band is: 2 112 1 + Current sample, line, band is: 3 112 1 + Current sample, line, band is: 4 112 1 + Current sample, line, band is: 5 112 1 + Current sample, line, band is: 6 112 1 + Current sample, line, band is: 7 112 1 + Current sample, line, band is: 8 112 1 + Current sample, line, band is: 9 112 1 + Current sample, line, band is: 10 112 1 + Current sample, line, band is: 11 112 1 + Current sample, line, band is: 12 112 1 + Current sample, line, band is: 13 112 1 + Current sample, line, band is: 14 112 1 + Current sample, line, band is: 15 112 1 + Current sample, line, band is: 16 112 1 + Current sample, line, band is: 17 112 1 + Current sample, line, band is: 18 112 1 + Current sample, line, band is: 19 112 1 + Current sample, line, band is: 20 112 1 + Current sample, line, band is: 21 112 1 + Current sample, line, band is: 22 112 1 + Current sample, line, band is: 23 112 1 + Current sample, line, band is: 24 112 1 + Current sample, line, band is: 25 112 1 + Current sample, line, band is: 26 112 1 + Current sample, line, band is: 27 112 1 + Current sample, line, band is: 28 112 1 + Current sample, line, band is: 29 112 1 + Current sample, line, band is: 30 112 1 + Current sample, line, band is: 31 112 1 + Current sample, line, band is: 32 112 1 + Current sample, line, band is: 33 112 1 + Current sample, line, band is: 34 112 1 + Current sample, line, band is: 35 112 1 + Current sample, line, band is: 36 112 1 + Current sample, line, band is: 37 112 1 + Current sample, line, band is: 38 112 1 + Current sample, line, band is: 39 112 1 + Current sample, line, band is: 40 112 1 + Current sample, line, band is: 41 112 1 + Current sample, line, band is: 42 112 1 + Current sample, line, band is: 43 112 1 + Current sample, line, band is: 44 112 1 + Current sample, line, band is: 45 112 1 + Current sample, line, band is: 46 112 1 + Current sample, line, band is: 47 112 1 + Current sample, line, band is: 48 112 1 + Current sample, line, band is: 49 112 1 + Current sample, line, band is: 50 112 1 + Current sample, line, band is: 51 112 1 + Current sample, line, band is: 52 112 1 + Current sample, line, band is: 53 112 1 + Current sample, line, band is: 54 112 1 + Current sample, line, band is: 55 112 1 + Current sample, line, band is: 56 112 1 + Current sample, line, band is: 57 112 1 + Current sample, line, band is: 58 112 1 + Current sample, line, band is: 59 112 1 + Current sample, line, band is: 60 112 1 + Current sample, line, band is: 61 112 1 + Current sample, line, band is: 62 112 1 + Current sample, line, band is: 63 112 1 + Current sample, line, band is: 64 112 1 + Current sample, line, band is: 65 112 1 + Current sample, line, band is: 66 112 1 + Current sample, line, band is: 67 112 1 + Current sample, line, band is: 68 112 1 + Current sample, line, band is: 69 112 1 + Current sample, line, band is: 70 112 1 + Current sample, line, band is: 71 112 1 + Current sample, line, band is: 72 112 1 + Current sample, line, band is: 73 112 1 + Current sample, line, band is: 74 112 1 + Current sample, line, band is: 75 112 1 + Current sample, line, band is: 76 112 1 + Current sample, line, band is: 77 112 1 + Current sample, line, band is: 78 112 1 + Current sample, line, band is: 79 112 1 + Current sample, line, band is: 80 112 1 + Current sample, line, band is: 81 112 1 + Current sample, line, band is: 82 112 1 + Current sample, line, band is: 83 112 1 + Current sample, line, band is: 84 112 1 + Current sample, line, band is: 85 112 1 + Current sample, line, band is: 86 112 1 + Current sample, line, band is: 87 112 1 + Current sample, line, band is: 88 112 1 + Current sample, line, band is: 89 112 1 + Current sample, line, band is: 90 112 1 + Current sample, line, band is: 91 112 1 + Current sample, line, band is: 92 112 1 + Current sample, line, band is: 93 112 1 + Current sample, line, band is: 94 112 1 + Current sample, line, band is: 95 112 1 + Current sample, line, band is: 96 112 1 + Current sample, line, band is: 97 112 1 + Current sample, line, band is: 98 112 1 + Current sample, line, band is: 99 112 1 + Current sample, line, band is: 100 112 1 + Current sample, line, band is: 101 112 1 + Current sample, line, band is: 102 112 1 + Current sample, line, band is: 103 112 1 + Current sample, line, band is: 104 112 1 + Current sample, line, band is: 105 112 1 + Current sample, line, band is: 106 112 1 + Current sample, line, band is: 107 112 1 + Current sample, line, band is: 108 112 1 + Current sample, line, band is: 109 112 1 + Current sample, line, band is: 110 112 1 + Current sample, line, band is: 111 112 1 + Current sample, line, band is: 112 112 1 + Current sample, line, band is: 113 112 1 + Current sample, line, band is: 114 112 1 + Current sample, line, band is: 115 112 1 + Current sample, line, band is: 116 112 1 + Current sample, line, band is: 117 112 1 + Current sample, line, band is: 118 112 1 + Current sample, line, band is: 119 112 1 + Current sample, line, band is: 120 112 1 + Current sample, line, band is: 121 112 1 + Current sample, line, band is: 122 112 1 + Current sample, line, band is: 123 112 1 + Current sample, line, band is: 124 112 1 + Current sample, line, band is: 125 112 1 + Current sample, line, band is: 126 112 1 + Current sample, line, band is: 1 113 1 + Current sample, line, band is: 2 113 1 + Current sample, line, band is: 3 113 1 + Current sample, line, band is: 4 113 1 + Current sample, line, band is: 5 113 1 + Current sample, line, band is: 6 113 1 + Current sample, line, band is: 7 113 1 + Current sample, line, band is: 8 113 1 + Current sample, line, band is: 9 113 1 + Current sample, line, band is: 10 113 1 + Current sample, line, band is: 11 113 1 + Current sample, line, band is: 12 113 1 + Current sample, line, band is: 13 113 1 + Current sample, line, band is: 14 113 1 + Current sample, line, band is: 15 113 1 + Current sample, line, band is: 16 113 1 + Current sample, line, band is: 17 113 1 + Current sample, line, band is: 18 113 1 + Current sample, line, band is: 19 113 1 + Current sample, line, band is: 20 113 1 + Current sample, line, band is: 21 113 1 + Current sample, line, band is: 22 113 1 + Current sample, line, band is: 23 113 1 + Current sample, line, band is: 24 113 1 + Current sample, line, band is: 25 113 1 + Current sample, line, band is: 26 113 1 + Current sample, line, band is: 27 113 1 + Current sample, line, band is: 28 113 1 + Current sample, line, band is: 29 113 1 + Current sample, line, band is: 30 113 1 + Current sample, line, band is: 31 113 1 + Current sample, line, band is: 32 113 1 + Current sample, line, band is: 33 113 1 + Current sample, line, band is: 34 113 1 + Current sample, line, band is: 35 113 1 + Current sample, line, band is: 36 113 1 + Current sample, line, band is: 37 113 1 + Current sample, line, band is: 38 113 1 + Current sample, line, band is: 39 113 1 + Current sample, line, band is: 40 113 1 + Current sample, line, band is: 41 113 1 + Current sample, line, band is: 42 113 1 + Current sample, line, band is: 43 113 1 + Current sample, line, band is: 44 113 1 + Current sample, line, band is: 45 113 1 + Current sample, line, band is: 46 113 1 + Current sample, line, band is: 47 113 1 + Current sample, line, band is: 48 113 1 + Current sample, line, band is: 49 113 1 + Current sample, line, band is: 50 113 1 + Current sample, line, band is: 51 113 1 + Current sample, line, band is: 52 113 1 + Current sample, line, band is: 53 113 1 + Current sample, line, band is: 54 113 1 + Current sample, line, band is: 55 113 1 + Current sample, line, band is: 56 113 1 + Current sample, line, band is: 57 113 1 + Current sample, line, band is: 58 113 1 + Current sample, line, band is: 59 113 1 + Current sample, line, band is: 60 113 1 + Current sample, line, band is: 61 113 1 + Current sample, line, band is: 62 113 1 + Current sample, line, band is: 63 113 1 + Current sample, line, band is: 64 113 1 + Current sample, line, band is: 65 113 1 + Current sample, line, band is: 66 113 1 + Current sample, line, band is: 67 113 1 + Current sample, line, band is: 68 113 1 + Current sample, line, band is: 69 113 1 + Current sample, line, band is: 70 113 1 + Current sample, line, band is: 71 113 1 + Current sample, line, band is: 72 113 1 + Current sample, line, band is: 73 113 1 + Current sample, line, band is: 74 113 1 + Current sample, line, band is: 75 113 1 + Current sample, line, band is: 76 113 1 + Current sample, line, band is: 77 113 1 + Current sample, line, band is: 78 113 1 + Current sample, line, band is: 79 113 1 + Current sample, line, band is: 80 113 1 + Current sample, line, band is: 81 113 1 + Current sample, line, band is: 82 113 1 + Current sample, line, band is: 83 113 1 + Current sample, line, band is: 84 113 1 + Current sample, line, band is: 85 113 1 + Current sample, line, band is: 86 113 1 + Current sample, line, band is: 87 113 1 + Current sample, line, band is: 88 113 1 + Current sample, line, band is: 89 113 1 + Current sample, line, band is: 90 113 1 + Current sample, line, band is: 91 113 1 + Current sample, line, band is: 92 113 1 + Current sample, line, band is: 93 113 1 + Current sample, line, band is: 94 113 1 + Current sample, line, band is: 95 113 1 + Current sample, line, band is: 96 113 1 + Current sample, line, band is: 97 113 1 + Current sample, line, band is: 98 113 1 + Current sample, line, band is: 99 113 1 + Current sample, line, band is: 100 113 1 + Current sample, line, band is: 101 113 1 + Current sample, line, band is: 102 113 1 + Current sample, line, band is: 103 113 1 + Current sample, line, band is: 104 113 1 + Current sample, line, band is: 105 113 1 + Current sample, line, band is: 106 113 1 + Current sample, line, band is: 107 113 1 + Current sample, line, band is: 108 113 1 + Current sample, line, band is: 109 113 1 + Current sample, line, band is: 110 113 1 + Current sample, line, band is: 111 113 1 + Current sample, line, band is: 112 113 1 + Current sample, line, band is: 113 113 1 + Current sample, line, band is: 114 113 1 + Current sample, line, band is: 115 113 1 + Current sample, line, band is: 116 113 1 + Current sample, line, band is: 117 113 1 + Current sample, line, band is: 118 113 1 + Current sample, line, band is: 119 113 1 + Current sample, line, band is: 120 113 1 + Current sample, line, band is: 121 113 1 + Current sample, line, band is: 122 113 1 + Current sample, line, band is: 123 113 1 + Current sample, line, band is: 124 113 1 + Current sample, line, band is: 125 113 1 + Current sample, line, band is: 126 113 1 + Current sample, line, band is: 1 114 1 + Current sample, line, band is: 2 114 1 + Current sample, line, band is: 3 114 1 + Current sample, line, band is: 4 114 1 + Current sample, line, band is: 5 114 1 + Current sample, line, band is: 6 114 1 + Current sample, line, band is: 7 114 1 + Current sample, line, band is: 8 114 1 + Current sample, line, band is: 9 114 1 + Current sample, line, band is: 10 114 1 + Current sample, line, band is: 11 114 1 + Current sample, line, band is: 12 114 1 + Current sample, line, band is: 13 114 1 + Current sample, line, band is: 14 114 1 + Current sample, line, band is: 15 114 1 + Current sample, line, band is: 16 114 1 + Current sample, line, band is: 17 114 1 + Current sample, line, band is: 18 114 1 + Current sample, line, band is: 19 114 1 + Current sample, line, band is: 20 114 1 + Current sample, line, band is: 21 114 1 + Current sample, line, band is: 22 114 1 + Current sample, line, band is: 23 114 1 + Current sample, line, band is: 24 114 1 + Current sample, line, band is: 25 114 1 + Current sample, line, band is: 26 114 1 + Current sample, line, band is: 27 114 1 + Current sample, line, band is: 28 114 1 + Current sample, line, band is: 29 114 1 + Current sample, line, band is: 30 114 1 + Current sample, line, band is: 31 114 1 + Current sample, line, band is: 32 114 1 + Current sample, line, band is: 33 114 1 + Current sample, line, band is: 34 114 1 + Current sample, line, band is: 35 114 1 + Current sample, line, band is: 36 114 1 + Current sample, line, band is: 37 114 1 + Current sample, line, band is: 38 114 1 + Current sample, line, band is: 39 114 1 + Current sample, line, band is: 40 114 1 + Current sample, line, band is: 41 114 1 + Current sample, line, band is: 42 114 1 + Current sample, line, band is: 43 114 1 + Current sample, line, band is: 44 114 1 + Current sample, line, band is: 45 114 1 + Current sample, line, band is: 46 114 1 + Current sample, line, band is: 47 114 1 + Current sample, line, band is: 48 114 1 + Current sample, line, band is: 49 114 1 + Current sample, line, band is: 50 114 1 + Current sample, line, band is: 51 114 1 + Current sample, line, band is: 52 114 1 + Current sample, line, band is: 53 114 1 + Current sample, line, band is: 54 114 1 + Current sample, line, band is: 55 114 1 + Current sample, line, band is: 56 114 1 + Current sample, line, band is: 57 114 1 + Current sample, line, band is: 58 114 1 + Current sample, line, band is: 59 114 1 + Current sample, line, band is: 60 114 1 + Current sample, line, band is: 61 114 1 + Current sample, line, band is: 62 114 1 + Current sample, line, band is: 63 114 1 + Current sample, line, band is: 64 114 1 + Current sample, line, band is: 65 114 1 + Current sample, line, band is: 66 114 1 + Current sample, line, band is: 67 114 1 + Current sample, line, band is: 68 114 1 + Current sample, line, band is: 69 114 1 + Current sample, line, band is: 70 114 1 + Current sample, line, band is: 71 114 1 + Current sample, line, band is: 72 114 1 + Current sample, line, band is: 73 114 1 + Current sample, line, band is: 74 114 1 + Current sample, line, band is: 75 114 1 + Current sample, line, band is: 76 114 1 + Current sample, line, band is: 77 114 1 + Current sample, line, band is: 78 114 1 + Current sample, line, band is: 79 114 1 + Current sample, line, band is: 80 114 1 + Current sample, line, band is: 81 114 1 + Current sample, line, band is: 82 114 1 + Current sample, line, band is: 83 114 1 + Current sample, line, band is: 84 114 1 + Current sample, line, band is: 85 114 1 + Current sample, line, band is: 86 114 1 + Current sample, line, band is: 87 114 1 + Current sample, line, band is: 88 114 1 + Current sample, line, band is: 89 114 1 + Current sample, line, band is: 90 114 1 + Current sample, line, band is: 91 114 1 + Current sample, line, band is: 92 114 1 + Current sample, line, band is: 93 114 1 + Current sample, line, band is: 94 114 1 + Current sample, line, band is: 95 114 1 + Current sample, line, band is: 96 114 1 + Current sample, line, band is: 97 114 1 + Current sample, line, band is: 98 114 1 + Current sample, line, band is: 99 114 1 + Current sample, line, band is: 100 114 1 + Current sample, line, band is: 101 114 1 + Current sample, line, band is: 102 114 1 + Current sample, line, band is: 103 114 1 + Current sample, line, band is: 104 114 1 + Current sample, line, band is: 105 114 1 + Current sample, line, band is: 106 114 1 + Current sample, line, band is: 107 114 1 + Current sample, line, band is: 108 114 1 + Current sample, line, band is: 109 114 1 + Current sample, line, band is: 110 114 1 + Current sample, line, band is: 111 114 1 + Current sample, line, band is: 112 114 1 + Current sample, line, band is: 113 114 1 + Current sample, line, band is: 114 114 1 + Current sample, line, band is: 115 114 1 + Current sample, line, band is: 116 114 1 + Current sample, line, band is: 117 114 1 + Current sample, line, band is: 118 114 1 + Current sample, line, band is: 119 114 1 + Current sample, line, band is: 120 114 1 + Current sample, line, band is: 121 114 1 + Current sample, line, band is: 122 114 1 + Current sample, line, band is: 123 114 1 + Current sample, line, band is: 124 114 1 + Current sample, line, band is: 125 114 1 + Current sample, line, band is: 126 114 1 + Current sample, line, band is: 1 115 1 + Current sample, line, band is: 2 115 1 + Current sample, line, band is: 3 115 1 + Current sample, line, band is: 4 115 1 + Current sample, line, band is: 5 115 1 + Current sample, line, band is: 6 115 1 + Current sample, line, band is: 7 115 1 + Current sample, line, band is: 8 115 1 + Current sample, line, band is: 9 115 1 + Current sample, line, band is: 10 115 1 + Current sample, line, band is: 11 115 1 + Current sample, line, band is: 12 115 1 + Current sample, line, band is: 13 115 1 + Current sample, line, band is: 14 115 1 + Current sample, line, band is: 15 115 1 + Current sample, line, band is: 16 115 1 + Current sample, line, band is: 17 115 1 + Current sample, line, band is: 18 115 1 + Current sample, line, band is: 19 115 1 + Current sample, line, band is: 20 115 1 + Current sample, line, band is: 21 115 1 + Current sample, line, band is: 22 115 1 + Current sample, line, band is: 23 115 1 + Current sample, line, band is: 24 115 1 + Current sample, line, band is: 25 115 1 + Current sample, line, band is: 26 115 1 + Current sample, line, band is: 27 115 1 + Current sample, line, band is: 28 115 1 + Current sample, line, band is: 29 115 1 + Current sample, line, band is: 30 115 1 + Current sample, line, band is: 31 115 1 + Current sample, line, band is: 32 115 1 + Current sample, line, band is: 33 115 1 + Current sample, line, band is: 34 115 1 + Current sample, line, band is: 35 115 1 + Current sample, line, band is: 36 115 1 + Current sample, line, band is: 37 115 1 + Current sample, line, band is: 38 115 1 + Current sample, line, band is: 39 115 1 + Current sample, line, band is: 40 115 1 + Current sample, line, band is: 41 115 1 + Current sample, line, band is: 42 115 1 + Current sample, line, band is: 43 115 1 + Current sample, line, band is: 44 115 1 + Current sample, line, band is: 45 115 1 + Current sample, line, band is: 46 115 1 + Current sample, line, band is: 47 115 1 + Current sample, line, band is: 48 115 1 + Current sample, line, band is: 49 115 1 + Current sample, line, band is: 50 115 1 + Current sample, line, band is: 51 115 1 + Current sample, line, band is: 52 115 1 + Current sample, line, band is: 53 115 1 + Current sample, line, band is: 54 115 1 + Current sample, line, band is: 55 115 1 + Current sample, line, band is: 56 115 1 + Current sample, line, band is: 57 115 1 + Current sample, line, band is: 58 115 1 + Current sample, line, band is: 59 115 1 + Current sample, line, band is: 60 115 1 + Current sample, line, band is: 61 115 1 + Current sample, line, band is: 62 115 1 + Current sample, line, band is: 63 115 1 + Current sample, line, band is: 64 115 1 + Current sample, line, band is: 65 115 1 + Current sample, line, band is: 66 115 1 + Current sample, line, band is: 67 115 1 + Current sample, line, band is: 68 115 1 + Current sample, line, band is: 69 115 1 + Current sample, line, band is: 70 115 1 + Current sample, line, band is: 71 115 1 + Current sample, line, band is: 72 115 1 + Current sample, line, band is: 73 115 1 + Current sample, line, band is: 74 115 1 + Current sample, line, band is: 75 115 1 + Current sample, line, band is: 76 115 1 + Current sample, line, band is: 77 115 1 + Current sample, line, band is: 78 115 1 + Current sample, line, band is: 79 115 1 + Current sample, line, band is: 80 115 1 + Current sample, line, band is: 81 115 1 + Current sample, line, band is: 82 115 1 + Current sample, line, band is: 83 115 1 + Current sample, line, band is: 84 115 1 + Current sample, line, band is: 85 115 1 + Current sample, line, band is: 86 115 1 + Current sample, line, band is: 87 115 1 + Current sample, line, band is: 88 115 1 + Current sample, line, band is: 89 115 1 + Current sample, line, band is: 90 115 1 + Current sample, line, band is: 91 115 1 + Current sample, line, band is: 92 115 1 + Current sample, line, band is: 93 115 1 + Current sample, line, band is: 94 115 1 + Current sample, line, band is: 95 115 1 + Current sample, line, band is: 96 115 1 + Current sample, line, band is: 97 115 1 + Current sample, line, band is: 98 115 1 + Current sample, line, band is: 99 115 1 + Current sample, line, band is: 100 115 1 + Current sample, line, band is: 101 115 1 + Current sample, line, band is: 102 115 1 + Current sample, line, band is: 103 115 1 + Current sample, line, band is: 104 115 1 + Current sample, line, band is: 105 115 1 + Current sample, line, band is: 106 115 1 + Current sample, line, band is: 107 115 1 + Current sample, line, band is: 108 115 1 + Current sample, line, band is: 109 115 1 + Current sample, line, band is: 110 115 1 + Current sample, line, band is: 111 115 1 + Current sample, line, band is: 112 115 1 + Current sample, line, band is: 113 115 1 + Current sample, line, band is: 114 115 1 + Current sample, line, band is: 115 115 1 + Current sample, line, band is: 116 115 1 + Current sample, line, band is: 117 115 1 + Current sample, line, band is: 118 115 1 + Current sample, line, band is: 119 115 1 + Current sample, line, band is: 120 115 1 + Current sample, line, band is: 121 115 1 + Current sample, line, band is: 122 115 1 + Current sample, line, band is: 123 115 1 + Current sample, line, band is: 124 115 1 + Current sample, line, band is: 125 115 1 + Current sample, line, band is: 126 115 1 + Current sample, line, band is: 1 116 1 + Current sample, line, band is: 2 116 1 + Current sample, line, band is: 3 116 1 + Current sample, line, band is: 4 116 1 + Current sample, line, band is: 5 116 1 + Current sample, line, band is: 6 116 1 + Current sample, line, band is: 7 116 1 + Current sample, line, band is: 8 116 1 + Current sample, line, band is: 9 116 1 + Current sample, line, band is: 10 116 1 + Current sample, line, band is: 11 116 1 + Current sample, line, band is: 12 116 1 + Current sample, line, band is: 13 116 1 + Current sample, line, band is: 14 116 1 + Current sample, line, band is: 15 116 1 + Current sample, line, band is: 16 116 1 + Current sample, line, band is: 17 116 1 + Current sample, line, band is: 18 116 1 + Current sample, line, band is: 19 116 1 + Current sample, line, band is: 20 116 1 + Current sample, line, band is: 21 116 1 + Current sample, line, band is: 22 116 1 + Current sample, line, band is: 23 116 1 + Current sample, line, band is: 24 116 1 + Current sample, line, band is: 25 116 1 + Current sample, line, band is: 26 116 1 + Current sample, line, band is: 27 116 1 + Current sample, line, band is: 28 116 1 + Current sample, line, band is: 29 116 1 + Current sample, line, band is: 30 116 1 + Current sample, line, band is: 31 116 1 + Current sample, line, band is: 32 116 1 + Current sample, line, band is: 33 116 1 + Current sample, line, band is: 34 116 1 + Current sample, line, band is: 35 116 1 + Current sample, line, band is: 36 116 1 + Current sample, line, band is: 37 116 1 + Current sample, line, band is: 38 116 1 + Current sample, line, band is: 39 116 1 + Current sample, line, band is: 40 116 1 + Current sample, line, band is: 41 116 1 + Current sample, line, band is: 42 116 1 + Current sample, line, band is: 43 116 1 + Current sample, line, band is: 44 116 1 + Current sample, line, band is: 45 116 1 + Current sample, line, band is: 46 116 1 + Current sample, line, band is: 47 116 1 + Current sample, line, band is: 48 116 1 + Current sample, line, band is: 49 116 1 + Current sample, line, band is: 50 116 1 + Current sample, line, band is: 51 116 1 + Current sample, line, band is: 52 116 1 + Current sample, line, band is: 53 116 1 + Current sample, line, band is: 54 116 1 + Current sample, line, band is: 55 116 1 + Current sample, line, band is: 56 116 1 + Current sample, line, band is: 57 116 1 + Current sample, line, band is: 58 116 1 + Current sample, line, band is: 59 116 1 + Current sample, line, band is: 60 116 1 + Current sample, line, band is: 61 116 1 + Current sample, line, band is: 62 116 1 + Current sample, line, band is: 63 116 1 + Current sample, line, band is: 64 116 1 + Current sample, line, band is: 65 116 1 + Current sample, line, band is: 66 116 1 + Current sample, line, band is: 67 116 1 + Current sample, line, band is: 68 116 1 + Current sample, line, band is: 69 116 1 + Current sample, line, band is: 70 116 1 + Current sample, line, band is: 71 116 1 + Current sample, line, band is: 72 116 1 + Current sample, line, band is: 73 116 1 + Current sample, line, band is: 74 116 1 + Current sample, line, band is: 75 116 1 + Current sample, line, band is: 76 116 1 + Current sample, line, band is: 77 116 1 + Current sample, line, band is: 78 116 1 + Current sample, line, band is: 79 116 1 + Current sample, line, band is: 80 116 1 + Current sample, line, band is: 81 116 1 + Current sample, line, band is: 82 116 1 + Current sample, line, band is: 83 116 1 + Current sample, line, band is: 84 116 1 + Current sample, line, band is: 85 116 1 + Current sample, line, band is: 86 116 1 + Current sample, line, band is: 87 116 1 + Current sample, line, band is: 88 116 1 + Current sample, line, band is: 89 116 1 + Current sample, line, band is: 90 116 1 + Current sample, line, band is: 91 116 1 + Current sample, line, band is: 92 116 1 + Current sample, line, band is: 93 116 1 + Current sample, line, band is: 94 116 1 + Current sample, line, band is: 95 116 1 + Current sample, line, band is: 96 116 1 + Current sample, line, band is: 97 116 1 + Current sample, line, band is: 98 116 1 + Current sample, line, band is: 99 116 1 + Current sample, line, band is: 100 116 1 + Current sample, line, band is: 101 116 1 + Current sample, line, band is: 102 116 1 + Current sample, line, band is: 103 116 1 + Current sample, line, band is: 104 116 1 + Current sample, line, band is: 105 116 1 + Current sample, line, band is: 106 116 1 + Current sample, line, band is: 107 116 1 + Current sample, line, band is: 108 116 1 + Current sample, line, band is: 109 116 1 + Current sample, line, band is: 110 116 1 + Current sample, line, band is: 111 116 1 + Current sample, line, band is: 112 116 1 + Current sample, line, band is: 113 116 1 + Current sample, line, band is: 114 116 1 + Current sample, line, band is: 115 116 1 + Current sample, line, band is: 116 116 1 + Current sample, line, band is: 117 116 1 + Current sample, line, band is: 118 116 1 + Current sample, line, band is: 119 116 1 + Current sample, line, band is: 120 116 1 + Current sample, line, band is: 121 116 1 + Current sample, line, band is: 122 116 1 + Current sample, line, band is: 123 116 1 + Current sample, line, band is: 124 116 1 + Current sample, line, band is: 125 116 1 + Current sample, line, band is: 126 116 1 + Current sample, line, band is: 1 117 1 + Current sample, line, band is: 2 117 1 + Current sample, line, band is: 3 117 1 + Current sample, line, band is: 4 117 1 + Current sample, line, band is: 5 117 1 + Current sample, line, band is: 6 117 1 + Current sample, line, band is: 7 117 1 + Current sample, line, band is: 8 117 1 + Current sample, line, band is: 9 117 1 + Current sample, line, band is: 10 117 1 + Current sample, line, band is: 11 117 1 + Current sample, line, band is: 12 117 1 + Current sample, line, band is: 13 117 1 + Current sample, line, band is: 14 117 1 + Current sample, line, band is: 15 117 1 + Current sample, line, band is: 16 117 1 + Current sample, line, band is: 17 117 1 + Current sample, line, band is: 18 117 1 + Current sample, line, band is: 19 117 1 + Current sample, line, band is: 20 117 1 + Current sample, line, band is: 21 117 1 + Current sample, line, band is: 22 117 1 + Current sample, line, band is: 23 117 1 + Current sample, line, band is: 24 117 1 + Current sample, line, band is: 25 117 1 + Current sample, line, band is: 26 117 1 + Current sample, line, band is: 27 117 1 + Current sample, line, band is: 28 117 1 + Current sample, line, band is: 29 117 1 + Current sample, line, band is: 30 117 1 + Current sample, line, band is: 31 117 1 + Current sample, line, band is: 32 117 1 + Current sample, line, band is: 33 117 1 + Current sample, line, band is: 34 117 1 + Current sample, line, band is: 35 117 1 + Current sample, line, band is: 36 117 1 + Current sample, line, band is: 37 117 1 + Current sample, line, band is: 38 117 1 + Current sample, line, band is: 39 117 1 + Current sample, line, band is: 40 117 1 + Current sample, line, band is: 41 117 1 + Current sample, line, band is: 42 117 1 + Current sample, line, band is: 43 117 1 + Current sample, line, band is: 44 117 1 + Current sample, line, band is: 45 117 1 + Current sample, line, band is: 46 117 1 + Current sample, line, band is: 47 117 1 + Current sample, line, band is: 48 117 1 + Current sample, line, band is: 49 117 1 + Current sample, line, band is: 50 117 1 + Current sample, line, band is: 51 117 1 + Current sample, line, band is: 52 117 1 + Current sample, line, band is: 53 117 1 + Current sample, line, band is: 54 117 1 + Current sample, line, band is: 55 117 1 + Current sample, line, band is: 56 117 1 + Current sample, line, band is: 57 117 1 + Current sample, line, band is: 58 117 1 + Current sample, line, band is: 59 117 1 + Current sample, line, band is: 60 117 1 + Current sample, line, band is: 61 117 1 + Current sample, line, band is: 62 117 1 + Current sample, line, band is: 63 117 1 + Current sample, line, band is: 64 117 1 + Current sample, line, band is: 65 117 1 + Current sample, line, band is: 66 117 1 + Current sample, line, band is: 67 117 1 + Current sample, line, band is: 68 117 1 + Current sample, line, band is: 69 117 1 + Current sample, line, band is: 70 117 1 + Current sample, line, band is: 71 117 1 + Current sample, line, band is: 72 117 1 + Current sample, line, band is: 73 117 1 + Current sample, line, band is: 74 117 1 + Current sample, line, band is: 75 117 1 + Current sample, line, band is: 76 117 1 + Current sample, line, band is: 77 117 1 + Current sample, line, band is: 78 117 1 + Current sample, line, band is: 79 117 1 + Current sample, line, band is: 80 117 1 + Current sample, line, band is: 81 117 1 + Current sample, line, band is: 82 117 1 + Current sample, line, band is: 83 117 1 + Current sample, line, band is: 84 117 1 + Current sample, line, band is: 85 117 1 + Current sample, line, band is: 86 117 1 + Current sample, line, band is: 87 117 1 + Current sample, line, band is: 88 117 1 + Current sample, line, band is: 89 117 1 + Current sample, line, band is: 90 117 1 + Current sample, line, band is: 91 117 1 + Current sample, line, band is: 92 117 1 + Current sample, line, band is: 93 117 1 + Current sample, line, band is: 94 117 1 + Current sample, line, band is: 95 117 1 + Current sample, line, band is: 96 117 1 + Current sample, line, band is: 97 117 1 + Current sample, line, band is: 98 117 1 + Current sample, line, band is: 99 117 1 + Current sample, line, band is: 100 117 1 + Current sample, line, band is: 101 117 1 + Current sample, line, band is: 102 117 1 + Current sample, line, band is: 103 117 1 + Current sample, line, band is: 104 117 1 + Current sample, line, band is: 105 117 1 + Current sample, line, band is: 106 117 1 + Current sample, line, band is: 107 117 1 + Current sample, line, band is: 108 117 1 + Current sample, line, band is: 109 117 1 + Current sample, line, band is: 110 117 1 + Current sample, line, band is: 111 117 1 + Current sample, line, band is: 112 117 1 + Current sample, line, band is: 113 117 1 + Current sample, line, band is: 114 117 1 + Current sample, line, band is: 115 117 1 + Current sample, line, band is: 116 117 1 + Current sample, line, band is: 117 117 1 + Current sample, line, band is: 118 117 1 + Current sample, line, band is: 119 117 1 + Current sample, line, band is: 120 117 1 + Current sample, line, band is: 121 117 1 + Current sample, line, band is: 122 117 1 + Current sample, line, band is: 123 117 1 + Current sample, line, band is: 124 117 1 + Current sample, line, band is: 125 117 1 + Current sample, line, band is: 126 117 1 + Current sample, line, band is: 1 118 1 + Current sample, line, band is: 2 118 1 + Current sample, line, band is: 3 118 1 + Current sample, line, band is: 4 118 1 + Current sample, line, band is: 5 118 1 + Current sample, line, band is: 6 118 1 + Current sample, line, band is: 7 118 1 + Current sample, line, band is: 8 118 1 + Current sample, line, band is: 9 118 1 + Current sample, line, band is: 10 118 1 + Current sample, line, band is: 11 118 1 + Current sample, line, band is: 12 118 1 + Current sample, line, band is: 13 118 1 + Current sample, line, band is: 14 118 1 + Current sample, line, band is: 15 118 1 + Current sample, line, band is: 16 118 1 + Current sample, line, band is: 17 118 1 + Current sample, line, band is: 18 118 1 + Current sample, line, band is: 19 118 1 + Current sample, line, band is: 20 118 1 + Current sample, line, band is: 21 118 1 + Current sample, line, band is: 22 118 1 + Current sample, line, band is: 23 118 1 + Current sample, line, band is: 24 118 1 + Current sample, line, band is: 25 118 1 + Current sample, line, band is: 26 118 1 + Current sample, line, band is: 27 118 1 + Current sample, line, band is: 28 118 1 + Current sample, line, band is: 29 118 1 + Current sample, line, band is: 30 118 1 + Current sample, line, band is: 31 118 1 + Current sample, line, band is: 32 118 1 + Current sample, line, band is: 33 118 1 + Current sample, line, band is: 34 118 1 + Current sample, line, band is: 35 118 1 + Current sample, line, band is: 36 118 1 + Current sample, line, band is: 37 118 1 + Current sample, line, band is: 38 118 1 + Current sample, line, band is: 39 118 1 + Current sample, line, band is: 40 118 1 + Current sample, line, band is: 41 118 1 + Current sample, line, band is: 42 118 1 + Current sample, line, band is: 43 118 1 + Current sample, line, band is: 44 118 1 + Current sample, line, band is: 45 118 1 + Current sample, line, band is: 46 118 1 + Current sample, line, band is: 47 118 1 + Current sample, line, band is: 48 118 1 + Current sample, line, band is: 49 118 1 + Current sample, line, band is: 50 118 1 + Current sample, line, band is: 51 118 1 + Current sample, line, band is: 52 118 1 + Current sample, line, band is: 53 118 1 + Current sample, line, band is: 54 118 1 + Current sample, line, band is: 55 118 1 + Current sample, line, band is: 56 118 1 + Current sample, line, band is: 57 118 1 + Current sample, line, band is: 58 118 1 + Current sample, line, band is: 59 118 1 + Current sample, line, band is: 60 118 1 + Current sample, line, band is: 61 118 1 + Current sample, line, band is: 62 118 1 + Current sample, line, band is: 63 118 1 + Current sample, line, band is: 64 118 1 + Current sample, line, band is: 65 118 1 + Current sample, line, band is: 66 118 1 + Current sample, line, band is: 67 118 1 + Current sample, line, band is: 68 118 1 + Current sample, line, band is: 69 118 1 + Current sample, line, band is: 70 118 1 + Current sample, line, band is: 71 118 1 + Current sample, line, band is: 72 118 1 + Current sample, line, band is: 73 118 1 + Current sample, line, band is: 74 118 1 + Current sample, line, band is: 75 118 1 + Current sample, line, band is: 76 118 1 + Current sample, line, band is: 77 118 1 + Current sample, line, band is: 78 118 1 + Current sample, line, band is: 79 118 1 + Current sample, line, band is: 80 118 1 + Current sample, line, band is: 81 118 1 + Current sample, line, band is: 82 118 1 + Current sample, line, band is: 83 118 1 + Current sample, line, band is: 84 118 1 + Current sample, line, band is: 85 118 1 + Current sample, line, band is: 86 118 1 + Current sample, line, band is: 87 118 1 + Current sample, line, band is: 88 118 1 + Current sample, line, band is: 89 118 1 + Current sample, line, band is: 90 118 1 + Current sample, line, band is: 91 118 1 + Current sample, line, band is: 92 118 1 + Current sample, line, band is: 93 118 1 + Current sample, line, band is: 94 118 1 + Current sample, line, band is: 95 118 1 + Current sample, line, band is: 96 118 1 + Current sample, line, band is: 97 118 1 + Current sample, line, band is: 98 118 1 + Current sample, line, band is: 99 118 1 + Current sample, line, band is: 100 118 1 + Current sample, line, band is: 101 118 1 + Current sample, line, band is: 102 118 1 + Current sample, line, band is: 103 118 1 + Current sample, line, band is: 104 118 1 + Current sample, line, band is: 105 118 1 + Current sample, line, band is: 106 118 1 + Current sample, line, band is: 107 118 1 + Current sample, line, band is: 108 118 1 + Current sample, line, band is: 109 118 1 + Current sample, line, band is: 110 118 1 + Current sample, line, band is: 111 118 1 + Current sample, line, band is: 112 118 1 + Current sample, line, band is: 113 118 1 + Current sample, line, band is: 114 118 1 + Current sample, line, band is: 115 118 1 + Current sample, line, band is: 116 118 1 + Current sample, line, band is: 117 118 1 + Current sample, line, band is: 118 118 1 + Current sample, line, band is: 119 118 1 + Current sample, line, band is: 120 118 1 + Current sample, line, band is: 121 118 1 + Current sample, line, band is: 122 118 1 + Current sample, line, band is: 123 118 1 + Current sample, line, band is: 124 118 1 + Current sample, line, band is: 125 118 1 + Current sample, line, band is: 126 118 1 + Current sample, line, band is: 1 119 1 + Current sample, line, band is: 2 119 1 + Current sample, line, band is: 3 119 1 + Current sample, line, band is: 4 119 1 + Current sample, line, band is: 5 119 1 + Current sample, line, band is: 6 119 1 + Current sample, line, band is: 7 119 1 + Current sample, line, band is: 8 119 1 + Current sample, line, band is: 9 119 1 + Current sample, line, band is: 10 119 1 + Current sample, line, band is: 11 119 1 + Current sample, line, band is: 12 119 1 + Current sample, line, band is: 13 119 1 + Current sample, line, band is: 14 119 1 + Current sample, line, band is: 15 119 1 + Current sample, line, band is: 16 119 1 + Current sample, line, band is: 17 119 1 + Current sample, line, band is: 18 119 1 + Current sample, line, band is: 19 119 1 + Current sample, line, band is: 20 119 1 + Current sample, line, band is: 21 119 1 + Current sample, line, band is: 22 119 1 + Current sample, line, band is: 23 119 1 + Current sample, line, band is: 24 119 1 + Current sample, line, band is: 25 119 1 + Current sample, line, band is: 26 119 1 + Current sample, line, band is: 27 119 1 + Current sample, line, band is: 28 119 1 + Current sample, line, band is: 29 119 1 + Current sample, line, band is: 30 119 1 + Current sample, line, band is: 31 119 1 + Current sample, line, band is: 32 119 1 + Current sample, line, band is: 33 119 1 + Current sample, line, band is: 34 119 1 + Current sample, line, band is: 35 119 1 + Current sample, line, band is: 36 119 1 + Current sample, line, band is: 37 119 1 + Current sample, line, band is: 38 119 1 + Current sample, line, band is: 39 119 1 + Current sample, line, band is: 40 119 1 + Current sample, line, band is: 41 119 1 + Current sample, line, band is: 42 119 1 + Current sample, line, band is: 43 119 1 + Current sample, line, band is: 44 119 1 + Current sample, line, band is: 45 119 1 + Current sample, line, band is: 46 119 1 + Current sample, line, band is: 47 119 1 + Current sample, line, band is: 48 119 1 + Current sample, line, band is: 49 119 1 + Current sample, line, band is: 50 119 1 + Current sample, line, band is: 51 119 1 + Current sample, line, band is: 52 119 1 + Current sample, line, band is: 53 119 1 + Current sample, line, band is: 54 119 1 + Current sample, line, band is: 55 119 1 + Current sample, line, band is: 56 119 1 + Current sample, line, band is: 57 119 1 + Current sample, line, band is: 58 119 1 + Current sample, line, band is: 59 119 1 + Current sample, line, band is: 60 119 1 + Current sample, line, band is: 61 119 1 + Current sample, line, band is: 62 119 1 + Current sample, line, band is: 63 119 1 + Current sample, line, band is: 64 119 1 + Current sample, line, band is: 65 119 1 + Current sample, line, band is: 66 119 1 + Current sample, line, band is: 67 119 1 + Current sample, line, band is: 68 119 1 + Current sample, line, band is: 69 119 1 + Current sample, line, band is: 70 119 1 + Current sample, line, band is: 71 119 1 + Current sample, line, band is: 72 119 1 + Current sample, line, band is: 73 119 1 + Current sample, line, band is: 74 119 1 + Current sample, line, band is: 75 119 1 + Current sample, line, band is: 76 119 1 + Current sample, line, band is: 77 119 1 + Current sample, line, band is: 78 119 1 + Current sample, line, band is: 79 119 1 + Current sample, line, band is: 80 119 1 + Current sample, line, band is: 81 119 1 + Current sample, line, band is: 82 119 1 + Current sample, line, band is: 83 119 1 + Current sample, line, band is: 84 119 1 + Current sample, line, band is: 85 119 1 + Current sample, line, band is: 86 119 1 + Current sample, line, band is: 87 119 1 + Current sample, line, band is: 88 119 1 + Current sample, line, band is: 89 119 1 + Current sample, line, band is: 90 119 1 + Current sample, line, band is: 91 119 1 + Current sample, line, band is: 92 119 1 + Current sample, line, band is: 93 119 1 + Current sample, line, band is: 94 119 1 + Current sample, line, band is: 95 119 1 + Current sample, line, band is: 96 119 1 + Current sample, line, band is: 97 119 1 + Current sample, line, band is: 98 119 1 + Current sample, line, band is: 99 119 1 + Current sample, line, band is: 100 119 1 + Current sample, line, band is: 101 119 1 + Current sample, line, band is: 102 119 1 + Current sample, line, band is: 103 119 1 + Current sample, line, band is: 104 119 1 + Current sample, line, band is: 105 119 1 + Current sample, line, band is: 106 119 1 + Current sample, line, band is: 107 119 1 + Current sample, line, band is: 108 119 1 + Current sample, line, band is: 109 119 1 + Current sample, line, band is: 110 119 1 + Current sample, line, band is: 111 119 1 + Current sample, line, band is: 112 119 1 + Current sample, line, band is: 113 119 1 + Current sample, line, band is: 114 119 1 + Current sample, line, band is: 115 119 1 + Current sample, line, band is: 116 119 1 + Current sample, line, band is: 117 119 1 + Current sample, line, band is: 118 119 1 + Current sample, line, band is: 119 119 1 + Current sample, line, band is: 120 119 1 + Current sample, line, band is: 121 119 1 + Current sample, line, band is: 122 119 1 + Current sample, line, band is: 123 119 1 + Current sample, line, band is: 124 119 1 + Current sample, line, band is: 125 119 1 + Current sample, line, band is: 126 119 1 + Current sample, line, band is: 1 120 1 + Current sample, line, band is: 2 120 1 + Current sample, line, band is: 3 120 1 + Current sample, line, band is: 4 120 1 + Current sample, line, band is: 5 120 1 + Current sample, line, band is: 6 120 1 + Current sample, line, band is: 7 120 1 + Current sample, line, band is: 8 120 1 + Current sample, line, band is: 9 120 1 + Current sample, line, band is: 10 120 1 + Current sample, line, band is: 11 120 1 + Current sample, line, band is: 12 120 1 + Current sample, line, band is: 13 120 1 + Current sample, line, band is: 14 120 1 + Current sample, line, band is: 15 120 1 + Current sample, line, band is: 16 120 1 + Current sample, line, band is: 17 120 1 + Current sample, line, band is: 18 120 1 + Current sample, line, band is: 19 120 1 + Current sample, line, band is: 20 120 1 + Current sample, line, band is: 21 120 1 + Current sample, line, band is: 22 120 1 + Current sample, line, band is: 23 120 1 + Current sample, line, band is: 24 120 1 + Current sample, line, band is: 25 120 1 + Current sample, line, band is: 26 120 1 + Current sample, line, band is: 27 120 1 + Current sample, line, band is: 28 120 1 + Current sample, line, band is: 29 120 1 + Current sample, line, band is: 30 120 1 + Current sample, line, band is: 31 120 1 + Current sample, line, band is: 32 120 1 + Current sample, line, band is: 33 120 1 + Current sample, line, band is: 34 120 1 + Current sample, line, band is: 35 120 1 + Current sample, line, band is: 36 120 1 + Current sample, line, band is: 37 120 1 + Current sample, line, band is: 38 120 1 + Current sample, line, band is: 39 120 1 + Current sample, line, band is: 40 120 1 + Current sample, line, band is: 41 120 1 + Current sample, line, band is: 42 120 1 + Current sample, line, band is: 43 120 1 + Current sample, line, band is: 44 120 1 + Current sample, line, band is: 45 120 1 + Current sample, line, band is: 46 120 1 + Current sample, line, band is: 47 120 1 + Current sample, line, band is: 48 120 1 + Current sample, line, band is: 49 120 1 + Current sample, line, band is: 50 120 1 + Current sample, line, band is: 51 120 1 + Current sample, line, band is: 52 120 1 + Current sample, line, band is: 53 120 1 + Current sample, line, band is: 54 120 1 + Current sample, line, band is: 55 120 1 + Current sample, line, band is: 56 120 1 + Current sample, line, band is: 57 120 1 + Current sample, line, band is: 58 120 1 + Current sample, line, band is: 59 120 1 + Current sample, line, band is: 60 120 1 + Current sample, line, band is: 61 120 1 + Current sample, line, band is: 62 120 1 + Current sample, line, band is: 63 120 1 + Current sample, line, band is: 64 120 1 + Current sample, line, band is: 65 120 1 + Current sample, line, band is: 66 120 1 + Current sample, line, band is: 67 120 1 + Current sample, line, band is: 68 120 1 + Current sample, line, band is: 69 120 1 + Current sample, line, band is: 70 120 1 + Current sample, line, band is: 71 120 1 + Current sample, line, band is: 72 120 1 + Current sample, line, band is: 73 120 1 + Current sample, line, band is: 74 120 1 + Current sample, line, band is: 75 120 1 + Current sample, line, band is: 76 120 1 + Current sample, line, band is: 77 120 1 + Current sample, line, band is: 78 120 1 + Current sample, line, band is: 79 120 1 + Current sample, line, band is: 80 120 1 + Current sample, line, band is: 81 120 1 + Current sample, line, band is: 82 120 1 + Current sample, line, band is: 83 120 1 + Current sample, line, band is: 84 120 1 + Current sample, line, band is: 85 120 1 + Current sample, line, band is: 86 120 1 + Current sample, line, band is: 87 120 1 + Current sample, line, band is: 88 120 1 + Current sample, line, band is: 89 120 1 + Current sample, line, band is: 90 120 1 + Current sample, line, band is: 91 120 1 + Current sample, line, band is: 92 120 1 + Current sample, line, band is: 93 120 1 + Current sample, line, band is: 94 120 1 + Current sample, line, band is: 95 120 1 + Current sample, line, band is: 96 120 1 + Current sample, line, band is: 97 120 1 + Current sample, line, band is: 98 120 1 + Current sample, line, band is: 99 120 1 + Current sample, line, band is: 100 120 1 + Current sample, line, band is: 101 120 1 + Current sample, line, band is: 102 120 1 + Current sample, line, band is: 103 120 1 + Current sample, line, band is: 104 120 1 + Current sample, line, band is: 105 120 1 + Current sample, line, band is: 106 120 1 + Current sample, line, band is: 107 120 1 + Current sample, line, band is: 108 120 1 + Current sample, line, band is: 109 120 1 + Current sample, line, band is: 110 120 1 + Current sample, line, band is: 111 120 1 + Current sample, line, band is: 112 120 1 + Current sample, line, band is: 113 120 1 + Current sample, line, band is: 114 120 1 + Current sample, line, band is: 115 120 1 + Current sample, line, band is: 116 120 1 + Current sample, line, band is: 117 120 1 + Current sample, line, band is: 118 120 1 + Current sample, line, band is: 119 120 1 + Current sample, line, band is: 120 120 1 + Current sample, line, band is: 121 120 1 + Current sample, line, band is: 122 120 1 + Current sample, line, band is: 123 120 1 + Current sample, line, band is: 124 120 1 + Current sample, line, band is: 125 120 1 + Current sample, line, band is: 126 120 1 + Current sample, line, band is: 1 121 1 + Current sample, line, band is: 2 121 1 + Current sample, line, band is: 3 121 1 + Current sample, line, band is: 4 121 1 + Current sample, line, band is: 5 121 1 + Current sample, line, band is: 6 121 1 + Current sample, line, band is: 7 121 1 + Current sample, line, band is: 8 121 1 + Current sample, line, band is: 9 121 1 + Current sample, line, band is: 10 121 1 + Current sample, line, band is: 11 121 1 + Current sample, line, band is: 12 121 1 + Current sample, line, band is: 13 121 1 + Current sample, line, band is: 14 121 1 + Current sample, line, band is: 15 121 1 + Current sample, line, band is: 16 121 1 + Current sample, line, band is: 17 121 1 + Current sample, line, band is: 18 121 1 + Current sample, line, band is: 19 121 1 + Current sample, line, band is: 20 121 1 + Current sample, line, band is: 21 121 1 + Current sample, line, band is: 22 121 1 + Current sample, line, band is: 23 121 1 + Current sample, line, band is: 24 121 1 + Current sample, line, band is: 25 121 1 + Current sample, line, band is: 26 121 1 + Current sample, line, band is: 27 121 1 + Current sample, line, band is: 28 121 1 + Current sample, line, band is: 29 121 1 + Current sample, line, band is: 30 121 1 + Current sample, line, band is: 31 121 1 + Current sample, line, band is: 32 121 1 + Current sample, line, band is: 33 121 1 + Current sample, line, band is: 34 121 1 + Current sample, line, band is: 35 121 1 + Current sample, line, band is: 36 121 1 + Current sample, line, band is: 37 121 1 + Current sample, line, band is: 38 121 1 + Current sample, line, band is: 39 121 1 + Current sample, line, band is: 40 121 1 + Current sample, line, band is: 41 121 1 + Current sample, line, band is: 42 121 1 + Current sample, line, band is: 43 121 1 + Current sample, line, band is: 44 121 1 + Current sample, line, band is: 45 121 1 + Current sample, line, band is: 46 121 1 + Current sample, line, band is: 47 121 1 + Current sample, line, band is: 48 121 1 + Current sample, line, band is: 49 121 1 + Current sample, line, band is: 50 121 1 + Current sample, line, band is: 51 121 1 + Current sample, line, band is: 52 121 1 + Current sample, line, band is: 53 121 1 + Current sample, line, band is: 54 121 1 + Current sample, line, band is: 55 121 1 + Current sample, line, band is: 56 121 1 + Current sample, line, band is: 57 121 1 + Current sample, line, band is: 58 121 1 + Current sample, line, band is: 59 121 1 + Current sample, line, band is: 60 121 1 + Current sample, line, band is: 61 121 1 + Current sample, line, band is: 62 121 1 + Current sample, line, band is: 63 121 1 + Current sample, line, band is: 64 121 1 + Current sample, line, band is: 65 121 1 + Current sample, line, band is: 66 121 1 + Current sample, line, band is: 67 121 1 + Current sample, line, band is: 68 121 1 + Current sample, line, band is: 69 121 1 + Current sample, line, band is: 70 121 1 + Current sample, line, band is: 71 121 1 + Current sample, line, band is: 72 121 1 + Current sample, line, band is: 73 121 1 + Current sample, line, band is: 74 121 1 + Current sample, line, band is: 75 121 1 + Current sample, line, band is: 76 121 1 + Current sample, line, band is: 77 121 1 + Current sample, line, band is: 78 121 1 + Current sample, line, band is: 79 121 1 + Current sample, line, band is: 80 121 1 + Current sample, line, band is: 81 121 1 + Current sample, line, band is: 82 121 1 + Current sample, line, band is: 83 121 1 + Current sample, line, band is: 84 121 1 + Current sample, line, band is: 85 121 1 + Current sample, line, band is: 86 121 1 + Current sample, line, band is: 87 121 1 + Current sample, line, band is: 88 121 1 + Current sample, line, band is: 89 121 1 + Current sample, line, band is: 90 121 1 + Current sample, line, band is: 91 121 1 + Current sample, line, band is: 92 121 1 + Current sample, line, band is: 93 121 1 + Current sample, line, band is: 94 121 1 + Current sample, line, band is: 95 121 1 + Current sample, line, band is: 96 121 1 + Current sample, line, band is: 97 121 1 + Current sample, line, band is: 98 121 1 + Current sample, line, band is: 99 121 1 + Current sample, line, band is: 100 121 1 + Current sample, line, band is: 101 121 1 + Current sample, line, band is: 102 121 1 + Current sample, line, band is: 103 121 1 + Current sample, line, band is: 104 121 1 + Current sample, line, band is: 105 121 1 + Current sample, line, band is: 106 121 1 + Current sample, line, band is: 107 121 1 + Current sample, line, band is: 108 121 1 + Current sample, line, band is: 109 121 1 + Current sample, line, band is: 110 121 1 + Current sample, line, band is: 111 121 1 + Current sample, line, band is: 112 121 1 + Current sample, line, band is: 113 121 1 + Current sample, line, band is: 114 121 1 + Current sample, line, band is: 115 121 1 + Current sample, line, band is: 116 121 1 + Current sample, line, band is: 117 121 1 + Current sample, line, band is: 118 121 1 + Current sample, line, band is: 119 121 1 + Current sample, line, band is: 120 121 1 + Current sample, line, band is: 121 121 1 + Current sample, line, band is: 122 121 1 + Current sample, line, band is: 123 121 1 + Current sample, line, band is: 124 121 1 + Current sample, line, band is: 125 121 1 + Current sample, line, band is: 126 121 1 + Current sample, line, band is: 1 122 1 + Current sample, line, band is: 2 122 1 + Current sample, line, band is: 3 122 1 + Current sample, line, band is: 4 122 1 + Current sample, line, band is: 5 122 1 + Current sample, line, band is: 6 122 1 + Current sample, line, band is: 7 122 1 + Current sample, line, band is: 8 122 1 + Current sample, line, band is: 9 122 1 + Current sample, line, band is: 10 122 1 + Current sample, line, band is: 11 122 1 + Current sample, line, band is: 12 122 1 + Current sample, line, band is: 13 122 1 + Current sample, line, band is: 14 122 1 + Current sample, line, band is: 15 122 1 + Current sample, line, band is: 16 122 1 + Current sample, line, band is: 17 122 1 + Current sample, line, band is: 18 122 1 + Current sample, line, band is: 19 122 1 + Current sample, line, band is: 20 122 1 + Current sample, line, band is: 21 122 1 + Current sample, line, band is: 22 122 1 + Current sample, line, band is: 23 122 1 + Current sample, line, band is: 24 122 1 + Current sample, line, band is: 25 122 1 + Current sample, line, band is: 26 122 1 + Current sample, line, band is: 27 122 1 + Current sample, line, band is: 28 122 1 + Current sample, line, band is: 29 122 1 + Current sample, line, band is: 30 122 1 + Current sample, line, band is: 31 122 1 + Current sample, line, band is: 32 122 1 + Current sample, line, band is: 33 122 1 + Current sample, line, band is: 34 122 1 + Current sample, line, band is: 35 122 1 + Current sample, line, band is: 36 122 1 + Current sample, line, band is: 37 122 1 + Current sample, line, band is: 38 122 1 + Current sample, line, band is: 39 122 1 + Current sample, line, band is: 40 122 1 + Current sample, line, band is: 41 122 1 + Current sample, line, band is: 42 122 1 + Current sample, line, band is: 43 122 1 + Current sample, line, band is: 44 122 1 + Current sample, line, band is: 45 122 1 + Current sample, line, band is: 46 122 1 + Current sample, line, band is: 47 122 1 + Current sample, line, band is: 48 122 1 + Current sample, line, band is: 49 122 1 + Current sample, line, band is: 50 122 1 + Current sample, line, band is: 51 122 1 + Current sample, line, band is: 52 122 1 + Current sample, line, band is: 53 122 1 + Current sample, line, band is: 54 122 1 + Current sample, line, band is: 55 122 1 + Current sample, line, band is: 56 122 1 + Current sample, line, band is: 57 122 1 + Current sample, line, band is: 58 122 1 + Current sample, line, band is: 59 122 1 + Current sample, line, band is: 60 122 1 + Current sample, line, band is: 61 122 1 + Current sample, line, band is: 62 122 1 + Current sample, line, band is: 63 122 1 + Current sample, line, band is: 64 122 1 + Current sample, line, band is: 65 122 1 + Current sample, line, band is: 66 122 1 + Current sample, line, band is: 67 122 1 + Current sample, line, band is: 68 122 1 + Current sample, line, band is: 69 122 1 + Current sample, line, band is: 70 122 1 + Current sample, line, band is: 71 122 1 + Current sample, line, band is: 72 122 1 + Current sample, line, band is: 73 122 1 + Current sample, line, band is: 74 122 1 + Current sample, line, band is: 75 122 1 + Current sample, line, band is: 76 122 1 + Current sample, line, band is: 77 122 1 + Current sample, line, band is: 78 122 1 + Current sample, line, band is: 79 122 1 + Current sample, line, band is: 80 122 1 + Current sample, line, band is: 81 122 1 + Current sample, line, band is: 82 122 1 + Current sample, line, band is: 83 122 1 + Current sample, line, band is: 84 122 1 + Current sample, line, band is: 85 122 1 + Current sample, line, band is: 86 122 1 + Current sample, line, band is: 87 122 1 + Current sample, line, band is: 88 122 1 + Current sample, line, band is: 89 122 1 + Current sample, line, band is: 90 122 1 + Current sample, line, band is: 91 122 1 + Current sample, line, band is: 92 122 1 + Current sample, line, band is: 93 122 1 + Current sample, line, band is: 94 122 1 + Current sample, line, band is: 95 122 1 + Current sample, line, band is: 96 122 1 + Current sample, line, band is: 97 122 1 + Current sample, line, band is: 98 122 1 + Current sample, line, band is: 99 122 1 + Current sample, line, band is: 100 122 1 + Current sample, line, band is: 101 122 1 + Current sample, line, band is: 102 122 1 + Current sample, line, band is: 103 122 1 + Current sample, line, band is: 104 122 1 + Current sample, line, band is: 105 122 1 + Current sample, line, band is: 106 122 1 + Current sample, line, band is: 107 122 1 + Current sample, line, band is: 108 122 1 + Current sample, line, band is: 109 122 1 + Current sample, line, band is: 110 122 1 + Current sample, line, band is: 111 122 1 + Current sample, line, band is: 112 122 1 + Current sample, line, band is: 113 122 1 + Current sample, line, band is: 114 122 1 + Current sample, line, band is: 115 122 1 + Current sample, line, band is: 116 122 1 + Current sample, line, band is: 117 122 1 + Current sample, line, band is: 118 122 1 + Current sample, line, band is: 119 122 1 + Current sample, line, band is: 120 122 1 + Current sample, line, band is: 121 122 1 + Current sample, line, band is: 122 122 1 + Current sample, line, band is: 123 122 1 + Current sample, line, band is: 124 122 1 + Current sample, line, band is: 125 122 1 + Current sample, line, band is: 126 122 1 + Current sample, line, band is: 1 123 1 + Current sample, line, band is: 2 123 1 + Current sample, line, band is: 3 123 1 + Current sample, line, band is: 4 123 1 + Current sample, line, band is: 5 123 1 + Current sample, line, band is: 6 123 1 + Current sample, line, band is: 7 123 1 + Current sample, line, band is: 8 123 1 + Current sample, line, band is: 9 123 1 + Current sample, line, band is: 10 123 1 + Current sample, line, band is: 11 123 1 + Current sample, line, band is: 12 123 1 + Current sample, line, band is: 13 123 1 + Current sample, line, band is: 14 123 1 + Current sample, line, band is: 15 123 1 + Current sample, line, band is: 16 123 1 + Current sample, line, band is: 17 123 1 + Current sample, line, band is: 18 123 1 + Current sample, line, band is: 19 123 1 + Current sample, line, band is: 20 123 1 + Current sample, line, band is: 21 123 1 + Current sample, line, band is: 22 123 1 + Current sample, line, band is: 23 123 1 + Current sample, line, band is: 24 123 1 + Current sample, line, band is: 25 123 1 + Current sample, line, band is: 26 123 1 + Current sample, line, band is: 27 123 1 + Current sample, line, band is: 28 123 1 + Current sample, line, band is: 29 123 1 + Current sample, line, band is: 30 123 1 + Current sample, line, band is: 31 123 1 + Current sample, line, band is: 32 123 1 + Current sample, line, band is: 33 123 1 + Current sample, line, band is: 34 123 1 + Current sample, line, band is: 35 123 1 + Current sample, line, band is: 36 123 1 + Current sample, line, band is: 37 123 1 + Current sample, line, band is: 38 123 1 + Current sample, line, band is: 39 123 1 + Current sample, line, band is: 40 123 1 + Current sample, line, band is: 41 123 1 + Current sample, line, band is: 42 123 1 + Current sample, line, band is: 43 123 1 + Current sample, line, band is: 44 123 1 + Current sample, line, band is: 45 123 1 + Current sample, line, band is: 46 123 1 + Current sample, line, band is: 47 123 1 + Current sample, line, band is: 48 123 1 + Current sample, line, band is: 49 123 1 + Current sample, line, band is: 50 123 1 + Current sample, line, band is: 51 123 1 + Current sample, line, band is: 52 123 1 + Current sample, line, band is: 53 123 1 + Current sample, line, band is: 54 123 1 + Current sample, line, band is: 55 123 1 + Current sample, line, band is: 56 123 1 + Current sample, line, band is: 57 123 1 + Current sample, line, band is: 58 123 1 + Current sample, line, band is: 59 123 1 + Current sample, line, band is: 60 123 1 + Current sample, line, band is: 61 123 1 + Current sample, line, band is: 62 123 1 + Current sample, line, band is: 63 123 1 + Current sample, line, band is: 64 123 1 + Current sample, line, band is: 65 123 1 + Current sample, line, band is: 66 123 1 + Current sample, line, band is: 67 123 1 + Current sample, line, band is: 68 123 1 + Current sample, line, band is: 69 123 1 + Current sample, line, band is: 70 123 1 + Current sample, line, band is: 71 123 1 + Current sample, line, band is: 72 123 1 + Current sample, line, band is: 73 123 1 + Current sample, line, band is: 74 123 1 + Current sample, line, band is: 75 123 1 + Current sample, line, band is: 76 123 1 + Current sample, line, band is: 77 123 1 + Current sample, line, band is: 78 123 1 + Current sample, line, band is: 79 123 1 + Current sample, line, band is: 80 123 1 + Current sample, line, band is: 81 123 1 + Current sample, line, band is: 82 123 1 + Current sample, line, band is: 83 123 1 + Current sample, line, band is: 84 123 1 + Current sample, line, band is: 85 123 1 + Current sample, line, band is: 86 123 1 + Current sample, line, band is: 87 123 1 + Current sample, line, band is: 88 123 1 + Current sample, line, band is: 89 123 1 + Current sample, line, band is: 90 123 1 + Current sample, line, band is: 91 123 1 + Current sample, line, band is: 92 123 1 + Current sample, line, band is: 93 123 1 + Current sample, line, band is: 94 123 1 + Current sample, line, band is: 95 123 1 + Current sample, line, band is: 96 123 1 + Current sample, line, band is: 97 123 1 + Current sample, line, band is: 98 123 1 + Current sample, line, band is: 99 123 1 + Current sample, line, band is: 100 123 1 + Current sample, line, band is: 101 123 1 + Current sample, line, band is: 102 123 1 + Current sample, line, band is: 103 123 1 + Current sample, line, band is: 104 123 1 + Current sample, line, band is: 105 123 1 + Current sample, line, band is: 106 123 1 + Current sample, line, band is: 107 123 1 + Current sample, line, band is: 108 123 1 + Current sample, line, band is: 109 123 1 + Current sample, line, band is: 110 123 1 + Current sample, line, band is: 111 123 1 + Current sample, line, band is: 112 123 1 + Current sample, line, band is: 113 123 1 + Current sample, line, band is: 114 123 1 + Current sample, line, band is: 115 123 1 + Current sample, line, band is: 116 123 1 + Current sample, line, band is: 117 123 1 + Current sample, line, band is: 118 123 1 + Current sample, line, band is: 119 123 1 + Current sample, line, band is: 120 123 1 + Current sample, line, band is: 121 123 1 + Current sample, line, band is: 122 123 1 + Current sample, line, band is: 123 123 1 + Current sample, line, band is: 124 123 1 + Current sample, line, band is: 125 123 1 + Current sample, line, band is: 126 123 1 + Current sample, line, band is: 1 124 1 + Current sample, line, band is: 2 124 1 + Current sample, line, band is: 3 124 1 + Current sample, line, band is: 4 124 1 + Current sample, line, band is: 5 124 1 + Current sample, line, band is: 6 124 1 + Current sample, line, band is: 7 124 1 + Current sample, line, band is: 8 124 1 + Current sample, line, band is: 9 124 1 + Current sample, line, band is: 10 124 1 + Current sample, line, band is: 11 124 1 + Current sample, line, band is: 12 124 1 + Current sample, line, band is: 13 124 1 + Current sample, line, band is: 14 124 1 + Current sample, line, band is: 15 124 1 + Current sample, line, band is: 16 124 1 + Current sample, line, band is: 17 124 1 + Current sample, line, band is: 18 124 1 + Current sample, line, band is: 19 124 1 + Current sample, line, band is: 20 124 1 + Current sample, line, band is: 21 124 1 + Current sample, line, band is: 22 124 1 + Current sample, line, band is: 23 124 1 + Current sample, line, band is: 24 124 1 + Current sample, line, band is: 25 124 1 + Current sample, line, band is: 26 124 1 + Current sample, line, band is: 27 124 1 + Current sample, line, band is: 28 124 1 + Current sample, line, band is: 29 124 1 + Current sample, line, band is: 30 124 1 + Current sample, line, band is: 31 124 1 + Current sample, line, band is: 32 124 1 + Current sample, line, band is: 33 124 1 + Current sample, line, band is: 34 124 1 + Current sample, line, band is: 35 124 1 + Current sample, line, band is: 36 124 1 + Current sample, line, band is: 37 124 1 + Current sample, line, band is: 38 124 1 + Current sample, line, band is: 39 124 1 + Current sample, line, band is: 40 124 1 + Current sample, line, band is: 41 124 1 + Current sample, line, band is: 42 124 1 + Current sample, line, band is: 43 124 1 + Current sample, line, band is: 44 124 1 + Current sample, line, band is: 45 124 1 + Current sample, line, band is: 46 124 1 + Current sample, line, band is: 47 124 1 + Current sample, line, band is: 48 124 1 + Current sample, line, band is: 49 124 1 + Current sample, line, band is: 50 124 1 + Current sample, line, band is: 51 124 1 + Current sample, line, band is: 52 124 1 + Current sample, line, band is: 53 124 1 + Current sample, line, band is: 54 124 1 + Current sample, line, band is: 55 124 1 + Current sample, line, band is: 56 124 1 + Current sample, line, band is: 57 124 1 + Current sample, line, band is: 58 124 1 + Current sample, line, band is: 59 124 1 + Current sample, line, band is: 60 124 1 + Current sample, line, band is: 61 124 1 + Current sample, line, band is: 62 124 1 + Current sample, line, band is: 63 124 1 + Current sample, line, band is: 64 124 1 + Current sample, line, band is: 65 124 1 + Current sample, line, band is: 66 124 1 + Current sample, line, band is: 67 124 1 + Current sample, line, band is: 68 124 1 + Current sample, line, band is: 69 124 1 + Current sample, line, band is: 70 124 1 + Current sample, line, band is: 71 124 1 + Current sample, line, band is: 72 124 1 + Current sample, line, band is: 73 124 1 + Current sample, line, band is: 74 124 1 + Current sample, line, band is: 75 124 1 + Current sample, line, band is: 76 124 1 + Current sample, line, band is: 77 124 1 + Current sample, line, band is: 78 124 1 + Current sample, line, band is: 79 124 1 + Current sample, line, band is: 80 124 1 + Current sample, line, band is: 81 124 1 + Current sample, line, band is: 82 124 1 + Current sample, line, band is: 83 124 1 + Current sample, line, band is: 84 124 1 + Current sample, line, band is: 85 124 1 + Current sample, line, band is: 86 124 1 + Current sample, line, band is: 87 124 1 + Current sample, line, band is: 88 124 1 + Current sample, line, band is: 89 124 1 + Current sample, line, band is: 90 124 1 + Current sample, line, band is: 91 124 1 + Current sample, line, band is: 92 124 1 + Current sample, line, band is: 93 124 1 + Current sample, line, band is: 94 124 1 + Current sample, line, band is: 95 124 1 + Current sample, line, band is: 96 124 1 + Current sample, line, band is: 97 124 1 + Current sample, line, band is: 98 124 1 + Current sample, line, band is: 99 124 1 + Current sample, line, band is: 100 124 1 + Current sample, line, band is: 101 124 1 + Current sample, line, band is: 102 124 1 + Current sample, line, band is: 103 124 1 + Current sample, line, band is: 104 124 1 + Current sample, line, band is: 105 124 1 + Current sample, line, band is: 106 124 1 + Current sample, line, band is: 107 124 1 + Current sample, line, band is: 108 124 1 + Current sample, line, band is: 109 124 1 + Current sample, line, band is: 110 124 1 + Current sample, line, band is: 111 124 1 + Current sample, line, band is: 112 124 1 + Current sample, line, band is: 113 124 1 + Current sample, line, band is: 114 124 1 + Current sample, line, band is: 115 124 1 + Current sample, line, band is: 116 124 1 + Current sample, line, band is: 117 124 1 + Current sample, line, band is: 118 124 1 + Current sample, line, band is: 119 124 1 + Current sample, line, band is: 120 124 1 + Current sample, line, band is: 121 124 1 + Current sample, line, band is: 122 124 1 + Current sample, line, band is: 123 124 1 + Current sample, line, band is: 124 124 1 + Current sample, line, band is: 125 124 1 + Current sample, line, band is: 126 124 1 + Current sample, line, band is: 1 125 1 + Current sample, line, band is: 2 125 1 + Current sample, line, band is: 3 125 1 + Current sample, line, band is: 4 125 1 + Current sample, line, band is: 5 125 1 + Current sample, line, band is: 6 125 1 + Current sample, line, band is: 7 125 1 + Current sample, line, band is: 8 125 1 + Current sample, line, band is: 9 125 1 + Current sample, line, band is: 10 125 1 + Current sample, line, band is: 11 125 1 + Current sample, line, band is: 12 125 1 + Current sample, line, band is: 13 125 1 + Current sample, line, band is: 14 125 1 + Current sample, line, band is: 15 125 1 + Current sample, line, band is: 16 125 1 + Current sample, line, band is: 17 125 1 + Current sample, line, band is: 18 125 1 + Current sample, line, band is: 19 125 1 + Current sample, line, band is: 20 125 1 + Current sample, line, band is: 21 125 1 + Current sample, line, band is: 22 125 1 + Current sample, line, band is: 23 125 1 + Current sample, line, band is: 24 125 1 + Current sample, line, band is: 25 125 1 + Current sample, line, band is: 26 125 1 + Current sample, line, band is: 27 125 1 + Current sample, line, band is: 28 125 1 + Current sample, line, band is: 29 125 1 + Current sample, line, band is: 30 125 1 + Current sample, line, band is: 31 125 1 + Current sample, line, band is: 32 125 1 + Current sample, line, band is: 33 125 1 + Current sample, line, band is: 34 125 1 + Current sample, line, band is: 35 125 1 + Current sample, line, band is: 36 125 1 + Current sample, line, band is: 37 125 1 + Current sample, line, band is: 38 125 1 + Current sample, line, band is: 39 125 1 + Current sample, line, band is: 40 125 1 + Current sample, line, band is: 41 125 1 + Current sample, line, band is: 42 125 1 + Current sample, line, band is: 43 125 1 + Current sample, line, band is: 44 125 1 + Current sample, line, band is: 45 125 1 + Current sample, line, band is: 46 125 1 + Current sample, line, band is: 47 125 1 + Current sample, line, band is: 48 125 1 + Current sample, line, band is: 49 125 1 + Current sample, line, band is: 50 125 1 + Current sample, line, band is: 51 125 1 + Current sample, line, band is: 52 125 1 + Current sample, line, band is: 53 125 1 + Current sample, line, band is: 54 125 1 + Current sample, line, band is: 55 125 1 + Current sample, line, band is: 56 125 1 + Current sample, line, band is: 57 125 1 + Current sample, line, band is: 58 125 1 + Current sample, line, band is: 59 125 1 + Current sample, line, band is: 60 125 1 + Current sample, line, band is: 61 125 1 + Current sample, line, band is: 62 125 1 + Current sample, line, band is: 63 125 1 + Current sample, line, band is: 64 125 1 + Current sample, line, band is: 65 125 1 + Current sample, line, band is: 66 125 1 + Current sample, line, band is: 67 125 1 + Current sample, line, band is: 68 125 1 + Current sample, line, band is: 69 125 1 + Current sample, line, band is: 70 125 1 + Current sample, line, band is: 71 125 1 + Current sample, line, band is: 72 125 1 + Current sample, line, band is: 73 125 1 + Current sample, line, band is: 74 125 1 + Current sample, line, band is: 75 125 1 + Current sample, line, band is: 76 125 1 + Current sample, line, band is: 77 125 1 + Current sample, line, band is: 78 125 1 + Current sample, line, band is: 79 125 1 + Current sample, line, band is: 80 125 1 + Current sample, line, band is: 81 125 1 + Current sample, line, band is: 82 125 1 + Current sample, line, band is: 83 125 1 + Current sample, line, band is: 84 125 1 + Current sample, line, band is: 85 125 1 + Current sample, line, band is: 86 125 1 + Current sample, line, band is: 87 125 1 + Current sample, line, band is: 88 125 1 + Current sample, line, band is: 89 125 1 + Current sample, line, band is: 90 125 1 + Current sample, line, band is: 91 125 1 + Current sample, line, band is: 92 125 1 + Current sample, line, band is: 93 125 1 + Current sample, line, band is: 94 125 1 + Current sample, line, band is: 95 125 1 + Current sample, line, band is: 96 125 1 + Current sample, line, band is: 97 125 1 + Current sample, line, band is: 98 125 1 + Current sample, line, band is: 99 125 1 + Current sample, line, band is: 100 125 1 + Current sample, line, band is: 101 125 1 + Current sample, line, band is: 102 125 1 + Current sample, line, band is: 103 125 1 + Current sample, line, band is: 104 125 1 + Current sample, line, band is: 105 125 1 + Current sample, line, band is: 106 125 1 + Current sample, line, band is: 107 125 1 + Current sample, line, band is: 108 125 1 + Current sample, line, band is: 109 125 1 + Current sample, line, band is: 110 125 1 + Current sample, line, band is: 111 125 1 + Current sample, line, band is: 112 125 1 + Current sample, line, band is: 113 125 1 + Current sample, line, band is: 114 125 1 + Current sample, line, band is: 115 125 1 + Current sample, line, band is: 116 125 1 + Current sample, line, band is: 117 125 1 + Current sample, line, band is: 118 125 1 + Current sample, line, band is: 119 125 1 + Current sample, line, band is: 120 125 1 + Current sample, line, band is: 121 125 1 + Current sample, line, band is: 122 125 1 + Current sample, line, band is: 123 125 1 + Current sample, line, band is: 124 125 1 + Current sample, line, band is: 125 125 1 + Current sample, line, band is: 126 125 1 + Current sample, line, band is: 1 126 1 + Current sample, line, band is: 2 126 1 + Current sample, line, band is: 3 126 1 + Current sample, line, band is: 4 126 1 + Current sample, line, band is: 5 126 1 + Current sample, line, band is: 6 126 1 + Current sample, line, band is: 7 126 1 + Current sample, line, band is: 8 126 1 + Current sample, line, band is: 9 126 1 + Current sample, line, band is: 10 126 1 + Current sample, line, band is: 11 126 1 + Current sample, line, band is: 12 126 1 + Current sample, line, band is: 13 126 1 + Current sample, line, band is: 14 126 1 + Current sample, line, band is: 15 126 1 + Current sample, line, band is: 16 126 1 + Current sample, line, band is: 17 126 1 + Current sample, line, band is: 18 126 1 + Current sample, line, band is: 19 126 1 + Current sample, line, band is: 20 126 1 + Current sample, line, band is: 21 126 1 + Current sample, line, band is: 22 126 1 + Current sample, line, band is: 23 126 1 + Current sample, line, band is: 24 126 1 + Current sample, line, band is: 25 126 1 + Current sample, line, band is: 26 126 1 + Current sample, line, band is: 27 126 1 + Current sample, line, band is: 28 126 1 + Current sample, line, band is: 29 126 1 + Current sample, line, band is: 30 126 1 + Current sample, line, band is: 31 126 1 + Current sample, line, band is: 32 126 1 + Current sample, line, band is: 33 126 1 + Current sample, line, band is: 34 126 1 + Current sample, line, band is: 35 126 1 + Current sample, line, band is: 36 126 1 + Current sample, line, band is: 37 126 1 + Current sample, line, band is: 38 126 1 + Current sample, line, band is: 39 126 1 + Current sample, line, band is: 40 126 1 + Current sample, line, band is: 41 126 1 + Current sample, line, band is: 42 126 1 + Current sample, line, band is: 43 126 1 + Current sample, line, band is: 44 126 1 + Current sample, line, band is: 45 126 1 + Current sample, line, band is: 46 126 1 + Current sample, line, band is: 47 126 1 + Current sample, line, band is: 48 126 1 + Current sample, line, band is: 49 126 1 + Current sample, line, band is: 50 126 1 + Current sample, line, band is: 51 126 1 + Current sample, line, band is: 52 126 1 + Current sample, line, band is: 53 126 1 + Current sample, line, band is: 54 126 1 + Current sample, line, band is: 55 126 1 + Current sample, line, band is: 56 126 1 + Current sample, line, band is: 57 126 1 + Current sample, line, band is: 58 126 1 + Current sample, line, band is: 59 126 1 + Current sample, line, band is: 60 126 1 + Current sample, line, band is: 61 126 1 + Current sample, line, band is: 62 126 1 + Current sample, line, band is: 63 126 1 + Current sample, line, band is: 64 126 1 + Current sample, line, band is: 65 126 1 + Current sample, line, band is: 66 126 1 + Current sample, line, band is: 67 126 1 + Current sample, line, band is: 68 126 1 + Current sample, line, band is: 69 126 1 + Current sample, line, band is: 70 126 1 + Current sample, line, band is: 71 126 1 + Current sample, line, band is: 72 126 1 + Current sample, line, band is: 73 126 1 + Current sample, line, band is: 74 126 1 + Current sample, line, band is: 75 126 1 + Current sample, line, band is: 76 126 1 + Current sample, line, band is: 77 126 1 + Current sample, line, band is: 78 126 1 + Current sample, line, band is: 79 126 1 + Current sample, line, band is: 80 126 1 + Current sample, line, band is: 81 126 1 + Current sample, line, band is: 82 126 1 + Current sample, line, band is: 83 126 1 + Current sample, line, band is: 84 126 1 + Current sample, line, band is: 85 126 1 + Current sample, line, band is: 86 126 1 + Current sample, line, band is: 87 126 1 + Current sample, line, band is: 88 126 1 + Current sample, line, band is: 89 126 1 + Current sample, line, band is: 90 126 1 + Current sample, line, band is: 91 126 1 + Current sample, line, band is: 92 126 1 + Current sample, line, band is: 93 126 1 + Current sample, line, band is: 94 126 1 + Current sample, line, band is: 95 126 1 + Current sample, line, band is: 96 126 1 + Current sample, line, band is: 97 126 1 + Current sample, line, band is: 98 126 1 + Current sample, line, band is: 99 126 1 + Current sample, line, band is: 100 126 1 + Current sample, line, band is: 101 126 1 + Current sample, line, band is: 102 126 1 + Current sample, line, band is: 103 126 1 + Current sample, line, band is: 104 126 1 + Current sample, line, band is: 105 126 1 + Current sample, line, band is: 106 126 1 + Current sample, line, band is: 107 126 1 + Current sample, line, band is: 108 126 1 + Current sample, line, band is: 109 126 1 + Current sample, line, band is: 110 126 1 + Current sample, line, band is: 111 126 1 + Current sample, line, band is: 112 126 1 + Current sample, line, band is: 113 126 1 + Current sample, line, band is: 114 126 1 + Current sample, line, band is: 115 126 1 + Current sample, line, band is: 116 126 1 + Current sample, line, band is: 117 126 1 + Current sample, line, band is: 118 126 1 + Current sample, line, band is: 119 126 1 + Current sample, line, band is: 120 126 1 + Current sample, line, band is: 121 126 1 + Current sample, line, band is: 122 126 1 + Current sample, line, band is: 123 126 1 + Current sample, line, band is: 124 126 1 + Current sample, line, band is: 125 126 1 + Current sample, line, band is: 126 126 1 + +Buffer Size: 1 1 2 + + Current sample, line, band is: 1 1 1 + Current sample, line, band is: 1 2 1 + Current sample, line, band is: 1 3 1 + Current sample, line, band is: 1 4 1 + Current sample, line, band is: 1 5 1 + Current sample, line, band is: 1 6 1 + Current sample, line, band is: 1 7 1 + Current sample, line, band is: 1 8 1 + Current sample, line, band is: 1 9 1 + Current sample, line, band is: 1 10 1 + Current sample, line, band is: 1 11 1 + Current sample, line, band is: 1 12 1 + Current sample, line, band is: 1 13 1 + Current sample, line, band is: 1 14 1 + Current sample, line, band is: 1 15 1 + Current sample, line, band is: 1 16 1 + Current sample, line, band is: 1 17 1 + Current sample, line, band is: 1 18 1 + Current sample, line, band is: 1 19 1 + Current sample, line, band is: 1 20 1 + Current sample, line, band is: 1 21 1 + Current sample, line, band is: 1 22 1 + Current sample, line, band is: 1 23 1 + Current sample, line, band is: 1 24 1 + Current sample, line, band is: 1 25 1 + Current sample, line, band is: 1 26 1 + Current sample, line, band is: 1 27 1 + Current sample, line, band is: 1 28 1 + Current sample, line, band is: 1 29 1 + Current sample, line, band is: 1 30 1 + Current sample, line, band is: 1 31 1 + Current sample, line, band is: 1 32 1 + Current sample, line, band is: 1 33 1 + Current sample, line, band is: 1 34 1 + Current sample, line, band is: 1 35 1 + Current sample, line, band is: 1 36 1 + Current sample, line, band is: 1 37 1 + Current sample, line, band is: 1 38 1 + Current sample, line, band is: 1 39 1 + Current sample, line, band is: 1 40 1 + Current sample, line, band is: 1 41 1 + Current sample, line, band is: 1 42 1 + Current sample, line, band is: 1 43 1 + Current sample, line, band is: 1 44 1 + Current sample, line, band is: 1 45 1 + Current sample, line, band is: 1 46 1 + Current sample, line, band is: 1 47 1 + Current sample, line, band is: 1 48 1 + Current sample, line, band is: 1 49 1 + Current sample, line, band is: 1 50 1 + Current sample, line, band is: 1 51 1 + Current sample, line, band is: 1 52 1 + Current sample, line, band is: 1 53 1 + Current sample, line, band is: 1 54 1 + Current sample, line, band is: 1 55 1 + Current sample, line, band is: 1 56 1 + Current sample, line, band is: 1 57 1 + Current sample, line, band is: 1 58 1 + Current sample, line, band is: 1 59 1 + Current sample, line, band is: 1 60 1 + Current sample, line, band is: 1 61 1 + Current sample, line, band is: 1 62 1 + Current sample, line, band is: 1 63 1 + Current sample, line, band is: 1 64 1 + Current sample, line, band is: 1 65 1 + Current sample, line, band is: 1 66 1 + Current sample, line, band is: 1 67 1 + Current sample, line, band is: 1 68 1 + Current sample, line, band is: 1 69 1 + Current sample, line, band is: 1 70 1 + Current sample, line, band is: 1 71 1 + Current sample, line, band is: 1 72 1 + Current sample, line, band is: 1 73 1 + Current sample, line, band is: 1 74 1 + Current sample, line, band is: 1 75 1 + Current sample, line, band is: 1 76 1 + Current sample, line, band is: 1 77 1 + Current sample, line, band is: 1 78 1 + Current sample, line, band is: 1 79 1 + Current sample, line, band is: 1 80 1 + Current sample, line, band is: 1 81 1 + Current sample, line, band is: 1 82 1 + Current sample, line, band is: 1 83 1 + Current sample, line, band is: 1 84 1 + Current sample, line, band is: 1 85 1 + Current sample, line, band is: 1 86 1 + Current sample, line, band is: 1 87 1 + Current sample, line, band is: 1 88 1 + Current sample, line, band is: 1 89 1 + Current sample, line, band is: 1 90 1 + Current sample, line, band is: 1 91 1 + Current sample, line, band is: 1 92 1 + Current sample, line, band is: 1 93 1 + Current sample, line, band is: 1 94 1 + Current sample, line, band is: 1 95 1 + Current sample, line, band is: 1 96 1 + Current sample, line, band is: 1 97 1 + Current sample, line, band is: 1 98 1 + Current sample, line, band is: 1 99 1 + Current sample, line, band is: 1 100 1 + Current sample, line, band is: 1 101 1 + Current sample, line, band is: 1 102 1 + Current sample, line, band is: 1 103 1 + Current sample, line, band is: 1 104 1 + Current sample, line, band is: 1 105 1 + Current sample, line, band is: 1 106 1 + Current sample, line, band is: 1 107 1 + Current sample, line, band is: 1 108 1 + Current sample, line, band is: 1 109 1 + Current sample, line, band is: 1 110 1 + Current sample, line, band is: 1 111 1 + Current sample, line, band is: 1 112 1 + Current sample, line, band is: 1 113 1 + Current sample, line, band is: 1 114 1 + Current sample, line, band is: 1 115 1 + Current sample, line, band is: 1 116 1 + Current sample, line, band is: 1 117 1 + Current sample, line, band is: 1 118 1 + Current sample, line, band is: 1 119 1 + Current sample, line, band is: 1 120 1 + Current sample, line, band is: 1 121 1 + Current sample, line, band is: 1 122 1 + Current sample, line, band is: 1 123 1 + Current sample, line, band is: 1 124 1 + Current sample, line, band is: 1 125 1 + Current sample, line, band is: 1 126 1 + Current sample, line, band is: 2 1 1 + Current sample, line, band is: 2 2 1 + Current sample, line, band is: 2 3 1 + Current sample, line, band is: 2 4 1 + Current sample, line, band is: 2 5 1 + Current sample, line, band is: 2 6 1 + Current sample, line, band is: 2 7 1 + Current sample, line, band is: 2 8 1 + Current sample, line, band is: 2 9 1 + Current sample, line, band is: 2 10 1 + Current sample, line, band is: 2 11 1 + Current sample, line, band is: 2 12 1 + Current sample, line, band is: 2 13 1 + Current sample, line, band is: 2 14 1 + Current sample, line, band is: 2 15 1 + Current sample, line, band is: 2 16 1 + Current sample, line, band is: 2 17 1 + Current sample, line, band is: 2 18 1 + Current sample, line, band is: 2 19 1 + Current sample, line, band is: 2 20 1 + Current sample, line, band is: 2 21 1 + Current sample, line, band is: 2 22 1 + Current sample, line, band is: 2 23 1 + Current sample, line, band is: 2 24 1 + Current sample, line, band is: 2 25 1 + Current sample, line, band is: 2 26 1 + Current sample, line, band is: 2 27 1 + Current sample, line, band is: 2 28 1 + Current sample, line, band is: 2 29 1 + Current sample, line, band is: 2 30 1 + Current sample, line, band is: 2 31 1 + Current sample, line, band is: 2 32 1 + Current sample, line, band is: 2 33 1 + Current sample, line, band is: 2 34 1 + Current sample, line, band is: 2 35 1 + Current sample, line, band is: 2 36 1 + Current sample, line, band is: 2 37 1 + Current sample, line, band is: 2 38 1 + Current sample, line, band is: 2 39 1 + Current sample, line, band is: 2 40 1 + Current sample, line, band is: 2 41 1 + Current sample, line, band is: 2 42 1 + Current sample, line, band is: 2 43 1 + Current sample, line, band is: 2 44 1 + Current sample, line, band is: 2 45 1 + Current sample, line, band is: 2 46 1 + Current sample, line, band is: 2 47 1 + Current sample, line, band is: 2 48 1 + Current sample, line, band is: 2 49 1 + Current sample, line, band is: 2 50 1 + Current sample, line, band is: 2 51 1 + Current sample, line, band is: 2 52 1 + Current sample, line, band is: 2 53 1 + Current sample, line, band is: 2 54 1 + Current sample, line, band is: 2 55 1 + Current sample, line, band is: 2 56 1 + Current sample, line, band is: 2 57 1 + Current sample, line, band is: 2 58 1 + Current sample, line, band is: 2 59 1 + Current sample, line, band is: 2 60 1 + Current sample, line, band is: 2 61 1 + Current sample, line, band is: 2 62 1 + Current sample, line, band is: 2 63 1 + Current sample, line, band is: 2 64 1 + Current sample, line, band is: 2 65 1 + Current sample, line, band is: 2 66 1 + Current sample, line, band is: 2 67 1 + Current sample, line, band is: 2 68 1 + Current sample, line, band is: 2 69 1 + Current sample, line, band is: 2 70 1 + Current sample, line, band is: 2 71 1 + Current sample, line, band is: 2 72 1 + Current sample, line, band is: 2 73 1 + Current sample, line, band is: 2 74 1 + Current sample, line, band is: 2 75 1 + Current sample, line, band is: 2 76 1 + Current sample, line, band is: 2 77 1 + Current sample, line, band is: 2 78 1 + Current sample, line, band is: 2 79 1 + Current sample, line, band is: 2 80 1 + Current sample, line, band is: 2 81 1 + Current sample, line, band is: 2 82 1 + Current sample, line, band is: 2 83 1 + Current sample, line, band is: 2 84 1 + Current sample, line, band is: 2 85 1 + Current sample, line, band is: 2 86 1 + Current sample, line, band is: 2 87 1 + Current sample, line, band is: 2 88 1 + Current sample, line, band is: 2 89 1 + Current sample, line, band is: 2 90 1 + Current sample, line, band is: 2 91 1 + Current sample, line, band is: 2 92 1 + Current sample, line, band is: 2 93 1 + Current sample, line, band is: 2 94 1 + Current sample, line, band is: 2 95 1 + Current sample, line, band is: 2 96 1 + Current sample, line, band is: 2 97 1 + Current sample, line, band is: 2 98 1 + Current sample, line, band is: 2 99 1 + Current sample, line, band is: 2 100 1 + Current sample, line, band is: 2 101 1 + Current sample, line, band is: 2 102 1 + Current sample, line, band is: 2 103 1 + Current sample, line, band is: 2 104 1 + Current sample, line, band is: 2 105 1 + Current sample, line, band is: 2 106 1 + Current sample, line, band is: 2 107 1 + Current sample, line, band is: 2 108 1 + Current sample, line, band is: 2 109 1 + Current sample, line, band is: 2 110 1 + Current sample, line, band is: 2 111 1 + Current sample, line, band is: 2 112 1 + Current sample, line, band is: 2 113 1 + Current sample, line, band is: 2 114 1 + Current sample, line, band is: 2 115 1 + Current sample, line, band is: 2 116 1 + Current sample, line, band is: 2 117 1 + Current sample, line, band is: 2 118 1 + Current sample, line, band is: 2 119 1 + Current sample, line, band is: 2 120 1 + Current sample, line, band is: 2 121 1 + Current sample, line, band is: 2 122 1 + Current sample, line, band is: 2 123 1 + Current sample, line, band is: 2 124 1 + Current sample, line, band is: 2 125 1 + Current sample, line, band is: 2 126 1 + Current sample, line, band is: 3 1 1 + Current sample, line, band is: 3 2 1 + Current sample, line, band is: 3 3 1 + Current sample, line, band is: 3 4 1 + Current sample, line, band is: 3 5 1 + Current sample, line, band is: 3 6 1 + Current sample, line, band is: 3 7 1 + Current sample, line, band is: 3 8 1 + Current sample, line, band is: 3 9 1 + Current sample, line, band is: 3 10 1 + Current sample, line, band is: 3 11 1 + Current sample, line, band is: 3 12 1 + Current sample, line, band is: 3 13 1 + Current sample, line, band is: 3 14 1 + Current sample, line, band is: 3 15 1 + Current sample, line, band is: 3 16 1 + Current sample, line, band is: 3 17 1 + Current sample, line, band is: 3 18 1 + Current sample, line, band is: 3 19 1 + Current sample, line, band is: 3 20 1 + Current sample, line, band is: 3 21 1 + Current sample, line, band is: 3 22 1 + Current sample, line, band is: 3 23 1 + Current sample, line, band is: 3 24 1 + Current sample, line, band is: 3 25 1 + Current sample, line, band is: 3 26 1 + Current sample, line, band is: 3 27 1 + Current sample, line, band is: 3 28 1 + Current sample, line, band is: 3 29 1 + Current sample, line, band is: 3 30 1 + Current sample, line, band is: 3 31 1 + Current sample, line, band is: 3 32 1 + Current sample, line, band is: 3 33 1 + Current sample, line, band is: 3 34 1 + Current sample, line, band is: 3 35 1 + Current sample, line, band is: 3 36 1 + Current sample, line, band is: 3 37 1 + Current sample, line, band is: 3 38 1 + Current sample, line, band is: 3 39 1 + Current sample, line, band is: 3 40 1 + Current sample, line, band is: 3 41 1 + Current sample, line, band is: 3 42 1 + Current sample, line, band is: 3 43 1 + Current sample, line, band is: 3 44 1 + Current sample, line, band is: 3 45 1 + Current sample, line, band is: 3 46 1 + Current sample, line, band is: 3 47 1 + Current sample, line, band is: 3 48 1 + Current sample, line, band is: 3 49 1 + Current sample, line, band is: 3 50 1 + Current sample, line, band is: 3 51 1 + Current sample, line, band is: 3 52 1 + Current sample, line, band is: 3 53 1 + Current sample, line, band is: 3 54 1 + Current sample, line, band is: 3 55 1 + Current sample, line, band is: 3 56 1 + Current sample, line, band is: 3 57 1 + Current sample, line, band is: 3 58 1 + Current sample, line, band is: 3 59 1 + Current sample, line, band is: 3 60 1 + Current sample, line, band is: 3 61 1 + Current sample, line, band is: 3 62 1 + Current sample, line, band is: 3 63 1 + Current sample, line, band is: 3 64 1 + Current sample, line, band is: 3 65 1 + Current sample, line, band is: 3 66 1 + Current sample, line, band is: 3 67 1 + Current sample, line, band is: 3 68 1 + Current sample, line, band is: 3 69 1 + Current sample, line, band is: 3 70 1 + Current sample, line, band is: 3 71 1 + Current sample, line, band is: 3 72 1 + Current sample, line, band is: 3 73 1 + Current sample, line, band is: 3 74 1 + Current sample, line, band is: 3 75 1 + Current sample, line, band is: 3 76 1 + Current sample, line, band is: 3 77 1 + Current sample, line, band is: 3 78 1 + Current sample, line, band is: 3 79 1 + Current sample, line, band is: 3 80 1 + Current sample, line, band is: 3 81 1 + Current sample, line, band is: 3 82 1 + Current sample, line, band is: 3 83 1 + Current sample, line, band is: 3 84 1 + Current sample, line, band is: 3 85 1 + Current sample, line, band is: 3 86 1 + Current sample, line, band is: 3 87 1 + Current sample, line, band is: 3 88 1 + Current sample, line, band is: 3 89 1 + Current sample, line, band is: 3 90 1 + Current sample, line, band is: 3 91 1 + Current sample, line, band is: 3 92 1 + Current sample, line, band is: 3 93 1 + Current sample, line, band is: 3 94 1 + Current sample, line, band is: 3 95 1 + Current sample, line, band is: 3 96 1 + Current sample, line, band is: 3 97 1 + Current sample, line, band is: 3 98 1 + Current sample, line, band is: 3 99 1 + Current sample, line, band is: 3 100 1 + Current sample, line, band is: 3 101 1 + Current sample, line, band is: 3 102 1 + Current sample, line, band is: 3 103 1 + Current sample, line, band is: 3 104 1 + Current sample, line, band is: 3 105 1 + Current sample, line, band is: 3 106 1 + Current sample, line, band is: 3 107 1 + Current sample, line, band is: 3 108 1 + Current sample, line, band is: 3 109 1 + Current sample, line, band is: 3 110 1 + Current sample, line, band is: 3 111 1 + Current sample, line, band is: 3 112 1 + Current sample, line, band is: 3 113 1 + Current sample, line, band is: 3 114 1 + Current sample, line, band is: 3 115 1 + Current sample, line, band is: 3 116 1 + Current sample, line, band is: 3 117 1 + Current sample, line, band is: 3 118 1 + Current sample, line, band is: 3 119 1 + Current sample, line, band is: 3 120 1 + Current sample, line, band is: 3 121 1 + Current sample, line, band is: 3 122 1 + Current sample, line, band is: 3 123 1 + Current sample, line, band is: 3 124 1 + Current sample, line, band is: 3 125 1 + Current sample, line, band is: 3 126 1 + Current sample, line, band is: 4 1 1 + Current sample, line, band is: 4 2 1 + Current sample, line, band is: 4 3 1 + Current sample, line, band is: 4 4 1 + Current sample, line, band is: 4 5 1 + Current sample, line, band is: 4 6 1 + Current sample, line, band is: 4 7 1 + Current sample, line, band is: 4 8 1 + Current sample, line, band is: 4 9 1 + Current sample, line, band is: 4 10 1 + Current sample, line, band is: 4 11 1 + Current sample, line, band is: 4 12 1 + Current sample, line, band is: 4 13 1 + Current sample, line, band is: 4 14 1 + Current sample, line, band is: 4 15 1 + Current sample, line, band is: 4 16 1 + Current sample, line, band is: 4 17 1 + Current sample, line, band is: 4 18 1 + Current sample, line, band is: 4 19 1 + Current sample, line, band is: 4 20 1 + Current sample, line, band is: 4 21 1 + Current sample, line, band is: 4 22 1 + Current sample, line, band is: 4 23 1 + Current sample, line, band is: 4 24 1 + Current sample, line, band is: 4 25 1 + Current sample, line, band is: 4 26 1 + Current sample, line, band is: 4 27 1 + Current sample, line, band is: 4 28 1 + Current sample, line, band is: 4 29 1 + Current sample, line, band is: 4 30 1 + Current sample, line, band is: 4 31 1 + Current sample, line, band is: 4 32 1 + Current sample, line, band is: 4 33 1 + Current sample, line, band is: 4 34 1 + Current sample, line, band is: 4 35 1 + Current sample, line, band is: 4 36 1 + Current sample, line, band is: 4 37 1 + Current sample, line, band is: 4 38 1 + Current sample, line, band is: 4 39 1 + Current sample, line, band is: 4 40 1 + Current sample, line, band is: 4 41 1 + Current sample, line, band is: 4 42 1 + Current sample, line, band is: 4 43 1 + Current sample, line, band is: 4 44 1 + Current sample, line, band is: 4 45 1 + Current sample, line, band is: 4 46 1 + Current sample, line, band is: 4 47 1 + Current sample, line, band is: 4 48 1 + Current sample, line, band is: 4 49 1 + Current sample, line, band is: 4 50 1 + Current sample, line, band is: 4 51 1 + Current sample, line, band is: 4 52 1 + Current sample, line, band is: 4 53 1 + Current sample, line, band is: 4 54 1 + Current sample, line, band is: 4 55 1 + Current sample, line, band is: 4 56 1 + Current sample, line, band is: 4 57 1 + Current sample, line, band is: 4 58 1 + Current sample, line, band is: 4 59 1 + Current sample, line, band is: 4 60 1 + Current sample, line, band is: 4 61 1 + Current sample, line, band is: 4 62 1 + Current sample, line, band is: 4 63 1 + Current sample, line, band is: 4 64 1 + Current sample, line, band is: 4 65 1 + Current sample, line, band is: 4 66 1 + Current sample, line, band is: 4 67 1 + Current sample, line, band is: 4 68 1 + Current sample, line, band is: 4 69 1 + Current sample, line, band is: 4 70 1 + Current sample, line, band is: 4 71 1 + Current sample, line, band is: 4 72 1 + Current sample, line, band is: 4 73 1 + Current sample, line, band is: 4 74 1 + Current sample, line, band is: 4 75 1 + Current sample, line, band is: 4 76 1 + Current sample, line, band is: 4 77 1 + Current sample, line, band is: 4 78 1 + Current sample, line, band is: 4 79 1 + Current sample, line, band is: 4 80 1 + Current sample, line, band is: 4 81 1 + Current sample, line, band is: 4 82 1 + Current sample, line, band is: 4 83 1 + Current sample, line, band is: 4 84 1 + Current sample, line, band is: 4 85 1 + Current sample, line, band is: 4 86 1 + Current sample, line, band is: 4 87 1 + Current sample, line, band is: 4 88 1 + Current sample, line, band is: 4 89 1 + Current sample, line, band is: 4 90 1 + Current sample, line, band is: 4 91 1 + Current sample, line, band is: 4 92 1 + Current sample, line, band is: 4 93 1 + Current sample, line, band is: 4 94 1 + Current sample, line, band is: 4 95 1 + Current sample, line, band is: 4 96 1 + Current sample, line, band is: 4 97 1 + Current sample, line, band is: 4 98 1 + Current sample, line, band is: 4 99 1 + Current sample, line, band is: 4 100 1 + Current sample, line, band is: 4 101 1 + Current sample, line, band is: 4 102 1 + Current sample, line, band is: 4 103 1 + Current sample, line, band is: 4 104 1 + Current sample, line, band is: 4 105 1 + Current sample, line, band is: 4 106 1 + Current sample, line, band is: 4 107 1 + Current sample, line, band is: 4 108 1 + Current sample, line, band is: 4 109 1 + Current sample, line, band is: 4 110 1 + Current sample, line, band is: 4 111 1 + Current sample, line, band is: 4 112 1 + Current sample, line, band is: 4 113 1 + Current sample, line, band is: 4 114 1 + Current sample, line, band is: 4 115 1 + Current sample, line, band is: 4 116 1 + Current sample, line, band is: 4 117 1 + Current sample, line, band is: 4 118 1 + Current sample, line, band is: 4 119 1 + Current sample, line, band is: 4 120 1 + Current sample, line, band is: 4 121 1 + Current sample, line, band is: 4 122 1 + Current sample, line, band is: 4 123 1 + Current sample, line, band is: 4 124 1 + Current sample, line, band is: 4 125 1 + Current sample, line, band is: 4 126 1 + Current sample, line, band is: 5 1 1 + Current sample, line, band is: 5 2 1 + Current sample, line, band is: 5 3 1 + Current sample, line, band is: 5 4 1 + Current sample, line, band is: 5 5 1 + Current sample, line, band is: 5 6 1 + Current sample, line, band is: 5 7 1 + Current sample, line, band is: 5 8 1 + Current sample, line, band is: 5 9 1 + Current sample, line, band is: 5 10 1 + Current sample, line, band is: 5 11 1 + Current sample, line, band is: 5 12 1 + Current sample, line, band is: 5 13 1 + Current sample, line, band is: 5 14 1 + Current sample, line, band is: 5 15 1 + Current sample, line, band is: 5 16 1 + Current sample, line, band is: 5 17 1 + Current sample, line, band is: 5 18 1 + Current sample, line, band is: 5 19 1 + Current sample, line, band is: 5 20 1 + Current sample, line, band is: 5 21 1 + Current sample, line, band is: 5 22 1 + Current sample, line, band is: 5 23 1 + Current sample, line, band is: 5 24 1 + Current sample, line, band is: 5 25 1 + Current sample, line, band is: 5 26 1 + Current sample, line, band is: 5 27 1 + Current sample, line, band is: 5 28 1 + Current sample, line, band is: 5 29 1 + Current sample, line, band is: 5 30 1 + Current sample, line, band is: 5 31 1 + Current sample, line, band is: 5 32 1 + Current sample, line, band is: 5 33 1 + Current sample, line, band is: 5 34 1 + Current sample, line, band is: 5 35 1 + Current sample, line, band is: 5 36 1 + Current sample, line, band is: 5 37 1 + Current sample, line, band is: 5 38 1 + Current sample, line, band is: 5 39 1 + Current sample, line, band is: 5 40 1 + Current sample, line, band is: 5 41 1 + Current sample, line, band is: 5 42 1 + Current sample, line, band is: 5 43 1 + Current sample, line, band is: 5 44 1 + Current sample, line, band is: 5 45 1 + Current sample, line, band is: 5 46 1 + Current sample, line, band is: 5 47 1 + Current sample, line, band is: 5 48 1 + Current sample, line, band is: 5 49 1 + Current sample, line, band is: 5 50 1 + Current sample, line, band is: 5 51 1 + Current sample, line, band is: 5 52 1 + Current sample, line, band is: 5 53 1 + Current sample, line, band is: 5 54 1 + Current sample, line, band is: 5 55 1 + Current sample, line, band is: 5 56 1 + Current sample, line, band is: 5 57 1 + Current sample, line, band is: 5 58 1 + Current sample, line, band is: 5 59 1 + Current sample, line, band is: 5 60 1 + Current sample, line, band is: 5 61 1 + Current sample, line, band is: 5 62 1 + Current sample, line, band is: 5 63 1 + Current sample, line, band is: 5 64 1 + Current sample, line, band is: 5 65 1 + Current sample, line, band is: 5 66 1 + Current sample, line, band is: 5 67 1 + Current sample, line, band is: 5 68 1 + Current sample, line, band is: 5 69 1 + Current sample, line, band is: 5 70 1 + Current sample, line, band is: 5 71 1 + Current sample, line, band is: 5 72 1 + Current sample, line, band is: 5 73 1 + Current sample, line, band is: 5 74 1 + Current sample, line, band is: 5 75 1 + Current sample, line, band is: 5 76 1 + Current sample, line, band is: 5 77 1 + Current sample, line, band is: 5 78 1 + Current sample, line, band is: 5 79 1 + Current sample, line, band is: 5 80 1 + Current sample, line, band is: 5 81 1 + Current sample, line, band is: 5 82 1 + Current sample, line, band is: 5 83 1 + Current sample, line, band is: 5 84 1 + Current sample, line, band is: 5 85 1 + Current sample, line, band is: 5 86 1 + Current sample, line, band is: 5 87 1 + Current sample, line, band is: 5 88 1 + Current sample, line, band is: 5 89 1 + Current sample, line, band is: 5 90 1 + Current sample, line, band is: 5 91 1 + Current sample, line, band is: 5 92 1 + Current sample, line, band is: 5 93 1 + Current sample, line, band is: 5 94 1 + Current sample, line, band is: 5 95 1 + Current sample, line, band is: 5 96 1 + Current sample, line, band is: 5 97 1 + Current sample, line, band is: 5 98 1 + Current sample, line, band is: 5 99 1 + Current sample, line, band is: 5 100 1 + Current sample, line, band is: 5 101 1 + Current sample, line, band is: 5 102 1 + Current sample, line, band is: 5 103 1 + Current sample, line, band is: 5 104 1 + Current sample, line, band is: 5 105 1 + Current sample, line, band is: 5 106 1 + Current sample, line, band is: 5 107 1 + Current sample, line, band is: 5 108 1 + Current sample, line, band is: 5 109 1 + Current sample, line, band is: 5 110 1 + Current sample, line, band is: 5 111 1 + Current sample, line, band is: 5 112 1 + Current sample, line, band is: 5 113 1 + Current sample, line, band is: 5 114 1 + Current sample, line, band is: 5 115 1 + Current sample, line, band is: 5 116 1 + Current sample, line, band is: 5 117 1 + Current sample, line, band is: 5 118 1 + Current sample, line, band is: 5 119 1 + Current sample, line, band is: 5 120 1 + Current sample, line, band is: 5 121 1 + Current sample, line, band is: 5 122 1 + Current sample, line, band is: 5 123 1 + Current sample, line, band is: 5 124 1 + Current sample, line, band is: 5 125 1 + Current sample, line, band is: 5 126 1 + Current sample, line, band is: 6 1 1 + Current sample, line, band is: 6 2 1 + Current sample, line, band is: 6 3 1 + Current sample, line, band is: 6 4 1 + Current sample, line, band is: 6 5 1 + Current sample, line, band is: 6 6 1 + Current sample, line, band is: 6 7 1 + Current sample, line, band is: 6 8 1 + Current sample, line, band is: 6 9 1 + Current sample, line, band is: 6 10 1 + Current sample, line, band is: 6 11 1 + Current sample, line, band is: 6 12 1 + Current sample, line, band is: 6 13 1 + Current sample, line, band is: 6 14 1 + Current sample, line, band is: 6 15 1 + Current sample, line, band is: 6 16 1 + Current sample, line, band is: 6 17 1 + Current sample, line, band is: 6 18 1 + Current sample, line, band is: 6 19 1 + Current sample, line, band is: 6 20 1 + Current sample, line, band is: 6 21 1 + Current sample, line, band is: 6 22 1 + Current sample, line, band is: 6 23 1 + Current sample, line, band is: 6 24 1 + Current sample, line, band is: 6 25 1 + Current sample, line, band is: 6 26 1 + Current sample, line, band is: 6 27 1 + Current sample, line, band is: 6 28 1 + Current sample, line, band is: 6 29 1 + Current sample, line, band is: 6 30 1 + Current sample, line, band is: 6 31 1 + Current sample, line, band is: 6 32 1 + Current sample, line, band is: 6 33 1 + Current sample, line, band is: 6 34 1 + Current sample, line, band is: 6 35 1 + Current sample, line, band is: 6 36 1 + Current sample, line, band is: 6 37 1 + Current sample, line, band is: 6 38 1 + Current sample, line, band is: 6 39 1 + Current sample, line, band is: 6 40 1 + Current sample, line, band is: 6 41 1 + Current sample, line, band is: 6 42 1 + Current sample, line, band is: 6 43 1 + Current sample, line, band is: 6 44 1 + Current sample, line, band is: 6 45 1 + Current sample, line, band is: 6 46 1 + Current sample, line, band is: 6 47 1 + Current sample, line, band is: 6 48 1 + Current sample, line, band is: 6 49 1 + Current sample, line, band is: 6 50 1 + Current sample, line, band is: 6 51 1 + Current sample, line, band is: 6 52 1 + Current sample, line, band is: 6 53 1 + Current sample, line, band is: 6 54 1 + Current sample, line, band is: 6 55 1 + Current sample, line, band is: 6 56 1 + Current sample, line, band is: 6 57 1 + Current sample, line, band is: 6 58 1 + Current sample, line, band is: 6 59 1 + Current sample, line, band is: 6 60 1 + Current sample, line, band is: 6 61 1 + Current sample, line, band is: 6 62 1 + Current sample, line, band is: 6 63 1 + Current sample, line, band is: 6 64 1 + Current sample, line, band is: 6 65 1 + Current sample, line, band is: 6 66 1 + Current sample, line, band is: 6 67 1 + Current sample, line, band is: 6 68 1 + Current sample, line, band is: 6 69 1 + Current sample, line, band is: 6 70 1 + Current sample, line, band is: 6 71 1 + Current sample, line, band is: 6 72 1 + Current sample, line, band is: 6 73 1 + Current sample, line, band is: 6 74 1 + Current sample, line, band is: 6 75 1 + Current sample, line, band is: 6 76 1 + Current sample, line, band is: 6 77 1 + Current sample, line, band is: 6 78 1 + Current sample, line, band is: 6 79 1 + Current sample, line, band is: 6 80 1 + Current sample, line, band is: 6 81 1 + Current sample, line, band is: 6 82 1 + Current sample, line, band is: 6 83 1 + Current sample, line, band is: 6 84 1 + Current sample, line, band is: 6 85 1 + Current sample, line, band is: 6 86 1 + Current sample, line, band is: 6 87 1 + Current sample, line, band is: 6 88 1 + Current sample, line, band is: 6 89 1 + Current sample, line, band is: 6 90 1 + Current sample, line, band is: 6 91 1 + Current sample, line, band is: 6 92 1 + Current sample, line, band is: 6 93 1 + Current sample, line, band is: 6 94 1 + Current sample, line, band is: 6 95 1 + Current sample, line, band is: 6 96 1 + Current sample, line, band is: 6 97 1 + Current sample, line, band is: 6 98 1 + Current sample, line, band is: 6 99 1 + Current sample, line, band is: 6 100 1 + Current sample, line, band is: 6 101 1 + Current sample, line, band is: 6 102 1 + Current sample, line, band is: 6 103 1 + Current sample, line, band is: 6 104 1 + Current sample, line, band is: 6 105 1 + Current sample, line, band is: 6 106 1 + Current sample, line, band is: 6 107 1 + Current sample, line, band is: 6 108 1 + Current sample, line, band is: 6 109 1 + Current sample, line, band is: 6 110 1 + Current sample, line, band is: 6 111 1 + Current sample, line, band is: 6 112 1 + Current sample, line, band is: 6 113 1 + Current sample, line, band is: 6 114 1 + Current sample, line, band is: 6 115 1 + Current sample, line, band is: 6 116 1 + Current sample, line, band is: 6 117 1 + Current sample, line, band is: 6 118 1 + Current sample, line, band is: 6 119 1 + Current sample, line, band is: 6 120 1 + Current sample, line, band is: 6 121 1 + Current sample, line, band is: 6 122 1 + Current sample, line, band is: 6 123 1 + Current sample, line, band is: 6 124 1 + Current sample, line, band is: 6 125 1 + Current sample, line, band is: 6 126 1 + Current sample, line, band is: 7 1 1 + Current sample, line, band is: 7 2 1 + Current sample, line, band is: 7 3 1 + Current sample, line, band is: 7 4 1 + Current sample, line, band is: 7 5 1 + Current sample, line, band is: 7 6 1 + Current sample, line, band is: 7 7 1 + Current sample, line, band is: 7 8 1 + Current sample, line, band is: 7 9 1 + Current sample, line, band is: 7 10 1 + Current sample, line, band is: 7 11 1 + Current sample, line, band is: 7 12 1 + Current sample, line, band is: 7 13 1 + Current sample, line, band is: 7 14 1 + Current sample, line, band is: 7 15 1 + Current sample, line, band is: 7 16 1 + Current sample, line, band is: 7 17 1 + Current sample, line, band is: 7 18 1 + Current sample, line, band is: 7 19 1 + Current sample, line, band is: 7 20 1 + Current sample, line, band is: 7 21 1 + Current sample, line, band is: 7 22 1 + Current sample, line, band is: 7 23 1 + Current sample, line, band is: 7 24 1 + Current sample, line, band is: 7 25 1 + Current sample, line, band is: 7 26 1 + Current sample, line, band is: 7 27 1 + Current sample, line, band is: 7 28 1 + Current sample, line, band is: 7 29 1 + Current sample, line, band is: 7 30 1 + Current sample, line, band is: 7 31 1 + Current sample, line, band is: 7 32 1 + Current sample, line, band is: 7 33 1 + Current sample, line, band is: 7 34 1 + Current sample, line, band is: 7 35 1 + Current sample, line, band is: 7 36 1 + Current sample, line, band is: 7 37 1 + Current sample, line, band is: 7 38 1 + Current sample, line, band is: 7 39 1 + Current sample, line, band is: 7 40 1 + Current sample, line, band is: 7 41 1 + Current sample, line, band is: 7 42 1 + Current sample, line, band is: 7 43 1 + Current sample, line, band is: 7 44 1 + Current sample, line, band is: 7 45 1 + Current sample, line, band is: 7 46 1 + Current sample, line, band is: 7 47 1 + Current sample, line, band is: 7 48 1 + Current sample, line, band is: 7 49 1 + Current sample, line, band is: 7 50 1 + Current sample, line, band is: 7 51 1 + Current sample, line, band is: 7 52 1 + Current sample, line, band is: 7 53 1 + Current sample, line, band is: 7 54 1 + Current sample, line, band is: 7 55 1 + Current sample, line, band is: 7 56 1 + Current sample, line, band is: 7 57 1 + Current sample, line, band is: 7 58 1 + Current sample, line, band is: 7 59 1 + Current sample, line, band is: 7 60 1 + Current sample, line, band is: 7 61 1 + Current sample, line, band is: 7 62 1 + Current sample, line, band is: 7 63 1 + Current sample, line, band is: 7 64 1 + Current sample, line, band is: 7 65 1 + Current sample, line, band is: 7 66 1 + Current sample, line, band is: 7 67 1 + Current sample, line, band is: 7 68 1 + Current sample, line, band is: 7 69 1 + Current sample, line, band is: 7 70 1 + Current sample, line, band is: 7 71 1 + Current sample, line, band is: 7 72 1 + Current sample, line, band is: 7 73 1 + Current sample, line, band is: 7 74 1 + Current sample, line, band is: 7 75 1 + Current sample, line, band is: 7 76 1 + Current sample, line, band is: 7 77 1 + Current sample, line, band is: 7 78 1 + Current sample, line, band is: 7 79 1 + Current sample, line, band is: 7 80 1 + Current sample, line, band is: 7 81 1 + Current sample, line, band is: 7 82 1 + Current sample, line, band is: 7 83 1 + Current sample, line, band is: 7 84 1 + Current sample, line, band is: 7 85 1 + Current sample, line, band is: 7 86 1 + Current sample, line, band is: 7 87 1 + Current sample, line, band is: 7 88 1 + Current sample, line, band is: 7 89 1 + Current sample, line, band is: 7 90 1 + Current sample, line, band is: 7 91 1 + Current sample, line, band is: 7 92 1 + Current sample, line, band is: 7 93 1 + Current sample, line, band is: 7 94 1 + Current sample, line, band is: 7 95 1 + Current sample, line, band is: 7 96 1 + Current sample, line, band is: 7 97 1 + Current sample, line, band is: 7 98 1 + Current sample, line, band is: 7 99 1 + Current sample, line, band is: 7 100 1 + Current sample, line, band is: 7 101 1 + Current sample, line, band is: 7 102 1 + Current sample, line, band is: 7 103 1 + Current sample, line, band is: 7 104 1 + Current sample, line, band is: 7 105 1 + Current sample, line, band is: 7 106 1 + Current sample, line, band is: 7 107 1 + Current sample, line, band is: 7 108 1 + Current sample, line, band is: 7 109 1 + Current sample, line, band is: 7 110 1 + Current sample, line, band is: 7 111 1 + Current sample, line, band is: 7 112 1 + Current sample, line, band is: 7 113 1 + Current sample, line, band is: 7 114 1 + Current sample, line, band is: 7 115 1 + Current sample, line, band is: 7 116 1 + Current sample, line, band is: 7 117 1 + Current sample, line, band is: 7 118 1 + Current sample, line, band is: 7 119 1 + Current sample, line, band is: 7 120 1 + Current sample, line, band is: 7 121 1 + Current sample, line, band is: 7 122 1 + Current sample, line, band is: 7 123 1 + Current sample, line, band is: 7 124 1 + Current sample, line, band is: 7 125 1 + Current sample, line, band is: 7 126 1 + Current sample, line, band is: 8 1 1 + Current sample, line, band is: 8 2 1 + Current sample, line, band is: 8 3 1 + Current sample, line, band is: 8 4 1 + Current sample, line, band is: 8 5 1 + Current sample, line, band is: 8 6 1 + Current sample, line, band is: 8 7 1 + Current sample, line, band is: 8 8 1 + Current sample, line, band is: 8 9 1 + Current sample, line, band is: 8 10 1 + Current sample, line, band is: 8 11 1 + Current sample, line, band is: 8 12 1 + Current sample, line, band is: 8 13 1 + Current sample, line, band is: 8 14 1 + Current sample, line, band is: 8 15 1 + Current sample, line, band is: 8 16 1 + Current sample, line, band is: 8 17 1 + Current sample, line, band is: 8 18 1 + Current sample, line, band is: 8 19 1 + Current sample, line, band is: 8 20 1 + Current sample, line, band is: 8 21 1 + Current sample, line, band is: 8 22 1 + Current sample, line, band is: 8 23 1 + Current sample, line, band is: 8 24 1 + Current sample, line, band is: 8 25 1 + Current sample, line, band is: 8 26 1 + Current sample, line, band is: 8 27 1 + Current sample, line, band is: 8 28 1 + Current sample, line, band is: 8 29 1 + Current sample, line, band is: 8 30 1 + Current sample, line, band is: 8 31 1 + Current sample, line, band is: 8 32 1 + Current sample, line, band is: 8 33 1 + Current sample, line, band is: 8 34 1 + Current sample, line, band is: 8 35 1 + Current sample, line, band is: 8 36 1 + Current sample, line, band is: 8 37 1 + Current sample, line, band is: 8 38 1 + Current sample, line, band is: 8 39 1 + Current sample, line, band is: 8 40 1 + Current sample, line, band is: 8 41 1 + Current sample, line, band is: 8 42 1 + Current sample, line, band is: 8 43 1 + Current sample, line, band is: 8 44 1 + Current sample, line, band is: 8 45 1 + Current sample, line, band is: 8 46 1 + Current sample, line, band is: 8 47 1 + Current sample, line, band is: 8 48 1 + Current sample, line, band is: 8 49 1 + Current sample, line, band is: 8 50 1 + Current sample, line, band is: 8 51 1 + Current sample, line, band is: 8 52 1 + Current sample, line, band is: 8 53 1 + Current sample, line, band is: 8 54 1 + Current sample, line, band is: 8 55 1 + Current sample, line, band is: 8 56 1 + Current sample, line, band is: 8 57 1 + Current sample, line, band is: 8 58 1 + Current sample, line, band is: 8 59 1 + Current sample, line, band is: 8 60 1 + Current sample, line, band is: 8 61 1 + Current sample, line, band is: 8 62 1 + Current sample, line, band is: 8 63 1 + Current sample, line, band is: 8 64 1 + Current sample, line, band is: 8 65 1 + Current sample, line, band is: 8 66 1 + Current sample, line, band is: 8 67 1 + Current sample, line, band is: 8 68 1 + Current sample, line, band is: 8 69 1 + Current sample, line, band is: 8 70 1 + Current sample, line, band is: 8 71 1 + Current sample, line, band is: 8 72 1 + Current sample, line, band is: 8 73 1 + Current sample, line, band is: 8 74 1 + Current sample, line, band is: 8 75 1 + Current sample, line, band is: 8 76 1 + Current sample, line, band is: 8 77 1 + Current sample, line, band is: 8 78 1 + Current sample, line, band is: 8 79 1 + Current sample, line, band is: 8 80 1 + Current sample, line, band is: 8 81 1 + Current sample, line, band is: 8 82 1 + Current sample, line, band is: 8 83 1 + Current sample, line, band is: 8 84 1 + Current sample, line, band is: 8 85 1 + Current sample, line, band is: 8 86 1 + Current sample, line, band is: 8 87 1 + Current sample, line, band is: 8 88 1 + Current sample, line, band is: 8 89 1 + Current sample, line, band is: 8 90 1 + Current sample, line, band is: 8 91 1 + Current sample, line, band is: 8 92 1 + Current sample, line, band is: 8 93 1 + Current sample, line, band is: 8 94 1 + Current sample, line, band is: 8 95 1 + Current sample, line, band is: 8 96 1 + Current sample, line, band is: 8 97 1 + Current sample, line, band is: 8 98 1 + Current sample, line, band is: 8 99 1 + Current sample, line, band is: 8 100 1 + Current sample, line, band is: 8 101 1 + Current sample, line, band is: 8 102 1 + Current sample, line, band is: 8 103 1 + Current sample, line, band is: 8 104 1 + Current sample, line, band is: 8 105 1 + Current sample, line, band is: 8 106 1 + Current sample, line, band is: 8 107 1 + Current sample, line, band is: 8 108 1 + Current sample, line, band is: 8 109 1 + Current sample, line, band is: 8 110 1 + Current sample, line, band is: 8 111 1 + Current sample, line, band is: 8 112 1 + Current sample, line, band is: 8 113 1 + Current sample, line, band is: 8 114 1 + Current sample, line, band is: 8 115 1 + Current sample, line, band is: 8 116 1 + Current sample, line, band is: 8 117 1 + Current sample, line, band is: 8 118 1 + Current sample, line, band is: 8 119 1 + Current sample, line, band is: 8 120 1 + Current sample, line, band is: 8 121 1 + Current sample, line, band is: 8 122 1 + Current sample, line, band is: 8 123 1 + Current sample, line, band is: 8 124 1 + Current sample, line, band is: 8 125 1 + Current sample, line, band is: 8 126 1 + Current sample, line, band is: 9 1 1 + Current sample, line, band is: 9 2 1 + Current sample, line, band is: 9 3 1 + Current sample, line, band is: 9 4 1 + Current sample, line, band is: 9 5 1 + Current sample, line, band is: 9 6 1 + Current sample, line, band is: 9 7 1 + Current sample, line, band is: 9 8 1 + Current sample, line, band is: 9 9 1 + Current sample, line, band is: 9 10 1 + Current sample, line, band is: 9 11 1 + Current sample, line, band is: 9 12 1 + Current sample, line, band is: 9 13 1 + Current sample, line, band is: 9 14 1 + Current sample, line, band is: 9 15 1 + Current sample, line, band is: 9 16 1 + Current sample, line, band is: 9 17 1 + Current sample, line, band is: 9 18 1 + Current sample, line, band is: 9 19 1 + Current sample, line, band is: 9 20 1 + Current sample, line, band is: 9 21 1 + Current sample, line, band is: 9 22 1 + Current sample, line, band is: 9 23 1 + Current sample, line, band is: 9 24 1 + Current sample, line, band is: 9 25 1 + Current sample, line, band is: 9 26 1 + Current sample, line, band is: 9 27 1 + Current sample, line, band is: 9 28 1 + Current sample, line, band is: 9 29 1 + Current sample, line, band is: 9 30 1 + Current sample, line, band is: 9 31 1 + Current sample, line, band is: 9 32 1 + Current sample, line, band is: 9 33 1 + Current sample, line, band is: 9 34 1 + Current sample, line, band is: 9 35 1 + Current sample, line, band is: 9 36 1 + Current sample, line, band is: 9 37 1 + Current sample, line, band is: 9 38 1 + Current sample, line, band is: 9 39 1 + Current sample, line, band is: 9 40 1 + Current sample, line, band is: 9 41 1 + Current sample, line, band is: 9 42 1 + Current sample, line, band is: 9 43 1 + Current sample, line, band is: 9 44 1 + Current sample, line, band is: 9 45 1 + Current sample, line, band is: 9 46 1 + Current sample, line, band is: 9 47 1 + Current sample, line, band is: 9 48 1 + Current sample, line, band is: 9 49 1 + Current sample, line, band is: 9 50 1 + Current sample, line, band is: 9 51 1 + Current sample, line, band is: 9 52 1 + Current sample, line, band is: 9 53 1 + Current sample, line, band is: 9 54 1 + Current sample, line, band is: 9 55 1 + Current sample, line, band is: 9 56 1 + Current sample, line, band is: 9 57 1 + Current sample, line, band is: 9 58 1 + Current sample, line, band is: 9 59 1 + Current sample, line, band is: 9 60 1 + Current sample, line, band is: 9 61 1 + Current sample, line, band is: 9 62 1 + Current sample, line, band is: 9 63 1 + Current sample, line, band is: 9 64 1 + Current sample, line, band is: 9 65 1 + Current sample, line, band is: 9 66 1 + Current sample, line, band is: 9 67 1 + Current sample, line, band is: 9 68 1 + Current sample, line, band is: 9 69 1 + Current sample, line, band is: 9 70 1 + Current sample, line, band is: 9 71 1 + Current sample, line, band is: 9 72 1 + Current sample, line, band is: 9 73 1 + Current sample, line, band is: 9 74 1 + Current sample, line, band is: 9 75 1 + Current sample, line, band is: 9 76 1 + Current sample, line, band is: 9 77 1 + Current sample, line, band is: 9 78 1 + Current sample, line, band is: 9 79 1 + Current sample, line, band is: 9 80 1 + Current sample, line, band is: 9 81 1 + Current sample, line, band is: 9 82 1 + Current sample, line, band is: 9 83 1 + Current sample, line, band is: 9 84 1 + Current sample, line, band is: 9 85 1 + Current sample, line, band is: 9 86 1 + Current sample, line, band is: 9 87 1 + Current sample, line, band is: 9 88 1 + Current sample, line, band is: 9 89 1 + Current sample, line, band is: 9 90 1 + Current sample, line, band is: 9 91 1 + Current sample, line, band is: 9 92 1 + Current sample, line, band is: 9 93 1 + Current sample, line, band is: 9 94 1 + Current sample, line, band is: 9 95 1 + Current sample, line, band is: 9 96 1 + Current sample, line, band is: 9 97 1 + Current sample, line, band is: 9 98 1 + Current sample, line, band is: 9 99 1 + Current sample, line, band is: 9 100 1 + Current sample, line, band is: 9 101 1 + Current sample, line, band is: 9 102 1 + Current sample, line, band is: 9 103 1 + Current sample, line, band is: 9 104 1 + Current sample, line, band is: 9 105 1 + Current sample, line, band is: 9 106 1 + Current sample, line, band is: 9 107 1 + Current sample, line, band is: 9 108 1 + Current sample, line, band is: 9 109 1 + Current sample, line, band is: 9 110 1 + Current sample, line, band is: 9 111 1 + Current sample, line, band is: 9 112 1 + Current sample, line, band is: 9 113 1 + Current sample, line, band is: 9 114 1 + Current sample, line, band is: 9 115 1 + Current sample, line, band is: 9 116 1 + Current sample, line, band is: 9 117 1 + Current sample, line, band is: 9 118 1 + Current sample, line, band is: 9 119 1 + Current sample, line, band is: 9 120 1 + Current sample, line, band is: 9 121 1 + Current sample, line, band is: 9 122 1 + Current sample, line, band is: 9 123 1 + Current sample, line, band is: 9 124 1 + Current sample, line, band is: 9 125 1 + Current sample, line, band is: 9 126 1 + Current sample, line, band is: 10 1 1 + Current sample, line, band is: 10 2 1 + Current sample, line, band is: 10 3 1 + Current sample, line, band is: 10 4 1 + Current sample, line, band is: 10 5 1 + Current sample, line, band is: 10 6 1 + Current sample, line, band is: 10 7 1 + Current sample, line, band is: 10 8 1 + Current sample, line, band is: 10 9 1 + Current sample, line, band is: 10 10 1 + Current sample, line, band is: 10 11 1 + Current sample, line, band is: 10 12 1 + Current sample, line, band is: 10 13 1 + Current sample, line, band is: 10 14 1 + Current sample, line, band is: 10 15 1 + Current sample, line, band is: 10 16 1 + Current sample, line, band is: 10 17 1 + Current sample, line, band is: 10 18 1 + Current sample, line, band is: 10 19 1 + Current sample, line, band is: 10 20 1 + Current sample, line, band is: 10 21 1 + Current sample, line, band is: 10 22 1 + Current sample, line, band is: 10 23 1 + Current sample, line, band is: 10 24 1 + Current sample, line, band is: 10 25 1 + Current sample, line, band is: 10 26 1 + Current sample, line, band is: 10 27 1 + Current sample, line, band is: 10 28 1 + Current sample, line, band is: 10 29 1 + Current sample, line, band is: 10 30 1 + Current sample, line, band is: 10 31 1 + Current sample, line, band is: 10 32 1 + Current sample, line, band is: 10 33 1 + Current sample, line, band is: 10 34 1 + Current sample, line, band is: 10 35 1 + Current sample, line, band is: 10 36 1 + Current sample, line, band is: 10 37 1 + Current sample, line, band is: 10 38 1 + Current sample, line, band is: 10 39 1 + Current sample, line, band is: 10 40 1 + Current sample, line, band is: 10 41 1 + Current sample, line, band is: 10 42 1 + Current sample, line, band is: 10 43 1 + Current sample, line, band is: 10 44 1 + Current sample, line, band is: 10 45 1 + Current sample, line, band is: 10 46 1 + Current sample, line, band is: 10 47 1 + Current sample, line, band is: 10 48 1 + Current sample, line, band is: 10 49 1 + Current sample, line, band is: 10 50 1 + Current sample, line, band is: 10 51 1 + Current sample, line, band is: 10 52 1 + Current sample, line, band is: 10 53 1 + Current sample, line, band is: 10 54 1 + Current sample, line, band is: 10 55 1 + Current sample, line, band is: 10 56 1 + Current sample, line, band is: 10 57 1 + Current sample, line, band is: 10 58 1 + Current sample, line, band is: 10 59 1 + Current sample, line, band is: 10 60 1 + Current sample, line, band is: 10 61 1 + Current sample, line, band is: 10 62 1 + Current sample, line, band is: 10 63 1 + Current sample, line, band is: 10 64 1 + Current sample, line, band is: 10 65 1 + Current sample, line, band is: 10 66 1 + Current sample, line, band is: 10 67 1 + Current sample, line, band is: 10 68 1 + Current sample, line, band is: 10 69 1 + Current sample, line, band is: 10 70 1 + Current sample, line, band is: 10 71 1 + Current sample, line, band is: 10 72 1 + Current sample, line, band is: 10 73 1 + Current sample, line, band is: 10 74 1 + Current sample, line, band is: 10 75 1 + Current sample, line, band is: 10 76 1 + Current sample, line, band is: 10 77 1 + Current sample, line, band is: 10 78 1 + Current sample, line, band is: 10 79 1 + Current sample, line, band is: 10 80 1 + Current sample, line, band is: 10 81 1 + Current sample, line, band is: 10 82 1 + Current sample, line, band is: 10 83 1 + Current sample, line, band is: 10 84 1 + Current sample, line, band is: 10 85 1 + Current sample, line, band is: 10 86 1 + Current sample, line, band is: 10 87 1 + Current sample, line, band is: 10 88 1 + Current sample, line, band is: 10 89 1 + Current sample, line, band is: 10 90 1 + Current sample, line, band is: 10 91 1 + Current sample, line, band is: 10 92 1 + Current sample, line, band is: 10 93 1 + Current sample, line, band is: 10 94 1 + Current sample, line, band is: 10 95 1 + Current sample, line, band is: 10 96 1 + Current sample, line, band is: 10 97 1 + Current sample, line, band is: 10 98 1 + Current sample, line, band is: 10 99 1 + Current sample, line, band is: 10 100 1 + Current sample, line, band is: 10 101 1 + Current sample, line, band is: 10 102 1 + Current sample, line, band is: 10 103 1 + Current sample, line, band is: 10 104 1 + Current sample, line, band is: 10 105 1 + Current sample, line, band is: 10 106 1 + Current sample, line, band is: 10 107 1 + Current sample, line, band is: 10 108 1 + Current sample, line, band is: 10 109 1 + Current sample, line, band is: 10 110 1 + Current sample, line, band is: 10 111 1 + Current sample, line, band is: 10 112 1 + Current sample, line, band is: 10 113 1 + Current sample, line, band is: 10 114 1 + Current sample, line, band is: 10 115 1 + Current sample, line, band is: 10 116 1 + Current sample, line, band is: 10 117 1 + Current sample, line, band is: 10 118 1 + Current sample, line, band is: 10 119 1 + Current sample, line, band is: 10 120 1 + Current sample, line, band is: 10 121 1 + Current sample, line, band is: 10 122 1 + Current sample, line, band is: 10 123 1 + Current sample, line, band is: 10 124 1 + Current sample, line, band is: 10 125 1 + Current sample, line, band is: 10 126 1 + Current sample, line, band is: 11 1 1 + Current sample, line, band is: 11 2 1 + Current sample, line, band is: 11 3 1 + Current sample, line, band is: 11 4 1 + Current sample, line, band is: 11 5 1 + Current sample, line, band is: 11 6 1 + Current sample, line, band is: 11 7 1 + Current sample, line, band is: 11 8 1 + Current sample, line, band is: 11 9 1 + Current sample, line, band is: 11 10 1 + Current sample, line, band is: 11 11 1 + Current sample, line, band is: 11 12 1 + Current sample, line, band is: 11 13 1 + Current sample, line, band is: 11 14 1 + Current sample, line, band is: 11 15 1 + Current sample, line, band is: 11 16 1 + Current sample, line, band is: 11 17 1 + Current sample, line, band is: 11 18 1 + Current sample, line, band is: 11 19 1 + Current sample, line, band is: 11 20 1 + Current sample, line, band is: 11 21 1 + Current sample, line, band is: 11 22 1 + Current sample, line, band is: 11 23 1 + Current sample, line, band is: 11 24 1 + Current sample, line, band is: 11 25 1 + Current sample, line, band is: 11 26 1 + Current sample, line, band is: 11 27 1 + Current sample, line, band is: 11 28 1 + Current sample, line, band is: 11 29 1 + Current sample, line, band is: 11 30 1 + Current sample, line, band is: 11 31 1 + Current sample, line, band is: 11 32 1 + Current sample, line, band is: 11 33 1 + Current sample, line, band is: 11 34 1 + Current sample, line, band is: 11 35 1 + Current sample, line, band is: 11 36 1 + Current sample, line, band is: 11 37 1 + Current sample, line, band is: 11 38 1 + Current sample, line, band is: 11 39 1 + Current sample, line, band is: 11 40 1 + Current sample, line, band is: 11 41 1 + Current sample, line, band is: 11 42 1 + Current sample, line, band is: 11 43 1 + Current sample, line, band is: 11 44 1 + Current sample, line, band is: 11 45 1 + Current sample, line, band is: 11 46 1 + Current sample, line, band is: 11 47 1 + Current sample, line, band is: 11 48 1 + Current sample, line, band is: 11 49 1 + Current sample, line, band is: 11 50 1 + Current sample, line, band is: 11 51 1 + Current sample, line, band is: 11 52 1 + Current sample, line, band is: 11 53 1 + Current sample, line, band is: 11 54 1 + Current sample, line, band is: 11 55 1 + Current sample, line, band is: 11 56 1 + Current sample, line, band is: 11 57 1 + Current sample, line, band is: 11 58 1 + Current sample, line, band is: 11 59 1 + Current sample, line, band is: 11 60 1 + Current sample, line, band is: 11 61 1 + Current sample, line, band is: 11 62 1 + Current sample, line, band is: 11 63 1 + Current sample, line, band is: 11 64 1 + Current sample, line, band is: 11 65 1 + Current sample, line, band is: 11 66 1 + Current sample, line, band is: 11 67 1 + Current sample, line, band is: 11 68 1 + Current sample, line, band is: 11 69 1 + Current sample, line, band is: 11 70 1 + Current sample, line, band is: 11 71 1 + Current sample, line, band is: 11 72 1 + Current sample, line, band is: 11 73 1 + Current sample, line, band is: 11 74 1 + Current sample, line, band is: 11 75 1 + Current sample, line, band is: 11 76 1 + Current sample, line, band is: 11 77 1 + Current sample, line, band is: 11 78 1 + Current sample, line, band is: 11 79 1 + Current sample, line, band is: 11 80 1 + Current sample, line, band is: 11 81 1 + Current sample, line, band is: 11 82 1 + Current sample, line, band is: 11 83 1 + Current sample, line, band is: 11 84 1 + Current sample, line, band is: 11 85 1 + Current sample, line, band is: 11 86 1 + Current sample, line, band is: 11 87 1 + Current sample, line, band is: 11 88 1 + Current sample, line, band is: 11 89 1 + Current sample, line, band is: 11 90 1 + Current sample, line, band is: 11 91 1 + Current sample, line, band is: 11 92 1 + Current sample, line, band is: 11 93 1 + Current sample, line, band is: 11 94 1 + Current sample, line, band is: 11 95 1 + Current sample, line, band is: 11 96 1 + Current sample, line, band is: 11 97 1 + Current sample, line, band is: 11 98 1 + Current sample, line, band is: 11 99 1 + Current sample, line, band is: 11 100 1 + Current sample, line, band is: 11 101 1 + Current sample, line, band is: 11 102 1 + Current sample, line, band is: 11 103 1 + Current sample, line, band is: 11 104 1 + Current sample, line, band is: 11 105 1 + Current sample, line, band is: 11 106 1 + Current sample, line, band is: 11 107 1 + Current sample, line, band is: 11 108 1 + Current sample, line, band is: 11 109 1 + Current sample, line, band is: 11 110 1 + Current sample, line, band is: 11 111 1 + Current sample, line, band is: 11 112 1 + Current sample, line, band is: 11 113 1 + Current sample, line, band is: 11 114 1 + Current sample, line, band is: 11 115 1 + Current sample, line, band is: 11 116 1 + Current sample, line, band is: 11 117 1 + Current sample, line, band is: 11 118 1 + Current sample, line, band is: 11 119 1 + Current sample, line, band is: 11 120 1 + Current sample, line, band is: 11 121 1 + Current sample, line, band is: 11 122 1 + Current sample, line, band is: 11 123 1 + Current sample, line, band is: 11 124 1 + Current sample, line, band is: 11 125 1 + Current sample, line, band is: 11 126 1 + Current sample, line, band is: 12 1 1 + Current sample, line, band is: 12 2 1 + Current sample, line, band is: 12 3 1 + Current sample, line, band is: 12 4 1 + Current sample, line, band is: 12 5 1 + Current sample, line, band is: 12 6 1 + Current sample, line, band is: 12 7 1 + Current sample, line, band is: 12 8 1 + Current sample, line, band is: 12 9 1 + Current sample, line, band is: 12 10 1 + Current sample, line, band is: 12 11 1 + Current sample, line, band is: 12 12 1 + Current sample, line, band is: 12 13 1 + Current sample, line, band is: 12 14 1 + Current sample, line, band is: 12 15 1 + Current sample, line, band is: 12 16 1 + Current sample, line, band is: 12 17 1 + Current sample, line, band is: 12 18 1 + Current sample, line, band is: 12 19 1 + Current sample, line, band is: 12 20 1 + Current sample, line, band is: 12 21 1 + Current sample, line, band is: 12 22 1 + Current sample, line, band is: 12 23 1 + Current sample, line, band is: 12 24 1 + Current sample, line, band is: 12 25 1 + Current sample, line, band is: 12 26 1 + Current sample, line, band is: 12 27 1 + Current sample, line, band is: 12 28 1 + Current sample, line, band is: 12 29 1 + Current sample, line, band is: 12 30 1 + Current sample, line, band is: 12 31 1 + Current sample, line, band is: 12 32 1 + Current sample, line, band is: 12 33 1 + Current sample, line, band is: 12 34 1 + Current sample, line, band is: 12 35 1 + Current sample, line, band is: 12 36 1 + Current sample, line, band is: 12 37 1 + Current sample, line, band is: 12 38 1 + Current sample, line, band is: 12 39 1 + Current sample, line, band is: 12 40 1 + Current sample, line, band is: 12 41 1 + Current sample, line, band is: 12 42 1 + Current sample, line, band is: 12 43 1 + Current sample, line, band is: 12 44 1 + Current sample, line, band is: 12 45 1 + Current sample, line, band is: 12 46 1 + Current sample, line, band is: 12 47 1 + Current sample, line, band is: 12 48 1 + Current sample, line, band is: 12 49 1 + Current sample, line, band is: 12 50 1 + Current sample, line, band is: 12 51 1 + Current sample, line, band is: 12 52 1 + Current sample, line, band is: 12 53 1 + Current sample, line, band is: 12 54 1 + Current sample, line, band is: 12 55 1 + Current sample, line, band is: 12 56 1 + Current sample, line, band is: 12 57 1 + Current sample, line, band is: 12 58 1 + Current sample, line, band is: 12 59 1 + Current sample, line, band is: 12 60 1 + Current sample, line, band is: 12 61 1 + Current sample, line, band is: 12 62 1 + Current sample, line, band is: 12 63 1 + Current sample, line, band is: 12 64 1 + Current sample, line, band is: 12 65 1 + Current sample, line, band is: 12 66 1 + Current sample, line, band is: 12 67 1 + Current sample, line, band is: 12 68 1 + Current sample, line, band is: 12 69 1 + Current sample, line, band is: 12 70 1 + Current sample, line, band is: 12 71 1 + Current sample, line, band is: 12 72 1 + Current sample, line, band is: 12 73 1 + Current sample, line, band is: 12 74 1 + Current sample, line, band is: 12 75 1 + Current sample, line, band is: 12 76 1 + Current sample, line, band is: 12 77 1 + Current sample, line, band is: 12 78 1 + Current sample, line, band is: 12 79 1 + Current sample, line, band is: 12 80 1 + Current sample, line, band is: 12 81 1 + Current sample, line, band is: 12 82 1 + Current sample, line, band is: 12 83 1 + Current sample, line, band is: 12 84 1 + Current sample, line, band is: 12 85 1 + Current sample, line, band is: 12 86 1 + Current sample, line, band is: 12 87 1 + Current sample, line, band is: 12 88 1 + Current sample, line, band is: 12 89 1 + Current sample, line, band is: 12 90 1 + Current sample, line, band is: 12 91 1 + Current sample, line, band is: 12 92 1 + Current sample, line, band is: 12 93 1 + Current sample, line, band is: 12 94 1 + Current sample, line, band is: 12 95 1 + Current sample, line, band is: 12 96 1 + Current sample, line, band is: 12 97 1 + Current sample, line, band is: 12 98 1 + Current sample, line, band is: 12 99 1 + Current sample, line, band is: 12 100 1 + Current sample, line, band is: 12 101 1 + Current sample, line, band is: 12 102 1 + Current sample, line, band is: 12 103 1 + Current sample, line, band is: 12 104 1 + Current sample, line, band is: 12 105 1 + Current sample, line, band is: 12 106 1 + Current sample, line, band is: 12 107 1 + Current sample, line, band is: 12 108 1 + Current sample, line, band is: 12 109 1 + Current sample, line, band is: 12 110 1 + Current sample, line, band is: 12 111 1 + Current sample, line, band is: 12 112 1 + Current sample, line, band is: 12 113 1 + Current sample, line, band is: 12 114 1 + Current sample, line, band is: 12 115 1 + Current sample, line, band is: 12 116 1 + Current sample, line, band is: 12 117 1 + Current sample, line, band is: 12 118 1 + Current sample, line, band is: 12 119 1 + Current sample, line, band is: 12 120 1 + Current sample, line, band is: 12 121 1 + Current sample, line, band is: 12 122 1 + Current sample, line, band is: 12 123 1 + Current sample, line, band is: 12 124 1 + Current sample, line, band is: 12 125 1 + Current sample, line, band is: 12 126 1 + Current sample, line, band is: 13 1 1 + Current sample, line, band is: 13 2 1 + Current sample, line, band is: 13 3 1 + Current sample, line, band is: 13 4 1 + Current sample, line, band is: 13 5 1 + Current sample, line, band is: 13 6 1 + Current sample, line, band is: 13 7 1 + Current sample, line, band is: 13 8 1 + Current sample, line, band is: 13 9 1 + Current sample, line, band is: 13 10 1 + Current sample, line, band is: 13 11 1 + Current sample, line, band is: 13 12 1 + Current sample, line, band is: 13 13 1 + Current sample, line, band is: 13 14 1 + Current sample, line, band is: 13 15 1 + Current sample, line, band is: 13 16 1 + Current sample, line, band is: 13 17 1 + Current sample, line, band is: 13 18 1 + Current sample, line, band is: 13 19 1 + Current sample, line, band is: 13 20 1 + Current sample, line, band is: 13 21 1 + Current sample, line, band is: 13 22 1 + Current sample, line, band is: 13 23 1 + Current sample, line, band is: 13 24 1 + Current sample, line, band is: 13 25 1 + Current sample, line, band is: 13 26 1 + Current sample, line, band is: 13 27 1 + Current sample, line, band is: 13 28 1 + Current sample, line, band is: 13 29 1 + Current sample, line, band is: 13 30 1 + Current sample, line, band is: 13 31 1 + Current sample, line, band is: 13 32 1 + Current sample, line, band is: 13 33 1 + Current sample, line, band is: 13 34 1 + Current sample, line, band is: 13 35 1 + Current sample, line, band is: 13 36 1 + Current sample, line, band is: 13 37 1 + Current sample, line, band is: 13 38 1 + Current sample, line, band is: 13 39 1 + Current sample, line, band is: 13 40 1 + Current sample, line, band is: 13 41 1 + Current sample, line, band is: 13 42 1 + Current sample, line, band is: 13 43 1 + Current sample, line, band is: 13 44 1 + Current sample, line, band is: 13 45 1 + Current sample, line, band is: 13 46 1 + Current sample, line, band is: 13 47 1 + Current sample, line, band is: 13 48 1 + Current sample, line, band is: 13 49 1 + Current sample, line, band is: 13 50 1 + Current sample, line, band is: 13 51 1 + Current sample, line, band is: 13 52 1 + Current sample, line, band is: 13 53 1 + Current sample, line, band is: 13 54 1 + Current sample, line, band is: 13 55 1 + Current sample, line, band is: 13 56 1 + Current sample, line, band is: 13 57 1 + Current sample, line, band is: 13 58 1 + Current sample, line, band is: 13 59 1 + Current sample, line, band is: 13 60 1 + Current sample, line, band is: 13 61 1 + Current sample, line, band is: 13 62 1 + Current sample, line, band is: 13 63 1 + Current sample, line, band is: 13 64 1 + Current sample, line, band is: 13 65 1 + Current sample, line, band is: 13 66 1 + Current sample, line, band is: 13 67 1 + Current sample, line, band is: 13 68 1 + Current sample, line, band is: 13 69 1 + Current sample, line, band is: 13 70 1 + Current sample, line, band is: 13 71 1 + Current sample, line, band is: 13 72 1 + Current sample, line, band is: 13 73 1 + Current sample, line, band is: 13 74 1 + Current sample, line, band is: 13 75 1 + Current sample, line, band is: 13 76 1 + Current sample, line, band is: 13 77 1 + Current sample, line, band is: 13 78 1 + Current sample, line, band is: 13 79 1 + Current sample, line, band is: 13 80 1 + Current sample, line, band is: 13 81 1 + Current sample, line, band is: 13 82 1 + Current sample, line, band is: 13 83 1 + Current sample, line, band is: 13 84 1 + Current sample, line, band is: 13 85 1 + Current sample, line, band is: 13 86 1 + Current sample, line, band is: 13 87 1 + Current sample, line, band is: 13 88 1 + Current sample, line, band is: 13 89 1 + Current sample, line, band is: 13 90 1 + Current sample, line, band is: 13 91 1 + Current sample, line, band is: 13 92 1 + Current sample, line, band is: 13 93 1 + Current sample, line, band is: 13 94 1 + Current sample, line, band is: 13 95 1 + Current sample, line, band is: 13 96 1 + Current sample, line, band is: 13 97 1 + Current sample, line, band is: 13 98 1 + Current sample, line, band is: 13 99 1 + Current sample, line, band is: 13 100 1 + Current sample, line, band is: 13 101 1 + Current sample, line, band is: 13 102 1 + Current sample, line, band is: 13 103 1 + Current sample, line, band is: 13 104 1 + Current sample, line, band is: 13 105 1 + Current sample, line, band is: 13 106 1 + Current sample, line, band is: 13 107 1 + Current sample, line, band is: 13 108 1 + Current sample, line, band is: 13 109 1 + Current sample, line, band is: 13 110 1 + Current sample, line, band is: 13 111 1 + Current sample, line, band is: 13 112 1 + Current sample, line, band is: 13 113 1 + Current sample, line, band is: 13 114 1 + Current sample, line, band is: 13 115 1 + Current sample, line, band is: 13 116 1 + Current sample, line, band is: 13 117 1 + Current sample, line, band is: 13 118 1 + Current sample, line, band is: 13 119 1 + Current sample, line, band is: 13 120 1 + Current sample, line, band is: 13 121 1 + Current sample, line, band is: 13 122 1 + Current sample, line, band is: 13 123 1 + Current sample, line, band is: 13 124 1 + Current sample, line, band is: 13 125 1 + Current sample, line, band is: 13 126 1 + Current sample, line, band is: 14 1 1 + Current sample, line, band is: 14 2 1 + Current sample, line, band is: 14 3 1 + Current sample, line, band is: 14 4 1 + Current sample, line, band is: 14 5 1 + Current sample, line, band is: 14 6 1 + Current sample, line, band is: 14 7 1 + Current sample, line, band is: 14 8 1 + Current sample, line, band is: 14 9 1 + Current sample, line, band is: 14 10 1 + Current sample, line, band is: 14 11 1 + Current sample, line, band is: 14 12 1 + Current sample, line, band is: 14 13 1 + Current sample, line, band is: 14 14 1 + Current sample, line, band is: 14 15 1 + Current sample, line, band is: 14 16 1 + Current sample, line, band is: 14 17 1 + Current sample, line, band is: 14 18 1 + Current sample, line, band is: 14 19 1 + Current sample, line, band is: 14 20 1 + Current sample, line, band is: 14 21 1 + Current sample, line, band is: 14 22 1 + Current sample, line, band is: 14 23 1 + Current sample, line, band is: 14 24 1 + Current sample, line, band is: 14 25 1 + Current sample, line, band is: 14 26 1 + Current sample, line, band is: 14 27 1 + Current sample, line, band is: 14 28 1 + Current sample, line, band is: 14 29 1 + Current sample, line, band is: 14 30 1 + Current sample, line, band is: 14 31 1 + Current sample, line, band is: 14 32 1 + Current sample, line, band is: 14 33 1 + Current sample, line, band is: 14 34 1 + Current sample, line, band is: 14 35 1 + Current sample, line, band is: 14 36 1 + Current sample, line, band is: 14 37 1 + Current sample, line, band is: 14 38 1 + Current sample, line, band is: 14 39 1 + Current sample, line, band is: 14 40 1 + Current sample, line, band is: 14 41 1 + Current sample, line, band is: 14 42 1 + Current sample, line, band is: 14 43 1 + Current sample, line, band is: 14 44 1 + Current sample, line, band is: 14 45 1 + Current sample, line, band is: 14 46 1 + Current sample, line, band is: 14 47 1 + Current sample, line, band is: 14 48 1 + Current sample, line, band is: 14 49 1 + Current sample, line, band is: 14 50 1 + Current sample, line, band is: 14 51 1 + Current sample, line, band is: 14 52 1 + Current sample, line, band is: 14 53 1 + Current sample, line, band is: 14 54 1 + Current sample, line, band is: 14 55 1 + Current sample, line, band is: 14 56 1 + Current sample, line, band is: 14 57 1 + Current sample, line, band is: 14 58 1 + Current sample, line, band is: 14 59 1 + Current sample, line, band is: 14 60 1 + Current sample, line, band is: 14 61 1 + Current sample, line, band is: 14 62 1 + Current sample, line, band is: 14 63 1 + Current sample, line, band is: 14 64 1 + Current sample, line, band is: 14 65 1 + Current sample, line, band is: 14 66 1 + Current sample, line, band is: 14 67 1 + Current sample, line, band is: 14 68 1 + Current sample, line, band is: 14 69 1 + Current sample, line, band is: 14 70 1 + Current sample, line, band is: 14 71 1 + Current sample, line, band is: 14 72 1 + Current sample, line, band is: 14 73 1 + Current sample, line, band is: 14 74 1 + Current sample, line, band is: 14 75 1 + Current sample, line, band is: 14 76 1 + Current sample, line, band is: 14 77 1 + Current sample, line, band is: 14 78 1 + Current sample, line, band is: 14 79 1 + Current sample, line, band is: 14 80 1 + Current sample, line, band is: 14 81 1 + Current sample, line, band is: 14 82 1 + Current sample, line, band is: 14 83 1 + Current sample, line, band is: 14 84 1 + Current sample, line, band is: 14 85 1 + Current sample, line, band is: 14 86 1 + Current sample, line, band is: 14 87 1 + Current sample, line, band is: 14 88 1 + Current sample, line, band is: 14 89 1 + Current sample, line, band is: 14 90 1 + Current sample, line, band is: 14 91 1 + Current sample, line, band is: 14 92 1 + Current sample, line, band is: 14 93 1 + Current sample, line, band is: 14 94 1 + Current sample, line, band is: 14 95 1 + Current sample, line, band is: 14 96 1 + Current sample, line, band is: 14 97 1 + Current sample, line, band is: 14 98 1 + Current sample, line, band is: 14 99 1 + Current sample, line, band is: 14 100 1 + Current sample, line, band is: 14 101 1 + Current sample, line, band is: 14 102 1 + Current sample, line, band is: 14 103 1 + Current sample, line, band is: 14 104 1 + Current sample, line, band is: 14 105 1 + Current sample, line, band is: 14 106 1 + Current sample, line, band is: 14 107 1 + Current sample, line, band is: 14 108 1 + Current sample, line, band is: 14 109 1 + Current sample, line, band is: 14 110 1 + Current sample, line, band is: 14 111 1 + Current sample, line, band is: 14 112 1 + Current sample, line, band is: 14 113 1 + Current sample, line, band is: 14 114 1 + Current sample, line, band is: 14 115 1 + Current sample, line, band is: 14 116 1 + Current sample, line, band is: 14 117 1 + Current sample, line, band is: 14 118 1 + Current sample, line, band is: 14 119 1 + Current sample, line, band is: 14 120 1 + Current sample, line, band is: 14 121 1 + Current sample, line, band is: 14 122 1 + Current sample, line, band is: 14 123 1 + Current sample, line, band is: 14 124 1 + Current sample, line, band is: 14 125 1 + Current sample, line, band is: 14 126 1 + Current sample, line, band is: 15 1 1 + Current sample, line, band is: 15 2 1 + Current sample, line, band is: 15 3 1 + Current sample, line, band is: 15 4 1 + Current sample, line, band is: 15 5 1 + Current sample, line, band is: 15 6 1 + Current sample, line, band is: 15 7 1 + Current sample, line, band is: 15 8 1 + Current sample, line, band is: 15 9 1 + Current sample, line, band is: 15 10 1 + Current sample, line, band is: 15 11 1 + Current sample, line, band is: 15 12 1 + Current sample, line, band is: 15 13 1 + Current sample, line, band is: 15 14 1 + Current sample, line, band is: 15 15 1 + Current sample, line, band is: 15 16 1 + Current sample, line, band is: 15 17 1 + Current sample, line, band is: 15 18 1 + Current sample, line, band is: 15 19 1 + Current sample, line, band is: 15 20 1 + Current sample, line, band is: 15 21 1 + Current sample, line, band is: 15 22 1 + Current sample, line, band is: 15 23 1 + Current sample, line, band is: 15 24 1 + Current sample, line, band is: 15 25 1 + Current sample, line, band is: 15 26 1 + Current sample, line, band is: 15 27 1 + Current sample, line, band is: 15 28 1 + Current sample, line, band is: 15 29 1 + Current sample, line, band is: 15 30 1 + Current sample, line, band is: 15 31 1 + Current sample, line, band is: 15 32 1 + Current sample, line, band is: 15 33 1 + Current sample, line, band is: 15 34 1 + Current sample, line, band is: 15 35 1 + Current sample, line, band is: 15 36 1 + Current sample, line, band is: 15 37 1 + Current sample, line, band is: 15 38 1 + Current sample, line, band is: 15 39 1 + Current sample, line, band is: 15 40 1 + Current sample, line, band is: 15 41 1 + Current sample, line, band is: 15 42 1 + Current sample, line, band is: 15 43 1 + Current sample, line, band is: 15 44 1 + Current sample, line, band is: 15 45 1 + Current sample, line, band is: 15 46 1 + Current sample, line, band is: 15 47 1 + Current sample, line, band is: 15 48 1 + Current sample, line, band is: 15 49 1 + Current sample, line, band is: 15 50 1 + Current sample, line, band is: 15 51 1 + Current sample, line, band is: 15 52 1 + Current sample, line, band is: 15 53 1 + Current sample, line, band is: 15 54 1 + Current sample, line, band is: 15 55 1 + Current sample, line, band is: 15 56 1 + Current sample, line, band is: 15 57 1 + Current sample, line, band is: 15 58 1 + Current sample, line, band is: 15 59 1 + Current sample, line, band is: 15 60 1 + Current sample, line, band is: 15 61 1 + Current sample, line, band is: 15 62 1 + Current sample, line, band is: 15 63 1 + Current sample, line, band is: 15 64 1 + Current sample, line, band is: 15 65 1 + Current sample, line, band is: 15 66 1 + Current sample, line, band is: 15 67 1 + Current sample, line, band is: 15 68 1 + Current sample, line, band is: 15 69 1 + Current sample, line, band is: 15 70 1 + Current sample, line, band is: 15 71 1 + Current sample, line, band is: 15 72 1 + Current sample, line, band is: 15 73 1 + Current sample, line, band is: 15 74 1 + Current sample, line, band is: 15 75 1 + Current sample, line, band is: 15 76 1 + Current sample, line, band is: 15 77 1 + Current sample, line, band is: 15 78 1 + Current sample, line, band is: 15 79 1 + Current sample, line, band is: 15 80 1 + Current sample, line, band is: 15 81 1 + Current sample, line, band is: 15 82 1 + Current sample, line, band is: 15 83 1 + Current sample, line, band is: 15 84 1 + Current sample, line, band is: 15 85 1 + Current sample, line, band is: 15 86 1 + Current sample, line, band is: 15 87 1 + Current sample, line, band is: 15 88 1 + Current sample, line, band is: 15 89 1 + Current sample, line, band is: 15 90 1 + Current sample, line, band is: 15 91 1 + Current sample, line, band is: 15 92 1 + Current sample, line, band is: 15 93 1 + Current sample, line, band is: 15 94 1 + Current sample, line, band is: 15 95 1 + Current sample, line, band is: 15 96 1 + Current sample, line, band is: 15 97 1 + Current sample, line, band is: 15 98 1 + Current sample, line, band is: 15 99 1 + Current sample, line, band is: 15 100 1 + Current sample, line, band is: 15 101 1 + Current sample, line, band is: 15 102 1 + Current sample, line, band is: 15 103 1 + Current sample, line, band is: 15 104 1 + Current sample, line, band is: 15 105 1 + Current sample, line, band is: 15 106 1 + Current sample, line, band is: 15 107 1 + Current sample, line, band is: 15 108 1 + Current sample, line, band is: 15 109 1 + Current sample, line, band is: 15 110 1 + Current sample, line, band is: 15 111 1 + Current sample, line, band is: 15 112 1 + Current sample, line, band is: 15 113 1 + Current sample, line, band is: 15 114 1 + Current sample, line, band is: 15 115 1 + Current sample, line, band is: 15 116 1 + Current sample, line, band is: 15 117 1 + Current sample, line, band is: 15 118 1 + Current sample, line, band is: 15 119 1 + Current sample, line, band is: 15 120 1 + Current sample, line, band is: 15 121 1 + Current sample, line, band is: 15 122 1 + Current sample, line, band is: 15 123 1 + Current sample, line, band is: 15 124 1 + Current sample, line, band is: 15 125 1 + Current sample, line, band is: 15 126 1 + Current sample, line, band is: 16 1 1 + Current sample, line, band is: 16 2 1 + Current sample, line, band is: 16 3 1 + Current sample, line, band is: 16 4 1 + Current sample, line, band is: 16 5 1 + Current sample, line, band is: 16 6 1 + Current sample, line, band is: 16 7 1 + Current sample, line, band is: 16 8 1 + Current sample, line, band is: 16 9 1 + Current sample, line, band is: 16 10 1 + Current sample, line, band is: 16 11 1 + Current sample, line, band is: 16 12 1 + Current sample, line, band is: 16 13 1 + Current sample, line, band is: 16 14 1 + Current sample, line, band is: 16 15 1 + Current sample, line, band is: 16 16 1 + Current sample, line, band is: 16 17 1 + Current sample, line, band is: 16 18 1 + Current sample, line, band is: 16 19 1 + Current sample, line, band is: 16 20 1 + Current sample, line, band is: 16 21 1 + Current sample, line, band is: 16 22 1 + Current sample, line, band is: 16 23 1 + Current sample, line, band is: 16 24 1 + Current sample, line, band is: 16 25 1 + Current sample, line, band is: 16 26 1 + Current sample, line, band is: 16 27 1 + Current sample, line, band is: 16 28 1 + Current sample, line, band is: 16 29 1 + Current sample, line, band is: 16 30 1 + Current sample, line, band is: 16 31 1 + Current sample, line, band is: 16 32 1 + Current sample, line, band is: 16 33 1 + Current sample, line, band is: 16 34 1 + Current sample, line, band is: 16 35 1 + Current sample, line, band is: 16 36 1 + Current sample, line, band is: 16 37 1 + Current sample, line, band is: 16 38 1 + Current sample, line, band is: 16 39 1 + Current sample, line, band is: 16 40 1 + Current sample, line, band is: 16 41 1 + Current sample, line, band is: 16 42 1 + Current sample, line, band is: 16 43 1 + Current sample, line, band is: 16 44 1 + Current sample, line, band is: 16 45 1 + Current sample, line, band is: 16 46 1 + Current sample, line, band is: 16 47 1 + Current sample, line, band is: 16 48 1 + Current sample, line, band is: 16 49 1 + Current sample, line, band is: 16 50 1 + Current sample, line, band is: 16 51 1 + Current sample, line, band is: 16 52 1 + Current sample, line, band is: 16 53 1 + Current sample, line, band is: 16 54 1 + Current sample, line, band is: 16 55 1 + Current sample, line, band is: 16 56 1 + Current sample, line, band is: 16 57 1 + Current sample, line, band is: 16 58 1 + Current sample, line, band is: 16 59 1 + Current sample, line, band is: 16 60 1 + Current sample, line, band is: 16 61 1 + Current sample, line, band is: 16 62 1 + Current sample, line, band is: 16 63 1 + Current sample, line, band is: 16 64 1 + Current sample, line, band is: 16 65 1 + Current sample, line, band is: 16 66 1 + Current sample, line, band is: 16 67 1 + Current sample, line, band is: 16 68 1 + Current sample, line, band is: 16 69 1 + Current sample, line, band is: 16 70 1 + Current sample, line, band is: 16 71 1 + Current sample, line, band is: 16 72 1 + Current sample, line, band is: 16 73 1 + Current sample, line, band is: 16 74 1 + Current sample, line, band is: 16 75 1 + Current sample, line, band is: 16 76 1 + Current sample, line, band is: 16 77 1 + Current sample, line, band is: 16 78 1 + Current sample, line, band is: 16 79 1 + Current sample, line, band is: 16 80 1 + Current sample, line, band is: 16 81 1 + Current sample, line, band is: 16 82 1 + Current sample, line, band is: 16 83 1 + Current sample, line, band is: 16 84 1 + Current sample, line, band is: 16 85 1 + Current sample, line, band is: 16 86 1 + Current sample, line, band is: 16 87 1 + Current sample, line, band is: 16 88 1 + Current sample, line, band is: 16 89 1 + Current sample, line, band is: 16 90 1 + Current sample, line, band is: 16 91 1 + Current sample, line, band is: 16 92 1 + Current sample, line, band is: 16 93 1 + Current sample, line, band is: 16 94 1 + Current sample, line, band is: 16 95 1 + Current sample, line, band is: 16 96 1 + Current sample, line, band is: 16 97 1 + Current sample, line, band is: 16 98 1 + Current sample, line, band is: 16 99 1 + Current sample, line, band is: 16 100 1 + Current sample, line, band is: 16 101 1 + Current sample, line, band is: 16 102 1 + Current sample, line, band is: 16 103 1 + Current sample, line, band is: 16 104 1 + Current sample, line, band is: 16 105 1 + Current sample, line, band is: 16 106 1 + Current sample, line, band is: 16 107 1 + Current sample, line, band is: 16 108 1 + Current sample, line, band is: 16 109 1 + Current sample, line, band is: 16 110 1 + Current sample, line, band is: 16 111 1 + Current sample, line, band is: 16 112 1 + Current sample, line, band is: 16 113 1 + Current sample, line, band is: 16 114 1 + Current sample, line, band is: 16 115 1 + Current sample, line, band is: 16 116 1 + Current sample, line, band is: 16 117 1 + Current sample, line, band is: 16 118 1 + Current sample, line, band is: 16 119 1 + Current sample, line, band is: 16 120 1 + Current sample, line, band is: 16 121 1 + Current sample, line, band is: 16 122 1 + Current sample, line, band is: 16 123 1 + Current sample, line, band is: 16 124 1 + Current sample, line, band is: 16 125 1 + Current sample, line, band is: 16 126 1 + Current sample, line, band is: 17 1 1 + Current sample, line, band is: 17 2 1 + Current sample, line, band is: 17 3 1 + Current sample, line, band is: 17 4 1 + Current sample, line, band is: 17 5 1 + Current sample, line, band is: 17 6 1 + Current sample, line, band is: 17 7 1 + Current sample, line, band is: 17 8 1 + Current sample, line, band is: 17 9 1 + Current sample, line, band is: 17 10 1 + Current sample, line, band is: 17 11 1 + Current sample, line, band is: 17 12 1 + Current sample, line, band is: 17 13 1 + Current sample, line, band is: 17 14 1 + Current sample, line, band is: 17 15 1 + Current sample, line, band is: 17 16 1 + Current sample, line, band is: 17 17 1 + Current sample, line, band is: 17 18 1 + Current sample, line, band is: 17 19 1 + Current sample, line, band is: 17 20 1 + Current sample, line, band is: 17 21 1 + Current sample, line, band is: 17 22 1 + Current sample, line, band is: 17 23 1 + Current sample, line, band is: 17 24 1 + Current sample, line, band is: 17 25 1 + Current sample, line, band is: 17 26 1 + Current sample, line, band is: 17 27 1 + Current sample, line, band is: 17 28 1 + Current sample, line, band is: 17 29 1 + Current sample, line, band is: 17 30 1 + Current sample, line, band is: 17 31 1 + Current sample, line, band is: 17 32 1 + Current sample, line, band is: 17 33 1 + Current sample, line, band is: 17 34 1 + Current sample, line, band is: 17 35 1 + Current sample, line, band is: 17 36 1 + Current sample, line, band is: 17 37 1 + Current sample, line, band is: 17 38 1 + Current sample, line, band is: 17 39 1 + Current sample, line, band is: 17 40 1 + Current sample, line, band is: 17 41 1 + Current sample, line, band is: 17 42 1 + Current sample, line, band is: 17 43 1 + Current sample, line, band is: 17 44 1 + Current sample, line, band is: 17 45 1 + Current sample, line, band is: 17 46 1 + Current sample, line, band is: 17 47 1 + Current sample, line, band is: 17 48 1 + Current sample, line, band is: 17 49 1 + Current sample, line, band is: 17 50 1 + Current sample, line, band is: 17 51 1 + Current sample, line, band is: 17 52 1 + Current sample, line, band is: 17 53 1 + Current sample, line, band is: 17 54 1 + Current sample, line, band is: 17 55 1 + Current sample, line, band is: 17 56 1 + Current sample, line, band is: 17 57 1 + Current sample, line, band is: 17 58 1 + Current sample, line, band is: 17 59 1 + Current sample, line, band is: 17 60 1 + Current sample, line, band is: 17 61 1 + Current sample, line, band is: 17 62 1 + Current sample, line, band is: 17 63 1 + Current sample, line, band is: 17 64 1 + Current sample, line, band is: 17 65 1 + Current sample, line, band is: 17 66 1 + Current sample, line, band is: 17 67 1 + Current sample, line, band is: 17 68 1 + Current sample, line, band is: 17 69 1 + Current sample, line, band is: 17 70 1 + Current sample, line, band is: 17 71 1 + Current sample, line, band is: 17 72 1 + Current sample, line, band is: 17 73 1 + Current sample, line, band is: 17 74 1 + Current sample, line, band is: 17 75 1 + Current sample, line, band is: 17 76 1 + Current sample, line, band is: 17 77 1 + Current sample, line, band is: 17 78 1 + Current sample, line, band is: 17 79 1 + Current sample, line, band is: 17 80 1 + Current sample, line, band is: 17 81 1 + Current sample, line, band is: 17 82 1 + Current sample, line, band is: 17 83 1 + Current sample, line, band is: 17 84 1 + Current sample, line, band is: 17 85 1 + Current sample, line, band is: 17 86 1 + Current sample, line, band is: 17 87 1 + Current sample, line, band is: 17 88 1 + Current sample, line, band is: 17 89 1 + Current sample, line, band is: 17 90 1 + Current sample, line, band is: 17 91 1 + Current sample, line, band is: 17 92 1 + Current sample, line, band is: 17 93 1 + Current sample, line, band is: 17 94 1 + Current sample, line, band is: 17 95 1 + Current sample, line, band is: 17 96 1 + Current sample, line, band is: 17 97 1 + Current sample, line, band is: 17 98 1 + Current sample, line, band is: 17 99 1 + Current sample, line, band is: 17 100 1 + Current sample, line, band is: 17 101 1 + Current sample, line, band is: 17 102 1 + Current sample, line, band is: 17 103 1 + Current sample, line, band is: 17 104 1 + Current sample, line, band is: 17 105 1 + Current sample, line, band is: 17 106 1 + Current sample, line, band is: 17 107 1 + Current sample, line, band is: 17 108 1 + Current sample, line, band is: 17 109 1 + Current sample, line, band is: 17 110 1 + Current sample, line, band is: 17 111 1 + Current sample, line, band is: 17 112 1 + Current sample, line, band is: 17 113 1 + Current sample, line, band is: 17 114 1 + Current sample, line, band is: 17 115 1 + Current sample, line, band is: 17 116 1 + Current sample, line, band is: 17 117 1 + Current sample, line, band is: 17 118 1 + Current sample, line, band is: 17 119 1 + Current sample, line, band is: 17 120 1 + Current sample, line, band is: 17 121 1 + Current sample, line, band is: 17 122 1 + Current sample, line, band is: 17 123 1 + Current sample, line, band is: 17 124 1 + Current sample, line, band is: 17 125 1 + Current sample, line, band is: 17 126 1 + Current sample, line, band is: 18 1 1 + Current sample, line, band is: 18 2 1 + Current sample, line, band is: 18 3 1 + Current sample, line, band is: 18 4 1 + Current sample, line, band is: 18 5 1 + Current sample, line, band is: 18 6 1 + Current sample, line, band is: 18 7 1 + Current sample, line, band is: 18 8 1 + Current sample, line, band is: 18 9 1 + Current sample, line, band is: 18 10 1 + Current sample, line, band is: 18 11 1 + Current sample, line, band is: 18 12 1 + Current sample, line, band is: 18 13 1 + Current sample, line, band is: 18 14 1 + Current sample, line, band is: 18 15 1 + Current sample, line, band is: 18 16 1 + Current sample, line, band is: 18 17 1 + Current sample, line, band is: 18 18 1 + Current sample, line, band is: 18 19 1 + Current sample, line, band is: 18 20 1 + Current sample, line, band is: 18 21 1 + Current sample, line, band is: 18 22 1 + Current sample, line, band is: 18 23 1 + Current sample, line, band is: 18 24 1 + Current sample, line, band is: 18 25 1 + Current sample, line, band is: 18 26 1 + Current sample, line, band is: 18 27 1 + Current sample, line, band is: 18 28 1 + Current sample, line, band is: 18 29 1 + Current sample, line, band is: 18 30 1 + Current sample, line, band is: 18 31 1 + Current sample, line, band is: 18 32 1 + Current sample, line, band is: 18 33 1 + Current sample, line, band is: 18 34 1 + Current sample, line, band is: 18 35 1 + Current sample, line, band is: 18 36 1 + Current sample, line, band is: 18 37 1 + Current sample, line, band is: 18 38 1 + Current sample, line, band is: 18 39 1 + Current sample, line, band is: 18 40 1 + Current sample, line, band is: 18 41 1 + Current sample, line, band is: 18 42 1 + Current sample, line, band is: 18 43 1 + Current sample, line, band is: 18 44 1 + Current sample, line, band is: 18 45 1 + Current sample, line, band is: 18 46 1 + Current sample, line, band is: 18 47 1 + Current sample, line, band is: 18 48 1 + Current sample, line, band is: 18 49 1 + Current sample, line, band is: 18 50 1 + Current sample, line, band is: 18 51 1 + Current sample, line, band is: 18 52 1 + Current sample, line, band is: 18 53 1 + Current sample, line, band is: 18 54 1 + Current sample, line, band is: 18 55 1 + Current sample, line, band is: 18 56 1 + Current sample, line, band is: 18 57 1 + Current sample, line, band is: 18 58 1 + Current sample, line, band is: 18 59 1 + Current sample, line, band is: 18 60 1 + Current sample, line, band is: 18 61 1 + Current sample, line, band is: 18 62 1 + Current sample, line, band is: 18 63 1 + Current sample, line, band is: 18 64 1 + Current sample, line, band is: 18 65 1 + Current sample, line, band is: 18 66 1 + Current sample, line, band is: 18 67 1 + Current sample, line, band is: 18 68 1 + Current sample, line, band is: 18 69 1 + Current sample, line, band is: 18 70 1 + Current sample, line, band is: 18 71 1 + Current sample, line, band is: 18 72 1 + Current sample, line, band is: 18 73 1 + Current sample, line, band is: 18 74 1 + Current sample, line, band is: 18 75 1 + Current sample, line, band is: 18 76 1 + Current sample, line, band is: 18 77 1 + Current sample, line, band is: 18 78 1 + Current sample, line, band is: 18 79 1 + Current sample, line, band is: 18 80 1 + Current sample, line, band is: 18 81 1 + Current sample, line, band is: 18 82 1 + Current sample, line, band is: 18 83 1 + Current sample, line, band is: 18 84 1 + Current sample, line, band is: 18 85 1 + Current sample, line, band is: 18 86 1 + Current sample, line, band is: 18 87 1 + Current sample, line, band is: 18 88 1 + Current sample, line, band is: 18 89 1 + Current sample, line, band is: 18 90 1 + Current sample, line, band is: 18 91 1 + Current sample, line, band is: 18 92 1 + Current sample, line, band is: 18 93 1 + Current sample, line, band is: 18 94 1 + Current sample, line, band is: 18 95 1 + Current sample, line, band is: 18 96 1 + Current sample, line, band is: 18 97 1 + Current sample, line, band is: 18 98 1 + Current sample, line, band is: 18 99 1 + Current sample, line, band is: 18 100 1 + Current sample, line, band is: 18 101 1 + Current sample, line, band is: 18 102 1 + Current sample, line, band is: 18 103 1 + Current sample, line, band is: 18 104 1 + Current sample, line, band is: 18 105 1 + Current sample, line, band is: 18 106 1 + Current sample, line, band is: 18 107 1 + Current sample, line, band is: 18 108 1 + Current sample, line, band is: 18 109 1 + Current sample, line, band is: 18 110 1 + Current sample, line, band is: 18 111 1 + Current sample, line, band is: 18 112 1 + Current sample, line, band is: 18 113 1 + Current sample, line, band is: 18 114 1 + Current sample, line, band is: 18 115 1 + Current sample, line, band is: 18 116 1 + Current sample, line, band is: 18 117 1 + Current sample, line, band is: 18 118 1 + Current sample, line, band is: 18 119 1 + Current sample, line, band is: 18 120 1 + Current sample, line, band is: 18 121 1 + Current sample, line, band is: 18 122 1 + Current sample, line, band is: 18 123 1 + Current sample, line, band is: 18 124 1 + Current sample, line, band is: 18 125 1 + Current sample, line, band is: 18 126 1 + Current sample, line, band is: 19 1 1 + Current sample, line, band is: 19 2 1 + Current sample, line, band is: 19 3 1 + Current sample, line, band is: 19 4 1 + Current sample, line, band is: 19 5 1 + Current sample, line, band is: 19 6 1 + Current sample, line, band is: 19 7 1 + Current sample, line, band is: 19 8 1 + Current sample, line, band is: 19 9 1 + Current sample, line, band is: 19 10 1 + Current sample, line, band is: 19 11 1 + Current sample, line, band is: 19 12 1 + Current sample, line, band is: 19 13 1 + Current sample, line, band is: 19 14 1 + Current sample, line, band is: 19 15 1 + Current sample, line, band is: 19 16 1 + Current sample, line, band is: 19 17 1 + Current sample, line, band is: 19 18 1 + Current sample, line, band is: 19 19 1 + Current sample, line, band is: 19 20 1 + Current sample, line, band is: 19 21 1 + Current sample, line, band is: 19 22 1 + Current sample, line, band is: 19 23 1 + Current sample, line, band is: 19 24 1 + Current sample, line, band is: 19 25 1 + Current sample, line, band is: 19 26 1 + Current sample, line, band is: 19 27 1 + Current sample, line, band is: 19 28 1 + Current sample, line, band is: 19 29 1 + Current sample, line, band is: 19 30 1 + Current sample, line, band is: 19 31 1 + Current sample, line, band is: 19 32 1 + Current sample, line, band is: 19 33 1 + Current sample, line, band is: 19 34 1 + Current sample, line, band is: 19 35 1 + Current sample, line, band is: 19 36 1 + Current sample, line, band is: 19 37 1 + Current sample, line, band is: 19 38 1 + Current sample, line, band is: 19 39 1 + Current sample, line, band is: 19 40 1 + Current sample, line, band is: 19 41 1 + Current sample, line, band is: 19 42 1 + Current sample, line, band is: 19 43 1 + Current sample, line, band is: 19 44 1 + Current sample, line, band is: 19 45 1 + Current sample, line, band is: 19 46 1 + Current sample, line, band is: 19 47 1 + Current sample, line, band is: 19 48 1 + Current sample, line, band is: 19 49 1 + Current sample, line, band is: 19 50 1 + Current sample, line, band is: 19 51 1 + Current sample, line, band is: 19 52 1 + Current sample, line, band is: 19 53 1 + Current sample, line, band is: 19 54 1 + Current sample, line, band is: 19 55 1 + Current sample, line, band is: 19 56 1 + Current sample, line, band is: 19 57 1 + Current sample, line, band is: 19 58 1 + Current sample, line, band is: 19 59 1 + Current sample, line, band is: 19 60 1 + Current sample, line, band is: 19 61 1 + Current sample, line, band is: 19 62 1 + Current sample, line, band is: 19 63 1 + Current sample, line, band is: 19 64 1 + Current sample, line, band is: 19 65 1 + Current sample, line, band is: 19 66 1 + Current sample, line, band is: 19 67 1 + Current sample, line, band is: 19 68 1 + Current sample, line, band is: 19 69 1 + Current sample, line, band is: 19 70 1 + Current sample, line, band is: 19 71 1 + Current sample, line, band is: 19 72 1 + Current sample, line, band is: 19 73 1 + Current sample, line, band is: 19 74 1 + Current sample, line, band is: 19 75 1 + Current sample, line, band is: 19 76 1 + Current sample, line, band is: 19 77 1 + Current sample, line, band is: 19 78 1 + Current sample, line, band is: 19 79 1 + Current sample, line, band is: 19 80 1 + Current sample, line, band is: 19 81 1 + Current sample, line, band is: 19 82 1 + Current sample, line, band is: 19 83 1 + Current sample, line, band is: 19 84 1 + Current sample, line, band is: 19 85 1 + Current sample, line, band is: 19 86 1 + Current sample, line, band is: 19 87 1 + Current sample, line, band is: 19 88 1 + Current sample, line, band is: 19 89 1 + Current sample, line, band is: 19 90 1 + Current sample, line, band is: 19 91 1 + Current sample, line, band is: 19 92 1 + Current sample, line, band is: 19 93 1 + Current sample, line, band is: 19 94 1 + Current sample, line, band is: 19 95 1 + Current sample, line, band is: 19 96 1 + Current sample, line, band is: 19 97 1 + Current sample, line, band is: 19 98 1 + Current sample, line, band is: 19 99 1 + Current sample, line, band is: 19 100 1 + Current sample, line, band is: 19 101 1 + Current sample, line, band is: 19 102 1 + Current sample, line, band is: 19 103 1 + Current sample, line, band is: 19 104 1 + Current sample, line, band is: 19 105 1 + Current sample, line, band is: 19 106 1 + Current sample, line, band is: 19 107 1 + Current sample, line, band is: 19 108 1 + Current sample, line, band is: 19 109 1 + Current sample, line, band is: 19 110 1 + Current sample, line, band is: 19 111 1 + Current sample, line, band is: 19 112 1 + Current sample, line, band is: 19 113 1 + Current sample, line, band is: 19 114 1 + Current sample, line, band is: 19 115 1 + Current sample, line, band is: 19 116 1 + Current sample, line, band is: 19 117 1 + Current sample, line, band is: 19 118 1 + Current sample, line, band is: 19 119 1 + Current sample, line, band is: 19 120 1 + Current sample, line, band is: 19 121 1 + Current sample, line, band is: 19 122 1 + Current sample, line, band is: 19 123 1 + Current sample, line, band is: 19 124 1 + Current sample, line, band is: 19 125 1 + Current sample, line, band is: 19 126 1 + Current sample, line, band is: 20 1 1 + Current sample, line, band is: 20 2 1 + Current sample, line, band is: 20 3 1 + Current sample, line, band is: 20 4 1 + Current sample, line, band is: 20 5 1 + Current sample, line, band is: 20 6 1 + Current sample, line, band is: 20 7 1 + Current sample, line, band is: 20 8 1 + Current sample, line, band is: 20 9 1 + Current sample, line, band is: 20 10 1 + Current sample, line, band is: 20 11 1 + Current sample, line, band is: 20 12 1 + Current sample, line, band is: 20 13 1 + Current sample, line, band is: 20 14 1 + Current sample, line, band is: 20 15 1 + Current sample, line, band is: 20 16 1 + Current sample, line, band is: 20 17 1 + Current sample, line, band is: 20 18 1 + Current sample, line, band is: 20 19 1 + Current sample, line, band is: 20 20 1 + Current sample, line, band is: 20 21 1 + Current sample, line, band is: 20 22 1 + Current sample, line, band is: 20 23 1 + Current sample, line, band is: 20 24 1 + Current sample, line, band is: 20 25 1 + Current sample, line, band is: 20 26 1 + Current sample, line, band is: 20 27 1 + Current sample, line, band is: 20 28 1 + Current sample, line, band is: 20 29 1 + Current sample, line, band is: 20 30 1 + Current sample, line, band is: 20 31 1 + Current sample, line, band is: 20 32 1 + Current sample, line, band is: 20 33 1 + Current sample, line, band is: 20 34 1 + Current sample, line, band is: 20 35 1 + Current sample, line, band is: 20 36 1 + Current sample, line, band is: 20 37 1 + Current sample, line, band is: 20 38 1 + Current sample, line, band is: 20 39 1 + Current sample, line, band is: 20 40 1 + Current sample, line, band is: 20 41 1 + Current sample, line, band is: 20 42 1 + Current sample, line, band is: 20 43 1 + Current sample, line, band is: 20 44 1 + Current sample, line, band is: 20 45 1 + Current sample, line, band is: 20 46 1 + Current sample, line, band is: 20 47 1 + Current sample, line, band is: 20 48 1 + Current sample, line, band is: 20 49 1 + Current sample, line, band is: 20 50 1 + Current sample, line, band is: 20 51 1 + Current sample, line, band is: 20 52 1 + Current sample, line, band is: 20 53 1 + Current sample, line, band is: 20 54 1 + Current sample, line, band is: 20 55 1 + Current sample, line, band is: 20 56 1 + Current sample, line, band is: 20 57 1 + Current sample, line, band is: 20 58 1 + Current sample, line, band is: 20 59 1 + Current sample, line, band is: 20 60 1 + Current sample, line, band is: 20 61 1 + Current sample, line, band is: 20 62 1 + Current sample, line, band is: 20 63 1 + Current sample, line, band is: 20 64 1 + Current sample, line, band is: 20 65 1 + Current sample, line, band is: 20 66 1 + Current sample, line, band is: 20 67 1 + Current sample, line, band is: 20 68 1 + Current sample, line, band is: 20 69 1 + Current sample, line, band is: 20 70 1 + Current sample, line, band is: 20 71 1 + Current sample, line, band is: 20 72 1 + Current sample, line, band is: 20 73 1 + Current sample, line, band is: 20 74 1 + Current sample, line, band is: 20 75 1 + Current sample, line, band is: 20 76 1 + Current sample, line, band is: 20 77 1 + Current sample, line, band is: 20 78 1 + Current sample, line, band is: 20 79 1 + Current sample, line, band is: 20 80 1 + Current sample, line, band is: 20 81 1 + Current sample, line, band is: 20 82 1 + Current sample, line, band is: 20 83 1 + Current sample, line, band is: 20 84 1 + Current sample, line, band is: 20 85 1 + Current sample, line, band is: 20 86 1 + Current sample, line, band is: 20 87 1 + Current sample, line, band is: 20 88 1 + Current sample, line, band is: 20 89 1 + Current sample, line, band is: 20 90 1 + Current sample, line, band is: 20 91 1 + Current sample, line, band is: 20 92 1 + Current sample, line, band is: 20 93 1 + Current sample, line, band is: 20 94 1 + Current sample, line, band is: 20 95 1 + Current sample, line, band is: 20 96 1 + Current sample, line, band is: 20 97 1 + Current sample, line, band is: 20 98 1 + Current sample, line, band is: 20 99 1 + Current sample, line, band is: 20 100 1 + Current sample, line, band is: 20 101 1 + Current sample, line, band is: 20 102 1 + Current sample, line, band is: 20 103 1 + Current sample, line, band is: 20 104 1 + Current sample, line, band is: 20 105 1 + Current sample, line, band is: 20 106 1 + Current sample, line, band is: 20 107 1 + Current sample, line, band is: 20 108 1 + Current sample, line, band is: 20 109 1 + Current sample, line, band is: 20 110 1 + Current sample, line, band is: 20 111 1 + Current sample, line, band is: 20 112 1 + Current sample, line, band is: 20 113 1 + Current sample, line, band is: 20 114 1 + Current sample, line, band is: 20 115 1 + Current sample, line, band is: 20 116 1 + Current sample, line, band is: 20 117 1 + Current sample, line, band is: 20 118 1 + Current sample, line, band is: 20 119 1 + Current sample, line, band is: 20 120 1 + Current sample, line, band is: 20 121 1 + Current sample, line, band is: 20 122 1 + Current sample, line, band is: 20 123 1 + Current sample, line, band is: 20 124 1 + Current sample, line, band is: 20 125 1 + Current sample, line, band is: 20 126 1 + Current sample, line, band is: 21 1 1 + Current sample, line, band is: 21 2 1 + Current sample, line, band is: 21 3 1 + Current sample, line, band is: 21 4 1 + Current sample, line, band is: 21 5 1 + Current sample, line, band is: 21 6 1 + Current sample, line, band is: 21 7 1 + Current sample, line, band is: 21 8 1 + Current sample, line, band is: 21 9 1 + Current sample, line, band is: 21 10 1 + Current sample, line, band is: 21 11 1 + Current sample, line, band is: 21 12 1 + Current sample, line, band is: 21 13 1 + Current sample, line, band is: 21 14 1 + Current sample, line, band is: 21 15 1 + Current sample, line, band is: 21 16 1 + Current sample, line, band is: 21 17 1 + Current sample, line, band is: 21 18 1 + Current sample, line, band is: 21 19 1 + Current sample, line, band is: 21 20 1 + Current sample, line, band is: 21 21 1 + Current sample, line, band is: 21 22 1 + Current sample, line, band is: 21 23 1 + Current sample, line, band is: 21 24 1 + Current sample, line, band is: 21 25 1 + Current sample, line, band is: 21 26 1 + Current sample, line, band is: 21 27 1 + Current sample, line, band is: 21 28 1 + Current sample, line, band is: 21 29 1 + Current sample, line, band is: 21 30 1 + Current sample, line, band is: 21 31 1 + Current sample, line, band is: 21 32 1 + Current sample, line, band is: 21 33 1 + Current sample, line, band is: 21 34 1 + Current sample, line, band is: 21 35 1 + Current sample, line, band is: 21 36 1 + Current sample, line, band is: 21 37 1 + Current sample, line, band is: 21 38 1 + Current sample, line, band is: 21 39 1 + Current sample, line, band is: 21 40 1 + Current sample, line, band is: 21 41 1 + Current sample, line, band is: 21 42 1 + Current sample, line, band is: 21 43 1 + Current sample, line, band is: 21 44 1 + Current sample, line, band is: 21 45 1 + Current sample, line, band is: 21 46 1 + Current sample, line, band is: 21 47 1 + Current sample, line, band is: 21 48 1 + Current sample, line, band is: 21 49 1 + Current sample, line, band is: 21 50 1 + Current sample, line, band is: 21 51 1 + Current sample, line, band is: 21 52 1 + Current sample, line, band is: 21 53 1 + Current sample, line, band is: 21 54 1 + Current sample, line, band is: 21 55 1 + Current sample, line, band is: 21 56 1 + Current sample, line, band is: 21 57 1 + Current sample, line, band is: 21 58 1 + Current sample, line, band is: 21 59 1 + Current sample, line, band is: 21 60 1 + Current sample, line, band is: 21 61 1 + Current sample, line, band is: 21 62 1 + Current sample, line, band is: 21 63 1 + Current sample, line, band is: 21 64 1 + Current sample, line, band is: 21 65 1 + Current sample, line, band is: 21 66 1 + Current sample, line, band is: 21 67 1 + Current sample, line, band is: 21 68 1 + Current sample, line, band is: 21 69 1 + Current sample, line, band is: 21 70 1 + Current sample, line, band is: 21 71 1 + Current sample, line, band is: 21 72 1 + Current sample, line, band is: 21 73 1 + Current sample, line, band is: 21 74 1 + Current sample, line, band is: 21 75 1 + Current sample, line, band is: 21 76 1 + Current sample, line, band is: 21 77 1 + Current sample, line, band is: 21 78 1 + Current sample, line, band is: 21 79 1 + Current sample, line, band is: 21 80 1 + Current sample, line, band is: 21 81 1 + Current sample, line, band is: 21 82 1 + Current sample, line, band is: 21 83 1 + Current sample, line, band is: 21 84 1 + Current sample, line, band is: 21 85 1 + Current sample, line, band is: 21 86 1 + Current sample, line, band is: 21 87 1 + Current sample, line, band is: 21 88 1 + Current sample, line, band is: 21 89 1 + Current sample, line, band is: 21 90 1 + Current sample, line, band is: 21 91 1 + Current sample, line, band is: 21 92 1 + Current sample, line, band is: 21 93 1 + Current sample, line, band is: 21 94 1 + Current sample, line, band is: 21 95 1 + Current sample, line, band is: 21 96 1 + Current sample, line, band is: 21 97 1 + Current sample, line, band is: 21 98 1 + Current sample, line, band is: 21 99 1 + Current sample, line, band is: 21 100 1 + Current sample, line, band is: 21 101 1 + Current sample, line, band is: 21 102 1 + Current sample, line, band is: 21 103 1 + Current sample, line, band is: 21 104 1 + Current sample, line, band is: 21 105 1 + Current sample, line, band is: 21 106 1 + Current sample, line, band is: 21 107 1 + Current sample, line, band is: 21 108 1 + Current sample, line, band is: 21 109 1 + Current sample, line, band is: 21 110 1 + Current sample, line, band is: 21 111 1 + Current sample, line, band is: 21 112 1 + Current sample, line, band is: 21 113 1 + Current sample, line, band is: 21 114 1 + Current sample, line, band is: 21 115 1 + Current sample, line, band is: 21 116 1 + Current sample, line, band is: 21 117 1 + Current sample, line, band is: 21 118 1 + Current sample, line, band is: 21 119 1 + Current sample, line, band is: 21 120 1 + Current sample, line, band is: 21 121 1 + Current sample, line, band is: 21 122 1 + Current sample, line, band is: 21 123 1 + Current sample, line, band is: 21 124 1 + Current sample, line, band is: 21 125 1 + Current sample, line, band is: 21 126 1 + Current sample, line, band is: 22 1 1 + Current sample, line, band is: 22 2 1 + Current sample, line, band is: 22 3 1 + Current sample, line, band is: 22 4 1 + Current sample, line, band is: 22 5 1 + Current sample, line, band is: 22 6 1 + Current sample, line, band is: 22 7 1 + Current sample, line, band is: 22 8 1 + Current sample, line, band is: 22 9 1 + Current sample, line, band is: 22 10 1 + Current sample, line, band is: 22 11 1 + Current sample, line, band is: 22 12 1 + Current sample, line, band is: 22 13 1 + Current sample, line, band is: 22 14 1 + Current sample, line, band is: 22 15 1 + Current sample, line, band is: 22 16 1 + Current sample, line, band is: 22 17 1 + Current sample, line, band is: 22 18 1 + Current sample, line, band is: 22 19 1 + Current sample, line, band is: 22 20 1 + Current sample, line, band is: 22 21 1 + Current sample, line, band is: 22 22 1 + Current sample, line, band is: 22 23 1 + Current sample, line, band is: 22 24 1 + Current sample, line, band is: 22 25 1 + Current sample, line, band is: 22 26 1 + Current sample, line, band is: 22 27 1 + Current sample, line, band is: 22 28 1 + Current sample, line, band is: 22 29 1 + Current sample, line, band is: 22 30 1 + Current sample, line, band is: 22 31 1 + Current sample, line, band is: 22 32 1 + Current sample, line, band is: 22 33 1 + Current sample, line, band is: 22 34 1 + Current sample, line, band is: 22 35 1 + Current sample, line, band is: 22 36 1 + Current sample, line, band is: 22 37 1 + Current sample, line, band is: 22 38 1 + Current sample, line, band is: 22 39 1 + Current sample, line, band is: 22 40 1 + Current sample, line, band is: 22 41 1 + Current sample, line, band is: 22 42 1 + Current sample, line, band is: 22 43 1 + Current sample, line, band is: 22 44 1 + Current sample, line, band is: 22 45 1 + Current sample, line, band is: 22 46 1 + Current sample, line, band is: 22 47 1 + Current sample, line, band is: 22 48 1 + Current sample, line, band is: 22 49 1 + Current sample, line, band is: 22 50 1 + Current sample, line, band is: 22 51 1 + Current sample, line, band is: 22 52 1 + Current sample, line, band is: 22 53 1 + Current sample, line, band is: 22 54 1 + Current sample, line, band is: 22 55 1 + Current sample, line, band is: 22 56 1 + Current sample, line, band is: 22 57 1 + Current sample, line, band is: 22 58 1 + Current sample, line, band is: 22 59 1 + Current sample, line, band is: 22 60 1 + Current sample, line, band is: 22 61 1 + Current sample, line, band is: 22 62 1 + Current sample, line, band is: 22 63 1 + Current sample, line, band is: 22 64 1 + Current sample, line, band is: 22 65 1 + Current sample, line, band is: 22 66 1 + Current sample, line, band is: 22 67 1 + Current sample, line, band is: 22 68 1 + Current sample, line, band is: 22 69 1 + Current sample, line, band is: 22 70 1 + Current sample, line, band is: 22 71 1 + Current sample, line, band is: 22 72 1 + Current sample, line, band is: 22 73 1 + Current sample, line, band is: 22 74 1 + Current sample, line, band is: 22 75 1 + Current sample, line, band is: 22 76 1 + Current sample, line, band is: 22 77 1 + Current sample, line, band is: 22 78 1 + Current sample, line, band is: 22 79 1 + Current sample, line, band is: 22 80 1 + Current sample, line, band is: 22 81 1 + Current sample, line, band is: 22 82 1 + Current sample, line, band is: 22 83 1 + Current sample, line, band is: 22 84 1 + Current sample, line, band is: 22 85 1 + Current sample, line, band is: 22 86 1 + Current sample, line, band is: 22 87 1 + Current sample, line, band is: 22 88 1 + Current sample, line, band is: 22 89 1 + Current sample, line, band is: 22 90 1 + Current sample, line, band is: 22 91 1 + Current sample, line, band is: 22 92 1 + Current sample, line, band is: 22 93 1 + Current sample, line, band is: 22 94 1 + Current sample, line, band is: 22 95 1 + Current sample, line, band is: 22 96 1 + Current sample, line, band is: 22 97 1 + Current sample, line, band is: 22 98 1 + Current sample, line, band is: 22 99 1 + Current sample, line, band is: 22 100 1 + Current sample, line, band is: 22 101 1 + Current sample, line, band is: 22 102 1 + Current sample, line, band is: 22 103 1 + Current sample, line, band is: 22 104 1 + Current sample, line, band is: 22 105 1 + Current sample, line, band is: 22 106 1 + Current sample, line, band is: 22 107 1 + Current sample, line, band is: 22 108 1 + Current sample, line, band is: 22 109 1 + Current sample, line, band is: 22 110 1 + Current sample, line, band is: 22 111 1 + Current sample, line, band is: 22 112 1 + Current sample, line, band is: 22 113 1 + Current sample, line, band is: 22 114 1 + Current sample, line, band is: 22 115 1 + Current sample, line, band is: 22 116 1 + Current sample, line, band is: 22 117 1 + Current sample, line, band is: 22 118 1 + Current sample, line, band is: 22 119 1 + Current sample, line, band is: 22 120 1 + Current sample, line, band is: 22 121 1 + Current sample, line, band is: 22 122 1 + Current sample, line, band is: 22 123 1 + Current sample, line, band is: 22 124 1 + Current sample, line, band is: 22 125 1 + Current sample, line, band is: 22 126 1 + Current sample, line, band is: 23 1 1 + Current sample, line, band is: 23 2 1 + Current sample, line, band is: 23 3 1 + Current sample, line, band is: 23 4 1 + Current sample, line, band is: 23 5 1 + Current sample, line, band is: 23 6 1 + Current sample, line, band is: 23 7 1 + Current sample, line, band is: 23 8 1 + Current sample, line, band is: 23 9 1 + Current sample, line, band is: 23 10 1 + Current sample, line, band is: 23 11 1 + Current sample, line, band is: 23 12 1 + Current sample, line, band is: 23 13 1 + Current sample, line, band is: 23 14 1 + Current sample, line, band is: 23 15 1 + Current sample, line, band is: 23 16 1 + Current sample, line, band is: 23 17 1 + Current sample, line, band is: 23 18 1 + Current sample, line, band is: 23 19 1 + Current sample, line, band is: 23 20 1 + Current sample, line, band is: 23 21 1 + Current sample, line, band is: 23 22 1 + Current sample, line, band is: 23 23 1 + Current sample, line, band is: 23 24 1 + Current sample, line, band is: 23 25 1 + Current sample, line, band is: 23 26 1 + Current sample, line, band is: 23 27 1 + Current sample, line, band is: 23 28 1 + Current sample, line, band is: 23 29 1 + Current sample, line, band is: 23 30 1 + Current sample, line, band is: 23 31 1 + Current sample, line, band is: 23 32 1 + Current sample, line, band is: 23 33 1 + Current sample, line, band is: 23 34 1 + Current sample, line, band is: 23 35 1 + Current sample, line, band is: 23 36 1 + Current sample, line, band is: 23 37 1 + Current sample, line, band is: 23 38 1 + Current sample, line, band is: 23 39 1 + Current sample, line, band is: 23 40 1 + Current sample, line, band is: 23 41 1 + Current sample, line, band is: 23 42 1 + Current sample, line, band is: 23 43 1 + Current sample, line, band is: 23 44 1 + Current sample, line, band is: 23 45 1 + Current sample, line, band is: 23 46 1 + Current sample, line, band is: 23 47 1 + Current sample, line, band is: 23 48 1 + Current sample, line, band is: 23 49 1 + Current sample, line, band is: 23 50 1 + Current sample, line, band is: 23 51 1 + Current sample, line, band is: 23 52 1 + Current sample, line, band is: 23 53 1 + Current sample, line, band is: 23 54 1 + Current sample, line, band is: 23 55 1 + Current sample, line, band is: 23 56 1 + Current sample, line, band is: 23 57 1 + Current sample, line, band is: 23 58 1 + Current sample, line, band is: 23 59 1 + Current sample, line, band is: 23 60 1 + Current sample, line, band is: 23 61 1 + Current sample, line, band is: 23 62 1 + Current sample, line, band is: 23 63 1 + Current sample, line, band is: 23 64 1 + Current sample, line, band is: 23 65 1 + Current sample, line, band is: 23 66 1 + Current sample, line, band is: 23 67 1 + Current sample, line, band is: 23 68 1 + Current sample, line, band is: 23 69 1 + Current sample, line, band is: 23 70 1 + Current sample, line, band is: 23 71 1 + Current sample, line, band is: 23 72 1 + Current sample, line, band is: 23 73 1 + Current sample, line, band is: 23 74 1 + Current sample, line, band is: 23 75 1 + Current sample, line, band is: 23 76 1 + Current sample, line, band is: 23 77 1 + Current sample, line, band is: 23 78 1 + Current sample, line, band is: 23 79 1 + Current sample, line, band is: 23 80 1 + Current sample, line, band is: 23 81 1 + Current sample, line, band is: 23 82 1 + Current sample, line, band is: 23 83 1 + Current sample, line, band is: 23 84 1 + Current sample, line, band is: 23 85 1 + Current sample, line, band is: 23 86 1 + Current sample, line, band is: 23 87 1 + Current sample, line, band is: 23 88 1 + Current sample, line, band is: 23 89 1 + Current sample, line, band is: 23 90 1 + Current sample, line, band is: 23 91 1 + Current sample, line, band is: 23 92 1 + Current sample, line, band is: 23 93 1 + Current sample, line, band is: 23 94 1 + Current sample, line, band is: 23 95 1 + Current sample, line, band is: 23 96 1 + Current sample, line, band is: 23 97 1 + Current sample, line, band is: 23 98 1 + Current sample, line, band is: 23 99 1 + Current sample, line, band is: 23 100 1 + Current sample, line, band is: 23 101 1 + Current sample, line, band is: 23 102 1 + Current sample, line, band is: 23 103 1 + Current sample, line, band is: 23 104 1 + Current sample, line, band is: 23 105 1 + Current sample, line, band is: 23 106 1 + Current sample, line, band is: 23 107 1 + Current sample, line, band is: 23 108 1 + Current sample, line, band is: 23 109 1 + Current sample, line, band is: 23 110 1 + Current sample, line, band is: 23 111 1 + Current sample, line, band is: 23 112 1 + Current sample, line, band is: 23 113 1 + Current sample, line, band is: 23 114 1 + Current sample, line, band is: 23 115 1 + Current sample, line, band is: 23 116 1 + Current sample, line, band is: 23 117 1 + Current sample, line, band is: 23 118 1 + Current sample, line, band is: 23 119 1 + Current sample, line, band is: 23 120 1 + Current sample, line, band is: 23 121 1 + Current sample, line, band is: 23 122 1 + Current sample, line, band is: 23 123 1 + Current sample, line, band is: 23 124 1 + Current sample, line, band is: 23 125 1 + Current sample, line, band is: 23 126 1 + Current sample, line, band is: 24 1 1 + Current sample, line, band is: 24 2 1 + Current sample, line, band is: 24 3 1 + Current sample, line, band is: 24 4 1 + Current sample, line, band is: 24 5 1 + Current sample, line, band is: 24 6 1 + Current sample, line, band is: 24 7 1 + Current sample, line, band is: 24 8 1 + Current sample, line, band is: 24 9 1 + Current sample, line, band is: 24 10 1 + Current sample, line, band is: 24 11 1 + Current sample, line, band is: 24 12 1 + Current sample, line, band is: 24 13 1 + Current sample, line, band is: 24 14 1 + Current sample, line, band is: 24 15 1 + Current sample, line, band is: 24 16 1 + Current sample, line, band is: 24 17 1 + Current sample, line, band is: 24 18 1 + Current sample, line, band is: 24 19 1 + Current sample, line, band is: 24 20 1 + Current sample, line, band is: 24 21 1 + Current sample, line, band is: 24 22 1 + Current sample, line, band is: 24 23 1 + Current sample, line, band is: 24 24 1 + Current sample, line, band is: 24 25 1 + Current sample, line, band is: 24 26 1 + Current sample, line, band is: 24 27 1 + Current sample, line, band is: 24 28 1 + Current sample, line, band is: 24 29 1 + Current sample, line, band is: 24 30 1 + Current sample, line, band is: 24 31 1 + Current sample, line, band is: 24 32 1 + Current sample, line, band is: 24 33 1 + Current sample, line, band is: 24 34 1 + Current sample, line, band is: 24 35 1 + Current sample, line, band is: 24 36 1 + Current sample, line, band is: 24 37 1 + Current sample, line, band is: 24 38 1 + Current sample, line, band is: 24 39 1 + Current sample, line, band is: 24 40 1 + Current sample, line, band is: 24 41 1 + Current sample, line, band is: 24 42 1 + Current sample, line, band is: 24 43 1 + Current sample, line, band is: 24 44 1 + Current sample, line, band is: 24 45 1 + Current sample, line, band is: 24 46 1 + Current sample, line, band is: 24 47 1 + Current sample, line, band is: 24 48 1 + Current sample, line, band is: 24 49 1 + Current sample, line, band is: 24 50 1 + Current sample, line, band is: 24 51 1 + Current sample, line, band is: 24 52 1 + Current sample, line, band is: 24 53 1 + Current sample, line, band is: 24 54 1 + Current sample, line, band is: 24 55 1 + Current sample, line, band is: 24 56 1 + Current sample, line, band is: 24 57 1 + Current sample, line, band is: 24 58 1 + Current sample, line, band is: 24 59 1 + Current sample, line, band is: 24 60 1 + Current sample, line, band is: 24 61 1 + Current sample, line, band is: 24 62 1 + Current sample, line, band is: 24 63 1 + Current sample, line, band is: 24 64 1 + Current sample, line, band is: 24 65 1 + Current sample, line, band is: 24 66 1 + Current sample, line, band is: 24 67 1 + Current sample, line, band is: 24 68 1 + Current sample, line, band is: 24 69 1 + Current sample, line, band is: 24 70 1 + Current sample, line, band is: 24 71 1 + Current sample, line, band is: 24 72 1 + Current sample, line, band is: 24 73 1 + Current sample, line, band is: 24 74 1 + Current sample, line, band is: 24 75 1 + Current sample, line, band is: 24 76 1 + Current sample, line, band is: 24 77 1 + Current sample, line, band is: 24 78 1 + Current sample, line, band is: 24 79 1 + Current sample, line, band is: 24 80 1 + Current sample, line, band is: 24 81 1 + Current sample, line, band is: 24 82 1 + Current sample, line, band is: 24 83 1 + Current sample, line, band is: 24 84 1 + Current sample, line, band is: 24 85 1 + Current sample, line, band is: 24 86 1 + Current sample, line, band is: 24 87 1 + Current sample, line, band is: 24 88 1 + Current sample, line, band is: 24 89 1 + Current sample, line, band is: 24 90 1 + Current sample, line, band is: 24 91 1 + Current sample, line, band is: 24 92 1 + Current sample, line, band is: 24 93 1 + Current sample, line, band is: 24 94 1 + Current sample, line, band is: 24 95 1 + Current sample, line, band is: 24 96 1 + Current sample, line, band is: 24 97 1 + Current sample, line, band is: 24 98 1 + Current sample, line, band is: 24 99 1 + Current sample, line, band is: 24 100 1 + Current sample, line, band is: 24 101 1 + Current sample, line, band is: 24 102 1 + Current sample, line, band is: 24 103 1 + Current sample, line, band is: 24 104 1 + Current sample, line, band is: 24 105 1 + Current sample, line, band is: 24 106 1 + Current sample, line, band is: 24 107 1 + Current sample, line, band is: 24 108 1 + Current sample, line, band is: 24 109 1 + Current sample, line, band is: 24 110 1 + Current sample, line, band is: 24 111 1 + Current sample, line, band is: 24 112 1 + Current sample, line, band is: 24 113 1 + Current sample, line, band is: 24 114 1 + Current sample, line, band is: 24 115 1 + Current sample, line, band is: 24 116 1 + Current sample, line, band is: 24 117 1 + Current sample, line, band is: 24 118 1 + Current sample, line, band is: 24 119 1 + Current sample, line, band is: 24 120 1 + Current sample, line, band is: 24 121 1 + Current sample, line, band is: 24 122 1 + Current sample, line, band is: 24 123 1 + Current sample, line, band is: 24 124 1 + Current sample, line, band is: 24 125 1 + Current sample, line, band is: 24 126 1 + Current sample, line, band is: 25 1 1 + Current sample, line, band is: 25 2 1 + Current sample, line, band is: 25 3 1 + Current sample, line, band is: 25 4 1 + Current sample, line, band is: 25 5 1 + Current sample, line, band is: 25 6 1 + Current sample, line, band is: 25 7 1 + Current sample, line, band is: 25 8 1 + Current sample, line, band is: 25 9 1 + Current sample, line, band is: 25 10 1 + Current sample, line, band is: 25 11 1 + Current sample, line, band is: 25 12 1 + Current sample, line, band is: 25 13 1 + Current sample, line, band is: 25 14 1 + Current sample, line, band is: 25 15 1 + Current sample, line, band is: 25 16 1 + Current sample, line, band is: 25 17 1 + Current sample, line, band is: 25 18 1 + Current sample, line, band is: 25 19 1 + Current sample, line, band is: 25 20 1 + Current sample, line, band is: 25 21 1 + Current sample, line, band is: 25 22 1 + Current sample, line, band is: 25 23 1 + Current sample, line, band is: 25 24 1 + Current sample, line, band is: 25 25 1 + Current sample, line, band is: 25 26 1 + Current sample, line, band is: 25 27 1 + Current sample, line, band is: 25 28 1 + Current sample, line, band is: 25 29 1 + Current sample, line, band is: 25 30 1 + Current sample, line, band is: 25 31 1 + Current sample, line, band is: 25 32 1 + Current sample, line, band is: 25 33 1 + Current sample, line, band is: 25 34 1 + Current sample, line, band is: 25 35 1 + Current sample, line, band is: 25 36 1 + Current sample, line, band is: 25 37 1 + Current sample, line, band is: 25 38 1 + Current sample, line, band is: 25 39 1 + Current sample, line, band is: 25 40 1 + Current sample, line, band is: 25 41 1 + Current sample, line, band is: 25 42 1 + Current sample, line, band is: 25 43 1 + Current sample, line, band is: 25 44 1 + Current sample, line, band is: 25 45 1 + Current sample, line, band is: 25 46 1 + Current sample, line, band is: 25 47 1 + Current sample, line, band is: 25 48 1 + Current sample, line, band is: 25 49 1 + Current sample, line, band is: 25 50 1 + Current sample, line, band is: 25 51 1 + Current sample, line, band is: 25 52 1 + Current sample, line, band is: 25 53 1 + Current sample, line, band is: 25 54 1 + Current sample, line, band is: 25 55 1 + Current sample, line, band is: 25 56 1 + Current sample, line, band is: 25 57 1 + Current sample, line, band is: 25 58 1 + Current sample, line, band is: 25 59 1 + Current sample, line, band is: 25 60 1 + Current sample, line, band is: 25 61 1 + Current sample, line, band is: 25 62 1 + Current sample, line, band is: 25 63 1 + Current sample, line, band is: 25 64 1 + Current sample, line, band is: 25 65 1 + Current sample, line, band is: 25 66 1 + Current sample, line, band is: 25 67 1 + Current sample, line, band is: 25 68 1 + Current sample, line, band is: 25 69 1 + Current sample, line, band is: 25 70 1 + Current sample, line, band is: 25 71 1 + Current sample, line, band is: 25 72 1 + Current sample, line, band is: 25 73 1 + Current sample, line, band is: 25 74 1 + Current sample, line, band is: 25 75 1 + Current sample, line, band is: 25 76 1 + Current sample, line, band is: 25 77 1 + Current sample, line, band is: 25 78 1 + Current sample, line, band is: 25 79 1 + Current sample, line, band is: 25 80 1 + Current sample, line, band is: 25 81 1 + Current sample, line, band is: 25 82 1 + Current sample, line, band is: 25 83 1 + Current sample, line, band is: 25 84 1 + Current sample, line, band is: 25 85 1 + Current sample, line, band is: 25 86 1 + Current sample, line, band is: 25 87 1 + Current sample, line, band is: 25 88 1 + Current sample, line, band is: 25 89 1 + Current sample, line, band is: 25 90 1 + Current sample, line, band is: 25 91 1 + Current sample, line, band is: 25 92 1 + Current sample, line, band is: 25 93 1 + Current sample, line, band is: 25 94 1 + Current sample, line, band is: 25 95 1 + Current sample, line, band is: 25 96 1 + Current sample, line, band is: 25 97 1 + Current sample, line, band is: 25 98 1 + Current sample, line, band is: 25 99 1 + Current sample, line, band is: 25 100 1 + Current sample, line, band is: 25 101 1 + Current sample, line, band is: 25 102 1 + Current sample, line, band is: 25 103 1 + Current sample, line, band is: 25 104 1 + Current sample, line, band is: 25 105 1 + Current sample, line, band is: 25 106 1 + Current sample, line, band is: 25 107 1 + Current sample, line, band is: 25 108 1 + Current sample, line, band is: 25 109 1 + Current sample, line, band is: 25 110 1 + Current sample, line, band is: 25 111 1 + Current sample, line, band is: 25 112 1 + Current sample, line, band is: 25 113 1 + Current sample, line, band is: 25 114 1 + Current sample, line, band is: 25 115 1 + Current sample, line, band is: 25 116 1 + Current sample, line, band is: 25 117 1 + Current sample, line, band is: 25 118 1 + Current sample, line, band is: 25 119 1 + Current sample, line, band is: 25 120 1 + Current sample, line, band is: 25 121 1 + Current sample, line, band is: 25 122 1 + Current sample, line, band is: 25 123 1 + Current sample, line, band is: 25 124 1 + Current sample, line, band is: 25 125 1 + Current sample, line, band is: 25 126 1 + Current sample, line, band is: 26 1 1 + Current sample, line, band is: 26 2 1 + Current sample, line, band is: 26 3 1 + Current sample, line, band is: 26 4 1 + Current sample, line, band is: 26 5 1 + Current sample, line, band is: 26 6 1 + Current sample, line, band is: 26 7 1 + Current sample, line, band is: 26 8 1 + Current sample, line, band is: 26 9 1 + Current sample, line, band is: 26 10 1 + Current sample, line, band is: 26 11 1 + Current sample, line, band is: 26 12 1 + Current sample, line, band is: 26 13 1 + Current sample, line, band is: 26 14 1 + Current sample, line, band is: 26 15 1 + Current sample, line, band is: 26 16 1 + Current sample, line, band is: 26 17 1 + Current sample, line, band is: 26 18 1 + Current sample, line, band is: 26 19 1 + Current sample, line, band is: 26 20 1 + Current sample, line, band is: 26 21 1 + Current sample, line, band is: 26 22 1 + Current sample, line, band is: 26 23 1 + Current sample, line, band is: 26 24 1 + Current sample, line, band is: 26 25 1 + Current sample, line, band is: 26 26 1 + Current sample, line, band is: 26 27 1 + Current sample, line, band is: 26 28 1 + Current sample, line, band is: 26 29 1 + Current sample, line, band is: 26 30 1 + Current sample, line, band is: 26 31 1 + Current sample, line, band is: 26 32 1 + Current sample, line, band is: 26 33 1 + Current sample, line, band is: 26 34 1 + Current sample, line, band is: 26 35 1 + Current sample, line, band is: 26 36 1 + Current sample, line, band is: 26 37 1 + Current sample, line, band is: 26 38 1 + Current sample, line, band is: 26 39 1 + Current sample, line, band is: 26 40 1 + Current sample, line, band is: 26 41 1 + Current sample, line, band is: 26 42 1 + Current sample, line, band is: 26 43 1 + Current sample, line, band is: 26 44 1 + Current sample, line, band is: 26 45 1 + Current sample, line, band is: 26 46 1 + Current sample, line, band is: 26 47 1 + Current sample, line, band is: 26 48 1 + Current sample, line, band is: 26 49 1 + Current sample, line, band is: 26 50 1 + Current sample, line, band is: 26 51 1 + Current sample, line, band is: 26 52 1 + Current sample, line, band is: 26 53 1 + Current sample, line, band is: 26 54 1 + Current sample, line, band is: 26 55 1 + Current sample, line, band is: 26 56 1 + Current sample, line, band is: 26 57 1 + Current sample, line, band is: 26 58 1 + Current sample, line, band is: 26 59 1 + Current sample, line, band is: 26 60 1 + Current sample, line, band is: 26 61 1 + Current sample, line, band is: 26 62 1 + Current sample, line, band is: 26 63 1 + Current sample, line, band is: 26 64 1 + Current sample, line, band is: 26 65 1 + Current sample, line, band is: 26 66 1 + Current sample, line, band is: 26 67 1 + Current sample, line, band is: 26 68 1 + Current sample, line, band is: 26 69 1 + Current sample, line, band is: 26 70 1 + Current sample, line, band is: 26 71 1 + Current sample, line, band is: 26 72 1 + Current sample, line, band is: 26 73 1 + Current sample, line, band is: 26 74 1 + Current sample, line, band is: 26 75 1 + Current sample, line, band is: 26 76 1 + Current sample, line, band is: 26 77 1 + Current sample, line, band is: 26 78 1 + Current sample, line, band is: 26 79 1 + Current sample, line, band is: 26 80 1 + Current sample, line, band is: 26 81 1 + Current sample, line, band is: 26 82 1 + Current sample, line, band is: 26 83 1 + Current sample, line, band is: 26 84 1 + Current sample, line, band is: 26 85 1 + Current sample, line, band is: 26 86 1 + Current sample, line, band is: 26 87 1 + Current sample, line, band is: 26 88 1 + Current sample, line, band is: 26 89 1 + Current sample, line, band is: 26 90 1 + Current sample, line, band is: 26 91 1 + Current sample, line, band is: 26 92 1 + Current sample, line, band is: 26 93 1 + Current sample, line, band is: 26 94 1 + Current sample, line, band is: 26 95 1 + Current sample, line, band is: 26 96 1 + Current sample, line, band is: 26 97 1 + Current sample, line, band is: 26 98 1 + Current sample, line, band is: 26 99 1 + Current sample, line, band is: 26 100 1 + Current sample, line, band is: 26 101 1 + Current sample, line, band is: 26 102 1 + Current sample, line, band is: 26 103 1 + Current sample, line, band is: 26 104 1 + Current sample, line, band is: 26 105 1 + Current sample, line, band is: 26 106 1 + Current sample, line, band is: 26 107 1 + Current sample, line, band is: 26 108 1 + Current sample, line, band is: 26 109 1 + Current sample, line, band is: 26 110 1 + Current sample, line, band is: 26 111 1 + Current sample, line, band is: 26 112 1 + Current sample, line, band is: 26 113 1 + Current sample, line, band is: 26 114 1 + Current sample, line, band is: 26 115 1 + Current sample, line, band is: 26 116 1 + Current sample, line, band is: 26 117 1 + Current sample, line, band is: 26 118 1 + Current sample, line, band is: 26 119 1 + Current sample, line, band is: 26 120 1 + Current sample, line, band is: 26 121 1 + Current sample, line, band is: 26 122 1 + Current sample, line, band is: 26 123 1 + Current sample, line, band is: 26 124 1 + Current sample, line, band is: 26 125 1 + Current sample, line, band is: 26 126 1 + Current sample, line, band is: 27 1 1 + Current sample, line, band is: 27 2 1 + Current sample, line, band is: 27 3 1 + Current sample, line, band is: 27 4 1 + Current sample, line, band is: 27 5 1 + Current sample, line, band is: 27 6 1 + Current sample, line, band is: 27 7 1 + Current sample, line, band is: 27 8 1 + Current sample, line, band is: 27 9 1 + Current sample, line, band is: 27 10 1 + Current sample, line, band is: 27 11 1 + Current sample, line, band is: 27 12 1 + Current sample, line, band is: 27 13 1 + Current sample, line, band is: 27 14 1 + Current sample, line, band is: 27 15 1 + Current sample, line, band is: 27 16 1 + Current sample, line, band is: 27 17 1 + Current sample, line, band is: 27 18 1 + Current sample, line, band is: 27 19 1 + Current sample, line, band is: 27 20 1 + Current sample, line, band is: 27 21 1 + Current sample, line, band is: 27 22 1 + Current sample, line, band is: 27 23 1 + Current sample, line, band is: 27 24 1 + Current sample, line, band is: 27 25 1 + Current sample, line, band is: 27 26 1 + Current sample, line, band is: 27 27 1 + Current sample, line, band is: 27 28 1 + Current sample, line, band is: 27 29 1 + Current sample, line, band is: 27 30 1 + Current sample, line, band is: 27 31 1 + Current sample, line, band is: 27 32 1 + Current sample, line, band is: 27 33 1 + Current sample, line, band is: 27 34 1 + Current sample, line, band is: 27 35 1 + Current sample, line, band is: 27 36 1 + Current sample, line, band is: 27 37 1 + Current sample, line, band is: 27 38 1 + Current sample, line, band is: 27 39 1 + Current sample, line, band is: 27 40 1 + Current sample, line, band is: 27 41 1 + Current sample, line, band is: 27 42 1 + Current sample, line, band is: 27 43 1 + Current sample, line, band is: 27 44 1 + Current sample, line, band is: 27 45 1 + Current sample, line, band is: 27 46 1 + Current sample, line, band is: 27 47 1 + Current sample, line, band is: 27 48 1 + Current sample, line, band is: 27 49 1 + Current sample, line, band is: 27 50 1 + Current sample, line, band is: 27 51 1 + Current sample, line, band is: 27 52 1 + Current sample, line, band is: 27 53 1 + Current sample, line, band is: 27 54 1 + Current sample, line, band is: 27 55 1 + Current sample, line, band is: 27 56 1 + Current sample, line, band is: 27 57 1 + Current sample, line, band is: 27 58 1 + Current sample, line, band is: 27 59 1 + Current sample, line, band is: 27 60 1 + Current sample, line, band is: 27 61 1 + Current sample, line, band is: 27 62 1 + Current sample, line, band is: 27 63 1 + Current sample, line, band is: 27 64 1 + Current sample, line, band is: 27 65 1 + Current sample, line, band is: 27 66 1 + Current sample, line, band is: 27 67 1 + Current sample, line, band is: 27 68 1 + Current sample, line, band is: 27 69 1 + Current sample, line, band is: 27 70 1 + Current sample, line, band is: 27 71 1 + Current sample, line, band is: 27 72 1 + Current sample, line, band is: 27 73 1 + Current sample, line, band is: 27 74 1 + Current sample, line, band is: 27 75 1 + Current sample, line, band is: 27 76 1 + Current sample, line, band is: 27 77 1 + Current sample, line, band is: 27 78 1 + Current sample, line, band is: 27 79 1 + Current sample, line, band is: 27 80 1 + Current sample, line, band is: 27 81 1 + Current sample, line, band is: 27 82 1 + Current sample, line, band is: 27 83 1 + Current sample, line, band is: 27 84 1 + Current sample, line, band is: 27 85 1 + Current sample, line, band is: 27 86 1 + Current sample, line, band is: 27 87 1 + Current sample, line, band is: 27 88 1 + Current sample, line, band is: 27 89 1 + Current sample, line, band is: 27 90 1 + Current sample, line, band is: 27 91 1 + Current sample, line, band is: 27 92 1 + Current sample, line, band is: 27 93 1 + Current sample, line, band is: 27 94 1 + Current sample, line, band is: 27 95 1 + Current sample, line, band is: 27 96 1 + Current sample, line, band is: 27 97 1 + Current sample, line, band is: 27 98 1 + Current sample, line, band is: 27 99 1 + Current sample, line, band is: 27 100 1 + Current sample, line, band is: 27 101 1 + Current sample, line, band is: 27 102 1 + Current sample, line, band is: 27 103 1 + Current sample, line, band is: 27 104 1 + Current sample, line, band is: 27 105 1 + Current sample, line, band is: 27 106 1 + Current sample, line, band is: 27 107 1 + Current sample, line, band is: 27 108 1 + Current sample, line, band is: 27 109 1 + Current sample, line, band is: 27 110 1 + Current sample, line, band is: 27 111 1 + Current sample, line, band is: 27 112 1 + Current sample, line, band is: 27 113 1 + Current sample, line, band is: 27 114 1 + Current sample, line, band is: 27 115 1 + Current sample, line, band is: 27 116 1 + Current sample, line, band is: 27 117 1 + Current sample, line, band is: 27 118 1 + Current sample, line, band is: 27 119 1 + Current sample, line, band is: 27 120 1 + Current sample, line, band is: 27 121 1 + Current sample, line, band is: 27 122 1 + Current sample, line, band is: 27 123 1 + Current sample, line, band is: 27 124 1 + Current sample, line, band is: 27 125 1 + Current sample, line, band is: 27 126 1 + Current sample, line, band is: 28 1 1 + Current sample, line, band is: 28 2 1 + Current sample, line, band is: 28 3 1 + Current sample, line, band is: 28 4 1 + Current sample, line, band is: 28 5 1 + Current sample, line, band is: 28 6 1 + Current sample, line, band is: 28 7 1 + Current sample, line, band is: 28 8 1 + Current sample, line, band is: 28 9 1 + Current sample, line, band is: 28 10 1 + Current sample, line, band is: 28 11 1 + Current sample, line, band is: 28 12 1 + Current sample, line, band is: 28 13 1 + Current sample, line, band is: 28 14 1 + Current sample, line, band is: 28 15 1 + Current sample, line, band is: 28 16 1 + Current sample, line, band is: 28 17 1 + Current sample, line, band is: 28 18 1 + Current sample, line, band is: 28 19 1 + Current sample, line, band is: 28 20 1 + Current sample, line, band is: 28 21 1 + Current sample, line, band is: 28 22 1 + Current sample, line, band is: 28 23 1 + Current sample, line, band is: 28 24 1 + Current sample, line, band is: 28 25 1 + Current sample, line, band is: 28 26 1 + Current sample, line, band is: 28 27 1 + Current sample, line, band is: 28 28 1 + Current sample, line, band is: 28 29 1 + Current sample, line, band is: 28 30 1 + Current sample, line, band is: 28 31 1 + Current sample, line, band is: 28 32 1 + Current sample, line, band is: 28 33 1 + Current sample, line, band is: 28 34 1 + Current sample, line, band is: 28 35 1 + Current sample, line, band is: 28 36 1 + Current sample, line, band is: 28 37 1 + Current sample, line, band is: 28 38 1 + Current sample, line, band is: 28 39 1 + Current sample, line, band is: 28 40 1 + Current sample, line, band is: 28 41 1 + Current sample, line, band is: 28 42 1 + Current sample, line, band is: 28 43 1 + Current sample, line, band is: 28 44 1 + Current sample, line, band is: 28 45 1 + Current sample, line, band is: 28 46 1 + Current sample, line, band is: 28 47 1 + Current sample, line, band is: 28 48 1 + Current sample, line, band is: 28 49 1 + Current sample, line, band is: 28 50 1 + Current sample, line, band is: 28 51 1 + Current sample, line, band is: 28 52 1 + Current sample, line, band is: 28 53 1 + Current sample, line, band is: 28 54 1 + Current sample, line, band is: 28 55 1 + Current sample, line, band is: 28 56 1 + Current sample, line, band is: 28 57 1 + Current sample, line, band is: 28 58 1 + Current sample, line, band is: 28 59 1 + Current sample, line, band is: 28 60 1 + Current sample, line, band is: 28 61 1 + Current sample, line, band is: 28 62 1 + Current sample, line, band is: 28 63 1 + Current sample, line, band is: 28 64 1 + Current sample, line, band is: 28 65 1 + Current sample, line, band is: 28 66 1 + Current sample, line, band is: 28 67 1 + Current sample, line, band is: 28 68 1 + Current sample, line, band is: 28 69 1 + Current sample, line, band is: 28 70 1 + Current sample, line, band is: 28 71 1 + Current sample, line, band is: 28 72 1 + Current sample, line, band is: 28 73 1 + Current sample, line, band is: 28 74 1 + Current sample, line, band is: 28 75 1 + Current sample, line, band is: 28 76 1 + Current sample, line, band is: 28 77 1 + Current sample, line, band is: 28 78 1 + Current sample, line, band is: 28 79 1 + Current sample, line, band is: 28 80 1 + Current sample, line, band is: 28 81 1 + Current sample, line, band is: 28 82 1 + Current sample, line, band is: 28 83 1 + Current sample, line, band is: 28 84 1 + Current sample, line, band is: 28 85 1 + Current sample, line, band is: 28 86 1 + Current sample, line, band is: 28 87 1 + Current sample, line, band is: 28 88 1 + Current sample, line, band is: 28 89 1 + Current sample, line, band is: 28 90 1 + Current sample, line, band is: 28 91 1 + Current sample, line, band is: 28 92 1 + Current sample, line, band is: 28 93 1 + Current sample, line, band is: 28 94 1 + Current sample, line, band is: 28 95 1 + Current sample, line, band is: 28 96 1 + Current sample, line, band is: 28 97 1 + Current sample, line, band is: 28 98 1 + Current sample, line, band is: 28 99 1 + Current sample, line, band is: 28 100 1 + Current sample, line, band is: 28 101 1 + Current sample, line, band is: 28 102 1 + Current sample, line, band is: 28 103 1 + Current sample, line, band is: 28 104 1 + Current sample, line, band is: 28 105 1 + Current sample, line, band is: 28 106 1 + Current sample, line, band is: 28 107 1 + Current sample, line, band is: 28 108 1 + Current sample, line, band is: 28 109 1 + Current sample, line, band is: 28 110 1 + Current sample, line, band is: 28 111 1 + Current sample, line, band is: 28 112 1 + Current sample, line, band is: 28 113 1 + Current sample, line, band is: 28 114 1 + Current sample, line, band is: 28 115 1 + Current sample, line, band is: 28 116 1 + Current sample, line, band is: 28 117 1 + Current sample, line, band is: 28 118 1 + Current sample, line, band is: 28 119 1 + Current sample, line, band is: 28 120 1 + Current sample, line, band is: 28 121 1 + Current sample, line, band is: 28 122 1 + Current sample, line, band is: 28 123 1 + Current sample, line, band is: 28 124 1 + Current sample, line, band is: 28 125 1 + Current sample, line, band is: 28 126 1 + Current sample, line, band is: 29 1 1 + Current sample, line, band is: 29 2 1 + Current sample, line, band is: 29 3 1 + Current sample, line, band is: 29 4 1 + Current sample, line, band is: 29 5 1 + Current sample, line, band is: 29 6 1 + Current sample, line, band is: 29 7 1 + Current sample, line, band is: 29 8 1 + Current sample, line, band is: 29 9 1 + Current sample, line, band is: 29 10 1 + Current sample, line, band is: 29 11 1 + Current sample, line, band is: 29 12 1 + Current sample, line, band is: 29 13 1 + Current sample, line, band is: 29 14 1 + Current sample, line, band is: 29 15 1 + Current sample, line, band is: 29 16 1 + Current sample, line, band is: 29 17 1 + Current sample, line, band is: 29 18 1 + Current sample, line, band is: 29 19 1 + Current sample, line, band is: 29 20 1 + Current sample, line, band is: 29 21 1 + Current sample, line, band is: 29 22 1 + Current sample, line, band is: 29 23 1 + Current sample, line, band is: 29 24 1 + Current sample, line, band is: 29 25 1 + Current sample, line, band is: 29 26 1 + Current sample, line, band is: 29 27 1 + Current sample, line, band is: 29 28 1 + Current sample, line, band is: 29 29 1 + Current sample, line, band is: 29 30 1 + Current sample, line, band is: 29 31 1 + Current sample, line, band is: 29 32 1 + Current sample, line, band is: 29 33 1 + Current sample, line, band is: 29 34 1 + Current sample, line, band is: 29 35 1 + Current sample, line, band is: 29 36 1 + Current sample, line, band is: 29 37 1 + Current sample, line, band is: 29 38 1 + Current sample, line, band is: 29 39 1 + Current sample, line, band is: 29 40 1 + Current sample, line, band is: 29 41 1 + Current sample, line, band is: 29 42 1 + Current sample, line, band is: 29 43 1 + Current sample, line, band is: 29 44 1 + Current sample, line, band is: 29 45 1 + Current sample, line, band is: 29 46 1 + Current sample, line, band is: 29 47 1 + Current sample, line, band is: 29 48 1 + Current sample, line, band is: 29 49 1 + Current sample, line, band is: 29 50 1 + Current sample, line, band is: 29 51 1 + Current sample, line, band is: 29 52 1 + Current sample, line, band is: 29 53 1 + Current sample, line, band is: 29 54 1 + Current sample, line, band is: 29 55 1 + Current sample, line, band is: 29 56 1 + Current sample, line, band is: 29 57 1 + Current sample, line, band is: 29 58 1 + Current sample, line, band is: 29 59 1 + Current sample, line, band is: 29 60 1 + Current sample, line, band is: 29 61 1 + Current sample, line, band is: 29 62 1 + Current sample, line, band is: 29 63 1 + Current sample, line, band is: 29 64 1 + Current sample, line, band is: 29 65 1 + Current sample, line, band is: 29 66 1 + Current sample, line, band is: 29 67 1 + Current sample, line, band is: 29 68 1 + Current sample, line, band is: 29 69 1 + Current sample, line, band is: 29 70 1 + Current sample, line, band is: 29 71 1 + Current sample, line, band is: 29 72 1 + Current sample, line, band is: 29 73 1 + Current sample, line, band is: 29 74 1 + Current sample, line, band is: 29 75 1 + Current sample, line, band is: 29 76 1 + Current sample, line, band is: 29 77 1 + Current sample, line, band is: 29 78 1 + Current sample, line, band is: 29 79 1 + Current sample, line, band is: 29 80 1 + Current sample, line, band is: 29 81 1 + Current sample, line, band is: 29 82 1 + Current sample, line, band is: 29 83 1 + Current sample, line, band is: 29 84 1 + Current sample, line, band is: 29 85 1 + Current sample, line, band is: 29 86 1 + Current sample, line, band is: 29 87 1 + Current sample, line, band is: 29 88 1 + Current sample, line, band is: 29 89 1 + Current sample, line, band is: 29 90 1 + Current sample, line, band is: 29 91 1 + Current sample, line, band is: 29 92 1 + Current sample, line, band is: 29 93 1 + Current sample, line, band is: 29 94 1 + Current sample, line, band is: 29 95 1 + Current sample, line, band is: 29 96 1 + Current sample, line, band is: 29 97 1 + Current sample, line, band is: 29 98 1 + Current sample, line, band is: 29 99 1 + Current sample, line, band is: 29 100 1 + Current sample, line, band is: 29 101 1 + Current sample, line, band is: 29 102 1 + Current sample, line, band is: 29 103 1 + Current sample, line, band is: 29 104 1 + Current sample, line, band is: 29 105 1 + Current sample, line, band is: 29 106 1 + Current sample, line, band is: 29 107 1 + Current sample, line, band is: 29 108 1 + Current sample, line, band is: 29 109 1 + Current sample, line, band is: 29 110 1 + Current sample, line, band is: 29 111 1 + Current sample, line, band is: 29 112 1 + Current sample, line, band is: 29 113 1 + Current sample, line, band is: 29 114 1 + Current sample, line, band is: 29 115 1 + Current sample, line, band is: 29 116 1 + Current sample, line, band is: 29 117 1 + Current sample, line, band is: 29 118 1 + Current sample, line, band is: 29 119 1 + Current sample, line, band is: 29 120 1 + Current sample, line, band is: 29 121 1 + Current sample, line, band is: 29 122 1 + Current sample, line, band is: 29 123 1 + Current sample, line, band is: 29 124 1 + Current sample, line, band is: 29 125 1 + Current sample, line, band is: 29 126 1 + Current sample, line, band is: 30 1 1 + Current sample, line, band is: 30 2 1 + Current sample, line, band is: 30 3 1 + Current sample, line, band is: 30 4 1 + Current sample, line, band is: 30 5 1 + Current sample, line, band is: 30 6 1 + Current sample, line, band is: 30 7 1 + Current sample, line, band is: 30 8 1 + Current sample, line, band is: 30 9 1 + Current sample, line, band is: 30 10 1 + Current sample, line, band is: 30 11 1 + Current sample, line, band is: 30 12 1 + Current sample, line, band is: 30 13 1 + Current sample, line, band is: 30 14 1 + Current sample, line, band is: 30 15 1 + Current sample, line, band is: 30 16 1 + Current sample, line, band is: 30 17 1 + Current sample, line, band is: 30 18 1 + Current sample, line, band is: 30 19 1 + Current sample, line, band is: 30 20 1 + Current sample, line, band is: 30 21 1 + Current sample, line, band is: 30 22 1 + Current sample, line, band is: 30 23 1 + Current sample, line, band is: 30 24 1 + Current sample, line, band is: 30 25 1 + Current sample, line, band is: 30 26 1 + Current sample, line, band is: 30 27 1 + Current sample, line, band is: 30 28 1 + Current sample, line, band is: 30 29 1 + Current sample, line, band is: 30 30 1 + Current sample, line, band is: 30 31 1 + Current sample, line, band is: 30 32 1 + Current sample, line, band is: 30 33 1 + Current sample, line, band is: 30 34 1 + Current sample, line, band is: 30 35 1 + Current sample, line, band is: 30 36 1 + Current sample, line, band is: 30 37 1 + Current sample, line, band is: 30 38 1 + Current sample, line, band is: 30 39 1 + Current sample, line, band is: 30 40 1 + Current sample, line, band is: 30 41 1 + Current sample, line, band is: 30 42 1 + Current sample, line, band is: 30 43 1 + Current sample, line, band is: 30 44 1 + Current sample, line, band is: 30 45 1 + Current sample, line, band is: 30 46 1 + Current sample, line, band is: 30 47 1 + Current sample, line, band is: 30 48 1 + Current sample, line, band is: 30 49 1 + Current sample, line, band is: 30 50 1 + Current sample, line, band is: 30 51 1 + Current sample, line, band is: 30 52 1 + Current sample, line, band is: 30 53 1 + Current sample, line, band is: 30 54 1 + Current sample, line, band is: 30 55 1 + Current sample, line, band is: 30 56 1 + Current sample, line, band is: 30 57 1 + Current sample, line, band is: 30 58 1 + Current sample, line, band is: 30 59 1 + Current sample, line, band is: 30 60 1 + Current sample, line, band is: 30 61 1 + Current sample, line, band is: 30 62 1 + Current sample, line, band is: 30 63 1 + Current sample, line, band is: 30 64 1 + Current sample, line, band is: 30 65 1 + Current sample, line, band is: 30 66 1 + Current sample, line, band is: 30 67 1 + Current sample, line, band is: 30 68 1 + Current sample, line, band is: 30 69 1 + Current sample, line, band is: 30 70 1 + Current sample, line, band is: 30 71 1 + Current sample, line, band is: 30 72 1 + Current sample, line, band is: 30 73 1 + Current sample, line, band is: 30 74 1 + Current sample, line, band is: 30 75 1 + Current sample, line, band is: 30 76 1 + Current sample, line, band is: 30 77 1 + Current sample, line, band is: 30 78 1 + Current sample, line, band is: 30 79 1 + Current sample, line, band is: 30 80 1 + Current sample, line, band is: 30 81 1 + Current sample, line, band is: 30 82 1 + Current sample, line, band is: 30 83 1 + Current sample, line, band is: 30 84 1 + Current sample, line, band is: 30 85 1 + Current sample, line, band is: 30 86 1 + Current sample, line, band is: 30 87 1 + Current sample, line, band is: 30 88 1 + Current sample, line, band is: 30 89 1 + Current sample, line, band is: 30 90 1 + Current sample, line, band is: 30 91 1 + Current sample, line, band is: 30 92 1 + Current sample, line, band is: 30 93 1 + Current sample, line, band is: 30 94 1 + Current sample, line, band is: 30 95 1 + Current sample, line, band is: 30 96 1 + Current sample, line, band is: 30 97 1 + Current sample, line, band is: 30 98 1 + Current sample, line, band is: 30 99 1 + Current sample, line, band is: 30 100 1 + Current sample, line, band is: 30 101 1 + Current sample, line, band is: 30 102 1 + Current sample, line, band is: 30 103 1 + Current sample, line, band is: 30 104 1 + Current sample, line, band is: 30 105 1 + Current sample, line, band is: 30 106 1 + Current sample, line, band is: 30 107 1 + Current sample, line, band is: 30 108 1 + Current sample, line, band is: 30 109 1 + Current sample, line, band is: 30 110 1 + Current sample, line, band is: 30 111 1 + Current sample, line, band is: 30 112 1 + Current sample, line, band is: 30 113 1 + Current sample, line, band is: 30 114 1 + Current sample, line, band is: 30 115 1 + Current sample, line, band is: 30 116 1 + Current sample, line, band is: 30 117 1 + Current sample, line, band is: 30 118 1 + Current sample, line, band is: 30 119 1 + Current sample, line, band is: 30 120 1 + Current sample, line, band is: 30 121 1 + Current sample, line, band is: 30 122 1 + Current sample, line, band is: 30 123 1 + Current sample, line, band is: 30 124 1 + Current sample, line, band is: 30 125 1 + Current sample, line, band is: 30 126 1 + Current sample, line, band is: 31 1 1 + Current sample, line, band is: 31 2 1 + Current sample, line, band is: 31 3 1 + Current sample, line, band is: 31 4 1 + Current sample, line, band is: 31 5 1 + Current sample, line, band is: 31 6 1 + Current sample, line, band is: 31 7 1 + Current sample, line, band is: 31 8 1 + Current sample, line, band is: 31 9 1 + Current sample, line, band is: 31 10 1 + Current sample, line, band is: 31 11 1 + Current sample, line, band is: 31 12 1 + Current sample, line, band is: 31 13 1 + Current sample, line, band is: 31 14 1 + Current sample, line, band is: 31 15 1 + Current sample, line, band is: 31 16 1 + Current sample, line, band is: 31 17 1 + Current sample, line, band is: 31 18 1 + Current sample, line, band is: 31 19 1 + Current sample, line, band is: 31 20 1 + Current sample, line, band is: 31 21 1 + Current sample, line, band is: 31 22 1 + Current sample, line, band is: 31 23 1 + Current sample, line, band is: 31 24 1 + Current sample, line, band is: 31 25 1 + Current sample, line, band is: 31 26 1 + Current sample, line, band is: 31 27 1 + Current sample, line, band is: 31 28 1 + Current sample, line, band is: 31 29 1 + Current sample, line, band is: 31 30 1 + Current sample, line, band is: 31 31 1 + Current sample, line, band is: 31 32 1 + Current sample, line, band is: 31 33 1 + Current sample, line, band is: 31 34 1 + Current sample, line, band is: 31 35 1 + Current sample, line, band is: 31 36 1 + Current sample, line, band is: 31 37 1 + Current sample, line, band is: 31 38 1 + Current sample, line, band is: 31 39 1 + Current sample, line, band is: 31 40 1 + Current sample, line, band is: 31 41 1 + Current sample, line, band is: 31 42 1 + Current sample, line, band is: 31 43 1 + Current sample, line, band is: 31 44 1 + Current sample, line, band is: 31 45 1 + Current sample, line, band is: 31 46 1 + Current sample, line, band is: 31 47 1 + Current sample, line, band is: 31 48 1 + Current sample, line, band is: 31 49 1 + Current sample, line, band is: 31 50 1 + Current sample, line, band is: 31 51 1 + Current sample, line, band is: 31 52 1 + Current sample, line, band is: 31 53 1 + Current sample, line, band is: 31 54 1 + Current sample, line, band is: 31 55 1 + Current sample, line, band is: 31 56 1 + Current sample, line, band is: 31 57 1 + Current sample, line, band is: 31 58 1 + Current sample, line, band is: 31 59 1 + Current sample, line, band is: 31 60 1 + Current sample, line, band is: 31 61 1 + Current sample, line, band is: 31 62 1 + Current sample, line, band is: 31 63 1 + Current sample, line, band is: 31 64 1 + Current sample, line, band is: 31 65 1 + Current sample, line, band is: 31 66 1 + Current sample, line, band is: 31 67 1 + Current sample, line, band is: 31 68 1 + Current sample, line, band is: 31 69 1 + Current sample, line, band is: 31 70 1 + Current sample, line, band is: 31 71 1 + Current sample, line, band is: 31 72 1 + Current sample, line, band is: 31 73 1 + Current sample, line, band is: 31 74 1 + Current sample, line, band is: 31 75 1 + Current sample, line, band is: 31 76 1 + Current sample, line, band is: 31 77 1 + Current sample, line, band is: 31 78 1 + Current sample, line, band is: 31 79 1 + Current sample, line, band is: 31 80 1 + Current sample, line, band is: 31 81 1 + Current sample, line, band is: 31 82 1 + Current sample, line, band is: 31 83 1 + Current sample, line, band is: 31 84 1 + Current sample, line, band is: 31 85 1 + Current sample, line, band is: 31 86 1 + Current sample, line, band is: 31 87 1 + Current sample, line, band is: 31 88 1 + Current sample, line, band is: 31 89 1 + Current sample, line, band is: 31 90 1 + Current sample, line, band is: 31 91 1 + Current sample, line, band is: 31 92 1 + Current sample, line, band is: 31 93 1 + Current sample, line, band is: 31 94 1 + Current sample, line, band is: 31 95 1 + Current sample, line, band is: 31 96 1 + Current sample, line, band is: 31 97 1 + Current sample, line, band is: 31 98 1 + Current sample, line, band is: 31 99 1 + Current sample, line, band is: 31 100 1 + Current sample, line, band is: 31 101 1 + Current sample, line, band is: 31 102 1 + Current sample, line, band is: 31 103 1 + Current sample, line, band is: 31 104 1 + Current sample, line, band is: 31 105 1 + Current sample, line, band is: 31 106 1 + Current sample, line, band is: 31 107 1 + Current sample, line, band is: 31 108 1 + Current sample, line, band is: 31 109 1 + Current sample, line, band is: 31 110 1 + Current sample, line, band is: 31 111 1 + Current sample, line, band is: 31 112 1 + Current sample, line, band is: 31 113 1 + Current sample, line, band is: 31 114 1 + Current sample, line, band is: 31 115 1 + Current sample, line, band is: 31 116 1 + Current sample, line, band is: 31 117 1 + Current sample, line, band is: 31 118 1 + Current sample, line, band is: 31 119 1 + Current sample, line, band is: 31 120 1 + Current sample, line, band is: 31 121 1 + Current sample, line, band is: 31 122 1 + Current sample, line, band is: 31 123 1 + Current sample, line, band is: 31 124 1 + Current sample, line, band is: 31 125 1 + Current sample, line, band is: 31 126 1 + Current sample, line, band is: 32 1 1 + Current sample, line, band is: 32 2 1 + Current sample, line, band is: 32 3 1 + Current sample, line, band is: 32 4 1 + Current sample, line, band is: 32 5 1 + Current sample, line, band is: 32 6 1 + Current sample, line, band is: 32 7 1 + Current sample, line, band is: 32 8 1 + Current sample, line, band is: 32 9 1 + Current sample, line, band is: 32 10 1 + Current sample, line, band is: 32 11 1 + Current sample, line, band is: 32 12 1 + Current sample, line, band is: 32 13 1 + Current sample, line, band is: 32 14 1 + Current sample, line, band is: 32 15 1 + Current sample, line, band is: 32 16 1 + Current sample, line, band is: 32 17 1 + Current sample, line, band is: 32 18 1 + Current sample, line, band is: 32 19 1 + Current sample, line, band is: 32 20 1 + Current sample, line, band is: 32 21 1 + Current sample, line, band is: 32 22 1 + Current sample, line, band is: 32 23 1 + Current sample, line, band is: 32 24 1 + Current sample, line, band is: 32 25 1 + Current sample, line, band is: 32 26 1 + Current sample, line, band is: 32 27 1 + Current sample, line, band is: 32 28 1 + Current sample, line, band is: 32 29 1 + Current sample, line, band is: 32 30 1 + Current sample, line, band is: 32 31 1 + Current sample, line, band is: 32 32 1 + Current sample, line, band is: 32 33 1 + Current sample, line, band is: 32 34 1 + Current sample, line, band is: 32 35 1 + Current sample, line, band is: 32 36 1 + Current sample, line, band is: 32 37 1 + Current sample, line, band is: 32 38 1 + Current sample, line, band is: 32 39 1 + Current sample, line, band is: 32 40 1 + Current sample, line, band is: 32 41 1 + Current sample, line, band is: 32 42 1 + Current sample, line, band is: 32 43 1 + Current sample, line, band is: 32 44 1 + Current sample, line, band is: 32 45 1 + Current sample, line, band is: 32 46 1 + Current sample, line, band is: 32 47 1 + Current sample, line, band is: 32 48 1 + Current sample, line, band is: 32 49 1 + Current sample, line, band is: 32 50 1 + Current sample, line, band is: 32 51 1 + Current sample, line, band is: 32 52 1 + Current sample, line, band is: 32 53 1 + Current sample, line, band is: 32 54 1 + Current sample, line, band is: 32 55 1 + Current sample, line, band is: 32 56 1 + Current sample, line, band is: 32 57 1 + Current sample, line, band is: 32 58 1 + Current sample, line, band is: 32 59 1 + Current sample, line, band is: 32 60 1 + Current sample, line, band is: 32 61 1 + Current sample, line, band is: 32 62 1 + Current sample, line, band is: 32 63 1 + Current sample, line, band is: 32 64 1 + Current sample, line, band is: 32 65 1 + Current sample, line, band is: 32 66 1 + Current sample, line, band is: 32 67 1 + Current sample, line, band is: 32 68 1 + Current sample, line, band is: 32 69 1 + Current sample, line, band is: 32 70 1 + Current sample, line, band is: 32 71 1 + Current sample, line, band is: 32 72 1 + Current sample, line, band is: 32 73 1 + Current sample, line, band is: 32 74 1 + Current sample, line, band is: 32 75 1 + Current sample, line, band is: 32 76 1 + Current sample, line, band is: 32 77 1 + Current sample, line, band is: 32 78 1 + Current sample, line, band is: 32 79 1 + Current sample, line, band is: 32 80 1 + Current sample, line, band is: 32 81 1 + Current sample, line, band is: 32 82 1 + Current sample, line, band is: 32 83 1 + Current sample, line, band is: 32 84 1 + Current sample, line, band is: 32 85 1 + Current sample, line, band is: 32 86 1 + Current sample, line, band is: 32 87 1 + Current sample, line, band is: 32 88 1 + Current sample, line, band is: 32 89 1 + Current sample, line, band is: 32 90 1 + Current sample, line, band is: 32 91 1 + Current sample, line, band is: 32 92 1 + Current sample, line, band is: 32 93 1 + Current sample, line, band is: 32 94 1 + Current sample, line, band is: 32 95 1 + Current sample, line, band is: 32 96 1 + Current sample, line, band is: 32 97 1 + Current sample, line, band is: 32 98 1 + Current sample, line, band is: 32 99 1 + Current sample, line, band is: 32 100 1 + Current sample, line, band is: 32 101 1 + Current sample, line, band is: 32 102 1 + Current sample, line, band is: 32 103 1 + Current sample, line, band is: 32 104 1 + Current sample, line, band is: 32 105 1 + Current sample, line, band is: 32 106 1 + Current sample, line, band is: 32 107 1 + Current sample, line, band is: 32 108 1 + Current sample, line, band is: 32 109 1 + Current sample, line, band is: 32 110 1 + Current sample, line, band is: 32 111 1 + Current sample, line, band is: 32 112 1 + Current sample, line, band is: 32 113 1 + Current sample, line, band is: 32 114 1 + Current sample, line, band is: 32 115 1 + Current sample, line, band is: 32 116 1 + Current sample, line, band is: 32 117 1 + Current sample, line, band is: 32 118 1 + Current sample, line, band is: 32 119 1 + Current sample, line, band is: 32 120 1 + Current sample, line, band is: 32 121 1 + Current sample, line, band is: 32 122 1 + Current sample, line, band is: 32 123 1 + Current sample, line, band is: 32 124 1 + Current sample, line, band is: 32 125 1 + Current sample, line, band is: 32 126 1 + Current sample, line, band is: 33 1 1 + Current sample, line, band is: 33 2 1 + Current sample, line, band is: 33 3 1 + Current sample, line, band is: 33 4 1 + Current sample, line, band is: 33 5 1 + Current sample, line, band is: 33 6 1 + Current sample, line, band is: 33 7 1 + Current sample, line, band is: 33 8 1 + Current sample, line, band is: 33 9 1 + Current sample, line, band is: 33 10 1 + Current sample, line, band is: 33 11 1 + Current sample, line, band is: 33 12 1 + Current sample, line, band is: 33 13 1 + Current sample, line, band is: 33 14 1 + Current sample, line, band is: 33 15 1 + Current sample, line, band is: 33 16 1 + Current sample, line, band is: 33 17 1 + Current sample, line, band is: 33 18 1 + Current sample, line, band is: 33 19 1 + Current sample, line, band is: 33 20 1 + Current sample, line, band is: 33 21 1 + Current sample, line, band is: 33 22 1 + Current sample, line, band is: 33 23 1 + Current sample, line, band is: 33 24 1 + Current sample, line, band is: 33 25 1 + Current sample, line, band is: 33 26 1 + Current sample, line, band is: 33 27 1 + Current sample, line, band is: 33 28 1 + Current sample, line, band is: 33 29 1 + Current sample, line, band is: 33 30 1 + Current sample, line, band is: 33 31 1 + Current sample, line, band is: 33 32 1 + Current sample, line, band is: 33 33 1 + Current sample, line, band is: 33 34 1 + Current sample, line, band is: 33 35 1 + Current sample, line, band is: 33 36 1 + Current sample, line, band is: 33 37 1 + Current sample, line, band is: 33 38 1 + Current sample, line, band is: 33 39 1 + Current sample, line, band is: 33 40 1 + Current sample, line, band is: 33 41 1 + Current sample, line, band is: 33 42 1 + Current sample, line, band is: 33 43 1 + Current sample, line, band is: 33 44 1 + Current sample, line, band is: 33 45 1 + Current sample, line, band is: 33 46 1 + Current sample, line, band is: 33 47 1 + Current sample, line, band is: 33 48 1 + Current sample, line, band is: 33 49 1 + Current sample, line, band is: 33 50 1 + Current sample, line, band is: 33 51 1 + Current sample, line, band is: 33 52 1 + Current sample, line, band is: 33 53 1 + Current sample, line, band is: 33 54 1 + Current sample, line, band is: 33 55 1 + Current sample, line, band is: 33 56 1 + Current sample, line, band is: 33 57 1 + Current sample, line, band is: 33 58 1 + Current sample, line, band is: 33 59 1 + Current sample, line, band is: 33 60 1 + Current sample, line, band is: 33 61 1 + Current sample, line, band is: 33 62 1 + Current sample, line, band is: 33 63 1 + Current sample, line, band is: 33 64 1 + Current sample, line, band is: 33 65 1 + Current sample, line, band is: 33 66 1 + Current sample, line, band is: 33 67 1 + Current sample, line, band is: 33 68 1 + Current sample, line, band is: 33 69 1 + Current sample, line, band is: 33 70 1 + Current sample, line, band is: 33 71 1 + Current sample, line, band is: 33 72 1 + Current sample, line, band is: 33 73 1 + Current sample, line, band is: 33 74 1 + Current sample, line, band is: 33 75 1 + Current sample, line, band is: 33 76 1 + Current sample, line, band is: 33 77 1 + Current sample, line, band is: 33 78 1 + Current sample, line, band is: 33 79 1 + Current sample, line, band is: 33 80 1 + Current sample, line, band is: 33 81 1 + Current sample, line, band is: 33 82 1 + Current sample, line, band is: 33 83 1 + Current sample, line, band is: 33 84 1 + Current sample, line, band is: 33 85 1 + Current sample, line, band is: 33 86 1 + Current sample, line, band is: 33 87 1 + Current sample, line, band is: 33 88 1 + Current sample, line, band is: 33 89 1 + Current sample, line, band is: 33 90 1 + Current sample, line, band is: 33 91 1 + Current sample, line, band is: 33 92 1 + Current sample, line, band is: 33 93 1 + Current sample, line, band is: 33 94 1 + Current sample, line, band is: 33 95 1 + Current sample, line, band is: 33 96 1 + Current sample, line, band is: 33 97 1 + Current sample, line, band is: 33 98 1 + Current sample, line, band is: 33 99 1 + Current sample, line, band is: 33 100 1 + Current sample, line, band is: 33 101 1 + Current sample, line, band is: 33 102 1 + Current sample, line, band is: 33 103 1 + Current sample, line, band is: 33 104 1 + Current sample, line, band is: 33 105 1 + Current sample, line, band is: 33 106 1 + Current sample, line, band is: 33 107 1 + Current sample, line, band is: 33 108 1 + Current sample, line, band is: 33 109 1 + Current sample, line, band is: 33 110 1 + Current sample, line, band is: 33 111 1 + Current sample, line, band is: 33 112 1 + Current sample, line, band is: 33 113 1 + Current sample, line, band is: 33 114 1 + Current sample, line, band is: 33 115 1 + Current sample, line, band is: 33 116 1 + Current sample, line, band is: 33 117 1 + Current sample, line, band is: 33 118 1 + Current sample, line, band is: 33 119 1 + Current sample, line, band is: 33 120 1 + Current sample, line, band is: 33 121 1 + Current sample, line, band is: 33 122 1 + Current sample, line, band is: 33 123 1 + Current sample, line, band is: 33 124 1 + Current sample, line, band is: 33 125 1 + Current sample, line, band is: 33 126 1 + Current sample, line, band is: 34 1 1 + Current sample, line, band is: 34 2 1 + Current sample, line, band is: 34 3 1 + Current sample, line, band is: 34 4 1 + Current sample, line, band is: 34 5 1 + Current sample, line, band is: 34 6 1 + Current sample, line, band is: 34 7 1 + Current sample, line, band is: 34 8 1 + Current sample, line, band is: 34 9 1 + Current sample, line, band is: 34 10 1 + Current sample, line, band is: 34 11 1 + Current sample, line, band is: 34 12 1 + Current sample, line, band is: 34 13 1 + Current sample, line, band is: 34 14 1 + Current sample, line, band is: 34 15 1 + Current sample, line, band is: 34 16 1 + Current sample, line, band is: 34 17 1 + Current sample, line, band is: 34 18 1 + Current sample, line, band is: 34 19 1 + Current sample, line, band is: 34 20 1 + Current sample, line, band is: 34 21 1 + Current sample, line, band is: 34 22 1 + Current sample, line, band is: 34 23 1 + Current sample, line, band is: 34 24 1 + Current sample, line, band is: 34 25 1 + Current sample, line, band is: 34 26 1 + Current sample, line, band is: 34 27 1 + Current sample, line, band is: 34 28 1 + Current sample, line, band is: 34 29 1 + Current sample, line, band is: 34 30 1 + Current sample, line, band is: 34 31 1 + Current sample, line, band is: 34 32 1 + Current sample, line, band is: 34 33 1 + Current sample, line, band is: 34 34 1 + Current sample, line, band is: 34 35 1 + Current sample, line, band is: 34 36 1 + Current sample, line, band is: 34 37 1 + Current sample, line, band is: 34 38 1 + Current sample, line, band is: 34 39 1 + Current sample, line, band is: 34 40 1 + Current sample, line, band is: 34 41 1 + Current sample, line, band is: 34 42 1 + Current sample, line, band is: 34 43 1 + Current sample, line, band is: 34 44 1 + Current sample, line, band is: 34 45 1 + Current sample, line, band is: 34 46 1 + Current sample, line, band is: 34 47 1 + Current sample, line, band is: 34 48 1 + Current sample, line, band is: 34 49 1 + Current sample, line, band is: 34 50 1 + Current sample, line, band is: 34 51 1 + Current sample, line, band is: 34 52 1 + Current sample, line, band is: 34 53 1 + Current sample, line, band is: 34 54 1 + Current sample, line, band is: 34 55 1 + Current sample, line, band is: 34 56 1 + Current sample, line, band is: 34 57 1 + Current sample, line, band is: 34 58 1 + Current sample, line, band is: 34 59 1 + Current sample, line, band is: 34 60 1 + Current sample, line, band is: 34 61 1 + Current sample, line, band is: 34 62 1 + Current sample, line, band is: 34 63 1 + Current sample, line, band is: 34 64 1 + Current sample, line, band is: 34 65 1 + Current sample, line, band is: 34 66 1 + Current sample, line, band is: 34 67 1 + Current sample, line, band is: 34 68 1 + Current sample, line, band is: 34 69 1 + Current sample, line, band is: 34 70 1 + Current sample, line, band is: 34 71 1 + Current sample, line, band is: 34 72 1 + Current sample, line, band is: 34 73 1 + Current sample, line, band is: 34 74 1 + Current sample, line, band is: 34 75 1 + Current sample, line, band is: 34 76 1 + Current sample, line, band is: 34 77 1 + Current sample, line, band is: 34 78 1 + Current sample, line, band is: 34 79 1 + Current sample, line, band is: 34 80 1 + Current sample, line, band is: 34 81 1 + Current sample, line, band is: 34 82 1 + Current sample, line, band is: 34 83 1 + Current sample, line, band is: 34 84 1 + Current sample, line, band is: 34 85 1 + Current sample, line, band is: 34 86 1 + Current sample, line, band is: 34 87 1 + Current sample, line, band is: 34 88 1 + Current sample, line, band is: 34 89 1 + Current sample, line, band is: 34 90 1 + Current sample, line, band is: 34 91 1 + Current sample, line, band is: 34 92 1 + Current sample, line, band is: 34 93 1 + Current sample, line, band is: 34 94 1 + Current sample, line, band is: 34 95 1 + Current sample, line, band is: 34 96 1 + Current sample, line, band is: 34 97 1 + Current sample, line, band is: 34 98 1 + Current sample, line, band is: 34 99 1 + Current sample, line, band is: 34 100 1 + Current sample, line, band is: 34 101 1 + Current sample, line, band is: 34 102 1 + Current sample, line, band is: 34 103 1 + Current sample, line, band is: 34 104 1 + Current sample, line, band is: 34 105 1 + Current sample, line, band is: 34 106 1 + Current sample, line, band is: 34 107 1 + Current sample, line, band is: 34 108 1 + Current sample, line, band is: 34 109 1 + Current sample, line, band is: 34 110 1 + Current sample, line, band is: 34 111 1 + Current sample, line, band is: 34 112 1 + Current sample, line, band is: 34 113 1 + Current sample, line, band is: 34 114 1 + Current sample, line, band is: 34 115 1 + Current sample, line, band is: 34 116 1 + Current sample, line, band is: 34 117 1 + Current sample, line, band is: 34 118 1 + Current sample, line, band is: 34 119 1 + Current sample, line, band is: 34 120 1 + Current sample, line, band is: 34 121 1 + Current sample, line, band is: 34 122 1 + Current sample, line, band is: 34 123 1 + Current sample, line, band is: 34 124 1 + Current sample, line, band is: 34 125 1 + Current sample, line, band is: 34 126 1 + Current sample, line, band is: 35 1 1 + Current sample, line, band is: 35 2 1 + Current sample, line, band is: 35 3 1 + Current sample, line, band is: 35 4 1 + Current sample, line, band is: 35 5 1 + Current sample, line, band is: 35 6 1 + Current sample, line, band is: 35 7 1 + Current sample, line, band is: 35 8 1 + Current sample, line, band is: 35 9 1 + Current sample, line, band is: 35 10 1 + Current sample, line, band is: 35 11 1 + Current sample, line, band is: 35 12 1 + Current sample, line, band is: 35 13 1 + Current sample, line, band is: 35 14 1 + Current sample, line, band is: 35 15 1 + Current sample, line, band is: 35 16 1 + Current sample, line, band is: 35 17 1 + Current sample, line, band is: 35 18 1 + Current sample, line, band is: 35 19 1 + Current sample, line, band is: 35 20 1 + Current sample, line, band is: 35 21 1 + Current sample, line, band is: 35 22 1 + Current sample, line, band is: 35 23 1 + Current sample, line, band is: 35 24 1 + Current sample, line, band is: 35 25 1 + Current sample, line, band is: 35 26 1 + Current sample, line, band is: 35 27 1 + Current sample, line, band is: 35 28 1 + Current sample, line, band is: 35 29 1 + Current sample, line, band is: 35 30 1 + Current sample, line, band is: 35 31 1 + Current sample, line, band is: 35 32 1 + Current sample, line, band is: 35 33 1 + Current sample, line, band is: 35 34 1 + Current sample, line, band is: 35 35 1 + Current sample, line, band is: 35 36 1 + Current sample, line, band is: 35 37 1 + Current sample, line, band is: 35 38 1 + Current sample, line, band is: 35 39 1 + Current sample, line, band is: 35 40 1 + Current sample, line, band is: 35 41 1 + Current sample, line, band is: 35 42 1 + Current sample, line, band is: 35 43 1 + Current sample, line, band is: 35 44 1 + Current sample, line, band is: 35 45 1 + Current sample, line, band is: 35 46 1 + Current sample, line, band is: 35 47 1 + Current sample, line, band is: 35 48 1 + Current sample, line, band is: 35 49 1 + Current sample, line, band is: 35 50 1 + Current sample, line, band is: 35 51 1 + Current sample, line, band is: 35 52 1 + Current sample, line, band is: 35 53 1 + Current sample, line, band is: 35 54 1 + Current sample, line, band is: 35 55 1 + Current sample, line, band is: 35 56 1 + Current sample, line, band is: 35 57 1 + Current sample, line, band is: 35 58 1 + Current sample, line, band is: 35 59 1 + Current sample, line, band is: 35 60 1 + Current sample, line, band is: 35 61 1 + Current sample, line, band is: 35 62 1 + Current sample, line, band is: 35 63 1 + Current sample, line, band is: 35 64 1 + Current sample, line, band is: 35 65 1 + Current sample, line, band is: 35 66 1 + Current sample, line, band is: 35 67 1 + Current sample, line, band is: 35 68 1 + Current sample, line, band is: 35 69 1 + Current sample, line, band is: 35 70 1 + Current sample, line, band is: 35 71 1 + Current sample, line, band is: 35 72 1 + Current sample, line, band is: 35 73 1 + Current sample, line, band is: 35 74 1 + Current sample, line, band is: 35 75 1 + Current sample, line, band is: 35 76 1 + Current sample, line, band is: 35 77 1 + Current sample, line, band is: 35 78 1 + Current sample, line, band is: 35 79 1 + Current sample, line, band is: 35 80 1 + Current sample, line, band is: 35 81 1 + Current sample, line, band is: 35 82 1 + Current sample, line, band is: 35 83 1 + Current sample, line, band is: 35 84 1 + Current sample, line, band is: 35 85 1 + Current sample, line, band is: 35 86 1 + Current sample, line, band is: 35 87 1 + Current sample, line, band is: 35 88 1 + Current sample, line, band is: 35 89 1 + Current sample, line, band is: 35 90 1 + Current sample, line, band is: 35 91 1 + Current sample, line, band is: 35 92 1 + Current sample, line, band is: 35 93 1 + Current sample, line, band is: 35 94 1 + Current sample, line, band is: 35 95 1 + Current sample, line, band is: 35 96 1 + Current sample, line, band is: 35 97 1 + Current sample, line, band is: 35 98 1 + Current sample, line, band is: 35 99 1 + Current sample, line, band is: 35 100 1 + Current sample, line, band is: 35 101 1 + Current sample, line, band is: 35 102 1 + Current sample, line, band is: 35 103 1 + Current sample, line, band is: 35 104 1 + Current sample, line, band is: 35 105 1 + Current sample, line, band is: 35 106 1 + Current sample, line, band is: 35 107 1 + Current sample, line, band is: 35 108 1 + Current sample, line, band is: 35 109 1 + Current sample, line, band is: 35 110 1 + Current sample, line, band is: 35 111 1 + Current sample, line, band is: 35 112 1 + Current sample, line, band is: 35 113 1 + Current sample, line, band is: 35 114 1 + Current sample, line, band is: 35 115 1 + Current sample, line, band is: 35 116 1 + Current sample, line, band is: 35 117 1 + Current sample, line, band is: 35 118 1 + Current sample, line, band is: 35 119 1 + Current sample, line, band is: 35 120 1 + Current sample, line, band is: 35 121 1 + Current sample, line, band is: 35 122 1 + Current sample, line, band is: 35 123 1 + Current sample, line, band is: 35 124 1 + Current sample, line, band is: 35 125 1 + Current sample, line, band is: 35 126 1 + Current sample, line, band is: 36 1 1 + Current sample, line, band is: 36 2 1 + Current sample, line, band is: 36 3 1 + Current sample, line, band is: 36 4 1 + Current sample, line, band is: 36 5 1 + Current sample, line, band is: 36 6 1 + Current sample, line, band is: 36 7 1 + Current sample, line, band is: 36 8 1 + Current sample, line, band is: 36 9 1 + Current sample, line, band is: 36 10 1 + Current sample, line, band is: 36 11 1 + Current sample, line, band is: 36 12 1 + Current sample, line, band is: 36 13 1 + Current sample, line, band is: 36 14 1 + Current sample, line, band is: 36 15 1 + Current sample, line, band is: 36 16 1 + Current sample, line, band is: 36 17 1 + Current sample, line, band is: 36 18 1 + Current sample, line, band is: 36 19 1 + Current sample, line, band is: 36 20 1 + Current sample, line, band is: 36 21 1 + Current sample, line, band is: 36 22 1 + Current sample, line, band is: 36 23 1 + Current sample, line, band is: 36 24 1 + Current sample, line, band is: 36 25 1 + Current sample, line, band is: 36 26 1 + Current sample, line, band is: 36 27 1 + Current sample, line, band is: 36 28 1 + Current sample, line, band is: 36 29 1 + Current sample, line, band is: 36 30 1 + Current sample, line, band is: 36 31 1 + Current sample, line, band is: 36 32 1 + Current sample, line, band is: 36 33 1 + Current sample, line, band is: 36 34 1 + Current sample, line, band is: 36 35 1 + Current sample, line, band is: 36 36 1 + Current sample, line, band is: 36 37 1 + Current sample, line, band is: 36 38 1 + Current sample, line, band is: 36 39 1 + Current sample, line, band is: 36 40 1 + Current sample, line, band is: 36 41 1 + Current sample, line, band is: 36 42 1 + Current sample, line, band is: 36 43 1 + Current sample, line, band is: 36 44 1 + Current sample, line, band is: 36 45 1 + Current sample, line, band is: 36 46 1 + Current sample, line, band is: 36 47 1 + Current sample, line, band is: 36 48 1 + Current sample, line, band is: 36 49 1 + Current sample, line, band is: 36 50 1 + Current sample, line, band is: 36 51 1 + Current sample, line, band is: 36 52 1 + Current sample, line, band is: 36 53 1 + Current sample, line, band is: 36 54 1 + Current sample, line, band is: 36 55 1 + Current sample, line, band is: 36 56 1 + Current sample, line, band is: 36 57 1 + Current sample, line, band is: 36 58 1 + Current sample, line, band is: 36 59 1 + Current sample, line, band is: 36 60 1 + Current sample, line, band is: 36 61 1 + Current sample, line, band is: 36 62 1 + Current sample, line, band is: 36 63 1 + Current sample, line, band is: 36 64 1 + Current sample, line, band is: 36 65 1 + Current sample, line, band is: 36 66 1 + Current sample, line, band is: 36 67 1 + Current sample, line, band is: 36 68 1 + Current sample, line, band is: 36 69 1 + Current sample, line, band is: 36 70 1 + Current sample, line, band is: 36 71 1 + Current sample, line, band is: 36 72 1 + Current sample, line, band is: 36 73 1 + Current sample, line, band is: 36 74 1 + Current sample, line, band is: 36 75 1 + Current sample, line, band is: 36 76 1 + Current sample, line, band is: 36 77 1 + Current sample, line, band is: 36 78 1 + Current sample, line, band is: 36 79 1 + Current sample, line, band is: 36 80 1 + Current sample, line, band is: 36 81 1 + Current sample, line, band is: 36 82 1 + Current sample, line, band is: 36 83 1 + Current sample, line, band is: 36 84 1 + Current sample, line, band is: 36 85 1 + Current sample, line, band is: 36 86 1 + Current sample, line, band is: 36 87 1 + Current sample, line, band is: 36 88 1 + Current sample, line, band is: 36 89 1 + Current sample, line, band is: 36 90 1 + Current sample, line, band is: 36 91 1 + Current sample, line, band is: 36 92 1 + Current sample, line, band is: 36 93 1 + Current sample, line, band is: 36 94 1 + Current sample, line, band is: 36 95 1 + Current sample, line, band is: 36 96 1 + Current sample, line, band is: 36 97 1 + Current sample, line, band is: 36 98 1 + Current sample, line, band is: 36 99 1 + Current sample, line, band is: 36 100 1 + Current sample, line, band is: 36 101 1 + Current sample, line, band is: 36 102 1 + Current sample, line, band is: 36 103 1 + Current sample, line, band is: 36 104 1 + Current sample, line, band is: 36 105 1 + Current sample, line, band is: 36 106 1 + Current sample, line, band is: 36 107 1 + Current sample, line, band is: 36 108 1 + Current sample, line, band is: 36 109 1 + Current sample, line, band is: 36 110 1 + Current sample, line, band is: 36 111 1 + Current sample, line, band is: 36 112 1 + Current sample, line, band is: 36 113 1 + Current sample, line, band is: 36 114 1 + Current sample, line, band is: 36 115 1 + Current sample, line, band is: 36 116 1 + Current sample, line, band is: 36 117 1 + Current sample, line, band is: 36 118 1 + Current sample, line, band is: 36 119 1 + Current sample, line, band is: 36 120 1 + Current sample, line, band is: 36 121 1 + Current sample, line, band is: 36 122 1 + Current sample, line, band is: 36 123 1 + Current sample, line, band is: 36 124 1 + Current sample, line, band is: 36 125 1 + Current sample, line, band is: 36 126 1 + Current sample, line, band is: 37 1 1 + Current sample, line, band is: 37 2 1 + Current sample, line, band is: 37 3 1 + Current sample, line, band is: 37 4 1 + Current sample, line, band is: 37 5 1 + Current sample, line, band is: 37 6 1 + Current sample, line, band is: 37 7 1 + Current sample, line, band is: 37 8 1 + Current sample, line, band is: 37 9 1 + Current sample, line, band is: 37 10 1 + Current sample, line, band is: 37 11 1 + Current sample, line, band is: 37 12 1 + Current sample, line, band is: 37 13 1 + Current sample, line, band is: 37 14 1 + Current sample, line, band is: 37 15 1 + Current sample, line, band is: 37 16 1 + Current sample, line, band is: 37 17 1 + Current sample, line, band is: 37 18 1 + Current sample, line, band is: 37 19 1 + Current sample, line, band is: 37 20 1 + Current sample, line, band is: 37 21 1 + Current sample, line, band is: 37 22 1 + Current sample, line, band is: 37 23 1 + Current sample, line, band is: 37 24 1 + Current sample, line, band is: 37 25 1 + Current sample, line, band is: 37 26 1 + Current sample, line, band is: 37 27 1 + Current sample, line, band is: 37 28 1 + Current sample, line, band is: 37 29 1 + Current sample, line, band is: 37 30 1 + Current sample, line, band is: 37 31 1 + Current sample, line, band is: 37 32 1 + Current sample, line, band is: 37 33 1 + Current sample, line, band is: 37 34 1 + Current sample, line, band is: 37 35 1 + Current sample, line, band is: 37 36 1 + Current sample, line, band is: 37 37 1 + Current sample, line, band is: 37 38 1 + Current sample, line, band is: 37 39 1 + Current sample, line, band is: 37 40 1 + Current sample, line, band is: 37 41 1 + Current sample, line, band is: 37 42 1 + Current sample, line, band is: 37 43 1 + Current sample, line, band is: 37 44 1 + Current sample, line, band is: 37 45 1 + Current sample, line, band is: 37 46 1 + Current sample, line, band is: 37 47 1 + Current sample, line, band is: 37 48 1 + Current sample, line, band is: 37 49 1 + Current sample, line, band is: 37 50 1 + Current sample, line, band is: 37 51 1 + Current sample, line, band is: 37 52 1 + Current sample, line, band is: 37 53 1 + Current sample, line, band is: 37 54 1 + Current sample, line, band is: 37 55 1 + Current sample, line, band is: 37 56 1 + Current sample, line, band is: 37 57 1 + Current sample, line, band is: 37 58 1 + Current sample, line, band is: 37 59 1 + Current sample, line, band is: 37 60 1 + Current sample, line, band is: 37 61 1 + Current sample, line, band is: 37 62 1 + Current sample, line, band is: 37 63 1 + Current sample, line, band is: 37 64 1 + Current sample, line, band is: 37 65 1 + Current sample, line, band is: 37 66 1 + Current sample, line, band is: 37 67 1 + Current sample, line, band is: 37 68 1 + Current sample, line, band is: 37 69 1 + Current sample, line, band is: 37 70 1 + Current sample, line, band is: 37 71 1 + Current sample, line, band is: 37 72 1 + Current sample, line, band is: 37 73 1 + Current sample, line, band is: 37 74 1 + Current sample, line, band is: 37 75 1 + Current sample, line, band is: 37 76 1 + Current sample, line, band is: 37 77 1 + Current sample, line, band is: 37 78 1 + Current sample, line, band is: 37 79 1 + Current sample, line, band is: 37 80 1 + Current sample, line, band is: 37 81 1 + Current sample, line, band is: 37 82 1 + Current sample, line, band is: 37 83 1 + Current sample, line, band is: 37 84 1 + Current sample, line, band is: 37 85 1 + Current sample, line, band is: 37 86 1 + Current sample, line, band is: 37 87 1 + Current sample, line, band is: 37 88 1 + Current sample, line, band is: 37 89 1 + Current sample, line, band is: 37 90 1 + Current sample, line, band is: 37 91 1 + Current sample, line, band is: 37 92 1 + Current sample, line, band is: 37 93 1 + Current sample, line, band is: 37 94 1 + Current sample, line, band is: 37 95 1 + Current sample, line, band is: 37 96 1 + Current sample, line, band is: 37 97 1 + Current sample, line, band is: 37 98 1 + Current sample, line, band is: 37 99 1 + Current sample, line, band is: 37 100 1 + Current sample, line, band is: 37 101 1 + Current sample, line, band is: 37 102 1 + Current sample, line, band is: 37 103 1 + Current sample, line, band is: 37 104 1 + Current sample, line, band is: 37 105 1 + Current sample, line, band is: 37 106 1 + Current sample, line, band is: 37 107 1 + Current sample, line, band is: 37 108 1 + Current sample, line, band is: 37 109 1 + Current sample, line, band is: 37 110 1 + Current sample, line, band is: 37 111 1 + Current sample, line, band is: 37 112 1 + Current sample, line, band is: 37 113 1 + Current sample, line, band is: 37 114 1 + Current sample, line, band is: 37 115 1 + Current sample, line, band is: 37 116 1 + Current sample, line, band is: 37 117 1 + Current sample, line, band is: 37 118 1 + Current sample, line, band is: 37 119 1 + Current sample, line, band is: 37 120 1 + Current sample, line, band is: 37 121 1 + Current sample, line, band is: 37 122 1 + Current sample, line, band is: 37 123 1 + Current sample, line, band is: 37 124 1 + Current sample, line, band is: 37 125 1 + Current sample, line, band is: 37 126 1 + Current sample, line, band is: 38 1 1 + Current sample, line, band is: 38 2 1 + Current sample, line, band is: 38 3 1 + Current sample, line, band is: 38 4 1 + Current sample, line, band is: 38 5 1 + Current sample, line, band is: 38 6 1 + Current sample, line, band is: 38 7 1 + Current sample, line, band is: 38 8 1 + Current sample, line, band is: 38 9 1 + Current sample, line, band is: 38 10 1 + Current sample, line, band is: 38 11 1 + Current sample, line, band is: 38 12 1 + Current sample, line, band is: 38 13 1 + Current sample, line, band is: 38 14 1 + Current sample, line, band is: 38 15 1 + Current sample, line, band is: 38 16 1 + Current sample, line, band is: 38 17 1 + Current sample, line, band is: 38 18 1 + Current sample, line, band is: 38 19 1 + Current sample, line, band is: 38 20 1 + Current sample, line, band is: 38 21 1 + Current sample, line, band is: 38 22 1 + Current sample, line, band is: 38 23 1 + Current sample, line, band is: 38 24 1 + Current sample, line, band is: 38 25 1 + Current sample, line, band is: 38 26 1 + Current sample, line, band is: 38 27 1 + Current sample, line, band is: 38 28 1 + Current sample, line, band is: 38 29 1 + Current sample, line, band is: 38 30 1 + Current sample, line, band is: 38 31 1 + Current sample, line, band is: 38 32 1 + Current sample, line, band is: 38 33 1 + Current sample, line, band is: 38 34 1 + Current sample, line, band is: 38 35 1 + Current sample, line, band is: 38 36 1 + Current sample, line, band is: 38 37 1 + Current sample, line, band is: 38 38 1 + Current sample, line, band is: 38 39 1 + Current sample, line, band is: 38 40 1 + Current sample, line, band is: 38 41 1 + Current sample, line, band is: 38 42 1 + Current sample, line, band is: 38 43 1 + Current sample, line, band is: 38 44 1 + Current sample, line, band is: 38 45 1 + Current sample, line, band is: 38 46 1 + Current sample, line, band is: 38 47 1 + Current sample, line, band is: 38 48 1 + Current sample, line, band is: 38 49 1 + Current sample, line, band is: 38 50 1 + Current sample, line, band is: 38 51 1 + Current sample, line, band is: 38 52 1 + Current sample, line, band is: 38 53 1 + Current sample, line, band is: 38 54 1 + Current sample, line, band is: 38 55 1 + Current sample, line, band is: 38 56 1 + Current sample, line, band is: 38 57 1 + Current sample, line, band is: 38 58 1 + Current sample, line, band is: 38 59 1 + Current sample, line, band is: 38 60 1 + Current sample, line, band is: 38 61 1 + Current sample, line, band is: 38 62 1 + Current sample, line, band is: 38 63 1 + Current sample, line, band is: 38 64 1 + Current sample, line, band is: 38 65 1 + Current sample, line, band is: 38 66 1 + Current sample, line, band is: 38 67 1 + Current sample, line, band is: 38 68 1 + Current sample, line, band is: 38 69 1 + Current sample, line, band is: 38 70 1 + Current sample, line, band is: 38 71 1 + Current sample, line, band is: 38 72 1 + Current sample, line, band is: 38 73 1 + Current sample, line, band is: 38 74 1 + Current sample, line, band is: 38 75 1 + Current sample, line, band is: 38 76 1 + Current sample, line, band is: 38 77 1 + Current sample, line, band is: 38 78 1 + Current sample, line, band is: 38 79 1 + Current sample, line, band is: 38 80 1 + Current sample, line, band is: 38 81 1 + Current sample, line, band is: 38 82 1 + Current sample, line, band is: 38 83 1 + Current sample, line, band is: 38 84 1 + Current sample, line, band is: 38 85 1 + Current sample, line, band is: 38 86 1 + Current sample, line, band is: 38 87 1 + Current sample, line, band is: 38 88 1 + Current sample, line, band is: 38 89 1 + Current sample, line, band is: 38 90 1 + Current sample, line, band is: 38 91 1 + Current sample, line, band is: 38 92 1 + Current sample, line, band is: 38 93 1 + Current sample, line, band is: 38 94 1 + Current sample, line, band is: 38 95 1 + Current sample, line, band is: 38 96 1 + Current sample, line, band is: 38 97 1 + Current sample, line, band is: 38 98 1 + Current sample, line, band is: 38 99 1 + Current sample, line, band is: 38 100 1 + Current sample, line, band is: 38 101 1 + Current sample, line, band is: 38 102 1 + Current sample, line, band is: 38 103 1 + Current sample, line, band is: 38 104 1 + Current sample, line, band is: 38 105 1 + Current sample, line, band is: 38 106 1 + Current sample, line, band is: 38 107 1 + Current sample, line, band is: 38 108 1 + Current sample, line, band is: 38 109 1 + Current sample, line, band is: 38 110 1 + Current sample, line, band is: 38 111 1 + Current sample, line, band is: 38 112 1 + Current sample, line, band is: 38 113 1 + Current sample, line, band is: 38 114 1 + Current sample, line, band is: 38 115 1 + Current sample, line, band is: 38 116 1 + Current sample, line, band is: 38 117 1 + Current sample, line, band is: 38 118 1 + Current sample, line, band is: 38 119 1 + Current sample, line, band is: 38 120 1 + Current sample, line, band is: 38 121 1 + Current sample, line, band is: 38 122 1 + Current sample, line, band is: 38 123 1 + Current sample, line, band is: 38 124 1 + Current sample, line, band is: 38 125 1 + Current sample, line, band is: 38 126 1 + Current sample, line, band is: 39 1 1 + Current sample, line, band is: 39 2 1 + Current sample, line, band is: 39 3 1 + Current sample, line, band is: 39 4 1 + Current sample, line, band is: 39 5 1 + Current sample, line, band is: 39 6 1 + Current sample, line, band is: 39 7 1 + Current sample, line, band is: 39 8 1 + Current sample, line, band is: 39 9 1 + Current sample, line, band is: 39 10 1 + Current sample, line, band is: 39 11 1 + Current sample, line, band is: 39 12 1 + Current sample, line, band is: 39 13 1 + Current sample, line, band is: 39 14 1 + Current sample, line, band is: 39 15 1 + Current sample, line, band is: 39 16 1 + Current sample, line, band is: 39 17 1 + Current sample, line, band is: 39 18 1 + Current sample, line, band is: 39 19 1 + Current sample, line, band is: 39 20 1 + Current sample, line, band is: 39 21 1 + Current sample, line, band is: 39 22 1 + Current sample, line, band is: 39 23 1 + Current sample, line, band is: 39 24 1 + Current sample, line, band is: 39 25 1 + Current sample, line, band is: 39 26 1 + Current sample, line, band is: 39 27 1 + Current sample, line, band is: 39 28 1 + Current sample, line, band is: 39 29 1 + Current sample, line, band is: 39 30 1 + Current sample, line, band is: 39 31 1 + Current sample, line, band is: 39 32 1 + Current sample, line, band is: 39 33 1 + Current sample, line, band is: 39 34 1 + Current sample, line, band is: 39 35 1 + Current sample, line, band is: 39 36 1 + Current sample, line, band is: 39 37 1 + Current sample, line, band is: 39 38 1 + Current sample, line, band is: 39 39 1 + Current sample, line, band is: 39 40 1 + Current sample, line, band is: 39 41 1 + Current sample, line, band is: 39 42 1 + Current sample, line, band is: 39 43 1 + Current sample, line, band is: 39 44 1 + Current sample, line, band is: 39 45 1 + Current sample, line, band is: 39 46 1 + Current sample, line, band is: 39 47 1 + Current sample, line, band is: 39 48 1 + Current sample, line, band is: 39 49 1 + Current sample, line, band is: 39 50 1 + Current sample, line, band is: 39 51 1 + Current sample, line, band is: 39 52 1 + Current sample, line, band is: 39 53 1 + Current sample, line, band is: 39 54 1 + Current sample, line, band is: 39 55 1 + Current sample, line, band is: 39 56 1 + Current sample, line, band is: 39 57 1 + Current sample, line, band is: 39 58 1 + Current sample, line, band is: 39 59 1 + Current sample, line, band is: 39 60 1 + Current sample, line, band is: 39 61 1 + Current sample, line, band is: 39 62 1 + Current sample, line, band is: 39 63 1 + Current sample, line, band is: 39 64 1 + Current sample, line, band is: 39 65 1 + Current sample, line, band is: 39 66 1 + Current sample, line, band is: 39 67 1 + Current sample, line, band is: 39 68 1 + Current sample, line, band is: 39 69 1 + Current sample, line, band is: 39 70 1 + Current sample, line, band is: 39 71 1 + Current sample, line, band is: 39 72 1 + Current sample, line, band is: 39 73 1 + Current sample, line, band is: 39 74 1 + Current sample, line, band is: 39 75 1 + Current sample, line, band is: 39 76 1 + Current sample, line, band is: 39 77 1 + Current sample, line, band is: 39 78 1 + Current sample, line, band is: 39 79 1 + Current sample, line, band is: 39 80 1 + Current sample, line, band is: 39 81 1 + Current sample, line, band is: 39 82 1 + Current sample, line, band is: 39 83 1 + Current sample, line, band is: 39 84 1 + Current sample, line, band is: 39 85 1 + Current sample, line, band is: 39 86 1 + Current sample, line, band is: 39 87 1 + Current sample, line, band is: 39 88 1 + Current sample, line, band is: 39 89 1 + Current sample, line, band is: 39 90 1 + Current sample, line, band is: 39 91 1 + Current sample, line, band is: 39 92 1 + Current sample, line, band is: 39 93 1 + Current sample, line, band is: 39 94 1 + Current sample, line, band is: 39 95 1 + Current sample, line, band is: 39 96 1 + Current sample, line, band is: 39 97 1 + Current sample, line, band is: 39 98 1 + Current sample, line, band is: 39 99 1 + Current sample, line, band is: 39 100 1 + Current sample, line, band is: 39 101 1 + Current sample, line, band is: 39 102 1 + Current sample, line, band is: 39 103 1 + Current sample, line, band is: 39 104 1 + Current sample, line, band is: 39 105 1 + Current sample, line, band is: 39 106 1 + Current sample, line, band is: 39 107 1 + Current sample, line, band is: 39 108 1 + Current sample, line, band is: 39 109 1 + Current sample, line, band is: 39 110 1 + Current sample, line, band is: 39 111 1 + Current sample, line, band is: 39 112 1 + Current sample, line, band is: 39 113 1 + Current sample, line, band is: 39 114 1 + Current sample, line, band is: 39 115 1 + Current sample, line, band is: 39 116 1 + Current sample, line, band is: 39 117 1 + Current sample, line, band is: 39 118 1 + Current sample, line, band is: 39 119 1 + Current sample, line, band is: 39 120 1 + Current sample, line, band is: 39 121 1 + Current sample, line, band is: 39 122 1 + Current sample, line, band is: 39 123 1 + Current sample, line, band is: 39 124 1 + Current sample, line, band is: 39 125 1 + Current sample, line, band is: 39 126 1 + Current sample, line, band is: 40 1 1 + Current sample, line, band is: 40 2 1 + Current sample, line, band is: 40 3 1 + Current sample, line, band is: 40 4 1 + Current sample, line, band is: 40 5 1 + Current sample, line, band is: 40 6 1 + Current sample, line, band is: 40 7 1 + Current sample, line, band is: 40 8 1 + Current sample, line, band is: 40 9 1 + Current sample, line, band is: 40 10 1 + Current sample, line, band is: 40 11 1 + Current sample, line, band is: 40 12 1 + Current sample, line, band is: 40 13 1 + Current sample, line, band is: 40 14 1 + Current sample, line, band is: 40 15 1 + Current sample, line, band is: 40 16 1 + Current sample, line, band is: 40 17 1 + Current sample, line, band is: 40 18 1 + Current sample, line, band is: 40 19 1 + Current sample, line, band is: 40 20 1 + Current sample, line, band is: 40 21 1 + Current sample, line, band is: 40 22 1 + Current sample, line, band is: 40 23 1 + Current sample, line, band is: 40 24 1 + Current sample, line, band is: 40 25 1 + Current sample, line, band is: 40 26 1 + Current sample, line, band is: 40 27 1 + Current sample, line, band is: 40 28 1 + Current sample, line, band is: 40 29 1 + Current sample, line, band is: 40 30 1 + Current sample, line, band is: 40 31 1 + Current sample, line, band is: 40 32 1 + Current sample, line, band is: 40 33 1 + Current sample, line, band is: 40 34 1 + Current sample, line, band is: 40 35 1 + Current sample, line, band is: 40 36 1 + Current sample, line, band is: 40 37 1 + Current sample, line, band is: 40 38 1 + Current sample, line, band is: 40 39 1 + Current sample, line, band is: 40 40 1 + Current sample, line, band is: 40 41 1 + Current sample, line, band is: 40 42 1 + Current sample, line, band is: 40 43 1 + Current sample, line, band is: 40 44 1 + Current sample, line, band is: 40 45 1 + Current sample, line, band is: 40 46 1 + Current sample, line, band is: 40 47 1 + Current sample, line, band is: 40 48 1 + Current sample, line, band is: 40 49 1 + Current sample, line, band is: 40 50 1 + Current sample, line, band is: 40 51 1 + Current sample, line, band is: 40 52 1 + Current sample, line, band is: 40 53 1 + Current sample, line, band is: 40 54 1 + Current sample, line, band is: 40 55 1 + Current sample, line, band is: 40 56 1 + Current sample, line, band is: 40 57 1 + Current sample, line, band is: 40 58 1 + Current sample, line, band is: 40 59 1 + Current sample, line, band is: 40 60 1 + Current sample, line, band is: 40 61 1 + Current sample, line, band is: 40 62 1 + Current sample, line, band is: 40 63 1 + Current sample, line, band is: 40 64 1 + Current sample, line, band is: 40 65 1 + Current sample, line, band is: 40 66 1 + Current sample, line, band is: 40 67 1 + Current sample, line, band is: 40 68 1 + Current sample, line, band is: 40 69 1 + Current sample, line, band is: 40 70 1 + Current sample, line, band is: 40 71 1 + Current sample, line, band is: 40 72 1 + Current sample, line, band is: 40 73 1 + Current sample, line, band is: 40 74 1 + Current sample, line, band is: 40 75 1 + Current sample, line, band is: 40 76 1 + Current sample, line, band is: 40 77 1 + Current sample, line, band is: 40 78 1 + Current sample, line, band is: 40 79 1 + Current sample, line, band is: 40 80 1 + Current sample, line, band is: 40 81 1 + Current sample, line, band is: 40 82 1 + Current sample, line, band is: 40 83 1 + Current sample, line, band is: 40 84 1 + Current sample, line, band is: 40 85 1 + Current sample, line, band is: 40 86 1 + Current sample, line, band is: 40 87 1 + Current sample, line, band is: 40 88 1 + Current sample, line, band is: 40 89 1 + Current sample, line, band is: 40 90 1 + Current sample, line, band is: 40 91 1 + Current sample, line, band is: 40 92 1 + Current sample, line, band is: 40 93 1 + Current sample, line, band is: 40 94 1 + Current sample, line, band is: 40 95 1 + Current sample, line, band is: 40 96 1 + Current sample, line, band is: 40 97 1 + Current sample, line, band is: 40 98 1 + Current sample, line, band is: 40 99 1 + Current sample, line, band is: 40 100 1 + Current sample, line, band is: 40 101 1 + Current sample, line, band is: 40 102 1 + Current sample, line, band is: 40 103 1 + Current sample, line, band is: 40 104 1 + Current sample, line, band is: 40 105 1 + Current sample, line, band is: 40 106 1 + Current sample, line, band is: 40 107 1 + Current sample, line, band is: 40 108 1 + Current sample, line, band is: 40 109 1 + Current sample, line, band is: 40 110 1 + Current sample, line, band is: 40 111 1 + Current sample, line, band is: 40 112 1 + Current sample, line, band is: 40 113 1 + Current sample, line, band is: 40 114 1 + Current sample, line, band is: 40 115 1 + Current sample, line, band is: 40 116 1 + Current sample, line, band is: 40 117 1 + Current sample, line, band is: 40 118 1 + Current sample, line, band is: 40 119 1 + Current sample, line, band is: 40 120 1 + Current sample, line, band is: 40 121 1 + Current sample, line, band is: 40 122 1 + Current sample, line, band is: 40 123 1 + Current sample, line, band is: 40 124 1 + Current sample, line, band is: 40 125 1 + Current sample, line, band is: 40 126 1 + Current sample, line, band is: 41 1 1 + Current sample, line, band is: 41 2 1 + Current sample, line, band is: 41 3 1 + Current sample, line, band is: 41 4 1 + Current sample, line, band is: 41 5 1 + Current sample, line, band is: 41 6 1 + Current sample, line, band is: 41 7 1 + Current sample, line, band is: 41 8 1 + Current sample, line, band is: 41 9 1 + Current sample, line, band is: 41 10 1 + Current sample, line, band is: 41 11 1 + Current sample, line, band is: 41 12 1 + Current sample, line, band is: 41 13 1 + Current sample, line, band is: 41 14 1 + Current sample, line, band is: 41 15 1 + Current sample, line, band is: 41 16 1 + Current sample, line, band is: 41 17 1 + Current sample, line, band is: 41 18 1 + Current sample, line, band is: 41 19 1 + Current sample, line, band is: 41 20 1 + Current sample, line, band is: 41 21 1 + Current sample, line, band is: 41 22 1 + Current sample, line, band is: 41 23 1 + Current sample, line, band is: 41 24 1 + Current sample, line, band is: 41 25 1 + Current sample, line, band is: 41 26 1 + Current sample, line, band is: 41 27 1 + Current sample, line, band is: 41 28 1 + Current sample, line, band is: 41 29 1 + Current sample, line, band is: 41 30 1 + Current sample, line, band is: 41 31 1 + Current sample, line, band is: 41 32 1 + Current sample, line, band is: 41 33 1 + Current sample, line, band is: 41 34 1 + Current sample, line, band is: 41 35 1 + Current sample, line, band is: 41 36 1 + Current sample, line, band is: 41 37 1 + Current sample, line, band is: 41 38 1 + Current sample, line, band is: 41 39 1 + Current sample, line, band is: 41 40 1 + Current sample, line, band is: 41 41 1 + Current sample, line, band is: 41 42 1 + Current sample, line, band is: 41 43 1 + Current sample, line, band is: 41 44 1 + Current sample, line, band is: 41 45 1 + Current sample, line, band is: 41 46 1 + Current sample, line, band is: 41 47 1 + Current sample, line, band is: 41 48 1 + Current sample, line, band is: 41 49 1 + Current sample, line, band is: 41 50 1 + Current sample, line, band is: 41 51 1 + Current sample, line, band is: 41 52 1 + Current sample, line, band is: 41 53 1 + Current sample, line, band is: 41 54 1 + Current sample, line, band is: 41 55 1 + Current sample, line, band is: 41 56 1 + Current sample, line, band is: 41 57 1 + Current sample, line, band is: 41 58 1 + Current sample, line, band is: 41 59 1 + Current sample, line, band is: 41 60 1 + Current sample, line, band is: 41 61 1 + Current sample, line, band is: 41 62 1 + Current sample, line, band is: 41 63 1 + Current sample, line, band is: 41 64 1 + Current sample, line, band is: 41 65 1 + Current sample, line, band is: 41 66 1 + Current sample, line, band is: 41 67 1 + Current sample, line, band is: 41 68 1 + Current sample, line, band is: 41 69 1 + Current sample, line, band is: 41 70 1 + Current sample, line, band is: 41 71 1 + Current sample, line, band is: 41 72 1 + Current sample, line, band is: 41 73 1 + Current sample, line, band is: 41 74 1 + Current sample, line, band is: 41 75 1 + Current sample, line, band is: 41 76 1 + Current sample, line, band is: 41 77 1 + Current sample, line, band is: 41 78 1 + Current sample, line, band is: 41 79 1 + Current sample, line, band is: 41 80 1 + Current sample, line, band is: 41 81 1 + Current sample, line, band is: 41 82 1 + Current sample, line, band is: 41 83 1 + Current sample, line, band is: 41 84 1 + Current sample, line, band is: 41 85 1 + Current sample, line, band is: 41 86 1 + Current sample, line, band is: 41 87 1 + Current sample, line, band is: 41 88 1 + Current sample, line, band is: 41 89 1 + Current sample, line, band is: 41 90 1 + Current sample, line, band is: 41 91 1 + Current sample, line, band is: 41 92 1 + Current sample, line, band is: 41 93 1 + Current sample, line, band is: 41 94 1 + Current sample, line, band is: 41 95 1 + Current sample, line, band is: 41 96 1 + Current sample, line, band is: 41 97 1 + Current sample, line, band is: 41 98 1 + Current sample, line, band is: 41 99 1 + Current sample, line, band is: 41 100 1 + Current sample, line, band is: 41 101 1 + Current sample, line, band is: 41 102 1 + Current sample, line, band is: 41 103 1 + Current sample, line, band is: 41 104 1 + Current sample, line, band is: 41 105 1 + Current sample, line, band is: 41 106 1 + Current sample, line, band is: 41 107 1 + Current sample, line, band is: 41 108 1 + Current sample, line, band is: 41 109 1 + Current sample, line, band is: 41 110 1 + Current sample, line, band is: 41 111 1 + Current sample, line, band is: 41 112 1 + Current sample, line, band is: 41 113 1 + Current sample, line, band is: 41 114 1 + Current sample, line, band is: 41 115 1 + Current sample, line, band is: 41 116 1 + Current sample, line, band is: 41 117 1 + Current sample, line, band is: 41 118 1 + Current sample, line, band is: 41 119 1 + Current sample, line, band is: 41 120 1 + Current sample, line, band is: 41 121 1 + Current sample, line, band is: 41 122 1 + Current sample, line, band is: 41 123 1 + Current sample, line, band is: 41 124 1 + Current sample, line, band is: 41 125 1 + Current sample, line, band is: 41 126 1 + Current sample, line, band is: 42 1 1 + Current sample, line, band is: 42 2 1 + Current sample, line, band is: 42 3 1 + Current sample, line, band is: 42 4 1 + Current sample, line, band is: 42 5 1 + Current sample, line, band is: 42 6 1 + Current sample, line, band is: 42 7 1 + Current sample, line, band is: 42 8 1 + Current sample, line, band is: 42 9 1 + Current sample, line, band is: 42 10 1 + Current sample, line, band is: 42 11 1 + Current sample, line, band is: 42 12 1 + Current sample, line, band is: 42 13 1 + Current sample, line, band is: 42 14 1 + Current sample, line, band is: 42 15 1 + Current sample, line, band is: 42 16 1 + Current sample, line, band is: 42 17 1 + Current sample, line, band is: 42 18 1 + Current sample, line, band is: 42 19 1 + Current sample, line, band is: 42 20 1 + Current sample, line, band is: 42 21 1 + Current sample, line, band is: 42 22 1 + Current sample, line, band is: 42 23 1 + Current sample, line, band is: 42 24 1 + Current sample, line, band is: 42 25 1 + Current sample, line, band is: 42 26 1 + Current sample, line, band is: 42 27 1 + Current sample, line, band is: 42 28 1 + Current sample, line, band is: 42 29 1 + Current sample, line, band is: 42 30 1 + Current sample, line, band is: 42 31 1 + Current sample, line, band is: 42 32 1 + Current sample, line, band is: 42 33 1 + Current sample, line, band is: 42 34 1 + Current sample, line, band is: 42 35 1 + Current sample, line, band is: 42 36 1 + Current sample, line, band is: 42 37 1 + Current sample, line, band is: 42 38 1 + Current sample, line, band is: 42 39 1 + Current sample, line, band is: 42 40 1 + Current sample, line, band is: 42 41 1 + Current sample, line, band is: 42 42 1 + Current sample, line, band is: 42 43 1 + Current sample, line, band is: 42 44 1 + Current sample, line, band is: 42 45 1 + Current sample, line, band is: 42 46 1 + Current sample, line, band is: 42 47 1 + Current sample, line, band is: 42 48 1 + Current sample, line, band is: 42 49 1 + Current sample, line, band is: 42 50 1 + Current sample, line, band is: 42 51 1 + Current sample, line, band is: 42 52 1 + Current sample, line, band is: 42 53 1 + Current sample, line, band is: 42 54 1 + Current sample, line, band is: 42 55 1 + Current sample, line, band is: 42 56 1 + Current sample, line, band is: 42 57 1 + Current sample, line, band is: 42 58 1 + Current sample, line, band is: 42 59 1 + Current sample, line, band is: 42 60 1 + Current sample, line, band is: 42 61 1 + Current sample, line, band is: 42 62 1 + Current sample, line, band is: 42 63 1 + Current sample, line, band is: 42 64 1 + Current sample, line, band is: 42 65 1 + Current sample, line, band is: 42 66 1 + Current sample, line, band is: 42 67 1 + Current sample, line, band is: 42 68 1 + Current sample, line, band is: 42 69 1 + Current sample, line, band is: 42 70 1 + Current sample, line, band is: 42 71 1 + Current sample, line, band is: 42 72 1 + Current sample, line, band is: 42 73 1 + Current sample, line, band is: 42 74 1 + Current sample, line, band is: 42 75 1 + Current sample, line, band is: 42 76 1 + Current sample, line, band is: 42 77 1 + Current sample, line, band is: 42 78 1 + Current sample, line, band is: 42 79 1 + Current sample, line, band is: 42 80 1 + Current sample, line, band is: 42 81 1 + Current sample, line, band is: 42 82 1 + Current sample, line, band is: 42 83 1 + Current sample, line, band is: 42 84 1 + Current sample, line, band is: 42 85 1 + Current sample, line, band is: 42 86 1 + Current sample, line, band is: 42 87 1 + Current sample, line, band is: 42 88 1 + Current sample, line, band is: 42 89 1 + Current sample, line, band is: 42 90 1 + Current sample, line, band is: 42 91 1 + Current sample, line, band is: 42 92 1 + Current sample, line, band is: 42 93 1 + Current sample, line, band is: 42 94 1 + Current sample, line, band is: 42 95 1 + Current sample, line, band is: 42 96 1 + Current sample, line, band is: 42 97 1 + Current sample, line, band is: 42 98 1 + Current sample, line, band is: 42 99 1 + Current sample, line, band is: 42 100 1 + Current sample, line, band is: 42 101 1 + Current sample, line, band is: 42 102 1 + Current sample, line, band is: 42 103 1 + Current sample, line, band is: 42 104 1 + Current sample, line, band is: 42 105 1 + Current sample, line, band is: 42 106 1 + Current sample, line, band is: 42 107 1 + Current sample, line, band is: 42 108 1 + Current sample, line, band is: 42 109 1 + Current sample, line, band is: 42 110 1 + Current sample, line, band is: 42 111 1 + Current sample, line, band is: 42 112 1 + Current sample, line, band is: 42 113 1 + Current sample, line, band is: 42 114 1 + Current sample, line, band is: 42 115 1 + Current sample, line, band is: 42 116 1 + Current sample, line, band is: 42 117 1 + Current sample, line, band is: 42 118 1 + Current sample, line, band is: 42 119 1 + Current sample, line, band is: 42 120 1 + Current sample, line, band is: 42 121 1 + Current sample, line, band is: 42 122 1 + Current sample, line, band is: 42 123 1 + Current sample, line, band is: 42 124 1 + Current sample, line, band is: 42 125 1 + Current sample, line, band is: 42 126 1 + Current sample, line, band is: 43 1 1 + Current sample, line, band is: 43 2 1 + Current sample, line, band is: 43 3 1 + Current sample, line, band is: 43 4 1 + Current sample, line, band is: 43 5 1 + Current sample, line, band is: 43 6 1 + Current sample, line, band is: 43 7 1 + Current sample, line, band is: 43 8 1 + Current sample, line, band is: 43 9 1 + Current sample, line, band is: 43 10 1 + Current sample, line, band is: 43 11 1 + Current sample, line, band is: 43 12 1 + Current sample, line, band is: 43 13 1 + Current sample, line, band is: 43 14 1 + Current sample, line, band is: 43 15 1 + Current sample, line, band is: 43 16 1 + Current sample, line, band is: 43 17 1 + Current sample, line, band is: 43 18 1 + Current sample, line, band is: 43 19 1 + Current sample, line, band is: 43 20 1 + Current sample, line, band is: 43 21 1 + Current sample, line, band is: 43 22 1 + Current sample, line, band is: 43 23 1 + Current sample, line, band is: 43 24 1 + Current sample, line, band is: 43 25 1 + Current sample, line, band is: 43 26 1 + Current sample, line, band is: 43 27 1 + Current sample, line, band is: 43 28 1 + Current sample, line, band is: 43 29 1 + Current sample, line, band is: 43 30 1 + Current sample, line, band is: 43 31 1 + Current sample, line, band is: 43 32 1 + Current sample, line, band is: 43 33 1 + Current sample, line, band is: 43 34 1 + Current sample, line, band is: 43 35 1 + Current sample, line, band is: 43 36 1 + Current sample, line, band is: 43 37 1 + Current sample, line, band is: 43 38 1 + Current sample, line, band is: 43 39 1 + Current sample, line, band is: 43 40 1 + Current sample, line, band is: 43 41 1 + Current sample, line, band is: 43 42 1 + Current sample, line, band is: 43 43 1 + Current sample, line, band is: 43 44 1 + Current sample, line, band is: 43 45 1 + Current sample, line, band is: 43 46 1 + Current sample, line, band is: 43 47 1 + Current sample, line, band is: 43 48 1 + Current sample, line, band is: 43 49 1 + Current sample, line, band is: 43 50 1 + Current sample, line, band is: 43 51 1 + Current sample, line, band is: 43 52 1 + Current sample, line, band is: 43 53 1 + Current sample, line, band is: 43 54 1 + Current sample, line, band is: 43 55 1 + Current sample, line, band is: 43 56 1 + Current sample, line, band is: 43 57 1 + Current sample, line, band is: 43 58 1 + Current sample, line, band is: 43 59 1 + Current sample, line, band is: 43 60 1 + Current sample, line, band is: 43 61 1 + Current sample, line, band is: 43 62 1 + Current sample, line, band is: 43 63 1 + Current sample, line, band is: 43 64 1 + Current sample, line, band is: 43 65 1 + Current sample, line, band is: 43 66 1 + Current sample, line, band is: 43 67 1 + Current sample, line, band is: 43 68 1 + Current sample, line, band is: 43 69 1 + Current sample, line, band is: 43 70 1 + Current sample, line, band is: 43 71 1 + Current sample, line, band is: 43 72 1 + Current sample, line, band is: 43 73 1 + Current sample, line, band is: 43 74 1 + Current sample, line, band is: 43 75 1 + Current sample, line, band is: 43 76 1 + Current sample, line, band is: 43 77 1 + Current sample, line, band is: 43 78 1 + Current sample, line, band is: 43 79 1 + Current sample, line, band is: 43 80 1 + Current sample, line, band is: 43 81 1 + Current sample, line, band is: 43 82 1 + Current sample, line, band is: 43 83 1 + Current sample, line, band is: 43 84 1 + Current sample, line, band is: 43 85 1 + Current sample, line, band is: 43 86 1 + Current sample, line, band is: 43 87 1 + Current sample, line, band is: 43 88 1 + Current sample, line, band is: 43 89 1 + Current sample, line, band is: 43 90 1 + Current sample, line, band is: 43 91 1 + Current sample, line, band is: 43 92 1 + Current sample, line, band is: 43 93 1 + Current sample, line, band is: 43 94 1 + Current sample, line, band is: 43 95 1 + Current sample, line, band is: 43 96 1 + Current sample, line, band is: 43 97 1 + Current sample, line, band is: 43 98 1 + Current sample, line, band is: 43 99 1 + Current sample, line, band is: 43 100 1 + Current sample, line, band is: 43 101 1 + Current sample, line, band is: 43 102 1 + Current sample, line, band is: 43 103 1 + Current sample, line, band is: 43 104 1 + Current sample, line, band is: 43 105 1 + Current sample, line, band is: 43 106 1 + Current sample, line, band is: 43 107 1 + Current sample, line, band is: 43 108 1 + Current sample, line, band is: 43 109 1 + Current sample, line, band is: 43 110 1 + Current sample, line, band is: 43 111 1 + Current sample, line, band is: 43 112 1 + Current sample, line, band is: 43 113 1 + Current sample, line, band is: 43 114 1 + Current sample, line, band is: 43 115 1 + Current sample, line, band is: 43 116 1 + Current sample, line, band is: 43 117 1 + Current sample, line, band is: 43 118 1 + Current sample, line, band is: 43 119 1 + Current sample, line, band is: 43 120 1 + Current sample, line, band is: 43 121 1 + Current sample, line, band is: 43 122 1 + Current sample, line, band is: 43 123 1 + Current sample, line, band is: 43 124 1 + Current sample, line, band is: 43 125 1 + Current sample, line, band is: 43 126 1 + Current sample, line, band is: 44 1 1 + Current sample, line, band is: 44 2 1 + Current sample, line, band is: 44 3 1 + Current sample, line, band is: 44 4 1 + Current sample, line, band is: 44 5 1 + Current sample, line, band is: 44 6 1 + Current sample, line, band is: 44 7 1 + Current sample, line, band is: 44 8 1 + Current sample, line, band is: 44 9 1 + Current sample, line, band is: 44 10 1 + Current sample, line, band is: 44 11 1 + Current sample, line, band is: 44 12 1 + Current sample, line, band is: 44 13 1 + Current sample, line, band is: 44 14 1 + Current sample, line, band is: 44 15 1 + Current sample, line, band is: 44 16 1 + Current sample, line, band is: 44 17 1 + Current sample, line, band is: 44 18 1 + Current sample, line, band is: 44 19 1 + Current sample, line, band is: 44 20 1 + Current sample, line, band is: 44 21 1 + Current sample, line, band is: 44 22 1 + Current sample, line, band is: 44 23 1 + Current sample, line, band is: 44 24 1 + Current sample, line, band is: 44 25 1 + Current sample, line, band is: 44 26 1 + Current sample, line, band is: 44 27 1 + Current sample, line, band is: 44 28 1 + Current sample, line, band is: 44 29 1 + Current sample, line, band is: 44 30 1 + Current sample, line, band is: 44 31 1 + Current sample, line, band is: 44 32 1 + Current sample, line, band is: 44 33 1 + Current sample, line, band is: 44 34 1 + Current sample, line, band is: 44 35 1 + Current sample, line, band is: 44 36 1 + Current sample, line, band is: 44 37 1 + Current sample, line, band is: 44 38 1 + Current sample, line, band is: 44 39 1 + Current sample, line, band is: 44 40 1 + Current sample, line, band is: 44 41 1 + Current sample, line, band is: 44 42 1 + Current sample, line, band is: 44 43 1 + Current sample, line, band is: 44 44 1 + Current sample, line, band is: 44 45 1 + Current sample, line, band is: 44 46 1 + Current sample, line, band is: 44 47 1 + Current sample, line, band is: 44 48 1 + Current sample, line, band is: 44 49 1 + Current sample, line, band is: 44 50 1 + Current sample, line, band is: 44 51 1 + Current sample, line, band is: 44 52 1 + Current sample, line, band is: 44 53 1 + Current sample, line, band is: 44 54 1 + Current sample, line, band is: 44 55 1 + Current sample, line, band is: 44 56 1 + Current sample, line, band is: 44 57 1 + Current sample, line, band is: 44 58 1 + Current sample, line, band is: 44 59 1 + Current sample, line, band is: 44 60 1 + Current sample, line, band is: 44 61 1 + Current sample, line, band is: 44 62 1 + Current sample, line, band is: 44 63 1 + Current sample, line, band is: 44 64 1 + Current sample, line, band is: 44 65 1 + Current sample, line, band is: 44 66 1 + Current sample, line, band is: 44 67 1 + Current sample, line, band is: 44 68 1 + Current sample, line, band is: 44 69 1 + Current sample, line, band is: 44 70 1 + Current sample, line, band is: 44 71 1 + Current sample, line, band is: 44 72 1 + Current sample, line, band is: 44 73 1 + Current sample, line, band is: 44 74 1 + Current sample, line, band is: 44 75 1 + Current sample, line, band is: 44 76 1 + Current sample, line, band is: 44 77 1 + Current sample, line, band is: 44 78 1 + Current sample, line, band is: 44 79 1 + Current sample, line, band is: 44 80 1 + Current sample, line, band is: 44 81 1 + Current sample, line, band is: 44 82 1 + Current sample, line, band is: 44 83 1 + Current sample, line, band is: 44 84 1 + Current sample, line, band is: 44 85 1 + Current sample, line, band is: 44 86 1 + Current sample, line, band is: 44 87 1 + Current sample, line, band is: 44 88 1 + Current sample, line, band is: 44 89 1 + Current sample, line, band is: 44 90 1 + Current sample, line, band is: 44 91 1 + Current sample, line, band is: 44 92 1 + Current sample, line, band is: 44 93 1 + Current sample, line, band is: 44 94 1 + Current sample, line, band is: 44 95 1 + Current sample, line, band is: 44 96 1 + Current sample, line, band is: 44 97 1 + Current sample, line, band is: 44 98 1 + Current sample, line, band is: 44 99 1 + Current sample, line, band is: 44 100 1 + Current sample, line, band is: 44 101 1 + Current sample, line, band is: 44 102 1 + Current sample, line, band is: 44 103 1 + Current sample, line, band is: 44 104 1 + Current sample, line, band is: 44 105 1 + Current sample, line, band is: 44 106 1 + Current sample, line, band is: 44 107 1 + Current sample, line, band is: 44 108 1 + Current sample, line, band is: 44 109 1 + Current sample, line, band is: 44 110 1 + Current sample, line, band is: 44 111 1 + Current sample, line, band is: 44 112 1 + Current sample, line, band is: 44 113 1 + Current sample, line, band is: 44 114 1 + Current sample, line, band is: 44 115 1 + Current sample, line, band is: 44 116 1 + Current sample, line, band is: 44 117 1 + Current sample, line, band is: 44 118 1 + Current sample, line, band is: 44 119 1 + Current sample, line, band is: 44 120 1 + Current sample, line, band is: 44 121 1 + Current sample, line, band is: 44 122 1 + Current sample, line, band is: 44 123 1 + Current sample, line, band is: 44 124 1 + Current sample, line, band is: 44 125 1 + Current sample, line, band is: 44 126 1 + Current sample, line, band is: 45 1 1 + Current sample, line, band is: 45 2 1 + Current sample, line, band is: 45 3 1 + Current sample, line, band is: 45 4 1 + Current sample, line, band is: 45 5 1 + Current sample, line, band is: 45 6 1 + Current sample, line, band is: 45 7 1 + Current sample, line, band is: 45 8 1 + Current sample, line, band is: 45 9 1 + Current sample, line, band is: 45 10 1 + Current sample, line, band is: 45 11 1 + Current sample, line, band is: 45 12 1 + Current sample, line, band is: 45 13 1 + Current sample, line, band is: 45 14 1 + Current sample, line, band is: 45 15 1 + Current sample, line, band is: 45 16 1 + Current sample, line, band is: 45 17 1 + Current sample, line, band is: 45 18 1 + Current sample, line, band is: 45 19 1 + Current sample, line, band is: 45 20 1 + Current sample, line, band is: 45 21 1 + Current sample, line, band is: 45 22 1 + Current sample, line, band is: 45 23 1 + Current sample, line, band is: 45 24 1 + Current sample, line, band is: 45 25 1 + Current sample, line, band is: 45 26 1 + Current sample, line, band is: 45 27 1 + Current sample, line, band is: 45 28 1 + Current sample, line, band is: 45 29 1 + Current sample, line, band is: 45 30 1 + Current sample, line, band is: 45 31 1 + Current sample, line, band is: 45 32 1 + Current sample, line, band is: 45 33 1 + Current sample, line, band is: 45 34 1 + Current sample, line, band is: 45 35 1 + Current sample, line, band is: 45 36 1 + Current sample, line, band is: 45 37 1 + Current sample, line, band is: 45 38 1 + Current sample, line, band is: 45 39 1 + Current sample, line, band is: 45 40 1 + Current sample, line, band is: 45 41 1 + Current sample, line, band is: 45 42 1 + Current sample, line, band is: 45 43 1 + Current sample, line, band is: 45 44 1 + Current sample, line, band is: 45 45 1 + Current sample, line, band is: 45 46 1 + Current sample, line, band is: 45 47 1 + Current sample, line, band is: 45 48 1 + Current sample, line, band is: 45 49 1 + Current sample, line, band is: 45 50 1 + Current sample, line, band is: 45 51 1 + Current sample, line, band is: 45 52 1 + Current sample, line, band is: 45 53 1 + Current sample, line, band is: 45 54 1 + Current sample, line, band is: 45 55 1 + Current sample, line, band is: 45 56 1 + Current sample, line, band is: 45 57 1 + Current sample, line, band is: 45 58 1 + Current sample, line, band is: 45 59 1 + Current sample, line, band is: 45 60 1 + Current sample, line, band is: 45 61 1 + Current sample, line, band is: 45 62 1 + Current sample, line, band is: 45 63 1 + Current sample, line, band is: 45 64 1 + Current sample, line, band is: 45 65 1 + Current sample, line, band is: 45 66 1 + Current sample, line, band is: 45 67 1 + Current sample, line, band is: 45 68 1 + Current sample, line, band is: 45 69 1 + Current sample, line, band is: 45 70 1 + Current sample, line, band is: 45 71 1 + Current sample, line, band is: 45 72 1 + Current sample, line, band is: 45 73 1 + Current sample, line, band is: 45 74 1 + Current sample, line, band is: 45 75 1 + Current sample, line, band is: 45 76 1 + Current sample, line, band is: 45 77 1 + Current sample, line, band is: 45 78 1 + Current sample, line, band is: 45 79 1 + Current sample, line, band is: 45 80 1 + Current sample, line, band is: 45 81 1 + Current sample, line, band is: 45 82 1 + Current sample, line, band is: 45 83 1 + Current sample, line, band is: 45 84 1 + Current sample, line, band is: 45 85 1 + Current sample, line, band is: 45 86 1 + Current sample, line, band is: 45 87 1 + Current sample, line, band is: 45 88 1 + Current sample, line, band is: 45 89 1 + Current sample, line, band is: 45 90 1 + Current sample, line, band is: 45 91 1 + Current sample, line, band is: 45 92 1 + Current sample, line, band is: 45 93 1 + Current sample, line, band is: 45 94 1 + Current sample, line, band is: 45 95 1 + Current sample, line, band is: 45 96 1 + Current sample, line, band is: 45 97 1 + Current sample, line, band is: 45 98 1 + Current sample, line, band is: 45 99 1 + Current sample, line, band is: 45 100 1 + Current sample, line, band is: 45 101 1 + Current sample, line, band is: 45 102 1 + Current sample, line, band is: 45 103 1 + Current sample, line, band is: 45 104 1 + Current sample, line, band is: 45 105 1 + Current sample, line, band is: 45 106 1 + Current sample, line, band is: 45 107 1 + Current sample, line, band is: 45 108 1 + Current sample, line, band is: 45 109 1 + Current sample, line, band is: 45 110 1 + Current sample, line, band is: 45 111 1 + Current sample, line, band is: 45 112 1 + Current sample, line, band is: 45 113 1 + Current sample, line, band is: 45 114 1 + Current sample, line, band is: 45 115 1 + Current sample, line, band is: 45 116 1 + Current sample, line, band is: 45 117 1 + Current sample, line, band is: 45 118 1 + Current sample, line, band is: 45 119 1 + Current sample, line, band is: 45 120 1 + Current sample, line, band is: 45 121 1 + Current sample, line, band is: 45 122 1 + Current sample, line, band is: 45 123 1 + Current sample, line, band is: 45 124 1 + Current sample, line, band is: 45 125 1 + Current sample, line, band is: 45 126 1 + Current sample, line, band is: 46 1 1 + Current sample, line, band is: 46 2 1 + Current sample, line, band is: 46 3 1 + Current sample, line, band is: 46 4 1 + Current sample, line, band is: 46 5 1 + Current sample, line, band is: 46 6 1 + Current sample, line, band is: 46 7 1 + Current sample, line, band is: 46 8 1 + Current sample, line, band is: 46 9 1 + Current sample, line, band is: 46 10 1 + Current sample, line, band is: 46 11 1 + Current sample, line, band is: 46 12 1 + Current sample, line, band is: 46 13 1 + Current sample, line, band is: 46 14 1 + Current sample, line, band is: 46 15 1 + Current sample, line, band is: 46 16 1 + Current sample, line, band is: 46 17 1 + Current sample, line, band is: 46 18 1 + Current sample, line, band is: 46 19 1 + Current sample, line, band is: 46 20 1 + Current sample, line, band is: 46 21 1 + Current sample, line, band is: 46 22 1 + Current sample, line, band is: 46 23 1 + Current sample, line, band is: 46 24 1 + Current sample, line, band is: 46 25 1 + Current sample, line, band is: 46 26 1 + Current sample, line, band is: 46 27 1 + Current sample, line, band is: 46 28 1 + Current sample, line, band is: 46 29 1 + Current sample, line, band is: 46 30 1 + Current sample, line, band is: 46 31 1 + Current sample, line, band is: 46 32 1 + Current sample, line, band is: 46 33 1 + Current sample, line, band is: 46 34 1 + Current sample, line, band is: 46 35 1 + Current sample, line, band is: 46 36 1 + Current sample, line, band is: 46 37 1 + Current sample, line, band is: 46 38 1 + Current sample, line, band is: 46 39 1 + Current sample, line, band is: 46 40 1 + Current sample, line, band is: 46 41 1 + Current sample, line, band is: 46 42 1 + Current sample, line, band is: 46 43 1 + Current sample, line, band is: 46 44 1 + Current sample, line, band is: 46 45 1 + Current sample, line, band is: 46 46 1 + Current sample, line, band is: 46 47 1 + Current sample, line, band is: 46 48 1 + Current sample, line, band is: 46 49 1 + Current sample, line, band is: 46 50 1 + Current sample, line, band is: 46 51 1 + Current sample, line, band is: 46 52 1 + Current sample, line, band is: 46 53 1 + Current sample, line, band is: 46 54 1 + Current sample, line, band is: 46 55 1 + Current sample, line, band is: 46 56 1 + Current sample, line, band is: 46 57 1 + Current sample, line, band is: 46 58 1 + Current sample, line, band is: 46 59 1 + Current sample, line, band is: 46 60 1 + Current sample, line, band is: 46 61 1 + Current sample, line, band is: 46 62 1 + Current sample, line, band is: 46 63 1 + Current sample, line, band is: 46 64 1 + Current sample, line, band is: 46 65 1 + Current sample, line, band is: 46 66 1 + Current sample, line, band is: 46 67 1 + Current sample, line, band is: 46 68 1 + Current sample, line, band is: 46 69 1 + Current sample, line, band is: 46 70 1 + Current sample, line, band is: 46 71 1 + Current sample, line, band is: 46 72 1 + Current sample, line, band is: 46 73 1 + Current sample, line, band is: 46 74 1 + Current sample, line, band is: 46 75 1 + Current sample, line, band is: 46 76 1 + Current sample, line, band is: 46 77 1 + Current sample, line, band is: 46 78 1 + Current sample, line, band is: 46 79 1 + Current sample, line, band is: 46 80 1 + Current sample, line, band is: 46 81 1 + Current sample, line, band is: 46 82 1 + Current sample, line, band is: 46 83 1 + Current sample, line, band is: 46 84 1 + Current sample, line, band is: 46 85 1 + Current sample, line, band is: 46 86 1 + Current sample, line, band is: 46 87 1 + Current sample, line, band is: 46 88 1 + Current sample, line, band is: 46 89 1 + Current sample, line, band is: 46 90 1 + Current sample, line, band is: 46 91 1 + Current sample, line, band is: 46 92 1 + Current sample, line, band is: 46 93 1 + Current sample, line, band is: 46 94 1 + Current sample, line, band is: 46 95 1 + Current sample, line, band is: 46 96 1 + Current sample, line, band is: 46 97 1 + Current sample, line, band is: 46 98 1 + Current sample, line, band is: 46 99 1 + Current sample, line, band is: 46 100 1 + Current sample, line, band is: 46 101 1 + Current sample, line, band is: 46 102 1 + Current sample, line, band is: 46 103 1 + Current sample, line, band is: 46 104 1 + Current sample, line, band is: 46 105 1 + Current sample, line, band is: 46 106 1 + Current sample, line, band is: 46 107 1 + Current sample, line, band is: 46 108 1 + Current sample, line, band is: 46 109 1 + Current sample, line, band is: 46 110 1 + Current sample, line, band is: 46 111 1 + Current sample, line, band is: 46 112 1 + Current sample, line, band is: 46 113 1 + Current sample, line, band is: 46 114 1 + Current sample, line, band is: 46 115 1 + Current sample, line, band is: 46 116 1 + Current sample, line, band is: 46 117 1 + Current sample, line, band is: 46 118 1 + Current sample, line, band is: 46 119 1 + Current sample, line, band is: 46 120 1 + Current sample, line, band is: 46 121 1 + Current sample, line, band is: 46 122 1 + Current sample, line, band is: 46 123 1 + Current sample, line, band is: 46 124 1 + Current sample, line, band is: 46 125 1 + Current sample, line, band is: 46 126 1 + Current sample, line, band is: 47 1 1 + Current sample, line, band is: 47 2 1 + Current sample, line, band is: 47 3 1 + Current sample, line, band is: 47 4 1 + Current sample, line, band is: 47 5 1 + Current sample, line, band is: 47 6 1 + Current sample, line, band is: 47 7 1 + Current sample, line, band is: 47 8 1 + Current sample, line, band is: 47 9 1 + Current sample, line, band is: 47 10 1 + Current sample, line, band is: 47 11 1 + Current sample, line, band is: 47 12 1 + Current sample, line, band is: 47 13 1 + Current sample, line, band is: 47 14 1 + Current sample, line, band is: 47 15 1 + Current sample, line, band is: 47 16 1 + Current sample, line, band is: 47 17 1 + Current sample, line, band is: 47 18 1 + Current sample, line, band is: 47 19 1 + Current sample, line, band is: 47 20 1 + Current sample, line, band is: 47 21 1 + Current sample, line, band is: 47 22 1 + Current sample, line, band is: 47 23 1 + Current sample, line, band is: 47 24 1 + Current sample, line, band is: 47 25 1 + Current sample, line, band is: 47 26 1 + Current sample, line, band is: 47 27 1 + Current sample, line, band is: 47 28 1 + Current sample, line, band is: 47 29 1 + Current sample, line, band is: 47 30 1 + Current sample, line, band is: 47 31 1 + Current sample, line, band is: 47 32 1 + Current sample, line, band is: 47 33 1 + Current sample, line, band is: 47 34 1 + Current sample, line, band is: 47 35 1 + Current sample, line, band is: 47 36 1 + Current sample, line, band is: 47 37 1 + Current sample, line, band is: 47 38 1 + Current sample, line, band is: 47 39 1 + Current sample, line, band is: 47 40 1 + Current sample, line, band is: 47 41 1 + Current sample, line, band is: 47 42 1 + Current sample, line, band is: 47 43 1 + Current sample, line, band is: 47 44 1 + Current sample, line, band is: 47 45 1 + Current sample, line, band is: 47 46 1 + Current sample, line, band is: 47 47 1 + Current sample, line, band is: 47 48 1 + Current sample, line, band is: 47 49 1 + Current sample, line, band is: 47 50 1 + Current sample, line, band is: 47 51 1 + Current sample, line, band is: 47 52 1 + Current sample, line, band is: 47 53 1 + Current sample, line, band is: 47 54 1 + Current sample, line, band is: 47 55 1 + Current sample, line, band is: 47 56 1 + Current sample, line, band is: 47 57 1 + Current sample, line, band is: 47 58 1 + Current sample, line, band is: 47 59 1 + Current sample, line, band is: 47 60 1 + Current sample, line, band is: 47 61 1 + Current sample, line, band is: 47 62 1 + Current sample, line, band is: 47 63 1 + Current sample, line, band is: 47 64 1 + Current sample, line, band is: 47 65 1 + Current sample, line, band is: 47 66 1 + Current sample, line, band is: 47 67 1 + Current sample, line, band is: 47 68 1 + Current sample, line, band is: 47 69 1 + Current sample, line, band is: 47 70 1 + Current sample, line, band is: 47 71 1 + Current sample, line, band is: 47 72 1 + Current sample, line, band is: 47 73 1 + Current sample, line, band is: 47 74 1 + Current sample, line, band is: 47 75 1 + Current sample, line, band is: 47 76 1 + Current sample, line, band is: 47 77 1 + Current sample, line, band is: 47 78 1 + Current sample, line, band is: 47 79 1 + Current sample, line, band is: 47 80 1 + Current sample, line, band is: 47 81 1 + Current sample, line, band is: 47 82 1 + Current sample, line, band is: 47 83 1 + Current sample, line, band is: 47 84 1 + Current sample, line, band is: 47 85 1 + Current sample, line, band is: 47 86 1 + Current sample, line, band is: 47 87 1 + Current sample, line, band is: 47 88 1 + Current sample, line, band is: 47 89 1 + Current sample, line, band is: 47 90 1 + Current sample, line, band is: 47 91 1 + Current sample, line, band is: 47 92 1 + Current sample, line, band is: 47 93 1 + Current sample, line, band is: 47 94 1 + Current sample, line, band is: 47 95 1 + Current sample, line, band is: 47 96 1 + Current sample, line, band is: 47 97 1 + Current sample, line, band is: 47 98 1 + Current sample, line, band is: 47 99 1 + Current sample, line, band is: 47 100 1 + Current sample, line, band is: 47 101 1 + Current sample, line, band is: 47 102 1 + Current sample, line, band is: 47 103 1 + Current sample, line, band is: 47 104 1 + Current sample, line, band is: 47 105 1 + Current sample, line, band is: 47 106 1 + Current sample, line, band is: 47 107 1 + Current sample, line, band is: 47 108 1 + Current sample, line, band is: 47 109 1 + Current sample, line, band is: 47 110 1 + Current sample, line, band is: 47 111 1 + Current sample, line, band is: 47 112 1 + Current sample, line, band is: 47 113 1 + Current sample, line, band is: 47 114 1 + Current sample, line, band is: 47 115 1 + Current sample, line, band is: 47 116 1 + Current sample, line, band is: 47 117 1 + Current sample, line, band is: 47 118 1 + Current sample, line, band is: 47 119 1 + Current sample, line, band is: 47 120 1 + Current sample, line, band is: 47 121 1 + Current sample, line, band is: 47 122 1 + Current sample, line, band is: 47 123 1 + Current sample, line, band is: 47 124 1 + Current sample, line, band is: 47 125 1 + Current sample, line, band is: 47 126 1 + Current sample, line, band is: 48 1 1 + Current sample, line, band is: 48 2 1 + Current sample, line, band is: 48 3 1 + Current sample, line, band is: 48 4 1 + Current sample, line, band is: 48 5 1 + Current sample, line, band is: 48 6 1 + Current sample, line, band is: 48 7 1 + Current sample, line, band is: 48 8 1 + Current sample, line, band is: 48 9 1 + Current sample, line, band is: 48 10 1 + Current sample, line, band is: 48 11 1 + Current sample, line, band is: 48 12 1 + Current sample, line, band is: 48 13 1 + Current sample, line, band is: 48 14 1 + Current sample, line, band is: 48 15 1 + Current sample, line, band is: 48 16 1 + Current sample, line, band is: 48 17 1 + Current sample, line, band is: 48 18 1 + Current sample, line, band is: 48 19 1 + Current sample, line, band is: 48 20 1 + Current sample, line, band is: 48 21 1 + Current sample, line, band is: 48 22 1 + Current sample, line, band is: 48 23 1 + Current sample, line, band is: 48 24 1 + Current sample, line, band is: 48 25 1 + Current sample, line, band is: 48 26 1 + Current sample, line, band is: 48 27 1 + Current sample, line, band is: 48 28 1 + Current sample, line, band is: 48 29 1 + Current sample, line, band is: 48 30 1 + Current sample, line, band is: 48 31 1 + Current sample, line, band is: 48 32 1 + Current sample, line, band is: 48 33 1 + Current sample, line, band is: 48 34 1 + Current sample, line, band is: 48 35 1 + Current sample, line, band is: 48 36 1 + Current sample, line, band is: 48 37 1 + Current sample, line, band is: 48 38 1 + Current sample, line, band is: 48 39 1 + Current sample, line, band is: 48 40 1 + Current sample, line, band is: 48 41 1 + Current sample, line, band is: 48 42 1 + Current sample, line, band is: 48 43 1 + Current sample, line, band is: 48 44 1 + Current sample, line, band is: 48 45 1 + Current sample, line, band is: 48 46 1 + Current sample, line, band is: 48 47 1 + Current sample, line, band is: 48 48 1 + Current sample, line, band is: 48 49 1 + Current sample, line, band is: 48 50 1 + Current sample, line, band is: 48 51 1 + Current sample, line, band is: 48 52 1 + Current sample, line, band is: 48 53 1 + Current sample, line, band is: 48 54 1 + Current sample, line, band is: 48 55 1 + Current sample, line, band is: 48 56 1 + Current sample, line, band is: 48 57 1 + Current sample, line, band is: 48 58 1 + Current sample, line, band is: 48 59 1 + Current sample, line, band is: 48 60 1 + Current sample, line, band is: 48 61 1 + Current sample, line, band is: 48 62 1 + Current sample, line, band is: 48 63 1 + Current sample, line, band is: 48 64 1 + Current sample, line, band is: 48 65 1 + Current sample, line, band is: 48 66 1 + Current sample, line, band is: 48 67 1 + Current sample, line, band is: 48 68 1 + Current sample, line, band is: 48 69 1 + Current sample, line, band is: 48 70 1 + Current sample, line, band is: 48 71 1 + Current sample, line, band is: 48 72 1 + Current sample, line, band is: 48 73 1 + Current sample, line, band is: 48 74 1 + Current sample, line, band is: 48 75 1 + Current sample, line, band is: 48 76 1 + Current sample, line, band is: 48 77 1 + Current sample, line, band is: 48 78 1 + Current sample, line, band is: 48 79 1 + Current sample, line, band is: 48 80 1 + Current sample, line, band is: 48 81 1 + Current sample, line, band is: 48 82 1 + Current sample, line, band is: 48 83 1 + Current sample, line, band is: 48 84 1 + Current sample, line, band is: 48 85 1 + Current sample, line, band is: 48 86 1 + Current sample, line, band is: 48 87 1 + Current sample, line, band is: 48 88 1 + Current sample, line, band is: 48 89 1 + Current sample, line, band is: 48 90 1 + Current sample, line, band is: 48 91 1 + Current sample, line, band is: 48 92 1 + Current sample, line, band is: 48 93 1 + Current sample, line, band is: 48 94 1 + Current sample, line, band is: 48 95 1 + Current sample, line, band is: 48 96 1 + Current sample, line, band is: 48 97 1 + Current sample, line, band is: 48 98 1 + Current sample, line, band is: 48 99 1 + Current sample, line, band is: 48 100 1 + Current sample, line, band is: 48 101 1 + Current sample, line, band is: 48 102 1 + Current sample, line, band is: 48 103 1 + Current sample, line, band is: 48 104 1 + Current sample, line, band is: 48 105 1 + Current sample, line, band is: 48 106 1 + Current sample, line, band is: 48 107 1 + Current sample, line, band is: 48 108 1 + Current sample, line, band is: 48 109 1 + Current sample, line, band is: 48 110 1 + Current sample, line, band is: 48 111 1 + Current sample, line, band is: 48 112 1 + Current sample, line, band is: 48 113 1 + Current sample, line, band is: 48 114 1 + Current sample, line, band is: 48 115 1 + Current sample, line, band is: 48 116 1 + Current sample, line, band is: 48 117 1 + Current sample, line, band is: 48 118 1 + Current sample, line, band is: 48 119 1 + Current sample, line, band is: 48 120 1 + Current sample, line, band is: 48 121 1 + Current sample, line, band is: 48 122 1 + Current sample, line, band is: 48 123 1 + Current sample, line, band is: 48 124 1 + Current sample, line, band is: 48 125 1 + Current sample, line, band is: 48 126 1 + Current sample, line, band is: 49 1 1 + Current sample, line, band is: 49 2 1 + Current sample, line, band is: 49 3 1 + Current sample, line, band is: 49 4 1 + Current sample, line, band is: 49 5 1 + Current sample, line, band is: 49 6 1 + Current sample, line, band is: 49 7 1 + Current sample, line, band is: 49 8 1 + Current sample, line, band is: 49 9 1 + Current sample, line, band is: 49 10 1 + Current sample, line, band is: 49 11 1 + Current sample, line, band is: 49 12 1 + Current sample, line, band is: 49 13 1 + Current sample, line, band is: 49 14 1 + Current sample, line, band is: 49 15 1 + Current sample, line, band is: 49 16 1 + Current sample, line, band is: 49 17 1 + Current sample, line, band is: 49 18 1 + Current sample, line, band is: 49 19 1 + Current sample, line, band is: 49 20 1 + Current sample, line, band is: 49 21 1 + Current sample, line, band is: 49 22 1 + Current sample, line, band is: 49 23 1 + Current sample, line, band is: 49 24 1 + Current sample, line, band is: 49 25 1 + Current sample, line, band is: 49 26 1 + Current sample, line, band is: 49 27 1 + Current sample, line, band is: 49 28 1 + Current sample, line, band is: 49 29 1 + Current sample, line, band is: 49 30 1 + Current sample, line, band is: 49 31 1 + Current sample, line, band is: 49 32 1 + Current sample, line, band is: 49 33 1 + Current sample, line, band is: 49 34 1 + Current sample, line, band is: 49 35 1 + Current sample, line, band is: 49 36 1 + Current sample, line, band is: 49 37 1 + Current sample, line, band is: 49 38 1 + Current sample, line, band is: 49 39 1 + Current sample, line, band is: 49 40 1 + Current sample, line, band is: 49 41 1 + Current sample, line, band is: 49 42 1 + Current sample, line, band is: 49 43 1 + Current sample, line, band is: 49 44 1 + Current sample, line, band is: 49 45 1 + Current sample, line, band is: 49 46 1 + Current sample, line, band is: 49 47 1 + Current sample, line, band is: 49 48 1 + Current sample, line, band is: 49 49 1 + Current sample, line, band is: 49 50 1 + Current sample, line, band is: 49 51 1 + Current sample, line, band is: 49 52 1 + Current sample, line, band is: 49 53 1 + Current sample, line, band is: 49 54 1 + Current sample, line, band is: 49 55 1 + Current sample, line, band is: 49 56 1 + Current sample, line, band is: 49 57 1 + Current sample, line, band is: 49 58 1 + Current sample, line, band is: 49 59 1 + Current sample, line, band is: 49 60 1 + Current sample, line, band is: 49 61 1 + Current sample, line, band is: 49 62 1 + Current sample, line, band is: 49 63 1 + Current sample, line, band is: 49 64 1 + Current sample, line, band is: 49 65 1 + Current sample, line, band is: 49 66 1 + Current sample, line, band is: 49 67 1 + Current sample, line, band is: 49 68 1 + Current sample, line, band is: 49 69 1 + Current sample, line, band is: 49 70 1 + Current sample, line, band is: 49 71 1 + Current sample, line, band is: 49 72 1 + Current sample, line, band is: 49 73 1 + Current sample, line, band is: 49 74 1 + Current sample, line, band is: 49 75 1 + Current sample, line, band is: 49 76 1 + Current sample, line, band is: 49 77 1 + Current sample, line, band is: 49 78 1 + Current sample, line, band is: 49 79 1 + Current sample, line, band is: 49 80 1 + Current sample, line, band is: 49 81 1 + Current sample, line, band is: 49 82 1 + Current sample, line, band is: 49 83 1 + Current sample, line, band is: 49 84 1 + Current sample, line, band is: 49 85 1 + Current sample, line, band is: 49 86 1 + Current sample, line, band is: 49 87 1 + Current sample, line, band is: 49 88 1 + Current sample, line, band is: 49 89 1 + Current sample, line, band is: 49 90 1 + Current sample, line, band is: 49 91 1 + Current sample, line, band is: 49 92 1 + Current sample, line, band is: 49 93 1 + Current sample, line, band is: 49 94 1 + Current sample, line, band is: 49 95 1 + Current sample, line, band is: 49 96 1 + Current sample, line, band is: 49 97 1 + Current sample, line, band is: 49 98 1 + Current sample, line, band is: 49 99 1 + Current sample, line, band is: 49 100 1 + Current sample, line, band is: 49 101 1 + Current sample, line, band is: 49 102 1 + Current sample, line, band is: 49 103 1 + Current sample, line, band is: 49 104 1 + Current sample, line, band is: 49 105 1 + Current sample, line, band is: 49 106 1 + Current sample, line, band is: 49 107 1 + Current sample, line, band is: 49 108 1 + Current sample, line, band is: 49 109 1 + Current sample, line, band is: 49 110 1 + Current sample, line, band is: 49 111 1 + Current sample, line, band is: 49 112 1 + Current sample, line, band is: 49 113 1 + Current sample, line, band is: 49 114 1 + Current sample, line, band is: 49 115 1 + Current sample, line, band is: 49 116 1 + Current sample, line, band is: 49 117 1 + Current sample, line, band is: 49 118 1 + Current sample, line, band is: 49 119 1 + Current sample, line, band is: 49 120 1 + Current sample, line, band is: 49 121 1 + Current sample, line, band is: 49 122 1 + Current sample, line, band is: 49 123 1 + Current sample, line, band is: 49 124 1 + Current sample, line, band is: 49 125 1 + Current sample, line, band is: 49 126 1 + Current sample, line, band is: 50 1 1 + Current sample, line, band is: 50 2 1 + Current sample, line, band is: 50 3 1 + Current sample, line, band is: 50 4 1 + Current sample, line, band is: 50 5 1 + Current sample, line, band is: 50 6 1 + Current sample, line, band is: 50 7 1 + Current sample, line, band is: 50 8 1 + Current sample, line, band is: 50 9 1 + Current sample, line, band is: 50 10 1 + Current sample, line, band is: 50 11 1 + Current sample, line, band is: 50 12 1 + Current sample, line, band is: 50 13 1 + Current sample, line, band is: 50 14 1 + Current sample, line, band is: 50 15 1 + Current sample, line, band is: 50 16 1 + Current sample, line, band is: 50 17 1 + Current sample, line, band is: 50 18 1 + Current sample, line, band is: 50 19 1 + Current sample, line, band is: 50 20 1 + Current sample, line, band is: 50 21 1 + Current sample, line, band is: 50 22 1 + Current sample, line, band is: 50 23 1 + Current sample, line, band is: 50 24 1 + Current sample, line, band is: 50 25 1 + Current sample, line, band is: 50 26 1 + Current sample, line, band is: 50 27 1 + Current sample, line, band is: 50 28 1 + Current sample, line, band is: 50 29 1 + Current sample, line, band is: 50 30 1 + Current sample, line, band is: 50 31 1 + Current sample, line, band is: 50 32 1 + Current sample, line, band is: 50 33 1 + Current sample, line, band is: 50 34 1 + Current sample, line, band is: 50 35 1 + Current sample, line, band is: 50 36 1 + Current sample, line, band is: 50 37 1 + Current sample, line, band is: 50 38 1 + Current sample, line, band is: 50 39 1 + Current sample, line, band is: 50 40 1 + Current sample, line, band is: 50 41 1 + Current sample, line, band is: 50 42 1 + Current sample, line, band is: 50 43 1 + Current sample, line, band is: 50 44 1 + Current sample, line, band is: 50 45 1 + Current sample, line, band is: 50 46 1 + Current sample, line, band is: 50 47 1 + Current sample, line, band is: 50 48 1 + Current sample, line, band is: 50 49 1 + Current sample, line, band is: 50 50 1 + Current sample, line, band is: 50 51 1 + Current sample, line, band is: 50 52 1 + Current sample, line, band is: 50 53 1 + Current sample, line, band is: 50 54 1 + Current sample, line, band is: 50 55 1 + Current sample, line, band is: 50 56 1 + Current sample, line, band is: 50 57 1 + Current sample, line, band is: 50 58 1 + Current sample, line, band is: 50 59 1 + Current sample, line, band is: 50 60 1 + Current sample, line, band is: 50 61 1 + Current sample, line, band is: 50 62 1 + Current sample, line, band is: 50 63 1 + Current sample, line, band is: 50 64 1 + Current sample, line, band is: 50 65 1 + Current sample, line, band is: 50 66 1 + Current sample, line, band is: 50 67 1 + Current sample, line, band is: 50 68 1 + Current sample, line, band is: 50 69 1 + Current sample, line, band is: 50 70 1 + Current sample, line, band is: 50 71 1 + Current sample, line, band is: 50 72 1 + Current sample, line, band is: 50 73 1 + Current sample, line, band is: 50 74 1 + Current sample, line, band is: 50 75 1 + Current sample, line, band is: 50 76 1 + Current sample, line, band is: 50 77 1 + Current sample, line, band is: 50 78 1 + Current sample, line, band is: 50 79 1 + Current sample, line, band is: 50 80 1 + Current sample, line, band is: 50 81 1 + Current sample, line, band is: 50 82 1 + Current sample, line, band is: 50 83 1 + Current sample, line, band is: 50 84 1 + Current sample, line, band is: 50 85 1 + Current sample, line, band is: 50 86 1 + Current sample, line, band is: 50 87 1 + Current sample, line, band is: 50 88 1 + Current sample, line, band is: 50 89 1 + Current sample, line, band is: 50 90 1 + Current sample, line, band is: 50 91 1 + Current sample, line, band is: 50 92 1 + Current sample, line, band is: 50 93 1 + Current sample, line, band is: 50 94 1 + Current sample, line, band is: 50 95 1 + Current sample, line, band is: 50 96 1 + Current sample, line, band is: 50 97 1 + Current sample, line, band is: 50 98 1 + Current sample, line, band is: 50 99 1 + Current sample, line, band is: 50 100 1 + Current sample, line, band is: 50 101 1 + Current sample, line, band is: 50 102 1 + Current sample, line, band is: 50 103 1 + Current sample, line, band is: 50 104 1 + Current sample, line, band is: 50 105 1 + Current sample, line, band is: 50 106 1 + Current sample, line, band is: 50 107 1 + Current sample, line, band is: 50 108 1 + Current sample, line, band is: 50 109 1 + Current sample, line, band is: 50 110 1 + Current sample, line, band is: 50 111 1 + Current sample, line, band is: 50 112 1 + Current sample, line, band is: 50 113 1 + Current sample, line, band is: 50 114 1 + Current sample, line, band is: 50 115 1 + Current sample, line, band is: 50 116 1 + Current sample, line, band is: 50 117 1 + Current sample, line, band is: 50 118 1 + Current sample, line, band is: 50 119 1 + Current sample, line, band is: 50 120 1 + Current sample, line, band is: 50 121 1 + Current sample, line, band is: 50 122 1 + Current sample, line, band is: 50 123 1 + Current sample, line, band is: 50 124 1 + Current sample, line, band is: 50 125 1 + Current sample, line, band is: 50 126 1 + Current sample, line, band is: 51 1 1 + Current sample, line, band is: 51 2 1 + Current sample, line, band is: 51 3 1 + Current sample, line, band is: 51 4 1 + Current sample, line, band is: 51 5 1 + Current sample, line, band is: 51 6 1 + Current sample, line, band is: 51 7 1 + Current sample, line, band is: 51 8 1 + Current sample, line, band is: 51 9 1 + Current sample, line, band is: 51 10 1 + Current sample, line, band is: 51 11 1 + Current sample, line, band is: 51 12 1 + Current sample, line, band is: 51 13 1 + Current sample, line, band is: 51 14 1 + Current sample, line, band is: 51 15 1 + Current sample, line, band is: 51 16 1 + Current sample, line, band is: 51 17 1 + Current sample, line, band is: 51 18 1 + Current sample, line, band is: 51 19 1 + Current sample, line, band is: 51 20 1 + Current sample, line, band is: 51 21 1 + Current sample, line, band is: 51 22 1 + Current sample, line, band is: 51 23 1 + Current sample, line, band is: 51 24 1 + Current sample, line, band is: 51 25 1 + Current sample, line, band is: 51 26 1 + Current sample, line, band is: 51 27 1 + Current sample, line, band is: 51 28 1 + Current sample, line, band is: 51 29 1 + Current sample, line, band is: 51 30 1 + Current sample, line, band is: 51 31 1 + Current sample, line, band is: 51 32 1 + Current sample, line, band is: 51 33 1 + Current sample, line, band is: 51 34 1 + Current sample, line, band is: 51 35 1 + Current sample, line, band is: 51 36 1 + Current sample, line, band is: 51 37 1 + Current sample, line, band is: 51 38 1 + Current sample, line, band is: 51 39 1 + Current sample, line, band is: 51 40 1 + Current sample, line, band is: 51 41 1 + Current sample, line, band is: 51 42 1 + Current sample, line, band is: 51 43 1 + Current sample, line, band is: 51 44 1 + Current sample, line, band is: 51 45 1 + Current sample, line, band is: 51 46 1 + Current sample, line, band is: 51 47 1 + Current sample, line, band is: 51 48 1 + Current sample, line, band is: 51 49 1 + Current sample, line, band is: 51 50 1 + Current sample, line, band is: 51 51 1 + Current sample, line, band is: 51 52 1 + Current sample, line, band is: 51 53 1 + Current sample, line, band is: 51 54 1 + Current sample, line, band is: 51 55 1 + Current sample, line, band is: 51 56 1 + Current sample, line, band is: 51 57 1 + Current sample, line, band is: 51 58 1 + Current sample, line, band is: 51 59 1 + Current sample, line, band is: 51 60 1 + Current sample, line, band is: 51 61 1 + Current sample, line, band is: 51 62 1 + Current sample, line, band is: 51 63 1 + Current sample, line, band is: 51 64 1 + Current sample, line, band is: 51 65 1 + Current sample, line, band is: 51 66 1 + Current sample, line, band is: 51 67 1 + Current sample, line, band is: 51 68 1 + Current sample, line, band is: 51 69 1 + Current sample, line, band is: 51 70 1 + Current sample, line, band is: 51 71 1 + Current sample, line, band is: 51 72 1 + Current sample, line, band is: 51 73 1 + Current sample, line, band is: 51 74 1 + Current sample, line, band is: 51 75 1 + Current sample, line, band is: 51 76 1 + Current sample, line, band is: 51 77 1 + Current sample, line, band is: 51 78 1 + Current sample, line, band is: 51 79 1 + Current sample, line, band is: 51 80 1 + Current sample, line, band is: 51 81 1 + Current sample, line, band is: 51 82 1 + Current sample, line, band is: 51 83 1 + Current sample, line, band is: 51 84 1 + Current sample, line, band is: 51 85 1 + Current sample, line, band is: 51 86 1 + Current sample, line, band is: 51 87 1 + Current sample, line, band is: 51 88 1 + Current sample, line, band is: 51 89 1 + Current sample, line, band is: 51 90 1 + Current sample, line, band is: 51 91 1 + Current sample, line, band is: 51 92 1 + Current sample, line, band is: 51 93 1 + Current sample, line, band is: 51 94 1 + Current sample, line, band is: 51 95 1 + Current sample, line, band is: 51 96 1 + Current sample, line, band is: 51 97 1 + Current sample, line, band is: 51 98 1 + Current sample, line, band is: 51 99 1 + Current sample, line, band is: 51 100 1 + Current sample, line, band is: 51 101 1 + Current sample, line, band is: 51 102 1 + Current sample, line, band is: 51 103 1 + Current sample, line, band is: 51 104 1 + Current sample, line, band is: 51 105 1 + Current sample, line, band is: 51 106 1 + Current sample, line, band is: 51 107 1 + Current sample, line, band is: 51 108 1 + Current sample, line, band is: 51 109 1 + Current sample, line, band is: 51 110 1 + Current sample, line, band is: 51 111 1 + Current sample, line, band is: 51 112 1 + Current sample, line, band is: 51 113 1 + Current sample, line, band is: 51 114 1 + Current sample, line, band is: 51 115 1 + Current sample, line, band is: 51 116 1 + Current sample, line, band is: 51 117 1 + Current sample, line, band is: 51 118 1 + Current sample, line, band is: 51 119 1 + Current sample, line, band is: 51 120 1 + Current sample, line, band is: 51 121 1 + Current sample, line, band is: 51 122 1 + Current sample, line, band is: 51 123 1 + Current sample, line, band is: 51 124 1 + Current sample, line, band is: 51 125 1 + Current sample, line, band is: 51 126 1 + Current sample, line, band is: 52 1 1 + Current sample, line, band is: 52 2 1 + Current sample, line, band is: 52 3 1 + Current sample, line, band is: 52 4 1 + Current sample, line, band is: 52 5 1 + Current sample, line, band is: 52 6 1 + Current sample, line, band is: 52 7 1 + Current sample, line, band is: 52 8 1 + Current sample, line, band is: 52 9 1 + Current sample, line, band is: 52 10 1 + Current sample, line, band is: 52 11 1 + Current sample, line, band is: 52 12 1 + Current sample, line, band is: 52 13 1 + Current sample, line, band is: 52 14 1 + Current sample, line, band is: 52 15 1 + Current sample, line, band is: 52 16 1 + Current sample, line, band is: 52 17 1 + Current sample, line, band is: 52 18 1 + Current sample, line, band is: 52 19 1 + Current sample, line, band is: 52 20 1 + Current sample, line, band is: 52 21 1 + Current sample, line, band is: 52 22 1 + Current sample, line, band is: 52 23 1 + Current sample, line, band is: 52 24 1 + Current sample, line, band is: 52 25 1 + Current sample, line, band is: 52 26 1 + Current sample, line, band is: 52 27 1 + Current sample, line, band is: 52 28 1 + Current sample, line, band is: 52 29 1 + Current sample, line, band is: 52 30 1 + Current sample, line, band is: 52 31 1 + Current sample, line, band is: 52 32 1 + Current sample, line, band is: 52 33 1 + Current sample, line, band is: 52 34 1 + Current sample, line, band is: 52 35 1 + Current sample, line, band is: 52 36 1 + Current sample, line, band is: 52 37 1 + Current sample, line, band is: 52 38 1 + Current sample, line, band is: 52 39 1 + Current sample, line, band is: 52 40 1 + Current sample, line, band is: 52 41 1 + Current sample, line, band is: 52 42 1 + Current sample, line, band is: 52 43 1 + Current sample, line, band is: 52 44 1 + Current sample, line, band is: 52 45 1 + Current sample, line, band is: 52 46 1 + Current sample, line, band is: 52 47 1 + Current sample, line, band is: 52 48 1 + Current sample, line, band is: 52 49 1 + Current sample, line, band is: 52 50 1 + Current sample, line, band is: 52 51 1 + Current sample, line, band is: 52 52 1 + Current sample, line, band is: 52 53 1 + Current sample, line, band is: 52 54 1 + Current sample, line, band is: 52 55 1 + Current sample, line, band is: 52 56 1 + Current sample, line, band is: 52 57 1 + Current sample, line, band is: 52 58 1 + Current sample, line, band is: 52 59 1 + Current sample, line, band is: 52 60 1 + Current sample, line, band is: 52 61 1 + Current sample, line, band is: 52 62 1 + Current sample, line, band is: 52 63 1 + Current sample, line, band is: 52 64 1 + Current sample, line, band is: 52 65 1 + Current sample, line, band is: 52 66 1 + Current sample, line, band is: 52 67 1 + Current sample, line, band is: 52 68 1 + Current sample, line, band is: 52 69 1 + Current sample, line, band is: 52 70 1 + Current sample, line, band is: 52 71 1 + Current sample, line, band is: 52 72 1 + Current sample, line, band is: 52 73 1 + Current sample, line, band is: 52 74 1 + Current sample, line, band is: 52 75 1 + Current sample, line, band is: 52 76 1 + Current sample, line, band is: 52 77 1 + Current sample, line, band is: 52 78 1 + Current sample, line, band is: 52 79 1 + Current sample, line, band is: 52 80 1 + Current sample, line, band is: 52 81 1 + Current sample, line, band is: 52 82 1 + Current sample, line, band is: 52 83 1 + Current sample, line, band is: 52 84 1 + Current sample, line, band is: 52 85 1 + Current sample, line, band is: 52 86 1 + Current sample, line, band is: 52 87 1 + Current sample, line, band is: 52 88 1 + Current sample, line, band is: 52 89 1 + Current sample, line, band is: 52 90 1 + Current sample, line, band is: 52 91 1 + Current sample, line, band is: 52 92 1 + Current sample, line, band is: 52 93 1 + Current sample, line, band is: 52 94 1 + Current sample, line, band is: 52 95 1 + Current sample, line, band is: 52 96 1 + Current sample, line, band is: 52 97 1 + Current sample, line, band is: 52 98 1 + Current sample, line, band is: 52 99 1 + Current sample, line, band is: 52 100 1 + Current sample, line, band is: 52 101 1 + Current sample, line, band is: 52 102 1 + Current sample, line, band is: 52 103 1 + Current sample, line, band is: 52 104 1 + Current sample, line, band is: 52 105 1 + Current sample, line, band is: 52 106 1 + Current sample, line, band is: 52 107 1 + Current sample, line, band is: 52 108 1 + Current sample, line, band is: 52 109 1 + Current sample, line, band is: 52 110 1 + Current sample, line, band is: 52 111 1 + Current sample, line, band is: 52 112 1 + Current sample, line, band is: 52 113 1 + Current sample, line, band is: 52 114 1 + Current sample, line, band is: 52 115 1 + Current sample, line, band is: 52 116 1 + Current sample, line, band is: 52 117 1 + Current sample, line, band is: 52 118 1 + Current sample, line, band is: 52 119 1 + Current sample, line, band is: 52 120 1 + Current sample, line, band is: 52 121 1 + Current sample, line, band is: 52 122 1 + Current sample, line, band is: 52 123 1 + Current sample, line, band is: 52 124 1 + Current sample, line, band is: 52 125 1 + Current sample, line, band is: 52 126 1 + Current sample, line, band is: 53 1 1 + Current sample, line, band is: 53 2 1 + Current sample, line, band is: 53 3 1 + Current sample, line, band is: 53 4 1 + Current sample, line, band is: 53 5 1 + Current sample, line, band is: 53 6 1 + Current sample, line, band is: 53 7 1 + Current sample, line, band is: 53 8 1 + Current sample, line, band is: 53 9 1 + Current sample, line, band is: 53 10 1 + Current sample, line, band is: 53 11 1 + Current sample, line, band is: 53 12 1 + Current sample, line, band is: 53 13 1 + Current sample, line, band is: 53 14 1 + Current sample, line, band is: 53 15 1 + Current sample, line, band is: 53 16 1 + Current sample, line, band is: 53 17 1 + Current sample, line, band is: 53 18 1 + Current sample, line, band is: 53 19 1 + Current sample, line, band is: 53 20 1 + Current sample, line, band is: 53 21 1 + Current sample, line, band is: 53 22 1 + Current sample, line, band is: 53 23 1 + Current sample, line, band is: 53 24 1 + Current sample, line, band is: 53 25 1 + Current sample, line, band is: 53 26 1 + Current sample, line, band is: 53 27 1 + Current sample, line, band is: 53 28 1 + Current sample, line, band is: 53 29 1 + Current sample, line, band is: 53 30 1 + Current sample, line, band is: 53 31 1 + Current sample, line, band is: 53 32 1 + Current sample, line, band is: 53 33 1 + Current sample, line, band is: 53 34 1 + Current sample, line, band is: 53 35 1 + Current sample, line, band is: 53 36 1 + Current sample, line, band is: 53 37 1 + Current sample, line, band is: 53 38 1 + Current sample, line, band is: 53 39 1 + Current sample, line, band is: 53 40 1 + Current sample, line, band is: 53 41 1 + Current sample, line, band is: 53 42 1 + Current sample, line, band is: 53 43 1 + Current sample, line, band is: 53 44 1 + Current sample, line, band is: 53 45 1 + Current sample, line, band is: 53 46 1 + Current sample, line, band is: 53 47 1 + Current sample, line, band is: 53 48 1 + Current sample, line, band is: 53 49 1 + Current sample, line, band is: 53 50 1 + Current sample, line, band is: 53 51 1 + Current sample, line, band is: 53 52 1 + Current sample, line, band is: 53 53 1 + Current sample, line, band is: 53 54 1 + Current sample, line, band is: 53 55 1 + Current sample, line, band is: 53 56 1 + Current sample, line, band is: 53 57 1 + Current sample, line, band is: 53 58 1 + Current sample, line, band is: 53 59 1 + Current sample, line, band is: 53 60 1 + Current sample, line, band is: 53 61 1 + Current sample, line, band is: 53 62 1 + Current sample, line, band is: 53 63 1 + Current sample, line, band is: 53 64 1 + Current sample, line, band is: 53 65 1 + Current sample, line, band is: 53 66 1 + Current sample, line, band is: 53 67 1 + Current sample, line, band is: 53 68 1 + Current sample, line, band is: 53 69 1 + Current sample, line, band is: 53 70 1 + Current sample, line, band is: 53 71 1 + Current sample, line, band is: 53 72 1 + Current sample, line, band is: 53 73 1 + Current sample, line, band is: 53 74 1 + Current sample, line, band is: 53 75 1 + Current sample, line, band is: 53 76 1 + Current sample, line, band is: 53 77 1 + Current sample, line, band is: 53 78 1 + Current sample, line, band is: 53 79 1 + Current sample, line, band is: 53 80 1 + Current sample, line, band is: 53 81 1 + Current sample, line, band is: 53 82 1 + Current sample, line, band is: 53 83 1 + Current sample, line, band is: 53 84 1 + Current sample, line, band is: 53 85 1 + Current sample, line, band is: 53 86 1 + Current sample, line, band is: 53 87 1 + Current sample, line, band is: 53 88 1 + Current sample, line, band is: 53 89 1 + Current sample, line, band is: 53 90 1 + Current sample, line, band is: 53 91 1 + Current sample, line, band is: 53 92 1 + Current sample, line, band is: 53 93 1 + Current sample, line, band is: 53 94 1 + Current sample, line, band is: 53 95 1 + Current sample, line, band is: 53 96 1 + Current sample, line, band is: 53 97 1 + Current sample, line, band is: 53 98 1 + Current sample, line, band is: 53 99 1 + Current sample, line, band is: 53 100 1 + Current sample, line, band is: 53 101 1 + Current sample, line, band is: 53 102 1 + Current sample, line, band is: 53 103 1 + Current sample, line, band is: 53 104 1 + Current sample, line, band is: 53 105 1 + Current sample, line, band is: 53 106 1 + Current sample, line, band is: 53 107 1 + Current sample, line, band is: 53 108 1 + Current sample, line, band is: 53 109 1 + Current sample, line, band is: 53 110 1 + Current sample, line, band is: 53 111 1 + Current sample, line, band is: 53 112 1 + Current sample, line, band is: 53 113 1 + Current sample, line, band is: 53 114 1 + Current sample, line, band is: 53 115 1 + Current sample, line, band is: 53 116 1 + Current sample, line, band is: 53 117 1 + Current sample, line, band is: 53 118 1 + Current sample, line, band is: 53 119 1 + Current sample, line, band is: 53 120 1 + Current sample, line, band is: 53 121 1 + Current sample, line, band is: 53 122 1 + Current sample, line, band is: 53 123 1 + Current sample, line, band is: 53 124 1 + Current sample, line, band is: 53 125 1 + Current sample, line, band is: 53 126 1 + Current sample, line, band is: 54 1 1 + Current sample, line, band is: 54 2 1 + Current sample, line, band is: 54 3 1 + Current sample, line, band is: 54 4 1 + Current sample, line, band is: 54 5 1 + Current sample, line, band is: 54 6 1 + Current sample, line, band is: 54 7 1 + Current sample, line, band is: 54 8 1 + Current sample, line, band is: 54 9 1 + Current sample, line, band is: 54 10 1 + Current sample, line, band is: 54 11 1 + Current sample, line, band is: 54 12 1 + Current sample, line, band is: 54 13 1 + Current sample, line, band is: 54 14 1 + Current sample, line, band is: 54 15 1 + Current sample, line, band is: 54 16 1 + Current sample, line, band is: 54 17 1 + Current sample, line, band is: 54 18 1 + Current sample, line, band is: 54 19 1 + Current sample, line, band is: 54 20 1 + Current sample, line, band is: 54 21 1 + Current sample, line, band is: 54 22 1 + Current sample, line, band is: 54 23 1 + Current sample, line, band is: 54 24 1 + Current sample, line, band is: 54 25 1 + Current sample, line, band is: 54 26 1 + Current sample, line, band is: 54 27 1 + Current sample, line, band is: 54 28 1 + Current sample, line, band is: 54 29 1 + Current sample, line, band is: 54 30 1 + Current sample, line, band is: 54 31 1 + Current sample, line, band is: 54 32 1 + Current sample, line, band is: 54 33 1 + Current sample, line, band is: 54 34 1 + Current sample, line, band is: 54 35 1 + Current sample, line, band is: 54 36 1 + Current sample, line, band is: 54 37 1 + Current sample, line, band is: 54 38 1 + Current sample, line, band is: 54 39 1 + Current sample, line, band is: 54 40 1 + Current sample, line, band is: 54 41 1 + Current sample, line, band is: 54 42 1 + Current sample, line, band is: 54 43 1 + Current sample, line, band is: 54 44 1 + Current sample, line, band is: 54 45 1 + Current sample, line, band is: 54 46 1 + Current sample, line, band is: 54 47 1 + Current sample, line, band is: 54 48 1 + Current sample, line, band is: 54 49 1 + Current sample, line, band is: 54 50 1 + Current sample, line, band is: 54 51 1 + Current sample, line, band is: 54 52 1 + Current sample, line, band is: 54 53 1 + Current sample, line, band is: 54 54 1 + Current sample, line, band is: 54 55 1 + Current sample, line, band is: 54 56 1 + Current sample, line, band is: 54 57 1 + Current sample, line, band is: 54 58 1 + Current sample, line, band is: 54 59 1 + Current sample, line, band is: 54 60 1 + Current sample, line, band is: 54 61 1 + Current sample, line, band is: 54 62 1 + Current sample, line, band is: 54 63 1 + Current sample, line, band is: 54 64 1 + Current sample, line, band is: 54 65 1 + Current sample, line, band is: 54 66 1 + Current sample, line, band is: 54 67 1 + Current sample, line, band is: 54 68 1 + Current sample, line, band is: 54 69 1 + Current sample, line, band is: 54 70 1 + Current sample, line, band is: 54 71 1 + Current sample, line, band is: 54 72 1 + Current sample, line, band is: 54 73 1 + Current sample, line, band is: 54 74 1 + Current sample, line, band is: 54 75 1 + Current sample, line, band is: 54 76 1 + Current sample, line, band is: 54 77 1 + Current sample, line, band is: 54 78 1 + Current sample, line, band is: 54 79 1 + Current sample, line, band is: 54 80 1 + Current sample, line, band is: 54 81 1 + Current sample, line, band is: 54 82 1 + Current sample, line, band is: 54 83 1 + Current sample, line, band is: 54 84 1 + Current sample, line, band is: 54 85 1 + Current sample, line, band is: 54 86 1 + Current sample, line, band is: 54 87 1 + Current sample, line, band is: 54 88 1 + Current sample, line, band is: 54 89 1 + Current sample, line, band is: 54 90 1 + Current sample, line, band is: 54 91 1 + Current sample, line, band is: 54 92 1 + Current sample, line, band is: 54 93 1 + Current sample, line, band is: 54 94 1 + Current sample, line, band is: 54 95 1 + Current sample, line, band is: 54 96 1 + Current sample, line, band is: 54 97 1 + Current sample, line, band is: 54 98 1 + Current sample, line, band is: 54 99 1 + Current sample, line, band is: 54 100 1 + Current sample, line, band is: 54 101 1 + Current sample, line, band is: 54 102 1 + Current sample, line, band is: 54 103 1 + Current sample, line, band is: 54 104 1 + Current sample, line, band is: 54 105 1 + Current sample, line, band is: 54 106 1 + Current sample, line, band is: 54 107 1 + Current sample, line, band is: 54 108 1 + Current sample, line, band is: 54 109 1 + Current sample, line, band is: 54 110 1 + Current sample, line, band is: 54 111 1 + Current sample, line, band is: 54 112 1 + Current sample, line, band is: 54 113 1 + Current sample, line, band is: 54 114 1 + Current sample, line, band is: 54 115 1 + Current sample, line, band is: 54 116 1 + Current sample, line, band is: 54 117 1 + Current sample, line, band is: 54 118 1 + Current sample, line, band is: 54 119 1 + Current sample, line, band is: 54 120 1 + Current sample, line, band is: 54 121 1 + Current sample, line, band is: 54 122 1 + Current sample, line, band is: 54 123 1 + Current sample, line, band is: 54 124 1 + Current sample, line, band is: 54 125 1 + Current sample, line, band is: 54 126 1 + Current sample, line, band is: 55 1 1 + Current sample, line, band is: 55 2 1 + Current sample, line, band is: 55 3 1 + Current sample, line, band is: 55 4 1 + Current sample, line, band is: 55 5 1 + Current sample, line, band is: 55 6 1 + Current sample, line, band is: 55 7 1 + Current sample, line, band is: 55 8 1 + Current sample, line, band is: 55 9 1 + Current sample, line, band is: 55 10 1 + Current sample, line, band is: 55 11 1 + Current sample, line, band is: 55 12 1 + Current sample, line, band is: 55 13 1 + Current sample, line, band is: 55 14 1 + Current sample, line, band is: 55 15 1 + Current sample, line, band is: 55 16 1 + Current sample, line, band is: 55 17 1 + Current sample, line, band is: 55 18 1 + Current sample, line, band is: 55 19 1 + Current sample, line, band is: 55 20 1 + Current sample, line, band is: 55 21 1 + Current sample, line, band is: 55 22 1 + Current sample, line, band is: 55 23 1 + Current sample, line, band is: 55 24 1 + Current sample, line, band is: 55 25 1 + Current sample, line, band is: 55 26 1 + Current sample, line, band is: 55 27 1 + Current sample, line, band is: 55 28 1 + Current sample, line, band is: 55 29 1 + Current sample, line, band is: 55 30 1 + Current sample, line, band is: 55 31 1 + Current sample, line, band is: 55 32 1 + Current sample, line, band is: 55 33 1 + Current sample, line, band is: 55 34 1 + Current sample, line, band is: 55 35 1 + Current sample, line, band is: 55 36 1 + Current sample, line, band is: 55 37 1 + Current sample, line, band is: 55 38 1 + Current sample, line, band is: 55 39 1 + Current sample, line, band is: 55 40 1 + Current sample, line, band is: 55 41 1 + Current sample, line, band is: 55 42 1 + Current sample, line, band is: 55 43 1 + Current sample, line, band is: 55 44 1 + Current sample, line, band is: 55 45 1 + Current sample, line, band is: 55 46 1 + Current sample, line, band is: 55 47 1 + Current sample, line, band is: 55 48 1 + Current sample, line, band is: 55 49 1 + Current sample, line, band is: 55 50 1 + Current sample, line, band is: 55 51 1 + Current sample, line, band is: 55 52 1 + Current sample, line, band is: 55 53 1 + Current sample, line, band is: 55 54 1 + Current sample, line, band is: 55 55 1 + Current sample, line, band is: 55 56 1 + Current sample, line, band is: 55 57 1 + Current sample, line, band is: 55 58 1 + Current sample, line, band is: 55 59 1 + Current sample, line, band is: 55 60 1 + Current sample, line, band is: 55 61 1 + Current sample, line, band is: 55 62 1 + Current sample, line, band is: 55 63 1 + Current sample, line, band is: 55 64 1 + Current sample, line, band is: 55 65 1 + Current sample, line, band is: 55 66 1 + Current sample, line, band is: 55 67 1 + Current sample, line, band is: 55 68 1 + Current sample, line, band is: 55 69 1 + Current sample, line, band is: 55 70 1 + Current sample, line, band is: 55 71 1 + Current sample, line, band is: 55 72 1 + Current sample, line, band is: 55 73 1 + Current sample, line, band is: 55 74 1 + Current sample, line, band is: 55 75 1 + Current sample, line, band is: 55 76 1 + Current sample, line, band is: 55 77 1 + Current sample, line, band is: 55 78 1 + Current sample, line, band is: 55 79 1 + Current sample, line, band is: 55 80 1 + Current sample, line, band is: 55 81 1 + Current sample, line, band is: 55 82 1 + Current sample, line, band is: 55 83 1 + Current sample, line, band is: 55 84 1 + Current sample, line, band is: 55 85 1 + Current sample, line, band is: 55 86 1 + Current sample, line, band is: 55 87 1 + Current sample, line, band is: 55 88 1 + Current sample, line, band is: 55 89 1 + Current sample, line, band is: 55 90 1 + Current sample, line, band is: 55 91 1 + Current sample, line, band is: 55 92 1 + Current sample, line, band is: 55 93 1 + Current sample, line, band is: 55 94 1 + Current sample, line, band is: 55 95 1 + Current sample, line, band is: 55 96 1 + Current sample, line, band is: 55 97 1 + Current sample, line, band is: 55 98 1 + Current sample, line, band is: 55 99 1 + Current sample, line, band is: 55 100 1 + Current sample, line, band is: 55 101 1 + Current sample, line, band is: 55 102 1 + Current sample, line, band is: 55 103 1 + Current sample, line, band is: 55 104 1 + Current sample, line, band is: 55 105 1 + Current sample, line, band is: 55 106 1 + Current sample, line, band is: 55 107 1 + Current sample, line, band is: 55 108 1 + Current sample, line, band is: 55 109 1 + Current sample, line, band is: 55 110 1 + Current sample, line, band is: 55 111 1 + Current sample, line, band is: 55 112 1 + Current sample, line, band is: 55 113 1 + Current sample, line, band is: 55 114 1 + Current sample, line, band is: 55 115 1 + Current sample, line, band is: 55 116 1 + Current sample, line, band is: 55 117 1 + Current sample, line, band is: 55 118 1 + Current sample, line, band is: 55 119 1 + Current sample, line, band is: 55 120 1 + Current sample, line, band is: 55 121 1 + Current sample, line, band is: 55 122 1 + Current sample, line, band is: 55 123 1 + Current sample, line, band is: 55 124 1 + Current sample, line, band is: 55 125 1 + Current sample, line, band is: 55 126 1 + Current sample, line, band is: 56 1 1 + Current sample, line, band is: 56 2 1 + Current sample, line, band is: 56 3 1 + Current sample, line, band is: 56 4 1 + Current sample, line, band is: 56 5 1 + Current sample, line, band is: 56 6 1 + Current sample, line, band is: 56 7 1 + Current sample, line, band is: 56 8 1 + Current sample, line, band is: 56 9 1 + Current sample, line, band is: 56 10 1 + Current sample, line, band is: 56 11 1 + Current sample, line, band is: 56 12 1 + Current sample, line, band is: 56 13 1 + Current sample, line, band is: 56 14 1 + Current sample, line, band is: 56 15 1 + Current sample, line, band is: 56 16 1 + Current sample, line, band is: 56 17 1 + Current sample, line, band is: 56 18 1 + Current sample, line, band is: 56 19 1 + Current sample, line, band is: 56 20 1 + Current sample, line, band is: 56 21 1 + Current sample, line, band is: 56 22 1 + Current sample, line, band is: 56 23 1 + Current sample, line, band is: 56 24 1 + Current sample, line, band is: 56 25 1 + Current sample, line, band is: 56 26 1 + Current sample, line, band is: 56 27 1 + Current sample, line, band is: 56 28 1 + Current sample, line, band is: 56 29 1 + Current sample, line, band is: 56 30 1 + Current sample, line, band is: 56 31 1 + Current sample, line, band is: 56 32 1 + Current sample, line, band is: 56 33 1 + Current sample, line, band is: 56 34 1 + Current sample, line, band is: 56 35 1 + Current sample, line, band is: 56 36 1 + Current sample, line, band is: 56 37 1 + Current sample, line, band is: 56 38 1 + Current sample, line, band is: 56 39 1 + Current sample, line, band is: 56 40 1 + Current sample, line, band is: 56 41 1 + Current sample, line, band is: 56 42 1 + Current sample, line, band is: 56 43 1 + Current sample, line, band is: 56 44 1 + Current sample, line, band is: 56 45 1 + Current sample, line, band is: 56 46 1 + Current sample, line, band is: 56 47 1 + Current sample, line, band is: 56 48 1 + Current sample, line, band is: 56 49 1 + Current sample, line, band is: 56 50 1 + Current sample, line, band is: 56 51 1 + Current sample, line, band is: 56 52 1 + Current sample, line, band is: 56 53 1 + Current sample, line, band is: 56 54 1 + Current sample, line, band is: 56 55 1 + Current sample, line, band is: 56 56 1 + Current sample, line, band is: 56 57 1 + Current sample, line, band is: 56 58 1 + Current sample, line, band is: 56 59 1 + Current sample, line, band is: 56 60 1 + Current sample, line, band is: 56 61 1 + Current sample, line, band is: 56 62 1 + Current sample, line, band is: 56 63 1 + Current sample, line, band is: 56 64 1 + Current sample, line, band is: 56 65 1 + Current sample, line, band is: 56 66 1 + Current sample, line, band is: 56 67 1 + Current sample, line, band is: 56 68 1 + Current sample, line, band is: 56 69 1 + Current sample, line, band is: 56 70 1 + Current sample, line, band is: 56 71 1 + Current sample, line, band is: 56 72 1 + Current sample, line, band is: 56 73 1 + Current sample, line, band is: 56 74 1 + Current sample, line, band is: 56 75 1 + Current sample, line, band is: 56 76 1 + Current sample, line, band is: 56 77 1 + Current sample, line, band is: 56 78 1 + Current sample, line, band is: 56 79 1 + Current sample, line, band is: 56 80 1 + Current sample, line, band is: 56 81 1 + Current sample, line, band is: 56 82 1 + Current sample, line, band is: 56 83 1 + Current sample, line, band is: 56 84 1 + Current sample, line, band is: 56 85 1 + Current sample, line, band is: 56 86 1 + Current sample, line, band is: 56 87 1 + Current sample, line, band is: 56 88 1 + Current sample, line, band is: 56 89 1 + Current sample, line, band is: 56 90 1 + Current sample, line, band is: 56 91 1 + Current sample, line, band is: 56 92 1 + Current sample, line, band is: 56 93 1 + Current sample, line, band is: 56 94 1 + Current sample, line, band is: 56 95 1 + Current sample, line, band is: 56 96 1 + Current sample, line, band is: 56 97 1 + Current sample, line, band is: 56 98 1 + Current sample, line, band is: 56 99 1 + Current sample, line, band is: 56 100 1 + Current sample, line, band is: 56 101 1 + Current sample, line, band is: 56 102 1 + Current sample, line, band is: 56 103 1 + Current sample, line, band is: 56 104 1 + Current sample, line, band is: 56 105 1 + Current sample, line, band is: 56 106 1 + Current sample, line, band is: 56 107 1 + Current sample, line, band is: 56 108 1 + Current sample, line, band is: 56 109 1 + Current sample, line, band is: 56 110 1 + Current sample, line, band is: 56 111 1 + Current sample, line, band is: 56 112 1 + Current sample, line, band is: 56 113 1 + Current sample, line, band is: 56 114 1 + Current sample, line, band is: 56 115 1 + Current sample, line, band is: 56 116 1 + Current sample, line, band is: 56 117 1 + Current sample, line, band is: 56 118 1 + Current sample, line, band is: 56 119 1 + Current sample, line, band is: 56 120 1 + Current sample, line, band is: 56 121 1 + Current sample, line, band is: 56 122 1 + Current sample, line, band is: 56 123 1 + Current sample, line, band is: 56 124 1 + Current sample, line, band is: 56 125 1 + Current sample, line, band is: 56 126 1 + Current sample, line, band is: 57 1 1 + Current sample, line, band is: 57 2 1 + Current sample, line, band is: 57 3 1 + Current sample, line, band is: 57 4 1 + Current sample, line, band is: 57 5 1 + Current sample, line, band is: 57 6 1 + Current sample, line, band is: 57 7 1 + Current sample, line, band is: 57 8 1 + Current sample, line, band is: 57 9 1 + Current sample, line, band is: 57 10 1 + Current sample, line, band is: 57 11 1 + Current sample, line, band is: 57 12 1 + Current sample, line, band is: 57 13 1 + Current sample, line, band is: 57 14 1 + Current sample, line, band is: 57 15 1 + Current sample, line, band is: 57 16 1 + Current sample, line, band is: 57 17 1 + Current sample, line, band is: 57 18 1 + Current sample, line, band is: 57 19 1 + Current sample, line, band is: 57 20 1 + Current sample, line, band is: 57 21 1 + Current sample, line, band is: 57 22 1 + Current sample, line, band is: 57 23 1 + Current sample, line, band is: 57 24 1 + Current sample, line, band is: 57 25 1 + Current sample, line, band is: 57 26 1 + Current sample, line, band is: 57 27 1 + Current sample, line, band is: 57 28 1 + Current sample, line, band is: 57 29 1 + Current sample, line, band is: 57 30 1 + Current sample, line, band is: 57 31 1 + Current sample, line, band is: 57 32 1 + Current sample, line, band is: 57 33 1 + Current sample, line, band is: 57 34 1 + Current sample, line, band is: 57 35 1 + Current sample, line, band is: 57 36 1 + Current sample, line, band is: 57 37 1 + Current sample, line, band is: 57 38 1 + Current sample, line, band is: 57 39 1 + Current sample, line, band is: 57 40 1 + Current sample, line, band is: 57 41 1 + Current sample, line, band is: 57 42 1 + Current sample, line, band is: 57 43 1 + Current sample, line, band is: 57 44 1 + Current sample, line, band is: 57 45 1 + Current sample, line, band is: 57 46 1 + Current sample, line, band is: 57 47 1 + Current sample, line, band is: 57 48 1 + Current sample, line, band is: 57 49 1 + Current sample, line, band is: 57 50 1 + Current sample, line, band is: 57 51 1 + Current sample, line, band is: 57 52 1 + Current sample, line, band is: 57 53 1 + Current sample, line, band is: 57 54 1 + Current sample, line, band is: 57 55 1 + Current sample, line, band is: 57 56 1 + Current sample, line, band is: 57 57 1 + Current sample, line, band is: 57 58 1 + Current sample, line, band is: 57 59 1 + Current sample, line, band is: 57 60 1 + Current sample, line, band is: 57 61 1 + Current sample, line, band is: 57 62 1 + Current sample, line, band is: 57 63 1 + Current sample, line, band is: 57 64 1 + Current sample, line, band is: 57 65 1 + Current sample, line, band is: 57 66 1 + Current sample, line, band is: 57 67 1 + Current sample, line, band is: 57 68 1 + Current sample, line, band is: 57 69 1 + Current sample, line, band is: 57 70 1 + Current sample, line, band is: 57 71 1 + Current sample, line, band is: 57 72 1 + Current sample, line, band is: 57 73 1 + Current sample, line, band is: 57 74 1 + Current sample, line, band is: 57 75 1 + Current sample, line, band is: 57 76 1 + Current sample, line, band is: 57 77 1 + Current sample, line, band is: 57 78 1 + Current sample, line, band is: 57 79 1 + Current sample, line, band is: 57 80 1 + Current sample, line, band is: 57 81 1 + Current sample, line, band is: 57 82 1 + Current sample, line, band is: 57 83 1 + Current sample, line, band is: 57 84 1 + Current sample, line, band is: 57 85 1 + Current sample, line, band is: 57 86 1 + Current sample, line, band is: 57 87 1 + Current sample, line, band is: 57 88 1 + Current sample, line, band is: 57 89 1 + Current sample, line, band is: 57 90 1 + Current sample, line, band is: 57 91 1 + Current sample, line, band is: 57 92 1 + Current sample, line, band is: 57 93 1 + Current sample, line, band is: 57 94 1 + Current sample, line, band is: 57 95 1 + Current sample, line, band is: 57 96 1 + Current sample, line, band is: 57 97 1 + Current sample, line, band is: 57 98 1 + Current sample, line, band is: 57 99 1 + Current sample, line, band is: 57 100 1 + Current sample, line, band is: 57 101 1 + Current sample, line, band is: 57 102 1 + Current sample, line, band is: 57 103 1 + Current sample, line, band is: 57 104 1 + Current sample, line, band is: 57 105 1 + Current sample, line, band is: 57 106 1 + Current sample, line, band is: 57 107 1 + Current sample, line, band is: 57 108 1 + Current sample, line, band is: 57 109 1 + Current sample, line, band is: 57 110 1 + Current sample, line, band is: 57 111 1 + Current sample, line, band is: 57 112 1 + Current sample, line, band is: 57 113 1 + Current sample, line, band is: 57 114 1 + Current sample, line, band is: 57 115 1 + Current sample, line, band is: 57 116 1 + Current sample, line, band is: 57 117 1 + Current sample, line, band is: 57 118 1 + Current sample, line, band is: 57 119 1 + Current sample, line, band is: 57 120 1 + Current sample, line, band is: 57 121 1 + Current sample, line, band is: 57 122 1 + Current sample, line, band is: 57 123 1 + Current sample, line, band is: 57 124 1 + Current sample, line, band is: 57 125 1 + Current sample, line, band is: 57 126 1 + Current sample, line, band is: 58 1 1 + Current sample, line, band is: 58 2 1 + Current sample, line, band is: 58 3 1 + Current sample, line, band is: 58 4 1 + Current sample, line, band is: 58 5 1 + Current sample, line, band is: 58 6 1 + Current sample, line, band is: 58 7 1 + Current sample, line, band is: 58 8 1 + Current sample, line, band is: 58 9 1 + Current sample, line, band is: 58 10 1 + Current sample, line, band is: 58 11 1 + Current sample, line, band is: 58 12 1 + Current sample, line, band is: 58 13 1 + Current sample, line, band is: 58 14 1 + Current sample, line, band is: 58 15 1 + Current sample, line, band is: 58 16 1 + Current sample, line, band is: 58 17 1 + Current sample, line, band is: 58 18 1 + Current sample, line, band is: 58 19 1 + Current sample, line, band is: 58 20 1 + Current sample, line, band is: 58 21 1 + Current sample, line, band is: 58 22 1 + Current sample, line, band is: 58 23 1 + Current sample, line, band is: 58 24 1 + Current sample, line, band is: 58 25 1 + Current sample, line, band is: 58 26 1 + Current sample, line, band is: 58 27 1 + Current sample, line, band is: 58 28 1 + Current sample, line, band is: 58 29 1 + Current sample, line, band is: 58 30 1 + Current sample, line, band is: 58 31 1 + Current sample, line, band is: 58 32 1 + Current sample, line, band is: 58 33 1 + Current sample, line, band is: 58 34 1 + Current sample, line, band is: 58 35 1 + Current sample, line, band is: 58 36 1 + Current sample, line, band is: 58 37 1 + Current sample, line, band is: 58 38 1 + Current sample, line, band is: 58 39 1 + Current sample, line, band is: 58 40 1 + Current sample, line, band is: 58 41 1 + Current sample, line, band is: 58 42 1 + Current sample, line, band is: 58 43 1 + Current sample, line, band is: 58 44 1 + Current sample, line, band is: 58 45 1 + Current sample, line, band is: 58 46 1 + Current sample, line, band is: 58 47 1 + Current sample, line, band is: 58 48 1 + Current sample, line, band is: 58 49 1 + Current sample, line, band is: 58 50 1 + Current sample, line, band is: 58 51 1 + Current sample, line, band is: 58 52 1 + Current sample, line, band is: 58 53 1 + Current sample, line, band is: 58 54 1 + Current sample, line, band is: 58 55 1 + Current sample, line, band is: 58 56 1 + Current sample, line, band is: 58 57 1 + Current sample, line, band is: 58 58 1 + Current sample, line, band is: 58 59 1 + Current sample, line, band is: 58 60 1 + Current sample, line, band is: 58 61 1 + Current sample, line, band is: 58 62 1 + Current sample, line, band is: 58 63 1 + Current sample, line, band is: 58 64 1 + Current sample, line, band is: 58 65 1 + Current sample, line, band is: 58 66 1 + Current sample, line, band is: 58 67 1 + Current sample, line, band is: 58 68 1 + Current sample, line, band is: 58 69 1 + Current sample, line, band is: 58 70 1 + Current sample, line, band is: 58 71 1 + Current sample, line, band is: 58 72 1 + Current sample, line, band is: 58 73 1 + Current sample, line, band is: 58 74 1 + Current sample, line, band is: 58 75 1 + Current sample, line, band is: 58 76 1 + Current sample, line, band is: 58 77 1 + Current sample, line, band is: 58 78 1 + Current sample, line, band is: 58 79 1 + Current sample, line, band is: 58 80 1 + Current sample, line, band is: 58 81 1 + Current sample, line, band is: 58 82 1 + Current sample, line, band is: 58 83 1 + Current sample, line, band is: 58 84 1 + Current sample, line, band is: 58 85 1 + Current sample, line, band is: 58 86 1 + Current sample, line, band is: 58 87 1 + Current sample, line, band is: 58 88 1 + Current sample, line, band is: 58 89 1 + Current sample, line, band is: 58 90 1 + Current sample, line, band is: 58 91 1 + Current sample, line, band is: 58 92 1 + Current sample, line, band is: 58 93 1 + Current sample, line, band is: 58 94 1 + Current sample, line, band is: 58 95 1 + Current sample, line, band is: 58 96 1 + Current sample, line, band is: 58 97 1 + Current sample, line, band is: 58 98 1 + Current sample, line, band is: 58 99 1 + Current sample, line, band is: 58 100 1 + Current sample, line, band is: 58 101 1 + Current sample, line, band is: 58 102 1 + Current sample, line, band is: 58 103 1 + Current sample, line, band is: 58 104 1 + Current sample, line, band is: 58 105 1 + Current sample, line, band is: 58 106 1 + Current sample, line, band is: 58 107 1 + Current sample, line, band is: 58 108 1 + Current sample, line, band is: 58 109 1 + Current sample, line, band is: 58 110 1 + Current sample, line, band is: 58 111 1 + Current sample, line, band is: 58 112 1 + Current sample, line, band is: 58 113 1 + Current sample, line, band is: 58 114 1 + Current sample, line, band is: 58 115 1 + Current sample, line, band is: 58 116 1 + Current sample, line, band is: 58 117 1 + Current sample, line, band is: 58 118 1 + Current sample, line, band is: 58 119 1 + Current sample, line, band is: 58 120 1 + Current sample, line, band is: 58 121 1 + Current sample, line, band is: 58 122 1 + Current sample, line, band is: 58 123 1 + Current sample, line, band is: 58 124 1 + Current sample, line, band is: 58 125 1 + Current sample, line, band is: 58 126 1 + Current sample, line, band is: 59 1 1 + Current sample, line, band is: 59 2 1 + Current sample, line, band is: 59 3 1 + Current sample, line, band is: 59 4 1 + Current sample, line, band is: 59 5 1 + Current sample, line, band is: 59 6 1 + Current sample, line, band is: 59 7 1 + Current sample, line, band is: 59 8 1 + Current sample, line, band is: 59 9 1 + Current sample, line, band is: 59 10 1 + Current sample, line, band is: 59 11 1 + Current sample, line, band is: 59 12 1 + Current sample, line, band is: 59 13 1 + Current sample, line, band is: 59 14 1 + Current sample, line, band is: 59 15 1 + Current sample, line, band is: 59 16 1 + Current sample, line, band is: 59 17 1 + Current sample, line, band is: 59 18 1 + Current sample, line, band is: 59 19 1 + Current sample, line, band is: 59 20 1 + Current sample, line, band is: 59 21 1 + Current sample, line, band is: 59 22 1 + Current sample, line, band is: 59 23 1 + Current sample, line, band is: 59 24 1 + Current sample, line, band is: 59 25 1 + Current sample, line, band is: 59 26 1 + Current sample, line, band is: 59 27 1 + Current sample, line, band is: 59 28 1 + Current sample, line, band is: 59 29 1 + Current sample, line, band is: 59 30 1 + Current sample, line, band is: 59 31 1 + Current sample, line, band is: 59 32 1 + Current sample, line, band is: 59 33 1 + Current sample, line, band is: 59 34 1 + Current sample, line, band is: 59 35 1 + Current sample, line, band is: 59 36 1 + Current sample, line, band is: 59 37 1 + Current sample, line, band is: 59 38 1 + Current sample, line, band is: 59 39 1 + Current sample, line, band is: 59 40 1 + Current sample, line, band is: 59 41 1 + Current sample, line, band is: 59 42 1 + Current sample, line, band is: 59 43 1 + Current sample, line, band is: 59 44 1 + Current sample, line, band is: 59 45 1 + Current sample, line, band is: 59 46 1 + Current sample, line, band is: 59 47 1 + Current sample, line, band is: 59 48 1 + Current sample, line, band is: 59 49 1 + Current sample, line, band is: 59 50 1 + Current sample, line, band is: 59 51 1 + Current sample, line, band is: 59 52 1 + Current sample, line, band is: 59 53 1 + Current sample, line, band is: 59 54 1 + Current sample, line, band is: 59 55 1 + Current sample, line, band is: 59 56 1 + Current sample, line, band is: 59 57 1 + Current sample, line, band is: 59 58 1 + Current sample, line, band is: 59 59 1 + Current sample, line, band is: 59 60 1 + Current sample, line, band is: 59 61 1 + Current sample, line, band is: 59 62 1 + Current sample, line, band is: 59 63 1 + Current sample, line, band is: 59 64 1 + Current sample, line, band is: 59 65 1 + Current sample, line, band is: 59 66 1 + Current sample, line, band is: 59 67 1 + Current sample, line, band is: 59 68 1 + Current sample, line, band is: 59 69 1 + Current sample, line, band is: 59 70 1 + Current sample, line, band is: 59 71 1 + Current sample, line, band is: 59 72 1 + Current sample, line, band is: 59 73 1 + Current sample, line, band is: 59 74 1 + Current sample, line, band is: 59 75 1 + Current sample, line, band is: 59 76 1 + Current sample, line, band is: 59 77 1 + Current sample, line, band is: 59 78 1 + Current sample, line, band is: 59 79 1 + Current sample, line, band is: 59 80 1 + Current sample, line, band is: 59 81 1 + Current sample, line, band is: 59 82 1 + Current sample, line, band is: 59 83 1 + Current sample, line, band is: 59 84 1 + Current sample, line, band is: 59 85 1 + Current sample, line, band is: 59 86 1 + Current sample, line, band is: 59 87 1 + Current sample, line, band is: 59 88 1 + Current sample, line, band is: 59 89 1 + Current sample, line, band is: 59 90 1 + Current sample, line, band is: 59 91 1 + Current sample, line, band is: 59 92 1 + Current sample, line, band is: 59 93 1 + Current sample, line, band is: 59 94 1 + Current sample, line, band is: 59 95 1 + Current sample, line, band is: 59 96 1 + Current sample, line, band is: 59 97 1 + Current sample, line, band is: 59 98 1 + Current sample, line, band is: 59 99 1 + Current sample, line, band is: 59 100 1 + Current sample, line, band is: 59 101 1 + Current sample, line, band is: 59 102 1 + Current sample, line, band is: 59 103 1 + Current sample, line, band is: 59 104 1 + Current sample, line, band is: 59 105 1 + Current sample, line, band is: 59 106 1 + Current sample, line, band is: 59 107 1 + Current sample, line, band is: 59 108 1 + Current sample, line, band is: 59 109 1 + Current sample, line, band is: 59 110 1 + Current sample, line, band is: 59 111 1 + Current sample, line, band is: 59 112 1 + Current sample, line, band is: 59 113 1 + Current sample, line, band is: 59 114 1 + Current sample, line, band is: 59 115 1 + Current sample, line, band is: 59 116 1 + Current sample, line, band is: 59 117 1 + Current sample, line, band is: 59 118 1 + Current sample, line, band is: 59 119 1 + Current sample, line, band is: 59 120 1 + Current sample, line, band is: 59 121 1 + Current sample, line, band is: 59 122 1 + Current sample, line, band is: 59 123 1 + Current sample, line, band is: 59 124 1 + Current sample, line, band is: 59 125 1 + Current sample, line, band is: 59 126 1 + Current sample, line, band is: 60 1 1 + Current sample, line, band is: 60 2 1 + Current sample, line, band is: 60 3 1 + Current sample, line, band is: 60 4 1 + Current sample, line, band is: 60 5 1 + Current sample, line, band is: 60 6 1 + Current sample, line, band is: 60 7 1 + Current sample, line, band is: 60 8 1 + Current sample, line, band is: 60 9 1 + Current sample, line, band is: 60 10 1 + Current sample, line, band is: 60 11 1 + Current sample, line, band is: 60 12 1 + Current sample, line, band is: 60 13 1 + Current sample, line, band is: 60 14 1 + Current sample, line, band is: 60 15 1 + Current sample, line, band is: 60 16 1 + Current sample, line, band is: 60 17 1 + Current sample, line, band is: 60 18 1 + Current sample, line, band is: 60 19 1 + Current sample, line, band is: 60 20 1 + Current sample, line, band is: 60 21 1 + Current sample, line, band is: 60 22 1 + Current sample, line, band is: 60 23 1 + Current sample, line, band is: 60 24 1 + Current sample, line, band is: 60 25 1 + Current sample, line, band is: 60 26 1 + Current sample, line, band is: 60 27 1 + Current sample, line, band is: 60 28 1 + Current sample, line, band is: 60 29 1 + Current sample, line, band is: 60 30 1 + Current sample, line, band is: 60 31 1 + Current sample, line, band is: 60 32 1 + Current sample, line, band is: 60 33 1 + Current sample, line, band is: 60 34 1 + Current sample, line, band is: 60 35 1 + Current sample, line, band is: 60 36 1 + Current sample, line, band is: 60 37 1 + Current sample, line, band is: 60 38 1 + Current sample, line, band is: 60 39 1 + Current sample, line, band is: 60 40 1 + Current sample, line, band is: 60 41 1 + Current sample, line, band is: 60 42 1 + Current sample, line, band is: 60 43 1 + Current sample, line, band is: 60 44 1 + Current sample, line, band is: 60 45 1 + Current sample, line, band is: 60 46 1 + Current sample, line, band is: 60 47 1 + Current sample, line, band is: 60 48 1 + Current sample, line, band is: 60 49 1 + Current sample, line, band is: 60 50 1 + Current sample, line, band is: 60 51 1 + Current sample, line, band is: 60 52 1 + Current sample, line, band is: 60 53 1 + Current sample, line, band is: 60 54 1 + Current sample, line, band is: 60 55 1 + Current sample, line, band is: 60 56 1 + Current sample, line, band is: 60 57 1 + Current sample, line, band is: 60 58 1 + Current sample, line, band is: 60 59 1 + Current sample, line, band is: 60 60 1 + Current sample, line, band is: 60 61 1 + Current sample, line, band is: 60 62 1 + Current sample, line, band is: 60 63 1 + Current sample, line, band is: 60 64 1 + Current sample, line, band is: 60 65 1 + Current sample, line, band is: 60 66 1 + Current sample, line, band is: 60 67 1 + Current sample, line, band is: 60 68 1 + Current sample, line, band is: 60 69 1 + Current sample, line, band is: 60 70 1 + Current sample, line, band is: 60 71 1 + Current sample, line, band is: 60 72 1 + Current sample, line, band is: 60 73 1 + Current sample, line, band is: 60 74 1 + Current sample, line, band is: 60 75 1 + Current sample, line, band is: 60 76 1 + Current sample, line, band is: 60 77 1 + Current sample, line, band is: 60 78 1 + Current sample, line, band is: 60 79 1 + Current sample, line, band is: 60 80 1 + Current sample, line, band is: 60 81 1 + Current sample, line, band is: 60 82 1 + Current sample, line, band is: 60 83 1 + Current sample, line, band is: 60 84 1 + Current sample, line, band is: 60 85 1 + Current sample, line, band is: 60 86 1 + Current sample, line, band is: 60 87 1 + Current sample, line, band is: 60 88 1 + Current sample, line, band is: 60 89 1 + Current sample, line, band is: 60 90 1 + Current sample, line, band is: 60 91 1 + Current sample, line, band is: 60 92 1 + Current sample, line, band is: 60 93 1 + Current sample, line, band is: 60 94 1 + Current sample, line, band is: 60 95 1 + Current sample, line, band is: 60 96 1 + Current sample, line, band is: 60 97 1 + Current sample, line, band is: 60 98 1 + Current sample, line, band is: 60 99 1 + Current sample, line, band is: 60 100 1 + Current sample, line, band is: 60 101 1 + Current sample, line, band is: 60 102 1 + Current sample, line, band is: 60 103 1 + Current sample, line, band is: 60 104 1 + Current sample, line, band is: 60 105 1 + Current sample, line, band is: 60 106 1 + Current sample, line, band is: 60 107 1 + Current sample, line, band is: 60 108 1 + Current sample, line, band is: 60 109 1 + Current sample, line, band is: 60 110 1 + Current sample, line, band is: 60 111 1 + Current sample, line, band is: 60 112 1 + Current sample, line, band is: 60 113 1 + Current sample, line, band is: 60 114 1 + Current sample, line, band is: 60 115 1 + Current sample, line, band is: 60 116 1 + Current sample, line, band is: 60 117 1 + Current sample, line, band is: 60 118 1 + Current sample, line, band is: 60 119 1 + Current sample, line, band is: 60 120 1 + Current sample, line, band is: 60 121 1 + Current sample, line, band is: 60 122 1 + Current sample, line, band is: 60 123 1 + Current sample, line, band is: 60 124 1 + Current sample, line, band is: 60 125 1 + Current sample, line, band is: 60 126 1 + Current sample, line, band is: 61 1 1 + Current sample, line, band is: 61 2 1 + Current sample, line, band is: 61 3 1 + Current sample, line, band is: 61 4 1 + Current sample, line, band is: 61 5 1 + Current sample, line, band is: 61 6 1 + Current sample, line, band is: 61 7 1 + Current sample, line, band is: 61 8 1 + Current sample, line, band is: 61 9 1 + Current sample, line, band is: 61 10 1 + Current sample, line, band is: 61 11 1 + Current sample, line, band is: 61 12 1 + Current sample, line, band is: 61 13 1 + Current sample, line, band is: 61 14 1 + Current sample, line, band is: 61 15 1 + Current sample, line, band is: 61 16 1 + Current sample, line, band is: 61 17 1 + Current sample, line, band is: 61 18 1 + Current sample, line, band is: 61 19 1 + Current sample, line, band is: 61 20 1 + Current sample, line, band is: 61 21 1 + Current sample, line, band is: 61 22 1 + Current sample, line, band is: 61 23 1 + Current sample, line, band is: 61 24 1 + Current sample, line, band is: 61 25 1 + Current sample, line, band is: 61 26 1 + Current sample, line, band is: 61 27 1 + Current sample, line, band is: 61 28 1 + Current sample, line, band is: 61 29 1 + Current sample, line, band is: 61 30 1 + Current sample, line, band is: 61 31 1 + Current sample, line, band is: 61 32 1 + Current sample, line, band is: 61 33 1 + Current sample, line, band is: 61 34 1 + Current sample, line, band is: 61 35 1 + Current sample, line, band is: 61 36 1 + Current sample, line, band is: 61 37 1 + Current sample, line, band is: 61 38 1 + Current sample, line, band is: 61 39 1 + Current sample, line, band is: 61 40 1 + Current sample, line, band is: 61 41 1 + Current sample, line, band is: 61 42 1 + Current sample, line, band is: 61 43 1 + Current sample, line, band is: 61 44 1 + Current sample, line, band is: 61 45 1 + Current sample, line, band is: 61 46 1 + Current sample, line, band is: 61 47 1 + Current sample, line, band is: 61 48 1 + Current sample, line, band is: 61 49 1 + Current sample, line, band is: 61 50 1 + Current sample, line, band is: 61 51 1 + Current sample, line, band is: 61 52 1 + Current sample, line, band is: 61 53 1 + Current sample, line, band is: 61 54 1 + Current sample, line, band is: 61 55 1 + Current sample, line, band is: 61 56 1 + Current sample, line, band is: 61 57 1 + Current sample, line, band is: 61 58 1 + Current sample, line, band is: 61 59 1 + Current sample, line, band is: 61 60 1 + Current sample, line, band is: 61 61 1 + Current sample, line, band is: 61 62 1 + Current sample, line, band is: 61 63 1 + Current sample, line, band is: 61 64 1 + Current sample, line, band is: 61 65 1 + Current sample, line, band is: 61 66 1 + Current sample, line, band is: 61 67 1 + Current sample, line, band is: 61 68 1 + Current sample, line, band is: 61 69 1 + Current sample, line, band is: 61 70 1 + Current sample, line, band is: 61 71 1 + Current sample, line, band is: 61 72 1 + Current sample, line, band is: 61 73 1 + Current sample, line, band is: 61 74 1 + Current sample, line, band is: 61 75 1 + Current sample, line, band is: 61 76 1 + Current sample, line, band is: 61 77 1 + Current sample, line, band is: 61 78 1 + Current sample, line, band is: 61 79 1 + Current sample, line, band is: 61 80 1 + Current sample, line, band is: 61 81 1 + Current sample, line, band is: 61 82 1 + Current sample, line, band is: 61 83 1 + Current sample, line, band is: 61 84 1 + Current sample, line, band is: 61 85 1 + Current sample, line, band is: 61 86 1 + Current sample, line, band is: 61 87 1 + Current sample, line, band is: 61 88 1 + Current sample, line, band is: 61 89 1 + Current sample, line, band is: 61 90 1 + Current sample, line, band is: 61 91 1 + Current sample, line, band is: 61 92 1 + Current sample, line, band is: 61 93 1 + Current sample, line, band is: 61 94 1 + Current sample, line, band is: 61 95 1 + Current sample, line, band is: 61 96 1 + Current sample, line, band is: 61 97 1 + Current sample, line, band is: 61 98 1 + Current sample, line, band is: 61 99 1 + Current sample, line, band is: 61 100 1 + Current sample, line, band is: 61 101 1 + Current sample, line, band is: 61 102 1 + Current sample, line, band is: 61 103 1 + Current sample, line, band is: 61 104 1 + Current sample, line, band is: 61 105 1 + Current sample, line, band is: 61 106 1 + Current sample, line, band is: 61 107 1 + Current sample, line, band is: 61 108 1 + Current sample, line, band is: 61 109 1 + Current sample, line, band is: 61 110 1 + Current sample, line, band is: 61 111 1 + Current sample, line, band is: 61 112 1 + Current sample, line, band is: 61 113 1 + Current sample, line, band is: 61 114 1 + Current sample, line, band is: 61 115 1 + Current sample, line, band is: 61 116 1 + Current sample, line, band is: 61 117 1 + Current sample, line, band is: 61 118 1 + Current sample, line, band is: 61 119 1 + Current sample, line, band is: 61 120 1 + Current sample, line, band is: 61 121 1 + Current sample, line, band is: 61 122 1 + Current sample, line, band is: 61 123 1 + Current sample, line, band is: 61 124 1 + Current sample, line, band is: 61 125 1 + Current sample, line, band is: 61 126 1 + Current sample, line, band is: 62 1 1 + Current sample, line, band is: 62 2 1 + Current sample, line, band is: 62 3 1 + Current sample, line, band is: 62 4 1 + Current sample, line, band is: 62 5 1 + Current sample, line, band is: 62 6 1 + Current sample, line, band is: 62 7 1 + Current sample, line, band is: 62 8 1 + Current sample, line, band is: 62 9 1 + Current sample, line, band is: 62 10 1 + Current sample, line, band is: 62 11 1 + Current sample, line, band is: 62 12 1 + Current sample, line, band is: 62 13 1 + Current sample, line, band is: 62 14 1 + Current sample, line, band is: 62 15 1 + Current sample, line, band is: 62 16 1 + Current sample, line, band is: 62 17 1 + Current sample, line, band is: 62 18 1 + Current sample, line, band is: 62 19 1 + Current sample, line, band is: 62 20 1 + Current sample, line, band is: 62 21 1 + Current sample, line, band is: 62 22 1 + Current sample, line, band is: 62 23 1 + Current sample, line, band is: 62 24 1 + Current sample, line, band is: 62 25 1 + Current sample, line, band is: 62 26 1 + Current sample, line, band is: 62 27 1 + Current sample, line, band is: 62 28 1 + Current sample, line, band is: 62 29 1 + Current sample, line, band is: 62 30 1 + Current sample, line, band is: 62 31 1 + Current sample, line, band is: 62 32 1 + Current sample, line, band is: 62 33 1 + Current sample, line, band is: 62 34 1 + Current sample, line, band is: 62 35 1 + Current sample, line, band is: 62 36 1 + Current sample, line, band is: 62 37 1 + Current sample, line, band is: 62 38 1 + Current sample, line, band is: 62 39 1 + Current sample, line, band is: 62 40 1 + Current sample, line, band is: 62 41 1 + Current sample, line, band is: 62 42 1 + Current sample, line, band is: 62 43 1 + Current sample, line, band is: 62 44 1 + Current sample, line, band is: 62 45 1 + Current sample, line, band is: 62 46 1 + Current sample, line, band is: 62 47 1 + Current sample, line, band is: 62 48 1 + Current sample, line, band is: 62 49 1 + Current sample, line, band is: 62 50 1 + Current sample, line, band is: 62 51 1 + Current sample, line, band is: 62 52 1 + Current sample, line, band is: 62 53 1 + Current sample, line, band is: 62 54 1 + Current sample, line, band is: 62 55 1 + Current sample, line, band is: 62 56 1 + Current sample, line, band is: 62 57 1 + Current sample, line, band is: 62 58 1 + Current sample, line, band is: 62 59 1 + Current sample, line, band is: 62 60 1 + Current sample, line, band is: 62 61 1 + Current sample, line, band is: 62 62 1 + Current sample, line, band is: 62 63 1 + Current sample, line, band is: 62 64 1 + Current sample, line, band is: 62 65 1 + Current sample, line, band is: 62 66 1 + Current sample, line, band is: 62 67 1 + Current sample, line, band is: 62 68 1 + Current sample, line, band is: 62 69 1 + Current sample, line, band is: 62 70 1 + Current sample, line, band is: 62 71 1 + Current sample, line, band is: 62 72 1 + Current sample, line, band is: 62 73 1 + Current sample, line, band is: 62 74 1 + Current sample, line, band is: 62 75 1 + Current sample, line, band is: 62 76 1 + Current sample, line, band is: 62 77 1 + Current sample, line, band is: 62 78 1 + Current sample, line, band is: 62 79 1 + Current sample, line, band is: 62 80 1 + Current sample, line, band is: 62 81 1 + Current sample, line, band is: 62 82 1 + Current sample, line, band is: 62 83 1 + Current sample, line, band is: 62 84 1 + Current sample, line, band is: 62 85 1 + Current sample, line, band is: 62 86 1 + Current sample, line, band is: 62 87 1 + Current sample, line, band is: 62 88 1 + Current sample, line, band is: 62 89 1 + Current sample, line, band is: 62 90 1 + Current sample, line, band is: 62 91 1 + Current sample, line, band is: 62 92 1 + Current sample, line, band is: 62 93 1 + Current sample, line, band is: 62 94 1 + Current sample, line, band is: 62 95 1 + Current sample, line, band is: 62 96 1 + Current sample, line, band is: 62 97 1 + Current sample, line, band is: 62 98 1 + Current sample, line, band is: 62 99 1 + Current sample, line, band is: 62 100 1 + Current sample, line, band is: 62 101 1 + Current sample, line, band is: 62 102 1 + Current sample, line, band is: 62 103 1 + Current sample, line, band is: 62 104 1 + Current sample, line, band is: 62 105 1 + Current sample, line, band is: 62 106 1 + Current sample, line, band is: 62 107 1 + Current sample, line, band is: 62 108 1 + Current sample, line, band is: 62 109 1 + Current sample, line, band is: 62 110 1 + Current sample, line, band is: 62 111 1 + Current sample, line, band is: 62 112 1 + Current sample, line, band is: 62 113 1 + Current sample, line, band is: 62 114 1 + Current sample, line, band is: 62 115 1 + Current sample, line, band is: 62 116 1 + Current sample, line, band is: 62 117 1 + Current sample, line, band is: 62 118 1 + Current sample, line, band is: 62 119 1 + Current sample, line, band is: 62 120 1 + Current sample, line, band is: 62 121 1 + Current sample, line, band is: 62 122 1 + Current sample, line, band is: 62 123 1 + Current sample, line, band is: 62 124 1 + Current sample, line, band is: 62 125 1 + Current sample, line, band is: 62 126 1 + Current sample, line, band is: 63 1 1 + Current sample, line, band is: 63 2 1 + Current sample, line, band is: 63 3 1 + Current sample, line, band is: 63 4 1 + Current sample, line, band is: 63 5 1 + Current sample, line, band is: 63 6 1 + Current sample, line, band is: 63 7 1 + Current sample, line, band is: 63 8 1 + Current sample, line, band is: 63 9 1 + Current sample, line, band is: 63 10 1 + Current sample, line, band is: 63 11 1 + Current sample, line, band is: 63 12 1 + Current sample, line, band is: 63 13 1 + Current sample, line, band is: 63 14 1 + Current sample, line, band is: 63 15 1 + Current sample, line, band is: 63 16 1 + Current sample, line, band is: 63 17 1 + Current sample, line, band is: 63 18 1 + Current sample, line, band is: 63 19 1 + Current sample, line, band is: 63 20 1 + Current sample, line, band is: 63 21 1 + Current sample, line, band is: 63 22 1 + Current sample, line, band is: 63 23 1 + Current sample, line, band is: 63 24 1 + Current sample, line, band is: 63 25 1 + Current sample, line, band is: 63 26 1 + Current sample, line, band is: 63 27 1 + Current sample, line, band is: 63 28 1 + Current sample, line, band is: 63 29 1 + Current sample, line, band is: 63 30 1 + Current sample, line, band is: 63 31 1 + Current sample, line, band is: 63 32 1 + Current sample, line, band is: 63 33 1 + Current sample, line, band is: 63 34 1 + Current sample, line, band is: 63 35 1 + Current sample, line, band is: 63 36 1 + Current sample, line, band is: 63 37 1 + Current sample, line, band is: 63 38 1 + Current sample, line, band is: 63 39 1 + Current sample, line, band is: 63 40 1 + Current sample, line, band is: 63 41 1 + Current sample, line, band is: 63 42 1 + Current sample, line, band is: 63 43 1 + Current sample, line, band is: 63 44 1 + Current sample, line, band is: 63 45 1 + Current sample, line, band is: 63 46 1 + Current sample, line, band is: 63 47 1 + Current sample, line, band is: 63 48 1 + Current sample, line, band is: 63 49 1 + Current sample, line, band is: 63 50 1 + Current sample, line, band is: 63 51 1 + Current sample, line, band is: 63 52 1 + Current sample, line, band is: 63 53 1 + Current sample, line, band is: 63 54 1 + Current sample, line, band is: 63 55 1 + Current sample, line, band is: 63 56 1 + Current sample, line, band is: 63 57 1 + Current sample, line, band is: 63 58 1 + Current sample, line, band is: 63 59 1 + Current sample, line, band is: 63 60 1 + Current sample, line, band is: 63 61 1 + Current sample, line, band is: 63 62 1 + Current sample, line, band is: 63 63 1 + Current sample, line, band is: 63 64 1 + Current sample, line, band is: 63 65 1 + Current sample, line, band is: 63 66 1 + Current sample, line, band is: 63 67 1 + Current sample, line, band is: 63 68 1 + Current sample, line, band is: 63 69 1 + Current sample, line, band is: 63 70 1 + Current sample, line, band is: 63 71 1 + Current sample, line, band is: 63 72 1 + Current sample, line, band is: 63 73 1 + Current sample, line, band is: 63 74 1 + Current sample, line, band is: 63 75 1 + Current sample, line, band is: 63 76 1 + Current sample, line, band is: 63 77 1 + Current sample, line, band is: 63 78 1 + Current sample, line, band is: 63 79 1 + Current sample, line, band is: 63 80 1 + Current sample, line, band is: 63 81 1 + Current sample, line, band is: 63 82 1 + Current sample, line, band is: 63 83 1 + Current sample, line, band is: 63 84 1 + Current sample, line, band is: 63 85 1 + Current sample, line, band is: 63 86 1 + Current sample, line, band is: 63 87 1 + Current sample, line, band is: 63 88 1 + Current sample, line, band is: 63 89 1 + Current sample, line, band is: 63 90 1 + Current sample, line, band is: 63 91 1 + Current sample, line, band is: 63 92 1 + Current sample, line, band is: 63 93 1 + Current sample, line, band is: 63 94 1 + Current sample, line, band is: 63 95 1 + Current sample, line, band is: 63 96 1 + Current sample, line, band is: 63 97 1 + Current sample, line, band is: 63 98 1 + Current sample, line, band is: 63 99 1 + Current sample, line, band is: 63 100 1 + Current sample, line, band is: 63 101 1 + Current sample, line, band is: 63 102 1 + Current sample, line, band is: 63 103 1 + Current sample, line, band is: 63 104 1 + Current sample, line, band is: 63 105 1 + Current sample, line, band is: 63 106 1 + Current sample, line, band is: 63 107 1 + Current sample, line, band is: 63 108 1 + Current sample, line, band is: 63 109 1 + Current sample, line, band is: 63 110 1 + Current sample, line, band is: 63 111 1 + Current sample, line, band is: 63 112 1 + Current sample, line, band is: 63 113 1 + Current sample, line, band is: 63 114 1 + Current sample, line, band is: 63 115 1 + Current sample, line, band is: 63 116 1 + Current sample, line, band is: 63 117 1 + Current sample, line, band is: 63 118 1 + Current sample, line, band is: 63 119 1 + Current sample, line, band is: 63 120 1 + Current sample, line, band is: 63 121 1 + Current sample, line, band is: 63 122 1 + Current sample, line, band is: 63 123 1 + Current sample, line, band is: 63 124 1 + Current sample, line, band is: 63 125 1 + Current sample, line, band is: 63 126 1 + Current sample, line, band is: 64 1 1 + Current sample, line, band is: 64 2 1 + Current sample, line, band is: 64 3 1 + Current sample, line, band is: 64 4 1 + Current sample, line, band is: 64 5 1 + Current sample, line, band is: 64 6 1 + Current sample, line, band is: 64 7 1 + Current sample, line, band is: 64 8 1 + Current sample, line, band is: 64 9 1 + Current sample, line, band is: 64 10 1 + Current sample, line, band is: 64 11 1 + Current sample, line, band is: 64 12 1 + Current sample, line, band is: 64 13 1 + Current sample, line, band is: 64 14 1 + Current sample, line, band is: 64 15 1 + Current sample, line, band is: 64 16 1 + Current sample, line, band is: 64 17 1 + Current sample, line, band is: 64 18 1 + Current sample, line, band is: 64 19 1 + Current sample, line, band is: 64 20 1 + Current sample, line, band is: 64 21 1 + Current sample, line, band is: 64 22 1 + Current sample, line, band is: 64 23 1 + Current sample, line, band is: 64 24 1 + Current sample, line, band is: 64 25 1 + Current sample, line, band is: 64 26 1 + Current sample, line, band is: 64 27 1 + Current sample, line, band is: 64 28 1 + Current sample, line, band is: 64 29 1 + Current sample, line, band is: 64 30 1 + Current sample, line, band is: 64 31 1 + Current sample, line, band is: 64 32 1 + Current sample, line, band is: 64 33 1 + Current sample, line, band is: 64 34 1 + Current sample, line, band is: 64 35 1 + Current sample, line, band is: 64 36 1 + Current sample, line, band is: 64 37 1 + Current sample, line, band is: 64 38 1 + Current sample, line, band is: 64 39 1 + Current sample, line, band is: 64 40 1 + Current sample, line, band is: 64 41 1 + Current sample, line, band is: 64 42 1 + Current sample, line, band is: 64 43 1 + Current sample, line, band is: 64 44 1 + Current sample, line, band is: 64 45 1 + Current sample, line, band is: 64 46 1 + Current sample, line, band is: 64 47 1 + Current sample, line, band is: 64 48 1 + Current sample, line, band is: 64 49 1 + Current sample, line, band is: 64 50 1 + Current sample, line, band is: 64 51 1 + Current sample, line, band is: 64 52 1 + Current sample, line, band is: 64 53 1 + Current sample, line, band is: 64 54 1 + Current sample, line, band is: 64 55 1 + Current sample, line, band is: 64 56 1 + Current sample, line, band is: 64 57 1 + Current sample, line, band is: 64 58 1 + Current sample, line, band is: 64 59 1 + Current sample, line, band is: 64 60 1 + Current sample, line, band is: 64 61 1 + Current sample, line, band is: 64 62 1 + Current sample, line, band is: 64 63 1 + Current sample, line, band is: 64 64 1 + Current sample, line, band is: 64 65 1 + Current sample, line, band is: 64 66 1 + Current sample, line, band is: 64 67 1 + Current sample, line, band is: 64 68 1 + Current sample, line, band is: 64 69 1 + Current sample, line, band is: 64 70 1 + Current sample, line, band is: 64 71 1 + Current sample, line, band is: 64 72 1 + Current sample, line, band is: 64 73 1 + Current sample, line, band is: 64 74 1 + Current sample, line, band is: 64 75 1 + Current sample, line, band is: 64 76 1 + Current sample, line, band is: 64 77 1 + Current sample, line, band is: 64 78 1 + Current sample, line, band is: 64 79 1 + Current sample, line, band is: 64 80 1 + Current sample, line, band is: 64 81 1 + Current sample, line, band is: 64 82 1 + Current sample, line, band is: 64 83 1 + Current sample, line, band is: 64 84 1 + Current sample, line, band is: 64 85 1 + Current sample, line, band is: 64 86 1 + Current sample, line, band is: 64 87 1 + Current sample, line, band is: 64 88 1 + Current sample, line, band is: 64 89 1 + Current sample, line, band is: 64 90 1 + Current sample, line, band is: 64 91 1 + Current sample, line, band is: 64 92 1 + Current sample, line, band is: 64 93 1 + Current sample, line, band is: 64 94 1 + Current sample, line, band is: 64 95 1 + Current sample, line, band is: 64 96 1 + Current sample, line, band is: 64 97 1 + Current sample, line, band is: 64 98 1 + Current sample, line, band is: 64 99 1 + Current sample, line, band is: 64 100 1 + Current sample, line, band is: 64 101 1 + Current sample, line, band is: 64 102 1 + Current sample, line, band is: 64 103 1 + Current sample, line, band is: 64 104 1 + Current sample, line, band is: 64 105 1 + Current sample, line, band is: 64 106 1 + Current sample, line, band is: 64 107 1 + Current sample, line, band is: 64 108 1 + Current sample, line, band is: 64 109 1 + Current sample, line, band is: 64 110 1 + Current sample, line, band is: 64 111 1 + Current sample, line, band is: 64 112 1 + Current sample, line, band is: 64 113 1 + Current sample, line, band is: 64 114 1 + Current sample, line, band is: 64 115 1 + Current sample, line, band is: 64 116 1 + Current sample, line, band is: 64 117 1 + Current sample, line, band is: 64 118 1 + Current sample, line, band is: 64 119 1 + Current sample, line, band is: 64 120 1 + Current sample, line, band is: 64 121 1 + Current sample, line, band is: 64 122 1 + Current sample, line, band is: 64 123 1 + Current sample, line, band is: 64 124 1 + Current sample, line, band is: 64 125 1 + Current sample, line, band is: 64 126 1 + Current sample, line, band is: 65 1 1 + Current sample, line, band is: 65 2 1 + Current sample, line, band is: 65 3 1 + Current sample, line, band is: 65 4 1 + Current sample, line, band is: 65 5 1 + Current sample, line, band is: 65 6 1 + Current sample, line, band is: 65 7 1 + Current sample, line, band is: 65 8 1 + Current sample, line, band is: 65 9 1 + Current sample, line, band is: 65 10 1 + Current sample, line, band is: 65 11 1 + Current sample, line, band is: 65 12 1 + Current sample, line, band is: 65 13 1 + Current sample, line, band is: 65 14 1 + Current sample, line, band is: 65 15 1 + Current sample, line, band is: 65 16 1 + Current sample, line, band is: 65 17 1 + Current sample, line, band is: 65 18 1 + Current sample, line, band is: 65 19 1 + Current sample, line, band is: 65 20 1 + Current sample, line, band is: 65 21 1 + Current sample, line, band is: 65 22 1 + Current sample, line, band is: 65 23 1 + Current sample, line, band is: 65 24 1 + Current sample, line, band is: 65 25 1 + Current sample, line, band is: 65 26 1 + Current sample, line, band is: 65 27 1 + Current sample, line, band is: 65 28 1 + Current sample, line, band is: 65 29 1 + Current sample, line, band is: 65 30 1 + Current sample, line, band is: 65 31 1 + Current sample, line, band is: 65 32 1 + Current sample, line, band is: 65 33 1 + Current sample, line, band is: 65 34 1 + Current sample, line, band is: 65 35 1 + Current sample, line, band is: 65 36 1 + Current sample, line, band is: 65 37 1 + Current sample, line, band is: 65 38 1 + Current sample, line, band is: 65 39 1 + Current sample, line, band is: 65 40 1 + Current sample, line, band is: 65 41 1 + Current sample, line, band is: 65 42 1 + Current sample, line, band is: 65 43 1 + Current sample, line, band is: 65 44 1 + Current sample, line, band is: 65 45 1 + Current sample, line, band is: 65 46 1 + Current sample, line, band is: 65 47 1 + Current sample, line, band is: 65 48 1 + Current sample, line, band is: 65 49 1 + Current sample, line, band is: 65 50 1 + Current sample, line, band is: 65 51 1 + Current sample, line, band is: 65 52 1 + Current sample, line, band is: 65 53 1 + Current sample, line, band is: 65 54 1 + Current sample, line, band is: 65 55 1 + Current sample, line, band is: 65 56 1 + Current sample, line, band is: 65 57 1 + Current sample, line, band is: 65 58 1 + Current sample, line, band is: 65 59 1 + Current sample, line, band is: 65 60 1 + Current sample, line, band is: 65 61 1 + Current sample, line, band is: 65 62 1 + Current sample, line, band is: 65 63 1 + Current sample, line, band is: 65 64 1 + Current sample, line, band is: 65 65 1 + Current sample, line, band is: 65 66 1 + Current sample, line, band is: 65 67 1 + Current sample, line, band is: 65 68 1 + Current sample, line, band is: 65 69 1 + Current sample, line, band is: 65 70 1 + Current sample, line, band is: 65 71 1 + Current sample, line, band is: 65 72 1 + Current sample, line, band is: 65 73 1 + Current sample, line, band is: 65 74 1 + Current sample, line, band is: 65 75 1 + Current sample, line, band is: 65 76 1 + Current sample, line, band is: 65 77 1 + Current sample, line, band is: 65 78 1 + Current sample, line, band is: 65 79 1 + Current sample, line, band is: 65 80 1 + Current sample, line, band is: 65 81 1 + Current sample, line, band is: 65 82 1 + Current sample, line, band is: 65 83 1 + Current sample, line, band is: 65 84 1 + Current sample, line, band is: 65 85 1 + Current sample, line, band is: 65 86 1 + Current sample, line, band is: 65 87 1 + Current sample, line, band is: 65 88 1 + Current sample, line, band is: 65 89 1 + Current sample, line, band is: 65 90 1 + Current sample, line, band is: 65 91 1 + Current sample, line, band is: 65 92 1 + Current sample, line, band is: 65 93 1 + Current sample, line, band is: 65 94 1 + Current sample, line, band is: 65 95 1 + Current sample, line, band is: 65 96 1 + Current sample, line, band is: 65 97 1 + Current sample, line, band is: 65 98 1 + Current sample, line, band is: 65 99 1 + Current sample, line, band is: 65 100 1 + Current sample, line, band is: 65 101 1 + Current sample, line, band is: 65 102 1 + Current sample, line, band is: 65 103 1 + Current sample, line, band is: 65 104 1 + Current sample, line, band is: 65 105 1 + Current sample, line, band is: 65 106 1 + Current sample, line, band is: 65 107 1 + Current sample, line, band is: 65 108 1 + Current sample, line, band is: 65 109 1 + Current sample, line, band is: 65 110 1 + Current sample, line, band is: 65 111 1 + Current sample, line, band is: 65 112 1 + Current sample, line, band is: 65 113 1 + Current sample, line, band is: 65 114 1 + Current sample, line, band is: 65 115 1 + Current sample, line, band is: 65 116 1 + Current sample, line, band is: 65 117 1 + Current sample, line, band is: 65 118 1 + Current sample, line, band is: 65 119 1 + Current sample, line, band is: 65 120 1 + Current sample, line, band is: 65 121 1 + Current sample, line, band is: 65 122 1 + Current sample, line, band is: 65 123 1 + Current sample, line, band is: 65 124 1 + Current sample, line, band is: 65 125 1 + Current sample, line, band is: 65 126 1 + Current sample, line, band is: 66 1 1 + Current sample, line, band is: 66 2 1 + Current sample, line, band is: 66 3 1 + Current sample, line, band is: 66 4 1 + Current sample, line, band is: 66 5 1 + Current sample, line, band is: 66 6 1 + Current sample, line, band is: 66 7 1 + Current sample, line, band is: 66 8 1 + Current sample, line, band is: 66 9 1 + Current sample, line, band is: 66 10 1 + Current sample, line, band is: 66 11 1 + Current sample, line, band is: 66 12 1 + Current sample, line, band is: 66 13 1 + Current sample, line, band is: 66 14 1 + Current sample, line, band is: 66 15 1 + Current sample, line, band is: 66 16 1 + Current sample, line, band is: 66 17 1 + Current sample, line, band is: 66 18 1 + Current sample, line, band is: 66 19 1 + Current sample, line, band is: 66 20 1 + Current sample, line, band is: 66 21 1 + Current sample, line, band is: 66 22 1 + Current sample, line, band is: 66 23 1 + Current sample, line, band is: 66 24 1 + Current sample, line, band is: 66 25 1 + Current sample, line, band is: 66 26 1 + Current sample, line, band is: 66 27 1 + Current sample, line, band is: 66 28 1 + Current sample, line, band is: 66 29 1 + Current sample, line, band is: 66 30 1 + Current sample, line, band is: 66 31 1 + Current sample, line, band is: 66 32 1 + Current sample, line, band is: 66 33 1 + Current sample, line, band is: 66 34 1 + Current sample, line, band is: 66 35 1 + Current sample, line, band is: 66 36 1 + Current sample, line, band is: 66 37 1 + Current sample, line, band is: 66 38 1 + Current sample, line, band is: 66 39 1 + Current sample, line, band is: 66 40 1 + Current sample, line, band is: 66 41 1 + Current sample, line, band is: 66 42 1 + Current sample, line, band is: 66 43 1 + Current sample, line, band is: 66 44 1 + Current sample, line, band is: 66 45 1 + Current sample, line, band is: 66 46 1 + Current sample, line, band is: 66 47 1 + Current sample, line, band is: 66 48 1 + Current sample, line, band is: 66 49 1 + Current sample, line, band is: 66 50 1 + Current sample, line, band is: 66 51 1 + Current sample, line, band is: 66 52 1 + Current sample, line, band is: 66 53 1 + Current sample, line, band is: 66 54 1 + Current sample, line, band is: 66 55 1 + Current sample, line, band is: 66 56 1 + Current sample, line, band is: 66 57 1 + Current sample, line, band is: 66 58 1 + Current sample, line, band is: 66 59 1 + Current sample, line, band is: 66 60 1 + Current sample, line, band is: 66 61 1 + Current sample, line, band is: 66 62 1 + Current sample, line, band is: 66 63 1 + Current sample, line, band is: 66 64 1 + Current sample, line, band is: 66 65 1 + Current sample, line, band is: 66 66 1 + Current sample, line, band is: 66 67 1 + Current sample, line, band is: 66 68 1 + Current sample, line, band is: 66 69 1 + Current sample, line, band is: 66 70 1 + Current sample, line, band is: 66 71 1 + Current sample, line, band is: 66 72 1 + Current sample, line, band is: 66 73 1 + Current sample, line, band is: 66 74 1 + Current sample, line, band is: 66 75 1 + Current sample, line, band is: 66 76 1 + Current sample, line, band is: 66 77 1 + Current sample, line, band is: 66 78 1 + Current sample, line, band is: 66 79 1 + Current sample, line, band is: 66 80 1 + Current sample, line, band is: 66 81 1 + Current sample, line, band is: 66 82 1 + Current sample, line, band is: 66 83 1 + Current sample, line, band is: 66 84 1 + Current sample, line, band is: 66 85 1 + Current sample, line, band is: 66 86 1 + Current sample, line, band is: 66 87 1 + Current sample, line, band is: 66 88 1 + Current sample, line, band is: 66 89 1 + Current sample, line, band is: 66 90 1 + Current sample, line, band is: 66 91 1 + Current sample, line, band is: 66 92 1 + Current sample, line, band is: 66 93 1 + Current sample, line, band is: 66 94 1 + Current sample, line, band is: 66 95 1 + Current sample, line, band is: 66 96 1 + Current sample, line, band is: 66 97 1 + Current sample, line, band is: 66 98 1 + Current sample, line, band is: 66 99 1 + Current sample, line, band is: 66 100 1 + Current sample, line, band is: 66 101 1 + Current sample, line, band is: 66 102 1 + Current sample, line, band is: 66 103 1 + Current sample, line, band is: 66 104 1 + Current sample, line, band is: 66 105 1 + Current sample, line, band is: 66 106 1 + Current sample, line, band is: 66 107 1 + Current sample, line, band is: 66 108 1 + Current sample, line, band is: 66 109 1 + Current sample, line, band is: 66 110 1 + Current sample, line, band is: 66 111 1 + Current sample, line, band is: 66 112 1 + Current sample, line, band is: 66 113 1 + Current sample, line, band is: 66 114 1 + Current sample, line, band is: 66 115 1 + Current sample, line, band is: 66 116 1 + Current sample, line, band is: 66 117 1 + Current sample, line, band is: 66 118 1 + Current sample, line, band is: 66 119 1 + Current sample, line, band is: 66 120 1 + Current sample, line, band is: 66 121 1 + Current sample, line, band is: 66 122 1 + Current sample, line, band is: 66 123 1 + Current sample, line, band is: 66 124 1 + Current sample, line, band is: 66 125 1 + Current sample, line, band is: 66 126 1 + Current sample, line, band is: 67 1 1 + Current sample, line, band is: 67 2 1 + Current sample, line, band is: 67 3 1 + Current sample, line, band is: 67 4 1 + Current sample, line, band is: 67 5 1 + Current sample, line, band is: 67 6 1 + Current sample, line, band is: 67 7 1 + Current sample, line, band is: 67 8 1 + Current sample, line, band is: 67 9 1 + Current sample, line, band is: 67 10 1 + Current sample, line, band is: 67 11 1 + Current sample, line, band is: 67 12 1 + Current sample, line, band is: 67 13 1 + Current sample, line, band is: 67 14 1 + Current sample, line, band is: 67 15 1 + Current sample, line, band is: 67 16 1 + Current sample, line, band is: 67 17 1 + Current sample, line, band is: 67 18 1 + Current sample, line, band is: 67 19 1 + Current sample, line, band is: 67 20 1 + Current sample, line, band is: 67 21 1 + Current sample, line, band is: 67 22 1 + Current sample, line, band is: 67 23 1 + Current sample, line, band is: 67 24 1 + Current sample, line, band is: 67 25 1 + Current sample, line, band is: 67 26 1 + Current sample, line, band is: 67 27 1 + Current sample, line, band is: 67 28 1 + Current sample, line, band is: 67 29 1 + Current sample, line, band is: 67 30 1 + Current sample, line, band is: 67 31 1 + Current sample, line, band is: 67 32 1 + Current sample, line, band is: 67 33 1 + Current sample, line, band is: 67 34 1 + Current sample, line, band is: 67 35 1 + Current sample, line, band is: 67 36 1 + Current sample, line, band is: 67 37 1 + Current sample, line, band is: 67 38 1 + Current sample, line, band is: 67 39 1 + Current sample, line, band is: 67 40 1 + Current sample, line, band is: 67 41 1 + Current sample, line, band is: 67 42 1 + Current sample, line, band is: 67 43 1 + Current sample, line, band is: 67 44 1 + Current sample, line, band is: 67 45 1 + Current sample, line, band is: 67 46 1 + Current sample, line, band is: 67 47 1 + Current sample, line, band is: 67 48 1 + Current sample, line, band is: 67 49 1 + Current sample, line, band is: 67 50 1 + Current sample, line, band is: 67 51 1 + Current sample, line, band is: 67 52 1 + Current sample, line, band is: 67 53 1 + Current sample, line, band is: 67 54 1 + Current sample, line, band is: 67 55 1 + Current sample, line, band is: 67 56 1 + Current sample, line, band is: 67 57 1 + Current sample, line, band is: 67 58 1 + Current sample, line, band is: 67 59 1 + Current sample, line, band is: 67 60 1 + Current sample, line, band is: 67 61 1 + Current sample, line, band is: 67 62 1 + Current sample, line, band is: 67 63 1 + Current sample, line, band is: 67 64 1 + Current sample, line, band is: 67 65 1 + Current sample, line, band is: 67 66 1 + Current sample, line, band is: 67 67 1 + Current sample, line, band is: 67 68 1 + Current sample, line, band is: 67 69 1 + Current sample, line, band is: 67 70 1 + Current sample, line, band is: 67 71 1 + Current sample, line, band is: 67 72 1 + Current sample, line, band is: 67 73 1 + Current sample, line, band is: 67 74 1 + Current sample, line, band is: 67 75 1 + Current sample, line, band is: 67 76 1 + Current sample, line, band is: 67 77 1 + Current sample, line, band is: 67 78 1 + Current sample, line, band is: 67 79 1 + Current sample, line, band is: 67 80 1 + Current sample, line, band is: 67 81 1 + Current sample, line, band is: 67 82 1 + Current sample, line, band is: 67 83 1 + Current sample, line, band is: 67 84 1 + Current sample, line, band is: 67 85 1 + Current sample, line, band is: 67 86 1 + Current sample, line, band is: 67 87 1 + Current sample, line, band is: 67 88 1 + Current sample, line, band is: 67 89 1 + Current sample, line, band is: 67 90 1 + Current sample, line, band is: 67 91 1 + Current sample, line, band is: 67 92 1 + Current sample, line, band is: 67 93 1 + Current sample, line, band is: 67 94 1 + Current sample, line, band is: 67 95 1 + Current sample, line, band is: 67 96 1 + Current sample, line, band is: 67 97 1 + Current sample, line, band is: 67 98 1 + Current sample, line, band is: 67 99 1 + Current sample, line, band is: 67 100 1 + Current sample, line, band is: 67 101 1 + Current sample, line, band is: 67 102 1 + Current sample, line, band is: 67 103 1 + Current sample, line, band is: 67 104 1 + Current sample, line, band is: 67 105 1 + Current sample, line, band is: 67 106 1 + Current sample, line, band is: 67 107 1 + Current sample, line, band is: 67 108 1 + Current sample, line, band is: 67 109 1 + Current sample, line, band is: 67 110 1 + Current sample, line, band is: 67 111 1 + Current sample, line, band is: 67 112 1 + Current sample, line, band is: 67 113 1 + Current sample, line, band is: 67 114 1 + Current sample, line, band is: 67 115 1 + Current sample, line, band is: 67 116 1 + Current sample, line, band is: 67 117 1 + Current sample, line, band is: 67 118 1 + Current sample, line, band is: 67 119 1 + Current sample, line, band is: 67 120 1 + Current sample, line, band is: 67 121 1 + Current sample, line, band is: 67 122 1 + Current sample, line, band is: 67 123 1 + Current sample, line, band is: 67 124 1 + Current sample, line, band is: 67 125 1 + Current sample, line, band is: 67 126 1 + Current sample, line, band is: 68 1 1 + Current sample, line, band is: 68 2 1 + Current sample, line, band is: 68 3 1 + Current sample, line, band is: 68 4 1 + Current sample, line, band is: 68 5 1 + Current sample, line, band is: 68 6 1 + Current sample, line, band is: 68 7 1 + Current sample, line, band is: 68 8 1 + Current sample, line, band is: 68 9 1 + Current sample, line, band is: 68 10 1 + Current sample, line, band is: 68 11 1 + Current sample, line, band is: 68 12 1 + Current sample, line, band is: 68 13 1 + Current sample, line, band is: 68 14 1 + Current sample, line, band is: 68 15 1 + Current sample, line, band is: 68 16 1 + Current sample, line, band is: 68 17 1 + Current sample, line, band is: 68 18 1 + Current sample, line, band is: 68 19 1 + Current sample, line, band is: 68 20 1 + Current sample, line, band is: 68 21 1 + Current sample, line, band is: 68 22 1 + Current sample, line, band is: 68 23 1 + Current sample, line, band is: 68 24 1 + Current sample, line, band is: 68 25 1 + Current sample, line, band is: 68 26 1 + Current sample, line, band is: 68 27 1 + Current sample, line, band is: 68 28 1 + Current sample, line, band is: 68 29 1 + Current sample, line, band is: 68 30 1 + Current sample, line, band is: 68 31 1 + Current sample, line, band is: 68 32 1 + Current sample, line, band is: 68 33 1 + Current sample, line, band is: 68 34 1 + Current sample, line, band is: 68 35 1 + Current sample, line, band is: 68 36 1 + Current sample, line, band is: 68 37 1 + Current sample, line, band is: 68 38 1 + Current sample, line, band is: 68 39 1 + Current sample, line, band is: 68 40 1 + Current sample, line, band is: 68 41 1 + Current sample, line, band is: 68 42 1 + Current sample, line, band is: 68 43 1 + Current sample, line, band is: 68 44 1 + Current sample, line, band is: 68 45 1 + Current sample, line, band is: 68 46 1 + Current sample, line, band is: 68 47 1 + Current sample, line, band is: 68 48 1 + Current sample, line, band is: 68 49 1 + Current sample, line, band is: 68 50 1 + Current sample, line, band is: 68 51 1 + Current sample, line, band is: 68 52 1 + Current sample, line, band is: 68 53 1 + Current sample, line, band is: 68 54 1 + Current sample, line, band is: 68 55 1 + Current sample, line, band is: 68 56 1 + Current sample, line, band is: 68 57 1 + Current sample, line, band is: 68 58 1 + Current sample, line, band is: 68 59 1 + Current sample, line, band is: 68 60 1 + Current sample, line, band is: 68 61 1 + Current sample, line, band is: 68 62 1 + Current sample, line, band is: 68 63 1 + Current sample, line, band is: 68 64 1 + Current sample, line, band is: 68 65 1 + Current sample, line, band is: 68 66 1 + Current sample, line, band is: 68 67 1 + Current sample, line, band is: 68 68 1 + Current sample, line, band is: 68 69 1 + Current sample, line, band is: 68 70 1 + Current sample, line, band is: 68 71 1 + Current sample, line, band is: 68 72 1 + Current sample, line, band is: 68 73 1 + Current sample, line, band is: 68 74 1 + Current sample, line, band is: 68 75 1 + Current sample, line, band is: 68 76 1 + Current sample, line, band is: 68 77 1 + Current sample, line, band is: 68 78 1 + Current sample, line, band is: 68 79 1 + Current sample, line, band is: 68 80 1 + Current sample, line, band is: 68 81 1 + Current sample, line, band is: 68 82 1 + Current sample, line, band is: 68 83 1 + Current sample, line, band is: 68 84 1 + Current sample, line, band is: 68 85 1 + Current sample, line, band is: 68 86 1 + Current sample, line, band is: 68 87 1 + Current sample, line, band is: 68 88 1 + Current sample, line, band is: 68 89 1 + Current sample, line, band is: 68 90 1 + Current sample, line, band is: 68 91 1 + Current sample, line, band is: 68 92 1 + Current sample, line, band is: 68 93 1 + Current sample, line, band is: 68 94 1 + Current sample, line, band is: 68 95 1 + Current sample, line, band is: 68 96 1 + Current sample, line, band is: 68 97 1 + Current sample, line, band is: 68 98 1 + Current sample, line, band is: 68 99 1 + Current sample, line, band is: 68 100 1 + Current sample, line, band is: 68 101 1 + Current sample, line, band is: 68 102 1 + Current sample, line, band is: 68 103 1 + Current sample, line, band is: 68 104 1 + Current sample, line, band is: 68 105 1 + Current sample, line, band is: 68 106 1 + Current sample, line, band is: 68 107 1 + Current sample, line, band is: 68 108 1 + Current sample, line, band is: 68 109 1 + Current sample, line, band is: 68 110 1 + Current sample, line, band is: 68 111 1 + Current sample, line, band is: 68 112 1 + Current sample, line, band is: 68 113 1 + Current sample, line, band is: 68 114 1 + Current sample, line, band is: 68 115 1 + Current sample, line, band is: 68 116 1 + Current sample, line, band is: 68 117 1 + Current sample, line, band is: 68 118 1 + Current sample, line, band is: 68 119 1 + Current sample, line, band is: 68 120 1 + Current sample, line, band is: 68 121 1 + Current sample, line, band is: 68 122 1 + Current sample, line, band is: 68 123 1 + Current sample, line, band is: 68 124 1 + Current sample, line, band is: 68 125 1 + Current sample, line, band is: 68 126 1 + Current sample, line, band is: 69 1 1 + Current sample, line, band is: 69 2 1 + Current sample, line, band is: 69 3 1 + Current sample, line, band is: 69 4 1 + Current sample, line, band is: 69 5 1 + Current sample, line, band is: 69 6 1 + Current sample, line, band is: 69 7 1 + Current sample, line, band is: 69 8 1 + Current sample, line, band is: 69 9 1 + Current sample, line, band is: 69 10 1 + Current sample, line, band is: 69 11 1 + Current sample, line, band is: 69 12 1 + Current sample, line, band is: 69 13 1 + Current sample, line, band is: 69 14 1 + Current sample, line, band is: 69 15 1 + Current sample, line, band is: 69 16 1 + Current sample, line, band is: 69 17 1 + Current sample, line, band is: 69 18 1 + Current sample, line, band is: 69 19 1 + Current sample, line, band is: 69 20 1 + Current sample, line, band is: 69 21 1 + Current sample, line, band is: 69 22 1 + Current sample, line, band is: 69 23 1 + Current sample, line, band is: 69 24 1 + Current sample, line, band is: 69 25 1 + Current sample, line, band is: 69 26 1 + Current sample, line, band is: 69 27 1 + Current sample, line, band is: 69 28 1 + Current sample, line, band is: 69 29 1 + Current sample, line, band is: 69 30 1 + Current sample, line, band is: 69 31 1 + Current sample, line, band is: 69 32 1 + Current sample, line, band is: 69 33 1 + Current sample, line, band is: 69 34 1 + Current sample, line, band is: 69 35 1 + Current sample, line, band is: 69 36 1 + Current sample, line, band is: 69 37 1 + Current sample, line, band is: 69 38 1 + Current sample, line, band is: 69 39 1 + Current sample, line, band is: 69 40 1 + Current sample, line, band is: 69 41 1 + Current sample, line, band is: 69 42 1 + Current sample, line, band is: 69 43 1 + Current sample, line, band is: 69 44 1 + Current sample, line, band is: 69 45 1 + Current sample, line, band is: 69 46 1 + Current sample, line, band is: 69 47 1 + Current sample, line, band is: 69 48 1 + Current sample, line, band is: 69 49 1 + Current sample, line, band is: 69 50 1 + Current sample, line, band is: 69 51 1 + Current sample, line, band is: 69 52 1 + Current sample, line, band is: 69 53 1 + Current sample, line, band is: 69 54 1 + Current sample, line, band is: 69 55 1 + Current sample, line, band is: 69 56 1 + Current sample, line, band is: 69 57 1 + Current sample, line, band is: 69 58 1 + Current sample, line, band is: 69 59 1 + Current sample, line, band is: 69 60 1 + Current sample, line, band is: 69 61 1 + Current sample, line, band is: 69 62 1 + Current sample, line, band is: 69 63 1 + Current sample, line, band is: 69 64 1 + Current sample, line, band is: 69 65 1 + Current sample, line, band is: 69 66 1 + Current sample, line, band is: 69 67 1 + Current sample, line, band is: 69 68 1 + Current sample, line, band is: 69 69 1 + Current sample, line, band is: 69 70 1 + Current sample, line, band is: 69 71 1 + Current sample, line, band is: 69 72 1 + Current sample, line, band is: 69 73 1 + Current sample, line, band is: 69 74 1 + Current sample, line, band is: 69 75 1 + Current sample, line, band is: 69 76 1 + Current sample, line, band is: 69 77 1 + Current sample, line, band is: 69 78 1 + Current sample, line, band is: 69 79 1 + Current sample, line, band is: 69 80 1 + Current sample, line, band is: 69 81 1 + Current sample, line, band is: 69 82 1 + Current sample, line, band is: 69 83 1 + Current sample, line, band is: 69 84 1 + Current sample, line, band is: 69 85 1 + Current sample, line, band is: 69 86 1 + Current sample, line, band is: 69 87 1 + Current sample, line, band is: 69 88 1 + Current sample, line, band is: 69 89 1 + Current sample, line, band is: 69 90 1 + Current sample, line, band is: 69 91 1 + Current sample, line, band is: 69 92 1 + Current sample, line, band is: 69 93 1 + Current sample, line, band is: 69 94 1 + Current sample, line, band is: 69 95 1 + Current sample, line, band is: 69 96 1 + Current sample, line, band is: 69 97 1 + Current sample, line, band is: 69 98 1 + Current sample, line, band is: 69 99 1 + Current sample, line, band is: 69 100 1 + Current sample, line, band is: 69 101 1 + Current sample, line, band is: 69 102 1 + Current sample, line, band is: 69 103 1 + Current sample, line, band is: 69 104 1 + Current sample, line, band is: 69 105 1 + Current sample, line, band is: 69 106 1 + Current sample, line, band is: 69 107 1 + Current sample, line, band is: 69 108 1 + Current sample, line, band is: 69 109 1 + Current sample, line, band is: 69 110 1 + Current sample, line, band is: 69 111 1 + Current sample, line, band is: 69 112 1 + Current sample, line, band is: 69 113 1 + Current sample, line, band is: 69 114 1 + Current sample, line, band is: 69 115 1 + Current sample, line, band is: 69 116 1 + Current sample, line, band is: 69 117 1 + Current sample, line, band is: 69 118 1 + Current sample, line, band is: 69 119 1 + Current sample, line, band is: 69 120 1 + Current sample, line, band is: 69 121 1 + Current sample, line, band is: 69 122 1 + Current sample, line, band is: 69 123 1 + Current sample, line, band is: 69 124 1 + Current sample, line, band is: 69 125 1 + Current sample, line, band is: 69 126 1 + Current sample, line, band is: 70 1 1 + Current sample, line, band is: 70 2 1 + Current sample, line, band is: 70 3 1 + Current sample, line, band is: 70 4 1 + Current sample, line, band is: 70 5 1 + Current sample, line, band is: 70 6 1 + Current sample, line, band is: 70 7 1 + Current sample, line, band is: 70 8 1 + Current sample, line, band is: 70 9 1 + Current sample, line, band is: 70 10 1 + Current sample, line, band is: 70 11 1 + Current sample, line, band is: 70 12 1 + Current sample, line, band is: 70 13 1 + Current sample, line, band is: 70 14 1 + Current sample, line, band is: 70 15 1 + Current sample, line, band is: 70 16 1 + Current sample, line, band is: 70 17 1 + Current sample, line, band is: 70 18 1 + Current sample, line, band is: 70 19 1 + Current sample, line, band is: 70 20 1 + Current sample, line, band is: 70 21 1 + Current sample, line, band is: 70 22 1 + Current sample, line, band is: 70 23 1 + Current sample, line, band is: 70 24 1 + Current sample, line, band is: 70 25 1 + Current sample, line, band is: 70 26 1 + Current sample, line, band is: 70 27 1 + Current sample, line, band is: 70 28 1 + Current sample, line, band is: 70 29 1 + Current sample, line, band is: 70 30 1 + Current sample, line, band is: 70 31 1 + Current sample, line, band is: 70 32 1 + Current sample, line, band is: 70 33 1 + Current sample, line, band is: 70 34 1 + Current sample, line, band is: 70 35 1 + Current sample, line, band is: 70 36 1 + Current sample, line, band is: 70 37 1 + Current sample, line, band is: 70 38 1 + Current sample, line, band is: 70 39 1 + Current sample, line, band is: 70 40 1 + Current sample, line, band is: 70 41 1 + Current sample, line, band is: 70 42 1 + Current sample, line, band is: 70 43 1 + Current sample, line, band is: 70 44 1 + Current sample, line, band is: 70 45 1 + Current sample, line, band is: 70 46 1 + Current sample, line, band is: 70 47 1 + Current sample, line, band is: 70 48 1 + Current sample, line, band is: 70 49 1 + Current sample, line, band is: 70 50 1 + Current sample, line, band is: 70 51 1 + Current sample, line, band is: 70 52 1 + Current sample, line, band is: 70 53 1 + Current sample, line, band is: 70 54 1 + Current sample, line, band is: 70 55 1 + Current sample, line, band is: 70 56 1 + Current sample, line, band is: 70 57 1 + Current sample, line, band is: 70 58 1 + Current sample, line, band is: 70 59 1 + Current sample, line, band is: 70 60 1 + Current sample, line, band is: 70 61 1 + Current sample, line, band is: 70 62 1 + Current sample, line, band is: 70 63 1 + Current sample, line, band is: 70 64 1 + Current sample, line, band is: 70 65 1 + Current sample, line, band is: 70 66 1 + Current sample, line, band is: 70 67 1 + Current sample, line, band is: 70 68 1 + Current sample, line, band is: 70 69 1 + Current sample, line, band is: 70 70 1 + Current sample, line, band is: 70 71 1 + Current sample, line, band is: 70 72 1 + Current sample, line, band is: 70 73 1 + Current sample, line, band is: 70 74 1 + Current sample, line, band is: 70 75 1 + Current sample, line, band is: 70 76 1 + Current sample, line, band is: 70 77 1 + Current sample, line, band is: 70 78 1 + Current sample, line, band is: 70 79 1 + Current sample, line, band is: 70 80 1 + Current sample, line, band is: 70 81 1 + Current sample, line, band is: 70 82 1 + Current sample, line, band is: 70 83 1 + Current sample, line, band is: 70 84 1 + Current sample, line, band is: 70 85 1 + Current sample, line, band is: 70 86 1 + Current sample, line, band is: 70 87 1 + Current sample, line, band is: 70 88 1 + Current sample, line, band is: 70 89 1 + Current sample, line, band is: 70 90 1 + Current sample, line, band is: 70 91 1 + Current sample, line, band is: 70 92 1 + Current sample, line, band is: 70 93 1 + Current sample, line, band is: 70 94 1 + Current sample, line, band is: 70 95 1 + Current sample, line, band is: 70 96 1 + Current sample, line, band is: 70 97 1 + Current sample, line, band is: 70 98 1 + Current sample, line, band is: 70 99 1 + Current sample, line, band is: 70 100 1 + Current sample, line, band is: 70 101 1 + Current sample, line, band is: 70 102 1 + Current sample, line, band is: 70 103 1 + Current sample, line, band is: 70 104 1 + Current sample, line, band is: 70 105 1 + Current sample, line, band is: 70 106 1 + Current sample, line, band is: 70 107 1 + Current sample, line, band is: 70 108 1 + Current sample, line, band is: 70 109 1 + Current sample, line, band is: 70 110 1 + Current sample, line, band is: 70 111 1 + Current sample, line, band is: 70 112 1 + Current sample, line, band is: 70 113 1 + Current sample, line, band is: 70 114 1 + Current sample, line, band is: 70 115 1 + Current sample, line, band is: 70 116 1 + Current sample, line, band is: 70 117 1 + Current sample, line, band is: 70 118 1 + Current sample, line, band is: 70 119 1 + Current sample, line, band is: 70 120 1 + Current sample, line, band is: 70 121 1 + Current sample, line, band is: 70 122 1 + Current sample, line, band is: 70 123 1 + Current sample, line, band is: 70 124 1 + Current sample, line, band is: 70 125 1 + Current sample, line, band is: 70 126 1 + Current sample, line, band is: 71 1 1 + Current sample, line, band is: 71 2 1 + Current sample, line, band is: 71 3 1 + Current sample, line, band is: 71 4 1 + Current sample, line, band is: 71 5 1 + Current sample, line, band is: 71 6 1 + Current sample, line, band is: 71 7 1 + Current sample, line, band is: 71 8 1 + Current sample, line, band is: 71 9 1 + Current sample, line, band is: 71 10 1 + Current sample, line, band is: 71 11 1 + Current sample, line, band is: 71 12 1 + Current sample, line, band is: 71 13 1 + Current sample, line, band is: 71 14 1 + Current sample, line, band is: 71 15 1 + Current sample, line, band is: 71 16 1 + Current sample, line, band is: 71 17 1 + Current sample, line, band is: 71 18 1 + Current sample, line, band is: 71 19 1 + Current sample, line, band is: 71 20 1 + Current sample, line, band is: 71 21 1 + Current sample, line, band is: 71 22 1 + Current sample, line, band is: 71 23 1 + Current sample, line, band is: 71 24 1 + Current sample, line, band is: 71 25 1 + Current sample, line, band is: 71 26 1 + Current sample, line, band is: 71 27 1 + Current sample, line, band is: 71 28 1 + Current sample, line, band is: 71 29 1 + Current sample, line, band is: 71 30 1 + Current sample, line, band is: 71 31 1 + Current sample, line, band is: 71 32 1 + Current sample, line, band is: 71 33 1 + Current sample, line, band is: 71 34 1 + Current sample, line, band is: 71 35 1 + Current sample, line, band is: 71 36 1 + Current sample, line, band is: 71 37 1 + Current sample, line, band is: 71 38 1 + Current sample, line, band is: 71 39 1 + Current sample, line, band is: 71 40 1 + Current sample, line, band is: 71 41 1 + Current sample, line, band is: 71 42 1 + Current sample, line, band is: 71 43 1 + Current sample, line, band is: 71 44 1 + Current sample, line, band is: 71 45 1 + Current sample, line, band is: 71 46 1 + Current sample, line, band is: 71 47 1 + Current sample, line, band is: 71 48 1 + Current sample, line, band is: 71 49 1 + Current sample, line, band is: 71 50 1 + Current sample, line, band is: 71 51 1 + Current sample, line, band is: 71 52 1 + Current sample, line, band is: 71 53 1 + Current sample, line, band is: 71 54 1 + Current sample, line, band is: 71 55 1 + Current sample, line, band is: 71 56 1 + Current sample, line, band is: 71 57 1 + Current sample, line, band is: 71 58 1 + Current sample, line, band is: 71 59 1 + Current sample, line, band is: 71 60 1 + Current sample, line, band is: 71 61 1 + Current sample, line, band is: 71 62 1 + Current sample, line, band is: 71 63 1 + Current sample, line, band is: 71 64 1 + Current sample, line, band is: 71 65 1 + Current sample, line, band is: 71 66 1 + Current sample, line, band is: 71 67 1 + Current sample, line, band is: 71 68 1 + Current sample, line, band is: 71 69 1 + Current sample, line, band is: 71 70 1 + Current sample, line, band is: 71 71 1 + Current sample, line, band is: 71 72 1 + Current sample, line, band is: 71 73 1 + Current sample, line, band is: 71 74 1 + Current sample, line, band is: 71 75 1 + Current sample, line, band is: 71 76 1 + Current sample, line, band is: 71 77 1 + Current sample, line, band is: 71 78 1 + Current sample, line, band is: 71 79 1 + Current sample, line, band is: 71 80 1 + Current sample, line, band is: 71 81 1 + Current sample, line, band is: 71 82 1 + Current sample, line, band is: 71 83 1 + Current sample, line, band is: 71 84 1 + Current sample, line, band is: 71 85 1 + Current sample, line, band is: 71 86 1 + Current sample, line, band is: 71 87 1 + Current sample, line, band is: 71 88 1 + Current sample, line, band is: 71 89 1 + Current sample, line, band is: 71 90 1 + Current sample, line, band is: 71 91 1 + Current sample, line, band is: 71 92 1 + Current sample, line, band is: 71 93 1 + Current sample, line, band is: 71 94 1 + Current sample, line, band is: 71 95 1 + Current sample, line, band is: 71 96 1 + Current sample, line, band is: 71 97 1 + Current sample, line, band is: 71 98 1 + Current sample, line, band is: 71 99 1 + Current sample, line, band is: 71 100 1 + Current sample, line, band is: 71 101 1 + Current sample, line, band is: 71 102 1 + Current sample, line, band is: 71 103 1 + Current sample, line, band is: 71 104 1 + Current sample, line, band is: 71 105 1 + Current sample, line, band is: 71 106 1 + Current sample, line, band is: 71 107 1 + Current sample, line, band is: 71 108 1 + Current sample, line, band is: 71 109 1 + Current sample, line, band is: 71 110 1 + Current sample, line, band is: 71 111 1 + Current sample, line, band is: 71 112 1 + Current sample, line, band is: 71 113 1 + Current sample, line, band is: 71 114 1 + Current sample, line, band is: 71 115 1 + Current sample, line, band is: 71 116 1 + Current sample, line, band is: 71 117 1 + Current sample, line, band is: 71 118 1 + Current sample, line, band is: 71 119 1 + Current sample, line, band is: 71 120 1 + Current sample, line, band is: 71 121 1 + Current sample, line, band is: 71 122 1 + Current sample, line, band is: 71 123 1 + Current sample, line, band is: 71 124 1 + Current sample, line, band is: 71 125 1 + Current sample, line, band is: 71 126 1 + Current sample, line, band is: 72 1 1 + Current sample, line, band is: 72 2 1 + Current sample, line, band is: 72 3 1 + Current sample, line, band is: 72 4 1 + Current sample, line, band is: 72 5 1 + Current sample, line, band is: 72 6 1 + Current sample, line, band is: 72 7 1 + Current sample, line, band is: 72 8 1 + Current sample, line, band is: 72 9 1 + Current sample, line, band is: 72 10 1 + Current sample, line, band is: 72 11 1 + Current sample, line, band is: 72 12 1 + Current sample, line, band is: 72 13 1 + Current sample, line, band is: 72 14 1 + Current sample, line, band is: 72 15 1 + Current sample, line, band is: 72 16 1 + Current sample, line, band is: 72 17 1 + Current sample, line, band is: 72 18 1 + Current sample, line, band is: 72 19 1 + Current sample, line, band is: 72 20 1 + Current sample, line, band is: 72 21 1 + Current sample, line, band is: 72 22 1 + Current sample, line, band is: 72 23 1 + Current sample, line, band is: 72 24 1 + Current sample, line, band is: 72 25 1 + Current sample, line, band is: 72 26 1 + Current sample, line, band is: 72 27 1 + Current sample, line, band is: 72 28 1 + Current sample, line, band is: 72 29 1 + Current sample, line, band is: 72 30 1 + Current sample, line, band is: 72 31 1 + Current sample, line, band is: 72 32 1 + Current sample, line, band is: 72 33 1 + Current sample, line, band is: 72 34 1 + Current sample, line, band is: 72 35 1 + Current sample, line, band is: 72 36 1 + Current sample, line, band is: 72 37 1 + Current sample, line, band is: 72 38 1 + Current sample, line, band is: 72 39 1 + Current sample, line, band is: 72 40 1 + Current sample, line, band is: 72 41 1 + Current sample, line, band is: 72 42 1 + Current sample, line, band is: 72 43 1 + Current sample, line, band is: 72 44 1 + Current sample, line, band is: 72 45 1 + Current sample, line, band is: 72 46 1 + Current sample, line, band is: 72 47 1 + Current sample, line, band is: 72 48 1 + Current sample, line, band is: 72 49 1 + Current sample, line, band is: 72 50 1 + Current sample, line, band is: 72 51 1 + Current sample, line, band is: 72 52 1 + Current sample, line, band is: 72 53 1 + Current sample, line, band is: 72 54 1 + Current sample, line, band is: 72 55 1 + Current sample, line, band is: 72 56 1 + Current sample, line, band is: 72 57 1 + Current sample, line, band is: 72 58 1 + Current sample, line, band is: 72 59 1 + Current sample, line, band is: 72 60 1 + Current sample, line, band is: 72 61 1 + Current sample, line, band is: 72 62 1 + Current sample, line, band is: 72 63 1 + Current sample, line, band is: 72 64 1 + Current sample, line, band is: 72 65 1 + Current sample, line, band is: 72 66 1 + Current sample, line, band is: 72 67 1 + Current sample, line, band is: 72 68 1 + Current sample, line, band is: 72 69 1 + Current sample, line, band is: 72 70 1 + Current sample, line, band is: 72 71 1 + Current sample, line, band is: 72 72 1 + Current sample, line, band is: 72 73 1 + Current sample, line, band is: 72 74 1 + Current sample, line, band is: 72 75 1 + Current sample, line, band is: 72 76 1 + Current sample, line, band is: 72 77 1 + Current sample, line, band is: 72 78 1 + Current sample, line, band is: 72 79 1 + Current sample, line, band is: 72 80 1 + Current sample, line, band is: 72 81 1 + Current sample, line, band is: 72 82 1 + Current sample, line, band is: 72 83 1 + Current sample, line, band is: 72 84 1 + Current sample, line, band is: 72 85 1 + Current sample, line, band is: 72 86 1 + Current sample, line, band is: 72 87 1 + Current sample, line, band is: 72 88 1 + Current sample, line, band is: 72 89 1 + Current sample, line, band is: 72 90 1 + Current sample, line, band is: 72 91 1 + Current sample, line, band is: 72 92 1 + Current sample, line, band is: 72 93 1 + Current sample, line, band is: 72 94 1 + Current sample, line, band is: 72 95 1 + Current sample, line, band is: 72 96 1 + Current sample, line, band is: 72 97 1 + Current sample, line, band is: 72 98 1 + Current sample, line, band is: 72 99 1 + Current sample, line, band is: 72 100 1 + Current sample, line, band is: 72 101 1 + Current sample, line, band is: 72 102 1 + Current sample, line, band is: 72 103 1 + Current sample, line, band is: 72 104 1 + Current sample, line, band is: 72 105 1 + Current sample, line, band is: 72 106 1 + Current sample, line, band is: 72 107 1 + Current sample, line, band is: 72 108 1 + Current sample, line, band is: 72 109 1 + Current sample, line, band is: 72 110 1 + Current sample, line, band is: 72 111 1 + Current sample, line, band is: 72 112 1 + Current sample, line, band is: 72 113 1 + Current sample, line, band is: 72 114 1 + Current sample, line, band is: 72 115 1 + Current sample, line, band is: 72 116 1 + Current sample, line, band is: 72 117 1 + Current sample, line, band is: 72 118 1 + Current sample, line, band is: 72 119 1 + Current sample, line, band is: 72 120 1 + Current sample, line, band is: 72 121 1 + Current sample, line, band is: 72 122 1 + Current sample, line, band is: 72 123 1 + Current sample, line, band is: 72 124 1 + Current sample, line, band is: 72 125 1 + Current sample, line, band is: 72 126 1 + Current sample, line, band is: 73 1 1 + Current sample, line, band is: 73 2 1 + Current sample, line, band is: 73 3 1 + Current sample, line, band is: 73 4 1 + Current sample, line, band is: 73 5 1 + Current sample, line, band is: 73 6 1 + Current sample, line, band is: 73 7 1 + Current sample, line, band is: 73 8 1 + Current sample, line, band is: 73 9 1 + Current sample, line, band is: 73 10 1 + Current sample, line, band is: 73 11 1 + Current sample, line, band is: 73 12 1 + Current sample, line, band is: 73 13 1 + Current sample, line, band is: 73 14 1 + Current sample, line, band is: 73 15 1 + Current sample, line, band is: 73 16 1 + Current sample, line, band is: 73 17 1 + Current sample, line, band is: 73 18 1 + Current sample, line, band is: 73 19 1 + Current sample, line, band is: 73 20 1 + Current sample, line, band is: 73 21 1 + Current sample, line, band is: 73 22 1 + Current sample, line, band is: 73 23 1 + Current sample, line, band is: 73 24 1 + Current sample, line, band is: 73 25 1 + Current sample, line, band is: 73 26 1 + Current sample, line, band is: 73 27 1 + Current sample, line, band is: 73 28 1 + Current sample, line, band is: 73 29 1 + Current sample, line, band is: 73 30 1 + Current sample, line, band is: 73 31 1 + Current sample, line, band is: 73 32 1 + Current sample, line, band is: 73 33 1 + Current sample, line, band is: 73 34 1 + Current sample, line, band is: 73 35 1 + Current sample, line, band is: 73 36 1 + Current sample, line, band is: 73 37 1 + Current sample, line, band is: 73 38 1 + Current sample, line, band is: 73 39 1 + Current sample, line, band is: 73 40 1 + Current sample, line, band is: 73 41 1 + Current sample, line, band is: 73 42 1 + Current sample, line, band is: 73 43 1 + Current sample, line, band is: 73 44 1 + Current sample, line, band is: 73 45 1 + Current sample, line, band is: 73 46 1 + Current sample, line, band is: 73 47 1 + Current sample, line, band is: 73 48 1 + Current sample, line, band is: 73 49 1 + Current sample, line, band is: 73 50 1 + Current sample, line, band is: 73 51 1 + Current sample, line, band is: 73 52 1 + Current sample, line, band is: 73 53 1 + Current sample, line, band is: 73 54 1 + Current sample, line, band is: 73 55 1 + Current sample, line, band is: 73 56 1 + Current sample, line, band is: 73 57 1 + Current sample, line, band is: 73 58 1 + Current sample, line, band is: 73 59 1 + Current sample, line, band is: 73 60 1 + Current sample, line, band is: 73 61 1 + Current sample, line, band is: 73 62 1 + Current sample, line, band is: 73 63 1 + Current sample, line, band is: 73 64 1 + Current sample, line, band is: 73 65 1 + Current sample, line, band is: 73 66 1 + Current sample, line, band is: 73 67 1 + Current sample, line, band is: 73 68 1 + Current sample, line, band is: 73 69 1 + Current sample, line, band is: 73 70 1 + Current sample, line, band is: 73 71 1 + Current sample, line, band is: 73 72 1 + Current sample, line, band is: 73 73 1 + Current sample, line, band is: 73 74 1 + Current sample, line, band is: 73 75 1 + Current sample, line, band is: 73 76 1 + Current sample, line, band is: 73 77 1 + Current sample, line, band is: 73 78 1 + Current sample, line, band is: 73 79 1 + Current sample, line, band is: 73 80 1 + Current sample, line, band is: 73 81 1 + Current sample, line, band is: 73 82 1 + Current sample, line, band is: 73 83 1 + Current sample, line, band is: 73 84 1 + Current sample, line, band is: 73 85 1 + Current sample, line, band is: 73 86 1 + Current sample, line, band is: 73 87 1 + Current sample, line, band is: 73 88 1 + Current sample, line, band is: 73 89 1 + Current sample, line, band is: 73 90 1 + Current sample, line, band is: 73 91 1 + Current sample, line, band is: 73 92 1 + Current sample, line, band is: 73 93 1 + Current sample, line, band is: 73 94 1 + Current sample, line, band is: 73 95 1 + Current sample, line, band is: 73 96 1 + Current sample, line, band is: 73 97 1 + Current sample, line, band is: 73 98 1 + Current sample, line, band is: 73 99 1 + Current sample, line, band is: 73 100 1 + Current sample, line, band is: 73 101 1 + Current sample, line, band is: 73 102 1 + Current sample, line, band is: 73 103 1 + Current sample, line, band is: 73 104 1 + Current sample, line, band is: 73 105 1 + Current sample, line, band is: 73 106 1 + Current sample, line, band is: 73 107 1 + Current sample, line, band is: 73 108 1 + Current sample, line, band is: 73 109 1 + Current sample, line, band is: 73 110 1 + Current sample, line, band is: 73 111 1 + Current sample, line, band is: 73 112 1 + Current sample, line, band is: 73 113 1 + Current sample, line, band is: 73 114 1 + Current sample, line, band is: 73 115 1 + Current sample, line, band is: 73 116 1 + Current sample, line, band is: 73 117 1 + Current sample, line, band is: 73 118 1 + Current sample, line, band is: 73 119 1 + Current sample, line, band is: 73 120 1 + Current sample, line, band is: 73 121 1 + Current sample, line, band is: 73 122 1 + Current sample, line, band is: 73 123 1 + Current sample, line, band is: 73 124 1 + Current sample, line, band is: 73 125 1 + Current sample, line, band is: 73 126 1 + Current sample, line, band is: 74 1 1 + Current sample, line, band is: 74 2 1 + Current sample, line, band is: 74 3 1 + Current sample, line, band is: 74 4 1 + Current sample, line, band is: 74 5 1 + Current sample, line, band is: 74 6 1 + Current sample, line, band is: 74 7 1 + Current sample, line, band is: 74 8 1 + Current sample, line, band is: 74 9 1 + Current sample, line, band is: 74 10 1 + Current sample, line, band is: 74 11 1 + Current sample, line, band is: 74 12 1 + Current sample, line, band is: 74 13 1 + Current sample, line, band is: 74 14 1 + Current sample, line, band is: 74 15 1 + Current sample, line, band is: 74 16 1 + Current sample, line, band is: 74 17 1 + Current sample, line, band is: 74 18 1 + Current sample, line, band is: 74 19 1 + Current sample, line, band is: 74 20 1 + Current sample, line, band is: 74 21 1 + Current sample, line, band is: 74 22 1 + Current sample, line, band is: 74 23 1 + Current sample, line, band is: 74 24 1 + Current sample, line, band is: 74 25 1 + Current sample, line, band is: 74 26 1 + Current sample, line, band is: 74 27 1 + Current sample, line, band is: 74 28 1 + Current sample, line, band is: 74 29 1 + Current sample, line, band is: 74 30 1 + Current sample, line, band is: 74 31 1 + Current sample, line, band is: 74 32 1 + Current sample, line, band is: 74 33 1 + Current sample, line, band is: 74 34 1 + Current sample, line, band is: 74 35 1 + Current sample, line, band is: 74 36 1 + Current sample, line, band is: 74 37 1 + Current sample, line, band is: 74 38 1 + Current sample, line, band is: 74 39 1 + Current sample, line, band is: 74 40 1 + Current sample, line, band is: 74 41 1 + Current sample, line, band is: 74 42 1 + Current sample, line, band is: 74 43 1 + Current sample, line, band is: 74 44 1 + Current sample, line, band is: 74 45 1 + Current sample, line, band is: 74 46 1 + Current sample, line, band is: 74 47 1 + Current sample, line, band is: 74 48 1 + Current sample, line, band is: 74 49 1 + Current sample, line, band is: 74 50 1 + Current sample, line, band is: 74 51 1 + Current sample, line, band is: 74 52 1 + Current sample, line, band is: 74 53 1 + Current sample, line, band is: 74 54 1 + Current sample, line, band is: 74 55 1 + Current sample, line, band is: 74 56 1 + Current sample, line, band is: 74 57 1 + Current sample, line, band is: 74 58 1 + Current sample, line, band is: 74 59 1 + Current sample, line, band is: 74 60 1 + Current sample, line, band is: 74 61 1 + Current sample, line, band is: 74 62 1 + Current sample, line, band is: 74 63 1 + Current sample, line, band is: 74 64 1 + Current sample, line, band is: 74 65 1 + Current sample, line, band is: 74 66 1 + Current sample, line, band is: 74 67 1 + Current sample, line, band is: 74 68 1 + Current sample, line, band is: 74 69 1 + Current sample, line, band is: 74 70 1 + Current sample, line, band is: 74 71 1 + Current sample, line, band is: 74 72 1 + Current sample, line, band is: 74 73 1 + Current sample, line, band is: 74 74 1 + Current sample, line, band is: 74 75 1 + Current sample, line, band is: 74 76 1 + Current sample, line, band is: 74 77 1 + Current sample, line, band is: 74 78 1 + Current sample, line, band is: 74 79 1 + Current sample, line, band is: 74 80 1 + Current sample, line, band is: 74 81 1 + Current sample, line, band is: 74 82 1 + Current sample, line, band is: 74 83 1 + Current sample, line, band is: 74 84 1 + Current sample, line, band is: 74 85 1 + Current sample, line, band is: 74 86 1 + Current sample, line, band is: 74 87 1 + Current sample, line, band is: 74 88 1 + Current sample, line, band is: 74 89 1 + Current sample, line, band is: 74 90 1 + Current sample, line, band is: 74 91 1 + Current sample, line, band is: 74 92 1 + Current sample, line, band is: 74 93 1 + Current sample, line, band is: 74 94 1 + Current sample, line, band is: 74 95 1 + Current sample, line, band is: 74 96 1 + Current sample, line, band is: 74 97 1 + Current sample, line, band is: 74 98 1 + Current sample, line, band is: 74 99 1 + Current sample, line, band is: 74 100 1 + Current sample, line, band is: 74 101 1 + Current sample, line, band is: 74 102 1 + Current sample, line, band is: 74 103 1 + Current sample, line, band is: 74 104 1 + Current sample, line, band is: 74 105 1 + Current sample, line, band is: 74 106 1 + Current sample, line, band is: 74 107 1 + Current sample, line, band is: 74 108 1 + Current sample, line, band is: 74 109 1 + Current sample, line, band is: 74 110 1 + Current sample, line, band is: 74 111 1 + Current sample, line, band is: 74 112 1 + Current sample, line, band is: 74 113 1 + Current sample, line, band is: 74 114 1 + Current sample, line, band is: 74 115 1 + Current sample, line, band is: 74 116 1 + Current sample, line, band is: 74 117 1 + Current sample, line, band is: 74 118 1 + Current sample, line, band is: 74 119 1 + Current sample, line, band is: 74 120 1 + Current sample, line, band is: 74 121 1 + Current sample, line, band is: 74 122 1 + Current sample, line, band is: 74 123 1 + Current sample, line, band is: 74 124 1 + Current sample, line, band is: 74 125 1 + Current sample, line, band is: 74 126 1 + Current sample, line, band is: 75 1 1 + Current sample, line, band is: 75 2 1 + Current sample, line, band is: 75 3 1 + Current sample, line, band is: 75 4 1 + Current sample, line, band is: 75 5 1 + Current sample, line, band is: 75 6 1 + Current sample, line, band is: 75 7 1 + Current sample, line, band is: 75 8 1 + Current sample, line, band is: 75 9 1 + Current sample, line, band is: 75 10 1 + Current sample, line, band is: 75 11 1 + Current sample, line, band is: 75 12 1 + Current sample, line, band is: 75 13 1 + Current sample, line, band is: 75 14 1 + Current sample, line, band is: 75 15 1 + Current sample, line, band is: 75 16 1 + Current sample, line, band is: 75 17 1 + Current sample, line, band is: 75 18 1 + Current sample, line, band is: 75 19 1 + Current sample, line, band is: 75 20 1 + Current sample, line, band is: 75 21 1 + Current sample, line, band is: 75 22 1 + Current sample, line, band is: 75 23 1 + Current sample, line, band is: 75 24 1 + Current sample, line, band is: 75 25 1 + Current sample, line, band is: 75 26 1 + Current sample, line, band is: 75 27 1 + Current sample, line, band is: 75 28 1 + Current sample, line, band is: 75 29 1 + Current sample, line, band is: 75 30 1 + Current sample, line, band is: 75 31 1 + Current sample, line, band is: 75 32 1 + Current sample, line, band is: 75 33 1 + Current sample, line, band is: 75 34 1 + Current sample, line, band is: 75 35 1 + Current sample, line, band is: 75 36 1 + Current sample, line, band is: 75 37 1 + Current sample, line, band is: 75 38 1 + Current sample, line, band is: 75 39 1 + Current sample, line, band is: 75 40 1 + Current sample, line, band is: 75 41 1 + Current sample, line, band is: 75 42 1 + Current sample, line, band is: 75 43 1 + Current sample, line, band is: 75 44 1 + Current sample, line, band is: 75 45 1 + Current sample, line, band is: 75 46 1 + Current sample, line, band is: 75 47 1 + Current sample, line, band is: 75 48 1 + Current sample, line, band is: 75 49 1 + Current sample, line, band is: 75 50 1 + Current sample, line, band is: 75 51 1 + Current sample, line, band is: 75 52 1 + Current sample, line, band is: 75 53 1 + Current sample, line, band is: 75 54 1 + Current sample, line, band is: 75 55 1 + Current sample, line, band is: 75 56 1 + Current sample, line, band is: 75 57 1 + Current sample, line, band is: 75 58 1 + Current sample, line, band is: 75 59 1 + Current sample, line, band is: 75 60 1 + Current sample, line, band is: 75 61 1 + Current sample, line, band is: 75 62 1 + Current sample, line, band is: 75 63 1 + Current sample, line, band is: 75 64 1 + Current sample, line, band is: 75 65 1 + Current sample, line, band is: 75 66 1 + Current sample, line, band is: 75 67 1 + Current sample, line, band is: 75 68 1 + Current sample, line, band is: 75 69 1 + Current sample, line, band is: 75 70 1 + Current sample, line, band is: 75 71 1 + Current sample, line, band is: 75 72 1 + Current sample, line, band is: 75 73 1 + Current sample, line, band is: 75 74 1 + Current sample, line, band is: 75 75 1 + Current sample, line, band is: 75 76 1 + Current sample, line, band is: 75 77 1 + Current sample, line, band is: 75 78 1 + Current sample, line, band is: 75 79 1 + Current sample, line, band is: 75 80 1 + Current sample, line, band is: 75 81 1 + Current sample, line, band is: 75 82 1 + Current sample, line, band is: 75 83 1 + Current sample, line, band is: 75 84 1 + Current sample, line, band is: 75 85 1 + Current sample, line, band is: 75 86 1 + Current sample, line, band is: 75 87 1 + Current sample, line, band is: 75 88 1 + Current sample, line, band is: 75 89 1 + Current sample, line, band is: 75 90 1 + Current sample, line, band is: 75 91 1 + Current sample, line, band is: 75 92 1 + Current sample, line, band is: 75 93 1 + Current sample, line, band is: 75 94 1 + Current sample, line, band is: 75 95 1 + Current sample, line, band is: 75 96 1 + Current sample, line, band is: 75 97 1 + Current sample, line, band is: 75 98 1 + Current sample, line, band is: 75 99 1 + Current sample, line, band is: 75 100 1 + Current sample, line, band is: 75 101 1 + Current sample, line, band is: 75 102 1 + Current sample, line, band is: 75 103 1 + Current sample, line, band is: 75 104 1 + Current sample, line, band is: 75 105 1 + Current sample, line, band is: 75 106 1 + Current sample, line, band is: 75 107 1 + Current sample, line, band is: 75 108 1 + Current sample, line, band is: 75 109 1 + Current sample, line, band is: 75 110 1 + Current sample, line, band is: 75 111 1 + Current sample, line, band is: 75 112 1 + Current sample, line, band is: 75 113 1 + Current sample, line, band is: 75 114 1 + Current sample, line, band is: 75 115 1 + Current sample, line, band is: 75 116 1 + Current sample, line, band is: 75 117 1 + Current sample, line, band is: 75 118 1 + Current sample, line, band is: 75 119 1 + Current sample, line, band is: 75 120 1 + Current sample, line, band is: 75 121 1 + Current sample, line, band is: 75 122 1 + Current sample, line, band is: 75 123 1 + Current sample, line, band is: 75 124 1 + Current sample, line, band is: 75 125 1 + Current sample, line, band is: 75 126 1 + Current sample, line, band is: 76 1 1 + Current sample, line, band is: 76 2 1 + Current sample, line, band is: 76 3 1 + Current sample, line, band is: 76 4 1 + Current sample, line, band is: 76 5 1 + Current sample, line, band is: 76 6 1 + Current sample, line, band is: 76 7 1 + Current sample, line, band is: 76 8 1 + Current sample, line, band is: 76 9 1 + Current sample, line, band is: 76 10 1 + Current sample, line, band is: 76 11 1 + Current sample, line, band is: 76 12 1 + Current sample, line, band is: 76 13 1 + Current sample, line, band is: 76 14 1 + Current sample, line, band is: 76 15 1 + Current sample, line, band is: 76 16 1 + Current sample, line, band is: 76 17 1 + Current sample, line, band is: 76 18 1 + Current sample, line, band is: 76 19 1 + Current sample, line, band is: 76 20 1 + Current sample, line, band is: 76 21 1 + Current sample, line, band is: 76 22 1 + Current sample, line, band is: 76 23 1 + Current sample, line, band is: 76 24 1 + Current sample, line, band is: 76 25 1 + Current sample, line, band is: 76 26 1 + Current sample, line, band is: 76 27 1 + Current sample, line, band is: 76 28 1 + Current sample, line, band is: 76 29 1 + Current sample, line, band is: 76 30 1 + Current sample, line, band is: 76 31 1 + Current sample, line, band is: 76 32 1 + Current sample, line, band is: 76 33 1 + Current sample, line, band is: 76 34 1 + Current sample, line, band is: 76 35 1 + Current sample, line, band is: 76 36 1 + Current sample, line, band is: 76 37 1 + Current sample, line, band is: 76 38 1 + Current sample, line, band is: 76 39 1 + Current sample, line, band is: 76 40 1 + Current sample, line, band is: 76 41 1 + Current sample, line, band is: 76 42 1 + Current sample, line, band is: 76 43 1 + Current sample, line, band is: 76 44 1 + Current sample, line, band is: 76 45 1 + Current sample, line, band is: 76 46 1 + Current sample, line, band is: 76 47 1 + Current sample, line, band is: 76 48 1 + Current sample, line, band is: 76 49 1 + Current sample, line, band is: 76 50 1 + Current sample, line, band is: 76 51 1 + Current sample, line, band is: 76 52 1 + Current sample, line, band is: 76 53 1 + Current sample, line, band is: 76 54 1 + Current sample, line, band is: 76 55 1 + Current sample, line, band is: 76 56 1 + Current sample, line, band is: 76 57 1 + Current sample, line, band is: 76 58 1 + Current sample, line, band is: 76 59 1 + Current sample, line, band is: 76 60 1 + Current sample, line, band is: 76 61 1 + Current sample, line, band is: 76 62 1 + Current sample, line, band is: 76 63 1 + Current sample, line, band is: 76 64 1 + Current sample, line, band is: 76 65 1 + Current sample, line, band is: 76 66 1 + Current sample, line, band is: 76 67 1 + Current sample, line, band is: 76 68 1 + Current sample, line, band is: 76 69 1 + Current sample, line, band is: 76 70 1 + Current sample, line, band is: 76 71 1 + Current sample, line, band is: 76 72 1 + Current sample, line, band is: 76 73 1 + Current sample, line, band is: 76 74 1 + Current sample, line, band is: 76 75 1 + Current sample, line, band is: 76 76 1 + Current sample, line, band is: 76 77 1 + Current sample, line, band is: 76 78 1 + Current sample, line, band is: 76 79 1 + Current sample, line, band is: 76 80 1 + Current sample, line, band is: 76 81 1 + Current sample, line, band is: 76 82 1 + Current sample, line, band is: 76 83 1 + Current sample, line, band is: 76 84 1 + Current sample, line, band is: 76 85 1 + Current sample, line, band is: 76 86 1 + Current sample, line, band is: 76 87 1 + Current sample, line, band is: 76 88 1 + Current sample, line, band is: 76 89 1 + Current sample, line, band is: 76 90 1 + Current sample, line, band is: 76 91 1 + Current sample, line, band is: 76 92 1 + Current sample, line, band is: 76 93 1 + Current sample, line, band is: 76 94 1 + Current sample, line, band is: 76 95 1 + Current sample, line, band is: 76 96 1 + Current sample, line, band is: 76 97 1 + Current sample, line, band is: 76 98 1 + Current sample, line, band is: 76 99 1 + Current sample, line, band is: 76 100 1 + Current sample, line, band is: 76 101 1 + Current sample, line, band is: 76 102 1 + Current sample, line, band is: 76 103 1 + Current sample, line, band is: 76 104 1 + Current sample, line, band is: 76 105 1 + Current sample, line, band is: 76 106 1 + Current sample, line, band is: 76 107 1 + Current sample, line, band is: 76 108 1 + Current sample, line, band is: 76 109 1 + Current sample, line, band is: 76 110 1 + Current sample, line, band is: 76 111 1 + Current sample, line, band is: 76 112 1 + Current sample, line, band is: 76 113 1 + Current sample, line, band is: 76 114 1 + Current sample, line, band is: 76 115 1 + Current sample, line, band is: 76 116 1 + Current sample, line, band is: 76 117 1 + Current sample, line, band is: 76 118 1 + Current sample, line, band is: 76 119 1 + Current sample, line, band is: 76 120 1 + Current sample, line, band is: 76 121 1 + Current sample, line, band is: 76 122 1 + Current sample, line, band is: 76 123 1 + Current sample, line, band is: 76 124 1 + Current sample, line, band is: 76 125 1 + Current sample, line, band is: 76 126 1 + Current sample, line, band is: 77 1 1 + Current sample, line, band is: 77 2 1 + Current sample, line, band is: 77 3 1 + Current sample, line, band is: 77 4 1 + Current sample, line, band is: 77 5 1 + Current sample, line, band is: 77 6 1 + Current sample, line, band is: 77 7 1 + Current sample, line, band is: 77 8 1 + Current sample, line, band is: 77 9 1 + Current sample, line, band is: 77 10 1 + Current sample, line, band is: 77 11 1 + Current sample, line, band is: 77 12 1 + Current sample, line, band is: 77 13 1 + Current sample, line, band is: 77 14 1 + Current sample, line, band is: 77 15 1 + Current sample, line, band is: 77 16 1 + Current sample, line, band is: 77 17 1 + Current sample, line, band is: 77 18 1 + Current sample, line, band is: 77 19 1 + Current sample, line, band is: 77 20 1 + Current sample, line, band is: 77 21 1 + Current sample, line, band is: 77 22 1 + Current sample, line, band is: 77 23 1 + Current sample, line, band is: 77 24 1 + Current sample, line, band is: 77 25 1 + Current sample, line, band is: 77 26 1 + Current sample, line, band is: 77 27 1 + Current sample, line, band is: 77 28 1 + Current sample, line, band is: 77 29 1 + Current sample, line, band is: 77 30 1 + Current sample, line, band is: 77 31 1 + Current sample, line, band is: 77 32 1 + Current sample, line, band is: 77 33 1 + Current sample, line, band is: 77 34 1 + Current sample, line, band is: 77 35 1 + Current sample, line, band is: 77 36 1 + Current sample, line, band is: 77 37 1 + Current sample, line, band is: 77 38 1 + Current sample, line, band is: 77 39 1 + Current sample, line, band is: 77 40 1 + Current sample, line, band is: 77 41 1 + Current sample, line, band is: 77 42 1 + Current sample, line, band is: 77 43 1 + Current sample, line, band is: 77 44 1 + Current sample, line, band is: 77 45 1 + Current sample, line, band is: 77 46 1 + Current sample, line, band is: 77 47 1 + Current sample, line, band is: 77 48 1 + Current sample, line, band is: 77 49 1 + Current sample, line, band is: 77 50 1 + Current sample, line, band is: 77 51 1 + Current sample, line, band is: 77 52 1 + Current sample, line, band is: 77 53 1 + Current sample, line, band is: 77 54 1 + Current sample, line, band is: 77 55 1 + Current sample, line, band is: 77 56 1 + Current sample, line, band is: 77 57 1 + Current sample, line, band is: 77 58 1 + Current sample, line, band is: 77 59 1 + Current sample, line, band is: 77 60 1 + Current sample, line, band is: 77 61 1 + Current sample, line, band is: 77 62 1 + Current sample, line, band is: 77 63 1 + Current sample, line, band is: 77 64 1 + Current sample, line, band is: 77 65 1 + Current sample, line, band is: 77 66 1 + Current sample, line, band is: 77 67 1 + Current sample, line, band is: 77 68 1 + Current sample, line, band is: 77 69 1 + Current sample, line, band is: 77 70 1 + Current sample, line, band is: 77 71 1 + Current sample, line, band is: 77 72 1 + Current sample, line, band is: 77 73 1 + Current sample, line, band is: 77 74 1 + Current sample, line, band is: 77 75 1 + Current sample, line, band is: 77 76 1 + Current sample, line, band is: 77 77 1 + Current sample, line, band is: 77 78 1 + Current sample, line, band is: 77 79 1 + Current sample, line, band is: 77 80 1 + Current sample, line, band is: 77 81 1 + Current sample, line, band is: 77 82 1 + Current sample, line, band is: 77 83 1 + Current sample, line, band is: 77 84 1 + Current sample, line, band is: 77 85 1 + Current sample, line, band is: 77 86 1 + Current sample, line, band is: 77 87 1 + Current sample, line, band is: 77 88 1 + Current sample, line, band is: 77 89 1 + Current sample, line, band is: 77 90 1 + Current sample, line, band is: 77 91 1 + Current sample, line, band is: 77 92 1 + Current sample, line, band is: 77 93 1 + Current sample, line, band is: 77 94 1 + Current sample, line, band is: 77 95 1 + Current sample, line, band is: 77 96 1 + Current sample, line, band is: 77 97 1 + Current sample, line, band is: 77 98 1 + Current sample, line, band is: 77 99 1 + Current sample, line, band is: 77 100 1 + Current sample, line, band is: 77 101 1 + Current sample, line, band is: 77 102 1 + Current sample, line, band is: 77 103 1 + Current sample, line, band is: 77 104 1 + Current sample, line, band is: 77 105 1 + Current sample, line, band is: 77 106 1 + Current sample, line, band is: 77 107 1 + Current sample, line, band is: 77 108 1 + Current sample, line, band is: 77 109 1 + Current sample, line, band is: 77 110 1 + Current sample, line, band is: 77 111 1 + Current sample, line, band is: 77 112 1 + Current sample, line, band is: 77 113 1 + Current sample, line, band is: 77 114 1 + Current sample, line, band is: 77 115 1 + Current sample, line, band is: 77 116 1 + Current sample, line, band is: 77 117 1 + Current sample, line, band is: 77 118 1 + Current sample, line, band is: 77 119 1 + Current sample, line, band is: 77 120 1 + Current sample, line, band is: 77 121 1 + Current sample, line, band is: 77 122 1 + Current sample, line, band is: 77 123 1 + Current sample, line, band is: 77 124 1 + Current sample, line, band is: 77 125 1 + Current sample, line, band is: 77 126 1 + Current sample, line, band is: 78 1 1 + Current sample, line, band is: 78 2 1 + Current sample, line, band is: 78 3 1 + Current sample, line, band is: 78 4 1 + Current sample, line, band is: 78 5 1 + Current sample, line, band is: 78 6 1 + Current sample, line, band is: 78 7 1 + Current sample, line, band is: 78 8 1 + Current sample, line, band is: 78 9 1 + Current sample, line, band is: 78 10 1 + Current sample, line, band is: 78 11 1 + Current sample, line, band is: 78 12 1 + Current sample, line, band is: 78 13 1 + Current sample, line, band is: 78 14 1 + Current sample, line, band is: 78 15 1 + Current sample, line, band is: 78 16 1 + Current sample, line, band is: 78 17 1 + Current sample, line, band is: 78 18 1 + Current sample, line, band is: 78 19 1 + Current sample, line, band is: 78 20 1 + Current sample, line, band is: 78 21 1 + Current sample, line, band is: 78 22 1 + Current sample, line, band is: 78 23 1 + Current sample, line, band is: 78 24 1 + Current sample, line, band is: 78 25 1 + Current sample, line, band is: 78 26 1 + Current sample, line, band is: 78 27 1 + Current sample, line, band is: 78 28 1 + Current sample, line, band is: 78 29 1 + Current sample, line, band is: 78 30 1 + Current sample, line, band is: 78 31 1 + Current sample, line, band is: 78 32 1 + Current sample, line, band is: 78 33 1 + Current sample, line, band is: 78 34 1 + Current sample, line, band is: 78 35 1 + Current sample, line, band is: 78 36 1 + Current sample, line, band is: 78 37 1 + Current sample, line, band is: 78 38 1 + Current sample, line, band is: 78 39 1 + Current sample, line, band is: 78 40 1 + Current sample, line, band is: 78 41 1 + Current sample, line, band is: 78 42 1 + Current sample, line, band is: 78 43 1 + Current sample, line, band is: 78 44 1 + Current sample, line, band is: 78 45 1 + Current sample, line, band is: 78 46 1 + Current sample, line, band is: 78 47 1 + Current sample, line, band is: 78 48 1 + Current sample, line, band is: 78 49 1 + Current sample, line, band is: 78 50 1 + Current sample, line, band is: 78 51 1 + Current sample, line, band is: 78 52 1 + Current sample, line, band is: 78 53 1 + Current sample, line, band is: 78 54 1 + Current sample, line, band is: 78 55 1 + Current sample, line, band is: 78 56 1 + Current sample, line, band is: 78 57 1 + Current sample, line, band is: 78 58 1 + Current sample, line, band is: 78 59 1 + Current sample, line, band is: 78 60 1 + Current sample, line, band is: 78 61 1 + Current sample, line, band is: 78 62 1 + Current sample, line, band is: 78 63 1 + Current sample, line, band is: 78 64 1 + Current sample, line, band is: 78 65 1 + Current sample, line, band is: 78 66 1 + Current sample, line, band is: 78 67 1 + Current sample, line, band is: 78 68 1 + Current sample, line, band is: 78 69 1 + Current sample, line, band is: 78 70 1 + Current sample, line, band is: 78 71 1 + Current sample, line, band is: 78 72 1 + Current sample, line, band is: 78 73 1 + Current sample, line, band is: 78 74 1 + Current sample, line, band is: 78 75 1 + Current sample, line, band is: 78 76 1 + Current sample, line, band is: 78 77 1 + Current sample, line, band is: 78 78 1 + Current sample, line, band is: 78 79 1 + Current sample, line, band is: 78 80 1 + Current sample, line, band is: 78 81 1 + Current sample, line, band is: 78 82 1 + Current sample, line, band is: 78 83 1 + Current sample, line, band is: 78 84 1 + Current sample, line, band is: 78 85 1 + Current sample, line, band is: 78 86 1 + Current sample, line, band is: 78 87 1 + Current sample, line, band is: 78 88 1 + Current sample, line, band is: 78 89 1 + Current sample, line, band is: 78 90 1 + Current sample, line, band is: 78 91 1 + Current sample, line, band is: 78 92 1 + Current sample, line, band is: 78 93 1 + Current sample, line, band is: 78 94 1 + Current sample, line, band is: 78 95 1 + Current sample, line, band is: 78 96 1 + Current sample, line, band is: 78 97 1 + Current sample, line, band is: 78 98 1 + Current sample, line, band is: 78 99 1 + Current sample, line, band is: 78 100 1 + Current sample, line, band is: 78 101 1 + Current sample, line, band is: 78 102 1 + Current sample, line, band is: 78 103 1 + Current sample, line, band is: 78 104 1 + Current sample, line, band is: 78 105 1 + Current sample, line, band is: 78 106 1 + Current sample, line, band is: 78 107 1 + Current sample, line, band is: 78 108 1 + Current sample, line, band is: 78 109 1 + Current sample, line, band is: 78 110 1 + Current sample, line, band is: 78 111 1 + Current sample, line, band is: 78 112 1 + Current sample, line, band is: 78 113 1 + Current sample, line, band is: 78 114 1 + Current sample, line, band is: 78 115 1 + Current sample, line, band is: 78 116 1 + Current sample, line, band is: 78 117 1 + Current sample, line, band is: 78 118 1 + Current sample, line, band is: 78 119 1 + Current sample, line, band is: 78 120 1 + Current sample, line, band is: 78 121 1 + Current sample, line, band is: 78 122 1 + Current sample, line, band is: 78 123 1 + Current sample, line, band is: 78 124 1 + Current sample, line, band is: 78 125 1 + Current sample, line, band is: 78 126 1 + Current sample, line, band is: 79 1 1 + Current sample, line, band is: 79 2 1 + Current sample, line, band is: 79 3 1 + Current sample, line, band is: 79 4 1 + Current sample, line, band is: 79 5 1 + Current sample, line, band is: 79 6 1 + Current sample, line, band is: 79 7 1 + Current sample, line, band is: 79 8 1 + Current sample, line, band is: 79 9 1 + Current sample, line, band is: 79 10 1 + Current sample, line, band is: 79 11 1 + Current sample, line, band is: 79 12 1 + Current sample, line, band is: 79 13 1 + Current sample, line, band is: 79 14 1 + Current sample, line, band is: 79 15 1 + Current sample, line, band is: 79 16 1 + Current sample, line, band is: 79 17 1 + Current sample, line, band is: 79 18 1 + Current sample, line, band is: 79 19 1 + Current sample, line, band is: 79 20 1 + Current sample, line, band is: 79 21 1 + Current sample, line, band is: 79 22 1 + Current sample, line, band is: 79 23 1 + Current sample, line, band is: 79 24 1 + Current sample, line, band is: 79 25 1 + Current sample, line, band is: 79 26 1 + Current sample, line, band is: 79 27 1 + Current sample, line, band is: 79 28 1 + Current sample, line, band is: 79 29 1 + Current sample, line, band is: 79 30 1 + Current sample, line, band is: 79 31 1 + Current sample, line, band is: 79 32 1 + Current sample, line, band is: 79 33 1 + Current sample, line, band is: 79 34 1 + Current sample, line, band is: 79 35 1 + Current sample, line, band is: 79 36 1 + Current sample, line, band is: 79 37 1 + Current sample, line, band is: 79 38 1 + Current sample, line, band is: 79 39 1 + Current sample, line, band is: 79 40 1 + Current sample, line, band is: 79 41 1 + Current sample, line, band is: 79 42 1 + Current sample, line, band is: 79 43 1 + Current sample, line, band is: 79 44 1 + Current sample, line, band is: 79 45 1 + Current sample, line, band is: 79 46 1 + Current sample, line, band is: 79 47 1 + Current sample, line, band is: 79 48 1 + Current sample, line, band is: 79 49 1 + Current sample, line, band is: 79 50 1 + Current sample, line, band is: 79 51 1 + Current sample, line, band is: 79 52 1 + Current sample, line, band is: 79 53 1 + Current sample, line, band is: 79 54 1 + Current sample, line, band is: 79 55 1 + Current sample, line, band is: 79 56 1 + Current sample, line, band is: 79 57 1 + Current sample, line, band is: 79 58 1 + Current sample, line, band is: 79 59 1 + Current sample, line, band is: 79 60 1 + Current sample, line, band is: 79 61 1 + Current sample, line, band is: 79 62 1 + Current sample, line, band is: 79 63 1 + Current sample, line, band is: 79 64 1 + Current sample, line, band is: 79 65 1 + Current sample, line, band is: 79 66 1 + Current sample, line, band is: 79 67 1 + Current sample, line, band is: 79 68 1 + Current sample, line, band is: 79 69 1 + Current sample, line, band is: 79 70 1 + Current sample, line, band is: 79 71 1 + Current sample, line, band is: 79 72 1 + Current sample, line, band is: 79 73 1 + Current sample, line, band is: 79 74 1 + Current sample, line, band is: 79 75 1 + Current sample, line, band is: 79 76 1 + Current sample, line, band is: 79 77 1 + Current sample, line, band is: 79 78 1 + Current sample, line, band is: 79 79 1 + Current sample, line, band is: 79 80 1 + Current sample, line, band is: 79 81 1 + Current sample, line, band is: 79 82 1 + Current sample, line, band is: 79 83 1 + Current sample, line, band is: 79 84 1 + Current sample, line, band is: 79 85 1 + Current sample, line, band is: 79 86 1 + Current sample, line, band is: 79 87 1 + Current sample, line, band is: 79 88 1 + Current sample, line, band is: 79 89 1 + Current sample, line, band is: 79 90 1 + Current sample, line, band is: 79 91 1 + Current sample, line, band is: 79 92 1 + Current sample, line, band is: 79 93 1 + Current sample, line, band is: 79 94 1 + Current sample, line, band is: 79 95 1 + Current sample, line, band is: 79 96 1 + Current sample, line, band is: 79 97 1 + Current sample, line, band is: 79 98 1 + Current sample, line, band is: 79 99 1 + Current sample, line, band is: 79 100 1 + Current sample, line, band is: 79 101 1 + Current sample, line, band is: 79 102 1 + Current sample, line, band is: 79 103 1 + Current sample, line, band is: 79 104 1 + Current sample, line, band is: 79 105 1 + Current sample, line, band is: 79 106 1 + Current sample, line, band is: 79 107 1 + Current sample, line, band is: 79 108 1 + Current sample, line, band is: 79 109 1 + Current sample, line, band is: 79 110 1 + Current sample, line, band is: 79 111 1 + Current sample, line, band is: 79 112 1 + Current sample, line, band is: 79 113 1 + Current sample, line, band is: 79 114 1 + Current sample, line, band is: 79 115 1 + Current sample, line, band is: 79 116 1 + Current sample, line, band is: 79 117 1 + Current sample, line, band is: 79 118 1 + Current sample, line, band is: 79 119 1 + Current sample, line, band is: 79 120 1 + Current sample, line, band is: 79 121 1 + Current sample, line, band is: 79 122 1 + Current sample, line, band is: 79 123 1 + Current sample, line, band is: 79 124 1 + Current sample, line, band is: 79 125 1 + Current sample, line, band is: 79 126 1 + Current sample, line, band is: 80 1 1 + Current sample, line, band is: 80 2 1 + Current sample, line, band is: 80 3 1 + Current sample, line, band is: 80 4 1 + Current sample, line, band is: 80 5 1 + Current sample, line, band is: 80 6 1 + Current sample, line, band is: 80 7 1 + Current sample, line, band is: 80 8 1 + Current sample, line, band is: 80 9 1 + Current sample, line, band is: 80 10 1 + Current sample, line, band is: 80 11 1 + Current sample, line, band is: 80 12 1 + Current sample, line, band is: 80 13 1 + Current sample, line, band is: 80 14 1 + Current sample, line, band is: 80 15 1 + Current sample, line, band is: 80 16 1 + Current sample, line, band is: 80 17 1 + Current sample, line, band is: 80 18 1 + Current sample, line, band is: 80 19 1 + Current sample, line, band is: 80 20 1 + Current sample, line, band is: 80 21 1 + Current sample, line, band is: 80 22 1 + Current sample, line, band is: 80 23 1 + Current sample, line, band is: 80 24 1 + Current sample, line, band is: 80 25 1 + Current sample, line, band is: 80 26 1 + Current sample, line, band is: 80 27 1 + Current sample, line, band is: 80 28 1 + Current sample, line, band is: 80 29 1 + Current sample, line, band is: 80 30 1 + Current sample, line, band is: 80 31 1 + Current sample, line, band is: 80 32 1 + Current sample, line, band is: 80 33 1 + Current sample, line, band is: 80 34 1 + Current sample, line, band is: 80 35 1 + Current sample, line, band is: 80 36 1 + Current sample, line, band is: 80 37 1 + Current sample, line, band is: 80 38 1 + Current sample, line, band is: 80 39 1 + Current sample, line, band is: 80 40 1 + Current sample, line, band is: 80 41 1 + Current sample, line, band is: 80 42 1 + Current sample, line, band is: 80 43 1 + Current sample, line, band is: 80 44 1 + Current sample, line, band is: 80 45 1 + Current sample, line, band is: 80 46 1 + Current sample, line, band is: 80 47 1 + Current sample, line, band is: 80 48 1 + Current sample, line, band is: 80 49 1 + Current sample, line, band is: 80 50 1 + Current sample, line, band is: 80 51 1 + Current sample, line, band is: 80 52 1 + Current sample, line, band is: 80 53 1 + Current sample, line, band is: 80 54 1 + Current sample, line, band is: 80 55 1 + Current sample, line, band is: 80 56 1 + Current sample, line, band is: 80 57 1 + Current sample, line, band is: 80 58 1 + Current sample, line, band is: 80 59 1 + Current sample, line, band is: 80 60 1 + Current sample, line, band is: 80 61 1 + Current sample, line, band is: 80 62 1 + Current sample, line, band is: 80 63 1 + Current sample, line, band is: 80 64 1 + Current sample, line, band is: 80 65 1 + Current sample, line, band is: 80 66 1 + Current sample, line, band is: 80 67 1 + Current sample, line, band is: 80 68 1 + Current sample, line, band is: 80 69 1 + Current sample, line, band is: 80 70 1 + Current sample, line, band is: 80 71 1 + Current sample, line, band is: 80 72 1 + Current sample, line, band is: 80 73 1 + Current sample, line, band is: 80 74 1 + Current sample, line, band is: 80 75 1 + Current sample, line, band is: 80 76 1 + Current sample, line, band is: 80 77 1 + Current sample, line, band is: 80 78 1 + Current sample, line, band is: 80 79 1 + Current sample, line, band is: 80 80 1 + Current sample, line, band is: 80 81 1 + Current sample, line, band is: 80 82 1 + Current sample, line, band is: 80 83 1 + Current sample, line, band is: 80 84 1 + Current sample, line, band is: 80 85 1 + Current sample, line, band is: 80 86 1 + Current sample, line, band is: 80 87 1 + Current sample, line, band is: 80 88 1 + Current sample, line, band is: 80 89 1 + Current sample, line, band is: 80 90 1 + Current sample, line, band is: 80 91 1 + Current sample, line, band is: 80 92 1 + Current sample, line, band is: 80 93 1 + Current sample, line, band is: 80 94 1 + Current sample, line, band is: 80 95 1 + Current sample, line, band is: 80 96 1 + Current sample, line, band is: 80 97 1 + Current sample, line, band is: 80 98 1 + Current sample, line, band is: 80 99 1 + Current sample, line, band is: 80 100 1 + Current sample, line, band is: 80 101 1 + Current sample, line, band is: 80 102 1 + Current sample, line, band is: 80 103 1 + Current sample, line, band is: 80 104 1 + Current sample, line, band is: 80 105 1 + Current sample, line, band is: 80 106 1 + Current sample, line, band is: 80 107 1 + Current sample, line, band is: 80 108 1 + Current sample, line, band is: 80 109 1 + Current sample, line, band is: 80 110 1 + Current sample, line, band is: 80 111 1 + Current sample, line, band is: 80 112 1 + Current sample, line, band is: 80 113 1 + Current sample, line, band is: 80 114 1 + Current sample, line, band is: 80 115 1 + Current sample, line, band is: 80 116 1 + Current sample, line, band is: 80 117 1 + Current sample, line, band is: 80 118 1 + Current sample, line, band is: 80 119 1 + Current sample, line, band is: 80 120 1 + Current sample, line, band is: 80 121 1 + Current sample, line, band is: 80 122 1 + Current sample, line, band is: 80 123 1 + Current sample, line, band is: 80 124 1 + Current sample, line, band is: 80 125 1 + Current sample, line, band is: 80 126 1 + Current sample, line, band is: 81 1 1 + Current sample, line, band is: 81 2 1 + Current sample, line, band is: 81 3 1 + Current sample, line, band is: 81 4 1 + Current sample, line, band is: 81 5 1 + Current sample, line, band is: 81 6 1 + Current sample, line, band is: 81 7 1 + Current sample, line, band is: 81 8 1 + Current sample, line, band is: 81 9 1 + Current sample, line, band is: 81 10 1 + Current sample, line, band is: 81 11 1 + Current sample, line, band is: 81 12 1 + Current sample, line, band is: 81 13 1 + Current sample, line, band is: 81 14 1 + Current sample, line, band is: 81 15 1 + Current sample, line, band is: 81 16 1 + Current sample, line, band is: 81 17 1 + Current sample, line, band is: 81 18 1 + Current sample, line, band is: 81 19 1 + Current sample, line, band is: 81 20 1 + Current sample, line, band is: 81 21 1 + Current sample, line, band is: 81 22 1 + Current sample, line, band is: 81 23 1 + Current sample, line, band is: 81 24 1 + Current sample, line, band is: 81 25 1 + Current sample, line, band is: 81 26 1 + Current sample, line, band is: 81 27 1 + Current sample, line, band is: 81 28 1 + Current sample, line, band is: 81 29 1 + Current sample, line, band is: 81 30 1 + Current sample, line, band is: 81 31 1 + Current sample, line, band is: 81 32 1 + Current sample, line, band is: 81 33 1 + Current sample, line, band is: 81 34 1 + Current sample, line, band is: 81 35 1 + Current sample, line, band is: 81 36 1 + Current sample, line, band is: 81 37 1 + Current sample, line, band is: 81 38 1 + Current sample, line, band is: 81 39 1 + Current sample, line, band is: 81 40 1 + Current sample, line, band is: 81 41 1 + Current sample, line, band is: 81 42 1 + Current sample, line, band is: 81 43 1 + Current sample, line, band is: 81 44 1 + Current sample, line, band is: 81 45 1 + Current sample, line, band is: 81 46 1 + Current sample, line, band is: 81 47 1 + Current sample, line, band is: 81 48 1 + Current sample, line, band is: 81 49 1 + Current sample, line, band is: 81 50 1 + Current sample, line, band is: 81 51 1 + Current sample, line, band is: 81 52 1 + Current sample, line, band is: 81 53 1 + Current sample, line, band is: 81 54 1 + Current sample, line, band is: 81 55 1 + Current sample, line, band is: 81 56 1 + Current sample, line, band is: 81 57 1 + Current sample, line, band is: 81 58 1 + Current sample, line, band is: 81 59 1 + Current sample, line, band is: 81 60 1 + Current sample, line, band is: 81 61 1 + Current sample, line, band is: 81 62 1 + Current sample, line, band is: 81 63 1 + Current sample, line, band is: 81 64 1 + Current sample, line, band is: 81 65 1 + Current sample, line, band is: 81 66 1 + Current sample, line, band is: 81 67 1 + Current sample, line, band is: 81 68 1 + Current sample, line, band is: 81 69 1 + Current sample, line, band is: 81 70 1 + Current sample, line, band is: 81 71 1 + Current sample, line, band is: 81 72 1 + Current sample, line, band is: 81 73 1 + Current sample, line, band is: 81 74 1 + Current sample, line, band is: 81 75 1 + Current sample, line, band is: 81 76 1 + Current sample, line, band is: 81 77 1 + Current sample, line, band is: 81 78 1 + Current sample, line, band is: 81 79 1 + Current sample, line, band is: 81 80 1 + Current sample, line, band is: 81 81 1 + Current sample, line, band is: 81 82 1 + Current sample, line, band is: 81 83 1 + Current sample, line, band is: 81 84 1 + Current sample, line, band is: 81 85 1 + Current sample, line, band is: 81 86 1 + Current sample, line, band is: 81 87 1 + Current sample, line, band is: 81 88 1 + Current sample, line, band is: 81 89 1 + Current sample, line, band is: 81 90 1 + Current sample, line, band is: 81 91 1 + Current sample, line, band is: 81 92 1 + Current sample, line, band is: 81 93 1 + Current sample, line, band is: 81 94 1 + Current sample, line, band is: 81 95 1 + Current sample, line, band is: 81 96 1 + Current sample, line, band is: 81 97 1 + Current sample, line, band is: 81 98 1 + Current sample, line, band is: 81 99 1 + Current sample, line, band is: 81 100 1 + Current sample, line, band is: 81 101 1 + Current sample, line, band is: 81 102 1 + Current sample, line, band is: 81 103 1 + Current sample, line, band is: 81 104 1 + Current sample, line, band is: 81 105 1 + Current sample, line, band is: 81 106 1 + Current sample, line, band is: 81 107 1 + Current sample, line, band is: 81 108 1 + Current sample, line, band is: 81 109 1 + Current sample, line, band is: 81 110 1 + Current sample, line, band is: 81 111 1 + Current sample, line, band is: 81 112 1 + Current sample, line, band is: 81 113 1 + Current sample, line, band is: 81 114 1 + Current sample, line, band is: 81 115 1 + Current sample, line, band is: 81 116 1 + Current sample, line, band is: 81 117 1 + Current sample, line, band is: 81 118 1 + Current sample, line, band is: 81 119 1 + Current sample, line, band is: 81 120 1 + Current sample, line, band is: 81 121 1 + Current sample, line, band is: 81 122 1 + Current sample, line, band is: 81 123 1 + Current sample, line, band is: 81 124 1 + Current sample, line, band is: 81 125 1 + Current sample, line, band is: 81 126 1 + Current sample, line, band is: 82 1 1 + Current sample, line, band is: 82 2 1 + Current sample, line, band is: 82 3 1 + Current sample, line, band is: 82 4 1 + Current sample, line, band is: 82 5 1 + Current sample, line, band is: 82 6 1 + Current sample, line, band is: 82 7 1 + Current sample, line, band is: 82 8 1 + Current sample, line, band is: 82 9 1 + Current sample, line, band is: 82 10 1 + Current sample, line, band is: 82 11 1 + Current sample, line, band is: 82 12 1 + Current sample, line, band is: 82 13 1 + Current sample, line, band is: 82 14 1 + Current sample, line, band is: 82 15 1 + Current sample, line, band is: 82 16 1 + Current sample, line, band is: 82 17 1 + Current sample, line, band is: 82 18 1 + Current sample, line, band is: 82 19 1 + Current sample, line, band is: 82 20 1 + Current sample, line, band is: 82 21 1 + Current sample, line, band is: 82 22 1 + Current sample, line, band is: 82 23 1 + Current sample, line, band is: 82 24 1 + Current sample, line, band is: 82 25 1 + Current sample, line, band is: 82 26 1 + Current sample, line, band is: 82 27 1 + Current sample, line, band is: 82 28 1 + Current sample, line, band is: 82 29 1 + Current sample, line, band is: 82 30 1 + Current sample, line, band is: 82 31 1 + Current sample, line, band is: 82 32 1 + Current sample, line, band is: 82 33 1 + Current sample, line, band is: 82 34 1 + Current sample, line, band is: 82 35 1 + Current sample, line, band is: 82 36 1 + Current sample, line, band is: 82 37 1 + Current sample, line, band is: 82 38 1 + Current sample, line, band is: 82 39 1 + Current sample, line, band is: 82 40 1 + Current sample, line, band is: 82 41 1 + Current sample, line, band is: 82 42 1 + Current sample, line, band is: 82 43 1 + Current sample, line, band is: 82 44 1 + Current sample, line, band is: 82 45 1 + Current sample, line, band is: 82 46 1 + Current sample, line, band is: 82 47 1 + Current sample, line, band is: 82 48 1 + Current sample, line, band is: 82 49 1 + Current sample, line, band is: 82 50 1 + Current sample, line, band is: 82 51 1 + Current sample, line, band is: 82 52 1 + Current sample, line, band is: 82 53 1 + Current sample, line, band is: 82 54 1 + Current sample, line, band is: 82 55 1 + Current sample, line, band is: 82 56 1 + Current sample, line, band is: 82 57 1 + Current sample, line, band is: 82 58 1 + Current sample, line, band is: 82 59 1 + Current sample, line, band is: 82 60 1 + Current sample, line, band is: 82 61 1 + Current sample, line, band is: 82 62 1 + Current sample, line, band is: 82 63 1 + Current sample, line, band is: 82 64 1 + Current sample, line, band is: 82 65 1 + Current sample, line, band is: 82 66 1 + Current sample, line, band is: 82 67 1 + Current sample, line, band is: 82 68 1 + Current sample, line, band is: 82 69 1 + Current sample, line, band is: 82 70 1 + Current sample, line, band is: 82 71 1 + Current sample, line, band is: 82 72 1 + Current sample, line, band is: 82 73 1 + Current sample, line, band is: 82 74 1 + Current sample, line, band is: 82 75 1 + Current sample, line, band is: 82 76 1 + Current sample, line, band is: 82 77 1 + Current sample, line, band is: 82 78 1 + Current sample, line, band is: 82 79 1 + Current sample, line, band is: 82 80 1 + Current sample, line, band is: 82 81 1 + Current sample, line, band is: 82 82 1 + Current sample, line, band is: 82 83 1 + Current sample, line, band is: 82 84 1 + Current sample, line, band is: 82 85 1 + Current sample, line, band is: 82 86 1 + Current sample, line, band is: 82 87 1 + Current sample, line, band is: 82 88 1 + Current sample, line, band is: 82 89 1 + Current sample, line, band is: 82 90 1 + Current sample, line, band is: 82 91 1 + Current sample, line, band is: 82 92 1 + Current sample, line, band is: 82 93 1 + Current sample, line, band is: 82 94 1 + Current sample, line, band is: 82 95 1 + Current sample, line, band is: 82 96 1 + Current sample, line, band is: 82 97 1 + Current sample, line, band is: 82 98 1 + Current sample, line, band is: 82 99 1 + Current sample, line, band is: 82 100 1 + Current sample, line, band is: 82 101 1 + Current sample, line, band is: 82 102 1 + Current sample, line, band is: 82 103 1 + Current sample, line, band is: 82 104 1 + Current sample, line, band is: 82 105 1 + Current sample, line, band is: 82 106 1 + Current sample, line, band is: 82 107 1 + Current sample, line, band is: 82 108 1 + Current sample, line, band is: 82 109 1 + Current sample, line, band is: 82 110 1 + Current sample, line, band is: 82 111 1 + Current sample, line, band is: 82 112 1 + Current sample, line, band is: 82 113 1 + Current sample, line, band is: 82 114 1 + Current sample, line, band is: 82 115 1 + Current sample, line, band is: 82 116 1 + Current sample, line, band is: 82 117 1 + Current sample, line, band is: 82 118 1 + Current sample, line, band is: 82 119 1 + Current sample, line, band is: 82 120 1 + Current sample, line, band is: 82 121 1 + Current sample, line, band is: 82 122 1 + Current sample, line, band is: 82 123 1 + Current sample, line, band is: 82 124 1 + Current sample, line, band is: 82 125 1 + Current sample, line, band is: 82 126 1 + Current sample, line, band is: 83 1 1 + Current sample, line, band is: 83 2 1 + Current sample, line, band is: 83 3 1 + Current sample, line, band is: 83 4 1 + Current sample, line, band is: 83 5 1 + Current sample, line, band is: 83 6 1 + Current sample, line, band is: 83 7 1 + Current sample, line, band is: 83 8 1 + Current sample, line, band is: 83 9 1 + Current sample, line, band is: 83 10 1 + Current sample, line, band is: 83 11 1 + Current sample, line, band is: 83 12 1 + Current sample, line, band is: 83 13 1 + Current sample, line, band is: 83 14 1 + Current sample, line, band is: 83 15 1 + Current sample, line, band is: 83 16 1 + Current sample, line, band is: 83 17 1 + Current sample, line, band is: 83 18 1 + Current sample, line, band is: 83 19 1 + Current sample, line, band is: 83 20 1 + Current sample, line, band is: 83 21 1 + Current sample, line, band is: 83 22 1 + Current sample, line, band is: 83 23 1 + Current sample, line, band is: 83 24 1 + Current sample, line, band is: 83 25 1 + Current sample, line, band is: 83 26 1 + Current sample, line, band is: 83 27 1 + Current sample, line, band is: 83 28 1 + Current sample, line, band is: 83 29 1 + Current sample, line, band is: 83 30 1 + Current sample, line, band is: 83 31 1 + Current sample, line, band is: 83 32 1 + Current sample, line, band is: 83 33 1 + Current sample, line, band is: 83 34 1 + Current sample, line, band is: 83 35 1 + Current sample, line, band is: 83 36 1 + Current sample, line, band is: 83 37 1 + Current sample, line, band is: 83 38 1 + Current sample, line, band is: 83 39 1 + Current sample, line, band is: 83 40 1 + Current sample, line, band is: 83 41 1 + Current sample, line, band is: 83 42 1 + Current sample, line, band is: 83 43 1 + Current sample, line, band is: 83 44 1 + Current sample, line, band is: 83 45 1 + Current sample, line, band is: 83 46 1 + Current sample, line, band is: 83 47 1 + Current sample, line, band is: 83 48 1 + Current sample, line, band is: 83 49 1 + Current sample, line, band is: 83 50 1 + Current sample, line, band is: 83 51 1 + Current sample, line, band is: 83 52 1 + Current sample, line, band is: 83 53 1 + Current sample, line, band is: 83 54 1 + Current sample, line, band is: 83 55 1 + Current sample, line, band is: 83 56 1 + Current sample, line, band is: 83 57 1 + Current sample, line, band is: 83 58 1 + Current sample, line, band is: 83 59 1 + Current sample, line, band is: 83 60 1 + Current sample, line, band is: 83 61 1 + Current sample, line, band is: 83 62 1 + Current sample, line, band is: 83 63 1 + Current sample, line, band is: 83 64 1 + Current sample, line, band is: 83 65 1 + Current sample, line, band is: 83 66 1 + Current sample, line, band is: 83 67 1 + Current sample, line, band is: 83 68 1 + Current sample, line, band is: 83 69 1 + Current sample, line, band is: 83 70 1 + Current sample, line, band is: 83 71 1 + Current sample, line, band is: 83 72 1 + Current sample, line, band is: 83 73 1 + Current sample, line, band is: 83 74 1 + Current sample, line, band is: 83 75 1 + Current sample, line, band is: 83 76 1 + Current sample, line, band is: 83 77 1 + Current sample, line, band is: 83 78 1 + Current sample, line, band is: 83 79 1 + Current sample, line, band is: 83 80 1 + Current sample, line, band is: 83 81 1 + Current sample, line, band is: 83 82 1 + Current sample, line, band is: 83 83 1 + Current sample, line, band is: 83 84 1 + Current sample, line, band is: 83 85 1 + Current sample, line, band is: 83 86 1 + Current sample, line, band is: 83 87 1 + Current sample, line, band is: 83 88 1 + Current sample, line, band is: 83 89 1 + Current sample, line, band is: 83 90 1 + Current sample, line, band is: 83 91 1 + Current sample, line, band is: 83 92 1 + Current sample, line, band is: 83 93 1 + Current sample, line, band is: 83 94 1 + Current sample, line, band is: 83 95 1 + Current sample, line, band is: 83 96 1 + Current sample, line, band is: 83 97 1 + Current sample, line, band is: 83 98 1 + Current sample, line, band is: 83 99 1 + Current sample, line, band is: 83 100 1 + Current sample, line, band is: 83 101 1 + Current sample, line, band is: 83 102 1 + Current sample, line, band is: 83 103 1 + Current sample, line, band is: 83 104 1 + Current sample, line, band is: 83 105 1 + Current sample, line, band is: 83 106 1 + Current sample, line, band is: 83 107 1 + Current sample, line, band is: 83 108 1 + Current sample, line, band is: 83 109 1 + Current sample, line, band is: 83 110 1 + Current sample, line, band is: 83 111 1 + Current sample, line, band is: 83 112 1 + Current sample, line, band is: 83 113 1 + Current sample, line, band is: 83 114 1 + Current sample, line, band is: 83 115 1 + Current sample, line, band is: 83 116 1 + Current sample, line, band is: 83 117 1 + Current sample, line, band is: 83 118 1 + Current sample, line, band is: 83 119 1 + Current sample, line, band is: 83 120 1 + Current sample, line, band is: 83 121 1 + Current sample, line, band is: 83 122 1 + Current sample, line, band is: 83 123 1 + Current sample, line, band is: 83 124 1 + Current sample, line, band is: 83 125 1 + Current sample, line, band is: 83 126 1 + Current sample, line, band is: 84 1 1 + Current sample, line, band is: 84 2 1 + Current sample, line, band is: 84 3 1 + Current sample, line, band is: 84 4 1 + Current sample, line, band is: 84 5 1 + Current sample, line, band is: 84 6 1 + Current sample, line, band is: 84 7 1 + Current sample, line, band is: 84 8 1 + Current sample, line, band is: 84 9 1 + Current sample, line, band is: 84 10 1 + Current sample, line, band is: 84 11 1 + Current sample, line, band is: 84 12 1 + Current sample, line, band is: 84 13 1 + Current sample, line, band is: 84 14 1 + Current sample, line, band is: 84 15 1 + Current sample, line, band is: 84 16 1 + Current sample, line, band is: 84 17 1 + Current sample, line, band is: 84 18 1 + Current sample, line, band is: 84 19 1 + Current sample, line, band is: 84 20 1 + Current sample, line, band is: 84 21 1 + Current sample, line, band is: 84 22 1 + Current sample, line, band is: 84 23 1 + Current sample, line, band is: 84 24 1 + Current sample, line, band is: 84 25 1 + Current sample, line, band is: 84 26 1 + Current sample, line, band is: 84 27 1 + Current sample, line, band is: 84 28 1 + Current sample, line, band is: 84 29 1 + Current sample, line, band is: 84 30 1 + Current sample, line, band is: 84 31 1 + Current sample, line, band is: 84 32 1 + Current sample, line, band is: 84 33 1 + Current sample, line, band is: 84 34 1 + Current sample, line, band is: 84 35 1 + Current sample, line, band is: 84 36 1 + Current sample, line, band is: 84 37 1 + Current sample, line, band is: 84 38 1 + Current sample, line, band is: 84 39 1 + Current sample, line, band is: 84 40 1 + Current sample, line, band is: 84 41 1 + Current sample, line, band is: 84 42 1 + Current sample, line, band is: 84 43 1 + Current sample, line, band is: 84 44 1 + Current sample, line, band is: 84 45 1 + Current sample, line, band is: 84 46 1 + Current sample, line, band is: 84 47 1 + Current sample, line, band is: 84 48 1 + Current sample, line, band is: 84 49 1 + Current sample, line, band is: 84 50 1 + Current sample, line, band is: 84 51 1 + Current sample, line, band is: 84 52 1 + Current sample, line, band is: 84 53 1 + Current sample, line, band is: 84 54 1 + Current sample, line, band is: 84 55 1 + Current sample, line, band is: 84 56 1 + Current sample, line, band is: 84 57 1 + Current sample, line, band is: 84 58 1 + Current sample, line, band is: 84 59 1 + Current sample, line, band is: 84 60 1 + Current sample, line, band is: 84 61 1 + Current sample, line, band is: 84 62 1 + Current sample, line, band is: 84 63 1 + Current sample, line, band is: 84 64 1 + Current sample, line, band is: 84 65 1 + Current sample, line, band is: 84 66 1 + Current sample, line, band is: 84 67 1 + Current sample, line, band is: 84 68 1 + Current sample, line, band is: 84 69 1 + Current sample, line, band is: 84 70 1 + Current sample, line, band is: 84 71 1 + Current sample, line, band is: 84 72 1 + Current sample, line, band is: 84 73 1 + Current sample, line, band is: 84 74 1 + Current sample, line, band is: 84 75 1 + Current sample, line, band is: 84 76 1 + Current sample, line, band is: 84 77 1 + Current sample, line, band is: 84 78 1 + Current sample, line, band is: 84 79 1 + Current sample, line, band is: 84 80 1 + Current sample, line, band is: 84 81 1 + Current sample, line, band is: 84 82 1 + Current sample, line, band is: 84 83 1 + Current sample, line, band is: 84 84 1 + Current sample, line, band is: 84 85 1 + Current sample, line, band is: 84 86 1 + Current sample, line, band is: 84 87 1 + Current sample, line, band is: 84 88 1 + Current sample, line, band is: 84 89 1 + Current sample, line, band is: 84 90 1 + Current sample, line, band is: 84 91 1 + Current sample, line, band is: 84 92 1 + Current sample, line, band is: 84 93 1 + Current sample, line, band is: 84 94 1 + Current sample, line, band is: 84 95 1 + Current sample, line, band is: 84 96 1 + Current sample, line, band is: 84 97 1 + Current sample, line, band is: 84 98 1 + Current sample, line, band is: 84 99 1 + Current sample, line, band is: 84 100 1 + Current sample, line, band is: 84 101 1 + Current sample, line, band is: 84 102 1 + Current sample, line, band is: 84 103 1 + Current sample, line, band is: 84 104 1 + Current sample, line, band is: 84 105 1 + Current sample, line, band is: 84 106 1 + Current sample, line, band is: 84 107 1 + Current sample, line, band is: 84 108 1 + Current sample, line, band is: 84 109 1 + Current sample, line, band is: 84 110 1 + Current sample, line, band is: 84 111 1 + Current sample, line, band is: 84 112 1 + Current sample, line, band is: 84 113 1 + Current sample, line, band is: 84 114 1 + Current sample, line, band is: 84 115 1 + Current sample, line, band is: 84 116 1 + Current sample, line, band is: 84 117 1 + Current sample, line, band is: 84 118 1 + Current sample, line, band is: 84 119 1 + Current sample, line, band is: 84 120 1 + Current sample, line, band is: 84 121 1 + Current sample, line, band is: 84 122 1 + Current sample, line, band is: 84 123 1 + Current sample, line, band is: 84 124 1 + Current sample, line, band is: 84 125 1 + Current sample, line, band is: 84 126 1 + Current sample, line, band is: 85 1 1 + Current sample, line, band is: 85 2 1 + Current sample, line, band is: 85 3 1 + Current sample, line, band is: 85 4 1 + Current sample, line, band is: 85 5 1 + Current sample, line, band is: 85 6 1 + Current sample, line, band is: 85 7 1 + Current sample, line, band is: 85 8 1 + Current sample, line, band is: 85 9 1 + Current sample, line, band is: 85 10 1 + Current sample, line, band is: 85 11 1 + Current sample, line, band is: 85 12 1 + Current sample, line, band is: 85 13 1 + Current sample, line, band is: 85 14 1 + Current sample, line, band is: 85 15 1 + Current sample, line, band is: 85 16 1 + Current sample, line, band is: 85 17 1 + Current sample, line, band is: 85 18 1 + Current sample, line, band is: 85 19 1 + Current sample, line, band is: 85 20 1 + Current sample, line, band is: 85 21 1 + Current sample, line, band is: 85 22 1 + Current sample, line, band is: 85 23 1 + Current sample, line, band is: 85 24 1 + Current sample, line, band is: 85 25 1 + Current sample, line, band is: 85 26 1 + Current sample, line, band is: 85 27 1 + Current sample, line, band is: 85 28 1 + Current sample, line, band is: 85 29 1 + Current sample, line, band is: 85 30 1 + Current sample, line, band is: 85 31 1 + Current sample, line, band is: 85 32 1 + Current sample, line, band is: 85 33 1 + Current sample, line, band is: 85 34 1 + Current sample, line, band is: 85 35 1 + Current sample, line, band is: 85 36 1 + Current sample, line, band is: 85 37 1 + Current sample, line, band is: 85 38 1 + Current sample, line, band is: 85 39 1 + Current sample, line, band is: 85 40 1 + Current sample, line, band is: 85 41 1 + Current sample, line, band is: 85 42 1 + Current sample, line, band is: 85 43 1 + Current sample, line, band is: 85 44 1 + Current sample, line, band is: 85 45 1 + Current sample, line, band is: 85 46 1 + Current sample, line, band is: 85 47 1 + Current sample, line, band is: 85 48 1 + Current sample, line, band is: 85 49 1 + Current sample, line, band is: 85 50 1 + Current sample, line, band is: 85 51 1 + Current sample, line, band is: 85 52 1 + Current sample, line, band is: 85 53 1 + Current sample, line, band is: 85 54 1 + Current sample, line, band is: 85 55 1 + Current sample, line, band is: 85 56 1 + Current sample, line, band is: 85 57 1 + Current sample, line, band is: 85 58 1 + Current sample, line, band is: 85 59 1 + Current sample, line, band is: 85 60 1 + Current sample, line, band is: 85 61 1 + Current sample, line, band is: 85 62 1 + Current sample, line, band is: 85 63 1 + Current sample, line, band is: 85 64 1 + Current sample, line, band is: 85 65 1 + Current sample, line, band is: 85 66 1 + Current sample, line, band is: 85 67 1 + Current sample, line, band is: 85 68 1 + Current sample, line, band is: 85 69 1 + Current sample, line, band is: 85 70 1 + Current sample, line, band is: 85 71 1 + Current sample, line, band is: 85 72 1 + Current sample, line, band is: 85 73 1 + Current sample, line, band is: 85 74 1 + Current sample, line, band is: 85 75 1 + Current sample, line, band is: 85 76 1 + Current sample, line, band is: 85 77 1 + Current sample, line, band is: 85 78 1 + Current sample, line, band is: 85 79 1 + Current sample, line, band is: 85 80 1 + Current sample, line, band is: 85 81 1 + Current sample, line, band is: 85 82 1 + Current sample, line, band is: 85 83 1 + Current sample, line, band is: 85 84 1 + Current sample, line, band is: 85 85 1 + Current sample, line, band is: 85 86 1 + Current sample, line, band is: 85 87 1 + Current sample, line, band is: 85 88 1 + Current sample, line, band is: 85 89 1 + Current sample, line, band is: 85 90 1 + Current sample, line, band is: 85 91 1 + Current sample, line, band is: 85 92 1 + Current sample, line, band is: 85 93 1 + Current sample, line, band is: 85 94 1 + Current sample, line, band is: 85 95 1 + Current sample, line, band is: 85 96 1 + Current sample, line, band is: 85 97 1 + Current sample, line, band is: 85 98 1 + Current sample, line, band is: 85 99 1 + Current sample, line, band is: 85 100 1 + Current sample, line, band is: 85 101 1 + Current sample, line, band is: 85 102 1 + Current sample, line, band is: 85 103 1 + Current sample, line, band is: 85 104 1 + Current sample, line, band is: 85 105 1 + Current sample, line, band is: 85 106 1 + Current sample, line, band is: 85 107 1 + Current sample, line, band is: 85 108 1 + Current sample, line, band is: 85 109 1 + Current sample, line, band is: 85 110 1 + Current sample, line, band is: 85 111 1 + Current sample, line, band is: 85 112 1 + Current sample, line, band is: 85 113 1 + Current sample, line, band is: 85 114 1 + Current sample, line, band is: 85 115 1 + Current sample, line, band is: 85 116 1 + Current sample, line, band is: 85 117 1 + Current sample, line, band is: 85 118 1 + Current sample, line, band is: 85 119 1 + Current sample, line, band is: 85 120 1 + Current sample, line, band is: 85 121 1 + Current sample, line, band is: 85 122 1 + Current sample, line, band is: 85 123 1 + Current sample, line, band is: 85 124 1 + Current sample, line, band is: 85 125 1 + Current sample, line, band is: 85 126 1 + Current sample, line, band is: 86 1 1 + Current sample, line, band is: 86 2 1 + Current sample, line, band is: 86 3 1 + Current sample, line, band is: 86 4 1 + Current sample, line, band is: 86 5 1 + Current sample, line, band is: 86 6 1 + Current sample, line, band is: 86 7 1 + Current sample, line, band is: 86 8 1 + Current sample, line, band is: 86 9 1 + Current sample, line, band is: 86 10 1 + Current sample, line, band is: 86 11 1 + Current sample, line, band is: 86 12 1 + Current sample, line, band is: 86 13 1 + Current sample, line, band is: 86 14 1 + Current sample, line, band is: 86 15 1 + Current sample, line, band is: 86 16 1 + Current sample, line, band is: 86 17 1 + Current sample, line, band is: 86 18 1 + Current sample, line, band is: 86 19 1 + Current sample, line, band is: 86 20 1 + Current sample, line, band is: 86 21 1 + Current sample, line, band is: 86 22 1 + Current sample, line, band is: 86 23 1 + Current sample, line, band is: 86 24 1 + Current sample, line, band is: 86 25 1 + Current sample, line, band is: 86 26 1 + Current sample, line, band is: 86 27 1 + Current sample, line, band is: 86 28 1 + Current sample, line, band is: 86 29 1 + Current sample, line, band is: 86 30 1 + Current sample, line, band is: 86 31 1 + Current sample, line, band is: 86 32 1 + Current sample, line, band is: 86 33 1 + Current sample, line, band is: 86 34 1 + Current sample, line, band is: 86 35 1 + Current sample, line, band is: 86 36 1 + Current sample, line, band is: 86 37 1 + Current sample, line, band is: 86 38 1 + Current sample, line, band is: 86 39 1 + Current sample, line, band is: 86 40 1 + Current sample, line, band is: 86 41 1 + Current sample, line, band is: 86 42 1 + Current sample, line, band is: 86 43 1 + Current sample, line, band is: 86 44 1 + Current sample, line, band is: 86 45 1 + Current sample, line, band is: 86 46 1 + Current sample, line, band is: 86 47 1 + Current sample, line, band is: 86 48 1 + Current sample, line, band is: 86 49 1 + Current sample, line, band is: 86 50 1 + Current sample, line, band is: 86 51 1 + Current sample, line, band is: 86 52 1 + Current sample, line, band is: 86 53 1 + Current sample, line, band is: 86 54 1 + Current sample, line, band is: 86 55 1 + Current sample, line, band is: 86 56 1 + Current sample, line, band is: 86 57 1 + Current sample, line, band is: 86 58 1 + Current sample, line, band is: 86 59 1 + Current sample, line, band is: 86 60 1 + Current sample, line, band is: 86 61 1 + Current sample, line, band is: 86 62 1 + Current sample, line, band is: 86 63 1 + Current sample, line, band is: 86 64 1 + Current sample, line, band is: 86 65 1 + Current sample, line, band is: 86 66 1 + Current sample, line, band is: 86 67 1 + Current sample, line, band is: 86 68 1 + Current sample, line, band is: 86 69 1 + Current sample, line, band is: 86 70 1 + Current sample, line, band is: 86 71 1 + Current sample, line, band is: 86 72 1 + Current sample, line, band is: 86 73 1 + Current sample, line, band is: 86 74 1 + Current sample, line, band is: 86 75 1 + Current sample, line, band is: 86 76 1 + Current sample, line, band is: 86 77 1 + Current sample, line, band is: 86 78 1 + Current sample, line, band is: 86 79 1 + Current sample, line, band is: 86 80 1 + Current sample, line, band is: 86 81 1 + Current sample, line, band is: 86 82 1 + Current sample, line, band is: 86 83 1 + Current sample, line, band is: 86 84 1 + Current sample, line, band is: 86 85 1 + Current sample, line, band is: 86 86 1 + Current sample, line, band is: 86 87 1 + Current sample, line, band is: 86 88 1 + Current sample, line, band is: 86 89 1 + Current sample, line, band is: 86 90 1 + Current sample, line, band is: 86 91 1 + Current sample, line, band is: 86 92 1 + Current sample, line, band is: 86 93 1 + Current sample, line, band is: 86 94 1 + Current sample, line, band is: 86 95 1 + Current sample, line, band is: 86 96 1 + Current sample, line, band is: 86 97 1 + Current sample, line, band is: 86 98 1 + Current sample, line, band is: 86 99 1 + Current sample, line, band is: 86 100 1 + Current sample, line, band is: 86 101 1 + Current sample, line, band is: 86 102 1 + Current sample, line, band is: 86 103 1 + Current sample, line, band is: 86 104 1 + Current sample, line, band is: 86 105 1 + Current sample, line, band is: 86 106 1 + Current sample, line, band is: 86 107 1 + Current sample, line, band is: 86 108 1 + Current sample, line, band is: 86 109 1 + Current sample, line, band is: 86 110 1 + Current sample, line, band is: 86 111 1 + Current sample, line, band is: 86 112 1 + Current sample, line, band is: 86 113 1 + Current sample, line, band is: 86 114 1 + Current sample, line, band is: 86 115 1 + Current sample, line, band is: 86 116 1 + Current sample, line, band is: 86 117 1 + Current sample, line, band is: 86 118 1 + Current sample, line, band is: 86 119 1 + Current sample, line, band is: 86 120 1 + Current sample, line, band is: 86 121 1 + Current sample, line, band is: 86 122 1 + Current sample, line, band is: 86 123 1 + Current sample, line, band is: 86 124 1 + Current sample, line, band is: 86 125 1 + Current sample, line, band is: 86 126 1 + Current sample, line, band is: 87 1 1 + Current sample, line, band is: 87 2 1 + Current sample, line, band is: 87 3 1 + Current sample, line, band is: 87 4 1 + Current sample, line, band is: 87 5 1 + Current sample, line, band is: 87 6 1 + Current sample, line, band is: 87 7 1 + Current sample, line, band is: 87 8 1 + Current sample, line, band is: 87 9 1 + Current sample, line, band is: 87 10 1 + Current sample, line, band is: 87 11 1 + Current sample, line, band is: 87 12 1 + Current sample, line, band is: 87 13 1 + Current sample, line, band is: 87 14 1 + Current sample, line, band is: 87 15 1 + Current sample, line, band is: 87 16 1 + Current sample, line, band is: 87 17 1 + Current sample, line, band is: 87 18 1 + Current sample, line, band is: 87 19 1 + Current sample, line, band is: 87 20 1 + Current sample, line, band is: 87 21 1 + Current sample, line, band is: 87 22 1 + Current sample, line, band is: 87 23 1 + Current sample, line, band is: 87 24 1 + Current sample, line, band is: 87 25 1 + Current sample, line, band is: 87 26 1 + Current sample, line, band is: 87 27 1 + Current sample, line, band is: 87 28 1 + Current sample, line, band is: 87 29 1 + Current sample, line, band is: 87 30 1 + Current sample, line, band is: 87 31 1 + Current sample, line, band is: 87 32 1 + Current sample, line, band is: 87 33 1 + Current sample, line, band is: 87 34 1 + Current sample, line, band is: 87 35 1 + Current sample, line, band is: 87 36 1 + Current sample, line, band is: 87 37 1 + Current sample, line, band is: 87 38 1 + Current sample, line, band is: 87 39 1 + Current sample, line, band is: 87 40 1 + Current sample, line, band is: 87 41 1 + Current sample, line, band is: 87 42 1 + Current sample, line, band is: 87 43 1 + Current sample, line, band is: 87 44 1 + Current sample, line, band is: 87 45 1 + Current sample, line, band is: 87 46 1 + Current sample, line, band is: 87 47 1 + Current sample, line, band is: 87 48 1 + Current sample, line, band is: 87 49 1 + Current sample, line, band is: 87 50 1 + Current sample, line, band is: 87 51 1 + Current sample, line, band is: 87 52 1 + Current sample, line, band is: 87 53 1 + Current sample, line, band is: 87 54 1 + Current sample, line, band is: 87 55 1 + Current sample, line, band is: 87 56 1 + Current sample, line, band is: 87 57 1 + Current sample, line, band is: 87 58 1 + Current sample, line, band is: 87 59 1 + Current sample, line, band is: 87 60 1 + Current sample, line, band is: 87 61 1 + Current sample, line, band is: 87 62 1 + Current sample, line, band is: 87 63 1 + Current sample, line, band is: 87 64 1 + Current sample, line, band is: 87 65 1 + Current sample, line, band is: 87 66 1 + Current sample, line, band is: 87 67 1 + Current sample, line, band is: 87 68 1 + Current sample, line, band is: 87 69 1 + Current sample, line, band is: 87 70 1 + Current sample, line, band is: 87 71 1 + Current sample, line, band is: 87 72 1 + Current sample, line, band is: 87 73 1 + Current sample, line, band is: 87 74 1 + Current sample, line, band is: 87 75 1 + Current sample, line, band is: 87 76 1 + Current sample, line, band is: 87 77 1 + Current sample, line, band is: 87 78 1 + Current sample, line, band is: 87 79 1 + Current sample, line, band is: 87 80 1 + Current sample, line, band is: 87 81 1 + Current sample, line, band is: 87 82 1 + Current sample, line, band is: 87 83 1 + Current sample, line, band is: 87 84 1 + Current sample, line, band is: 87 85 1 + Current sample, line, band is: 87 86 1 + Current sample, line, band is: 87 87 1 + Current sample, line, band is: 87 88 1 + Current sample, line, band is: 87 89 1 + Current sample, line, band is: 87 90 1 + Current sample, line, band is: 87 91 1 + Current sample, line, band is: 87 92 1 + Current sample, line, band is: 87 93 1 + Current sample, line, band is: 87 94 1 + Current sample, line, band is: 87 95 1 + Current sample, line, band is: 87 96 1 + Current sample, line, band is: 87 97 1 + Current sample, line, band is: 87 98 1 + Current sample, line, band is: 87 99 1 + Current sample, line, band is: 87 100 1 + Current sample, line, band is: 87 101 1 + Current sample, line, band is: 87 102 1 + Current sample, line, band is: 87 103 1 + Current sample, line, band is: 87 104 1 + Current sample, line, band is: 87 105 1 + Current sample, line, band is: 87 106 1 + Current sample, line, band is: 87 107 1 + Current sample, line, band is: 87 108 1 + Current sample, line, band is: 87 109 1 + Current sample, line, band is: 87 110 1 + Current sample, line, band is: 87 111 1 + Current sample, line, band is: 87 112 1 + Current sample, line, band is: 87 113 1 + Current sample, line, band is: 87 114 1 + Current sample, line, band is: 87 115 1 + Current sample, line, band is: 87 116 1 + Current sample, line, band is: 87 117 1 + Current sample, line, band is: 87 118 1 + Current sample, line, band is: 87 119 1 + Current sample, line, band is: 87 120 1 + Current sample, line, band is: 87 121 1 + Current sample, line, band is: 87 122 1 + Current sample, line, band is: 87 123 1 + Current sample, line, band is: 87 124 1 + Current sample, line, band is: 87 125 1 + Current sample, line, band is: 87 126 1 + Current sample, line, band is: 88 1 1 + Current sample, line, band is: 88 2 1 + Current sample, line, band is: 88 3 1 + Current sample, line, band is: 88 4 1 + Current sample, line, band is: 88 5 1 + Current sample, line, band is: 88 6 1 + Current sample, line, band is: 88 7 1 + Current sample, line, band is: 88 8 1 + Current sample, line, band is: 88 9 1 + Current sample, line, band is: 88 10 1 + Current sample, line, band is: 88 11 1 + Current sample, line, band is: 88 12 1 + Current sample, line, band is: 88 13 1 + Current sample, line, band is: 88 14 1 + Current sample, line, band is: 88 15 1 + Current sample, line, band is: 88 16 1 + Current sample, line, band is: 88 17 1 + Current sample, line, band is: 88 18 1 + Current sample, line, band is: 88 19 1 + Current sample, line, band is: 88 20 1 + Current sample, line, band is: 88 21 1 + Current sample, line, band is: 88 22 1 + Current sample, line, band is: 88 23 1 + Current sample, line, band is: 88 24 1 + Current sample, line, band is: 88 25 1 + Current sample, line, band is: 88 26 1 + Current sample, line, band is: 88 27 1 + Current sample, line, band is: 88 28 1 + Current sample, line, band is: 88 29 1 + Current sample, line, band is: 88 30 1 + Current sample, line, band is: 88 31 1 + Current sample, line, band is: 88 32 1 + Current sample, line, band is: 88 33 1 + Current sample, line, band is: 88 34 1 + Current sample, line, band is: 88 35 1 + Current sample, line, band is: 88 36 1 + Current sample, line, band is: 88 37 1 + Current sample, line, band is: 88 38 1 + Current sample, line, band is: 88 39 1 + Current sample, line, band is: 88 40 1 + Current sample, line, band is: 88 41 1 + Current sample, line, band is: 88 42 1 + Current sample, line, band is: 88 43 1 + Current sample, line, band is: 88 44 1 + Current sample, line, band is: 88 45 1 + Current sample, line, band is: 88 46 1 + Current sample, line, band is: 88 47 1 + Current sample, line, band is: 88 48 1 + Current sample, line, band is: 88 49 1 + Current sample, line, band is: 88 50 1 + Current sample, line, band is: 88 51 1 + Current sample, line, band is: 88 52 1 + Current sample, line, band is: 88 53 1 + Current sample, line, band is: 88 54 1 + Current sample, line, band is: 88 55 1 + Current sample, line, band is: 88 56 1 + Current sample, line, band is: 88 57 1 + Current sample, line, band is: 88 58 1 + Current sample, line, band is: 88 59 1 + Current sample, line, band is: 88 60 1 + Current sample, line, band is: 88 61 1 + Current sample, line, band is: 88 62 1 + Current sample, line, band is: 88 63 1 + Current sample, line, band is: 88 64 1 + Current sample, line, band is: 88 65 1 + Current sample, line, band is: 88 66 1 + Current sample, line, band is: 88 67 1 + Current sample, line, band is: 88 68 1 + Current sample, line, band is: 88 69 1 + Current sample, line, band is: 88 70 1 + Current sample, line, band is: 88 71 1 + Current sample, line, band is: 88 72 1 + Current sample, line, band is: 88 73 1 + Current sample, line, band is: 88 74 1 + Current sample, line, band is: 88 75 1 + Current sample, line, band is: 88 76 1 + Current sample, line, band is: 88 77 1 + Current sample, line, band is: 88 78 1 + Current sample, line, band is: 88 79 1 + Current sample, line, band is: 88 80 1 + Current sample, line, band is: 88 81 1 + Current sample, line, band is: 88 82 1 + Current sample, line, band is: 88 83 1 + Current sample, line, band is: 88 84 1 + Current sample, line, band is: 88 85 1 + Current sample, line, band is: 88 86 1 + Current sample, line, band is: 88 87 1 + Current sample, line, band is: 88 88 1 + Current sample, line, band is: 88 89 1 + Current sample, line, band is: 88 90 1 + Current sample, line, band is: 88 91 1 + Current sample, line, band is: 88 92 1 + Current sample, line, band is: 88 93 1 + Current sample, line, band is: 88 94 1 + Current sample, line, band is: 88 95 1 + Current sample, line, band is: 88 96 1 + Current sample, line, band is: 88 97 1 + Current sample, line, band is: 88 98 1 + Current sample, line, band is: 88 99 1 + Current sample, line, band is: 88 100 1 + Current sample, line, band is: 88 101 1 + Current sample, line, band is: 88 102 1 + Current sample, line, band is: 88 103 1 + Current sample, line, band is: 88 104 1 + Current sample, line, band is: 88 105 1 + Current sample, line, band is: 88 106 1 + Current sample, line, band is: 88 107 1 + Current sample, line, band is: 88 108 1 + Current sample, line, band is: 88 109 1 + Current sample, line, band is: 88 110 1 + Current sample, line, band is: 88 111 1 + Current sample, line, band is: 88 112 1 + Current sample, line, band is: 88 113 1 + Current sample, line, band is: 88 114 1 + Current sample, line, band is: 88 115 1 + Current sample, line, band is: 88 116 1 + Current sample, line, band is: 88 117 1 + Current sample, line, band is: 88 118 1 + Current sample, line, band is: 88 119 1 + Current sample, line, band is: 88 120 1 + Current sample, line, band is: 88 121 1 + Current sample, line, band is: 88 122 1 + Current sample, line, band is: 88 123 1 + Current sample, line, band is: 88 124 1 + Current sample, line, band is: 88 125 1 + Current sample, line, band is: 88 126 1 + Current sample, line, band is: 89 1 1 + Current sample, line, band is: 89 2 1 + Current sample, line, band is: 89 3 1 + Current sample, line, band is: 89 4 1 + Current sample, line, band is: 89 5 1 + Current sample, line, band is: 89 6 1 + Current sample, line, band is: 89 7 1 + Current sample, line, band is: 89 8 1 + Current sample, line, band is: 89 9 1 + Current sample, line, band is: 89 10 1 + Current sample, line, band is: 89 11 1 + Current sample, line, band is: 89 12 1 + Current sample, line, band is: 89 13 1 + Current sample, line, band is: 89 14 1 + Current sample, line, band is: 89 15 1 + Current sample, line, band is: 89 16 1 + Current sample, line, band is: 89 17 1 + Current sample, line, band is: 89 18 1 + Current sample, line, band is: 89 19 1 + Current sample, line, band is: 89 20 1 + Current sample, line, band is: 89 21 1 + Current sample, line, band is: 89 22 1 + Current sample, line, band is: 89 23 1 + Current sample, line, band is: 89 24 1 + Current sample, line, band is: 89 25 1 + Current sample, line, band is: 89 26 1 + Current sample, line, band is: 89 27 1 + Current sample, line, band is: 89 28 1 + Current sample, line, band is: 89 29 1 + Current sample, line, band is: 89 30 1 + Current sample, line, band is: 89 31 1 + Current sample, line, band is: 89 32 1 + Current sample, line, band is: 89 33 1 + Current sample, line, band is: 89 34 1 + Current sample, line, band is: 89 35 1 + Current sample, line, band is: 89 36 1 + Current sample, line, band is: 89 37 1 + Current sample, line, band is: 89 38 1 + Current sample, line, band is: 89 39 1 + Current sample, line, band is: 89 40 1 + Current sample, line, band is: 89 41 1 + Current sample, line, band is: 89 42 1 + Current sample, line, band is: 89 43 1 + Current sample, line, band is: 89 44 1 + Current sample, line, band is: 89 45 1 + Current sample, line, band is: 89 46 1 + Current sample, line, band is: 89 47 1 + Current sample, line, band is: 89 48 1 + Current sample, line, band is: 89 49 1 + Current sample, line, band is: 89 50 1 + Current sample, line, band is: 89 51 1 + Current sample, line, band is: 89 52 1 + Current sample, line, band is: 89 53 1 + Current sample, line, band is: 89 54 1 + Current sample, line, band is: 89 55 1 + Current sample, line, band is: 89 56 1 + Current sample, line, band is: 89 57 1 + Current sample, line, band is: 89 58 1 + Current sample, line, band is: 89 59 1 + Current sample, line, band is: 89 60 1 + Current sample, line, band is: 89 61 1 + Current sample, line, band is: 89 62 1 + Current sample, line, band is: 89 63 1 + Current sample, line, band is: 89 64 1 + Current sample, line, band is: 89 65 1 + Current sample, line, band is: 89 66 1 + Current sample, line, band is: 89 67 1 + Current sample, line, band is: 89 68 1 + Current sample, line, band is: 89 69 1 + Current sample, line, band is: 89 70 1 + Current sample, line, band is: 89 71 1 + Current sample, line, band is: 89 72 1 + Current sample, line, band is: 89 73 1 + Current sample, line, band is: 89 74 1 + Current sample, line, band is: 89 75 1 + Current sample, line, band is: 89 76 1 + Current sample, line, band is: 89 77 1 + Current sample, line, band is: 89 78 1 + Current sample, line, band is: 89 79 1 + Current sample, line, band is: 89 80 1 + Current sample, line, band is: 89 81 1 + Current sample, line, band is: 89 82 1 + Current sample, line, band is: 89 83 1 + Current sample, line, band is: 89 84 1 + Current sample, line, band is: 89 85 1 + Current sample, line, band is: 89 86 1 + Current sample, line, band is: 89 87 1 + Current sample, line, band is: 89 88 1 + Current sample, line, band is: 89 89 1 + Current sample, line, band is: 89 90 1 + Current sample, line, band is: 89 91 1 + Current sample, line, band is: 89 92 1 + Current sample, line, band is: 89 93 1 + Current sample, line, band is: 89 94 1 + Current sample, line, band is: 89 95 1 + Current sample, line, band is: 89 96 1 + Current sample, line, band is: 89 97 1 + Current sample, line, band is: 89 98 1 + Current sample, line, band is: 89 99 1 + Current sample, line, band is: 89 100 1 + Current sample, line, band is: 89 101 1 + Current sample, line, band is: 89 102 1 + Current sample, line, band is: 89 103 1 + Current sample, line, band is: 89 104 1 + Current sample, line, band is: 89 105 1 + Current sample, line, band is: 89 106 1 + Current sample, line, band is: 89 107 1 + Current sample, line, band is: 89 108 1 + Current sample, line, band is: 89 109 1 + Current sample, line, band is: 89 110 1 + Current sample, line, band is: 89 111 1 + Current sample, line, band is: 89 112 1 + Current sample, line, band is: 89 113 1 + Current sample, line, band is: 89 114 1 + Current sample, line, band is: 89 115 1 + Current sample, line, band is: 89 116 1 + Current sample, line, band is: 89 117 1 + Current sample, line, band is: 89 118 1 + Current sample, line, band is: 89 119 1 + Current sample, line, band is: 89 120 1 + Current sample, line, band is: 89 121 1 + Current sample, line, band is: 89 122 1 + Current sample, line, band is: 89 123 1 + Current sample, line, band is: 89 124 1 + Current sample, line, band is: 89 125 1 + Current sample, line, band is: 89 126 1 + Current sample, line, band is: 90 1 1 + Current sample, line, band is: 90 2 1 + Current sample, line, band is: 90 3 1 + Current sample, line, band is: 90 4 1 + Current sample, line, band is: 90 5 1 + Current sample, line, band is: 90 6 1 + Current sample, line, band is: 90 7 1 + Current sample, line, band is: 90 8 1 + Current sample, line, band is: 90 9 1 + Current sample, line, band is: 90 10 1 + Current sample, line, band is: 90 11 1 + Current sample, line, band is: 90 12 1 + Current sample, line, band is: 90 13 1 + Current sample, line, band is: 90 14 1 + Current sample, line, band is: 90 15 1 + Current sample, line, band is: 90 16 1 + Current sample, line, band is: 90 17 1 + Current sample, line, band is: 90 18 1 + Current sample, line, band is: 90 19 1 + Current sample, line, band is: 90 20 1 + Current sample, line, band is: 90 21 1 + Current sample, line, band is: 90 22 1 + Current sample, line, band is: 90 23 1 + Current sample, line, band is: 90 24 1 + Current sample, line, band is: 90 25 1 + Current sample, line, band is: 90 26 1 + Current sample, line, band is: 90 27 1 + Current sample, line, band is: 90 28 1 + Current sample, line, band is: 90 29 1 + Current sample, line, band is: 90 30 1 + Current sample, line, band is: 90 31 1 + Current sample, line, band is: 90 32 1 + Current sample, line, band is: 90 33 1 + Current sample, line, band is: 90 34 1 + Current sample, line, band is: 90 35 1 + Current sample, line, band is: 90 36 1 + Current sample, line, band is: 90 37 1 + Current sample, line, band is: 90 38 1 + Current sample, line, band is: 90 39 1 + Current sample, line, band is: 90 40 1 + Current sample, line, band is: 90 41 1 + Current sample, line, band is: 90 42 1 + Current sample, line, band is: 90 43 1 + Current sample, line, band is: 90 44 1 + Current sample, line, band is: 90 45 1 + Current sample, line, band is: 90 46 1 + Current sample, line, band is: 90 47 1 + Current sample, line, band is: 90 48 1 + Current sample, line, band is: 90 49 1 + Current sample, line, band is: 90 50 1 + Current sample, line, band is: 90 51 1 + Current sample, line, band is: 90 52 1 + Current sample, line, band is: 90 53 1 + Current sample, line, band is: 90 54 1 + Current sample, line, band is: 90 55 1 + Current sample, line, band is: 90 56 1 + Current sample, line, band is: 90 57 1 + Current sample, line, band is: 90 58 1 + Current sample, line, band is: 90 59 1 + Current sample, line, band is: 90 60 1 + Current sample, line, band is: 90 61 1 + Current sample, line, band is: 90 62 1 + Current sample, line, band is: 90 63 1 + Current sample, line, band is: 90 64 1 + Current sample, line, band is: 90 65 1 + Current sample, line, band is: 90 66 1 + Current sample, line, band is: 90 67 1 + Current sample, line, band is: 90 68 1 + Current sample, line, band is: 90 69 1 + Current sample, line, band is: 90 70 1 + Current sample, line, band is: 90 71 1 + Current sample, line, band is: 90 72 1 + Current sample, line, band is: 90 73 1 + Current sample, line, band is: 90 74 1 + Current sample, line, band is: 90 75 1 + Current sample, line, band is: 90 76 1 + Current sample, line, band is: 90 77 1 + Current sample, line, band is: 90 78 1 + Current sample, line, band is: 90 79 1 + Current sample, line, band is: 90 80 1 + Current sample, line, band is: 90 81 1 + Current sample, line, band is: 90 82 1 + Current sample, line, band is: 90 83 1 + Current sample, line, band is: 90 84 1 + Current sample, line, band is: 90 85 1 + Current sample, line, band is: 90 86 1 + Current sample, line, band is: 90 87 1 + Current sample, line, band is: 90 88 1 + Current sample, line, band is: 90 89 1 + Current sample, line, band is: 90 90 1 + Current sample, line, band is: 90 91 1 + Current sample, line, band is: 90 92 1 + Current sample, line, band is: 90 93 1 + Current sample, line, band is: 90 94 1 + Current sample, line, band is: 90 95 1 + Current sample, line, band is: 90 96 1 + Current sample, line, band is: 90 97 1 + Current sample, line, band is: 90 98 1 + Current sample, line, band is: 90 99 1 + Current sample, line, band is: 90 100 1 + Current sample, line, band is: 90 101 1 + Current sample, line, band is: 90 102 1 + Current sample, line, band is: 90 103 1 + Current sample, line, band is: 90 104 1 + Current sample, line, band is: 90 105 1 + Current sample, line, band is: 90 106 1 + Current sample, line, band is: 90 107 1 + Current sample, line, band is: 90 108 1 + Current sample, line, band is: 90 109 1 + Current sample, line, band is: 90 110 1 + Current sample, line, band is: 90 111 1 + Current sample, line, band is: 90 112 1 + Current sample, line, band is: 90 113 1 + Current sample, line, band is: 90 114 1 + Current sample, line, band is: 90 115 1 + Current sample, line, band is: 90 116 1 + Current sample, line, band is: 90 117 1 + Current sample, line, band is: 90 118 1 + Current sample, line, band is: 90 119 1 + Current sample, line, band is: 90 120 1 + Current sample, line, band is: 90 121 1 + Current sample, line, band is: 90 122 1 + Current sample, line, band is: 90 123 1 + Current sample, line, band is: 90 124 1 + Current sample, line, band is: 90 125 1 + Current sample, line, band is: 90 126 1 + Current sample, line, band is: 91 1 1 + Current sample, line, band is: 91 2 1 + Current sample, line, band is: 91 3 1 + Current sample, line, band is: 91 4 1 + Current sample, line, band is: 91 5 1 + Current sample, line, band is: 91 6 1 + Current sample, line, band is: 91 7 1 + Current sample, line, band is: 91 8 1 + Current sample, line, band is: 91 9 1 + Current sample, line, band is: 91 10 1 + Current sample, line, band is: 91 11 1 + Current sample, line, band is: 91 12 1 + Current sample, line, band is: 91 13 1 + Current sample, line, band is: 91 14 1 + Current sample, line, band is: 91 15 1 + Current sample, line, band is: 91 16 1 + Current sample, line, band is: 91 17 1 + Current sample, line, band is: 91 18 1 + Current sample, line, band is: 91 19 1 + Current sample, line, band is: 91 20 1 + Current sample, line, band is: 91 21 1 + Current sample, line, band is: 91 22 1 + Current sample, line, band is: 91 23 1 + Current sample, line, band is: 91 24 1 + Current sample, line, band is: 91 25 1 + Current sample, line, band is: 91 26 1 + Current sample, line, band is: 91 27 1 + Current sample, line, band is: 91 28 1 + Current sample, line, band is: 91 29 1 + Current sample, line, band is: 91 30 1 + Current sample, line, band is: 91 31 1 + Current sample, line, band is: 91 32 1 + Current sample, line, band is: 91 33 1 + Current sample, line, band is: 91 34 1 + Current sample, line, band is: 91 35 1 + Current sample, line, band is: 91 36 1 + Current sample, line, band is: 91 37 1 + Current sample, line, band is: 91 38 1 + Current sample, line, band is: 91 39 1 + Current sample, line, band is: 91 40 1 + Current sample, line, band is: 91 41 1 + Current sample, line, band is: 91 42 1 + Current sample, line, band is: 91 43 1 + Current sample, line, band is: 91 44 1 + Current sample, line, band is: 91 45 1 + Current sample, line, band is: 91 46 1 + Current sample, line, band is: 91 47 1 + Current sample, line, band is: 91 48 1 + Current sample, line, band is: 91 49 1 + Current sample, line, band is: 91 50 1 + Current sample, line, band is: 91 51 1 + Current sample, line, band is: 91 52 1 + Current sample, line, band is: 91 53 1 + Current sample, line, band is: 91 54 1 + Current sample, line, band is: 91 55 1 + Current sample, line, band is: 91 56 1 + Current sample, line, band is: 91 57 1 + Current sample, line, band is: 91 58 1 + Current sample, line, band is: 91 59 1 + Current sample, line, band is: 91 60 1 + Current sample, line, band is: 91 61 1 + Current sample, line, band is: 91 62 1 + Current sample, line, band is: 91 63 1 + Current sample, line, band is: 91 64 1 + Current sample, line, band is: 91 65 1 + Current sample, line, band is: 91 66 1 + Current sample, line, band is: 91 67 1 + Current sample, line, band is: 91 68 1 + Current sample, line, band is: 91 69 1 + Current sample, line, band is: 91 70 1 + Current sample, line, band is: 91 71 1 + Current sample, line, band is: 91 72 1 + Current sample, line, band is: 91 73 1 + Current sample, line, band is: 91 74 1 + Current sample, line, band is: 91 75 1 + Current sample, line, band is: 91 76 1 + Current sample, line, band is: 91 77 1 + Current sample, line, band is: 91 78 1 + Current sample, line, band is: 91 79 1 + Current sample, line, band is: 91 80 1 + Current sample, line, band is: 91 81 1 + Current sample, line, band is: 91 82 1 + Current sample, line, band is: 91 83 1 + Current sample, line, band is: 91 84 1 + Current sample, line, band is: 91 85 1 + Current sample, line, band is: 91 86 1 + Current sample, line, band is: 91 87 1 + Current sample, line, band is: 91 88 1 + Current sample, line, band is: 91 89 1 + Current sample, line, band is: 91 90 1 + Current sample, line, band is: 91 91 1 + Current sample, line, band is: 91 92 1 + Current sample, line, band is: 91 93 1 + Current sample, line, band is: 91 94 1 + Current sample, line, band is: 91 95 1 + Current sample, line, band is: 91 96 1 + Current sample, line, band is: 91 97 1 + Current sample, line, band is: 91 98 1 + Current sample, line, band is: 91 99 1 + Current sample, line, band is: 91 100 1 + Current sample, line, band is: 91 101 1 + Current sample, line, band is: 91 102 1 + Current sample, line, band is: 91 103 1 + Current sample, line, band is: 91 104 1 + Current sample, line, band is: 91 105 1 + Current sample, line, band is: 91 106 1 + Current sample, line, band is: 91 107 1 + Current sample, line, band is: 91 108 1 + Current sample, line, band is: 91 109 1 + Current sample, line, band is: 91 110 1 + Current sample, line, band is: 91 111 1 + Current sample, line, band is: 91 112 1 + Current sample, line, band is: 91 113 1 + Current sample, line, band is: 91 114 1 + Current sample, line, band is: 91 115 1 + Current sample, line, band is: 91 116 1 + Current sample, line, band is: 91 117 1 + Current sample, line, band is: 91 118 1 + Current sample, line, band is: 91 119 1 + Current sample, line, band is: 91 120 1 + Current sample, line, band is: 91 121 1 + Current sample, line, band is: 91 122 1 + Current sample, line, band is: 91 123 1 + Current sample, line, band is: 91 124 1 + Current sample, line, band is: 91 125 1 + Current sample, line, band is: 91 126 1 + Current sample, line, band is: 92 1 1 + Current sample, line, band is: 92 2 1 + Current sample, line, band is: 92 3 1 + Current sample, line, band is: 92 4 1 + Current sample, line, band is: 92 5 1 + Current sample, line, band is: 92 6 1 + Current sample, line, band is: 92 7 1 + Current sample, line, band is: 92 8 1 + Current sample, line, band is: 92 9 1 + Current sample, line, band is: 92 10 1 + Current sample, line, band is: 92 11 1 + Current sample, line, band is: 92 12 1 + Current sample, line, band is: 92 13 1 + Current sample, line, band is: 92 14 1 + Current sample, line, band is: 92 15 1 + Current sample, line, band is: 92 16 1 + Current sample, line, band is: 92 17 1 + Current sample, line, band is: 92 18 1 + Current sample, line, band is: 92 19 1 + Current sample, line, band is: 92 20 1 + Current sample, line, band is: 92 21 1 + Current sample, line, band is: 92 22 1 + Current sample, line, band is: 92 23 1 + Current sample, line, band is: 92 24 1 + Current sample, line, band is: 92 25 1 + Current sample, line, band is: 92 26 1 + Current sample, line, band is: 92 27 1 + Current sample, line, band is: 92 28 1 + Current sample, line, band is: 92 29 1 + Current sample, line, band is: 92 30 1 + Current sample, line, band is: 92 31 1 + Current sample, line, band is: 92 32 1 + Current sample, line, band is: 92 33 1 + Current sample, line, band is: 92 34 1 + Current sample, line, band is: 92 35 1 + Current sample, line, band is: 92 36 1 + Current sample, line, band is: 92 37 1 + Current sample, line, band is: 92 38 1 + Current sample, line, band is: 92 39 1 + Current sample, line, band is: 92 40 1 + Current sample, line, band is: 92 41 1 + Current sample, line, band is: 92 42 1 + Current sample, line, band is: 92 43 1 + Current sample, line, band is: 92 44 1 + Current sample, line, band is: 92 45 1 + Current sample, line, band is: 92 46 1 + Current sample, line, band is: 92 47 1 + Current sample, line, band is: 92 48 1 + Current sample, line, band is: 92 49 1 + Current sample, line, band is: 92 50 1 + Current sample, line, band is: 92 51 1 + Current sample, line, band is: 92 52 1 + Current sample, line, band is: 92 53 1 + Current sample, line, band is: 92 54 1 + Current sample, line, band is: 92 55 1 + Current sample, line, band is: 92 56 1 + Current sample, line, band is: 92 57 1 + Current sample, line, band is: 92 58 1 + Current sample, line, band is: 92 59 1 + Current sample, line, band is: 92 60 1 + Current sample, line, band is: 92 61 1 + Current sample, line, band is: 92 62 1 + Current sample, line, band is: 92 63 1 + Current sample, line, band is: 92 64 1 + Current sample, line, band is: 92 65 1 + Current sample, line, band is: 92 66 1 + Current sample, line, band is: 92 67 1 + Current sample, line, band is: 92 68 1 + Current sample, line, band is: 92 69 1 + Current sample, line, band is: 92 70 1 + Current sample, line, band is: 92 71 1 + Current sample, line, band is: 92 72 1 + Current sample, line, band is: 92 73 1 + Current sample, line, band is: 92 74 1 + Current sample, line, band is: 92 75 1 + Current sample, line, band is: 92 76 1 + Current sample, line, band is: 92 77 1 + Current sample, line, band is: 92 78 1 + Current sample, line, band is: 92 79 1 + Current sample, line, band is: 92 80 1 + Current sample, line, band is: 92 81 1 + Current sample, line, band is: 92 82 1 + Current sample, line, band is: 92 83 1 + Current sample, line, band is: 92 84 1 + Current sample, line, band is: 92 85 1 + Current sample, line, band is: 92 86 1 + Current sample, line, band is: 92 87 1 + Current sample, line, band is: 92 88 1 + Current sample, line, band is: 92 89 1 + Current sample, line, band is: 92 90 1 + Current sample, line, band is: 92 91 1 + Current sample, line, band is: 92 92 1 + Current sample, line, band is: 92 93 1 + Current sample, line, band is: 92 94 1 + Current sample, line, band is: 92 95 1 + Current sample, line, band is: 92 96 1 + Current sample, line, band is: 92 97 1 + Current sample, line, band is: 92 98 1 + Current sample, line, band is: 92 99 1 + Current sample, line, band is: 92 100 1 + Current sample, line, band is: 92 101 1 + Current sample, line, band is: 92 102 1 + Current sample, line, band is: 92 103 1 + Current sample, line, band is: 92 104 1 + Current sample, line, band is: 92 105 1 + Current sample, line, band is: 92 106 1 + Current sample, line, band is: 92 107 1 + Current sample, line, band is: 92 108 1 + Current sample, line, band is: 92 109 1 + Current sample, line, band is: 92 110 1 + Current sample, line, band is: 92 111 1 + Current sample, line, band is: 92 112 1 + Current sample, line, band is: 92 113 1 + Current sample, line, band is: 92 114 1 + Current sample, line, band is: 92 115 1 + Current sample, line, band is: 92 116 1 + Current sample, line, band is: 92 117 1 + Current sample, line, band is: 92 118 1 + Current sample, line, band is: 92 119 1 + Current sample, line, band is: 92 120 1 + Current sample, line, band is: 92 121 1 + Current sample, line, band is: 92 122 1 + Current sample, line, band is: 92 123 1 + Current sample, line, band is: 92 124 1 + Current sample, line, band is: 92 125 1 + Current sample, line, band is: 92 126 1 + Current sample, line, band is: 93 1 1 + Current sample, line, band is: 93 2 1 + Current sample, line, band is: 93 3 1 + Current sample, line, band is: 93 4 1 + Current sample, line, band is: 93 5 1 + Current sample, line, band is: 93 6 1 + Current sample, line, band is: 93 7 1 + Current sample, line, band is: 93 8 1 + Current sample, line, band is: 93 9 1 + Current sample, line, band is: 93 10 1 + Current sample, line, band is: 93 11 1 + Current sample, line, band is: 93 12 1 + Current sample, line, band is: 93 13 1 + Current sample, line, band is: 93 14 1 + Current sample, line, band is: 93 15 1 + Current sample, line, band is: 93 16 1 + Current sample, line, band is: 93 17 1 + Current sample, line, band is: 93 18 1 + Current sample, line, band is: 93 19 1 + Current sample, line, band is: 93 20 1 + Current sample, line, band is: 93 21 1 + Current sample, line, band is: 93 22 1 + Current sample, line, band is: 93 23 1 + Current sample, line, band is: 93 24 1 + Current sample, line, band is: 93 25 1 + Current sample, line, band is: 93 26 1 + Current sample, line, band is: 93 27 1 + Current sample, line, band is: 93 28 1 + Current sample, line, band is: 93 29 1 + Current sample, line, band is: 93 30 1 + Current sample, line, band is: 93 31 1 + Current sample, line, band is: 93 32 1 + Current sample, line, band is: 93 33 1 + Current sample, line, band is: 93 34 1 + Current sample, line, band is: 93 35 1 + Current sample, line, band is: 93 36 1 + Current sample, line, band is: 93 37 1 + Current sample, line, band is: 93 38 1 + Current sample, line, band is: 93 39 1 + Current sample, line, band is: 93 40 1 + Current sample, line, band is: 93 41 1 + Current sample, line, band is: 93 42 1 + Current sample, line, band is: 93 43 1 + Current sample, line, band is: 93 44 1 + Current sample, line, band is: 93 45 1 + Current sample, line, band is: 93 46 1 + Current sample, line, band is: 93 47 1 + Current sample, line, band is: 93 48 1 + Current sample, line, band is: 93 49 1 + Current sample, line, band is: 93 50 1 + Current sample, line, band is: 93 51 1 + Current sample, line, band is: 93 52 1 + Current sample, line, band is: 93 53 1 + Current sample, line, band is: 93 54 1 + Current sample, line, band is: 93 55 1 + Current sample, line, band is: 93 56 1 + Current sample, line, band is: 93 57 1 + Current sample, line, band is: 93 58 1 + Current sample, line, band is: 93 59 1 + Current sample, line, band is: 93 60 1 + Current sample, line, band is: 93 61 1 + Current sample, line, band is: 93 62 1 + Current sample, line, band is: 93 63 1 + Current sample, line, band is: 93 64 1 + Current sample, line, band is: 93 65 1 + Current sample, line, band is: 93 66 1 + Current sample, line, band is: 93 67 1 + Current sample, line, band is: 93 68 1 + Current sample, line, band is: 93 69 1 + Current sample, line, band is: 93 70 1 + Current sample, line, band is: 93 71 1 + Current sample, line, band is: 93 72 1 + Current sample, line, band is: 93 73 1 + Current sample, line, band is: 93 74 1 + Current sample, line, band is: 93 75 1 + Current sample, line, band is: 93 76 1 + Current sample, line, band is: 93 77 1 + Current sample, line, band is: 93 78 1 + Current sample, line, band is: 93 79 1 + Current sample, line, band is: 93 80 1 + Current sample, line, band is: 93 81 1 + Current sample, line, band is: 93 82 1 + Current sample, line, band is: 93 83 1 + Current sample, line, band is: 93 84 1 + Current sample, line, band is: 93 85 1 + Current sample, line, band is: 93 86 1 + Current sample, line, band is: 93 87 1 + Current sample, line, band is: 93 88 1 + Current sample, line, band is: 93 89 1 + Current sample, line, band is: 93 90 1 + Current sample, line, band is: 93 91 1 + Current sample, line, band is: 93 92 1 + Current sample, line, band is: 93 93 1 + Current sample, line, band is: 93 94 1 + Current sample, line, band is: 93 95 1 + Current sample, line, band is: 93 96 1 + Current sample, line, band is: 93 97 1 + Current sample, line, band is: 93 98 1 + Current sample, line, band is: 93 99 1 + Current sample, line, band is: 93 100 1 + Current sample, line, band is: 93 101 1 + Current sample, line, band is: 93 102 1 + Current sample, line, band is: 93 103 1 + Current sample, line, band is: 93 104 1 + Current sample, line, band is: 93 105 1 + Current sample, line, band is: 93 106 1 + Current sample, line, band is: 93 107 1 + Current sample, line, band is: 93 108 1 + Current sample, line, band is: 93 109 1 + Current sample, line, band is: 93 110 1 + Current sample, line, band is: 93 111 1 + Current sample, line, band is: 93 112 1 + Current sample, line, band is: 93 113 1 + Current sample, line, band is: 93 114 1 + Current sample, line, band is: 93 115 1 + Current sample, line, band is: 93 116 1 + Current sample, line, band is: 93 117 1 + Current sample, line, band is: 93 118 1 + Current sample, line, band is: 93 119 1 + Current sample, line, band is: 93 120 1 + Current sample, line, band is: 93 121 1 + Current sample, line, band is: 93 122 1 + Current sample, line, band is: 93 123 1 + Current sample, line, band is: 93 124 1 + Current sample, line, band is: 93 125 1 + Current sample, line, band is: 93 126 1 + Current sample, line, band is: 94 1 1 + Current sample, line, band is: 94 2 1 + Current sample, line, band is: 94 3 1 + Current sample, line, band is: 94 4 1 + Current sample, line, band is: 94 5 1 + Current sample, line, band is: 94 6 1 + Current sample, line, band is: 94 7 1 + Current sample, line, band is: 94 8 1 + Current sample, line, band is: 94 9 1 + Current sample, line, band is: 94 10 1 + Current sample, line, band is: 94 11 1 + Current sample, line, band is: 94 12 1 + Current sample, line, band is: 94 13 1 + Current sample, line, band is: 94 14 1 + Current sample, line, band is: 94 15 1 + Current sample, line, band is: 94 16 1 + Current sample, line, band is: 94 17 1 + Current sample, line, band is: 94 18 1 + Current sample, line, band is: 94 19 1 + Current sample, line, band is: 94 20 1 + Current sample, line, band is: 94 21 1 + Current sample, line, band is: 94 22 1 + Current sample, line, band is: 94 23 1 + Current sample, line, band is: 94 24 1 + Current sample, line, band is: 94 25 1 + Current sample, line, band is: 94 26 1 + Current sample, line, band is: 94 27 1 + Current sample, line, band is: 94 28 1 + Current sample, line, band is: 94 29 1 + Current sample, line, band is: 94 30 1 + Current sample, line, band is: 94 31 1 + Current sample, line, band is: 94 32 1 + Current sample, line, band is: 94 33 1 + Current sample, line, band is: 94 34 1 + Current sample, line, band is: 94 35 1 + Current sample, line, band is: 94 36 1 + Current sample, line, band is: 94 37 1 + Current sample, line, band is: 94 38 1 + Current sample, line, band is: 94 39 1 + Current sample, line, band is: 94 40 1 + Current sample, line, band is: 94 41 1 + Current sample, line, band is: 94 42 1 + Current sample, line, band is: 94 43 1 + Current sample, line, band is: 94 44 1 + Current sample, line, band is: 94 45 1 + Current sample, line, band is: 94 46 1 + Current sample, line, band is: 94 47 1 + Current sample, line, band is: 94 48 1 + Current sample, line, band is: 94 49 1 + Current sample, line, band is: 94 50 1 + Current sample, line, band is: 94 51 1 + Current sample, line, band is: 94 52 1 + Current sample, line, band is: 94 53 1 + Current sample, line, band is: 94 54 1 + Current sample, line, band is: 94 55 1 + Current sample, line, band is: 94 56 1 + Current sample, line, band is: 94 57 1 + Current sample, line, band is: 94 58 1 + Current sample, line, band is: 94 59 1 + Current sample, line, band is: 94 60 1 + Current sample, line, band is: 94 61 1 + Current sample, line, band is: 94 62 1 + Current sample, line, band is: 94 63 1 + Current sample, line, band is: 94 64 1 + Current sample, line, band is: 94 65 1 + Current sample, line, band is: 94 66 1 + Current sample, line, band is: 94 67 1 + Current sample, line, band is: 94 68 1 + Current sample, line, band is: 94 69 1 + Current sample, line, band is: 94 70 1 + Current sample, line, band is: 94 71 1 + Current sample, line, band is: 94 72 1 + Current sample, line, band is: 94 73 1 + Current sample, line, band is: 94 74 1 + Current sample, line, band is: 94 75 1 + Current sample, line, band is: 94 76 1 + Current sample, line, band is: 94 77 1 + Current sample, line, band is: 94 78 1 + Current sample, line, band is: 94 79 1 + Current sample, line, band is: 94 80 1 + Current sample, line, band is: 94 81 1 + Current sample, line, band is: 94 82 1 + Current sample, line, band is: 94 83 1 + Current sample, line, band is: 94 84 1 + Current sample, line, band is: 94 85 1 + Current sample, line, band is: 94 86 1 + Current sample, line, band is: 94 87 1 + Current sample, line, band is: 94 88 1 + Current sample, line, band is: 94 89 1 + Current sample, line, band is: 94 90 1 + Current sample, line, band is: 94 91 1 + Current sample, line, band is: 94 92 1 + Current sample, line, band is: 94 93 1 + Current sample, line, band is: 94 94 1 + Current sample, line, band is: 94 95 1 + Current sample, line, band is: 94 96 1 + Current sample, line, band is: 94 97 1 + Current sample, line, band is: 94 98 1 + Current sample, line, band is: 94 99 1 + Current sample, line, band is: 94 100 1 + Current sample, line, band is: 94 101 1 + Current sample, line, band is: 94 102 1 + Current sample, line, band is: 94 103 1 + Current sample, line, band is: 94 104 1 + Current sample, line, band is: 94 105 1 + Current sample, line, band is: 94 106 1 + Current sample, line, band is: 94 107 1 + Current sample, line, band is: 94 108 1 + Current sample, line, band is: 94 109 1 + Current sample, line, band is: 94 110 1 + Current sample, line, band is: 94 111 1 + Current sample, line, band is: 94 112 1 + Current sample, line, band is: 94 113 1 + Current sample, line, band is: 94 114 1 + Current sample, line, band is: 94 115 1 + Current sample, line, band is: 94 116 1 + Current sample, line, band is: 94 117 1 + Current sample, line, band is: 94 118 1 + Current sample, line, band is: 94 119 1 + Current sample, line, band is: 94 120 1 + Current sample, line, band is: 94 121 1 + Current sample, line, band is: 94 122 1 + Current sample, line, band is: 94 123 1 + Current sample, line, band is: 94 124 1 + Current sample, line, band is: 94 125 1 + Current sample, line, band is: 94 126 1 + Current sample, line, band is: 95 1 1 + Current sample, line, band is: 95 2 1 + Current sample, line, band is: 95 3 1 + Current sample, line, band is: 95 4 1 + Current sample, line, band is: 95 5 1 + Current sample, line, band is: 95 6 1 + Current sample, line, band is: 95 7 1 + Current sample, line, band is: 95 8 1 + Current sample, line, band is: 95 9 1 + Current sample, line, band is: 95 10 1 + Current sample, line, band is: 95 11 1 + Current sample, line, band is: 95 12 1 + Current sample, line, band is: 95 13 1 + Current sample, line, band is: 95 14 1 + Current sample, line, band is: 95 15 1 + Current sample, line, band is: 95 16 1 + Current sample, line, band is: 95 17 1 + Current sample, line, band is: 95 18 1 + Current sample, line, band is: 95 19 1 + Current sample, line, band is: 95 20 1 + Current sample, line, band is: 95 21 1 + Current sample, line, band is: 95 22 1 + Current sample, line, band is: 95 23 1 + Current sample, line, band is: 95 24 1 + Current sample, line, band is: 95 25 1 + Current sample, line, band is: 95 26 1 + Current sample, line, band is: 95 27 1 + Current sample, line, band is: 95 28 1 + Current sample, line, band is: 95 29 1 + Current sample, line, band is: 95 30 1 + Current sample, line, band is: 95 31 1 + Current sample, line, band is: 95 32 1 + Current sample, line, band is: 95 33 1 + Current sample, line, band is: 95 34 1 + Current sample, line, band is: 95 35 1 + Current sample, line, band is: 95 36 1 + Current sample, line, band is: 95 37 1 + Current sample, line, band is: 95 38 1 + Current sample, line, band is: 95 39 1 + Current sample, line, band is: 95 40 1 + Current sample, line, band is: 95 41 1 + Current sample, line, band is: 95 42 1 + Current sample, line, band is: 95 43 1 + Current sample, line, band is: 95 44 1 + Current sample, line, band is: 95 45 1 + Current sample, line, band is: 95 46 1 + Current sample, line, band is: 95 47 1 + Current sample, line, band is: 95 48 1 + Current sample, line, band is: 95 49 1 + Current sample, line, band is: 95 50 1 + Current sample, line, band is: 95 51 1 + Current sample, line, band is: 95 52 1 + Current sample, line, band is: 95 53 1 + Current sample, line, band is: 95 54 1 + Current sample, line, band is: 95 55 1 + Current sample, line, band is: 95 56 1 + Current sample, line, band is: 95 57 1 + Current sample, line, band is: 95 58 1 + Current sample, line, band is: 95 59 1 + Current sample, line, band is: 95 60 1 + Current sample, line, band is: 95 61 1 + Current sample, line, band is: 95 62 1 + Current sample, line, band is: 95 63 1 + Current sample, line, band is: 95 64 1 + Current sample, line, band is: 95 65 1 + Current sample, line, band is: 95 66 1 + Current sample, line, band is: 95 67 1 + Current sample, line, band is: 95 68 1 + Current sample, line, band is: 95 69 1 + Current sample, line, band is: 95 70 1 + Current sample, line, band is: 95 71 1 + Current sample, line, band is: 95 72 1 + Current sample, line, band is: 95 73 1 + Current sample, line, band is: 95 74 1 + Current sample, line, band is: 95 75 1 + Current sample, line, band is: 95 76 1 + Current sample, line, band is: 95 77 1 + Current sample, line, band is: 95 78 1 + Current sample, line, band is: 95 79 1 + Current sample, line, band is: 95 80 1 + Current sample, line, band is: 95 81 1 + Current sample, line, band is: 95 82 1 + Current sample, line, band is: 95 83 1 + Current sample, line, band is: 95 84 1 + Current sample, line, band is: 95 85 1 + Current sample, line, band is: 95 86 1 + Current sample, line, band is: 95 87 1 + Current sample, line, band is: 95 88 1 + Current sample, line, band is: 95 89 1 + Current sample, line, band is: 95 90 1 + Current sample, line, band is: 95 91 1 + Current sample, line, band is: 95 92 1 + Current sample, line, band is: 95 93 1 + Current sample, line, band is: 95 94 1 + Current sample, line, band is: 95 95 1 + Current sample, line, band is: 95 96 1 + Current sample, line, band is: 95 97 1 + Current sample, line, band is: 95 98 1 + Current sample, line, band is: 95 99 1 + Current sample, line, band is: 95 100 1 + Current sample, line, band is: 95 101 1 + Current sample, line, band is: 95 102 1 + Current sample, line, band is: 95 103 1 + Current sample, line, band is: 95 104 1 + Current sample, line, band is: 95 105 1 + Current sample, line, band is: 95 106 1 + Current sample, line, band is: 95 107 1 + Current sample, line, band is: 95 108 1 + Current sample, line, band is: 95 109 1 + Current sample, line, band is: 95 110 1 + Current sample, line, band is: 95 111 1 + Current sample, line, band is: 95 112 1 + Current sample, line, band is: 95 113 1 + Current sample, line, band is: 95 114 1 + Current sample, line, band is: 95 115 1 + Current sample, line, band is: 95 116 1 + Current sample, line, band is: 95 117 1 + Current sample, line, band is: 95 118 1 + Current sample, line, band is: 95 119 1 + Current sample, line, band is: 95 120 1 + Current sample, line, band is: 95 121 1 + Current sample, line, band is: 95 122 1 + Current sample, line, band is: 95 123 1 + Current sample, line, band is: 95 124 1 + Current sample, line, band is: 95 125 1 + Current sample, line, band is: 95 126 1 + Current sample, line, band is: 96 1 1 + Current sample, line, band is: 96 2 1 + Current sample, line, band is: 96 3 1 + Current sample, line, band is: 96 4 1 + Current sample, line, band is: 96 5 1 + Current sample, line, band is: 96 6 1 + Current sample, line, band is: 96 7 1 + Current sample, line, band is: 96 8 1 + Current sample, line, band is: 96 9 1 + Current sample, line, band is: 96 10 1 + Current sample, line, band is: 96 11 1 + Current sample, line, band is: 96 12 1 + Current sample, line, band is: 96 13 1 + Current sample, line, band is: 96 14 1 + Current sample, line, band is: 96 15 1 + Current sample, line, band is: 96 16 1 + Current sample, line, band is: 96 17 1 + Current sample, line, band is: 96 18 1 + Current sample, line, band is: 96 19 1 + Current sample, line, band is: 96 20 1 + Current sample, line, band is: 96 21 1 + Current sample, line, band is: 96 22 1 + Current sample, line, band is: 96 23 1 + Current sample, line, band is: 96 24 1 + Current sample, line, band is: 96 25 1 + Current sample, line, band is: 96 26 1 + Current sample, line, band is: 96 27 1 + Current sample, line, band is: 96 28 1 + Current sample, line, band is: 96 29 1 + Current sample, line, band is: 96 30 1 + Current sample, line, band is: 96 31 1 + Current sample, line, band is: 96 32 1 + Current sample, line, band is: 96 33 1 + Current sample, line, band is: 96 34 1 + Current sample, line, band is: 96 35 1 + Current sample, line, band is: 96 36 1 + Current sample, line, band is: 96 37 1 + Current sample, line, band is: 96 38 1 + Current sample, line, band is: 96 39 1 + Current sample, line, band is: 96 40 1 + Current sample, line, band is: 96 41 1 + Current sample, line, band is: 96 42 1 + Current sample, line, band is: 96 43 1 + Current sample, line, band is: 96 44 1 + Current sample, line, band is: 96 45 1 + Current sample, line, band is: 96 46 1 + Current sample, line, band is: 96 47 1 + Current sample, line, band is: 96 48 1 + Current sample, line, band is: 96 49 1 + Current sample, line, band is: 96 50 1 + Current sample, line, band is: 96 51 1 + Current sample, line, band is: 96 52 1 + Current sample, line, band is: 96 53 1 + Current sample, line, band is: 96 54 1 + Current sample, line, band is: 96 55 1 + Current sample, line, band is: 96 56 1 + Current sample, line, band is: 96 57 1 + Current sample, line, band is: 96 58 1 + Current sample, line, band is: 96 59 1 + Current sample, line, band is: 96 60 1 + Current sample, line, band is: 96 61 1 + Current sample, line, band is: 96 62 1 + Current sample, line, band is: 96 63 1 + Current sample, line, band is: 96 64 1 + Current sample, line, band is: 96 65 1 + Current sample, line, band is: 96 66 1 + Current sample, line, band is: 96 67 1 + Current sample, line, band is: 96 68 1 + Current sample, line, band is: 96 69 1 + Current sample, line, band is: 96 70 1 + Current sample, line, band is: 96 71 1 + Current sample, line, band is: 96 72 1 + Current sample, line, band is: 96 73 1 + Current sample, line, band is: 96 74 1 + Current sample, line, band is: 96 75 1 + Current sample, line, band is: 96 76 1 + Current sample, line, band is: 96 77 1 + Current sample, line, band is: 96 78 1 + Current sample, line, band is: 96 79 1 + Current sample, line, band is: 96 80 1 + Current sample, line, band is: 96 81 1 + Current sample, line, band is: 96 82 1 + Current sample, line, band is: 96 83 1 + Current sample, line, band is: 96 84 1 + Current sample, line, band is: 96 85 1 + Current sample, line, band is: 96 86 1 + Current sample, line, band is: 96 87 1 + Current sample, line, band is: 96 88 1 + Current sample, line, band is: 96 89 1 + Current sample, line, band is: 96 90 1 + Current sample, line, band is: 96 91 1 + Current sample, line, band is: 96 92 1 + Current sample, line, band is: 96 93 1 + Current sample, line, band is: 96 94 1 + Current sample, line, band is: 96 95 1 + Current sample, line, band is: 96 96 1 + Current sample, line, band is: 96 97 1 + Current sample, line, band is: 96 98 1 + Current sample, line, band is: 96 99 1 + Current sample, line, band is: 96 100 1 + Current sample, line, band is: 96 101 1 + Current sample, line, band is: 96 102 1 + Current sample, line, band is: 96 103 1 + Current sample, line, band is: 96 104 1 + Current sample, line, band is: 96 105 1 + Current sample, line, band is: 96 106 1 + Current sample, line, band is: 96 107 1 + Current sample, line, band is: 96 108 1 + Current sample, line, band is: 96 109 1 + Current sample, line, band is: 96 110 1 + Current sample, line, band is: 96 111 1 + Current sample, line, band is: 96 112 1 + Current sample, line, band is: 96 113 1 + Current sample, line, band is: 96 114 1 + Current sample, line, band is: 96 115 1 + Current sample, line, band is: 96 116 1 + Current sample, line, band is: 96 117 1 + Current sample, line, band is: 96 118 1 + Current sample, line, band is: 96 119 1 + Current sample, line, band is: 96 120 1 + Current sample, line, band is: 96 121 1 + Current sample, line, band is: 96 122 1 + Current sample, line, band is: 96 123 1 + Current sample, line, band is: 96 124 1 + Current sample, line, band is: 96 125 1 + Current sample, line, band is: 96 126 1 + Current sample, line, band is: 97 1 1 + Current sample, line, band is: 97 2 1 + Current sample, line, band is: 97 3 1 + Current sample, line, band is: 97 4 1 + Current sample, line, band is: 97 5 1 + Current sample, line, band is: 97 6 1 + Current sample, line, band is: 97 7 1 + Current sample, line, band is: 97 8 1 + Current sample, line, band is: 97 9 1 + Current sample, line, band is: 97 10 1 + Current sample, line, band is: 97 11 1 + Current sample, line, band is: 97 12 1 + Current sample, line, band is: 97 13 1 + Current sample, line, band is: 97 14 1 + Current sample, line, band is: 97 15 1 + Current sample, line, band is: 97 16 1 + Current sample, line, band is: 97 17 1 + Current sample, line, band is: 97 18 1 + Current sample, line, band is: 97 19 1 + Current sample, line, band is: 97 20 1 + Current sample, line, band is: 97 21 1 + Current sample, line, band is: 97 22 1 + Current sample, line, band is: 97 23 1 + Current sample, line, band is: 97 24 1 + Current sample, line, band is: 97 25 1 + Current sample, line, band is: 97 26 1 + Current sample, line, band is: 97 27 1 + Current sample, line, band is: 97 28 1 + Current sample, line, band is: 97 29 1 + Current sample, line, band is: 97 30 1 + Current sample, line, band is: 97 31 1 + Current sample, line, band is: 97 32 1 + Current sample, line, band is: 97 33 1 + Current sample, line, band is: 97 34 1 + Current sample, line, band is: 97 35 1 + Current sample, line, band is: 97 36 1 + Current sample, line, band is: 97 37 1 + Current sample, line, band is: 97 38 1 + Current sample, line, band is: 97 39 1 + Current sample, line, band is: 97 40 1 + Current sample, line, band is: 97 41 1 + Current sample, line, band is: 97 42 1 + Current sample, line, band is: 97 43 1 + Current sample, line, band is: 97 44 1 + Current sample, line, band is: 97 45 1 + Current sample, line, band is: 97 46 1 + Current sample, line, band is: 97 47 1 + Current sample, line, band is: 97 48 1 + Current sample, line, band is: 97 49 1 + Current sample, line, band is: 97 50 1 + Current sample, line, band is: 97 51 1 + Current sample, line, band is: 97 52 1 + Current sample, line, band is: 97 53 1 + Current sample, line, band is: 97 54 1 + Current sample, line, band is: 97 55 1 + Current sample, line, band is: 97 56 1 + Current sample, line, band is: 97 57 1 + Current sample, line, band is: 97 58 1 + Current sample, line, band is: 97 59 1 + Current sample, line, band is: 97 60 1 + Current sample, line, band is: 97 61 1 + Current sample, line, band is: 97 62 1 + Current sample, line, band is: 97 63 1 + Current sample, line, band is: 97 64 1 + Current sample, line, band is: 97 65 1 + Current sample, line, band is: 97 66 1 + Current sample, line, band is: 97 67 1 + Current sample, line, band is: 97 68 1 + Current sample, line, band is: 97 69 1 + Current sample, line, band is: 97 70 1 + Current sample, line, band is: 97 71 1 + Current sample, line, band is: 97 72 1 + Current sample, line, band is: 97 73 1 + Current sample, line, band is: 97 74 1 + Current sample, line, band is: 97 75 1 + Current sample, line, band is: 97 76 1 + Current sample, line, band is: 97 77 1 + Current sample, line, band is: 97 78 1 + Current sample, line, band is: 97 79 1 + Current sample, line, band is: 97 80 1 + Current sample, line, band is: 97 81 1 + Current sample, line, band is: 97 82 1 + Current sample, line, band is: 97 83 1 + Current sample, line, band is: 97 84 1 + Current sample, line, band is: 97 85 1 + Current sample, line, band is: 97 86 1 + Current sample, line, band is: 97 87 1 + Current sample, line, band is: 97 88 1 + Current sample, line, band is: 97 89 1 + Current sample, line, band is: 97 90 1 + Current sample, line, band is: 97 91 1 + Current sample, line, band is: 97 92 1 + Current sample, line, band is: 97 93 1 + Current sample, line, band is: 97 94 1 + Current sample, line, band is: 97 95 1 + Current sample, line, band is: 97 96 1 + Current sample, line, band is: 97 97 1 + Current sample, line, band is: 97 98 1 + Current sample, line, band is: 97 99 1 + Current sample, line, band is: 97 100 1 + Current sample, line, band is: 97 101 1 + Current sample, line, band is: 97 102 1 + Current sample, line, band is: 97 103 1 + Current sample, line, band is: 97 104 1 + Current sample, line, band is: 97 105 1 + Current sample, line, band is: 97 106 1 + Current sample, line, band is: 97 107 1 + Current sample, line, band is: 97 108 1 + Current sample, line, band is: 97 109 1 + Current sample, line, band is: 97 110 1 + Current sample, line, band is: 97 111 1 + Current sample, line, band is: 97 112 1 + Current sample, line, band is: 97 113 1 + Current sample, line, band is: 97 114 1 + Current sample, line, band is: 97 115 1 + Current sample, line, band is: 97 116 1 + Current sample, line, band is: 97 117 1 + Current sample, line, band is: 97 118 1 + Current sample, line, band is: 97 119 1 + Current sample, line, band is: 97 120 1 + Current sample, line, band is: 97 121 1 + Current sample, line, band is: 97 122 1 + Current sample, line, band is: 97 123 1 + Current sample, line, band is: 97 124 1 + Current sample, line, band is: 97 125 1 + Current sample, line, band is: 97 126 1 + Current sample, line, band is: 98 1 1 + Current sample, line, band is: 98 2 1 + Current sample, line, band is: 98 3 1 + Current sample, line, band is: 98 4 1 + Current sample, line, band is: 98 5 1 + Current sample, line, band is: 98 6 1 + Current sample, line, band is: 98 7 1 + Current sample, line, band is: 98 8 1 + Current sample, line, band is: 98 9 1 + Current sample, line, band is: 98 10 1 + Current sample, line, band is: 98 11 1 + Current sample, line, band is: 98 12 1 + Current sample, line, band is: 98 13 1 + Current sample, line, band is: 98 14 1 + Current sample, line, band is: 98 15 1 + Current sample, line, band is: 98 16 1 + Current sample, line, band is: 98 17 1 + Current sample, line, band is: 98 18 1 + Current sample, line, band is: 98 19 1 + Current sample, line, band is: 98 20 1 + Current sample, line, band is: 98 21 1 + Current sample, line, band is: 98 22 1 + Current sample, line, band is: 98 23 1 + Current sample, line, band is: 98 24 1 + Current sample, line, band is: 98 25 1 + Current sample, line, band is: 98 26 1 + Current sample, line, band is: 98 27 1 + Current sample, line, band is: 98 28 1 + Current sample, line, band is: 98 29 1 + Current sample, line, band is: 98 30 1 + Current sample, line, band is: 98 31 1 + Current sample, line, band is: 98 32 1 + Current sample, line, band is: 98 33 1 + Current sample, line, band is: 98 34 1 + Current sample, line, band is: 98 35 1 + Current sample, line, band is: 98 36 1 + Current sample, line, band is: 98 37 1 + Current sample, line, band is: 98 38 1 + Current sample, line, band is: 98 39 1 + Current sample, line, band is: 98 40 1 + Current sample, line, band is: 98 41 1 + Current sample, line, band is: 98 42 1 + Current sample, line, band is: 98 43 1 + Current sample, line, band is: 98 44 1 + Current sample, line, band is: 98 45 1 + Current sample, line, band is: 98 46 1 + Current sample, line, band is: 98 47 1 + Current sample, line, band is: 98 48 1 + Current sample, line, band is: 98 49 1 + Current sample, line, band is: 98 50 1 + Current sample, line, band is: 98 51 1 + Current sample, line, band is: 98 52 1 + Current sample, line, band is: 98 53 1 + Current sample, line, band is: 98 54 1 + Current sample, line, band is: 98 55 1 + Current sample, line, band is: 98 56 1 + Current sample, line, band is: 98 57 1 + Current sample, line, band is: 98 58 1 + Current sample, line, band is: 98 59 1 + Current sample, line, band is: 98 60 1 + Current sample, line, band is: 98 61 1 + Current sample, line, band is: 98 62 1 + Current sample, line, band is: 98 63 1 + Current sample, line, band is: 98 64 1 + Current sample, line, band is: 98 65 1 + Current sample, line, band is: 98 66 1 + Current sample, line, band is: 98 67 1 + Current sample, line, band is: 98 68 1 + Current sample, line, band is: 98 69 1 + Current sample, line, band is: 98 70 1 + Current sample, line, band is: 98 71 1 + Current sample, line, band is: 98 72 1 + Current sample, line, band is: 98 73 1 + Current sample, line, band is: 98 74 1 + Current sample, line, band is: 98 75 1 + Current sample, line, band is: 98 76 1 + Current sample, line, band is: 98 77 1 + Current sample, line, band is: 98 78 1 + Current sample, line, band is: 98 79 1 + Current sample, line, band is: 98 80 1 + Current sample, line, band is: 98 81 1 + Current sample, line, band is: 98 82 1 + Current sample, line, band is: 98 83 1 + Current sample, line, band is: 98 84 1 + Current sample, line, band is: 98 85 1 + Current sample, line, band is: 98 86 1 + Current sample, line, band is: 98 87 1 + Current sample, line, band is: 98 88 1 + Current sample, line, band is: 98 89 1 + Current sample, line, band is: 98 90 1 + Current sample, line, band is: 98 91 1 + Current sample, line, band is: 98 92 1 + Current sample, line, band is: 98 93 1 + Current sample, line, band is: 98 94 1 + Current sample, line, band is: 98 95 1 + Current sample, line, band is: 98 96 1 + Current sample, line, band is: 98 97 1 + Current sample, line, band is: 98 98 1 + Current sample, line, band is: 98 99 1 + Current sample, line, band is: 98 100 1 + Current sample, line, band is: 98 101 1 + Current sample, line, band is: 98 102 1 + Current sample, line, band is: 98 103 1 + Current sample, line, band is: 98 104 1 + Current sample, line, band is: 98 105 1 + Current sample, line, band is: 98 106 1 + Current sample, line, band is: 98 107 1 + Current sample, line, band is: 98 108 1 + Current sample, line, band is: 98 109 1 + Current sample, line, band is: 98 110 1 + Current sample, line, band is: 98 111 1 + Current sample, line, band is: 98 112 1 + Current sample, line, band is: 98 113 1 + Current sample, line, band is: 98 114 1 + Current sample, line, band is: 98 115 1 + Current sample, line, band is: 98 116 1 + Current sample, line, band is: 98 117 1 + Current sample, line, band is: 98 118 1 + Current sample, line, band is: 98 119 1 + Current sample, line, band is: 98 120 1 + Current sample, line, band is: 98 121 1 + Current sample, line, band is: 98 122 1 + Current sample, line, band is: 98 123 1 + Current sample, line, band is: 98 124 1 + Current sample, line, band is: 98 125 1 + Current sample, line, band is: 98 126 1 + Current sample, line, band is: 99 1 1 + Current sample, line, band is: 99 2 1 + Current sample, line, band is: 99 3 1 + Current sample, line, band is: 99 4 1 + Current sample, line, band is: 99 5 1 + Current sample, line, band is: 99 6 1 + Current sample, line, band is: 99 7 1 + Current sample, line, band is: 99 8 1 + Current sample, line, band is: 99 9 1 + Current sample, line, band is: 99 10 1 + Current sample, line, band is: 99 11 1 + Current sample, line, band is: 99 12 1 + Current sample, line, band is: 99 13 1 + Current sample, line, band is: 99 14 1 + Current sample, line, band is: 99 15 1 + Current sample, line, band is: 99 16 1 + Current sample, line, band is: 99 17 1 + Current sample, line, band is: 99 18 1 + Current sample, line, band is: 99 19 1 + Current sample, line, band is: 99 20 1 + Current sample, line, band is: 99 21 1 + Current sample, line, band is: 99 22 1 + Current sample, line, band is: 99 23 1 + Current sample, line, band is: 99 24 1 + Current sample, line, band is: 99 25 1 + Current sample, line, band is: 99 26 1 + Current sample, line, band is: 99 27 1 + Current sample, line, band is: 99 28 1 + Current sample, line, band is: 99 29 1 + Current sample, line, band is: 99 30 1 + Current sample, line, band is: 99 31 1 + Current sample, line, band is: 99 32 1 + Current sample, line, band is: 99 33 1 + Current sample, line, band is: 99 34 1 + Current sample, line, band is: 99 35 1 + Current sample, line, band is: 99 36 1 + Current sample, line, band is: 99 37 1 + Current sample, line, band is: 99 38 1 + Current sample, line, band is: 99 39 1 + Current sample, line, band is: 99 40 1 + Current sample, line, band is: 99 41 1 + Current sample, line, band is: 99 42 1 + Current sample, line, band is: 99 43 1 + Current sample, line, band is: 99 44 1 + Current sample, line, band is: 99 45 1 + Current sample, line, band is: 99 46 1 + Current sample, line, band is: 99 47 1 + Current sample, line, band is: 99 48 1 + Current sample, line, band is: 99 49 1 + Current sample, line, band is: 99 50 1 + Current sample, line, band is: 99 51 1 + Current sample, line, band is: 99 52 1 + Current sample, line, band is: 99 53 1 + Current sample, line, band is: 99 54 1 + Current sample, line, band is: 99 55 1 + Current sample, line, band is: 99 56 1 + Current sample, line, band is: 99 57 1 + Current sample, line, band is: 99 58 1 + Current sample, line, band is: 99 59 1 + Current sample, line, band is: 99 60 1 + Current sample, line, band is: 99 61 1 + Current sample, line, band is: 99 62 1 + Current sample, line, band is: 99 63 1 + Current sample, line, band is: 99 64 1 + Current sample, line, band is: 99 65 1 + Current sample, line, band is: 99 66 1 + Current sample, line, band is: 99 67 1 + Current sample, line, band is: 99 68 1 + Current sample, line, band is: 99 69 1 + Current sample, line, band is: 99 70 1 + Current sample, line, band is: 99 71 1 + Current sample, line, band is: 99 72 1 + Current sample, line, band is: 99 73 1 + Current sample, line, band is: 99 74 1 + Current sample, line, band is: 99 75 1 + Current sample, line, band is: 99 76 1 + Current sample, line, band is: 99 77 1 + Current sample, line, band is: 99 78 1 + Current sample, line, band is: 99 79 1 + Current sample, line, band is: 99 80 1 + Current sample, line, band is: 99 81 1 + Current sample, line, band is: 99 82 1 + Current sample, line, band is: 99 83 1 + Current sample, line, band is: 99 84 1 + Current sample, line, band is: 99 85 1 + Current sample, line, band is: 99 86 1 + Current sample, line, band is: 99 87 1 + Current sample, line, band is: 99 88 1 + Current sample, line, band is: 99 89 1 + Current sample, line, band is: 99 90 1 + Current sample, line, band is: 99 91 1 + Current sample, line, band is: 99 92 1 + Current sample, line, band is: 99 93 1 + Current sample, line, band is: 99 94 1 + Current sample, line, band is: 99 95 1 + Current sample, line, band is: 99 96 1 + Current sample, line, band is: 99 97 1 + Current sample, line, band is: 99 98 1 + Current sample, line, band is: 99 99 1 + Current sample, line, band is: 99 100 1 + Current sample, line, band is: 99 101 1 + Current sample, line, band is: 99 102 1 + Current sample, line, band is: 99 103 1 + Current sample, line, band is: 99 104 1 + Current sample, line, band is: 99 105 1 + Current sample, line, band is: 99 106 1 + Current sample, line, band is: 99 107 1 + Current sample, line, band is: 99 108 1 + Current sample, line, band is: 99 109 1 + Current sample, line, band is: 99 110 1 + Current sample, line, band is: 99 111 1 + Current sample, line, band is: 99 112 1 + Current sample, line, band is: 99 113 1 + Current sample, line, band is: 99 114 1 + Current sample, line, band is: 99 115 1 + Current sample, line, band is: 99 116 1 + Current sample, line, band is: 99 117 1 + Current sample, line, band is: 99 118 1 + Current sample, line, band is: 99 119 1 + Current sample, line, band is: 99 120 1 + Current sample, line, band is: 99 121 1 + Current sample, line, band is: 99 122 1 + Current sample, line, band is: 99 123 1 + Current sample, line, band is: 99 124 1 + Current sample, line, band is: 99 125 1 + Current sample, line, band is: 99 126 1 + Current sample, line, band is: 100 1 1 + Current sample, line, band is: 100 2 1 + Current sample, line, band is: 100 3 1 + Current sample, line, band is: 100 4 1 + Current sample, line, band is: 100 5 1 + Current sample, line, band is: 100 6 1 + Current sample, line, band is: 100 7 1 + Current sample, line, band is: 100 8 1 + Current sample, line, band is: 100 9 1 + Current sample, line, band is: 100 10 1 + Current sample, line, band is: 100 11 1 + Current sample, line, band is: 100 12 1 + Current sample, line, band is: 100 13 1 + Current sample, line, band is: 100 14 1 + Current sample, line, band is: 100 15 1 + Current sample, line, band is: 100 16 1 + Current sample, line, band is: 100 17 1 + Current sample, line, band is: 100 18 1 + Current sample, line, band is: 100 19 1 + Current sample, line, band is: 100 20 1 + Current sample, line, band is: 100 21 1 + Current sample, line, band is: 100 22 1 + Current sample, line, band is: 100 23 1 + Current sample, line, band is: 100 24 1 + Current sample, line, band is: 100 25 1 + Current sample, line, band is: 100 26 1 + Current sample, line, band is: 100 27 1 + Current sample, line, band is: 100 28 1 + Current sample, line, band is: 100 29 1 + Current sample, line, band is: 100 30 1 + Current sample, line, band is: 100 31 1 + Current sample, line, band is: 100 32 1 + Current sample, line, band is: 100 33 1 + Current sample, line, band is: 100 34 1 + Current sample, line, band is: 100 35 1 + Current sample, line, band is: 100 36 1 + Current sample, line, band is: 100 37 1 + Current sample, line, band is: 100 38 1 + Current sample, line, band is: 100 39 1 + Current sample, line, band is: 100 40 1 + Current sample, line, band is: 100 41 1 + Current sample, line, band is: 100 42 1 + Current sample, line, band is: 100 43 1 + Current sample, line, band is: 100 44 1 + Current sample, line, band is: 100 45 1 + Current sample, line, band is: 100 46 1 + Current sample, line, band is: 100 47 1 + Current sample, line, band is: 100 48 1 + Current sample, line, band is: 100 49 1 + Current sample, line, band is: 100 50 1 + Current sample, line, band is: 100 51 1 + Current sample, line, band is: 100 52 1 + Current sample, line, band is: 100 53 1 + Current sample, line, band is: 100 54 1 + Current sample, line, band is: 100 55 1 + Current sample, line, band is: 100 56 1 + Current sample, line, band is: 100 57 1 + Current sample, line, band is: 100 58 1 + Current sample, line, band is: 100 59 1 + Current sample, line, band is: 100 60 1 + Current sample, line, band is: 100 61 1 + Current sample, line, band is: 100 62 1 + Current sample, line, band is: 100 63 1 + Current sample, line, band is: 100 64 1 + Current sample, line, band is: 100 65 1 + Current sample, line, band is: 100 66 1 + Current sample, line, band is: 100 67 1 + Current sample, line, band is: 100 68 1 + Current sample, line, band is: 100 69 1 + Current sample, line, band is: 100 70 1 + Current sample, line, band is: 100 71 1 + Current sample, line, band is: 100 72 1 + Current sample, line, band is: 100 73 1 + Current sample, line, band is: 100 74 1 + Current sample, line, band is: 100 75 1 + Current sample, line, band is: 100 76 1 + Current sample, line, band is: 100 77 1 + Current sample, line, band is: 100 78 1 + Current sample, line, band is: 100 79 1 + Current sample, line, band is: 100 80 1 + Current sample, line, band is: 100 81 1 + Current sample, line, band is: 100 82 1 + Current sample, line, band is: 100 83 1 + Current sample, line, band is: 100 84 1 + Current sample, line, band is: 100 85 1 + Current sample, line, band is: 100 86 1 + Current sample, line, band is: 100 87 1 + Current sample, line, band is: 100 88 1 + Current sample, line, band is: 100 89 1 + Current sample, line, band is: 100 90 1 + Current sample, line, band is: 100 91 1 + Current sample, line, band is: 100 92 1 + Current sample, line, band is: 100 93 1 + Current sample, line, band is: 100 94 1 + Current sample, line, band is: 100 95 1 + Current sample, line, band is: 100 96 1 + Current sample, line, band is: 100 97 1 + Current sample, line, band is: 100 98 1 + Current sample, line, band is: 100 99 1 + Current sample, line, band is: 100 100 1 + Current sample, line, band is: 100 101 1 + Current sample, line, band is: 100 102 1 + Current sample, line, band is: 100 103 1 + Current sample, line, band is: 100 104 1 + Current sample, line, band is: 100 105 1 + Current sample, line, band is: 100 106 1 + Current sample, line, band is: 100 107 1 + Current sample, line, band is: 100 108 1 + Current sample, line, band is: 100 109 1 + Current sample, line, band is: 100 110 1 + Current sample, line, band is: 100 111 1 + Current sample, line, band is: 100 112 1 + Current sample, line, band is: 100 113 1 + Current sample, line, band is: 100 114 1 + Current sample, line, band is: 100 115 1 + Current sample, line, band is: 100 116 1 + Current sample, line, band is: 100 117 1 + Current sample, line, band is: 100 118 1 + Current sample, line, band is: 100 119 1 + Current sample, line, band is: 100 120 1 + Current sample, line, band is: 100 121 1 + Current sample, line, band is: 100 122 1 + Current sample, line, band is: 100 123 1 + Current sample, line, band is: 100 124 1 + Current sample, line, band is: 100 125 1 + Current sample, line, band is: 100 126 1 + Current sample, line, band is: 101 1 1 + Current sample, line, band is: 101 2 1 + Current sample, line, band is: 101 3 1 + Current sample, line, band is: 101 4 1 + Current sample, line, band is: 101 5 1 + Current sample, line, band is: 101 6 1 + Current sample, line, band is: 101 7 1 + Current sample, line, band is: 101 8 1 + Current sample, line, band is: 101 9 1 + Current sample, line, band is: 101 10 1 + Current sample, line, band is: 101 11 1 + Current sample, line, band is: 101 12 1 + Current sample, line, band is: 101 13 1 + Current sample, line, band is: 101 14 1 + Current sample, line, band is: 101 15 1 + Current sample, line, band is: 101 16 1 + Current sample, line, band is: 101 17 1 + Current sample, line, band is: 101 18 1 + Current sample, line, band is: 101 19 1 + Current sample, line, band is: 101 20 1 + Current sample, line, band is: 101 21 1 + Current sample, line, band is: 101 22 1 + Current sample, line, band is: 101 23 1 + Current sample, line, band is: 101 24 1 + Current sample, line, band is: 101 25 1 + Current sample, line, band is: 101 26 1 + Current sample, line, band is: 101 27 1 + Current sample, line, band is: 101 28 1 + Current sample, line, band is: 101 29 1 + Current sample, line, band is: 101 30 1 + Current sample, line, band is: 101 31 1 + Current sample, line, band is: 101 32 1 + Current sample, line, band is: 101 33 1 + Current sample, line, band is: 101 34 1 + Current sample, line, band is: 101 35 1 + Current sample, line, band is: 101 36 1 + Current sample, line, band is: 101 37 1 + Current sample, line, band is: 101 38 1 + Current sample, line, band is: 101 39 1 + Current sample, line, band is: 101 40 1 + Current sample, line, band is: 101 41 1 + Current sample, line, band is: 101 42 1 + Current sample, line, band is: 101 43 1 + Current sample, line, band is: 101 44 1 + Current sample, line, band is: 101 45 1 + Current sample, line, band is: 101 46 1 + Current sample, line, band is: 101 47 1 + Current sample, line, band is: 101 48 1 + Current sample, line, band is: 101 49 1 + Current sample, line, band is: 101 50 1 + Current sample, line, band is: 101 51 1 + Current sample, line, band is: 101 52 1 + Current sample, line, band is: 101 53 1 + Current sample, line, band is: 101 54 1 + Current sample, line, band is: 101 55 1 + Current sample, line, band is: 101 56 1 + Current sample, line, band is: 101 57 1 + Current sample, line, band is: 101 58 1 + Current sample, line, band is: 101 59 1 + Current sample, line, band is: 101 60 1 + Current sample, line, band is: 101 61 1 + Current sample, line, band is: 101 62 1 + Current sample, line, band is: 101 63 1 + Current sample, line, band is: 101 64 1 + Current sample, line, band is: 101 65 1 + Current sample, line, band is: 101 66 1 + Current sample, line, band is: 101 67 1 + Current sample, line, band is: 101 68 1 + Current sample, line, band is: 101 69 1 + Current sample, line, band is: 101 70 1 + Current sample, line, band is: 101 71 1 + Current sample, line, band is: 101 72 1 + Current sample, line, band is: 101 73 1 + Current sample, line, band is: 101 74 1 + Current sample, line, band is: 101 75 1 + Current sample, line, band is: 101 76 1 + Current sample, line, band is: 101 77 1 + Current sample, line, band is: 101 78 1 + Current sample, line, band is: 101 79 1 + Current sample, line, band is: 101 80 1 + Current sample, line, band is: 101 81 1 + Current sample, line, band is: 101 82 1 + Current sample, line, band is: 101 83 1 + Current sample, line, band is: 101 84 1 + Current sample, line, band is: 101 85 1 + Current sample, line, band is: 101 86 1 + Current sample, line, band is: 101 87 1 + Current sample, line, band is: 101 88 1 + Current sample, line, band is: 101 89 1 + Current sample, line, band is: 101 90 1 + Current sample, line, band is: 101 91 1 + Current sample, line, band is: 101 92 1 + Current sample, line, band is: 101 93 1 + Current sample, line, band is: 101 94 1 + Current sample, line, band is: 101 95 1 + Current sample, line, band is: 101 96 1 + Current sample, line, band is: 101 97 1 + Current sample, line, band is: 101 98 1 + Current sample, line, band is: 101 99 1 + Current sample, line, band is: 101 100 1 + Current sample, line, band is: 101 101 1 + Current sample, line, band is: 101 102 1 + Current sample, line, band is: 101 103 1 + Current sample, line, band is: 101 104 1 + Current sample, line, band is: 101 105 1 + Current sample, line, band is: 101 106 1 + Current sample, line, band is: 101 107 1 + Current sample, line, band is: 101 108 1 + Current sample, line, band is: 101 109 1 + Current sample, line, band is: 101 110 1 + Current sample, line, band is: 101 111 1 + Current sample, line, band is: 101 112 1 + Current sample, line, band is: 101 113 1 + Current sample, line, band is: 101 114 1 + Current sample, line, band is: 101 115 1 + Current sample, line, band is: 101 116 1 + Current sample, line, band is: 101 117 1 + Current sample, line, band is: 101 118 1 + Current sample, line, band is: 101 119 1 + Current sample, line, band is: 101 120 1 + Current sample, line, band is: 101 121 1 + Current sample, line, band is: 101 122 1 + Current sample, line, band is: 101 123 1 + Current sample, line, band is: 101 124 1 + Current sample, line, band is: 101 125 1 + Current sample, line, band is: 101 126 1 + Current sample, line, band is: 102 1 1 + Current sample, line, band is: 102 2 1 + Current sample, line, band is: 102 3 1 + Current sample, line, band is: 102 4 1 + Current sample, line, band is: 102 5 1 + Current sample, line, band is: 102 6 1 + Current sample, line, band is: 102 7 1 + Current sample, line, band is: 102 8 1 + Current sample, line, band is: 102 9 1 + Current sample, line, band is: 102 10 1 + Current sample, line, band is: 102 11 1 + Current sample, line, band is: 102 12 1 + Current sample, line, band is: 102 13 1 + Current sample, line, band is: 102 14 1 + Current sample, line, band is: 102 15 1 + Current sample, line, band is: 102 16 1 + Current sample, line, band is: 102 17 1 + Current sample, line, band is: 102 18 1 + Current sample, line, band is: 102 19 1 + Current sample, line, band is: 102 20 1 + Current sample, line, band is: 102 21 1 + Current sample, line, band is: 102 22 1 + Current sample, line, band is: 102 23 1 + Current sample, line, band is: 102 24 1 + Current sample, line, band is: 102 25 1 + Current sample, line, band is: 102 26 1 + Current sample, line, band is: 102 27 1 + Current sample, line, band is: 102 28 1 + Current sample, line, band is: 102 29 1 + Current sample, line, band is: 102 30 1 + Current sample, line, band is: 102 31 1 + Current sample, line, band is: 102 32 1 + Current sample, line, band is: 102 33 1 + Current sample, line, band is: 102 34 1 + Current sample, line, band is: 102 35 1 + Current sample, line, band is: 102 36 1 + Current sample, line, band is: 102 37 1 + Current sample, line, band is: 102 38 1 + Current sample, line, band is: 102 39 1 + Current sample, line, band is: 102 40 1 + Current sample, line, band is: 102 41 1 + Current sample, line, band is: 102 42 1 + Current sample, line, band is: 102 43 1 + Current sample, line, band is: 102 44 1 + Current sample, line, band is: 102 45 1 + Current sample, line, band is: 102 46 1 + Current sample, line, band is: 102 47 1 + Current sample, line, band is: 102 48 1 + Current sample, line, band is: 102 49 1 + Current sample, line, band is: 102 50 1 + Current sample, line, band is: 102 51 1 + Current sample, line, band is: 102 52 1 + Current sample, line, band is: 102 53 1 + Current sample, line, band is: 102 54 1 + Current sample, line, band is: 102 55 1 + Current sample, line, band is: 102 56 1 + Current sample, line, band is: 102 57 1 + Current sample, line, band is: 102 58 1 + Current sample, line, band is: 102 59 1 + Current sample, line, band is: 102 60 1 + Current sample, line, band is: 102 61 1 + Current sample, line, band is: 102 62 1 + Current sample, line, band is: 102 63 1 + Current sample, line, band is: 102 64 1 + Current sample, line, band is: 102 65 1 + Current sample, line, band is: 102 66 1 + Current sample, line, band is: 102 67 1 + Current sample, line, band is: 102 68 1 + Current sample, line, band is: 102 69 1 + Current sample, line, band is: 102 70 1 + Current sample, line, band is: 102 71 1 + Current sample, line, band is: 102 72 1 + Current sample, line, band is: 102 73 1 + Current sample, line, band is: 102 74 1 + Current sample, line, band is: 102 75 1 + Current sample, line, band is: 102 76 1 + Current sample, line, band is: 102 77 1 + Current sample, line, band is: 102 78 1 + Current sample, line, band is: 102 79 1 + Current sample, line, band is: 102 80 1 + Current sample, line, band is: 102 81 1 + Current sample, line, band is: 102 82 1 + Current sample, line, band is: 102 83 1 + Current sample, line, band is: 102 84 1 + Current sample, line, band is: 102 85 1 + Current sample, line, band is: 102 86 1 + Current sample, line, band is: 102 87 1 + Current sample, line, band is: 102 88 1 + Current sample, line, band is: 102 89 1 + Current sample, line, band is: 102 90 1 + Current sample, line, band is: 102 91 1 + Current sample, line, band is: 102 92 1 + Current sample, line, band is: 102 93 1 + Current sample, line, band is: 102 94 1 + Current sample, line, band is: 102 95 1 + Current sample, line, band is: 102 96 1 + Current sample, line, band is: 102 97 1 + Current sample, line, band is: 102 98 1 + Current sample, line, band is: 102 99 1 + Current sample, line, band is: 102 100 1 + Current sample, line, band is: 102 101 1 + Current sample, line, band is: 102 102 1 + Current sample, line, band is: 102 103 1 + Current sample, line, band is: 102 104 1 + Current sample, line, band is: 102 105 1 + Current sample, line, band is: 102 106 1 + Current sample, line, band is: 102 107 1 + Current sample, line, band is: 102 108 1 + Current sample, line, band is: 102 109 1 + Current sample, line, band is: 102 110 1 + Current sample, line, band is: 102 111 1 + Current sample, line, band is: 102 112 1 + Current sample, line, band is: 102 113 1 + Current sample, line, band is: 102 114 1 + Current sample, line, band is: 102 115 1 + Current sample, line, band is: 102 116 1 + Current sample, line, band is: 102 117 1 + Current sample, line, band is: 102 118 1 + Current sample, line, band is: 102 119 1 + Current sample, line, band is: 102 120 1 + Current sample, line, band is: 102 121 1 + Current sample, line, band is: 102 122 1 + Current sample, line, band is: 102 123 1 + Current sample, line, band is: 102 124 1 + Current sample, line, band is: 102 125 1 + Current sample, line, band is: 102 126 1 + Current sample, line, band is: 103 1 1 + Current sample, line, band is: 103 2 1 + Current sample, line, band is: 103 3 1 + Current sample, line, band is: 103 4 1 + Current sample, line, band is: 103 5 1 + Current sample, line, band is: 103 6 1 + Current sample, line, band is: 103 7 1 + Current sample, line, band is: 103 8 1 + Current sample, line, band is: 103 9 1 + Current sample, line, band is: 103 10 1 + Current sample, line, band is: 103 11 1 + Current sample, line, band is: 103 12 1 + Current sample, line, band is: 103 13 1 + Current sample, line, band is: 103 14 1 + Current sample, line, band is: 103 15 1 + Current sample, line, band is: 103 16 1 + Current sample, line, band is: 103 17 1 + Current sample, line, band is: 103 18 1 + Current sample, line, band is: 103 19 1 + Current sample, line, band is: 103 20 1 + Current sample, line, band is: 103 21 1 + Current sample, line, band is: 103 22 1 + Current sample, line, band is: 103 23 1 + Current sample, line, band is: 103 24 1 + Current sample, line, band is: 103 25 1 + Current sample, line, band is: 103 26 1 + Current sample, line, band is: 103 27 1 + Current sample, line, band is: 103 28 1 + Current sample, line, band is: 103 29 1 + Current sample, line, band is: 103 30 1 + Current sample, line, band is: 103 31 1 + Current sample, line, band is: 103 32 1 + Current sample, line, band is: 103 33 1 + Current sample, line, band is: 103 34 1 + Current sample, line, band is: 103 35 1 + Current sample, line, band is: 103 36 1 + Current sample, line, band is: 103 37 1 + Current sample, line, band is: 103 38 1 + Current sample, line, band is: 103 39 1 + Current sample, line, band is: 103 40 1 + Current sample, line, band is: 103 41 1 + Current sample, line, band is: 103 42 1 + Current sample, line, band is: 103 43 1 + Current sample, line, band is: 103 44 1 + Current sample, line, band is: 103 45 1 + Current sample, line, band is: 103 46 1 + Current sample, line, band is: 103 47 1 + Current sample, line, band is: 103 48 1 + Current sample, line, band is: 103 49 1 + Current sample, line, band is: 103 50 1 + Current sample, line, band is: 103 51 1 + Current sample, line, band is: 103 52 1 + Current sample, line, band is: 103 53 1 + Current sample, line, band is: 103 54 1 + Current sample, line, band is: 103 55 1 + Current sample, line, band is: 103 56 1 + Current sample, line, band is: 103 57 1 + Current sample, line, band is: 103 58 1 + Current sample, line, band is: 103 59 1 + Current sample, line, band is: 103 60 1 + Current sample, line, band is: 103 61 1 + Current sample, line, band is: 103 62 1 + Current sample, line, band is: 103 63 1 + Current sample, line, band is: 103 64 1 + Current sample, line, band is: 103 65 1 + Current sample, line, band is: 103 66 1 + Current sample, line, band is: 103 67 1 + Current sample, line, band is: 103 68 1 + Current sample, line, band is: 103 69 1 + Current sample, line, band is: 103 70 1 + Current sample, line, band is: 103 71 1 + Current sample, line, band is: 103 72 1 + Current sample, line, band is: 103 73 1 + Current sample, line, band is: 103 74 1 + Current sample, line, band is: 103 75 1 + Current sample, line, band is: 103 76 1 + Current sample, line, band is: 103 77 1 + Current sample, line, band is: 103 78 1 + Current sample, line, band is: 103 79 1 + Current sample, line, band is: 103 80 1 + Current sample, line, band is: 103 81 1 + Current sample, line, band is: 103 82 1 + Current sample, line, band is: 103 83 1 + Current sample, line, band is: 103 84 1 + Current sample, line, band is: 103 85 1 + Current sample, line, band is: 103 86 1 + Current sample, line, band is: 103 87 1 + Current sample, line, band is: 103 88 1 + Current sample, line, band is: 103 89 1 + Current sample, line, band is: 103 90 1 + Current sample, line, band is: 103 91 1 + Current sample, line, band is: 103 92 1 + Current sample, line, band is: 103 93 1 + Current sample, line, band is: 103 94 1 + Current sample, line, band is: 103 95 1 + Current sample, line, band is: 103 96 1 + Current sample, line, band is: 103 97 1 + Current sample, line, band is: 103 98 1 + Current sample, line, band is: 103 99 1 + Current sample, line, band is: 103 100 1 + Current sample, line, band is: 103 101 1 + Current sample, line, band is: 103 102 1 + Current sample, line, band is: 103 103 1 + Current sample, line, band is: 103 104 1 + Current sample, line, band is: 103 105 1 + Current sample, line, band is: 103 106 1 + Current sample, line, band is: 103 107 1 + Current sample, line, band is: 103 108 1 + Current sample, line, band is: 103 109 1 + Current sample, line, band is: 103 110 1 + Current sample, line, band is: 103 111 1 + Current sample, line, band is: 103 112 1 + Current sample, line, band is: 103 113 1 + Current sample, line, band is: 103 114 1 + Current sample, line, band is: 103 115 1 + Current sample, line, band is: 103 116 1 + Current sample, line, band is: 103 117 1 + Current sample, line, band is: 103 118 1 + Current sample, line, band is: 103 119 1 + Current sample, line, band is: 103 120 1 + Current sample, line, band is: 103 121 1 + Current sample, line, band is: 103 122 1 + Current sample, line, band is: 103 123 1 + Current sample, line, band is: 103 124 1 + Current sample, line, band is: 103 125 1 + Current sample, line, band is: 103 126 1 + Current sample, line, band is: 104 1 1 + Current sample, line, band is: 104 2 1 + Current sample, line, band is: 104 3 1 + Current sample, line, band is: 104 4 1 + Current sample, line, band is: 104 5 1 + Current sample, line, band is: 104 6 1 + Current sample, line, band is: 104 7 1 + Current sample, line, band is: 104 8 1 + Current sample, line, band is: 104 9 1 + Current sample, line, band is: 104 10 1 + Current sample, line, band is: 104 11 1 + Current sample, line, band is: 104 12 1 + Current sample, line, band is: 104 13 1 + Current sample, line, band is: 104 14 1 + Current sample, line, band is: 104 15 1 + Current sample, line, band is: 104 16 1 + Current sample, line, band is: 104 17 1 + Current sample, line, band is: 104 18 1 + Current sample, line, band is: 104 19 1 + Current sample, line, band is: 104 20 1 + Current sample, line, band is: 104 21 1 + Current sample, line, band is: 104 22 1 + Current sample, line, band is: 104 23 1 + Current sample, line, band is: 104 24 1 + Current sample, line, band is: 104 25 1 + Current sample, line, band is: 104 26 1 + Current sample, line, band is: 104 27 1 + Current sample, line, band is: 104 28 1 + Current sample, line, band is: 104 29 1 + Current sample, line, band is: 104 30 1 + Current sample, line, band is: 104 31 1 + Current sample, line, band is: 104 32 1 + Current sample, line, band is: 104 33 1 + Current sample, line, band is: 104 34 1 + Current sample, line, band is: 104 35 1 + Current sample, line, band is: 104 36 1 + Current sample, line, band is: 104 37 1 + Current sample, line, band is: 104 38 1 + Current sample, line, band is: 104 39 1 + Current sample, line, band is: 104 40 1 + Current sample, line, band is: 104 41 1 + Current sample, line, band is: 104 42 1 + Current sample, line, band is: 104 43 1 + Current sample, line, band is: 104 44 1 + Current sample, line, band is: 104 45 1 + Current sample, line, band is: 104 46 1 + Current sample, line, band is: 104 47 1 + Current sample, line, band is: 104 48 1 + Current sample, line, band is: 104 49 1 + Current sample, line, band is: 104 50 1 + Current sample, line, band is: 104 51 1 + Current sample, line, band is: 104 52 1 + Current sample, line, band is: 104 53 1 + Current sample, line, band is: 104 54 1 + Current sample, line, band is: 104 55 1 + Current sample, line, band is: 104 56 1 + Current sample, line, band is: 104 57 1 + Current sample, line, band is: 104 58 1 + Current sample, line, band is: 104 59 1 + Current sample, line, band is: 104 60 1 + Current sample, line, band is: 104 61 1 + Current sample, line, band is: 104 62 1 + Current sample, line, band is: 104 63 1 + Current sample, line, band is: 104 64 1 + Current sample, line, band is: 104 65 1 + Current sample, line, band is: 104 66 1 + Current sample, line, band is: 104 67 1 + Current sample, line, band is: 104 68 1 + Current sample, line, band is: 104 69 1 + Current sample, line, band is: 104 70 1 + Current sample, line, band is: 104 71 1 + Current sample, line, band is: 104 72 1 + Current sample, line, band is: 104 73 1 + Current sample, line, band is: 104 74 1 + Current sample, line, band is: 104 75 1 + Current sample, line, band is: 104 76 1 + Current sample, line, band is: 104 77 1 + Current sample, line, band is: 104 78 1 + Current sample, line, band is: 104 79 1 + Current sample, line, band is: 104 80 1 + Current sample, line, band is: 104 81 1 + Current sample, line, band is: 104 82 1 + Current sample, line, band is: 104 83 1 + Current sample, line, band is: 104 84 1 + Current sample, line, band is: 104 85 1 + Current sample, line, band is: 104 86 1 + Current sample, line, band is: 104 87 1 + Current sample, line, band is: 104 88 1 + Current sample, line, band is: 104 89 1 + Current sample, line, band is: 104 90 1 + Current sample, line, band is: 104 91 1 + Current sample, line, band is: 104 92 1 + Current sample, line, band is: 104 93 1 + Current sample, line, band is: 104 94 1 + Current sample, line, band is: 104 95 1 + Current sample, line, band is: 104 96 1 + Current sample, line, band is: 104 97 1 + Current sample, line, band is: 104 98 1 + Current sample, line, band is: 104 99 1 + Current sample, line, band is: 104 100 1 + Current sample, line, band is: 104 101 1 + Current sample, line, band is: 104 102 1 + Current sample, line, band is: 104 103 1 + Current sample, line, band is: 104 104 1 + Current sample, line, band is: 104 105 1 + Current sample, line, band is: 104 106 1 + Current sample, line, band is: 104 107 1 + Current sample, line, band is: 104 108 1 + Current sample, line, band is: 104 109 1 + Current sample, line, band is: 104 110 1 + Current sample, line, band is: 104 111 1 + Current sample, line, band is: 104 112 1 + Current sample, line, band is: 104 113 1 + Current sample, line, band is: 104 114 1 + Current sample, line, band is: 104 115 1 + Current sample, line, band is: 104 116 1 + Current sample, line, band is: 104 117 1 + Current sample, line, band is: 104 118 1 + Current sample, line, band is: 104 119 1 + Current sample, line, band is: 104 120 1 + Current sample, line, band is: 104 121 1 + Current sample, line, band is: 104 122 1 + Current sample, line, band is: 104 123 1 + Current sample, line, band is: 104 124 1 + Current sample, line, band is: 104 125 1 + Current sample, line, band is: 104 126 1 + Current sample, line, band is: 105 1 1 + Current sample, line, band is: 105 2 1 + Current sample, line, band is: 105 3 1 + Current sample, line, band is: 105 4 1 + Current sample, line, band is: 105 5 1 + Current sample, line, band is: 105 6 1 + Current sample, line, band is: 105 7 1 + Current sample, line, band is: 105 8 1 + Current sample, line, band is: 105 9 1 + Current sample, line, band is: 105 10 1 + Current sample, line, band is: 105 11 1 + Current sample, line, band is: 105 12 1 + Current sample, line, band is: 105 13 1 + Current sample, line, band is: 105 14 1 + Current sample, line, band is: 105 15 1 + Current sample, line, band is: 105 16 1 + Current sample, line, band is: 105 17 1 + Current sample, line, band is: 105 18 1 + Current sample, line, band is: 105 19 1 + Current sample, line, band is: 105 20 1 + Current sample, line, band is: 105 21 1 + Current sample, line, band is: 105 22 1 + Current sample, line, band is: 105 23 1 + Current sample, line, band is: 105 24 1 + Current sample, line, band is: 105 25 1 + Current sample, line, band is: 105 26 1 + Current sample, line, band is: 105 27 1 + Current sample, line, band is: 105 28 1 + Current sample, line, band is: 105 29 1 + Current sample, line, band is: 105 30 1 + Current sample, line, band is: 105 31 1 + Current sample, line, band is: 105 32 1 + Current sample, line, band is: 105 33 1 + Current sample, line, band is: 105 34 1 + Current sample, line, band is: 105 35 1 + Current sample, line, band is: 105 36 1 + Current sample, line, band is: 105 37 1 + Current sample, line, band is: 105 38 1 + Current sample, line, band is: 105 39 1 + Current sample, line, band is: 105 40 1 + Current sample, line, band is: 105 41 1 + Current sample, line, band is: 105 42 1 + Current sample, line, band is: 105 43 1 + Current sample, line, band is: 105 44 1 + Current sample, line, band is: 105 45 1 + Current sample, line, band is: 105 46 1 + Current sample, line, band is: 105 47 1 + Current sample, line, band is: 105 48 1 + Current sample, line, band is: 105 49 1 + Current sample, line, band is: 105 50 1 + Current sample, line, band is: 105 51 1 + Current sample, line, band is: 105 52 1 + Current sample, line, band is: 105 53 1 + Current sample, line, band is: 105 54 1 + Current sample, line, band is: 105 55 1 + Current sample, line, band is: 105 56 1 + Current sample, line, band is: 105 57 1 + Current sample, line, band is: 105 58 1 + Current sample, line, band is: 105 59 1 + Current sample, line, band is: 105 60 1 + Current sample, line, band is: 105 61 1 + Current sample, line, band is: 105 62 1 + Current sample, line, band is: 105 63 1 + Current sample, line, band is: 105 64 1 + Current sample, line, band is: 105 65 1 + Current sample, line, band is: 105 66 1 + Current sample, line, band is: 105 67 1 + Current sample, line, band is: 105 68 1 + Current sample, line, band is: 105 69 1 + Current sample, line, band is: 105 70 1 + Current sample, line, band is: 105 71 1 + Current sample, line, band is: 105 72 1 + Current sample, line, band is: 105 73 1 + Current sample, line, band is: 105 74 1 + Current sample, line, band is: 105 75 1 + Current sample, line, band is: 105 76 1 + Current sample, line, band is: 105 77 1 + Current sample, line, band is: 105 78 1 + Current sample, line, band is: 105 79 1 + Current sample, line, band is: 105 80 1 + Current sample, line, band is: 105 81 1 + Current sample, line, band is: 105 82 1 + Current sample, line, band is: 105 83 1 + Current sample, line, band is: 105 84 1 + Current sample, line, band is: 105 85 1 + Current sample, line, band is: 105 86 1 + Current sample, line, band is: 105 87 1 + Current sample, line, band is: 105 88 1 + Current sample, line, band is: 105 89 1 + Current sample, line, band is: 105 90 1 + Current sample, line, band is: 105 91 1 + Current sample, line, band is: 105 92 1 + Current sample, line, band is: 105 93 1 + Current sample, line, band is: 105 94 1 + Current sample, line, band is: 105 95 1 + Current sample, line, band is: 105 96 1 + Current sample, line, band is: 105 97 1 + Current sample, line, band is: 105 98 1 + Current sample, line, band is: 105 99 1 + Current sample, line, band is: 105 100 1 + Current sample, line, band is: 105 101 1 + Current sample, line, band is: 105 102 1 + Current sample, line, band is: 105 103 1 + Current sample, line, band is: 105 104 1 + Current sample, line, band is: 105 105 1 + Current sample, line, band is: 105 106 1 + Current sample, line, band is: 105 107 1 + Current sample, line, band is: 105 108 1 + Current sample, line, band is: 105 109 1 + Current sample, line, band is: 105 110 1 + Current sample, line, band is: 105 111 1 + Current sample, line, band is: 105 112 1 + Current sample, line, band is: 105 113 1 + Current sample, line, band is: 105 114 1 + Current sample, line, band is: 105 115 1 + Current sample, line, band is: 105 116 1 + Current sample, line, band is: 105 117 1 + Current sample, line, band is: 105 118 1 + Current sample, line, band is: 105 119 1 + Current sample, line, band is: 105 120 1 + Current sample, line, band is: 105 121 1 + Current sample, line, band is: 105 122 1 + Current sample, line, band is: 105 123 1 + Current sample, line, band is: 105 124 1 + Current sample, line, band is: 105 125 1 + Current sample, line, band is: 105 126 1 + Current sample, line, band is: 106 1 1 + Current sample, line, band is: 106 2 1 + Current sample, line, band is: 106 3 1 + Current sample, line, band is: 106 4 1 + Current sample, line, band is: 106 5 1 + Current sample, line, band is: 106 6 1 + Current sample, line, band is: 106 7 1 + Current sample, line, band is: 106 8 1 + Current sample, line, band is: 106 9 1 + Current sample, line, band is: 106 10 1 + Current sample, line, band is: 106 11 1 + Current sample, line, band is: 106 12 1 + Current sample, line, band is: 106 13 1 + Current sample, line, band is: 106 14 1 + Current sample, line, band is: 106 15 1 + Current sample, line, band is: 106 16 1 + Current sample, line, band is: 106 17 1 + Current sample, line, band is: 106 18 1 + Current sample, line, band is: 106 19 1 + Current sample, line, band is: 106 20 1 + Current sample, line, band is: 106 21 1 + Current sample, line, band is: 106 22 1 + Current sample, line, band is: 106 23 1 + Current sample, line, band is: 106 24 1 + Current sample, line, band is: 106 25 1 + Current sample, line, band is: 106 26 1 + Current sample, line, band is: 106 27 1 + Current sample, line, band is: 106 28 1 + Current sample, line, band is: 106 29 1 + Current sample, line, band is: 106 30 1 + Current sample, line, band is: 106 31 1 + Current sample, line, band is: 106 32 1 + Current sample, line, band is: 106 33 1 + Current sample, line, band is: 106 34 1 + Current sample, line, band is: 106 35 1 + Current sample, line, band is: 106 36 1 + Current sample, line, band is: 106 37 1 + Current sample, line, band is: 106 38 1 + Current sample, line, band is: 106 39 1 + Current sample, line, band is: 106 40 1 + Current sample, line, band is: 106 41 1 + Current sample, line, band is: 106 42 1 + Current sample, line, band is: 106 43 1 + Current sample, line, band is: 106 44 1 + Current sample, line, band is: 106 45 1 + Current sample, line, band is: 106 46 1 + Current sample, line, band is: 106 47 1 + Current sample, line, band is: 106 48 1 + Current sample, line, band is: 106 49 1 + Current sample, line, band is: 106 50 1 + Current sample, line, band is: 106 51 1 + Current sample, line, band is: 106 52 1 + Current sample, line, band is: 106 53 1 + Current sample, line, band is: 106 54 1 + Current sample, line, band is: 106 55 1 + Current sample, line, band is: 106 56 1 + Current sample, line, band is: 106 57 1 + Current sample, line, band is: 106 58 1 + Current sample, line, band is: 106 59 1 + Current sample, line, band is: 106 60 1 + Current sample, line, band is: 106 61 1 + Current sample, line, band is: 106 62 1 + Current sample, line, band is: 106 63 1 + Current sample, line, band is: 106 64 1 + Current sample, line, band is: 106 65 1 + Current sample, line, band is: 106 66 1 + Current sample, line, band is: 106 67 1 + Current sample, line, band is: 106 68 1 + Current sample, line, band is: 106 69 1 + Current sample, line, band is: 106 70 1 + Current sample, line, band is: 106 71 1 + Current sample, line, band is: 106 72 1 + Current sample, line, band is: 106 73 1 + Current sample, line, band is: 106 74 1 + Current sample, line, band is: 106 75 1 + Current sample, line, band is: 106 76 1 + Current sample, line, band is: 106 77 1 + Current sample, line, band is: 106 78 1 + Current sample, line, band is: 106 79 1 + Current sample, line, band is: 106 80 1 + Current sample, line, band is: 106 81 1 + Current sample, line, band is: 106 82 1 + Current sample, line, band is: 106 83 1 + Current sample, line, band is: 106 84 1 + Current sample, line, band is: 106 85 1 + Current sample, line, band is: 106 86 1 + Current sample, line, band is: 106 87 1 + Current sample, line, band is: 106 88 1 + Current sample, line, band is: 106 89 1 + Current sample, line, band is: 106 90 1 + Current sample, line, band is: 106 91 1 + Current sample, line, band is: 106 92 1 + Current sample, line, band is: 106 93 1 + Current sample, line, band is: 106 94 1 + Current sample, line, band is: 106 95 1 + Current sample, line, band is: 106 96 1 + Current sample, line, band is: 106 97 1 + Current sample, line, band is: 106 98 1 + Current sample, line, band is: 106 99 1 + Current sample, line, band is: 106 100 1 + Current sample, line, band is: 106 101 1 + Current sample, line, band is: 106 102 1 + Current sample, line, band is: 106 103 1 + Current sample, line, band is: 106 104 1 + Current sample, line, band is: 106 105 1 + Current sample, line, band is: 106 106 1 + Current sample, line, band is: 106 107 1 + Current sample, line, band is: 106 108 1 + Current sample, line, band is: 106 109 1 + Current sample, line, band is: 106 110 1 + Current sample, line, band is: 106 111 1 + Current sample, line, band is: 106 112 1 + Current sample, line, band is: 106 113 1 + Current sample, line, band is: 106 114 1 + Current sample, line, band is: 106 115 1 + Current sample, line, band is: 106 116 1 + Current sample, line, band is: 106 117 1 + Current sample, line, band is: 106 118 1 + Current sample, line, band is: 106 119 1 + Current sample, line, band is: 106 120 1 + Current sample, line, band is: 106 121 1 + Current sample, line, band is: 106 122 1 + Current sample, line, band is: 106 123 1 + Current sample, line, band is: 106 124 1 + Current sample, line, band is: 106 125 1 + Current sample, line, band is: 106 126 1 + Current sample, line, band is: 107 1 1 + Current sample, line, band is: 107 2 1 + Current sample, line, band is: 107 3 1 + Current sample, line, band is: 107 4 1 + Current sample, line, band is: 107 5 1 + Current sample, line, band is: 107 6 1 + Current sample, line, band is: 107 7 1 + Current sample, line, band is: 107 8 1 + Current sample, line, band is: 107 9 1 + Current sample, line, band is: 107 10 1 + Current sample, line, band is: 107 11 1 + Current sample, line, band is: 107 12 1 + Current sample, line, band is: 107 13 1 + Current sample, line, band is: 107 14 1 + Current sample, line, band is: 107 15 1 + Current sample, line, band is: 107 16 1 + Current sample, line, band is: 107 17 1 + Current sample, line, band is: 107 18 1 + Current sample, line, band is: 107 19 1 + Current sample, line, band is: 107 20 1 + Current sample, line, band is: 107 21 1 + Current sample, line, band is: 107 22 1 + Current sample, line, band is: 107 23 1 + Current sample, line, band is: 107 24 1 + Current sample, line, band is: 107 25 1 + Current sample, line, band is: 107 26 1 + Current sample, line, band is: 107 27 1 + Current sample, line, band is: 107 28 1 + Current sample, line, band is: 107 29 1 + Current sample, line, band is: 107 30 1 + Current sample, line, band is: 107 31 1 + Current sample, line, band is: 107 32 1 + Current sample, line, band is: 107 33 1 + Current sample, line, band is: 107 34 1 + Current sample, line, band is: 107 35 1 + Current sample, line, band is: 107 36 1 + Current sample, line, band is: 107 37 1 + Current sample, line, band is: 107 38 1 + Current sample, line, band is: 107 39 1 + Current sample, line, band is: 107 40 1 + Current sample, line, band is: 107 41 1 + Current sample, line, band is: 107 42 1 + Current sample, line, band is: 107 43 1 + Current sample, line, band is: 107 44 1 + Current sample, line, band is: 107 45 1 + Current sample, line, band is: 107 46 1 + Current sample, line, band is: 107 47 1 + Current sample, line, band is: 107 48 1 + Current sample, line, band is: 107 49 1 + Current sample, line, band is: 107 50 1 + Current sample, line, band is: 107 51 1 + Current sample, line, band is: 107 52 1 + Current sample, line, band is: 107 53 1 + Current sample, line, band is: 107 54 1 + Current sample, line, band is: 107 55 1 + Current sample, line, band is: 107 56 1 + Current sample, line, band is: 107 57 1 + Current sample, line, band is: 107 58 1 + Current sample, line, band is: 107 59 1 + Current sample, line, band is: 107 60 1 + Current sample, line, band is: 107 61 1 + Current sample, line, band is: 107 62 1 + Current sample, line, band is: 107 63 1 + Current sample, line, band is: 107 64 1 + Current sample, line, band is: 107 65 1 + Current sample, line, band is: 107 66 1 + Current sample, line, band is: 107 67 1 + Current sample, line, band is: 107 68 1 + Current sample, line, band is: 107 69 1 + Current sample, line, band is: 107 70 1 + Current sample, line, band is: 107 71 1 + Current sample, line, band is: 107 72 1 + Current sample, line, band is: 107 73 1 + Current sample, line, band is: 107 74 1 + Current sample, line, band is: 107 75 1 + Current sample, line, band is: 107 76 1 + Current sample, line, band is: 107 77 1 + Current sample, line, band is: 107 78 1 + Current sample, line, band is: 107 79 1 + Current sample, line, band is: 107 80 1 + Current sample, line, band is: 107 81 1 + Current sample, line, band is: 107 82 1 + Current sample, line, band is: 107 83 1 + Current sample, line, band is: 107 84 1 + Current sample, line, band is: 107 85 1 + Current sample, line, band is: 107 86 1 + Current sample, line, band is: 107 87 1 + Current sample, line, band is: 107 88 1 + Current sample, line, band is: 107 89 1 + Current sample, line, band is: 107 90 1 + Current sample, line, band is: 107 91 1 + Current sample, line, band is: 107 92 1 + Current sample, line, band is: 107 93 1 + Current sample, line, band is: 107 94 1 + Current sample, line, band is: 107 95 1 + Current sample, line, band is: 107 96 1 + Current sample, line, band is: 107 97 1 + Current sample, line, band is: 107 98 1 + Current sample, line, band is: 107 99 1 + Current sample, line, band is: 107 100 1 + Current sample, line, band is: 107 101 1 + Current sample, line, band is: 107 102 1 + Current sample, line, band is: 107 103 1 + Current sample, line, band is: 107 104 1 + Current sample, line, band is: 107 105 1 + Current sample, line, band is: 107 106 1 + Current sample, line, band is: 107 107 1 + Current sample, line, band is: 107 108 1 + Current sample, line, band is: 107 109 1 + Current sample, line, band is: 107 110 1 + Current sample, line, band is: 107 111 1 + Current sample, line, band is: 107 112 1 + Current sample, line, band is: 107 113 1 + Current sample, line, band is: 107 114 1 + Current sample, line, band is: 107 115 1 + Current sample, line, band is: 107 116 1 + Current sample, line, band is: 107 117 1 + Current sample, line, band is: 107 118 1 + Current sample, line, band is: 107 119 1 + Current sample, line, band is: 107 120 1 + Current sample, line, band is: 107 121 1 + Current sample, line, band is: 107 122 1 + Current sample, line, band is: 107 123 1 + Current sample, line, band is: 107 124 1 + Current sample, line, band is: 107 125 1 + Current sample, line, band is: 107 126 1 + Current sample, line, band is: 108 1 1 + Current sample, line, band is: 108 2 1 + Current sample, line, band is: 108 3 1 + Current sample, line, band is: 108 4 1 + Current sample, line, band is: 108 5 1 + Current sample, line, band is: 108 6 1 + Current sample, line, band is: 108 7 1 + Current sample, line, band is: 108 8 1 + Current sample, line, band is: 108 9 1 + Current sample, line, band is: 108 10 1 + Current sample, line, band is: 108 11 1 + Current sample, line, band is: 108 12 1 + Current sample, line, band is: 108 13 1 + Current sample, line, band is: 108 14 1 + Current sample, line, band is: 108 15 1 + Current sample, line, band is: 108 16 1 + Current sample, line, band is: 108 17 1 + Current sample, line, band is: 108 18 1 + Current sample, line, band is: 108 19 1 + Current sample, line, band is: 108 20 1 + Current sample, line, band is: 108 21 1 + Current sample, line, band is: 108 22 1 + Current sample, line, band is: 108 23 1 + Current sample, line, band is: 108 24 1 + Current sample, line, band is: 108 25 1 + Current sample, line, band is: 108 26 1 + Current sample, line, band is: 108 27 1 + Current sample, line, band is: 108 28 1 + Current sample, line, band is: 108 29 1 + Current sample, line, band is: 108 30 1 + Current sample, line, band is: 108 31 1 + Current sample, line, band is: 108 32 1 + Current sample, line, band is: 108 33 1 + Current sample, line, band is: 108 34 1 + Current sample, line, band is: 108 35 1 + Current sample, line, band is: 108 36 1 + Current sample, line, band is: 108 37 1 + Current sample, line, band is: 108 38 1 + Current sample, line, band is: 108 39 1 + Current sample, line, band is: 108 40 1 + Current sample, line, band is: 108 41 1 + Current sample, line, band is: 108 42 1 + Current sample, line, band is: 108 43 1 + Current sample, line, band is: 108 44 1 + Current sample, line, band is: 108 45 1 + Current sample, line, band is: 108 46 1 + Current sample, line, band is: 108 47 1 + Current sample, line, band is: 108 48 1 + Current sample, line, band is: 108 49 1 + Current sample, line, band is: 108 50 1 + Current sample, line, band is: 108 51 1 + Current sample, line, band is: 108 52 1 + Current sample, line, band is: 108 53 1 + Current sample, line, band is: 108 54 1 + Current sample, line, band is: 108 55 1 + Current sample, line, band is: 108 56 1 + Current sample, line, band is: 108 57 1 + Current sample, line, band is: 108 58 1 + Current sample, line, band is: 108 59 1 + Current sample, line, band is: 108 60 1 + Current sample, line, band is: 108 61 1 + Current sample, line, band is: 108 62 1 + Current sample, line, band is: 108 63 1 + Current sample, line, band is: 108 64 1 + Current sample, line, band is: 108 65 1 + Current sample, line, band is: 108 66 1 + Current sample, line, band is: 108 67 1 + Current sample, line, band is: 108 68 1 + Current sample, line, band is: 108 69 1 + Current sample, line, band is: 108 70 1 + Current sample, line, band is: 108 71 1 + Current sample, line, band is: 108 72 1 + Current sample, line, band is: 108 73 1 + Current sample, line, band is: 108 74 1 + Current sample, line, band is: 108 75 1 + Current sample, line, band is: 108 76 1 + Current sample, line, band is: 108 77 1 + Current sample, line, band is: 108 78 1 + Current sample, line, band is: 108 79 1 + Current sample, line, band is: 108 80 1 + Current sample, line, band is: 108 81 1 + Current sample, line, band is: 108 82 1 + Current sample, line, band is: 108 83 1 + Current sample, line, band is: 108 84 1 + Current sample, line, band is: 108 85 1 + Current sample, line, band is: 108 86 1 + Current sample, line, band is: 108 87 1 + Current sample, line, band is: 108 88 1 + Current sample, line, band is: 108 89 1 + Current sample, line, band is: 108 90 1 + Current sample, line, band is: 108 91 1 + Current sample, line, band is: 108 92 1 + Current sample, line, band is: 108 93 1 + Current sample, line, band is: 108 94 1 + Current sample, line, band is: 108 95 1 + Current sample, line, band is: 108 96 1 + Current sample, line, band is: 108 97 1 + Current sample, line, band is: 108 98 1 + Current sample, line, band is: 108 99 1 + Current sample, line, band is: 108 100 1 + Current sample, line, band is: 108 101 1 + Current sample, line, band is: 108 102 1 + Current sample, line, band is: 108 103 1 + Current sample, line, band is: 108 104 1 + Current sample, line, band is: 108 105 1 + Current sample, line, band is: 108 106 1 + Current sample, line, band is: 108 107 1 + Current sample, line, band is: 108 108 1 + Current sample, line, band is: 108 109 1 + Current sample, line, band is: 108 110 1 + Current sample, line, band is: 108 111 1 + Current sample, line, band is: 108 112 1 + Current sample, line, band is: 108 113 1 + Current sample, line, band is: 108 114 1 + Current sample, line, band is: 108 115 1 + Current sample, line, band is: 108 116 1 + Current sample, line, band is: 108 117 1 + Current sample, line, band is: 108 118 1 + Current sample, line, band is: 108 119 1 + Current sample, line, band is: 108 120 1 + Current sample, line, band is: 108 121 1 + Current sample, line, band is: 108 122 1 + Current sample, line, band is: 108 123 1 + Current sample, line, band is: 108 124 1 + Current sample, line, band is: 108 125 1 + Current sample, line, band is: 108 126 1 + Current sample, line, band is: 109 1 1 + Current sample, line, band is: 109 2 1 + Current sample, line, band is: 109 3 1 + Current sample, line, band is: 109 4 1 + Current sample, line, band is: 109 5 1 + Current sample, line, band is: 109 6 1 + Current sample, line, band is: 109 7 1 + Current sample, line, band is: 109 8 1 + Current sample, line, band is: 109 9 1 + Current sample, line, band is: 109 10 1 + Current sample, line, band is: 109 11 1 + Current sample, line, band is: 109 12 1 + Current sample, line, band is: 109 13 1 + Current sample, line, band is: 109 14 1 + Current sample, line, band is: 109 15 1 + Current sample, line, band is: 109 16 1 + Current sample, line, band is: 109 17 1 + Current sample, line, band is: 109 18 1 + Current sample, line, band is: 109 19 1 + Current sample, line, band is: 109 20 1 + Current sample, line, band is: 109 21 1 + Current sample, line, band is: 109 22 1 + Current sample, line, band is: 109 23 1 + Current sample, line, band is: 109 24 1 + Current sample, line, band is: 109 25 1 + Current sample, line, band is: 109 26 1 + Current sample, line, band is: 109 27 1 + Current sample, line, band is: 109 28 1 + Current sample, line, band is: 109 29 1 + Current sample, line, band is: 109 30 1 + Current sample, line, band is: 109 31 1 + Current sample, line, band is: 109 32 1 + Current sample, line, band is: 109 33 1 + Current sample, line, band is: 109 34 1 + Current sample, line, band is: 109 35 1 + Current sample, line, band is: 109 36 1 + Current sample, line, band is: 109 37 1 + Current sample, line, band is: 109 38 1 + Current sample, line, band is: 109 39 1 + Current sample, line, band is: 109 40 1 + Current sample, line, band is: 109 41 1 + Current sample, line, band is: 109 42 1 + Current sample, line, band is: 109 43 1 + Current sample, line, band is: 109 44 1 + Current sample, line, band is: 109 45 1 + Current sample, line, band is: 109 46 1 + Current sample, line, band is: 109 47 1 + Current sample, line, band is: 109 48 1 + Current sample, line, band is: 109 49 1 + Current sample, line, band is: 109 50 1 + Current sample, line, band is: 109 51 1 + Current sample, line, band is: 109 52 1 + Current sample, line, band is: 109 53 1 + Current sample, line, band is: 109 54 1 + Current sample, line, band is: 109 55 1 + Current sample, line, band is: 109 56 1 + Current sample, line, band is: 109 57 1 + Current sample, line, band is: 109 58 1 + Current sample, line, band is: 109 59 1 + Current sample, line, band is: 109 60 1 + Current sample, line, band is: 109 61 1 + Current sample, line, band is: 109 62 1 + Current sample, line, band is: 109 63 1 + Current sample, line, band is: 109 64 1 + Current sample, line, band is: 109 65 1 + Current sample, line, band is: 109 66 1 + Current sample, line, band is: 109 67 1 + Current sample, line, band is: 109 68 1 + Current sample, line, band is: 109 69 1 + Current sample, line, band is: 109 70 1 + Current sample, line, band is: 109 71 1 + Current sample, line, band is: 109 72 1 + Current sample, line, band is: 109 73 1 + Current sample, line, band is: 109 74 1 + Current sample, line, band is: 109 75 1 + Current sample, line, band is: 109 76 1 + Current sample, line, band is: 109 77 1 + Current sample, line, band is: 109 78 1 + Current sample, line, band is: 109 79 1 + Current sample, line, band is: 109 80 1 + Current sample, line, band is: 109 81 1 + Current sample, line, band is: 109 82 1 + Current sample, line, band is: 109 83 1 + Current sample, line, band is: 109 84 1 + Current sample, line, band is: 109 85 1 + Current sample, line, band is: 109 86 1 + Current sample, line, band is: 109 87 1 + Current sample, line, band is: 109 88 1 + Current sample, line, band is: 109 89 1 + Current sample, line, band is: 109 90 1 + Current sample, line, band is: 109 91 1 + Current sample, line, band is: 109 92 1 + Current sample, line, band is: 109 93 1 + Current sample, line, band is: 109 94 1 + Current sample, line, band is: 109 95 1 + Current sample, line, band is: 109 96 1 + Current sample, line, band is: 109 97 1 + Current sample, line, band is: 109 98 1 + Current sample, line, band is: 109 99 1 + Current sample, line, band is: 109 100 1 + Current sample, line, band is: 109 101 1 + Current sample, line, band is: 109 102 1 + Current sample, line, band is: 109 103 1 + Current sample, line, band is: 109 104 1 + Current sample, line, band is: 109 105 1 + Current sample, line, band is: 109 106 1 + Current sample, line, band is: 109 107 1 + Current sample, line, band is: 109 108 1 + Current sample, line, band is: 109 109 1 + Current sample, line, band is: 109 110 1 + Current sample, line, band is: 109 111 1 + Current sample, line, band is: 109 112 1 + Current sample, line, band is: 109 113 1 + Current sample, line, band is: 109 114 1 + Current sample, line, band is: 109 115 1 + Current sample, line, band is: 109 116 1 + Current sample, line, band is: 109 117 1 + Current sample, line, band is: 109 118 1 + Current sample, line, band is: 109 119 1 + Current sample, line, band is: 109 120 1 + Current sample, line, band is: 109 121 1 + Current sample, line, band is: 109 122 1 + Current sample, line, band is: 109 123 1 + Current sample, line, band is: 109 124 1 + Current sample, line, band is: 109 125 1 + Current sample, line, band is: 109 126 1 + Current sample, line, band is: 110 1 1 + Current sample, line, band is: 110 2 1 + Current sample, line, band is: 110 3 1 + Current sample, line, band is: 110 4 1 + Current sample, line, band is: 110 5 1 + Current sample, line, band is: 110 6 1 + Current sample, line, band is: 110 7 1 + Current sample, line, band is: 110 8 1 + Current sample, line, band is: 110 9 1 + Current sample, line, band is: 110 10 1 + Current sample, line, band is: 110 11 1 + Current sample, line, band is: 110 12 1 + Current sample, line, band is: 110 13 1 + Current sample, line, band is: 110 14 1 + Current sample, line, band is: 110 15 1 + Current sample, line, band is: 110 16 1 + Current sample, line, band is: 110 17 1 + Current sample, line, band is: 110 18 1 + Current sample, line, band is: 110 19 1 + Current sample, line, band is: 110 20 1 + Current sample, line, band is: 110 21 1 + Current sample, line, band is: 110 22 1 + Current sample, line, band is: 110 23 1 + Current sample, line, band is: 110 24 1 + Current sample, line, band is: 110 25 1 + Current sample, line, band is: 110 26 1 + Current sample, line, band is: 110 27 1 + Current sample, line, band is: 110 28 1 + Current sample, line, band is: 110 29 1 + Current sample, line, band is: 110 30 1 + Current sample, line, band is: 110 31 1 + Current sample, line, band is: 110 32 1 + Current sample, line, band is: 110 33 1 + Current sample, line, band is: 110 34 1 + Current sample, line, band is: 110 35 1 + Current sample, line, band is: 110 36 1 + Current sample, line, band is: 110 37 1 + Current sample, line, band is: 110 38 1 + Current sample, line, band is: 110 39 1 + Current sample, line, band is: 110 40 1 + Current sample, line, band is: 110 41 1 + Current sample, line, band is: 110 42 1 + Current sample, line, band is: 110 43 1 + Current sample, line, band is: 110 44 1 + Current sample, line, band is: 110 45 1 + Current sample, line, band is: 110 46 1 + Current sample, line, band is: 110 47 1 + Current sample, line, band is: 110 48 1 + Current sample, line, band is: 110 49 1 + Current sample, line, band is: 110 50 1 + Current sample, line, band is: 110 51 1 + Current sample, line, band is: 110 52 1 + Current sample, line, band is: 110 53 1 + Current sample, line, band is: 110 54 1 + Current sample, line, band is: 110 55 1 + Current sample, line, band is: 110 56 1 + Current sample, line, band is: 110 57 1 + Current sample, line, band is: 110 58 1 + Current sample, line, band is: 110 59 1 + Current sample, line, band is: 110 60 1 + Current sample, line, band is: 110 61 1 + Current sample, line, band is: 110 62 1 + Current sample, line, band is: 110 63 1 + Current sample, line, band is: 110 64 1 + Current sample, line, band is: 110 65 1 + Current sample, line, band is: 110 66 1 + Current sample, line, band is: 110 67 1 + Current sample, line, band is: 110 68 1 + Current sample, line, band is: 110 69 1 + Current sample, line, band is: 110 70 1 + Current sample, line, band is: 110 71 1 + Current sample, line, band is: 110 72 1 + Current sample, line, band is: 110 73 1 + Current sample, line, band is: 110 74 1 + Current sample, line, band is: 110 75 1 + Current sample, line, band is: 110 76 1 + Current sample, line, band is: 110 77 1 + Current sample, line, band is: 110 78 1 + Current sample, line, band is: 110 79 1 + Current sample, line, band is: 110 80 1 + Current sample, line, band is: 110 81 1 + Current sample, line, band is: 110 82 1 + Current sample, line, band is: 110 83 1 + Current sample, line, band is: 110 84 1 + Current sample, line, band is: 110 85 1 + Current sample, line, band is: 110 86 1 + Current sample, line, band is: 110 87 1 + Current sample, line, band is: 110 88 1 + Current sample, line, band is: 110 89 1 + Current sample, line, band is: 110 90 1 + Current sample, line, band is: 110 91 1 + Current sample, line, band is: 110 92 1 + Current sample, line, band is: 110 93 1 + Current sample, line, band is: 110 94 1 + Current sample, line, band is: 110 95 1 + Current sample, line, band is: 110 96 1 + Current sample, line, band is: 110 97 1 + Current sample, line, band is: 110 98 1 + Current sample, line, band is: 110 99 1 + Current sample, line, band is: 110 100 1 + Current sample, line, band is: 110 101 1 + Current sample, line, band is: 110 102 1 + Current sample, line, band is: 110 103 1 + Current sample, line, band is: 110 104 1 + Current sample, line, band is: 110 105 1 + Current sample, line, band is: 110 106 1 + Current sample, line, band is: 110 107 1 + Current sample, line, band is: 110 108 1 + Current sample, line, band is: 110 109 1 + Current sample, line, band is: 110 110 1 + Current sample, line, band is: 110 111 1 + Current sample, line, band is: 110 112 1 + Current sample, line, band is: 110 113 1 + Current sample, line, band is: 110 114 1 + Current sample, line, band is: 110 115 1 + Current sample, line, band is: 110 116 1 + Current sample, line, band is: 110 117 1 + Current sample, line, band is: 110 118 1 + Current sample, line, band is: 110 119 1 + Current sample, line, band is: 110 120 1 + Current sample, line, band is: 110 121 1 + Current sample, line, band is: 110 122 1 + Current sample, line, band is: 110 123 1 + Current sample, line, band is: 110 124 1 + Current sample, line, band is: 110 125 1 + Current sample, line, band is: 110 126 1 + Current sample, line, band is: 111 1 1 + Current sample, line, band is: 111 2 1 + Current sample, line, band is: 111 3 1 + Current sample, line, band is: 111 4 1 + Current sample, line, band is: 111 5 1 + Current sample, line, band is: 111 6 1 + Current sample, line, band is: 111 7 1 + Current sample, line, band is: 111 8 1 + Current sample, line, band is: 111 9 1 + Current sample, line, band is: 111 10 1 + Current sample, line, band is: 111 11 1 + Current sample, line, band is: 111 12 1 + Current sample, line, band is: 111 13 1 + Current sample, line, band is: 111 14 1 + Current sample, line, band is: 111 15 1 + Current sample, line, band is: 111 16 1 + Current sample, line, band is: 111 17 1 + Current sample, line, band is: 111 18 1 + Current sample, line, band is: 111 19 1 + Current sample, line, band is: 111 20 1 + Current sample, line, band is: 111 21 1 + Current sample, line, band is: 111 22 1 + Current sample, line, band is: 111 23 1 + Current sample, line, band is: 111 24 1 + Current sample, line, band is: 111 25 1 + Current sample, line, band is: 111 26 1 + Current sample, line, band is: 111 27 1 + Current sample, line, band is: 111 28 1 + Current sample, line, band is: 111 29 1 + Current sample, line, band is: 111 30 1 + Current sample, line, band is: 111 31 1 + Current sample, line, band is: 111 32 1 + Current sample, line, band is: 111 33 1 + Current sample, line, band is: 111 34 1 + Current sample, line, band is: 111 35 1 + Current sample, line, band is: 111 36 1 + Current sample, line, band is: 111 37 1 + Current sample, line, band is: 111 38 1 + Current sample, line, band is: 111 39 1 + Current sample, line, band is: 111 40 1 + Current sample, line, band is: 111 41 1 + Current sample, line, band is: 111 42 1 + Current sample, line, band is: 111 43 1 + Current sample, line, band is: 111 44 1 + Current sample, line, band is: 111 45 1 + Current sample, line, band is: 111 46 1 + Current sample, line, band is: 111 47 1 + Current sample, line, band is: 111 48 1 + Current sample, line, band is: 111 49 1 + Current sample, line, band is: 111 50 1 + Current sample, line, band is: 111 51 1 + Current sample, line, band is: 111 52 1 + Current sample, line, band is: 111 53 1 + Current sample, line, band is: 111 54 1 + Current sample, line, band is: 111 55 1 + Current sample, line, band is: 111 56 1 + Current sample, line, band is: 111 57 1 + Current sample, line, band is: 111 58 1 + Current sample, line, band is: 111 59 1 + Current sample, line, band is: 111 60 1 + Current sample, line, band is: 111 61 1 + Current sample, line, band is: 111 62 1 + Current sample, line, band is: 111 63 1 + Current sample, line, band is: 111 64 1 + Current sample, line, band is: 111 65 1 + Current sample, line, band is: 111 66 1 + Current sample, line, band is: 111 67 1 + Current sample, line, band is: 111 68 1 + Current sample, line, band is: 111 69 1 + Current sample, line, band is: 111 70 1 + Current sample, line, band is: 111 71 1 + Current sample, line, band is: 111 72 1 + Current sample, line, band is: 111 73 1 + Current sample, line, band is: 111 74 1 + Current sample, line, band is: 111 75 1 + Current sample, line, band is: 111 76 1 + Current sample, line, band is: 111 77 1 + Current sample, line, band is: 111 78 1 + Current sample, line, band is: 111 79 1 + Current sample, line, band is: 111 80 1 + Current sample, line, band is: 111 81 1 + Current sample, line, band is: 111 82 1 + Current sample, line, band is: 111 83 1 + Current sample, line, band is: 111 84 1 + Current sample, line, band is: 111 85 1 + Current sample, line, band is: 111 86 1 + Current sample, line, band is: 111 87 1 + Current sample, line, band is: 111 88 1 + Current sample, line, band is: 111 89 1 + Current sample, line, band is: 111 90 1 + Current sample, line, band is: 111 91 1 + Current sample, line, band is: 111 92 1 + Current sample, line, band is: 111 93 1 + Current sample, line, band is: 111 94 1 + Current sample, line, band is: 111 95 1 + Current sample, line, band is: 111 96 1 + Current sample, line, band is: 111 97 1 + Current sample, line, band is: 111 98 1 + Current sample, line, band is: 111 99 1 + Current sample, line, band is: 111 100 1 + Current sample, line, band is: 111 101 1 + Current sample, line, band is: 111 102 1 + Current sample, line, band is: 111 103 1 + Current sample, line, band is: 111 104 1 + Current sample, line, band is: 111 105 1 + Current sample, line, band is: 111 106 1 + Current sample, line, band is: 111 107 1 + Current sample, line, band is: 111 108 1 + Current sample, line, band is: 111 109 1 + Current sample, line, band is: 111 110 1 + Current sample, line, band is: 111 111 1 + Current sample, line, band is: 111 112 1 + Current sample, line, band is: 111 113 1 + Current sample, line, band is: 111 114 1 + Current sample, line, band is: 111 115 1 + Current sample, line, band is: 111 116 1 + Current sample, line, band is: 111 117 1 + Current sample, line, band is: 111 118 1 + Current sample, line, band is: 111 119 1 + Current sample, line, band is: 111 120 1 + Current sample, line, band is: 111 121 1 + Current sample, line, band is: 111 122 1 + Current sample, line, band is: 111 123 1 + Current sample, line, band is: 111 124 1 + Current sample, line, band is: 111 125 1 + Current sample, line, band is: 111 126 1 + Current sample, line, band is: 112 1 1 + Current sample, line, band is: 112 2 1 + Current sample, line, band is: 112 3 1 + Current sample, line, band is: 112 4 1 + Current sample, line, band is: 112 5 1 + Current sample, line, band is: 112 6 1 + Current sample, line, band is: 112 7 1 + Current sample, line, band is: 112 8 1 + Current sample, line, band is: 112 9 1 + Current sample, line, band is: 112 10 1 + Current sample, line, band is: 112 11 1 + Current sample, line, band is: 112 12 1 + Current sample, line, band is: 112 13 1 + Current sample, line, band is: 112 14 1 + Current sample, line, band is: 112 15 1 + Current sample, line, band is: 112 16 1 + Current sample, line, band is: 112 17 1 + Current sample, line, band is: 112 18 1 + Current sample, line, band is: 112 19 1 + Current sample, line, band is: 112 20 1 + Current sample, line, band is: 112 21 1 + Current sample, line, band is: 112 22 1 + Current sample, line, band is: 112 23 1 + Current sample, line, band is: 112 24 1 + Current sample, line, band is: 112 25 1 + Current sample, line, band is: 112 26 1 + Current sample, line, band is: 112 27 1 + Current sample, line, band is: 112 28 1 + Current sample, line, band is: 112 29 1 + Current sample, line, band is: 112 30 1 + Current sample, line, band is: 112 31 1 + Current sample, line, band is: 112 32 1 + Current sample, line, band is: 112 33 1 + Current sample, line, band is: 112 34 1 + Current sample, line, band is: 112 35 1 + Current sample, line, band is: 112 36 1 + Current sample, line, band is: 112 37 1 + Current sample, line, band is: 112 38 1 + Current sample, line, band is: 112 39 1 + Current sample, line, band is: 112 40 1 + Current sample, line, band is: 112 41 1 + Current sample, line, band is: 112 42 1 + Current sample, line, band is: 112 43 1 + Current sample, line, band is: 112 44 1 + Current sample, line, band is: 112 45 1 + Current sample, line, band is: 112 46 1 + Current sample, line, band is: 112 47 1 + Current sample, line, band is: 112 48 1 + Current sample, line, band is: 112 49 1 + Current sample, line, band is: 112 50 1 + Current sample, line, band is: 112 51 1 + Current sample, line, band is: 112 52 1 + Current sample, line, band is: 112 53 1 + Current sample, line, band is: 112 54 1 + Current sample, line, band is: 112 55 1 + Current sample, line, band is: 112 56 1 + Current sample, line, band is: 112 57 1 + Current sample, line, band is: 112 58 1 + Current sample, line, band is: 112 59 1 + Current sample, line, band is: 112 60 1 + Current sample, line, band is: 112 61 1 + Current sample, line, band is: 112 62 1 + Current sample, line, band is: 112 63 1 + Current sample, line, band is: 112 64 1 + Current sample, line, band is: 112 65 1 + Current sample, line, band is: 112 66 1 + Current sample, line, band is: 112 67 1 + Current sample, line, band is: 112 68 1 + Current sample, line, band is: 112 69 1 + Current sample, line, band is: 112 70 1 + Current sample, line, band is: 112 71 1 + Current sample, line, band is: 112 72 1 + Current sample, line, band is: 112 73 1 + Current sample, line, band is: 112 74 1 + Current sample, line, band is: 112 75 1 + Current sample, line, band is: 112 76 1 + Current sample, line, band is: 112 77 1 + Current sample, line, band is: 112 78 1 + Current sample, line, band is: 112 79 1 + Current sample, line, band is: 112 80 1 + Current sample, line, band is: 112 81 1 + Current sample, line, band is: 112 82 1 + Current sample, line, band is: 112 83 1 + Current sample, line, band is: 112 84 1 + Current sample, line, band is: 112 85 1 + Current sample, line, band is: 112 86 1 + Current sample, line, band is: 112 87 1 + Current sample, line, band is: 112 88 1 + Current sample, line, band is: 112 89 1 + Current sample, line, band is: 112 90 1 + Current sample, line, band is: 112 91 1 + Current sample, line, band is: 112 92 1 + Current sample, line, band is: 112 93 1 + Current sample, line, band is: 112 94 1 + Current sample, line, band is: 112 95 1 + Current sample, line, band is: 112 96 1 + Current sample, line, band is: 112 97 1 + Current sample, line, band is: 112 98 1 + Current sample, line, band is: 112 99 1 + Current sample, line, band is: 112 100 1 + Current sample, line, band is: 112 101 1 + Current sample, line, band is: 112 102 1 + Current sample, line, band is: 112 103 1 + Current sample, line, band is: 112 104 1 + Current sample, line, band is: 112 105 1 + Current sample, line, band is: 112 106 1 + Current sample, line, band is: 112 107 1 + Current sample, line, band is: 112 108 1 + Current sample, line, band is: 112 109 1 + Current sample, line, band is: 112 110 1 + Current sample, line, band is: 112 111 1 + Current sample, line, band is: 112 112 1 + Current sample, line, band is: 112 113 1 + Current sample, line, band is: 112 114 1 + Current sample, line, band is: 112 115 1 + Current sample, line, band is: 112 116 1 + Current sample, line, band is: 112 117 1 + Current sample, line, band is: 112 118 1 + Current sample, line, band is: 112 119 1 + Current sample, line, band is: 112 120 1 + Current sample, line, band is: 112 121 1 + Current sample, line, band is: 112 122 1 + Current sample, line, band is: 112 123 1 + Current sample, line, band is: 112 124 1 + Current sample, line, band is: 112 125 1 + Current sample, line, band is: 112 126 1 + Current sample, line, band is: 113 1 1 + Current sample, line, band is: 113 2 1 + Current sample, line, band is: 113 3 1 + Current sample, line, band is: 113 4 1 + Current sample, line, band is: 113 5 1 + Current sample, line, band is: 113 6 1 + Current sample, line, band is: 113 7 1 + Current sample, line, band is: 113 8 1 + Current sample, line, band is: 113 9 1 + Current sample, line, band is: 113 10 1 + Current sample, line, band is: 113 11 1 + Current sample, line, band is: 113 12 1 + Current sample, line, band is: 113 13 1 + Current sample, line, band is: 113 14 1 + Current sample, line, band is: 113 15 1 + Current sample, line, band is: 113 16 1 + Current sample, line, band is: 113 17 1 + Current sample, line, band is: 113 18 1 + Current sample, line, band is: 113 19 1 + Current sample, line, band is: 113 20 1 + Current sample, line, band is: 113 21 1 + Current sample, line, band is: 113 22 1 + Current sample, line, band is: 113 23 1 + Current sample, line, band is: 113 24 1 + Current sample, line, band is: 113 25 1 + Current sample, line, band is: 113 26 1 + Current sample, line, band is: 113 27 1 + Current sample, line, band is: 113 28 1 + Current sample, line, band is: 113 29 1 + Current sample, line, band is: 113 30 1 + Current sample, line, band is: 113 31 1 + Current sample, line, band is: 113 32 1 + Current sample, line, band is: 113 33 1 + Current sample, line, band is: 113 34 1 + Current sample, line, band is: 113 35 1 + Current sample, line, band is: 113 36 1 + Current sample, line, band is: 113 37 1 + Current sample, line, band is: 113 38 1 + Current sample, line, band is: 113 39 1 + Current sample, line, band is: 113 40 1 + Current sample, line, band is: 113 41 1 + Current sample, line, band is: 113 42 1 + Current sample, line, band is: 113 43 1 + Current sample, line, band is: 113 44 1 + Current sample, line, band is: 113 45 1 + Current sample, line, band is: 113 46 1 + Current sample, line, band is: 113 47 1 + Current sample, line, band is: 113 48 1 + Current sample, line, band is: 113 49 1 + Current sample, line, band is: 113 50 1 + Current sample, line, band is: 113 51 1 + Current sample, line, band is: 113 52 1 + Current sample, line, band is: 113 53 1 + Current sample, line, band is: 113 54 1 + Current sample, line, band is: 113 55 1 + Current sample, line, band is: 113 56 1 + Current sample, line, band is: 113 57 1 + Current sample, line, band is: 113 58 1 + Current sample, line, band is: 113 59 1 + Current sample, line, band is: 113 60 1 + Current sample, line, band is: 113 61 1 + Current sample, line, band is: 113 62 1 + Current sample, line, band is: 113 63 1 + Current sample, line, band is: 113 64 1 + Current sample, line, band is: 113 65 1 + Current sample, line, band is: 113 66 1 + Current sample, line, band is: 113 67 1 + Current sample, line, band is: 113 68 1 + Current sample, line, band is: 113 69 1 + Current sample, line, band is: 113 70 1 + Current sample, line, band is: 113 71 1 + Current sample, line, band is: 113 72 1 + Current sample, line, band is: 113 73 1 + Current sample, line, band is: 113 74 1 + Current sample, line, band is: 113 75 1 + Current sample, line, band is: 113 76 1 + Current sample, line, band is: 113 77 1 + Current sample, line, band is: 113 78 1 + Current sample, line, band is: 113 79 1 + Current sample, line, band is: 113 80 1 + Current sample, line, band is: 113 81 1 + Current sample, line, band is: 113 82 1 + Current sample, line, band is: 113 83 1 + Current sample, line, band is: 113 84 1 + Current sample, line, band is: 113 85 1 + Current sample, line, band is: 113 86 1 + Current sample, line, band is: 113 87 1 + Current sample, line, band is: 113 88 1 + Current sample, line, band is: 113 89 1 + Current sample, line, band is: 113 90 1 + Current sample, line, band is: 113 91 1 + Current sample, line, band is: 113 92 1 + Current sample, line, band is: 113 93 1 + Current sample, line, band is: 113 94 1 + Current sample, line, band is: 113 95 1 + Current sample, line, band is: 113 96 1 + Current sample, line, band is: 113 97 1 + Current sample, line, band is: 113 98 1 + Current sample, line, band is: 113 99 1 + Current sample, line, band is: 113 100 1 + Current sample, line, band is: 113 101 1 + Current sample, line, band is: 113 102 1 + Current sample, line, band is: 113 103 1 + Current sample, line, band is: 113 104 1 + Current sample, line, band is: 113 105 1 + Current sample, line, band is: 113 106 1 + Current sample, line, band is: 113 107 1 + Current sample, line, band is: 113 108 1 + Current sample, line, band is: 113 109 1 + Current sample, line, band is: 113 110 1 + Current sample, line, band is: 113 111 1 + Current sample, line, band is: 113 112 1 + Current sample, line, band is: 113 113 1 + Current sample, line, band is: 113 114 1 + Current sample, line, band is: 113 115 1 + Current sample, line, band is: 113 116 1 + Current sample, line, band is: 113 117 1 + Current sample, line, band is: 113 118 1 + Current sample, line, band is: 113 119 1 + Current sample, line, band is: 113 120 1 + Current sample, line, band is: 113 121 1 + Current sample, line, band is: 113 122 1 + Current sample, line, band is: 113 123 1 + Current sample, line, band is: 113 124 1 + Current sample, line, band is: 113 125 1 + Current sample, line, band is: 113 126 1 + Current sample, line, band is: 114 1 1 + Current sample, line, band is: 114 2 1 + Current sample, line, band is: 114 3 1 + Current sample, line, band is: 114 4 1 + Current sample, line, band is: 114 5 1 + Current sample, line, band is: 114 6 1 + Current sample, line, band is: 114 7 1 + Current sample, line, band is: 114 8 1 + Current sample, line, band is: 114 9 1 + Current sample, line, band is: 114 10 1 + Current sample, line, band is: 114 11 1 + Current sample, line, band is: 114 12 1 + Current sample, line, band is: 114 13 1 + Current sample, line, band is: 114 14 1 + Current sample, line, band is: 114 15 1 + Current sample, line, band is: 114 16 1 + Current sample, line, band is: 114 17 1 + Current sample, line, band is: 114 18 1 + Current sample, line, band is: 114 19 1 + Current sample, line, band is: 114 20 1 + Current sample, line, band is: 114 21 1 + Current sample, line, band is: 114 22 1 + Current sample, line, band is: 114 23 1 + Current sample, line, band is: 114 24 1 + Current sample, line, band is: 114 25 1 + Current sample, line, band is: 114 26 1 + Current sample, line, band is: 114 27 1 + Current sample, line, band is: 114 28 1 + Current sample, line, band is: 114 29 1 + Current sample, line, band is: 114 30 1 + Current sample, line, band is: 114 31 1 + Current sample, line, band is: 114 32 1 + Current sample, line, band is: 114 33 1 + Current sample, line, band is: 114 34 1 + Current sample, line, band is: 114 35 1 + Current sample, line, band is: 114 36 1 + Current sample, line, band is: 114 37 1 + Current sample, line, band is: 114 38 1 + Current sample, line, band is: 114 39 1 + Current sample, line, band is: 114 40 1 + Current sample, line, band is: 114 41 1 + Current sample, line, band is: 114 42 1 + Current sample, line, band is: 114 43 1 + Current sample, line, band is: 114 44 1 + Current sample, line, band is: 114 45 1 + Current sample, line, band is: 114 46 1 + Current sample, line, band is: 114 47 1 + Current sample, line, band is: 114 48 1 + Current sample, line, band is: 114 49 1 + Current sample, line, band is: 114 50 1 + Current sample, line, band is: 114 51 1 + Current sample, line, band is: 114 52 1 + Current sample, line, band is: 114 53 1 + Current sample, line, band is: 114 54 1 + Current sample, line, band is: 114 55 1 + Current sample, line, band is: 114 56 1 + Current sample, line, band is: 114 57 1 + Current sample, line, band is: 114 58 1 + Current sample, line, band is: 114 59 1 + Current sample, line, band is: 114 60 1 + Current sample, line, band is: 114 61 1 + Current sample, line, band is: 114 62 1 + Current sample, line, band is: 114 63 1 + Current sample, line, band is: 114 64 1 + Current sample, line, band is: 114 65 1 + Current sample, line, band is: 114 66 1 + Current sample, line, band is: 114 67 1 + Current sample, line, band is: 114 68 1 + Current sample, line, band is: 114 69 1 + Current sample, line, band is: 114 70 1 + Current sample, line, band is: 114 71 1 + Current sample, line, band is: 114 72 1 + Current sample, line, band is: 114 73 1 + Current sample, line, band is: 114 74 1 + Current sample, line, band is: 114 75 1 + Current sample, line, band is: 114 76 1 + Current sample, line, band is: 114 77 1 + Current sample, line, band is: 114 78 1 + Current sample, line, band is: 114 79 1 + Current sample, line, band is: 114 80 1 + Current sample, line, band is: 114 81 1 + Current sample, line, band is: 114 82 1 + Current sample, line, band is: 114 83 1 + Current sample, line, band is: 114 84 1 + Current sample, line, band is: 114 85 1 + Current sample, line, band is: 114 86 1 + Current sample, line, band is: 114 87 1 + Current sample, line, band is: 114 88 1 + Current sample, line, band is: 114 89 1 + Current sample, line, band is: 114 90 1 + Current sample, line, band is: 114 91 1 + Current sample, line, band is: 114 92 1 + Current sample, line, band is: 114 93 1 + Current sample, line, band is: 114 94 1 + Current sample, line, band is: 114 95 1 + Current sample, line, band is: 114 96 1 + Current sample, line, band is: 114 97 1 + Current sample, line, band is: 114 98 1 + Current sample, line, band is: 114 99 1 + Current sample, line, band is: 114 100 1 + Current sample, line, band is: 114 101 1 + Current sample, line, band is: 114 102 1 + Current sample, line, band is: 114 103 1 + Current sample, line, band is: 114 104 1 + Current sample, line, band is: 114 105 1 + Current sample, line, band is: 114 106 1 + Current sample, line, band is: 114 107 1 + Current sample, line, band is: 114 108 1 + Current sample, line, band is: 114 109 1 + Current sample, line, band is: 114 110 1 + Current sample, line, band is: 114 111 1 + Current sample, line, band is: 114 112 1 + Current sample, line, band is: 114 113 1 + Current sample, line, band is: 114 114 1 + Current sample, line, band is: 114 115 1 + Current sample, line, band is: 114 116 1 + Current sample, line, band is: 114 117 1 + Current sample, line, band is: 114 118 1 + Current sample, line, band is: 114 119 1 + Current sample, line, band is: 114 120 1 + Current sample, line, band is: 114 121 1 + Current sample, line, band is: 114 122 1 + Current sample, line, band is: 114 123 1 + Current sample, line, band is: 114 124 1 + Current sample, line, band is: 114 125 1 + Current sample, line, band is: 114 126 1 + Current sample, line, band is: 115 1 1 + Current sample, line, band is: 115 2 1 + Current sample, line, band is: 115 3 1 + Current sample, line, band is: 115 4 1 + Current sample, line, band is: 115 5 1 + Current sample, line, band is: 115 6 1 + Current sample, line, band is: 115 7 1 + Current sample, line, band is: 115 8 1 + Current sample, line, band is: 115 9 1 + Current sample, line, band is: 115 10 1 + Current sample, line, band is: 115 11 1 + Current sample, line, band is: 115 12 1 + Current sample, line, band is: 115 13 1 + Current sample, line, band is: 115 14 1 + Current sample, line, band is: 115 15 1 + Current sample, line, band is: 115 16 1 + Current sample, line, band is: 115 17 1 + Current sample, line, band is: 115 18 1 + Current sample, line, band is: 115 19 1 + Current sample, line, band is: 115 20 1 + Current sample, line, band is: 115 21 1 + Current sample, line, band is: 115 22 1 + Current sample, line, band is: 115 23 1 + Current sample, line, band is: 115 24 1 + Current sample, line, band is: 115 25 1 + Current sample, line, band is: 115 26 1 + Current sample, line, band is: 115 27 1 + Current sample, line, band is: 115 28 1 + Current sample, line, band is: 115 29 1 + Current sample, line, band is: 115 30 1 + Current sample, line, band is: 115 31 1 + Current sample, line, band is: 115 32 1 + Current sample, line, band is: 115 33 1 + Current sample, line, band is: 115 34 1 + Current sample, line, band is: 115 35 1 + Current sample, line, band is: 115 36 1 + Current sample, line, band is: 115 37 1 + Current sample, line, band is: 115 38 1 + Current sample, line, band is: 115 39 1 + Current sample, line, band is: 115 40 1 + Current sample, line, band is: 115 41 1 + Current sample, line, band is: 115 42 1 + Current sample, line, band is: 115 43 1 + Current sample, line, band is: 115 44 1 + Current sample, line, band is: 115 45 1 + Current sample, line, band is: 115 46 1 + Current sample, line, band is: 115 47 1 + Current sample, line, band is: 115 48 1 + Current sample, line, band is: 115 49 1 + Current sample, line, band is: 115 50 1 + Current sample, line, band is: 115 51 1 + Current sample, line, band is: 115 52 1 + Current sample, line, band is: 115 53 1 + Current sample, line, band is: 115 54 1 + Current sample, line, band is: 115 55 1 + Current sample, line, band is: 115 56 1 + Current sample, line, band is: 115 57 1 + Current sample, line, band is: 115 58 1 + Current sample, line, band is: 115 59 1 + Current sample, line, band is: 115 60 1 + Current sample, line, band is: 115 61 1 + Current sample, line, band is: 115 62 1 + Current sample, line, band is: 115 63 1 + Current sample, line, band is: 115 64 1 + Current sample, line, band is: 115 65 1 + Current sample, line, band is: 115 66 1 + Current sample, line, band is: 115 67 1 + Current sample, line, band is: 115 68 1 + Current sample, line, band is: 115 69 1 + Current sample, line, band is: 115 70 1 + Current sample, line, band is: 115 71 1 + Current sample, line, band is: 115 72 1 + Current sample, line, band is: 115 73 1 + Current sample, line, band is: 115 74 1 + Current sample, line, band is: 115 75 1 + Current sample, line, band is: 115 76 1 + Current sample, line, band is: 115 77 1 + Current sample, line, band is: 115 78 1 + Current sample, line, band is: 115 79 1 + Current sample, line, band is: 115 80 1 + Current sample, line, band is: 115 81 1 + Current sample, line, band is: 115 82 1 + Current sample, line, band is: 115 83 1 + Current sample, line, band is: 115 84 1 + Current sample, line, band is: 115 85 1 + Current sample, line, band is: 115 86 1 + Current sample, line, band is: 115 87 1 + Current sample, line, band is: 115 88 1 + Current sample, line, band is: 115 89 1 + Current sample, line, band is: 115 90 1 + Current sample, line, band is: 115 91 1 + Current sample, line, band is: 115 92 1 + Current sample, line, band is: 115 93 1 + Current sample, line, band is: 115 94 1 + Current sample, line, band is: 115 95 1 + Current sample, line, band is: 115 96 1 + Current sample, line, band is: 115 97 1 + Current sample, line, band is: 115 98 1 + Current sample, line, band is: 115 99 1 + Current sample, line, band is: 115 100 1 + Current sample, line, band is: 115 101 1 + Current sample, line, band is: 115 102 1 + Current sample, line, band is: 115 103 1 + Current sample, line, band is: 115 104 1 + Current sample, line, band is: 115 105 1 + Current sample, line, band is: 115 106 1 + Current sample, line, band is: 115 107 1 + Current sample, line, band is: 115 108 1 + Current sample, line, band is: 115 109 1 + Current sample, line, band is: 115 110 1 + Current sample, line, band is: 115 111 1 + Current sample, line, band is: 115 112 1 + Current sample, line, band is: 115 113 1 + Current sample, line, band is: 115 114 1 + Current sample, line, band is: 115 115 1 + Current sample, line, band is: 115 116 1 + Current sample, line, band is: 115 117 1 + Current sample, line, band is: 115 118 1 + Current sample, line, band is: 115 119 1 + Current sample, line, band is: 115 120 1 + Current sample, line, band is: 115 121 1 + Current sample, line, band is: 115 122 1 + Current sample, line, band is: 115 123 1 + Current sample, line, band is: 115 124 1 + Current sample, line, band is: 115 125 1 + Current sample, line, band is: 115 126 1 + Current sample, line, band is: 116 1 1 + Current sample, line, band is: 116 2 1 + Current sample, line, band is: 116 3 1 + Current sample, line, band is: 116 4 1 + Current sample, line, band is: 116 5 1 + Current sample, line, band is: 116 6 1 + Current sample, line, band is: 116 7 1 + Current sample, line, band is: 116 8 1 + Current sample, line, band is: 116 9 1 + Current sample, line, band is: 116 10 1 + Current sample, line, band is: 116 11 1 + Current sample, line, band is: 116 12 1 + Current sample, line, band is: 116 13 1 + Current sample, line, band is: 116 14 1 + Current sample, line, band is: 116 15 1 + Current sample, line, band is: 116 16 1 + Current sample, line, band is: 116 17 1 + Current sample, line, band is: 116 18 1 + Current sample, line, band is: 116 19 1 + Current sample, line, band is: 116 20 1 + Current sample, line, band is: 116 21 1 + Current sample, line, band is: 116 22 1 + Current sample, line, band is: 116 23 1 + Current sample, line, band is: 116 24 1 + Current sample, line, band is: 116 25 1 + Current sample, line, band is: 116 26 1 + Current sample, line, band is: 116 27 1 + Current sample, line, band is: 116 28 1 + Current sample, line, band is: 116 29 1 + Current sample, line, band is: 116 30 1 + Current sample, line, band is: 116 31 1 + Current sample, line, band is: 116 32 1 + Current sample, line, band is: 116 33 1 + Current sample, line, band is: 116 34 1 + Current sample, line, band is: 116 35 1 + Current sample, line, band is: 116 36 1 + Current sample, line, band is: 116 37 1 + Current sample, line, band is: 116 38 1 + Current sample, line, band is: 116 39 1 + Current sample, line, band is: 116 40 1 + Current sample, line, band is: 116 41 1 + Current sample, line, band is: 116 42 1 + Current sample, line, band is: 116 43 1 + Current sample, line, band is: 116 44 1 + Current sample, line, band is: 116 45 1 + Current sample, line, band is: 116 46 1 + Current sample, line, band is: 116 47 1 + Current sample, line, band is: 116 48 1 + Current sample, line, band is: 116 49 1 + Current sample, line, band is: 116 50 1 + Current sample, line, band is: 116 51 1 + Current sample, line, band is: 116 52 1 + Current sample, line, band is: 116 53 1 + Current sample, line, band is: 116 54 1 + Current sample, line, band is: 116 55 1 + Current sample, line, band is: 116 56 1 + Current sample, line, band is: 116 57 1 + Current sample, line, band is: 116 58 1 + Current sample, line, band is: 116 59 1 + Current sample, line, band is: 116 60 1 + Current sample, line, band is: 116 61 1 + Current sample, line, band is: 116 62 1 + Current sample, line, band is: 116 63 1 + Current sample, line, band is: 116 64 1 + Current sample, line, band is: 116 65 1 + Current sample, line, band is: 116 66 1 + Current sample, line, band is: 116 67 1 + Current sample, line, band is: 116 68 1 + Current sample, line, band is: 116 69 1 + Current sample, line, band is: 116 70 1 + Current sample, line, band is: 116 71 1 + Current sample, line, band is: 116 72 1 + Current sample, line, band is: 116 73 1 + Current sample, line, band is: 116 74 1 + Current sample, line, band is: 116 75 1 + Current sample, line, band is: 116 76 1 + Current sample, line, band is: 116 77 1 + Current sample, line, band is: 116 78 1 + Current sample, line, band is: 116 79 1 + Current sample, line, band is: 116 80 1 + Current sample, line, band is: 116 81 1 + Current sample, line, band is: 116 82 1 + Current sample, line, band is: 116 83 1 + Current sample, line, band is: 116 84 1 + Current sample, line, band is: 116 85 1 + Current sample, line, band is: 116 86 1 + Current sample, line, band is: 116 87 1 + Current sample, line, band is: 116 88 1 + Current sample, line, band is: 116 89 1 + Current sample, line, band is: 116 90 1 + Current sample, line, band is: 116 91 1 + Current sample, line, band is: 116 92 1 + Current sample, line, band is: 116 93 1 + Current sample, line, band is: 116 94 1 + Current sample, line, band is: 116 95 1 + Current sample, line, band is: 116 96 1 + Current sample, line, band is: 116 97 1 + Current sample, line, band is: 116 98 1 + Current sample, line, band is: 116 99 1 + Current sample, line, band is: 116 100 1 + Current sample, line, band is: 116 101 1 + Current sample, line, band is: 116 102 1 + Current sample, line, band is: 116 103 1 + Current sample, line, band is: 116 104 1 + Current sample, line, band is: 116 105 1 + Current sample, line, band is: 116 106 1 + Current sample, line, band is: 116 107 1 + Current sample, line, band is: 116 108 1 + Current sample, line, band is: 116 109 1 + Current sample, line, band is: 116 110 1 + Current sample, line, band is: 116 111 1 + Current sample, line, band is: 116 112 1 + Current sample, line, band is: 116 113 1 + Current sample, line, band is: 116 114 1 + Current sample, line, band is: 116 115 1 + Current sample, line, band is: 116 116 1 + Current sample, line, band is: 116 117 1 + Current sample, line, band is: 116 118 1 + Current sample, line, band is: 116 119 1 + Current sample, line, band is: 116 120 1 + Current sample, line, band is: 116 121 1 + Current sample, line, band is: 116 122 1 + Current sample, line, band is: 116 123 1 + Current sample, line, band is: 116 124 1 + Current sample, line, band is: 116 125 1 + Current sample, line, band is: 116 126 1 + Current sample, line, band is: 117 1 1 + Current sample, line, band is: 117 2 1 + Current sample, line, band is: 117 3 1 + Current sample, line, band is: 117 4 1 + Current sample, line, band is: 117 5 1 + Current sample, line, band is: 117 6 1 + Current sample, line, band is: 117 7 1 + Current sample, line, band is: 117 8 1 + Current sample, line, band is: 117 9 1 + Current sample, line, band is: 117 10 1 + Current sample, line, band is: 117 11 1 + Current sample, line, band is: 117 12 1 + Current sample, line, band is: 117 13 1 + Current sample, line, band is: 117 14 1 + Current sample, line, band is: 117 15 1 + Current sample, line, band is: 117 16 1 + Current sample, line, band is: 117 17 1 + Current sample, line, band is: 117 18 1 + Current sample, line, band is: 117 19 1 + Current sample, line, band is: 117 20 1 + Current sample, line, band is: 117 21 1 + Current sample, line, band is: 117 22 1 + Current sample, line, band is: 117 23 1 + Current sample, line, band is: 117 24 1 + Current sample, line, band is: 117 25 1 + Current sample, line, band is: 117 26 1 + Current sample, line, band is: 117 27 1 + Current sample, line, band is: 117 28 1 + Current sample, line, band is: 117 29 1 + Current sample, line, band is: 117 30 1 + Current sample, line, band is: 117 31 1 + Current sample, line, band is: 117 32 1 + Current sample, line, band is: 117 33 1 + Current sample, line, band is: 117 34 1 + Current sample, line, band is: 117 35 1 + Current sample, line, band is: 117 36 1 + Current sample, line, band is: 117 37 1 + Current sample, line, band is: 117 38 1 + Current sample, line, band is: 117 39 1 + Current sample, line, band is: 117 40 1 + Current sample, line, band is: 117 41 1 + Current sample, line, band is: 117 42 1 + Current sample, line, band is: 117 43 1 + Current sample, line, band is: 117 44 1 + Current sample, line, band is: 117 45 1 + Current sample, line, band is: 117 46 1 + Current sample, line, band is: 117 47 1 + Current sample, line, band is: 117 48 1 + Current sample, line, band is: 117 49 1 + Current sample, line, band is: 117 50 1 + Current sample, line, band is: 117 51 1 + Current sample, line, band is: 117 52 1 + Current sample, line, band is: 117 53 1 + Current sample, line, band is: 117 54 1 + Current sample, line, band is: 117 55 1 + Current sample, line, band is: 117 56 1 + Current sample, line, band is: 117 57 1 + Current sample, line, band is: 117 58 1 + Current sample, line, band is: 117 59 1 + Current sample, line, band is: 117 60 1 + Current sample, line, band is: 117 61 1 + Current sample, line, band is: 117 62 1 + Current sample, line, band is: 117 63 1 + Current sample, line, band is: 117 64 1 + Current sample, line, band is: 117 65 1 + Current sample, line, band is: 117 66 1 + Current sample, line, band is: 117 67 1 + Current sample, line, band is: 117 68 1 + Current sample, line, band is: 117 69 1 + Current sample, line, band is: 117 70 1 + Current sample, line, band is: 117 71 1 + Current sample, line, band is: 117 72 1 + Current sample, line, band is: 117 73 1 + Current sample, line, band is: 117 74 1 + Current sample, line, band is: 117 75 1 + Current sample, line, band is: 117 76 1 + Current sample, line, band is: 117 77 1 + Current sample, line, band is: 117 78 1 + Current sample, line, band is: 117 79 1 + Current sample, line, band is: 117 80 1 + Current sample, line, band is: 117 81 1 + Current sample, line, band is: 117 82 1 + Current sample, line, band is: 117 83 1 + Current sample, line, band is: 117 84 1 + Current sample, line, band is: 117 85 1 + Current sample, line, band is: 117 86 1 + Current sample, line, band is: 117 87 1 + Current sample, line, band is: 117 88 1 + Current sample, line, band is: 117 89 1 + Current sample, line, band is: 117 90 1 + Current sample, line, band is: 117 91 1 + Current sample, line, band is: 117 92 1 + Current sample, line, band is: 117 93 1 + Current sample, line, band is: 117 94 1 + Current sample, line, band is: 117 95 1 + Current sample, line, band is: 117 96 1 + Current sample, line, band is: 117 97 1 + Current sample, line, band is: 117 98 1 + Current sample, line, band is: 117 99 1 + Current sample, line, band is: 117 100 1 + Current sample, line, band is: 117 101 1 + Current sample, line, band is: 117 102 1 + Current sample, line, band is: 117 103 1 + Current sample, line, band is: 117 104 1 + Current sample, line, band is: 117 105 1 + Current sample, line, band is: 117 106 1 + Current sample, line, band is: 117 107 1 + Current sample, line, band is: 117 108 1 + Current sample, line, band is: 117 109 1 + Current sample, line, band is: 117 110 1 + Current sample, line, band is: 117 111 1 + Current sample, line, band is: 117 112 1 + Current sample, line, band is: 117 113 1 + Current sample, line, band is: 117 114 1 + Current sample, line, band is: 117 115 1 + Current sample, line, band is: 117 116 1 + Current sample, line, band is: 117 117 1 + Current sample, line, band is: 117 118 1 + Current sample, line, band is: 117 119 1 + Current sample, line, band is: 117 120 1 + Current sample, line, band is: 117 121 1 + Current sample, line, band is: 117 122 1 + Current sample, line, band is: 117 123 1 + Current sample, line, band is: 117 124 1 + Current sample, line, band is: 117 125 1 + Current sample, line, band is: 117 126 1 + Current sample, line, band is: 118 1 1 + Current sample, line, band is: 118 2 1 + Current sample, line, band is: 118 3 1 + Current sample, line, band is: 118 4 1 + Current sample, line, band is: 118 5 1 + Current sample, line, band is: 118 6 1 + Current sample, line, band is: 118 7 1 + Current sample, line, band is: 118 8 1 + Current sample, line, band is: 118 9 1 + Current sample, line, band is: 118 10 1 + Current sample, line, band is: 118 11 1 + Current sample, line, band is: 118 12 1 + Current sample, line, band is: 118 13 1 + Current sample, line, band is: 118 14 1 + Current sample, line, band is: 118 15 1 + Current sample, line, band is: 118 16 1 + Current sample, line, band is: 118 17 1 + Current sample, line, band is: 118 18 1 + Current sample, line, band is: 118 19 1 + Current sample, line, band is: 118 20 1 + Current sample, line, band is: 118 21 1 + Current sample, line, band is: 118 22 1 + Current sample, line, band is: 118 23 1 + Current sample, line, band is: 118 24 1 + Current sample, line, band is: 118 25 1 + Current sample, line, band is: 118 26 1 + Current sample, line, band is: 118 27 1 + Current sample, line, band is: 118 28 1 + Current sample, line, band is: 118 29 1 + Current sample, line, band is: 118 30 1 + Current sample, line, band is: 118 31 1 + Current sample, line, band is: 118 32 1 + Current sample, line, band is: 118 33 1 + Current sample, line, band is: 118 34 1 + Current sample, line, band is: 118 35 1 + Current sample, line, band is: 118 36 1 + Current sample, line, band is: 118 37 1 + Current sample, line, band is: 118 38 1 + Current sample, line, band is: 118 39 1 + Current sample, line, band is: 118 40 1 + Current sample, line, band is: 118 41 1 + Current sample, line, band is: 118 42 1 + Current sample, line, band is: 118 43 1 + Current sample, line, band is: 118 44 1 + Current sample, line, band is: 118 45 1 + Current sample, line, band is: 118 46 1 + Current sample, line, band is: 118 47 1 + Current sample, line, band is: 118 48 1 + Current sample, line, band is: 118 49 1 + Current sample, line, band is: 118 50 1 + Current sample, line, band is: 118 51 1 + Current sample, line, band is: 118 52 1 + Current sample, line, band is: 118 53 1 + Current sample, line, band is: 118 54 1 + Current sample, line, band is: 118 55 1 + Current sample, line, band is: 118 56 1 + Current sample, line, band is: 118 57 1 + Current sample, line, band is: 118 58 1 + Current sample, line, band is: 118 59 1 + Current sample, line, band is: 118 60 1 + Current sample, line, band is: 118 61 1 + Current sample, line, band is: 118 62 1 + Current sample, line, band is: 118 63 1 + Current sample, line, band is: 118 64 1 + Current sample, line, band is: 118 65 1 + Current sample, line, band is: 118 66 1 + Current sample, line, band is: 118 67 1 + Current sample, line, band is: 118 68 1 + Current sample, line, band is: 118 69 1 + Current sample, line, band is: 118 70 1 + Current sample, line, band is: 118 71 1 + Current sample, line, band is: 118 72 1 + Current sample, line, band is: 118 73 1 + Current sample, line, band is: 118 74 1 + Current sample, line, band is: 118 75 1 + Current sample, line, band is: 118 76 1 + Current sample, line, band is: 118 77 1 + Current sample, line, band is: 118 78 1 + Current sample, line, band is: 118 79 1 + Current sample, line, band is: 118 80 1 + Current sample, line, band is: 118 81 1 + Current sample, line, band is: 118 82 1 + Current sample, line, band is: 118 83 1 + Current sample, line, band is: 118 84 1 + Current sample, line, band is: 118 85 1 + Current sample, line, band is: 118 86 1 + Current sample, line, band is: 118 87 1 + Current sample, line, band is: 118 88 1 + Current sample, line, band is: 118 89 1 + Current sample, line, band is: 118 90 1 + Current sample, line, band is: 118 91 1 + Current sample, line, band is: 118 92 1 + Current sample, line, band is: 118 93 1 + Current sample, line, band is: 118 94 1 + Current sample, line, band is: 118 95 1 + Current sample, line, band is: 118 96 1 + Current sample, line, band is: 118 97 1 + Current sample, line, band is: 118 98 1 + Current sample, line, band is: 118 99 1 + Current sample, line, band is: 118 100 1 + Current sample, line, band is: 118 101 1 + Current sample, line, band is: 118 102 1 + Current sample, line, band is: 118 103 1 + Current sample, line, band is: 118 104 1 + Current sample, line, band is: 118 105 1 + Current sample, line, band is: 118 106 1 + Current sample, line, band is: 118 107 1 + Current sample, line, band is: 118 108 1 + Current sample, line, band is: 118 109 1 + Current sample, line, band is: 118 110 1 + Current sample, line, band is: 118 111 1 + Current sample, line, band is: 118 112 1 + Current sample, line, band is: 118 113 1 + Current sample, line, band is: 118 114 1 + Current sample, line, band is: 118 115 1 + Current sample, line, band is: 118 116 1 + Current sample, line, band is: 118 117 1 + Current sample, line, band is: 118 118 1 + Current sample, line, band is: 118 119 1 + Current sample, line, band is: 118 120 1 + Current sample, line, band is: 118 121 1 + Current sample, line, band is: 118 122 1 + Current sample, line, band is: 118 123 1 + Current sample, line, band is: 118 124 1 + Current sample, line, band is: 118 125 1 + Current sample, line, band is: 118 126 1 + Current sample, line, band is: 119 1 1 + Current sample, line, band is: 119 2 1 + Current sample, line, band is: 119 3 1 + Current sample, line, band is: 119 4 1 + Current sample, line, band is: 119 5 1 + Current sample, line, band is: 119 6 1 + Current sample, line, band is: 119 7 1 + Current sample, line, band is: 119 8 1 + Current sample, line, band is: 119 9 1 + Current sample, line, band is: 119 10 1 + Current sample, line, band is: 119 11 1 + Current sample, line, band is: 119 12 1 + Current sample, line, band is: 119 13 1 + Current sample, line, band is: 119 14 1 + Current sample, line, band is: 119 15 1 + Current sample, line, band is: 119 16 1 + Current sample, line, band is: 119 17 1 + Current sample, line, band is: 119 18 1 + Current sample, line, band is: 119 19 1 + Current sample, line, band is: 119 20 1 + Current sample, line, band is: 119 21 1 + Current sample, line, band is: 119 22 1 + Current sample, line, band is: 119 23 1 + Current sample, line, band is: 119 24 1 + Current sample, line, band is: 119 25 1 + Current sample, line, band is: 119 26 1 + Current sample, line, band is: 119 27 1 + Current sample, line, band is: 119 28 1 + Current sample, line, band is: 119 29 1 + Current sample, line, band is: 119 30 1 + Current sample, line, band is: 119 31 1 + Current sample, line, band is: 119 32 1 + Current sample, line, band is: 119 33 1 + Current sample, line, band is: 119 34 1 + Current sample, line, band is: 119 35 1 + Current sample, line, band is: 119 36 1 + Current sample, line, band is: 119 37 1 + Current sample, line, band is: 119 38 1 + Current sample, line, band is: 119 39 1 + Current sample, line, band is: 119 40 1 + Current sample, line, band is: 119 41 1 + Current sample, line, band is: 119 42 1 + Current sample, line, band is: 119 43 1 + Current sample, line, band is: 119 44 1 + Current sample, line, band is: 119 45 1 + Current sample, line, band is: 119 46 1 + Current sample, line, band is: 119 47 1 + Current sample, line, band is: 119 48 1 + Current sample, line, band is: 119 49 1 + Current sample, line, band is: 119 50 1 + Current sample, line, band is: 119 51 1 + Current sample, line, band is: 119 52 1 + Current sample, line, band is: 119 53 1 + Current sample, line, band is: 119 54 1 + Current sample, line, band is: 119 55 1 + Current sample, line, band is: 119 56 1 + Current sample, line, band is: 119 57 1 + Current sample, line, band is: 119 58 1 + Current sample, line, band is: 119 59 1 + Current sample, line, band is: 119 60 1 + Current sample, line, band is: 119 61 1 + Current sample, line, band is: 119 62 1 + Current sample, line, band is: 119 63 1 + Current sample, line, band is: 119 64 1 + Current sample, line, band is: 119 65 1 + Current sample, line, band is: 119 66 1 + Current sample, line, band is: 119 67 1 + Current sample, line, band is: 119 68 1 + Current sample, line, band is: 119 69 1 + Current sample, line, band is: 119 70 1 + Current sample, line, band is: 119 71 1 + Current sample, line, band is: 119 72 1 + Current sample, line, band is: 119 73 1 + Current sample, line, band is: 119 74 1 + Current sample, line, band is: 119 75 1 + Current sample, line, band is: 119 76 1 + Current sample, line, band is: 119 77 1 + Current sample, line, band is: 119 78 1 + Current sample, line, band is: 119 79 1 + Current sample, line, band is: 119 80 1 + Current sample, line, band is: 119 81 1 + Current sample, line, band is: 119 82 1 + Current sample, line, band is: 119 83 1 + Current sample, line, band is: 119 84 1 + Current sample, line, band is: 119 85 1 + Current sample, line, band is: 119 86 1 + Current sample, line, band is: 119 87 1 + Current sample, line, band is: 119 88 1 + Current sample, line, band is: 119 89 1 + Current sample, line, band is: 119 90 1 + Current sample, line, band is: 119 91 1 + Current sample, line, band is: 119 92 1 + Current sample, line, band is: 119 93 1 + Current sample, line, band is: 119 94 1 + Current sample, line, band is: 119 95 1 + Current sample, line, band is: 119 96 1 + Current sample, line, band is: 119 97 1 + Current sample, line, band is: 119 98 1 + Current sample, line, band is: 119 99 1 + Current sample, line, band is: 119 100 1 + Current sample, line, band is: 119 101 1 + Current sample, line, band is: 119 102 1 + Current sample, line, band is: 119 103 1 + Current sample, line, band is: 119 104 1 + Current sample, line, band is: 119 105 1 + Current sample, line, band is: 119 106 1 + Current sample, line, band is: 119 107 1 + Current sample, line, band is: 119 108 1 + Current sample, line, band is: 119 109 1 + Current sample, line, band is: 119 110 1 + Current sample, line, band is: 119 111 1 + Current sample, line, band is: 119 112 1 + Current sample, line, band is: 119 113 1 + Current sample, line, band is: 119 114 1 + Current sample, line, band is: 119 115 1 + Current sample, line, band is: 119 116 1 + Current sample, line, band is: 119 117 1 + Current sample, line, band is: 119 118 1 + Current sample, line, band is: 119 119 1 + Current sample, line, band is: 119 120 1 + Current sample, line, band is: 119 121 1 + Current sample, line, band is: 119 122 1 + Current sample, line, band is: 119 123 1 + Current sample, line, band is: 119 124 1 + Current sample, line, band is: 119 125 1 + Current sample, line, band is: 119 126 1 + Current sample, line, band is: 120 1 1 + Current sample, line, band is: 120 2 1 + Current sample, line, band is: 120 3 1 + Current sample, line, band is: 120 4 1 + Current sample, line, band is: 120 5 1 + Current sample, line, band is: 120 6 1 + Current sample, line, band is: 120 7 1 + Current sample, line, band is: 120 8 1 + Current sample, line, band is: 120 9 1 + Current sample, line, band is: 120 10 1 + Current sample, line, band is: 120 11 1 + Current sample, line, band is: 120 12 1 + Current sample, line, band is: 120 13 1 + Current sample, line, band is: 120 14 1 + Current sample, line, band is: 120 15 1 + Current sample, line, band is: 120 16 1 + Current sample, line, band is: 120 17 1 + Current sample, line, band is: 120 18 1 + Current sample, line, band is: 120 19 1 + Current sample, line, band is: 120 20 1 + Current sample, line, band is: 120 21 1 + Current sample, line, band is: 120 22 1 + Current sample, line, band is: 120 23 1 + Current sample, line, band is: 120 24 1 + Current sample, line, band is: 120 25 1 + Current sample, line, band is: 120 26 1 + Current sample, line, band is: 120 27 1 + Current sample, line, band is: 120 28 1 + Current sample, line, band is: 120 29 1 + Current sample, line, band is: 120 30 1 + Current sample, line, band is: 120 31 1 + Current sample, line, band is: 120 32 1 + Current sample, line, band is: 120 33 1 + Current sample, line, band is: 120 34 1 + Current sample, line, band is: 120 35 1 + Current sample, line, band is: 120 36 1 + Current sample, line, band is: 120 37 1 + Current sample, line, band is: 120 38 1 + Current sample, line, band is: 120 39 1 + Current sample, line, band is: 120 40 1 + Current sample, line, band is: 120 41 1 + Current sample, line, band is: 120 42 1 + Current sample, line, band is: 120 43 1 + Current sample, line, band is: 120 44 1 + Current sample, line, band is: 120 45 1 + Current sample, line, band is: 120 46 1 + Current sample, line, band is: 120 47 1 + Current sample, line, band is: 120 48 1 + Current sample, line, band is: 120 49 1 + Current sample, line, band is: 120 50 1 + Current sample, line, band is: 120 51 1 + Current sample, line, band is: 120 52 1 + Current sample, line, band is: 120 53 1 + Current sample, line, band is: 120 54 1 + Current sample, line, band is: 120 55 1 + Current sample, line, band is: 120 56 1 + Current sample, line, band is: 120 57 1 + Current sample, line, band is: 120 58 1 + Current sample, line, band is: 120 59 1 + Current sample, line, band is: 120 60 1 + Current sample, line, band is: 120 61 1 + Current sample, line, band is: 120 62 1 + Current sample, line, band is: 120 63 1 + Current sample, line, band is: 120 64 1 + Current sample, line, band is: 120 65 1 + Current sample, line, band is: 120 66 1 + Current sample, line, band is: 120 67 1 + Current sample, line, band is: 120 68 1 + Current sample, line, band is: 120 69 1 + Current sample, line, band is: 120 70 1 + Current sample, line, band is: 120 71 1 + Current sample, line, band is: 120 72 1 + Current sample, line, band is: 120 73 1 + Current sample, line, band is: 120 74 1 + Current sample, line, band is: 120 75 1 + Current sample, line, band is: 120 76 1 + Current sample, line, band is: 120 77 1 + Current sample, line, band is: 120 78 1 + Current sample, line, band is: 120 79 1 + Current sample, line, band is: 120 80 1 + Current sample, line, band is: 120 81 1 + Current sample, line, band is: 120 82 1 + Current sample, line, band is: 120 83 1 + Current sample, line, band is: 120 84 1 + Current sample, line, band is: 120 85 1 + Current sample, line, band is: 120 86 1 + Current sample, line, band is: 120 87 1 + Current sample, line, band is: 120 88 1 + Current sample, line, band is: 120 89 1 + Current sample, line, band is: 120 90 1 + Current sample, line, band is: 120 91 1 + Current sample, line, band is: 120 92 1 + Current sample, line, band is: 120 93 1 + Current sample, line, band is: 120 94 1 + Current sample, line, band is: 120 95 1 + Current sample, line, band is: 120 96 1 + Current sample, line, band is: 120 97 1 + Current sample, line, band is: 120 98 1 + Current sample, line, band is: 120 99 1 + Current sample, line, band is: 120 100 1 + Current sample, line, band is: 120 101 1 + Current sample, line, band is: 120 102 1 + Current sample, line, band is: 120 103 1 + Current sample, line, band is: 120 104 1 + Current sample, line, band is: 120 105 1 + Current sample, line, band is: 120 106 1 + Current sample, line, band is: 120 107 1 + Current sample, line, band is: 120 108 1 + Current sample, line, band is: 120 109 1 + Current sample, line, band is: 120 110 1 + Current sample, line, band is: 120 111 1 + Current sample, line, band is: 120 112 1 + Current sample, line, band is: 120 113 1 + Current sample, line, band is: 120 114 1 + Current sample, line, band is: 120 115 1 + Current sample, line, band is: 120 116 1 + Current sample, line, band is: 120 117 1 + Current sample, line, band is: 120 118 1 + Current sample, line, band is: 120 119 1 + Current sample, line, band is: 120 120 1 + Current sample, line, band is: 120 121 1 + Current sample, line, band is: 120 122 1 + Current sample, line, band is: 120 123 1 + Current sample, line, band is: 120 124 1 + Current sample, line, band is: 120 125 1 + Current sample, line, band is: 120 126 1 + Current sample, line, band is: 121 1 1 + Current sample, line, band is: 121 2 1 + Current sample, line, band is: 121 3 1 + Current sample, line, band is: 121 4 1 + Current sample, line, band is: 121 5 1 + Current sample, line, band is: 121 6 1 + Current sample, line, band is: 121 7 1 + Current sample, line, band is: 121 8 1 + Current sample, line, band is: 121 9 1 + Current sample, line, band is: 121 10 1 + Current sample, line, band is: 121 11 1 + Current sample, line, band is: 121 12 1 + Current sample, line, band is: 121 13 1 + Current sample, line, band is: 121 14 1 + Current sample, line, band is: 121 15 1 + Current sample, line, band is: 121 16 1 + Current sample, line, band is: 121 17 1 + Current sample, line, band is: 121 18 1 + Current sample, line, band is: 121 19 1 + Current sample, line, band is: 121 20 1 + Current sample, line, band is: 121 21 1 + Current sample, line, band is: 121 22 1 + Current sample, line, band is: 121 23 1 + Current sample, line, band is: 121 24 1 + Current sample, line, band is: 121 25 1 + Current sample, line, band is: 121 26 1 + Current sample, line, band is: 121 27 1 + Current sample, line, band is: 121 28 1 + Current sample, line, band is: 121 29 1 + Current sample, line, band is: 121 30 1 + Current sample, line, band is: 121 31 1 + Current sample, line, band is: 121 32 1 + Current sample, line, band is: 121 33 1 + Current sample, line, band is: 121 34 1 + Current sample, line, band is: 121 35 1 + Current sample, line, band is: 121 36 1 + Current sample, line, band is: 121 37 1 + Current sample, line, band is: 121 38 1 + Current sample, line, band is: 121 39 1 + Current sample, line, band is: 121 40 1 + Current sample, line, band is: 121 41 1 + Current sample, line, band is: 121 42 1 + Current sample, line, band is: 121 43 1 + Current sample, line, band is: 121 44 1 + Current sample, line, band is: 121 45 1 + Current sample, line, band is: 121 46 1 + Current sample, line, band is: 121 47 1 + Current sample, line, band is: 121 48 1 + Current sample, line, band is: 121 49 1 + Current sample, line, band is: 121 50 1 + Current sample, line, band is: 121 51 1 + Current sample, line, band is: 121 52 1 + Current sample, line, band is: 121 53 1 + Current sample, line, band is: 121 54 1 + Current sample, line, band is: 121 55 1 + Current sample, line, band is: 121 56 1 + Current sample, line, band is: 121 57 1 + Current sample, line, band is: 121 58 1 + Current sample, line, band is: 121 59 1 + Current sample, line, band is: 121 60 1 + Current sample, line, band is: 121 61 1 + Current sample, line, band is: 121 62 1 + Current sample, line, band is: 121 63 1 + Current sample, line, band is: 121 64 1 + Current sample, line, band is: 121 65 1 + Current sample, line, band is: 121 66 1 + Current sample, line, band is: 121 67 1 + Current sample, line, band is: 121 68 1 + Current sample, line, band is: 121 69 1 + Current sample, line, band is: 121 70 1 + Current sample, line, band is: 121 71 1 + Current sample, line, band is: 121 72 1 + Current sample, line, band is: 121 73 1 + Current sample, line, band is: 121 74 1 + Current sample, line, band is: 121 75 1 + Current sample, line, band is: 121 76 1 + Current sample, line, band is: 121 77 1 + Current sample, line, band is: 121 78 1 + Current sample, line, band is: 121 79 1 + Current sample, line, band is: 121 80 1 + Current sample, line, band is: 121 81 1 + Current sample, line, band is: 121 82 1 + Current sample, line, band is: 121 83 1 + Current sample, line, band is: 121 84 1 + Current sample, line, band is: 121 85 1 + Current sample, line, band is: 121 86 1 + Current sample, line, band is: 121 87 1 + Current sample, line, band is: 121 88 1 + Current sample, line, band is: 121 89 1 + Current sample, line, band is: 121 90 1 + Current sample, line, band is: 121 91 1 + Current sample, line, band is: 121 92 1 + Current sample, line, band is: 121 93 1 + Current sample, line, band is: 121 94 1 + Current sample, line, band is: 121 95 1 + Current sample, line, band is: 121 96 1 + Current sample, line, band is: 121 97 1 + Current sample, line, band is: 121 98 1 + Current sample, line, band is: 121 99 1 + Current sample, line, band is: 121 100 1 + Current sample, line, band is: 121 101 1 + Current sample, line, band is: 121 102 1 + Current sample, line, band is: 121 103 1 + Current sample, line, band is: 121 104 1 + Current sample, line, band is: 121 105 1 + Current sample, line, band is: 121 106 1 + Current sample, line, band is: 121 107 1 + Current sample, line, band is: 121 108 1 + Current sample, line, band is: 121 109 1 + Current sample, line, band is: 121 110 1 + Current sample, line, band is: 121 111 1 + Current sample, line, band is: 121 112 1 + Current sample, line, band is: 121 113 1 + Current sample, line, band is: 121 114 1 + Current sample, line, band is: 121 115 1 + Current sample, line, band is: 121 116 1 + Current sample, line, band is: 121 117 1 + Current sample, line, band is: 121 118 1 + Current sample, line, band is: 121 119 1 + Current sample, line, band is: 121 120 1 + Current sample, line, band is: 121 121 1 + Current sample, line, band is: 121 122 1 + Current sample, line, band is: 121 123 1 + Current sample, line, band is: 121 124 1 + Current sample, line, band is: 121 125 1 + Current sample, line, band is: 121 126 1 + Current sample, line, band is: 122 1 1 + Current sample, line, band is: 122 2 1 + Current sample, line, band is: 122 3 1 + Current sample, line, band is: 122 4 1 + Current sample, line, band is: 122 5 1 + Current sample, line, band is: 122 6 1 + Current sample, line, band is: 122 7 1 + Current sample, line, band is: 122 8 1 + Current sample, line, band is: 122 9 1 + Current sample, line, band is: 122 10 1 + Current sample, line, band is: 122 11 1 + Current sample, line, band is: 122 12 1 + Current sample, line, band is: 122 13 1 + Current sample, line, band is: 122 14 1 + Current sample, line, band is: 122 15 1 + Current sample, line, band is: 122 16 1 + Current sample, line, band is: 122 17 1 + Current sample, line, band is: 122 18 1 + Current sample, line, band is: 122 19 1 + Current sample, line, band is: 122 20 1 + Current sample, line, band is: 122 21 1 + Current sample, line, band is: 122 22 1 + Current sample, line, band is: 122 23 1 + Current sample, line, band is: 122 24 1 + Current sample, line, band is: 122 25 1 + Current sample, line, band is: 122 26 1 + Current sample, line, band is: 122 27 1 + Current sample, line, band is: 122 28 1 + Current sample, line, band is: 122 29 1 + Current sample, line, band is: 122 30 1 + Current sample, line, band is: 122 31 1 + Current sample, line, band is: 122 32 1 + Current sample, line, band is: 122 33 1 + Current sample, line, band is: 122 34 1 + Current sample, line, band is: 122 35 1 + Current sample, line, band is: 122 36 1 + Current sample, line, band is: 122 37 1 + Current sample, line, band is: 122 38 1 + Current sample, line, band is: 122 39 1 + Current sample, line, band is: 122 40 1 + Current sample, line, band is: 122 41 1 + Current sample, line, band is: 122 42 1 + Current sample, line, band is: 122 43 1 + Current sample, line, band is: 122 44 1 + Current sample, line, band is: 122 45 1 + Current sample, line, band is: 122 46 1 + Current sample, line, band is: 122 47 1 + Current sample, line, band is: 122 48 1 + Current sample, line, band is: 122 49 1 + Current sample, line, band is: 122 50 1 + Current sample, line, band is: 122 51 1 + Current sample, line, band is: 122 52 1 + Current sample, line, band is: 122 53 1 + Current sample, line, band is: 122 54 1 + Current sample, line, band is: 122 55 1 + Current sample, line, band is: 122 56 1 + Current sample, line, band is: 122 57 1 + Current sample, line, band is: 122 58 1 + Current sample, line, band is: 122 59 1 + Current sample, line, band is: 122 60 1 + Current sample, line, band is: 122 61 1 + Current sample, line, band is: 122 62 1 + Current sample, line, band is: 122 63 1 + Current sample, line, band is: 122 64 1 + Current sample, line, band is: 122 65 1 + Current sample, line, band is: 122 66 1 + Current sample, line, band is: 122 67 1 + Current sample, line, band is: 122 68 1 + Current sample, line, band is: 122 69 1 + Current sample, line, band is: 122 70 1 + Current sample, line, band is: 122 71 1 + Current sample, line, band is: 122 72 1 + Current sample, line, band is: 122 73 1 + Current sample, line, band is: 122 74 1 + Current sample, line, band is: 122 75 1 + Current sample, line, band is: 122 76 1 + Current sample, line, band is: 122 77 1 + Current sample, line, band is: 122 78 1 + Current sample, line, band is: 122 79 1 + Current sample, line, band is: 122 80 1 + Current sample, line, band is: 122 81 1 + Current sample, line, band is: 122 82 1 + Current sample, line, band is: 122 83 1 + Current sample, line, band is: 122 84 1 + Current sample, line, band is: 122 85 1 + Current sample, line, band is: 122 86 1 + Current sample, line, band is: 122 87 1 + Current sample, line, band is: 122 88 1 + Current sample, line, band is: 122 89 1 + Current sample, line, band is: 122 90 1 + Current sample, line, band is: 122 91 1 + Current sample, line, band is: 122 92 1 + Current sample, line, band is: 122 93 1 + Current sample, line, band is: 122 94 1 + Current sample, line, band is: 122 95 1 + Current sample, line, band is: 122 96 1 + Current sample, line, band is: 122 97 1 + Current sample, line, band is: 122 98 1 + Current sample, line, band is: 122 99 1 + Current sample, line, band is: 122 100 1 + Current sample, line, band is: 122 101 1 + Current sample, line, band is: 122 102 1 + Current sample, line, band is: 122 103 1 + Current sample, line, band is: 122 104 1 + Current sample, line, band is: 122 105 1 + Current sample, line, band is: 122 106 1 + Current sample, line, band is: 122 107 1 + Current sample, line, band is: 122 108 1 + Current sample, line, band is: 122 109 1 + Current sample, line, band is: 122 110 1 + Current sample, line, band is: 122 111 1 + Current sample, line, band is: 122 112 1 + Current sample, line, band is: 122 113 1 + Current sample, line, band is: 122 114 1 + Current sample, line, band is: 122 115 1 + Current sample, line, band is: 122 116 1 + Current sample, line, band is: 122 117 1 + Current sample, line, band is: 122 118 1 + Current sample, line, band is: 122 119 1 + Current sample, line, band is: 122 120 1 + Current sample, line, band is: 122 121 1 + Current sample, line, band is: 122 122 1 + Current sample, line, band is: 122 123 1 + Current sample, line, band is: 122 124 1 + Current sample, line, band is: 122 125 1 + Current sample, line, band is: 122 126 1 + Current sample, line, band is: 123 1 1 + Current sample, line, band is: 123 2 1 + Current sample, line, band is: 123 3 1 + Current sample, line, band is: 123 4 1 + Current sample, line, band is: 123 5 1 + Current sample, line, band is: 123 6 1 + Current sample, line, band is: 123 7 1 + Current sample, line, band is: 123 8 1 + Current sample, line, band is: 123 9 1 + Current sample, line, band is: 123 10 1 + Current sample, line, band is: 123 11 1 + Current sample, line, band is: 123 12 1 + Current sample, line, band is: 123 13 1 + Current sample, line, band is: 123 14 1 + Current sample, line, band is: 123 15 1 + Current sample, line, band is: 123 16 1 + Current sample, line, band is: 123 17 1 + Current sample, line, band is: 123 18 1 + Current sample, line, band is: 123 19 1 + Current sample, line, band is: 123 20 1 + Current sample, line, band is: 123 21 1 + Current sample, line, band is: 123 22 1 + Current sample, line, band is: 123 23 1 + Current sample, line, band is: 123 24 1 + Current sample, line, band is: 123 25 1 + Current sample, line, band is: 123 26 1 + Current sample, line, band is: 123 27 1 + Current sample, line, band is: 123 28 1 + Current sample, line, band is: 123 29 1 + Current sample, line, band is: 123 30 1 + Current sample, line, band is: 123 31 1 + Current sample, line, band is: 123 32 1 + Current sample, line, band is: 123 33 1 + Current sample, line, band is: 123 34 1 + Current sample, line, band is: 123 35 1 + Current sample, line, band is: 123 36 1 + Current sample, line, band is: 123 37 1 + Current sample, line, band is: 123 38 1 + Current sample, line, band is: 123 39 1 + Current sample, line, band is: 123 40 1 + Current sample, line, band is: 123 41 1 + Current sample, line, band is: 123 42 1 + Current sample, line, band is: 123 43 1 + Current sample, line, band is: 123 44 1 + Current sample, line, band is: 123 45 1 + Current sample, line, band is: 123 46 1 + Current sample, line, band is: 123 47 1 + Current sample, line, band is: 123 48 1 + Current sample, line, band is: 123 49 1 + Current sample, line, band is: 123 50 1 + Current sample, line, band is: 123 51 1 + Current sample, line, band is: 123 52 1 + Current sample, line, band is: 123 53 1 + Current sample, line, band is: 123 54 1 + Current sample, line, band is: 123 55 1 + Current sample, line, band is: 123 56 1 + Current sample, line, band is: 123 57 1 + Current sample, line, band is: 123 58 1 + Current sample, line, band is: 123 59 1 + Current sample, line, band is: 123 60 1 + Current sample, line, band is: 123 61 1 + Current sample, line, band is: 123 62 1 + Current sample, line, band is: 123 63 1 + Current sample, line, band is: 123 64 1 + Current sample, line, band is: 123 65 1 + Current sample, line, band is: 123 66 1 + Current sample, line, band is: 123 67 1 + Current sample, line, band is: 123 68 1 + Current sample, line, band is: 123 69 1 + Current sample, line, band is: 123 70 1 + Current sample, line, band is: 123 71 1 + Current sample, line, band is: 123 72 1 + Current sample, line, band is: 123 73 1 + Current sample, line, band is: 123 74 1 + Current sample, line, band is: 123 75 1 + Current sample, line, band is: 123 76 1 + Current sample, line, band is: 123 77 1 + Current sample, line, band is: 123 78 1 + Current sample, line, band is: 123 79 1 + Current sample, line, band is: 123 80 1 + Current sample, line, band is: 123 81 1 + Current sample, line, band is: 123 82 1 + Current sample, line, band is: 123 83 1 + Current sample, line, band is: 123 84 1 + Current sample, line, band is: 123 85 1 + Current sample, line, band is: 123 86 1 + Current sample, line, band is: 123 87 1 + Current sample, line, band is: 123 88 1 + Current sample, line, band is: 123 89 1 + Current sample, line, band is: 123 90 1 + Current sample, line, band is: 123 91 1 + Current sample, line, band is: 123 92 1 + Current sample, line, band is: 123 93 1 + Current sample, line, band is: 123 94 1 + Current sample, line, band is: 123 95 1 + Current sample, line, band is: 123 96 1 + Current sample, line, band is: 123 97 1 + Current sample, line, band is: 123 98 1 + Current sample, line, band is: 123 99 1 + Current sample, line, band is: 123 100 1 + Current sample, line, band is: 123 101 1 + Current sample, line, band is: 123 102 1 + Current sample, line, band is: 123 103 1 + Current sample, line, band is: 123 104 1 + Current sample, line, band is: 123 105 1 + Current sample, line, band is: 123 106 1 + Current sample, line, band is: 123 107 1 + Current sample, line, band is: 123 108 1 + Current sample, line, band is: 123 109 1 + Current sample, line, band is: 123 110 1 + Current sample, line, band is: 123 111 1 + Current sample, line, band is: 123 112 1 + Current sample, line, band is: 123 113 1 + Current sample, line, band is: 123 114 1 + Current sample, line, band is: 123 115 1 + Current sample, line, band is: 123 116 1 + Current sample, line, band is: 123 117 1 + Current sample, line, band is: 123 118 1 + Current sample, line, band is: 123 119 1 + Current sample, line, band is: 123 120 1 + Current sample, line, band is: 123 121 1 + Current sample, line, band is: 123 122 1 + Current sample, line, band is: 123 123 1 + Current sample, line, band is: 123 124 1 + Current sample, line, band is: 123 125 1 + Current sample, line, band is: 123 126 1 + Current sample, line, band is: 124 1 1 + Current sample, line, band is: 124 2 1 + Current sample, line, band is: 124 3 1 + Current sample, line, band is: 124 4 1 + Current sample, line, band is: 124 5 1 + Current sample, line, band is: 124 6 1 + Current sample, line, band is: 124 7 1 + Current sample, line, band is: 124 8 1 + Current sample, line, band is: 124 9 1 + Current sample, line, band is: 124 10 1 + Current sample, line, band is: 124 11 1 + Current sample, line, band is: 124 12 1 + Current sample, line, band is: 124 13 1 + Current sample, line, band is: 124 14 1 + Current sample, line, band is: 124 15 1 + Current sample, line, band is: 124 16 1 + Current sample, line, band is: 124 17 1 + Current sample, line, band is: 124 18 1 + Current sample, line, band is: 124 19 1 + Current sample, line, band is: 124 20 1 + Current sample, line, band is: 124 21 1 + Current sample, line, band is: 124 22 1 + Current sample, line, band is: 124 23 1 + Current sample, line, band is: 124 24 1 + Current sample, line, band is: 124 25 1 + Current sample, line, band is: 124 26 1 + Current sample, line, band is: 124 27 1 + Current sample, line, band is: 124 28 1 + Current sample, line, band is: 124 29 1 + Current sample, line, band is: 124 30 1 + Current sample, line, band is: 124 31 1 + Current sample, line, band is: 124 32 1 + Current sample, line, band is: 124 33 1 + Current sample, line, band is: 124 34 1 + Current sample, line, band is: 124 35 1 + Current sample, line, band is: 124 36 1 + Current sample, line, band is: 124 37 1 + Current sample, line, band is: 124 38 1 + Current sample, line, band is: 124 39 1 + Current sample, line, band is: 124 40 1 + Current sample, line, band is: 124 41 1 + Current sample, line, band is: 124 42 1 + Current sample, line, band is: 124 43 1 + Current sample, line, band is: 124 44 1 + Current sample, line, band is: 124 45 1 + Current sample, line, band is: 124 46 1 + Current sample, line, band is: 124 47 1 + Current sample, line, band is: 124 48 1 + Current sample, line, band is: 124 49 1 + Current sample, line, band is: 124 50 1 + Current sample, line, band is: 124 51 1 + Current sample, line, band is: 124 52 1 + Current sample, line, band is: 124 53 1 + Current sample, line, band is: 124 54 1 + Current sample, line, band is: 124 55 1 + Current sample, line, band is: 124 56 1 + Current sample, line, band is: 124 57 1 + Current sample, line, band is: 124 58 1 + Current sample, line, band is: 124 59 1 + Current sample, line, band is: 124 60 1 + Current sample, line, band is: 124 61 1 + Current sample, line, band is: 124 62 1 + Current sample, line, band is: 124 63 1 + Current sample, line, band is: 124 64 1 + Current sample, line, band is: 124 65 1 + Current sample, line, band is: 124 66 1 + Current sample, line, band is: 124 67 1 + Current sample, line, band is: 124 68 1 + Current sample, line, band is: 124 69 1 + Current sample, line, band is: 124 70 1 + Current sample, line, band is: 124 71 1 + Current sample, line, band is: 124 72 1 + Current sample, line, band is: 124 73 1 + Current sample, line, band is: 124 74 1 + Current sample, line, band is: 124 75 1 + Current sample, line, band is: 124 76 1 + Current sample, line, band is: 124 77 1 + Current sample, line, band is: 124 78 1 + Current sample, line, band is: 124 79 1 + Current sample, line, band is: 124 80 1 + Current sample, line, band is: 124 81 1 + Current sample, line, band is: 124 82 1 + Current sample, line, band is: 124 83 1 + Current sample, line, band is: 124 84 1 + Current sample, line, band is: 124 85 1 + Current sample, line, band is: 124 86 1 + Current sample, line, band is: 124 87 1 + Current sample, line, band is: 124 88 1 + Current sample, line, band is: 124 89 1 + Current sample, line, band is: 124 90 1 + Current sample, line, band is: 124 91 1 + Current sample, line, band is: 124 92 1 + Current sample, line, band is: 124 93 1 + Current sample, line, band is: 124 94 1 + Current sample, line, band is: 124 95 1 + Current sample, line, band is: 124 96 1 + Current sample, line, band is: 124 97 1 + Current sample, line, band is: 124 98 1 + Current sample, line, band is: 124 99 1 + Current sample, line, band is: 124 100 1 + Current sample, line, band is: 124 101 1 + Current sample, line, band is: 124 102 1 + Current sample, line, band is: 124 103 1 + Current sample, line, band is: 124 104 1 + Current sample, line, band is: 124 105 1 + Current sample, line, band is: 124 106 1 + Current sample, line, band is: 124 107 1 + Current sample, line, band is: 124 108 1 + Current sample, line, band is: 124 109 1 + Current sample, line, band is: 124 110 1 + Current sample, line, band is: 124 111 1 + Current sample, line, band is: 124 112 1 + Current sample, line, band is: 124 113 1 + Current sample, line, band is: 124 114 1 + Current sample, line, band is: 124 115 1 + Current sample, line, band is: 124 116 1 + Current sample, line, band is: 124 117 1 + Current sample, line, band is: 124 118 1 + Current sample, line, band is: 124 119 1 + Current sample, line, band is: 124 120 1 + Current sample, line, band is: 124 121 1 + Current sample, line, band is: 124 122 1 + Current sample, line, band is: 124 123 1 + Current sample, line, band is: 124 124 1 + Current sample, line, band is: 124 125 1 + Current sample, line, band is: 124 126 1 + Current sample, line, band is: 125 1 1 + Current sample, line, band is: 125 2 1 + Current sample, line, band is: 125 3 1 + Current sample, line, band is: 125 4 1 + Current sample, line, band is: 125 5 1 + Current sample, line, band is: 125 6 1 + Current sample, line, band is: 125 7 1 + Current sample, line, band is: 125 8 1 + Current sample, line, band is: 125 9 1 + Current sample, line, band is: 125 10 1 + Current sample, line, band is: 125 11 1 + Current sample, line, band is: 125 12 1 + Current sample, line, band is: 125 13 1 + Current sample, line, band is: 125 14 1 + Current sample, line, band is: 125 15 1 + Current sample, line, band is: 125 16 1 + Current sample, line, band is: 125 17 1 + Current sample, line, band is: 125 18 1 + Current sample, line, band is: 125 19 1 + Current sample, line, band is: 125 20 1 + Current sample, line, band is: 125 21 1 + Current sample, line, band is: 125 22 1 + Current sample, line, band is: 125 23 1 + Current sample, line, band is: 125 24 1 + Current sample, line, band is: 125 25 1 + Current sample, line, band is: 125 26 1 + Current sample, line, band is: 125 27 1 + Current sample, line, band is: 125 28 1 + Current sample, line, band is: 125 29 1 + Current sample, line, band is: 125 30 1 + Current sample, line, band is: 125 31 1 + Current sample, line, band is: 125 32 1 + Current sample, line, band is: 125 33 1 + Current sample, line, band is: 125 34 1 + Current sample, line, band is: 125 35 1 + Current sample, line, band is: 125 36 1 + Current sample, line, band is: 125 37 1 + Current sample, line, band is: 125 38 1 + Current sample, line, band is: 125 39 1 + Current sample, line, band is: 125 40 1 + Current sample, line, band is: 125 41 1 + Current sample, line, band is: 125 42 1 + Current sample, line, band is: 125 43 1 + Current sample, line, band is: 125 44 1 + Current sample, line, band is: 125 45 1 + Current sample, line, band is: 125 46 1 + Current sample, line, band is: 125 47 1 + Current sample, line, band is: 125 48 1 + Current sample, line, band is: 125 49 1 + Current sample, line, band is: 125 50 1 + Current sample, line, band is: 125 51 1 + Current sample, line, band is: 125 52 1 + Current sample, line, band is: 125 53 1 + Current sample, line, band is: 125 54 1 + Current sample, line, band is: 125 55 1 + Current sample, line, band is: 125 56 1 + Current sample, line, band is: 125 57 1 + Current sample, line, band is: 125 58 1 + Current sample, line, band is: 125 59 1 + Current sample, line, band is: 125 60 1 + Current sample, line, band is: 125 61 1 + Current sample, line, band is: 125 62 1 + Current sample, line, band is: 125 63 1 + Current sample, line, band is: 125 64 1 + Current sample, line, band is: 125 65 1 + Current sample, line, band is: 125 66 1 + Current sample, line, band is: 125 67 1 + Current sample, line, band is: 125 68 1 + Current sample, line, band is: 125 69 1 + Current sample, line, band is: 125 70 1 + Current sample, line, band is: 125 71 1 + Current sample, line, band is: 125 72 1 + Current sample, line, band is: 125 73 1 + Current sample, line, band is: 125 74 1 + Current sample, line, band is: 125 75 1 + Current sample, line, band is: 125 76 1 + Current sample, line, band is: 125 77 1 + Current sample, line, band is: 125 78 1 + Current sample, line, band is: 125 79 1 + Current sample, line, band is: 125 80 1 + Current sample, line, band is: 125 81 1 + Current sample, line, band is: 125 82 1 + Current sample, line, band is: 125 83 1 + Current sample, line, band is: 125 84 1 + Current sample, line, band is: 125 85 1 + Current sample, line, band is: 125 86 1 + Current sample, line, band is: 125 87 1 + Current sample, line, band is: 125 88 1 + Current sample, line, band is: 125 89 1 + Current sample, line, band is: 125 90 1 + Current sample, line, band is: 125 91 1 + Current sample, line, band is: 125 92 1 + Current sample, line, band is: 125 93 1 + Current sample, line, band is: 125 94 1 + Current sample, line, band is: 125 95 1 + Current sample, line, band is: 125 96 1 + Current sample, line, band is: 125 97 1 + Current sample, line, band is: 125 98 1 + Current sample, line, band is: 125 99 1 + Current sample, line, band is: 125 100 1 + Current sample, line, band is: 125 101 1 + Current sample, line, band is: 125 102 1 + Current sample, line, band is: 125 103 1 + Current sample, line, band is: 125 104 1 + Current sample, line, band is: 125 105 1 + Current sample, line, band is: 125 106 1 + Current sample, line, band is: 125 107 1 + Current sample, line, band is: 125 108 1 + Current sample, line, band is: 125 109 1 + Current sample, line, band is: 125 110 1 + Current sample, line, band is: 125 111 1 + Current sample, line, band is: 125 112 1 + Current sample, line, band is: 125 113 1 + Current sample, line, band is: 125 114 1 + Current sample, line, band is: 125 115 1 + Current sample, line, band is: 125 116 1 + Current sample, line, band is: 125 117 1 + Current sample, line, band is: 125 118 1 + Current sample, line, band is: 125 119 1 + Current sample, line, band is: 125 120 1 + Current sample, line, band is: 125 121 1 + Current sample, line, band is: 125 122 1 + Current sample, line, band is: 125 123 1 + Current sample, line, band is: 125 124 1 + Current sample, line, band is: 125 125 1 + Current sample, line, band is: 125 126 1 + Current sample, line, band is: 126 1 1 + Current sample, line, band is: 126 2 1 + Current sample, line, band is: 126 3 1 + Current sample, line, band is: 126 4 1 + Current sample, line, band is: 126 5 1 + Current sample, line, band is: 126 6 1 + Current sample, line, band is: 126 7 1 + Current sample, line, band is: 126 8 1 + Current sample, line, band is: 126 9 1 + Current sample, line, band is: 126 10 1 + Current sample, line, band is: 126 11 1 + Current sample, line, band is: 126 12 1 + Current sample, line, band is: 126 13 1 + Current sample, line, band is: 126 14 1 + Current sample, line, band is: 126 15 1 + Current sample, line, band is: 126 16 1 + Current sample, line, band is: 126 17 1 + Current sample, line, band is: 126 18 1 + Current sample, line, band is: 126 19 1 + Current sample, line, band is: 126 20 1 + Current sample, line, band is: 126 21 1 + Current sample, line, band is: 126 22 1 + Current sample, line, band is: 126 23 1 + Current sample, line, band is: 126 24 1 + Current sample, line, band is: 126 25 1 + Current sample, line, band is: 126 26 1 + Current sample, line, band is: 126 27 1 + Current sample, line, band is: 126 28 1 + Current sample, line, band is: 126 29 1 + Current sample, line, band is: 126 30 1 + Current sample, line, band is: 126 31 1 + Current sample, line, band is: 126 32 1 + Current sample, line, band is: 126 33 1 + Current sample, line, band is: 126 34 1 + Current sample, line, band is: 126 35 1 + Current sample, line, band is: 126 36 1 + Current sample, line, band is: 126 37 1 + Current sample, line, band is: 126 38 1 + Current sample, line, band is: 126 39 1 + Current sample, line, band is: 126 40 1 + Current sample, line, band is: 126 41 1 + Current sample, line, band is: 126 42 1 + Current sample, line, band is: 126 43 1 + Current sample, line, band is: 126 44 1 + Current sample, line, band is: 126 45 1 + Current sample, line, band is: 126 46 1 + Current sample, line, band is: 126 47 1 + Current sample, line, band is: 126 48 1 + Current sample, line, band is: 126 49 1 + Current sample, line, band is: 126 50 1 + Current sample, line, band is: 126 51 1 + Current sample, line, band is: 126 52 1 + Current sample, line, band is: 126 53 1 + Current sample, line, band is: 126 54 1 + Current sample, line, band is: 126 55 1 + Current sample, line, band is: 126 56 1 + Current sample, line, band is: 126 57 1 + Current sample, line, band is: 126 58 1 + Current sample, line, band is: 126 59 1 + Current sample, line, band is: 126 60 1 + Current sample, line, band is: 126 61 1 + Current sample, line, band is: 126 62 1 + Current sample, line, band is: 126 63 1 + Current sample, line, band is: 126 64 1 + Current sample, line, band is: 126 65 1 + Current sample, line, band is: 126 66 1 + Current sample, line, band is: 126 67 1 + Current sample, line, band is: 126 68 1 + Current sample, line, band is: 126 69 1 + Current sample, line, band is: 126 70 1 + Current sample, line, band is: 126 71 1 + Current sample, line, band is: 126 72 1 + Current sample, line, band is: 126 73 1 + Current sample, line, band is: 126 74 1 + Current sample, line, band is: 126 75 1 + Current sample, line, band is: 126 76 1 + Current sample, line, band is: 126 77 1 + Current sample, line, band is: 126 78 1 + Current sample, line, band is: 126 79 1 + Current sample, line, band is: 126 80 1 + Current sample, line, band is: 126 81 1 + Current sample, line, band is: 126 82 1 + Current sample, line, band is: 126 83 1 + Current sample, line, band is: 126 84 1 + Current sample, line, band is: 126 85 1 + Current sample, line, band is: 126 86 1 + Current sample, line, band is: 126 87 1 + Current sample, line, band is: 126 88 1 + Current sample, line, band is: 126 89 1 + Current sample, line, band is: 126 90 1 + Current sample, line, band is: 126 91 1 + Current sample, line, band is: 126 92 1 + Current sample, line, band is: 126 93 1 + Current sample, line, band is: 126 94 1 + Current sample, line, band is: 126 95 1 + Current sample, line, band is: 126 96 1 + Current sample, line, band is: 126 97 1 + Current sample, line, band is: 126 98 1 + Current sample, line, band is: 126 99 1 + Current sample, line, band is: 126 100 1 + Current sample, line, band is: 126 101 1 + Current sample, line, band is: 126 102 1 + Current sample, line, band is: 126 103 1 + Current sample, line, band is: 126 104 1 + Current sample, line, band is: 126 105 1 + Current sample, line, band is: 126 106 1 + Current sample, line, band is: 126 107 1 + Current sample, line, band is: 126 108 1 + Current sample, line, band is: 126 109 1 + Current sample, line, band is: 126 110 1 + Current sample, line, band is: 126 111 1 + Current sample, line, band is: 126 112 1 + Current sample, line, band is: 126 113 1 + Current sample, line, band is: 126 114 1 + Current sample, line, band is: 126 115 1 + Current sample, line, band is: 126 116 1 + Current sample, line, band is: 126 117 1 + Current sample, line, band is: 126 118 1 + Current sample, line, band is: 126 119 1 + Current sample, line, band is: 126 120 1 + Current sample, line, band is: 126 121 1 + Current sample, line, band is: 126 122 1 + Current sample, line, band is: 126 123 1 + Current sample, line, band is: 126 124 1 + Current sample, line, band is: 126 125 1 + Current sample, line, band is: 126 126 1 + + Current sample, line, band is: 50 1 1 + + Current sample, line, band is: 1 50 1 + +Testing errors ... +**PROGRAMMER ERROR** Invalid value for argument [sample] + +Testing errors ... +**PROGRAMMER ERROR** Invalid value for argument [line] + diff --git a/isis/src/base/objs/BandManager/Makefile b/isis/src/base/objs/BandManager/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b597295f4d86ca661e4ee3b96b2ddeae1ab11472 --- /dev/null +++ b/isis/src/base/objs/BandManager/Makefile @@ -0,0 +1,5 @@ +INCS = BandManager.h +SRCS = BandManager.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/BandManager/unitTest.cpp b/isis/src/base/objs/BandManager/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe7f726cf04ded7000936db8f874a56939ce2387 --- /dev/null +++ b/isis/src/base/objs/BandManager/unitTest.cpp @@ -0,0 +1,83 @@ + +#include +#include +#include + +#include "Preference.h" +#include "iException.h" +#include "Cube.h" +#include "BandManager.h" + +using namespace std; +int main (int argc, char *argv[]) { + + Isis::Preference::Preferences(true); + + string fname = "$base/testData/isisTruth.cub"; + Isis::Cube cube; + cube.Open (fname); + + Isis::BandManager band(cube); + cout << "Buffer Size: " << + band.SampleDimension() << " " << + band.LineDimension() << " " << + band.BandDimension() << endl; + cout << endl; + + for (band.begin(); !band.end(); band++) { + cout << " Current sample, line, band is: " + << band.Sample() << " " + << band.Line() << " " + << band.Band() << endl; + } + cout << endl; + + Isis::BandManager bandReverse(cube,true); + cout << "Buffer Size: " << + bandReverse.SampleDimension() << " " << + bandReverse.LineDimension() << " " << + bandReverse.BandDimension() << endl; + cout << endl; + + for (bandReverse.begin(); !bandReverse.end(); bandReverse++) { + cout << " Current sample, line, band is: " + << bandReverse.Sample() << " " + << bandReverse.Line() << " " + << bandReverse.Band() << endl; + } + cout << endl; + + band.SetBand(50); + cout << " Current sample, line, band is: " + << band.Sample() << " " + << band.Line() << " " + << band.Band() << endl; + cout << endl; + + bandReverse.SetBand(50); + cout << " Current sample, line, band is: " + << bandReverse.Sample() << " " + << bandReverse.Line() << " " + << bandReverse.Band() << endl; + cout << endl; + + try { + cout << "Testing errors ... " << endl; + band.SetBand(0,0); + } + catch (Isis::iException &e) { + e.Report(false); + cout << endl; + } + + try { + cout << "Testing errors ... " << endl; + band.SetBand(1,0); + } + catch (Isis::iException &e) { + e.Report(false); + cout << endl; + } + + cube.Close (); +} diff --git a/isis/src/base/objs/Basis1VariableFunction/Basis1VariableFunction.cpp b/isis/src/base/objs/Basis1VariableFunction/Basis1VariableFunction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..669098c06254f7bb4053eda8319ebc17c964e6c4 --- /dev/null +++ b/isis/src/base/objs/Basis1VariableFunction/Basis1VariableFunction.cpp @@ -0,0 +1,45 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/01/11 23:18:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include + +#include "Basis1VariableFunction.h" +#include "iString.h" +#include "iException.h" + +namespace Isis { + +/** + * Creates a Basis Function with a single variable. + * + * @param name Name of the Basis1VariableFunction. For example, "affine". + * @param numCoefs Number of coefficients in the equation. For example: + * @f[ + * x = C1 + C2 * x + C3 * x**2 + * @f] + * has three coefficients: C1, C2 & C3. + */ + Basis1VariableFunction::Basis1VariableFunction(const std::string &name, int numCoefs) : + Isis::BasisFunction(name,1,numCoefs) { + } + +} diff --git a/isis/src/base/objs/Basis1VariableFunction/Basis1VariableFunction.h b/isis/src/base/objs/Basis1VariableFunction/Basis1VariableFunction.h new file mode 100644 index 0000000000000000000000000000000000000000..936fd1b9e86068e48b46ff901cb8d26ea16276e8 --- /dev/null +++ b/isis/src/base/objs/Basis1VariableFunction/Basis1VariableFunction.h @@ -0,0 +1,77 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/01/11 23:18:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef Basis1VariableFunction_h +#define Basis1VariableFunction_h + +#include +#include + +#include "BasisFunction.h" + +namespace Isis { +/** + * @brief Time based linear equation class + * + * This is a class for generating a general one-variable equation for the Isis + * least squares fitting algorithm (IsisLSQ). It allows the programmer to set up + * equations in the form of: + * @f[ + * x = C1*T1 + C2*T2 + ... + CN*TN; + * @f] + * where C1-CN are coefficients and T1-TN are terms with a single variable. + * For example, + * @f[ + * x = C1 + C2*t + C3*t**2 + * @f] + * + * @ingroup Math + * + * @author 2004-06-24 Jeff Anderson + * + * @internal + * @todo Add coded example + * @history 2005-03-16 Leah Dahmer modified file to support Doxygen + * documentation. + * @history 2008-01-08 Tracie Sucharski, Derived from BasisFunction class for + * a single variable function. Added Derivative + * methods as pure virtuals. This class was + * developed as a convenience to simplify the + * Derivative methods and any other methods that + * might need to be developed in the future. + * + */ + class Basis1VariableFunction : public Isis::BasisFunction { + public: + Basis1VariableFunction(const std::string &name, int numCoefs); + //! Destroys the Basis1VariableFunction object. + virtual ~Basis1VariableFunction() {}; + + virtual double DerivativeVar (const double value) = 0; + virtual double DerivativeCoef (const double value, const int coefIndex) = 0; + + protected: + + }; +}; + +#endif diff --git a/isis/src/base/objs/Basis1VariableFunction/Basis1VariableFunction.truth b/isis/src/base/objs/Basis1VariableFunction/Basis1VariableFunction.truth new file mode 100644 index 0000000000000000000000000000000000000000..8c101be5672feea8925aa5f8d114888e69647495 --- /dev/null +++ b/isis/src/base/objs/Basis1VariableFunction/Basis1VariableFunction.truth @@ -0,0 +1 @@ +This class currently contains only pure virtual functions,so this is a dummy unit test. diff --git a/isis/src/base/objs/Basis1VariableFunction/Makefile b/isis/src/base/objs/Basis1VariableFunction/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..414b548e12c01ac41bc6981687ae0cb02a0e9f11 --- /dev/null +++ b/isis/src/base/objs/Basis1VariableFunction/Makefile @@ -0,0 +1,5 @@ +INCS = Basis1VariableFunction.h +SRCS = Basis1VariableFunction.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Basis1VariableFunction/unitTest.cpp b/isis/src/base/objs/Basis1VariableFunction/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e602b8a586d27153b9514cb7c76205f5054c15d2 --- /dev/null +++ b/isis/src/base/objs/Basis1VariableFunction/unitTest.cpp @@ -0,0 +1,10 @@ +#include + +using namespace std; +int main (int argc, char *argv[]) +{ + + cout << "This class currently contains only pure virtual functions," << + "so this is a dummy unit test." << endl; +} + diff --git a/isis/src/base/objs/BasisFunction/BasisFunction.cpp b/isis/src/base/objs/BasisFunction/BasisFunction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b938107a1c0c4064a9fe58256acf69723d26cc02 --- /dev/null +++ b/isis/src/base/objs/BasisFunction/BasisFunction.cpp @@ -0,0 +1,111 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include "BasisFunction.h" +#include "iException.h" + +namespace Isis { + +/** + * Creates a BasisFunction object. + * + * @param name Name of the BasisFunction. For example, "affine". + * @param numVars Number of variables in the equation. For example: + * @f[ + * x = C1 + C2*y + C3*z + * @f] + * has two variables: y and z. + * @param numCoefs Number of coefficients in the equation. For example: + * @f[ + * x = C1 + C2*y + C3*z + * @f] + * has three coefficients: C1, C2 & C3. + */ + BasisFunction::BasisFunction(const std::string &name, int numVars, int numCoefs) { + p_name = name; + p_numVars = numVars; + p_numCoefs = numCoefs; + } + +/** + * Set the coefficients for the equation. + * + * @param coefs A vector of coefficients for the equation. + */ + void BasisFunction::SetCoefficients(const std::vector &coefs) { + if ((int)coefs.size() != p_numCoefs) { + std::string msg = "[coefs] does not match number of coefficients "; + msg += "in the basis equation"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + p_coefs = coefs; + } + +/** + * Compute the equation using the input variables. + * + * @param vars A vector of double values to use for the equation. After setting + * the coefficients, this can be invoked many times to compute output values + * given input values. + * + * @return The output value. + */ + double BasisFunction::Evaluate (const std::vector &vars) { + if ((int)vars.size() != p_numVars) { + std::string msg = "[vars] does not match the number of variables "; + msg += "in the basis equation"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + Expand(vars); + if ((int)p_terms.size() != p_numCoefs) { + std::string msg = "Expansion of [terms] does not match number of "; + msg += "coefficients in the basis equation"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + double result = 0.0; + for (int i=0; i &vars) { + p_terms = vars; + } +} diff --git a/isis/src/base/objs/BasisFunction/BasisFunction.h b/isis/src/base/objs/BasisFunction/BasisFunction.h new file mode 100644 index 0000000000000000000000000000000000000000..89a80b06000f478a30f5aa2b2e409d56e25ac350 --- /dev/null +++ b/isis/src/base/objs/BasisFunction/BasisFunction.h @@ -0,0 +1,132 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef BasisFunction_h +#define BasisFunction_h + +#include +#include + +namespace Isis { +/** + * @brief Generic linear equation class + * + * This is a base class for generating "generic" equations for the + * Isis least squares fitting algorithm (IsisLSQ). It allows the programmer + * to set up equations in the form of: + * @f[ + * x = C1*T1 + C2*T2 + ... + CN*TN; + * @f] + * where C1-CN are coefficients and T1-TN are terms. Note that terms can + * be comprised of multiple variables and/or functions. For example, + * @f[ + * x = C1 + C2*y + C3*y**2; + * @f] + * @f[ + * x = C1 + C2*y + C3*z + C4*y*z; + * @f] + * By deriving different functions off of this base class this allows the + * least squares class to be generalized. + * + * @ingroup Math + * + * @author 2004-06-24 Jeff Anderson + * + * @internal + * @todo Add coded example + * @history 2005-03-16 Leah Dahmer modified file to support Doxygen + * documentation. + */ + class BasisFunction { + public: + BasisFunction(const std::string &name, int numVars, int numCoefs); + //! Destroys the BasisFunction object. + virtual ~BasisFunction() {}; + + void SetCoefficients(const std::vector &coefs); + double Evaluate (const std::vector &vars); + virtual void Expand(const std::vector &vars); + +/** + * Returns the number of coefficients for the equation. + * + * @return The number of coefficients. + */ + int Coefficients() const { return p_numCoefs; }; +/** + * Returns the number of variables in the equation. + * + * @return The number of variables. + */ + int Variables() const { return p_numVars; }; +/** + * Returns the name of the equation. + * + * @return The name of the equation. + */ + std::string Name() const { return p_name; }; +/** + * Returns the cth term. This is only valid after a Evalute/Expand has been + * invoked. It represents the expansion of the variables into the ith term. + * For example, + * @f[ + * x = C1 + C2*x + C3*y + C4*x*y + * @f] + * would return x*y for the 3rd + * term (zero-based) + * + * @param c The index for the desired coefficient. + * + * @return The cth term. + */ + double Term(int c) const { return p_terms[c]; }; +/** + * Returns the ith coefficient + * + * @param i The index for the desired coefficient. + * + * @return The ith coefficient + */ + double Coefficient(int i) const { return p_coefs[i]; }; + + protected: + //! The name of the equation. Call it by using Name() + std::string p_name; + //! The number of variables in the equation. Call it by using Variables() + int p_numVars; + /** The number of coefficients in the equation. Call it by using + * Coefficients() + */ + int p_numCoefs; + /** A vector of the coefficients in the equation. Call it by using + * Coefficient() + */ + std::vector p_coefs; + /** A vector of the terms in the equation. Call it by using + * Term() + */ + std::vector p_terms; + + }; +}; + +#endif diff --git a/isis/src/base/objs/BasisFunction/BasisFunction.truth b/isis/src/base/objs/BasisFunction/BasisFunction.truth new file mode 100644 index 0000000000000000000000000000000000000000..060f87570735ed9c70b3fbc945b1c598d3e4cf7b --- /dev/null +++ b/isis/src/base/objs/BasisFunction/BasisFunction.truth @@ -0,0 +1,13 @@ +Name = Basis +Ncoefs = 2 +Vars = 2 +0.5 +-0.5 +--- +0.5 +0.5 +-0.5 +--- +-0.5 +1 +2 diff --git a/isis/src/base/objs/BasisFunction/Makefile b/isis/src/base/objs/BasisFunction/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ad3bb1e1939bd62ffc0b3338edfb26b7fb84a1e6 --- /dev/null +++ b/isis/src/base/objs/BasisFunction/Makefile @@ -0,0 +1,5 @@ +INCS = BasisFunction.h +SRCS = BasisFunction.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/BasisFunction/unitTest.cpp b/isis/src/base/objs/BasisFunction/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46aeec5b9e931a9844983f411cb54517542ea440 --- /dev/null +++ b/isis/src/base/objs/BasisFunction/unitTest.cpp @@ -0,0 +1,40 @@ +#include "BasisFunction.h" +#include "Preference.h" +#include + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + Isis::BasisFunction b("Basis",2,2); + vector coefs; + coefs.push_back(0.5); + coefs.push_back(-0.5); + b.SetCoefficients(coefs); + + cout << "Name = " << b.Name() << endl; + cout << "Ncoefs = " << b.Coefficients() << endl; + cout << "Vars = " << b.Variables() << endl; + for (int i=0; i vars = coefs; + cout << b.Evaluate(vars) << endl; + for (int i=0; i +#include +#include +#include "Blob.h" +#include "Pvl.h" +#include "Filename.h" +#include "iException.h" +#include "iException.h" +#include "iException.h" +#include "Message.h" + +using namespace std; +namespace Isis { + /** + * Constructs a Blob object using a name and type. + * + * @param name The blob name + * @param type The blob type + */ + Blob::Blob(const std::string &name, const std::string &type) { + p_blobName = name; + p_buffer = NULL; + p_labelFile = ""; + p_nbytes = 0; + p_type = type; + + p_blobPvl.SetName(p_type); + p_blobPvl += Isis::PvlKeyword("Name", p_blobName); + p_blobPvl += Isis::PvlKeyword("StartByte", 0); + p_blobPvl += Isis::PvlKeyword("Bytes", 0); + } + + /** + * Constructs a Blob object using a name, type, and reading Pvl values from a + * file. + * + * @param name The blob name + * @param type The blob type + * @param file The filename to read from. + */ + Blob::Blob(const std::string &name, const std::string &type, const std::string &file) { + p_blobName = name; + p_buffer = NULL; + p_nbytes = 0; + p_type = type; + p_labelFile = Filename(file).Expanded(); + + Read(file); + } + + /** + * This copies the blob object. + * + * @param other + */ + Blob::Blob(const Blob &other) { + p_blobPvl = other.p_blobPvl; + p_blobName = other.p_blobName; + p_startByte = other.p_startByte; + p_nbytes = other.p_nbytes; + p_type = other.p_type; + p_detached = other.p_detached; + p_labelFile = other.p_labelFile; + + p_buffer = NULL; + + if(other.p_buffer) { + p_buffer = new char[p_nbytes]; + + for(int i = 0; i < p_nbytes; i++) { + p_buffer[i] = other.p_buffer[i]; + } + } + } + + //! Destroys the Blob object. + Blob::~Blob() { + if(p_buffer != NULL) delete [] p_buffer; + } + + /** + * This makes the two blob objects exactly the same (copies the blob) + * + * @param other + * + * @return Blob& + */ + Blob &Blob::operator=(const Blob &other) { + p_blobPvl = other.p_blobPvl; + p_blobName = other.p_blobName; + p_startByte = other.p_startByte; + p_nbytes = other.p_nbytes; + p_type = other.p_type; + p_detached = other.p_detached; + p_labelFile = other.p_labelFile; + + p_buffer = NULL; + + if(other.p_buffer) { + p_buffer = new char[p_nbytes]; + + for(int i = 0; i < p_nbytes; i++) { + p_buffer[i] = other.p_buffer[i]; + } + } + + return *this; + } + + /** + * This reads Pvl values from a specified file. + * + * @param file The filename to read from. + * + * @throws Isis::iException::Io - Unable to open file + * @throws Isis::iException::Pvl - Invalid label format + */ + void Blob::Read(const std::string &file) { + // Expand the filename + string temp(Filename(file).Expanded()); + + // Open the file + fstream istm; + istm.open(temp.c_str(), std::ios::in); + if(!istm) { + string message = Isis::Message::FileOpen(temp); + throw Isis::iException::Message(Isis::iException::Io, message, _FILEINFO_); + } + + // Get the pvl + try { + Isis::Pvl pvl; + try { + istm >> pvl; + } + catch(Isis::iException &e) { + istm.close(); + string msg = "Invalid " + p_type + " label format"; + throw Isis::iException::Message(Isis::iException::Pvl, msg, _FILEINFO_); + } + + // Check pvl and read from the stream + Read(pvl, istm); + } + catch(Isis::iException &e) { + istm.close(); + string msg = "Unable to open " + p_type + " [" + p_blobName + + "] in file [" + temp + "]"; + throw Isis::iException::Message(Isis::iException::Io, msg, _FILEINFO_); + } + + istm.close(); + } + + // Read blob from an open file (probably a cube) + void Blob::Read(Isis::Pvl &pvl, std::istream &istm) { + try { + Find(pvl); + ReadInit(); + if(p_detached != "") { + fstream dstm; + dstm.open(p_detached.c_str(), std::ios::in); + if(!dstm) { + string message = Isis::Message::FileOpen(p_detached); + throw Isis::iException::Message(Isis::iException::Io, message, _FILEINFO_); + } + ReadData(dstm); + } + else { + ReadData(istm); + } + } + catch(Isis::iException &e) { + string msg = "Unable to read " + p_type + " [" + p_blobName + "]"; + throw Isis::iException::Message(Isis::iException::Io, msg, _FILEINFO_); + } + } + + // Search PVL for the desire blob + void Blob::Find(Isis::Pvl &pvl) { + bool found = false; + try { + // Search for the blob name + Isis::iString blobName = p_blobName; + blobName.UpCase(); + for(int o = 0; o < pvl.Objects(); o++) { + Isis::PvlObject &obj = pvl.Object(o); + if(obj.IsNamed(p_type)) { + Isis::iString curName = (string) obj["Name"]; + curName.UpCase(); + if(blobName == curName) { + p_blobPvl = obj; + found = true; + break; + } + else { + if(p_type == "OriginalLabel" && curName == "ORIGINALLABEL") { + p_blobPvl = obj; + found = true; + break; + } + } + } + } + } + catch(Isis::iException &e) { + string msg = "Invalid " + p_type + " label format"; + throw Isis::iException::Message(Isis::iException::Pvl, msg, _FILEINFO_); + } + + // Did we find it? + if(!found) { + string msg = "Unable to find " + p_type + " [" + p_blobName + "]"; + throw Isis::iException::Message(Isis::iException::Programmer, msg, _FILEINFO_); + } + + // Ok the blob exists so we need to prep for reading the binary data + try { + p_startByte = p_blobPvl["StartByte"]; + p_nbytes = p_blobPvl["Bytes"]; + p_detached = ""; + if(p_blobPvl.HasKeyword("^" + p_type)) { + string path = ""; + if(p_labelFile != "") { + path = Filename(p_labelFile).Path() + "/"; + } + p_detached = path + (std::string) p_blobPvl["^"+p_type]; + p_blobPvl.DeleteKeyword("^" + p_type); + } + } + catch(Isis::iException &e) { + string msg = "Invalid " + p_type + " label format"; + throw Isis::iException::Message(Isis::iException::Pvl, msg, _FILEINFO_); + } + } + + /** + * Read binary data from an input stream into the Blob. + * + * @param stream The input stream to read from. + * + * @throws Isis::iException::Io - Error reading data from stream + */ + void Blob::ReadData(std::istream &stream) { + // Read the binary data + if(p_buffer != NULL) delete [] p_buffer; + p_buffer = new char[p_nbytes]; + + streampos sbyte = p_startByte - 1; + stream.seekg(sbyte, std::ios::beg); + if(!stream.good()) { + string msg = "Error preparing to read data from " + p_type + + " [" + p_blobName + "]"; + throw Isis::iException::Message(Isis::iException::Io, msg, _FILEINFO_); + } + + stream.read(p_buffer, p_nbytes); + if(!stream.good()) { + string msg = "Error reading data from " + p_type + " [" + p_blobName + "]"; + throw Isis::iException::Message(Isis::iException::Io, msg, _FILEINFO_); + } + } + + /** + * Write the blob data out to a file. + * + * @param file The filename to write to. + * + * @throws Isis::iException::Io - Unable to open file + * @throws Isis::iException::Io - Error preparing to write data to file + * @throws Isis::iException::Io - Error creating file + */ + void Blob::Write(const std::string &file) { + // Determine the size of the label and write it out + try { + WriteInit(); + Isis::Pvl pvl; + pvl.AddObject(p_blobPvl); + ostringstream os; + os << pvl << endl; + os.seekp(0, std::ios::end); + Isis::BigInt nbytes = (Isis::BigInt) os.tellp() + (Isis::BigInt) 64; + p_startByte = nbytes + 1 + 1; // 1-based; + pvl.FindObject(p_type)["StartByte"] = p_startByte; + pvl.FindObject(p_type)["Bytes"] = p_nbytes; + pvl.Write(file); + + // Prepare and write the binary data + fstream stream; + ios::openmode flags = std::ios::in | std::ios::binary | std::ios::out; + stream.open(file.c_str(), flags); + if(!stream) { + string message = "Unable to open [" + file + "]"; + throw Isis::iException::Message(Isis::iException::Io, message, _FILEINFO_); + } + + streampos sbyte = p_startByte - 1; + stream.seekp(sbyte, std::ios::beg); + if(!stream.good()) { + stream.close(); + string msg = "Error preparing to write data to " + + p_type + " [" + p_blobName + "]"; + throw Isis::iException::Message(Isis::iException::Io, msg, _FILEINFO_); + } + + WriteData(stream); + stream.close(); + } + catch(Isis::iException &e) { + string msg = "Unable to create " + p_type + " file [" + file + "]"; + throw Isis::iException::Message(Isis::iException::Io, msg, _FILEINFO_); + } + } + + /** + * Write the blob data out to a Pvl object. + * @param pvl The pvl object to update + * @param stm stream to write data to + * @param detachedFilename If the stream is detached from the labels give + * the name of the file + */ + void Blob::Write(Isis::Pvl &pvl, std::fstream &stm, + const std::string &detachedFilename) { + // Handle 64-bit I/O + WriteInit(); + + // Find out where they wanted to write the blob + streampos sbyte = stm.tellp(); + sbyte += 1; + + // Find out where the end-of-file is + stm.seekp(0, std::ios::end); + streampos eofbyte = stm.tellp(); + eofbyte += 1; + + // Handle detached blobs + if(detachedFilename != "") { + p_blobPvl += Isis::PvlKeyword("^" + p_type, detachedFilename); + } + + // See if the blob is already in the file + p_blobPvl["StartByte"] = (Isis::BigInt) sbyte; + p_blobPvl["Bytes"] = p_nbytes; + + bool found = false; + for(int i = 0; i < pvl.Objects(); i++) { + if(pvl.Object(i).Name() == p_blobPvl.Name()) { + PvlObject &obj = pvl.Object(i); + if((string) obj["Name"] == (string) p_blobPvl["Name"]) { + found = true; + + Isis::BigInt oldSbyte = obj["StartByte"]; + int oldNbytes = (int) obj["Bytes"]; + + // Does it fit in the old space + if(p_nbytes <= oldNbytes) { + p_blobPvl["StartByte"] = obj["StartByte"]; + sbyte = oldSbyte; + } + + // Was the old space at the end of the file + else if(((oldSbyte + oldNbytes) == eofbyte) && + (eofbyte >= sbyte)) { + p_blobPvl["StartByte"] = obj["StartByte"]; + sbyte = oldSbyte; + } + + // Put it at the requested position/end of the file + else { + // Leave this here for clarity + } + + obj = p_blobPvl; + } + } + } + + // Didn't find the same blob so add it to the labels + if(!found) { + pvl.AddObject(p_blobPvl); + } + + stm.seekp((Isis::BigInt) sbyte - (Isis::BigInt)1); + WriteData(stm); + + // Handle detached blobs + if(detachedFilename != "") { + p_blobPvl.DeleteKeyword("^" + p_type); + } + } + + /** + * Writes blob data to a stream + * + * @param stream Output steam blob data will be written to + * + * @throws Isis::iException::Io - Error writing data to stream + */ + void Blob::WriteData(std::fstream &stream) { + stream.write(p_buffer, p_nbytes); + if(!stream.good()) { + string msg = "Error writing data to " + p_type + " [" + p_blobName + "]"; + throw Isis::iException::Message(Isis::iException::Io, msg, _FILEINFO_); + } + } + + /** + * Checks pvl object and returns whether or not it is a Blob + * + * @param obj Pvl object + * + * @return bool Returns true if the object is a blob, and false if it is not + */ + bool IsBlob(Isis::PvlObject &obj) { + if(obj.IsNamed("TABLE")) return true; + return false; + } +} // end namespace isis + diff --git a/isis/src/base/objs/Blob/Blob.h b/isis/src/base/objs/Blob/Blob.h new file mode 100644 index 0000000000000000000000000000000000000000..69c7720935760761e48dcf9a0bb2edf6bd01c6cc --- /dev/null +++ b/isis/src/base/objs/Blob/Blob.h @@ -0,0 +1,95 @@ +#if !defined(Blob_h) +#define Blob_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/05/14 19:16:39 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "Pvl.h" + +namespace Isis { + bool IsBlob(Isis::PvlObject &obj); + /** + * @internal + * @history Jeff Anderson 04-04-2006 Class was not overwriting + * existing blobs correctly. + * @history Elizabeth Miller 02-20-2007 Fixed bug with + * OriginalLabel naming and modified to be backwards + * compatible + * @history Steven Lambright Added copy constructor, + * assignment operator + * @history Steven Lambright Added copy constructor, + * assignment operator + * @history 2010-05-15 Steven Lambright Changed Read to use an + * istream instead of an fstream + * + * @todo Write class description, history, etc. + */ + class Blob { + public: + Blob(const std::string &name, const std::string &type); + Blob(const std::string &name, const std::string &type, + const std::string &file); + Blob(const Blob &other); + virtual ~Blob(); + + void Read(const std::string &file); + virtual void Read(Isis::Pvl &pvl, std::istream &is); + + void Write(const std::string &file); + void Write(Isis::Pvl &pvl, std::fstream &stm, + const std::string &detachedFilename = ""); + + std::string Type() const { + return p_type; + }; + std::string Name() const { + return p_blobName; + }; + + PvlObject &Label() { + return p_blobPvl; + }; + + Blob &operator=(const Blob &other); + + protected: + void Find(Isis::Pvl &pvl); + virtual void ReadInit() {}; + virtual void ReadData(std::istream &is); + + virtual void WriteInit() {}; + virtual void WriteData(std::fstream &os); + + Isis::PvlObject p_blobPvl; //!< Pvl Blob object + std::string p_blobName; //!< Name of the Blob object + + char *p_buffer; //!< Buffer blob data is stored in + BigInt p_startByte; //!< Byte blob data starts at in buffer + int p_nbytes; //!< Size of blob data (in bytes) + std::string p_type; //!< Type of data stored in the buffer + std::string p_detached; //!< Used for reading detached blobs + std::string p_labelFile; //!< The file containing the labels + }; +}; + +#endif diff --git a/isis/src/base/objs/Blob/Blob.truth b/isis/src/base/objs/Blob/Blob.truth new file mode 100644 index 0000000000000000000000000000000000000000..3da78c2d7ce18b2f647e719e04e4f0c164833b27 --- /dev/null +++ b/isis/src/base/objs/Blob/Blob.truth @@ -0,0 +1,7 @@ +4 +150 +ABCD +3 +150 +4 +150 diff --git a/isis/src/base/objs/Blob/Makefile b/isis/src/base/objs/Blob/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a610430bffa131dfbc75df851ff28187f055c46c --- /dev/null +++ b/isis/src/base/objs/Blob/Makefile @@ -0,0 +1,5 @@ +INCS = Blob.h +SRCS = Blob.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Blob/unitTest.cpp b/isis/src/base/objs/Blob/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e3c283bf62d185115d87d28b739308a8b2982bf --- /dev/null +++ b/isis/src/base/objs/Blob/unitTest.cpp @@ -0,0 +1,75 @@ +#include +#include "Blob.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +class MyBlob : public Isis::Blob { + public: + MyBlob(const string &name) : Isis::Blob(name, "Blob") {}; + MyBlob(const string &name, const string &file) : Isis::Blob(name, "Blob", file) {}; + void MyBuf(char *buf, int size) { + p_buffer = new char[size]; + p_nbytes = size; + memcpy(p_buffer, buf, size); + }; + int Bytes() { + return p_nbytes; + }; + int StartByte() { + return p_startByte; + }; + void GetBuf(char *buf) { + memcpy(buf, p_buffer, p_nbytes); + } +}; + +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + try { + MyBlob b("UnitTest"); + char buf[] = {"ABCD"}; + b.MyBuf(buf, 4); + b.Write("junk"); + + MyBlob c("UNITtest", "junk"); + cout << c.Bytes() << endl; + cout << c.StartByte() << endl; + char buf2[5]; + c.GetBuf(buf2); + buf2[4] = 0; + cout << buf2 << endl; + + // Test writing into existing space + Isis::Pvl pvl("junk"); + fstream strm; + strm.open("junk", std::ios::binary | std::ios::out); + c.MyBuf(buf, 3); + c.Write(pvl, strm); + strm.seekp(0, std::ios::beg); + strm << pvl; + cout << c.Bytes() << endl; + cout << c.StartByte() << endl; + strm.close(); + + // Test writing over existing space at the end of file + Isis::Pvl pvl2("junk"); + fstream strm2; + strm2.open("junk", std::ios::binary | std::ios::out); + c.MyBuf(buf, 4); + c.Write(pvl2, strm2); + strm2.seekp(0, std::ios::beg); + strm2 << pvl2; + cout << c.Bytes() << endl; + cout << c.StartByte() << endl; + strm2.close(); + + remove("junk"); + + } + catch(Isis::iException &e) { + e.Report(); + } +} + diff --git a/isis/src/base/objs/Blobber/Blobber.cpp b/isis/src/base/objs/Blobber/Blobber.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9852d0ecc7f7b3756f6cc9f28690c0aa31a29354 --- /dev/null +++ b/isis/src/base/objs/Blobber/Blobber.cpp @@ -0,0 +1,239 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/05/14 21:07:10 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include "Blobber.h" +#include "Table.h" +#include "Cube.h" +#include "Progress.h" +#include "SpecialPixel.h" +#include "iException.h" + +namespace Isis { + +using std::string; +using std::vector; + +/** + * @brief Default basic constructor that is mostly not useful + * + * This basic constructor may only be required so that Blobbers can be + * used in STL constructs (as they require a default constructor) + */ +Blobber::Blobber() : _blobname("_undefined_"), _fieldname("_undefined_"), + _name("Blob") { } +/** + * @brief Name-only based constructor + * + * This constructor does not require an accompanying cube and allows the + * user to simply define the Table object and field names to establish these + * for multiple reads from different cubes. + * + * @param [in] blobname (const std::string&) specifies the name of the ISIS + * BLOB that contains the field + * to read the data from + * @param [in] fieldname (const std::string&) specifies the name of the field + * in blobname to read and convert + * to double precision floating point + * data + * @param [in] name (const std::string&) Associates a name of the implementors + * choosing that identifies an + * instantiation of this class + */ +Blobber::Blobber(const std::string &blobname, const std::string &fieldname, + const std::string &name) : _blobname(blobname), + _fieldname(fieldname), _name(name) { +} + +/** + * @brief Constructor using an ISIS cube class + * + * Reads the contents of the specified field (fieldname) from an ISIS table + * BLOB (blobname). Upon instatiation of this class, the BLOB data is read + * in and converted to double precision floating point data. Upon successful + * return from this construtor, the data is accessble through various methods. + * + * @param [in] cube (Cube&) Reference to an ISIS cube file that has been + * opened or created in the Cube object. This file + * is expected to contain a Table object that is + * named blobname and must contain a field called + * fieldname. + * @param [in] blobname (const std::string&) specifies the name of the ISIS + * BLOB that contains the field + * to read the data from + * @param [in] fieldname (const std::string&) specifies the name of the field + * in blobname to read and convert + * to double precision floating point + * data + * @param [in] name (const std::string&) Associates a name of the implementors + * choosing that identifies an + * instantiation of this class + */ +Blobber::Blobber(Cube &cube, const std::string &blobname, + const std::string &fieldname, + const std::string &name) : + _blobname(blobname), + _fieldname(fieldname), + _name(name) { + load(cube); +} + +/** + * @brief Create a unique copy of this blob + * + * This method creates a fully new copy of this object. The default copy + * constructors/methods create a reference to the data read from the Table + * object. For example, the following code fragment will result in two + * Blobbers that refer to the same memory location that stores the BLOB data: + * + * @code + * Blobber myblob = yourblob; + * @endcode + * + * To ensure you have two unique storage areas of the BLOB data so they + * can change independantly, use: + * + * @code + * Blobber myblob = yourblob.deepcopy(); + * @endcode + * + * @return (Blobber) Returns a completely new copy, including data, to + * caller. + */ +Blobber Blobber::deepcopy() const { + Blobber myblob = *this; + myblob._buf = _buf.copy(); + return (myblob); +} + +/** + * @brief Loads the contents of a BLOB from a cube file + * + * Provides the I/O interface for ISIS cube files. + * + * @param [in] filename (string&) Name of ISIS cube file to read + */ +void Blobber::load(const std::string &filename) { + Cube cube; + cube.Open(filename); + load(cube); + return; +} +/** + * @brief Loads the contents of a BLOB from a Cube object + * + * Provides the I/O interface for the Cube object. One thing to note here + * is that it creates a CubeInfo object from the Cube object and then calls + * the CubeInfo load method. Hence, this method is required as an + * intermediary method that cascades to the actual method that does the real + * work. + * + * @param [in] cube (Cube&) Reference to an ISIS cube file that has been + * opened or created in the Cube object. + */ +void Blobber::load(Cube &cube) { + Table tbl(getBlobName()); + cube.Read(tbl); + TableField data = tbl[0][getFieldName()]; + if (data.IsDouble()) { + loadDouble(tbl); + } + else if (data.IsInteger()) { + loadInteger(tbl); + } + else { + string msg = "Field type for " + getFieldName() + + " is not double or integer"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } +} + + +/** + * @brief Provides direct reading in of the field data from the BLOB + * + * This method is called when the data stored in the BLOB is double precision. + * It determines the number of rows (lines) and columns (samples) in the BLOB + * and allocates the internal buffer required to store it + * + * @param [in] tbl (Table&) Reference to an ISIS Table object that contains the + * field from which to extract the data. + */ +void Blobber::loadDouble(Table &tbl) { + int nlines = tbl.Records(); + int nsamps = tbl[0][getFieldName()].Size(); + BlobBuf pixels(nlines, nsamps); + for (int i = 0 ; i < nlines ; i++) { + vector d = tbl[i][getFieldName()]; + for (unsigned int j = 0 ; j < d.size() ; j++) { + pixels[i][j] = d[j]; + } + } + _buf = pixels; +} + +/** + * @brief Provides direct reading in of the field data from the BLOB + * + * This method is called when the data stored in the BLOB is integer data. + * It determines the number of rows (lines) and columns (samples) in the BLOB + * and allocates the internal buffer required to store it. This differs from + * the double precision version only in the care taken when casting the data + * to double precision. We must properly convert special pixels from integer + * to double precision. + * + * @param [in] tbl (Table&) Reference to an ISIS Table object that contains the + * field from which to extract the data. + */ +void Blobber::loadInteger(Table &tbl) { + int nlines = tbl.Records(); + int nsamps = tbl[0][getFieldName()].Size(); + BlobBuf pixels(nlines, nsamps); + for (int i = 0 ; i < nlines ; i++) { + vector d = tbl[i][getFieldName()]; + for (unsigned int j = 0 ; j < d.size(); j++) { + pixels[i][j] = int2ToDouble(d[j]); + } + } + _buf = pixels; +} + +/** + * @brief Converts integer data to double precision + * + * This method lives to properly handle the conversion of integer BLOB data + * to double precision. We must properly convert integer special pixel data + * that may exist in the BLOB to its appropriate double precision value. + * + * @param [in] value (int) Integer value to convert + */ +double Blobber::int2ToDouble (int value) const { + if (value == NULL2) return NULL8; + else if (value == LOW_REPR_SAT2) return LOW_REPR_SAT8; + else if (value == LOW_INSTR_SAT2) return LOW_INSTR_SAT8; + else if (value == HIGH_INSTR_SAT2) return HIGH_INSTR_SAT8; + else if (value == HIGH_REPR_SAT2) return HIGH_REPR_SAT8; + else return value; + +} + +} // end namespace Isis diff --git a/isis/src/base/objs/Blobber/Blobber.h b/isis/src/base/objs/Blobber/Blobber.h new file mode 100644 index 0000000000000000000000000000000000000000..e9b20b9c0d4605db437448713a0787b293b7695a --- /dev/null +++ b/isis/src/base/objs/Blobber/Blobber.h @@ -0,0 +1,240 @@ +#ifndef Blobber_h +#define Blobber_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2009/12/22 02:09:54 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "tnt/tnt_array2d.h" + +namespace Isis { + +class Cube; +class CubeInfo; +class Table; + + /** + * @brief Base class for accessing ISIS blobs + * + * This class will read any ISIS BLOB and provide generalized access + * to its data. Developers can derive new classes that define access + * information in the form of names of the Isis Object and field name. + * + * The entire contents of the field are read in and internally stored + * as double floating point values. All recognized ISIS special pixels + * are converted when read. + * + * Note that this provides read access only. Currently, no output is performed + * in this implementation although it could be acheived in derived classes. + * + * This class does not maintain persistant access to the BLOB. This means + * that the entire contents of the BLOB are read and stored and the interface + * to the ISIS BLOB is then terminated. + * + * Below is an example using this class to access a HiRISE BLOB. It loads + * the BLOB, reports the number of lines and samples and then computes + * the mean and standard deviation using the Statistics class: + * + * @code + * Cube cube("hirise.cub"); + * Blobber hiblob(cube, "HiRISE Calibration Image", "Calibration", + * "CalibrationImage"); + * std::cout << "Number of lines: " << hiblob.Lines() << std::endl; + * std::cout << "Number of samples: " << hiblob.Samples() << std::endl; + * + * Statistics stats; + * for (int line = 0 ; line < hiblob.Lines() ; line++) { + * stats.AddData(hiblob[line], hiblob.Samples()); + * } + * + * std::cout << "Average: " << stats.Average() << std::endl; + * std::cout << "StdDev: " << stats.StandardDeviation() << std::endl; + * @endcode + * + * In the above example, the name of the ISIS Table (BLOB) is "HiRISE + * Calibration Image" and the field of interest in that table is "Calibration". + * Upon instantiation, the BLOB contents are read and converted to double + * precision floating point values. + * + * Note that this class is reuseable and reentrant. This provides the user + * to specify a different cube to load the data from. + * + * One special thing to note that assigning these objects to other object + * variables results in a \b reference to the data...it is \b not copied. + * The following illustrates this concept: + * @code + * Cube cube('hirise.cub'); + * Blobber hiblob(cube, "HiRISE Calibration Image", "Calibration", + * "CalibrationImage"); + * + * Blobber myblob(hiblob); + * Blobber blob2 = myblob; + * @endcode + * In this example, \b hiblob, \b myblob and \b blob2 refer to the same + * blob data. + * Changing a pixel element in one blob results in the change in all + * instances of the blob. To get a completely independant copy of the + * data, use the \b deepcopy() method. + * + * @ingroup LowLevelCubeIO + * + * @author 2005-12-16 Kris Becker + * + * @internal + * @history 2008-05-12 Steven Lambright - Removed references to CubeInfo + * @history 2008-06-18 Christopher Austin - Fixed documentation errors + */ + class Blobber { + public: + Blobber(); + Blobber(const std::string &blobname, const std::string &fieldname, + const std::string &name = "Blob"); + Blobber(Cube &cube, const std::string &blobname, + const std::string &fieldname, const std::string &name = "Blob"); + /** Destructor of this object */ + virtual ~Blobber() { } + + Blobber deepcopy() const; + + /** + * @brief Specifies the name of this class instantiation + * + * This is just an additional name that can be used to identify + * instantiations of this class. It provides a way to uniquely + * identify each object. + * + * @param name Unique name + */ + void setName(const std::string &name) { _name = name; } + + /** + * @brief Sets the name of the ISIS BLOB object that contains the data + * + * This is name of a ISIS Table object that contains one or more fields + * that make up the BLOB. This is the value of the [i]Name[/i] keyword + * in the Table object. + * + * @param bname Blobber name + */ + void setBlobName(const std::string &bname) { _blobname = bname; } + + /** + * @brief Sets field name in the ISIS BLOB object that contains data + * + * This method sets the name of the field contained within the Table + * object BLOB from which the data is extracted. + * + * @param fname Field name + */ + void setFieldName(const std::string &fname) { _fieldname = fname; } + + /** + * Returns the total number of elements (rows * columns) in blob + * @return The product of rows and columns + */ + inline int size() const { return (Lines() * Samples()); } + + /** + * Number of rows or lines in the BLOB + * @return The lines or rows + */ + inline int Lines() const { return (_buf.dim1()); } + /** + * Number of columns or samples in the BLOB + * @return The number of samples or columns + */ + inline int Samples() const { return (_buf.dim2()); } + + /** + * Returns the name of the BLOB given to refer to this instantiation + * @return Name of BLOB instance + */ + std::string getName() const { return (_name); } + + /** + * @brief Retrieves the name of the Table object + * @return (string) Name of the Table + */ + std::string getBlobName() const { return (_blobname); } + + /** + * @brief Retreive the name of the field in the Tabel object BLOB + * @return (string) Name of the BLOB field + */ + std::string getFieldName() const { return (_fieldname); } + + /** + * Returns the ith row/line in the BLOB that can be further referenced + * into samples. To access the 2nd sample in the 10th line use: + * @code + * double sample = blobber[9][1]; + * @endcode + * + * @param i Index + * + * @return Pointer to the ith row in the BLOB + */ + inline double *operator[](int i) {return (_buf[i]); } + /** + * Returns the ith row/line in the BLOB that can be further referenced + * into samples. This method provides const access to the data in + * row matrix form. To access the 2nd sample in the 10th line use: + * @code + * double sample = blobber[9][1]; + * @endcode + * + * @param i Index + * + * @return Const pointer to the ith row in the BLOB + */ + inline double const *operator[](int i) const { return (_buf[i]); } + +// Load options for reading the BLOB from ISIS files + void load(const std::string &filename); + void load(Cube &cube); + + + protected: + typedef TNT::Array2D BlobBuf; //!< Internal buffer uses TNT + + /** + * Returns a const reference to the internal buffer for ease of use + * to derived objects. + * @return Const reference to BLOB buffer + */ + inline const BlobBuf &ref() const { return (_buf); } + + private: + std::string _blobname; //!< Name of BLOB to read + std::string _fieldname; //!< Name of field in BLOB to read + std::string _name; //!< Name of this data set + BlobBuf _buf; //!< Buffer holding data + +// Low/level I/O and conversion methods + void loadDouble(Table &tbl); + void loadInteger(Table &tbl); + double int2ToDouble (int value) const; + }; +}; + +#endif + diff --git a/isis/src/base/objs/Blobber/Blobber.truth b/isis/src/base/objs/Blobber/Blobber.truth new file mode 100644 index 0000000000000000000000000000000000000000..e8f70c7adef90f31c760a83a8791ee32cb773b8a --- /dev/null +++ b/isis/src/base/objs/Blobber/Blobber.truth @@ -0,0 +1,24 @@ +*** Blobber unitTest *** + +File Source: $base/testData/blobTruth.cub + +** Test Cube Class access... +Blob Name: Blobber +Object Name: HiRISE Calibration Ancillary +Field Name: DarkPixels +Number Blob Lines: 168 +Number Blob Samples: 16 +Total Pixels: 2688 + +** Blob Values... +Pixel[0][0] = 1008 +Pixel[84][8] = 1115 +Pixel[167][15] = 1259 + +** Test Blobber direct access (via filename)... + +** Test Blobber(Blobber) constructor... + +** Test Blobber copy assignment (constructor)... + +** Test Blobber deep copy... diff --git a/isis/src/base/objs/Blobber/Makefile b/isis/src/base/objs/Blobber/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5c737792152ff1813ac586a0c3091cec42a52b9f --- /dev/null +++ b/isis/src/base/objs/Blobber/Makefile @@ -0,0 +1,5 @@ +INCS = Blobber.h +SRCS = Blobber.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Blobber/unitTest.cpp b/isis/src/base/objs/Blobber/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d52e4ae202615ad6fe494db75ba69273e4ed0fd1 --- /dev/null +++ b/isis/src/base/objs/Blobber/unitTest.cpp @@ -0,0 +1,157 @@ +#include +#include "Preference.h" +#include "SpecialPixel.h" +#include "Blobber.h" +#include "iException.h" +#include "Cube.h" + +using namespace std; +using namespace Isis; + +int main (int argc, char *argv[]) { + int nfailed(0); + try { + + std::cout << "*** Blobber unitTest ***\n"; + Preference::Preferences(true); + string fname = "$base/testData/blobTruth.cub"; + std::cout << "\nFile Source: " << fname << std::endl; + +// This is assumed to be Hirise cube source + string blobName = "HiRISE Calibration Ancillary"; + string fieldName = "DarkPixels"; + string name = "Blobber"; + +// Test access from Cube object class + std::cout << "\n** Test Cube Class access...\n"; + Cube cube; + cube.Open(fname); + Blobber blob1(cube, blobName, fieldName, name); + std::cout << "Blob Name: " << blob1.getName() << std::endl; + std::cout << "Object Name: " << blob1.getBlobName() << std::endl; + std::cout << "Field Name: " << blob1.getFieldName() << std::endl; + std::cout << "Number Blob Lines: " << blob1.Lines() << std::endl; + std::cout << "Number Blob Samples: " << blob1.Samples() << std::endl; + std::cout << "Total Pixels: " << blob1.size() << std::endl; + + BigInt lines(blob1.Lines()), samples(blob1.Samples()), + ntotal(blob1.size()); + +// Ensure product of lines & sample are equal to size() + if (ntotal != (lines * samples)) { + std::cout << "--> FAILED < Total Blob Size (" << ntotal + << ") does not equal product of Lines, Samples (" + << (lines * samples) << ")!\n"; + nfailed++; + } + +// Test access to pixels + double pixel0 = blob1[0][0]; + double pixelN = blob1[lines-1][samples-1]; + double pixelx = blob1[lines/2][samples/2]; + + std::cout << "\n** Blob Values...\n"; + std::cout << "Pixel[0][0] = " << PixelToString(pixel0) << std::endl; + std::cout << "Pixel[" << (lines/2) << "][" << (samples/2) << "] = " + << PixelToString(pixelx) << std::endl; + std::cout << "Pixel[" << (lines-1) << "][" << (samples-1) << "] = " + << PixelToString(pixelN) << std::endl; + +// Now reload using Cube explicit method + blob1.load(cube); + if (pixel0 != blob1[0][0]) { + std::cout << "--> FAILED < Pixel[Line=0][Sample=0] = " << pixel0 + << " != " << blob1[0][0] << " after reload!!" << std::endl; + nfailed++; + } + + if (pixelx != blob1[lines/2][samples/2]) { + std::cout << "--> FAILED < Pixel[Line=" << (lines/2) + << "][Sample=" << (samples/2) + << "] = " << pixelx << " != " + << blob1[lines/2][samples/2] + << " after reload!!" << std::endl; + nfailed++; + } + + + if (pixelN != blob1[lines-1][samples-1]) { + std::cout << "--> FAILED < Pixel[Line=" << (lines-1) + << "][Sample=" << (samples-1) + << "] = " << pixelN << " != " + << blob1[lines-1][samples-1] + << " after reload!!" << std::endl; + nfailed++; + } + +// Test Cube access to blob + std::cout << "\n** Test Blobber direct access (via filename)...\n"; + Blobber blob3(blobName, fieldName, name); + blob3.load(fname); + + if (pixelx != blob3[lines/2][samples/2]) { + std::cout << "--> FAILED < Pixel[Line=" << (lines/2) + << "][Sample=" << (samples/2) + << "] = " << pixelx << " != " + << blob1[lines/2][samples/2] + << " from named file source!!" << std::endl; + nfailed++; + } + +// Test copying + std::cout << "\n** Test Blobber(Blobber) constructor...\n"; + Blobber blob4(blob1); + if (pixelx != blob4[lines/2][samples/2]) { + std::cout << "--> FAILED < Pixel[Line=" << (lines/2) + << "][Sample=" << (samples/2) + << "] = " << pixelx << " != " + << blob1[lines/2][samples/2] + << " from Blobber(blob) constructor!!" << std::endl; + nfailed++; + + } + + std::cout << "\n** Test Blobber copy assignment (constructor)...\n"; + Blobber blob5 = blob1; + if (pixelx != blob5[lines/2][samples/2]) { + std::cout << "--> FAILED < Pixel[Line=" << (lines/2) + << "][Sample=" << (samples/2) + << "] = " << pixelx << " != " + << blob1[lines/2][samples/2] + << " from Blobber blob = oblob constructor!!" << std::endl; + nfailed++; + } + + +// Test deep copy + std::cout << "\n** Test Blobber deep copy...\n"; + Blobber blob6; + blob6 = blob1.deepcopy(); + if (pixelx != blob6[lines/2][samples/2]) { + std::cout << "--> FAILED < Pixel[Line=" << (lines/2) + << "][Sample=" << (samples/2) + << "] = " << pixelx << " != " + << blob1[lines/2][samples/2] + << " from deepcopy!!" << std::endl; + nfailed++; + } + +// Now change pixel in copied version + blob6[lines/2][samples/2] += 1.0; + if (blob1[lines/2][samples/2] == blob6[lines/2][samples/2]) { + std::cout << "--> FAILED < Pixel[Line=" << (lines/2) + << "][Sample=" << (samples/2) + << "] = " << pixelx << " == " + << blob1[lines/2][samples/2] + << " deepcopy failed to make separate copy!!" << std::endl; + nfailed++; + } + } + catch (Isis::iException &e) { + e.Report(); + } + + // Return status + return (nfailed); +} + diff --git a/isis/src/base/objs/BoxcarManager/BoxcarManager.cpp b/isis/src/base/objs/BoxcarManager/BoxcarManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d13f32476a8b21f2d7063b9e82efa9d9a7dbb933 --- /dev/null +++ b/isis/src/base/objs/BoxcarManager/BoxcarManager.cpp @@ -0,0 +1,50 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "BoxcarManager.h" + +using namespace std; +namespace Isis { +/** + * Constructs a BoxcarManager object + * + * @param cube The cube this buffer will be associated with. + * + * @param boxSamples The number of samples in each boxcar buffer. + * + * @param boxLines The number of lines in each boxcar buffer. + */ + BoxcarManager::BoxcarManager(const Isis::Cube &cube, + const int &boxSamples, const int &boxLines) : + Isis::BufferManager(cube.Samples(),cube.Lines(),cube.Bands(), + boxSamples,boxLines,1,cube.PixelType()) { + + Isis::BufferManager::SetIncrements (1,1,1); + int soff,loff,boff; + soff = (int) ((boxSamples-1) / 2) * -1; + loff = (int) ((boxLines-1) / 2) * -1; + boff = 0; + Isis::BufferManager::SetOffsets (soff,loff,boff); + } +} // end namespace isis + diff --git a/isis/src/base/objs/BoxcarManager/BoxcarManager.h b/isis/src/base/objs/BoxcarManager/BoxcarManager.h new file mode 100644 index 0000000000000000000000000000000000000000..2d13572b010b637fe793053c8068d50f51d1cf5c --- /dev/null +++ b/isis/src/base/objs/BoxcarManager/BoxcarManager.h @@ -0,0 +1,78 @@ +#if !defined(BoxcarManager_h) +#define BoxcarManager_h +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "BufferManager.h" +#include "Cube.h" + +namespace Isis { +/** + * @brief Buffer manager, for moving through a cube by boxcar. + * + * This class is used as a manager for moving through a cube one boxcar at + * a time. A boxcar is defined as two-dimensional (n samples by m lines) + * sub area of a cube. The band direction is always one deep. + * + * The sequence of boxcars starts with the boxcar containing sample one, line + * one and band one. It then moves across the cube in the sample direction one + * pixel at a time, then the line direction and finally to the next boxcar in + * the band direction. + * + * The pixel being processed will be indexed into the boxcar buffer as follows: + * index = (int((boxLines-1)/2) * boxSamples) + int((boxSamples-1)/2), + * for example, if the boxcar is 5x5, the pixel being processed would be at + * sample 3, line 3 of the boxcar. If the boxcar is a 4x4, the pixel being + * processed would be at sample 2, line 2. + * + * If you would like to see BoxcarManager being used in implementation, + * see the ProcessByBoxcar class. + * + * @ingroup LowLevelCubeIO + * + * @author 2003-01-02 Tracie Sucharski + * + * @internal + * @history 2003-04-01 Tracie Sucharski - added documentation explaining the + * offsets (which pixel is being + * processed within the boxcar) and + * added unitTest. + * @history 2003-05-16 Stuart Sides - modified schema from + * astrogeology...isis.astrogeology + */ + class BoxcarManager : public Isis::BufferManager { + + public: + // Constructors and Destructors + BoxcarManager(const Isis::Cube &cube, + const int &boxSamples, const int &boxLines); + + //! Destroys the BoxcarManager object + ~BoxcarManager() {}; + + }; +}; + +#endif + + diff --git a/isis/src/base/objs/BoxcarManager/BoxcarManager.truth b/isis/src/base/objs/BoxcarManager/BoxcarManager.truth new file mode 100644 index 0000000000000000000000000000000000000000..33cb64f293d7b2612dc1d188ed392bc4f015d70e --- /dev/null +++ b/isis/src/base/objs/BoxcarManager/BoxcarManager.truth @@ -0,0 +1,762 @@ +Buffer (Boxcar) Size: 5 5 1 + + Coordinates of upper left corner of boxcar, sample, line, band is: -1 -1 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 -1 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 0 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 0 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 1 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 1 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 2 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 2 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 3 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 3 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 4 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 4 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 5 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 5 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 6 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 6 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 7 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 7 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 8 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 8 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 9 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 9 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 10 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 10 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 11 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 11 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 12 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 12 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 13 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 13 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 14 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 14 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 15 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 15 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 16 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 16 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 17 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 17 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 18 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 18 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 19 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 19 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 20 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 20 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 21 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 21 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 22 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 22 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 23 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 23 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 24 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 24 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 25 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 25 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 26 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 26 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 27 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 27 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 28 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 28 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 29 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 29 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 30 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 30 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 31 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 31 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 32 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 32 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 33 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 33 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 34 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 34 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 35 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 35 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 36 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 36 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 37 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 37 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 38 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 38 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 39 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 39 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 40 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 40 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 41 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 41 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 42 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 42 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 43 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 43 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 44 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 44 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 45 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 45 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 46 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 46 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 47 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 47 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 48 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 48 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 49 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 49 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 50 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 50 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 51 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 51 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 52 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 52 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 53 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 53 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 54 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 54 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 55 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 55 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 56 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 56 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 57 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 57 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 58 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 58 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 59 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 59 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 60 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 60 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 61 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 61 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 62 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 62 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 63 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 63 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 64 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 64 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 65 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 65 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 66 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 66 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 67 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 67 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 68 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 68 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 69 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 69 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 70 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 70 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 71 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 71 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 72 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 72 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 73 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 73 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 74 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 74 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 75 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 75 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 76 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 76 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 77 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 77 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 78 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 78 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 79 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 79 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 80 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 80 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 81 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 81 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 82 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 82 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 83 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 83 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 84 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 84 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 85 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 85 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 86 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 86 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 87 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 87 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 88 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 88 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 89 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 89 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 90 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 90 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 91 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 91 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 92 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 92 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 93 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 93 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 94 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 94 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 95 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 95 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 96 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 96 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 97 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 97 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 98 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 98 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 99 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 99 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 100 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 100 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 101 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 101 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 102 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 102 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 103 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 103 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 104 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 104 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 105 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 105 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 106 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 106 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 107 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 107 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 108 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 108 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 109 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 109 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 110 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 110 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 111 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 111 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 112 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 112 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 113 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 113 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 114 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 114 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 115 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 115 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 116 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 116 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 117 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 117 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 118 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 118 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 119 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 119 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 120 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 120 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 121 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 121 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 122 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 122 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 123 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 123 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 124 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 124 1 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 -1 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 -1 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 0 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 0 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 1 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 1 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 2 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 2 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 3 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 3 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 4 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 4 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 5 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 5 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 6 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 6 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 7 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 7 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 8 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 8 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 9 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 9 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 10 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 10 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 11 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 11 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 12 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 12 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 13 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 13 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 14 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 14 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 15 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 15 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 16 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 16 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 17 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 17 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 18 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 18 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 19 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 19 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 20 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 20 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 21 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 21 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 22 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 22 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 23 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 23 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 24 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 24 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 25 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 25 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 26 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 26 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 27 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 27 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 28 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 28 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 29 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 29 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 30 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 30 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 31 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 31 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 32 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 32 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 33 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 33 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 34 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 34 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 35 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 35 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 36 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 36 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 37 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 37 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 38 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 38 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 39 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 39 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 40 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 40 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 41 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 41 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 42 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 42 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 43 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 43 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 44 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 44 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 45 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 45 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 46 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 46 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 47 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 47 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 48 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 48 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 49 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 49 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 50 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 50 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 51 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 51 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 52 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 52 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 53 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 53 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 54 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 54 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 55 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 55 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 56 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 56 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 57 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 57 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 58 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 58 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 59 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 59 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 60 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 60 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 61 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 61 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 62 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 62 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 63 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 63 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 64 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 64 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 65 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 65 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 66 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 66 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 67 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 67 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 68 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 68 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 69 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 69 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 70 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 70 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 71 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 71 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 72 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 72 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 73 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 73 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 74 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 74 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 75 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 75 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 76 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 76 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 77 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 77 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 78 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 78 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 79 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 79 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 80 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 80 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 81 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 81 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 82 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 82 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 83 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 83 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 84 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 84 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 85 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 85 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 86 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 86 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 87 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 87 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 88 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 88 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 89 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 89 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 90 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 90 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 91 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 91 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 92 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 92 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 93 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 93 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 94 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 94 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 95 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 95 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 96 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 96 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 97 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 97 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 98 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 98 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 99 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 99 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 100 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 100 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 101 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 101 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 102 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 102 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 103 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 103 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 104 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 104 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 105 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 105 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 106 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 106 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 107 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 107 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 108 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 108 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 109 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 109 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 110 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 110 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 111 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 111 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 112 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 112 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 113 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 113 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 114 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 114 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 115 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 115 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 116 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 116 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 117 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 117 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 118 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 118 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 119 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 119 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 120 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 120 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 121 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 121 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 122 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 122 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 123 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 123 2 + Coordinates of upper left corner of boxcar, sample, line, band is: -1 124 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 124 2 + +Buffer (Boxcar) Size: 4 4 1 + + Coordinates of upper left corner of boxcar, sample, line, band is: 0 0 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 1 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 2 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 3 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 4 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 5 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 6 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 7 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 8 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 9 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 10 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 11 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 12 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 13 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 14 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 15 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 16 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 17 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 18 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 19 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 20 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 21 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 22 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 23 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 24 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 25 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 26 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 27 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 28 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 29 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 30 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 31 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 32 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 33 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 34 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 35 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 36 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 37 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 38 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 39 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 40 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 41 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 42 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 43 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 44 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 45 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 46 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 47 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 48 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 49 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 50 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 51 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 52 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 53 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 54 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 55 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 56 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 57 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 58 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 59 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 60 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 61 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 62 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 63 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 64 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 65 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 66 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 67 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 68 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 69 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 70 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 71 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 72 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 73 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 74 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 75 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 76 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 77 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 78 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 79 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 80 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 81 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 82 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 83 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 84 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 85 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 86 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 87 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 88 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 89 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 90 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 91 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 92 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 93 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 94 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 95 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 96 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 97 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 98 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 99 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 100 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 101 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 102 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 103 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 104 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 105 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 106 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 107 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 108 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 109 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 110 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 111 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 112 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 113 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 114 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 115 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 116 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 117 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 118 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 119 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 120 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 121 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 122 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 123 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 124 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 125 1 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 0 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 1 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 2 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 3 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 4 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 5 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 6 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 7 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 8 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 9 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 10 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 11 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 12 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 13 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 14 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 15 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 16 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 17 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 18 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 19 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 20 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 21 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 22 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 23 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 24 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 25 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 26 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 27 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 28 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 29 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 30 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 31 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 32 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 33 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 34 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 35 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 36 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 37 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 38 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 39 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 40 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 41 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 42 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 43 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 44 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 45 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 46 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 47 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 48 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 49 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 50 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 51 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 52 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 53 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 54 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 55 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 56 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 57 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 58 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 59 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 60 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 61 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 62 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 63 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 64 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 65 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 66 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 67 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 68 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 69 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 70 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 71 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 72 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 73 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 74 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 75 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 76 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 77 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 78 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 79 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 80 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 81 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 82 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 83 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 84 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 85 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 86 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 87 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 88 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 89 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 90 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 91 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 92 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 93 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 94 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 95 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 96 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 97 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 98 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 99 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 100 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 101 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 102 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 103 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 104 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 105 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 106 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 107 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 108 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 109 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 110 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 111 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 112 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 113 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 114 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 115 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 116 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 117 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 118 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 119 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 120 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 121 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 122 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 123 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 124 2 + Coordinates of upper left corner of boxcar, sample, line, band is: 0 125 2 + diff --git a/isis/src/base/objs/BoxcarManager/Makefile b/isis/src/base/objs/BoxcarManager/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..284376b049e9dd7e461ccd5e93bc01a49fc6697e --- /dev/null +++ b/isis/src/base/objs/BoxcarManager/Makefile @@ -0,0 +1,5 @@ +INCS = BoxcarManager.h +SRCS = BoxcarManager.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/BoxcarManager/unitTest.cpp b/isis/src/base/objs/BoxcarManager/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3dc21a492654873d61ead40c1fa26d642f04a6df --- /dev/null +++ b/isis/src/base/objs/BoxcarManager/unitTest.cpp @@ -0,0 +1,56 @@ +#include +#include +#include + +#include "Preference.h" +#include "Cube.h" +#include "BoxcarManager.h" + +using namespace std; + +int main (int argc, char *argv[]) { + + Isis::Preference::Preferences(true); + + string fname = "$base/testData/isisTruth.cub"; + Isis::Cube cube; + cube.Open (fname); + + // Test 5x5 boxcar + Isis::BoxcarManager box5x5(cube,5,5); + cout << "Buffer (Boxcar) Size: " << + box5x5.SampleDimension() << " " << + box5x5.LineDimension() << " " << + box5x5.BandDimension() << endl; + cout << endl; + + for (box5x5.begin(); !box5x5.end(); box5x5++) { + if (box5x5.Sample() <= 0) { + cout << " Coordinates of upper left corner of boxcar, sample, line, band is: " + << box5x5.Sample() << " " + << box5x5.Line() << " " + << box5x5.Band() << endl; + } + } + cout << endl; + + // Test 4x4 boxcar + Isis::BoxcarManager box4x4(cube,4,4); + cout << "Buffer (Boxcar) Size: " << + box4x4.SampleDimension() << " " << + box4x4.LineDimension() << " " << + box4x4.BandDimension() << endl; + cout << endl; + + for (box4x4.begin(); !box4x4.end(); box4x4++) { + if (box4x4.Sample() <= 0) { + cout << " Coordinates of upper left corner of boxcar, sample, line, band is: " + << box4x4.Sample() << " " + << box4x4.Line() << " " + << box4x4.Band() << endl; + } + } + cout << endl; + + cube.Close (); +} diff --git a/isis/src/base/objs/Brick/Brick.cpp b/isis/src/base/objs/Brick/Brick.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b06ff9ac2c7c19de86b798b8714e075cd21aa5c1 --- /dev/null +++ b/isis/src/base/objs/Brick/Brick.cpp @@ -0,0 +1,66 @@ +/** + * + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "Brick.h" + +namespace Isis { + /** + * Resizes the memory buffer to the specified number of samples, lines, and + * bands. + * + * @param nsamps Number of samples + * @param nlines Number of lines + * @param nbands Number of bands + */ + void Brick::Resize(const int nsamps, const int nlines, const int nbands) { + delete [] p_buf; + delete [] (char *) p_rawbuf; + p_nsamps = nsamps; + p_nlines = nlines; + p_nbands = nbands; + p_npixels = p_nsamps * p_nlines * p_nbands; + Allocate(); + } + + /** + * Sets the current brick as requested + * + * @param brick The brick number within a cube. This number starts with the + * upper left corner of the cube and proceedes across the samples + * then down the lines and lastly through the bands. The first + * brick starts at (1,1,1). The last brick contains the point + * (cubeSamples,cubeLines,cubeBands). + * + * @return bool + * + * @throws Isis::iException::Programmer - invalid argument value + */ + bool Brick::SetBrick (const int brick) { + if (brick < 1) { + std::string message = "Invalid value for argument [brick]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + return setpos(brick-1); + } +} // end namespace isis diff --git a/isis/src/base/objs/Brick/Brick.h b/isis/src/base/objs/Brick/Brick.h new file mode 100644 index 0000000000000000000000000000000000000000..e6cd91f3c7ce8ae35ed2a69d6ad94b32891289ce --- /dev/null +++ b/isis/src/base/objs/Brick/Brick.h @@ -0,0 +1,138 @@ +#if !defined(Brick_h) +#define Brick_h +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PixelType.h" +#include "BufferManager.h" +#include "Cube.h" + +namespace Isis { +/** + * @brief Buffer for containing a three dimensional section of an image + * + * This class is a Buffer. The shape of the buffer is three dimensional in the + * line, sample, and band directions. This class provides a random access + * window into a cube. The position can be set to any line, sample and band, + * including outside the image. + * + * @ingroup LowLevelCubeIO + * + * @author 2005-01-18 Jeff Anderson + * + * @internal + * @history 2005-02-25 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2006-04-21 Jacob Danton - Modified Brick to extend BufferManager, + * added new constructor, and two methods, + * SetBrick and Bricks + * + * @todo 2005-02-28 Jeff Anderson - add coded and implementation examples to + * class documentation + */ + class Brick : public Isis::BufferManager { + public: + + /** + * Constructs a Brick object + * + * @param nsamps Number of samples in shape buffer + * + * @param nlines Number of lines in shape buffer + * + * @param nbands Number of bands in shape buffer + * + * @param type Type of pixel in raw buffer + */ + Brick(const int nsamps, const int nlines, const int nbands, + const Isis::PixelType type) : + Isis::BufferManager(nsamps,nlines,nbands, + nsamps,nlines,nbands,type) { + }; + + Brick(const Isis::Cube &cube, const int &bufNumSamples, + const int &bufNumLines, const int &bufNumBands) : + Isis::BufferManager(cube.Samples(),cube.Lines(),cube.Bands(), + bufNumSamples,bufNumLines,bufNumBands, + cube.PixelType()) { + }; + + public: + /** + * This method is used to set the base position of the shape buffer. + * It is used to progress sequentially through a cube by brick. + * + * @param start_sample Starting sample to set. + * @param start_line Starting line to set. + * @param start_band Starting band to set. + */ + void SetBasePosition(const int start_sample, const int start_line, + const int start_band) { + this->Isis::Buffer::SetBasePosition(start_sample,start_line,start_band); + }; + + /** + * This method is used to set the base sample position of the shape buffer. + * + * @param start_samp Starting sample to set + */ + inline void SetBaseSample(const int start_samp) + { this->Isis::Buffer::SetBaseSample(start_samp);}; + + /** + * This method is used to set the base line position of the shape buffer. + * + * @param start_line Starting line to set + */ + inline void SetBaseLine(const int start_line) + { this->Isis::Buffer::SetBaseLine(start_line);}; + + /** + * This method is used to set the base band position of the shape buffer. + * + * @param start_band Starting band to set + */ + inline void SetBaseBand(const int start_band) + { this->Isis::Buffer::SetBaseBand(start_band);}; + + void Resize (const int nsamps, const int nlines, const int nbands); + + /** + * This method is used to set the position of the brick. + * + * @param brick Brick number to move to. + * + * @return bool Is the brick at the end of the cube? + */ + bool SetBrick(const int brick); + + /** + * Returns the number of Bricks in the cube. + * + * @return int + */ + inline int Bricks() { return MaxMaps();}; + }; +}; + +#endif diff --git a/isis/src/base/objs/Brick/Brick.truth b/isis/src/base/objs/Brick/Brick.truth new file mode 100644 index 0000000000000000000000000000000000000000..42be9261da801b210795cebcd82b7789e095c60a --- /dev/null +++ b/isis/src/base/objs/Brick/Brick.truth @@ -0,0 +1,20 @@ +Isis::Brick Unit Test + +SampleDimension: 4 +LineDimension: 3 +BandDimension: 2 +Size: 24 + +SampleDimension: 9 +LineDimension: 8 +BandDimension: 7 +Size: 504 + +Sample(): 3 +Line(): 2 +Band(): 1 + +Sample(): 5 +Line(): 6 +Band(): 7 + diff --git a/isis/src/base/objs/Brick/Makefile b/isis/src/base/objs/Brick/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..eaef8c617d1c730b468f5f0ba5e1b895951d7459 --- /dev/null +++ b/isis/src/base/objs/Brick/Makefile @@ -0,0 +1,5 @@ +INCS = Brick.h +SRCS = Brick.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Brick/unitTest.cpp b/isis/src/base/objs/Brick/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2afb55ce0aa1dee8e0412ba74e5c8a6add587614 --- /dev/null +++ b/isis/src/base/objs/Brick/unitTest.cpp @@ -0,0 +1,42 @@ + +#include +#include "Buffer.h" +#include "Brick.h" +#include "Preference.h" + +using namespace std; + +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + cout << "Isis::Brick Unit Test" << endl << endl; + + Isis::Brick b(4,3,2, Isis::SignedInteger); + + cout << "SampleDimension: " << b.SampleDimension() << endl; + cout << "LineDimension: " << b.LineDimension() << endl; + cout << "BandDimension: " << b.BandDimension() << endl; + cout << "Size: " << b.size() << endl << endl; + + b.Resize(9,8,7); + + cout << "SampleDimension: " << b.SampleDimension() << endl; + cout << "LineDimension: " << b.LineDimension() << endl; + cout << "BandDimension: " << b.BandDimension() << endl; + cout << "Size: " << b.size() << endl << endl; + + b.SetBasePosition (3,2,1); + cout << "Sample(): " << b.Sample() << endl; + cout << "Line(): " << b.Line() << endl; + cout << "Band(): " << b.Band() << endl << endl; + + b.SetBaseSample(5); + b.SetBaseLine(6); + b.SetBaseBand(7); + + cout << "Sample(): " << b.Sample() << endl; + cout << "Line(): " << b.Line() << endl; + cout << "Band(): " << b.Band() << endl << endl; + + return 0; +} diff --git a/isis/src/base/objs/Buffer/Buffer.cpp b/isis/src/base/objs/Buffer/Buffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e3760496f3ce848fdf958206bdd33dfc8eb686b --- /dev/null +++ b/isis/src/base/objs/Buffer/Buffer.cpp @@ -0,0 +1,331 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/06/26 01:05:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PixelType.h" +#include "Buffer.h" +#include "iException.h" +#include "Message.h" + +#include + +using namespace std; +namespace Isis { + + /** + * @brief Default constructor for proper initialization purposes + * + * This constructor is mostly useless but is needed so that it protects + * against improper usage. + */ + Buffer::Buffer() : p_sample(0), p_nsamps(0), p_line(0), p_nlines(0), + p_band(0), p_nbands(0), p_npixels(0), p_buf(0), + p_pixelType(None), p_rawbuf(0) { } + + /** + * Creates a Buffer object. Note that the number of pixels in the buffer + * can not exceed 2GB. + * + * @param nsamps Number of samples in shape. + * @param nlines Number of lines in shape. + * @param nbands Number of bands in shape. + * @param type Raw buffer pixel type + * + * @throws Isis::iException::Programmer - Invalid value for a dimension + */ + Buffer::Buffer(const int nsamps, const int nlines, + const int nbands, const Isis::PixelType type) : + p_nsamps(nsamps), p_nlines(nlines), + p_nbands(nbands), p_pixelType(type) { + + p_sample = p_line = p_band = 0; + + if(p_nsamps <= 0) { + string message = "Invalid value for sample dimensions (nsamps)"; + throw Isis::iException::Message(Isis::iException::Programmer, message, _FILEINFO_); + } + if(p_nlines <= 0) { + string message = "Invalid value for line dimensions (nlines)"; + throw Isis::iException::Message(Isis::iException::Programmer, message, _FILEINFO_); + } + if(p_nbands <= 0) { + string message = "Invalid value for band dimensions (nbands)"; + throw Isis::iException::Message(Isis::iException::Programmer, message, _FILEINFO_); + } + + p_npixels = p_nsamps * p_nlines * p_nbands; + + Allocate(); + } + + //! Destroys the Buffer object and frees shape buffer. + Buffer::~Buffer() { + try { + if(p_buf) { + delete [] p_buf; + } + if(p_rawbuf) { + delete [](char *) p_rawbuf; + } + } + catch(...) { + + } + } + + /** + * @brief Assign the entire buffer to a constant double value + * @param d Value to assign to the buffer + * + * @return the current Buffer + */ + Buffer & Buffer::operator=(const double &d) { + for(int i = 0 ; i < p_npixels ; i++) { + p_buf[i] = d; + } + return (*this); + } + + /** + * This method is used to set the base position of the shape buffer. In general + * it is used by BufferManager objects to progress sequentially through + * a cube by line, tile, boxcar, etc. + * + * @param start_sample Starting sample to set. + * @param start_line Starting line to set. + * @param start_band Starting band to set. + */ + void Buffer::SetBasePosition(const int start_sample, + const int start_line, + const int start_band) { + SetBaseSample(start_sample); + SetBaseLine(start_line); + SetBaseBand(start_band); + } + + /** + * Returns the sample position associated with a shape buffer index. The + * shape buffer is one dimensional. Let us assume a nsamps=2, nlines=3, + * and nbands=2. Therefore the total size of the shape buffer is 12 and valid + * index values are 0-11. Sample(0), Sample(2), Sample(4), etc will return a + * 1 while Sample(1), Sample(3), Sample(5), etc will return a 2. + * + * @param index Shape buffer index to map to a sample position. + * Defaults to 0. + * + * @return int The absolute sample number based on the buffer index. + */ + int Buffer::Sample(const int index) const { + return (index % p_nsamps) + p_sample; + } + + /** + * Returns the line position associated with a shape buffer index. The + * shape buffer is one dimensional. Let us assume a nsamps=2, nlines=3, and + * nbands=2. Therefore the total size of the shape buffer is 12 and valid + * index values are 0-11. Line(0), Line(1), Line(6) and Line(7), will return + * a 1, Line(2), Line(3), Line(8) and Line(9) will return a 2, and Line(4), + * Line(5), Line(10), and Line(11) will return a 3. + * + * @param index Shape buffer index to map to a line position. + * Defaults to 0 + * + * @return int The absolute line number based on the buffer index + */ + int Buffer::Line(const int index) const { + int sub_index = index % (p_nsamps * p_nlines); + return sub_index / p_nsamps + p_line; + } + + /** + * Returns the band position associated with a shape buffer index. The + * shape buffer is one dimensional. Let us assume a nsamps=2, nlines=3, and + * nbands=2. Therefore the total size of the shape buffer is 12 and valid + * index values are 0-11. Indexes 0-5 will return band 1 and 6-11 will return + * band 2. + * + * @param index Shape buffer index to map to a band position. Defaults to 0. + * + * @return int The absolute band number based on the buffer index. + */ + int Buffer::Band(const int index) const { + return index / (p_nsamps * p_nlines) + p_band; + } + + /** + * Returns the sample, line, and band position associated with a + * shape buffer index. Performs the same function as the Sample, Line, + * and Band methods. + * + * @param index Shape buffer index to map to a band position. + * @param i_samp Sample position in shape buffer at index. + * @param i_line Line position in shape buffer at index + * @param i_band Band position in shape buffer at index. + */ + void Buffer::Position(const int index, int &i_samp, int &i_line, + int &i_band) const { + i_samp = Sample(index); + i_line = Line(index); + i_band = Band(index); + } + + /** + * Given a sample, line, and band position, this returns the appropriate index + * in the shape buffer. + * + * @param i_samp Sample position. + * @param i_line Line position. + * @param i_band Band position. + * + * @return int Index at the specified sample, line and band. + * + * @throws Isis::iException::Programmer - Array Subscript not in range + */ + int Buffer::Index(const int i_samp, const int i_line, const int i_band) + const throw(Isis::iException &) { + + if((i_samp < p_sample) || (i_samp > (p_sample + p_nsamps - 1))) { + string message = Isis::Message::ArraySubscriptNotInRange(i_samp); + throw Isis::iException::Message(Isis::iException::Programmer, message, _FILEINFO_); + } + + if((i_line < p_line) || (i_line > (p_line + p_nlines - 1))) { + string message = Isis::Message::ArraySubscriptNotInRange(i_line); + throw Isis::iException::Message(Isis::iException::Programmer, message, _FILEINFO_); + } + + if((i_band < p_band) || (i_band > (p_band + p_nbands - 1))) { + string message = Isis::Message::ArraySubscriptNotInRange(i_band); + throw Isis::iException::Message(Isis::iException::Programmer, message, _FILEINFO_); + } + + // Got a valid reference location so compute the index and return + int index = (i_band - p_band) * (p_nlines * p_nsamps) + + (i_line - p_line) * (p_nsamps) + + (i_samp - p_sample); + return (index); + } + + /** + * Returns the value in the shape buffer at the given index. + * + * @param index Index position in buffer. Out of bounds index is trapped. + * + * @return double Buffer value at index + * + * @throws Isis::iException::Programmer - Array Subscript not in range + */ + double Buffer::at(const int index) const { + if(index < 0) { + string message = Isis::Message::ArraySubscriptNotInRange(index); + throw Isis::iException::Message(Isis::iException::Programmer, message, _FILEINFO_); + } + else if(index >= p_npixels) { + string message = Isis::Message::ArraySubscriptNotInRange(index); + throw Isis::iException::Message(Isis::iException::Programmer, message, _FILEINFO_); + } + + return p_buf[index]; + } + + /** + * Allows copying of the buffer contents to another Buffer + * + * @param in The Buffer to be copied. + * + * @throws Isis::iException::Programmer - Input and Output buffers are not the + * same size + */ + void Buffer::Copy(const Buffer &in) { + if(p_npixels != in.size()) { + string message = "Input and output buffers are not the same size"; + throw Isis::iException::Message(Isis::iException::Programmer, message, _FILEINFO_); + } + + if(p_pixelType != in.PixelType()) { + string message = "Input and output buffers are not the same pixel type"; + throw Isis::iException::Message(Isis::iException::Programmer, message, _FILEINFO_); + } + + size_t n = sizeof(double); + n = n * (size_t) p_npixels; + memcpy(p_buf, in.p_buf, n); + + n = Isis::SizeOf(p_pixelType); + n = n * (size_t) p_npixels; + memcpy(p_rawbuf, in.p_rawbuf, n); + } + + /** + * The copy constructor. Allows a new Buffer object to be created using + * an existing Buffer object. + * + * @param rhs The Buffer to be used to create the new buffer + */ + Buffer::Buffer(const Buffer &rhs) : + p_nsamps(rhs.p_nsamps), p_nlines(rhs.p_nlines), + p_nbands(rhs.p_nbands), p_pixelType(rhs.p_pixelType) { + + p_sample = rhs.p_sample; + p_line = rhs.p_line; + p_band = rhs.p_band; + + p_npixels = rhs.p_npixels; + + Allocate(); + Copy(rhs); + } + + /** + * Size or resize the memory buffer. + * + * @throws Isis::iException::System - Memory allocation failed + */ + void Buffer::Allocate() { + p_buf = NULL; + p_rawbuf = NULL; + try { + p_buf = new double [p_npixels]; + size_t n = Isis::SizeOf(p_pixelType); + n = n * (size_t) p_npixels; + p_rawbuf = new char[n]; + } + catch(...) { + try { + if(p_buf) { + delete [] p_buf; + p_buf = NULL; + } + if(p_rawbuf) { + delete [](char *)p_rawbuf; + p_rawbuf = NULL; + } + } + catch(...) { + p_buf = NULL; + p_rawbuf = NULL; + } + string message = Isis::Message::MemoryAllocationFailed(); + throw Isis::iException::Message(Isis::iException::System, message, _FILEINFO_); + } + } +} diff --git a/isis/src/base/objs/Buffer/Buffer.h b/isis/src/base/objs/Buffer/Buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..f3ccbb496b3a0de656b9d9f13d1eac30a8862ebb --- /dev/null +++ b/isis/src/base/objs/Buffer/Buffer.h @@ -0,0 +1,245 @@ +#ifndef Buffer_h +#define Buffer_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/06/22 17:47:56 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "iException.h" +#include "PixelType.h" + +namespace Isis { + /** + * @brief Buffer for reading and writing cube data + * + * This is the base class for I/O on buffers of data from cubes. The programmer + * can define an arbitrary shape using this object and then read or write that + * shape from a cube. Some example shapes are lines, tiles, columns, cublets, + * and spectral pencils. Data which is read or written to a cube will always be + * contained within an internal buffer of type double. There are methods for + * querying the sample/line/band position based upon the buffer index. Note + * that this class does not read/write data but is used in conjunction + * with the class to read/write data. Even more powerful are the BufferManager + * classes which inherit this object and can step through cubes by line, tile, + * boxcar, column, etc. + * + * If you would like to see Buffer being used in implementation, see circle.cpp + * + * @ingroup LowLevelCubeIO + * + * @author 2002-04-09 Kris Becker & Jeff Anderson + * + * @internal + * @history 2003-05-16 Stuart Sides - modified schema from + * astrogeology...isis.astrogeology + * @history 2005-01-16 Jeff Anderson - moved some private methods/variables + * into protected space + * @history 2007-09-05 Kris Becker - Added default constructor for added + * protection; Added assignment operator for a single value for + * convenience. + * @history 2008-06-25 Noah Hilt - Added some safety measures to the allocate + * and deconstructor methods to prevent accessing buffers that have + * not been initialized. Added memory checking to make sure to release + * any memory if initialized. + * @history 2010-06-22 Steven Lambright - "Copy" now ensures pixel types are + * the same to prevent going out of memory bounds + * @todo Consider making some of the position methods virtual (Line, Sample, + * Band etc.) to increase speed. This means the derived class, like Line, + * can make faster computations. + */ + class Buffer { + public: + Buffer(); + Buffer(const int nsamps, const int nlines, const int nbands, + const Isis::PixelType type); + + ~Buffer(); + + Buffer(const Buffer &); + + Buffer &operator=(const double &d); + + /** + * Returns the number of samples in the shape buffer + * + * @return int + */ + inline int SampleDimension() const { + return (p_nsamps); + } + + /** + * Returns the number of lines in the shape buffer + * + * @return int + */ + inline int LineDimension() const { + return (p_nlines); + } + + /** + * Returns the number of bands in the shape buffer + * + * @return int + */ + inline int BandDimension() const { + return (p_nbands); + } + + /** + * Returns the total number of pixels in the shape buffer + * + * @return int + */ + inline int size() const { + return (p_npixels); + } + + // Methods which return absolute coordinates relative to the buffer + int Sample(const int index = 0) const; + int Line(const int index = 0) const; + int Band(const int index = 0) const; + void Position(const int index, int &i_samp, int &i_line, int &i_band) const; + int Index(const int i_samp, const int i_line, const int i_band) const + throw(Isis::iException &); + + // Methods which give info about the buffer or its contents + double at(const int index) const; + + /** + * Returns the value in the shape buffer at given index. + * + * @param index Index position in buffer. No out of bounds index is checked + * + * @return double& + */ + inline double &operator[](const int index) { + return (p_buf[index]); + } + + /** + * Returns the value in the shape buffer at given index. + * + * @param index Index position in buffer. No out of bounds index is checked + * + * @return double + */ + const double &operator[](const int index) const { + return (p_buf[index]); + } + + /** + * Returns the value of the shape buffer + * + * @return double* The shape buffer + */ + inline double *DoubleBuffer() const { + return (p_buf); + }; + void Copy(const Buffer &in); + + /** + * Returns a void pointer to the raw buffer. Cast this void pointer using + * information from the PixelType() method + * + * @return void* Pointer to the raw buffer + */ + void *RawBuffer() const { + return p_rawbuf; + }; + + /** + * Returns the raw buffer pixel type + * + * @return Isis::PixelType + */ + Isis::PixelType PixelType() const { + return p_pixelType; + }; + + protected: + void SetBasePosition(const int start_sample, const int start_line, + const int start_band); + + /** + * This method is used to set the base sample position of the shape buffer. + * + * @param start_samp Starting sample to set + */ + inline void SetBaseSample(const int start_samp) { + p_sample = start_samp; + return; + } + + /** + * This method is used to set the base line position of the shape buffer. + * + * @param start_line Starting line to set + */ + inline void SetBaseLine(const int start_line) { + p_line = start_line; + return; + } + + /** + * This method is used to set the base band position of the shape buffer. + * + * @param start_band Starting band to set + */ + inline void SetBaseBand(const int start_band) { + p_band = start_band; + return; + } + + int p_sample; //!< Starting sample to read/write + int p_nsamps; //!< Number of samples to read/write + + int p_line; //!< Starting line to read/write + int p_nlines; //!< Number of lines to read/write + + int p_band; //!< Starting band to read/write + int p_nbands; //!< Number of bands to read/write + + int p_npixels; //!< Number of pixels (nsamps * nlines * nbands) + double *p_buf; /**< Shape buffer allocated to the size of npixels for + handling reads/writes*/ + + const Isis::PixelType p_pixelType; //!< The pixel type of the raw buffer + void *p_rawbuf; //!< The raw dm read from the disk + + void Allocate(); + + /** + * Copy operator. We will make it private since copies of these buffers + * do not need to occur. + * + * @param rvalue Right hand side + * + * @return Buffer& + */ + Buffer &operator=(const Buffer &rvalue) { + return const_cast(rvalue); + }; + + }; +}; + +#endif diff --git a/isis/src/base/objs/Buffer/Buffer.truth b/isis/src/base/objs/Buffer/Buffer.truth new file mode 100644 index 0000000000000000000000000000000000000000..fce7276b28e07d7303fc13ba4f13e6b747613a2d --- /dev/null +++ b/isis/src/base/objs/Buffer/Buffer.truth @@ -0,0 +1,53 @@ +Isis::Buffer Unit Test + +SampleDimension: 4 +LineDimension: 3 +BandDimension: 2 +Size: 24 + +Sample(): 0 +Line(): 0 +Band(): 0 +Position: 0 0 0 +Index: 0 + +at(0): 0 +at(10): 10 +at(23): 23 +b[0]: 0 +b[10]: 10 +b[23]: 23 + +Sample(): 3 +Line(): 2 +Band(): 1 +Position: 3 2 1 +Index: 0 + +Sample(16): 3 +Line(16): 3 +Band(16): 2 +Position: 3 3 2 +Index: 16 + +Copy constructor: Worked +SampleDimension: 4 +LineDimension: 3 +BandDimension: 2 +Size: 24 +a[0]: 0 +a[23]: 23 + +PixelType = SignedInteger + +Null Buffer size: 0 + +Test assignment operator for a constant... +d.size(): 8 +d[0]: 999 +d[2]: 999 +d[n]: 999 + +**PROGRAMMER ERROR** Array subscript [-1] is out of array bounds +**PROGRAMMER ERROR** Array subscript [24] is out of array bounds +**PROGRAMMER ERROR** Input and output buffers are not the same pixel type diff --git a/isis/src/base/objs/Buffer/Makefile b/isis/src/base/objs/Buffer/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bfcbd34c1542306a716278648eda4d5e689135fb --- /dev/null +++ b/isis/src/base/objs/Buffer/Makefile @@ -0,0 +1,5 @@ +INCS = Buffer.h +SRCS = Buffer.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Buffer/unitTest.cpp b/isis/src/base/objs/Buffer/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1b5e0c6787b85690d99a6d8a3e9992c505503d9 --- /dev/null +++ b/isis/src/base/objs/Buffer/unitTest.cpp @@ -0,0 +1,128 @@ +#include +#include "Buffer.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +class Test : public Buffer { + public: + Test(int s, int l, int b) : Isis::Buffer(s, l, b, Isis::SignedInteger) {}; + ~Test() {}; + void Report(); +}; + +void Test::Report() { + SetBasePosition(3, 2, 1); + cout << "Sample(): " << Sample() << endl; + cout << "Line(): " << Line() << endl; + cout << "Band(): " << Band() << endl; + + int samp, line, band; + Position(0, samp, line, band); + cout << "Position: " << samp << " " << line << " " << band + << endl; + cout << "Index: " << Index(samp, line, band) << endl << endl; + + cout << "Sample(16): " << Sample(16) << endl; + cout << "Line(16): " << Line(16) << endl; + cout << "Band(16): " << Band(16) << endl; + + Position(16, samp, line, band); + cout << "Position: " << samp << " " << line << " " << band + << endl; + cout << "Index: " << Index(samp, line, band) << endl << endl; +} + +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + cout << "Isis::Buffer Unit Test" << endl << endl; + + Test b(4, 3, 2); + for(int i = 0; i < b.size(); i++) { + b[i] = i; + } + + cout << "SampleDimension: " << b.SampleDimension() << endl; + cout << "LineDimension: " << b.LineDimension() << endl; + cout << "BandDimension: " << b.BandDimension() << endl; + cout << "Size: " << b.size() << endl << endl; + + cout << "Sample(): " << b.Sample() << endl; + cout << "Line(): " << b.Line() << endl; + cout << "Band(): " << b.Band() << endl; + + int samp, line, band; + b.Position(0, samp, line, band); + cout << "Position: " << samp << " " << line << " " << band + << endl; + cout << "Index: " << b.Index(samp, line, band) << endl << endl; + + cout << "at(0): " << b.at(0) << endl; + cout << "at(10): " << b.at(10) << endl; + cout << "at(23): " << b.at(23) << endl; + cout << "b[0]: " << b[0] << endl; + cout << "b[10]: " << b[10] << endl; + cout << "b[23]: " << b[23] << endl << endl; + + b.Report(); + + Test a = b; + if(a.DoubleBuffer() != b.DoubleBuffer()) { + cout << "Copy constructor: Worked" << endl; + } + else { + cout << "Copy constructor: Failed" << endl; + } + cout << "SampleDimension: " << a.SampleDimension() << endl; + cout << "LineDimension: " << a.LineDimension() << endl; + cout << "BandDimension: " << a.BandDimension() << endl; + cout << "Size: " << a.size() << endl ; + cout << "a[0]: " << a[0] << endl; + cout << "a[23]: " << a[23] << endl << endl; + + cout << "PixelType = " << Isis::PixelTypeName(a.PixelType()) << endl; + cout << endl; + + // Test new default constructor. Enclose in braces so destructor is tested + { + Buffer nullbuf; + cout << "Null Buffer size: " << nullbuf.size() << endl << endl; + } + + // Test assignment operator + cout << "Test assignment operator for a constant...\n"; + Buffer d(2, 2, 2, Double); + d = 999.0; + cout << "d.size(): " << d.size() << endl; + cout << "d[0]: " << d[0] << endl; + cout << "d[2]: " << d[2] << endl; + cout << "d[n]: " << d[d.size()-1] << endl << endl; + + try { + a.at(-1); + } + catch(Isis::iException &e) { + e.Report(false); + } + + try { + a.at(24); + } + catch(Isis::iException &e) { + e.Report(false); + } + + try { + Buffer a2(2, 2, 2, Isis::SignedWord); + Buffer b2(2, 2, 2, Isis::SignedByte); + + a2.Copy(b2); + } + catch(Isis::iException &e) { + e.Report(false); + } + + return 0; +} diff --git a/isis/src/base/objs/BufferManager/BufferManager.cpp b/isis/src/base/objs/BufferManager/BufferManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57752fa71f22a21b5890b07e5eb944130e34593f --- /dev/null +++ b/isis/src/base/objs/BufferManager/BufferManager.cpp @@ -0,0 +1,254 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/06/18 19:35:16 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include "BufferManager.h" + +using namespace std; +namespace Isis { +/** + * Constructs a BufferManager object. + * + * @param maxsamps Maximum samples to map + * + * @param maxlines Maximum lines to map + * + * @param maxbands Maximum bands to map + * + * @param bufsamps Number of samples in the shape buffer + * + * @param buflines Number of lines in the shape buffer + * + * @param bufbands Number of bands in the shape buffer + * + * @param type Type of pixel in raw buffer + * + * @param reverse Modifies the order of progression this + * buffer takes through the cube. By default, + * progresses samples first, then lines, then bands. + * If reverse = true, then the buffer progresses + * bands first, then lines, then samples. + */ + BufferManager::BufferManager(const int maxsamps,const int maxlines, + const int maxbands,const int bufsamps, + const int buflines, const int bufbands, + const Isis::PixelType type, const bool reverse) : + Isis::Buffer(bufsamps,buflines,bufbands,type), + p_maxSamps(maxsamps),p_maxLines(maxlines), + p_maxBands(maxbands) { + SetIncrements (bufsamps,buflines,bufbands); + p_reverse = reverse; + } + +/** + * Sets how the shape is incremented through the cube. By default (if this + * method is not invoked) shapes are moved sequentially through the cube with + * no overlap. For example, assume a 3 sample by 3 line tile buffer. It would + * first move across the image from left-to-right starting at sample 1, line 1, + * and band 1. Upon an increment it would be positioned at sample 4, line 1, + * and band 1. Each successive increment would cause the sample position to + * increase by 3 until it exceeds the number of samples in the cube. At that + * point the shape buffer would be positioned at sample 1, line 4, and band 1 + * (effectively moving to the next row of tiles). The shape would then continue + * moving across the cube until it reaches the edge again. Then the next row of + * tiles would be accessed until the shape reached the bottom of the cube. This + * default management can be overridden using this method. For example, by + * setting the increments to (6,3,1) we effectively skip every other tile. By + * setting them to (6,6,1) we skip every other tile and every other row of + * tiles. By setting them to (1,1,1) we essentially have NSxNLxNB positions + * in the cube and the 3x3 tile is managed such that the top left corner + * of the tile is moved over by 1 sample until it reaches the end of the + * line then down 1 line and so on until the end of the cube is reached. + * + * @param sinc Sample increment + * + * @param linc Line increment + * + * @param binc Band increment + */ + void BufferManager::SetIncrements(const int sinc, const int linc, + const int binc) { + p_sinc = sinc; + p_linc = linc; + p_binc = binc; + + p_soff = 0; + p_loff = 0; + p_boff = 0; + + p_currentSample = p_currentLine = p_currentBand = 1; + p_currentMap = 0; + + p_nmaps = ( (BigInt) ((p_maxSamps - 1) / p_sinc + 1) * + (BigInt) ((p_maxLines - 1) / p_linc + 1) * + (BigInt) ((p_maxBands - 1) / p_binc + 1) ); + } + +/** + * Sets the offset of the buffer. By default (if this method is not invoked) + * the offsets are (0,0,0). Offsets are applied when computing the top-left + * corner of the shape buffer. When used in conjunction with the SetIncrements + * method, this allows for centering shape buffers around a pixel when passing + * in negative offsets. For example,with a 3x3x1 shape and offsets of (-1,-1,0) + * and increments of (1,1,1) would cause the manager to walk a 3x3 buffer + * through the entire image. Setting the manager position the beginning causes + * the 3x3 window to be positioned such that sample 1, line 1 of the cube would + * be at the center of the window and increment would cause sample 2, line 1 to + * be at the center of the window. Successive increments will move the window in + * the sample direction until the end of line is reached at which time the + * buffer would be centered on sample 1, line 2. + * + * @param soff Sample offset + * + * @param loff Line offset + * + * @param boff Band offset + */ + void BufferManager::SetOffsets (const int soff, const int loff, + const int boff) { + p_soff = soff; + p_loff = loff; + p_boff = boff; + } + +/** + * Sets the position of the shape in the cube. This shape fits + * into the cube a specific number of times. + * + * When p_reverse is left false: (default) + * For example, a line shape on a 100 sample, 200 line, and 2 + * band cube would have 200*2 or 400 different positions as + * there are 400 total lines in the cube. Performing setpos(0) + * would position the shape at sample 1, line 1, and band 1. + * While setpos(200) would position the shape at sample 1, line + * 1, and band 2. Finally, setpos(399) would position the shape + * at sample 1, line 400, and band 2. Setpos returns true if it + * was sucessfully in setting the position, and false if the + * shape is at the end of the cube (beyond index 399 in the case + * of our example). + * + * When p_reverse is set to true: + * Following the above cube with 100 samples, 200 lines, and 2 bands, performing the + * setpos(0) would still position othe shape at sample 1, line + * 1, and band 1. However, setpos(1) would position the shape + * at sample 1, line 1, band 2, while setpos(200) would position + * the spame at sample 1, line 100, band 1. Setpos returns true + * of it was sucessfully in setting the position, and false if + * the shape is at the end of the cube(beyond final index). + * + * @param map Shape buffer position value + * + * @return bool True or False depending on whether the shape is at the end of + * the cube or not. + * + * @throws Isis::iException::Programmer - Invalid value for map argument + */ + bool BufferManager::setpos(const BigInt map) { + if (map < 0) { + string message = "Invalid value for argument [map]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + if ( p_reverse ) { + if (p_currentMap+1 == map) { + p_currentBand += p_binc; + if (p_currentBand > p_maxBands) { + p_currentBand = 1; + p_currentLine += p_linc; + if (p_currentLine > p_maxLines) { + p_currentLine = 1; + p_currentSample += p_sinc; + } + } + } else if (p_currentMap-1 == map) { + p_currentBand -= p_binc; + if (p_currentBand < 1) { + p_currentBand = ((p_maxBands - 1) / p_binc) * p_binc + 1; + p_currentBand -= p_binc; + if (p_currentLine < 1) { + p_currentLine = ((p_maxLines - 1) / p_linc) * p_linc + 1; + p_currentSample -= p_sinc; + } + } + } else { + p_currentSample = p_currentLine = p_currentBand = 1; + if (map < p_nmaps) { + for (int i=0; i p_maxBands) { + p_currentBand = 1; + p_currentLine += p_linc; + if (p_currentLine > p_maxLines) { + p_currentLine = 1; + p_currentSample += p_sinc; + } + } + } + } + } + } else { //p_reverse is false + if (p_currentMap+1 == map) { + p_currentSample += p_sinc; + if (p_currentSample > p_maxSamps) { + p_currentSample = 1; + p_currentLine += p_linc; + if (p_currentLine > p_maxLines) { + p_currentLine = 1; + p_currentBand += p_binc; + } + } + } else if (p_currentMap-1 == map) { + p_currentSample -= p_sinc; + if (p_currentSample < 1) { + p_currentSample = ((p_maxSamps - 1) / p_sinc) * p_sinc + 1; + p_currentLine -= p_linc; + if (p_currentLine < 1) { + p_currentLine = ((p_maxLines - 1) / p_linc) * p_linc + 1; + p_currentBand -= p_binc; + } + } + } else { + p_currentSample = p_currentLine = p_currentBand = 1; + if (map < p_nmaps) { + for (int i=0; i p_maxSamps) { + p_currentSample = 1; + p_currentLine += p_linc; + if (p_currentLine > p_maxLines) { + p_currentLine = 1; + p_currentBand += p_binc; + } + } + } + } + } + } + + SetBasePosition (p_currentSample + p_soff, + p_currentLine + p_loff, + p_currentBand + p_boff); + + p_currentMap = map; + + return !end(); + } +} // end namespace isis diff --git a/isis/src/base/objs/BufferManager/BufferManager.h b/isis/src/base/objs/BufferManager/BufferManager.h new file mode 100644 index 0000000000000000000000000000000000000000..828f83d59fa0d56d95440c3c3370622c361f38b4 --- /dev/null +++ b/isis/src/base/objs/BufferManager/BufferManager.h @@ -0,0 +1,177 @@ +#ifndef BufferManager_h +#define BufferManager_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/06/18 19:35:16 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Constants.h" +#include "PixelType.h" +#include "Buffer.h" + +namespace Isis { + /** + * @brief Manages a Buffer over a cube. + * + * This class is used to manage a Buffer over a cube. Recall a Buffer is + * simply a 3-d shape (or subset) of a cube. For example, a line, tile, or + * spectra are some possible shapes. A buffer manager will walk the shape + * over the entire cube to ensure every pixel is accessed. When constructing + * a BufferManager, arguments for the cube size and buffer size are required. + * For example, construction for a (100 sample, 200 line, 2 band) cube + * accessed by a line shape would require the shape buffer to have 100 + * samples, 1 line, and 1 band. The manager would then access the lines + * sequentially in the first band and then proceed to the second band. A 100 + * sample, 1 line, and 2 band shape buffer would access each line but both + * bands simultaneously. Typically, a BufferManager is not instantiated + * directly but is used in a derived class such a Line or Tile. + * + * If you would like to see BufferManager being used in implementation, + * see the LineManager, BoxcarManager, or TileManager class. + * + * @ingroup LowLevelCubeIO + * + * @author 2003-02-01 Jeff Anderson + * + * @internal + * @history 2003-05-16 Stuart Sides - modified schema from + * astrogeology...isis.astrogeology + * @history 2003-06-02 Jeff Anderson - Modified setpos method to allow for + * speedy reverse direction management. + * @history 2005-05-23 Jeff Anderson - Modified to support 2GB+ files + * @history 2007-12-04 Christopher Austin - Added option to + * constructor to change the order of the progression + * through the cube + * @history 2008-06-18 Christopher Austin - Fixed documenation errors + * + * @todo Jeff Anderson - add coded and implementation example to class doc. + */ +class BufferManager : public Isis::Buffer { + + private: + const int p_maxSamps; //!< Maximum samples to map + const int p_maxLines; //!< Maximum lines to map + const int p_maxBands; //!< Maximum bands to map + + int p_sinc; //!< Sample increment + int p_linc; //!< Line increment + int p_binc; //!< Band increment + + int p_soff; //!< Sample offset + int p_loff; //!< Line offset + int p_boff; //!< Band offset + + int p_currentSample; //!< Current sample + int p_currentLine; //!< Current line + int p_currentBand; //!< Current band + + BigInt p_nmaps; //!< Total number of objects to map + BigInt p_currentMap; //!< Current buffer map position + + /** + * If true the axies are processed in Band, Line, Sample order + * (e.g., BIL). If left false, the axies are processed in the + * Sample, Line, Band order (e.g., BSQ, BIP). + */ + bool p_reverse; + + public: + // Constructors and Destructors + BufferManager(const int maxsamps, const int maxlines, const int maxbands, + const int bufsamps, const int buflines, const int bufbands, + const Isis::PixelType type, const bool reverse=false); + + //! Destroys the BufferManager object + ~BufferManager() {}; + + // Traversal Methods + + /** + * Moves the shape buffer to the next position. Returns true if the next + * position is valid. + * + * @return bool + */ + inline bool operator++(int) { return (next()); } + + /** + * Moves the shape buffer to the first position + * + * @return bool + */ + inline bool begin() { return (setpos(0)); } + + /** + * Moves the shape buffer to the next position. Returns true if the next + * position is valid. + * + * @return bool + */ + inline bool next() { return (setpos(p_currentMap+1)); } + + /** + * Returns true if the shape buffer has accessed the end of the cube. + * + * @return bool + */ + inline bool end() const { return (p_currentMap >= p_nmaps); } + + protected: + bool setpos(const BigInt map); + + // Methods visable to deriving classes + + /** + * Returns the number of samples in the cube + * + * @return int + */ + inline int MaxSamples() const { return (p_maxSamps); } + + /** + * Returns the number of lines in the cube + * + * @return int + */ + inline int MaxLines() const { return (p_maxLines); } + + /** + * Returns the number of bands in the cube + * + * @return int + */ + inline int MaxBands() const { return (p_maxBands); } + + /** + * Returns the maximum number of positions the shape buffer needs to cover + * the entire image (see setpos method for more info). + * + * @return int + */ + inline BigInt MaxMaps() const { return (p_nmaps); } + + void SetIncrements(const int sinc, const int linc, const int binc); + void SetOffsets(const int soff, const int loff, const int boff); + }; +}; + +#endif + diff --git a/isis/src/base/objs/BufferManager/BufferManager.truth b/isis/src/base/objs/BufferManager/BufferManager.truth new file mode 100644 index 0000000000000000000000000000000000000000..3841389e6d25da64a8c605fac141f803ea0e7f74 --- /dev/null +++ b/isis/src/base/objs/BufferManager/BufferManager.truth @@ -0,0 +1,36 @@ +Isis::BufferManager Unit Test + +Position: 1 1 1 +Position: 4 1 1 +Position: 1 3 1 +Position: 4 3 1 +Position: 1 1 2 +Position: 4 1 2 +Position: 1 3 2 +Position: 4 3 2 + +Position: 1 1 1 +Position: 2 1 1 +Position: 3 1 1 +Position: 4 1 1 +Position: 1 2 1 +Position: 2 2 1 +Position: 3 2 1 +Position: 4 2 1 +Position: 1 3 1 +Position: 2 3 1 +Position: 3 3 1 +Position: 4 3 1 +Position: 1 1 2 +Position: 2 1 2 +Position: 3 1 2 +Position: 4 1 2 +Position: 1 2 2 +Position: 2 2 2 +Position: 3 2 2 +Position: 4 2 2 +Position: 1 3 2 +Position: 2 3 2 +Position: 3 3 2 +Position: 4 3 2 + diff --git a/isis/src/base/objs/BufferManager/Makefile b/isis/src/base/objs/BufferManager/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cb7730bc47ccf9aa341f5a543ebc459f641bce39 --- /dev/null +++ b/isis/src/base/objs/BufferManager/Makefile @@ -0,0 +1,5 @@ +INCS = BufferManager.h +SRCS = BufferManager.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/BufferManager/unitTest.cpp b/isis/src/base/objs/BufferManager/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0fce0cc2ca1c6a7b59593cd73f5e0f5a8ea2103e --- /dev/null +++ b/isis/src/base/objs/BufferManager/unitTest.cpp @@ -0,0 +1,32 @@ +#include +#include "BufferManager.h" +#include "Preference.h" + +using namespace std; + +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + cout << "Isis::BufferManager Unit Test" << endl << endl; + + Isis::BufferManager bm(6,4,2,3,2,1,Isis::Real); + + for (bm.begin(); !bm.end(); bm++) { + cout << "Position: " << bm.Sample() << " " + << bm.Line() << " " + << bm.Band() << endl; + } + cout << endl; + + Isis::BufferManager bm2(4,3,2,1,1,1,Isis::Real); + + bm2.begin(); + do { + cout << "Position: " << bm2.Sample() << " " + << bm2.Line() << " " + << bm2.Band() << endl; + } while (bm2.next()); + cout << endl; + + return 0; +} diff --git a/isis/src/base/objs/BundleAdjust/BundleAdjust.cpp b/isis/src/base/objs/BundleAdjust/BundleAdjust.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6e20e30b1a1368681bc9c1f28d82838aeae3c8c --- /dev/null +++ b/isis/src/base/objs/BundleAdjust/BundleAdjust.cpp @@ -0,0 +1,920 @@ +#include "BundleAdjust.h" + +#include + +#include "SpecialPixel.h" +#include "BasisFunction.h" +#include "LeastSquares.h" +#include "CameraGroundMap.h" +#include "CameraDetectorMap.h" +#include "CameraDistortionMap.h" +#include "ControlPoint.h" +#include "SpicePosition.h" +#include "Application.h" + +namespace Isis { + BundleAdjust::BundleAdjust(const std::string &cnetFile, + const std::string &cubeList, + bool printSummary) { + // Get control net and serial number list + p_cleanUp = true; + Progress progress; + p_cnet = new Isis::ControlNet(cnetFile, &progress); + p_snlist = new Isis::SerialNumberList(cubeList); + p_printSummary = printSummary; + p_heldsnlist = NULL; + p_observationMode = false; + p_solutionMethod = "SVD"; + p_onlist = NULL; + + Init( &progress ); + } + + BundleAdjust::BundleAdjust(const std::string &cnetFile, + const std::string &cubeList, + const std::string &heldList, + bool printSummary) { + // Get control net, serial number list, and held serial number list + p_cleanUp = true; + Progress progress; + p_cnet = new Isis::ControlNet(cnetFile, &progress); + p_snlist = new Isis::SerialNumberList(cubeList); + p_heldsnlist = new Isis::SerialNumberList(heldList); + p_printSummary = printSummary; + p_observationMode = false; + p_solutionMethod = "SVD"; + p_onlist = NULL; + + Init( &progress ); + } + + BundleAdjust::BundleAdjust(Isis::ControlNet &cnet, + Isis::SerialNumberList &snlist, + bool printSummary) { + // Get control net and serial number list + p_cleanUp = false; + p_cnet = &cnet; + p_snlist = &snlist; + p_printSummary = printSummary; + p_heldsnlist = NULL; + p_observationMode = false; + p_solutionMethod = "SVD"; + p_onlist = NULL; + + Init(); + } + + BundleAdjust::BundleAdjust(Isis::ControlNet &cnet, + Isis::SerialNumberList &snlist, + Isis::SerialNumberList &heldsnlist, + bool printSummary) { + // Get control net, image serial number list and hold image serial number list + p_cleanUp = false; + p_cnet = &cnet; + p_snlist = &snlist; + p_heldsnlist = &heldsnlist; + p_printSummary = printSummary; + p_observationMode = false; + p_solutionMethod = "SVD"; + p_onlist = NULL; + + Init(); + } + + BundleAdjust::~BundleAdjust() { + if (p_cleanUp) { + delete p_cnet; + delete p_snlist; + if (p_heldImages > 0) delete p_heldsnlist; + if (p_observationMode) delete p_onlist; + } + } + + + void BundleAdjust::Init(Progress *progress) { + // Get the cameras set up for all images + p_cnet->SetImages(*p_snlist, progress); + + p_heldImages = 0; + int count; + + if (p_heldsnlist != NULL) { + //Check to make sure held images are in the control net + CheckHeldList(); + // Set all points on held images to held, using measurement on held image + // to get lat/lon/radius of point + ApplyHeldList(); + + // Create a lookup table of held images + count = 0; + for (int i=0; iSize(); i++) { + if (p_heldsnlist->HasSerialNumber(p_snlist->SerialNumber(i))) { + p_imageIndexMap.push_back(-1); + p_heldImages++; + } else { + p_imageIndexMap.push_back(count); + count++; + } + } + } + else { + for (int i=0; iSize(); i++) p_imageIndexMap.push_back(i); + } + + + // Create a lookup table of ignored, held, and ground points + p_heldPoints = p_groundPoints = p_ignoredPoints = 0; + count = 0; + for (int i=0; iSize(); i++) { + if ((*p_cnet)[i].Held()) { + p_pointIndexMap.push_back(-1); + p_heldPoints++; + } + else if ((*p_cnet)[i].Ignore()) { + p_pointIndexMap.push_back(-1); + p_ignoredPoints++; + } + else if ((*p_cnet)[i].Type() == ControlPoint::Ground) { + p_pointIndexMap.push_back(-1); + p_groundPoints++; + } + else { + p_pointIndexMap.push_back(count); + count++; + } + } + + // Set default variables to solve for + p_solveTwist = true; + p_solveRadii = false; + p_cmatrixSolveType = AnglesOnly; + p_spacecraftPositionSolveType = Nothing; + p_ckDegree = 2; + p_solveCamDegree = p_ckDegree; + p_numberCameraCoefSolved = 1; + + ComputeNumberPartials(); + + // TODO: Need to have some validation code to make sure everything is + // on the up-and-up with the control network. Add checks for multiple + // networks, images without any points, and points on images removed from + // the control net (when we start adding software to remove points with high + // residuals) and ?. + } + + /** + * This method finds all the measurements on held images and holds the control + * point they are on. The lat/lon/radius are determined by mapping the line/sample + * measurement on the held image to the surface. + */ + void BundleAdjust::CheckHeldList () { + for (int ih=0; ih < p_heldsnlist->Size(); ih++) { + if (!(p_snlist->HasSerialNumber(p_heldsnlist->SerialNumber(ih)))) { + std::string msg = "Held image [" + p_heldsnlist->SerialNumber(ih) + + "not in FROMLIST"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + } + + + /** + * This method finds all the measurements on held images, finds their + * lat/lon/radius(m), sets the control point they are on to that lat/lon/radius, + * and makes the control point a held point. + */ + void BundleAdjust::ApplyHeldList () { + double lat,lon,rad; + // TODO Check for points already held ie) case where user has a point on 2 + // or more held images + + for (int i=0; iSize(); i++) { + ControlPoint &pt = (*p_cnet)[i]; + if (pt.Ignore()) continue; + + for (int j=0; jHasSerialNumber(m.CubeSerialNumber())) { + Camera *cam=m.Camera(); + if (cam->SetImage(m.Sample(), m.Line())) { + lat = cam->UniversalLatitude(); + lon = cam->UniversalLongitude(); + rad = cam->LocalRadius(); //meters + } + else { + std::string msg = "Cannot compute lat/lon for control point [" + + pt.Id() + "], measure [" + m.CubeSerialNumber() + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + pt.SetUniversalGround (lat, lon, rad); + pt.SetHeld (true); + } + } + } + } + + /** + * This method determines the number of partials per image and + * per point. It is based on the variables to be solved for + * (e.g., twist, radii, cmatrix velocity, cmatrix acceleration, + * etc) + */ + void BundleAdjust::ComputeNumberPartials() { + p_numImagePartials = 0; + + if (p_cmatrixSolveType != None) { + // Solve for ra/dec always + p_numImagePartials = 2; + + // Do we solve for twist + if (p_solveTwist) { + p_numImagePartials++; + } + + // Do we solve for angles only, +velocity, or +velocity and acceleration, or all coefficients + p_numImagePartials *= p_numberCameraCoefSolved; +/* if (p_cmatrixSolveType == AnglesVelocity) { + p_numImagePartials *= 2; + } + else if (p_cmatrixSolveType == AnglesVelocityAcceleration) { + p_numImagePartials *= 3; + }*/ + } + + if (p_spacecraftPositionSolveType != Nothing) { + // Solve for position always. + p_numImagePartials += 3; + + // Do we solve for position and velocity, position, velocity and acceleration, or position only + if (p_spacecraftPositionSolveType == PositionVelocity) { + p_numImagePartials += 3; + } + else if (p_spacecraftPositionSolveType == PositionVelocityAcceleration) { + p_numImagePartials += 6; + } + } + + // Solve for lat/lon always + p_numPointPartials = 2; + + // Do we solve for radii + if (p_solveRadii) { + p_numPointPartials++; + } + } + + /** + * This method turns on observation mode and creates the observation number list. + * It also checks to make sure the held image list is consistent for all images in + * an observation + */ + void BundleAdjust::SetObservationMode ( bool observationMode ) { + p_observationMode = observationMode; + + if (p_observationMode) { + // Create the observation number list + p_onlist = new Isis::ObservationNumberList(p_snlist); + if (p_heldImages != 0) { + p_onlist->Remove(p_heldsnlist); + } + + if (p_heldsnlist != NULL) { + //Make sure ALL images in an observation are held if any are + for (int ih=0; ih < p_heldsnlist->Size(); ih++) { + for (int isn=0; isn < p_snlist->Size(); isn++) { + if (p_heldsnlist->ObservationNumber(ih) == p_snlist->ObservationNumber(isn)) { + if (!(p_heldsnlist->HasSerialNumber(p_snlist->SerialNumber(isn)))) { + std::string msg = "Cube file " + p_snlist->Filename(isn) + + " must be held since it is on the same observation as held cube " + + p_heldsnlist->Filename(ih); + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + } + } + } + } + } + + + + + /** + * Should we solve for the twist in each image? + */ + void BundleAdjust::SetSolveTwist(bool solve) { + p_solveTwist = solve; + ComputeNumberPartials(); + } + + /** + * Should we solve for the radii at each point? + */ + void BundleAdjust::SetSolveRadii(bool solve) { + p_solveRadii = solve; + ComputeNumberPartials(); + } + + /** + * For which camera angle coefficients do we solve? + */ + void BundleAdjust::SetSolveCmatrix(CmatrixSolveType type) { + p_cmatrixSolveType = type; + + switch (type) { + case BundleAdjust::AnglesOnly: + p_numberCameraCoefSolved = 1; + break; + case BundleAdjust::AnglesVelocity: + p_numberCameraCoefSolved = 2; + break; + case BundleAdjust::AnglesVelocityAcceleration: + p_numberCameraCoefSolved = 3; + break; + case BundleAdjust::All: + p_numberCameraCoefSolved = p_solveCamDegree+1; + break; + default: + p_numberCameraCoefSolved = 0; + break; + } + + // Make sure the degree of the polynomial the user selected for + // the camera angles fit is sufficient for the selected CAMSOLVE + if (p_numberCameraCoefSolved > p_solveCamDegree+1 ) { + std::string msg = "Selected SolveCameraDegree " + iString(p_solveCamDegree) + + " is not sufficient for the CAMSOLVE"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + ComputeNumberPartials(); + } + + /** + * Should we solve for the spacecraft position, velocity, and acceleration + */ + void BundleAdjust::SetSolveSpacecraftPosition(SpacecraftPositionSolveType type) { + p_spacecraftPositionSolveType = type; + ComputeNumberPartials(); + } + + /** + * Determine the number of columns we will need for the least + * squares. When we create a row of data we will store all the + * image partials first and then the point partials + */ + int BundleAdjust::BasisColumns() const { + int imageColumns = Observations() * p_numImagePartials; + +// imageColumns -= p_heldImages * p_numImagePartials; + + int pointColumns = p_cnet->Size() * p_numPointPartials; + + pointColumns -= p_groundPoints * p_numPointPartials; + pointColumns -= p_heldPoints * p_numPointPartials; + pointColumns -= p_ignoredPoints * p_numPointPartials; + + return imageColumns + pointColumns; + } + + /** + * The solve method is an least squares solution for updating the camera + * pointing. It is iterative as the equations are non-linear. If it does + * not iterate to a solution in maxIterations it will throw an error. During + * each iteration it is updating portions of the control net, as well as the + * instrument pointing in the camera. An error is thrown if it does not + * converge in the maximum iterations. However, even if an error is thrown + * the control network will contain the errors at each control measure. + * + * @param tol Maximum pixel error for any control network + * measurement + * @param maxIterations Maximum iterations, if tolerance is never + * met an iException will be thrown. + */ + double BundleAdjust::Solve(double tol, int maxIterations) { + double mmPerPixel = DBL_MAX; + double averageError; + std::vector observationInitialValueIndex; // Index of image to use for observation inital values + int iIndex = -1; //Index of the image to use for initial spice for an observation + int oIndex = -1; // Index of current observation + + if (p_observationMode) { + observationInitialValueIndex.assign( p_onlist->ObservationSize(), -1); + } + + for (int i=0; i 0) { + if ((p_heldsnlist->HasSerialNumber(p_snlist->SerialNumber(i)))) continue; + } + Camera *cam = p_cnet->Camera(i); + + if (p_observationMode) { + oIndex = i; + oIndex = p_onlist->ObservationNumberMapIndex(oIndex); // Get the observation index for this image + iIndex = observationInitialValueIndex[oIndex]; // Get the index of the image to use for initial values + // being used for the observation + } + if (p_cmatrixSolveType != None) { + // For observations, find the index of the first image and use its polynomial for the observation + // initial coefficient values. Initialize indeces to -1 + + // Fit the camera pointing to an equation + SpiceRotation *rot = cam->InstrumentRotation(); + + if (!p_observationMode ) { + rot->SetPolynomialDegree( p_ckDegree ); // Set the ck polynomial fit degree + rot->SetPolynomial(); + rot->SetPolynomialDegree( p_solveCamDegree ); // Update to the solve polynomial fit degree + } + else { + // Index of image to use for initial values is set already so set polynomial to initial values + if (iIndex >= 0) { + SpiceRotation *orot = p_cnet->Camera(iIndex)->InstrumentRotation(); //Observation rotation + std::vector anglePoly1, anglePoly2, anglePoly3; + orot->GetPolynomial( anglePoly1, anglePoly2, anglePoly3); + double baseTime = orot->GetBaseTime(); + double timeScale = orot->GetTimeScale(); + rot->SetPolynomialDegree( p_solveCamDegree ); // Update to the solve polynomial fit degree + rot->SetOverrideBaseTime( baseTime, timeScale ); + rot->SetPolynomial( anglePoly1, anglePoly2, anglePoly3); + } + else { + // Index of image to use for inital observation values has not been assigned yet so use this image + rot->SetPolynomialDegree( p_ckDegree ); + rot->SetPolynomial(); + rot->SetPolynomialDegree( p_solveCamDegree ); // Update to the solve polynomial fit degree + observationInitialValueIndex[oIndex] = i; + } + } + } + if (p_spacecraftPositionSolveType != Nothing) { + // Set the spacecraft position to an equation + SpicePosition *pos = cam->InstrumentPosition(); + + if (!p_observationMode ) { + pos->SetPolynomial(); + } + else { + // Index of image to use for initial values is set already so set polynomial to initial values + if (iIndex >= 0) { + SpicePosition *opos = p_cnet->Camera(iIndex)->InstrumentPosition(); //Observation position + std::vector posPoly1, posPoly2, posPoly3; + opos->GetPolynomial( posPoly1, posPoly2, posPoly3); + double baseTime = opos->GetBaseTime(); + pos->SetOverrideBaseTime( baseTime ); + pos->SetPolynomial( posPoly1, posPoly2, posPoly3); + } + else { + // Index of image to use for inital observation values has not been assigned yet so use this image + pos->SetPolynomial(); + observationInitialValueIndex[oIndex] = i; + } + } + } + if (cam->PixelPitch() < mmPerPixel) { + mmPerPixel = cam->PixelPitch(); + } + } + + // Compute the apriori lat/lons for each nonheld point + p_error = DBL_MAX; + p_cnet->ComputeApriori(); + + // Initialize solution parameters + double sigmaXY, sigmaHat, sigmaX, sigmaY; + sigmaXY = sigmaHat = sigmaX = sigmaY = 0.; + p_iteration = 0; + + while (p_iteration < maxIterations) { + p_iteration++; + p_cnet->ComputeErrors(); + p_error = p_cnet->MaximumError(); + averageError = p_cnet->AverageError(); + if (p_printSummary) { + IterationSummary(averageError,sigmaXY,sigmaHat,sigmaX,sigmaY); + } + p_statx.Reset(); + p_staty.Reset(); + + if (p_error <= tol) return p_error; + + // Create the basis function and prep for a least squares solution + BasisFunction basis("Bundle",BasisColumns(),BasisColumns()); + LeastSquares *lsq; + if (p_solutionMethod == "SPARSE") { + lsq = new LeastSquares(basis,Isis::LeastSquares::SPARSE, + p_cnet->NumValidMeasures()*2,BasisColumns()); + } + else { + lsq = new LeastSquares(basis); + } + + // Loop through the control net and add the partials for each point + for (int i=0; iSize(); i++) { + AddPartials(*lsq,i); + } + // Try to solve the iteration + try { + if (p_solutionMethod == "SVD") { + lsq->Solve(Isis::LeastSquares::SVD); + + } else if (p_solutionMethod == "QRD") { + lsq->Solve(Isis::LeastSquares::QRD); + } + else { + int zeroColumn = lsq->Solve(Isis::LeastSquares::SPARSE); + if (zeroColumn != 0) { + std::string msg; + int imageColumns = Observations() * p_numImagePartials; + if (zeroColumn <= imageColumns) { + msg = "Solution matrix has a column of zeros which probably "; + msg += "indicates an image with no points. Running the program, "; + msg += "cnetcheck, before jigsaw should catch these problems."; + } + else { + msg = "Solution matrix has a column of zeros which probably "; + msg += "indicates a point with no measures. Running the program, "; + msg += "cnetcheck, before jigsaw should catch these problems."; + } + throw Isis::iException::Message(iException::Math,msg,_FILEINFO_); + } + } + } + catch (iException &e) { + std::string msg = "Unable to solve in BundleAdjust, "; + msg += "Iteration " + Isis::iString(p_iteration) + " of "; + msg += Isis::iString(maxIterations) + ", Tolerance = "; + msg += Isis::iString(tol); + throw Isis::iException::Message(iException::Math,msg,_FILEINFO_); + } + + // Ok take the results and put them back into the camera blobs + Update(basis); + // return p_error; + + //Compute sigmas + sigmaXY = sqrt((p_statx.SumSquare() + p_staty.SumSquare())/lsq->Knowns()); + sigmaHat = (lsq->Knowns() - BasisColumns()) ? + (sqrt((p_statx.SumSquare() + p_staty.SumSquare())/ (lsq->Knowns() - BasisColumns()))) + : 0.; + sigmaX = p_statx.TotalPixels() ? + sqrt(p_statx.SumSquare()/p_statx.TotalPixels()) : 0.; + sigmaY = p_staty.TotalPixels() ? + sqrt(p_staty.SumSquare()/p_staty.TotalPixels()) : 0.; + } + + std::string msg = "Did not converge to tolerance ["; + msg += iString(tol) + "] in less than ["; + msg += iString(maxIterations) + "] iterations"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + /** + * Populate the least squares matrix with measures for a point + */ + void BundleAdjust::AddPartials (LeastSquares &lsq, + int pointIndex) { + ControlPoint &point = (*p_cnet)[pointIndex]; + if (point.Ignore()) return; // Ignore entire point + double cudx, cudy; + + for (int i=0; iHasSerialNumber(point[i].CubeSerialNumber())) continue; + } + + Camera *cam = point[i].Camera(); + // Get focal length with direction + // Map the control point lat/lon/radius into the camera through the Spice + // at the measured point to correctly compute the partials for line scan + // cameras. The camera SetUniversalGround method computes a time based + // on the lat/lon/radius and uses the Spice for that time instead of the + // measured point's time. + cam->SetImage(point[i].Sample(),point[i].Line()); // Set the Spice to the measured point + + // Compute the look vector in instrument coordinates based on time of observation and apriori lat/lon/radius + if (!(cam->GroundMap()->GetXY( point.UniversalLatitude(), point.UniversalLongitude(), + point.Radius(), &cudx, &cudy))) { + std::string msg = "Unable to map apriori surface point for measure "; + msg += iString(i) + " on point " + point.Id() + " into focal plane"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Create the known array to put in the least squares + std::vector xKnowns(BasisColumns(),0.0); + std::vector yKnowns(BasisColumns(),0.0); + + // Determine the image index for nonheld images + bool useImage=false; + + if ( p_heldImages == 0) { + useImage = true; + } + else if (p_heldImages > 0) { + if ((!(p_heldsnlist->HasSerialNumber(point[i].CubeSerialNumber())))) + useImage = true; + } + if (useImage) { + int index = p_snlist->SerialNumberIndex(point[i].CubeSerialNumber()); + index = ImageIndex(index); + + if (p_spacecraftPositionSolveType != Nothing) { + // Add the partial for the x coordinate of the position (differentiating + // point(x,y,z) - spacecraftPosition(x,y,z) in J2000 + for (int icoef=0; icoefGroundMap()->GetdXYdPosition(SpicePosition::WRT_X, icoef, &xKnowns[index], &yKnowns[index]); + index++; + } + + // Add the partial for the y coordinate of the position + for (int icoef=0; icoefGroundMap()->GetdXYdPosition(SpicePosition::WRT_Y, icoef, &xKnowns[index], &yKnowns[index]); + index++; + } + + // Add the partial for the z coordinate of the position + for (int icoef=0; icoefGroundMap()->GetdXYdPosition(SpicePosition::WRT_Z, icoef, &xKnowns[index], &yKnowns[index]); + index++; + } + } + if (p_cmatrixSolveType != None) { + std::vector d_lookC; + + // Add the partials for ra + for (int icoef=0; icoefGroundMap()->GetdXYdOrientation(SpiceRotation::WRT_RightAscension, icoef, &xKnowns[index], &yKnowns[index]); + index++; + } + + // Add the partials for dec + for (int icoef=0; icoefGroundMap()->GetdXYdOrientation(SpiceRotation::WRT_Declination, icoef, &xKnowns[index], &yKnowns[index]); + index++; + } + + // Add the partial for twist if necessary + if (p_solveTwist) { + for (int icoef=0; icoefGroundMap()->GetdXYdOrientation(SpiceRotation::WRT_Twist, icoef, &xKnowns[index], &yKnowns[index]); + index++; + } + } + } + } + if ((!point.Held()) && (point.Type() != ControlPoint::Ground)) { + int index = PointIndex(pointIndex); + cam->GroundMap()->GetdXYdPoint(point.UniversalLatitude(), point.UniversalLongitude(), point.Radius(), + CameraGroundMap::WRT_Latitude, &xKnowns[index], &yKnowns[index]); + index++; + cam->GroundMap()->GetdXYdPoint(point.UniversalLatitude(), point.UniversalLongitude(), point.Radius(), CameraGroundMap::WRT_Longitude, &xKnowns[index], &yKnowns[index]); + index++; + if (p_solveRadii) { + cam->GroundMap()->GetdXYdPoint(point.UniversalLatitude(), point.UniversalLongitude(), point.Radius(), + CameraGroundMap::WRT_Radius, &xKnowns[index], &yKnowns[index]); + index++; + } + } + + double mudx = point[i].FocalPlaneMeasuredX(); + double mudy = point[i].FocalPlaneMeasuredY(); + + double deltax = mudx - cudx; + double deltay = mudy - cudy; + +// std::cout<<"mudx mudy="< 0) { + if ((p_heldsnlist->HasSerialNumber(p_snlist->SerialNumber(i)))) continue; + } + + Camera *cam = p_cnet->Camera(i); + int index = i; + index = ImageIndex(index); + +// std::cout<SerialNumber(i) << " " << +// basis.Coefficient(index)<<","<InstrumentPosition(); + std::vector abcX(3),abcY(3),abcZ(3); + pos->GetPolynomial(abcX,abcY,abcZ); + + // Update the X coordinate coefficient(s) + abcX[0] += basis.Coefficient(index); index++; + if (p_spacecraftPositionSolveType > PositionOnly) { + abcX[1] += basis.Coefficient(index); index++; + if (p_spacecraftPositionSolveType == PositionVelocityAcceleration) { + abcX[2] += basis.Coefficient(index); index++; + } + } + + // Update the Y coordinate coefficient(s) + abcY[0] += basis.Coefficient(index); index++; + if (p_spacecraftPositionSolveType > PositionOnly) { + abcY[1] += basis.Coefficient(index); index++; + if (p_spacecraftPositionSolveType == PositionVelocityAcceleration) { + abcY[2] += basis.Coefficient(index); index++; + } + } + + // Update the Z coordinate coefficient(s) + abcZ[0] += basis.Coefficient(index); index++; + if (p_spacecraftPositionSolveType > PositionOnly) { + abcZ[1] += basis.Coefficient(index); index++; + if (p_spacecraftPositionSolveType == PositionVelocityAcceleration) { + abcZ[2] += basis.Coefficient(index); index++; + } + } + pos->SetPolynomial(abcX,abcY,abcZ); + } + + if (p_cmatrixSolveType != None) { + SpiceRotation *rot = cam->InstrumentRotation(); + std::vector coefRA(p_numberCameraCoefSolved), + coefDEC(p_numberCameraCoefSolved), + coefTWI(p_numberCameraCoefSolved); + rot->GetPolynomial(coefRA,coefDEC,coefTWI); + + // Update right ascension coefficient(s) + for (int icoef=0; icoefSetPolynomial(coefRA,coefDEC,coefTWI); + } + } + + // Update lat/lon for each control point + for (int i=0; iSize(); i++) { + if ((*p_cnet)[i].Held()) continue; + if ((*p_cnet)[i].Ignore()) continue; + if ((*p_cnet)[i].Type() == ControlPoint::Ground) continue; + + double lat = (*p_cnet)[i].UniversalLatitude(); + double lon = (*p_cnet)[i].UniversalLongitude(); + double rad = (*p_cnet)[i].Radius(); + int index = PointIndex(i); + +// std::cout<<"For point "< 90.) { + lat = 180. - lat; + lon = lon + 180.; + } + while (lon > 360.) lon = lon - 360.; + while (lon < 0) lon = lon + 360.; + + if (p_solveRadii) { + rad += 1000.*basis.Coefficient(index); index++; + } +/* else { // Recompute radius to match updated lat/lon... Should this be removed? + ControlMeasure &m = ((*p_cnet)[i])[0]; + Camera *cam = m.Camera(); + cam->SetUniversalGround(lat, lon); + rad = cam->LocalRadius(); //meters + }*/ + (*p_cnet)[i].SetUniversalGround(lat,lon,rad); + } + } + + //! Return index to basis function for ith point + int BundleAdjust::PointIndex (int i) const { + int index; + + if (!p_observationMode) { + index = (Images() - p_heldImages) * p_numImagePartials; + } + else { + index = Observations() * p_numImagePartials; + } + + index += p_pointIndexMap[i] * p_numPointPartials; + return index; + } + + //! Return index to basis function for ith image + int BundleAdjust::ImageIndex (int i) const { + if (!p_observationMode) { + return p_imageIndexMap[i] * p_numImagePartials; + } + else { + return p_onlist->ObservationNumberMapIndex(i) * p_numImagePartials; + } + } + + + //! Return the ith filename in the cube list file given to constructor + std::string BundleAdjust::Filename(int i) { +// std::string serialNumber = (*p_snlist)[i]; +// return p_snlist->Filename(serialNumber); + return p_snlist->Filename(i); + } + + //! Return a table cmatrix for the ith cube in the cube list given to the + //! constructor + Table BundleAdjust::Cmatrix(int i) { + return p_cnet->Camera(i)->InstrumentRotation()->Cache("InstrumentPointing"); + } + + //! Return a table spacecraft vector for the ith cube in the cube list given to the + //! constructor + Table BundleAdjust::SpVector(int i) { + return p_cnet->Camera(i)->InstrumentPosition()->Cache("InstrumentPosition"); + } + + //! Return the number of cubes in list given to the constructor + int BundleAdjust::Images () const { + return p_snlist->Size(); + } + + //! Return the number of observations in list given to the constructor + int BundleAdjust::Observations () const { + if ( !p_observationMode ) { + return p_snlist->Size() - p_heldImages; + } + else { + return p_onlist->ObservationSize(); + } + } + + + /** + * This method creates an iteration summary and creates an iteration group for + * the BundleAdjust summary. + * + * @param it Iteration number + * + * @param avErr Average error or iteration (pixels) + * + * @param sigmaXY Standard deviation of coordinates (mm) + * + * @param sigmaHat Aposteriori standard deviation of unit weight (mm) + * + * @param sigmaX Standard deviation of deltax (mm) + * + * @param sigmaY Standard deviation of deltay (mm) + * + */ + void BundleAdjust::IterationSummary(double avErr, double sigmaXY, double sigmaHat, + double sigmaX, double sigmaY) { + //Add this iteration to the summary pvl + std::string itlog = "Iteration" + iString( p_iteration ); + PvlGroup gp( itlog ); + gp += PvlKeyword("MaximumError", p_error, "pixels"); + gp += PvlKeyword("AverageError", avErr, "pixels"); + gp += PvlKeyword("SigmaXY", sigmaXY, "mm"); + gp += PvlKeyword("SigmaHat", sigmaHat, "mm"); + gp += PvlKeyword("SigmaX", sigmaX, "mm"); + gp += PvlKeyword("SigmaY", sigmaY, "mm"); + + Application::Log( gp ); + } + +} diff --git a/isis/src/base/objs/BundleAdjust/BundleAdjust.h b/isis/src/base/objs/BundleAdjust/BundleAdjust.h new file mode 100644 index 0000000000000000000000000000000000000000..6797a85c7e9ce4f01c7762742789a65367130b7d --- /dev/null +++ b/isis/src/base/objs/BundleAdjust/BundleAdjust.h @@ -0,0 +1,196 @@ +#ifndef BundleAdjust_h +#define BundleAdjust_h +/** + * @file + * $Revision: 1.24 $ + * $Date: 2010/03/27 06:23:42 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + * + * @author 2006-05-30 Jeff Anderson, Debbie A. Cook, and Tracie Sucharski + * + * @internal + * @history 2005-05-30 Jeff Anderson, Debbie A. Cook & Tracie Sucharski Original version + * @history 2007-05-29 Debbie A. Cook Added new method IterationSummary and + * changed points on held images to held instead of ground + * @history 2007-07-12 Debbie A. Cook Fixed bug in iteration statistics calculations in the + * case of a single control point that was causing a divide by zero error + * @history 2007-08-25 Debbie A. Cook Added methods and members to support instrument position solution + * @history 2007-09-17 Debbie A. Cook Added ability to process in observation mode for Lunar Orbiter + * @history 2007-11-17 Debbie A. Cook Added method SetSolution Method. + * @history 2007-12-21 Debbie A. Cook Added member p_Degree and methods p_solveCamDegree and ckDegree + * @history 2008-01-11 Debbie A. Cook Added observation mode functionality for spacecraft position + * and upgraded ObservationNumber methods for compatability + * @history 2008-01-14 Debbie A. Cook Added code to solve for local radii + * @history 2008-04-18 Debbie A. Cook Added progress for ControlNet + * @history 2008-06-18 Christopher Austin Fixed ifndef + * @history 2008-11-07 Tracie Sucharski, Added bool to constructors to + * indicate whether to print iteration summary info + * to the session log. This was needed for qtie which + * has no session log. + * @history 2008-11-22 Debbie A. Cook Added code to wrap longitude to keep it in [0.,360.] + * @history 2008-11-22 Debbie A. Cook Added new call to get timeScale and set for the observation along with basetime + * @history 2008-11-26 Debbie A. Cook Added check to ApplyHeldList for Ignored points and measures + * @history 2009-01-08 Debbie A. Cook Revised AddPartials and PointPartial to avoid using the camera methods + * to map a body-fixed vector to the camera because they compute a new time for line + * scan cameras based on the lat/lon/radius and the new time is used to retrieve Spice. + * The updated software uses the Spice at the time of the measurement. + * @history 2009-02-15 Debbie A. Cook Corrected focal length to include its sign and removed obsolete calls to X/Y + * direction methods. Also modified PointPartial to use lat/lon/radius from the point + * instead of the camera. + * @history 2009-08-13 Debbie A. Cook Corrected calculations of cudx and cudy so that they use the signed focal length + * also + * @history 2009-10-14 Debbie A. Cook Modified AddPartials method to use new CameraGroundMap method, GetXY + * @history 2009-10-30 Debbie A. Cook Improved error message in AddPartials + * @history 2009-12-14 Debbie A. Cook Updated SpicePosition enumerated partial type constants + * @history 2010-03-19 Debbie A. Cook Moved partials to GroundMap classes to support Radar sensors and modified + * argument list for GroundMap method ComputeXY since it now returns cudx and cudy + */ + +#include "ControlNet.h" +#include "SerialNumberList.h" +#include "ObservationNumberList.h" +#include "Camera.h" +#include "Statistics.h" +#include "SpicePosition.h" +#include "Progress.h" +#include "CameraGroundMap.h" + +namespace Isis { + class LeastSquares; + class BasisFunction; + + class BundleAdjust { + public: + BundleAdjust(const std::string &cnetFile, const std::string &cubeList, + bool printSummary=true); + BundleAdjust(const std::string &cnetFile, const std::string &cubeList, + const std::string &heldList,bool printSummary=true); + BundleAdjust(Isis::ControlNet &cnet, Isis::SerialNumberList &snlist, + bool printSummary=true); + BundleAdjust(Isis::ControlNet &cnet, Isis::SerialNumberList &snlist, + Isis::SerialNumberList &heldsnlist,bool printSummary=true); + ~BundleAdjust(); + + double Solve(double tol, int maxIterations); + + Isis::ControlNet *ControlNet() { return p_cnet; }; + + Isis::SerialNumberList *SerialNumberList() { return p_snlist; }; + int Images() const; + int Observations() const; + std::string Filename(int index); + Table Cmatrix(int index); + Table SpVector(int index); + + void SetSolveTwist(bool solve); + void SetSolveRadii(bool solve); + + enum CmatrixSolveType { + None, + AnglesOnly, + AnglesVelocity, + AnglesVelocityAcceleration, + All + }; + + enum SpacecraftPositionSolveType { + Nothing, + PositionOnly, + PositionVelocity, + PositionVelocityAcceleration + }; + + void SetSolveCmatrix(CmatrixSolveType type); + void SetSolveSpacecraftPosition(SpacecraftPositionSolveType type); + + //! Set the degree of the polynomial to fit to the camera angles + void SetCkDegree( int degree ) { p_ckDegree = degree; }; + + //! Set the degree of the polynomial to adjust in the solution + void SetSolveCamDegree( int degree ) { p_solveCamDegree = degree; }; + + int BasisColumns() const; + + double Error() const { return p_error; }; + double Iteration() const { return p_iteration; }; + + int HeldPoints() const { return p_heldPoints; }; + int IgnoredPoints() const { return p_ignoredPoints; }; + int GroundPoints() const { return p_groundPoints; }; + void SetObservationMode ( bool observationMode ); + + //! Set the solution method to use for solving the matrix + void SetSolutionMethod ( std::string solutionMethod ) { p_solutionMethod = solutionMethod;}; + + private: + void Init(Progress *progress=0); + + void ComputeNumberPartials(); + + void AddPartials (LeastSquares &lsq, + int point); + void Update (BasisFunction &basis); + + int PointIndex (int i) const; + + int ImageIndex (int i) const; + + void CheckHeldList(); + void ApplyHeldList(); + + Isis::ControlNet *p_cnet; + Isis::SerialNumberList *p_snlist; + Isis::SerialNumberList *p_heldsnlist; + Isis::ObservationNumberList *p_onlist; + + double p_error; + int p_iteration; + bool p_printSummary; + + int p_numImagePartials; + int p_numPointPartials; + + bool p_solveTwist; + bool p_solveRadii; + bool p_observationMode; + CmatrixSolveType p_cmatrixSolveType; + SpacecraftPositionSolveType p_spacecraftPositionSolveType; + + int p_heldPoints; + int p_groundPoints; + int p_ignoredPoints; + int p_heldImages; + int p_heldObservations; + std::vector p_pointIndexMap; + std::vector p_imageIndexMap; + bool p_cleanUp; + + void IterationSummary(double avErr, double sigmaXY, + double sigmaHat, double sigmaX, double sigmaY); + Statistics p_statx; + Statistics p_staty; + std::string p_solutionMethod; + int p_ckDegree; + int p_solveCamDegree; + int p_numberCameraCoefSolved; //!< The number of camera angle coefficients in the solution + }; +}; + +#endif + diff --git a/isis/src/base/objs/BundleAdjust/BundleAdjust.truth b/isis/src/base/objs/BundleAdjust/BundleAdjust.truth new file mode 100644 index 0000000000000000000000000000000000000000..6778689df11b8053607b38917aa3493066c6f6ca --- /dev/null +++ b/isis/src/base/objs/BundleAdjust/BundleAdjust.truth @@ -0,0 +1 @@ +This class is currently tested by the jigsaw application diff --git a/isis/src/base/objs/BundleAdjust/Makefile b/isis/src/base/objs/BundleAdjust/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c831e5b76cb40702c527dc76bd75a9e921c172b3 --- /dev/null +++ b/isis/src/base/objs/BundleAdjust/Makefile @@ -0,0 +1,5 @@ +INCS = BundleAdjust.h +SRCS = BundleAdjust.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/BundleAdjust/unitTest.cpp b/isis/src/base/objs/BundleAdjust/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f8ec6834eb6b8ee2f9197d28e7472a0de51ef08 --- /dev/null +++ b/isis/src/base/objs/BundleAdjust/unitTest.cpp @@ -0,0 +1,5 @@ +#include +int main (int argc, char *argv[]) +{ + std::cout << "This class is currently tested by the jigsaw application" << std::endl; +} diff --git a/isis/src/base/objs/CSVReader/CSVReader.cpp b/isis/src/base/objs/CSVReader/CSVReader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f37d2b5cfe426f6cbc698e944aed15deea786ab --- /dev/null +++ b/isis/src/base/objs/CSVReader/CSVReader.cpp @@ -0,0 +1,461 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/04/09 21:11:43 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include +#include "iString.h" +#include "CSVReader.h" +#include "CollectorMap.h" +#include "iException.h" + +using namespace std; + +namespace Isis { + +/** + * @brief Default constructor for CSV reader + * + * The default constructor sets up to read a source that has not header and + * skips no lines. It also sets the delimiter to the comma, as implied by its + * name (CSV = comma separated value), and treats multiple successive occurances + * of the delimiting character as individual tokens (keeping empty parts). + * + * This method can be used when deferring the reading of the input source. + * Other methods available in this class can be used to adjust the behavior of + * the parsing before [i]and[/i] after reading of the source as parsing is + * performed on demand. This means a single input source can be parsed + * repeatedly after adjusting parameters. + */ +CSVReader::CSVReader() : _header(false), _skip(0), + _delimiter(','), _keepParts(true), _lines(), + _ignoreComments(true) { } + +/** + * @brief Parameterized constructor for parsing an input file source + * + * This constructor can be used when the input source is an identified file. + * Parameters are available for specifying the parsing behavior, but are not + * necessarily required here as defaults are provided. Other methods in this + * class can set parsing conditions after the input file has been read in. + * + * If the file cannot be opened or an error is encountered during the reading of + * the file, an Isis exception is thrown. + * + * All lines are read in from the file and stored for subsequent parsing. + * Therefore, parsing can be performed at any time upon returning from this + * constructor. + * + * @param csvfile Name of file to open and read + * @param header Indicates if a header exists (true) in the file or not + * (false) + * @param skip Number of lines to skip to header, if it exists, or to the first + * data line + * @param delimiter Indicates the character to be used to delimit each token in + * the string/line + * @param keepEmptyParts Indicates successive delimiters are to be treated as + * empty tokens (true) or collapsed into one token + * (false) + */ +CSVReader::CSVReader(const std::string &csvfile, bool header, int skip, + const char &delimiter, const bool keepEmptyParts, + const bool ignoreComments) : + _header(header), _skip(skip),_delimiter(delimiter), + _keepParts(keepEmptyParts), _lines(), + _ignoreComments(ignoreComments) { + + read(csvfile); +} + + +/** + * @brief Determine the number of columns in the input source + * + * This method is applies the parsing conditions to all data lines to determine + * the number of columns. Note that it is assumed that all lines contain the + * same number of columns. + * + * If the number of columns vary in any of the lines, the least number of + * columns found in all lines is returned due to the nature of how the columns + * are determined. @see isTableValid(). + * + * Note that this can be an expensive operation if the input source is large as + * all lines are parsed. This does not include the header. @see columns(const + * CSVReader::CSVTable &table) for an alternative and more efficient method. + * That method takes a previously parsed table of all lines as an argument, + * which is precisely how this method determines the columns. + * + * @return int Number of columns in table, smallest column count if some lines + * are different + * @see getColumnSummary() + */ +int CSVReader::columns() const { + return ((rows() > 0) ? columns(getTable()) : 0); +} + +/** + * @brief Determine the number of columns in a parser CSV Table + * + * This method computes the number of columns from a CSVTable. This table is a + * result of the getTable method. + * + * It is assumed each row in the table has the same number of columns after + * parsing. If one or more of the rows contain differing columns, only the + * smallest number of columns are reported. + * + * @param table The table from which the CVSTable rows are obtained + * + * @return int Number of columns in table, smallest column count if some lines + * are different + * @see getColumnSummary() + */ +int CSVReader::columns(const CSVReader::CSVTable &table) const { + CSVColumnSummary summary = getColumnSummary(table); + return ((summary.size() > 0) ? summary.key(0) : 0); +} + + +/** + * @brief Reads the entire contents of a file for subsequent parsing + * + * This method opens the specified file and reads every line storing them in + * this object. It is assumed this file is a text file. Other methods in this + * class can be utilized to set parsing conditions before [i]or[/i] after the + * file has been read. + * + * Note that parsing the file is deferred until explicity invoked through other + * methods in this class. Users of this class can extract individual rows, + * columns or the complete table. + * + * This object is reentrant. Additional files can be read in. Any existing + * data from previous input sources is discarded upon subsequent reads. + * + * @param csvfile Name of file to read + */ +void CSVReader::read(const std::string &csvfile) throw (iException &) { + ifstream ifile(csvfile.c_str(), ios::in); + if (!ifile) { + string mess = "Unable to open file " + csvfile; + throw iException::Message(iException::User, mess, _FILEINFO_); + } + + _lines.clear(); + load(ifile); + ifile.close(); +} + +/** + * @brief Retrieve the header from the input source if it exists + * + * This method will return the header if it exists after appling the parsing + * rules. + * + * The existance of the header is determined entirely by the user of this class. + * If the header does not exist, a zero-length array is returned. + * + * Note that this routine does not trim leading or trailing whitespace from each + * header. This must be handled by the caller. + * + * @return CSVReader::CSVAxis Array containing the elements of the header + * @see haveHeader() + * @see setHeader() + */ +CSVReader::CSVAxis CSVReader::getHeader() const { + // Return an empty header if we don't have one + if ((!_header) || (_skip >= rows())) { return (CSVAxis(0)); } + return (Parser(_lines[_skip],_delimiter,_keepParts).result()); +} + +/** + * @brief Parse and return the requested row by index + * + * This method will parse and return the requested row from the input source as + * an array. If the requested row is determined to be an invalid index, then a + * zero-length array is returned. It is up to the caller to check for validity + * of the returned row array. + * + * @param index Index of the desired row to return + * + * @return CSVReader::CSVAxis Array of tokens after parsing rules are applied + */ +CSVReader::CSVAxis CSVReader::getRow(int index) const { + // Return an empty header if we don't have one + if ((index < 0) || (index >= rows())) { return (CSVAxis(0)); } + return (Parser(_lines[index+firstRowIndex()],_delimiter,_keepParts).result()); +} + + +/** + * @brief Parse and return a column specified by index order + * + * This method extracts a column from each row and returns the result. Note + * that parsing rules are applied to each row and the column at index is + * extracted and returned in the array. The array is always the number of rows + * from the input source (less skipped lines and header if they exist). + * + * It is assumed that every row has the same number of columns (@see + * isTableValid()) but in the event that the requested column does not exist for + * any (or all rows for that matter) a default constructed token is returned for + * that row. If the requested index is less than 0, an empty column is + * returned. + * + * Columns are 0-based index so the valid number of columns range 0 to + * (columns() - 1). + * + * @param index Zero-based column index to parse and return + * + * @return CSVReader::CSVAxis Array of token element from each column + */ +CSVReader::CSVAxis CSVReader::getColumn(int index) const { + // Return an empty header if we don't have one + if (index < 0) { return (CSVAxis(0)); } + + int nrows(rows()); + int nbad(0); + CSVAxis column(nrows); + Parser parser; + for (int i = 0 ; i < nrows ; i++) { + parser.parse(_lines[i+firstRowIndex()], _delimiter,_keepParts); + if (parser.size() <= index) { +// column[i] = Parser::TokenType(""); + nbad++; + } + else { + column[i] = parser(index); + } + } + + // If we had no good columns (index is invalid) return an empty column + return ((nbad == nrows) ? CSVAxis(0) : column); +} + +/** + * @brief Parse and return column specified by header name + * + * This method will parse and extract a column that corresponds to named column + * in the header. This method return a zero-length array if a header does not + * exist for this input source or the named column does not exist. + * + * The header is parsed using the same rules as each row. It is the + * responsibility of the user of this class to specify the existance of a + * header. Once the header is parsed, a case-insensitive search of the names is + * performed until the requested column name is found. The index of this header + * name is then used to extract the column from each row. + * + * It is assumed the column exists in each row. If it does not, a default + * constructed token is returned for non-existant columns in a row. + * + * @param hname Name of the column as it exists in the header + * + * @return CSVReader::CSVAxis Column array parsed from each row + */ +CSVReader::CSVAxis CSVReader::getColumn(const std::string &hname) const { + // Get the header + CSVAxis header(getHeader()); + std::string head = iString(hname).Trim(" "); + for (int i = 0 ; i < header.dim() ; i++) { + if (iString::Equal(head,iString(header[i]).Trim(" "))) { + return (getColumn(i)); + } + } + + // If we reach here, we did not find the column name + return (CSVAxis(0)); +} + + +/** + * @brief Parse and return all rows and columns in a table array + * + * This method returns a 2-D table of all rows and columns after parsing rules + * are applied. Each column or token in each row is returned as a + * CSVParser::TokenType. Subsequent conversion can be performed if the type + * sufficiently supports it or the user can provide its own conversion + * techniques. + * + * The validity of the table with regards to column integrity (same number of + * columns in each row) can be checked with the isTableValid method. A summary + * of the number of rows containing differing numbers of columns is provided by + * the getColumnSummary method. + * + * The returned table does not include the header row or any skipped rows. An + * empty table, zero-length array is returned if no rows are present. + * + * The table itself is a 1-dimenional array that contains a row at each element. + * This conceptually is a 2-dimensional table. Each element in the row (first) + * dimension of the table is a CSVAxis array containing parsed columns or + * tokens. Note that the number of columns may vary from row to row. + * + * @return CSVReader::CSVTable 2-D table of parsed columns in each row + */ +CSVReader::CSVTable CSVReader::getTable() const { + CSVTable table(rows()); + int nrows(rows()); + Parser parser; + for (int row = 0 ; row < nrows ; row++) { + parser.parse(_lines[row+firstRowIndex()], _delimiter, _keepParts); + table[row] = parser.result(); + } + return (table); +} + +/** + * @brief Computes a row summary of the number of distinct columns in table + * + * A CSVColumnSummary is a CollectorMap where the key is the number of columns + * and the value is the number of rows that contain that number of columns. + * This is useful to determine the consistancy of a parser input source such + * that every row contains the same number of columns. + * + * Once this summary is computed, there should exist one and only ome element in + * the summary where the key is the column count for each row and the value of + * that key is the number of rows that contain those columns. + * + * This example shows how to determine this information: + * @code + * CSVReader::CSVTable table = csv.getTable(); + * CSVReader::CSVColumnSummary summary = csv.getColumnSummary(table); + * cout << "Number of columns: " << csv.columns(table) << endl; + * cout << "Number distinct columns: " << summary.size() << endl; + * for (int ncols = 0 ; ncols < summary.size() ; ncols++) { + * cout << "--> " << summary.getNth(ncols) << " rows have " + * << summary.key(ncols) << " columns." << endl; + * } + * @endcode + * + * @param table Input table as returned by the getTable method + * + * @return CSVReader::CSVColumnSummary A CollectorMap that idicates the number + * of rows with distinct numbers of columns + * @see getTable() + * @see isTableValid() + */ +CSVReader::CSVColumnSummary CSVReader::getColumnSummary(const CSVTable &table) + const { + CSVColumnSummary summary; + for (int row = 0 ; row < table.dim() ; row++) { + int n(table[row].dim()); + if (summary.exists(n)) { + int &count = summary.get(n); + count++; + } + else { + summary.add(n,1); + } + } + + return (summary); +} + +/** + * @brief Indicates if all rows have the same number of columns + * + * This method checks the integrity of all rows in the inputs source as to + * whether they have the same number of columns. + * + * @param table Input table to check for integrity/validty + * + * @return bool True if all rows have the same number of columns, false if they + * do not + */ +bool CSVReader::isTableValid(const CSVReader::CSVTable &table) const { + CSVColumnSummary summary = getColumnSummary(table); + return (summary.size() <= 1); +} + +/** + * @brief Reads all lines from the input stream until an EOF is encoutered + * + * This method is the used to read from an input stream all lines of text until + * an end-of-file (EOF) is encountered. It is used to perform read operations + * for all sources of input, files and direct streams as supplied by the users + * of this class. + * + * All lines are assumed to end with a newline sequence pertinent to the systems + * this software is compiled on. All lines are stored as they are read in + * unless they are empty lines. The default behavior is to treat all lines that + * begin with a '#' as a comment. These lines are ignored by default and + * excluded as they are read. (Comment and blank line feature was added + * 2010/04/08.) + * + * As lines are read in from the input stream, they are pushed onto the internal + * stack in the order they are read. The calling environment is responsible for + * the state of the stack as to whether it is cleared or appended to an existing + * state. + * + * @param ifile Input source stream of lines of text + * + * @return std::istream& Returns the state of the input stream at the end of + * read operations. + */ +std::istream &CSVReader::load(std::istream &ifile) { + + string iline; + int nlines(0); + while (getline(ifile,iline)) { + if (!iline.empty()) { + if (!(_ignoreComments && (iline[0] == '#'))) { + _lines.push_back(iline); + nlines++; + } + } + } + + if (!ifile.eof()) { + ostringstream mess; + mess << "Error reading line " << (nlines+1) << ends; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + return (ifile); +} + +/** + * @brief Input read operator for input stream sources + * + * This input operator can be invoked directly from the users environment to + * read the complete input source. It can also be used to augment an existing + * source as this technique does not discard existing data (lines). + * + * It is presumed that any additional input sources are consistant to + * pre-established parsing guidelines otherwise, the integrity of the table is + * compromized. + * + * Here is an example of how to use this method: + * @code + * ifstream ifile("myfile.csv"); + * CSVReader csv; + * ifile >> csv; + * @endcode + * + * @param is Input stream source + * @param csv CSVReader object to read input source lines from + * + * @return std::istream& Returns the state of the input stream at EOF or error + */ +std::istream& operator>>(std::istream &is, CSVReader &csv) { + return (csv.load(is)); +} + +} diff --git a/isis/src/base/objs/CSVReader/CSVReader.h b/isis/src/base/objs/CSVReader/CSVReader.h new file mode 100644 index 0000000000000000000000000000000000000000..e5d8e973b5281c8b8afd4f82ab820f27ae9303d4 --- /dev/null +++ b/isis/src/base/objs/CSVReader/CSVReader.h @@ -0,0 +1,513 @@ +#ifndef CSVReader_h +#define CSVReader_h +/** + * @file + * $Revision: 1.6 $ + * $Date: 2010/04/09 21:11:43 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "tnt/tnt_array1d.h" +#include "iString.h" +#include "CollectorMap.h" +#include "iException.h" + +namespace Isis { + +/** + * @brief CSV Parser seperates fields (tokens) from a string with a delimeter + * + * CSVParser is a lightweigh parser that takes a string as an argument, either + * through the constructor or a method, and parses the string into tokens that + * are separated by a single delimiting character, usually a comma. It can work + * on spaces as well, but typically these types of strings have multiple spaces + * between them. For these cases, set keepEmptyParts = false, which treats + * succesive tokens as a single token. + * + * One important note about its token storage mechanism: It uses the TNT 1-D + * array class which is reference counted. This makes exporting of tokens very + * efficient at the expense of all instances referring to the same token list. + * This is subtle but can cause many surprising results when other users change + * the contents of the tokens. Use the TNT copy() method if you require your + * own list. + * + * This is a templated class that allows the user to select the token storage + * type. This type, which defaults to the Isis::iString class (I will explain + * the reason for this shortly), must provide a few features that are + * explicitly used in providing support for tokenization. + * + * The TokenStore class must provide a default, unparameterized constructor + * since it will be used as the default initializer. + * + * The class must also accept a string as a constructor option. This class uses + * a string splitter/tokenizer that returns a vector of strings. It then + * creates the token array and copies the result to it using an assignment + * statement from the string-accepted constructor of the TokenStore type. + * + * This token storage class is primarily used in the CSVReader which has + * additional requirements on the TokenStore type. See the CSVReader class + * documentation for more details. + * + * @ingroup Parsing + * @see CSVReader + * + * @author 2006-08-14 Kris Becker, USGS + * + * @history 2007-06-05 Brendan George - Modified to work with + * iString/StringTools merge + * @history 2008-06-18 Christopher Austin - Fixed documentation + */ +template +class CSVParser { + public: + typedef TokenStore TokenType; //!< Token storage type + typedef TNT::Array1D TokenList; //!< List of tokens + + /** Default constructor */ + CSVParser() { } + /** Destructor */ + virtual ~CSVParser() { } + + /** + * @brief Constructor that parses strings according to given parameters + * + * This constructor accepts a string to parse, the delimiter that separates + * words and indicate whether successive occurances of the delimiter + * translates into a single value or they are taken as empty tokens. + * + * @param str iString to parse + * @param delimiter Character that separates individual tokens in the string + * @param keepEmptyParts Specifies the occurance of successive tokens is to + * treated as one token (false) or each delimiter + * indicates an empty token (true) + */ + CSVParser(const std::string &str, const char &delimiter = ',', + bool keepEmptyParts = true) { + parse(str, delimiter, keepEmptyParts); + } + + /** Returns the number of tokens in the parsed string */ + int size() const { return (_elements.dim()); } + + /** + * @brief Returns the nth token in the parsed string + * + * Use of this method and size(), one can iterate through all the tokens in + * the resulting list using a for loop. Be sure the element exists before + * attempting to access it. + * + * @param nth Indicates the nth value to return - valid range is 0 to + * n_elements. + * @return const TokenType& Reference to the nth token in the parsed list + */ + const TokenType &operator()(const int nth) const { return (_elements[nth]); } + + /** + * @brief Parser method accepting string, delimiter and multiple token + * handling + * + * This method duplicates the behavior of the constructor so that it can be + * maintained for subsequent use. There is little overhead involved in the + * construction of this lightweight class, but this allows the same instance + * to be resued. + * + * @param str iString to parse into tokens separated by the delimiter + * @param delimiter Character that separates each token in str + * @param keepEmptyParts Specifies the occurance of successive tokens is to + * treated as one token (false) or each delimiter + * indicates an empty token (true) + * + * @return int Number of tokens found/parsed in the input string + */ + int parse(const std::string &str, const char &delimiter = ',', + bool keepEmptyParts = true) { + std::vector tokens; + iString::Split(delimiter,str,tokens,keepEmptyParts); + TokenList slist(tokens.size()); + for (unsigned int i = 0 ; i < tokens.size() ; i++) { + slist[i] = TokenType(tokens[i]); + } + _elements = slist; + return (_elements.dim()); + } + + /** + * @brief Returns the list of tokens + * + * This method returns the complete list of tokens. Note that it utilizes + * the most efficient method of storing and exporting tokens, namely a + * reference counted array. + */ + TokenList result() const { return (_elements); } + + private: + TokenList _elements; //!< List of tokens parsed from string +}; + + + +/** + * @brief Reads strings and parses them into tokens separated by a delimiter + * character. + * + * The class will read text strings from an input source stream or file where + * each line (string) contains a single character delimeter that separates them + * into tokens. The input stream is text in nature and each line is terminated + * with a newline as appropriate for the computer system. + * + * This class provides methods that support skipping irrelevant lines and + * recognizing and utlizing a header line. Tokens within a given line are + * separated by a single character. Consecutive delimiter characters can be + * treated as empty tokens (columns) or translated as a single token. + * Typically, consecutive tokens as empty strings is used for comma separated + * values (CSV) whereas space delimited strings oftentimes require multiple + * spaces to be treated as a single separator. This class supports both cases. + * + * Comments can exist in a CSV and are indicated with '#' as the first character + * in the line. Default behavior (as of 2010/04/08) is to ignore these lines as + * well as blank lines. Use the setComment() method to alter this behavior. + * Also note that the skip lines count does not include comments or blank lines. + * + * Each text line in the input source is read and stored in an internal stack. + * Only when explicitly requested does parsing take place - no parsing is + * performed during the reading of the input source. This approach allows the + * users of this class to alter or otherwise adjust parsing conditions after the + * input source has been internalized. This makes this implementation efficient + * and flexible deligating more control to the users of this class. + * + * The mechanism in which parsed data is stored and returned to the callers + * enviroment makes this class efficient. The returned rows, columns and tables + * use memory reference counting. This allows parsed data to be exported with + * virtually no cost to the calling environment in terms of efficiency. It does + * however, lend itself to utilization issues. Reference counting means that + * all instances of a parsed row, column or table refer to the same copy of the + * data and a change in one instance of those elements is reflected in all + * instances of that same row. Note that this concern rests entirely on how the + * caller's environment utilizes returned data as only the original lines read + * from the input source are maintained internal to objects. + * + * The following example demonstrates how to use this class to read a comma + * delimited file that may have consecutive commas and should be treated as + * empty columns. Furthermore, there are 2 lines to skip and a header line as + * well: + * @code + * cout << "\n\nProcessing comma table...\n"; + * std::string csvfile("comma.csv"); + * CSVReader csv(csvfile,true,2,','true); + * @endcode + * + * Another way to ingest this file using methods instead of the constructor is + * as follows: + * @code + * cout << "\n\nProcessing comma table using methods...\n"; + * std::string csvfile("comma.csv"); + * CSVReader csv; + * csv.setSkip(2); + * csv.setHeader(true); + * csv.setDelimiter(','); + * csv.setKeepEmptyParts(); + * csv.read(csvfile); + * @endcode + * Using this method will always purge any previously read data from the + * CSVReader object. + * + * @ingroup Utility + * @ingroup Parsing + * @author 2006-08-14 Kris Becker + * + * @history 2008-06-18 Christopher Austin - Fixed documentation + * @history 2010-04-08 Kris Becker - Added discarding of comment and blank lines + */ + class CSVReader { + + private: + typedef CSVParser Parser; //!< Defines single line parser + + public: + friend std::istream& operator>>(std::istream &is, CSVReader &csv); + + typedef Parser::TokenList CSVAxis; //!< Row/Column token list + typedef TNT::Array1D CSVTable; //!< Table of all rows/columns + typedef CollectorMap CSVColumnSummary; //!< Column summary for all rows + + typedef TNT::Array1D CSVDblVector; //!< Double array def. + typedef TNT::Array1D CSVIntVector; //!< Integer array def. + + // Constructors and Destructor + CSVReader(); + CSVReader(const std::string &csvfile, bool header = false, int skip = 0, + const char &delimiter = ',', const bool keepEmptyParts = true, + const bool ignoreComments = true); + + /** Destructor (benign) */ + virtual ~CSVReader () { } + + /** + * @brief Reports the total number of lines read from the stream + * @return int Number of lines read from input source + */ + int size() const { return (_lines.size()); } + + /** + * @brief Reports the number of rows in the table + * + * This method returns only the number of rows of data. This count does + * not include skipped lines or the header line if either exists. Note + * that if no lines are skipped and no header exists, this count will be + * identical to size(). + * + * @return int Number of rows of data from the input source + */ + int rows() const { + int nrows(_lines.size() - firstRowIndex()); + return ((nrows < 0) ? 0 : nrows); + } + + int columns() const; + int columns(const CSVTable &table) const; + + /** + * @brief Allows the user to indicate comment disposition + * + * Comments are indicated in a CSV file by a '#' sign in the first + * column. If they are present, the default is to ignore them and + * discard them when they are read in. This method allows the user to + * specify how to treat lines that begin with a '#' in the off chance they + * are part of the good stuff. + * + * Comment lines are not part of the skip lines parameter unless this is + * set to false. Then skip lines will include lines that start with a '#' + * if they exist. + * + * Also not that any and all blanl/empty lines are discarded and not + * included in any count - includig the skip line count. + * + * @param ignore True indicates lines that start with a '#' are considered + * a comment and are discarded. False will not discard + * these lines but include them in the parsing content. + */ + void setComment(const bool ignore = true) { _ignoreComments = ignore; } + + /** + * Indicate the number of lines at the top of the source to skip to data + * + * This method allows the user to indicate the number of lines that are to + * be ignored at the begining of the input source. These lines may + * contain any text, but are persistantly ignored for all row and column + * parsing operations. + * + * Note that this should not include a header line if one exists as the + * header methods maintain that information for parsing operations. It is + * assumed that header lines always follow skipped lines and immediately + * precede data lines. + * + * This count does not include comments lines (first character is a '#'), + * if they are ignored (default) or blank lines. + * + * @param nskip Number of lines to skip + */ + void setSkip(int nskip) { if (nskip >= 0) _skip = nskip; } + + /** + * @brief Reports the number of lines to skip + * + * This is the number of lines to skip to get to the header, if one + * exists, or to the first row of data to parse. + * + * @return int Number of lines to skip + */ + int getSkip() const { return (_skip); } + + /** + * @brief Returns true if a header is present in the input source + * + * The existance of a header line is always determined by the user of this + * class. See the setHeader() method for additional information on header + * maintainence. + */ + bool haveHeader() const { return (_header); } + + /** + * @brief Allows the user to indicate header disposition + * + * The determination of a header is entirely up to the user of this class. + * If a header exists, the user must indicate this with a true parameter + * to this method. That line is excluded from the row-by-row and column + * data parsing operations. If no header exists, provide false to this + * method. + * + * It is assumed that headers exist immediately prior to data rows and any + * skipped lines preceed the header line. Only one line is presumed to be + * a header. + * + * Note that this method can be set at any time in the process of reading + * from a file or stream source as parsing is done on demand and not at + * the time the source is read in. + * + * @param gotIt True indicates the presence of a header, false indicates + * one does not exist. + */ + void setHeader(const bool gotIt = true) { _header = gotIt; } + + + /** + * @brief Set the delimiter character that separate tokens in the strings + * + * This method provides the user of this class to indicate the character + * that separates individual tokens in each row, including the header + * line. + * + * One must ensure the delimiter character is not within tokens (such as + * comma delimited strings) or incorrect parsing will occur. + * + * @param delimiter Single character that delimits tokens in each string + */ + void setDelimiter(const char &delimiter) { _delimiter = delimiter; } + + /** + * @brief Reports the character used to delimit tokens in strings + * + * @return char Current character used to delimit tokens + */ + char getDelimiter() const { return (_delimiter); } + + /** + * @brief Indicate multiple occurances of delimiters are empty tokens + * + * Use of this method indicates that when multiple instances of the + * delimiting character occure in succession, they should be treated as + * empty tokens. This is useful when input sources truly have empty + * fields. + */ + void setKeepEmptyParts() { _keepParts = true; } + + /** + * @brief Indicate multiple occurances of delimiters are one token + * + * Use of this method indicates that when multiple instances of the + * delimiting character occurs in succession, they should be treated as a + * single token. This is useful when input sources have space separated + * tokens. Frequently, there are many spaces between values when spaces + * are used as the delimiting character. Call this method when spaces are + * used as token delimiters. + */ + void setSkipEmptyParts() { _keepParts = false; } + + /** Returns true when preserving succesive tokens, false when they are + * treated as one token. + * @see setKeepEmptyParts() + * @see setSkipEmptyParts() + */ + bool keepEmptyParts() const { return (_keepParts); } + + void read(const std::string &fname) throw (iException &); + + CSVAxis getHeader() const; + CSVAxis getRow(int index) const; + CSVAxis getColumn(int index) const; + CSVAxis getColumn(const std::string &hname) const; + CSVTable getTable() const; + bool isTableValid(const CSVTable &table) const; + + CSVColumnSummary getColumnSummary(const CSVTable &table) const; + + template TNT::Array1D convert(const CSVAxis &data) const; + + /** + * @brief Discards all lines read from an input source + * + * This method discards all lines read from any previous stream. Any + * subsequent row or column requests will return an empty condition. + */ + void clear() { _lines.clear(); } + + private: + typedef std::vector CSVList; //!< Input source line container + bool _header; //!< Indicates presences of header + int _skip; //!< Number of lines to skip + char _delimiter; //!< Separator of values + bool _keepParts; //!< Keep empty parts between delimiter + CSVList _lines; //!< List of lines from file + bool _ignoreComments; //!< Ignore comments on read + + /** + * @brief Computes the index of the first data + * + * This convenience method computes the index of the first data row + * considering the number of lines to skip and the existance of a header + * line. + * + * @return int Index of the first row of data + */ + int firstRowIndex() const { return (_skip + ((_header) ? 1 : 0)); } + + std::istream &load(std::istream &ifile); + }; + + + /** + * @brief Converts a row or column of data to the specified type + * + * This method will convert a row or column of data to the specified type. + * Since this is a template method, it must be invoked explicity through + * template syntax. Here is an example to extract a column by a header name + * and convert it to a double precision array: + * @code + * // Convert column 0/1 to double + * CSVReader::CSVAxis scol = csv.getColumn("0/1"); + * CSVReader::CSVDblVector dcol = csv.convert(scol); + * @endcode + * + * At present, this class uses the Isis iString class as its token storage type + * (TokenType). All that is required is that it have a cast operator for a + * given type. If the Isis iString class has the operator, it can be invoked + * for that type. The precise statement used to convert the token to the + * explict type is: + * @code + * out[i] = (T) s; + * @endcode + * In this example, \b s is the individual token and \b T is the type double + * as in the previous example. + * + * Note that conversions of specific special pixel values is not inherently + * handled by this method. If you anticipate textual representations of + * special pixels, such as NULL, LIS etc..., this is left up to the caller to + * handle directly. + * + * @param data Input row or column + * + * @return TNT::Array1D Converted data array of specified type + */ + template + TNT::Array1D CSVReader::convert(const CSVAxis &data) const { + TNT::Array1D out(data.dim()); + for (int i = 0 ; i < data.dim() ; i++) { + Parser::TokenType s = data[i]; + out[i] = (T) s; + } + return (out); + } +} + + +#endif + diff --git a/isis/src/base/objs/CSVReader/CSVReader.truth b/isis/src/base/objs/CSVReader/CSVReader.truth new file mode 100644 index 0000000000000000000000000000000000000000..5c3cc569f8281bc994c465537ea641179bc4348a --- /dev/null +++ b/isis/src/base/objs/CSVReader/CSVReader.truth @@ -0,0 +1,1101 @@ + + +Processing comma table... +Number of lines read: 1055 +Number of table rows: 1052 +Number lines skipped: 2 +Got a header: 1 +Size of header: 30 + First header value: Line No +Number of columns: 30 +Number distinct columns: 1 +--> 1052 rows have 30 columns. +Table integrity OK: 1 +Size of column 0/1: 1052 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 0.9050 Double: 0.9050 +iString: 1.0064 Double: 1.0064 +iString: 0.9972 Double: 0.9972 +iString: 1.0013 Double: 1.0013 +iString: 1.0035 Double: 1.0035 +iString: 1.0005 Double: 1.0005 +iString: 1.0060 Double: 1.0060 +iString: 1.0029 Double: 1.0029 +iString: 1.0027 Double: 1.0027 +iString: 0.9975 Double: 0.9975 +iString: 0.9968 Double: 0.9968 +iString: 0.9981 Double: 0.9981 +iString: 1.0057 Double: 1.0057 +iString: 1.0046 Double: 1.0046 +iString: 0.9975 Double: 0.9975 +iString: 0.9877 Double: 0.9877 +iString: 0.9912 Double: 0.9912 +iString: 1.0019 Double: 1.0019 +iString: 0.9957 Double: 0.9957 +iString: 1.0058 Double: 1.0058 +iString: 1.0020 Double: 1.0020 +iString: 0.9931 Double: 0.9931 +iString: 0.9941 Double: 0.9941 +iString: 0.9918 Double: 0.9918 +iString: 0.9997 Double: 0.9997 +iString: 0.9986 Double: 0.9986 +iString: 0.9977 Double: 0.9977 +iString: 0.9912 Double: 0.9912 +iString: 0.9877 Double: 0.9877 +iString: 0.9857 Double: 0.9857 +iString: 0.9982 Double: 0.9982 +iString: 0.9967 Double: 0.9967 +iString: 1.0036 Double: 1.0036 +iString: 0.9963 Double: 0.9963 +iString: 0.9875 Double: 0.9875 +iString: 0.9949 Double: 0.9949 +iString: 0.9935 Double: 0.9935 +iString: 0.9946 Double: 0.9946 +iString: 0.9963 Double: 0.9963 +iString: 0.9903 Double: 0.9903 +iString: 0.9890 Double: 0.9890 +iString: 0.9851 Double: 0.9851 +iString: 0.9872 Double: 0.9872 +iString: 0.9989 Double: 0.9989 +iString: 0.9954 Double: 0.9954 +iString: 1.0013 Double: 1.0013 +iString: 0.9948 Double: 0.9948 +iString: 0.9892 Double: 0.9892 +iString: 0.9926 Double: 0.9926 +iString: 0.9863 Double: 0.9863 +iString: 0.9928 Double: 0.9928 +iString: 0.9954 Double: 0.9954 +iString: 0.9957 Double: 0.9957 +iString: 0.9888 Double: 0.9888 +iString: 0.9859 Double: 0.9859 +iString: 0.9913 Double: 0.9913 +iString: 1.0006 Double: 1.0006 +iString: 0.9918 Double: 0.9918 +iString: 0.9986 Double: 0.9986 +iString: 0.9939 Double: 0.9939 +iString: 0.9914 Double: 0.9914 +iString: 0.9890 Double: 0.9890 +iString: 0.9925 Double: 0.9925 +iString: 0.9940 Double: 0.9940 +iString: 0.9987 Double: 0.9987 +iString: 0.9974 Double: 0.9974 +iString: 0.9915 Double: 0.9915 +iString: 0.9855 Double: 0.9855 +iString: 0.9918 Double: 0.9918 +iString: 0.9922 Double: 0.9922 +iString: 0.9924 Double: 0.9924 +iString: 0.9973 Double: 0.9973 +iString: 0.9946 Double: 0.9946 +iString: 0.9877 Double: 0.9877 +iString: 0.9928 Double: 0.9928 +iString: 0.9908 Double: 0.9908 +iString: 0.9965 Double: 0.9965 +iString: 0.9999 Double: 0.9999 +iString: 0.9960 Double: 0.9960 +iString: 0.9896 Double: 0.9896 +iString: 0.9871 Double: 0.9871 +iString: 0.9895 Double: 0.9895 +iString: 0.9975 Double: 0.9975 +iString: 0.9986 Double: 0.9986 +iString: 1.0030 Double: 1.0030 +iString: 0.9954 Double: 0.9954 +iString: 0.9928 Double: 0.9928 +iString: 0.9934 Double: 0.9934 +iString: 0.9984 Double: 0.9984 +iString: 0.9955 Double: 0.9955 +iString: 0.9998 Double: 0.9998 +iString: 0.9940 Double: 0.9940 +iString: 0.9920 Double: 0.9920 +iString: 0.9876 Double: 0.9876 +iString: 0.9884 Double: 0.9884 +iString: 0.9939 Double: 0.9939 +iString: 0.9941 Double: 0.9941 +iString: 1.0005 Double: 1.0005 +iString: 0.9957 Double: 0.9957 +iString: 0.9926 Double: 0.9926 +iString: 0.9960 Double: 0.9960 +iString: 0.9948 Double: 0.9948 +iString: 0.9961 Double: 0.9961 +iString: 0.9969 Double: 0.9969 +iString: 0.9987 Double: 0.9987 +iString: 0.9933 Double: 0.9933 +iString: 0.9895 Double: 0.9895 +iString: 0.9861 Double: 0.9861 +iString: 0.9994 Double: 0.9994 +iString: 0.9951 Double: 0.9951 +iString: 1.0016 Double: 1.0016 +iString: 0.9956 Double: 0.9956 +iString: 0.9910 Double: 0.9910 +iString: 0.9943 Double: 0.9943 +iString: 0.9956 Double: 0.9956 +iString: 0.9984 Double: 0.9984 +iString: 1.0012 Double: 1.0012 +iString: 0.9968 Double: 0.9968 +iString: 0.9982 Double: 0.9982 +iString: 0.9886 Double: 0.9886 +iString: 0.9945 Double: 0.9945 +iString: 1.0044 Double: 1.0044 +iString: 0.9979 Double: 0.9979 +iString: 1.0023 Double: 1.0023 +iString: 0.9991 Double: 0.9991 +iString: 0.9963 Double: 0.9963 +iString: 0.9942 Double: 0.9942 +iString: 0.9959 Double: 0.9959 +iString: 0.9999 Double: 0.9999 +iString: 1.0015 Double: 1.0015 +iString: 0.9945 Double: 0.9945 +iString: 0.9916 Double: 0.9916 +iString: 0.9912 Double: 0.9912 +iString: 0.9890 Double: 0.9890 +iString: 1.0016 Double: 1.0016 +iString: 0.9938 Double: 0.9938 +iString: 1.0055 Double: 1.0055 +iString: 0.9961 Double: 0.9961 +iString: 0.9950 Double: 0.9950 +iString: 0.9950 Double: 0.9950 +iString: 0.9955 Double: 0.9955 +iString: 1.0009 Double: 1.0009 +iString: 1.0036 Double: 1.0036 +iString: 0.9966 Double: 0.9966 +iString: 0.9986 Double: 0.9986 +iString: 0.9956 Double: 0.9956 +iString: 0.9898 Double: 0.9898 +iString: 1.0047 Double: 1.0047 +iString: 1.0024 Double: 1.0024 +iString: 1.0058 Double: 1.0058 +iString: 0.9994 Double: 0.9994 +iString: 0.9947 Double: 0.9947 +iString: 0.9984 Double: 0.9984 +iString: 0.9959 Double: 0.9959 +iString: 1.0018 Double: 1.0018 +iString: 1.0019 Double: 1.0019 +iString: 1.0042 Double: 1.0042 +iString: 1.0004 Double: 1.0004 +iString: 0.9940 Double: 0.9940 +iString: 0.9927 Double: 0.9927 +iString: 1.0087 Double: 1.0087 +iString: 1.0028 Double: 1.0028 +iString: 1.0075 Double: 1.0075 +iString: 0.9985 Double: 0.9985 +iString: 0.9972 Double: 0.9972 +iString: 1.0002 Double: 1.0002 +iString: 0.9979 Double: 0.9979 +iString: 1.0061 Double: 1.0061 +iString: 1.0122 Double: 1.0122 +iString: 1.0004 Double: 1.0004 +iString: 0.9986 Double: 0.9986 +iString: 0.9924 Double: 0.9924 +iString: 0.9946 Double: 0.9946 +iString: 1.0050 Double: 1.0050 +iString: 0.9988 Double: 0.9988 +iString: 1.0046 Double: 1.0046 +iString: 1.0007 Double: 1.0007 +iString: 0.9945 Double: 0.9945 +iString: 0.9992 Double: 0.9992 +iString: 1.0014 Double: 1.0014 +iString: 1.0035 Double: 1.0035 +iString: 1.0034 Double: 1.0034 +iString: 1.0006 Double: 1.0006 +iString: 0.9977 Double: 0.9977 +iString: 0.9986 Double: 0.9986 +iString: 0.9952 Double: 0.9952 +iString: 1.0022 Double: 1.0022 +iString: 0.9967 Double: 0.9967 +iString: 1.0069 Double: 1.0069 +iString: 1.0002 Double: 1.0002 +iString: 0.9986 Double: 0.9986 +iString: 0.9999 Double: 0.9999 +iString: 0.9996 Double: 0.9996 +iString: 0.9989 Double: 0.9989 +iString: 1.0026 Double: 1.0026 +iString: 1.0048 Double: 1.0048 +iString: 0.9979 Double: 0.9979 +iString: 0.9863 Double: 0.9863 +iString: 0.9926 Double: 0.9926 +iString: 1.0012 Double: 1.0012 +iString: 1.0017 Double: 1.0017 +iString: 1.0056 Double: 1.0056 +iString: 1.0011 Double: 1.0011 +iString: 0.9988 Double: 0.9988 +iString: 0.9978 Double: 0.9978 +iString: 0.9983 Double: 0.9983 +iString: 1.0001 Double: 1.0001 +iString: 1.0024 Double: 1.0024 +iString: 0.9995 Double: 0.9995 +iString: 0.9901 Double: 0.9901 +iString: 0.9906 Double: 0.9906 +iString: 0.9944 Double: 0.9944 +iString: 1.0040 Double: 1.0040 +iString: 1.0002 Double: 1.0002 +iString: 1.0080 Double: 1.0080 +iString: 0.9983 Double: 0.9983 +iString: 0.9989 Double: 0.9989 +iString: 0.9955 Double: 0.9955 +iString: 0.9983 Double: 0.9983 +iString: 1.0011 Double: 1.0011 +iString: 1.0022 Double: 1.0022 +iString: 1.0004 Double: 1.0004 +iString: 0.9993 Double: 0.9993 +iString: 0.9908 Double: 0.9908 +iString: 0.9979 Double: 0.9979 +iString: 1.0056 Double: 1.0056 +iString: 0.9987 Double: 0.9987 +iString: 1.0042 Double: 1.0042 +iString: 1.0019 Double: 1.0019 +iString: 0.9967 Double: 0.9967 +iString: 1.0007 Double: 1.0007 +iString: 0.9995 Double: 0.9995 +iString: 1.0023 Double: 1.0023 +iString: 1.0032 Double: 1.0032 +iString: 1.0031 Double: 1.0031 +iString: 0.9989 Double: 0.9989 +iString: 0.9966 Double: 0.9966 +iString: 0.9985 Double: 0.9985 +iString: 1.0049 Double: 1.0049 +iString: 0.9968 Double: 0.9968 +iString: 1.0065 Double: 1.0065 +iString: 0.9996 Double: 0.9996 +iString: 0.9969 Double: 0.9969 +iString: 0.9958 Double: 0.9958 +iString: 0.9976 Double: 0.9976 +iString: 1.0015 Double: 1.0015 +iString: 1.0040 Double: 1.0040 +iString: 1.0004 Double: 1.0004 +iString: 1.0046 Double: 1.0046 +iString: 0.9920 Double: 0.9920 +iString: 0.9933 Double: 0.9933 +iString: 0.8962 Double: 0.8962 +iString: 1.0077 Double: 1.0077 +iString: 1.0063 Double: 1.0063 +iString: 1.0002 Double: 1.0002 +iString: 1.0032 Double: 1.0032 +iString: 1.0002 Double: 1.0002 +iString: 0.9982 Double: 0.9982 +iString: 1.0048 Double: 1.0048 +iString: 0.9971 Double: 0.9971 +iString: 1.0046 Double: 1.0046 +iString: 0.9973 Double: 0.9973 +iString: 0.9981 Double: 0.9981 +iString: 1.0019 Double: 1.0019 +iString: 1.0013 Double: 1.0013 +iString: 1.0020 Double: 1.0020 +iString: 0.9997 Double: 0.9997 +iString: 0.9962 Double: 0.9962 +iString: 1.0032 Double: 1.0032 +iString: 0.9990 Double: 0.9990 +iString: 1.0036 Double: 1.0036 +iString: 1.0044 Double: 1.0044 +iString: 1.0007 Double: 1.0007 +iString: 1.0033 Double: 1.0033 +iString: 1.0035 Double: 1.0035 +iString: 1.0026 Double: 1.0026 +iString: 1.0064 Double: 1.0064 +iString: 1.0016 Double: 1.0016 +iString: 1.0046 Double: 1.0046 +iString: 1.0012 Double: 1.0012 +iString: 0.9997 Double: 0.9997 +iString: 1.0014 Double: 1.0014 +iString: 1.0000 Double: 1.0000 +iString: 1.0005 Double: 1.0005 +iString: 1.0017 Double: 1.0017 +iString: 0.9979 Double: 0.9979 +iString: 1.0038 Double: 1.0038 +iString: 1.0027 Double: 1.0027 +iString: 1.0021 Double: 1.0021 +iString: 1.0020 Double: 1.0020 +iString: 1.0022 Double: 1.0022 +iString: 1.0028 Double: 1.0028 +iString: 1.0024 Double: 1.0024 +iString: 0.9982 Double: 0.9982 +iString: 1.0014 Double: 1.0014 +iString: 0.9948 Double: 0.9948 +iString: 1.0037 Double: 1.0037 +iString: 1.0013 Double: 1.0013 +iString: 1.0019 Double: 1.0019 +iString: 1.0045 Double: 1.0045 +iString: 1.0000 Double: 1.0000 +iString: 0.9976 Double: 0.9976 +iString: 0.9992 Double: 0.9992 +iString: 1.0005 Double: 1.0005 +iString: 0.9964 Double: 0.9964 +iString: 0.9957 Double: 0.9957 +iString: 0.9972 Double: 0.9972 +iString: 0.9985 Double: 0.9985 +iString: 0.9962 Double: 0.9962 +iString: 0.9988 Double: 0.9988 +iString: 1.0058 Double: 1.0058 +iString: 0.9979 Double: 0.9979 +iString: 1.0021 Double: 1.0021 +iString: 0.9965 Double: 0.9965 +iString: 0.9991 Double: 0.9991 +iString: 1.0004 Double: 1.0004 +iString: 1.0000 Double: 1.0000 +iString: 0.9948 Double: 0.9948 +iString: 0.9953 Double: 0.9953 +iString: 0.9951 Double: 0.9951 +iString: 1.0014 Double: 1.0014 +iString: 0.9963 Double: 0.9963 +iString: 1.0026 Double: 1.0026 +iString: 1.0010 Double: 1.0010 +iString: 0.9982 Double: 0.9982 +iString: 1.0011 Double: 1.0011 +iString: 1.0000 Double: 1.0000 +iString: 0.9979 Double: 0.9979 +iString: 0.9948 Double: 0.9948 +iString: 0.9973 Double: 0.9973 +iString: 0.9981 Double: 0.9981 +iString: 0.9953 Double: 0.9953 +iString: 0.9977 Double: 0.9977 +iString: 1.0013 Double: 1.0013 +iString: 1.0007 Double: 1.0007 +iString: 0.9993 Double: 0.9993 +iString: 1.0009 Double: 1.0009 +iString: 0.9954 Double: 0.9954 +iString: 1.0029 Double: 1.0029 +iString: 0.9982 Double: 0.9982 +iString: 0.9964 Double: 0.9964 +iString: 0.9977 Double: 0.9977 +iString: 1.0018 Double: 1.0018 +iString: 0.9986 Double: 0.9986 +iString: 0.9984 Double: 0.9984 +iString: 0.9970 Double: 0.9970 +iString: 1.0031 Double: 1.0031 +iString: 0.9961 Double: 0.9961 +iString: 0.9957 Double: 0.9957 +iString: 1.0003 Double: 1.0003 +iString: 0.9974 Double: 0.9974 +iString: 0.9977 Double: 0.9977 +iString: 0.9967 Double: 0.9967 +iString: 0.9975 Double: 0.9975 +iString: 1.0000 Double: 1.0000 +iString: 0.9998 Double: 0.9998 +iString: 1.0008 Double: 1.0008 +iString: 0.9950 Double: 0.9950 +iString: 0.9948 Double: 0.9948 +iString: 1.0009 Double: 1.0009 +iString: 0.9967 Double: 0.9967 +iString: 0.9987 Double: 0.9987 +iString: 1.0053 Double: 1.0053 +iString: 0.9963 Double: 0.9963 +iString: 1.0007 Double: 1.0007 +iString: 0.9969 Double: 0.9969 +iString: 1.0008 Double: 1.0008 +iString: 1.0023 Double: 1.0023 +iString: 1.0000 Double: 1.0000 +iString: 0.9968 Double: 0.9968 +iString: 0.9971 Double: 0.9971 +iString: 0.9953 Double: 0.9953 +iString: 1.0013 Double: 1.0013 +iString: 0.9956 Double: 0.9956 +iString: 0.9966 Double: 0.9966 +iString: 0.9983 Double: 0.9983 +iString: 0.9981 Double: 0.9981 +iString: 0.9988 Double: 0.9988 +iString: 1.0022 Double: 1.0022 +iString: 0.9978 Double: 0.9978 +iString: 1.0013 Double: 1.0013 +iString: 0.9971 Double: 0.9971 +iString: 0.9978 Double: 0.9978 +iString: 0.9966 Double: 0.9966 +iString: 0.9943 Double: 0.9943 +iString: 0.9974 Double: 0.9974 +iString: 0.9963 Double: 0.9963 +iString: 0.9989 Double: 0.9989 +iString: 1.0034 Double: 1.0034 +iString: 0.9975 Double: 0.9975 +iString: 1.0037 Double: 1.0037 +iString: 0.9951 Double: 0.9951 +iString: 1.0007 Double: 1.0007 +iString: 1.0007 Double: 1.0007 +iString: 0.9996 Double: 0.9996 +iString: 0.9986 Double: 0.9986 +iString: 0.9972 Double: 0.9972 +iString: 0.9954 Double: 0.9954 +iString: 1.0027 Double: 1.0027 +iString: 0.9967 Double: 0.9967 +iString: 1.0078 Double: 1.0078 +iString: 1.0035 Double: 1.0035 +iString: 0.9979 Double: 0.9979 +iString: 1.0021 Double: 1.0021 +iString: 1.0013 Double: 1.0013 +iString: 0.9989 Double: 0.9989 +iString: 1.0013 Double: 1.0013 +iString: 1.0000 Double: 1.0000 +iString: 0.9984 Double: 0.9984 +iString: 0.9934 Double: 0.9934 +iString: 0.9931 Double: 0.9931 +iString: 0.9998 Double: 0.9998 +iString: 0.9983 Double: 0.9983 +iString: 1.0022 Double: 1.0022 +iString: 1.0013 Double: 1.0013 +iString: 0.9978 Double: 0.9978 +iString: 1.0012 Double: 1.0012 +iString: 0.9976 Double: 0.9976 +iString: 1.0028 Double: 1.0028 +iString: 1.0044 Double: 1.0044 +iString: 1.0055 Double: 1.0055 +iString: 0.9992 Double: 0.9992 +iString: 0.9961 Double: 0.9961 +iString: 0.9973 Double: 0.9973 +iString: 1.0068 Double: 1.0068 +iString: 0.9963 Double: 0.9963 +iString: 1.0059 Double: 1.0059 +iString: 1.0074 Double: 1.0074 +iString: 0.9994 Double: 0.9994 +iString: 1.0035 Double: 1.0035 +iString: 1.0014 Double: 1.0014 +iString: 1.0002 Double: 1.0002 +iString: 0.9993 Double: 0.9993 +iString: 0.9984 Double: 0.9984 +iString: 0.9996 Double: 0.9996 +iString: 1.0002 Double: 1.0002 +iString: 1.0000 Double: 1.0000 +iString: 1.0028 Double: 1.0028 +iString: 0.9986 Double: 0.9986 +iString: 1.0034 Double: 1.0034 +iString: 1.0077 Double: 1.0077 +iString: 0.9983 Double: 0.9983 +iString: 1.0022 Double: 1.0022 +iString: 0.9994 Double: 0.9994 +iString: 1.0023 Double: 1.0023 +iString: 1.0001 Double: 1.0001 +iString: 1.0048 Double: 1.0048 +iString: 1.0021 Double: 1.0021 +iString: 0.9983 Double: 0.9983 +iString: 0.9949 Double: 0.9949 +iString: 1.0036 Double: 1.0036 +iString: 0.9982 Double: 0.9982 +iString: 1.0024 Double: 1.0024 +iString: 1.0020 Double: 1.0020 +iString: 0.9983 Double: 0.9983 +iString: 1.0000 Double: 1.0000 +iString: 0.9980 Double: 0.9980 +iString: 1.0000 Double: 1.0000 +iString: 1.0068 Double: 1.0068 +iString: 1.0012 Double: 1.0012 +iString: 1.0009 Double: 1.0009 +iString: 0.9966 Double: 0.9966 +iString: 0.9965 Double: 0.9965 +iString: 1.0031 Double: 1.0031 +iString: 0.9982 Double: 0.9982 +iString: 1.0002 Double: 1.0002 +iString: 1.0021 Double: 1.0021 +iString: 0.9975 Double: 0.9975 +iString: 1.0026 Double: 1.0026 +iString: 1.0003 Double: 1.0003 +iString: 1.0044 Double: 1.0044 +iString: 1.0011 Double: 1.0011 +iString: 1.0004 Double: 1.0004 +iString: 0.9959 Double: 0.9959 +iString: 0.9996 Double: 0.9996 +iString: 0.9959 Double: 0.9959 +iString: 0.9969 Double: 0.9969 +iString: 0.9954 Double: 0.9954 +iString: 1.0013 Double: 1.0013 +iString: 1.0037 Double: 1.0037 +iString: 0.9986 Double: 0.9986 +iString: 1.0037 Double: 1.0037 +iString: 1.0049 Double: 1.0049 +iString: 0.9974 Double: 0.9974 +iString: 1.0017 Double: 1.0017 +iString: 0.9979 Double: 0.9979 +iString: 0.9987 Double: 0.9987 +iString: 0.9963 Double: 0.9963 +iString: 0.9947 Double: 0.9947 +iString: 0.9992 Double: 0.9992 +iString: 0.9995 Double: 0.9995 +iString: 1.0000 Double: 1.0000 +iString: 1.0060 Double: 1.0060 +iString: 0.9974 Double: 0.9974 +iString: 1.0022 Double: 1.0022 +iString: 0.9990 Double: 0.9990 +iString: 0.9942 Double: 0.9942 +iString: 0.9996 Double: 0.9996 +iString: 1.0016 Double: 1.0016 +iString: 0.9956 Double: 0.9956 +iString: 0.9955 Double: 0.9955 +iString: 0.9955 Double: 0.9955 +iString: 1.0036 Double: 1.0036 +iString: 0.9965 Double: 0.9965 +iString: 1.0034 Double: 1.0034 +iString: 1.0033 Double: 1.0033 +iString: 0.9979 Double: 0.9979 +iString: 1.0019 Double: 1.0019 +iString: 1.0010 Double: 1.0010 +iString: 0.9999 Double: 0.9999 +iString: 1.0045 Double: 1.0045 +iString: 0.9998 Double: 0.9998 +iString: 0.9999 Double: 0.9999 +iString: 0.9963 Double: 0.9963 +iString: 0.8968 Double: 0.8968 +iString: 0.9996 Double: 0.9996 +iString: 1.0001 Double: 1.0001 +iString: 0.9981 Double: 0.9981 +iString: 1.0002 Double: 1.0002 +iString: 0.9998 Double: 0.9998 +iString: 1.0029 Double: 1.0029 +iString: 0.9987 Double: 0.9987 +iString: 0.9985 Double: 0.9985 +iString: 0.9976 Double: 0.9976 +iString: 1.0029 Double: 1.0029 +iString: 1.0029 Double: 1.0029 +iString: 1.0022 Double: 1.0022 +iString: 1.0006 Double: 1.0006 +iString: 0.9985 Double: 0.9985 +iString: 0.9992 Double: 0.9992 +iString: 1.0059 Double: 1.0059 +iString: 1.0052 Double: 1.0052 +iString: 1.0064 Double: 1.0064 +iString: 1.0044 Double: 1.0044 +iString: 1.0037 Double: 1.0037 +iString: 1.0006 Double: 1.0006 +iString: 0.9960 Double: 0.9960 +iString: 1.0018 Double: 1.0018 +iString: 1.0068 Double: 1.0068 +iString: 1.0003 Double: 1.0003 +iString: 0.9976 Double: 0.9976 +iString: 0.9941 Double: 0.9941 +iString: 0.9982 Double: 0.9982 +iString: 1.0019 Double: 1.0019 +iString: 0.9980 Double: 0.9980 +iString: 1.0028 Double: 1.0028 +iString: 1.0038 Double: 1.0038 +iString: 0.9986 Double: 0.9986 +iString: 0.9991 Double: 0.9991 +iString: 0.9964 Double: 0.9964 +iString: 1.0001 Double: 1.0001 +iString: 1.0029 Double: 1.0029 +iString: 1.0010 Double: 1.0010 +iString: 0.9983 Double: 0.9983 +iString: 0.9996 Double: 0.9996 +iString: 0.9984 Double: 0.9984 +iString: 1.0019 Double: 1.0019 +iString: 1.0007 Double: 1.0007 +iString: 1.0096 Double: 1.0096 +iString: 1.0007 Double: 1.0007 +iString: 0.9956 Double: 0.9956 +iString: 0.9982 Double: 0.9982 +iString: 0.9960 Double: 0.9960 +iString: 0.9934 Double: 0.9934 +iString: 1.0023 Double: 1.0023 +iString: 1.0004 Double: 1.0004 +iString: 1.0028 Double: 1.0028 +iString: 0.9961 Double: 0.9961 +iString: 0.9965 Double: 0.9965 +iString: 1.0018 Double: 1.0018 +iString: 1.0023 Double: 1.0023 +iString: 1.0058 Double: 1.0058 +iString: 1.0030 Double: 1.0030 +iString: 0.9959 Double: 0.9959 +iString: 0.9985 Double: 0.9985 +iString: 0.9950 Double: 0.9950 +iString: 0.9998 Double: 0.9998 +iString: 1.0090 Double: 1.0090 +iString: 1.0030 Double: 1.0030 +iString: 0.9981 Double: 0.9981 +iString: 0.9941 Double: 0.9941 +iString: 0.9947 Double: 0.9947 +iString: 1.0058 Double: 1.0058 +iString: 0.9944 Double: 0.9944 +iString: 1.0025 Double: 1.0025 +iString: 1.0027 Double: 1.0027 +iString: 0.9977 Double: 0.9977 +iString: 0.9957 Double: 0.9957 +iString: 0.9953 Double: 0.9953 +iString: 1.0046 Double: 1.0046 +iString: 1.0082 Double: 1.0082 +iString: 0.9978 Double: 0.9978 +iString: 0.9964 Double: 0.9964 +iString: 0.9965 Double: 0.9965 +iString: 0.9987 Double: 0.9987 +iString: 1.0009 Double: 1.0009 +iString: 0.9957 Double: 0.9957 +iString: 0.9990 Double: 0.9990 +iString: 1.0037 Double: 1.0037 +iString: 0.9955 Double: 0.9955 +iString: 0.9987 Double: 0.9987 +iString: 0.9974 Double: 0.9974 +iString: 1.0002 Double: 1.0002 +iString: 1.0017 Double: 1.0017 +iString: 1.0011 Double: 1.0011 +iString: 0.9989 Double: 0.9989 +iString: 0.9943 Double: 0.9943 +iString: 0.9887 Double: 0.9887 +iString: 0.9977 Double: 0.9977 +iString: 0.9967 Double: 0.9967 +iString: 1.0030 Double: 1.0030 +iString: 1.0034 Double: 1.0034 +iString: 0.9995 Double: 0.9995 +iString: 1.0011 Double: 1.0011 +iString: 0.9964 Double: 0.9964 +iString: 0.9953 Double: 0.9953 +iString: 1.0021 Double: 1.0021 +iString: 0.9998 Double: 0.9998 +iString: 0.9992 Double: 0.9992 +iString: 0.9916 Double: 0.9916 +iString: 0.9944 Double: 0.9944 +iString: 1.0004 Double: 1.0004 +iString: 0.9972 Double: 0.9972 +iString: 1.0013 Double: 1.0013 +iString: 1.0021 Double: 1.0021 +iString: 0.9975 Double: 0.9975 +iString: 0.9976 Double: 0.9976 +iString: 0.9906 Double: 0.9906 +iString: 0.9963 Double: 0.9963 +iString: 1.0012 Double: 1.0012 +iString: 0.9979 Double: 0.9979 +iString: 0.9941 Double: 0.9941 +iString: 0.9946 Double: 0.9946 +iString: 0.9955 Double: 0.9955 +iString: 1.0019 Double: 1.0019 +iString: 0.9980 Double: 0.9980 +iString: 1.0026 Double: 1.0026 +iString: 0.9989 Double: 0.9989 +iString: 1.0000 Double: 1.0000 +iString: 0.9965 Double: 0.9965 +iString: 0.9952 Double: 0.9952 +iString: 1.0017 Double: 1.0017 +iString: 1.0038 Double: 1.0038 +iString: 0.9972 Double: 0.9972 +iString: 1.0000 Double: 1.0000 +iString: 0.9954 Double: 0.9954 +iString: 1.0023 Double: 1.0023 +iString: 0.9978 Double: 0.9978 +iString: 0.9974 Double: 0.9974 +iString: 0.9988 Double: 0.9988 +iString: 1.0010 Double: 1.0010 +iString: 0.9964 Double: 0.9964 +iString: 0.9990 Double: 0.9990 +iString: 0.9931 Double: 0.9931 +iString: 0.9964 Double: 0.9964 +iString: 1.0019 Double: 1.0019 +iString: 0.9976 Double: 0.9976 +iString: 1.0024 Double: 1.0024 +iString: 0.9949 Double: 0.9949 +iString: 0.9965 Double: 0.9965 +iString: 1.0003 Double: 1.0003 +iString: 0.9960 Double: 0.9960 +iString: 1.0032 Double: 1.0032 +iString: 0.9996 Double: 0.9996 +iString: 0.9981 Double: 0.9981 +iString: 0.9973 Double: 0.9973 +iString: 0.9965 Double: 0.9965 +iString: 0.9972 Double: 0.9972 +iString: 1.0044 Double: 1.0044 +iString: 1.0003 Double: 1.0003 +iString: 0.9984 Double: 0.9984 +iString: 0.9930 Double: 0.9930 +iString: 0.9978 Double: 0.9978 +iString: 1.0014 Double: 1.0014 +iString: 1.0013 Double: 1.0013 +iString: 1.0019 Double: 1.0019 +iString: 1.0030 Double: 1.0030 +iString: 0.9960 Double: 0.9960 +iString: 1.0044 Double: 1.0044 +iString: 0.9979 Double: 0.9979 +iString: 1.0024 Double: 1.0024 +iString: 1.0052 Double: 1.0052 +iString: 1.0027 Double: 1.0027 +iString: 1.0008 Double: 1.0008 +iString: 0.9971 Double: 0.9971 +iString: 0.9982 Double: 0.9982 +iString: 1.0030 Double: 1.0030 +iString: 0.9966 Double: 0.9966 +iString: 1.0020 Double: 1.0020 +iString: 0.9999 Double: 0.9999 +iString: 0.9989 Double: 0.9989 +iString: 1.0000 Double: 1.0000 +iString: 0.9976 Double: 0.9976 +iString: 0.9995 Double: 0.9995 +iString: 1.0066 Double: 1.0066 +iString: 0.9979 Double: 0.9979 +iString: 1.0013 Double: 1.0013 +iString: 0.9989 Double: 0.9989 +iString: 0.9973 Double: 0.9973 +iString: 1.0030 Double: 1.0030 +iString: 1.0008 Double: 1.0008 +iString: 1.0055 Double: 1.0055 +iString: 1.0061 Double: 1.0061 +iString: 1.0022 Double: 1.0022 +iString: 0.9999 Double: 0.9999 +iString: 1.0025 Double: 1.0025 +iString: 1.0033 Double: 1.0033 +iString: 1.0055 Double: 1.0055 +iString: 1.0011 Double: 1.0011 +iString: 1.0037 Double: 1.0037 +iString: 1.0006 Double: 1.0006 +iString: 0.9954 Double: 0.9954 +iString: 1.0025 Double: 1.0025 +iString: 1.0020 Double: 1.0020 +iString: 1.0088 Double: 1.0088 +iString: 1.0062 Double: 1.0062 +iString: 1.0031 Double: 1.0031 +iString: 1.0003 Double: 1.0003 +iString: 1.0039 Double: 1.0039 +iString: 1.0012 Double: 1.0012 +iString: 1.0058 Double: 1.0058 +iString: 0.9994 Double: 0.9994 +iString: 1.0022 Double: 1.0022 +iString: 0.9990 Double: 0.9990 +iString: 0.9988 Double: 0.9988 +iString: 1.0055 Double: 1.0055 +iString: 1.0059 Double: 1.0059 +iString: 1.0020 Double: 1.0020 +iString: 1.0043 Double: 1.0043 +iString: 0.9995 Double: 0.9995 +iString: 0.9991 Double: 0.9991 +iString: 0.9983 Double: 0.9983 +iString: 0.9991 Double: 0.9991 +iString: 1.0059 Double: 1.0059 +iString: 0.9981 Double: 0.9981 +iString: 0.9968 Double: 0.9968 +iString: 0.9971 Double: 0.9971 +iString: 1.0018 Double: 1.0018 +iString: 1.0050 Double: 1.0050 +iString: 0.9982 Double: 0.9982 +iString: 1.0032 Double: 1.0032 +iString: 1.0043 Double: 1.0043 +iString: 1.0038 Double: 1.0038 +iString: 1.0001 Double: 1.0001 +iString: 0.9970 Double: 0.9970 +iString: 1.0016 Double: 1.0016 +iString: 1.0063 Double: 1.0063 +iString: 1.0002 Double: 1.0002 +iString: 1.0035 Double: 1.0035 +iString: 0.9987 Double: 0.9987 +iString: 1.0007 Double: 1.0007 +iString: 1.0001 Double: 1.0001 +iString: 0.9989 Double: 0.9989 +iString: 1.0051 Double: 1.0051 +iString: 1.0071 Double: 1.0071 +iString: 0.9926 Double: 0.9926 +iString: 1.0010 Double: 1.0010 +iString: 0.9953 Double: 0.9953 +iString: 1.0066 Double: 1.0066 +iString: 1.0037 Double: 1.0037 +iString: 1.0040 Double: 1.0040 +iString: 1.0053 Double: 1.0053 +iString: 0.9979 Double: 0.9979 +iString: 0.9973 Double: 0.9973 +iString: 1.0033 Double: 1.0033 +iString: 1.0015 Double: 1.0015 +iString: 1.0043 Double: 1.0043 +iString: 0.9976 Double: 0.9976 +iString: 0.9979 Double: 0.9979 +iString: 1.0021 Double: 1.0021 +iString: 0.9990 Double: 0.9990 +iString: 1.0035 Double: 1.0035 +iString: 1.0062 Double: 1.0062 +iString: 1.0035 Double: 1.0035 +iString: 1.0037 Double: 1.0037 +iString: 0.9918 Double: 0.9918 +iString: 0.9990 Double: 0.9990 +iString: 0.8972 Double: 0.8972 +iString: 1.0012 Double: 1.0012 +iString: 1.0056 Double: 1.0056 +iString: 1.0013 Double: 1.0013 +iString: 1.0057 Double: 1.0057 +iString: 1.0024 Double: 1.0024 +iString: 1.0005 Double: 1.0005 +iString: 1.0018 Double: 1.0018 +iString: 0.9990 Double: 0.9990 +iString: 1.0051 Double: 1.0051 +iString: 1.0014 Double: 1.0014 +iString: 1.0065 Double: 1.0065 +iString: 1.0070 Double: 1.0070 +iString: 1.0024 Double: 1.0024 +iString: 0.9950 Double: 0.9950 +iString: 1.0019 Double: 1.0019 +iString: 1.0018 Double: 1.0018 +iString: 1.0078 Double: 1.0078 +iString: 1.0030 Double: 1.0030 +iString: 1.0042 Double: 1.0042 +iString: 1.0037 Double: 1.0037 +iString: 1.0014 Double: 1.0014 +iString: 1.0008 Double: 1.0008 +iString: 1.0049 Double: 1.0049 +iString: 1.0034 Double: 1.0034 +iString: 1.0053 Double: 1.0053 +iString: 1.0008 Double: 1.0008 +iString: 0.9959 Double: 0.9959 +iString: 1.0019 Double: 1.0019 +iString: 1.0009 Double: 1.0009 +iString: 1.0039 Double: 1.0039 +iString: 1.0019 Double: 1.0019 +iString: 1.0054 Double: 1.0054 +iString: 1.0100 Double: 1.0100 +iString: 1.0015 Double: 1.0015 +iString: 1.0007 Double: 1.0007 +iString: 1.0051 Double: 1.0051 +iString: 1.0045 Double: 1.0045 +iString: 1.0038 Double: 1.0038 +iString: 1.0011 Double: 1.0011 +iString: 0.9974 Double: 0.9974 +iString: 1.0015 Double: 1.0015 +iString: 0.9940 Double: 0.9940 +iString: 1.0015 Double: 1.0015 +iString: 0.9996 Double: 0.9996 +iString: 1.0047 Double: 1.0047 +iString: 0.9997 Double: 0.9997 +iString: 1.0000 Double: 1.0000 +iString: 0.9997 Double: 0.9997 +iString: 1.0030 Double: 1.0030 +iString: 1.0013 Double: 1.0013 +iString: 1.0063 Double: 1.0063 +iString: 1.0010 Double: 1.0010 +iString: 0.9947 Double: 0.9947 +iString: 0.9995 Double: 0.9995 +iString: 0.9999 Double: 0.9999 +iString: 1.0086 Double: 1.0086 +iString: 1.0050 Double: 1.0050 +iString: 1.0004 Double: 1.0004 +iString: 1.0067 Double: 1.0067 +iString: 1.0028 Double: 1.0028 +iString: 1.0013 Double: 1.0013 +iString: 0.9997 Double: 0.9997 +iString: 1.0060 Double: 1.0060 +iString: 1.0047 Double: 1.0047 +iString: 0.9994 Double: 0.9994 +iString: 0.9941 Double: 0.9941 +iString: 1.0029 Double: 1.0029 +iString: 1.0029 Double: 1.0029 +iString: 1.0102 Double: 1.0102 +iString: 1.0000 Double: 1.0000 +iString: 1.0074 Double: 1.0074 +iString: 1.0057 Double: 1.0057 +iString: 1.0035 Double: 1.0035 +iString: 1.0042 Double: 1.0042 +iString: 1.0001 Double: 1.0001 +iString: 1.0025 Double: 1.0025 +iString: 1.0063 Double: 1.0063 +iString: 0.9974 Double: 0.9974 +iString: 0.9997 Double: 0.9997 +iString: 1.0039 Double: 1.0039 +iString: 1.0004 Double: 1.0004 +iString: 1.0035 Double: 1.0035 +iString: 1.0015 Double: 1.0015 +iString: 1.0075 Double: 1.0075 +iString: 1.0024 Double: 1.0024 +iString: 0.9975 Double: 0.9975 +iString: 1.0049 Double: 1.0049 +iString: 1.0008 Double: 1.0008 +iString: 1.0026 Double: 1.0026 +iString: 1.0038 Double: 1.0038 +iString: 1.0029 Double: 1.0029 +iString: 0.9987 Double: 0.9987 +iString: 0.9997 Double: 0.9997 +iString: 0.9960 Double: 0.9960 +iString: 1.0081 Double: 1.0081 +iString: 1.0010 Double: 1.0010 +iString: 1.0072 Double: 1.0072 +iString: 0.9987 Double: 0.9987 +iString: 0.9974 Double: 0.9974 +iString: 1.0006 Double: 1.0006 +iString: 1.0027 Double: 1.0027 +iString: 1.0029 Double: 1.0029 +iString: 1.0085 Double: 1.0085 +iString: 1.0011 Double: 1.0011 +iString: 0.9983 Double: 0.9983 +iString: 0.9975 Double: 0.9975 +iString: 0.9983 Double: 0.9983 +iString: 1.0058 Double: 1.0058 +iString: 0.9943 Double: 0.9943 +iString: 0.9995 Double: 0.9995 +iString: 1.0012 Double: 1.0012 +iString: 0.9991 Double: 0.9991 +iString: 1.0009 Double: 1.0009 +iString: 1.0021 Double: 1.0021 +iString: 1.0080 Double: 1.0080 +iString: 1.0043 Double: 1.0043 +iString: 0.9981 Double: 0.9981 +iString: 0.9935 Double: 0.9935 +iString: 1.0022 Double: 1.0022 +iString: 1.0007 Double: 1.0007 +iString: 1.0048 Double: 1.0048 +iString: 0.9990 Double: 0.9990 +iString: 1.0059 Double: 1.0059 +iString: 1.0034 Double: 1.0034 +iString: 1.0017 Double: 1.0017 +iString: 0.9994 Double: 0.9994 +iString: 1.0066 Double: 1.0066 +iString: 1.0039 Double: 1.0039 +iString: 1.0001 Double: 1.0001 +iString: 0.9988 Double: 0.9988 +iString: 0.9992 Double: 0.9992 +iString: 1.0003 Double: 1.0003 +iString: 0.9990 Double: 0.9990 +iString: 1.0072 Double: 1.0072 +iString: 1.0052 Double: 1.0052 +iString: 1.0067 Double: 1.0067 +iString: 1.0080 Double: 1.0080 +iString: 1.0024 Double: 1.0024 +iString: 1.0033 Double: 1.0033 +iString: 1.0061 Double: 1.0061 +iString: 1.0085 Double: 1.0085 +iString: 1.0045 Double: 1.0045 +iString: 1.0060 Double: 1.0060 +iString: 1.0018 Double: 1.0018 +iString: 1.0024 Double: 1.0024 +iString: 1.0002 Double: 1.0002 +iString: 1.0120 Double: 1.0120 +iString: 1.0064 Double: 1.0064 +iString: 1.0068 Double: 1.0068 +iString: 1.0026 Double: 1.0026 +iString: 1.0014 Double: 1.0014 +iString: 1.0016 Double: 1.0016 +iString: 1.0056 Double: 1.0056 +iString: 1.0075 Double: 1.0075 +iString: 1.0039 Double: 1.0039 +iString: 1.0005 Double: 1.0005 +iString: 1.0023 Double: 1.0023 +iString: 0.9984 Double: 0.9984 +iString: 1.0046 Double: 1.0046 +iString: 1.0097 Double: 1.0097 +iString: 1.0053 Double: 1.0053 +iString: 1.0028 Double: 1.0028 +iString: 1.0025 Double: 1.0025 +iString: 1.0035 Double: 1.0035 +iString: 1.0017 Double: 1.0017 +iString: 1.0032 Double: 1.0032 +iString: 1.0065 Double: 1.0065 +iString: 1.0046 Double: 1.0046 +iString: 1.0038 Double: 1.0038 +iString: 0.9994 Double: 0.9994 +iString: 1.0050 Double: 1.0050 +iString: 1.0025 Double: 1.0025 +iString: 1.0105 Double: 1.0105 +iString: 1.0045 Double: 1.0045 +iString: 1.0077 Double: 1.0077 +iString: 1.0054 Double: 1.0054 +iString: 1.0037 Double: 1.0037 +iString: 1.0034 Double: 1.0034 +iString: 1.0065 Double: 1.0065 +iString: 1.0111 Double: 1.0111 +iString: 1.0122 Double: 1.0122 +iString: 1.0055 Double: 1.0055 +iString: 1.0013 Double: 1.0013 +iString: 1.0061 Double: 1.0061 +iString: 1.0068 Double: 1.0068 +iString: 1.0103 Double: 1.0103 +iString: 1.0094 Double: 1.0094 +iString: 1.0117 Double: 1.0117 +iString: 1.0096 Double: 1.0096 +iString: 1.0007 Double: 1.0007 +iString: 1.0051 Double: 1.0051 +iString: 1.0088 Double: 1.0088 +iString: 1.0129 Double: 1.0129 +iString: 1.0107 Double: 1.0107 +iString: 1.0069 Double: 1.0069 +iString: 1.0036 Double: 1.0036 +iString: 1.0096 Double: 1.0096 +iString: 1.0047 Double: 1.0047 +iString: 1.0169 Double: 1.0169 +iString: 1.0080 Double: 1.0080 +iString: 1.0149 Double: 1.0149 +iString: 1.0119 Double: 1.0119 +iString: 1.0081 Double: 1.0081 +iString: 1.0115 Double: 1.0115 +iString: 1.0153 Double: 1.0153 +iString: 1.0102 Double: 1.0102 +iString: 1.0197 Double: 1.0197 +iString: 1.0132 Double: 1.0132 +iString: 1.0080 Double: 1.0080 +iString: 1.0068 Double: 1.0068 +iString: 1.0092 Double: 1.0092 +iString: 1.0143 Double: 1.0143 +iString: 1.0086 Double: 1.0086 +iString: 1.0102 Double: 1.0102 +iString: 1.0123 Double: 1.0123 +iString: 1.0095 Double: 1.0095 +iString: 1.0133 Double: 1.0133 +iString: 1.0115 Double: 1.0115 +iString: 1.0139 Double: 1.0139 +iString: 1.0164 Double: 1.0164 +iString: 1.0136 Double: 1.0136 +iString: 1.0023 Double: 1.0023 +iString: 1.0086 Double: 1.0086 +iString: 1.0090 Double: 1.0090 +iString: 1.0159 Double: 1.0159 +iString: 1.0060 Double: 1.0060 +iString: 1.0152 Double: 1.0152 +iString: 1.0144 Double: 1.0144 +iString: 1.0086 Double: 1.0086 +iString: 1.0051 Double: 1.0051 +iString: 1.0127 Double: 1.0127 +iString: 1.0150 Double: 1.0150 +iString: 1.0138 Double: 1.0138 +iString: 1.0075 Double: 1.0075 +iString: 1.0066 Double: 1.0066 +iString: 1.0088 Double: 1.0088 +iString: 1.0105 Double: 1.0105 +iString: 1.0139 Double: 1.0139 +iString: 1.0159 Double: 1.0159 +iString: 1.0142 Double: 1.0142 +iString: 1.0120 Double: 1.0120 +iString: 1.0057 Double: 1.0057 +iString: 1.0117 Double: 1.0117 +iString: 1.0142 Double: 1.0142 +iString: 1.0150 Double: 1.0150 +iString: 1.0141 Double: 1.0141 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 +iString: 1.0000 Double: 1.0000 + + +Processing spaces table... +Number of lines read: 254 +Number of table rows: 252 +Number lines skipped: 2 +Got a header: 0 +Size of header: 0 +Number of columns: 126 +Number distinct columns: 1 +--> 252 rows have 126 columns. +Table integrity OK: 1 + + +Check empty table conditions... +Number of lines read: 0 +Number of table rows: 0 +Number lines skipped: 2 +Got a header: 0 +Size of header: 0 +Number of columns: 0 +Number distinct columns: 0 +Table integrity OK: 1 + + +Processing spaces table using streams... +Number of lines read: 254 +Number of table rows: 252 +Number lines skipped: 2 +Got a header: 0 +Size of header: 0 +Number of columns: 126 +Number distinct columns: 1 +--> 252 rows have 126 columns. +Table integrity OK: 1 diff --git a/isis/src/base/objs/CSVReader/Makefile b/isis/src/base/objs/CSVReader/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..82e9804ab70ec62ffac21cc0b2fd4423513e7c64 --- /dev/null +++ b/isis/src/base/objs/CSVReader/Makefile @@ -0,0 +1,6 @@ +INCS = CSVReader.h +SRCS = CSVReader.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/base/objs/CSVReader/comma.csv b/isis/src/base/objs/CSVReader/comma.csv new file mode 100644 index 0000000000000000000000000000000000000000..b1cc72ac5e22c79b28d3da2d8005bdb4d2a32ea4 --- /dev/null +++ b/isis/src/base/objs/CSVReader/comma.csv @@ -0,0 +1,1055 @@ +C:\HiRISE\Images\050603_Flat\_050603_Flatver11_A_MATRIX.csv +Header is CCD no/channel number +Line No, 0/0, 0/1, 1/0, 1/1, 2/0, 2/1, 3/0, 3/1, 4/0, 4/1, 5/0, 5/1, 6/0, 6/1, 7/0, 7/1, 8/0, 8/1, 9/0, 9/1, 10/0, 10/1, 11/0, 11/1, 12/0, 12/1, 13/0, 13/1, + 0, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 2, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 3, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 4, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 5, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 6, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 7, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 8, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 9, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 10, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 11, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 12, 0.9248, 0.9050, 0.9144, 0.9039, 0.9129, 0.9446, 0.9498, 0.9179, 0.9363, 0.9427, 0.9525, 0.9225, 0.9379, 0.9068, 0.9709, 0.9254, 0.9020, 0.8600, 0.9197, 0.9006, 0.8960, 0.9509, 0.9405, 0.9673, 0.9300, 0.8786, 0.9594, 0.9693, + 13, 1.0092, 1.0064, 1.0076, 1.0051, 1.0079, 1.0104, 1.0138, 1.0081, 1.0065, 1.0054, 1.0082, 1.0183, 1.0031, 1.0006, 1.0042, 1.0175, 1.0016, 1.0103, 1.0044, 1.0283, 1.0062, 1.0209, 0.9906, 1.0171, 0.9951, 0.9901, 0.9989, 0.9993, + 14, 1.0016, 0.9972, 1.0059, 1.0022, 1.0027, 1.0037, 1.0049, 0.9982, 1.0033, 1.0051, 1.0025, 1.0110, 1.0056, 1.0029, 0.9955, 1.0053, 1.0035, 1.0110, 0.9942, 1.0131, 1.0063, 1.0210, 0.9836, 1.0090, 0.9960, 0.9923, 0.9907, 0.9923, + 15, 1.0028, 1.0013, 1.0062, 1.0028, 1.0076, 1.0070, 1.0010, 0.9950, 1.0015, 1.0044, 0.9981, 1.0062, 1.0014, 1.0031, 0.9955, 1.0067, 1.0033, 1.0115, 0.9936, 1.0147, 0.9986, 1.0136, 0.9830, 1.0080, 0.9926, 0.9927, 0.9918, 0.9935, + 16, 1.0095, 1.0035, 1.0151, 1.0105, 1.0108, 1.0108, 1.0117, 1.0063, 1.0079, 1.0091, 1.0027, 1.0096, 1.0120, 1.0110, 0.9991, 1.0175, 1.0079, 1.0174, 1.0024, 1.0234, 0.9939, 1.0099, 0.9914, 1.0159, 0.9989, 0.9987, 0.9952, 0.9935, + 17, 1.0029, 1.0005, 1.0107, 1.0083, 1.0063, 1.0065, 1.0069, 1.0019, 1.0030, 1.0058, 1.0022, 1.0114, 1.0101, 1.0105, 0.9985, 1.0113, 1.0062, 1.0158, 0.9984, 1.0188, 0.9998, 1.0151, 0.9881, 1.0138, 0.9954, 0.9965, 0.9971, 0.9941, + 18, 1.0097, 1.0060, 1.0133, 1.0103, 1.0103, 1.0099, 1.0080, 1.0042, 1.0058, 1.0085, 1.0045, 1.0165, 1.0067, 1.0108, 0.9968, 1.0113, 1.0078, 1.0173, 0.9973, 1.0189, 1.0058, 1.0185, 0.9881, 1.0142, 0.9944, 0.9975, 0.9933, 0.9941, + 19, 1.0038, 1.0029, 1.0043, 1.0006, 1.0013, 1.0022, 1.0032, 0.9962, 0.9989, 1.0012, 0.9980, 1.0047, 1.0026, 1.0035, 0.9935, 1.0055, 1.0044, 1.0112, 0.9934, 1.0137, 0.9977, 1.0122, 0.9835, 1.0072, 0.9934, 0.9924, 0.9912, 0.9908, + 20, 1.0038, 1.0027, 1.0007, 0.9979, 1.0038, 1.0049, 1.0014, 0.9968, 1.0017, 1.0062, 0.9953, 1.0033, 1.0002, 1.0045, 0.9912, 1.0049, 1.0012, 1.0109, 0.9904, 1.0102, 1.0017, 1.0142, 0.9843, 1.0117, 0.9903, 0.9922, 0.9920, 0.9924, + 21, 1.0000, 0.9975, 1.0019, 1.0007, 1.0029, 1.0040, 1.0001, 0.9951, 0.9994, 1.0025, 0.9968, 1.0044, 0.9988, 1.0003, 0.9928, 1.0038, 1.0005, 1.0086, 0.9915, 1.0103, 0.9934, 1.0102, 0.9832, 1.0094, 0.9891, 0.9896, 0.9905, 0.9933, + 22, 0.9996, 0.9968, 1.0030, 0.9992, 1.0038, 1.0033, 1.0024, 0.9966, 0.9994, 0.9999, 0.9987, 1.0089, 1.0026, 1.0049, 0.9919, 1.0074, 1.0009, 1.0071, 0.9914, 1.0111, 0.9975, 1.0111, 0.9812, 1.0062, 0.9885, 0.9871, 0.9868, 0.9889, + 23, 1.0011, 0.9981, 1.0004, 0.9979, 1.0042, 1.0052, 1.0040, 1.0020, 0.9980, 1.0001, 0.9957, 1.0050, 0.9997, 1.0062, 0.9961, 1.0079, 1.0005, 1.0095, 0.9910, 1.0108, 1.0003, 1.0143, 0.9809, 1.0059, 0.9881, 0.9915, 0.9854, 0.9837, + 24, 1.0090, 1.0057, 1.0062, 1.0026, 1.0034, 1.0041, 1.0031, 0.9989, 0.9999, 1.0011, 0.9989, 1.0090, 0.9983, 0.9992, 0.9967, 1.0138, 1.0044, 1.0116, 0.9955, 1.0148, 0.9967, 1.0100, 0.9854, 1.0076, 0.9903, 0.9892, 0.9916, 0.9935, + 25, 1.0054, 1.0046, 1.0063, 1.0034, 1.0064, 1.0047, 1.0043, 1.0004, 1.0018, 1.0078, 0.9967, 1.0063, 1.0014, 1.0052, 0.9935, 1.0098, 1.0011, 1.0126, 0.9926, 1.0136, 0.9933, 1.0078, 0.9832, 1.0077, 0.9916, 0.9932, 0.9874, 0.9882, + 26, 0.9998, 0.9975, 1.0004, 0.9980, 0.9998, 1.0012, 0.9967, 0.9902, 0.9982, 1.0013, 0.9989, 1.0102, 0.9921, 0.9954, 0.9908, 1.0032, 0.9988, 1.0028, 0.9840, 1.0012, 1.0025, 1.0142, 0.9783, 1.0019, 0.9847, 0.9831, 0.9873, 0.9883, + 27, 0.9932, 0.9877, 0.9910, 0.9866, 0.9927, 0.9949, 0.9943, 0.9873, 0.9898, 0.9898, 0.9907, 0.9990, 0.9811, 0.9834, 0.9872, 0.9959, 0.9897, 0.9949, 0.9814, 0.9960, 0.9993, 1.0102, 0.9742, 0.9976, 0.9770, 0.9735, 0.9818, 0.9817, + 28, 0.9928, 0.9912, 0.9949, 0.9913, 0.9995, 1.0003, 0.9989, 0.9947, 0.9935, 0.9955, 0.9927, 0.9984, 0.9977, 1.0043, 0.9901, 1.0027, 0.9960, 1.0041, 0.9853, 1.0029, 0.9995, 1.0111, 0.9785, 1.0021, 0.9850, 0.9853, 0.9809, 0.9822, + 29, 1.0068, 1.0019, 1.0039, 0.9979, 1.0035, 1.0020, 1.0029, 0.9955, 1.0006, 1.0014, 0.9987, 1.0041, 0.9980, 0.9984, 0.9961, 1.0096, 1.0018, 1.0061, 0.9941, 1.0121, 0.9955, 1.0057, 0.9846, 1.0043, 0.9894, 0.9846, 0.9969, 0.9952, + 30, 0.9991, 0.9957, 1.0047, 1.0027, 1.0015, 1.0021, 1.0041, 0.9995, 0.9987, 0.9981, 0.9965, 1.0053, 1.0015, 1.0057, 0.9930, 1.0077, 0.9988, 1.0050, 0.9910, 1.0084, 0.9899, 1.0038, 0.9870, 1.0089, 0.9889, 0.9901, 0.9890, 0.9902, + 31, 1.0088, 1.0058, 1.0049, 0.9997, 1.0049, 1.0042, 1.0029, 0.9971, 1.0015, 1.0033, 1.0004, 1.0095, 1.0003, 1.0032, 0.9953, 1.0077, 1.0025, 1.0104, 0.9927, 1.0112, 1.0042, 1.0124, 0.9836, 1.0056, 0.9887, 0.9891, 0.9916, 0.9908, + 32, 1.0039, 1.0020, 1.0010, 0.9977, 1.0015, 1.0020, 1.0017, 0.9971, 0.9974, 0.9991, 0.9973, 1.0064, 0.9948, 0.9944, 0.9955, 1.0060, 1.0007, 1.0064, 0.9881, 1.0055, 0.9994, 1.0108, 0.9878, 1.0098, 0.9838, 0.9851, 0.9899, 0.9922, + 33, 0.9961, 0.9931, 0.9974, 0.9961, 0.9977, 0.9975, 0.9994, 0.9946, 0.9951, 0.9955, 0.9917, 0.9985, 0.9950, 0.9997, 0.9927, 1.0018, 0.9938, 0.9994, 0.9877, 1.0056, 0.9986, 1.0111, 0.9839, 1.0059, 0.9822, 0.9801, 0.9873, 0.9884, + 34, 0.9968, 0.9941, 0.9991, 0.9976, 0.9984, 0.9984, 0.9984, 0.9933, 0.9963, 0.9973, 0.9965, 1.0055, 0.9918, 0.9929, 0.9918, 1.0032, 0.9938, 0.9975, 0.9863, 1.0026, 0.9991, 1.0090, 0.9831, 1.0060, 0.9871, 0.9859, 0.9900, 0.9877, + 35, 0.9971, 0.9918, 0.9975, 0.9943, 0.9968, 0.9981, 1.0003, 0.9959, 0.9935, 0.9927, 0.9956, 1.0047, 0.9922, 0.9956, 0.9903, 1.0011, 0.9938, 0.9979, 0.9859, 1.0034, 0.9893, 1.0025, 0.9779, 0.9999, 0.9838, 0.9813, 0.9838, 0.9851, + 36, 1.0035, 0.9997, 1.0005, 0.9964, 1.0018, 1.0013, 1.0018, 0.9975, 0.9977, 0.9970, 0.9943, 1.0033, 0.9958, 1.0050, 0.9929, 1.0050, 1.0002, 1.0079, 0.9882, 1.0060, 0.9947, 1.0078, 0.9799, 1.0026, 0.9873, 0.9877, 0.9869, 0.9861, + 37, 1.0017, 0.9986, 0.9994, 0.9944, 1.0006, 1.0006, 1.0008, 0.9949, 0.9947, 0.9962, 0.9980, 1.0072, 0.9937, 0.9949, 0.9915, 1.0076, 0.9964, 1.0023, 0.9904, 1.0098, 0.9913, 1.0045, 0.9819, 1.0048, 0.9859, 0.9850, 0.9873, 0.9891, + 38, 1.0008, 0.9977, 1.0033, 0.9992, 1.0013, 1.0009, 1.0010, 0.9967, 0.9975, 0.9990, 0.9936, 1.0027, 0.9952, 0.9974, 0.9917, 1.0060, 0.9953, 1.0025, 0.9909, 1.0095, 0.9891, 1.0024, 0.9836, 1.0071, 0.9887, 0.9889, 0.9882, 0.9884, + 39, 0.9960, 0.9912, 0.9971, 0.9947, 0.9958, 0.9969, 0.9955, 0.9905, 0.9932, 0.9960, 0.9923, 1.0019, 0.9882, 0.9932, 0.9886, 1.0030, 0.9923, 0.9992, 0.9812, 0.9984, 0.9939, 1.0062, 0.9778, 1.0001, 0.9810, 0.9797, 0.9868, 0.9854, + 40, 0.9914, 0.9877, 0.9908, 0.9879, 0.9915, 0.9941, 0.9950, 0.9895, 0.9895, 0.9908, 0.9909, 0.9972, 0.9817, 0.9838, 0.9874, 0.9951, 0.9892, 0.9921, 0.9795, 0.9958, 0.9991, 1.0094, 0.9783, 1.0028, 0.9759, 0.9709, 0.9811, 0.9798, + 41, 0.9903, 0.9857, 0.9964, 0.9900, 0.9961, 0.9969, 0.9966, 0.9914, 0.9898, 0.9904, 0.9943, 1.0032, 0.9925, 0.9980, 0.9887, 0.9983, 0.9918, 0.9969, 0.9827, 0.9973, 0.9906, 1.0042, 0.9771, 0.9978, 0.9814, 0.9787, 0.9801, 0.9790, + 42, 1.0035, 0.9982, 1.0004, 0.9963, 1.0002, 1.0012, 0.9989, 0.9942, 0.9979, 0.9986, 0.9990, 1.0069, 0.9952, 0.9954, 0.9931, 1.0054, 0.9979, 1.0036, 0.9925, 1.0102, 0.9912, 1.0028, 0.9822, 1.0016, 0.9872, 0.9827, 0.9916, 0.9903, + 43, 0.9994, 0.9967, 1.0018, 0.9978, 1.0005, 1.0019, 1.0003, 0.9962, 0.9968, 0.9994, 0.9937, 1.0021, 0.9996, 1.0028, 0.9916, 1.0058, 0.9976, 1.0056, 0.9892, 1.0070, 0.9852, 0.9985, 0.9859, 1.0063, 0.9895, 0.9883, 0.9881, 0.9868, + 44, 1.0072, 1.0036, 1.0055, 1.0015, 1.0043, 1.0043, 1.0026, 0.9979, 1.0008, 1.0009, 0.9995, 1.0062, 1.0007, 1.0041, 0.9949, 1.0110, 1.0031, 1.0099, 0.9933, 1.0112, 1.0005, 1.0108, 0.9835, 1.0047, 0.9877, 0.9873, 0.9918, 0.9896, + 45, 1.0007, 0.9963, 0.9991, 0.9945, 0.9999, 1.0016, 1.0001, 0.9967, 0.9940, 0.9943, 0.9980, 1.0095, 0.9895, 0.9936, 0.9942, 1.0053, 0.9952, 1.0008, 0.9863, 1.0031, 0.9985, 1.0100, 0.9844, 1.0048, 0.9846, 0.9838, 0.9845, 0.9846, + 46, 0.9924, 0.9875, 0.9956, 0.9927, 0.9934, 0.9947, 0.9986, 0.9910, 0.9922, 0.9927, 0.9945, 1.0017, 0.9919, 0.9968, 0.9890, 0.9988, 0.9913, 0.9957, 0.9864, 1.0032, 0.9978, 1.0088, 0.9805, 1.0017, 0.9818, 0.9796, 0.9878, 0.9867, + 47, 0.9971, 0.9949, 0.9992, 0.9959, 0.9969, 0.9993, 0.9977, 0.9945, 0.9951, 0.9981, 0.9930, 1.0040, 0.9903, 0.9954, 0.9907, 1.0035, 0.9928, 0.9993, 0.9873, 1.0049, 0.9954, 1.0071, 0.9793, 1.0035, 0.9860, 0.9849, 0.9877, 0.9892, + 48, 0.9985, 0.9935, 0.9983, 0.9951, 0.9986, 0.9997, 0.9992, 0.9952, 0.9944, 0.9944, 0.9939, 1.0005, 0.9952, 0.9982, 0.9907, 1.0008, 0.9954, 1.0014, 0.9878, 1.0037, 0.9915, 1.0045, 0.9809, 1.0023, 0.9842, 0.9823, 0.9860, 0.9858, + 49, 0.9999, 0.9946, 0.9980, 0.9956, 0.9999, 1.0010, 0.9990, 0.9964, 0.9942, 0.9939, 0.9947, 1.0025, 0.9937, 1.0004, 0.9912, 1.0034, 0.9964, 1.0018, 0.9880, 1.0039, 0.9974, 1.0078, 0.9786, 0.9995, 0.9854, 0.9876, 0.9844, 0.9828, + 50, 0.9998, 0.9963, 1.0010, 0.9982, 0.9990, 1.0002, 1.0008, 0.9968, 0.9962, 0.9968, 0.9958, 1.0064, 0.9925, 0.9974, 0.9921, 1.0050, 0.9949, 1.0016, 0.9912, 1.0088, 0.9959, 1.0066, 0.9827, 1.0038, 0.9862, 0.9852, 0.9900, 0.9901, + 51, 0.9951, 0.9903, 0.9987, 0.9946, 0.9981, 0.9974, 0.9967, 0.9919, 0.9939, 0.9939, 0.9926, 0.9983, 0.9921, 0.9969, 0.9888, 1.0008, 0.9924, 0.9979, 0.9869, 1.0037, 0.9908, 1.0034, 0.9834, 1.0055, 0.9823, 0.9821, 0.9904, 0.9890, + 52, 0.9941, 0.9890, 0.9945, 0.9914, 0.9956, 0.9981, 0.9971, 0.9958, 0.9944, 0.9981, 0.9880, 0.9935, 0.9889, 0.9937, 0.9890, 1.0013, 0.9913, 0.9984, 0.9873, 1.0040, 0.9988, 1.0075, 0.9781, 0.9958, 0.9818, 0.9800, 0.9836, 0.9825, + 53, 0.9920, 0.9851, 0.9883, 0.9847, 0.9889, 0.9923, 0.9927, 0.9872, 0.9873, 0.9870, 0.9897, 0.9991, 0.9782, 0.9808, 0.9860, 0.9936, 0.9861, 0.9890, 0.9798, 0.9946, 0.9989, 1.0076, 0.9767, 0.9977, 0.9739, 0.9689, 0.9820, 0.9795, + 54, 0.9907, 0.9872, 0.9913, 0.9883, 0.9962, 0.9979, 0.9950, 0.9917, 0.9900, 0.9902, 0.9932, 1.0000, 0.9935, 0.9992, 0.9875, 0.9965, 0.9925, 0.9975, 0.9836, 0.9977, 0.9937, 1.0056, 0.9766, 0.9976, 0.9805, 0.9804, 0.9808, 0.9798, + 55, 1.0043, 0.9989, 0.9996, 0.9944, 0.9984, 1.0006, 0.9972, 0.9916, 0.9961, 0.9980, 0.9951, 1.0044, 0.9944, 0.9948, 0.9913, 1.0046, 0.9955, 1.0025, 0.9919, 1.0083, 0.9892, 1.0012, 0.9824, 1.0019, 0.9842, 0.9803, 0.9925, 0.9911, + 56, 1.0005, 0.9954, 1.0037, 0.9981, 1.0019, 1.0006, 1.0024, 0.9972, 0.9992, 0.9995, 0.9954, 1.0015, 1.0021, 1.0048, 0.9932, 1.0039, 0.9989, 1.0025, 0.9894, 1.0036, 0.9915, 1.0007, 0.9872, 1.0052, 0.9859, 0.9824, 0.9911, 0.9906, + 57, 1.0044, 1.0013, 1.0007, 0.9965, 0.9992, 1.0009, 0.9981, 0.9942, 0.9975, 0.9988, 0.9943, 1.0013, 0.9963, 1.0012, 0.9903, 1.0044, 0.9975, 1.0052, 0.9889, 1.0052, 0.9986, 1.0084, 0.9825, 1.0030, 0.9840, 0.9829, 0.9915, 0.9885, + 58, 0.9990, 0.9948, 0.9985, 0.9942, 0.9979, 0.9990, 1.0005, 0.9968, 0.9935, 0.9926, 0.9959, 1.0043, 0.9900, 0.9900, 0.9921, 1.0037, 0.9949, 0.9994, 0.9898, 1.0051, 0.9979, 1.0056, 0.9843, 1.0070, 0.9847, 0.9840, 0.9864, 0.9877, + 59, 0.9935, 0.9892, 0.9959, 0.9913, 0.9911, 0.9948, 0.9955, 0.9922, 0.9915, 0.9920, 0.9883, 0.9935, 0.9913, 0.9968, 0.9873, 0.9972, 0.9900, 0.9968, 0.9843, 1.0009, 0.9953, 1.0059, 0.9794, 0.9995, 0.9793, 0.9760, 0.9873, 0.9873, + 60, 0.9941, 0.9926, 0.9975, 0.9940, 0.9966, 0.9985, 0.9969, 0.9925, 0.9959, 0.9981, 0.9938, 1.0020, 0.9920, 0.9945, 0.9923, 1.0042, 0.9919, 0.9971, 0.9875, 1.0035, 0.9989, 1.0083, 0.9794, 0.9993, 0.9860, 0.9845, 0.9882, 0.9895, + 61, 0.9921, 0.9863, 0.9955, 0.9914, 0.9923, 0.9945, 0.9963, 0.9916, 0.9886, 0.9870, 0.9928, 1.0017, 0.9884, 0.9918, 0.9889, 0.9984, 0.9875, 0.9921, 0.9865, 1.0006, 0.9949, 1.0045, 0.9788, 0.9978, 0.9826, 0.9813, 0.9856, 0.9878, + 62, 0.9963, 0.9928, 0.9963, 0.9936, 0.9978, 0.9993, 0.9987, 0.9954, 0.9932, 0.9943, 0.9907, 0.9962, 0.9929, 1.0003, 0.9907, 1.0035, 0.9932, 0.9993, 0.9884, 1.0042, 0.9946, 1.0044, 0.9792, 0.9995, 0.9899, 0.9846, 0.9865, 0.9857, + 63, 0.9992, 0.9954, 1.0017, 0.9969, 0.9989, 0.9994, 0.9993, 0.9954, 0.9954, 0.9966, 0.9913, 0.9988, 0.9910, 0.9956, 0.9920, 1.0052, 0.9958, 1.0029, 0.9932, 1.0083, 0.9954, 1.0052, 0.9834, 1.0018, 0.9790, 0.9811, 0.9887, 0.9884, + 64, 0.9992, 0.9957, 0.9998, 0.9968, 0.9996, 0.9995, 0.9979, 0.9938, 0.9966, 0.9956, 0.9980, 1.0047, 0.9943, 0.9971, 0.9912, 1.0025, 0.9944, 1.0010, 0.9913, 1.0075, 0.9940, 1.0053, 0.9842, 1.0048, 0.9875, 0.9846, 0.9917, 0.9892, + 65, 0.9931, 0.9888, 0.9918, 0.9878, 0.9953, 0.9967, 0.9953, 0.9908, 0.9927, 0.9939, 0.9937, 1.0016, 0.9883, 0.9929, 0.9866, 0.9937, 0.9910, 0.9958, 0.9863, 1.0024, 0.9991, 1.0088, 0.9748, 0.9923, 0.9815, 0.9816, 0.9870, 0.9870, + 66, 0.9910, 0.9859, 0.9876, 0.9829, 0.9899, 0.9922, 0.9940, 0.9890, 0.9894, 0.9893, 0.9869, 0.9916, 0.9850, 0.9863, 0.9913, 0.9940, 0.9866, 0.9898, 0.9854, 0.9989, 0.9981, 1.0055, 0.9773, 0.9968, 0.9754, 0.9701, 0.9828, 0.9813, + 67, 0.9957, 0.9913, 0.9924, 0.9904, 0.9967, 0.9966, 0.9935, 0.9899, 0.9911, 0.9938, 0.9870, 0.9927, 0.9915, 0.9975, 0.9895, 0.9983, 0.9909, 0.9967, 0.9832, 0.9946, 0.9888, 1.0002, 0.9779, 0.9969, 0.9802, 0.9768, 0.9823, 0.9815, + 68, 1.0029, 1.0006, 1.0047, 0.9985, 0.9999, 1.0013, 1.0014, 0.9972, 0.9979, 0.9984, 0.9958, 1.0035, 0.9969, 0.9981, 0.9962, 1.0092, 0.9999, 1.0048, 0.9955, 1.0117, 0.9919, 1.0021, 0.9840, 1.0023, 0.9867, 0.9843, 0.9947, 0.9904, + 69, 0.9949, 0.9918, 1.0013, 0.9978, 0.9982, 0.9990, 1.0001, 0.9969, 0.9930, 0.9943, 0.9955, 1.0061, 0.9959, 0.9999, 0.9914, 1.0042, 0.9930, 1.0008, 0.9908, 1.0065, 0.9874, 0.9998, 0.9825, 1.0012, 0.9833, 0.9824, 0.9899, 0.9868, + 70, 1.0026, 0.9986, 1.0017, 0.9971, 0.9994, 1.0003, 0.9990, 0.9961, 0.9974, 0.9980, 0.9974, 1.0078, 0.9973, 1.0018, 0.9914, 1.0041, 0.9990, 1.0046, 0.9927, 1.0085, 0.9991, 1.0047, 0.9828, 1.0004, 0.9878, 0.9837, 0.9893, 0.9882, + 71, 0.9978, 0.9939, 0.9996, 0.9958, 0.9974, 0.9998, 1.0006, 0.9973, 0.9932, 0.9929, 0.9935, 1.0020, 0.9881, 0.9907, 0.9930, 1.0034, 0.9938, 0.9984, 0.9915, 1.0063, 0.9941, 1.0039, 0.9838, 1.0055, 0.9842, 0.9812, 0.9870, 0.9832, + 72, 0.9966, 0.9914, 0.9976, 0.9938, 0.9940, 0.9955, 0.9963, 0.9934, 0.9924, 0.9932, 0.9909, 0.9980, 0.9936, 0.9980, 0.9937, 1.0005, 0.9920, 0.9974, 0.9850, 1.0003, 0.9958, 1.0067, 0.9823, 0.9988, 0.9813, 0.9791, 0.9878, 0.9853, + 73, 0.9932, 0.9890, 0.9960, 0.9919, 0.9952, 0.9980, 0.9963, 0.9927, 0.9924, 0.9931, 0.9954, 1.0043, 0.9884, 0.9915, 0.9895, 0.9999, 0.9896, 0.9947, 0.9866, 1.0016, 0.9977, 1.0067, 0.9817, 1.0018, 0.9853, 0.9841, 0.9912, 0.9878, + 74, 0.9944, 0.9925, 0.9959, 0.9930, 0.9953, 0.9982, 0.9977, 0.9953, 0.9925, 0.9930, 0.9912, 1.0005, 0.9925, 0.9959, 0.9905, 1.0022, 0.9927, 0.9976, 0.9895, 1.0043, 0.9940, 1.0059, 0.9821, 1.0031, 0.9843, 0.9824, 0.9899, 0.9900, + 75, 0.9970, 0.9940, 0.9989, 0.9963, 0.9981, 0.9996, 0.9985, 0.9965, 0.9935, 0.9929, 0.9905, 0.9969, 0.9908, 0.9981, 0.9895, 1.0019, 0.9939, 1.0007, 0.9876, 1.0026, 0.9940, 1.0055, 0.9808, 0.9988, 0.9842, 0.9832, 0.9887, 0.9867, + 76, 1.0001, 0.9987, 1.0016, 0.9973, 1.0000, 1.0012, 1.0004, 0.9979, 0.9961, 0.9980, 0.9947, 1.0057, 0.9932, 0.9986, 0.9941, 1.0069, 0.9962, 1.0046, 0.9916, 1.0060, 0.9951, 1.0034, 0.9837, 1.0033, 0.9870, 0.9859, 0.9926, 0.9887, + 77, 0.9999, 0.9974, 0.9989, 0.9946, 0.9986, 1.0000, 0.9987, 0.9966, 0.9961, 0.9977, 0.9962, 1.0070, 0.9947, 0.9987, 0.9913, 1.0028, 0.9940, 1.0020, 0.9900, 1.0034, 0.9912, 1.0016, 0.9847, 1.0050, 0.9863, 0.9821, 0.9883, 0.9869, + 78, 0.9936, 0.9915, 0.9943, 0.9914, 0.9942, 0.9965, 0.9928, 0.9892, 0.9932, 0.9954, 0.9926, 1.0022, 0.9869, 0.9926, 0.9880, 0.9965, 0.9918, 0.9960, 0.9840, 0.9990, 0.9983, 1.0072, 0.9785, 0.9964, 0.9800, 0.9760, 0.9880, 0.9848, + 79, 0.9899, 0.9855, 0.9884, 0.9836, 0.9924, 0.9959, 0.9932, 0.9886, 0.9877, 0.9880, 0.9872, 0.9930, 0.9797, 0.9830, 0.9869, 0.9938, 0.9864, 0.9899, 0.9826, 0.9941, 1.0005, 1.0063, 0.9790, 0.9986, 0.9754, 0.9705, 0.9833, 0.9814, + 80, 0.9951, 0.9918, 0.9995, 0.9960, 0.9926, 0.9955, 0.9944, 0.9905, 0.9900, 0.9910, 0.9901, 0.9960, 0.9873, 0.9948, 0.9902, 0.9972, 0.9908, 0.9959, 0.9837, 0.9973, 0.9924, 1.0024, 0.9805, 0.9994, 0.9800, 0.9768, 0.9893, 0.9841, + 81, 0.9959, 0.9922, 1.0001, 0.9942, 0.9973, 0.9982, 0.9994, 0.9947, 0.9929, 0.9926, 0.9975, 1.0076, 0.9910, 0.9927, 0.9949, 1.0041, 0.9918, 0.9973, 0.9950, 1.0080, 0.9901, 1.0006, 0.9811, 0.9984, 0.9868, 0.9823, 0.9913, 0.9870, + 82, 0.9965, 0.9924, 1.0009, 0.9960, 0.9988, 0.9997, 1.0010, 0.9967, 0.9959, 0.9961, 0.9963, 1.0036, 0.9983, 1.0000, 0.9932, 1.0048, 0.9958, 1.0003, 0.9910, 1.0055, 0.9928, 1.0001, 0.9880, 1.0023, 0.9883, 0.9880, 0.9933, 0.9894, + 83, 0.9998, 0.9973, 1.0015, 0.9953, 1.0006, 1.0004, 0.9992, 0.9943, 0.9969, 0.9978, 0.9927, 0.9985, 0.9972, 1.0005, 0.9932, 1.0022, 0.9987, 1.0042, 0.9925, 1.0048, 0.9977, 1.0052, 0.9845, 0.9992, 0.9861, 0.9798, 0.9916, 0.9866, + 84, 0.9986, 0.9946, 1.0023, 0.9971, 0.9986, 1.0009, 1.0035, 1.0015, 0.9937, 0.9946, 0.9935, 1.0015, 0.9895, 0.9919, 0.9938, 1.0061, 0.9948, 1.0000, 0.9904, 1.0038, 0.9989, 1.0063, 0.9875, 1.0073, 0.9840, 0.9821, 0.9911, 0.9887, + 85, 0.9909, 0.9877, 0.9947, 0.9910, 0.9917, 0.9933, 0.9946, 0.9906, 0.9909, 0.9903, 0.9931, 1.0017, 0.9897, 0.9940, 0.9889, 0.9964, 0.9898, 0.9948, 0.9852, 0.9999, 0.9974, 1.0055, 0.9805, 0.9996, 0.9804, 0.9770, 0.9894, 0.9864, + 86, 0.9953, 0.9928, 0.9987, 0.9941, 0.9968, 0.9985, 0.9978, 0.9943, 0.9948, 0.9982, 0.9926, 1.0018, 0.9902, 0.9940, 0.9899, 1.0012, 0.9906, 0.9961, 0.9905, 1.0046, 0.9979, 1.0054, 0.9811, 1.0002, 0.9853, 0.9817, 0.9917, 0.9881, + 87, 0.9936, 0.9908, 0.9955, 0.9905, 0.9944, 0.9972, 0.9970, 0.9922, 0.9913, 0.9917, 0.9916, 1.0006, 0.9915, 0.9952, 0.9887, 0.9981, 0.9935, 0.9973, 0.9869, 1.0007, 0.9974, 1.0067, 0.9803, 0.9987, 0.9814, 0.9786, 0.9898, 0.9878, + 88, 0.9980, 0.9965, 0.9985, 0.9970, 0.9990, 0.9997, 0.9980, 0.9957, 0.9948, 0.9958, 0.9911, 0.9976, 0.9954, 1.0015, 0.9918, 1.0019, 0.9934, 1.0016, 0.9890, 1.0034, 0.9991, 1.0070, 0.9806, 0.9983, 0.9866, 0.9859, 0.9898, 0.9868, + 89, 1.0014, 0.9999, 0.9980, 0.9956, 1.0001, 1.0009, 0.9979, 0.9946, 0.9963, 0.9970, 0.9931, 1.0018, 0.9937, 0.9967, 0.9937, 1.0034, 0.9951, 1.0024, 0.9907, 1.0057, 0.9934, 1.0029, 0.9835, 1.0007, 0.9897, 0.9864, 0.9911, 0.9884, + 90, 0.9987, 0.9960, 1.0009, 0.9969, 1.0000, 1.0004, 0.9994, 0.9976, 0.9962, 0.9989, 0.9915, 1.0001, 0.9961, 1.0014, 0.9918, 1.0059, 0.9957, 1.0032, 0.9911, 1.0064, 0.9921, 1.0032, 0.9859, 1.0042, 0.9864, 0.9844, 0.9939, 0.9888, + 91, 0.9912, 0.9896, 0.9944, 0.9914, 0.9929, 0.9946, 0.9933, 0.9895, 0.9913, 0.9927, 0.9893, 0.9978, 0.9822, 0.9872, 0.9899, 0.9957, 0.9875, 0.9922, 0.9844, 0.9982, 0.9973, 1.0066, 0.9757, 0.9944, 0.9789, 0.9722, 0.9880, 0.9868, + 92, 0.9908, 0.9871, 0.9892, 0.9848, 0.9911, 0.9946, 0.9935, 0.9905, 0.9879, 0.9885, 0.9897, 0.9966, 0.9801, 0.9826, 0.9880, 0.9951, 0.9874, 0.9890, 0.9832, 0.9971, 1.0003, 1.0084, 0.9785, 0.9976, 0.9752, 0.9671, 0.9834, 0.9818, + 93, 0.9915, 0.9895, 0.9951, 0.9912, 0.9927, 0.9944, 0.9947, 0.9917, 0.9891, 0.9894, 0.9912, 0.9971, 0.9899, 0.9938, 0.9882, 0.9964, 0.9883, 0.9931, 0.9819, 0.9953, 0.9902, 1.0018, 0.9786, 0.9944, 0.9774, 0.9736, 0.9877, 0.9869, + 94, 0.9999, 0.9975, 0.9989, 0.9940, 0.9985, 1.0001, 0.9998, 0.9967, 0.9957, 0.9966, 0.9953, 1.0035, 0.9960, 0.9982, 0.9956, 1.0044, 0.9962, 1.0024, 0.9934, 1.0092, 0.9877, 0.9985, 0.9839, 1.0011, 0.9867, 0.9828, 0.9906, 0.9876, + 95, 0.9998, 0.9986, 0.9986, 0.9954, 0.9997, 1.0016, 0.9969, 0.9940, 0.9976, 0.9993, 0.9922, 0.9972, 0.9980, 1.0003, 0.9931, 1.0030, 0.9968, 1.0033, 0.9892, 1.0018, 0.9902, 1.0008, 0.9890, 1.0049, 0.9864, 0.9834, 0.9925, 0.9880, + 96, 1.0055, 1.0030, 1.0027, 0.9992, 1.0024, 1.0020, 1.0005, 0.9959, 0.9998, 1.0009, 0.9965, 1.0051, 0.9997, 1.0030, 0.9923, 1.0043, 0.9997, 1.0069, 0.9910, 1.0065, 1.0011, 1.0091, 0.9859, 1.0020, 0.9863, 0.9844, 0.9916, 0.9883, + 97, 0.9972, 0.9954, 0.9976, 0.9934, 0.9963, 0.9982, 0.9992, 0.9958, 0.9930, 0.9942, 0.9952, 1.0042, 0.9875, 0.9880, 0.9918, 1.0013, 0.9930, 0.9976, 0.9884, 1.0006, 0.9982, 1.0051, 0.9865, 1.0059, 0.9816, 0.9763, 0.9887, 0.9826, + 98, 0.9950, 0.9928, 0.9975, 0.9943, 0.9941, 0.9963, 0.9970, 0.9930, 0.9938, 0.9936, 0.9903, 0.9971, 0.9934, 0.9976, 0.9908, 1.0015, 0.9931, 0.9976, 0.9872, 1.0017, 0.9967, 1.0071, 0.9846, 0.9998, 0.9824, 0.9778, 0.9910, 0.9878, + 99, 0.9946, 0.9934, 0.9968, 0.9920, 0.9970, 0.9983, 0.9971, 0.9939, 0.9935, 0.9959, 0.9919, 0.9986, 0.9874, 0.9914, 0.9895, 0.9983, 0.9899, 0.9940, 0.9892, 1.0039, 0.9974, 1.0062, 0.9801, 0.9999, 0.9846, 0.9802, 0.9916, 0.9897, + 100, 0.9995, 0.9984, 0.9985, 0.9962, 0.9982, 0.9998, 0.9982, 0.9951, 0.9964, 0.9958, 0.9936, 1.0017, 0.9952, 0.9980, 0.9920, 1.0021, 0.9953, 1.0023, 0.9914, 1.0061, 0.9970, 1.0064, 0.9848, 1.0027, 0.9848, 0.9809, 0.9914, 0.9885, + 101, 0.9979, 0.9955, 0.9980, 0.9946, 0.9968, 1.0005, 0.9964, 0.9957, 0.9932, 0.9932, 0.9946, 1.0038, 0.9924, 0.9992, 0.9905, 1.0004, 0.9932, 1.0009, 0.9892, 1.0029, 0.9943, 1.0048, 0.9797, 0.9969, 0.9845, 0.9826, 0.9902, 0.9896, + 102, 1.0013, 0.9998, 1.0008, 0.9955, 1.0000, 1.0005, 0.9994, 0.9956, 0.9965, 0.9971, 0.9944, 1.0033, 0.9935, 0.9963, 0.9941, 1.0039, 0.9956, 1.0010, 0.9908, 1.0058, 0.9945, 1.0056, 0.9825, 1.0019, 0.9856, 0.9813, 0.9911, 0.9887, + 103, 0.9952, 0.9940, 0.9999, 0.9968, 0.9968, 0.9992, 0.9979, 0.9961, 0.9942, 0.9956, 0.9922, 0.9987, 0.9911, 0.9963, 0.9919, 1.0032, 0.9928, 0.9986, 0.9903, 1.0046, 0.9890, 1.0011, 0.9852, 1.0033, 0.9840, 0.9828, 0.9931, 0.9903, + 104, 0.9947, 0.9920, 0.9962, 0.9920, 0.9947, 0.9967, 0.9960, 0.9920, 0.9946, 0.9962, 0.9923, 1.0002, 0.9877, 0.9934, 0.9905, 1.0003, 0.9914, 0.9963, 0.9863, 0.9988, 0.9942, 1.0040, 0.9890, 0.9997, 0.9831, 0.9818, 0.9879, 0.9839, + 105, 0.9903, 0.9876, 0.9903, 0.9867, 0.9899, 0.9928, 0.9936, 0.9911, 0.9882, 0.9866, 0.9907, 0.9966, 0.9808, 0.9800, 0.9894, 0.9938, 0.9844, 0.9888, 0.9829, 0.9976, 0.9974, 1.0065, 0.9828, 0.9983, 0.9771, 0.9725, 0.9852, 0.9819, + 106, 0.9894, 0.9884, 0.9952, 0.9929, 0.9958, 0.9975, 0.9941, 0.9915, 0.9906, 0.9901, 0.9943, 1.0027, 0.9947, 0.9979, 0.9890, 0.9956, 0.9896, 0.9963, 0.9845, 0.9969, 0.9933, 1.0038, 0.9794, 0.9961, 0.9803, 0.9766, 0.9907, 0.9870, + 107, 0.9963, 0.9939, 0.9974, 0.9922, 0.9972, 0.9995, 0.9974, 0.9935, 0.9941, 0.9951, 0.9953, 1.0004, 0.9926, 0.9952, 0.9949, 1.0042, 0.9928, 1.0004, 0.9931, 1.0077, 0.9907, 1.0020, 0.9844, 0.9999, 0.9869, 0.9818, 0.9952, 0.9878, + 108, 0.9956, 0.9941, 0.9998, 0.9960, 0.9976, 0.9994, 0.9982, 0.9960, 0.9958, 0.9960, 1.0082, 1.0016, 0.9975, 1.0005, 0.9916, 1.0020, 0.9935, 0.9985, 0.9900, 1.0046, 0.9924, 1.0033, 0.9897, 1.0067, 0.9868, 0.9861, 0.9964, 0.9906, + 109, 1.0036, 1.0005, 1.0041, 0.9980, 1.0003, 1.0009, 0.9994, 0.9966, 0.9992, 0.9998, 1.0255, 1.0047, 0.9988, 1.0007, 0.9945, 1.0023, 0.9993, 1.0036, 0.9934, 1.0064, 1.0000, 1.0069, 0.9867, 1.0012, 0.9890, 0.9828, 0.9950, 0.9878, + 110, 0.9969, 0.9957, 0.9959, 0.9927, 0.9962, 1.0005, 0.9995, 0.9967, 0.9939, 0.9943, 1.0273, 1.0039, 0.9897, 0.9917, 0.9926, 1.0020, 0.9942, 1.0001, 0.9874, 1.0021, 0.9981, 1.0076, 0.9869, 1.0050, 0.9846, 0.9810, 0.9922, 0.9873, + 111, 0.9939, 0.9926, 0.9935, 0.9890, 0.9937, 0.9961, 0.9940, 0.9906, 0.9926, 0.9937, 1.0159, 0.9977, 0.9930, 0.9970, 0.9886, 0.9940, 0.9935, 0.9965, 0.9853, 0.9981, 0.9972, 1.0060, 0.9826, 0.9971, 0.9827, 0.9798, 0.9918, 0.9890, + 112, 0.9971, 0.9960, 0.9971, 0.9926, 0.9950, 0.9983, 0.9948, 0.9915, 0.9967, 0.9978, 0.9957, 1.0020, 0.9915, 0.9954, 0.9900, 0.9991, 0.9924, 0.9989, 0.9881, 1.0028, 0.9974, 1.0071, 0.9831, 1.0015, 0.9892, 0.9885, 0.9931, 0.9887, + 113, 0.9965, 0.9948, 0.9973, 0.9936, 0.9960, 0.9986, 0.9977, 0.9950, 0.9946, 0.9957, 0.9909, 0.9957, 0.9949, 0.9976, 0.9909, 0.9997, 0.9943, 0.9986, 0.9891, 1.0030, 0.9899, 1.0015, 0.9847, 1.0004, 0.9840, 0.9788, 0.9918, 0.9881, + 114, 0.9961, 0.9961, 1.0022, 1.0008, 0.9979, 0.9989, 0.9992, 0.9997, 0.9941, 0.9928, 0.9934, 1.0009, 0.9930, 1.0005, 0.9928, 1.0036, 0.9949, 1.0006, 0.9920, 1.0086, 0.9968, 1.0071, 0.9820, 0.9971, 0.9846, 0.9837, 0.9915, 0.9848, + 115, 0.9986, 0.9969, 0.9985, 0.9944, 0.9978, 0.9989, 0.9987, 0.9959, 0.9954, 0.9959, 0.9980, 1.0078, 0.9913, 0.9937, 0.9928, 1.0028, 0.9935, 0.9997, 0.9923, 1.0067, 0.9967, 1.0054, 0.9831, 1.0003, 0.9851, 0.9815, 0.9942, 0.9884, + 116, 0.9999, 0.9987, 1.0011, 0.9967, 0.9993, 1.0003, 0.9988, 0.9962, 0.9986, 0.9978, 0.9955, 1.0019, 0.9961, 1.0009, 0.9918, 1.0029, 0.9966, 1.0031, 0.9909, 1.0056, 0.9939, 1.0031, 0.9860, 1.0017, 0.9905, 0.9914, 0.9965, 0.9917, + 117, 0.9928, 0.9933, 0.9916, 0.9871, 0.9931, 0.9962, 0.9936, 0.9889, 0.9938, 0.9988, 0.9907, 0.9964, 0.9845, 0.9917, 0.9879, 0.9965, 0.9902, 0.9946, 0.9837, 0.9964, 0.9956, 1.0061, 0.9797, 0.9941, 0.9829, 0.9793, 0.9889, 0.9832, + 118, 0.9919, 0.9895, 0.9902, 0.9858, 0.9907, 0.9946, 0.9931, 0.9876, 0.9895, 0.9889, 0.9885, 0.9925, 0.9814, 0.9829, 0.9882, 0.9930, 0.9882, 0.9914, 0.9816, 0.9927, 0.9969, 1.0057, 0.9802, 0.9978, 0.9777, 0.9723, 0.9875, 0.9789, + 119, 0.9871, 0.9861, 0.9957, 0.9920, 0.9925, 0.9963, 0.9948, 0.9936, 0.9885, 0.9884, 0.9890, 0.9944, 0.9896, 0.9978, 0.9891, 0.9966, 0.9887, 0.9939, 0.9846, 0.9993, 0.9952, 1.0060, 0.9798, 0.9951, 0.9799, 0.9771, 0.9879, 0.9818, + 120, 1.0009, 0.9994, 1.0014, 0.9961, 0.9975, 0.9994, 0.9998, 0.9961, 0.9972, 0.9967, 0.9978, 1.0051, 0.9950, 0.9976, 0.9963, 1.0069, 0.9979, 1.0014, 0.9955, 1.0099, 0.9949, 1.0038, 0.9861, 0.9989, 0.9879, 0.9862, 0.9978, 0.9901, + 121, 0.9963, 0.9951, 1.0014, 0.9973, 0.9973, 0.9992, 0.9975, 0.9951, 0.9943, 0.9966, 0.9942, 0.9998, 0.9961, 1.0002, 0.9940, 1.0038, 0.9930, 0.9992, 0.9891, 1.0019, 0.9884, 1.0007, 0.9891, 1.0054, 0.9871, 0.9873, 0.9955, 0.9899, + 122, 1.0017, 1.0016, 1.0048, 1.0007, 1.0014, 1.0028, 1.0000, 0.9980, 1.0000, 0.9997, 0.9946, 1.0005, 1.0008, 1.0058, 0.9964, 1.0064, 1.0009, 1.0063, 0.9927, 1.0071, 0.9970, 1.0061, 0.9855, 1.0003, 0.9888, 0.9879, 0.9962, 0.9893, + 123, 0.9967, 0.9956, 0.9936, 0.9898, 0.9944, 0.9980, 0.9979, 0.9973, 0.9920, 0.9925, 0.9955, 1.0033, 0.9887, 0.9923, 0.9934, 0.9988, 0.9944, 0.9994, 0.9877, 1.0000, 0.9967, 1.0048, 0.9847, 0.9998, 0.9839, 0.9840, 0.9898, 0.9838, + 124, 0.9919, 0.9910, 0.9967, 0.9926, 0.9943, 0.9970, 0.9944, 0.9897, 0.9922, 0.9924, 0.9917, 0.9970, 0.9933, 0.9974, 0.9887, 0.9970, 0.9904, 0.9957, 0.9870, 1.0007, 0.9970, 1.0074, 0.9852, 0.9986, 0.9835, 0.9824, 0.9940, 0.9888, + 125, 0.9959, 0.9943, 0.9962, 0.9913, 0.9941, 0.9974, 0.9948, 0.9923, 0.9938, 0.9944, 0.9921, 0.9985, 0.9888, 0.9931, 0.9917, 1.0008, 0.9892, 0.9952, 0.9895, 1.0028, 0.9963, 1.0050, 0.9838, 1.0005, 0.9882, 0.9860, 0.9955, 0.9916, + 126, 0.9971, 0.9956, 0.9979, 0.9944, 0.9977, 0.9993, 0.9995, 0.9967, 0.9939, 0.9944, 0.9920, 0.9975, 0.9949, 0.9986, 0.9925, 1.0028, 0.9937, 0.9995, 0.9909, 1.0046, 0.9906, 1.0013, 0.9861, 0.9997, 0.9844, 0.9835, 0.9928, 0.9883, + 127, 0.9968, 0.9984, 1.0028, 1.0031, 0.9984, 1.0034, 1.0006, 1.0005, 0.9939, 0.9969, 0.9944, 1.0037, 0.9930, 1.0035, 0.9936, 1.0111, 0.9946, 1.0028, 0.9928, 1.0075, 0.9930, 1.0051, 0.9840, 1.0001, 0.9875, 0.9918, 0.9932, 0.9891, + 128, 1.0008, 1.0012, 1.0015, 0.9973, 0.9999, 1.0029, 0.9997, 0.9985, 0.9971, 0.9988, 0.9988, 1.0094, 0.9945, 0.9979, 0.9950, 1.0059, 0.9963, 1.0047, 0.9948, 1.0101, 0.9943, 1.0042, 0.9852, 1.0011, 0.9896, 0.9908, 0.9958, 0.9904, + 129, 0.9983, 0.9968, 0.9991, 0.9941, 0.9986, 1.0003, 0.9981, 0.9956, 0.9950, 0.9977, 0.9955, 1.0052, 0.9935, 0.9999, 0.9917, 1.0014, 0.9937, 1.0007, 0.9918, 1.0049, 0.9905, 1.0017, 0.9883, 1.0030, 0.9882, 0.9894, 0.9950, 0.9894, + 130, 0.9972, 0.9982, 0.9960, 0.9938, 0.9946, 0.9989, 0.9945, 0.9913, 0.9958, 0.9979, 0.9913, 0.9970, 0.9887, 0.9942, 0.9911, 0.9991, 0.9924, 0.9983, 0.9847, 0.9987, 0.9988, 1.0075, 0.9792, 0.9964, 0.9834, 0.9839, 0.9895, 0.9864, + 131, 0.9893, 0.9886, 0.9896, 0.9865, 0.9904, 0.9943, 0.9919, 0.9883, 0.9886, 0.9878, 0.9872, 0.9926, 0.9802, 0.9835, 0.9884, 0.9914, 0.9868, 0.9881, 0.9816, 0.9928, 0.9967, 1.0064, 0.9839, 0.9997, 0.9765, 0.9713, 0.9851, 0.9813, + 132, 0.9957, 0.9945, 0.9957, 0.9912, 0.9968, 0.9987, 0.9943, 0.9903, 0.9944, 0.9952, 0.9936, 0.9994, 0.9950, 1.0011, 0.9905, 0.9962, 0.9937, 0.9978, 0.9832, 0.9945, 0.9961, 1.0051, 0.9807, 0.9935, 0.9865, 0.9866, 0.9913, 0.9848, + 133, 1.0041, 1.0044, 0.9987, 0.9926, 0.9999, 1.0018, 0.9975, 0.9925, 0.9998, 1.0004, 0.9978, 1.0033, 0.9982, 0.9982, 0.9945, 1.0033, 0.9973, 1.0045, 0.9927, 1.0052, 0.9909, 1.0000, 0.9862, 1.0006, 0.9870, 0.9845, 0.9983, 0.9925, + 134, 0.9989, 0.9979, 1.0022, 0.9985, 1.0007, 1.0024, 1.0001, 0.9987, 0.9972, 0.9981, 0.9923, 1.0000, 1.0003, 1.0059, 0.9964, 1.0036, 0.9976, 1.0026, 0.9914, 1.0043, 0.9900, 1.0004, 0.9917, 1.0055, 0.9896, 0.9901, 0.9962, 0.9923, + 135, 1.0033, 1.0023, 1.0031, 0.9976, 0.9994, 1.0031, 1.0012, 0.9963, 0.9978, 0.9996, 0.9951, 1.0012, 0.9972, 1.0030, 0.9947, 1.0056, 0.9980, 1.0049, 0.9929, 1.0069, 0.9986, 1.0073, 0.9875, 1.0007, 0.9890, 0.9889, 0.9944, 0.9886, + 136, 1.0014, 0.9991, 1.0007, 0.9947, 1.0005, 1.0006, 1.0019, 0.9984, 0.9975, 0.9945, 0.9982, 1.0030, 0.9961, 0.9956, 0.9962, 1.0022, 0.9981, 1.0003, 0.9950, 1.0089, 1.0026, 1.0071, 0.9909, 1.0058, 0.9894, 0.9863, 0.9952, 0.9888, + 137, 0.9976, 0.9963, 0.9996, 0.9942, 0.9940, 0.9977, 0.9955, 0.9924, 0.9939, 0.9948, 0.9925, 0.9986, 0.9942, 0.9986, 0.9925, 0.9989, 0.9903, 0.9967, 0.9870, 0.9983, 0.9958, 1.0067, 0.9817, 0.9987, 0.9816, 0.9800, 0.9931, 0.9884, + 138, 0.9953, 0.9942, 1.0006, 0.9960, 0.9977, 1.0012, 0.9974, 0.9943, 0.9966, 0.9978, 0.9954, 1.0025, 0.9923, 0.9959, 0.9936, 1.0030, 0.9912, 0.9962, 0.9889, 1.0017, 1.0013, 1.0090, 0.9840, 1.0002, 0.9878, 0.9870, 0.9947, 0.9926, + 139, 0.9967, 0.9959, 0.9956, 0.9921, 0.9944, 0.9991, 0.9963, 0.9938, 0.9935, 0.9921, 0.9935, 1.0007, 0.9916, 0.9947, 0.9929, 0.9978, 0.9916, 0.9966, 0.9889, 1.0010, 0.9910, 1.0011, 0.9838, 0.9987, 0.9855, 0.9847, 0.9924, 0.9888, + 140, 0.9996, 0.9999, 0.9988, 0.9959, 1.0002, 1.0031, 0.9998, 0.9979, 0.9971, 0.9977, 0.9935, 0.9990, 0.9989, 1.0057, 0.9930, 1.0039, 0.9981, 1.0054, 0.9910, 1.0061, 0.9961, 1.0068, 0.9875, 1.0005, 0.9911, 0.9937, 0.9899, 0.9850, + 141, 1.0022, 1.0015, 0.9999, 0.9970, 0.9997, 1.0034, 0.9984, 0.9962, 0.9964, 0.9965, 0.9956, 1.0025, 0.9931, 0.9968, 0.9948, 1.0036, 0.9951, 1.0013, 0.9920, 1.0046, 0.9934, 1.0037, 0.9881, 1.0039, 0.9892, 0.9889, 0.9970, 0.9929, + 142, 0.9956, 0.9945, 1.0012, 0.9989, 0.9962, 1.0006, 0.9991, 0.9976, 0.9949, 0.9950, 0.9947, 1.0018, 0.9929, 0.9996, 0.9942, 1.0020, 0.9929, 0.9991, 0.9908, 1.0066, 0.9945, 1.0062, 0.9891, 1.0041, 0.9887, 0.9893, 0.9955, 0.9913, + 143, 0.9941, 0.9916, 0.9943, 0.9884, 0.9928, 0.9971, 0.9943, 0.9908, 0.9932, 0.9948, 0.9930, 1.0003, 0.9852, 0.9910, 0.9911, 0.9983, 0.9899, 0.9950, 0.9854, 0.9970, 1.0019, 1.0097, 0.9808, 0.9963, 0.9827, 0.9834, 0.9931, 0.9871, + 144, 0.9927, 0.9912, 0.9899, 0.9863, 0.9895, 0.9941, 0.9922, 0.9886, 0.9886, 0.9872, 0.9895, 0.9938, 0.9810, 0.9828, 0.9899, 0.9942, 0.9873, 0.9890, 0.9823, 0.9934, 0.9986, 1.0071, 0.9825, 0.9970, 0.9802, 0.9783, 0.9890, 0.9826, + 145, 0.9912, 0.9890, 0.9931, 0.9892, 0.9951, 0.9998, 0.9960, 0.9943, 0.9892, 0.9893, 0.9914, 0.9970, 0.9939, 0.9994, 0.9922, 1.0022, 0.9898, 0.9958, 0.9858, 0.9953, 0.9926, 1.0040, 0.9825, 0.9954, 0.9848, 0.9851, 0.9916, 0.9856, + 146, 1.0031, 1.0016, 1.0039, 0.9985, 1.0003, 1.0020, 1.0004, 0.9964, 0.9985, 0.9968, 0.9994, 1.0155, 0.9973, 0.9980, 0.9971, 1.0058, 0.9975, 1.0046, 0.9961, 1.0176, 0.9920, 1.0034, 0.9879, 1.0023, 0.9908, 0.9896, 1.0027, 0.9964, + 147, 0.9956, 0.9938, 0.9995, 0.9964, 0.9960, 1.0000, 0.9984, 0.9960, 0.9931, 0.9930, 0.9941, 1.0041, 0.9944, 0.9996, 0.9964, 1.0019, 0.9942, 0.9983, 0.9920, 1.0231, 0.9891, 0.9995, 0.9892, 1.0031, 0.9895, 0.9879, 0.9960, 0.9926, + 148, 1.0072, 1.0055, 1.0053, 0.9999, 1.0024, 1.0045, 1.0014, 0.9987, 1.0023, 1.0021, 0.9971, 1.0035, 1.0009, 1.0051, 0.9981, 1.0062, 1.0004, 1.0058, 0.9948, 1.0177, 1.0028, 1.0097, 0.9905, 1.0032, 0.9907, 0.9908, 0.9980, 0.9929, + 149, 0.9980, 0.9961, 1.0002, 0.9948, 0.9982, 1.0034, 1.0014, 0.9986, 0.9928, 0.9920, 0.9962, 1.0041, 0.9911, 0.9934, 0.9951, 1.0009, 0.9942, 0.9966, 0.9923, 1.0053, 0.9946, 1.0052, 0.9881, 1.0040, 0.9854, 0.9823, 0.9922, 0.9871, + 150, 0.9954, 0.9950, 0.9997, 0.9958, 0.9937, 0.9987, 0.9971, 0.9942, 0.9923, 0.9944, 0.9923, 0.9985, 0.9938, 0.9984, 0.9930, 0.9998, 0.9909, 0.9960, 0.9875, 1.0002, 0.9988, 1.0069, 0.9840, 0.9979, 0.9879, 0.9864, 0.9944, 0.9897, + 151, 0.9972, 0.9950, 0.9982, 0.9931, 0.9966, 1.0002, 0.9969, 0.9941, 0.9955, 0.9950, 0.9949, 1.0008, 0.9935, 0.9960, 0.9926, 0.9973, 0.9920, 0.9960, 0.9906, 1.0040, 1.0002, 1.0080, 0.9840, 0.9990, 0.9897, 0.9892, 0.9953, 0.9919, + 152, 0.9978, 0.9955, 0.9986, 0.9948, 0.9969, 1.0014, 0.9987, 0.9955, 0.9943, 0.9935, 0.9936, 1.0017, 0.9943, 0.9980, 0.9936, 1.0020, 0.9953, 1.0007, 0.9915, 1.0048, 0.9945, 1.0039, 0.9865, 1.0007, 0.9878, 0.9885, 0.9932, 0.9900, + 153, 1.0012, 1.0009, 0.9975, 0.9926, 0.9998, 1.0051, 0.9993, 0.9972, 0.9968, 0.9969, 0.9946, 1.0005, 0.9975, 1.0048, 0.9943, 1.0025, 0.9967, 1.0037, 0.9890, 1.0028, 1.0000, 1.0099, 0.9841, 0.9977, 0.9897, 0.9930, 0.9914, 0.9863, + 154, 1.0035, 1.0036, 1.0029, 1.0002, 1.0002, 1.0030, 1.0015, 0.9982, 0.9987, 1.0000, 0.9956, 1.0026, 0.9939, 0.9981, 0.9975, 1.0071, 0.9975, 1.0046, 0.9935, 1.0073, 0.9950, 1.0050, 0.9873, 1.0017, 0.9905, 0.9901, 0.9991, 0.9957, + 155, 0.9981, 0.9966, 1.0031, 0.9989, 0.9967, 0.9994, 0.9994, 0.9982, 0.9950, 0.9940, 0.9934, 0.9986, 0.9924, 0.9990, 0.9938, 1.0038, 0.9932, 0.9981, 0.9908, 1.0056, 0.9897, 1.0019, 0.9886, 1.0030, 0.9897, 0.9917, 0.9962, 0.9919, + 156, 0.9997, 0.9986, 0.9989, 0.9938, 0.9972, 1.0014, 0.9948, 0.9923, 0.9967, 0.9977, 0.9932, 1.0017, 0.9875, 0.9936, 0.9927, 1.0017, 0.9946, 1.0005, 0.9875, 1.0001, 1.0027, 1.0091, 0.9830, 0.9966, 0.9878, 0.9899, 0.9953, 0.9947, + 157, 0.9959, 0.9956, 0.9911, 0.9873, 0.9925, 0.9977, 0.9935, 0.9902, 0.9905, 0.9909, 0.9914, 0.9967, 0.9812, 0.9842, 0.9908, 1.0054, 0.9888, 0.9917, 0.9850, 0.9956, 0.9954, 1.0053, 0.9800, 0.9959, 0.9775, 0.9731, 0.9882, 0.9850, + 158, 0.9906, 0.9898, 0.9972, 0.9924, 0.9940, 0.9989, 0.9953, 0.9935, 0.9908, 0.9932, 0.9933, 0.9991, 0.9948, 1.0008, 0.9910, 1.0033, 0.9908, 0.9968, 0.9851, 0.9978, 0.9930, 1.0040, 0.9831, 0.9945, 0.9869, 0.9866, 0.9865, 0.9808, + 159, 1.0045, 1.0047, 1.0034, 0.9971, 1.0015, 1.0052, 1.0003, 0.9972, 0.9995, 0.9995, 0.9954, 1.0027, 0.9964, 0.9986, 0.9988, 1.0082, 0.9977, 1.0043, 0.9957, 1.0092, 0.9914, 1.0005, 0.9894, 1.0003, 0.9902, 0.9899, 1.0010, 0.9959, + 160, 1.0030, 1.0024, 1.0054, 1.0018, 1.0022, 1.0041, 1.0014, 1.0011, 0.9995, 1.0006, 0.9949, 1.0015, 1.0023, 1.0068, 0.9968, 1.0074, 0.9995, 1.0055, 0.9937, 1.0087, 0.9884, 0.9997, 0.9918, 1.0073, 0.9924, 0.9923, 0.9996, 0.9933, + 161, 1.0046, 1.0058, 1.0078, 1.0042, 1.0023, 1.0042, 1.0018, 1.0000, 1.0004, 1.0001, 1.0008, 1.0108, 0.9994, 1.0056, 0.9966, 1.0071, 0.9995, 1.0056, 0.9959, 1.0096, 1.0001, 1.0087, 0.9930, 1.0025, 0.9900, 0.9903, 0.9984, 0.9954, + 162, 1.0019, 0.9994, 1.0033, 0.9983, 1.0009, 1.0040, 1.0011, 0.9996, 0.9969, 0.9938, 1.0011, 1.0153, 0.9895, 0.9930, 0.9977, 1.0053, 0.9959, 1.0004, 0.9956, 1.0071, 1.0013, 1.0081, 0.9916, 1.0047, 0.9924, 0.9910, 0.9965, 0.9906, + 163, 0.9955, 0.9947, 0.9973, 0.9914, 0.9939, 0.9988, 0.9946, 0.9914, 0.9935, 0.9940, 0.9932, 0.9972, 0.9941, 0.9981, 0.9913, 0.9984, 0.9927, 0.9969, 0.9864, 0.9998, 0.9956, 1.0045, 0.9859, 0.9987, 0.9883, 0.9892, 0.9958, 0.9911, + 164, 0.9991, 0.9984, 1.0025, 0.9983, 1.0005, 1.0032, 1.0006, 0.9983, 0.9985, 0.9992, 0.9917, 0.9957, 0.9954, 0.9994, 0.9963, 1.0057, 0.9939, 0.9991, 0.9978, 1.0081, 1.0012, 1.0078, 0.9885, 1.0026, 0.9937, 0.9934, 0.9969, 0.9941, + 165, 0.9979, 0.9959, 1.0016, 0.9982, 0.9982, 1.0018, 0.9991, 0.9972, 0.9950, 0.9938, 0.9977, 1.0054, 0.9959, 1.0010, 0.9950, 1.0025, 0.9928, 0.9969, 0.9927, 1.0058, 0.9941, 1.0043, 0.9890, 1.0049, 0.9870, 0.9882, 0.9955, 0.9915, + 166, 1.0014, 1.0018, 0.9987, 0.9958, 0.9998, 1.0044, 0.9984, 0.9963, 0.9965, 0.9973, 0.9983, 1.0056, 0.9972, 1.0046, 0.9940, 1.0021, 0.9963, 1.0021, 0.9901, 1.0045, 1.0009, 1.0102, 0.9884, 0.9994, 0.9907, 0.9945, 0.9931, 0.9880, + 167, 1.0023, 1.0019, 1.0012, 0.9961, 0.9987, 1.0022, 0.9995, 0.9974, 0.9974, 0.9966, 0.9980, 1.0058, 0.9929, 0.9957, 0.9968, 1.0057, 0.9972, 1.0014, 0.9930, 1.0059, 0.9970, 1.0049, 0.9881, 1.0016, 0.9923, 0.9927, 0.9987, 0.9937, + 168, 1.0036, 1.0042, 1.0029, 0.9995, 1.0014, 1.0043, 1.0001, 0.9988, 1.0010, 1.0006, 0.9950, 1.0012, 0.9982, 1.0050, 0.9943, 1.0041, 0.9989, 1.0047, 0.9933, 1.0075, 0.9941, 1.0031, 0.9929, 1.0057, 0.9942, 0.9975, 0.9986, 0.9946, + 169, 1.0007, 1.0004, 0.9959, 0.9908, 0.9979, 1.0010, 0.9939, 0.9894, 0.9976, 0.9995, 0.9927, 0.9966, 0.9898, 0.9946, 0.9938, 0.9984, 0.9953, 0.9998, 0.9864, 0.9982, 1.0007, 1.0102, 0.9815, 0.9961, 0.9872, 0.9908, 0.9940, 0.9907, + 170, 0.9958, 0.9940, 0.9921, 0.9878, 0.9934, 0.9984, 0.9938, 0.9905, 0.9913, 0.9909, 0.9914, 0.9966, 0.9843, 0.9856, 0.9902, 0.9936, 0.9893, 0.9915, 0.9850, 0.9977, 1.0038, 1.0103, 0.9829, 0.9950, 0.9808, 0.9804, 0.9898, 0.9855, + 171, 0.9919, 0.9927, 0.9954, 0.9924, 0.9954, 0.9996, 0.9961, 0.9941, 0.9906, 0.9913, 0.9932, 0.9986, 0.9932, 0.9992, 0.9920, 0.9991, 0.9911, 0.9945, 0.9860, 0.9975, 0.9954, 1.0056, 0.9831, 0.9949, 0.9851, 0.9859, 0.9880, 0.9822, + 172, 1.0081, 1.0087, 1.0057, 0.9993, 1.0007, 1.0051, 1.0005, 0.9984, 1.0007, 0.9998, 0.9984, 1.0044, 0.9984, 1.0005, 0.9984, 1.0093, 1.0002, 1.0064, 0.9980, 1.0118, 0.9954, 1.0042, 0.9909, 1.0033, 0.9931, 0.9934, 1.0009, 0.9979, + 173, 1.0010, 1.0028, 1.0041, 1.0008, 1.0007, 1.0051, 1.0011, 0.9994, 0.9969, 0.9984, 0.9978, 1.0046, 1.0017, 1.0041, 0.9963, 1.0057, 0.9963, 1.0040, 0.9946, 1.0089, 0.9884, 1.0009, 0.9908, 1.0034, 0.9927, 0.9950, 0.9953, 0.9909, + 174, 1.0045, 1.0075, 1.0036, 0.9999, 1.0018, 1.0052, 1.0005, 0.9972, 1.0010, 1.0003, 1.0024, 1.0111, 1.0000, 1.0050, 0.9957, 1.0045, 1.0009, 1.0076, 0.9934, 1.0103, 1.0016, 1.0104, 0.9883, 1.0013, 0.9926, 0.9958, 0.9979, 0.9930, + 175, 0.9997, 0.9985, 0.9986, 0.9946, 0.9962, 1.0014, 0.9977, 0.9958, 0.9934, 0.9922, 0.9945, 1.0017, 0.9883, 0.9910, 0.9946, 1.0021, 0.9936, 0.9973, 0.9880, 1.0006, 1.0013, 1.0080, 0.9869, 0.9999, 0.9898, 0.9884, 0.9946, 0.9906, + 176, 0.9954, 0.9972, 0.9987, 0.9937, 0.9958, 1.0004, 0.9974, 0.9940, 0.9950, 0.9970, 0.9916, 0.9940, 0.9960, 1.0001, 0.9923, 0.9997, 0.9949, 0.9976, 0.9891, 1.0022, 1.0036, 1.0127, 0.9890, 1.0008, 0.9889, 0.9895, 0.9975, 0.9923, + 177, 0.9998, 1.0002, 0.9987, 0.9945, 0.9960, 1.0010, 0.9969, 0.9947, 0.9953, 0.9980, 0.9934, 0.9984, 0.9899, 0.9943, 0.9935, 1.0016, 0.9914, 0.9968, 0.9899, 1.0047, 1.0005, 1.0083, 0.9861, 1.0009, 0.9907, 0.9909, 0.9963, 0.9937, + 178, 0.9981, 0.9979, 1.0024, 1.0000, 0.9980, 1.0020, 1.0002, 0.9993, 0.9954, 0.9967, 0.9962, 1.0021, 0.9961, 0.9995, 0.9951, 1.0033, 0.9950, 1.0004, 0.9922, 1.0059, 0.9954, 1.0055, 0.9886, 1.0020, 0.9916, 0.9915, 0.9938, 0.9913, + 179, 1.0050, 1.0061, 1.0007, 0.9976, 0.9981, 1.0028, 0.9988, 0.9952, 0.9973, 0.9982, 0.9976, 1.0054, 0.9932, 1.0001, 0.9939, 1.0030, 0.9962, 1.0071, 0.9900, 1.0055, 0.9985, 1.0082, 0.9889, 1.0018, 0.9921, 0.9948, 0.9950, 0.9905, + 180, 1.0088, 1.0122, 1.0039, 1.0010, 1.0026, 1.0071, 1.0021, 1.0026, 1.0006, 1.0037, 0.9967, 1.0039, 0.9989, 1.0031, 0.9990, 1.0096, 1.0024, 1.0096, 0.9946, 1.0099, 0.9996, 1.0113, 0.9918, 1.0059, 0.9937, 0.9951, 1.0006, 0.9987, + 181, 0.9992, 1.0004, 1.0048, 1.0003, 0.9987, 1.0034, 1.0039, 1.0020, 0.9982, 0.9995, 0.9945, 1.0007, 0.9957, 1.0027, 0.9975, 1.0076, 0.9957, 1.0022, 0.9944, 1.0081, 0.9927, 1.0037, 0.9935, 1.0072, 0.9917, 0.9936, 0.9955, 0.9913, + 182, 0.9981, 0.9986, 0.9992, 0.9957, 0.9950, 0.9993, 0.9939, 0.9923, 0.9966, 0.9987, 0.9976, 1.0036, 0.9862, 0.9921, 0.9936, 0.9999, 0.9927, 0.9969, 0.9877, 1.0020, 1.0020, 1.0081, 0.9848, 1.0002, 0.9890, 0.9897, 0.9943, 0.9921, + 183, 0.9920, 0.9924, 0.9940, 0.9902, 0.9909, 0.9961, 0.9940, 0.9906, 0.9897, 0.9901, 0.9936, 0.9997, 0.9805, 0.9817, 0.9928, 0.9964, 0.9879, 0.9885, 0.9829, 0.9942, 0.9981, 1.0061, 0.9813, 0.9942, 0.9828, 0.9785, 0.9910, 0.9859, + 184, 0.9943, 0.9946, 0.9984, 0.9940, 0.9970, 1.0010, 0.9958, 0.9960, 0.9927, 0.9947, 0.9950, 0.9993, 0.9967, 1.0024, 0.9979, 0.9986, 0.9939, 0.9993, 0.9871, 0.9986, 0.9965, 1.0065, 0.9858, 0.9975, 0.9888, 0.9917, 0.9871, 0.9828, + 185, 1.0054, 1.0050, 1.0036, 0.9988, 0.9991, 1.0021, 1.0002, 0.9968, 0.9995, 1.0023, 0.9992, 1.0059, 0.9963, 0.9977, 0.9995, 1.0065, 0.9961, 1.0011, 0.9969, 1.0103, 0.9923, 1.0021, 0.9905, 1.0049, 0.9950, 0.9924, 1.0022, 0.9971, + 186, 0.9994, 0.9988, 1.0043, 1.0012, 1.0009, 1.0039, 1.0016, 1.0005, 0.9991, 0.9997, 0.9966, 1.0013, 1.0015, 1.0046, 0.9975, 1.0064, 0.9976, 1.0026, 0.9945, 1.0074, 0.9888, 0.9993, 0.9931, 1.0056, 0.9952, 0.9975, 0.9960, 0.9919, + 187, 1.0037, 1.0046, 1.0052, 1.0009, 1.0008, 1.0042, 1.0013, 0.9992, 0.9999, 1.0022, 0.9993, 1.0055, 0.9986, 1.0028, 0.9977, 1.0069, 0.9991, 1.0041, 0.9948, 1.0066, 1.0007, 1.0074, 0.9911, 1.0021, 0.9928, 0.9930, 0.9987, 0.9942, + 188, 0.9997, 1.0007, 1.0019, 0.9978, 0.9972, 1.0024, 1.0005, 0.9978, 0.9953, 0.9963, 0.9975, 1.0037, 0.9919, 0.9950, 0.9967, 1.0042, 0.9974, 1.0008, 0.9903, 1.0027, 1.0012, 1.0074, 0.9877, 1.0003, 0.9882, 0.9854, 0.9950, 0.9916, + 189, 0.9962, 0.9945, 0.9976, 0.9930, 0.9951, 0.9974, 0.9972, 0.9935, 0.9945, 0.9931, 0.9973, 1.0015, 0.9944, 0.9961, 0.9946, 0.9955, 0.9929, 0.9949, 0.9894, 1.0016, 1.0035, 1.0103, 0.9895, 0.9998, 0.9899, 0.9885, 0.9960, 0.9906, + 190, 0.9976, 0.9992, 0.9987, 0.9952, 0.9962, 1.0013, 0.9963, 0.9937, 0.9974, 1.0001, 0.9955, 1.0009, 0.9925, 0.9951, 0.9954, 1.0009, 0.9922, 0.9978, 0.9890, 1.0014, 0.9992, 1.0084, 0.9848, 0.9997, 0.9948, 0.9961, 0.9959, 0.9937, + 191, 0.9996, 1.0014, 1.0005, 0.9973, 0.9995, 1.0039, 0.9976, 0.9980, 0.9967, 0.9996, 0.9928, 0.9984, 0.9982, 1.0011, 0.9951, 1.0019, 0.9955, 1.0021, 0.9914, 1.0043, 0.9943, 1.0023, 0.9886, 1.0009, 0.9923, 0.9933, 0.9926, 0.9901, + 192, 1.0031, 1.0035, 1.0057, 1.0028, 1.0022, 1.0062, 1.0017, 1.0021, 0.9989, 1.0016, 0.9965, 1.0030, 0.9993, 1.0059, 0.9967, 1.0045, 0.9985, 1.0058, 0.9929, 1.0056, 0.9993, 1.0086, 0.9872, 1.0006, 0.9948, 0.9986, 0.9920, 0.9894, + 193, 1.0014, 1.0034, 1.0039, 0.9999, 0.9990, 1.0042, 1.0011, 0.9985, 0.9961, 1.0001, 0.9991, 1.0077, 0.9955, 0.9985, 0.9991, 1.0081, 0.9972, 1.0012, 0.9970, 1.0092, 0.9986, 1.0072, 0.9896, 1.0038, 0.9958, 0.9954, 0.9975, 0.9970, + 194, 0.9999, 1.0006, 1.0025, 0.9992, 0.9988, 1.0025, 1.0017, 1.0002, 0.9974, 1.0022, 0.9976, 1.0071, 0.9950, 1.0022, 0.9963, 1.0057, 0.9963, 1.0015, 0.9939, 1.0077, 0.9966, 1.0040, 0.9897, 1.0033, 0.9950, 0.9964, 0.9964, 0.9946, + 195, 0.9957, 0.9977, 0.9982, 0.9957, 0.9956, 0.9995, 0.9940, 0.9909, 0.9951, 0.9996, 0.9932, 0.9974, 0.9863, 0.9908, 0.9929, 0.9983, 0.9906, 0.9949, 0.9854, 0.9948, 0.9990, 1.0076, 0.9828, 0.9971, 0.9869, 0.9879, 0.9936, 0.9922, + 196, 0.9964, 0.9986, 0.9943, 0.9905, 0.9933, 0.9987, 0.9952, 0.9923, 0.9923, 0.9949, 0.9898, 0.9957, 0.9843, 0.9874, 0.9920, 0.9968, 0.9909, 0.9931, 0.9851, 0.9956, 0.9995, 1.0093, 0.9824, 0.9950, 0.9867, 0.9839, 0.9903, 0.9875, + 197, 0.9945, 0.9952, 0.9989, 0.9939, 0.9966, 1.0009, 0.9964, 0.9937, 0.9928, 0.9989, 0.9953, 0.9998, 0.9958, 1.0019, 0.9929, 0.9978, 0.9929, 0.9966, 0.9863, 0.9959, 0.9977, 1.0068, 0.9843, 0.9964, 0.9901, 0.9921, 0.9873, 0.9823, + 198, 1.0013, 1.0022, 1.0029, 0.9990, 0.9971, 1.0013, 1.0002, 0.9979, 0.9988, 1.0019, 0.9988, 1.0051, 0.9969, 0.9985, 0.9994, 1.0065, 0.9972, 1.0014, 0.9965, 1.0095, 0.9952, 1.0042, 0.9903, 1.0028, 0.9960, 0.9930, 1.0020, 1.0006, + 199, 0.9961, 0.9967, 1.0046, 1.0004, 0.9995, 1.0032, 1.0006, 0.9997, 0.9962, 1.0005, 0.9951, 1.0012, 0.9998, 1.0045, 0.9961, 1.0049, 0.9954, 1.0002, 0.9936, 1.0057, 0.9932, 1.0024, 0.9931, 1.0064, 0.9944, 0.9951, 0.9972, 0.9938, + 200, 1.0064, 1.0069, 1.0070, 1.0035, 1.0020, 1.0044, 1.0030, 1.0003, 1.0001, 1.0038, 0.9978, 1.0010, 1.0010, 1.0061, 0.9983, 1.0075, 1.0012, 1.0058, 0.9963, 1.0086, 1.0050, 1.0100, 0.9931, 1.0055, 0.9961, 0.9960, 1.0003, 0.9975, + 201, 1.0011, 1.0002, 1.0029, 0.9994, 0.9972, 1.0030, 1.0005, 0.9984, 0.9963, 0.9977, 0.9982, 1.0053, 0.9961, 0.9920, 0.9985, 1.0049, 0.9949, 0.9989, 0.9922, 1.0032, 1.0013, 1.0098, 0.9917, 1.0072, 0.9932, 0.9920, 0.9969, 0.9944, + 202, 0.9986, 0.9986, 0.9992, 0.9940, 0.9954, 1.0002, 0.9976, 0.9944, 0.9963, 0.9995, 0.9962, 1.0006, 1.0049, 1.0018, 0.9955, 1.0002, 0.9961, 0.9994, 0.9918, 1.0037, 1.0040, 1.0120, 0.9884, 1.0037, 0.9915, 0.9924, 0.9962, 0.9916, + 203, 0.9998, 0.9999, 0.9991, 0.9954, 0.9977, 1.0013, 0.9966, 0.9928, 0.9989, 1.0017, 0.9939, 0.9985, 0.9929, 0.9947, 0.9954, 1.0016, 0.9945, 0.9960, 0.9897, 0.9999, 1.0015, 1.0073, 0.9854, 1.0012, 0.9937, 0.9938, 0.9972, 0.9947, + 204, 1.0011, 0.9996, 1.0014, 0.9959, 0.9993, 1.0025, 0.9994, 0.9968, 0.9975, 1.0001, 0.9942, 0.9994, 0.9988, 1.0021, 0.9947, 1.0018, 0.9976, 1.0009, 0.9912, 1.0012, 0.9951, 1.0039, 0.9889, 1.0015, 0.9901, 0.9905, 0.9957, 0.9922, + 205, 0.9983, 0.9989, 1.0000, 0.9974, 0.9978, 1.0030, 0.9995, 0.9985, 0.9959, 0.9969, 0.9949, 0.9995, 0.9955, 1.0020, 0.9942, 1.0004, 0.9950, 0.9988, 0.9913, 1.0045, 0.9975, 1.0049, 0.9859, 0.9988, 0.9937, 0.9959, 0.9917, 0.9882, + 206, 1.0026, 1.0026, 1.0013, 0.9961, 0.9993, 1.0024, 1.0002, 0.9965, 0.9980, 1.0002, 0.9979, 1.0035, 0.9940, 0.9980, 0.9970, 1.0052, 0.9972, 1.0014, 0.9944, 1.0070, 0.9958, 1.0050, 0.9897, 1.0052, 0.9931, 0.9941, 0.9991, 0.9957, + 207, 1.0013, 1.0048, 1.0027, 1.0009, 0.9988, 1.0044, 0.9992, 0.9992, 0.9969, 1.0027, 0.9923, 0.9991, 0.9950, 1.0019, 0.9943, 1.0060, 0.9966, 1.0009, 0.9936, 1.0083, 0.9934, 1.0051, 0.9914, 1.0078, 0.9939, 0.9986, 0.9972, 0.9942, + 208, 0.9985, 0.9979, 1.0003, 0.9974, 0.9954, 1.0002, 0.9949, 0.9930, 0.9970, 0.9999, 0.9943, 0.9993, 0.9910, 0.9939, 0.9930, 0.9996, 0.9924, 0.9969, 0.9890, 0.9993, 1.0027, 1.0104, 0.9826, 0.9976, 0.9905, 0.9908, 0.9958, 0.9929, + 209, 0.9877, 0.9863, 0.9898, 0.9839, 0.9878, 0.9939, 0.9929, 0.9892, 0.9866, 0.9878, 0.9894, 0.9945, 0.9786, 0.9825, 0.9901, 0.9927, 0.9841, 0.9859, 0.9827, 0.9933, 1.0020, 1.0092, 0.9801, 0.9933, 0.9846, 0.9804, 0.9879, 0.9881, + 210, 0.9918, 0.9926, 0.9960, 0.9924, 0.9965, 1.0016, 0.9966, 0.9946, 0.9935, 0.9969, 0.9911, 0.9946, 0.9960, 1.0015, 0.9930, 0.9983, 0.9924, 0.9946, 0.9886, 1.0013, 0.9975, 1.0057, 0.9851, 0.9983, 0.9892, 0.9894, 0.9876, 0.9839, + 211, 1.0002, 1.0012, 1.0038, 0.9983, 0.9974, 1.0016, 0.9990, 0.9976, 0.9969, 1.0000, 0.9938, 0.9991, 0.9963, 0.9972, 0.9978, 1.0055, 0.9966, 1.0005, 0.9976, 1.0103, 0.9935, 1.0034, 0.9909, 1.0028, 0.9933, 0.9915, 1.0016, 0.9993, + 212, 1.0020, 1.0017, 1.0055, 1.0014, 1.0008, 1.0045, 1.0011, 0.9996, 0.9983, 0.9995, 0.9968, 1.0033, 1.0020, 1.0055, 0.9963, 1.0047, 0.9998, 1.0036, 0.9962, 1.0088, 0.9949, 1.0057, 0.9930, 1.0070, 0.9973, 0.9992, 0.9979, 0.9963, + 213, 1.0052, 1.0056, 1.0026, 0.9987, 1.0003, 1.0044, 1.0003, 0.9960, 1.0004, 1.0013, 1.0013, 1.0074, 0.9989, 1.0040, 0.9944, 1.0046, 1.0006, 1.0047, 0.9953, 1.0084, 1.0041, 1.0097, 0.9896, 1.0008, 0.9958, 0.9983, 0.9986, 0.9965, + 214, 1.0074, 1.0011, 1.0011, 0.9962, 0.9987, 1.0027, 1.0006, 0.9976, 0.9964, 0.9975, 0.9950, 0.9987, 0.9925, 0.9955, 0.9956, 1.0054, 0.9974, 1.0014, 0.9924, 1.0030, 1.0018, 1.0090, 0.9881, 1.0018, 0.9931, 0.9929, 0.9944, 0.9931, + 215, 0.9979, 0.9988, 1.0003, 0.9955, 0.9968, 1.0012, 0.9981, 0.9950, 0.9967, 0.9988, 0.9921, 0.9942, 0.9983, 1.0011, 0.9933, 0.9986, 0.9963, 1.0017, 0.9928, 1.0036, 1.0019, 1.0068, 0.9899, 1.0020, 0.9930, 0.9917, 0.9966, 0.9936, + 216, 0.9992, 0.9978, 1.0037, 0.9995, 0.9986, 1.0018, 1.0002, 0.9970, 0.9991, 1.0001, 0.9959, 1.0009, 0.9943, 0.9977, 0.9974, 1.0051, 0.9946, 0.9979, 0.9955, 1.0078, 1.0017, 1.0082, 0.9888, 1.0031, 0.9971, 0.9971, 0.9963, 0.9955, + 217, 0.9980, 0.9983, 1.0014, 0.9981, 0.9983, 1.0015, 0.9998, 0.9976, 0.9937, 0.9953, 0.9974, 1.0037, 0.9979, 0.9986, 0.9964, 1.0016, 0.9949, 0.9967, 0.9955, 1.0078, 0.9969, 1.0052, 0.9853, 0.9987, 0.9919, 0.9906, 0.9943, 0.9901, + 218, 0.9998, 1.0001, 1.0006, 0.9980, 1.0002, 1.0037, 1.0002, 1.0001, 0.9986, 0.9995, 0.9978, 1.0040, 0.9971, 1.0044, 0.9949, 1.0030, 0.9973, 1.0008, 0.9952, 1.0063, 0.9994, 1.0078, 0.9864, 0.9995, 0.9965, 0.9983, 0.9911, 0.9861, + 219, 1.0027, 1.0024, 1.0044, 1.0012, 1.0002, 1.0032, 1.0013, 0.9996, 0.9986, 1.0004, 0.9961, 1.0007, 0.9948, 0.9976, 0.9985, 1.0067, 0.9989, 1.0012, 0.9979, 1.0117, 0.9955, 1.0035, 0.9892, 1.0040, 0.9970, 0.9977, 0.9986, 0.9974, + 220, 0.9996, 0.9995, 1.0046, 1.0011, 1.0006, 1.0025, 1.0034, 1.0010, 0.9993, 1.0003, 0.9958, 1.0006, 0.9974, 1.0020, 0.9980, 1.0067, 0.9981, 1.0001, 0.9963, 1.0082, 0.9938, 1.0040, 0.9926, 1.0055, 0.9972, 0.9987, 0.9976, 0.9938, + 221, 0.9907, 0.9901, 0.9943, 0.9893, 0.9938, 0.9986, 0.9952, 0.9931, 0.9942, 0.9986, 0.9954, 1.0016, 0.9884, 0.9918, 0.9907, 0.9967, 0.9909, 0.9924, 0.9900, 1.0032, 1.0011, 1.0079, 0.9803, 0.9939, 0.9912, 0.9904, 0.9918, 0.9901, + 222, 0.9910, 0.9906, 0.9906, 0.9861, 0.9887, 0.9933, 0.9922, 0.9875, 0.9890, 0.9891, 0.9905, 0.9940, 0.9823, 0.9839, 0.9902, 0.9935, 0.9879, 0.9872, 0.9870, 0.9953, 1.0037, 1.0087, 0.9827, 0.9933, 0.9834, 0.9781, 0.9902, 0.9908, + 223, 0.9942, 0.9944, 0.9954, 0.9922, 0.9989, 1.0008, 0.9959, 0.9944, 0.9944, 0.9976, 0.9900, 0.9910, 0.9972, 1.0019, 0.9922, 0.9983, 0.9923, 0.9955, 0.9903, 1.0017, 0.9966, 1.0061, 0.9844, 0.9978, 0.9901, 0.9902, 0.9884, 0.9844, + 224, 1.0032, 1.0040, 1.0074, 1.0021, 1.0005, 1.0037, 1.0016, 0.9982, 0.9994, 1.0010, 0.9988, 1.0059, 0.9992, 1.0014, 0.9995, 1.0091, 0.9998, 1.0039, 0.9999, 1.0133, 0.9931, 1.0018, 0.9921, 1.0045, 0.9976, 0.9975, 0.9998, 0.9997, + 225, 0.9999, 1.0002, 1.0037, 1.0010, 1.0007, 1.0046, 1.0004, 0.9993, 0.9973, 1.0007, 0.9997, 1.0054, 1.0032, 1.0052, 0.9966, 1.0039, 0.9986, 1.0016, 0.9953, 1.0079, 0.9890, 0.9991, 0.9923, 1.0076, 0.9975, 0.9961, 0.9949, 0.9948, + 226, 1.0055, 1.0080, 1.0050, 1.0025, 1.0018, 1.0055, 1.0013, 0.9993, 1.0016, 1.0047, 1.0002, 1.0076, 1.0014, 1.0059, 0.9959, 1.0054, 1.0017, 1.0076, 0.9963, 1.0091, 1.0058, 1.0116, 0.9911, 1.0040, 0.9964, 0.9959, 0.9983, 0.9990, + 227, 0.9983, 0.9983, 0.9988, 0.9951, 0.9965, 1.0008, 0.9981, 0.9957, 0.9937, 0.9946, 0.9947, 1.0002, 0.9885, 0.9908, 0.9942, 1.0021, 0.9947, 0.9958, 0.9916, 1.0035, 1.0013, 1.0071, 0.9863, 1.0016, 0.9927, 0.9923, 0.9945, 0.9936, + 228, 0.9982, 0.9989, 1.0017, 0.9977, 0.9959, 1.0001, 0.9985, 0.9978, 0.9968, 0.9985, 0.9914, 0.9952, 0.9963, 1.0011, 0.9935, 1.0005, 0.9955, 1.0006, 0.9933, 1.0051, 1.0036, 1.0093, 0.9886, 1.0025, 0.9946, 0.9948, 0.9973, 0.9962, + 229, 0.9943, 0.9955, 1.0016, 0.9979, 0.9948, 0.9987, 0.9969, 0.9951, 0.9944, 0.9951, 0.9975, 1.0038, 0.9916, 0.9935, 0.9954, 1.0031, 0.9920, 0.9921, 0.9932, 1.0043, 1.0016, 1.0066, 0.9850, 1.0002, 0.9963, 0.9990, 0.9943, 0.9948, + 230, 0.9979, 0.9983, 1.0011, 0.9974, 0.9974, 1.0007, 0.9983, 0.9972, 0.9960, 0.9964, 0.9974, 1.0032, 0.9962, 0.9989, 0.9957, 1.0021, 0.9949, 0.9966, 0.9956, 1.0076, 0.9954, 1.0035, 0.9868, 1.0001, 0.9964, 0.9952, 0.9935, 0.9953, + 231, 0.9990, 1.0011, 1.0007, 0.9973, 0.9997, 1.0033, 0.9989, 0.9972, 0.9994, 1.0044, 0.9933, 0.9965, 1.0001, 1.0039, 0.9957, 1.0030, 0.9975, 1.0013, 0.9935, 1.0057, 0.9994, 1.0069, 0.9859, 1.0001, 0.9953, 0.9955, 0.9922, 0.9888, + 232, 1.0014, 1.0022, 1.0068, 1.0038, 1.0003, 1.0030, 1.0010, 1.0014, 0.9989, 1.0016, 0.9964, 1.0023, 0.9966, 1.0001, 1.0001, 1.0098, 1.0036, 1.0032, 1.0000, 1.0116, 1.0015, 1.0074, 0.9893, 1.0048, 0.9985, 0.9973, 0.9992, 0.9974, + 233, 0.9974, 1.0004, 1.0041, 1.0008, 0.9990, 1.0022, 1.0003, 1.0012, 0.9972, 1.0009, 0.9976, 1.0048, 0.9954, 1.0015, 0.9966, 1.0048, 0.9978, 1.0005, 0.9974, 1.0106, 0.9991, 1.0056, 0.9918, 1.0050, 0.9997, 0.9999, 0.9980, 0.9968, + 234, 0.9975, 0.9993, 1.0018, 0.9976, 0.9970, 1.0008, 0.9973, 0.9952, 0.9982, 1.0038, 0.9949, 0.9999, 0.9909, 0.9965, 0.9928, 1.0010, 0.9945, 0.9974, 0.9929, 1.0043, 1.0040, 1.0104, 0.9853, 1.0006, 0.9942, 0.9955, 0.9955, 0.9964, + 235, 0.9901, 0.9908, 0.9897, 0.9869, 0.9899, 0.9937, 0.9941, 0.9906, 0.9901, 0.9911, 0.9913, 0.9946, 0.9838, 0.9869, 0.9907, 0.9918, 0.9886, 0.9877, 0.9890, 0.9987, 1.0054, 1.0114, 0.9851, 0.9993, 0.9866, 0.9832, 0.9908, 0.9913, + 236, 0.9962, 0.9979, 0.9964, 0.9923, 0.9975, 0.9994, 0.9940, 0.9922, 0.9953, 0.9996, 0.9921, 0.9957, 0.9982, 1.0024, 0.9929, 0.9976, 0.9946, 0.9948, 0.9884, 0.9989, 1.0023, 1.0076, 0.9871, 0.9992, 0.9945, 0.9933, 0.9902, 0.9891, + 237, 1.0041, 1.0056, 1.0054, 0.9999, 1.0006, 1.0018, 0.9999, 0.9965, 1.0012, 1.0015, 0.9987, 1.0029, 0.9994, 0.9990, 0.9985, 1.0050, 0.9983, 1.0017, 0.9984, 1.0106, 0.9949, 1.0004, 0.9892, 1.0009, 0.9991, 0.9972, 0.9997, 0.9996, + 238, 0.9990, 0.9987, 1.0044, 0.9992, 1.0016, 1.0020, 1.0013, 0.9998, 0.9981, 1.0011, 0.9954, 0.9992, 1.0031, 1.0061, 0.9960, 1.0058, 1.0004, 1.0034, 0.9967, 1.0094, 0.9914, 1.0000, 0.9928, 1.0058, 0.9955, 0.9949, 0.9983, 0.9982, + 239, 1.0030, 1.0042, 1.0075, 1.0040, 1.0011, 1.0028, 1.0012, 1.0006, 1.0001, 1.0020, 0.9993, 1.0055, 1.0011, 1.0047, 0.9985, 1.0060, 1.0000, 1.0041, 0.9991, 1.0123, 1.0073, 1.0102, 0.9913, 1.0025, 0.9965, 0.9947, 0.9983, 0.9989, + 240, 1.0027, 1.0019, 1.0027, 0.9980, 0.9990, 1.0009, 1.0002, 0.9989, 0.9973, 0.9982, 0.9971, 1.0020, 0.9904, 0.9931, 0.9970, 1.0045, 0.9976, 0.9984, 0.9932, 1.0019, 1.0038, 1.0077, 0.9868, 1.0031, 0.9946, 0.9911, 0.9946, 0.9954, + 241, 0.9960, 0.9967, 0.9989, 0.9948, 0.9923, 0.9952, 0.9963, 0.9951, 0.9945, 0.9985, 0.9945, 0.9986, 0.9977, 0.9999, 0.9924, 0.9984, 0.9937, 0.9952, 0.9909, 1.0034, 1.0008, 1.0054, 0.9875, 0.9989, 0.9931, 0.9913, 0.9953, 0.9958, + 242, 1.0002, 1.0007, 1.0011, 0.9976, 0.9999, 1.0005, 0.9971, 0.9942, 0.9981, 1.0021, 0.9953, 0.9986, 0.9958, 0.9968, 0.9956, 1.0036, 0.9954, 0.9979, 0.9933, 1.0034, 1.0024, 1.0063, 0.9884, 1.0037, 0.9991, 0.9969, 0.9972, 0.9997, + 243, 0.9996, 0.9995, 0.9994, 0.9943, 1.0002, 1.0008, 0.9965, 0.9965, 0.9964, 0.9985, 0.9923, 0.9967, 0.9989, 1.0001, 0.9941, 0.9994, 0.9972, 0.9983, 0.9931, 1.0035, 0.9965, 1.0036, 0.9882, 1.0029, 0.9951, 0.9934, 0.9936, 0.9964, + 244, 1.0010, 1.0023, 1.0036, 0.9993, 1.0004, 1.0023, 1.0011, 0.9998, 0.9984, 1.0001, 0.9956, 1.0012, 1.0001, 1.0073, 0.9957, 1.0043, 0.9992, 1.0041, 0.9950, 1.0067, 1.0035, 1.0092, 0.9883, 1.0023, 1.0004, 1.0015, 0.9907, 0.9914, + 245, 1.0023, 1.0032, 1.0031, 0.9991, 0.9980, 0.9989, 0.9991, 0.9980, 0.9983, 1.0018, 0.9984, 1.0038, 0.9979, 0.9965, 0.9965, 1.0075, 0.9977, 0.9995, 0.9940, 1.0055, 0.9980, 1.0038, 0.9896, 1.0052, 0.9949, 0.9915, 0.9997, 1.0014, + 246, 1.0021, 1.0031, 1.0049, 1.0022, 1.0004, 1.0013, 1.0001, 0.9990, 1.0001, 1.0043, 0.9961, 1.0009, 1.0003, 1.0034, 0.9965, 1.0046, 0.9992, 1.0015, 0.9964, 1.0083, 0.9953, 1.0035, 0.9929, 1.0058, 0.9984, 0.9971, 0.9989, 0.9991, + 247, 0.9963, 0.9989, 0.9989, 0.9941, 0.9967, 0.9990, 0.9949, 0.9930, 0.9966, 1.0034, 0.9940, 0.9987, 0.9930, 0.9943, 0.9943, 0.9991, 0.9947, 0.9958, 0.9917, 1.0020, 1.0032, 1.0080, 0.9829, 0.9987, 0.9944, 0.9953, 0.9948, 0.9962, + 248, 0.9955, 0.9966, 0.9934, 0.9896, 0.9937, 0.9964, 0.9932, 0.9916, 0.9924, 0.9945, 0.9920, 0.9955, 0.9879, 0.9874, 0.9928, 0.9976, 0.9929, 0.9923, 0.9878, 0.9969, 1.0070, 1.0102, 0.9850, 1.0006, 0.9877, 0.9838, 0.9902, 0.9927, + 249, 0.9961, 0.9985, 0.9999, 0.9969, 0.9949, 0.9976, 0.9958, 0.9945, 0.9924, 0.9952, 0.9945, 0.9991, 0.9971, 1.0018, 0.9937, 1.0040, 0.9933, 0.9945, 0.9892, 0.9989, 0.9973, 1.0043, 0.9857, 0.9999, 0.9945, 0.9933, 0.9903, 0.9882, + 250, 1.0028, 1.0049, 1.0078, 1.0028, 1.0025, 1.0022, 1.0026, 1.0004, 1.0000, 1.0019, 0.9991, 1.0044, 1.0026, 1.0019, 0.9999, 1.0090, 1.0014, 1.0039, 0.9999, 1.0119, 0.9959, 1.0026, 0.9903, 1.0042, 1.0003, 0.9991, 1.0029, 1.0017, + 251, 0.9981, 0.9968, 1.0047, 1.0003, 0.9994, 1.0008, 1.0005, 1.0003, 0.9948, 0.9988, 0.9950, 0.9979, 0.9979, 1.0036, 0.9970, 1.0050, 0.9970, 0.9990, 0.9960, 1.0080, 0.9916, 0.9983, 0.9914, 1.0047, 0.9967, 0.9958, 0.9975, 0.9981, + 252, 1.0036, 1.0065, 1.0088, 1.0041, 1.0032, 1.0036, 1.0028, 1.0018, 1.0019, 1.0053, 1.0003, 1.0070, 1.0017, 1.0065, 0.9993, 1.0098, 1.0023, 1.0051, 0.9988, 1.0124, 1.0055, 1.0083, 0.9968, 1.0059, 1.0018, 1.0017, 1.0015, 1.0011, + 253, 1.0010, 0.9996, 1.0030, 1.0001, 0.9984, 0.9991, 0.9995, 0.9978, 0.9936, 0.9951, 0.9990, 1.0051, 0.9887, 0.9894, 0.9982, 1.0037, 0.9949, 0.9950, 0.9926, 1.0016, 1.0013, 1.0065, 0.9924, 1.0055, 0.9945, 0.9944, 0.9950, 0.9949, + 254, 0.9951, 0.9969, 0.9998, 0.9948, 0.9963, 0.9974, 0.9966, 0.9952, 0.9965, 0.9994, 0.9957, 1.0013, 1.0007, 1.0014, 0.9922, 0.9967, 0.9950, 0.9963, 0.9930, 1.0026, 1.0068, 1.0079, 0.9884, 1.0019, 0.9947, 0.9936, 0.9962, 0.9962, + 255, 0.9962, 0.9958, 1.0014, 0.9974, 0.9987, 0.9997, 0.9990, 0.9948, 0.9960, 1.0004, 0.9941, 0.9977, 0.9936, 0.9957, 0.9959, 1.0006, 0.9941, 0.9964, 0.9924, 1.0029, 1.0057, 1.0083, 0.9887, 1.0042, 0.9987, 0.9992, 0.9996, 0.9991, + 256, 0.9976, 0.9976, 1.0009, 0.9971, 0.9990, 0.9994, 0.9988, 0.9993, 0.9943, 0.9986, 0.9956, 1.0006, 0.9973, 0.9992, 0.9960, 1.0008, 0.9954, 0.9977, 0.9947, 1.0045, 1.0034, 1.0071, 0.9907, 1.0054, 0.9966, 0.9975, 0.9959, 0.9970, + 257, 1.0019, 1.0015, 0.9994, 0.9949, 1.0009, 1.0003, 0.9993, 0.9984, 0.9987, 1.0040, 0.9943, 0.9983, 1.0002, 1.0043, 0.9953, 1.0020, 0.9978, 0.9998, 0.9913, 1.0018, 1.0033, 1.0065, 0.9885, 1.0042, 0.9965, 0.9966, 0.9912, 0.9909, + 258, 1.0026, 1.0040, 1.0043, 1.0028, 1.0009, 1.0021, 1.0000, 1.0001, 0.9992, 1.0031, 0.9979, 1.0036, 0.9975, 1.0001, 0.9981, 1.0065, 0.9995, 1.0031, 0.9949, 1.0051, 1.0014, 1.0046, 0.9916, 1.0076, 0.9977, 0.9979, 0.9999, 1.0019, + 259, 0.9997, 1.0004, 1.0006, 0.9962, 0.9984, 0.9988, 0.9976, 0.9975, 0.9969, 1.0035, 0.9958, 1.0024, 0.9982, 1.0014, 0.9950, 1.0011, 0.9985, 1.0003, 0.9909, 1.0025, 0.9947, 1.0013, 0.9877, 1.0036, 0.9972, 0.9990, 0.9985, 0.9991, + 260, 1.0002, 1.0046, 0.9980, 0.9964, 0.9982, 1.0005, 0.9936, 0.9917, 1.0006, 1.0069, 0.9936, 0.9987, 0.9934, 0.9982, 0.9917, 0.9994, 0.9966, 0.9989, 0.9881, 0.9965, 1.0096, 1.0128, 0.9840, 1.0031, 0.9942, 0.9979, 0.9966, 1.0013, + 261, 0.9936, 0.9920, 0.9927, 0.9904, 0.9927, 0.9948, 0.9936, 0.9908, 0.9923, 0.9961, 0.9899, 0.9908, 0.9845, 0.9856, 0.9925, 0.9942, 0.9907, 0.9909, 0.9863, 0.9956, 1.0006, 1.0037, 0.9846, 0.9986, 0.9856, 0.9800, 0.9905, 0.9903, + 262, 0.9932, 0.9933, 1.0030, 1.0009, 0.9971, 0.9968, 0.9970, 0.9980, 0.9938, 0.9982, 0.9937, 0.9985, 0.9959, 1.0006, 0.9950, 0.9995, 0.9932, 0.9949, 0.9889, 0.9993, 0.9994, 1.0050, 0.9845, 1.0009, 0.9927, 0.9920, 0.9886, 0.9881, + 263, 0.9113, 0.8962, 0.9047, 0.8960, 0.9036, 0.9362, 0.9397, 0.9106, 0.9309, 0.9382, 0.9469, 0.9120, 0.9255, 0.8933, 0.9645, 0.9081, 0.8911, 0.8423, 0.9160, 0.8885, 0.8960, 0.9427, 0.9408, 0.9609, 0.9340, 0.8813, 0.9657, 0.9756, + 264, 1.0065, 1.0077, 0.9952, 0.9917, 1.0035, 1.0071, 1.0039, 1.0018, 1.0053, 1.0103, 0.9983, 0.9996, 0.9975, 0.9945, 0.9983, 1.0045, 0.9959, 0.9996, 1.0006, 1.0132, 1.0066, 1.0129, 0.9959, 1.0110, 1.0082, 1.0012, 1.0105, 1.0095, + 265, 1.0043, 1.0063, 1.0099, 1.0077, 1.0054, 1.0066, 1.0038, 1.0023, 1.0054, 1.0105, 0.9977, 0.9982, 1.0034, 1.0013, 0.9986, 1.0032, 1.0027, 1.0057, 1.0004, 1.0109, 1.0074, 1.0119, 0.9965, 1.0167, 1.0107, 1.0081, 1.0072, 1.0074, + 266, 1.0015, 1.0002, 1.0108, 1.0092, 1.0044, 1.0050, 1.0039, 1.0027, 1.0037, 1.0089, 0.9968, 1.0014, 1.0040, 1.0036, 0.9982, 1.0021, 1.0020, 1.0054, 1.0008, 1.0140, 1.0013, 1.0085, 0.9966, 1.0135, 1.0100, 1.0064, 1.0056, 1.0052, + 267, 1.0019, 1.0032, 1.0041, 1.0025, 1.0024, 1.0036, 1.0008, 0.9970, 1.0027, 1.0068, 0.9966, 0.9987, 0.9994, 0.9994, 0.9954, 0.9990, 1.0013, 1.0028, 0.9937, 1.0054, 1.0063, 1.0095, 0.9908, 1.0091, 1.0038, 1.0048, 1.0041, 1.0043, + 268, 1.0010, 1.0002, 1.0037, 1.0034, 1.0015, 1.0024, 1.0007, 0.9995, 1.0006, 1.0037, 0.9982, 1.0015, 0.9956, 0.9975, 0.9955, 0.9986, 1.0014, 1.0032, 0.9972, 1.0094, 1.0031, 1.0087, 0.9906, 1.0085, 1.0044, 1.0014, 1.0041, 1.0040, + 269, 1.0001, 0.9982, 1.0051, 1.0010, 1.0033, 1.0005, 1.0018, 0.9986, 1.0023, 1.0038, 1.0008, 1.0030, 1.0026, 1.0032, 0.9974, 1.0018, 1.0019, 1.0018, 0.9980, 1.0084, 1.0088, 1.0102, 0.9895, 1.0047, 1.0085, 1.0016, 1.0051, 1.0046, + 270, 1.0061, 1.0048, 1.0072, 1.0036, 1.0028, 1.0023, 1.0017, 0.9995, 1.0022, 1.0052, 0.9999, 1.0047, 1.0027, 0.9998, 0.9997, 1.0043, 1.0035, 1.0062, 0.9988, 1.0116, 1.0039, 1.0062, 0.9925, 1.0063, 1.0037, 1.0011, 1.0024, 1.0037, + 271, 0.9986, 0.9971, 1.0057, 1.0029, 0.9992, 0.9986, 0.9999, 0.9982, 0.9987, 1.0019, 0.9950, 0.9958, 1.0034, 1.0007, 0.9961, 0.9995, 0.9996, 0.9996, 0.9972, 1.0084, 1.0009, 1.0045, 0.9927, 1.0106, 0.9995, 0.9991, 1.0016, 1.0017, + 272, 1.0045, 1.0046, 1.0056, 1.0025, 1.0040, 1.0023, 1.0018, 0.9995, 1.0049, 1.0092, 0.9973, 1.0011, 1.0057, 1.0054, 1.0004, 1.0050, 1.0037, 1.0074, 0.9978, 1.0109, 1.0099, 1.0115, 0.9960, 1.0113, 1.0046, 1.0028, 1.0040, 1.0062, + 273, 0.9981, 0.9973, 1.0027, 0.9999, 1.0011, 1.0014, 1.0010, 1.0005, 0.9981, 0.9985, 0.9983, 1.0017, 0.9968, 0.9979, 0.9977, 1.0012, 1.0007, 1.0007, 0.9954, 1.0070, 1.0049, 1.0073, 0.9915, 1.0085, 1.0004, 0.9971, 1.0010, 1.0032, + 274, 0.9981, 0.9981, 1.0007, 0.9994, 1.0005, 1.0002, 0.9981, 0.9990, 0.9995, 1.0027, 0.9980, 1.0024, 1.0036, 1.0053, 0.9946, 1.0014, 0.9989, 1.0008, 0.9957, 1.0074, 1.0086, 1.0096, 0.9919, 1.0082, 1.0005, 1.0005, 0.9982, 0.9974, + 275, 1.0013, 1.0019, 1.0036, 1.0008, 0.9998, 0.9995, 0.9992, 0.9974, 1.0002, 1.0020, 0.9973, 1.0009, 0.9978, 0.9963, 1.0014, 1.0040, 1.0006, 1.0004, 0.9976, 1.0107, 1.0022, 1.0046, 0.9919, 1.0086, 1.0019, 0.9977, 1.0042, 1.0051, + 276, 1.0013, 1.0013, 1.0042, 1.0034, 1.0010, 1.0000, 1.0006, 0.9995, 1.0000, 1.0027, 0.9970, 1.0013, 1.0016, 1.0016, 0.9978, 1.0047, 1.0001, 1.0024, 0.9971, 1.0096, 0.9999, 1.0034, 0.9925, 1.0098, 1.0014, 1.0037, 1.0025, 1.0032, + 277, 1.0006, 1.0020, 1.0031, 1.0030, 0.9991, 0.9990, 0.9981, 0.9954, 0.9976, 1.0021, 0.9981, 1.0038, 0.9969, 0.9975, 0.9960, 1.0015, 0.9996, 1.0015, 0.9950, 1.0054, 1.0052, 1.0098, 0.9889, 1.0082, 0.9965, 0.9957, 1.0000, 1.0032, + 278, 1.0000, 0.9997, 1.0010, 0.9977, 0.9965, 0.9982, 0.9968, 0.9953, 0.9961, 1.0001, 0.9943, 0.9989, 0.9987, 0.9963, 0.9968, 1.0019, 0.9999, 1.0037, 0.9937, 1.0038, 1.0065, 1.0083, 0.9894, 1.0050, 0.9917, 0.9868, 0.9961, 0.9989, + 279, 0.9978, 0.9962, 0.9984, 0.9953, 1.0008, 0.9993, 0.9986, 0.9980, 0.9982, 1.0010, 0.9943, 0.9964, 1.0011, 1.0035, 0.9952, 0.9981, 0.9975, 0.9989, 0.9914, 1.0025, 0.9976, 1.0026, 0.9892, 1.0077, 0.9947, 0.9900, 0.9910, 0.9914, + 280, 1.0037, 1.0032, 1.0073, 1.0041, 1.0032, 1.0012, 1.0006, 0.9970, 1.0005, 1.0011, 0.9997, 1.0040, 0.9988, 0.9976, 0.9991, 1.0051, 1.0019, 1.0025, 0.9976, 1.0054, 0.9988, 1.0022, 0.9897, 1.0051, 1.0005, 0.9948, 1.0036, 1.0056, + 281, 0.9991, 0.9990, 1.0003, 0.9978, 1.0013, 1.0015, 0.9998, 0.9989, 0.9996, 1.0003, 0.9975, 1.0010, 0.9967, 0.9971, 0.9958, 1.0018, 0.9998, 1.0006, 0.9927, 1.0034, 0.9978, 1.0014, 0.9873, 1.0034, 1.0015, 0.9997, 0.9989, 1.0011, + 282, 1.0036, 1.0036, 1.0008, 0.9974, 1.0034, 1.0017, 1.0012, 1.0003, 1.0032, 1.0043, 1.0003, 1.0059, 1.0050, 1.0044, 0.9984, 1.0032, 1.0041, 1.0067, 0.9981, 1.0061, 1.0068, 1.0072, 0.9903, 1.0064, 1.0050, 1.0024, 1.0030, 1.0036, + 283, 1.0035, 1.0044, 1.0045, 1.0014, 1.0009, 0.9999, 0.9999, 0.9957, 0.9980, 0.9986, 0.9977, 1.0025, 0.9989, 0.9971, 1.0004, 1.0050, 1.0021, 1.0031, 0.9962, 1.0070, 0.9993, 1.0015, 0.9903, 1.0069, 0.9970, 0.9912, 1.0007, 1.0020, + 284, 1.0008, 1.0007, 1.0004, 0.9975, 1.0001, 1.0002, 0.9991, 0.9987, 0.9983, 1.0010, 0.9968, 0.9999, 1.0044, 1.0030, 0.9964, 1.0001, 0.9994, 1.0007, 0.9938, 1.0050, 1.0023, 1.0058, 0.9906, 1.0080, 0.9973, 0.9969, 0.9992, 1.0024, + 285, 1.0022, 1.0033, 1.0016, 0.9995, 1.0022, 1.0005, 1.0009, 0.9981, 1.0019, 1.0034, 0.9961, 0.9991, 1.0010, 1.0021, 0.9979, 1.0043, 1.0029, 1.0046, 0.9973, 1.0076, 1.0080, 1.0072, 0.9905, 1.0075, 1.0013, 0.9965, 1.0007, 1.0048, + 286, 1.0033, 1.0035, 1.0043, 1.0019, 1.0020, 1.0023, 1.0040, 1.0046, 0.9982, 0.9982, 0.9973, 1.0021, 0.9996, 0.9984, 0.9984, 1.0047, 1.0015, 1.0030, 0.9950, 1.0041, 1.0034, 1.0043, 0.9899, 1.0076, 1.0004, 0.9949, 0.9987, 1.0016, + 287, 1.0016, 1.0026, 0.9997, 0.9992, 0.9991, 0.9990, 1.0003, 1.0009, 0.9979, 0.9970, 0.9972, 1.0019, 1.0013, 1.0038, 0.9955, 1.0020, 0.9997, 1.0010, 0.9955, 1.0072, 1.0029, 1.0033, 0.9902, 1.0074, 0.9993, 0.9982, 0.9945, 0.9965, + 288, 1.0063, 1.0064, 1.0072, 1.0033, 1.0034, 1.0023, 1.0017, 1.0009, 1.0012, 1.0038, 1.0006, 1.0059, 1.0015, 1.0012, 0.9991, 1.0079, 1.0025, 1.0051, 0.9974, 1.0080, 0.9996, 1.0017, 0.9928, 1.0071, 1.0000, 0.9980, 1.0001, 1.0052, + 289, 1.0011, 1.0016, 1.0018, 0.9996, 1.0016, 0.9997, 0.9997, 0.9990, 0.9973, 0.9977, 0.9994, 1.0040, 0.9997, 1.0007, 0.9980, 1.0028, 0.9992, 1.0005, 0.9964, 1.0057, 1.0014, 1.0028, 0.9897, 1.0072, 1.0001, 0.9997, 1.0017, 1.0027, + 290, 1.0039, 1.0046, 1.0011, 0.9989, 1.0003, 0.9996, 0.9979, 0.9953, 1.0005, 1.0012, 0.9964, 1.0001, 0.9996, 0.9996, 0.9975, 1.0031, 1.0003, 1.0027, 0.9942, 1.0042, 1.0034, 1.0058, 0.9881, 1.0043, 0.9967, 0.9932, 0.9987, 1.0027, + 291, 1.0017, 1.0012, 0.9988, 0.9950, 0.9980, 0.9989, 0.9971, 0.9958, 0.9971, 1.0011, 0.9940, 0.9966, 0.9967, 0.9941, 0.9981, 1.0017, 0.9987, 0.9994, 0.9899, 0.9992, 1.0026, 1.0015, 0.9887, 1.0060, 0.9870, 0.9804, 0.9942, 0.9964, + 292, 0.9974, 0.9997, 1.0022, 1.0011, 1.0010, 1.0000, 1.0006, 0.9991, 0.9978, 1.0005, 0.9978, 1.0027, 1.0048, 1.0033, 0.9963, 1.0009, 0.9974, 1.0003, 0.9945, 1.0041, 0.9957, 1.0010, 0.9898, 1.0079, 0.9937, 0.9898, 0.9924, 0.9950, + 293, 1.0025, 1.0014, 1.0006, 0.9974, 0.9996, 0.9991, 0.9982, 0.9969, 0.9987, 1.0003, 1.0020, 1.0087, 0.9984, 0.9948, 0.9971, 1.0036, 0.9980, 0.9991, 0.9945, 1.0045, 0.9997, 1.0026, 0.9896, 1.0030, 0.9994, 0.9949, 1.0028, 1.0060, + 294, 0.9999, 1.0000, 1.0006, 0.9956, 1.0014, 1.0011, 0.9994, 0.9980, 0.9971, 0.9966, 0.9955, 0.9987, 0.9981, 0.9981, 0.9952, 1.0014, 0.9989, 1.0006, 0.9924, 0.9993, 0.9995, 1.0014, 0.9891, 1.0048, 1.0008, 1.0010, 0.9994, 1.0026, + 295, 1.0008, 1.0005, 0.9997, 0.9973, 1.0016, 1.0001, 1.0006, 0.9981, 0.9979, 0.9987, 0.9952, 0.9968, 1.0030, 1.0037, 0.9981, 1.0047, 1.0000, 1.0011, 0.9969, 1.0069, 1.0041, 1.0051, 0.9906, 1.0060, 1.0009, 0.9985, 1.0079, 1.0040, + 296, 1.0026, 1.0017, 1.0082, 1.0035, 1.0002, 1.0006, 1.0005, 0.9979, 0.9984, 0.9982, 1.0006, 1.0048, 1.0011, 0.9985, 1.0011, 1.0073, 1.0005, 1.0014, 0.9978, 1.0056, 1.0010, 1.0034, 0.9964, 1.0122, 0.9965, 0.9903, 1.0027, 0.9995, + 297, 0.9977, 0.9979, 1.0019, 0.9983, 0.9976, 0.9987, 0.9995, 0.9977, 0.9952, 0.9977, 0.9979, 1.0021, 1.0008, 1.0018, 0.9957, 0.9985, 0.9967, 0.9966, 0.9940, 1.0045, 1.0037, 1.0045, 0.9914, 1.0082, 0.9950, 0.9938, 0.9997, 1.0017, + 298, 1.0038, 1.0038, 1.0018, 0.9978, 1.0014, 1.0018, 0.9986, 0.9972, 1.0004, 1.0041, 0.9991, 1.0033, 1.0039, 1.0022, 0.9977, 1.0028, 1.0011, 1.0017, 0.9966, 1.0041, 1.0069, 1.0063, 0.9924, 1.0074, 0.9992, 0.9954, 1.0025, 1.0047, + 299, 1.0011, 1.0027, 0.9989, 0.9952, 1.0005, 1.0009, 1.0011, 0.9992, 0.9972, 0.9995, 0.9970, 1.0004, 1.0000, 0.9972, 0.9979, 1.0003, 1.0007, 1.0004, 0.9934, 0.9990, 1.0011, 1.0026, 0.9923, 1.0067, 0.9965, 0.9923, 0.9986, 1.0007, + 300, 1.0014, 1.0021, 1.0000, 0.9972, 1.0006, 1.0003, 0.9986, 0.9979, 0.9975, 0.9988, 0.9953, 0.9972, 1.0011, 1.0064, 0.9949, 0.9998, 0.9997, 1.0014, 0.9957, 1.0055, 1.0014, 1.0036, 0.9905, 1.0079, 0.9993, 1.0006, 0.9941, 0.9983, + 301, 1.0008, 1.0020, 1.0001, 0.9974, 1.0014, 0.9998, 0.9989, 0.9965, 0.9975, 0.9990, 0.9982, 1.0035, 0.9987, 0.9969, 0.9963, 1.0009, 0.9974, 0.9972, 0.9946, 1.0008, 1.0050, 1.0071, 0.9915, 1.0065, 0.9993, 0.9948, 1.0014, 1.0036, + 302, 1.0021, 1.0022, 1.0033, 1.0009, 1.0022, 1.0007, 1.0011, 1.0007, 0.9977, 0.9992, 0.9963, 1.0013, 1.0019, 1.0028, 0.9984, 1.0053, 0.9992, 1.0007, 0.9988, 1.0051, 1.0065, 1.0060, 0.9933, 1.0093, 1.0015, 1.0009, 1.0009, 1.0017, + 303, 1.0011, 1.0028, 0.9994, 0.9981, 0.9980, 1.0005, 0.9965, 0.9955, 0.9977, 1.0027, 0.9955, 0.9982, 0.9989, 0.9992, 0.9981, 1.0028, 0.9982, 0.9996, 0.9963, 1.0017, 1.0025, 1.0064, 0.9858, 1.0033, 0.9929, 0.9934, 0.9978, 1.0029, + 304, 1.0008, 1.0024, 1.0010, 0.9989, 0.9994, 1.0001, 0.9983, 0.9960, 0.9973, 1.0024, 0.9953, 1.0004, 0.9979, 0.9961, 0.9983, 1.0029, 0.9989, 0.9998, 0.9926, 0.9981, 1.0045, 1.0055, 0.9883, 1.0034, 0.9898, 0.9837, 0.9941, 0.9959, + 305, 0.9980, 0.9982, 0.9978, 0.9950, 1.0001, 0.9996, 0.9986, 0.9980, 0.9951, 0.9987, 0.9987, 1.0038, 1.0015, 1.0023, 0.9945, 0.9973, 0.9965, 0.9966, 0.9940, 0.9996, 0.9988, 1.0010, 0.9882, 1.0061, 0.9940, 0.9913, 0.9914, 0.9931, + 306, 0.9998, 1.0014, 1.0005, 0.9970, 0.9986, 0.9991, 0.9980, 0.9946, 0.9985, 0.9995, 0.9986, 1.0029, 0.9944, 0.9941, 0.9962, 1.0017, 0.9984, 0.9982, 0.9961, 1.0000, 1.0031, 1.0049, 0.9894, 1.0039, 0.9991, 0.9956, 1.0039, 1.0067, + 307, 0.9963, 0.9948, 0.9956, 0.9923, 0.9983, 0.9982, 0.9986, 0.9954, 0.9928, 0.9950, 0.9920, 0.9933, 0.9927, 0.9943, 0.9930, 0.9980, 0.9963, 0.9956, 0.9932, 0.9966, 1.0022, 1.0024, 0.9899, 1.0046, 0.9997, 0.9959, 1.0002, 1.0040, + 308, 1.0018, 1.0037, 1.0000, 0.9979, 0.9998, 0.9995, 0.9984, 0.9972, 0.9991, 0.9999, 0.9975, 1.0001, 1.0022, 1.0048, 0.9969, 1.0038, 1.0002, 1.0019, 0.9950, 1.0005, 1.0088, 1.0077, 0.9890, 1.0053, 0.9988, 0.9973, 1.0025, 1.0051, + 309, 1.0014, 1.0013, 1.0034, 0.9991, 0.9982, 0.9972, 0.9980, 0.9945, 0.9959, 0.9985, 0.9973, 0.9997, 0.9953, 0.9991, 0.9994, 1.0051, 0.9986, 0.9984, 0.9984, 1.0023, 1.0023, 1.0032, 0.9924, 1.0046, 0.9947, 0.9873, 0.9975, 1.0020, + 310, 1.0020, 1.0019, 1.0028, 1.0001, 1.0011, 1.0005, 1.0003, 0.9980, 0.9978, 1.0012, 0.9965, 1.0019, 1.0054, 1.0060, 0.9970, 1.0012, 1.0000, 1.0018, 0.9978, 1.0046, 1.0026, 1.0039, 0.9928, 1.0078, 0.9976, 0.9971, 1.0005, 1.0028, + 311, 1.0033, 1.0045, 1.0006, 0.9980, 1.0004, 1.0003, 0.9976, 0.9959, 0.9991, 1.0017, 0.9967, 1.0008, 1.0024, 0.9999, 0.9966, 1.0031, 1.0015, 1.0023, 0.9972, 1.0026, 1.0060, 1.0058, 0.9923, 1.0068, 0.9958, 0.9946, 0.9998, 1.0031, + 312, 0.9992, 1.0000, 1.0025, 1.0001, 0.9994, 0.9998, 1.0011, 1.0004, 0.9968, 0.9977, 0.9966, 0.9993, 1.0019, 0.9990, 0.9976, 1.0033, 0.9993, 0.9999, 1.0005, 1.0034, 1.0020, 1.0043, 0.9958, 1.0126, 0.9952, 0.9940, 0.9970, 1.0012, + 313, 0.9982, 0.9976, 1.0020, 0.9993, 0.9982, 0.9996, 0.9967, 0.9965, 0.9945, 0.9951, 0.9979, 1.0048, 0.9981, 1.0029, 0.9940, 1.0007, 0.9958, 0.9966, 0.9960, 1.0027, 1.0023, 1.0037, 0.9922, 1.0087, 0.9996, 1.0000, 0.9960, 0.9961, + 314, 0.9988, 0.9992, 1.0044, 1.0014, 1.0004, 1.0001, 1.0014, 0.9995, 0.9987, 0.9991, 0.9987, 1.0046, 0.9979, 0.9967, 0.9998, 1.0065, 0.9992, 0.9979, 0.9994, 1.0038, 1.0036, 1.0032, 0.9899, 1.0055, 0.9989, 0.9978, 1.0005, 1.0037, + 315, 1.0012, 1.0005, 0.9995, 0.9962, 1.0003, 0.9990, 0.9996, 0.9995, 0.9961, 0.9988, 0.9961, 1.0000, 1.0037, 0.9995, 0.9986, 1.0040, 0.9979, 0.9980, 0.9965, 1.0023, 0.9977, 0.9996, 0.9917, 1.0063, 0.9988, 0.9990, 1.0010, 1.0023, + 316, 0.9955, 0.9964, 0.9986, 0.9953, 0.9990, 0.9981, 0.9967, 0.9941, 0.9963, 0.9986, 0.9968, 1.0008, 0.9972, 1.0001, 0.9967, 1.0003, 0.9958, 0.9982, 0.9937, 1.0006, 1.0024, 1.0040, 0.9877, 1.0013, 0.9937, 0.9913, 0.9957, 0.9996, + 317, 0.9953, 0.9957, 0.9966, 0.9937, 0.9950, 0.9958, 0.9955, 0.9924, 0.9922, 0.9956, 0.9933, 0.9941, 0.9914, 0.9884, 0.9954, 0.9985, 0.9938, 0.9928, 0.9920, 0.9957, 0.9987, 0.9989, 0.9876, 1.0020, 0.9896, 0.9833, 0.9926, 0.9949, + 318, 0.9966, 0.9972, 1.0019, 0.9990, 1.0011, 1.0003, 0.9992, 0.9983, 0.9963, 1.0000, 0.9955, 1.0004, 1.0016, 1.0033, 0.9966, 1.0009, 0.9977, 0.9979, 0.9950, 0.9989, 0.9962, 0.9977, 0.9931, 1.0074, 0.9945, 0.9931, 0.9918, 0.9937, + 319, 0.9994, 0.9985, 1.0004, 0.9972, 0.9985, 0.9974, 0.9986, 0.9957, 0.9956, 0.9976, 0.9968, 1.0013, 0.9955, 0.9951, 0.9976, 1.0025, 0.9963, 0.9969, 0.9966, 1.0010, 1.0003, 1.0022, 0.9909, 1.0050, 0.9962, 0.9924, 1.0007, 1.0045, + 320, 0.9964, 0.9962, 0.9973, 0.9938, 0.9991, 0.9983, 0.9978, 0.9957, 0.9935, 0.9911, 0.9965, 1.0013, 0.9932, 0.9934, 0.9937, 0.9990, 0.9965, 0.9958, 0.9932, 0.9962, 1.0014, 1.0037, 0.9897, 1.0031, 0.9978, 0.9975, 0.9991, 1.0009, + 321, 0.9997, 0.9988, 0.9993, 0.9964, 1.0006, 0.9998, 0.9978, 0.9973, 0.9969, 0.9969, 0.9989, 1.0033, 1.0007, 1.0034, 0.9966, 1.0011, 1.0005, 0.9996, 0.9979, 1.0032, 1.0042, 1.0054, 0.9893, 1.0027, 1.0018, 0.9990, 1.0004, 1.0037, + 322, 1.0072, 1.0058, 1.0060, 1.0004, 1.0053, 1.0028, 1.0020, 0.9970, 1.0005, 0.9996, 0.9987, 1.0016, 1.0021, 0.9982, 1.0010, 1.0049, 1.0032, 1.0038, 1.0005, 1.0044, 1.0000, 0.9999, 0.9953, 1.0074, 1.0002, 0.9969, 0.9990, 1.0020, + 323, 0.9979, 0.9979, 1.0018, 0.9986, 0.9995, 0.9992, 0.9998, 0.9980, 0.9955, 0.9989, 0.9934, 0.9968, 1.0039, 1.0028, 0.9963, 0.9999, 0.9980, 0.9984, 0.9967, 1.0032, 1.0002, 1.0026, 0.9913, 1.0080, 0.9928, 0.9930, 0.9962, 0.9989, + 324, 1.0026, 1.0021, 1.0035, 0.9997, 1.0017, 1.0030, 1.0001, 0.9985, 0.9991, 1.0040, 0.9997, 1.0054, 1.0025, 1.0026, 0.9993, 1.0062, 0.9994, 1.0007, 0.9983, 1.0049, 1.0071, 1.0076, 0.9903, 1.0054, 0.9993, 0.9973, 0.9991, 1.0032, + 325, 0.9965, 0.9965, 0.9985, 0.9966, 0.9992, 0.9985, 0.9997, 0.9988, 0.9926, 0.9920, 0.9988, 1.0048, 0.9941, 0.9935, 0.9955, 0.9980, 0.9961, 0.9964, 0.9960, 1.0014, 1.0012, 1.0014, 0.9903, 1.0064, 0.9955, 0.9924, 0.9965, 0.9975, + 326, 1.0004, 0.9991, 1.0035, 1.0011, 0.9990, 0.9992, 0.9987, 0.9983, 0.9970, 0.9986, 0.9949, 1.0000, 1.0030, 1.0045, 0.9958, 1.0041, 0.9968, 0.9988, 0.9966, 1.0032, 1.0016, 1.0035, 0.9899, 1.0058, 1.0008, 1.0000, 0.9949, 0.9961, + 327, 1.0012, 1.0004, 0.9997, 0.9973, 0.9990, 1.0000, 0.9987, 0.9968, 0.9966, 0.9974, 0.9945, 0.9986, 0.9974, 0.9965, 0.9964, 1.0030, 0.9964, 0.9976, 0.9975, 1.0038, 0.9998, 1.0015, 0.9884, 1.0049, 0.9990, 0.9965, 0.9988, 1.0018, + 328, 0.9999, 1.0000, 1.0009, 0.9980, 1.0001, 0.9993, 0.9995, 0.9993, 0.9975, 0.9990, 0.9968, 1.0018, 1.0006, 1.0002, 0.9972, 1.0014, 0.9994, 1.0002, 0.9982, 1.0026, 1.0022, 1.0036, 0.9924, 1.0063, 1.0022, 1.0024, 0.9984, 1.0003, + 329, 0.9957, 0.9948, 0.9960, 0.9943, 0.9985, 0.9968, 0.9968, 0.9969, 0.9954, 0.9977, 0.9951, 0.9996, 0.9976, 0.9988, 0.9955, 0.9994, 0.9963, 0.9971, 0.9929, 0.9985, 1.0059, 1.0053, 0.9893, 1.0020, 0.9977, 0.9954, 0.9967, 1.0021, + 330, 0.9952, 0.9953, 0.9981, 0.9964, 0.9974, 0.9989, 0.9980, 0.9967, 0.9940, 0.9966, 0.9934, 0.9985, 0.9958, 0.9944, 0.9959, 0.9984, 0.9963, 0.9973, 0.9921, 0.9977, 1.0060, 1.0060, 0.9916, 1.0092, 0.9910, 0.9875, 0.9940, 0.9983, + 331, 0.9972, 0.9951, 0.9986, 0.9954, 0.9987, 0.9987, 0.9972, 0.9966, 0.9934, 0.9967, 0.9927, 0.9944, 0.9983, 0.9999, 0.9954, 0.9982, 0.9963, 0.9958, 0.9925, 0.9960, 0.9980, 0.9989, 0.9910, 1.0071, 0.9942, 0.9918, 0.9927, 0.9946, + 332, 1.0013, 1.0014, 1.0046, 0.9995, 1.0014, 0.9996, 0.9988, 0.9971, 0.9983, 1.0005, 0.9985, 1.0047, 0.9965, 0.9953, 0.9966, 1.0023, 0.9991, 0.9992, 0.9976, 1.0033, 1.0027, 1.0040, 0.9931, 1.0077, 0.9988, 0.9950, 1.0033, 1.0077, + 333, 0.9989, 0.9963, 0.9990, 0.9927, 0.9987, 0.9983, 0.9985, 0.9956, 0.9939, 0.9940, 0.9975, 1.0005, 0.9952, 0.9954, 0.9945, 0.9969, 0.9976, 0.9961, 0.9932, 0.9975, 1.0017, 1.0040, 0.9899, 1.0049, 0.9998, 0.9969, 0.9989, 1.0010, + 334, 1.0034, 1.0026, 1.0009, 0.9969, 1.0041, 1.0019, 0.9996, 0.9991, 0.9999, 1.0019, 0.9973, 1.0017, 1.0047, 1.0067, 0.9984, 1.0041, 1.0026, 1.0046, 0.9988, 1.0050, 1.0080, 1.0078, 0.9914, 1.0064, 1.0032, 0.9997, 1.0008, 1.0052, + 335, 1.0026, 1.0010, 0.9998, 0.9963, 1.0008, 0.9993, 0.9979, 0.9956, 0.9977, 1.0003, 0.9965, 1.0004, 0.9986, 0.9963, 0.9993, 1.0025, 0.9992, 1.0001, 0.9954, 1.0006, 1.0022, 1.0015, 0.9922, 1.0073, 0.9954, 0.9911, 0.9985, 1.0010, + 336, 0.9987, 0.9982, 1.0009, 0.9986, 1.0000, 0.9994, 0.9994, 0.9983, 0.9965, 0.9993, 0.9942, 0.9961, 1.0039, 1.0039, 0.9949, 1.0001, 0.9983, 0.9990, 0.9957, 1.0012, 1.0012, 1.0012, 0.9941, 1.0101, 0.9974, 0.9946, 0.9990, 1.0033, + 337, 1.0016, 1.0011, 1.0017, 0.9990, 1.0000, 1.0001, 0.9989, 0.9954, 0.9980, 1.0008, 0.9965, 1.0005, 0.9997, 0.9994, 0.9969, 1.0016, 0.9976, 0.9986, 0.9962, 1.0027, 1.0045, 1.0036, 0.9919, 1.0070, 0.9986, 0.9965, 0.9981, 1.0037, + 338, 1.0004, 1.0000, 0.9994, 0.9973, 1.0012, 1.0005, 1.0019, 1.0008, 0.9961, 0.9962, 0.9962, 0.9997, 0.9980, 0.9970, 0.9973, 1.0003, 1.0004, 1.0019, 0.9963, 1.0011, 1.0012, 1.0030, 0.9925, 1.0097, 0.9979, 0.9953, 0.9968, 1.0005, + 339, 0.9989, 0.9979, 0.9988, 0.9985, 0.9990, 0.9981, 0.9996, 0.9972, 0.9946, 0.9947, 0.9958, 0.9989, 1.0004, 1.0026, 0.9941, 0.9988, 0.9959, 0.9969, 0.9955, 1.0025, 1.0033, 1.0048, 0.9896, 1.0096, 0.9998, 0.9977, 0.9937, 0.9947, + 340, 0.9960, 0.9948, 0.9985, 0.9962, 0.9978, 0.9964, 0.9963, 0.9956, 0.9940, 0.9951, 0.9972, 1.0023, 0.9934, 0.9944, 0.9971, 1.0032, 0.9941, 0.9946, 0.9953, 1.0034, 1.0049, 1.0053, 0.9895, 1.0045, 0.9999, 0.9974, 0.9994, 1.0040, + 341, 0.9978, 0.9973, 1.0009, 0.9984, 0.9986, 0.9986, 0.9994, 0.9984, 0.9961, 0.9964, 0.9942, 0.9965, 0.9986, 0.9992, 0.9985, 1.0022, 0.9964, 0.9963, 0.9974, 1.0039, 1.0018, 1.0028, 0.9936, 1.0095, 0.9981, 0.9979, 0.9969, 1.0007, + 342, 0.9988, 0.9981, 0.9996, 0.9967, 1.0010, 0.9991, 0.9987, 0.9963, 0.9981, 1.0022, 0.9931, 0.9961, 0.9990, 0.9995, 0.9985, 1.0023, 0.9993, 1.0007, 0.9960, 1.0016, 1.0073, 1.0084, 0.9900, 1.0042, 0.9948, 0.9908, 0.9992, 1.0032, + 343, 0.9975, 0.9953, 0.9958, 0.9933, 0.9963, 0.9966, 0.9950, 0.9937, 0.9927, 0.9955, 0.9932, 0.9969, 0.9934, 0.9885, 0.9955, 0.9957, 0.9945, 0.9951, 0.9892, 0.9943, 1.0065, 1.0068, 0.9873, 1.0027, 0.9890, 0.9823, 0.9930, 0.9975, + 344, 0.9971, 0.9977, 0.9961, 0.9954, 1.0003, 0.9992, 0.9966, 0.9961, 0.9946, 0.9973, 0.9963, 1.0009, 0.9995, 1.0007, 0.9941, 0.9950, 0.9972, 0.9984, 0.9927, 0.9982, 0.9986, 1.0018, 0.9909, 1.0056, 0.9974, 0.9951, 0.9922, 0.9938, + 345, 1.0026, 1.0013, 1.0004, 0.9947, 1.0001, 1.0007, 0.9984, 0.9949, 0.9996, 1.0005, 0.9948, 0.9977, 0.9968, 0.9958, 0.9977, 1.0015, 0.9985, 0.9990, 0.9957, 1.0011, 0.9989, 1.0009, 0.9909, 1.0048, 0.9998, 0.9981, 1.0014, 1.0042, + 346, 1.0006, 1.0007, 0.9982, 0.9952, 1.0012, 0.9992, 0.9989, 0.9989, 0.9965, 0.9982, 0.9924, 0.9956, 0.9958, 0.9972, 0.9948, 0.9999, 0.9988, 0.9995, 0.9938, 0.9997, 1.0009, 1.0035, 0.9915, 1.0050, 1.0006, 0.9996, 0.9977, 1.0014, + 347, 1.0003, 0.9993, 1.0000, 0.9976, 1.0010, 0.9995, 1.0001, 0.9976, 0.9973, 0.9982, 0.9966, 1.0022, 1.0010, 1.0016, 0.9996, 1.0034, 0.9987, 0.9994, 0.9984, 1.0031, 1.0061, 1.0058, 0.9906, 1.0042, 1.0026, 1.0004, 1.0010, 1.0032, + 348, 1.0004, 1.0009, 1.0035, 1.0023, 0.9995, 1.0000, 0.9990, 0.9966, 0.9961, 0.9967, 1.0009, 1.0071, 0.9970, 0.9951, 1.0010, 1.0050, 0.9977, 0.9983, 0.9984, 1.0058, 1.0039, 1.0033, 0.9901, 1.0040, 0.9978, 0.9918, 0.9970, 0.9998, + 349, 0.9990, 0.9954, 1.0011, 0.9967, 1.0000, 0.9964, 1.0009, 0.9959, 0.9978, 0.9968, 0.9986, 0.9997, 1.0021, 0.9992, 0.9978, 0.9967, 0.9994, 0.9963, 0.9982, 1.0016, 0.9995, 0.9994, 0.9965, 1.0068, 1.0009, 0.9945, 0.9996, 0.9997, + 350, 1.0032, 1.0029, 1.0056, 1.0013, 1.0028, 1.0005, 1.0008, 1.0007, 1.0000, 1.0040, 0.9966, 1.0013, 1.0043, 1.0028, 1.0005, 1.0053, 1.0015, 1.0032, 0.9998, 1.0078, 1.0055, 1.0046, 0.9951, 1.0080, 1.0024, 1.0019, 1.0002, 1.0045, + 351, 0.9992, 0.9982, 0.9971, 0.9961, 0.9997, 0.9983, 1.0006, 1.0000, 0.9947, 0.9946, 0.9971, 1.0005, 0.9969, 0.9944, 0.9968, 0.9999, 0.9975, 0.9974, 0.9930, 0.9975, 0.9985, 1.0001, 0.9915, 1.0049, 0.9983, 0.9940, 0.9956, 0.9993, + 352, 0.9971, 0.9964, 0.9990, 0.9985, 0.9990, 0.9986, 0.9980, 0.9975, 0.9957, 0.9963, 0.9974, 1.0023, 1.0012, 1.0041, 0.9957, 0.9985, 0.9975, 0.9976, 0.9953, 1.0019, 1.0039, 1.0053, 0.9935, 1.0079, 1.0025, 1.0005, 0.9968, 0.9984, + 353, 0.9989, 0.9977, 1.0015, 0.9978, 0.9986, 0.9972, 0.9990, 0.9961, 0.9968, 0.9992, 0.9971, 1.0006, 0.9940, 0.9943, 0.9981, 1.0037, 0.9946, 0.9947, 0.9991, 1.0066, 1.0031, 1.0033, 0.9939, 1.0077, 1.0012, 0.9998, 1.0010, 1.0043, + 354, 1.0017, 1.0018, 1.0033, 1.0023, 1.0015, 1.0008, 1.0011, 1.0015, 0.9981, 1.0002, 0.9945, 0.9974, 1.0016, 1.0017, 0.9991, 1.0025, 0.9996, 0.9996, 0.9979, 1.0048, 1.0019, 1.0034, 0.9961, 1.0104, 1.0009, 1.0006, 0.9995, 1.0044, + 355, 0.9974, 0.9986, 1.0015, 0.9994, 0.9983, 0.9976, 0.9957, 0.9940, 0.9949, 0.9974, 0.9968, 1.0011, 0.9981, 0.9978, 0.9979, 1.0010, 1.0009, 0.9974, 0.9948, 0.9998, 1.0036, 1.0049, 0.9914, 1.0052, 0.9963, 0.9937, 0.9956, 1.0028, + 356, 0.9990, 0.9984, 0.9972, 0.9935, 0.9987, 0.9983, 0.9972, 0.9962, 0.9938, 0.9984, 0.9988, 1.0041, 0.9949, 0.9905, 0.9976, 0.9968, 0.9970, 0.9962, 0.9919, 0.9961, 1.0020, 1.0045, 0.9903, 1.0036, 0.9897, 0.9842, 0.9921, 0.9942, + 357, 0.9958, 0.9970, 0.9952, 0.9965, 0.9981, 0.9999, 0.9980, 0.9992, 0.9948, 1.0013, 0.9950, 1.0018, 1.0009, 1.0026, 0.9967, 0.9975, 0.9963, 0.9995, 0.9921, 0.9975, 0.9968, 1.0016, 0.9929, 1.0088, 0.9946, 0.9935, 0.9900, 0.9938, + 358, 1.0030, 1.0031, 1.0021, 0.9989, 1.0016, 1.0005, 0.9995, 0.9981, 0.9987, 1.0002, 0.9966, 0.9996, 0.9977, 0.9990, 0.9977, 1.0027, 0.9992, 0.9995, 0.9962, 1.0026, 1.0000, 1.0036, 0.9932, 1.0068, 1.0024, 1.0009, 1.0036, 1.0069, + 359, 0.9944, 0.9961, 0.9967, 0.9943, 0.9978, 0.9969, 0.9972, 0.9956, 0.9918, 0.9912, 0.9917, 0.9938, 0.9913, 0.9923, 0.9948, 0.9967, 0.9944, 0.9933, 0.9907, 0.9958, 0.9991, 1.0005, 0.9893, 1.0049, 0.9992, 0.9951, 0.9978, 1.0019, + 360, 0.9962, 0.9957, 1.0021, 1.0003, 0.9999, 0.9987, 1.0000, 0.9979, 0.9949, 0.9944, 1.0010, 1.0083, 1.0068, 1.0005, 0.9979, 1.0016, 0.9991, 0.9990, 0.9985, 1.0038, 1.0053, 1.0064, 0.9913, 1.0020, 1.0039, 1.0036, 0.9991, 1.0016, + 361, 1.0013, 1.0003, 1.0012, 0.9969, 0.9982, 0.9993, 0.9988, 0.9959, 0.9962, 0.9971, 0.9987, 1.0023, 0.9981, 0.9955, 1.0013, 1.0041, 0.9971, 0.9978, 0.9980, 1.0017, 1.0029, 1.0030, 0.9925, 1.0031, 0.9970, 0.9944, 0.9962, 0.9995, + 362, 0.9968, 0.9974, 1.0024, 0.9990, 0.9983, 0.9998, 0.9992, 0.9991, 0.9953, 0.9993, 0.9934, 0.9954, 1.0046, 1.0034, 0.9968, 0.9979, 1.0015, 0.9997, 0.9972, 1.0034, 1.0010, 1.0024, 0.9944, 1.0078, 0.9982, 0.9960, 0.9960, 1.0018, + 363, 0.9992, 0.9977, 1.0039, 1.0005, 1.0003, 0.9985, 1.0015, 0.9996, 0.9969, 1.0005, 0.9957, 0.9981, 1.0011, 0.9997, 0.9986, 1.0057, 0.9986, 0.9973, 0.9989, 1.0049, 1.0065, 1.0055, 0.9916, 1.0057, 1.0004, 0.9981, 0.9976, 1.0034, + 364, 0.9980, 0.9967, 0.9996, 0.9957, 1.0003, 0.9992, 1.0011, 1.0007, 0.9947, 0.9968, 1.0005, 1.0053, 0.9974, 0.9983, 0.9959, 0.9968, 0.9982, 0.9972, 0.9961, 0.9994, 1.0032, 1.0029, 0.9918, 1.0058, 0.9993, 0.9953, 0.9960, 0.9992, + 365, 0.9988, 0.9975, 0.9998, 0.9966, 0.9989, 0.9984, 0.9991, 0.9990, 0.9963, 0.9981, 0.9958, 0.9981, 1.0012, 1.0053, 0.9947, 0.9976, 0.9968, 0.9965, 0.9987, 1.0047, 1.0048, 1.0049, 0.9939, 1.0072, 1.0018, 1.0006, 0.9974, 0.9986, + 366, 1.0019, 1.0000, 1.0016, 0.9987, 1.0001, 0.9994, 0.9999, 0.9972, 0.9992, 1.0013, 0.9985, 1.0025, 1.0001, 0.9987, 0.9981, 1.0017, 1.0001, 0.9981, 0.9986, 1.0015, 1.0094, 1.0103, 0.9951, 1.0077, 1.0045, 0.9983, 1.0024, 1.0046, + 367, 0.9989, 0.9998, 1.0001, 0.9984, 0.9982, 0.9981, 0.9990, 0.9981, 0.9961, 0.9976, 0.9939, 0.9971, 0.9993, 1.0001, 0.9963, 1.0003, 0.9972, 0.9987, 0.9975, 1.0025, 1.0048, 1.0049, 0.9943, 1.0073, 1.0031, 1.0025, 0.9972, 1.0023, + 368, 1.0004, 1.0008, 1.0008, 0.9983, 0.9991, 0.9987, 0.9965, 0.9940, 0.9979, 1.0013, 0.9956, 0.9995, 0.9981, 1.0001, 0.9966, 1.0012, 0.9981, 0.9996, 0.9951, 0.9987, 1.0062, 1.0064, 0.9906, 0.9995, 1.0006, 0.9986, 0.9970, 1.0022, + 369, 0.9973, 0.9950, 0.9967, 0.9934, 0.9953, 0.9963, 0.9949, 0.9941, 0.9929, 0.9972, 0.9935, 0.9956, 0.9952, 0.9926, 0.9985, 1.0008, 0.9958, 0.9956, 0.9950, 0.9993, 1.0041, 1.0048, 0.9910, 1.0045, 0.9897, 0.9839, 0.9928, 0.9950, + 370, 0.9949, 0.9948, 1.0016, 0.9992, 0.9996, 0.9980, 1.0007, 0.9996, 0.9947, 0.9977, 0.9965, 1.0002, 1.0018, 1.0029, 0.9973, 0.9988, 0.9975, 0.9977, 0.9969, 1.0013, 0.9992, 1.0021, 0.9932, 1.0072, 0.9975, 0.9945, 0.9910, 0.9941, + 371, 1.0010, 1.0009, 1.0011, 0.9997, 0.9991, 0.9987, 0.9975, 0.9972, 0.9976, 1.0004, 0.9980, 1.0021, 0.9965, 0.9972, 0.9977, 1.0026, 0.9982, 0.9993, 0.9964, 1.0023, 1.0048, 1.0042, 0.9925, 1.0032, 0.9999, 0.9965, 1.0020, 1.0058, + 372, 0.9997, 0.9967, 0.9978, 0.9944, 0.9978, 0.9972, 0.9993, 0.9984, 0.9931, 0.9941, 0.9968, 1.0004, 0.9957, 0.9946, 0.9946, 0.9963, 0.9956, 0.9944, 0.9935, 0.9956, 0.9975, 0.9997, 0.9908, 1.0029, 1.0025, 0.9998, 0.9978, 1.0009, + 373, 1.0021, 0.9987, 1.0003, 0.9971, 1.0007, 0.9984, 0.9983, 0.9975, 0.9981, 1.0016, 0.9967, 1.0013, 1.0006, 1.0045, 0.9969, 1.0036, 0.9998, 1.0004, 0.9984, 1.0029, 1.0028, 1.0040, 0.9926, 1.0027, 1.0041, 1.0025, 0.9986, 1.0027, + 374, 1.0041, 1.0053, 1.0041, 0.9996, 1.0034, 1.0018, 0.9992, 0.9979, 1.0008, 1.0032, 0.9962, 0.9995, 1.0037, 1.0010, 1.0017, 1.0049, 1.0029, 1.0033, 0.9996, 1.0050, 1.0042, 1.0058, 0.9963, 1.0076, 1.0003, 0.9948, 0.9977, 1.0011, + 375, 0.9969, 0.9963, 1.0008, 0.9977, 0.9985, 0.9976, 0.9992, 0.9977, 0.9950, 0.9979, 0.9951, 0.9976, 1.0045, 1.0019, 0.9949, 0.9968, 0.9975, 0.9970, 0.9966, 1.0009, 1.0012, 1.0018, 0.9966, 1.0065, 0.9980, 0.9976, 0.9968, 1.0016, + 376, 1.0016, 1.0007, 1.0039, 1.0002, 1.0017, 0.9988, 0.9999, 0.9965, 0.9988, 1.0014, 0.9981, 1.0020, 1.0051, 1.0014, 0.9980, 1.0017, 0.9999, 0.9987, 0.9990, 1.0041, 1.0087, 1.0070, 0.9979, 1.0079, 0.9999, 0.9976, 0.9999, 1.0045, + 377, 0.9985, 0.9969, 0.9998, 0.9965, 1.0013, 0.9982, 1.0002, 1.0003, 0.9935, 0.9963, 0.9982, 1.0018, 0.9987, 0.9965, 0.9969, 0.9982, 0.9984, 0.9966, 0.9971, 1.0005, 1.0011, 1.0039, 0.9938, 1.0078, 0.9985, 0.9967, 0.9961, 0.9988, + 378, 1.0008, 1.0008, 1.0026, 1.0005, 1.0029, 0.9989, 1.0013, 1.0000, 0.9969, 0.9993, 0.9958, 0.9994, 1.0033, 1.0075, 0.9961, 0.9995, 0.9991, 1.0003, 0.9992, 1.0071, 1.0035, 1.0056, 0.9945, 1.0066, 1.0035, 1.0041, 0.9949, 0.9972, + 379, 1.0014, 1.0023, 0.9999, 0.9971, 1.0017, 0.9979, 0.9981, 0.9967, 0.9979, 0.9998, 0.9973, 1.0013, 0.9974, 0.9965, 0.9978, 1.0006, 0.9993, 0.9985, 0.9982, 1.0007, 1.0051, 1.0050, 0.9935, 1.0046, 1.0031, 1.0014, 1.0011, 1.0024, + 380, 1.0010, 1.0000, 1.0007, 0.9973, 1.0034, 0.9980, 0.9992, 0.9978, 0.9975, 0.9965, 0.9983, 1.0032, 0.9999, 1.0008, 0.9964, 0.9994, 0.9988, 0.9993, 0.9991, 1.0055, 1.0003, 1.0027, 0.9941, 1.0050, 1.0005, 1.0019, 0.9965, 1.0006, + 381, 0.9981, 0.9968, 0.9984, 0.9950, 1.0015, 0.9965, 0.9953, 0.9940, 0.9969, 0.9999, 0.9963, 1.0000, 0.9977, 0.9983, 1.0003, 0.9999, 0.9984, 0.9989, 0.9962, 1.0007, 1.0049, 1.0059, 0.9907, 0.9986, 0.9965, 0.9949, 0.9967, 1.0002, + 382, 0.9982, 0.9971, 0.9998, 0.9971, 1.0021, 0.9967, 0.9972, 0.9956, 0.9939, 0.9952, 0.9925, 0.9944, 0.9969, 0.9942, 0.9980, 1.0000, 0.9977, 0.9976, 0.9966, 0.9997, 1.0042, 1.0057, 0.9905, 1.0022, 0.9922, 0.9858, 0.9940, 0.9978, + 383, 0.9958, 0.9953, 1.0002, 0.9981, 1.0025, 0.9974, 0.9972, 0.9976, 0.9938, 0.9974, 0.9955, 0.9988, 1.0004, 1.0003, 0.9977, 0.9966, 0.9951, 0.9946, 0.9948, 1.0003, 0.9963, 0.9992, 0.9948, 1.0054, 0.9990, 0.9977, 0.9914, 0.9935, + 384, 1.0024, 1.0013, 1.0039, 1.0019, 1.0075, 0.9998, 1.0007, 1.0015, 0.9986, 1.0002, 0.9995, 1.0060, 0.9957, 0.9970, 0.9983, 1.0043, 1.0001, 1.0016, 0.9999, 1.0065, 1.0038, 1.0055, 0.9953, 1.0060, 1.0044, 1.0027, 1.0034, 1.0073, + 385, 0.9962, 0.9956, 0.9973, 0.9928, 1.0061, 0.9990, 0.9998, 0.9988, 0.9957, 0.9967, 0.9993, 1.0023, 0.9962, 0.9969, 0.9949, 0.9971, 0.9981, 0.9982, 0.9949, 0.9986, 1.0012, 1.0028, 0.9914, 1.0020, 1.0032, 1.0032, 0.9981, 1.0024, + 386, 0.9962, 0.9966, 1.0025, 0.9994, 1.0093, 1.0011, 1.0007, 1.0013, 0.9980, 0.9998, 0.9987, 1.0031, 1.0028, 1.0077, 0.9980, 1.0021, 1.0010, 1.0024, 0.9973, 1.0048, 1.0077, 1.0083, 0.9974, 1.0066, 1.0076, 1.0078, 1.0021, 1.0054, + 387, 0.9998, 0.9983, 1.0018, 0.9978, 1.0057, 0.9976, 0.9975, 0.9970, 0.9954, 0.9970, 0.9972, 1.0017, 0.9983, 0.9961, 0.9988, 1.0016, 0.9983, 0.9978, 0.9992, 1.0036, 1.0030, 1.0051, 0.9975, 1.0072, 0.9991, 0.9946, 0.9977, 1.0022, + 388, 0.9977, 0.9981, 1.0024, 0.9998, 1.0070, 0.9981, 0.9981, 0.9977, 0.9962, 0.9980, 0.9961, 0.9982, 1.0040, 1.0034, 0.9947, 0.9974, 0.9991, 0.9990, 0.9965, 1.0024, 1.0012, 1.0031, 0.9980, 1.0086, 1.0013, 0.9999, 0.9987, 1.0012, + 389, 0.9998, 0.9988, 1.0021, 0.9993, 1.0068, 0.9988, 0.9976, 0.9970, 0.9977, 1.0020, 0.9990, 1.0074, 1.0013, 1.0022, 0.9965, 1.0015, 0.9997, 1.0004, 0.9969, 1.0030, 1.0057, 1.0064, 0.9941, 1.0066, 0.9999, 0.9985, 0.9990, 1.0025, + 390, 1.0021, 1.0022, 0.9998, 0.9964, 1.0103, 1.0004, 1.0003, 1.0001, 0.9970, 0.9966, 0.9997, 1.0152, 1.0019, 1.0002, 0.9973, 0.9980, 1.0006, 1.0007, 0.9953, 1.0004, 1.0025, 1.0051, 0.9931, 1.0025, 1.0035, 1.0014, 0.9981, 1.0032, + 391, 0.9987, 0.9978, 0.9956, 0.9934, 1.0062, 0.9973, 0.9972, 0.9955, 0.9962, 0.9981, 0.9958, 1.0034, 1.0015, 1.0041, 0.9940, 0.9970, 0.9984, 0.9974, 0.9931, 0.9989, 1.0020, 1.0053, 0.9958, 1.0044, 1.0029, 1.0036, 0.9947, 0.9971, + 392, 1.0015, 1.0013, 1.0032, 0.9992, 1.0094, 1.0000, 0.9993, 0.9994, 0.9989, 1.0022, 0.9956, 0.9950, 0.9998, 1.0018, 0.9988, 1.0021, 1.0002, 1.0012, 0.9951, 1.0020, 1.0004, 1.0022, 0.9963, 1.0056, 1.0017, 1.0000, 0.9996, 1.0032, + 393, 0.9977, 0.9971, 1.0029, 0.9998, 1.0086, 0.9986, 1.0006, 1.0018, 0.9953, 0.9968, 0.9962, 1.0003, 1.0003, 1.0011, 0.9988, 1.0023, 0.9970, 0.9972, 0.9975, 1.0048, 1.0022, 1.0034, 0.9965, 1.0074, 1.0022, 1.0002, 0.9993, 1.0025, + 394, 0.9983, 0.9978, 0.9986, 0.9960, 1.0075, 0.9979, 0.9966, 0.9959, 0.9971, 0.9975, 1.0007, 1.0067, 0.9993, 1.0008, 0.9977, 1.0004, 0.9974, 0.9982, 0.9929, 1.0001, 1.0092, 1.0091, 0.9917, 1.0012, 1.0004, 0.9970, 0.9986, 1.0023, + 395, 0.9965, 0.9966, 0.9959, 0.9933, 1.0046, 0.9958, 0.9962, 0.9930, 0.9937, 0.9944, 0.9957, 0.9974, 0.9942, 0.9910, 0.9959, 0.9947, 0.9959, 0.9940, 0.9928, 0.9985, 1.0033, 1.0029, 0.9900, 1.0007, 0.9935, 0.9905, 0.9924, 0.9956, + 396, 0.9961, 0.9943, 0.9977, 0.9952, 1.0074, 0.9980, 0.9967, 0.9968, 0.9962, 0.9992, 0.9963, 0.9984, 1.0021, 1.0028, 0.9943, 0.9955, 0.9951, 0.9959, 0.9919, 0.9973, 0.9966, 1.0010, 0.9947, 1.0035, 0.9964, 0.9935, 0.9923, 0.9944, + 397, 0.9991, 0.9974, 0.9994, 0.9946, 1.0097, 0.9992, 1.0003, 1.0002, 0.9989, 1.0015, 0.9962, 0.9997, 0.9987, 0.9977, 0.9993, 1.0023, 0.9997, 0.9991, 0.9987, 1.0062, 1.0010, 1.0012, 0.9904, 1.0011, 1.0011, 0.9995, 1.0042, 1.0069, + 398, 0.9969, 0.9963, 0.9987, 0.9953, 1.0092, 0.9998, 1.0002, 0.9999, 0.9947, 0.9943, 0.9962, 0.9975, 0.9974, 0.9988, 0.9966, 0.9988, 0.9984, 0.9994, 0.9940, 1.0007, 1.0064, 1.0063, 0.9943, 1.0023, 1.0041, 1.0017, 1.0002, 1.0041, + 399, 1.0000, 0.9989, 0.9993, 0.9955, 1.0080, 0.9970, 0.9988, 0.9992, 0.9962, 0.9968, 0.9985, 1.0015, 1.0045, 1.0032, 0.9981, 1.0030, 0.9987, 0.9977, 0.9958, 1.0039, 1.0095, 1.0087, 0.9944, 1.0023, 1.0040, 1.0034, 1.0024, 1.0070, + 400, 1.0048, 1.0034, 1.0038, 0.9996, 1.0110, 1.0000, 1.0007, 1.0001, 0.9991, 1.0001, 0.9981, 1.0022, 1.0057, 0.9986, 0.9994, 1.0028, 1.0013, 1.0021, 0.9965, 1.0027, 1.0025, 1.0021, 0.9986, 1.0070, 1.0039, 1.0035, 1.0005, 1.0032, + 401, 0.9977, 0.9975, 1.0002, 0.9990, 1.0096, 0.9992, 0.9997, 0.9992, 0.9978, 1.0004, 0.9943, 0.9957, 1.0044, 1.0039, 0.9973, 0.9980, 0.9974, 0.9986, 0.9955, 1.0022, 0.9983, 0.9994, 0.9964, 1.0059, 0.9987, 0.9990, 0.9971, 1.0017, + 402, 1.0051, 1.0037, 1.0040, 1.0000, 1.0135, 1.0014, 1.0014, 0.9968, 1.0033, 1.0042, 1.0010, 1.0031, 1.0077, 1.0044, 0.9997, 1.0018, 1.0053, 1.0031, 0.9969, 1.0024, 1.0079, 1.0035, 0.9997, 1.0040, 1.0036, 1.0007, 1.0024, 1.0046, + 403, 0.9967, 0.9951, 0.9975, 0.9948, 1.0084, 0.9983, 0.9992, 0.9998, 0.9935, 0.9943, 0.9986, 1.0022, 0.9981, 0.9967, 0.9977, 0.9976, 0.9984, 0.9973, 0.9911, 0.9960, 1.0005, 1.0011, 0.9934, 1.0046, 0.9984, 0.9970, 0.9970, 1.0012, + 404, 1.0014, 1.0007, 1.0043, 0.9970, 1.0080, 0.9982, 0.9988, 0.9992, 0.9981, 0.9991, 0.9953, 0.9963, 1.0048, 1.0066, 0.9981, 0.9995, 0.9989, 0.9995, 0.9966, 1.0048, 1.0042, 1.0046, 0.9983, 1.0063, 1.0032, 1.0023, 0.9958, 0.9973, + 405, 1.0024, 1.0007, 1.0087, 0.9990, 1.0108, 0.9988, 1.0016, 0.9990, 0.9992, 1.0002, 0.9963, 0.9985, 0.9993, 0.9998, 1.0001, 1.0051, 0.9994, 0.9992, 0.9958, 1.0018, 1.0029, 1.0021, 0.9972, 1.0058, 1.0002, 0.9986, 1.0014, 1.0045, + 406, 1.0015, 0.9996, 1.0044, 1.0045, 1.0119, 1.0005, 1.0028, 1.0034, 0.9988, 0.9993, 0.9994, 1.0034, 1.0044, 1.0047, 1.0012, 1.0044, 0.9995, 1.0004, 0.9987, 1.0070, 0.9998, 1.0005, 0.9982, 1.0075, 1.0046, 1.0067, 0.9988, 1.0041, + 407, 0.9993, 0.9986, 0.9963, 0.9952, 1.0062, 0.9966, 0.9963, 0.9945, 0.9975, 1.0009, 0.9979, 1.0027, 1.0001, 0.9993, 0.9981, 0.9987, 0.9976, 0.9971, 0.9932, 1.0022, 1.0012, 1.0021, 0.9912, 0.9982, 0.9966, 0.9963, 0.9979, 1.0004, + 408, 0.9982, 0.9972, 0.9960, 0.9938, 1.0072, 0.9981, 0.9963, 0.9937, 0.9953, 1.0004, 0.9965, 0.9986, 0.9969, 0.9942, 0.9979, 0.9965, 0.9987, 0.9974, 0.9898, 0.9970, 1.0037, 1.0046, 0.9925, 1.0032, 0.9927, 0.9861, 0.9932, 0.9946, + 409, 0.9952, 0.9954, 0.9983, 0.9959, 1.0078, 0.9992, 0.9983, 0.9968, 0.9948, 0.9990, 0.9943, 0.9969, 1.0031, 1.0052, 0.9949, 0.9960, 0.9973, 0.9969, 0.9913, 0.9967, 0.9964, 0.9975, 0.9944, 1.0035, 0.9974, 0.9943, 0.9894, 0.9922, + 410, 1.0013, 1.0027, 1.0004, 1.0009, 1.0099, 1.0019, 0.9995, 1.0005, 0.9983, 1.0021, 0.9980, 1.0017, 0.9993, 1.0022, 0.9968, 1.0021, 0.9995, 1.0016, 0.9954, 1.0046, 1.0011, 1.0038, 0.9949, 1.0054, 1.0019, 0.9987, 1.0010, 1.0083, + 411, 0.9991, 0.9967, 0.9944, 0.9924, 1.0051, 0.9967, 0.9979, 0.9959, 0.9953, 0.9947, 0.9952, 0.9984, 0.9950, 0.9963, 0.9951, 0.9934, 0.9978, 0.9957, 0.9916, 0.9985, 1.0010, 1.0023, 0.9945, 1.0024, 1.0018, 1.0005, 0.9970, 1.0011, + 412, 1.0065, 1.0078, 0.9989, 0.9957, 1.0101, 1.0007, 0.9968, 0.9958, 1.0017, 1.0059, 0.9974, 1.0016, 1.0047, 1.0079, 0.9950, 0.9997, 1.0041, 1.0042, 0.9926, 0.9999, 1.0068, 1.0052, 0.9960, 1.0026, 1.0038, 1.0027, 1.0017, 1.0049, + 413, 1.0041, 1.0035, 1.0024, 0.9999, 1.0093, 1.0013, 0.9994, 0.9994, 0.9976, 1.0020, 0.9963, 0.9975, 1.0022, 1.0001, 1.0000, 1.0017, 1.0008, 1.0014, 0.9944, 1.0023, 1.0028, 1.0039, 0.9968, 1.0066, 0.9986, 0.9953, 0.9950, 0.9995, + 414, 0.9998, 0.9979, 1.0034, 1.0000, 1.0088, 1.0005, 1.0001, 1.0003, 0.9983, 0.9997, 0.9957, 0.9959, 1.0067, 1.0058, 0.9978, 0.9991, 1.0008, 0.9996, 0.9958, 1.0028, 1.0001, 1.0029, 0.9990, 1.0061, 1.0006, 0.9989, 0.9987, 1.0026, + 415, 1.0032, 1.0021, 1.0006, 0.9989, 1.0086, 1.0004, 0.9995, 1.0000, 0.9991, 1.0017, 0.9980, 1.0005, 1.0040, 1.0018, 0.9974, 0.9988, 1.0015, 1.0010, 0.9942, 1.0028, 1.0064, 1.0060, 0.9962, 1.0046, 1.0017, 0.9988, 0.9992, 1.0022, + 416, 1.0017, 1.0013, 1.0038, 0.9999, 1.0096, 1.0021, 1.0017, 1.0018, 0.9974, 0.9992, 1.0002, 1.0039, 1.0017, 1.0011, 1.0000, 0.9990, 1.0018, 1.0012, 0.9931, 0.9990, 1.0013, 1.0025, 0.9956, 1.0026, 0.9989, 0.9954, 0.9965, 1.0005, + 417, 1.0019, 0.9989, 1.0006, 0.9992, 1.0057, 0.9998, 0.9995, 1.0002, 0.9985, 0.9991, 0.9998, 1.0025, 1.0032, 1.0056, 0.9963, 0.9998, 0.9998, 0.9985, 0.9954, 1.0033, 1.0067, 1.0052, 0.9969, 1.0037, 1.0000, 0.9998, 0.9955, 0.9972, + 418, 1.0020, 1.0013, 1.0009, 0.9991, 1.0082, 1.0006, 1.0002, 1.0004, 0.9998, 1.0007, 0.9994, 1.0036, 0.9991, 0.9994, 0.9992, 1.0023, 0.9999, 0.9992, 0.9951, 1.0017, 1.0054, 1.0048, 0.9987, 1.0068, 1.0042, 1.0024, 1.0025, 1.0052, + 419, 1.0014, 1.0000, 1.0012, 0.9984, 1.0086, 1.0003, 1.0001, 0.9992, 0.9983, 1.0008, 0.9960, 0.9972, 1.0011, 1.0024, 0.9977, 1.0005, 0.9997, 0.9997, 0.9943, 1.0021, 1.0006, 1.0016, 0.9984, 1.0065, 1.0017, 1.0032, 0.9974, 1.0027, + 420, 0.9986, 0.9984, 0.9983, 0.9977, 1.0053, 1.0003, 0.9970, 0.9953, 0.9987, 1.0021, 0.9989, 1.0012, 1.0002, 1.0023, 0.9982, 0.9991, 0.9997, 0.9991, 0.9932, 0.9982, 1.0059, 1.0066, 0.9963, 1.0030, 0.9987, 0.9977, 0.9974, 1.0035, + 421, 0.9946, 0.9934, 0.9960, 0.9933, 1.0027, 0.9969, 0.9964, 0.9953, 0.9932, 0.9935, 0.9956, 0.9966, 0.9943, 0.9924, 0.9979, 0.9975, 0.9953, 0.9930, 0.9890, 0.9946, 1.0039, 1.0050, 0.9929, 1.0018, 0.9921, 0.9852, 0.9926, 0.9963, + 422, 0.9942, 0.9931, 0.9996, 0.9971, 1.0046, 0.9988, 0.9986, 0.9994, 0.9964, 0.9985, 0.9978, 1.0004, 1.0044, 1.0047, 0.9968, 0.9963, 0.9984, 0.9973, 0.9930, 0.9992, 1.0017, 1.0031, 0.9981, 1.0049, 0.9983, 0.9965, 0.9930, 0.9946, + 423, 1.0005, 0.9998, 0.9973, 0.9949, 1.0055, 0.9983, 0.9987, 0.9971, 0.9984, 0.9999, 0.9976, 1.0020, 0.9952, 0.9953, 0.9972, 1.0013, 0.9993, 0.9980, 0.9951, 1.0011, 0.9981, 1.0000, 0.9941, 1.0011, 0.9992, 0.9960, 1.0028, 1.0071, + 424, 0.9991, 0.9983, 0.9970, 0.9938, 1.0066, 1.0006, 0.9995, 0.9987, 0.9959, 0.9962, 0.9952, 0.9961, 0.9968, 0.9973, 0.9987, 1.0028, 0.9989, 0.9978, 0.9928, 0.9981, 0.9988, 1.0023, 0.9975, 1.0036, 1.0016, 1.0014, 1.0003, 1.0043, + 425, 1.0007, 1.0022, 1.0034, 1.0038, 1.0059, 1.0003, 1.0002, 1.0001, 0.9983, 0.9969, 1.0012, 1.0054, 1.0042, 1.0069, 0.9991, 1.0035, 1.0016, 1.0013, 0.9964, 1.0032, 1.0080, 1.0079, 0.9975, 1.0028, 1.0030, 1.0043, 1.0016, 1.0054, + 426, 1.0026, 1.0013, 1.0030, 1.0020, 1.0060, 1.0004, 1.0010, 1.0015, 0.9982, 0.9987, 0.9988, 1.0026, 1.0005, 0.9985, 1.0013, 1.0047, 1.0002, 1.0009, 0.9964, 1.0040, 1.0042, 1.0020, 0.9979, 1.0037, 0.9982, 0.9966, 0.9976, 1.0011, + 427, 0.9988, 0.9978, 0.9975, 0.9965, 1.0027, 0.9983, 1.0001, 0.9996, 0.9948, 0.9963, 0.9954, 0.9978, 1.0028, 1.0035, 0.9958, 0.9959, 0.9978, 0.9980, 0.9951, 1.0009, 0.9991, 1.0002, 0.9981, 1.0048, 0.9960, 0.9944, 0.9977, 1.0018, + 428, 1.0024, 1.0012, 1.0027, 1.0009, 1.0066, 1.0015, 1.0008, 1.0012, 1.0009, 1.0031, 0.9993, 1.0023, 1.0037, 1.0023, 0.9996, 1.0025, 1.0010, 1.0007, 0.9968, 1.0039, 1.0034, 1.0015, 0.9969, 1.0031, 1.0018, 0.9992, 0.9972, 1.0018, + 429, 1.0018, 0.9976, 0.9999, 0.9983, 1.0069, 1.0013, 1.0034, 1.0025, 0.9961, 0.9971, 0.9987, 1.0009, 0.9974, 0.9962, 0.9973, 0.9982, 0.9986, 0.9976, 0.9946, 0.9982, 0.9998, 1.0005, 0.9954, 1.0016, 0.9992, 0.9979, 0.9949, 0.9996, + 430, 1.0031, 1.0028, 1.0006, 0.9994, 1.0060, 1.0005, 1.0003, 0.9999, 1.0005, 1.0010, 0.9993, 1.0054, 1.0068, 1.0071, 0.9965, 0.9997, 1.0023, 1.0021, 0.9985, 1.0050, 1.0058, 1.0056, 0.9979, 1.0044, 1.0037, 1.0020, 0.9954, 0.9984, + 431, 1.0013, 1.0044, 1.0004, 0.9978, 1.0033, 0.9982, 0.9991, 0.9983, 0.9988, 1.0001, 0.9983, 1.0009, 0.9988, 0.9986, 0.9989, 1.0011, 0.9981, 0.9983, 0.9951, 1.0007, 1.0017, 1.0013, 0.9968, 1.0034, 1.0015, 0.9987, 0.9994, 1.0032, + 432, 1.0041, 1.0055, 1.0017, 0.9986, 1.0079, 1.0007, 1.0012, 1.0008, 1.0009, 1.0012, 0.9965, 0.9988, 1.0029, 1.0059, 0.9986, 1.0000, 1.0014, 1.0009, 0.9969, 1.0030, 1.0036, 1.0035, 0.9989, 1.0025, 1.0030, 1.0024, 1.0006, 1.0049, + 433, 0.9997, 0.9992, 0.9978, 0.9967, 1.0034, 0.9980, 0.9972, 0.9964, 0.9983, 1.0023, 0.9942, 0.9972, 1.0005, 1.0013, 0.9978, 1.0015, 0.9987, 0.9986, 0.9939, 0.9990, 1.0075, 1.0052, 0.9931, 0.9986, 0.9995, 0.9976, 0.9966, 1.0019, + 434, 0.9979, 0.9961, 1.0004, 1.0002, 1.0038, 0.9973, 1.0003, 0.9989, 0.9946, 0.9959, 0.9964, 0.9979, 0.9956, 0.9921, 0.9996, 0.9983, 0.9986, 0.9965, 0.9941, 0.9968, 1.0038, 1.0032, 0.9962, 1.0019, 0.9937, 0.9872, 0.9953, 0.9969, + 435, 0.9970, 0.9973, 0.9994, 0.9978, 1.0045, 0.9986, 0.9999, 1.0054, 0.9976, 0.9992, 0.9971, 1.0001, 1.0030, 1.0027, 0.9971, 0.9981, 0.9977, 0.9976, 0.9943, 0.9982, 0.9962, 0.9982, 0.9966, 1.0029, 0.9962, 0.9968, 0.9910, 0.9936, + 436, 1.0060, 1.0068, 1.0035, 1.0018, 1.0088, 1.0023, 1.0028, 1.0036, 1.0025, 1.0054, 1.0018, 1.0086, 0.9994, 0.9997, 0.9999, 1.0038, 1.0032, 1.0048, 0.9978, 1.0043, 1.0005, 1.0015, 0.9954, 1.0012, 1.0011, 0.9969, 1.0020, 1.0077, + 437, 0.9979, 0.9963, 0.9977, 0.9966, 1.0048, 1.0009, 0.9988, 0.9995, 0.9955, 0.9960, 0.9990, 1.0022, 0.9961, 0.9957, 0.9965, 0.9979, 0.9986, 0.9969, 0.9963, 0.9998, 1.0004, 1.0024, 0.9953, 1.0007, 1.0023, 1.0030, 0.9975, 1.0022, + 438, 1.0075, 1.0059, 1.0084, 1.0072, 1.0087, 1.0036, 1.0025, 1.0043, 1.0036, 1.0028, 1.0012, 1.0067, 1.0085, 1.0094, 1.0002, 1.0044, 1.0040, 1.0055, 0.9986, 1.0048, 1.0074, 1.0056, 1.0017, 1.0040, 1.0061, 1.0055, 1.0037, 1.0072, + 439, 1.0072, 1.0074, 1.0022, 1.0015, 1.0060, 1.0002, 1.0006, 0.9999, 1.0014, 1.0031, 0.9975, 0.9997, 1.0042, 1.0006, 1.0020, 1.0049, 1.0036, 1.0031, 0.9997, 1.0036, 0.9987, 1.0002, 0.9990, 1.0066, 0.9967, 0.9917, 0.9975, 1.0007, + 440, 1.0009, 0.9994, 1.0062, 1.0041, 1.0057, 1.0008, 1.0032, 1.0046, 0.9986, 1.0001, 1.0000, 1.0029, 1.0061, 1.0051, 0.9986, 1.0016, 1.0000, 1.0005, 0.9974, 1.0031, 1.0017, 1.0024, 1.0009, 1.0059, 0.9989, 0.9975, 0.9984, 1.0045, + 441, 1.0032, 1.0035, 1.0042, 1.0031, 1.0071, 1.0018, 1.0005, 1.0015, 0.9991, 1.0016, 1.0036, 1.0109, 1.0021, 1.0015, 0.9992, 1.0027, 1.0007, 0.9995, 0.9991, 1.0026, 1.0061, 1.0054, 0.9994, 1.0025, 1.0032, 1.0009, 0.9977, 1.0041, + 442, 1.0021, 1.0014, 1.0003, 0.9988, 1.0090, 1.0026, 1.0019, 1.0018, 0.9971, 0.9979, 0.9993, 1.0030, 1.0005, 0.9987, 0.9969, 0.9981, 1.0018, 1.0013, 0.9950, 1.0002, 1.0013, 1.0016, 0.9977, 1.0018, 1.0015, 1.0034, 0.9959, 1.0004, + 443, 0.9999, 1.0002, 1.0017, 1.0001, 1.0054, 0.9996, 1.0016, 1.0027, 0.9970, 0.9987, 0.9929, 0.9951, 1.0031, 1.0049, 0.9962, 0.9990, 1.0002, 0.9992, 0.9982, 1.0032, 1.0006, 1.0030, 1.0006, 1.0042, 1.0005, 1.0018, 0.9942, 0.9986, + 444, 1.0001, 0.9993, 1.0045, 1.0019, 1.0064, 1.0004, 1.0006, 1.0010, 0.9987, 1.0011, 1.0008, 1.0068, 0.9976, 0.9977, 0.9998, 1.0046, 0.9983, 0.9988, 0.9972, 1.0020, 1.0046, 1.0041, 0.9995, 1.0062, 0.9980, 0.9964, 0.9998, 1.0047, + 445, 0.9994, 0.9984, 0.9994, 0.9986, 1.0069, 0.9995, 1.0006, 1.0000, 0.9975, 0.9982, 1.0013, 1.0038, 1.0091, 1.0016, 0.9984, 0.9982, 1.0008, 0.9992, 0.9985, 1.0009, 1.0034, 1.0035, 1.0010, 1.0044, 1.0039, 1.0024, 0.9995, 1.0028, + 446, 1.0029, 0.9996, 1.0003, 0.9972, 1.0078, 0.9990, 0.9976, 0.9973, 0.9991, 1.0014, 0.9984, 1.0028, 1.0015, 1.0005, 0.9978, 0.9983, 1.0003, 0.9994, 0.9961, 1.0012, 1.0067, 1.0051, 0.9983, 1.0012, 1.0011, 1.0015, 0.9977, 1.0022, + 447, 1.0006, 1.0002, 0.9954, 0.9943, 1.0055, 0.9976, 0.9964, 0.9949, 0.9963, 0.9984, 0.9946, 0.9961, 0.9967, 0.9921, 0.9992, 0.9950, 0.9989, 0.9964, 0.9902, 0.9915, 1.0021, 1.0014, 0.9964, 1.0016, 0.9915, 0.9848, 0.9931, 0.9947, + 448, 1.0008, 1.0000, 1.0007, 0.9987, 1.0115, 1.0029, 0.9998, 1.0004, 0.9996, 1.0020, 0.9957, 0.9966, 1.0060, 1.0061, 0.9972, 0.9956, 1.0015, 1.0009, 0.9935, 0.9972, 0.9982, 1.0011, 0.9996, 1.0035, 0.9982, 0.9968, 0.9919, 0.9948, + 449, 1.0032, 1.0028, 1.0010, 0.9996, 1.0110, 1.0011, 0.9990, 0.9979, 0.9998, 1.0022, 0.9998, 1.0055, 1.0001, 0.9997, 0.9979, 1.0010, 1.0024, 1.0012, 0.9980, 1.0013, 1.0030, 1.0041, 0.9976, 1.0010, 1.0026, 0.9972, 1.0005, 1.0052, + 450, 1.0007, 0.9986, 0.9994, 0.9955, 1.0101, 1.0004, 1.0003, 1.0007, 0.9968, 0.9972, 0.9975, 0.9996, 0.9989, 0.9974, 0.9967, 0.9965, 1.0016, 0.9998, 0.9957, 0.9987, 1.0054, 1.0051, 0.9984, 1.0010, 1.0034, 1.0027, 0.9990, 1.0018, + 451, 1.0034, 1.0034, 1.0019, 1.0019, 1.0112, 1.0011, 1.0011, 1.0009, 1.0001, 1.0011, 1.0000, 1.0022, 1.0043, 1.0063, 1.0000, 1.0041, 1.0046, 1.0110, 1.0011, 1.0062, 1.0062, 1.0052, 0.9980, 1.0011, 1.0040, 1.0018, 0.9994, 1.0032, + 452, 1.0074, 1.0077, 1.0049, 1.0013, 1.0123, 1.0026, 0.9996, 1.0004, 1.0007, 1.0050, 1.0008, 1.0040, 1.0017, 1.0018, 1.0031, 1.0112, 1.0036, 1.0044, 0.9987, 1.0053, 1.0038, 1.0041, 1.0000, 1.0039, 0.9991, 0.9949, 0.9975, 1.0023, + 453, 0.9972, 0.9983, 1.0029, 1.0001, 1.0101, 0.9998, 0.9978, 0.9983, 0.9952, 0.9976, 1.0009, 1.0049, 1.0054, 1.0026, 0.9964, 0.9977, 0.9985, 0.9982, 0.9980, 1.0000, 1.0010, 1.0025, 1.0001, 1.0021, 0.9975, 0.9976, 0.9964, 1.0013, + 454, 1.0022, 1.0022, 1.0019, 1.0001, 1.0104, 1.0007, 1.0003, 1.0007, 1.0007, 1.0018, 0.9999, 1.0043, 1.0036, 1.0020, 1.0000, 1.0007, 1.0024, 1.0018, 0.9998, 1.0043, 1.0099, 1.0085, 0.9987, 1.0021, 1.0025, 1.0034, 0.9987, 1.0024, + 455, 1.0001, 0.9994, 0.9976, 0.9960, 1.0095, 0.9992, 1.0006, 1.0006, 0.9957, 0.9955, 0.9964, 0.9971, 1.0001, 0.9972, 0.9981, 0.9970, 1.0004, 0.9977, 0.9946, 0.9962, 1.0057, 1.0054, 0.9978, 1.0028, 0.9990, 0.9950, 0.9970, 1.0019, + 456, 1.0019, 1.0023, 1.0007, 0.9994, 1.0098, 1.0013, 1.0002, 1.0025, 0.9981, 1.0008, 0.9953, 0.9976, 1.0044, 1.0079, 0.9963, 0.9989, 1.0012, 1.0011, 0.9985, 1.0029, 1.0073, 1.0056, 0.9999, 1.0030, 1.0020, 1.0015, 0.9965, 0.9979, + 457, 1.0022, 1.0001, 1.0029, 1.0032, 1.0120, 1.0007, 1.0007, 1.0014, 0.9981, 1.0003, 1.0006, 1.0045, 0.9981, 1.0003, 1.0023, 1.0034, 1.0004, 1.0003, 1.0007, 1.0047, 1.0027, 1.0027, 1.0006, 1.0039, 1.0030, 1.0020, 1.0006, 1.0038, + 458, 1.0049, 1.0048, 1.0017, 1.0009, 1.0157, 1.0018, 1.0002, 1.0020, 1.0006, 1.0014, 0.9999, 1.0042, 1.0046, 1.0032, 0.9998, 1.0004, 1.0026, 1.0026, 0.9992, 1.0045, 1.0041, 1.0028, 1.0017, 1.0030, 1.0042, 1.0056, 1.0019, 1.0046, + 459, 1.0036, 1.0021, 0.9980, 0.9971, 1.0108, 0.9993, 0.9968, 0.9970, 0.9991, 1.0039, 0.9972, 0.9994, 1.0007, 1.0005, 0.9995, 1.0000, 1.0020, 1.0019, 0.9965, 0.9994, 1.0071, 1.0066, 0.9982, 1.0011, 0.9963, 0.9942, 0.9970, 1.0004, + 460, 0.9993, 0.9983, 0.9985, 0.9985, 1.0095, 0.9985, 0.9975, 0.9982, 0.9950, 0.9994, 0.9959, 0.9986, 0.9973, 0.9942, 0.9991, 0.9980, 0.9984, 0.9973, 0.9942, 0.9967, 1.0039, 1.0035, 1.0002, 1.0048, 0.9895, 0.9842, 0.9936, 0.9976, + 461, 0.9963, 0.9949, 0.9967, 0.9978, 1.0101, 0.9987, 0.9987, 0.9998, 0.9959, 0.9968, 1.0001, 1.0037, 1.0023, 1.0025, 0.9964, 0.9957, 0.9974, 0.9956, 0.9951, 0.9986, 0.9972, 1.0015, 0.9989, 1.0039, 0.9973, 0.9960, 0.9909, 0.9925, + 462, 1.0042, 1.0036, 1.0013, 0.9990, 1.0134, 1.0024, 1.0027, 1.0022, 1.0010, 1.0034, 1.0028, 1.0066, 0.9984, 1.0005, 1.0003, 1.0052, 1.0016, 0.9998, 0.9991, 1.0032, 1.0002, 1.0024, 0.9980, 1.0019, 1.0025, 1.0035, 1.0053, 1.0071, + 463, 0.9979, 0.9982, 0.9945, 0.9953, 1.0103, 0.9996, 0.9996, 1.0005, 0.9953, 0.9979, 0.9960, 0.9999, 0.9961, 0.9973, 0.9961, 0.9957, 0.9991, 0.9983, 0.9929, 0.9959, 0.9991, 0.9999, 0.9968, 0.9992, 1.0006, 1.0019, 0.9981, 1.0025, + 464, 1.0018, 1.0024, 0.9999, 0.9993, 1.0138, 1.0029, 1.0011, 1.0035, 0.9996, 1.0008, 1.0009, 1.0046, 1.0048, 1.0065, 0.9987, 1.0022, 1.0032, 1.0026, 0.9994, 1.0041, 1.0073, 1.0055, 1.0001, 1.0026, 1.0061, 1.0069, 1.0011, 1.0053, + 465, 1.0034, 1.0020, 1.0030, 1.0016, 1.0109, 1.0007, 1.0012, 1.0003, 0.9991, 1.0003, 0.9992, 1.0010, 1.0018, 0.9983, 1.0023, 1.0047, 1.0009, 0.9985, 1.0004, 1.0046, 0.9998, 1.0002, 1.0019, 1.0047, 1.0017, 1.0006, 0.9977, 0.9993, + 466, 0.9996, 0.9983, 1.0034, 1.0017, 1.0111, 0.9997, 1.0003, 1.0034, 0.9981, 1.0000, 0.9985, 1.0015, 1.0056, 1.0044, 1.0001, 1.0005, 1.0001, 0.9990, 0.9976, 1.0015, 0.9997, 1.0009, 1.0038, 1.0064, 0.9984, 0.9999, 0.9993, 1.0013, + 467, 1.0008, 1.0000, 1.0022, 1.0023, 1.0118, 1.0010, 0.9996, 1.0014, 0.9995, 1.0025, 0.9987, 1.0014, 1.0031, 1.0033, 1.0029, 1.0020, 1.0014, 1.0001, 0.9994, 1.0041, 1.0079, 1.0046, 1.0017, 1.0030, 0.9988, 0.9962, 0.9993, 1.0029, + 468, 1.0002, 0.9980, 0.9974, 0.9969, 1.0086, 0.9997, 0.9999, 1.0009, 0.9949, 0.9947, 1.0014, 1.0056, 0.9979, 0.9971, 0.9973, 0.9968, 1.0000, 0.9988, 0.9958, 0.9974, 1.0053, 1.0049, 0.9987, 1.0016, 0.9976, 0.9967, 0.9962, 0.9988, + 469, 1.0001, 1.0000, 0.9971, 0.9972, 1.0087, 0.9992, 0.9990, 1.0007, 0.9977, 0.9990, 0.9976, 1.0003, 1.0028, 1.0052, 0.9961, 0.9971, 0.9986, 0.9984, 0.9987, 1.0037, 1.0045, 1.0036, 0.9986, 1.0011, 1.0026, 1.0031, 0.9952, 0.9939, + 470, 1.0078, 1.0068, 1.0042, 1.0043, 1.0145, 1.0034, 1.0018, 1.0026, 1.0022, 1.0047, 0.9995, 1.0023, 1.0040, 1.0033, 1.0007, 1.0050, 1.0034, 1.0027, 0.9999, 1.0039, 1.0049, 1.0029, 1.0020, 1.0076, 1.0051, 1.0086, 1.0026, 1.0045, + 471, 1.0018, 1.0012, 1.0010, 1.0006, 1.0108, 1.0018, 1.0008, 1.0042, 0.9977, 0.9994, 0.9981, 0.9992, 1.0037, 1.0026, 1.0012, 1.0013, 0.9998, 0.9997, 0.9988, 1.0028, 1.0027, 1.0027, 0.9999, 1.0030, 1.0027, 1.0050, 0.9989, 1.0012, + 472, 1.0022, 1.0009, 1.0018, 1.0007, 1.0138, 1.0020, 0.9994, 1.0004, 1.0020, 1.0045, 1.0021, 1.0049, 1.0047, 1.0049, 1.0015, 1.0006, 1.0045, 1.0026, 1.0000, 1.0013, 1.0098, 1.0077, 0.9988, 0.9990, 1.0012, 0.9989, 1.0014, 0.9990, + 473, 0.9961, 0.9966, 0.9961, 0.9969, 1.0055, 0.9974, 0.9960, 0.9968, 0.9934, 0.9961, 0.9972, 1.0013, 0.9944, 0.9922, 0.9990, 0.9977, 0.9964, 0.9945, 0.9934, 0.9964, 1.0038, 1.0041, 0.9948, 1.0000, 0.9908, 0.9879, 0.9921, 0.9956, + 474, 0.9973, 0.9965, 0.9993, 0.9998, 1.0105, 1.0016, 0.9989, 1.0010, 0.9973, 1.0001, 0.9980, 1.0001, 1.0035, 1.0049, 0.9975, 0.9979, 0.9996, 0.9988, 0.9972, 0.9993, 0.9978, 0.9975, 0.9984, 1.0023, 0.9981, 0.9977, 0.9914, 0.9923, + 475, 1.0036, 1.0031, 1.0007, 1.0009, 1.0105, 1.0010, 0.9993, 1.0001, 0.9995, 1.0007, 0.9980, 1.0012, 0.9980, 0.9968, 1.0008, 1.0026, 1.0014, 1.0015, 0.9981, 1.0009, 1.0011, 1.0019, 0.9972, 1.0008, 1.0043, 1.0027, 1.0038, 1.0059, + 476, 0.9999, 0.9982, 0.9966, 0.9956, 1.0076, 1.0014, 0.9978, 0.9985, 0.9952, 0.9973, 0.9978, 1.0022, 0.9979, 0.9989, 0.9960, 0.9965, 0.9996, 0.9987, 0.9932, 0.9968, 1.0015, 1.0021, 0.9974, 1.0011, 1.0033, 1.0070, 0.9960, 1.0011, + 477, 0.9989, 1.0002, 0.9985, 0.9984, 1.0066, 0.9995, 0.9998, 1.0003, 0.9993, 1.0011, 0.9995, 1.0040, 1.0016, 1.0045, 0.9995, 1.0023, 1.0013, 1.0004, 0.9971, 1.0002, 1.0072, 1.0049, 1.0005, 1.0014, 1.0050, 1.0049, 1.0023, 1.0042, + 478, 1.0032, 1.0021, 1.0041, 1.0041, 1.0092, 1.0015, 0.9985, 1.0008, 0.9993, 1.0022, 0.9984, 1.0015, 1.0026, 1.0011, 1.0022, 1.0054, 1.0028, 1.0028, 0.9990, 1.0030, 1.0051, 1.0050, 1.0035, 1.0072, 0.9981, 0.9952, 0.9984, 1.0013, + 479, 0.9978, 0.9975, 0.9991, 1.0000, 1.0044, 0.9981, 0.9984, 1.0011, 0.9951, 0.9984, 0.9942, 0.9956, 1.0028, 1.0041, 0.9988, 0.9979, 0.9980, 0.9978, 0.9978, 1.0007, 1.0007, 1.0017, 1.0012, 1.0039, 0.9985, 1.0002, 0.9985, 1.0000, + 480, 1.0044, 1.0026, 1.0028, 1.0025, 1.0085, 1.0043, 1.0002, 1.0008, 1.0007, 1.0048, 1.0004, 1.0040, 1.0036, 1.0038, 1.0010, 1.0044, 1.0028, 1.0011, 1.0011, 1.0051, 1.0089, 1.0064, 1.0023, 1.0039, 1.0038, 1.0055, 0.9998, 1.0044, + 481, 1.0003, 1.0003, 0.9988, 0.9969, 1.0070, 1.0006, 0.9990, 1.0003, 0.9974, 0.9961, 1.0007, 1.0063, 0.9988, 0.9984, 0.9986, 0.9985, 1.0008, 0.9994, 0.9999, 1.0027, 1.0045, 1.0033, 1.0013, 1.0074, 1.0008, 1.0003, 0.9967, 0.9967, + 482, 1.0064, 1.0044, 1.0006, 1.0012, 1.0062, 1.0008, 0.9979, 0.9990, 1.0003, 1.0029, 0.9974, 0.9999, 1.0075, 1.0088, 0.9971, 0.9984, 1.0004, 1.0005, 0.9972, 1.0012, 1.0047, 1.0033, 1.0011, 1.0025, 1.0028, 1.0057, 0.9943, 0.9938, + 483, 1.0010, 1.0011, 1.0013, 1.0013, 1.0070, 1.0017, 0.9989, 1.0005, 1.0003, 1.0018, 0.9964, 0.9985, 0.9998, 1.0001, 1.0005, 1.0011, 1.0002, 0.9991, 0.9972, 0.9993, 1.0067, 1.0040, 0.9981, 1.0027, 1.0016, 1.0007, 1.0006, 1.0024, + 484, 1.0021, 1.0004, 0.9992, 0.9989, 1.0057, 1.0010, 1.0006, 1.0007, 0.9983, 1.0001, 0.9973, 0.9978, 1.0025, 1.0025, 0.9996, 1.0007, 1.0003, 0.9996, 0.9986, 1.0024, 1.0010, 1.0009, 1.0003, 1.0036, 1.0032, 1.0036, 0.9991, 1.0005, + 485, 0.9982, 0.9959, 0.9943, 0.9941, 1.0019, 0.9981, 0.9959, 0.9955, 0.9983, 1.0020, 0.9982, 0.9995, 0.9990, 0.9991, 0.9988, 0.9988, 0.9984, 0.9968, 0.9940, 1.0001, 1.0032, 1.0027, 0.9970, 1.0001, 0.9983, 0.9974, 0.9964, 0.9983, + 486, 0.9998, 0.9996, 0.9996, 0.9996, 1.0025, 0.9981, 0.9965, 0.9957, 0.9970, 0.9988, 0.9946, 0.9948, 0.9991, 0.9947, 1.0011, 0.9967, 1.0007, 0.9981, 0.9952, 0.9976, 1.0054, 1.0039, 0.9968, 0.9990, 0.9956, 0.9922, 0.9961, 0.9939, + 487, 0.9968, 0.9959, 0.9964, 0.9960, 1.0039, 1.0000, 0.9972, 0.9973, 0.9955, 0.9984, 0.9969, 0.9998, 1.0030, 1.0036, 0.9969, 0.9953, 0.9983, 0.9955, 0.9965, 0.9976, 0.9985, 0.9992, 0.9967, 1.0010, 0.9982, 0.9974, 0.9912, 0.9929, + 488, 0.9982, 0.9969, 0.9999, 0.9983, 1.0032, 0.9993, 0.9990, 0.9991, 0.9975, 0.9965, 1.0002, 1.0026, 0.9960, 0.9960, 0.9995, 1.0017, 0.9971, 0.9952, 0.9992, 1.0012, 1.0052, 1.0035, 0.9977, 0.9994, 1.0047, 1.0040, 1.0025, 1.0027, + 489, 0.9967, 0.9954, 0.9956, 0.9960, 1.0031, 1.0011, 0.9973, 0.9981, 0.9943, 0.9948, 0.9947, 0.9949, 0.9956, 0.9949, 0.9976, 0.9964, 0.9980, 0.9950, 0.9955, 0.9988, 1.0027, 1.0017, 0.9983, 0.9995, 1.0033, 1.0030, 0.9978, 0.9994, + 490, 1.0016, 1.0013, 1.0027, 1.0049, 1.0055, 1.0038, 1.0019, 1.0049, 0.9998, 1.0011, 0.9976, 1.0004, 1.0044, 1.0099, 0.9994, 1.0051, 1.0029, 1.0051, 1.0021, 1.0076, 1.0075, 1.0086, 1.0009, 1.0037, 1.0046, 1.0071, 1.0029, 1.0061, + 491, 1.0039, 1.0037, 1.0023, 1.0018, 1.0021, 1.0004, 0.9986, 0.9994, 0.9976, 0.9975, 0.9997, 1.0029, 0.9985, 0.9973, 1.0035, 1.0027, 1.0007, 1.0002, 0.9998, 1.0044, 1.0037, 1.0030, 0.9991, 1.0037, 1.0002, 0.9966, 0.9982, 0.9995, + 492, 0.9998, 0.9986, 0.9975, 0.9981, 1.0016, 1.0018, 0.9974, 0.9995, 0.9964, 0.9987, 0.9996, 1.0028, 1.0051, 1.0046, 1.0030, 0.9960, 0.9990, 0.9994, 0.9991, 1.0035, 1.0031, 1.0041, 0.9988, 1.0014, 1.0029, 1.0058, 0.9959, 0.9989, + 493, 1.0025, 1.0037, 0.9995, 1.0002, 1.0044, 1.0018, 0.9995, 0.9983, 1.0010, 1.0034, 0.9972, 0.9983, 1.0035, 1.0031, 0.9996, 1.0017, 1.0026, 1.0016, 1.0002, 1.0027, 1.0067, 1.0048, 0.9975, 1.0027, 1.0038, 1.0035, 0.9983, 1.0017, + 494, 1.0047, 1.0049, 1.0016, 1.0001, 1.0066, 1.0044, 1.0024, 1.0045, 0.9998, 1.0000, 0.9994, 1.0005, 1.0036, 1.0012, 1.0000, 1.0005, 1.0028, 1.0023, 0.9982, 1.0012, 1.0021, 1.0014, 0.9994, 1.0025, 1.0023, 1.0033, 0.9984, 0.9996, + 495, 0.9977, 0.9974, 0.9992, 0.9999, 1.0005, 0.9992, 1.0028, 0.9999, 0.9985, 0.9992, 0.9973, 0.9995, 1.0022, 1.0036, 0.9978, 0.9993, 0.9986, 0.9966, 0.9988, 1.0011, 1.0037, 1.0060, 0.9995, 1.0000, 1.0011, 1.0019, 0.9934, 0.9933, + 496, 1.0025, 1.0017, 1.0029, 1.0036, 1.0029, 1.0003, 0.9974, 1.0024, 0.9988, 0.9994, 1.0013, 1.0049, 0.9979, 0.9990, 1.0031, 1.0048, 1.0004, 0.9986, 1.0017, 1.0074, 1.0065, 1.0063, 0.9968, 0.9997, 1.0043, 1.0019, 0.9999, 0.9989, + 497, 0.9993, 0.9979, 0.9999, 0.9986, 1.0003, 0.9986, 1.0006, 1.0028, 0.9981, 0.9979, 0.9999, 1.0034, 1.0007, 1.0016, 0.9987, 1.0037, 0.9981, 0.9985, 1.0010, 1.0048, 1.0012, 1.0014, 1.0004, 1.0015, 1.0048, 1.0064, 0.9987, 0.9983, + 498, 1.0001, 0.9987, 1.0003, 1.0004, 1.0023, 1.0003, 1.0005, 1.0012, 1.0008, 1.0010, 0.9988, 0.9995, 1.0016, 1.0023, 1.0024, 1.0009, 1.0013, 1.0004, 0.9988, 1.0015, 1.0039, 1.0049, 0.9961, 0.9980, 1.0038, 1.0058, 0.9973, 0.9971, + 499, 0.9986, 0.9963, 0.9988, 0.9988, 1.0003, 0.9971, 1.0004, 1.0000, 0.9957, 0.9965, 0.9987, 0.9986, 0.9999, 0.9925, 1.0020, 0.9986, 0.9993, 0.9953, 0.9961, 0.9945, 1.0057, 1.0041, 0.9984, 0.9990, 0.9978, 0.9914, 0.9932, 0.9928, + 500, 0.9953, 0.9947, 0.9969, 0.9979, 1.0018, 0.9992, 0.9980, 0.9988, 0.9958, 0.9979, 1.0009, 1.0046, 1.0033, 1.0015, 0.9964, 0.9963, 0.9974, 0.9947, 0.9949, 0.9970, 0.9998, 1.0019, 0.9996, 1.0009, 0.9994, 0.9999, 0.9908, 0.9902, + 501, 1.0016, 0.9992, 0.9974, 0.9969, 1.0031, 0.9997, 0.9995, 0.9997, 0.9999, 0.9985, 0.9994, 1.0009, 0.9970, 0.9971, 1.0002, 1.0019, 0.9992, 0.9970, 1.0001, 1.0020, 1.0039, 1.0037, 0.9992, 1.0001, 1.0038, 1.0015, 1.0036, 1.0042, + 502, 1.0005, 0.9995, 0.9981, 0.9991, 1.0053, 1.0031, 1.0001, 1.0018, 0.9991, 0.9988, 0.9955, 0.9948, 1.0004, 1.0005, 0.9990, 0.9995, 1.0015, 0.9997, 0.9990, 0.9989, 1.0051, 1.0050, 0.9994, 1.0014, 1.0056, 1.0049, 1.0007, 1.0003, + 503, 1.0001, 1.0000, 0.9989, 0.9992, 1.0035, 1.0011, 1.0002, 1.0029, 0.9995, 0.9999, 1.0015, 1.0035, 1.0044, 1.0056, 1.0016, 1.0029, 1.0014, 1.0008, 0.9999, 1.0034, 1.0061, 1.0069, 0.9985, 1.0007, 1.0054, 1.0047, 1.0008, 1.0028, + 504, 1.0068, 1.0060, 1.0041, 1.0047, 1.0050, 1.0020, 1.0015, 1.0015, 1.0021, 1.0036, 1.0032, 1.0074, 1.0032, 1.0011, 1.0039, 1.0046, 1.0040, 1.0023, 1.0013, 1.0032, 1.0026, 1.0035, 1.0036, 1.0039, 0.9998, 0.9998, 0.9964, 0.9976, + 505, 0.9991, 0.9974, 0.9995, 1.0003, 1.0022, 1.0007, 0.9995, 0.9997, 0.9976, 0.9995, 1.0016, 1.0036, 1.0067, 1.0046, 0.9995, 0.9970, 0.9990, 0.9974, 0.9989, 1.0011, 1.0027, 1.0048, 1.0023, 1.0025, 1.0015, 1.0023, 0.9977, 0.9990, + 506, 1.0012, 1.0022, 1.0019, 1.0036, 1.0047, 1.0024, 1.0011, 0.9996, 1.0003, 1.0002, 0.9994, 1.0008, 1.0038, 1.0031, 1.0015, 1.0036, 1.0017, 0.9995, 1.0007, 1.0028, 1.0104, 1.0103, 1.0010, 1.0008, 1.0040, 1.0049, 1.0003, 1.0014, + 507, 0.9997, 0.9990, 0.9995, 1.0007, 1.0029, 1.0007, 1.0020, 1.0047, 0.9965, 0.9944, 0.9975, 0.9983, 0.9990, 0.9964, 1.0010, 1.0000, 0.9999, 0.9998, 1.0003, 1.0004, 1.0030, 1.0038, 0.9980, 0.9995, 1.0015, 0.9991, 0.9971, 0.9975, + 508, 0.9966, 0.9942, 1.0007, 1.0010, 1.0006, 0.9995, 0.9992, 1.0014, 0.9972, 0.9928, 1.0012, 1.0049, 1.0013, 1.0030, 0.9986, 0.9995, 0.9972, 0.9943, 1.0003, 1.0027, 1.0033, 1.0059, 0.9986, 0.9982, 1.0054, 1.0076, 0.9926, 0.9914, + 509, 1.0002, 0.9996, 0.9986, 0.9992, 1.0019, 1.0002, 0.9984, 0.9989, 0.9997, 1.0002, 1.0007, 1.0039, 0.9974, 0.9991, 1.0027, 1.0026, 0.9984, 0.9970, 1.0003, 1.0030, 1.0051, 1.0060, 0.9991, 0.9986, 1.0037, 1.0050, 0.9992, 1.0000, + 510, 1.0020, 1.0016, 1.0025, 1.0027, 1.0055, 1.0025, 1.0015, 1.0028, 1.0010, 1.0012, 0.9959, 0.9967, 1.0051, 1.0061, 1.0018, 1.0028, 1.0023, 1.0006, 1.0017, 1.0052, 1.0041, 1.0054, 1.0028, 1.0022, 1.0040, 1.0074, 0.9997, 1.0004, + 511, 0.9965, 0.9956, 0.9978, 0.9984, 1.0003, 0.9980, 0.9982, 0.9994, 0.9973, 1.0006, 0.9939, 0.9942, 0.9979, 0.9992, 1.0022, 1.0012, 0.9969, 0.9955, 0.9977, 0.9978, 1.0082, 1.0087, 0.9963, 0.9968, 1.0003, 1.0012, 0.9949, 0.9977, + 512, 0.9965, 0.9955, 0.9979, 0.9986, 0.9986, 0.9980, 0.9968, 0.9966, 0.9945, 0.9955, 0.9999, 1.0025, 0.9948, 0.9917, 1.0036, 0.9965, 0.9981, 0.9947, 0.9947, 0.9947, 1.0085, 1.0083, 0.9971, 0.9995, 0.9956, 0.9945, 0.9927, 0.9941, + 513, 0.9961, 0.9955, 0.9988, 0.9997, 1.0025, 1.0011, 0.9998, 1.0020, 0.9970, 0.9984, 0.9979, 0.9996, 1.0033, 1.0033, 0.9984, 0.9960, 0.9991, 0.9989, 0.9983, 0.9977, 0.9997, 1.0031, 0.9989, 0.9997, 0.9996, 1.0013, 0.9891, 0.9920, + 514, 1.0025, 1.0036, 0.9993, 1.0007, 1.0050, 1.0020, 0.9997, 1.0006, 1.0023, 1.0004, 1.0012, 1.0034, 1.0003, 1.0003, 1.0009, 1.0015, 1.0023, 1.0054, 1.0004, 1.0004, 1.0058, 1.0094, 1.0000, 0.9986, 1.0061, 1.0064, 1.0062, 1.0056, + 515, 0.9983, 0.9965, 0.9951, 0.9952, 1.0013, 0.9996, 0.9966, 0.9980, 0.9951, 0.9953, 0.9960, 0.9939, 0.9962, 0.9953, 0.9972, 0.9954, 0.9986, 0.9983, 0.9972, 0.9970, 1.0054, 1.0078, 0.9984, 0.9972, 1.0045, 1.0072, 0.9992, 0.9996, + 516, 1.0038, 1.0034, 0.9982, 0.9985, 1.0049, 1.0036, 0.9991, 1.0007, 1.0022, 1.0010, 1.0001, 1.0039, 1.0054, 1.0076, 1.0000, 1.0021, 1.0041, 1.0039, 1.0025, 1.0039, 1.0065, 1.0084, 0.9996, 0.9971, 1.0093, 1.0136, 1.0017, 1.0024, + 517, 1.0031, 1.0033, 1.0028, 1.0033, 1.0043, 1.0019, 0.9997, 1.0014, 0.9994, 1.0015, 0.9982, 0.9986, 1.0030, 0.9999, 1.0049, 1.0050, 1.0061, 1.0014, 1.0015, 1.0036, 1.0025, 1.0056, 1.0016, 1.0025, 1.0013, 1.0009, 0.9990, 1.0002, + 518, 0.9991, 0.9979, 1.0037, 1.0048, 1.0022, 1.0007, 1.0011, 1.0036, 0.9988, 0.9991, 0.9987, 1.0016, 1.0073, 1.0064, 1.0023, 0.9996, 1.0009, 1.0003, 1.0057, 1.0051, 1.0040, 1.0068, 1.0031, 1.0024, 1.0020, 1.0034, 1.0018, 0.9999, + 519, 1.0016, 1.0019, 0.9997, 1.0012, 1.0020, 1.0000, 0.9994, 1.0005, 1.0003, 1.0005, 1.0006, 1.0023, 1.0007, 1.0001, 1.0008, 1.0046, 1.0019, 0.9989, 1.0006, 1.0022, 1.0097, 1.0107, 0.9995, 0.9989, 1.0022, 1.0024, 1.0008, 1.0014, + 520, 1.0015, 1.0010, 0.9984, 0.9996, 1.0035, 0.9996, 1.0010, 1.0029, 0.9988, 0.9985, 1.0009, 1.0037, 1.0032, 0.9993, 1.0017, 0.9998, 1.0011, 1.0008, 0.9997, 0.9989, 1.0018, 1.0035, 0.9988, 0.9954, 1.0016, 1.0020, 0.9977, 0.9987, + 521, 1.0003, 0.9999, 0.9980, 0.9975, 1.0024, 1.0005, 0.9982, 1.0001, 0.9987, 1.0004, 0.9983, 0.9990, 1.0037, 1.0057, 0.9993, 0.9978, 1.0010, 0.9997, 1.0008, 1.0028, 1.0028, 1.0070, 1.0024, 1.0000, 1.0031, 1.0040, 0.9953, 0.9936, + 522, 1.0049, 1.0045, 1.0006, 1.0018, 1.0048, 1.0029, 0.9999, 0.9998, 1.0031, 1.0027, 0.9994, 0.9996, 1.0017, 1.0024, 1.0031, 1.0029, 1.0024, 1.0021, 1.0004, 1.0022, 1.0046, 1.0076, 1.0034, 1.0016, 1.0041, 1.0046, 1.0018, 1.0003, + 523, 0.9990, 0.9998, 0.9995, 1.0016, 1.0028, 1.0006, 0.9987, 1.0006, 0.9979, 0.9977, 0.9968, 0.9975, 1.0014, 1.0016, 1.0017, 0.9995, 1.0003, 0.9984, 1.0022, 1.0037, 1.0036, 1.0085, 1.0029, 1.0024, 1.0036, 1.0058, 0.9987, 0.9986, + 524, 0.9988, 0.9999, 0.9998, 1.0014, 0.9999, 0.9983, 0.9964, 0.9955, 0.9982, 0.9995, 0.9989, 1.0010, 0.9984, 0.9977, 1.0000, 1.0001, 0.9992, 0.9979, 0.9989, 0.9999, 1.0082, 1.0113, 1.0009, 0.9986, 0.9988, 0.9989, 0.9991, 1.0020, + 525, 0.9989, 0.9963, 0.9960, 0.9958, 1.0003, 0.9973, 0.9979, 0.9987, 0.9976, 0.9985, 0.9970, 0.9961, 0.9959, 0.9922, 1.0029, 0.9978, 0.9985, 0.9950, 0.9988, 0.9971, 1.0066, 1.0087, 0.9979, 0.9974, 0.9944, 0.9899, 0.9942, 0.9930, + 526, 0.9122, 0.8968, 0.9020, 0.8982, 0.9078, 0.9378, 0.9414, 0.9135, 0.9320, 0.9374, 0.9500, 0.9119, 0.9273, 0.8941, 0.9695, 0.9072, 0.8950, 0.8435, 0.9217, 0.8859, 0.9018, 0.9464, 0.9538, 0.9557, 0.9412, 0.8893, 0.9677, 0.9786, + 527, 1.0010, 0.9996, 0.9936, 0.9958, 1.0026, 1.0034, 1.0081, 1.0076, 1.0016, 1.0001, 1.0027, 1.0025, 0.9957, 0.9871, 1.0029, 0.9990, 0.9943, 0.9928, 1.0075, 1.0102, 1.0061, 1.0139, 1.0074, 1.0090, 1.0143, 1.0090, 1.0115, 1.0113, + 528, 0.9994, 1.0001, 1.0071, 1.0106, 1.0058, 1.0056, 1.0051, 1.0053, 1.0054, 1.0062, 0.9974, 0.9949, 1.0063, 1.0043, 1.0052, 0.9995, 1.0032, 1.0040, 1.0067, 1.0104, 1.0081, 1.0160, 1.0059, 1.0081, 1.0153, 1.0151, 1.0103, 1.0083, + 529, 0.9966, 0.9981, 1.0050, 1.0090, 1.0040, 1.0034, 1.0029, 1.0037, 1.0020, 1.0030, 0.9999, 0.9996, 1.0031, 0.9999, 1.0026, 1.0003, 1.0014, 1.0007, 1.0056, 1.0081, 1.0085, 1.0160, 1.0048, 1.0082, 1.0119, 1.0133, 1.0186, 1.0083, + 530, 1.0001, 1.0002, 1.0062, 1.0083, 1.0047, 1.0037, 1.0036, 1.0047, 1.0014, 1.0020, 1.0009, 1.0021, 1.0046, 1.0035, 1.0025, 1.0009, 1.0049, 1.0026, 1.0077, 1.0109, 1.0105, 1.0156, 1.0048, 1.0054, 1.0129, 1.0131, 1.0144, 1.0074, + 531, 1.0001, 0.9998, 0.9976, 1.0010, 1.0033, 1.0011, 1.0013, 1.0026, 1.0025, 1.0048, 1.0013, 1.0001, 1.0044, 1.0026, 1.0025, 0.9997, 1.0031, 1.0023, 1.0031, 1.0060, 1.0066, 1.0123, 1.0019, 1.0035, 1.0125, 1.0123, 1.0041, 1.0058, + 532, 1.0026, 1.0029, 1.0072, 1.0100, 1.0077, 1.0051, 1.0041, 1.0060, 1.0014, 1.0049, 0.9994, 0.9983, 1.0017, 0.9997, 1.0036, 1.0041, 1.0061, 1.0066, 1.0028, 1.0052, 1.0043, 1.0113, 1.0055, 1.0062, 1.0090, 1.0090, 1.0062, 1.0065, + 533, 0.9994, 0.9987, 1.0031, 1.0056, 1.0042, 1.0033, 1.0014, 1.0027, 1.0032, 1.0061, 1.0001, 1.0006, 1.0071, 1.0040, 1.0017, 0.9998, 1.0047, 1.0039, 1.0018, 1.0055, 1.0053, 1.0092, 1.0050, 1.0060, 1.0073, 1.0089, 1.0045, 1.0058, + 534, 0.9991, 0.9985, 1.0004, 1.0033, 1.0033, 1.0003, 0.9999, 0.9994, 1.0013, 1.0014, 0.9994, 0.9999, 1.0015, 0.9981, 1.0051, 0.9983, 1.0041, 1.0018, 0.9988, 0.9988, 1.0105, 1.0128, 1.0029, 1.0018, 1.0092, 1.0084, 1.0076, 1.0078, + 535, 0.9990, 0.9976, 0.9960, 0.9967, 1.0004, 0.9982, 0.9988, 0.9984, 0.9984, 0.9971, 0.9971, 0.9943, 0.9964, 0.9936, 0.9983, 0.9966, 1.0005, 0.9963, 0.9995, 1.0011, 1.0020, 1.0081, 1.0008, 0.9987, 1.0059, 1.0062, 1.0019, 1.0028, + 536, 1.0023, 1.0029, 1.0017, 1.0065, 1.0073, 1.0035, 1.0019, 1.0040, 1.0033, 1.0049, 1.0019, 1.0009, 1.0076, 1.0092, 1.0036, 1.0048, 1.0058, 1.0061, 1.0038, 1.0069, 1.0089, 1.0117, 1.0016, 1.0020, 1.0086, 1.0122, 1.0019, 1.0014, + 537, 1.0039, 1.0029, 1.0076, 1.0100, 1.0056, 1.0036, 1.0043, 1.0065, 1.0052, 1.0057, 1.0030, 1.0035, 1.0067, 1.0039, 1.0076, 1.0078, 1.0056, 1.0039, 1.0087, 1.0138, 1.0019, 1.0058, 1.0067, 1.0029, 1.0090, 1.0099, 1.0045, 1.0059, + 538, 1.0029, 1.0022, 1.0050, 1.0081, 1.0055, 1.0030, 1.0025, 1.0043, 1.0037, 1.0036, 1.0051, 1.0066, 1.0102, 1.0078, 1.0046, 1.0033, 1.0064, 1.0042, 1.0059, 1.0093, 0.9997, 1.0048, 1.0062, 1.0059, 1.0094, 1.0131, 1.0030, 1.0034, + 539, 1.0007, 1.0006, 0.9990, 1.0035, 1.0019, 0.9998, 0.9971, 0.9968, 1.0000, 1.0045, 1.0016, 1.0027, 1.0025, 0.9998, 1.0012, 0.9986, 1.0013, 0.9991, 0.9992, 1.0002, 1.0096, 1.0112, 1.0003, 1.0006, 0.9989, 1.0021, 0.9997, 1.0007, + 540, 0.9984, 0.9985, 0.9965, 0.9990, 1.0020, 0.9996, 0.9991, 1.0004, 0.9981, 0.9993, 0.9970, 0.9961, 1.0004, 0.9952, 1.0021, 0.9981, 1.0016, 1.0001, 0.9979, 0.9961, 1.0076, 1.0105, 0.9985, 1.0010, 0.9967, 0.9937, 0.9989, 1.0005, + 541, 0.9993, 0.9992, 0.9986, 1.0018, 1.0046, 1.0028, 0.9997, 1.0015, 1.0007, 1.0019, 0.9993, 0.9976, 1.0081, 1.0103, 1.0004, 0.9985, 1.0036, 1.0017, 1.0011, 1.0031, 1.0063, 1.0113, 1.0019, 1.0037, 1.0033, 1.0050, 0.9964, 0.9966, + 542, 1.0049, 1.0059, 1.0014, 1.0034, 1.0071, 1.0038, 1.0002, 1.0022, 1.0045, 1.0030, 1.0079, 1.0082, 1.0054, 1.0027, 1.0042, 1.0044, 1.0060, 1.0042, 1.0026, 1.0051, 1.0040, 1.0073, 1.0042, 1.0021, 1.0093, 1.0128, 1.0070, 1.0083, + 543, 1.0028, 1.0052, 0.9964, 1.0008, 1.0054, 1.0043, 0.9986, 0.9999, 1.0021, 1.0054, 0.9990, 1.0001, 1.0072, 1.0059, 1.0009, 1.0008, 1.0039, 1.0066, 0.9998, 1.0027, 0.9977, 1.0055, 1.0015, 1.0024, 1.0035, 1.0087, 1.0010, 1.0047, + 544, 1.0059, 1.0064, 1.0019, 1.0043, 1.0082, 1.0047, 1.0011, 1.0036, 1.0059, 1.0076, 0.9997, 0.9992, 1.0093, 1.0093, 1.0036, 1.0056, 1.0089, 1.0081, 1.0031, 1.0048, 1.0100, 1.0128, 1.0040, 1.0023, 1.0079, 1.0127, 1.0051, 1.0048, + 545, 1.0039, 1.0044, 1.0028, 1.0056, 1.0054, 1.0034, 1.0014, 1.0020, 1.0011, 1.0001, 1.0013, 1.0019, 1.0032, 1.0014, 1.0054, 1.0074, 1.0054, 1.0039, 0.9998, 1.0024, 1.0053, 1.0076, 1.0042, 1.0031, 1.0024, 1.0042, 1.0012, 1.0043, + 546, 1.0026, 1.0037, 1.0011, 1.0054, 1.0054, 1.0025, 1.0006, 1.0028, 1.0029, 1.0044, 0.9999, 1.0013, 1.0071, 1.0057, 1.0023, 0.9995, 1.0039, 1.0035, 1.0011, 1.0026, 1.0058, 1.0115, 1.0036, 1.0031, 1.0038, 1.0085, 1.0026, 1.0021, + 547, 0.9996, 1.0006, 0.9995, 1.0012, 1.0008, 0.9987, 0.9981, 0.9989, 1.0002, 1.0019, 1.0003, 1.0015, 0.9958, 0.9958, 1.0028, 0.9990, 0.9999, 0.9969, 0.9952, 0.9964, 1.0029, 1.0062, 0.9988, 0.9980, 1.0006, 1.0011, 1.0036, 1.0039, + 548, 0.9982, 0.9960, 0.9960, 0.9983, 0.9996, 0.9981, 0.9983, 0.9992, 0.9999, 0.9985, 0.9991, 0.9984, 1.0005, 0.9988, 1.0000, 0.9949, 1.0004, 0.9986, 0.9989, 1.0005, 1.0055, 1.0103, 0.9957, 0.9917, 1.0036, 1.0012, 1.0059, 1.0008, + 549, 1.0026, 1.0018, 0.9976, 1.0001, 1.0049, 1.0015, 1.0018, 1.0032, 1.0000, 0.9996, 1.0004, 1.0014, 1.0041, 1.0049, 1.0012, 0.9988, 1.0002, 0.9996, 0.9981, 1.0007, 1.0060, 1.0077, 1.0011, 0.9996, 1.0059, 1.0114, 1.0011, 0.9967, + 550, 1.0068, 1.0068, 1.0068, 1.0087, 1.0049, 1.0026, 1.0014, 1.0019, 1.0038, 1.0041, 1.0021, 1.0024, 1.0061, 1.0028, 1.0058, 1.0063, 1.0068, 1.0046, 1.0037, 1.0072, 0.9995, 1.0041, 1.0073, 1.0032, 1.0097, 1.0125, 1.0029, 1.0056, + 551, 1.0006, 1.0003, 0.9988, 1.0020, 1.0034, 1.0020, 1.0005, 1.0007, 1.0018, 1.0024, 0.9986, 0.9980, 1.0071, 1.0068, 1.0021, 1.0010, 1.0024, 1.0018, 1.0001, 1.0028, 1.0012, 1.0039, 1.0053, 1.0047, 1.0048, 1.0085, 1.0020, 1.0038, + 552, 0.9996, 0.9976, 1.0020, 1.0021, 1.0019, 0.9985, 0.9993, 0.9984, 1.0018, 1.0007, 1.0028, 1.0025, 1.0042, 1.0006, 1.0040, 1.0031, 1.0040, 0.9985, 1.0018, 1.0016, 1.0137, 1.0131, 1.0023, 0.9983, 1.0014, 1.0000, 1.0010, 1.0018, + 553, 0.9951, 0.9941, 0.9940, 0.9980, 0.9960, 0.9965, 0.9976, 0.9982, 0.9975, 0.9969, 1.0000, 0.9993, 0.9955, 0.9922, 1.0013, 1.0045, 0.9976, 0.9971, 0.9939, 0.9948, 1.0086, 1.0096, 0.9991, 0.9963, 0.9945, 0.9910, 0.9966, 0.9999, + 554, 0.9989, 0.9982, 0.9973, 0.9993, 1.0014, 0.9991, 0.9992, 1.0015, 0.9996, 0.9988, 0.9998, 0.9976, 1.0059, 1.0060, 0.9996, 1.0020, 1.0017, 0.9990, 0.9998, 1.0040, 1.0056, 1.0066, 1.0015, 1.0005, 1.0017, 1.0026, 0.9949, 0.9934, + 555, 1.0020, 1.0019, 1.0006, 1.0034, 1.0018, 1.0006, 0.9997, 0.9998, 1.0013, 1.0015, 1.0007, 1.0013, 1.0011, 0.9983, 1.0031, 1.0021, 1.0022, 0.9998, 0.9993, 1.0017, 0.9985, 1.0028, 1.0017, 0.9993, 1.0053, 1.0060, 1.0079, 1.0077, + 556, 0.9998, 0.9980, 0.9980, 1.0007, 1.0031, 1.0014, 1.0003, 1.0017, 1.0010, 1.0002, 1.0001, 1.0003, 1.0053, 1.0038, 1.0028, 1.0003, 1.0024, 1.0024, 0.9987, 1.0013, 0.9984, 1.0035, 1.0025, 1.0010, 1.0056, 1.0069, 1.0020, 1.0028, + 557, 1.0026, 1.0028, 1.0003, 1.0023, 1.0053, 1.0025, 1.0010, 1.0020, 1.0023, 1.0025, 1.0049, 1.0055, 1.0047, 1.0052, 1.0040, 1.0035, 1.0051, 1.0041, 1.0013, 1.0041, 1.0074, 1.0092, 1.0019, 0.9983, 1.0059, 1.0104, 1.0025, 1.0036, + 558, 1.0033, 1.0038, 1.0006, 1.0037, 1.0030, 1.0015, 1.0010, 1.0027, 1.0015, 1.0002, 1.0018, 1.0027, 0.9996, 0.9979, 1.0047, 1.0031, 1.0050, 1.0026, 1.0009, 1.0020, 1.0055, 1.0073, 1.0041, 1.0030, 1.0018, 1.0014, 1.0029, 1.0032, + 559, 0.9996, 0.9986, 0.9972, 1.0014, 1.0007, 0.9999, 0.9969, 0.9991, 0.9976, 0.9987, 0.9978, 0.9975, 1.0004, 0.9987, 1.0001, 0.9973, 0.9986, 0.9964, 0.9976, 1.0008, 0.9985, 1.0018, 0.9997, 1.0005, 0.9989, 1.0006, 0.9980, 0.9984, + 560, 1.0047, 0.9991, 0.9989, 1.0018, 1.0012, 1.0004, 0.9972, 0.9981, 1.0018, 1.0024, 0.9991, 0.9996, 1.0012, 0.9990, 1.0015, 1.0003, 1.0015, 0.9978, 0.9969, 0.9959, 1.0048, 1.0071, 0.9979, 0.9974, 1.0040, 1.0045, 1.0013, 1.0026, + 561, 0.9988, 0.9964, 0.9920, 0.9939, 0.9996, 0.9997, 0.9969, 0.9985, 0.9978, 0.9967, 1.0009, 0.9997, 0.9980, 0.9962, 1.0017, 0.9944, 0.9994, 0.9955, 0.9926, 0.9951, 1.0040, 1.0052, 0.9964, 0.9954, 1.0022, 1.0043, 0.9975, 0.9999, + 562, 1.0009, 1.0001, 0.9952, 0.9984, 1.0035, 1.0006, 1.0001, 1.0028, 0.9992, 0.9981, 1.0002, 1.0009, 1.0055, 1.0069, 1.0009, 0.9999, 1.0027, 1.0015, 0.9982, 1.0005, 1.0005, 1.0030, 0.9992, 0.9961, 1.0058, 1.0111, 0.9977, 0.9965, + 563, 1.0021, 1.0029, 0.9984, 1.0006, 1.0011, 1.0004, 0.9985, 0.9981, 1.0001, 1.0013, 1.0022, 1.0017, 1.0013, 0.9978, 1.0026, 1.0000, 1.0016, 0.9994, 0.9986, 1.0003, 1.0006, 1.0038, 1.0014, 0.9973, 1.0015, 1.0026, 1.0026, 1.0014, + 564, 1.0011, 1.0010, 1.0002, 1.0035, 1.0015, 1.0002, 0.9990, 1.0013, 1.0012, 1.0021, 0.9975, 0.9973, 1.0058, 1.0049, 1.0033, 1.0012, 1.0028, 1.0019, 0.9992, 1.0019, 0.9990, 1.0034, 1.0029, 1.0019, 1.0042, 1.0079, 1.0019, 0.9999, + 565, 0.9995, 0.9983, 1.0000, 1.0038, 0.9989, 0.9979, 0.9967, 0.9983, 1.0000, 1.0000, 0.9984, 0.9979, 1.0020, 0.9984, 1.0022, 0.9995, 0.9987, 0.9979, 0.9977, 0.9981, 1.0060, 1.0075, 0.9998, 0.9971, 0.9986, 0.9987, 0.9986, 0.9998, + 566, 1.0010, 0.9996, 0.9961, 0.9987, 0.9989, 0.9998, 0.9986, 1.0006, 0.9986, 0.9977, 1.0003, 1.0009, 1.0005, 0.9917, 1.0028, 0.9963, 1.0004, 0.9980, 0.9959, 0.9941, 1.0063, 1.0078, 0.9970, 0.9953, 0.9956, 0.9912, 0.9955, 0.9976, + 567, 0.9992, 0.9984, 0.9959, 0.9993, 1.0007, 1.0005, 0.9990, 1.0001, 0.9997, 0.9994, 0.9992, 0.9972, 1.0050, 1.0062, 1.0004, 0.9971, 1.0001, 0.9977, 0.9960, 0.9986, 1.0003, 1.0039, 0.9983, 0.9947, 0.9988, 0.9969, 0.9947, 0.9926, + 568, 1.0022, 1.0019, 1.0013, 1.0043, 1.0022, 1.0014, 1.0016, 1.0027, 1.0013, 1.0009, 1.0042, 1.0060, 1.0016, 0.9977, 1.0034, 1.0029, 1.0043, 1.0025, 1.0036, 1.0037, 0.9981, 1.0031, 1.0034, 0.9983, 1.0069, 1.0087, 1.0065, 1.0059, + 569, 1.0031, 1.0007, 0.9989, 1.0019, 1.0028, 1.0007, 1.0011, 1.0027, 1.0006, 1.0002, 0.9983, 0.9969, 1.0060, 1.0022, 1.0042, 1.0040, 1.0037, 1.0013, 1.0008, 0.9999, 0.9975, 1.0007, 1.0044, 0.9998, 1.0034, 1.0049, 1.0012, 1.0008, + 570, 1.0081, 1.0096, 1.0021, 1.0059, 1.0065, 1.0056, 1.0027, 1.0066, 1.0048, 1.0058, 1.0046, 1.0065, 1.0095, 1.0105, 1.0073, 1.0087, 1.0076, 1.0114, 1.0038, 1.0048, 1.0060, 1.0107, 1.0047, 1.0022, 1.0060, 1.0096, 1.0062, 1.0065, + 571, 1.0025, 1.0007, 1.0019, 1.0056, 1.0007, 1.0003, 1.0004, 1.0026, 0.9994, 0.9980, 1.0039, 1.0041, 0.9976, 0.9935, 1.0058, 1.0029, 1.0026, 1.0013, 1.0033, 1.0018, 1.0037, 1.0048, 1.0020, 0.9986, 0.9964, 0.9929, 0.9986, 1.0019, + 572, 0.9978, 0.9956, 0.9977, 1.0014, 1.0003, 0.9999, 0.9978, 1.0001, 0.9987, 0.9994, 1.0036, 1.0061, 1.0011, 1.0028, 1.0027, 0.9973, 0.9990, 0.9991, 1.0012, 0.9980, 1.0011, 1.0052, 1.0015, 0.9989, 1.0020, 1.0029, 0.9997, 1.0006, + 573, 0.9985, 0.9982, 0.9936, 0.9949, 1.0021, 1.0018, 0.9983, 0.9997, 1.0003, 1.0032, 0.9983, 0.9976, 0.9988, 0.9970, 1.0005, 0.9985, 1.0011, 0.9993, 0.9999, 0.9977, 1.0042, 1.0067, 0.9987, 0.9926, 1.0072, 1.0108, 1.0027, 1.0037, + 574, 0.9980, 0.9960, 0.9955, 0.9970, 0.9984, 0.9988, 0.9988, 1.0004, 0.9975, 0.9959, 0.9965, 0.9942, 0.9981, 0.9951, 1.0004, 0.9958, 0.9996, 0.9971, 0.9978, 0.9939, 1.0021, 1.0066, 1.0016, 0.9962, 1.0008, 1.0025, 1.0002, 1.0001, + 575, 0.9939, 0.9934, 0.9944, 0.9973, 1.0003, 0.9991, 0.9987, 1.0021, 0.9968, 0.9939, 1.0000, 1.0007, 1.0001, 1.0036, 1.0013, 0.9976, 0.9972, 0.9949, 0.9985, 0.9972, 1.0016, 1.0053, 1.0002, 0.9985, 1.0001, 1.0037, 0.9964, 0.9938, + 576, 1.0042, 1.0023, 1.0017, 1.0052, 1.0022, 1.0015, 0.9995, 1.0014, 1.0006, 1.0010, 1.0032, 1.0035, 1.0013, 0.9991, 1.0049, 1.0020, 1.0028, 1.0014, 1.0044, 1.0020, 1.0034, 1.0056, 1.0043, 0.9993, 1.0036, 1.0062, 1.0039, 1.0044, + 577, 1.0006, 1.0004, 0.9981, 0.9997, 1.0019, 0.9999, 0.9991, 1.0009, 1.0008, 1.0010, 1.0001, 1.0008, 1.0037, 1.0031, 1.0028, 0.9987, 1.0000, 0.9978, 1.0003, 0.9990, 0.9969, 1.0022, 1.0041, 1.0005, 1.0043, 1.0056, 1.0018, 1.0006, + 578, 1.0047, 1.0028, 0.9978, 1.0000, 1.0039, 1.0021, 0.9968, 0.9981, 1.0028, 1.0059, 1.0006, 0.9981, 1.0051, 1.0034, 1.0033, 0.9974, 1.0031, 1.0021, 0.9992, 0.9970, 1.0075, 1.0096, 1.0050, 0.9987, 0.9986, 0.9987, 1.0023, 1.0002, + 579, 0.9976, 0.9961, 0.9920, 0.9950, 0.9990, 0.9988, 0.9951, 0.9965, 0.9967, 0.9975, 0.9981, 0.9970, 0.9956, 0.9893, 1.0010, 0.9917, 0.9990, 0.9958, 0.9953, 0.9905, 1.0032, 1.0061, 0.9988, 0.9955, 0.9926, 0.9904, 0.9962, 0.9933, + 580, 0.9966, 0.9965, 0.9946, 0.9978, 1.0004, 0.9999, 0.9958, 1.0001, 0.9992, 0.9987, 0.9986, 0.9977, 1.0048, 1.0059, 0.9982, 0.9946, 0.9996, 0.9981, 0.9970, 0.9942, 1.0015, 1.0082, 1.0006, 0.9958, 0.9981, 0.9997, 0.9964, 0.9925, + 581, 1.0028, 1.0018, 0.9998, 1.0040, 1.0028, 1.0005, 0.9994, 1.0016, 1.0002, 1.0014, 1.0009, 1.0012, 1.0006, 0.9983, 1.0055, 1.0025, 1.0021, 1.0003, 1.0035, 1.0013, 1.0021, 1.0053, 1.0038, 1.0003, 1.0051, 1.0057, 1.0063, 1.0055, + 582, 1.0019, 1.0023, 1.0005, 1.0033, 1.0025, 1.0008, 1.0002, 1.0014, 1.0031, 1.0016, 0.9976, 0.9975, 1.0046, 1.0023, 1.0048, 1.0024, 1.0018, 1.0012, 1.0008, 0.9990, 0.9992, 1.0037, 1.0043, 0.9994, 1.0035, 1.0046, 1.0002, 1.0019, + 583, 1.0062, 1.0058, 1.0007, 1.0033, 1.0056, 1.0033, 0.9996, 1.0031, 1.0032, 1.0056, 1.0013, 1.0018, 1.0040, 1.0066, 1.0055, 1.0060, 1.0056, 1.0045, 1.0007, 0.9995, 1.0060, 1.0091, 1.0031, 0.9969, 1.0020, 1.0068, 1.0043, 1.0017, + 584, 1.0041, 1.0030, 1.0019, 1.0054, 1.0036, 1.0025, 1.0007, 1.0027, 1.0015, 0.9995, 1.0047, 1.0067, 1.0007, 0.9987, 1.0064, 1.0026, 1.0042, 1.0044, 1.0006, 1.0006, 1.0066, 1.0081, 1.0025, 0.9989, 0.9999, 0.9988, 1.0034, 1.0000, + 585, 0.9960, 0.9959, 0.9956, 0.9978, 0.9983, 0.9971, 0.9972, 0.9992, 0.9974, 0.9983, 0.9993, 0.9991, 0.9991, 0.9990, 0.9998, 0.9957, 0.9972, 0.9955, 0.9988, 0.9952, 1.0029, 1.0069, 1.0019, 0.9978, 0.9979, 1.0019, 1.0015, 0.9996, + 586, 0.9997, 0.9985, 0.9962, 0.9985, 1.0001, 0.9987, 0.9963, 0.9968, 1.0007, 0.9999, 0.9955, 0.9953, 0.9983, 0.9977, 1.0015, 0.9980, 0.9984, 0.9948, 0.9989, 0.9963, 1.0097, 1.0128, 1.0003, 0.9949, 1.0029, 1.0032, 1.0059, 1.0024, + 587, 0.9966, 0.9950, 0.9901, 0.9925, 0.9968, 0.9944, 0.9950, 0.9975, 0.9957, 0.9934, 0.9953, 0.9924, 0.9919, 0.9933, 0.9992, 0.9919, 0.9952, 0.9913, 0.9970, 0.9934, 1.0030, 1.0058, 1.0005, 0.9959, 0.9961, 0.9970, 1.0036, 1.0001, + 588, 0.9993, 0.9998, 0.9971, 1.0003, 1.0012, 0.9998, 0.9978, 1.0025, 1.0008, 0.9991, 0.9987, 0.9959, 1.0029, 1.0036, 1.0024, 0.9989, 1.0010, 0.9995, 0.9980, 0.9970, 1.0024, 1.0062, 1.0023, 0.9971, 1.0017, 1.0065, 0.9987, 0.9966, + 589, 1.0080, 1.0090, 1.0026, 1.0057, 1.0048, 1.0020, 1.0010, 1.0007, 1.0047, 1.0038, 1.0030, 1.0041, 1.0038, 1.0022, 1.0074, 1.0041, 1.0053, 1.0052, 1.0053, 1.0043, 1.0032, 1.0065, 1.0066, 1.0008, 1.0046, 1.0087, 1.0066, 1.0029, + 590, 1.0039, 1.0030, 1.0013, 1.0041, 1.0031, 1.0015, 1.0002, 1.0017, 1.0030, 1.0040, 1.0004, 1.0004, 1.0085, 1.0064, 1.0052, 1.0016, 1.0029, 1.0023, 1.0016, 1.0013, 0.9983, 1.0037, 1.0084, 1.0029, 1.0026, 1.0071, 1.0062, 1.0022, + 591, 0.9996, 0.9981, 0.9980, 1.0009, 0.9999, 0.9990, 0.9970, 0.9996, 0.9996, 1.0017, 0.9973, 0.9955, 1.0005, 0.9995, 1.0027, 0.9979, 1.0004, 0.9988, 0.9994, 0.9994, 1.0042, 1.0066, 1.0030, 0.9970, 0.9945, 0.9966, 1.0016, 0.9991, + 592, 0.9956, 0.9941, 0.9944, 0.9984, 0.9990, 0.9975, 0.9981, 1.0015, 0.9956, 0.9944, 1.0015, 1.0026, 0.9929, 0.9935, 1.0032, 0.9976, 0.9970, 0.9934, 0.9970, 0.9954, 1.0082, 1.0095, 1.0009, 0.9972, 0.9949, 0.9952, 0.9991, 0.9961, + 593, 0.9971, 0.9947, 0.9970, 1.0000, 0.9990, 0.9978, 0.9960, 0.9992, 0.9977, 0.9964, 0.9980, 0.9985, 1.0033, 1.0027, 1.0009, 0.9980, 0.9978, 0.9949, 0.9975, 0.9951, 0.9976, 1.0031, 1.0006, 0.9958, 0.9959, 0.9992, 0.9975, 0.9926, + 594, 1.0045, 1.0058, 1.0010, 1.0026, 1.0028, 1.0018, 1.0007, 1.0017, 1.0038, 1.0043, 1.0016, 1.0028, 1.0022, 1.0012, 1.0061, 1.0030, 1.0029, 1.0030, 1.0034, 1.0027, 0.9993, 1.0028, 1.0055, 0.9987, 1.0041, 1.0058, 1.0093, 1.0064, + 595, 0.9961, 0.9944, 0.9953, 0.9981, 0.9991, 0.9980, 0.9974, 1.0014, 0.9959, 0.9960, 0.9986, 0.9982, 1.0005, 1.0011, 1.0020, 0.9972, 0.9987, 0.9958, 0.9977, 0.9980, 0.9946, 0.9986, 1.0028, 0.9984, 0.9991, 1.0024, 1.0037, 0.9996, + 596, 1.0012, 1.0025, 1.0008, 1.0052, 1.0035, 1.0017, 0.9992, 1.0019, 1.0013, 0.9999, 1.0010, 1.0013, 1.0032, 1.0054, 1.0065, 1.0056, 1.0036, 1.0038, 1.0024, 1.0036, 1.0022, 1.0049, 1.0060, 0.9999, 1.0043, 1.0093, 1.0059, 1.0052, + 597, 1.0030, 1.0027, 0.9997, 1.0037, 1.0043, 1.0022, 1.0019, 1.0068, 1.0002, 1.0002, 1.0012, 1.0035, 1.0007, 0.9983, 1.0060, 1.0046, 1.0029, 1.0038, 1.0009, 0.9995, 1.0023, 1.0052, 1.0039, 1.0009, 0.9986, 1.0013, 1.0042, 0.9995, + 598, 0.9989, 0.9977, 0.9987, 1.0010, 1.0009, 1.0000, 0.9988, 1.0030, 0.9987, 0.9989, 0.9981, 0.9973, 1.0026, 1.0025, 1.0028, 0.9997, 0.9994, 0.9974, 0.9982, 0.9998, 1.0018, 1.0050, 1.0051, 1.0011, 0.9974, 1.0020, 1.0040, 1.0005, + 599, 0.9963, 0.9957, 0.9933, 0.9945, 0.9977, 0.9963, 0.9953, 0.9989, 0.9979, 0.9975, 1.0002, 1.0012, 0.9942, 0.9931, 1.0003, 0.9948, 0.9972, 0.9945, 0.9959, 0.9951, 1.0049, 1.0059, 0.9992, 0.9933, 0.9991, 0.9994, 1.0066, 1.0011, + 600, 0.9968, 0.9953, 0.9925, 0.9946, 0.9990, 0.9980, 0.9967, 0.9978, 0.9974, 0.9941, 0.9975, 0.9963, 0.9953, 0.9933, 1.0016, 0.9933, 0.9992, 0.9955, 0.9968, 0.9948, 1.0022, 1.0043, 1.0008, 0.9949, 1.0007, 1.0011, 1.0075, 1.0007, + 601, 1.0041, 1.0046, 1.0007, 1.0031, 1.0029, 1.0009, 0.9979, 1.0005, 0.9995, 0.9972, 0.9994, 0.9993, 1.0039, 1.0053, 1.0011, 0.9995, 1.0008, 1.0010, 0.9999, 1.0002, 1.0015, 1.0011, 1.0031, 0.9982, 1.0040, 1.0087, 1.0059, 0.9965, + 602, 1.0048, 1.0082, 1.0039, 1.0069, 1.0053, 1.0035, 1.0022, 1.0046, 1.0035, 1.0028, 1.0028, 1.0026, 1.0066, 1.0032, 1.0086, 1.0038, 1.0053, 1.0068, 1.0051, 1.0053, 1.0021, 1.0048, 1.0067, 1.0006, 1.0045, 1.0075, 1.0129, 1.0033, + 603, 0.9987, 0.9978, 0.9992, 1.0016, 1.0014, 0.9995, 0.9985, 1.0023, 0.9995, 0.9999, 1.0007, 1.0018, 1.0033, 1.0029, 1.0039, 0.9994, 1.0002, 0.9984, 1.0012, 1.0016, 0.9972, 1.0007, 1.0041, 0.9991, 1.0007, 1.0046, 1.0097, 0.9996, + 604, 0.9968, 0.9964, 0.9980, 0.9998, 0.9991, 0.9981, 0.9977, 1.0000, 0.9995, 1.0004, 1.0021, 1.0036, 1.0006, 0.9992, 1.0054, 0.9977, 0.9997, 0.9991, 0.9993, 0.9997, 1.0068, 1.0062, 1.0005, 0.9961, 0.9970, 0.9996, 1.0080, 0.9987, + 605, 0.9981, 0.9965, 0.9977, 0.9998, 1.0007, 0.9986, 0.9996, 1.0015, 0.9962, 0.9940, 0.9988, 0.9981, 0.9984, 0.9916, 1.0034, 0.9972, 0.9994, 0.9967, 0.9975, 0.9960, 1.0056, 1.0047, 1.0005, 0.9962, 0.9945, 0.9947, 1.0053, 0.9945, + 606, 1.0007, 0.9987, 0.9977, 1.0017, 1.0025, 1.0006, 0.9994, 1.0021, 0.9991, 0.9977, 0.9977, 0.9979, 1.0070, 1.0056, 1.0021, 0.9975, 1.0010, 1.0005, 0.9973, 0.9961, 1.0031, 1.0038, 1.0040, 0.9972, 1.0031, 1.0046, 1.0017, 0.9945, + 607, 1.0016, 1.0009, 0.9979, 1.0004, 1.0007, 1.0001, 0.9995, 1.0003, 1.0002, 1.0006, 1.0027, 1.0081, 0.9993, 0.9978, 1.0039, 0.9994, 1.0006, 1.0008, 1.0000, 1.0020, 0.9992, 1.0002, 1.0023, 0.9983, 1.0046, 1.0084, 1.0088, 1.0043, + 608, 0.9961, 0.9957, 0.9972, 1.0007, 1.0018, 0.9994, 0.9982, 1.0014, 0.9993, 0.9978, 1.0011, 1.0012, 1.0037, 1.0030, 1.0033, 0.9999, 1.0011, 0.9995, 1.0002, 1.0003, 1.0013, 1.0020, 1.0047, 0.9987, 1.0036, 1.0074, 1.0045, 1.0005, + 609, 0.9998, 0.9990, 0.9979, 0.9994, 1.0029, 1.0005, 0.9986, 1.0007, 1.0007, 0.9984, 1.0002, 1.0015, 1.0041, 1.0038, 1.0038, 1.0003, 1.0022, 1.0026, 0.9987, 1.0002, 1.0087, 1.0077, 1.0060, 0.9989, 0.9998, 1.0049, 1.0092, 1.0044, + 610, 1.0040, 1.0037, 1.0034, 1.0067, 1.0034, 1.0019, 1.0009, 1.0051, 1.0009, 1.0002, 1.0001, 1.0000, 1.0008, 0.9983, 1.0072, 1.0036, 1.0038, 1.0030, 1.0006, 0.9994, 1.0059, 1.0051, 1.0080, 1.0034, 1.0022, 1.0036, 1.0068, 1.0032, + 611, 0.9962, 0.9955, 0.9956, 0.9988, 0.9982, 0.9973, 0.9974, 1.0009, 0.9970, 0.9980, 0.9980, 0.9981, 0.9999, 1.0005, 1.0014, 0.9957, 0.9973, 0.9985, 0.9962, 0.9963, 1.0014, 1.0024, 1.0049, 1.0000, 0.9963, 1.0002, 1.0054, 0.9996, + 612, 0.9993, 0.9987, 0.9955, 0.9986, 1.0011, 1.0004, 0.9949, 0.9971, 1.0016, 1.0017, 0.9990, 0.9998, 0.9970, 0.9960, 1.0023, 0.9956, 0.9997, 0.9976, 0.9950, 0.9948, 1.0090, 1.0074, 0.9998, 0.9948, 1.0028, 1.0043, 1.0058, 1.0038, + 613, 0.9990, 0.9974, 0.9934, 0.9966, 0.9987, 0.9971, 0.9973, 1.0000, 0.9973, 0.9943, 0.9976, 0.9956, 0.9964, 0.9936, 1.0029, 0.9923, 0.9983, 0.9975, 0.9963, 0.9946, 1.0032, 1.0027, 1.0025, 0.9968, 0.9988, 1.0005, 1.0025, 0.9974, + 614, 0.9994, 1.0002, 0.9992, 1.0033, 1.0020, 1.0008, 0.9976, 1.0017, 0.9985, 0.9996, 0.9995, 0.9995, 1.0050, 1.0066, 1.0013, 0.9972, 1.0010, 1.0021, 0.9951, 0.9949, 1.0036, 1.0026, 1.0027, 0.9977, 1.0006, 1.0053, 1.0019, 0.9951, + 615, 1.0025, 1.0017, 0.9971, 0.9996, 1.0010, 0.9988, 0.9986, 1.0021, 0.9999, 0.9990, 0.9989, 0.9966, 1.0027, 1.0005, 1.0026, 1.0016, 1.0011, 1.0002, 0.9992, 0.9993, 1.0001, 0.9997, 1.0048, 0.9976, 1.0003, 1.0055, 1.0075, 1.0034, + 616, 1.0014, 1.0011, 1.0006, 1.0033, 1.0001, 0.9983, 0.9980, 1.0020, 1.0013, 0.9996, 0.9986, 0.9972, 1.0049, 1.0031, 1.0019, 0.9984, 0.9994, 1.0003, 1.0006, 1.0017, 0.9981, 0.9965, 1.0059, 1.0007, 1.0000, 1.0067, 1.0052, 1.0005, + 617, 0.9995, 0.9989, 0.9982, 1.0023, 0.9985, 0.9980, 0.9967, 0.9976, 1.0011, 1.0024, 0.9973, 0.9962, 1.0003, 0.9982, 1.0026, 0.9962, 1.0009, 1.0000, 0.9981, 0.9977, 1.0055, 1.0033, 1.0007, 0.9956, 0.9970, 0.9979, 1.0038, 1.0012, + 618, 0.9957, 0.9943, 0.9956, 0.9978, 0.9986, 0.9984, 0.9994, 1.0019, 0.9966, 0.9963, 0.9992, 0.9983, 0.9974, 0.9927, 1.0025, 0.9956, 0.9985, 0.9957, 0.9957, 0.9932, 1.0081, 1.0048, 1.0009, 0.9946, 0.9945, 0.9922, 1.0009, 0.9985, + 619, 0.9903, 0.9887, 0.9926, 0.9963, 0.9960, 0.9948, 0.9955, 0.9989, 0.9921, 0.9902, 0.9971, 0.9964, 0.9975, 0.9984, 0.9975, 0.9951, 0.9910, 0.9885, 0.9942, 0.9929, 1.0030, 1.0015, 1.0000, 0.9932, 0.9977, 1.0030, 0.9951, 0.9919, + 620, 0.9992, 0.9977, 0.9989, 1.0003, 1.0023, 0.9990, 0.9996, 1.0029, 1.0000, 0.9992, 0.9999, 0.9980, 0.9990, 0.9981, 1.0034, 1.0014, 1.0002, 1.0010, 1.0027, 1.0014, 1.0017, 0.9987, 1.0049, 0.9997, 1.0022, 1.0048, 1.0088, 1.0055, + 621, 0.9975, 0.9967, 0.9998, 1.0038, 1.0021, 0.9996, 0.9985, 1.0015, 0.9987, 0.9984, 0.9958, 0.9946, 1.0047, 1.0026, 1.0024, 0.9989, 1.0001, 0.9998, 1.0001, 0.9982, 0.9994, 0.9989, 1.0060, 1.0004, 1.0008, 1.0026, 1.0054, 1.0037, + 622, 1.0034, 1.0030, 1.0001, 1.0038, 1.0046, 1.0021, 0.9995, 1.0033, 1.0027, 1.0005, 1.0037, 1.0046, 1.0038, 1.0043, 1.0040, 1.0001, 1.0049, 1.0043, 1.0013, 0.9998, 1.0085, 1.0059, 1.0055, 0.9985, 1.0030, 1.0057, 1.0080, 1.0037, + 623, 1.0011, 1.0034, 0.9962, 1.0015, 1.0016, 0.9996, 0.9984, 1.0013, 0.9974, 1.0000, 1.0012, 1.0043, 0.9974, 0.9964, 1.0039, 0.9992, 1.0002, 1.0034, 0.9987, 0.9982, 1.0062, 1.0042, 1.0022, 0.9984, 0.9991, 1.0022, 1.0045, 1.0045, + 624, 0.9997, 0.9995, 0.9986, 1.0001, 1.0014, 0.9986, 0.9973, 1.0003, 1.0006, 1.0005, 0.9961, 0.9931, 1.0034, 1.0024, 1.0017, 0.9966, 0.9999, 0.9986, 0.9993, 0.9976, 1.0022, 0.9988, 1.0047, 0.9983, 0.9995, 1.0030, 1.0011, 0.9981, + 625, 1.0022, 1.0011, 0.9991, 1.0025, 1.0014, 0.9996, 0.9972, 0.9997, 1.0004, 0.9999, 0.9963, 0.9943, 0.9975, 0.9970, 1.0015, 0.9961, 0.9985, 0.9972, 0.9970, 0.9923, 1.0024, 0.9991, 1.0016, 0.9980, 1.0016, 1.0063, 1.0029, 1.0005, + 626, 0.9987, 0.9964, 0.9949, 0.9981, 1.0013, 0.9997, 0.9997, 1.0038, 0.9974, 0.9975, 0.9977, 0.9955, 0.9961, 0.9963, 1.0008, 0.9972, 0.9991, 0.9980, 0.9972, 0.9947, 1.0045, 1.0002, 1.0041, 0.9964, 1.0012, 1.0031, 1.0030, 0.9992, + 627, 0.9947, 0.9953, 0.9962, 1.0017, 0.9993, 0.9985, 0.9973, 1.0024, 0.9960, 0.9920, 1.0023, 1.0043, 0.9982, 1.0007, 1.0010, 0.9964, 0.9963, 0.9948, 0.9979, 0.9963, 1.0018, 0.9997, 0.9973, 0.9934, 0.9993, 1.0039, 0.9984, 0.9925, + 628, 1.0033, 1.0021, 0.9996, 1.0026, 1.0006, 0.9992, 0.9998, 1.0017, 1.0020, 1.0018, 1.0025, 1.0034, 1.0009, 0.9985, 1.0056, 1.0010, 1.0016, 1.0011, 1.0034, 1.0015, 1.0016, 0.9976, 1.0058, 0.9994, 1.0012, 1.0026, 1.0055, 1.0035, + 629, 1.0006, 0.9998, 1.0031, 1.0075, 1.0025, 0.9989, 0.9997, 1.0029, 1.0003, 0.9997, 0.9989, 0.9979, 1.0033, 1.0042, 1.0046, 1.0017, 1.0003, 0.9979, 1.0017, 1.0000, 0.9979, 0.9931, 1.0080, 1.0021, 1.0038, 1.0098, 1.0043, 1.0003, + 630, 0.9994, 0.9992, 0.9991, 1.0017, 1.0002, 0.9983, 0.9973, 0.9998, 1.0010, 1.0006, 0.9999, 0.9994, 1.0005, 1.0007, 1.0028, 0.9987, 1.0001, 0.9991, 0.9987, 0.9960, 1.0044, 1.0018, 1.0018, 0.9958, 0.9973, 1.0004, 1.0003, 0.9983, + 631, 0.9934, 0.9916, 0.9914, 0.9953, 0.9955, 0.9965, 0.9955, 1.0011, 0.9938, 0.9941, 1.0006, 1.0015, 0.9916, 0.9891, 1.0006, 0.9955, 0.9941, 0.9920, 0.9923, 0.9882, 1.0069, 1.0013, 1.0006, 0.9949, 0.9926, 0.9925, 0.9985, 0.9962, + 632, 0.9965, 0.9944, 0.9971, 0.9990, 1.0004, 0.9966, 0.9998, 1.0013, 0.9992, 0.9960, 0.9983, 0.9948, 1.0045, 1.0044, 0.9995, 0.9945, 1.0001, 0.9953, 0.9996, 0.9970, 1.0065, 1.0021, 1.0046, 0.9981, 1.0019, 1.0038, 0.9999, 0.9941, + 633, 1.0020, 1.0004, 1.0016, 1.0041, 1.0026, 0.9996, 0.9997, 1.0033, 1.0017, 1.0016, 0.9982, 0.9977, 0.9998, 0.9985, 1.0056, 1.0024, 1.0013, 1.0008, 1.0019, 1.0013, 1.0000, 0.9978, 1.0064, 0.9998, 1.0029, 1.0049, 1.0117, 1.0051, + 634, 0.9986, 0.9972, 1.0003, 1.0048, 1.0037, 1.0019, 1.0002, 1.0039, 1.0011, 0.9994, 1.0012, 1.0011, 1.0042, 1.0048, 1.0049, 1.0003, 1.0008, 1.0019, 1.0021, 0.9993, 1.0014, 0.9964, 1.0064, 1.0016, 1.0028, 1.0069, 1.0042, 1.0014, + 635, 1.0028, 1.0013, 0.9987, 1.0021, 1.0015, 1.0003, 0.9978, 1.0022, 1.0016, 1.0021, 1.0052, 1.0082, 1.0020, 1.0042, 1.0038, 0.9991, 1.0019, 1.0004, 0.9996, 0.9965, 1.0042, 0.9999, 1.0053, 0.9977, 1.0011, 1.0027, 1.0029, 1.0017, + 636, 1.0028, 1.0021, 0.9999, 1.0034, 1.0028, 1.0004, 1.0000, 1.0033, 1.0025, 1.0013, 1.0041, 1.0031, 0.9990, 0.9971, 1.0048, 1.0019, 1.0028, 1.0030, 0.9988, 0.9958, 1.0064, 1.0011, 1.0065, 1.0009, 0.9985, 1.0009, 1.0041, 1.0016, + 637, 0.9982, 0.9975, 0.9981, 1.0012, 1.0019, 0.9992, 0.9970, 1.0018, 1.0002, 1.0003, 0.9989, 0.9974, 1.0033, 1.0027, 1.0047, 0.9973, 0.9995, 0.9995, 0.9990, 0.9954, 1.0039, 0.9997, 1.0050, 0.9995, 0.9989, 1.0038, 1.0028, 1.0001, + 638, 0.9989, 0.9976, 0.9958, 0.9982, 1.0016, 0.9984, 0.9984, 1.0020, 1.0015, 1.0024, 0.9966, 0.9943, 0.9965, 0.9968, 1.0032, 0.9987, 0.9995, 0.9974, 0.9989, 0.9955, 1.0056, 1.0001, 0.9985, 0.9927, 1.0018, 1.0062, 1.0063, 1.0040, + 639, 0.9923, 0.9906, 0.9921, 0.9953, 0.9950, 0.9960, 0.9973, 0.9988, 0.9933, 0.9880, 0.9991, 0.9984, 0.9888, 0.9907, 1.0001, 0.9934, 0.9926, 0.9894, 0.9958, 0.9904, 1.0009, 0.9964, 0.9985, 0.9916, 0.9996, 1.0020, 0.9974, 0.9960, + 640, 0.9973, 0.9963, 0.9973, 1.0002, 1.0012, 0.9987, 0.9991, 1.0027, 0.9991, 0.9963, 1.0017, 1.0013, 1.0019, 1.0043, 1.0026, 0.9996, 0.9987, 0.9980, 0.9992, 0.9971, 1.0063, 1.0007, 1.0007, 0.9942, 1.0054, 1.0113, 0.9988, 0.9947, + 641, 1.0006, 1.0012, 1.0006, 1.0019, 1.0030, 1.0006, 0.9987, 1.0044, 1.0021, 1.0021, 0.9991, 0.9965, 1.0012, 1.0012, 1.0057, 1.0031, 1.0023, 1.0021, 1.0032, 0.9999, 1.0007, 0.9959, 1.0049, 0.9993, 1.0015, 1.0062, 1.0038, 1.0030, + 642, 0.9986, 0.9979, 1.0044, 1.0074, 1.0014, 1.0000, 1.0011, 1.0051, 1.0006, 0.9992, 0.9981, 0.9969, 1.0052, 1.0058, 1.0083, 1.0040, 1.0000, 0.9993, 1.0037, 0.9999, 1.0019, 0.9961, 1.0082, 1.0028, 1.0027, 1.0065, 1.0036, 1.0008, + 643, 0.9960, 0.9941, 0.9975, 0.9993, 0.9983, 0.9968, 0.9951, 0.9974, 0.9990, 0.9977, 1.0009, 1.0014, 0.9975, 0.9965, 1.0018, 0.9965, 0.9969, 0.9955, 0.9982, 0.9933, 1.0061, 1.0014, 1.0008, 0.9941, 0.9960, 0.9985, 0.9999, 0.9979, + 644, 0.9976, 0.9946, 0.9936, 0.9959, 0.9973, 0.9970, 0.9971, 1.0004, 0.9965, 0.9952, 0.9986, 0.9974, 0.9949, 0.9920, 1.0037, 0.9960, 0.9979, 0.9959, 0.9982, 0.9941, 1.0086, 1.0016, 1.0017, 0.9941, 0.9933, 0.9929, 1.0000, 0.9969, + 645, 0.9967, 0.9955, 0.9950, 0.9971, 0.9996, 0.9982, 0.9967, 1.0009, 0.9989, 0.9972, 0.9977, 0.9957, 1.0033, 1.0050, 1.0003, 0.9933, 0.9994, 0.9983, 0.9986, 0.9956, 1.0066, 1.0021, 1.0035, 0.9977, 1.0011, 1.0048, 0.9985, 0.9924, + 646, 1.0032, 1.0019, 1.0011, 1.0037, 1.0026, 0.9990, 1.0004, 1.0020, 1.0023, 1.0021, 1.0002, 0.9968, 1.0016, 1.0002, 1.0053, 1.0013, 1.0009, 1.0008, 1.0035, 0.9997, 1.0043, 0.9982, 1.0063, 1.0010, 1.0064, 1.0125, 1.0076, 1.0074, + 647, 0.9982, 0.9980, 0.9968, 0.9987, 1.0017, 0.9998, 0.9979, 1.0028, 1.0010, 0.9996, 0.9976, 0.9959, 1.0017, 1.0023, 1.0025, 0.9972, 0.9995, 0.9978, 0.9987, 0.9954, 0.9987, 0.9937, 1.0039, 0.9966, 1.0031, 1.0127, 1.0023, 0.9998, + 648, 1.0029, 1.0026, 1.0009, 1.0052, 1.0041, 1.0033, 1.0011, 1.0060, 1.0034, 1.0021, 1.0018, 1.0012, 1.0049, 1.0091, 1.0046, 1.0025, 1.0047, 1.0073, 1.0026, 1.0006, 1.0048, 1.0022, 1.0069, 0.9989, 1.0025, 1.0156, 1.0091, 1.0023, + 649, 1.0002, 0.9989, 1.0013, 1.0045, 1.0016, 1.0012, 1.0006, 1.0045, 1.0002, 0.9980, 1.0046, 1.0026, 0.9975, 0.9977, 1.0077, 1.0027, 1.0018, 1.0012, 1.0028, 0.9986, 1.0079, 1.0022, 1.0057, 1.0013, 0.9962, 1.0015, 1.0048, 1.0022, + 650, 0.9998, 1.0000, 1.0001, 1.0046, 1.0011, 0.9997, 0.9982, 1.0031, 1.0002, 1.0014, 1.0013, 1.0016, 1.0015, 1.0037, 1.0029, 0.9991, 1.0002, 0.9998, 0.9996, 0.9969, 1.0040, 1.0011, 1.0055, 1.0007, 1.0005, 1.0040, 1.0017, 1.0019, + 651, 0.9992, 0.9965, 0.9955, 0.9964, 0.9955, 0.9941, 0.9965, 0.9990, 0.9989, 0.9986, 0.9995, 0.9977, 0.9938, 0.9929, 1.0012, 0.9949, 0.9960, 0.9931, 0.9954, 0.9902, 1.0033, 0.9974, 1.0000, 0.9950, 0.9994, 1.0007, 1.0024, 1.0014, + 652, 0.9969, 0.9952, 0.9937, 0.9958, 0.9991, 0.9971, 0.9973, 0.9993, 0.9985, 0.9949, 0.9982, 0.9961, 0.9952, 0.9949, 1.0011, 0.9927, 0.9975, 0.9949, 0.9965, 0.9916, 1.0012, 0.9967, 1.0040, 0.9961, 1.0015, 1.0018, 0.9997, 0.9982, + 653, 1.0018, 1.0017, 0.9953, 0.9975, 1.0035, 1.0004, 0.9974, 1.0025, 1.0019, 1.0017, 0.9972, 0.9948, 1.0039, 1.0073, 1.0019, 0.9991, 1.0023, 1.0008, 0.9987, 0.9958, 1.0043, 1.0004, 1.0041, 0.9971, 1.0040, 1.0092, 0.9966, 0.9949, + 654, 1.0046, 1.0038, 1.0043, 1.0063, 1.0017, 0.9999, 1.0003, 1.0038, 1.0042, 1.0020, 1.0022, 1.0001, 1.0046, 1.0016, 1.0060, 1.0024, 1.0045, 1.0030, 1.0042, 1.0015, 1.0050, 0.9991, 1.0080, 1.0029, 1.0048, 1.0065, 1.0053, 1.0021, + 655, 0.9969, 0.9972, 0.9992, 1.0022, 0.9981, 0.9961, 0.9975, 1.0025, 0.9992, 0.9974, 0.9987, 0.9978, 1.0009, 1.0019, 1.0019, 0.9972, 0.9975, 0.9955, 1.0008, 0.9974, 0.9975, 0.9946, 1.0079, 1.0022, 0.9991, 1.0037, 1.0020, 1.0002, + 656, 1.0021, 1.0000, 0.9988, 1.0013, 1.0014, 0.9993, 0.9972, 1.0003, 1.0023, 1.0015, 0.9990, 0.9977, 1.0018, 1.0005, 1.0035, 0.9988, 1.0009, 1.0004, 1.0008, 0.9974, 1.0062, 1.0011, 1.0039, 0.9977, 0.9981, 0.9999, 0.9996, 1.0011, + 657, 0.9977, 0.9954, 0.9952, 0.9967, 0.9973, 0.9948, 0.9964, 1.0000, 0.9978, 0.9959, 0.9982, 0.9969, 0.9952, 0.9923, 1.0037, 0.9953, 0.9958, 0.9926, 1.0036, 0.9988, 1.0075, 1.0007, 1.0046, 0.9993, 0.9963, 0.9955, 0.9993, 0.9964, + 658, 1.0030, 1.0023, 1.0002, 1.0027, 1.0028, 0.9997, 0.9972, 1.0006, 1.0022, 0.9988, 1.0001, 0.9980, 1.0071, 1.0079, 1.0014, 0.9961, 1.0012, 1.0012, 0.9987, 0.9946, 1.0090, 1.0026, 1.0085, 0.9994, 1.0026, 1.0071, 0.9986, 0.9933, + 659, 0.9995, 0.9978, 0.9984, 1.0000, 1.0024, 0.9992, 0.9986, 1.0000, 1.0020, 0.9986, 1.0019, 1.0007, 1.0006, 0.9974, 1.0037, 0.9993, 0.9997, 0.9987, 1.0009, 0.9964, 0.9988, 0.9941, 1.0049, 0.9979, 1.0040, 1.0057, 1.0066, 1.0028, + 660, 0.9991, 0.9974, 0.9988, 1.0015, 1.0019, 1.0006, 1.0001, 1.0027, 1.0024, 1.0000, 0.9993, 0.9964, 1.0062, 1.0046, 1.0022, 0.9989, 1.0019, 1.0013, 1.0014, 0.9977, 0.9996, 0.9959, 1.0069, 1.0003, 1.0020, 1.0072, 1.0021, 0.9987, + 661, 1.0005, 0.9988, 1.0020, 1.0037, 1.0034, 1.0007, 0.9998, 1.0039, 1.0032, 0.9988, 1.0019, 1.0013, 1.0033, 1.0037, 1.0048, 1.0032, 1.0029, 1.0027, 1.0026, 0.9995, 1.0054, 0.9997, 1.0069, 0.9990, 1.0056, 1.0082, 1.0050, 1.0011, + 662, 1.0022, 1.0010, 1.0026, 1.0055, 1.0031, 0.9999, 1.0028, 1.0087, 1.0004, 0.9982, 1.0028, 1.0038, 0.9986, 0.9992, 1.0067, 1.0033, 1.0009, 1.0005, 1.0030, 1.0016, 1.0048, 0.9994, 1.0088, 1.0044, 1.0055, 1.0092, 1.0030, 1.0012, + 663, 0.9975, 0.9964, 0.9979, 1.0016, 0.9989, 0.9959, 0.9949, 1.0006, 0.9979, 0.9963, 0.9991, 0.9982, 0.9980, 0.9982, 1.0017, 0.9955, 0.9962, 0.9952, 1.0000, 0.9969, 1.0017, 0.9996, 1.0062, 0.9999, 1.0011, 1.0052, 0.9999, 0.9975, + 664, 0.9985, 0.9990, 0.9959, 0.9987, 1.0002, 0.9984, 0.9964, 0.9998, 1.0034, 1.0041, 1.0012, 1.0004, 0.9990, 0.9992, 1.0007, 0.9965, 0.9992, 0.9976, 1.0006, 0.9964, 1.0062, 1.0004, 1.0024, 0.9966, 1.0016, 1.0030, 1.0018, 1.0013, + 665, 0.9952, 0.9931, 0.9938, 0.9948, 0.9995, 0.9985, 0.9965, 1.0006, 0.9965, 0.9939, 0.9972, 0.9941, 0.9958, 0.9953, 0.9997, 0.9964, 0.9970, 0.9953, 0.9954, 0.9912, 1.0055, 0.9996, 1.0031, 0.9963, 1.0010, 1.0023, 1.0003, 0.9992, + 666, 0.9957, 0.9964, 0.9977, 1.0000, 1.0003, 0.9989, 0.9970, 1.0022, 0.9988, 0.9935, 1.0011, 1.0006, 1.0033, 1.0057, 1.0015, 0.9998, 0.9996, 0.9976, 0.9990, 0.9963, 1.0065, 1.0019, 1.0071, 0.9997, 1.0030, 1.0081, 0.9990, 0.9956, + 667, 1.0030, 1.0019, 1.0007, 1.0024, 1.0007, 0.9980, 0.9992, 1.0014, 1.0000, 0.9990, 1.0001, 0.9993, 0.9995, 0.9981, 1.0032, 1.0005, 1.0015, 1.0010, 1.0025, 0.9995, 1.0012, 0.9945, 1.0076, 1.0019, 1.0035, 1.0068, 1.0022, 1.0011, + 668, 0.9986, 0.9976, 0.9997, 1.0032, 1.0003, 0.9980, 0.9983, 1.0034, 1.0002, 0.9988, 1.0009, 0.9988, 1.0066, 1.0066, 1.0012, 0.9977, 1.0002, 1.0015, 1.0008, 0.9987, 0.9973, 0.9945, 1.0083, 1.0022, 1.0030, 1.0070, 1.0027, 0.9995, + 669, 1.0019, 1.0024, 0.9957, 0.9979, 1.0000, 0.9980, 0.9957, 0.9980, 1.0012, 1.0017, 0.9988, 1.0000, 1.0017, 1.0014, 1.0013, 0.9954, 1.0029, 1.0009, 0.9997, 0.9962, 1.0084, 1.0013, 1.0031, 0.9954, 0.9999, 1.0014, 0.9987, 1.0003, + 670, 0.9979, 0.9949, 0.9934, 0.9946, 0.9974, 0.9975, 0.9962, 0.9990, 0.9974, 0.9967, 1.0002, 0.9965, 0.9947, 0.9914, 1.0008, 0.9947, 0.9990, 0.9969, 0.9960, 0.9924, 1.0085, 1.0022, 1.0051, 0.9989, 0.9971, 0.9952, 0.9982, 0.9953, + 671, 0.9969, 0.9965, 0.9959, 1.0002, 0.9986, 0.9978, 0.9949, 0.9991, 0.9989, 0.9989, 0.9946, 0.9902, 1.0049, 1.0056, 0.9987, 0.9933, 0.9974, 0.9970, 0.9949, 0.9914, 0.9994, 0.9949, 1.0035, 0.9966, 0.9998, 1.0020, 0.9928, 0.9904, + 672, 1.0001, 1.0003, 1.0032, 1.0043, 1.0012, 1.0007, 1.0014, 1.0053, 1.0028, 1.0005, 1.0013, 0.9989, 1.0007, 1.0003, 1.0053, 1.0028, 1.0012, 1.0031, 1.0060, 1.0056, 1.0040, 0.9977, 1.0073, 1.0015, 1.0067, 1.0086, 1.0046, 1.0057, + 673, 0.9975, 0.9960, 0.9979, 1.0009, 0.9999, 0.9995, 0.9991, 1.0025, 0.9978, 0.9959, 1.0022, 1.0024, 1.0016, 1.0015, 1.0038, 0.9981, 0.9997, 0.9987, 1.0012, 0.9982, 1.0033, 0.9990, 1.0067, 0.9997, 1.0019, 1.0059, 1.0010, 1.0002, + 674, 1.0040, 1.0032, 0.9995, 1.0027, 1.0038, 1.0024, 0.9995, 1.0024, 1.0030, 1.0020, 1.0034, 1.0032, 1.0039, 1.0058, 1.0041, 1.0047, 1.0041, 1.0067, 1.0032, 0.9998, 1.0107, 1.0020, 1.0070, 0.9980, 1.0091, 1.0143, 1.0036, 1.0026, + 675, 0.9995, 0.9996, 0.9988, 1.0022, 0.9992, 0.9994, 1.0008, 1.0051, 0.9993, 0.9991, 1.0011, 0.9989, 0.9962, 0.9955, 1.0027, 0.9973, 1.0002, 1.0003, 0.9994, 0.9960, 1.0026, 0.9972, 1.0058, 1.0000, 1.0004, 1.0007, 1.0006, 0.9988, + 676, 0.9980, 0.9981, 0.9990, 1.0042, 0.9995, 0.9997, 0.9992, 1.0031, 1.0008, 1.0030, 0.9971, 0.9940, 1.0029, 1.0039, 1.0022, 0.9968, 1.0007, 1.0013, 0.9995, 0.9981, 1.0024, 0.9998, 1.0068, 1.0022, 0.9998, 1.0033, 0.9997, 0.9997, + 677, 0.9980, 0.9973, 0.9966, 1.0003, 1.0005, 0.9996, 0.9977, 1.0038, 0.9996, 0.9993, 0.9988, 0.9972, 0.9943, 0.9951, 1.0011, 0.9967, 0.9981, 0.9986, 0.9996, 0.9958, 1.0101, 1.0025, 1.0039, 0.9992, 1.0046, 1.0085, 1.0005, 1.0020, + 678, 0.9971, 0.9965, 0.9945, 0.9981, 0.9976, 0.9977, 0.9987, 1.0016, 0.9972, 0.9949, 1.0007, 0.9972, 0.9941, 0.9941, 1.0005, 0.9939, 0.9972, 0.9956, 0.9981, 0.9924, 1.0084, 1.0016, 1.0034, 0.9945, 1.0020, 1.0046, 1.0008, 0.9998, + 679, 0.9991, 0.9972, 0.9936, 0.9959, 0.9994, 0.9990, 0.9963, 1.0002, 0.9991, 0.9959, 0.9986, 0.9960, 1.0022, 1.0049, 1.0002, 0.9965, 0.9995, 0.9994, 0.9964, 0.9938, 1.0042, 0.9978, 1.0031, 0.9954, 1.0028, 1.0064, 0.9971, 0.9941, + 680, 1.0046, 1.0044, 1.0021, 1.0059, 1.0022, 1.0010, 1.0009, 1.0063, 1.0037, 1.0041, 1.0013, 0.9951, 1.0024, 1.0022, 1.0105, 1.0035, 1.0039, 1.0064, 1.0052, 1.0030, 1.0027, 0.9953, 1.0078, 0.9996, 1.0047, 1.0085, 1.0053, 1.0024, + 681, 1.0007, 1.0003, 1.0020, 1.0044, 1.0001, 0.9995, 0.9972, 1.0017, 1.0013, 1.0009, 1.0011, 1.0001, 1.0062, 1.0069, 1.0011, 0.9972, 1.0009, 1.0010, 1.0001, 0.9972, 0.9974, 0.9934, 1.0099, 1.0010, 1.0029, 1.0072, 0.9995, 0.9991, + 682, 1.0000, 0.9984, 0.9996, 1.0011, 0.9984, 0.9989, 0.9963, 0.9987, 1.0001, 1.0003, 1.0005, 1.0002, 0.9996, 1.0005, 1.0020, 0.9956, 0.9996, 0.9991, 0.9994, 0.9944, 1.0060, 0.9996, 1.0054, 0.9983, 0.9982, 1.0010, 1.0008, 1.0010, + 683, 0.9949, 0.9930, 0.9922, 0.9949, 0.9951, 0.9971, 0.9958, 0.9987, 0.9958, 0.9944, 0.9979, 0.9944, 0.9912, 0.9885, 1.0044, 0.9913, 0.9958, 0.9935, 0.9980, 0.9942, 1.0039, 0.9979, 1.0036, 0.9963, 0.9921, 0.9905, 0.9956, 0.9944, + 684, 0.9978, 0.9978, 0.9987, 1.0014, 0.9991, 0.9997, 0.9982, 1.0025, 1.0006, 1.0003, 0.9959, 0.9925, 1.0040, 1.0070, 0.9998, 0.9951, 0.9996, 1.0005, 0.9986, 0.9946, 1.0011, 0.9965, 1.0062, 0.9980, 0.9997, 1.0048, 0.9934, 0.9924, + 685, 1.0044, 1.0014, 1.0047, 1.0054, 1.0039, 1.0012, 1.0027, 1.0056, 1.0052, 1.0024, 1.0031, 1.0022, 1.0014, 1.0001, 1.0062, 1.0026, 1.0038, 1.0019, 1.0092, 1.0037, 1.0011, 0.9944, 1.0092, 0.9995, 1.0082, 1.0094, 1.0080, 1.0057, + 686, 1.0021, 1.0013, 1.0013, 1.0043, 1.0008, 1.0004, 1.0000, 1.0042, 1.0012, 1.0002, 1.0033, 1.0026, 1.0056, 1.0042, 1.0035, 1.0014, 1.0006, 1.0002, 1.0030, 0.9989, 0.9980, 0.9947, 1.0081, 1.0010, 1.0048, 1.0085, 1.0005, 0.9987, + 687, 1.0036, 1.0019, 0.9975, 0.9997, 1.0022, 1.0023, 0.9976, 1.0027, 1.0027, 1.0028, 1.0040, 1.0046, 1.0015, 1.0039, 1.0029, 0.9970, 1.0031, 1.0044, 1.0006, 0.9977, 1.0053, 0.9995, 1.0081, 0.9998, 1.0056, 1.0094, 1.0000, 1.0002, + 688, 1.0031, 1.0030, 1.0017, 1.0042, 1.0036, 1.0022, 1.0012, 1.0060, 1.0045, 1.0045, 1.0007, 0.9975, 1.0016, 1.0012, 1.0050, 1.0010, 1.0042, 1.0058, 1.0021, 0.9974, 1.0077, 1.0004, 1.0088, 1.0027, 1.0022, 1.0039, 0.9998, 1.0012, + 689, 0.9972, 0.9960, 0.9974, 1.0010, 0.9975, 0.9990, 0.9969, 1.0013, 1.0007, 1.0008, 0.9983, 0.9976, 1.0006, 1.0035, 0.9985, 0.9947, 0.9989, 0.9995, 0.9982, 0.9945, 1.0022, 0.9989, 1.0076, 1.0030, 0.9990, 1.0045, 0.9987, 1.0003, + 690, 1.0033, 1.0044, 0.9977, 1.0009, 1.0008, 0.9993, 0.9973, 0.9999, 1.0031, 1.0038, 1.0003, 1.0001, 0.9972, 0.9975, 0.9993, 0.9949, 1.0023, 1.0010, 0.9975, 0.9923, 1.0089, 1.0019, 1.0023, 0.9952, 1.0071, 1.0107, 1.0015, 1.0015, + 691, 0.9990, 0.9979, 0.9903, 0.9931, 0.9978, 0.9984, 0.9953, 0.9984, 0.9995, 0.9993, 0.9984, 0.9935, 0.9953, 0.9951, 0.9967, 0.9900, 0.9974, 0.9960, 0.9967, 0.9891, 1.0018, 0.9974, 1.0031, 0.9940, 1.0000, 1.0022, 0.9968, 0.9999, + 692, 1.0022, 1.0024, 0.9942, 0.9989, 1.0016, 1.0020, 0.9972, 1.0018, 1.0014, 1.0008, 0.9980, 0.9954, 1.0037, 1.0083, 0.9996, 0.9959, 1.0028, 1.0035, 0.9988, 0.9951, 1.0048, 0.9988, 1.0047, 0.9961, 1.0029, 1.0070, 0.9958, 0.9967, + 693, 1.0048, 1.0052, 1.0036, 1.0068, 1.0018, 1.0004, 0.9997, 1.0035, 1.0030, 1.0019, 1.0015, 0.9985, 1.0005, 1.0007, 1.0049, 1.0019, 1.0026, 1.0011, 1.0058, 1.0007, 1.0045, 0.9965, 1.0109, 1.0025, 1.0040, 1.0086, 1.0022, 1.0031, + 694, 1.0021, 1.0027, 1.0017, 1.0053, 1.0025, 1.0006, 0.9989, 1.0036, 1.0042, 1.0024, 1.0013, 0.9994, 1.0061, 1.0081, 1.0026, 1.0011, 1.0016, 1.0028, 1.0035, 0.9998, 0.9985, 0.9940, 1.0101, 1.0016, 1.0037, 1.0091, 1.0009, 1.0004, + 695, 1.0011, 1.0008, 0.9986, 1.0008, 0.9976, 0.9990, 0.9947, 0.9992, 1.0018, 1.0033, 1.0004, 0.9981, 0.9980, 0.9996, 1.0023, 0.9970, 1.0012, 0.9988, 0.9996, 0.9959, 1.0033, 0.9965, 1.0022, 0.9937, 0.9965, 0.9970, 0.9977, 0.9996, + 696, 0.9974, 0.9971, 0.9958, 1.0006, 0.9981, 0.9987, 0.9977, 1.0013, 0.9997, 0.9992, 1.0007, 0.9991, 0.9948, 0.9927, 1.0017, 0.9936, 0.9997, 0.9985, 0.9963, 0.9906, 1.0095, 1.0024, 1.0035, 0.9970, 0.9935, 0.9916, 0.9958, 0.9965, + 697, 0.9974, 0.9982, 0.9953, 0.9977, 0.9991, 1.0002, 0.9966, 1.0016, 1.0003, 0.9988, 0.9993, 0.9976, 1.0031, 1.0061, 0.9994, 0.9957, 0.9987, 0.9990, 0.9990, 0.9933, 1.0019, 0.9960, 1.0068, 0.9975, 1.0015, 1.0058, 0.9948, 0.9940, + 698, 1.0039, 1.0030, 1.0016, 1.0042, 1.0024, 1.0021, 1.0003, 1.0044, 1.0040, 1.0037, 1.0011, 0.9980, 1.0012, 1.0017, 1.0040, 1.0016, 1.0042, 1.0029, 1.0069, 1.0023, 0.9995, 0.9946, 1.0105, 1.0024, 1.0081, 1.0120, 1.0060, 1.0071, + 699, 0.9971, 0.9966, 0.9986, 1.0018, 0.9994, 1.0001, 0.9967, 1.0008, 1.0002, 0.9996, 1.0002, 0.9967, 1.0007, 1.0033, 1.0012, 0.9947, 0.9998, 0.9993, 0.9990, 0.9952, 0.9976, 0.9943, 1.0084, 1.0014, 1.0035, 1.0073, 0.9988, 0.9996, + 700, 1.0018, 1.0020, 1.0015, 1.0067, 1.0000, 1.0001, 0.9994, 1.0039, 1.0020, 0.9997, 1.0036, 1.0026, 1.0004, 1.0046, 1.0018, 0.9996, 1.0034, 1.0023, 1.0049, 1.0011, 1.0093, 1.0011, 1.0093, 1.0009, 1.0046, 1.0083, 1.0016, 1.0032, + 701, 1.0001, 0.9999, 1.0009, 1.0034, 0.9998, 1.0017, 1.0007, 1.0063, 1.0014, 0.9993, 1.0018, 1.0001, 0.9977, 1.0000, 1.0062, 0.9998, 1.0024, 1.0013, 1.0014, 0.9966, 1.0096, 1.0021, 1.0076, 1.0015, 1.0015, 1.0037, 1.0010, 1.0016, + 702, 0.9983, 0.9989, 0.9988, 1.0017, 0.9981, 0.9983, 0.9980, 1.0026, 1.0024, 1.0003, 1.0010, 0.9987, 1.0006, 1.0029, 1.0012, 0.9969, 1.0015, 0.9992, 1.0004, 0.9957, 1.0034, 0.9970, 1.0091, 0.9998, 1.0015, 1.0054, 0.9979, 1.0011, + 703, 0.9986, 1.0000, 0.9946, 0.9988, 0.9976, 0.9998, 0.9972, 1.0015, 1.0013, 1.0028, 0.9981, 0.9974, 0.9942, 0.9989, 0.9997, 0.9943, 0.9980, 0.9992, 0.9977, 0.9946, 1.0005, 0.9974, 1.0058, 0.9984, 1.0022, 1.0078, 1.0007, 1.0038, + 704, 0.9990, 0.9976, 0.9959, 0.9988, 0.9989, 1.0003, 0.9977, 1.0014, 1.0010, 0.9966, 0.9987, 0.9967, 0.9945, 0.9966, 0.9993, 0.9909, 0.9998, 0.9975, 0.9975, 0.9909, 1.0064, 0.9989, 1.0065, 0.9958, 1.0036, 1.0074, 1.0005, 0.9997, + 705, 0.9972, 0.9995, 0.9973, 1.0015, 0.9975, 0.9991, 0.9982, 1.0021, 0.9992, 0.9962, 1.0011, 0.9980, 1.0005, 1.0051, 1.0000, 0.9983, 1.0019, 0.9992, 0.9997, 0.9941, 1.0044, 0.9967, 1.0047, 0.9954, 1.0018, 1.0084, 0.9963, 0.9963, + 706, 1.0072, 1.0066, 1.0032, 1.0066, 1.0013, 1.0017, 1.0013, 1.0043, 1.0050, 1.0022, 1.0029, 0.9998, 1.0025, 1.0027, 1.0057, 1.0016, 1.0043, 1.0032, 1.0066, 1.0030, 1.0033, 0.9978, 1.0097, 1.0018, 1.0040, 1.0039, 1.0024, 1.0049, + 707, 0.9970, 0.9979, 1.0001, 1.0043, 0.9978, 0.9989, 0.9971, 1.0024, 1.0003, 0.9993, 1.0006, 0.9998, 1.0023, 1.0054, 1.0053, 0.9967, 0.9990, 0.9977, 1.0017, 0.9967, 0.9946, 0.9907, 1.0078, 1.0012, 1.0013, 1.0040, 0.9984, 0.9996, + 708, 1.0008, 1.0013, 0.9999, 1.0031, 0.9986, 1.0001, 0.9971, 0.9996, 1.0042, 1.0048, 1.0016, 0.9987, 1.0008, 1.0034, 1.0091, 0.9973, 1.0022, 1.0023, 1.0007, 0.9961, 1.0045, 0.9977, 1.0035, 0.9949, 0.9990, 1.0015, 0.9978, 1.0015, + 709, 0.9988, 0.9989, 0.9956, 0.9989, 0.9965, 0.9986, 0.9975, 1.0025, 0.9997, 0.9979, 1.0009, 0.9999, 0.9969, 0.9923, 1.0054, 0.9923, 0.9997, 0.9965, 0.9986, 0.9914, 1.0060, 0.9991, 1.0033, 0.9946, 0.9974, 0.9951, 0.9947, 0.9959, + 710, 0.9973, 0.9973, 0.9980, 1.0001, 0.9990, 1.0015, 0.9974, 1.0021, 1.0009, 0.9991, 0.9995, 0.9966, 1.0047, 1.0083, 1.0016, 0.9940, 0.9993, 0.9983, 1.0004, 0.9956, 1.0026, 0.9968, 1.0058, 0.9974, 1.0013, 1.0053, 0.9924, 0.9933, + 711, 1.0033, 1.0030, 1.0000, 1.0022, 0.9997, 1.0000, 0.9986, 1.0019, 1.0040, 1.0027, 1.0001, 0.9977, 0.9996, 0.9997, 1.0031, 0.9980, 1.0034, 1.0011, 1.0021, 0.9961, 1.0004, 0.9948, 1.0071, 0.9986, 1.0040, 1.0057, 1.0034, 1.0054, + 712, 1.0022, 1.0008, 1.0024, 1.0038, 1.0020, 1.0003, 1.0007, 1.0047, 1.0059, 1.0042, 1.0014, 0.9955, 1.0058, 1.0067, 1.0038, 0.9977, 1.0049, 1.0012, 1.0034, 0.9981, 1.0031, 0.9948, 1.0116, 1.0005, 1.0042, 1.0075, 1.0002, 1.0027, + 713, 1.0042, 1.0055, 1.0033, 1.0082, 1.0010, 0.9998, 1.0007, 1.0047, 1.0040, 0.9990, 1.0027, 1.0021, 1.0017, 1.0049, 1.0051, 1.0025, 1.0035, 1.0041, 1.0033, 0.9996, 1.0061, 0.9999, 1.0089, 0.9992, 1.0063, 1.0102, 1.0017, 1.0016, + 714, 1.0051, 1.0061, 1.0036, 1.0068, 1.0005, 1.0004, 1.0008, 1.0060, 1.0035, 1.0023, 1.0037, 1.0039, 1.0009, 1.0001, 1.0061, 1.0079, 1.0052, 1.0073, 1.0061, 1.0032, 1.0064, 1.0000, 1.0095, 1.0022, 1.0008, 1.0022, 0.9982, 1.0018, + 715, 0.9995, 1.0022, 0.9971, 1.0013, 0.9983, 0.9989, 0.9988, 1.0019, 1.0013, 1.0016, 1.0018, 0.9989, 1.0008, 1.0025, 1.0036, 0.9934, 1.0016, 1.0002, 1.0004, 0.9942, 0.9972, 0.9934, 1.0046, 0.9955, 0.9964, 0.9978, 0.9967, 0.9976, + 716, 0.9991, 0.9999, 1.0001, 1.0022, 0.9986, 0.9990, 0.9964, 1.0001, 1.0032, 1.0020, 1.0017, 1.0011, 0.9946, 0.9965, 0.9995, 0.9942, 0.9988, 0.9974, 0.9979, 0.9921, 1.0074, 0.9986, 1.0071, 0.9975, 1.0035, 1.0046, 1.0007, 1.0018, + 717, 1.0021, 1.0025, 0.9970, 0.9998, 1.0001, 0.9998, 0.9986, 1.0023, 1.0016, 0.9992, 0.9981, 0.9954, 0.9961, 0.9973, 1.0011, 0.9933, 1.0002, 0.9980, 0.9990, 0.9926, 1.0029, 0.9961, 1.0076, 0.9962, 1.0014, 1.0037, 0.9981, 1.0001, + 718, 1.0030, 1.0033, 0.9995, 1.0035, 1.0014, 1.0011, 1.0008, 1.0081, 1.0045, 1.0003, 1.0016, 0.9996, 1.0052, 1.0102, 1.0028, 0.9980, 1.0043, 1.0030, 1.0014, 0.9961, 1.0039, 0.9972, 1.0094, 0.9991, 1.0025, 1.0059, 0.9981, 0.9949, + 719, 1.0028, 1.0055, 1.0047, 1.0084, 0.9997, 1.0004, 1.0010, 1.0055, 1.0021, 1.0012, 1.0042, 1.0048, 1.0009, 0.9999, 1.0040, 1.0027, 1.0029, 1.0020, 1.0059, 1.0024, 1.0015, 0.9949, 1.0085, 0.9991, 1.0021, 1.0059, 0.9999, 1.0018, + 720, 1.0005, 1.0011, 1.0026, 1.0055, 1.0000, 1.0002, 0.9991, 1.0024, 1.0033, 1.0021, 1.0064, 1.0078, 1.0036, 1.0055, 1.0015, 0.9970, 1.0016, 1.0008, 1.0042, 0.9995, 0.9996, 0.9930, 1.0102, 1.0004, 1.0058, 1.0093, 1.0015, 1.0003, + 721, 1.0017, 1.0037, 0.9980, 1.0026, 0.9985, 0.9993, 0.9961, 0.9986, 1.0032, 1.0043, 1.0001, 0.9983, 1.0011, 1.0009, 1.0008, 0.9962, 1.0008, 0.9985, 1.0001, 0.9949, 1.0043, 0.9964, 1.0069, 0.9966, 0.9979, 1.0018, 0.9970, 0.9993, + 722, 0.9995, 1.0006, 0.9982, 1.0021, 0.9981, 0.9992, 1.0006, 1.0041, 1.0007, 0.9986, 0.9969, 0.9938, 0.9973, 0.9957, 1.0027, 0.9987, 1.0004, 0.9985, 1.0017, 0.9960, 1.0053, 0.9987, 1.0084, 1.0002, 0.9946, 0.9943, 0.9965, 0.9967, + 723, 0.9944, 0.9954, 0.9978, 1.0015, 0.9979, 0.9979, 0.9979, 1.0017, 0.9986, 0.9977, 1.0015, 0.9974, 1.0011, 1.0045, 0.9999, 0.9938, 0.9985, 0.9953, 0.9987, 0.9928, 0.9983, 0.9960, 1.0089, 0.9998, 0.9955, 0.9975, 0.9922, 0.9925, + 724, 1.0025, 1.0025, 1.0026, 1.0054, 1.0014, 1.0010, 0.9997, 1.0048, 1.0046, 1.0028, 1.0052, 1.0059, 1.0005, 1.0002, 1.0028, 0.9986, 1.0022, 1.0022, 1.0054, 1.0001, 1.0038, 0.9964, 1.0085, 1.0004, 1.0054, 1.0085, 1.0059, 1.0048, + 725, 1.0006, 1.0020, 0.9986, 1.0021, 1.0002, 1.0005, 0.9991, 1.0029, 1.0025, 0.9999, 1.0015, 1.0009, 1.0034, 1.0040, 1.0072, 0.9981, 1.0023, 1.0013, 1.0023, 0.9962, 0.9971, 0.9931, 1.0103, 1.0010, 1.0046, 1.0094, 1.0029, 1.0012, + 726, 1.0066, 1.0088, 1.0028, 1.0052, 1.0021, 1.0033, 1.0004, 1.0044, 1.0066, 1.0036, 1.0033, 1.0022, 1.0055, 1.0095, 1.0030, 1.0010, 1.0061, 1.0069, 1.0044, 0.9994, 1.0048, 0.9984, 1.0122, 1.0015, 1.0075, 1.0115, 1.0018, 1.0023, + 727, 1.0054, 1.0062, 0.9995, 1.0020, 1.0025, 1.0024, 0.9995, 1.0042, 1.0037, 1.0035, 1.0012, 0.9982, 0.9986, 0.9988, 1.0046, 0.9974, 1.0047, 1.0041, 1.0018, 0.9976, 1.0035, 0.9967, 1.0104, 1.0019, 1.0023, 1.0050, 0.9994, 0.9987, + 728, 0.9999, 1.0031, 1.0029, 1.0034, 0.9994, 0.9995, 0.9983, 1.0021, 1.0025, 1.0029, 1.0021, 0.9981, 1.0032, 1.0031, 1.0000, 0.9957, 1.0015, 1.0006, 1.0014, 0.9962, 1.0056, 0.9979, 1.0095, 1.0005, 1.0003, 1.0029, 0.9982, 0.9994, + 729, 0.9999, 1.0003, 1.0023, 1.0030, 0.9988, 0.9999, 0.9981, 1.0014, 1.0030, 1.0021, 1.0005, 0.9990, 0.9956, 0.9967, 1.0016, 0.9984, 0.9981, 0.9953, 0.9999, 0.9929, 1.0081, 1.0004, 1.0072, 0.9994, 1.0009, 1.0037, 0.9999, 1.0017, + 730, 1.0018, 1.0039, 0.9958, 1.0000, 0.9996, 1.0022, 0.9985, 1.0045, 1.0017, 1.0006, 0.9998, 0.9973, 0.9987, 1.0002, 0.9995, 0.9972, 1.0023, 1.0017, 0.9992, 0.9940, 1.0050, 0.9971, 1.0070, 0.9979, 1.0028, 1.0042, 0.9986, 1.0012, + 731, 0.9995, 1.0012, 0.9958, 1.0000, 0.9998, 1.0000, 0.9996, 1.0044, 1.0014, 1.0000, 1.0027, 0.9996, 1.0022, 1.0058, 1.0005, 0.9954, 1.0004, 0.9992, 1.0000, 0.9941, 1.0013, 0.9953, 1.0031, 0.9947, 1.0029, 1.0062, 0.9941, 0.9928, + 732, 1.0044, 1.0058, 1.0026, 1.0052, 1.0012, 1.0013, 0.9989, 1.0044, 1.0048, 1.0041, 1.0075, 1.0086, 1.0014, 1.0017, 1.0037, 0.9994, 1.0045, 1.0053, 1.0054, 1.0015, 1.0004, 0.9928, 1.0093, 0.9979, 1.0045, 1.0067, 1.0014, 1.0034, + 733, 0.9984, 0.9994, 1.0009, 1.0034, 0.9978, 0.9989, 0.9998, 1.0028, 1.0005, 1.0007, 1.0018, 1.0009, 1.0030, 1.0046, 1.0014, 0.9980, 0.9994, 0.9973, 1.0028, 0.9986, 1.0001, 0.9945, 1.0105, 1.0018, 1.0045, 1.0093, 0.9994, 1.0012, + 734, 1.0016, 1.0022, 1.0003, 1.0023, 0.9972, 0.9995, 0.9977, 0.9996, 1.0035, 1.0030, 0.9998, 0.9971, 1.0018, 1.0006, 1.0022, 0.9955, 1.0021, 1.0012, 0.9994, 0.9929, 1.0102, 0.9996, 1.0091, 0.9982, 0.9991, 1.0022, 1.0016, 0.9999, + 735, 0.9978, 0.9990, 0.9934, 0.9962, 0.9949, 0.9962, 0.9957, 0.9993, 0.9977, 0.9968, 0.9969, 0.9926, 0.9931, 0.9910, 0.9991, 0.9911, 0.9989, 0.9969, 0.9955, 0.9858, 1.0068, 0.9972, 1.0046, 0.9959, 0.9909, 0.9885, 0.9973, 0.9966, + 736, 0.9985, 0.9988, 0.9988, 1.0021, 0.9986, 1.0003, 0.9999, 1.0035, 1.0018, 1.0011, 1.0001, 0.9969, 1.0061, 1.0073, 0.9988, 0.9944, 1.0000, 1.0006, 1.0024, 0.9970, 1.0028, 0.9952, 1.0092, 0.9972, 1.0013, 1.0024, 0.9944, 0.9928, + 737, 1.0050, 1.0055, 1.0018, 1.0030, 1.0012, 1.0009, 0.9998, 1.0038, 1.0038, 1.0026, 1.0051, 1.0054, 1.0007, 0.9994, 1.0039, 1.0007, 1.0037, 1.0038, 1.0060, 1.0006, 0.9992, 0.9932, 1.0093, 0.9992, 1.0068, 1.0087, 1.0065, 1.0066, + 738, 1.0062, 1.0059, 1.0019, 1.0054, 1.0029, 1.0031, 1.0030, 1.0050, 1.0058, 1.0051, 1.0016, 0.9975, 1.0090, 1.0067, 1.0048, 1.0014, 1.0059, 1.0062, 1.0053, 0.9992, 1.0022, 0.9946, 1.0130, 1.0036, 1.0053, 1.0083, 1.0046, 1.0035, + 739, 1.0027, 1.0020, 1.0012, 1.0041, 1.0016, 1.0008, 1.0014, 1.0058, 1.0061, 1.0041, 1.0036, 1.0014, 1.0043, 1.0055, 1.0037, 1.0002, 1.0052, 1.0037, 1.0060, 0.9997, 1.0042, 0.9976, 1.0122, 1.0003, 1.0014, 1.0028, 1.0018, 1.0029, + 740, 1.0034, 1.0043, 1.0035, 1.0071, 0.9982, 1.0003, 1.0003, 1.0048, 1.0026, 1.0010, 1.0071, 1.0086, 0.9972, 0.9975, 1.0030, 0.9998, 1.0049, 1.0028, 1.0054, 1.0003, 1.0070, 0.9984, 1.0114, 1.0032, 1.0012, 1.0011, 1.0012, 0.9988, + 741, 0.9982, 0.9995, 1.0011, 1.0046, 0.9977, 0.9992, 0.9994, 1.0045, 1.0006, 1.0016, 1.0036, 1.0026, 1.0021, 1.0009, 1.0012, 0.9973, 1.0005, 0.9998, 1.0026, 0.9966, 1.0001, 0.9938, 1.0081, 0.9982, 1.0017, 1.0052, 1.0018, 1.0006, + 742, 0.9992, 0.9991, 0.9952, 0.9994, 0.9976, 1.0010, 0.9991, 1.0028, 1.0034, 1.0054, 0.9999, 0.9998, 0.9979, 0.9979, 1.0004, 0.9980, 1.0001, 0.9994, 1.0013, 0.9949, 1.0045, 0.9960, 1.0025, 0.9927, 1.0047, 1.0078, 1.0017, 1.0029, + 743, 0.9982, 0.9983, 0.9934, 0.9964, 0.9948, 0.9971, 0.9961, 1.0011, 0.9973, 0.9938, 1.0000, 0.9974, 0.9943, 0.9941, 0.9979, 0.9952, 0.9983, 0.9960, 0.9991, 0.9914, 1.0016, 0.9942, 1.0055, 0.9962, 1.0015, 1.0034, 0.9981, 0.9988, + 744, 0.9988, 0.9991, 0.9969, 0.9995, 0.9996, 1.0011, 1.0009, 1.0057, 1.0021, 1.0002, 1.0022, 1.0010, 1.0051, 1.0068, 1.0007, 1.0003, 1.0022, 1.0006, 1.0029, 1.0008, 0.9993, 0.9923, 1.0057, 0.9957, 1.0063, 1.0122, 0.9965, 0.9963, + 745, 1.0029, 1.0059, 1.0037, 1.0089, 1.0016, 1.0015, 1.0010, 1.0062, 1.0037, 1.0031, 1.0055, 1.0024, 1.0010, 0.9996, 1.0049, 1.0036, 1.0030, 1.0022, 1.0065, 1.0001, 1.0005, 0.9923, 1.0116, 1.0017, 1.0039, 1.0066, 1.0026, 1.0027, + 746, 0.9986, 0.9981, 1.0036, 1.0072, 0.9995, 1.0009, 1.0007, 1.0058, 1.0018, 1.0007, 1.0018, 1.0002, 1.0048, 1.0059, 1.0025, 0.9996, 1.0026, 0.9994, 1.0036, 0.9993, 0.9994, 0.9923, 1.0125, 1.0029, 1.0045, 1.0068, 1.0013, 1.0013, + 747, 0.9979, 0.9968, 0.9956, 0.9985, 0.9947, 0.9970, 0.9956, 0.9989, 1.0000, 1.0000, 1.0036, 1.0030, 0.9983, 0.9958, 0.9987, 0.9924, 0.9976, 0.9958, 0.9994, 0.9914, 1.0033, 0.9974, 1.0054, 0.9939, 0.9938, 0.9942, 0.9960, 0.9975, + 748, 0.9969, 0.9971, 0.9940, 0.9967, 0.9957, 0.9979, 0.9959, 0.9987, 0.9984, 0.9977, 0.9998, 0.9982, 0.9960, 0.9920, 0.9990, 0.9918, 1.0004, 0.9980, 0.9990, 0.9914, 1.0037, 0.9955, 1.0035, 0.9925, 0.9928, 0.9919, 0.9933, 0.9943, + 749, 1.0009, 1.0018, 0.9972, 1.0010, 1.0006, 1.0022, 0.9991, 1.0017, 1.0025, 1.0019, 0.9999, 0.9948, 1.0085, 1.0080, 1.0012, 0.9940, 1.0040, 1.0026, 1.0014, 0.9959, 1.0003, 0.9914, 1.0082, 0.9970, 1.0034, 1.0042, 0.9964, 0.9947, + 750, 1.0055, 1.0050, 1.0043, 1.0071, 1.0026, 1.0030, 1.0023, 1.0075, 1.0051, 1.0047, 1.0107, 1.0012, 1.0050, 1.0021, 1.0048, 1.0070, 1.0042, 1.0044, 1.0074, 0.9995, 1.0005, 0.9942, 1.0115, 1.0008, 1.0079, 1.0108, 1.0127, 1.0061, + 751, 0.9986, 0.9982, 0.9994, 1.0029, 0.9999, 1.0017, 0.9981, 1.0022, 1.0017, 1.0013, 1.0021, 1.0013, 1.0053, 1.0052, 1.0028, 0.9991, 1.0026, 1.0011, 1.0024, 0.9973, 0.9968, 0.9900, 1.0093, 0.9979, 1.0044, 1.0068, 0.9999, 0.9989, + 752, 1.0022, 1.0032, 1.0003, 1.0035, 1.0020, 1.0025, 1.0002, 1.0038, 1.0048, 1.0041, 1.0062, 1.0062, 1.0058, 1.0059, 1.0053, 1.0012, 1.0052, 1.0037, 1.0066, 0.9988, 1.0084, 0.9981, 1.0089, 0.9979, 1.0072, 1.0078, 1.0035, 1.0018, + 753, 1.0036, 1.0043, 1.0037, 1.0061, 1.0014, 1.0028, 1.0018, 1.0051, 1.0026, 1.0028, 1.0029, 1.0012, 0.9988, 0.9973, 1.0050, 1.0095, 1.0032, 1.0036, 1.0034, 0.9971, 1.0037, 0.9945, 1.0095, 1.0006, 1.0004, 1.0013, 1.0000, 0.9989, + 754, 1.0018, 1.0038, 1.0011, 1.0047, 1.0007, 1.0022, 1.0001, 1.0057, 1.0050, 1.0041, 1.0023, 1.0011, 1.0054, 1.0058, 1.0038, 0.9991, 1.0042, 1.0035, 1.0037, 0.9979, 1.0015, 0.9949, 1.0105, 1.0012, 1.0054, 1.0099, 1.0010, 0.9997, + 755, 0.9982, 1.0001, 0.9944, 1.0001, 0.9960, 0.9994, 0.9975, 0.9984, 1.0023, 1.0026, 1.0014, 0.9995, 0.9987, 0.9976, 0.9998, 0.9945, 0.9993, 0.9976, 1.0014, 0.9915, 1.0048, 0.9959, 1.0037, 0.9934, 1.0045, 1.0059, 1.0032, 1.0021, + 756, 0.9950, 0.9970, 0.9942, 0.9984, 0.9952, 0.9967, 0.9979, 1.0016, 0.9996, 0.9976, 0.9997, 0.9964, 0.9984, 0.9958, 0.9990, 0.9933, 0.9987, 0.9960, 1.0021, 0.9956, 1.0052, 0.9964, 1.0090, 0.9975, 1.0032, 1.0052, 0.9989, 0.9997, + 757, 0.9991, 1.0016, 0.9989, 1.0026, 0.9994, 1.0027, 0.9985, 1.0043, 1.0023, 1.0051, 1.0001, 0.9981, 1.0050, 1.0075, 1.0001, 0.9966, 1.0021, 1.0020, 1.0013, 0.9941, 1.0034, 0.9974, 1.0108, 0.9992, 1.0035, 1.0079, 0.9990, 0.9975, + 758, 1.0051, 1.0063, 1.0042, 1.0090, 0.9998, 1.0013, 1.0020, 1.0049, 1.0050, 1.0052, 1.0009, 0.9974, 1.0025, 1.0008, 1.0068, 1.0022, 1.0037, 1.0041, 1.0065, 1.0004, 1.0031, 0.9956, 1.0118, 1.0035, 1.0064, 1.0081, 1.0061, 1.0058, + 759, 0.9998, 1.0002, 1.0013, 1.0052, 0.9984, 0.9998, 0.9996, 1.0050, 1.0033, 1.0018, 1.0014, 0.9992, 1.0028, 1.0036, 1.0014, 0.9977, 1.0021, 0.9979, 1.0049, 0.9987, 1.0003, 0.9922, 1.0126, 1.0021, 1.0038, 1.0084, 1.0042, 1.0015, + 760, 1.0026, 1.0035, 0.9988, 1.0040, 0.9991, 1.0007, 0.9976, 0.9998, 1.0042, 1.0052, 1.0032, 1.0034, 1.0041, 1.0021, 1.0009, 0.9934, 1.0041, 1.0031, 1.0039, 0.9965, 1.0077, 0.9994, 1.0071, 0.9972, 1.0027, 1.0056, 1.0025, 1.0018, + 761, 0.9982, 0.9987, 0.9957, 0.9988, 0.9968, 1.0002, 0.9979, 1.0019, 1.0009, 0.9992, 1.0009, 0.9978, 0.9981, 0.9926, 0.9999, 0.9943, 0.9998, 0.9968, 1.0010, 0.9930, 1.0064, 0.9959, 1.0057, 0.9957, 0.9976, 0.9965, 0.9958, 0.9939, + 762, 0.9994, 1.0007, 0.9973, 1.0011, 0.9997, 1.0015, 0.9969, 0.9987, 1.0031, 1.0034, 0.9997, 0.9951, 1.0096, 1.0082, 0.9999, 0.9942, 1.0022, 1.0007, 0.9997, 0.9920, 1.0005, 0.9936, 1.0092, 0.9988, 1.0007, 1.0013, 0.9950, 0.9944, + 763, 1.0001, 1.0001, 0.9988, 1.0026, 0.9984, 1.0001, 0.9992, 1.0059, 1.0030, 1.0015, 1.0012, 0.9980, 0.9994, 0.9972, 1.0022, 0.9985, 1.0006, 0.9977, 1.0053, 0.9980, 0.9954, 0.9874, 1.0096, 0.9998, 1.0034, 1.0039, 1.0023, 1.0047, + 764, 0.9970, 0.9989, 0.9979, 1.0010, 0.9974, 1.0001, 0.9983, 1.0074, 1.0028, 0.9989, 1.0002, 0.9958, 1.0040, 1.0022, 0.9998, 0.9965, 1.0024, 1.0021, 1.0032, 0.9955, 0.9960, 0.9887, 1.0098, 0.9982, 1.0037, 1.0057, 0.9986, 0.9997, + 765, 1.0060, 1.0051, 1.0024, 1.0043, 1.0027, 1.0019, 1.0033, 1.0038, 1.0074, 1.0022, 1.0042, 0.9995, 1.0082, 1.0060, 1.0044, 1.0007, 1.0084, 1.0040, 1.0091, 1.0013, 1.0067, 0.9948, 1.0123, 0.9989, 1.0082, 1.0082, 1.0048, 1.0015, + 766, 1.0032, 1.0071, 1.0011, 1.0047, 1.0004, 1.0020, 1.0013, 1.0056, 1.0048, 1.0032, 1.0029, 1.0030, 0.9999, 0.9973, 1.0085, 0.9997, 1.0058, 1.0035, 1.0033, 0.9967, 1.0064, 0.9965, 1.0097, 0.9998, 1.0021, 1.0035, 1.0018, 0.9996, + 767, 0.9919, 0.9926, 0.9947, 0.9973, 0.9941, 0.9966, 0.9971, 1.0002, 0.9983, 0.9944, 1.0008, 0.9972, 0.9982, 0.9972, 1.0007, 0.9938, 0.9968, 0.9929, 1.0003, 0.9928, 1.0002, 0.9924, 1.0077, 0.9964, 1.0023, 1.0030, 0.9956, 0.9976, + 768, 0.9991, 1.0010, 0.9973, 1.0007, 0.9980, 1.0009, 0.9979, 1.0016, 1.0027, 1.0023, 0.9986, 0.9944, 0.9958, 0.9963, 1.0056, 0.9953, 0.9995, 0.9976, 1.0033, 0.9976, 1.0045, 0.9949, 1.0065, 0.9959, 1.0054, 1.0074, 1.0011, 1.0020, + 769, 0.9965, 0.9953, 0.9950, 0.9977, 0.9968, 0.9989, 0.9978, 1.0003, 1.0006, 0.9954, 0.9968, 0.9923, 0.9954, 0.9929, 1.0018, 0.9909, 0.9997, 0.9950, 1.0027, 0.9938, 1.0021, 0.9937, 1.0093, 0.9978, 1.0024, 1.0010, 0.9998, 0.9994, + 770, 1.0056, 1.0066, 1.0015, 1.0072, 0.9988, 1.0013, 0.9987, 1.0035, 1.0023, 0.9979, 1.0037, 1.0030, 1.0066, 1.0065, 1.0010, 0.9957, 1.0019, 1.0004, 1.0035, 0.9969, 1.0060, 0.9976, 1.0110, 0.9985, 1.0066, 1.0110, 0.9974, 0.9959, + 771, 1.0032, 1.0037, 0.9984, 1.0012, 0.9973, 0.9994, 0.9993, 1.0008, 1.0030, 0.9997, 1.0051, 1.0041, 0.9987, 0.9978, 1.0032, 0.9967, 1.0030, 1.0022, 1.0049, 0.9989, 1.0010, 0.9933, 1.0084, 0.9989, 1.0047, 1.0043, 1.0012, 1.0031, + 772, 1.0025, 1.0040, 1.0012, 1.0053, 1.0004, 1.0020, 1.0013, 1.0049, 1.0056, 1.0034, 0.9989, 0.9951, 1.0069, 1.0057, 1.0034, 0.9985, 1.0054, 1.0036, 1.0061, 1.0004, 0.9988, 0.9905, 1.0132, 1.0015, 1.0065, 1.0102, 0.9996, 1.0006, + 773, 1.0019, 1.0053, 1.0013, 1.0050, 0.9989, 1.0010, 0.9998, 1.0028, 1.0058, 1.0066, 0.9992, 0.9970, 1.0046, 1.0018, 1.0022, 0.9968, 1.0051, 1.0042, 1.0044, 0.9973, 1.0027, 0.9948, 1.0085, 0.9975, 1.0019, 1.0028, 0.9996, 1.0003, + 774, 0.9985, 0.9979, 0.9982, 1.0034, 0.9981, 1.0013, 1.0009, 1.0051, 1.0007, 0.9996, 1.0015, 0.9991, 0.9940, 0.9917, 1.0028, 0.9954, 1.0014, 0.9991, 1.0029, 0.9952, 1.0070, 0.9975, 1.0090, 0.9985, 0.9992, 0.9987, 0.9980, 0.9974, + 775, 0.9951, 0.9973, 0.9984, 1.0039, 0.9946, 0.9984, 0.9987, 1.0020, 0.9991, 0.9963, 1.0010, 0.9988, 1.0020, 1.0032, 0.9998, 0.9940, 0.9971, 0.9944, 1.0020, 0.9947, 1.0019, 0.9939, 1.0054, 0.9939, 1.0038, 1.0046, 0.9945, 0.9922, + 776, 1.0027, 1.0033, 1.0021, 1.0054, 0.9993, 1.0019, 1.0023, 1.0056, 1.0048, 1.0027, 1.0062, 1.0063, 1.0006, 0.9982, 1.0046, 1.0069, 1.0036, 1.0021, 1.0088, 1.0024, 0.9954, 0.9886, 1.0126, 1.0000, 1.0096, 1.0086, 1.0064, 1.0049, + 777, 0.9993, 1.0015, 1.0007, 1.0061, 1.0000, 1.0005, 1.0012, 1.0055, 1.0043, 1.0014, 1.0033, 0.9968, 1.0060, 1.0040, 1.0029, 1.0011, 1.0036, 1.0013, 1.0056, 0.9981, 0.9952, 0.9878, 1.0120, 1.0014, 1.0089, 1.0099, 0.9998, 1.0005, + 778, 1.0030, 1.0043, 1.0011, 1.0056, 1.0023, 1.0031, 1.0021, 1.0080, 1.0052, 1.0037, 1.0061, 1.0041, 1.0050, 1.0068, 1.0042, 1.0027, 1.0055, 1.0048, 1.0059, 1.0000, 1.0042, 0.9963, 1.0119, 0.9970, 1.0100, 1.0103, 1.0035, 1.0026, + 779, 0.9980, 0.9976, 1.0001, 1.0046, 0.9956, 0.9982, 0.9968, 1.0016, 0.9991, 0.9968, 1.0060, 1.0053, 0.9957, 0.9945, 1.0012, 0.9983, 1.0004, 0.9978, 1.0017, 0.9938, 1.0026, 0.9937, 1.0110, 1.0004, 1.0041, 1.0051, 1.0025, 0.9987, + 780, 0.9968, 0.9979, 0.9970, 1.0018, 0.9965, 0.9986, 0.9988, 1.0018, 1.0038, 1.0002, 1.0003, 0.9957, 1.0028, 1.0008, 0.9997, 0.9931, 1.0004, 0.9978, 1.0031, 0.9954, 1.0025, 0.9941, 1.0125, 0.9993, 1.0040, 1.0041, 1.0022, 1.0011, + 781, 1.0011, 1.0021, 1.0002, 1.0040, 0.9990, 0.9998, 1.0005, 1.0040, 1.0047, 1.0052, 0.9980, 0.9942, 0.9979, 0.9960, 0.9999, 0.9969, 1.0005, 0.9973, 1.0017, 0.9938, 1.0048, 0.9952, 1.0091, 0.9981, 1.0066, 1.0053, 1.0038, 1.0049, + 782, 0.9979, 0.9990, 0.9974, 1.0020, 0.9970, 0.9999, 0.9991, 1.0037, 1.0018, 0.9983, 1.0011, 0.9979, 0.9970, 0.9960, 1.0010, 0.9959, 1.0004, 0.9976, 1.0026, 0.9949, 1.0005, 0.9938, 1.0097, 0.9985, 1.0057, 1.0040, 0.9997, 0.9998, + 783, 1.0000, 1.0035, 0.9991, 1.0069, 0.9981, 1.0019, 0.9976, 1.0020, 1.0019, 1.0026, 1.0042, 1.0052, 1.0042, 1.0057, 1.0032, 0.9965, 1.0017, 1.0002, 0.9997, 0.9928, 0.9982, 0.9923, 1.0101, 0.9993, 1.0020, 1.0062, 0.9975, 0.9980, + 784, 1.0057, 1.0062, 1.0029, 1.0067, 0.9994, 0.9994, 1.0011, 1.0056, 1.0066, 1.0050, 1.0052, 1.0020, 1.0036, 1.0020, 1.0068, 1.0001, 1.0038, 1.0023, 1.0061, 0.9991, 1.0036, 0.9937, 1.0129, 1.0006, 1.0089, 1.0060, 1.0019, 1.0039, + 785, 1.0012, 1.0035, 1.0016, 1.0076, 0.9977, 0.9994, 1.0003, 1.0030, 1.0025, 1.0021, 1.0014, 0.9978, 1.0033, 1.0031, 1.0007, 0.9958, 1.0018, 0.9999, 1.0057, 0.9984, 0.9979, 0.9899, 1.0125, 1.0006, 1.0073, 1.0072, 1.0027, 1.0013, + 786, 1.0035, 1.0037, 1.0036, 1.0094, 0.9972, 0.9991, 0.9987, 1.0029, 1.0050, 1.0038, 0.9989, 0.9954, 1.0018, 1.0009, 1.0025, 0.9991, 1.0034, 1.0011, 1.0026, 0.9959, 1.0041, 0.9945, 1.0108, 0.9964, 1.0006, 1.0009, 1.0026, 1.0031, + 787, 0.9917, 0.9918, 0.9961, 1.0010, 0.9927, 0.9948, 0.9982, 1.0056, 0.9956, 0.9918, 1.0027, 1.0001, 0.9919, 0.9861, 1.0005, 0.9934, 0.9959, 0.9914, 0.9987, 0.9916, 1.0019, 0.9915, 1.0041, 0.9933, 0.9979, 0.9928, 0.9941, 0.9944, + 788, 0.9972, 0.9990, 1.0004, 1.0035, 0.9974, 0.9988, 0.9994, 1.0135, 1.0015, 0.9992, 1.0036, 0.9973, 1.0041, 1.0044, 1.0048, 0.9937, 1.0005, 0.9994, 1.0029, 0.9935, 1.0008, 0.9936, 1.0085, 0.9954, 1.0066, 1.0094, 0.9959, 0.9920, + 789, 0.9119, 0.8972, 0.8999, 0.9003, 0.9018, 0.9362, 0.9404, 0.9167, 0.9344, 0.9368, 0.9514, 0.9092, 0.9266, 0.8906, 0.9731, 0.9022, 0.8947, 0.8419, 0.9258, 0.8824, 0.8985, 0.9345, 0.9608, 0.9537, 0.9442, 0.8923, 0.9739, 0.9797, + 790, 1.0005, 1.0012, 0.9952, 1.0023, 0.9990, 1.0028, 1.0074, 1.0086, 1.0072, 1.0055, 1.0066, 1.0027, 0.9987, 0.9936, 1.0037, 1.0061, 0.9954, 0.9970, 1.0116, 1.0067, 1.0034, 0.9979, 1.0158, 1.0061, 1.0172, 1.0126, 1.0145, 1.0126, + 791, 1.0036, 1.0056, 1.0107, 1.0155, 1.0025, 1.0049, 1.0045, 1.0080, 1.0113, 1.0106, 1.0045, 0.9978, 1.0084, 1.0028, 1.0050, 1.0078, 1.0074, 1.0059, 1.0129, 1.0081, 1.0037, 0.9984, 1.0195, 1.0103, 1.0194, 1.0184, 1.0125, 1.0098, + 792, 1.0027, 1.0013, 1.0119, 1.0184, 1.0047, 1.0051, 1.0081, 1.0093, 1.0095, 1.0067, 1.0064, 0.9981, 1.0122, 1.0068, 1.0056, 0.9990, 1.0072, 1.0045, 1.0134, 1.0071, 0.9992, 0.9923, 1.0203, 1.0099, 1.0174, 1.0147, 1.0134, 1.0101, + 793, 1.0030, 1.0057, 1.0092, 1.0177, 1.0022, 1.0039, 1.0051, 1.0092, 1.0087, 1.0086, 1.0044, 1.0009, 1.0071, 1.0061, 1.0040, 0.9994, 1.0089, 1.0071, 1.0133, 1.0074, 1.0044, 0.9976, 1.0160, 1.0080, 1.0161, 1.0188, 1.0093, 1.0094, + 794, 1.0005, 1.0024, 1.0046, 1.0120, 1.0001, 1.0015, 1.0039, 1.0081, 1.0048, 1.0005, 1.0088, 1.0040, 1.0034, 0.9984, 1.0027, 0.9969, 1.0058, 1.0029, 1.0094, 1.0039, 1.0042, 0.9979, 1.0141, 1.0070, 1.0171, 1.0198, 1.0084, 1.0076, + 795, 1.0002, 1.0005, 1.0012, 1.0075, 0.9983, 1.0004, 1.0012, 1.0041, 1.0060, 1.0065, 1.0063, 1.0000, 1.0057, 1.0043, 0.9999, 0.9951, 1.0040, 1.0019, 1.0077, 1.0019, 1.0047, 0.9981, 1.0134, 1.0016, 1.0118, 1.0118, 1.0079, 1.0047, + 796, 0.9999, 1.0018, 1.0053, 1.0113, 1.0002, 1.0019, 1.0023, 1.0058, 1.0080, 1.0062, 1.0038, 0.9980, 1.0035, 1.0003, 1.0023, 0.9981, 1.0077, 1.0040, 1.0095, 1.0029, 1.0136, 1.0024, 1.0158, 1.0042, 1.0130, 1.0126, 1.0111, 1.0084, + 797, 0.9987, 0.9990, 1.0011, 1.0073, 0.9966, 0.9983, 1.0017, 1.0040, 1.0031, 1.0028, 1.0034, 0.9987, 1.0043, 0.9998, 1.0013, 0.9946, 1.0016, 0.9978, 1.0064, 0.9997, 1.0099, 0.9984, 1.0148, 1.0043, 1.0113, 1.0129, 1.0071, 1.0065, + 798, 1.0049, 1.0051, 1.0045, 1.0128, 0.9985, 1.0039, 1.0031, 1.0046, 1.0053, 1.0044, 1.0036, 0.9980, 1.0048, 1.0029, 1.0065, 0.9978, 1.0056, 1.0028, 1.0073, 1.0030, 1.0063, 0.9978, 1.0171, 1.0083, 1.0115, 1.0127, 1.0079, 1.0070, + 799, 1.0005, 1.0014, 1.0008, 1.0077, 1.0003, 1.0014, 1.0023, 1.0066, 1.0037, 1.0046, 1.0032, 1.0001, 1.0042, 1.0014, 1.0027, 1.0005, 1.0053, 1.0042, 1.0055, 0.9979, 0.9993, 0.9934, 1.0149, 1.0040, 1.0076, 1.0074, 1.0035, 1.0051, + 800, 1.0038, 1.0065, 1.0017, 1.0081, 1.0027, 1.0031, 1.0014, 1.0046, 1.0075, 1.0083, 1.0053, 1.0025, 1.0096, 1.0080, 1.0003, 0.9974, 1.0081, 1.0059, 1.0060, 1.0012, 1.0005, 0.9945, 1.0136, 1.0036, 1.0117, 1.0162, 1.0027, 1.0015, + 801, 1.0057, 1.0070, 1.0017, 1.0084, 0.9998, 0.9990, 1.0015, 1.0034, 1.0081, 1.0086, 1.0035, 0.9984, 1.0010, 0.9993, 1.0030, 0.9963, 1.0081, 1.0076, 1.0040, 0.9952, 1.0051, 0.9960, 1.0161, 1.0049, 1.0103, 1.0135, 1.0087, 1.0086, + 802, 1.0023, 1.0024, 0.9994, 1.0055, 0.9978, 0.9996, 1.0017, 1.0051, 1.0043, 1.0029, 1.0011, 0.9942, 0.9998, 0.9988, 1.0007, 0.9959, 1.0038, 1.0030, 1.0030, 0.9945, 1.0003, 0.9923, 1.0118, 1.0011, 1.0102, 1.0141, 1.0070, 1.0042, + 803, 0.9940, 0.9950, 0.9983, 1.0046, 0.9925, 0.9955, 0.9980, 1.0015, 1.0007, 1.0010, 1.0016, 0.9981, 1.0014, 0.9981, 1.0031, 0.9970, 0.9973, 0.9952, 1.0018, 0.9927, 1.0025, 0.9950, 1.0077, 0.9972, 1.0009, 1.0012, 1.0030, 1.0050, + 804, 1.0016, 1.0019, 1.0038, 1.0088, 0.9979, 0.9994, 1.0002, 1.0033, 1.0040, 1.0046, 1.0060, 1.0029, 1.0047, 0.9976, 1.0056, 0.9995, 1.0057, 1.0009, 1.0057, 0.9988, 1.0084, 0.9966, 1.0129, 1.0031, 0.9997, 0.9964, 1.0023, 1.0022, + 805, 1.0015, 1.0018, 1.0021, 1.0077, 0.9999, 0.9998, 1.0024, 1.0037, 1.0042, 1.0039, 1.0051, 1.0012, 1.0137, 1.0069, 1.0034, 1.0030, 1.0036, 1.0013, 1.0057, 0.9973, 0.9968, 0.9894, 1.0123, 1.0001, 1.0071, 1.0096, 0.9996, 0.9987, + 806, 1.0065, 1.0078, 1.0063, 1.0108, 1.0027, 1.0019, 1.0057, 1.0077, 1.0085, 1.0069, 1.0064, 1.0020, 1.0113, 1.0047, 1.0056, 1.0014, 1.0103, 1.0066, 1.0099, 1.0034, 0.9990, 0.9922, 1.0158, 1.0022, 1.0116, 1.0126, 1.0103, 1.0104, + 807, 1.0015, 1.0030, 1.0006, 1.0088, 1.0012, 1.0016, 1.0034, 1.0062, 1.0034, 1.0042, 1.0016, 0.9962, 1.0055, 1.0016, 1.0039, 0.9977, 1.0067, 1.0038, 1.0047, 0.9965, 0.9997, 0.9910, 1.0139, 1.0015, 1.0073, 1.0111, 1.0047, 1.0036, + 808, 1.0029, 1.0042, 1.0060, 1.0106, 1.0004, 1.0006, 1.0047, 1.0075, 1.0060, 1.0036, 1.0053, 1.0010, 1.0074, 1.0074, 1.0035, 1.0022, 1.0060, 1.0031, 1.0099, 1.0018, 1.0104, 1.0007, 1.0169, 1.0026, 1.0088, 1.0131, 1.0066, 1.0069, + 809, 1.0017, 1.0037, 1.0038, 1.0107, 0.9980, 0.9995, 1.0025, 1.0045, 1.0043, 1.0061, 1.0040, 1.0033, 1.0018, 0.9987, 1.0159, 1.0023, 1.0045, 1.0034, 1.0064, 0.9996, 1.0095, 0.9987, 1.0159, 1.0050, 1.0066, 1.0051, 1.0055, 1.0077, + 810, 0.9994, 1.0014, 0.9996, 1.0050, 0.9966, 0.9979, 0.9991, 1.0031, 1.0028, 1.0011, 1.0037, 1.0003, 1.0071, 1.0021, 1.0032, 0.9952, 1.0018, 0.9997, 1.0042, 0.9956, 1.0050, 0.9948, 1.0111, 1.0024, 1.0040, 1.0088, 1.0049, 1.0048, + 811, 1.0004, 1.0008, 0.9999, 1.0077, 0.9972, 0.9994, 1.0003, 1.0010, 1.0028, 1.0022, 1.0022, 0.9954, 1.0064, 1.0004, 1.0021, 0.9989, 1.0024, 1.0007, 1.0032, 0.9950, 1.0007, 0.9914, 1.0108, 0.9996, 1.0069, 1.0079, 1.0073, 1.0053, + 812, 1.0040, 1.0049, 1.0027, 1.0087, 1.0010, 1.0017, 1.0031, 1.0057, 1.0066, 1.0058, 1.0054, 1.0017, 1.0196, 1.0036, 1.0028, 1.0010, 1.0071, 1.0063, 1.0075, 0.9989, 1.0005, 0.9908, 1.0146, 1.0026, 1.0061, 1.0073, 1.0015, 1.0021, + 813, 1.0022, 1.0034, 1.0018, 1.0064, 0.9981, 0.9983, 1.0043, 1.0075, 1.0032, 1.0007, 1.0049, 1.0017, 1.0182, 1.0050, 1.0017, 0.9996, 1.0023, 0.9998, 1.0045, 0.9980, 0.9966, 0.9911, 1.0141, 1.0008, 1.0075, 1.0084, 1.0010, 0.9992, + 814, 1.0036, 1.0053, 1.0039, 1.0097, 0.9972, 0.9997, 1.0019, 1.0039, 1.0039, 1.0031, 1.0051, 0.9975, 1.0027, 0.9982, 1.0038, 1.0004, 1.0068, 1.0055, 1.0054, 0.9961, 1.0065, 0.9954, 1.0148, 1.0011, 1.0110, 1.0139, 1.0100, 1.0101, + 815, 1.0000, 1.0008, 0.9979, 1.0032, 0.9970, 0.9978, 1.0002, 1.0019, 1.0038, 1.0018, 0.9985, 0.9922, 0.9988, 0.9955, 1.0003, 0.9920, 1.0022, 1.0030, 1.0030, 0.9951, 1.0025, 0.9910, 1.0097, 0.9970, 1.0069, 1.0097, 1.0092, 1.0040, + 816, 0.9970, 0.9959, 0.9988, 1.0037, 0.9961, 0.9969, 0.9976, 1.0009, 1.0023, 1.0008, 1.0029, 1.0005, 1.0034, 0.9994, 1.0065, 0.9991, 0.9988, 0.9984, 1.0035, 0.9949, 1.0014, 0.9907, 1.0072, 0.9940, 1.0038, 1.0042, 1.0017, 1.0032, + 817, 1.0015, 1.0019, 1.0006, 1.0062, 0.9969, 0.9975, 0.9991, 0.9999, 1.0035, 1.0036, 1.0032, 1.0005, 1.0046, 0.9971, 1.0052, 0.9978, 1.0016, 0.9976, 1.0070, 0.9970, 1.0003, 0.9900, 1.0123, 0.9994, 0.9997, 0.9958, 1.0011, 0.9991, + 818, 1.0008, 1.0009, 1.0019, 1.0054, 0.9993, 0.9998, 1.0014, 1.0045, 1.0020, 1.0010, 1.0048, 0.9991, 1.0106, 1.0067, 1.0010, 0.9972, 1.0042, 0.9989, 1.0059, 0.9954, 0.9948, 0.9870, 1.0130, 1.0002, 1.0074, 1.0056, 1.0007, 0.9944, + 819, 1.0049, 1.0039, 1.0052, 1.0078, 1.0007, 1.0008, 1.0029, 1.0035, 1.0054, 1.0019, 1.0032, 0.9976, 1.0088, 1.0015, 1.0037, 1.0000, 1.0072, 1.0053, 1.0085, 1.0003, 0.9952, 0.9879, 1.0141, 0.9985, 1.0076, 1.0057, 1.0090, 1.0080, + 820, 1.0013, 1.0019, 1.0022, 1.0074, 1.0019, 1.0036, 1.0034, 1.0077, 1.0070, 1.0061, 1.0018, 0.9972, 1.0101, 1.0022, 1.0025, 0.9995, 1.0063, 1.0040, 1.0057, 0.9968, 0.9983, 0.9892, 1.0163, 1.0061, 1.0095, 1.0095, 1.0054, 1.0068, + 821, 1.0055, 1.0054, 1.0002, 1.0046, 0.9991, 0.9993, 1.0007, 1.0026, 1.0058, 1.0031, 1.0067, 1.0038, 1.0074, 1.0055, 1.0003, 0.9944, 1.0050, 1.0026, 1.0065, 0.9979, 1.0047, 0.9948, 1.0129, 1.0004, 1.0098, 1.0108, 1.0076, 1.0058, + 822, 1.0070, 1.0100, 1.0018, 1.0070, 1.0005, 1.0017, 1.0012, 1.0030, 1.0087, 1.0068, 1.0031, 0.9971, 1.0051, 0.9999, 1.0044, 1.0040, 1.0070, 1.0045, 1.0029, 0.9931, 1.0051, 0.9947, 1.0151, 0.9997, 1.0076, 1.0072, 1.0076, 1.0052, + 823, 1.0004, 1.0015, 0.9980, 1.0034, 0.9961, 0.9980, 1.0002, 1.0025, 1.0021, 1.0014, 0.9992, 0.9928, 1.0045, 0.9999, 1.0004, 0.9950, 1.0010, 0.9968, 1.0033, 0.9931, 1.0016, 0.9941, 1.0119, 0.9987, 1.0038, 1.0030, 1.0032, 1.0033, + 824, 1.0013, 1.0007, 0.9987, 1.0037, 0.9984, 1.0008, 1.0004, 1.0042, 1.0053, 1.0054, 1.0018, 0.9964, 1.0039, 1.0021, 1.0051, 0.9998, 1.0024, 1.0007, 1.0044, 0.9962, 1.0018, 0.9922, 1.0137, 0.9981, 1.0078, 1.0062, 1.0073, 1.0078, + 825, 1.0032, 1.0051, 1.0029, 1.0072, 0.9998, 1.0005, 1.0023, 1.0064, 1.0049, 1.0045, 1.0044, 1.0006, 1.0066, 1.0016, 1.0045, 0.9973, 1.0060, 1.0027, 1.0041, 0.9960, 0.9977, 0.9900, 1.0150, 1.0005, 1.0056, 1.0054, 1.0096, 1.0036, + 826, 1.0036, 1.0045, 1.0029, 1.0099, 0.9997, 1.0028, 1.0052, 1.0084, 1.0070, 1.0035, 1.0061, 1.0026, 1.0057, 1.0068, 1.0031, 1.0028, 1.0040, 1.0065, 1.0063, 0.9990, 0.9937, 0.9887, 1.0128, 0.9997, 1.0060, 1.0067, 1.0020, 1.0007, + 827, 1.0021, 1.0038, 1.0027, 1.0083, 0.9963, 0.9978, 0.9994, 1.0019, 1.0037, 1.0025, 1.0040, 1.0010, 0.9989, 0.9950, 1.0157, 0.9979, 1.0029, 0.9992, 1.0020, 0.9924, 1.0021, 0.9931, 1.0124, 0.9987, 1.0073, 1.0046, 1.0084, 1.0081, + 828, 1.0018, 1.0011, 0.9973, 1.0030, 0.9982, 0.9991, 0.9999, 1.0028, 1.0031, 1.0000, 1.0020, 0.9965, 0.9976, 0.9945, 1.0004, 0.9920, 1.0023, 0.9978, 1.0021, 0.9927, 1.0014, 0.9916, 1.0117, 0.9978, 1.0129, 1.0150, 1.0086, 1.0053, + 829, 0.9973, 0.9974, 0.9942, 0.9989, 0.9943, 0.9956, 0.9964, 0.9975, 1.0048, 1.0039, 1.0014, 0.9919, 1.0040, 0.9991, 1.0016, 0.9929, 0.9991, 0.9964, 1.0014, 0.9913, 0.9987, 0.9905, 1.0128, 0.9954, 1.0011, 1.0017, 1.0036, 1.0010, + 830, 1.0016, 1.0015, 0.9996, 1.0042, 0.9958, 0.9980, 0.9979, 1.0005, 1.0038, 1.0038, 1.0034, 0.9966, 1.0030, 0.9974, 1.0050, 0.9949, 1.0017, 0.9984, 1.0038, 0.9935, 1.0019, 0.9922, 1.0160, 1.0016, 1.0013, 0.9960, 1.0017, 1.0032, + 831, 0.9933, 0.9940, 0.9992, 1.0040, 0.9967, 0.9984, 1.0003, 1.0022, 1.0007, 0.9987, 1.0016, 0.9955, 1.0056, 1.0025, 1.0011, 0.9909, 0.9992, 0.9952, 1.0040, 0.9951, 0.9945, 0.9889, 1.0110, 0.9981, 1.0016, 0.9988, 0.9989, 0.9972, + 832, 1.0021, 1.0015, 1.0035, 1.0076, 0.9993, 0.9997, 1.0020, 1.0027, 1.0052, 1.0027, 1.0062, 1.0018, 1.0056, 1.0006, 1.0033, 0.9990, 1.0072, 1.0027, 1.0093, 1.0005, 0.9978, 0.9886, 1.0157, 0.9987, 1.0102, 1.0076, 1.0096, 1.0108, + 833, 0.9990, 0.9996, 1.0024, 1.0050, 0.9954, 0.9964, 1.0016, 1.0037, 1.0035, 0.9999, 1.0040, 0.9977, 1.0070, 0.9972, 1.0017, 1.0021, 1.0023, 0.9984, 1.0110, 0.9979, 0.9969, 0.9883, 1.0158, 1.0019, 1.0073, 1.0059, 1.0071, 1.0049, + 834, 1.0037, 1.0047, 1.0034, 1.0082, 0.9978, 0.9995, 0.9999, 1.0013, 1.0045, 1.0030, 1.0050, 0.9981, 1.0095, 1.0028, 1.0056, 0.9958, 1.0040, 1.0003, 1.0061, 0.9966, 0.9982, 0.9919, 1.0161, 1.0002, 1.0103, 1.0090, 1.0075, 1.0061, + 835, 0.9991, 0.9997, 1.0004, 1.0043, 0.9982, 0.9990, 0.9991, 1.0015, 1.0043, 1.0037, 1.0034, 0.9981, 0.9991, 0.9955, 1.0064, 0.9952, 1.0022, 0.9981, 1.0032, 0.9926, 1.0035, 0.9936, 1.0135, 0.9988, 1.0032, 0.9980, 1.0063, 1.0060, + 836, 0.9990, 1.0000, 0.9988, 1.0048, 0.9964, 0.9998, 1.0005, 1.0043, 1.0028, 1.0037, 1.0021, 0.9971, 1.0038, 1.0029, 1.0053, 0.9948, 1.0025, 1.0005, 1.0051, 0.9970, 1.0008, 0.9924, 1.0151, 0.9994, 1.0055, 1.0050, 1.0055, 1.0050, + 837, 0.9988, 0.9997, 0.9973, 1.0017, 0.9969, 0.9984, 0.9997, 1.0017, 1.0046, 1.0030, 1.0034, 0.9986, 1.0023, 0.9991, 1.0043, 0.9952, 1.0026, 0.9968, 1.0041, 0.9951, 0.9972, 0.9882, 1.0110, 0.9964, 1.0085, 1.0056, 1.0103, 1.0067, + 838, 1.0034, 1.0030, 1.0015, 1.0079, 0.9996, 1.0006, 1.0032, 1.0058, 1.0053, 1.0041, 1.0040, 0.9981, 1.0024, 0.9992, 1.0059, 0.9976, 1.0050, 1.0017, 1.0082, 0.9968, 0.9941, 0.9883, 1.0152, 1.0001, 1.0064, 1.0032, 1.0063, 1.0045, + 839, 0.9996, 1.0013, 1.0003, 1.0065, 0.9973, 1.0007, 1.0011, 1.0062, 1.0046, 1.0017, 1.0039, 0.9985, 1.0037, 1.0038, 1.0019, 0.9994, 1.0017, 0.9979, 1.0071, 0.9985, 0.9926, 0.9849, 1.0127, 0.9983, 1.0073, 1.0093, 0.9998, 0.9981, + 840, 1.0039, 1.0063, 1.0023, 1.0094, 0.9983, 0.9994, 1.0009, 1.0032, 1.0070, 1.0055, 1.0057, 1.0017, 1.0008, 0.9982, 1.0025, 0.9965, 1.0060, 1.0031, 1.0037, 0.9942, 1.0003, 0.9922, 1.0136, 0.9983, 1.0103, 1.0112, 1.0079, 1.0092, + 841, 1.0006, 1.0010, 0.9964, 1.0013, 0.9977, 0.9988, 1.0000, 1.0028, 1.0020, 1.0000, 1.0015, 0.9962, 0.9963, 0.9958, 1.0003, 0.9950, 1.0017, 0.9976, 1.0033, 0.9914, 1.0004, 0.9893, 1.0112, 0.9962, 1.0099, 1.0095, 1.0064, 1.0067, + 842, 0.9933, 0.9947, 0.9925, 0.9973, 0.9947, 0.9965, 0.9961, 0.9981, 1.0018, 1.0001, 1.0014, 0.9966, 0.9999, 0.9989, 1.0002, 0.9949, 1.0013, 0.9959, 1.0014, 0.9906, 1.0006, 0.9928, 1.0070, 0.9909, 1.0003, 0.9969, 1.0054, 1.0033, + 843, 0.9975, 0.9995, 0.9981, 1.0034, 0.9925, 0.9952, 0.9962, 0.9974, 1.0007, 0.9995, 1.0008, 0.9917, 0.9977, 0.9919, 1.0028, 0.9968, 1.0001, 0.9950, 1.0053, 0.9951, 0.9981, 0.9894, 1.0121, 0.9972, 0.9975, 0.9921, 1.0033, 1.0017, + 844, 1.0013, 0.9999, 1.0029, 1.0081, 0.9977, 0.9986, 1.0021, 1.0057, 1.0024, 0.9998, 1.0014, 0.9955, 1.0104, 1.0060, 1.0035, 1.0020, 1.0047, 1.0003, 1.0083, 0.9981, 0.9935, 0.9867, 1.0150, 0.9982, 1.0066, 1.0061, 1.0010, 0.9978, + 845, 1.0077, 1.0086, 1.0063, 1.0102, 1.0008, 1.0001, 1.0064, 1.0047, 1.0091, 1.0072, 1.0091, 1.0035, 1.0084, 1.0064, 1.0066, 1.0006, 1.0098, 1.0047, 1.0151, 1.0030, 0.9963, 0.9877, 1.0159, 0.9975, 1.0120, 1.0088, 1.0114, 1.0116, + 846, 1.0042, 1.0050, 1.0041, 1.0083, 0.9995, 1.0014, 1.0040, 1.0074, 1.0050, 1.0074, 1.0047, 0.9994, 1.0042, 1.0009, 1.0037, 0.9988, 1.0091, 1.0041, 1.0069, 0.9967, 0.9970, 0.9878, 1.0146, 0.9974, 1.0076, 1.0071, 1.0047, 1.0075, + 847, 1.0011, 1.0004, 1.0016, 1.0080, 0.9969, 0.9979, 0.9998, 1.0013, 1.0042, 1.0027, 1.0062, 1.0010, 1.0031, 1.0021, 1.0008, 0.9982, 1.0057, 0.9984, 1.0067, 0.9964, 1.0004, 0.9910, 1.0136, 0.9950, 1.0074, 1.0085, 1.0056, 1.0062, + 848, 1.0043, 1.0067, 1.0031, 1.0076, 1.0000, 1.0014, 1.0026, 1.0035, 1.0060, 1.0048, 1.0047, 0.9967, 0.9990, 0.9974, 1.0054, 0.9999, 1.0056, 1.0024, 1.0084, 0.9989, 1.0031, 0.9925, 1.0165, 0.9999, 1.0055, 1.0026, 1.0054, 1.0083, + 849, 1.0031, 1.0028, 0.9981, 1.0040, 0.9956, 0.9982, 1.0016, 1.0047, 1.0032, 1.0032, 1.0047, 0.9943, 1.0037, 1.0034, 1.0035, 0.9978, 1.0039, 1.0007, 1.0101, 0.9968, 0.9992, 0.9895, 1.0149, 0.9981, 1.0044, 1.0031, 1.0069, 1.0056, + 850, 1.0006, 1.0013, 0.9996, 1.0054, 0.9972, 0.9993, 1.0015, 1.0046, 1.0052, 1.0048, 1.0065, 1.0025, 1.0033, 1.0009, 1.0055, 0.9991, 1.0020, 0.9986, 1.0077, 0.9986, 0.9971, 0.9905, 1.0119, 0.9944, 1.0053, 1.0026, 1.0067, 1.0109, + 851, 1.0001, 0.9997, 0.9990, 1.0049, 0.9956, 0.9979, 1.0013, 1.0033, 1.0015, 1.0019, 1.0090, 1.0037, 0.9981, 0.9964, 1.0047, 0.9945, 1.0015, 0.9985, 1.0049, 0.9944, 0.9941, 0.9867, 1.0118, 0.9965, 1.0038, 1.0026, 1.0018, 1.0042, + 852, 1.0038, 1.0060, 1.0024, 1.0074, 1.0021, 1.0031, 1.0027, 1.0060, 1.0065, 1.0054, 1.0046, 0.9996, 1.0066, 1.0072, 1.0035, 0.9964, 1.0057, 1.0028, 1.0093, 0.9988, 0.9933, 0.9859, 1.0160, 0.9998, 1.0119, 1.0139, 1.0015, 1.0030, + 853, 1.0016, 1.0047, 1.0029, 1.0082, 0.9971, 0.9988, 1.0008, 1.0031, 1.0039, 1.0048, 1.0016, 0.9946, 0.9985, 0.9953, 1.0046, 0.9994, 1.0035, 0.9998, 1.0055, 0.9944, 0.9971, 0.9900, 1.0164, 0.9993, 1.0091, 1.0090, 1.0090, 1.0085, + 854, 0.9992, 0.9994, 0.9986, 1.0048, 0.9972, 0.9986, 1.0019, 1.0056, 1.0024, 1.0007, 1.0044, 0.9972, 0.9974, 0.9959, 1.0019, 0.9957, 1.0017, 0.9968, 1.0047, 0.9925, 0.9996, 0.9908, 1.0148, 0.9980, 1.0083, 1.0061, 1.0067, 1.0053, + 855, 0.9933, 0.9941, 0.9919, 0.9982, 0.9933, 0.9946, 0.9974, 0.9998, 0.9998, 1.0001, 1.0032, 0.9997, 0.9984, 0.9975, 1.0039, 0.9920, 0.9981, 0.9933, 1.0024, 0.9901, 0.9988, 0.9916, 1.0068, 0.9894, 1.0038, 1.0028, 1.0029, 1.0039, + 856, 1.0017, 1.0029, 0.9994, 1.0042, 0.9959, 0.9971, 1.0006, 1.0019, 1.0025, 1.0026, 1.0049, 0.9986, 1.0000, 0.9943, 1.0027, 0.9980, 1.0015, 0.9976, 1.0062, 0.9954, 1.0005, 0.9903, 1.0147, 0.9962, 1.0041, 1.0005, 1.0012, 1.0017, + 857, 1.0014, 1.0029, 1.0004, 1.0059, 1.0004, 1.0003, 1.0003, 1.0018, 1.0048, 1.0073, 1.0073, 0.9962, 1.0113, 1.0081, 1.0012, 0.9999, 1.0042, 1.0014, 1.0047, 0.9954, 0.9912, 0.9851, 1.0194, 0.9991, 1.0069, 1.0057, 1.0040, 1.0013, + 858, 1.0069, 1.0102, 1.0058, 1.0105, 1.0028, 1.0042, 1.0036, 1.0052, 1.0084, 1.0094, 1.0098, 1.0001, 1.0080, 1.0051, 1.0043, 1.0013, 1.0085, 1.0071, 1.0110, 1.0015, 0.9923, 0.9863, 1.0158, 0.9988, 1.0111, 1.0102, 1.0084, 1.0106, + 859, 0.9990, 1.0000, 0.9970, 1.0047, 0.9976, 0.9995, 1.0014, 1.0036, 1.0025, 1.0003, 1.0036, 0.9979, 1.0009, 0.9974, 1.0032, 0.9944, 1.0043, 0.9999, 1.0052, 0.9932, 0.9964, 0.9904, 1.0131, 0.9961, 1.0079, 1.0061, 1.0032, 1.0060, + 860, 1.0035, 1.0074, 1.0040, 1.0087, 0.9995, 1.0000, 1.0028, 1.0050, 1.0059, 1.0050, 1.0047, 0.9987, 1.0062, 1.0066, 1.0040, 1.0023, 1.0058, 1.0035, 1.0114, 1.0008, 1.0037, 0.9951, 1.0189, 0.9996, 1.0111, 1.0097, 1.0068, 1.0088, + 861, 1.0053, 1.0057, 1.0057, 1.0081, 0.9990, 1.0001, 1.0026, 1.0039, 1.0053, 1.0055, 1.0042, 0.9978, 0.9993, 0.9962, 1.0064, 1.0079, 1.0035, 1.0016, 1.0092, 0.9988, 1.0026, 0.9930, 1.0147, 0.9977, 1.0054, 1.0028, 1.0050, 1.0063, + 862, 1.0023, 1.0035, 1.0009, 1.0085, 0.9977, 0.9991, 1.0023, 1.0038, 1.0031, 1.0053, 1.0028, 0.9971, 1.0064, 1.0033, 1.0048, 1.0028, 1.0032, 1.0003, 1.0073, 0.9961, 1.0017, 0.9930, 1.0147, 0.9972, 1.0075, 1.0078, 1.0016, 1.0043, + 863, 1.0009, 1.0042, 0.9965, 1.0044, 0.9985, 1.0003, 0.9990, 1.0020, 1.0027, 1.0044, 1.0064, 1.0044, 1.0021, 1.0011, 1.0010, 0.9980, 1.0013, 1.0007, 1.0056, 0.9947, 0.9975, 0.9918, 1.0100, 0.9940, 1.0077, 1.0081, 1.0039, 1.0088, + 864, 0.9989, 1.0001, 1.0001, 1.0039, 0.9975, 0.9989, 1.0020, 1.0036, 1.0008, 1.0014, 1.0040, 0.9994, 1.0014, 0.9969, 1.0020, 0.9959, 1.0022, 0.9986, 1.0051, 0.9931, 0.9998, 0.9909, 1.0140, 0.9947, 1.0073, 1.0052, 1.0012, 1.0041, + 865, 1.0019, 1.0025, 1.0003, 1.0063, 0.9972, 0.9988, 1.0037, 1.0038, 1.0039, 1.0012, 1.0016, 0.9965, 1.0033, 1.0036, 1.0011, 0.9974, 1.0039, 1.0003, 1.0068, 0.9957, 0.9978, 0.9914, 1.0159, 0.9975, 1.0097, 1.0097, 0.9996, 0.9999, + 866, 1.0038, 1.0063, 1.0005, 1.0068, 0.9984, 0.9987, 1.0003, 1.0017, 1.0040, 1.0057, 1.0027, 0.9955, 1.0025, 0.9980, 1.0007, 1.0001, 1.0037, 1.0023, 1.0063, 0.9925, 0.9993, 0.9916, 1.0143, 0.9957, 1.0077, 1.0062, 1.0074, 1.0113, + 867, 0.9969, 0.9974, 0.9944, 1.0010, 0.9931, 0.9947, 0.9984, 1.0014, 0.9996, 0.9981, 1.0043, 0.9934, 0.9962, 0.9925, 0.9995, 0.9926, 0.9999, 0.9941, 1.0023, 0.9925, 0.9988, 0.9905, 1.0113, 0.9921, 1.0066, 1.0062, 1.0038, 1.0059, + 868, 0.9992, 0.9997, 0.9960, 0.9995, 0.9972, 0.9974, 0.9989, 1.0009, 1.0023, 1.0034, 1.0043, 0.9982, 1.0024, 1.0001, 1.0028, 0.9950, 1.0029, 0.9995, 1.0054, 0.9922, 1.0009, 0.9906, 1.0109, 0.9908, 1.0054, 1.0052, 1.0038, 1.0059, + 869, 1.0036, 1.0039, 0.9995, 1.0039, 0.9985, 0.9986, 0.9996, 1.0005, 1.0034, 1.0042, 1.0017, 0.9950, 0.9997, 0.9937, 1.0042, 0.9997, 1.0018, 0.9977, 1.0065, 0.9940, 1.0014, 0.9913, 1.0163, 0.9967, 0.9981, 0.9946, 1.0001, 1.0034, + 870, 1.0000, 1.0004, 1.0042, 1.0091, 0.9976, 0.9993, 1.0046, 1.0074, 1.0032, 1.0020, 1.0048, 0.9942, 1.0080, 1.0067, 1.0084, 1.0024, 1.0043, 1.0017, 1.0102, 0.9987, 0.9922, 0.9860, 1.0186, 1.0002, 1.0052, 1.0045, 1.0005, 0.9999, + 871, 1.0026, 1.0035, 1.0034, 1.0079, 0.9987, 0.9990, 1.0023, 1.0050, 1.0049, 1.0012, 1.0109, 1.0063, 1.0035, 0.9990, 1.0063, 1.0016, 1.0055, 1.0018, 1.0141, 1.0019, 0.9938, 0.9874, 1.0171, 0.9970, 1.0111, 1.0106, 1.0084, 1.0102, + 872, 1.0024, 1.0015, 1.0045, 1.0074, 1.0019, 0.9994, 1.0061, 1.0067, 1.0036, 1.0014, 1.0075, 1.0012, 1.0030, 0.9989, 1.0059, 1.0007, 1.0071, 1.0016, 1.0089, 0.9954, 0.9963, 0.9867, 1.0156, 0.9950, 1.0107, 1.0090, 1.0062, 1.0075, + 873, 1.0040, 1.0075, 1.0020, 1.0058, 0.9987, 0.9997, 1.0022, 1.0062, 1.0053, 1.0053, 1.0100, 1.0005, 1.0064, 1.0058, 1.0040, 0.9996, 1.0046, 1.0042, 1.0108, 0.9997, 0.9998, 0.9903, 1.0188, 0.9974, 1.0100, 1.0111, 1.0070, 1.0077, + 874, 1.0008, 1.0024, 1.0022, 1.0069, 0.9961, 0.9980, 1.0011, 1.0034, 1.0046, 1.0031, 1.0079, 1.0000, 0.9980, 0.9947, 1.0061, 0.9990, 1.0029, 0.9995, 1.0093, 0.9978, 1.0011, 0.9925, 1.0178, 0.9999, 1.0083, 1.0085, 1.0036, 1.0089, + 875, 0.9950, 0.9975, 0.9968, 1.0019, 0.9935, 0.9954, 0.9998, 1.0018, 0.9993, 0.9991, 0.9998, 0.9933, 1.0003, 0.9954, 1.0033, 0.9992, 0.9997, 0.9963, 1.0087, 0.9957, 0.9947, 0.9884, 1.0139, 0.9955, 1.0037, 1.0049, 1.0024, 1.0042, + 876, 1.0025, 1.0049, 1.0036, 1.0088, 0.9980, 0.9992, 1.0012, 1.0032, 1.0033, 1.0037, 1.0048, 0.9992, 1.0021, 1.0006, 1.0042, 1.0014, 1.0032, 0.9993, 1.0101, 0.9969, 0.9983, 0.9901, 1.0164, 0.9994, 1.0076, 1.0089, 1.0055, 1.0084, + 877, 0.9998, 1.0008, 1.0011, 1.0057, 0.9986, 1.0000, 1.0031, 1.0063, 1.0023, 1.0013, 1.0047, 0.9992, 1.0004, 0.9993, 1.0032, 0.9998, 1.0025, 0.9998, 1.0091, 0.9954, 0.9976, 0.9916, 1.0151, 0.9966, 1.0055, 1.0028, 1.0021, 1.0045, + 878, 1.0010, 1.0026, 1.0000, 1.0035, 0.9990, 0.9996, 1.0028, 1.0053, 1.0035, 1.0010, 1.0065, 1.0026, 1.0025, 1.0044, 1.0027, 0.9993, 1.0035, 1.0011, 1.0093, 0.9972, 0.9983, 0.9906, 1.0158, 0.9977, 1.0072, 1.0093, 0.9990, 1.0024, + 879, 1.0025, 1.0038, 1.0002, 1.0031, 0.9952, 0.9963, 1.0007, 1.0008, 1.0030, 1.0029, 1.0042, 0.9975, 0.9953, 0.9947, 0.9997, 0.9963, 1.0016, 0.9997, 1.0075, 0.9937, 0.9961, 0.9887, 1.0131, 0.9928, 1.0097, 1.0114, 1.0056, 1.0092, + 880, 1.0013, 1.0029, 0.9984, 1.0019, 0.9981, 0.9992, 1.0016, 1.0048, 1.0039, 1.0034, 1.0008, 0.9940, 0.9976, 0.9957, 0.9996, 0.9961, 1.0047, 1.0001, 1.0075, 0.9944, 0.9977, 0.9898, 1.0148, 0.9943, 1.0121, 1.0127, 1.0040, 1.0082, + 881, 0.9978, 0.9987, 0.9972, 1.0002, 0.9960, 0.9970, 0.9981, 1.0004, 1.0021, 1.0016, 1.0022, 0.9951, 1.0015, 0.9998, 1.0028, 0.9956, 1.0016, 0.9983, 1.0071, 0.9943, 0.9988, 0.9903, 1.0100, 0.9898, 1.0041, 1.0032, 1.0029, 1.0068, + 882, 0.9991, 0.9997, 1.0002, 1.0039, 0.9973, 0.9977, 1.0000, 1.0021, 1.0028, 1.0040, 1.0052, 0.9993, 1.0009, 0.9948, 1.0059, 1.0013, 1.0004, 0.9961, 1.0088, 0.9971, 1.0000, 0.9905, 1.0136, 0.9946, 1.0011, 1.0005, 0.9981, 1.0035, + 883, 0.9946, 0.9960, 0.9983, 1.0017, 0.9945, 0.9960, 1.0011, 1.0040, 0.9999, 0.9988, 1.0040, 0.9972, 1.0025, 1.0016, 1.0029, 0.9972, 0.9985, 0.9933, 1.0084, 0.9948, 0.9927, 0.9859, 1.0135, 0.9941, 1.0046, 1.0044, 0.9996, 0.9984, + 884, 1.0068, 1.0081, 1.0068, 1.0093, 1.0011, 1.0015, 1.0060, 1.0080, 1.0070, 1.0065, 1.0065, 1.0010, 1.0068, 1.0032, 1.0052, 1.0051, 1.0098, 1.0058, 1.0157, 1.0032, 0.9924, 0.9857, 1.0181, 0.9956, 1.0127, 1.0114, 1.0077, 1.0118, + 885, 1.0017, 1.0010, 1.0001, 1.0029, 0.9985, 0.9997, 1.0043, 1.0069, 1.0030, 1.0015, 1.0055, 0.9954, 1.0048, 0.9996, 1.0033, 0.9961, 1.0038, 1.0045, 1.0072, 0.9932, 0.9944, 0.9871, 1.0155, 0.9956, 1.0078, 1.0114, 1.0053, 1.0064, + 886, 1.0031, 1.0072, 1.0028, 1.0050, 0.9979, 0.9993, 1.0026, 1.0032, 1.0060, 1.0051, 1.0084, 1.0011, 1.0053, 1.0050, 1.0049, 1.0008, 1.0051, 1.0078, 1.0110, 1.0007, 1.0004, 0.9919, 1.0175, 0.9965, 1.0121, 1.0133, 1.0050, 1.0096, + 887, 0.9979, 0.9987, 1.0013, 1.0036, 0.9943, 0.9955, 1.0000, 1.0026, 1.0019, 1.0024, 1.0056, 0.9985, 0.9941, 0.9935, 1.0059, 1.0140, 1.0016, 1.0008, 1.0081, 0.9939, 1.0021, 0.9925, 1.0167, 0.9986, 1.0050, 1.0045, 1.0018, 1.0076, + 888, 0.9959, 0.9974, 0.9994, 1.0010, 0.9953, 0.9979, 1.0008, 1.0012, 1.0024, 1.0028, 1.0027, 0.9954, 1.0032, 1.0012, 1.0038, 0.9966, 1.0018, 0.9989, 1.0086, 0.9962, 1.0022, 0.9934, 1.0166, 0.9977, 1.0049, 1.0067, 1.0061, 1.0070, + 889, 1.0002, 1.0006, 0.9995, 1.0044, 0.9964, 0.9994, 1.0006, 1.0049, 1.0022, 1.0030, 1.0041, 0.9966, 1.0018, 1.0000, 1.0079, 1.0001, 1.0030, 1.0008, 1.0091, 0.9962, 0.9988, 0.9919, 1.0173, 0.9977, 1.0077, 1.0097, 1.0068, 1.0107, + 890, 1.0009, 1.0027, 1.0009, 1.0051, 0.9968, 0.9987, 1.0023, 1.0053, 1.0040, 1.0016, 1.0070, 1.0017, 1.0018, 0.9995, 1.0035, 0.9984, 1.0043, 1.0023, 1.0107, 0.9998, 0.9992, 0.9913, 1.0181, 1.0002, 1.0052, 1.0057, 1.0029, 1.0088, + 891, 1.0012, 1.0029, 0.9984, 1.0027, 0.9967, 0.9986, 1.0015, 1.0054, 1.0036, 1.0036, 1.0049, 1.0001, 1.0035, 1.0028, 1.0015, 0.9931, 1.0030, 1.0001, 1.0092, 0.9972, 0.9927, 0.9890, 1.0153, 0.9964, 1.0063, 1.0122, 0.9977, 1.0007, + 892, 1.0063, 1.0085, 1.0039, 1.0079, 0.9991, 1.0006, 1.0008, 1.0019, 1.0074, 1.0093, 1.0035, 0.9981, 1.0002, 0.9983, 1.0042, 1.0000, 1.0065, 1.0047, 1.0083, 0.9949, 1.0006, 0.9929, 1.0158, 0.9975, 1.0074, 1.0102, 1.0069, 1.0093, + 893, 1.0009, 1.0011, 0.9970, 0.9997, 0.9968, 0.9990, 1.0023, 1.0030, 1.0026, 1.0024, 1.0020, 0.9954, 0.9983, 0.9966, 1.0044, 0.9941, 1.0027, 0.9983, 1.0042, 0.9922, 0.9985, 0.9910, 1.0140, 0.9939, 1.0063, 1.0107, 1.0033, 1.0073, + 894, 0.9974, 0.9983, 0.9950, 0.9998, 0.9947, 0.9960, 0.9972, 0.9989, 1.0005, 1.0002, 1.0010, 0.9936, 0.9991, 0.9988, 1.0067, 1.0025, 1.0009, 0.9968, 1.0051, 0.9917, 0.9995, 0.9923, 1.0113, 0.9909, 1.0002, 1.0021, 1.0024, 1.0088, + 895, 0.9978, 0.9975, 0.9963, 0.9973, 0.9930, 0.9949, 0.9985, 0.9990, 1.0006, 1.0003, 1.0013, 0.9935, 0.9980, 0.9907, 1.0047, 0.9963, 0.9990, 0.9963, 1.0079, 0.9939, 0.9981, 0.9888, 1.0133, 0.9934, 0.9976, 0.9969, 1.0044, 1.0014, + 896, 0.9976, 0.9983, 1.0023, 1.0052, 0.9973, 0.9986, 1.0027, 1.0050, 1.0026, 1.0014, 1.0053, 0.9932, 1.0073, 1.0100, 1.0025, 0.9950, 1.0028, 1.0010, 1.0104, 0.9961, 0.9897, 0.9854, 1.0161, 0.9951, 1.0078, 1.0110, 0.9980, 0.9995, + 897, 1.0059, 1.0058, 1.0048, 1.0082, 0.9999, 1.0000, 1.0040, 1.0031, 1.0060, 1.0054, 1.0069, 1.0000, 1.0056, 1.0056, 1.0088, 1.0012, 1.0086, 1.0042, 1.0151, 1.0036, 0.9943, 0.9881, 1.0167, 0.9925, 1.0105, 1.0099, 1.0130, 1.0113, + 898, 0.9968, 0.9943, 0.9999, 1.0021, 0.9954, 0.9969, 1.0036, 1.0065, 0.9999, 0.9965, 1.0061, 0.9989, 0.9983, 0.9949, 1.0043, 0.9948, 1.0007, 0.9960, 1.0073, 0.9927, 0.9985, 0.9898, 1.0153, 0.9924, 1.0091, 1.0147, 1.0111, 1.0078, + 899, 0.9993, 0.9995, 1.0004, 1.0025, 0.9971, 0.9969, 1.0018, 1.0037, 1.0023, 1.0014, 1.0062, 0.9939, 1.0010, 1.0020, 1.0043, 0.9992, 1.0011, 0.9972, 1.0127, 0.9989, 0.9989, 0.9910, 1.0176, 0.9947, 1.0065, 1.0075, 1.0047, 1.0068, + 900, 1.0011, 1.0012, 1.0027, 1.0077, 0.9973, 1.0002, 1.0027, 1.0064, 1.0069, 1.0073, 1.0099, 0.9942, 1.0000, 0.9985, 1.0085, 1.0002, 1.0051, 1.0009, 1.0125, 0.9979, 1.0024, 0.9944, 1.0201, 0.9998, 1.0060, 1.0054, 1.0054, 1.0094, + 901, 0.9981, 0.9991, 0.9970, 1.0006, 0.9957, 0.9970, 1.0000, 1.0025, 1.0017, 1.0014, 1.0060, 0.9984, 1.0015, 0.9991, 1.0016, 0.9916, 1.0017, 0.9974, 1.0123, 0.9951, 1.0004, 0.9938, 1.0144, 0.9921, 1.0060, 1.0060, 1.0020, 1.0052, + 902, 1.0005, 1.0009, 0.9967, 0.9993, 0.9960, 0.9981, 0.9997, 1.0024, 1.0040, 1.0027, 1.0059, 1.0006, 1.0004, 1.0002, 1.0029, 0.9947, 1.0032, 1.0004, 1.0114, 0.9964, 0.9997, 0.9923, 1.0129, 0.9905, 1.0102, 1.0122, 1.0042, 1.0103, + 903, 1.0006, 1.0021, 0.9987, 1.0004, 0.9969, 0.9991, 1.0012, 1.0040, 1.0032, 1.0035, 1.0010, 0.9928, 0.9990, 0.9970, 1.0021, 0.9981, 1.0039, 1.0009, 1.0110, 0.9972, 0.9941, 0.9866, 1.0151, 0.9932, 1.0050, 1.0080, 0.9984, 1.0045, + 904, 1.0063, 1.0080, 1.0051, 1.0087, 1.0008, 1.0016, 1.0037, 1.0086, 1.0063, 1.0065, 1.0041, 0.9961, 1.0049, 1.0059, 1.0034, 0.9993, 1.0064, 1.0043, 1.0138, 1.0044, 0.9923, 0.9877, 1.0189, 0.9963, 1.0094, 1.0145, 1.0000, 1.0015, + 905, 1.0017, 1.0043, 1.0051, 1.0079, 0.9994, 1.0004, 1.0032, 1.0070, 1.0066, 1.0051, 1.0056, 0.9958, 0.9986, 0.9989, 1.0044, 1.0010, 1.0048, 1.0012, 1.0132, 0.9975, 1.0002, 0.9925, 1.0174, 0.9967, 1.0094, 1.0121, 1.0072, 1.0108, + 906, 0.9970, 0.9981, 0.9978, 1.0024, 0.9966, 0.9986, 1.0021, 1.0045, 1.0021, 0.9983, 1.0117, 1.0016, 0.9941, 0.9953, 1.0018, 0.9960, 1.0010, 0.9969, 1.0097, 0.9951, 1.0012, 0.9941, 1.0114, 0.9882, 1.0085, 1.0106, 1.0063, 1.0063, + 907, 0.9931, 0.9935, 0.9935, 0.9956, 0.9915, 0.9939, 0.9960, 0.9970, 1.0006, 1.0007, 1.0049, 0.9976, 1.0018, 0.9962, 1.0038, 0.9985, 0.9993, 0.9948, 1.0057, 0.9911, 0.9946, 0.9891, 1.0102, 0.9863, 1.0007, 1.0001, 1.0016, 1.0051, + 908, 1.0001, 1.0022, 1.0025, 1.0052, 0.9971, 0.9994, 1.0013, 1.0034, 1.0056, 1.0052, 1.0050, 0.9936, 1.0013, 0.9958, 1.0077, 0.9987, 1.0045, 1.0016, 1.0125, 1.0003, 0.9969, 0.9894, 1.0167, 0.9955, 1.0043, 1.0044, 1.0028, 1.0047, + 909, 0.9980, 1.0007, 1.0017, 1.0045, 0.9986, 0.9997, 1.0021, 1.0034, 1.0037, 1.0024, 1.0052, 0.9969, 1.0100, 1.0080, 1.0044, 0.9996, 1.0024, 1.0001, 1.0116, 0.9988, 0.9901, 0.9859, 1.0198, 0.9964, 1.0057, 1.0070, 0.9967, 0.9983, + 910, 1.0031, 1.0048, 1.0052, 1.0076, 0.9992, 0.9999, 1.0047, 1.0043, 1.0060, 1.0029, 1.0190, 1.0060, 1.0047, 1.0014, 1.0078, 1.0096, 1.0062, 1.0032, 1.0166, 1.0025, 0.9941, 0.9886, 1.0203, 0.9964, 1.0133, 1.0146, 1.0113, 1.0121, + 911, 0.9971, 0.9990, 0.9996, 1.0005, 0.9969, 0.9985, 1.0036, 1.0073, 1.0021, 0.9990, 1.0067, 0.9948, 0.9996, 0.9969, 1.0047, 0.9971, 1.0026, 0.9974, 1.0099, 0.9972, 0.9979, 0.9911, 1.0175, 0.9953, 1.0101, 1.0130, 1.0066, 1.0076, + 912, 1.0032, 1.0059, 1.0039, 1.0081, 0.9989, 1.0014, 1.0046, 1.0068, 1.0068, 1.0055, 1.0038, 0.9955, 1.0068, 1.0072, 1.0029, 1.0007, 1.0066, 1.0035, 1.0177, 1.0018, 1.0003, 0.9932, 1.0209, 0.9957, 1.0109, 1.0142, 1.0124, 1.0085, + 913, 1.0006, 1.0034, 1.0040, 1.0064, 0.9981, 0.9997, 1.0011, 1.0049, 1.0056, 1.0039, 1.0061, 1.0040, 0.9981, 0.9982, 1.0062, 1.0004, 1.0053, 1.0011, 1.0126, 0.9982, 1.0019, 0.9923, 1.0188, 0.9982, 1.0053, 1.0059, 1.0032, 1.0081, + 914, 0.9998, 1.0017, 0.9981, 1.0011, 0.9978, 0.9990, 1.0020, 1.0039, 1.0037, 1.0018, 1.0099, 1.0016, 1.0051, 1.0019, 1.0037, 0.9946, 1.0020, 0.9993, 1.0100, 0.9976, 0.9969, 0.9909, 1.0181, 0.9949, 1.0070, 1.0075, 1.0012, 1.0043, + 915, 0.9975, 0.9994, 0.9946, 0.9979, 0.9953, 0.9979, 0.9997, 1.0004, 1.0034, 1.0053, 1.0060, 0.9986, 1.0020, 0.9991, 1.0064, 0.9970, 1.0013, 0.9979, 1.0083, 0.9923, 0.9986, 0.9919, 1.0127, 0.9908, 1.0070, 1.0073, 1.0024, 1.0081, + 916, 1.0030, 1.0066, 1.0029, 1.0072, 0.9992, 1.0018, 1.0043, 1.0070, 1.0065, 1.0061, 1.0042, 0.9970, 1.0043, 1.0033, 1.0048, 1.0089, 1.0055, 1.0051, 1.0126, 0.9997, 0.9998, 0.9947, 1.0192, 0.9988, 1.0085, 1.0113, 1.0016, 1.0088, + 917, 1.0012, 1.0039, 1.0023, 1.0059, 0.9983, 0.9998, 1.0042, 1.0067, 1.0044, 1.0032, 1.0039, 0.9963, 1.0048, 1.0045, 1.0037, 1.0105, 1.0021, 0.9994, 1.0131, 0.9976, 0.9908, 0.9875, 1.0172, 0.9963, 1.0092, 1.0097, 1.0002, 1.0009, + 918, 0.9969, 1.0001, 0.9991, 1.0013, 0.9998, 0.9998, 1.0029, 1.0049, 1.0049, 1.0004, 1.0064, 1.0009, 0.9981, 0.9966, 1.0038, 1.0022, 1.0026, 0.9981, 1.0142, 0.9993, 0.9976, 0.9920, 1.0099, 0.9876, 1.0124, 1.0159, 1.0046, 1.0072, + 919, 0.9971, 0.9988, 0.9936, 0.9965, 0.9929, 0.9970, 1.0016, 1.0033, 1.0019, 0.9987, 1.0039, 0.9968, 0.9935, 0.9931, 1.0024, 0.9930, 1.0002, 0.9945, 1.0092, 0.9935, 0.9993, 0.9911, 1.0126, 0.9872, 1.0110, 1.0136, 1.0031, 1.0071, + 920, 0.9936, 0.9992, 0.9956, 0.9976, 0.9955, 0.9981, 0.9975, 1.0002, 1.0035, 1.0047, 1.0011, 0.9895, 1.0022, 1.0024, 1.0049, 1.0017, 1.0011, 0.9985, 1.0094, 0.9950, 0.9954, 0.9902, 1.0126, 0.9887, 1.0045, 1.0037, 1.0000, 1.0063, + 921, 0.9984, 1.0003, 1.0021, 1.0033, 0.9955, 0.9981, 1.0036, 1.0042, 1.0026, 1.0001, 1.0042, 0.9924, 0.9990, 0.9942, 1.0103, 1.0127, 1.0016, 0.9957, 1.0145, 1.0062, 1.0012, 0.9929, 1.0168, 0.9963, 1.0030, 1.0012, 1.0000, 1.0020, + 922, 0.9975, 0.9990, 0.9997, 1.0031, 0.9982, 0.9993, 1.0019, 1.0032, 1.0032, 1.0033, 1.0078, 1.0019, 1.0092, 1.0061, 1.0080, 0.9974, 1.0010, 1.0013, 1.0133, 0.9972, 0.9916, 0.9860, 1.0182, 0.9946, 1.0080, 1.0075, 0.9959, 1.0015, + 923, 1.0035, 1.0072, 1.0039, 1.0055, 0.9991, 1.0014, 1.0043, 1.0035, 1.0084, 1.0059, 1.0064, 0.9989, 1.0145, 1.0022, 1.0101, 1.0079, 1.0075, 1.0027, 1.0172, 1.0025, 0.9928, 0.9866, 1.0190, 0.9943, 1.0140, 1.0116, 1.0086, 1.0109, + 924, 1.0011, 1.0052, 1.0023, 1.0033, 1.0015, 1.0033, 1.0040, 1.0079, 1.0074, 1.0047, 1.0057, 0.9999, 1.0097, 1.0019, 1.0067, 1.0029, 1.0068, 1.0056, 1.0121, 0.9954, 1.0017, 0.9946, 1.0185, 0.9970, 1.0123, 1.0162, 1.0069, 1.0110, + 925, 1.0047, 1.0067, 1.0038, 1.0026, 1.0006, 1.0005, 1.0043, 1.0055, 1.0102, 1.0036, 1.0073, 0.9983, 1.0082, 1.0061, 1.0093, 1.0078, 1.0076, 1.0059, 1.0175, 1.0008, 1.0040, 0.9940, 1.0200, 0.9949, 1.0181, 1.0174, 1.0070, 1.0108, + 926, 1.0039, 1.0080, 1.0015, 1.0045, 0.9996, 1.0015, 1.0027, 1.0056, 1.0073, 1.0068, 1.0059, 0.9981, 1.0037, 1.0009, 1.0062, 1.0116, 1.0058, 1.0027, 1.0131, 0.9970, 1.0015, 0.9928, 1.0182, 0.9961, 1.0160, 1.0194, 1.0062, 1.0087, + 927, 0.9975, 1.0024, 0.9985, 1.0014, 0.9967, 0.9986, 1.0020, 1.0020, 1.0043, 1.0029, 1.0014, 0.9918, 1.0068, 1.0016, 1.0032, 1.0036, 1.0015, 0.9991, 1.0115, 0.9936, 0.9956, 0.9900, 1.0154, 0.9928, 1.0063, 1.0068, 1.0014, 1.0057, + 928, 0.9974, 1.0033, 1.0011, 1.0044, 0.9978, 1.0009, 1.0022, 1.0047, 1.0072, 1.0049, 1.0054, 0.9995, 1.0034, 1.0029, 1.0087, 1.0048, 1.0054, 1.0019, 1.0142, 0.9998, 0.9991, 0.9920, 1.0159, 0.9950, 1.0089, 1.0096, 1.0055, 1.0103, + 929, 1.0030, 1.0061, 1.0023, 1.0041, 0.9976, 0.9994, 1.0052, 1.0069, 1.0059, 1.0049, 1.0082, 1.0014, 1.0052, 1.0002, 1.0063, 0.9988, 1.0039, 1.0019, 1.0131, 0.9958, 0.9965, 0.9893, 1.0175, 0.9951, 1.0086, 1.0078, 1.0022, 1.0061, + 930, 1.0033, 1.0085, 1.0009, 1.0033, 0.9971, 1.0004, 1.0040, 1.0068, 1.0064, 1.0032, 1.0128, 1.0014, 1.0062, 1.0059, 1.0053, 1.0002, 1.0048, 1.0011, 1.0163, 0.9988, 0.9925, 0.9875, 1.0175, 0.9934, 1.0105, 1.0123, 1.0000, 1.0006, + 931, 1.0012, 1.0045, 0.9984, 1.0015, 0.9972, 0.9988, 1.0028, 1.0021, 1.0065, 1.0035, 1.0073, 0.9960, 0.9960, 0.9963, 1.0040, 1.0012, 1.0053, 1.0014, 1.0125, 0.9960, 0.9956, 0.9881, 1.0145, 0.9925, 1.0124, 1.0131, 1.0052, 1.0090, + 932, 1.0009, 1.0060, 0.9978, 0.9991, 0.9981, 0.9994, 1.0021, 1.0037, 1.0071, 1.0031, 1.0014, 0.9938, 1.0003, 1.0012, 1.0031, 1.0050, 1.0064, 1.0029, 1.0142, 0.9964, 1.0008, 0.9919, 1.0175, 0.9963, 1.0125, 1.0162, 1.0093, 1.0081, + 933, 0.9984, 1.0018, 0.9948, 0.9972, 0.9941, 0.9975, 0.9962, 0.9971, 1.0026, 1.0036, 1.0032, 0.9964, 1.0001, 0.9992, 1.0053, 0.9976, 1.0004, 0.9962, 1.0093, 0.9920, 0.9969, 0.9924, 1.0126, 0.9898, 1.0039, 1.0040, 1.0000, 1.0065, + 934, 1.0007, 1.0024, 1.0019, 1.0025, 0.9949, 0.9971, 1.0010, 1.0009, 1.0052, 1.0031, 1.0050, 0.9956, 1.0010, 0.9951, 1.0054, 1.0000, 1.0034, 0.9986, 1.0133, 0.9954, 0.9990, 0.9919, 1.0199, 0.9967, 0.9999, 0.9964, 0.9983, 1.0026, + 935, 0.9967, 1.0002, 0.9995, 1.0013, 0.9975, 0.9987, 1.0028, 1.0043, 1.0038, 1.0022, 1.0029, 0.9955, 1.0084, 1.0066, 1.0039, 1.0032, 1.0017, 0.9973, 1.0141, 0.9976, 0.9908, 0.9871, 1.0171, 0.9942, 1.0073, 1.0071, 0.9956, 0.9993, + 936, 1.0080, 1.0120, 1.0062, 1.0071, 1.0031, 1.0044, 1.0062, 1.0068, 1.0098, 1.0067, 1.0090, 1.0004, 1.0083, 1.0054, 1.0080, 1.0023, 1.0105, 1.0074, 1.0220, 1.0051, 0.9945, 0.9870, 1.0189, 0.9933, 1.0153, 1.0168, 1.0097, 1.0123, + 937, 1.0036, 1.0064, 1.0019, 1.0024, 1.0002, 1.0021, 1.0050, 1.0079, 1.0077, 1.0049, 1.0087, 1.0014, 1.0042, 1.0016, 1.0066, 0.9971, 1.0094, 1.0061, 1.0151, 0.9958, 0.9995, 0.9908, 1.0185, 0.9948, 1.0130, 1.0166, 1.0011, 1.0083, + 938, 1.0040, 1.0068, 1.0029, 1.0039, 0.9986, 1.0011, 1.0036, 1.0044, 1.0070, 1.0036, 1.0122, 1.0021, 1.0106, 1.0072, 1.0063, 1.0022, 1.0114, 1.0057, 1.0181, 1.0008, 0.9977, 0.9918, 1.0186, 0.9949, 1.0115, 1.0146, 1.0026, 1.0086, + 939, 1.0007, 1.0026, 1.0002, 1.0037, 1.0003, 1.0020, 1.0039, 1.0056, 1.0061, 1.0028, 1.0064, 0.9963, 1.0025, 0.9967, 1.0065, 1.0051, 1.0049, 1.0043, 1.0143, 0.9958, 1.0009, 0.9912, 1.0189, 0.9952, 1.0096, 1.0100, 1.0009, 1.0056, + 940, 0.9985, 1.0014, 1.0020, 1.0043, 0.9967, 0.9996, 1.0043, 1.0061, 1.0049, 1.0010, 1.0091, 0.9947, 1.0034, 1.0037, 1.0065, 0.9982, 1.0048, 1.0014, 1.0167, 0.9979, 0.9977, 0.9917, 1.0180, 0.9945, 1.0105, 1.0111, 1.0035, 1.0080, + 941, 0.9987, 1.0016, 1.0013, 1.0037, 0.9984, 1.0020, 1.0040, 1.0060, 1.0066, 1.0029, 1.0160, 1.0005, 1.0021, 1.0021, 1.0071, 1.0017, 1.0041, 1.0001, 1.0149, 0.9988, 0.9961, 0.9889, 1.0180, 0.9936, 1.0125, 1.0179, 1.0082, 1.0103, + 942, 1.0030, 1.0056, 1.0025, 1.0054, 1.0007, 1.0020, 1.0047, 1.0076, 1.0057, 1.0012, 1.0198, 1.0040, 1.0020, 0.9999, 1.0101, 1.0017, 1.0077, 1.0045, 1.0167, 0.9987, 0.9965, 0.9890, 1.0199, 0.9965, 1.0133, 1.0166, 1.0104, 1.0077, + 943, 1.0016, 1.0075, 0.9998, 1.0043, 0.9995, 1.0039, 1.0032, 1.0080, 1.0070, 1.0055, 1.0087, 1.0035, 1.0156, 1.0089, 1.0044, 1.0010, 1.0062, 1.0041, 1.0155, 1.0000, 0.9925, 0.9897, 1.0176, 0.9963, 1.0091, 1.0141, 1.0028, 1.0061, + 944, 1.0006, 1.0039, 1.0034, 1.0035, 0.9991, 1.0014, 1.0037, 1.0062, 1.0090, 1.0059, 1.0069, 0.9974, 1.0129, 1.0019, 1.0061, 0.9977, 1.0064, 1.0050, 1.0172, 0.9969, 1.0012, 0.9937, 1.0183, 0.9923, 1.0153, 1.0182, 1.0122, 1.0126, + 945, 0.9990, 1.0005, 0.9983, 0.9999, 0.9959, 0.9989, 1.0032, 1.0056, 1.0042, 1.0006, 1.0063, 0.9977, 1.0122, 0.9980, 1.0030, 0.9930, 1.0039, 0.9983, 1.0126, 0.9940, 1.0027, 0.9938, 1.0199, 0.9934, 1.0124, 1.0191, 1.0039, 1.0095, + 946, 0.9979, 1.0023, 1.0003, 1.0035, 0.9943, 0.9984, 0.9987, 0.9996, 1.0041, 1.0005, 1.0047, 0.9985, 1.0114, 1.0011, 1.0064, 0.9963, 1.0015, 0.9968, 1.0132, 0.9951, 0.9976, 0.9907, 1.0161, 0.9932, 1.0062, 1.0096, 1.0076, 1.0093, + 947, 0.9966, 0.9984, 0.9961, 0.9984, 0.9975, 0.9980, 1.0006, 1.0012, 1.0027, 1.0004, 1.0048, 0.9962, 1.0000, 0.9956, 1.0100, 0.9964, 1.0021, 0.9984, 1.0130, 0.9936, 0.9975, 0.9896, 1.0152, 0.9931, 0.9995, 0.9969, 1.0049, 1.0042, + 948, 1.0021, 1.0046, 1.0011, 1.0024, 1.0010, 1.0029, 1.0037, 1.0042, 1.0073, 1.0056, 1.0063, 0.9995, 1.0146, 1.0106, 1.0051, 1.0018, 1.0079, 1.0042, 1.0168, 0.9970, 0.9941, 0.9879, 1.0193, 0.9930, 1.0104, 1.0150, 0.9982, 1.0021, + 949, 1.0069, 1.0097, 1.0036, 1.0031, 1.0014, 1.0035, 1.0057, 1.0037, 1.0099, 1.0064, 1.0099, 1.0016, 1.0095, 1.0057, 1.0099, 1.0059, 1.0099, 1.0074, 1.0180, 1.0006, 0.9937, 0.9861, 1.0200, 0.9934, 1.0137, 1.0161, 1.0091, 1.0141, + 950, 1.0035, 1.0053, 1.0035, 1.0049, 1.0016, 1.0036, 1.0068, 1.0079, 1.0079, 1.0050, 1.0100, 0.9955, 1.0087, 1.0043, 1.0127, 1.0002, 1.0099, 1.0067, 1.0188, 0.9940, 0.9939, 0.9873, 1.0203, 0.9971, 1.0130, 1.0155, 1.0033, 1.0089, + 951, 1.0021, 1.0028, 1.0035, 1.0059, 0.9979, 1.0001, 1.0047, 1.0051, 1.0066, 1.0019, 1.0109, 0.9980, 1.0065, 1.0065, 1.0053, 0.9968, 1.0056, 1.0021, 1.0190, 0.9997, 0.9983, 0.9913, 1.0190, 0.9935, 1.0120, 1.0140, 1.0060, 1.0084, + 952, 1.0021, 1.0025, 1.0056, 1.0057, 1.0003, 1.0029, 1.0056, 1.0057, 1.0086, 1.0053, 1.0095, 1.0030, 1.0001, 0.9999, 1.0101, 1.0025, 1.0079, 1.0043, 1.0167, 0.9978, 1.0059, 0.9950, 1.0181, 0.9951, 1.0101, 1.0101, 1.0097, 1.0095, + 953, 1.0011, 1.0035, 0.9991, 1.0009, 0.9987, 0.9995, 1.0036, 1.0025, 1.0047, 1.0004, 1.0086, 0.9990, 1.0038, 1.0034, 1.0050, 1.0019, 1.0066, 1.0028, 1.0161, 0.9960, 0.9990, 0.9916, 1.0169, 0.9925, 1.0105, 1.0147, 1.0057, 1.0088, + 954, 1.0004, 1.0017, 0.9978, 0.9989, 0.9978, 1.0013, 1.0037, 1.0043, 1.0075, 1.0046, 1.0081, 0.9980, 1.0054, 1.0041, 1.0077, 0.9968, 1.0067, 1.0013, 1.0154, 0.9944, 0.9972, 0.9894, 1.0150, 0.9897, 1.0115, 1.0166, 1.0077, 1.0108, + 955, 1.0009, 1.0032, 1.0022, 1.0049, 0.9996, 1.0011, 1.0056, 1.0064, 1.0054, 1.0031, 1.0056, 0.9968, 1.0033, 1.0026, 1.0107, 0.9974, 1.0067, 1.0044, 1.0147, 0.9934, 0.9937, 0.9888, 1.0172, 0.9945, 1.0081, 1.0103, 1.0069, 1.0085, + 956, 1.0037, 1.0065, 1.0040, 1.0070, 1.0032, 1.0046, 1.0062, 1.0099, 1.0085, 1.0063, 1.0085, 0.9995, 1.0083, 1.0104, 1.0162, 1.0025, 1.0082, 1.0082, 1.0190, 1.0012, 0.9960, 0.9921, 1.0201, 0.9961, 1.0105, 1.0148, 1.0020, 1.0046, + 957, 1.0031, 1.0046, 1.0037, 1.0061, 0.9984, 0.9994, 1.0048, 1.0052, 1.0087, 1.0039, 1.0074, 1.0016, 0.9985, 1.0001, 1.0115, 1.0023, 1.0058, 1.0015, 1.0157, 0.9954, 1.0024, 0.9942, 1.0146, 0.9915, 1.0126, 1.0150, 1.0105, 1.0125, + 958, 1.0021, 1.0038, 0.9980, 1.0005, 0.9986, 1.0008, 1.0039, 1.0026, 1.0055, 1.0012, 1.0070, 0.9975, 0.9973, 0.9998, 1.0037, 0.9942, 1.0090, 1.0031, 1.0144, 0.9942, 0.9989, 0.9905, 1.0177, 0.9930, 1.0144, 1.0186, 1.0106, 1.0117, + 959, 0.9956, 0.9994, 1.0005, 1.0025, 0.9946, 0.9977, 0.9974, 0.9970, 1.0043, 1.0026, 1.0018, 0.9936, 1.0022, 1.0010, 1.0059, 0.9948, 1.0079, 0.9989, 1.0122, 0.9913, 0.9953, 0.9882, 1.0123, 0.9875, 1.0061, 1.0090, 1.0139, 1.0080, + 960, 1.0026, 1.0050, 1.0004, 1.0033, 0.9986, 1.0019, 1.0035, 1.0033, 1.0063, 1.0047, 1.0063, 0.9984, 1.0056, 1.0014, 1.0076, 0.9963, 1.0065, 1.0041, 1.0169, 0.9952, 0.9981, 0.9914, 1.0171, 0.9926, 1.0027, 1.0031, 0.9995, 1.0044, + 961, 0.9995, 1.0025, 1.0029, 1.0043, 1.0003, 1.0022, 1.0052, 1.0049, 1.0055, 1.0016, 1.0071, 1.0009, 1.0084, 1.0100, 1.0053, 0.9960, 1.0058, 1.0026, 1.0185, 0.9952, 0.9898, 0.9847, 1.0196, 0.9924, 1.0097, 1.0117, 1.0007, 1.0042, + 962, 1.0082, 1.0105, 1.0069, 1.0087, 1.0028, 1.0044, 1.0075, 1.0066, 1.0107, 1.0065, 1.0092, 1.0006, 1.0070, 1.0069, 1.0091, 1.0016, 1.0103, 1.0076, 1.0244, 1.0021, 0.9902, 0.9849, 1.0198, 0.9926, 1.0161, 1.0178, 1.0112, 1.0142, + 963, 1.0022, 1.0045, 1.0026, 1.0038, 1.0002, 1.0039, 1.0074, 1.0069, 1.0060, 1.0035, 1.0058, 0.9968, 1.0085, 1.0037, 1.0064, 1.0008, 1.0091, 1.0079, 1.0182, 0.9950, 0.9948, 0.9867, 1.0185, 0.9944, 1.0115, 1.0148, 1.0057, 1.0098, + 964, 1.0051, 1.0077, 1.0088, 1.0114, 1.0029, 1.0047, 1.0086, 1.0082, 1.0111, 1.0050, 1.0089, 1.0029, 1.0088, 1.0114, 1.0112, 1.0055, 1.0110, 1.0080, 1.0243, 1.0060, 0.9982, 0.9888, 1.0199, 0.9950, 1.0170, 1.0219, 1.0136, 1.0105, + 965, 1.0029, 1.0054, 1.0047, 1.0077, 0.9991, 1.0029, 1.0061, 1.0055, 1.0090, 1.0040, 1.0125, 1.0054, 1.0030, 0.9995, 1.0079, 1.0028, 1.0073, 1.0044, 1.0198, 0.9993, 0.9999, 0.9909, 1.0190, 0.9966, 1.0113, 1.0134, 1.0122, 1.0088, + 966, 1.0009, 1.0037, 0.9998, 1.0032, 0.9986, 1.0007, 1.0053, 1.0047, 1.0080, 1.0059, 1.0090, 1.0029, 1.0065, 1.0070, 1.0057, 0.9998, 1.0060, 1.0042, 1.0179, 0.9962, 0.9989, 0.9912, 1.0178, 0.9917, 1.0107, 1.0147, 1.0086, 1.0052, + 967, 1.0002, 1.0034, 0.9992, 1.0020, 0.9996, 1.0009, 1.0032, 1.0029, 1.0069, 1.0035, 1.0152, 0.9966, 1.0038, 1.0047, 1.0072, 1.0030, 1.0063, 1.0056, 1.0160, 0.9939, 0.9954, 0.9882, 1.0148, 0.9895, 1.0119, 1.0127, 1.0083, 1.0110, + 968, 1.0035, 1.0065, 1.0039, 1.0050, 1.0031, 1.0045, 1.0077, 1.0065, 1.0105, 1.0061, 1.0110, 0.9997, 1.0061, 1.0071, 1.0067, 1.0006, 1.0081, 1.0094, 1.0179, 0.9960, 0.9981, 0.9890, 1.0203, 0.9971, 1.0106, 1.0134, 1.0115, 1.0107, + 969, 1.0070, 1.0111, 1.0039, 1.0062, 1.0030, 1.0040, 1.0066, 1.0057, 1.0100, 1.0053, 1.0091, 1.0029, 1.0056, 1.0087, 1.0067, 0.9968, 1.0100, 1.0127, 1.0188, 0.9981, 0.9922, 0.9874, 1.0192, 0.9956, 1.0149, 1.0210, 1.0043, 1.0048, + 970, 1.0094, 1.0122, 1.0023, 1.0048, 1.0017, 1.0048, 1.0034, 1.0023, 1.0120, 1.0089, 1.0084, 1.0001, 1.0040, 1.0061, 1.0061, 0.9961, 1.0117, 1.0094, 1.0169, 0.9947, 0.9972, 0.9889, 1.0183, 0.9936, 1.0128, 1.0154, 1.0107, 1.0141, + 971, 1.0025, 1.0055, 0.9964, 0.9993, 1.0001, 1.0014, 1.0052, 1.0031, 1.0061, 1.0015, 1.0038, 0.9944, 1.0013, 1.0005, 1.0026, 0.9940, 1.0055, 1.0028, 1.0134, 0.9918, 0.9986, 0.9901, 1.0167, 0.9922, 1.0136, 1.0169, 1.0084, 1.0096, + 972, 0.9990, 1.0013, 1.0020, 1.0029, 0.9974, 1.0009, 1.0018, 1.0004, 1.0076, 1.0012, 1.0083, 0.9965, 1.0045, 1.0046, 1.0095, 0.9990, 1.0060, 1.0050, 1.0174, 0.9944, 0.9971, 0.9911, 1.0149, 0.9900, 1.0087, 1.0131, 1.0046, 1.0099, + 973, 1.0031, 1.0061, 1.0005, 1.0013, 0.9978, 0.9998, 1.0028, 1.0009, 1.0076, 1.0056, 1.0076, 0.9995, 1.0024, 1.0002, 1.0125, 1.0033, 1.0053, 1.0025, 1.0175, 0.9980, 0.9993, 0.9911, 1.0170, 0.9921, 1.0046, 1.0059, 1.0018, 1.0072, + 974, 1.0044, 1.0068, 1.0066, 1.0095, 1.0025, 1.0043, 1.0073, 1.0071, 1.0098, 1.0049, 1.0098, 1.0017, 1.0129, 1.0142, 1.0062, 1.0056, 1.0089, 1.0049, 1.0208, 0.9981, 0.9899, 0.9847, 1.0203, 0.9947, 1.0083, 1.0090, 1.0022, 1.0027, + 975, 1.0070, 1.0103, 1.0076, 1.0085, 1.0033, 1.0044, 1.0083, 1.0073, 1.0108, 1.0069, 1.0182, 1.0074, 1.0085, 1.0069, 1.0095, 1.0006, 1.0119, 1.0086, 1.0244, 1.0033, 0.9922, 0.9857, 1.0184, 0.9914, 1.0155, 1.0180, 1.0124, 1.0134, + 976, 1.0048, 1.0094, 1.0022, 1.0041, 1.0035, 1.0042, 1.0080, 1.0070, 1.0111, 1.0052, 1.0128, 1.0005, 1.0057, 1.0052, 1.0082, 0.9958, 1.0101, 1.0127, 1.0190, 0.9966, 0.9973, 0.9884, 1.0216, 0.9956, 1.0174, 1.0230, 1.0087, 1.0132, + 977, 1.0075, 1.0117, 1.0062, 1.0067, 1.0016, 1.0031, 1.0075, 1.0075, 1.0121, 1.0076, 1.0069, 0.9993, 1.0109, 1.0126, 1.0105, 1.0000, 1.0115, 1.0171, 1.0237, 1.0031, 0.9975, 0.9902, 1.0221, 0.9959, 1.0153, 1.0214, 1.0102, 1.0117, + 978, 1.0062, 1.0096, 1.0072, 1.0062, 1.0030, 1.0038, 1.0072, 1.0052, 1.0123, 1.0072, 1.0103, 1.0025, 1.0073, 1.0049, 1.0083, 1.0121, 1.0104, 1.0075, 1.0209, 0.9966, 1.0011, 0.9929, 1.0231, 0.9988, 1.0126, 1.0145, 1.0071, 1.0125, + 979, 0.9969, 1.0007, 1.0007, 1.0031, 0.9960, 1.0034, 1.0049, 1.0042, 1.0048, 0.9996, 1.0053, 0.9973, 1.0066, 1.0034, 1.0095, 1.0025, 1.0040, 1.0010, 1.0183, 0.9952, 0.9994, 0.9919, 1.0158, 0.9917, 1.0089, 1.0122, 1.0064, 1.0088, + 980, 1.0009, 1.0051, 1.0029, 1.0026, 0.9994, 1.0022, 1.0046, 1.0047, 1.0101, 1.0026, 1.0104, 1.0039, 1.0050, 1.0058, 1.0098, 1.0032, 1.0067, 1.0034, 1.0198, 0.9973, 1.0021, 0.9933, 1.0168, 0.9921, 1.0132, 1.0184, 1.0139, 1.0148, + 981, 1.0059, 1.0088, 1.0053, 1.0058, 1.0032, 1.0022, 1.0077, 1.0071, 1.0100, 1.0049, 1.0090, 1.0019, 1.0048, 1.0041, 1.0115, 1.0006, 1.0087, 1.0070, 1.0186, 0.9956, 0.9940, 0.9874, 1.0181, 0.9951, 1.0108, 1.0147, 1.0071, 1.0112, + 982, 1.0062, 1.0129, 1.0043, 1.0068, 1.0046, 1.0051, 1.0097, 1.0102, 1.0114, 1.0070, 1.0083, 1.0015, 1.0107, 1.0120, 1.0107, 1.0001, 1.0110, 1.0086, 1.0209, 0.9987, 0.9925, 0.9868, 1.0202, 0.9954, 1.0138, 1.0196, 1.0092, 1.0071, + 983, 1.0049, 1.0107, 1.0031, 1.0036, 1.0005, 1.0020, 1.0059, 1.0069, 1.0115, 1.0091, 1.0073, 1.0013, 1.0034, 1.0049, 1.0070, 0.9955, 1.0070, 1.0056, 1.0188, 0.9967, 0.9988, 0.9917, 1.0150, 0.9887, 1.0147, 1.0193, 1.0143, 1.0156, + 984, 1.0020, 1.0069, 1.0009, 1.0021, 0.9987, 1.0008, 1.0055, 1.0042, 1.0090, 1.0019, 1.0072, 0.9988, 1.0050, 1.0021, 1.0087, 0.9953, 1.0088, 1.0055, 1.0174, 0.9947, 0.9966, 0.9889, 1.0159, 0.9900, 1.0147, 1.0205, 1.0147, 1.0122, + 985, 0.9988, 1.0036, 0.9983, 0.9986, 0.9968, 0.9998, 1.0042, 1.0032, 1.0076, 1.0029, 1.0109, 0.9991, 1.0047, 1.0114, 1.0152, 1.0100, 1.0044, 1.0025, 1.0179, 0.9946, 0.9961, 0.9891, 1.0112, 0.9867, 1.0084, 1.0126, 1.0083, 1.0119, + 986, 1.0029, 1.0096, 1.0037, 1.0065, 0.9990, 1.0014, 1.0043, 1.0049, 1.0089, 1.0076, 1.0104, 1.0018, 1.0044, 1.0077, 1.0111, 1.0118, 1.0064, 1.0058, 1.0213, 0.9995, 0.9958, 0.9890, 1.0160, 0.9938, 1.0044, 1.0053, 1.0061, 1.0103, + 987, 0.9993, 1.0047, 1.0050, 1.0053, 0.9999, 1.0036, 1.0052, 1.0052, 1.0085, 1.0039, 1.0076, 0.9991, 1.0109, 1.0108, 1.0063, 1.0019, 1.0056, 1.0019, 1.0197, 0.9968, 0.9873, 0.9821, 1.0145, 0.9918, 1.0097, 1.0126, 1.0068, 1.0031, + 988, 1.0104, 1.0169, 1.0101, 1.0091, 1.0073, 1.0051, 1.0108, 1.0097, 1.0162, 1.0108, 1.0144, 1.0086, 1.0139, 1.0124, 1.0111, 1.0054, 1.0154, 1.0139, 1.0287, 1.0057, 0.9937, 0.9876, 1.0167, 0.9916, 1.0198, 1.0246, 1.0237, 1.0178, + 989, 1.0039, 1.0080, 1.0038, 1.0027, 1.0004, 1.0042, 1.0095, 1.0081, 1.0111, 1.0041, 1.0105, 1.0023, 1.0128, 1.0062, 1.0087, 1.0025, 1.0129, 1.0098, 1.0207, 0.9958, 0.9941, 0.9865, 1.0163, 0.9921, 1.0159, 1.0193, 1.0125, 1.0128, + 990, 1.0088, 1.0149, 1.0056, 1.0055, 1.0036, 1.0041, 1.0073, 1.0071, 1.0131, 1.0074, 1.0165, 1.0004, 1.0102, 1.0142, 1.0070, 1.0032, 1.0130, 1.0112, 1.0231, 1.0009, 1.0005, 0.9921, 1.0167, 0.9928, 1.0166, 1.0224, 1.0235, 1.0155, + 991, 1.0046, 1.0119, 1.0065, 1.0056, 0.9995, 1.0028, 1.0065, 1.0051, 1.0117, 1.0070, 1.0089, 1.0006, 1.0102, 1.0055, 1.0100, 1.0031, 1.0082, 1.0074, 1.0202, 0.9966, 0.9983, 0.9903, 1.0166, 0.9943, 1.0117, 1.0134, 1.0223, 1.0159, + 992, 1.0018, 1.0081, 1.0076, 1.0080, 0.9998, 1.0015, 1.0096, 1.0086, 1.0094, 1.0023, 1.0104, 1.0004, 1.0139, 1.0073, 1.0107, 1.0000, 1.0075, 1.0096, 1.0219, 0.9985, 0.9977, 0.9895, 1.0178, 0.9933, 1.0135, 1.0193, 1.0173, 1.0127, + 993, 1.0064, 1.0115, 1.0048, 1.0053, 1.0012, 1.0037, 1.0090, 1.0076, 1.0116, 1.0057, 1.0119, 1.0052, 1.0083, 1.0096, 1.0140, 1.0030, 1.0108, 1.0088, 1.0226, 0.9995, 0.9962, 0.9893, 1.0152, 0.9932, 1.0153, 1.0189, 1.0191, 1.0161, + 994, 1.0085, 1.0153, 1.0096, 1.0094, 1.0035, 1.0065, 1.0105, 1.0108, 1.0133, 1.0079, 1.0133, 1.0057, 1.0115, 1.0096, 1.0113, 1.0025, 1.0129, 1.0122, 1.0232, 0.9987, 0.9945, 0.9872, 1.0153, 0.9919, 1.0118, 1.0141, 1.0176, 1.0142, + 995, 1.0040, 1.0102, 1.0051, 1.0050, 1.0022, 1.0038, 1.0089, 1.0085, 1.0120, 1.0063, 1.0167, 1.0062, 1.0126, 1.0121, 1.0087, 1.0076, 1.0089, 1.0080, 1.0212, 0.9985, 0.9898, 0.9852, 1.0164, 0.9921, 1.0122, 1.0182, 1.0105, 1.0090, + 996, 1.0112, 1.0197, 1.0107, 1.0093, 1.0049, 1.0062, 1.0100, 1.0088, 1.0153, 1.0113, 1.0138, 1.0012, 1.0080, 1.0073, 1.0137, 1.0023, 1.0133, 1.0115, 1.0238, 1.0008, 0.9997, 0.9917, 1.0168, 0.9924, 1.0173, 1.0230, 1.0206, 1.0194, + 997, 1.0078, 1.0132, 1.0035, 1.0045, 1.0011, 1.0033, 1.0095, 1.0093, 1.0138, 1.0069, 1.0081, 1.0000, 1.0083, 1.0048, 1.0087, 0.9998, 1.0109, 1.0099, 1.0211, 0.9950, 0.9966, 0.9865, 1.0162, 0.9927, 1.0171, 1.0208, 1.0226, 1.0147, + 998, 1.0024, 1.0080, 1.0052, 1.0058, 0.9999, 1.0009, 1.0063, 1.0044, 1.0109, 1.0045, 1.0148, 1.0034, 1.0095, 1.0085, 1.0100, 1.0063, 1.0077, 1.0059, 1.0208, 0.9979, 0.9969, 0.9893, 1.0123, 0.9877, 1.0089, 1.0141, 1.0165, 1.0156, + 999, 1.0013, 1.0068, 1.0046, 1.0036, 0.9972, 0.9991, 1.0061, 1.0028, 1.0090, 1.0035, 1.0197, 1.0051, 1.0029, 1.0014, 1.0103, 0.9960, 1.0074, 1.0054, 1.0225, 0.9979, 0.9957, 0.9871, 1.0141, 0.9905, 1.0043, 1.0046, 1.0090, 1.0104, + 1000, 1.0036, 1.0092, 1.0059, 1.0046, 1.0039, 1.0046, 1.0070, 1.0050, 1.0113, 1.0056, 1.0141, 1.0023, 1.0168, 1.0144, 1.0095, 1.0039, 1.0114, 1.0089, 1.0235, 0.9991, 0.9890, 0.9822, 1.0172, 0.9912, 1.0128, 1.0185, 1.0105, 1.0095, + 1001, 1.0089, 1.0143, 1.0108, 1.0096, 1.0048, 1.0058, 1.0129, 1.0094, 1.0144, 1.0072, 1.0115, 1.0010, 1.0133, 1.0121, 1.0141, 1.0113, 1.0145, 1.0137, 1.0305, 1.0067, 0.9911, 0.9853, 1.0203, 0.9958, 1.0198, 1.0240, 1.0238, 1.0204, + 1002, 1.0022, 1.0086, 1.0078, 1.0085, 1.0024, 1.0024, 1.0108, 1.0103, 1.0101, 1.0059, 1.0136, 1.0063, 1.0101, 1.0081, 1.0119, 1.0084, 1.0118, 1.0101, 1.0254, 0.9999, 0.9950, 0.9867, 1.0194, 0.9966, 1.0171, 1.0190, 1.0208, 1.0178, + 1003, 1.0059, 1.0102, 1.0075, 1.0067, 0.9997, 1.0022, 1.0077, 1.0065, 1.0094, 1.0037, 1.0169, 1.0065, 1.0105, 1.0111, 1.0082, 1.0060, 1.0094, 1.0061, 1.0236, 1.0013, 0.9986, 0.9894, 1.0196, 0.9922, 1.0153, 1.0212, 1.0233, 1.0173, + 1004, 1.0071, 1.0123, 1.0074, 1.0070, 1.0046, 1.0052, 1.0087, 1.0054, 1.0135, 1.0066, 1.0123, 1.0031, 1.0081, 1.0078, 1.0101, 1.0054, 1.0130, 1.0110, 1.0244, 0.9981, 0.9995, 0.9889, 1.0190, 0.9952, 1.0141, 1.0171, 1.0233, 1.0208, + 1005, 1.0073, 1.0095, 1.0053, 1.0012, 1.0033, 1.0027, 1.0116, 1.0073, 1.0129, 1.0057, 1.0118, 1.0010, 1.0107, 1.0098, 1.0105, 0.9980, 1.0121, 1.0083, 1.0233, 0.9959, 0.9963, 0.9867, 1.0189, 0.9920, 1.0187, 1.0206, 1.0222, 1.0168, + 1006, 1.0073, 1.0133, 1.0033, 1.0044, 1.0050, 1.0065, 1.0099, 1.0067, 1.0137, 1.0080, 1.0109, 1.0025, 1.0101, 1.0118, 1.0096, 1.0032, 1.0123, 1.0133, 1.0235, 1.0005, 0.9938, 0.9875, 1.0139, 0.9909, 1.0189, 1.0245, 1.0186, 1.0196, + 1007, 1.0074, 1.0115, 1.0058, 1.0048, 1.0041, 1.0055, 1.0114, 1.0067, 1.0107, 1.0072, 1.0125, 1.0043, 1.0069, 1.0077, 1.0090, 1.0011, 1.0118, 1.0123, 1.0223, 0.9965, 0.9964, 0.9886, 1.0146, 0.9921, 1.0131, 1.0156, 1.0165, 1.0167, + 1008, 1.0091, 1.0139, 1.0092, 1.0093, 1.0066, 1.0074, 1.0124, 1.0111, 1.0150, 1.0080, 1.0160, 1.0037, 1.0130, 1.0149, 1.0092, 1.0125, 1.0125, 1.0145, 1.0266, 1.0027, 0.9947, 0.9887, 1.0179, 0.9947, 1.0160, 1.0218, 1.0162, 1.0154, + 1009, 1.0117, 1.0164, 1.0103, 1.0099, 1.0051, 1.0056, 1.0124, 1.0086, 1.0152, 1.0109, 1.0117, 1.0016, 1.0091, 1.0076, 1.0110, 1.0046, 1.0136, 1.0153, 1.0259, 1.0001, 0.9985, 0.9895, 1.0140, 0.9945, 1.0178, 1.0227, 1.0196, 1.0232, + 1010, 1.0077, 1.0136, 1.0062, 1.0056, 1.0039, 1.0048, 1.0123, 1.0104, 1.0122, 1.0068, 1.0189, 1.0024, 1.0074, 1.0067, 1.0100, 1.0006, 1.0118, 1.0121, 1.0227, 0.9982, 0.9999, 0.9894, 1.0132, 0.9909, 1.0188, 1.0246, 1.0188, 1.0184, + 1011, 0.9989, 1.0023, 0.9986, 0.9992, 0.9973, 0.9980, 1.0061, 1.0012, 1.0082, 1.0026, 1.0169, 1.0039, 1.0060, 1.0054, 1.0085, 1.0014, 1.0080, 1.0068, 1.0198, 0.9923, 0.9941, 0.9872, 1.0070, 0.9838, 1.0080, 1.0091, 1.0139, 1.0175, + 1012, 1.0039, 1.0086, 1.0051, 1.0038, 0.9983, 1.0014, 1.0083, 1.0027, 1.0107, 1.0033, 1.0112, 1.0013, 1.0053, 1.0043, 1.0101, 0.9984, 1.0095, 1.0089, 1.0273, 0.9979, 0.9992, 0.9890, 1.0126, 0.9906, 1.0107, 1.0114, 1.0123, 1.0126, + 1013, 1.0038, 1.0090, 1.0062, 1.0070, 1.0034, 1.0067, 1.0116, 1.0087, 1.0106, 1.0068, 1.0100, 1.0021, 1.0171, 1.0158, 1.0086, 0.9973, 1.0117, 1.0152, 1.0250, 1.0010, 0.9956, 0.9889, 1.0140, 0.9935, 1.0148, 1.0224, 1.0153, 1.0156, + 1014, 1.0125, 1.0159, 1.0126, 1.0101, 1.0073, 1.0060, 1.0165, 1.0101, 1.0164, 1.0098, 1.0151, 1.0030, 1.0148, 1.0136, 1.0133, 1.0036, 1.0184, 1.0156, 1.0312, 1.0024, 0.9939, 0.9864, 1.0160, 0.9919, 1.0213, 1.0233, 1.0366, 1.0267, + 1015, 1.0046, 1.0060, 1.0080, 1.0068, 1.0036, 1.0041, 1.0151, 1.0089, 1.0116, 1.0056, 1.0107, 1.0020, 1.0080, 1.0065, 1.0099, 0.9969, 1.0131, 1.0122, 1.0250, 0.9977, 0.9953, 0.9851, 1.0148, 0.9909, 1.0189, 1.0233, 1.0266, 1.0200, + 1016, 1.0109, 1.0152, 1.0110, 1.0100, 1.0048, 1.0045, 1.0123, 1.0062, 1.0144, 1.0087, 1.0138, 1.0059, 1.0121, 1.0155, 1.0118, 1.0009, 1.0156, 1.0137, 1.0315, 1.0089, 0.9990, 0.9903, 1.0179, 0.9925, 1.0231, 1.0302, 1.0251, 1.0251, + 1017, 1.0124, 1.0144, 1.0104, 1.0082, 1.0049, 1.0048, 1.0131, 1.0076, 1.0168, 1.0096, 1.0160, 1.0027, 1.0098, 1.0108, 1.0129, 1.0007, 1.0143, 1.0173, 1.0305, 1.0058, 1.0046, 0.9923, 1.0192, 0.9967, 1.0147, 1.0161, 1.0268, 1.0245, + 1018, 1.0063, 1.0086, 1.0070, 1.0067, 1.0021, 1.0027, 1.0144, 1.0095, 1.0103, 1.0045, 1.0144, 1.0017, 1.0112, 1.0111, 1.0107, 0.9972, 1.0107, 1.0117, 1.0284, 1.0012, 0.9969, 0.9887, 1.0176, 0.9949, 1.0162, 1.0203, 1.0224, 1.0230, + 1019, 1.0031, 1.0051, 1.0041, 1.0037, 1.0019, 1.0015, 1.0112, 1.0067, 1.0119, 1.0039, 1.0152, 1.0076, 1.0075, 1.0081, 1.0113, 0.9968, 1.0092, 1.0055, 1.0272, 0.9986, 0.9967, 0.9878, 1.0131, 0.9906, 1.0202, 1.0236, 1.0265, 1.0250, + 1020, 1.0092, 1.0127, 1.0126, 1.0136, 1.0053, 1.0047, 1.0169, 1.0115, 1.0138, 1.0067, 1.0154, 1.0076, 1.0101, 1.0099, 1.0129, 1.0025, 1.0145, 1.0136, 1.0291, 0.9992, 0.9933, 0.9862, 1.0142, 0.9934, 1.0189, 1.0227, 1.0301, 1.0222, + 1021, 1.0104, 1.0150, 1.0096, 1.0081, 1.0079, 1.0061, 1.0165, 1.0099, 1.0160, 1.0103, 1.0170, 1.0064, 1.0203, 1.0149, 1.0099, 1.0033, 1.0146, 1.0156, 1.0290, 1.0010, 0.9918, 0.9847, 1.0175, 0.9944, 1.0186, 1.0232, 1.0184, 1.0193, + 1022, 1.0115, 1.0138, 1.0106, 1.0094, 1.0035, 1.0043, 1.0131, 1.0079, 1.0141, 1.0079, 1.0196, 1.0053, 1.0071, 1.0088, 1.0108, 1.0012, 1.0148, 1.0183, 1.0304, 1.0000, 0.9980, 0.9867, 1.0139, 0.9940, 1.0220, 1.0294, 1.0237, 1.0263, + 1023, 1.0037, 1.0075, 1.0040, 1.0046, 1.0014, 1.0027, 1.0137, 1.0089, 1.0108, 1.0038, 1.0232, 1.0002, 1.0041, 1.0046, 1.0092, 0.9991, 1.0108, 1.0083, 1.0271, 0.9982, 0.9958, 0.9852, 1.0130, 0.9904, 1.0222, 1.0276, 1.0207, 1.0227, + 1024, 1.0032, 1.0066, 1.0058, 1.0042, 1.0013, 1.0016, 1.0125, 1.0062, 1.0106, 1.0069, 1.0146, 1.0036, 1.0084, 1.0114, 1.0130, 1.0002, 1.0100, 1.0124, 1.0268, 0.9969, 0.9946, 0.9878, 1.0095, 0.9882, 1.0155, 1.0233, 1.0211, 1.0247, + 1025, 1.0062, 1.0088, 1.0101, 1.0094, 1.0008, 1.0020, 1.0134, 1.0080, 1.0116, 1.0082, 1.0140, 1.0022, 1.0072, 1.0057, 1.0146, 1.0013, 1.0105, 1.0096, 1.0299, 1.0007, 1.0005, 0.9891, 1.0147, 0.9942, 1.0146, 1.0170, 1.0222, 1.0221, + 1026, 1.0068, 1.0105, 1.0095, 1.0089, 1.0037, 1.0052, 1.0138, 1.0068, 1.0115, 1.0052, 1.0170, 1.0099, 1.0148, 1.0149, 1.0091, 0.9966, 1.0107, 1.0081, 1.0299, 0.9989, 0.9929, 0.9859, 1.0164, 0.9938, 1.0210, 1.0257, 1.0174, 1.0186, + 1027, 1.0102, 1.0139, 1.0114, 1.0103, 1.0047, 1.0043, 1.0145, 1.0074, 1.0165, 1.0084, 1.0170, 1.0068, 1.0165, 1.0115, 1.0123, 1.0001, 1.0149, 1.0148, 1.0342, 1.0053, 0.9903, 0.9835, 1.0152, 0.9920, 1.0229, 1.0294, 1.0270, 1.0283, + 1028, 1.0108, 1.0159, 1.0126, 1.0100, 1.0081, 1.0092, 1.0167, 1.0109, 1.0170, 1.0129, 1.0135, 1.0033, 1.0149, 1.0137, 1.0124, 1.0008, 1.0193, 1.0191, 1.0308, 1.0018, 0.9934, 0.9846, 1.0156, 0.9962, 1.0272, 1.0347, 1.0221, 1.0270, + 1029, 1.0104, 1.0142, 1.0129, 1.0101, 1.0047, 1.0054, 1.0155, 1.0086, 1.0155, 1.0090, 1.0180, 1.0051, 1.0177, 1.0161, 1.0108, 1.0016, 1.0154, 1.0142, 1.0348, 1.0029, 0.9971, 0.9894, 1.0166, 0.9939, 1.0261, 1.0324, 1.0297, 1.0293, + 1030, 1.0095, 1.0120, 1.0113, 1.0103, 1.0040, 1.0044, 1.0151, 1.0078, 1.0153, 1.0080, 1.0350, 1.0079, 1.0088, 1.0103, 1.0138, 1.0034, 1.0153, 1.0141, 1.0329, 1.0013, 1.0031, 0.9920, 1.0149, 0.9964, 1.0222, 1.0259, 1.0248, 1.0253, + 1031, 1.0034, 1.0057, 1.0074, 1.0056, 0.9987, 1.0008, 1.0139, 1.0052, 1.0104, 1.0015, 1.0209, 1.0052, 1.0087, 1.0087, 1.0085, 0.9931, 1.0094, 1.0078, 1.0289, 0.9962, 0.9980, 0.9870, 1.0134, 0.9908, 1.0224, 1.0268, 1.0267, 1.0257, + 1032, 1.0104, 1.0117, 1.0102, 1.0073, 1.0045, 1.0043, 1.0156, 1.0062, 1.0152, 1.0091, 1.0195, 1.0018, 1.0116, 1.0111, 1.0122, 1.0002, 1.0142, 1.0089, 1.0308, 0.9992, 0.9964, 0.9859, 1.0138, 0.9906, 1.0257, 1.0306, 1.0279, 1.0280, + 1033, 1.0120, 1.0142, 1.0131, 1.0113, 1.0069, 1.0058, 1.0165, 1.0104, 1.0144, 1.0083, 1.0142, 1.0032, 1.0153, 1.0130, 1.0129, 1.0011, 1.0169, 1.0169, 1.0324, 0.9982, 0.9977, 0.9889, 1.0175, 0.9977, 1.0269, 1.0320, 1.0278, 1.0288, + 1034, 1.0113, 1.0150, 1.0101, 1.0093, 1.0068, 1.0066, 1.0169, 1.0106, 1.0153, 1.0092, 1.0236, 1.0080, 1.0164, 1.0192, 1.0124, 0.9993, 1.0147, 1.0156, 1.0317, 1.0000, 0.9982, 0.9902, 1.0186, 0.9959, 1.0302, 1.0388, 1.0305, 1.0249, + 1035, 1.0129, 1.0141, 1.0140, 1.0168, 1.0051, 1.0026, 1.0147, 1.0081, 1.0169, 1.0085, 1.0211, 1.0072, 1.0122, 1.0193, 1.0115, 1.0004, 1.0148, 1.0139, 1.0310, 0.9995, 1.0048, 0.9971, 1.0199, 0.9984, 1.0431, 1.0370, 1.0312, 1.0370, + 1036, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1037, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1038, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1039, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1040, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1041, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1042, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1043, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1044, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1045, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1046, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1047, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1048, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1049, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1050, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, + 1051, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, diff --git a/isis/src/base/objs/CSVReader/spaces.csv b/isis/src/base/objs/CSVReader/spaces.csv new file mode 100644 index 0000000000000000000000000000000000000000..9b15274a8badff06574072213c82b3ebd8dbea1e --- /dev/null +++ b/isis/src/base/objs/CSVReader/spaces.csv @@ -0,0 +1,254 @@ +Input Cube: /usgs/cpkgs/isis3.0.0/data/base/testData/isisTruth.cub +Samples:Lines:Bands: 126:126:2 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 39 + 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 59 + 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 79 + 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 + 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 + 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 + 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 158 + 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 177 + 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 197 + 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 217 + 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 236 + 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 + -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 -1e+20 + -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 -8.4615e+19 + -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 -6.9231e+19 + -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 -5.3846e+19 + -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 -3.8462e+19 + -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 -2.3077e+19 + -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 -7.6923e+18 + 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 7.6923e+18 + 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 2.3077e+19 + 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 3.8462e+19 + 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 5.3846e+19 + 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 6.9231e+19 + 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 8.4615e+19 + 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 1e+20 + -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 -1e-20 + -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 -8.4615e-21 + -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 -6.9231e-21 + -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 -5.3846e-21 + -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 -3.8462e-21 + -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 -2.3077e-21 + -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 -7.6923e-22 + 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 7.6923e-22 + 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 2.3077e-21 + 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 3.8462e-21 + 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 5.3846e-21 + 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 6.9231e-21 + 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 8.4615e-21 + 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 1e-20 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS + 0 20 39 59 79 98 118 138 158 177 197 217 236 256 -1e+20 -8.4615e+19 -6.9231e+19 -5.3846e+19 -3.8462e+19 -2.3077e+19 -7.6923e+18 7.6923e+18 2.3077e+19 3.8462e+19 5.3846e+19 6.9231e+19 8.4615e+19 1e+20 -1e-20 -8.4615e-21 -6.9231e-21 -5.3846e-21 -3.8462e-21 -2.3077e-21 -7.6923e-22 7.6923e-22 2.3077e-21 3.8462e-21 5.3846e-21 6.9231e-21 8.4615e-21 1e-20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS LRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS HRS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS LIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS HIS diff --git a/isis/src/base/objs/CSVReader/unitTest.cpp b/isis/src/base/objs/CSVReader/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e606d789ff52997935398e5f05868920ec37e44 --- /dev/null +++ b/isis/src/base/objs/CSVReader/unitTest.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include "CSVReader.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +CSVReader::CSVTable summarize(const CSVReader &csv) { + cout << "Number of lines read: " << csv.size() << endl; + cout << "Number of table rows: " << csv.rows() << endl; + cout << "Number lines skipped: " << csv.getSkip() << endl; + cout << "Got a header: " << csv.haveHeader() << endl; + + CSVReader::CSVAxis header = csv.getHeader(); + cout << "Size of header: " << header.dim() << endl; + if (header.dim() > 0) { + cout << " First header value: " << header[0] << endl; + } + + CSVReader::CSVTable table = csv.getTable(); + CSVReader::CSVColumnSummary summary = csv.getColumnSummary(table); + cout << "Number of columns: " << csv.columns(table) << endl; + cout << "Number distinct columns: " << summary.size() << endl; + for (int ncols = 0 ; ncols < summary.size() ; ncols++) { + cout << "--> " << summary.getNth(ncols) << " rows have " + << summary.key(ncols) << " columns." << endl; + } + + cout << "Table integrity OK: " << csv.isTableValid(table) << endl; + return (table); +} + +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + try { + cout << "\n\nProcessing comma table...\n"; + std::string csvfile("comma.csv"); + CSVReader csv(csvfile,true,2); + CSVReader::CSVTable table = summarize(csv); + + // Convert column 0/1 to double + CSVReader::CSVAxis scol = csv.getColumn("0/1"); + CSVReader::CSVDblVector dcol = csv.convert(scol); + cout.setf(ios::fixed); + cout << "Size of column 0/1: " << scol.dim() << endl; + for (int i = 0 ; i < dcol.dim() ; i++ ) { + cout << "iString: " << setw(10) << scol[i] + << " \tDouble: " << setprecision(4) << dcol[i] << endl; + } + + cout << "\n\nProcessing spaces table...\n"; + csv.setSkipEmptyParts(); + csv.setHeader(false); + csv.setDelimiter(' '); + csv.setSkip(2); + csv.read("spaces.csv"); + table = summarize(csv); + + + cout << "\n\nCheck empty table conditions...\n"; + csv.clear(); + summarize(csv); + + // Lets test the stream read operation + cout << "\n\nProcessing spaces table using streams...\n"; + ifstream isCsv("spaces.csv"); + isCsv >> csv; + table = summarize(csv); + isCsv.close(); + + } + catch (iException &ie) { + ie.Report(); + } + + return (0); +} diff --git a/isis/src/base/objs/Calculator/Calculator.cpp b/isis/src/base/objs/Calculator/Calculator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8506cf0e7269bfd43b9e3fafbbd254a90475e39a --- /dev/null +++ b/isis/src/base/objs/Calculator/Calculator.cpp @@ -0,0 +1,1040 @@ +/** + * @file + * $Revision: 1.14 $ + * $Date: 2010/04/08 15:05:24 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#include +#include + +#include "ProcessByLine.h" +#include "Calculator.h" +#include "InfixToPostfix.h" +#include "iException.h" +#include "SpecialPixel.h" + +using namespace std; + +namespace Isis { + /** + * The code that performs math operations is designed + * to call a function and use the result. These helper + * methods convert standard operators into functions which + * perform the desired operations. See the implementation of + * Calculator::Negative for an example. + */ + + /** + * Returns the nagative of the input parameter. + * + * @param a Input double + * + * @return double negative of a + */ + double NegateOperator(double a) { return -1*a; } + + + /** + * Returns the result of a multiplied by b. + * + * @param a Input double + * @param b Input double + * + * @return double result of a*b + */ + double MultiplyOperator(double a, double b) { return a*b; } + + + /** + * Returns the result of dividing a by b + * + * @param a Input double + * @param b Intput double + * + * @return double result of a/b + */ + double DivideOperator(double a, double b) { return a/b; } + + + /** + * Returns the result of additing a with b. + * + * @param a Input double + * @param b Input double + * + * @return double result of a+b + */ + double AddOperator(double a, double b) { return a+b; } + + + /** + * Returns the result of subtracting b from a. + * + * @param a Input subtractee + * @param b Input subtractor + * + * @return double result of a-b + */ + double SubtractOperator(double a, double b) { return a-b; } + + + /** + * Returns 1.0 if a is greater than b. Otherwise 0.0 is returned. + * + * @param a Input double + * @param b Input double + * + * @return 1.0 if a>b + */ + double GreaterThanOperator(double a, double b) { return a > b ? 1.0 : 0.0; } + + + /** + * Returns 1.0 if a is less than b. Otherwise 0.0 is returned. + * + * @param a Input double + * @param b Input double + * + * @return 1.0 if a=b + */ + double GreaterThanOrEqualOperator(double a, double b) { return a >= b ? 1.0 : 0.0; } + + + /** + * Returns 1.0 if a is less than or eqaul to b. Otherwise 0.0 is returned. + * + * @param a Input double + * @param b Input double + * + * @return 1.0 if a<=b + */ + double LessThanOrEqualOperator(double a, double b) { return a <= b ? 1.0 : 0.0; } + + + /** + * Returns 1.0 is a is not equal to b. Otherwise 0.0 is returned. + * + * @param a Input double + * @param b Input double + * + * @return 1.0 if a!=b + */ + double NotEqualOperator(double a, double b) { return a != b ? 1.0 : 0.0; } + + + /** + * Returns the cosecant of the input a + * + * @param a Input double + * + * @return the double result of the cosecant of a + */ + double CosecantOperator(double a) { return 1.0 / sin(a); } + + + /** + * Returns the secant of the input a + * + * @param a Input double + * + * @return the double result of the secant of a + */ + double SecantOperator(double a) { return 1.0 / cos(a); } + + /** + * Returns the cotangent of the input a + * + * @param a Input double + * + * @return the double result of the cotangent of a + */ + double CotangentOperator(double a) { return 1.0 / tan(a); } + + + /** + * Returns the result of rounding the input a to the closest integer. + * + * @param a Inut double + * + * @return the int result of rounding a to the closest whole number + */ + int Round(double a) { return (a>0)? (int)(a+0.5) : (int)(a-0.5); } + + + /** + * Returns the result of a bitwise AND accross a and b + * + * @param a Input double + * @param b Input double + * + * @return the double result of a bitwise AND operation + */ + double BitwiseAndOperator(double a, double b) { return (double)(Round(a)&Round(b)); } + + + /** + * Returns the result of a bitwise OR across a and b + * + * @param a Input double + * @param b INput double + * + * @return the double result of a bitwise OR operation + */ + double BitwiseOrOperator(double a, double b) { return (double)(Round(a)|Round(b)); } + + + /** + * Returns the modulus of a by b + * + * @param a Input modulee + * @param b Input modulator + * + * @return double result of a%b + */ + double ModulusOperator(double a, double b) { return (double)(Round(a)%Round(b)); } + + /** + * Returns the max of a and b + * + * @param a First input value + * @param b Second input value + * + * @return The larger of the two + */ + double MaximumOperator(double a, double b) { return (a > b)? a : b; } + + /** + * Returns the min of a and b + * + * @param a First input value + * @param b Second input value + * + * @return The smaller of the two + */ + double MinimumOperator(double a, double b) { return (a < b)? a : b; } + + + //! Constructor + Calculator::Calculator() { + p_valStack = NULL; + + p_valStack = new QStack< QVector >(); + } + + //! Constructor + Calculator::~Calculator() { + if(p_valStack) { + delete p_valStack; + p_valStack = NULL; + } + } + + + /** + * Pops an element, negates it, then pushes the result + */ + void Calculator::Negative() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), NegateOperator); + Push(result); + } + + + /** + * Pops two elements, multiplies them, then pushes the product on the stack + */ + void Calculator::Multiply() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), MultiplyOperator); + Push(result); + } + + + /** + * Pops two elements, adds them, then pushes the sum on the stack + */ + void Calculator::Add() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), AddOperator); + Push(result); + } + + + /** + * Pops two elements, subtracts them, then pushes the difference on the stack + */ + void Calculator::Subtract() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), SubtractOperator); + Push(result); + } + + + /** + * Pops two, divides them, then pushes the quotient on the stack + */ + void Calculator::Divide() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), DivideOperator); + Push(result); + } + + /** + * Pops two elements, mods them, then pushes the result on the stack + */ + void Calculator::Modulus() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), ModulusOperator); + Push(result); + } + + + /** + * Pops two elements, computes the power then pushes the result on the stack + * The exponent has to be a scalar. + * + * @throws Isis::iException::Math + */ + void Calculator::Exponent() { + QVector exponent = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), exponent.begin(), exponent.end(), pow); + Push(result); + } + + + /** + * Pop an element, compute its square root, then push the root on the stack + * + * @throws Isis::iException::Math + */ + void Calculator::SquareRoot() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), sqrt); + Push(result); + } + + + /** + * Pop an element, compute its absolute value, then push the result on the stack + */ + void Calculator::AbsoluteValue() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), fabs); + Push(result); + } + + + /** + * Pop an element, compute its log, then push the result on the stack + * + * @throws Isis::iException::Math + */ + void Calculator::Log() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), log); + Push(result); + } + + + /** + * Pop an element, compute its base 10 log, then push the result on the stack + */ + void Calculator::Log10() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), log10); + Push(result); + } + + + /** + * Pop the top element, then perform a left shift with zero fill + * + * @throws Isis::iException::Math + */ + void Calculator::LeftShift() { + QVector y = Pop(); + if(y.size() != 1) { + std::string msg = "Must use scalars for shifting."; + throw Isis::iException::Message(Isis::iException::Math, msg, _FILEINFO_); + } + else { + QVector x = Pop(); + + if((int)y[0] > (int)x.size()) { + std::string msg = "Shift value must be <= to number of samples."; + throw Isis::iException::Message(Isis::iException::Math, msg, _FILEINFO_); + } + else { + QVector result; + int shift = (int)y[0]; + result.resize(x.size()); + + for(int i = 0; i < result.size(); i++) { + if(i+shift < x.size() && i+shift >= 0) + result[i] = x[i+shift]; + else + result[i] = sqrt(-1.0); // create a NaN + } + + Push(result); + } + } + } + + + /** + * Pop the top element, then perform a right shift with zero fill + * + * @throws Isis::iException::Math + */ + void Calculator::RightShift() { + QVector y = Pop(); + if(y.size() != 1) { + std::string msg = "Must use scalars for shifting."; + throw Isis::iException::Message(Isis::iException::Math, msg, _FILEINFO_); + } + else { + QVector x = Pop(); + + if((int)y[0] > (int)x.size()) { + std::string msg = "Shift value must be <= to number of samples."; + throw Isis::iException::Message(Isis::iException::Math, msg, _FILEINFO_); + } + else { + QVector result; + int shift = (int)y[0]; + result.resize(x.size()); + + for(int i = 0; i < (int)result.size(); i++) { + if(i-shift < (int)x.size() && i-shift >= 0) { + result[i] = x[i-shift]; + } + else { + result[i] = sqrt(-1.0); // create a NaN + } + } + + Push(result); + } + } + } + + /** + * Pop one element, then push the minimum on the stack + */ + void Calculator::MinimumLine() { + QVector result = Pop(); + + double minVal = result[0]; + for(int i = 0; i < result.size(); i++) { + if(!IsSpecial(result[i])) { + minVal = min(minVal, result[i]); + } + } + + result.clear(); + result.push_back(minVal); + Push(result); + } + + + /** + * Pop one element, then push the maximum on the stack + */ + void Calculator::MaximumLine() { + QVector result = Pop(); + + double maxVal = result[0]; + for(int i = 0; i < result.size(); i++) { + if(!IsSpecial(result[i])) { + maxVal = max(maxVal, result[i]); + } + } + + result.clear(); + result.push_back(maxVal); + Push(result); + } + + + /** + * Pop two elements, then push the minimum on a pixel by pixel + * basis back on the stack + */ + void Calculator::MinimumPixel() { + QVector x = Pop(); + QVector y = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), + MinimumOperator); + Push(result); + } + + + /** + * Pop two elements, then push the maximum on a pixel by pixel + * basis back on the stack + */ + void Calculator::MaximumPixel() { + QVector x = Pop(); + QVector y = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), + MaximumOperator); + Push(result); + } + + + /** + * Pop two elements off the stack and compare them to see where one is greater + * than the other, then push the results on the stack. + */ + void Calculator::GreaterThan() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), + GreaterThanOperator); + Push(result); + } + + + /** + * Pop two elements off the stack and compare them to see where one is less + * than the other, then push the results on the stack. + */ + void Calculator::LessThan() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), + LessThanOperator); + Push(result); + } + + + /** + * Pop two elements off the stack and compare them to see where one is equal + * to the other, then push the results on the stack. + */ + void Calculator::Equal() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), + EqualOperator); + Push(result); + } + + + /** + * Pop two elements off the stack and compare them to see where one is greater + * than or equal to the other, then push the results on the stack. + */ + void Calculator::GreaterThanOrEqual() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), + GreaterThanOrEqualOperator); + Push(result); + } + + + /** + * Pop two elements off the stack and compare them to see where one is less + * than or equal to the other, then push the results on the stack. + */ + void Calculator::LessThanOrEqual() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), + LessThanOrEqualOperator); + Push(result); + } + + + /** + * Pop two elements off the stack and compare them to see where one is not + * equal to the other, then push the results on the stack. + */ + void Calculator::NotEqual() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), + NotEqualOperator); + Push(result); + } + + + // Commented out because bitwise ops only work with integers instead of + // doubles + + /** + * Pop two elements, AND them, then push the result on the stack + */ + void Calculator::And() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), + BitwiseAndOperator); + Push(result); + } + + + /** + * Pop two elements, OR them, then push the result on the stack + */ + void Calculator::Or() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), + BitwiseOrOperator); + Push(result); + } + + + /** + * Pops one element and push the sine + */ + void Calculator::Sine() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), sin); + Push(result); + } + + + /** + * Pops one element and push the cosine + */ + void Calculator::Cosine() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), cos); + Push(result); + } + + + /** + * Pops one element and push the tangent + */ + void Calculator::Tangent() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), tan); + Push(result); + } + + + /** + * Pops one element and push the cosecant + */ + void Calculator::Cosecant() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), CosecantOperator); + Push(result); + } + + + /** + * Pops one element and push the secant + */ + void Calculator::Secant() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), SecantOperator); + Push(result); + } + + + /** + * Pops one element and push the cotangent + */ + void Calculator::Cotangent() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), CotangentOperator); + Push(result); + } + + + /** + * Pops one element and push the arcsine + */ + void Calculator::Arcsine() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), asin); + Push(result); + } + + + /** + * Pops one element and push the arccosine + */ + void Calculator::Arccosine() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), acos); + Push(result); + } + + + /** + * Pops one element and push the arctangent + */ + void Calculator::Arctangent() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), atan); + Push(result); + } + + + /** + * Pops one element and push the inverse hyperbolic sine + */ + void Calculator::ArcsineH() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), asinh); + Push(result); + } + + + /** + * Pops one element and push the inverse hyperbolic cosine + */ + void Calculator::ArccosineH() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), acosh); + Push(result); + } + + + /** + * Pops one element and push the inverse hyperbolic tangent + */ + void Calculator::ArctangentH() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), atanh); + Push(result); + } + + + /** + * Pops two elements and push the arctangent + */ + void Calculator::Arctangent2() { + QVector y = Pop(); + QVector x = Pop(); + QVector result; + + PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), atan2); + Push(result); + } + + + /** + * Pops one element and push the hyperbolic sine + */ + void Calculator::SineH() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), sinh); + Push(result); + } + + + /** + * Pops one element and push the hyperbolic cosine + */ + void Calculator::CosineH() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), cosh); + Push(result); + } + + + /** + * Pops one element and push the hyperbolic tangent + */ + void Calculator::TangentH() { + QVector result = Pop(); + PerformOperation(result, result.begin(), result.end(), tanh); + Push(result); + } + + + // Stack methods + + //! Get the current stack size + int Calculator::StackSize() { + return p_valStack->size(); + } + + /** + * Push a vector onto the stack + * + * @param vect The vector that will be pushed on the stack + */ + void Calculator::Push(QVector &vect) { + p_valStack->push(vect); + } + + + /** + * Push a scalar onto the stack + * + * @param scalar The scalar that will be pushed on the stack + */ + void Calculator::Push(double scalar) { + QVector s; + s.push_back(scalar); + Push(s); + } + + + /** + * Push a buffer onto the stack + * + * @param buff The buffer that will be pushed on the stack + */ + void Calculator::Push(Buffer &buff) { + QVector b(buff.size()); + + for(int i = 0; i < buff.size(); i++) { + // Test for special pixels and map them to valid values + if(IsSpecial(buff[i])) { + if(Isis::IsNullPixel(buff[i])) { + //b[i] = NAN; + b[i] = sqrt(-1.0); + } + else if(Isis::IsHrsPixel(buff[i])) { + //b[i] = INFINITY; + b[i] = DBL_MAX * 2; + } + else if(Isis::IsHisPixel(buff[i])) { + //b[i] = INFINITY; + b[i] = DBL_MAX * 2; + } + else if(Isis::IsLrsPixel(buff[i])) { + //b[i] = -INFINITY; + b[i] = -DBL_MAX * 2; + } + else if(Isis::IsLisPixel(buff[i])) { + //b[i] = -INFINITY; + b[i] = -DBL_MAX * 2; + } + } + else + b[i] = buff[i]; + } + + Push(b); + } + + + /** + * Pop an element off the stack + * + * @param keepSpecials If true, special pixels will be + * preserved; otherwise, they will be mapped + * to double values + * + * @return The top of the stack, which gets popped + */ + QVector Calculator::Pop(bool keepSpecials) { + QVector top; + + if(p_valStack->empty()) { + std::string msg = "Stack is empty, cannot perform any more operations."; + throw Isis::iException::Message(Isis::iException::Math, msg, _FILEINFO_); + } + + top = p_valStack->top(); + + if(keepSpecials) { + for(int i = 0; i < (int)top.size(); i++) { + if(isnan(top[i])) { + top[i] = Isis::Null; + } + // Test for +INFINITY + else if(top[i] > DBL_MAX) { + top[i] = Isis::Hrs; + } + // Test for -INFINITY) + else if(top[i] < -DBL_MAX) { + top[i] = Isis::Lrs; + } + else { + // Do nothing + } + } + } + + p_valStack->pop(); + + + return top; + } + + + /** + * Print the vector at the top of the stack + */ + void Calculator::PrintTop() { + if(p_valStack->empty()) return; + + std::cout << "[ "; + QVector top = p_valStack->top(); + for(int i = 0; i < (int)top.size(); i++) { + std::cout << top[i] << " "; + } + std::cout << "]" << std::endl; + } + + + /** + * Check if the stack is empty + * + * @return bool True if the stack is empty + */ + bool Calculator::Empty() { + return p_valStack->empty(); + } + + + /** + * Clear out the stack + */ + void Calculator::Clear() { + while(!p_valStack->empty()) { + p_valStack->pop(); + } + } + + + /** + * Performs the mathematical operations on each argument. + * + * @param results [out] The results of the performed operation + * @param arg1Start The first argument to have the operation done on + * @param arg1End One argument beyond the final argument to have the operation + * done upon + * @param operation The operation to be done on all arguments + */ + void Calculator::PerformOperation(QVector &results, + QVector::iterator arg1Start, + QVector::iterator arg1End, + double operation(double)) + { + results.resize(arg1End-arg1Start); + + for(int pos = 0; pos < results.size(); pos++) { + results[pos] = operation(*arg1Start); + + arg1Start++; + } + } + + + /** + * Performs the mathematical operation on each pair of arguments, or a set of + * agruments against a single argument. + * + * @param results [out] The results of the performed operation + * @param arg1Start The first of the primary argument to have the operation done + * on + * @param arg1End One arguement beyond the final primary argument to have the + * operation done upon + * @param arg2Start The first of the secondaty argument to have the operation + * done on + * @param arg2End One arguement beyond the final secondary argument to have the + * operation done upon + * @param operation The operation to be done on all pairs of arguments + */ + void Calculator::PerformOperation(QVector &results, + QVector::iterator arg1Start, + QVector::iterator arg1End, + QVector::iterator arg2Start, + QVector::iterator arg2End, + double operation(double, double)) { + if(arg1End-arg1Start != 1 && arg2End-arg2Start != 1 && + arg1End-arg1Start != arg2End-arg2Start) { + std::string msg = "Cannot operate on vectors of differing sizes."; + throw Isis::iException::Message(Isis::iException::Math, msg, _FILEINFO_); + } + + int iSize = max(arg1End-arg1Start, arg2End-arg2Start); + results.resize(iSize); + + for(int pos = 0; pos < results.size(); pos++) { + results[pos] = operation(*arg1Start, *arg2Start); + + if(arg1Start+1 != arg1End) arg1Start++; + if(arg2Start+1 != arg2End) arg2Start++; + } + } +} // End of namespace Isis diff --git a/isis/src/base/objs/Calculator/Calculator.h b/isis/src/base/objs/Calculator/Calculator.h new file mode 100644 index 0000000000000000000000000000000000000000..69bda97758e41cfa6c2adf287f44cf09d6aa4128 --- /dev/null +++ b/isis/src/base/objs/Calculator/Calculator.h @@ -0,0 +1,150 @@ +/** + * @file + * $Revision: 1.11 $ + * $Date: 2010/04/16 19:10:14 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +// Calculator.h +#ifndef CALCULATOR_H_ +#define CALCULATOR_H_ + +#include "Buffer.h" + +// I'm not sure how to forward declare the iterators +#include + +template class QStack; +template class QVector; + +namespace Isis { +/** + * @brief Calculator for arrays + * + * This class is a RPN calculator on arrays. It uses classic + * push/pop/operator methods. That is, push array1, push + * array2, add, pop arrayResult. + * + * @ingroup Math + * + * @author 2007-04-01 Sean Crosby + * + * @internal + * @history 2007-06-11 Jeff Anderson - Fixed bug in + * Push(Buffer) method. NAN was not computed + * properly. + * @history 2007-08-21 Steven Lambright - Moved the infix to postfix + * conversion into its own class. + * @history 2008-01-28 Steven Lambright - Added more support for the + * power operator + * @history 2008-03-28 Steven Lambright - Condensed math methods to + * just call PerformOperation(...). Converted valarray's to vectors + * (in order to use iterators) + * @history 2008-06-18 Christopher Austin - Added as well as fixed + * documentation + * @history 2010-02-23 Steven Lambright - Added Minimum2, Maximum2 and all + * min/max operations now ignore special pixels. + * @history 2010-04-08 Steven Lambright - Made min, max have proper + * implementations and vectors are now QVectors. + * + */ + class Calculator { + public: + Calculator(); // Constructor + //! Virtual Constructor + virtual ~Calculator(); + + // Math methods + void Negative(); + void Multiply(); + void Add(); + void Subtract(); + void Divide(); + void Modulus(); + + void Exponent(); + void SquareRoot(); + void AbsoluteValue(); + void Log(); + void Log10(); + + void LeftShift(); + void RightShift(); + void MinimumPixel(); + void MaximumPixel(); + void MinimumLine(); + void MaximumLine(); + void Minimum2(); + void Maximum2(); + void GreaterThan(); + void LessThan(); + void Equal(); + void LessThanOrEqual(); + void GreaterThanOrEqual(); + void NotEqual(); + void And(); + void Or(); + + void Sine(); + void Cosine(); + void Tangent(); + void Secant(); + void Cosecant(); + void Cotangent(); + void Arcsine(); + void Arccosine(); + void Arctangent(); + void Arctangent2(); + void SineH(); + void CosineH(); + void TangentH(); + void ArcsineH(); + void ArccosineH(); + void ArctangentH(); + + // Stack methods + void Push(double scalar); + void Push(Buffer &buff); + void Push(QVector &vect); + QVector Pop(bool keepSpecials = false); + void PrintTop(); + bool Empty(); + virtual void Clear(); + + protected: + void PerformOperation(QVector &results, + QVector::iterator arg1Start, + QVector::iterator arg1End, + double operation(double)); + void PerformOperation(QVector &results, + QVector::iterator arg1Start, + QVector::iterator arg1End, + QVector::iterator arg2Start, + QVector::iterator arg2End, + double operation(double, double)); + + //! Returns the current stack size + int StackSize(); + + private: + //! The current stack of arguments + QStack< QVector > * p_valStack; + }; +}; + +#endif diff --git a/isis/src/base/objs/Calculator/Calculator.truth b/isis/src/base/objs/Calculator/Calculator.truth new file mode 100644 index 0000000000000000000000000000000000000000..2f01b57a8aca942c6070bd467d76d5811cedcb31 --- /dev/null +++ b/isis/src/base/objs/Calculator/Calculator.truth @@ -0,0 +1,56 @@ +------------------------------------------------------- +v1: [ 1 2 3 ] +v2: [ 4 5 6 ] +v4: [ 2 2 2 ] +Scalar: [ 2 ] +Big: [ 2.22045e-16 ] +------------------------------------------------------- +Negative (-v1): [ -1 -2 -3 ] +Multiply (v1*v2): [ 4 10 18 ] +Multiply (v1*scalar): [ 2 4 6 ] +Multiply (big*big): [ 4.93038e-32 ] +Add (v1+v2): [ 5 7 9 ] +Add (v1+scalar): [ 3 4 5 ] +Subtract (v1-v2): [ -3 -3 -3 ] +Subtract (v1-scalar): [ -1 0 1 ] +Divide (v1/v2): [ 0.25 0.4 0.5 ] +Divide (v1/scalar): [ 0.5 1 1.5 ] +Divide (1/0): [ inf ] +Divide (-1/0): [ -inf ] +Exponent (v1^scalar): [ 1 4 9 ] +Square Root (sqrt[v1]): [ 1 1.41421 1.73205 ] +Absolute value (-v1): [ 1 2 3 ] +Log (log[v1]): [ 0 0.693147 1.09861 ] +Log10 (log10[v1]): [ 0 0.30103 0.477121 ] +LeftShift (v1<>scalar): [ nan nan 1 ] +Min (v1): [ 1 ] +Max (v1): [ 3 ] +GreaterThan (v1>v4): [ 0 0 1 ] +LessThan (v1=v4): [ 0 1 1 ] +NotEqual (v1!=v4): [ 1 0 1 ] +Sine (v1): [ 0.841471 0.909297 0.14112 ] +Cosine (v1): [ 0.540302 -0.416147 -0.989992 ] +Tangent (v1): [ 1.55741 -2.18504 -0.142547 ] +Secant (v1): [ 1.85082 -2.403 -1.01011 ] +Cosecant (v1): [ 1.1884 1.09975 7.08617 ] +Cotangent (v1): [ 0.642093 -0.457658 -7.01525 ] +Arcsine (v1): [ 1.5708 nan nan ] +Arccosine (v1): [ 0 nan nan ] +Arctangent (v1): [ 0.785398 1.10715 1.24905 ] +SineH (v1): [ 1.1752 3.62686 10.0179 ] +CosineH (v1): [ 1.54308 3.7622 10.0677 ] +TangentH (v1): [ 0.761594 0.964028 0.995055 ] +Modulus (v1%v4): [ 1 0 1 ] +Bitwise And (v1,v4): [ 0 2 2 ] +Bitwise Or (v1,v4): [ 3 2 3 ] +Square Root(-1): [ nan ] +Log(of 0): [ -inf ] +------------------------------------------------------- +**MATH ERROR** Shift value must be <= to number of samples. +**MATH ERROR** Shift value must be <= to number of samples. +**MATH ERROR** Cannot operate on vectors of differing sizes. +**MATH ERROR** Stack is empty, cannot perform any more operations. diff --git a/isis/src/base/objs/Calculator/Makefile b/isis/src/base/objs/Calculator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e65630f47ee3cf1332389e4c051e8ddd72ea90ca --- /dev/null +++ b/isis/src/base/objs/Calculator/Makefile @@ -0,0 +1,5 @@ +INCS = Calculator.h +SRCS = Calculator.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Calculator/unitTest.cpp b/isis/src/base/objs/Calculator/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e07085b6c17a5de26497d004be936c2e2bea2ec1 --- /dev/null +++ b/isis/src/base/objs/Calculator/unitTest.cpp @@ -0,0 +1,388 @@ +#include "Calculator.h" + +#include + +#include + +#include "Preference.h" + + +using namespace std; +using namespace Isis; + +int main(int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + Isis::Calculator c; + QVector v1; + QVector v2; + QVector v3; + QVector v4; + double scalar = 2.0; + double big = DBL_EPSILON; + + v1.push_back(1); + v1.push_back(2); + v1.push_back(3); + + v2.push_back(4); + v2.push_back(5); + v2.push_back(6); + + v4.push_back(2); + v4.push_back(2); + v4.push_back(2); + + cout << "-------------------------------------------------------" << endl; + + c.Push(v1); + cout << "v1: "; + c.PrintTop(); + c.Push(v2); + cout << "v2: "; + c.PrintTop(); + c.Push(v4); + cout << "v4: "; + c.PrintTop(); + c.Push(scalar); + cout << "Scalar: "; + c.PrintTop(); + c.Push(big); + cout << "Big: "; + c.PrintTop(); + c.Clear(); + + cout << "-------------------------------------------------------" << endl; + + c.Push(v1); + c.Negative(); + cout << "Negative (-v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(v2); + c.Multiply(); + cout << "Multiply (v1*v2): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(scalar); + c.Multiply(); + cout << "Multiply (v1*scalar): "; + c.PrintTop(); + c.Clear(); + + c.Push(big); + c.Push(big); + c.Multiply(); + cout << "Multiply (big*big): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(v2); + c.Add(); + cout << "Add (v1+v2): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(scalar); + c.Add(); + cout << "Add (v1+scalar): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(v2); + c.Subtract(); + cout << "Subtract (v1-v2): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(scalar); + c.Subtract(); + cout << "Subtract (v1-scalar): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(v2); + c.Divide(); + cout << "Divide (v1/v2): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(scalar); + c.Divide(); + cout << "Divide (v1/scalar): "; + c.PrintTop(); + c.Clear(); + + c.Push(1.0); + c.Push(0.0); + c.Divide(); + cout << "Divide (1/0): "; + c.PrintTop(); + c.Clear(); + + c.Push(-1.0); + c.Push(0.0); + c.Divide(); + cout << "Divide (-1/0): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(scalar); + c.Exponent(); + cout << "Exponent (v1^scalar): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.SquareRoot(); + cout << "Square Root (sqrt[v1]): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Negative(); + c.AbsoluteValue(); + cout << "Absolute value (-v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Log(); + cout << "Log (log[v1]): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Log10(); + cout << "Log10 (log10[v1]): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(scalar); + c.LeftShift(); + cout << "LeftShift (v1<>scalar): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.MinimumLine(); + cout << "Min (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.MaximumLine(); + cout << "Max (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(v4); + c.GreaterThan(); + cout << "GreaterThan (v1>v4): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(v4); + c.LessThan(); + cout << "LessThan (v1=v4): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(v4); + c.NotEqual(); + cout << "NotEqual (v1!=v4): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Sine(); + cout << "Sine (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Cosine(); + cout << "Cosine (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Tangent(); + cout << "Tangent (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Secant(); + cout << "Secant (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Cosecant(); + cout << "Cosecant (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Cotangent(); + cout << "Cotangent (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Arcsine(); + cout << "Arcsine (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Arccosine(); + cout << "Arccosine (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Arctangent(); + cout << "Arctangent (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.SineH(); + cout << "SineH (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.CosineH(); + cout << "CosineH (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.TangentH(); + cout << "TangentH (v1): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(v4); + c.Modulus(); + cout << "Modulus (v1%v4): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(v4); + c.And(); + cout << "Bitwise And (v1,v4): "; + c.PrintTop(); + c.Clear(); + + c.Push(v1); + c.Push(v4); + c.Or(); + cout << "Bitwise Or (v1,v4): "; + c.PrintTop(); + c.Clear(); + + c.Push(1.0); + c.Negative(); + c.SquareRoot(); + cout << "Square Root(-1): "; + c.PrintTop(); + c.Clear(); + + c.Push(0.0); + c.Log(); + cout << "Log(of 0): "; + c.PrintTop(); + c.Clear(); + + std::cout << "-------------------------------------------------------" << std::endl; + try { + c.Push(v1); + c.Push(4); + c.LeftShift(); + cout << "LeftShift(too far): "; + c.PrintTop(); + c.Clear(); + } + catch(Isis::iException &e) { + e.Report(false); + } + + try { + c.Push(v1); + c.Push(4); + c.RightShift(); + cout << "RightShift(too far): "; + c.PrintTop(); + c.Clear(); + } + catch(Isis::iException &e) { + e.Report(false); + } + + try { + c.Push(v1); + c.Push(v3); + c.Add(); + } + catch(Isis::iException &e) { + e.Report(false); + } + + try { + c.Push(v1); + c.Add(); + c.Clear(); + } + catch(Isis::iException &e) { + e.Report(false); + } +} diff --git a/isis/src/base/objs/Camera/Camera.cpp b/isis/src/base/objs/Camera/Camera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6feef704e8c679798371494d38554b8b9c50f320 --- /dev/null +++ b/isis/src/base/objs/Camera/Camera.cpp @@ -0,0 +1,1494 @@ +/** + * @file + * $Revision: 1.31 $ + * $Date: 2010/06/16 18:22:48 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include "Camera.h" +#include "Projection.h" +#include "Constants.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraDistortionMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "ProjectionFactory.h" +#include "NaifStatus.h" +#include "iException.h" +#include "iString.h" + +using namespace std; +namespace Isis { + /** + * Constructs the Camera object + * + * @param lab Pvl label used to create the Camera object + */ + Camera::Camera(Isis::Pvl &lab) : Isis::Sensor(lab) { + // Get the image size which can be different than the alpha cube size + Isis::PvlGroup &dims = lab.FindObject("IsisCube") + .FindObject("Core") + .FindGroup("Dimensions"); + p_lines = dims["Lines"]; + p_samples = dims["Samples"]; + p_bands = dims["Bands"]; + + SetGeometricTilingHint(); + + // Get the AlphaCube information + p_alphaCube = new Isis::AlphaCube(lab); + + // Get the projection group if it exists + if(lab.FindObject("IsisCube").HasGroup("Mapping")) { + p_projection = ProjectionFactory::CreateFromCube(lab); + } + else { + p_projection = NULL; + } + p_ignoreProjection = false; + + // Initialize stuff + p_focalLength = 0.0; + p_pixelPitch = 1.0; + p_referenceBand = 0; + p_childBand = 1; + p_ckFrameId = 0; + p_ckReferenceId = 0; + p_ckwriteReady = false; + + p_distortionMap = NULL; + p_focalPlaneMap = NULL; + p_detectorMap = NULL; + p_groundMap = NULL; + p_skyMap = NULL; + + // See if we have a reference band + Isis::PvlGroup &inst = lab.FindObject("IsisCube").FindGroup("Instrument"); + if(inst.HasKeyword("ReferenceBand")) { + p_referenceBand = inst["ReferenceBand"]; + } + + // Set the FrameId and the ReferenceFrameId + SetCkFrameId(); + SetCkReferenceId(); + + p_groundRangeComputed = false; + p_raDecRangeComputed = false; + p_pointComputed = false; + } + + //! Destroys the Camera Object + Camera::~Camera() { + if(p_projection) { + delete p_projection; + p_projection = NULL; + } + + if(p_alphaCube) { + delete p_alphaCube; + p_alphaCube = NULL; + } + + if(p_distortionMap) { + delete p_distortionMap; + p_distortionMap = NULL; + } + + if(p_focalPlaneMap) { + delete p_focalPlaneMap; + p_focalPlaneMap = NULL; + } + + if(p_detectorMap) { + delete p_detectorMap; + p_detectorMap = NULL; + } + + if(p_groundMap) { + delete p_groundMap; + p_groundMap = NULL; + } + + if(p_skyMap) { + delete p_skyMap; + p_skyMap = NULL; + } + } + + /** + * Sets the sample/line values of the to get the lat/lon values + * + * @param sample Sample coordinate of the cube + * + * @param line Line coordinate of the cube + * + * @return bool Returns true if the image was set successfully and false if it + * was not + */ + bool Camera::SetImage(const double sample, const double line) { + p_childSample = sample; + p_childLine = line; + p_pointComputed = true; + + // Case of no map projection + if(p_projection == NULL || p_ignoreProjection) { + // Convert to parent coordinate (remove crop, pad, shrink, enlarge) + double parentSample = p_alphaCube->AlphaSample(sample); + double parentLine = p_alphaCube->AlphaLine(line); + // Convert from parent to detector + if(p_detectorMap->SetParent(parentSample, parentLine)) { + double detectorSample = p_detectorMap->DetectorSample(); + double detectorLine = p_detectorMap->DetectorLine(); + // Now Convert from detector to distorted focal plane + if(p_focalPlaneMap->SetDetector(detectorSample, detectorLine)) { + double focalPlaneX = p_focalPlaneMap->FocalPlaneX(); + double focalPlaneY = p_focalPlaneMap->FocalPlaneY(); + // Remove optical distortion + if(p_distortionMap->SetFocalPlane(focalPlaneX, focalPlaneY)) { + // Map to the ground + double x = p_distortionMap->UndistortedFocalPlaneX(); + double y = p_distortionMap->UndistortedFocalPlaneY(); + double z = p_distortionMap->UndistortedFocalPlaneZ(); + p_hasIntersection = p_groundMap->SetFocalPlane(x, y, z); + return p_hasIntersection; + } + } + } + } + + // The projection is a sky map + else if(p_projection->IsSky()) { + if(p_projection->SetWorld(sample, line)) { + if(SetRightAscensionDeclination(p_projection->Longitude(), + p_projection->UniversalLatitude())) { + p_childSample = sample; + p_childLine = line; + + return HasSurfaceIntersection(); + } + } + } + + // We have map projected camera model + else { + if(p_projection->SetWorld(sample, line)) { + if(SetUniversalGround(p_projection->UniversalLatitude(), + p_projection->UniversalLongitude())) { + p_childSample = sample; + p_childLine = line; + + p_hasIntersection = true; + return p_hasIntersection; + } + } + } + + // failure + p_hasIntersection = false; + return p_hasIntersection; + } + + /** + * Sets the lat/lon values to get the sample/line values + * + * @param latitude Latitude coordinate of the point + * @param longitude Longitude coordinate of the point + * + * @return 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) { + // Convert lat/lon to undistorted focal plane x/y + if(p_groundMap->SetGround(latitude, longitude)) { + return RawFocalPlanetoImage(); + } + + p_hasIntersection = false; + return p_hasIntersection; + } + + + + /** + * Computes the image coordinate for the current universal ground point + * + * + * @return bool Returns true if image coordinate was computed successfully and + * false if it was not + */ + bool Camera::RawFocalPlanetoImage() { + double ux = p_groundMap->FocalPlaneX(); + double uy = p_groundMap->FocalPlaneY(); + // Convert undistorted x/y to distorted x/y + if(p_distortionMap->SetUndistortedFocalPlane(ux, uy)) { + double focalPlaneX = p_distortionMap->FocalPlaneX(); + double focalPlaneY = p_distortionMap->FocalPlaneY(); + // Convert distorted x/y to detector position + if(p_focalPlaneMap->SetFocalPlane(focalPlaneX, focalPlaneY)) { + double detectorSample = p_focalPlaneMap->DetectorSample(); + double detectorLine = p_focalPlaneMap->DetectorLine(); + // Convert detector to parent position + if(p_detectorMap->SetDetector(detectorSample, detectorLine)) { + double parentSample = p_detectorMap->ParentSample(); + double parentLine = p_detectorMap->ParentLine(); + p_pointComputed = true; + + if(p_projection == NULL || p_ignoreProjection) { + p_childSample = p_alphaCube->BetaSample(parentSample); + p_childLine = p_alphaCube->BetaLine(parentLine); + p_hasIntersection = true; + return p_hasIntersection; + } + else if(p_projection->IsSky()) { + if(p_projection->SetGround(Declination(), RightAscension())) { + p_childSample = p_projection->WorldX(); + p_childLine = p_projection->WorldY(); + p_hasIntersection = true; + return p_hasIntersection; + } + } + else { + if(p_projection->SetUniversalGround(UniversalLatitude(), UniversalLongitude())) { + p_childSample = p_projection->WorldX(); + p_childLine = p_projection->WorldY(); + p_hasIntersection = true; + return p_hasIntersection; + } + } + } + } + } + + p_hasIntersection = false; + return p_hasIntersection; + } + + + + /** + * 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 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) { + // Convert lat/lon to undistorted focal plane x/y + if(p_groundMap->SetGround(latitude, longitude, radius)) { + return RawFocalPlanetoImage(); // sets p_hasIntersection + } + + p_hasIntersection = false; + return p_hasIntersection; + } + + /** + * Returns the detector resolution at the current position + * + * @return double The detector resolution + */ + double Camera::DetectorResolution() { + if(HasSurfaceIntersection()) { + 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 dist = sqrt(a * a + b * b + c * c) * 1000.0; + return dist / (p_focalLength / p_pixelPitch); + } + return -1.0; + } + + /** + * Returns the sample resolution at the current position + * + * @return double The sample resolution + */ + double Camera::SampleResolution() { + return DetectorResolution() * p_detectorMap->SampleScaleFactor(); + } + + /** + * Returns the line resolution at the current position + * + * @return double The line resolution + */ + double Camera::LineResolution() { + return DetectorResolution() * p_detectorMap->LineScaleFactor(); + } + + /** + * Returns the pixel resolution at the current position in m/pix + * + * @return double The pixel resolution + */ + double Camera::PixelResolution() { + double lineRes = LineResolution(); + double sampRes = SampleResolution(); + if(lineRes < 0.0) return -1.0; + if(sampRes < 0.0) return -1.0; + return (lineRes + sampRes) / 2.0; + } + + /** + * Returns the lowest/worst resolution in the entire image + * + * @return double The lowest/worst resolution in the image + */ + double Camera::LowestImageResolution() { + GroundRangeResolution(); + return p_maxres; + } + + /** + * Returns the highest/best resolution in the entire image + * + * @return double The highest/best resolution in the entire image + */ + double Camera::HighestImageResolution() { + GroundRangeResolution(); + return p_minres; + } + + /** + * Computes the ground range and min/max resolution + */ + void Camera::GroundRangeResolution() { + // Have we already done this + if(p_groundRangeComputed) return; + p_groundRangeComputed = true; + + bool computed = p_pointComputed; + double originalSample = Sample(); + double originalLine = Line(); + int originalBand = Band(); + + // Initializations + p_minlat = DBL_MAX; + p_minlon = DBL_MAX; + p_minlon180 = DBL_MAX; + p_maxlat = -DBL_MAX; + p_maxlon = -DBL_MAX; + p_maxlon180 = -DBL_MAX; + p_minres = DBL_MAX; + p_maxres = -DBL_MAX; + + // See if we have band dependence and loop for the appropriate number of bands + int eband = p_bands; + if(IsBandIndependent()) eband = 1; + for(int band = 1; band <= eband; band++) { + SetBand(band); + + // Loop for each line testing the left and right sides of the image + for(int line = 1; line <= p_lines + 1; line++) { + // Look for the first good lat/lon on the left edge of the image + // If it is the first or last line then test the whole line + int samp; + for(samp = 1; samp <= p_samples + 1; samp++) { + + if(SetImage((double)samp - 0.5, (double)line - 0.5)) { + double lat = UniversalLatitude(); + double lon = UniversalLongitude(); + if(lat < p_minlat) p_minlat = lat; + if(lat > p_maxlat) p_maxlat = lat; + if(lon < p_minlon) p_minlon = lon; + if(lon > p_maxlon) p_maxlon = lon; + + if(lon > 180.0) lon -= 360.0; + if(lon < p_minlon180) p_minlon180 = lon; + if(lon > p_maxlon180) p_maxlon180 = lon; + + double res = PixelResolution(); + if(res > 0.0) { + if(res < p_minres) p_minres = res; + if(res > p_maxres) p_maxres = res; + } + if((line != 1) && (line != p_lines + 1)) break; + } + } + + //We've already checked the first and last lines. + if(line == 1) continue; + if(line == p_lines + 1) continue; + + // Look for the first good lat/lon on the right edge of the image + if(samp < p_samples + 1) { + for(samp = p_samples + 1; samp >= 1; samp--) { + if(SetImage((double)samp - 0.5, (double)line - 0.5)) { + double lat = UniversalLatitude(); + double lon = UniversalLongitude(); + if(lat < p_minlat) p_minlat = lat; + if(lat > p_maxlat) p_maxlat = lat; + if(lon < p_minlon) p_minlon = lon; + if(lon > p_maxlon) p_maxlon = lon; + + if(lon > 180.0) lon -= 360.0; + if(lon < p_minlon180) p_minlon180 = lon; + if(lon > p_maxlon180) p_maxlon180 = lon; + + double res = PixelResolution(); + if(res > 0.0) { + if(res < p_minres) p_minres = res; + if(res > p_maxres) p_maxres = res; + } + break; + } + } + } + } + + // Test at the sub-spacecraft point to see if we have a + // better resolution + double lat, lon; + SubSpacecraftPoint(lat, lon); + if(SetUniversalGround(lat, lon)) { + if(Sample() >= 0.5 && Line() >= 0.5 && + Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) { + double res = PixelResolution(); + if(res > 0.0) { + if(res < p_minres) p_minres = res; + if(res > p_maxres) p_maxres = res; + } + } + } + + // Special test for ground range to see if either pole is in the image + if(SetUniversalGround(90.0, 0.0)) { + if(Sample() >= 0.5 && Line() >= 0.5 && + Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) { + p_maxlat = 90.0; + p_minlon = 0.0; + p_maxlon = 360.0; + p_minlon180 = -180.0; + p_maxlon180 = 180.0; + } + } + + if(SetUniversalGround(-90.0, 0.0)) { + if(Sample() >= 0.5 && Line() >= 0.5 && + Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) { + p_minlat = -90.0; + p_minlon = 0.0; + p_maxlon = 360.0; + p_minlon180 = -180.0; + p_maxlon180 = 180.0; + } + } + + // Another special test for ground range as we could have the + // 0-360 seam running right through the image so + // test it as well (the increment may not be fine enough !!!) + for(double lat = p_minlat; lat <= p_maxlat; lat += (p_maxlat - p_minlat) / 10.0) { + if(SetUniversalGround(lat, 0.0)) { + if(Sample() >= 0.5 && Line() >= 0.5 && + Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) { + p_minlon = 0.0; + p_maxlon = 360.0; + break; + } + } + } + + // Another special test for ground range as we could have the + // -180-180 seam running right through the image so + // test it as well (the increment may not be fine enough !!!) + for(double lat = p_minlat; lat <= p_maxlat; lat += (p_maxlat - p_minlat) / 10.0) { + if(SetUniversalGround(lat, 180.0)) { + if(Sample() >= 0.5 && Line() >= 0.5 && + Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) { + p_minlon180 = -180.0; + p_maxlon180 = 180.0; + break; + } + } + } + } + + SetBand(originalBand); + + if(computed) { + SetImage(originalSample, originalLine); + } + else { + p_pointComputed = false; + } + + // Checks for invalide lat/lon ranges + 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::Message(iException::Camera, message, _FILEINFO_); + } + } + + /** + * Checks whether the ground range intersects the longitude domain or not + * + * @param pvl The pvl file used to set the ground range + * + * @return bool Returns true if the range intersects the longitude domain, and + * false if it does not + */ + bool Camera::IntersectsLongitudeDomain(Isis::Pvl &pvl) { + double minlat, minlon, maxlat, maxlon; + return GroundRange(minlat, maxlat, minlon, maxlon, pvl); + } + + /** + * Computes the Ground Range + * + * @param minlat The minimum latitude + * + * @param maxlat The maximum latitude + * + * @param minlon The minimum longitude + * + * @param maxlon The maximum longitude + * + * @param pvl The pvl file used for ground range calculations + * + * @return bool Returns true if it crosses the longitude domain boundary and + * false if it does not + */ + bool Camera::GroundRange(double &minlat, double &maxlat, + double &minlon, double &maxlon, + Isis::Pvl &pvl) { + // Compute the ground range and resolution + GroundRangeResolution(); + + // Get the default radii + double radii[3]; + Radii(radii); + double a = radii[0] * 1000.0; + double b = radii[2] * 1000.0; + + // See if the PVL overrides the radii + Isis::PvlGroup map = pvl.FindGroup("Mapping", Isis::Pvl::Traverse); + if(map.HasKeyword("EquatorialRadius")) a = map["EquatorialRadius"]; + if(map.HasKeyword("PolarRadius")) b = map["PolarRadius"]; + + // Convert to planetographic if necessary + minlat = p_minlat; + maxlat = p_maxlat; + if(map.HasKeyword("LatitudeType")) { + Isis::iString latType = (string) map["LatitudeType"]; + if(latType.UpCase() == "PLANETOGRAPHIC") { + if(abs(minlat) < 90.0) { // So tan doesn't fail + minlat *= Isis::PI / 180.0; + minlat = atan(tan(minlat) * (a / b) * (a / b)); + minlat *= 180.0 / Isis::PI; + } + + if(abs(maxlat) < 90.0) { // So tan doesn't fail + maxlat *= Isis::PI / 180.0; + maxlat = atan(tan(maxlat) * (a / b) * (a / b)); + maxlat *= 180.0 / Isis::PI; + } + } + } + + // Assume 0 to 360 domain but change it if necessary + minlon = p_minlon; + maxlon = p_maxlon; + bool domain360 = true; + if(map.HasKeyword("LongitudeDomain")) { + Isis::iString lonDomain = (string) map["LongitudeDomain"]; + if(lonDomain.UpCase() == "180") { + minlon = p_minlon180; + maxlon = p_maxlon180; + domain360 = false; + } + } + + // Convert to the proper longitude direction + if(map.HasKeyword("LongitudeDirection")) { + Isis::iString lonDirection = (string) map["LongitudeDirection"]; + if(lonDirection.UpCase() == "POSITIVEWEST") { + double swap = minlon; + minlon = -maxlon; + maxlon = -swap; + } + } + + // Convert to the proper longitude domain + if(domain360) { + while(minlon < 0.0) { + minlon += 360.0; + maxlon += 360.0; + } + while(minlon > 360.0) { + minlon -= 360.0; + maxlon -= 360.0; + } + } + else { + while(minlon < -180.0) { + minlon += 360.0; + maxlon += 360.0; + } + while(minlon > 180.0) { + minlon -= 360.0; + maxlon -= 360.0; + } + } + // Now return if it crosses the longitude domain boundary + if((maxlon - minlon) > 359.0) return true; + return false; + } + + /** + * Writes the basic mapping group to the specified Pvl. + * + * @param pvl Pvl to write mapping group to + */ + void Camera::BasicMapping(Isis::Pvl &pvl) { + Isis::PvlGroup map("Mapping"); + map += Isis::PvlKeyword("TargetName", Target()); + map += Isis::PvlKeyword("EquatorialRadius", p_radii[0] * 1000.0, "meters"); + map += Isis::PvlKeyword("PolarRadius", p_radii[2] * 1000.0, "meters"); + map += Isis::PvlKeyword("LatitudeType", "Planetocentric"); + map += Isis::PvlKeyword("LongitudeDirection", "PositiveEast"); + map += Isis::PvlKeyword("LongitudeDomain", "360"); + + GroundRangeResolution(); + map += Isis::PvlKeyword("MinimumLatitude", p_minlat); + map += Isis::PvlKeyword("MaximumLatitude", p_maxlat); + map += Isis::PvlKeyword("MinimumLongitude", p_minlon); + map += Isis::PvlKeyword("MaximumLongitude", p_maxlon); + map += Isis::PvlKeyword("PixelResolution", p_minres); + + map += Isis::PvlKeyword("ProjectionName", "Sinusoidal"); + pvl.AddGroup(map); + } + + //! Reads the focal length from the instrument kernel + void Camera::SetFocalLength() { + int code = NaifIkCode(); + string key = "INS" + Isis::iString(code) + "_FOCAL_LENGTH"; + SetFocalLength(Isis::Spice::GetDouble(key)); + } + + //! Reads the Pixel Pitch from the instrument kernel + void Camera::SetPixelPitch() { + int code = NaifIkCode(); + string key = "INS" + Isis::iString(code) + "_PIXEL_PITCH"; + SetPixelPitch(Isis::Spice::GetDouble(key)); + } + + /** + * Sets the right ascension declination + * + * @param ra + * + * @param dec + * + * @return bool Returns true if the declination was set successfully and false + * if it was not + */ + bool Camera::SetRightAscensionDeclination(const double ra, const double dec) { + if(p_skyMap->SetSky(ra, dec)) { + double ux = p_skyMap->FocalPlaneX(); + double uy = p_skyMap->FocalPlaneY(); + if(p_distortionMap->SetUndistortedFocalPlane(ux, uy)) { + double dx = p_distortionMap->FocalPlaneX(); + double dy = p_distortionMap->FocalPlaneY(); + if(p_focalPlaneMap->SetFocalPlane(dx, dy)) { + double detectorSamp = p_focalPlaneMap->DetectorSample(); + double detectorLine = p_focalPlaneMap->DetectorLine(); + if(p_detectorMap->SetDetector(detectorSamp, detectorLine)) { + double parentSample = p_detectorMap->ParentSample(); + double parentLine = p_detectorMap->ParentLine(); + p_pointComputed = true; + + if(p_projection == NULL || p_ignoreProjection) { + p_childSample = p_alphaCube->BetaSample(parentSample); + p_childLine = p_alphaCube->BetaLine(parentLine); + return true; + } + else if(p_projection->IsSky()) { + if(p_projection->SetGround(dec, ra)) { + p_childSample = p_projection->WorldX(); + p_childLine = p_projection->WorldY(); + return true; + } + } + else if(p_hasIntersection) { + if(p_projection->SetUniversalGround(UniversalLatitude(), + UniversalLongitude())) { + p_childSample = p_projection->WorldX(); + p_childLine = p_projection->WorldY(); + return true; + } + } + } + } + } + } + + return false; + } + + /** + * Computes the RaDec range + * + * @param minra + * + * @param maxra + * + * @param mindec + * + * @param maxdec + * + * @return 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) { + if(p_projection != NULL && !p_projection->IsSky()) { + iString msg = "Camera::RaDecRange can not calculate a right ascension, declination range"; + msg += " for projected images which are not projected to sky"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + bool computed = p_pointComputed; + double originalSample = Sample(); + double originalLine = Line(); + int originalBand = Band(); + + // Have we already done this + if(!p_raDecRangeComputed) { + p_raDecRangeComputed = true; + + // Initializations + p_mindec = DBL_MAX; + p_minra = DBL_MAX; + p_minra180 = DBL_MAX; + p_maxdec = -DBL_MAX; + p_maxra = -DBL_MAX; + p_maxra180 = -DBL_MAX; + + // See if we have band dependence and loop for the appropriate number of bands + int eband = p_bands; + if(IsBandIndependent()) eband = 1; + for(int band = 1; band <= eband; band++) { + this->SetBand(band); + + for(int line = 1; line <= p_lines; line++) { + // Test left, top, and bottom sides + int samp; + for(samp = 1; samp <= p_samples; samp++) { + SetImage((double)samp, (double)line); + double ra = RightAscension(); + double dec = Declination(); + if(ra < p_minra) p_minra = ra; + if(ra > p_maxra) p_maxra = ra; + if(dec < p_mindec) p_mindec = dec; + if(dec > p_maxdec) p_maxdec = dec; + + if(ra > 180.0) ra -= 360.0; + if(ra < p_minra180) p_minra180 = ra; + if(ra > p_maxra180) p_maxra180 = ra; + + if((line != 1) && (line != p_lines)) break; + } + + // Test right side + if(samp < p_samples) { + for(samp = p_samples; samp >= 1; samp--) { + SetImage((double)samp, (double)line); + double ra = RightAscension(); + double dec = Declination(); + if(ra < p_minra) p_minra = ra; + if(ra > p_maxra) p_maxra = ra; + if(dec < p_mindec) p_mindec = dec; + if(dec > p_maxdec) p_maxdec = dec; + + if(ra > 180.0) ra -= 360.0; + if(ra < p_minra180) p_minra180 = ra; + if(ra > p_maxra180) p_maxra180 = ra; + + break; + } + } + } + + // Special test for ground range to see if either pole is in the image + if(SetRightAscensionDeclination(0.0, 90.0)) { + if((Line() >= 0.5) && (Line() <= p_lines) && + (Sample() >= 0.5) && (Sample() <= p_samples)) { + p_maxdec = 90.0; + p_minra = 0.0; + p_maxra = 360.0; + p_minra180 = -180.0; + p_maxra180 = 180.0; + } + } + + if(SetRightAscensionDeclination(0.0, -90.0)) { + if((Line() >= 0.5) && (Line() <= p_lines) && + (Sample() >= 0.5) && (Sample() <= p_samples)) { + p_mindec = -90.0; + p_minra = 0.0; + p_maxra = 360.0; + p_minra180 = -180.0; + p_maxra180 = 180.0; + } + } + + // Another special test for ground range as we could have the + // 0-360 seam running right through the image so + // test it as well (the increment may not be fine enough !!!) + for(double dec = p_mindec; dec <= p_maxdec; dec += (p_maxdec - p_mindec) / 10.0) { + if(SetRightAscensionDeclination(0.0, dec)) { + if((Line() >= 0.5) && (Line() <= p_lines) && + (Sample() >= 0.5) && (Sample() <= p_samples)) { + p_minra = 0.0; + p_maxra = 360.0; + break; + } + } + } + + // Another special test for ground range as we could have the + // 0-360 seam running right through the image so + // test it as well (the increment may not be fine enough !!!) + for(double dec = p_mindec; dec <= p_maxdec; dec += (p_maxdec - p_mindec) / 10.0) { + if(SetRightAscensionDeclination(180.0, dec)) { + if((Line() >= 0.5) && (Line() <= p_lines) && + (Sample() >= 0.5) && (Sample() <= p_samples)) { + p_minra180 = -180.0; + p_maxra180 = 180.0; + break; + } + } + } + } + } + + minra = p_minra; + maxra = p_maxra; + mindec = p_mindec; + maxdec = p_maxdec; + + SetBand(originalBand); + + if(computed) { + SetImage(originalSample, originalLine); + } + else { + p_pointComputed = false; + } + + return true; + } + + + /** + * Returns the RaDec resolution + * + * + * @return double The resutant RaDec resolution + */ + double Camera::RaDecResolution() { + if(p_projection != NULL && !p_projection->IsSky()) { + iString msg = "Camera::RaDecResolution can not calculate a right ascension, declination resolution"; + msg += " for projected images which are not projected to sky"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + bool computed = p_pointComputed; + double originalSample = Sample(); + double originalLine = Line(); + int originalBand = Band(); + + SetImage(1.0, 1.0); + double ra1 = RightAscension(); + double dec1 = Declination(); + + SetImage(1.0, (double)p_lines); + double ra2 = RightAscension(); + double dec2 = Declination(); + + double dist = (ra1 - ra2) * (ra1 - ra2) + (dec1 - dec2) * (dec1 - dec2); + dist = sqrt(dist); + double lineRes = dist / (p_lines - 1); + + SetImage((double)p_samples, 1.0); + ra2 = RightAscension(); + dec2 = Declination(); + + dist = (ra1 - ra2) * (ra1 - ra2) + (dec1 - dec2) * (dec1 - dec2); + dist = sqrt(dist); + double sampRes = dist / (p_samples - 1); + + SetBand(originalBand); + + if(computed) { + SetImage(originalSample, originalLine); + } + else { + p_pointComputed = false; + } + + return (sampRes < lineRes) ? sampRes : lineRes; + } + + /** + * Returns the North Azimuth + * + * @return double North Azimuth + */ + double Camera::NorthAzimuth() { + return ComputeAzimuth(p_radii[2], 90.0, 0.0); + } + + /** + * Returns the Sun Azimuth + * + * @return double Sun Azimuth + * + * @todo Get appropriate radius at the subsolar point + */ + double Camera::SunAzimuth() { + double lat, lon; + SubSolarPoint(lat, lon); + return ComputeAzimuth(LocalRadius() / 1000.0, lat, lon); + } + + /** + * Return the Spacecraft Azimuth + * + * @return double Spacecraft Azimuth + * + * @todo Get appropriate radius at the subscraft point + */ + double Camera::SpacecraftAzimuth() { + double lat, lon; + SubSpacecraftPoint(lat, lon); + return ComputeAzimuth(LocalRadius() / 1000.0, lat, lon); + } + + /** + * Computes the Azimuth value at specified lat/lon with the entered radius + * + * @param radius The Radius + * + * @param lat The Latitude + * + * @param lon The Longitude + * + * @return double Azimuth value + * + * @history 2009-09-23 Tracie Sucharski - Convert negative + * longitudes coming out of reclat. + * + * @todo Write PushState and PopState method to ensure the + * internals of the class are set based on SetImage or SetGround + */ + double Camera::ComputeAzimuth(const double radius, + const double lat, const double lon) { + if(!HasSurfaceIntersection()) return -1.0; + + bool computed = p_pointComputed; + double originalSample = Sample(); + double originalLine = Line(); + + NaifStatus::CheckErrors(); + + // Convert the point to x/y/z in body-fixed + SpiceDouble pB[3]; + latrec_c(radius, lon * Isis::PI / 180.0, lat * Isis::PI / 180.0, pB); + + // Get the origin point + SpiceDouble oB[3]; + Coordinate(oB); + + // Get the difference unit vector + SpiceDouble poB[3], upoB[3]; + vsub_c(pB, oB, poB); + vhat_c(poB, upoB); + + // Scale to be within a pixel (km) + double scale = (PixelResolution() / 1000.0) / 2.0; + SpiceDouble supoB[3]; + vscl_c(scale, upoB, supoB); + + // Compute the new point in body fixed. This point will be within + // a pixel of the origin but in the same direction as the + // requested lat/lon + SpiceDouble nB[3]; + vadd_c(oB, supoB, nB); + + // However, it could be below the surface of the planet so bring it + // back + vhat_c(nB, nB); + vscl_c(LocalRadius() / 1000.0, nB, nB); + + // Get the origin image coordinate + double osample = Sample(); + double oline = Line(); + + // Convert the point to a lat/lon and find out its image coordinate + double nrad, nlon, nlat; + reclat_c(nB, &nrad, &nlon, &nlat); + nlat = nlat * 180.0 / Isis::PI; + nlon = nlon * 180.0 / Isis::PI; + if(nlon < 0) nlon += 360.0; + SetUniversalGround(nlat, nlon); + double nsample = Sample(); + double nline = Line(); + + // TODO: Write PushState and PopState method to ensure the + // internals of the class are set based on SetImage or SetGround + SetImage(osample, oline); + + double deltaSample = nsample - osample; + double deltaLine = nline - oline; + + // Compute the angle + double azimuth = 0.0; + if(deltaSample != 0.0 || deltaLine != 0.0) { + azimuth = atan2(deltaLine, deltaSample); + azimuth *= 180.0 / Isis::PI; + } + if(azimuth < 0.0) azimuth += 360.0; + if(azimuth > 360.0) azimuth -= 360.0; + + NaifStatus::CheckErrors(); + + if(computed) { + SetImage(originalSample, originalLine); + } + else { + p_pointComputed = false; + } + + return azimuth; + } + + /** + * Return the off nadir angle in degrees. + * + * @return double Off Nadir Angle + */ + double Camera::OffNadirAngle() { + NaifStatus::CheckErrors(); + + // Get the xyz coordinates for the spacecraft and point we are interested in + double coord[3], spCoord[3]; + Coordinate(coord); + InstrumentPosition(spCoord); + + // Get the angle between the 2 points and convert to degrees + double a = vsep_c(coord, spCoord) * 180.0 / Isis::PI; + double b = 180.0 - EmissionAngle(); + + // The three angles in a triangle must add up to 180 degrees + double c = 180.0 - (a + b); + + NaifStatus::CheckErrors(); + + return c; + } + + /** + * Computes and returns the ground azimuth between the ground point and + * another point of interest, such as the subspacecraft point or the + * subsolar point. The ground azimuth is the clockwise angle on the + * ground between a line drawn from the ground point to the North pole + * of the body and a line drawn from the ground point to the point of + * interest (such as the subsolar point or the subspacecraft point). + * + * @param glat The latitude of the ground point + * @param glon The longitude of the ground point + * @param slat The latitude of the subspacecraft or subsolar point + * @param slon The longitude of the subspacecraft or subsolar point + * + * @return double The azimuth in degrees + */ + double Camera::GroundAzimuth(double glat, double glon, + double slat, double slon) { + double a = (90.0 - slat) * Isis::PI / 180.0; + double b = (90.0 - glat) * Isis::PI / 180.0; + double c = (glon - slon) * Isis::PI / 180.0; + double absum = 0.5 * (a + b); + double cosabsum = cos(absum); + double sinabsum = sin(absum); + double abdif = 0.5 * (a - b); + double cosabdif = cos(abdif); + double sinabdif = sin(abdif); + double cotc = 1.0 / (tan(0.5 * c)); + double tanabsum = cotc * cosabdif / cosabsum; + double tanabdif = cotc * sinabdif / sinabsum; + double ABsum = atan(tanabsum); + double ABdif = atan(tanabdif); + double A = ABsum + ABdif; + double B = ABsum - ABdif; + double sinc = sin(c) * sin(a) / sin(A); + c = asin(sinc); + double azimuthA = A * 180.0 / Isis::PI + 90.0; + double azimuthB = 90.0 - B * 180.0 / Isis::PI; + double azimuth = 0.0; + if((glat > slat && glon > slon) || + (glat < slat && glon > slon)) { + if(azimuthA < azimuthB) { + azimuth = 270.0 - azimuthA; + } + else { + azimuth = 270.0 - azimuthB; + } + } + else if((glat < slat && glon < slon) || + (glat > slat && glon < slon)) { + if(azimuthA < azimuthB) { + azimuth = 90.0 - azimuthA; + } + else { + azimuth = 90.0 - azimuthB; + } + } + return azimuth; + } + + /** + * Computes and returns the distance between two latitude/longitude points in + * meters, given the radius of the sphere. The method uses the haversine + * formula to compute the distance. + * + * @param lat1 The first latitude value + * @param lon1 The first longitude value + * @param lat2 The second latitude value + * @param lon2 The second longitude value + * @param radius The radius of the sphere (in meters) + * + * @return double The distance between the two points + */ + double Camera::Distance(double lat1, double lon1, + double lat2, double lon2, double radius) { + // Convert lat/lon values to radians + double latRad1 = lat1 * Isis::PI / 180.0; + double latRad2 = lat2 * Isis::PI / 180.0; + double lonRad1 = lon1 * Isis::PI / 180.0; + double lonRad2 = lon2 * Isis::PI / 180.0; + + double deltaLat = latRad2 - latRad1; + double deltaLon = lonRad2 - lonRad1; + double a = (sin(deltaLat / 2) * sin(deltaLat / 2)) + cos(latRad1) * + cos(latRad2) * (sin(deltaLon / 2) * sin(deltaLon / 2)); + double c = 2 * atan(sqrt(a) / sqrt(1 - a)); + double dist = radius * c; + return dist; + } + + + /** + * Sets the Distortion Map. This object will take ownership of the distortion + * map pointer. + * + * @param *map Pointer to a CameraDistortionMap object + */ + void Camera::SetDistortionMap(CameraDistortionMap *map) { + if(p_distortionMap) { + delete p_distortionMap; + } + + p_distortionMap = map; + }; + + /** + * Sets the Focal Plane Map. This object will take ownership of the focal plane + * map pointer. + * + * @param *map Pointer to a CameraFocalPlaneMap object + */ + void Camera::SetFocalPlaneMap(CameraFocalPlaneMap *map) { + if(p_focalPlaneMap) { + delete p_focalPlaneMap; + } + + p_focalPlaneMap = map; + }; + + /** + * Sets the Detector Map. This object will take ownership of the detector map + * pointer. + * + * @param *map Pointer to a CameraDetectorMap object + */ + void Camera::SetDetectorMap(CameraDetectorMap *map) { + if(p_detectorMap) { + delete p_detectorMap; + } + + p_detectorMap = map; + }; + + /** + * Sets the Ground Map. This object will take ownership of the ground map + * pointer. + * + * @param *map Pointer to a CameraGroundMap object + */ + void Camera::SetGroundMap(CameraGroundMap *map) { + if(p_groundMap) { + delete p_groundMap; + } + + p_groundMap = map; + }; + + /** + * Sets the Sky Map. This object will take ownership of the sky map pointer. + * + * @param *map Pointer to a CameraSkyMap object + */ + void Camera::SetSkyMap(CameraSkyMap *map) { + if(p_skyMap) { + delete p_skyMap; + } + + 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 + * image, one otherwise. + * + * @param cacheSize The size of the spice cache. Should be >1 or not entered. + * + */ + void Camera::LoadCache(int cacheSize) { + // We want to stay in unprojected space for this process + bool projIgnored = p_ignoreProjection; + p_ignoreProjection = true; + + double etStart = 0.0, etEnd = 0.0; + + for(int band = 1; band <= Bands(); band++) { + SetBand(band); + SetImage(0.5, 0.5); + double etStartTmp = EphemerisTime(); + SetImage(p_alphaCube->BetaSamples() + 0.5, p_alphaCube->BetaLines() + 0.5); + double etEndTmp = EphemerisTime(); + + if(band == 1) { + etStart = min(etStartTmp, etEndTmp); + etEnd = max(etStartTmp, etEndTmp); + } + + etStart = min(etStart, min(etStartTmp, etEndTmp)); + etEnd = max(etEnd, max(etStartTmp, etEndTmp)); + } + + if(cacheSize <= 0) { + // BetaLines() + 1 so we get at least 2 points for interpolation + cacheSize = p_alphaCube->BetaLines() + 1; + + if(etStart == etEnd) { + cacheSize = 1; + } + } + + if(etStart == -DBL_MAX || etEnd == -DBL_MAX) { + string msg = "Unable to find time range for the spice kernels"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + // Set a position in the image so that the PixelResolution can be calculated + SetImage(p_alphaCube->BetaSamples() / 2, p_alphaCube->BetaLines() / 2); + double tol = PixelResolution() / 100.; //meters/pix/100. + + if(tol < 0.) { + // Alternative calculation of ground resolution of a pixel/100 + double altitudeMeters; + if(IsSky()) { // Use the unit sphere as the target + altitudeMeters = 1.0; + } + else { + altitudeMeters = SpacecraftAltitude() * 1000.; + } + tol = PixelPitch() * altitudeMeters / FocalLength() / 100.; + } + + p_ignoreProjection = projIgnored; + + Spice::CreateCache(etStart, etEnd, cacheSize, tol); + + SetEphemerisTime(etStart); + + // Reset to band 1 + SetBand(1); + } + + /** + * This method sets the best geometric tiling size for projecting from this + * camera model. This is used by cam2map/ProcessRubberSheet. When cubes are + * projected, an attempt is made to use linear equations to take large, square + * chunks of data at a time to cull the amount of SetUniversalGround(...) calls + * necessary to project a cube. If the chunk of data fails to be linear, then it + * will be split up into 4 corners and each of the new chunks (corners) are + * reconsidered up until endSize is reached - the endsize size will be + * considered, it is inclusive. The startSize must be a power of 2 greater + * than 2, and the endSize must be a power of 2 equal to or less than the + * start size but greater than 2. If both the startSize and endSize are set to 2 + * then no geometric tiling will be enabled. + * + * @param startSize The tile size to start with; default 128 + * @param endSize The tile size to give up at; default 8 + */ + void Camera::SetGeometricTilingHint(int startSize, int endSize) { + // verify the start size is a multiple of 2 greater than 2 + int powerOf2 = 2; + + // No hint if 2's are passed in + if(startSize == 2 && endSize == 2) { + p_geometricTilingStartSize = 2; + p_geometricTilingEndSize = 2; + return; + } + + if(endSize > startSize) { + iString message = "Camera::SetGeometricTilingHint End size must be smaller than the start size"; + throw iException::Message(iException::Programmer, message, _FILEINFO_); + } + + if(startSize < 4) { + iString message = "Camera::SetGeometricTilingHint Start size must be at least 4"; + throw iException::Message(iException::Programmer, message, _FILEINFO_); + } + + bool foundEnd = false; + while(powerOf2 > 0 && startSize != powerOf2) { + if(powerOf2 == endSize) foundEnd = true; + powerOf2 *= 2; + } + + // Didnt find a solution, the integer became negative first, must not be + // a power of 2 + if(powerOf2 < 0) { + iString message = "Camera::SetGeometricTilingHint Start size must be a power of 2"; + throw iException::Message(iException::Programmer, message, _FILEINFO_); + } + + if(!foundEnd) { + iString message = "Camera::SetGeometricTilingHint End size must be a power of 2 less than the start size, but greater than 2"; + throw iException::Message(iException::Programmer, message, _FILEINFO_); + } + + p_geometricTilingStartSize = startSize; + p_geometricTilingEndSize = endSize; + } + + /** + * This will get the geometric tiling hint; these values are typically used for + * ProcessRubberSheet::SetTiling(...). + * + * @param startSize Tiling start size + * @param endSize Tiling end size + */ + void Camera::GetGeometricTilingHint(int &startSize, int &endSize) { + startSize = p_geometricTilingStartSize; + endSize = p_geometricTilingEndSize; + } + + + /** + * This returns true if the current Sample() or Line() value + * is outside of the cube (meaning the point must have been + * extrapolated). + * + * + * @return bool Point was extrapolated + */ + bool Camera::InCube() { + if(Sample() < 0.5 || Line() < 0.5) { + return false; + } + + if(Sample() > Samples() + 0.5 || Line() > Lines() + 0.5) { + return false; + } + + return true; + } + + //! Reads the ck frame id from the instrument kernel + void Camera::SetCkFrameId() { + int code = NaifIkCode(); + string key = "INS" + Isis::iString(code) + "_CK_FRAME_ID"; + try { + p_ckFrameId = Isis::Spice::GetInteger(key, 0); + p_ckwriteReady = true; + } + catch(iException &e) { + p_ckwriteReady = false; + e.Clear(); + } + } + + //! Returns the ck frame id if defined + int Camera::CkFrameId() { + if(p_ckwriteReady) { + return p_ckFrameId; + } + else { + std::string msg = "Unable to find CK_FRAME_ID keyword for instrument"; + throw Isis::iException::Message(iException::Camera, msg, _FILEINFO_); + } + } + + + //! Reads the ck reference frame id if known + void Camera::SetCkReferenceId() { + int code = NaifIkCode(); + string key = "INS" + Isis::iString(code) + "_CK_REFERENCE_ID"; + try { + p_ckReferenceId = Isis::Spice::GetInteger(key); + p_ckwriteReady = true; + } + catch(iException &e) { + p_ckwriteReady = false; + e.Clear(); + } + } + + + //! Returns the ck reference frame id if known + int Camera::CkReferenceId() { + if(p_ckwriteReady) { + return p_ckReferenceId; + } + else { + std::string msg = "Unable to find CK_REFERENCE_ID keyword for instrument"; + throw Isis::iException::Message(iException::Camera, msg, _FILEINFO_); + } + } +// end namespace isis +} diff --git a/isis/src/base/objs/Camera/Camera.h b/isis/src/base/objs/Camera/Camera.h new file mode 100644 index 0000000000000000000000000000000000000000..083fc54868ae750303aa2421897e4363a663605a --- /dev/null +++ b/isis/src/base/objs/Camera/Camera.h @@ -0,0 +1,540 @@ +#ifndef Camera_h +#define Camera_h +/** + * @file + * $Revision: 1.32 $ + * $Date: 2010/06/16 18:22:48 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Sensor.h" +#include "AlphaCube.h" + +namespace Isis { + class Projection; + class CameraDetectorMap; + class CameraFocalPlaneMap; + class CameraDistortionMap; + class CameraGroundMap; + class CameraSkyMap; + + /** + * @author ??? Jeff Anderson + * + * @internal + * @todo Finish documentation. + * + * @history 2005-11-09 Tracie Sucharski - Added HasProjection method. + * @history 2006-04-11 Tracie Sucharski - Added IgnoreProjection method and + * p_ignoreProjection so that the + * Camera is used rather than Projection. + * @history 2006-04-19 Elizabeth Miller - Added SpacecraftRoll method + * @history 2006-06-08 Elizabeth Miller - Added static Distance method that + * calculates the distance between 2 + * lat/lon pts (given the radius) + * @history 2006-07-25 Elizabeth Miller - Fixed bug in Distance method + * @history 2006-07-31 Elizabeth Miller - Added OffNadirAngle method and + * removed SpacecraftRoll method + * @history 2007-06-11 Debbie A. Cook - Added overloaded method SetUniversalGround + * that includes a radius argument and method + * RawFocalPlanetoImage() to handle the common + * functionality between the SetUniversalGround + * methods. + * @history 2008-01-28 Christopher Austin - Added error throw + * when minlon range isn't set beyond initialization. + * + * @history 2008-02-15 Stacy Alley - In the + * GroundRangeResolution () method we had to subtract + * 0.5 when looking at the far left of pixels and + * add 0.5 to ensure we are seeing the far right of + * pixels. + * @history 2008-05-21 Steven Lambright - Fixed boundary condition in the + * GroundRangeResolution () method. + * @history 2008-06-18 Christopher Austin - Fixed documentation errors + * @history 2008-07-15 Steven Lambright - Added NaifStatus calls + * @history 2008-07-24 Steven Lambright - Fixed memory leaks: the alpha cube, + * distortion map, focal plane map, sky map, detector map, and ground + * map were not being deleted. + * @history 2008-08-08 Steven Lambright - Added the LoadCache() method which + * tries to find the correct time range and calls + * Spice::CreateCache + * @history 2008-09-10 Steven Lambright - Added the geometric tiling methods + * in order to optimize push frame cameras and prevent corruption of + * data when running cam2map with push frame cameras + * @history 2008-11-13 Janet Barrett - Added the GroundAzimuth method. This + * method computes and returns the ground azimuth between the ground + * point and another point of interest, such as the subspacecraft + * point or the subsolar point. The ground azimuth is the clockwise + * angle on the ground between a line drawn from the ground point to + * the North pole of the body and a line drawn from the ground point + * to the point of interest (such as the subsolar point or the + * subspacecraft point). + * @history 2009-01-05 Steven Lambright - Added InCube method + * @history 2009-03-02 Steven Lambright - This class now keeps track of the + * current child band, has added error checks, and now hopefully + * resets state when methods like GroundRangeResolution are called. + * @history 2009-05-21 Steven Lambright - The geometric tiling hint can now be + * 2,2 as a special case meaning no tiling will be used (the initial + * box will be a 2x2 box - only the 4 corners - is the + * idea behind using this value). + * @history 2009-05-22 Debbie A. Cook - Added Resolution method for Sensor (parent) virtual + * @history 2009-06-05 Mackenzie Boyd - Updated samson + * truthdata + * @history 2009-07-08 Janet Barrett - Added RadarGroundMap and RadarSlantRangeMap + * as friends to this class so that they have access to the SetFocalLength + * method. The Radar instrument does not have a focal length and these + * classes need to be able to change the focal length value each time the + * slant range changes. This insures that the detector resolution always + * comes out to the pixel width/height for the Radar instrument. + * @history 2009-07-09 Debbie A. Cook - Set p_hasIntersection in SetImage if + * successful instead of just returning the bool to that other methods + * will know a ground point was successfully set. + * @history 2009-08-03 Debbie A. Cook - Added computation of + * tolerance to support change in Spice class for + * supporting downsizing of Spice tables + * @history 2009-08-14 Debbie A. Cook - Corrected alternate tolerance + * @history 2009-08-17 Debbie A. Cook - Added default tolerance for sky images + * @history 2009-08-19 Janet Barrett - Fixed the GroundAzimuth method so that it + * checks the quadrant that the subspacecraft or subsolar point lies in + * to calculate the correct azimuth value. + * @history 2009-08-28 Steven Lambright - Added GetCameraType method and + * returned enumeration value + * @history 2009-09-23 Tracie Sucharski - Convert negative longitudes coming + * out of reclat when computing azimuths. + * @history 2009-12-14 Steven Lambright - BasicMapping(...) will now populate + * the map Pvl parameter with a valid Pvl + * @history 2010-03-19 Debbie A. Cook - Added members p_ckFrameId and + * p_ckReferenceId and members SetCkFrameId(), SetCkReferenceId(), + * CkFrameId(), and CkReferenceId() needed by the ckwriter application + * @history 2010-03-29 Debbie A. Cook - Modified SetCkFrameid and + * SetCkReferenceFrame to set new bool value p_ckwriteReady to true + * if the kernels have values and false if they don't instead of bombing. + */ + + class Camera : public Isis::Sensor { + public: + // constructors + Camera(Isis::Pvl &lab); + + // destructor + virtual ~Camera(); + + // Methods + bool SetImage(const double sample, const double line); + bool SetUniversalGround(const double latitude, const double longitude); + bool SetUniversalGround(const double latitude, const double longitude, + const double radius); + bool SetRightAscensionDeclination(const double ra, const double dec); + + /** + * Checks to see if the camera object has a projection + * + * @return bool Returns true if it has a projection and false if it does + * not + */ + bool HasProjection() { + return p_projection != 0; + }; + + /** + * Virtual method that checks if the band is independent + * + * @return bool Returns true if the band is independent, and false if it is + * not + */ + virtual bool IsBandIndependent() { + return true; + }; + + /** + * Returns the reference band + * + * @return int Reference Band + */ + int ReferenceBand() const { + return p_referenceBand; + }; + + /** + * Checks to see if the Camera object has a reference band + * + * @return bool Returns true if it has a reference band, and false if it + * does not + */ + bool HasReferenceBand() const { + return p_referenceBand != 0; + }; + + /** + * Virtual method that sets the band number + * + * @param band Band Number + */ + virtual void SetBand(const int band) { + p_childBand = band; + }; + + /** + * Returns the current sample number + * + * @return double Sample Number + */ + inline double Sample() { + return p_childSample; + }; + + /** + * Returns the current band + * + * @return int Band + */ + inline int Band() { + return p_childBand; + } + + /** + * Returns the current line number + * + * @return double Line Number + */ + inline double Line() { + return p_childLine; + }; + + bool GroundRange(double &minlat, double &maxlat, + double &minlon, double &maxlon, Isis::Pvl &pvl); + bool IntersectsLongitudeDomain(Isis::Pvl &pvl); + + double PixelResolution(); + double LineResolution(); + double SampleResolution(); + double DetectorResolution(); + + /** + * Returns the resolution of the camera + * + * @return double pixel resolution + */ + virtual double Resolution() { + return PixelResolution(); + }; + + double LowestImageResolution(); + double HighestImageResolution(); + + void BasicMapping(Isis::Pvl &map); + + /** + * Returns the focal length + * + * @return double Focal Length + */ + inline double FocalLength() const { + return p_focalLength; + }; + + /** + * Returns the pixel pitch + * + * @return double Pixel Pitch + */ + inline double PixelPitch() const { + return p_pixelPitch; + }; + + /** + * Returns the number of samples in the image + * + * @return int Number of Samples + */ + inline int Samples() const { + return p_samples; + }; + + /** + * Returns the number of lines in the image + * + * @return int Number of Lines + */ + inline int Lines() const { + return p_lines; + }; + + /** + * Returns the number of bands in the image + * + * @return int Number of Bands + */ + inline int Bands() const { + return p_bands; + }; + + /** + * Returns the number of lines in the parent alphacube + * + * @return int Number of Lines in parent alphacube + */ + inline int ParentLines() const { + return p_alphaCube->AlphaLines(); + }; + + /** + * Returns the number of samples in the parent alphacube + * + * @return int Number of Samples in the parent alphacube + */ + inline int ParentSamples() const { + return p_alphaCube->AlphaSamples(); + }; + + bool RaDecRange(double &minra, double &maxra, + double &mindec, double &maxdec); + double RaDecResolution(); + + /** + * Returns a pointer to the CameraDistortionMap object + * + * @return CameraDistortionMap* + */ + CameraDistortionMap *DistortionMap() { + return p_distortionMap; + }; + + /** + * Returns a pointer to the CameraFocalPlaneMap object + * + * @return CameraFocalPlaneMap* + */ + CameraFocalPlaneMap *FocalPlaneMap() { + return p_focalPlaneMap; + }; + + /** + * Returns a pointer to the CameraDetectorMap object + * + * @return CameraDetectorMap* + */ + CameraDetectorMap *DetectorMap() { + return p_detectorMap; + }; + + /** + * Returns a pointer to the CameraGroundMap object + * + * @return CameraCGroundMap* + */ + CameraGroundMap *GroundMap() { + return p_groundMap; + }; + + /** + * Returns a pointer to the CameraSkyMap object + * + * @return CameraSkyMap* + */ + CameraSkyMap *SkyMap() { + return p_skyMap; + }; + + /** + * Sets the Distortion Map + * + * @param *map Pointer to a CameraDistortionMap object + */ + void SetDistortionMap(CameraDistortionMap *map); + + /** + * Sets the Focal Plane Map + * + * @param *map Pointer to a CameraFocalPlaneMap object + */ + void SetFocalPlaneMap(CameraFocalPlaneMap *map); + + /** + * Sets the Detector Map + * + * @param *map Pointer to a CameraDetectorMap object + */ + void SetDetectorMap(CameraDetectorMap *map); + + /** + * Sets the Ground Map + * + * @param *map Pointer to a CameraGroundMap object + */ + void SetGroundMap(CameraGroundMap *map); + + /** + * Sets the Sky Map + * + * @param *map Pointer to a CameraSkyMap object + */ + void SetSkyMap(CameraSkyMap *map); + + double NorthAzimuth(); + double SunAzimuth(); + double SpacecraftAzimuth(); + double OffNadirAngle(); + + static double Distance(double lat1, double lon1, + double lat2, double lon2, double radius); + + static double GroundAzimuth(double glat, double glon, double slat, + double slon); + + /** + * Set whether or not the camera should ignore the Projection + * + * @param ignore + */ + void IgnoreProjection(bool ignore) { + p_ignoreProjection = ignore; + }; + + void LoadCache(int cacheSize = 0); + + void GetGeometricTilingHint(int &startSize, int &endSize); + + bool InCube(); + + enum CameraType { + Framing, + PushFrame, + LineScan, + Radar, + Point + }; + + /** + * Returns the type of camera that was created. + * + * @return CameraType + */ + virtual CameraType GetCameraType() const = 0; + + void SetCkFrameId(); + void SetCkReferenceId(); + + /** + * Returns the ck frame id + * + * @return ck frame id + */ + int CkFrameId(); + + /** + * Returns the ck reference id + * + * @return ck reference id + */ + int CkReferenceId(); + + protected: + + /** + * Sets the focal length + * + * @param v Focal Length + */ + void SetFocalLength(double v) { + p_focalLength = v; + }; + + /** + * Sets the pixel pitch + * + * @param v Pixel Pitch + */ + void SetPixelPitch(double v) { + p_pixelPitch = v; + }; + + void SetFocalLength(); + void SetPixelPitch(); + + void SetGeometricTilingHint(int startSize = 128, int endSize = 8); + + // These 2 classes need to be friends of the Camera class because + // of the way Radar works - there is no set focal length for the + // instrument, so the focal length needs to be set each time the + // slant range changes. + friend class RadarGroundMap; + friend class RadarSlantRangeMap; + + private: + double p_focalLength; //! + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 + End_Group + + Group = Archive + DataSetId = MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0 + ProductId = AB-1-024/01 + ProducerId = MGS_MOC_TEAM + ProductCreationTime = 1999-01-15T20:40:59 + SoftwareName = "makepds 1.3" + UploadId = moc_p024_v1.sasf + ImageNumber = 7293-024/01 + ImageKeyId = 56181-024/01 + End_Group + + Group = BandBin + FilterName = RED + OriginalBand = 1 + Center = 0.6134 + Width = 5.0e-02 + End_Group + + Group = Kernels + NaifFrameCode = -94032 + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = $base/kernels/spk/de405.bsp + Instrument = $mgs/kernels/ik/moc20.ti + SpacecraftClock = $mgs/kernels/sclk/MGS_SCLKSCET.00061.tsc + InstrumentAddendum = $mgs/kernels/iak/mocAddendum004.ti + InstrumentPointing = $mgs/kernels/ck/mgs_sc_ab1.bc + InstrumentPosition = $mgs/kernels/spk/mgs_ab1.bsp + ShapeModel = $base/dems/molaMarsPlanetaryRadius0002.cub + CameraVersion = 1 + End_Group + + Group = Radiometry + CalibrationKernel = /usgs/cpkgs/isis3/data/mgs/calibration/moccal.ker.001 + CoefficientFile = $MGS/calibration/mocRedWA.coef + + # Radiometric equation in moccal + # r = (pixel - z + off) / a - g / ex - dc + a = 16.03 + off = 25.0 + ex = 100.0 + z = 27.67658 + dc = 1.33691e-03 + g = 0.123262 + + # Reflectance = r * iof, where iof = (s * s) / w0 + w0 = 3.991 + s = 1.4234269469347 + iof = 0.50767834459028 + End_Group + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679808356 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.766902750622 + MaximumLatitude = 34.44419678224 + MinimumLongitude = 219.7240455337 + MaximumLongitude = 236.18955063342 + UpperLeftCornerX = -480000.0 + UpperLeftCornerY = 2042000.0 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + LineProjectionOffset = -2041.5 + SampleProjectionOffset = -479.5 + End_Group + + Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = History + Name = IsisCube + StartByte = 5832705 + Bytes = 2611 +End_Object + +Group = Mapping + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.763445899478 + MaximumLatitude = 34.449775120271 + MinimumLongitude = 218.13667853438 + MaximumLongitude = 237.62560286587 + PixelResolution = 429.52632181214 + ProjectionName = Sinusoidal +End_Group +End + +FocalLength: 11.2054 +PixelPitch: 0.007 +Samples: 959 +Lines: 1404 +Bands: 1 +ParentLines: 768 +ParentSamples: 640 +**PROGRAMMER ERROR** Camera::RaDecRange can not calculate a right ascension, declination range for projected images which are not projected to sky +**PROGRAMMER ERROR** Camera::RaDecResolution can not calculate a right ascension, declination resolution for projected images which are not projected to sky +Calling Distortion, FocalPlane, Detector, Ground, and Sky Map functions... Done. +Calling IgnoreProjection (false)... + +Testing SetUniversalGround(lat,lon,radius)... +Has intersection 1 +Latitude = 18.221 +Longitude = 226.671 +Radius = 3.41403e+06 +Point = -2225.2 -2358.93 1067.51 + +Test Polar Boundary Conditions + +Basic Mapping: +Group = Mapping + TargetName = Moon + EquatorialRadius = 1737400.0 + PolarRadius = 1737400.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 87.796624435692 + MaximumLatitude = 90.0 + MinimumLongitude = 0.0 + MaximumLongitude = 360.0 + PixelResolution = 193.58289321251 + ProjectionName = Sinusoidal +End_Group +End + +180 Domain Range: +Latitude Range: 87.7966 to 90 +Longitude Range: -180 to 180 diff --git a/isis/src/base/objs/Camera/Camera_Darwin_i386.truth b/isis/src/base/objs/Camera/Camera_Darwin_i386.truth new file mode 100644 index 0000000000000000000000000000000000000000..2b2a835aa7b0cb2c63c68fe92043aa936e937909 --- /dev/null +++ b/isis/src/base/objs/Camera/Camera_Darwin_i386.truth @@ -0,0 +1,223 @@ + +Line: 453, Sample: 534 +Lat: 18.221, Lon: 226.671 +RightAscension: 347.016, Declination: -51.2677 +Camera* from: $ISIS3DATA/mgs/testData/ab102401.lev2.cub + +SetImage (sample, line): 1 + +NorthAzimuth: 269.544 +SunAzimuth: 168.17 +SpacecraftAzimuth: 184.591 +OffNadirAngle: 44.4225 + +SetUniversalGround(lat, lon): 1 +SetRightAscensionDeclination(ra, dec): 1 +HasProjection: 1 +IsBandIndependent called... +ReferenceBand: 0 +HasReferenceBand: 0 +SetBand called, band: 7 +Sample: 408.126 +Line: 962.452 +GroundRange: 0 +IntersectsLongitudeDomain: 0 +PixelResolution: 628.042 +LineResolution: 628.042 +SampleResolution: 628.042 +DetectorResolution: 157.011 +LowestImageResolution: 2047.19 +HighestImageResolution: 429.526 +Calling BasicMapping (pvl)... +BasicMapping PVL: +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 + End_Group + + Group = Pixels + Type = Real + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 + End_Group + + Group = Archive + DataSetId = MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0 + ProductId = AB-1-024/01 + ProducerId = MGS_MOC_TEAM + ProductCreationTime = 1999-01-15T20:40:59 + SoftwareName = "makepds 1.3" + UploadId = moc_p024_v1.sasf + ImageNumber = 7293-024/01 + ImageKeyId = 56181-024/01 + End_Group + + Group = BandBin + FilterName = RED + OriginalBand = 1 + Center = 0.6134 + Width = 5.0e-02 + End_Group + + Group = Kernels + NaifFrameCode = -94032 + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = $base/kernels/spk/de405.bsp + Instrument = $mgs/kernels/ik/moc20.ti + SpacecraftClock = $mgs/kernels/sclk/MGS_SCLKSCET.00061.tsc + InstrumentAddendum = $mgs/kernels/iak/mocAddendum004.ti + InstrumentPointing = $mgs/kernels/ck/mgs_sc_ab1.bc + InstrumentPosition = $mgs/kernels/spk/mgs_ab1.bsp + ShapeModel = $base/dems/molaMarsPlanetaryRadius0002.cub + CameraVersion = 1 + End_Group + + Group = Radiometry + CalibrationKernel = /usgs/cpkgs/isis3/data/mgs/calibration/moccal.ker.001 + CoefficientFile = $MGS/calibration/mocRedWA.coef + + # Radiometric equation in moccal + # r = (pixel - z + off) / a - g / ex - dc + a = 16.03 + off = 25.0 + ex = 100.0 + z = 27.67658 + dc = 1.33691e-03 + g = 0.123262 + + # Reflectance = r * iof, where iof = (s * s) / w0 + w0 = 3.991 + s = 1.4234269469347 + iof = 0.50767834459028 + End_Group + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679808356 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.766902750622 + MaximumLatitude = 34.44419678224 + MinimumLongitude = 219.7240455337 + MaximumLongitude = 236.18955063342 + UpperLeftCornerX = -480000.0 + UpperLeftCornerY = 2042000.0 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + LineProjectionOffset = -2041.5 + SampleProjectionOffset = -479.5 + End_Group + + Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = History + Name = IsisCube + StartByte = 5832705 + Bytes = 2611 +End_Object + +Group = Mapping + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.763445899478 + MaximumLatitude = 34.449775120271 + MinimumLongitude = 218.13667853438 + MaximumLongitude = 237.62560286587 + PixelResolution = 429.52632181214 + ProjectionName = Sinusoidal +End_Group +End + +FocalLength: 11.2054 +PixelPitch: 0.007 +Samples: 959 +Lines: 1404 +Bands: 1 +ParentLines: 768 +ParentSamples: 640 +**PROGRAMMER ERROR** Camera::RaDecRange can not calculate a right ascension, declination range for projected images which are not projected to sky +**PROGRAMMER ERROR** Camera::RaDecResolution can not calculate a right ascension, declination resolution for projected images which are not projected to sky +Calling Distortion, FocalPlane, Detector, Ground, and Sky Map functions... Done. +Calling IgnoreProjection (false)... + +Testing SetUniversalGround(lat,lon,radius)... +Has intersection 1 +Latitude = 18.221 +Longitude = 226.671 +Radius = 3.41403e+06 +Point = -2225.2 -2358.93 1067.51 + +Test Polar Boundary Conditions + +Basic Mapping: +Group = Mapping + TargetName = Moon + EquatorialRadius = 1737400.0 + PolarRadius = 1737400.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 87.796624435692 + MaximumLatitude = 90.0 + MinimumLongitude = 0.0 + MaximumLongitude = 360.0 + PixelResolution = 193.58289321251 + ProjectionName = Sinusoidal +End_Group +End + +180 Domain Range: +Latitude Range: 87.7966 to 90 +Longitude Range: -180 to 180 diff --git a/isis/src/base/objs/Camera/Camera_Darwin_powerpc.truth b/isis/src/base/objs/Camera/Camera_Darwin_powerpc.truth new file mode 100644 index 0000000000000000000000000000000000000000..5b51755c895cdba71b997ab924ec8232b7c8a57b --- /dev/null +++ b/isis/src/base/objs/Camera/Camera_Darwin_powerpc.truth @@ -0,0 +1,223 @@ + +Line: 453, Sample: 534 +Lat: 18.221, Lon: 226.671 +RightAscension: 347.016, Declination: -51.2677 +Camera* from: $ISIS3DATA/mgs/testData/ab102401.lev2.cub + +SetImage (sample, line): 1 + +NorthAzimuth: 269.544 +SunAzimuth: 168.17 +SpacecraftAzimuth: 184.591 +OffNadirAngle: 44.4229 + +SetUniversalGround(lat, lon): 1 +SetRightAscensionDeclination(ra, dec): 1 +HasProjection: 1 +IsBandIndependent called... +ReferenceBand: 0 +HasReferenceBand: 0 +SetBand called, band: 7 +Sample: 408.127 +Line: 962.454 +GroundRange: 0 +IntersectsLongitudeDomain: 0 +PixelResolution: 628.048 +LineResolution: 628.048 +SampleResolution: 628.048 +DetectorResolution: 157.012 +LowestImageResolution: 2047.19 +HighestImageResolution: 429.526 +Calling BasicMapping (pvl)... +BasicMapping PVL: +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 + End_Group + + Group = Pixels + Type = Real + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 + End_Group + + Group = Archive + DataSetId = MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0 + ProductId = AB-1-024/01 + ProducerId = MGS_MOC_TEAM + ProductCreationTime = 1999-01-15T20:40:59 + SoftwareName = "makepds 1.3" + UploadId = moc_p024_v1.sasf + ImageNumber = 7293-024/01 + ImageKeyId = 56181-024/01 + End_Group + + Group = BandBin + FilterName = RED + OriginalBand = 1 + Center = 0.6134 + Width = 5.0e-02 + End_Group + + Group = Kernels + NaifFrameCode = -94032 + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = $base/kernels/spk/de405.bsp + Instrument = $mgs/kernels/ik/moc20.ti + SpacecraftClock = $mgs/kernels/sclk/MGS_SCLKSCET.00061.tsc + InstrumentAddendum = $mgs/kernels/iak/mocAddendum004.ti + InstrumentPointing = $mgs/kernels/ck/mgs_sc_ab1.bc + InstrumentPosition = $mgs/kernels/spk/mgs_ab1.bsp + ShapeModel = $base/dems/molaMarsPlanetaryRadius0002.cub + CameraVersion = 1 + End_Group + + Group = Radiometry + CalibrationKernel = /usgs/cpkgs/isis3/data/mgs/calibration/moccal.ker.001 + CoefficientFile = $MGS/calibration/mocRedWA.coef + + # Radiometric equation in moccal + # r = (pixel - z + off) / a - g / ex - dc + a = 16.03 + off = 25.0 + ex = 100.0 + z = 27.67658 + dc = 1.33691e-03 + g = 0.123262 + + # Reflectance = r * iof, where iof = (s * s) / w0 + w0 = 3.991 + s = 1.4234269469347 + iof = 0.50767834459028 + End_Group + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679808356 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.766902750622 + MaximumLatitude = 34.44419678224 + MinimumLongitude = 219.7240455337 + MaximumLongitude = 236.18955063342 + UpperLeftCornerX = -480000.0 + UpperLeftCornerY = 2042000.0 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + LineProjectionOffset = -2041.5 + SampleProjectionOffset = -479.5 + End_Group + + Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = History + Name = IsisCube + StartByte = 5832705 + Bytes = 2611 +End_Object + +Group = Mapping + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.763445899478 + MaximumLatitude = 34.449775120271 + MinimumLongitude = 218.13667853438 + MaximumLongitude = 237.62560286587 + PixelResolution = 429.52631513749 + ProjectionName = Sinusoidal +End_Group +End + +FocalLength: 11.2054 +PixelPitch: 0.007 +Samples: 959 +Lines: 1404 +Bands: 1 +ParentLines: 768 +ParentSamples: 640 +**PROGRAMMER ERROR** Camera::RaDecRange can not calculate a right ascension, declination range for projected images which are not projected to sky +**PROGRAMMER ERROR** Camera::RaDecResolution can not calculate a right ascension, declination resolution for projected images which are not projected to sky +Calling Distortion, FocalPlane, Detector, Ground, and Sky Map functions... Done. +Calling IgnoreProjection (false)... + +Testing SetUniversalGround(lat,lon,radius)... +Has intersection 1 +Latitude = 18.221 +Longitude = 226.671 +Radius = 3.41403e+06 +Point = -2225.2 -2358.93 1067.51 + +Test Polar Boundary Conditions + +Basic Mapping: +Group = Mapping + TargetName = Moon + EquatorialRadius = 1737400.0 + PolarRadius = 1737400.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 87.796624435692 + MaximumLatitude = 90.0 + MinimumLongitude = 0.0 + MaximumLongitude = 360.0 + PixelResolution = 193.58289321251 + ProjectionName = Sinusoidal +End_Group +End + +180 Domain Range: +Latitude Range: 87.7966 to 90 +Longitude Range: -180 to 180 diff --git a/isis/src/base/objs/Camera/Camera_Linux_i686_RedHat5_4.truth b/isis/src/base/objs/Camera/Camera_Linux_i686_RedHat5_4.truth new file mode 100644 index 0000000000000000000000000000000000000000..a3d727b6b9a49d76853b7c7263973bb8bb9b2063 --- /dev/null +++ b/isis/src/base/objs/Camera/Camera_Linux_i686_RedHat5_4.truth @@ -0,0 +1,223 @@ + +Line: 453, Sample: 534 +Lat: 18.221, Lon: 226.671 +RightAscension: 347.016, Declination: -51.2677 +Camera* from: $ISIS3DATA/mgs/testData/ab102401.lev2.cub + +SetImage (sample, line): 1 + +NorthAzimuth: 269.544 +SunAzimuth: 168.17 +SpacecraftAzimuth: 184.591 +OffNadirAngle: 44.4225 + +SetUniversalGround(lat, lon): 1 +SetRightAscensionDeclination(ra, dec): 1 +HasProjection: 1 +IsBandIndependent called... +ReferenceBand: 0 +HasReferenceBand: 0 +SetBand called, band: 7 +Sample: 408.126 +Line: 962.452 +GroundRange: 0 +IntersectsLongitudeDomain: 0 +PixelResolution: 628.042 +LineResolution: 628.042 +SampleResolution: 628.042 +DetectorResolution: 157.011 +LowestImageResolution: 2047.19 +HighestImageResolution: 429.526 +Calling BasicMapping (pvl)... +BasicMapping PVL: +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 + End_Group + + Group = Pixels + Type = Real + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 + End_Group + + Group = Archive + DataSetId = MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0 + ProductId = AB-1-024/01 + ProducerId = MGS_MOC_TEAM + ProductCreationTime = 1999-01-15T20:40:59 + SoftwareName = "makepds 1.3" + UploadId = moc_p024_v1.sasf + ImageNumber = 7293-024/01 + ImageKeyId = 56181-024/01 + End_Group + + Group = BandBin + FilterName = RED + OriginalBand = 1 + Center = 0.6134 + Width = 5.0e-02 + End_Group + + Group = Kernels + NaifFrameCode = -94032 + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = $base/kernels/spk/de405.bsp + Instrument = $mgs/kernels/ik/moc20.ti + SpacecraftClock = $mgs/kernels/sclk/MGS_SCLKSCET.00061.tsc + InstrumentAddendum = $mgs/kernels/iak/mocAddendum004.ti + InstrumentPointing = $mgs/kernels/ck/mgs_sc_ab1.bc + InstrumentPosition = $mgs/kernels/spk/mgs_ab1.bsp + ShapeModel = $base/dems/molaMarsPlanetaryRadius0002.cub + CameraVersion = 1 + End_Group + + Group = Radiometry + CalibrationKernel = /usgs/cpkgs/isis3/data/mgs/calibration/moccal.ker.001 + CoefficientFile = $MGS/calibration/mocRedWA.coef + + # Radiometric equation in moccal + # r = (pixel - z + off) / a - g / ex - dc + a = 16.03 + off = 25.0 + ex = 100.0 + z = 27.67658 + dc = 1.33691e-03 + g = 0.123262 + + # Reflectance = r * iof, where iof = (s * s) / w0 + w0 = 3.991 + s = 1.4234269469347 + iof = 0.50767834459028 + End_Group + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679808356 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.766902750622 + MaximumLatitude = 34.44419678224 + MinimumLongitude = 219.7240455337 + MaximumLongitude = 236.18955063342 + UpperLeftCornerX = -480000.0 + UpperLeftCornerY = 2042000.0 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + LineProjectionOffset = -2041.5 + SampleProjectionOffset = -479.5 + End_Group + + Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = History + Name = IsisCube + StartByte = 5832705 + Bytes = 2611 +End_Object + +Group = Mapping + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.763445899478 + MaximumLatitude = 34.449775120271 + MinimumLongitude = 218.13667853438 + MaximumLongitude = 237.62560286587 + PixelResolution = 429.52632180311 + ProjectionName = Sinusoidal +End_Group +End + +FocalLength: 11.2054 +PixelPitch: 0.007 +Samples: 959 +Lines: 1404 +Bands: 1 +ParentLines: 768 +ParentSamples: 640 +**PROGRAMMER ERROR** Camera::RaDecRange can not calculate a right ascension, declination range for projected images which are not projected to sky +**PROGRAMMER ERROR** Camera::RaDecResolution can not calculate a right ascension, declination resolution for projected images which are not projected to sky +Calling Distortion, FocalPlane, Detector, Ground, and Sky Map functions... Done. +Calling IgnoreProjection (false)... + +Testing SetUniversalGround(lat,lon,radius)... +Has intersection 1 +Latitude = 18.221 +Longitude = 226.671 +Radius = 3.41403e+06 +Point = -2225.2 -2358.93 1067.51 + +Test Polar Boundary Conditions + +Basic Mapping: +Group = Mapping + TargetName = Moon + EquatorialRadius = 1737400.0 + PolarRadius = 1737400.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 87.796624435692 + MaximumLatitude = 90.0 + MinimumLongitude = 0.0 + MaximumLongitude = 360.0 + PixelResolution = 193.58289321251 + ProjectionName = Sinusoidal +End_Group +End + +180 Domain Range: +Latitude Range: 87.7966 to 90 +Longitude Range: -180 to 180 diff --git a/isis/src/base/objs/Camera/Camera_Linux_i686_RedHat5_5.truth b/isis/src/base/objs/Camera/Camera_Linux_i686_RedHat5_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..a3d727b6b9a49d76853b7c7263973bb8bb9b2063 --- /dev/null +++ b/isis/src/base/objs/Camera/Camera_Linux_i686_RedHat5_5.truth @@ -0,0 +1,223 @@ + +Line: 453, Sample: 534 +Lat: 18.221, Lon: 226.671 +RightAscension: 347.016, Declination: -51.2677 +Camera* from: $ISIS3DATA/mgs/testData/ab102401.lev2.cub + +SetImage (sample, line): 1 + +NorthAzimuth: 269.544 +SunAzimuth: 168.17 +SpacecraftAzimuth: 184.591 +OffNadirAngle: 44.4225 + +SetUniversalGround(lat, lon): 1 +SetRightAscensionDeclination(ra, dec): 1 +HasProjection: 1 +IsBandIndependent called... +ReferenceBand: 0 +HasReferenceBand: 0 +SetBand called, band: 7 +Sample: 408.126 +Line: 962.452 +GroundRange: 0 +IntersectsLongitudeDomain: 0 +PixelResolution: 628.042 +LineResolution: 628.042 +SampleResolution: 628.042 +DetectorResolution: 157.011 +LowestImageResolution: 2047.19 +HighestImageResolution: 429.526 +Calling BasicMapping (pvl)... +BasicMapping PVL: +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 + End_Group + + Group = Pixels + Type = Real + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 + End_Group + + Group = Archive + DataSetId = MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0 + ProductId = AB-1-024/01 + ProducerId = MGS_MOC_TEAM + ProductCreationTime = 1999-01-15T20:40:59 + SoftwareName = "makepds 1.3" + UploadId = moc_p024_v1.sasf + ImageNumber = 7293-024/01 + ImageKeyId = 56181-024/01 + End_Group + + Group = BandBin + FilterName = RED + OriginalBand = 1 + Center = 0.6134 + Width = 5.0e-02 + End_Group + + Group = Kernels + NaifFrameCode = -94032 + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = $base/kernels/spk/de405.bsp + Instrument = $mgs/kernels/ik/moc20.ti + SpacecraftClock = $mgs/kernels/sclk/MGS_SCLKSCET.00061.tsc + InstrumentAddendum = $mgs/kernels/iak/mocAddendum004.ti + InstrumentPointing = $mgs/kernels/ck/mgs_sc_ab1.bc + InstrumentPosition = $mgs/kernels/spk/mgs_ab1.bsp + ShapeModel = $base/dems/molaMarsPlanetaryRadius0002.cub + CameraVersion = 1 + End_Group + + Group = Radiometry + CalibrationKernel = /usgs/cpkgs/isis3/data/mgs/calibration/moccal.ker.001 + CoefficientFile = $MGS/calibration/mocRedWA.coef + + # Radiometric equation in moccal + # r = (pixel - z + off) / a - g / ex - dc + a = 16.03 + off = 25.0 + ex = 100.0 + z = 27.67658 + dc = 1.33691e-03 + g = 0.123262 + + # Reflectance = r * iof, where iof = (s * s) / w0 + w0 = 3.991 + s = 1.4234269469347 + iof = 0.50767834459028 + End_Group + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679808356 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.766902750622 + MaximumLatitude = 34.44419678224 + MinimumLongitude = 219.7240455337 + MaximumLongitude = 236.18955063342 + UpperLeftCornerX = -480000.0 + UpperLeftCornerY = 2042000.0 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + LineProjectionOffset = -2041.5 + SampleProjectionOffset = -479.5 + End_Group + + Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = History + Name = IsisCube + StartByte = 5832705 + Bytes = 2611 +End_Object + +Group = Mapping + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.763445899478 + MaximumLatitude = 34.449775120271 + MinimumLongitude = 218.13667853438 + MaximumLongitude = 237.62560286587 + PixelResolution = 429.52632180311 + ProjectionName = Sinusoidal +End_Group +End + +FocalLength: 11.2054 +PixelPitch: 0.007 +Samples: 959 +Lines: 1404 +Bands: 1 +ParentLines: 768 +ParentSamples: 640 +**PROGRAMMER ERROR** Camera::RaDecRange can not calculate a right ascension, declination range for projected images which are not projected to sky +**PROGRAMMER ERROR** Camera::RaDecResolution can not calculate a right ascension, declination resolution for projected images which are not projected to sky +Calling Distortion, FocalPlane, Detector, Ground, and Sky Map functions... Done. +Calling IgnoreProjection (false)... + +Testing SetUniversalGround(lat,lon,radius)... +Has intersection 1 +Latitude = 18.221 +Longitude = 226.671 +Radius = 3.41403e+06 +Point = -2225.2 -2358.93 1067.51 + +Test Polar Boundary Conditions + +Basic Mapping: +Group = Mapping + TargetName = Moon + EquatorialRadius = 1737400.0 + PolarRadius = 1737400.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 87.796624435692 + MaximumLatitude = 90.0 + MinimumLongitude = 0.0 + MaximumLongitude = 360.0 + PixelResolution = 193.58289321251 + ProjectionName = Sinusoidal +End_Group +End + +180 Domain Range: +Latitude Range: 87.7966 to 90 +Longitude Range: -180 to 180 diff --git a/isis/src/base/objs/Camera/Camera_Linux_i686_SUSE10_1.truth b/isis/src/base/objs/Camera/Camera_Linux_i686_SUSE10_1.truth new file mode 100644 index 0000000000000000000000000000000000000000..a3d727b6b9a49d76853b7c7263973bb8bb9b2063 --- /dev/null +++ b/isis/src/base/objs/Camera/Camera_Linux_i686_SUSE10_1.truth @@ -0,0 +1,223 @@ + +Line: 453, Sample: 534 +Lat: 18.221, Lon: 226.671 +RightAscension: 347.016, Declination: -51.2677 +Camera* from: $ISIS3DATA/mgs/testData/ab102401.lev2.cub + +SetImage (sample, line): 1 + +NorthAzimuth: 269.544 +SunAzimuth: 168.17 +SpacecraftAzimuth: 184.591 +OffNadirAngle: 44.4225 + +SetUniversalGround(lat, lon): 1 +SetRightAscensionDeclination(ra, dec): 1 +HasProjection: 1 +IsBandIndependent called... +ReferenceBand: 0 +HasReferenceBand: 0 +SetBand called, band: 7 +Sample: 408.126 +Line: 962.452 +GroundRange: 0 +IntersectsLongitudeDomain: 0 +PixelResolution: 628.042 +LineResolution: 628.042 +SampleResolution: 628.042 +DetectorResolution: 157.011 +LowestImageResolution: 2047.19 +HighestImageResolution: 429.526 +Calling BasicMapping (pvl)... +BasicMapping PVL: +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 + End_Group + + Group = Pixels + Type = Real + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 + End_Group + + Group = Archive + DataSetId = MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0 + ProductId = AB-1-024/01 + ProducerId = MGS_MOC_TEAM + ProductCreationTime = 1999-01-15T20:40:59 + SoftwareName = "makepds 1.3" + UploadId = moc_p024_v1.sasf + ImageNumber = 7293-024/01 + ImageKeyId = 56181-024/01 + End_Group + + Group = BandBin + FilterName = RED + OriginalBand = 1 + Center = 0.6134 + Width = 5.0e-02 + End_Group + + Group = Kernels + NaifFrameCode = -94032 + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = $base/kernels/spk/de405.bsp + Instrument = $mgs/kernels/ik/moc20.ti + SpacecraftClock = $mgs/kernels/sclk/MGS_SCLKSCET.00061.tsc + InstrumentAddendum = $mgs/kernels/iak/mocAddendum004.ti + InstrumentPointing = $mgs/kernels/ck/mgs_sc_ab1.bc + InstrumentPosition = $mgs/kernels/spk/mgs_ab1.bsp + ShapeModel = $base/dems/molaMarsPlanetaryRadius0002.cub + CameraVersion = 1 + End_Group + + Group = Radiometry + CalibrationKernel = /usgs/cpkgs/isis3/data/mgs/calibration/moccal.ker.001 + CoefficientFile = $MGS/calibration/mocRedWA.coef + + # Radiometric equation in moccal + # r = (pixel - z + off) / a - g / ex - dc + a = 16.03 + off = 25.0 + ex = 100.0 + z = 27.67658 + dc = 1.33691e-03 + g = 0.123262 + + # Reflectance = r * iof, where iof = (s * s) / w0 + w0 = 3.991 + s = 1.4234269469347 + iof = 0.50767834459028 + End_Group + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679808356 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.766902750622 + MaximumLatitude = 34.44419678224 + MinimumLongitude = 219.7240455337 + MaximumLongitude = 236.18955063342 + UpperLeftCornerX = -480000.0 + UpperLeftCornerY = 2042000.0 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + LineProjectionOffset = -2041.5 + SampleProjectionOffset = -479.5 + End_Group + + Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = History + Name = IsisCube + StartByte = 5832705 + Bytes = 2611 +End_Object + +Group = Mapping + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.763445899478 + MaximumLatitude = 34.449775120271 + MinimumLongitude = 218.13667853438 + MaximumLongitude = 237.62560286587 + PixelResolution = 429.52632180311 + ProjectionName = Sinusoidal +End_Group +End + +FocalLength: 11.2054 +PixelPitch: 0.007 +Samples: 959 +Lines: 1404 +Bands: 1 +ParentLines: 768 +ParentSamples: 640 +**PROGRAMMER ERROR** Camera::RaDecRange can not calculate a right ascension, declination range for projected images which are not projected to sky +**PROGRAMMER ERROR** Camera::RaDecResolution can not calculate a right ascension, declination resolution for projected images which are not projected to sky +Calling Distortion, FocalPlane, Detector, Ground, and Sky Map functions... Done. +Calling IgnoreProjection (false)... + +Testing SetUniversalGround(lat,lon,radius)... +Has intersection 1 +Latitude = 18.221 +Longitude = 226.671 +Radius = 3.41403e+06 +Point = -2225.2 -2358.93 1067.51 + +Test Polar Boundary Conditions + +Basic Mapping: +Group = Mapping + TargetName = Moon + EquatorialRadius = 1737400.0 + PolarRadius = 1737400.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 87.796624435692 + MaximumLatitude = 90.0 + MinimumLongitude = 0.0 + MaximumLongitude = 360.0 + PixelResolution = 193.58289321251 + ProjectionName = Sinusoidal +End_Group +End + +180 Domain Range: +Latitude Range: 87.7966 to 90 +Longitude Range: -180 to 180 diff --git a/isis/src/base/objs/Camera/Makefile b/isis/src/base/objs/Camera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..74b53c0949a05f6c488f1f21fa4cdcf5f52bb2f0 --- /dev/null +++ b/isis/src/base/objs/Camera/Makefile @@ -0,0 +1,5 @@ +INCS = Camera.h +SRCS = Camera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Camera/unitTest.cpp b/isis/src/base/objs/Camera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc9e67d590dbf3e7ebb585384b19aa7703533cef --- /dev/null +++ b/isis/src/base/objs/Camera/unitTest.cpp @@ -0,0 +1,162 @@ +#include "Camera.h" +#include "Preference.h" +#include "CameraFactory.h" + +using namespace std; +using namespace Isis; + +class MyCamera : public Isis::Camera { + public: + MyCamera(Isis::Pvl &lab) : Isis::Camera(lab) { } + + bool IsBandIndependent() { + cout << "IsBandIndependent called..." << endl; + return true; + } + + void SetBand(const int band) { + cout << "SetBand called, band: " << band << endl; + } + + virtual CameraType GetCameraType() const { + return Framing; + } +}; + +int main() { + Isis::Preference::Preferences(true); + string inputFile = "$ISIS3DATA/mgs/testData/ab102401.lev2.cub"; + Cube cube; + cube.Open(inputFile); + Camera *c = cube.Camera(); + Pvl &pvl = *cube.Label(); + MyCamera cam(pvl); + + double line = 453.0; + double sample = 534.0; + double lat = 18.221; + double lon = 226.671; + double ra = 347.016; + double dec = -51.2677; + + cout << endl << "Line: " << line << ", Sample: " << sample << endl; + cout << "Lat: " << lat << ", Lon: " << lon << endl; + cout << "RightAscension: " << ra << ", Declination: " << dec << endl; + cout << "Camera* from: " << inputFile << endl << endl; + + cout << "SetImage (sample, line): " << c->SetImage(sample, line) << endl << endl; + + cout << "NorthAzimuth: " << c->NorthAzimuth() << endl; + cout << "SunAzimuth: " << c->SunAzimuth() << endl; + cout << "SpacecraftAzimuth: " << c->SpacecraftAzimuth() << endl; + cout << "OffNadirAngle: " << c->OffNadirAngle() << endl << endl; + + cout << "SetUniversalGround(lat, lon): " + << c->SetUniversalGround(lat, lon) << endl; + cout << "SetRightAscensionDeclination(ra, dec): " + << c->SetRightAscensionDeclination(ra, dec) << endl; + cout << "HasProjection: " << c->HasProjection() << endl; + cam.IsBandIndependent(); + cout << "ReferenceBand: " << c->ReferenceBand() << endl; + cout << "HasReferenceBand: " << c->HasReferenceBand() << endl; + cam.SetBand(7); + cout << "Sample: " << c->Sample() << endl; + cout << "Line: " << c->Line() << endl; + + try { + cout << "GroundRange: " + << c->GroundRange(lat, lat, lon, lon, pvl) << endl; + cout << "IntersectsLongitudeDomain: " + << c->IntersectsLongitudeDomain(pvl) << endl; + } + catch(iException &e) { + e.Clear(); + cout << "No mapping group found, so GroundRange and " << endl + << "IntersectsLongitudeDomain cannot run." << endl; + } + + cout << "PixelResolution: " << c->PixelResolution() << endl; + cout << "LineResolution: " << c->LineResolution() << endl; + cout << "SampleResolution: " << c->SampleResolution() << endl; + cout << "DetectorResolution: " << c->DetectorResolution() << endl; + cout << "LowestImageResolution: " << c->LowestImageResolution() << endl; + cout << "HighestImageResolution: " << c->HighestImageResolution() << endl; + cout << "Calling BasicMapping (pvl)..." << endl; + c->BasicMapping(pvl); + cout << "BasicMapping PVL: " << endl << pvl << endl << endl; + cout << "FocalLength: " << c->FocalLength() << endl; + cout << "PixelPitch: " << c->PixelPitch() << endl; + cout << "Samples: " << c->Samples() << endl; + cout << "Lines: " << c->Lines() << endl; + cout << "Bands: " << c->Bands() << endl; + cout << "ParentLines: " << c->ParentLines() << endl; + cout << "ParentSamples: " << c->ParentSamples() << endl; + + + try { + cout << c->RaDecRange(ra, ra, dec, dec) << endl; + } + catch(iException &e) { + e.Report(false); + e.Clear(); + } + + try { + cout << c->RaDecResolution() << endl; + } + catch(iException &e) { + e.Report(false); + e.Clear(); + } + + cout << "Calling Distortion, FocalPlane, "; + cout << "Detector, Ground, and Sky Map functions... "; + c->DistortionMap(); + c->FocalPlaneMap(); + c->DetectorMap(); + c->GroundMap(); + c->SkyMap(); + cout << "Done." << endl; + + cout << "Calling IgnoreProjection (false)..." << endl; + c->IgnoreProjection(false); + + cout << endl << "Testing SetUniversalGround(lat,lon,radius)..." << endl; + lat = 18.221; + lon = 226.671; + double radius = 3420.; + c->SetUniversalGround(lat, lon, radius); + cout << "Has intersection " << c->HasSurfaceIntersection() << endl; + cout << "Latitude = " << c->UniversalLatitude() << endl; + cout << "Longitude = " << c->UniversalLongitude() << endl; + cout << "Radius = " << c->LocalRadius() << endl; + double p[3]; + c->Coordinate(p); + cout << "Point = " << p[0] << " " << p[1] << " " << p[2] << endl; + + std::cout << std::endl; + std::cout << "Test Polar Boundary Conditions" << std::endl; + inputFile = "$clementine1/testData/lub5992r.292.lev1.phot.cub"; + cube.Close(); + cube.Open(inputFile); + pvl = *cube.Label(); + Camera *cam2 = CameraFactory::Create(pvl); + cube.Close(); + + std::cout << std::endl; + std::cout << "Basic Mapping: " << std::endl; + Pvl camMap; + cam2->BasicMapping(camMap); + std::cout << camMap << std::endl; + + std::cout << std::endl; + std::cout << "180 Domain Range: " << std::endl; + double minlat, maxlat, minlon, maxlon; + camMap.FindGroup("Mapping")["LongitudeDomain"][0] = "180"; + cam2->GroundRange(minlat, maxlat, minlon, maxlon, camMap); + std::cout << "Latitude Range: " << minlat << " to " << maxlat << std::endl; + std::cout << "Longitude Range: " << minlon << " to " << maxlon << std::endl; + + cube.Close(); + delete cam2; +} diff --git a/isis/src/base/objs/CameraDetectorMap/CameraDetectorMap.cpp b/isis/src/base/objs/CameraDetectorMap/CameraDetectorMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39ca2400c92b1ec88ce9a74d4deec3ae8919646b --- /dev/null +++ b/isis/src/base/objs/CameraDetectorMap/CameraDetectorMap.cpp @@ -0,0 +1,88 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2009/04/08 02:32:55 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "CameraDetectorMap.h" + +namespace Isis { + /** Default constructor assumes no summing and starting detector offsets + * + * @param parent Camera that will use this detector map + */ + CameraDetectorMap::CameraDetectorMap(Camera *parent) { + p_camera = parent; + p_startingDetectorSample = 1.0; + p_startingDetectorLine = 1.0; + p_detectorSampleSumming = 1.0; + p_detectorLineSumming = 1.0; + Compute(); + if (parent != 0) { + p_camera->SetDetectorMap(this); + } + } + + /** Compute parent position from a detector coordinate + * + * This method will compute a parent sample/line given a + * detector coordinate + * + * @param sample Sample number in the detector + * @param line Line number in the detector + * + * @return conversion successful + */ + bool CameraDetectorMap::SetDetector(const double sample, const double line) { + p_detectorSample = sample; + p_detectorLine = line; + p_parentSample = (p_detectorSample - p_ss) / p_detectorSampleSumming + 1.0; + p_parentLine = (p_detectorLine - p_sl) / p_detectorLineSumming + 1.0; + return true; + } + + /** Compute detector position from a parent image coordinate + * + * This method will compute the detector position from the parent + * line/sample coordinate + * + * @param sample Sample number in the parent image + * @param line Line number in the parent image + * + * @return conversion successful + */ + bool CameraDetectorMap::SetParent(const double sample, const double line) { + p_parentSample = sample; + p_parentLine = line; + p_detectorSample = (p_parentSample - 1.0) * p_detectorSampleSumming + p_ss; + p_detectorLine = (p_parentLine - 1.0) * p_detectorLineSumming + p_sl; + return true; + } + + //! Compute new offsets whenenver summing or starting sample/lines change + void CameraDetectorMap::Compute() { + p_ss = (p_detectorSampleSumming / 2.0) + 0.5 + + (p_startingDetectorSample - 1.0); + + p_sl = (p_detectorLineSumming / 2.0) + 0.5 + + (p_startingDetectorLine - 1.0); + } + +} + diff --git a/isis/src/base/objs/CameraDetectorMap/CameraDetectorMap.h b/isis/src/base/objs/CameraDetectorMap/CameraDetectorMap.h new file mode 100644 index 0000000000000000000000000000000000000000..3509e308dabd97c3e881e5a7abbe3400bc20af7c --- /dev/null +++ b/isis/src/base/objs/CameraDetectorMap/CameraDetectorMap.h @@ -0,0 +1,155 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/04/08 02:32:55 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the + * USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef CameraDetectorMap_h +#define CameraDetectorMap_h + +#include "Camera.h" + +namespace Isis { + /** Convert between parent image coordinates and detector coordinates + * + * This base class is used to convert between parent dector coordinates + * (sample/line) and detector coordinates for the camera. + * + * @ingroup Camera + * + * @see Camera + * + * @author 2005-02-03 Jeff Anderson + * + * @internal + * @history 2009-04-02 Debbie A. Cook Removed obsolete methods IsXAxisTimeDependent,IsYAxisTimeDependent, + * XAxisDirection, YAxisDirection, SetXAxisDirection, and SetYAxisDirection + * + */ + class CameraDetectorMap { + public: + CameraDetectorMap(Camera *parent=0); + + //! Destructor + virtual ~CameraDetectorMap() {}; + + virtual bool SetParent(const double sample, const double line); + + virtual bool SetDetector(const double sample, const double line); + + //! Return parent sample + inline double ParentSample() const { return p_parentSample; }; + + //! Return parent line + inline double ParentLine() const { return p_parentLine; }; + + //! Return detector sample + inline double DetectorSample() const { return p_detectorSample; }; + + //! Return detector line + inline double DetectorLine() const { return p_detectorLine; }; + + /** Set the starting detector sample + * + * Use this method to specify the starting detector that represents + * the first image sample in the cube. If not set the default is 1. + * + * @param sample Starting detector sample + * + */ + inline void SetStartingDetectorSample (const double sample) { + p_startingDetectorSample = sample; + Compute(); + }; + + /** Set the starting detector line + * + * Use this method to specify the starting detector that represents + * the first image line in the cube. If not set the default is 1. + * + * @param line Starting detector line + * + */ + inline void SetStartingDetectorLine (const double line) { + p_startingDetectorSample = line; + Compute(); + }; + + /** Set sample summing mode + * + * Use this method to specify if detector samples are summed/averaged. + * That is, one image sample represents the average of N detectors. + * If not set the default is 1. + * + * @param summing Sample summing mode + * + */ + inline void SetDetectorSampleSumming (const double summing) { + p_detectorSampleSumming = summing; + Compute(); + }; + + /** Set line summing mode + * + * Use this method to specify if detector lines are summed/averaged. + * That is, one image lines represents the average of N detectors. + * If not set the default is 1. + * + * @param summing Line summing mode + * + */ + inline void SetDetectorLineSumming (const double summing) { + p_detectorLineSumming = summing; + Compute(); + }; + + //! Return scaling factor for computing sample resolution + virtual double SampleScaleFactor () const { + return p_detectorSampleSumming; + }; + + //! Return scaling factor for computing line resolution + virtual double LineScaleFactor () const { + return p_detectorLineSumming; + }; + + //! Return the line collection rate (0 for framing cameras) + virtual double LineRate () const { return 0.0; }; + protected: + Camera *p_camera; + + double p_parentSample; + double p_parentLine; + double p_detectorLine; + double p_detectorSample; + + double p_detectorSampleSumming; + double p_detectorLineSumming; + double p_startingDetectorSample; + double p_startingDetectorLine; + + double p_ss; + double p_sl; + + private: + void Compute(); + }; +}; +#endif diff --git a/isis/src/base/objs/CameraDetectorMap/CameraDetectorMap.truth b/isis/src/base/objs/CameraDetectorMap/CameraDetectorMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..6347fe6d38f458077e14c2efcd5624b000c19da3 --- /dev/null +++ b/isis/src/base/objs/CameraDetectorMap/CameraDetectorMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Camera models. diff --git a/isis/src/base/objs/CameraDetectorMap/Makefile b/isis/src/base/objs/CameraDetectorMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..be89e6d3ab99a92a046ac8db569a276d8510e85b --- /dev/null +++ b/isis/src/base/objs/CameraDetectorMap/Makefile @@ -0,0 +1,5 @@ +INCS = CameraDetectorMap.h +SRCS = CameraDetectorMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CameraDetectorMap/unitTest.cpp b/isis/src/base/objs/CameraDetectorMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..32848e184bde01774fb1dcc2517cfc7cc9c8f441 --- /dev/null +++ b/isis/src/base/objs/CameraDetectorMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/CameraDistortionMap/CameraDistortionMap.cpp b/isis/src/base/objs/CameraDistortionMap/CameraDistortionMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c1c07c30a404f0d1b667afe3288dc2a27608f92 --- /dev/null +++ b/isis/src/base/objs/CameraDistortionMap/CameraDistortionMap.cpp @@ -0,0 +1,189 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/02/21 16:04:33 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "iString.h" +#include "CameraDistortionMap.h" + +namespace Isis { + /** Camera distortion map constructor + * + * Create a camera distortion map. This class maps between distorted + * and undistorted focal plane x/y's. The default mapping is the + * identity, that is, the focal plane x/y and undistorted focal plane + * x/y will be identical. + * + * @param parent the parent camera that will use this distortion map + * @param zDirection the direction of the focal plane Z-axis + * (either 1 or -1) + * + */ + CameraDistortionMap::CameraDistortionMap(Camera *parent, double zDirection) { + p_camera = parent; + p_camera->SetDistortionMap(this); + p_zDirection = zDirection; + } + + /** Load distortion coefficients + * + * This method loads the distortion coefficients from the instrument + * kernel. The coefficients in the NAIF instrument kernel are + * expected to be in the form of: + * + * @code + * INSxxxxx_OD_K = ( coef1, coef2, ..., coefN) + * + * where xxxxx is the instrument code (always a negative number) + * @endcode + * + * These coefficient will be used to convert from focal plane x,y + * to undistorted x,y as follows (add equation here) + * + * @param naifIkCode Code to search for in instrument kernel + * @todo Generalize to read variable number of coefficients + * @todo Add latex equation to the documentation + */ + void CameraDistortionMap::SetDistortion(const int naifIkCode) { + std::string odkkey = "INS" + Isis::iString(naifIkCode) + "_OD_K"; + for (int i = 0; i < 3; ++i) { + p_odk.push_back(p_camera->Spice::GetDouble(odkkey, i)); + } + } + + /** Compute undistorted focal plane x/y + * + * Compute undistorted focal plane x/y given a distorted focal plane x/y. + * This virtual method can be used to apply various techniques for removing + * optical distortion in the focal plane of a camera. The default + * implementation uses a polynomial distortion if the SetDistortion method + * is invoked. After calling this method, you can obtain the undistorted + * x/y via the UndistortedFocalPlaneX and UndistortedFocalPlaneY methods + * + * @param dx distorted focal plane x in millimeters + * @param dy distorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + * @todo Generalize polynomial equation + */ + bool CameraDistortionMap::SetFocalPlane(const double dx, const double dy) { + p_focalPlaneX = dx; + p_focalPlaneY = dy; + + // No coefficients == no distortion + if (p_odk.size() <= 0) { + p_undistortedFocalPlaneX = dx; + p_undistortedFocalPlaneY = dy; + return true; + } + + // Get the distance from the focal plane center and if we are close + // then skip the distortion + double r2 = (dx * dx) + (dy *dy); + if (r2 <= 1.0E-6) { + p_undistortedFocalPlaneX = dx; + p_undistortedFocalPlaneY = dy; + return true; + } + + // Ok we need to apply distortion correction + double drOverR = p_odk[0] + (r2 * (p_odk[1] + (r2 * p_odk[2]))); + p_undistortedFocalPlaneX = dx - (drOverR * dx); + p_undistortedFocalPlaneY = dy - (drOverR * dy); + return true; + } + + /** Compute distorted focal plane x/y + * + * Compute distorted focal plane x/y given an undistorted focal plane x/y. + * This virtual method is used to apply various techniques for adding + * optical distortion in the focal plane of a camera. The default + * implementation of this virtual method uses a polynomial distortion if + * the SetDistortion method was invoked. + * After calling this method, you can obtain the distorted x/y via the + * FocalPlaneX and FocalPlaneY methods + * + * @param ux undistorted focal plane x in millimeters + * @param uy undistorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + * @todo Generalize polynomial equation + * @todo Figure out a better solution for divergence condition + */ + bool CameraDistortionMap::SetUndistortedFocalPlane(const double ux, + const double uy) { + p_undistortedFocalPlaneX = ux; + p_undistortedFocalPlaneY = uy; + + // No coefficients == nodistortion + if (p_odk.size() <= 0) { + p_focalPlaneX = ux; + p_focalPlaneY = uy; + return true; + } + + // Compute the distance from the focal plane center and if we are + // close to the center then no distortion is required + double rp2 = (ux * ux) + (uy * uy); + if (rp2 <= 1.0E-6) { + p_focalPlaneX = ux; + p_focalPlaneY = uy; + return true; + } + + // Ok make the correction, start by computing + // fractional distortion at rp (r-prime) + double rp = sqrt(rp2); + double drOverR = p_odk[0] + (rp2 * (p_odk[1] + (rp2 * p_odk[2]))); + + // Estimate r + double r = rp + (drOverR * rp); + double r_prev, r2_prev; + double tolMilliMeters = p_camera->PixelPitch() / 100.0; + int iteration = 0; + do { + // Don't get in a end-less loop. This algorithm should + // converge quickly. If not then we are probably way outside + // of the focal plane. Just set the distorted position to the + // undistorted position. Also, make sure the focal plane is less + // than 1km, it is unreasonable for it to grow larger than that. + if (iteration >= 15 || r > 1E9) { + drOverR = 0.0; + break; + } + + r_prev = r; + r2_prev = r * r; + + // Compute new fractional distortion: + drOverR = p_odk[0] + (r2_prev * (p_odk[1] + (r2_prev * p_odk[2]))); + + r = rp + (drOverR * r_prev); // Compute new estimate of r + iteration++; + } while (fabs(r - r_prev) > tolMilliMeters); + + p_focalPlaneX = ux / (1.0 - drOverR); + p_focalPlaneY = uy / (1.0 - drOverR); + return true; + } +} + diff --git a/isis/src/base/objs/CameraDistortionMap/CameraDistortionMap.h b/isis/src/base/objs/CameraDistortionMap/CameraDistortionMap.h new file mode 100644 index 0000000000000000000000000000000000000000..5525f337fe2d0f05ed83d55d07d61b1787dfbe85 --- /dev/null +++ b/isis/src/base/objs/CameraDistortionMap/CameraDistortionMap.h @@ -0,0 +1,89 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/02/21 16:04:33 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef CameraDistortionMap_h +#define CameraDistortionMap_h + +#include +#include "Camera.h" + +namespace Isis { + /** Distort/undistort focal plane coordinates + * + * Creates a map for adding/removing optical distortions + * from the focal plane of a camera. + * + * @ingroup Camera + * + * @see Camera + * + * @author 2005-02-01 Jeff Anderson + * + * @history 2008-02-05 Jeff Anderson - Modified to allow for variable focal + * length + * @history 2008-02-21 Steven Lambright - Fixed a problem that resulted in infinities + * and NaNs + * + * @internal + */ + class CameraDistortionMap { + public: + CameraDistortionMap(Camera *parent, double zDirection = 1.0); + + void SetDistortion(const int naifIkCode); + + //! Destructor + virtual ~CameraDistortionMap() {}; + + virtual bool SetFocalPlane(const double dx, const double dy); + + virtual bool SetUndistortedFocalPlane(const double ux, const double uy); + + //! Return distorted focal plane x + inline double FocalPlaneX() const { return p_focalPlaneX; }; + + //! Return distorted focal plane y + inline double FocalPlaneY() const { return p_focalPlaneY; }; + + //! Return undistorted focal plane x + inline double UndistortedFocalPlaneX() const { return p_undistortedFocalPlaneX; }; + + //! Return undistorted focal plane y + inline double UndistortedFocalPlaneY() const { return p_undistortedFocalPlaneY; }; + + //! Return undistorted focal plane z + inline double UndistortedFocalPlaneZ() const + { return p_zDirection * p_camera->FocalLength(); }; + + protected: + Camera *p_camera; + + double p_focalPlaneX; + double p_focalPlaneY; + double p_undistortedFocalPlaneX; + double p_undistortedFocalPlaneY; + double p_zDirection; + + std::vector p_odk; + }; +}; +#endif diff --git a/isis/src/base/objs/CameraDistortionMap/CameraDistortionMap.truth b/isis/src/base/objs/CameraDistortionMap/CameraDistortionMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..6347fe6d38f458077e14c2efcd5624b000c19da3 --- /dev/null +++ b/isis/src/base/objs/CameraDistortionMap/CameraDistortionMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Camera models. diff --git a/isis/src/base/objs/CameraDistortionMap/Makefile b/isis/src/base/objs/CameraDistortionMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4676b6656fa0f4db72c12d28145e8292a230923e --- /dev/null +++ b/isis/src/base/objs/CameraDistortionMap/Makefile @@ -0,0 +1,5 @@ +INCS = CameraDistortionMap.h +SRCS = CameraDistortionMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CameraDistortionMap/unitTest.cpp b/isis/src/base/objs/CameraDistortionMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..32848e184bde01774fb1dcc2517cfc7cc9c8f441 --- /dev/null +++ b/isis/src/base/objs/CameraDistortionMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/CameraFactory/CameraFactory.cpp b/isis/src/base/objs/CameraFactory/CameraFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..540e2068a5b1c464512f39b7eca924d088b3f5d9 --- /dev/null +++ b/isis/src/base/objs/CameraFactory/CameraFactory.cpp @@ -0,0 +1,153 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2009/05/12 20:07:31 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "CameraFactory.h" +#include "Camera.h" +#include "Plugin.h" +#include "iException.h" +#include "Filename.h" + +using namespace std; +namespace Isis { + /** + * Creates a Camera object using Pvl Specifications + * + * @param lab Pvl label containing specifications for the Camera object + * + * @return Camera* The Camera object created + * + * @throws Isis::iException::System - Unsupported camera model, unable to find + * the plugin + * @throws Isis::iException::Camera - Unable to initialize camera model + */ + Camera *CameraFactory::Create(Isis::Pvl &lab) { + // Try to load a plugin file in the current working directory and then + // load the system file + Plugin p; + Filename localFile("Camera.plugin"); + if (localFile.Exists()) p.Read(localFile.Expanded()); + Filename systemFile("$ISISROOT/lib/Camera.plugin"); + if (systemFile.Exists()) p.Read(systemFile.Expanded()); + + try { + // First get the spacecraft and instrument and combine them + PvlGroup &inst = lab.FindGroup("Instrument",Isis::Pvl::Traverse); + iString spacecraft = (string) inst["SpacecraftName"]; + iString name = (string) inst["InstrumentId"]; + spacecraft.UpCase(); + name.UpCase(); + iString group = spacecraft + "/" + name; + group.Remove(" "); + + PvlGroup &kerns = lab.FindGroup("Kernels",Isis::Pvl::Traverse); + // Default version 1 for backwards compatibility (spiceinit'd cubes before camera model versioning) + if(!kerns.HasKeyword("CameraVersion")) { + kerns.AddKeyword(PvlKeyword("CameraVersion", "1")); + } + + int cameraOriginalVersion = (int)kerns["CameraVersion"]; + int cameraNewestVersion = CameraVersion(lab); + + if(cameraOriginalVersion != cameraNewestVersion) { + string msg = "The camera model used to create a camera for this cube is out of date, " \ + "please re-run spiceinit on the file or process with an old Isis version " \ + "that has the correct camera model."; + throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); + } + + // See if we have a camera model plugin + void *ptr; + try { + ptr = p.GetPlugin(group); + } + catch (Isis::iException &e) { + string msg = "Unsupported camera model, unable to find plugin for "; + msg += "SpacecraftName [" + spacecraft + "] with InstrumentId ["; + msg += name + "]"; + throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); + } + + // Now cast that pointer in the proper way + Camera * (*plugin) (Isis::Pvl &lab); + plugin = (Camera * (*)(Isis::Pvl &lab)) ptr; + + // Create the projection as requested + return (*plugin)(lab); + } + catch (Isis::iException &e) { + string message = "Unable to initialize camera model from group [Instrument]"; + throw Isis::iException::Message(Isis::iException::Camera,message,_FILEINFO_); + } + } + + /** + * This looks up the current camera model version from the cube labels. + * + * @param lab Input Cube Labels + * + * @return int Latest Camera Version + */ + int CameraFactory::CameraVersion(Pvl &lab) { + // Try to load a plugin file in the current working directory and then + // load the system file + Pvl cameraPluginGrp; + Filename localFile("Camera.plugin"); + if (localFile.Exists()) cameraPluginGrp.Read(localFile.Expanded()); + Filename systemFile("$ISISROOT/lib/Camera.plugin"); + if (systemFile.Exists()) cameraPluginGrp.Read(systemFile.Expanded()); + + try { + // First get the spacecraft and instrument and combine them + PvlGroup &inst = lab.FindGroup("Instrument", Isis::Pvl::Traverse); + iString spacecraft = (string) inst["SpacecraftName"]; + iString name = (string) inst["InstrumentId"]; + spacecraft.UpCase(); + name.UpCase(); + iString group = spacecraft + "/" + name; + group.Remove(" "); + + PvlGroup plugin; + try { + plugin = cameraPluginGrp.FindGroup(group); + } + catch (iException &e) { + string msg = "Unsupported camera model, unable to find plugin for "; + msg += "SpacecraftName [" + spacecraft + "] with InstrumentId ["; + msg += name + "]"; + throw Isis::iException::Message(Isis::iException::Camera,msg,_FILEINFO_); + } + + if(!plugin.HasKeyword("Version")) { + string msg = "Camera model identified by [" + group + "] does not have a version number"; + throw Isis::iException::Message(Isis::iException::Camera,msg,_FILEINFO_); + } + + return (int)plugin["Version"]; + } + catch (Isis::iException &e) { + string msg = "Unable to locate latest camera model version number from group [Instrument]"; + throw Isis::iException::Message(Isis::iException::Camera,msg,_FILEINFO_); + } + } +} // end namespace isis + + diff --git a/isis/src/base/objs/CameraFactory/CameraFactory.h b/isis/src/base/objs/CameraFactory/CameraFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..c1789fcbbc661e3088e7858b969665c7874b1964 --- /dev/null +++ b/isis/src/base/objs/CameraFactory/CameraFactory.h @@ -0,0 +1,75 @@ +#if !defined(CameraFactory_h) +#define CameraFactory_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2009/05/12 19:31:55 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Camera.h" + +namespace Isis { + class Pvl; + class Camera; +/** + * @brief Initializes a Camera Model + * + * This factory class is used to obtain a Camera Model object given a PVL which + * contains a valid Instrument group. The Instrument group can come from an + * image/cube or a hand-created PVL file. The camera is loaded based on + * information using the SpacecraftName and IntrumentID contained in the + * Instrument group. It is plugin oriented. That is, this class looks in + * $ISISROOT/lib/Camera.plugin to convert the SpacecraftName and IntrumentID + * string into a pointer to the appropriate camera class + * (e.g., Viking, HiRISE, etc.). This allows programmers who develop new + * camera models to create a plugin without the need for recompiling all the + * Isis applications that use camera models. + * + * @ingroup Camera + * + * @author 2005-05-10 Elizabeth Ribelin + * + * @internal + * @history 2005-10-06 Elizabeth Miller - added unitTest.exclude file + * @history 2006-05-17 Elizabeth Miller - changed CameraManager.plugin to + * Camera.plugin + * @history 2009-05-12 Steven Lambright - Added CameraVersion(...) and version + * checking. + */ + + class CameraFactory { + public: + static Camera *Create(Pvl &pvl); + static int CameraVersion(Pvl &pvl); + + private: + /** + * Constructor (Its private, so you cannot use it. Use the Create method + * instead + */ + CameraFactory() {}; + + //! Destroys the CameraFactory object + ~CameraFactory() {}; + }; +}; + +#endif + + diff --git a/isis/src/base/objs/CameraFactory/CameraFactory.truth b/isis/src/base/objs/CameraFactory/CameraFactory.truth new file mode 100644 index 0000000000000000000000000000000000000000..f11379ab1aa5f675f70ac287710823aaa8122d86 --- /dev/null +++ b/isis/src/base/objs/CameraFactory/CameraFactory.truth @@ -0,0 +1,32 @@ +Unit test for CameraFactory +Testing missing Instrument Group ... +**CAMERA ERROR** Unable to locate latest camera model version number from group [Instrument] +**PVL ERROR** Unable to find group [Instrument] +Version: +**CAMERA ERROR** Unable to initialize camera model from group [Instrument] +**PVL ERROR** Unable to find group [Instrument] + +Testing missing spacecraft name ... +**CAMERA ERROR** Unable to locate latest camera model version number from group [Instrument] +**PVL ERROR** Keyword [SpacecraftName] does not exist in [Group = Instrument] +Version: +**CAMERA ERROR** Unable to initialize camera model from group [Instrument] +**PVL ERROR** Keyword [SpacecraftName] does not exist in [Group = Instrument] + +Testing missing instrument id ... +**CAMERA ERROR** Unable to locate latest camera model version number from group [Instrument] +**PVL ERROR** Keyword [InstrumentId] does not exist in [Group = Instrument] +Version: +**CAMERA ERROR** Unable to initialize camera model from group [Instrument] +**PVL ERROR** Keyword [InstrumentId] does not exist in [Group = Instrument] + +Testing unsupported camera mode ... +**CAMERA ERROR** Unable to locate latest camera model version number from group [Instrument] +**CAMERA ERROR** Unsupported camera model, unable to find plugin for SpacecraftName [BOGUS SPACECRAFT] with InstrumentId [BOGUS INSTRUMENT] +**PVL ERROR** Unable to find group [BOGUSSPACECRAFT/BOGUSINSTRUMENT] in file [/usgs/pkgs/isis3nightly/isis/lib/Camera.plugin] +Version: +**CAMERA ERROR** Unable to initialize camera model from group [Instrument] +**CAMERA ERROR** Unable to locate latest camera model version number from group [Instrument] +**CAMERA ERROR** Unsupported camera model, unable to find plugin for SpacecraftName [BOGUS SPACECRAFT] with InstrumentId [BOGUS INSTRUMENT] +**PVL ERROR** Unable to find group [BOGUSSPACECRAFT/BOGUSINSTRUMENT] in file [/usgs/pkgs/isis3nightly/isis/lib/Camera.plugin] + diff --git a/isis/src/base/objs/CameraFactory/Makefile b/isis/src/base/objs/CameraFactory/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8c4d3f0031f44666091c584044fc430dfc65aaa1 --- /dev/null +++ b/isis/src/base/objs/CameraFactory/Makefile @@ -0,0 +1,5 @@ +INCS = CameraFactory.h +SRCS = CameraFactory.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CameraFactory/unitTest.cpp b/isis/src/base/objs/CameraFactory/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3028019bb74de6895a4d98a0293140f4ec0143bb --- /dev/null +++ b/isis/src/base/objs/CameraFactory/unitTest.cpp @@ -0,0 +1,56 @@ +#include +#include "iException.h" +#include "CameraFactory.h" +#include "Pvl.h" +#include "Preference.h" + +using namespace std; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + void doit(Isis::Pvl &lab); + + cout << "Unit test for CameraFactory" << endl; + cout << "Testing missing Instrument Group ..." << endl; + Isis::Pvl lab; + doit(lab); + + lab.AddGroup(Isis::PvlGroup("Kernels")); + + cout << "Testing missing spacecraft name ..." << endl; + lab.AddGroup(Isis::PvlGroup("Instrument")); + doit(lab); + + cout << "Testing missing instrument id ..." << endl; + Isis::PvlGroup &inst = lab.FindGroup("Instrument"); + inst += Isis::PvlKeyword("SpacecraftName", "Bogus Spacecraft"); + doit(lab); + + cout << "Testing unsupported camera mode ..." << endl; + inst += Isis::PvlKeyword("InstrumentId", "Bogus Instrument"); + doit(lab); +} + +void doit(Isis::Pvl &lab) { + try { + std::cout << "Version: "; + std::cout << Isis::CameraFactory::CameraVersion(lab) << std::endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl; + + try { + Isis::CameraFactory::Create(lab); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl; +} + + + diff --git a/isis/src/base/objs/CameraFactory/unitTest.exclude b/isis/src/base/objs/CameraFactory/unitTest.exclude new file mode 100644 index 0000000000000000000000000000000000000000..adda8c712a67e0bdd072082ced6d390c58ba306c --- /dev/null +++ b/isis/src/base/objs/CameraFactory/unitTest.exclude @@ -0,0 +1 @@ +Camera.plugin diff --git a/isis/src/base/objs/CameraFocalPlaneMap/CameraFocalPlaneMap.cpp b/isis/src/base/objs/CameraFocalPlaneMap/CameraFocalPlaneMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c7396790fd7c8cac53812048bb12541ebcf7c914 --- /dev/null +++ b/isis/src/base/objs/CameraFocalPlaneMap/CameraFocalPlaneMap.cpp @@ -0,0 +1,190 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2008/06/17 16:10:40 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "Spice.h" +#include "CameraFocalPlaneMap.h" +#include + +namespace Isis { + /** Construct mapping between detectors and focal plane x/y + * + * @param parent parent camera that will use this map + * @param naifIkCode code of the naif instrument for reading coefficients + * + */ + CameraFocalPlaneMap::CameraFocalPlaneMap(Camera *parent, const int naifIkCode) { + Init(parent,naifIkCode); + } + + /** Construct mapping between detectors and focal plane x/y + * + * @param naifIkCode code of the naif instrument for reading coefficients + * + */ + CameraFocalPlaneMap::CameraFocalPlaneMap(const int naifIkCode) { + Init(0,naifIkCode); + } + + void CameraFocalPlaneMap::Init(Camera *parent, const int naifIkCode) { + p_detectorSampleOrigin = 0.0; + p_detectorLineOrigin = 0.0; + p_detectorSampleOffset = 0.0; + p_detectorLineOffset = 0.0; + p_camera = parent; + + if (naifIkCode != 0) { + std::string xkey = "INS" + Isis::iString(naifIkCode) + "_TRANSX"; + std::string ykey = "INS" + Isis::iString(naifIkCode) + "_TRANSY"; + std::string ixkey = "INS" + Isis::iString(naifIkCode) + "_ITRANSS"; + std::string iykey = "INS" + Isis::iString(naifIkCode) + "_ITRANSL"; + for (int i = 0; i < 3; ++i) { + p_transx[i] = Spice::GetDouble(xkey, i); + p_transy[i] = Spice::GetDouble(ykey, i); + p_itranss[i] = Spice::GetDouble(ixkey, i); + p_itransl[i] = Spice::GetDouble(iykey, i); + } + } + else { + std::string xkey = "IDEAL_TRANSX"; + std::string ykey = "IDEAL_TRANSY"; + std::string ixkey = "IDEAL_TRANSS"; + std::string iykey = "IDEAL_TRANSL"; + for (int i = 0; i < 3; ++i) { + p_transx[i] = Spice::GetDouble(xkey, i); + p_transy[i] = Spice::GetDouble(ykey, i); + p_itranss[i] = Spice::GetDouble(ixkey, i); + p_itransl[i] = Spice::GetDouble(iykey, i); + } + } + + if (parent != 0) { + p_camera->SetFocalPlaneMap(this); + } + } + + /** Compute detector position from focal plane coordinate + * + * This method will compute both the centered and normal detector position + * given a distorted focal plane coordinate. + * + * @param dx distorted focal plane x in millimeters + * @param dy distorted focal plane y in millimeters + * + * @return conversion was successful + */ + bool CameraFocalPlaneMap::SetFocalPlane(const double dx, const double dy) { + p_focalPlaneX = dx; + p_focalPlaneY = dy; + + p_centeredDetectorSample = p_itranss[0] + (p_itranss[1] * dx) + + (p_itranss[2] * dy); + p_centeredDetectorLine = p_itransl[0] + (p_itransl[1] * dx) + + (p_itransl[2] * dy); + ComputeUncentered(); + return true; + } + + /** Compute distorted focal plane coordinate from detector position + * + * This method will compute both the distorted focal plane x/y and centered + * detector position given a detector position + * + * @param sample undistorted focal plane x in millimeters + * @param line undistorted focal plane y in millimeters + * + * @return conversion was successful + */ + bool CameraFocalPlaneMap::SetDetector(const double sample, const double line) { + p_detectorSample = sample; + p_detectorLine = line; + ComputeCentered(); + p_focalPlaneX = p_transx[0] + (p_transx[1] * p_centeredDetectorSample) + + (p_transx[2] * p_centeredDetectorLine) ; + p_focalPlaneY = p_transy[0] + (p_transy[1] * p_centeredDetectorSample) + + (p_transy[2] * p_centeredDetectorLine) ; + return true; + } + + /** Return the focal plane x dependency variable + * + * This method returns the image variable (sample or line) on + * which the focal plane x depends. + * + * @return dependency variable + */ +// CameraFocalPlaneMap::FocalPlaneXDependencyType CameraFocalPlaneMap::FocalPlaneXDependency() { + int CameraFocalPlaneMap::FocalPlaneXDependency() { + if (p_transx[1] > p_transx[2]) { + return Sample; + } + else { + return Line; + } + } + + + /** Return the sign of the p_transx coefficient with the greatest magnitude + * + * This method returns a +1. or -1. based on the sign of the p_transx + * coefficient with the greatest magnitude. Only p_transx[1] and + * p_transx[2] are compared since p_transx[0] is used as a constant in the + * affine transformation. + * + * @return sign of most significant coefficient + */ + double CameraFocalPlaneMap::SignMostSigX() { + double magCoef1 = fabs(p_transx[1]); + double magCoef2 = fabs(p_transx[2]); + + if (magCoef1 > magCoef2) { + return (magCoef1/p_transx[1]); + } + else { + return (magCoef2/p_transx[2]); + } + } + + + + /** Return the sign of the p_transy coefficient with the greatest magnitude + * + * This method returns a +1 or -1 based on the sign of the p_transy + * coefficient with the greatest magnitude. Only p_transy[1] and + * p_transy[2] are compared since p_transy[0] is used as a constant in the + * affine transformation. + * + * @return sign of most significant coefficient + */ + double CameraFocalPlaneMap::SignMostSigY() { + double magCoef1 = fabs(p_transy[1]); + double magCoef2 = fabs(p_transy[2]); + + if (magCoef1 > magCoef2) { + return (magCoef1/p_transy[1]); + } + else { + return (magCoef2/p_transy[2]); + } + } + +} + diff --git a/isis/src/base/objs/CameraFocalPlaneMap/CameraFocalPlaneMap.h b/isis/src/base/objs/CameraFocalPlaneMap/CameraFocalPlaneMap.h new file mode 100644 index 0000000000000000000000000000000000000000..408fa6dd5fac52f577c25db10d0048adc32e9c9c --- /dev/null +++ b/isis/src/base/objs/CameraFocalPlaneMap/CameraFocalPlaneMap.h @@ -0,0 +1,193 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2007/02/13 23:03:54 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef CameraFocalPlaneMap_h +#define CameraFocalPlaneMap_h + +#include "Camera.h" + +namespace Isis { + /** Convert between distorted focal plane and detector coordinates + * + * This base class is used to convert between distorted focal plane + * coordinates (x/y) in millimeters and detector coordinates in + * pixels. The class expects to find a set of coefficients in the + * naif instrument (or instrument addendum) kernel that describe the + * transform from detector to focal plane and vice versa. The transform + * from detector to focal plane is: + * + * @code + * x = transx[0] + sample * transx[1] + line * transx[2]; + * y = transy[0] + sample * transy[1] + line * transy[2]; + * + * where, transx and transy are the coefficients from the naif kernel. + * The should be in the form of: + * + * INSxxxxxx_TRANSX = ( a, b, c) + * INSxxxxxx_TRANSY = ( d, e, f) + * + * where, xxxxxx is the NAIF instrument id code. + * @endcode + * + * Likewise, the inverse transform is: + * + * @code + * samp = itranss[0] + x * itranss[1] + y * itranss[2]; + * line = itransl[0] + x * itransl[1] + y * itransl[2]; + * + * where, itranss and itranss are the coefficients from the naif kernel. + * The should be in the form of: + * + * INSxxxxxx_ITRANSS = ( a, b, c) + * INSxxxxxx_ITRANSL = ( d, e, f) + * + * where, xxxxxx is the NAIF instrument id code. + * @endcode + * + * @ingroup Camera + * + * @author Jeff Anderson 2005-02-05 + * + * @see Camera + * + * @internal + * @history 2007-02-13 Debbie A. Cook - Added methods SignMostSigX() and + * SignMostSigY() + * + */ + class CameraFocalPlaneMap { + public: + CameraFocalPlaneMap(Camera *parent, const int naifIkCode); + CameraFocalPlaneMap(const int naifIkCode); + + //! Destructor + virtual ~CameraFocalPlaneMap() {}; + + virtual bool SetDetector(const double sample, const double line); + + virtual bool SetFocalPlane(const double dx, const double dy); + + //! Return distorted focal plane x + inline double FocalPlaneX() const { return p_focalPlaneX; }; + + //! Return distorted focal plane y + inline double FocalPlaneY() const { return p_focalPlaneY; }; + + //! Return detector sample + inline double DetectorSample() const { return p_detectorSample; }; + + //! Return detector line + inline double DetectorLine() const { return p_detectorLine; }; + + //! Return centered detector sample + inline double CenteredDetectorSample() const { return p_centeredDetectorSample; }; + + //! Return centered detector line + inline double CenteredDetectorLine() const { return p_centeredDetectorLine; }; + + /** Set the detector origin + * + * This is used to set the origin of the detector. Typically the middle + * of the detector. For example, a 512x512 dectector would have the + * origin at (256.5,256.5). If not set both are 0. + * + * @param sample detector sample at the origin + * @param line detector line at the origin + */ + inline void SetDetectorOrigin (const double sample, const double line) { + p_detectorSampleOrigin = sample; + p_detectorLineOrigin = line; + }; + + //! Return detector line origin + inline double DetectorLineOrigin () const { return p_detectorLineOrigin; }; + + //! Return detector sample origin + inline double DetectorSampleOrigin () const { return p_detectorSampleOrigin; }; + + /** Set the detector offset + * + * This is used to set the offset between the detector origin and + * the average location in detector pixels where the image is being + * viewed. If not set the offset are both 0.0 + * + * @param sampleOffset sample offset in pixels + * @param lineOffset sample offset in lines + */ + inline void SetDetectorOffset (const double sampleOffset, + const double lineOffset) { + p_detectorSampleOffset = sampleOffset; + p_detectorLineOffset = lineOffset; + }; + + //! Return detector line offset + inline double DetectorLineOffset () const { return p_detectorLineOffset; }; + + //! Return detector sample offset + inline double DetectorSampleOffset () const { return p_detectorSampleOffset; }; + + enum FocalPlaneXDependencyType { + Sample=1, + Line=2 + }; + +// FocalPlaneXDependencyType FocalPlaneXDependency(); + int FocalPlaneXDependency(); + double SignMostSigX(); + double SignMostSigY(); + + protected: + //! Convenience method to center detector origin (use when inheriting) + inline void ComputeCentered() { + p_centeredDetectorSample = p_detectorSample - p_detectorSampleOrigin; + p_centeredDetectorLine = p_detectorLine - p_detectorLineOrigin; + } + + //! Convenience method to center detector origin (use when inheriting) + inline void ComputeUncentered() { + p_detectorSample = p_centeredDetectorSample + p_detectorSampleOrigin; + p_detectorLine = p_centeredDetectorLine + p_detectorLineOrigin; + } + + Camera *p_camera; + + double p_detectorLineOrigin; + double p_detectorSampleOrigin; + + double p_focalPlaneX; + double p_focalPlaneY; + double p_detectorLine; + double p_detectorSample; + double p_centeredDetectorSample; + double p_centeredDetectorLine; + + double p_detectorLineOffset; + double p_detectorSampleOffset; + + double p_transx[3],p_transy[3]; + double p_itranss[3],p_itransl[3]; + + private: + void Init (Camera *parent, const int naifIkCode); + }; +}; +#endif diff --git a/isis/src/base/objs/CameraFocalPlaneMap/CameraFocalPlaneMap.truth b/isis/src/base/objs/CameraFocalPlaneMap/CameraFocalPlaneMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..6347fe6d38f458077e14c2efcd5624b000c19da3 --- /dev/null +++ b/isis/src/base/objs/CameraFocalPlaneMap/CameraFocalPlaneMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Camera models. diff --git a/isis/src/base/objs/CameraFocalPlaneMap/Makefile b/isis/src/base/objs/CameraFocalPlaneMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0151511b93bfeabbde7003aeb6cf48d09b4383fe --- /dev/null +++ b/isis/src/base/objs/CameraFocalPlaneMap/Makefile @@ -0,0 +1,5 @@ +INCS = CameraFocalPlaneMap.h +SRCS = CameraFocalPlaneMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CameraFocalPlaneMap/unitTest.cpp b/isis/src/base/objs/CameraFocalPlaneMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..32848e184bde01774fb1dcc2517cfc7cc9c8f441 --- /dev/null +++ b/isis/src/base/objs/CameraFocalPlaneMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/CameraGroundMap/CameraGroundMap.cpp b/isis/src/base/objs/CameraGroundMap/CameraGroundMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f79c7bdc22fc8e22a6b1cb8fe38be1bcda7670e --- /dev/null +++ b/isis/src/base/objs/CameraGroundMap/CameraGroundMap.cpp @@ -0,0 +1,335 @@ +/** + * @file + * $Revision: 1.7 $ + * $Date: 2010/03/27 06:36:41 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "CameraGroundMap.h" +#include "NaifStatus.h" + +namespace Isis { + CameraGroundMap::CameraGroundMap(Camera *parent) { + p_camera = parent; + p_camera->SetGroundMap(this); + } + + /** Compute ground position from focal plane coordinate + * + * This method will compute the ground position given an + * undistorted focal plane coordinate. Note that the latitude/longitude + * value can be obtained from the camera class passed into the constructor. + * + * @param ux distorted focal plane x in millimeters + * @param uy distorted focal plane y in millimeters + * @param uz distorted focal plane z in millimeters + * + * @return conversion was successful + */ + bool CameraGroundMap::SetFocalPlane(const double ux, const double uy, + double uz) { + NaifStatus::CheckErrors(); + + SpiceDouble lookC[3]; + lookC[0] = ux; + lookC[1] = uy; + lookC[2] = uz; + + SpiceDouble unitLookC[3]; + vhat_c(lookC,unitLookC); + + NaifStatus::CheckErrors(); + + return p_camera->SetLookDirection(unitLookC); + } + + /** Compute undistorted focal plane coordinate from ground position + * + * @param lat planetocentric latitude in degrees + * @param lon planetocentric longitude in degrees + * + * @return conversion was successful + */ + bool CameraGroundMap::SetGround(const double lat, const double lon) { + if (p_camera->Sensor::SetUniversalGround (lat,lon)) { + LookCtoFocalPlaneXY(); + return true; + } + return false; + } + + //! Compute undistorted focal plane coordinate from camera look vector + void CameraGroundMap::LookCtoFocalPlaneXY(){ + double lookC[3]; + p_camera->Sensor::LookDirection(lookC); + double scale = p_camera->FocalLength() / lookC[2]; + p_focalPlaneX = lookC[0] * scale; + p_focalPlaneY = lookC[1] * scale; + } + + /** Compute undistorted focal plane coordinate from ground position that includes a local radius + * + * @param lat planetocentric latitude in degrees + * @param lon planetocentric longitude in degrees + * @param radius local radius in meters + * + * @return conversion was successful + */ + bool CameraGroundMap::SetGround(const double lat, const double lon, const double radius) { + if (p_camera->Sensor::SetUniversalGround (lat,lon, radius)) { + LookCtoFocalPlaneXY(); + return true; + } + return false; + } + + /** Compute undistorted focal plane coordinate from ground position using current Spice from SetImage call + * + * This method will compute the undistorted focal plane coordinate for + * a ground position, using the current Spice settings (time and kernels) + * without resetting the current point values for lat/lon/radius/x/y. The + * class value for p_look is set by this method. + * + * @param lat planetocentric latitude in degrees + * @param lon planetocentric longitude in degrees + * @param radius local radius in m + * + * @return conversion was successful + */ + bool CameraGroundMap::GetXY(const double lat, const double lon, const double radius, + double *cudx, double *cudy) { + + // Check for Sky images + if ( p_camera->IsSky() ) { + return false; + } + + // Should a check be added to make sure SetImage has been called??? + + // Compute the look vector in body-fixed coordinates + double pB[3]; // Point on surface + latrec_c( radius/1000.0, lon*Isis::PI/180.0, lat*Isis::PI/180.0, pB); + + // Get spacecraft vector in body-fixed coordinates + SpiceRotation *bodyRot = p_camera->BodyRotation(); + SpiceRotation *instRot = p_camera->InstrumentRotation(); + std::vector sB = bodyRot->ReferenceVector(p_camera->InstrumentPosition()->Coordinate()); + std::vector lookB(3); + for (int ic=0; ic<3; ic++) lookB[ic] = pB[ic] - sB[ic]; + + // Check for point on back of planet by checking to see if surface point is viewable (test emission angle) + // During iterations, we may not want to do the back of planet test??? + double upsB[3],upB[3],dist; + vminus_c ( (SpiceDouble *) &lookB[0], upsB); + unorm_c (upsB, upsB, &dist); + unorm_c (pB, upB, &dist); + double angle = vdot_c(upB, upsB); + double emission; + if (angle > 1) { + emission = 0; + } + else if (angle < -1) { + emission = 180.; + } + else { + emission = acos (angle) * 180.0 / Isis::PI; + } + if (fabs(emission) > 90.) return false; + + // Get the look vector in the camera frame and the instrument rotation + p_lookJ.resize(3); + p_lookJ = p_camera->BodyRotation()->J2000Vector( lookB ); + std::vector lookC(3); + lookC = instRot->ReferenceVector( p_lookJ); + + // Get focal length with direction for scaling coordinates + double fl = p_camera->DistortionMap()->UndistortedFocalPlaneZ(); + + *cudx = lookC[0] * fl / lookC[2]; + *cudy = lookC[1] * fl / lookC[2]; + + return true; + } + + /** Compute derivative w/r to position of focal plane coordinate from ground position using current Spice from SetImage call + * + * This method will compute the derivative of the undistorted focal plane coordinate for + * a ground position with respect to a spacecraft position coordinate, using the current + * Spice settings (time and kernels) without resetting the current point values for lat/lon/radius/x/y. + * + * @param varType enumerated partial type (definitions in SpicePosition) + * @param coefIndex coefficient index of fit polynomial + * @param *dx pointer to partial derivative of undistorted focal plane x + * @param *dy pointer to partial derivative of undistorted focal plane y + * + * @return conversion was successful + */ + // also have a GetDxyDorientation and a GetDxyDpoint + bool CameraGroundMap::GetdXYdPosition(const SpicePosition::PartialType varType, int coefIndex, + double *dx, double *dy) { + + // TODO add a check to make sure p_lookJ has been set + + // Get directional fl for scaling coordinates + double fl = p_camera->DistortionMap()->UndistortedFocalPlaneZ(); + + // Rotate look vector into camera frame + SpiceRotation *instRot = p_camera->InstrumentRotation(); + std::vector lookC(3); + lookC = instRot->ReferenceVector( p_lookJ ); + + SpicePosition *instPos = p_camera->InstrumentPosition(); + + std::vector d_lookJ = instPos->CoordinatePartial (varType, coefIndex); + for (int j=0; j<3; j++) d_lookJ[j] *= -1.0; + std::vector d_lookC = instRot->ReferenceVector(d_lookJ); + *dx = fl * DQuotient(lookC, d_lookC, 0); + *dy = fl * DQuotient(lookC, d_lookC, 1); + return true; + } + + /** Compute derivative of focal plane coordinate w/r to orientation from ground position using current Spice from SetImage call + * + * This method will compute the derivative of the undistorted focal plane coordinate for + * a ground position with respect to the instrument orientation, using the current Spice + * settings (time and kernels) without resetting the current point values for lat/lon/radius/x/y. + * + * @param varType enumerated partial type (definitions in SpicePosition) + * @param coefIndex coefficient index of fit polynomial + * @param *dx pointer to partial derivative of undistorted focal plane x + * @param *dy pointer to partial derivative of undistorted focal plane y + * + * @return conversion was successful + */ + // also have a GetDxyDorientation and a GetDxyDpoint + bool CameraGroundMap::GetdXYdOrientation(const SpiceRotation::PartialType varType, int coefIndex, + double *dx, double *dy) { + + // TODO add a check to make sure p_lookJ has been set + + // Get directional fl for scaling coordinates + double fl = p_camera->DistortionMap()->UndistortedFocalPlaneZ(); + + // Rotate look vector into camera frame + SpiceRotation *instRot = p_camera->InstrumentRotation(); + std::vector lookC(3); + lookC = instRot->ReferenceVector( p_lookJ ); + + std::vector d_lookC = instRot->ToReferencePartial(p_lookJ, varType, coefIndex); + *dx = fl * DQuotient(lookC, d_lookC, 0); + *dy = fl * DQuotient(lookC, d_lookC, 1); + return true; + } + + /** Compute derivative of focal plane coordinate w/r to ground point from ground position using current Spice from SetImage call + * + * This method will compute the derivative of the undistorted focal plane coordinate for + * a ground position with respect to lat, lon, or radius, using the current Spice settings (time and kernels) + * without resetting the current point values for lat/lon/radius/x/y. + * + * @param varType enumerated partial type (definitions in SpicePosition) + * @param coefIndex coefficient index of fit polynomial + * @param *dx pointer to partial derivative of undistorted focal plane x + * @param *dy pointer to partial derivative of undistorted focal plane y + * + * @return conversion was successful + */ + bool CameraGroundMap::GetdXYdPoint(double lat, double lon, double radius, PartialType wrt, + double *dx, double *dy) { + + // TODO add a check to make sure p_lookJ has been set + + // Get directional fl for scaling coordinates + double fl = p_camera->DistortionMap()->UndistortedFocalPlaneZ(); + + // Rotate look vector into camera frame + SpiceRotation *instRot = p_camera->InstrumentRotation(); + std::vector lookC(3); + lookC = instRot->ReferenceVector( p_lookJ ); + + // Get the partial derivative of the surface point + std::vector d_lookB = PointPartial(lat, lon, radius, wrt); + + SpiceRotation *bodyRot = p_camera->BodyRotation(); + std::vector d_lookJ = bodyRot->J2000Vector(d_lookB); + std::vector d_lookC = instRot->ReferenceVector(d_lookJ); + + *dx = fl * DQuotient(lookC, d_lookC, 0); + *dy = fl * DQuotient(lookC, d_lookC, 1); + return true; + } + + + /** Compute derivative with respect to indicated variable of conversion function from lat/lon/rad to rectangular coord + * + * @param lat planetocentric latitude in degrees + * @param lon planetocentric longitude in degrees + * @param radius local radius in meters + * @param wrt take derivative with respect to this value + * + * @return partialDerivative + */ + std::vector CameraGroundMap::PointPartial(double lat, double lon, double radius, PartialType wrt) { + double rlat = lat * Isis::PI / 180.0; + double rlon = lon * Isis::PI / 180.0; + double sinLon = sin(rlon); + double cosLon = cos(rlon); + double sinLat = sin(rlat); + double cosLat = cos(rlat); + double radkm = radius / 1000.0; + + std::vector v(3); + if (wrt == WRT_Latitude) { + v[0] = -radkm * sinLat * cosLon; + v[1] = -radkm * sinLon * sinLat; + v[2] = radkm * cosLat; + } + else if (wrt == WRT_Longitude) { + v[0] = -radkm * cosLat * sinLon; + v[1] = radkm * cosLat * cosLon; + v[2] = 0.0; + } + else { + v[0] = cosLon * cosLat; + v[1] = sinLon * cosLat; + v[2] = sinLat; + } + + return v; + } + + + /** + * Convenience method for quotient rule applied to look vector + * + * This method will compute the derivative of the following function + * (coordinate x or y) / (coordinate z) + * + * @param look look vector in camera frame + * @param dlook derivative of look vector in camera frame + * @param index vector value to differentiate + * + * @return derivative + */ + double CameraGroundMap::DQuotient(std::vector &look, + std::vector &dlook, + int index) { + return (look[2] * dlook[index] - look[index] * dlook[2]) / + (look[2] * look[2]); + } +} diff --git a/isis/src/base/objs/CameraGroundMap/CameraGroundMap.h b/isis/src/base/objs/CameraGroundMap/CameraGroundMap.h new file mode 100644 index 0000000000000000000000000000000000000000..4f5f3716bb5b0515bc16c2a32d3f74825c3a4d64 --- /dev/null +++ b/isis/src/base/objs/CameraGroundMap/CameraGroundMap.h @@ -0,0 +1,106 @@ +/** + * @file + * $Revision: 1.7 $ + * $Date: 2010/03/27 06:36:41 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef CameraGroundMap_h +#define CameraGroundMap_h + +#include "Camera.h" +#include "CameraDistortionMap.h" +#include "SpicePosition.h" + +namespace Isis { + /** Convert between undistorted focal plane and ground coordinates + * + * This base class is used to convert between undistorted focal plane + * coordinates (x/y) in millimeters and ground coordinates lat/lon. + * This class handles the case of framing cameras. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2005-02-08 Jeff Anderson + * Original version + * + * @history 2005-11-16 Jeff Anderson Fixed bug in SetGround not setting the + * proper boolean return value + * @history 2007-06-11 Debbie A. Cook - Added overloaded method SetGround that + * includes a radius argument and the method + * LookCtoFocalPlaneXY() to handle the common functionality + * between the SetGround methods + * @history 2008-07-14 Steven Lambright Added NaifStatus calls + * @history 2009-10-14 Debbie A. Cook Added new virtual method GetXY(lat,lon,radius, lookJ) + * @history 2009-11-27 Debbie A. Cook Modified virtual method GetXY(lat,lon,radius,lookJ,cudx,cudy) + * @history 2010-03-19 Debbie A. Cook Modified virtual method to return cudx and cudy; added + * methods GetdXYdPosition, GetdXYdOrientation, GetdXYdPoint, PointPartial, + * and DQuotient; and added members PartialType (from BundleAdjust) and p_lookJ. + * + */ + class CameraGroundMap { + public: + CameraGroundMap(Camera *parent); + + //! Destructor + virtual ~CameraGroundMap() {}; + + virtual bool SetFocalPlane(const double ux, const double uy, + const double uz); + + enum PartialType { + WRT_Latitude, + WRT_Longitude, + WRT_Radius + }; + + virtual bool SetGround(const double lat, const double lon); + virtual bool SetGround(const double lat, const double lon, const double radius); + virtual bool GetXY(const double lat, const double lon, const double radius, + double *cudx, double *cudy); + virtual bool GetdXYdPosition(const SpicePosition::PartialType varType, int coefIndex, + double *cudx, double *cudy); + virtual bool GetdXYdOrientation(const SpiceRotation::PartialType varType, int coefIndex, + double *cudx, double *cudy); + virtual bool GetdXYdPoint(double lat, double lon, double radius, PartialType wrt, + double *cudx, double *cudy); + std::vector PointPartial(double lat, double lon, double radius, PartialType wrt); + double DQuotient(std::vector &look, std::vector &dlook, int index); + + //! Return undistorted focal plane x + inline double FocalPlaneX() const { return p_focalPlaneX; }; + + //! Return undistorted focal plane y + inline double FocalPlaneY() const { return p_focalPlaneY; }; + + protected: + Camera *p_camera; + double p_focalPlaneX; + double p_focalPlaneY; + + private: + void LookCtoFocalPlaneXY(); //!< Calculate focalplane x/y from lookvector in camera + std::vector p_lookJ; //!< Look vector in J2000 calculated from ground coordinates in GetXY and used for partials + }; +}; +#endif diff --git a/isis/src/base/objs/CameraGroundMap/CameraGroundMap.truth b/isis/src/base/objs/CameraGroundMap/CameraGroundMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..6347fe6d38f458077e14c2efcd5624b000c19da3 --- /dev/null +++ b/isis/src/base/objs/CameraGroundMap/CameraGroundMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Camera models. diff --git a/isis/src/base/objs/CameraGroundMap/Makefile b/isis/src/base/objs/CameraGroundMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1e9e42668079f1e3fb9523f620e9f33dc029fca8 --- /dev/null +++ b/isis/src/base/objs/CameraGroundMap/Makefile @@ -0,0 +1,5 @@ +INCS = CameraGroundMap.h +SRCS = CameraGroundMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CameraGroundMap/unitTest.cpp b/isis/src/base/objs/CameraGroundMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..32848e184bde01774fb1dcc2517cfc7cc9c8f441 --- /dev/null +++ b/isis/src/base/objs/CameraGroundMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo.cpp b/isis/src/base/objs/CameraPointInfo/CameraPointInfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..282411fc45b4b9f940dfa64310bbeadb7e30c33a --- /dev/null +++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo.cpp @@ -0,0 +1,387 @@ +/** + * @file + * $Revision: 1.7 $ + * $Date: 2010/06/07 22:42:38 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "Brick.h" +#include "Camera.h" +#include "CameraPointInfo.h" +#include "CubeManager.h" +#include "iException.h" +#include "iTime.h" +#include "PvlGroup.h" + +using namespace std; + +namespace Isis { + + + /** + * Constructor, initializes CubeManager and other variables for + * use. + * + */ + CameraPointInfo::CameraPointInfo() { + usedCubes = NULL; + usedCubes = new CubeManager(); + usedCubes->SetNumOpenCubes(50); + currentCube = NULL; + camera = NULL; + } + + /** + * Destructor, deletes CubeManager object used. + * + */ + CameraPointInfo::~CameraPointInfo() { + if (usedCubes) { + delete usedCubes; + usedCubes = NULL; + } + } + + + /** + * 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 filename + */ + void CameraPointInfo::SetCube(const std::string & cubeFilename) { + currentCube = usedCubes->OpenCube(cubeFilename); + camera = currentCube->Camera(); + } + + + /** + * SetImage sets a sample, line image coordinate in the camera + * so data can be accessed. + * + * @param sample A sample coordinate in or almost in the cube + * @param line A line coordinate in or almost in the cubei + * + * @return 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, + const bool outside, const bool errors) { + if (CheckCube()) { + bool passed = camera->SetImage(sample, line); + return GetPointInfo(passed, outside, errors); + } + // Should never get here, error will be thrown in CheckCube() + return NULL; + } + + /** + * SetCenter sets the image coordinates to the center of the image. + * + * @return PvlGroup* The pertinent data from the Camera class on + * the point. Ownership is passed to caller. + */ + PvlGroup * CameraPointInfo::SetCenter(const bool outside, const bool errors) { + if (CheckCube()) { + bool passed = camera->SetImage(currentCube->Samples()/2, currentCube->Lines()/2); + return GetPointInfo(passed, outside, errors); + } + // Should never get here, error will be thrown in CheckCube() + return NULL; + } + + + /** + * SetSample sets the image coordinates to the center line and the + * given sample. + * + * @return PvlGroup* The pertinent data from the Camera class on + * the point. Ownership is passed to caller. + */ + PvlGroup * CameraPointInfo::SetSample(const double sample, + const bool outside, const bool errors) { + if (CheckCube()) { + bool passed = camera->SetImage(sample, currentCube->Lines()/2); + return GetPointInfo(passed, outside, errors); + } + // Should never get here, error will be thrown in CheckCube() + return NULL; + } + + + /** + * SetLine sets the image coordinates to the center sample and the + * given line. + * + * @return PvlGroup* The pertinent data from the Camera class on + * the point. Ownership is passed to caller. + */ + PvlGroup * CameraPointInfo::SetLine(const double line, + const bool outside, const bool errors) { + if (CheckCube()) { + bool passed = camera->SetImage(currentCube->Samples()/2, line); + return GetPointInfo(passed, outside, errors); + } + // Should never get here, error will be thrown in CheckCube() + return NULL; + } + + + /** + * SetGround sets a latitude, longitude grrund coordinate in the + * camera so data can be accessed. + * + * @param latitude A latitude coordinate in or almost in the + * cube + * @param longitude A longitude coordinate in or almost in the + * cube + * + * @return 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, + const bool outside, const bool errors) { + if (CheckCube()) { + bool passed = camera->SetUniversalGround(latitude, longitude); + return GetPointInfo(passed, outside, errors); + } + // Should never get here, error will be thrown in CheckCube() + return NULL; + } + + + /** + * CheckCube checks that a cube has been set before the data for + * a point is accessed. + * + * @return bool Whether or not a cube has been set, true if it has been. + */ + bool CameraPointInfo::CheckCube() { + if (currentCube == NULL) { + string msg = "Please set a cube before setting parameters"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + return false; + } + return true; + } + + /** + * GetPointInfo builds the PvlGroup containing all the important + * information derived from the Camera. + * + * @return PvlGroup* Data taken directly from the Camera and + * drived from Camera information. Ownership passed. + */ + PvlGroup * CameraPointInfo::GetPointInfo(bool passed, bool allowOutside, bool allowErrors) { + PvlGroup * gp = new PvlGroup("GroundPoint"); + { + 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")); + if (allowErrors) gp->AddKeyword(PvlKeyword("Error")); + } + + bool noErrors = passed; + string error = ""; + if (!camera->HasSurfaceIntersection()) { + error = "Requested position does not project in camera model; no surface intersection"; + noErrors = false; + if (!allowErrors) throw iException::Message(iException::Camera, error, _FILEINFO_); + } + if(!camera->InCube() && !allowOutside) { + error = "Requested position does not project in camera model; not inside cube"; + noErrors = false; + if (!allowErrors) throw iException::Message(iException::Camera ,error, _FILEINFO_); + } + + if (!noErrors) { + for (int i = 0; i < gp->Keywords(); i++) { + string name = (*gp)[i].Name(); + // These three keywords have 3 values, so they must have 3 N/As + if (name == "BodyFixedCoordinate" || name == "SpacecraftPosition" || + name == "SunPosition") { + (*gp)[i].AddValue("N/A"); + (*gp)[i].AddValue("N/A"); + (*gp)[i].AddValue("N/A"); + } + else { + (*gp)[i].SetValue("N/A"); + } + } + // Set all keywords that still have valid information + gp->FindKeyword("Error").SetValue(error); + gp->FindKeyword("Filename").SetValue(currentCube->Filename()); + gp->FindKeyword("Sample").SetValue(camera->Sample()); + gp->FindKeyword("Line").SetValue(camera->Line()); + gp->FindKeyword("EphemerisTime").SetValue(camera->EphemerisTime(), "seconds"); + gp->FindKeyword("EphemerisTime").AddComment("Time"); + iTime t(camera->EphemerisTime()); + string utc; + utc = t.UTC(); + gp->FindKeyword("UTC").SetValue(utc); + gp->FindKeyword("SpacecraftPosition").AddComment("Spacecraft Information"); + gp->FindKeyword("SunPosition").AddComment("Sun Information"); + gp->FindKeyword("Phase").AddComment("Illumination and Other"); + } + + else { + + Brick b(3,3,1,currentCube->PixelType()); + + int intSamp = (int)(camera->Sample() + 0.5); + int intLine = (int)(camera->Line() + 0.5); + b.SetBasePosition(intSamp, intLine, 1); + currentCube->Read(b); + + double pB[3], spB[3], sB[3]; + string utc; + double ssplat, ssplon, sslat, sslon, pwlon, oglat; + + { + gp->FindKeyword("Filename").SetValue(currentCube->Filename()); + gp->FindKeyword("Sample").SetValue(camera->Sample()); + gp->FindKeyword("Line").SetValue(camera->Line()); + gp->FindKeyword("PixelValue").SetValue(PixelToString(b[0])); + gp->FindKeyword("RightAscension").SetValue(camera->RightAscension()); + gp->FindKeyword("Declination").SetValue(camera->Declination()); + gp->FindKeyword("PlanetocentricLatitude").SetValue(camera->UniversalLatitude()); + + // Convert lat to planetographic + double radii[3]; + camera->Radii(radii); + oglat = Isis::Projection::ToPlanetographic(camera->UniversalLatitude(), + radii[0],radii[2]); + gp->FindKeyword("PlanetographicLatitude").SetValue(oglat); + + gp->FindKeyword("PositiveEast360Longitude").SetValue( + camera->UniversalLongitude()); + + //Convert lon to -180 - 180 range + gp->FindKeyword("PositiveEast180Longitude").SetValue( + Isis::Projection::To180Domain( + camera->UniversalLongitude())); + + //Convert lon to positive west + pwlon = Isis::Projection::ToPositiveWest(camera->UniversalLongitude(), + 360); + gp->FindKeyword("PositiveWest360Longitude").SetValue(pwlon); + + //Convert pwlon to -180 - 180 range + gp->FindKeyword("PositiveWest180Longitude").SetValue( + Isis::Projection::To180Domain(pwlon)); + + camera->Coordinate(pB); + gp->FindKeyword("BodyFixedCoordinate").AddValue(pB[0],"km"); + gp->FindKeyword("BodyFixedCoordinate").AddValue(pB[1],"km"); + gp->FindKeyword("BodyFixedCoordinate").AddValue(pB[2],"km"); + + gp->FindKeyword("LocalRadius").SetValue(camera->LocalRadius(),"m"); + gp->FindKeyword("SampleResolution").SetValue(camera->SampleResolution(),"m"); + gp->FindKeyword("LineResolution").SetValue(camera->LineResolution(),"m"); + + camera->InstrumentPosition(spB); + gp->FindKeyword("SpacecraftPosition").AddValue(spB[0],"km"); + gp->FindKeyword("SpacecraftPosition").AddValue(spB[1],"km"); + gp->FindKeyword("SpacecraftPosition").AddValue(spB[2],"km"); + gp->FindKeyword("SpacecraftPosition").AddComment("Spacecraft Information"); + + gp->FindKeyword("SpacecraftAzimuth").SetValue(camera->SpacecraftAzimuth()); + gp->FindKeyword("SlantDistance").SetValue(camera->SlantDistance(),"km"); + gp->FindKeyword("TargetCenterDistance").SetValue(camera->TargetCenterDistance(),"km"); + camera->SubSpacecraftPoint(ssplat,ssplon); + gp->FindKeyword("SubSpacecraftLatitude").SetValue(ssplat); + gp->FindKeyword("SubSpacecraftLongitude").SetValue(ssplon); + gp->FindKeyword("SpacecraftAltitude").SetValue(camera->SpacecraftAltitude(),"km"); + gp->FindKeyword("OffNadirAngle").SetValue(camera->OffNadirAngle()); + double subspcgrdaz; + subspcgrdaz = camera->GroundAzimuth(camera->UniversalLatitude(),camera->UniversalLongitude(), + ssplat,ssplon); + gp->FindKeyword("SubSpacecraftGroundAzimuth").SetValue(subspcgrdaz); + + camera->SunPosition(sB); + gp->FindKeyword("SunPosition").AddValue(sB[0],"km"); + gp->FindKeyword("SunPosition").AddValue(sB[1],"km"); + gp->FindKeyword("SunPosition").AddValue(sB[2],"km"); + gp->FindKeyword("SunPosition").AddComment("Sun Information"); + + gp->FindKeyword("SubSolarAzimuth").SetValue(camera->SunAzimuth()); + gp->FindKeyword("SolarDistance").SetValue(camera->SolarDistance(),"AU"); + camera->SubSolarPoint(sslat,sslon); + gp->FindKeyword("SubSolarLatitude").SetValue(sslat); + gp->FindKeyword("SubSolarLongitude").SetValue(sslon); + double subsolgrdaz; + subsolgrdaz = camera->GroundAzimuth(camera->UniversalLatitude(),camera->UniversalLongitude(), + sslat,sslon); + gp->FindKeyword("SubSolarGroundAzimuth").SetValue(subsolgrdaz); + + gp->FindKeyword("Phase").SetValue(camera->PhaseAngle()); + gp->FindKeyword("Phase").AddComment("Illumination and Other"); + gp->FindKeyword("Incidence").SetValue(camera->IncidenceAngle()); + gp->FindKeyword("Emission").SetValue(camera->EmissionAngle()); + gp->FindKeyword("NorthAzimuth").SetValue(camera->NorthAzimuth()); + + gp->FindKeyword("EphemerisTime").SetValue(camera->EphemerisTime(), "seconds"); + gp->FindKeyword("EphemerisTime").AddComment("Time"); + iTime t(camera->EphemerisTime()); + utc = t.UTC(); + gp->FindKeyword("UTC").SetValue(utc); + gp->FindKeyword("LocalSolarTime").SetValue(camera->LocalSolarTime(),"hour"); + gp->FindKeyword("SolarLongitude").SetValue(camera->SolarLongitude()); + if (allowErrors) gp->FindKeyword("Error").SetValue("N/A"); + } + } + return gp; + } +} diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo.h b/isis/src/base/objs/CameraPointInfo/CameraPointInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..73099ddec2a5bf5fbe54c4fe6add285522a624db --- /dev/null +++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo.h @@ -0,0 +1,110 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/06/07 22:42:38 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef CameraPointInfo_h +#define CameraPointInfo_h + +#include + +namespace Isis { + class CubeManager; + class Cube; + class Camera; + class PvlGroup; + + + /** + * @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 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 when working with control nets and + * the opening of cubes several times. + * + * @author 2009-08-25 Mackenzie Boyd + * + * @internal + * @history 2009-09-13 Mackenzie Boyd - Added methods SetCenter, SetSample + * and SetLine to support campt + * functionality. Added CheckCube + * private method to check + * currentCube isn't NULL. + * @history 2010-03-25 MNB - Modified longitude output to have + * Positive East and West, 360 and 180 + * longitudes. + * @history 2010-05-25 MNB - Many changes, primary changes had + * to do with how errors are + * handled. Depending on the options + * sent in, errors can be handled by + * putting an Error keyword into the + * PvlGroup instead of throwing an + * exception. Other changes, + * addition of two booleans, both + * defaulting to false, to the Set + * methods (excluding SetCube) so + * that allowoutside option and + * allowerrors option could be taken + * in instead of using setters. + * CheckConditions method was + * removed and placed within + * GetPointInfo, GetPointInfo had 3 + * boolean parameters added, passed + * - whether or not the SetImage or + * SetGround done above was + * successful, allowoutside - if + * locations outside the cube are + * acceptable, and allowerrors - + * what to do with errors. + * @history 2010-06-07 MNB - Changed Error keyword so that it + * is always present when + * allowErrors is true. + */ + class CameraPointInfo { + + public: + CameraPointInfo(); + virtual ~CameraPointInfo(); + + void SetCube(const std::string & cubeFilename); + 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); + PvlGroup * SetSample(const double sample, const bool outside = false, + const bool error = false); + PvlGroup * SetLine(const double line, const bool outside = false, + const bool error = false); + PvlGroup * SetGround(const double latitude, const double longitude, + const bool outside = false, const bool error = false); + + private: + bool CheckCube(); + PvlGroup * GetPointInfo(bool passed, bool outside, bool errors); + CubeManager * usedCubes; + Cube * currentCube; + Camera * camera; + }; +}; + +#endif diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo.truth b/isis/src/base/objs/CameraPointInfo/CameraPointInfo.truth new file mode 100644 index 0000000000000000000000000000000000000000..5612dfa58342bc9a60a4355730d43f5785991eb5 --- /dev/null +++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo.truth @@ -0,0 +1,103 @@ +Group = GroundPoint + Sample = 1.0 + Line = 1.0 + PixelValue = 0.0144526 + RightAscension = 261.05448074442 + Declination = 64.973136000721 + PlanetocentricLatitude = -84.757759588221 + PlanetographicLatitude = -84.757759588221 + PositiveEast360Longitude = 12.099790311414 + PositiveEast180Longitude = 12.099790311414 + PositiveWest360Longitude = 347.90020968859 + PositiveWest180Longitude = -12.099790311414 + BodyFixedCoordinate = (155.17944862822, 33.266997191508, + -1729.7476298847) + LocalRadius = 1737013.0159186 + SampleResolution = 187.5857977999 + LineResolution = 187.5857977999 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 199.50893004833 + SlantDistance = 735.2547683331 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.43997729947884 + SubSpacecraftGroundAzimuth = 106.69243625663 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.677449357755 + SolarDistance = 0.99964724201843 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.55088801451667 + + # Illumination and Other + Phase = 86.140995878783 + Incidence = 86.004187896944 + Emission = 0.62621240236416 + NorthAzimuth = 87.184188657782 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.598282533703 + SolarLongitude = 129.01790468942 +End_Group + +Group = GroundPoint + Sample = 0.8901226055642 + Line = 1.1511384074406 + PixelValue = 0.0144526 + RightAscension = 262.29095189623 + Declination = 65.693495329982 + PlanetocentricLatitude = -84.5 + PlanetographicLatitude = -84.5 + PositiveEast360Longitude = 15.0 + PositiveEast180Longitude = 15.0 + PositiveWest360Longitude = 345.0 + PositiveWest180Longitude = -15.0 + BodyFixedCoordinate = (160.94890808189, 43.126129943212, + -1730.4831018617) + LocalRadius = 1738486.75 + SampleResolution = 187.22618189816 + LineResolution = 187.22618189816 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 280.8533797296 + SlantDistance = 733.84493360323 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.77330380084493 + SubSpacecraftGroundAzimuth = 195.20808001613 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.701141069967 + SolarDistance = 0.99964718498012 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.30025894895209 + + # Illumination and Other + Phase = 86.801052123281 + Incidence = 85.725629970735 + Emission = 1.0997203354418 + NorthAzimuth = 89.399652221308 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.791629977495 + SolarLongitude = 129.01790468942 +End_Group \ No newline at end of file diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Darwin_i386.truth b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Darwin_i386.truth new file mode 100644 index 0000000000000000000000000000000000000000..7cd0700978462e88db2771d2af85cd6e858d2fa1 --- /dev/null +++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Darwin_i386.truth @@ -0,0 +1,99 @@ +Group = GroundPoint + Sample = 1.0 + Line = 1.0 + PixelValue = 0.0144526 + RightAscension = 261.05448074442 + Declination = 64.973136000721 + PlanetocentricLatitude = -84.757759588221 + PlanetographicLatitude = -84.757759588221 + PositiveEastLongitude = 12.099790311414 + PositiveWestLongitude = 347.90020968859 + BodyFixedCoordinate = (155.17944862822, 33.266997191508, + -1729.7476298847) + LocalRadius = 1737013.0159186 + SampleResolution = 187.5857977999 + LineResolution = 187.5857977999 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 199.50893004833 + SlantDistance = 735.2547683331 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.43997729947884 + SubSpacecraftGroundAzimuth = 106.69243625663 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.677449357755 + SolarDistance = 0.99964724201843 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.55088801451667 + + # Illumination and Other + Phase = 86.140995878783 + Incidence = 86.004187896944 + Emission = 0.62621240236416 + NorthAzimuth = 87.184188657782 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.598282533703 + SolarLongitude = 129.01790468942 +End_Group + +Group = GroundPoint + Sample = 0.8901226055642 + Line = 1.1511384074406 + PixelValue = 0.0144526 + RightAscension = 262.29095189623 + Declination = 65.693495329982 + PlanetocentricLatitude = -84.5 + PlanetographicLatitude = -84.5 + PositiveEastLongitude = 15.0 + PositiveWestLongitude = 345.0 + BodyFixedCoordinate = (160.94890808189, 43.126129943212, + -1730.4831018617) + LocalRadius = 1738486.75 + SampleResolution = 187.22618189816 + LineResolution = 187.22618189816 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 280.8533797296 + SlantDistance = 733.84493360323 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.77330380084493 + SubSpacecraftGroundAzimuth = 195.20808001613 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.701141069967 + SolarDistance = 0.99964718498012 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.30025894895211 + + # Illumination and Other + Phase = 86.801052123281 + Incidence = 85.725629970735 + Emission = 1.0997203354418 + NorthAzimuth = 89.399652221308 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.791629977495 + SolarLongitude = 129.01790468942 +End_Group \ No newline at end of file diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Darwin_i386_10_5.truth b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Darwin_i386_10_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..5b1cdeefc32c32a6ac7d7d1917b9c758355f1884 --- /dev/null +++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Darwin_i386_10_5.truth @@ -0,0 +1,103 @@ +Group = GroundPoint + Sample = 1.0 + Line = 1.0 + PixelValue = 0.0144526 + RightAscension = 261.05448074442 + Declination = 64.973136000721 + PlanetocentricLatitude = -84.757759588221 + PlanetographicLatitude = -84.757759588221 + PositiveEast360Longitude = 12.099790311414 + PositiveEast180Longitude = 12.099790311414 + PositiveWest360Longitude = 347.90020968859 + PositiveWest180Longitude = -12.099790311414 + BodyFixedCoordinate = (155.17944862822, 33.266997191508, + -1729.7476298847) + LocalRadius = 1737013.0159186 + SampleResolution = 187.5857977999 + LineResolution = 187.5857977999 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 199.50893004833 + SlantDistance = 735.2547683331 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.43997729947884 + SubSpacecraftGroundAzimuth = 106.69243625663 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.677449357755 + SolarDistance = 0.99964724201843 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.55088801451667 + + # Illumination and Other + Phase = 86.140995878783 + Incidence = 86.004187896944 + Emission = 0.62621240236416 + NorthAzimuth = 87.184188657766 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.598282533703 + SolarLongitude = 129.01790468942 +End_Group + +Group = GroundPoint + Sample = 0.8901226055642 + Line = 1.1511384074406 + PixelValue = 0.0144526 + RightAscension = 262.29095189623 + Declination = 65.693495329982 + PlanetocentricLatitude = -84.5 + PlanetographicLatitude = -84.5 + PositiveEast360Longitude = 15.0 + PositiveEast180Longitude = 15.0 + PositiveWest360Longitude = 345.0 + PositiveWest180Longitude = -15.0 + BodyFixedCoordinate = (160.94890808189, 43.126129943212, + -1730.4831018617) + LocalRadius = 1738486.75 + SampleResolution = 187.22618189816 + LineResolution = 187.22618189816 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 280.85337972962 + SlantDistance = 733.84493360323 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.77330380084493 + SubSpacecraftGroundAzimuth = 195.20808001613 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.701141069967 + SolarDistance = 0.99964718498012 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.30025894895209 + + # Illumination and Other + Phase = 86.801052123281 + Incidence = 85.725629970735 + Emission = 1.0997203354418 + NorthAzimuth = 89.399652221311 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.791629977495 + SolarLongitude = 129.01790468942 +End_Group \ No newline at end of file diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Darwin_i386_10_5_8.truth b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Darwin_i386_10_5_8.truth new file mode 100644 index 0000000000000000000000000000000000000000..5b1cdeefc32c32a6ac7d7d1917b9c758355f1884 --- /dev/null +++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Darwin_i386_10_5_8.truth @@ -0,0 +1,103 @@ +Group = GroundPoint + Sample = 1.0 + Line = 1.0 + PixelValue = 0.0144526 + RightAscension = 261.05448074442 + Declination = 64.973136000721 + PlanetocentricLatitude = -84.757759588221 + PlanetographicLatitude = -84.757759588221 + PositiveEast360Longitude = 12.099790311414 + PositiveEast180Longitude = 12.099790311414 + PositiveWest360Longitude = 347.90020968859 + PositiveWest180Longitude = -12.099790311414 + BodyFixedCoordinate = (155.17944862822, 33.266997191508, + -1729.7476298847) + LocalRadius = 1737013.0159186 + SampleResolution = 187.5857977999 + LineResolution = 187.5857977999 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 199.50893004833 + SlantDistance = 735.2547683331 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.43997729947884 + SubSpacecraftGroundAzimuth = 106.69243625663 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.677449357755 + SolarDistance = 0.99964724201843 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.55088801451667 + + # Illumination and Other + Phase = 86.140995878783 + Incidence = 86.004187896944 + Emission = 0.62621240236416 + NorthAzimuth = 87.184188657766 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.598282533703 + SolarLongitude = 129.01790468942 +End_Group + +Group = GroundPoint + Sample = 0.8901226055642 + Line = 1.1511384074406 + PixelValue = 0.0144526 + RightAscension = 262.29095189623 + Declination = 65.693495329982 + PlanetocentricLatitude = -84.5 + PlanetographicLatitude = -84.5 + PositiveEast360Longitude = 15.0 + PositiveEast180Longitude = 15.0 + PositiveWest360Longitude = 345.0 + PositiveWest180Longitude = -15.0 + BodyFixedCoordinate = (160.94890808189, 43.126129943212, + -1730.4831018617) + LocalRadius = 1738486.75 + SampleResolution = 187.22618189816 + LineResolution = 187.22618189816 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 280.85337972962 + SlantDistance = 733.84493360323 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.77330380084493 + SubSpacecraftGroundAzimuth = 195.20808001613 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.701141069967 + SolarDistance = 0.99964718498012 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.30025894895209 + + # Illumination and Other + Phase = 86.801052123281 + Incidence = 85.725629970735 + Emission = 1.0997203354418 + NorthAzimuth = 89.399652221311 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.791629977495 + SolarLongitude = 129.01790468942 +End_Group \ No newline at end of file diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Darwin_powerpc.truth b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Darwin_powerpc.truth new file mode 100644 index 0000000000000000000000000000000000000000..6c8ae6169ff62b9f75cc90deae8f251b150b0902 --- /dev/null +++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Darwin_powerpc.truth @@ -0,0 +1,99 @@ +Group = GroundPoint + Sample = 1.0 + Line = 1.0 + PixelValue = 0.0144526 + RightAscension = 261.05448074442 + Declination = 64.973136000721 + PlanetocentricLatitude = -84.757759588221 + PlanetographicLatitude = -84.757759588221 + PositiveEastLongitude = 12.099790311414 + PositiveWestLongitude = 347.90020968859 + BodyFixedCoordinate = (155.17944862822, 33.266997191508, + -1729.7476298847) + LocalRadius = 1737013.0159186 + SampleResolution = 187.5857977999 + LineResolution = 187.5857977999 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 199.50893004779 + SlantDistance = 735.2547683331 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.43997729947884 + SubSpacecraftGroundAzimuth = 106.69243625663 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.677449357776 + SolarDistance = 0.99964724201843 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.55088801451667 + + # Illumination and Other + Phase = 86.140995878783 + Incidence = 86.004187896944 + Emission = 0.62621240236416 + NorthAzimuth = 87.184188657422 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.598282533703 + SolarLongitude = 129.01790468942 +End_Group + +Group = GroundPoint + Sample = 0.8901226055642 + Line = 1.1511384074406 + PixelValue = 0.0144526 + RightAscension = 262.29095189623 + Declination = 65.693495329982 + PlanetocentricLatitude = -84.5 + PlanetographicLatitude = -84.5 + PositiveEastLongitude = 15.0 + PositiveWestLongitude = 345.0 + BodyFixedCoordinate = (160.94890808189, 43.126129943212, + -1730.4831018617) + LocalRadius = 1738486.75 + SampleResolution = 187.22618189816 + LineResolution = 187.22618189816 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 280.85337972964 + SlantDistance = 733.84493360323 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.77330380084493 + SubSpacecraftGroundAzimuth = 195.20808001613 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.701141069897 + SolarDistance = 0.99964718498012 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.30025894895209 + + # Illumination and Other + Phase = 86.801052123281 + Incidence = 85.725629970735 + Emission = 1.0997203354418 + NorthAzimuth = 89.399652220996 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.791629977495 + SolarLongitude = 129.01790468942 +End_Group \ No newline at end of file diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Linux_i686_RedHat5_4.truth b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Linux_i686_RedHat5_4.truth new file mode 100644 index 0000000000000000000000000000000000000000..6366f7e0c85a7edeb6b482c0f55fc06b81017b99 --- /dev/null +++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Linux_i686_RedHat5_4.truth @@ -0,0 +1,103 @@ +Group = GroundPoint + Sample = 1.0 + Line = 1.0 + PixelValue = 0.0144526 + RightAscension = 261.05448074442 + Declination = 64.973136000721 + PlanetocentricLatitude = -84.757759588221 + PlanetographicLatitude = -84.757759588221 + PositiveEast360Longitude = 12.099790311414 + PositiveEast180Longitude = 12.099790311414 + PositiveWest360Longitude = 347.90020968859 + PositiveWest180Longitude = -12.099790311414 + BodyFixedCoordinate = (155.17944862822, 33.266997191508, + -1729.7476298847) + LocalRadius = 1737013.0159186 + SampleResolution = 187.5857977999 + LineResolution = 187.5857977999 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 199.50893004812 + SlantDistance = 735.2547683331 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.43997729947885 + SubSpacecraftGroundAzimuth = 106.69243625663 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.677449357772 + SolarDistance = 0.99964724201843 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.55088801451668 + + # Illumination and Other + Phase = 86.140995878783 + Incidence = 86.004187896944 + Emission = 0.62621240236416 + NorthAzimuth = 87.184188658207 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.598282533703 + SolarLongitude = 129.01790468942 +End_Group + +Group = GroundPoint + Sample = 0.8901226055642 + Line = 1.1511384074406 + PixelValue = 0.0144526 + RightAscension = 262.29095189623 + Declination = 65.693495329982 + PlanetocentricLatitude = -84.5 + PlanetographicLatitude = -84.5 + PositiveEast360Longitude = 15.0 + PositiveEast180Longitude = 15.0 + PositiveWest360Longitude = 345.0 + PositiveWest180Longitude = -15.0 + BodyFixedCoordinate = (160.94890808189, 43.126129943212, + -1730.4831018617) + LocalRadius = 1738486.75 + SampleResolution = 187.22618189816 + LineResolution = 187.22618189816 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 280.85337972958 + SlantDistance = 733.84493360323 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.77330380084461 + SubSpacecraftGroundAzimuth = 195.20808001613 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.701141069976 + SolarDistance = 0.99964718498012 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.30025894895211 + + # Illumination and Other + Phase = 86.801052123281 + Incidence = 85.725629970735 + Emission = 1.0997203354414 + NorthAzimuth = 89.399652220842 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.791629977495 + SolarLongitude = 129.01790468942 +End_Group \ No newline at end of file diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Linux_i686_RedHat5_5.truth b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Linux_i686_RedHat5_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..6366f7e0c85a7edeb6b482c0f55fc06b81017b99 --- /dev/null +++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Linux_i686_RedHat5_5.truth @@ -0,0 +1,103 @@ +Group = GroundPoint + Sample = 1.0 + Line = 1.0 + PixelValue = 0.0144526 + RightAscension = 261.05448074442 + Declination = 64.973136000721 + PlanetocentricLatitude = -84.757759588221 + PlanetographicLatitude = -84.757759588221 + PositiveEast360Longitude = 12.099790311414 + PositiveEast180Longitude = 12.099790311414 + PositiveWest360Longitude = 347.90020968859 + PositiveWest180Longitude = -12.099790311414 + BodyFixedCoordinate = (155.17944862822, 33.266997191508, + -1729.7476298847) + LocalRadius = 1737013.0159186 + SampleResolution = 187.5857977999 + LineResolution = 187.5857977999 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 199.50893004812 + SlantDistance = 735.2547683331 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.43997729947885 + SubSpacecraftGroundAzimuth = 106.69243625663 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.677449357772 + SolarDistance = 0.99964724201843 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.55088801451668 + + # Illumination and Other + Phase = 86.140995878783 + Incidence = 86.004187896944 + Emission = 0.62621240236416 + NorthAzimuth = 87.184188658207 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.598282533703 + SolarLongitude = 129.01790468942 +End_Group + +Group = GroundPoint + Sample = 0.8901226055642 + Line = 1.1511384074406 + PixelValue = 0.0144526 + RightAscension = 262.29095189623 + Declination = 65.693495329982 + PlanetocentricLatitude = -84.5 + PlanetographicLatitude = -84.5 + PositiveEast360Longitude = 15.0 + PositiveEast180Longitude = 15.0 + PositiveWest360Longitude = 345.0 + PositiveWest180Longitude = -15.0 + BodyFixedCoordinate = (160.94890808189, 43.126129943212, + -1730.4831018617) + LocalRadius = 1738486.75 + SampleResolution = 187.22618189816 + LineResolution = 187.22618189816 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 280.85337972958 + SlantDistance = 733.84493360323 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.77330380084461 + SubSpacecraftGroundAzimuth = 195.20808001613 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.701141069976 + SolarDistance = 0.99964718498012 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.30025894895211 + + # Illumination and Other + Phase = 86.801052123281 + Incidence = 85.725629970735 + Emission = 1.0997203354414 + NorthAzimuth = 89.399652220842 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.791629977495 + SolarLongitude = 129.01790468942 +End_Group \ No newline at end of file diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Linux_i686_SUSE10_1.truth b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Linux_i686_SUSE10_1.truth new file mode 100644 index 0000000000000000000000000000000000000000..8e49dfaf4553f5cb50ce86bfb42b93a6affc0c02 --- /dev/null +++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo_Linux_i686_SUSE10_1.truth @@ -0,0 +1,103 @@ +Group = GroundPoint + Sample = 1.0 + Line = 1.0 + PixelValue = 0.0144526 + RightAscension = 261.05448074442 + Declination = 64.973136000721 + PlanetocentricLatitude = -84.757759588221 + PlanetographicLatitude = -84.757759588221 + PositiveEast360Longitude = 12.099790311414 + PositiveEast180Longitude = 12.099790311414 + PositiveWest360Longitude = 347.90020968859 + PositiveWest180Longitude = -12.099790311414 + BodyFixedCoordinate = (155.17944862822, 33.266997191508, + -1729.7476298847) + LocalRadius = 1737013.0159186 + SampleResolution = 187.5857977999 + LineResolution = 187.5857977999 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 199.50893004811 + SlantDistance = 735.2547683331 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.43997729947885 + SubSpacecraftGroundAzimuth = 106.69243625663 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.677449357771 + SolarDistance = 0.99964724201843 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.55088801451668 + + # Illumination and Other + Phase = 86.140995878783 + Incidence = 86.004187896944 + Emission = 0.62621240236416 + NorthAzimuth = 87.184188658239 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.598282533703 + SolarLongitude = 129.01790468942 +End_Group + +Group = GroundPoint + Sample = 0.8901226055642 + Line = 1.1511384074406 + PixelValue = 0.0144526 + RightAscension = 262.29095189623 + Declination = 65.693495329982 + PlanetocentricLatitude = -84.5 + PlanetographicLatitude = -84.5 + PositiveEast360Longitude = 15.0 + PositiveEast180Longitude = 15.0 + PositiveWest360Longitude = 345.0 + PositiveWest180Longitude = -15.0 + BodyFixedCoordinate = (160.94890808189, 43.126129943212, + -1730.4831018617) + LocalRadius = 1738486.75 + SampleResolution = 187.22618189816 + LineResolution = 187.22618189816 + + # Spacecraft Information + SpacecraftPosition = (216.76438021064, 54.256829537357, + -2462.1179579952) + SpacecraftAzimuth = 280.85337972958 + SlantDistance = 733.84493360323 + TargetCenterDistance = 2472.2369302237 + SubSpacecraftLatitude = -84.814280390521 + SubSpacecraftLongitude = 14.052595361014 + SpacecraftAltitude = 734.4776489877 + OffNadirAngle = 0.77330380084461 + SubSpacecraftGroundAzimuth = 195.20808001613 + + # Sun Information + SunPosition = (142092302.24738, 46513072.418956, + 3175615.049146) + SubSolarAzimuth = 91.701141069957 + SolarDistance = 0.99964718498012 + SubSolarLatitude = 1.2167758823866 + SubSolarLongitude = 18.125552305876 + SubSolarGroundAzimuth = 0.30025894895211 + + # Illumination and Other + Phase = 86.801052123281 + Incidence = 85.725629970735 + Emission = 1.0997203354414 + NorthAzimuth = 89.399652220765 + + # Time + EphemerisTime = -182103311.79772 + UTC = 1994-03-25T19:43:48.0166464 + LocalSolarTime = 11.791629977495 + SolarLongitude = 129.01790468942 +End_Group \ No newline at end of file diff --git a/isis/src/base/objs/CameraPointInfo/Makefile b/isis/src/base/objs/CameraPointInfo/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b4dda97c466c199b6472cc6263342f036d378a1d --- /dev/null +++ b/isis/src/base/objs/CameraPointInfo/Makefile @@ -0,0 +1,5 @@ +INCS = CameraPointInfo.h +SRCS = CameraPointInfo.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CameraPointInfo/unitTest.cpp b/isis/src/base/objs/CameraPointInfo/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a6beb595865730ff62da25fca657a90fd457ea6 --- /dev/null +++ b/isis/src/base/objs/CameraPointInfo/unitTest.cpp @@ -0,0 +1,36 @@ +#include "CameraPointInfo.h" +#include "Preference.h" +#include "PvlGroup.h" + +#include +#include + +using namespace std; + +int main() { + Isis::Preference::Preferences(true); + + // The class being tested + Isis::CameraPointInfo cpi; + + // It is necessary to delete the Filename keyword for the test to pass + // this is because the directory it is run from may change + // under normal usage Filename is always included + + cpi.SetCube("unitTest1.cub"); + Isis::PvlGroup *grp = cpi.SetImage(1, 1); + grp->DeleteKeyword("Filename"); + cout << (*grp) << endl << endl; + + cpi.SetCube("unitTest1.cub"); + Isis::PvlGroup *too = cpi.SetGround(-84.5, 15.0); + too->DeleteKeyword("Filename"); + cout << (*too); + + // We have ownership, so, delete + delete grp; + grp = NULL; + delete too; + too = NULL; + return 0; +} diff --git a/isis/src/base/objs/CameraSkyMap/CameraSkyMap.cpp b/isis/src/base/objs/CameraSkyMap/CameraSkyMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..557964d0006d703f9fc06962cc3707f715080261 --- /dev/null +++ b/isis/src/base/objs/CameraSkyMap/CameraSkyMap.cpp @@ -0,0 +1,90 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/07/15 15:07:19 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "CameraSkyMap.h" +#include "NaifStatus.h" + +namespace Isis { + /** Constructor a map between focal plane x/y and right acension/declination + * + * @param parent parent camera which will use this map + * + */ + CameraSkyMap::CameraSkyMap(Camera *parent) { + p_camera = parent; + p_camera->SetSkyMap(this); + } + + /** Compute ra/dec from focal plane coordinate + * + * This method will compute the right ascension and declination given an + * undistorted focal plane coordinate. Note that the ra/dec values + * can be obtained from the parent camera class passed into the constructor. + * + * @param ux distorted focal plane x in millimeters + * @param uy distorted focal plane y in millimeters + * @param uz distorted focal plane z in millimeters + * + * @return conversion was successful + */ + bool CameraSkyMap::SetFocalPlane(const double ux, const double uy, + double uz) { + NaifStatus::CheckErrors(); + + SpiceDouble lookC[3]; + lookC[0] = ux; + lookC[1] = uy; + lookC[2] = uz; + + SpiceDouble unitLookC[3]; + vhat_c(lookC,unitLookC); + p_camera->SetLookDirection(unitLookC); + + NaifStatus::CheckErrors(); + + return true; + } + + /** + * Compute undistorted focal plane coordinate from ra/dec + * + * @param ra The right ascension angle + * @param dec The declination + * + * @return conversion was successful + * @todo what happens if we are looking behind the focal plane????? + * @todo what happens if we are looking parallel to the focal plane?? + * @todo can lookC[2] == zero imply parallel + * @todo can this all be solved by restricting the physical size of + * the focal plane? + */ + bool CameraSkyMap::SetSky(const double ra, const double dec) { + p_camera->Sensor::SetRightAscensionDeclination(ra,dec); + double lookC[3]; + p_camera->Sensor::LookDirection(lookC); + double scale = p_camera->FocalLength() / lookC[2]; + p_focalPlaneX = lookC[0] * scale; + p_focalPlaneY = lookC[1] * scale; + return true; + } +} diff --git a/isis/src/base/objs/CameraSkyMap/CameraSkyMap.h b/isis/src/base/objs/CameraSkyMap/CameraSkyMap.h new file mode 100644 index 0000000000000000000000000000000000000000..7644ddf3ad715df45724d2876fb11d34393efadb --- /dev/null +++ b/isis/src/base/objs/CameraSkyMap/CameraSkyMap.h @@ -0,0 +1,69 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/07/15 15:07:19 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef CameraSkyMap_h +#define CameraSkyMap_h + +#include "Camera.h" + +namespace Isis { + /** Convert between undistorted focal plane and ra/dec coordinates + * + * This base class is used to convert between undistorted focal plane + * coordinates (x/y) in millimeters and sky (ra/dec). This + * class handles the case of framing cameras. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * @history 2005-02-08 Jeff Anderson Original version + * @history 2008-07-14 Steven Lambright Added NaifStatus calls + * + */ + class CameraSkyMap { + public: + CameraSkyMap(Camera *parent); + + //! Destructor + virtual ~CameraSkyMap() {}; + + virtual bool SetFocalPlane(const double ux, const double uy, + const double uz); + + virtual bool SetSky(const double ra, const double dec); + + //! Return undistorted focal plane x + inline double FocalPlaneX() const { return p_focalPlaneX; }; + + //! Return undistorted focal plane y + inline double FocalPlaneY() const { return p_focalPlaneY; }; + + protected: + Camera *p_camera; + double p_focalPlaneX; + double p_focalPlaneY; + }; +}; +#endif diff --git a/isis/src/base/objs/CameraSkyMap/CameraSkyMap.truth b/isis/src/base/objs/CameraSkyMap/CameraSkyMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..6347fe6d38f458077e14c2efcd5624b000c19da3 --- /dev/null +++ b/isis/src/base/objs/CameraSkyMap/CameraSkyMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Camera models. diff --git a/isis/src/base/objs/CameraSkyMap/Makefile b/isis/src/base/objs/CameraSkyMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..af8b85ebaf8d1f349e1f130ce6a53bbf72696b46 --- /dev/null +++ b/isis/src/base/objs/CameraSkyMap/Makefile @@ -0,0 +1,5 @@ +INCS = CameraSkyMap.h +SRCS = CameraSkyMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CameraSkyMap/unitTest.cpp b/isis/src/base/objs/CameraSkyMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..32848e184bde01774fb1dcc2517cfc7cc9c8f441 --- /dev/null +++ b/isis/src/base/objs/CameraSkyMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/Chip/Chip.cpp b/isis/src/base/objs/Chip/Chip.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c6245a32936a5c11d3caaa8487fae149b1ca3f7 --- /dev/null +++ b/isis/src/base/objs/Chip/Chip.cpp @@ -0,0 +1,1011 @@ +/** + * @file + * $Revision: 1.18 $ + * $Date: 2010/06/15 19:39:56 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include "Camera.h" +#include "Chip.h" +#include "Cube.h" +#include "iException.h" +#include "Interpolator.h" +#include "LineManager.h" +#include "PolygonTools.h" +#include "Portal.h" +#include "Projection.h" +#include "Statistics.h" +#include "geos/geom/Point.h" +#include "tnt/tnt_array2d_utils.h" + +using namespace std; +namespace Isis { + + /** + * Constructs a Chip. The default size is 3x3 + */ + Chip::Chip () { + Init(3,3); + } + + + /** + * Construct a Chip with specified dimensions + * + * @param samples number of samples in the chip + * @param lines number of lines in the chip + */ + Chip::Chip (const int samples, const int lines) { + Init(samples,lines); + } + + + //! Destroys the Chip object + Chip::~Chip() { + if (p_clipPolygon != NULL) delete p_clipPolygon; + } + + + /** + * @brief Single value assignment operator + * + * Sets the entire chip to a constant + * + * @param d Value to set the chip to + */ + void Chip::SetAllValues(const double &d) { + for (unsigned int i = 0 ; i < p_buf.size() ; i++) { + fill(p_buf[i].begin(), p_buf[i].end(), d); + } + } + + /** + * Common initialization used by constructors + * + * @param samples number of samples in the chip + * @param lines number of lines in the chip + * @internal + * @history 2010-06-15 Jeannie Walldren - Added call to set Read() method's + * interpolator to default to Cubic Convolution type + */ + void Chip::Init (const int samples, const int lines) { + SetReadInterpolator(Interpolator::CubicConvolutionType); + SetSize(samples,lines); + SetValidRange(); + p_clipPolygon = NULL; + } + + + /** + * Change the size of the Chip + * + * @param samples number of samples in the chip + * @param lines number of lines in the chip + * @throws Isis::iException::User - Samples and lines must be greater than + * zero. + * @internal + * @history 2010-06-10 Jeannie Walldren - Modified error message + */ + void Chip::SetSize(const int samples, const int lines) throw (iException &){ + if(samples <= 0.0 || lines <= 0.0) { + string msg = "Unable to set chip size to [" + iString(samples); + msg += ", " + iString(lines) + "]. Samples and lines must be greater than zero."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_chipSamples = samples; + p_chipLines = lines; + p_buf.clear(); + p_buf.resize(lines); + for (int i=0; i maxSamp) return false; + if (line < minLine || line > maxLine) return false; + return true; + } + + + /** + * This sets which cube position will be located at the chip + * tack position + * + * @param cubeSample the cube sample value to tack + * @param cubeLine the cube line value to tack + */ + void Chip::TackCube (const double cubeSample, const double cubeLine) { + p_cubeTackSample = cubeSample; + p_cubeTackLine = cubeLine; + p_affine.Identity(); + p_affine.Translate(p_cubeTackSample,p_cubeTackLine); + } + + + /** + * Load cube data into the Chip. The data will be loaded such that the + * position set using TackCube method will be put at the center of the + * chip. The data will be loaded to sub-pixel accuracy using the interpolator + * indicated using SetReadInterpolator() method. + * + * @param cube The cube used to put data into the chip + * @param rotation rotation in degrees of data about the + * cube tack point (default of 0) + * @param scale scale factor (default of 1) + * @param band Band number to use when loading (default of 1) + * @see Read() + * @see SetReadInterpolator() + * @see GetReadInterpolator() + */ + void Chip::Load(Cube &cube, const double rotation, const double scale, + const int band) { + // Initialize our affine transform + p_affine.Identity(); + + // We want an affine which translates from chip to cube. Note + // that we want to give adjusted chip coordinates such that + // (0,0) is at the chip tack point and maps to the cube tack point. + p_affine.Scale(scale); + p_affine.Rotate(rotation); + p_affine.Translate(p_cubeTackSample,p_cubeTackLine); + + // Now go read the data from the cube into the chip + Read(cube,band); + + // Store off the cube address in case someone wants to match + // this chip + p_filename = cube.Filename(); + } + + /** + * @brief Load a chip using an Affine transform as provided by caller + * + * This method will load data from a cube using an established Affine + * transform as provided by the caller. It is up to the caller to set up the + * affine appropriately. + * + * For example, the first thing this method will do is set the chip tack point + * to the transformed cube location by replacing the existing affine transform + * with the one passed in and then calling SetChipPosition providing the chip + * tack point as the argument. This establishes which cube pixel is located + * at the chip tack point. + * + * The data will be loaded to sub-pixel accuracy using the interpolator + * indicated using SetReadInterpolator() method. + * + * @param cube Cube to load the data from + * @param affine Affine transform to set for chip load/operations + * @param keepPoly Indicates whether clipping polygon should be kept or removed + * (default of true) + * @param band Band number to read data from (default of 1) + * @see Read() + * @see SetReadInterpolator() + * @see GetReadInterpolator() + */ + void Chip::Load(Cube &cube, const Affine &affine, const bool &keepPoly, + const int band) { + + // Set the tackpoint center to the cube location + SetTransform(affine); + SetChipPosition(TackSample(), TackLine()); + + // Remove the clipping polygon if requested + if (!keepPoly) { + delete p_clipPolygon; + p_clipPolygon = 0; + } + + // Now go read the data from the cube into the chip + Read(cube,band); + + // Store off the cube address in case someone wants to match + // this chip + p_filename = cube.Filename(); + } + + + /** + * Loads cube data into the Chip. The data will be loaded such that the + * position set using TackCube method will be put at the center of the + * chip. The data will be loaded to sub-pixel accuracy using the interpolator + * indicated using SetReadInterpolator() method. Additionally, the data will be loaded + * such that it matches the camera and/or projective geometry of a + * given Chip. + * + * @param cube The cube used to put data into the chip + * @param match Match the geometry of this chip + * @param matchChipCube The cube used to put data into the match chip + * @param scale scale factor (default of 1) + * @param band Band number to use when loading (default of 1) + * + * @throws Isis::iException::Programmer - Chip cube is not a camera or map + * projection + * @throws Isis::iException::Programmer - Match chip cube is not a camera or + * map projection + * @throws Isis::iException::Programmer - Cannot find enough points to perform + * Affine transformation. + * @see Read() + * @see SetReadInterpolator() + * @see GetReadInterpolator() + * + * @internal + * @history 2010-01-28 Tracie Sucharski - When calculating control points away + * from the corners, added a linc to move into + * the center of the chip in a non-linear fashion to + * prevent control points that fall in a line + * and cause the matrix inversion to fail. + * @history 2010-05-24 Jeannie Walldren - Modified code when looking for + * control points for affine to start at each corner and + * move inward rather than looping around the corners. + * This lessens the likelyhood that the points will be + * too linear for the transform to work properly. A + * check was also added to ensure that we do not choose + * colinear points. + * @history 2010-06-10 Jeannie Walldren - Modified error message and added + * tolerance to linearity check. Fixed error messages. + */ + void Chip::Load (Cube &cube, Chip &match, Cube &matchChipCube, const double scale, const int band) throw (iException &){ + // See if the match cube has a camera or projection + Camera *matchCam = NULL; + Projection *matchProj = NULL; + try { + matchCam = matchChipCube.Camera(); + } + catch (iException &error) { + try { + matchProj = matchChipCube.Projection(); + error.Clear(); + } + catch (iException &error) { + string msg = "Can not geom chip. "; + msg += "Match chip cube [" + matchChipCube.Filename(); + msg += "] is not a camera or map projection"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + // See if the cube we are loading has a camera/projection + Camera *cam = NULL; + Projection *proj = NULL; + try { + cam = cube.Camera(); + } + catch (iException &error) { + try { + proj = cube.Projection(); + error.Clear(); + } + catch (iException &error) { + string msg = "Can not geom chip. "; + msg += "Chip cube [" + cube.Filename(); + msg += "] is not a camera or map projection"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + // Ok we can attempt to create an affine transformation that + // maps our chip to the match chip. We will need a set of at + // least 3 control points so we can fit the affine transform. + // We will try to find 4 points, one from each corner of the chip + vector x(4),y(4); + vector xp(4),yp(4); + + // Choose these control points by beginning at each corner and moving + // inward in the chip until an acceptable point is found + // i = 0, start at upper left corner (1, 1) + // i = 1, start at lower left corner (1, Lines()-1) + // i = 2, start at upper right corner (Samples()-1, 1) + // i = 3, start at lower right corner (Samples()-1, Lines()-1) + for (int i = 0; i < (int) xp.size(); i++) { + // define initial values for starting/ending sample/line for each index + int startSamp = 1; + int startLine = 1; + int endSamp = Samples()-1; + int endLine = Lines()-1; + + bool pointfound = false; + while (!pointfound) { + // start and end may cross (see MovePoints()) + // if we move outside chip, break out of loop + if (startSamp < 1 || startSamp > Samples()-1 || + endSamp < 1 || endSamp > Samples()-1 || + startLine < 1 || startLine > Lines()-1 || + endLine < 1 || endLine > Lines()-1) { + // unable to find acceptable control point from this corner + // erase point and go to the next corner + x.erase(x.begin()+i); + y.erase(y.begin()+i); + xp.erase(xp.begin()+i); + yp.erase(yp.begin()+i); + i--; + break; + } + int chipSamp, chipLine; + if (i < 2){ + chipSamp = startSamp; + } + else { + chipSamp = endSamp; + } + if (i % 2 == 0) { + chipLine = startLine; + } + else { + chipLine = endLine; + } + // Determine the offset from the tack point in our chip + // to one of the four corners + int sampOffset = chipSamp - TackSample(); + int lineOffset = chipLine - TackLine(); + + // Use this offset to compute a chip position in the match + // chip + double matchChipSamp = match.TackSample() + sampOffset; + double matchChipLine = match.TackLine() + lineOffset; + + // Now get the lat/lon at that chip position + match.SetChipPosition(matchChipSamp,matchChipLine); + double lat,lon; + if (matchCam != NULL) { + matchCam->SetImage(match.CubeSample(),match.CubeLine()); + if (!matchCam->HasSurfaceIntersection()){ + vector newlocation = MovePoints(startSamp, startLine, endSamp, endLine); + startSamp = newlocation[0]; + startLine = newlocation[1]; + endSamp = newlocation[2]; + endLine = newlocation[3]; + continue; + } + lat = matchCam->UniversalLatitude(); + lon = matchCam->UniversalLongitude(); + } + else { + matchProj->SetWorld(match.CubeSample(),match.CubeLine()); + if (!matchProj->IsGood()) { + vector newlocation = MovePoints(startSamp, startLine, endSamp, endLine); + startSamp = newlocation[0]; + startLine = newlocation[1]; + endSamp = newlocation[2]; + endLine = newlocation[3]; + continue; + } + lat = matchProj->UniversalLatitude(); + lon = matchProj->UniversalLongitude(); + } + + // Now use that lat/lon to find a line/sample in our chip + double line,samp; + if (cam != NULL) { + cam->SetUniversalGround(lat,lon); + if (!cam->HasSurfaceIntersection()) { + vector newlocation = MovePoints(startSamp, startLine, endSamp, endLine); + startSamp = newlocation[0]; + startLine = newlocation[1]; + endSamp = newlocation[2]; + endLine = newlocation[3]; + continue; + } + samp = cam->Sample(); // getting negative sample?!?!?! + line = cam->Line(); + } + else { + proj->SetUniversalGround(lat,lon); + if (!proj->IsGood()) { + vector newlocation = MovePoints(startSamp, startLine, endSamp, endLine); + startSamp = newlocation[0]; + startLine = newlocation[1]; + endSamp = newlocation[2]; + endLine = newlocation[3]; + continue; + } + samp = proj->WorldX(); + line = proj->WorldY(); + } + + // if (line < 1 || line > cube.Lines()) continue; + // if (samp < 1 || samp > cube.Samples()) continue; + + // Ok save this control point + pointfound = true; + x[i] = sampOffset; + y[i] = lineOffset; + xp[i] = samp; + yp[i] = line; + + // if we get 3 points on the same line, affine transform will fail + // choose a one degree default tolerance for linearity check method + double tol = 1.0; + // if we have already removed a point, use a stricter tolerance of 2 degrees + if (xp.size() == 3) { + tol = 2.0; + } + if (i > 1) { + if (PointsColinear(xp[0],yp[0],xp[1],yp[1],xp[i],yp[i],tol)) { + // try to find a point further along that is not colinear + pointfound = false; + vector newlocation = MovePoints(startSamp, startLine, endSamp, endLine); + startSamp = newlocation[0]; + startLine = newlocation[1]; + endSamp = newlocation[2]; + endLine = newlocation[3]; + continue; + } + } + } + } + + if (xp.size() < 3){ + string msg = "Cannot find enough points to perform Affine transformation. "; + msg += "Unable to load chip from [" + cube.Filename(); + msg += "] to match chip from [" + matchChipCube.Filename() + "]."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Now take our control points and create the affine map + p_affine.Solve(&x[0],&y[0],&xp[0],&yp[0],(int)x.size()); + + // TLS 8/3/06 Apply scale + p_affine.Scale(scale); + + // Finally we need to make the affine map the tack point + // to the requested cube sample/line + p_affine.Compute(0.0,0.0); + double cubeSampleOffset = p_cubeTackSample - p_affine.xp(); + double cubeLineOffset = p_cubeTackLine - p_affine.yp(); + p_affine.Translate(cubeSampleOffset,cubeLineOffset); + + // Now go read the data from the cube into the chip + Read(cube,band); + + // Store off the cube address in case someone wants to match + // this chip + p_filename = cube.Filename(); + } + + + /** + * This method is called by Load() to determine whether the + * given 3 points are nearly colinear. This is done by + * considering the triangle composed of these points. The + * method returns true if all angles of the triangle are greater + * than the tolerance angle and less than 180 degrees minus the + * tolerance angle. + * + * @param x0 The x-value of the first point + * @param y0 The y-value of the first point + * @param x1 The x-value of the second point + * @param y1 The y-value of the second point + * @param x2 The x-value of the third point + * @param y2 The y-value of the third point + * @param tol Minimum tolerance angle in degrees + * + * @return @b bool True if 3 given points are nearly colinear + * + * @internal + * @author Jeannie Walldren + * @history 2010-05-24 Jeannie Walldren - Original version. + * @history 2010-06-10 Jeannie Walldren - Modified to take in user defined + * tolerance as parameter to allow registration of + * narrow search chip areas + */ + bool Chip::PointsColinear(const double x0, const double y0, const double x1, const double y1, + const double x2, const double y2, const double tol){ + // check angles at each point of the triangle composed of the 3 points + // if any angle is near 0 or 180 degrees, then the points are almost colinear + + // we have the following property: + // sin(theta) = |v x w|/(|v|*|w|) where + // v=(vx,vy) and w=(wx,wy) are the vectors that define the angle theta + // |v| is the magnitude (norm) of the vector. In 2D, this is |v| = sqrt(vx^2 + vy^2) + // v x w is the cross product of the vectors. In 2D, this is v x w = vx*wy-vy*wx + // See equations (5) and (6) at http://mathworld.wolfram.com/CrossProduct.html + + + // first find the vectors that define the angles at each point + // For example, if we shift the point P0 to the origin, + // the vectors defining the angle at P0 + // are v01 = (x1-x0, y1-y0) and v02 = (x2-x0, y2-y0) + // Note: v10 = -v01 and |v x w| = |w x v| + // so we only need 3 vectors and the order we use these doesn't matter + vector v01, v12, v20; + // + v01.push_back(x1-x0); v01.push_back(y1-y0); + v12.push_back(x2-x1); v12.push_back(y2-y1); + v20.push_back(x0-x2); v20.push_back(y0-y2); + + // sin(angle at P0) = |v01 x v02|/(|v01|*|v02|) = |v01x*v02y-v01y*v02x|/(sqrt(v01x^2+v01y^2)*sqrt(v01x^2+v02y^2)) + double sinP0 = fabs(v01[0]*v20[1]-v01[1]*v20[0])/sqrt((pow(v01[0],2)+pow(v01[1],2))*(pow(v12[0],2)+pow(v12[1],2))); + // sin(angle at P1) + double sinP1 = fabs(v12[0]*v20[1]-v12[1]*v20[0])/sqrt((pow(v12[0],2)+pow(v12[1],2))*(pow(v20[0],2)+pow(v20[1],2))); + // sin(angle at P2) + double sinP2 = fabs(v20[0]*v01[1]-v20[1]*v01[0])/sqrt((pow(v20[0],2)+pow(v20[1],2))*(pow(v01[0],2)+pow(v01[1],2))); + + // We will seek angles with sine near 0 (thus a multiple of 180 degrees or pi radians) + // we will use a tolerance of tol degrees (tol*pi/180 radians) + // compare the smallest sine value to the sine of tol, + // if it is less, then the angle is less than tol degrees or + // greater than 180-tol degrees, so points are almost colinear + double minSinValue = min(sinP0,min(sinP1,sinP2)); + if (minSinValue < sin(tol*PI/180)){ + return true; + } + else{ + return false; + } + } + + + /** + * This method is called by Load() to move a control point + * across the chip. + * + * @param *startSamp Sample value to be increased, or moved + * right. + * @param *startLine Line value to be increased, or moved + * downward. + * @param *endSamp Sample value to be decreased, or moved + * left. + * @param *endLine Line value to be decreased, or moved + * upward. + * + * @return @b vector < @b int > Vector containing the new + * sample and line values in the same order + * as the parameters passed into the method. + * @internal + * @author Tracie Sucharski + * @history 2010-05-24 Jeannie Walldren - Moved from Load() method to its own + * method since this code needed to be repeated several + * times. + */ + vector Chip::MovePoints(const int startSamp, const int startLine, const int endSamp, const int endLine){ + vector newlocations(4); + int sinc = (endSamp - startSamp) / 4; + // Ensures that the inc can cause start and end to cross + if (sinc < 1) { + sinc = 1; + } + int linc = (endLine - startLine) / 3; + // Ensures that the inc can cause start and end to cross + if (linc < 1) { + linc = 1; + } + newlocations[0] = startSamp + sinc; + newlocations[1] = startLine + linc; + newlocations[2] = endSamp - sinc; + newlocations[3] = endLine - linc; + return newlocations; + } + + /** + * Compute the position of the cube given a chip coordinate. Any + * rotation or geometric matching done during the Load process will + * be taken into account. Use the CubeSample and CubeLine methods + * to obtain results. Note the results could be outside of the cube + * + * @param sample chip sample coordinate + * @param line chip line coordinate + */ + void Chip::SetChipPosition (const double sample, const double line) { + p_chipSample = sample; + p_chipLine = line; + p_affine.Compute(sample-TackSample(),line-TackLine()); + p_cubeSample = p_affine.xp(); + p_cubeLine = p_affine.yp(); + } + + + /** + * Compute the position of the chip given a cube coordinate. Any + * rotation or geometric matching done during the Load process will + * be taken into account. Use the ChipSample and ChipLine methods + * to obtain results. Note that the results could be outside of the + * chip. + * + * @param sample chip sample coordinate + * @param line chip line coordinate + */ + void Chip::SetCubePosition (const double sample, const double line) { + p_cubeSample = sample; + p_cubeLine = line; + p_affine.ComputeInverse(sample,line); + p_chipSample = p_affine.x() + TackSample(); + p_chipLine = p_affine.y() + TackLine(); + } + + + /** + * Set the valid range of data in the chip. If never called all + * data in the chip is consider valid (other than special pixels). + * + * @param minimum minimum valid pixel value (default of Isis::ValidMinimum) + * @param maximum maximum valid pixel value (default of Isis::ValidMaximum) + * + * @throws Isis::iException::Programmer - First parameter must be smaller than + * the second. + * @internal + * @history 2010-06-10 Jeannie Walldren - Modified error message + */ + void Chip::SetValidRange (const double minimum, const double maximum) throw (iException &){ + if (minimum >= maximum) { + string msg = "Unable to set valid chip range to [" + iString(minimum); + msg += ", " + iString(maximum) + "]. First parameter must be smaller than the second."; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + p_validMinimum = minimum; + p_validMaximum = maximum; + } + + + /** + * Return if the pixel is valid at a particular position + * + * @param sample sample position to test + * @param line line position to test + * + * @return bool - Returns true if the pixel is valid, and false if it is not + */ + /* bool Chip::IsValid(int sample, int line) { + double value = (*this)(sample,line); + if (value < p_validMinimum) return false; + if (value > p_validMaximum) return false; + return true; + }*/ + + + /** + * Return if the total number of valid pixels in the chip meets a specified + * percentage of the entire chip. + * + * @param percentage The percentage that the valid pixels percentage must + * exceed + * + * @return bool Returns true if the percentage of valid pixels is greater + * than the specified percentage, and false if it is not + */ + bool Chip::IsValid(double percentage) { + int validCount = 0; + for (int samp=1; samp<=Samples(); samp++) { + for (int line=1; line<=Lines(); line++) { + if (IsValid(samp,line)) validCount++; + } + } + double validPercentage = 100.0 * (double) validCount / + (double) (Samples() * Lines()); + if (validPercentage < percentage) return false; + return true; + } + + + /** + * Extract a sub-chip from a chip. + * + * + * @param samples Number of samples in the extracted chip (must + * be less than or equal to "this" chip) + * @param lines Number of lines in the extracted chip (must + * be less than or equal to "this" chip) + * @param samp Input chip sample to be placed at output chip tack + * @param line Input chip line to be placed at output chip tack + * @return @b Chip Sub-chip extracted from the chip + * @throws Isis::iException::Programmer - Chip extraction invalid + * @internal + * @history 2010-06-10 Jeannie Walldren - Modified error message + */ + Chip Chip::Extract (int samples, int lines, int samp, int line) throw (iException &){ + if (samples > Samples() || lines > Lines()) { + string msg = "Cannot exatract sub-chip of size [" + iString(samples); + msg += ", " + iString(lines) + "] from chip of size [" + iString(Samples()); + msg += ", " + iString(Lines()) + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + Chip chipped(samples,lines); + for (int oline=1; oline<=lines; oline++) { + for (int osamp=1; osamp<=samples; osamp++) { + int thisSamp = samp + (osamp - chipped.TackSample()); + int thisLine = line + (oline - chipped.TackLine()); + if ((thisSamp < 1) || (thisLine < 1) || + (thisSamp > Samples()) || thisLine > Lines()) { + chipped.SetValue(osamp,oline, Isis::Null); + } + else { + chipped.SetValue(osamp,oline, GetValue(thisSamp,thisLine)); + } + } + } + + chipped.p_affine = p_affine; + chipped.p_validMinimum = p_validMinimum; + chipped.p_validMaximum = p_validMaximum; + chipped.p_tackSample = chipped.TackSample() + TackSample() - samp; + chipped.p_tackLine = chipped.TackLine() + TackLine() - line; + + return chipped; + } + + /** + * @brief Extract a subchip centered at the designated coordinate + * + * This method extracts a subchip that is centered at the given sample and + * line coordinate. All appropriate variables in the given chipped parameter + * are set appropriately prior to return. + * + * @param samp Center (tack) sample chip coordinate to extract subchip + * @param line Center (tack) line chip coordinate to extract subchip + * @param chipped Chip to load the subchip in and return to caller + */ + void Chip::Extract (int samp, int line, Chip &chipped) { + int samples = chipped.Samples(); + int lines = chipped.Lines(); + //chipped.Init(samples, lines); + chipped.p_tackSample = ((samples - 1) / 2) + 1; + chipped.p_tackLine = ((lines - 1) / 2) + 1; + + for (int oline=1; oline<=lines; oline++) { + for (int osamp=1; osamp<=samples; osamp++) { + int thisSamp = samp + (osamp - chipped.TackSample()); + int thisLine = line + (oline - chipped.TackLine()); + if ((thisSamp < 1) || (thisLine < 1) || + (thisSamp > Samples()) || thisLine > Lines()) { + chipped.SetValue(osamp,oline, Isis::Null); + } + else { + chipped.SetValue(osamp,oline,GetValue(thisSamp,thisLine)); + } + } + } + + chipped.p_affine = p_affine; + chipped.p_validMinimum = p_validMinimum; + chipped.p_validMaximum = p_validMaximum; + chipped.p_tackSample = chipped.TackSample() + TackSample() - samp; + chipped.p_tackLine = chipped.TackLine() + TackLine() - line; + + return; + } + + + /** + * @brief Extract a subchip of this chip using an Affine transform + * + * This method will translate the data in this chip using an Affine transform + * to the output chip as provided. Note that the Affine transformation is only + * applied within the confines of this chip. No file I/O is performed. + * + * A proper Affine transform should not deviate too much from the identity as + * the mapping operation may result in a NULL filled chip. The operation of + * this affine is added to the existing affine so that proper relationship to + * the input cube (and any affine operations applied at load time) is + * preserved. This implies that the resulting affine should yield nearly + * identical results when read directly from the cube. + * + * Bilinear interpolation is applied to surrounding transformed pixels to + * provide each new output pixel. + * + * The chipped parameter will be updated to fully reflect the state of this + * original chip. The state of the chipped parameter dictates the size and + * the tack sample and line coordinates. Upon return, the corresponding cube + * sample and line coordinate is updated to the tack sample and line chip + * coordinate. + * + * As such, note that an identity affine transform will yield identical + * results to the Chip::Extract method specifying the tack sample and line as + * the location to extract. + * + * The following example demonstrates how to linearly shift a chip one pixel + * right and one down. + * @code + * Chip mychip(35,35); + * Cube cube("mycube.cub"); + * mychip.TackCube(200.0,200.0); + * mychip.Load(cube); + * + * Affine shift; + * shift.Translate(-1.0,-1.0); + * + * Chip ochip(15,15); + * mychip.Extract(ochip, shift); + * @endcode + * + * @param chipped Input/output chip containing the transformed subchip + * @param affine Affine transform to apply to extract subchip + */ + void Chip::Extract (Chip &chipped, Affine &affine) { + // Create an interpolator and portal for interpolation + Interpolator interp(Interpolator::BiLinearType); + Portal port(interp.Samples(),interp.Lines(),Isis::Double, + interp.HotSample(),interp.HotLine()); + + int samples = chipped.Samples(); + int lines = chipped.Lines(); + + for (int oline=1; oline<=lines; oline++) { + int thisLine = TackLine() + (oline - chipped.TackLine()); + for (int osamp=1; osamp<=samples; osamp++) { + int thisSamp = TackSample() + (osamp - chipped.TackSample()); + affine.Compute(thisSamp,thisLine); + double xp = affine.xp(); + double yp = affine.yp(); + port.SetPosition(xp, yp, 1); + for (int i = 0 ; i < port.size() ; i++) { + int csamp = port.Sample(i); + int cline = port.Line(i); + if ((csamp < 1) || (cline < 1) || + (csamp > Samples()) || cline > Lines()) { + port[i] = Isis::Null; + } + else { + port[i] = GetValue(csamp,cline); + } + } + chipped.SetValue(osamp,oline,interp.Interpolate (xp, yp, port.DoubleBuffer())); + } + } + + chipped.p_validMinimum = p_validMinimum; + chipped.p_validMaximum = p_validMaximum; + chipped.p_filename = p_filename; + + // Update the affine + Affine::AMatrix taffine = p_affine.Forward() + + (affine.Forward() - Affine::getIdentity()); + + chipped.p_affine = Affine(taffine); + chipped.SetChipPosition(chipped.TackSample(), chipped.TackLine()); + return; + } + + + /** + * Returns a statistics object of the current data in the chip. + * + * The caller takes ownership of the returned instance. + * + * @return Isis::Statistics* Statistics of the data in the chip + */ + Isis::Statistics *Chip::Statistics() { + Isis::Statistics *stats = new Isis::Statistics(); + + stats->SetValidRange(p_validMinimum, p_validMaximum); + + for (int i = 0; i < p_chipSamples; i++) { + stats->AddData(&p_buf[i][0], p_chipLines); + } + + return stats; + } + + + /** + * This method will read data from a cube and put it into the chip. + * The affine transform is used in the SetChipPosition routine and + * therefore the geom of the chip is automatic. This method uses a default + * interpolator type of Cubic Convolution. This can be changed using the + * SetReadInterpolator() method, + * + * @param cube Cube to read data from + * @param band Band number to read data from + * @see SetReadInterpolator + * + * @todo We could modify the affine class to return the coefficients + * and then compute the derivative of the change in cube sample and line + * with respect to chip sample or line. The change might make the geom + * run a bit faster. + * @see SetReadInterpolator() + * @see GetReadInterpolator() + * @internal + * @history 2010-06-15 Jeannie Walldren - Modified to allow use of any + * interpolator type except "None" + */ + void Chip::Read(Cube &cube, const int band) { + // Create an interpolator and portal for geoming + Interpolator interp(p_readInterpolator); + Portal port(interp.Samples(),interp.Lines(),cube.PixelType(), + interp.HotSample(),interp.HotLine()); + // Loop through the pixels in the chip and geom them + for (int line=1; line<=Lines(); line++) { + for (int samp=1; samp<=Samples(); samp++) { + SetChipPosition((double)samp,(double)line); + if ((CubeSample() < 0.5) || (CubeLine() < 0.5) || + (CubeSample() > cube.Samples()+0.5) || + (CubeLine() > cube.Lines()+0.5)) { + p_buf[line-1][samp-1] = Isis::NULL8; + } + else if (p_clipPolygon == NULL) { + port.SetPosition (CubeSample(),CubeLine(), band); + cube.Read(port); + p_buf[line-1][samp-1] = + interp.Interpolate (CubeSample(), CubeLine(), port.DoubleBuffer()); + } + else { + geos::geom::Point *pnt = globalFactory.createPoint( + geos::geom::Coordinate(CubeSample(), CubeLine())); + if (pnt->within(p_clipPolygon)) { + port.SetPosition (CubeSample(),CubeLine(), band); + cube.Read(port); + p_buf[line-1][samp-1] = + interp.Interpolate (CubeSample(), CubeLine(), port.DoubleBuffer()); + } + else { + p_buf[line-1][samp-1] = Isis::NULL8; + } + delete pnt; + } + } + } + } + + + /** + * Writes the contents of the Chip to a cube. + * + * @param filename Name of the cube to create + */ + void Chip::Write (const string &filename) { + Cube c; + c.SetDimensions(Samples(),Lines(),1); + c.Create(filename); + LineManager line(c); + for (int i=1; i<=Lines(); i++) { + line.SetLine(i); + for (int j=1; j<=Samples(); j++) { + line[j-1] = GetValue(j,i); + } + c.Write(line); + } + c.Close(); + } + + + /** + * Sets the clipping polygon for this chip. The coordinates must be in + * (sample,line) order. All Pixel values outside this polygon will be set to + * Null8. The cubic convolution interpolation is allowed to uses valid pixels + * outside the clipping area. + * + * @param clipPolygon The polygons used to clip the chip + */ + void Chip::SetClipPolygon (const geos::geom::MultiPolygon &clipPolygon) { + if (p_clipPolygon != NULL) delete p_clipPolygon; + p_clipPolygon = PolygonTools::CopyMultiPolygon(clipPolygon); + } + +} // end namespace isis diff --git a/isis/src/base/objs/Chip/Chip.h b/isis/src/base/objs/Chip/Chip.h new file mode 100644 index 0000000000000000000000000000000000000000..531a0de0a5f8f64d30b8845a1a7fb636600b837e --- /dev/null +++ b/isis/src/base/objs/Chip/Chip.h @@ -0,0 +1,339 @@ +/** + * @file + * $Revision: 1.16 $ + * $Date: 2010/06/15 18:27:43 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef Chip_h +#define Chip_h + +#include + +#include "Affine.h" +#include "Interpolator.h" +#include "Pvl.h" +#include "SpecialPixel.h" +#include "geos/geom/MultiPolygon.h" + +using namespace std; +namespace Isis { + class Cube; + class Statistics; + + /** + * @brief A small chip of data used for pattern matching + * + * A chip is a small rectangular area that can be used for pattern + * matching. Data can be loaded into the chip manually or by reading + * directly from a cube. + * + * @ingroup PatternMatching + * + * @author 2005-05-05 Jeff Anderson + * + * @internal + * @history 2006-07-11 Tracie Sucharski - Added reLoad method to use + * p_cube instead of cube passed in. + * @history 2006-08-03 Tracie Sucharski - Added Load and ReLoad method + * to apply scale factor to chip. + * @history 2006-08-04 Stuart Sides - Added SetClipPolygon method. If the + * clip polygon is set all pixel values outside the + * polygon will be set to NULL. + * @history 2007-10-01 Steven Koechle - Fixed inc in LoadChip to fix an + * infinite loop problem when x.size() never grew + * to be more than 3. + * @history 2009-01-19 Steven Koechle - Fixed memory leak + * @history 2009-06-02 Stacy Alley, Added a check in the SetSize() method to + * make sure the given samples and lines are not equal + * to or less than zero. + * @history 2009-08-19 Kris Becker - Added new Extract method that applies an + * Affine transform to the extract a portion of the + * chip; added an assigment operator that sets the + * entire chip to a single value for convenience; + * added a getter that returns a const reference to the + * internal Affine transform of this chip. + * @history 2009-08-20 Steven Lambright - Removed local cube pointer and + * parenthesis operator + * @history 2009-08-20 Travis Addair - Added Statistics method + * @history 2009-08-28 Kris Becker - Added new Affine setter method to + * establish a new Affine transform to the chip; added + * another Load method that uses a new Affine transform + * to load a chip from a cube. + * @history 2009-09-01 Travis Addair, Added valid Min/Max pixel value + * functionality for Statistics method + * @history 2010-01-28 Tracie Sucharski - In the Load method (with match + * chip) when calculating control points away from the + * corners, added a linc to move into the center of the + * chip in a non-linear fashion to prevent control + * points that fall in a line and cause the matrix + * inversion to fail. + * @history 2010-05-24 Jeannie Walldren - Fixed bug in the Load() method + * (with match chip). Modified to look for control + * points from each corner, rather than looping around. + * Added a method, PointsColinear() to check whether + * the points added are almost along the same line. + * Moved the code from Load() that chose new points to + * a new method, MovePoints(). + * @history 2010-06-10 Jeannie Walldren - Modified PointsColinear() method to + * take in user defined tolerance as parameter to allow + * registration of more narrow search chip areas. + * Updated documentation, error messages and unitTest. + * @history 2010-06-15 Jeannie Walldren - Added set and accessor methods for + * Read() method's Interpolator::interpType. Updated + * documentation and unitTest. + * + * @see AutoReg + * @see AutoRegFactory + */ + class Chip { + public: + Chip (); + Chip (const int samples, const int lines); + virtual ~Chip(); + + void SetSize (const int samples, const int lines) throw (iException &); + + bool IsInsideChip(double sample, double line); + + //! Return the number of samples in the chip + inline int Samples () const { return p_chipSamples; }; + + //! Return the number of lines in the chip + inline int Lines () const { return p_chipLines; }; + + //! Returns the expanded filename of the cube from + //! which this chip was chipped. + inline string Filename() const { return p_filename; }; + + void SetAllValues(const double &d); + + /** + * This sets a value in the chip + * + * @param sample Sample position to load (1-based) + * @param line Line position to load (1-based) + * @param value Value to set + */ + void SetValue(int sample, int line, const double &value) { + p_buf[line-1][sample-1] = value; + } + + /** + * Loads a Chip with a value. For example, + * @code + * Chip c(10,5); + * c(1,1) = 1.1; + * c(10,5) = 1.2; + * @endcode + * + * @param sample Sample position to load (1-based) + * @param line Line position to load (1-based) + */ + inline double GetValue(int sample,int line) { + return p_buf[line-1][sample-1]; + } + + /** Get a value from a Chip. For example, + * @code + * Chip c(10,5); + * cout << c[3,3] << endl; + * @endcode + * + * @param sample Sample position to get (1-based) + * @param line Line position to get (1-based) + */ + inline const double GetValue(int sample,int line) const { + return p_buf[line-1][sample-1]; + } + + void TackCube (const double cubeSample, const double cubeLine); + + /** + * Return the fixed tack sample of the chip. That is, the middle of the + * chip. It is a chip coordinate not a cube coordinate. For a chip with 5 + * samples, this will return 3, the middle pixel. For a chip with 4 + * samples it will return 2 + */ + inline int TackSample() const { return p_tackSample; }; + + /** + * Return the fixed tack line of the chip. That is, the middle of the + * chip. It is a chip coordinate not a cube coordinate. For a chip with 5 + * lines, this will return 3, the middle pixel. For a chip with 4 lines + * it will return 2 + */ + inline int TackLine() const { return p_tackLine; }; + + void Load(Cube &cube, const double rotation=0.0, const double scale=1.0, + const int band=1); + void Load(Cube &cube, Chip &match, Cube &matchChipCube, + const double scale=1.0, const int band=1) throw (iException &); + void Load(Cube &cube, const Affine &affine, const bool &keepPoly = true, + const int band=1); + + void SetChipPosition (const double sample, const double line); + + //! Returns cube sample after invoking SetChipPosition + inline double CubeSample() const { return p_cubeSample; }; + + //! Returns cube line after invoking SetChipPosition + inline double CubeLine() const { return p_cubeLine; }; + + void SetCubePosition (const double sample, const double line); + + //! Returns chip sample after invoking SetCubePosition + double ChipSample() const { return p_chipSample; }; + + //! Returns chip line after invoking SetCubePosition + double ChipLine() const { return p_chipLine; }; + + void SetValidRange (const double minimum = Isis::ValidMinimum, + const double maximum = Isis::ValidMaximum) throw (iException &); + bool IsValid(double percentage); + + /** Returns whether the value at the given sample, line position is within the + * valid range + * + * @param sample Sample position + * @param line Line position + */ + inline bool IsValid(int sample, int line) { + double value = GetValue(sample,line); + if (value < p_validMinimum) return false; + if (value > p_validMaximum) return false; + return true; + } + + Chip Extract (int samples, int lines, int samp, int line) throw (iException &); + void Extract (int samp, int line, Chip &output); + Isis::Statistics *Statistics(); + void Extract (Chip &output, Affine &affine); + void Write (const string &filename); + + void SetClipPolygon (const geos::geom::MultiPolygon &clipPolygon); + + /** + * @brief Returns the Affine transformation of chip-to-cube indices + * + * This method returns the affine transform used to load a chip from the + * same area as a match cube. It also is used to track the tack point + * line and sample translations from the chip indices to the absolute cube + * coordiates. + * + * @return @b const @b Affine& Transform map from chip coordinates to cube + * coordinates + */ + const Affine &GetTransform() const { return (p_affine); } + + /** + * @brief Sets the internal Affine transform to new translation + * + * Provides the ability to establish a new affine transformation without + * overhead of, say, loading the chip with a new translation. + * + * The caller also has the option to specify the disposition of an + * established polygon. + * + * @param affine New affine tranform to set for this chip + * @param keepPoly Indicates whether an existing polygon clipper should be kept + * (default of true) + */ + void SetTransform(const Affine &affine, const bool &keepPoly = true) { + p_affine = affine; + if (!keepPoly) { + delete p_clipPolygon; + p_clipPolygon = 0; + } + return; + } + + /** + * Access method that returns the Interpolator Type used for loading a chip. + * @return @b const @b Interpolator::interpType Interpolator used to read + * data from cube and put it into a chip. + * @see Read() + * @see SetReadInterpolator() + * @author Jeannie Walldren + * @internal + * @history 2010-06-05 Jeannie Walldren - Original version + */ + const Interpolator::interpType GetReadInterpolator () { return p_readInterpolator; } + + + /** + * Sets Interpolator Type for loading a chip. This type is used in the Read() + * method. + * @param type Interpolator type to be used. + * @throws Isis::iException::Programmer - Invalid Interpolator Type + * @see Read() + * @see SetReadInterpolator() + * @author Jeannie Walldren + * @internal + * @history 2010-06-05 Jeannie Walldren - Original version + */ + void SetReadInterpolator (const Interpolator::interpType type) { + if (type == Interpolator::NearestNeighborType || + type == Interpolator::BiLinearType || + type == Interpolator::CubicConvolutionType) { + p_readInterpolator = type; + return; + } + // Interpolator::None is not valid type + string msg = "Invalid Interpolator type. Cannot use ["; + msg += iString(type) + "] to read cube into chip."; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + private: + void Init (const int samples, const int lines); + void Read (Cube &cube, const int band); + vector MovePoints(const int startSamp, const int startLine, + const int endSamp, const int endLine); + bool PointsColinear(const double x0, const double y0, + const double x1, const double y1, + const double x2, const double y2, + const double tol ); + + + int p_chipSamples; //!< Number of samples in the chip + int p_chipLines; //!< Number of lines in the chip + vector > p_buf; //!< Chip buffer + int p_tackSample; //!< Middle sample of the chip + int p_tackLine; //!< Middle line of the chip + + double p_cubeTackSample; //!< cube sample at the chip tack + double p_cubeTackLine; //!< cube line at the chip tack + + double p_validMinimum; //!< valid minimum chip pixel value + double p_validMaximum; //!< valid maximum chip pixel value + + double p_chipSample; //!< chip sample set by SetChip/CubePosition + double p_chipLine; //!< chip line set by SetChip/CubePosition + double p_cubeSample; //!< cube sample set by SetCubePosition + double p_cubeLine; //!< cube line set by SetCubePosition + geos::geom::MultiPolygon *p_clipPolygon; //!< clipping polygon set by SetClipPolygon (line,samp) + + Affine p_affine; //!< Transform set by SetTransform. Used to load cubes into chip + Interpolator::interpType p_readInterpolator; //!< Interpolator type set by SetReadInterpolator. Used to read cubes into chip. + string p_filename; //!< Filename of loaded cube + }; +}; + +#endif diff --git a/isis/src/base/objs/Chip/Chip.truth b/isis/src/base/objs/Chip/Chip.truth new file mode 100644 index 0000000000000000000000000000000000000000..4ff824cc84bf4450ece48bff67757b61feea26b1 --- /dev/null +++ b/isis/src/base/objs/Chip/Chip.truth @@ -0,0 +1,204 @@ +Test basics +51 +50 +26 +25 +Test chip-to-cube and cube-to-chip mapping +453.5 +568.5 +428.5 +544.5 +1 +1 +Test assignment of chip data to constant +Test loading chip data +Valid tests +0 +1 +1 +0 +Extract test +2425 2426 2427 2428 +2525 2526 2527 2528 +2625 2626 2627 2628 +Test writing chip +Test load chip from cube with rotation + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 136 203.154 280.609 352.174 407.695 489.162 569.934 624.761 697.596 782.35 848.576 908.074 991.586 1069.18 1122.76 1199.81 1283.55 1343.82 1409.18 1493.84 1560.09 1631.51 1751 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 134 201.74 279.043 350.69 406.452 487.735 568.343 623.468 696.297 780.755 847.161 906.83 990.09 1067.62 1121.5 1198.46 1281.94 1342.47 1407.92 1492.29 1565.84 1620.61 1701.51 1772.93 1851 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 133 200.326 277.708 349.422 404.885 486.251 567.099 622.041 694.705 779.462 845.862 905.234 988.675 1066.37 1120 1196.9 1280.68 1341.13 1406.31 1490.93 1564.58 1619.06 1699.3 1781.19 1842.93 1914.35 1951 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 132 198.912 276.343 347.816 403.55 484.983 565.532 620.557 693.461 778.035 844.27 903.941 987.376 1064.78 1118.59 1195.66 1279.18 1339.57 1405.05 1489.59 1562.98 1617.71 1698.05 1779.64 1835.8 1906.71 1984.36 2055.77 2151 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 130 197.497 274.802 346.561 402.185 483.377 564.198 619.289 691.894 776.551 843.027 902.515 985.784 1063.49 1117.29 1194.06 1277.76 1338.32 1403.55 1488.03 1561.71 1616.36 1696.44 1778.29 1834.54 1905.16 1989.95 2058.73 2125.78 2197.2 2251 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 129 196.083 273.553 345.041 400.644 482.122 562.833 617.683 690.56 775.283 841.46 901.03 984.541 1062.06 1115.7 1192.77 1276.47 1336.72 1402.14 1486.78 1560.22 1614.8 1695.18 1776.95 1832.93 1903.81 1988.69 2057.18 2114.84 2197.62 2267.2 2338.62 2451 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 127 194.669 271.95 343.652 399.395 480.602 561.291 616.428 689.195 773.677 840.125 899.762 982.974 1060.57 1114.45 1191.34 1274.87 1335.43 1400.84 1485.19 1558.8 1613.56 1693.68 1775.39 1831.67 1902.47 1987.09 2055.82 2113.59 2196.07 2275.06 2329.2 2408.62 2480.04 2551 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 126 193.255 270.671 342.336 397.793 479.213 560.042 614.908 687.653 772.422 838.76 898.156 981.639 1059.31 1112.89 1189.86 1273.63 1334.01 1399.25 1483.89 1557.5 1611.96 1692.27 1774.14 1830.17 1900.91 1985.82 2054.48 2111.98 2194.72 2273.8 2327.65 2402.98 2487.28 2550.04 2621.46 2651 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 125 191.841 269.215 340.755 396.514 477.897 558.44 613.519 686.404 770.902 837.219 896.901 980.274 1057.7 1111.55 1188.59 1272.06 1332.52 1398 1482.47 1555.91 1610.67 1690.97 1772.55 1828.76 1899.66 1984.33 2052.92 2110.72 2193.37 2272.2 2326.3 2401.73 2485.73 2548.57 2611.54 2691.46 2762.88 2851 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 123 190.426 267.76 339.513 395.058 476.316 557.161 612.203 684.802 769.513 835.97 895.381 978.733 1056.45 1110.19 1186.99 1270.73 1331.25 1396.43 1480.98 1554.67 1609.24 1689.37 1771.25 1827.46 1898.07 1982.91 2051.67 2109.22 2191.81 2270.93 2324.95 2400.12 2484.37 2547.31 2609.99 2694.15 2769.61 2832.88 2904.3 2951 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 122 189.012 266.48 337.932 393.602 475.074 555.705 610.622 683.523 768.197 834.368 893.992 977.484 1054.93 1108.65 1185.73 1269.36 1329.65 1395.1 1479.72 1553.1 1607.76 1688.13 1769.83 1825.87 1896.77 1981.61 2050.08 2107.81 2190.57 2269.44 2323.39 2398.85 2483.03 2545.7 2608.64 2692.89 2768.06 2822.07 2901.19 2974.31 3045.72 3151 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 120 187.598 264.878 336.616 392.323 473.493 554.249 609.38 682.067 766.616 833.088 892.676 975.882 1053.54 1107.4 1184.21 1267.82 1328.39 1393.74 1478.11 1551.77 1606.49 1686.56 1768.34 1824.62 1895.35 1980.02 2048.79 2106.51 2188.97 2268.02 2322.15 2397.36 2481.47 2544.44 2607.29 2691.29 2766.71 2820.82 2899.64 2982.29 3040.09 3115.73 3187.14 3251 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 119 186.184 263.629 335.227 390.721 472.177 552.97 607.799 680.611 765.374 831.633 891.096 974.603 1052.22 1105.79 1182.82 1266.57 1326.87 1392.19 1476.85 1550.4 1604.88 1685.23 1767.07 1823.06 1893.86 1978.78 2047.36 2104.91 2187.68 2266.72 2320.55 2395.94 2480.22 2542.94 2605.73 2690.02 2765.37 2819.21 2898.29 2981.03 3038.54 3107.18 3192.1 3257.15 3328.57 3351 -1.79769e+308 + -1.79769e+308 -1.79769e+308 118 184.769 262.088 333.707 389.472 470.788 551.368 606.483 679.332 763.793 830.177 889.853 973.147 1050.64 1104.52 1181.51 1264.97 1325.48 1390.94 1475.33 1548.86 1603.63 1683.86 1765.47 1821.72 1892.59 1977.21 2045.87 2103.67 2186.25 2265.13 2319.26 2394.64 2478.63 2541.53 2604.49 2688.53 2763.81 2817.95 2896.95 2979.43 3037.18 3105.92 3190.55 3261.34 3317.62 3398.57 3469.99 3551 + -1.79769e+308 116 183.355 260.723 332.452 387.93 469.268 550.119 605.094 677.73 762.477 828.898 888.272 971.691 1049.4 1103.06 1179.92 1263.69 1324.17 1389.34 1473.95 1547.61 1602.11 1682.32 1764.21 1820.36 1890.99 1975.88 2044.61 2102.1 2184.77 2263.89 2317.83 2393.05 2477.33 2540.23 2602.89 2687.11 2762.56 2816.45 2895.39 2978.16 3035.84 3104.32 3189.2 3260.08 3316.07 3397.83 3478.21 3539.99 3611.41 + 115 181.941 259.388 330.846 386.565 468.013 548.577 603.574 676.481 761.088 827.295 886.956 970.412 1047.82 1101.6 1178.68 1262.24 1322.59 1388.06 1472.63 1546.01 1600.72 1681.07 1762.69 1818.82 1889.73 1974.51 2043 2100.77 2183.5 2262.32 2316.35 2391.81 2475.91 2538.64 2601.6 2685.81 2760.97 2815.04 2894.14 2976.67 3034.28 3103.05 3187.85 3258.47 3314.72 3396.57 3476.66 3531.29 3604.98 3681.41 + 180.527 257.822 329.578 385.23 466.407 547.212 602.319 674.939 759.568 826.046 885.567 968.81 1046.5 1100.32 1177.1 1260.78 1321.34 1386.61 1471.05 1544.73 1599.4 1679.47 1761.3 1817.57 1888.21 1972.97 2041.75 2099.4 2181.9 2260.99 2315.08 2390.24 2474.42 2537.39 2600.17 2684.22 2759.67 2813.74 2892.55 2975.25 3033.04 3101.56 3186.29 3257.21 3313.37 3394.97 3475.3 3530.04 3603.43 3687.96 3753.44 + 256.578 328.094 383.664 465.139 545.878 600.713 673.575 758.313 824.505 884.047 967.561 1045.11 1098.72 1175.79 1259.5 1319.76 1385.15 1469.81 1543.27 1597.82 1678.19 1759.99 1815.96 1886.82 1971.72 2040.23 2097.86 2180.64 2259.62 2313.48 2388.91 2473.16 2535.83 2598.69 2682.98 2758.25 2812.14 2891.25 2973.95 3031.44 3100.14 3185.05 3255.71 3311.81 3393.7 3473.96 3528.43 3602.08 3686.7 3751.89 3812.33 + 326.667 382.42 463.655 544.311 599.445 672.24 756.707 823.14 882.792 966.019 1043.59 1097.47 1174.4 1257.9 1318.45 1383.87 1468.23 1541.82 1596.58 1676.74 1758.41 1814.69 1885.51 1970.12 2038.84 2096.61 2179.12 2258.08 2312.22 2387.54 2471.55 2534.49 2597.42 2681.41 2756.76 2810.9 2889.83 2972.36 3030.15 3098.84 3183.45 3254.3 3310.57 3392.21 3472.4 3527.17 3600.73 3685.1 3750.54 3811.07 3894.56 + 380.828 462.228 543.067 597.961 670.673 755.439 821.805 881.186 964.654 1042.34 1095.93 1172.88 1256.65 1317.06 1382.27 1466.91 1540.54 1595 1675.28 1757.16 1813.23 1883.93 1968.84 2037.52 2095.01 2177.73 2256.83 2310.7 2386 2470.29 2533.13 2595.81 2680.08 2755.49 2809.33 2888.34 2971.12 3028.72 3097.25 3182.16 3253 3308.97 3390.79 3471.15 3525.67 3599.17 3683.83 3749.19 3809.47 3893.2 3970.25 + 460.935 541.475 596.534 669.429 753.954 820.239 879.919 963.319 1040.73 1094.57 1171.62 1255.11 1315.54 1381.02 1465.52 1538.94 1593.68 1674 1755.58 1811.77 1882.68 1967.39 2035.94 2093.73 2176.42 2255.23 2309.31 2384.75 2468.77 2531.59 2594.56 2678.71 2753.89 2808 2887.07 2969.55 3027.24 3096.01 3180.73 3251.41 3307.68 3389.49 3469.56 3524.25 3597.93 3682.34 3747.63 3808.2 3891.86 3968.64 4022.48 + 540.176 595.241 667.838 752.528 818.995 878.434 961.753 1039.46 1093.23 1170.02 1253.74 1314.28 1379.48 1464 1537.69 1592.3 1672.4 1754.27 1810.49 1881.1 1965.93 2034.7 2092.28 2174.84 2253.95 2308 2383.15 2467.39 2530.34 2593.04 2677.17 2752.63 2806.63 2885.47 2968.22 3025.97 3094.44 3179.25 3250.16 3306.25 3387.9 3468.26 3522.96 3596.33 3680.92 3746.39 3806.71 3890.3 3967.38 4021.14 4098.56 + 593.646 666.539 751.235 817.403 877.007 960.509 1037.98 1091.67 1168.75 1252.41 1312.68 1378.11 1462.75 1536.15 1590.78 1671.15 1752.88 1808.89 1879.79 1964.65 2033.12 2090.82 2173.59 2252.49 2306.42 2381.87 2466.07 2528.74 2591.65 2675.92 2751.11 2805.09 2884.21 2966.85 3024.36 3093.11 3177.98 3248.6 3304.77 3386.66 3466.84 3521.36 3595.04 3679.62 3744.79 3805.29 3889.05 3965.88 4019.58 4097.29 4180.69 + 665.123 749.64 816.104 875.714 958.917 1036.55 1090.42 1167.26 1250.84 1311.41 1376.78 1461.14 1534.78 1589.52 1669.61 1751.36 1807.64 1878.4 1963.05 2031.8 2089.54 2172.01 2251.04 2305.17 2380.42 2464.49 2527.46 2590.33 2674.32 2749.72 2803.84 2882.69 2965.31 3023.11 3091.74 3176.38 3247.26 3303.5 3385.09 3465.35 3520.12 3593.61 3678.03 3743.5 3803.99 3887.46 3964.47 4018.34 4095.8 4179.13 4238.81 + 748.395 814.689 874.119 957.618 1035.26 1088.83 1165.84 1249.6 1309.92 1375.21 1459.87 1533.45 1587.91 1668.24 1750.1 1806.1 1876.88 1961.8 2030.41 2087.94 2170.7 2249.76 2303.59 2378.96 2463.25 2526 2588.75 2673.04 2748.41 2802.24 2881.3 2964.06 3021.59 3090.2 3175.12 3245.9 3301.9 3383.76 3464.09 3518.55 3592.13 3676.79 3742.08 3802.4 3886.16 3963.17 4016.74 4094.38 4177.88 4237.31 4303.61 + 813.193 872.874 956.203 1033.66 1087.53 1164.54 1248.01 1308.5 1373.97 1458.39 1531.88 1586.65 1666.91 1748.5 1804.74 1875.62 1960.26 2028.89 2086.69 2169.31 2248.16 2302.28 2377.68 2461.67 2524.54 2587.51 2671.58 2746.83 2800.96 2879.99 2962.46 3020.2 3088.95 3173.6 3244.36 3300.64 3382.39 3462.48 3517.22 3590.86 3675.22 3740.59 3801.16 3884.74 3961.58 4015.45 4093.08 4176.29 4235.9 4302.36 4386.88 + 871.314 954.707 1032.42 1086.12 1162.95 1246.71 1307.21 1372.38 1456.96 1530.64 1585.16 1665.34 1747.23 1803.4 1874.02 1958.89 2027.64 2085.15 2167.79 2246.91 2300.89 2376.08 2460.35 2523.26 2585.93 2670.13 2745.58 2799.51 2878.41 2961.18 3018.88 3087.35 3172.21 3243.11 3299.12 3380.85 3461.22 3515.85 3589.25 3673.89 3739.32 3799.59 3883.25 3960.33 4014.02 4091.49 4174.99 4234.6 4300.76 4385.46 4458.35 + 953.444 1030.86 1084.62 1161.7 1245.29 1305.61 1371.08 1455.67 1529.04 1583.74 1664.1 1745.75 1801.84 1872.75 1957.56 2026.03 2083.78 2166.53 2245.37 2299.37 2374.83 2458.96 2521.66 2584.61 2668.85 2744 2798.05 2877.16 2959.72 3017.3 3086.07 3170.9 3241.51 3297.73 3379.6 3459.7 3514.31 3588 3672.52 3737.72 3798.26 3881.98 3958.77 4012.54 4090.25 4173.57 4233.01 4299.47 4384.16 4456.76 4511.82 + 1029.52 1083.36 1160.14 1243.8 1304.37 1369.66 1454.07 1527.75 1582.44 1662.51 1744.32 1800.59 1871.27 1955.99 2024.76 2082.45 2164.93 2244 2298.11 2373.29 2457.44 2520.41 2583.23 2667.25 2742.69 2796.77 2875.58 2958.27 3016.06 3084.61 3169.32 3240.23 3296.42 3378 3458.32 3513.06 3586.48 3670.98 3736.46 3796.89 3880.38 3957.43 4011.27 4088.68 4172.08 4231.76 4298.05 4382.57 4455.47 4510.52 4591.06 + 1081.75 1158.8 1242.53 1302.81 1368.17 1452.83 1526.33 1580.85 1661.21 1743.03 1799 1869.84 1954.75 2023.28 2080.88 2163.66 2242.67 2296.51 2371.92 2456.19 2518.87 2581.71 2666 2741.3 2795.17 2874.27 2956.99 3014.48 3083.16 3168.07 3238.77 3294.84 3376.72 3457 3511.46 3585.09 3669.73 3734.94 3795.35 3879.12 3956.07 4009.66 4087.35 4170.81 4230.19 4296.56 4381.33 4454.04 4508.93 4589.77 4671.17 + 1157.44 1240.93 1301.46 1366.9 1451.27 1524.83 1579.6 1659.79 1741.43 1797.7 1868.55 1953.16 2021.85 2079.64 2162.17 2241.1 2295.24 2370.59 2454.58 2517.51 2580.45 2664.46 2739.78 2793.92 2872.88 2955.39 3013.16 3081.88 3166.49 3237.31 3293.59 3375.26 3455.42 3510.18 3583.77 3668.13 3733.55 3794.1 3877.6 3954.53 4008.41 4085.98 4169.21 4228.86 4295.29 4379.76 4452.55 4507.69 4588.35 4669.58 4725.33 + 1239.67 1300.11 1365.3 1449.92 1523.57 1578.04 1658.3 1740.19 1796.29 1866.95 1951.86 2020.56 2078.05 2160.75 2239.86 2293.75 2369.02 2453.31 2516.17 2578.84 2663.09 2738.52 2792.38 2871.36 2954.14 3011.77 3080.28 3165.18 3236.04 3292.01 3373.81 3454.18 3508.73 3582.19 3666.85 3732.24 3792.5 3876.21 3953.28 4006.89 4084.44 4167.95 4227.5 4293.69 4378.43 4451.29 4506.12 4586.86 4668.34 4723.91 4795.42 + 1298.56 1364.04 1448.57 1521.96 1576.7 1657.03 1738.63 1794.79 1865.71 1950.44 2018.96 2076.75 2159.45 2238.26 2292.33 2367.78 2451.83 2514.61 2577.58 2661.76 2736.92 2791.01 2870.1 2952.6 3010.25 3079.03 3163.79 3234.43 3290.7 3372.53 3452.6 3507.27 3580.95 3665.39 3730.66 3791.22 3874.9 3951.68 4005.5 4083.19 4166.43 4225.95 4292.43 4377.06 4449.68 4504.79 4585.59 4666.77 4722.42 4794.18 4878.86 + 1370.59 1447.02 1520.71 1575.34 1655.43 1737.28 1793.53 1864.15 1948.95 2017.72 2075.33 2157.86 2236.96 2291.03 2366.19 2450.4 2513.36 2576.09 2660.19 2735.65 2789.68 2868.5 2951.23 3009 3077.49 3162.27 3233.18 3289.31 3370.93 3451.28 3505.99 3579.37 3663.94 3729.41 3789.76 3873.32 3950.4 4004.18 4081.59 4165.04 4224.7 4290.91 4375.52 4448.43 4503.42 4583.99 4665.43 4721.15 4792.61 4877.38 4941.48 + 1440.59 1512.01 1573.79 1654.17 1735.93 1791.92 1862.8 1947.68 2016.16 2073.84 2156.61 2235.55 2289.44 2364.89 2449.11 2511.77 2574.67 2658.95 2734.17 2788.11 2867.23 2949.9 3007.39 3076.12 3161.01 3231.64 3287.79 3369.68 3449.89 3504.39 3578.05 3662.66 3727.83 3788.31 3872.08 3948.94 4002.6 4080.31 4163.73 4223.1 4289.52 4374.27 4446.91 4501.88 4582.73 4664.07 4719.55 4791.28 4876.11 4940.06 5011.48 + 1501 1582.01 1653.43 1734.38 1790.66 1861.45 1946.08 2014.82 2072.57 2155.05 2234.05 2288.19 2363.47 2447.51 2510.47 2573.37 2657.36 2732.74 2786.87 2865.75 2948.33 3006.13 3074.79 3159.41 3230.28 3286.53 3368.14 3448.37 3503.14 3576.67 3661.06 3726.52 3787.03 3870.49 3947.48 4001.36 4078.85 4162.15 4221.82 4288.21 4372.67 4445.52 4500.63 4581.21 4662.53 4718.29 4789.91 4874.5 4938.65 5010.07 5036 + -1.79769e+308 1701 1723.43 1794.85 1859.9 1944.82 2013.46 2070.97 2153.71 2232.79 2286.63 2361.98 2446.27 2509.06 2571.78 2656.06 2731.45 2785.28 2864.32 2947.09 3004.64 3073.22 3158.14 3228.94 3284.93 3366.77 3447.12 3501.6 3575.15 3659.81 3725.13 3785.43 3869.18 3946.21 3999.78 4077.4 4160.9 4220.37 4286.63 4371.39 4444.2 4499.03 4579.82 4661.28 4716.77 4788.37 4873.25 4937.23 5008.65 5034 -1.79769e+308 + -1.79769e+308 -1.79769e+308 1801 1864.86 1936.27 2011.91 2069.71 2152.36 2231.18 2285.29 2360.71 2444.71 2507.56 2570.53 2654.64 2729.85 2783.98 2863.03 2945.49 3003.21 3071.98 3156.65 3227.38 3283.66 3365.44 3445.51 3500.23 3573.89 3658.26 3723.61 3784.18 3867.79 3944.6 3998.46 4076.12 4159.32 4218.91 4285.38 4369.93 4442.62 4497.75 4578.51 4659.68 4715.38 4787.12 4871.73 4935.82 5007.24 5033 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 1901 2006.28 2077.69 2150.81 2229.93 2283.94 2359.11 2443.36 2506.3 2568.97 2653.15 2728.61 2782.56 2861.43 2944.19 3001.92 3070.39 3155.23 3226.13 3282.17 3363.87 3444.24 3498.9 3572.28 3656.9 3722.35 3782.64 3866.27 3943.35 3997.07 4074.52 4158.01 4217.63 4283.8 4368.48 4441.38 4496.3 4576.93 4658.4 4714.07 4785.52 4870.34 4934.41 5005.82 5032 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2101 2147.7 2219.12 2282.39 2357.85 2442.01 2504.69 2567.63 2651.88 2727.05 2781.07 2860.19 2942.78 3000.33 3069.09 3153.93 3224.54 3280.75 3362.63 3442.76 3497.33 3571.02 3655.57 3720.75 3781.27 3865.01 3941.81 3995.55 4073.27 4156.62 4216.03 4282.49 4367.2 4439.8 4494.84 4575.68 4656.94 4712.49 4784.24 4869.02 4932.99 5004.41 5030 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2201 2289.12 2360.54 2440.46 2503.43 2566.27 2650.27 2725.7 2779.8 2858.63 2941.28 2999.08 3067.67 3152.34 3223.24 3279.45 3361.03 3441.33 3496.09 3569.53 3654 3719.48 3779.94 3863.41 3940.45 3994.3 4071.73 4155.1 4214.78 4281.1 4365.6 4438.48 4493.56 4574.1 4655.49 4711.24 4782.78 4867.44 4931.58 5003 5029 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2401 2430.54 2501.96 2564.72 2649.02 2724.35 2778.2 2857.28 2940.02 2997.52 3066.18 3151.09 3221.83 3277.86 3359.73 3440.04 3494.5 3568.11 3652.75 3717.99 3778.37 3862.14 3939.11 3992.69 4070.36 4153.84 4213.24 4279.58 4364.35 4437.09 4491.96 4572.79 4654.21 4709.66 4781.33 4866.2 4930.16 5001.58 5027 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2501 2571.96 2643.38 2722.8 2776.94 2855.93 2938.41 2996.18 3064.91 3149.53 3220.33 3276.61 3358.32 3438.44 3493.2 3566.81 3651.16 3716.57 3777.13 3860.66 3937.55 3991.43 4069.03 4152.24 4211.87 4278.32 4362.81 4435.57 4490.71 4571.4 4652.61 4708.35 4780.05 4864.62 4928.75 5000.17 5026 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2601 2713.38 2784.8 2854.38 2937.16 2994.82 3063.31 3148.19 3219.07 3275.05 3356.82 3437.2 3491.78 3565.22 3649.86 3715.28 3775.53 3859.23 3936.3 3989.94 4067.46 4150.97 4210.54 4276.72 4361.44 4434.32 4489.17 4569.88 4651.36 4706.96 4778.45 4863.3 4927.33 4998.75 5025 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2801 2854.8 2926.22 2993.27 3062.05 3146.84 3217.46 3273.71 3355.56 3435.64 3490.29 3563.97 3648.45 3713.68 3774.24 3857.94 3934.71 3988.51 4066.22 4149.49 4208.97 4275.45 4360.11 4432.71 4487.8 4568.62 4649.81 4705.44 4777.2 4861.91 4925.92 4997.34 5023 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2901 2996.23 3067.64 3145.29 3216.2 3272.36 3353.95 3434.29 3489.02 3562.41 3646.95 3712.43 3772.82 3856.34 3933.41 3987.22 4064.62 4148.06 4207.73 4273.96 4358.54 4431.44 4486.47 4567.02 4648.45 4704.18 4775.66 4860.39 4924.51 4995.92 5022 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 3101 3137.65 3209.07 3270.81 3352.7 3432.94 3487.42 3561.07 3645.69 3710.87 3771.32 3855.1 3932 3985.63 4063.32 4146.77 4206.14 4272.54 4357.3 4429.96 4484.9 4565.75 4647.11 4702.58 4774.29 4859.14 4923.09 4994.51 5020 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 3201 3279.07 3350.49 3431.39 3486.16 3559.71 3644.08 3709.53 3770.06 3853.54 3930.5 3984.38 4061.91 4145.17 4204.84 4271.25 4355.7 4428.53 4483.66 4564.26 4645.55 4701.31 4772.96 4857.53 4921.68 4993.1 5019 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 3301 3420.49 3491.91 3558.16 3642.82 3708.18 3768.45 3852.19 3929.24 3982.82 4060.41 4143.93 4203.42 4269.65 4354.4 4427.24 4482.07 4562.84 4644.3 4699.83 4771.39 4856.26 4920.26 4991.68 5018 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 3501 3561.91 3633.33 3706.63 3767.2 3850.84 3927.63 3981.48 4059.15 4142.37 4201.93 4268.41 4352.99 4425.64 4480.77 4561.55 4642.71 4698.4 4770.15 4854.78 4918.85 4990.27 5016 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 +Test load chip from cube with rotation and clipping polygon + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2253.95 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2252.49 2306.42 2381.87 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2251.04 2305.17 2380.42 2464.49 2527.46 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2249.76 2303.59 2378.96 2463.25 2526 2588.75 2673.04 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2461.67 2524.54 2587.51 2671.58 2746.83 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 2670.13 2745.58 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 -1.79769e+308 + +Testing Affine transformation extraction (-1, -1)... +Cube Sample, Line = 26, 25 +Shift Cube Sample, Line = 25, 24 +New Cube Sample, Line = 25, 24 +I/O Nulls: 0 +Shift Nulls: 0 +Sum Diff: 0 + +Testing direct Affine Application... +Affine Cube Sample, Line = 25, 24 + +Test reading with new Affine transform... +I/O Nulls: 0 +Shift Nulls: 0 +Sum Diff: 0 +Affine Cube loaded at Sample, Line = 25, 24 + +Test reading with match chip and cube... + +Match chip values... + 0.0318189 0.0311426 0.0310773 0.0316069 + 0.0317859 0.0313744 0.0311243 0.0312174 + 0.0319391 0.0316342 0.0313629 0.0312892 + 0.0331934 0.0326919 0.0317496 0.0313146 + +New chip values... + 0.0318187 0.0311423 0.0310775 0.031607 + 0.0317859 0.0313744 0.0311243 0.0312174 + 0.0319395 0.0316345 0.0313631 0.0312893 + 0.0331939 0.0326931 0.0317508 0.0313149 +Passes if difference is less than EPSILON = 2e-06 + -1.94545e-07 -3.20125e-07 2.07761e-07 1.26571e-07 + 7.14045e-09 0 -2.17735e-09 -2.72403e-09 + 3.85854e-07 2.50248e-07 1.44934e-07 6.02544e-08 + 4.61695e-07 1.25204e-06 1.17625e-06 2.32237e-07 + + +Test interpolator set/get methods +default: 4 +nearest neighbor: 1 +bilinear: 2 +cubic convolution: 4 + + +Generate Errors: +Try to set interpolator to type 0 (Interpolator::None): +**PROGRAMMER ERROR** Invalid Interpolator type. Cannot use [0] to read cube into chip. + +Try to set interpolator to type 3 (enum value not assigned): +**PROGRAMMER ERROR** Invalid Interpolator type. Cannot use [3] to read cube into chip. + +Try to set chip size with input parameter equal to 0: +**USER ERROR** Unable to set chip size to [0, 1]. Samples and lines must be greater than zero. + +Try to load a cube that is not camera or map projection: +**USER ERROR** Can not geom chip. Chip cube [junk.cub] is not a camera or map projection +**PROJECTION ERROR** Unable to initialize cube projection from file [junk.cub] +**PVL ERROR** Unable to find group [Mapping] in file [junk.cub] +**CAMERA ERROR** Unable to initialize camera model from group [Instrument] +**PVL ERROR** Unable to find group [Instrument] in file [junk.cub] + +Try to load a cube with a match cube that is not camera or map projection: +**USER ERROR** Can not geom chip. Match chip cube [junk.cub] is not a camera or map projection +**PROJECTION ERROR** Unable to initialize cube projection from file [junk.cub] +**PVL ERROR** Unable to find group [Mapping] in file [junk.cub] +**CAMERA ERROR** Unable to initialize camera model from group [Instrument] +**PVL ERROR** Unable to find group [Instrument] in file [junk.cub] + +Try to load a cube with match chip and cube that can not find at least 3 points for Affine Transformation: +**USER ERROR** Cannot find enough points to perform Affine transformation. Unable to load chip from [ab102401_ideal.cub] to match chip from [f319b18_ideal.cub]. + +Try to set valid range with larger number passed in as first parameter: +**PROGRAMMER ERROR** Unable to set valid chip range to [4.0, 3.0]. First parameter must be smaller than the second. + +Try to extract a sub-chip with samples or lines greater than original chip: +**PROGRAMMER ERROR** Cannot exatract sub-chip of size [2, 5] from chip of size [4, 4] + diff --git a/isis/src/base/objs/Chip/Makefile b/isis/src/base/objs/Chip/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..25cef4fb6f68a849da0f949c6311ee8149c2abee --- /dev/null +++ b/isis/src/base/objs/Chip/Makefile @@ -0,0 +1,5 @@ +INCS = Chip.h +SRCS = Chip.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Chip/unitTest.cpp b/isis/src/base/objs/Chip/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b654000a2c80c48c3855ebb5dd23ca94db84ff8d --- /dev/null +++ b/isis/src/base/objs/Chip/unitTest.cpp @@ -0,0 +1,428 @@ +#include +#include +#include + +#include "Affine.h" +#include "Chip.h" +#include "Cube.h" +#include "Filename.h" +#include "iString.h" +#include "LineManager.h" +#include "Preference.h" +#include "SpecialPixel.h" +#include "geos/geom/Coordinate.h" +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/geom/GeometryFactory.h" +#include "geos/geom/Polygon.h" +#include "geos/geom/MultiPolygon.h" + +using namespace std; +using namespace Isis; + +int main () { + Preference::Preferences(true); + void ReportError(iString err); + Chip chip(51, 50); + cout << "Test basics" << endl; + cout << chip.Samples() << endl; + cout << chip.Lines() << endl; + + chip.TackCube(453.5, 568.5); + cout << chip.TackSample() << endl; + cout << chip.TackLine() << endl; + + cout << "Test chip-to-cube and cube-to-chip mapping" << endl; + chip.SetChipPosition(chip.TackSample(), chip.TackLine()); + cout << chip.CubeSample() << endl; + cout << chip.CubeLine() << endl; + + chip.SetChipPosition(1.0, 1.0); + cout << chip.CubeSample() << endl; + cout << chip.CubeLine() << endl; + + chip.SetCubePosition(chip.CubeSample(), chip.CubeLine()); + cout << chip.ChipSample() << endl; + cout << chip.ChipLine() << endl; + + + cout << "Test assignment of chip data to constant" << endl; + chip.SetAllValues(10.0); + for (int i = 1; i <= chip.Lines(); i++) { + for (int j = 1; j <= chip.Samples(); j++) { + double value = chip.GetValue(j, i); + if (value != 10.0) { + cout << "bad constant (!= 10) at " << j << ", " << i << endl; + } + } + } + + cout << "Test loading chip data" << endl; + for (int i = 1; i <= chip.Lines(); i++) { + for (int j = 1; j <= chip.Samples(); j++) { + chip.SetValue(j, i, (double) (i*100 + j)); + } + } + + for (int i = 1; i <= chip.Lines(); i++) { + for (int j = 1; j <= chip.Samples(); j++) { + double value = chip.GetValue(j, i); + if (value != (double) (i*100 + j)) { + cout << "bad at " << j << ", " << i << endl; + } + } + } + + + + + chip.SetValidRange(0.0, 5050.0); + cout << "Valid tests" << endl; + // is chip valid at 51, 50? + cout << chip.IsValid(chip.Samples(), chip.Lines()) << endl; + // is chip valid at 50, 50? + cout << chip.IsValid(chip.Samples()-1, chip.Lines()) << endl; + // is at least 95% of chip values valid? + cout << chip.IsValid(95.0) << endl; + // is at least 99.99% of chip values valid? + cout << chip.IsValid(99.99) << endl; + + cout << "Extract test" << endl; + // Extract 4 by 3 subchip at 26, 25 + Chip sub = chip.Extract(4, 3, chip.TackSample(), chip.TackLine()); + for (int i = 1; i <= sub.Lines(); i++) { + for (int j = 1; j <= sub.Samples(); j++) { + cout << sub.GetValue(j, i) << " "; + } + cout << endl; + } + + cout << "Test writing chip" << endl; + chip.Write("junk.cub"); + + Cube junk; + junk.Open("junk.cub"); + LineManager line(junk); + + for (int i = 1; i <= chip.Lines(); i++) { + line.SetLine(i); + junk.Read(line); + for (int j = 1; j <= chip.Samples(); j++) { + double value = chip.GetValue(j, i); + if (value != line[j-1]) { + cout << "bad at " << j << ", " << i << endl; + } + } + } + + cout << "Test load chip from cube with rotation" << endl; + chip.TackCube(26.0, 25.0); + chip.Load(junk, 45.0); + for (int i = 1; i <= chip.Lines(); i++) { + for (int j = 1; j <= chip.Samples(); j++) { + cout << std::setw(14) << chip.GetValue(j, i) << " "; + } + cout << endl; + } + + cout << "Test load chip from cube with rotation and clipping polygon " << endl; + chip.TackCube(26.0, 25.0); + + geos::geom::CoordinateSequence *pts = new geos::geom::CoordinateArraySequence (); + pts->add (geos::geom::Coordinate (23.0, 22.0)); + pts->add (geos::geom::Coordinate (28.0, 22.0)); + pts->add (geos::geom::Coordinate (28.0, 27.0)); + pts->add (geos::geom::Coordinate (25.0, 28.0)); + pts->add (geos::geom::Coordinate (23.0, 22.0)); + vector polys; + geos::geom::GeometryFactory gf; + polys.push_back (gf.createPolygon (gf.createLinearRing (pts), NULL)); + geos::geom::MultiPolygon* mPolygon = gf.createMultiPolygon (polys); + + chip.SetClipPolygon(*mPolygon); + chip.Load(junk, 45.0); + for (int i = 1; i <= chip.Lines(); i++) { + for (int j = 1; j <= chip.Samples(); j++) { + cout << std::setw(14) << chip.GetValue(j, i) << " "; + } + cout << endl; + } + + // Test affine transformation + cout << "\nTesting Affine transformation extraction (-1, -1)...\n"; + Affine affine; + affine.Translate(-1.0, -1.0); + + Chip mychip(51, 50); // Needed because chip has poly clipping + mychip.TackCube(26.0, 25.0); + mychip.Load(junk); + mychip.SetChipPosition(mychip.TackSample(), mychip.TackLine()); + cout << "Cube Sample, Line = " << mychip.CubeSample() << ", " + << mychip.CubeLine() << endl; + Chip shift(25, 25); + mychip.Extract(shift, affine); + shift.SetChipPosition(shift.TackSample(), shift.TackLine()); + cout << "Shift Cube Sample, Line = " << shift.CubeSample() << ", " + << shift.CubeLine() << endl; + + Chip io = shift; + io.TackCube(25.0, 24.0); + io.Load(junk); + io.SetChipPosition(io.TackSample(), io.TackLine()); + cout << "New Cube Sample, Line = " << io.CubeSample() << ", " + << io.CubeLine() << endl; + + int ioNull(0), shiftNull(0); + double sumDiff(0.0); + for (int il = 1 ; il <= io.Lines() ; il++) { + for (int is = 1 ; is <= io.Samples() ; is++) { + if (IsSpecial(io.GetValue(is, il))) { + ioNull++; + } + else if (IsSpecial(shift.GetValue(is, il))) { + shiftNull++; + } + else { + sumDiff += io.GetValue(is, il) - shift.GetValue(is, il); + } + } + } + + cout << "I/O Nulls: " << ioNull << endl; + cout << "Shift Nulls: " << shiftNull << endl; + cout << "Sum Diff: " << sumDiff << endl; + + cout << "\nTesting direct Affine Application...\n"; + Chip affchip(25, 25); + affchip.TackCube(25.0, 24.0); + affchip.SetTransform(io.GetTransform()); + affchip.SetChipPosition(affchip.TackSample(), affchip.TackLine()); + cout << "Affine Cube Sample, Line = " << affchip.CubeSample() << ", " + << affchip.CubeLine() << endl; + + cout << "\nTest reading with new Affine transform...\n"; + affchip.Load(junk, io.GetTransform()); + ioNull = shiftNull = 0; + sumDiff = 0.0; + for (int il = 1 ; il <= io.Lines() ; il++) { + for (int is = 1 ; is <= io.Samples() ; is++) { + if (IsSpecial(io.GetValue(is, il))) { + ioNull++; + } + else if (IsSpecial(affchip.GetValue(is, il))) { + shiftNull++; + } + else { + sumDiff += io.GetValue(is, il) - affchip.GetValue(is, il); + } + } + } + + cout << "I/O Nulls: " << ioNull << endl; + cout << "Shift Nulls: " << shiftNull << endl; + cout << "Sum Diff: " << sumDiff << endl; + + affchip.SetChipPosition(affchip.TackSample(), affchip.TackLine()); + cout << "Affine Cube loaded at Sample, Line = " << affchip.CubeSample() << ", " + << affchip.CubeLine() << endl; + + + // Test Load using match chip method + cout << "\nTest reading with match chip and cube...\n"; + Cube junkCube; + junkCube.Open("$base/testData/ab102401_ideal.cub"); + // 4 by 4 chip at samle 1000 line 500 + Chip matchChip(4, 4); + matchChip.TackCube(1000, 500); + matchChip.Load(junkCube); + cout << "\nMatch chip values..."<< endl; + for (int i = 1; i <= matchChip.Lines(); i++) { + for (int j = 1; j <= matchChip.Samples(); j++) { + cout << std::setw(14) << matchChip.GetValue(j, i) << " "; + } + cout << endl; + } + // make sure that if we create a new chip from the same cube that is matched to the match chip, + Chip newChip(4, 4); + newChip.TackCube(1000, 500); + newChip.Load(junkCube, matchChip, junkCube); + cout << "\nNew chip values..." << endl; + for (int i = 1; i <= newChip.Lines(); i++) { + for (int j = 1; j <= newChip.Samples(); j++) { + cout << std::setw(14) << newChip.GetValue(j, i) << " "; + } + cout << endl; + } + // the chips should be almost identical + cout << "Passes if difference is less than EPSILON = " << 2E-6 << endl; + for (int i = 1; i <= newChip.Lines(); i++) { + for (int j = 1; j <= newChip.Samples(); j++) { + double difference = newChip.GetValue(j, i) - matchChip.GetValue(j, i); + cout << std::setw(14) << difference << "\t"; + if (fabs(difference) > 2E-6) { + cout << "bad at " << j << ", " << i << endl; + cout << "difference at " <Camera(); + } + catch(Isis::iException &e) { + std::string msg = "Cannot Create Camera for Image:" + pCube->Filename(); + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + + measureCamera->SetImage(pdSample, pdLine); + + mdEmissionAngle = measureCamera->EmissionAngle(); + mdIncidenceAngle = measureCamera->IncidenceAngle(); + mdResolution = measureCamera->PixelResolution(); + + Isis::Portal inPortal(1, 1, pCube->PixelType()); + inPortal.SetPosition(pdSample, pdLine, 1); + pCube->Read(inPortal); + mdDnValue = inPortal[0]; + + if(pMeasureGrp != NULL) { + *pMeasureGrp += Isis::PvlKeyword("EmissionAngle", mdEmissionAngle); + *pMeasureGrp += Isis::PvlKeyword("IncidenceAngle", mdIncidenceAngle); + *pMeasureGrp += Isis::PvlKeyword("DNValue", mdDnValue); + *pMeasureGrp += Isis::PvlKeyword("Resolution", mdResolution); + } + + if(ValidEmissionAngle(mdEmissionAngle) && ValidIncidenceAngle(mdIncidenceAngle) && + ValidDnValue(mdDnValue) && ValidResolution(mdResolution) && + PixelsFromEdge((int)pdSample, (int)pdLine, pCube) && MetersFromEdge((int)pdSample, (int)pdLine, pCube)) { + return true; + } + return false; + } + + /** + * Validate and Read the Pixels and Meters from Edge Standard + * Options + * + * @author sprasad (6/22/2010) + */ + void CnetValidMeasure::ValidatePvlFromEdge(void) { + // Parse the Pixels from edge + if(mPvlOpGrp.HasKeyword("PixelsFromEdge")) { + miPixelsFromEdge = mPvlOpGrp["PixelsFromEdge"]; + if(miPixelsFromEdge < 0) { + miPixelsFromEdge = 0; + } + } + mStdOptionsGrp += Isis::PvlKeyword("PixelsFromEdge", miPixelsFromEdge); + + // Parse the Meters from edge + if(mPvlOpGrp.HasKeyword("MetersFromEdge")) { + mdMetersFromEdge = mPvlOpGrp["MetersFromEdge"]; + if(mdMetersFromEdge < 0) { + mdMetersFromEdge = 0; + } + } + mStdOptionsGrp += Isis::PvlKeyword("MetersFromEdge", mdMetersFromEdge); + } + + /** + * Validate the Min and Max Resolution Values set by the user in the Operator pvl file. + * If not set then set the options to default and enter their names in the Unused Group. + * If the user set values are invalid then exception is thrown. + * + * @author Sharmila Prasad (6/4/2010) + */ + void CnetValidMeasure::ValidatePvlResolution(void) { + if(mPvlOpGrp.HasKeyword("MinResolution")) + mdMinResolution = mPvlOpGrp["MinResolution"]; + else { + mdMinResolution = 0; + } + mStdOptionsGrp += Isis::PvlKeyword("MinResolution", mdMinResolution); + + if(mPvlOpGrp.HasKeyword("MaxResolution")) + mdMaxResolution = mPvlOpGrp["MaxResolution"]; + else { + mdMaxResolution = DBL_MAX; + } + mStdOptionsGrp += Isis::PvlKeyword("MaxResolution", mdMaxResolution); + + if(mdMinResolution < 0 || mdMaxResolution < 0) { + std::string msg = "Invalid Resolution value(s), Resolution must be greater than zero"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + if(mdMaxResolution < mdMinResolution) { + std::string msg = "MinResolution must be less than MaxResolution"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + /** + * Validate the Min and Max Dn Values set by the user in the Operator pvl file. + * If not set then set the options to default and enter their names in the Unused Group. + * If the user set values are invalid then exception is thrown. + * + * @author Sharmila Prasad (5/10/2010) + * + */ + void CnetValidMeasure::ValidatePvlDN(void) { + if(mPvlOpGrp.HasKeyword("MinDN")) + mdMinDN = mPvlOpGrp["MinDN"]; + else { + mdMinDN = Isis::ValidMinimum; + } + mStdOptionsGrp += Isis::PvlKeyword("MinDN", mdMinDN); + + if(mPvlOpGrp.HasKeyword("MaxDN")) + mdMaxDN = mPvlOpGrp["MaxDN"]; + else { + mdMaxDN = Isis::ValidMaximum; + } + mStdOptionsGrp += Isis::PvlKeyword("MaxDN", mdMaxDN); + + if(mdMaxDN < mdMinDN) { + std::string msg = "MinDN must be less than MaxDN"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + /** + * ValidateEmissionAngle: Validate the Min and Max Emission Values set by the user in the Operator pvl file. + * If not set then set the options to default and enter their names in the Unused Group. + * If the user set values are invalid then exception is thrown, the valid range being [0-135] + * + * @author Sharmila Prasad (5/10/2010) + * + */ + void CnetValidMeasure::ValidatePvlEmissionAngle(void) { + if(mPvlOpGrp.HasKeyword("MinEmission")) { + mdMinEmissionAngle = mPvlOpGrp["MinEmission"]; + if(mdMinEmissionAngle < 0 || mdMinEmissionAngle > 135) { + std::string msg = "Invalid Min Emission Angle, Valid Range is [0-135]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + mStdOptionsGrp += Isis::PvlKeyword("MinEmission", mdMinEmissionAngle); + + if(mPvlOpGrp.HasKeyword("MaxEmission")) { + mdMaxEmissionAngle = mPvlOpGrp["MaxEmission"]; + if(mdMaxEmissionAngle < 0 || mdMaxEmissionAngle > 135) { + std::string msg = "Invalid Max Emission Angle, Valid Range is [0-135]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + mStdOptionsGrp += Isis::PvlKeyword("MaxEmission", mdMaxEmissionAngle); + + if(mdMaxEmissionAngle < mdMinEmissionAngle) { + std::string msg = "Min EmissionAngle must be less than Max EmissionAngle"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + } + + /** + * ValidateIncidenceAngle: Validate the Min and Max Incidence Values set by the user in the Operator pvl file. + * If not set then set the options to default and enter their names in the Unused Group. + * If the user set values are invalid then exception is thrown, the valid range being [0-135] + * + * @author Sharmila Prasad (5/10/2010) + * + * + */ + void CnetValidMeasure::ValidatePvlIncidenceAngle(void) { + if(mPvlOpGrp.HasKeyword("MinIncidence")) { + mdMinIncidenceAngle = mPvlOpGrp["MinIncidence"]; + if(mdMinIncidenceAngle < 0 || mdMinIncidenceAngle > 135) { + std::string msg = "Invalid Min Incidence Angle, Valid Range is [0-135]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + mStdOptionsGrp += Isis::PvlKeyword("MinIncidence", mdMinIncidenceAngle); + + if(mPvlOpGrp.HasKeyword("MaxIncidence")) { + mdMaxIncidenceAngle = mPvlOpGrp["MaxIncidence"]; + if(mdMaxIncidenceAngle < 0 || mdMaxIncidenceAngle > 135) { + std::string msg = "Invalid Max Incidence Angle, Valid Range is [0-135]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + mStdOptionsGrp += Isis::PvlKeyword("MaxIncidence", mdMaxIncidenceAngle); + + if(mdMaxIncidenceAngle < mdMinIncidenceAngle) { + std::string msg = "Min IncidenceAngle must be less than Max IncidenceAngle"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + + /** + * Validates an Emission angle by comparing with the min and max values in the def file. + * If Emission Angle is greater or lesser than the max/min values in the def file or the defaults + * it returns false else true. + * + * @author Sharmila Prasad (3/30/2010) + * + * + * @return bool + */ + bool CnetValidMeasure::ValidEmissionAngle(double pdEmissionAngle) { + if(pdEmissionAngle < mdMinEmissionAngle || pdEmissionAngle > mdMaxEmissionAngle) { + return false; + } + return true; + } + + /** + * Validates an Incidence angle by comparing with the min and max values in the def file. + * If Incidence Angle is greater or lesser than the max/min values in the def file or the defaults + * it returns false else true. + * + * @author Sharmila Prasad (5/10/2010) + * + * + * @return bool + */ + bool CnetValidMeasure::ValidIncidenceAngle(double pdIncidenceAngle) { + if(pdIncidenceAngle < mdMinIncidenceAngle || pdIncidenceAngle > mdMaxIncidenceAngle) { + return false; + } + return true; + } + + /** + * Validates Dn Value by comparing against the Min and Max DN Values set in the + * def file or the defaults. + * + * @author Sharmila Prasad (3/30/2010) + * + * @return bool + */ + bool CnetValidMeasure::ValidDnValue(double pdDnValue) { + if(Isis::IsSpecial(pdDnValue) || pdDnValue < mdMinDN || pdDnValue > mdMaxDN) { + return false; + } + return true; + } + + /** + * Validates Dn Value by comparing against the Min and Max DN Values set in the + * def file or the defaults. + * + * @author Sharmila Prasad (6/4/2010) + * + * @return bool + */ + bool CnetValidMeasure::ValidResolution(double pdResolution) { + if(pdResolution < mdMinResolution || pdResolution > mdMaxResolution) { + return false; + } + return true; + } + + /** + * Validate if a point has a valid lat, lon for that camera + * + * @author Sharmila Prasad (6/4/2010) + * + * @param pCamera + * @param piSample + * @param piLine + * + * @return bool + */ + bool CnetValidMeasure::ValidLatLon(Camera *pCamera, int piSample, int piLine) { + return true; + } + + /** + * Validate if a point is user defined number of pixels from the edge + * + * @author Sharmila Prasad (6/21/2010) + * + * @param piSample + * @param piLine + * @param pCube + * + * @return bool + */ + bool CnetValidMeasure::PixelsFromEdge(int piSample, int piLine, Cube *pCube) { + if(miPixelsFromEdge <= 0) { + return true; + } + + int iNumSamples = pCube->Samples(); + int iNumLines = pCube->Lines(); + + // test right + if((iNumSamples - piSample) < miPixelsFromEdge) { + return false; + } + + // test left + if((piSample - miPixelsFromEdge) <= 0) { + return false; + } + + // test down + if((iNumLines - piLine) < miPixelsFromEdge) { + return false; + } + + // test up + if((piLine - miPixelsFromEdge) <= 0) { + return false; + } + + return true; + } + + /** + * Validate if a point is user defined number of meters from the edge + * + * @author Sharmila Prasad (6/21/2010) + * + * @param piSample + * @param piLine + * @param pCube + * + * @return bool + */ + bool CnetValidMeasure::MetersFromEdge(int piSample, int piLine, Cube *pCube) { + if(mdMetersFromEdge <= 0) { + return true; + } + + int iNumSamples = pCube->Samples(); + int iNumLines = pCube->Lines(); + + try { + // Get the image's camera to get pixel resolution + Camera *camera = pCube->Camera(); + double resMetersTotal = 0; + bool bMinDistance = false; + + // test top + for(int line = piLine - 1; line > 0; line--) { + camera->SetImage(piSample, line); + double resolution = camera->PixelResolution(); + resMetersTotal += resolution; + if(resMetersTotal >= mdMetersFromEdge) { + bMinDistance = true; + break; + } + } + if(!bMinDistance) { + return false; + } + + // test bottom + bMinDistance = false; + resMetersTotal = 0; + for(int line = piLine + 1; line <= iNumLines; line++) { + camera->SetImage(piSample, line); + double resolution = camera->PixelResolution(); + resMetersTotal += resolution; + if(resMetersTotal >= mdMetersFromEdge) { + bMinDistance = true; + break; + } + } + if(!bMinDistance) { + return false; + } + + // test left + resMetersTotal = 0; + bMinDistance = false; + for(int sample = piSample - 1; sample > 0; sample--) { + camera->SetImage(sample, piLine); + double resolution = camera->PixelResolution(); + resMetersTotal += resolution; + if(resMetersTotal >= mdMetersFromEdge) { + bMinDistance = true; + break; + } + } + if(!bMinDistance) { + return false; + } + + // test right + resMetersTotal = 0; + bMinDistance = false; + for(int sample = piSample + 1; sample <= iNumSamples; sample++) { + camera->SetImage(sample, piLine); + double resolution = camera->PixelResolution(); + resMetersTotal += resolution; + if(resMetersTotal >= mdMetersFromEdge) { + return true; + } + } + return false; + } + catch(iException &e) { + std::string msg = "Cannot Create Camera for Image:" + pCube->Filename(); + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + } + +}; + diff --git a/isis/src/base/objs/CnetValidMeasure/CnetValidMeasure.h b/isis/src/base/objs/CnetValidMeasure/CnetValidMeasure.h new file mode 100644 index 0000000000000000000000000000000000000000..377cb22c480ee724ec56cf31095a64a6f0debcd5 --- /dev/null +++ b/isis/src/base/objs/CnetValidMeasure/CnetValidMeasure.h @@ -0,0 +1,179 @@ +#ifndef _CnetValidMeasure_h_ +#define _CnetValidMeasure_h_ + +#include "CubeManager.h" +#include "iString.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Progress.h" +#include "SerialNumberList.h" + +#include +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/06/23 22:28:50 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { + + class Camera; + class Cube; + class ControlNet; + /** + * @brief CnetValidMeasure class + * + * Base class to validate all the common Control Network options + * specific to Control Network applications. + * + * @see cnetref autoseed etc. + * + * @internal + * @history 2010-05-11 Sharmila Prasad - Original Version + * @history 2010-06-21 Sharmila Prasad - Remove references to UniversalGroundMap and Cubes + * use CubeManager instead + * @history 2010-06-23 Sharmila Prasad - Added Pixels/Meters from the edge options + * and Validate Standard Options + */ + + class CnetValidMeasure { + public: + CnetValidMeasure(Pvl *pvl = 0); + CnetValidMeasure(Pvl &pvl); + + void InitStdOptions(void); //!< Initialize the Standard Options + void InitStdOptionsGroup(void); //!< Initialize the Standard Options Pvl Group with no DefFile + + virtual ~CnetValidMeasure(); + + void Parse(Pvl &pvlDef); //!< Parse the DefFile for Standard Options + + //!< Get the Pvl Log file + virtual Pvl &GetLogPvl(void) { + return mPvlLog; + }; + + //!< Virtual Function to get better references for a Control Network based on Criteria + virtual void FindCnetRef(const ControlNet &pOrigNet, ControlNet &pNewNet) {}; + + bool ValidEmissionAngle(double pdEmissionAngle); //!< Validate whether the Emission Angle is in the set Range + bool ValidIncidenceAngle(double pdIncidenceAngle); //!< Validate whether the Incidence Angle is in the set Range + bool ValidDnValue(double pdDnValue); //!< Validate whether the DN Value is in the set Range + bool ValidResolution(double pdResolution); //!< Validate whether the Resolution is in the set Range + bool ValidLatLon(Isis::Camera *pCamera, int piSample, int piLine); //!< Validate the Lat/Lon + + //!< Get the Standard Options Pvl Group + PvlGroup &GetStdOptions(void) { + return mStdOptionsGrp; + }; + + //!< Get the Statistics Pvl Grp + PvlGroup &GetStatistics(void) { + return mStatisticsGrp; + }; + + //!< Get the option MinDN + double GetMinDN(void) { + return mdMinDN; + }; + + //!< Get the option MaxDN + double GetMaxDN(void) { + return mdMaxDN; + }; + + //!< Get the option MinEmissionAngle + double GetMinEmissionAngle(void) { + return mdMinEmissionAngle; + }; + + //!< Get the option MaxEmissionAngle + double GetMaxEmissionAngle(void) { + return mdMaxEmissionAngle; + }; + + //!< Get the option MinIncidenceAngle + double GetMinIncidenceAngle(void) { + return mdMinIncidenceAngle; + }; + + //!< Get the option MaxIncidenceAngle + double GetMaxIncidenceAngle(void) { + return mdMaxIncidenceAngle; + }; + + //!< Get the option PixelsFromEdge + double GetPixelsFromEdge(void) { + return miPixelsFromEdge; + }; + + //!< Get the option MetersFromEdge + double GetMetersFromEdge(void) { + return mdMetersFromEdge; + }; + + //!< API to display location in the form "Sample,Line" + iString LocationString(double pdSample, double pdLine) const { + return iString((int)pdSample) + "," + iString((int)pdLine); + }; + + //!< Test for a point to be user defined number of pixels from the edge + bool PixelsFromEdge(int piSample, int piLine, Cube *pCube); + + //!< Test for a point to be user defined number of meters from the edge + bool MetersFromEdge(int piSample, int piLine, Cube *pCube); + + //!< Validate Standard options to pick a reference based on a particular criteria + bool ValidStandardOptions(double pdSample, double pdLine, Cube *pCube, PvlGroup *pMeasureGrp = NULL); + + protected: + void ValidatePvlDN(void); //!< Validate PVL Min & Max DN Standard Options + void ValidatePvlEmissionAngle(void); //!< Validate PVL Min & Max EmissionAngle Standard Options + void ValidatePvlIncidenceAngle(void); //!< Validate PVL Min & Max IncidenceAngle Standard Options + void ValidatePvlResolution(void); //!< Validate PVL Min & Max Resolution Standard Options + void ValidatePvlFromEdge(void); //!< Validate and read Pixels and Meters from Edge Standard Options + void ReadSerialNumbers(std::string psSerialNumfile); //!< Read the Serial Numbers from the file and open assocaited cubes + + double mdMinDN; //!< Standard Option MinDN + double mdMaxDN; //!< Standard Option MaxDN + double mdMinResolution; //!< Standard Option MinResolution + double mdMaxResolution; //!< Standard Option MaxResolution + double mdMinEmissionAngle; //!< Standard Option MinEmissionAngle + double mdMaxEmissionAngle; //!< Standard Option MaxEmissionAngle + double mdMinIncidenceAngle; //!< Standard Option MinIncidenceAngle + double mdMaxIncidenceAngle; //!< Standard Option MaxIncidenceAngle + double mdMetersFromEdge; //!< Standard Option MeteresFromEdge + int miPixelsFromEdge; //!< Standard Option PixelsFromEdge + + double mdEmissionAngle; //!< Store current Measure's Emission Angle + double mdIncidenceAngle; //!< Store current Measure's Incidence Angle + double mdResolution; //!< Store current Measure's Resolution + double mdDnValue; //!< Store current Measure's DN Value + + PvlGroup mPvlOpGrp; //!< Pvl Operator Group + PvlGroup mStdOptionsGrp; //!< Pvl Standard Options Group + PvlGroup mStatisticsGrp; //!< Pvl output Statistics Group + Pvl mPvlLog; //!< Pvl Log - containing all the processing log + Progress mStatus; //!< Monitor the Progress/status of the application running + CubeManager mCubeMgr; //!< CubeManager to open and read cubes + SerialNumberList mSerialNumbers; //!< Serial numbers lists read from the list file + }; +}; +#endif diff --git a/isis/src/base/objs/CnetValidMeasure/CnetValidMeasure.truth b/isis/src/base/objs/CnetValidMeasure/CnetValidMeasure.truth new file mode 100644 index 0000000000000000000000000000000000000000..b3c6ecb738f215f8ceb22ac542889af96046ead6 --- /dev/null +++ b/isis/src/base/objs/CnetValidMeasure/CnetValidMeasure.truth @@ -0,0 +1,17 @@ +**USER ERROR** MinDN must be less than MaxDN +**USER ERROR** Min EmissionAngle must be less than Max EmissionAngle +**USER ERROR** Invalid Max Incidence Angle, Valid Range is [0-135] +**USER ERROR** Invalid Resolution value(s), Resolution must be greater than zero +Group = StandardOptions + MinDN = -1.0 + MaxDN = 1.0 + MinEmission = 0.0 + MaxEmission = 135.0 + MinIncidence = 0.0 + MaxIncidence = 135.0 + MinResolution = 100.0 + MaxResolution = 500.0 + PixelsFromEdge = 0 + MetersFromEdge = 0.0 +End_Group +End \ No newline at end of file diff --git a/isis/src/base/objs/CnetValidMeasure/Makefile b/isis/src/base/objs/CnetValidMeasure/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..68327da5d26b2b83ac4a8ff353b038684a8ede03 --- /dev/null +++ b/isis/src/base/objs/CnetValidMeasure/Makefile @@ -0,0 +1,5 @@ +INCS = CnetValidMeasure.h +SRCS = CnetValidMeasure.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CnetValidMeasure/unitTest.cpp b/isis/src/base/objs/CnetValidMeasure/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d9274247f91402fe802331491afdb0e67e5ae14 --- /dev/null +++ b/isis/src/base/objs/CnetValidMeasure/unitTest.cpp @@ -0,0 +1,130 @@ +#include "CnetValidMeasure.h" +#include "Preference.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +int main(void) { + Isis::Preference::Preferences(true); + try { + try { + Pvl pvlLog; + PvlGroup op("Operator"); + op += PvlKeyword("Name", "StandardDeviation"); + op += PvlKeyword("DeltaLine", 100); + op += PvlKeyword("DeltaSamp", 100); + op += PvlKeyword("Samples", 15); + op += PvlKeyword("Lines", 15); + op += PvlKeyword("MinimumInterest", 0.01); + op += PvlKeyword("MinDN", 1.0); + op += PvlKeyword("MaxDN", -1.0); + op += PvlKeyword("MinEmission", 15.0); + op += PvlKeyword("MaxEmission", 25.0); + op += PvlKeyword("MinIncidence", 0.0); + op += PvlKeyword("MaxIncidence", 135.0); + + pvlLog += op; + + CnetValidMeasure cnetVM(pvlLog); + cout << cnetVM.GetLogPvl(); + } + catch(Isis::iException e) { + e.Report(false); + } + + try { + Pvl pvlLog; + PvlGroup op("Operator"); + op += PvlKeyword("Name", "None"); + op += PvlKeyword("MinDN", -1.0); + op += PvlKeyword("MaxDN", 1.0); + op += PvlKeyword("MinEmission", 25.0); + op += PvlKeyword("MaxEmission", 15.0); + op += PvlKeyword("MinIncidence", 0.0); + op += PvlKeyword("MaxIncidence", 135.0); + + pvlLog += op; + + CnetValidMeasure cnetVM(pvlLog); + cout << cnetVM.GetLogPvl(); + } + catch(Isis::iException e) { + e.Report(false); + } + + try { + Pvl pvlLog; + PvlGroup op("Operator"); + op += PvlKeyword("Name", "StandardDeviation"); + op += PvlKeyword("DeltaLine", 100); + op += PvlKeyword("DeltaSamp", 100); + op += PvlKeyword("Samples", 15); + op += PvlKeyword("Lines", 15); + op += PvlKeyword("MinimumInterest", 0.01); + op += PvlKeyword("MinDN", -1.0); + op += PvlKeyword("MaxDN", 1.0); + op += PvlKeyword("MinEmission", 0.0); + op += PvlKeyword("MaxEmission", 135.0); + op += PvlKeyword("MinIncidence", 0.0); + op += PvlKeyword("MaxIncidence", 150.0); + + pvlLog += op; + + CnetValidMeasure cnetVM(pvlLog); + cout << cnetVM.GetLogPvl(); + } + catch(Isis::iException e) { + e.Report(false); + } + + try { + Pvl pvlLog; + PvlGroup op("Operator"); + op += PvlKeyword("Name", "None"); + op += PvlKeyword("MinDN", -1.0); + op += PvlKeyword("MaxDN", 1.0); + op += PvlKeyword("MinEmission", 0.0); + op += PvlKeyword("MaxEmission", 135.0); + op += PvlKeyword("MinIncidence", 0.0); + op += PvlKeyword("MaxIncidence", 135.0); + op += PvlKeyword("MinResolution", 100.0); + op += PvlKeyword("MaxResolution", -1.0); + + pvlLog += op; + + CnetValidMeasure cnetVM(pvlLog); + cout << cnetVM.GetLogPvl(); + } + catch(Isis::iException e) { + e.Report(false); + } + + try { + Pvl pvlLog; + PvlGroup op("Operator"); + op += PvlKeyword("Name", "None"); + op += PvlKeyword("MinDN", -1.0); + op += PvlKeyword("MaxDN", 1.0); + op += PvlKeyword("MinEmission", 0.0); + op += PvlKeyword("MaxEmission", 135.0); + op += PvlKeyword("MinIncidence", 0.0); + op += PvlKeyword("MaxIncidence", 135.0); + op += PvlKeyword("MinResolution", 100.0); + op += PvlKeyword("MaxResolution", 500.0); + + pvlLog += op; + + CnetValidMeasure cnetVM(pvlLog); + cout << cnetVM.GetLogPvl(); + } + catch(Isis::iException e) { + e.Report(false); + } + } + catch(Isis::iException e) { + throw Isis::iException::Message(Isis::iException::Programmer, "CnetValidMeasure Unit test Exception", _FILEINFO_); + } + + return 0; +} diff --git a/isis/src/base/objs/CollectorMap/CollectorMap.h b/isis/src/base/objs/CollectorMap/CollectorMap.h new file mode 100644 index 0000000000000000000000000000000000000000..05ab30cfaf20344dc1ad19630b7a72ab01001036 --- /dev/null +++ b/isis/src/base/objs/CollectorMap/CollectorMap.h @@ -0,0 +1,755 @@ +#ifndef CollectorMap_h +#define CollectorMap_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/06/18 21:57:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "iString.h" +#include "iException.h" +#include + + +namespace Isis { + +/** + * @brief Provides a simple comparison between two values + * + * This simple comparison function object is provided with no special frills + * that does pretty much exactly what std::less does. + */ + template struct SimpleCompare { + + /** + * Returns true if v1 is less than v2 + * + * @param v1 Input constant + * @param v2 Input constant + * + * @return bool Returns true if v1 is less than v2 + */ + bool operator() (const K &v1, const K &v2) const { + return (v1 < v2); + } + + }; + + /** + * @brief Provides a case insensitive string comparison + * + * This string comparison functor object compares two strings ignoring case. Use + * this policy when your key into the collector map is a string and you want to + * ignore case when finding elements in the collection. + */ + template struct NoCaseStringCompare { + + /** + * Compares v1 and v2 as case insensitive strings, and returns true of v1 is + * less than v2 (as those strings). + * + * @param v1 Input constant + * @param v2 Input constant + * + * @return bool Returns true if v1 is less than v2 in string format + */ + bool operator() (const K &v1, const K &v2) const { + return (iString::DownCase(v1) < iString::DownCase(v2)); + } + + }; + +/** + * @brief Provides a robust comparison of double/float values + * + * This functor compares floating point values using a default epsilon of + * 1.0e-6. It can be used for doubles or floats, however floats will be promoted + * to double for the comparison. + */ + template struct RobustFloatCompare { + + /** + * Compares v1 and v2 as floating point values. + * + * @param v1 + * @param v2 + * + * @return bool + */ + bool operator() (const K &v1, const K &v2) const { + return (gsl_fcmp(v1, v2, -1.0E-6) < 0); + } + + }; + +/** + * @brief Supplies a NOOP default for removal of a CollectorMap entry + * + * This simple declaration is basically a NOOP that implements removal + * of a CollectionMap entry. It is most useful (and the default behavior) + * when the storage element of the CollectorMap is anything but a pointer. + * Pointers that require deletion should use the PointerRemoval policy unless + * the pointers are owned by another "entity". + */ +template struct NoopRemoval { + protected: + + /** + * Destroys the CollectorMap entry + * + * @param element The CollectorMap to be destroyed + */ + void destroy(T *element) { return; } + +}; + +/** + * @brief Supplies a policy for deleting pointers that CollectorMap owns + * + * Defines a method to delete pointers when removed from a CollectorMap. + * This is necessary to prevent memory leaks and defer the deletion to + * removal from CollectorMap class. + */ +template struct PointerRemoval { + protected: + + /** + * Destroys the CollectorMap pointer's CollectorMap + * + * @param element The pointer pointing to the CollectorMap to be destroyed + */ + void destroy(T *element) { + delete (*element); + return; + } + +}; + +/** + * @brief Policy for deleting arrays that CollectorMap owns + * + * Defines a method to delete arrays when removed from a CollectorMap. + * This is necessary to prevent memory leaks and defer the deletion to + * removal from CollectorMap class. + */ +template struct ArrayRemoval { + protected: + + /** + * Destroys the array of CollectorMaps + * + * @param element The array of CollectorMaps to be destroyed + */ + void destroy(T *element) { + delete [] (*element); + return; + } + +}; + + +/** + * @brief (Default) Policy for copying map elements + * + * Defines a method to copy simple elements from an existing map to a + * destination map. This policy just makes a direct copy of the element to the + * destination. + * + * This policy assumes the assignment operator handles the proper copying of + * each element T in the collection. + */ +template struct DefaultCopy { + protected: + + /** + * Returns a copy of the input + * + * @param src The map element to be copied + * + * @return const T& The copy of the input + */ + const T ©(const T &src) const { + return (src); + } + +}; + + +/** + * @brief Pointer to object policy for copying map elements + * + * Defines a copy method to properly handle pointers to objects (assumed) when + * copying the complete CollectorMap. This implementation assumes the copy + * constructor properly handles the creation of a new element from a different + * one. + * + * This policy assumes the assignment operator handles the proper copying of + * each element T* in the collection. + * + * This employs an intersting technique of redirection. Because the type T is + * actually T*, the templated allocate() method exists to get down to the T + * class base level. Looks strange but it works. + */ +template struct PointerCopy { + protected: + /** + * @brief Allocate new object using copy construtor and new pointer + * + * This copy method takes a pointer to a pointer (T is actually a T*) and + * allocates a new object using the copy constructor. + * + * @param src Pointer to pointer of new class to allocate + * + * @return T Pointer to new object type T + */ + T copy(const T &src) const { + return (allocate(*(src))); + } + + private: + /** + * @brief Allocate new object using copy constructor + * + * @param obj Source object to create new one from + * + * @return P* Pointer to newly allocated object + */ + template + P *allocate(const P &obj) const { + return (new P(obj)); + } +}; + + + +/** + * @brief Collector/container for arbitrary items + * + * Used to contain types with iterators of const and non-const conditions. + * This is a multimap that contains arbitrary keys with arbitrary elements. It + * is intended to be used for pointers and copyable objects. They should be + * rather efficient in the copy out operation so large objects may not be + * suitable or classes that do not have a good copy operator. During testing + * it was noted that an object is copied up to four times and destroyed three + * times upon an add() operation. + * + * This class is implemented using policies. The ComparePolicy is used to test + * key elements such as strings and double values. The NoCaseStringCompare + * policy is provided that expedites case insensitive string key comparisons. + * The RobustFloatCompare implements the comparison of double or float key + * types. Direct comparisons of floats can be problematic due to round off and + * storage manifestations of these values in conputers. The default policy, + * SimpleCompare, does a simple parameter to key equality test. + * + * The RemovalPolicy is provided when a map value is removed from the list. + * This allows pointers and arrays to be stored in the map as well. To store + * pointers, use PointerRemoval and for arrays there is the ArrayRemoval + * policy. The default is the NoopRemoval policy which simply lets the + * destructor handle removals. + * + * The CopyPolicy is necessary to properly handle the copying of elements. + * This is especially important for pointers and arrays. In order to minimize + * difficult passing strategies, map elements are passed by address and the + * return type is the element type. DefaultCopy simply copies the elements as + * is relying on the element T assigment operator to do the right thing. For + * pointers to objects, the PointerCopy allocates the object using the copy + * constructor. One could provide a similar operator assuming a clone() + * method existed for the type T element. The ArrayCopy policy is left to the + * user to provide their own as it cannot support arrays of varying length. + * (One should use std::vector instead!) Users can supply their own CopyPolicy + * that need only expose a copy(cont T *src) method. + * + * Here are some examples that demonstrate how this policy-based template class + * can be used: + * + * @code + * // Create a unique string key list that stores double floating point values. + * // Use the default removal and copy policies but allow testing for character + * // keys without regard to case via the NoCaseStringCompare. + * #include "CollectorMap.h" + * + * CollectorMap dmap; + * cout << "\nSize of double map = " << dmap.size() << endl; + * dmap.add("one", 1.0); + * dmap.add("two", 2.0); + * cout << "Size of double map = " << dmap.size() << endl; + * + * cout << "One = " << dmap.get("one") << endl; + * cout << "Two = " << dmap.get("Two") << endl; + * + * const double &one = dmap.get("one"); + * cout << "\nTest Const one = " << one << endl; + * + * dmap.remove("one"); + * @endcode + * + * Using this class internal to classes is perhaps where it may be applied more + * frequently. The example below shows how to declare an integer key using + * pointers to classes: + * + * @code + * #include "CollectorMap.h" + * + * class ClassTest { + * public: + * ClassTest(int n = 0) : _n(n) { } + * ~ClassTest() { } + * int Ident() const { return (_n); } + * private: + * int _n; + * }; + * + * + * // Typedefs are sometimes convenient in these cases + * typedef CollectorMap PointerMap; + * + * PointerMap ctest2; + * ctest2.add(4,new ClassTest(4)); + * ctest2.add(5,new ClassTest(5)); + * ctest2.add(6,new ClassTest(6)); + * ctest2.add(7,new ClassTest(7)); + * + * cout << "Remove ClassTest 6\n"; + * ctest2.remove(6); + * + * // Creates a copy of ctest2 using the PointerCopy policy + * PointerMap map2(ctest2); + * + * cout << "Find element 7: " << map2.find(7)->Ident() << endl; + * + * @endcode + * + * And, finally, an example of how to use duplicate keys: + * + * @code + * #include "CollectorMap.h" + * + * typedef CollectorMap IntStr; + * IntStr dupstr(IntStr::DuplicateKeys); + * dupstr.add(1,"One"); + * dupstr.add(1, "One #2"); + * dupstr.add(1,"One #3"); + * dupstr.add(2,"Two"); + * dupstr.add(2,"Two #2"); + * dupstr.add(3,"Three"); + * + * cout << "Size of Dup object: " << dupstr.size() << endl; + * cout << "Number Ones: " << dupstr.count(1) << endl; + * cout << "Number Twos: " << dupstr.count(2) << endl; + * cout << "Number Threes: " << dupstr.count(3) << endl; + * cout << "Number Fours: " << dupstr.count(4) << endl; + * + * IntStr::CollectorConstIter isIter; + * int j = 0; + * for (isIter = dupstr.begin() ; isIter != dupstr.end() ; ++isIter, j++) { + * cout << "IntStr[" << j << "] = {" << isIter->first << ", " + * << isIter->second << "}, Index: " << dupstr.index(isIter->first) + * << endl; + * cout << "Nth Test Ident = " << dupstr.getNth(j) << endl; + * } + * @endcode + * + * The output of the above example is: + * @code + * Size of Dup object: 6 + * Number Ones: 3 + * Number Twos: 2 + * Number Threes: 1 + * Number Fours: 0 + * IntStr[0] = {1, One}, Index: 0 + * Nth Test Ident = One + * IntStr[1] = {1, One #2}, Index: 0 + * Nth Test Ident = One #2 + * IntStr[2] = * {1, One #3}, Index: 0 + * Nth Test Ident = One #3 + * IntStr[3] * = {2, Two}, Index: 3 + * Nth Test Ident = Two + * IntStr[4] = * {2, Two #2}, Index: 3 + * Nth Test Ident = Two #2 + * IntStr[5] = * {3, Three}, Index: 5 + * Nth Test Ident = Three + * @endcode + * + * @ingroup Utility + * + * @author 2006-06-21 Kris Becker + * + * @internal + * @history 2006-07-03 Kris Becker Added the ability to stored duplicate keys + * if needed (using a multimap instead of a map). Initial default + * behavior of unique keys is retained. See KeyPolicy. + * @history 2006-07-28 Kris Becker Fixed a bug in the NoCaseStringCompare + * implementation. Prior to this fix, it would not function + * properly at all for case-insenstive keys. + * @history 2006-08-30 Kris Becker Fixed bug in copy constructors that + * attempted to use a virtual method in the object being created + * when it *must* use the method from the one it is being created + * from. (g++ 4.1 on Suse 10.1 didn't like this bug at all!) + * @history 2008-06-18 Christopher Austin Fixed Documentation + */ +template class ComparePolicy = SimpleCompare, + template class RemovalPolicy = NoopRemoval, + template class CopyPolicy = DefaultCopy +> +class CollectorMap : public RemovalPolicy, public CopyPolicy { + public: + typedef T CollectorType; //!< Data type + //! A multimap attacking a key to a CollectorType and a ComparePolicy + typedef std::multimap > CollectorList; + //! CollectorList iterator type declaration + typedef typename CollectorList::iterator CollectorIter; + //! CollectorList constant iterator type declaration + typedef typename CollectorList::const_iterator CollectorConstIter; + + /** + * @brief Enumerated selection of key behaviour + * + * Using this enumeration during construction allows the user of this class + * to specify if the keys used to identify elements are unique or can be + * duplicated. + */ + enum KeyPolicy { UniqueKeys, //!< Constrain keys to be unique + DuplicateKeys //!< Allow duplication of keys + }; + + /** Constructor */ + CollectorMap() : _keyPolicy(UniqueKeys) { } + + /** + * @brief Allows the user to choose if keys can be duplicated + * + * This constructor is provided to the user that wants to explicity define how + * the keys, namely insertions are managed. The default is unique keys in the + * noop constructor...this one allows instantiation of either policy. + * + * @param keyPolicy Can be UniqueKeys or DuplicateKeys + */ + CollectorMap(const KeyPolicy &keyPolicy) : _keyPolicy(keyPolicy) { } + + /** Destructor handles removal of the elements within the collection + * + * This must take into account the removal strategy and apply to any + * remaining elements. + */ + virtual ~CollectorMap() { + selfDestruct(); + } + + /** + * @brief Copy constructor invokes the copy policy as provided by the users + * + * This copy constructor will transfer the map of an incoming CollectorMap to + * a newly created one. This process employs the user selectable CopyPolicy. + * It invokes the copy() method exposed in the copy policy. + * + * @param cmap The CollectorMap to be copied + */ + CollectorMap(const CollectorMap &cmap) { + _keyPolicy = cmap._keyPolicy; + CollectorConstIter cItr; + for (cItr = cmap._list.begin() ; cItr != cmap._list.end() ; cItr++) { + _list.insert(std::make_pair(cItr->first, cmap.copy(cItr->second))); + } + } + + /** + * @brief Assignment operator for the CollectorMap class object + * + * This object assignment operator is provided to properly handle the copying + * of CollectorMap elements to a new instantiation. This implements the + * CopyPolicy for each element in the @b cmap object to the current one. This + * is a two step operation: first destroy any elements that exist in the + * destination object (using the RemovalPolicy) and then copy all elements + * from the @b cmap object to the current one using the copy() method exposed + * in the CopyPolicy. + * + * @param cmap The CollectorMap to be copied + */ + CollectorMap &operator=(const CollectorMap &cmap) { + if (&cmap != this) { + selfDestruct(); + _keyPolicy = cmap._keyPolicy; + CollectorConstIter cItr; + for (cItr = cmap._list.begin() ; cItr != cmap._list.end() ; cItr++) { + _list.insert(std::make_pair(cItr->first, cmap.copy(cItr->second))); + } + } + return (*this); + } + + /** + * Returns the size of the collection + * + * @return int Number of elements in collection + */ + int size() const { return (_list.size()); } + + /** + * @brief Returns the number of keys found in the list + * + * For unique keys, this will always be 1. If duplicate keys are allowed, + * this will return the number of keys in the container. + * + * @param key Key to return count for + * + * @return int Number keys in container + */ + int count(const K &key) const { + return (_list.count(key)); + } + + /** + * Adds the element to the list. + * + * If the element exists and the key policy is restricted to uniqueness, it is + * replaced after the removal strategy is applied. If it doesn't exist, it is + * inserted into the list. For duplicate keys, it is simply inserted. + * + * @param key Key in the associative map for the value + * @param value Value to be associated with the key + */ + void add(const K &key, const T &value) { + if (_keyPolicy == UniqueKeys) remove(key); + _list.insert(std::make_pair(key, value)); + return; + } + + /** + * Checks the existance of a particular key in the list + * @param key Key to search for in the list + * @return bool True if the key exists, false otherwise + */ + bool exists(const K &key) const { + CollectorConstIter cItr = _list.find(key); + return (cItr != _list.end()); + } + + /** + * @brief Returns the value associated with the name provided + * + * If the specifed name and value does not exist in the list, an out_of_range + * exception is thrown. Use @b exists to predetermine of the value is in the + * list. + * + * @param key Key to fetch the value for + * @return T Value associated with name + * @throws iException if the value is not found + */ + T &get(const K &key) throw (iException &) { + CollectorIter cItr = _list.find(key); + if (cItr == _list.end()) { + std::string mess = "Requested value does not exist!"; + throw iException::Message(iException::Programmer,mess.c_str(),_FILEINFO_); + } + return (cItr->second); + } + + /** + * @brief Const version returning the value associated with the given name + * + * @param key Key to fetch the value for + */ + const T &get(const K &key) const throw (iException &) { + CollectorConstIter cItr = _list.find(key); + if (cItr == _list.end()) { + std::string mess = "Requested value does not exist!"; + throw iException::Message(iException::Programmer,mess.c_str(),_FILEINFO_); + } + return (cItr->second); + } + + /** + * @brief Returns the index of the first occuring element in the list + * + * This returns the index such that the getNth() methods would retrieve the + * element with key. For duplicate keys, it is garaunteed to return the first + * element. It will return -1 if the element is not in the list. + * + * @param key Key to fetch the value for + * + * @return int Zero-based index of (first) element with key. If it doesn't + * exist, -1 is returned. + */ + int index(const K &key) const { + CollectorConstIter cItr = _list.lower_bound(key); + if (cItr == _list.end()) { + return (-1); + } + else { + return (std::distance(_list.begin(), cItr)); + } + } + + /** + * @brief Returns the nth value in the collection + * + * If the specifed value does not exist in the list, an out_of_range exception + * is thrown. Use @b size() to predetermine if the range is valid. + * + * @param nth Return the Nth value in the list + * + * @return T Value associated with name + */ + T &getNth(int nth) throw (iException &) { + CollectorIter cItr; + int i; + for (cItr = _list.begin(), i = 0 ; cItr != _list.end() ; ++cItr, i++) { + if (i == nth) break; + } + + if (cItr == _list.end()) { + std::ostringstream mess; + mess << "Requested index (" << nth << ") out of range" << std::endl; + throw iException::Message(iException::Programmer,mess.str(),_FILEINFO_); + } + return (cItr->second); + } + + /** + * @brief Returns the nth value in the collection + * + * If the specifed value does not exist in the list, an out_of_range exception + * is thrown. Use @b size() to predetermine if the range is valid. + * + * @param nth Return the Nth value in the list + * + * @return T Value associated with name + */ + const T &getNth(int nth) const throw (iException &) { + CollectorConstIter cItr; + int i; + for (cItr = _list.begin(), i = 0 ; cItr != _list.end() ; ++cItr, i++) { + if (i == nth) break; + } + if (cItr == _list.end()) { + std::ostringstream mess; + mess << "Requested index (" << nth << ") out of range" << std::endl; + throw iException::Message(iException::Programmer,mess.str(),_FILEINFO_); + } + return (cItr->second); + } + + /** + * @brief Returns the nth key in the collection + * + * If the specifed key does not exist in the list, an out_of_range exception + * is thrown. Use @b size() to predetermine if the range is valid. + * + * @param nth Return the Nth key in the list + * + * @return K Key associated with name + */ + const K &key(int nth) const throw (iException &) { + CollectorConstIter cItr; + int i; + for (cItr = _list.begin(), i = 0 ; cItr != _list.end() ; ++cItr, i++) { + if (i == nth) break; + } + if (cItr == _list.end()) { + std::ostringstream mess; + mess << "Requested key index (" << nth << ") out of range" << std::endl; + throw iException::Message(iException::Programmer,mess.str(),_FILEINFO_); + } + return (cItr->first); + } + + /** + * Removes and entry from the list + * + * @param key Name of key/value pair to remove from the list + * + * @return int Number of elements erased + */ + int remove(const K &key) { + CollectorIter Itr1 = _list.lower_bound(key); + if (Itr1 == _list.end()) return (0); + + CollectorIter Itr2 = _list.upper_bound(key); + while (Itr1 != Itr2) { + destroy(&Itr1->second); + ++Itr1; + } + return (_list.erase(key)); + } + + /** + * Const iterator into list + * + * @return CollectorConstIter Returns a const iterator to the list + */ + CollectorConstIter begin() const { return _list.begin(); } + + /** + * Const iterator to end of list + * + * @return CollectorConstIter Returns the const end of the list + */ + CollectorConstIter end() const { return _list.end(); } + + /** + * Returns the start of the list for iterating purposes + * + * @return CollectorIter Returns an iterator on the collection + */ + CollectorIter begin() { return _list.begin(); } + + /** + * Returns the end of the list + * + * @return CollectorIter Returns the end of the list for determining the end + * of the iteration loop + */ + CollectorIter end() { return _list.end(); } + + private: + KeyPolicy _keyPolicy; //!< Unique or duplicate key constraint + CollectorList _list; //!< The list + + /** + * @brief Thourough destruction of list + * + * This method iterates through each element in the list applying the + * RemovalPolicy to each value in the map. It then clears the internal list + * for subsequent reuse if needed. + */ + void selfDestruct() { + CollectorIter itr; + for (itr = _list.begin() ; itr != _list.end() ; itr++) { + destroy(&itr->second); + } + _list.clear(); + } + + +}; + +}; +#endif + + diff --git a/isis/src/base/objs/CollectorMap/CollectorMap.truth b/isis/src/base/objs/CollectorMap/CollectorMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..af11837189ac9daf5f8b5a6f7c84f0112828691e --- /dev/null +++ b/isis/src/base/objs/CollectorMap/CollectorMap.truth @@ -0,0 +1,108 @@ + +Size of double map = 0 +Size of double map = 2 +One = 1 +Two = 2 + +Test Const one = 1 + + +Create array of 10 doubles... +Size of array map = 1 +Initializing 0 to 9... + +Checking values... +Array[0] = 0 +Array[1] = 1 +Array[2] = 2 +Array[3] = 3 +Array[4] = 4 +Array[5] = 5 +Array[6] = 6 +Array[7] = 7 +Array[8] = 8 +Array[9] = 9 + + +Test Class copying activity and scoping... +Done with 1, doing 2... +Done with 2, removing 1... +Removed 1, doing 3... +Get ClassTest 2 via a copy +Got it: 2 +Get ClassTest 3 via a reference +Got it: 3 + + +Test CollectorMap copy operation... +Copy size: 2 +ClassTest 2 copy Ident: 2 +Going out of scope for ClassTest 1 + + +Test ClassTest Pointers... +Remove ClassTest 6 + + +Testing Const Iterators... +Const Test Ident = 4 +Const Test Ident = 5 +Const Test Ident = 7 + + +Testing Non-Const Iterators... +Non-Const Test Ident = 4 +Nth Test Ident = 4 +Non-Const Test Ident = 5 +Nth Test Ident = 5 +Non-Const Test Ident = 7 +Nth Test Ident = 7 + + +Test copying of pointer object... +Copied the pointer map, size: 3 + + +Testing internal class usage... +Adding Class 10! +Adding 10 to int list +Int list size = 1 +Adding 10 to double list +Double list size = 1 +Adding 10 to string list +iString list size = 1 + + +Adding Class 11! +Adding 11 to int list +Int list size = 2 +Adding 11 to double list +Double list size = 2 +Adding 11 to string list +iString list size = 2 +Got element 10 and 10 - In string?: 1 +Exists in double list?: 1 +Got element 11 and 11 - In string? 1 + + +Testing Duplicate Keys... +Size of Dup object: 6 +Number Ones: 3 +Number Twos: 2 +Number Threes: 1 +Number Fours: 0 +IntStr[0] = {1, One}, Index: 0 +Nth Test Ident = One +IntStr[1] = {1, One #2}, Index: 0 +Nth Test Ident = One #2 +IntStr[2] = {1, One #3}, Index: 0 +Nth Test Ident = One #3 +IntStr[3] = {2, Two}, Index: 3 +Nth Test Ident = Two +IntStr[4] = {2, Two #2}, Index: 3 +Nth Test Ident = Two #2 +IntStr[5] = {3, Three}, Index: 5 +Nth Test Ident = Three +Non-existant Index: -1 + +Terminating... diff --git a/isis/src/base/objs/CollectorMap/Makefile b/isis/src/base/objs/CollectorMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ddcb974eef4f56217c72d225c7ae641496195e92 --- /dev/null +++ b/isis/src/base/objs/CollectorMap/Makefile @@ -0,0 +1,5 @@ +INCS = CollectorMap.h +SRCS = +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CollectorMap/unitTest.cpp b/isis/src/base/objs/CollectorMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae638bada2b3f13325923351ef47925511c73474 --- /dev/null +++ b/isis/src/base/objs/CollectorMap/unitTest.cpp @@ -0,0 +1,262 @@ +#include +#include +#include +#include +#include "iString.h" +#include "CollectorMap.h" +#include "Preference.h" + + +using namespace std; +using namespace Isis; + +class ClassTest { +public: + ClassTest(int n = 0) : _n(n) { +#if defined(DEBUG) + cout << "ClassTest " << _n << " being created!\n"; +#endif + } + ~ClassTest() { +#if defined(DEBUG) + cout << "ClassTest " << _n << " being destroyed!\n"; +#endif + } + ClassTest(const ClassTest &rhs) : _n(rhs._n) { +#if defined(DEBUG) + cout << "ClassTest " << _n << " being copy constructed!\n"; +#endif + } + ClassTest &operator=(const ClassTest &rhs) { + if (&rhs != this) { +#if defined(DEBUG) + cout << "Copying ClassTest(" << rhs._n << ")\n"; +#endif + _n = rhs._n; + } + return (*this); + } + + int Ident() const { return (_n); } + +private: + int _n; +}; + + +class TestCollector { +public: + TestCollector() { } + ~TestCollector() { } + + void addClass(const ClassTest &t) { + cout << "Adding " << t.Ident() << " to int list\n"; + _list.add(t.Ident(), t); + cout << "Int list size = " << _list.size() << "\n"; + + cout << "Adding " << t.Ident() << " to double list\n"; + _flist.add(t.Ident(), t); + cout << "Double list size = " << _flist.size() << "\n"; + + cout << "Adding " << t.Ident() << " to string list\n"; + _slist.add(iString(t.Ident()), t); + cout << "iString list size = " << _slist.size() << "\n"; + + return; + } + + ClassTest &find(int n) { + cout << "Exists in double list?: " << _flist.exists(n) << endl; + return(_list.get(n)); + } + + + ClassTest &find(double n) { + cout << "Exists in int list?: " << _flist.exists(n) << endl; + return(_flist.get(n)); + } + + ClassTest &findInString(double n) { + string sN= iString(n); + cout << "Exists in int list?: " << _slist.exists(sN) << endl; + return(_slist.get(sN)); + } + + void report(int n) const { + bool exists = _list.exists(n); + const ClassTest &t = _list.get(n); + exists = _flist.exists(n); + const ClassTest &ft = _flist.get(n); + exists = _slist.exists(iString(n)); + cout << "Got element " << t.Ident() << " and " << ft.Ident() + << " - In string?: " << exists << endl; + return; + } + + void reportNth(int i) const { + const ClassTest &t = _list.getNth(i); + bool exists = _flist.exists(t.Ident()); + const ClassTest &ft = _flist.getNth(i); + exists = _slist.exists(iString(t.Ident())); + cout << "Got element " << t.Ident() << " and " << ft.Ident() + << " - In string? " << exists << endl; + return; + } + + +private: + CollectorMap _list; + CollectorMap _flist; + CollectorMap _slist; + +}; + +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + typedef CollectorMap NoCaseStrings; + NoCaseStrings dmap; + + cout << "\nSize of double map = " << dmap.size() << endl; + dmap.add("two", 2.0); + dmap.add("one", 1.0); + cout << "Size of double map = " << dmap.size() << endl; + + cout << "One = " << dmap.get("one") << endl; + cout << "Two = " << dmap.get("Two") << endl; + + const double &one = dmap.get("one"); + cout << "\nTest Const one = " << one << endl; + + dmap.remove("one"); + + + cout << "\n\nCreate array of 10 doubles...\n"; + typedef CollectorMap ArrayMap; + ArrayMap buffer; + buffer.add("array", new double[10]); + + cout << "Size of array map = " << buffer.size() << endl; + cout << "Initializing 0 to 9...\n"; + for (int i = 0 ; i < 10 ; i++) { + buffer.get("array")[i] = (double) i; + } + + + cout << "\nChecking values...\n"; + double *d = buffer.get("array"); + for (int j = 0 ; j < 10 ; j++) { + cout << "Array[" << j << "] = " << d[j] << endl; + } + + cout << "\n\nTest Class copying activity and scoping...\n"; + { + typedef CollectorMap ClassMap; + ClassMap ctest1; + ctest1.add(1,ClassTest(1)); + cout << "Done with 1, doing 2...\n"; + ctest1.add(2,ClassTest(2)); + cout << "Done with 2, removing 1...\n"; + ctest1.remove(1); + cout << "Removed 1, doing 3...\n"; + ctest1.add(3,ClassTest(3)); + + cout << "Get ClassTest 2 via a copy\n"; + ClassTest two = ctest1.get(2); + cout << "Got it: " << two.Ident() << endl; + + + cout << "Get ClassTest 3 via a reference\n"; + ClassTest &three = ctest1.get(3); + cout << "Got it: " << three.Ident() << endl; + + + cout << "\n\nTest CollectorMap copy operation...\n"; + ClassMap cCopy = ctest1; + cout << "Copy size: " << cCopy.size() << endl; + cout << "ClassTest 2 copy Ident: " << cCopy.get(2).Ident() << endl; + + cout << "Going out of scope for ClassTest 1\n"; + } + + cout << "\n\nTest ClassTest Pointers...\n"; + typedef CollectorMap PointerMap; + PointerMap ctest2; + ctest2.add(4,new ClassTest(4)); + ctest2.add(5,new ClassTest(5)); + ctest2.add(6,new ClassTest(6)); + ctest2.add(7,new ClassTest(7)); + + cout << "Remove ClassTest 6\n"; + ctest2.remove(6); + +// Test const interators + cout << "\n\nTesting Const Iterators...\n"; + PointerMap::CollectorConstIter cIter; + for (cIter = ctest2.begin() ; cIter != ctest2.end() ; ++cIter) { + cout << "Const Test Ident = " << cIter->second->Ident() << endl; + } + + // Test non-const interators and fetch routine + cout << "\n\nTesting Non-Const Iterators...\n"; + PointerMap::CollectorIter ncIter; + int i = 0; + for (ncIter = ctest2.begin() ; ncIter != ctest2.end() ; ++ncIter, i++) { + cout << "Non-Const Test Ident = " << ncIter->second->Ident() << endl; + cout << "Nth Test Ident = " << ctest2.getNth(i)->Ident() << endl; + } + +// Ok...let's test the pointer copy constructor + cout << "\n\nTest copying of pointer object...\n"; + PointerMap map2(ctest2); + cout << "Copied the pointer map, size: " << map2.size() << endl; + +// Test internal class usage + cout << "\n\nTesting internal class usage...\n"; + TestCollector t; + cout << "Adding Class 10!\n"; + t.addClass(ClassTest(10)); + cout << "\n\nAdding Class 11!\n"; + t.addClass(ClassTest(11)); + t.report(10); + t.find(11); + t.reportNth(1); + + // Test duplicate keys + cout << "\n\nTesting Duplicate Keys...\n"; + typedef CollectorMap IntStr; + IntStr dupstr(IntStr::DuplicateKeys); + dupstr.add(1,"One"); + dupstr.add(1, "One #2"); + dupstr.add(1,"One #3"); + dupstr.add(2,"Two"); + dupstr.add(2,"Two #2"); + dupstr.add(3,"Three"); + + cout << "Size of Dup object: " << dupstr.size() << endl; + cout << "Number Ones: " << dupstr.count(1) << endl; + cout << "Number Twos: " << dupstr.count(2) << endl; + cout << "Number Threes: " << dupstr.count(3) << endl; + cout << "Number Fours: " << dupstr.count(4) << endl; + IntStr::CollectorConstIter isIter; + int j = 0; + for (isIter = dupstr.begin() ; isIter != dupstr.end() ; ++isIter, j++) { + cout << "IntStr[" << j << "] = {" << isIter->first << ", " + << isIter->second << "}, Index: " << dupstr.index(isIter->first) + << endl; + cout << "Nth Test Ident = " << dupstr.getNth(j) << endl; + } + + cout << "Non-existant Index: " << dupstr.index(4) << endl; + + + cout << "\nTerminating...\n"; + + return (0); +} diff --git a/isis/src/base/objs/Column/Column.cpp b/isis/src/base/objs/Column/Column.cpp new file mode 100644 index 0000000000000000000000000000000000000000..23126ae31ef15b51fc4f6b2523f06030b82c6ec8 --- /dev/null +++ b/isis/src/base/objs/Column/Column.cpp @@ -0,0 +1,153 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/10/14 18:15:36 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "Column.h" +#include "iException.h" + +namespace Isis{ + + /** + * Constructor. Sets the precision for decimal-aligned columns to 4 + */ + Column::Column(){ + p_precision = 4; + p_width = 0; + p_name = ""; + SetAlignment(Column::NoAlign); + SetType(Column::NoType); + } + + /** + * Constructor with parameter + * + * @param name The name of the column, used as the header + * @param width The width (in characters) to make the column + * @param type The type of information the column is to represent + * @param align The alignment, within the column, the data is to conform to + */ + Column::Column( std::string name, int width, Column::Type type, Column::Align align) { + //Set the parameters with function calls, to make use of pre-existing error checks + SetWidth(width); + SetName(name); + SetType(type); + SetAlignment(align); + + p_precision = 4; + } + + /** + * Sets the Column name, or header + * + * @param name The name of the Column + */ + void Column::SetName (std::string name) { + if (p_width != 0 && name.length() > p_width) { + std::string message = "Name[" + name + "] is wider than width"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + p_name = name; + } + + /** + * Sets the width of the Column, in text columns + * + * @param width The number of text columns the Column will hold + */ + void Column::SetWidth (unsigned int width) { + if (p_name.size() > 0 && p_name.size() > width) { + std::string message = "Width is insufficient to contain name["; + message += p_name + "]"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + p_width = width; + } + + /** + * Sets the data type of the Column + * + * @param type The data type for the Column + */ + void Column::SetType (Column::Type type) { + if (p_align == Column::Decimal && + (type == Column::Integer || type == Column::String)) { + std::string message = "Integer or string type is not sensible if "; + message += "alignment is Decimal."; + throw iException::Message(iException::User,message,_FILEINFO_); + } + p_type = type; + } + + /** + * Sets the alignment of the Column + * + * The text in the Column will be aligned according to this parameter, + * which is Right, Left, or, possible only with real-number values, + * aligned by the decimal point + * + * @param alignment The alignment of the text in the Column + */ + void Column::SetAlignment (Column::Align alignment) { + if (alignment == Column::Decimal && + (p_type == Column::Integer || p_type == Column::String)) { + std::string message = "Decimal alignment does not make sense for "; + message += "integer or string values."; + throw iException::Message(iException::Programmer,message,_FILEINFO_); + } + p_align = alignment; + } + + /** + * Sets the precision of the Column, for real number values + * + * This sets the number of digits after the decimal point, for decimal aligned + * values. If the Column's alignment is anything else, an error is thrown. + * + * @param precision The number of digits after the decimal point to be shown + */ + void Column::SetPrecision(unsigned int precision) { + if (DataType() != Column::Real && + DataType() != Column::Pixel) { + std::string message = "Setting precision only makes sense for Decimal Alignment"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + p_precision = precision; + } + + + /** + * Returns the type of data this column will contain + * + * @return Column::Type The data type of this column + */ + Column::Type Column::DataType() { + + if (p_type == 0) { + std::string message = "Type has not been set yet!"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + + return p_type; + } +} diff --git a/isis/src/base/objs/Column/Column.h b/isis/src/base/objs/Column/Column.h new file mode 100644 index 0000000000000000000000000000000000000000..73cadfe58ebfb3fa23bdb981f9e2086c1680f748 --- /dev/null +++ b/isis/src/base/objs/Column/Column.h @@ -0,0 +1,115 @@ +#ifndef Column_h +#define Column_h + +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/10/14 18:15:36 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +namespace Isis { + /** + * @brief Format ascii tables + * + * This class takes in a series of string vectors and writes them out to a + * file as a table. Formatting options are up to the user. + * + * @ingroup Utility + * + * @author 2007-05-01 Brendan George + * + * @internal + * @history 2007-06-18 Brendan George Fixed error message outputs and + * unitTest + * @history 2009-10-14 Eric Hyer Added documentation; + * Moved from base/apps/cubediff to base/objs; + */ + class Column { + public: + + //! Alignment of data in the Column + enum Align { + //! no alignment + NoAlign = 0, + //! right alignment + Right = 1, + //! left alignment + Left = 2, + //! decimal alignment + Decimal = 3 + }; + + //! Type of data in the Column + enum Type { + //! No data type + NoType = 0, + //! Integer data type + Integer = 1, + //! Real data type + Real = 2, + //! String data type + String = 3, + //! Pixel data type + Pixel = 4 + }; + + Column (); + Column (std::string name, int width, Column::Type type, Align align=Column::Right); + void SetName (std::string name); + void SetWidth (unsigned int width); + void SetType (Column::Type type); + void SetAlignment (Column::Align alignment); + void SetPrecision (unsigned int precision); + + //! get the Column's name + std::string Name() { return p_name; }; + + //! get the Column's width + unsigned int Width() { return p_width; }; + + Column::Type DataType(); + + //! get the Column's alignment + Column::Align Alignment() { return p_align; }; + + //! get the Column's precision + unsigned int Precision() { return p_precision; }; + + private: + //! Name of the Column + std::string p_name; + + //! Width of the Column + unsigned int p_width; + + //! Type of the data in the Column + Column::Type p_type; + + //! Alignment of the data in the Column + Column::Align p_align; + + //! Precision of the data in the Column + unsigned int p_precision; + }; +}; + +#endif diff --git a/isis/src/base/objs/Column/Column.truth b/isis/src/base/objs/Column/Column.truth new file mode 100644 index 0000000000000000000000000000000000000000..69077fa04f3ed70889ce811a99ffc98b1a41722e --- /dev/null +++ b/isis/src/base/objs/Column/Column.truth @@ -0,0 +1,13 @@ + +Unit Test for Column!!! + +Name() returns: test column + +Width() returns: 15 + +DataType() returns: 1 + +Alignment() returns: 1 + +Precision() returns: 4 + diff --git a/isis/src/base/objs/Column/Makefile b/isis/src/base/objs/Column/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..49ed6086d77ece9424d8ca27ab2c6b075659773c --- /dev/null +++ b/isis/src/base/objs/Column/Makefile @@ -0,0 +1,5 @@ +INCS = Column.h +SRCS = Column.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Column/unitTest.cpp b/isis/src/base/objs/Column/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b15b5c37e5320c3729e9c899fb52bcb05cdb6157 --- /dev/null +++ b/isis/src/base/objs/Column/unitTest.cpp @@ -0,0 +1,26 @@ +#include "Column.h" + +#include + +#include "Preference.h" + + + +using namespace std; +using namespace Isis; + +int main() +{ + cerr << "\nUnit Test for Column!!!\n\n"; + Preference::Preferences(true); + + Column * testColumn = new Column("test column", 15, Column::Integer); + + cerr << "Name() returns: " << testColumn->Name() << "\n\n"; + cerr << "Width() returns: " << testColumn->Width() << "\n\n"; + cerr << "DataType() returns: " << testColumn->DataType() << "\n\n"; + cerr << "Alignment() returns: " << testColumn->Alignment() << "\n\n"; + cerr << "Precision() returns: " << testColumn->Precision() << "\n\n"; + + return 0; +} diff --git a/isis/src/base/objs/Constants/Constants.h b/isis/src/base/objs/Constants/Constants.h new file mode 100644 index 0000000000000000000000000000000000000000..3c65835571604155d15eadba91c75e7e4b081b4f --- /dev/null +++ b/isis/src/base/objs/Constants/Constants.h @@ -0,0 +1,66 @@ +/** + * @file + * $Revision: 1.43 $ + * $Date: 2010/05/24 22:57:44 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef Constants_h +#define Constants_h + +#include + +namespace Isis { + /** + * @brief Sets some basic constants for use in ISIS programming + * + * Sets constants used in ISIS applications and objects such as PI and E. + * + * @ingroup Utility + * + * @author 2003-01-22 Tracie Sucharski + * + * @internal + * @history 2003-02-11 Stuart Sides - Documented and created an object + * unitTest. + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2006-05-17 Elizabeth Miller - Removed .xml file and added + * documentation to .h file + * @history 2009-03-16 Tracie Sucharski - Updated for release 3.2.0. + * @history 2010-03-18 Tracie Sucharski - Updated to 3.2.1beta. + * @history 2010-05-24 Travis Addair - Added DEG2RAD and + * RAD2DEG + */ + + const std::string version("3.2.1beta | 2010-03-18"); + + const double E(2.7182818284590452354); //! +#include +#include "Constants.h" +#include "Preference.h" + +using namespace std; + +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Unit test for IsisConstants" << endl; + + cout << setprecision(16) << setw(17) << endl; + cout << Isis::PI << endl; + cout << Isis::HALFPI << endl; + cout << Isis::E << endl; + cout << Isis::DEG2RAD << endl; + cout << Isis::RAD2DEG << endl; + cout << "PI/2 radians is " << Isis::HALFPI *Isis::RAD2DEG << " degrees" << endl; + cout << "180 degrees is " << 180 * Isis::DEG2RAD << " radians" << endl << endl; + + cout << sizeof(Isis::BigInt) << endl; + +} + + + + + + diff --git a/isis/src/base/objs/ControlGraph/ControlGraph.cpp b/isis/src/base/objs/ControlGraph/ControlGraph.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9532cfea5c0d0becfe7f675df6c24afa4d810ef6 --- /dev/null +++ b/isis/src/base/objs/ControlGraph/ControlGraph.cpp @@ -0,0 +1,520 @@ +#include "IsisDebug.h" +#include "ControlGraph.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ControlMeasure.h" +#include "GroupedStatistics.h" +#include "ControlNet.h" +#include "iException.h" +#include "iString.h" + + + +namespace Isis +{ + + /** + * construct a ControlGraph given a ControlNet + * + * @param someControlNet ControlNet to construct a ControlGraph from + */ + ControlGraph::ControlGraph(ControlNet * someControlNet) + { + cnet = someControlNet; + cubeIdToIndexHash = NULL; + cubeIndexToIdHash = NULL; + graph = NULL; + graph = new QMap< int, QPair< AdjacentCubeList, GroupedStatistics > >(); + + // cubeIdToIndexHash provides a way of assigning unique sequential indices + // to all of the Cube Serial numbers in the ControlNet, while + // cubeIndexToIdHash prvides a way to get the Cube Serial numbers back. + cubeIdToIndexHash = new QHash< QString, int >(); + cubeIndexToIdHash = new QHash< int, QString >(); + cubeIdToIndexHash->reserve(cnet->Size() / 5); + cubeIndexToIdHash->reserve(cnet->Size() / 5); + + HashCubesAndPopulateGraph(someControlNet); + + CalculateIslands(); + + if (islands->size()) + connected = false; + else + connected = true; + } + + + /** + * copy construct a ControlGraph object + * + * @param other The ControlGraph to construct a copy of + */ + ControlGraph::ControlGraph(const ControlGraph & other) + { + cnet = other.cnet; + + cubeIdToIndexHash = NULL; + cubeIndexToIdHash = NULL; + graph = NULL; + islands = NULL; + + cubeIdToIndexHash = new QHash< QString, int >(*other.cubeIdToIndexHash); + cubeIndexToIdHash = new QHash< int, QString >(*other.cubeIndexToIdHash); + graph = new QMap< int, QPair< AdjacentCubeList, GroupedStatistics > >( + *other.graph); + islands = new QVector< QVector< int > >(*other.islands); + + connected = other.connected; + } + + + /** + * Destruct a ControlGraph + */ + ControlGraph::~ControlGraph() + { + cnet = NULL; + + if (cubeIdToIndexHash) + { + delete cubeIdToIndexHash; + cubeIdToIndexHash = NULL; + } + + if (cubeIndexToIdHash) + { + delete cubeIndexToIdHash; + cubeIndexToIdHash = NULL; + } + + if (graph) + { + delete graph; + graph = NULL; + } + + if (islands) + { + delete islands; + islands = NULL; + } + } + + + //! Returns true if this ControlGraph is connected or false otherwise + const bool ControlGraph::IsConnected() const + { + return connected; + } + + + /** + * There can be 0 islands or 2 or more islands. GetIslandCount will never + * return 1 since 1 island is really just a connected graph (with 0 islands). + */ + const int ControlGraph::GetIslandCount() const + { + return islands->size(); + } + + + /** + * @param island A list of all cubes that are on this island are desired + * + * @returns A list of CubeSerialNumbers which are located on the given island + */ + const QVector< QString > ControlGraph::GetCubesOnIsland(const int & island) + const + { + if (connected) + { + std::string message = "\n\nGetCubesOnIsland called on connected graph "; + message += "with no islands!!!\n\n"; + throw Isis::iException::Message(Isis::iException::Programmer, message, + _FILEINFO_); + } + + ASSERT(islands->size() != 0); + + if (island < 0 || island >= islands->size()) + { + iString message = "\n\nA list of cubes was requested from island "; + message += iString(island); + message += "\nbut that island does not exist!!!"; + message += "\n\nThere are " + iString(islands->size()) + " islands "; + message += "numbered from 0 to " + iString(islands->size() - 1) + "\n\n"; + throw Isis::iException::Message(Isis::iException::Programmer, message, + _FILEINFO_); + } + + QVector< QString > cubeList; + for (int i = 0; i < (*islands)[island].size(); i++) + { + cubeList.push_back(cubeIndexToIdHash->value((*islands)[island][i])); + } + + return cubeList; + } + + + /** + * @returns A list of all CubeSerialNumbers in the given ControlNet + */ + const QVector< QString > ControlGraph::GetCubeList() const + { + QVector< QString > cubeList; + + // for each key in the cubeIdToIndexHash add the key to a vector + QHash< QString, int >::const_iterator i = cubeIdToIndexHash->constBegin(); + while (i != cubeIdToIndexHash->constEnd()) + { + cubeList.push_back(i.key()); + i++; + } + + return cubeList; +} + + + /** + * @param CubeSerialNumber The Serial number of the cube to get Statistics on + * + * @returns Statistics for all measures associated with the given cube + */ + const GroupedStatistics & ControlGraph::GetMeasureStats(const QString & + CubeSerialNumber) const + { + return graph->find(cubeIdToIndexHash->value(CubeSerialNumber)).value() + .second; + } + + + /** + * @param other The ControlGraph on the right side of the = + */ + ControlGraph & ControlGraph::operator=(const ControlGraph & other) + { + cnet = other.cnet; + connected = other.connected; + + delete cubeIdToIndexHash; + cubeIdToIndexHash = NULL; + delete cubeIndexToIdHash; + cubeIndexToIdHash = NULL; + delete graph; + graph = NULL; + delete islands; + islands = NULL; + + cubeIdToIndexHash = new QHash< QString, int >(*other.cubeIdToIndexHash); + cubeIndexToIdHash = new QHash< int, QString >(*other.cubeIndexToIdHash); + graph = new QMap< int, QPair< AdjacentCubeList, GroupedStatistics > >( + *other.graph); + islands = new QVector< QVector< int > >(*other.islands); + + return *this; + } + + + /** + * @param someControlNet The ControlNet to create a ControlGraph from + */ + void ControlGraph::HashCubesAndPopulateGraph(ControlNet * someControlNet) + { + // index assigned to last hashed cube (-1 means empty hash table) + int cubeIndex = -1; + + // whats about to happen is this: + // + // for all ControlPoints in the given ControlNet + // for each ControlMeasure (cube) in the ControlPoint + // for all the other ControlMeasures (other cubes) in the ControlPoint + // add connection from previous for loops cube to this for loops cube + // + // along the way as we encounter new cubes they are hashed. Also, for all + // the measures encountered be the middle for loop statistics are saved. + + for (int cpIndex = 0; cpIndex < cnet->Size(); cpIndex++) + { + if (!(*cnet)[cpIndex].Ignore()) + { + // use a reference for the current ControlPoint for clearity + ControlPoint & curCtrlPoint = (*cnet)[cpIndex]; + for (int cmIndex = 0; cmIndex < curCtrlPoint.Size(); cmIndex++) + { + // get current cube's serial number and hash if new + std::string temp = curCtrlPoint[cmIndex].CubeSerialNumber(); + QString curCube(temp.c_str()); + if (!cubeIdToIndexHash->contains(curCube)) + { + cubeIdToIndexHash->insert(curCube, ++cubeIndex); + cubeIndexToIdHash->insert(cubeIndex, curCube); + } + int curCubeIndex = cubeIdToIndexHash->value(curCube); + + QMap< int, QPair< AdjacentCubeList, GroupedStatistics > + >::iterator graphIterator = graph->find(curCubeIndex); + + // look for adjacent cubes + for (int cmIndex2 = 0; cmIndex2 < curCtrlPoint.Size(); cmIndex2++) + { + if (cmIndex2 != cmIndex) + { + // get adjacent cube's serial number and hash if new + std::string temp = curCtrlPoint[cmIndex2].CubeSerialNumber(); + QString adjacentCube(temp.c_str()); + if (!cubeIdToIndexHash->contains(adjacentCube)) + { + cubeIdToIndexHash->insert(adjacentCube, ++cubeIndex); + cubeIndexToIdHash->insert(cubeIndex, adjacentCube); + } + int adjCubeIndex = cubeIdToIndexHash->value(adjacentCube); + + // add a connection from the current cube to the adjacent cube + if (graphIterator != graph->end()) + { + graphIterator.value().first.AddConnection(adjCubeIndex, cpIndex, + cmIndex2); + } + else + { + AdjacentCubeList newCubeList(adjCubeIndex, cpIndex, cmIndex2); + GroupedStatistics cmStats; + graph->insert(curCubeIndex, qMakePair(newCubeList, cmStats)); + } + } + } // of for all measures in cp + + // save off statistics + if (graphIterator != graph->end()) + { + QVector< QString > dataNames((*cnet)[cpIndex][cmIndex] + .GetMeasureDataNames()); + + for (int i = 0; i < dataNames.size(); i++) + graphIterator.value().second.AddStatistic(dataNames[i], + (*cnet)[cpIndex][cmIndex].GetMeasureData(dataNames[i])); + } // of saving statistics + } // of for all measures in cp + } // of if not an igrored point + } // of for all ControlPoints in net + } // of HashCubesAndPopulateGraph + + + /** + * Determines whether or not islands exist and calculates what they are if + * present + */ + void ControlGraph::CalculateIslands() + { + // assume subgraphs exist! (check assumption at the very end of the method) + + // A search list has a value for every cube, which defaults to false. + // A breadth-first search is used to test connectivity and works by setting + // each cubes cooresponding search list value to true as it is visited. + // At the end of the first round the true entries make up the first + // subgragh. As they are added to the first subgraph they are removed from + // the search list. The remaining false entries must have the breadth-first + // search done on them to determine the next subgraph(s). This process + // continues until all entries in the search list are true (until all cubes + // have been visited) + QMap< int, bool > searchList; + for (int i = 0; i < graph->size(); i++) + searchList.insert(i, false); + + // For each subgraph keep a list of the cubes in the subgraph. This is + // represented by a 2d vector where the inner vectors are cubes within a + // subgraph and the outer vector is a list of subgraphs + islands = new QVector< QVector< int > >(); + + // keeps track of which itteration of the breadth-first search we are on and + // thus also which subgraph we are currently populating + int subgraphIndex = -1; + + while (searchList.size()) + { + // create a new subgraph + subgraphIndex++; + islands->push_back(QVector< int >()); + + // The queue used for breadth-first searching + QQueue< int > q; + + // visit the first cube + searchList.begin().value() = true; + q.enqueue(searchList.begin().key()); + + // visit all cubes possible using the breadth-first approach + while (q.size()) + { + int curVertex(q.dequeue()); + QVector< int > adjacentVertices = graph->find(curVertex).value().first + .GetAdjacentCubes(); + + for (int i = 0; i < adjacentVertices.size(); i++) + { + const int & curNeighbor = adjacentVertices[i]; + + ASSERT(searchList.find(curNeighbor) != searchList.end()); + + if (!searchList.find(curNeighbor).value()) + { + searchList.find(curNeighbor).value() = true; + q.enqueue(curNeighbor); + } + } + } // end of breadth-first search + + // add all true entries to the current subgraph + QMap< int, bool >::iterator i = searchList.begin(); + while (i != searchList.end()) + { + if (i.value()) + { + (*islands)[subgraphIndex].push_back(i.key()); + } + i++; + } + + // remove all the true entries from the search list + for (int i = 0; i < (*islands)[subgraphIndex].size(); i++) + { + searchList.remove((*islands)[subgraphIndex][i]); + } + } + + // if there was only ever one subgraph created then the initial assumption + // was wrong! There are no islands at all - this is a connected graph! + if (subgraphIndex == 0) + { + islands->clear(); + } + } + + + /** + * Construct a new AdjacentCubeList given one initial adjacent connection. + * An adjacent connection means both an adjacent vertex as well as the edge + * that connects it. The cubeIndex is the vertex. The edge is a + * ControlPoint - ControlMeasure combo. + * + * @param cubeIndex First adjacent cube + * @param cpIndex ControlPoint Index + * @param cmIndex ControlMeasure Index + */ + ControlGraph::AdjacentCubeList::AdjacentCubeList(const int & cubeIndex, + const int & cpIndex, const int & cmIndex) + { + connections = NULL; + + QVector< QPair< int, int > > firstEdge; + firstEdge.push_back(qMakePair(cpIndex, cmIndex)); + connections = new QMap< int, QVector< QPair< int, int > > >(); + connections->insert(cubeIndex, firstEdge); + } + + + /** + * copy construct an AdjacentCubeList + * + * @param other The AdjacentCubeList to construct a copy of + */ + ControlGraph::AdjacentCubeList::AdjacentCubeList(const AdjacentCubeList & + other) + { + connections = NULL; + connections = new QMap< int, QVector< QPair< int, int > > >( + *other.connections); + } + + + //! destruct an AdjacentCubeList + ControlGraph::AdjacentCubeList::~AdjacentCubeList() + { + if (connections) + { + delete connections; + connections = NULL; + } + } + + + /** + * @returns A list of adjacent cubes! + */ + const QVector< int > ControlGraph::AdjacentCubeList::GetAdjacentCubes() const + { + // vector of adjacent cubes to be returned + QVector< int > adjacentCubes; + + if (!connections) + return adjacentCubes; + + QMap< int, QVector< QPair< int, int > > >::const_iterator i = + connections->constBegin(); + while (i != connections->constEnd()) + { + adjacentCubes.push_back(i.key()); + i++; + } + + return adjacentCubes; + } + + + /** + * Adds a connection to an AdjacentCubeList. A connection consists of a new + * vertex as well as the edge that connects it. The vertex is the cube index + * and the edge is the ControlPoint - ControlMeasure combo. + * + * @param cubeIndex Adjacent cube + * @param cpIndex ControlPoint index + * @param cmIndex ControlMeasure index + */ + void ControlGraph::AdjacentCubeList::AddConnection(const int & cubeIndex, + const int & cpIndex, const int & cmIndex) + { + QMap< int, QVector< QPair< int, int > > >::iterator i = + connections->find(cubeIndex); + + // if the cube already exists in our list then just add another edge to it. + // otherwise we need to add the cube as well. + if (i != connections->end()) + { + i.value().push_back(qMakePair(cpIndex, cmIndex)); + } + else + { + QVector< QPair< int, int > > firstEdge; + firstEdge.push_back(qMakePair(cpIndex, cmIndex)); + connections->insert(cubeIndex, firstEdge); + } + } + + + /** + * @param other The AdjacentCubeList on the right side of the = + */ + ControlGraph::AdjacentCubeList & ControlGraph::AdjacentCubeList::operator=( + const AdjacentCubeList & other) + { + delete connections; + connections = NULL; + + connections = new QMap< int, QVector< QPair< int, int > > >( + *other.connections); + + return *this; + } +} diff --git a/isis/src/base/objs/ControlGraph/ControlGraph.h b/isis/src/base/objs/ControlGraph/ControlGraph.h new file mode 100644 index 0000000000000000000000000000000000000000..ae0d849424bbbe4d26ca60c70ef7e0f403818ebb --- /dev/null +++ b/isis/src/base/objs/ControlGraph/ControlGraph.h @@ -0,0 +1,143 @@ +#ifndef ControlGraph_h +#define ControlGraph_h + +/** + * @file + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +// Global forward declarations +template< class A, class B > class QHash; +template< class A, class B > class QMap; +template< class A, class B > class QPair; +template< class A> class QVector; +class QString; + +namespace Isis +{ + + // Isis forward declarations + class ControlNet; + class GroupedStatistics; + + /** + * @brief Control Network statistics and connectivity + * + * This class is used to store statistics on a Control Network + * + * This class is include safe meaning that includers of this class will only + * get this class. + * + * @ingroup ControlGraph + * + * @author Eric Hyer + * @history 2009-09-23 Eric Hyer Original version + * @history 2009-10-15 Eric Hyer Added GetCubeList Method + * + * @see ControlNet ControlPoint ControlMeasure GroupedStatistics + * + * @internal + * + */ + class ControlGraph + { + public: + ControlGraph(ControlNet * someControlNet); + ControlGraph(const ControlGraph & other); + ~ControlGraph(); + + const bool IsConnected() const; + const int GetIslandCount() const; + const QVector< QString > GetCubesOnIsland(const int & island) const; + const QVector< QString > GetCubeList() const; + const GroupedStatistics & GetMeasureStats(const QString & + CubeSerialNumber) const; + + ControlGraph & operator=(const ControlGraph & other); + + private: + // nested class forward declaration + class AdjacentCubeList; + + void HashCubesAndPopulateGraph(ControlNet * someControlNet); + void CalculateIslands(); + + //! ControlNet to make a graph from + ControlNet * cnet; + + //! Used to get an index from a cube serial number + QHash< QString, int > * cubeIdToIndexHash; + + //! Used to get a cube serial number from an index + QHash< int, QString > * cubeIndexToIdHash; + + /** + * THE GRAPH!! It is a map of cube indices to a pair. The first pair + * element is a list that contains not only all the cubes which are + * adjacent to it (as indices also), but also the edges that make these + * these connections. The second pair element contains statistics on + * this cube. + */ + QMap< int, QPair< AdjacentCubeList, GroupedStatistics > > * graph; + + /** + * Stores the state of the graphs connectivity so that connectivity must + * only be calculated once. + */ + bool connected; + + //! Stores a list of islands which are themselves a list of cube indices + QVector< QVector< int > > * islands; + + /** + * @brief Control Graph nested class + * + * This class is used to store adjacent cube connections for ControlGraph + * + * @ingroup ControlGraph + * + * @author 2009-09-18 Eric Hyer + * + * @see ControlGraph + * + * @internal + * + */ + class AdjacentCubeList + { + public: + AdjacentCubeList(const int & cubeIndex, const int & cpIndex, const int + & cmIndex); + AdjacentCubeList(const AdjacentCubeList & other); + ~AdjacentCubeList(); + + const QVector< int > GetAdjacentCubes() const; + void AddConnection(const int & cubeIndex, const int & cpIndex, const + int & cmIndex); + AdjacentCubeList & operator=(const AdjacentCubeList & other); + + private: + //! stores all edges or connections for an adjacent cube + QMap< int, QVector< QPair< int, int > > > * connections; + }; + }; +}; + +#endif + diff --git a/isis/src/base/objs/ControlGraph/ControlGraph.truth b/isis/src/base/objs/ControlGraph/ControlGraph.truth new file mode 100644 index 0000000000000000000000000000000000000000..9bbd1843e62c3ba0d9e63ed5878e758d9db7ef8e --- /dev/null +++ b/isis/src/base/objs/ControlGraph/ControlGraph.truth @@ -0,0 +1,43 @@ + +Unit Test for ControlGraph!!! + +building the following ControlNet for testing... + + ControlPoint | Images +----------------|-------------------------- + 0 | A B + 1 | A B C + 2 | A B C + 3 | B C + 4 | B C + 5 | D E + +ControlNet built! + +constructing a ControlGraph... +ControlGraph constructed! + +IsConnected() returns: false + +GetIslandCount returns: 2 + +GetCubesOnIsland(0) returns: A B C + +GetCubesOnIsland(1) returns: D E + +GetCubesOnIsland(42) returns:**PROGRAMMER ERROR** + +A list of cubes was requested from island 42 +but that island does not exist!!! + +There are 2 islands numbered from 0 to 1 + + + +GetCubeList() returns: + D + E + A + B + C + diff --git a/isis/src/base/objs/ControlGraph/Makefile b/isis/src/base/objs/ControlGraph/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f1b414e724e1d23f29a19114990d97fd5a156e1e --- /dev/null +++ b/isis/src/base/objs/ControlGraph/Makefile @@ -0,0 +1,6 @@ +INCS = ControlGraph.h +SRCS = ControlGraph.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/base/objs/ControlGraph/unitTest.cpp b/isis/src/base/objs/ControlGraph/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58aab191cf6d527f4058923b68e5f257da666246 --- /dev/null +++ b/isis/src/base/objs/ControlGraph/unitTest.cpp @@ -0,0 +1,157 @@ +#include "ControlPoint.h" +#include "ControlMeasure.h" +#include "ControlNet.h" +#include "iException.h" +#include "Preference.h" +#include "ControlGraph.h" + +#include + +#include + + +using namespace std; +using namespace Isis; + +int main() +{ + cerr << "\nUnit Test for ControlGraph!!!\n\n" + "building the following ControlNet for testing...\n\n"; + Preference::Preferences(true); + + // control point 0 + ControlMeasure cp0cm1; + cp0cm1.SetCubeSerialNumber("A"); + ControlMeasure cp0cm2; + cp0cm2.SetCubeSerialNumber("B"); + + ControlPoint cp0("0"); + cp0.Add(cp0cm1); + cp0.Add(cp0cm2); + + + // control point 1 + ControlMeasure cp1cm1; + cp1cm1.SetCubeSerialNumber("A"); + ControlMeasure cp1cm2; + cp1cm2.SetCubeSerialNumber("B"); + ControlMeasure cp1cm3; + cp1cm3.SetCubeSerialNumber("C"); + + ControlPoint cp1("1"); + cp1.Add(cp1cm1); + cp1.Add(cp1cm2); + cp1.Add(cp1cm3); + + + // control point 2 + ControlMeasure cp2cm1; + cp2cm1.SetCubeSerialNumber("A"); + ControlMeasure cp2cm2; + cp2cm2.SetCubeSerialNumber("B"); + ControlMeasure cp2cm3; + cp2cm3.SetCubeSerialNumber("C"); + + ControlPoint cp2("2"); + cp2.Add(cp2cm1); + cp2.Add(cp2cm2); + cp2.Add(cp2cm3); + + + // control point 3 + ControlMeasure cp3cm1; + cp3cm1.SetCubeSerialNumber("B"); + ControlMeasure cp3cm2; + cp3cm2.SetCubeSerialNumber("C"); + + ControlPoint cp3("3"); + cp3.Add(cp3cm1); + cp3.Add(cp3cm2); + + + // control point 4 + ControlMeasure cp4cm1; + cp4cm1.SetCubeSerialNumber("B"); + ControlMeasure cp4cm2; + cp4cm2.SetCubeSerialNumber("C"); + + ControlPoint cp4("4"); + cp4.Add(cp4cm1); + cp4.Add(cp4cm2); + + + // control point 5 + ControlMeasure cp5cm1; + cp5cm1.SetCubeSerialNumber("D"); + ControlMeasure cp5cm2; + cp5cm2.SetCubeSerialNumber("E"); + + ControlPoint cp5("5"); + cp5.Add(cp5cm1); + cp5.Add(cp5cm2); +// cp5.SetIgnore(true); + + + // now build controlnet + ControlNet cnet; + cnet.Add(cp0); + cnet.Add(cp1); + cnet.Add(cp2); + cnet.Add(cp3); + cnet.Add(cp4); + cnet.Add(cp5); + + cerr << " ControlPoint | Images\n" + "----------------|--------------------------"; + for (int i = 0; i < cnet.Size(); i++) + { + cerr << "\n\t" << cnet[i].Id() << "\t|"; + for (int j = 0; j < cnet[i].Size(); j++) + { + cerr << "\t" << cnet[i][j].CubeSerialNumber(); + } + } + cerr << "\n\nControlNet built!\n\n" + "constructing a ControlGraph...\n"; + + ControlGraph cg(&cnet); + cerr << "ControlGraph constructed!\n\n" + "IsConnected() returns: "; + + if (cg.IsConnected()) + cerr << "true\n\n"; + else + cerr << "false\n\n"; + + cerr << "GetIslandCount returns: " << cg.GetIslandCount() << "\n\n" + "GetCubesOnIsland(0) returns:"; + QVector< QString > cubesOnIsland = cg.GetCubesOnIsland(0); + for (int i = 0; i < cubesOnIsland.size(); i++) + cerr << " " << cubesOnIsland[i].toStdString(); + + cerr << "\n\nGetCubesOnIsland(1) returns:"; + cubesOnIsland = cg.GetCubesOnIsland(1); + for (int i = 0; i < cubesOnIsland.size(); i++) + cerr << " " << cubesOnIsland[i].toStdString(); + + try + { + cerr << "\n\nGetCubesOnIsland(42) returns:"; + cubesOnIsland = cg.GetCubesOnIsland(42); + } + catch (iException e) + { + e.Report(); + } + + cerr << "\nGetCubeList() returns:\n"; + QVector< QString > cubeList = cg.GetCubeList(); + for (int i = 0; i < cubeList.size(); i++) + { + cerr << " " << cubeList[i].toStdString() << "\n"; + } + + cerr << "\n"; + + return 0; +} diff --git a/isis/src/base/objs/ControlMeasure/ControlMeasure.cpp b/isis/src/base/objs/ControlMeasure/ControlMeasure.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90d46e898e1e7b618a3d7ee87258248594e6e973 --- /dev/null +++ b/isis/src/base/objs/ControlMeasure/ControlMeasure.cpp @@ -0,0 +1,270 @@ +/** + * @file + * $Revision: 1.8 $ + * $Date: 2010/06/10 23:56:44 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "ControlMeasure.h" +#include "SpecialPixel.h" +#include "Camera.h" +#include "Application.h" +#include "iTime.h" + + +namespace Isis { + //! Create a control point measurement + ControlMeasure::ControlMeasure() { + SetType(Unmeasured); + SetCoordinate(0.0, 0.0); + SetDiameter(Isis::Null); + SetCubeSerialNumber(""); + SetDateTime(""); + SetChooserName(""); + SetIgnore(false); + SetError(0.0, 0.0); + SetGoodnessOfFit(Isis::Null); + SetZScores(Isis::Null, Isis::Null); + SetReference(false); + SetCamera(0); + } + + /** + * Loads a PvlGroup into the ControlMeasure + * + * @param p PvlGroup containing ControlMeasure information + * + * @throws Isis::iException::User - Invalid Measure Type + */ + void ControlMeasure::Load(PvlGroup &p) { + SetCubeSerialNumber((std::string)p["SerialNumber"]); + std::string type = p["MeasureType"]; + MeasureType mType; + if(type == "Unmeasured") mType = Unmeasured; + else if(type == "Manual") mType = Manual; + else if(type == "Estimated") mType = Estimated; + else if(type == "Automatic") mType = Automatic; + else if(type == "ValidatedManual") mType = ValidatedManual; + else if(type == "ValidatedAutomatic") mType = ValidatedAutomatic; + else { + std::string msg = "Invalid Measure Type, [" + type + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + SetType(mType); + if(mType != Unmeasured) { + SetCoordinate(p["Sample"], p["Line"]); + SetError(p["ErrorSample"], p["ErrorLine"]); + ErrorMagnitude(); + } + if(p.HasKeyword("Diameter")) p_diameter = p["Diameter"]; + if(p.HasKeyword("DateTime")) p_dateTime = (std::string)p["DateTime"]; + if(p.HasKeyword("ChooserName")) p_chooserName = (std::string)p["ChooserName"]; + if(p.HasKeyword("Ignore")) p_ignore = true; + if(p.HasKeyword("GoodnessOfFit")) p_goodnessOfFit = p["GoodnessOfFit"]; + if(p.HasKeyword("Reference")) p_isReference = ((std::string)p["Reference"] == "True"); + + if(p.HasKeyword("ZScore")) SetZScores(p["ZScore"][0], p["ZScore"][1]); + } + + /** + * Sets up and returns a PvlGroup for the ControlMeasure + * + * @return The PvlGroup for the ControlMeasure + * + * @throws Isis::iException::Programmer - Invalid Measure Enumeration + */ + PvlGroup ControlMeasure::CreatePvlGroup() { + PvlGroup p("ControlMeasure"); + p += PvlKeyword("SerialNumber", p_serialNumber); + + if(p_measureType == Unmeasured) { + p += PvlKeyword("MeasureType", "Unmeasured"); + } + else if(p_measureType == Manual) { + p += PvlKeyword("MeasureType", "Manual"); + } + else if(p_measureType == Estimated) { + p += PvlKeyword("MeasureType", "Estimated"); + } + else if(p_measureType == Automatic) { + p += PvlKeyword("MeasureType", "Automatic"); + } + else if(p_measureType == ValidatedManual) { + p += PvlKeyword("MeasureType", "ValidatedManual"); + } + else if(p_measureType == ValidatedAutomatic) { + p += PvlKeyword("MeasureType", "ValidatedAutomatic"); + } + else { + std::string msg = "Invalid Measure Enumeration, [" + iString(p_measureType) + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + if(p_measureType == Unmeasured) { + p += PvlKeyword("Sample", "Null"); + p += PvlKeyword("Line", "Null"); + } + else { + p += PvlKeyword("Sample", p_sample); + p += PvlKeyword("Line", p_line); + p += PvlKeyword("ErrorLine", p_lineError); + p += PvlKeyword("ErrorSample", p_sampleError); + p += PvlKeyword("ErrorMagnitude", ErrorMagnitude()); + } + + if(p_zScoreMin != Isis::Null && p_zScoreMax != Isis::Null) { + PvlKeyword zscores("ZScore"); + zscores += p_zScoreMin; + zscores += p_zScoreMax; + p += zscores; + } + + if(p_diameter != Isis::Null) p += PvlKeyword("Diameter", p_diameter); + if(p_dateTime != "") p += PvlKeyword("DateTime", p_dateTime); + if(p_chooserName != "") p += PvlKeyword("ChooserName", p_chooserName); + if(p_ignore == true) p += PvlKeyword("Ignore", "True"); + if(p_goodnessOfFit != Isis::Null) { + p += PvlKeyword("GoodnessOfFit", p_goodnessOfFit); + } + if(IsReference()) p += PvlKeyword("Reference", "True"); + else p += PvlKeyword("Reference", "False"); + + return p; + } + + + //! Return error magnitude + double ControlMeasure::ErrorMagnitude() const { + double dist = (p_lineError * p_lineError) + (p_sampleError * p_sampleError); + return sqrt(dist); + } + + + //! Set date/time the coordinate was last changed to the current date/time + void ControlMeasure::SetDateTime() { + p_dateTime = iTime::CurrentLocalTime(); + }; + + + //! Set chooser name to a user who last changed the coordinate + void ControlMeasure::SetChooserName() { + p_chooserName = Application::UserName(); + }; + + + //! Set the focal plane x/y for the measured line/sample + void ControlMeasure::SetFocalPlaneMeasured(double x, double y) { + p_focalPlaneMeasuredX = x; + p_focalPlaneMeasuredY = y; + } + + + //! Set the focal plane x/y for the computed (apriori) lat/lon + void ControlMeasure::SetFocalPlaneComputed(double x, double y) { + p_focalPlaneComputedX = x; + p_focalPlaneComputedY = y; + } + + + //! One Getter to rule them all + const double ControlMeasure::GetMeasureData(QString data) const { + if(data == "ZScoreMin") + return p_zScoreMin; + else if(data == "ZScoreMax") + return p_zScoreMax; + else if(data == "SampleError") + return p_sampleError; + else if(data == "LineError") + return p_lineError; + else if(data == "ErrorMagnitude") + return ErrorMagnitude(); + else if(data == "Type") + return p_measureType; + else if(data == "IsMeasured") + return IsMeasured(); + else if(data == "IsValidated") + return IsValidated(); + else if(data == "Ignore") + return p_ignore; + else if(data == "GoodnessOfFit") + return p_goodnessOfFit; + else { + std::string msg = data.toStdString(); + msg += " passed to GetMeasureData but is invalid"; + throw Isis::iException::Message(Isis::iException::Programmer, msg, + _FILEINFO_); + } + } + + + //! Returns a list of all valid options to pass to GetMeasureData + const QVector< QString > ControlMeasure::GetMeasureDataNames() { + QVector< QString > names; + + names.push_back("ZScoreMin"); + names.push_back("ZScoreMax"); + names.push_back("SampleError"); + names.push_back("LineError"); + names.push_back("ErrorMagnitude"); + names.push_back("Type"); + names.push_back("IsMeasured"); + names.push_back("IsValidated"); + names.push_back("Ignore"); + names.push_back("GoodnessOfFit"); + + return names; + } + + /** + * Compare 2 Control Measures for inequality + * + * @author sprasad (4/20/2010) + * + * @param pMeasure + * + * @return bool + */ + bool ControlMeasure::operator != (const Isis::ControlMeasure &pMeasure) const { + return !(*this == pMeasure); + } + /** + * Check for Control Measures equality + * + * @author sprasad (4/20/2010) + * + * @param pMeasure - Control Measure to be compared against + * + * @return bool + */ + bool ControlMeasure::operator == (const Isis::ControlMeasure &pMeasure) const { + if(pMeasure.p_measureType != p_measureType || pMeasure.p_serialNumber != p_serialNumber || + pMeasure.p_line != p_line || pMeasure.p_sample != p_sample || pMeasure.p_diameter != p_diameter || + pMeasure.p_ignore != p_ignore || pMeasure.p_isReference != p_isReference || + pMeasure.p_sampleError != p_sampleError || pMeasure.p_lineError != p_lineError || pMeasure.p_zScoreMin != p_zScoreMin || + pMeasure.p_zScoreMax != p_zScoreMax || pMeasure.p_goodnessOfFit != p_goodnessOfFit || pMeasure.p_focalPlaneMeasuredX != p_focalPlaneMeasuredX || + pMeasure.p_focalPlaneMeasuredY != p_focalPlaneMeasuredY || pMeasure.p_focalPlaneComputedX != p_focalPlaneComputedX || + pMeasure.p_focalPlaneComputedY != p_focalPlaneComputedY || pMeasure.p_measuredEphemerisTime != p_measuredEphemerisTime || + pMeasure.p_computedEphemerisTime != p_computedEphemerisTime) { + + return false; + } + + return true; + } + +} diff --git a/isis/src/base/objs/ControlMeasure/ControlMeasure.h b/isis/src/base/objs/ControlMeasure/ControlMeasure.h new file mode 100644 index 0000000000000000000000000000000000000000..88b4a7b5aa92fac7892a9321d099ff3c375cca10 --- /dev/null +++ b/isis/src/base/objs/ControlMeasure/ControlMeasure.h @@ -0,0 +1,387 @@ +#ifndef ControlMeasure_h +#define ControlMeasure_h +/** + * @file + * $Revision: 1.11 $ + * $Date: 2010/06/10 23:56:44 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +template< class A> class QVector; +class QString; + +namespace Isis { + + class PvlGroup; + class Camera; + + /** + * @brief a control measurement + * + * This class is used to record a coordinate (measurement) on a cube + * for a control point. + * + * @ingroup ControlNetwork + * + * @author 2005-07-29 Jeff Anderson + * + * @see ControlPoint ControlNet + * + * @internal + * @history 2005-07-29 Jeff Anderson - Original version + * @history 2006-01-11 Jacob Danton Added a Reference flag and updated unitTest + * @history 2006-10-05 Brendan George Modified call to retrieve current time to + * use iTime class, instead of Application class + * @history 2008-06-23 Steven Lambright - The ZScore keyword is now supported + * @history 2008-06-25 Steven Koechle - Added get methods for ZScore values. + * @history 2009-09-01 Eric Hyer - Added the methods GetMeasureData and + * GetMeasureDataNames. Also fixed include + * issues. + * @history 2009-09-22 Eric Hyer - Removed forward declaration for QPair + * @history 2009-10-30 Eric Hyer - GetMeasurDataNames is now static + */ + class ControlMeasure { + public: + /** + * @brief Control network measurement types + * + * Unmeasured implies the coordinate (sample, line) has not been + * identified and therefore should not be used. An error will be + * thrown if the programmer attempts to acquire a coordinate for + * an unmeasured measurement + * + * Manual implies the coordinate was selected by a human + * but still may be in error. It is subject to refinement by other + * computer programs. + * + * Estimated implies the coordinate was selected by a computer program + * but has not been sub-pixel registered and is more than likely in + * error. It is subject to refinement by other computer programs + * + * Automatic implies the coordinate was selected by a computer program + * and met registration criteria (but still may be in error). It is + * subject to refinement by other computer programs + * + * ValidatedManual implies the coordinate was manually selected by a + * human, was validated by a human, and should not be changed by + * any automated means. + * + * ValidatedAutomatic implies the coordinate was automatically selected + * by a computer program, was validated by a human, and should not + * be changed by any automated means. + * + */ + enum MeasureType { Unmeasured, Manual, Estimated, Automatic, + ValidatedManual, ValidatedAutomatic + }; + + // Constructor + ControlMeasure(); + + //! Destroy a control point measurement + ~ControlMeasure() {}; + + void Load(PvlGroup &p); + PvlGroup CreatePvlGroup(); + + /** + * @brief Set the coordinate of the measurement + * + * @param sample Sample coordinate of the measurement + * @param line Line coordinate of the measurement + */ + void SetCoordinate(const double &sample, const double &line) { + p_sample = sample; + p_line = line; + }; + + /** + * @brief Set the coordinate of the measurement + * + * @param sample Sample coordinate of the measurement + * @param line Line coordinate of the measurement + * @param type The type of the coordinate + */ + void SetCoordinate(const double &sample, const double &line, + const MeasureType &type) { + p_sample = sample; + p_line = line; + SetType(type); + }; + + //! Return the sample coordinate of the measurement + double Sample() const { + return p_sample; + }; + + //! Return the line coordinate of the measurement + double Line() const { + return p_line; + }; + + /** + * @brief Set the error of the coordinate + * + * @param serror Sample error + * @param lerror Line error + */ + void SetError(const double &serror, const double &lerror) { + p_sampleError = serror; + p_lineError = lerror; + }; + + /** + * @brief Sets the Z Scores of the coordinate + * + * @param zScoreMin Z Score of Minimum DN + * @param zScoreMin Z Score of Maximum DN + */ + void SetZScores(const double &zScoreMin, const double &zScoreMax) { + p_zScoreMin = zScoreMin; + p_zScoreMax = zScoreMax; + } + + /** + * @brief Returns the minimum zScore + * @return the minimum zScore + */ + double GetZScoreMin() const { + return p_zScoreMin; + }; + + /** + * @brief Returns the maximum zScore + * @return the maximum zScore + */ + double GetZScoreMax() const { + return p_zScoreMax; + }; + + //! Return error the sample coordinate of the measurement + double SampleError() const { + return p_sampleError; + }; + + //! Return error the line coordinate of the measurement + double LineError() const { + return p_lineError; + }; + + double ErrorMagnitude() const; + + //! Set how the coordinate was obtained + void SetType(const MeasureType &type) { + p_measureType = type; + }; + + //! Return the type of the measurment + MeasureType Type() const { + return p_measureType; + }; + + //! Has the measurement be measured?? + bool IsMeasured() const { + return p_measureType != Unmeasured; + }; + + //! Has the measurement be validated by a human? + bool IsValidated() const { + return (p_measureType == ValidatedManual) || + (p_measureType == ValidatedAutomatic); + }; + + //! Set if a reference measurement + void SetReference(bool value) { + p_isReference = value; + }; + + //! Is the measurement a reference? + bool IsReference() const { + return (p_isReference && IsMeasured()); + }; + + /** + * @brief Set cube serial number + * + * This method is used to set the serial number of the cube. That is, + * the coordinate was selected from a cube with this unique serial + * number + * + * @param sn Serial number of the cube where the coordinate was + * selected + */ + void SetCubeSerialNumber(const std::string &sn) { + p_serialNumber = sn; + }; + + //! Return the serial number of the cube containing the coordinate + std::string CubeSerialNumber() const { + return p_serialNumber; + }; + + /** + * @brief Set the crater diameter at the coordinate + * + * This method sets the crater diameter at the coordinate. If + * left unset a diameter of 0 is assumed which implies no crater + * + * @param diameter The diameter of the crater in pixels + */ + void SetDiameter(double diameter) { + p_diameter = diameter; + }; + + //! Return the diameter of the crater in pixels (0 implies no crater) + double Diameter() const { + return p_diameter; + }; + + void SetDateTime(); + + //! Set date/time the coordinate was last changed to specified date/time + void SetDateTime(const std::string &datetime) { + p_dateTime = datetime; + }; + + //! Return the date/time the coordinate was last changed + std::string DateTime() const { + return p_dateTime; + }; + + void SetChooserName(); + + //! Set the chooser name to an application that last changed the coordinate + void SetChooserName(const std::string &name) { + p_chooserName = name; + }; + + //! Return the chooser name + std::string ChooserName() const { + return p_chooserName; + }; + + //! Set up to ignore this measurement + void SetIgnore(bool ignore) { + p_ignore = ignore; + }; + + //! Return if this measurement should be ignored + bool Ignore() const { + return p_ignore; + }; + + //! Set the Goodness of Fit variable + void SetGoodnessOfFit(const double fit) { + p_goodnessOfFit = fit; + }; + + //! Return the Goodnes of Fit + double GoodnessOfFit() const { + return p_goodnessOfFit; + }; + + //! Set the camera for this measure + void SetCamera(Isis::Camera *camera) { + p_camera = camera; + }; + + //! Return the camera associated with this measure + Isis::Camera *Camera() const { + return p_camera; + }; + + void SetFocalPlaneMeasured(double x, double y); + + //! Return the measured focal plane x + double FocalPlaneMeasuredX() const { + return p_focalPlaneMeasuredX; + }; + + //! Return the measured focal plane y + double FocalPlaneMeasuredY() const { + return p_focalPlaneMeasuredY; + }; + + void SetFocalPlaneComputed(double x, double y); + + //! Return the computed focal plane x + double FocalPlaneComputedX() const { + return p_focalPlaneComputedX; + }; + + //! Return the computed focal plane y + double FocalPlaneComputedY() const { + return p_focalPlaneComputedY; + }; + + //! Set the measured ephemeris time of the measure + void SetMeasuredEphemerisTime(double et) { + p_measuredEphemerisTime = et; + }; + + //! Get the measured ephemeris time of the measure + double MeasuredEphemerisTime() const { + return p_measuredEphemerisTime; + }; + + //! Set the computed ephemeris time of the measure + void SetComputedEphemerisTime(double et) { + p_computedEphemerisTime = et; + }; + + //! Get the computed ephemeris time of the measure + double ComputedEphemerisTime() const { + return p_computedEphemerisTime; + }; + + const double GetMeasureData(QString type) const; + static const QVector< QString > GetMeasureDataNames(); + + bool operator == (const Isis::ControlMeasure &pMeasure) const; + bool operator != (const Isis::ControlMeasure &pMeasure) const; + + private: + MeasureType p_measureType; + std::string p_serialNumber; + double p_line; + double p_sample; + double p_diameter; + std::string p_dateTime; + std::string p_chooserName; + bool p_ignore; + bool p_isReference; + double p_sampleError; + double p_lineError; + double p_zScoreMin; + double p_zScoreMax; + double p_goodnessOfFit; + Isis::Camera *p_camera; + double p_focalPlaneMeasuredX; + double p_focalPlaneMeasuredY; + double p_focalPlaneComputedX; + double p_focalPlaneComputedY; + + double p_measuredEphemerisTime; + double p_computedEphemerisTime; + }; +}; + +#endif diff --git a/isis/src/base/objs/ControlMeasure/ControlMeasure.truth b/isis/src/base/objs/ControlMeasure/ControlMeasure.truth new file mode 100644 index 0000000000000000000000000000000000000000..0927a84b7a08a1954d3d8e89ff0d03eedbe4695c --- /dev/null +++ b/isis/src/base/objs/ControlMeasure/ControlMeasure.truth @@ -0,0 +1,112 @@ +Test 1 +Group = ControlMeasure + SerialNumber = Null + MeasureType = Unmeasured + Sample = Null + Line = Null + Reference = False +End_Group +End +Test 2 +Group = ControlMeasure + SerialNumber = Test + MeasureType = Manual + Sample = 1.0 + Line = 2.0 + ErrorLine = 4.0 + ErrorSample = -3.0 + ErrorMagnitude = 5.0 + Diameter = 15.0 + DateTime = 2005-05-03T00:00:00 + ChooserName = Bob + Ignore = True + GoodnessOfFit = 0.5 + Reference = True +End_Group +End +Test 3 +Group = ControlMeasure + SerialNumber = Test + MeasureType = Estimated + Sample = 1.0 + Line = 2.0 + ErrorLine = 4.0 + ErrorSample = -3.0 + ErrorMagnitude = 5.0 + Diameter = 15.0 + DateTime = 2005-05-03T00:00:00 + ChooserName = Bob + Ignore = True + GoodnessOfFit = 0.5 + Reference = False +End_Group +End +Test 4 +Group = ControlMeasure + SerialNumber = Test + MeasureType = Automatic + Sample = 1.0 + Line = 2.0 + ErrorLine = 4.0 + ErrorSample = -3.0 + ErrorMagnitude = 5.0 + Diameter = 15.0 + DateTime = 2005-05-03T00:00:00 + ChooserName = Bob + Ignore = True + GoodnessOfFit = 0.5 + Reference = False +End_Group +End +Test 5 +Group = ControlMeasure + SerialNumber = Test + MeasureType = ValidatedManual + Sample = 1.0 + Line = 2.0 + ErrorLine = 4.0 + ErrorSample = -3.0 + ErrorMagnitude = 5.0 + Diameter = 15.0 + DateTime = 2005-05-03T00:00:00 + ChooserName = Bob + Ignore = True + GoodnessOfFit = 0.5 + Reference = False +End_Group +End +Test 6 +Group = ControlMeasure + SerialNumber = Test + MeasureType = ValidatedAutomatic + Sample = 1.0 + Line = 2.0 + ErrorLine = 4.0 + ErrorSample = -3.0 + ErrorMagnitude = 5.0 + Diameter = 15.0 + DateTime = 2005-05-03T00:00:00 + ChooserName = Bob + Ignore = True + GoodnessOfFit = 0.5 + Reference = False +End_Group +End +Test 7 +Group = ControlMeasure + SerialNumber = Test + MeasureType = ValidatedAutomatic + Sample = 1.0 + Line = 2.0 + ErrorLine = 4.0 + ErrorSample = -3.0 + ErrorMagnitude = 5.0 + ZScore = (-1.1, 1.0) + Diameter = 15.0 + DateTime = 2005-05-03T00:00:00 + ChooserName = Bob + Ignore = True + GoodnessOfFit = 0.5 + Reference = False +End_Group +End diff --git a/isis/src/base/objs/ControlMeasure/Makefile b/isis/src/base/objs/ControlMeasure/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..123df99744cc971a4bb044d2ee03bf14ede00b7f --- /dev/null +++ b/isis/src/base/objs/ControlMeasure/Makefile @@ -0,0 +1,5 @@ +INCS = ControlMeasure.h +SRCS = ControlMeasure.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ControlMeasure/unitTest.cpp b/isis/src/base/objs/ControlMeasure/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d6a1a4b4cf62f3d0051c1bb8554ad94208ad1df --- /dev/null +++ b/isis/src/base/objs/ControlMeasure/unitTest.cpp @@ -0,0 +1,54 @@ +#include "ControlMeasure.h" +#include "Preference.h" + +#include +using namespace std; +void outit (Isis::ControlMeasure &d); + +int main () { + Isis::Preference::Preferences(true); + Isis::ControlMeasure d; + cout << "Test 1" << endl; + outit(d); + + d.SetCoordinate(1.0,2.0); + d.SetCubeSerialNumber("Test"); + d.SetDiameter(15.0); + d.SetIgnore(true); + d.SetType(Isis::ControlMeasure::Manual); + d.SetChooserName("Bob"); + d.SetDateTime("2005-05-03T00:00:00"); + d.SetError(-3.0,4.0); + d.SetGoodnessOfFit(0.5); + d.SetReference(true); + cout << "Test 2" << endl; + outit(d); + + d.SetType(Isis::ControlMeasure::Estimated); + d.SetReference(false); + cout << "Test 3" << endl; + outit(d); + + d.SetType(Isis::ControlMeasure::Automatic); + cout << "Test 4" << endl; + outit(d); + + d.SetType(Isis::ControlMeasure::ValidatedManual); + cout << "Test 5" << endl; + outit(d); + + d.SetType(Isis::ControlMeasure::ValidatedAutomatic); + cout << "Test 6" << endl; + outit(d); + + d.SetZScores(-1.1, 1.0); + cout << "Test 7" << endl; + outit(d); + +} + +void outit (Isis::ControlMeasure &d) { + Isis::Pvl pvl; + pvl.AddGroup(d.CreatePvlGroup()); + cout << pvl << endl; +} diff --git a/isis/src/base/objs/ControlNet/ControlNet.cpp b/isis/src/base/objs/ControlNet/ControlNet.cpp new file mode 100644 index 0000000000000000000000000000000000000000..986c109c6b622e92a718736c8ff7cb1d75578490 --- /dev/null +++ b/isis/src/base/objs/ControlNet/ControlNet.cpp @@ -0,0 +1,499 @@ +#include "ControlNet.h" +#include "SpecialPixel.h" +#include "iException.h" +#include "CameraFactory.h" +#include "iTime.h" + +namespace Isis { + //!Creates an empty ControlNet object + ControlNet::ControlNet () { + p_invalid = false; + } + + + /** + * Creates a ControlNet object with the given list of control points and cubes + * + * @param ptfile Name of file containing a Pvl list of control points + * @param progress A pointer to the progress of reading in the control points + * @param forceBuild Forces invalid Control Points to be added to this Control + * Network + */ + ControlNet::ControlNet(const std::string &ptfile, Progress *progress, bool forceBuild) { + p_invalid = false; + ReadControl(ptfile, progress, forceBuild); + } + + + /** + * Adds a ControlPoint to the ControlNet + * + * @param point Control point to be added + * @param forceBuild Forces invalid Control Points to be added to this Control + * Network + * + * @throws Isis::iException::Programmer - "ControlPoint must + * have unique Id" + */ + void ControlNet::Add (const ControlPoint &point, bool forceBuild) { + if(p_pointsHash.contains(QString::fromStdString(point.Id()))) { + std::string msg = "ControlPoint must have unique Id"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } else { + p_pointsHash.insert(QString::fromStdString(point.Id()), point); + p_pointIds.push_back(QString::fromStdString(point.Id())); + } + } + + + /** + * Deletes the ControlPoint at the specified index in the ControlNet + * + * @param index The index of the ControlPoint to be deleted + * + * @throws Isis::iException::User - "There is no ControlPoint at + * the given index number" + */ + void ControlNet::Delete (int index) { + if (index >= (int)p_pointsHash.size() || index < 0) { + std::string msg = "There is no ControlPoint at the given index number"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + else { + // See if removing this point qualifies for a re-check of validity + bool check = false; + if( p_invalid && p_pointsHash[p_pointIds[index]].Invalid()) check = true; + + p_pointsHash.remove(p_pointIds[index]); + p_pointIds.remove(index); + + // Check validity if needed + if( check ) { + p_invalid = false; + for (int i=0; iSetText("Loading Control Points..."); + progress->SetMaximumSteps(cn.Objects()); + progress->CheckStatus(); + } + for (int i=0; iCheckStatus(); + } + } + catch (iException &e) { + std::string msg = "Invalid Format in [" + ptfile + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + + /** + * Writes out the ControlPoints + * + * @param ptfile Name of file containing a Pvl list of control points + * @throws Isis::iException::Programmer - "Invalid Net + * Enumeration" + * @throws Isis::iException::Io - "Unable to write PVL + * infomation to file" + */ + void ControlNet::Write(const std::string &ptfile) { + Pvl p; + PvlObject net("ControlNetwork"); + net += PvlKeyword("NetworkId", p_networkId); + if (p_type == Singleton) { + net += PvlKeyword("NetworkType", "Singleton"); + } + else if (p_type == ImageToImage) { + net += PvlKeyword("NetworkType", "ImageToImage"); + } + else if (p_type == ImageToGround) { + net += PvlKeyword("NetworkType", "ImageToGround"); + } + else { + std::string msg = "Invalid Net Enumeration, [" + iString(p_type) + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + net += PvlKeyword("TargetName", p_targetName); + net += PvlKeyword("UserName", p_userName); + std::string mod = iString(p_modified).UpCase(); + if( mod == "NULL" || mod == "" ) { + SetModifiedDate( Isis::iTime::CurrentLocalTime() ); + } + std::string cre = iString(p_created).UpCase(); + if( cre == "NULL" || cre == "" ) { + SetCreatedDate( p_modified ); + } + net += PvlKeyword("Created", p_created); + net += PvlKeyword("LastModified", p_modified); + net += PvlKeyword("Description", p_description); + + for (int i=0; i<(int)p_pointsHash.size(); i++) { + PvlObject cp = p_pointsHash[p_pointIds[i]].CreatePvlObject(); + net.AddObject(cp); + } + p.AddObject(net); + + try { + p.Write(ptfile); + } + catch (iException e) { + std::string message = "Unable to write PVL infomation to file [" + + ptfile + "]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + + /** + * Finds and returns a pointer to the ControlPoint with the specified id + * + * @param id The id of the ControlPoint to be deleted + * + * @return ControlPoint* Pointer to the ControlPoint with + * the given id + * + * @throws Isis::iException::User - "A ControlPoint matching the + * id was not found in the + * ControlNet" + */ + ControlPoint *ControlNet::Find(const std::string &id) { + if(!p_pointIds.contains(QString::fromStdString(id))) { + std::string msg = "A ControlPoint matching the id [" + id + + "] was not found in the ControlNet"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + return &p_pointsHash.find(QString::fromStdString(id)).value(); + } + + + /** + * Returns true if the given ControlPoint has the same id as + * another ControlPoint in class + * + * @param point The ControlPoint whos id is being compared + * + * @return bool If the ControlPoint id was found + */ + bool ControlNet::Exists( ControlPoint &point ) { + if(p_pointsHash.contains(QString::fromStdString(point.Id()))) { + return true; + } + return false; + } + + + /** + * Finds and returns a pointer to the closest ControlPoint to the + * ControlMeasure with the given serial number and line sample location + * + * @param serialNumber The serial number of the the file the ControlMeasure is + * on + * @param sample The sample number of the ControlMeasure + * @param line The line number of the ControlMeasure + * + * @return ControlPoint* Pointer to the ControlPoint + * closest to the given line, sample position + */ + ControlPoint *ControlNet::FindClosest(const std::string &serialNumber, + double sample, double line) { + + ControlPoint *savePoint=NULL; + double dist; + double minDist=99999.; + for (int i=0; i < (int)p_pointsHash.size(); i++) { + for (int j=0; j < p_pointsHash[p_pointIds[i]].Size(); j++) { + if (p_pointsHash[p_pointIds[i]][j].CubeSerialNumber() != serialNumber) continue; + //Find closest line sample & return that controlpoint + dist = fabs(sample - p_pointsHash[p_pointIds[i]][j].Sample()) + + fabs(line - p_pointsHash[p_pointIds[i]][j].Line()); + if (dist < minDist) { + minDist = dist; + savePoint = &p_pointsHash[p_pointIds[i]]; + } + } + } + return savePoint; + } + + + /** + * Compute aprior values for each point in the network + */ + void ControlNet::ComputeApriori() { + // TODO: Make sure the cameras have been initialized + for (int i=0; i<(int)p_pointsHash.size(); i++) { + p_pointsHash[p_pointIds[i]].ComputeApriori(); + } + } + + + /** + * Compute error for each point in the network + */ + void ControlNet::ComputeErrors() { + // TODO: Make sure the cameras have been initialized + for (int i=0; i<(int)p_pointsHash.size(); i++) { + p_pointsHash[p_pointIds[i]].ComputeErrors(); + } + } + + + /** + * Determine the maximum error of all points in the network + * @return double Max error of points + */ + double ControlNet::MaximumError() { + // TODO: Make sure the cameras have been initialized + double maxError = 0.0; + for (int i=0; i<(int)p_pointsHash.size(); i++) { + double error = p_pointsHash[p_pointIds[i]].MaximumError(); + if (error > maxError) maxError = error; + } + return maxError; + } + + + /** + * Compute the average error of all points in the network + * @return double Average error of points + */ + double ControlNet::AverageError() { + // TODO: Make sure the cameras have been initialized + double avgError = 0.0; + int count = 0; + for (int i=0; i<(int)p_pointsHash.size(); i++) { + if (p_pointsHash[p_pointIds[i]].Ignore()) continue; + avgError += p_pointsHash[p_pointIds[i]].AverageError(); + count++; + } + if (count == 0) return avgError; + return avgError / count; + } + + + /** + * Creates the ControlNet's image cameras based on an input file + * + * @param imageListFile The list of images + */ + void ControlNet::SetImages (const std::string &imageListFile) { + SerialNumberList list(imageListFile); + SetImages(list); + } + + + /** + * Creates the ControlNet's image camera's based on the list of Serial Numbers + * + * @param list The list of Serial Numbers + * @param progress A pointer to the progress of creating the cameras + * @throws Isis::iException::System - "Unable to create camera + * for cube file" + * @throws Isis::iException::User - "Control point measure does + * not have a cube with a matching serial number" + * @internal + * @history 2009-01-06 Jeannie Walldren - Fixed typo in + * exception output. + */ + void ControlNet::SetImages (SerialNumberList &list, Progress *progress) { + // Prep for reporting progress + if (progress != NULL) { + progress->SetText("Setting input images..."); + progress->SetMaximumSteps(list.Size()); + progress->CheckStatus(); + } + // Open the camera for all the images in the serial number list + for (int i=0; iCheckStatus(); + } + + // Loop through all measures and set the camera + for (int p=0; p +#include +#include + +namespace Isis { + /** + * @brief a control network + * + * This class is used to store a network of ControlPoints + * + * @ingroup ControlNetwork + * + * @author 2005-07-29 Jeff Anderson + * + * @see ControlPoint ControlMeasure + * + * @internal + * @history 2005-07-29 Jeff Anderson Original version + * @history 2006-01-11 Jacob Danton Updated unitTest + * @history 2006-06-22 Brendan George Updated to conform to changes in + * SerialNumberList class + * @history 2008-04-04 Christopher Austin Added Exists function + * @history 2008-04-18 Debbie A. Cook Added Progress reports to loading and SetImages + * and calculates the total number of measurements in the control net + * @history 2008-06-18 Christopher Austin Fixed documentation errors + * @history 2009-01-06 Jeannie Walldren - Fixed typo in + * SetImages() exception output. Added + * documentation. + * @history 2009-02-05 Christopher Austin - when the created date or the + * modified date are not set, they default to the time in which + * Write() is called. + * @history 2009-04-07 Tracie Sucharski - Added NumValidMeasures and + * NumIgnoredMeasures methods. + * @history 2009-06-03 Christopher Austin - Added p_invalid functionality + * along with forceBuild, as well as other small fixes including + * documentation. + * @history 2009-07-13 Stacy Alley - The std::vector of + * ControlPoints called 'p_points' was replaced with + * a QVector of QString 'p_pointIds' in conjunction + * with a QHash of called + * 'p_pointsHash'. This was done to speed up the Add + * method which was essentially slowing down the + * reading or creation of Control Networks. + * @history 2009-09-01 Eric Hyer - Added two includes: QVector and QString + * @history 2009-09-25 Travis Addair - Changed methods + * which return the number of control measures in the + * network to compute those values at the time the + * method is called, not when the control network is + * first initialized + * + */ + class ControlNet { + public: + // Constuctors + ControlNet (); + ControlNet(const std::string &ptfile, Progress *progress=0, bool forceBuild=false ); + + //! Destroy the control network + ~ControlNet () {}; + + /** + * Enumeration defining network type + */ + enum NetworkType { Singleton, //! p_pointIds; //!< QVector of ControlPoint Ids + QHash p_pointsHash; //!< Hash table of Control Points. + std::string p_targetName; //!< Name of the target + std::string p_networkId; //!< The Network Id + std::string p_created; //!< Creation Date + std::string p_modified; //!< Date Last Modified + std::string p_description; //!< Textual Description of network + std::string p_userName; //!< The user who created the network + NetworkType p_type; //!< The type of network being used + int p_numIgnoredMeasures; //!< Number of ignored measures + std::map p_cameraMap; //!< A map from serialnumber to camera + std::vector p_cameraList; //!< Vector of image number to camera + + bool p_invalid; //!< If the Control Network is currently invalid + + }; +}; + +#endif + diff --git a/isis/src/base/objs/ControlNet/ControlNet.truth b/isis/src/base/objs/ControlNet/ControlNet.truth new file mode 100644 index 0000000000000000000000000000000000000000..7bc025a57bfe7affbdec2d141d8534610c6354b1 --- /dev/null +++ b/isis/src/base/objs/ControlNet/ControlNet.truth @@ -0,0 +1,114 @@ +UnitTest for ControlNet .... + +Test adding control points with identical id numbers ... +**PROGRAMMER ERROR** ControlPoint must have unique Id + +Test adding invalid control point ... +**PROGRAMMER ERROR** Invalid Point Enumeration, [999] for ControlPoint [T0002]. + +Test deleting nonexistant control point id ... +**USER ERROR** A ControlPoint matching the id [T0002] was not found in the ControlNet + +Test deleting nonexistant control point index ... +**USER ERROR** There is no ControlPoint at the given index number + +Object = ControlNetwork + NetworkId = Test + NetworkType = ImageToGround + TargetName = Mars + UserName = jdoe + Created = 2009-02-05T14:20:15 + LastModified = 2009-02-05T14:20:55 + Description = "UnitTest of ControlNetwork" + + Object = ControlPoint + PointType = Tie + PointId = T0001 + Ignore = True + + Group = ControlMeasure + SerialNumber = Id1 + MeasureType = Unmeasured + Sample = Null + Line = Null + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = G0001 + Latitude = 30.5 + Longitude = 175.0 + Radius = 3950.2 + Held = True + + Group = ControlMeasure + SerialNumber = Id1 + MeasureType = Manual + Sample = 15.5 + Line = 23.2 + ErrorLine = 1.0 + ErrorSample = 1.0 + ErrorMagnitude = 1.4142135623731 + Diameter = 7900.4 + DateTime = 2004-12-20T10:12:05 + ChooserName = janeDoe + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Id2 + MeasureType = Automatic + Sample = 13.5 + Line = 168.3 + ErrorLine = 0.5 + ErrorSample = 0.5 + ErrorMagnitude = 0.70710678118655 + Reference = False + End_Group + End_Object + + Object = ControlPoint + PointType = Ground + PointId = G0002 + Latitude = 63.5 + Longitude = 168.2 + Radius = 3950.2 + + Group = ControlMeasure + SerialNumber = Id1 + MeasureType = ValidatedManual + Sample = 45.2 + Line = 135.4 + ErrorLine = 0.25 + ErrorSample = 0.25 + ErrorMagnitude = 0.35355339059327 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Id2 + MeasureType = ValidatedAutomatic + Sample = 53.8 + Line = 110.5 + ErrorLine = 0.1 + ErrorSample = 0.1 + ErrorMagnitude = 0.14142135623731 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Id3 + MeasureType = Estimated + Sample = 70.1 + Line = 118.7 + ErrorLine = 0.75 + ErrorSample = 0.75 + ErrorMagnitude = 1.0606601717798 + Ignore = True + Reference = False + End_Group + End_Object +End_Object +End diff --git a/isis/src/base/objs/ControlNet/Makefile b/isis/src/base/objs/ControlNet/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3d628a1771b3079e9462c9e2c0f33474d7992cd1 --- /dev/null +++ b/isis/src/base/objs/ControlNet/Makefile @@ -0,0 +1,5 @@ +INCS = ControlNet.h +SRCS = ControlNet.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ControlNet/unitTest.cpp b/isis/src/base/objs/ControlNet/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f1899f6803b987b8d42e5f62339fc7438330628e --- /dev/null +++ b/isis/src/base/objs/ControlNet/unitTest.cpp @@ -0,0 +1,164 @@ +#include "ControlNet.h" +#include "SpecialPixel.h" +#include "TextFile.h" +#include "iException.h" +#include "Preference.h" + +#include +#include +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + cout << "UnitTest for ControlNet ...." << endl << endl; + Isis::ControlMeasure cm; + cm.SetType(Isis::ControlMeasure::Unmeasured); + cm.SetCubeSerialNumber("Id1"); + + Isis::ControlPoint cp1("T0001"); + cp1.SetType(Isis::ControlPoint::Tie); + cp1.SetIgnore(true); + cp1.Add(cm); + + Isis::ControlMeasure cm1; + cm1.SetCoordinate(15.5, 23.2, Isis::ControlMeasure::Manual); + cm1.SetError(1.0,1.0); + cm1.SetCubeSerialNumber("Id1"); + cm1.SetDiameter(7900.4); + cm1.SetChooserName("janeDoe"); + cm1.SetDateTime("2004-12-20T10:12:05"); + + Isis::ControlMeasure cm2; + cm2.SetCoordinate(13.5, 168.3, Isis::ControlMeasure::Automatic); + cm2.SetError(0.5,0.5); + cm2.SetCubeSerialNumber("Id2"); + + Isis::ControlPoint cp2("G0001"); + cp2.SetType(Isis::ControlPoint::Ground); + cp2.SetUniversalGround(30.5, 175.0, 3950.2); + cp2.SetHeld(true); + cp2.Add(cm1); + cp2.Add(cm2); + + Isis::ControlMeasure cm3; + cm3.SetCoordinate(45.2, 135.4, Isis::ControlMeasure::ValidatedManual); + cm3.SetError(0.25,0.25); + cm3.SetCubeSerialNumber("Id1"); + + Isis::ControlMeasure cm4; + cm4.SetCoordinate(53.8, 110.5, Isis::ControlMeasure::ValidatedAutomatic); + cm4.SetError(0.1,0.1); + cm4.SetCubeSerialNumber("Id2"); + + Isis::ControlMeasure cm5; + cm5.SetCoordinate(70.1, 118.7, Isis::ControlMeasure::Estimated); + cm5.SetError(0.75,0.75); + cm5.SetCubeSerialNumber("Id3"); + cm5.SetIgnore(true); + + Isis::ControlMeasure cm6; + cm6.SetCoordinate(84.1, 168.7, Isis::ControlMeasure::Estimated); + cm6.SetError(0.75,0.75); + cm6.SetCubeSerialNumber("Id3"); + + Isis::ControlPoint cp3("G0002"); + cp3.SetType(Isis::ControlPoint::Ground); + cp3.SetUniversalGround(63.5, 168.2, 3950.2); + cp3.Add(cm3); + cp3.Add(cm4); + cp3.Add(cm5); + + Isis::ControlPoint cp4("G0002"); + cp4.SetType(Isis::ControlPoint::Ground); + cp4.SetUniversalGround(65.1, 102.2, 3950.2); + cp4.Add(cm5); + + Isis::ControlPoint cp5("T0002"); + cp5.SetType((Isis::ControlPoint::PointType)999); + cp5.Add(cm); + + Isis::ControlNet cn1; + cn1.SetType(Isis::ControlNet::ImageToGround); + cn1.SetTarget("Mars"); + cn1.SetNetworkId("Test"); + cn1.SetUserName("jdoe"); + cn1.SetCreatedDate( "2009-02-05T14:20:15" ); + cn1.SetModifiedDate( "2009-02-05T14:20:55" ); + cn1.SetDescription("UnitTest of ControlNetwork"); + cn1.Add(cp1); + cn1.Add(cp2); + cn1.Add(cp3); + cn1.Add(cp5); + + cout << "Test adding control points with identical id numbers ..." << endl; + try { + cn1.Add(cp4); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Test adding invalid control point ..." << endl; + try { + cn1.Write("temp.txt"); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cn1.Delete(cp5.Id()); + + cn1.Write("temp.txt"); + cout << "Test deleting nonexistant control point id ..." << endl; + try { + cn1.Delete(cp5.Id()); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Test deleting nonexistant control point index ..." << endl; + try { + cn1.Delete(7); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + Isis::ControlNet cn2("temp.txt"); + + cn2.Write("temp2.txt"); + + string f1 = "temp.txt"; + string f2 = "temp2.txt"; + + Isis::TextFile t1; + Isis::TextFile t2; + t1.Open(f1); + t2.Open(f2); + + if (t1.LineCount() != t2.LineCount()) { + cout << "ERROR: Text Files are not the same!" << endl; + } + else { + for (int l=0; loperator[](g).CreatePvlGroup()); + } + + return p; + } + + /** + * Add a measurement to the control point + * + * @param measure The ControlMeasure to add + * @param forceBuild Forces the Control Measure to be added reguardless of + * validity + * @internal + * @history 2009-10-13 Jeannie Walldren - Added detail to + * error message. + */ + void ControlPoint::Add(const ControlMeasure &measure, bool forceBuild) { + for (int i=0; ioperator[](i).CubeSerialNumber() == measure.CubeSerialNumber()) { + if( forceBuild ) { + p_invalid |= true; + break; + } + else { + std::string msg = "The SerialNumber is not unique. A measure with serial number ["; + msg += measure.CubeSerialNumber() + "] already exists for ControlPoint [" + Id() + "]."; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + } + p_measures.push_back(measure); + } + + /** + * Remove a measurement from the control point + * + * @param index The index of the control point to delete + */ + void ControlPoint::Delete(int index) { + p_measures.erase(p_measures.begin()+index); + + // Check if the control point is still invalid or not + if(p_invalid) { + p_invalid = false; + for (int i=0; ioperator[](i).CubeSerialNumber() == this->operator[](j).CubeSerialNumber()) { + p_invalid = true; + } + } + } + + } + } + + /** + * Return the measurement for the given serial number + * + * @param serialNumber The serial number + * + * @return The ControlMeasure corresponding to the give serial number + * @internal + * @history 2009-10-13 Jeannie Walldren - Added detail to + * error message. + */ + ControlMeasure &ControlPoint::operator[](const std::string &serialNumber) { + for (int m=0; mSize(); m++) { + if (this->operator[](m).CubeSerialNumber() == serialNumber) { + return this->operator [](m); + } + } + std::string msg = "Requested measurement serial number [" + serialNumber + "] "; + msg += "does not exist in ControlPoint [" + Id() + "]."; + throw iException::Message(iException::User,msg,_FILEINFO_); + + } + + /** + * Return the measurement for the given serial number + * + * @param serialNumber The serial number + * + * @return The ControlMeasure corresponding to the give serial number + * @internal + * @history 2009-10-13 Jeannie Walldren - Added detail to + * error message. + */ + const ControlMeasure &ControlPoint::operator[](const std::string &serialNumber) const{ + for (int m=0; mSize(); m++) { + if (this->operator[](m).CubeSerialNumber() == serialNumber) { + return this->operator [](m); + } + } + std::string msg = "Requested measurement serial number [" + serialNumber + "] "; + msg += "does not exist in ControlPoint [" + Id() + "]."; + throw iException::Message(iException::User,msg,_FILEINFO_); + + } + + /** + * Return true if given serial number exists in point + * + * @param serialNumber The serial number + * @return True if point contains serial number, false if not + */ + bool ControlPoint::HasSerialNumber(std::string &serialNumber) { + for (int m=0; mSize(); m++) { + if (this->operator[](m).CubeSerialNumber() == serialNumber) { + return true; + } + } + return false; + + } + + + /** + * Obtain a string representation of a given PointType + * + * @returns A string representation of type + * + * @throws iException::Programmer When unable to translate type + * @internal + * @history 2009-10-13 Jeannie Walldren - Added detail to + * error message. + * @history 2010-06-04 Eric Hyer - removed parameter + */ + const std::string ControlPoint::PointTypeToString() const { + std::string str = ""; + switch (p_type) { + case Ground: + str = "Ground"; + break; + case Tie: + str = "Tie"; + break; + default: + str = "Unable to translate PointType [" + iString(p_type) + + "] inside PointTypeToString for ControlPoint [" + Id() + "]."; + throw iException::Message(iException::Programmer, str, _FILEINFO_); + } + + return str; + } + + + /** + * Set the ground coordinate of a control point + * + * @param lat planetocentric latitude in degrees + * @param lon planetocentric longitude in degrees + * @param radius radius at coordinate in meters + */ + void ControlPoint::SetUniversalGround (double lat, double lon, double radius) { + p_latitude = lat; + p_longitude = lon; + p_radius = radius; + } + + //! Return the average error of all measurements + double ControlPoint::AverageError() const { + double cerr = 0.0; + int count = 0; + for (int i=0; i<(int)p_measures.size(); i++) { + if (p_measures[i].Ignore()) continue; + if (p_measures[i].Type() == ControlMeasure::Unmeasured) continue; + cerr += p_measures[i].ErrorMagnitude(); + count++; + } + + if (count == 0) return 0.0; + return cerr / (double) count; + } + + + /** + * Return true if there is a Reference measure, otherwise return false + * + * @todo ??? Check for more than one reference measure ??? + * Should print error, this check should also go in + * ReferenceIndex. + */ + bool ControlPoint::HasReference() { + + if (p_measures.size() == 0) { + std::string msg = "There are no ControlMeasures in the ControlPoint [" + Id() + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + // Return true if reference measure is found + for (unsigned int i=0; iSetImage(m.Sample(),m.Line())) { + goodMeasures++; + lat += cam->UniversalLatitude(); + + // Deal with longitude wrapping + double wraplon = WrapLongitude(cam->UniversalLongitude(), baselon); + lon += wraplon; + baselon = wraplon; + rad += cam->LocalRadius(); + double x = cam->DistortionMap()->UndistortedFocalPlaneX(); + double y = cam->DistortionMap()->UndistortedFocalPlaneY(); + m.SetFocalPlaneMeasured(x,y); + m.SetMeasuredEphemerisTime(cam->EphemerisTime()); + } + else { + // JAA: Don't stop if we know the lat/lon. The SetImage may fail + // but the FocalPlane measures have been set + if (Type() == ControlPoint::Ground || Held()) continue; + + // TODO: What do we do + std::string msg = "Cannot compute lat/lon for ControlPoint [" + + Id() + "], measure [" + m.CubeSerialNumber() + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + + // m.SetFocalPlaneMeasured(?,?); + } + } + } + + // Don't update the lat/lon for held or ground points + if (Held()) return; + if (Type() == ControlPoint::Ground) return; + + // Did we have any measures? + if (goodMeasures == 0) { + std::string msg = "ControlPoint [" + Id() + "] has no measures which "; + msg += "project to latitude/longitude"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Compute the averages + lat = lat / goodMeasures; + lon = lon / goodMeasures; + if (lon < 0) lon += 360.; + rad = rad / goodMeasures; + + SetUniversalGround(lat,lon,rad); + } + + + /** + * This method computes the errors for a point. + * + * @history 2008-07-17 Tracie Sucharski, Added ptid and measure serial + * number to the unable to map to surface error. + */ + + void ControlPoint::ComputeErrors() { + if (Ignore()) return; + + double lat = UniversalLatitude(); + double lon = UniversalLongitude(); + double rad = Radius(); + + // Loop for each measure to compute the error + for (int j=0; j<(int)p_measures.size(); j++) { + ControlMeasure &m = p_measures[j]; + if (m.Ignore()) continue; + if (m.Type() == ControlMeasure::Unmeasured) continue; + + // TODO: Should we use crater diameter? + Camera *cam = m.Camera(); + cam->SetImage(m.Sample(),m.Line()); + // Map the lat/lon/radius of the control point through the Spice of the + // measurement sample/line to get the computed sample/line. This must be + // done manually because the camera will compute a new time for line scanners, + // instead of using the measured time. + // First compute the look vector in body-fixed coordinates + std::vector look(3); + double cudx,cudy; + cam->GroundMap()->GetXY(lat, lon, rad, &cudx, &cudy); + m.SetFocalPlaneComputed ( cudx, cudy ); + + CameraFocalPlaneMap *fpmap = m.Camera()->FocalPlaneMap(); + + if (cam->GetCameraType() != Isis::Camera::Radar) { + // Now things get tricky. We want to produce errors in pixels not mm + // but some of the camera maps could fail. One that won't is the + // FocalPlaneMap which takes x/y to detector s/l. We will bypass the + // distortion map and have residuals in undistorted pixels. + if (!fpmap->SetFocalPlane(m.FocalPlaneComputedX(), m.FocalPlaneComputedY())) { + std::string msg = "Sanity check #1 for ControlPoint [" + + Id() + "], ControlMeasure [" + m.CubeSerialNumber() + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + // This error shouldn't happen but check anyways + } + } + + else { + // For radar, we can't skip the "distortion map" because it really converts + // slant range to ground range. + // Convert slant range/ doppler shift x/y to ground range x/y + m.Camera()->DistortionMap()->SetUndistortedFocalPlane(cudx,cudy); + + // Convert ground range x/y to detector position + double focalPlaneX = m.Camera()->DistortionMap()->FocalPlaneX(); + double focalPlaneY = m.Camera()->DistortionMap()->FocalPlaneY(); + + if (!fpmap->SetFocalPlane(focalPlaneX,focalPlaneY)) { + std::string msg = "Sanity check #1 for ControlPoint [" + + Id() + "], ControlMeasure [" + m.CubeSerialNumber() + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + double cuSamp = fpmap->DetectorSample(); + double cuLine = fpmap->DetectorLine(); + + if (cam->GetCameraType() != Isis::Camera::Radar) { + // Again we will bypass the distortion map and have residuals in undistorted pixels. + if (!fpmap->SetFocalPlane(m.FocalPlaneMeasuredX(),m.FocalPlaneMeasuredY())) { + std::string msg = "Sanity check #2 for ControlPoint [" + + Id() + "], ControlMeasure [" + m.CubeSerialNumber() + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + // This error shouldn't happen but check anyways + } + } + else{ + // In the radar case we can't skip this step since it is really converting slant range to ground range + m.Camera()->DistortionMap()->SetUndistortedFocalPlane(m.FocalPlaneMeasuredX(),m.FocalPlaneMeasuredY()); + double focalPlaneX = m.Camera()->DistortionMap()->FocalPlaneX(); + double focalPlaneY = m.Camera()->DistortionMap()->FocalPlaneY(); + + if (!fpmap->SetFocalPlane(focalPlaneX,focalPlaneY)) { + std::string msg = "Sanity check #2 for ControlPoint [" + + Id() + "], ControlMeasure [" + m.CubeSerialNumber() + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + double muSamp = fpmap->DetectorSample(); + double muLine = fpmap->DetectorLine(); + + // The units are in detector sample/lines. We will apply the instrument + // summing mode to get close to real pixels. Note however we are in + // undistorted pixels + CameraDetectorMap *cdmap = m.Camera()->DetectorMap(); + double sampError = muSamp - cuSamp; + double lineError = muLine - cuLine; + + if (cam->GetCameraType() != Isis::Camera::Radar) { + sampError /= cdmap->SampleScaleFactor(); + lineError /= cdmap->LineScaleFactor(); + } + + m.SetError(sampError,lineError); + } + return; + } + + /** + * Return the maximum error magnitude of the measures in the point. + * Ignored and unmeasured measures will not be included. + */ + double ControlPoint::MaximumError () const { + double maxError = 0.0; + if (Ignore()) return maxError; + + for (int j=0; j<(int) p_measures.size(); j++) { + if (p_measures[j].Ignore()) continue; + if (p_measures[j].Type() == ControlMeasure::Unmeasured) continue; + if (p_measures[j].ErrorMagnitude() > maxError) { + maxError = p_measures[j].ErrorMagnitude(); + } + } + + return maxError; + } + + + /** + * Wraps the input longitude toward a base longitude + * + * @param lon Input longitude to be wrapped + * @param baselon Longitude to compare + * @return The wrapped longitude + */ + double ControlPoint::WrapLongitude( double lon, double baselon) { + double diff = baselon - lon; + + if (diff <= 180. && diff >= -180.) { // No wrap needed + return lon; + } + else if (diff > 180.) { + return (lon + 360.); + } + else { // (diff < -180.) + return (lon - 360.); + } + } + + + /** + * Returns the number of non-ignored control measures + * + * @return Number of valid control measures + */ + int ControlPoint::NumValidMeasures() { + int size = 0; + for(int cm = 0; cm < Size(); cm ++) { + if(!p_measures[cm].Ignore()) size ++; + } + return size; + } + + /** + * Copy Constructor + * + * @author sprasad (5/11/2010) + * + * @param pPoint + * + * @return ControlPoint& + */ + ControlPoint & ControlPoint::operator= (const Isis::ControlPoint &pPoint) + { + p_id = pPoint.p_id; + p_type = pPoint.p_type; + p_ignore = pPoint.p_ignore; + p_held = pPoint.p_held; + p_latitude = pPoint.p_latitude; + p_longitude = pPoint.p_longitude; + p_radius = pPoint.p_radius; + p_invalid = pPoint.p_invalid; + + //!< List of Control Measures + for (int i=0; i +#include +#include "ControlMeasure.h" + +namespace Isis { + + class PvlObject; + + /** + * @brief A single control point + * + * A control point is one or more measurements that identify the same feature + * or location in different images. + * + * @ingroup ControlNetwork + * + * @author 2005-07-29 Jeff Anderson + * + * @see ControlMeasure ControlNet + * + * @internal + * @history 2005-07-29 Jeff Anderson Original version + * @history 2006-01-11 Jacob Danton Added ReferenceIndex method and updated unitTest + * @history 2006-06-28 Tracie Sucharski, Added method to return measure + * for given serial number. + * @history 2006-10-31 Tracie Sucharski, Added HasReference method, + * changed ReferenceIndex method to throw error if there is no + * Reference ControlMeasure. + * @history 2007-01-25 Debbie A. Cook, Removed return statement in SetApriori method + * for GroundPoint case so that FocalPlaneMeasures will get set. The method + * already has a later return statement to avoid changing the lat/lon values. + * @history 2007-10-19 Debbie A. Cook, Wrapped longitudes when calculating apriori longitude + * for points with a difference of more than 180 degrees of longitude between measures. + * @history 2008-01-14 Debbie A. Cook, Changed call to Camera->SetUniversalGround in ComputeErrors + * to include the radius as an argument since the method has been overloaded to include + * radius. + * @history 2008-09-12 Tracie Sucharski, Add method to return true/false + * for existence of Serial Number. + * @history 2009-03-07 Debbie A. Cook Fixed ComputeErrors method to set focal plane coordinates + * without changing time and improved error messages. + * @history 2009-06-03 Christopher Austin, Added the p_invalid functionality + * along with forceBuild, fixed documentation errors. + * @history 2009-06-22 Jeff Anderson, Modified ComputeAprior + * method to correctly handle ground and held points. + * Previosuly it would throw an error if the lat/lon + * of a measure could not be computed. Also, modify + * the ComputeErrors method to not abort any longer + * if a control point lat/lon could not be projected + * back to a image line/sample. + * @history 2009-08-13 Debbie A. Cook Corrected calculation of + * scale used to get the undistorted focal plane + * coordinates to use the signed focal length (Z) from + * the CameraDistortionMap, + * @history 2009-08-21 Christopher Austin, Put the default return of + * ReferenceIndex() back as the first Measured measure. + * @history 2009-09-01 Eric Hyer, fixed some include issues. + * @history 2009-09-08 Eric Hyer, Added PointTypeToString method. + * @history 2009-10-13 Jeannie Walldren - Added detail to + * error messages. + * @history 2010-03-19 Debbie A. Cook Replaced code in method ComputeErrors with call to + * CameraGroundMap->GetXY + * @history 2010-05-11 Sharmila Prasad Added API's Copy Constructor to copy one point to another and + * ReferenceIndexNoException not to throw Exception if there are no reference point or + * no measures in a Control Point. + * @history 2010-06-04 Eric Hyer - removed parametor for PointTypeToString() + */ + class ControlPoint { + public: + ControlPoint(); + ControlPoint (const std::string &id); + + //! Destroy a control point + ~ControlPoint () {}; + + void Load(PvlObject &p, bool forceBuild=false); + + PvlObject CreatePvlObject(); + + /** + * Sets the Id of the control point + * + * @param id Control Point Id + */ + void SetId(const std::string &id) { p_id = id; }; + + /** + * Return the Id of the control point + * + * @return Control Point Id + */ + std::string Id() const { return p_id; }; + + void Add(const ControlMeasure &measure, bool forceBuild=false); + void Delete(int index); + + /** + * Return the ith measurement of the control point + * + * @param index Control Measure index + * + * @return The Control Measure at the provided index + */ + ControlMeasure &operator[](int index) { return p_measures[index]; }; + + /** + * Return the ith measurement of the control point + * + * @param index Control Measure index + * + * @return The Control Measure at the provided index + */ + const ControlMeasure &operator[](int index) const { return p_measures[index]; }; + + //! Return the measurement for the given serial number + ControlMeasure &operator[](const std::string &serialNumber); + + //! Return the measurement for the given serial number + const ControlMeasure &operator[](const std::string &serialNumber) const; + + //! Does Serial Number exist in point + bool HasSerialNumber (std::string &serialNumber); + + //! Return the number of measurements in the control point + int Size () const { return p_measures.size(); }; + int NumValidMeasures (); + + /** + * Set whether to ignore or use control point + * + * @param ignore True to ignore this Control Point, False to un-ignore + */ + void SetIgnore(bool ignore) { p_ignore = ignore; }; + + //! Return if the control point should be ignored + bool Ignore() const { return p_ignore; }; + + //! Return if the control point is invalid + bool Invalid() const { return p_invalid; } + + /** + * Set the control point as held to its lat/lon + * + * @param held True to hold this Control Point, False to release + */ + void SetHeld(bool held) { p_held = held; }; + + //! Is the control point lat/lon held? + bool Held() const { return p_held; }; + + /** + * A control point can have one of two types, either Ground or Tie. + */ + enum PointType { + /** + * A Ground point is a Control Point whose lat/lon is well established + * and should not be changed. Some people will refer to this as a + * truth (i.e., ground truth). Holding a point is equivalent to making + * it a ground point. A ground point can be identifed in one or more + * cubes. + */ + Ground, + /** + * A Tie point is a Control Point that identifies common measurements + * between two or more cubes. While it could have a lat/lon, it is not + * necessarily correct and is subject to change. This is the most + * common type of control point. + */ + Tie + }; + + /** + * Change the type of the control point + * + * @param type The type for this Control Point + */ + void SetType (PointType type) { p_type = type; }; + + //! Return the type of the point + PointType Type () const { return p_type; }; + + const std::string PointTypeToString() const; + + void SetUniversalGround (double lat, double lon, double radius); + + //! Return the planetocentric latitude of the point + double UniversalLatitude () const { return p_latitude; }; + + //! Return the planetocentric longitude of the point + double UniversalLongitude () const { return p_longitude; }; + + //! Return the radius of the point in meters + double Radius () const { return p_radius; }; + + double AverageError() const; + + // std::string Thumbnail() const; + // std::string FeatureName() const; + + bool HasReference(); + + int ReferenceIndex(); + + int ReferenceIndexNoException(); + + void ComputeApriori(); + + void ComputeErrors(); + + double MaximumError() const; + + double WrapLongitude ( double lon, double baselon); + + bool operator == (const Isis::ControlPoint &pPoint) const; + bool operator != (const Isis::ControlPoint &pPoint) const; + ControlPoint & operator = (const Isis::ControlPoint &pPoint); + + + private: + std::string p_id; //!< Point Id + std::vector p_measures; //!< List of Control Measures + PointType p_type; //!< This Control Point's Type + bool p_ignore; //!< If this Control Point is ignored + bool p_held; //!< If this Control Point is held + double p_latitude; //!< The Latitude of this Control Point + double p_longitude; //!< The Longtude of this Control Point + double p_radius; //!< The raduis of this Control Point + + bool p_invalid; //!< If this Control Point is invalid + }; +}; + +#endif + diff --git a/isis/src/base/objs/ControlPoint/ControlPoint.truth b/isis/src/base/objs/ControlPoint/ControlPoint.truth new file mode 100644 index 0000000000000000000000000000000000000000..ec752bdb9283c6167dac124b1c7ed0a720fdbfaf --- /dev/null +++ b/isis/src/base/objs/ControlPoint/ControlPoint.truth @@ -0,0 +1,80 @@ +ControlPoint unitTest +test PointTypeToString(): Ground +Object = ControlPoint + PointType = Ground + PointId = C151 + Latitude = 10.0 + Longitude = 15.0 + Radius = 20.0 + Held = True + Ignore = True + + Group = ControlMeasure + SerialNumber = Test1 + MeasureType = Unmeasured + Sample = Null + Line = Null + Diameter = 15.0 + Reference = False + End_Group +End_Object +End +Object = ControlPoint + PointType = Ground + PointId = C151 + Latitude = 10.0 + Longitude = 15.0 + Radius = 20.0 + Held = True + Ignore = True + + Group = ControlMeasure + SerialNumber = Test1 + MeasureType = Unmeasured + Sample = Null + Line = Null + Diameter = 15.0 + Reference = False + End_Group + + Group = ControlMeasure + SerialNumber = Test2 + MeasureType = Manual + Sample = 100.0 + Line = 200.0 + ErrorLine = 2.0 + ErrorSample = -2.0 + ErrorMagnitude = 2.8284271247462 + Diameter = 15.0 + Reference = True + End_Group +End_Object +End +ReferenceIndex = 1 +Object = ControlPoint + PointType = Ground + PointId = C151 + Latitude = 10.0 + Longitude = 15.0 + Radius = 20.0 + Held = True + Ignore = True + + Group = ControlMeasure + SerialNumber = Test2 + MeasureType = Manual + Sample = 100.0 + Line = 200.0 + ErrorLine = 2.0 + ErrorSample = -2.0 + ErrorMagnitude = 2.8284271247462 + Diameter = 15.0 + Reference = True + End_Group +End_Object +End +ReferenceIndex = 0 + +Test adding control measures with identical serial numbers ... +**PROGRAMMER ERROR** The SerialNumber is not unique. A measure with serial number [Test2] already exists for ControlPoint [C151]. + diff --git a/isis/src/base/objs/ControlPoint/Makefile b/isis/src/base/objs/ControlPoint/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5afe5f1fb771bbf444e310292ecf239f9e8ff94f --- /dev/null +++ b/isis/src/base/objs/ControlPoint/Makefile @@ -0,0 +1,5 @@ +INCS = ControlPoint.h +SRCS = ControlPoint.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ControlPoint/unitTest.cpp b/isis/src/base/objs/ControlPoint/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a0718686a277eeaba94b0e931533c0efdefc88e2 --- /dev/null +++ b/isis/src/base/objs/ControlPoint/unitTest.cpp @@ -0,0 +1,57 @@ +#include "ControlPoint.h" +#include "Preference.h" +#include "iException.h" + +#include +#include + +using namespace std; +void outit(Isis::ControlPoint &p); + +int main () { + Isis::Preference::Preferences(true); + cout << "ControlPoint unitTest" << endl; + + Isis::ControlPoint c("C151"); + Isis::ControlMeasure d; + d.SetCoordinate(1.0,2.0); + d.SetCubeSerialNumber("Test1"); + d.SetDiameter(15.0); + d.SetError(-1.0,1.0); + c.Add(d); + + c.SetHeld(true); + c.SetIgnore(true); + c.SetUniversalGround(10.0,15.0,20.0); + c.SetType(Isis::ControlPoint::Ground); + cout << "test PointTypeToString(): " << c.PointTypeToString() << "\n"; + outit(c); + + d.SetCubeSerialNumber("Test2"); + d.SetCoordinate(100.0,200.0); + d.SetType(Isis::ControlMeasure::Manual); + d.SetError(-2.0,2.0); + d.SetReference(true); + c.Add(d); + outit(c); + cout <<"ReferenceIndex = " << c.ReferenceIndex() << endl; + + c.Delete(0); + outit(c); + cout <<"ReferenceIndex = " << c.ReferenceIndex() << endl; + + cout << endl << "Test adding control measures with identical serial numbers ..." << endl; + try { + c.Add(d); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; +} + +void outit(Isis::ControlPoint &p) { + Isis::Pvl pvl; + pvl.AddObject(p.CreatePvlObject()); + cout << pvl << endl; +} diff --git a/isis/src/base/objs/ControlPointList/ControlPointList.cpp b/isis/src/base/objs/ControlPointList/ControlPointList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b735b7880c62976fb3731a3188a5ff8cf7ea1981 --- /dev/null +++ b/isis/src/base/objs/ControlPointList/ControlPointList.cpp @@ -0,0 +1,133 @@ +#include "ControlPointList.h" +#include "iException.h" +#include "FileList.h" +#include "Filename.h" +#include "iString.h" + +namespace Isis { + /** + * Creates a ControlPointList from a list of control point ids' + * + * @param psListFile The file withe list of control point ids' + */ + ControlPointList::ControlPointList(const std::string &psListFile) { + try { + QList qList; + FileList list(psListFile); + int size = (int)list.size(); + for(int i = 0; i < size; i++) { + qList.insert(i, QString(list[i].c_str())); + mbFound.push_back(false); + } + mqCpList = QStringList(qList); + + //sort the list for faster searches - internally uses qsort() + mqCpList.sort(); + } + catch(iException &e) { + std::string msg = "Can't open or invalid file list [" + psListFile + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + /** + * Destructor + */ + ControlPointList::~ControlPointList() { + } + + + /** + * Determines whether or not the requested control point id + * exists in the list + * + * @param psCpId The control point id to be checked for + * + * @return bool + */ + bool ControlPointList::HasControlPoint(const std::string &psCpId) { + int index = mqCpList.indexOf(QString(psCpId.c_str())); + + if(index == -1 || index >= Size()) + return false; + + mbFound[index] = true; + return true; + } + + + /** + * How many control points in the list + * + * @return int Returns number of control point in the list + */ + int ControlPointList::Size() const { + return mqCpList.size(); + } + + + /** + * Return a control point id given an index + * + * @param piIndex The index of the desired control point id + * + * @return std::string The control point id returned + */ + std::string ControlPointList::ControlPointId(int piIndex) { + int size = Size(); + if(piIndex >= 0 && piIndex < size) { + return (mqCpList.value(piIndex).toStdString()); + } + else { + iString num = iString(piIndex); + std::string msg = "Index [" + (std::string) num + "] is invalid"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + /** + * return a list index given a control point id + * + * @param ps_cpId The control point id to be searched for + * + * @return int The index of the control point id + */ + int ControlPointList::ControlPointIndex(const std::string &psCpId) { + if(HasControlPoint(psCpId)) { + return mqCpList.indexOf(QString(psCpId.c_str())); + } + else { + std::string msg = "Requested control point id [" + psCpId + "] "; + msg += "does not exist in the list"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + /** + * Register invalid control point and calculate the valid & + * invalid point count + * + * @param Pvl Will contain stats in pvl keywords + */ + void ControlPointList::RegisterStatistics(Pvl &pcPvlLog) { + int size = Size(); + int iNotFound = 0; + std::string sPointsNotFound = ""; + + for(int i = 0; i < size; i++) { + if(!mbFound[i]) { + if(iNotFound) { + sPointsNotFound += ", "; + } + sPointsNotFound += mqCpList.value(i).toStdString(); + iNotFound++; + } + } + + pcPvlLog += Isis::PvlKeyword("TotalPoints", size); + pcPvlLog += Isis::PvlKeyword("ValidPoints", size - iNotFound); + pcPvlLog += Isis::PvlKeyword("InValidPoints", iNotFound); + pcPvlLog += Isis::PvlKeyword("InValidPointIds", sPointsNotFound); + } +} + diff --git a/isis/src/base/objs/ControlPointList/ControlPointList.h b/isis/src/base/objs/ControlPointList/ControlPointList.h new file mode 100644 index 0000000000000000000000000000000000000000..322da7de10bba67ad979bd64562ecec7c66eb1bd --- /dev/null +++ b/isis/src/base/objs/ControlPointList/ControlPointList.h @@ -0,0 +1,69 @@ +#ifndef ControlPointList_h +#define ControlPointList_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/06/28 17:15:01 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc/documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include "Pvl.h" + +namespace Isis { + /** + * @brief Control Point List generator + * + * Create a list of Control Points from a file with control + * points ids + * + * @ingroup ControlNetworks + * + * @author 2009-08-11 Sharmila Prasad + * + * @internal + * + * @history 2009-08-11 Sharmila Prasad Original Version + */ + + class ControlPointList { + public: + ControlPointList(const std::string &psFileName); + virtual ~ControlPointList(); + + std::string ControlPointId(int piIndex); + int ControlPointIndex(const std::string &psCpId); + + bool HasControlPoint(const std::string &psCpId); + + int Size() const; + + void RegisterStatistics(Pvl &pcPvlLog); + + private: + QStringList mqCpList; + std::vector mbFound; // holds one to one correspondence with "mqCpList" on + // whether the point was valid + }; +}; + +#endif diff --git a/isis/src/base/objs/ControlPointList/ControlPointList.truth b/isis/src/base/objs/ControlPointList/ControlPointList.truth new file mode 100644 index 0000000000000000000000000000000000000000..eefa36a0e167d5f39c7bee3b545c5e76e189e957 --- /dev/null +++ b/isis/src/base/objs/ControlPointList/ControlPointList.truth @@ -0,0 +1,12 @@ +**PROGRAMMER ERROR** Index [8] is invalid +**PROGRAMMER ERROR** Requested control point id [new0000] does not exist in the list +new0001 +new0007 +new0008 +new0020 +new0036 +new0050 +new01000 +new1233 +1 +4 diff --git a/isis/src/base/objs/ControlPointList/Makefile b/isis/src/base/objs/ControlPointList/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..965d4f0033d558c161433b0296615fe1a3ec9bc4 --- /dev/null +++ b/isis/src/base/objs/ControlPointList/Makefile @@ -0,0 +1,5 @@ +INCS = ControlPointList.h +SRCS = ControlPointList.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ControlPointList/points.lis b/isis/src/base/objs/ControlPointList/points.lis new file mode 100644 index 0000000000000000000000000000000000000000..849866b07784c3a934a0ea1735d50a73fc694d68 --- /dev/null +++ b/isis/src/base/objs/ControlPointList/points.lis @@ -0,0 +1,9 @@ +new0007 +new0050 +new1233 +new0001 +new0036 +new0020 +new0008 +new01000 + diff --git a/isis/src/base/objs/ControlPointList/unitTest.cpp b/isis/src/base/objs/ControlPointList/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..12accfe83b6c9be9bbd687f19faddc0a5f97c73a --- /dev/null +++ b/isis/src/base/objs/ControlPointList/unitTest.cpp @@ -0,0 +1,34 @@ +#include "ControlPointList.h" +#include "iException.h" + +#include +#include +using namespace std; + +int main() { + Isis::ControlPointList cpl("points.lis"); //list of Control Point Ids in the file + + int size = cpl.Size(); + + //print point ids in the list + for(int i = 0; i < size; i++) { + std::cout << cpl.ControlPointId(i) << "\n"; + } + + // index out of range + try { + std::cout << cpl.ControlPointId(size) << "\n"; + } + catch(Isis::iException &e) { + e.Report(false); + } + + try { + std::cout << cpl.ControlPointIndex("new0007") << "\n"; + std::cout << cpl.ControlPointIndex("new0036") << "\n"; + std::cout << cpl.ControlPointIndex("new0000") << "\n"; //not found - invalid point + } + catch(Isis::iException &e) { + e.Report(false); + } +} diff --git a/isis/src/base/objs/Cube/Cube.cpp b/isis/src/base/objs/Cube/Cube.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5cd2824ca8d8218590a74709c08f23331cd269b7 --- /dev/null +++ b/isis/src/base/objs/Cube/Cube.cpp @@ -0,0 +1,1243 @@ +/** + * @file + * $Revision: 1.19 $ + * $Date: 2010/03/22 19:44:53 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#include + +#include "Cube.h" +#include "Preference.h" +#include "Filename.h" +#include "iException.h" +#include "CubeBsqHandler.h" +#include "CubeTileHandler.h" +#include "Endian.h" +#include "SpecialPixel.h" +#include "Message.h" +#include "Application.h" +#include "System.h" +#include "Camera.h" +#include "CameraFactory.h" +#include "Projection.h" +#include "Statistics.h" +#include "Histogram.h" +#include "LineManager.h" + +using namespace std; +namespace Isis { + //! Constructs a Cube object. + Cube::Cube () { + // Initialize the user preferences + p_attachedPreference = true; + p_overwritePreference = true; + p_historyPreference = true; + + // Override them + Isis::PvlGroup &pref = Isis::Preference::Preferences().FindGroup("CubeCustomization"); + + Isis::iString temp = (string) pref["Format"]; + p_attachedPreference = temp.UpCase() == "ATTACHED"; + + temp = (string) pref["Overwrite"]; + p_overwritePreference = temp.UpCase() == "ALLOW"; + + temp = (string) pref["History"]; + p_historyPreference = temp.UpCase() == "ON"; + + // convert max size from gigabytes to bytes for later comparison + p_maxSizePreference = pref["MaximumSize"]; + p_maxSizePreference *= 1073741824; + + // Init the i/o handler pointer + p_ioHandler = NULL; + + // Init the cube def + p_cube.labelFile = ""; + p_cube.label.Clear(); + p_cube.labelBytes = 65536; + p_cube.attached = p_attachedPreference; + p_cube.history = p_historyPreference; + p_cube.dataFile = ""; + p_cube.startByte = 0; + p_cube.access = IsisCubeDef::ReadWrite; + p_cube.samples = 512; + p_cube.lines = 512; + p_cube.bands = 1; + p_cube.pixelType = Isis::Real; + p_cube.cubeFormat = Isis::Tile; + if (Isis::IsBigEndian()) p_cube.byteOrder = Isis::Msb; + if (Isis::IsLittleEndian()) p_cube.byteOrder = Isis::Lsb; + p_cube.base = 0.0; + p_cube.multiplier = 1.0; + p_cube.virtualBandList.clear(); + + p_tempCube = ""; + p_camera = NULL; + p_projection = NULL; + + p_formatTemplateFile = "$base/templates/labels/CubeFormatTemplate.pft"; + + p_mutex = new QMutex(); + } + + //! Destroys the Cube object. + Cube::~Cube () { + Close(); + if(p_camera != NULL) delete p_camera; + if(p_projection != NULL) delete p_projection; + if(p_mutex != NULL) delete p_mutex; + } + +/** + * This method will open an isis sube for reading or reading/writing. + * + * @param[in] cfile Name of the cube file to open. If the extenstion ".cub" is not + * given it will be appended (i.e., the extension of .cub is forced). + * Environment variables in the filename will be automatically expanded as well. + * @param[in] access (Default value of "r") Defines how the cube will be accessed. + * Either readonly "r" or read-write "rw". + */ + void Cube::Open (const std::string &cfile, std::string access) { + // Already opened? + if (IsOpen()) { + string msg = "Cube::Open - You already have [" + p_cube.labelFile + + "] opened"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Figure out the access type + if (access == "r") { + p_cube.access = IsisCubeDef::ReadOnly; + } + else if (access == "rw") { + p_cube.access = IsisCubeDef::ReadWrite; + } + else { + string message = "Invalid value for argument [access] must be [r,rw]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + // Expand name + Isis::Filename cubfile(cfile); + + // Read the labels + try { + p_cube.label.Clear(); + p_cube.label.Read(cubfile.Expanded()); + if (p_cube.label.Objects() == 0) { + throw Isis::iException::Message(Isis::iException::Io,"Dummy",_FILEINFO_); + } + } + catch (Isis::iException &e) { + e.Clear(); + try { + cubfile.AddExtension("cub"); + p_cube.label.Clear(); + p_cube.label.Read(cubfile.Expanded()); + if (p_cube.label.Objects() == 0) { + throw Isis::iException::Message(Isis::iException::Io,"Dummy",_FILEINFO_); + } + } + catch (Isis::iException &e) { + e.Clear(); + try { + cubfile.RemoveExtension(); + cubfile.AddExtension("lbl"); + p_cube.label.Clear(); + p_cube.label.Read(cubfile.Expanded()); + } + catch (Isis::iException &e) { + e.Clear(); + string msg = Isis::Message::FileOpen(cfile); + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + } + p_cube.labelFile = cubfile.Expanded(); + + // See if this is an old Isis cube format. If so then we will + // need to internalize a new label + if (p_cube.label.HasKeyword("CCSD3ZF0000100000001NJPL3IF0PDS200000001")) { + p_tempCube = ""; + if (access == "r") { + ReformatOldIsisLabel(p_cube.labelFile); + return; + } + else { + string msg = "Can not open old cube file format with write access [" + + cfile + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + + // Figure out the name of the data file + Isis::PvlObject &core = p_cube.label.FindObject("IsisCube").FindObject("Core"); + if (core.HasKeyword("^Core")) { + Isis::Filename temp(core["^Core"]); + if (temp.OriginalPath() == ".") { + p_cube.dataFile = cubfile.Path() + "/" + temp.Name(); + } + else { + p_cube.dataFile = temp.Expanded(); + } + p_cube.attached = false; + } + else { + p_cube.dataFile = cubfile.Expanded(); + p_cube.attached = true; + } + + // Get location of cube data in the data file + p_cube.startByte = (Isis::BigInt) core["StartByte"]; + + // Get dimensions + Isis::PvlGroup &dims = core.FindGroup("Dimensions"); + p_cube.samples = dims["Samples"]; + p_cube.lines = dims["Lines"]; + p_cube.bands = dims["Bands"]; + + // Get pixel type + Isis::PvlGroup &ptype = core.FindGroup("Pixels"); + p_cube.pixelType = Isis::PixelTypeEnumeration(ptype["Type"]); + + // Get endianness + p_cube.byteOrder = Isis::ByteOrderEnumeration(ptype["ByteOrder"]); + + // Get core base and multipler + p_cube.base = ptype["Base"]; + p_cube.multiplier = ptype["Multiplier"]; + + // Determine the number of bytes in the label + if (p_cube.attached) { + p_cube.labelBytes = p_cube.label.FindObject("Label")["Bytes"]; + } + else { + p_cube.labelBytes = LabelBytesUsed (); + } + + // Now examine the format to see which type of handler to create + if ((string) core["Format"] == "BandSequential") { + p_cube.cubeFormat = Isis::Bsq; + p_ioHandler = new Isis::CubeBsqHandler (p_cube); + } + else { + p_cube.cubeFormat = Isis::Tile; + p_ioHandler = new Isis::CubeTileHandler (p_cube); + } + + // Open the file + p_ioHandler->Open(); + + // If the virtual band list is empty all bands are assumed + if (p_virtualBandList.size() == 0) { + for (int i=0; iOpen(); + } + catch ( Isis::iException &e ) { + // If access requested is read/write, try opening read, but throw error. + if (access == "rw") { + e.Clear(); + p_cube.access = IsisCubeDef::ReadOnly; + p_ioHandler->Open(); + string msg = "Cannot open read/write [" + p_cube.labelFile + + "] will be opened read only"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + + } + + + +/** + * This method will create an isis cube for writing. The programmer should + * make appropriate calls to Set methods before invoking Create. If none are + * made there are internal defaults which are: + * @code + * Dimensions 512x512x1 + * PixelType Real + * ByteOrder Matches architecture of host machine + * Attached From user preference file + * Label Size 65536 bytes + * Format Tiled + * Base 0.0 + * Multiplier 1.0 + * @endcode + * + * @param cfile Name of the cube file to open. If the extenstion ".cub" is not + * given it will be appended (i.e., the extension of .cub is forced). + * Environment variables in the filename will be automatically expanded as well. + */ + void Cube::Create(const std::string &cfile) { + // Already opened? + if (IsOpen()) { + string msg = "Cube::Create - You already have [" + p_cube.labelFile + + "] opened"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Make sure the cube is not going to exceed the maximum size preference + BigInt size = (BigInt)p_cube.samples * (BigInt)p_cube.lines * + (BigInt)p_cube.bands * (BigInt)Isis::SizeOf(p_cube.pixelType); + if (size > p_maxSizePreference) { + string msg; + msg += "The cube you are attempting to create [" + cfile + "] is ["; + msg += (Isis::iString)(size / 1073741824) + "GB] "; + msg += "This is larger than the current allowed size of ["; + msg += (Isis::iString)(p_maxSizePreference / 1073741824) + "GB]. The cube "; + msg += "dimensions were (S,L,B) [" + (Isis::iString)p_cube.samples + ", "; + msg += (iString)p_cube.lines + ", " + (Isis::iString)p_cube.bands; + msg += "] with [" + (Isis::iString)(Isis::SizeOf(p_cube.pixelType)); + msg += "] bytes per pixel."; + msg += " If you still wish to create this cube, the maximum value can"; + msg += " be changed in the file [~/.Isis/IsisPreferences] within the group"; + msg += " CubeCustomization, keyword MaximumSize."; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + + // Set the access + p_cube.access = IsisCubeDef::ReadWrite; + + // Expand output name + Isis::Filename cubfile(cfile); + cubfile.AddExtension("cub"); + + // See if we have attached or detached labels + Isis::PvlObject core("Core"); + if (p_cube.attached) { + p_cube.startByte = p_cube.labelBytes + 1; + core += Isis::PvlKeyword("StartByte",p_cube.startByte); + p_cube.labelFile = cubfile.Expanded(); + p_cube.dataFile = cubfile.Expanded(); + } + else { + p_cube.startByte = 1; + core += Isis::PvlKeyword("StartByte",p_cube.startByte); + core += Isis::PvlKeyword("^Core",cubfile.Name()); + p_cube.dataFile = cubfile.Expanded(); + cubfile.RemoveExtension(); + cubfile.AddExtension("lbl"); + p_cube.labelFile = cubfile.Expanded(); + } + + // Create the size of the core + Isis::PvlGroup dims("Dimensions"); + dims += Isis::PvlKeyword("Samples",p_cube.samples); + dims += Isis::PvlKeyword("Lines",p_cube.lines); + dims += Isis::PvlKeyword("Bands",p_cube.bands); + core.AddGroup(dims); + + // Create the pixel type + Isis::PvlGroup ptype("Pixels"); + ptype += Isis::PvlKeyword("Type",Isis::PixelTypeName(p_cube.pixelType)); + + + + // And the byte ordering + ptype += Isis::PvlKeyword ("ByteOrder",Isis::ByteOrderName(p_cube.byteOrder)); + + // Set the pixel base and multiplier (real pix = base + mult * disk pix) + if (p_cube.pixelType == Isis::Real) { + p_cube.base = 0.0; + p_cube.multiplier = 1.0; + } + ptype += Isis::PvlKeyword("Base",p_cube.base); + ptype += Isis::PvlKeyword("Multiplier",p_cube.multiplier); + core.AddGroup(ptype); + + // Create the Cube + Isis::PvlObject isiscube("IsisCube"); + isiscube.AddObject(core); + + p_cube.label.Clear(); + p_cube.label.AddObject(isiscube); + + // Setup storage reserved for the label + Isis::PvlObject lbl("Label"); + lbl += Isis::PvlKeyword("Bytes",p_cube.labelBytes); + p_cube.label.AddObject(lbl); + + // Create the appropriate handler + if (p_cube.cubeFormat == Isis::Bsq) { + p_ioHandler = new Isis::CubeBsqHandler (p_cube); + } + else { + p_ioHandler = new Isis::CubeTileHandler (p_cube); + } + + // Set up the virtual band list (all bands always for output) + for (int i=0; iCreate(p_overwritePreference); + + // Write the labels + WriteLabels(); + + } + +/** + * This method will read a buffer of data from the cube as specified by the + * contents of the Buffer object. + * + * @param rbuf Buffer to be loaded + */ + void Cube::Read(Isis::Buffer &rbuf) { + if (!IsOpen()) { + string msg = "Cube::Read - Try opening a file before you read it"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + p_mutex->lock(); + + try { + p_ioHandler->Read(rbuf); + } + catch(...) { + p_mutex->unlock(); + throw; + } + + p_mutex->unlock(); + + p_ioHandler->ToDouble(rbuf); + } + +/** + * This method will write a buffer of data from the cube as specified by the + * contents of the Buffer object. + * + * + * @param wbuf Buffer to be written. + */ + void Cube::Write(Isis::Buffer &wbuf) { + if (!IsOpen()) { + string msg = "Cube::Write - Try opening/creating a file before you write it"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (IsReadOnly()) { + string msg = "The cube [" + Filename() + "] is opened read-only ... "; + msg += "you can't write to it"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + p_ioHandler->ToRaw(wbuf); + + p_mutex->lock(); + + try { + p_ioHandler->Write(wbuf); + } + catch(...) { + p_mutex->unlock(); + throw; + } + + p_mutex->unlock(); + } + +/** + * Closes the cube and updates the labels. Optionally, it deletes the cube if + * requested. + * + * @param removeIt (Default value = false) Indicates if the file should be + * removed/deleted. + */ + void Cube::Close(const bool removeIt) { + // Ignore if the stream is closed + if (p_ioHandler == NULL) return; + + if (p_cube.stream.is_open()) { + + // Write the labels + if (p_cube.access == IsisCubeDef::ReadWrite) { + if (!removeIt) WriteLabels(); + } + + // Close the data file + p_ioHandler->Close(removeIt); + } + + // Always remove a temporary file + if (p_tempCube != "") { + remove(p_tempCube.c_str()); + p_tempCube = ""; + } + + delete p_ioHandler; + p_cube.virtualBandList.clear(); + p_ioHandler = NULL; + } + + void Cube::ReformatOldIsisLabel(const std::string &oldCube) { + string parameters = "from="+oldCube; + Isis::Filename oldName(oldCube); + Isis::Filename tempCube("Temporary_"+oldName.Name(),"cub"); + parameters += " to="+tempCube.Expanded(); + + if (Isis::iApp == NULL) { + string command = "$ISISROOT/bin/pds2isis " + parameters; + System(command); + } + else { + std::string prog = "pds2isis"; + Isis::iApp->Exec(prog,parameters); + } + + p_tempCube = tempCube.Expanded(); + Open(tempCube.Expanded(),"r"); + } + + /** + * This method will return the physical band number given a virtual band number. + * Physical and virtual bands always match unless the programmer made a call + * to SetVirtualBand prior to opening the cube. + * + * + * @param virtualBand Virtual band to translate to physical band. + * + * @return int The physical band number. + */ + int Cube::PhysicalBand (const int virtualBand) const { + if ((virtualBand < 1) || + (virtualBand > (int)p_cube.virtualBandList.size())) { + string msg = "Out of array bounds [" + Isis::iString(virtualBand) + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_cube.virtualBandList[virtualBand-1]; + } + + void Cube::WriteLabels () { + // Set the pvl's format template + p_cube.label.SetFormatTemplate(p_formatTemplateFile); + // Write them with attached data + if (p_cube.attached) { + ostringstream temp; + temp << p_cube.label << endl; + string tempstr = temp.str(); + if ((int) tempstr.length() < p_cube.labelBytes) { + // Clear out the label area + char *tempbuf = new char[p_cube.labelBytes]; + memset(tempbuf,0,p_cube.labelBytes); + p_cube.stream.seekp(0,std::ios::beg); + p_cube.stream.write(tempbuf,p_cube.labelBytes); + delete [] tempbuf; + + p_cube.stream.seekp(0,std::ios::beg); + p_cube.stream.write(tempstr.c_str(),tempstr.length()); + } + else { + p_cube.stream.close(); + string msg = "Label space is full in [" + p_cube.labelFile + + "] unable to write labels"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + + // or detached label + else { + p_cube.label.Write(p_cube.labelFile); + } + } + +/** + * Used prior to the Create method, this will allocate a specific number of + * bytes in the label area for attached files. If not invoked, 65536 bytes will + * be reserved by default. + * + * @param[in] labelBytes Number of bytes to reserve for label space. + */ + void Cube::SetLabelBytes (int labelBytes) { + OpenCheck(); + p_cube.labelBytes = labelBytes; + } + +/** + * Used prior to the Create method to specify the size of the cube. If not + * invoked, a 512 x 512 x 1 cube will be created. + * + * + * @param ns Number of samples + * @param nl Number of lines + * @param nb Number of bands + */ + void Cube::SetDimensions (int ns, int nl, int nb) { + OpenCheck(); + if ((ns < 1) || (nl < 1) || (nb < 1)) { + string msg = "SetDimensions: Invalid number of sample, lines or bands"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + p_cube.samples = ns; + p_cube.lines = nl; + p_cube.bands = nb; + } + +/** + * Used prior to the Create method, this will specify the output pixel type. + * If not invoked, the pixel type will be Real. + * + * @param pixelType An enumeration of the pixelType desired in the output cube. + * See PixelType documentation for more information. + */ + void Cube::SetPixelType (Isis::PixelType pixelType) { + OpenCheck(); + p_cube.pixelType = pixelType; + } + +/** + * Used prior to the Create method, this will specify the format of the cube, + * either band, sequential or tiled. + * If not invoked, a tiled file will be created. + * + * @param cubeFormat An enumeration of either Isis::Bsq or Isis::Tile. + */ + void Cube::SetCubeFormat (Isis::CubeFormat cubeFormat) { + OpenCheck(); + p_cube.cubeFormat = cubeFormat; + } + +/** + * Used prior to the Create method, this will specify the byte order of pixels, + * either least or most significant byte. + * + * @param byteOrder An enumeration of either Isis::Msb or Isis::Lsb. + */ + void Cube::SetByteOrder (Isis::ByteOrder byteOrder) { + OpenCheck(); + p_cube.byteOrder = byteOrder; + } + + +/** + * Used prior to the Create method, this will compute a good base and + * multiplier value given the minimum/maximum range of the 32bit data. For + * example, min=0.0 and max=1.0 of 32-bit pixels will ensure the base and + * multiplier will cause the data to be spread out fully in the 8=bit or + * 16-bit range. + * + * @param min Minimum 32-bit pixel. + * @param max Maximum 32-bit pixel. + */ + void Cube::SetMinMax (double min, double max) { + OpenCheck(); + + double base = 0.0; + double multiplier = 1.0; + double x1,x2; + + if (p_cube.pixelType == Isis::UnsignedByte) { + x1 = Isis::VALID_MIN1; + x2 = Isis::VALID_MAX1; + multiplier = (max - min) / (x2 - x1); + base = min - multiplier * x1; + } + else if (p_cube.pixelType == Isis::SignedWord) { + x1 = Isis::VALID_MIN2; + x2 = Isis::VALID_MAX2; + multiplier = (max - min) / (x2 - x1); + base = min - multiplier * x1; + } + + p_cube.base = base; + p_cube.multiplier = multiplier; + } + +/** + * Used prior to the Create method, this will specify the base and multiplier + * for converting 8-bit/16-bit back and forth between 32-bit: + * @f[ + * 32-bit pixel = 8-bit/16-bit pixel * multiplier + base + * @f] + * + * @param base Additive constant. + * @param mult Multiplicative constant. + */ + void Cube::SetBaseMultiplier (double base, double mult) { + OpenCheck(); + p_cube.base = base; + p_cube.multiplier = mult; + } + +/** + * Used prior to the Create method, this will specify that the labels and data + * will be in one file. + */ + void Cube::SetAttached () { + OpenCheck(); + p_cube.attached = true; + } + +/** + * Used prior to the Create method, this will specify that the labels and data + * will be in separate files. In particular, filename.lbl and filename.cub will + * contain the labels and cube, respectively. + */ + void Cube::SetDetached () { + OpenCheck(); + p_cube.attached = false; + } + +/** + * Returns the number of bands in the cube. Note that this is the number of + * virtual bands if the Open method was used. + * + * @return int The number of bands in the cube. + */ + int Cube::Bands() const { + return p_cube.virtualBandList.size(); + } + +/** + * Used prior to the Open method, this allows the programmer to specify a subset + * of bands to work with. For example, if the programmer only wants to work with + * band 5 out of a 10 band cube, this can be accommodated. In the future, this + * method will accept BandBin FilterName as well as band numbers. + * + * @param[in] vbands A vector of strings containing the virtual bands. The bands + * will be verified when the cube is opened. For now, the vector must contain + * integers (e.g., "5", "10", "1"). + */ + void Cube::SetVirtualBands (const std::vector &vbands) { + OpenCheck(); + p_cube.virtualBandList.clear(); + p_virtualBandList = vbands; + } + +/** + * Used prior to the Open method this allows the programmer to specify a subset + * of bands to work with. + */ + void Cube::SetVirtualBands () { + // For now convert to integers ... later convert filter names to band numbers + int i; + try { + for (i=0; i<(int)p_virtualBandList.size(); i++) { + Isis::iString sband = p_virtualBandList[i]; + int band = sband.ToInteger(); + if ((band < 1) || (band > p_cube.bands)) { + string msg = "Invalid virtual band list"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + p_cube.virtualBandList.push_back(band); + } + } + catch (Isis::iException &e) { + string msg = "Invalid virtual band [" + p_virtualBandList[i] + "]"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + + void Cube::OpenCheck() { + if (IsOpen()) { + string msg = "Sorry you can't do a SetMethod after the cube is opened"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + +/** + * Returns the number of bytes used by the label. + * + * @return int the number of bytes used by the label. + */ + int Cube::LabelBytesUsed () { + ostringstream s; + s << p_cube.label << endl; + string temp = s.str(); + return temp.size(); + } + +/** + * This method will read data from the specified Blob object. + * + * @param[in] blob The Blob data to be loaded + * + * @return (type)return description + */ + void Cube::Read(Isis::Blob &blob) { + if (!p_cube.stream.is_open()) { + string msg = "The cube is not opened so you can't read a blob from it"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + blob.Read(p_cube.label,p_cube.stream); + } + + /** + * This method will write a blob of data (e.g. History, Table, etc) + * to the cube as specified by the contents of the Blob object. + * + * @param blob data to be written + */ + void Cube::Write(Isis::Blob &blob) { + if (!p_cube.stream.is_open()) { + string msg = "The cube is not opened so you can't write a blob to it"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (p_cube.access == IsisCubeDef::ReadOnly) { + string msg = "The cube must be opened in read/write mode, not readOnly"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Write an attached blob + if (p_cube.attached) { + // Compute the number of bytes in the cube + label bytes and if the + // endpos of the file // is not greater than this then seek to that position. + p_cube.stream.seekp(0,std::ios::end); + streampos sbyte = p_cube.stream.tellp(); + streampos maxbyte = (streampos) p_cube.labelBytes + p_cube.dataBytes; + if (sbyte < maxbyte) p_cube.stream.seekp(maxbyte,std::ios::beg); + blob.Write(p_cube.label,p_cube.stream); + } + + // Write a detached blob + else { + Isis::Filename blobFilename = Filename(); + blobFilename.RemoveExtension(); + blobFilename.AddExtension(blob.Type()); + blobFilename.AddExtension(blob.Name()); + string blobFile(blobFilename.Expanded()); + ios::openmode flags = std::ios::in | std::ios::binary | std::ios::out | + std::ios::trunc; + fstream detachedStream; + detachedStream.open(blobFile.c_str(),flags); + if (!detachedStream) { + string message = "Unable to open data file [" + + blobFilename.Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + +// Changed to work with mods to Filename class +// blob.Write(p_cube.label,detachedStream,blobFilename.Basename()+"."+ +// blob.Type()+"."+ +// blobFilename.Extension()); + blob.Write(p_cube.label,detachedStream,blobFilename.Name()); + } + } + + /** + * This method will delete a blob label object from the cube as specified by the + * Blob type and name. If blob does not exist it will do nothing and return + * false. + * + * @param BlobType type of blob to search for (Polygon, Table, etc) + * @param BlobName blob to be deleted + * @return boolean if it found the blob and deleted it. + */ + bool Cube::BlobDelete(std::string BlobType, std::string BlobName) { + for(int i = 0; i < p_cube.label.Objects();i++) { + Isis::PvlObject obj = p_cube.label.Object(i); + if (obj.Name().compare(BlobType) == 0) { + if(obj.FindKeyword("Name")[0] == BlobName) { + p_cube.label.DeleteObject(i); + return true; + } + } + } + return false; + } + + /** + * Return a camera associated with the cube. The generation of + * the camera can throw an exception, so you might want to catch errors + * if that interests you. + */ + Isis::Camera *Cube::Camera() { + if (p_camera == NULL) { + p_camera = CameraFactory::Create(*Label()); + } + return p_camera; + } + + /** + * Returns true if the labels of the cube appear to have a valid mapping + * group. This returning true does not guarantee that the cube can project or + * that the Projection() method will succeed. + * + * + * @return bool True if the file should have a valid projection + */ + bool Cube::HasProjection() { + return Label()->FindObject("IsisCube").HasGroup("Mapping"); + } + + /** + * Return a projection associated with the cube. The generation of + * the projection can throw an exception, so you might want to catch errors + * if that interests you. + */ + Isis::Projection *Cube::Projection() { + if (p_projection == NULL) { + p_projection = ProjectionFactory::CreateFromCube(*Label()); + } + return p_projection; + } + + /** + * Check to see if the cube contains a pvl table by the provided name + * + * @param name The name of the pvl table to search for + * + * @return bool True if the pvl table was found + */ + bool Cube::HasTable(const std::string &name) { + for (int o=0; oObjects(); o++) { + Isis::PvlObject &obj = Label()->Object(o); + if (obj.IsNamed("Table")) { + if (obj.HasKeyword("Name")) { + Isis::iString temp = (string) obj["Name"]; + temp.UpCase(); + Isis::iString temp2 = name; + temp2.UpCase(); + if (temp == temp2) return true; + } + } + } + return false; + } + + /** + * This method returns a pointer to a Statistics object + * which allows the program to obtain and use various statistics + * from the cube. Cube does not retain ownership of + * the returned pointer - please delete it when you are done with it. + * + * @param[in] band (Default value is 1) Returns the statistics for the specified + * band.If the user specifies 0 for this parameter, the method will loop + * through every band in the cube and accumulate statistics from each band + * seperately + * + * @param msg The message to display with the percent process while gathering + * statistics + * + * @return (Isis::Histogram) A pointer to a Statistics object containing details + * such as the minimum and maximum pixel values for the input cube on the + * band specified, or all bands as the case may be. + */ + Isis::Statistics *Cube::Statistics(const int band, std::string msg) { + return Statistics(band, Isis::ValidMinimum, Isis::ValidMaximum, msg); + } + + + /** + * This method returns a pointer to a Statistics object + * which allows the program to obtain and use various statistics + * from the cube. Cube does not retain ownership of + * the returned pointer - please delete it when you are done with it. + * + * @param band Returns the statistics for the specified + * band. If the user specifies 0 for this parameter, the method will + * loop through every band in the cube and accumulate statistics from + * each band seperately + * @param validMin + * @param validMax + * @param msg + * + * @return Isis::Statistics* + */ + Isis::Statistics *Cube::Statistics(const int band, const double validMin, + const double validMax, std::string msg) { + // Make sure band is valid + if ((band < 0) || (band > Bands())) { + string msg = "Invalid band in [CubeInfo::Statistics]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Construct a line buffer manager and a statistics object + Isis::LineManager line(*this); + Isis::Statistics *stats = new Isis::Statistics(); + + stats->SetValidRange(validMin, validMax); + + int bandStart = band; + int bandStop = band; + int maxSteps = Lines(); + if (band == 0){ + bandStart = 1; + bandStop = Bands(); + maxSteps = Lines() * Bands(); + } + + Isis::Progress progress; + progress.SetText(msg); + progress.SetMaximumSteps(maxSteps); + progress.CheckStatus(); + + // Loop and get the statistics for a good minimum/maximum + for (int useBand = bandStart ; useBand <= bandStop ; useBand++){ + for (int i=1; i<=Lines(); i++) { + line.SetLine(i,useBand); + Read(line); + stats->AddData (line.DoubleBuffer(),line.size()); + progress.CheckStatus(); + } + } + + return stats; + } + + /** + * This method returns a pointer to a Histogram object + * which allows the program to obtain and use various statistics and + * histogram information from the cube. Cube does not retain ownership of + * the returned pointer - please delete it when you are done with it. + * + * @param[in] band (Default value is 1) Returns the histogram for the specified + * band.If the user specifies 0 for this parameter, the method will loop + * through every band in the cube and accumulate a histogram from all of + * them + * + * @param msg The message to display with the percent process while gathering + * histogram data + * + * @return (Isis::Histogram) A pointer to a Histogram object. + * + * @throws IsisProgrammerError Band was less than zero or more than the number + * of bands in the cube. + */ + Isis::Histogram *Cube::Histogram (const int band, std::string msg) { + return Histogram(band, Isis::ValidMinimum, Isis::ValidMaximum, msg); + } + + + /** + * This method returns a pointer to a Histogram object + * which allows the program to obtain and use various statistics and + * histogram information from the cube. Cube does not retain ownership of + * the returned pointer - please delete it when you are done with it. + * + * @param[in] band Returns the histogram for the specified + * band. If the user specifies 0 for this parameter, the method will + * loop through every band in the cube and accumulate a histogram from + * all of them + * + * @param validMin The start of the bin range and valid data range for the + * histogram + * + * @param validMax The end of the bin range and valid data range for the + * histogram + * + * @param msg The message to display with the percent process while gathering + * histogram data + * + * @return (Isis::Histogram) A pointer to a Histogram object. + * + * @throws ProgrammerError Band was less than zero or more than the number + * of bands in the cube. + */ + Isis::Histogram *Cube::Histogram (const int band, const double validMin, const double validMax, std::string msg) { + // Make sure band is valid + if ((band < 0) || (band > Bands())) { + string msg = "Invalid band in [CubeInfo::Histogram]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + int bandStart = band; + int bandStop = band; + int maxSteps = Lines(); + if (band == 0){ + bandStart = 1; + bandStop = Bands(); + maxSteps = Lines() * Bands(); + } + + Isis::Progress progress; + Isis::Histogram *hist = new Isis::Histogram(*this,band,&progress); + Isis::LineManager line(*this); + + // This range is for throwing out data; the default parameters are OK always + hist->SetValidRange(validMin, validMax); + + // We now need to know the binning range - Isis::ValidMinimum/Maximum are no longer + // acceptable, default to the bin range start/end. + double binMin = validMin; + double binMax = validMax; + if(binMin == Isis::ValidMinimum) { + binMin = hist->BinRangeStart(); + } + + if(binMax == Isis::ValidMaximum) { + binMax = hist->BinRangeEnd(); + } + + hist->SetBinRange(binMin, binMax); + + // Loop and get the histogram + progress.SetText(msg); + progress.SetMaximumSteps(maxSteps); + progress.CheckStatus(); + + for (int useBand = bandStart ; useBand <= bandStop ; useBand++){ + for (int i=1; i<=Lines(); i++) { + line.SetLine(i,useBand); + Read(line); + hist->AddData (line.DoubleBuffer(),line.size()); + progress.CheckStatus(); + } + } + + return hist; + } + + /** + * Adds a group in a Label to the cube. If the group already + * exists in the cube it will be completely overwritten. + * This will only work on output cubes, therefore, input cubes will not be + * updated. + * + * @throws IsisProgrammerError The programmer attempted to overwrite the Cube + * group. + * + * @param[in] group Label containing the group to put. + */ + void Cube::PutGroup (Isis::PvlGroup &group) { + Isis::PvlObject &isiscube = Label()->FindObject("IsisCube"); + if (isiscube.HasGroup(group.Name())) { + isiscube.FindGroup(group.Name()) = group; + } + else { + isiscube.AddGroup(group); + } + } + + /** + * Read a group from the cube into a Label. If the group does not exist an + * exception will be thrown. + * + * @param[out] group Name of the group to get + * @return (Isis::PvlGroup) Label which will contain the requested group. + */ + Isis::PvlGroup &Cube::GetGroup (const std::string &group) { + Isis::PvlObject &isiscube = Label()->FindObject("IsisCube"); + return isiscube.FindGroup(group); + } + + /** + * Deletes a group from the cube labels. If the group does not + * exist nothing happens; otherwise the group is removed. + * This will only work on output cubes, therefore, input cubes + * will not be updated. + * + * @param[out] group Name of the group to delete. + */ + void Cube::DeleteGroup (const std::string &group) { + Isis::PvlObject &isiscube = Label()->FindObject("IsisCube"); + if (!isiscube.HasGroup(group)) return; + isiscube.DeleteGroup(group); + } + + /** + * Return if the cube has a specified group in the labels. + * + * @param[out] group Name of the group to check. + * + * @return (bool) True if the cube has the specified group, false if not. + */ + bool Cube::HasGroup (const std::string &group) { + Isis::PvlObject &isiscube = Label()->FindObject("IsisCube"); + if (isiscube.HasGroup(group)) return true; + return false; + } +} diff --git a/isis/src/base/objs/Cube/Cube.h b/isis/src/base/objs/Cube/Cube.h new file mode 100644 index 0000000000000000000000000000000000000000..4f45868909cf31731a818118a366472b9f6aee3d --- /dev/null +++ b/isis/src/base/objs/Cube/Cube.h @@ -0,0 +1,315 @@ +#ifndef Cube_h +#define Cube_h +/** + * @file + * $Revision: 1.17 $ + * $Date: 2010/03/22 19:44:53 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "CubeIoHandler.h" +#include "Blob.h" + +class QMutex; + +namespace Isis { + class Camera; + class Projection; + class Statistics; + class Histogram; + +/** + * @brief I/O Handler for Isis Cubes. + * + * This class is used to open, create, read, and write data from Isis cube + * files. + * + * @ingroup LowLevelCubeIO + * + * @author 2003-02-14 Jeff Anderson + * + * @internal + * @todo There are undocumented methods and private variables in the Cube + * class. Also, it needs an example. + * @history 2003-03-31 Jeff Anderson - updated unitTest truth file. + * @history 2003-05-16 Stuart Sides - modified schema from + * astrogeology...isis.astrogeology + * @history 2003-05-21 Jeff Anderson - added read/write methods to improve + * speed for IsisLine buffer managers. + * Also added error checks on reads, + * writes, and seeks. + * @history 2003-05-30 Jeff Anderson - added PhysicalBand method and updated + * unitTest. + * @history 2003-10-06 Jeff Anderson - added PVL to create method to allow for + * propagation of Pixel specifications. + * @history 2003-10-15 Jeff Anderson - fixed bad error check in PhysicalBand + * method. + * @history 2004-01-30 Jeff Anderson - added many Set methods. Major refractor + * of the class. + * @history 2004-02-12 Jeff Anderson - added pruning of the band bin group + * given the virtual band list. + * @history 2004-02-17 Jeff Anderson - modified the number of bands in the + * label if a virtual band list was given. + * @history 2004-03-01 Jeff Anderson - added ability to read Isis 2.1 cube + * format. + * @history 2004-04-01 Jeff Anderson - fixed bug swapping NULL cache tile for + * non-native cubes in move method. + * @history 2005-03-24 Jeff Anderson - Added methods to return a camera or + * projection associated with the cube. + * @history 2005-07-18 Elizabeth Ribelin - Fixed bug in method that returns a + * projection associated with the cube + * @history 2005-10-03 Elizabeth Miller - Added error check to Write(blob) + * @history 2006-02-24 Kris Becker - Made the destructor virtual to properly + * allow the class to be inherited. + * @history 2006-04-21 Jacob Danton - Modified the WriteLabel method to use + * the Pvl's format template abilities. + * @history 2006-05-17 Elizabeth Miller - Depricated CameraManger to + * CameraFactory + * @history 2006-07-10 Elizabeth Miller - Added max size preference + * @history 2006-11-28 Jeff Anderson - Fixed detached blob bug + * @history 2007-01-05 Jeff Anderson - Fixed bug when reading/writing outside + * cube + * @history 2007-02-07 Tracie Sucharski - Added ReOpen method + * @history 2008-05-09 Steven Lambright - Added Statistics, Histogram, PutGroup, + * GetGroup, DeleteGroup, HasGroup conveinience methods. Removed excess + * references to CubeInfo. + * @history 2008-05-27 Jeff Anderson - Fixed bug in open method where + * virtual bands were not handled correctly if a + * BandBin group did not exist + * @history 2008-06-09 Christopher Austin - Improved maximum cube size error + * message. + * @history 2008-06-11 Steven Lambright - Changed prototype for SetVirtualBands + * @history 2008-06-18 Christopher Austin - Fixed documentation errors + * @history 2008-08-11 Steven Lambright - Added another Statistics method + * which accepts a valid range -- also added another Histogram + * method which accepts a bin/valid range (applies both). + * @history 2008-08-11 Steven Lambright - Fixed definition of IsisCubeDef, + * problem pointed out by "novas0x2a" (Support Board Member) + * @history 2008-12-15 Steven Koechle - Added a method to delete blobs from a + * cube + * @history 2008-12-17 Steven Koechle - BlobDelete method was broken, fixed + * @history 2009-06-30 Steven Lambright - Added "HasProjection" for uniform + * projection existance test + * @history 2010-03-22 Steven Lambright - Added a mutex for reading and writing, + * which makes these methods thread safe. + * + */ + class Cube { + public: + Cube (); + virtual ~Cube (); + + void Open(const std::string &cfile, std::string access = "r"); + void ReOpen (std::string access = "r"); + void Create(const std::string &cfile); + + /** + * Returns if the cube is opened. + * + * @return bool True if the cube is opened, false if it is not. + */ + bool IsOpen () { return p_cube.stream.is_open(); }; + + /** + * Returns if the cube is opened readonly. Default more for Open method. + * + * @return bool True if the cube is opened readonly, false if it is not. + */ + bool IsReadOnly () const { return p_cube.access == IsisCubeDef::ReadOnly; }; + + /** + * Returns if the cube is opened read/write. + * + * @return bool True if the cube is opened read/write, false if it is not. + */ + bool IsReadWrite () const { return p_cube.access == IsisCubeDef::ReadWrite; }; + + void Close(const bool remove=false); + void Read(Isis::Buffer &rbuf); + void Write(Isis::Buffer &wbuf); + void Read(Isis::Blob &blob); + void Write(Isis::Blob &blob); + bool BlobDelete(std::string BlobType, std::string BlobName); + + /** + * Returns the expanded filename. + * + * @return std::string The expanded filename. + */ + inline std::string Filename() const { return p_cube.labelFile; }; + + /** + * Returns a pointer to the IsisLabel object associated with the cube. + * Modifications made to the label will be written when the file is closed if + * it was opened read-write or created. Take care not to mangle the Core Object + * as this can produce unexpected results when a new attempt is made to open + * the file. + * + * @return Isis::Pvl Pointer to the Label object associated with the cube. + */ + inline Isis::Pvl *Label() { return &p_cube.label; }; + + void SetLabelBytes (int labelBytes); + void SetDimensions (int ns, int nl, int nb); + void SetPixelType (Isis::PixelType pixelType); + void SetCubeFormat (Isis::CubeFormat cubeFormat); + void SetByteOrder (Isis::ByteOrder byteOrder); + void SetMinMax (double min, double max); + void SetBaseMultiplier (double base, double mult); + void SetAttached (); + void SetDetached (); + + /** + * Returns the number of bytes reserved for the label. + * + * @return int The number of bytes used for the label. + */ + inline int LabelBytes () const { return p_cube.labelBytes; }; + int LabelBytesUsed(); + + /** + * Returns the number of samples in the cube. + * + * @return int The number of samples in the cube. + */ + inline int Samples () const { return p_cube.samples; }; + + /** + * Returns the number of lines in the cube. + * + * @return int The number of lines in the cube. + */ + inline int Lines () const { return p_cube.lines; }; + int Bands () const; + + /** + * Returns an enumeration of the PixelType. + * @see PixelType.h + * + * return Isis::PixelType An enumeration of the PixelType. + */ + inline Isis::PixelType PixelType () const { return p_cube.pixelType; }; + + /** + * Returns an enumeration of the cube format (tiled or bsq). + * @see CubeFormat.h + * + * @return Isis::CubeFormat An enumeration of the cube format. + */ + inline Isis::CubeFormat CubeFormat () const { return p_cube.cubeFormat; }; + + /** + * Returns an enumeration of the byte order (Isb or Msb). + * @see Endian.h + * + * @return Isis::ByteOrder An enumeration of the byte order. + */ + inline Isis::ByteOrder ByteOrder () const { return p_cube.byteOrder; }; + + /** + * Returns if the cube and label data are in the same file. + * + * @return bool True if the cube and label data are in the same file, + * false if they are not. + */ + inline bool IsAttached () const { return p_cube.attached; }; + + /** + * Returns if the cube and label data are in separate files. + * + * @return bool Returns true if the cube and label data are in separate + * files, false if they are in the same file. + */ + inline bool IsDetached () const { return !p_cube.attached; }; + + /** + * Returns the base value for converting 8-bit/16-bit pixels to 32-bit. + * @f[ + * out = in * multiplier + base + * @f] + * + * @return double The base value for converting 8-bit/16-bit pixels to + * 32-bit. + */ + inline double Base () const { return p_cube.base; }; + + /** + * Returns the multiplier value for converting 8-bit/16-bit pixels to 32-bit. + * @f[ + * out = in * multiplier + base + * @f] + * + * @return double The multiplier value for converting 8-bit/16-bit pixels + * to 32-bit. + */ + inline double Multiplier () const { return p_cube.multiplier; }; + + void SetVirtualBands (const std::vector &vbands); + int PhysicalBand (const int virtualBand) const; + + bool HasProjection(); + + Isis::Camera *Camera(); + Isis::Projection *Projection(); + Isis::Statistics *Statistics(const int band = 1, std::string msg = "Gathering statistics"); + Isis::Statistics *Statistics(const int band, const double validMin, const double validMax, std::string msg = "Gathering statistics"); + Isis::Histogram *Histogram (const int band = 1, std::string msg = "Gathering histogram"); + Isis::Histogram *Histogram (const int band, const double validMin, const double validMax, std::string msg = "Gathering histogram"); + + // Change a group in the labels + void PutGroup (Isis::PvlGroup &group); + + // Return a group in a label + Isis::PvlGroup &GetGroup (const std::string &group); + + // Delete a group in the labels + void DeleteGroup (const std::string &group); + + // Check to see if a group is in the labels + bool HasGroup (const std::string &group); + + bool HasTable(const std::string &name); + + private: + IsisCubeDef p_cube; + Isis::CubeIoHandler *p_ioHandler; + + bool p_overwritePreference; + bool p_historyPreference; + bool p_attachedPreference; + BigInt p_maxSizePreference; + + void WriteLabels (); + void ReformatOldIsisLabel (const std::string &oldCube); + void OpenCheck(); + + std::vector p_virtualBandList; + void SetVirtualBands (); + + std::string p_tempCube; + std::string p_formatTemplateFile; + + Isis::Camera *p_camera; + Isis::Projection *p_projection; + + QMutex *p_mutex; + }; +}; + +#endif diff --git a/isis/src/base/objs/Cube/Cube.truth b/isis/src/base/objs/Cube/Cube.truth new file mode 100644 index 0000000000000000000000000000000000000000..cdd4c4d62d3e461492e300c423dd875851db162c --- /dev/null +++ b/isis/src/base/objs/Cube/Cube.truth @@ -0,0 +1,197 @@ +Unit test for Isis::Cube +Constructing cube ... +File = +Samps = 512 +Lines = 512 +Bands = 0 +Base = 0 +Mult = 1 +Type = 7 +Atchd = 1 +Dtchd = 0 +Format = 1 +Open = 0 +R/O = 0 +R/W = 1 +Lbytes = 65536 + +Creating 32-bit cube ... +File = /tmp/IsisCube_01.cub +Samps = 150 +Lines = 200 +Bands = 2 +Base = 0 +Mult = 1 +Type = 7 +Atchd = 1 +Dtchd = 0 +Format = 1 +Open = 1 +R/O = 0 +R/W = 1 +Lbytes = 65536 + +Write cube ... +Opening cube ... +File = /tmp/IsisCube_01.cub +Samps = 150 +Lines = 200 +Bands = 2 +Base = 0 +Mult = 1 +Type = 7 +Atchd = 1 +Dtchd = 0 +Format = 1 +Open = 1 +R/O = 1 +R/W = 0 +Lbytes = 65536 + +Comparing cube ... + +Creating 8-bit cube ... +Comparing cube ... +File = /tmp/IsisCube_02.lbl +Samps = 150 +Lines = 200 +Bands = 1 +Base = 200 +Mult = -1 +Type = 1 +Atchd = 0 +Dtchd = 1 +Format = 0 +Open = 1 +R/O = 1 +R/W = 0 +Lbytes = 419 + +Creating 16-bit cube ... +Comparing cube ... +File = /tmp/IsisCube_03.cub +Samps = 150 +Lines = 200 +Bands = 2 +Base = 30000 +Mult = -1 +Type = 4 +Atchd = 1 +Dtchd = 0 +Format = 1 +Open = 1 +R/O = 1 +R/W = 0 +Lbytes = 65536 + +Testing histogram method, band 1 ... +Computing min/max for histogram +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Gathering histogram +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Average: 14900 +Standard Dev: 8602.66 +Mode: 149.148 +Total Pixels: 30000 +Null Pixels: 0 + +Testing histogram method, all bands ... +Computing min/max for histogram +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Gathering histogram +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Average: 29800 +Standard Dev: 17205.2 +Mode: 149.148 +Total Pixels: 60000 +Null Pixels: 0 + +**PROGRAMMER ERROR** Invalid band in [CubeInfo::Histogram] +Testing statistics method, band 1 ... +Gathering statistics +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Average: 14900 +Standard Dev: 8602.66 +Total Pixels: 30000 +Null Pixels: 0 + +Testing statistics method, all bands ... +Gathering statistics +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Average: 29800 +Standard Dev: 17205.2 +Total Pixels: 60000 +Null Pixels: 0 + +**PROGRAMMER ERROR** Invalid band in [CubeInfo::Statistics] + +Virtual band tests +Nbands = 2 +Band 1 = 1 +Band 2 = 2 + +Nbands = 1 +Band 1 = 2 + +ReOpen tests +File = /tmp/IsisCube_01.cub +Samps = 150 +Lines = 200 +Bands = 1 +Base = 0 +Mult = 1 +Type = 7 +Atchd = 1 +Dtchd = 0 +Format = 1 +Open = 1 +R/O = 1 +R/W = 0 +Lbytes = 65536 + +File = /tmp/IsisCube_01.cub +Samps = 150 +Lines = 200 +Bands = 1 +Base = 0 +Mult = 1 +Type = 7 +Atchd = 1 +Dtchd = 0 +Format = 1 +Open = 1 +R/O = 0 +R/W = 1 +Lbytes = 65536 + +File = /tmp/IsisCube_01.cub +Samps = 150 +Lines = 200 +Bands = 1 +Base = 0 +Mult = 1 +Type = 7 +Atchd = 1 +Dtchd = 0 +Format = 1 +Open = 1 +R/O = 1 +R/W = 0 +Lbytes = 65536 + +Testing errors ... +**PROGRAMMER ERROR** Cube::Open - You already have [/tmp/IsisCube_01.cub] opened +**PROGRAMMER ERROR** Cube::Create - You already have [/tmp/IsisCube_01.cub] opened +**PROGRAMMER ERROR** The cube [/tmp/IsisCube_01.cub] is opened read-only ... you can't write to it +**I/O ERROR** Unable to open [blah] +**PROGRAMMER ERROR** Out of array bounds [2] +**PROGRAMMER ERROR** Out of array bounds [0] +**PROGRAMMER ERROR** Cube::Read - Try opening a file before you read it +**PROGRAMMER ERROR** Cube::Write - Try opening/creating a file before you write it +**I/O ERROR** Label space is full in [/tmp/IsisCube_04.cub] unable to write labels +**USER ERROR** The cube you are attempting to create [/tmp/IsisCube_05] is [33527GB] This is larger than the current allowed size of [12GB]. The cube dimensions were (S,L,B) [1000000, 1000000, 9] with [4] bytes per pixel. If you still wish to create this cube, the maximum value can be changed in the file [~/.Isis/IsisPreferences] within the group CubeCustomization, keyword MaximumSize. +**PROGRAMMER ERROR** Invalid value for argument [access] must be [r,rw] +**PROGRAMMER ERROR** SetDimensions: Invalid number of sample, lines or bands +**PROGRAMMER ERROR** SetDimensions: Invalid number of sample, lines or bands +**PROGRAMMER ERROR** SetDimensions: Invalid number of sample, lines or bands +**PROGRAMMER ERROR** Cannot open read/write [/usgs/cpkgs/isis3/data/base/testData/isisTruth.cub] will be opened read only diff --git a/isis/src/base/objs/Cube/CubeBsqHandler.cpp b/isis/src/base/objs/Cube/CubeBsqHandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..adc3f8d164aeb7bcdd8c4b71173bfa27ebee57f8 --- /dev/null +++ b/isis/src/base/objs/Cube/CubeBsqHandler.cpp @@ -0,0 +1,495 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2008/09/03 16:21:02 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "CubeBsqHandler.h" +#include "iException.h" +#include "SpecialPixel.h" +#include + +using namespace std; +namespace Isis { + CubeBsqHandler::CubeBsqHandler(IsisCubeDef &cube) : + Isis::CubeIoHandler(cube) { + + Isis::PvlObject &core = p_cube->label.FindObject("IsisCube").FindObject("Core"); + + if (!core.HasKeyword("Format")) { + core += Isis::PvlKeyword("Format","BandSequential"); + } + + p_tileSamples = p_cube->samples; + p_tileLines = (1024 * 1024) / (p_cube->samples * Isis::SizeOf(p_cube->pixelType)); + if (p_tileLines < 1) p_tileLines = 1; + + p_bytesPerTile = p_tileLines * p_tileSamples * Isis::SizeOf(p_cube->pixelType); + p_sampleTiles = (p_cube->samples - 1) / p_tileSamples + 1; + p_lineTiles = (p_cube->lines - 1) / p_tileLines + 1; + + // p_maxTiles = p_lineTiles; + // if (p_maxTiles < p_sampleTiles) p_maxTiles = p_sampleTiles; + // if (p_maxTiles < p_bands) p_maxTiles = p_bands; + p_maxTiles = p_cube->bands; + + p_cube->dataBytes = (streampos) p_cube->samples * + (streampos) p_cube->lines * + (streampos) p_cube->bands * + (streampos) Isis::SizeOf(p_cube->pixelType); + + p_bufList.clear(); + p_cacheList.clear(); + p_lastCache = -1; + p_nullCache.buf = NULL; + p_tileAllocated.clear(); + } + + CubeBsqHandler::~CubeBsqHandler() { + Close(); + } + + void CubeBsqHandler::Create(bool overwrite) { + Isis::CubeIoHandler::Create(overwrite); + + p_tileAllocated.resize(p_sampleTiles*p_lineTiles*p_cube->bands); + unsigned int ntiles = p_tileAllocated.size(); + for (unsigned int i=0; istream.is_open()) return; + + // Empty the cache + unsigned int listSize = p_cacheList.size(); + for (unsigned int i=0; ibuf != NULL) { + InternalCache *cache = p_cacheList[i]; + WriteCache(cache); + delete [] cache->buf; + cache->buf = NULL; + } + delete p_cacheList[i]; + p_cacheList[i] = NULL; + } + p_cacheList.clear(); + p_bufList.clear(); + + // Write any tiles which where never allocated + if (p_nullCache.buf == NULL) MakeNullCache(); + unsigned int ntiles = p_tileAllocated.size(); + for (unsigned int i=0; istream.close(); + if (removeFile) remove (p_cube->dataFile.c_str()); + } + + void CubeBsqHandler::Read(Isis::Buffer &rbuf) { + // See if the cache needs to get bigger + GrowCache(rbuf); + + // Starting corner in the Isis::Buffer + int ssamp = rbuf.Sample(); + int sline = rbuf.Line(); + int sband = rbuf.Band(); + + // Ending corner in the Isis::Buffer + int esamp = rbuf.Sample(rbuf.size()-1); + int eline = rbuf.Line(rbuf.size()-1); + int eband = rbuf.Band(rbuf.size()-1); + + // Current corner of a cache we will work on + p_sample = ssamp; + p_line = sline; + int tempBand = sband; + + InternalCache *cache; + char *rawbuf = (char *) rbuf.RawBuffer(); + int ss,es,sl,el; + + while (tempBand <= eband) { + p_band = p_cube->virtualBandList[tempBand-1]; + cache = FindCache(); + + ss = (p_sample > cache->startSamp) ? p_sample : cache->startSamp; + es = (esamp < cache->endSamp) ? esamp : cache->endSamp; + sl = (p_line > cache->startLine) ? p_line : cache->startLine; + el = (eline < cache->endLine) ? eline : cache->endLine; + + int cacheIndex = (sl - cache->startLine) * p_tileSamples + + ss - cache->startSamp; + int rawIndex = rbuf.Index(ss,sl,tempBand); + int rawAdd = rbuf.SampleDimension(); + int ns = es - ss + 1; + + for (int line = sl; line<=el; line++) { + Move(rawbuf,rawIndex,cache->buf,cacheIndex,ns); + cacheIndex += p_tileSamples; + rawIndex += rawAdd; + } + + p_sample = cache->endSamp + 1; + if (p_sample > esamp) { + p_sample = ssamp; + p_line = cache->endLine + 1; + if (p_line > eline) { + p_line = sline; + tempBand++; + } + } + } + } + + void CubeBsqHandler::Write(Isis::Buffer &wbuf) { + // Put an error check here if the access if ReadOnly + + // See if the cache needs to get bigger + GrowCache(wbuf); + + // Starting corner in the Isis::Buffer + // We don't care about pixels outside the cube + int ssamp = (wbuf.Sample() < 1) ? 1 : wbuf.Sample(); + int sline = (wbuf.Line() < 1) ? 1 : wbuf.Line(); + int sband = (wbuf.Band() < 1) ? 1 : wbuf.Band(); + + // Ending corner in the Isis::Buffer + int esamp = (wbuf.Sample(wbuf.size()-1) > p_cube->samples) ? p_cube->samples : wbuf.Sample(wbuf.size()-1); + int eline = (wbuf.Line(wbuf.size()-1) > p_cube->lines) ? p_cube->lines : wbuf.Line(wbuf.size()-1); + int eband = (wbuf.Band(wbuf.size()-1) > p_cube->bands) ? p_cube->bands : wbuf.Band(wbuf.size()-1); + + // Current corner of a cache we will work on + p_sample = ssamp; + p_line = sline; + p_band = sband; + + InternalCache *cache; + char *rawbuf = (char *) wbuf.RawBuffer(); + int ss,es,sl,el; + + while (p_band <= eband) { + cache = FindCache(); + cache->dirty = true; + + ss = (p_sample > cache->startSamp) ? p_sample : cache->startSamp; + es = (esamp < cache->endSamp) ? esamp : cache->endSamp; + sl = (p_line > cache->startLine) ? p_line : cache->startLine; + el = (eline < cache->endLine) ? eline : cache->endLine; + + int cacheIndex = (sl - cache->startLine) * p_tileSamples + + ss - cache->startSamp; + int rawIndex = wbuf.Index(ss,sl,p_band); + int rawAdd = wbuf.SampleDimension(); + int ns = es - ss + 1; + + for (int line = sl; line<=el; line++) { + Move(cache->buf,cacheIndex,rawbuf,rawIndex,ns); + cacheIndex += p_tileSamples; + rawIndex += rawAdd; + } + + p_sample = cache->endSamp + 1; + if (p_sample > esamp) { + p_sample = ssamp; + p_line = cache->endLine + 1; + if (p_line > eline) { + p_line = sline; + p_band++; + } + } + } + } + + void CubeBsqHandler::GrowCache(const Isis::Buffer &buf) { + // The old method created a new cache for every new buffer used + // on a cube +#if 0 + if (p_nullCache.buf == NULL) MakeNullCache(); + + for (unsigned int i=0; ibuf = NULL; + p_cacheList.push_back(cache); + } +#endif + + // The new method makes six tiles sets worth of caches total. + // Six was used to ensure large highpass filters don't thrash + if (p_nullCache.buf != NULL) return; + MakeNullCache(); + for (int j=0; j<3; j++) { + for (int i=0; ibuf = NULL; + p_cacheList.push_back(cache); + } + } + } + + CubeBsqHandler::InternalCache *CubeBsqHandler::FindCache () { + // See if its outside the image + if ((p_sample < 1) || (p_line < 1) || (p_band < 1) || + (p_sample > p_cube->samples) || (p_line > p_cube->lines) || + (p_band > p_cube->bands)) { + + if (p_sample <= 0) { + p_nullCache.startSamp = (p_sample - p_tileSamples) / p_tileSamples * p_tileSamples + 1; + } + else { + p_nullCache.startSamp = (p_sample - 1) / p_tileSamples * p_tileSamples + 1; + } + + if (p_line <= 0) { + p_nullCache.startLine = (p_line - p_tileLines) / p_tileLines * p_tileLines + 1; + } + else { + p_nullCache.startLine = (p_line - 1) / p_tileLines * p_tileLines + 1; + } + + p_nullCache.endSamp = p_nullCache.startSamp + p_tileSamples - 1; + p_nullCache.endLine = p_nullCache.startLine + p_tileLines - 1; + + p_nullCache.band = p_band; + p_nullCache.dirty = false; + return &p_nullCache; + } + + // Look through the cache list to see if we already have the cache + // but check the last cache first + if (p_lastCache >= 0) { + InternalCache *cache; + int next = p_lastCache; + int count = p_cacheList.size(); + for (int i=0; ibuf != NULL) { + if ((p_sample >= cache->startSamp) && (p_sample <= cache->endSamp) && + (p_line >= cache->startLine) && (p_line <= cache->endLine) && + (p_band == cache->band)) { + p_lastCache = next; + return cache; + } + } + next++; + if (next >= count) next = 0; + } + } + + // Ok its not in the cache see if there is an open slot + InternalCache *cache = NULL; + unsigned int listSize = p_cacheList.size(); + for (unsigned int i=0; ibuf == NULL) { + cache = p_cacheList[i]; + cache->buf = new char [p_bytesPerTile]; + cache->dirty = false; + p_lastCache = i; + break; + } + } + + // If there are no open slots so chose one to get rid of + if (cache == NULL) { + p_lastCache++; + if (p_lastCache >= (int)p_cacheList.size()) p_lastCache = 0; + cache = p_cacheList[p_lastCache]; + } + + // Write out the tile + WriteCache(cache); + + // Set up for reading the tile + cache->startSamp = (p_sample - 1) / p_tileSamples * p_tileSamples + 1; + cache->startLine = (p_line - 1) / p_tileLines * p_tileLines + 1; + cache->endSamp = cache->startSamp + p_tileSamples - 1; + cache->endLine = cache->startLine + p_tileLines - 1; + if (cache->endLine > p_cube->lines) cache->endLine = p_cube->lines; + cache->band = p_band; + cache->dirty = false; + + int startTile = (cache->band - 1) * p_sampleTiles * p_lineTiles + + (cache->startLine - 1) / p_tileLines * p_sampleTiles + + (cache->startSamp - 1) / p_tileSamples + 1; + + // If this cube is being created the tile may not exist so we + // shouldn't try to read it + if (p_tileAllocated.size() > 0) { + if (!p_tileAllocated[startTile-1]) { + memmove(cache->buf,p_nullCache.buf,p_bytesPerTile); + p_tileAllocated[startTile-1] = true; + cache->dirty = true; + return cache; + } + } + + // Ok looks like we need to read the tile + streampos sbyte = (streampos) (p_cube->startByte - 1) + + (streampos) (cache->band - 1) * + (streampos) (p_cube->lines) * + (streampos) (p_cube->samples * Isis::SizeOf(p_cube->pixelType)) + + (streampos)(cache->startLine - 1) * + (streampos)(p_cube->samples * Isis::SizeOf(p_cube->pixelType)); + + p_cube->stream.seekg(sbyte,std::ios::beg); + if (!p_cube->stream.good()) { + string msg = "Error preparing to read data from cube"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + int bytes = (streampos)(cache->endLine - cache->startLine + 1) * + (streampos)(cache->endSamp - cache->startSamp + 1) * + (streampos)Isis::SizeOf(p_cube->pixelType); + p_cube->stream.read(cache->buf,bytes); + if (!p_cube->stream.good()) { + string msg = "Error reading data from cube"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // We have a cache containing the line sample + return cache; + } + + void CubeBsqHandler::Move(char *dest, int dindex, + char *src, int sindex, + int nelements) { + // Don't change the null cache + if (dest == p_nullCache.buf) return; + + int nbytes = Isis::SizeOf(p_cube->pixelType); + if ((p_native) || (nbytes == 1) || (!p_native && (src == p_nullCache.buf))) { + memmove(&dest[dindex*nbytes],&src[sindex*nbytes],nelements*nbytes); + } + else if (nbytes == 2) { + int d = dindex*nbytes; + int s = sindex*nbytes; + for (int i=0; ipixelType == Isis::UnsignedByte) { + ((unsigned char *)p_nullCache.buf)[i] = Isis::NULL1; + } + else if (p_cube->pixelType == Isis::SignedWord) { + ((short *)p_nullCache.buf)[i] = Isis::NULL2; + } + else if (p_cube->pixelType == Isis::Real) { + ((float *)p_nullCache.buf)[i] = Isis::NULL4; + } + else { + string msg = "Unsupported pixel type"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + } + + void CubeBsqHandler::WriteCache (CubeBsqHandler::InternalCache *cache) { + // Do nothing if the cache isn't dirty + if (!cache->dirty) return; + + // Otherwise compute sbyte and number of bytes to write + streampos sbyte = (streampos) (p_cube->startByte - 1) + + (streampos) (cache->band - 1) * + (streampos) (p_cube->lines) * + (streampos) (p_cube->samples * Isis::SizeOf(p_cube->pixelType)) + + (streampos)(cache->startLine - 1) * + (streampos)(p_cube->samples * Isis::SizeOf(p_cube->pixelType)); + + streamsize nbytes = (streamsize)(cache->endLine - cache->startLine + 1) * + (streamsize)(cache->endSamp - cache->startSamp + 1) * + (streamsize)Isis::SizeOf(p_cube->pixelType); + + WriteBuf(cache->buf,sbyte,nbytes); + } + + void CubeBsqHandler::WriteTile (char *buf, int tile) { + int tilesPerBand = (p_tileAllocated.size() - 1) / p_cube->bands + 1; + int band = (tile - 1) / tilesPerBand + 1; + + streampos sbyte = (streampos) (p_cube->startByte - 1) + + (streampos) (band - 1) * + (streampos) (p_cube->lines) * + (streampos) (p_cube->samples * Isis::SizeOf(p_cube->pixelType)); + + int relativeTile = (tile - (band - 1) * tilesPerBand); + sbyte += (relativeTile - 1) * p_bytesPerTile; + + streamsize nbytes; + if (relativeTile == tilesPerBand) { + int lines = p_cube->lines - (relativeTile - 1) * p_tileLines; + nbytes = (streamsize) lines * + (streamsize) (p_cube->samples * Isis::SizeOf(p_cube->pixelType)); + } + else { + nbytes = p_bytesPerTile; + } + + WriteBuf(buf,sbyte,nbytes); + } + + void CubeBsqHandler::WriteBuf (char *buf, std::streampos sbyte, std::streamsize nbytes) { + p_cube->stream.seekp(sbyte,std::ios::beg); + if (!p_cube->stream.good()) { + string msg = "Error preparing to write data to cube"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + p_cube->stream.write(buf,nbytes); + if (!p_cube->stream.good()) { + string msg = "Error writing data to cube"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } +} diff --git a/isis/src/base/objs/Cube/CubeBsqHandler.h b/isis/src/base/objs/Cube/CubeBsqHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..f9c5ff21b29ffb690246a0f3c309cfb8d807ea32 --- /dev/null +++ b/isis/src/base/objs/Cube/CubeBsqHandler.h @@ -0,0 +1,99 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/09/03 16:21:02 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#if !defined(CubeBsqHandler_h) +#define CubeBsqHandler_h + +#include "CubeIoHandler.h" + +namespace Isis { +/** + * @internal + * @todo CubeBsqHandler doesn't have any documentation. + * + * @brief I/O Handler for Isis Cubes using the BSQ format. + * + * This class is used to open, create, read, and write data from Isis cube + * files. + * + * @ingroup LowLevelCubeIO + * + * @author 2003-02-14 Jeff Anderson + * + * @internal + * @history 2007-09-14 Stuart Sides - Fixed bug where pixels + * from a buffer outside the ns/nl were being + * transfered to the right most and bottom most tiles + * @history 2007-10-11 Stuart Sides - Fixed bug introduced with + * previous bug fix. + * @history 2008-09-03 Steven Lambright - Fixed MSB/LSB problem with + * the Move(...) method + */ + class CubeBsqHandler : public Isis::CubeIoHandler { + public: + CubeBsqHandler(IsisCubeDef &cube); + ~CubeBsqHandler(); + void Close(const bool remove=false); + void Read(Isis::Buffer &rbuf); + void Write(Isis::Buffer &wbuf); + void Create(bool overwrite); + + private: + class InternalCache { + public: + bool dirty; + int startLine,startSamp; + int endLine,endSamp; + int band; + char *buf; + }; + + int p_tileSamples; + int p_tileLines; + std::vector p_tileAllocated; + + int p_bytesPerTile; + int p_sampleTiles; + int p_lineTiles; + int p_maxTiles; + std::vector p_bufList; + std::vector p_cacheList; + InternalCache p_nullCache; + int p_lastCache; + + int p_sample; + int p_line; + int p_band; + + void GrowCache (const Isis::Buffer &buf); + InternalCache *FindCache(); + void Move(char *dest, int dindex, + char *src, int sindex, int nelements); + void WriteCache (InternalCache *cache); + void WriteTile (char *buf, int tile); + void WriteBuf (char *buf, std::streampos sbyte, std::streamsize nbytes); + void MakeNullCache (); + + }; +}; + +#endif diff --git a/isis/src/base/objs/Cube/CubeDef.h b/isis/src/base/objs/Cube/CubeDef.h new file mode 100644 index 0000000000000000000000000000000000000000..d8a73ee699e36706ac4d6cd914bc9af6c2110891 --- /dev/null +++ b/isis/src/base/objs/Cube/CubeDef.h @@ -0,0 +1,66 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/10/30 16:52:30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisCubeDef_h +#define IsisCubeDef_h + +#include +#include +#include +#include + +#include "Constants.h" +#include "Pvl.h" +#include "PixelType.h" +#include "Endian.h" +#include "CubeFormat.h" + +struct IsisCubeDef { + std::string labelFile; + Isis::Pvl label; + int labelBytes; + bool attached; + bool history; + + std::string dataFile; + Isis::BigInt startByte; + std::fstream stream; + enum Access { ReadOnly, ReadWrite } access; + + int samples; + int lines; + int bands; + Isis::PixelType pixelType; + Isis::CubeFormat cubeFormat; + + Isis::ByteOrder byteOrder; + + double base; + double multiplier; + + std::vector virtualBandList; + + std::streampos dataBytes; +}; + +#endif diff --git a/isis/src/base/objs/Cube/CubeFormat.h b/isis/src/base/objs/Cube/CubeFormat.h new file mode 100644 index 0000000000000000000000000000000000000000..cb5493fa5e918ff8977c356af166e13eea996705 --- /dev/null +++ b/isis/src/base/objs/Cube/CubeFormat.h @@ -0,0 +1,54 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#if !defined(CubeFormat_h) +#define CubeFormat_h + +#include "iException.h" + +namespace Isis { + enum CubeFormat { + Bsq, + Tile + }; + + inline std::string CubeFormatName (CubeFormat cubeFormat) { + if (cubeFormat == Tile) return "Tile"; + if (cubeFormat == Bsq) return "BandSequential"; + + std::string msg = "Invalid cube format name [" + Isis::iString(cubeFormat) + "]"; + throw Isis::iException::Message(Isis::iException::Parse,msg, _FILEINFO_); + } + + inline CubeFormat CubeFormatEnumeration(const std::string &cubeFormat) { + Isis::iString temp(cubeFormat); + temp = temp.UpCase(); + if (temp == "TILE") return Tile; + if (temp == "BSQ") return Bsq; + if (temp == "BANDSEQUENTIAL") return Bsq; + + std::string msg = "Invalid cube format string [" + cubeFormat + "]"; + throw Isis::iException::Message(Isis::iException::Parse,msg, _FILEINFO_); + } +} + +#endif diff --git a/isis/src/base/objs/Cube/CubeIoHandler.cpp b/isis/src/base/objs/Cube/CubeIoHandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ab1e24c29e301dda35d6d6283c35b33cfd55e5a --- /dev/null +++ b/isis/src/base/objs/Cube/CubeIoHandler.cpp @@ -0,0 +1,261 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "CubeIoHandler.h" +#include "iString.h" +#include "PixelType.h" +#include "iException.h" +#include "iException.h" +#include "SpecialPixel.h" +#include "Endian.h" + +using namespace std; +namespace Isis { + CubeIoHandler::CubeIoHandler(IsisCubeDef &cube) { + p_cube = &cube; + if (p_cube->byteOrder == Isis::Msb) { + p_native = Isis::IsBigEndian(); + } + else { + p_native = Isis::IsLittleEndian(); + } + } + + CubeIoHandler::~CubeIoHandler() { + if (p_cube->stream.is_open()) { + p_cube->stream.close(); + } + } + + void CubeIoHandler::Open() { + // Attempt to open the file + ios::openmode flags = std::ios::in | std::ios::binary; + if (p_cube->access == IsisCubeDef::ReadWrite) flags |= std::ios::out; + p_cube->stream.clear(); + p_cube->stream.open(p_cube->dataFile.c_str(),flags); + if (!p_cube->stream) { + string message = "Unable to open cube data file [" + + p_cube->dataFile + "]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + void CubeIoHandler::Create(bool overwrite) { + // If we are not allowed to overwrite then complain if the file exists + if (!overwrite) { + ios::openmode flags = std::ios::in | std::ios::binary; + p_cube->stream.open(p_cube->dataFile.c_str(),flags); + if (p_cube->stream) { + p_cube->stream.close(); + string msg = "Cube file [" + p_cube->dataFile + "] exists, " + + "user preference does not allow overwrite"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + + // Attempt to create the file + p_cube->stream.clear(); + ios::openmode flags = std::ios::in | std::ios::binary | std::ios::out | + std::ios::trunc; + p_cube->stream.open(p_cube->dataFile.c_str(),flags); + if (!p_cube->stream) { + string message = "Unable to open data file [" + p_cube->dataFile + "]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + + // Zero out label area + if (p_cube->startByte > 1) { + char *temp = new char[p_cube->startByte - 1]; + memset(temp,0,p_cube->startByte-1); + p_cube->stream.seekp(0,std::ios::beg); + p_cube->stream.write(temp,p_cube->startByte - 1); + delete [] temp; + } + } + + void CubeIoHandler::ToDouble(Isis::Buffer &rbuf) { + if (rbuf.PixelType() == Isis::UnsignedByte) { + double *dbuf = rbuf.DoubleBuffer(); + unsigned char *cbuf = (unsigned char *) rbuf.RawBuffer(); + for (int i=0; imultiplier + p_cube->base; + } + } + } + else if (rbuf.PixelType() == Isis::SignedWord) { + double *dbuf = rbuf.DoubleBuffer(); + short int *sbuf = (short *) rbuf.RawBuffer(); + for (int i=0; imultiplier + p_cube->base; + } + } + } + else { + double *dbuf = rbuf.DoubleBuffer(); + float *fbuf = (float *) rbuf.RawBuffer(); + for (int i=0; ibase) / p_cube->multiplier; + if (temp < Isis::VALID_MIN1 - 0.5) { + cbuf[i] = Isis::LOW_REPR_SAT1; + } + else if (temp > Isis::VALID_MAX1 + 0.5) { + cbuf[i] = Isis::HIGH_REPR_SAT1; + } + else { + int itemp = (int) (temp + 0.5); + if (itemp < Isis::VALID_MIN1) { + cbuf[i] = Isis::LOW_REPR_SAT1; + } + else if (itemp > Isis::VALID_MAX1) { + cbuf[i] = Isis::HIGH_REPR_SAT1; + } + else { + cbuf[i] = (unsigned char) (temp + 0.5); + } + } + } + } + } + else if (rbuf.PixelType() == Isis::SignedWord) { + double *dbuf = rbuf.DoubleBuffer(); + short *sbuf = (short *) rbuf.RawBuffer(); + double temp; + for (int i=0; ibase) / p_cube->multiplier; + if (temp < Isis::VALID_MIN2 - 0.5) { + sbuf[i] = Isis::LOW_REPR_SAT2; + } + if (temp > Isis::VALID_MAX2 + 0.5) { + sbuf[i] = Isis::HIGH_REPR_SAT2; + } + else { + int itemp; + if (temp < 0.0) { + itemp = (int) (temp - 0.5); + } + else { + itemp = (int) (temp + 0.5); + } + + if (itemp < Isis::VALID_MIN2) { + sbuf[i] = Isis::LOW_REPR_SAT2; + } + else if (itemp > Isis::VALID_MAX2) { + sbuf[i] = Isis::HIGH_REPR_SAT2; + } + else if (temp < 0.0) { + sbuf[i] = (short) (temp - 0.5); + } + else { + sbuf[i] = (short) (temp + 0.5); + } + } + } + } + } + else { + double *dbuf = rbuf.DoubleBuffer(); + float *fbuf = (float *) rbuf.RawBuffer(); + double temp; + for (int i=0; ibase) / p_cube->multiplier; + if (temp < (double) Isis::VALID_MIN4) { + fbuf[i] = Isis::LOW_REPR_SAT4; + } + else if (temp > (double) Isis::VALID_MAX4) { + fbuf[i] = Isis::HIGH_REPR_SAT4; + } + else { + fbuf[i] = (float) temp; + } + } + } + } + } +} diff --git a/isis/src/base/objs/Cube/CubeIoHandler.h b/isis/src/base/objs/Cube/CubeIoHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..bd46ffb35c99b9753255da922b46205f73aa70c7 --- /dev/null +++ b/isis/src/base/objs/Cube/CubeIoHandler.h @@ -0,0 +1,75 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#if !defined(CubeIoHandler_h) +#define CubeIoHandler_h + +#include "CubeDef.h" +#include "Buffer.h" +#include "Constants.h" + +namespace Isis { +/** + * @brief Pixel value mapper + * + * This class is used to stretch or remap pixel values. For example, it can be + * used to apply contrast stretches, color code stretches, or remap from a + * double range to 8-bit (0 to 255). The methodology used is straightforward. + * The program must set up a list of stretch pairs, input-to-output mappings, + * using the AddPair method. For example, (0,0) and (1,255) are two pairs which + * would cause an input of 0 to be mapped to 0, 0.5 would be mapped to 127.5 + * and 1 would be mapped to 255. More than two pairs can be used which + * generates piece-wise linear mappings. Special pixels are mapped to themselves + * unless overridden with methods such as SetNull. Input values outside the + * minimum and maximum input pair values are mapped to LRS and HRS respectively. + * + * If you would like to see Stretch being used in implementation, + * see stretch.cpp + * + * @ingroup Low Level Cube I/O + * + * @author ??? + * + * @internal + * @history 2006-06-12 Tracie Sucharski - Clear stream bits before opening + * cube. + */ + class CubeIoHandler { + public: + CubeIoHandler(IsisCubeDef &cube); + virtual ~CubeIoHandler(); + void Open(); + virtual void Create(bool overwrite); + virtual void Close(const bool remove=false) = 0; + virtual void Read(Isis::Buffer &rbuf) = 0; + virtual void Write(Isis::Buffer &wbuf) = 0; + void ToDouble(Isis::Buffer &buf); + void ToRaw(Isis::Buffer &buf); + + protected: + IsisCubeDef *p_cube; + bool p_native; + }; +}; + +#endif diff --git a/isis/src/base/objs/Cube/CubeTileHandler.cpp b/isis/src/base/objs/Cube/CubeTileHandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..55c921eab19a98ba89d556bd83d838df03c4b785 --- /dev/null +++ b/isis/src/base/objs/Cube/CubeTileHandler.cpp @@ -0,0 +1,467 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2007/09/14 16:44:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "CubeTileHandler.h" +#include "iException.h" +#include "SpecialPixel.h" +#include + +using namespace std; +namespace Isis { + CubeTileHandler::CubeTileHandler(IsisCubeDef &cube) : + Isis::CubeIoHandler(cube) { + + + Isis::PvlObject &core = p_cube->label.FindObject("IsisCube").FindObject("Core"); + + if (core.HasKeyword("Format")) { + p_tileSamples = core["TileSamples"]; + p_tileLines = core["TileLines"]; + } + else { + core += Isis::PvlKeyword("Format","Tile"); + p_tileSamples = 128; + p_tileLines = 128; + core += Isis::PvlKeyword("TileSamples",p_tileSamples); + core += Isis::PvlKeyword("TileLines",p_tileLines); + } + + p_bytesPerTile = p_tileLines * p_tileSamples * Isis::SizeOf(p_cube->pixelType); + p_sampleTiles = (p_cube->samples - 1) / p_tileSamples + 1; + p_lineTiles = (p_cube->lines - 1) / p_tileLines + 1; + + p_maxTiles = p_lineTiles; + if (p_maxTiles < p_sampleTiles) p_maxTiles = p_sampleTiles; + if (p_maxTiles < p_cube->bands) p_maxTiles = p_cube->bands; + + p_cube->dataBytes = (streampos) p_sampleTiles * + (streampos) p_lineTiles * + (streampos) p_cube->bands * + (streampos) p_bytesPerTile; + + p_bufList.clear(); + p_cacheList.clear(); + p_lastCache = -1; + p_nullCache.buf = NULL; + p_tileAllocated.clear(); + } + + CubeTileHandler::~CubeTileHandler() { + Close(); + } + + void CubeTileHandler::Create(bool overwrite) { + Isis::CubeIoHandler::Create(overwrite); + + p_tileAllocated.resize(p_sampleTiles*p_lineTiles*p_cube->bands); + unsigned int ntiles = p_tileAllocated.size(); + for (unsigned int i=0; istream.is_open()) return; + + // Empty the cache + unsigned int listSize = p_cacheList.size(); + for (unsigned int i=0; ibuf != NULL) { + InternalCache *cache = p_cacheList[i]; + WriteCache(cache); + delete [] cache->buf; + cache->buf = NULL; + } + delete p_cacheList[i]; + p_cacheList[i] = NULL; + } + p_cacheList.clear(); + p_bufList.clear(); + + // Write any tiles which where never allocated + if (p_nullCache.buf == NULL) MakeNullCache(); + unsigned int ntiles = p_tileAllocated.size(); + for (unsigned int i=0; istream.close(); + if (removeFile) remove (p_cube->dataFile.c_str()); + } + + void CubeTileHandler::Read(Isis::Buffer &rbuf) { + // See if the cache needs to get bigger + GrowCache(rbuf); + + // Starting corner in the Isis::Buffer + int ssamp = rbuf.Sample(); + int sline = rbuf.Line(); + int sband = rbuf.Band(); + + // Ending corner in the Isis::Buffer + int esamp = rbuf.Sample(rbuf.size()-1); + int eline = rbuf.Line(rbuf.size()-1); + int eband = rbuf.Band(rbuf.size()-1); + + // Current corner of a cache we will work on + p_sample = ssamp; + p_line = sline; + int tempBand = sband; + + InternalCache *cache; + char *rawbuf = (char *) rbuf.RawBuffer(); + int ss,es,sl,el; + + while (tempBand <= eband) { + p_band = p_cube->virtualBandList[tempBand-1]; + cache = FindCache(); + + ss = (p_sample > cache->startSamp) ? p_sample : cache->startSamp; + es = (esamp < cache->endSamp) ? esamp : cache->endSamp; + sl = (p_line > cache->startLine) ? p_line : cache->startLine; + el = (eline < cache->endLine) ? eline : cache->endLine; + + // Don't worry about fixing the NULL cache index since everything is + // NULL in the buffer + int cacheIndex = (sl - cache->startLine) * p_tileSamples + + ss - cache->startSamp; + int rawIndex = rbuf.Index(ss,sl,tempBand); + int rawAdd = rbuf.SampleDimension(); + int ns = es - ss + 1; + + for (int line = sl; line<=el; line++) { + Move(rawbuf,rawIndex,cache->buf,cacheIndex,ns); + cacheIndex += p_tileSamples; + rawIndex += rawAdd; + } + + p_sample = cache->endSamp + 1; + if (p_sample > esamp) { + p_sample = ssamp; + p_line = cache->endLine + 1; + if (p_line > eline) { + p_line = sline; + tempBand++; + } + } + } + } + + void CubeTileHandler::Write(Isis::Buffer &wbuf) { + // Put an error check here if the access is ReadOnly + + // See if the cache needs to get bigger + GrowCache(wbuf); + + // Starting corner in the Isis::Buffer + // We don't care about pixels outside the cube + int ssamp = (wbuf.Sample() < 1) ? 1 : wbuf.Sample(); + int sline = (wbuf.Line() < 1) ? 1 : wbuf.Line(); + int sband = (wbuf.Band() < 1) ? 1 : wbuf.Band(); + + // Ending corner in the Isis::Buffer + int esamp = (wbuf.Sample(wbuf.size()-1) > p_cube->samples) ? p_cube->samples : wbuf.Sample(wbuf.size()-1); + int eline = (wbuf.Line(wbuf.size()-1) > p_cube->lines) ? p_cube->lines : wbuf.Line(wbuf.size()-1); + int eband = (wbuf.Band(wbuf.size()-1) > p_cube->bands) ? p_cube->bands : wbuf.Band(wbuf.size()-1); + + // Current corner of a cache we will work on + p_sample = ssamp; + p_line = sline; + p_band = sband; + + InternalCache *cache; + char *rawbuf = (char *) wbuf.RawBuffer(); + int ss,es,sl,el; + + while (p_band <= eband) { + cache = FindCache(); + cache->dirty = true; + + // Find the samples/lines/bands that are in this cache + ss = (p_sample > cache->startSamp) ? p_sample : cache->startSamp; + es = (esamp < cache->endSamp) ? esamp : cache->endSamp; + sl = (p_line > cache->startLine) ? p_line : cache->startLine; + el = (eline < cache->endLine) ? eline : cache->endLine; + + // Don't worry about fixing the NULL cache index since everything is + // NULL in the buffer + int cacheIndex = (sl - cache->startLine) * p_tileSamples + + ss - cache->startSamp; + int rawIndex = wbuf.Index(ss,sl,p_band); + int rawAdd = wbuf.SampleDimension(); + int ns = es - ss + 1; + + for (int line = sl; line<=el; line++) { + Move(cache->buf,cacheIndex,rawbuf,rawIndex,ns); + cacheIndex += p_tileSamples; + rawIndex += rawAdd; + } + + p_sample = cache->endSamp + 1; + if (p_sample > esamp) { + p_sample = ssamp; + p_line = cache->endLine + 1; + if (p_line > eline) { + p_line = sline; + p_band++; + } + } + } + } + + void CubeTileHandler::GrowCache(const Isis::Buffer &buf) { + // The old method created a new cache for every new buffer used + // on a cube +#if 0 + if (p_nullCache.buf == NULL) MakeNullCache(); + + for (unsigned int i=0; ibuf = NULL; + p_cacheList.push_back(cache); + } +#endif + + // The new method makes six tiles sets worth of caches total. + // Six was used to ensure large highpass filters don't thrash + if (p_nullCache.buf != NULL) return; + MakeNullCache(); + for (int j=0; j<6; j++) { + for (int i=0; ibuf = NULL; + p_cacheList.push_back(cache); + } + } + } + + CubeTileHandler::InternalCache *CubeTileHandler::FindCache () { + // See if its outside the image + if ((p_sample < 1) || (p_line < 1) || (p_band < 1) || + (p_sample > p_cube->samples) || (p_line > p_cube->lines) || (p_band > p_cube->bands)) { + + if (p_sample <= 0) { + p_nullCache.startSamp = (p_sample - p_tileSamples) / p_tileSamples * p_tileSamples + 1; + } + else { + p_nullCache.startSamp = (p_sample - 1) / p_tileSamples * p_tileSamples + 1; + } + + if (p_line <= 0) { + p_nullCache.startLine = (p_line - p_tileLines) / p_tileLines * p_tileLines + 1; + } + else { + p_nullCache.startLine = (p_line - 1) / p_tileLines * p_tileLines + 1; + } + + p_nullCache.endSamp = p_nullCache.startSamp + p_tileSamples - 1; + p_nullCache.endLine = p_nullCache.startLine + p_tileLines - 1; + + p_nullCache.band = p_band; + p_nullCache.dirty = false; + return &p_nullCache; + } + + // Look through the cache list to see if we already have the cache + // but check the last cache first + if (p_lastCache >= 0) { + InternalCache *cache; + int next = p_lastCache; + int count = p_cacheList.size(); + for (int i=0; ibuf != NULL) { + if ((p_sample >= cache->startSamp) && (p_sample <= cache->endSamp) && + (p_line >= cache->startLine) && (p_line <= cache->endLine) && + (p_band == cache->band)) { + p_lastCache = next; + return cache; + } + } + next++; + if (next >= count) next = 0; + } + } + + // Ok its not in the cache see if there is an open slot + InternalCache *cache = NULL; + unsigned int listSize = p_cacheList.size(); + for (unsigned int i=0; ibuf == NULL) { + cache = p_cacheList[i]; + cache->buf = new char [p_bytesPerTile]; + cache->dirty = false; + p_lastCache = i; + break; + } + } + + // If there are no open slots so chose one to get rid of + if (cache == NULL) { + p_lastCache++; + if (p_lastCache >= (int)p_cacheList.size()) p_lastCache = 0; + cache = p_cacheList[p_lastCache]; + } + + // Write out the tile + WriteCache(cache); + + // Set up for reading the tile + cache->startSamp = (p_sample - 1) / p_tileSamples * p_tileSamples + 1; + cache->startLine = (p_line - 1) / p_tileLines * p_tileLines + 1; + cache->endSamp = cache->startSamp + p_tileSamples - 1; + cache->endLine = cache->startLine + p_tileLines - 1; + cache->band = p_band; + cache->dirty = false; + + int startTile = (cache->band - 1) * p_sampleTiles * p_lineTiles + + (cache->startLine - 1) / p_tileLines * p_sampleTiles + + (cache->startSamp - 1) / p_tileSamples + 1; + + // If this cube is being created the tile may not exist so we + // shouldn't try to read it + if (p_tileAllocated.size() > 0) { + if (!p_tileAllocated[startTile-1]) { + memmove(cache->buf,p_nullCache.buf,p_bytesPerTile); + p_tileAllocated[startTile-1] = true; + cache->dirty = true; + return cache; + } + } + + // Ok looks like we need to read the tile + streampos sbyte = (streampos) (p_cube->startByte - 1) + + (streampos) (startTile - 1) * (streampos) p_bytesPerTile; + p_cube->stream.seekg(sbyte,std::ios::beg); + if (!p_cube->stream.good()) { + string msg = "Error preparing to read data from cube"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + int bytes = p_bytesPerTile; + p_cube->stream.read(cache->buf,bytes); + if (!p_cube->stream.good()) { + string msg = "Error reading data from cube"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // We have a cache containing the line sample + return cache; + } + + void CubeTileHandler::Move(char *dest, int dindex, + char *src, int sindex, + int nelements) { + // Don't change the null cache + if (dest == p_nullCache.buf) return; + + int nbytes = Isis::SizeOf(p_cube->pixelType); + if ((p_native) || (nbytes == 1) || (!p_native && (src == p_nullCache.buf))) { + memmove(&dest[dindex*nbytes],&src[sindex*nbytes],nelements*nbytes); + } + else if (nbytes == 2) { + int d = dindex*nbytes; + int s = sindex*nbytes; + for (int i=0; ipixelType == Isis::UnsignedByte) { + ((unsigned char *)p_nullCache.buf)[i] = Isis::NULL1; + } + else if (p_cube->pixelType == Isis::SignedWord) { + ((short *)p_nullCache.buf)[i] = Isis::NULL2; + } + else if (p_cube->pixelType == Isis::Real) { + ((float *)p_nullCache.buf)[i] = Isis::NULL4; + } + else { + string msg = "Unsupported pixel type"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + + } + + void CubeTileHandler::WriteCache (CubeTileHandler::InternalCache *cache) { + // Do nothing if the cache isn't dirty + if (!cache->dirty) return; + + // Otherwise compute tile number and write it + int tile = (cache->band - 1) * p_sampleTiles * p_lineTiles + + (cache->startLine - 1) / p_tileLines * p_sampleTiles + + (cache->startSamp - 1) / p_tileSamples + 1; + WriteTile(cache->buf,tile); + } + + void CubeTileHandler::WriteTile (char *buf, int tile) { + streampos sbyte = (streampos)(p_cube->startByte - 1) + + (streampos)(tile - 1) * (streampos)p_bytesPerTile; + p_cube->stream.seekp(sbyte,std::ios::beg); + if (!p_cube->stream.good()) { + string msg = "Error preparing to write data to cube"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + int bytes = p_bytesPerTile; + p_cube->stream.write(buf,bytes); + if (!p_cube->stream.good()) { + string msg = "Error writing data to cube"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } +} diff --git a/isis/src/base/objs/Cube/CubeTileHandler.h b/isis/src/base/objs/Cube/CubeTileHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..0aebf8775f8db8d82d51d703d15e730677e6e104 --- /dev/null +++ b/isis/src/base/objs/Cube/CubeTileHandler.h @@ -0,0 +1,95 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/09/03 16:21:02 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef CubeTileHandler_h +#define CubeTileHandler_h + +#include "CubeIoHandler.h" + +namespace Isis { + +/** + * @brief I/O Handler for Isis Cubes using the tile format. + * + * This class is used to open, create, read, and write data from Isis cube + * files. + * + * @ingroup LowLevelCubeIO + * + * @author 2003-02-14 Jeff Anderson + * + * @internal + * @history 2007-09-14 Stuart Sides - Fixed bug where pixels + * from a buffer outside the ns/nl were being + * transfered to the right most and bottom most tiles + */ + + + class CubeTileHandler : public Isis::CubeIoHandler { + public: + CubeTileHandler(IsisCubeDef &cube); + ~CubeTileHandler(); + void Close(const bool remove=false); + void Read(Isis::Buffer &rbuf); + void Write(Isis::Buffer &wbuf); + void Create(bool overwrite); + + private: + class InternalCache { + public: + bool dirty; + int startLine,startSamp; + int endLine,endSamp; + int band; + char *buf; + }; + + int p_tileSamples; + int p_tileLines; + std::vector p_tileAllocated; + + int p_bytesPerTile; + int p_sampleTiles; + int p_lineTiles; + int p_maxTiles; + std::vector p_bufList; + std::vector p_cacheList; + InternalCache p_nullCache; + int p_lastCache; + + int p_sample; + int p_line; + int p_band; + + void GrowCache (const Isis::Buffer &buf); + InternalCache *FindCache(); + void Move(char *dest, int dindex, + char *src, int sindex, int nelements); + void WriteCache (InternalCache *cache); + void WriteTile (char *buf, int tile); + void MakeNullCache (); + + }; +}; + +#endif diff --git a/isis/src/base/objs/Cube/Makefile b/isis/src/base/objs/Cube/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0e0ab072c79e58073e853a53ba0f262c4bc2631e --- /dev/null +++ b/isis/src/base/objs/Cube/Makefile @@ -0,0 +1,7 @@ +INCS = Cube.h CubeBsqHandler.h CubeDef.h CubeFormat.h CubeIoHandler.h CubeTileHandler.h + +SRCS = CubeBsqHandler.cpp Cube.cpp CubeIoHandler.cpp CubeTileHandler.cpp + +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Cube/unitTest.cpp b/isis/src/base/objs/Cube/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a251632143573fdd9b47569177b25cac00ff304 --- /dev/null +++ b/isis/src/base/objs/Cube/unitTest.cpp @@ -0,0 +1,387 @@ +#include +#include "iException.h" +#include "Cube.h" +#include "LineManager.h" +#include "Pvl.h" +#include "Preference.h" +#include "Histogram.h" +#include "Statistics.h" + +using namespace std; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + +try { + void Report(Isis::Cube &c); + cout << "Unit test for Isis::Cube" << endl; + + cout << "Constructing cube ... " << endl; + Isis::Cube out; + Report(out); + + // Test create and write methods + cout << "Creating 32-bit cube ... " << endl; + out.SetDimensions(150,200,2); + out.Create("/tmp/IsisCube_01"); + Report(out); + + cout << "Write cube ... " << endl; + Isis::LineManager line(out); + int j = 0; + for (line.begin(); !line.end(); line++) { + for (int i=0; iAverage() << endl; + cout << "Standard Dev: " << bandOneHist->StandardDeviation() << endl; + cout << "Mode: " << bandOneHist->Mode() << endl; + cout << "Total Pixels: " << bandOneHist->TotalPixels() << endl; + cout << "Null Pixels: " << bandOneHist->NullPixels() << endl; + cout << endl; + + // Test histogram object on all bands + cout << "Testing histogram method, all bands ... " << endl; + Isis::Histogram *allBandsHistogram = in.Histogram(0); + cout << "Average: " << allBandsHistogram->Average() << endl; + cout << "Standard Dev: " << allBandsHistogram->StandardDeviation() << endl; + cout << "Mode: " << allBandsHistogram->Mode() << endl; + cout << "Total Pixels: " << allBandsHistogram->TotalPixels() << endl; + cout << "Null Pixels: " << allBandsHistogram->NullPixels() << endl; + cout << endl; + + // Check error for too few (negative) bands + try { + in.Histogram(-1); + } + catch (Isis::iException &e) { + e.Report(false); + } + + // Test statistics object on a single band, 1 by default + cout << "Testing statistics method, band 1 ... " << endl; + Isis::Statistics *bandOneStats = in.Statistics(); + cout << "Average: " << bandOneStats->Average() << endl; + cout << "Standard Dev: " << bandOneStats->StandardDeviation() << endl; + cout << "Total Pixels: " << bandOneStats->TotalPixels() << endl; + cout << "Null Pixels: " << bandOneStats->NullPixels() << endl; + cout << endl; + + // Test statistics object on all bands + cout << "Testing statistics method, all bands ... " << endl; + Isis::Statistics *allBandsStats = in.Statistics(0); + cout << "Average: " << allBandsStats->Average() << endl; + cout << "Standard Dev: " << allBandsStats->StandardDeviation() << endl; + cout << "Total Pixels: " << allBandsStats->TotalPixels() << endl; + cout << "Null Pixels: " << allBandsStats->NullPixels() << endl; + cout << endl; + + // Check error for too few (negative) bands + try { + in.Statistics(-1); + } + catch (Isis::iException &e) { + e.Report(false); + } + + cout << endl; + + cout << "Virtual band tests" << endl; // Virtual Band tests + + cout << "Nbands = " << in.Bands() << endl; + cout << "Band 1 = " << in.PhysicalBand(1) << endl; + cout << "Band 2 = " << in.PhysicalBand(2) << endl; + in.Close(); + cout << endl; + + vector vbands; vbands.push_back("2"); + in.SetVirtualBands(vbands); + in.Open("/tmp/IsisCube_01"); + cout << "Nbands = " << in.Bands() << endl; + cout << "Band 1 = " << in.PhysicalBand(1) << endl; + cout << endl; + + + // Test ReOpen + cout << "ReOpen tests" << endl; + Report(in); + in.ReOpen("rw"); + Report(in); + in.ReOpen("r"); + Report(in); + + // Check errors + cout << "Testing errors ... " << endl; + try { + in.Open("blah"); + } + catch (Isis::iException &e) { + e.Report(false); + } + + try { + in.Create("blah"); + } + catch (Isis::iException &e) { + e.Report(false); + } + + try { + in.Write(inLine3); + } + catch (Isis::iException &e) { + e.Report(false); + } + + try { + Isis::Cube in; + in.Open("blah"); + } + catch (Isis::iException &e) { + e.Report(false); + } + + try { + in.PhysicalBand(2); + } + catch (Isis::iException &e) { + e.Report(false); + } + + try { + in.PhysicalBand(0); + } + catch (Isis::iException &e) { + e.Report(false); + } + + try { + Isis::Cube in; + in.Read(inLine3); + } + catch (Isis::iException &e) { + e.Report(false); + } + + try { + Isis::Cube in; + in.Write(inLine3); + } + catch (Isis::iException &e) { + e.Report(false); + } + + try { + Isis::Cube out; + out.SetLabelBytes(15); + out.Create("/tmp/IsisCube_04"); + out.Close(); + } + catch (Isis::iException &e) { + e.Report(false); + } + try { + Isis::Cube out; + out.SetDimensions(1000000,1000000,9); + out.Create("/tmp/IsisCube_05"); + out.Close(); + } + catch (Isis::iException &e) { + e.Report(false); + } + try { + Isis::Cube in; + in.Open("/tmp/IsisCube_01","a"); + } + catch (Isis::iException &e) { + e.Report(false); + } + try { + Isis::Cube in; + in.SetDimensions(0,0,0); + } + catch (Isis::iException &e) { + e.Report(false); + } + try { + Isis::Cube in; + in.SetDimensions(1,0,0); + } + catch (Isis::iException &e) { + e.Report(false); + } + try { + Isis::Cube in; + in.SetDimensions(1,1,0); + } + catch (Isis::iException &e) { + e.Report(false); + } + + Isis::Cube in4; + try { + in4.Open("$base/testData/isisTruth.cub"); + } + catch (Isis::iException &e) { + e.Report(false); + } + try { + in4.ReOpen("rw"); + } + catch (Isis::iException &e) { + e.Report(false); + } + +} +catch (Isis::iException &e) { + e.Report(); +} + + remove ("/tmp/IsisCube_01.cub"); + remove ("/tmp/IsisCube_02.cub"); + remove ("/tmp/IsisCube_02.lbl"); + remove ("/tmp/IsisCube_03.cub"); + remove ("/tmp/IsisCube_04.cub"); + remove ("/tmp/IsisCube_05.cub"); + return 0; +} + + +void Report (Isis::Cube &c) { + cout << "File = " << c.Filename() << endl; + cout << "Samps = " << c.Samples() << endl; + cout << "Lines = " << c.Lines() << endl; + cout << "Bands = " << c.Bands() << endl; + cout << "Base = " << c.Base() << endl; + cout << "Mult = " << c.Multiplier() << endl; + cout << "Type = " << c.PixelType() << endl; +// cout << "Order = " << c.ByteOrder() << endl; // Needs to be system independent + cout << "Atchd = " << c.IsAttached() << endl; + cout << "Dtchd = " << c.IsDetached() << endl; + cout << "Format = " << c.CubeFormat() << endl; + cout << "Open = " << c.IsOpen() << endl; + cout << "R/O = " << c.IsReadOnly() << endl; + cout << "R/W = " << c.IsReadWrite() << endl; + cout << "Lbytes = " << c.LabelBytes() << endl; + cout << endl; +} diff --git a/isis/src/base/objs/CubeAttribute/CubeAttribute.cpp b/isis/src/base/objs/CubeAttribute/CubeAttribute.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f31cb0086571a0da811580172866f81671f8ea6 --- /dev/null +++ b/isis/src/base/objs/CubeAttribute/CubeAttribute.cpp @@ -0,0 +1,469 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include + +#include "iException.h" +#include "iException.h" +#include "Preference.h" + +#include "CubeAttribute.h" + +using namespace std; +namespace Isis { + + CubeAttribute::CubeAttribute () { + p_attribute.clear(); + } + + + CubeAttribute::CubeAttribute (const Isis::iString &att) { + // Strip off the filename if there is one + std::string::size_type pos = att.find('+'); + if (pos == 0) { + p_attribute = att; + } + else if (pos != std::string::npos) { + p_attribute = att.substr(pos-1); + } + else if (att.length() == 0) { + p_attribute = ""; + } + else if (pos == std::string::npos) { + p_attribute = ""; + } + else { + string msg = "Invalid cube attribute string [" + att + "]"; + throw Isis::iException::Message(Isis::iException::Parse,msg, _FILEINFO_); + } + } + + + CubeAttribute::~CubeAttribute () {} + + + void CubeAttribute::Write(std::ostream &ostr) const { + ostr << p_attribute; + } + + + void CubeAttribute::Write(std::string &str) const { + str = p_attribute; + } + + + void CubeAttribute::Write(Isis::Pvl &pvl) const { + Isis::PvlGroup atts("Attributes"); + atts += Isis::PvlKeyword("Format", p_attribute); + pvl.AddGroup(atts); + } + + + //--------------------------------------------------------------------------- + // CubeAttributeInput Implementation + //--------------------------------------------------------------------------- + CubeAttributeInput::CubeAttributeInput () { + p_bands.clear(); + } + + + CubeAttributeInput::CubeAttributeInput (const Isis::iString &att) + : CubeAttribute(att) { + p_bands.clear(); + Parse (p_attribute); + } + + + CubeAttributeInput::~CubeAttributeInput () {} + + + void CubeAttributeInput::Set (const std::string &att) { + Parse(att); + } + + + string CubeAttributeInput::BandsStr() const { + string str; + for (unsigned int i=0; i0) str += ","; + str += p_bands[i]; + } + + return str; + } + + + vector CubeAttributeInput::Bands() const { + return p_bands; + } + + + void CubeAttributeInput::Bands (const std::vector &bands) { + p_bands.clear(); + for (unsigned int i=0; i 0) { + str = "+"; + } + for (unsigned int i=0; i0) str += ","; + str += p_bands[i]; + } + } + + + void CubeAttributeInput::Write(Isis::Pvl &pvl) const { + Isis::PvlKeyword bands("Bands"); + for (unsigned int b=0; b 0) { + // Is this token a range of bands + if (commaTok.find('-') != std::string::npos) { + Isis::iString dashTok; + int start = commaTok.Token("-").ToInteger(); + int end = commaTok.Token("-").ToInteger(); + int direction; + direction = (start<=end) ? 1 : -1; + // Save the entire range of bands + for (int band = start; band != end; band+=direction) { + p_bands.push_back(Isis::iString(band)); + } + p_bands.push_back(Isis::iString(end)); + } + // This token is a single band specification + else { + p_bands.push_back(commaTok); + } + } + } + + + //--------------------------------------------------------------------------- + // CubeAttributeOutput Implementation + //--------------------------------------------------------------------------- + CubeAttributeOutput::CubeAttributeOutput () { + Initialize (); + } + + + CubeAttributeOutput::CubeAttributeOutput (const Isis::iString &att) + : CubeAttribute (att) { + + Initialize (); + p_attribute = att; + Parse (p_attribute); + } + + + CubeAttributeOutput::~CubeAttributeOutput () {} + + + void CubeAttributeOutput::Set (const std::string &att) { + Parse(att); + } + + + string CubeAttributeOutput::FileFormatStr() const { + return Isis::CubeFormatName(p_format); + } + + + Isis::CubeFormat CubeAttributeOutput::FileFormat() const { + return p_format; + } + + + void CubeAttributeOutput::Format (const Isis::CubeFormat fmt) { + p_format = fmt; + } + + + double CubeAttributeOutput::Minimum () const { + return p_minimum; + } + + + double CubeAttributeOutput::Maximum () const { + return p_maximum; + } + + + void CubeAttributeOutput::Minimum (const double min) { + p_minimum = min; + p_rangeType = Isis::RangeSet; + } + + + void CubeAttributeOutput::Maximum (const double max) { + p_maximum = max; + p_rangeType = Isis::RangeSet; + } + + + Isis::PixelType CubeAttributeOutput::PixelType() const { + if (p_pixelType == Isis::None) { + string msg; + msg = msg + "Request for CubeAttributeOutput::PixelType failed. " + + "PixelType has not been set. Use PropagatePixelType or " + + "UserPixelType to determine how to set PixelType."; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + return p_pixelType; + } + + + void CubeAttributeOutput::PixelType (const Isis::PixelType type) { + p_pixelType = type; + if (p_pixelType == Isis::None) { + p_pixelTypeDef = "PROPAGATE"; + } + else { + p_pixelTypeDef = "SET"; + } + } + + + string CubeAttributeOutput::ByteOrderStr() const { + return Isis::ByteOrderName(p_order); + } + + + Isis::ByteOrder CubeAttributeOutput::ByteOrder() const { + return p_order; + } + + + void CubeAttributeOutput::Order (const Isis::ByteOrder order) { + p_order = order; + } + + + void CubeAttributeOutput::Write(std::ostream &ostr) const { + string st; + Write(st); + ostr << st; + } + + + void CubeAttributeOutput::Write(std::string &str) const { + str.clear(); + if (p_pixelTypeDef != "PROPAGATE") { + str += "+" + Isis::PixelTypeName (p_pixelType); + } + if (p_pixelType != Isis::Real && p_pixelType != Isis::None) { + str += "+" + Isis::iString(p_minimum) + ":" + Isis::iString(p_maximum); + } + str += "+" + FileFormatStr(); + str += "+" + ByteOrderStr(); + str += "+" + Isis::LabelAttachmentName (p_labelAttachment); + } + + + void CubeAttributeOutput::Write(Isis::Pvl &pvl) const { + Isis::PvlGroup outatt("OutputCubeAttributes"); + + if (p_pixelTypeDef != "PROPAGATE") { + outatt += Isis::PvlKeyword("Type", PixelTypeName(p_pixelType)); + } + outatt += Isis::PvlKeyword("Format", FileFormatStr()); + if (p_pixelType != Isis::Real) { + outatt += Isis::PvlKeyword("Minimum", p_minimum); + outatt += Isis::PvlKeyword("Maximum", p_maximum); + } + outatt += Isis::PvlKeyword("ByteOrder", ByteOrderStr()); + outatt += Isis::PvlKeyword("LabelType", Isis::LabelAttachmentName(p_labelAttachment)); + + pvl.AddGroup(outatt); + } + + + void CubeAttributeOutput::Reset() { + Initialize(); + } + + + void CubeAttributeOutput::Parse (const std::string &att) { + + Isis::iString str(att); + + // Strip off the leading "+" and put the attributes in a temporary + std::string::size_type pos = str.find('+'); + if (pos != std::string::npos) { + str = str.substr(pos); + } + else { + str = ""; + } + + // Remove any white space + str.ConvertWhiteSpace(); + str.Compress(); + str.Remove(" "); + str.UpCase(); + str.TrimHead ("+"); + + // Look at each "+" separate attribute + Isis::iString tok; + while ((tok = str.Token("+")).length() > 0) { + + // If there is a ":" in this token then it is assumed to be a min:max + if (tok.find(":") != std::string::npos) { + + // Pull out the minimum + Isis::iString colonTok = tok; + Isis::iString min = colonTok.Token(":"); + if (min.length() > 0) { + p_minimum = min.ToDouble(); + } + else { + p_minimum = 0.0; + } + + // Pull out the maximum + Isis::iString max = colonTok.Token(":"); + if (max.length() > 0) { + p_maximum = max.ToDouble(); + } + else { + p_maximum = 0.0; + } + p_rangeType = Isis::RangeSet; + } + + // Parse any pixel type attributes + else if (tok == "8BIT" || tok == "8-BIT" || tok == "UNSIGNEDBYTE") { + p_pixelType = Isis::UnsignedByte; + p_pixelTypeDef = "SET"; + } + else if (tok == "16BIT" || tok == "16-BIT" || tok == "SIGNEDWORD") { + p_pixelType = Isis::SignedWord; + p_pixelTypeDef = "SET"; + } + else if (tok == "32BIT" || tok == "32-BIT" || tok == "REAL") { + p_pixelType = Isis::Real; + p_pixelTypeDef = "SET"; + } + else if (tok == "PROPAGATE") { + p_pixelType = Isis::None; + p_pixelTypeDef = "PROPAGATE"; + } + + // Parse any file formats + else if (tok == "TILE") { + p_format = Isis::Tile; + } + else if (tok == "BSQ" || tok == "BANDSEQUENTIAL") { + p_format = Isis::Bsq; + } + + // Parse any byte order + else if (tok == "LSB") { + p_order = Isis::Lsb; + } + else if (tok == "MSB") { + p_order = Isis::Msb; + } + + // Parse any label type + else if (tok == "ATTACHED") { + p_labelAttachment = Isis::AttachedLabel; + } + else if (tok == "DETACHED") { + p_labelAttachment = Isis::DetachedLabel; + } + } + } + + + void CubeAttributeOutput::Initialize () { + p_pixelType = Isis::None; + p_pixelTypeDef = "PROPAGATE"; + p_rangeType = Isis::PropagateRange; + p_minimum = 0.0; + p_maximum = 0.0; + p_format = Isis::Tile; + + // The byte order default is dependant on the hardware + if (Isis::IsLsb()) { + p_order = Isis::Lsb; + } + else { + p_order = Isis::Msb; + } + + // The type of label to produce is dependent on the preference file + Isis::PvlGroup &cust = Isis::Preference::Preferences().FindGroup("CubeCustomization"); + p_labelAttachment = Isis::LabelAttachmentEnumeration (cust["Format"]); + } +} diff --git a/isis/src/base/objs/CubeAttribute/CubeAttribute.h b/isis/src/base/objs/CubeAttribute/CubeAttribute.h new file mode 100644 index 0000000000000000000000000000000000000000..fc5f39375ccc700ee77e4e7b532bf669dfe09545 --- /dev/null +++ b/isis/src/base/objs/CubeAttribute/CubeAttribute.h @@ -0,0 +1,518 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef CubeAttribute_h +#define CubeAttribute_h +#include +#include "Pvl.h" +#include "iString.h" +#include "PixelType.h" +#include "Endian.h" +#include "iException.h" +#include "CubeFormat.h" + +namespace Isis { + + /** + * @brief Output cube range tracker + * + * This enumeration and its functions are for the output range + * of a cube. + **/ + enum RangeType { + PropagateRange, //!< Propagate the range from an input cube + RangeSet, //!< The range has been set + }; + + + /** + * Return the string representation of the contents of a + * variable of type RangeType + * + * @param rangeType enum to be converted to a string + * + * @return A string representation of the rangeType parameter + */ + inline std::string RangeTypeName (RangeType rangeType) { + if (rangeType == PropagateRange) return "Propagate"; + if (rangeType == RangeSet) return "Set"; + + std::string msg = "Invalid output range type [" + Isis::iString(rangeType) + "]"; + throw Isis::iException::Message(Isis::iException::Parse,msg, _FILEINFO_); + } + + + /** + * Return the appropriate RangeType depending on which of + * the valid values the argument spells + * + * @param rangeType A string representation of the rangeType + * + * @return The RangeType enum corresponding to the string parameter + */ + inline RangeType RangeTypeEnumeration (const std::string &rangeType) { + Isis::iString temp(rangeType); + temp = temp.UpCase(); + if (temp == "PROPAGATE") return PropagateRange; + if (temp == "SET") return RangeSet; + + std::string msg = "Invalid output range type string [" + rangeType + "]"; + throw Isis::iException::Message(Isis::iException::Parse,msg, _FILEINFO_); + } + + + /** + * @brief Input cube label type tracker + * + * This enumeration and its functions are for the label + * type of an input cube. The enum defines the type of labels (i.e., + * Both the label and cube are in the same file and the label is in a + * separate file from the cube. + **/ + enum LabelAttachment { + AttachedLabel, //!< The input label is embedded in the image file + DetachedLabel //!< The input label is in a separate data file from the image + }; + + + /** + * Return the string representation of the contents of a + * variable of type LabelAttachment + * + * @param labelType The LabelAttachment enum to be converted to a string + * + * @return A string representation of the parameter + */ + inline std::string LabelAttachmentName (LabelAttachment labelType) { + if (labelType == AttachedLabel) return "Attached"; + if (labelType == DetachedLabel) return "Detached"; + + std::string msg = "Invalid label attachment type [" + Isis::iString(labelType) + "]"; + throw Isis::iException::Message(Isis::iException::Parse,msg, _FILEINFO_); + } + + + /** + * Return the appropriate LabelType depending on which of + * the valid values the argument spells + * + * @param labelType + * + * @return The RangeType enum corresponding to the string parameter + */ + inline LabelAttachment LabelAttachmentEnumeration (const std::string &labelType) { + Isis::iString temp(labelType); + temp = temp.UpCase(); + if (temp == "ATTACHED") return AttachedLabel; + if (temp == "DETACHED") return DetachedLabel; + + std::string msg = "Invalid label attachment type string [" + labelType + "]"; + throw Isis::iException::Message(Isis::iException::Parse,msg, _FILEINFO_); + } + + + +/** + * @brief Parent class for CubeAttributeInput and CubeAttributeOutput. + * + * This class provides common functionality for the CubeAttributeInput and + * CubeAttributeOutput classes. These classes are used to parse and + * manipulate attribute information attached to the end of a cube filename. + * + * @see IsisAml IsisGui + * + * @ingroup Parsing + * + * @internal + * @history 2003-07-09 Stuart Sides + * Original version + * + * @history 2003-07-17 Stuart Sides + * Added input file band attribute capabilities. + * + * @history 2003-07-29 Stuart Sides + * Separated the input and output attributes into two separated class + * deriving off a base class, instead of one class for all cases. + * + * @history 2003-10-03 Stuart Sides + * Added members HasPixelType. It was needed by the IsisCube so it could do + * an easy check. Added IsMsb, IsLsb, HasOrder, ByteOrderStr, ByteOrderType, + * Order and Order. These were needed to allow users to specify a + * byte order for output cubes. + * + * @history 2004-02-03 Stuart Sides + * Refactor for IsisProcess and cube changes + * + * @history 2004-03-03 Stuart Sides + * Modified IsisCubeAttributeOutput::Write so min and max don't get written + * when the pixel type is real. + * + */ + class CubeAttribute { + public: + + //! Constructs an empty CubeAttribute + CubeAttribute (); + + + /** + * @brief Constructs a CubeAttribute using the argument + * + * Constructs a CubeAttribute and initializes it with the + * contents of the string parameter. Minimal error checking + * is done to see if the string looks like an attribute. + * + * @param att A string containing the file attributes. All characters + * before the first "+" are assumed to be the filename + * and are ignored. + */ + CubeAttribute (const Isis::iString &att); + + + //! Destroys the object + virtual ~CubeAttribute (); + + + /** + * Write the attributes to a stream + * + * @param ostr The stream to write the attributes to + */ + virtual void Write(std::ostream &ostr) const; + + + /** + * Write the attributes to a string + * + * @param str The string to write the attributes to + */ + virtual void Write(std::string &str) const; + + + /** + * Write the attributes to an Isis::Pvl + * + * @param pvl The pvl to write the attributes to + */ + virtual void Write(Isis::Pvl &pvl) const; + + protected: + Isis::iString p_attribute; //!< Contains the unparsed attributes with the filename stripped + }; + + +#ifndef DOXY_INTERNAL + + /** + * @brief Manipulate and parse attributes of input cube filenames. + * + * This class provides parsing and manipulation of attributes associated + * with input cube filenames. Input cube filenames can have an attribute + * of "band(s) specification" + * + * @see IsisAml IsisGui + * + * @ingroup Parsing + * + * @internal + * @history 2003-07-29 Stuart Sides + * Separated the input and output attributes into two seprated class + * deriving off a base class, instead of one class for all cases. + * + * @history 2004-02-03 Stuart Sides + * Refactor for IsisProcess and cube changes + * + * @history 2006-01-05 Stuart Sides + * Fixed bug when the input attribute was "+7-10". In this case the Write + * members were not putting the "+" at the beginning. + * + */ + class CubeAttributeInput : public CubeAttribute { + + public: + + //! Constructs an empty CubeAttributeInput + CubeAttributeInput (); + + + /** + * + * Constructs a CubeAttributeInput and initialized it with the + * contents of the string parameter. The string is parased to + * obtain any band specifiers. Any attribute information that + * is not valie for an input cube will throw an error. + * + * @param att The attribute string to be parsed. + **/ + CubeAttributeInput (const Isis::iString &att); + + + //! Destroys the object + ~CubeAttributeInput (); + + + /** + * Set the input attributes according to the argument. Note: + * the attributes are not initialized prior to parsing the argument. This + * means that multipal invocations will be cumulative. + * + * @param att A string containing the file attributes. All characters + * before the first "+" are assumed to be the filename + * and are ignored. + **/ + void Set (const std::string &att); + + + //! Set the input attributes to the default state (i.e., empty) + void Reset (); + + + //! Return an STL vector of the input bands specified + std::vector Bands () const; + + /** + * @brief Return a string representation of all the bands + * + * @internal + * @history Stuart Sides 2005-01-2005 ??? + * + * Combines all the specified bands numbers into a single + * string with commas between each band number + * + * @return A comma delimited string of all bands from the input attribute + */ + std::string BandsStr() const; + + //! Set the band attribute according to the list of bands + void Bands (const std::vector &bands); + + //! Set the band attribute according the string parameter + void Bands (const std::string &bands); + + //! Write the attributes to a stream + void Write(std::ostream &ostr) const; + + //! Write the attributes to a string + void Write(std::string &str) const; + + //! Write the attributes to a Pvl + void Write(Isis::Pvl &pvl) const; + + private: + std::vector p_bands; //!< A list of the specified bands + + /** + * + * Parse the string parameter and populate the private + * variable accordinly. + * + * @param att A string containing the file attributes. All characters + * before the first "+" are assumed to be the filename + * and are ignored. + */ + void Parse (const std::string &att); + }; + + + /** + * @brief Manipulate and parse attributes of output cube filenames. + * + * This class provides parsing and manipulation of attributes associated + * with output cube filenames. Output cube filenames can have an attributes + * of "minimum:maximum", "pixel type", "file format", "byte order", and + * "label placement" + * + * @see IsisAml IsisGui + * + * @ingroup Parsing + * + * @internal + * @history 2003-07-29 Stuart Sides + * Separated the input and output attributes into two separated class + * deriving off a base class, instead of one class for all cases. + * + * @history 2003-10-03 Stuart Sides + * Added members HasPixelType. It was needed by the IsisCube so it could do + * an easy check. Added IsMsb, IsLsb, HasOrder, ByteOrderStr, ByteOrderType, + * Order and Order. These were needed to allow users to specify a + * byte order for output cubes. + * + * @history 2004-02-03 Stuart Sides + * Refactor for IsisProcess and cube changes + * + * @history 2004-03-03 Stuart Sides + * Modified IsisCubeAttributeOutput::Write so min and max don't get written + * when the pixel type is real. + * + */ + class CubeAttributeOutput : public CubeAttribute { + public: + + //! Constructs an empty CubeAttributeOutput + CubeAttributeOutput (); + + /** + * + * Constructs a CubeAttributeOutput and initialized it with the + * contents of the string parameter. The string is parased to + * obtain any min/max, pixel type, byte order, file format or + * label placement. Any attribute information that + * is not valie for an output cube will throw an error. + * + * @param att A string containing the file attributes. All characters + * before the first "+" are assumed to be the filename + * and are ignored. + **/ + CubeAttributeOutput (const Isis::iString &att); + + + //! Destroys the object + ~CubeAttributeOutput (); + + + //! Return true if the pixel type is to be propagated from an input cube + inline bool PropagatePixelType () const { + if (p_pixelTypeDef == "PROPAGATE") { + return true; + } + return false; + }; + + //! Return true if the min/max are to be propagated from an input cube + inline bool PropagateMinimumMaximum () const { + if (p_rangeType == Isis::PropagateRange) { + return true; + } + return false; + }; + + /** + * Set the output attributes according to the argument. Note: + * the attributes are not initialized prior to parsing the argument. This + * means that multipal invocations will be cumulative. + * + * @param att A string containing the file attributes. All characters + * before the first "+" are assumed to be the filename + * and are ignored. + **/ + void Set (const std::string &att); + + /** + * Set the output attributes to the default state + * + * @see Initialize + **/ + void Reset (); + + //! Return the file format as a string + std::string FileFormatStr() const; + + //! Return the file format an Isis::CubeFormat + Isis::CubeFormat FileFormat() const; + + //! Set the format to the fmt parameter + void Format (const Isis::CubeFormat fmt); + + //! Return the byte order as a string + std::string ByteOrderStr() const; + + //! Return the byte order as an Isis::ByteOrder + Isis::ByteOrder ByteOrder() const; + + //! Set the order according to the parameter order + void Order (const Isis::ByteOrder order); + + //! Return the output cube attribute minimum + double Minimum() const; + + //! Return the output cube attribute maximum + double Maximum() const; + + //! Set the output cube attribute minimum + void Minimum (const double min); + + //! Set the output cube attribute maximum + void Maximum (const double max); + + //! Return the pixel type as an Isis::PixelType + Isis::PixelType PixelType() const; + + //! Set the label attachment type to the parameter value + void Label(Isis::LabelAttachment attachment) { p_labelAttachment = attachment; }; + + //! Return true if the attachement type is "Attached" + bool AttachedLabel() const { return p_labelAttachment == Isis::AttachedLabel; }; + + //! Return true if the attachement type is "Detached" + bool DetachedLabel() const { return p_labelAttachment == Isis::DetachedLabel; }; + + //! Set the pixel type to that given by the parameter + void PixelType (const Isis::PixelType type); + + //! Write the output attributes to a stream + void Write(std::ostream &ostr) const; + + //! Write the output attributes to a string + void Write(std::string &str) const; + + //! Write the output attributes to a Pvl + void Write(Isis::Pvl &pvl) const; + + + private: + Isis::PixelType p_pixelType; //!< Stores the pixel type + /** + * + * Stores weather the p_pixelType has been set or should be + * propagated from an input cube. + */ + std::string p_pixelTypeDef; + /** + * + * Stores weather the pixel range has been set or should be + * propagated from an input cube + */ + Isis::RangeType p_rangeType; + + double p_minimum; //!< Stores the minimum for the output cube attribute + double p_maximum; //!< Stores the maximum for the output cube attribute + Isis::CubeFormat p_format; //!< Store the cube format + Isis::ByteOrder p_order; //!< Store the byte order for the cube attribute + Isis::LabelAttachment p_labelAttachment; //!< Store the type of label attachment + + /** + * + * Parse the string parameter and populate the private member variables + * accordingly + * @param att + */ + void Parse (const std::string &att); + + //! Initialize the output cube attribute to default values + void Initialize (); + + }; + #endif //DOXY_INTERNAL +}; + +#endif diff --git a/isis/src/base/objs/CubeAttribute/CubeAttribute.truth b/isis/src/base/objs/CubeAttribute/CubeAttribute.truth new file mode 100644 index 0000000000000000000000000000000000000000..48ddb479221c73b1b95065f36d8193dee53c9898 --- /dev/null +++ b/isis/src/base/objs/CubeAttribute/CubeAttribute.truth @@ -0,0 +1,217 @@ +Unit test for Isis::CubeAttribute and its subclasses + +Test of invalid attribute "sometext" + + + +Test of attribute "+sometext" ++sometext ++sometext +Group = Attributes + Format = +sometext +End_Group +End + + + +Test of system default output cube attributes ++Tile+Lsb+Attached +Group = OutputCubeAttributes + Format = Tile + Minimum = 0.0 + Maximum = 0.0 + ByteOrder = Lsb + LabelType = Attached +End_Group +End + +Propagate Pixel Type = 1 +**PROGRAMMER ERROR** Request for CubeAttributeOutput::PixelType failed. PixelType has not been set. Use PropagatePixelType or UserPixelType to determine how to set PixelType. +Propagate Min/Max = 1 +Minimum = 0 +Maximum = 0 +FileFormatStr = Tile +FileFormat enum = Tile +ByteOrder = ok +Label attachment = Attached + + + + +Test of output attribute "+8bit+Tile+0.0:100.1+MSB" ++UnsignedByte+0.0:100.1+Tile+Msb+Attached +Group = OutputCubeAttributes + Type = UnsignedByte + Format = Tile + Minimum = 0.0 + Maximum = 100.1 + ByteOrder = Msb + LabelType = Attached +End_Group +End + +Propagate Pixel Type = 0 +PixelType = UnsignedByte +Propagate Min/Max = 0 +Minimum = 0 +Maximum = 100.1 +FileFormatStr = Tile +FileFormat enum = Tile +ByteOrder = ok +Label attachment = Attached + + + + +Test of output attribute "+16bit+Bsq+-10000.0:-100.1+lsb" ++SignedWord+-100000.0:-100.1+BandSequential+Lsb+Attached +Group = OutputCubeAttributes + Type = SignedWord + Format = BandSequential + Minimum = -100000.0 + Maximum = -100.1 + ByteOrder = Lsb + LabelType = Attached +End_Group +End + +Propagate Pixel Type = 0 +PixelType = SignedWord +Propagate Min/Max = 0 +Minimum = -100000 +Maximum = -100.1 +FileFormatStr = BandSequential +FileFormat enum = BandSequential +ByteOrder = ok +Label attachment = Attached + + + + +Test of output attribute "+32bit" ++Real+Tile+Lsb+Attached +Group = OutputCubeAttributes + Type = Real + Format = Tile + ByteOrder = Lsb + LabelType = Attached +End_Group +End + +Propagate Pixel Type = 0 +PixelType = Real +Propagate Min/Max = 0 +Minimum = 999 +Maximum = 9999 +FileFormatStr = Tile +FileFormat enum = Tile +ByteOrder = ok +Label attachment = Attached + + + + +Test of output attribute "+0.0:100.1+detached" ++Tile+Lsb+Detached +Group = OutputCubeAttributes + Format = Tile + Minimum = 0.0 + Maximum = 100.1 + ByteOrder = Lsb + LabelType = Detached +End_Group +End + +Propagate Pixel Type = 1 +**PROGRAMMER ERROR** Request for CubeAttributeOutput::PixelType failed. PixelType has not been set. Use PropagatePixelType or UserPixelType to determine how to set PixelType. +Propagate Min/Max = 0 +Minimum = 0 +Maximum = 100.1 +FileFormatStr = Tile +FileFormat enum = Tile +ByteOrder = ok +Label attachment = Detached + + + + +Test of output attribute "+8bit+Tile" ++UnsignedByte+0.0:0.0+Tile+Lsb+Attached +Group = OutputCubeAttributes + Type = UnsignedByte + Format = Tile + Minimum = 0.0 + Maximum = 0.0 + ByteOrder = Lsb + LabelType = Attached +End_Group +End + +Propagate Pixel Type = 0 +PixelType = UnsignedByte +Propagate Min/Max = 1 +Minimum = 0 +Maximum = 0 +FileFormatStr = Tile +FileFormat enum = Tile +ByteOrder = ok +Label attachment = Attached + + + + +Test of output attribute "Defaults" with Set ++UnsignedByte+0.0:0.0+Tile+Lsb+Detached +Group = OutputCubeAttributes + Type = UnsignedByte + Format = Tile + Minimum = 0.0 + Maximum = 0.0 + ByteOrder = Lsb + LabelType = Detached +End_Group +End + +Propagate Pixel Type = 0 +PixelType = UnsignedByte +Propagate Min/Max = 1 +Minimum = 0 +Maximum = 0 +FileFormatStr = Tile +FileFormat enum = Tile +ByteOrder = ok +Label attachment = Detached + + + + +Test of input attribute "+3" ++3 ++3 +Group = InputAttributes + Bands = 3 +End_Group +End + + +Test of input attribute "+3,5-9,99" ++3,5,6,7,8,9,99 ++3,5,6,7,8,9,99 +Group = InputAttributes + Bands = (3, 5, 6, 7, 8, 9, 99) +End_Group +End + + +Test of input attribute "+7-10" ++7,8,9,10 ++7,8,9,10 +Group = InputAttributes + Bands = (7, 8, 9, 10) +End_Group +End + + +Testing put members (strings) ++Tile+Lsb+Attached + diff --git a/isis/src/base/objs/CubeAttribute/CubeAttribute_Darwin_powerpc.truth b/isis/src/base/objs/CubeAttribute/CubeAttribute_Darwin_powerpc.truth new file mode 100644 index 0000000000000000000000000000000000000000..4ef8cdb466fcaad452e15282f260e8ef56f585d7 --- /dev/null +++ b/isis/src/base/objs/CubeAttribute/CubeAttribute_Darwin_powerpc.truth @@ -0,0 +1,217 @@ +Unit test for Isis::CubeAttribute and its subclasses + +Test of invalid attribute "sometext" + + + +Test of attribute "+sometext" ++sometext ++sometext +Group = Attributes + Format = +sometext +End_Group +End + + + +Test of system default output cube attributes ++Tile+Msb+Attached +Group = OutputCubeAttributes + Format = Tile + Minimum = 0.0 + Maximum = 0.0 + ByteOrder = Msb + LabelType = Attached +End_Group +End + +Propagate Pixel Type = 1 +**PROGRAMMER ERROR** Request for CubeAttributeOutput::PixelType failed. PixelType has not been set. Use PropagatePixelType or UserPixelType to determine how to set PixelType. +Propagate Min/Max = 1 +Minimum = 0 +Maximum = 0 +FileFormatStr = Tile +FileFormat enum = Tile +ByteOrder = ok +Label attachment = Attached + + + + +Test of output attribute "+8bit+Tile+0.0:100.1+MSB" ++UnsignedByte+0.0:100.1+Tile+Msb+Attached +Group = OutputCubeAttributes + Type = UnsignedByte + Format = Tile + Minimum = 0.0 + Maximum = 100.1 + ByteOrder = Msb + LabelType = Attached +End_Group +End + +Propagate Pixel Type = 0 +PixelType = UnsignedByte +Propagate Min/Max = 0 +Minimum = 0 +Maximum = 100.1 +FileFormatStr = Tile +FileFormat enum = Tile +ByteOrder = ok +Label attachment = Attached + + + + +Test of output attribute "+16bit+Bsq+-10000.0:-100.1+lsb" ++SignedWord+-100000.0:-100.1+BandSequential+Lsb+Attached +Group = OutputCubeAttributes + Type = SignedWord + Format = BandSequential + Minimum = -100000.0 + Maximum = -100.1 + ByteOrder = Lsb + LabelType = Attached +End_Group +End + +Propagate Pixel Type = 0 +PixelType = SignedWord +Propagate Min/Max = 0 +Minimum = -100000 +Maximum = -100.1 +FileFormatStr = BandSequential +FileFormat enum = BandSequential +ByteOrder = ok +Label attachment = Attached + + + + +Test of output attribute "+32bit" ++Real+Tile+Msb+Attached +Group = OutputCubeAttributes + Type = Real + Format = Tile + ByteOrder = Msb + LabelType = Attached +End_Group +End + +Propagate Pixel Type = 0 +PixelType = Real +Propagate Min/Max = 0 +Minimum = 999 +Maximum = 9999 +FileFormatStr = Tile +FileFormat enum = Tile +ByteOrder = ok +Label attachment = Attached + + + + +Test of output attribute "+0.0:100.1+detached" ++Tile+Msb+Detached +Group = OutputCubeAttributes + Format = Tile + Minimum = 0.0 + Maximum = 100.1 + ByteOrder = Msb + LabelType = Detached +End_Group +End + +Propagate Pixel Type = 1 +**PROGRAMMER ERROR** Request for CubeAttributeOutput::PixelType failed. PixelType has not been set. Use PropagatePixelType or UserPixelType to determine how to set PixelType. +Propagate Min/Max = 0 +Minimum = 0 +Maximum = 100.1 +FileFormatStr = Tile +FileFormat enum = Tile +ByteOrder = ok +Label attachment = Detached + + + + +Test of output attribute "+8bit+Tile" ++UnsignedByte+0.0:0.0+Tile+Msb+Attached +Group = OutputCubeAttributes + Type = UnsignedByte + Format = Tile + Minimum = 0.0 + Maximum = 0.0 + ByteOrder = Msb + LabelType = Attached +End_Group +End + +Propagate Pixel Type = 0 +PixelType = UnsignedByte +Propagate Min/Max = 1 +Minimum = 0 +Maximum = 0 +FileFormatStr = Tile +FileFormat enum = Tile +ByteOrder = ok +Label attachment = Attached + + + + +Test of output attribute "Defaults" with Set ++UnsignedByte+0.0:0.0+Tile+Msb+Detached +Group = OutputCubeAttributes + Type = UnsignedByte + Format = Tile + Minimum = 0.0 + Maximum = 0.0 + ByteOrder = Msb + LabelType = Detached +End_Group +End + +Propagate Pixel Type = 0 +PixelType = UnsignedByte +Propagate Min/Max = 1 +Minimum = 0 +Maximum = 0 +FileFormatStr = Tile +FileFormat enum = Tile +ByteOrder = ok +Label attachment = Detached + + + + +Test of input attribute "+3" ++3 ++3 +Group = InputAttributes + Bands = 3 +End_Group +End + + +Test of input attribute "+3,5-9,99" ++3,5,6,7,8,9,99 ++3,5,6,7,8,9,99 +Group = InputAttributes + Bands = (3, 5, 6, 7, 8, 9, 99) +End_Group +End + + +Test of input attribute "+7-10" ++7,8,9,10 ++7,8,9,10 +Group = InputAttributes + Bands = (7, 8, 9, 10) +End_Group +End + + +Testing put members (strings) ++Tile+Msb+Attached + diff --git a/isis/src/base/objs/CubeAttribute/Makefile b/isis/src/base/objs/CubeAttribute/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b6bd060fb525d093b9ac51853e8ce0a862701517 --- /dev/null +++ b/isis/src/base/objs/CubeAttribute/Makefile @@ -0,0 +1,5 @@ +INCS = CubeAttribute.h +SRCS = CubeAttribute.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CubeAttribute/unitTest.cpp b/isis/src/base/objs/CubeAttribute/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c2e1ed4eda1ce1c10631c4a3eed0af4a16c75da --- /dev/null +++ b/isis/src/base/objs/CubeAttribute/unitTest.cpp @@ -0,0 +1,301 @@ +/** + * @file + * + * Test driver that tests this Object for accuracy and correct behavior. + * $Revision: 1.1.1.1 $ + * $Id: unitTest.cpp,v 1.1.1.1 2006/10/31 23:18:06 isis3mgr Exp $ + * $Author: isis3mgr $ + * $Date: 2006/10/31 23:18:06 $ + * + */ + + /*********************************************************************** + * PLEASE NOTE * + * This unit test modifies the truth file that it is meant to be tested * + * against. The reason for this is that the output of the unit test is * + * dependent upon the system architecture, so an unchanged truth file * + * will only be correct on LSB xor MSB machines. To see the code that * + * changes CubeAttriube.truth, go to lines 254 - ### * + * * + ***********************************************************************/ + +#include +#include +#include "iException.h" +#include "Preference.h" +#include "CubeAttribute.h" +#include "EndianSwapper.h" +#include "Pvl.h" + +using namespace std; + +int main (int argc, char *argv[]) { + + void ReportOutput (Isis::CubeAttributeOutput *att, string oh); + + Isis::Preference::Preferences(true); + + cout << "Unit test for Isis::CubeAttribute and its subclasses" << endl << endl; + + cout << "Test of invalid attribute \"sometext\"" << endl; + try { + Isis::CubeAttribute *att = new Isis::CubeAttribute("sometext"); + delete att; + cout << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl << endl; + + cout << "Test of attribute \"+sometext\"" << endl; + try { + Isis::CubeAttribute *att = new Isis::CubeAttribute("+sometext"); + att->Write(cout); + cout << endl; + string str; + att->Write(str); + cout << str << endl; + Isis::Pvl pvl; + att->Write(pvl); + cout << pvl << endl; + cout << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl << endl; + + + cout << "Test of system default output cube attributes" << endl; + try { + Isis::CubeAttributeOutput *att = new Isis::CubeAttributeOutput(); + ReportOutput (att, "SYS"); + cout << endl << endl; + delete att; + } + catch (Isis::iException &error) { + error.Report (true); + } + cout << endl << endl; + + + cout << "Test of output attribute \"+8bit+Tile+0.0:100.1+MSB\"" << endl; + try { + Isis::CubeAttributeOutput *att = new Isis::CubeAttributeOutput("+8bit+Tile+0.0:100.1+MSB"); + ReportOutput (att, "MSB"); + cout << endl << endl; + delete att; + } + catch (Isis::iException &error) { + error.Report (true); + } + cout << endl << endl; + + + cout << "Test of output attribute \"+16bit+Bsq+-10000.0:-100.1+lsb\"" << endl; + try { + Isis::CubeAttributeOutput *att = new Isis::CubeAttributeOutput ("+16bit+Bsq+-100000.0:-100.1+lsb"); + ReportOutput (att, "LSB"); + cout << endl << endl; + delete att; + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl << endl; + + + cout << "Test of output attribute \"+32bit\"" << endl; + try { + Isis::CubeAttributeOutput *att = new Isis::CubeAttributeOutput("+32bit+tile+999:9999"); + ReportOutput (att,"SYS"); + cout << endl << endl; + delete att; + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl << endl; + + + cout << "Test of output attribute \"+0.0:100.1+detached\"" << endl; + try { + Isis::CubeAttributeOutput *att = new Isis::CubeAttributeOutput ("+0.0:100.1+detached"); + ReportOutput (att,"SYS"); + cout << endl << endl; + delete att; + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl << endl; + + + cout << "Test of output attribute \"+8bit+Tile\"" << endl; + try { + Isis::CubeAttributeOutput *att = new Isis::CubeAttributeOutput ("+8bit+Tile"); + ReportOutput (att, "SYS"); + cout << endl << endl; + delete att; + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl << endl; + + cout << "Test of output attribute \"Defaults\" with Set" << endl; + try { + Isis::CubeAttributeOutput *att = new Isis::CubeAttributeOutput (); + att->Set("+8-bit+Detached"); + ReportOutput (att, "SYS"); + cout << endl << endl; + delete att; + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl << endl; + + + cout << "Test of input attribute \"+3\"" << endl; + try { + Isis::CubeAttributeInput *att = new Isis::CubeAttributeInput("+3"); + att->Write(cout); + cout << endl; + string str; + att->Write(str); + cout << str << endl; + Isis::Pvl pvl; + att->Write(pvl); + cout << pvl << endl; + delete att; + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl << endl; + + cout << "Test of input attribute \"+3,5-9,99\"" << endl; + try { + Isis::CubeAttributeInput *att = new Isis::CubeAttributeInput("+3,5-9,99"); + att->Write(cout); + cout << endl; + string str; + att->Write(str); + cout << str << endl; + Isis::Pvl pvl; + att->Write(pvl); + cout << pvl << endl; + delete att; + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl << endl; + + cout << "Test of input attribute \"+7-10\"" << endl; + try { + Isis::CubeAttributeInput *att = new Isis::CubeAttributeInput("+7-10"); + att->Write(cout); + cout << endl; + string str; + att->Write(str); + cout << str << endl; + Isis::Pvl pvl; + att->Write(pvl); + cout << pvl << endl; + delete att; + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl << endl; + + + cout << "Testing put members (strings)" << endl; + try { + Isis::CubeAttributeOutput *att = new Isis::CubeAttributeOutput(); + att->Set("bsq"); + att->Set("8bit"); + att->Set("msb"); + att->Set("dETacHEd"); + att->Minimum(1.0); + att->Maximum(2.0); + att->Write(cout); + delete att; + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl << endl; + +} + + +// Function to report everything about an output cube attribute +void ReportOutput (Isis::CubeAttributeOutput *att, string orderHint) { + att->Write(cout); + cout << endl; + Isis::Pvl pvl; + att->Write(pvl); + cout << pvl << endl; + cout << endl; + cout << "Propagate Pixel Type = " << att->PropagatePixelType() << endl; + try { + string tmp = Isis::PixelTypeName(att->PixelType()); + cout << "PixelType = " << tmp << endl; + } + catch (Isis::iException &error) { + error.Report(false); + } + cout << "Propagate Min/Max = " << att->PropagateMinimumMaximum() << endl; + cout << "Minimum = " << att->Minimum() << endl; + cout << "Maximum = " << att->Maximum() << endl; + cout << "FileFormatStr = " << att->FileFormatStr() << endl; + cout << "FileFormat enum = " << CubeFormatName(att->FileFormat()) << endl; + +// cout << "ByteOrderStr = " << att->ByteOrderStr() << endl; +// cout << "ByteOrder enum = " << Isis::ByteOrderName(att->ByteOrder()) << endl; + Isis::ByteOrder oh; + if (orderHint == "SYS") { + if (Isis::IsLsb()) { + oh = Isis::Lsb; + } + else { + oh = Isis::Msb; + } + } + else { + oh = Isis::ByteOrderEnumeration(orderHint); + } + Isis::ByteOrder order = att->ByteOrder(); + if (order == oh) { + cout << "ByteOrder = ok" << endl; + } + else { + cout << "ByteOrder = wrong" << endl; + } + + cout << "Label attachment = "; + if (att->AttachedLabel()) cout << LabelAttachmentName(Isis::AttachedLabel) << endl; + if (att->DetachedLabel()) cout << LabelAttachmentName(Isis::DetachedLabel) << endl; + +#if 0 + fstream stream("CubeAttribute.truth", ios::in| ios::out); + int positions[] = {203, 1520, 1877, 2388, 2767, 3213}; + if (stream.is_open()){ + for (int i = 0 ; i < 6 ; i++){ + stream.seekg(positions[i]); + if (Isis::IsLsb()) + stream.put('L'); + else + stream.put('M'); + } + } + stream.close(); +#endif +} + + + diff --git a/isis/src/base/objs/CubeCalculator/CubeCalculator.cpp b/isis/src/base/objs/CubeCalculator/CubeCalculator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4db1d49a369817a5b1af21dc95be7df0a287b071 --- /dev/null +++ b/isis/src/base/objs/CubeCalculator/CubeCalculator.cpp @@ -0,0 +1,474 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2010/04/08 15:03:37 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#include "CubeCalculator.h" +#include "iString.h" +#include "Statistics.h" + +using namespace std; + +namespace Isis { + + //! Constructor + CubeCalculator::CubeCalculator() { + p_calculations = NULL; + p_methods = NULL; + p_data = NULL; + p_dataDefinitions = NULL; + p_cubeStats = NULL; + + p_calculations = new QVector(); + p_methods = new QVector< void (Calculator::*)( void ) >(); + p_data = new QVector< QVector >(); + p_dataDefinitions = new QVector< DataValue >(); + p_cubeStats = new QVector< Statistics * >(); + + p_outputSamples = 0; + } + + void CubeCalculator::Clear() { + Calculator::Clear(); + + if(p_calculations) { + p_calculations->clear(); + } + + if(p_methods) { + p_methods->clear(); + } + + if(p_data) { + p_data->clear(); + } + + if(p_dataDefinitions) { + p_dataDefinitions->clear(); + } + + if(p_cubeStats) { + p_cubeStats->clear(); + } + } + + /** + * This method will execute the calculations built up when PrepareCalculations was called. + * + * @param cubeData The input cubes' data + * @param curLine The current line in the output cube + * @param curBand The current band in the output cube + * + * @return std::vector The results of the calculations (with Isis Special Pixels) + * + * @throws Isis::iException::Math + */ + QVector CubeCalculator::RunCalculations(QVector &cubeData, int curLine, int curBand) { + // For now we'll only process a single line in this method for our results. In order + // to do more powerful indexing, passing a list of cubes and the output cube will + // be necessary. + int methodIndex = 0; + int dataIndex = 0; + for(int currentCalculation = 0; currentCalculation < p_calculations->size(); + currentCalculation++) { + if((*p_calculations)[currentCalculation] == callNextMethod) { + void (Calculator::*aMethod)() = (*p_methods)[methodIndex]; + (this->*aMethod)(); + methodIndex ++; + } + else { + DataValue &data = (*p_dataDefinitions)[dataIndex]; + if(data.getType() == DataValue::constant) { + Push(data.getContant()); + } + else if(data.getType() == DataValue::band) { + Push(curBand); + } + else if(data.getType() == DataValue::line) { + Push(curLine); + } + else if(data.getType() == DataValue::sample) { + QVector samples; + samples.resize(p_outputSamples); + + for(int i = 0; i < p_outputSamples; i++) { + samples[i] = i+1; + } + + Push(samples); + } + else if(data.getType() == DataValue::cubeData) { + Push(*cubeData[data.getCubeIndex()]); + } + else { + } + + dataIndex ++; + } + } + + if(StackSize() != 1) { + string msg = "Too many operands in the equation."; + throw Isis::iException::Message(Isis::iException::Math, msg, _FILEINFO_); + } + + return Pop(true); + } + + + /** + * This method builds a list of actions to perform based on the postfix expression. + * Error checking is done using the inCubeInfos, and the outCubeInfo is necessary + * to tell the dimensions of the output cube. Call this method before calling + * RunCalculations(). This method will also erase all calculator history before building + * up a new set of calculations to run. + * + * @param equation The equation in postfix notation + * @param inCubes The input cubes + * @param outCube The output cube + */ + void CubeCalculator::PrepareCalculations(iString equation, + QVector &inCubes, + Cube *outCube) { + Clear(); + + p_outputSamples = outCube->Samples(); + + iString eq = equation; + while(eq != "") { + iString token = eq.Token(" "); + + // Step through every part of the postfix equation and set up the appropriate + // action list based on the current token. Attempting to order if-else conditions + // in terms of what would probably be encountered more often. + + // Scalars + if(isdigit(token[0]) || token[0] == '.') { + p_calculations->push_back(pushNextData); + p_dataDefinitions->push_back( DataValue(DataValue::constant, + token.ToDouble()) ); + } + // File, e.g. F1 = first file in list. Must come after any functions starting with 'f' that + // is not a cube. + else if(token[0] == 'f') { + iString tok(token.substr(1)); + int file = tok.ToInteger() - 1; + if(file < 0 || file >= (int)inCubes.size()) { + std::string msg = "Invalid file number [" + tok + "]"; + throw Isis::iException::Message(Isis::iException::Math, msg, _FILEINFO_); + } + + p_calculations->push_back(pushNextData); + p_dataDefinitions->push_back( DataValue(DataValue::cubeData, file) ); + } + else if(token == "band") { + p_calculations->push_back(pushNextData); + p_dataDefinitions->push_back( DataValue(DataValue::band) ); + } + else if(token == "line") { + p_calculations->push_back(pushNextData); + p_dataDefinitions->push_back( DataValue(DataValue::line) ); + } + else if(token == "sample") { + p_calculations->push_back(pushNextData); + p_dataDefinitions->push_back( DataValue(DataValue::sample) ); + } + // Addition + else if(token == "+") { + AddMethodCall(&Isis::Calculator::Add); + } + + // Subtraction + else if(token == "-") { + AddMethodCall(&Isis::Calculator::Subtract); + } + + // Multiplication + else if(token == "*") { + AddMethodCall(&Isis::Calculator::Multiply); + } + + // Division + else if(token == "/") { + AddMethodCall(&Isis::Calculator::Divide); + } + + // Modulus + else if(token == "%") { + AddMethodCall(&Isis::Calculator::Modulus); + } + + // Exponent + else if(token == "^") { + AddMethodCall(&Isis::Calculator::Exponent); + } + + // Negative + else if(token == "--") { + AddMethodCall(&Isis::Calculator::Negative); + } + + // Left shift + else if(token == "<<") { + AddMethodCall(&Isis::Calculator::LeftShift); + } + + // Right shift + else if(token == ">>") { + AddMethodCall(&Isis::Calculator::RightShift); + } + + // Maximum In The Line + else if(token == "linemax") { + AddMethodCall(&Isis::Calculator::MaximumLine); + } + + // Maximum Pixel on a per-pixel basis + else if(token == "max") { + AddMethodCall(&Isis::Calculator::MaximumPixel); + } + + // Minimum In The Line + else if(token == "linemin") { + AddMethodCall(&Isis::Calculator::MinimumLine); + } + + // Minimum Pixel on a per-pixel basis + else if(token == "min") { + AddMethodCall(&Isis::Calculator::MinimumPixel); + } + + // Absolute value + else if(token == "abs") { + AddMethodCall(&Isis::Calculator::AbsoluteValue); + } + + // Square root + else if(token == "sqrt") { + AddMethodCall(&Isis::Calculator::SquareRoot); + } + + // Natural Log + else if(token == "log" || token == "ln") { + AddMethodCall(&Isis::Calculator::Log); + } + + // Log base 10 + else if(token == "log10") { + AddMethodCall(&Isis::Calculator::Log10); + } + + // Pi + else if(token == "pi") { + p_calculations->push_back(pushNextData); + p_dataDefinitions->push_back( + DataValue(DataValue::constant, Isis::PI) + ); + } + + // e + else if(token == "e") { + p_calculations->push_back(pushNextData); + p_dataDefinitions->push_back( + DataValue(DataValue::constant, Isis::E) + ); + } + + // Sine + else if(token == "sin") { + AddMethodCall(&Isis::Calculator::Sine); + } + + // Cosine + else if(token == "cos") { + AddMethodCall(&Isis::Calculator::Cosine); + } + + // Tangent + else if(token == "tan") { + AddMethodCall(&Isis::Calculator::Tangent); + } + + // Secant + else if(token == "sec") { + AddMethodCall(&Isis::Calculator::Secant); + } + + // Cosecant + else if(token == "csc") { + AddMethodCall(&Isis::Calculator::Cosecant); + } + + // Cotangent + else if(token == "cot") { + AddMethodCall(&Isis::Calculator::Cotangent); + } + + // Arcsin + else if(token == "asin") { + AddMethodCall(&Isis::Calculator::Arcsine); + } + + // Arccos + else if(token == "acos") { + AddMethodCall(&Isis::Calculator::Arccosine); + } + + // Arctan + else if(token == "atan") { + AddMethodCall(&Isis::Calculator::Arctangent); + } + + // Arctan2 + else if(token == "atan2") { + AddMethodCall(&Isis::Calculator::Arctangent2); + } + + // SineH + else if(token == "sinh") { + AddMethodCall(&Isis::Calculator::SineH); + } + + // CosH + else if(token == "cosh") { + AddMethodCall(&Isis::Calculator::CosineH); + } + + // TanH + else if(token == "tanh") { + AddMethodCall(&Isis::Calculator::TangentH); + } + + // Less than + else if(token == "<") { + AddMethodCall(&Isis::Calculator::LessThan); + } + + // Greater than + else if(token == ">") { + AddMethodCall(&Isis::Calculator::GreaterThan); + } + + // Less than or equal + else if(token == "<=") { + AddMethodCall(&Isis::Calculator::LessThanOrEqual); + } + + // Greater than or equal + else if(token == ">=") { + AddMethodCall(&Isis::Calculator::GreaterThanOrEqual); + } + + // Equal + else if(token == "==") { + AddMethodCall(&Isis::Calculator::Equal); + } + + // Not equal + else if(token == "!=") { + AddMethodCall(&Isis::Calculator::NotEqual); + } + + // Maximum in a cube + else if(token == "cubemax") { + int cubeIndex = LastPushToCubeStats(inCubes); + + p_calculations->push_back(pushNextData); + p_dataDefinitions->push_back( + DataValue(DataValue::constant, (*p_cubeStats)[cubeIndex]->Maximum()) + ); + } + + // Maximum in a cube + else if(token == "cubemin") { + int cubeIndex = LastPushToCubeStats(inCubes); + + p_calculations->push_back(pushNextData); + p_dataDefinitions->push_back( + DataValue(DataValue::constant, (*p_cubeStats)[cubeIndex]->Minimum()) + ); + } + + // Ignore empty token + else if(token == "") { } + + else { + string msg = "Unidentified operator ["; + msg += token + "]"; + throw Isis::iException::Message(Isis::iException::Math, msg, _FILEINFO_); + } + } // while loop + } + + int CubeCalculator::LastPushToCubeStats(QVector &inCubes) { + if(!p_calculations->size()) { + string msg = "Not sure which file to get statistics from"; + throw Isis::iException::Message(Isis::iException::Math, msg, _FILEINFO_); + } + + if((*p_calculations)[p_calculations->size() - 1] != pushNextData) { + string msg = "This function must not contain calculations,"; + msg += " only input cubes may be specified."; + throw Isis::iException::Message(Isis::iException::Math, msg, _FILEINFO_); + } + + p_calculations->pop_back(); + + // This must have data if calculations had data that equaled push data + DataValue lastData = (*p_dataDefinitions)[p_dataDefinitions->size() - 1]; + + if(lastData.getType() != DataValue::cubeData) { + string msg = "This function must not contain constants,"; + msg += " only input cubes may be specified."; + throw Isis::iException::Message(Isis::iException::Math, msg, _FILEINFO_); + } + + int cubeStatsIndex = lastData.getCubeIndex(); + p_dataDefinitions->pop_back(); + + // Member variables are now cleaned up, we need to verify the stats exists + + // Make sure room exists in the vector + while(p_cubeStats->size() < cubeStatsIndex + 1) { + p_cubeStats->push_back(NULL); + } + + // Now we can for sure put the stats object in the right place... put it + // there + if((*p_cubeStats)[cubeStatsIndex] == NULL) { + (*p_cubeStats)[cubeStatsIndex] = inCubes[cubeStatsIndex]->Statistics(); + } + + return cubeStatsIndex; + } + + /** + * This is a conveinience method for PrepareCalculations(...). + * This will cause RunCalculations(...) to execute this method in order. + * + * @param method The method to call, i.e. &Isis::Calculator::Multiply + */ + void CubeCalculator::AddMethodCall(void (Calculator::*method)( void )) { + p_calculations->push_back(callNextMethod); + p_methods->push_back(method); + } +} // End of namespace Isis diff --git a/isis/src/base/objs/CubeCalculator/CubeCalculator.h b/isis/src/base/objs/CubeCalculator/CubeCalculator.h new file mode 100644 index 0000000000000000000000000000000000000000..532bcac94073886a47fe455e25a7c60491ef981b --- /dev/null +++ b/isis/src/base/objs/CubeCalculator/CubeCalculator.h @@ -0,0 +1,184 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2010/04/08 15:03:37 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +// Calculator.h +#ifndef CUBE_CALCULATOR_H_ +#define CUBE_CALCULATOR_H_ + +#include "Calculator.h" +#include "Cube.h" + +template class QVector; + +namespace Isis { + class DataValue; + +/** + * @brief Calculator for arrays + * + * This class is a RPN calculator on cubes. The base Calculator class + * is used in conjunction with methods to retrieve data from a cube + * and perform calculations. + * + * @ingroup Math + * + * @author 2008-03-26 Steven Lambright + * + * @internal + * @history 2008-05-12 Steven Lambright - Removed references to CubeInfo + * @history 2008-06-18 Steven Lambright - Fixed documentation + * @history 2009-03-03 Steven Lambright - Added missing secant method call + * @history 2010-02-23 Steven Lambright - Added min2,max2 + * @history 2010-04-08 Steven Lambright - Replaced min2,max2 with proper + * implementations of cubemin, cubemax, linemin, linemax, min and max. + * Added support for getting statistics of a cube for constants. + */ + class CubeCalculator : Calculator { + public: + CubeCalculator(); + + /** + * This method completely resets the calculator. The prepared + * calculations will be erased when this is called. + */ + void Clear(); + + void PrepareCalculations(iString equation, + QVector &inCubes, + Cube *outCube); + + QVector RunCalculations(QVector &cubeData, + int line, int band); + + private: + /** + * This is used to define + * the overall action to perform in + * RunCalculations(..). + */ + enum calculations { + //! The calculation requires calling one of the methods + callNextMethod, + //! The calculation requires input data + pushNextData + }; + + void AddMethodCall(void (Calculator::*method)( void )); + + int LastPushToCubeStats(QVector &inCubes); + + /** + * This is what RunCalculations(...) will loop over. + * The action to perform (push data or execute calculation) + * is defined in this vector. + */ + QVector< calculations > *p_calculations; + + /** + * This stores the addresses to the methods RunCalculations(...) + * will call + */ + QVector< void (Calculator::*)( void ) > *p_methods; + + /** + * This stores the addressed to the methods RunCalculations(...) + * will push (constants), along with placeholders for simplicity to + * keep synchronized with the data definitions. + */ + QVector< QVector > *p_data; + + /** + * This defines what kind of data RunCalculations(...) will push + * onto the calculator. Constants will be taken from p_data, which + * is synchronized (index-wise) with this vector. + */ + QVector< DataValue > *p_dataDefinitions; + + QVector *p_cubeStats; + + int p_outputSamples; + }; + + class DataValue { + public: + /** + * This is used to tell what kind of data to + * push onto the RPN calculator. + */ + enum dataValueType { + constant, //!< a single constant value + sample, //!< current sample number + line, //!< current line number + band, //!< current band number + cubeData //!< a brick of cube data + }; + + DataValue() { + p_type = (dataValueType)-1; + p_cubeIndex = -1; + p_constantValue = 0.0; + } + + DataValue(dataValueType type) { + p_type = type; + p_constantValue = 0.0; + p_cubeIndex = -1; + } + + DataValue(dataValueType type, int cubeIndex) { + p_type = type; + p_constantValue = 0.0; + + if(type == cubeData) { + p_cubeIndex = cubeIndex; + } + } + + DataValue(dataValueType type, double value) { + p_type = type; + p_cubeIndex = -1; + + if(type == constant) { + p_constantValue = value; + } + } + + dataValueType getType() { + return p_type; + } + + int getCubeIndex() { + return p_cubeIndex; + } + + double getContant() { + return p_constantValue; + } + + private: + int p_cubeIndex; + double p_constantValue; + + dataValueType p_type; + }; +} +#endif diff --git a/isis/src/base/objs/CubeCalculator/CubeCalculator.truth b/isis/src/base/objs/CubeCalculator/CubeCalculator.truth new file mode 100644 index 0000000000000000000000000000000000000000..850a35721a48f7962fc86c90712fe1b1d3af6160 --- /dev/null +++ b/isis/src/base/objs/CubeCalculator/CubeCalculator.truth @@ -0,0 +1,28 @@ +CubeCalculator unit test +------------------------ + +EQUATION: sample line + -- band * +Line 1 Band 1 +-2 +-3 +-4 +Line 2 Band 1 +-3 +-4 +-5 +Line 3 Band 1 +-4 +-5 +-6 +Line 1 Band 2 +-4 +-6 +-8 +Line 2 Band 2 +-6 +-8 +-10 +Line 3 Band 2 +-8 +-10 +-12 diff --git a/isis/src/base/objs/CubeCalculator/Makefile b/isis/src/base/objs/CubeCalculator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3925f143133d4185de72a30a4a9ae6f387a2af14 --- /dev/null +++ b/isis/src/base/objs/CubeCalculator/Makefile @@ -0,0 +1,5 @@ +INCS = CubeCalculator.h +SRCS = CubeCalculator.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CubeCalculator/unitTest.cpp b/isis/src/base/objs/CubeCalculator/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8a8d041ea91c7f835124c96fde2126b8d0175a1 --- /dev/null +++ b/isis/src/base/objs/CubeCalculator/unitTest.cpp @@ -0,0 +1,42 @@ +#include + +#include "CubeCalculator.h" +#include "ProcessByLine.h" +#include "CubeAttribute.h" +#include "LineManager.h" +#include "Preference.h" + +using namespace Isis; + +int main(int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + Isis::CubeCalculator c; + Isis::ProcessByLine p; + + Isis::CubeAttributeInput att; + + Isis::Cube *icube = p.SetInputCube("unitTest.cub", att); + std::cout << "CubeCalculator unit test" << std::endl; + std::cout << "------------------------" << std::endl << std::endl; + + std::string postfix = "sample line + -- band *"; + QVector iCubes; + iCubes.push_back(icube); + c.PrepareCalculations(postfix, iCubes, icube); + + std::cout << "EQUATION: " << postfix << std::endl; + + Isis::LineManager mgr(*icube); + mgr.SetLine(1); + QVector cubeData; + cubeData.push_back(&mgr); + + while(!mgr.end()) { + QVector res = c.RunCalculations(cubeData, mgr.Line(), mgr.Band()); + + std::cout << "Line " << mgr.Line() << " Band " << mgr.Band() << std::endl; + for(int i = 0; i < (int)res.size(); i++) std::cout << res[i] << std::endl; + mgr ++; + } +} diff --git a/isis/src/base/objs/CubeDataThread/CubeDataThread.cpp b/isis/src/base/objs/CubeDataThread/CubeDataThread.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a843d2e8dc48b3df77579bf771aea18dcb3c1a94 --- /dev/null +++ b/isis/src/base/objs/CubeDataThread/CubeDataThread.cpp @@ -0,0 +1,647 @@ +#include "CubeDataThread.h" + +#include +#include +#include +#include +#include + +#include "iString.h" +#include "Filename.h" +#include "Brick.h" +#include "Cube.h" + +namespace Isis { + + /** + * This constructs a CubeDataThread(). This will spawn a new thread and + * move the ownership of this instance to itself (so slots are called + * in this self-contained thread). + * + */ + CubeDataThread::CubeDataThread() { + p_managedCubes = NULL; + p_managedData = NULL; + p_managedCubesMutex = NULL; + p_managedDataSources = NULL; + + p_managedCubes = new QMap< int, QPair< bool, Isis::Cube * > >; + p_managedData = new QList< QPair >; + p_managedCubesMutex = new QMutex(); + p_managedDataSources = new QList< int >; + + p_numChangeListeners = 0; + p_currentLocksWaiting = 0; + p_currentId = 1; // start with ID == 1 + + // Start this thread's event loop and make it so the slots are contained + // within this thread (this class automatically runs in its own thread) + start(); + moveToThread(this); + } + + + /** + * This class is a self-contained thread, so normally it would be bad to + * simply delete it. However, this destructor will synchronize the shutdown + * of the thread so you can safely delete an instance of this class without + * using the deleteLater() method. + * + */ + CubeDataThread::~CubeDataThread() { + // Shutdown the event loop(s) + QThread::exit(0); + + while(!isFinished()) { + QThread::yieldCurrentThread(); + } + + // Destroy the bricks still in memory + if(p_managedData) { + for(int i = p_managedData->size() - 1; i >= 0; i--) { + delete (*p_managedData)[i].first; + delete (*p_managedData)[i].second; + p_managedData->removeAt(i); + } + } + + // Destroy the cubes still in memory + if(p_managedCubes) { + for(int i = p_managedCubes->size() - 1; i >= 0; i--) { + if ((p_managedCubes->end() - 1)->first) // only delete if we own it! + delete (p_managedCubes->end() - 1).value().second; + p_managedCubes->erase(p_managedCubes->end() - 1); + } + } + + // Destroy the mutex that controls access to the cubes + if(p_managedCubesMutex) { + delete p_managedCubesMutex; + p_managedCubesMutex = NULL; + } + + // Destroy the data sources vector + if(p_managedDataSources) { + delete p_managedDataSources; + p_managedDataSources = NULL; + } + } + + /** + * This method is designed to be callable from any thread before data is + * requested, though no known side effects exist if this is called during + * other I/O operations (though I don't recommend it). + * + * If possible, the cube will be opened with R/W permissions, otherwise it + * will be opened with read-only access + * + * @param fileName The cube to open + * @param mustOpenReadWrite If true and cube has read-only access then an + * exception will be thrown + * + * @return int The cube ID necessary for retrieving information about this cube + * in the future. + */ + int CubeDataThread::AddCube(const Isis::Filename &fileName, + bool mustOpenReadWrite) { + Isis::Cube * newCube = new Isis::Cube(); + + try { + newCube->Open(fileName.Expanded(), "rw"); + } + catch(Isis::iException &e) { + if(!mustOpenReadWrite) { + e.Clear(); + newCube->Open(fileName.Expanded(), "r"); + } + else { + throw; + } + } + + p_managedCubesMutex->lock(); + + int newId = p_currentId; + p_currentId ++; + + QPair< bool, Cube * > newEntry; + newEntry.first = true; // we own this! + newEntry.second = newCube; + p_managedCubes->insert(newId, newEntry); + + p_managedCubesMutex->unlock(); + + return newId; + } + + + /** + * This method is designed to be callable from any thread before data is + * requested, though no known side effects exist if this is called during + * other I/O operations (though I don't recommend it). + * + * Ownership is not taken of this cube + * + * @param cube The cube to encapsulate + * + * @return int The cube ID necessary for retrieving information about this cube + * in the future. + */ + int CubeDataThread::AddCube(Isis::Cube *cube) { + p_managedCubesMutex->lock(); + + int newId = p_currentId; + p_currentId ++; + + QPair< bool, Cube * > newEntry; + newEntry.first = false; // we don't own this! + newEntry.second = cube; + p_managedCubes->insert(newId, newEntry); + + p_managedCubesMutex->unlock(); + + return newId; + } + + + /** + * You must call this method after connecting to the BrickChanged signal, + * otherwise you are not guaranteed a good Brick pointer. + */ + void CubeDataThread::AddChangeListener() { + p_numChangeListeners ++; + } + + + /** + * You must call this method after disconnecting from the BrickChanged signal, + * otherwise bricks cannot be freed from memory. + */ + void CubeDataThread::RemoveChangeListener() { + p_numChangeListeners --; + } + + + + /** + * This helper method reads in cube data and handles the locking of similar + * bricks appropriately. + * + * @param cubeId Cube ID To Read From + * @param ss Starting Sample Position + * @param sl Starting Line Position + * @param es Ending Sample Position + * @param el Ending Line Position + * @param band Band Number To Read From (multi-band bricks not supported at this + * time) + * @param caller A pointer to the calling class, used to identify who requested + * the data when they receive either the ReadReady or the + * ReadWriteReady signal + * @param sharedLock True if read-only, false if read-write + */ + void CubeDataThread::GetCubeData(int cubeId, int ss, int sl, + int es, int el, int band, + void *caller, bool sharedLock) { + Isis::Brick * requestedBrick = NULL; + + p_managedCubesMutex->lock(); + requestedBrick = new Isis::Brick(*p_managedCubes->value(cubeId).second, + es - ss + 1, + el - sl + 1, 1); + requestedBrick->SetBasePosition(ss, sl, band); + p_managedCubesMutex->unlock(); + + // See if we already have this brick + int instance = 0; + int exactIndex = -1; + bool exactMatch = false; + int index = OverlapIndex(requestedBrick, cubeId, instance, exactMatch); + + while(index != -1) { + if(sharedLock) { + // make sure we can get read locks on exact overlaps + // We need to try to get the lock to verify partial overlaps not + // write locked and only keep read locks on exact matches. + AcquireLock((*p_managedData)[index].first, true); + + if(!exactMatch) { + (*p_managedData)[index].first->unlock(); + } + } + else { + AcquireLock((*p_managedData)[index].first, false); + + // we arent actually writing to this, but now we know we can delete it + (*p_managedData)[index].first->unlock(); + + // destroy things that overlap but arent the same when asking to write + if(!exactMatch && FreeBrick(index)) { + instance --; + } + } + + if(exactMatch) { + exactIndex = index; + } + + instance++; + index = OverlapIndex(requestedBrick, cubeId, instance, exactMatch); + } + + if(exactIndex == -1) { + p_managedCubesMutex->lock(); + + p_managedCubes->value(cubeId).second->Read(*requestedBrick); + + QPair managedDataEntry; + + managedDataEntry.first = new QReadWriteLock(); + + AcquireLock(managedDataEntry.first, sharedLock); + + managedDataEntry.second = requestedBrick; + p_managedData->push_back(managedDataEntry); + p_managedDataSources->push_back(cubeId); + exactIndex = p_managedData->size() - 1; + + p_managedCubesMutex->unlock(); + } + + if(sharedLock) { + emit ReadReady(caller, cubeId, (*p_managedData)[exactIndex].second); + } + else { + emit ReadWriteReady(caller, cubeId, (*p_managedData)[exactIndex].second); + } + + } + + + /** + * This method is exclusively used to acquire locks. This handles the problem + * of being unable to receive signals that would free locks while waiting for + * a lock to be made. + * + * @param lockObject Lock object we're trying to acquire a lock on + * @param readLock True if we're trying for read lock, false for read/write + */ + void CubeDataThread::AcquireLock(QReadWriteLock *lockObject, bool readLock) { + if(readLock) { + while(!lockObject->tryLockForRead()) { + // while we can't get the lock, allow other processing to happen for + // brief periods of time + // + // Give time for things to happen in other threads + QThread::yieldCurrentThread(); + + p_currentLocksWaiting ++; + QEventLoop eventLoop; + eventLoop.processEvents(); + p_currentLocksWaiting --; + } + } + else { + while(!lockObject->tryLockForWrite()) { + // while we can't get the lock, allow other processing to happen for + // brief periods of time + // + // Give time for things to happen in other threads + QThread::yieldCurrentThread(); + + p_currentLocksWaiting ++; + QEventLoop eventLoop; + eventLoop.processEvents(); + p_currentLocksWaiting --; + } + } + } + + + /** + * This slot should be connected to and upon receiving a signal it will begin + * the necessary cube I/O to get this data. When the data is available, a + * ReadReady signal will be emitted with the parameter caller being equal to + * the requester pointer in the signal. You should pass "this" for caller, and + * you must ignore all ReadReady signals which do not have "requester == this" + * -> otherwise your pointer is not guaranteed. + * + * @param cubeId Cube to read from + * @param startSample Starting Sample Position + * @param startLine Starting Line Position + * @param endSample Ending Sample Position + * @param endLine Ending Line Position + * @param band Band Number To Read From (multi-band bricks not supported at this + * time) + * @param caller A pointer to the calling class, used to identify who requested + * the data when they receive the ReadReady signal + */ + void CubeDataThread::ReadCube(int cubeId, int startSample, int startLine, + int endSample, int endLine, int band, + void *caller) { + + if (!p_managedCubes->contains(cubeId)) + { + iString msg = "cube ID ["; + msg += iString(cubeId); + msg += "] is not a valid cube ID"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + GetCubeData(cubeId, startSample, startLine, endSample, endLine, band, + caller, true); + } + + + /** + * This slot should be connected to and upon receiving a signal it will begin + * the necessary cube I/O to get this data. When the data is available, a + * ReadWriteReady signal will be emitted with the parameter caller being equal + * to the requester pointer in the signal. You should pass "this" for caller, + * and you must ignore all ReadReady signals which do not have "requester == + * this" -> otherwise your pointer is not guaranteed and you are corrupting the + * process of the real requester. + * + * @param cubeId Cube to read from + * @param startSample Starting Sample Position + * @param startLine Starting Line Position + * @param endSample Ending Sample Position + * @param endLine Ending Line Position + * @param band Band Number To Read From (multi-band bricks not supported at this + * time) + * @param caller A pointer to the calling class, used to identify who requested + * the data when they receive the ReadWriteReady signal + */ + void CubeDataThread::ReadWriteCube(int cubeId, int startSample, int startLine, + int endSample, int endLine, int band, + void *caller) { + + if (!p_managedCubes->contains(cubeId)) + { + iString msg = "cube ID ["; + msg += iString(cubeId); + msg += "] is not a valid cube ID"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + GetCubeData(cubeId, startSample, startLine, endSample, endLine, band, + caller, false); + } + + + /** + * This is a searching method used to identify overlapping data already in + * memory. + * + * @param overlapping Brick to check for overlaps with + * @param cubeId Cube ID asssociated with this brick + * @param instanceNum Which instance of overlap to return + * @param exact This is set to false if the match found is not exactly + * the overlapping brick. + * + * @return int -1 for none found, otherwise the index into p_managedData and + * p_managedDataSources that an overlap was found at + */ + int CubeDataThread::OverlapIndex(const Isis::Brick *overlapping, + int cubeId, + int instanceNum, + bool &exact) { + exact = false; + + // Start with extracting the range of the input (search) brick + int startSample = overlapping->Sample(0); + int endSample = overlapping->Sample(overlapping->size()-1); + int startLine = overlapping->Line(0); + int endLine = overlapping->Line(overlapping->size()-1); + int startBand = overlapping->Band(0); + int endBand = overlapping->Band(overlapping->size()-1); + + // Now let's search for overlaps + for(int knownBrick = 0; + knownBrick < p_managedData->size(); + knownBrick++) { + int sourceCube = (*p_managedDataSources)[knownBrick]; + + // Ignore other cubes; they can't overlap + if(sourceCube != cubeId) continue; + + QPair &managedBrick = + (*p_managedData)[knownBrick]; + + Isis::Brick &brick = *managedBrick.second; + + // Get the range of this brick we've found in memory to see if any overlap + // exists + int compareSampStart = brick.Sample(0); + int compareSampEnd = brick.Sample(brick.size()-1); + int compareLineStart = brick.Line(0); + int compareLineEnd = brick.Line(brick.size()-1); + int compareBandStart = brick.Band(0); + int compareBandEnd = brick.Band(brick.size()-1); + + bool overlap = false; + + // sample start is inside our sample range + if(compareSampStart >= startSample && compareSampStart <= endSample) { + overlap = true; + } + + // sample end is inside our sample range + if(compareSampEnd >= startSample && compareSampEnd <= endSample) { + overlap = true; + } + + // line start is in our line range + if(compareLineStart >= startLine && compareLineStart <= endLine) { + overlap = true; + } + + // line end is in our line range + if(compareLineEnd >= startLine && compareLineEnd <= endLine) { + overlap = true; + } + + // band start is in our line range + if(compareBandStart >= startBand && compareBandStart <= endBand) { + overlap = true; + } + + // band end is in our line range + if(compareBandEnd >= startBand && compareBandEnd <= endBand) { + overlap = true; + } + + exact = false; + if(compareSampStart == startSample && + compareSampEnd == endSample && + compareLineStart == startLine && + compareLineEnd == endLine && + compareBandStart == startBand && + compareBandEnd == endBand) { + exact = true; + } + + // If we have overlap, and we're at the requested instance of overlap, + // return it. + if(overlap) { + instanceNum --; + + if(instanceNum < 0) return knownBrick; + } + } + + // None found at this instance + return -1; + } + + + /** + * When done processing with a brick (reading or writing) this slot needs to + * be signalled to free locks and memory. + * + * @param cubeId Cube associated with the brick + * @param brickDone Brick pointer given by ReadReady, ReadWriteReady or + * BrickChanged. An equivalent brick is also acceptable + * (exact same range, but not same pointer). + */ + void CubeDataThread::DoneWithData(int cubeId, const Isis::Brick *brickDone) { + int instance = 0; + bool exactMatch = false; + bool writeLock = false; + + int index = OverlapIndex(brickDone, cubeId, instance, exactMatch); + + while(index != -1) { + // If this isn't the data they're finished with, we don't care about it + if(!exactMatch) { + instance++; + index = OverlapIndex(brickDone, cubeId, instance, exactMatch); + continue; + } + + // Test if we had a write lock (tryLockForRead will fail). If we had a + // write lock make note of it. + if(!(*p_managedData)[index].first->tryLockForRead()) { + if(writeLock) { + Isis::iString msg = "Overlapping data had write locks"; + throw Isis::iException::Message(Isis::iException::Programmer, + msg, + _FILEINFO_); + } + + writeLock = true; + } + // A read lock was in place, undo the lock we just made + else { + if(writeLock) { + Isis::iString msg = "Overlapping data had write locks"; + throw Isis::iException::Message(Isis::iException::Programmer, + msg, + _FILEINFO_); + } + + // Unlock the lock we just made + (*p_managedData)[index].first->unlock(); + } + + // If we had a write lock we need to write the data to the file and + // notify others of the change if we have listeners. + if(writeLock) { + p_managedCubesMutex->lock(); + Isis::Brick cpy(*brickDone); + p_managedCubes->value(cubeId).second->Write(cpy); + p_managedCubesMutex->unlock(); + + // Unlock the existing lock + (*p_managedData)[index].first->unlock(); + + // No listeners? Remove this entry + if(p_numChangeListeners == 0) { + if(FreeBrick(index)) { + // We've freed the one and only match, nobody wants to know about + // it, so we're done + break; + } + } + // We have listeners, lock the data the appropriate number of times and + // then emit the BrickChanged with a pointer + else { + // notify others of this change + for(int i = 0; i < p_numChangeListeners; i++) { + AcquireLock((*p_managedData)[index].first, true); + } + + emit BrickChanged((*p_managedDataSources)[index], + (*p_managedData)[index].second); + } + } + // if we had a read lock and no longer have any locks, remove data from + // list + else { + // We had the one and only (hopefully!) exact match, let's free it if + // we can get a write lock and be done. + // Free original read lock + (*p_managedData)[index].first->unlock(); + + if((*p_managedData)[index].first->tryLockForWrite()) { + (*p_managedData)[index].first->unlock(); + FreeBrick(index); + } + + break; + } + + instance++; + index = OverlapIndex(brickDone, cubeId, instance, exactMatch); + } + } + + + /** + * This is used internally to delete bricks when possible. + * + * @param brickIndex Brick to request deletion + * + * @return bool True if deletion actually happened + */ + bool CubeDataThread::FreeBrick(int brickIndex) { + if(!(*p_managedData)[brickIndex].first->tryLockForWrite()) { + std::cerr << "WARNING: UNSAFE FreeBrick CALL, LOCKS EXIST" << std::endl; + } + else { + (*p_managedData)[brickIndex].first->unlock(); + } + + if(p_currentLocksWaiting == 0) { + delete (*p_managedData)[brickIndex].first; + delete (*p_managedData)[brickIndex].second; + + p_managedData->removeAt(brickIndex); + p_managedDataSources->removeAt(brickIndex); + + // Try to free any leftover bricks too + for(int i = 0; i < p_managedData->size(); i++) { + if((*p_managedData)[i].first->tryLockForWrite()) { + p_managedData->removeAt(i); + p_managedDataSources->removeAt(i); + i --; + } + } + + return true; + } + + // no actual free was done + return false; + } + + + /** + * This is a helper method for both testing/debugging and general information + * that provides the current number of bricks in memory. + * + * @return int Count of how many bricks reside in memory. + */ + int CubeDataThread::BricksInMemory() { + return p_managedData->size(); + } +}; diff --git a/isis/src/base/objs/CubeDataThread/CubeDataThread.h b/isis/src/base/objs/CubeDataThread/CubeDataThread.h new file mode 100644 index 0000000000000000000000000000000000000000..22e74319deeb8f0aff78ec079235086500ce75f2 --- /dev/null +++ b/isis/src/base/objs/CubeDataThread/CubeDataThread.h @@ -0,0 +1,180 @@ +#ifndef CubeDataThread_h +#define CubeDataThread_h + +#include +#include + +namespace Isis { + class Cube; + class Filename; + class Brick; +}; + +template class QList; + +template class QPair; +template class QMap; + +class QReadWriteLock; +class QMutex; + +namespace Isis { + + /** + * @brief Encapsulation of Cube I/O with Change Notifications + * + * The main purpose of this class is to create cube change notifications, + * ideal for GUI's with changing cubes. This class is designed to encapsulate + * Cube I/O into a separate thread and serializes each cube I/O. This class + * also speeds up I/O by reusing bricks instead of always reading from the + * disk. + * + * This is not a full concurrency control/transaction handler. Consistent + * states are not guaranteed, though a consistent state for any given brick + * is, and results from reads do not guaranteed serial equivalence. Deadlocks + * are possible, if two processes want to R/W to the same sections of data, + * and it is up to the users of this class to avoid such conditions. + * + * @author 2010-01-15 Steven Lambright + * + * @internal + * @history 2010-04-12 Eric Hyer - Added check for valid cube ID's for slots + * ReadCube and ReadWriteCube + * + * @todo Add state recording/reverting functionality + * + */ + class CubeDataThread : public QThread { + Q_OBJECT + + public: + CubeDataThread(); + virtual ~CubeDataThread(); + + int AddCube(const Isis::Filename &fileName, + bool mustOpenReadWrite = false); + + int AddCube(Isis::Cube *cube); + + void AddChangeListener(); + void RemoveChangeListener(); + + int BricksInMemory(); + + public slots: + void ReadCube(int cubeId, int startSample, int startLine, + int endSample, int endLine, int band, void *caller); + void ReadWriteCube(int cubeId, int startSample, int startLine, + int endSample, int endLine, int band, void *caller); + + void DoneWithData(int, const Isis::Brick *); + + signals: + /** + * This signal will be emitted when ReadCube has finished processing. + * + * When done with the data, given you are the requester, you call the + * DoneWithData slot (via a signal). + * + * @param requester Pointer to the calling class (must ignore all + * ReadReady signals where this != requester) + * @param cubeId Cube ID of the cube the data is from + * @param data The data in the cube + */ + void ReadReady(void *requester, int cubeId, const Isis::Brick *data); + + /** + * This signal will be emitted when ReadWriteCube has finished processing. + * + * When done with the data, given you are the requester, you call the + * DoneWithData slot (via a signal). + * + * @param requester Pointer to the calling class (must ignore all + * ReadReady signals where this != requester) + * @param cubeId Cube ID of the cube the data is from + * @param data The data in the cube, also where you should write changes + */ + void ReadWriteReady(void *requester, int cubeId, Isis::Brick *data); + + /** + * DO NOT CONNECT TO THIS SIGNAL WITHOUT CALLING AddChangeListener(). + * + * When a write occurs, and change listeners exist, this signal is emitted + * with the new data. + * + * When done with the data, given you are the requester, you call the + * DoneWithData slot (via a signal). + * + * @param cubeId Cube ID of the change + * @param data Area written to the cube + */ + void BrickChanged(int cubeId, const Isis::Brick *data); + + private: + int OverlapIndex(const Isis::Brick *initial, int cubeId, + int instanceNum, bool &exact); + + void GetCubeData(int cubeId, int ss, int sl, int es, int el, int band, + void *caller, bool sharedLock); + + void AcquireLock(QReadWriteLock *lockObject, bool readLock); + + bool FreeBrick(int brickIndex); + + /** + * This is a list of the opened cubes. Since opening cubes is allowed in + * other threads (via AddCube(...)) and is accessed with many threads, all + * operations on this map must be serialized (non-simultaneous). The + * p_managedCubesMutex enables this. + * + */ + QMap< int, QPair< bool, Isis::Cube * > > * p_managedCubes; + + //! This locks the member variable p_managedCubes + QMutex * p_managedCubesMutex; + + /** + * This is a list of bricks in memory and their locks. The following + * assumptions are vital or at least important for understanding this data + * structure: + * 1) No two bricks have the exact same area. + * 2) Deletions may only happen in the destructor or in FreeBrick(int) + * 3) A brick with no locks on it is available for deletion later, but + * may not be deleted if p_currentLocksWaiting != 0 (something is + * attempting a lock somewhere else). + * 4) Bricks may overlap, but locks only pertain to exact matches. + * 5) If you want to make an exclusive (R/W) lock on a brick, you must + * first make all overlapping bricks available for deletion (and/or + * delete) + * 6) If you wish to make a shared (R) lock on a brick, no overlapping + * bricks can be write locked. + * 7) All operations happen in this thread in order to prevent checks + * happening for access executing simultaneously, at least more + * than AcquireLock() allows. + * 8) New bricks must be appended to the end of this list. + * 8) Searches for conflicts must start at the beginning of this list + * and proceed to the end. + * 10) No NULL or invalid pointers may exist in this list. + */ + QList< QPair > * p_managedData; + + //! This is the associated cube ID with each brick + QList< int > * p_managedDataSources; + + //! This is the number of shaded locks to put on a brick when changes made + int p_numChangeListeners; + + //! This is the unique id counter for cubes + unsigned int p_currentId; + + /** + * Number of locks being attempted that re-entered the event loop. As long + * as this isn't zero, no bricks should be removed from p_managedData. + */ + unsigned int p_currentLocksWaiting; + }; + +}; + + +#endif diff --git a/isis/src/base/objs/CubeDataThread/CubeDataThread.truth b/isis/src/base/objs/CubeDataThread/CubeDataThread.truth new file mode 100644 index 0000000000000000000000000000000000000000..5486d716b5275f5267a3295b13b8fe73dd23cd38 --- /dev/null +++ b/isis/src/base/objs/CubeDataThread/CubeDataThread.truth @@ -0,0 +1,122 @@ +=============== Testing Basic Read =============== + CubeDataThreadTester::ReadBrick + Requester is me? Yes + Data: + 0 0 20 20 + + Notify done with this brick + + +=============== Testing Multiple Non-Conflicting Cube Reads =============== + CubeDataThreadTester::ReadBrick + Requester is me? Yes + Data: + 0 0 0 20 20 20 + + CubeDataThreadTester::ReadBrick + Requester is me? Yes + Data: + 1221 1206 1221 + + Notify done with this brick + Notify done with first brick + + +=============== Testing Exact Overlap Cube Reads =============== + + CubeDataThreadTester::ReadBrick + Requester is me? Yes + Data: + 20 20 + + CubeDataThreadTester::ReadBrick + Requester is me? Yes + Data: + 20 20 + + Notify done with this brick + Notify done with first brick + + +=============== Testing Basic R/W =============== + + CubeDataThreadTester::ReadWriteBrick + Changing Brick : Index 0 Becoming 5 + + Old Data: + 2 3 3 4 + New Data: + 5 3 3 4 + + Notify done with this brick + CubeDataThreadTester::ReadBrick + Requester is me? Yes + Data: + 5 3 3 4 + + Notify done with this brick + + +=============== Testing Multiple Non-Conflicting Cube R/W =============== + + CubeDataThreadTester::ReadWriteBrick + Changing Brick : Index 0 Becoming 5 + + Old Data: + 5 3 4 + New Data: + 5 3 4 + + CubeDataThreadTester::ReadWriteBrick + Changing Brick : Index 0 Becoming 5 + + Old Data: + 2 3 4 + New Data: + 5 3 4 + + Notify done with this brick + Notify done with first brick + + +=============== Testing Conflicting Cube R/W =============== + CubeDataThreadTester::ReadWriteBrick + Changing Brick : Index 0 Becoming 5 + + Old Data: + 5 3 4 + New Data: + 5 3 4 + + Breaking Deadlock From Test 3 + Notify done with first brick + CubeDataThreadTester::ReadWriteBrick + Changing Brick : Index 0 Becoming 5 + + Old Data: + 5 3 4 + New Data: + 5 3 4 + + Notify done with this brick + + +=============== Testing Change Notification =============== + CubeDataThreadTester::ReadWriteBrick + Changing Brick : Index 0 Becoming 5 + + Old Data: + 6 + New Data: + 5 + + Notify done with this brick + CubeDataThreadTester::BrickChanged + Data: + 5 + + +Cleanup Tester +Cleanup Cubes +Deleting Temporary R/W Cubes +Unit Test Complete diff --git a/isis/src/base/objs/CubeDataThread/CubeDataThreadTester.cpp b/isis/src/base/objs/CubeDataThread/CubeDataThreadTester.cpp new file mode 100644 index 0000000000000000000000000000000000000000..940d6690aba52acf9d4a97cc23c7901e397eed0e --- /dev/null +++ b/isis/src/base/objs/CubeDataThread/CubeDataThreadTester.cpp @@ -0,0 +1,374 @@ +#include "CubeDataThreadTester.h" + +#include + +#include +#include +#include +#include +#include + +#include "CubeDataThread.h" +#include "iString.h" +#include "Filename.h" +#include "Brick.h" +#include "Cube.h" + +using namespace std; +using namespace Isis; + +namespace Isis { + /** + * This initializes a CubeDataThreadTester. The CubeDataThread given is the + * subject of the tests. + * + * @param testObject The CubeDataThread instance to be tested + */ + CubeDataThreadTester::CubeDataThreadTester(CubeDataThread *testObject) : + QThread() { + p_cachedDoneBricks = NULL; + p_cubeDataThread = testObject; + p_numTestsDone = 0; + p_execStarted = false; + p_notifyDone = true; + + p_cachedDoneBricks = new QVector< QPair >; + + start(); + moveToThread(this); + } + + + /** + * This connects this class' signals and slots with CubeDataThread's signals + * and slots. + */ + void CubeDataThreadTester::Connect() { + connect(this, + SIGNAL(RequestReadCube(int, int, int, int, int, int, void*)), + p_cubeDataThread, + SLOT(ReadCube(int, int, int, int, int, int, void*))); + + connect(this, + SIGNAL(RequestReadWriteCube(int, int, int, int, int, int, void*)), + p_cubeDataThread, + SLOT(ReadWriteCube(int, int, int, int, int, int, void*))); + + connect(this, SIGNAL(NotifyDoneWithData(int, const Isis::Brick *)), + p_cubeDataThread, SLOT(DoneWithData(int, const Isis::Brick *))); + + connect(p_cubeDataThread, SIGNAL(ReadReady(void *, int, const Isis::Brick *)), + this, SLOT(ReadBrick(void *, int, const Isis::Brick *))); + + connect(p_cubeDataThread, SIGNAL(ReadWriteReady(void *, int, Isis::Brick *)), + this, SLOT(ReadWriteBrick(void *, int, Isis::Brick *))); + } + + + /** + * This cleans up the cube data thread. + * + */ + CubeDataThreadTester::~CubeDataThreadTester() { + if(!p_execStarted) { + QThread::yieldCurrentThread(); + } + + QThread::exit(0); + + wait(); + } + + //! returns the cube id + void CubeDataThreadTester::run() { + p_execStarted = true; + exec(); + } + + /** + * This tests a basic read. This performs 1 test. + * + * @param cubeId The identifier given by the data thread for the file to test + */ + void CubeDataThreadTester::ReadCubeTest(int cubeId) { + cout << "=============== Testing Basic Read ===============" << endl; + emit RequestReadCube(cubeId, 1, 1, 2, 2, 1, this); + } + + + /** + * This tests two basic reads with no conflicts. This performs 2 tests. + * + * @param cubeId1 Cube for first read + * @param cubeId2 Cube for second read + */ + void CubeDataThreadTester::ReadCubeTest2(int cubeId1, int cubeId2) { + cout << "=============== Testing Multiple Non-Conflicting Cube Reads " << + "===============" << endl; + + p_notifyDone = false; + emit RequestReadCube(cubeId1, 1, 1, 3, 2, 1, this); + emit RequestReadCube(cubeId2, 1, 2, 3, 2, 1, this); + } + + + /** + * This tests an overlapping read. This performs 2 tests. + * + * @param cubeId The identifier given by the data thread for the file to test + */ + void CubeDataThreadTester::ReadCubeTest3(int cubeId) { + cout << "=============== Testing Exact Overlap Cube Reads ===============" + << endl << endl; + + p_notifyDone = false; + emit RequestReadCube(cubeId, 1, 2, 2, 2, 1, this); + emit RequestReadCube(cubeId, 1, 2, 2, 2, 1, this); + } + + + /** + * This tests a basic write. This performs 2 tests. + * + * @param cubeId The identifier given by the data thread for the file to test + */ + void CubeDataThreadTester::WriteCubeTest(int cubeId) { + cout << "=============== Testing Basic R/W ===============" << endl << endl; + emit RequestReadWriteCube(cubeId, 1, 1, 2, 2, 1, this); + emit RequestReadCube(cubeId, 1, 1, 2, 2, 1, this); + } + + + /** + * This tests two non-conflicting writes. This performs 2 tests. + * + * @param cubeId1 Cube for first write + * @param cubeId2 Cube for second write + */ + void CubeDataThreadTester::WriteCubeTest2(int cubeId1, int cubeId2) { + cout << "=============== Testing Multiple Non-Conflicting Cube R/W " << + "===============" << endl << endl; + + p_notifyDone = false; + emit RequestReadWriteCube(cubeId1, 1, 1, 3, 1, 1, this); + emit RequestReadWriteCube(cubeId2, 1, 1, 3, 1, 1, this); + } + + + /** + * This tests two conflicting* writes. This causes a deadlock! + * + * This performs a test, deadlocks, and once the deadlock is broken (via + * WriteCubeTest3BreakDeadlock), finishes another test. + * + * @param cubeId The identifier given by the data thread for the file to test + */ + void CubeDataThreadTester::WriteCubeTest3(int cubeId) { + cout << "=============== Testing Conflicting Cube R/W ===============" + << endl; + + p_notifyDone = false; + emit RequestReadWriteCube(cubeId, 1, 1, 3, 1, 1, this); + emit RequestReadWriteCube(cubeId, 1, 1, 3, 1, 1, this); + } + + + /** + * This test breaks the deadlock caused by the third write test + * + */ + void CubeDataThreadTester::WriteCubeTest3BreakDeadlock() { + cout << " Breaking Deadlock From Test 3" << endl; + while(!p_cachedDoneBricks->size()) { + msleep(100); + } + + if(p_cachedDoneBricks->size()) { + cout << " Notify done with first brick" << endl; + emit NotifyDoneWithData((*p_cachedDoneBricks)[0].first, + (*p_cachedDoneBricks)[0].second); + p_cachedDoneBricks->clear(); + } + } + + + /** + * This test tests this automatic change notifications. This performs 2 tests. + * + * @param cubeId The identifier given by the data thread for the file to test + */ + void CubeDataThreadTester::NotifyChangeTest(int cubeId) { + cout << "=============== Testing Change Notification ===============" + << endl; + + connect(p_cubeDataThread, + SIGNAL(BrickChanged(int, const Isis::Brick *)), + this, + SLOT(BrickChanged(int, const Isis::Brick *)) + ); + + p_cubeDataThread->AddChangeListener(); + emit RequestReadWriteCube(cubeId, 5, 1, 5, 1, 1, this); + } + + + /** + * This is called when a brick is read. + * + * @param requester Pointer to requesting class + * @param cubeId Cube identifier + * @param data Brick of data read + */ + void CubeDataThreadTester::ReadBrick(void *requester, int cubeId, + const Isis::Brick *data) { + cout << " CubeDataThreadTester::ReadBrick" << endl; + + cout << " Requester is me? " << ((this == requester)? "Yes" : "No") + << endl; + + if(this != requester) return; + + cout << " Data:" << endl; + + for(int i = 0; i < data->size(); i++) { + if(i == 0) cout << " "; + if(i % 6 == 6-1 && i != data->size() - 1) { + cout << data->at(i) << endl << " "; + } + else if(i == data->size() - 1) { + cout << data->at(i) << endl; + } + else { + cout << data->at(i) << "\t"; + } + } + + cout << endl; + if(p_notifyDone) { + cout << " Notify done with this brick" << endl; + emit NotifyDoneWithData(cubeId, data); + + if(p_cachedDoneBricks->size()) { + cout << " Notify done with first brick" << endl; + emit NotifyDoneWithData((*p_cachedDoneBricks)[0].first, + (*p_cachedDoneBricks)[0].second); + p_cachedDoneBricks->clear(); + } + } + else { + QPair cache; + cache.first = cubeId; + cache.second = data; + + p_cachedDoneBricks->push_back(cache); + } + + p_notifyDone = true; + p_numTestsDone ++; + } + + /** + * This is called when a brick is given for R/W. + * + * @param requester Pointer to requesting class + * @param cubeId Cube identifier + * @param data Brick of data read + */ + void CubeDataThreadTester::ReadWriteBrick(void *requester, int cubeId, + Isis::Brick *data) { + cout << " CubeDataThreadTester::ReadWriteBrick" << endl; + + // This was a nice idea, but has race conditions that are difficult + // at best to resolve. + + //cout << " Managed Bricks in Memory = " << + // p_cubeDataThread->BricksInMemory() << endl; + + cout << " Changing Brick : Index 0 Becoming 5" << endl; + cout << endl; + + cout << " Old Data: " << endl; + + for(int i = 0; i < data->size(); i++) { + if(i == 0) cout << " "; + if(i % 6 == 6-1 && i != data->size() - 1) { + cout << data->at(i) << endl << " "; + } + else if(i == data->size() - 1) { + cout << data->at(i) << endl; + } + else { + cout << data->at(i) << "\t"; + } + } + + (*data)[0] = 5; + + cout << " New Data: " << endl; + + for(int i = 0; i < data->size(); i++) { + if(i == 0) cout << " "; + if(i % 6 == 6-1 && i != data->size() - 1) { + cout << data->at(i) << endl << " "; + } + else if(i == data->size() - 1) { + cout << data->at(i) << endl; + } + else { + cout << data->at(i) << "\t"; + } + } + + cout << endl; + + if(p_notifyDone) { + cout << " Notify done with this brick" << endl; + emit NotifyDoneWithData(cubeId, data); + + if(p_cachedDoneBricks->size()) { + cout << " Notify done with first brick" << endl; + emit NotifyDoneWithData((*p_cachedDoneBricks)[0].first, + (*p_cachedDoneBricks)[0].second); + p_cachedDoneBricks->clear(); + } + } + else { + QPair cache; + cache.first = cubeId; + cache.second = data; + + p_cachedDoneBricks->push_back(cache); + } + + p_notifyDone = true; + p_numTestsDone ++; + } + + + /** + * This is called when a brick is written. + * + * @param cubeId Cube identifier + * @param data Brick of data read + */ + void CubeDataThreadTester::BrickChanged(int cubeId, const Isis::Brick *data) { + cout << " CubeDataThreadTester::BrickChanged" << endl; + cout << " Data:" << endl; + + for(int i = 0; i < data->size(); i++) { + if(i == 0) cout << " "; + if(i % 6 == 6-1 && i != data->size() - 1) { + cout << data->at(i) << endl << " "; + } + else if(i == data->size() - 1) { + cout << data->at(i) << endl; + } + else { + cout << data->at(i) << "\t"; + } + } + + p_numTestsDone ++; + emit NotifyDoneWithData(cubeId, data); + } +}; diff --git a/isis/src/base/objs/CubeDataThread/CubeDataThreadTester.h b/isis/src/base/objs/CubeDataThread/CubeDataThreadTester.h new file mode 100644 index 0000000000000000000000000000000000000000..26caaf736f45032659159d141f6bcda505e85c99 --- /dev/null +++ b/isis/src/base/objs/CubeDataThread/CubeDataThreadTester.h @@ -0,0 +1,101 @@ +#ifndef CubeDataThreadTester_h +#define CubeDataThreadTester_h + +#include + +template class QList; +template class QPair; + +namespace Isis { + class Brick; + class CubeDataThread; + + class CubeDataThreadTester : public QThread { + Q_OBJECT + + public: + CubeDataThreadTester(CubeDataThread *); + virtual ~CubeDataThreadTester(); + + //! Returns the number of tests done (testing methods count as several) + int NumberOfTestsDone() { return p_numTestsDone; } + + //! Returns the cube data thread being tested + CubeDataThread *DataThread() { return p_cubeDataThread; } + + void Connect(); + void ReadCubeTest(int); + void ReadCubeTest2(int, int); + void ReadCubeTest3(int); + void WriteCubeTest(int); + void WriteCubeTest2(int, int); + void WriteCubeTest3(int); + void WriteCubeTest3BreakDeadlock(); + void NotifyChangeTest(int); + + public slots: + void ReadBrick(void *requester, int cubeId, const Isis::Brick *data); + void ReadWriteBrick(void *requester, int cubeId, Isis::Brick *data); + void BrickChanged(int cubeId, const Isis::Brick *data); + + signals: + /** + * Ask for a brick for reading. + * + * @param cubeId Cube identifier + * @param startSample Brick starting sample + * @param startLine Brick starting line + * @param endSample Brick ending sample + * @param endLine Brick ending line + * @param band Brick band + * @param caller A this pointer + */ + void RequestReadCube(int cubeId, int startSample, int startLine, + int endSample, int endLine, int band, void *caller); + + + /** + * Ask for a brick for reading and writing. + * + * @param cubeId Cube identifier + * @param startSample Brick starting sample + * @param startLine Brick starting line + * @param endSample Brick ending sample + * @param endLine Brick ending line + * @param band Brick band + * @param caller A this pointer + */ + void RequestReadWriteCube(int cubeId, int startSample, int startLine, + int endSample, int endLine, int band, void *caller); + + + /** + * Let the cube data thread know we're no longer working with a particular + * brick. + */ + void NotifyDoneWithData(int, const Isis::Brick *); + + private: + //! This thread is centered completely around its event loop + void run(); + + //! The count of completed tests + int p_numTestsDone; + + //! The data thread being tested + CubeDataThread *p_cubeDataThread; + + //! True if this thread is started + bool p_execStarted; + + //! True if we will notify done on the next brick received for R/W + bool p_notifyDone; + + //! A list of bricks we haven't send the done signal for + QVector< QPair > * p_cachedDoneBricks; + }; + +}; + + +#endif diff --git a/isis/src/base/objs/CubeDataThread/Makefile b/isis/src/base/objs/CubeDataThread/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5a7a54c37c5fa55066016a03be7be7ef334db30d --- /dev/null +++ b/isis/src/base/objs/CubeDataThread/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp unitTest.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CubeDataThread/unitTest.cpp b/isis/src/base/objs/CubeDataThread/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2ab6ca2777c6d19afee091217e48d064c6fefd3c --- /dev/null +++ b/isis/src/base/objs/CubeDataThread/unitTest.cpp @@ -0,0 +1,137 @@ +#include "Isis.h" + +#include +#include + +#include "CubeDataThread.h" +#include "CubeDataThreadTester.h" +#include "Filename.h" +#include "Cube.h" + +using namespace Isis; + +using namespace std; + +void IsisMain() { + system("cp unitTest.cub unitTest2.cub"); + system("cp unitTest.cub unitTest3.cub"); + + CubeDataThread *cubeData = new CubeDataThread(); + + int readOnly1 = cubeData->AddCube(Filename("$base/testData/isisTruth.cub")); + int readOnly2 = cubeData->AddCube(Filename("$base/testData/blobTruth.cub")); + int readWrite1 = cubeData->AddCube(Filename("./unitTest2.cub")); + int readWrite2 = cubeData->AddCube(Filename("./unitTest3.cub")); + + Cube someCube; + cubeData->AddCube(&someCube); + + CubeDataThreadTester *tester = new CubeDataThreadTester(cubeData); + tester->Connect(); + + // Basic Read Test (increments NumberOfTestsDone() once) + tester->ReadCubeTest(readOnly1); + + // Wait for test 1 complete + while(cubeData->BricksInMemory() != 0 || + tester->NumberOfTestsDone() != 1) { + QThread::yieldCurrentThread(); + } + // Test 1 is complete + + cout << endl << endl; + + // Simultaneous Read Test (increments NumberOfTestsDone() twice) + tester->ReadCubeTest2(readOnly1, readOnly2); + + // Wait for test 2 complete + while(cubeData->BricksInMemory() != 0 || + tester->NumberOfTestsDone() != 3) { + QThread::yieldCurrentThread(); + } + // Test 2 is complete + + cout << endl << endl; + + // Overlapping Read Test (increments NumberOfTestsDone() twice) + tester->ReadCubeTest3(readOnly1); + + // Wait for test 3 complete + while(cubeData->BricksInMemory() != 0 || + tester->NumberOfTestsDone() != 5) { + QThread::yieldCurrentThread(); + } + // Test 3 is complete + + cout << endl << endl; + + // Basic Write Test (increments NumberOfTestsDone() twice) + tester->WriteCubeTest(readWrite1); + + // Wait for test 4 complete + while(cubeData->BricksInMemory() != 0 || + tester->NumberOfTestsDone() != 7) { + QThread::yieldCurrentThread(); + } + // Test 4 is complete + + cout << endl << endl; + + // Simultaneous Write Test (increments NumberOfTestsDone() twice) + tester->WriteCubeTest2(readWrite1, readWrite2); + + // Wait for test 5 complete + while(cubeData->BricksInMemory() != 0 || + tester->NumberOfTestsDone() != 9) { + QThread::yieldCurrentThread(); + } + // Test 5 is complete + + cout << endl << endl; + + // Conflicting Write Test -- deadlocks (increments NumberOfTestsDone() once, + // deadlocks, then again) + tester->WriteCubeTest3(readWrite1); + + // Wait for test 6 deadlock + while(cubeData->BricksInMemory() != 1 || + tester->NumberOfTestsDone() != 10) { + QThread::yieldCurrentThread(); + } + // Wait test 6 is deadlocked + + tester->WriteCubeTest3BreakDeadlock(); + + // Wait for test 6 complete + while(cubeData->BricksInMemory() != 0 || + tester->NumberOfTestsDone() != 11) { + QThread::yieldCurrentThread(); + } + // Test 6 is complete + + cout << endl << endl; + + // Tests the BrickChanged signal (increments NumberOfTestsDone() twice) + tester->NotifyChangeTest(readWrite1); + + // Wait for test 7 complete + while(cubeData->BricksInMemory() != 0 || + tester->NumberOfTestsDone() != 13) { + QThread::yieldCurrentThread(); + } + // Test 7 is complete + + cout << endl << endl << "Cleanup Tester" << endl; + delete tester; + + cout << "Cleanup Cubes" << endl; + delete cubeData; + + cout << "Deleting Temporary R/W Cubes" << endl; + remove("unitTest2.cub"); + remove("unitTest3.cub"); + + cout << "Unit Test Complete" << endl; +} + + diff --git a/isis/src/base/objs/CubeDataThread/unitTest.xml b/isis/src/base/objs/CubeDataThread/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..1549011579134851d8836cf5a927e6e083425b6e --- /dev/null +++ b/isis/src/base/objs/CubeDataThread/unitTest.xml @@ -0,0 +1,37 @@ + + + + + + Brief description + + + + This program tests the GroundGrid class. + + + + + Original version + + + + + Utility + + + + + + cube + output + Default + Brief for parameter CUBE + + Description for CUBE. + + + + + + diff --git a/isis/src/base/objs/CubeInfixToPostfix/CubeInfixToPostfix.cpp b/isis/src/base/objs/CubeInfixToPostfix/CubeInfixToPostfix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9f7da064810843f497986ff6873053983e559fd6 --- /dev/null +++ b/isis/src/base/objs/CubeInfixToPostfix/CubeInfixToPostfix.cpp @@ -0,0 +1,85 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/02/23 17:09:44 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "CubeInfixToPostfix.h" +#include "iException.h" + +using namespace std; + +namespace Isis { + + /** + * This method will return true if it believes the argument represents + * a valid function or operator. + * + * @param representation The symbolic representation of the operator, such as 'sin' + * + * @return bool True if it looks valid, false if it's not known + */ + bool CubeInfixToPostfix::IsKnownSymbol(iString representation) { + for(int i = 0; i < p_operators.size(); i++) { + if(representation.compare(p_operators[i]->InputString()) == 0) { + return true; + } + } + + bool isFunction = (representation.size() > 1); + if(representation[0] == 'f') { + for(unsigned int i = 1; isFunction && i < representation.size(); i++) { + isFunction &= (representation[i] >= '0' && representation[i] <= '9'); + } + } + else { + isFunction = false; + } + + return isFunction; + } + + InfixOperator *CubeInfixToPostfix::FindOperator(iString representation) { + try { + return InfixToPostfix::FindOperator(representation); + } + catch(iException &e) { + e.Clear(); + } + + bool isFunction = (representation.size() > 1); + if(representation[0] == 'f') { + for(unsigned int i = 1; i < representation.size(); i++) { + isFunction &= (representation[i] >= '0' && representation[i] <= '9'); + } + } + else { + isFunction = false; + } + + if(isFunction) { + p_operators.push_back(new InfixFunction(representation, 0)); + return p_operators[p_operators.size()-1]; + } + + throw iException::Message(iException::User, "The operator '" + representation + "' is not recognized.", _FILEINFO_); + } + + +}; // end namespace Isis diff --git a/isis/src/base/objs/CubeInfixToPostfix/CubeInfixToPostfix.h b/isis/src/base/objs/CubeInfixToPostfix/CubeInfixToPostfix.h new file mode 100644 index 0000000000000000000000000000000000000000..3029089d508a75ff7017e6da5180286dc1125f58 --- /dev/null +++ b/isis/src/base/objs/CubeInfixToPostfix/CubeInfixToPostfix.h @@ -0,0 +1,57 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/02/23 17:09:44 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef CUBEINFIXTOPOSTFIX_H_ +#define CUBEINFIXTOPOSTFIX_H_ + +#include "iString.h" +#include "InfixToPostfix.h" +#include +#include + +namespace Isis { + +/** + * @brief Converter for math equations + * + * This class converts infix equations to postfix + * + * @ingroup Math + * + * @author 2007-08-21 Steven Lambright + * + * @internal + * @history 2010-02-23 Steven Lambright Updated to use InfixOperator class + * method instead of direct access to member + */ + class CubeInfixToPostfix : public InfixToPostfix { + public: + CubeInfixToPostfix() {} ; + ~CubeInfixToPostfix() {}; + + protected: + bool IsKnownSymbol(iString representation); + InfixOperator *FindOperator(iString representation); + }; +}; + +#endif diff --git a/isis/src/base/objs/CubeInfixToPostfix/CubeInfixToPostfix.truth b/isis/src/base/objs/CubeInfixToPostfix/CubeInfixToPostfix.truth new file mode 100644 index 0000000000000000000000000000000000000000..922c82b40e9f8691360a803610f30e45ce1f773a --- /dev/null +++ b/isis/src/base/objs/CubeInfixToPostfix/CubeInfixToPostfix.truth @@ -0,0 +1,122 @@ +------------------------------------------------------- +Test CubeInfixToPostfix + + +1: Convert '-4' to postfix + Tokenized equation: '( -- ( 4 ) )' + Postfix: '4 --' + + +2: Convert '1*2' to postfix + Tokenized equation: '1 * 2' + Postfix: '1 2 *' + + +3: Convert '((1)+(1))' to postfix + Tokenized equation: '( ( 1 ) + ( 1 ) )' + Postfix: '1 1 +' + + +4: Convert '1*2/2-2' to postfix + Tokenized equation: '1 * 2 / 2 - 2' + Postfix: '1 2 * 2 / 2 -' + + +5: Convert 'sin(5)' to postfix + Tokenized equation: '( sin ( 5 ) )' + Postfix: '5 sin' + + +6: Convert 'sin 5' to postfix +**USER ERROR** Missing parenthesis after sin + + +7: Convert '--sin(-(f54+f65()))' to postfix + Tokenized equation: '( -- ( ( sin ( ( -- ( ( f54 ( ) ) + ( f65 ( ) ) ) ) ) ) ) )' + Postfix: 'f54 f65 + -- sin --' + + +8: Convert '--sin(-f54+--f65)' to postfix + Tokenized equation: '( -- ( ( sin ( ( -- ( ( f54 ( ) ) ) ) + ( -- ( ( f65 ( ) ) ) ) ) ) ) )' + Postfix: 'f54 -- f65 -- + sin --' + + +9: Convert '2/3^6' to postfix + Tokenized equation: '2 / 3 ^ 6' + Postfix: '2 3 6 ^ /' + + +10: Convert 'atan2(5,--4)' to postfix + Tokenized equation: '( atan2 ( ( 5 ) , ( -- ( 4 ) ) ) )' + Postfix: '5 4 -- atan2' + + +11: Convert 'atan2(--5)' to postfix +**USER ERROR** There were not enough arguments supplied to the function 'atan2'. + + +12: Convert 'atan2(1,2,3)' to postfix +**USER ERROR** There were too many arguments supplied to the function 'atan2'. + + +13: Convert 'atan2(1,)' to postfix +**USER ERROR** Argument 2 in function atan2 must not be empty. + + +14: Convert 'atan2(1,2' to postfix +**USER ERROR** The definition of 'atan2' is not complete. + + +15: Convert 'f999-f548-f126^2' to postfix + Tokenized equation: '( f999 ( ) ) - ( f548 ( ) ) - ( f126 ( ) ) ^ 2' + Postfix: 'f999 f548 - f126 2 ^ -' + + +16: Convert 'sin(0)^2' to postfix + Tokenized equation: '( sin ( 0 ) ) ^ 2' + Postfix: '0 sin 2 ^' + + +17: Convert 'somefunc(5)' to postfix + Tokenized equation: 'somefunc ( 5 )' +**USER ERROR** The operator 'somefunc' is not recognized. + + +18: Convert '3#3' to postfix + Tokenized equation: '3 # 3' +**USER ERROR** The operator '#' is not recognized. + + +19: Convert '(f3)(f2)' to postfix + Tokenized equation: '( ( f3 ( ) ) ) ( ( f2 ( ) ) )' +**USER ERROR** Missing an operator before f2. + + +20: Convert '(3)(2)' to postfix + Tokenized equation: '( 3 ) ( 2 )' +**USER ERROR** Missing an operator before 2. + + +21: Convert 'atan2(1+2/3^(--6), 5^ (tan ( 42 ^ (f1 / --f264) / 4 ) - 65 ) != 0)' to postfix + Tokenized equation: '( atan2 ( ( 1 + 2 / 3 ^ ( ( -- ( 6 ) ) ) ) , 5 ^ ( ( tan ( 42 ^ ( ( f1 ( ) ) / ( -- ( ( f264 ( ) ) ) ) ) / 4 ) ) - 65 ) != 0 ) )' + Postfix: '1 2 3 6 -- ^ / + 5 42 f1 f264 -- / ^ 4 / tan 65 - ^ 0 != atan2' + + +22: Convert '1++2' to postfix + Tokenized equation: '1 + + 2' +**USER ERROR** Missing an operand near the operator '+'. + + +23: Convert '1+-2' to postfix + Tokenized equation: '1 + ( -- ( 2 ) )' + Postfix: '1 2 -- +' + + +24: Convert '(1+3*(4)' to postfix + Tokenized equation: '( 1 + 3 * ( 4 )' +**USER ERROR** There are too many opening parentheses ('(') in the equation. + + +25: Convert '(1+3*(4)))' to postfix + Tokenized equation: '( 1 + 3 * ( 4 ) ) )' +**USER ERROR** There are too many closing parentheses (')') in the equation. diff --git a/isis/src/base/objs/CubeInfixToPostfix/Makefile b/isis/src/base/objs/CubeInfixToPostfix/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c1af5454ba3a9471a43c550c58f56a884322944b --- /dev/null +++ b/isis/src/base/objs/CubeInfixToPostfix/Makefile @@ -0,0 +1,5 @@ +INCS = CubeInfixToPostfix.h +SRCS = CubeInfixToPostfix.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CubeInfixToPostfix/unitTest.cpp b/isis/src/base/objs/CubeInfixToPostfix/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b91f0ec782f26db2438b1ca3d6ab2ae7ec4ad67e --- /dev/null +++ b/isis/src/base/objs/CubeInfixToPostfix/unitTest.cpp @@ -0,0 +1,58 @@ +#include "Calculator.h" +#include "CubeInfixToPostfix.h" +#include "Preference.h" +#include + +using namespace std; +using namespace Isis; + +int main(int argc, char *argv[]) +{ + cout << "-------------------------------------------------------" << endl; + cout << "Test CubeInfixToPostfix" << endl; + + const int NUM_EQUATIONS = 25; + iString equations[NUM_EQUATIONS] = { + "-4", + "1*2", + "((1)+(1))", + "1*2/2-2", + "sin(5)", + "sin 5", + "--sin(-(f54+f65()))", + "--sin(-f54+--f65)", + "2/3^6", + "atan2(5,--4)", + "atan2(--5)", + "atan2(1,2,3)", + "atan2(1,)", + "atan2(1,2", + "f999-f548-f126^2", + "sin(0)^2", + "somefunc(5)", + "3#3", + "(f3)(f2)", // Can't detect the problem here yet because f3 and f2 are functions/operators + "(3)(2)", + "atan2(1+2/3^(--6), 5^ (tan ( 42 ^ (f1 / --f264) / 4 ) - 65 ) != 0)", + "1++2", // This doesn't work + "1+-2", // This does work, however, because -2 is a negation and not a subtract. + "(1+3*(4)", + "(1+3*(4)))" + }; + + CubeInfixToPostfix converter; + for(int equation = 0; equation < NUM_EQUATIONS; equation ++) { + cout << endl << endl << equation+1 << ": Convert '" << equations[equation] << "' to postfix" << endl; + + try { + iString tokenized = converter.TokenizeEquation(equations[equation]); + cout << " Tokenized equation: '" << tokenized << "'" << endl; + iString postfix = converter.Convert(equations[equation]); + cout << " Postfix: '" << postfix << "'" << endl; + } + catch(iException e) { + e.Report(false); + iException::Clear(); + } + } +} diff --git a/isis/src/base/objs/CubeManager/CubeManager.cpp b/isis/src/base/objs/CubeManager/CubeManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1870484f3db954994ad639d766c01360e089da49 --- /dev/null +++ b/isis/src/base/objs/CubeManager/CubeManager.cpp @@ -0,0 +1,113 @@ +#include "Cube.h" +#include "CubeAttribute.h" +#include "CubeManager.h" +#include "Filename.h" +#include "iString.h" + +#include + +namespace Isis { + CubeManager CubeManager::p_instance; + + /** + * This initializes a CubeManager object + * + */ + CubeManager::CubeManager() { + p_minimumCubes = 0; + } + + /** + * This is the CubeManager destructor. This method calls CleanCubes(). + * + */ + CubeManager::~CubeManager() { + CleanCubes(); + } + + /** + * This method opens a cube. If the cube is already opened, this method will + * return the cube from memory. The CubeManager class retains ownership of this + * cube pointer, so do not close the cube, destroy the pointer, or otherwise + * modify the cube object or pointer such that another object using them would + * fail. This method does not guarantee you are the only one with this pointer, + * nor is it recommended to keep this pointer out of a local (method) scope. + * + * @param cubeFilename The filename of the cube you wish to open + * + * @return Cube* A pointer to the cube object that CubeManager retains ownership + * to and may delete at any time + */ + Cube *CubeManager::OpenCube(const std::string &cubeFilename) { + CubeAttributeInput attIn(cubeFilename); + iString attri = attIn.BandsStr(); + iString expName = Filename(cubeFilename).Expanded(); + + // If there are attributes, we need a plus sign on the name + if (attri.size() > 0) { + expName += "+"; + } + + iString fullName = expName + attri; + QString fileName(fullName); + QMap::iterator searchResult = p_cubes.find(fileName); + + if(searchResult == p_cubes.end()) { + p_cubes.insert(fileName, new Cube()); + searchResult = p_cubes.find(fileName); + // Bands are the only thing input attributes can affect + (*searchResult)->SetVirtualBands(attIn.Bands()); + (*searchResult)->Open(fileName.toStdString()); + } + + // Keep track of the newly opened cube in our queue + p_opened.removeAll(fileName); + p_opened.enqueue(fileName); + + // cleanup if necessary + if(p_minimumCubes != 0) { + while(p_opened.size() > (int)(p_minimumCubes)) { + QString needsCleaned = p_opened.dequeue(); + CleanCubes(needsCleaned.toStdString()); + } + } + + return (*searchResult); + } + + /** + * This method removes a cube from memory, if it exists. If the cube is not + * loaded into memory, nothing happens. This will cause any pointers to this + * cube, obtained via OpenCube, to be invalid. + * + * @param cubeFilename The filename of the cube to remove from memory + */ + void CubeManager::CleanCubes(const std::string &cubeFilename) { + QString fileName((iString)Filename(cubeFilename).Expanded()); + QMap::iterator searchResult = p_cubes.find(fileName); + + if(searchResult == p_cubes.end()) { + return; + } + + (*searchResult)->Close(); + delete *searchResult; + p_cubes.erase(searchResult); + } + + /** + * This method removes all cubes from memory. All pointers returned via OpenCube + * will be invalid. + */ + void CubeManager::CleanCubes() { + QMap::iterator pos = p_cubes.begin(); + + while(pos != p_cubes.end()) { + (*pos)->Close(); + delete *pos; + pos ++; + } + + p_cubes.clear(); + } +} diff --git a/isis/src/base/objs/CubeManager/CubeManager.h b/isis/src/base/objs/CubeManager/CubeManager.h new file mode 100644 index 0000000000000000000000000000000000000000..a3c136fb2f290a3101bde42bc2b0ee2e2fe45361 --- /dev/null +++ b/isis/src/base/objs/CubeManager/CubeManager.h @@ -0,0 +1,111 @@ +#ifndef CubeManager_h +#define CubeManager_h + +#include +#include +#include + +/* + * Unless noted otherwise, the portions of Isis written by the + * USGS are public domain. See individual third-party library + * and package descriptions for intellectual property + * information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +namespace Isis { + class Cube; + + /** + * @brief Class for quick re-accessing of cubes based on file name + * + * This class holds cubes in static memory for reading. + * This is helpful to prevent reading of the same cube many times. Files will remain + * opened for reading, this is not for use with a cube that will ever be written + * to. You can either use the static methods of the class, in which case cubes + * will be cleaned up after IsisMain(...) is done executing, or you can + * instantiate the class for more control. + * + * @author 2008-05-20 Steven Lambright + * + * @internal + * @author 2008-06-19 Steven Lambright - Added CleanUp methods + * @history 2008-08-19 Steven Koechle - Removed Geos includes + * @author 2009-02-12 Steven Lambright - Made the class available as an + * instance and not just statically. Added optional cube open limits. + * @history 2009-11-03 Mackenzie Boyd - Modified to include + * cube attributes (input) when opening cubes. + * + */ + class CubeManager { + public: + CubeManager(); + ~CubeManager(); + + /** + * This method calls the method OpenCube() on the static instance + * + * @see OpenCube + * + * @param cubeFilename Filename of the cube to be opened + * + * @return Cube* Pointer to the cube (guaranteed not null) + */ + static Cube *Open(const std::string &cubeFilename) { return p_instance.OpenCube(cubeFilename); } + + /** + * This method calls CleanCubes(const std::string &cubeFilename) on the static + * instance + * + * @see CleanCubes(const std::string &cubeFilename) + * + * @param cubeFilename The filename of the cube to destroy from memory + */ + static void CleanUp(const std::string &cubeFilename) { p_instance.CleanCubes(cubeFilename); } + + /** + * This method calls CleanCubes() on the static instance + * + * @see CleanCubes + */ + static void CleanUp() { p_instance.CleanCubes(); }; + + void CleanCubes(const std::string &cubeFilename); + void CleanCubes(); + + Cube *OpenCube(const std::string &cubeFilename); + + /** + * This sets the maximum number of opened cubes for this instance of + * CubeManager. The last "maxCubes" opened cubes are guaranteed to be + * valid as long as one of the CleanCubes(...) are not called. + * + * @param numCubes Maximum number of open cubes + */ + void SetNumOpenCubes(unsigned int numCubes) { p_minimumCubes = numCubes; } + + protected: + //! There is always at least one instance of CubeManager around + static CubeManager p_instance; + + //! This keeps track of the open cubes + QMap p_cubes; + //! This keeps track of cubes that have been opened + QQueue p_opened; + + //! At least this many cubes must be allowed in memory, more can be cleaned up, 0 means no limit + unsigned int p_minimumCubes; + }; +} + +#endif diff --git a/isis/src/base/objs/CubeManager/CubeManager.truth b/isis/src/base/objs/CubeManager/CubeManager.truth new file mode 100644 index 0000000000000000000000000000000000000000..48d1c726003bc36a6a9b4ce3105e388f12307137 --- /dev/null +++ b/isis/src/base/objs/CubeManager/CubeManager.truth @@ -0,0 +1,27 @@ +CubeManager Unit Test +Verify proper cubes have been read +Cube Filenames: + 1 : isisTruth + 2 : isisTruth + 3 : blobTruth + 4 : blobTruth + 5 : isisTruth + 6 : isisTruth + +Verify We Don't Have Duplicates... + Cube # | Equals 1 | Equals 2 | Equals 3 | Equals 4 | Equals 5 | Equals 6 + Cube 1 | 1 | 1 | 0 | 0 | 0 | 0 + Cube 2 | 1 | 1 | 0 | 0 | 0 | 0 + Cube 3 | 0 | 0 | 1 | 1 | 0 | 0 + Cube 4 | 0 | 0 | 1 | 1 | 0 | 0 + Cube 5 | 0 | 0 | 0 | 0 | 1 | 1 + Cube 6 | 0 | 0 | 0 | 0 | 1 | 1 + +Verify cube attributes have been taken into account + Cube # | # of Bands + Cube 1 | 2 + Cube 2 | 2 + Cube 3 | 1 + Cube 4 | 1 + Cube 5 | 1 + Cube 6 | 1 diff --git a/isis/src/base/objs/CubeManager/Makefile b/isis/src/base/objs/CubeManager/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..83f13fb9effa6a9c6be418709c26cee93f608db8 --- /dev/null +++ b/isis/src/base/objs/CubeManager/Makefile @@ -0,0 +1,5 @@ +INCS = CubeManager.h +SRCS = CubeManager.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/CubeManager/unitTest.cpp b/isis/src/base/objs/CubeManager/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63e6841f2713debe238e79d6353ffd69b75afd7a --- /dev/null +++ b/isis/src/base/objs/CubeManager/unitTest.cpp @@ -0,0 +1,66 @@ +#include "CubeManager.h" +#include "Filename.h" +#include "Cube.h" +#include "Preference.h" + +#include + +#include + +using namespace std; +using namespace Isis; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + std::cout << "CubeManager Unit Test" << std::endl; + QVector cubes; + + // Read Cubes Into Memory + cubes.push_back(CubeManager::Open("$base/testData/isisTruth.cub")); + cubes.push_back(CubeManager::Open("$base/testData/isisTruth.cub")); + cubes.push_back(CubeManager::Open("$base/testData/blobTruth.cub")); + cubes.push_back(CubeManager::Open("$base/testData/blobTruth.cub")); + cubes.push_back(CubeManager::Open("$base/testData/isisTruth.cub+1")); + cubes.push_back(CubeManager::Open("$base/testData/isisTruth.cub+1")); + + // Print Cube Filenames To Verify We Have Correct Ones + std::cout << "Verify proper cubes have been read" << std::endl; + std::cout << "Cube Filenames: " << std::endl; + + for(int i = 0; i < (int)cubes.size(); i++) { + std::cout << " " << i+1 << " : " << Filename(cubes[i]->Filename()).Basename() << std::endl; + } + + std::cout << std::endl; + + // Print Cube Pointer Comparisons (1 if match, 0 if differ) + std::cout << "Verify We Don't Have Duplicates..." << std::endl; + + // Print Table Header... up to 9 (for formatting) + std::cout << " Cube #"; + for(int i = 0; i < 9 && i < (int)cubes.size(); i++) { + std::cout << " | Equals " << i+1; + } + std::cout << std::endl; + + // Print Comparison Table Data + for(int i = 0; i < (int)cubes.size(); i++) { + std::cout << " Cube " << i+1; + + for(int j = 0; j < (int)cubes.size(); j++) { + std::cout << " | " << (int)(cubes[i] == cubes[j]); + } + + std::cout << std::endl; + } + + std::cout << std::endl; + + // Test cube attributes presence, input attributes only affect bands + std::cout << "Verify cube attributes have been taken into account" << std::endl; + std::cout << " Cube # | # of Bands" << std::endl; + for (int i = 0; i < (int)cubes.size(); i++) { + std::cout << " Cube " << i + 1 << " | " << cubes[i]->Bands() << std::endl; + } +} diff --git a/isis/src/base/objs/Endian/Endian.h b/isis/src/base/objs/Endian/Endian.h new file mode 100644 index 0000000000000000000000000000000000000000..10699f6af9cd62800959bf11080358ff7908106a --- /dev/null +++ b/isis/src/base/objs/Endian/Endian.h @@ -0,0 +1,129 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#if !defined(Endian_h) +#define Endian_h + +#include "iString.h" + +namespace Isis { + /** + * @brief Tests the current architecture for byte order + * + * Allows ISIS applications and objects to test the architecture's byte order. + * Little Endian or Big Endian. Note: Middle Endian is not supported at this + * time. + * + * @ingroup Utility + * + * @author 2002-12-01 Tracie Sucharski + * + * @internal + * @history 2003-02-11 Stuart Sides - Documented and created an object + * unittest + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-10-03 Stuart Sides - Added the byte order enumeration and + * functions to convert the enumeration + * to a string and from a string to an + * enumeration. Also deprecated the + * LittleEndian and BigEndian functions. + * They were replaced by Lsb and Msb + * functions. + * @history 2004-03-18 Stuart Sides - Added to macros for case where we need + * to know at compile time if a system is + * LSB or MSB. The macros are + * ISIS_LITTLE_ENDIAN and ISIS_BIG_ENDIAN + */ + + enum ByteOrder { + NoByteOrder = 0, + Lsb, + Msb + }; + + inline std::string ByteOrderName (Isis::ByteOrder byteOrder) { + if (byteOrder == Isis::NoByteOrder) return "None"; + if (byteOrder == Isis::Lsb) return "Lsb"; + if (byteOrder == Isis::Msb) return "Msb"; + return "Error"; + } + + inline Isis::ByteOrder ByteOrderEnumeration(const std::string &order) { + Isis::iString temp(order); + temp = temp.UpCase(); + if (temp == "LSB") return Isis::Lsb; + if (temp == "MSB") return Isis::Msb; + return Isis::NoByteOrder; + } + + /** + * Return true if this host is an LSB first machine and false if it is not + * + * @return bool - Returns true if host is LSB and false if it is MSB + */ + inline bool IsLsb(){ + union { + short a; + char b[2]; + } test; + + test.a = 1; + if (test.b[0] == 0) return false; + return true; + } + + /** + * Return true if this host is an MSB first machine and false if it is not + * + * @return bool - Returns true if host is MSB and false if it is LSB + */ + inline bool IsMsb() { + return !Isis::IsLsb(); + } + + /** + * @deprecated + * + * Test the architecture the application is running on. + * + * @return True if it's LittleEndian, False if it's not. + */ + inline bool IsLittleEndian() { + return IsLsb(); + } + + /** + * @deprecated + * + * Test the architecture the application is running on. + * + * @return True if it's BigEndian, False if it's not. + */ + inline bool IsBigEndian() { + return !Isis::IsLsb(); + } +} + +#endif + diff --git a/isis/src/base/objs/Endian/Endian.truth b/isis/src/base/objs/Endian/Endian.truth new file mode 100644 index 0000000000000000000000000000000000000000..4a0b7a37fb9afd4812ac299fd8a59d860212bacf --- /dev/null +++ b/isis/src/base/objs/Endian/Endian.truth @@ -0,0 +1,7 @@ +Unit test for IsisEndian +1 +0 +1 +0 +Msb +Lsb diff --git a/isis/src/base/objs/Endian/Makefile b/isis/src/base/objs/Endian/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4d87db5410fc44c5b7ac4970a27a8b302c328d11 --- /dev/null +++ b/isis/src/base/objs/Endian/Makefile @@ -0,0 +1,5 @@ +INCS = Endian.h +SRCS = +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Endian/unitTest.cpp b/isis/src/base/objs/Endian/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f834a50063261dd7552c6ce6da8bc85dfbeb148f --- /dev/null +++ b/isis/src/base/objs/Endian/unitTest.cpp @@ -0,0 +1,32 @@ +#include +#include "Endian.h" +#include "Preference.h" + +using namespace std; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Unit test for IsisEndian" << endl; + + if (Isis::IsLittleEndian() == true) { + cout << Isis::IsLittleEndian() << endl; + cout << Isis::IsBigEndian() << endl; + } + else { + cout << Isis::IsBigEndian() << endl; + cout << Isis::IsLittleEndian() << endl; + } + + if (Isis::IsLsb() == true) { + cout << Isis::IsLsb() << endl; + cout << Isis::IsMsb() << endl; + } + else { + cout << Isis::IsMsb() << endl; + cout << Isis::IsLsb() << endl; + } + + cout << Isis::ByteOrderName(Isis::ByteOrderEnumeration("msb")) << endl; + cout << Isis::ByteOrderName(Isis::ByteOrderEnumeration("lsb")) << endl; +} diff --git a/isis/src/base/objs/EndianSwapper/EndianSwapper.cpp b/isis/src/base/objs/EndianSwapper/EndianSwapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87d1a45136341ec7baf15e0551c7e7d222262c3a --- /dev/null +++ b/isis/src/base/objs/EndianSwapper/EndianSwapper.cpp @@ -0,0 +1,168 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/04/16 17:37:59 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "Endian.h" +#include "EndianSwapper.h" +#include "iException.h" +#include "Message.h" +#include + +#include + +using namespace std; +namespace Isis { +/** + * Constructs an EndianSwapper object, determining whether swapping of bytes + * actually needs to occur and sets the direction of swapping. + * + * @param inputEndian Byte order of input value (MSB or LSB). + */ + EndianSwapper::EndianSwapper (std::string inputEndian) { + + if (inputEndian != "LSB" && inputEndian != "MSB") { + string message = "Invalid parameter-InputEndian must be LSB or MSB"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + if ( (Isis::IsLsb() && inputEndian == "LSB") || + (Isis::IsMsb() && inputEndian == "MSB") ) { + p_needSwap = false; + p_swapDirection = 1; + } + else { + p_needSwap = true; + p_swapDirection = -1; + } + + } + + +/** + * Destroys the EndianSwapper object. + */ + EndianSwapper::~EndianSwapper () { + } + + +/** + * Swaps a double precision value. + * + * @param buf Input double precision value to swap. + */ + double EndianSwapper::Double (void *buf) { + char *ptr = (char *)buf + (sizeof (double) -1) * p_needSwap; + + for (unsigned int i=0; i +#include +#include "EndianSwapper.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + Isis::EndianSwapper lsb ("LSB"); + Isis::EndianSwapper msb ("MSB"); + + double DoubleValue; + float FloatValue; + short int ShortIntValue; + unsigned short int UShortIntValue; + int IntValue; + long long LongLongIntValue; + + DoubleValue = 0x12345678; + FloatValue = 0x1234; + ShortIntValue = 0x1234; + UShortIntValue = 0x1234; + IntValue = 0x12345678; + LongLongIntValue = 0x12345600; + + // Do the conversions from lsb to host first if this is a little endian machine + if (ISIS_LITTLE_ENDIAN) { + cout << "Size of Double: " << sizeof (double); + cout << " Double 0x12345678 to HOST: " << lsb.Double (&DoubleValue) << endl; + cout << "Size of Float: " << sizeof (float); + cout << " Float 0x1234 to HOST: " << lsb.Float (&FloatValue) << endl; + cout << "Size of Short Int: " << sizeof (short int); + cout << " Short Int 0x1234 to HOST: " << lsb.ShortInt (&ShortIntValue) << endl; + cout << "Size of Unsigned Short Int: " << sizeof (unsigned short int); + cout << " Unsigned Short Int 0x1234 to HOST: " << lsb.UnsignedShortInt (&UShortIntValue) << endl; + + cout << "Size of Double: " << sizeof (double); + cout << " Double 0x12345678 to HOST: " << msb.Double (&DoubleValue) << endl; + cout << "Size of Float: " << sizeof (float); + cout << " Float 0x1234 to HOST: " << msb.Float (&FloatValue) << endl; + cout << "Size of Short Int: " << sizeof (short int); + cout << " Short Int 0x1234 to HOST: " << msb.ShortInt (&ShortIntValue) << endl; + cout << "Size of Unsigned Short Int: " << sizeof (unsigned short int); + cout << " Unsigned Short Int 0x1234 to HOST: " << msb.UnsignedShortInt (&UShortIntValue) << endl; + cout << "Size of Int: " << sizeof (int); + cout << " Int 0x12345678 to HOST: " << msb.Int (&IntValue) << endl; + cout << "Size of Long Long Int: " << sizeof (long long int); + cout << " Long Long Int 0x0000000012345600 to HOST: " << msb.LongLongInt (&LongLongIntValue) << endl; + + // Test valid floats that when swapped become nan + cout << "Testing nan: " << endl; + union { + float myfloat; + int myint; + char mychar[4]; + } myunion; + + //myunion.myfloat = 0.0350742; Do NOT use this line, it is not the same as the bit pattern the following 4 lines produce + myunion.mychar[0] = (char)-1; + myunion.mychar[1] = (char)-87; + myunion.mychar[2] = (char)15; + myunion.mychar[3] = (char)61; + cout << "PreSwap: " << (int)(myunion.mychar[0]) << " " << (int)(myunion.mychar[1]); + cout << " " << (int)(myunion.mychar[2]) << " " << (int)(myunion.mychar[3]) << " " << endl; + myunion.myint = msb.ExportFloat( (void *)(&myunion.myfloat) ); + cout << "PostSwap: " << (int)(myunion.mychar[0]) << " " << (int)(myunion.mychar[1]); + cout << " " << (int)(myunion.mychar[2]) << " " << (int)(myunion.mychar[3]) << " " << endl; + + } + // Do the conversions from msb to host first if this is a big endian machine + else { + cout << "Size of Double: " << sizeof (double); + cout << " Double 0x12345678 to HOST: " << msb.Double (&DoubleValue) << endl; + cout << "Size of Float: " << sizeof (float); + cout << " Float 0x1234 to HOST: " << msb.Float (&FloatValue) << endl; + cout << "Size of Short Int: " << sizeof (short int); + cout << " Short Int 0x1234 to HOST: " << msb.ShortInt (&ShortIntValue) << endl; + cout << "Size of Unsigned Short Int: " << sizeof (unsigned short int); + cout << " Unsigned Short Int 0x1234 to HOST: " << msb.UnsignedShortInt (&UShortIntValue) << endl; + + cout << "Size of Double: " << sizeof (double); + cout << " Double 0x12345678 to HOST: " << lsb.Double (&DoubleValue) << endl; + cout << "Size of Float: " << sizeof (float); + cout << " Float 0x1234 to HOST: " << lsb.Float (&FloatValue) << endl; + cout << "Size of Short Int: " << sizeof (short int); + cout << " Short Int 0x1234 to HOST: " << lsb.ShortInt (&ShortIntValue) << endl; + cout << "Size of Unsigned Short Int: " << sizeof (unsigned short int); + cout << " Unsigned Short Int 0x1234 to HOST: " << lsb.UnsignedShortInt (&UShortIntValue) << endl; + cout << "Size of Int: " << sizeof (int); + cout << " Int 0x12345678 to HOST: " << lsb.Int (&IntValue) << endl; + cout << "Size of Long Long Int: " << sizeof (long long int); + cout << " Long Long Int 0x0000000012345600 to HOST: " << lsb.LongLongInt (&LongLongIntValue) << endl; + + // Test valid floats that when swapped become nan + cout << "Testing nan: " << endl; + union { + float myfloat; + int myint; + char mychar[4]; + } myunion; + + //myunion.myfloat = 0.0350742; Do NOT use this line, it is not the same as the bit pattern the following 4 lines produce + myunion.mychar[3] = (char)-1; + myunion.mychar[2] = (char)-87; + myunion.mychar[1] = (char)15; + myunion.mychar[0] = (char)61; + cout << "PreSwap: " << (int)(myunion.mychar[3]) << " " << (int)(myunion.mychar[2]); + cout << " " << (int)(myunion.mychar[1]) << " " << (int)(myunion.mychar[0]) << " " << endl; + myunion.myint = lsb.ExportFloat( (void *)(&myunion.myfloat) ); + cout << "PostSwap: " << (int)(myunion.mychar[3]) << " " << (int)(myunion.mychar[2]); + cout << " " << (int)(myunion.mychar[1]) << " " << (int)(myunion.mychar[0]) << " " << endl; + +} + +// Test wrong parameter + try { + Isis::EndianSwapper invalid ("INV"); + } + catch (Isis::iException &e) { + e.Report(false); + } + +} diff --git a/isis/src/base/objs/Equirectangular/Equirectangular.cpp b/isis/src/base/objs/Equirectangular/Equirectangular.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d5795c8072646e38c3ad9903eb3622378a7f4bd --- /dev/null +++ b/isis/src/base/objs/Equirectangular/Equirectangular.cpp @@ -0,0 +1,300 @@ +/** + * @file + * $Revision: 1.7 $ + * $Date: 2008/11/13 15:56:27 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "Equirectangular.h" +#include "iException.h" +#include "Constants.h" +#include +#include + +using namespace std; +namespace Isis { +/** + * Constructs a Equirectangular object. + * + * @param label This argument must be a Label containing the proper mapping + * information as indicated in the IsisProjection class. + * Additionally, the equirectangular projection requires the center + * longitude to be defined in the keyword CenterLongitude as well + * as the center latitude in CenterLatitude. + * + * @param allowDefaults (Default value is false) If set to false the + * constructor requires that the keywords CenterLongitude + * and CenterLatitude exist in the label. Otherwise if they + * do not exist they will be computed and written to the + * label using the middle of the latitude/longitude range + * as specified in the labels. + * + * @throws Isis::iException::Io An error is thrown if the label does not + * contain the keyword 'CenterLongtitude' or + * 'CenterLatitude'. + */ + Equirectangular::Equirectangular(Isis::Pvl &label, bool allowDefaults) : + Isis::Projection::Projection (label) { + try { + // Try to read the mapping group + Isis::PvlGroup &mapGroup = label.FindGroup ("Mapping",Isis::Pvl::Traverse); + + // Compute the default value if allowed and needed + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLongitude"))) { + double lon = 0.0; + mapGroup += Isis::PvlKeyword("CenterLongitude",lon); + } + + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLatitude"))) { + double lat = (p_minimumLatitude + p_maximumLatitude) / 2.0; + if (lat >= 65.0) { + lat = 65.0; + } + else if (lat <= -65.0) { + lat = -65.0; + } + else { + lat = 0.0; + } + mapGroup += Isis::PvlKeyword("CenterLatitude",lat); + } + + // Get the center longitude, convert to radians, adjust for longitude + // direction + p_centerLongitude = mapGroup["CenterLongitude"]; + p_centerLongitude *= Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) p_centerLongitude *= -1.0; + + // Get the center latitude, the radius at the clat, and convert to radians + p_centerLatitude = mapGroup["CenterLatitude"]; + p_clatRadius = LocalRadius(p_centerLatitude); + p_centerLatitude *= Isis::PI / 180.0; + + // This keyword is just for user's information, and was put in for Hirise + if (!mapGroup.HasKeyword("CenterLatitudeRadius")) { + mapGroup += PvlKeyword("CenterLatitudeRadius"); + } + + mapGroup["CenterLatitudeRadius"] = p_clatRadius; + + // Compute cos of the center latitude and make sure it is valid as + // we will be dividing with it later on + p_cosCenterLatitude = cos(p_centerLatitude); + if (fabs(p_cosCenterLatitude) < DBL_EPSILON) { + string message = "Keyword value for CenterLatitude is too close to the pole"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + catch (Isis::iException &e) { + string message = "Invalid label group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + //! Destroys the Equirectangular object. + Equirectangular::~Equirectangular() { + } + + /** + * This method is used to set the latitude/longitude (assumed to be of the + * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. + * + * @param lat Latitude value to project + * + * @param lon Longitude value to project + * + * @return bool + */ + bool Equirectangular::SetGround(const double lat,const double lon) { + // Convert to radians + p_latitude = lat; + p_longitude = lon; + double latRadians = lat * Isis::PI / 180.0; + double lonRadians = lon * Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) lonRadians *= -1.0; + + // Compute the coordinate + double deltaLon = (lonRadians - p_centerLongitude); + double x = p_clatRadius * p_cosCenterLatitude * deltaLon; + double y = p_clatRadius * latRadians; + SetComputedXY(x,y); + p_good = true; + return p_good; + } + + /** + * This method is used to set the projection x/y. The Set forces an attempted + * calculation of the corresponding latitude/longitude position. This may or + * may not be successful and a status is returned as such. + * + * @param x X coordinate of the projection in units that are the same as the + * radii in the label + * + * @param y Y coordinate of the projection in units that are the same as the + * radii in the label + * + * @return bool + */ + bool Equirectangular::SetCoordinate(const double x, const double y) { + // Save the coordinate + SetXY(x,y); + + // Compute latitude and make sure it is not above 90 + p_latitude = GetY() / p_clatRadius; + if ((fabs(p_latitude) - Isis::HALFPI) > DBL_EPSILON) { + p_good = false; + return p_good; + } + + // Compute longitude + p_longitude = p_centerLongitude + + GetX() / (p_clatRadius * p_cosCenterLatitude); + + // Convert to degrees + p_latitude *= 180.0 / Isis::PI; + p_longitude *= 180.0 / Isis::PI; + + // Cleanup the longitude + if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; + // Do these if the projection is circular + // p_longitude = To360Domain (p_longitude); + // if (p_longitudeDomain == 180) p_longitude = To180Domain(p_longitude); + + p_good = true; + return p_good; + } + + /** + * This method is used to determine the x/y range which completely covers the + * area of interest specified by the lat/lon range. The latitude/longitude + * range may be obtained from the labels. The purpose of this method is to + * return the x/y range so it can be used to compute how large a map may need + * to be. For example, how big a piece of paper is needed or how large of an + * image needs to be created. The method may fail as indicated by its return + * value. + * + * @param minX Minimum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxX Maximum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param minY Minimum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxY Maximum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @return bool + */ + bool Equirectangular::XYRange(double &minX, double &maxX, + double &minY, double&maxY) { + // Check the corners of the lat/lon range + XYRangeCheck (p_minimumLatitude,p_minimumLongitude); + XYRangeCheck (p_maximumLatitude,p_minimumLongitude); + XYRangeCheck (p_minimumLatitude,p_maximumLongitude); + XYRangeCheck (p_maximumLatitude,p_maximumLongitude); + + // Make sure everything is ordered + if (p_minimumX >= p_maximumX) return false; + if (p_minimumY >= p_maximumY) return false; + + // Return X/Y min/maxs + minX = p_minimumX; + maxX = p_maximumX; + minY = p_minimumY; + maxY = p_maximumY; + return true; + } + + /** + * This function returns the keywords that this projection uses. + * + * @return PvlGroup The keywords that this projection uses + */ + PvlGroup Equirectangular::Mapping() { + PvlGroup mapping = Projection::Mapping(); + + mapping += p_mappingGrp["CenterLatitude"]; + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * This function returns the latitude keywords that this projection uses + * + * @return PvlGroup The latitude keywords that this projection uses + */ + PvlGroup Equirectangular::MappingLatitudes() { + PvlGroup mapping = Projection::MappingLatitudes(); + + mapping += p_mappingGrp["CenterLatitude"]; + + return mapping; + } + + /** + * This function returns the longitude keywords that this projection uses + * + * @return PvlGroup The longitude keywords that this projection uses + */ + PvlGroup Equirectangular::MappingLongitudes() { + PvlGroup mapping = Projection::MappingLongitudes(); + + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * Compares two Projection objects to see if they are equal + * + * @param proj Projection object to do comparison on + * + * @return bool Returns true if the Projection objects are equal, and false if + * they are not + */ + bool Equirectangular::operator== (const Isis::Projection &proj) { + if (!Isis::Projection::operator==(proj)) return false; + // dont do the below it is a recusive plunge + // if (Isis::Projection::operator!=(proj)) return false; + Equirectangular *equi = (Equirectangular *) &proj; + if (equi->p_centerLongitude != this->p_centerLongitude) return false; + if (equi->p_centerLatitude != this->p_centerLatitude) return false; + return true; + } + + /** + * Returns the latitude of true scale (in the case of Equirectangular it is the + * center latitude). + * + * @return double The center latitude + */ + double Equirectangular::TrueScaleLatitude() const { + return p_centerLatitude * 180.0 / Isis::PI; + } +} + +extern "C" Isis::Projection *EquirectangularPlugin (Isis::Pvl &lab, + bool allowDefaults) { + return new Isis::Equirectangular(lab,allowDefaults); +} + diff --git a/isis/src/base/objs/Equirectangular/Equirectangular.h b/isis/src/base/objs/Equirectangular/Equirectangular.h new file mode 100644 index 0000000000000000000000000000000000000000..3d974615e891def7583933cf503947ff0e557033 --- /dev/null +++ b/isis/src/base/objs/Equirectangular/Equirectangular.h @@ -0,0 +1,102 @@ +#ifndef Equirectangular_h +#define Equirectangular_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/11/13 15:56:28 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Projection.h" + +namespace Isis { +/** + * @brief Equirectangular Map Projection + * + * This class provides methods for the forward and inverse equations of a + * Equirectangular map projection (for a sphere). The code was converted to + * C++ from the Fortran version of the USGS General Cartographic Transformation + * Package (GCTP). In particular it was modified from the Equidistant + * Cylindrical code. This class inherits IsisProjection and provides the two + * virtual methods SetGround (forward) and SetCoordinate (inverse) and a third + * virtual method, XYRange, for obtaining projection coordinate coverage for a + * latitude/longitude window. Please see the IsisProjection class for a full + * accounting of all the methods available. + * + * + * @ingroup MapProjection + * + * @author 2003-11-13 Jeff Anderson + * + * @internal + * @history 2004-02-07 Jeff Anderson - added plug-in capability. + * @history 2004-02-24 Jeff Anderson - Modified forward and inverse methods to + * use the local radius at the center + * latitude instead of the equitorial + * radius. + * @history 2005-03-11 Elizabeth Ribelin - added TrueScaleLatitude method test + * to the unitTest + * @history 2007-06-29 Steven Lambright - Added Mapping, MappingLatitudes and + * MappingLongitudes methods. + * @history 2008-05-09 Steven Lambright - Added Name, Version, IsEquatorialCylindrical methods + * @history 2008-05-09 Steven Lambright - Fixed test for being too close to a + * pole + * @history 2008-11-12 Steven Lambright - Commented some unclear code + * (CenterLatitudeRadius keyword) + */ + class Equirectangular : public Projection { + public: + Equirectangular (Isis::Pvl &label, bool allowDefaults=false); + ~Equirectangular (); + bool SetGround (const double lat, const double lon); + bool SetCoordinate (const double x, const double y); + bool XYRange (double &minX, double &maxX, double &minY, double &maxY); + virtual PvlGroup Mapping(); + virtual PvlGroup MappingLatitudes(); + virtual PvlGroup MappingLongitudes(); + + /** + * Returns the name of the map projection + * + * @return string Name of projection + */ + std::string Name() const { return "Equirectangular"; } + + /** + * Returns the version of the map projection + * + * + * @return std::string Version number + */ + std::string Version () const { return "1.0"; } + + bool IsEquatorialCylindrical() { return true; } + bool operator==(const Isis::Projection &proj); + double TrueScaleLatitude() const; + + private: + double p_centerLongitude; //! +#include +#include "iException.h" +#include "Equirectangular.h" +#include "ProjectionFactory.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main (int argc, char *argv[]) { + Preference::Preferences(true); + + cout << "UNIT TEST FOR Equirectangular" << endl << endl; + + Pvl lab; + lab.AddGroup(PvlGroup("Mapping")); + PvlGroup &mapGroup = lab.FindGroup("Mapping"); + mapGroup += PvlKeyword("EquatorialRadius",1.0); + mapGroup += PvlKeyword("PolarRadius",1.0); + mapGroup += PvlKeyword("LatitudeType","Planetocentric"); + mapGroup += PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += PvlKeyword("LongitudeDomain",180); + mapGroup += PvlKeyword("MinimumLatitude",-90.0); + mapGroup += PvlKeyword("MaximumLatitude",90.0); + mapGroup += PvlKeyword("MinimumLongitude",-180.0); + mapGroup += PvlKeyword("MaximumLongitude",180.0); + mapGroup += PvlKeyword("ProjectionName","Equirectangular"); + + cout << "Test missing center longitude keyword ..." << endl; + try { + Equirectangular p(lab); + } + catch (iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += PvlKeyword("CenterLongitude",-90.0); + + cout << "Test missing center latitude keyword ..." << endl; + try { + Equirectangular p(lab); + } + catch (iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += PvlKeyword("CenterLatitude",0.0); + + Projection &p = *ProjectionFactory::Create(lab); + + cout << "Test SetGround method ... " << endl; + cout << std::setprecision(16); + cout << "Setting ground to (-50,-75)" << endl; + p.SetGround(-50.0,-75.0); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + + cout << "Test SetCoordinate method ... " << endl; + cout << "Setting coordinate to (0.2617993877991494,-0.8726646259971648)" << endl; + p.SetCoordinate(0.2617993877991494,-0.8726646259971648); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + cout << "Test XYRange method ... " << endl; + double minX,maxX,minY,maxY; + p.XYRange(minX,maxX,minY,maxY); + cout << "Minimum X: " << minX << endl; + cout << "Maximum X: " << maxX << endl; + cout << "Minimum Y: " << minY << endl; + cout << "Maximum Y: " << maxY << endl; + cout << endl; + + cout << "Test TrueScaleLatitude method..." << endl; + cout << "TrueScaleLatitude = " << p.TrueScaleLatitude() << endl; + cout << endl; + + Projection *s = &p; + cout << "Test Name and comparision methods ... " << endl; + cout << "Name: " << s->Name() << endl; + cout << "operator== " << (*s == *s) << endl; + cout << endl; + + cout << "Testing default option ... " << endl; + mapGroup.DeleteKeyword("CenterLongitude"); + mapGroup.DeleteKeyword("CenterLatitude"); + Equirectangular p2(lab,true); + cout << lab << endl; + cout << endl; + + cout << "Testing Mapping() methods ... " << endl; + + Pvl tmp1; + Pvl tmp2; + Pvl tmp3; + tmp1.AddGroup(p.Mapping()); + tmp2.AddGroup(p.MappingLatitudes()); + tmp3.AddGroup(p.MappingLongitudes()); + + cout << "Mapping() = " << endl; + cout << tmp1 << endl; + cout << "MappingLatitudes() = " << endl; + cout << tmp2 << endl; + cout << "MappingLongitudes() = " << endl; + cout << tmp3 << endl; + cout << endl; + + std::cout << "Check Invalid Latitude" << std::endl; + mapGroup.AddKeyword(PvlKeyword("CenterLatitude", 90.0), Pvl::Replace); + std::cout << mapGroup << std::endl; + try { + Equirectangular p2(lab); + } + catch (iException &e) { + e.Report(false); + } +} + + + diff --git a/isis/src/base/objs/FileList/FileList.cpp b/isis/src/base/objs/FileList/FileList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1a66568b1b118ad653e8e18178708b4a264d36e --- /dev/null +++ b/isis/src/base/objs/FileList/FileList.cpp @@ -0,0 +1,203 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/02/20 16:28:21 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "FileList.h" +#include "iException.h" +#include "Message.h" +#include "Filename.h" +#include "iString.h" + +using namespace std; +namespace Isis { + +/** + * Constructs an empty FileList. + * + */ + FileList::FileList () { + } + +/** + * Constructs a FileList from a file. + * + * @param list Name of the file containing a list of files. + */ + FileList::FileList (const std::string &list) { + Read(list); + } + +/** + * Constructs a FileList from a stream. + * + * @param in An input stream containing a list of files. + */ + FileList::FileList (std::istream &in) { + Read(in); + } + +/** + * Opens and loads the list of files from a file. + * + * @param list Name of the file to open that contains the list of files. + * + * @throws Isis::iException::Io - Cannot open file + */ + void FileList::Read(const std::string &list) { + // Set up for opening + Isis::Filename temp(list); + string file = temp.Expanded(); + ifstream istm; + + // Open the file + istm.open(file.c_str(),std::ios::in); + if (!istm) { + string message = Isis::Message::FileOpen(file); + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + + // Internalize + try { + Read(istm); + + // Close the file + istm.close(); + } + catch (Isis::iException &e) { + istm.close(); + string msg = "File [" + file + "] contains no data"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + } + +/** + * Loads list of files from a stream. + * This takes in a stream and loads a file list from it. The lines in the stream + * are considered separate entries, and comments are ignored. comments are + * considered to be any line starting with a '#' or '//', and anything after any + * whitespace following the first text on the line. + * + * @param in An input stream containing a list of files. + * + */ + void FileList::Read(std::istream &in) { + // Read each file and put it in the vector + char buf[65536]; + Isis::iString s; + bool bHasQuotes = false; + + in.getline(buf,65536); + bool isComment = false; + while (!in.eof()) { + s = buf; + string::size_type loc = s.find("\"", 0); + + if(loc != string::npos) { + bHasQuotes = true; + } + + if(bHasQuotes) { + s = s.TrimHead("\""); + s = s.TrimTail("\""); + } + + s = s.TrimHead(" \n\r\t\v"); + + isComment = false; + if (strlen(buf) == 0) { + in.getline(buf,65536); + continue; + } + for (int index = 0; index < (int)strlen(buf); index++) { + if (buf[index] == '#' || (buf[index] == '/' && buf[index+1] == '/')) { + isComment = true; + break; + } + else if (buf[index] == ' ') { + continue; + } + else { + isComment = false; + break; + } + } + if (isComment) { + in.getline(buf,65536); + continue; + } + else{ + + if(bHasQuotes) { + s = s.Token(" \n\r\t\v"); + }else { + s = s.Token(" \n\r\t\v,"); + } + + this->push_back(s); + in.getline(buf,65536); + } + } + if (this->size() == 0) { + string msg = "Input Stream Empty"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + +/** + * Writes a list of files to a file. + * + * @param list The name of the file to create. The method will overwrite any + * existing files. + * + * @throws Isis::iException::Io File could not be created. + */ + void FileList::Write(const std::string &list) { + // Set up for opening + Isis::Filename temp(list); + string file = temp.Expanded(); + ofstream ostm; + + // Open the file + ostm.open(file.c_str(),std::ios::out); + if (!ostm) { + string message = Isis::Message::FileOpen(file); + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + + // Internalize + Write(ostm); + + // Close the file + ostm.close(); + } + +/** + * Writes a list of files to a stream. + * + * @param out The list will be written to this output stream. + */ + void FileList::Write(std::ostream &out) { + for (unsigned int i=0; isize(); i++) { + out << (*this)[i] << endl; + } + } +} // end isis namespace diff --git a/isis/src/base/objs/FileList/FileList.h b/isis/src/base/objs/FileList/FileList.h new file mode 100644 index 0000000000000000000000000000000000000000..d240b1cbde9faf4aee5195a3ebfa530653d6b1fa --- /dev/null +++ b/isis/src/base/objs/FileList/FileList.h @@ -0,0 +1,82 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/02/20 16:28:21 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef FileList_h +#define FileList_h + +#include +#include +#include +#include + +namespace Isis { +/** + * @brief Internalizes a list of files. + * + * This class reads a list of filenames from a file an internalizes them in a + * standard template vector of strings. Thus, a file like: + * @code + * m0035431.imq + * m0030402.imq + * m0033231.imq + * . + * . + * . + * m0203331.imq + * @endcode + * Will be internalized as and accessable as an vector. + * + * @ingroup Parsing + * + * @author 2003-05-01 Jeff Anderson + * + * @internal + * @history 2003-05-16 Stuart Sides - modified schema from + * astrogeology... isis.astrogeology... + * @history 2005-03-16 Leah Dahmer - modified file to support Doxygen + * documentation. + * @history 2006-04-05 Elizabeth Miller - Added error message to catch empty + * files + * @history 2007-01-04 Brendan George - Added comment recognition and it now + * only reads the first column + * @history 2007-02-19 Stacy Alley - modified the Read method + * such that if a file name and it's attributes are + * surround with double quotes, then don't use commas + * as a 'end of line' signal. + */ + class FileList : public std::vector { + public: + FileList (const std::string &list); + FileList (std::istream &in); + FileList (); + + //! Destroys the FileList object. + ~FileList () {}; + + void Read(const std::string &list); + void Read(std::istream &in); + void Write(const std::string &list); + void Write(std::ostream &out); + }; +}; + +#endif diff --git a/isis/src/base/objs/FileList/FileList.truth b/isis/src/base/objs/FileList/FileList.truth new file mode 100644 index 0000000000000000000000000000000000000000..e526e698dac837595628df6ce52e3f4016e4a65c --- /dev/null +++ b/isis/src/base/objs/FileList/FileList.truth @@ -0,0 +1,10 @@ +Testing on unitTest.list: +/usgs/pkgs/isis3/isis/src/base/objs/FileList/FileList.cpp +/usgs/pkgs/isis3/isis/src/base/objs/FileList/FileList.h +unitTest.cpp +>This +^is +Makefile +FileList.h +Testing on nonexistant file: +Unable to open the file diff --git a/isis/src/base/objs/FileList/Makefile b/isis/src/base/objs/FileList/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ae2e4abb34fda3022b0ac31aefb51ca7f8fc7c44 --- /dev/null +++ b/isis/src/base/objs/FileList/Makefile @@ -0,0 +1,5 @@ +INCS = FileList.h +SRCS = FileList.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/FileList/unitTest.cpp b/isis/src/base/objs/FileList/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..228e35d0d23961cfafe6bbbede035f1864ba733e --- /dev/null +++ b/isis/src/base/objs/FileList/unitTest.cpp @@ -0,0 +1,22 @@ +#include "FileList.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +int main (void) { + Isis::Preference::Preferences(true); + cout << "Testing on unitTest.list:" << endl; + Isis::FileList fl2("unitTest.list"); + fl2.Write(cout); + + cout << "Testing on nonexistant file:" << endl; + try { + Isis::FileList fl2("NoWayThisFileExists"); + } + catch (Isis::iException &e) { +// e.Report(false); + cerr << "Unable to open the file" << endl; + } + return 0; +} diff --git a/isis/src/base/objs/FileList/unitTest.list b/isis/src/base/objs/FileList/unitTest.list new file mode 100644 index 0000000000000000000000000000000000000000..e5f5167bd69d4e9980858fc463a8f3e8c85eb17a --- /dev/null +++ b/isis/src/base/objs/FileList/unitTest.list @@ -0,0 +1,14 @@ +/usgs/pkgs/isis3/isis/src/base/objs/FileList/FileList.cpp +/usgs/pkgs/isis3/isis/src/base/objs/FileList/FileList.h +#Comment +unitTest.cpp +>This will not be comment ignored + +^is a blank line, this line will not be ignored as a comment + Makefile + //Testing comment with prepended spaces + +#Above and below are for testing multiple blank lines + + +FileList.h diff --git a/isis/src/base/objs/Filename/Filename.cpp b/isis/src/base/objs/Filename/Filename.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0371646abf741176dd58dd8882a23b772ca4f4d6 --- /dev/null +++ b/isis/src/base/objs/Filename/Filename.cpp @@ -0,0 +1,496 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2009/01/07 18:33:38 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "Preference.h" +#include "iString.h" +#include "iException.h" +#include "Filename.h" + +using namespace std; +namespace Isis { + + //! Constructs an empty Filename object. + Filename::Filename () { + p_original.clear(); + } + +/** + * Constructs a Filename object and expands environment variables and + * Preferences from the DataDirectory group embedded in the filename. + * + * @param file A string containing a filename. + */ + Filename::Filename (const std::string &file) + : QFileInfo () { + p_original = file; + QFileInfo::setFile ((iString)Expand (file)); + } + +/** + * Creates a temporary filename from the arguments. The new filename is checked + * to make sure it doesn't exist, but race conditions could still occur between + * the time the file is checked for existance and the application attempts to + * create the file. + * + * @param name Name of the temporary file. + * + * @param extension Extension of the temporary file. + */ + Filename::Filename (const std::string &name, const std::string &extension) { + Temporary (name, extension); + } + + //! Destroys the Filename object. + Filename::~Filename () {} + +/** + * Clears the current contents of the Filename object and reinitializes it with + * the argument. + * + * @param file File name to replace the current contents of the object. + */ + void Filename::operator=(const std::string &file) { + p_original = file; + QFileInfo::setFile ((iString)Expand (file)); + } + +/** + * Clears the current contents of the Filename object and reinitializes it with + * the argument. + * + * @param file File name to replace the current contents of the object. + */ + void Filename::operator=(const char *file) { + p_original = file; + QFileInfo::setFile ((iString)Expand (file)); + } + +/** + * Returns the path + * Returns the path portion of a filename. For *nix operating + * systems this includes everything upto but not including the + * last slash "/". For file names created without any slashes + * the current working directory will be returned. + *
    + *   for a full file specification of:
    + *   "/home/me/img/picture.jpg"
    + *   Path() gives:
    + *   "/home/me/img"
    + * 
    + */ + std::string Filename::Path() const { + return QFileInfo::absolutePath().toStdString(); + } + +/** + * Returns the basename + * Returns the file name only. This excludes any path and the last extension. + * For *nix operating systems this includes everything following the last slash + * "/" and upto the last dot ".". If a file name contains multiple extensions, + * all but the last one will be returned. If a file name has no extension, + * Basename returns the same as Name + */ + std::string Filename::Basename() const { + if (QFileInfo::suffix().length() == 0) { + return QFileInfo::baseName().toStdString(); + } + else { + return QFileInfo::completeBaseName().toStdString(); + } + } + +/** + * Returns the filename. + * Returns the file name and all extensions of the filename. For + * *nix operating systems this includes everything following the + * last slash "/". + */ + std::string Filename::Name() const { + return QFileInfo::fileName().toStdString(); + } + +/** + * Returns the extension (Does not include .) + * Returns the extension of the filename. If multiple extensions + * exist, then only the last one will be returned. + */ + std::string Filename::Extension () const { + return QFileInfo::suffix().toStdString(); + } + +/** + * Returns the full filename (path, basename and extension(s)) + * Returns a fully expanded version of the file name. This will + * include the expansion of any Isis Preference variables, + * environment variables and operating system shortcuts such as + * ".", "..", or "~" + */ + std::string Filename::Expanded () const { + return QFileInfo::absoluteFilePath().toStdString(); + } + +/** + * Returns whether the file exists or not. + * + * @return True if the file exists, false if it doesn't. + */ + bool Filename::Exists () { + return QFileInfo::exists(); + } + +/** + * Returns the path used to initialize the Filename object, if any. + */ + std::string Filename::OriginalPath() const { + QFileInfo fi(p_original.c_str()); + return fi.path().toStdString(); + } + +/** + * Adds an extension to the filename. If the existing extension is the same + * nothing is added. If it is different then the existing + * extensions is added to the basename. For example, + * base="temp", ext="cub" and invoking AddExtension("jpg") gives + * base="temp.cub" and ext="jpg". If the existing extension is + * null then it is replaced. + * + * @param ext Extention to add. + */ + void Filename::AddExtension (const std::string &ext) { + // Don't modify the extension if it is already there + if (Extension() == ext) return; + + // Add the argument as an extension to the current filename + if (ext.length() > 0) { + QFileInfo::setFile (iString(Expanded() + "." + ext)); + } + } + + /** + * Removes all extensions from the file name. + */ + void Filename::RemoveExtension () { + QFileInfo::setFile (iString(this->Path() + "/" + this->Basename())); + } + +/** + * Searches for a filename with the highest integer version number. Version + * numbers are defined as a sequence of question marks "?" in the filename. + * Only one sequence is allowed per filename. The already internalized filename + * is used as the directory to be searched, and it is used as the template for + * where the version number is located. The search is not recursive. The + * original name stored in the Filename object will be overwritten with the + * results of the search. + * + * @throws Isis::iException::Io - The path does not exist + * @throws Isis::iException::Programmer - No versions available for the file + */ + void Filename::HighestVersion (){ + + CheckVersion(); + + int highestVersion = -1; + Isis::iString highestVersionStr; + + // Get the path of the current file and make sure it exists + QDir dir((QString)(iString)Path()); + if (!dir.exists()) { + string msg = "The path [" + Path() + "] does not exist"; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + // Find the beginning and end of the "?"s in the versioned filename + unsigned int start = Name().find_first_of("?"); + unsigned int end = Name().find_last_of("?"); + unsigned int charsAfterVersion = Name().length() - end - 1; + + + // Loop through all files in the dir and see if they match our name + for (unsigned int indx=0; indx < dir.count(); indx++) { + + string file = dir[indx].toStdString(); + bool leftSide = file.substr(0, start) == Name().substr(0, start); + bool rightSide = ((int)file.length()-(int)charsAfterVersion) >= 0; + if (rightSide) { + rightSide = rightSide && + (file.substr(file.length()-charsAfterVersion) == Name().substr(end+1)); + } + + if (leftSide && rightSide) { + + Isis::iString version = file.substr(start, file.length()-charsAfterVersion-start); + + if ((version.length() > 0) && + (version.find_first_not_of("0123456789") == string::npos) && + (version.ToInteger() > highestVersion)) { + highestVersion = version.ToInteger(); + highestVersionStr = version; + } + } + } + + // Make sure we got a version number + if (highestVersion == -1) { + string msg = "No versions available for file [" + Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + + string temp = Path() + "/" + Name().substr(0, start) + + highestVersionStr + Name().substr(end+1); + QFileInfo::setFile(temp.c_str()); + } + +/** + * Creates a filename with a version number one higher than the previous highest + * integer version number. Version numbers are defined as a sequence of question + * marks "?" in the filename. Only one sequence is allowed per filename. The + * already internalized filename is used as the directory to be searched, and + * it is used as the template for where the version number is located. The + * search is not recursive. As is the case with HighestVersion, The original + * name stored in the Filename object will be overwritten with the results of + * the search. Thus, a user may operate on a Filename to change the sequence of + * question marks to the highest version, or the new version, but may not do + * both operations on the same Filename. + * + * @throws Isis::iException::Io - The path does not exist + * @throws Isis::iException::Programmer - No versions available for the file + */ + void Filename::NewVersion (){ + + CheckVersion(); + + // Get the path of the current file and make sure it exists + QDir dir((QString)(iString)Path()); + if (!dir.exists()) { + string msg = "The path [" + Path() + "] does not exist"; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + // Find the beginning and end of the "?"s in the versioned filename + unsigned int start = Name().find_first_of("?"); + unsigned int end = Name().find_last_of("?"); + unsigned int charsAfterVersion = Name().length() - end - 1; + + int highestVersion = 0; + // Loop through all files in the dir and see if they match our name + for (unsigned int indx=0; indx < dir.count(); indx++) { + + string file = dir[indx].toStdString(); + bool leftSide = file.substr(0, start) == Name().substr(0, start); + bool rightSide = ((int)file.length()-(int)charsAfterVersion) >= 0; + if (rightSide) { + rightSide = rightSide && + (file.substr(file.length()-charsAfterVersion) == Name().substr(end+1)); + } + + if (leftSide && rightSide) { + + Isis::iString version = file.substr(start, file.length()-charsAfterVersion-start); + + if ((version.length() > 0) && + (version.find_first_not_of("0123456789") == string::npos) && + (version.ToInteger() > highestVersion)) { + highestVersion = version.ToInteger(); + } + } + } + //create a string with the new version number + Isis::iString newVersion = ++highestVersion; + + + + //pad each extra "?" with a 0. This maintains the length of the Filename + //so that "file.???.ext" will be "file.001.ext" instead of "file.1.ext" + int zeroesNeeded = end - start - newVersion.length(); + for (int i = 0 ; i <= zeroesNeeded; i++){ + newVersion = "0" + newVersion; + } + + string temp = Path() + "/" + Name().substr(0, start) + + newVersion + Name().substr(end+1); + QFileInfo::setFile(temp.c_str()); + } + +/** + * Makes a directory. + * + * @throws Isis::iException::Programmer - Unable to create the directory + */ + void Filename::MakeDirectory() { + + QDir dir; + if (!dir.mkdir(iString(Expanded()))) { + string msg = "Unable to create directory [" + Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Programmer, + msg, _FILEINFO_); + } + + } + +/** + * Create a temporary file. If the Preference "DataDirectory->Temporary" + * exists then the file will be created there. If not the file will be created + * using only what is specified in the current filename. The filename will + * consist of the current name with a number between 100000 and 999999 appended + * to the name portion. + * + * @param name The name of the temporary file. + * + * @param extension The extension of the temporary file. + * + * @throws Isis::iException::Io - No temporary files available for the given + * name and extension + */ + void Filename::Temporary (const std::string &name, const std::string &extension) { + string tempDir; + tempDir.clear(); + // If the IsisPreference exists use it otherwise just use name as is + if (!(name.at(0)=='/') && Isis::Preference::Preferences().HasGroup("DataDirectory")) { + Isis::PvlGroup &dataDir = Isis::Preference::Preferences().FindGroup("DataDirectory"); + if (dataDir.HasKeyword("Temporary")) { + tempDir = (string) dataDir["Temporary"]; + } + } + + // Start off by appending "100000" to the name if that file exists + // increment it and try again + int add = 100000; + string tfile; + + do { + Isis::iString num(add); + tfile = tempDir + "/" + name + num + "." + extension; + QFileInfo f(tfile.c_str()); + if (f.exists()) { + add++; + } + else { + p_original = tfile; + QFileInfo::setFile (tfile.c_str()); + return; + } + } while (add < 1000000); + + string msg = "No temporary files available for [" + name + extension + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + + } + +/** + * Expand any $xxxxx into Isis preference and environment variables. + * Note: "DataDirectory" is the only group search in Preferences. + * + * @param file The file to be expanded. + * + * @return string + */ + string Filename::Expand (const std::string &file) { + + // Setup an index for searching strings + std::string::size_type pos, pos2; + + // Work with a tempory copy + string temp = file; + + // Strip off any cube attributes + if ((pos = temp.find("+")) != std::string::npos) temp.erase(pos); + + + // Expand any $xxxxx into ISIS preferences and environment variables + // *** NOTE *** This may be very operating system dependent + string prefVar; + string var; + pos = 0; + + // Loop while there are any "$" at the current position or after + // Some "$" might be skipped if no translation can be found + while ((pos = temp.find("$", pos)) != std::string::npos) { + pos2 = temp.find ("/", pos); + var = temp.substr(pos+1, pos2-pos-1); + string value; + value.clear(); + + // Find the corresponding Isis Preference if one exists + if (Isis::Preference::Preferences().HasGroup("DataDirectory")) { + Isis::PvlGroup &dataDir = Isis::Preference::Preferences().FindGroup("DataDirectory"); + if (dataDir.HasKeyword(var)) { + value = (string) dataDir[var]; + } + } + + // Find the corresponding environment variable if one exists + if (value.length() == 0) { + char *val; + val = getenv(var.c_str()); + if (val != NULL) value = val; + } + + // Replace the $xxxx with the pref/env, but don't move + // the pointer. We may have replaced one $ for another. + // Note: May need to put a test for circular replaces in here + if (value.length() > 0) { + temp.replace (pos, pos2-pos, value); + } + // No pref or env was available so ignore this "$" and move on + else { + pos++; + } + } + return temp; + } + + /** + * Check the current filename for a valid version sequence of "?"s + * + * @throws Isis::iException::Programmer - File does not contain a version + * @throws Isis::iException::Programmer - File has too many version sequences, + * only one is allowed + */ + void Filename::CheckVersion () const { + + // Find the series of "?" + string name = Expanded(); + + std::string::size_type start = name.find_first_of("?"); + std::string::size_type end = name.find_last_of("?"); + + // Make sure there was at least one "?" for a version number + if (start == string::npos || end == string::npos) { + string msg = "Filename [" + Expanded() + + "] does not contain a version sequence"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + + // Make sure all chars between start and end are "?" + for (unsigned int pos=start; pos<=end; ++pos) { + if (name[pos] != '?') { + string msg = "Only one version sequence is allowed per filename [" + + Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + } + } +} // end namespace Isis diff --git a/isis/src/base/objs/Filename/Filename.h b/isis/src/base/objs/Filename/Filename.h new file mode 100644 index 0000000000000000000000000000000000000000..7047051c9e37b274801530e161c4d5d5b1dd0056 --- /dev/null +++ b/isis/src/base/objs/Filename/Filename.h @@ -0,0 +1,166 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/01/07 18:55:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef Isis_Filename_h +#define Isis_Filename_h + +#include +#include + +#include +#include + +namespace Isis { +/** + * @brief Filename manipulation and expansion. + * + * This class is used for manipulating filenames. It allows access to the path, + * extension, base name and attributes. A standard Isis filename takes the + * form of + * @code + * /path/base.extension:attribute + * @endcode + * For example: + * @code + * /work1/mars.cub:5 + * @endcode + * + * @ingroup Parsing + * + * @author 2002-06-11 Jeff Anderson + * + * @internal + * @todo This class needs an example. + * @history 2002-11-27 Stuart Sides - added capability to expand environment + * variables within a filename. + * @history 2003-01-27 Jeff Anderson - added a method to allow full file + * specification to be extracted (includes the attributes. + * @history 2002-02-12 Stuart Sides - fixed bug with incorrect parsing when + * filename did not have a path. + * @history 2003-05-16 Stuart Sides - modified schema from + * astrogeology...isis.astrogeology. + * @history 2003-07-21 Stuart Sides - modified to use "+" as the attribute + * delimiter instead of a ":". + * @history 2003-10-17 Added default constructor, operator "=" and temporary + * members. + * @history 2003-10-30 Added new members: HighestVersion and Exists. + * @history 2003-12-03 Added capability to expand Preferences in the + * DataDirectory group only. + * @history 2004-01-14 Added new member OriginalPath. + * @history 2004-01-22 Added new member Name. Name returns the filename only + * without any path, extension or attributes. + * @history 2004-01-27 Tool all references to attributes out. IsisFilename + * now ignores all cube attributes. + * @history 2004-01-27 Removed the member FullSpecification, because + * FullSpecification without the cube attributes now does + * the same thing as Filename. + * @history 2004-01-27 Added a new constructor with two parameters. This new + * constructor will create a temporary filename using the + * path from the Preference DataDirectory/Temporary the + * filename from argument one appended with a number from + * 100000 to 199999 and the extension of argument two. + * @history 2004-05-17 Added new member MakeDirectory. + * @history 2005-07-28 Drew Davidson - added new member NewVersion. + * @history 2007-10-03 Steven Koechle - Fixed Temporary() so if a path was + * specified it will have the cwd put on in front of it. + * @history 2009-01-07 Steven Lambright - Expanded(...) no longer behaves + * differently for unit tests + * + * + */ + class Filename : public QFileInfo { + public: + // Create an empty filename + Filename (); + + // Create a new Filename with the string + Filename (const std::string &filename); + + // Create a new Filename using the users temporary directory + // preference with the name and extension specified + Filename (const std::string &Name, const std::string &extension); + + // Destroys the Filename Object + ~Filename (); + + // Set the filename to the argument + void operator=(const std::string &filename); + void operator=(const char *filename); + + // Return only the path + std::string Path() const; + + // Return the name without the extension or path + std::string Basename () const; // equiv to qt baseName + // renamed from Name + + // Return only the name with extension and without the path + std::string Name () const; // equiv to qt fileName + // renamed from Basename + + // Return only the extension (no path, name or ".") + std::string Extension () const; // equiv to qt extension + + // Return the expanded filename (path, name & extension) + std::string Expanded () const; // mostly qt absFilePath without $ expansion + + // Return the original path without "$" expansion if any + std::string OriginalPath() const; + + // Add an extension to an existing Filename + // Doesn't do anything if an extension already exists + void AddExtension (const std::string &extension); + + // Remove the extension + void RemoveExtension (); + + // Find the highest version of a filename + void HighestVersion (); + + // Find the highest version + 1 of a filename + void NewVersion(); + + // Return true if the file exists + bool Exists (); + + // Create a directory + void MakeDirectory (); + + // Create a temporary filename using the + // Isis::Preference DataDirectory/Temporary + // directory with the name and extension of the arguments + void Temporary (const std::string &name, const std::string &extension); + + private: + + // Expand any "$xxxx" into Isis preferences and environment variables + // THe "DataDirectory" is the only group searched in IsisPreferences + std::string Expand (const std::string &file); + + void CheckVersion () const; + + std::string p_original; //!< The original filename saved at construction + + }; +}; + +#endif diff --git a/isis/src/base/objs/Filename/Filename.truth b/isis/src/base/objs/Filename/Filename.truth new file mode 100644 index 0000000000000000000000000000000000000000..2e33d0efc898164482369a66a084b292d6080aa7 --- /dev/null +++ b/isis/src/base/objs/Filename/Filename.truth @@ -0,0 +1,191 @@ +Testing Basics ... +Original filename: /path/base.ext+attr +Path: /path +Name: base.ext +Basename: base +Extension: ext +Filename: /path/base.ext +Original path /path + +Testing Extension change ... +Filename: /path/base.tmp +Filename: /path/base.tmp.jpg + +Testing path with a dot and extension ... +Original filename: /path1/.path2/base.ext+attr +Path: /path1/.path2 +Name: base.ext +Basename: base +Extension: ext +Filename: /path1/.path2/base.ext +Original path /path1/.path2 + +Testing path with dot and no extension ... +Original filename: /path1/pat.h2/base+attr +Path: /path1/pat.h2 +Name: base +Basename: base +Extension: +Filename: /path1/pat.h2/base +Original path /path1/pat.h2 + +Testing path starting with a dot ... +Original filename: /.path1/path2/base +Path: /.path1/path2 +Name: base +Basename: base +Extension: +Filename: /.path1/path2/base +Original path /.path1/path2 + +Testing file with a dot at the end ... +Original filename: /.path1/path2/base.+attr +Path: /.path1/path2 +Name: base. +Basename: base +Extension: +Filename: /.path1/path2/base. +Original path /.path1/path2 + +Testing file name with multiple extensions... +Original filename: /path/base.ex1.exten2.ext3 +Path: /another/path +Name: base.ex1.exten2.ext3 +Basename: base.ex1.exten2 +Extension: ext3 +Filename: /another/path/base.ex1.exten2.ext3 +Original path /another/path + +Testing environment variable expansion +Original filename: $base/testData/isisTruth.cub +Filename was expanded correctly +Name: isisTruth.cub +Basename: isisTruth +Extension: cub +Original path $base/testData + +Testing bad environment variable expansion +Original filename: $BADENV/base.ext+attr +New filename: /$BADENV/base.ext +Path: /$BADENV +Name: base.ext +Basename: base +Extension: ext +Original path /$BADENV + +Testing ISIS preference variable expansion +Original filename: /$TEMPORARY/unitTest.cpp +New filename: /unitTest.cpp +Name: unitTest.cpp +Basename: unitTest +Extension: cpp +Original path /$TEMPORARY + +Testing file name without a path +Original filename: unitTest.cpp +Filename was expanded correctly +Name: unitTest.cpp +Basename: unitTest +Extension: cpp +Original path . + +Testing file name with . as the path +Original filename: ./unitTest.cpp +Filename was expanded correctly +Name: unitTest.cpp +Basename: unitTest +Extension: cpp +Original path . + +Testing file name with no path and no extension +Original filename: Makefile +Filename was expanded correctly +Name: Makefile +Basename: Makefile +Extension: +Original path . + +Testing file name with no path and only an extension +Original filename: .cub +Name: .cub +Basename: +Extension: cub +Original path . + +Testing filename operator= with a c++ string +Original filename: /home/me/new.extension+0:255 +New filename: /home/me/new.extension +Path: /home/me +Name: new.extension +Basename: new +Extension: extension +Original path /home/me + +Testing filename operator= with a c string +Original filename: /home/me/new.extension+0:255 +New filename: /home/me/new.extension +Path: /home/me +Name: new.extension +Basename: new +Extension: extension +Original path /home/me + +Testing 1st temporary file name +Name and extension : tttt, tmp +Name: tttt100000.tmp +Basename: tttt100000 +Extension: tmp +Original path . + +Testing 2nd temporary file name +Name and extension : tttt, tmp +Name: tttt100001.tmp +Basename: tttt100001 +Extension: tmp +Original path . + +Testing HighestVersion for file tttt??????.tmp + tttt000008.tmp + +Testing HighestVersion for file tttt?????? + tttt000001 + +Testing HighestVersion for file ?tttt000008.tmp + 2tttt000008.tmp + +Testing HighestVersion for file tttt +No version string in tttt + +Testing HighestVersion for file ??tttt +No version available for ??tttt + +Testing HighestVersion to expand 1 "?" into 2 digits +junk09.tmp + +Testing NewVersion for file tttt??????.tmp + tttt000009.tmp + +Testing NewVersion for file tttt?????? + tttt000002 + +Testing NewVersion for file ?tttt000008.tmp + 3tttt000008.tmp + +Testing NewVersion for file tttt +No version string in tttt + +Testing NewVersion for file ??tttt + 01tttt + +Testing Exists() for a file that should exist: + The test file for "Exists()" was located + +Testing Exists() for a file that does NOT exist: + The test file for "!Exists()" was not located (this is correct) + +Testing MakeDirctory for /tmp/IsisFilenameTest + The directory create succeed + +Testing MakeDirectory for /tmp/IsisFilenameTest +**PROGRAMMER ERROR** Unable to create directory [/tmp/IsisFilenameTest] + diff --git a/isis/src/base/objs/Filename/Makefile b/isis/src/base/objs/Filename/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5e854aec6390fed8759de41630fa4a275cbe91a3 --- /dev/null +++ b/isis/src/base/objs/Filename/Makefile @@ -0,0 +1,5 @@ +INCS = Filename.h +SRCS = Filename.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Filename/unitTest.cpp b/isis/src/base/objs/Filename/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a787ffb762e036a81aa8aba6c191b48297b55ec9 --- /dev/null +++ b/isis/src/base/objs/Filename/unitTest.cpp @@ -0,0 +1,486 @@ +#include +#include + +#include "Preference.h" +#include "iException.h" +#include "Filename.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + try { + + Isis::Preference::Preferences(true); + + Isis::Filename f("/path/base.ext+attr"); + + cout << "Testing Basics ..." << endl; + cout << "Original filename: " << "/path/base.ext+attr" << endl; + cout << "Path: " << f.Path() << endl; + cout << "Name: " << f.Name() << endl; + cout << "Basename: " << f.Basename() << endl; + cout << "Extension: " << f.Extension() << endl; + cout << "Filename: " << f.Expanded() << endl; + cout << "Original path " << f.OriginalPath() << endl; + cout << endl; + + cout << "Testing Extension change ..." << endl; + f.RemoveExtension(); + f.AddExtension("tmp"); + cout << "Filename: " << f.Expanded() << endl; + f.AddExtension("jpg"); + f.AddExtension("jpg"); + cout << "Filename: " << f.Expanded() << endl; + cout << endl; + + Isis::Filename fa("/path1/.path2/base.ext+attr"); + cout << "Testing path with a dot and extension ..." << endl; + cout << "Original filename: " << "/path1/.path2/base.ext+attr" << endl; + cout << "Path: " << fa.Path() << endl; + cout << "Name: " << fa.Name() << endl; + cout << "Basename: " << fa.Basename() << endl; + cout << "Extension: " << fa.Extension() << endl; + cout << "Filename: " << fa.Expanded() << endl; + cout << "Original path " << fa.OriginalPath() << endl; + cout << endl; + + Isis::Filename fb("/path1/pat.h2/base+attr"); + cout << "Testing path with dot and no extension ..." << endl; + cout << "Original filename: " << "/path1/pat.h2/base+attr" << endl; + cout << "Path: " << fb.Path() << endl; + cout << "Name: " << fb.Name() << endl; + cout << "Basename: " << fb.Basename() << endl; + cout << "Extension: " << fb.Extension() << endl; + cout << "Filename: " << fb.Expanded() << endl; + cout << "Original path " << fb.OriginalPath() << endl; + cout << endl; + + Isis::Filename fc("/.path1/path2/base"); + cout << "Testing path starting with a dot ..." << endl; + cout << "Original filename: " << "/.path1/path2/base" << endl; + cout << "Path: " << fc.Path() << endl; + cout << "Name: " << fc.Name() << endl; + cout << "Basename: " << fc.Basename() << endl; + cout << "Extension: " << fc.Extension() << endl; + cout << "Filename: " << fc.Expanded() << endl; + cout << "Original path " << fc.OriginalPath() << endl; + cout << endl; + + Isis::Filename fd("/.path1/path2/base.+attr"); + cout << "Testing file with a dot at the end ..." << endl; + cout << "Original filename: " << "/.path1/path2/base.+attr" << endl; + cout << "Path: " << fd.Path() << endl; + cout << "Name: " << fd.Name() << endl; + cout << "Basename: " << fd.Basename() << endl; + cout << "Extension: " << fd.Extension() << endl; + cout << "Filename: " << fd.Expanded() << endl; + cout << "Original path " << fd.OriginalPath() << endl; + cout << endl; + + Isis::Filename f2("/another/path/base.ex1.exten2.ext3"); + cout << "Testing file name with multiple extensions..." << endl; + cout << "Original filename: " << "/path/base.ex1.exten2.ext3" << endl; + cout << "Path: " << f2.Path() << endl; + cout << "Name: " << f2.Name() << endl; + cout << "Basename: " << f2.Basename() << endl; + cout << "Extension: " << f2.Extension() << endl; + cout << "Filename: " << f2.Expanded() << endl; + cout << "Original path " << f2.OriginalPath() << endl; + cout << endl; + + cout << "Testing environment variable expansion" << endl; + Isis::Filename g("$base/testData/isisTruth.cub"); + cout << "Original filename: " << "$base/testData/isisTruth.cub" << endl; + if (g.Exists()) { + cout << "Filename was expanded correctly" << endl; + } + else { + cout << "Filename was NOT expanded correctly" << endl; + } + cout << "Name: " << g.Name() << endl; + cout << "Basename: " << g.Basename() << endl; + cout << "Extension: " << g.Extension() << endl; + cout << "Original path " << g.OriginalPath() << endl; + cout << endl; + + cout << "Testing bad environment variable expansion" << endl; + Isis::Filename h("/$BADENV/base.ext+attr"); + cout << "Original filename: " << "$BADENV/base.ext+attr" << endl; + cout << "New filename: " << h.Expanded() << endl; + cout << "Path: " << h.Path() << endl; + cout << "Name: " << h.Name() << endl; + cout << "Basename: " << h.Basename() << endl; + cout << "Extension: " << h.Extension() << endl; + cout << "Original path " << h.OriginalPath() << endl; + cout << endl; + + cout << "Testing ISIS preference variable expansion" << endl; + Isis::Filename g2("/$TEMPORARY/unitTest.cpp"); + cout << "Original filename: " << "/$TEMPORARY/unitTest.cpp" << endl; + cout << "New filename: " << g2.Expanded() << endl; + cout << "Name: " << g2.Name() << endl; + cout << "Basename: " << g2.Basename() << endl; + cout << "Extension: " << g2.Extension() << endl; + cout << "Original path " << g2.OriginalPath() << endl; + cout << endl; + + // This code taken out because if a matching preference is not + // found then it tries an environment variable +// cout << "Testing bad ISIS preference variable expansion" << endl; +// Isis::Filename h2("$BADPREF/name.ext+attr"); +// cout << "Original filename: " << "$BADPREF/name.ext+attr" << endl; +// cout << "New filename: " << h2.Expanded() << endl; +// cout << "Path: " << h2.Path() << endl; +// cout << "Name: " << h2.Name() << endl; +// cout << "Basename: " << h2.Basename() << endl; +// cout << "Extension: " << h2.Extension() << endl; +// cout << "Original path " << h2.OriginalPath() << endl; +// cout << endl; + + cout << "Testing file name without a path" << endl; + Isis::Filename i("unitTest.cpp"); + cout << "Original filename: " << "unitTest.cpp" << endl; + if (i.Exists()) { + cout << "Filename was expanded correctly" << endl; + } + else { + cout << "Filename was NOT expanded correctly" << endl; + } + +// These two lines removed because the output from them contains +// the current working directory. Making the unitTest fail. +// cout << "New filename: " << i.Expanded() << endl; +// cout << "Path: " << i.Path() << endl; + cout << "Name: " << i.Name() << endl; + cout << "Basename: " << i.Basename() << endl; + cout << "Extension: " << i.Extension() << endl; + cout << "Original path " << i.OriginalPath() << endl; + cout << endl; + + cout << "Testing file name with . as the path" << endl; + Isis::Filename j("./unitTest.cpp"); + cout << "Original filename: " << "./unitTest.cpp" << endl; + if (j.Exists()) { + cout << "Filename was expanded correctly" << endl; + } + else { + cout << "Filename was NOT expanded correctly" << endl; + } + +// These two lines removed because the output from them contains +// the current working directory. Making the unitTest fail. +// cout << "New filename: " << j.Expanded() << endl; +// cout << "Path: " << j.Path() << endl; + cout << "Name: " << j.Name() << endl; + cout << "Basename: " << j.Basename() << endl; + cout << "Extension: " << j.Extension() << endl; + cout << "Original path " << j.OriginalPath() << endl; + cout << endl; + + { + cout << "Testing file name with no path and no extension" << endl; + Isis::Filename k("Makefile"); + cout << "Original filename: " << "Makefile" << endl; + if (k.Exists()) { + cout << "Filename was expanded correctly" << endl; + } + else { + cout << "Filename was NOT expanded correctly" << endl; + } +// cout << "New filename: " << k.Expanded() << endl; +// cout << "Path: " << k.Path() << endl; + cout << "Name: " << k.Name() << endl; + cout << "Basename: " << k.Basename() << endl; + cout << "Extension: " << k.Extension() << endl; + cout << "Original path " << k.OriginalPath() << endl; + cout << endl; + } + + { + cout << "Testing file name with no path and only an extension" << endl; + Isis::Filename k(".cub"); + cout << "Original filename: " << ".cub" << endl; + cout << "Name: " << k.Name() << endl; + cout << "Basename: " << k.Basename() << endl; + cout << "Extension: " << k.Extension() << endl; + cout << "Original path " << k.OriginalPath() << endl; + cout << endl; + } + + cout << "Testing filename operator= with a c++ string" << endl; + Isis::Filename l("/tmp/uid/name.ext+16bit"); + string x = "/home/me/new.extension+0:255"; + l = x; + cout << "Original filename: " << "/home/me/new.extension+0:255" << endl; + cout << "New filename: " << l.Expanded() << endl; + cout << "Path: " << l.Path() << endl; + cout << "Name: " << l.Name() << endl; + cout << "Basename: " << l.Basename() << endl; + cout << "Extension: " << l.Extension() << endl; + cout << "Original path " << l.OriginalPath() << endl; + cout << endl; + + cout << "Testing filename operator= with a c string" << endl; + Isis::Filename m("/tmp/uid/name.ext+16bit"); + m = "/home/me/new.extension+0:255"; + cout << "Original filename: " << "/home/me/new.extension+0:255" << endl; + cout << "New filename: " << m.Expanded() << endl; + cout << "Path: " << m.Path() << endl; + cout << "Name: " << m.Name() << endl; + cout << "Basename: " << m.Basename() << endl; + cout << "Extension: " << m.Extension() << endl; + cout << "Original path " << m.OriginalPath() << endl; + cout << endl; + + cout << "Testing 1st temporary file name" << endl; + Isis::Filename n("tttt", "tmp"); + cout << "Name and extension : " << "tttt, tmp" << endl; + cout << "Name: " << n.Name() << endl; + cout << "Basename: " << n.Basename() << endl; + cout << "Extension: " << n.Extension() << endl; + cout << "Original path " << n.OriginalPath() << endl; + cout << endl; + + ofstream nstm; + string n_str(n.Expanded()); + nstm.open(n_str.c_str(), std::ios::out); + nstm.close(); + + cout << "Testing 2nd temporary file name" << endl; + Isis::Filename o("tttt", "tmp"); + cout << "Name and extension : " << "tttt, tmp" << endl; + cout << "Name: " << o.Name() << endl; + cout << "Basename: " << o.Basename() << endl; + cout << "Extension: " << o.Extension() << endl; + cout << "Original path " << o.OriginalPath() << endl; + cout << endl; + + ofstream ostm; + string o_str(o.Expanded()); + ostm.open(o_str.c_str(), std::ios::out); + ostm.close(); + + remove(n_str.c_str()); + remove(o_str.c_str()); + + // Use the files created in the last two tests to + // test the HighestVersion member + system ("touch tttt000001"); + system ("touch tttt000001.tmp"); + system ("touch tttt000005.tmp"); + system ("touch tttt000006.tmp"); + system ("touch tttt000008.tmp"); + system ("touch 1tttt000008.tmp"); + system ("touch 2tttt000008.tmp"); + + Isis::Filename p ("tttt??????.tmp"); + cout << "Testing HighestVersion for file " << p.Name() << endl; + try { + p.HighestVersion (); + } + catch (Isis::iException &error) { + error.Report(false); + } + cout << " " << p.Name() << endl; + cout << endl; + + Isis::Filename q ("tttt??????"); + cout << "Testing HighestVersion for file " << q.Name() << endl; + try { + q.HighestVersion (); + } + catch (Isis::iException &error) { + error.Report(false); + } + cout << " " << q.Name() << endl; + cout << endl; + + Isis::Filename q2 ("?tttt000008.tmp"); + cout << "Testing HighestVersion for file " << q2.Name() << endl; + try { + q2.HighestVersion (); + } + catch (Isis::iException &error) { + error.Report(false); + } + cout << " " << q2.Name() << endl; + cout << endl; + + + remove ("tttt000001"); + remove ("tttt000001.tmp"); + remove ("tttt000005.tmp"); + remove ("tttt000006.tmp"); + remove ("tttt000008.tmp"); + remove ("1tttt000008.tmp"); + remove ("2tttt000008.tmp"); + + Isis::Filename r ("tttt"); + cout << "Testing HighestVersion for file " << r.Name() << endl; + try { + r.HighestVersion (); + } + catch (Isis::iException &error) { + cout << "No version string in tttt" << endl; + error.Clear(); + } + cout << endl; + + Isis::Filename s ("??tttt"); + cout << "Testing HighestVersion for file " << s.Name() << endl; + try { + s.HighestVersion (); + } + catch (Isis::iException &error) { + cout << "No version available for ??tttt" << endl; + error.Clear(); + } + cout << endl; + system ("touch junk06.tmp"); + system ("touch junk09.tmp"); + + Isis::Filename junk("junk?.tmp"); + junk.HighestVersion(); + cout << "Testing HighestVersion to expand 1 \"?\" into 2 digits" < + +namespace Isis { + /** + * This method returns the amount of interest for the given chip. + * + * @param chip + * + * @return the amount of interest for this chip + */ + double ForstnerOperator::Interest (Chip &chip) { + Isis::FourierTransform ft; + + int nSamp = ft.NextPowerOfTwo(chip.Samples()-1); + int nLine = ft.NextPowerOfTwo(chip.Lines()-1); + + TNT::Array2D< std::complex > Guu(nLine, nSamp); + TNT::Array2D< std::complex > Guv(nLine, nSamp); + TNT::Array2D< std::complex > Gvv(nLine, nSamp); + + // calculate the diagonal gradients + // (if any of the four pixels are special + // the gradients are zeroed out) + // and perform the fourier transform in the + // line direction on the 3 matrices + for (int i=0; i > line1(Guu.dim2()); + std::vector< std::complex > line2(Guv.dim2()); + std::vector< std::complex > line3(Gvv.dim2()); + + double gu, gv; + + for (int j=0; jchip.Lines()-2 || j>chip.Samples()-2 || + IsSpecial(chip.GetValue(j+1,i+1)) || IsSpecial(chip.GetValue(j+1,i+2)) || + IsSpecial(chip.GetValue(j+2,i+1)) || IsSpecial(chip.GetValue(j+2,i+2)) ) { + gu = 0.0; + gv = 0.0; + } + else { + gu = chip.GetValue(j+1,i+1)-chip.GetValue(j+2,i+2); + gv = chip.GetValue(j+2,i+1)-chip.GetValue(j+1,i+2); + } + + line1[j] = gu*gu; + line2[j] = gu*gv; + line3[j] = gv*gv; + } + + std::vector< std::complex > transform1 = ft.Transform(line1); + std::vector< std::complex > transform2 = ft.Transform(line2); + std::vector< std::complex > transform3 = ft.Transform(line3); + + //copy the transformed data back into the matrices + for (int j=0; j > samp1(Guu.dim1()); + std::vector< std::complex > samp2(Guv.dim1()); + std::vector< std::complex > samp3(Gvv.dim1()); + + for (int i=0; i > transform1 = ft.Transform(samp1); + std::vector< std::complex > transform2 = ft.Transform(samp2); + std::vector< std::complex > transform3 = ft.Transform(samp3); + + //copy the transformed data back into the matrices + for (int i=0; i > line(Guu.dim2()); + + for (int j=0; j > transform = ft.Transform(line); + + //copy the transformed data back into the matrix + for (int j=0; j N(chip.Lines()-1, chip.Samples()-1); + + // And then the sample direction + for (int j=0; j > samp(Guu.dim1()); + + for (int i=0; i > transform = ft.Transform(samp); + + //copy the transformed data back into the matrix + for (int i=0; i lu(N); + + // use LU decomposition to calculate the determinant + return abs(lu.det()); + } +} + +extern "C" Isis::InterestOperator *ForstnerOperatorPlugin (Isis::Pvl &pvl) { + return new Isis::ForstnerOperator(pvl); +} + diff --git a/isis/src/base/objs/ForstnerOperator/ForstnerOperator.h b/isis/src/base/objs/ForstnerOperator/ForstnerOperator.h new file mode 100644 index 0000000000000000000000000000000000000000..df5dec68417977a23383c1a254f04f2b40235fa3 --- /dev/null +++ b/isis/src/base/objs/ForstnerOperator/ForstnerOperator.h @@ -0,0 +1,57 @@ +#if !defined(ForstnerOperator_h) +#define ForstnerOperator_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/08/02 23:21:03 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "InterestOperator.h" + +namespace Isis { + class Pvl; + class Chip; + + /** + * @brief Forstner interest operator + * + * This class is used to construct a forstner interest operator. + * For this class, the interest is always positive with the worst + * interest amount being 0. The higher the interest, the better. + * + * @see InterestOperator + * + * @see "A Fast Operator for Detection and Precise Location of + * Distinct Points, Corners and Centres of Circular + * Features" by W. Forstner and E. Gulch (Forstner.pdf) + * + * @author 2006-05-01 Jacob Danton + */ + class ForstnerOperator : public InterestOperator { + public: + ForstnerOperator (Pvl &pvl) : InterestOperator(pvl) {}; + virtual ~ForstnerOperator() {}; + + protected: + virtual double Interest (Chip &chip); + }; +}; + +#endif diff --git a/isis/src/base/objs/ForstnerOperator/ForstnerOperator.truth b/isis/src/base/objs/ForstnerOperator/ForstnerOperator.truth new file mode 100644 index 0000000000000000000000000000000000000000..24a3f11af1a3c3132f429ae11f2cfeb65c56fa8d --- /dev/null +++ b/isis/src/base/objs/ForstnerOperator/ForstnerOperator.truth @@ -0,0 +1,14 @@ +Object = InterestOperator + Group = Operator + Name = Forstner + DeltaLine = 100 + DeltaSamp = 100 + Samples = 15 + Lines = 15 + MinimumInterest = 0.0 + End_Group +End_Object +End +Sample: 87 +Line : 380 +Interest: 4.75802e-92 diff --git a/isis/src/base/objs/ForstnerOperator/InterestOperator.plugin b/isis/src/base/objs/ForstnerOperator/InterestOperator.plugin new file mode 100644 index 0000000000000000000000000000000000000000..cf249e96a7195b2fa83c382197064e4ebc1acfde --- /dev/null +++ b/isis/src/base/objs/ForstnerOperator/InterestOperator.plugin @@ -0,0 +1,4 @@ +Group = Forstner + Library = ForstnerOperator + Routine = ForstnerOperatorPlugin +End_Group diff --git a/isis/src/base/objs/ForstnerOperator/Makefile b/isis/src/base/objs/ForstnerOperator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..38c32d1d724c9a503789f989c26b2661bf42782e --- /dev/null +++ b/isis/src/base/objs/ForstnerOperator/Makefile @@ -0,0 +1,5 @@ +INCS = ForstnerOperator.h +SRCS = ForstnerOperator.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ForstnerOperator/unitTest.cpp b/isis/src/base/objs/ForstnerOperator/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6adfc180daa7129dc1dc4c599ceb371d1ac2abad --- /dev/null +++ b/isis/src/base/objs/ForstnerOperator/unitTest.cpp @@ -0,0 +1,50 @@ +#include +#include +#include "InterestOperator.h" +#include "InterestOperatorFactory.h" +#include "ForstnerOperator.h" +#include "Chip.h" +#include "Cube.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + try { + Isis::Preference::Preferences(true); + PvlGroup op("Operator"); + op += PvlKeyword("Name","Forstner"); + op += PvlKeyword("DeltaLine", 100); + op += PvlKeyword("DeltaSamp", 100); + op += PvlKeyword("Samples", 15); + op += PvlKeyword("Lines", 15); + op += PvlKeyword("MinimumInterest", 0.0); + + PvlObject o("InterestOperator"); + o.AddGroup(op); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl; + + InterestOperator *iop = InterestOperatorFactory::Create(pvl); + + Cube c; + c.Open("$mgs/testData/ab102401.cub"); + + //iop->Operate(c, 100, 350); + UniversalGroundMap univGrndMap(c); + iop->Operate(c, univGrndMap, 100, 350); + + std::cout << "Sample: " << iop->CubeSample() << std::endl + << "Line : " << iop->CubeLine() << std::endl + << "Interest: " << iop->InterestAmount() << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/FourierTransform/FourierTransform.cpp b/isis/src/base/objs/FourierTransform/FourierTransform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..afe384c7e3467b2465b853a3fb63fd035a7c4972 --- /dev/null +++ b/isis/src/base/objs/FourierTransform/FourierTransform.cpp @@ -0,0 +1,179 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "FourierTransform.h" + +using namespace std; + +namespace Isis { + //! Constructs the FourierTransform object. + FourierTransform::FourierTransform () {}; + + //! Destroys the FourierTransform object. + FourierTransform::~FourierTransform () {}; + + /** + * Applies the Fourier transform on the input data + * and returns the result. + * + * @param input The data to be transformed. + * + * @return vector + */ + std::vector< std::complex > + FourierTransform::Transform (std::vector< std::complex > input) { + // data length must be a power of two + // any extra space is filled with zeroes + int n = NextPowerOfTwo(input.size()); + vector< std::complex > output(n); + input.resize(n); + + // rearrange the data to fit the iterative algorithm + // which will apply the transform from the bottom up + for (int i=0; i Wm(polar(1.0, -1.0*PI/m)); // Wm = e^(-PI/m *i) + for (int k=0; k W(1.0); + for (int j=0; j t = W*output[k+j+m]; // the "twiddle" factor + complex u = output[k+j]; + output[k+j] = u+t; // a[k+j]+Wm^j*a[k+j+m] + output[k+j+m] = u-t; // a[k+j]+Wm^(j+m)*[k+j+m] = a[k+j]-Wm^j*[k+j+m] + W = W*Wm; + } + } + } + + return output; + } + + + /** + * Applies the inverse Fourier transform on the input data + * and returns the result. + * + * @param input The data to be transformed. + * + * @return vector + */ + std::vector< std::complex > + FourierTransform::Inverse (std::vector< std::complex > input) { + // Inverse(input) = 1/n*conj(Transform(conj(input))) + int n = input.size(); + std::vector< std::complex > temp(n); + for (int i=0; i > output = Transform(temp); + + for (int i=0; i1) { + if (n%2==1) return false; + n/=2; + } + + return true; + } + + /** + * This function returns the floor of log2(n) + * + * @param n The input integer + * + * @return int - the floor of log2(n) + */ + int FourierTransform:: lg (int n) { + int k=0; + while (n>1) { + n=n/2; + k++; + } + return k; + } + + /** + * Reverses the binary representation of the input integer + * in the number of bits specified. + * bitReverse(n,x) = + * n/2*(2^-a1 + 2^-a2 + ... + 2^-ak) where x = 2^a1 + 2^a2 + ... + 2^ak + * + * @param n The number of bits + * + * @param x The input integer + * + * @return int - The reverse of the binary representation of the input integer + */ + int FourierTransform::BitReverse (int n, int x) { + double ans = 0.0; + double a = 1.0; + while (x>0) { + if (x%2==1) { + ans+=a; + x-=1; + } + x=x/2; + a=a/2.0; + } + + return(int)(ans*n/2); + } + + /** + * This function returns the next power of two greater than or equal to n. + * If n is a power of two, it returns n. + * + * @param n The number of bits + * + * @return int - the next power of two greater than or equal to n + */ + int FourierTransform::NextPowerOfTwo (int n) { + if (IsPowerOfTwo(n)) return n; + return(int)pow(2.0, lg(n)+1); + } +} diff --git a/isis/src/base/objs/FourierTransform/FourierTransform.h b/isis/src/base/objs/FourierTransform/FourierTransform.h new file mode 100644 index 0000000000000000000000000000000000000000..b5f58c4edab182a088e25235ba12c2934dee8080 --- /dev/null +++ b/isis/src/base/objs/FourierTransform/FourierTransform.h @@ -0,0 +1,63 @@ +#ifndef FourierTransform_h +#define FourierTransform_h +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Constants.h" + +namespace Isis +{ + /** + * @brief Fourier Transform class + * + * This class is used to apply a Fourier transform to a vector of complex + * data as well as the inverse Fourier transform. Applying the Fourier + * transform on data in the spatial domain will convert it to data in the + * Fourier (or frequency) domain. The inverse transform takes data + * from the frequency domain to the spatial. + * + * If you would like to see FourierTransform being used + * in implementation, see fft.cpp or ifft.cpp. + * + * @ingroup Math and Statistics + * + * @author Jacob Danton - 2005-11-28 + * + * @internal + */ + class FourierTransform + { + public: + FourierTransform (); + ~FourierTransform (); + std::vector< std::complex > Transform(std::vector< std::complex > input); + std::vector< std::complex > Inverse(std::vector< std::complex > input); + bool IsPowerOfTwo(int n); + int lg(int n); + int BitReverse (int n, int x); + int NextPowerOfTwo (int n); + }; +} + +#endif diff --git a/isis/src/base/objs/FourierTransform/FourierTransform.truth b/isis/src/base/objs/FourierTransform/FourierTransform.truth new file mode 100644 index 0000000000000000000000000000000000000000..0debd5129f7a9473321c3292d40dfb80e35eede3 --- /dev/null +++ b/isis/src/base/objs/FourierTransform/FourierTransform.truth @@ -0,0 +1,17 @@ +Original Transformed Inverted +(0,13) (78,91) (0,13) +(1,12) (2.01367,23.1234) (1,12) +(2,11) (7.48528,0) (2,11) +(3,10) (17.5877,1.2483) (3,10) +(4,9) (12,13) (4,9) +(5,8) (0,12.8891) (5,8) +(6,7) (0,4.10051) (6,7) +(7,6) (2.46662,0.599456) (7,6) +(8,5) (6,7) (8,5) +(9,4) (0,13.1192) (9,4) +(10,3) (0,9.07107) (10,3) +(11,2) (0,0.165911) (11,2) +(12,1) (0,1) (12,1) +(0,0) (0,14.8682) (0,0) +(0,0) (0,23.8995) (0,0) +(0,0) (0,0) (0,0) diff --git a/isis/src/base/objs/FourierTransform/Makefile b/isis/src/base/objs/FourierTransform/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..57c1db7803d75a69f70b77c958ae08b63ecf5699 --- /dev/null +++ b/isis/src/base/objs/FourierTransform/Makefile @@ -0,0 +1,5 @@ +INCS = FourierTransform.h +SRCS = FourierTransform.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/FourierTransform/unitTest.cpp b/isis/src/base/objs/FourierTransform/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca74e0fbbd296612c6386cb9ee14c0a5a1f95934 --- /dev/null +++ b/isis/src/base/objs/FourierTransform/unitTest.cpp @@ -0,0 +1,44 @@ +#include +#include +#include "FourierTransform.h" +#include "Preference.h" + +using namespace std; + +std::complex Round(std::complex n); + +int main(int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + Isis::FourierTransform fft; + int n = 13; + vector< std::complex > original(n); + for (int i=0; i(i, n-i); + } + + vector< std::complex > transformed = fft.Transform(original); + + vector< std::complex > inverted = fft.Inverse(transformed); + + original.resize(inverted.size()); + + cout << "Original Transformed Inverted" << endl; + + for (unsigned int i=0; i Round(std::complex n) { + double CUTOFF = std::pow(10.0, -14.0); + double real = n.real(); + double imag = n.imag(); + if (real < CUTOFF) real = 0; + if (imag < CUTOFF) imag = 0; + return std::complex(real, imag); +} diff --git a/isis/src/base/objs/FramingCamera/FramingCamera.cpp b/isis/src/base/objs/FramingCamera/FramingCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd49ae0fefb900e7ad2016e31bad06278b40667b --- /dev/null +++ b/isis/src/base/objs/FramingCamera/FramingCamera.cpp @@ -0,0 +1,35 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/08/31 15:11:48 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "FramingCamera.h" + +namespace Isis { + /** + * Constructs the FramingCamera object + * + * @param lab Pvl label used to create the parent Camera object + */ + FramingCamera::FramingCamera (Isis::Pvl &lab) : Camera (lab) { + } +}; + diff --git a/isis/src/base/objs/FramingCamera/FramingCamera.h b/isis/src/base/objs/FramingCamera/FramingCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..c54ab4b8354489e568cb0428464300cd1b044024 --- /dev/null +++ b/isis/src/base/objs/FramingCamera/FramingCamera.h @@ -0,0 +1,55 @@ +#ifndef FramingCamera_h +#define FramingCamera_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/08/31 15:11:48 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Camera.h" + +namespace Isis { +/** + * @brief Generic class for Framing Cameras + * + * This class is used to abstract out framing camera functionality from children + * classes. + * + * @author 2009-08-26 Steven Lambright + * + * @internal + * @todo Implement more functionality in this class and abstract away from the children + */ + + class FramingCamera : public Camera { + public: + FramingCamera(Isis::Pvl &lab); + + virtual CameraType GetCameraType() const { return Framing; } + + private: + //! Copying cameras is not allowed + FramingCamera(const FramingCamera &); + //! Assigning cameras is not allowed + FramingCamera &operator=(const FramingCamera &); + }; +}; + +#endif diff --git a/isis/src/base/objs/FramingCamera/FramingCamera.truth b/isis/src/base/objs/FramingCamera/FramingCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..4168bc9c708559fea1e026804dfc7bac1ef6ec4d --- /dev/null +++ b/isis/src/base/objs/FramingCamera/FramingCamera.truth @@ -0,0 +1,4 @@ +Camera = Framing? 1 +Camera = LineScan? 0 +Camera = PushFrame? 0 +Camera = Radar? 0 diff --git a/isis/src/base/objs/FramingCamera/Makefile b/isis/src/base/objs/FramingCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d2db0851ae897e291fae3587b840bb76da077dfa --- /dev/null +++ b/isis/src/base/objs/FramingCamera/Makefile @@ -0,0 +1,5 @@ +INCS = FramingCamera.h +SRCS = FramingCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/FramingCamera/unitTest.cpp b/isis/src/base/objs/FramingCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d604c6b051e78792aa13d0d6445e862fcdaf3a7 --- /dev/null +++ b/isis/src/base/objs/FramingCamera/unitTest.cpp @@ -0,0 +1,22 @@ +#include "FramingCamera.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +class MyCamera : public FramingCamera { + public: + MyCamera(Isis::Pvl& lab) : Isis::FramingCamera(lab) { } +}; + +int main() { + Isis::Preference::Preferences(true); + string inputFile = "$ISIS3DATA/mgs/testData/ab102401.lev2.cub"; + Pvl pvl(inputFile); + MyCamera cam(pvl); + + cout << "Camera = Framing? " << (cam.GetCameraType() == Camera::Framing) << std::endl; + cout << "Camera = LineScan? " << (cam.GetCameraType() == Camera::LineScan) << std::endl; + cout << "Camera = PushFrame? " << (cam.GetCameraType() == Camera::PushFrame) << std::endl; + cout << "Camera = Radar? " << (cam.GetCameraType() == Camera::Radar) << std::endl; +} diff --git a/isis/src/base/objs/GSLUtility/GSLUtility.cpp b/isis/src/base/objs/GSLUtility/GSLUtility.cpp new file mode 100644 index 0000000000000000000000000000000000000000..acdcadd3b4fd4495d551bee11696c37b4b862b1c --- /dev/null +++ b/isis/src/base/objs/GSLUtility/GSLUtility.cpp @@ -0,0 +1,353 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/06/26 01:08:24 $ + * $Id: GSLUtility.cpp,v 1.2 2010/06/26 01:08:24 ehyer Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include + +#include + +#include "GSLUtility.h" +#include "iException.h" + +using namespace std; + +namespace Isis { + namespace GSL { + +///! Initialization of object reference +GSLUtility *GSLUtility::_instance = 0; + +/** + * @brief Contructs a GSLUtility object with an error handler + * + * Sets an error handler for the GSL library so fatal GSL errors are intercepted + * and handled throught the ISIS exception utility. + * + * See http://www.gnu.org/software/gsl/manual/html_node/Error-Handling.html for + * additional information. + */ +GSLUtility::GSLUtility() { + gsl_set_error_handler(handler); +} + + +/** + * @brief Return a reference to the GSL (singleton) object + * + * This method returns a pointer reference to the GSL utility object. If it is + * not yet created, one is constructed and lives until the application + * terminates. + * + * @return GSLUtility::GSLUtility* Pointer reference to GSLUtility singleton + */ +GSLUtility * GSLUtility::getInstance() { + if ( _instance == 0 ) { + _instance = new GSLUtility(); + } + return (_instance); +} + + +/** + * @brief Creates a GSL vector + * + * This convenience method creates a GSL vector for use within applications. + * The memory is dynamically allocated and must be managed (i.e., freed) by the + * caller. See the free() method for this provision. + * + * @param n Size of GSL vector to create + * @param zero Set to true if you want GSL to assign 0 to the allocated vector + * otherwise, false will not initilize the memory. + * + * @return gsl_vector* Returns an allocated GSL vector + */ +gsl_vector *GSLUtility::vector(size_t n, bool zero) const { + if ( zero ) { + return (gsl_vector_calloc(n)); + } + else { + return (gsl_vector_alloc(n)); + } +} + +/** + * @brief Creates a GSL matrix + * + * This convenience method creates a GSL matrix for use within applications. The + * memory is dynamically allocated and must be managed (i.e., freed) by the + * caller. See the free() method for this provision. + * + * @param n1 Size of rows in the GSL matrix to create + * @param n2 Size of columns in the GSL matrix to create + * @param zero Set to true if you want GSL to assign 0 to the allocated matrix + * otherwise, false will not initilize the memory. + * + * @return gsl_matrix* Returns an allocated GSL matrix + */ +gsl_matrix *GSLUtility::matrix(size_t n1, size_t n2, bool zero) const { + if ( zero ) { + return (gsl_matrix_calloc(n1, n2)); + } + else { + return (gsl_matrix_alloc(n1, n2)); + } +} + +/** + * @brief Returns a GSL identity matrix of the specified size + * + * This method allocates a square or rectanglar matrix and initilizes it to the + * identity matrix. The diagonal elements are all set to 1.0, all other + * elements are set to 0. + * + * @param n1 Number rows to allocate + * @param n2 Number columns to allocate + * + * @return gsl_matrix* Returns pointer to identity matrix + */ +gsl_matrix *GSLUtility::identity(size_t n1, size_t n2) const { + gsl_matrix *i = gsl_matrix_alloc(n1, n2); + gsl_matrix_set_identity(i); + return (i); +} + +/** + * @brief Initializes an existing GSL matrix to the identity matrix + * + * @param m Pointer to matrix to set to identity + */ +void GSLUtility::setIdentity(gsl_matrix *m) const { + gsl_matrix_set_identity(m); + return; +} + +/** + * @brief Frees a GSL vector + * + * Frees the memory allocated to a GSL vector. As with any free operation, the + * vector cannot be used thereafter. + * + * It is up to the user to manage all GSL allocated elements. It is not done + * automatically. + * + * @param v GSL vector to free + */ +void GSLUtility::free(gsl_vector *v) const { + gsl_vector_free(v); + return; +} + +/** + * @brief Frees a GSL matrix + * + * Frees the memory allocated to a GSL matrix. As with any free operation, the + * matrix cannot be used thereafter. + * + * It is up to the user to manage all GSL allocated elements. It is not done + * automatically. + * + * @param m GSL matrix to free + */ +void GSLUtility::free(gsl_matrix *m) const { + gsl_matrix_free(m); + return; +} + +/** + * @brief Converts a GSL vector to a TNT-based vector + * + * Convenience method to convert to GSLVector type + * + * @param v GSL vector to convert + * + * @return GSLUtility::GSLVector TNT-based vector + */ +GSLUtility::GSLVector GSLUtility::gslToGSL(const gsl_vector *v) const { + size_t n = size(v);; + GSLVector Nv(n); + for (size_t i = 0 ; i < n ; i++) { + Nv[i] = gsl_vector_get(v, i); + } + return (Nv); +} + +/** + * @brief Converts a GSL matrix to a TNT-based matrix + * + * Convenience method to convert to GSLMatrix type + * + * @param m GSL matrix to convert + * + * @return GSLUtility::GSLMatrix TNT-based matrix + */ +GSLUtility::GSLMatrix GSLUtility::gslToGSL(const gsl_matrix *m) const { + size_t nrows = Rows(m); + size_t ncols = Columns(m); + GSLMatrix Nm(nrows, ncols); + for (size_t i = 0 ; i < nrows ; i++) { + for (size_t j = 0 ; j < ncols ; j++) { + Nm[i][j] = gsl_matrix_get(m,i,j); + } + } + return (Nm); +} + + +/** + * @brief Converts TNT-based vector to GSL vector + * + * Convenience method to convert TNT-based vector to a GSL vector. + * + * @param v TNT-based vector to convert + * @param gv Optional GSL vector of same size to copy data to + * + * @return gsl_vector* Pointer to GSL vector copy + */ +gsl_vector *GSLUtility::GSLTogsl(const GSLUtility::GSLVector &v, + gsl_vector *gv) const { + if (gv == 0) { + gv = gsl_vector_alloc(v.dim()); + } + else if (size(gv) != (size_t) v.dim()) { + ostringstream mess; + mess << "Size of NL vector (" << v.dim() << ") not same as GSL vector (" + << gv->size << ")"; + throw iException::Message(iException::Programmer, mess.str(), _FILEINFO_); + } + + for (int i = 0 ; i < v.dim() ; i++) { + gsl_vector_set(gv, i, v[i]); + } + return (gv); +} + +/** + * @brief Converts TNT-based matrix to GSL matrix + * + * Convenience method to convert TNT-based matrix to a GSL matrix. + * + * @param m TNT-based matrix to convert + * @param gm Optional GSL matrix of same size to copy data to + * + * @return gsl_matrix* Pointer to GSL matrix copy + */ +gsl_matrix *GSLUtility::GSLTogsl(const GSLUtility::GSLMatrix &m, + gsl_matrix *gm) const { + if (gm == 0) { + gm = gsl_matrix_alloc(m.dim1(), m.dim2()); + } + else if ((Rows(gm) != (size_t) m.dim1()) && + (Columns(gm)!= (size_t) m.dim2()) ) { + ostringstream mess; + mess << "Size of NL matrix (" << m.dim1() << "," << m.dim2() + << ") not same as GSL matrix (" << Rows(gm) << "," << Columns(gm) + << ")"; + throw iException::Message(iException::Programmer, mess.str(), _FILEINFO_); + } + + for (int i = 0 ; i < m.dim1() ; i++) { + for (int j = 0 ; j < m.dim2() ; j++) { + gsl_matrix_set(gm, i, j, m[i][j]); + } + } + return (gm); +} + +/** Returns number of rows in a GSL matrix */ +size_t GSLUtility::Rows(const gsl_matrix *m) const { + return (m->size1); +} + +/** Returns the number of coulumns in a GSL matrix */ +size_t GSLUtility::Columns(const gsl_matrix *m) const { + return (m->size2); +} + +/** Returns the number of columns in TNT-based matrix */ +size_t GSLUtility::Columns(const GSLMatrix &m) const { + return (m.dim1()); +} + +/** Returns the number of rows in TNT-based matrix */ +size_t GSLUtility::Rows(const GSLMatrix &m) const { + return (m.dim2()); +} + +/** Returns the size of a GSL vector */ +size_t GSLUtility::size(const gsl_vector *v) const { + return (v->size); +} + +/** Returns the total number of elements in a GSL matrix */ +size_t GSLUtility::size(const gsl_matrix *m) const { + return (Rows(m) * Columns(m)); +} + +/** + * @brief Performs a check on GSL library function return status + * + * This covenience method performs a validity check on the return status of a + * GSL function. It will throw an ISIS exception should the status be anything + * other than GSL_SUCCESS. + * + * @param gsl_status Return value of GSL function + * @param src Name of the source file where the function was called. + * @param line Line number in the source where the call/error occurs + */ +void GSLUtility::check(int gsl_status, char *src, int line) + const throw (iException &) { + if (gsl_status != GSL_SUCCESS) { + string msg = "GSL error occured: " + string(gsl_strerror(gsl_status)); + throw iException::Message(iException::Programmer,msg.c_str(),src,line); + } + return; +} + +/** + * @brief Special GSL errror handler + * + * This method is the designated ISIS error handler for errors that occur + * within the GSL library. It will be called by the GSL library when errors + * occur to handle failures. It is designed to override GSL default behavior + * which is to issue an error and abort the application. + * + * This method traps the error and throws an ISIS exception indicating the + * error. + * + * @param reason GSL description of the error + * @param file Source file where the error originates + * @param line Line if source file where error occurred + * @param gsl_errno Actual GSL error encountered + */ +void GSLUtility::handler(const char * reason, const char * file, int line, + int gsl_errno) { + ostringstream mess; + mess << "GSLError (" << gsl_errno << ") -> " << reason; + throw iException::Message(iException::Programmer, mess.str(), + const_cast (file), line); +} + +} } // namespace ISIS::GSL diff --git a/isis/src/base/objs/GSLUtility/GSLUtility.h b/isis/src/base/objs/GSLUtility/GSLUtility.h new file mode 100644 index 0000000000000000000000000000000000000000..70aec9aadd199487952ce7d13e3d40a71eefa5c8 --- /dev/null +++ b/isis/src/base/objs/GSLUtility/GSLUtility.h @@ -0,0 +1,149 @@ +#if !defined(GSLUtility_h) +#define GSLUtility_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2009/12/22 02:09:54 $ + * $Id: GSLUtility.h,v 1.2 2009/12/22 02:09:54 ehyer Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include + +#include "tnt/tnt_array1d.h" +#include "tnt/tnt_array1d_utils.h" +#include "tnt/tnt_array2d.h" +#include "tnt/tnt_array2d_utils.h" + +#include +#include + +// Some GSL optimization on by default, off if DEBUG or SAFE_GSL is defined +#if !defined(DEBUG) +#if !defined(SAFE_GSL) +#define GSL_RANGE_CHECK_OFF 1 +#endif +#endif + +#include "iException.h" + +namespace Isis { + namespace GSL { + + /** + * @brief GSLUtility Provides top level interface to the GNU GSL + * + * Provides GSL setup and interface utilities. This object is provided for + * convenience of GSL vector and matrix manipulation as well as better + * management of GSL error handling. + * + * Without setting up GSL error handling, the GSL will abort when certain + * errors occur. This singleton object, an object where there is never more + * than one instance, an error handler is established that captures GSL errors + * and formats them into ISIS exceptions. + * + * There are many convenience methods provided for manipulation of GSL vectors + * and matrixs. Motivation for this is to address element access and + * efficient parameter and copy mechanisms (provided by the TNT library). + * + * There are some compile options on by default that help optimize the GSL. + * When the compile time DEBUG macro is set, range checking is turned on. + * Inline functions are also turned on by default unless the DEBUG macro is + * set. In addition, an additional compile time macro called SAFE_GSL is + * provided to emulate the DEBUG behavior, but does not invoke additional + * DEBUG behavior/side effects. + * + * See http://www.gnu.org/software/gsl/ for additional details on the GNU + * Scientific Library. + * + * @ingroup Utility + * @author 2008-05-06 Kris Becker + * @internal + * @history 2009-08-20 Kris Becker Completed documentation + */ + class GSLUtility { + public: + typedef TNT::Array1D GSLVector; + typedef TNT::Array2D GSLMatrix; + + static GSLUtility *getInstance(); + + /** Tests if status is success */ + inline bool success(int status) const { + return (status == GSL_SUCCESS); + } + + /** + * @brief Returns GSL specific error text + * + * @param gsl_errno GSL error number + * @return std::string Textual context of GSL error + */ + inline std::string status(int gsl_errno) const { + return (std::string(gsl_strerror(gsl_errno))); + } + + void check(int gsl_status, char *src = __FILE__, int line = __LINE__) + const throw (iException &); + + + size_t Rows(const gsl_matrix *m) const; + size_t Columns(const gsl_matrix *m) const; + + size_t Rows(const GSLMatrix &m) const; + size_t Columns(const GSLMatrix &m) const; + + size_t size(const gsl_vector *v) const; + size_t size(const gsl_matrix *m) const; + + gsl_vector *vector(size_t n, bool zero = false) const; + gsl_matrix *matrix(size_t n1, size_t n2, bool zero = false) const; + gsl_matrix *identity(size_t n1, size_t n2) const; + void setIdentity(gsl_matrix *m) const; + + void free(gsl_vector *v) const; + void free(gsl_matrix *m) const; + + GSLVector gslToGSL(const gsl_vector *v) const; + GSLMatrix gslToGSL(const gsl_matrix *m) const; + gsl_vector *GSLTogsl(const GSLVector &v, gsl_vector *gv = 0) const; + gsl_matrix *GSLTogsl(const GSLMatrix &m, gsl_matrix *gm = 0) const; + + + private: + // Private Constructor/Destructor makes this a singleton + GSLUtility(); + ~GSLUtility() { } + + static GSLUtility *_instance; //!< Singleton self-reference pointer + + static void handler(const char * reason, const char * file, int line, + int gsl_errno); + + + }; + + } // namespace GSL +} // namespace Isis +#endif + diff --git a/isis/src/base/objs/GSLUtility/GSLUtility.truth b/isis/src/base/objs/GSLUtility/GSLUtility.truth new file mode 100644 index 0000000000000000000000000000000000000000..65e60e90c6b35a23cbff1a31b5ea3469dfa07354 --- /dev/null +++ b/isis/src/base/objs/GSLUtility/GSLUtility.truth @@ -0,0 +1,13 @@ + +*** Test GSLUtility Functionality *** +Tests use GSL Cholesky and Eigen Value Solutions +Data provided by a Gruen Test case +Expected result for Fit = 0.02782 + +Solve using GSL Cholesky +Solve Affine translation +Affine parameters = 2 3 +-0.02394 -0.04493 -0.01943 +-0.01661 -0.02399 0.4105 +Eigen Vectors: 0.02499 0.01224 +Fit: 0.02782 diff --git a/isis/src/base/objs/GSLUtility/Makefile b/isis/src/base/objs/GSLUtility/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3a949f06e44346e404c98018d68c115f15742e52 --- /dev/null +++ b/isis/src/base/objs/GSLUtility/Makefile @@ -0,0 +1,5 @@ +INCS = GSLUtility.h +SRCS = GSLUtility.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/GSLUtility/unitTest.cpp b/isis/src/base/objs/GSLUtility/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..752d7d4bbf6b8c17953a3a91d1dd5ee38aa49630 --- /dev/null +++ b/isis/src/base/objs/GSLUtility/unitTest.cpp @@ -0,0 +1,119 @@ +// $Id: unitTest.cpp,v 1.1 2009/08/21 01:04:57 kbecker Exp $ +#include +#include +#include +#include +#include + +#include "GSLUtility.h" + +#include +#include +#include +#include + +using namespace Isis; +using namespace Isis::GSL; +using namespace std; + +typedef GSLUtility::GSLMatrix GSLMatrix; +typedef GSLUtility::GSLVector GSLVector; + +int main(int argc, char *argv[]) { + + cout << "\n*** Test GSLUtility Functionality ***\n"; + cout << "Tests use GSL Cholesky and Eigen Value Solutions\n"; + cout << "Data provided by a Gruen Test case\n"; + cout << "Expected result for Fit = 0.02782\n"; + + // Setup with initialization of parameters + string ata_str = "8 8\n" +"0.00394087 -0.00134017 0.000698616 -0.00118582 5.08835e-05 -0.000191336 0.269915 0.0100344\n" +"-0.00134017 0.00261999 -0.000314756 5.08835e-05 -0.000710193 4.11822e-05 -0.168693 -0.00628949\n" +"0.000698616 -0.000314756 0.000219502 -0.000191336 4.11822e-05 -5.97796e-05 0.0939977 0.00337862\n" +"-0.00118582 5.08835e-05 -0.000191336 0.00382973 0.000141468 0.000632668 -0.0836021 -0.00315921\n" +"5.08835e-05 -0.000710193 4.11822e-05 0.000141468 0.00140484 -7.57756e-05 0.0812913 0.00282839\n" +"-0.000191336 4.11822e-05 -5.97796e-05 0.000632668 -7.57756e-05 0.000169357 -0.0542839 -0.00190863\n" +"0.269915 -0.168693 0.0939977 -0.0836021 0.0812913 -0.0542839 169 5.81505\n" +"0.0100344 -0.00628949 0.00337862 -0.00315921 0.00282839 -0.00190863 5.81505 0.200532\n"; + + istringstream data_inp(ata_str); + GSLMatrix ata; + data_inp >> ata; + + double resid = 0.000167867; + int npts = 169; + + string str_atl = "8\n-0.00031961\n9.03622e-05\n-7.49718e-05\n0.0003005\n" + "-5.42596e-05\n8.0876e-05\n-0.0431598\n-0.00160416\n"; + data_inp.str(str_atl.c_str()); + GSLVector atl; + data_inp >> atl; + + + // Get instance of GSLUtility + GSLUtility *gsl = GSLUtility::getInstance(); + + size_t nRows = gsl->Rows(ata); + size_t nCols = gsl->Columns(ata); + + // Compute variance + double variance = resid / (double) (npts - nRows); + gsl_matrix *A, *atai; + try { + cout << "\nSolve using GSL Cholesky\n"; + A = gsl->GSLTogsl(ata); // Convert GSLMatrix to gsl_matrix + gsl->check(gsl_linalg_cholesky_decomp(A)); // Compute Choleksy decomp + atai = gsl->identity(gsl->Rows(ata), gsl->Columns(ata)); // GSL identity + + + // Solve each variable independantly + for (size_t i = 0 ; i < nRows ; i++ ) { + gsl_vector_view x = gsl_vector_view_array(gsl_matrix_ptr(atai, i, 0), + nCols); + gsl->check(gsl_linalg_cholesky_svx(A, &x.vector)); + } + + // Solve Gruen affine parameter contributions + cout << "Solve Affine translation\n"; + GSLMatrix covar(8,8); + GSLVector alpha(8); + for ( size_t r = 0 ; r < nRows ; r++ ) { + alpha[r] = 0.0; + for (size_t c = 0 ; c < nCols ; c++ ) { + double ataiV = gsl_matrix_get(atai, r, c); + alpha[r] += ataiV * atl[c]; + covar[r][c] = variance * ataiV; + } + } + + // Compute eigen vector solution for shift parameters + GSLVector eigen(2); + GSLMatrix subvar(2,2); + subvar[0][0] = covar[2][2]; + subvar[0][1] = covar[2][5]; + subvar[1][0] = covar[5][2]; + subvar[1][1] = covar[5][5]; + gsl_matrix_view skmat = gsl_matrix_view_array(&subvar[0][0],2,2); + gsl_vector_view evals = gsl_vector_view_array(&eigen[0], 2); + gsl_eigen_symm_workspace *w = gsl_eigen_symm_alloc(2); + gsl->check(gsl_eigen_symm(&skmat.matrix, &evals.vector, w)); + gsl_eigen_symm_free(w); + gsl_eigen_symmv_sort(&evals.vector, &skmat.matrix, GSL_EIGEN_SORT_VAL_DESC); + gsl->free(A); + gsl->free(atai); + +// Report results + GSLMatrix affine(2,3,&alpha[0]); + cout << "Affine parameters = " << setprecision(4) << affine; + cout << "Eigen Vectors: " << eigen[0] << " " << eigen[1] << endl; + cout << "Fit: " << setprecision(4) + << sqrt(eigen[0]*eigen[0] + eigen[1]*eigen[1]) << endl; + } + catch (iException &ie) { + ie.Report(); + } + + return (0); + +} diff --git a/isis/src/base/objs/GaussianDistribution/GaussianDistribution.cpp b/isis/src/base/objs/GaussianDistribution/GaussianDistribution.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c10f4e26f605d76ab6ddf85cf86f93078792f2c --- /dev/null +++ b/isis/src/base/objs/GaussianDistribution/GaussianDistribution.cpp @@ -0,0 +1,192 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/07/09 16:58:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "GaussianDistribution.h" +#include "Message.h" +#include +#include + +using namespace std; +namespace Isis { + /** + * Constructs a gaussian distribution object. + * + * @param mean The Distribution's mean + * @param standardDeviation The Distribution's standard deviation + */ + GaussianDistribution::GaussianDistribution (const double mean, const double standardDeviation) { + p_mean = mean; + p_stdev = standardDeviation; + } + + /** + * Computes and returns the probability of the specified value + * on the gaussian distribution. + * + * @param value The input value + * + * @returns The PDF evaluated at the specified value + */ + double GaussianDistribution::Probability (const double value) { + // P(x) = 1/(sqrt(2*pi)*sigma)*e^(-1/2*((x-mu)/sigma)^2) + return std::exp(-0.5*std::pow((value-p_mean)/p_stdev, 2))/(std::sqrt(2*PI)*p_stdev); + } + + /** + * Computes and returns the cumulative distribution up to the + * specified value on the gaussian distribution. + * + * @param value the input value + * + * @returns The CDF evaluated at the specified value + */ + double GaussianDistribution::CumulativeDistribution (const double value) { + // returns for the two extremes + if (value == DBL_MIN) { + return 0.0; + } else if (value == DBL_MAX) { + return 1.0; + } + + // normalize the value and calculate the area under the + // pdf's curve. + double x = (value-p_mean)/p_stdev; + double sum = 0.0, + pre = -1.0; + double fact = 1.0; // fact = n! + // use taylor series to compute the area to machine precesion + // i.e. if an iteration has no impact on the sum, none of the following + // ones will since they are monotonically decreasing + for (int n=0; pre != sum; n++) { + pre = sum; + // the nth term is x^(2n+1)/( (2n+1)*n!*(-2)^n ) + sum += std::pow(x, 2*n+1)/(fact*(2*n+1)*std::pow(-2.0, n)); + fact *= n+1; + } + + // return the percentage (100% based) + return 50.0 + 100.0/std::sqrt(2.0*PI)*sum; + } + + /** + * Computes and returns the inverse cumulative distribution + * evaluated at the specified percentage value on the gaussian + * distribution. + * + *@see "Rational Chebyshev Approximations for the Error Function + * - W. J. Cody + *@see + * http://home.online.no/~pjacklam/notes/invnorm/#The_distribution_function + * + * @param percent The input percentage value + * @returns The ICDF evaluated at the specified percentage value + */ + double GaussianDistribution::InverseCumulativeDistribution (const double percent) { + // the cutoff values used in the ICDF algorithm + static double lowCutoff = 2.425; + static double highCutoff = 97.575; + + if ((percent < 0.0) || (percent > 100.0)) { + string m = "Argument percent outside of the range 0 to 100 in"; + m += " [GaussianDistribution::InverseCumulativeDistribution]"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // for information on the following algorithm, go to the website + // specified above + + double x; + + if (percent == 0.0) { + return DBL_MIN; + } else if (percent == 100.0) { + return DBL_MAX; + } + + if (percent < lowCutoff) { + double q = std::sqrt(-2.0*std::log(percent/100.0)); + x = C(q)/D(q); + } else if (percent < highCutoff) { + double q = percent/100.0 - 0.5, + r = q*q; + x = A(r)*q/B(r); + } else { + double q = std::sqrt(-2.0*std::log(1.0 - percent/100.0)); + x = -1.0*C(q)/D(q); + } + + // refine the calculated value using one iteration of Halley's method + // for full machine precision + double e = CumulativeDistribution(p_stdev*x + p_mean) - percent; // the error amount + double u = e*std::sqrt(2.0*PI)*std::exp(-0.5*x*x); + x = x - u/(1 + 0.5*x*u); + + return p_stdev*x + p_mean; + } + + // The following methods are used to compute the ICDF + // see the InverseCumulativeDistribution method for + // more information + + double GaussianDistribution::A (const double x) { + static const double a[6] = { -39.69683028665376, + 220.9460984245205, + -275.9285104469687, + 138.3577518672690, + -30.66479806614716, + 2.506628277459239}; + + return((((a[0]*x + a[1])*x + a[2])*x + a[3])*x + a[4])*x + a[5]; + } + + double GaussianDistribution::B (const double x) { + static const double b[6] = { -54.47609879822406, + 161.5858368580409, + -155.6989798598866, + 66.80131188771972, + -13.28068155288572, + 1.0}; + + return((((b[0]*x + b[1])*x + b[2])*x + b[3])*x + b[4])*x + b[5]; + } + + double GaussianDistribution::C (const double x) { + static const double c[6] = { -0.007784894002430293, + -0.3223964580411365, + -2.400758277161838, + -2.549732539343734, + 4.374664141464968, + 2.938163982698783}; + + return((((c[0]*x + c[1])*x + c[2])*x + c[3])*x + c[4])*x + c[5]; + } + + double GaussianDistribution::D (const double x) { + static const double d[5] = { 0.007784695709041462, + 0.3224671290700398, + 2.445134137142996, + 3.754408661907416, + 1.0}; + + return(((d[0]*x + d[1])*x + d[2])*x + d[3])*x + d[4]; + } +} diff --git a/isis/src/base/objs/GaussianDistribution/GaussianDistribution.h b/isis/src/base/objs/GaussianDistribution/GaussianDistribution.h new file mode 100644 index 0000000000000000000000000000000000000000..8f8033d5ca206cf51d827e5753ac8e74c3b41621 --- /dev/null +++ b/isis/src/base/objs/GaussianDistribution/GaussianDistribution.h @@ -0,0 +1,90 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/07/09 16:58:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef GaussianDistribution_h +#define GaussianDistribution_h + +#include "Statistics.h" +#include "iException.h" +#include "Constants.h" + +namespace Isis { +/** + * @brief gaussian distribution class + * + * This class is used to calculate the probability distribution + * function, the cumulative distribution function, and the + * inverse cumulative distribution function of a gaussian (or + * normal) distribution. + * + * @ingroup Statistics + * + * @author 2006-05-25 Jacob Danton + * + * @internal + * @history 2006-05-25 Jacob Danton Original Version + * @history 2007-07-09 Janet Barrett - Removed invalid declaration of + * "static const double" variables + * p_lowCutoff and p_highCutoff from + * this file and moved them to the + * GaussianDistribution.cpp file. The + * variables were also renamed to + * lowCutoff and highCutoff. + */ + class GaussianDistribution : public Isis::Statistics { + public: + GaussianDistribution (const double mean = 0.0, const double standardDeviation = 1.0) ; + ~GaussianDistribution () {}; + + double Probability (const double value); + double CumulativeDistribution (const double value); + double InverseCumulativeDistribution (const double percent); + + /** +* Returns the mean. +* +* @returns The mean +*/ + inline double Mean () const { return p_mean;}; + + /** + * Returns the standard deviation. + * + * @returns The standard deviation + */ + inline double StandardDeviation () const { return p_stdev;}; + + private: + //! Value of the mean + double p_mean; + //! Value of the standard deviation + double p_stdev; + + // functions used for computing the ICDF + double A (const double x); + double B (const double x); + double C (const double x); + double D (const double x); + }; +}; + +#endif diff --git a/isis/src/base/objs/GaussianDistribution/GaussianDistribution.truth b/isis/src/base/objs/GaussianDistribution/GaussianDistribution.truth new file mode 100644 index 0000000000000000000000000000000000000000..fb7dc6b1ab3b12da613df1380d6042e5bf902b5f --- /dev/null +++ b/isis/src/base/objs/GaussianDistribution/GaussianDistribution.truth @@ -0,0 +1,26 @@ +Cumulative Distribution +-3 0.13498980316% +-2.5 0.62096653258% +-2 2.2750131948% +-1.5 6.6807201269% +-1 15.865525393% +-0.5 30.853753873% +0 50% +0.5 69.146246127% +1 84.134474607% +1.5 93.319279873% +2 97.724986805% +2.5 99.379033467% +3 99.865010197% +Inverse Cumulative Distribution +0% 2.2250738585e-308 +10% -1.2815515913 +20% -0.8416212744 +30% -0.52440046989 +40% -0.25334712873 +50% 0 +60% 0.25334712873 +70% 0.52440046989 +80% 0.8416212744 +90% 1.2815515913 +100% 1.7976931349e+308 diff --git a/isis/src/base/objs/GaussianDistribution/Makefile b/isis/src/base/objs/GaussianDistribution/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..18d6f99baaae82cef56e2c9a3aad9c107b397156 --- /dev/null +++ b/isis/src/base/objs/GaussianDistribution/Makefile @@ -0,0 +1,5 @@ +INCS = GaussianDistribution.h +SRCS = GaussianDistribution.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/GaussianDistribution/unitTest.cpp b/isis/src/base/objs/GaussianDistribution/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..11940df3249985f789a223768424a371972fb600 --- /dev/null +++ b/isis/src/base/objs/GaussianDistribution/unitTest.cpp @@ -0,0 +1,27 @@ +#include +#include +#include "GaussianDistribution.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + Isis::GaussianDistribution g; + + cout << setprecision(11); + + cout << "Cumulative Distribution" << endl; + for (int i=-30; i<=30; i +=5) { + double x = i/10.0; + cout << x << " " << g.CumulativeDistribution(x) << "%"<< endl; + } + + cout << "Inverse Cumulative Distribution" << endl; + for (int i=0; i<=10; i++) { + double p = 0.1*i; + cout << (10*i) << "% " << g.InverseCumulativeDistribution(p*100.0) << endl; + } +} diff --git a/isis/src/base/objs/GaussianStretch/GaussianStretch.cpp b/isis/src/base/objs/GaussianStretch/GaussianStretch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c1c70355be25891878f6fa7e9ce3d90ebf7d4b5 --- /dev/null +++ b/isis/src/base/objs/GaussianStretch/GaussianStretch.cpp @@ -0,0 +1,76 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/09/09 17:07:41 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "GaussianStretch.h" +#include "GaussianDistribution.h" +#include "Stretch.h" +#include "Message.h" +#include +#include +#include + +using namespace std; +namespace Isis { + /** + * Constructs a gaussian stretch object. + * + * @param histogram The input histogram + * @param mean The mean of the output distribution + * @param standardDeviation The standard deviation of the output + * distribution + */ + GaussianStretch::GaussianStretch (Histogram &histogram, const double mean, const double standardDeviation) { + GaussianDistribution dis(mean, standardDeviation); + + p_stretch.ClearPairs(); + p_stretch.AddPair(histogram.Minimum(), histogram.Minimum()); + double lastvalue = histogram.Minimum(); + for (int i=1; i<=histogram.Bins()-1; i++) { + double percent = 100.0 * (double)i / (double)histogram.Bins(); + double input = histogram.Percent(percent); + // stretch pairs must be monotonically increasing + if (lastvalue + DBL_EPSILON > input) continue; + if (fabs(input - lastvalue) < 100.0 * DBL_EPSILON) continue; + double output = dis.InverseCumulativeDistribution(percent); + p_stretch.AddPair(input, output); + lastvalue = input; + } + + if (histogram.Maximum() > lastvalue) { + if (abs(histogram.Maximum() - lastvalue) > 100 * DBL_EPSILON) { + p_stretch.AddPair(histogram.Maximum(), histogram.Maximum()); + } + } + } + + /** + * Maps an input value to an output value based on the gaussian + * distribution. + * + * @param value Value to map + * + * @return double The mapped output value is returned by this method + */ + double GaussianStretch::Map (const double value) const { + return p_stretch.Map(value); + } +} diff --git a/isis/src/base/objs/GaussianStretch/GaussianStretch.h b/isis/src/base/objs/GaussianStretch/GaussianStretch.h new file mode 100644 index 0000000000000000000000000000000000000000..70ce2ad4f5e8555da30f79dc17e15be203ba4478 --- /dev/null +++ b/isis/src/base/objs/GaussianStretch/GaussianStretch.h @@ -0,0 +1,63 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/09/09 17:07:44 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef GaussianStretch_h +#define GaussianStretch_h + +#include "Statistics.h" +#include "Histogram.h" +#include "Stretch.h" +#include "iException.h" +#include "Constants.h" + +namespace Isis { +/** + * @brief Gaussian stretch class + * + * This class is used to stretch the input histogram to a + * gaussian distribution with the specified mean and standard + * deviation. + * + * @ingroup Utility + * + * @author 2006-05-25 Jacob Danton + * + * @internal + * @history 2006-05-25 Jacob Danton Original Version + * @history 2006-10-28 Stuart Sides Fixed stretch pair ordering + * @history 2008-09-09 Steven Lambright Fixed stretch pair ordering again; + * this fix does not solve our problem but makes our tests work and + * isn't wrong. + */ + class GaussianStretch : public Isis::Statistics { + public: + GaussianStretch (Histogram &histogram, const double mean = 0.0, const double standardDeviation = 1.0) ; + ~GaussianStretch () {}; + + double Map (const double value) const; + private: + //! Value of the mean + Stretch p_stretch; + }; +}; + +#endif diff --git a/isis/src/base/objs/GaussianStretch/GaussianStretch.truth b/isis/src/base/objs/GaussianStretch/GaussianStretch.truth new file mode 100644 index 0000000000000000000000000000000000000000..5f0c44c98e4636ffe55993e3b03427af068e7c18 --- /dev/null +++ b/isis/src/base/objs/GaussianStretch/GaussianStretch.truth @@ -0,0 +1,100 @@ +0 0 +1 20.747515240369 +2 23.168889429356 +3 24.990395084633 +4 26.472049078042 +5 27.733169666996 +6 28.838925840712 +7 29.828998318883 +8 30.729429394183 +9 31.558277721534 +10 32.328605975205 +11 33.05018480289 +12 33.730524401716 +13 34.375529683922 +14 34.989933086505 +15 35.577590077165 +16 36.141686662209 +17 36.684888677989 +18 37.209451496438 +19 37.717302158345 +20 38.210101889665 +21 38.68929439416 +22 39.156143656381 +23 39.611763889768 +24 40.057143521158 +25 40.493164590787 +26 40.920618587854 +27 41.340219486121 +28 41.546417022757 +29 41.752614559393 +30 42.55809563574 +31 42.952217161815 +32 43.341215855026 +33 43.725516184403 +34 44.105513306503 +35 44.481576603619 +36 44.854052775204 +37 45.223268555055 +38 45.589533114039 +39 45.953140197843 +40 46.314370041136 +41 46.673491092903 +42 47.030761582441 +43 47.386430951265 +44 47.740741172714 +45 48.093927978313 +46 48.446222007737 +47 48.79784989748 +48 49.149035321994 +49 49.5 +50 49.850964678006 +51 50.20215010252 +52 50.553777992263 +53 50.906072021687 +54 51.259258827286 +55 51.613569048735 +56 51.791403733147 +57 51.969238417559 +58 52.326508907097 +59 53.046859802157 +60 53.410466885961 +61 53.776731444945 +62 54.145947224796 +63 54.518423396381 +64 54.894486693498 +65 55.274483815597 +66 55.658784144974 +67 56.047782838184 +68 56.44190436426 +69 56.841606578435 +70 57.247385440607 +71 57.659780513879 +72 58.079381412145 +73 58.506835409213 +74 58.942856478842 +75 59.388236110232 +76 59.843856343619 +77 60.31070560584 +78 60.789898110335 +79 61.282697841655 +80 61.790548503561 +81 62.315111322011 +82 62.858313337791 +83 63.422409922834 +84 64.010066913494 +85 64.624470316078 +86 65.269475598284 +87 65.94981519711 +88 66.671394024795 +89 67.441722278465 +90 68.270570605816 +91 69.171001681115 +92 70.161074159289 +93 71.266830333007 +94 72.527950921956 +95 74.009604915362 +96 75.831110570644 +97 78.252484759631 +98 82.068870239263 +99 99 diff --git a/isis/src/base/objs/GaussianStretch/GaussianStretch_Darwin_powerpc.truth b/isis/src/base/objs/GaussianStretch/GaussianStretch_Darwin_powerpc.truth new file mode 100644 index 0000000000000000000000000000000000000000..35b58572e7548b02a05c11be0d7c32daeaf798f3 --- /dev/null +++ b/isis/src/base/objs/GaussianStretch/GaussianStretch_Darwin_powerpc.truth @@ -0,0 +1,100 @@ +0 0 +1 20.747515240369 +2 23.168889429353 +3 24.990395084635 +4 26.472049078043 +5 27.733169666993 +6 28.838925840713 +7 29.828998318883 +8 30.729429394182 +9 31.558277721535 +10 32.328605975203 +11 33.05018480289 +12 33.730524401716 +13 34.375529683922 +14 34.989933086505 +15 35.577590077165 +16 36.141686662209 +17 36.684888677989 +18 37.209451496439 +19 37.717302158345 +20 38.210101889665 +21 38.68929439416 +22 39.15614365638 +23 39.611763889768 +24 40.057143521158 +25 40.493164590787 +26 40.920618587854 +27 41.340219486121 +28 41.546417022757 +29 41.752614559393 +30 42.55809563574 +31 42.952217161816 +32 43.341215855026 +33 43.725516184403 +34 44.105513306503 +35 44.481576603619 +36 44.854052775204 +37 45.223268555055 +38 45.589533114039 +39 45.953140197843 +40 46.314370041136 +41 46.673491092903 +42 47.030761582441 +43 47.386430951265 +44 47.740741172714 +45 48.093927978313 +46 48.446222007737 +47 48.79784989748 +48 49.149035321994 +49 49.5 +50 49.850964678006 +51 50.20215010252 +52 50.553777992263 +53 50.906072021687 +54 51.259258827286 +55 51.613569048735 +56 51.791403733147 +57 51.969238417559 +58 52.326508907097 +59 53.046859802157 +60 53.410466885961 +61 53.776731444945 +62 54.145947224796 +63 54.518423396381 +64 54.894486693498 +65 55.274483815597 +66 55.658784144974 +67 56.047782838184 +68 56.44190436426 +69 56.841606578435 +70 57.247385440607 +71 57.659780513879 +72 58.079381412146 +73 58.506835409213 +74 58.942856478842 +75 59.388236110231 +76 59.843856343619 +77 60.31070560584 +78 60.789898110335 +79 61.282697841655 +80 61.790548503561 +81 62.315111322011 +82 62.858313337791 +83 63.422409922835 +84 64.010066913495 +85 64.624470316078 +86 65.269475598284 +87 65.94981519711 +88 66.671394024797 +89 67.441722278465 +90 68.270570605818 +91 69.171001681115 +92 70.161074159289 +93 71.266830333003 +94 72.527950921957 +95 74.009604915367 +96 75.831110570647 +97 78.252484759631 +98 82.068870239263 +99 99 diff --git a/isis/src/base/objs/GaussianStretch/GaussianStretch_Linux_i686_RedHat5_4.truth b/isis/src/base/objs/GaussianStretch/GaussianStretch_Linux_i686_RedHat5_4.truth new file mode 100644 index 0000000000000000000000000000000000000000..c6c725f95c9e306ba82ffe5696e20db24d10ad86 --- /dev/null +++ b/isis/src/base/objs/GaussianStretch/GaussianStretch_Linux_i686_RedHat5_4.truth @@ -0,0 +1,100 @@ +0 0 +1 20.747515240369 +2 23.168889429355 +3 24.990395084635 +4 26.472049078043 +5 27.733169666995 +6 28.838925840712 +7 29.828998318885 +8 30.729429394182 +9 31.558277721536 +10 32.328605975204 +11 33.050184802889 +12 33.730524401716 +13 34.375529683923 +14 34.989933086505 +15 35.577590077165 +16 36.141686662209 +17 36.684888677989 +18 37.209451496439 +19 37.717302158345 +20 38.210101889665 +21 38.68929439416 +22 39.156143656381 +23 39.611763889768 +24 40.057143521158 +25 40.493164590787 +26 40.920618587854 +27 41.340219486121 +28 41.752614559393 +29 42.158393421565 +30 42.55809563574 +31 42.952217161816 +32 43.341215855026 +33 43.725516184403 +34 44.105513306503 +35 44.481576603619 +36 44.854052775203 +37 45.223268555055 +38 45.589533114039 +39 45.953140197843 +40 46.314370041136 +41 46.673491092903 +42 47.030761582441 +43 47.386430951265 +44 47.740741172714 +45 48.093927978313 +46 48.446222007736 +47 48.79784989748 +48 49.149035321994 +49 49.5 +50 49.850964678006 +51 50.20215010252 +52 50.377964047392 +53 50.553777992264 +54 51.259258827286 +55 51.613569048735 +56 51.969238417559 +57 52.326508907097 +58 52.50606943298 +59 52.685629958864 +60 53.410466885961 +61 53.776731444945 +62 54.145947224797 +63 54.518423396381 +64 54.894486693498 +65 55.274483815598 +66 55.658784144974 +67 56.047782838184 +68 56.44190436426 +69 56.841606578435 +70 57.247385440607 +71 57.659780513879 +72 58.079381412146 +73 58.506835409213 +74 58.942856478842 +75 59.388236110231 +76 59.843856343619 +77 60.31070560584 +78 60.789898110335 +79 61.282697841655 +80 61.790548503561 +81 62.315111322011 +82 62.858313337791 +83 63.422409922835 +84 64.010066913495 +85 64.624470316078 +86 65.269475598284 +87 65.949815197111 +88 66.671394024795 +89 67.441722278464 +90 68.270570605818 +91 69.171001681115 +92 70.161074159287 +93 71.266830333005 +94 72.527950921957 +95 74.009604915365 +96 75.831110570645 +97 78.252484759631 +98 82.068870239263 +99 99 diff --git a/isis/src/base/objs/GaussianStretch/GaussianStretch_Linux_i686_RedHat5_5.truth b/isis/src/base/objs/GaussianStretch/GaussianStretch_Linux_i686_RedHat5_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..c6c725f95c9e306ba82ffe5696e20db24d10ad86 --- /dev/null +++ b/isis/src/base/objs/GaussianStretch/GaussianStretch_Linux_i686_RedHat5_5.truth @@ -0,0 +1,100 @@ +0 0 +1 20.747515240369 +2 23.168889429355 +3 24.990395084635 +4 26.472049078043 +5 27.733169666995 +6 28.838925840712 +7 29.828998318885 +8 30.729429394182 +9 31.558277721536 +10 32.328605975204 +11 33.050184802889 +12 33.730524401716 +13 34.375529683923 +14 34.989933086505 +15 35.577590077165 +16 36.141686662209 +17 36.684888677989 +18 37.209451496439 +19 37.717302158345 +20 38.210101889665 +21 38.68929439416 +22 39.156143656381 +23 39.611763889768 +24 40.057143521158 +25 40.493164590787 +26 40.920618587854 +27 41.340219486121 +28 41.752614559393 +29 42.158393421565 +30 42.55809563574 +31 42.952217161816 +32 43.341215855026 +33 43.725516184403 +34 44.105513306503 +35 44.481576603619 +36 44.854052775203 +37 45.223268555055 +38 45.589533114039 +39 45.953140197843 +40 46.314370041136 +41 46.673491092903 +42 47.030761582441 +43 47.386430951265 +44 47.740741172714 +45 48.093927978313 +46 48.446222007736 +47 48.79784989748 +48 49.149035321994 +49 49.5 +50 49.850964678006 +51 50.20215010252 +52 50.377964047392 +53 50.553777992264 +54 51.259258827286 +55 51.613569048735 +56 51.969238417559 +57 52.326508907097 +58 52.50606943298 +59 52.685629958864 +60 53.410466885961 +61 53.776731444945 +62 54.145947224797 +63 54.518423396381 +64 54.894486693498 +65 55.274483815598 +66 55.658784144974 +67 56.047782838184 +68 56.44190436426 +69 56.841606578435 +70 57.247385440607 +71 57.659780513879 +72 58.079381412146 +73 58.506835409213 +74 58.942856478842 +75 59.388236110231 +76 59.843856343619 +77 60.31070560584 +78 60.789898110335 +79 61.282697841655 +80 61.790548503561 +81 62.315111322011 +82 62.858313337791 +83 63.422409922835 +84 64.010066913495 +85 64.624470316078 +86 65.269475598284 +87 65.949815197111 +88 66.671394024795 +89 67.441722278464 +90 68.270570605818 +91 69.171001681115 +92 70.161074159287 +93 71.266830333005 +94 72.527950921957 +95 74.009604915365 +96 75.831110570645 +97 78.252484759631 +98 82.068870239263 +99 99 diff --git a/isis/src/base/objs/GaussianStretch/GaussianStretch_Linux_i686_SUSE10_1.truth b/isis/src/base/objs/GaussianStretch/GaussianStretch_Linux_i686_SUSE10_1.truth new file mode 100644 index 0000000000000000000000000000000000000000..add802c61cf90490ac304165dcd50fa4c6aa4dcf --- /dev/null +++ b/isis/src/base/objs/GaussianStretch/GaussianStretch_Linux_i686_SUSE10_1.truth @@ -0,0 +1,100 @@ +0 0 +1 20.747515240369 +2 23.168889429355 +3 24.990395084635 +4 26.472049078043 +5 27.733169666995 +6 28.838925840712 +7 29.828998318885 +8 30.729429394182 +9 31.558277721536 +10 32.328605975204 +11 33.050184802889 +12 33.730524401716 +13 34.375529683923 +14 34.989933086505 +15 35.577590077165 +16 36.141686662209 +17 36.684888677989 +18 37.209451496438 +19 37.717302158345 +20 38.210101889665 +21 38.68929439416 +22 39.156143656381 +23 39.611763889768 +24 40.057143521158 +25 40.493164590787 +26 40.920618587854 +27 41.340219486121 +28 41.752614559393 +29 42.158393421565 +30 42.55809563574 +31 42.952217161816 +32 43.341215855026 +33 43.725516184403 +34 44.105513306503 +35 44.481576603619 +36 44.854052775204 +37 45.223268555055 +38 45.589533114039 +39 45.953140197843 +40 46.314370041136 +41 46.673491092903 +42 47.030761582441 +43 47.386430951265 +44 47.740741172714 +45 48.093927978313 +46 48.446222007736 +47 48.79784989748 +48 49.149035321994 +49 49.5 +50 49.850964678006 +51 50.20215010252 +52 50.377964047392 +53 50.553777992264 +54 51.259258827286 +55 51.613569048735 +56 51.969238417559 +57 52.326508907097 +58 52.50606943298 +59 52.685629958864 +60 53.410466885961 +61 53.776731444945 +62 54.145947224796 +63 54.518423396381 +64 54.894486693498 +65 55.274483815598 +66 55.658784144974 +67 56.047782838184 +68 56.44190436426 +69 56.841606578435 +70 57.247385440607 +71 57.659780513879 +72 58.079381412146 +73 58.506835409213 +74 58.942856478842 +75 59.388236110231 +76 59.843856343619 +77 60.31070560584 +78 60.789898110335 +79 61.282697841655 +80 61.790548503562 +81 62.315111322011 +82 62.858313337791 +83 63.422409922835 +84 64.010066913495 +85 64.624470316078 +86 65.269475598284 +87 65.949815197111 +88 66.671394024795 +89 67.441722278464 +90 68.270570605818 +91 69.171001681115 +92 70.161074159287 +93 71.266830333005 +94 72.527950921957 +95 74.009604915365 +96 75.831110570645 +97 78.252484759631 +98 82.068870239263 +99 99 diff --git a/isis/src/base/objs/GaussianStretch/Makefile b/isis/src/base/objs/GaussianStretch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..978356021db0d9ba61f994a695e2afe11ae8e954 --- /dev/null +++ b/isis/src/base/objs/GaussianStretch/Makefile @@ -0,0 +1,5 @@ +INCS = GaussianStretch.h +SRCS = GaussianStretch.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/GaussianStretch/unitTest.cpp b/isis/src/base/objs/GaussianStretch/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3835c4590a1a94d54c6e5a2ae228cca105396a85 --- /dev/null +++ b/isis/src/base/objs/GaussianStretch/unitTest.cpp @@ -0,0 +1,28 @@ +#include +#include +#include "GaussianStretch.h" +#include "Histogram.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + Isis::Histogram hist(0, 99, 100); + + cout << setprecision(14); + + int numData = 100; + double data[numData]; + for (int i=0; i 1 && height > 1) { + for(int i = 1; i <= width; i++) { + pix1 = chip.GetValue(i + offset, 1 + offset); + pix2 = chip.GetValue(width - i + 1 + offset, height + offset); + if(ValidDnValue(pix1) && ValidDnValue(pix2)) gradient += std::abs(pix1 - pix2); + } + + for(int i = 2; i < height; i++) { + pix1 = chip.GetValue(1 + offset, i + offset); + pix2 = chip.GetValue(width + offset, height - i + 1 + offset); + if(ValidDnValue(pix1) && ValidDnValue(pix2)) gradient += std::abs(pix1 - pix2); + } + + width -= 2; + height -= 2; + offset += 1; + } + + return gradient; + } +} + +extern "C" Isis::InterestOperator *GradientOperatorPlugin(Isis::Pvl &pPvl) { + return new Isis::GradientOperator(pPvl); +} + diff --git a/isis/src/base/objs/GradientOperator/GradientOperator.h b/isis/src/base/objs/GradientOperator/GradientOperator.h new file mode 100644 index 0000000000000000000000000000000000000000..3150047fd773c3478e57339a19f812cc26601dcd --- /dev/null +++ b/isis/src/base/objs/GradientOperator/GradientOperator.h @@ -0,0 +1,55 @@ +#if !defined(GradientOperator_h) +#define GradientOperator_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/06/10 23:40:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "InterestOperator.h" + +namespace Isis { + class Pvl; + class Chip; + + /** + * @brief Gradient interest operator + * + * This class is used to construct a gradient interest operator. + * For this class, the interest is always positive with the worst + * interest amount being 0. The higher the interest, the better. + * + * @see InterestOperator + * + * @author 2006-02-11 Jacob Danton + * + * @history 2010-06-10 Sharmila Prasad Updated to accomadate CnetValidMeasure base class + */ + class GradientOperator : public InterestOperator { + public: + GradientOperator(Pvl &pPvl) : InterestOperator(pPvl) {}; + virtual ~GradientOperator() {}; + + protected: + virtual double Interest(Chip &chip); + }; +}; + +#endif diff --git a/isis/src/base/objs/GradientOperator/GradientOperator.truth b/isis/src/base/objs/GradientOperator/GradientOperator.truth new file mode 100644 index 0000000000000000000000000000000000000000..7e32b0c5669a3b92143d8f3c396e8bb2f3340dbd --- /dev/null +++ b/isis/src/base/objs/GradientOperator/GradientOperator.truth @@ -0,0 +1,14 @@ +Object = InterestOperator + Group = Operator + Name = Gradient + DeltaLine = 100 + DeltaSamp = 100 + Samples = 15 + Lines = 15 + MinimumInterest = 1 + End_Group +End_Object +End +Sample: 91 +Line : 371 +Interest: 2.99249 diff --git a/isis/src/base/objs/GradientOperator/InterestOperator.plugin b/isis/src/base/objs/GradientOperator/InterestOperator.plugin new file mode 100644 index 0000000000000000000000000000000000000000..2eb4e65810d703978fa69ec6990797a5db8a03cd --- /dev/null +++ b/isis/src/base/objs/GradientOperator/InterestOperator.plugin @@ -0,0 +1,4 @@ +Group = Gradient + Library = GradientOperator + Routine = GradientOperatorPlugin +End_Group diff --git a/isis/src/base/objs/GradientOperator/Makefile b/isis/src/base/objs/GradientOperator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..247d177bf4b38164cd715f7ed6c5d5c6c4122880 --- /dev/null +++ b/isis/src/base/objs/GradientOperator/Makefile @@ -0,0 +1,5 @@ +INCS = GradientOperator.h +SRCS = GradientOperator.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/GradientOperator/unitTest.cpp b/isis/src/base/objs/GradientOperator/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be2d9d245a930b47792e9399ece4c3a4207c66e5 --- /dev/null +++ b/isis/src/base/objs/GradientOperator/unitTest.cpp @@ -0,0 +1,50 @@ +#include +#include +#include "InterestOperator.h" +#include "InterestOperatorFactory.h" +#include "GradientOperator.h" +#include "Chip.h" +#include "Cube.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + try { + PvlGroup op("Operator"); + op += PvlKeyword("Name","Gradient"); + op += PvlKeyword("DeltaLine", 100); + op += PvlKeyword("DeltaSamp", 100); + op += PvlKeyword("Samples", 15); + op += PvlKeyword("Lines", 15); + op += PvlKeyword("MinimumInterest", 1); + + PvlObject o("InterestOperator"); + o.AddGroup(op); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl; + + InterestOperator *iop = InterestOperatorFactory::Create(pvl); + + Cube c; + c.Open("$mgs/testData/ab102401.cub"); + + //iop->Operate(c, 100, 350); + UniversalGroundMap univGrndMap(c); + iop->Operate(c, univGrndMap, 100, 350); + + std::cout << "Sample: " << iop->CubeSample() << std::endl + << "Line : " << iop->CubeLine() << std::endl + << "Interest: " << iop->InterestAmount() << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/GridPolygonSeeder/GridPolygonSeeder.cpp b/isis/src/base/objs/GridPolygonSeeder/GridPolygonSeeder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f1f3e01a28d0c30a3f8add5defeef6c965c88640 --- /dev/null +++ b/isis/src/base/objs/GridPolygonSeeder/GridPolygonSeeder.cpp @@ -0,0 +1,495 @@ +/** + * @file + * $Revision: 1.15 $ + * $Date: 2010/05/05 21:24:01 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "PolygonTools.h" +#include "iString.h" + +#include "GridPolygonSeeder.h" + +namespace Isis { + + /** + * @brief Construct a GridPolygonSeeder algorithm + * + * + * @param pvl A Pvl object that contains a valid polygon point + * seeding definition + */ + GridPolygonSeeder::GridPolygonSeeder (Pvl &pvl) : PolygonSeeder(pvl) { + Parse(pvl); + }; + + + /** + * @brief Seed a polygon with points + * + * Seed the supplied polygon with points in a grid pattern. The spacing + * is determined by the PVL group "PolygonSeederAlgorithm" + * + * @param lonLatPoly geos::MultiPolygon The polygon to be seeded with + * points. + * @param proj The Projection to seed the polygon into + * + * @return std::vector A vector of points which have been + * seeded into the polygon. The caller assumes responsibility for deleteing + * these. + * + * @internal + * @history 2007-05-09 Tracie Sucharski, Changed a single spacing value + * to a separate value for x and y. + */ + std::vector GridPolygonSeeder::Seed(const geos::geom::MultiPolygon *lonLatPoly) { + //Projection *proj) { + /*if (proj == NULL) { + std::string msg = "No Projection object available"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + }*/ + + if(!p_subGrid) + //return SeedGrid(lonLatPoly, proj); + return SeedGrid(lonLatPoly); + else + //return SeedSubGrid(lonLatPoly, proj); + return SeedSubGrid(lonLatPoly); + + } + + std::vector GridPolygonSeeder::SeedGrid(const geos::geom::MultiPolygon *multiPoly) { + + // Storage for the points to be returned + std::vector points; + + // Create some things we will need shortly + const geos::geom::Envelope *polyBoundBox = multiPoly->getEnvelopeInternal(); + + // Call the parents standardTests member + std::string msg = StandardTests(multiPoly, polyBoundBox); + if (!msg.empty()) { + return points; + } + + // Do grid specific tests to make sure this poly should be seeded + // (none for now) + + // Starting at the centroid of the xy polygon populate the polygon with a + // grid of points with the requested spacing + geos::geom::Point *centroid = multiPoly->getCentroid(); + double centerX = centroid->getX(); + double centerY = centroid->getY(); + delete centroid; + + int xStepsLeft = (int)((centerX-polyBoundBox->getMinX())/p_Xspacing + 0.5); + int yStepsLeft = (int)((centerY-polyBoundBox->getMinY())/p_Yspacing + 0.5); + double dRealMinX = centerX - (xStepsLeft * p_Xspacing); + double dRealMinY = centerY - (yStepsLeft * p_Yspacing); + + for (double y=dRealMinY; y <= polyBoundBox->getMaxY(); y += p_Yspacing) { + for (double x=dRealMinX; x <= polyBoundBox->getMaxX(); x +=p_Xspacing) { + geos::geom::Coordinate c(x,y); + geos::geom::Point *p = Isis::globalFactory.createPoint(c); + + if (p->within(multiPoly)) { + points.push_back(Isis::globalFactory.createPoint(c)); + } + else { + delete p; + } + } + } + + return points; + } + + /** + * This method works a lot like SeedGrid, except around the edges of known polygons. + * This method varies in that every grid square around the edge of a found polygon will + * be searched in more depth than all other grid squares. + * + * @param lonLatPoly + * @param proj + * + * @return std::vector List of found points inside the polygon + */ + std::vector GridPolygonSeeder::SeedSubGrid(const geos::geom::MultiPolygon *multiPoly) { + //Projection *proj) { + // Storage for the points to be returned + std::vector points; + + // Create some things we will need shortly + //geos::geom::MultiPolygon *xymp = PolygonTools::LatLonToXY(*lonLatPoly, proj); + const geos::geom::Envelope *polyBoundBox = multiPoly->getEnvelopeInternal(); + + // Call the parents standardTests member + std::string msg = StandardTests(multiPoly, polyBoundBox); + if (!msg.empty()) { + return points; + } + + geos::geom::Point *centroid = multiPoly->getCentroid(); + double centerX = centroid->getX(); + double centerY = centroid->getY(); + delete centroid; + + // Do grid specific tests to make sure this poly should be seeded + // (none for now) + + /** + * Every square in the grid needs to be monitored, we'll need to know if: + * (a) center needs checked - pointShouldCheck + * (b) entire square needs checked using precision, next to found pt - pointShouldSubGridCheck + * (c) A point was found in the square - pointFound + * (d) The center of the square is not found, but the square hasnt been checked in depth - pointNotFound + * (e) The square has been checked in depth and no valid points found - pointCantFind + */ + enum PointStatus { + pointShouldCheck, + pointShouldSubGridCheck, + pointFound, + pointNotFound, + pointCantFind + }; + + // For maintaining an idea of what's going on in this polygon, we needs to know the dimensions + // of the grid. + int xSteps = (int)((polyBoundBox->getMaxX()-polyBoundBox->getMinX())/p_Xspacing + 1.5); + int ySteps = (int)((polyBoundBox->getMaxY()-polyBoundBox->getMinY())/p_Yspacing + 1.5); + PointStatus pointCheck[xSteps][ySteps]; + + // Initialize our grid of point status' + for(int y = 0; y < ySteps; y++) { + for(int x = 0; x < xSteps; x++) { + pointCheck[x][y] = pointShouldCheck; + } + } + + /** + * This is a pretty good equation for how much precision is to be used in the in-depth checks + * around the edges of polygons. + * + * Thickness * Depth^2 <= 0.5 (0.5 is a constant, the larger the more precision to be used) + * Depth^2 <= 0.5/Thickness + * Depth <= (0.5/Thickness)^0.5 + */ + int precision = (int)pow(0.5/MinimumThickness(), 0.5)*2; + bool bGridCleared = true; + int xStepsToCentroid = (int)((centerX-polyBoundBox->getMinX())/p_Xspacing + 0.5); + int yStepsToCentroid = (int)((centerY-polyBoundBox->getMinY())/p_Yspacing + 0.5); + double dRealMinX = centerX - (xStepsToCentroid * p_Xspacing); + double dRealMinY = centerY - (yStepsToCentroid * p_Yspacing); + + do { + // gridCleared is true if we did nothing, if we performed any actions on the grid + // it becomes false and another pass should be used. + bGridCleared = true; + + for(int y = 0; y < ySteps; y++) { + double centerY = dRealMinY + p_Yspacing * y; + for(int x = 0; x < xSteps; x++) { + double centerX = dRealMinX + p_Xspacing * x; + geos::geom::Point *p = NULL; + + // pointShouldCheck tells us we need to check center. Calling + // CheckSubGrid with precision=0 will do this for us. + if(pointCheck[x][y] == pointShouldCheck) { + p = CheckSubGrid(*multiPoly, centerX, centerY, 0); + } + // pointShouldSubGridCheck tells us we're next to a grid + // square where a point was found, so check in depth + else if(pointCheck[x][y] == pointShouldSubGridCheck) { + p = CheckSubGrid(*multiPoly, centerX, centerY, precision); + } + + // If we found a point, verify we can setCoordinate and save the point + if(p != NULL) { + // Convert the x/y point to a lon/lat point + /*if (proj->SetCoordinate(p->getX(),p->getY())) { + points.push_back(Isis::globalFactory.createPoint( + geos::geom::Coordinate(proj->UniversalLongitude(), + proj->UniversalLatitude()))); + } + else { + iString msg = "Unable to convert [(" + iString(x) + ","; + msg += iString(y) + ")] to a (lon,lat)"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + }*/ + points.push_back(Isis::globalFactory.createPoint( + geos::geom::Coordinate(p->getX(), p->getY()))); + + // We found something new and need a new pass + bGridCleared = false; + pointCheck[x][y] = pointFound; + } + else { + if(pointCheck[x][y] == pointShouldCheck) { + pointCheck[x][y] = pointNotFound; + } + else if(pointCheck[x][y] == pointShouldSubGridCheck) { + pointCheck[x][y] = pointCantFind; + } + } + } + } + + // now that the grid has been updated with it's founds, we can look for subgrid checks + for(int y = 0; y < ySteps; y++) { + for(int x = 0; x < xSteps; x++) { + if(pointCheck[x][y] == pointFound) { + for(int yOff = -1; yOff <= 1; yOff++) { + for(int xOff = -1; xOff <= 1; xOff++) { + if(x+xOff >= 0 && x+xOff < xSteps && + y+yOff >= 0 && y+yOff < ySteps && + pointCheck[x+xOff][y+yOff] == pointNotFound) { + + pointCheck[x+xOff][y+yOff] = pointShouldSubGridCheck; + + // We need to do a searchso we need another pass + bGridCleared = false; + } + } + } + } + } + } + + } + while(!bGridCleared); + + return points; + } + + /** + * This method is used to search for a valid point, on the polygon, within the square + * whose center is defined by the centerX, centerY arguments and size is given by p_Xspacing + * and p_Yspacing. The precision parameter determines how many points are checked. If precision + * is zero, then only the center is checked. In other cases, the pattern looks like this: + * 0: ___________________________ + * | 2 1 2 | + * | 2 2 2 | + * | 2 1 2 0 2 1 2 | + * | 2 2 2 | + * | 2 1 2 | + * |___________________________| + * Where the numbers represent the precision at which the point will be found. + * + * @param xymp The multipolygon we're testing for points + * @param centerX The X position of the center of the polygon + * @param centerY The Y position of the center of the polygon + * @param precision See description + * + * @return geos::Point* Found point, NULL if nothing found + */ + geos::geom::Point *GridPolygonSeeder::CheckSubGrid(const geos::geom::MultiPolygon &xymp, const double ¢erX, + const double ¢erY, const int &precision) { + // We'll make a 2D array detailing which points to check, and which not to, in this rectangle. + // Figure out how many points across and vertically we need to check + int gridSize = 1; + for(int prec = 0; prec < precision && prec < 6; prec ++) { + // Maybe solve the recurrence relation for a single equation?? + gridSize = gridSize*2+1; + } + + // These are the possible values in which the 2D array can be. We need the transition value + // gridNewCheckPt to not count new points as old points. + enum GridPoint { + gridEmpty, + gridNewCheckPt, + gridCheckPt + }; + + GridPoint grid[gridSize][gridSize]; + + for(int y = 0; y < gridSize; y++) { + for(int x = 0; x < gridSize; x++) { + grid[x][y] = gridEmpty; + } + } + + // Precision 0: Always center, this is always true + grid[gridSize/2][gridSize/2] = gridCheckPt; + + // now populate the grid with what we wish to check for + for(int prec = 0; prec < precision; prec ++) { + // This tells us how far over in the 2D array to go at a precision from already found points + int checkDist = (gridSize+1)/(int)(4*(pow(2.0,prec))+0.5); + + // Search the grid for already found points and set everything checkDist away to be checked too + for(int y = 0; y < gridSize; y++) { + for(int x = 0; x < gridSize; x++) { + if(grid[x][y] == gridCheckPt) { + // We should never overwrite found points, the checkDist should assure this wont happen + if(x-checkDist>0) grid[x-checkDist][y] = gridNewCheckPt; + if(y-checkDist>0) grid[x][y-checkDist] = gridNewCheckPt; + if(x+checkDistwithin(&xymp)) { + result = p; + } + else { + delete p; + } + } + } + + return result; + } + + /** + * @brief Parse the GridPolygonSeeder spicific parameters from the PVL + * + * @param pvl The PVL object containing the control parameters for this + * polygon seeder. + */ + void GridPolygonSeeder::Parse(Pvl &pvl) { + // Call the parents Parse method + PolygonSeeder::Parse(pvl); + + // Pull parameters specific to this algorithm out + try { + // Get info from Algorithm group + PvlGroup &algo = pvl.FindGroup("PolygonSeederAlgorithm",Pvl::Traverse); + PvlGroup & invalgo = invalidInput->FindGroup("PolygonSeederAlgorithm", + Pvl::Traverse); + + // Set the spacing + p_Xspacing = 0.0; + if (algo.HasKeyword("XSpacing")) { + p_Xspacing = (double) algo["XSpacing"]; + if (invalgo.HasKeyword("XSpacing")) { + invalgo.DeleteKeyword("XSpacing"); + } + } + else { + std::string msg = "PVL for GridPolygonSeeder must contain [XSpacing] in ["; + msg += pvl.Filename() + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + p_Yspacing = 0.0; + if (algo.HasKeyword("YSpacing")) { + p_Yspacing = (double) algo["YSpacing"]; + if (invalgo.HasKeyword("YSpacing")) { + invalgo.DeleteKeyword("YSpacing"); + } + } + else { + std::string msg = "PVL for GridPolygonSeeder must contain [YSpacing] in ["; + msg += pvl.Filename() + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + p_subGrid = false; + if(algo.HasKeyword("SubGrid")) { + p_subGrid = iString((std::string)algo["SubGrid"]).UpCase() != "FALSE"; + if (invalgo.HasKeyword("SubGrid")) { + invalgo.DeleteKeyword("SubGrid"); + } + } + } + catch (iException &e) { + std::string msg = "Improper format for PolygonSeeder PVL ["+pvl.Filename()+"]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + if (p_Xspacing <= 0.0) { + iString msg = "X Spacing must be greater that 0.0 [(" + iString(p_Xspacing) + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + if (p_Yspacing <= 0.0) { + iString msg = "Y Spacing must be greater that 0.0 [(" + iString(p_Yspacing) + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + PvlGroup GridPolygonSeeder::PluginParameters(std::string grpName) { + PvlGroup pluginInfo(grpName); + + PvlKeyword name("Name", Algorithm()); + PvlKeyword minThickness("MinimumThickness", MinimumThickness()); + PvlKeyword minArea("MinimumArea", MinimumArea()); + PvlKeyword xSpac("XSpacing", p_Xspacing); + PvlKeyword ySpac("YSpacing", p_Yspacing); + PvlKeyword subGrid("SubGrid", p_subGrid); + + pluginInfo.AddKeyword(name); + pluginInfo.AddKeyword(minThickness); + pluginInfo.AddKeyword(minArea); + pluginInfo.AddKeyword(xSpac); + pluginInfo.AddKeyword(ySpac); + pluginInfo.AddKeyword(subGrid); + + return pluginInfo; + } + +}; // End of namespace Isis + + +/** + * @brief Create a GridPolygonSeeder object + * + * Used to create a GridPolygonSeeder object from a PolygonSeeder plugin PVL + * file. + * + * @param pvl The Pvl object that describes how the new object should be + * initialized. + * + * @return A pointer to the new object + */ +extern "C" Isis::PolygonSeeder *GridPolygonSeederPlugin (Isis::Pvl &pvl) { + return new Isis::GridPolygonSeeder(pvl); +} + diff --git a/isis/src/base/objs/GridPolygonSeeder/GridPolygonSeeder.h b/isis/src/base/objs/GridPolygonSeeder/GridPolygonSeeder.h new file mode 100644 index 0000000000000000000000000000000000000000..c0623e7f5ca66e342143bbe2a4fcf95b1143b15b --- /dev/null +++ b/isis/src/base/objs/GridPolygonSeeder/GridPolygonSeeder.h @@ -0,0 +1,94 @@ +#ifndef GridPolygonSeeder_h +#define GridPolygonSeeder_h +/** + * @file + * $Revision: 1.11 $ + * $Date: 2010/05/05 21:24:01 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "geos/geom/Point.h" +#include "geos/geom/MultiPolygon.h" + +#include "PolygonSeeder.h" + +namespace Isis { + class Pvl; + + /** + * @brief Seed points using a grid + * + * This class is used to construct a grid of points inside a polygon. + * + * @ingroup PatternMatching + * + * @author 2006-01-20 Stuart Sides + * + * @internal + * @history 2007-05-09 Tracie Sucharski, Changed a single spacing value + * to a separate value for x and y. + * @history 2008-02-29 Steven Lambright - Created SubGrid capabilities, + * cleaned up Seed methods + * @history 2008-06-18 Christopher Austin - Fixed documentation errors + * @history 2008-08-18 Christopher Austin - Upgraded to geos3.0.0 + * @history 2008-11-25 Steven Lambright - Added error checking + * @history 2008-12-05 Christopher Austin - capped the subgrid to 127x127 to + * prevent segfaults on too high a precision + * @history 2000-01-30 Steven Lambright - Fixed an issue with not seeding entire + * polygons when a large portion of the polygon was on the right side + * of the envelope. + * @history 2009-08-05 Travis Addair - Encapsulated group + * creation for seed definition group + * @history 2010-04-15 Eric Hyer - Now updates parent's invalidInput variable + * - included SubGrid for what PluginParameters + * returns + * @history 2010-04-20 Christopher Austin - adapted for generic/unitless + * seeding + */ + class GridPolygonSeeder : public PolygonSeeder { + public: + GridPolygonSeeder (Pvl &pvl); + + //! Destructor + virtual ~GridPolygonSeeder() {}; + + std::vector Seed(const geos::geom::MultiPolygon *mp); + + const bool SubGrid() { return p_subGrid; } + virtual PvlGroup PluginParameters(std::string grpName); + + protected: + virtual void Parse(Pvl &pvl); + + private: + std::vector SeedGrid(const geos::geom::MultiPolygon *mp); + + std::vector SeedSubGrid(const geos::geom::MultiPolygon *mp); + + + geos::geom::Point *CheckSubGrid(const geos::geom::MultiPolygon &, const double &, + const double &, const int &); + + double p_Xspacing; + double p_Yspacing; + bool p_subGrid; + }; +}; + +#endif diff --git a/isis/src/base/objs/GridPolygonSeeder/GridPolygonSeeder.truth b/isis/src/base/objs/GridPolygonSeeder/GridPolygonSeeder.truth new file mode 100644 index 0000000000000000000000000000000000000000..c124cc06e48ca89dc851c602952e59b9073823c4 --- /dev/null +++ b/isis/src/base/objs/GridPolygonSeeder/GridPolygonSeeder.truth @@ -0,0 +1,844 @@ +Test 1, create a seeder +Test without subgrid +Object = AutoSeed + Group = PolygonSeederAlgorithm + Name = Grid + MinimumThickness = 0.3 + MinimumArea = 10 + XSpacing = 1500 + YSpacing = 1500 + End_Group +End_Object +End + +Test to make sure Parse did it's job +MinimumThickness = 0.3 +MinimumArea = 10 +SubGrid = 0 +Test 2, test a square polygon +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.5000000000000000, 0.5000000000000000 0.5000000000000000, 0.5000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000))) + POINT (0.02224207650506 0.02224524784625) + POINT (0.04754798569954 0.02224524784625) + POINT (0.07285389489402 0.02224524784625) + POINT (0.09815980408851 0.02224524784625) + POINT (0.123465713283 0.02224524784625) + POINT (0.1487716224775 0.02224524784625) + POINT (0.174077531672 0.02224524784625) + POINT (0.1993834408664 0.02224524784625) + POINT (0.2246893500609 0.02224524784625) + POINT (0.2499952592554 0.02224524784625) + POINT (0.2753011684499 0.02224524784625) + POINT (0.3006070776444 0.02224524784625) + POINT (0.3259129868388 0.02224524784625) + POINT (0.3512188960333 0.02224524784625) + POINT (0.3765248052278 0.02224524784625) + POINT (0.4018307144223 0.02224524784625) + POINT (0.4271366236168 0.02224524784625) + POINT (0.4524425328113 0.02224524784625) + POINT (0.4777484420057 0.02224524784625) + POINT (0.02224208248856 0.04755115513342) + POINT (0.04754799849076 0.04755115513342) + POINT (0.07285391449296 0.04755115513342) + POINT (0.09815983049517 0.04755115513342) + POINT (0.1234657464974 0.04755115513342) + POINT (0.1487716624996 0.04755115513342) + POINT (0.1740775785018 0.04755115513342) + POINT (0.199383494504 0.04755115513342) + POINT (0.2246894105062 0.04755115513342) + POINT (0.2499953265084 0.04755115513342) + POINT (0.2753012425106 0.04755115513342) + POINT (0.3006071585128 0.04755115513342) + POINT (0.325913074515 0.04755115513342) + POINT (0.3512189905172 0.04755115513342) + POINT (0.3765249065194 0.04755115513342) + POINT (0.4018308225216 0.04755115513342) + POINT (0.4271367385238 0.04755115513342) + POINT (0.452442654526 0.04755115513342) + POINT (0.4777485705282 0.04755115513342) + POINT (0.02224209281091 0.07285706242059) + POINT (0.04754802055735 0.07285706242059) + POINT (0.0728539483038 0.07285706242059) + POINT (0.09815987605025 0.07285706242059) + POINT (0.1234658037967 0.07285706242059) + POINT (0.1487717315431 0.07285706242059) + POINT (0.1740776592896 0.07285706242059) + POINT (0.199383587036 0.07285706242059) + POINT (0.2246895147825 0.07285706242059) + POINT (0.2499954425289 0.07285706242059) + POINT (0.2753013702754 0.07285706242059) + POINT (0.3006072980218 0.07285706242059) + POINT (0.3259132257683 0.07285706242059) + POINT (0.3512191535147 0.07285706242059) + POINT (0.3765250812612 0.07285706242059) + POINT (0.4018310090076 0.07285706242059) + POINT (0.4271369367541 0.07285706242059) + POINT (0.4524428645005 0.07285706242059) + POINT (0.477748792247 0.07285706242059) + POINT (0.02224210747211 0.09816296970776) + POINT (0.04754805189934 0.09816296970776) + POINT (0.07285399632657 0.09816296970776) + POINT (0.0981599407538 0.09816296970776) + POINT (0.123465885181 0.09816296970776) + POINT (0.1487718296083 0.09816296970776) + POINT (0.1740777740355 0.09816296970776) + POINT (0.1993837184627 0.09816296970776) + POINT (0.2246896628899 0.09816296970776) + POINT (0.2499956073172 0.09816296970776) + POINT (0.2753015517444 0.09816296970776) + POINT (0.3006074961716 0.09816296970776) + POINT (0.3259134405989 0.09816296970776) + POINT (0.3512193850261 0.09816296970776) + POINT (0.3765253294533 0.09816296970776) + POINT (0.4018312738806 0.09816296970776) + POINT (0.4271372183078 0.09816296970776) + POINT (0.452443162735 0.09816296970776) + POINT (0.4777491071622 0.09816296970776) + POINT (0.0222421264722 0.1234688769949) + POINT (0.04754809251676 0.1234688769949) + POINT (0.07285405856132 0.1234688769949) + POINT (0.09816002460588 0.1234688769949) + POINT (0.1234659906504 0.1234688769949) + POINT (0.148771956695 0.1234688769949) + POINT (0.1740779227396 0.1234688769949) + POINT (0.1993838887841 0.1234688769949) + POINT (0.2246898548287 0.1234688769949) + POINT (0.2499958208733 0.1234688769949) + POINT (0.2753017869178 0.1234688769949) + POINT (0.3006077529624 0.1234688769949) + POINT (0.3259137190069 0.1234688769949) + POINT (0.3512196850515 0.1234688769949) + POINT (0.3765256510961 0.1234688769949) + POINT (0.4018316171406 0.1234688769949) + POINT (0.4271375831852 0.1234688769949) + POINT (0.4524435492297 0.1234688769949) + POINT (0.4777495152743 0.1234688769949) + POINT (0.02224214981117 0.1487747842821) + POINT (0.04754814240964 0.1487747842821) + POINT (0.07285413500811 0.1487747842821) + POINT (0.09816012760657 0.1487747842821) + POINT (0.123466120205 0.1487747842821) + POINT (0.1487721128035 0.1487747842821) + POINT (0.174078105402 0.1487747842821) + POINT (0.1993840980004 0.1487747842821) + POINT (0.2246900905989 0.1487747842821) + POINT (0.2499960831974 0.1487747842821) + POINT (0.2753020757958 0.1487747842821) + POINT (0.3006080683943 0.1487747842821) + POINT (0.3259140609928 0.1487747842821) + POINT (0.3512200535912 0.1487747842821) + POINT (0.3765260461897 0.1487747842821) + POINT (0.4018320387882 0.1487747842821) + POINT (0.4271380313866 0.1487747842821) + POINT (0.4524440239851 0.1487747842821) + POINT (0.4777500165836 0.1487747842821) + POINT (0.02224217748906 0.1740806915693) + POINT (0.04754820157803 0.1740806915693) + POINT (0.07285422566701 0.1740806915693) + POINT (0.09816024975598 0.1740806915693) + POINT (0.1234662738449 0.1740806915693) + POINT (0.1487722979339 0.1740806915693) + POINT (0.1740783220229 0.1740806915693) + POINT (0.1993843461119 0.1740806915693) + POINT (0.2246903702008 0.1740806915693) + POINT (0.2499963942898 0.1740806915693) + POINT (0.2753024183788 0.1740806915693) + POINT (0.3006084424677 0.1740806915693) + POINT (0.3259144665567 0.1740806915693) + POINT (0.3512204906457 0.1740806915693) + POINT (0.3765265147347 0.1740806915693) + POINT (0.4018325388236 0.1740806915693) + POINT (0.4271385629126 0.1740806915693) + POINT (0.4524445870016 0.1740806915693) + POINT (0.4777506110905 0.1740806915693) + POINT (0.0222422095059 0.1993865988565) + POINT (0.047548270022 0.1993865988565) + POINT (0.07285433053811 0.1993865988565) + POINT (0.09816039105421 0.1993865988565) + POINT (0.1234664515703 0.1993865988565) + POINT (0.1487725120864 0.1993865988565) + POINT (0.1740785726025 0.1993865988565) + POINT (0.1993846331186 0.1993865988565) + POINT (0.2246906936347 0.1993865988565) + POINT (0.2499967541508 0.1993865988565) + POINT (0.2753028146669 0.1993865988565) + POINT (0.300608875183 0.1993865988565) + POINT (0.3259149356992 0.1993865988565) + POINT (0.3512209962153 0.1993865988565) + POINT (0.3765270567314 0.1993865988565) + POINT (0.4018331172475 0.1993865988565) + POINT (0.4271391777636 0.1993865988565) + POINT (0.4524452382797 0.1993865988565) + POINT (0.4777512987958 0.1993865988565) + POINT (0.0222422458617 0.2246925061436) + POINT (0.04754834774161 0.2246925061436) + POINT (0.07285444962151 0.2246925061436) + POINT (0.09816055150141 0.2246925061436) + POINT (0.1234666533813 0.2246925061436) + POINT (0.1487727552612 0.2246925061436) + POINT (0.1740788571411 0.2246925061436) + POINT (0.199384959021 0.2246925061436) + POINT (0.2246910609009 0.2246925061436) + POINT (0.2499971627808 0.2246925061436) + POINT (0.2753032646607 0.2246925061436) + POINT (0.3006093665406 0.2246925061436) + POINT (0.3259154684205 0.2246925061436) + POINT (0.3512215703004 0.2246925061436) + POINT (0.3765276721803 0.2246925061436) + POINT (0.4018337740603 0.2246925061436) + POINT (0.4271398759402 0.2246925061436) + POINT (0.4524459778201 0.2246925061436) + POINT (0.4777520797 0.2246925061436) + POINT (0.02224228655652 0.2499984134308) + POINT (0.04754843473693 0.2499984134308) + POINT (0.07285458291734 0.2499984134308) + POINT (0.09816073109774 0.2499984134308) + POINT (0.1234668792781 0.2499984134308) + POINT (0.1487730274586 0.2499984134308) + POINT (0.174079175639 0.2499984134308) + POINT (0.1993853238194 0.2499984134308) + POINT (0.2246914719998 0.2499984134308) + POINT (0.2499976201802 0.2499984134308) + POINT (0.2753037683606 0.2499984134308) + POINT (0.300609916541 0.2499984134308) + POINT (0.3259160647214 0.2499984134308) + POINT (0.3512222129018 0.2499984134308) + POINT (0.3765283610822 0.2499984134308) + POINT (0.4018345092626 0.2499984134308) + POINT (0.427140657443 0.2499984134308) + POINT (0.4524468056234 0.2499984134308) + POINT (0.4777529538038 0.2499984134308) + POINT (0.02224233159039 0.275304320718) + POINT (0.04754853100805 0.275304320718) + POINT (0.07285473042571 0.275304320718) + POINT (0.09816092984337 0.275304320718) + POINT (0.123467129261 0.275304320718) + POINT (0.1487733286787 0.275304320718) + POINT (0.1740795280964 0.275304320718) + POINT (0.199385727514 0.275304320718) + POINT (0.2246919269317 0.275304320718) + POINT (0.2499981263493 0.275304320718) + POINT (0.275304325767 0.275304320718) + POINT (0.3006105251847 0.275304320718) + POINT (0.3259167246023 0.275304320718) + POINT (0.35122292402 0.275304320718) + POINT (0.3765291234376 0.275304320718) + POINT (0.4018353228553 0.275304320718) + POINT (0.427141522273 0.275304320718) + POINT (0.4524477216906 0.275304320718) + POINT (0.4777539211083 0.275304320718) + POINT (0.02224238096335 0.3006102280051) + POINT (0.04754863655506 0.3006102280051) + POINT (0.07285489214678 0.3006102280051) + POINT (0.0981611477385 0.3006102280051) + POINT (0.1234674033302 0.3006102280051) + POINT (0.1487736589219 0.3006102280051) + POINT (0.1740799145136 0.3006102280051) + POINT (0.1993861701054 0.3006102280051) + POINT (0.2246924256971 0.3006102280051) + POINT (0.2499986812888 0.3006102280051) + POINT (0.2753049368805 0.3006102280051) + POINT (0.3006111924722 0.3006102280051) + POINT (0.3259174480639 0.3006102280051) + POINT (0.3512237036557 0.3006102280051) + POINT (0.3765299592474 0.3006102280051) + POINT (0.4018362148391 0.3006102280051) + POINT (0.4271424704308 0.3006102280051) + POINT (0.4524487260225 0.3006102280051) + POINT (0.4777549816142 0.3006102280051) + POINT (0.02224243467545 0.3259161352923) + POINT (0.04754875137807 0.3259161352923) + POINT (0.0728550680807 0.3259161352923) + POINT (0.09816138478333 0.3259161352923) + POINT (0.123467701486 0.3259161352923) + POINT (0.1487740181886 0.3259161352923) + POINT (0.1740803348912 0.3259161352923) + POINT (0.1993866515938 0.3259161352923) + POINT (0.2246929682965 0.3259161352923) + POINT (0.2499992849991 0.3259161352923) + POINT (0.2753056017017 0.3259161352923) + POINT (0.3006119184043 0.3259161352923) + POINT (0.325918235107 0.3259161352923) + POINT (0.3512245518096 0.3259161352923) + POINT (0.3765308685122 0.3259161352923) + POINT (0.4018371852148 0.3259161352923) + POINT (0.4271435019175 0.3259161352923) + POINT (0.4524498186201 0.3259161352923) + POINT (0.4777561353227 0.3259161352923) + POINT (0.02224249272674 0.3512220425795) + POINT (0.04754887547719 0.3512220425795) + POINT (0.07285525822764 0.3512220425795) + POINT (0.09816164097809 0.3512220425795) + POINT (0.1234680237285 0.3512220425795) + POINT (0.148774406479 0.3512220425795) + POINT (0.1740807892294 0.3512220425795) + POINT (0.1993871719799 0.3512220425795) + POINT (0.2246935547304 0.3512220425795) + POINT (0.2499999374808 0.3512220425795) + POINT (0.2753063202313 0.3512220425795) + POINT (0.3006127029817 0.3512220425795) + POINT (0.3259190857322 0.3512220425795) + POINT (0.3512254684826 0.3512220425795) + POINT (0.3765318512331 0.3512220425795) + POINT (0.4018382339835 0.3512220425795) + POINT (0.427144616734 0.3512220425795) + POINT (0.4524509994844 0.3512220425795) + POINT (0.4777573822349 0.3512220425795) + POINT (0.02224255511729 0.3765279498667) + POINT (0.04754900885254 0.3765279498667) + POINT (0.0728554625878 0.3765279498667) + POINT (0.09816191632305 0.3765279498667) + POINT (0.1234683700583 0.3765279498667) + POINT (0.1487748237936 0.3765279498667) + POINT (0.1740812775288 0.3765279498667) + POINT (0.1993877312641 0.3765279498667) + POINT (0.2246941849993 0.3765279498667) + POINT (0.2500006387346 0.3765279498667) + POINT (0.2753070924698 0.3765279498667) + POINT (0.3006135462051 0.3765279498667) + POINT (0.3259199999403 0.3765279498667) + POINT (0.3512264536756 0.3765279498667) + POINT (0.3765329074109 0.3765279498667) + POINT (0.4018393611461 0.3765279498667) + POINT (0.4271458148814 0.3765279498667) + POINT (0.4524522686166 0.3765279498667) + POINT (0.4777587223519 0.3765279498667) + POINT (0.02224262184714 0.4018338571538) + POINT (0.04754915150425 0.4018338571538) + POINT (0.07285568116136 0.4018338571538) + POINT (0.09816221081847 0.4018338571538) + POINT (0.1234687404756 0.4018338571538) + POINT (0.1487752701327 0.4018338571538) + POINT (0.1740817997898 0.4018338571538) + POINT (0.1993883294469 0.4018338571538) + POINT (0.224694859104 0.4018338571538) + POINT (0.2500013887611 0.4018338571538) + POINT (0.2753079184182 0.4018338571538) + POINT (0.3006144480753 0.4018338571538) + POINT (0.3259209777324 0.4018338571538) + POINT (0.3512275073895 0.4018338571538) + POINT (0.3765340370467 0.4018338571538) + POINT (0.4018405667038 0.4018338571538) + POINT (0.4271470963609 0.4018338571538) + POINT (0.452453626018 0.4018338571538) + POINT (0.4777601556751 0.4018338571538) + POINT (0.02224269291637 0.427139764441) + POINT (0.04754930343246 0.427139764441) + POINT (0.07285591394854 0.427139764441) + POINT (0.09816252446462 0.427139764441) + POINT (0.1234691349807 0.427139764441) + POINT (0.1487757454968 0.427139764441) + POINT (0.1740823560129 0.427139764441) + POINT (0.199388966529 0.427139764441) + POINT (0.224695577045 0.427139764441) + POINT (0.2500021875611 0.427139764441) + POINT (0.2753087980772 0.427139764441) + POINT (0.3006154085933 0.427139764441) + POINT (0.3259220191094 0.427139764441) + POINT (0.3512286296255 0.427139764441) + POINT (0.3765352401415 0.427139764441) + POINT (0.4018418506576 0.427139764441) + POINT (0.4271484611737 0.427139764441) + POINT (0.4524550716898 0.427139764441) + POINT (0.4777616822059 0.427139764441) + POINT (0.02224276832505 0.4524456717282) + POINT (0.04754946463731 0.4524456717282) + POINT (0.07285616094957 0.4524456717282) + POINT (0.09816285726183 0.4524456717282) + POINT (0.1234695535741 0.4524456717282) + POINT (0.1487762498864 0.4524456717282) + POINT (0.1740829461986 0.4524456717282) + POINT (0.1993896425109 0.4524456717282) + POINT (0.2246963388231 0.4524456717282) + POINT (0.2500030351354 0.4524456717282) + POINT (0.2753097314477 0.4524456717282) + POINT (0.3006164277599 0.4524456717282) + POINT (0.3259231240722 0.4524456717282) + POINT (0.3512298203844 0.4524456717282) + POINT (0.3765365166967 0.4524456717282) + POINT (0.401843213009 0.4524456717282) + POINT (0.4271499093212 0.4524456717282) + POINT (0.4524566056335 0.4524456717282) + POINT (0.4777633019457 0.4524456717282) + POINT (0.02224284807325 0.4777515790154) + POINT (0.04754963511897 0.4777515790154) + POINT (0.07285642216469 0.4777515790154) + POINT (0.09816320921041 0.4777515790154) + POINT (0.1234699962561 0.4777515790154) + POINT (0.1487767833019 0.4777515790154) + POINT (0.1740835703476 0.4777515790154) + POINT (0.1993903573933 0.4777515790154) + POINT (0.224697144439 0.4777515790154) + POINT (0.2500039314847 0.4777515790154) + POINT (0.2753107185305 0.4777515790154) + POINT (0.3006175055762 0.4777515790154) + POINT (0.3259242926219 0.4777515790154) + POINT (0.3512310796676 0.4777515790154) + POINT (0.3765378667134 0.4777515790154) + POINT (0.4018446537591 0.4777515790154) + POINT (0.4271514408048 0.4777515790154) + POINT (0.4524582278505 0.4777515790154) + POINT (0.4777650148962 0.4777515790154) +Test 3, test for too thin +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.5000000000000000, 0.0125000000000000 0.5000000000000000, 0.0125000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000))) +Test with subgrid +Object = AutoSeed + Group = PolygonSeederAlgorithm + Name = Grid + MinimumThickness = 0.3 + MinimumArea = 10 + XSpacing = 1500 + YSpacing = 1500 + SubGrid = 1 + End_Group +End_Object +End + +Test to make sure Parse did it's job +MinimumThickness = 0.3 +MinimumArea = 10 +SubGrid = 1 +Test 2, test a square polygon +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.5000000000000000, 0.5000000000000000 0.5000000000000000, 0.5000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000))) + POINT (0.02224207650506 0.02224524784625) + POINT (0.04754798569954 0.02224524784625) + POINT (0.07285389489402 0.02224524784625) + POINT (0.09815980408851 0.02224524784625) + POINT (0.123465713283 0.02224524784625) + POINT (0.1487716224775 0.02224524784625) + POINT (0.174077531672 0.02224524784625) + POINT (0.1993834408664 0.02224524784625) + POINT (0.2246893500609 0.02224524784625) + POINT (0.2499952592554 0.02224524784625) + POINT (0.2753011684499 0.02224524784625) + POINT (0.3006070776444 0.02224524784625) + POINT (0.3259129868388 0.02224524784625) + POINT (0.3512188960333 0.02224524784625) + POINT (0.3765248052278 0.02224524784625) + POINT (0.4018307144223 0.02224524784625) + POINT (0.4271366236168 0.02224524784625) + POINT (0.4524425328113 0.02224524784625) + POINT (0.4777484420057 0.02224524784625) + POINT (0.02224208248856 0.04755115513342) + POINT (0.04754799849076 0.04755115513342) + POINT (0.07285391449296 0.04755115513342) + POINT (0.09815983049517 0.04755115513342) + POINT (0.1234657464974 0.04755115513342) + POINT (0.1487716624996 0.04755115513342) + POINT (0.1740775785018 0.04755115513342) + POINT (0.199383494504 0.04755115513342) + POINT (0.2246894105062 0.04755115513342) + POINT (0.2499953265084 0.04755115513342) + POINT (0.2753012425106 0.04755115513342) + POINT (0.3006071585128 0.04755115513342) + POINT (0.325913074515 0.04755115513342) + POINT (0.3512189905172 0.04755115513342) + POINT (0.3765249065194 0.04755115513342) + POINT (0.4018308225216 0.04755115513342) + POINT (0.4271367385238 0.04755115513342) + POINT (0.452442654526 0.04755115513342) + POINT (0.4777485705282 0.04755115513342) + POINT (0.02224209281091 0.07285706242059) + POINT (0.04754802055735 0.07285706242059) + POINT (0.0728539483038 0.07285706242059) + POINT (0.09815987605025 0.07285706242059) + POINT (0.1234658037967 0.07285706242059) + POINT (0.1487717315431 0.07285706242059) + POINT (0.1740776592896 0.07285706242059) + POINT (0.199383587036 0.07285706242059) + POINT (0.2246895147825 0.07285706242059) + POINT (0.2499954425289 0.07285706242059) + POINT (0.2753013702754 0.07285706242059) + POINT (0.3006072980218 0.07285706242059) + POINT (0.3259132257683 0.07285706242059) + POINT (0.3512191535147 0.07285706242059) + POINT (0.3765250812612 0.07285706242059) + POINT (0.4018310090076 0.07285706242059) + POINT (0.4271369367541 0.07285706242059) + POINT (0.4524428645005 0.07285706242059) + POINT (0.477748792247 0.07285706242059) + POINT (0.02224210747211 0.09816296970776) + POINT (0.04754805189934 0.09816296970776) + POINT (0.07285399632657 0.09816296970776) + POINT (0.0981599407538 0.09816296970776) + POINT (0.123465885181 0.09816296970776) + POINT (0.1487718296083 0.09816296970776) + POINT (0.1740777740355 0.09816296970776) + POINT (0.1993837184627 0.09816296970776) + POINT (0.2246896628899 0.09816296970776) + POINT (0.2499956073172 0.09816296970776) + POINT (0.2753015517444 0.09816296970776) + POINT (0.3006074961716 0.09816296970776) + POINT (0.3259134405989 0.09816296970776) + POINT (0.3512193850261 0.09816296970776) + POINT (0.3765253294533 0.09816296970776) + POINT (0.4018312738806 0.09816296970776) + POINT (0.4271372183078 0.09816296970776) + POINT (0.452443162735 0.09816296970776) + POINT (0.4777491071622 0.09816296970776) + POINT (0.0222421264722 0.1234688769949) + POINT (0.04754809251676 0.1234688769949) + POINT (0.07285405856132 0.1234688769949) + POINT (0.09816002460588 0.1234688769949) + POINT (0.1234659906504 0.1234688769949) + POINT (0.148771956695 0.1234688769949) + POINT (0.1740779227396 0.1234688769949) + POINT (0.1993838887841 0.1234688769949) + POINT (0.2246898548287 0.1234688769949) + POINT (0.2499958208733 0.1234688769949) + POINT (0.2753017869178 0.1234688769949) + POINT (0.3006077529624 0.1234688769949) + POINT (0.3259137190069 0.1234688769949) + POINT (0.3512196850515 0.1234688769949) + POINT (0.3765256510961 0.1234688769949) + POINT (0.4018316171406 0.1234688769949) + POINT (0.4271375831852 0.1234688769949) + POINT (0.4524435492297 0.1234688769949) + POINT (0.4777495152743 0.1234688769949) + POINT (0.02224214981117 0.1487747842821) + POINT (0.04754814240964 0.1487747842821) + POINT (0.07285413500811 0.1487747842821) + POINT (0.09816012760657 0.1487747842821) + POINT (0.123466120205 0.1487747842821) + POINT (0.1487721128035 0.1487747842821) + POINT (0.174078105402 0.1487747842821) + POINT (0.1993840980004 0.1487747842821) + POINT (0.2246900905989 0.1487747842821) + POINT (0.2499960831974 0.1487747842821) + POINT (0.2753020757958 0.1487747842821) + POINT (0.3006080683943 0.1487747842821) + POINT (0.3259140609928 0.1487747842821) + POINT (0.3512200535912 0.1487747842821) + POINT (0.3765260461897 0.1487747842821) + POINT (0.4018320387882 0.1487747842821) + POINT (0.4271380313866 0.1487747842821) + POINT (0.4524440239851 0.1487747842821) + POINT (0.4777500165836 0.1487747842821) + POINT (0.02224217748906 0.1740806915693) + POINT (0.04754820157803 0.1740806915693) + POINT (0.07285422566701 0.1740806915693) + POINT (0.09816024975598 0.1740806915693) + POINT (0.1234662738449 0.1740806915693) + POINT (0.1487722979339 0.1740806915693) + POINT (0.1740783220229 0.1740806915693) + POINT (0.1993843461119 0.1740806915693) + POINT (0.2246903702008 0.1740806915693) + POINT (0.2499963942898 0.1740806915693) + POINT (0.2753024183788 0.1740806915693) + POINT (0.3006084424677 0.1740806915693) + POINT (0.3259144665567 0.1740806915693) + POINT (0.3512204906457 0.1740806915693) + POINT (0.3765265147347 0.1740806915693) + POINT (0.4018325388236 0.1740806915693) + POINT (0.4271385629126 0.1740806915693) + POINT (0.4524445870016 0.1740806915693) + POINT (0.4777506110905 0.1740806915693) + POINT (0.0222422095059 0.1993865988565) + POINT (0.047548270022 0.1993865988565) + POINT (0.07285433053811 0.1993865988565) + POINT (0.09816039105421 0.1993865988565) + POINT (0.1234664515703 0.1993865988565) + POINT (0.1487725120864 0.1993865988565) + POINT (0.1740785726025 0.1993865988565) + POINT (0.1993846331186 0.1993865988565) + POINT (0.2246906936347 0.1993865988565) + POINT (0.2499967541508 0.1993865988565) + POINT (0.2753028146669 0.1993865988565) + POINT (0.300608875183 0.1993865988565) + POINT (0.3259149356992 0.1993865988565) + POINT (0.3512209962153 0.1993865988565) + POINT (0.3765270567314 0.1993865988565) + POINT (0.4018331172475 0.1993865988565) + POINT (0.4271391777636 0.1993865988565) + POINT (0.4524452382797 0.1993865988565) + POINT (0.4777512987958 0.1993865988565) + POINT (0.0222422458617 0.2246925061436) + POINT (0.04754834774161 0.2246925061436) + POINT (0.07285444962151 0.2246925061436) + POINT (0.09816055150141 0.2246925061436) + POINT (0.1234666533813 0.2246925061436) + POINT (0.1487727552612 0.2246925061436) + POINT (0.1740788571411 0.2246925061436) + POINT (0.199384959021 0.2246925061436) + POINT (0.2246910609009 0.2246925061436) + POINT (0.2499971627808 0.2246925061436) + POINT (0.2753032646607 0.2246925061436) + POINT (0.3006093665406 0.2246925061436) + POINT (0.3259154684205 0.2246925061436) + POINT (0.3512215703004 0.2246925061436) + POINT (0.3765276721803 0.2246925061436) + POINT (0.4018337740603 0.2246925061436) + POINT (0.4271398759402 0.2246925061436) + POINT (0.4524459778201 0.2246925061436) + POINT (0.4777520797 0.2246925061436) + POINT (0.02224228655652 0.2499984134308) + POINT (0.04754843473693 0.2499984134308) + POINT (0.07285458291734 0.2499984134308) + POINT (0.09816073109774 0.2499984134308) + POINT (0.1234668792781 0.2499984134308) + POINT (0.1487730274586 0.2499984134308) + POINT (0.174079175639 0.2499984134308) + POINT (0.1993853238194 0.2499984134308) + POINT (0.2246914719998 0.2499984134308) + POINT (0.2499976201802 0.2499984134308) + POINT (0.2753037683606 0.2499984134308) + POINT (0.300609916541 0.2499984134308) + POINT (0.3259160647214 0.2499984134308) + POINT (0.3512222129018 0.2499984134308) + POINT (0.3765283610822 0.2499984134308) + POINT (0.4018345092626 0.2499984134308) + POINT (0.427140657443 0.2499984134308) + POINT (0.4524468056234 0.2499984134308) + POINT (0.4777529538038 0.2499984134308) + POINT (0.02224233159039 0.275304320718) + POINT (0.04754853100805 0.275304320718) + POINT (0.07285473042571 0.275304320718) + POINT (0.09816092984337 0.275304320718) + POINT (0.123467129261 0.275304320718) + POINT (0.1487733286787 0.275304320718) + POINT (0.1740795280964 0.275304320718) + POINT (0.199385727514 0.275304320718) + POINT (0.2246919269317 0.275304320718) + POINT (0.2499981263493 0.275304320718) + POINT (0.275304325767 0.275304320718) + POINT (0.3006105251847 0.275304320718) + POINT (0.3259167246023 0.275304320718) + POINT (0.35122292402 0.275304320718) + POINT (0.3765291234376 0.275304320718) + POINT (0.4018353228553 0.275304320718) + POINT (0.427141522273 0.275304320718) + POINT (0.4524477216906 0.275304320718) + POINT (0.4777539211083 0.275304320718) + POINT (0.02224238096335 0.3006102280051) + POINT (0.04754863655506 0.3006102280051) + POINT (0.07285489214678 0.3006102280051) + POINT (0.0981611477385 0.3006102280051) + POINT (0.1234674033302 0.3006102280051) + POINT (0.1487736589219 0.3006102280051) + POINT (0.1740799145136 0.3006102280051) + POINT (0.1993861701054 0.3006102280051) + POINT (0.2246924256971 0.3006102280051) + POINT (0.2499986812888 0.3006102280051) + POINT (0.2753049368805 0.3006102280051) + POINT (0.3006111924722 0.3006102280051) + POINT (0.3259174480639 0.3006102280051) + POINT (0.3512237036557 0.3006102280051) + POINT (0.3765299592474 0.3006102280051) + POINT (0.4018362148391 0.3006102280051) + POINT (0.4271424704308 0.3006102280051) + POINT (0.4524487260225 0.3006102280051) + POINT (0.4777549816142 0.3006102280051) + POINT (0.02224243467545 0.3259161352923) + POINT (0.04754875137807 0.3259161352923) + POINT (0.0728550680807 0.3259161352923) + POINT (0.09816138478333 0.3259161352923) + POINT (0.123467701486 0.3259161352923) + POINT (0.1487740181886 0.3259161352923) + POINT (0.1740803348912 0.3259161352923) + POINT (0.1993866515938 0.3259161352923) + POINT (0.2246929682965 0.3259161352923) + POINT (0.2499992849991 0.3259161352923) + POINT (0.2753056017017 0.3259161352923) + POINT (0.3006119184043 0.3259161352923) + POINT (0.325918235107 0.3259161352923) + POINT (0.3512245518096 0.3259161352923) + POINT (0.3765308685122 0.3259161352923) + POINT (0.4018371852148 0.3259161352923) + POINT (0.4271435019175 0.3259161352923) + POINT (0.4524498186201 0.3259161352923) + POINT (0.4777561353227 0.3259161352923) + POINT (0.02224249272674 0.3512220425795) + POINT (0.04754887547719 0.3512220425795) + POINT (0.07285525822764 0.3512220425795) + POINT (0.09816164097809 0.3512220425795) + POINT (0.1234680237285 0.3512220425795) + POINT (0.148774406479 0.3512220425795) + POINT (0.1740807892294 0.3512220425795) + POINT (0.1993871719799 0.3512220425795) + POINT (0.2246935547304 0.3512220425795) + POINT (0.2499999374808 0.3512220425795) + POINT (0.2753063202313 0.3512220425795) + POINT (0.3006127029817 0.3512220425795) + POINT (0.3259190857322 0.3512220425795) + POINT (0.3512254684826 0.3512220425795) + POINT (0.3765318512331 0.3512220425795) + POINT (0.4018382339835 0.3512220425795) + POINT (0.427144616734 0.3512220425795) + POINT (0.4524509994844 0.3512220425795) + POINT (0.4777573822349 0.3512220425795) + POINT (0.02224255511729 0.3765279498667) + POINT (0.04754900885254 0.3765279498667) + POINT (0.0728554625878 0.3765279498667) + POINT (0.09816191632305 0.3765279498667) + POINT (0.1234683700583 0.3765279498667) + POINT (0.1487748237936 0.3765279498667) + POINT (0.1740812775288 0.3765279498667) + POINT (0.1993877312641 0.3765279498667) + POINT (0.2246941849993 0.3765279498667) + POINT (0.2500006387346 0.3765279498667) + POINT (0.2753070924698 0.3765279498667) + POINT (0.3006135462051 0.3765279498667) + POINT (0.3259199999403 0.3765279498667) + POINT (0.3512264536756 0.3765279498667) + POINT (0.3765329074109 0.3765279498667) + POINT (0.4018393611461 0.3765279498667) + POINT (0.4271458148814 0.3765279498667) + POINT (0.4524522686166 0.3765279498667) + POINT (0.4777587223519 0.3765279498667) + POINT (0.02224262184714 0.4018338571538) + POINT (0.04754915150425 0.4018338571538) + POINT (0.07285568116136 0.4018338571538) + POINT (0.09816221081847 0.4018338571538) + POINT (0.1234687404756 0.4018338571538) + POINT (0.1487752701327 0.4018338571538) + POINT (0.1740817997898 0.4018338571538) + POINT (0.1993883294469 0.4018338571538) + POINT (0.224694859104 0.4018338571538) + POINT (0.2500013887611 0.4018338571538) + POINT (0.2753079184182 0.4018338571538) + POINT (0.3006144480753 0.4018338571538) + POINT (0.3259209777324 0.4018338571538) + POINT (0.3512275073895 0.4018338571538) + POINT (0.3765340370467 0.4018338571538) + POINT (0.4018405667038 0.4018338571538) + POINT (0.4271470963609 0.4018338571538) + POINT (0.452453626018 0.4018338571538) + POINT (0.4777601556751 0.4018338571538) + POINT (0.02224269291637 0.427139764441) + POINT (0.04754930343246 0.427139764441) + POINT (0.07285591394854 0.427139764441) + POINT (0.09816252446462 0.427139764441) + POINT (0.1234691349807 0.427139764441) + POINT (0.1487757454968 0.427139764441) + POINT (0.1740823560129 0.427139764441) + POINT (0.199388966529 0.427139764441) + POINT (0.224695577045 0.427139764441) + POINT (0.2500021875611 0.427139764441) + POINT (0.2753087980772 0.427139764441) + POINT (0.3006154085933 0.427139764441) + POINT (0.3259220191094 0.427139764441) + POINT (0.3512286296255 0.427139764441) + POINT (0.3765352401415 0.427139764441) + POINT (0.4018418506576 0.427139764441) + POINT (0.4271484611737 0.427139764441) + POINT (0.4524550716898 0.427139764441) + POINT (0.4777616822059 0.427139764441) + POINT (0.02224276832505 0.4524456717282) + POINT (0.04754946463731 0.4524456717282) + POINT (0.07285616094957 0.4524456717282) + POINT (0.09816285726183 0.4524456717282) + POINT (0.1234695535741 0.4524456717282) + POINT (0.1487762498864 0.4524456717282) + POINT (0.1740829461986 0.4524456717282) + POINT (0.1993896425109 0.4524456717282) + POINT (0.2246963388231 0.4524456717282) + POINT (0.2500030351354 0.4524456717282) + POINT (0.2753097314477 0.4524456717282) + POINT (0.3006164277599 0.4524456717282) + POINT (0.3259231240722 0.4524456717282) + POINT (0.3512298203844 0.4524456717282) + POINT (0.3765365166967 0.4524456717282) + POINT (0.401843213009 0.4524456717282) + POINT (0.4271499093212 0.4524456717282) + POINT (0.4524566056335 0.4524456717282) + POINT (0.4777633019457 0.4524456717282) + POINT (0.02224284807325 0.4777515790154) + POINT (0.04754963511897 0.4777515790154) + POINT (0.07285642216469 0.4777515790154) + POINT (0.09816320921041 0.4777515790154) + POINT (0.1234699962561 0.4777515790154) + POINT (0.1487767833019 0.4777515790154) + POINT (0.1740835703476 0.4777515790154) + POINT (0.1993903573933 0.4777515790154) + POINT (0.224697144439 0.4777515790154) + POINT (0.2500039314847 0.4777515790154) + POINT (0.2753107185305 0.4777515790154) + POINT (0.3006175055762 0.4777515790154) + POINT (0.3259242926219 0.4777515790154) + POINT (0.3512310796676 0.4777515790154) + POINT (0.3765378667134 0.4777515790154) + POINT (0.4018446537591 0.4777515790154) + POINT (0.4271514408048 0.4777515790154) + POINT (0.4524582278505 0.4777515790154) + POINT (0.4777650148962 0.4777515790154) + POINT (0.003262644363297 0.0001025789699696) + POINT (0.0159155980069 0.0001025789699696) + POINT (0.04122150529412 0.0001025789699696) + POINT (0.06652741258133 0.0001025789699696) + POINT (0.09183331986854 0.0001025789699696) + POINT (0.1171392271558 0.0001025789699696) + POINT (0.142445134443 0.0001025789699696) + POINT (0.1677510417302 0.0001025789699696) + POINT (0.1930569490174 0.0001025789699696) + POINT (0.2183628563046 0.0001025789699696) + POINT (0.2436687635918 0.0001025789699696) + POINT (0.268974670879 0.0001025789699696) + POINT (0.2942805781663 0.0001025789699696) + POINT (0.3195864854535 0.0001025789699696) + POINT (0.3448923927407 0.0001025789699696) + POINT (0.3701983000279 0.0001025789699696) + POINT (0.3955042073151 0.0001025789699696) + POINT (0.4208101146023 0.0001025789699696) + POINT (0.4461160218895 0.0001025789699696) + POINT (0.4714219291767 0.0001025789699696) + POINT (0.496727836464 0.0001025789699696) + POINT (9.940595623227e-05 0.01591877102445) + POINT (0.4998910941679 0.01591877102445) + POINT (9.940597812629e-05 0.04122467831163) + POINT (0.4998912042682 0.04122467831163) + POINT (9.940601941182e-05 0.0665305855988) + POINT (0.4998914118843 0.0665305855988) + POINT (9.94060800889e-05 0.09183649288597) + POINT (0.4998917170162 0.09183649288597) + POINT (9.940616015759e-05 0.1171424001731) + POINT (0.4998921196643 0.1171424001731) + POINT (9.940625961795e-05 0.1424483074603) + POINT (0.499892619829 0.1424483074603) + POINT (9.94063784701e-05 0.1677542147475) + POINT (0.4998932175108 0.1677542147475) + POINT (9.940651671415e-05 0.1930601220347) + POINT (0.4998939127103 0.1930601220347) + POINT (9.940667435022e-05 0.2183660293218) + POINT (0.4998947054281 0.2183660293218) + POINT (9.940685137849e-05 0.243671936609) + POINT (0.499895595665 0.243671936609) + POINT (9.940704779911e-05 0.2689778438962) + POINT (0.4998965834219 0.2689778438962) + POINT (9.940726361228e-05 0.2942837511834) + POINT (0.4998976686998 0.2942837511834) + POINT (9.940749881821e-05 0.3195896584705) + POINT (0.4998988514996 0.3195896584705) + POINT (9.940775341713e-05 0.3448955657577) + POINT (0.4999001318226 0.3448955657577) + POINT (9.940802740929e-05 0.3702014730449) + POINT (0.49990150967 0.3702014730449) + POINT (9.940832079495e-05 0.395507380332) + POINT (0.4999029850432 0.395507380332) + POINT (9.940863357441e-05 0.4208132876192) + POINT (0.4999045579436 0.4208132876192) + POINT (9.940896574796e-05 0.4461191949064) + POINT (0.4999062283726 0.4461191949064) + POINT (9.940931731593e-05 0.4714251021936) + POINT (0.4999079963321 0.4714251021936) + POINT (9.940968827867e-05 0.4967310094807) + POINT (0.01907955344025 0.4967310094807) + POINT (0.04438641177622 0.4967310094807) + POINT (0.06969327011218 0.4967310094807) + POINT (0.09500012844815 0.4967310094807) + POINT (0.1203069867841 0.4967310094807) + POINT (0.1456138451201 0.4967310094807) + POINT (0.170920703456 0.4967310094807) + POINT (0.196227561792 0.4967310094807) + POINT (0.221534420128 0.4967310094807) + POINT (0.2468412784639 0.4967310094807) + POINT (0.2721481367999 0.4967310094807) + POINT (0.2974549951359 0.4967310094807) + POINT (0.3227618534718 0.4967310094807) + POINT (0.3480687118078 0.4967310094807) + POINT (0.3733755701438 0.4967310094807) + POINT (0.3986824284797 0.4967310094807) + POINT (0.4239892868157 0.4967310094807) + POINT (0.4492961451517 0.4967310094807) + POINT (0.4746030034876 0.4967310094807) + POINT (0.4999098618236 0.4967310094807) +Test 3, test for too thin +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.5000000000000000, 0.0125000000000000 0.5000000000000000, 0.0125000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000))) diff --git a/isis/src/base/objs/GridPolygonSeeder/Makefile b/isis/src/base/objs/GridPolygonSeeder/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e6958e111551dea7647d5537c94c48e17a5bf3ec --- /dev/null +++ b/isis/src/base/objs/GridPolygonSeeder/Makefile @@ -0,0 +1,5 @@ +INCS = GridPolygonSeeder.h +SRCS = GridPolygonSeeder.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/GridPolygonSeeder/PolygonSeeder.plugin b/isis/src/base/objs/GridPolygonSeeder/PolygonSeeder.plugin new file mode 100644 index 0000000000000000000000000000000000000000..8e7b580b77108090bb85f7f8c084ef681be2fb0c --- /dev/null +++ b/isis/src/base/objs/GridPolygonSeeder/PolygonSeeder.plugin @@ -0,0 +1,4 @@ +Group = Grid + Library = GridPolygonSeeder + Routine = GridPolygonSeederPlugin +End_Group diff --git a/isis/src/base/objs/GridPolygonSeeder/unitTest.cpp b/isis/src/base/objs/GridPolygonSeeder/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ddfa8ea55870d7b9ec7f7bb7c4d327054720722 --- /dev/null +++ b/isis/src/base/objs/GridPolygonSeeder/unitTest.cpp @@ -0,0 +1,176 @@ +#include +#include +#include +#include + +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/geom/Geometry.h" +#include "geos/geom/Polygon.h" + +#include "iException.h" +#include "PolygonTools.h" +#include "PolygonSeeder.h" +#include "PolygonSeederFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "ProjectionFactory.h" +#include "GridPolygonSeeder.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + try { + cout << "Test 1, create a seeder" << endl; + + PvlGroup alg("PolygonSeederAlgorithm"); + + do { + if(!alg.HasKeyword("Name")) { + cout << "Test without subgrid" << endl; + alg += PvlKeyword("Name","Grid"); + alg += PvlKeyword("MinimumThickness", 0.3); + alg += PvlKeyword("MinimumArea", 10); + alg += PvlKeyword("XSpacing", 1500); + alg += PvlKeyword("YSpacing", 1500); + } + else { + cout << "Test with subgrid" << endl; + alg += PvlKeyword("SubGrid", true); + } + + PvlObject o("AutoSeed"); + o.AddGroup(alg); + + Pvl pvl; + pvl.AddObject(o); + cout << pvl << endl << endl; + + PolygonSeeder *ps = PolygonSeederFactory::Create(pvl); + + std::cout << "Test to make sure Parse did it's job" << std::endl; + std::cout << "MinimumThickness = " << ps->MinimumThickness() << std::endl; + std::cout << "MinimumArea = " << ps->MinimumArea() << std::endl; + std::cout << "SubGrid = " << ((GridPolygonSeeder*)ps)->SubGrid() << std::endl; + // std::cout << "Spaceing = " << ((GridPolygonSeeder*)ps)->Spacing() << std::endl; + + + cout << "Test 2, test a square polygon" << endl; + try { + // Call the seed member with a polygon + geos::geom::CoordinateSequence *pts; + vector polys; + + // Create the A polygon + pts = new geos::geom::CoordinateArraySequence (); + pts->add (geos::geom::Coordinate (0, 0)); + pts->add (geos::geom::Coordinate (0, 0.5)); + pts->add (geos::geom::Coordinate (0.5, 0.5)); + pts->add (geos::geom::Coordinate (0.5, 0)); + pts->add (geos::geom::Coordinate (0, 0)); + + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing(pts),NULL)); + + geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon (polys); + + cout << "Lon/Lat polygon = " << mp->toString() << endl; + // Create the projection necessary for seeding + PvlGroup radii = Projection::TargetRadii("MARS"); + Isis::Pvl maplab; + maplab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = maplab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",(string)radii["EquatorialRadius"]); + mapGroup += Isis::PvlKeyword("PolarRadius",(string)radii["PolarRadius"]); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetocentric"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",360); + mapGroup += Isis::PvlKeyword("CenterLatitude",0); + mapGroup += Isis::PvlKeyword("CenterLongitude",0); + mapGroup += Isis::PvlKeyword("ProjectionName","Sinusoidal"); + + Projection *proj = Isis::ProjectionFactory::Create(maplab); + + geos::geom::MultiPolygon *xymp = PolygonTools::LatLonToXY(*mp, proj); + vector seedValues = ps->Seed(xymp); + + vector points; + for( unsigned int pt = 0; pt < seedValues.size(); pt ++) { + if (proj->SetCoordinate(seedValues[pt]->getX(),seedValues[pt]->getY())) { + points.push_back(Isis::globalFactory.createPoint( + geos::geom::Coordinate(proj->UniversalLongitude(), + proj->UniversalLatitude()))); + } + else { + iString msg = "Unable to convert to a (lon,lat)"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + cout << setprecision(13); + for (unsigned int i=0; igetX() << " " << points[i]->getY() << ")" << endl; + } + } + catch (iException &e) { + e.Report(); + } + + cout << "Test 3, test for too thin" << endl; + try { + // Call the seed member with a polygon + geos::geom::CoordinateSequence *pts; + vector polys; + + // Create the A polygon + pts = new geos::geom::CoordinateArraySequence (); + pts->add (geos::geom::Coordinate (0, 0)); + pts->add (geos::geom::Coordinate (0, 0.5)); + pts->add (geos::geom::Coordinate (0.0125, 0.5)); + pts->add (geos::geom::Coordinate (0.0125, 0)); + pts->add (geos::geom::Coordinate (0, 0)); + + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing(pts),NULL)); + + geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon (polys); + + cout << "Lon/Lat polygon = " << mp->toString() << endl; + + // Create the projection necessary for seeding + PvlGroup radii = Projection::TargetRadii("MARS"); + Isis::Pvl maplab; + maplab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = maplab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",(string)radii["EquatorialRadius"]); + mapGroup += Isis::PvlKeyword("PolarRadius",(string)radii["PolarRadius"]); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetocentric"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",360); + mapGroup += Isis::PvlKeyword("CenterLatitude",0); + mapGroup += Isis::PvlKeyword("CenterLongitude",0); + mapGroup += Isis::PvlKeyword("ProjectionName","Sinusoidal"); + Projection *proj = Isis::ProjectionFactory::Create(maplab); + + // NOTHING SHOULD BE PRINTED (the thickness test should not have been met) + geos::geom::MultiPolygon *xymp = PolygonTools::LatLonToXY(*mp, proj); + vector seedValues = ps->Seed(xymp); + for (unsigned int i=0; i + +#include "ProjectionFactory.h" +#include "UniversalGroundMap.h" +#include "Camera.h" +#include "Projection.h" +#include "Progress.h" + +using namespace std; + +namespace Isis { + /** + * This method initializes the class by allocating the grid, + * calculating the lat/lon range, and getting a default grid + * resolution. + * + * @param gmap A universal ground map to use for calculating the grid + * @param splitLatLon Make two grids: one for latitude lines and + * one for longitude lines + * @param width The width of the grid; often cube samples + * @param height The height of the grid; often cube samples + */ + GroundGrid::GroundGrid(UniversalGroundMap *gmap, bool splitLatLon, + unsigned int width, unsigned int height) { + p_width = width; + p_height = height; + + // Initialize our grid pointer to null + p_grid = 0; + p_latLinesGrid = 0; + p_lonLinesGrid = 0; + + // Now let's figure out how big the grid needs to be, then allocate and + // initialize + p_gridSize = (unsigned long)(ceil(width * height / 8.0) + 0.5); + + if(!splitLatLon) { + p_grid = new char[p_gridSize]; + } + else { + p_latLinesGrid = new char[p_gridSize]; + p_lonLinesGrid = new char[p_gridSize]; + } + + for(unsigned long i = 0; i < p_gridSize; i++) { + if(p_grid) p_grid[i] = 0; + if(p_latLinesGrid) p_latLinesGrid[i] = 0; + if(p_lonLinesGrid) p_lonLinesGrid[i] = 0; + } + + // The first call of CreateGrid doesn't have to reinitialize + p_reinitialize = false; + + p_groundMap = gmap; + + // We need a lat/lon range for gridding, use the mapping group + // (in case of camera, use BasicMapping) + p_minLat = 0.0; + p_minLon = 0.0; + p_maxLat = 0.0; + p_maxLon = 0.0; + + PvlGroup mapping; + + if(p_groundMap->Camera()) { + Pvl tmp; + p_groundMap->Camera()->BasicMapping(tmp); + mapping = tmp.FindGroup("Mapping"); + } + else { + mapping = p_groundMap->Projection()->Mapping(); + } + + p_minLat = mapping["MinimumLatitude"]; + p_maxLat = mapping["MaximumLatitude"]; + p_minLon = mapping["MinimumLongitude"]; + p_maxLon = mapping["MaximumLongitude"]; + + double radius1 = mapping["EquatorialRadius"]; + double radius2 = mapping["PolarRadius"]; + + double largerRadius = max(radius1, radius2); + + // p_defaultResolution is in degrees/pixel + + if(p_groundMap->HasCamera()) { + p_defaultResolution = + (p_groundMap->Camera()->HighestImageResolution() / largerRadius) * 10; + } + else { + p_defaultResolution = (p_groundMap->Resolution() / largerRadius) * 10; + } + + if(p_defaultResolution < 0) { + p_defaultResolution = 10.0 / largerRadius; + } + } + + /** + * Delete the object + */ + GroundGrid::~GroundGrid() { + if(p_grid) { + delete [] p_grid; + p_grid = NULL; + } + + if(p_latLinesGrid) { + delete [] p_latLinesGrid; + p_latLinesGrid = NULL; + } + + if(p_lonLinesGrid) { + delete [] p_lonLinesGrid; + p_lonLinesGrid = NULL; + } + } + + + /** + * This method draws the grid internally. It is not valid to call PixelOnGrid + * until this method has been called. + * + * @param baseLat Latitude to hit in the grid + * @param baseLon Longitude to hit in the grid + * @param latInc Distance between latitude lines + * @param lonInc Distance between longitude lines + * @param progress If passed in, this progress will be used + * @param latRes Resolution of latitude lines (in degrees/pixel) + * @param lonRes Resolution of longitude lines (in degrees/pixel) + */ + void GroundGrid::CreateGrid(double baseLat, double baseLon, + double latInc, double lonInc, + Progress *progress, + double latRes, double lonRes) { + if(p_groundMap == NULL || + (p_grid == NULL && p_latLinesGrid == NULL && p_lonLinesGrid == NULL)) { + iString msg = "GroundGrid::CreateGrid missing ground map or grid array"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + if(p_reinitialize) { + for(unsigned long i = 0; i < p_gridSize; i++) { + if(p_grid) p_grid[i] = 0; + if(p_latLinesGrid) p_latLinesGrid[i] = 0; + if(p_lonLinesGrid) p_lonLinesGrid[i] = 0; + } + } + + // subsequent calls to this method must always reinitialize the grid + p_reinitialize = true; + + // Find starting points for lat/lon + double startLat = baseLat - floor((baseLat - p_minLat) / latInc) * latInc; + double startLon = baseLon - floor((baseLat - p_minLon) / lonInc) * lonInc; + + if(latRes == 0.0) { + latRes = p_defaultResolution; + } + + if(lonRes == 0.0) { + lonRes = p_defaultResolution; + } + + double endLat = (long)((p_maxLat - startLat) / latInc) * latInc + startLat; + double endLon = (long)((p_maxLon - startLon) / lonInc) * lonInc + startLon; + + if(progress) { + double numSteps = (endLat - startLat) / latInc + 1; + numSteps += (endLon - startLon) / lonInc + 1; + + if(numSteps <= 0) { + iString msg = "No gridlines would intersect the image"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + progress->SetMaximumSteps((long)(numSteps + 0.5)); + progress->CheckStatus(); + } + + for(double lat = startLat; lat <= endLat; lat += latInc) { + unsigned int previousX = 0; + unsigned int previousY = 0; + bool havePrevious = false; + + for(double lon = startLon; lon <= p_maxLon; lon += latRes) { + unsigned int x = 0; + unsigned int y = 0; + bool valid = GetXY(lat, lon, x, y); + + if(valid && havePrevious) { + if(previousX == x && previousY == y) { + continue; + } + + DrawLineOnGrid(previousX, previousY, x, y, true); + } + + havePrevious = valid; + previousX = x; + previousY = y; + } + + if(progress) { + progress->CheckStatus(); + } + } + + for(double lon = startLon; lon <= endLon; lon += lonInc) { + unsigned int previousX = 0; + unsigned int previousY = 0; + bool havePrevious = false; + + for(double lat = startLat; lat <= p_maxLat; lat += lonRes) { + unsigned int x = 0; + unsigned int y = 0; + + bool valid = GetXY(lat, lon, x, y); + + if(valid && havePrevious) { + if(previousX == x && previousY == y) { + continue; + } + + DrawLineOnGrid(previousX, previousY, x, y, false); + } + + havePrevious = valid; + previousX = x; + previousY = y; + } + + if(progress) { + progress->CheckStatus(); + } + } + } + + + /** + * Returns true if the grid is on this point. Using this method + * is recommended if lat/lon grids are separate. + * + * @param x X-Coordinate of grid (0-based) + * @param y Y-Coordinate of grid (0-based) + * @param latGrid True for latitude lines, false for longitude + * lines + * + * @return bool Pixel lies on grid + */ + bool GroundGrid::PixelOnGrid(int x, int y, bool latGrid) { + if(x < 0) return false; + if(y < 0) return false; + + if(x >= (int)p_width) return false; + if(y >= (int)p_height) return false; + + return GetGridBit(x, y, latGrid); + } + + + /** + * Returns true if the grid is on this point. + * + * @param x X-Coordinate of grid (0-based) + * @param y Y-Coordinate of grid (0-based) + * + * @return bool Pixel lies on grid + */ + bool GroundGrid::PixelOnGrid(int x, int y) { + if(x < 0) return false; + if(y < 0) return false; + + if(x >= (int)p_width) return false; + if(y >= (int)p_height) return false; + + return GetGridBit(x, y, true); // third argument shouldnt matter + } + + + /** + * This method converts a lat/lon to an X/Y. This implementation converts to + * sample/line. + * + * @param lat Latitude of Lat/Lon pair to convert to S/L + * @param lon Longitude of Lat/Lon pair to convert to S/L + * @param x Output sample (0-based) + * @param y Output line (0-based) + * + * @return bool Successful + */ + bool GroundGrid::GetXY(double lat, double lon, + unsigned int &x, unsigned int &y) { + if(!GroundMap()) return false; + + if(!GroundMap()->SetUniversalGround(lat, lon)) return false; + x = (int)(p_groundMap->Sample() - 0.5); + y = (int)(p_groundMap->Line() - 0.5); + + return true; + } + + + /** + * This flags a bit as on the grid lines. + * + * @param x X-Coordinate (0-based) + * @param y Y-Coordinate (0-based) + * @param latGrid True if this is derived from a latitude line + */ + void GroundGrid::SetGridBit(unsigned int x, unsigned int y, bool latGrid) { + unsigned long bitPosition = (y * p_width) + x; + unsigned long byteContainer = bitPosition / 8; + unsigned int bitOffset = bitPosition % 8; + + if(byteContainer < 0 || byteContainer > p_gridSize) return; + + if(p_grid) { + char &importantByte = p_grid[byteContainer]; + importantByte |= (1 << bitOffset); + } + else if(latGrid && p_latLinesGrid) { + char &importantByte = p_latLinesGrid[byteContainer]; + importantByte |= (1 << bitOffset); + } + else if(!latGrid && p_lonLinesGrid) { + char &importantByte = p_lonLinesGrid[byteContainer]; + importantByte |= (1 << bitOffset); + } + else { + iString msg = "GroundGrid::SetGridBit no grids available"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + /** + * Returns true if the specified coordinate is on the grid lines. + * + * @param x X-Coordinate (0-based) + * @param y Y-Coordinate (0-based) + * + * @return bool Value at grid coordinate + */ + bool GroundGrid::GetGridBit(unsigned int x, unsigned int y, bool latGrid) { + unsigned long bitPosition = (y * p_width) + x; + unsigned long byteContainer = bitPosition / 8; + unsigned int bitOffset = bitPosition % 8; + + if(byteContainer < 0 || byteContainer > p_gridSize) return false; + + bool result = false; + + if(p_grid) { + char &importantByte = p_grid[byteContainer]; + result = (importantByte >> bitOffset) & 1; + } + else if(latGrid && p_latLinesGrid) { + char &importantByte = p_latLinesGrid[byteContainer]; + result = (importantByte >> bitOffset) & 1; + } + else if(!latGrid && p_lonLinesGrid) { + char &importantByte = p_lonLinesGrid[byteContainer]; + result = (importantByte >> bitOffset) & 1; + } + else { + iString msg = "GroundGrid::GetGridBit no grids available"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + return result; + } + + + /** + * This sets the bits on the grid along the specified line. + * + * @param x1 Start X + * @param y1 Start Y + * @param x2 End X + * @param y2 End Y + * @param isLatLine + */ + void GroundGrid::DrawLineOnGrid(unsigned int x1, unsigned int y1, + unsigned int x2, unsigned int y2, + bool isLatLine) { + int dx = x2 - x1; + int dy = y2 - y1; + + SetGridBit(x1, y1, isLatLine); + + if(dx != 0) { + double m = (double)dy / (double)dx; + double b = y1 - m * x1; + + dx = (x2 > x1) ? 1 : -1; + while(x1 != x2) { + x1 += dx; + y1 = (int)(m * x1 + b + 0.5); + SetGridBit(x1, y1, isLatLine); + } + } + } +}; diff --git a/isis/src/base/objs/GroundGrid/GroundGrid.h b/isis/src/base/objs/GroundGrid/GroundGrid.h new file mode 100644 index 0000000000000000000000000000000000000000..74e03ecf01d028cde5a887e712b1dfa744d59dab --- /dev/null +++ b/isis/src/base/objs/GroundGrid/GroundGrid.h @@ -0,0 +1,96 @@ +#ifndef GroundGrid_h +#define GroundGrid_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/06/22 23:57:57 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { + class Progress; + class UniversalGroundMap; + + /** + * @brief Calculates a lat/lon grid over an area + * + * This class, given a universal ground map, area width and height, + * base lat/lon, lat/lon increments, and optionalls a progress and + * resolutions will calculate where grid lines should lie. + * + * @author 2010-01-06 Steven Lambright + * + * @internal + * @history 2010-05-06 Steven Lambright Added Split Lat/Lon + * Functionality + * @history 2010-06-22 Steven Lambright Improved handling of resolutions + */ + class GroundGrid { + public: + GroundGrid(UniversalGroundMap *gmap, bool splitLatLon, + unsigned int width, unsigned int height); + + virtual ~GroundGrid(); + + void CreateGrid(double baseLat, double baseLon, + double latInc, double lonInc, + Progress *progress = 0, + double latRes = 0.0, double lonRes = 0.0); + + bool PixelOnGrid(int x, int y); + bool PixelOnGrid(int x, int y, bool latGrid); + + protected: + virtual bool GetXY(double lat, double lon, + unsigned int &x, unsigned int &y); + + //! Returns the ground map for children + UniversalGroundMap *GroundMap() { + return p_groundMap; + } + + private: + void SetGridBit(unsigned int x, unsigned int y, bool latGrid); + bool GetGridBit(unsigned int x, unsigned int y, bool latGrid); + void DrawLineOnGrid(unsigned int x1, unsigned int y1, + unsigned int x2, unsigned int y2, + bool isLatLine); + + + char *p_grid; //!< This stores the bits of each pixel in the grid + char *p_latLinesGrid; //!< This stores the bits of each pixel in the grid + char *p_lonLinesGrid; //!< This stores the bits of each pixel in the grid + unsigned int p_width; //!< This is the width of the grid + unsigned int p_height; //!< This is the height of the grid + unsigned long p_gridSize; //!< This is width*height + UniversalGroundMap *p_groundMap; //!< This calculates single grid pts + + double p_minLat; //!< Lowest latitude in image + double p_minLon; //!< Lowest longitude in image + double p_maxLat; //!< Highest latitude in image + double p_maxLon; //!< Highest longitude in image + + double p_defaultResolution; //!< Default step size in degrees/pixel + + bool p_reinitialize; //!< True if we need to reset p_grid in CreateGrid + }; + +} + + +#endif diff --git a/isis/src/base/objs/GroundGrid/GroundGrid.truth b/isis/src/base/objs/GroundGrid/GroundGrid.truth new file mode 100644 index 0000000000000000000000000000000000000000..58e4921e13579fa0898bf2d4db0f2d227e756b1a --- /dev/null +++ b/isis/src/base/objs/GroundGrid/GroundGrid.truth @@ -0,0 +1,156 @@ +Reading cube... +Create universal ground map... +Create grid... +unittest: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed First line on grid: +0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 0 0 0 0 0 +0 0 0 0 1 0 0 0 0 0 +0 0 0 0 0 1 0 0 0 0 +0 0 0 0 0 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 0 0 +0 0 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 diff --git a/isis/src/base/objs/GroundGrid/GroundGrid_Darwin_powerpc.truth b/isis/src/base/objs/GroundGrid/GroundGrid_Darwin_powerpc.truth new file mode 100644 index 0000000000000000000000000000000000000000..729c511ec24fefa6547243e905568187f9ed7f40 --- /dev/null +++ b/isis/src/base/objs/GroundGrid/GroundGrid_Darwin_powerpc.truth @@ -0,0 +1,156 @@ +Reading cube... +Create universal ground map... +Create grid... +unittest: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed First line on grid: +0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 0 0 0 0 0 +0 0 0 0 1 0 0 0 0 0 +0 0 0 0 0 1 0 0 0 0 +0 0 0 0 0 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 0 0 +0 0 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 diff --git a/isis/src/base/objs/GroundGrid/GroundGrid_Linux_i686_RedHat5_4.truth b/isis/src/base/objs/GroundGrid/GroundGrid_Linux_i686_RedHat5_4.truth new file mode 100644 index 0000000000000000000000000000000000000000..729c511ec24fefa6547243e905568187f9ed7f40 --- /dev/null +++ b/isis/src/base/objs/GroundGrid/GroundGrid_Linux_i686_RedHat5_4.truth @@ -0,0 +1,156 @@ +Reading cube... +Create universal ground map... +Create grid... +unittest: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed First line on grid: +0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 0 0 0 0 0 +0 0 0 0 1 0 0 0 0 0 +0 0 0 0 0 1 0 0 0 0 +0 0 0 0 0 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 0 0 +0 0 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 diff --git a/isis/src/base/objs/GroundGrid/GroundGrid_Linux_i686_RedHat5_5.truth b/isis/src/base/objs/GroundGrid/GroundGrid_Linux_i686_RedHat5_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..729c511ec24fefa6547243e905568187f9ed7f40 --- /dev/null +++ b/isis/src/base/objs/GroundGrid/GroundGrid_Linux_i686_RedHat5_5.truth @@ -0,0 +1,156 @@ +Reading cube... +Create universal ground map... +Create grid... +unittest: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed First line on grid: +0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 0 0 0 0 0 +0 0 0 0 1 0 0 0 0 0 +0 0 0 0 0 1 0 0 0 0 +0 0 0 0 0 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 0 0 +0 0 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 diff --git a/isis/src/base/objs/GroundGrid/GroundGrid_Linux_i686_SUSE10_1.truth b/isis/src/base/objs/GroundGrid/GroundGrid_Linux_i686_SUSE10_1.truth new file mode 100644 index 0000000000000000000000000000000000000000..729c511ec24fefa6547243e905568187f9ed7f40 --- /dev/null +++ b/isis/src/base/objs/GroundGrid/GroundGrid_Linux_i686_SUSE10_1.truth @@ -0,0 +1,156 @@ +Reading cube... +Create universal ground map... +Create grid... +unittest: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed First line on grid: +0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 0 0 0 0 0 0 +0 0 0 0 1 0 0 0 0 0 +0 0 0 0 0 1 0 0 0 0 +0 0 0 0 0 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 0 0 +0 0 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 diff --git a/isis/src/base/objs/GroundGrid/Makefile b/isis/src/base/objs/GroundGrid/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8c6864dc2e6a429bc1b6657b2c20fc7a36f15db6 --- /dev/null +++ b/isis/src/base/objs/GroundGrid/Makefile @@ -0,0 +1,5 @@ +INCS = GroundGrid.h +SRCS = GroundGrid.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/GroundGrid/unitTest.cpp b/isis/src/base/objs/GroundGrid/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e75206056c562999e76694ce36449e8f51359193 --- /dev/null +++ b/isis/src/base/objs/GroundGrid/unitTest.cpp @@ -0,0 +1,40 @@ +#include "Isis.h" + +#include + +#include "Cube.h" +#include "UniversalGroundMap.h" +#include "GroundGrid.h" +#include "Progress.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + /* + The output of this class directly correlates to the output of the "grid" + application when mode=ground - if that application is correct, then this + object is correct and vice versa. + */ + Cube someCube; + + cout << "Reading cube..." << endl; + someCube.Open("$base/testData/ab102401_ideal.cub"); + + cout << "Create universal ground map..." << endl; + UniversalGroundMap gmap(someCube); + + cout << "Create grid..." << endl; + Progress progress; + GroundGrid grid(&gmap, false, someCube.Samples(), someCube.Lines()); + + grid.CreateGrid(0, 0, 0.1, 0.1, &progress, 0.5, 0.5); + + cout << "First line on grid: " << endl; + for(int i = 0; i < someCube.Samples(); i++) { + cout << grid.PixelOnGrid(i, 0) << "\t"; + if(i % 10 == 0) cout << endl; + } + + cout << endl; +} diff --git a/isis/src/base/objs/GroundGrid/unitTest.xml b/isis/src/base/objs/GroundGrid/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..1549011579134851d8836cf5a927e6e083425b6e --- /dev/null +++ b/isis/src/base/objs/GroundGrid/unitTest.xml @@ -0,0 +1,37 @@ + + + + + + Brief description + + + + This program tests the GroundGrid class. + + + + + Original version + + + + + Utility + + + + + + cube + output + Default + Brief for parameter CUBE + + Description for CUBE. + + + + + + diff --git a/isis/src/base/objs/GroupedStatistics/GroupedStatistics.cpp b/isis/src/base/objs/GroupedStatistics/GroupedStatistics.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13ccf543aa129feb9566cb7e2b3796b496ba89f7 --- /dev/null +++ b/isis/src/base/objs/GroupedStatistics/GroupedStatistics.cpp @@ -0,0 +1,122 @@ +#include "GroupedStatistics.h" +#include "Statistics.h" + +#include +#include +#include + +namespace Isis +{ + + //! construct a GroupedStatistics object + GroupedStatistics::GroupedStatistics() + { + groupedStats = NULL; + groupedStats = new QMap< QString, Statistics >(); + } + + + /** + * copy construct a GroupedStatistics object + * + * @param other The GroupedStatistics to copy + */ + GroupedStatistics::GroupedStatistics(const GroupedStatistics & other) + { + groupedStats = NULL; + groupedStats = new QMap< QString, Statistics >(*other.groupedStats); + } + + + //! destroy a GroupedStatistics object + GroupedStatistics::~GroupedStatistics() + { + if (groupedStats) + { + delete groupedStats; + groupedStats = NULL; + } + } + + + /** + * Add a new data entry for a given type of data + * + * @param statType Type of data (GoodnessOfFit for example) + * + * @param newStat New statistical data to be added + * + */ + void GroupedStatistics::AddStatistic(const QString & statType, const + double & newStat) + { + (*groupedStats)[statType].AddData(newStat); + } + + + /** + * Get statistics for a given type of data + * + * @param statType Type of data + * + * @returns Statisticts for the given type of data + * + * @throws iException When the given type of data does not exist + */ + const Statistics & GroupedStatistics::GetStatistics(const QString & statType) + const + { + QMap< QString, Statistics >::const_iterator i; + i = groupedStats->constFind(statType); + + if (i == groupedStats->constEnd()) + { + std::string msg = statType.toStdString(); + msg += " passed to GetStats but does not exist within the map"; + throw Isis::iException::Message(Isis::iException::Programmer, msg, + _FILEINFO_); + } + + return i.value(); + } + + + /** + * Return a list of all the different statistic tyes that this + * GroupedStatistics has + * + * @returns A list of statistic types that this GroupedStatistics has + */ + const QVector< QString > GroupedStatistics::GetStatisticTypes() + const + { + QVector< QString > statTypes; + + // for each key in the groupedStats QMap add the key to a vector + QMap< QString, Statistics >::const_iterator i = groupedStats->constBegin(); + while (i != groupedStats->constEnd()) + { + statTypes.push_back(i.key()); + i++; + } + + return statTypes; + } + + + /** + * Assign a GroupedStatistics with another GroupedStatistics using = + * + * @param other The GroupedStatistics to copy + */ + GroupedStatistics & GroupedStatistics::operator=(const GroupedStatistics + & other) + { + delete groupedStats; + groupedStats = NULL; + + groupedStats = new QMap< QString, Statistics >(*other.groupedStats); + + return *this; + } +} diff --git a/isis/src/base/objs/GroupedStatistics/GroupedStatistics.h b/isis/src/base/objs/GroupedStatistics/GroupedStatistics.h new file mode 100755 index 0000000000000000000000000000000000000000..f36d6c202bee41bb8e8a3c3efef7cfae3037e193 --- /dev/null +++ b/isis/src/base/objs/GroupedStatistics/GroupedStatistics.h @@ -0,0 +1,75 @@ +#ifndef GroupedStatistics_h +#define GroupedStatistics_h + +/** + * @file + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +// Global forward declarations +template< class A, class B > class QMap; +template< class A > class QVector; +class QString; + +namespace Isis +{ + + // Isis forward declarations + class Statistics; + + /** + * @brief Grouped Statistics + * + * This class is used to store statistics on a group of related items. + * + * This class is include safe meaning that includers of this class will only + * get this class. + * + * @ingroup Statistics + * + * @author 2009-09-14 Eric Hyer + * + * @see Statistics + * + * @internal + * @history 2009-09-14 Eric Hyer - Original Version + * @history 2009-09-18 Eric Hyer - Fixed some comments / documentation + * @history 2009-10-15 Eric Hyer - Added GetStatisticTypes method + * + */ + class GroupedStatistics + { + public: + GroupedStatistics(); + GroupedStatistics(const GroupedStatistics & other); + ~GroupedStatistics(); + + void AddStatistic(const QString & statType, const double & newStat); + const Statistics & GetStatistics(const QString & statType) const; + const QVector< QString > GetStatisticTypes() const; + + GroupedStatistics & operator=(const GroupedStatistics & other); + + private: + //! Map from statistic type to Statistics object + QMap< QString, Statistics > * groupedStats; + }; +}; + +#endif + diff --git a/isis/src/base/objs/GroupedStatistics/GroupedStatistics.truth b/isis/src/base/objs/GroupedStatistics/GroupedStatistics.truth new file mode 100644 index 0000000000000000000000000000000000000000..465c576316ffe40b1034ba3fc7d3a408ac2474b9 --- /dev/null +++ b/isis/src/base/objs/GroupedStatistics/GroupedStatistics.truth @@ -0,0 +1,14 @@ +GroupedStatistics unitTest!!! + +testing constructor... + +testing AddStatistic... + +testing copy constructor... + +testing GetStatistics... + 71.5 + +testing GetStatisticTypes... + Height + diff --git a/isis/src/base/objs/GroupedStatistics/Makefile b/isis/src/base/objs/GroupedStatistics/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..f8205e25c7dc53dde2544f59f072622e72c5381f --- /dev/null +++ b/isis/src/base/objs/GroupedStatistics/Makefile @@ -0,0 +1,5 @@ +INCS = GroupedStatistics.h +SRCS = GroupedStatistics.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/GroupedStatistics/unitTest.cpp b/isis/src/base/objs/GroupedStatistics/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b26e08d70557c20031860ed84d4d94329f006d9f --- /dev/null +++ b/isis/src/base/objs/GroupedStatistics/unitTest.cpp @@ -0,0 +1,49 @@ +#include + +#include +#include + +#include "GroupedStatistics.h" +#include "Statistics.h" +#include "Preference.h" + + +using namespace std; +using namespace Isis; + + +int main () +{ + Isis::Preference::Preferences(true); + cerr << "GroupedStatistics unitTest!!!\n\n"; + + // test constructor + cerr << "testing constructor...\n\n"; + GroupedStatistics * groupedStats = new GroupedStatistics(); + + // test AddStatistic + cerr << "testing AddStatistic...\n\n"; + groupedStats->AddStatistic("Height", 71.5); + + // test copy constructor + cerr << "testing copy constructor...\n\n"; + GroupedStatistics * groupedStats2 = new GroupedStatistics(*groupedStats); + + // test GetStatistics + cerr << "testing GetStatistics...\n"; + Statistics stats = groupedStats2->GetStatistics("Height"); + cerr << " " << stats.Average() << "\n\n"; + + // test GetStatisticTypes + cerr << "testing GetStatisticTypes...\n"; + QVector< QString > statTypes = groupedStats->GetStatisticTypes(); + for (int i = 0; i < statTypes.size(); i++) + cerr << " " << statTypes[i].toStdString() << "\n"; + cerr << "\n"; + + // test destructor + delete groupedStats; + delete groupedStats2; + + return 0; +} diff --git a/isis/src/base/objs/Gruen/Gruen.cpp b/isis/src/base/objs/Gruen/Gruen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..16e7a39e1c0361c4283b2d378726f47c8a560a51 --- /dev/null +++ b/isis/src/base/objs/Gruen/Gruen.cpp @@ -0,0 +1,980 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/06/14 20:45:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include + +#include "Gruen.h" +#include "Chip.h" + +#include +#include + + +namespace Isis { + + using namespace GSL; + + /** Basic Gruen algorithm constructor */ + Gruen::Gruen(Pvl &pvl) : AutoReg(pvl) { + init(pvl); + } + + /** + * @brief Sets established radiometric parameters for registration processes + * + * This method provides a mechanism for establishing predetermined values for + * registration activities. This is intended to be used for the DEM + * generation processing where points are grown around seed points. This is + * intended to lead to rapid convergence of points surrounding established + * seed points. + * + * This should be used in conjuction with the resulting Affine transform as + * determined from the seed point. + * + * Note that once this is established, it remains constant for all subsequent + * registration processes. To reset the default, all this method with no + * arguments. + * + * Also note that these defaults can be established in the input AutoReg + * definition file. + * + * These values are set when reset() is called - typically at the start of any + * adaptive application of the Gruen algorithm. + * + * @param gain Precomputed radiometric gain value to use as default + * @param shift Precomputed radiometric shift value to use as default + */ + void Gruen::SetRadiometrics(const double &gain, const double &shift) { + _defGain = gain; + _defShift = shift; + return; + } + + /** + * @brief Real workhorse of the computational Gruen algorithm + * + * This method is called for all registration requests and actually performs + * the registration of two chips. + * + * The pattern chip is deemed constant. The subsearch chip is generally an + * extraction from the search chip that has had an affine transform applied to + * fill it. + * + * At each iteration of the Gruen algorithm, the affine transform is + * incrementally updated based upon the results from this method. There are + * six affine parameters and two radiometric (shift and gain) parameters that + * are solved/computed here. + * + * The algorithm itself is a first derivative computation of the subsearch + * chip with small radiometric adjustments applied to better tone match the + * two chips. This is intended to minimize the affine variability. + * + * @param pattern Fixed pattern chip which subsearch is trying to match + * @param subsearch Affined extraction of the search chip + * + * @return GruenResult Container storing the results and helper methods of the + * solution + */ + GruenResult Gruen::algorithm (Chip &pattern, Chip &subsearch) { + + _totalIterations++; // Bump iteration counter + + // Initialize loop variables + int tackSamp = pattern.TackSample(); + int tackLine = pattern.TackLine(); + + // Internal variables + GruenResult result; + result.nIters = _nIters + 1; + BigInt npts(0); + + // pattern chip is rh image , subsearch chip is lh image + GSLVector a(8); + for (int line = 2 ; line <= pattern.Lines()-1; line++ ) { + for (int samp = 2; samp <= pattern.Samples()-1; samp++ ) { + + if (!pattern.IsValid(samp,line)) continue; + if (!subsearch.IsValid(samp,line)) continue; + if (!subsearch.IsValid(samp+1,line)) continue; + if (!subsearch.IsValid(samp-1,line)) continue; + if (!subsearch.IsValid(samp,line-1)) continue; + if (!subsearch.IsValid(samp,line+1)) continue; + + // Compute parameters + npts++; + double x0 = (double) (samp - tackSamp); + double y0 = (double) (line - tackLine); + + double gxtemp = subsearch.GetValue(samp+1,line) - + subsearch.GetValue(samp-1,line); + double gytemp = subsearch.GetValue(samp,line+1) - + subsearch.GetValue(samp,line-1); + + a[0] = gxtemp * x0; + a[1] = gxtemp * y0; + a[2] = gxtemp; + a[3] = gytemp * x0; + a[4] = gytemp * y0; + a[5] = gytemp; + a[6] = 1.0; + a[7] = subsearch.GetValue(samp,line); + double ell = pattern.GetValue(samp,line) - + (((1.0 + Gain()) * subsearch.GetValue(samp,line)) + + Shift()); + + // Compute residual + result.resid += (ell * ell); + + // Add this point to the ATA and ATL summation matrices. + // This eliminates the need to store all the points as was + // in the original ISIS2 algorithm. + for ( int i = 0 ; i < 8 ; i++ ) { + for ( int j = 0 ; j < 8 ; j++ ) { + result.ata[i][j] += (a[i] * a[j]); + } + result.atl[i] += (a[i] * ell); + } + } + } + + // Check for enough points + result.npts = npts; + BigInt tPnts = (pattern.Lines()-1) * (pattern.Samples()-1); + if (!ValidPoints(tPnts, npts)) { + result.gerrno = NotEnoughPoints; + std::ostringstream mess; + mess << "Minimum points (" << MinValidPoints(tPnts) + << ") criteria not met (" << result.npts << ")"; + result.gerrmsg = mess.str(); + result.isGood = false; + logError(result.gerrno, result.gerrmsg); + return (result); + } + + // Compute error analysis + solve(result); +// GSLMatrix aff(2,3, &result.alpha[0]); +// std::cout << "DAffine = " << aff << std::endl; + return (result); + } + + /** + * @brief Computes solution and error analysis using Cholesky/Jacobi methods + * + * This method computes the affine and radiometric parameter solution and + * associated errors/uncertainty from the algorithm() processing. + * + * The affine parameters are solved using Cholesky decomposition. Error + * analysis is computed using Jacobian eigenvector methods. The GNU + * Scientific Library (GSL) is used to apply these routines. + * + * See http://www.gnu.org/software/gsl/ for additional details on the GNU + * Scientific Library. + * + * @param result Input parameters provided to compute solution. This + * container is also updated by this method with the solution + * and error analysis. + * + * @return bool True if successful, false if an error occurs + */ + bool Gruen::solve(GruenResult &result) { + GSLUtility *gsl = GSLUtility::getInstance(); + + size_t nRows = gsl->Rows(result.ata); + size_t nCols = gsl->Columns(result.ata); +// std::cout << "Ata = " << result.ata << std::endl; +// std::cout << "Resid = " << result.resid << std::endl; +// std::cout << "npts = " << result.npts << std::endl; +// std::cout << "Atl = " << result.atl << std::endl; + + // Compute variance + double variance = result.Variance(); + gsl_matrix *A, *atai; + try { + A = gsl->GSLTogsl(result.ata); + gsl->check(gsl_linalg_cholesky_decomp(A)); + atai = gsl->identity(nRows, nCols); + + for (size_t i = 0 ; i < nRows ; i++ ) { + gsl_vector_view x = gsl_vector_view_array(gsl_matrix_ptr(atai, i, 0), + nCols); + gsl->check(gsl_linalg_cholesky_svx(A, &x.vector)); + } + } + catch (iException &ie) { + result.gerrno = CholeskyFailed; + result.gerrmsg = "Cholesky Failed:: " + ie.Errors(); + result.isGood = false; + ie.Clear(); + logError(result.gerrno, result.gerrmsg); + return (false); + } + + // Solve Gruen parameter contributions + for ( size_t r = 0 ; r < nRows ; r++ ) { + result.alpha[r] = 0.0; + for (size_t c = 0 ; c < nCols ; c++ ) { + double ataiV = gsl_matrix_get(atai, r, c); + result.alpha[r] += ataiV * result.atl[c]; + result.kmat[r][c] = variance * ataiV; + } + } + + // Set up submatrix + result.skmat[0][0] = result.kmat[2][2]; + result.skmat[0][1] = result.kmat[2][5]; + result.skmat[1][0] = result.kmat[5][2]; + result.skmat[1][1] = result.kmat[5][5]; + try { + gsl_matrix_view skmat = gsl_matrix_view_array(&result.skmat[0][0],2,2); + gsl_vector_view evals = gsl_vector_view_array(&result.eigen[0], 2); + gsl_eigen_symm_workspace *w = gsl_eigen_symm_alloc(2); + gsl->check(gsl_eigen_symm(&skmat.matrix, &evals.vector, w)); + gsl_eigen_symm_free(w); + gsl_eigen_symmv_sort(&evals.vector, &skmat.matrix, GSL_EIGEN_SORT_VAL_DESC); + gsl->free(A); + gsl->free(atai); + } + catch (iException &ie) { + result.gerrno = EigenSolutionFailed; + result.gerrmsg = "Eigen Solution Failed:: " + ie.Errors(); + result.isGood = false; + ie.Clear(); + logError(result.gerrno, result.gerrmsg); + return (false); + } + result.isGood = true; + return (result.isGood); + } + +/** + * @brief Minimization of data set using Gruen algorithm + * + * This is a very minimal application of the Gruen algorithm that provides the + * ability to use it in a non-adaptive capacity. This method processes two + * chips of the same size, pattern and subsearch. The subsearch has typically + * been extracted in the same manner as the MinimumDifference or + * MaximumCorrelation routines are utilized. + * + * It simply applies the algorithm to the current state of the two chips, + * computes the error analysis on it and returns the eigen vector solution as an + * indication of chip registration integrity. + * + * Note that in this mode, most all the parameters found in the definition file + * that apply to the adaptive mode are ignored when utilizing the algorithm in + * this fashion. + * + * @param pattern [in] A Chip object usually containing an nxm area of a cube. + * Must be the same diminsions as \b subsearch. + * @param subsearch [in] A Chip object usually containing an nxm area of a cube. + * Must be the same diminsions as \b pattern. This is normally + * a subarea of a larger portion of the image. + * + * @return The square root of the eigen values of DN differences OR Isis::NULL + * if the Gruen algorithm fails. + */ + double Gruen::MatchAlgorithm (Chip &pattern, Chip &subsearch) { + reset(); + GruenResult result = algorithm(pattern, subsearch); + _result.update(result); + if (IsGood() ) return (_result.Eigen()); + return (Null); + } + + /** + * This virtual method must return if the 1st fit is equal to or better + * than the second fit. + * + * @param fit1 1st goodness of fit + * @param fit2 2nd goodness of fit + */ + bool Gruen::CompareFits (double fit1, double fit2) { + return (fit1 <= fit2); + } + + + /** + * @brief Applies the adaptive Gruen algorithm to pattern and search chips + * + * This method computes the adaptive Gruen algorithm for a pattern chip and + * search chip. The search chip is assumed to be of a larger size than the + * pattern chip as dictated by the contents of the registration definition + * file. + * + * This algorithm can be used with or without "fast geoming" the search chip. + * It works quite well where the two images are assumed to be nearly spatially + * registered. Its real intent is to compute parallax angles between two + * images taken at different viewing geometry. This provides an efficient + * process for deriving a digital elevation model (DEM) from two datasets. + * + * The Gruen algorithm is applied to the chips until the algorithm converges + * (current iteration yields a detla affine within tolerance limits), an error + * is encountered, or the maximum number of iterations is exceeded. + * + * Note that bestSamp and bestLine may not be the original center of the + * search chip. It is subject to chip reduction matching as specified by the + * user. All distance tolerances are compute from this postion. The + * process of chip reduction processing is handled by AutoReg prior to calling + * this routine. + * + * @see getThreshHold() for Affine limit information + * + * @param sChip Full search chip as rendered from the search image + * @param pChip Full pattern chip as rendered from the pattern/match image + * @param fChip Maintains the solution vector at each chip location + * @param startSamp Starting sample of the search image range + * @param startLine Starting line of the search image range + * @param endSamp Ending sample of the search image range + * @param endLine Ending line of the search image range + * @param bestSamp Best registering sample of search chip + * @param bestLine best registering line of search chip + * + * @return AutoReg::RegisterStatus Returns AutoReg::Success if the chip is + * successfully registered, otherwise returns + * AutoReg::AdaptiveAlgorithmFailed. + */ + AutoReg::RegisterStatus Gruen::AdaptiveRegistration(Chip &sChip,Chip &pChip, + Chip &fChip,int startSamp, + int startLine,int endSamp, + int endLine, int bestSamp, + int bestLine) { +#if defined(WRITE_CHIPS) + static int callNo(0); + callNo++; +#endif + + // Reset internal parameters + reset(); + + // Set initial chip location + sChip.SetChipPosition(bestSamp, bestLine); + _result.setStartImage(sChip.CubeSample(), sChip.CubeLine()); + + // Ok create a fit chip whose size is the same as the search chip + // and then fill it with nulls. Then adjust the Affine mapping such that + // it scales to the user specified precision (1/10th) so that fits can + // be recorded + fChip.SetSize(sChip.Samples(),sChip.Lines()); + fChip.SetAllValues(Null); + Affine faffine = sChip.GetTransform(); + faffine.Translate(bestSamp-sChip.TackSample(), bestLine-sChip.TackLine()); + faffine.Scale(_fitChipScale); + fChip.SetTransform(faffine, false); + + // Create a chip the same size as the pattern chip. It is critical to use + // the original search chip to create the subsearch. Copying the orginal + // search chip and then resizing preserves established minimum/maximum + // value ranges. + Chip subsearch = sChip; + subsearch.SetSize(pChip.Samples(), pChip.Lines()); + + // Set up Affine transform by establishing search tack point + Affine tform; + tform.Translate(bestSamp-sChip.TackSample(), bestLine-sChip.TackLine()); + + bool done(false); + GSLVector alpha(GruenResult::Constraints(), 0.0); + GSLVector threshold = getThreshHold(subsearch); + for (_nIters = 0 ; _nIters < _maxIters ; _nIters++) { + // Extract the sub search chip. The algorithm method handles the + // determination of good data volumes + sChip.Extract(subsearch, tform); + +#if defined(WRITE_CHIPS) + std::ostringstream ss; + ss << "C" << callNo << "I" << _nIters; + std::string sfname = "subchip" + ss.str() + ".cub"; + subsearch.Write(sfname); +#endif + + // Try to match the two subchips + GruenResult result = algorithm(pChip, subsearch); + if (!result.IsGood()) { + return (Status(result)); + } + + // Test for termination conditions - errors or convergence + if (_nIters > 0) { + if ((done = HasConverged(alpha, threshold, result)) == true) { + ErrorAnalysis(result); + break; + } + } + + // Update the affine transform, other internal parameters + alpha = result.Alpha().copy(); + try { + tform = UpdateAffine(result, tform); + } catch (iException &ie) { + result.gerrno = AffineNotInvertable; + result.gerrmsg = "Affine invalid/not invertable"; + result.isGood = false; + logError(result.gerrno, result.gerrmsg); + ie.Clear(); + return (Status(result)); + } + + // Set output to result + subsearch.SetChipPosition(subsearch.TackSample(), subsearch.TackLine()); + fChip.SetCubePosition(subsearch.CubeSample(), subsearch.CubeLine()); + if (fChip.IsInsideChip(fChip.ChipSample(),fChip.ChipLine())) { + fChip.SetValue((int) fChip.ChipSample(), (int) fChip.ChipLine(), + result.Eigen()); + } + } // Adaptive Loop Terminate + + // Test for solution constraints and update chip if valid + if (TestConstraints(done, _result)) { + UpdateChip(sChip, tform); + SetChipSample(sChip.TackSample()); + SetChipLine(sChip.TackLine()); + _result.setChipTransform(sChip.GetTransform()); + SetGoodnessOfFit(_result.Eigen()); + sChip.SetChipPosition(bestSamp, bestLine); + _result.setFinalImage(sChip.CubeSample(), sChip.CubeLine()); + CheckAffineTolerance(); + } + + return (Status()); + } + + /** + * @brief Create Gruen error and processing statistics Pvl output + * + * This method generates two groups specific to the Gruen algorithm: The + * GruenFailures group which logs all the errors enountered during processing + * and the GruenStatistics group which logs selected statistics gathered + * during a registration run. + * + * These groups are added to the AutoReg log output Pvl container for + * reporting to user/log files. + * + * @param pvl Input AutoReg Pvl container to add results to + * + * @return Pvl Output Pvl container with Gruen information + */ + Pvl Gruen::AlgorithmStatistics(Pvl &pvl) { + PvlGroup algo("GruenFailures"); + algo += PvlKeyword("Name", AlgorithmName()); + algo += PvlKeyword("Mode", (IsAdaptive() ? "Adaptive" : "NonAdaptive")); + + // Log errors + for (int e = 0 ; e < _errors.size() ; e++) { + algo += _errors.getNth(e).LogIt(); + } + + if (_unclassified > 0) { + algo += PvlKeyword("UnclassifiedErrors", _unclassified); + } + pvl.AddGroup(algo); + pvl.AddGroup(StatsLog()); + pvl.AddGroup(ParameterLog()); + return (pvl); + } + + /** + * @brief Create a PvlGroup with the Gruen specific statistics + * + * This method generates a PvlGroup from statistics collected for a particular + * Gruen algorithm application. This routine is called from the AutoReg + * algorithm specific statistics routine and augments the AutoReg statistics + * log output. + * + * @return PvlGroup Group containing Pvl keywords with collected statistics + */ + PvlGroup Gruen::StatsLog() const { + PvlGroup stats("GruenStatistics"); + + stats += PvlKeyword("TotalIterations", _totalIterations); + stats += ValidateKey("IterationMinimum", _iterStat.Minimum()); + stats += ValidateKey("IterationAverage", _iterStat.Average()); + stats += ValidateKey("IterationMaximum", _iterStat.Maximum()); + stats += ValidateKey("IterationStandardDeviation", _iterStat.StandardDeviation()); + + stats += ValidateKey("EigenMinimum", _eigenStat.Minimum()); + stats += ValidateKey("EigenAverage", _eigenStat.Average()); + stats += ValidateKey("EigenMaximum", _eigenStat.Maximum()); + stats += ValidateKey("EigenStandardDeviation", _eigenStat.StandardDeviation()); + + stats += ValidateKey("RadioShiftMinimum", _shiftStat.Minimum()); + stats += ValidateKey("RadioShiftAverage", _shiftStat.Average()); + stats += ValidateKey("RadioShiftMaximum", _shiftStat.Maximum()); + stats += ValidateKey("RadioShiftStandardDeviation", _shiftStat.StandardDeviation()); + + stats += ValidateKey("RadioGainMinimum", _gainStat.Minimum()); + stats += ValidateKey("RadioGainAverage", _gainStat.Average()); + stats += ValidateKey("RadioGainMaximum", _gainStat.Maximum()); + stats += ValidateKey("RadioGainStandardDeviation", _gainStat.StandardDeviation()); + + return (stats); + + } + + /** + * @brief Create a PvlGroup with the Gruen specific parameters + * + * This method generates a PvlGroup of Gruen algorithm parameters. This + * routine is called from the AutoReg algorithm specific statistics routine + * and augments the AutoReg log output. + * + * @return PvlGroup Group containing Pvl keywords of Gruen parameters + */ + PvlGroup Gruen::ParameterLog() const { + PvlGroup parms("GruenParameters"); + + parms += PvlKeyword("MaximumIterations", _maxIters); + parms += ValidateKey("AffineScaleTolerance", _scaleTol); + parms += ValidateKey("AffineShearTolerance", _shearTol); + parms += ValidateKey("AffineTranslationTolerance", _transTol); + + parms += ParameterKey("AffineTolerance", _affineTol); + parms += ParameterKey("SpiceTolerance", _spiceTol); + + parms += ParameterKey("RadioShiftTolerance", _rshiftTol); + + parms += ParameterKey("RadioGainMinTolerance", _rgainMinTol); + parms += ParameterKey("RadioGainMaxTolerance", _rgainMaxTol); + + parms += ValidateKey("FitChipScale", _fitChipScale, "pixels"); + parms += ValidateKey("DefaultRadioGain", _defGain); + parms += ValidateKey("DefaultRadioShift", _defShift); + + return (parms); + } + + + /** + * @brief Creates an error list from know Gruen errors + * + * This method creates the list of known/expected Gruen errors that might + * occur during processing. This should be closely maintained with the + * GruenErrors enum list. + * + * @return Gruen::ErrorList Error list container + */ + Gruen::ErrorList Gruen::initErrorList() const { + ErrorList elist; + elist.add(1,ErrorCounter(1,"NotEnoughPoints")); + elist.add(2,ErrorCounter(2,"CholeskyFailed")); + elist.add(3,ErrorCounter(3,"EigenSolutionFailed")); + elist.add(4,ErrorCounter(4,"AffineNotInvertable")); + elist.add(5,ErrorCounter(5,"MaxIterationsExceeded")); + elist.add(6,ErrorCounter(6,"RadShiftExceeded")); + elist.add(7,ErrorCounter(7,"RadGainExceeded")); + elist.add(8,ErrorCounter(8,"MaxEigenExceeded")); + elist.add(9,ErrorCounter(9,"AffineDistExceeded")); + return (elist); + } + + + /** + * @brief Logs a Gruen error + * + * A running count of errors that occur is maintained through this method. If + * an error occurs that is not in the list, it will also be counted. This + * would indicate that a new error condition has occured and needs to be added + * to the list. + * + * @param gerrno One of the errors as defined by GruenError enum + * @param gerrmsg Optional message although it is ignored in this context + */ + void Gruen::logError(int gerrno, const std::string &gerrmsg) { + if (!_errors.exists(gerrno)) { + _unclassified++; + } + else { + _errors.get(gerrno).BumpIt(); + } + return; + } + + /** + * @brief Initialize the object + * + * This method reads from the Algorithm group (if it exists) to set variables + * used in this object. If not all the keywords are present, then appropriate + * values are provided. + * + * @param PvlObject &pvl PVL object/groups that contain algorithm parameters + */ + void Gruen::init(Pvl &pvl) { + // Establish the parameters + if (pvl.HasObject("AutoRegistration")) { + _prof = DbProfile(pvl.FindGroup("Algorithm",Pvl::Traverse)); + } + else { + _prof = DbProfile(pvl); + } + + if (_prof.Name().empty()) _prof.setName("Gruen"); + + // Define internal parameters + _maxIters = ConfKey(_prof,"MaximumIterations", 25); + + _transTol = ConfKey(_prof,"AffineTranslationTolerance", 0.1); + _scaleTol = ConfKey(_prof,"AffineScaleTolerance", 0.5); + _shearTol = ConfKey(_prof,"AffineShearTolerance", _scaleTol); + _affineTol = ConfKey(_prof,"AffineTolerance", DBL_MAX); + + _spiceTol = ConfKey(_prof,"SpiceTolerance", DBL_MAX); + + _rshiftTol = ConfKey(_prof,"RadioShiftTolerance", DBL_MAX); + _rgainMinTol = ConfKey(_prof,"RadioGainMinTolerance", -DBL_MAX); + _rgainMaxTol = ConfKey(_prof,"RadioGainMaxTolerance", DBL_MAX); + + _fitChipScale = ConfKey(_prof,"FitChipScale", 0.1); // Set to 10th pixel + + // Set radiometric defaults + SetRadiometrics(); + _defGain = ConfKey(_prof,"DefaultRadioGain", _defGain); + _defShift = ConfKey(_prof,"DefaultRadioShift", _defShift); + + _nIters = 0; + _totalIterations = 0; + _errors = initErrorList(); + _unclassified = 0; + + reset(); + return; + } + + + /** + * @brief Reset registration-dependant counters only + * + * This method is intended to be invoked to reset interal variables that track + * or govern behavior pertaining to the registration of two chips. It should + * be invoked as the first call prior to calling the algorithm method for a + * new registration. + */ + void Gruen::reset() { + _result = GruenResult(); + _result.setGain(getDefaultGain()); + _result.setShift(getDefaultShift()); + _nIters = 0; + return; + } + + /** + * @brief Reset Gruen statistics as needed + * + */ + void Gruen::resetStats() { + _eigenStat.Reset(); + _iterStat.Reset(); + _shiftStat.Reset(); + _gainStat.Reset(); + return; + } + + /** + * @brief Compute the Affine convergence parameters + * + * This method should be invoked using either the subsearch or pattern chip + * since they are both the same size. The six Affine convergence parameters + * are computed from the size of the chip and the AffineThreshHold1 and + * AffineThreshHold2 registration parameters. + * + * AffineThreshHold1 governs the shift in line and sample and is used directly + * as specified in the registration config file. + * + * AffineThreshHold2 governs scaling of sample and line as a function of the + * number of lines and samples in the chip provided. The value from the + * registration config file is divided by half the samples for the X Affine + * component; the Y Affine component is divided by half the number of lines + * in the chip. + * + * + * @param chip Chip to use to compute affine convergence threshholds + * + * @see HasConverged(). + * + * @return Gruen::GSLVector Returns a vector of convergence thresholds that + * coincides with the linear order of the affine transform components. + */ + Gruen::GSLVector Gruen::getThreshHold(const Chip &chip) const { + GSLVector thresh(6); + thresh[0] = _scaleTol/(((double) (chip.Samples()-1))/2.0); + thresh[1] = _shearTol/(((double) (chip.Lines()-1))/2.0); + thresh[2] = _transTol; + thresh[3] = _shearTol/(((double) (chip.Samples()-1))/2.0); + thresh[4] = _scaleTol/(((double) (chip.Lines()-1))/2.0); + thresh[5] = _transTol; + return (thresh); + } + + /** + * @brief Tests Affine parameters for convergence + * + * This method is invoked after the first iteration to test for convergence + * of the affine transform components of the Gruen registration algorithm. + * When the absolute value of all the affine components are less than or equal + * to its coinciding limit, convergence has been reached. + * + * This method does not consider the radiometric shift and gain parameters in + * its determination of convergence. + * + * @param alpha Affine transform change from last iteration to test + * @param thresh Six element array of affine threshholds to test against + * @param results Results container should any information be needed from it + * + * @return bool True if we have converged, false if convergence is not yet + * reached. + * + * @internal + * @history 2009-09-17 Kris Becker Test should be >= rather than >. + */ + bool Gruen::HasConverged(const GSLVector &alpha, const GSLVector &thresh, + const GruenResult &results) const { + int maxholds = std::min(alpha.dim(), thresh.dim()); + for (int nhold = 0 ; nhold < maxholds ; nhold++) { + if (fabs(alpha[nhold]) >= thresh[nhold]) return (false); + } + return (true); + } + + + /** + * @brief Computes the number of minimum valid points + * + * This method uses the pattern valid percent as specified in the registration + * config file (or the programmer) to compute the minimum number of valid + * points from the total. + * + * @param totalPoints Assumed to be total number of relavent pixels in a chip + * + * @return BigInt Minimum number of valid points determined from the + * percentage specified by user/programmer. + */ + BigInt Gruen::MinValidPoints(BigInt totalPoints) const { + double pts = (double) totalPoints * (PatternValidPercent() / 100.0); + return ((BigInt) pts); + } + + /** + * @brief Determines if number of points is valid percentage of all points + * + * Computes the number of minimum valid points from user specified percentage + * and tests the acutal number used. + * + * @param totalPoints Total number of possible valid points in chip + * @param nPoints Actual number of valid points used in chips + * + * @return bool True if number of actual points exceeds percent mimimum valid, + * otherwise returns false. + */ + bool Gruen::ValidPoints(BigInt totalPoints, BigInt nPoints) const { + return (nPoints > MinValidPoints(totalPoints)); + } + + /** + * @brief Computes/determines error analysis after the solution converges + * + * This method maintains the error analysis computed from the Gruen algorithm + * when a convergent condition is encountered. This essentially is a copy of + * the iterative analysis that takes place at each application of the Gruen + * algorithm. It ensures the error analysis is current by making a copy of + * the last error analysis perform as found in the results container. + * + * It moves the iterative error analysis to the cummulative result container. + * + * @param result Iterative solution container with last error analysis that is + * to be preserved + */ + void Gruen::ErrorAnalysis(GruenResult &result) { + _result.setErrorAnalysis(result); + return; + } + + /** + * @brief Test user limits/contraints after the algorithm has converged + * + * This method is invoked immediately after the Gruen algorithm has converged + * to test against user specified limits. This call is only valid in the + * adaptive context as much of the error checking is handled by AutoReg when + * using the non-adaptive algorithm. + * + * This method tests for convergence, maximum iterations exceeded, tolerance + * limits of radiometric shift and gain and whether the eigenvalue of the + * solution exceeds the limit. + * + * The result container is altered should a constraint not be meet which + * indicates the registration failed. + * + * @param done Input parameter that indicates convergence has occurred + * @param result Container with results update by status of contraint check + * + * @return bool Returns true if all constraints tests are valid, otherwise + * returns false indicating an error. + */ + bool Gruen::TestConstraints(const bool &done, GruenResult &result) { + + if (!done) { + result.isGood = false; + result.gerrno = MaxIterationsExceeded; + result.gerrmsg = "Maximum Iterations exceeded"; + logError(result.gerrno, result.gerrmsg); + return (false); + } + else { + + + if (result.Iterations() > _maxIters) { + result.isGood = false; + result.gerrno = MaxIterationsExceeded; + result.gerrmsg = "Maximum Iterations exceeded"; + logError(result.gerrno, result.gerrmsg); + return (false); + } + _iterStat.AddData(result.Iterations()); + + if (result.Shift() > _rshiftTol) { + result.isGood = false; + result.gerrno = RadShiftExceeded; + result.gerrmsg = "Radiometric shift exceeds tolerance"; + logError(result.gerrno, result.gerrmsg); + return (false); + } + _shiftStat.AddData(result.Shift()); + + if (((1.0+result.Gain()) > _rgainMaxTol) || + ((1.0+result.Gain()) < _rgainMinTol) ) { + result.isGood = false; + result.gerrno = RadGainExceeded; + result.gerrmsg = "Radiometric gain exceeds tolerances"; + logError(result.gerrno, result.gerrmsg); + return (false); + } + _gainStat.AddData(result.Gain()); + + if (result.Eigen() > Tolerance()) { + result.isGood = false; + result.gerrno = MaxEigenExceeded; + result.gerrmsg = "Eigen value exceeds tolerance"; + logError(result.gerrno, result.gerrmsg); + return (false); + } + _eigenStat.AddData(result.Eigen()); + } + + return (result.IsGood()); + } + + + /** + * @brief Updates the affine transform with the final iterative solution + * + * This method is called at the end of each iteration that updates the affine + * transform with the sum of all prior affine changes. The affine for the + * current result is added to the cummulative result container and the + * incremental affine is added to the cummulate transform. + * + * @param result Container representing the last iteration solution + * @param gtrans Accumulating affine transform for search chip + * + * @return Affine Returns the newly updated Affine transform + */ + Affine Gruen::UpdateAffine(GruenResult &result, const Affine >rans) { + _result.update(result); + const GSLVector &alpha = result.Alpha(); + Affine::AMatrix dAffine = gtrans.Forward(); + for (int i = 0, a = 0 ; i < 2 ; i++) { + for (int j = 0 ; j < 3 ; j++, a++) { + dAffine[i][j] += alpha[a]; + } + } + return (Affine(dAffine)); + } + + /** + * @brief Updates the (search) chip with the final Affine transform + * + * This method applies the convergent Affine transform parameters to the chip + * provided. The accummulated transform only represents the result of the + * Gruen algorithm. Therefore, any existing Affine transform used to load the + * orginal chip will be added to it for the final resulting solution. + * + * When completed, in theory, the chip can be used to reload from the file and + * it should match well with the original pattern chip on the final iteration + * of the Gruen algorithm which converged. + * + * @param chip Chip to update with accummulated Affine transform + * @param affine Gruen accummulated Affine transform to add to chip + */ + void Gruen::UpdateChip(Chip &chip, const Affine &affine) { + Affine::AMatrix c = chip.GetTransform().Forward() + + (affine.Forward() - Affine::getIdentity()); + chip.SetTransform(Affine(c)); + return; + } + + /** + * @brief Check affine tolerance for validity + * + * This method checks for a convergent solution that travels to far from the + * original tack point (best point in most cases). The user can control this + * tolerance with the AffineTolerance parameter in the registration config + * file. The check is a sample/line magnitude check from the original + * starting pixel location to the one after the affine transform has + * converged to match to a new cube pixel coordinate. + * + * Note this check is independant of TestConstraints() method since the update + * of the chip only occurs after other limits pass. The chip must be updated + * and the new tack point cube pixel location must be determined prior to + * calling this method. + * + * @return bool True if the new pixel location does not exceed the defined + * tolerance, otherwise returns false. + */ + bool Gruen::CheckAffineTolerance() { + if (_result.ErrorMagnitude() > AffineTolerance()) { + _result.isGood = false; + _result.gerrno = AffineDistExceeded; + _result.gerrmsg = "Affine tolerance exceeded"; + logError(_result.gerrno, _result.gerrmsg); + return (false); + } + return (true); + } + + /** + * @brief Returns the proper status given a Gruen result container + * + * This method will return registration status consistant with + * AutoReg::RegisterStatus return codes. + * + * @param result Gruen result container used to determine status + * @return AutoReg::RegisterStatus Returns AutoReg::Success if the Gruen + * registration is successful, otherwise returns + * AutoReg::AdaptiveAlgorithmFailed. + */ + AutoReg::RegisterStatus Gruen::Status(const GruenResult &result) const { + if (result.IsGood()) { + return (AutoReg::Success); + } + return (AutoReg::AdaptiveAlgorithmFailed); + } +} diff --git a/isis/src/base/objs/Gruen/Gruen.h b/isis/src/base/objs/Gruen/Gruen.h new file mode 100644 index 0000000000000000000000000000000000000000..0d7372a1849c751ecd1d92d6d0cf598f64b0c005 --- /dev/null +++ b/isis/src/base/objs/Gruen/Gruen.h @@ -0,0 +1,317 @@ +#if !defined(Gruen_h) +#define Gruen_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/06/14 20:45:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +#include "AutoReg.h" +#include "GruenResult.h" +#include "DbProfile.h" +#include "CollectorMap.h" +#include "Statistics.h" +#include "PvlGroup.h" + +namespace Isis { + class Pvl; + class Chip; + + /** + * @brief Gruen pattern matching algorithm + * + * This class provides adaptive image (chip) registration using + * the AutoReg factory architecture. This algorithm uses an + * Affine transform to iteratively adjust the search chip at + * each iteration. Each iteration solves for new adjustments to + * the Affine transform until the 6 affine parameters fall below the + * tolerances as specified in AffineThreshHold1 and AffineThreshHold2. + * + * This class minimizes the 6 specifiable Affine transform components of a 3x3 + * matrix. The three Affine components for X (sample) and Y (line) are scale, + * shear and translation. Gruen provides control over the maximum values + * these three components should attain in order for the registration to + * converge to a successful match. These limits are specified + * by AffineScaleTolerance, AffineShearTolerance and + * AffineTranslationTolerance. AffineShearTolerance is + * optional and if not specified, it defaults to the value of + * AffineScaleTolerance. These tolerances specify the maximum amount + * of translation pixels can be shifted between one Gruen iteration and + * another. For example, AffineTranslationTolerance = 0.2 means that a + * subsearch chip cannot move in sample or line direction more than 0.2 pixels + * in order to satisfy convergence. AffineScaleTolerance constrains + * the sample and line scale elements of the Affine transformation. And + * AffineShearTolerance constrains the sample and line shear elements + * of the Affine transformation. The scale and shear parameters are scaled by + * size of the Chip. The sample scale and shear Affine components maximum + * limit is computed as AffineScaleTolerance/((#Samples-1)/2) and + * AffineShearTolerance/((#Samples-1)/2). Likewise, the line scale and + * shear maximums are computed using #Lines in the preceding equation. + * + * @ingroup PatternMatching + * + * @see MinimumGruen AdaptiveGruen AutoReg + * + * @author 2009-09-09 Kris Becker + * + * @internal + * @history 2009-09-10 Kris Becker Changed AffineThreshHold1 to + * AffineTranslationTolerance and AffineThreshHold2 to + * AffineScaleTolerance. Added AffineShearTolerance. Added logging + * of Gruen parameters. + * @history 2009-09-11 Kris Becker Minor error in computation of radiometric + * shift + * @history 2010-06-14 Jeannie Walldren - Capitalized getTransform and + * setTransform to match changes in Chip class + */ + class Gruen : public AutoReg { + public: + /** + * @brief Construct a GruenMinimization search algorithm + * + * This will construct a minimum difference search algorith. It is + * recommended that you use a AutoRegFactory class as opposed to + * this constructor + * + * @param pvl A Pvl object that contains a valid automatic registration + * definition + */ + Gruen(Pvl &pvl); + + //! Destructor + virtual ~Gruen() { } + + /** + * Gruen default mode is adaptive + */ + virtual bool IsAdaptive() { return true; } + + /** Returns the radiometric gain value from the last solution */ + inline double Gain() const { return (_result.Gain()); } + /** Returns the radiometric shift value from the last solution */ + inline double Shift() const { return (_result.Shift()); } + + void SetRadiometrics(const double &gain = 0.0, const double &shift = 0.0); + + /** Returns the SPICE tolerance constraint as read from config file */ + inline double SpiceTolerance() const { return (_spiceTol); } + + /** Returns the Affine tolerance constraint as read from config file */ + inline double AffineTolerance() const { return (_affineTol); } + + GruenResult algorithm (Chip &pattern, Chip &subsearch); + /** Returns the results container from the last solution */ + const GruenResult &Results() const { return (_result); } + + /** Returns status of the last registration result */ + bool IsGood() const { return (IsGood(_result)); } + /** Returns the status of the given Gruen result container */ + bool IsGood(const GruenResult &result) const { return (result.IsGood()); } + + protected: + typedef GSL::GSLUtility::GSLMatrix GSLMatrix; + typedef GSL::GSLUtility::GSLVector GSLVector; + + /** Returns the default name of the algorithm as Gruen */ + virtual std::string AlgorithmName() const {return ("Gruen");} + + bool solve(GruenResult &result); + + // These methods are for AutoReg non-adaptive requirements + virtual double MatchAlgorithm (Chip &pattern, Chip &subsearch); + virtual bool CompareFits(double fit1, double fit2); + /** Returns the ideal fit for a perfect Gruen result */ + virtual double IdealFit() const { return (0.0);} + + // AutoReg adaptive method + virtual AutoReg::RegisterStatus AdaptiveRegistration(Chip &sChip, + Chip &pChip, + Chip &fChip, + int startSamp, + int startLine, + int endSamp, + int endLine, + int bestSamp, + int bestLine); + + virtual Pvl AlgorithmStatistics(Pvl &pvl); + + private: + + /** Error enumeration values */ + enum GruenErrors { NotEnoughPoints = 1, CholeskyFailed = 2, + EigenSolutionFailed = 3, AffineNotInvertable = 4, + MaxIterationsExceeded = 5, RadShiftExceeded = 6, + RadGainExceeded = 7, MaxEigenExceeded = 8, + AffineDistExceeded = 9 }; + + /** Structure that maintains error counts */ + struct ErrorCounter { + ErrorCounter() : _gerrno(0), _keyname("Unknown"), _count(0) { } + ErrorCounter(int gerrno, const std::string &keyname) : _gerrno(gerrno), + _keyname(keyname), _count(0) { } + inline int Errno() const { return (_gerrno); } + inline BigInt Count() const { return (_count); } + inline void BumpIt() { _count++; } + PvlKeyword LogIt() const { return (PvlKeyword(_keyname, _count)); } + int _gerrno; + std::string _keyname; + BigInt _count; + }; + + /// Declaration of error count list + typedef CollectorMap ErrorList; + + DbProfile _prof; + int _maxIters; + double _transTol; + double _scaleTol; + double _shearTol; + + double _affineTol; + double _spiceTol; + + double _rgainMinTol; + double _rgainMaxTol; + double _rshiftTol; + double _fitChipScale; + + // Iteration loop variables + int _nIters; + GruenResult _result; //!< last result, cummulative + BigInt _totalIterations; + ErrorList _errors; + BigInt _unclassified; + + // These are for recomputing SMTK points + double _defGain; + double _defShift; + + // Statistics gathered during process + Statistics _eigenStat; + Statistics _iterStat; + Statistics _shiftStat; + Statistics _gainStat; + + + /** + * @brief Helper method to initialize parameters + * + * This method will check the existance of a keyword and extract the value + + * if it exists to the passed parameter (type). If it doesn't exist, the + * default values is returned. + * + * @param T Templated variable type + * @param conf Parameter profile container + * @param keyname Name of keyword to get a value from + * @param defval Default value it keyword/value doesn't exist + * @param index Optional index of the value for keyword arrays + * + * @return T Return type + */ + template + T ConfKey(const DbProfile &conf, const std::string &keyname, + const T &defval,int index = 0) const { + if (!conf.exists(keyname)) { return (defval); } + if (conf.count(keyname) < index) { return (defval); } + iString iValue(conf.value(keyname, index)); + T value = iValue; // This makes it work with a string? + return (value); + }; + + /** + * @brief Keyword formatter for Gruen parameters + * + * Constructs a keyword with actual user/programmer values if provided, + * otherwise sets the value to "Unbounded". + * + * @param T Type of value to record + * @param keyname Name of keyword to create + * @param value Value to set keyword to if in profile + * @param unit Optional unit value + * + * @return PvlKeyword Constructed keyword for key/value + */ + template + PvlKeyword ParameterKey(const std::string &keyname, + const T &value, + const std::string &unit = "") const { + if (_prof.exists(keyname)) { + return(ValidateKey(keyname, value, unit)); + } + return (PvlKeyword(keyname, "Unbounded")); + }; + + + /** + * @brief Checks value of key, produces appropriate value + * + * This function checks the value of the keyword for specialness + * and will create the appropriate keyword if it is special. + * + * @param keyname Name of keyword to create + * @param value Keyword value + * @param unit Optional unit qualifer with value + * + * @return PvlKeyword Returns newly created keyword/value + */ + inline PvlKeyword ValidateKey(const std::string keyname, + const double &value, + const std::string &unit = "") const { + if (IsSpecial(value)) { + return (PvlKeyword(keyname,"NULL")); + } + else { + return (PvlKeyword(keyname,value,unit)); + } + } + + ErrorList initErrorList() const; + void logError(int gerrno, const std::string &gerrmsg); + PvlGroup StatsLog() const; + PvlGroup ParameterLog() const; + + void init( Pvl &pvl); + /** Returns the default radiometric gain value */ + inline double getDefaultGain() const { return (_defGain); } + /** Returns the default radiometric shift value */ + inline double getDefaultShift() const { return (_defShift); } + void reset(); + void resetStats(); + + GSLVector getThreshHold(const Chip &chip) const; + bool HasConverged(const GSLVector &alpha, const GSLVector &thresh, + const GruenResult &results) const; + BigInt MinValidPoints(BigInt totalPoints) const; + bool ValidPoints(BigInt totalPoints, BigInt nPoints) const; + void ErrorAnalysis(GruenResult &result); + bool TestConstraints(const bool &done, GruenResult &result); + Affine UpdateAffine(GruenResult &result, const Affine >rans); + void UpdateChip(Chip &sChip, const Affine &affine); + bool CheckAffineTolerance(); + AutoReg::RegisterStatus Status(const GruenResult &result) const; + /** Returns status of the last Gruen registration result */ + AutoReg::RegisterStatus Status() const { return (Status(_result)); } + }; + +} // namespace Isis +#endif diff --git a/isis/src/base/objs/Gruen/Gruen.truth b/isis/src/base/objs/Gruen/Gruen.truth new file mode 100644 index 0000000000000000000000000000000000000000..f989bf32059e7b599e6bcba0acd8efceb5b3b2f0 --- /dev/null +++ b/isis/src/base/objs/Gruen/Gruen.truth @@ -0,0 +1,22 @@ +Object = AutoRegistration + Group = Algorithm + Name = Gruen + Tolerance = 100.0 + AffineTranslationTolerance = 0.2 + AffineScaleTolerance = 0.7 + MaximumIterations = 30 + End_Group + + Group = PatternChip + Samples = 15 + Lines = 15 + End_Group + + Group = SearchChip + Samples = 30 + Lines = 30 + End_Group +End_Object +End +Register = 0 +Position = 512.195 512.085 diff --git a/isis/src/base/objs/Gruen/GruenResult.h b/isis/src/base/objs/Gruen/GruenResult.h new file mode 100644 index 0000000000000000000000000000000000000000..6461d625b13f23b1b2acac50d2c981ec19a8b67e --- /dev/null +++ b/isis/src/base/objs/Gruen/GruenResult.h @@ -0,0 +1,243 @@ +#if !defined(GruenResult_h) +#define GruenResult_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/09 23:15:18 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include + +#include "GSLUtility.h" +#include "Affine.h" +#include "Constants.h" + +namespace Isis { + +/** + * @brief GruenResults contains data derived from the Gruen registration process + * + * This struct container maintains a sizeable volume of data produced by the + * Gruen class during registration of a point. It is the return type of the + * interactive registration algorithm. + * + * @author Kris Becker + */ +struct GruenResult { + typedef GSL::GSLUtility::GSLVector GSLVector; + typedef GSL::GSLUtility::GSLMatrix GSLMatrix; + enum { NCONSTR = 8 }; //!< Number solution parameters + + /** + * @brief Default constructor for GruenResult + */ + GruenResult() { init(); } + /** Destructor */ + ~GruenResult() { } + + + /** Returns state of solution - final or iterative */ + inline bool IsGood() const { return (isGood); } + /** Returns the number of paramters/degrees of freedom */ + static int Constraints() { return ((int) NCONSTR); } + /** Returns the number of iterations - final or iteration */ + inline int Iterations() const { return (nIters); } + /** Number of points used in current iteration */ + inline int Points() const { return (npts); } + + /** Returns const reference to Gruen Affine/Gain/Shift parameters */ + inline const GSLVector &Alpha() const { return (alpha); } + + /** Reterns the value of the current state of radiometric gain */ + inline double Gain() const { return (alpha[7]); } + /** Sets initial radiometric gain state */ + void setGain(const double gain) { alpha[7] = gain; } + + /** Returns the value of the current state of radiometric shift */ + inline double Shift() const { return (alpha[6]); } + /** Sets initial value of radiometric shift state */ + void setShift(const double shift) { alpha[6] = shift; } + + /** Returns the residual pixel error of the current iteration */ + inline double Residuals() const { return (resid); } + /** Returns the variance of the pixel error of the current iteration */ + inline double Variance() const { + return (Residuals() / (double) (Points() - Constraints())); + } + + /** Returns the first (largest) eigen value from the Jacobi solution */ + inline double EigenValue1() const { return (eigen[0]); } + /** Returns the second (smaller) eigen value from the Jacobi solution */ + inline double EigenValue2() const { return (eigen[1]); } + /** Returns the eigen value (magnitude) for the Jacobi solution */ + inline double Eigen() const { + return (std::sqrt((eigen[0]*eigen[0])+(eigen[1]*eigen[1]))); + } + + /** Store starting sample, line pixel location in image */ + void setStartImage(const double &ssamp, const double &sline) { + _startSamp = ssamp; + _startLine = sline; + return; + } + + /** Store final starting sample, line pixel location in image */ + void setFinalImage(const double &fsamp, const double &fline) { + _finalSamp = fsamp; + _finalLine = fline; + return; + } + + /** Return sample error in solution */ + inline double SampleError() const { return (_startSamp - _finalSamp); } + + /** Return line error in solution */ + inline double LineError() const { return (_startLine - _finalLine); } + + /** Return the pixel offset error */ + inline double ErrorMagnitude() const { + return (std::sqrt(SampleError()*SampleError() + LineError()*LineError())); + } + + /** Sample shift error as determined by Jacobi solution */ + inline double SampleUncertainty() const { return (skmat[0][0]); } + /** Line shift error as determined by Jacobi solution */ + inline double LineUncertainty() const { return (skmat[1][1]); } + /** Magnitude of pixel shift error from Jacobi solution */ + inline double Uncertainty() const { + double sUnc = SampleUncertainty() * SampleUncertainty(); + double lUnc = LineUncertainty() * LineUncertainty(); + return (std::sqrt(sUnc + lUnc)); } + + + /** Get the final Chip Affine transform for the solution */ + inline Affine getChipTransform() const { return (_chipTransform); } + + /** Set the final Chip Affine tranform found in the solution */ + void setChipTransform(const Affine &affine) { _chipTransform = affine; } + + + /** + * @brief Accumulation of Gruen adaptive interations results + * + * The Gruen algorithm iterates over a set of Chips to determine the best + * fitting adaptive solution. At the end of each interation, the solution + * must be accumlated to comprise the complete result. This method makes the + * necessary updates to a complete result from a single iteration. + * + * + * @param result Single iteration of a Gruen result + */ + void update(const GruenResult &result) { + isGood = result.isGood; + gerrno = result.gerrno; + gerrmsg = result.gerrmsg; + nIters = result.nIters; + npts = result.npts; + resid = result.resid; + ata = result.ata; + atl = result.atl; + kmat = result.kmat; + skmat = result.skmat; + alpha += result.alpha; + eigen = result.eigen; + return; + } + + /** + * @brief Sets final error analysis once the solution converges + * + * This method makes the appropriate updates to an accumlated Gruen result. + * This step is typically recording the error analysis (which is actually done + * at each iteration). These results are used to further apply constraints in + * the determination of a "good" Gruen solution. + * + * + * @param result Final iterative Gruen result with error analysis data + */ + void setErrorAnalysis(const GruenResult &result) { + isGood = result.isGood; + gerrno = result.gerrno; + gerrmsg = result.gerrmsg; + nIters = result.nIters; + npts = result.npts; + resid = result.resid; + ata = result.ata; + atl = result.atl; + kmat = result.kmat; + skmat = result.skmat; + eigen = result.eigen; + } + + // Intermediate solution variables + bool isGood; + int gerrno; + std::string gerrmsg; + + int nIters; + BigInt npts; + double resid; + + // Gruen Match algorithm results + GSLMatrix ata; + GSLVector atl; + GSLMatrix kmat; + GSLMatrix skmat; + GSLVector alpha; + GSLVector eigen; //!< sevals in original code + + Affine _chipTransform; //!< Final chip transfrom + double _startLine, _startSamp; + double _finalLine, _finalSamp; + + /** + * @brief Initialization of this structure + * + * This sets up variables used in the Gruen algorithm. It is expected that + * these parameters be created for immediate use directly in the Gruen class + * so proper sizes and initial values are carefully maintained. + */ + void init() { + isGood = false; + gerrno = 0; + gerrmsg = "none"; + nIters = 0; + npts = 0; + resid = 0.0; + ata = GSLMatrix(NCONSTR, NCONSTR, 0.0); + atl = GSLVector(NCONSTR, 0.0); + kmat = GSLMatrix(NCONSTR, NCONSTR, 0.0); + skmat = GSLMatrix(2, 2, 0.0); + alpha = GSLVector(NCONSTR, 0.0); + eigen = GSLVector(2, 0.0); + + _chipTransform = Affine(); + _startLine = _startSamp = 0.0; + _finalLine = _finalSamp = 0.0; + + return; + } +}; + +} // namespace Isis +#endif diff --git a/isis/src/base/objs/Gruen/Makefile b/isis/src/base/objs/Gruen/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..60bee094d8d8d5dcfbd361dcb45f27dfbadf3e04 --- /dev/null +++ b/isis/src/base/objs/Gruen/Makefile @@ -0,0 +1,7 @@ +INCS = Gruen.h GruenResult.h +SRCS = Gruen.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + + diff --git a/isis/src/base/objs/Gruen/template/coreg.adaptgruen.p1515s3030.def b/isis/src/base/objs/Gruen/template/coreg.adaptgruen.p1515s3030.def new file mode 100644 index 0000000000000000000000000000000000000000..245a4d2689ae84f847c69c2ae36e35c1d5d3540b --- /dev/null +++ b/isis/src/base/objs/Gruen/template/coreg.adaptgruen.p1515s3030.def @@ -0,0 +1,29 @@ + Object = AutoRegistration + Group = Algorithm + Name = AdaptiveGruen + Tolerance = 0.1 + MaximumIterations = 30 + AffineTolerance = 5.0 + AffineTranslationTolerance = 0.2 + AffineScaleTolerance = 0.7 + +# AffineShearTolerance = 0.7 +# SpiceTolerance = 7.0 +# RadioShiftTolerance = 256 +# RadioGainMinTolerance = -0.75 +# RadioGainMaxTolerance = 3.0 +# FitChipScale = 0.1 +# DefaultRadioShift = 0.0 +# DefaultRadioGain = 0.0 + EndGroup + + Group = PatternChip + Samples = 15 + Lines = 15 + EndGroup + + Group = SearchChip + Samples = 30 + Lines = 30 + EndGroup + EndObject diff --git a/isis/src/base/objs/Gruen/unitTest.cpp b/isis/src/base/objs/Gruen/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e702fcb13a716bbb39b013b4589d5815545a7e56 --- /dev/null +++ b/isis/src/base/objs/Gruen/unitTest.cpp @@ -0,0 +1,72 @@ +#include +#include + +#include "AutoReg.h" +#include "Gruen.h" +#include "Chip.h" +#include "Cube.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + try { + PvlGroup alg("Algorithm"); + alg += PvlKeyword("Name","Gruen"); + alg += PvlKeyword("Tolerance",100.0); + alg += PvlKeyword("AffineTranslationTolerance",0.2); + alg += PvlKeyword("AffineScaleTolerance",0.7); + alg += PvlKeyword("MaximumIterations",30); + + PvlGroup pchip("PatternChip"); + pchip += PvlKeyword("Samples",15); + pchip += PvlKeyword("Lines",15); + + PvlGroup schip("SearchChip"); + schip += PvlKeyword("Samples",30); + schip += PvlKeyword("Lines",30); + + PvlObject o("AutoRegistration"); + o.AddGroup(alg); + o.AddGroup(pchip); + o.AddGroup(schip); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl; + + Gruen gruen(pvl); + + Cube p; + p.Open("$messenger/testData/EW0131770376G.equi.cub"); + + Cube s; + s.Open("$messenger/testData/EW0131770381F.equi.cub"); + + gruen.SearchChip()->TackCube(512.0, 512.0); + gruen.SearchChip()->Load(s); + gruen.PatternChip()->TackCube(512.0, 512.0); + gruen.PatternChip()->Load(p); + + std::cout << "Register = " << gruen.Register() << std::endl; + std::cout << "Position = " << gruen.CubeSample() << " " << + gruen.CubeLine() << std::endl; + + +#if defined(FULL_DISCLOSURE) + Pvl pstat = gruen.RegistrationStatistics(); + std::cout << "\n\n" << pstat << std::endl; +#endif + + + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/Gui/Gui.cpp b/isis/src/base/objs/Gui/Gui.cpp new file mode 100644 index 0000000000000000000000000000000000000000..84ebdeaf112da773b06e30feaf0e036e6b5703f7 --- /dev/null +++ b/isis/src/base/objs/Gui/Gui.cpp @@ -0,0 +1,829 @@ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Gui.h" +#include "UserInterface.h" +#include "Preference.h" +#include "iString.h" +#include "iException.h" +#include "Application.h" +#include "PvlObject.h" +#include "PvlGroup.h" +#include "Pvl.h" +#include "SessionLog.h" +#include "Filename.h" + +namespace Isis { + + //! Singleton + Gui *Gui::p_gui = NULL; + Gui *Gui::Create (Isis::UserInterface &ui, int &argc, char *argv[]) { + // Don't recreate + if (p_gui != NULL) return p_gui; + + // Get preferences + PvlGroup &uiPref = Preference::Preferences().FindGroup("UserInterface"); + + // Create the application + new QApplication (argc, argv); + QApplication::setQuitOnLastWindowClosed(true); + + Isis::Filename qtpluginpath ("$ISISROOT/3rdParty/plugins"); + QCoreApplication::addLibraryPath(qtpluginpath.Expanded().c_str()); + + + // Qt is smart enough to use the style of the system running the program. + // However, Isis supports overriding this with a setting in IsisPreferences. + // Here we check to see if this has been done and force the style if needed. + if (uiPref.HasKeyword("GuiStyle")) + { + std::string style = uiPref["GuiStyle"]; + QApplication::setStyle((iString)style); + } + + // Create the main window + p_gui = new Gui(ui); + p_gui->show(); + + return p_gui; + } + + //! Constructor + Gui::Gui(Isis::UserInterface &ui) : QMainWindow (0,Qt::Window) { + // Create the toolbar and menu and populate them with actions + CreateAreas (); + + // Add parameters to the main area + for (int group=0; groupUpdate(); + connect(param,SIGNAL(ValueChanged()),this,SLOT(UpdateCommandLine())); + } + + + // Make the horizontal direction in the scrolling widget non-stretchable + p_scrollLayout->addStretch(1); + + // Setup status bar + p_progressBar = new QProgressBar(); + p_progressBar->setMinimum(0); + p_progressBar->setMaximum(100); + p_progressBar->setValue(0); + p_progressBar->setMinimumWidth(200); + + p_statusText = new QLabel("Ready"); + + statusBar()->setSizeGripEnabled(true); + statusBar()->addWidget(p_progressBar,0); + statusBar()->addWidget(p_statusText,3); + + // Setup the current history pointer + p_historyEntry = -1; + + } + + //! Destructor + Gui::~Gui() { + for(unsigned int i = 0; i < p_parameters.size(); i++) { + delete p_parameters[i]; + } + + p_parameters.clear(); + } + + // Create the main widget, menus, toolbars, status, actions + void Gui::CreateAreas () { + // Create the main area + QSplitter *split = new QSplitter (Qt::Vertical, this); + + // Add a scrolled area for the parameters to the splitter + p_scrollArea = new QScrollArea (); + p_scrollWidget = new QWidget(); + p_scrollLayout = new QVBoxLayout; + p_scrollWidget->setLayout(p_scrollLayout); + p_scrollArea->setWidget(p_scrollWidget); + p_scrollArea->setWidgetResizable(true); + + // Set the scroll area size + int height = QApplication::desktop()->height(); + + // Add the log area to the bottom of the spliter + p_log = new GuiLog (); + p_log->setMinimumHeight(10); + p_log->resize(p_log->width(), 250); + + split->addWidget(p_scrollArea); + split->addWidget(p_log); + split->setChildrenCollapsible(false); + split->setStretchFactor(0,3); + split->setStretchFactor(1,0); + setCentralWidget (split); + resize(720, (int)(height / 2) + 350); + + // Create all the actions for menus, toolbars... + p_processAction = CreateProcessAction(); + p_stopAction = CreateStopAction(); + p_exitAction = CreateExitAction(); + + p_previousHistoryAction = CreatePreviousHistoryAction(); + p_nextHistoryAction = CreateNextHistoryAction(); + p_resetAction = CreateResetAction(); + + p_saveLogAction = CreateSaveLogAction(); + p_clearLogAction = CreateClearLogAction(); + + QAction *whatsThisAction = CreateWhatsThisAction(); + + // Create the File menu + QMenu *fileMenu = menuBar()->addMenu("&File"); + fileMenu->addAction(p_processAction); + fileMenu->addAction(p_stopAction); + fileMenu->addAction(p_exitAction); + + // Create the Options menu + QMenu *optionsMenu = menuBar()->addMenu("&Options"); + optionsMenu->addAction(p_resetAction); + optionsMenu->addAction(p_previousHistoryAction); + optionsMenu->addAction(p_nextHistoryAction); + optionsMenu->addAction(p_saveLogAction); + optionsMenu->addAction(p_clearLogAction); + + // Create the Controls Toolbar + QToolBar *tb = addToolBar("Controls"); + tb->setIconSize(QSize(22,22)); + tb->addAction(p_processAction); + tb->addAction(p_stopAction); + tb->addAction(p_exitAction); + tb->addSeparator(); + + tb->addAction(p_previousHistoryAction); + tb->addAction(p_nextHistoryAction); + tb->addAction(p_resetAction); + tb->addSeparator(); + + tb->addAction(p_saveLogAction); + tb->addAction(p_clearLogAction); + tb->addSeparator(); + + tb->addAction(whatsThisAction); + + QAction *showControls = new QAction(this); + showControls->setText("Controls"); + showControls->setCheckable(true); + connect(showControls,SIGNAL(toggled(bool)),tb,SLOT(setVisible(bool))); + + tb->installEventFilter(this); + + // Create the command line toolbar + tb = new QToolBar("Command Line"); + addToolBar(Qt::BottomToolBarArea,tb); + tb->setIconSize(QSize(22,22)); + tb->setAllowedAreas(Qt::BottomToolBarArea); + p_commandLineEdit = new QLineEdit(tb); + p_commandLineEdit->setReadOnly(true); + tb->addWidget(p_commandLineEdit); + QAction *showCommandLine = new QAction(this); + showCommandLine->setText("Command Line"); + showCommandLine->setCheckable(true); + connect(showCommandLine,SIGNAL(toggled(bool)),tb,SLOT(setVisible(bool))); + //tb->hide(); + + // Create the view menu + QMenu *viewMenu = menuBar()->addMenu("&View"); + viewMenu->addAction(showControls); + viewMenu->addAction(showCommandLine); + showControls->setChecked(true); + showCommandLine->setChecked(true); + + // Create the Help menu + QMenu *helpMenu = menuBar()->addMenu("&Help"); + helpMenu->addAction(whatsThisAction); + + QAction *aboutProgram = new QAction(this); + aboutProgram->setText("About this program"); + aboutProgram->setShortcut(Qt::CTRL+Qt::Key_H); + helpMenu->addAction(aboutProgram); + connect(aboutProgram,SIGNAL(triggered(bool)),this,SLOT(AboutProgram())); + + QAction *aboutIsis = new QAction(this); + aboutIsis->setText("About Isis"); + aboutIsis->setShortcut(Qt::CTRL+Qt::Key_I); + helpMenu->addAction(aboutIsis); + connect(aboutIsis,SIGNAL(triggered(bool)),this,SLOT(AboutIsis())); + } + + + // Create the "Begin/Start Processing" action + QAction *Gui::CreateProcessAction () { + QAction *processAction = new QAction (this); + QString baseDir = (iString)Filename("$BASE/icons").Expanded(); + processAction->setIcon (QPixmap(baseDir+"/guiRun.png")); + processAction->setText ("&Run"); + processAction->setToolTip ("Run"); + QString processActionWhatsThisText = "

    Function: \ + Runs the application with the current parameters

    \ +

    Shortcut: Ctrl+R

    "; + processAction->setShortcut(Qt::CTRL+Qt::Key_R); + processAction->setWhatsThis(processActionWhatsThisText); + + connect(processAction,SIGNAL(triggered(bool)),this,SLOT(StartProcess())); + + return processAction; + } + + /** + * The user pressed the go button + * + * @internal + * @history 2007-05-16 Tracie Sucharski - Change cursor to wait while + * processing. + * + */ + void Gui::StartProcess () { + p_processAction->setEnabled(false); + ProgressText ("Working"); + Progress(0); + p_stop = false; + + Isis::UserInterface &ui = Isis::iApp->GetUserInterface(); + + // Pull the values from the parameters and put them into the Aml + for (int p=0; p<(int)p_parameters.size(); p++) { + GuiParameter ¶m = *(p_parameters[p]); + ui.Clear(param.Name()); + if (param.IsEnabled() && param.IsModified()) { + Isis::iString value = param.Value(); + value.ConvertWhiteSpace(); + value.Compress(); + value.Trim(" "); + if (value.length() > 0) { + ui.PutAsString(param.Name(),value); + } + } + } + + // Make sure the parameters were valid + // Call the application's main + ProcessEvents(); + try { + ui.VerifyAll (); + ui.SaveHistory(); + Isis::SessionLog::TheLog(true); + QApplication::setOverrideCursor(Qt::WaitCursor); + (*p_funct) (); // Call IsisMain + QApplication::restoreOverrideCursor(); + Isis::iApp->FunctionCleanup(); + + // Display the parameters incase the app changed one or more + for (int p=0; p<(int)p_parameters.size (); p++) { + GuiParameter ¶m = *(p_parameters[p]); + param.Update(); + } + + Progress(100); + ProgressText ("Done"); + } + catch (Isis::iException &e) { + QApplication::restoreOverrideCursor(); + if (e.Type() == Isis::iException::Cancel) { + e.Clear (); + ProgressText ("Stopped"); + } + else { + Isis::iApp->FunctionError(e); + if (ShowWarning ()) exit (0); + ProgressText ("Error"); + } + } + + p_processAction->setEnabled(true); + } + + // Create the "Exit" action + QAction *Gui::CreateExitAction () { + QAction *exitAction = new QAction (this); + QString baseDir = (iString)Filename("$BASE/icons").Expanded(); + exitAction->setIcon (QPixmap(baseDir+"/guiExit.png")); + exitAction->setText ("&Exit"); + exitAction->setToolTip ("Exit"); + QString exitWhatsThisText = "

    Function: \ + Closes the program window

    Shortcut: Ctrl+Q

    "; + exitAction->setWhatsThis(exitWhatsThisText); + exitAction->setShortcut(Qt::CTRL+Qt::Key_Q); + connect (exitAction,SIGNAL(triggered()),qApp,SLOT(quit())); + return exitAction; + } + + // Create the "Reset" action + QAction *Gui::CreateResetAction () { + QAction *resetAction = new QAction (this); + QString baseDir = (iString)Filename("$BASE/icons").Expanded(); + resetAction->setIcon (QPixmap(baseDir+"/guiReset.png")); + resetAction->setText ("&Reset"); + resetAction->setToolTip ("Reset parameters"); + QString resetWhatsThisText = "

    Function: \ + Resets the application parameters to their default values

    \ +

    Shortcut: F3

    "; + resetAction->setWhatsThis(resetWhatsThisText); + resetAction->setShortcut(Qt::Key_F3); + connect (resetAction,SIGNAL(triggered()),this,SLOT(ResetParameters())); + + return resetAction; + } + + // Create the "Stop" action + QAction *Gui::CreateStopAction () { + QAction *stopAction = new QAction (this); + QString baseDir = (iString)Filename("$BASE/icons").Expanded(); + stopAction->setIcon (QPixmap(baseDir+"/guiStop.png")); + stopAction->setText ("&Stop"); + stopAction->setToolTip ("Stop"); + QString stopWhatsThisText = "

    Function: \ + Stops the application from running

    \ +

    Shortcut: Ctrl+E

    "; + stopAction->setShortcut(Qt::CTRL+Qt::Key_E); + stopAction->setWhatsThis(stopWhatsThisText); + connect (stopAction,SIGNAL(triggered()),this,SLOT(StopProcessing())); + + return stopAction; + } + + // Create the "SaveLog" action + QAction *Gui::CreateSaveLogAction () { + QAction *saveLogAction = new QAction (this); + QString baseDir = (iString)Filename("$BASE/icons").Expanded(); + saveLogAction->setIcon (QPixmap(baseDir+"/guiSaveLog.png")); + saveLogAction->setText ("&Save Log..."); + saveLogAction->setToolTip ("Save log"); + QString saveWhatsThisText = "

    Function: Saves the information \ + currently in the log area to a file

    Shortcut: Ctrl+S

    "; + saveLogAction->setWhatsThis(saveWhatsThisText); + saveLogAction->setShortcut(Qt::CTRL+Qt::Key_S); + connect (saveLogAction,SIGNAL(triggered(bool)),p_log,SLOT(Save())); + + return saveLogAction; + } + + // Create the "ClearLog" action + QAction *Gui::CreateClearLogAction () { + QAction *clearlogAction = new QAction (this); + QString baseDir = (iString)Filename("$BASE/icons").Expanded(); + clearlogAction->setIcon (QPixmap(baseDir+"/guiClearLog.png")); + clearlogAction->setText ("&Clear Log"); + clearlogAction->setToolTip ("Clear log"); + QString clearWhatsThisText = "

    Function: Clears all information \ + from the log area at the bottom of the application screen

    \ +

    Shortcut: Ctrl+L

    "; + clearlogAction->setWhatsThis(clearWhatsThisText); + clearlogAction->setShortcut(Qt::CTRL+Qt::Key_L); + connect (clearlogAction,SIGNAL(triggered(bool)),p_log,SLOT(Clear())); + + return clearlogAction; + } + + // Create the "Previous History" action + QAction *Gui::CreatePreviousHistoryAction () { + QAction *previousHistoryAction = new QAction (this); + QString baseDir = (iString)Filename("$BASE/icons").Expanded(); + previousHistoryAction->setIcon (QPixmap(baseDir+"/guiPrevHistory.png")); + previousHistoryAction->setText ("&Previous"); + previousHistoryAction->setToolTip ("Previous parameters"); + QString previousWhatsThisText = "

    Function: Fills in parameter \ + values using the previous history entry

    \ +

    Shortcut: F5

    "; + previousHistoryAction->setWhatsThis(previousWhatsThisText); + previousHistoryAction->setShortcut(Qt::Key_F5); + connect (previousHistoryAction,SIGNAL(triggered()),this,SLOT(PreviousHistory())); + + return previousHistoryAction; + } + + // Create the "Next History" action + QAction *Gui::CreateNextHistoryAction () { + QAction *nextHistoryAction = new QAction (this); + QString baseDir = (iString)Filename("$BASE/icons").Expanded(); + nextHistoryAction->setIcon (QPixmap(baseDir+"/guiNextHistory.png")); + nextHistoryAction->setText ("&Next"); + nextHistoryAction->setToolTip ("Next parameters"); + QString nextWhatsThisText = "

    Function: Fills in parameter \ + values using the next history entry

    \ +

    Shortcut: F6

    "; + nextHistoryAction->setWhatsThis(nextWhatsThisText); + nextHistoryAction->setShortcut(Qt::Key_F6); + connect (nextHistoryAction,SIGNAL(triggered()),this,SLOT(NextHistory())); + + return nextHistoryAction; + } + + // Create the Whats Action action + QAction *Gui::CreateWhatsThisAction () { + QAction *action = new QAction (this); + QString baseDir = (iString)Filename("$BASE/icons").Expanded(); + action->setIcon (QPixmap(baseDir+"/contexthelp.png")); + action->setText ("&What's This"); + action->setToolTip ("What's This"); + QString whatsThisText = "

    Function: Use this to get longer \ + descriptions of button functions and parameter information

    \ +

    Shortcut: Shift+F1

    "; + action->setWhatsThis(whatsThisText); + action->setShortcut(Qt::SHIFT+Qt::Key_F1); + connect(action,SIGNAL(triggered(bool)),this,SLOT(WhatsThis())); + + return action; + } + + // Add a new parameter to this main window + GuiParameter* Gui::AddParameter (Isis::UserInterface &ui, int group, int param) { + // Create the group box if this is the first parameter in the group + QGridLayout *gridLayout = NULL; + if (!p_grids.contains(ui.GroupName(group))) { + // Create a new groupbox and add it to the scroll layout + QGroupBox *groupBox = new QGroupBox ((iString)ui.GroupName(group)); + p_scrollLayout->addWidget(groupBox); + groupBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + groupBox->setAlignment(Qt::AlignHCenter); + + // Create a gridlayout for the new groupbox and save it + gridLayout = new QGridLayout; + gridLayout->setColumnStretch(0, 0); + gridLayout->setColumnStretch(1, 0); + gridLayout->setColumnMinimumWidth(1,10); + gridLayout->setColumnStretch(2, 10); + groupBox->setLayout(gridLayout); + p_grids[ui.GroupName(group)] = gridLayout; + } + // Find the group box for this parameter + else { + gridLayout = p_grids[ui.GroupName(group)]; + } + + GuiParameter *p = GuiParameterFactory::Create(gridLayout, ui, group, param); + connect(p,SIGNAL(ValueChanged()),this,SLOT(UpdateExclusions())); + connect(p,SIGNAL(HelperTrigger(const QString &)), + this,SLOT(InvokeHelper(const QString &))); + return p; + } + + //! Change progress text + void Gui::ProgressText (const std::string &text) { + p_statusText->setText((iString)text); + qApp->processEvents(); // Needed when programs run programs + } + + //! Update the progress bar + void Gui::Progress (int percent) { + p_progressBar->setValue(percent); + qApp->processEvents(); // Needed when programs run programs + } + + /** + * Start the Gui and enter the main loop + * This routine only returns when the program is ready to exit + */ + int Gui::Exec (void (*funct)()) { + p_funct = funct; + return qApp->exec(); + } + + //! Add more information to the error message + void Gui::LoadMessage (const std::string &message) { + // Convert newlines to breaks + std::string m = message; + while (m.find("\n") != std::string::npos) { + m.replace(m.find("\n"),1,"
    "); + } + + // If there is a set of "[]" change everything between them to red text + if ((message.find ("[") >= 0) && + (message.rfind ("]") < message.size()) && + (message.find ("[") < message.rfind ("]"))) { + + int indx = 0; + while (m.find ("[", indx) != std::string::npos) { + m.insert (m.find ("[",indx) + 1, ""); + m.insert (m.find ("]",indx), ""); + indx = m.find ("]", indx) + 1; + } + } + p_errorString += (QString)(iString)m; + } + + //! Show an error message and return if the user wants to continue/abort + int Gui::ShowWarning() { + Isis::UserInterface &ui = Isis::iApp->GetUserInterface(); + int status = QMessageBox::warning (this, + (iString)ui.ProgramName(), + p_errorString, + "Ok", "Abort", "", 0, 1); + p_errorString.clear(); + return status; + } + + //! Write text to the gui log + void Gui::Log (const std::string &text) { + QString s = (iString)text; + p_log->Write(s); + } + + //! Reset the Progress bar when the user moves the mouse onto the toolbar + bool Gui::eventFilter(QObject *o, QEvent *e) { + if (e->type() == QEvent::Enter) { + if (p_processAction->isEnabled()) { + ProgressText ("Ready"); + Progress(0); + } + } + return FALSE; + } + + //! The user pressed the stop button ... see what they want to do + void Gui::StopProcessing() { + if (p_processAction->isEnabled()) return; + + Isis::UserInterface &ui = Application::GetUserInterface(); + switch (QMessageBox::information (this, + (iString)ui.ProgramName(), + QString("Program suspended, choose to ") + + QString("continue processing, stop ") + + QString("processing or exit the program"), + "Continue", + "Stop", + "Exit",0,2)) { + case 0: // Pressed continue + break; + + case 1: // Pressed stop + p_stop = true; + break; + + case 2: // Pressed exit + p_stop = true; + qApp->quit(); + } + } + + /** Let the event loop have some time to see if we need to cancel. + * This is normally called by the Isis::Progress class. + */ + bool Gui::ProcessEvents () { + qApp->processEvents(); + return p_stop; + } + + //! Reset the parameters fields to the defaults + void Gui::ResetParameters() { + // Clear the AML to default values + Isis::UserInterface &ui = Application::GetUserInterface(); + for (int p=0; p<(int)p_parameters.size(); p++) { + GuiParameter ¶m = *(p_parameters[p]); + ui.Clear(param.Name()); + } + + // Display the updated parameters + for (int p=0; p<(int)p_parameters.size (); p++) { + GuiParameter ¶m = *(p_parameters[p]); + param.Update(); + } + } + + //! Goto the next history entry + void Gui::NextHistory() { + p_historyEntry--; + UpdateHistory(); + } + + //! Goto the previous history entry + void Gui::PreviousHistory() { + p_historyEntry++; + UpdateHistory(); + } + + //! Changed the parameters based on the history pointer + void Gui::UpdateHistory() { + if (p_historyEntry < -1) { + p_historyEntry = -1; + QApplication::beep(); + return; + } + + if (p_historyEntry == -1) { + ResetParameters(); + return; + } + + // Find out if this application has a history file + Isis::UserInterface &ui = Application::GetUserInterface(); + Preference &p = Preference::Preferences(); + + PvlGroup &grp = p.FindGroup("UserInterface", Isis::Pvl::Traverse); + Isis::Filename progHist(grp["HistoryPath"][0] + "/" + ui.ProgramName() + ".par"); + + if (!progHist.Exists()) { + p_historyEntry = -1; + QApplication::beep(); + return; + } + + Isis::Pvl hist; + + try { + hist.Read(progHist.Expanded()); + } + catch(...) { + p_historyEntry = -1; + std::string msg = "A corrupt parameter history file [" + progHist.Expanded() + + "] has been detected. Please fix or remove this file"; + LoadMessage(msg); + if (ShowWarning ()) exit (0); + return; + } + + int entries = 0; + for (int i=0; i excludeList = param.Exclusions(); + for (int i=0; i<(int)excludeList.size(); i++) { + for (unsigned int e=0; esetText(cline.c_str()); + } + + //! Update Parameters + void Gui::UpdateParameters() { + for (unsigned int p=0; p> /dev/null &"; + system (command.c_str()); + } + + // Show help for the current app + void Gui::AboutProgram () { + Isis::Filename file((std::string) + "$ISISROOT/doc/Application/presentation/PrinterFriendly/" + + Isis::Application::GetUserInterface().ProgramName() + + "/" + + Isis::Application::GetUserInterface().ProgramName() + + ".html"); + + Isis::PvlGroup &uig = Isis::Preference::Preferences().FindGroup("UserInterface"); + std::string command = (std::string) uig["GuiHelpBrowser"] + + (std::string)" file:" + file.Expanded() + " &"; + system (command.c_str()); + } + + //! Activate helper buttons + void Gui::InvokeHelper(const QString &funct) { + p_processAction->setEnabled(false); + try { + Isis::UserInterface &ui = Application::GetUserInterface(); + + // Pull the values from the parameters and put them into the Aml + for (int p=0; p<(int)p_parameters.size(); p++) { + GuiParameter ¶m = *(p_parameters[p]); + ui.Clear(param.Name()); + if (param.IsEnabled() && param.IsModified()) { + Isis::iString value = param.Value(); + value.ConvertWhiteSpace(); + value.Compress(); + value.Trim(" "); + if (value.length() > 0) { + ui.PutAsString(param.Name(),value); + } + } + } + + // Get the helper function and run + void* ptr = Isis::iApp->GetGuiHelper(funct.toStdString()); + void (*helper)(); + helper = (void (*)())ptr; + helper(); + } + catch (Isis::iException &e) { + Isis::iApp->GuiReportError(e); + } + + // Update parameters in GUI + UpdateParameters(); + p_processAction->setEnabled(true); + } + +} diff --git a/isis/src/base/objs/Gui/Gui.h b/isis/src/base/objs/Gui/Gui.h new file mode 100644 index 0000000000000000000000000000000000000000..d5dbb729f1f099a2165437aae4882f5ea6b7a597 --- /dev/null +++ b/isis/src/base/objs/Gui/Gui.h @@ -0,0 +1,167 @@ +#ifndef Isis_GuiMainWindow_h +#define Isis_GuiMainWindow_h + +/** + * @file + * $Revision: 1.6 $ + * $Date: 2010/03/17 15:50:24 $ + + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PvlObject.h" +#include "PvlGroup.h" + +#include "GuiLog.h" +#include "GuiParameter.h" +#include "GuiParameterFactory.h" + +namespace Isis { +/** + * @brief Gui for Isis Applications + * + * This is the main GUI for all Isis Applications. + * + * @author 2003-01-01 Stuart Sides + * + * @internal + * @history 2007-07-19 Steven Lambright Fixed bugs: Command Line not checked + * but displayed initially and Command Line edit was not + * read only. + * @history 2008-06-06 Steven Lambright Fixed bug with corrupt parameter + * history file causing the program to crash + * @history 2008-07-29 Steven Lambright Fixed memory leaks and naming + * convention + * @history 2009-11-19 Kris Becker - Made argc pass by reference since Qt's + * QApplication/QCoreApplication requires it + * @history 2010-03-17 Stuart Sides - Added the location of the Qt plugins + * into the library path + */ + + class Gui : public QMainWindow { + Q_OBJECT + + public: + static Gui *Create (Isis::UserInterface &ui, int &argc, char *argv[]); + + void ProgressText (const std::string &text); + void Progress (int percent); + + int Exec (void (*funct)()); + bool ProcessEvents (); + + void LoadMessage (const std::string &message); + int ShowWarning (); + + void ShowLog () {}; + void Log (const std::string &text); + + Gui (Isis::UserInterface &ui); + ~Gui (); + + bool eventFilter(QObject *o, QEvent *e); + + public slots: + + private: + static Gui *p_gui; + + GuiParameter* AddParameter (Isis::UserInterface &ui, int group, int param); + void Preferences (); + void CreateAreas (); + + QAction *CreateProcessAction (); + QAction *CreateStopAction (); + QAction *CreateExitAction (); + QAction *CreateResetAction (); + QAction *CreatePreviousHistoryAction (); + QAction *CreateNextHistoryAction (); + QAction *CreateSaveLogAction (); + QAction *CreateClearLogAction (); + QAction *CreateWhatsThisAction (); + + void (*p_funct)(); // Function to be called for procesing phase + + QScrollArea *p_scrollArea; // Scrolling area for parameter group boxes + QWidget *p_scrollWidget; // Widget with layout for group boxes + QVBoxLayout *p_scrollLayout; // Layout for all parameter group boxes + + QLabel *p_statusText; + QProgressBar *p_progressBar; + GuiLog *p_log; + + QAction *p_processAction; + QAction *p_exitAction; + QAction *p_stopAction; + QAction *p_resetAction; + QAction *p_saveLogAction; + QAction *p_clearLogAction; + QAction *p_previousHistoryAction; + QAction *p_nextHistoryAction; + + QMap p_grids; + + std::vector p_parameters; + + QString p_errorString; + bool p_stop; + + void UpdateHistory(); + int p_historyEntry; + + QLineEdit *p_commandLineEdit; + + private slots: + void StartProcess (); + void StopProcessing(); + + void ResetParameters(); + + void NextHistory(); + void PreviousHistory(); + + void UpdateExclusions(); + void UpdateCommandLine(); + void UpdateParameters(); + + void WhatsThis(); + void AboutProgram(); + void AboutIsis(); + + void InvokeHelper(const QString &funct); + }; +}; + + + +#endif diff --git a/isis/src/base/objs/Gui/Gui.truth b/isis/src/base/objs/Gui/Gui.truth new file mode 100644 index 0000000000000000000000000000000000000000..458188724c30ec895f98f760a0d3e716bf773742 --- /dev/null +++ b/isis/src/base/objs/Gui/Gui.truth @@ -0,0 +1 @@ +Replace this when we decide how to do unit tests for interactive objects diff --git a/isis/src/base/objs/Gui/GuiBooleanParameter.cpp b/isis/src/base/objs/Gui/GuiBooleanParameter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a685d6c6fa35a9feaed305808e8401252bffca0 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiBooleanParameter.cpp @@ -0,0 +1,87 @@ +#include +#include +#include "UserInterface.h" + +#include "GuiBooleanParameter.h" + + +namespace Isis { + + GuiBooleanParameter::GuiBooleanParameter(QGridLayout *grid, UserInterface &ui, + int group, int param) : + GuiParameter(grid, ui, group, param) { + + p_checkBox = new QCheckBox((iString)ui.ParamBrief(group, param)); + + grid->addWidget(p_checkBox,param,2); + + RememberWidget(p_checkBox); + connect(p_checkBox,SIGNAL(toggled(bool)),this,SIGNAL(ValueChanged())); + + if (p_ui->HelpersSize(group,param) != 0) { + grid->addWidget(AddHelpers(p_checkBox),param,3); + } + + p_type = BooleanWidget; + } + + + GuiBooleanParameter::~GuiBooleanParameter() {} + + + void GuiBooleanParameter::Set (iString newValue) { + p_checkBox->setChecked(p_ui->StringToBool(newValue)); + emit ValueChanged(); + } + + + iString GuiBooleanParameter::Value () { + return p_checkBox->isChecked() ? "YES" : "NO"; + } + + std::vector GuiBooleanParameter::Exclusions() { + std::vector list; + + // Exclude exclusions or inclusions + if (Value() == "YES") { + for (int i=0; iParamExcludeSize(p_group,p_param); i++) { + std::string s = p_ui->ParamExclude(p_group,p_param,i); + list.push_back(s); + } + } + else { + for (int i=0; iParamIncludeSize(p_group,p_param); i++) { + std::string s = p_ui->ParamInclude(p_group,p_param,i); + list.push_back(s); + } + } + + return list; + } + + //! Return if the parameter value is different from the default value + bool GuiBooleanParameter::IsModified() { + if (!IsEnabled()) return false; + iString value; + if (p_ui->ParamDefault (p_group, p_param).size() > 0) { + value = p_ui->ParamDefault(p_group,p_param); + } + else { + value = "NO"; + } + + value.UpCase(); + if (value == "0") value = "NO"; + if (value == "FALSE") value = "NO"; + if (value == "N") value = "NO"; + if (value == "OFF") value = "NO"; + if (value == "1") value = "YES"; + if (value == "TRUE") value = "YES"; + if (value == "Y") value = "YES"; + if (value == "ON") value = "YES"; + + if (Value() == value) return false; + return true; + } +} + diff --git a/isis/src/base/objs/Gui/GuiBooleanParameter.h b/isis/src/base/objs/Gui/GuiBooleanParameter.h new file mode 100644 index 0000000000000000000000000000000000000000..a7e9f21769dc742a81b2aba1c85b8e5b69233df6 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiBooleanParameter.h @@ -0,0 +1,38 @@ + +#ifndef Isis_GuiBooleanParameter_h +#define Isis_GuiBooleanParameter_h + +#include + +#include "GuiParameter.h" + + +namespace Isis { + + class GuiBooleanParameter : public GuiParameter { + + Q_OBJECT + + public: + + GuiBooleanParameter (QGridLayout *grid, UserInterface &ui, + int group, int param); + ~GuiBooleanParameter (); + + iString Value (); + + void Set (iString newValue); + + virtual std::vector Exclusions(); + + bool IsModified(); + + private: + QCheckBox *p_checkBox; + }; +}; + + + +#endif + diff --git a/isis/src/base/objs/Gui/GuiCubeParameter.cpp b/isis/src/base/objs/Gui/GuiCubeParameter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d3383d672eb4c264bc101c3d46613d6953cbb27e --- /dev/null +++ b/isis/src/base/objs/Gui/GuiCubeParameter.cpp @@ -0,0 +1,239 @@ +/** + * @file + * $Revision: 1.12 $ + * $Date: 2010/01/06 19:40:17 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GuiCubeParameter.h" + +#include "Application.h" +#include "Cube.h" +#include "Filename.h" +#include "Preference.h" +#include "GuiInputAttribute.h" +#include "GuiOutputAttribute.h" +#include "iException.h" +#include "Pvl.h" +#include "System.h" +#include "UserInterface.h" + + +namespace Isis { + + GuiCubeParameter::GuiCubeParameter(QGridLayout *grid, UserInterface &ui, + int group, int param) : + GuiFilenameParameter(grid, ui, group, param) { + p_menu = new QMenu (); + + QAction *fileAction = new QAction(this); + fileAction->setText("Select Cube"); + connect(fileAction,SIGNAL(triggered(bool)),this,SLOT(SelectFile())); + p_menu->addAction(fileAction); + + QAction *attAction = new QAction(this); + attAction->setText("Change Attributes ..."); + connect(attAction,SIGNAL(triggered(bool)),this,SLOT(SelectAttribute())); + p_menu->addAction(attAction); + + QAction *viewAction = new QAction(this); + viewAction->setText("View cube"); + connect(viewAction,SIGNAL(triggered(bool)),this,SLOT(ViewCube())); + p_menu->addAction(viewAction); + + QAction *labAction = new QAction(this); + labAction->setText("View labels"); + connect(labAction,SIGNAL(triggered(bool)),this,SLOT(ViewLabel())); + p_menu->addAction(labAction); + + p_fileButton->setMenu(p_menu); + p_fileButton->setPopupMode(QToolButton::MenuButtonPopup); + QString optButtonWhatsThisText = "

    Function: \ + Opens a file chooser window to select a file from

    \ + Hint: Click the arrow for more cube parameter options

    "; + p_fileButton->setWhatsThis(optButtonWhatsThisText); + + p_type = CubeWidget; + } + + + GuiCubeParameter::~GuiCubeParameter() { + delete p_menu; + } + + + /** + * Gets an input/output file from a GUI filechooser or typed in + * filename. + * + * @internal + * @history 2007-05-16 Tracie Sucharski - For cubes located in CWD, do + * not include path in the lineEdit. + * @history 2007-06-05 Steven Koechle - Corrected problem where + * output cube was being opened not + * saved. + */ + void GuiCubeParameter::SelectFile() { + // What directory do we look in? + QString dir; + if ((p_lineEdit->text().length() > 0) && + (p_lineEdit->text().toStdString() != p_ui->ParamInternalDefault(p_group,p_param))) { + Isis::Filename f(p_lineEdit->text().toStdString()); + dir = (QString)(iString)f.Expanded(); + } else if (p_ui->ParamPath(p_group,p_param).length() > 0) { + Isis::Filename f(p_ui->ParamPath(p_group,p_param)); + dir = (QString)(iString)Filename(p_ui->ParamPath(p_group,p_param)).Expanded(); + } + + // Set up the filter + QString filter = (iString)p_ui->ParamFilter(p_group,p_param); + if (filter.isEmpty()) { + filter = "Any(*)"; + } + else { + filter += ";;Any(*)"; + } + + + // Get the filename + QString s; + if (p_ui->ParamFileMode(p_group,p_param) == "input") { + s = QFileDialog::getOpenFileName(p_fileButton,"Select file",dir,filter); + } + else { + // if/else statements are functionally identical, but left in case + // different file selection capabilities are desired for different + // preferences later + if (Preference::Preferences().FindGroup("CubeCustomization").FindKeyword("Overwrite")[0] == "Allow") { + QFlags options (QFileDialog::DontConfirmOverwrite); + s = QFileDialog::getSaveFileName(p_fileButton,"Select file",dir,filter,0,options); + } + else { + QFlags options (QFileDialog::DontConfirmOverwrite); + s = QFileDialog::getSaveFileName(p_fileButton,"Select file",dir,filter,0,options); + } + } + + if (s != "") { + Isis::Filename f(s.toStdString()); + if (f.absoluteDir() == QDir::currentPath()) { + s = (QString)(iString)f.Name(); + } + Set(s.toStdString()); + } + } + + void GuiCubeParameter::SelectAttribute() { + if (p_ui->ParamFileMode(p_group,p_param) == "input") { + Isis::CubeAttributeInput att(p_lineEdit->text().toStdString()); + std::string curAtt = att.BandsStr(); + std::string newAtt; + int status = GuiInputAttribute::GetAttributes (curAtt,newAtt, + p_ui->ParamName(p_group,p_param), + p_fileButton); + if ((status == 1) && (curAtt != newAtt)) { + Isis::Filename f(p_lineEdit->text().toStdString()); + p_lineEdit->setText((iString)(f.Expanded() + newAtt)); + } + } else { + Isis::CubeAttributeOutput att("+" + p_ui->PixelType(p_group,p_param)); + bool allowProp = att.PropagatePixelType(); + att.Set(p_lineEdit->text().toStdString()); + + std::string curAtt; + att.Write(curAtt); + std::string newAtt; + int status = GuiOutputAttribute::GetAttributes (curAtt,newAtt, + p_ui->ParamName(p_group,p_param), + allowProp, + p_fileButton); + if ((status == 1) && (curAtt != newAtt)) { + Isis::Filename f(p_lineEdit->text().toStdString()); + p_lineEdit->setText((iString)(f.Expanded() + newAtt)); + } + } + + return; + } + + void GuiCubeParameter::ViewCube() { + try { + // Make sure the user entered a value + if (IsModified()) { + std::string cubeName = Value(); + + // Check to make sure the cube can be opened + Isis::Cube temp; + temp.Open(cubeName); + temp.Close(); + + // Open the cube in Qview + std::string command = "qview " + cubeName + " &"; + Isis::System(command); + } + // Throw an error if no cube name was entered + else { + std::string msg = "You must enter a cube name to open"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } catch (Isis::iException &e) { + Isis::iApp->GuiReportError(e); + } + } + + void GuiCubeParameter::ViewLabel() { + try { + // Make sure the user entered a value + if (IsModified()) { + std::string cubeName = Value(); + + // Check to make sure the cube can be opened + Isis::Cube temp; + temp.Open(cubeName); + + // Get the label and write it out to the log + Isis::Pvl *label = temp.Label(); + Isis::Application::GuiLog(*label); + + // Close the cube + temp.Close(); + + } else { + std::string msg = "You must enter a cube name to open"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } catch (Isis::iException &e) { + Isis::iApp->GuiReportError(e); + } + + } +} + diff --git a/isis/src/base/objs/Gui/GuiCubeParameter.h b/isis/src/base/objs/Gui/GuiCubeParameter.h new file mode 100644 index 0000000000000000000000000000000000000000..0a300005cfc3842b6f753ec940457d0022871266 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiCubeParameter.h @@ -0,0 +1,73 @@ +#ifndef Isis_GuiCubeParameter_h +#define Isis_GuiCubeParameter_h + +/** + * @file + * $Revision: 1.5 $ + * $Date: 2009/12/15 20:44:57 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "GuiFilenameParameter.h" + +#include + +namespace Isis { + +/** + * @author 2006-10-31 ??? + * + * @internal + * @history 2009-11-10 Mackenzie Boyd - Moved SelectFile + * method up to parent class GuiParameter, also moved + * member pointers to QToolButton and QLineEdit up. + * @history 2009-12-15 Travis Addair - Fixed bug with button + * for opening file dialog, made this class a child + * of GuiFilenameParameter, and moved SelectFile + * method back to this class, no longer prompting + * users to confirm overwriting a file. + */ + + class GuiCubeParameter : public GuiFilenameParameter { + + Q_OBJECT + + public: + + GuiCubeParameter (QGridLayout *grid, UserInterface &ui, + int group, int param); + ~GuiCubeParameter (); + + protected slots: + virtual void SelectFile(); + + private: + QMenu *p_menu; + + private slots: + void SelectAttribute(); + void ViewCube(); + void ViewLabel(); + }; +}; + + + +#endif + diff --git a/isis/src/base/objs/Gui/GuiDoubleParameter.cpp b/isis/src/base/objs/Gui/GuiDoubleParameter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed04c4b9571f8824fcbd1a145586042cc0887ee6 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiDoubleParameter.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include "GuiDoubleParameter.h" +#include "UserInterface.h" + + +namespace Isis { + + GuiDoubleParameter::GuiDoubleParameter(QGridLayout *grid, UserInterface &ui, + int group, int param) : + GuiParameter(grid, ui, group, param) { + + p_lineEdit = new QLineEdit; + p_lineEdit->setValidator(new QDoubleValidator(p_lineEdit)); + connect(p_lineEdit,SIGNAL(textChanged(const QString &)),this,SIGNAL(ValueChanged())); + grid->addWidget(p_lineEdit,param,2); + + if (p_ui->HelpersSize(group,param) != 0) { + grid->addWidget(AddHelpers(p_lineEdit),param,3); + } + + RememberWidget(p_lineEdit); + + p_type = DoubleWidget; + } + + + GuiDoubleParameter::~GuiDoubleParameter() {} + + + void GuiDoubleParameter::Set (iString newValue) { + p_lineEdit->setText (newValue.c_str()); + } + + + iString GuiDoubleParameter::Value () { + return p_lineEdit->text().toStdString(); + } + +} + diff --git a/isis/src/base/objs/Gui/GuiDoubleParameter.h b/isis/src/base/objs/Gui/GuiDoubleParameter.h new file mode 100644 index 0000000000000000000000000000000000000000..65fb621eeb8a6d10f0436aebc0382fde9a693273 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiDoubleParameter.h @@ -0,0 +1,36 @@ +#ifndef Isis_GuiDoubleParameter_h +#define Isis_GuiDoubleParameter_h + +#include + +#include "GuiParameter.h" + + +namespace Isis { + +// class QTextEdit; + + class GuiDoubleParameter : public GuiParameter { + + Q_OBJECT + + public: + + GuiDoubleParameter (QGridLayout *grid, UserInterface &ui, + int group, int param); + ~GuiDoubleParameter (); + + iString Value (); + + void Set (iString newValue); + + private: + QLineEdit *p_lineEdit; + + }; +}; + + + +#endif + diff --git a/isis/src/base/objs/Gui/GuiFilenameParameter.cpp b/isis/src/base/objs/Gui/GuiFilenameParameter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fcea205118da6e8a71f3e9a05603a53e599f6bc1 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiFilenameParameter.cpp @@ -0,0 +1,137 @@ +/** + * @file + * $Revision: 1.11 $ + * $Date: 2009/12/15 20:44:57 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "GuiFilenameParameter.h" + +#include "iString.h" +#include "UserInterface.h" + + +namespace Isis { + + GuiFilenameParameter::GuiFilenameParameter(QGridLayout *grid, UserInterface &ui, + int group, int param) : + GuiParameter(grid, ui, group, param) { + connect(p_lineEdit,SIGNAL(textChanged(const QString &)),this,SIGNAL(ValueChanged())); + grid->addWidget(p_lineEdit,param,2); + + grid->addWidget(p_fileButton,param,3); + + QAction *action = new QAction(this); + std::string file = Filename("$ISIS3DATA/base/icons/view_tree.png").Expanded(); + action->setIcon(QPixmap((iString)file)); + connect(action,SIGNAL(triggered(bool)),this,SLOT(SelectFile())); + + p_fileButton->setIconSize(QSize(22,22)); + p_fileButton->setIcon(QPixmap((iString)file)); + p_fileButton->setDefaultAction(action); + p_fileButton->setToolTip("Select file"); + QString fileButtonWhatsThisText = "

    Function: \ + Opens a file chooser window to select a file from

    "; + p_fileButton->setWhatsThis(fileButtonWhatsThisText); + + if (p_ui->HelpersSize(group,param) != 0) { + grid->addWidget(AddHelpers(p_lineEdit),param,4); + } + + RememberWidget(p_lineEdit); + RememberWidget(p_fileButton); + + p_type = FilenameWidget; + } + + + GuiFilenameParameter::~GuiFilenameParameter() {} + + + void GuiFilenameParameter::Set (iString newValue) { + p_lineEdit->setText (newValue.ToQt()); + } + + + iString GuiFilenameParameter::Value () { + return p_lineEdit->text().toStdString(); + } + + /** + * + * @internal + * @history 2007-05-16 Tracie Sucharski - For files located in CWD, do + * not include path in the lineEdit. + * @history 2007-06-05 Steven Koechle - Corrected problem where + * output Filename was being opened + * not saved. Defaulted to output mode + * if not specified. + * @history 2009-11-02 Mackenzie Boyd - Corrected building of + * filter string to match + * GuiCubeParameter.cpp and, if no + * filters specified, to specify + * "Any(*)" not ";;Any(*)" as it had + * been doing. + */ + void GuiFilenameParameter::SelectFile() { + // What directory do we look in? + QString dir; + if ((p_lineEdit->text().length() > 0) && + (p_lineEdit->text().toStdString() != p_ui->ParamInternalDefault(p_group,p_param))) { + Isis::Filename f(p_lineEdit->text().toStdString()); + dir = (QString)(iString)f.Expanded(); + } else if (p_ui->ParamPath(p_group,p_param).length() > 0) { + Isis::Filename f(p_ui->ParamPath(p_group,p_param)); + dir = (QString)(iString)f.Expanded(); + } + + // Set up the filter + QString filter = (iString)p_ui->ParamFilter(p_group,p_param); + if (filter.isEmpty()) { + filter = "Any(*)"; + } + else { + filter += ";;Any(*)"; + } + + // Get the filename + QString s; + + if (p_ui->ParamFileMode(p_group,p_param) == "input") { + s = QFileDialog::getOpenFileName(p_fileButton,"Select file",dir,filter); + } + else { + QFlags options (QFileDialog::ShowDirsOnly); + s = QFileDialog::getSaveFileName(p_fileButton,"Select file",dir,filter,0,options); + } + + if (s != "") { + Isis::Filename f(s.toStdString()); + if (f.absoluteDir() == QDir::currentPath()) { + s = (QString)(iString)f.Name(); + } + Set(s.toStdString()); + } + } +} + diff --git a/isis/src/base/objs/Gui/GuiFilenameParameter.h b/isis/src/base/objs/Gui/GuiFilenameParameter.h new file mode 100644 index 0000000000000000000000000000000000000000..308e75a7e6ea31ad484c09a2224c8d479e26fe61 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiFilenameParameter.h @@ -0,0 +1,67 @@ +#ifndef Isis_GuiFilenameParameter_h +#define Isis_GuiFilenameParameter_h + +/** + * @file + * $Revision: 1.4 $ + * $Date: 2009/12/15 20:44:57 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "GuiParameter.h" + +namespace Isis { + +/** + * @author 2006-10-31 ??? + * + * @internal + * @history 2009-11-10 Mackenzie Boyd - Moved SelectFile + * method up to parent class GuiParameter, also moved + * member pointers to QToolButton and QLineEdit up. + * @history 2009-12-15 Travis Addair - Fixed bug with button + * for opening file dialog, made this class a parent + * for GuiCubeParameter, and moved SelectFile method + * back to this class, no longer prompting users to + * confirm overwriting a file. + */ + + class GuiFilenameParameter : public GuiParameter { + + Q_OBJECT + + public: + + GuiFilenameParameter (QGridLayout *grid, UserInterface &ui, + int group, int param); + ~GuiFilenameParameter (); + + iString Value (); + + void Set (iString newValue); + + protected slots: + virtual void SelectFile(); + }; +}; + + + +#endif + diff --git a/isis/src/base/objs/Gui/GuiHelperAction.cpp b/isis/src/base/objs/Gui/GuiHelperAction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c71149891ae560868f8628927a5838851bb7a7e3 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiHelperAction.cpp @@ -0,0 +1,18 @@ +#include "GuiHelperAction.h" +#include + +namespace Isis { + GuiHelperAction::GuiHelperAction(QObject *parent, const QString &funct) : QAction(parent) { + p_funct = funct; + connect(this,SIGNAL(triggered(bool)),this,SLOT(retrigger())); + } + + GuiHelperAction::~GuiHelperAction() {}; + + void GuiHelperAction::retrigger() { + emit trigger(p_funct); + } + +} + + diff --git a/isis/src/base/objs/Gui/GuiHelperAction.h b/isis/src/base/objs/Gui/GuiHelperAction.h new file mode 100644 index 0000000000000000000000000000000000000000..fa0c19d4caa93fceb05dd88178cecaadb233c5fb --- /dev/null +++ b/isis/src/base/objs/Gui/GuiHelperAction.h @@ -0,0 +1,24 @@ +#include +#include "iString.h" + +namespace Isis { + class GuiHelperAction : public QAction { + + Q_OBJECT + + public: + + GuiHelperAction(QObject *parent, const QString &funct); + ~GuiHelperAction(); + + signals: + void trigger(const QString &funct); + + private slots: + void retrigger(); + + private: + QString p_funct; + }; +} + diff --git a/isis/src/base/objs/Gui/GuiInputAttribute.cpp b/isis/src/base/objs/Gui/GuiInputAttribute.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5d1e0c6bb9d7eaa13426875f9b32b7e2d67e18ea --- /dev/null +++ b/isis/src/base/objs/Gui/GuiInputAttribute.cpp @@ -0,0 +1,144 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/07/11 20:16:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "CubeAttribute.h" +#include "GuiInputAttribute.h" + +namespace Isis { + //! Convenience access to dialog + int GuiInputAttribute::GetAttributes (const std::string &defaultAttribute, + std::string &newAttribute, + const std::string &title, + QWidget *parent) { + // Construct dialog if necessary + static GuiInputAttribute *p_dialog = 0; + if (p_dialog == 0) { + p_dialog = new GuiInputAttribute (parent); + } + p_dialog->setWindowTitle(title.c_str()); + + // Load default attributes and then get the new ones + p_dialog->SetAttributes(defaultAttribute); + if (p_dialog->exec() == QDialog::Accepted) { + newAttribute = p_dialog->GetAttributes(); + return 1; + } + newAttribute = defaultAttribute; + return 0; + } + + //! Constuctor + GuiInputAttribute::GuiInputAttribute (QWidget *parent) : QDialog (parent) { + // Create the two radio buttons + QRadioButton *allBands = new QRadioButton("&All Bands"); + allBands->setToolTip("Select all bands from the input cube"); + + QRadioButton *listBands = new QRadioButton("&Band List"); + listBands->setToolTip("Select any bands from the input cube"); + + // Create the button group for the radio buttons + p_buttonGroup = new QButtonGroup(); + p_buttonGroup->addButton(allBands); + p_buttonGroup->addButton(listBands); + p_buttonGroup->setExclusive(true); + + // Create the text field for list toggle button + p_lineEdit = new QLineEdit (); + connect(allBands, SIGNAL(toggled(bool)), p_lineEdit, SLOT(setDisabled(bool))); + allBands->setChecked(true); + + // Put the buttons and text field in a gridlayout + QGridLayout *gridLayout = new QGridLayout (); + gridLayout->addWidget(allBands,0,0); + gridLayout->addWidget(listBands,1,0); + gridLayout->addWidget(p_lineEdit, 1, 1); + + // Create the action buttons + QPushButton *okButton = new QPushButton ("Ok"); + connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); + + QPushButton* cancelButton = new QPushButton ("Cancel"); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + +#if 0 + // Add them to a button group + QButtonGroup *actionGroup = new QButtonGroup(); + actionGroup->addButton(okButton); + actionGroup->addButton(cancelButton); +#endif + + // Put the buttons in a horizontal orientation + QHBoxLayout *actionLayout = new QHBoxLayout(); + actionLayout->addWidget(okButton); + actionLayout->addWidget(cancelButton); + + // Put the grid layout and action layout on the dialog + QVBoxLayout *dialogLayout = new QVBoxLayout(this); + dialogLayout->addLayout(gridLayout); + dialogLayout->addLayout(actionLayout); + } + + + // Destructor + GuiInputAttribute::~GuiInputAttribute () {} + + + // Return the attributes in the dialog + std::string GuiInputAttribute::GetAttributes () { + if (p_lineEdit->isEnabled()) { + Isis::iString s = p_lineEdit->text().toStdString(); + s.Remove(" "); + s.Trim("+"); + if (s == "") return s; + return (std::string)"+" + s; + } + else { + return std::string(""); + } + } + + // Set the attributes in the dialog + void GuiInputAttribute::SetAttributes (const std::string &value) { + Isis::CubeAttributeInput att(value); + std::vector bands = att.Bands(); + if (bands.size() == 0) { + p_buttonGroup->buttons()[0]->setChecked(true); + p_lineEdit->setText(""); + } + else { + p_buttonGroup->buttons()[1]->setChecked(true); + p_lineEdit->setText((iString)att.BandsStr()); + } + } +} + diff --git a/isis/src/base/objs/Gui/GuiInputAttribute.h b/isis/src/base/objs/Gui/GuiInputAttribute.h new file mode 100644 index 0000000000000000000000000000000000000000..1ae96ebd8131c2c99da49e3276dc916d2827550d --- /dev/null +++ b/isis/src/base/objs/Gui/GuiInputAttribute.h @@ -0,0 +1,55 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisGuiInputAttribute_h +#define IsisGuiInputAttribute_h + +#include +#include +#include + +namespace Isis { + class GuiInputAttribute : public QDialog { + Q_OBJECT + + public: + GuiInputAttribute (QWidget *parent=0); + + ~GuiInputAttribute (); + + std::string GetAttributes (); + + void SetAttributes (const std::string &value); + + static int GetAttributes (const std::string &defaultAttribute, + std::string &newAttribute, + const std::string &title, + QWidget *parent); + private: + QLineEdit *p_lineEdit; + QButtonGroup *p_buttonGroup; + }; +}; + +#endif + diff --git a/isis/src/base/objs/Gui/GuiIntegerParameter.cpp b/isis/src/base/objs/Gui/GuiIntegerParameter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c7022d17f6db641398c246f4033c6222d022c970 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiIntegerParameter.cpp @@ -0,0 +1,39 @@ +#include +#include + +#include "GuiIntegerParameter.h" +#include "UserInterface.h" + +namespace Isis { + + GuiIntegerParameter::GuiIntegerParameter(QGridLayout *grid, UserInterface &ui, + int group, int param) : + GuiParameter(grid, ui, group, param) { + + p_lineEdit = new QLineEdit; + p_lineEdit->setValidator(new QIntValidator(p_lineEdit)); + connect(p_lineEdit,SIGNAL(textChanged(const QString &)),this,SIGNAL(ValueChanged())); + grid->addWidget(p_lineEdit,param,2); + + if (p_ui->HelpersSize(group,param) != 0) { + grid->addWidget(AddHelpers(p_lineEdit),param,3); + } + + RememberWidget(p_lineEdit); + p_type = IntegerWidget; + } + + + GuiIntegerParameter::~GuiIntegerParameter() {} + + void GuiIntegerParameter::Set (iString newValue) { + p_lineEdit->setText (newValue); + } + + + iString GuiIntegerParameter::Value () { + return p_lineEdit->text().toStdString(); + } + +} + diff --git a/isis/src/base/objs/Gui/GuiIntegerParameter.h b/isis/src/base/objs/Gui/GuiIntegerParameter.h new file mode 100644 index 0000000000000000000000000000000000000000..45984df385177131c98ec8485cb9140a4f65b697 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiIntegerParameter.h @@ -0,0 +1,37 @@ + +#ifndef Isis_GuiIntegerParameter_h +#define Isis_GuiIntegerParameter_h + +#include + +#include "GuiParameter.h" + + +namespace Isis { + +// class QTextEdit; + + class GuiIntegerParameter : public GuiParameter { + + Q_OBJECT + + public: + + GuiIntegerParameter (QGridLayout *grid, UserInterface &ui, + int group, int param); + ~GuiIntegerParameter (); + + iString Value (); + + void Set (iString newValue); + + private: + QLineEdit *p_lineEdit; + + }; +}; + + + +#endif + diff --git a/isis/src/base/objs/Gui/GuiListParameter.cpp b/isis/src/base/objs/Gui/GuiListParameter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a40d87abf06523d362994f48b5cdfe7dceb48194 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiListParameter.cpp @@ -0,0 +1,117 @@ +#include +#include +#include +#include + +#include "UserInterface.h" + +#include "GuiListParameter.h" + +namespace Isis { + + GuiListParameter::GuiListParameter(QGridLayout *grid, UserInterface &ui, + int group, int param) : + GuiParameter(grid, ui, group, param) { + + // Reset the default alignment of the label + p_label->setAlignment(Qt::AlignRight | Qt::AlignTop); + + + // Create a vertical box layout for the radio buttons and add it to + // the grid layout + QVBoxLayout *lo = new QVBoxLayout; + grid->addLayout(lo, param, 2); + + // Create a button group so these buttons don't react to other buttons + // with the same parent + p_buttonGroup = new QButtonGroup (); + + // Create a button for each list item and add each to a button group and + // to the layout + for (int item=0; itemHelpersSize(group,param) != 0)) { + // Create Horizontal layout box + QHBoxLayout *hlo = new QHBoxLayout; + lo->addLayout(hlo); + + // Create radio button & add to horizontal layout + QRadioButton *rb = new QRadioButton ((iString)btext); + hlo->addWidget(rb); + p_buttonGroup->addButton(rb); + + // Get helpers and add to horizontal layout + QWidget *helper = AddHelpers(p_buttonGroup); + hlo->addWidget(helper); + + RememberWidget(rb); + RememberWidget(helper); + } + else { + QRadioButton *rb = new QRadioButton ((iString)btext); + lo->addWidget(rb); + p_buttonGroup->addButton(rb); + RememberWidget(rb); + } + } + connect(p_buttonGroup,SIGNAL(buttonClicked(QAbstractButton *)), + this,SIGNAL(ValueChanged())); + + p_type = ListWidget; + } + + + GuiListParameter::~GuiListParameter() { + delete p_buttonGroup; + } + + + void GuiListParameter::Set (iString newValue) { + iString value = newValue; + value.UpCase(); + + int foundAtButton = -1; + for (int i=0; iParamListSize(p_group,p_param); i++) { + iString option = p_ui->ParamListValue(p_group, p_param, i); + option.UpCase(); + if (option.compare(0,value.size(),value) == 0) foundAtButton = i; + } + + if (foundAtButton != -1) { + p_buttonGroup->buttons()[foundAtButton]->setChecked(true); + } + + emit ValueChanged(); + } + + + iString GuiListParameter::Value () { + if (p_buttonGroup->checkedButton() == 0) { + return ""; + } + + return (iString)p_ui->ParamListValue(p_group, p_param, + p_buttonGroup->buttons().indexOf(p_buttonGroup->checkedButton())); + } + + std::vector GuiListParameter::Exclusions() { + std::vector list; + + if (p_buttonGroup->checkedButton() == 0) return list; + int index = p_buttonGroup->buttons().indexOf(p_buttonGroup->checkedButton()); + + for (int i=0; iParamListExcludeSize(p_group,p_param,index); i++) { + std::string s = p_ui->ParamListExclude(p_group,p_param,index,i); + list.push_back(s); + } + + return list; + } +} + diff --git a/isis/src/base/objs/Gui/GuiListParameter.h b/isis/src/base/objs/Gui/GuiListParameter.h new file mode 100644 index 0000000000000000000000000000000000000000..76362ae0fb2b4840a1ea6f3ecfdd0318f199d8d9 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiListParameter.h @@ -0,0 +1,35 @@ +#ifndef Isis_GuiListParameter_h +#define Isis_GuiListParameter_h + +#include + +#include "GuiParameter.h" + + +namespace Isis { + + class GuiListParameter : public GuiParameter { + + Q_OBJECT + + public: + + GuiListParameter (QGridLayout *grid, UserInterface &ui, + int group, int param); + ~GuiListParameter (); + + iString Value (); + + void Set (iString newValue); + + virtual std::vector Exclusions(); + + private: + QButtonGroup *p_buttonGroup; + }; +}; + + + +#endif + diff --git a/isis/src/base/objs/Gui/GuiLog.cpp b/isis/src/base/objs/Gui/GuiLog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6fc0804995b8ca8e910fe64d8e640c29cf6192b --- /dev/null +++ b/isis/src/base/objs/Gui/GuiLog.cpp @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include + +#include "GuiLog.h" + +namespace Isis { + //! Constructor + GuiLog::GuiLog(QWidget *parent) : QWidget (parent) { + + QVBoxLayout *lo = new QVBoxLayout; + setLayout(lo); + +// QLabel *lb = new QLabel("Log"); +// lo->addWidget(lb); + + p_textEdit = new QTextEdit; + p_textEdit->setFont(QFont("Courier")); + p_textEdit->setFontPointSize(10); +// p_textEdit->setReadOnly(true); + + lo->addWidget(p_textEdit); + } + + //! Destructor + GuiLog::~GuiLog() { + } + + //! Add more information to the log widget + void GuiLog::Write(const QString &string) { + p_textEdit->append(string); + } + + //! Clear the contents of the log widget + void GuiLog::Clear() { + p_textEdit->clear(); + p_textEdit->setFont(QFont("Courier")); + p_textEdit->setFontPointSize(10); + } + + //! Save the contents of the log widget to a file + void GuiLog::Save() { + QString s = QFileDialog::getSaveFileName(this,"Save log to file"); + if (s != "") { + std::ofstream fout; + std::string filename(s.toStdString()); + fout.open(filename.c_str()); + fout << p_textEdit->toPlainText().toStdString(); + fout.close(); + } + } +} diff --git a/isis/src/base/objs/Gui/GuiLog.h b/isis/src/base/objs/Gui/GuiLog.h new file mode 100644 index 0000000000000000000000000000000000000000..1f9ac9a75b283d29e02957a6b5cf3a087c764176 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiLog.h @@ -0,0 +1,31 @@ + +#ifndef Isis_GuiLog_h +#define Isis_GuiLog_h + +#include + +namespace Isis { + + class GuiLog : public QWidget { + + Q_OBJECT + + public: + + GuiLog (QWidget *parent=0); + ~GuiLog (); + + void Write(const QString &string); + + public slots: + void Clear(); + void Save(); + + private: + QTextEdit *p_textEdit; + }; +}; + + + +#endif diff --git a/isis/src/base/objs/Gui/GuiOutputAttribute.cpp b/isis/src/base/objs/Gui/GuiOutputAttribute.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8398696e40617f867394b7914334e5511cbaedd6 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiOutputAttribute.cpp @@ -0,0 +1,273 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/07/11 20:16:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CubeAttribute.h" +#include "GuiOutputAttribute.h" + +namespace Isis { + //! Convenience access to dialog + int GuiOutputAttribute::GetAttributes (const std::string &defaultAttribute, + std::string &newAttribute, + const std::string &title, + bool allowProp, + QWidget *parent) { + // Construct dialog if necessary + static GuiOutputAttribute *p_dialog = 0; + if (p_dialog == 0) { + p_dialog = new GuiOutputAttribute (parent); + } + p_dialog->setWindowTitle((iString)title); + p_dialog->SetPropagation(allowProp); + + // Load default attributes and then get the new ones + p_dialog->SetAttributes(defaultAttribute); + if (p_dialog->exec() == QDialog::Accepted) { + newAttribute = p_dialog->GetAttributes(); + return 1; + } + newAttribute = defaultAttribute; + return 0; + } + + //! Constuctor + GuiOutputAttribute::GuiOutputAttribute (QWidget *parent) : QDialog (parent) { + // Create the pixel type group + p_propagate = new QRadioButton("&Propagate"); + p_propagate->setToolTip("Propagate pixel type from input cube"); + p_unsignedByte = new QRadioButton("&Unsigned Byte"); + p_unsignedByte->setToolTip("Unsigned 8-bit pixels"); + p_signedWord = new QRadioButton("&Signed Word"); + p_signedWord->setToolTip("Signed 16-bit pixels"); + p_real = new QRadioButton("&Real"); + p_real->setToolTip("Floating point 32-bit pixels"); + + QButtonGroup *buttonGroup = new QButtonGroup(); + buttonGroup->addButton(p_propagate); + buttonGroup->addButton(p_unsignedByte); + buttonGroup->addButton(p_signedWord); + buttonGroup->addButton(p_real); + buttonGroup->setExclusive(true); + + p_minEdit = new QLineEdit (); + p_maxEdit = new QLineEdit (); + QLabel *minLabel = new QLabel("Minimum"); + QLabel *maxLabel = new QLabel("Maximum"); + connect (p_propagate,SIGNAL(toggled(bool)),p_minEdit,SLOT(setDisabled(bool))); + connect (p_propagate,SIGNAL(toggled(bool)),p_maxEdit,SLOT(setDisabled(bool))); + connect (p_unsignedByte,SIGNAL(toggled(bool)),p_minEdit,SLOT(setEnabled(bool))); + connect (p_unsignedByte,SIGNAL(toggled(bool)),p_maxEdit,SLOT(setEnabled(bool))); + connect (p_signedWord,SIGNAL(toggled(bool)),p_minEdit,SLOT(setEnabled(bool))); + connect (p_signedWord,SIGNAL(toggled(bool)),p_maxEdit,SLOT(setEnabled(bool))); + connect (p_real,SIGNAL(toggled(bool)),p_minEdit,SLOT(setDisabled(bool))); + connect (p_real,SIGNAL(toggled(bool)),p_maxEdit,SLOT(setDisabled(bool))); + p_minEdit->setValidator(new QDoubleValidator(p_minEdit)); + p_maxEdit->setValidator(new QDoubleValidator(p_maxEdit)); + + QGridLayout *gridLayout = new QGridLayout (); + gridLayout->addWidget(p_propagate,0,0); + gridLayout->addWidget(p_unsignedByte,1,0); + gridLayout->addWidget(p_signedWord,2,0); + gridLayout->addWidget(p_real,3,0); + gridLayout->addWidget(minLabel,0,1); + gridLayout->addWidget(p_minEdit,1,1); + gridLayout->addWidget(maxLabel,2,1); + gridLayout->addWidget(p_maxEdit,3,1); + + QGroupBox *pixelTypeBox = new QGroupBox("Pixel Type"); + pixelTypeBox->setLayout(gridLayout); + + // Create detached/attached stuff + p_attached = new QRadioButton("&Attached"); + p_attached->setToolTip("Save labels and image data in one file"); + p_detached = new QRadioButton("&Detached"); + p_detached->setToolTip("Save labels and image data in separate files"); + p_attached->setChecked(true); + + buttonGroup = new QButtonGroup(); + buttonGroup->addButton(p_attached); + buttonGroup->addButton(p_detached); + buttonGroup->setExclusive(true); + + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(p_attached); + layout->addWidget(p_detached); + + QGroupBox *labelFormatBox = new QGroupBox("Label Format"); + labelFormatBox->setLayout(layout); + + // Create cube format stuff + p_tiled = new QRadioButton("&Tiled"); + p_tiled->setToolTip("Save image data in tiled format"); + p_bsq = new QRadioButton("&BSQ"); + p_bsq->setToolTip("Save image data in band sequential format"); + + buttonGroup = new QButtonGroup(); + buttonGroup->addButton(p_tiled); + buttonGroup->addButton(p_bsq); + buttonGroup->setExclusive(true); + + layout = new QVBoxLayout(); + layout->addWidget(p_tiled); + layout->addWidget(p_bsq); + + QGroupBox *cubeFormatBox = new QGroupBox("Cube Format"); + cubeFormatBox->setLayout(layout); + + // Create cube format stuff + p_lsb = new QRadioButton("&LSB"); + p_lsb->setToolTip("Save image data in little endian format"); + p_msb = new QRadioButton("&MSB"); + p_msb->setToolTip("Save image data in big endian format"); + + buttonGroup = new QButtonGroup(); + buttonGroup->addButton(p_lsb); + buttonGroup->addButton(p_msb); + buttonGroup->setExclusive(true); + + layout = new QVBoxLayout(); + layout->addWidget(p_lsb); + layout->addWidget(p_msb); + + QGroupBox *byteOrderBox = new QGroupBox("Byte Order"); + byteOrderBox->setLayout(layout); + + // Create the action buttons + QPushButton *okButton = new QPushButton ("Ok"); + connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); + + QPushButton* cancelButton = new QPushButton ("Cancel"); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + // Put the buttons in a horizontal orientation + QHBoxLayout *actionLayout = new QHBoxLayout(); + actionLayout->addWidget(okButton); + actionLayout->addWidget(cancelButton); + + // Put the grid layout and action layout on the dialog + QVBoxLayout *dialogLayout = new QVBoxLayout(this); + dialogLayout->addWidget(pixelTypeBox); + dialogLayout->addWidget(labelFormatBox); + dialogLayout->addWidget(cubeFormatBox); + dialogLayout->addWidget(byteOrderBox); + dialogLayout->addLayout(actionLayout); + } + + + // Destructor + GuiOutputAttribute::~GuiOutputAttribute () {} + + + // Return the attributes in the dialog + std::string GuiOutputAttribute::GetAttributes () { + std::string att; + if (p_lsb->isChecked()) att += "+lsb"; + if (p_msb->isChecked()) att += "+msb"; + + if (p_tiled->isChecked()) att += "+tiled"; + if (p_bsq->isChecked()) att += "+bsq"; + + if (p_attached->isChecked()) att += "+attached"; + if (p_detached->isChecked()) att += "+detached"; + + if (p_real->isChecked()) att += "+real"; + if (p_unsignedByte->isChecked()) att += "+8bit"; + if (p_signedWord->isChecked()) att += "+16bit"; + + if (p_unsignedByte->isChecked() || p_signedWord->isChecked()) { + if ((p_minEdit->text() != "") && (p_maxEdit->text() != "")) { + att += "+"; + att += p_minEdit->text().toStdString(); + att += ":"; + att += p_maxEdit->text().toStdString(); + } + } + + Isis::CubeAttributeOutput catt(att); + std::string s; + catt.Write(s); + return s; + } + + // Set the attributes in the dialog + void GuiOutputAttribute::SetAttributes (const std::string &value) { + Isis::CubeAttributeOutput att(value); + if (att.FileFormat() == Isis::Tile) { + p_tiled->setChecked(true); + } + else { + p_bsq->setChecked(true); + } + + if (att.ByteOrder() == Isis::Lsb) { + p_lsb->setChecked(true); + } + else { + p_msb->setChecked(true); + } + + if (att.AttachedLabel()) { + p_attached->setChecked(true); + } + else { + p_detached->setChecked(true); + } + + if (att.PropagatePixelType()) { + p_propagate->setChecked(true); + } + else if (att.PixelType() == Isis::UnsignedByte) { + p_unsignedByte->setChecked(true); + } + else if (att.PixelType() == Isis::SignedWord) { + p_signedWord->setChecked(true); + } + else { + p_real->setChecked(true); + } + + if (!att.PropagateMinimumMaximum()) { + p_minEdit->setText(QString::number(att.Minimum())); + p_maxEdit->setText(QString::number(att.Maximum())); + } + } + + //! Do we allow propagation + void GuiOutputAttribute::SetPropagation(bool enabled) { + p_propagationEnabled = enabled; + p_propagate->setEnabled(enabled); + } +} + diff --git a/isis/src/base/objs/Gui/GuiOutputAttribute.h b/isis/src/base/objs/Gui/GuiOutputAttribute.h new file mode 100644 index 0000000000000000000000000000000000000000..088e8ba8e05154e0b378d706e8d3f0cce0471e41 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiOutputAttribute.h @@ -0,0 +1,70 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisGuiOutputAttribute_h +#define IsisGuiOutputAttribute_h + +#include +#include +#include + +namespace Isis { + class GuiOutputAttribute : public QDialog { + Q_OBJECT + + public: + GuiOutputAttribute (QWidget *parent=0); + + ~GuiOutputAttribute (); + + std::string GetAttributes (); + + void SetAttributes (const std::string &value); + + static int GetAttributes (const std::string &defaultAttribute, + std::string &newAttribute, + const std::string &title, + bool allowProp, + QWidget *parent); + + void SetPropagation(bool enabled); + + private: + QRadioButton *p_propagate; + QRadioButton *p_unsignedByte; + QRadioButton *p_signedWord; + QRadioButton *p_real; + QLineEdit *p_minEdit; + QLineEdit *p_maxEdit; + QRadioButton *p_attached; + QRadioButton *p_detached; + QRadioButton *p_tiled; + QRadioButton *p_bsq; + QRadioButton *p_lsb; + QRadioButton *p_msb; + bool p_propagationEnabled; + }; +}; + +#endif + diff --git a/isis/src/base/objs/Gui/GuiParameter.cpp b/isis/src/base/objs/Gui/GuiParameter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2608a091ca18967adec1fa3ff3000636b7779f9 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiParameter.cpp @@ -0,0 +1,364 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2009/12/15 20:44:57 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include + +#include "GuiParameter.h" + +#include "Application.h" +#include "Filename.h" +#include "GuiHelperAction.h" +#include "UserInterface.h" + +#include "GuiFilenameParameter.h" +#include "GuiCubeParameter.h" + +namespace Isis { + //! Constructor + GuiParameter::GuiParameter(QGridLayout *grid, UserInterface &ui, + int group, int param) : QObject() { + p_ui = &ui; + p_group = group; + p_param = param; + + p_name = ui.ParamName(group, param); + + p_fileButton = new QToolButton(); + p_lineEdit = new QLineEdit(); + + p_label = new QLabel((iString)p_ui->ParamName(group, param)); + p_label->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + p_label->setToolTip((iString)p_ui->ParamBrief(group,param)); + grid->addWidget(p_label, param, 0, Qt::AlignCenter); + + QString whatsThis; + whatsThis = (QString)(iString)("Parameter: " + p_ui->ParamName(group,param)); + whatsThis += (QString)(iString)("

    Type: " + p_ui->ParamType(group,param) + "

    "); + whatsThis += (QString)(iString)("

    Brief: " + p_ui->ParamBrief(group,param) + "

    "); + iString def = p_ui->ParamDefault(group,param); + if (def == "") def = "None"; + whatsThis += "

    Default: " + QString(def) + "

    "; + iString intdef = p_ui->ParamInternalDefault(group,param); + if (intdef != "") { + whatsThis += "

    Internal Default: " + QString(intdef) + "

    "; + } + iString pixtype = p_ui->PixelType(group,param); + if (pixtype != "") { + whatsThis += "

    Pixel Type: " + QString(pixtype) + "

    "; + } + iString pmin = p_ui->ParamMinimum(group,param); + if (pmin != "") { + if (p_ui->ParamMinimumInclusive(group,param) =="YES") { + whatsThis += "

    Greater Than Or Equal To: " + + QString(pmin) + "

    "; + } + else { + whatsThis += "

    Greater Than: " + QString(pmin) + "

    "; + } + } + iString pmax = p_ui->ParamMaximum(group,param); + if (pmax != "") { + if (p_ui->ParamMaximumInclusive(group,param) =="YES") { + whatsThis += "

    Less Than Or Equal To: " + + QString(pmax) + "

    "; + } + else { + whatsThis += "

    Less Than: " + QString(pmax) + "

    "; + } + } + if (p_ui->ParamLessThanSize(group,param) > 0) { + whatsThis += "

    Less Than: " + + QString((iString)p_ui->ParamLessThan(group,param,0)); + for (int l=1; lParamLessThanSize(group,param); l++) { + whatsThis += ", " + QString((iString)p_ui->ParamLessThan(group,param,l)); + } + whatsThis += "

    "; + } + if (p_ui->ParamLessThanOrEqualSize(group,param) > 0) { + whatsThis += "

    Less Than Or Equal: " + + QString((iString)p_ui->ParamLessThanOrEqual(group,param,0)); + for (int l=1; lParamLessThanOrEqualSize(group,param); l++) { + whatsThis += ", " + + QString((iString)p_ui->ParamLessThanOrEqual(group,param,l)); + } + whatsThis += "

    "; + } + if (p_ui->ParamNotEqualSize(group,param) > 0) { + whatsThis += "

    Not Equal: " + + QString((iString)p_ui->ParamNotEqual(group,param,0)); + for (int l=1; lParamNotEqualSize(group,param); l++) { + whatsThis += ", " + QString((iString)p_ui->ParamNotEqual(group,param,l)); + } + whatsThis += "

    "; + } + if (p_ui->ParamGreaterThanSize(group,param) > 0) { + whatsThis += "

    Greater Than: " + + QString((iString)p_ui->ParamGreaterThan(group,param,0)); + for (int l=1; lParamGreaterThanSize(group,param); l++) { + whatsThis += ", " + + QString((iString)p_ui->ParamGreaterThan(group,param,l)); + } + whatsThis += "

    "; + } + if (p_ui->ParamGreaterThanOrEqualSize(group,param) > 0) { + whatsThis += "

    Greater Than Or Equal: " + + QString((iString)p_ui->ParamGreaterThanOrEqual(group,param,0)); + for (int l=1; lParamGreaterThanOrEqualSize(group,param); l++) { + whatsThis += ", " + + QString((iString)p_ui->ParamGreaterThanOrEqual(group,param,l)); + } + whatsThis += "

    "; + } + if (p_ui->ParamIncludeSize(group,param) >0) { + whatsThis += "

    Inclusions: " + + QString((iString)p_ui->ParamInclude(group,param,0)); + for (int l=1; lParamIncludeSize(group,param); l++) { + whatsThis += ", " + + QString((iString)p_ui->ParamInclude(group,param,l)); + } + whatsThis += "

    "; + } + if (p_ui->ParamExcludeSize(group,param) >0) { + whatsThis += "

    Exclusions: " + + QString((iString)p_ui->ParamExclude(group,param,0)); + for (int l=1; lParamExcludeSize(group,param); l++) { + whatsThis += ", " + + QString((iString)p_ui->ParamExclude(group,param,l)); + } + whatsThis += "

    "; + } + if (p_ui->ParamOdd(group,param) != "") { + whatsThis += "

    Odd: " + + QString((iString)p_ui->ParamOdd(group,param)) + "

    "; + } + p_label->setWhatsThis(whatsThis); + + p_helperMenu = NULL; + } + + + //! Destructor + GuiParameter::~GuiParameter() { + if(p_helperMenu) { + delete p_helperMenu; + p_helperMenu = NULL; + } + + p_widgetList.clear(); + } + + //! Change the parameter to the default value + void GuiParameter::SetToDefault () { + if (p_ui->ParamDefault (p_group, p_param).size() > 0) { + Set(p_ui->ParamDefault (p_group, p_param)); + } + else if (p_ui->ParamInternalDefault (p_group, p_param).size () > 0) { + Set(p_ui->ParamInternalDefault (p_group, p_param)); + } + else { + Set (""); + } + } + + //! Change the parameter to the current user interface value + void GuiParameter::SetToCurrent () { + if (p_ui->WasEntered(p_name)) { + Set (p_ui->GetAsString(p_name)); + } + else { + SetToDefault(); + } + } + + //! Return if the parameter value is different from the default value + bool GuiParameter::IsModified() { + if (!IsEnabled()) return false; + if (p_ui->ParamDefault (p_group, p_param).size() > 0) { + if (Value() == p_ui->ParamDefault (p_group, p_param)) return false; + } + else if (p_ui->ParamInternalDefault (p_group, p_param).size () > 0) { + if (Value() == p_ui->ParamInternalDefault (p_group, p_param)) return false; + } + else { + if (Value() == "") return false; + } + return true; + } + + //! Update the value on the GUI with the value in the UI + void GuiParameter::Update() { + if (p_ui->WasEntered(p_name)) { + Set (p_ui->GetAsString(p_name)); + } + else if (p_ui->ParamDefault (p_group, p_param).size() > 0) { + Set (p_ui->ParamDefault (p_group, p_param)); + } + else if (p_ui->ParamInternalDefault (p_group, p_param).size () > 0) { + Set (p_ui->ParamInternalDefault (p_group, p_param)); + } + else { + Set (""); + } + } + + //! Add widgets to a list for enabling/disabling + void GuiParameter::RememberWidget(QWidget *w) { + p_widgetList.push_back(w); + } + + //! Enable or disable the parameter + void GuiParameter::SetEnabled(bool enabled) { + p_label->setEnabled(enabled); + for (int i=0; isetEnabled(enabled); + } + } + + //! Return list of current exclusions + std::vector GuiParameter::Exclusions() { + std::vector list; + return list; + } + + //! Sets up helper button + QWidget *GuiParameter::AddHelpers(QObject *lo) { + // Just make one single helper button + if (p_ui->HelpersSize(p_group,p_param) == 1) { + GuiHelperAction *action = + new GuiHelperAction(lo,(iString)p_ui->HelperFunction(p_group,p_param,0)); + if (p_ui->HelperIcon(p_group,p_param,0) != "") { + iString file = Filename( + p_ui->HelperIcon(p_group,p_param,0)).Expanded(); + action->setIcon(QIcon(QPixmap(file))); + } + else { + action->setText((iString)p_ui->HelperButtonName(p_group, p_param, 0)); + } + action->setToolTip((iString)p_ui->HelperBrief(p_group,p_param,0)); + QString helperText = "

    Function: " + + QString((iString)p_ui->HelperDescription(p_group,p_param,0)) + "

    "; + action->setWhatsThis(helperText); + connect (action,SIGNAL(trigger(const QString &)),this, + SIGNAL(HelperTrigger(const QString &))); + + QToolButton *helper = new QToolButton(); + helper->setText((iString)p_ui->HelperButtonName(p_group, p_param, 0)); + helper->setDefaultAction(action); + + if (p_ui->HelperIcon(p_group,p_param,0) != "") { + helper->setText(""); + iString file = Filename( + p_ui->HelperIcon(p_group,p_param,0)).Expanded(); + helper->setIconSize(QSize(22,22)); + helper->setIcon(QIcon(QPixmap(file))); + } + else { + helper->setFixedWidth(helper->fontMetrics().width( + " " + helper->text() + " ")); + } + RememberWidget(helper); + return helper; + } + + // Make a drop down menu of helper buttons + else { + if(p_helperMenu) { + throw iException::Message(iException::Programmer, "Can not call GuiParameter::AddHelpers twice", _FILEINFO_); + } + + p_helperMenu = new QMenu (); + + // Create default action item + GuiHelperAction *action = + new GuiHelperAction(lo,(iString)p_ui->HelperFunction(p_group,p_param,0)); + if (p_ui->HelperIcon(p_group,p_param,0) != "") { + iString file = Filename( + p_ui->HelperIcon(p_group,p_param,0)).Expanded(); + action->setIcon(QIcon(QPixmap(file))); + } + else { + action->setText((iString)p_ui->HelperButtonName(p_group, p_param, 0)); + } + connect (action,SIGNAL(trigger(const QString &)),this, + SIGNAL(HelperTrigger(const QString &))); + + // Set up helper button + QToolButton *helper = new QToolButton(); + helper->setText((iString)p_ui->HelperButtonName(p_group, p_param, 0)); + + helper->setMenu(p_helperMenu); + helper->setPopupMode(QToolButton::MenuButtonPopup); + helper->setDefaultAction(action); + helper->setToolTip((iString)p_ui->HelperBrief(p_group,p_param,0)); + QString text = "

    Function: " + + QString((iString)p_ui->HelperDescription(p_group,p_param,0)) + "

    " + + "

    Hint: Click on the arrow to see more helper functions

    "; + helper->setWhatsThis(text); + + if (p_ui->HelperIcon(p_group,p_param,0) != "") { + helper->setText(""); + iString file = Filename( + p_ui->HelperIcon(p_group,p_param,0)).Expanded(); + helper->setIconSize(QSize(22,22)); + helper->setIcon(QIcon(QPixmap(file))); + } + else { + helper->setFixedWidth(helper->fontMetrics().width( + " " + helper->text() + " ")); + } + + // Set up default action item in menu list + GuiHelperAction *action2 = + new GuiHelperAction(lo,(iString)p_ui->HelperFunction(p_group,p_param,0)); + action2->setText((iString)p_ui->HelperBrief(p_group, p_param, 0)); + action2->setToolTip((iString)p_ui->HelperBrief(p_group,p_param,0)); + QString helperText = "

    Function: " + + QString((iString)p_ui->HelperDescription(p_group,p_param,0)) + "

    "; + action2->setWhatsThis(helperText); + connect (action2,SIGNAL(trigger(const QString &)),this, + SIGNAL(HelperTrigger(const QString &))); + p_helperMenu->addAction(action2); + + + // Add each additional helper button to the menu list + for (int i=1; iHelpersSize(p_group,p_param); i++) { + GuiHelperAction *helperAction = + new GuiHelperAction(lo,(iString)p_ui->HelperFunction(p_group,p_param,i)); + helperAction->setText((iString)p_ui->HelperBrief(p_group, p_param, i)); + helperAction->setToolTip((iString)p_ui->HelperBrief(p_group,p_param,i)); + QString helperText = "

    Function: " + + QString((iString)p_ui->HelperDescription(p_group,p_param,i)) + "

    "; + helperAction->setWhatsThis(helperText); + connect (helperAction,SIGNAL(trigger(const QString &)),this, + SIGNAL(HelperTrigger(const QString &))); + p_helperMenu->addAction(helperAction); + } + RememberWidget(helper); + return helper; + } + } +} diff --git a/isis/src/base/objs/Gui/GuiParameter.h b/isis/src/base/objs/Gui/GuiParameter.h new file mode 100644 index 0000000000000000000000000000000000000000..6218b731b22b9599acd4466ff457aa04ad22c76c --- /dev/null +++ b/isis/src/base/objs/Gui/GuiParameter.h @@ -0,0 +1,117 @@ +#ifndef Isis_GuiParameter_h +#define Isis_GuiParameter_h + +/** + * @file + * $Revision: 1.5 $ + * $Date: 2009/12/15 20:44:57 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include +#include + +#include "iString.h" + +namespace Isis { + class UserInterface; + +/** + * @author 2006-10-31 ??? + * + * @internal + * @history 2009-11-10 Mackenzie Boyd - Refactored to reduce + * code duplication in children GuiCubeParameter and + * GuiFilenameParameter, specifically, SelectFile + * method. + * @history 2009-12-15 Travis Addair - Moved the SelectFile + * method back to children. + */ + + class GuiParameter : public QObject { + + Q_OBJECT + + public: + + GuiParameter (QGridLayout *grid, UserInterface &ui, int group, int param); + virtual ~GuiParameter (); + + //! Return the name of the parameter + iString Name() const { return p_name; }; + + void SetToDefault (); + + void SetToCurrent (); + + virtual iString Value () = 0; + + virtual void Set (iString newValue) = 0; + + void SetEnabled (bool enabled); + + //! Is the parameter enabled + bool IsEnabled () const { return p_label->isEnabled(); } + + virtual bool IsModified(); + + void Update(); + + void RememberWidget(QWidget *w); + + QWidget *AddHelpers(QObject *lo); + + virtual std::vector Exclusions(); + + enum ParameterType { IntegerWidget, DoubleWidget, StringWidget, + ListWidget, FilenameWidget, CubeWidget, + BooleanWidget }; + ParameterType Type() { return p_type; }; + + protected: + + QToolButton *p_fileButton; + QLineEdit *p_lineEdit; + + int p_group; + int p_param; + iString p_name; + UserInterface *p_ui; + + QLabel *p_label; + + QList p_widgetList; + + ParameterType p_type; + + private: + QMenu *p_helperMenu; + + signals: + void ValueChanged(); + void HelperTrigger(const QString &); + + }; +}; + +#endif diff --git a/isis/src/base/objs/Gui/GuiParameterFactory.cpp b/isis/src/base/objs/Gui/GuiParameterFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78129b72af4680b2035da025d1ccbdf523f1a1a9 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiParameterFactory.cpp @@ -0,0 +1,50 @@ +#include "GuiListParameter.h" +#include "GuiCubeParameter.h" +#include "GuiFilenameParameter.h" +#include "GuiStringParameter.h" +#include "GuiIntegerParameter.h" +#include "GuiDoubleParameter.h" +#include "GuiBooleanParameter.h" +#include "GuiParameterFactory.h" +#include "UserInterface.h" +#include "Application.h" + +namespace Isis { + GuiParameter* GuiParameterFactory::Create (QGridLayout *grid, + Isis::UserInterface &ui, + int group, int param) { + std::string paramType = ui.ParamType(group, param); + + GuiParameter *p = NULL; + if (ui.ParamListSize(group, param) > 0) { + p = new GuiListParameter (grid, ui, group, param); + } + else if (paramType == "cube") { + p = new GuiCubeParameter (grid, ui, group, param); + } + else if (paramType == "filename") { + p = new GuiFilenameParameter (grid, ui, group, param); + } + else if (paramType == "string") { + p = new GuiStringParameter (grid, ui, group, param); + } + else if (paramType == "integer") { + p = new GuiIntegerParameter (grid, ui, group, param); + } + else if (paramType == "double") { + p = new GuiDoubleParameter (grid, ui, group, param); + } + else if (paramType == "boolean") { + p = new GuiBooleanParameter (grid, ui, group, param); + } + else { + std::string msg = "Invalid parameter type in XML [" + paramType + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + return p; + } +} + + + diff --git a/isis/src/base/objs/Gui/GuiParameterFactory.h b/isis/src/base/objs/Gui/GuiParameterFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..8abce45018fbc022aa39a3eb2c17b2865f3540f2 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiParameterFactory.h @@ -0,0 +1,22 @@ +#ifndef Isis_GuiParameterFactory_h +#define Isis_GuiParameterFactory_h + +#include +#include "GuiParameter.h" + +namespace Isis { + class GuiParameterFactory { + public: + static GuiParameter* Create (QGridLayout *grid, + Isis::UserInterface &ui, + int group, int param); + + private: + GuiParameterFactory () {}; + virtual ~GuiParameterFactory () {}; + }; +}; + + + +#endif diff --git a/isis/src/base/objs/Gui/GuiStringParameter.cpp b/isis/src/base/objs/Gui/GuiStringParameter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f62e6790489bf7db7bac4d1f796834296dea2ac7 --- /dev/null +++ b/isis/src/base/objs/Gui/GuiStringParameter.cpp @@ -0,0 +1,39 @@ +#include + +#include "GuiStringParameter.h" +#include "UserInterface.h" + +namespace Isis { + + GuiStringParameter::GuiStringParameter(QGridLayout *grid, UserInterface &ui, + int group, int param) : + GuiParameter(grid, ui, group, param) { + + p_lineEdit = new QLineEdit; + connect(p_lineEdit,SIGNAL(textChanged(const QString &)),this,SIGNAL(ValueChanged())); + grid->addWidget(p_lineEdit,param,2); + + if (p_ui->HelpersSize(group,param) != 0) { + grid->addWidget(AddHelpers(p_lineEdit),param,3); + } + + RememberWidget(p_lineEdit); + + p_type = StringWidget; + } + + + GuiStringParameter::~GuiStringParameter() {} + + void GuiStringParameter::Set (iString newValue) { + p_lineEdit->setText ((iString)newValue); + } + + + iString GuiStringParameter::Value () { + return p_lineEdit->text().toStdString(); + } + + +} + diff --git a/isis/src/base/objs/Gui/GuiStringParameter.h b/isis/src/base/objs/Gui/GuiStringParameter.h new file mode 100644 index 0000000000000000000000000000000000000000..c81cbe8672242d973bac25c92415c85f8fe1860e --- /dev/null +++ b/isis/src/base/objs/Gui/GuiStringParameter.h @@ -0,0 +1,36 @@ +#ifndef Isis_GuiStringParameter_h +#define Isis_GuiStringParameter_h + +#include + +#include "GuiParameter.h" + + +namespace Isis { + +// class QTextEdit; + + class GuiStringParameter : public GuiParameter { + + Q_OBJECT + + public: + + GuiStringParameter (QGridLayout *grid, UserInterface &ui, + int group, int param); + ~GuiStringParameter (); + + iString Value (); + + void Set (iString newValue); + + private: + QLineEdit *p_lineEdit; + + }; +}; + + + +#endif + diff --git a/isis/src/base/objs/Gui/Makefile b/isis/src/base/objs/Gui/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0a5ad585bf9cd89fa7eb5054b9d756e501fd6897 --- /dev/null +++ b/isis/src/base/objs/Gui/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp unitTest.cpp, $(wildcard *.cpp))#no moc+unitTest cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Gui/unitTest.cpp b/isis/src/base/objs/Gui/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe2a638368160f084ea6163a13a28f5730f074ff --- /dev/null +++ b/isis/src/base/objs/Gui/unitTest.cpp @@ -0,0 +1,11 @@ +#include +#include "iException.h" +#include "Preference.h" + +using namespace std; +int main (void) +{ + Isis::Preference::Preferences(true); + cout << "Replace this when we decide how to do unit tests for interactive objects" << endl; +} + diff --git a/isis/src/base/objs/HapkeAtm1/AtmosModel.plugin b/isis/src/base/objs/HapkeAtm1/AtmosModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..e48432aca430b5bc9ff7dc4c7b967b775dfc412d --- /dev/null +++ b/isis/src/base/objs/HapkeAtm1/AtmosModel.plugin @@ -0,0 +1,4 @@ +Group = HapkeAtm1 + Library = HapkeAtm1 + Routine = HapkeAtm1Plugin +End_Group diff --git a/isis/src/base/objs/HapkeAtm1/HapkeAtm1.cpp b/isis/src/base/objs/HapkeAtm1/HapkeAtm1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f07b1798ece92f62e80a64979a52cbc1eab6ba03 --- /dev/null +++ b/isis/src/base/objs/HapkeAtm1/HapkeAtm1.cpp @@ -0,0 +1,245 @@ +#include +#include "AtmosModel.h" +#include "Constants.h" +#include "HapkeAtm1.h" +#include "NumericalApproximation.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "iString.h" + +using std::max; + +namespace Isis { + HapkeAtm1::HapkeAtm1 (Pvl &pvl, PhotoModel &pmodel) : AtmosModel(pvl,pmodel) { + PvlGroup &algo = pvl.FindObject("AtmosphericModel").FindGroup("Algorithm", Pvl::Traverse); + + SetAtmosHnorm(0.003); + + if (algo.HasKeyword("Hnorm")) { + SetAtmosHnorm(algo["Hnorm"]); + } + } + + /** + * Henyey-Greenstein atmos scattering in the 1st approximation. + * Isotropic atmospheric scattering in the first approximation, + * with corrections to the singly-scattered terms (in the spirit of + * Hapke's photometric function for surfaces) for a strongly + * anisotropic single-particle phase function. The particular + * phase function implemented is a single-term Henyey-Greenstein. + * The model for scattering for a general, non-Lambertian surface with + * an atmosphere looks like this: + * + * P = Pstd + trans*(rho*Ah*munot)/(1.d0-rho*Ab*sbar) + + * trans0*rho*(Psurf-Ah*munot) + * + * where P is the overall photometric function (the model of the data), + * PSTD is the pure atmospheric-scattering term, PSURF is the surface + * photometric function, AH*MUNOT is a Lambertian approximation to this + * with hemispheric albedo AH, TRANS and TRANS0 quantify transmission + * of surface reflected light through the atmosphere overall and with + * no scatterings in the atmosphere, and finally SBAR quantifies the + * illumination of the ground by the sky. RHO is the ratio of the sur- + * face albedo to the albedo assumed in the functional form of PSURF. + * + * @param phase Value of the phase angle. + * @param incidence Value of the incidence angle. + * @param emission Value of the emission angle. + * + * @history 2000-07-07 Randy Kirk - USGS, Flagstaff - Original + * code + * @history 2000-12-18 K Teal Thompson Port to Unix/ISIS; + * @history 2007-02-20 Janet Barrett - Imported from Isis2 + * pht_atm_functions to Isis3. + * @history 2008-11-05 Jeannie Walldren - Modified references to + * NumericalMethods class and replaced Isis::PI with PI + * since this is in Isis namespace. + */ + void HapkeAtm1::AtmosModelAlgorithm (double phase, double incidence, double emission) { + double munot,mu; + double xx; + double emunot,emu; + double xmunot,ymunot; + double xmu,ymu; + double gmunot,gmu; + double hpsq1; + double munotp,mup; + double fix; + double hahgt,hahgt0; + double phasefn; + double maxval; + + if (p_atmosTau == 0.0) { + p_pstd = 0.0; + p_trans = 1.0; + p_trans0 = 1.0; + p_sbar = 0.0; + return; + } + + if (TauOrWhaChanged()) { + // preparation includes exponential integrals e sub 2 through 4 + p_wha2 = 0.5 * p_atmosWha; + p_e2 = AtmosModel::En(2,p_atmosTau); + p_e3 = AtmosModel::En(3,p_atmosTau); + p_e4 = AtmosModel::En(4,p_atmosTau); + + // zeroth moments of (uncorrected) x and y times characteristic fn + p_x0 = p_wha2; + p_y0 = p_wha2 * p_e2; + + // higher-order correction term for x and y + p_delta = (1.0 - (p_x0 + p_y0) - (1.0 - p_atmosWha) / (1.0 - (p_x0 - p_y0))) / (p_atmosWha * (0.5 - p_e3)); + + // moments of (corrected) x and y + p_alpha0 = 1.0 + p_delta * (0.5 - p_e3); + p_alpha1 = 0.5 + p_delta * ((1.0/3.0) - p_e4); + p_beta0 = p_e2 + p_delta * (0.5 - p_e3); + p_beta1 = p_e3 + p_delta * ((1.0/3.0) - p_e4); + + // prepare to find correct mixture of x and y in conservative case + if (p_atmosWha == 1.0) { + p_e5 = AtmosModel::En(5,p_atmosTau); + p_alpha2 = (1.0/3.0) + p_delta * (0.25 - p_e5); + p_beta2 = p_e4 + p_delta * (0.25 - p_e5); + p_fixcon = (p_beta0 * p_atmosTau - p_alpha1 + p_beta1) / + ((p_alpha1 + p_beta1) * p_atmosTau + 2.0 * (p_alpha2 + p_beta2)); + } + + + // gamma will be a weighted sum of x and y functions + p_gammax = p_wha2 * p_beta0; + p_gammay = 1.0 - p_wha2 * p_alpha0; + + + // sbar is total diffuse illumination + // isotropic part comes from moments, correction is numerical integral + GenerateHahgTables(); + p_sbar = 1.0 - ((2.0 - p_atmosWha * p_alpha0) * p_alpha1 + p_atmosWha * p_beta0 * p_beta1) + p_atmosHahgsb; + + SetOldTau(p_atmosTau); + SetOldWha(p_atmosWha); + } + + // correct the path lengths for planetary curvature + hpsq1 = pow((1.0+p_atmosHnorm),2.0) - 1.0; + + if (incidence == 90.0) { + munot = 0.0; + } + else { + munot = cos((PI/180.0)*incidence); + } + + maxval = max(1.0e-30,hpsq1+munot*munot); + munotp = p_atmosHnorm / (sqrt(maxval) - munot); + munotp = max(munotp,p_atmosTau/69.0); + + if (emission == 90.0) { + mu = 0.0; + } + else { + mu = cos((PI/180.0)*emission); + } + + maxval = max(1.0e-30, hpsq1 + mu*mu); + mup = p_atmosHnorm / (sqrt(maxval) - mu); + mup = max(mup, p_atmosTau / 69.0); +// build the x and y functions of mu0 and mu + maxval = max(1.0e-30,munotp); + xx = -p_atmosTau / maxval; + + if (xx < -69.0) { + emunot = 0.0; + } + else if (xx > 69.0) { + emunot = 1.0e30; + } + else { + emunot = exp(-p_atmosTau/munotp); + } + + maxval = max(1.0e-30,mup); + xx = -p_atmosTau / maxval; + + if (xx < -69.0) { + emu = 0.0; + } + else if (xx > 69.0) { + emu = 1.0e30; + } + else { + emu = exp(-p_atmosTau/mup); + } + + xmunot = 1.0 + p_delta * munotp * (1.0 - emunot); + ymunot = emunot + p_delta * munotp * (1.0 - emunot); + xmu = 1.0 + p_delta * mup * (1.0 - emu); + ymu = emu + p_delta * mup * (1.0 - emu); + + // mix the x and y as required in the conservative case + if (p_atmosWha == 1.0) { + fix = p_fixcon * munotp * (xmunot + ymunot); + xmunot = xmunot + fix; + ymunot = ymunot + fix; + fix = p_fixcon * mup * (xmu + ymu); + xmu = xmu + fix; + ymu = ymu + fix; + } + + + // gamma1 functions come from x and y, with a correction for + // highly forward-scattered light as tabulated in hahgtTable + hahgt = p_atmosHahgtSpline.Evaluate(incidence,NumericalApproximation::Extrapolate); + gmunot = p_gammax * xmunot + p_gammay * ymunot + hahgt; + + hahgt = p_atmosHahgtSpline.Evaluate(emission,NumericalApproximation::Extrapolate); + gmu = p_gammax * xmu + p_gammay * ymu + hahgt; + + // purely atmos term uses x and y (plus single-particle phase + // function correction) + if (phase == 90.0) { + phasefn = (1.0 - p_atmosHga * p_atmosHga) / pow(1.0+2.0*p_atmosHga*0.0+p_atmosHga*p_atmosHga,1.5); + } + else { + phasefn = (1.0 - p_atmosHga * p_atmosHga) / + pow(1.0 + 2.0 * p_atmosHga * cos((PI/180.0) * phase) + p_atmosHga * p_atmosHga,1.5); + } + + p_pstd = 0.25 * p_atmosWha * munotp / (munotp + mup) * + ((xmunot * xmu - ymunot * ymu) + (phasefn - 1.0) * (1.0 - emu * emunot)); + + // xmitted surface term uses gammas + p_trans = gmunot * gmu; + + // finally, never-scattered term is given by pure attenuation, with + // a correction for highly forward-scattered light (on the way down + // but not on the way up) as tabulated in hahgt0Table + hahgt0 = p_atmosHahgt0Spline.Evaluate(incidence,NumericalApproximation::Extrapolate); + p_trans0 = (emunot + hahgt0) * emu; + } + + /** + * Set the Atmospheric function parameter. This is the + * atmospheric shell thickness normalized to the planet radius + * and is used to modify angles to get more accurate path + * lengths near the terminator (ratio of scale height to the + * planetary radius). This parameter is limited to values that + * are >=0. + * + * @param hnorm Atmospheric function parameter, default is 0.003 + */ + void HapkeAtm1::SetAtmosHnorm (const double hnorm) { + if (hnorm < 0.0) { + std::string msg = "Invalid value of Atmospheric hnorm [" + iString(hnorm) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosHnorm = hnorm; + } +} + +extern "C" Isis::AtmosModel *HapkeAtm1Plugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel) { + return new Isis::HapkeAtm1(pvl,pmodel); +} diff --git a/isis/src/base/objs/HapkeAtm1/HapkeAtm1.h b/isis/src/base/objs/HapkeAtm1/HapkeAtm1.h new file mode 100644 index 0000000000000000000000000000000000000000..230c328763801ae23ad91236d95515ab43b7cf5f --- /dev/null +++ b/isis/src/base/objs/HapkeAtm1/HapkeAtm1.h @@ -0,0 +1,77 @@ +#if !defined(HapkeAtm1_h) +#define HapkeAtm1_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/11/05 23:38:28 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "AtmosModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief Implements the Hapke Atmospheric Model + * + * @ingroup RadiometricAndPhotometricCorrection + * @author 2000-07-07 Randy Kirk + * + * @internal + * @history 2000-07-07 Randy Kirk - USGS, Flagstaff - Original + * code + * @history 2007-02-20 Janet Barrett - Imported from Isis2. + * @history 2007-08-15 Steven Lambright - Refactored code + * @history 2008-03-07 Janet Barrett - Moved code to set standard + * conditions to the AtmosModel class + * @history 2008-06-18 Stuart Sides - Fixed error in + * documentation + * @history 2008-11-05 Jeannie Walldren - Modified references + * to NumericalMethods class. Added documentation from + * Isis2. + */ + class HapkeAtm1 : public AtmosModel { + public: + HapkeAtm1 (Pvl &pvl, PhotoModel &pmodel); + virtual ~HapkeAtm1() {}; + + //! Return atmospheric Hnorm value + double AtmosHnorm () const { return p_atmosHnorm; }; + + protected: + virtual void AtmosModelAlgorithm (double phase, double incidence, double emission); + + private: + void SetAtmosHnorm(const double hnorm); + + double p_atmosHnorm; + double p_e2,p_e3,p_e4,p_e5; + + double p_x0,p_y0; + double p_wha2; + double p_alpha0,p_alpha1,p_alpha2; + double p_beta0,p_beta1,p_beta2; + double p_delta; + double p_fixcon; + double p_gammax,p_gammay; + }; +}; + +#endif diff --git a/isis/src/base/objs/HapkeAtm1/HapkeAtm1.truth b/isis/src/base/objs/HapkeAtm1/HapkeAtm1.truth new file mode 100644 index 0000000000000000000000000000000000000000..a6791caa9140d5693043124fd297f5cbff705d55 --- /dev/null +++ b/isis/src/base/objs/HapkeAtm1/HapkeAtm1.truth @@ -0,0 +1,33 @@ +UNIT TEST for HapkeAtm1 atmospheric function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = AtmosphericModel + Group = Algorithm + Name = HapkeAtm1 + End_Group +End_Object +End + +Test phase=0.0, incidence=0.0, emission=0.0 (standard conditions) ... +Pstd = 0 +Trans = 1 +Trans0 = 1 +Sbar = 0 + +Test phase=86.7226722, incidence=51.7002388, emission=38.9414439 ... +Pstd = 0.0367801 +Trans = 0.87694 +Trans0 = 0.591404 +Sbar = 0.0798177 + +Test phase=180.0, incidence=90.0, emission=90.0 ... +Pstd = 1.95977 +Trans = 0.100023 +Trans0 = 5.19719e-07 +Sbar = 0.0798177 + diff --git a/isis/src/base/objs/HapkeAtm1/Makefile b/isis/src/base/objs/HapkeAtm1/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..772de434590bf4ee5cd5bd03440f4c99f1661429 --- /dev/null +++ b/isis/src/base/objs/HapkeAtm1/Makefile @@ -0,0 +1,5 @@ +INCS = HapkeAtm1.h +SRCS = HapkeAtm1.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/HapkeAtm1/unitTest.cpp b/isis/src/base/objs/HapkeAtm1/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d0843586c31f5cf6ae8f8fb4af193d0d904107b --- /dev/null +++ b/isis/src/base/objs/HapkeAtm1/unitTest.cpp @@ -0,0 +1,76 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "HapkeAtm1.h" +#include "AtmosModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + double pstd; + double trans; + double trans0; + double sbar; + + std::cout << "UNIT TEST for HapkeAtm1 atmospheric function" << std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup alga("Algorithm"); + alga += PvlKeyword("Name","HapkeAtm1"); + + PvlObject oa("AtmosphericModel"); + oa.AddGroup(alga); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(oa); + + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + HapkeAtm1 *am = (HapkeAtm1*)AtmosModelFactory::Create(pvl,*pm); + + am->SetStandardConditions(true); + am->CalcAtmEffect(0.0,0.0,0.0,&pstd,&trans,&trans0,&sbar); + am->SetStandardConditions(false); + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 (standard conditions) ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + + am->CalcAtmEffect(86.7226722,51.7002388,38.9414439,&pstd,&trans,&trans0,&sbar); + + std::cout << "Test phase=86.7226722, incidence=51.7002388, emission=38.9414439 ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + + am->CalcAtmEffect(180.0,90.0,90.0,&pstd,&trans,&trans0,&sbar); + + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/HapkeAtm2/AtmosModel.plugin b/isis/src/base/objs/HapkeAtm2/AtmosModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..96a234681153eb9171c82f2b174526c933fadc59 --- /dev/null +++ b/isis/src/base/objs/HapkeAtm2/AtmosModel.plugin @@ -0,0 +1,4 @@ +Group = HapkeAtm2 + Library = HapkeAtm2 + Routine = HapkeAtm2Plugin +End_Group diff --git a/isis/src/base/objs/HapkeAtm2/HapkeAtm2.cpp b/isis/src/base/objs/HapkeAtm2/HapkeAtm2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8d92b2a70f81feef44cda3758400dfa43351ada --- /dev/null +++ b/isis/src/base/objs/HapkeAtm2/HapkeAtm2.cpp @@ -0,0 +1,299 @@ +#include +#include "AtmosModel.h" +#include "Constants.h" +#include "HapkeAtm2.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "NumericalApproximation.h" +#include "iException.h" +#include "iString.h" + +using std::max; + +namespace Isis { + HapkeAtm2::HapkeAtm2 (Pvl &pvl, PhotoModel &pmodel) : AtmosModel(pvl,pmodel) { + PvlGroup &algo = pvl.FindObject("AtmosphericModel").FindGroup("Algorithm",Pvl::Traverse); + + SetAtmosHnorm(0.003); + + if (algo.HasKeyword("Hnorm")) { + SetAtmosHnorm(algo["Hnorm"]); + } + } +/** + * Henyey-Greenstein atmos scattering in the 1st approximation. + * Isotropic atmospheric scattering in the second approximation, + * with corrections to the singly-scattered terms (in the spirit of + * Hapke's photometric function for surfaces) for a strongly + * anisotropic single-particle phase function. The particular + * phase function implemented is a single-term Henyey-Greenstein. + * The model for scattering for a general, non-Lambertian surface with + * an atmosphere looks like this: + * + * P = Pstd + trans*(rho*Ah*munot)/(1.d0-rho*Ab*sbar) + + * trans0*rho*(psurf-Ah*munot) + * + * where P is the overall photometric function (the model of the data), + * PSTD is the pure atmospheric-scattering term, PSURF is the surface + * photometric function, AH*MUNOT is a Lambertian approximation to this + * with hemispheric albedo AH, TRANS and TRANS0 quantify transmission + * of surface reflected light through the atmosphere overall and with + * no scatterings in the atmosphere, and finally SBAR quantifies the + * illumination of the ground by the sky. RHO is the ratio of the sur- + * face albedo to the albedo assumed in the functional form of PSURF. + * + * @param phase Value of the phase angle. + * @param incidence Value of the incidence angle. + * @param emission Value of the emission angle. + * + * @history 2000-07-07 Randy Kirk - USGS, Flagstaff - Original + * code + * @history 2000-12-18 K Teal Thompson Port to Unix/ISIS; + * @history 2007-02-20 Janet Barrett - Imported from Isis2 + * pht_atm_functions to Isis3. + * @history 2008-11-05 Jeannie Walldren - Modified references + * to NumericalMethods class. Replaced Isis::PI with + * PI since this is in Isis namespace. + */ + void HapkeAtm2::AtmosModelAlgorithm (double phase, double incidence, + double p_emission) + { + double xx; + double maxval; + double munot,mu; + double p_emunot,emu; + double munotp,mup; + double f1munot,f1mmunot; + double xmunot,ymunot; + double xmu,ymu; + double gmunot,gmu; + double hpsq1; + double fix; + double f1mu,f1mmu; + double hahgt,hahgt0; + double phasefn; + + if (p_atmosTau == 0.0) { + p_pstd = 0.0; + p_trans = 1.0; + p_trans0 = 1.0; + p_sbar = 0.0; + return; + } + + if (TauOrWhaChanged()) { + + // preparation includes exponential integrals p_e sub 2 through 4 + p_wha2 = 0.5 * p_atmosWha; + p_e1 = AtmosModel::En(1,p_atmosTau); + p_e1_2 = AtmosModel::En(1,2.0*p_atmosTau); + p_e2 = AtmosModel::En(2,p_atmosTau); + p_e3 = AtmosModel::En(3,p_atmosTau); + p_e4 = AtmosModel::En(4,p_atmosTau); + + // chandra's gmn functions require fm and fn at mu=-1 + xx = -p_atmosTau; + if (xx < -69.0) { + p_em = 0.0; + } + else if (xx > 69.0) { + p_em = 1.0e30; + } + else { + p_em = exp(xx); + } + + p_f1m = log(2.0) - p_em * p_e1 + p_e1_2; + p_f2m = -1.0 * (p_f1m + p_em * p_e2 - 1.0); + p_f3m = -1.0 * (p_f2m + p_em * p_e3 - 0.5); + p_g12 = (p_atmosTau * p_e1 * p_e2 + p_f1m + p_f2m) * 0.5; + p_g13 = (p_atmosTau * p_e1 * p_e3 + p_f1m + p_f3m) * (1.0/3.0); + + // chandra's g'mn functions require g'11 and f at mu=+1 + xx = p_atmosTau; + if (xx < -69.0) { + p_e = 0.0; + } + else if (xx > 69.0) { + p_e = 1.0e30; + } + else { + p_e = exp(xx); + } + + p_f1 = Eulgam() + log(p_atmosTau) + p_e * p_e1; + p_f2 = p_f1 + p_e * p_e2 - 1.0; + p_f3 = p_f2 + p_e * p_e3 - 0.5; + p_g11p = AtmosModel::G11Prime(p_atmosTau); + p_g12p = (p_atmosTau * (p_e1 - p_g11p) + p_em * (p_f1 + p_f2)) * 0.25; + p_g13p = (p_atmosTau * (0.5 * p_e1 - p_g12p) + p_em * (p_f1 + p_f3)) * 0.2; + + // zeroth moments of (uncorrected) x and y times characteristic fn + p_x0 = p_wha2 * (1.0 + p_wha2 * p_g12); + p_y0 = p_wha2 * (p_e2 + p_wha2 * p_g12p); + + // higher-order correction term for x and y + p_delta = (1.0 - (p_x0 + p_y0) - (1.0 - p_atmosWha) / (1.0 - (p_x0 - p_y0))) / (p_atmosWha * (0.5 - p_e3)); + + // moments of (corrected) x and y + p_alpha0 = 1.0 + p_wha2 * p_g12 + p_delta * (0.5 - p_e3); + p_alpha1 = 0.5 + p_wha2 * p_g13 + p_delta * ((1.0/3.0) - p_e4); + p_beta0 = p_e2 + p_wha2 * p_g12p + p_delta * (0.5 - p_e3); + p_beta1 = p_e3 + p_wha2 * p_g13p + p_delta * ((1.0/3.0) - p_e4); + + // prepare to find correct mixture of x and y in conservative case + if (p_atmosWha == 1.0) { + p_e5 = AtmosModel::En(5, p_atmosTau); + p_f4m = -1.0 * (p_f3m + p_em * p_e4 - (1.0/3.0)); + p_g14 = (p_atmosTau * p_e1 * p_e4 + p_f1m + p_f4m) * 0.25; + p_f4 = p_f3 + p_e * p_e4 - (1.0/3.0); + p_g14p = (p_atmosTau * (0.5 * p_e1 - p_g13p) + p_em * (p_f1 + p_f4)) * (1.0/6.0); + p_alpha2 = (1.0/3.0) + p_wha2 * p_g14 + p_delta * (0.25 - p_e5); + p_beta2 = p_e4 + p_wha2 * p_g14p + p_delta * (0.25 - p_e5); + p_fixcon = (p_beta0 * p_atmosTau - p_alpha1 + p_beta1) / + ((p_alpha1 + p_beta1) * p_atmosTau + 2.0 * (p_alpha2 + p_beta2)); + } + + // gamma will be a weighted sum of x and y functions + p_gammax = p_wha2 * p_beta0; + p_gammay = 1.0 - p_wha2 * p_alpha0; + + // sbar is total diffuse illumination + // isotropic part comes from moments, correction is numerical integral + GenerateHahgTables(); + p_sbar = 1.0 - ((2.0 - p_atmosWha * p_alpha0) * p_alpha1 + p_atmosWha * p_beta0 * p_beta1) + p_atmosHahgsb; + + SetOldTau(p_atmosTau); + SetOldWha(p_atmosWha); + } + + // correct the path lengths for planetary curvature + hpsq1 = pow((1.0+p_atmosHnorm),2.0) - 1.0; + munot = cos((PI/180.0)*incidence); + maxval = max(1.0e-30,hpsq1+munot*munot); + munotp = p_atmosHnorm / (sqrt(maxval) - munot); + munotp = max(munotp,p_atmosTau/69.0); + mu = cos((PI/180.0)*p_emission); + maxval = max(1.0e-30,hpsq1+mu*mu); + mup = p_atmosHnorm / (sqrt(maxval) - mu); + mup = max(mup,p_atmosTau/69.0); + + // build the x and y functions of mu0 and mu + maxval = max(1.0e-30,munotp); + xx = -p_atmosTau / maxval; + + if (xx < -69.0) { + p_emunot = 0.0; + } + else if (xx > 69.0) { + p_emunot = 1.0e30; + } + else { + p_emunot = exp(-p_atmosTau/munotp); + } + + maxval = max(1.0e-30,mup); + xx = -p_atmosTau / maxval; + if (xx < -69.0) { + emu = 0.0; + } + else if (xx > 69.0) { + emu = 1.0e30; + } + else { + emu = exp(-p_atmosTau/mup); + } + + // in the second approximation the x and y include the p_f1 function + xx = munotp; + if (fabs(xx-1.0) < 1.0e-10) { + f1munot = p_f1; + f1mmunot = xx * (log(1.0+1.0/xx) - p_e1 * p_emunot + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); + } + else if (xx > 0.0) { + f1munot = xx * (log(xx/(1.0-xx)) + p_e1 / p_emunot + AtmosModel::Ei(p_atmosTau*(1.0/xx-1.0))); + f1mmunot = xx * (log(1.0+1.0/xx) - p_e1 * p_emunot + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); + } + else { + std::string msg = "Negative length of planetary curvature "; + msg += "encountered"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + + xx = mup; + if (fabs(xx-1.0) < 1.0e-10) { + f1mu = p_f1; + f1mmu = xx * (log(1.0+1.0/xx) - p_e1 * emu + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); + } + else if (xx > 0.0) { + f1mu = xx * (log(xx/(1.0-xx)) + p_e1 / emu + AtmosModel::Ei(p_atmosTau*(1.0/xx-1.0))); + f1mmu = xx * (log(1.0+1.0/xx) - p_e1 * emu + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); + } else { + std::string msg = "Negative length of planetary curvature "; + msg += "encountered"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + + xmunot = 1.0 + p_wha2 * f1mmunot + p_delta * munotp * (1.0 - p_emunot); + ymunot = p_emunot * (1.0 + p_wha2 * f1munot) + p_delta * munotp * (1.0 - p_emunot); + xmu = 1.0 + p_wha2 * f1mmu + p_delta * mup * (1.0 - emu); + ymu = emu * (1.0 + p_wha2 * f1mu) + p_delta * mup * (1.0 - emu); + + // mix the x and y as required in the conservative case + if (p_atmosWha == 1.0) { + fix = p_fixcon * munotp * (xmunot + ymunot); + xmunot = xmunot + fix; + ymunot = ymunot + fix; + fix = p_fixcon * mup * (xmu + ymu); + xmu = xmu + fix; + ymu = ymu + fix; + } + + // gamma1 functions come from x and y, with a correction for + // highly forward-scattered light as tabulated in hahgtTable + hahgt = p_atmosHahgtSpline.Evaluate(incidence,NumericalApproximation::Extrapolate); + gmunot = p_gammax * xmunot + p_gammay * ymunot + hahgt; + + hahgt = p_atmosHahgtSpline.Evaluate(p_emission,NumericalApproximation::Extrapolate); + gmu = p_gammax * xmu + p_gammay * ymu + hahgt; + + // purely atmos term uses x and y (plus single-particle phase + // function correction) + phasefn = (1.0 - p_atmosHga * p_atmosHga) / pow(1.0+2.0*p_atmosHga* + cos((PI/180.0)*phase)+p_atmosHga*p_atmosHga,1.5); + p_pstd = 0.25 * p_atmosWha * munotp / (munotp + mup) * ((xmunot * xmu - ymunot * ymu) + + (phasefn - 1.0) * (1.0 - emu * p_emunot)); + + // xmitted surface term uses gammas + p_trans = gmunot * gmu; + + // finally, never-scattered term is given by pure attenuation, with + // a correction for highly forward-scattered light (on the way down + // but not on the way up) as tabulated in hahgt0Table + hahgt0 = p_atmosHahgt0Spline.Evaluate(incidence,NumericalApproximation::Extrapolate); + p_trans0 = (p_emunot + hahgt0) * emu; + } + + /** + * Set the Atmospheric function parameter. This is the + * atmospheric shell thickness normalized to the planet radius + * and is used to modify angles to get more accurate path + * lengths near the terminator (ratio of scale height to the + * planetary radius). This parameter is limited to values that + * are >=0. + * + * @param hnorm Atmospheric function parameter, default is 0.003 + */ + void HapkeAtm2::SetAtmosHnorm (const double hnorm) { + if (hnorm < 0.0) { + std::string msg = "Invalid value of Atmospheric hnorm [" + iString(hnorm) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosHnorm = hnorm; + } +} + +extern "C" Isis::AtmosModel *HapkeAtm2Plugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel) { + return new Isis::HapkeAtm2(pvl,pmodel); +} diff --git a/isis/src/base/objs/HapkeAtm2/HapkeAtm2.h b/isis/src/base/objs/HapkeAtm2/HapkeAtm2.h new file mode 100644 index 0000000000000000000000000000000000000000..73137fab1b683b7515022b10f52181d7e404058b --- /dev/null +++ b/isis/src/base/objs/HapkeAtm2/HapkeAtm2.h @@ -0,0 +1,83 @@ +#if !defined(HapkeAtm2_h) +#define HapkeAtm2_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/11/05 23:38:39 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "AtmosModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief + * + * @ingroup RadiometricAndPhotometricCorrection + * @author 2000-07-07 Randy Kirk + * + * @internal + * @history 2000-07-07 Randy Kirk - USGS, Flagstaff - Original + * code + * @history 2007-02-20 Janet Barrett - Imported from Isis2. + * @history 2007-08-15 Steven Lambright - Refactored code + * @history 2008-03-07 Janet Barrett - Moved code to set + * standard conditions to the AtmosModel + * class + * @history 2008-06-18 Stuart Sides - Fixed doc error + * @history 2008-11-05 Jeannie Walldren - Modified references + * to NumericalMethods class. Added documentation + * from Isis2. + */ + class HapkeAtm2 : public AtmosModel { + public: + HapkeAtm2 (Pvl &pvl, PhotoModel &pmodel); + virtual ~HapkeAtm2() {}; + + //! Return atmospheric Hnorm value + inline double AtmosHnorm () const { return p_atmosHnorm; }; + + protected: + void SetAtmosHnorm(const double hnorm); + + virtual void AtmosModelAlgorithm (double phase, double incidence, + double emission); + + private: + double p_atmosHnorm; + double p_e1,p_e1_2,p_e2,p_e3,p_e4,p_e5; + double p_em; + double p_e; + double p_g11p,p_g12p,p_g13p,p_g14p; + double p_x0,p_y0; + double p_wha2; + double p_g12,p_g13,p_g14; + double p_f1,p_f2,p_f3,p_f4; + double p_f1m,p_f2m,p_f3m,p_f4m; + double p_delta; + double p_fixcon; + double p_alpha0,p_alpha1,p_alpha2; + double p_beta0,p_beta1,p_beta2; + double p_gammax,p_gammay; + }; +}; + +#endif diff --git a/isis/src/base/objs/HapkeAtm2/HapkeAtm2.truth b/isis/src/base/objs/HapkeAtm2/HapkeAtm2.truth new file mode 100644 index 0000000000000000000000000000000000000000..c504d14ad1494e4b65d573bf398ae7ced57e774b --- /dev/null +++ b/isis/src/base/objs/HapkeAtm2/HapkeAtm2.truth @@ -0,0 +1,33 @@ +UNIT TEST for HapkeAtm2 atmospheric function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = AtmosphericModel + Group = Algorithm + Name = HapkeAtm2 + End_Group +End_Object +End + +Test phase=0.0, incidence=0.0, emission=0.0 (standard conditions) ... +Pstd = 0 +Trans = 1 +Trans0 = 1 +Sbar = 0 + +Test phase=86.7226722, incidence=51.7002388, emission=38.9414439 ... +Pstd = 0.0444537 +Trans = 0.821832 +Trans0 = 0.591404 +Sbar = 0.126012 + +Test phase=180.0, incidence=90.0, emission=90.0 ... +Pstd = 1.96829 +Trans = 0.0866976 +Trans0 = 5.19719e-07 +Sbar = 0.126012 + diff --git a/isis/src/base/objs/HapkeAtm2/Makefile b/isis/src/base/objs/HapkeAtm2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8ccf5f7ec410d73d9855e4e3282e6dd0b81704d5 --- /dev/null +++ b/isis/src/base/objs/HapkeAtm2/Makefile @@ -0,0 +1,5 @@ +INCS = HapkeAtm2.h +SRCS = HapkeAtm2.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/HapkeAtm2/unitTest.cpp b/isis/src/base/objs/HapkeAtm2/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf5c64bff0fed60ba2517c52cee656740f6406ab --- /dev/null +++ b/isis/src/base/objs/HapkeAtm2/unitTest.cpp @@ -0,0 +1,75 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "AtmosModel.h" +#include "AtmosModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + double pstd; + double trans; + double trans0; + double sbar; + + std::cout << "UNIT TEST for HapkeAtm2 atmospheric function" << std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup alga("Algorithm"); + alga += PvlKeyword("Name","HapkeAtm2"); + + PvlObject oa("AtmosphericModel"); + oa.AddGroup(alga); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(oa); + + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + AtmosModel *am = AtmosModelFactory::Create(pvl,*pm); + + am->SetStandardConditions(true); + am->CalcAtmEffect(0.0,0.0,0.0,&pstd,&trans,&trans0,&sbar); + am->SetStandardConditions(false); + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 (standard conditions) ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + + am->CalcAtmEffect(86.7226722,51.7002388,38.9414439,&pstd,&trans,&trans0,&sbar); + + std::cout << "Test phase=86.7226722, incidence=51.7002388, emission=38.9414439 ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + + am->CalcAtmEffect(180.0,90.0,90.0,&pstd,&trans,&trans0,&sbar); + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/HapkeHen/HapkeHen.cpp b/isis/src/base/objs/HapkeHen/HapkeHen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e46d2376201a07cc71904167a841b6da050d30a7 --- /dev/null +++ b/isis/src/base/objs/HapkeHen/HapkeHen.cpp @@ -0,0 +1,270 @@ +#include +#include "Constants.h" +#include "HapkeHen.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "iString.h" + +using namespace std; + +namespace Isis { + + HapkeHen::HapkeHen (Pvl &pvl) : HapkePhotoModel(pvl) { + p_photoHg1 = 0.0; + p_photoHg2 = 0.0; + + PvlGroup &algorithm = pvl.FindObject("PhotometricModel").FindGroup("Algorithm",Pvl::Traverse); + + if (algorithm.HasKeyword("Hg1")) { + SetPhotoHg1(algorithm["Hg1"]); + } + + if (algorithm.HasKeyword("Hg2")) { + SetPhotoHg2(algorithm["Hg2"]); + } + } + + /* + * Computes normal albedo mult factor w/o opp surge from + * Hapke input parameters: W,H,BO,HG,THETA. + * Full-up Hapke's Law with macroscopic roughness. The photometric + * function multiplied back in will be modified to take out oppos- + * ition effect. This requires saving the actual value of B0 while + * temporarily setting it to zero in the common block to compute + * the overall normalization. + * + * @param phase Value of phase angle, in degrees. + * @param incidence Value of incidence angle, in degrees. + * @param emission Value of emission angle, in degrees. + * @returns double + * + * + * @history 1989-08-02 Unknown author in Isis2 under name pht_hapke + * @history 1991-08-07 Tammy Becker relinked hapke to new photompr + * @history 1997-02-16 James M Anderson - changed nonstandard degree trig + * to use radians + * @history 1999-01-11 KTT - Remove mu,munot,and alpha from the argument + * list and pass in only ema,inc, and phase. Remove + * lat and lon from argument list because they aren't + * used. + * @history 1999-03-01 K Teal Thompson Implement 1999-01-08 Randy Kirk + * Original Specs & Code. Declare vars, add implicit none. + * @history 1999-11-18 Randy Kirk - fixed minor typos, implemented return with + * smooth Hapke (Theta=0) result before doing rough Hapke + * calculations, allow single-particle-phase params = 0 + * @history 2008-01-14 Janet Barrett - Imported into Isis3. Changed name from pht_hapke to PhotoModelAlgorithm() + * @history 2008-11-05 Jeannie Walldren - Added documentation + * from Isis2 files. Replaced Isis::PI with PI since this is in Isis namespace. + * + */ + double HapkeHen::PhotoModelAlgorithm (double phase, double incidence, + double emission) { + double pht_hapkehen; + double pharad; //phase angle in radians + double incrad; // incidence angle in radians + double emarad; // emission angle in radians + double munot; + double mu; + double cost; + double sint; + double tan2t; + double gamma; + double hgs; + double sing; + double cosg; + double tang; + double bg; + double pg; + double pg1; + double pg2; + double sini; + double coti; + double cot2i; + double ecoti; + double ecot2i; + double u0p0; + double sine; + double cote; + double cot2e; + double cosei; + double sinei; + double caz; + double az; + double az2; + double faz; + double tanaz2; + double sin2a2; + double api; + double ecote; + double ecot2e; + double up0; + double q; + double ecei; + double s2ei; + double u0p; + double up; + double ecee; + double s2ee; + double rr1; + double rr2; + + pharad = phase * PI / 180.0; + incrad = incidence * PI / 180.0; + emarad = emission * PI / 180.0; + munot = cos(incrad); + mu = cos(emarad); + + if (p_photoTheta != p_photoThetaold) { + cost = cos(p_photoTheta * PI / 180.0); + sint = sin(p_photoTheta * PI / 180.0); + p_photoCott = cost / max(1.0e-10, sint); + p_photoCot2t = p_photoCott * p_photoCott; + p_photoTant = sint / cost; + tan2t = p_photoTant * p_photoTant; + p_photoSr = sqrt(1.0 + PI * tan2t); + p_photoOsr = 1.0 / p_photoSr; + SetOldTheta(p_photoTheta); + } + + if (incidence >= 90.0) { + pht_hapkehen = 0.0; + return pht_hapkehen; + } + + gamma = sqrt(1.0 - p_photoWh); + hgs = p_photoHg1 * p_photoHg1; + + sing = sin(pharad); + cosg = cos(pharad); + tang = sing / max(1.0e-10, cosg); + + if (p_photoHh == 0.0) { + bg = 0.0; + } else { + if (phase <= 90.0) { + bg = p_photoB0 / max(-5.0, 1.0 + tang / p_photoHh); + } else { + bg = 0.0; + } + } + + pg1 = (1.0 - p_photoHg2) * (1.0 - hgs) / pow((1.0 + hgs + 2.0 * + p_photoHg1 * cosg), 1.5); + pg2 = p_photoHg2 * (1.0 - hgs) / pow((1.0 + hgs - 2.0 * + p_photoHg1 * cosg), 1.5); + pg = pg1 + pg2; + + if (p_photoTheta <= 0.0) { + pht_hapkehen = p_photoWh / 4.0 * munot / (munot + mu) * ((1.0 + bg) * + pg - 1.0 + Hfunc(munot,gamma) * Hfunc(mu,gamma)); + return pht_hapkehen; + } + + sini = sin(incrad); + coti = munot / max(1.0e-10, sini); + cot2i = coti * coti; + ecoti = exp(min(-p_photoCot2t * cot2i / PI , 23.0)); + ecot2i = exp(min(-2.0 * p_photoCott * coti / PI, 23.0)); + u0p0 = p_photoOsr * (munot + sini * p_photoTant * ecoti / (2.0 - ecot2i)); + + sine = sin(emarad); + cote = mu / max(1.0e-10, sine); + cot2e = cote * cote; + + cosei = mu * munot; + sinei = sine * sini; + + if (sinei == 0.0) { + caz = 1.0; + az = 0.0; + } else { + caz = (cosg - cosei) / sinei; + if (caz <= -1.0) { + az = 180.0; + } else if (caz > 1.0) { + az = 0.0; + } else { + az = acos(caz) * 180.0 / PI; + } + } + + az2 = az / 2.0; + if (az2 >= 90.0) { + faz = 0.0; + } else { + tanaz2 = tan(az2 * PI / 180.0); + faz = exp(min(-2.0 * tanaz2, 23.0)); + } + + sin2a2 = pow(sin(az2 * PI / 180.0), 2.0); + api = az / 180.0; + + ecote = exp(min(-p_photoCot2t * cot2e / PI, 23.0)); + ecot2e = exp(min(-2.0 * p_photoCott * cote / PI, 23.0)); + up0 = p_photoOsr * (mu + sine * p_photoTant * ecote / (2.0 - ecot2e)); + + if (incidence <= emission) { + q = p_photoOsr * munot / u0p0; + } else { + q = p_photoOsr * mu / up0; + } + + if (incidence <= emission) { + ecei = (2.0 - ecot2e - api * ecot2i); + s2ei = sin2a2 * ecoti; + u0p = p_photoOsr * (munot + sini * p_photoTant * (caz * ecote + s2ei) / ecei); + up = p_photoOsr * (mu + sine * p_photoTant * (ecote - s2ei) / ecei); + } else { + ecee = (2.0 - ecot2i - api * ecot2e); + s2ee = sin2a2 * ecote; + u0p = p_photoOsr * (munot + sini * p_photoTant * (ecoti - s2ee) / ecee); + up = p_photoOsr * (mu + sine * p_photoTant * (caz * ecoti + s2ee) / ecee); + } + + rr1 = p_photoWh / 4.0 * u0p / (u0p + up) * ((1.0 + bg) * pg - + 1.0 + Hfunc(u0p, gamma) * Hfunc(up, gamma)); + rr2 = up * munot / (up0 * u0p0 * p_photoSr * (1.0 - faz + faz * q)); + pht_hapkehen = rr1 * rr2; + + return pht_hapkehen; + } + + /** + * Set the Hapke Henyey Greenstein coefficient for the single + * particle phase function. This is one of two coefficients + * needed for the single particle phase function. This parameter + * is limited to values that are >-1 and <1. + * + * @param hg1 Hapke Henyey Greenstein coefficient, default is 0.0 + */ + void HapkeHen::SetPhotoHg1 (const double hg1) { + if (hg1 <= -1.0 || hg1 >= 1.0) { + string msg = "Invalid value of Hapke Henyey Greenstein hg1 [" + + iString(hg1) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_photoHg1 = hg1; + } + + /** + * Set the Hapke Henyey Greenstein coefficient for the single + * particle phase function. This is one of two coefficients + * needed for the single particle phase function. This parameter + * is limited to values that are >=0 and <=1. + * + * @param hg2 Hapke Henyey Greenstein coefficient, default is 0.0 + */ + void HapkeHen::SetPhotoHg2 (const double hg2) { + if (hg2 < 0.0 || hg2 > 1.0) { + string msg = "Invalid value of Hapke Henyey Greenstein hg2 [" + + iString(hg2) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_photoHg2 = hg2; + } +} + +extern "C" Isis::PhotoModel *HapkeHenPlugin (Isis::Pvl &pvl) { + return new Isis::HapkeHen(pvl); +} diff --git a/isis/src/base/objs/HapkeHen/HapkeHen.h b/isis/src/base/objs/HapkeHen/HapkeHen.h new file mode 100644 index 0000000000000000000000000000000000000000..4282e83589a7323c0851fd350530720f5a00d014 --- /dev/null +++ b/isis/src/base/objs/HapkeHen/HapkeHen.h @@ -0,0 +1,83 @@ +#ifndef HapkeHen_h +#define HapkeHen_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/11/05 23:38:50 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "HapkePhotoModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief Hapke-Henyey-Greenstein photometric model. + * Derive model albedo using complete Hapke model with + * Henyey-Greenstein single-particle phase function + * whose coefficients are hg1 and hg2, plus single + * scattering albedo wh, opposition surge parameters + * hh and b0, and macroscopic roughness theta. + * + * @ingroup RadiometricAndPhotometricCorrection + * @author 1989-08-02 Unknown + * @history 2008-01-14 Janet Barret - Imported into Isis3 from + * Isis2. + * @history 2008-03-07 Janet Barrett - Moved variables and related + * methods that pertain to Hapke specific parameters + * to the PhotoModel class. + * @history 2008-06-18 Stuart Sides - Fixed doc error + * @history 2008-10-17 Steven Lambright - Changed inheritance, moved + * HapkeHen specific methods into this class from + * the base class. + * @history 2008-11-05 Jeannie Walldren - Added documentation + * from Isis2 files + * + */ + class HapkeHen : public HapkePhotoModel { + public: + HapkeHen (Pvl &pvl); + virtual ~HapkeHen() {}; + + void SetPhotoHg1(const double hg1); + //! Return photometric Hg1 value + inline double PhotoHg1 () const { return p_photoHg1; }; + + void SetPhotoHg2(const double hg2); + //! Return photometric Hg2 value + inline double PhotoHg2 () const { return p_photoHg2; }; + + protected: + virtual double PhotoModelAlgorithm (double phase, double incidence, + double emission); + + private: + double p_photoHg1; + double p_photoHg2; + double p_photoCott; + double p_photoCot2t; + double p_photoTant; + double p_photoSr; + double p_photoOsr; + }; +}; + +#endif diff --git a/isis/src/base/objs/HapkeHen/HapkeHen.truth b/isis/src/base/objs/HapkeHen/HapkeHen.truth new file mode 100644 index 0000000000000000000000000000000000000000..c4a66da53655f5b970c6b183c115dce4c55b348c --- /dev/null +++ b/isis/src/base/objs/HapkeHen/HapkeHen.truth @@ -0,0 +1,24 @@ +UNIT TEST for HapkeHen photometric function + +Object = PhotometricModel + Group = Algorithm + Name = HapkeHen + Wh = 0.52 + B0 = 0.0 + Hh = 0.0 + Theta = 30.0 + Hg1 = 0.213 + Hg2 = 1.0 + End_Group +End_Object +End + +Test phase=0.0, incidence=0.0, emission=0.0 ... +Albedo = 0.158749 + +Test phase=60.0, incidence=45.0, emission=30.0 ... +Albedo = 0.0911799 + +Test phase=180.0, incidence=90.0, emission=90.0 ... +Albedo = 0 + diff --git a/isis/src/base/objs/HapkeHen/Makefile b/isis/src/base/objs/HapkeHen/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c818c8b7c342ed568c38173da8307dde80824640 --- /dev/null +++ b/isis/src/base/objs/HapkeHen/Makefile @@ -0,0 +1,5 @@ +INCS = HapkeHen.h +SRCS = HapkeHen.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/HapkeHen/PhotoModel.plugin b/isis/src/base/objs/HapkeHen/PhotoModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..bd617e2928e135c312fdae5cb6beced57240dca6 --- /dev/null +++ b/isis/src/base/objs/HapkeHen/PhotoModel.plugin @@ -0,0 +1,4 @@ +Group = HapkeHen + Library = HapkeHen + Routine = HapkeHenPlugin +End_Group diff --git a/isis/src/base/objs/HapkeHen/unitTest.cpp b/isis/src/base/objs/HapkeHen/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eb659fefec2adef1b37b9951377a57e94f63fd7b --- /dev/null +++ b/isis/src/base/objs/HapkeHen/unitTest.cpp @@ -0,0 +1,51 @@ +#include +#include +#include "HapkeHen.h" +#include "PhotoModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" + +using namespace Isis; + +int main () { + std::cout << "UNIT TEST for HapkeHen photometric function" << + std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","HapkeHen"); + algp += PvlKeyword("Wh",0.52); + algp += PvlKeyword("B0",0.0); + algp += PvlKeyword("Hh",0.0); + algp += PvlKeyword("Theta",30.0); + algp += PvlKeyword("Hg1",0.213); + algp += PvlKeyword("Hg2",1.0); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + Pvl pvl; + pvl.AddObject(op); + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(0.0,0.0,0.0) << std::endl << std::endl; + + std::cout << "Test phase=60.0, incidence=45.0, emission=30.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(60.0,45.0,30.0) << std::endl << std::endl; + + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(180.0,90.0,90.0) << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/HapkePhotoModel/HapkePhotoModel.cpp b/isis/src/base/objs/HapkePhotoModel/HapkePhotoModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99db0ed31a0f1583b0a65ca2f5fda87964cb1a6d --- /dev/null +++ b/isis/src/base/objs/HapkePhotoModel/HapkePhotoModel.cpp @@ -0,0 +1,115 @@ +#include +#include "HapkePhotoModel.h" +#include "iException.h" + +using namespace std; + +namespace Isis { + HapkePhotoModel::HapkePhotoModel (Pvl &pvl) : PhotoModel(pvl) { + p_photoHh = 0.0; + p_photoB0 = 0.0; + p_photoTheta = 0.0; + p_photoWh = 0.5; + p_photoThetaold = -999.0; + + PvlGroup &algorithm = pvl.FindObject("PhotometricModel").FindGroup("Algorithm",Pvl::Traverse); + + if (algorithm.HasKeyword("Wh")) { + SetPhotoWh(algorithm["Wh"]); + } + + if (algorithm.HasKeyword("Hh")) { + SetPhotoHh(algorithm["Hh"]); + } + + if (algorithm.HasKeyword("B0")) { + SetPhotoB0(algorithm["B0"]); + } + + p_photoB0save = p_photoB0; + + if (algorithm.HasKeyword("Theta")) { + SetPhotoTheta(algorithm["Theta"]); + } + } + + + /** + * Set the Hapke single scattering albedo component. + * This parameter is limited to values that are >0 and + * <=1. + * + * @param wh Hapke single scattering albedo component, default is 0.5 + */ + void HapkePhotoModel::SetPhotoWh (const double wh) { + if (wh <= 0.0 || wh > 1.0) { + string msg = "Invalid value of Hapke wh [" + + iString(wh) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_photoWh = wh; + } + + + /** + * Set the Hapke opposition surge component. This is one of + * two opposition surge components needed for the Hapke model. + * This parameter is limited to values that are >=0. + * + * @param hh Hapke opposition surge component, default is 0.0 + */ + void HapkePhotoModel::SetPhotoHh (const double hh) { + if (hh < 0.0) { + string msg = "Invalid value of Hapke hh [" + + iString(hh) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_photoHh = hh; + } + + + /** + * Set the Hapke opposition surge component. This is one of + * two opposition surge components needed for the Hapke model. + * This parameter is limited to values that are >=0. + * + * @param b0 Hapke opposition surge component, default is 0.0 + */ + void HapkePhotoModel::SetPhotoB0 (const double b0) { + if (b0 < 0.0) { + string msg = "Invalid value of Hapke b0 [" + + iString(b0) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_photoB0 = b0; + } + + + /** + * Set the Hapke macroscopic roughness component. This parameter + * is limited to values that are >=0 and <=90. + * + * @param theta Hapke macroscopic roughness component, default is 0.0 + */ + void HapkePhotoModel::SetPhotoTheta (const double theta) { + if (theta < 0.0 || theta > 90.0) { + string msg = "Invalid value of Hapke theta [" + + iString(theta) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_photoTheta = theta; + } + + + void HapkePhotoModel::SetStandardConditions(bool standard) { + PhotoModel::SetStandardConditions(standard); + + if (standard) { + p_photoB0save = p_photoB0; + p_photoB0 = 0.0; + } + else { + p_photoB0 = p_photoB0save; + } + } +} diff --git a/isis/src/base/objs/HapkePhotoModel/HapkePhotoModel.h b/isis/src/base/objs/HapkePhotoModel/HapkePhotoModel.h new file mode 100644 index 0000000000000000000000000000000000000000..14b25e0e402a9508005e269340546d053b21dfa0 --- /dev/null +++ b/isis/src/base/objs/HapkePhotoModel/HapkePhotoModel.h @@ -0,0 +1,89 @@ +#ifndef HapkePhotoModel_h +#define HapkePhotoModel_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/10/17 16:58:50 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "PhotoModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief Hapke photometric model class. + * + * This class contains the shared data between all Hapke photometric models. + * These photometric models include Hapke Legendre, Hapke Legendre Smooth, + * Hapke Henyey Greenstein, and Hapke Henyey Greenstein Smooth. + * + * This class is not a photometric model in itself, it simply handles these + * parameters: + * Wh + * Hh + * B0 + * Theta + * + * @author 2008-10-17 Steven Lambright + * + */ + class HapkePhotoModel : public PhotoModel { + public: + HapkePhotoModel (Pvl &pvl); + virtual ~HapkePhotoModel() {}; + + void SetPhotoWh(const double wh); + //! Return photometric Wh value + inline double PhotoWh () const { return p_photoWh; }; + + void SetPhotoHh(const double hh); + //! Return photometric Hh value + inline double PhotoHh () const { return p_photoHh; }; + + void SetPhotoB0(const double b0); + //! Return photometric B0 value + inline double PhotoB0 () const { return p_photoB0; }; + + void SetPhotoTheta(const double theta); + //! Return photometric Theta value + inline double PhotoTheta () const { return p_photoTheta; }; + + void SetOldTheta(double theta) { p_photoThetaold = theta; } + + //! Hapke's approximation to Chandra's H function + inline double Hfunc(double u, double gamma) { + return (1.0 + 2.0 * u)/(1.0 + 2.0 * u * gamma); + } + + void SetStandardConditions(bool standard); + + protected: + double p_photoWh; + double p_photoHh; + double p_photoB0; + double p_photoB0save; + double p_photoTheta; + double p_photoThetaold; + }; +}; + +#endif diff --git a/isis/src/base/objs/HapkePhotoModel/HapkePhotoModel.truth b/isis/src/base/objs/HapkePhotoModel/HapkePhotoModel.truth new file mode 100644 index 0000000000000000000000000000000000000000..3879f2c0964c14111ba2f8b3b41b19490035e5e1 --- /dev/null +++ b/isis/src/base/objs/HapkePhotoModel/HapkePhotoModel.truth @@ -0,0 +1,30 @@ +HapkePhotoModel unit test + +Test No Model +**PVL ERROR** Unable to find object [PhotometricModel] + +Test Defaults +Object = PhotometricModel + Group = Algorithm + End_Group +End_Object +End +SUCCESS + +0.5,0,0,0,0.6 + +Test Initialized +Object = PhotometricModel + Group = Algorithm + Name = Test + Wh = 1 + Hh = 2 + B0 = 3 + Theta = 4 + End_Group +End_Object +End +SUCCESS + +1,2,3,4,0.6 + diff --git a/isis/src/base/objs/HapkePhotoModel/Makefile b/isis/src/base/objs/HapkePhotoModel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9d33c2f05a84acb1e825006b5e075013d0c7b05d --- /dev/null +++ b/isis/src/base/objs/HapkePhotoModel/Makefile @@ -0,0 +1,5 @@ +INCS = HapkePhotoModel.h +SRCS = HapkePhotoModel.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/HapkePhotoModel/unitTest.cpp b/isis/src/base/objs/HapkePhotoModel/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..40f1ffa59c59c54e1d05a1d0e4f2a022cefd6f2b --- /dev/null +++ b/isis/src/base/objs/HapkePhotoModel/unitTest.cpp @@ -0,0 +1,79 @@ +#include "HapkePhotoModel.h" +#include "Preference.h" +#include "iException.h" + +using namespace Isis; + +class TestHapke : public HapkePhotoModel { + public: + TestHapke(Pvl &alg) : HapkePhotoModel(alg) {} + + protected: + virtual double PhotoModelAlgorithm(double,double,double) { + return 0.0; + } +}; + +int main() { + Isis::Preference::Preferences(true); + + std::cout << "HapkePhotoModel unit test" << std::endl << std::endl; + + std::cout << "Test No Model" << std::endl; + Pvl alg; + try { + TestHapke model(alg); + std::cout << "SUCCESS" << std::endl; + } + catch (iException &e) { + e.Report(false); + e.Clear(); + } + + alg += PvlObject("PhotometricModel"); + alg.FindObject("PhotometricModel") += PvlGroup("Algorithm"); + + std::cout << std::endl << "Test Defaults" << std::endl; + try { + std::cout << alg << std::endl; + TestHapke model(alg); + std::cout << "SUCCESS" << std::endl; + std::cout << std::endl; + std::cout << model.PhotoWh() << "," + << model.PhotoHh() << "," + << model.PhotoB0() << "," + << model.PhotoTheta() << "," + << model.Hfunc(1,2) << std::endl; + std::cout << std::endl; + } + catch (iException &e) { + e.Report(false); + e.Clear(); + } + + alg.FindObject("PhotometricModel").FindGroup("Algorithm") += PvlKeyword("Name", "Test"); + alg.FindObject("PhotometricModel").FindGroup("Algorithm") += PvlKeyword("Wh", 1); + alg.FindObject("PhotometricModel").FindGroup("Algorithm") += PvlKeyword("Hh", 2); + alg.FindObject("PhotometricModel").FindGroup("Algorithm") += PvlKeyword("B0", 3); + alg.FindObject("PhotometricModel").FindGroup("Algorithm") += PvlKeyword("Theta", 4); + + std::cout << "Test Initialized" << std::endl; + try { + std::cout << alg << std::endl; + TestHapke model(alg); + std::cout << "SUCCESS" << std::endl; + std::cout << std::endl; + std::cout << model.PhotoWh() << "," + << model.PhotoHh() << "," + << model.PhotoB0() << "," + << model.PhotoTheta() << "," + << model.Hfunc(1,2) << std::endl; + std::cout << std::endl; + } + catch (iException &e) { + e.Report(false); + e.Clear(); + } + + return 0; +} diff --git a/isis/src/base/objs/HexConverter/HexConverter.cpp b/isis/src/base/objs/HexConverter/HexConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f82a30d47f543c5370aa4622aa877fcf50d52d25 --- /dev/null +++ b/isis/src/base/objs/HexConverter/HexConverter.cpp @@ -0,0 +1,221 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2010/05/14 20:24:29 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "HexConverter.h" + +#include + +#include + +#include "iString.h" +#include "iException.h" + +using namespace std; + +namespace Isis { + /** + * This converts HEX to an iString. Not a good choice if you + * expect binary data to come out of the hex code. + * + * @param hexCode + * + * @return iString + */ + iString HexConverter::ToString(iString hexCode) { + QByteArray binaryVersion; + iString result; + + binaryVersion = ToBinary(hexCode); + + for(int i = 0; i < binaryVersion.size(); i++) { + result += binaryVersion[i]; + } + + return result; + } + + + /** + * This converts HEX to an array of bytes. + * + * @param hexCode + * + * @return QByteArray + */ + QByteArray HexConverter::ToBinary(iString hexCode) { + QByteArray result; + + unsigned int pos = 0; + bool byteStarted = false; + + while(pos < hexCode.length()) { + if(!IsHex(hexCode[pos])) { + pos ++; + continue; + } + + if(!byteStarted) { + result.push_back(HexToChar(hexCode[pos]) << 4); + byteStarted = true; + } + else { + result.data()[result.size() - 1] += HexToChar(hexCode[pos]); + byteStarted = false; + } + + pos ++; + } + + if(byteStarted) { + iString msg = "An even number of hex codes are required to decode into "; + msg += "bytes"; + throw iException::Message(iException::Io, msg, _FILEINFO_); + } + + return result; + } + + + /** + * This converts an iString to Hex + * + * @param str + * + * @return QByteArray + */ + iString HexConverter::ToHex(iString str) { + QByteArray stringArray; + + for(unsigned int strPos = 0; strPos < str.length(); strPos++) { + stringArray.push_back(str[strPos]); + } + + return ToHex(stringArray); + } + + + /** + * This converts an array of bytes to Hex + * + * @param binary + * + * @return QByteArray + */ + iString HexConverter::ToHex(QByteArray binary) { + iString result; + + for(int bytePos = 0; bytePos < binary.size(); bytePos++) { + char thisByte = binary[bytePos]; + result += CharToHex(thisByte); + } + + return result; + } + + + /** + * Returns true if the character is 0-9, a-f, A-F + * + * @author slambright (5/14/2010) + * + * @param hex + * + * @return bool + */ + bool HexConverter::IsHex(char hex) { + if(hex >= '0' && hex <= '9') return true; + if(hex >= 'a' && hex <= 'f') return true; + if(hex >= 'A' && hex <= 'F') return true; + + return false; + } + + + /** + * Converts hex to binary (always in the first 4 bits) + * + * @param hex + * + * @return char + */ + char HexConverter::HexToChar(char hex) { + if(hex >= '0' && hex <= '9') { + return (char)(hex - '0'); + } + + if(hex >= 'a' && hex <= 'f') { + return (char)(10 + hex - 'a'); + } + + if(hex >= 'A' && hex <= 'F') { + return (char)(10 + hex - 'A'); + } + + iString error = "Character ["; + error += hex; + error += "] does not appear to be a hex digit"; + throw iException::Message(iException::Programmer, error, _FILEINFO_); + } + + + /** + * Converts a binary char to hex (2 hex characters) + * + * @param binary + * + * @return iString + */ + iString HexConverter::CharToHex(char binary) { + // get the left and right parts of the character + char bin1 = binary >> 4; + char bin2 = binary & 0xF; + + char hex1 = NibbleToHex(bin1); + char hex2 = NibbleToHex(bin2); + + iString result; + result += hex1; + result += hex2; + + return result; + } + + + /** + * A nibble is 4 bits (half a byte). Converts half a byte to a + * hex value (0-9,A-F) + * + * @param binary + * + * @return iString + */ + char HexConverter::NibbleToHex(char binary) { + binary &= 0xF; + + if(binary < 10) { + return binary + '0'; + } + else { + return binary - 10 + 'A'; + } + } +} diff --git a/isis/src/base/objs/HexConverter/HexConverter.h b/isis/src/base/objs/HexConverter/HexConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..be1c908e05a595ae982fbdab29c28899985a627f --- /dev/null +++ b/isis/src/base/objs/HexConverter/HexConverter.h @@ -0,0 +1,60 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2010/05/14 20:24:29 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef HexConverter_h +#define HexConverter_h + +class QByteArray; + +namespace Isis { + class iString; + + /** + * @brief Convert to and from ASCII Hex Notation + * + * @ingroup Utility + * + * @author + * + * @internal + */ + class HexConverter { + public: + static iString ToString(iString hexCode); + static QByteArray ToBinary(iString hexCode); + + static iString ToHex(iString str); + static iString ToHex(QByteArray binary); + + private: + //! Not implemented, this class can only be used statically + HexConverter(); + + static bool IsHex(char hex); + static char HexToChar(char hex); + static iString CharToHex(char binary); + static char NibbleToHex(char binary); + }; +}; + +#endif diff --git a/isis/src/base/objs/HexConverter/HexConverter.truth b/isis/src/base/objs/HexConverter/HexConverter.truth new file mode 100644 index 0000000000000000000000000000000000000000..8cfda97fc2a756999e98da6f87d7f5595bb21ed5 --- /dev/null +++ b/isis/src/base/objs/HexConverter/HexConverter.truth @@ -0,0 +1,3 @@ +Original String: Hello, This is A C#$$@Oo))*$@l String +Hex String: 48656C6C6F2C205468697320697320412043232424404F6F29292A24406C2009537472696E67 +Reconverted String: Hello, This is A C#$$@Oo))*$@l String diff --git a/isis/src/base/objs/HexConverter/Makefile b/isis/src/base/objs/HexConverter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d04d2487c1daeb89d30b71d6b2870a19846a8f36 --- /dev/null +++ b/isis/src/base/objs/HexConverter/Makefile @@ -0,0 +1,5 @@ +INCS = HexConverter.h +SRCS = HexConverter.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/HexConverter/unitTest.cpp b/isis/src/base/objs/HexConverter/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd49d5ee98f32e9e77a5e2e21e04f275e8bacda0 --- /dev/null +++ b/isis/src/base/objs/HexConverter/unitTest.cpp @@ -0,0 +1,17 @@ +#include "HexConverter.h" + +#include + +#include "iString.h" + +using namespace std; +using namespace Isis; + +int main() { + iString testStr = "Hello, This is A C#$$@Oo))*$@l \tString"; + cout << "Original String: " << testStr << "\n"; + testStr = HexConverter::ToHex(testStr); + cout << "Hex String: " << testStr << "\n"; + testStr = HexConverter::ToString(testStr); + cout << "Reconverted String: " << testStr << "\n"; +} diff --git a/isis/src/base/objs/Histogram/Histogram.cpp b/isis/src/base/objs/Histogram/Histogram.cpp new file mode 100644 index 0000000000000000000000000000000000000000..334b3797f750a6c98209d1fc80cbb79a758381ea --- /dev/null +++ b/isis/src/base/objs/Histogram/Histogram.cpp @@ -0,0 +1,407 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/08/15 22:03:32 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "Histogram.h" +#include "Message.h" +#include "LineManager.h" +#include +#include + +using namespace std; +namespace Isis { + + /** + * Constructs a histogram object. Only data between the minimum and maximum + * will be binned, and the bin range will be from the minimum to the maximum. + * + * @param minimum Minimum value for binning the data into the histogram. + * @param maximum Maximum value for binning the data into the histogram. + * @param nbins The number of bins to use + */ + Histogram::Histogram (const double minimum, const double maximum, + const int nbins) { + SetValidRange(minimum,maximum); + SetBinRange(minimum, maximum); + SetBins(nbins); + } + + + /** + * Constructs a histogram object using a cube. This constructor computes + * the minimum, maximum for the binning range and number of bins + * automatically. All statistics will still be collected, though data at + * either end of the histogram will be put into one bin in order to attempt to + * achieve better histogram statistics. + * + * @param cube The cube to used to determine min/max and bins + * @param band The band number the histogram will be collected from + * @param progress The Isis::Progress object to be used to output the percent + * processed information + */ + Histogram::Histogram (Cube &cube, const int band, Progress *progress) { + InitializeFromCube(cube, band, progress); + } + + + void Histogram::InitializeFromCube(Cube &cube, const int band, Progress *progress) { + // Make sure band is valid + if ((band < 0) || (band > cube.Bands())) { + string msg = "Invalid band in [Histogram constructor]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + double min,max; + int nbins; + + if (cube.PixelType() == Isis::UnsignedByte) { + min = 0.0 * cube.Multiplier() + cube.Base(); + max = 255.0 * cube.Multiplier() + cube.Base(); + nbins = 256; + } + else if (cube.PixelType() == Isis::SignedWord) { + min = -32768.0 * cube.Multiplier() + cube.Base(); + max = 32767.0 * cube.Multiplier() + cube.Base(); + nbins = 65536; + } + else if (cube.PixelType() == Isis::Real) { + // Determine the band for statistics + int bandStart = band; + int bandStop = band; + int maxSteps = cube.Lines(); + if (band == 0){ + bandStart = 1; + bandStop = cube.Bands(); + maxSteps = cube.Lines() * cube.Bands(); + } + + // Construct a line buffer manager and a statistics object + LineManager line(cube); + Statistics stats = Statistics(); + + // Prep for reporting progress if necessary + if (progress != NULL) { + string save = progress->Text (); + progress->SetText("Computing min/max for histogram"); + progress->SetMaximumSteps(maxSteps); + progress->CheckStatus(); + } + + for (int useBand = bandStart ; useBand <= bandStop ; useBand++){ + // Loop and get the statistics for a good minimum/maximum + for (int i=1; i<=cube.Lines(); i++) { + line.SetLine(i,useBand); + cube.Read(line); + stats.AddData (line.DoubleBuffer(),line.size()); + if (progress != NULL) progress->CheckStatus(); + } + } + + // Get the min/max for constructing a histogram object + if (stats.ValidPixels() == 0) { + min = 0.0; + max = 1.0; + } + else { + min = stats.BestMinimum (); + max = stats.BestMaximum (); + } + + nbins = 65536; + } + else { + std::string msg = "Unsupported pixel type"; + throw iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Set the bins and range + SetBinRange(min,max); + SetBins(nbins); + } + + + //! Destructs a histogram object. + Histogram::~Histogram() { + } + + void Histogram::SetBinRange(double binStart, double binEnd) { + if(binEnd < binStart) { + string msg = "The binning range start [" + iString(binStart) + + " must be less than the end [" + iString(binEnd) + "."; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + p_binRangeStart = binStart; + p_binRangeEnd = binEnd; + } + + + //! Resets histogram counters to zero. + void Histogram::Reset () { + Isis::Statistics::Reset(); + for (int i=0; i<(int)p_bins.size(); i++) { + p_bins[i] = 0; + } + } + + + //! Change the number of bins in the histogram and reset counters + void Histogram::SetBins(const int nbins) { + p_bins.resize(nbins); + Histogram::Reset(); + } + + /** + * Add an array of doubles to the histogram counters. This method can be + * invoked multiple times. For example, once for each line in a cube, before + * obtaining statistics and histogram information. + * + * @param data Pointer to array of double to add. + * @param count Number of doubles to process. + */ + void Histogram::AddData (const double *data, + const unsigned int count) { + Isis::Statistics::AddData (data,count); + + int nbins = p_bins.size(); + int index; + for (unsigned int i=0; i= nbins) index = nbins - 1; + p_bins[index] += 1; + } + } + } + + /** + * Remove an array of doubles from the histogram counters. Note that this + * invalidates the absolute minimum and maximum. They will no longer be + * useable. + * @see Stats + * + * @param data Pointer to array of doubles to remove. + * @param count number of doubles to process. + */ + void Histogram::RemoveData (const double *data, + const unsigned int count) { + Isis::Statistics::RemoveData (data,count); + + int nbins = p_bins.size(); + int index; + for (unsigned int i=0; i= nbins) index = nbins - 1; + p_bins[index] -= 1; + } + } + } + + /** + * Returns the median. + * + * @returns The median + */ + double Histogram::Median () const { + return Percent (50.0); + } + + /** + * Returns the mode. + * + * @returns The mode + */ + double Histogram::Mode () const { + int mode = 0; + for (int i=0; i<(int)p_bins.size(); i++) { + if (p_bins[i] > p_bins[mode]) mode = i; + } + + if (p_bins[mode] < 1) return Isis::NULL8; + + return BinMiddle (mode); + } + + + /** + * Computes and returns the value at X percent of the histogram. For example, + * Percent(50.0) is equivalent to the computing the median. While Percent(0.5) + * and Percent(99.5) would obtain a minimum and maximum for the data that + * could be used for a good contrast stretch. + * + * @param percent X percent of the histogram to compute. + * + * @returns The value at X percent of the histogram. + */ + double Histogram::Percent (double percent) const { + if ((percent < 0.0) || (percent > 100.0)) { + string m = "Argument percent outside of the range 0 to 100 in"; + m += " [Histogram::Percent]"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + if (ValidPixels() < 1) return Isis::NULL8; + + Isis::BigInt currentPixels = 0; + double currentPercent; + + for (int i=0; i<(int)p_bins.size(); i++) { + currentPixels += p_bins[i]; + currentPercent = (double) currentPixels / (double) ValidPixels() * 100.0; + if (currentPercent >= percent) { + return BinMiddle (i); + } + } + + return BinMiddle ((int)p_bins.size() - 1); + } + + + /** + * Computes and returns the skew. If there are no valid pixels then NULL8 is + * returned. Recognize that because of the binning which occurs, in order to + * generate the histogram, the skew may not be precise but will be very close. + * + * @return The skew. + */ + double Histogram::Skew() const { + if (ValidPixels() < 1) return Isis::NULL8; + double sdev = StandardDeviation(); + if (sdev == 0.0) return 0.0; + return 3.0 * (Average() - Median()) / sdev; + } + + + /** + * Returns the count at a bin position in the histogram. + * + * @param index Index of the desired bin 0 to Bins()-1. + * + * @return The count at a bin position in the histogram. + */ + BigInt Histogram::BinCount (const int index) const { + if ((index < 0) || (index >= (int)p_bins.size())) { + string message = Isis::Message::ArraySubscriptNotInRange(index); + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + return p_bins[index]; + } + + + /** + * Returns the left edge and right edge values of a bin. That is the range of + * data the bin covers. + * + * @throws Isis::iException The programmer has passed in an index outside of 0 + * to Bins()-1. + * + * @param index Index of the desired bin 0 to Bins()-1. + * @param low The value at the left edge of the requested bin. + * @param high The value at the right edge of the requested bin. + */ + void Histogram::BinRange (const int index, + double &low, double &high) const { + if ((index < 0) || (index >= (int)p_bins.size())) { + string message = Isis::Message::ArraySubscriptNotInRange(index); + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + double binSize = (BinRangeEnd() - BinRangeStart()) / (double) (p_bins.size() - 1); + low = BinRangeStart() - binSize / 2.0 + binSize * (double) index; + high = low + binSize; + } + + + /** + * Returns the value represented by a bin. This is not the count, but the + * actual data value at the middle of the bin. + * + * @param index Index of the desired bin 0 to Bins()-1. + * + * @returns The middle value of the bin. + */ + double Histogram::BinMiddle (const int index) const { + if ((index < 0) || (index >= (int)p_bins.size())) { + string message = Isis::Message::ArraySubscriptNotInRange(index); + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + double low,high; + BinRange (index,low,high); + return (low + high) / 2.0; + } + + + /** + * Returns the size of an individual bin. Essentially, the difference of the + * high and low edge values (BinRange) of a bin. This value is constant for + * all bins. + * + * @return The size of the individual bin. + */ + double Histogram::BinSize () const { + double low,high; + BinRange (0,low,high); + return high - low; + } + + + /** + * Returns the number of bins in the histogram. + * + * @return The number of bins in the histogram. + */ + int Histogram::Bins () const { + return (int)p_bins.size(); + } + + + /** + * Returns the highest bin count. + * + * @return The highest bin count. + */ + BigInt Histogram::MaxBinCount () const { + + Isis::BigInt maxBinCount = 0; + for (int i=0; i<(int)p_bins.size(); i++) { + if (p_bins[i] > maxBinCount) maxBinCount = p_bins[i]; + } + + return maxBinCount; + } +} diff --git a/isis/src/base/objs/Histogram/Histogram.h b/isis/src/base/objs/Histogram/Histogram.h new file mode 100644 index 0000000000000000000000000000000000000000..dbafc037f6c7d64816fa83d24f2c0259e0b15e73 --- /dev/null +++ b/isis/src/base/objs/Histogram/Histogram.h @@ -0,0 +1,102 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/08/15 22:03:32 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef Histogram_h +#define Histogram_h + +#include "Statistics.h" +#include "iException.h" +#include "Constants.h" +#include "Progress.h" +#include "Cube.h" + +namespace Isis { +/** + * @brief Container of a cube histogram + * + * This class is used to accumulate a histogram on double arrays. In + * particular, it is highly useful for obtaining a histogram on cube data. + * Parameters which can be computed are the 1) median, 2) mode, and 3) skew. + * The histogram consists of a fixed set of distinct bins. When an object is + * created the programmer must provide a minimum and maximum which defines how + * data is further placed in the bins. The minimum is mapped to the left edge + * of the first bin [0] and the maximum is mapped to the right edge of the + * last bin [Bins()-1]. There are a set of methods which return bin information + * such as 1) count, 2) size, 3) middle value, 4) range, and 5) maximum bin + * count. + * + * @ingroup Statistics + * + * @author 2002-05-13 Jeff Anderson + * + * @internal + * @todo This class needs an example. + * @history 2002-05-22 Jeff Anderson moved Reset, AddData, and RemoveData + * methods into public space. + * @history 2002-10-05 Tracie Sucharski added MaxBinCount, a method to return + * the maximum bin count. + * @history 2005-06-21 Modified index computations in AddData and RemoveData + * to round + * @history 2008-08-15 Added BinRange methods and functionality. Now, you can + * collect statistics over all of the data and also set where the + * binning will start and end. Increased the default number of bins + * for floating point cubes. + */ + class Histogram : public Isis::Statistics { + public: + Histogram (const double minimum, const double maximum, + const int bins=1024); + Histogram (Cube &cube, const int band, Progress *progress=NULL); + + ~Histogram (); + + void SetBins (const int bins); + + void Reset (); + void AddData (const double *data, const unsigned int count); + void RemoveData (const double *data, const unsigned int count); + + double Median () const; + double Mode () const; + double Percent (const double percent) const; + double Skew () const; + + BigInt BinCount (const int index) const; + void BinRange (const int index, double &low, double &high) const; + double BinMiddle (const int index) const; + double BinSize () const; + int Bins () const; + BigInt MaxBinCount () const; + + double BinRangeStart() const { return p_binRangeStart; } + double BinRangeEnd() const { return p_binRangeEnd; } + void SetBinRange(double binStart, double binEnd); + + private: + void InitializeFromCube(Cube &cube, const int band, Progress *progress); + //! The array of counts. + std::vector p_bins; + double p_binRangeStart, p_binRangeEnd; + }; +}; + +#endif diff --git a/isis/src/base/objs/Histogram/Histogram.truth b/isis/src/base/objs/Histogram/Histogram.truth new file mode 100644 index 0000000000000000000000000000000000000000..d6b8705d5bbfb8d737891e746ff164a83d2628b9 --- /dev/null +++ b/isis/src/base/objs/Histogram/Histogram.truth @@ -0,0 +1,33 @@ +Median: 2 +Mode: 2 +Skew: 0 +Percent(0.5): 1 +Percent(99.5): 3 +Bins: 21 +BinSize: 1 +BinMiddle: -10 +BinRange(0,low): -10.5 +BinRange(0,high): -9.5 +BinCount(0): 0 +BinRange(20,low): 9.5 +BinRange(20,high): 10.5 +BinCount(20): 0 + +Average: 4 +Median: 5 +Mode: 5 +Skew: -1.73205 +Percent(0.5): 2 +Percent(99.5): 5 +BinCount(0): 0 +BinCount(20): 0 + +**PROGRAMMER ERROR** Invalid Range: Minimum [1.0] must be less than the Maximum [0.0] +**PROGRAMMER ERROR** Argument percent outside of the range 0 to 100 in [Histogram::Percent] +**PROGRAMMER ERROR** Argument percent outside of the range 0 to 100 in [Histogram::Percent] +**PROGRAMMER ERROR** Array subscript [-1] is out of array bounds +**PROGRAMMER ERROR** Array subscript [1024] is out of array bounds +**PROGRAMMER ERROR** Array subscript [-1] is out of array bounds +**PROGRAMMER ERROR** Array subscript [1024] is out of array bounds +**PROGRAMMER ERROR** Array subscript [-1] is out of array bounds +**PROGRAMMER ERROR** Array subscript [1024] is out of array bounds diff --git a/isis/src/base/objs/Histogram/Makefile b/isis/src/base/objs/Histogram/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..37f90aebada775558786556fdff765c380abd918 --- /dev/null +++ b/isis/src/base/objs/Histogram/Makefile @@ -0,0 +1,5 @@ +INCS = Histogram.h +SRCS = Histogram.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Histogram/unitTest.cpp b/isis/src/base/objs/Histogram/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f051d632f4f05683886d8e22c07c7b62a78e039e --- /dev/null +++ b/isis/src/base/objs/Histogram/unitTest.cpp @@ -0,0 +1,131 @@ +#include +#include "Histogram.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + Isis::Histogram h(-10.0,10.0,21); + double low,high; + try { + + double a[9]; + a[0] = 1.0; + a[1] = 2.0; + a[2] = 3.0; + a[3] = Isis::NULL8; + a[4] = Isis::HIGH_REPR_SAT8; + a[5] = Isis::LOW_REPR_SAT8; + a[6] = Isis::HIGH_INSTR_SAT8; + a[7] = Isis::LOW_INSTR_SAT8; + a[8] = 2.0; + + h.AddData(a,9); + + cout << "Median: " << h.Median() << endl; + cout << "Mode: " << h.Mode() << endl; + cout << "Skew: " << h.Skew() << endl; + cout << "Percent(0.5): " << h.Percent(0.5) << endl; + cout << "Percent(99.5): " << h.Percent(99.5) << endl; + cout << "Bins: " << h.Bins() << endl; + cout << "BinSize: " << h.BinSize() << endl; + cout << "BinMiddle: " << h.BinMiddle(0) << endl; + + h.BinRange(0,low,high); + cout << "BinRange(0,low): " << low << endl; + cout << "BinRange(0,high): " << high << endl; + cout << "BinCount(0): " << h.BinCount(0) << endl; + h.BinRange(20,low,high); + cout << "BinRange(20,low): " << low << endl; + cout << "BinRange(20,high): " << high << endl; + cout << "BinCount(20): " << h.BinCount(20) << endl; + cout << endl; + + h.RemoveData (a,3); + double b[4]; + b[0] = -11.0; + b[1] = 11.0; + b[2] = 5.0; + b[3] = 5.0; + h.AddData (b,4); + + cout << "Average: " << h.Average() << endl; + cout << "Median: " << h.Median() << endl; + cout << "Mode: " << h.Mode() << endl; + cout << "Skew: " << h.Skew() << endl; + cout << "Percent(0.5): " << h.Percent(0.5) << endl; + cout << "Percent(99.5): " << h.Percent(99.5) << endl; + cout << "BinCount(0): " << h.BinCount(0) << endl; + cout << "BinCount(20): " << h.BinCount(20) << endl; + cout << endl; + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + Isis::Histogram g(1.0,0.0); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + h.Percent (-1.0); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + h.Percent (101.0); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + h.BinCount (-1); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + h.BinCount (1024); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + h.BinMiddle (-1); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + h.BinMiddle (1024); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + h.BinRange (-1,low,high); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + h.BinRange (1024,low,high); + } + catch (Isis::iException &e) { + e.Report (false); + } +} diff --git a/isis/src/base/objs/History/History.cpp b/isis/src/base/objs/History/History.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01c23f830fd39c35f6271084b213ed6232155746 --- /dev/null +++ b/isis/src/base/objs/History/History.cpp @@ -0,0 +1,89 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/05/14 19:17:59 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include "History.h" +#include "Application.h" +#include "PvlObject.h" + +using namespace std; +namespace Isis { + // Constructor for creating a history blob + History::History(const std::string &name) : Isis::Blob(name, "History") { + p_history.SetTerminator(""); + } + + // Constructor for reading a history blob + History::History(const std::string &name, const std::string &file) : + Isis::Blob(name, "History") { + Blob::Read(file); + } + + // Destructor + History::~History() { + } + + void History::AddEntry() { + PvlObject hist = Isis::iApp->History(); + AddEntry(hist); + } + + void History::AddEntry(Isis::PvlObject &obj) { + p_history.AddObject(obj); + } + + void History::WriteInit() { + ostringstream ostr; + if(p_nbytes > 0) ostr << std::endl; + ostr << p_history; + string histStr = ostr.str(); + int bytes = histStr.size(); + + char *temp = p_buffer; + p_buffer = new char[p_nbytes+bytes]; + if(temp != NULL) memcpy(p_buffer, temp, p_nbytes); + const char *ptr = histStr.c_str(); + memcpy(&p_buffer[p_nbytes], (void *)ptr, bytes); + p_nbytes += bytes; + + if(temp != NULL) delete [] temp; + } + + Pvl History::ReturnHist() { + Pvl pvl; + stringstream os; + for(int i = 0; i < p_nbytes; i++) os << p_buffer[i]; + os >> pvl; + return pvl; + } + + void History::Read(Isis::Pvl &pvl, std::istream &is) { + try { + Blob::Read(pvl, is); + } + catch(iException &e) { + e.Clear(); + } + } +} diff --git a/isis/src/base/objs/History/History.h b/isis/src/base/objs/History/History.h new file mode 100644 index 0000000000000000000000000000000000000000..e95d3931821ea9c97a2d6e6e446da490ce3d9f5b --- /dev/null +++ b/isis/src/base/objs/History/History.h @@ -0,0 +1,59 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/05/14 19:17:59 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#if !defined(History_h) +#define History_h + +#include "Blob.h" + +namespace Isis { + /** + * + * @history 2006-12-11 Kris Becker Fixed bug in WriteInit method using a + * temporary string to reference a char pointer + * to its contents. The string remain after the + * reference or its toast. + * + * @internal + * @todo This class needs documentation. + */ + class History : public Isis::Blob { + public: + History(const std::string &name); + History(const std::string &name, const std::string &file); + ~History(); + + void AddEntry(); + void AddEntry(Isis::PvlObject &obj); + Pvl ReturnHist(); + void Read(Isis::Pvl &pvl, std::istream &is); + + protected: + void WriteInit(); + + private: + Pvl p_history; + }; +}; + +#endif + diff --git a/isis/src/base/objs/History/History.truth b/isis/src/base/objs/History/History.truth new file mode 100644 index 0000000000000000000000000000000000000000..ab26d982cdc671f1f7ace607bb92da5d7d13dc65 --- /dev/null +++ b/isis/src/base/objs/History/History.truth @@ -0,0 +1,18 @@ +Object = Root + Object = hist + IsisVersion = "3.0.16 beta | 2006-03-22" + ProgramVersion = 2005-03-28 + ExecutionDateTime = 2006-03-29T14:39:39 + HostName = orkin + UserName = janderso + Description = "Unit test for History class" + + Group = UserParameters + FROM = unitTest.cub + TO = /tmp/isisprocess_01.cub + TO2 = /tmp/isisprocess_02.cub + TO3 = /tmp/isisprocess_03.cub + TO4 = /tmp/isisprocess_04.cub + End_Group + End_Object +End_Object diff --git a/isis/src/base/objs/History/Makefile b/isis/src/base/objs/History/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4cc1251d85cb153512a9942a0513b4ebfc6fefd9 --- /dev/null +++ b/isis/src/base/objs/History/Makefile @@ -0,0 +1,5 @@ +INCS = History.h +SRCS = History.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/History/unitTest.cpp b/isis/src/base/objs/History/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a75563b5841f3593a4c3384ad7d68c39e8565c5 --- /dev/null +++ b/isis/src/base/objs/History/unitTest.cpp @@ -0,0 +1,24 @@ +#include "Isis.h" + +#include +#include + +#include "Pvl.h" +#include "History.h" +#include "Preference.h" + +using namespace std; +void IsisMain() { + Isis::Preference::Preferences(true); + + Isis::History h("Haha");; + h.AddEntry(); + std::string file = "unitTest.tttt"; + h.Write(file); + + Isis::History h2("Haha", file); + Isis::PvlObject o = h2.ReturnHist(); + std::cout << o << std::endl; + + remove(file.c_str()); +} diff --git a/isis/src/base/objs/History/unitTest.exclude b/isis/src/base/objs/History/unitTest.exclude new file mode 100644 index 0000000000000000000000000000000000000000..c0b4c410bab8651d358e8a3d22e9501aea986460 --- /dev/null +++ b/isis/src/base/objs/History/unitTest.exclude @@ -0,0 +1,6 @@ +ProgramPath +DateTime +User +HostName +IsisVersion + diff --git a/isis/src/base/objs/History/unitTest.xml b/isis/src/base/objs/History/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..f7e604eca381ac95f36f32946d347ce02445f49d --- /dev/null +++ b/isis/src/base/objs/History/unitTest.xml @@ -0,0 +1,95 @@ + + + + Unit test for History class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + unitTest.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisprocess_01.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisprocess_02.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisprocess_03.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisprocess_04.cub + + + + diff --git a/isis/src/base/objs/ID/ID.cpp b/isis/src/base/objs/ID/ID.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b8dcfaa675e2eea4b6248c33089bb7cdb5c8b5b --- /dev/null +++ b/isis/src/base/objs/ID/ID.cpp @@ -0,0 +1,84 @@ +/** + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "ID.h" +#include "iException.h" +#include "Message.h" +#include "iString.h" +#include +using namespace std; +namespace Isis{ + + /** + * Creates an ID object + * @param name The string to be a base for the serial IDs + * @param basenum The number to start the count at. Defaults to + * one. + */ + ID::ID (const std::string &name, int basenum){ + p_current = basenum; + p_namebase = name; + if (p_namebase.find("?",0) == std::string::npos) { + std::string msg = "No replacement set in string [" + p_namebase + "]"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + p_numStart = ((int) p_namebase.find("?",0)); + int endPos = (int)p_namebase.find_last_of("?",p_namebase.size()); + p_numLength = (endPos - p_numStart)+1; + std::string sub = p_namebase.substr(p_numStart, p_numLength); + for (int i=0; i<(int)sub.length(); i++) { + if (sub[i] != '?') { + std::string msg = "iString [" + p_namebase + "] contains more than one replacement set"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + p_namebase.erase(p_numStart, p_numLength); + } + + /** + * Deconstructor + */ + ID::~ID(){ + } + + /** + * Returns the next ID in the sequence. + * + * @return std::string The next ID in the sequence + */ + std::string ID::Next(){ + iString num(p_current); + if ((int)num.size() > p_numLength) { + std::string replacement = "?"; + while ((int)replacement.size() + +namespace Isis{ + /** + * @brief Creates sequential IDs + * + * This class generates IDs in numerical sequence, from an input + * string. The input must contain one, and only one, series of + * question marks, which will be replaced with numbers in the + * generation of IDs. The default start value is 1, but this can + * be changed. + * + * @ingroup Utility + * + * @author 2006-07-05 Brendan George + * + * @internal + */ + class ID{ + public: + ID(const std::string &name, int basenum=1); + + ~ID(); + + std::string Next(); + + private: + std::string p_namebase; + int p_current; + int p_numLength; + int p_numStart; + }; +} + +#endif diff --git a/isis/src/base/objs/ID/ID.truth b/isis/src/base/objs/ID/ID.truth new file mode 100644 index 0000000000000000000000000000000000000000..eeea0b8c8d994ed24450071a6ccd4faa80533a78 --- /dev/null +++ b/isis/src/base/objs/ID/ID.truth @@ -0,0 +1,25 @@ +Test One: core test and limit test +ABCD01EFG +ABCD11EFG +ABCD21EFG +ABCD31EFG +ABCD41EFG +ABCD51EFG +ABCD61EFG +ABCD71EFG +ABCD81EFG +ABCD91EFG +**USER ERROR** Maximum number reached for string [ABCD??EFG] + +Test 2: No '?' test +**USER ERROR** No replacement set in string [Serial] + +Test 3: Broken replacement string +**USER ERROR** iString [Serial??Number??] contains more than one replacement set + +Test 4: differing start numbers +Test00 +Test01 +Test02 +Test03 +Test04 diff --git a/isis/src/base/objs/ID/Makefile b/isis/src/base/objs/ID/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1305daf9776e4fb4554ec2a531bd9047f24931dd --- /dev/null +++ b/isis/src/base/objs/ID/Makefile @@ -0,0 +1,6 @@ +INCS = ID.h +SRCS = ID.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/base/objs/ID/unitTest.cpp b/isis/src/base/objs/ID/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e2fdd9056dd5c55f99fc08cedc7b6bcac5c997f --- /dev/null +++ b/isis/src/base/objs/ID/unitTest.cpp @@ -0,0 +1,55 @@ +#include +#include "iException.h" +#include "ID.h" +#include "Preference.h" + +int main() { + Isis::Preference::Preferences(true); + std::cout << "Test One: core test and limit test" << std::endl; + try{ + Isis::ID pid("ABCD??EFG"); + for (int i=0; i<100; i++) { + std::string test = pid.Next(); + if (i%10 == 0) { + std::cout << test << std::endl; + } + } + } + catch (Isis::iException &e) { + e.Report(false); + } + + std::cout << std::endl << "Test 2: No '?' test" << std::endl; + try{ + Isis::ID pid2("Serial"); + for (int i=0; i<5; i++ ) { + std::cout << pid2.Next() << std::endl; + } + } + catch (Isis::iException &e){ + e.Report(false); + } + + std::cout << std::endl << "Test 3: Broken replacement string" << std::endl; + try{ + Isis::ID pid3("Serial??Number??"); + for (int i=0; i<5; i++ ) { + std::cout << pid3.Next() << std::endl; + } + } + catch (Isis::iException &e){ + e.Report(false); + } + + std::cout << std::endl << "Test 4: differing start numbers" << std::endl; + try{ + Isis::ID pid4("Test??",0); + for (int i=0; i<5; i++) { + std::cout << pid4.Next() << std::endl; + } + } + catch (Isis::iException &e){ + e.Report(false); + } + return 0; +} diff --git a/isis/src/base/objs/IdealCamera/Camera.plugin b/isis/src/base/objs/IdealCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..7944a0a3108ec33798aea662ba9ecc9393c6a447 --- /dev/null +++ b/isis/src/base/objs/IdealCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = IdealSpacecraft/IdealCamera + Version = 1 + Library = IdealCamera + Routine = IdealCameraPlugin +EndGroup + diff --git a/isis/src/base/objs/IdealCamera/IdealCamera.cpp b/isis/src/base/objs/IdealCamera/IdealCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79d21df9038262543bf10d98e5314a434dfa9c97 --- /dev/null +++ b/isis/src/base/objs/IdealCamera/IdealCamera.cpp @@ -0,0 +1,176 @@ +/** + * @file + * $Revision: 1.10 $ + * $Date: 2009/08/31 15:12:28 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "IdealCamera.h" +#include "LineScanCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraDistortionMap.h" +#include "LineScanCameraGroundMap.h" +#include "LineScanCameraSkyMap.h" +#include + + +namespace Isis { + /** + * Creates a generic camera model. That is a camera without + * optical distortion. The following information from the label + * must be available + * \code + * + * Group = Instrument + * SpacecraftName = IdealSpacecraft + * InstrumentId = IdealCamera + * TargetName = Mars | Moon | etc + * StartTime = YYYY-MM-DDTHH:MM:SS.SSS + * StopTime = YYYY-MM-DDTHH:MM:SS.SSS + * + * EphermisTime = nnnnnnnnnn.sss + * ExposureDuration = nnn.nn + * + * InstrumentType = Framing | Linescan + * FocalLength = nnn.n + * PixelPitch = nn.n + * SampleDetectors = nnnn + * LineDetectors = nnnn + * End_Group + * + * \endcode + * Note boresight is assumed to be at the center of the + * detectors + * + * @param lab Pvl label from the image + * @internal + * @history 2007-02-12 Debbie A. Cook - Added sign for all the trans parameters + */ + IdealCamera::IdealCamera (Isis::Pvl &lab) : Isis::Camera(lab) { + // Get required keywords from instrument group + Isis::PvlGroup &inst = lab.FindGroup ("Instrument",Isis::Pvl::Traverse); + double focalLength = inst["FocalLength"]; + double pixelPitch = inst["PixelPitch"]; + double et = inst["EphemerisTime"]; + double exposureDuration=0.; + if (inst.HasKeyword("ExposureDuration")) exposureDuration = (double) inst["ExposureDuration"] / 1000.0; + double sampleDetectors = inst["SampleDetectors"]; + double lineDetectors = inst["LineDetectors"]; + + int yDependency; + int xDependency = inst["FocalPlaneXDependency"]; + double xdir,ydir,sdir,ldir; // Pixel direction + + xdir = 1.; + if (inst.HasKeyword("TransX")) xdir = inst["TransX"]; + ydir = 1.; + if (inst.HasKeyword("TransY")) ydir = inst["TransY"]; + + if (xDependency == Isis::CameraFocalPlaneMap::Sample) { + yDependency = Isis::CameraFocalPlaneMap::Line; + sdir = xdir; + ldir = ydir; + } + else { + yDependency = Isis::CameraFocalPlaneMap::Sample; + sdir = ydir; + ldir = xdir; + } + double keyval[3]; + + // Put the translation coefficients into the Naif kernel pool so the + // CameraFocalPlaneClass can find them + keyval[0] = 0.; + if (inst.HasKeyword("TransX0")) keyval[0] = inst["TransX0"]; + keyval[xDependency] = pixelPitch*xdir; + keyval[yDependency] = 0.; + pdpool_c("IDEAL_TRANSX", 3, keyval); + + keyval[0] = 0.; + if (inst.HasKeyword("TransY0")) keyval[0] = inst["TransY0"]; + keyval[yDependency] = pixelPitch*ydir; + keyval[xDependency] = 0.; + pdpool_c("IDEAL_TRANSY", 3, keyval); + + keyval[0] = 0.; + if (inst.HasKeyword("TransS0")) keyval[0] = inst["TransS0"]; + keyval[xDependency] = 1/pixelPitch*sdir; + keyval[yDependency] = 0.; + pdpool_c("IDEAL_TRANSS", 3, keyval); + + keyval[0] = 0.; + if (inst.HasKeyword("TransL0")) keyval[0] = inst["TransL0"]; + keyval[yDependency] = 1/pixelPitch*ldir; + keyval[xDependency] = 0.; + pdpool_c("IDEAL_TRANSL", 3, keyval); + + // Setup camera characteristics from instrument + SetFocalLength(focalLength); + SetPixelPitch(pixelPitch); + + // Create correct camera type + Isis::iString type = (std::string) inst["InstrumentType"]; + if (type.UpCase() == "FRAMING") { + p_framing = true; + new CameraDetectorMap(this); + CameraFocalPlaneMap *fmap = new CameraFocalPlaneMap(this,0); + fmap->SetDetectorOrigin(sampleDetectors/2.0+0.5, + lineDetectors/2.0+0.5); + new CameraDistortionMap(this); + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(et); + LoadCache(); + } + else if (type.UpCase() == "LINESCAN") { + p_framing = false; + new LineScanCameraDetectorMap(this,et,exposureDuration); + CameraFocalPlaneMap *fmap = new CameraFocalPlaneMap(this,0); + fmap->SetDetectorOrigin(sampleDetectors/2.0+0.5, + 0.0); + new CameraDistortionMap(this); + new LineScanCameraGroundMap(this); + new LineScanCameraSkyMap(this); + + LoadCache(); + } + else { + std::string msg = "Unknown InstrumentType [" + + (std::string) inst["InstrumentType"] + "]"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + + //! Destroys the IdealCamera object + IdealCamera::~IdealCamera () {} +} + +/** + * @brief External C function for createing the camera plugin + * + * This function is used by the CameraFactory to create an instance of the + * IdealCamera object. + * + * @param lab The Isis::Pvl label object used for the information as how to + * create this object. + */ +extern "C" Isis::Camera *IdealCameraPlugin (Isis::Pvl &lab) { + return new Isis::IdealCamera(lab); +} diff --git a/isis/src/base/objs/IdealCamera/IdealCamera.h b/isis/src/base/objs/IdealCamera/IdealCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..18dfcc32f620a2d58badd4f0bfd2ee9acc5a9bea --- /dev/null +++ b/isis/src/base/objs/IdealCamera/IdealCamera.h @@ -0,0 +1,71 @@ +#ifndef IdealCamera_h +#define IdealCamera_h + +/** + * @file + * $Revision: 1.5 $ + * $Date: 2009/08/31 15:12:28 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Camera.h" + +namespace Isis { + /** + * @brief Ideal Camera Model + * + * This class is the implementation of a generic camera model + * with no optical distortion. + * + * @ingroup SpiceInstrumentsAndCameras + * + * @author 2006-10-17 Jeff Anderson and Debbie Cook + * + * @internal + * @history 2007-10-18 Debbie A. Cook Corrected coding error with TransS0 and TransL0 and + * @history 2008-06-18 Stuart Sides - Fixed doc error + * @history 2008-08-08 Steven Lambright Made the unit test work with a Sensor + * change. Also, now using the new LoadCache(...) method instead of + * CreateCache(...). + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class IdealCamera : public Isis::Camera { + public: + // Constructs a HiriseCamera object + IdealCamera (Isis::Pvl &lab); + + // Destroys the HiriseCamera object + ~IdealCamera (); + + /** + * Returns the type of camera that was created. + * + * @return CameraType + */ + virtual CameraType GetCameraType() const { + if(p_framing) return Framing; + return LineScan; + } + + private: + bool p_framing; //!< true if framing camera + }; +}; + +#endif diff --git a/isis/src/base/objs/IdealCamera/IdealCamera.truth b/isis/src/base/objs/IdealCamera/IdealCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..7d49a67e44593ecb6f008e57b1cefb0b43551b27 --- /dev/null +++ b/isis/src/base/objs/IdealCamera/IdealCamera.truth @@ -0,0 +1,43 @@ +Unit Test for IdealCamera... +Testing image $base/testData/ab102401_ideal.cub ... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK + +Testing image $base/testData/f319b18_ideal.cub ... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK + diff --git a/isis/src/base/objs/IdealCamera/Makefile b/isis/src/base/objs/IdealCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ed5dd8f20aa5fefe9db53250127a6201e24539c6 --- /dev/null +++ b/isis/src/base/objs/IdealCamera/Makefile @@ -0,0 +1,5 @@ +INCS = IdealCamera.h +SRCS = IdealCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/IdealCamera/unitTest.cpp b/isis/src/base/objs/IdealCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db96febecafb66649747264ef2eb73f085ded68a --- /dev/null +++ b/isis/src/base/objs/IdealCamera/unitTest.cpp @@ -0,0 +1,99 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for IdealCamera..." << endl; + /* + * IdealCamera unit test tests two images instead of the typical one. Increased tolerances + * for line/samp->lat/lon->line/samp + */ + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownLat[2] = {22.79610742949229,-82.44021272004072}; + double knownLon[2] = {225.0055153560127,75.88746680693571}; + char files[2][1024] = { "$base/testData/ab102401_ideal.cub", "$base/testData/f319b18_ideal.cub" }; + + for(unsigned int i = 0; i < sizeof(knownLat)/sizeof(double); i++) { + Isis::Pvl p(files[i]); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + cout << "Testing image " << files[i] << " ..." << endl; + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat[i]) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat[i] << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon[i]) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon[i] << endl; + } + + cout << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.013) deltaSamp = 0; + if (fabs(deltaLine) < 0.0016) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} diff --git a/isis/src/base/objs/ImageOverlap/ImageOverlap.cpp b/isis/src/base/objs/ImageOverlap/ImageOverlap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..24def0e1a022a8bed2fa05bc2f86e4f96b3dada9 --- /dev/null +++ b/isis/src/base/objs/ImageOverlap/ImageOverlap.cpp @@ -0,0 +1,206 @@ +#include +#include + +#include "geos/io/WKBReader.h" +#include "geos/io/WKBWriter.h" + +#include "PolygonTools.h" +#include "iException.h" +#include "Filename.h" +#include "ImageOverlap.h" +#include "iString.h" + +namespace Isis { + + /** + * Construct an empty ImageOverlap object + * + */ + ImageOverlap::ImageOverlap() { + Init(); + } + + + /** + * Construct an ImageOverlap object and initialize it with the arguments + * + * @param serialNumber The initial serial number assiciated with the polygon. + * + * @param polygon The polygon that defines the overlap area. + * + */ + ImageOverlap::ImageOverlap(std::string serialNumber, + geos::geom::MultiPolygon &polygon) { + Init(); + SetPolygon(polygon); + Add(serialNumber); + } + + /** + * Construct an ImageOverlap object and initialize it from the istream + * + * @param inputStream A stream containing a representation of the image overlap + * + */ + ImageOverlap::ImageOverlap(std::istream &inputStream) { + geos::io::WKBReader geosReader; + + std::string fileData; + getline(inputStream, fileData); + + iString serialNums = fileData; + iString serialNum; + while((serialNum = serialNums.Token(",")) != "") { + Add(serialNum); + } + + // now get the multipolygon on the next line + getline(inputStream, fileData); + + std::stringstream multiPolygon; + multiPolygon << fileData; + multiPolygon.seekg(0, std::ios::beg); + + p_polygon = (geos::geom::MultiPolygon *)geosReader.readHEX(multiPolygon); + } + + + /** + * Destroy this ImageOverlap object + * + */ + ImageOverlap::~ImageOverlap() { + delete p_polygon; + }; + + + /** + * Initialize this object to a known state. + * + */ + void ImageOverlap::Init() { + p_serialNumbers.clear(); + p_polygon = NULL; + } + + + /** + * This method will replace the existing polygon that defines the overlap with + * a new one. + * + * @param polygon The new polygon. + * + */ + void ImageOverlap::SetPolygon(const geos::geom::MultiPolygon &polygon) { + if(p_polygon != NULL) { + delete p_polygon; + p_polygon = NULL; + } + + p_polygon = PolygonTools::CopyMultiPolygon(polygon); + } + + + /** + * This method will replace the existing polygon that defines the overlap with + * a new one. + * + * @param polygon The new polygon. + * + */ + void ImageOverlap::SetPolygon(const geos::geom::MultiPolygon *polygon) { + if(p_polygon != NULL) { + delete p_polygon; + p_polygon = NULL; + } + + p_polygon = PolygonTools::CopyMultiPolygon(polygon); + } + + + void ImageOverlap::Write(std::ostream &outputStream) { + geos::io::WKBWriter geosWriter; + + iString serialNums; + + for(unsigned int sn = 0; sn < p_serialNumbers.size(); sn++) { + if(sn != 0) { + serialNums += ","; + } + + serialNums += p_serialNumbers[sn]; + } + + serialNums += "\n"; + + outputStream << serialNums; + + geosWriter.writeHEX(*p_polygon, outputStream); + } + /** + * This method will add a new serial number to the list of serial numbers + * alread associated with the overlap. + * + * @param sn The serial number to be added to the list. + * + */ + void ImageOverlap::Add(std::string &sn) { + for(unsigned int s = 0; s < p_serialNumbers.size(); ++s) { + if(sn == p_serialNumbers[s]) { + std::string msg = "Duplicate SN added to [" + p_polygon->toString() + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + p_serialNumbers.push_back(sn); + return; + } + + + /** + * This method will return the area of the polygon. This member does not + * assume any particular units of measure for the verticies of the polygon. + * It is provided as a convience. + * + */ + double ImageOverlap::Area() { + return p_polygon->getArea(); + } + + /** + * This method will return true if any serial number from this ImageOverlap is + * also in the other ImageOverlap + */ + bool ImageOverlap::HasAnySameSerialNumber(ImageOverlap &other) const { + for(int thisSn = 0; thisSn < this->Size(); ++thisSn) { + for(int otherSn = 0; otherSn < other.Size(); ++otherSn) { + if(p_serialNumbers[thisSn] == other.p_serialNumbers[otherSn]) { + return true; + } + } + } + return false; + } + + + + /** + * This method will return true if input serial number exists in the + * ImageOverlap. + * + * @param[in] sn (std::string &) Serial Number to search for + * + * @return bool Returns true if the serial number exists in the + * ImageOverlap. + */ + bool ImageOverlap::HasSerialNumber(std::string &sn) const { + for(int thisSn = 0; thisSn < Size(); ++thisSn) { + if(p_serialNumbers[thisSn] == sn) { + return true; + } + } + return false; + } + + +} diff --git a/isis/src/base/objs/ImageOverlap/ImageOverlap.h b/isis/src/base/objs/ImageOverlap/ImageOverlap.h new file mode 100644 index 0000000000000000000000000000000000000000..0acbaf50004f5d8a2647ce53f76939714754713c --- /dev/null +++ b/isis/src/base/objs/ImageOverlap/ImageOverlap.h @@ -0,0 +1,105 @@ +#ifndef ImageOverlap_h +#define ImageOverlap_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/05/25 22:49:35 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc/documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "geos/geom/MultiPolygon.h" + +namespace Isis { + + /** + * @brief Individual overlap container + * + * Hold information about a single area of overlap. This includes the + * serial numbers of each cube that overlap this area and the polygon + * that defines this area. + * + * @ingroup ControlNetworks + * + * @author 2005-08-03 Stuart Sides + * + * @internal + * @history 2005-08-03 Stuart Sides Original version + * @history 2007-11-02 Tracie Sucharski, Added HasSN method + * @history 2008-08-18 Steven Lambright - Updated to work with geos3.0.0 + * instead of geos2. Mostly namespace changes. + * @history 2008-11-03 Steven Lambright - Added the Read and Write methods + * @history 2010-05-25 Steven Lambright - Made HasAnySameSerialNumber and + * HasSerialNumber const + * + */ + + class ImageOverlap { + public: + ImageOverlap(); + ImageOverlap(std::string serialNumber, geos::geom::MultiPolygon &polygon); + ImageOverlap(std::istream &inputStream); + + virtual ~ImageOverlap(); + + // Set a new polygon + virtual void SetPolygon(const geos::geom::MultiPolygon &polygon); + virtual void SetPolygon(const geos::geom::MultiPolygon *polygon); + + // Add a serial number + void Add(std::string &sn); + + // Return the number of serial numbers in this overlap area + int Size() const { + return p_serialNumbers.size(); + }; + + // Return the ith serial number + std::string operator[](int index) const { + return p_serialNumbers[index]; + }; + + // Return the polygon + const geos::geom::MultiPolygon *Polygon() const { + return p_polygon; + }; + + // Return the area of the polygon + virtual double Area(); + + // Compare the serial numbers with another ImageOverlap + bool HasAnySameSerialNumber(ImageOverlap &other) const; + + // Does serial number exist in this ImageOverlap + bool HasSerialNumber(std::string &sn) const; + + void Write(std::ostream &outputStream); + private: + + std::vector p_serialNumbers; + geos::geom::MultiPolygon *p_polygon; + + void Init(); + + }; +}; + +#endif diff --git a/isis/src/base/objs/ImageOverlap/ImageOverlap.truth b/isis/src/base/objs/ImageOverlap/ImageOverlap.truth new file mode 100644 index 0000000000000000000000000000000000000000..66d7aafd3b99da6103ec4d891c4425dbdea4ff46 --- /dev/null +++ b/isis/src/base/objs/ImageOverlap/ImageOverlap.truth @@ -0,0 +1,55 @@ +One ---------------------------------------------- +Original coordinates: +(0 0, 0 10, 5 15, 8 -5, 0 0) +Well Known Text version of the multi polygon +MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 10.0000000000000000, 5.0000000000000000 15.0000000000000000, 8.0000000000000000 -5.0000000000000000, 0.0000000000000000 0.0000000000000000))) + +Area of the polygon 97.5 +Number of serial numbers: 1 +Serial numbers: + idOne + +Two ---------------------------------------------- +Well Known Text version of the multi polygon +MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 10.0000000000000000, 5.0000000000000000 15.0000000000000000, 8.0000000000000000 -5.0000000000000000, 0.0000000000000000 0.0000000000000000))) + +Area of the polygon 97.5 +Number of serial numbers: 4 +Serial numbers: + idOne + sn2 + sn3 + sn4 + +Three -------------------------------------------- +Well Known Text version of the multi polygon +MULTIPOLYGON (((0.1234567890000000 0.1234567890000000, 0.1234567890000000 10.1234567890000005, 5.1234567889999996 15.1234567890000005, 8.1234567890000005 -5.1234567889999996, 0.1234567890000000 0.1234567890000000))) + +Area of the polygon 98.1173 +Number of serial numbers: 4 +Serial numbers: + idOne + sn2 + sn3 + sn4 + +Well Known Text version of the multi polygon +MULTIPOLYGON (((10.1234567890000005 10.1234567890000005, 10.1234567890000005 110.1234567890000022, 15.1234567890000005 115.1234567890000022, 18.1234567889999987 -15.1234567890000005, 10.1234567890000005 10.1234567890000005))) + +Area of the polygon 733.117 +Number of serial numbers: 4 +Serial numbers: + idOne + sn2 + sn3 + sn4 + +Four --------------------------------------------- +Well Known Text version of the multi polygon +MULTIPOLYGON (((0.1234567890000000 0.1234567890000000, 0.1234567890000000 10.1234567890000005, 5.1234567889999996 15.1234567890000005, 8.1234567890000005 -5.1234567889999996, 0.1234567890000000 0.1234567890000000))) + +Area of the polygon 98.1173 +Number of serial numbers: 1 +Serial numbers: + idFour + diff --git a/isis/src/base/objs/ImageOverlap/Makefile b/isis/src/base/objs/ImageOverlap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f0062107bd1395808c24c033355fb86e98f0a9c8 --- /dev/null +++ b/isis/src/base/objs/ImageOverlap/Makefile @@ -0,0 +1,5 @@ +INCS = ImageOverlap.h +SRCS = ImageOverlap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ImageOverlap/unitTest.cpp b/isis/src/base/objs/ImageOverlap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd495d4d0de2c71fc020dccab39468897790d99a --- /dev/null +++ b/isis/src/base/objs/ImageOverlap/unitTest.cpp @@ -0,0 +1,154 @@ +#include + +#include "Preference.h" +#include "ImageOverlap.h" +#include "PolygonTools.h" +#include "geos/geom/CoordinateSequence.h" +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/geom/Polygon.h" +#include "geos/geom/MultiPolygon.h" +#include "geos/util/GEOSException.h" + + +using namespace std; + +int main() { + Isis::Preference::Preferences(true); + void PrintImageOverlap(Isis::ImageOverlap & poi); + + { + cout << "One ----------------------------------------------" << endl; + + // Create coordinate sequence so we can later create a multi polygon + geos::geom::CoordinateSequence *pts = new geos::geom::CoordinateArraySequence(); + pts->add(geos::geom::Coordinate(0, 0)); + pts->add(geos::geom::Coordinate(0, 10)); + pts->add(geos::geom::Coordinate(5, 15)); + pts->add(geos::geom::Coordinate(8, -5)); + pts->add(geos::geom::Coordinate(0, 0)); + + // Write the original coordinates to the screen + cout << "Original coordinates:" << endl; + cout << pts->toString() << endl; + + // Create a multi polygon + vector polys; + polys.push_back(Isis::globalFactory.createPolygon( + Isis::globalFactory.createLinearRing(pts), NULL)); + geos::geom::MultiPolygon *mPolygon = Isis::globalFactory.createMultiPolygon(polys); + + // Add more coordinates so we can make sure we did a deep copy when we + // created the multipolygon + pts->add(geos::geom::Coordinate(-1, -1)); + pts->add(geos::geom::Coordinate(-2, -2)); + + Isis::ImageOverlap a("idOne", *mPolygon); + + PrintImageOverlap(a); + + // Add some serial numbers and print it again + cout << "Two ----------------------------------------------" << endl; + std::string st = "sn2"; + a.Add(st); + st = "sn3"; + a.Add(st); + st = "sn4"; + a.Add(st); + + PrintImageOverlap(a); + + // Create a new multipolygon and test the SetPolygon method + cout << "Three --------------------------------------------" << endl; + geos::geom::CoordinateSequence *pts3 = new geos::geom::CoordinateArraySequence(); + pts3->add(geos::geom::Coordinate(0.123456789, 0.123456789)); + pts3->add(geos::geom::Coordinate(0.123456789, 10.123456789)); + pts3->add(geos::geom::Coordinate(5.123456789, 15.123456789)); + pts3->add(geos::geom::Coordinate(8.123456789, -5.123456789)); + pts3->add(geos::geom::Coordinate(0.123456789, 0.123456789)); + + try { + vector polys3; + polys3.push_back(Isis::globalFactory.createPolygon( + Isis::globalFactory.createLinearRing(pts3), NULL)); + geos::geom::MultiPolygon *mPolygon3 = Isis::globalFactory.createMultiPolygon(polys3); + a.SetPolygon(*mPolygon3); + delete mPolygon3; + } + catch(geos::util::GEOSException *exc) { + cout << "GEOS Exception: " << exc->what() << endl; + delete exc; + } + + PrintImageOverlap(a); + + + geos::geom::CoordinateSequence *pts4 = new geos::geom::DefaultCoordinateSequence(); + pts4->add(geos::geom::Coordinate(10.123456789, 10.123456789)); + pts4->add(geos::geom::Coordinate(10.123456789, 110.123456789)); + pts4->add(geos::geom::Coordinate(15.123456789, 115.123456789)); + pts4->add(geos::geom::Coordinate(18.123456789, -15.123456789)); + pts4->add(geos::geom::Coordinate(10.123456789, 10.123456789)); + + try { + vector polys4; + polys4.push_back(Isis::globalFactory.createPolygon( + Isis::globalFactory.createLinearRing(pts4), NULL)); + geos::geom::MultiPolygon *mPolygon4 = Isis::globalFactory.createMultiPolygon(polys4); + a.SetPolygon(mPolygon4); + delete mPolygon4; + } + catch(geos::util::GEOSException *exc) { + cout << "GEOS Exception: " << exc->what() << endl; + delete exc; + } + + PrintImageOverlap(a); + + + } + + { + // + cout << "Four ---------------------------------------------" << endl; + geos::geom::CoordinateSequence *pts = new geos::geom::CoordinateArraySequence(); + pts->add(geos::geom::Coordinate(0.123456789, 0.123456789)); + pts->add(geos::geom::Coordinate(0.123456789, 10.123456789)); + pts->add(geos::geom::Coordinate(5.123456789, 15.123456789)); + pts->add(geos::geom::Coordinate(8.123456789, -5.123456789)); + pts->add(geos::geom::Coordinate(0.123456789, 0.123456789)); + + try { + vector polys; + polys.push_back(Isis::globalFactory.createPolygon( + Isis::globalFactory.createLinearRing(pts), NULL)); + + geos::geom::MultiPolygon *mPolygon = Isis::globalFactory.createMultiPolygon(polys); + + Isis::ImageOverlap a("idFour", *mPolygon); + PrintImageOverlap(a); + } + catch(geos::util::GEOSException *exc) { + cout << "GEOS Exception: " << exc->what() << endl; + delete exc; + } + } + +} + +// Print a ImageOverlap +void PrintImageOverlap(Isis::ImageOverlap &poi) { + + // Write the wkt version of the multi polygon to the screen + const geos::geom::MultiPolygon *mp = poi.Polygon(); + cout << "Well Known Text version of the multi polygon" << endl; + cout << mp->toString() << endl << endl; + + cout << "Area of the polygon " << poi.Area() << endl; + cout << "Number of serial numbers: " << poi.Size() << endl;; + cout << "Serial numbers: " << endl; + for(int i = 0; i < poi.Size(); i++) { + cout << " " << poi[i] << endl; + } + cout << endl; + return; +} diff --git a/isis/src/base/objs/ImageOverlapSet/ImageOverlapSet.cpp b/isis/src/base/objs/ImageOverlapSet/ImageOverlapSet.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a65931f3e680d8c1964883fc873b32c22935161b --- /dev/null +++ b/isis/src/base/objs/ImageOverlapSet/ImageOverlapSet.cpp @@ -0,0 +1,983 @@ +#include +#include +#include +#include +#include +#include + +#include "geos/operation/distance/DistanceOp.h" +#include "geos/util/IllegalArgumentException.h" +#include "geos/geom/Point.h" +#include "geos/opOverlay.h" +#include "iException.h" +#include "Cube.h" +#include "SerialNumberList.h" +#include "PolygonTools.h" +#include "ImagePolygon.h" +#include "Filename.h" +#include "ImageOverlapSet.h" +#include "Progress.h" + +using namespace std; + +namespace Isis { + /** + * Create FindImageOverlaps object. + * + * Create an empty FindImageOverlaps object. + * + * @param continueOnError Whether or not this class throws exceptions in + * addition to logging errors. + * @see automaticRegistration.doc + */ + ImageOverlapSet::ImageOverlapSet(bool continueOnError) { + p_continueAfterError = continueOnError; + p_writtenSoFar = 0; + p_calculatedSoFar = -1; + p_threadedCalculate = false; + p_snlist = NULL; + } + + + /** + * Delete this object. + * + * Delete the FindImageOverlaps object. The stored ImageOverlaps + * will be deleted as well. + */ + ImageOverlapSet::~ImageOverlapSet() { + for (int i=0; iPolys()); + + delete poly; + poly = NULL; + + geos::geom::MultiPolygon *mp = NULL; + + // If footprint is invalid throw exception + if (!tmp->isValid()) { + delete tmp; + tmp = NULL; + iString msg = "The image [" + sns.Filename(sns.SerialNumber(i)) + "] has an invalid footprint"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + try { + mp = PolygonTools::Despike (tmp); + } catch (iException &e) { + if (tmp->isValid()) { + mp = tmp; + tmp = NULL; + } else { + delete tmp; + tmp = NULL; + HandleError(e, &sns); + continue; + } + } + + p_lonLatOverlaps.push_back(CreateNewOverlap(sns.SerialNumber(i), mp)); + + if (mp) { + delete mp; + mp = NULL; + } + + if (tmp) { + delete tmp; + tmp = NULL; + } + } + + // Despikes the polygons from the Serial Numbers prior to overlap determination + DespikeLonLatOverlaps(); + + if(p_threadedCalculate) { + // Call FindAllOverlaps in other thread + start(); + } + else { + // Determine the overlap between each boundary polygon + FindAllOverlaps (&sns); + } + } + + /** + * This method calculates image overlaps given a SerialNumberList and writes it + * to the filename specified by outputFile. This method is internally optimized + * and multi-threaded: the overlaps will NOT persist in memory after this method + * is called. This object will be reset to its initial state when this is + * called, and it is invalid to call this method if you have called other + * methods first. + * + * This method is internally multi-threaded and more efficient than the others + * for calculating overlaps. + * + * @param boundaries The files to find overlaps between + * @param outputFile The output ImageOverlapSet file + * + */ + void ImageOverlapSet::FindImageOverlaps(SerialNumberList &boundaries, std::string outputFile) { + // Do a common sense programmer check, this should be empty before we start + if(!p_lonLatOverlaps.empty()) { + string msg = "FindImageOverlaps(SerialNumberList&,std::string) may not be called on an ImageOverlapSet " \ + "which already contains overlaps."; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + p_writtenSoFar = 0; + p_calculatedSoFar = -1; + + p_snlist = &boundaries; + + // This will enable using mutexes and spawning threads where necessary. + p_threadedCalculate = true; + + FindImageOverlaps(boundaries); + + // While our exit condition is not true, call WriteImageOverlaps with the filename. The + // WriteImageOverlaps call will block if it is waiting on calculations. + while(p_calculatedSoFar != (int)p_lonLatOverlaps.size()) { + WriteImageOverlaps(outputFile); + } + + // Wait for the calculation thread to actually exit, this has more than likely already occurred. + wait(); + + // re-initialize object to original state + p_lonLatOverlaps.clear(); + p_writtenSoFar = 0; + p_calculatedSoFar = -1; + p_threadedCalculate = false; + p_snlist = NULL; + } + + + /** This is a strict pthread implementation of this class' multi-threading! + * + void ImageOverlapSet::FindImageOverlaps(SerialNumberList &boundaries, std::string outputFile) { + // Do a common sense programmer check, this should be empty before we start + if(!p_lonLatOverlaps.empty()) { + string msg = "FindImageOverlaps(SerialNumberList&,std::string) may not be called on an ImageOverlapSet " \ + "which already contains overlaps."; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + p_writtenSoFar = 0; + p_calculatedSoFar = -1; + + // This will enable using mutexes in the method calls where necessary. + p_threadedCalculate = true; + + // We need to pass a this pointer to the thread AND the serial number list in order to have it + // calculate properly. Build the void* to pass in. + void *data[] = {this, &boundaries}; + + // This is the thread that will be calculating the overlaps. Our current thread will be the one writing + // to the output file so synchronization at exit is not an issue. + pthread_t calculateThread; + + // Enter the initialization phase: don't try to write until the other thread says initialization is done by + // unlocking this mutex. + pthread_mutex_lock(&initDataMutex); + + // Create the other thread - it will initialize variables (the ImageOverlap list), unlock the initDataMutex, + // and proceed to calculate. After each polygon is calculated the calculating mutex will also be + // unlocked in order to allow I/O if possible. When done calculatedSoFar == p_lonLatOverlaps.size() and the calculating mutex + // is unlocked. + pthread_create(&calculateThread, NULL, FindImageOverlapsThreadStart, &data); + + // this will let us pass when initialization is done + pthread_mutex_lock(&initDataMutex); + + // Final unlock of the initialization mutex - we locked it to get into this code + pthread_mutex_unlock(&initDataMutex); + + // While our exit condition is not true, call WriteImageOverlaps with the filename. The + // WriteImageOverlaps call will block if it is waiting on calculations. + while(p_calculatedSoFar != (int)p_lonLatOverlaps.size()) { + WriteImageOverlaps(outputFile); + } + + // Wait for the calculation thread to actually exit, this has more than likely already occurred. + void *result; + pthread_join(calculateThread, &result); + + // re-initialize object to original state + p_lonLatOverlaps.clear(); + p_writtenSoFar = 0; + p_calculatedSoFar = -1; + p_threadedCalculate = false; + }*/ + + + /** + * This is the method that is called when a thread is spawned by + * FindImageOverlaps(...). It simply calls FindImageOverlaps with a + * SerialNumberList and exits. + * + * @param data An array of the form {ImageOverlapSet* instance, SerialNumberList + * *snlist) + * + * @return void* Returns null + * + void *ImageOverlapSet::FindImageOverlapsThreadStart(void *data) { + ImageOverlapSet *instance = (ImageOverlapSet *) ((void**)data)[0]; + SerialNumberList *snlist = (SerialNumberList *)((void**)data)[1]; + instance->FindImageOverlaps( *snlist ); + pthread_exit(NULL); + }*/ + + + /** + * Create polygons of overlap from the polygons specified. The serial numbers + * and the polygons are assumed to be parallel arrays. The original polygons + * passed as arguments are copied, so the ownership of the originals remains + * with the caller. + * + * @param sns The serial number list to use when finding overlaps + * + * @param polygons The polygons which are to be used when finding overlaps + * + * @see automaticRegistration.doc + */ + void ImageOverlapSet::FindImageOverlaps(std::vector sns, + std::vector polygons) { + + if (sns.size() != polygons.size()) { + string message = "Invalid argument sizes. Sizes must match."; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + // Create one ImageOverlap for each image sn + for (unsigned int i=0; iisValid() || (multiPolygon->getArea() < 1.0e-10 && !multiPolygon->isEmpty())) { + delete multiPolygon; + multiPolygon = Isis::globalFactory.createMultiPolygon(); + } + + if(position > (int)p_lonLatOverlaps.size()) { + position = p_lonLatOverlaps.size(); + } + + try { + if(!multiPolygon->isEmpty()) { + geos::geom::MultiPolygon *despiked = PolygonTools::Despike(multiPolygon); + delete multiPolygon; + multiPolygon = despiked; + } + } + catch(iException &e) { + e.Clear(); + } + + if (multiPolygon->isValid() && (multiPolygon->isEmpty() || multiPolygon->getArea() > 1.0e-14)) { + if(!insert) { + p_lonLatOverlaps.at(position)->SetPolygon(multiPolygon); + + if(sncopy) { + AddSerialNumbers(p_lonLatOverlaps.at(position), sncopy); + } + } + else if(!multiPolygon->isEmpty()) { + ImageOverlap *imageOverlap = new ImageOverlap(); + imageOverlap->SetPolygon(multiPolygon); + delete multiPolygon; + multiPolygon = NULL; + + if(sncopy) { + AddSerialNumbers(imageOverlap, sncopy); + } + + p_lonLatOverlaps.insert(p_lonLatOverlaps.begin() + position, imageOverlap); + } + + success = true; + } + + return success; + } + + + /** + * Write polygons of overlap to the file specified. + * + * @param filename The file to write the image overlaps to + */ + void ImageOverlapSet::WriteImageOverlaps(const std::string &filename) { + iString file = Filename(filename).Expanded(); + bool failed = false; + if(p_threadedCalculate) p_calculatePolygonMutex.lock(); + + try { + // Let's get an ostream pointed at our file + std::ofstream outStream; + + if (p_writtenSoFar == 0) { + outStream.open(file.c_str(), fstream::out | fstream::trunc | fstream::binary); + } else { + outStream.open(file.c_str(), fstream::out | fstream::app | fstream::binary); + } + + failed |= outStream.fail(); + + static bool overlapWritten = false; + for (int overlap = p_writtenSoFar; !failed && overlap <= p_calculatedSoFar; overlap++) { + if (overlap < (int)p_lonLatOverlaps.size() && p_lonLatOverlaps[overlap]) { + if (!p_lonLatOverlaps[overlap]->Polygon()->isEmpty()) { + if (overlapWritten) { + outStream << std::endl; + } + + p_lonLatOverlaps[overlap]->Write(outStream); + overlapWritten = true; + } + + delete p_lonLatOverlaps[overlap]; + p_lonLatOverlaps[overlap] = NULL; + p_writtenSoFar ++; + } + } + + failed |= outStream.fail(); + outStream.close(); + + failed |= outStream.fail(); + } catch (...) { + failed = true; + } + + /** + * Don't wait for an unlock from FindImageOverlaps(...) if we're done + * calculating. + */ + if(p_calculatedSoFar == (int)p_lonLatOverlaps.size()) { + if(p_threadedCalculate) p_calculatePolygonMutex.unlock(); + } + + if (failed) { + iString msg = "Unable to write the image overlap list to [" + filename + "]"; + throw iException::Message(iException::Io, msg, _FILEINFO_); + } + } + + + /** + * Find the overlaps between all the existing ImageOverlap Objects + * + * @param snlist The serialnumber list relating to the overlaps described by the + * current known ImageOverlap objects or NULL + */ + void ImageOverlapSet::FindAllOverlaps (SerialNumberList *snlist) { + if (p_lonLatOverlaps.size() <= 1) return; + + Progress p; + p.SetText("Calculating Image Overlaps"); + p.SetMaximumSteps( p_lonLatOverlaps.size() - 1 ); + p.CheckStatus(); + + geos::geom::MultiPolygon *emptyPolygon = Isis::globalFactory.createMultiPolygon(); + + // Compare each polygon with all of the others + for (unsigned int outside=0; outsideHasAnySameSerialNumber(*p_lonLatOverlaps.at(inside))) continue; + + // We know these are valid because they were filtered early on + const geos::geom::MultiPolygon *poly1 = p_lonLatOverlaps.at(outside)->Polygon(); + const geos::geom::MultiPolygon *poly2 = p_lonLatOverlaps.at(inside)->Polygon(); + + // Check to see if the two poygons are equivalent. + // If they are, then we can get rid of one of them + if (PolygonTools::Equal(poly1, poly2)) { + AddSerialNumbers (p_lonLatOverlaps[outside],p_lonLatOverlaps[inside]); + p_lonLatOverlaps.erase(p_lonLatOverlaps.begin()+inside); + inside --; + continue; + } + + // We can get empty polygons in our list sometimes; try to avoid extra processing + if (poly2->isEmpty() || poly2->getArea() < 1.0e-14) { + p_lonLatOverlaps.erase(p_lonLatOverlaps.begin()+inside); + inside --; + continue; + } + + geos::geom::Geometry *intersected = NULL; + try { + intersected = PolygonTools::Intersect(poly1, poly2); + } catch (iException &e) { + intersected = NULL; + string error = "Intersection of overlaps failed."; + + // We never want to double seed, so we must delete one or both + // of these polygons because they more than likely have an intersection + // that we simply can't calculate. + double outsideArea = poly1->getArea(); + double insideArea = poly2->getArea(); + double areaRatio = std::min(outsideArea, insideArea) / std::max(outsideArea, insideArea); + + // If one of the polygons is < 1% the area of the other, then only throw out the small one to + // try to minimize the impact of this failure. + if(areaRatio < 0.1) { + if(poly1->getArea() > poly2->getArea()) { + error += " The first polygon will be removed."; + HandleError(e, snlist, error, inside, outside); + p_lonLatOverlaps.erase(p_lonLatOverlaps.begin()+inside); + inside --; + } + else { + error += " The second polygon will be removed."; + HandleError(e, snlist, error, inside, outside); + p_lonLatOverlaps.erase(p_lonLatOverlaps.begin()+outside); + inside = outside; + } + } + else { + error += " Both polygons will be removed to prevent the possibility of double counted areas."; + HandleError(e, snlist, error, inside, outside); + p_lonLatOverlaps.erase(p_lonLatOverlaps.begin()+inside); + p_lonLatOverlaps.erase(p_lonLatOverlaps.begin()+outside); + inside = outside; + } + + continue; + } + + if (intersected->isEmpty() || intersected->getArea() < 1.0e-14) { + delete intersected; + intersected = NULL; + continue; + } + + // We are only interested in overlaps that result in polygon(s) + // and not any that are lines or points, so create a new multipolygon + // with only the polygons of overlap + geos::geom::MultiPolygon *overlap = NULL; + try { + overlap = PolygonTools::Despike(intersected); + + delete intersected; + intersected = NULL; + } catch (iException &e) { + if (!intersected->isValid()) { + delete intersected; + intersected = NULL; + + HandleError(e, snlist, "", inside, outside); + continue; + } + else { + overlap = PolygonTools::MakeMultiPolygon(intersected); + e.Clear(); + + delete intersected; + intersected = NULL; + } + } catch (geos::util::GEOSException *exc) { + delete intersected; + intersected = NULL; + HandleError(exc, snlist, "", inside, outside); + continue; + } + + if (!overlap->isValid()) { + delete overlap; + overlap = NULL; + HandleError(snlist, "Intersection produced invalid overlap area", inside, outside); + continue; + } + + // is there really overlap? + if(overlap->isEmpty() || overlap->getArea() < 1.0e-14) { + delete overlap; + overlap = NULL; + continue; + } + + // poly1 is completly inside poly2 + if (PolygonTools::Equal(poly1,overlap)) { + geos::geom::Geometry *tmpGeom = NULL; + try { + tmpGeom = PolygonTools::Difference(poly2, poly1); + } catch (iException &e) { + HandleError(e, snlist, "Differencing overlap polygons failed. The first polygon will be removed.", inside, outside); + + // Delete outside polygon directly and reset outside loop + // - current outside is thrown out! + p_lonLatOverlaps.erase(p_lonLatOverlaps.begin()+outside); + inside = outside; + + continue; + } + + SetPolygon(tmpGeom, inside); + SetPolygon(overlap, outside, p_lonLatOverlaps[inside]); + } + + // poly2 is completly inside poly1 + else if (PolygonTools::Equal(poly2,overlap)) { + geos::geom::Geometry *tmpGeom = NULL; + try { + tmpGeom = PolygonTools::Difference(poly1, poly2); + } catch (iException &e) { + HandleError(e, snlist, "Differencing overlap polygons failed. The second polygon will be removed.", inside, outside); + + + // Delete inside polygon directly and process next inside + p_lonLatOverlaps.erase(p_lonLatOverlaps.begin()+inside); + inside --; + + continue; + } + + SetPolygon(tmpGeom, outside); + SetPolygon(overlap, inside, p_lonLatOverlaps[outside]); + } + // There is partial overlap + else { + // Subtract overlap from poly1 and set poly1 to the result + geos::geom::Geometry *tmpGeom = NULL; + try { + tmpGeom = PolygonTools::Difference(poly1, overlap); + } catch (iException &e) { + e.Clear(); + tmpGeom = NULL; + } + + // If we failed to subtract overlap, try to subtract poly2 from poly1 and set poly1 to the result + try { + if(tmpGeom == NULL) { + tmpGeom = PolygonTools::Difference(poly1, poly2); + } + } + catch (iException &e) { + tmpGeom = NULL; + HandleError(e, snlist, "Differencing overlap polygons failed", inside, outside); + continue; + } + + if(!SetPolygon(tmpGeom, outside)) { + SetPolygon(Isis::globalFactory.createMultiPolygon(), outside); + } + + int oldSize = p_lonLatOverlaps.size(); + if(SetPolygon(overlap, inside+1, p_lonLatOverlaps[outside], true)) { + int newSize = p_lonLatOverlaps.size(); + int newSteps = newSize - oldSize; + p.AddSteps(newSteps); + + if(newSize != oldSize) inside++; + } + } // End of partial overlap else + } + // Collections are illegal as intersection argument + catch (iException &e) { + HandleError(e, snlist, "Unable to find overlap.", inside, outside); + } + // Collections are illegal as intersection argument + catch (geos::util::IllegalArgumentException *ill) { + HandleError(NULL, snlist, "Unable to find overlap", inside, outside); + } + catch (geos::util::GEOSException *exc) { + HandleError(exc, snlist, "Unable to find overlap", inside, outside); + } + catch (...) { + HandleError(snlist, "Unknown Error: Unable to find overlap", inside, outside); + } + } + + p.CheckStatus(); + } + + p_calculatedSoFar = p_lonLatOverlaps.size(); + delete emptyPolygon; + + // unblock the writing process + p_calculatePolygonMutex.unlock(); + } + + + /** + * Add the serial numbers from the second overlap to the first + * + * Note: Need to check for existence of a SN before adding it + * + * @param to The object to receive the new serial numbers + * + * @param from The object to copy the serial numbers from + * + */ + void ImageOverlapSet::AddSerialNumbers (ImageOverlap *to, ImageOverlap *from) { + for (int i=0; iSize(); i++) { + string s = (*from)[i]; + to->Add(s); + } + } + + + /** + * Create an overlap item to hold the overlap poly and its SN + * + * @param serialNumber The serial number + * + * @param latLonPolygon The object to copy the serial numbers from + * + */ + ImageOverlap* ImageOverlapSet::CreateNewOverlap(std::string serialNumber, + geos::geom::MultiPolygon* latLonPolygon) { + + return new ImageOverlap(serialNumber, *latLonPolygon); + } + + + /** + * Return the overlaps that have a specific serial number. + * + * Search the existing ImageOverlap objects for all that have the + * serial numbers associated with them. Note: This could be costly when many + * overlaps exist. + * + * @param serialNumber The serial number to be search for in all existing + * ImageOverlaps + * @return List of related ImageOverlap objects, ownership is retained by + * ImageOverlapSet* + */ + std::vector ImageOverlapSet::operator[](std::string serialNumber) { + vector matches; + + // Look at all the ImageOverlaps we have and return the ones that + // have this sn + for (unsigned int ov = 0; ov < p_lonLatOverlaps.size(); ++ov) { + for (int sn=0; snSize(); ++sn) { + if ((*p_lonLatOverlaps[ov])[sn] == serialNumber) { + matches.push_back(p_lonLatOverlaps[ov]); + } + } + } + + return matches; + } + + /** + * If a problem occurred when searching for image overlaps, + * this method will handle it. + * + * @param e Isis Exception representing the problem + * @param snlist Serial number list to get file information from + * @param msg Error message + * @param overlap1 First problematic overlap + * @param overlap2 Second problematic overlap + */ + void ImageOverlapSet::HandleError(iException &e, SerialNumberList *snlist, iString msg, int overlap1, int overlap2) { + PvlGroup err("ImageOverlapError"); + + if (overlap1 >= 0 && (unsigned)overlap1 < p_lonLatOverlaps.size()) { + PvlKeyword serialNumbers("PolySerialNumbers"); + PvlKeyword filename("Filenames"); + PvlKeyword polygon("Polygon"); + + for (int i=0; i< p_lonLatOverlaps.at(overlap1)->Size(); i++) { + serialNumbers += (*p_lonLatOverlaps.at(overlap1))[i]; + + if (snlist != NULL) { + filename += snlist->Filename((*p_lonLatOverlaps.at(overlap1))[i]); + } + } + polygon += p_lonLatOverlaps.at(overlap1)->Polygon()->toString(); + + err += serialNumbers; + + if (filename.Size() != 0) { + err += filename; + } + + err += polygon; + } + + if (overlap2 >= 0 && (unsigned)overlap1 < p_lonLatOverlaps.size() && (unsigned)overlap2 < p_lonLatOverlaps.size()) { + PvlKeyword serialNumbers("PolySerialNumbers"); + PvlKeyword filename("Filenames"); + PvlKeyword polygon("Polygon"); + + for (int i=0; iSize(); i++) { + serialNumbers += (*p_lonLatOverlaps.at(overlap2))[i]; + + if (snlist != NULL) { + filename += snlist->Filename((*p_lonLatOverlaps.at(overlap2))[i]); + } + } + polygon += p_lonLatOverlaps.at(overlap2)->Polygon()->toString(); + + err += serialNumbers; + + if (filename.Size() != 0) { + err += filename; + } + + err += polygon; + } + + err += PvlKeyword("Error", e.what()); + + if (!msg.empty()) { + err += PvlKeyword("Description", msg); + } + + p_errorLog.push_back(err); + + if (!p_continueAfterError) throw; + + e.Clear(); + } + + /** + * If a problem occurred when searching for image overlaps, + * this method will handle it. + * + * @param exc GEOS Exception representing the problem + * @param snlist Serial number list to get file information from + * @param msg Error message + * @param overlap1 First problematic overlap + * @param overlap2 Second problematic overlap + */ + void ImageOverlapSet::HandleError(geos::util::GEOSException *exc, SerialNumberList *snlist, iString msg, int overlap1, int overlap2) { + PvlGroup err("ImageOverlapError"); + + if (overlap1 >= 0 && (unsigned)overlap1 < p_lonLatOverlaps.size()) { + PvlKeyword serialNumbers("PolySerialNumbers"); + PvlKeyword filename("Filenames"); + + for (int i=0; iSize(); i++) { + serialNumbers += (*p_lonLatOverlaps.at(overlap1))[i]; + + if (snlist != NULL) { + filename += snlist->Filename((*p_lonLatOverlaps.at(overlap1))[i]); + } + } + + err += serialNumbers; + + if (filename.Size() != 0) { + err += filename; + } + } + + if (overlap2 >= 0 && (unsigned)overlap1 < p_lonLatOverlaps.size() && (unsigned)overlap2 < p_lonLatOverlaps.size()) { + PvlKeyword serialNumbers("PolySerialNumbers"); + PvlKeyword filename("Filenames"); + + for (int i=0; iSize(); i++) { + serialNumbers += (*p_lonLatOverlaps.at(overlap2))[i]; + + if (snlist != NULL) { + filename += snlist->Filename((*p_lonLatOverlaps.at(overlap2))[i]); + } + } + + err += serialNumbers; + + if (filename.Size() != 0) { + err += filename; + } + } + + err += PvlKeyword("Error", iString(exc->what())); + + if (!msg.empty()) { + err += PvlKeyword("Description", msg); + } + + p_errorLog.push_back(err); + + delete exc; + + if (!p_continueAfterError) { + throw iException::Message(iException::Programmer, err["Description"], _FILEINFO_); + } + } + + + /** + * If a problem occurred when searching for image overlaps, + * this method will handle it. + * + * @param snlist Serial number list to get file information from + * @param msg Error message + * @param overlap1 First problematic overlap + * @param overlap2 Second problematic overlap + */ + void ImageOverlapSet::HandleError(SerialNumberList *snlist, iString msg, int overlap1, int overlap2) { + PvlGroup err("ImageOverlapError"); + + if (overlap1 >= 0 && (unsigned)overlap1 < p_lonLatOverlaps.size()) { + PvlKeyword serialNumbers("PolySerialNumbers"); + PvlKeyword filename("Filenames"); + + for (int i=0; iSize(); i++) { + serialNumbers += (*p_lonLatOverlaps.at(overlap1))[i]; + + if (snlist != NULL) { + filename += snlist->Filename((*p_lonLatOverlaps.at(overlap1))[i]); + } + } + + err += serialNumbers; + + if (filename.Size() != 0) { + err += filename; + } + } + + if (overlap2 >= 0 && (unsigned)overlap1 < p_lonLatOverlaps.size() && (unsigned)overlap2 < p_lonLatOverlaps.size()) { + PvlKeyword serialNumbers("PolySerialNumbers"); + PvlKeyword filename("Filenames"); + + for (int i=0; iSize(); i++) { + serialNumbers += (*p_lonLatOverlaps.at(overlap2))[i]; + + if (snlist != NULL) { + filename += snlist->Filename((*p_lonLatOverlaps.at(overlap2))[i]); + } + } + + err += serialNumbers; + + if (filename.Size() != 0) { + err += filename; + } + } + + err += PvlKeyword("Description", msg); + + p_errorLog.push_back(err); + + if (!p_continueAfterError) { + throw iException::Message(iException::Programmer, err["Description"], _FILEINFO_); + } + } + + + /** + * Despikes all of the overlaps in p_lonLatOverlaps. + * Currently (2009-03-19), this fixes spiked multipolygons generated by + * footprintinit, prior to calculating overlaps. + */ + void ImageOverlapSet::DespikeLonLatOverlaps() { + for (int i=0; iSetPolygon( + PolygonTools::Despike( p_lonLatOverlaps[i]->Polygon() ) ); + } catch (iException &e) { + e.Clear(); + } + } + } + + +} diff --git a/isis/src/base/objs/ImageOverlapSet/ImageOverlapSet.h b/isis/src/base/objs/ImageOverlapSet/ImageOverlapSet.h new file mode 100644 index 0000000000000000000000000000000000000000..98773f1db30deae6ac8f9e0c1382dcd951f08994 --- /dev/null +++ b/isis/src/base/objs/ImageOverlapSet/ImageOverlapSet.h @@ -0,0 +1,162 @@ +#ifndef ImageOverlapSet_h +#define ImageOverlapSet_h +/** + * @file + * $Revision: 1.17 $ + * $Date: 2009/06/01 15:18:11 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc/documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include +#include + +#include "geos/geom/MultiPolygon.h" +#include "geos/geom/LinearRing.h" +#include "geos/util/GEOSException.h" + +#include "ImageOverlap.h" +#include "iException.h" +#include "PvlGroup.h" + +namespace Isis { + + // Forward declarations + class SerialNumberList; + + /** + * This class is used to find the overlaps between all the images in a list of + * serial numbers. The overlaps are created in (Lon,Lat) coordinates of + * geos::geom::MultiPolygons. Each overlap has an associated list of serial numbers + * which are contained in that overlap. + * + * @ingroup PatternMatching + * + * @author 2006-01-20 Stuart Sides + * + * @internal + * @history 2008-06-18 Christopher Austin - Fixed documentation + * @history 2008-08-18 Steven Lambright - Updated to work with geos3.0.0 + * instead of geos2. Mostly namespace changes. + * @history 2008-11-24 Steven Lambright - Improved upon error reporting. Added + * the Errors() method. + * @history 2008-11-25 Steven Koechle - Moved Despike Methods from + * ImageOverlapSet to PolygonTools + * @history 2008-12-10 Steven Koechle - Moved MakeMultiPolygon Method from + * ImageOverlapSet to PolygonTools + * @history 2008-12-05 Steven Lambright - Checking footprints for validity now, + * fixed an issue with the intersection operator where an invalid but + * repairable polygon is produced, and fixed a memory leak. + * @history 2008-12-15 Steven Koechle - Fixed to read new footprint blob naming + * scheme. + * @history 2009-01-06 Steven Koechle - Removed backwards compatibility for old + * footprint blob name. Added a throw if footprints are invalid in an + * image. + * @history 2009-01-07 Steven Lambright & Christopher Austin - Fixed handling + * of Despike(...) throwing errors on empty polygons + * @history 2009-01-13 Steven Lambright - Deletes both overlaps if an + * intersection fails for an unknown reason. + * @history 2009-01-28 Steven Lambright - Fixed memory leaks + * @history 2009-03-12 Christopher Austin - Added the MULTIPOLYGON to + * HandleError() as the Keyword "Polygon" + * @history 2009-06-01 Christopher Austin - Changed the basic algorithm to + * improve results. + * @history 2009-06-01 Steven Lambright - Multi-threaded this object. Split + * code into smaller methods, now new elements are inserted next + * instead of appended to the end of the overlap list, and added more + * error-recovery solutions. + */ + class ImageOverlapSet : private QThread { + public: + ImageOverlapSet (bool continueOnError = false); + virtual ~ImageOverlapSet(); + + void FindImageOverlaps(SerialNumberList &boundaries); + void FindImageOverlaps(std::vector sns, + std::vector polygons); + void FindImageOverlaps(SerialNumberList &boundaries, std::string outputFile); + void ReadImageOverlaps(const std::string &filename); + void WriteImageOverlaps(const std::string &filename); + + /** + * Returns the total number of latitude and longitude overlaps + * + * @return int The number of lat/lon overlaps + */ + int Size() { return p_lonLatOverlaps.size(); } + + /** + * Returns the images which overlap at a given loverlap + * + * @param index The index of the overlap + * + * @return const ImageOverlap* The polygon and serial numbers which define the + * indexed overlap. + */ + const ImageOverlap* operator[](int index) {return p_lonLatOverlaps[index];}; + + std::vector operator[](std::string serialNumber); + + //! Return the a list of errors encountered + const std::vector &Errors() { return p_errorLog; } + protected: + void FindAllOverlaps (SerialNumberList *snlist = NULL); + void AddSerialNumbers (ImageOverlap *to, ImageOverlap *from); + + //! This is a list of detailed* errors including all known information + std::vector p_errorLog; + + private: + //! Find overlaps is all the threaded calculate does + void run() { FindAllOverlaps(p_snlist); } + + void DespikeLonLatOverlaps (); + + std::vector p_lonLatOverlaps; //!< The list of lat/lon overlaps + + ImageOverlap* CreateNewOverlap (std::string serialNumber, + geos::geom::MultiPolygon* lonLatPolygon); + + bool SetPolygon(geos::geom::Geometry *poly, int position, ImageOverlap *sncopy = NULL, bool insert=false); + void HandleError(iException &e, SerialNumberList *snlist, iString msg = "", int overlap1 = -1, int overlap2 = -1); + void HandleError(geos::util::GEOSException *exc, SerialNumberList *snlist, iString msg = "", int overlap1 = -1, int overlap2 = -1); + void HandleError(SerialNumberList *snlist, iString msg, int overlap1 = -1, int overlap2 = -1); + + bool p_continueAfterError; //!< If false iExceptions will be thrown from FindImageOverlaps(...) + bool p_threadedCalculate; //!< True if we want to do calculations in a threaded way + int p_writtenSoFar; //!< The index of the last overlap that is done writing (number written-1) + int p_calculatedSoFar; //!< The index of the last overlap that is done calculating (number calculated-1) + + //! This is used for multi-threaded calls to FindAllOverlaps only; this class never gets ownership of this pointer + SerialNumberList *p_snlist; + + /** + * This mutex will be used to have blocking on the write method when + * multi-threading (instead of busy waiting), it is not intended to prevent + * calculations and writing from happening simultaneously. Every time we have + * new polygons this is unlocked by FindImageOverlaps(...) and re-locked by + * WriteImageOverlaps(...). + */ + QMutex p_calculatePolygonMutex; + }; +}; + +#endif diff --git a/isis/src/base/objs/ImageOverlapSet/ImageOverlapSet.truth b/isis/src/base/objs/ImageOverlapSet/ImageOverlapSet.truth new file mode 100644 index 0000000000000000000000000000000000000000..9d6addc10c66dcda14b5d6427f1a0e1c972e13e8 --- /dev/null +++ b/isis/src/base/objs/ImageOverlapSet/ImageOverlapSet.truth @@ -0,0 +1,99 @@ +Test 1 +Calculating Image Overlaps +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed Well Known Text + MULTIPOLYGON (((1.0000000000000000 9.0000000000000000, 3.0000000000000000 9.0000000000000000, 3.0000000000000000 7.0000000000000000, 5.0000000000000000 7.0000000000000000, 5.0000000000000000 4.0000000000000000, 1.0000000000000000 4.0000000000000000, 1.0000000000000000 9.0000000000000000))) + Number of serial numbers: 1 + Serial numbers: + A + +Well Known Text + MULTIPOLYGON (((3.0000000000000000 10.0000000000000000, 12.0000000000000000 10.0000000000000000, 12.0000000000000000 9.0000000000000000, 11.0000000000000000 9.0000000000000000, 11.0000000000000000 8.0000000000000000, 6.0000000000000000 8.0000000000000000, 6.0000000000000000 9.0000000000000000, 3.0000000000000000 9.0000000000000000, 3.0000000000000000 10.0000000000000000))) + Number of serial numbers: 1 + Serial numbers: + B + +Well Known Text + MULTIPOLYGON (((5.0000000000000000 7.0000000000000000, 3.0000000000000000 7.0000000000000000, 3.0000000000000000 9.0000000000000000, 6.0000000000000000 9.0000000000000000, 6.0000000000000000 8.0000000000000000, 5.0000000000000000 8.0000000000000000, 5.0000000000000000 7.0000000000000000))) + Number of serial numbers: 2 + Serial numbers: + A + B + +Well Known Text + MULTIPOLYGON (((12.0000000000000000 8.0000000000000000, 12.0000000000000000 9.0000000000000000, 15.0000000000000000 9.0000000000000000, 15.0000000000000000 5.0000000000000000, 14.0000000000000000 5.0000000000000000, 14.0000000000000000 8.0000000000000000, 12.0000000000000000 8.0000000000000000))) + Number of serial numbers: 1 + Serial numbers: + C + +Well Known Text + MULTIPOLYGON (((11.0000000000000000 8.0000000000000000, 11.0000000000000000 9.0000000000000000, 12.0000000000000000 9.0000000000000000, 12.0000000000000000 8.0000000000000000, 11.0000000000000000 8.0000000000000000))) + Number of serial numbers: 2 + Serial numbers: + B + C + +Well Known Text + MULTIPOLYGON (((14.0000000000000000 5.0000000000000000, 14.0000000000000000 2.0000000000000000, 5.0000000000000000 2.0000000000000000, 5.0000000000000000 4.0000000000000000, 6.0000000000000000 4.0000000000000000, 6.0000000000000000 7.0000000000000000, 11.0000000000000000 7.0000000000000000, 11.0000000000000000 6.0000000000000000, 10.0000000000000000 6.0000000000000000, 10.0000000000000000 4.0000000000000000, 13.0000000000000000 4.0000000000000000, 13.0000000000000000 5.0000000000000000, 14.0000000000000000 5.0000000000000000))) + Number of serial numbers: 1 + Serial numbers: + D + +Well Known Text + MULTIPOLYGON (((11.0000000000000000 8.0000000000000000, 12.0000000000000000 8.0000000000000000, 12.0000000000000000 7.0000000000000000, 11.0000000000000000 7.0000000000000000, 11.0000000000000000 8.0000000000000000))) + Number of serial numbers: 3 + Serial numbers: + B + C + D + +Well Known Text + MULTIPOLYGON (((14.0000000000000000 8.0000000000000000, 14.0000000000000000 5.0000000000000000, 13.0000000000000000 5.0000000000000000, 13.0000000000000000 6.0000000000000000, 11.0000000000000000 6.0000000000000000, 11.0000000000000000 7.0000000000000000, 12.0000000000000000 7.0000000000000000, 12.0000000000000000 8.0000000000000000, 14.0000000000000000 8.0000000000000000))) + Number of serial numbers: 2 + Serial numbers: + C + D + +Well Known Text + MULTIPOLYGON (((5.0000000000000000 7.0000000000000000, 5.0000000000000000 8.0000000000000000, 6.0000000000000000 8.0000000000000000, 6.0000000000000000 7.0000000000000000, 5.0000000000000000 7.0000000000000000))) + Number of serial numbers: 3 + Serial numbers: + A + B + D + +Well Known Text + MULTIPOLYGON (((6.0000000000000000 7.0000000000000000, 6.0000000000000000 8.0000000000000000, 11.0000000000000000 8.0000000000000000, 11.0000000000000000 7.0000000000000000, 6.0000000000000000 7.0000000000000000))) + Number of serial numbers: 2 + Serial numbers: + B + D + +Well Known Text + MULTIPOLYGON (((5.0000000000000000 4.0000000000000000, 5.0000000000000000 7.0000000000000000, 6.0000000000000000 7.0000000000000000, 6.0000000000000000 4.0000000000000000, 5.0000000000000000 4.0000000000000000))) + Number of serial numbers: 2 + Serial numbers: + A + D + +Well Known Text + MULTIPOLYGON (((10.0000000000000000 6.0000000000000000, 11.0000000000000000 6.0000000000000000, 11.0000000000000000 5.0000000000000000, 13.0000000000000000 5.0000000000000000, 13.0000000000000000 4.0000000000000000, 10.0000000000000000 4.0000000000000000, 10.0000000000000000 6.0000000000000000))) + Number of serial numbers: 2 + Serial numbers: + E + D + +Well Known Text + MULTIPOLYGON (((11.0000000000000000 6.0000000000000000, 13.0000000000000000 6.0000000000000000, 13.0000000000000000 5.0000000000000000, 11.0000000000000000 5.0000000000000000, 11.0000000000000000 6.0000000000000000))) + Number of serial numbers: 3 + Serial numbers: + C + D + E + +Well Known Text + MULTIPOLYGON (((1.0000000000000000 1.0000000000000000, 1.0000000000000000 2.0000000000000000, 4.0000000000000000 2.0000000000000000, 4.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000))) + Number of serial numbers: 1 + Serial numbers: + F + + diff --git a/isis/src/base/objs/ImageOverlapSet/Makefile b/isis/src/base/objs/ImageOverlapSet/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..25fb164a2c0a9a823b76ffd9f9bbc6b1235637eb --- /dev/null +++ b/isis/src/base/objs/ImageOverlapSet/Makefile @@ -0,0 +1,5 @@ +INCS = ImageOverlapSet.h +SRCS = ImageOverlapSet.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ImageOverlapSet/unitTest.cpp b/isis/src/base/objs/ImageOverlapSet/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9ca28767f7134eac63c679aba6872de4e3da03eb --- /dev/null +++ b/isis/src/base/objs/ImageOverlapSet/unitTest.cpp @@ -0,0 +1,205 @@ +#include +#include + +#include "iException.h" +#include "SerialNumberList.h" +#include "PolygonTools.h" +#include "ImageOverlapSet.h" +#include "Preference.h" +#include "geos/util/GEOSException.h" +#include "geos/geom/Polygon.h" +#include "geos/geom/LinearRing.h" +#include "geos/geom/CoordinateArraySequence.h" + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + void PrintImageOverlap (const Isis::ImageOverlap *poi); + + // Create 6 multi polygons + // 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 + // 10 +--------------------------+ + // | B | + // 09 +-----|--------+ +--|--------+ + // | A | a | |c | C | + // 08 | | +--|--------------|--|-----+ | + // | | |g | d |h | | | + // 07 | +-----|--|--------------|--+ e | | + // | | | | | | + // 06 | |b | D +-|-----+ | | + // | | | | | f | | | + // 05 | | | | +-----|--|--+ + // | | | | E | | + // 04 +-----------|--+ +-------+ | + // | | + // 03 | | + // | | + // 02 +--------+ +--------------------------+ + // | F | + // 01 +--------+ + // + // Name Comes From + // A A-a-b <---First start + // B B-a-c-d + // C C-c-e-f + // D D-b-d-e + // E E-f + // F F <---First stop + // a AnB-g <---Second start + // b AnD-g + // c BnC-h + // d BnD-h + // e CnD + // f CnE + // DnE * Equivalent to E so throw it away + // g anb <---Third start + // h cnd <-- Second stop + // + //----------------------------------------------------------------- + + cout << "Test 1" << endl; + + // Fill a vector of MultiPolygon* and serial numbers + vector boundaries; + vector sns; + + // Reusable variables + geos::geom::CoordinateSequence *pts; + vector polys; + + // Create the A polygon + pts = new geos::geom::CoordinateArraySequence (); + pts->add (geos::geom::Coordinate (1,9)); + pts->add (geos::geom::Coordinate (6,9)); + pts->add (geos::geom::Coordinate (6,4)); + pts->add (geos::geom::Coordinate (1,4)); + pts->add (geos::geom::Coordinate (1,9)); + + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing(pts),NULL)); + + boundaries.push_back(Isis::globalFactory.createMultiPolygon (polys)); + + for (unsigned int i=0; iadd (geos::geom::Coordinate (3,10)); + pts->add (geos::geom::Coordinate (12,10)); + pts->add (geos::geom::Coordinate (12,7)); + pts->add (geos::geom::Coordinate (3,7)); + pts->add (geos::geom::Coordinate (3,10)); + + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing (pts),NULL)); + boundaries.push_back(Isis::globalFactory.createMultiPolygon (polys)); + + for (unsigned int i=0; iadd (geos::geom::Coordinate (11,5)); + pts->add (geos::geom::Coordinate (11,9)); + pts->add (geos::geom::Coordinate (15,9)); + pts->add (geos::geom::Coordinate (15,5)); + pts->add (geos::geom::Coordinate (11,5)); + + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing (pts),NULL)); + boundaries.push_back(Isis::globalFactory.createMultiPolygon (polys)); + + for (unsigned int i=0; iadd (geos::geom::Coordinate (14,8)); + pts->add (geos::geom::Coordinate (14,2)); + pts->add (geos::geom::Coordinate (5,2)); + pts->add (geos::geom::Coordinate (5,8)); + pts->add (geos::geom::Coordinate (14,8)); + + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing (pts),NULL)); + boundaries.push_back(Isis::globalFactory.createMultiPolygon (polys)); + + for (unsigned int i=0; iadd (geos::geom::Coordinate (10,6)); + pts->add (geos::geom::Coordinate (13,6)); + pts->add (geos::geom::Coordinate (13,4)); + pts->add (geos::geom::Coordinate (10,4)); + pts->add (geos::geom::Coordinate (10,6)); + + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing (pts),NULL)); + boundaries.push_back(Isis::globalFactory.createMultiPolygon (polys)); + + for (unsigned int i=0; iadd (geos::geom::Coordinate (1,1)); + pts->add (geos::geom::Coordinate (1,2)); + pts->add (geos::geom::Coordinate (4,2)); + pts->add (geos::geom::Coordinate (4,1)); + pts->add (geos::geom::Coordinate (1,1)); + + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing (pts),NULL)); + boundaries.push_back(Isis::globalFactory.createMultiPolygon (polys)); + + for (unsigned int i=0; iPolygon(); + cout << "Well Known Text" << endl; + cout << " " << mp->toString() << endl; + cout << " Number of serial numbers: " << poi->Size() << endl;; + cout << " Serial numbers: " << endl; + for (int i=0; iSize(); i++) { + cout << " " << (*poi)[i] << endl; + } + cout << endl; + return; +} + diff --git a/isis/src/base/objs/ImageOverlapSet/unitTest.exclude b/isis/src/base/objs/ImageOverlapSet/unitTest.exclude new file mode 100644 index 0000000000000000000000000000000000000000..f060743489e0cd516a300828c4538c30c150bdf3 --- /dev/null +++ b/isis/src/base/objs/ImageOverlapSet/unitTest.exclude @@ -0,0 +1 @@ +Processed diff --git a/isis/src/base/objs/ImagePolygon/ImagePolygon.cpp b/isis/src/base/objs/ImagePolygon/ImagePolygon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a4b4fbfb5f625822ff407d6156461aca73896a41 --- /dev/null +++ b/isis/src/base/objs/ImagePolygon/ImagePolygon.cpp @@ -0,0 +1,1390 @@ +/** +* @file +* $Revision: 1.37 $ +* $Date: 2010/05/14 19:17:43 $ +* +* Unless noted otherwise, the portions of Isis written by the USGS are +* public domain. See individual third-party library and package descriptions +* for intellectual property information, user agreements, and related +* information. +* +* Although Isis has been used by the USGS, no warranty, expressed or +* implied, is made by the USGS as to the accuracy and functioning of such +* software and related material nor shall the fact of distribution +* constitute any such warranty, and no responsibility is assumed by the +* USGS in connection therewith. +* +* For additional information, launch +* $ISISROOT/doc//documents/Disclaimers/Disclaimers.html +* in a browser or see the Privacy & Disclaimers page on the Isis website, +* http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on +* http://www.usgs.gov/privacy.html. +*/ + + +#include +#include +#include +#include "ImagePolygon.h" +#include "SpecialPixel.h" +#include "PolygonTools.h" +#include "geos/geom/Geometry.h" +#include "geos/geom/Polygon.h" +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/algorithm/LineIntersector.h" +#include "geos/util/IllegalArgumentException.h" +#include "geos/util/TopologyException.h" +#include "geos/util/GEOSException.h" +#include "geos/io/WKTReader.h" +#include "geos/io/WKTWriter.h" +#include "geos/operation/distance/DistanceOp.h" + +using namespace std; + +namespace Isis { + + /** + * Constructs a Polygon object, setting the polygon name + * + */ + ImagePolygon::ImagePolygon() : Blob("Footprint", "Polygon") { + p_polygons = NULL; + p_cubeStartSamp = 1; + p_cubeStartLine = 1; + p_emission = 180.0; + p_incidence = 180.0; + p_subpixelAccuracy = 50; //An accuracte and quick number + p_ellipsoid = false; + } + + + //! Destroys the Polygon object + ImagePolygon::~ImagePolygon() { + if(p_polygons != 0) delete p_polygons; + } + + + /** + * Create a Polygon from given cube + * + * @param[in] cube (Cube &) Cube used to create polygon + * + * @param[in] sampinc (Default=1) (in) Pixel increment to define the + * granularity of the resulting polygon in the sample direction + * @param[in] lineinc (Default=1) (in) Pixel increment to define the + * granularity of the resulting polygon in the line direction + * + * @param[in] ss (Default=1) (in) Starting sample number + * @param[in] sl (Default=1) (in) Starting Line number + * @param[in] ns (Default=0) (in) Number of samples used to create + * the polygon. Default of 0 will cause ns to be set to the number of + * samples in the cube. + * @param[in] nl (Default=0) (in) Number of lines used to create + * the polygon. Default of 0 will cause nl to be set to the number of + * lines in the cube. + * @param[in] band (Default=1) (in) Image band number + * + * @history 2008-04-28 Tracie Sucharski, When calculating p_pixInc, set + * to 1 if values calculated is 0. + * @history 2008-12-30 Tracie Sucharski - If ground map returns pole make + * sure it is actually on the image. + * @history 2009-05-28 Stuart Sides - Added the quality argument. + */ + void ImagePolygon::Create(Cube &cube, int sampinc, int lineinc, + int ss, int sl, int ns, int nl, int band) { + + p_sampinc = sampinc; + p_lineinc = lineinc; + p_pts = new geos::geom::CoordinateArraySequence(); + + p_gMap = new UniversalGroundMap(cube); + p_gMap->SetBand(band); + + p_cube = &cube; + + Camera *cam = NULL; + Projection *proj = NULL; + p_isProjected = false; + + try { + cam = cube.Camera(); + } + catch(iException &error) { + try { + proj = cube.Projection(); + error.Clear(); + } + catch(iException &error) { + std::string msg = "Can not create polygon, "; + msg += "cube [" + cube.Filename(); + msg += "] is not a camera or map projection"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + if(cam != NULL) p_isProjected = cam->HasProjection(); + + // Create brick for use in SetImage + p_brick = new Brick(1, 1, 1, cube.PixelType()); + + /*------------------------------------------------------------------------ + / Save cube number of samples and lines for later use. + /-----------------------------------------------------------------------*/ + p_cubeSamps = cube.Samples(); + p_cubeLines = cube.Lines(); + + if(ns != 0) { + p_cubeSamps = std::min(p_cubeSamps, ss + ns); + } + + if(nl != 0) { + p_cubeLines = std::min(p_cubeLines, sl + nl); + } + + p_cubeStartSamp = ss; + p_cubeStartLine = sl; + + if(p_ellipsoid && IsLimb()) { + try { + p_gMap->Camera()->IgnoreElevationModel(true); + } + catch(iException &e) { + e.Clear(); + std::string msg = "Cannot use an ellipsoid shape model"; + msg += " on a limb image without a camera."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + try { + WalkPoly(); + } + catch(iException &e) { + std::string msg = "Cannot find polygon for image [" + cube.Filename() + "]"; + msg += " The increment/step size might be too large."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + /*------------------------------------------------------------------------ + / If image contains 0/360 boundary, the polygon needs to be split up + / into multi polygons. + /-----------------------------------------------------------------------*/ + Pvl defaultMap; + cam->BasicMapping(defaultMap); + + // Create the polygon, fixing if needed + Fix360Poly(); + + if(p_brick != 0) delete p_brick; + + p_gMap->Camera()->IgnoreElevationModel(false); + } + + + /** + * Finds the next point on the image using a left hand rule walking algorithm. To + * initiate the walk pass it the same point for both currentPoint and lastPoint. + * + * @param[in] currentPoint (geos::geom::Coordinate *currentPoint) This is the + * currentPoint in the path. You are looking for its successor. + * + * @param[in] lastPoint (geos::geom::Coordinate lastPoint) This is the + * lastPoint in the path, it allows the algorithm to calculate direction. + * + * @param[in] recursionDepth (int) This optional parameter keeps track + * of how far it has walked around a point. By default it is zero. + * + * throws Isis::iException::Programmer - Error walking the file + * + */ + geos::geom::Coordinate ImagePolygon::FindNextPoint(geos::geom::Coordinate *currentPoint, + geos::geom::Coordinate lastPoint, + int recursionDepth) { + double x = lastPoint.x - currentPoint->x; + double y = lastPoint.y - currentPoint->y; + geos::geom::Coordinate result; + + // Check to see if depth is too deep (walked all the way around and found nothing) + if(recursionDepth > 6) { + return *currentPoint; + } + + // Check and walk in appropriate direction + if(x == 0.0 && y == 0.0) { // Find the starting point on an image + for(int line = -1 * p_lineinc; line <= 1 * p_lineinc; line += p_lineinc) { + for(int samp = -1 * p_sampinc; samp <= 1 * p_sampinc; samp += p_sampinc) { + double s = currentPoint->x + samp; + double l = currentPoint->y + line; + // Try the next left hand rule point if (s,l) does not produce a + // lat/long or it is not on the image. + if(!InsideImage(s, l) || !SetImage(s, l)) { + geos::geom::Coordinate next(s, l); + return FindNextPoint(currentPoint, next); + } + } + } + + std::string msg = "Unable to create image footprint. Starting point is not on the edge of the image."; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + else if(x < 0 && y < 0) { // current is top left + geos::geom::Coordinate next(currentPoint->x, currentPoint->y - 1 * p_lineinc); + MoveBackInsideImage(next.x, next.y, 0, -p_lineinc); + if(!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) { + result = FindNextPoint(currentPoint, next, recursionDepth + 1); + } + else { + result = FindBestPoint(currentPoint, next, lastPoint); + } + } + else if(x == 0.0 && y < 0) { // current is top + geos::geom::Coordinate next(currentPoint->x + 1 * p_sampinc, currentPoint->y - 1 * p_lineinc); + MoveBackInsideImage(next.x, next.y, p_sampinc, -p_lineinc); + if(!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) { + result = FindNextPoint(currentPoint, next, recursionDepth + 1); + } + else { + result = FindBestPoint(currentPoint, next, lastPoint); + } + } + else if(x > 0 && y < 0) { // current is top right + geos::geom::Coordinate next(currentPoint->x + 1 * p_sampinc, currentPoint->y); + MoveBackInsideImage(next.x, next.y, p_sampinc, 0); + if(!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) { + result = FindNextPoint(currentPoint, next, recursionDepth + 1); + } + else { + result = FindBestPoint(currentPoint, next, lastPoint); + } + } + else if(x > 0 && y == 0.0) { // current is right + geos::geom::Coordinate next(currentPoint->x + 1 * p_sampinc, currentPoint->y + 1 * p_lineinc); + MoveBackInsideImage(next.x, next.y, p_sampinc, p_lineinc); + if(!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) { + result = FindNextPoint(currentPoint, next, recursionDepth + 1); + } + else { + result = FindBestPoint(currentPoint, next, lastPoint); + } + } + else if(x > 0 && y > 0) { // current is bottom right + geos::geom::Coordinate next(currentPoint->x, currentPoint->y + 1 * p_lineinc); + MoveBackInsideImage(next.x, next.y, 0, p_lineinc); + if(!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) { + result = FindNextPoint(currentPoint, next, recursionDepth + 1); + } + else { + result = FindBestPoint(currentPoint, next, lastPoint); + } + } + else if(x == 0.0 && y > 0) { // current is bottom + geos::geom::Coordinate next(currentPoint->x - 1 * p_sampinc, currentPoint->y + 1 * p_lineinc); + MoveBackInsideImage(next.x, next.y, -p_sampinc, p_lineinc); + if(!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) { + result = FindNextPoint(currentPoint, next, recursionDepth + 1); + } + else { + result = FindBestPoint(currentPoint, next, lastPoint); + } + } + else if(x < 0 && y > 0) { // current is bottom left + geos::geom::Coordinate next(currentPoint->x - 1 * p_sampinc, currentPoint->y); + MoveBackInsideImage(next.x, next.y, -p_sampinc, 0); + if(!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) { + result = FindNextPoint(currentPoint, next, recursionDepth + 1); + } + else { + result = FindBestPoint(currentPoint, next, lastPoint); + } + } + else if(x < 0 && y == 0.0) { // current is left + geos::geom::Coordinate next(currentPoint->x - 1 * p_sampinc, currentPoint->y - 1 * p_lineinc); + MoveBackInsideImage(next.x, next.y, -p_sampinc, -p_lineinc); + if(!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) { + result = FindNextPoint(currentPoint, next, recursionDepth + 1); + } + else { + result = FindBestPoint(currentPoint, next, lastPoint); + } + } + else { + std::string msg = "Unable to create image footprint. Error walking image."; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + + return result; + } + + /** + * This method ensures sample/line after sinc/linc have been applied is inside + * the image. If not, it snaps to the edge of the image - given we didn't start + * at the edge. + * + * @param sample Sample after sinc applied + * @param line Line after linc applied + * @param sinc Sample increment (we can back up at most this much) + * @param linc Line increment (we can back up at most this much) + */ + void ImagePolygon::MoveBackInsideImage(double &sample, double &line, double sinc, double linc) { + // snap to centers of pixels! + + // Starting sample to snap to + const double startSample = p_cubeStartSamp; + // Ending sample to snap to + const double endSample = p_cubeSamps; + // Starting line to snap to + const double startLine = p_cubeStartLine; + // Ending line to snap to + const double endLine = p_cubeLines; + // Original sample for this point (before sinc) + const double origSample = sample - sinc; + // Original line for this point (before linc) + const double origLine = line - linc; + + // We moved left off the image - snap to the edge + if(sample < startSample && sinc < 0) { + // don't snap if we started at the edge + if(origSample == startSample) { + return; + } + + sample = startSample; + } + + // We moved right off the image - snap to the edge + if(sample > endSample && sinc > 0) { + // don't snap if we started at the edge + if(origSample == endSample) { + return; + } + + sample = endSample; + } + + // We moved up off the image - snap to the edge + if(line < startLine && linc < 0) { + // don't snap if we started at the edge + if(origLine == startLine) { + return; + } + + line = startLine; + } + + // We moved down off the image - snap to the edge + if(line > endLine && linc > 0) { + // don't snap if we started at the edge + if(fabs(origLine - endLine) < 0.5) { + return; + } + + line = endLine; + } + + return; + } + + + /** + * This returns true if sample/line are inside the cube + * + * @param sample + * @param line + * + * @return bool + */ + bool ImagePolygon::InsideImage(double sample, double line) { + return (sample >= p_cubeStartSamp - 0.5 && + line > p_cubeStartLine - 0.5 && + sample <= p_cubeSamps + 0.5 && + line <= p_cubeLines + 0.5); + } + + + /** + * Finds the first point that projects in an image + * + * @return geos::geom::Coordinate A starting point that is on the edge of the + * polygon. + */ + geos::geom::Coordinate ImagePolygon::FindFirstPoint() { + // @todo: Brute force method, should be improved + for(int sample = p_cubeStartSamp; sample <= p_cubeSamps; sample++) { + for(int line = p_cubeStartLine; line <= p_cubeLines; line++) { + if(SetImage(sample, line)) { + return geos::geom::Coordinate(sample, line); + } + } + } + + // Check to make sure a point was found + std::string msg = "No lat/lon data found for image"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + + /** + * Walks the image finding its lon lat polygon and stores it to p_pts. + * + * WARNING: Very large pixel increments for cubes that have cameras/projections + * with no data at any of the 4 corners can still fail in this algorithm. + */ + + void ImagePolygon::WalkPoly() { + vector points; + double lat, lon, prevLat, prevLon; + + // Find the edge of the polygon + geos::geom::Coordinate firstPoint = FindFirstPoint(); + points.push_back(firstPoint); + //************************ + // Start walking the edge + //************************ + + // set up for intialization + geos::geom::Coordinate currentPoint = firstPoint; + geos::geom::Coordinate lastPoint = firstPoint; + geos::geom::Coordinate tempPoint; + + do { + tempPoint = FindNextPoint(¤tPoint, lastPoint); + + + // First check if the distance is within range of skipping + bool snapToFirstPoint = true; + + // Never needs to find firstPoint on incements of 1 + snapToFirstPoint &= (p_sampinc != 1 && p_lineinc != 1); + + // Prevents catching the first point as the last + snapToFirstPoint &= (points.size() > 2); + + // This method fails for steps larger than line/sample length + snapToFirstPoint &= (p_sampinc < p_cubeSamps && p_lineinc < p_cubeLines); + + // Checks for appropriate distance without sqrt() call + int minStepSize = std::min(p_sampinc, p_lineinc); + snapToFirstPoint &= (DistanceSquared(¤tPoint, &firstPoint) < (minStepSize * minStepSize)); + + // Searches for skipped firstPoint due to a large pixinc, by using a pixinc of 1 + if(snapToFirstPoint) { + tempPoint = firstPoint; + } + // If pixinc is greater than line or sample dimention, then we could + // skip firstPoint. This checks for that case. + else if(p_sampinc > p_cubeSamps || p_lineinc > p_cubeLines) { + // This is not expensive because incement must be large + for(int pt = 0; pt < (int)points.size(); pt ++) { + if(points[pt].equals(tempPoint)) { + tempPoint = firstPoint; + break; + } + } + } + + + // Failed to find the next point + if(tempPoint.equals(currentPoint)) { + geos::geom::Coordinate oldDuplicatePoint = tempPoint; + + // Init vars for first run through the loop + tempPoint = lastPoint; + lastPoint = currentPoint; + currentPoint = tempPoint; + + // Must be 3 (not 2) to prevent the revisit of the starting point, + // resulting in an infinite loop + if(points.size() < 3) { + std::string msg = "Failed to find next point in the image."; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + // remove last point from the list + points.pop_back(); + + tempPoint = FindNextPoint(¤tPoint, lastPoint, 1); + + if(tempPoint.equals(currentPoint) || tempPoint.equals(oldDuplicatePoint)) { + std::string msg = "Failed to find next valid point in the image."; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + // Check for triangle cycles and try to fix + if(p_sampinc > 1 || p_lineinc > 1) { + if(points[points.size()-3].x == tempPoint.x && + points[points.size()-3].y == tempPoint.y) { + // Remove the triangle from the list + points.pop_back(); + points.pop_back(); + points.pop_back(); + // Reset the current (to be last) point + currentPoint = points[points.size()-1]; + // change increment to prevent randomly bad pixels in the image + if(p_sampinc > 1) p_sampinc --; + if(p_lineinc > 1) p_lineinc --; + } + + /** + * If we have a very large polygon, look for the inability to find the + * starting point by looking for the first cycle in the polygon + * + * "very large" is defined as 250 points + */ + if(points.size() > 250) { + int cycleStart = 0; + int cycleEnd = 0; + + for(unsigned int pt = 1; pt < points.size() && cycleStart == 0; pt ++) { + for(unsigned int check = pt + 1; check < points.size() && cycleStart == 0; check ++) { + if(points[pt] == points[check]) { + cycleStart = pt; + cycleEnd = check; + } + } + } + + // If a cycle was found, make it the polygon + if(cycleStart != 0) { + vector cyclePoints; + for(int pt = cycleStart; pt <= cycleEnd; pt ++) { + cyclePoints.push_back(points[pt]); + } + + points = cyclePoints; + break; + } + } + + } + + lastPoint = currentPoint; + currentPoint = tempPoint; + points.push_back(currentPoint); + + } + while(!currentPoint.equals(firstPoint)); + +// Prints out the sample/line polygon; should be removed once the algorithm is "completed" + /*geos::geom::CoordinateSequence * temp = new geos::geom::CoordinateArraySequence(); + for( unsigned int i = 0; i < points.size(); i ++ ) { + temp->add( points[i] ); + } + std::cerr << std::endl; + std::cerr << temp->toString() << std::endl; + std::cerr << std::endl;*/ + + if(points.size() <= 3) { + std::string msg = "Failed to find enough points on the image."; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + FindSubpixel(points); + +// Prints out the sample/line polygon after subpixel adjustments; should be removed once the algorithm is "completed" + /*geos::geom::CoordinateSequence * temp2 = new geos::geom::CoordinateArraySequence(); + for( unsigned int i = 0; i < points.size(); i ++ ) { + temp2->add( points[i] ); + } + std::cerr << std::endl; + std::cerr << temp2->toString() << std::endl; + std::cerr << std::endl;*/ + + prevLat = 0; + prevLon = 0; + // this vector stores crossing points, where the image crosses the + // meridian. It stores the first coordinate of the pair in its vector + vector *crossingPoints = new vector; + for(unsigned int i = 0; i < points.size(); i++) { + geos::geom::Coordinate *temp = &(points.at(i)); + SetImage(temp->x, temp->y); + lon = p_gMap->UniversalLongitude(); + lat = p_gMap->UniversalLatitude(); + if(abs(lon - prevLon) >= 180 && i != 0) { + crossingPoints->push_back(geos::geom::Coordinate(prevLon, prevLat)); + } + p_pts->add(geos::geom::Coordinate(lon, lat)); + prevLon = lon; + prevLat = lat; + } + + + // Checks for self-intersection and attempts to correct + geos::geom::CoordinateSequence *tempPts = new geos::geom::CoordinateArraySequence(); + + // Gets the starting, second, second to last, and last points to check for validity + tempPts->add(geos::geom::Coordinate((*p_pts)[0].x, (*p_pts)[0].y)); + tempPts->add(geos::geom::Coordinate((*p_pts)[1].x, (*p_pts)[1].y)); + tempPts->add(geos::geom::Coordinate((*p_pts)[p_pts->size()-3].x, (*p_pts)[p_pts->size()-3].y)); + tempPts->add(geos::geom::Coordinate((*p_pts)[p_pts->size()-2].x, (*p_pts)[p_pts->size()-2].y)); + tempPts->add(geos::geom::Coordinate((*p_pts)[0].x, (*p_pts)[0].y)); + + geos::geom::Polygon *tempPoly = globalFactory.createPolygon + (globalFactory.createLinearRing(tempPts), NULL); + + // Remove the last point of the sequence if it produces invalid polygons + if(!tempPoly->isValid()) { + p_pts->deleteAt(p_pts->size() - 2); + } + + delete tempPts; + tempPts = NULL; + // end self-intersection check + + FixPolePoly(crossingPoints); + delete crossingPoints; + crossingPoints = NULL; + } + + + /** + * If the cube crosses the 0/360 boundary and contains a pole, Some points are + * added to allow the polygon to unwrap properly. Throws an error if both poles + * are in the image. Returns if there is no pole in the image. + * + * @param crossingPoints The coordinate sequence that crosses the 0/360 boundry + */ + void ImagePolygon::FixPolePoly(std::vector *crossingPoints) { + // We currently do not support both poles in one image + if(p_gMap->SetUniversalGround(90, 0) && p_gMap->SetUniversalGround(-90, 0)) { + std::string msg = "Unable to create image footprint because image has both poles"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + else if(crossingPoints->size() == 0) { + // No crossing points + return; + } + + if(p_gMap->SetUniversalGround(90, 0)) { + // If the (north) pole is settable but not within proper angles, + // then the polygon does not contain the (north) pole when the cube does + if(p_gMap->Camera()->EmissionAngle() > p_emission) { + return; + } + if(p_gMap->Camera()->IncidenceAngle() > p_incidence) { + return; + } + } + else if(p_gMap->SetUniversalGround(-90, 0)) { + // If the (south) pole is settable but not within proper angles, + // then the polygon does not contain the (south) pole when the cube does + if(p_gMap->Camera()->EmissionAngle() > p_emission) { + return; + } + if(p_gMap->Camera()->IncidenceAngle() > p_incidence) { + return; + } + } + + geos::geom::Coordinate *closestPoint = &crossingPoints->at(0); + geos::geom::Coordinate *pole = NULL; + + // Setup the right pole + if(p_gMap->SetUniversalGround(90, 0)) { + pole = new geos::geom::Coordinate(0, 90); + } + else if(p_gMap->SetUniversalGround(-90, 0)) { + pole = new geos::geom::Coordinate(0, -90); + } + else if(crossingPoints->size() % 2 == 1) { + geos::geom::Coordinate nPole(0, 90); + double nDist = DBL_MAX; + geos::geom::Coordinate sPole(0, -90); + double sDist = DBL_MAX; + + for(unsigned int index = 0; index < p_pts->size(); index ++) { + double north = DistanceSquared(&nPole, &((*p_pts)[index])); + if(north < nDist) { + nDist = north; + } + double south = DistanceSquared(&sPole, &((*p_pts)[index])); + if(south < sDist) { + sDist = south; + } + } + + if(sDist < nDist) { + pole = new geos::geom::Coordinate(0, -90); + } + else { + pole = new geos::geom::Coordinate(0, 90); + } + } + + // Skip the fix if no pole was determined + if(pole == NULL) { + return; + } + + // Find where the pole needs to be split + double closestDistance = DBL_MAX; + for(unsigned int i = 0; i < crossingPoints->size(); i++) { + geos::geom::Coordinate *temp = &crossingPoints->at(i); + double tempDistance; + // Make sure the Lat is as close to 0 as possible for a correct distance + if(temp->x > 180) { + double mod = 0.0; + while((temp->x - mod) > 180) mod += 360.0; + + // Create the modified Point, create a pointer to it, and find the distance + geos::geom::Coordinate modPointMem = geos::geom::Coordinate(temp->x - mod, temp->y); + geos::geom::Coordinate *modPoint = &modPointMem; + tempDistance = DistanceSquared(modPoint, pole); + } + else { + tempDistance = DistanceSquared(temp, pole); + } + if(tempDistance < closestDistance) { + closestDistance = tempDistance; + closestPoint = temp; + } + } + + if(closestDistance == DBL_MAX) { + std::string msg = "Image contains a pole but did not detect a meridian crossing!"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + // split image at the pole + geos::geom::CoordinateSequence *new_points = new geos::geom::CoordinateArraySequence(); + for(unsigned int i = 0; i < p_pts->size(); i++) { + geos::geom::Coordinate temp = p_pts->getAt(i); + new_points->add(temp); + if(temp.equals(*closestPoint)) { + // Setup direction + if(i + 1 != p_pts->size()) { // Prevent overflow exception + double fromLon, toLon; + if((p_pts->getAt(i + 1).x - closestPoint->x) > 0) { + fromLon = 0.0; + toLon = 360.0; + } + else { + fromLon = 360.0; + toLon = 0.0; + } + + geos::algorithm::LineIntersector lineIntersector; + geos::geom::Coordinate crossingPoint; + geos::geom::Coordinate nPole(0.0, 90.0); + geos::geom::Coordinate sPole(0.0, -90.0); + double dist = DBL_MAX; + + for(int num = 0; num < 2 && dist > 180.0; num ++) { + nPole = geos::geom::Coordinate(num * 360.0, 90.0); + sPole = geos::geom::Coordinate(num * 360.0, -90.0); + + if(temp.x > 0.0 && p_pts->getAt(i + 1).x > 0.0) { + crossingPoint = geos::geom::Coordinate(p_pts->getAt(i + 1).x - 360.0 + (num * 720.0), p_pts->getAt(i + 1).y); + } + else if(temp.x < 0.0 && p_pts->getAt(i + 1).x < 0.0) { // This should never happen + crossingPoint = geos::geom::Coordinate(p_pts->getAt(i + 1).x + 360.0 - (num * 720.0), p_pts->getAt(i + 1).y); + } + + dist = std::sqrt(DistanceSquared(&temp, &crossingPoint)); + } + + lineIntersector.computeIntersection(nPole, sPole, temp, crossingPoint); + + if(lineIntersector.hasIntersection()) { + const geos::geom::Coordinate &intersection = lineIntersector.getIntersection(0); + + // Calculate the latituded of the points along the meridian + if(pole->y < intersection.y) { + dist = -dist; + } + vector lats; + double maxLat = std::max(intersection.y, pole->y); + double minLat = std::min(intersection.y, pole->y); + for(double lat = intersection.y + dist; lat < maxLat && lat > minLat; lat += dist) { + lats.push_back(lat); + } + + // Add the new points + new_points->add(geos::geom::Coordinate(fromLon, intersection.y)); + for(int lat = 0; lat < (int)lats.size(); lat ++) { + new_points->add(geos::geom::Coordinate(fromLon, lats[lat])); + } + new_points->add(geos::geom::Coordinate(fromLon, pole->y)); + new_points->add(geos::geom::Coordinate(toLon, pole->y)); + for(int lat = lats.size() - 1; lat >= 0; lat --) { + new_points->add(geos::geom::Coordinate(toLon, lats[lat])); + } + new_points->add(geos::geom::Coordinate(toLon, intersection.y)); + } + else { + std::string msg = "Image contains a pole but could not determine a meridian crossing!"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + } + } + } + delete p_pts; + p_pts = new_points; + delete pole; + } + + + /** + * Sets the sample/line values of the cube to get lat/lon values. This + * method checks whether the image pixel is Null for level 2 images and + * if so, it is considered an invalid pixel. + * + * @param[in] sample (const double) Sample coordinate of the cube + * + * @param[in] line (const double) Line coordinate of the cube + * + * @return bool Returns true if the image was set successfully and false if it + * was not or if pixel of level 2 images is NULL. + */ + bool ImagePolygon::SetImage(const double sample, const double line) { + bool found = false; + if(!p_isProjected) { + found = p_gMap->SetImage(sample, line); + if(!found) { + return false; + } + else { + // Check for valid emission and incidence + try { + if(p_gMap->Camera()->EmissionAngle() > p_emission) { + return false; + } + if(p_gMap->Camera()->IncidenceAngle() > p_incidence) { + return false; + } + } + catch(iException &error) { + error.Clear(); + } + + /** + * This check has been removed because it causes push frame cameras + * to fail inbetween the framelets, resulting in only the first + * framlet to be walked, leaving out the rest of the image. + * + * This can cause autoseed/jigsaw issues, since they require conversion + * from lat/lon to samp/line + */ + // Make sure we can go back to image coordinates + // This is done because some camera models due to distortion, get + // a lat/lon for samp/line=1:1, but entering that lat/lon does + // not return samp/line =1:1. Ie. moc WA global images + //double lat = p_gMap->UniversalLatitude(); + //double lon = p_gMap->UniversalLongitude(); + //return p_gMap->SetUniversalGround(lat,lon); + + return found; + } + } + else { + // If projected, make sure the pixel DN is valid before worrying about + // geometry. + p_brick->SetBasePosition((int)sample, (int)line, 1); + p_cube->Read(*p_brick); + if(Isis::IsNullPixel((*p_brick)[0])) { + return false; + } + else { + found = p_gMap->SetImage(sample, line); + if(!found) { + return false; + } + else { + // Check for valid emission and incidence + try { + if(p_gMap->Camera()->EmissionAngle() > p_emission) { + return false; + } + if(p_gMap->Camera()->IncidenceAngle() > p_incidence) { + return false; + } + } + catch(iException &error) { + error.Clear(); + } + return found; + } + } + } + } + + + /** + * If the cube crosses the 0/360 boundary and does not include a pole, the + * polygon is separated into multiple polygons, usually one on each side of the + * boundary. These polygons are put into a geos Multipolygon. If the cube does + * not cross the 0/360 boundary then the Multipolygon will be a single Polygon. + */ + void ImagePolygon::Fix360Poly() { + bool convertLon = false; + bool negAdjust = false; + bool newCoords = false; // coordinates have been adjusted + geos::geom::CoordinateSequence *newLonLatPts = new geos::geom::CoordinateArraySequence(); + double lon, lat; + double lonOffset = 0; + double prevLon = p_pts->getAt(0).x; + double prevLat = p_pts->getAt(0).y; + + newLonLatPts->add(geos::geom::Coordinate(prevLon, prevLat)); + double dist = 0.0; + for(unsigned int i = 1; i < p_pts->getSize(); i++) { + lon = p_pts->getAt(i).x; + lat = p_pts->getAt(i).y; + // check to see if you just crossed the Meridian + if(abs(lon - prevLon) > 180 && (prevLat != 90 && prevLat != -90)) { + newCoords = true; + // if you were already converting then stop (crossed Meridian even number of times) + if(convertLon) { + convertLon = false; + lonOffset = 0; + } + else { // Need to start converting again, deside how to adjust coordinates + if((lon - prevLon) > 0) { + lonOffset = -360.; + negAdjust = true; + } + else if((lon - prevLon) < 0) { + lonOffset = 360.; + negAdjust = false; + } + convertLon = true; + } + + + } + + // Change to a minimum calculation + if(newCoords && dist == 0.0) { + double longitude = (lon + lonOffset) - prevLon; + double latitude = lat - prevLat; + dist = std::sqrt((longitude * longitude) + (latitude * latitude)); + } + + // add coord + newLonLatPts->add(geos::geom::Coordinate(lon + lonOffset, lat)); + + // set current to old + prevLon = lon; + prevLat = lat; + } + + // Nothing was done so return + if(!newCoords) { + geos::geom::Polygon *newPoly = globalFactory.createPolygon + (globalFactory.createLinearRing(newLonLatPts), NULL); + p_polygons = PolygonTools::MakeMultiPolygon(newPoly); + delete newLonLatPts; + return; + } + + // bisect into seperate polygons + try { + geos::geom::Polygon *newPoly = globalFactory.createPolygon + (globalFactory.createLinearRing(newLonLatPts), NULL); + + geos::geom::CoordinateSequence *pts = new geos::geom::CoordinateArraySequence(); + geos::geom::CoordinateSequence *pts2 = new geos::geom::CoordinateArraySequence(); + + // Depending on direction of compensation bound accordingly + //*************************************************** + + // please verify correct if you change these values + //*************************************************** + if(negAdjust) { + pts->add(geos::geom::Coordinate(0., 90.)); + pts->add(geos::geom::Coordinate(-360., 90.)); + pts->add(geos::geom::Coordinate(-360., -90.)); + pts->add(geos::geom::Coordinate(0., -90.)); + for(double lat = -90.0 + dist; lat < 90.0; lat += dist) { + pts->add(geos::geom::Coordinate(0.0, lat)); + } + pts->add(geos::geom::Coordinate(0., 90.)); + pts2->add(geos::geom::Coordinate(0., 90.)); + pts2->add(geos::geom::Coordinate(360., 90.)); + pts2->add(geos::geom::Coordinate(360., -90.)); + pts2->add(geos::geom::Coordinate(0., -90.)); + for(double lat = -90.0 + dist; lat < 90.0; lat += dist) { + pts2->add(geos::geom::Coordinate(0.0, lat)); + } + pts2->add(geos::geom::Coordinate(0., 90.)); + } + else { + pts->add(geos::geom::Coordinate(360., 90.)); + pts->add(geos::geom::Coordinate(720., 90.)); + pts->add(geos::geom::Coordinate(720., -90.)); + pts->add(geos::geom::Coordinate(360., -90.)); + for(double lat = -90.0 + dist; lat < 90.0; lat += dist) { + pts->add(geos::geom::Coordinate(360.0, lat)); + } + pts->add(geos::geom::Coordinate(360., 90.)); + pts2->add(geos::geom::Coordinate(360., 90.)); + pts2->add(geos::geom::Coordinate(0., 90.)); + pts2->add(geos::geom::Coordinate(0., -90.)); + pts2->add(geos::geom::Coordinate(360., -90.)); + for(double lat = -90.0 + dist; lat < 90.0; lat += dist) { + pts2->add(geos::geom::Coordinate(360.0, lat)); + } + pts2->add(geos::geom::Coordinate(360., 90.)); + } + + geos::geom::Polygon *boundaryPoly = globalFactory.createPolygon + (globalFactory.createLinearRing(pts), NULL); + geos::geom::Polygon *boundaryPoly2 = globalFactory.createPolygon + (globalFactory.createLinearRing(pts2), NULL); + /*------------------------------------------------------------------------ + / Intersecting the original polygon (converted coordinates) with the + / boundary polygons will create the multi polygons with the converted coordinates. + / These will need to be converted back to the original coordinates. + /-----------------------------------------------------------------------*/ + geos::geom::Geometry *intersection = PolygonTools::Intersect(newPoly, boundaryPoly); + geos::geom::MultiPolygon *convertPoly = PolygonTools::MakeMultiPolygon(intersection); + delete intersection; + + intersection = PolygonTools::Intersect(newPoly, boundaryPoly2); + geos::geom::MultiPolygon *convertPoly2 = PolygonTools::MakeMultiPolygon(intersection); + delete intersection; + + /*------------------------------------------------------------------------ + / Adjust points created in the negative space or >360 space to be back in + / the 0-360 world. This will always only need to be done on convertPoly. + / Then add geometries to finalpolys. + /-----------------------------------------------------------------------*/ + vector *finalpolys = new vector; + geos::geom::Geometry *newGeom = NULL; + + for(unsigned int i = 0; i < convertPoly->getNumGeometries(); i++) { + newGeom = (convertPoly->getGeometryN(i))->clone(); + pts = convertPoly->getGeometryN(i)->getCoordinates(); + geos::geom::CoordinateSequence *newLonLatPts = new geos::geom::CoordinateArraySequence(); + // fix the points + + for(unsigned int k = 0; k < pts->getSize() ; k++) { + double lon = pts->getAt(k).x; + double lat = pts->getAt(k).y; + if(negAdjust) { + lon = lon + 360; + } + else { + lon = lon - 360; + } + newLonLatPts->add(geos::geom::Coordinate(lon, lat), k); + + } + // Add the points to polys + finalpolys->push_back(globalFactory.createPolygon + (globalFactory.createLinearRing(newLonLatPts), NULL)); + } + + // This loop is over polygons that will always be in 0-360 space no need to convert + for(unsigned int i = 0; i < convertPoly2->getNumGeometries(); i++) { + newGeom = (convertPoly2->getGeometryN(i))->clone(); + finalpolys->push_back(newGeom); + } + + p_polygons = globalFactory.createMultiPolygon(*finalpolys); + + delete finalpolys; + delete newGeom; + delete newLonLatPts; + delete pts; + delete pts2; + } + catch(geos::util::IllegalArgumentException *geosIll) { + std::string msg = "Unable to create image footprint (Fix360Poly) due to "; + msg += "geos illegal argument [" + iString(geosIll->what()) + "]"; + delete geosIll; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + catch(geos::util::GEOSException *geosExc) { + std::string msg = "Unable to create image footprint (Fix360Poly) due to "; + msg += "geos exception [" + iString(geosExc->what()) + "]"; + delete geosExc; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + catch(iException &e) { + std::string msg = "Unable to create image footprint (Fix360Poly) due to "; + msg += "isis operation exception [" + iString(e.what()) + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + catch(...) { + std::string msg = "Unable to create image footprint (Fix360Poly) due to "; + msg += "unknown exception"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + /** + * Reads Multipolygon from cube blob + * + * @param[in] is (std::fstream) Input stream to read from + * + * throws Isis::iException::Io - Error reading data from stream + * + */ + void ImagePolygon::ReadData(std::istream &is) { + + streampos sbyte = p_startByte - 1; + is.seekg(sbyte, std::ios::beg); + if(!is.good()) { + string msg = "Error preparing to read data from " + p_type + + " [" + p_blobName + "]"; + throw Isis::iException::Message(Isis::iException::Io, msg, _FILEINFO_); + } + + char *buf = new char[p_nbytes+1]; + is.read(buf, p_nbytes); + p_polyStr = buf; + delete []buf; + + if(!is.good()) { + string msg = "Error reading data from " + p_type + " [" + + p_blobName + "]"; + throw Isis::iException::Message(Isis::iException::Io, msg, _FILEINFO_); + } + + geos::io::WKTReader *wkt = new geos::io::WKTReader(&(globalFactory)); + p_polygons = (geos::geom::MultiPolygon *) wkt->read(p_polyStr); + delete wkt; + } + + + //! Initializes for writing polygon to cube blob + void ImagePolygon::WriteInit() { + geos::io::WKTWriter *wkt = new geos::io::WKTWriter(); + + // Check to see p_polygons is valid data + if(!p_polygons) { + string msg = "Cannot write a NULL polygon!"; + throw Isis::iException::Message(iException::Programmer, msg, _FILEINFO_); + } + p_polyStr = wkt->write(p_polygons); + p_nbytes = p_polyStr.size(); + + delete wkt; + } + + + /** + * Writes polygon to cube blob + * + * @param[in] os (std::fstream &) Output steam blob data will be written to + * + * @throws Isis::iException::Io - Error writing data to stream + */ + void ImagePolygon::WriteData(std::fstream &os) { + os.write(p_polyStr.c_str(), p_nbytes); + } + + + /** + * Calculates the distance squared between two coordinates. + * + * @param p1 The first Coordinate for the calculation + * @param p2 The second Coordinate for the calculation + * + * return The distance squared between the Coordinates + */ + double ImagePolygon::DistanceSquared(const geos::geom::Coordinate *p1, const geos::geom::Coordinate *p2) { + return ((p2->x - p1->x) * (p2->x - p1->x)) + ((p2->y - p1->y) * (p2->y - p1->y)); + } + + + /** + * Returns True when the input image is a limb image + * + * @return bool True if any of the 4 corners of the input image cannot be set + */ + bool ImagePolygon::IsLimb() { + bool hasFourCorners = true; + hasFourCorners &= SetImage(1, 1); + hasFourCorners &= SetImage(p_cubeSamps, 1); + hasFourCorners &= SetImage(p_cubeSamps, p_cubeLines); + hasFourCorners &= SetImage(1, p_cubeLines); + return !hasFourCorners; + } + + + + /** + * While walking the image in sample/line space, this function finds the best + * valid point between the first valid point found and the last point which + * failed its validity test using a linear search. + * + * @param currentPoint The last point added to the polygon + * @param newPoint The first valid point found for the next step. + * @param lastPoint The last point that was found to be invalid which checking + * for the next step. + * + * @return geos::geom::Coordinate The valid point found via searching between + * the provided points. + */ + geos::geom::Coordinate ImagePolygon::FindBestPoint(geos::geom::Coordinate *currentPoint, + geos::geom::Coordinate newPoint, + geos::geom::Coordinate lastPoint) { + geos::geom::Coordinate result = newPoint; + // Use a binary search to snap to the limb when needed + if(p_sampinc > 1 || p_lineinc > 1) { + + // Pull the invalid point back inside the image + double x = lastPoint.x; + double y = lastPoint.y; + if(x < p_cubeStartSamp) { + x = p_cubeStartSamp; + } + else if(x > p_cubeSamps) { + x = p_cubeSamps; + } + if(y < p_cubeStartLine) { + y = p_cubeStartLine; + } + else if(y > p_cubeLines) { + y = p_cubeLines; + } + geos::geom::Coordinate invalid(x, y); + geos::geom::Coordinate valid(result.x, result.y); + + // Find the best valid Coordinate + while(!SetImage(invalid.x, invalid.y)) { + int x, y; + if(invalid.x > valid.x) { + x = (int)invalid.x - 1; + } + else if(invalid.x < valid.x) { + x = (int)invalid.x + 1; + } + else { + x = (int)invalid.x; + } + if(invalid.y > valid.y) { + y = (int)invalid.y - 1; + } + else if(invalid.y < valid.y) { + y = (int)invalid.y + 1; + } + else { + y = (int)invalid.y; + } + invalid = geos::geom::Coordinate(x, y); + } + + result = FixCornerSkip(currentPoint, invalid); + } + + return result; + } + + + /** + * Looks at the next possible point relative to the lasts and attempts to adjust + * the point outward to grab valid corner data. + * + * @param currentPoint The last valid point added to the polygon + * @param newPoint The new point to be added to the polygon + * + * @return geos::geom::Coordinate The new point modified for a better result + */ + geos::geom::Coordinate ImagePolygon::FixCornerSkip(geos::geom::Coordinate *currentPoint, + geos::geom::Coordinate newPoint) { + geos::geom::Coordinate originalPoint = newPoint; + geos::geom::Coordinate modPoint = newPoint; + + // Step Too big + if(p_sampinc > p_cubeSamps || p_lineinc > p_cubeLines) { + return newPoint; + } + + // An upper left corner + else if(currentPoint->x < newPoint.x && currentPoint->y > newPoint.y) { + while(newPoint.x >= currentPoint->x && SetImage(newPoint.x, newPoint.y)) { + modPoint = newPoint; + newPoint.x -= 1; + } + } + + // An upper right corner + else if(currentPoint->y < newPoint.y && currentPoint->x < newPoint.x) { + while(newPoint.y >= currentPoint->y && SetImage(newPoint.x, newPoint.y)) { + modPoint = newPoint; + newPoint.y -= 1; + } + } + + // An lower right corner + else if(currentPoint->x > newPoint.x && currentPoint->y < newPoint.y) { + while(newPoint.x <= currentPoint->x && SetImage(newPoint.x, newPoint.y)) { + modPoint = newPoint; + newPoint.x += 1; + } + } + + // An lower left corner + else if(currentPoint->y > newPoint.y && currentPoint->x > newPoint.x) { + while(newPoint.y <= currentPoint->y && SetImage(newPoint.x, newPoint.y)) { + modPoint = newPoint; + newPoint.y += 1; + } + } + + if(currentPoint->x == modPoint.x && currentPoint->y == modPoint.y) { + return originalPoint; + } + return modPoint; + } + + + /** + * Takes p_polygons in sample/line space and finds its subpixel accuracy. This + * algorithm depends on a left-hand-turn algorithm and assumes that the vector + * of Coordinates provided is not empty. + * + * @param points The vector of Coordinate to set to subpixel accuracy + */ + void ImagePolygon::FindSubpixel(std::vector & points) { + if(p_subpixelAccuracy > 0) { + + // Fix the polygon with subpixel accuracy + geos::geom::Coordinate old = points.at(0); + bool didStartingPoint = false; + for(unsigned int pt = 1; !didStartingPoint; pt ++) { + if(pt >= points.size() - 1) { + pt = 0; + didStartingPoint = true; + } + + // Binary Coordinate Search + double maxStep = std::max(p_sampinc, p_lineinc); + double stepY = (old.x - points.at(pt + 1).x) / maxStep; + double stepX = (points.at(pt + 1).y - old.y) / maxStep; + + geos::geom::Coordinate valid = points.at(pt); + geos::geom::Coordinate invalid(valid.x + stepX, valid.y + stepY); + + for(int itt = 0; itt < p_subpixelAccuracy; itt ++) { + geos::geom::Coordinate half((valid.x + invalid.x) / 2.0, (valid.y + invalid.y) / 2.0); + if(SetImage(half.x, half.y) && InsideImage(half.x, half.y)) { + valid = half; + } + else { + invalid = half; + } + } + + old = points.at(pt); + + // Set new coordinate + points[pt] = valid; + + } + + // Fix starting point + points[points.size()-1] = geos::geom::Coordinate(points[0].x, points[0].y); + + } + } + + +} // end namespace isis + diff --git a/isis/src/base/objs/ImagePolygon/ImagePolygon.h b/isis/src/base/objs/ImagePolygon/ImagePolygon.h new file mode 100644 index 0000000000000000000000000000000000000000..06d2ed03e79ac76c3c8b48c6be81dd1142155928 --- /dev/null +++ b/isis/src/base/objs/ImagePolygon/ImagePolygon.h @@ -0,0 +1,271 @@ +#ifndef ImagePolygon_h +#define ImagePolygon_h +/** + * @file + * $Revision: 1.33 $ + * $Date: 2010/05/14 19:17:43 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "iException.h" +#include "Cube.h" +#include "Brick.h" +#include "Camera.h" +#include "Projection.h" +#include "UniversalGroundMap.h" +#include "Blob.h" +#include "geos/geom/Coordinate.h" +#include "geos/geom/MultiPolygon.h" +#include "geos/geom/CoordinateSequence.h" + +namespace Isis { + + /** + * @brief Create cube polygons, read/write polygons to blobs + * + * This class creates polygons defining an image boundary, reads + * the polygon from a cube blob, and writes a polygon to a cube + * blob. The GEOS (Geometry Engine Open Source) package is used + * to create and manipulate the polygons. See + * http://geos.refractions.net for information about this + * package. + * + * @ingroup Registration + * + * @author 2005-11-22 Tracie Sucharski + * + * @internal + * + * @history 2006-05-17 Stuart Sides Renamed from PolygonTools and moved the + * geos::GeometryFactory to the new PolygonTools + * @history 2007-01-04 Tracie Sucharski, Fixed bug in Fix360Poly, on + * non-pole images after splitting at the 360 boundary, + * wasn't insuring that start and end points of polygon were + * the same. + * @history 2007-01-05 Tracie Sucharski, Made a change to the SetImage + * method. Cannot make the assumption that if a sample/line + * returns a lat/lon, that the lat/lon will return a sample/line. + * This was found using a Moc WA, global image, sample 1, line 1 + * returned a lat/lon, but entering that lat/lon does not return a + * valid sample/line. + * @history 2007-01-08 Tracie Sucharski, Fixed bugs in the ToImage and + * ToGround class for images that contain a pole. + * + * @history 2007-01-19 Tracie Sucharski, Comment out the ToGround method. + * + * @history 2007-01-31 Tracie Sucharski, Add WKT method to return WKT polygon + * as a string. + * @history 2007-02-06 Tracie Sucharski, Added band parameter to Create + * method and call UniversalGroundMap::SetBand. + * @history 2007-05-04 Robert Sucharski, with Jeff, Stuart, and + * Tracie's blessing, moved the WKT method to the + * PolygonTools class. + * @history 2007-07-26 Tracie Sucharski, Added ss,sl,ns,nl to constructor + * for sub-poly creation. + * @history 2007-11-09 Tracie Sucharski, Remove WKT method since the geos + * package know has a method to return a WKT + * string + * @history 2008-03-17 Tracie Sucharski, Added try/catch block to Create + * and Fix360Poly to catch geos exceptions. + * + * @history 2008-06-18 Stuart Sides - Fixed doc error + * @history 2008-08-18 Steven Lambright - Updated to work with geos3.0.0 + * instead of geos2. Mostly namespace changes. + * @history 2008-12-10 Steven Koechle - Split pole code into seperate function, + * chanded the way FixPoly360 did its intersection to handle a + * multipolygon being returned. + * @history 2008-12-10 Steven Lambright - Fixed logical problem which could + * happen when the limb of the planet was on the left and was the + * first thing found in the FindPoly method. + * @history 2009-01-06 Steven Koechle - Changed Constructor, removed backwards + * compatibility for footprint name. + * @history 2009-01-28 Steven Lambright - Fixed memory leaks + * @history 2009-02-20 Steven Koechle - Fixed Fix360Poly to use the + * PolygonTools Intersect method. + * @history 2009-04-17 Steven Koechle - Rewrote most of the class. Implemented + * a left-hand rule AI walking algotithm in the walkpoly method. Pole + * and 360 boundary logic was more integrated and simplified. Method + * of finding the first point was seperated into its own method. + * @history 2009-05-06 Steven Koechle - Fixed Error where a NULL polygon was + * being written. + * @history 2009-05-28 Steven Lambright - This program will no longer generate + * invalid polygons and should use despike as a correction algorithm + * if it is necessary. + * @history 2009-05-28 Stuart Sides - Added a new argument to Create for + * controling the quality of the polygon. + * @history 2009-05-28 Steven Lambright - Moved the quality parameter in the + * argument list, improved speed and the edges of files (and subareas) + * should be checked if the algorithm reaches them now. Fixed the + * sub-area capabilities. + * @history 2009-06-16 Christopher Austin - Fixed WalkPoly() to catch large + * pixel increments that ( though snapping ) skip over the starting + * point. Also skip the first left turn in FindNextPoint() to prevent + * double point checking as well as errors with snapping. + * @history 2009-06-17 Christopher Austin - Removed p_name. Uses parent Name() + * @history 2009-06-18 Christopher Austin - Changes starting point skipping + * solution to a snap. Added fix for polygons that form + * self-intersecting polygons due to this first point snapping. + * @history 2009-06-19 Christopher Austin - Temporarily reverted for backport, + * fixed truthdata for SpiceRotation, re-commited with all updates + * @history 2009-07-01 Christopher Austin - Added Emission and Phase Angle + * tolerences. + * @history 2009-07-09 Christopher Austin - Fixed range error in FixPolePoly() + * when no points cross, an overflow exception, as well as emission + * and incidence handling of poles. + * @history 2009-07-21 Christopher Austin - Added limb snapping along with + * internal corner searching. Fixed lat/lon crossing when samp/line + * does not cross. Removed the SetUniversalGround call in SetImage(). + * Limbs are now detected and handled using an ellipsoid shape model + * if p_ellipsoid is true. + * @history 2009-07-28 Christopher Austin - Changed qualitiy increment to + * sample/line increment to remove unnecessary points from the + * polygon. + * @history 2009-08-05 Christopher Austin - Added pole meridian proper polygon + * division. + * @history 2009-08-20 Christopher Austin - Added meridian walking and subpixel + * accuracy. + * @history 2009-08-28 Christopher Austin - Fixed a memory bounds error. + * @history 2010-02-08 Christopher Austin - Fixed an infinite loop which + * revisited the starting point, and added 360 meridian crossing + * @history 2010-02-17 Christopher Austin - Fixed two more infinite looping + * issues, including a cycle fix which occured during Emission Angle + * and Incidence Angle restrictions + */ + + class ImagePolygon : public Isis::Blob { + + public: + ImagePolygon(); + ~ImagePolygon(); + + void Create(Cube &cube, int sampinc = 1, int lineinc = 1, + int ss = 1, int sl = 1, int ns = 0, int nl = 0, int band = 1); + + /** + * Set the maximum emission angle ( light refleted to camera ) + * + * @param emission The maximum valid emission angle + */ + void Emission(double emission) { + p_emission = emission; + } + /** + * Set the maximum incidence angle ( light contacting the planet ) + * + * @param incidence The maximum valid incidence angle + */ + void Incidence(double incidence) { + p_incidence = incidence; + } + + /** + * If a limb is detected, use un ellipsoid shape model if true. If false, + * use the default (spiceinit defined) shape model. + * + * @param ellip True to use ellipsoid on limb images + */ + void EllipsoidLimb(bool ellip) { + p_ellipsoid = ellip; + } + + /** + * The subpixel accuracy to use. This accuracy is the number of binary steps to + * take to find the subpixel accuracy. A higher number provided gives more + * accurate results at the cost of runtime. + * + * ImagePolygon's constructor sets a default value of 50 + * + * @param div The subpixel accuracy to use + */ + void SubpixelAccuracy(int div) { + p_subpixelAccuracy = div; + } + + //! Return a geos Multipolygon + geos::geom::MultiPolygon *Polys() { + return p_polygons; + }; + + protected: + void ReadData(std::istream &is); + void WriteInit(); + void WriteData(std::fstream &os); + + private: + // Please do not add new polygon manipulation methods to this class. + // Polygon manipulation should be done in the PolygonTools class. + bool SetImage(const double sample, const double line); + + geos::geom::Coordinate FindFirstPoint(); + void WalkPoly(); + geos::geom::Coordinate FindNextPoint(geos::geom::Coordinate *currentPoint, + geos::geom::Coordinate lastPoint, + int recursionDepth = 0); + + double DistanceSquared(const geos::geom::Coordinate *p1, const geos::geom::Coordinate *p2); + + void MoveBackInsideImage(double &sample, double &line, double sinc, double linc); + bool InsideImage(double sample, double line); + void Fix360Poly(); + void FixPolePoly(std::vector *crossingPoints); + + bool IsLimb(); + geos::geom::Coordinate FindBestPoint(geos::geom::Coordinate *currentPoint, + geos::geom::Coordinate newPoint, + geos::geom::Coordinate lastPoint); + geos::geom::Coordinate FixCornerSkip(geos::geom::Coordinate *currentPoint, + geos::geom::Coordinate newPoint); + + void FindSubpixel(std::vector & points); + + Cube *p_cube; //!< The cube provided + bool p_isProjected; //!< True when the provided cube is projected + + Brick *p_brick; //!< Used to check for valid DNs + + geos::geom::CoordinateSequence *p_pts; //!< The sequence of coordinates that compose the boundry of the image + + geos::geom::MultiPolygon *p_polygons; //!< The multipolygon of the image + + std::string p_polyStr; //!< The string representation of the polygon + + UniversalGroundMap *p_gMap; //!< The cube's ground map + + int p_cubeStartSamp; //!< The the sample of the first valid point in the cube + int p_cubeStartLine; //!< The the line of the first valid point in the cube + int p_cubeSamps; //!< The number of samples in the cube + int p_cubeLines; //!< The number of lines in the cube + + int p_sampinc; //!< The increment for walking along the polygon in the sample direction + int p_lineinc; //!< The increment for walking along the polygon in the line direcction + + double p_emission; //!< The maximum emission angle to consider valid + double p_incidence; //!< The maximum incidence angle to consider valid + bool p_ellipsoid; //!< Uses an ellipsoid if a limb is detected + + int p_subpixelAccuracy; //!< The subpixel accuracy to use + + }; +}; + +#endif + diff --git a/isis/src/base/objs/ImagePolygon/ImagePolygon.truth b/isis/src/base/objs/ImagePolygon/ImagePolygon.truth new file mode 100644 index 0000000000000000000000000000000000000000..8523462ea1a35a311c4091cf9b86db363898aa9e --- /dev/null +++ b/isis/src/base/objs/ImagePolygon/ImagePolygon.truth @@ -0,0 +1,3 @@ +MULTIPOLYGON (((223.8172826870554388 34.4551387030861491, 223.8417027793910279 34.4596506066820112, 223.8575436553176701 34.4592772202857844, 223.8731987947955702 34.4589061403268389, 223.8888001595454966 34.4585342458576349, 223.9044019981010649 34.4581602382883219, 223.9200661671754347 34.4577826049052831, 223.9355075424467429 34.4574083328668834, 223.9508457646257682 34.4570345511811595, 223.9660146266157881 34.4566629441688406, 223.9810473116613707 34.4562927476240120, 223.9957878473876747 34.4559279256362956, 224.0106582442351453 34.4555579476699165, 224.0255459276724821 34.4551856180930614, 224.0403444766045311 34.4548136399185410, 224.0550707902558543 34.4544416140812260, 224.0696826278450544 34.4540706528633081, 224.0842130299532755 34.4536999451661856, 224.0986612451088149 34.4533295402476796, 224.1130364689869623 34.4529592283796191, 224.1273202299933018 34.4525895194552731, 224.1415662443043573 34.4522190340582313, 224.1557339918608704 34.4518488559867606, 224.1698107918541609 34.4514793494806284, 224.1838116920665982 34.4511101458139208, 224.1977227034556961 34.4507416459917692, 224.2115924901468702 34.4503725738795836, 224.2254006440637681 34.4500034947196099, 224.2391929104324504 34.4496331904990001, 224.2529511041107355 34.4492621618858976, 224.2666975062502672 34.4488898121368337, 224.2803860065775439 34.4485174107728724, 224.2940079847231800 34.4481452153055372, 224.3075938798835978 34.4477724066462869, 224.3210795841726224 34.4474007776905964, 224.3344990942370032 34.4470294144046818, 224.3478450164772369 34.4466585461289370, 224.3611125161780251 34.4462883334162839, 224.3742955932223424 34.4459189716523113, 224.3874260849249538 34.4455495872321151, 224.4004958875964064 34.4451804279779594, 224.4135260618142524 34.4448109130245967, 224.4264828608789912 34.4444420219817644, 224.4393721008836167 34.4440736115621888, 224.4522012232876591 34.4437054889999104, 224.4649910968735753 34.4433370695209504, 224.4777393619483519 34.4429684345123448, 224.4904489206230380 34.4425995128584503, 224.5030718093267126 34.4422317208438145, 224.5156259768878328 34.4418645587055465, 224.5281770921911857 34.4414961127534696, 224.5407219882328320 34.4411264780584858, 224.5531975742495661 34.4407575293592743, 224.5656264624743699 34.4403886150134326, 224.5780227094808765 34.4400193297392221, 224.5903757296815400 34.4396500013147318, 224.6026728254119291 34.4392810252896382, 224.6148668913133122 34.4389138407199553, 224.6269709753682093 34.4385480837916376, 224.6390599334172578 34.4381815076602962, 224.6511372139618175 34.4378140121817182, 224.6632067785040476 34.4374454801668293, 224.6751614661697261 34.4370792014152798, 224.6870933909598023 34.4367123756374625, 224.6989898632547238 34.4363454016597004, 224.7108678965473416 34.4359777634713211, 224.7226881483722991 34.4356106889183167, 224.7344958302550708 34.4352427865472563, 224.7462652761358015 34.4348748626036780, 224.7579793002169026 34.4345074672970526, 224.7696431367291439 34.4341404523806460, 224.7812728007805561 34.4337733275598907, 224.7928435543977344 34.4334068854894113, 224.8043847867216130 34.4330402109262153, 224.8157283419619716 34.4326786627865005, 224.8270886232841690 34.4323154551120965, 224.8384166745431685 34.4319521503576169, 224.8497524406567720 34.4315874760106411, 224.8610108250075541 34.4312241690653664, 224.8722867697038623 34.4308591870978660, 224.8835699922025810 34.4304928586050210, 224.8948651191152521 34.4301250319575658, 224.9061662755833879 34.4297558956339884, 224.9173542816715781 34.4293893381866098, 224.9284086365155417 34.4290260616187993, 224.9394220907865360 34.4286630586182127, 224.9504388176640077 34.4282988871562736, 224.9614347391278102 34.4279343412270009, 224.9724090215291596 34.4275694544292463, 224.9833614191804259 34.4272042411422490, 224.9942931924667278 34.4268386657352323, 225.0052127357933216 34.4264724542664169, 225.0161268911519983 34.4261053817509719, 225.0270072241578134 34.4257384031269211, 225.0379099782836647 34.4253696378408165, 225.0487812548770989 34.4250008963959786, 225.0595876459126430 34.4246333158877320, 225.0703030756958185 34.4242677965401143, 225.0809691073864656 34.4239029512769363, 225.0916138569805582 34.4235378364048117, 225.1022391575891959 34.4231723953056203, 225.1128542317258336 34.4228063180293233, 225.1234516167740765 34.4224398635157556, 225.1340217161871919 34.4220733665334180, 225.1445720848678889 34.4217065741965840, 225.1551012336083772 34.4213395433927403, 225.1655864785901997 34.4209730651206414, 225.1760248993641085 34.4206072521104787, 225.1864409930022077 34.4202412644615379, 225.1968389824640724 34.4198749609670074, 225.2072200098035353 34.4195083066778125, 225.2175785697109234 34.4191414990643736, 225.2279161215415968 34.4187744928887298, 225.2382328071077211 34.4184072887788659, 225.2485261485682315 34.4180399796766565, 225.2587970262709973 34.4176725406107664, 225.2690410352409742 34.4173051335255948, 225.2792535965254217 34.4169379279162868, 225.2894249396076418 34.4165712794060497, 225.2995612323753960 34.4162049783027371, 225.3096797795340080 34.4158384149443748, 225.3197769941242257 34.4154717224572408, 225.3298508715159585 34.4151049782719625, 225.3399032249868128 34.4147381230933931, 225.3499338576569073 34.4143711695009245, 225.3599442461228932 34.4140040696646849, 225.3699387631349111 34.4136366704509342, 225.3799126564553319 34.4132691483703610, 225.3898592055629706 34.4129017528991028, 225.3997746327033838 34.4125346283236553, 225.4096413759663164 34.4121684231094349, 225.4194664480515655 34.4118028921399457, 225.4292333250850220 34.4114386506334142, 225.4389847119238937 34.4110741438094863, 225.4487227950546355 34.4107092950618707, 225.4584529700451867 34.4103439088415755, 225.4681791118237868 34.4099778441967459, 225.4779501834397308 34.4096092904921065, 225.4877658689309783 34.4092382501921250, 225.4975606253910314 34.4088671491674702, 225.5073160520562396 34.4084966774081309, 225.5170945589489975 34.4081245163349578, 225.5268331233620245 34.4077530164326788, 225.5365021994056747 34.4073832928032175, 225.5461190551147297 34.4070147129218213, 225.5556995064936814 34.4066466938671667, 225.5652214497690409 34.4062800756482829, 225.5747432098429783 34.4059126712269006, 225.5842560908538417 34.4055448095740175, 225.5937778006128553 34.4051758227699196, 225.6033009157918059 34.4048059909125215, 225.6128238278373033 34.4044353752724277, 225.6223471750254532 34.4040639520834688, 225.6318758783412477 34.4036915342067431, 225.6414016415699280 34.4033184378166581, 225.6509363628046003 34.4029442090107551, 225.6604947562084647 34.4025682829215427, 225.6700415056936606 34.4021920106849635, 225.6795791566649996 34.4018152973413507, 225.6890709330758114 34.4014395611739303, 225.6985268750812850 34.4010644243483270, 225.7079299361909932 34.4006905526265498, 225.7172925180968832 34.4003174765961646, 225.7266351872193013 34.3999444072982925, 225.7359624913239884 34.3995711723548609, 225.7452560214270534 34.3991984905109618, 225.7545267975710601 34.3988259392688747, 225.7637889836344414 34.3984529709160256, 225.7730507645073317 34.3980792678529141, 225.7823252012635180 34.3977043199699821, 225.7916004169035205 34.3973285906499058, 225.8008725342959622 34.3969522323247858, 225.8101369195184134 34.3965754280254501, 225.8193892451850218 34.3961983497526589, 225.8286274988493858 34.3958210792869465, 225.8378496687657275 34.3954436987810084, 225.8470551995606286 34.3950662332777384, 225.8562326011004018 34.3946891400830452, 225.8653930029058472 34.3943119835577278, 225.8745410760741379 34.3939345816838795, 225.8836776373499617 34.3935569043987428, 225.8928019411091839 34.3931789835027715, 225.9019194640785599 34.3928006034879772, 225.9110308751989749 34.3924217392180083, 225.9201549499623809 34.3920416439267100, 225.9292743320435477 34.3916610090137027, 225.9383845714556003 34.3912800134750256, 225.9474795314178550 34.3908989044373357, 225.9565581779352499 34.3905177257819048, 225.9656244992437450 34.3901363203602273, 225.9746802477525875 34.3897546199894251, 225.9837284337445169 34.3893725057496198, 225.9927658599887081 34.3889901074684872, 226.0017891753058166 34.3886075615055375, 226.0108161763018302 34.3882241545240106, 226.0198457173550253 34.3878399331655515, 226.0288659304852672 34.3874553757630252, 226.0378750537378778 34.3870705548477034, 226.0468586590083930 34.3866860531593659, 226.0558323074971554 34.3863012459153055, 226.0647969809047027 34.3859160948656566, 226.0737494779210124 34.3855307302515385, 226.0826909505214530 34.3851451068040603, 226.0916392243316864 34.3847585069560395, 226.1005846293875834 34.3843713215449966, 226.1095237944467726 34.3839836875571763, 226.1184552396198910 34.3835956656762889, 226.1273766599849182 34.3832073496778676, 226.1362843513687437 34.3828188893592923, 226.1451789838363595 34.3824302579892915, 226.1540696341189687 34.3820410907882916, 226.1629557016454157 34.3816514125989272, 226.1718415645501068 34.3812610485457881, 226.1807230054455999 34.3808701688271512, 226.1896010103693300 34.3804787347538792, 226.1984731024690234 34.3800868460323059, 226.2073393250070410 34.3796945012310715, 226.2162010894380444 34.3793016444903685, 226.2250584402766265 34.3789082745362009, 226.2339210610063560 34.3785140099351949, 226.2427791039827127 34.3781192423319908, 226.2516314343283170 34.3777240168995561, 226.2604782195339226 34.3773283272095398, 226.2693193564055321 34.3769321772336838, 226.2781549132746193 34.3765355639964483, 226.2869854330353121 34.3761384661654006, 226.2958114626155748 34.3757408625676888, 226.3046334835679545 34.3753427349446667, 226.3134536502138019 34.3749440038212271, 226.3222666039530395 34.3745448675868772, 226.3310674200903350 34.3741454965105504, 226.3398662973730779 34.3737455139907979, 226.3486632146650379 34.3733449207269217, 226.3574580470379658 34.3729437205966306, 226.3662507195154205 34.3725419149321496, 226.3750416931271161 34.3721394877984991, 226.3838307521521074 34.3717364446175608, 226.3926183115015363 34.3713327721326252, 226.4014042158760844 34.3709284729463391, 226.4101886820603227 34.3705235397049265, 226.4189713667341266 34.3701179688710852, 226.4277528949788518 34.3697117359899522, 226.4365339441874028 34.3693048460954742, 226.4453141371841980 34.3688973009585865, 226.4540932758034728 34.3684891262239631, 226.4628714412388035 34.3680802909390195, 226.4716492125770628 34.3676707554958369, 226.4804266127447647 34.3672605340832646, 226.4892039200612430 34.3668496114386883, 226.4979812270886441 34.3664379860401468, 226.5067586403042696 34.3660256539005715, 226.5155350783788037 34.3656126841276048, 226.5243113274158588 34.3651990254046851, 226.5330863836773290 34.3647847378262838, 226.5418613931196887 34.3643697520982840, 226.5506364357558766 34.3639540648018951, 226.5594125115484587 34.3635376201859799, 226.5681899791629235 34.3631204005482616, 226.5769703953518786 34.3627023214856777, 226.5857530174790213 34.3622834276467799, 226.5945393457379566 34.3618636384960254, 226.6033280976941739 34.3614430267662812, 226.6121204829055102 34.3610215277182292, 226.6209149844707156 34.3605992248942727, 226.6297112468444084 34.3601761375813552, 226.6385086581271366 34.3597522984601511, 226.6473076484998614 34.3593276840231567, 226.6561088518905933 34.3589022601831786, 226.6649128221872047 34.3584759974264813, 226.6737198569121006 34.3580488800412880, 226.6825293890375974 34.3576209381841053, 226.6913400811723420 34.3571922425097114, 226.7001540295673578 34.3567626816807206, 226.7089712049645414 34.3563322571851657, 226.7177870375159330 34.3559012099767713, 226.7266041828078187 34.3554693992389133, 226.7354247297398331 34.3550367145667792, 226.7442492611458533 34.3546031251241786, 226.7530788598978972 34.3541685737675522, 226.7619128745805881 34.3537330945820614, 226.7707514832060269 34.3532966779085598, 226.7795960290009418 34.3528592527794885, 226.7884459906872507 34.3524208461995855, 226.7973003349381997 34.3519815119965344, 226.8061593642061098 34.3515412337322488, 226.8150233317537925 34.3510999975136926, 226.8238934698196942 34.3506577379326501, 226.8327720567338872 34.3502143344743303, 226.8416573813208856 34.3497698762915888, 226.8505497655341401 34.3493243455891317, 226.8594358490680065 34.3488784447268642, 226.8683250410213361 34.3484316781252730, 226.8772265484987827 34.3479835600551269, 226.8861363120287820 34.3475343031321501, 226.8950567593712151 34.3470837781792824, 226.9039829499012342 34.3466322445209400, 226.9129146680944871 34.3461797125383654, 226.9218556874094190 34.3457259818489007, 226.9308045477948497 34.3452711282402134, 226.9397756292526935 34.3448143895302991, 226.9487603184134912 34.3443562188081657, 226.9577713539455033 34.3438959389133061, 226.9667906962734207 34.3434345027779884, 226.9758185915864317 34.3429718957263219, 226.9848216200828404 34.3425098913908897, 226.9938252716434022 34.3420471374260501, 227.0028484628032004 34.3415826267594184, 227.0118809439680376 34.3411169021389355, 227.0209235817709157 34.3406499156234659, 227.0299791780944361 34.3401815158194594, 227.0390478252961657 34.3397116954514985, 227.0481467096626034 34.3392395333766132, 227.0572602651047589 34.3387658574176626, 227.0663771858033613 34.3382912703767857, 227.0755008947110412 34.3378155877346103, 227.0846303913073996 34.3373388616534214, 227.0937637964039482 34.3368611917210984, 227.1029086135041553 34.3363821733254184, 227.1120687985143718 34.3359015911654311, 227.1212359111418095 34.3354198971172906, 227.1304019305065083 34.3349375223436439, 227.1395758196006227 34.3344539825447796, 227.1487597349276939 34.3339691593657577, 227.1579902583264072 34.3334810704758411, 227.1672328061905830 34.3329915812163335, 227.1764712676953764 34.3325015630313359, 227.1857181919765196 34.3320103346922068, 227.1949746843040998 34.3315178341563865, 227.2042427831847817 34.3310239482966324, 227.2135235122841266 34.3305286187725329, 227.2228146140698470 34.3300319660012079, 227.2321158182128897 34.3295340024028164, 227.2414261879402773 34.3290347769038107, 227.2507440105588898 34.3285343811480175, 227.2600744088126987 34.3280325324944187, 227.2694283383975744 34.3275286268106896, 227.2787965981403033 34.3270231647175663, 227.2881796631106397 34.3265161168639992, 227.2975768164326098 34.3260075194109362, 227.3069878365900536 34.3254973813716262, 227.3164104609731453 34.3249858245099446, 227.3258502854863821 34.3244725367080221, 227.3353080996716926 34.3239574703682919, 227.3447883387066213 34.3234403755929947, 227.3542849111706516 34.3229215853954273, 227.3637955610474251 34.3224012213397032, 227.3733236581833523 34.3218790926137274, 227.3828696239687872 34.3213551716832939, 227.3924291244552194 34.3208296960990751, 227.4020038477916899 34.3203025683132310, 227.4115915765664226 34.3197739086688429, 227.4211903006604985 34.3192438265212729, 227.4308034100351392 34.3187121290632149, 227.4404322668985969 34.3181787363226363, 227.4500783315635317 34.3176435624042711, 227.4597408211544121 34.3171066472117161, 227.4694373999262780 34.3165669913512446, 227.4791525994612869 34.3160254597000716, 227.4888678788144887 34.3154830952473375, 227.4985957069042399 34.3149391921614466, 227.5083373853138085 34.3143936735035808, 227.5181018062715737 34.3138460313880955, 227.5278825759429537 34.3132966234387382, 227.5376789842295011 34.3127454859353236, 227.5475028125167398 34.3121919440087666, 227.5573500149448023 34.3116362217108133, 227.5672257339052180 34.3110780196529035, 227.5771363516663541 34.3105169659525373, 227.5870780116667618 34.3099532729218311, 227.5970431329253074 34.3093873675369281, 227.6070304509327684 34.3088193164755495, 227.6170402145462788 34.3082490997872682, 227.6270614888811394 34.3076773412008720, 227.6371021487410076 34.3071035836203393, 227.6471620472045458 34.3065278304867363, 227.6572333482910437 34.3059505296988263, 227.6673250879570389 34.3053711550848135, 227.6774425887975610 34.3047893928164669, 227.6875956283761582 34.3042046687850117, 227.6977747165031190 34.3036175255403180, 227.7079695685462184 34.3030285548813652, 227.7181855113298639 34.3024374420603024, 227.7284236548779006 34.3018441166910293, 227.7386810962439654 34.3012487425372896, 227.7489607488712977 34.3006511438889916, 227.7592652945483849 34.3000511576431748, 227.7696049562804603 34.2994481772121489, 227.7799661327425724 34.2988429927923519, 227.7903495499146516 34.2982355558256558, 227.8007531420874443 34.2976259820286913, 227.8111804588932330 34.2970140563683188, 227.8216354765219762 34.2963995373976758, 227.8321461589635533 34.2957807625226039, 227.8426781272081598 34.2951597549059954, 227.8532313530564579 34.2945365103118789, 227.8637943594835917 34.2939117050406495, 227.8743681842870785 34.2932852743100582, 227.8849595330412967 34.2926568151128990, 227.8955699765630243 34.2920262286820261, 227.9062407193817990 34.2913910462529685, 227.9169476338818185 34.2907526962728753, 227.9276713907391354 34.2901123277707356, 227.9383745218270860 34.2894721855654012, 227.9490646281740283 34.2888318174488589, 227.9597329801610215 34.2881917519580597, 227.9704830712439048 34.2875457532931378, 227.9813063056426188 34.2868943187016697, 227.9922004455596038 34.2862375637549448, 228.0031311318133760 34.2855775502002231, 228.0140933799731044 34.2849145701223819, 228.0250913628472631 34.2842483610777151, 228.0361342648420191 34.2835783542064405, 228.0472235719963976 34.2829044463308890, 228.0583488204560183 34.2822272628250673, 228.0695055535578035 34.2815470657209858, 228.0806796288569274 34.2808647114042699, 228.0918858625025791 34.2801792865075754, 228.1031233132273712 34.2794908394530822, 228.1143887119357885 34.2787995620820851, 228.1256453028393594 34.2781077090887152, 228.1369030524184325 34.2774146678620184, 228.1481798443663820 34.2767193332270210, 228.1595524441736416 34.2760169519050493, 228.1709717099908517 34.2753105403553633, 228.1824155794452338 34.2746014535234167, 228.1938803829937683 34.2738899119351572, 228.2054189265468267 34.2731726235595602, 228.2170280980613484 34.2724497608496677, 228.2287243266976020 34.2717202776986909, 228.2405154509019098 34.2709836584986789, 228.2523281114683300 34.2702444678746545, 228.2641942766789498 34.2695006944830070, 228.2760966165556056 34.2687534104679514, 228.2880311232885049 34.2680028567511243, 228.3000080489240418 34.2672483774467338, 228.3120073191867618 34.2664912261054937, 228.3240136615007714 34.2657323607450479, 228.3360270491550921 34.2649717804313170, 228.3480846101073780 34.2642071288155847, 228.3601573792798547 34.2634402313342505, 228.3722738818091784 34.2626692688684358, 228.3844436938970262 34.2618936178110189, 228.3966618612765558 34.2611135776316047, 228.4089824127830468 34.2603256808090606, 228.4213463879687822 34.2595336690666770, 228.4337530236520877 34.2587375774856255, 228.4462104847060004 34.2579368681707308, 228.4587268133269902 34.2571310076858282, 228.4712928807757919 34.2563205652334943, 228.4839104809788353 34.2555054090234847, 228.4966228686225236 34.2546827270764211, 228.5094182245555317 34.2538532539691261, 228.5222741771181916 34.2530184132892543, 228.5351729278072810 34.2521793410413196, 228.5481108241753248 34.2513362605627520, 228.5610933369307247 34.2504888022589995, 228.5740744626591265 34.2496399537063851, 228.5870890608425441 34.2487874359030542, 228.6001377310801956 34.2479311982219343, 228.6132200400504360 34.2470712574983480, 228.6263499085960689 34.2462066876372475, 228.6395379494453266 34.2453367741268693, 228.6528307701242682 34.2444584248850106, 228.6663763632237476 34.2435618321320945, 228.6803617216070279 34.2426345403196279, 228.6952015541801302 34.2416489116415121, 228.7105525888537727 34.2406274235319827, 228.7265499348228843 34.2395608902071729, 228.7421439706193098 34.2385190300592086, 228.7570825716228740 34.2375188386586800, 228.7710598753439228 34.2365810240280624, 228.7833530683670915 34.2357543577948604, 228.7952800700753357 34.2349509230007385, 228.8072627602488183 34.2341424759791479, 228.8196514308424128 34.2333054216225463, 228.8331287442263147 34.2323936078462410, 228.8473922131469180 34.2314270979657991, 228.8618442087490621 34.2304460497711815, 228.8763439298241451 34.2294599387118268, 228.8909482643396984 34.2284648839076837, 228.9056482136823263 34.2274614587343677, 228.9203772896302098 34.2264541587582727, 228.9351647839141037 34.2254409727997029, 228.9499300140618629 34.2244273972624740, 228.9641311146921510 34.2234505681392989, 228.9782062980468424 34.2224806099825472, 228.9925852306207048 34.2214880257807508, 229.0081810669700531 34.2204098059550574, 229.0243240483496265 34.2192917030580901, 229.0404841060924355 34.2181701533111919, 229.0561546197716325 34.2170802519520976, 229.0718159793608208 34.2159888444595595, 229.0875983321438127 34.2148868823153975, 229.1034887026832507 34.2137752211917530, 229.1195460111437399 34.2126497038870880, 229.1358158382292629 34.2115070741072032, 229.1519329161566532 34.2103728455040397, 229.1680640638790010 34.2092353650360934, 229.1841528314637060 34.2080985980235397, 229.1997352210103145 34.2069952675949907, 229.2145400585607717 34.2059447195264852, 229.2300224803216508 34.2048443142916554, 229.2467979267665044 34.2036501662420562, 229.2636965491348633 34.2024448212972416, 229.2805688058051032 34.2012388685525011, 229.2975531551136896 34.2000224457224888, 229.3153572084256666 34.1987449442457461, 229.3330755456161967 34.1974708312596221, 229.3499864414941953 34.1962519261839049, 229.3671162393675331 34.1950147939656333, 229.3845622241133242 34.1937523319198036, 229.4014568277656281 34.1925270212032331, 229.4184179979918952 34.1912944082571215, 229.4358437587445678 34.1900256223240930, 229.4537366314563656 34.1887202761169675, 229.4717783256412531 34.1874013196511797, 229.4899255387612413 34.1860718421937335, 229.5081725982472847 34.1847322093503649, 229.5265398704868574 34.1833808832578470, 229.5450922295952978 34.1820130472502939, 229.5638787832904484 34.1806250030229819, 229.5833013117678547 34.1791870290051136, 229.6027619755459170 34.1777429731368088, 229.6217226068972934 34.1763326527843674, 229.6405847438497574 34.1749265203990618, 229.6596052490852458 34.1735055273338943, 229.6788397630403722 34.1720654517922213, 229.6983584810002981 34.1706009483857613, 229.7180957279716438 34.1691167911206222, 229.7380788626514345 34.1676108188229577, 229.7584117626756210 34.1660750989131117, 229.7790969056334802 34.1645092649619926, 229.7996369176232463 34.1629506915650722, 229.8203742932615512 34.1613735311362277, 229.8416825811018498 34.1597493412739439, 229.8624957634657449 34.1581588785920331, 229.8824174025879756 34.1566326127752262, 229.9024284096595068 34.1550960778054673, 229.9235693656282535 34.1534695744186010, 229.9452549994916239 34.1517974116376379, 229.9672683739203762 34.1500959777487694, 229.9895003849197508 34.1483735025366926, 230.0115335641944796 34.1466621287872840, 230.0333871041715099 34.1449604786041903, 230.0555507514620786 34.1432306179808407, 230.0779079317051696 34.1414814475757709, 230.1005423000428038 34.1397063292869589, 230.1238833343684291 34.1378715064769835, 230.1469833844930122 34.1360508854267408, 230.1701524619105044 34.1342202325622708, 230.1934678024694563 34.1323734190311399, 230.2165682856712010 34.1305388895063047, 230.2389046257694361 34.1287602695710035, 230.2627494181147370 34.1268575757473371, 230.2877550267185711 34.1248575756020784, 230.3121994425740979 34.1228969831179683, 230.3374538174993518 34.1208664279545033, 230.3631413116128499 34.1187956310739793, 230.3880206607562116 34.1167841714593436, 230.4129740677024358 34.1147614026916131, 230.4381720996264562 34.1127134836086370, 230.4639006138211812 34.1106170798747073, 230.4899617774171361 34.1084879303946877, 230.5160751630245954 34.1063486758618453, 230.5424933623011725 34.1041786332810233, 230.5692512088523074 34.1019747430087818, 230.5962633488587983 34.0997437898786515, 230.6233712572403647 34.0974986647174276, 230.6505324126961796 34.0952428144590840, 230.6778991777003398 34.0929635734629102, 230.7056768660073374 34.0906437346523816, 230.7338743165616393 34.0882822719610203, 230.7624290256065365 34.0858841097945273, 230.7912515729211975 34.0834564851068436, 230.8203176007895934 34.0810012491227283, 230.8496066250636432 34.0785199485613006, 230.8792222279615203 34.0760036572390774, 230.9092353385915999 34.0734461133305047, 230.9394837891280190 34.0708608099390204, 230.9699110764533714 34.0682523865333948, 231.0006928671985236 34.0656056693742499, 231.0318850272019517 34.0629155853065200, 231.0635571686676144 34.0601758150416529, 231.0955368340583789 34.0574008701334989, 231.1277395308281086 34.0545978214642773, 231.1598263150311539 34.0517959464563944, 231.1923731408357128 34.0489451184199154, 231.2256091620638472 34.0460249133125785, 231.2592693972243296 34.0430580047345188, 231.2932997455176860 34.0400487929999755, 231.3276773418911603 34.0369989773430675, 231.3623788652666065 34.0339103205237095, 231.3976872584197793 34.0307573786865163, 231.4333912448704211 34.0275584578910752, 231.4693555746214315 34.0243253059693487, 231.5059110724441780 34.0210279683690260, 231.5428878342104326 34.0176812112379139, 231.5803120488249078 34.0142822697343661, 231.6182257696958402 34.0108269012199855, 231.6563923558109366 34.0073361889261321, 231.6951328869912459 34.0037805360141476, 231.7344016753486926 34.0001635696370883, 231.7741163313663151 33.9964923488039190, 231.8144687461388287 33.9927486901787077, 231.8555242505667024 33.9889258811518644, 231.8967616380454331 33.9850717164516354, 231.9384874592085453 33.9811573545970163, 231.9810031243091828 33.9771540024940606, 232.0239997222591910 33.9730898996244761, 232.0678388327741004 33.9689303372334663, 232.1123373517177697 33.9646917582200416, 232.1571892772059869 33.9604025762483772, 232.2028902909401040 33.9560149644208167, 232.2491821770346974 33.9515527435585938, 232.2960411962056355 33.9470175078809362, 232.3439306823368327 33.9423637057927863, 232.3925149926278095 33.9376227334373368, 232.4421795019375736 33.9327560903860643, 232.4923819961781533 33.9278156109878850, 232.5436698047475943 33.9227466787318050, 232.5951687842305660 33.9176343955933319, 232.6475716307096491 33.9124096239597819, 232.7012278930365596 33.9070362580221598, 232.7556828037685932 33.9015582139110379, 232.8111272810814398 33.8959551460956590, 232.8675924455159816 33.8902225111619586, 232.9251556044691256 33.8843509815862305, 232.9836292775250968 33.8783581195321943, 233.0432332674061513 33.8722199923502458, 233.1036814246760969 33.8659644314339374, 233.1655576137215462 33.8595295606769966, 233.2282972755570256 33.8529720149463031, 233.2926253692118621 33.8462144248317571, 233.3579653179138518 33.8393149568009335, 233.4238324437535823 33.8323232701533669, 233.4921199961581237 33.8250368578670901, 233.5612785481834521 33.8176174604834614, 233.6323604437994845 33.8099502308987709, 233.7049545857546491 33.8020762209202985, 233.8182991445546577 33.7896946458198784, 233.8076868009974589 33.7447711158304671, 233.7998795211175320 33.7148904495256616, 233.7932833621273119 33.6848666704869686, 233.7861879662788454 33.6548975267118138, 233.7790138732386254 33.6249371303082327, 233.7721258780049141 33.5949457573665811, 233.7653244276447140 33.5649451761957351, 233.7589504395879771 33.5348983219310384, 233.7517922485339454 33.5049370175201346, 233.7451099030573118 33.4749242024867826, 233.7380079968495465 33.4449572273965430, 233.7308913047606893 33.4150038906188911, 233.7242842861141980 33.3850066679223403, 233.7177523609356058 33.3550016102456084, 233.7105361718773793 33.3250710555783130, 233.7038713781764727 33.2950810138029354, 233.6970686629649947 33.2651062318509361, 233.6905337589382725 33.2351027782129762, 233.6840504442202189 33.2050940973791811, 233.6777241043450886 33.1750688063842745, 233.6714174242955551 33.1450417812508391, 233.6651265169321618 33.1149842339622964, 233.6589877929609713 33.0848829896515255, 233.6524321129587634 33.0548271749566851, 233.6459016739153753 33.0247690228650228, 233.6397274744219601 32.9946728445241177, 233.6329292366539221 32.9646443836585377, 233.6264198619547301 32.9345851795598108, 233.6202087451694069 32.9044942683736537, 233.6139880511333615 32.8744048430015070, 233.6079852678255975 32.8442924251869215, 233.6024480633732878 32.8141580578265177, 233.5966311951531225 32.7840805084876550, 233.5901811265881065 32.7540715696615052, 233.5840609929455809 32.7240276623760948, 233.5780234847293855 32.6939754071204050, 233.5723051528725591 32.6638894275744747, 233.5666017738128915 32.6338024224210770, 233.5607542214523278 32.6037314697343774, 233.5546837866806982 32.5736849918668483, 233.5486024506201943 32.5436402502741728, 233.5424177865809554 32.5135952203075078, 233.5365716068125153 32.4835032167910711, 233.5315060001448160 32.4533282705142625, 233.5261496479418497 32.4231850921035090, 233.5203742088707770 32.3930873794257081, 233.5147182819266618 32.3629775113514597, 233.5094845867136542 32.3328231673348014, 233.5039894605985467 32.3026974293673916, 233.4978335602601760 32.2726429029673483, 233.4931590406256134 32.2424309058476481, 233.4878027400856979 32.2122923883547898, 233.4822943077738842 32.1821707946306645, 233.4769428295691682 32.1520331688125083, 233.4715484852565339 32.1219008274845450, 233.4659832529781056 32.0917874105425440, 233.4604242299232908 32.0616740463839278, 233.4547057474827341 32.0315783749592171, 233.4493448635818140 32.0014453815873523, 233.4439538849541975 31.9713163426436822, 233.4388438489372675 31.9411582034324582, 233.4333516271450435 31.9110653070441082, 233.4279989231125114 31.8809809552748860, 233.4229566390458501 31.8508644672415961, 233.4183811248644531 31.8206993019833142, 233.4138877626305373 31.7905263247609824, 233.4092102827142980 31.7603737819017198, 233.4050516566460942 31.7301671582915539, 233.4001074317153552 31.7000447186518208, 233.3957145715358479 31.6698647915971421, 233.3913100753762819 31.6396870518093642, 233.3864447837853504 31.6095336382647432, 233.3812875214192673 31.5793879738905119, 233.3764952550197904 31.5492046024446289, 233.3713681256496670 31.5190575396906105, 233.3665069083577919 31.4888832848857305, 233.3615529342137052 31.4587197535848766, 233.3563206750544055 31.4285865290605066, 233.3514797003734316 31.3984129292956951, 233.3465577546590453 31.3682488232810641, 233.3417228713095142 31.3380764927870743, 233.3370904021178944 31.3078918587356796, 233.3327447691412999 31.2776856492184727, 233.3284034057362533 31.2474800412854812, 233.3238447530990811 31.2172983697557100, 233.3202001870982656 31.1870215346005537, 233.3161949179906856 31.1567837769810723, 233.3117460132445729 31.1265937910656625, 233.3074302664846300 31.0963908863597460, 233.3031004202551912 31.0661905619150076, 233.2993877463872536 31.0359264957759784, 233.2953127272744496 31.0057054347712580, 233.2898951298277552 30.9756300525318586, 233.2854622844924393 30.9454523392395160, 233.2811087260189993 30.9152674167444381, 233.2766787725826703 30.8850916312266328, 233.2723182338893366 30.8549096935436786, 233.2680625875142084 30.8247179031670910, 233.2636594360837989 30.7945427206847562, 233.2591073856077344 30.7643842796401081, 233.2546430265682602 30.7342178079628567, 233.2506548072817054 30.7039852299420275, 233.2467326449200016 30.6737304211930422, 233.2427735884617448 30.6434806792112653, 233.2385419917315517 30.6132606393829505, 233.2344263708046697 30.5830296838953224, 233.2299724550055089 30.5528352857997980, 233.2257801219477642 30.5226147735751212, 233.2217008351061622 30.4923836900467258, 233.2176536181539745 30.4621505031472743, 233.2137701089008033 30.4319014927329441, 233.2097164924721255 30.4016889943031359, 233.2057273903702423 30.3714876142136916, 233.2018315928332299 30.3412778047890157, 233.1982994816497126 30.3110314135098342, 233.1949660442566028 30.2807656745234013, 233.1909995460327423 30.2505672081963901, 233.1869329125315176 30.2203804896412329, 233.1830432862202258 30.1901766843428980, 233.1794294371081264 30.1599455462454706, 233.1757256558107088 30.1297251350849109, 233.1722016871892436 30.0994998764303112, 233.1687265873930528 30.0692827643050293, 233.1657971256008466 30.0390104336791062, 233.1620197155411915 30.0088276220406094, 233.1588110553900322 29.9785872276917402, 233.1558657451028012 29.9483210009432845, 233.1526520127786171 29.9180841251987211, 233.1489461530049425 29.8878997696919093, 233.1453943524933834 29.8577009226217811, 233.1419015804141281 29.8274974560065331, 233.1385470571378562 29.7972455511092846, 233.1353455350549098 29.7669455615295817, 233.1321205569724384 29.7366494892085207, 233.1286857503217504 29.7063766210424909, 233.1248502693014757 29.6761466884616709, 233.1219322346422018 29.6458233627627941, 233.1187887011243447 29.6155248850105153, 233.1158036471033483 29.5852115613275402, 233.1128189974455722 29.5548997434324079, 233.1096148239391823 29.5246121600670683, 233.1059421915823577 29.4943963291803932, 233.1029253621701969 29.4641350065372549, 233.1002381417609399 29.4338412716992366, 233.0969753054017701 29.4036085512195093, 233.0938295190734380 29.3733653616548978, 233.0913472163580593 29.3430553834513503, 233.0892058098987150 29.3127119349485170, 233.0863428536628135 29.2824445349018241, 233.0832116703717247 29.2522064239827806, 233.0797675612365651 29.2220021876052947, 233.0766708226278183 29.1917583918291292, 233.0740702319781690 29.1614600580752779, 233.0714565710503052 29.1311647753718894, 233.0690128690097254 29.1008537235290135, 233.0668902691572271 29.0705113857552107, 233.0645048567228059 29.0401978200036126, 233.0622308672101894 29.0098745532463980, 233.0598776027648569 28.9795611971523428, 233.0578674387814431 28.9492143655959779, 233.0557478222019085 28.9188805699689659, 233.0535026840542230 28.8885669116903081, 233.0508429036588041 28.8583027762556554, 233.0484008302832422 28.8280180911296142, 233.0460454447872962 28.7977263211071275, 233.0438808462369309 28.7674168095387550, 233.0413729393396807 28.7371443319295992, 233.0390306784818790 28.7068567067617089, 233.0369262675736479 28.6765465604866172, 233.0347470633701619 28.6462459426569609, 233.0329268350126029 28.6159104396724331, 233.0304011304856431 28.5856435995657741, 233.0285767800048120 28.5553016797995802, 233.0267613739302988 28.5249607573186239, 233.0251239162247430 28.4946035505017079, 233.0235861249787490 28.4642380888183837, 233.0216106034008021 28.4339193332019669, 233.0189545611982567 28.4036720750902134, 233.0154885602265438 28.3735094844721552, 233.0142983651934401 28.3431162820911595, 233.0278250723133340 28.3112211640409832, 233.0452282676277491 28.2789483187385642, 233.0538325274343094 28.2475942808530149, 233.0539975568602529 28.2171064726347396, 233.0513725666164362 28.1869063911917266, 233.0495940247801911 28.1566216920424530, 233.0476156283759224 28.1263594901667702, 233.0441012164610015 28.0962563986380012, 233.0341267619562586 28.0668153191363920, 233.0153669885792738 28.0382716562388197, 233.0004310857394785 28.0093374012700203, 232.9972907785160601 27.9791790793518445, 232.9993492557859440 27.9484712223743550, 232.9984005080535496 27.9180717344066807, 232.9974307125876010 27.8876765098116586, 232.9972130492358247 27.8572068668353161, 232.9974480176594227 27.8266933234033083, 232.9991589372485805 27.7960317666082872, 232.9989280134374212 27.7655700234398743, 232.9984242466584305 27.7351382270208582, 232.9981795284512316 27.7046822703976723, 232.9979878384327492 27.6742274580723340, 232.9973841036610906 27.6438208719064029, 232.9969627048609766 27.6133979690381288, 232.9956424441186300 27.5830686696756686, 232.9942467721440380 27.5527492409820631, 232.9928294278056455 27.5224342236380508, 232.9910051527021437 27.4921627558272910, 232.9892752252020500 27.4618839132446020, 232.9876407499817219 27.4315975974861637, 232.9860500535251049 27.4013090709267040, 232.9845431092235799 27.3710008489806249, 232.9832144523942645 27.3406640377758308, 232.9813211962325568 27.3103867100814384, 232.9796046601171327 27.2800936680540786, 232.9778668740795808 27.2498050024457292, 232.9760812623403865 27.2195234107069197, 232.9744936225158938 27.1892239957064312, 232.9725389188245686 27.1589640136283244, 232.9710993706607098 27.1286541056528847, 232.9695310658502763 27.0983595097531946, 232.9678740179837177 27.0681026007771948, 232.9664105876216240 27.0378534557890475, 232.9648174107140619 27.0076198078588838, 232.9633173341063355 26.9773791166742747, 232.9625444737612554 26.9470672981345558, 232.9609409653380112 26.9168418629002275, 232.9596090239890316 26.8865913871609727, 232.9583747341857531 26.8563334706206511, 232.9570418888882273 26.8260879392119449, 232.9556783045244401 26.7958479490301471, 232.9541208556610741 26.7656115503644898, 232.9529072543819552 26.7353254479201219, 232.9513372321579823 26.7050777308408733, 232.9496721067915814 26.6748420272618745, 232.9482697864153238 26.6445822619811459, 232.9469308519850870 26.6143185587787521, 232.9456308588750346 26.5840533948264905, 232.9445891873294840 26.5537646856055289, 232.9435705002171630 26.5234761549716360, 232.9424930684089077 26.4931960433853639, 232.9411883949197772 26.4629460272430315, 232.9404661357677355 26.4326443638835542, 232.9397077071035085 26.4023488673881417, 232.9389590229797022 26.3720549233583768, 232.9380771814587661 26.3417769121321328, 232.9371118552418238 26.3115098363031592, 232.9363055939249421 26.2812293227256468, 232.9349899869485796 26.2510025504793205, 232.9335253420537128 26.2207932922122922, 232.9325013463742948 26.1905423329594775, 232.9312666334037374 26.1603104013803893, 232.9304842317117732 26.1300312111249866, 232.9301915141380164 26.0997055104343616, 232.9294881720715580 26.0694236562425061, 232.9290727465349278 26.0391155705938253, 232.9284303149261461 26.0088329122040527, 232.9279035226248311 25.9785413248613892, 232.9273612165927716 25.9482539711808862, 232.9268538349265896 25.9179658022049715, 232.9262752018361766 25.8876874677902151, 232.9258886605539374 25.8574103205503185, 232.9254503185429996 25.8271578908256707, 232.9251078811091702 25.7968986263608180, 232.9246578931968656 25.7666529016120727, 232.9240220891967965 25.7364285482953861, 232.9236035390602524 25.7061852433478357, 232.9230685584527407 25.6759563790138827, 232.9227337276142293 25.6457103098244836, 232.9226746290123629 25.6154395052224721, 232.9151284100965995 25.5859193756642966, 232.8937666408189386 25.5577604985455196, 232.8940638254572661 25.5274256431740376, 232.8871864394730835 25.4978083491673111, 232.8887549686981799 25.4673523877788810, 232.8922447980336017 25.4367079618528003, 232.8868549805569899 25.4069505089107857, 232.8862070943299898 25.3767236846523225, 232.8896433829220882 25.3460933179365959, 232.8904085764630452 25.3157316467882083, 232.8749355209038185 25.2869872854491931, 232.8752451627683229 25.2566951708063385, 232.8833426366030608 25.2256500908747263, 232.8835253170702799 25.1953944684774207, 232.8791674520630863 25.1655927164424504, 232.8897864848736390 25.1343065993527439, 232.8853793269061612 25.1045158111557143, 232.8872412250227626 25.0741054813626967, 232.8902504012405075 25.0435843557223734, 232.8862819506680353 25.0137587009765561, 232.8849165371166805 24.9836776255639741, 232.8615444346234824 24.9557405574212190, 232.8678957260945594 24.9248252132857893, 232.8743003819388377 24.8939074623086256, 232.8845451260537516 24.8626121460513509, 232.8855114925712826 24.8322389783660178, 232.8777786943019805 24.8027302997633399, 232.8784494298064658 24.7723922672678611, 232.8786766284533769 24.7421011266518107, 232.8815821188912878 24.7115479150936572, 232.8784798199646957 24.6815922415318632, 232.8815210228855790 24.6510507831175936, 232.8869507733595299 24.6202941881330695, 232.8897516433328008 24.5898008393355489, 232.8918981621112039 24.5593753741429381, 232.8953447470361766 24.5288244473084802, 232.9021256321721580 24.4979467948482359, 232.9055803921938832 24.4674014151714516, 232.9256796376523369 24.4352113534178201, 232.9278143680417088 24.4048031511444989, 232.9273308331784165 24.3746574337605182, 232.9233851757292086 24.3448714448658983, 232.9184915904676814 24.3151952701589487, 232.9128735282994285 24.2855934651471159, 232.9070168457516559 24.2560179019932747, 232.8961245154026187 24.2269419337473373, 232.9056956381912471 24.1958493513260677, 232.9163992201185636 24.1646481367450328, 232.9148753749125831 24.1346574495094899, 232.9260392073335311 24.1034175400766486, 232.9206813332552315 24.0738120737350201, 232.9204495721024557 24.0437090839679222, 232.9242943937483687 24.0132123141866103, 232.9256437470648962 23.9829650936419547, 232.9266377200116835 23.9527562658711091, 232.9335016546866370 23.9219720544854724, 232.9350094751261224 23.8917194173821663, 232.9318311548631470 23.8619319937482217, 232.9368722189848881 23.8313379252621438, 232.9450679386290517 23.8004364540854993, 232.9487612036169821 23.7699821915590910, 232.9457539898387495 23.7401711441849308, 232.9427211904170463 23.7103463853456446, 232.9402080397393888 23.6804735786337801, 232.9433835896780352 23.6500442500705255, 232.9429844400121681 23.6199700523985001, 232.9448047522230922 23.5896808975073959, 232.9476776161833982 23.5592916672883526, 232.9482010012357307 23.5291369223763986, 232.9512697054896080 23.4987353646153103, 232.9482075711343327 23.4689398428672362, 232.9524304169726179 23.4384270363305625, 232.9546730816440743 23.4081077648677791, 232.9582883792438111 23.3776571360643324, 232.9647493345424039 23.3469304505496851, 232.9703738878391732 23.3162894618000038, 232.9749310818776564 23.2857568940812207, 232.9745359585149913 23.2557144437894792, 232.9767231067804687 23.2254218015470144, 232.9747120127887570 23.1955449257939854, 232.9822413993304906 23.1647348153342918, 232.9804333913460539 23.1348442843248563, 232.9799632302537020 23.1048251182840616, 232.9861015984569690 23.0741610276239371, 232.9875906071483769 23.0439567789152555, 232.9885163914815394 23.0138113509045752, 232.9880927479807724 22.9838018051451627, 232.9920786516129283 22.9533634401114597, 232.9956900448752890 22.9229654565282139, 232.9980286669976408 22.8926959143639905, 232.9994463255823121 22.8625202868843473, 233.0007273528797214 22.8323817678633567, 233.0026223772322567 22.8022057942484011, 233.0043541575535926 22.7720495280457556, 233.0056855084943663 22.7419361868120333, 233.0075168388990221 22.7117776143631644, 233.0086972640626470 22.6816864800318783, 233.0110141290699062 22.6514878823163421, 233.0150980296511989 22.6211202179953652, 233.0183630377297845 22.5908364989234265, 233.0205235277442171 22.5606646286184223, 233.0226990889820513 22.5304748350743687, 233.0250312227692291 22.5002543316308454, 233.0273417265109117 22.4700397096754436, 233.0294322534792286 22.4398503559635607, 233.0316537241797050 22.4096519869835191, 233.0341646708320695 22.3794291320634464, 233.0365342747201112 22.3492238899731959, 233.0390090295576613 22.3190121956477192, 233.0410423262773918 22.2888474231631264, 233.0431049504354633 22.2586836085089459, 233.0454588239587679 22.2284945391122264, 233.0478015507949863 22.1983097810625374, 233.0502410036448282 22.1681194492568139, 233.0528960638682747 22.1379119636236723, 233.0557407392532241 22.1076898814232550, 233.0583526795629439 22.0774943964448305, 233.0611965970119286 22.0472802075900702, 233.0637667924078755 22.0170966232015246, 233.0661707317356672 21.9869331635871532, 233.0688355155518821 21.9567482211745428, 233.0712133980820226 21.9266163988525697, 233.0735932642362229 21.8965084710525772, 233.0760567739937130 21.8663964169622957, 233.0786160068223012 21.8362790738185488, 233.0813521306658913 21.8061485618539130, 233.0841934460657967 21.7760118752912746, 233.0868186398116393 21.7459002817007843, 233.0896572715981847 21.7157720084171899, 233.0925606006185262 21.6856415363909711, 233.0953944803874833 21.6555219187505301, 233.0982658468537920 21.6253757162664222, 233.1010684296373654 21.5952146479776523, 233.1039565019003135 21.5650493241765950, 233.1070084941936784 21.5348721394971818, 233.1101013321710980 21.5046950639545003, 233.1128703125103243 21.4745535124936815, 233.1158241929650217 21.4443980967747834, 233.1188318357311005 21.4142415632226886, 233.1218563893511941 21.3840874972769690, 233.1246794786605676 21.3539570957466367, 233.1274225833886931 21.3238601080463503, 233.1306370619428208 21.2937419769091889, 233.1338110029608401 21.2636319987267903, 233.1368714757588236 21.2335372461871934, 233.1401888172863437 21.2034218385369968, 233.1433772706163268 21.1733231701487838, 233.1465315269799419 21.1432320716031548, 233.1496154961199068 21.1131520453783281, 233.1523256640593331 21.0831124742891163, 233.1550432763680760 21.0530764455185277, 233.1579828491568946 21.0230058062467613, 233.1607722023841802 20.9929374507901692, 233.1636624180470676 20.9628635552655247, 233.1666398146294057 20.9327854558762887, 233.1696517888767346 20.9027082544394602, 233.1726003364721009 20.8726414315882920, 233.1758702061451345 20.8425478178669259, 233.1788078856151856 20.8124905745848885, 233.1817470920860274 20.7824374565909338, 233.1847240764050753 20.7523849749798011, 233.1882571694646344 20.7222788476118502, 233.1922497393497622 20.6921286818578096, 233.1963717973547432 20.6619703873674538, 233.1999109853457526 20.6318727135351736, 233.2035406237867221 20.6017706851485762, 233.2070288687683330 20.5716866761621020, 233.2105921939143514 20.5415998140439520, 233.2140636677692385 20.5115262079037066, 233.2178119026467868 20.4814303279723475, 233.2217592402049036 20.4513196856889081, 233.2251909010724944 20.4212673943468950, 233.2282694104284246 20.3912575382026056, 233.2318419184239815 20.3612045154493515, 233.2355239631732502 20.3311453845283658, 233.2391586893154454 20.3010952640841786, 233.2428990778608977 20.2710394342439066, 233.2464567058851799 20.2410056660194080, 233.2499761034001153 20.2109800535650379, 233.2536732782447757 20.1809418254342638, 233.2573748161999561 20.1509076803071778, 233.2610258437933908 20.1208946526018622, 233.2648839717271301 20.0908774183957135, 233.2690707989333987 20.0608332119564174, 233.2729399482114445 20.0308241593004865, 233.2766399932764330 20.0008359799500361, 233.2812975167479976 19.9707604951296069, 233.2864835103322889 19.9406389605168357, 233.2910589909977830 19.9105807426328631, 233.2951517126284102 19.8805735518180278, 233.2994281961467209 19.8505534223365459, 233.3035672940376344 19.8205511747601868, 233.3079874496854131 19.7905266854675261, 233.3129269618572721 19.7604571404374916, 233.3212816261195712 19.7300649786178290, 233.3230339210745399 19.7003105135329868, 233.3250709695567195 19.6705333692279147, 233.3296297888962272 19.6405193531334774, 233.3340604185271729 19.6105224014149684, 233.3383183316778968 19.5805467749155291, 233.3428179007618439 19.5505528168765963, 233.3472901991913204 19.5205884333304382, 233.3519547731943362 19.4906315127633114, 233.3565130545534316 19.4606896820815081, 233.3611875776566933 19.4307416675757381, 233.3661894040619700 19.4007673213283738, 233.3703364722979643 19.3708796063483923, 233.3750997856715230 19.3409379714334904, 233.3796821891314153 19.3110185896687021, 233.3838727404156259 19.2811415854923034, 233.3885341449362727 19.2512246218168102, 233.3933864583176216 19.2212534982861172, 233.3986811268007102 19.1912063079851336, 233.4036949063699069 19.1611907724062220, 233.4090010487341829 19.1311522333228119, 233.4132186008963572 19.1012223437113988, 233.4123898127269854 19.0717780874003857, 233.4234938187712487 19.0412018332192972, 233.4281136087350319 19.0112482688797080, 233.4325499943371369 18.9813170712390935, 233.4385722855595304 18.9512397884117547, 233.4443472688414261 18.9211910404438655, 233.4496096001402066 18.8911960802090242, 233.4547716285619288 18.8612156352242870, 233.4583507146321608 18.8313907512366683, 233.4655539292224091 18.8012260954861965, 233.4711278176775693 18.7712214498370962, 233.4767412811398799 18.7412180638716350, 233.4825004788564229 18.7112058596042665, 233.4883578875892454 18.6811893699161473, 233.4930940637389085 18.6512844874408437, 233.4992980387236230 18.6212451930439151, 233.5048315554937517 18.5912746804041298, 233.5077083127482638 18.5615615247289476, 233.5090647555902592 18.5319976053133892, 233.5185189872614160 18.5016701736141833, 233.5255892488341942 18.4715741711933816, 233.5300607514989224 18.4417298953676472, 233.5355540632440920 18.4117937924144890, 233.5416644756876394 18.3818043137723670, 233.5436055658501573 18.3522152471283597, 233.5514883548236185 18.3220390661888750, 233.5588538183609160 18.2918895888480471, 233.5647531547830340 18.2618841625459112, 233.5705679155844336 18.2318918456861674, 233.5766138328914110 18.2018827384108697, 233.5826686372002996 18.1718779111117179, 233.5888785936488432 18.1418635244059807, 233.5951383721327943 18.1118495698595687, 233.6014674713914019 18.0818342119676174, 233.6076764094576390 18.0518354029397443, 233.6140209223674447 18.0218522835348871, 233.6204423275639783 17.9918892523867520, 233.6265487122046807 17.9619613307537271, 233.6313515417370752 17.9321620036408689, 233.6386754118331623 17.9021295475461137, 233.6451980358387175 17.8721782134278087, 233.6513777074440270 17.8422646488141012, 233.6535623902091743 17.8127339294621265, 233.6609506865578396 17.7827168172390664, 233.6699594117104652 17.7525520608942990, 233.6710216303398511 17.7231431656523597, 233.6718987092318116 17.6937567665132640, 233.6886100264510446 17.6628813678101864, 233.6960663227023360 17.6328849764936990, 233.7026278411701128 17.6029784898318944, 233.7090592952019676 17.5730897219913196, 233.7159774810301371 17.5431605027643300, 233.7217275105666374 17.5133469216293420, 233.7187734896178881 17.4843590860856359, 233.7270853483593100 17.4543148473689484, 233.7331808847967523 17.4244650559017700, 233.7435127694119501 17.3942028951404453, 233.7536136123764550 17.3639679699225233, 233.7604356213904566 17.3340473252823131, 233.7671770100476749 17.3041397118946207, 233.7740217614510243 17.2742278149319297, 233.7808503086502583 17.2443229050392830, 233.7874669746069003 17.2144434060500231, 233.7940569940029434 17.1845718878380751, 233.8008596200677118 17.1546858578329271, 233.8077378287036368 17.1248364577722185, 233.8147908320279384 17.0950124866516973, 233.8216472061116065 17.0652127325247385, 233.8287550488172997 17.0353950862871919, 233.8358236301641000 17.0055868895558753, 233.8429318876115133 16.9757807353721333, 233.8498250513236201 16.9460005561535851, 233.8567982136573846 16.9162186517835593, 233.8644027751852263 16.8863833032129627, 233.8717789030442304 16.8565752238198030, 233.8787743155451437 16.8267903345429772, 233.8864271812514630 16.7969322128191010, 233.8943020020596748 16.7670590848810228, 233.9020234295209946 16.7372061476229348, 233.9097388861926277 16.7073595931650090, 233.9174310488908759 16.6775210529157647, 233.9253368298226974 16.6476683527042297, 233.9331359103080672 16.6178315076893348, 233.9401620368684576 16.5880728789070986, 233.9480199084255219 16.5582422694894262, 233.9556240340307625 16.5284143707426274, 233.9629611951966979 16.4985917371493649, 233.9680858443129523 16.4689817308657247, 233.9697189392310577 16.4397036867625808, 233.9810825587126999 16.4095219192687374, 233.9908561410638583 16.3794945960977074, 233.9882558493688407 16.3506288802557087, 234.0070396851330088 16.3197717513132616, 234.0069713596252541 16.2906809733634645, 234.0202313686372975 16.2603515811764971, 234.0396206151058891 16.2294769327835162, 234.0450716390547257 16.1999297991625113, 234.0561919768812231 16.1698594103722293, 234.0658256080933484 16.1399339059125637, 234.0741862230366053 16.1101332895480844, 234.0828109349569672 16.0803141029273924, 234.0913423001479430 16.0505097118435671, 234.0998453011710581 16.0207140639358698, 234.1085331389406292 15.9909072930984113, 234.1171059035082749 15.9611173752930284, 234.1257060288378398 15.9313287300367410, 234.1339610710347756 15.9015761555191943, 234.1421311326385535 15.8718375959232336, 234.1504002194577367 15.8420959238434982, 234.1587546085733038 15.8123524373627653, 234.1674495379574523 15.7825834029317260, 234.1763947301172664 15.7527972553046585, 234.1849920604828981 15.7230496510434978, 234.1933783950207726 15.6933278489870016, 234.2016682323672399 15.6636212039726868, 234.2106661097371330 15.6338573919411701, 234.2195850300125812 15.6041094923900445, 234.2284696625345646 15.5743710696476931, 234.2372546655175825 15.5446481978355600, 234.2462970033934084 15.5149077482144495, 234.2553563453492700 15.4851720525691867, 234.2644515611109455 15.4554393745744552, 234.2736445746277525 15.4257039865255212, 234.2828900285930445 15.3959701114112644, 234.2920854371644168 15.3662472678846687, 234.3013275319602258 15.3365240160719942, 234.3104684925447430 15.3068141675627647, 234.3196567184559171 15.2771063205312547, 234.3288051980732121 15.2474085454701331, 234.3378564288254324 15.2177261763429605, 234.3470450329756432 15.1880375021932092, 234.3562524198230790 15.1583535186594478, 234.3654777340128135 15.1286743193465743, 234.3747378383685600 15.0989983562836674, 234.3840812970269099 15.0693211572941852, 234.3931289741021828 15.0396512747805424, 234.4024907287821406 15.0099336756868329, 234.4122604228975320 14.9801847782135766, 234.4219977290714780 14.9504452810051252, 234.4316158209413743 14.9207232126728560, 234.4409823334430598 14.8910307928157444, 234.4498350286750963 14.8613922148236419, 234.4587414390796880 14.8317550981146429, 234.4679675142334077 14.8020949297871400, 234.4770902761938487 14.7724507458019794, 234.4864736837242845 14.7428161287315600, 234.4957933007898987 14.7132196608638797, 234.5055218334094320 14.6835921627046986, 234.5149128953590321 14.6540024086710705, 234.5240841556149007 14.6244395506431832, 234.5338855759494550 14.5948253658854856, 234.5441277226521493 14.5651773496976791, 234.5546148319625672 14.5355135559399677, 234.5650071680218787 14.5058652497170009, 234.5754239649155579 14.4762214794163704, 234.5860298977280820 14.4465631054023937, 234.5967350007561834 14.4168986450669578, 234.6069521162467311 14.3872858480203902, 234.6171532254527108 14.3576813563410912, 234.6275466840538684 14.3280660629932619, 234.6379311549195563 14.2984584660047442, 234.6483279323177840 14.2688566256103382, 234.6586953208047248 14.2392643795011846, 234.6688702844757586 14.2096966780773784, 234.6792465114648394 14.1801174490024575, 234.6895268513892461 14.1505511408581963, 234.6998289448953585 14.1209871012067207, 234.7101500394396680 14.0914282330706779, 234.7207265989751477 14.0618529129046710, 234.7321276646646311 14.0322091287124575, 234.7421715987841822 14.0026964529921418, 234.7518848038956207 13.9732209508361471, 234.7623775574046192 13.9436811555426505, 234.7730116684240897 13.9141354451606745, 234.7836780932642000 13.8845938046600228, 234.7943396384986841 13.8550596462965832, 234.8051586487551958 13.8255181701178014, 234.8160814495535931 13.7959742975977431, 234.8270783532049961 13.7664307564641728, 234.8381481281385277 13.7368876812022247, 234.8493417347460195 13.7073404461621440, 234.8606864116887891 13.6777865960779792, 234.8720570722587695 13.6482375497503181, 234.8830833189578584 13.6187270373040761, 234.8942578953382849 13.5892102038194693, 234.9053801461334388 13.5596778327200553, 234.9167589090509409 13.5301032210258434, 234.9279630753756578 13.5005515901187945, 234.9394192259657075 13.4709841685230476, 234.9508887087120570 13.4414226749875336, 234.9626309708700660 13.4118435574707284, 234.9742477492846433 13.3822830146718665, 234.9858310012523930 13.3527327037391768, 234.9970791621787498 13.3232199972591054, 235.0084942258517913 13.2936993449303102, 235.0186419320547770 13.2643038493261933, 235.0288272435886654 13.2349149251491323, 235.0401198038483130 13.2054328062422517, 235.0532620142338374 13.1757903601525044, 235.0624271207734068 13.1465153770093117, 235.0713600064045750 13.1172684942957840, 235.0793940337581489 13.0881099968979413, 235.0890500815442010 13.0588118576902303, 235.1001302405501860 13.0293921653006581, 235.1114135822560343 12.9999613922397916, 235.1209243695386135 12.9707237606482515, 235.1309020897632820 12.9414756651344565, 235.1414756816763543 12.9121812018778321, 235.1521051678167282 12.8828891503746785, 235.1634486045849712 12.8535402164776222, 235.1748378334555696 12.8241946968538763, 235.1866932396247023 12.7948147508486176, 235.1962591085319900 12.7656485146804730, 235.2079865863655925 12.7362952189512431, 235.2197326745993564 12.7069478740712203, 235.2313225714797227 12.6776155785111495, 235.2423722895124456 12.6483331654411533, 235.2530634947058275 12.6190905340401454, 235.2639518184354870 12.5898377702198960, 235.2744025913662256 12.5606318600724816, 235.2867725902066240 12.5312613935276858, 235.2991023661358554 12.5019022719193309, 235.3116716233483317 12.4725294411014591, 235.3219926188672559 12.4433657659187435, 235.3334198864923508 12.4141106633753289, 235.3448295691033536 12.3848381641287659, 235.3590631815229415 12.3552954059736280, 235.3671572189190897 12.3263093688257310, 235.3791241623067663 12.2969845357516512, 235.3921032498335535 12.2675769255236897, 235.4040318790397635 12.2382708372973177, 235.4133898124759412 12.2092018441388799, 235.4233087209121322 12.1800902645324101, 235.4339080982001633 12.1509255317514953, 235.4452235714742301 12.1217045744836369, 235.4567443232773485 12.0924703557183673, 235.4687492488390603 12.0631982531233231, 235.4810288736117343 12.0339094861732487, 235.4933593765950093 12.0046240088453882, 235.5055131845066398 11.9753620783452011, 235.5183936065197088 11.9460434002548137, 235.5313914411344172 11.9167221953183660, 235.5445277549281400 11.8873966213114315, 235.5579758498066951 11.8580513221761432, 235.5708596306865275 11.8287640872622148, 235.5855568213401057 11.7993272975649965, 235.5997530464831868 11.7699461618724861, 235.6118792697535014 11.7407565433222043, 235.6222863798969911 11.7117271087384989, 235.6370065829994473 11.6823236091034719, 235.6501351704513638 11.6530691110666655, 235.6620788997951479 11.6239274594960431, 235.6746660023580375 11.5947368831364290, 235.6884231603173134 11.5654509339622074, 235.7004295445096318 11.5363277616853797, 235.7116587816107653 11.5072743978115017, 235.7235065834900070 11.4781679472531195, 235.7365096550367127 11.4489676032006464, 235.7509681343241823 11.4196470655213886, 235.7663406602954126 11.3902542183865609, 235.7777363714225771 11.3612199442138770, 235.7886739885623797 11.3322339874387712, 235.8008113264958183 11.3031504556224558, 235.8129270658486121 11.2740769145439081, 235.8254455463137731 11.2449760862040069, 235.8379734894969602 11.2159103138021727, 235.8515159915447725 11.1867900343017261, 235.8657944078324817 11.1576136472877927, 235.8797318094724460 11.1284757052297607, 235.8937716656566295 11.0993373101821966, 235.9083287918834912 11.0701621525963976, 235.9230551242763454 11.0409807942013884, 235.9376740007390936 11.0118174850440553, 235.9515272763334792 10.9827297851711894, 235.9638445602315073 10.9537849358168398, 235.9770623676747618 10.9247485593648044, 235.9907218608971675 10.8956618895965960, 236.0047319410548994 10.8665530900764598, 236.0183309333028205 10.8374886511489006, 236.0323861690052070 10.8083929297519710, 236.0537151650576106 10.7647439316584066, 235.8067955133563487 10.7864349997890709, 235.6404746257549050 10.8009251269224613, 235.4886934161563090 10.8140812538425859, 235.3440743681633194 10.8265506526397672, 235.2013541677872581 10.8387871303979448, 235.0605785760558604 10.8507895528866261, 234.9266644391592536 10.8621511165544540, 234.7983134326682091 10.8729887160327756, 234.6742684848876479 10.8834132357187077, 234.5539738435558093 10.8934756928844845, 234.4326844057642347 10.9035680020157386, 234.3062264801246215 10.9140277809663164, 234.1842183967322342 10.9240715931274739, 234.0687460570583767 10.9335373293069207, 233.9561439769059348 10.9427259417912808, 233.8474210956631509 10.9515604135292577, 233.7435151522079764 10.9599707574291010, 233.6385624025285779 10.9684248104055708, 233.5358140067685326 10.9766660932999969, 233.4407131631531342 10.9842712723458380, 233.3422237141446089 10.9921074822156886, 233.2513957968607770 10.9993144684109971, 233.1514470230774236 11.0071956760767709, 233.0568672341268268 11.0146280042103246, 232.9714593141207217 11.0213255319050045, 232.8803341230172919 11.0284323244548599, 232.7943082344645518 11.0351214682081213, 232.7094524258487809 11.0416948896581566, 232.6269891539108698 11.0480614832231261, 232.5469229652644003 11.0542229776369396, 232.4651981313369333 11.0604848215878384, 232.3872682244125656 11.0664391550579264, 232.3089820002455212 11.0723973916104050, 232.2344266808472071 11.0780568263891706, 232.1612777882611454 11.0835918116322976, 232.0879579900140470 11.0891193379889383, 232.0165771813888114 11.0944847829273883, 231.9444953164244794 11.0998822668698729, 231.8732154220784309 11.1052019606563253, 231.8057772059842137 11.1102241836769355, 231.7386284223711641 11.1152083218847366, 231.6726527935735476 11.1200909547501485, 231.6064561948248581 11.1249729598940004, 231.5413069011224252 11.1297634611436838, 231.4780838222075090 11.1344005203999021, 231.4150219500249648 11.1390109034253264, 231.3534789037249482 11.1434985250687806, 231.2922763752978028 11.1479476252960712, 231.2321986804804794 11.1523031971319266, 231.1727759778428322 11.1565989553883824, 231.1144830584675844 11.1608020872514171, 231.0567419751282898 11.1649536385302941, 231.0002949603130844 11.1690023089595787, 230.9442330255996296 11.1730119569343600, 230.8887529573797224 11.1769692032438481, 230.8340953656557133 11.1808578017260558, 230.7801047938849592 11.1846889342734332, 230.7267933250105045 11.1884621644695219, 230.6741394301091646 11.1921793597281063, 230.6222024977036256 11.1958368476612140, 230.5710284673361343 11.1994319110143241, 230.5203688901636383 11.2029818304628126, 230.4702850162541097 11.2064827482238183, 230.4211332149626514 11.2099109379551578, 230.3722347960806474 11.2133125718895510, 230.3238995148835784 11.2166669987468861, 230.2759727552659399 11.2199848672525260, 230.2288337046632876 11.2232410798017348, 230.1821784107610824 11.2264562859122670, 230.1360978920992579 11.2296246903222858, 230.0904502464934467 11.2327559867974180, 230.0451126661331500 11.2358585089279366, 230.0005121694860009 11.2389042679665501, 229.9563201538430803 11.2419152341142503, 229.9126038169200683 11.2448872011781784, 229.8693914420420299 11.2478185506001704, 229.8266141936523184 11.2507140176866258, 229.7844926752367201 11.2535594487218447, 229.7426279584758220 11.2563810618782671, 229.7011060076216040 11.2591734075647292, 229.6601354388773188 11.2619231614147282, 229.6197463420439817 11.2646286372140789, 229.5797488137789912 11.2673023162465977, 229.5399124326933418 11.2699591633018521, 229.5003744155729066 11.2725904639326817, 229.4613780020150102 11.2751808122651145, 229.4229479289658684 11.2777288707496943, 229.3846678777049419 11.2802613604144639, 229.3465203971843209 11.2827794526095353, 229.3092627460586925 11.2852352682155690, 229.2721541795518476 11.2876759727222673, 229.2355028971691127 11.2900822055293411, 229.1990236077021166 11.2924720971991803, 229.1627789235925832 11.2948417900818434, 229.1268004674420808 11.2971894009668787, 229.0910977852267933 11.2995144425208256, 229.0558429789198556 11.3018062999761035, 229.0210984390745352 11.3040612741786077, 228.9866394069139233 11.3062935182293298, 228.9523786369052232 11.3085085479037950, 228.9184628476472483 11.3106973739286509, 228.8847576778029236 11.3128684166009119, 228.8514037966496630 11.3150131009844515, 228.8184344402530144 11.3171295215195773, 228.7856962146676665 11.3192272249858679, 228.7530968391201611 11.3213119416410635, 228.7207523182538296 11.3233766438682917, 228.6886580791888548 11.3254217054343105, 228.6568808000469062 11.3274431670293048, 228.6255699416117295 11.3294320811030449, 228.5943557727715074 11.3314109976706128, 228.5633199203958270 11.3333750202067769, 228.5325366678410148 11.3353197346958243, 228.5019329259168614 11.3372496289070153, 228.4715394680731890 11.3391629188288814, 228.4413945509302266 11.3410573865418574, 228.4114629408679491 11.3429352267224637, 228.3817510016924075 11.3447961341414043, 228.3522475214008693 11.3466408530271394, 228.3230615139313500 11.3484629748790748, 228.2940740736263194 11.3502696640891187, 228.2653336387764398 11.3520581199518453, 228.2367430860684010 11.3538341663080260, 228.2082916103083505 11.3555984904766376, 228.1800368130793117 11.3573477475009099, 228.1520392237875967 11.3590784464209307, 228.1243947354929844 11.3607850493464291, 228.0969443603398190 11.3624769794781795, 228.0696393456295539 11.3641571482644679, 228.0424929933010674 11.3658248267683515, 228.0154106641673479 11.3674855738926084, 227.9885578563481374 11.3691297953353825, 227.9618650794204200 11.3707615940505633, 227.9353348111912680 11.3723808773608148, 227.9089933044639054 11.3739861801390099, 227.8828228745905733 11.3755785815541977, 227.8568634996865114 11.3771558345525552, 227.8309964239465728 11.3787248265649676, 227.8053094676684509 11.3802805503758524, 227.7797848238544418 11.3818240807472453, 227.7544332388526129 11.3833548536377336, 227.7292690741705314 11.3848721031830813, 227.7042771343951415 11.3863767513912375, 227.6794424865351800 11.3878696987312100, 227.6547547108986294 11.3893515833046468, 227.6302153125810435 11.3908223637586765, 227.6058446822487724 11.3922809322129357, 227.5815837284553993 11.3937306712760531, 227.5574768187678387 11.3951691152893524, 227.5335303503320290 11.3965959501297025, 227.5097275399109833 11.3980121642247596, 227.4860553007757460 11.3994185320559378, 227.4625029322769194 11.4008156893180974, 227.4390700032307961 11.4022036943794731, 227.4157514915798401 11.4035828609687258, 227.3925662525225562 11.4049521734577617, 227.3695676411404918 11.4063087093438291, 227.3466880305276732 11.4076562680175844, 227.3239817936694749 11.4089918766877290, 227.3013618133047657 11.4103203927839978, 227.2788626998101904 11.4116399330742109, 227.2564905837951699 11.4129501940545577, 227.2341471861246305 11.4142566063190909, 227.2119503831800671 11.4155527167828144, 227.1898755316235565 11.4168399144063564, 227.1679212759821098 11.4181183068057379, 227.1461045130937464 11.4193870060475948, 227.1244248889419168 11.4206460692728164, 227.1028554367262871 11.4218969988970116, 227.0813921445934511 11.4231400422407940, 227.0600099683261135 11.4243765834220152, 227.0387800565269458 11.4256027995307967, 227.0176858866700798 11.4268196232913724, 226.9967364182923859 11.4280266090250517, 226.9758565799991175 11.4292278308048303, 226.9550385935661438 11.4304237238046849, 226.9342329016709527 11.4316169579053106, 226.9135052379866977 11.4328040202277510, 226.8929749480163025 11.4339785612803233, 226.8725374557904217 11.4351462062810540, 226.8522123581976189 11.4363059371368561, 226.8319968195319518 11.4374579339901992, 226.8118864201212830 11.4386024598112925, 226.7918595656044261 11.4397406845203573, 226.7719343835058226 11.4408716721278054, 226.7520928931478750 11.4419963969853402, 226.7323585007384281 11.4431136486025657, 226.7126918304146841 11.4442255234732126, 226.6930802682913395 11.4453327000192484, 226.6735784057233900 11.4464323335892999, 226.6541678320585618 11.4475254147592285, 226.6348499723003727 11.4486118924843705, 226.6156086420497218 11.4496926332811118, 226.5964513089176933 11.4507672681177546, 226.5773802830670718 11.4518356983188578, 226.5583938982732946 11.4528980320229987, 226.5394514986686545 11.4539563930335184, 226.5205720112754193 11.4550098145010253, 226.5017744116908602 11.4560573339612208, 226.4830830479979795 11.4570977194829009, 226.4644630477073406 11.4581327889146145, 226.4458929607677931 11.4591636593943669, 226.4273420018058687 11.4601919179165357, 226.4089327375767766 11.4612113075361997, 226.3905321797895738 11.4622286455691889, 226.3721760724194496 11.4632421133368112, 226.3540415653064031 11.4642427211329760, 226.3361333516311902 11.4652302892907549, 226.3181669859138481 11.4662192771337264, 226.3002739486506414 11.4672030229303132, 226.2824320913041731 11.4681826620260043, 226.2646422367273829 11.4691581650756707, 226.2469095834710231 11.4701292830936108, 226.2292344049313897 11.4710960160787430, 226.2116353879809196 11.4720574419513870, 226.1941018513785480 11.4730141135445951, 226.1766306716312727 11.4739662026907236, 226.1592231105851738 11.4749136616605600, 226.1418925461004221 11.4758558407877249, 226.1246140672749334 11.4767939954809481, 226.1074024905080080 11.4777274041137769, 226.0902695214729761 11.4786555042624894, 226.0731674626638892 11.4795806696773699, 226.0561148944824197 11.4805019915790982, 226.0391203976545000 11.4814190596774068, 226.0221853383609698 11.4823318209273602, 226.0053302814410472 11.4832392822302278, 225.9885536989861805 11.4841415383496983, 225.9718003975521015 11.4850413028381215, 225.9550662527160227 11.4859387811263254, 225.9383869128336073 11.4868322431797356, 225.9217536701517588 11.4877221247833017, 225.9051656781826978 11.4886084777220923, 225.8886411839913251 11.4894904303538077, 225.8721818201436236 11.4903679195340356, 225.8557774564196166 11.4912414492684487, 225.8394241488462342 11.4921112224597479, 225.8231345766302809 11.4929766430547744, 225.8068834000255549 11.4938389401884038, 225.7906841315510462 11.4946974768467634, 225.7745264906764078 11.4955527558965187, 225.7584156584575226 11.4964045403774602, 225.7423465946611998 11.4972530808697719, 225.7263306551080575 11.4980978487034342, 225.7103637501312221 11.4989390503598727, 225.6944403535995320 11.4997769586268870, 225.6785731333571334 11.5006109868028794, 225.6627606321937378 11.5014412173606519, 225.6469855377227418 11.5022684764026693, 225.6312478555471444 11.5030927722663758, 225.6155505187072094 11.5039139764720328, 225.5999034371527046 11.5047316362642924, 225.5843036923893692 11.5055458998858136, 225.5687372937127293 11.5063574287637636, 225.5532030184863004 11.5071662870658145, 225.5377227249349801 11.5079714709681848, 225.5222898787807537 11.5087732956897408, 225.5069090090448469 11.5095715644164081, 225.4915549235061292 11.5103674479623592, 225.4762447625155630 11.5111601660448795, 225.4609749326394876 11.5119498938921492, 225.4457365038286696 11.5127370489375576, 225.4305250723075460 11.5135218388493605, 225.4153505895338014 11.5143038171213341, 225.4002092546284359 11.5150831649119425, 225.3851016085638435 11.5158598654166937, 225.3700330195549668 11.5166336842014907, 225.3550142447406586 11.5174041464428090, 225.3400350352184205 11.5181717255856064, 225.3250842761325714 11.5189369296321988, 225.3101705090110443 11.5196993830200629, 225.2952945149411903 11.5204590600189807, 225.2804449879828610 11.5212164731226441, 225.2656236019600158 11.5219715538163427, 225.2508347977898495 11.5227241118038215, 225.2360836991653912 11.5234739286072809, 225.2213701223724058 11.5242210218960714, 225.2066922232504851 11.5249654822953591, 225.1920523314320235 11.5257072167190060, 225.1774439551024329 11.5264465188783927, 225.1628688639239613 11.5271833193508293, 225.1483231609231552 11.5279177960268999, 225.1338080113100091 11.5286499054819789, 225.1193156868255869 11.5293799895936093, 225.1048406914377722 11.5301082903483714, 225.0903927203169417 11.5308343935948869, 225.0759731997245296 11.5315582445592355, 225.0615726061136002 11.5322802576213679, 225.0471948914249083 11.5330002677360355, 225.0328448252998612 11.5337180770247567, 225.0185250472492839 11.5344335803454925, 225.0042336758090187 11.5351468651000317, 224.9899666840133534 11.5358581082563951, 224.9757293128520246 11.5365670952889197, 224.9615188349451955 11.5372739482831079, 224.9473343603615376 11.5379787112424008, 224.9331867189993659 11.5386809398550945, 224.9190651590855623 11.5393810912804238, 224.9049589851288147 11.5400796146826714, 224.8908763596490132 11.5407761760249468, 224.8768203267520391 11.5414706560850586, 224.8627911626610114 11.5421630507503536, 224.8487873231403000 11.5428534304463373, 224.8348025935591181 11.5435420547040746, 224.8208432662326004 11.5442286728549472, 224.8069064464881137 11.5449134088086396, 224.7929952890946197 11.5455961415900141, 224.7790961745715776 11.5462774242074797, 224.7652157298564077 11.5469569934464271, 224.7513584997161615 11.5476346729728849, 224.7375268209599710 11.5483103768095621, 224.7237220902749186 11.5489840576780978, 224.7099413765578788 11.5496558393060589, 224.6961637810833281 11.5503265461398446, 224.6824171483842463 11.5509950911857580, 224.6686890557816412 11.5516619670139367, 224.6549772382032870 11.5523272659126715, 224.6412812909752574 11.5529910072087549, 224.6276091034430920 11.5536528929961140, 224.6139594562434354 11.5543129777076068, 224.6003182497858006 11.5549718025661718, 224.5867005368061768 11.5556288004452110, 224.5731010661888547 11.5562841764879352, 224.5595318451174194 11.5569374888469927, 224.5459817047643298 11.5575891644451509, 224.5324427190798815 11.5582395019069519, 224.5189143401576359 11.5588885230225600, 224.5054022183505253 11.5595360233582749, 224.4919123846902949 11.5601817896909829, 224.4784375362918922 11.5608260941027599, 224.4649757674625334 11.5614690093643855, 224.4515271517104793 11.5621105363191763, 224.4380954082653545 11.5627505474210537, 224.4246791510040566 11.5633890977002594, 224.4112755960885295 11.5640262896197967, 224.3978846737749677 11.5646621293277523, 224.3845066428580992 11.5652966117857297, 224.3711457528072799 11.5659295968898910, 224.3577977362114098 11.5665612362847892, 224.3444652819509599 11.5671914448426509, 224.3311485458355321 11.5678202246618813, 224.3178463670823248 11.5684476215481595, 224.3045557510947106 11.5690737397450327, 224.2912636805589273 11.5696990018417161, 224.2779812886722084 11.5703230455082942, 224.2647169075775651 11.5709456114698224, 224.2514653724536799 11.5715668719248708, 224.2382246445113481 11.5721868961343297, 224.2249954647936079 11.5728056663857863, 224.2117774258863392 11.5734232007857347, 224.1985677641190193 11.5740395865862666, 224.1853739310522826 11.5746546100326597, 224.1721921301367502 11.5752683925175521, 224.1590180429048473 11.5758810639248129, 224.1458517540414732 11.5764926247077806, 224.1326993443369702 11.5771029132241008, 224.1195552562867306 11.5777120902351882, 224.1064199000637984 11.5783201500287358, 224.0932922280787238 11.5789271253157189, 224.0801718772106028 11.5795330298010271, 224.0670575303311978 11.5801378996871716, 224.0539473086338944 11.5807417811292463, 224.0408440714013807 11.5813446074145894, 224.0277532395568016 11.5819462641689093, 224.0146726415863156 11.5825468155354745, 224.0016005777064834 11.5831463107815384, 223.9885357303068645 11.5837447873712911, 223.9754767473346249 11.5843422797721338, 223.9624200726210574 11.5849388562089111, 223.9493664901763452 11.5855344995887286, 223.9363221822940204 11.5861291150833914, 223.9232837412836545 11.5867227707854603, 223.9102514687331791 11.5873154735646064, 223.8972278339570039 11.5879072106724461, 223.8842074228040815 11.5884980596409761, 223.8711897945744056 11.5890880278296695, 223.8581768384303530 11.5896771077336140, 223.8451691054746391 11.5902653131262241, 223.8321650096247595 11.5908526677192825, 223.8191624724294684 11.5914391819224125, 223.8061618009817266 11.5920248568798314, 223.7931629563942124 11.5926096948298962, 223.7801640483884000 11.5931936738872050, 223.7671670080405022 11.5937768052707160, 223.7541730621465206 11.5943591186183301, 223.7411823205447945 11.5949406428819604, 223.7281945822350622 11.5955214095179251, 223.7152092203544385 11.5961014400467270, 223.7022255713048651 11.5966807498982440, 223.6892422590746605 11.5972592901497720, 223.6762589726454848 11.5978370356977791, 223.6632763821540379 11.5984140565029268, 223.6502941596612857 11.5989903554735516, 223.6373122485578335 11.5995659928018569, 223.6243300457994962 11.6001409101370623, 223.6113474183802055 11.6007150945083968, 223.5983643014758400 11.6012885646784660, 223.5853804742061470 11.6018613807905879, 223.5723949789524738 11.6024337740613035, 223.5594084415180305 11.6030053638277568, 223.5464202437128733 11.6035763342790617, 223.5334298265300106 11.6041467476564453, 223.5204368671151371 11.6047166055491324, 223.5074413311778017 11.6052858741608773, 223.4944432982260878 11.6058545207539758, 223.4814424785570282 11.6064225703277071, 223.4684383277615893 11.6069900726994231, 223.4554303426207014 11.6075570640144345, 223.4424179562216750 11.6081235823802746, 223.4294005333650546 11.6086896685705661, 223.4163767564448335 11.6092554251278521, 223.4033493491633067 11.6098205677991118, 223.3903182963025813 11.6103850983762644, 223.3772834961584977 11.6109490258485373, 223.3642450371687289 11.6115123420402657, 223.3512033206642116 11.6120750138094984, 223.3381552833168939 11.6126372900905022, 223.3251009602240629 11.6131991535604477, 223.3120397912722694 11.6137606354716958, 223.2989722102144583 11.6143216904755153, 223.2858985034930868 11.6148822884616791, 223.2728171532845636 11.6154425337012182, 223.2597285678833714 11.6160023858956460, 223.2466317184563422 11.6165619095860251, 223.2335277664742250 11.6171210135472585, 223.2204169764052324 11.6176796739022148, 223.2072988293887192 11.6182379214719873, 223.1941722853877934 11.6187958206584696, 223.1810361052811231 11.6193534462392343, 223.1678913125285533 11.6199107220438496, 223.1547381380195532 11.6204676270151737, 223.1415754377214853 11.6210242292760242, 223.1284015147909372 11.6215806294669530, 223.1152151257165031 11.6221368962333358, 223.1020209030151591 11.6226927309393666, 223.0888180899143265 11.6232481781277510, 223.0756052319343894 11.6238033234461131, 223.0623811454720169 11.6243582333811322, 223.0491451294242040 11.6249129434946941, 223.0358968024115143 11.6254674694465869, 223.0226367869014155 11.6260217673261028, 223.0093615337405595 11.6265760397115301, 222.9960678207878289 11.6271304645774922, 222.9827655838388409 11.6276844535504598, 222.9694554206592443 11.6282379715212905, 222.9561342545880791 11.6287911941992892, 222.9427998983100281 11.6293442422904576, 222.9294510268497618 11.6298971849420312, 222.9160884180228663 11.6304499718435022, 222.9027074603658320 11.6310028545879938, 222.8893176033846828 11.6315552994956750, 222.8759211426458364 11.6321071794923245, 222.8625124070450170 11.6326588071240860, 222.8490832134943105 11.6332106252390091, 222.8356348319159679 11.6337625545310122, 222.8221730868960435 11.6343142716203776, 222.8086998368628429 11.6348656728460060, 222.7952032410204879 11.6354173891255126, 222.7816844858264176 11.6359693461022538, 222.7681514532162907 11.6365211163933093, 222.7546094596874582 11.6370724158920975, 222.7410496054532985 11.6376237118726813, 222.7274689117784021 11.6381751538626439, 222.7138741945792617 11.6387263791939652, 222.7002655263075610 11.6392773809061207, 222.6866375324842124 11.6398284332340332, 222.6729866912269813 11.6403797107135603, 222.6593141329908860 11.6409311470154773, 222.6456207319734517 11.6414826900451711, 222.6319141538503459 11.6420339437049929, 222.6181898888893045 11.6425851339993027, 222.6044497077721189 11.6431361669500060, 222.5906859946134375 11.6436874213117303, 222.5768997746839943 11.6442388379762196, 222.5630916264516372 11.6447903810373035, 222.5492639055905215 11.6453419268843490, 222.5354268513513034 11.6458929634969444, 222.5215672763436032 11.6464441414374580, 222.5076782329797993 11.6469957955481807, 222.4937638625373211 11.6475477129612344, 222.4798292363327619 11.6480996383395290, 222.4658732608350817 11.6486516197575565, 222.4519005455341585 11.6492034280487822, 222.4379138599454677 11.6497549259658317, 222.4239108831781380 11.6503062232925103, 222.4098822394056754 11.6508577672794029, 222.3958278149365810 11.6514095559922666, 222.3817501135733607 11.6519614625816583, 222.3676471868176634 11.6525135736721523, 222.3535187113662914 11.6530658977189141, 222.3393601721830919 11.6536186413768181, 222.3251663416662041 11.6541720424480655, 222.3109466623485844 11.6547256460647457, 222.2967040816845383 11.6552793072737035, 222.2824345096863681 11.6558332118137287, 222.2681376654342955 11.6563873656892145, 222.2537934125679442 11.6569426977978008, 222.2394296278611137 11.6574979009509079, 222.2250456168251276 11.6580530033632179, 222.2106332312139614 11.6586083764543069, 222.1961901634210790 11.6591641190119280, 222.1817259895384495 11.6597197839798312, 222.1672323459239919 11.6602757492673099, 222.1527060469091452 11.6608321525715102, 222.1381498752822665 11.6613888587151155, 222.1235645886079055 11.6619458257867166, 222.1089488152713898 11.6625031085844704, 222.0943054474924168 11.6630605689785138, 222.0796369850662870 11.6636180879175431, 222.0649326370137260 11.6641761438836653, 222.0501916741791320 11.6647347600561329, 222.0354200415976607 11.6652936614482048, 222.0206255050637481 11.6658524948229072, 222.0058055009189957 11.6664113692121720, 221.9909317003400986 11.6669715336748201, 221.9760187813593575 11.6675323245008133, 221.9610674740678178 11.6680936993382627, 221.9460834295299492 11.6686553999180251, 221.9310575638693024 11.6692178165951557, 221.9159984711464233 11.6697805626031830, 221.9009259266182426 11.6703427671831381, 221.8858296896012519 11.6709048744380706, 221.8706995944909295 11.6714673207546262, 221.8555326260521667 11.6720302285181958, 221.8403304885907517 11.6725935149842535, 221.8250972499780858 11.6731569963145727, 221.8098195614849146 11.6737212391111793, 221.7944889260287198 11.6742865963530384, 221.7791202134376647 11.6748524179258037, 221.7637180402751653 11.6754184975181392, 221.7482700456498321 11.6759853535227798, 221.7327669514012030 11.6765533683532627, 221.7172115229149085 11.6771224104258984, 221.7016211571622364 11.6776917309401540, 221.6860028019623599 11.6782610287884872, 221.6703447482998399 11.6788307904525137, 221.6546244431601451 11.6794019527549153, 221.6388611839099951 11.6799736915289696, 221.6230487052656883 11.6805462579599411, 221.6071946734351457 11.6811193203291595, 221.5913075585570766 11.6816925165768879, 221.5753864703937950 11.6822658761466514, 221.5594131535228257 11.6828401465026825, 221.5433904492085446 11.6834151972955738, 221.5273308964312662 11.6839905000419026, 221.5112244756874702 11.6845664577698898, 221.4950649900496273 11.6851433129840192, 221.4788646116655002 11.6857205548552265, 221.4626020103548569 11.6862990436845706, 221.4462705120642738 11.6868790352296799, 221.4298859924444685 11.6874598673674459, 221.4134506856227631 11.6880414365500922, 221.3969754781630286 11.6886232905391001, 221.3804605137580950 11.6892054142711928, 221.3638996850384046 11.6897880441024000, 221.3472772159424551 11.6903718019422271, 221.3305813530331818 11.6909571427403947, 221.3137711140890644 11.6915456840148906, 221.2969116219956618 11.6921348014644693, 221.2800176036289201 11.6927238980664399, 221.2630934336351345 11.6933127927512874, 221.2461192125688001 11.6939022660947209, 221.2290863538791825 11.6944926448374780, 221.2119945040117273 11.6950839284474686, 221.1948675705588698 11.6956751636056868, 221.1776935519540359 11.6962668126450460, 221.1604303534508631 11.6968605094593148, 221.1430823375198713 11.6974560609985367, 221.1256729793842908 11.6980525325018565, 221.1082343240076113 11.6986486654835566, 221.0907777951840387 11.6992440115853711, 221.0732731529905379 11.6998397354871191, 221.0556760649134844 11.7004375334853155, 221.0379809653511245 11.7010375956553752, 221.0201910780052401 11.7016397730643664, 221.0023326505245791 11.7022430374960269, 220.9844141227260934 11.7028470498581800, 220.9664267865848046 11.7034521267778491, 220.9483618371737066 11.7040585853194052, 220.9302181846813085 11.7046664470968480, 220.9120117963100540 11.7052750889533517, 220.8937461626249217 11.7058843638380630, 220.8754296372306953 11.7064939431866843, 220.8570353831397597 11.7071048211080768, 220.8385387414590184 11.7077179002450666, 220.8199419597744964 11.7083330701137101, 220.8012542966671958 11.7089499601075566, 220.7824976140121294 11.7095677351636258, 220.7636932618528647 11.7101855873258316, 220.7448115762643397 11.7108046009476432, 220.7258449069571213 11.7114250382026324, 220.7067902066008855 11.7120469892192514, 220.6876435492166593 11.7126705751678752, 220.6684018412074693 11.7132958852828502, 220.6490775002795601 11.7139224419230299, 220.6296751617481959 11.7145500551708484, 220.6101884901048891 11.7151789348560165, 220.5906226553490512 11.7158088720504860, 220.5709709286415716 11.7164400891991374, 220.5512576667543385 11.7170716871744123, 220.5314614383958087 11.7177044199496514, 220.5115590022694505 11.7183390981714997, 220.4915452243125742 11.7189758769615491, 220.4714307799496567 11.7196143463289246, 220.4512468588935121 11.7202533715732216, 220.4309992066251311 11.7208927312610225, 220.4106498399640373 11.7215337511258344, 220.3901880983314356 11.7221767796032985, 220.3696269742773666 11.7228213298105270, 220.3489604038595360 11.7234675875962715, 220.3281690552250609 11.7241162000845627, 220.3072756756521926 11.7247663403802918, 220.2862824116052138 11.7254179062594375, 220.2651764715898821 11.7260713139578225, 220.2439627765912178 11.7267263625395888, 220.2226597862525637 11.7273823863475251, 220.2012604090778041 11.7280396048920039, 220.1797602368997104 11.7286981429012638, 220.1581417345539080 11.7293585718169044, 220.1364090861300156 11.7300207161521133, 220.1145235049643532 11.7306858616742726, 220.0924773395380214 11.7313542240955595, 220.0703026463924346 11.7320246749398329, 220.0480152578872719 11.7326966446454506, 220.0256193313570066 11.7333699618091085, 220.0031393234807240 11.7340437771874129, 219.9805459909590581 11.7347190432092177, 219.9578262375317195 11.7353961632534389, 219.9350228461180166 11.7360736819629636, 219.9120955538532485 11.7367529071512759, 219.8890352094778962 11.7374341046332820, 219.8658230573190906 11.7381178519633629, 219.8424378550888889 11.7388048002984231, 219.8189420393960916 11.7394928593078127, 219.7954051231398296 11.7401797339112814, 219.7717126788431301 11.7408691262396143, 219.7478364883703819 11.7415619025074314, 219.7238247217930223 11.7422564541995786, 219.6876080273489436 11.7432997520176681, 219.6987523783379856 11.7853029348258165, 219.7061791771063213 11.8133127052587561, 219.7135986549952236 11.8413287509520497, 219.7210947404886099 11.8693483800486028, 219.7285881728001016 11.8973741241781905, 219.7359476924907256 11.9254261184903640, 219.7433492070103682 11.9534995743589398, 219.7507477436034549 11.9815790420371542, 219.7579850993488151 12.0096695496526920, 219.7652250045894959 12.0377658721436855, 219.7725553247495327 12.0658652068473007, 219.7800022085723128 12.0939667193786491, 219.7873408945879703 12.1220775512080277, 219.7950743482600444 12.1501817176683709, 219.8021390085208395 12.1783129843083433, 219.8093731982236250 12.2064422366432552, 219.8167053718840123 12.2345716176753534, 219.8241449129442060 12.2627034586213295, 219.8313191007843272 12.2908495551188075, 219.8387108569059478 12.3189946084991622, 219.8460894153434992 12.3471459191464970, 219.8532640727768239 12.3753095044270172, 219.8601696000009724 12.4034874078261979, 219.8674454814815817 12.4316594206823332, 219.8745707847417066 12.4598419912327891, 219.8816850375779950 12.4880175631037567, 219.8889121190733249 12.5161815294953112, 219.8961929096689403 12.5443496532151944, 219.9035207112792136 12.5725221393741382, 219.9108000505651717 12.6007019865559329, 219.9180033534095458 12.6288900488054807, 219.9252926238032160 12.6570812286973560, 219.9325837931077388 12.6852781631490377, 219.9416672226408593 12.7134247385197234, 219.9543961129569425 12.7414629673091611, 219.9609663348926460 12.7696974746051932, 219.9637127244800183 12.7980546219476423, 219.9693396485584742 12.8263272759272695, 219.9763389820033410 12.8545627691681332, 219.9873479021010496 12.8826789123672061, 219.9942663403161305 12.9109285110434495, 220.0001191110418972 12.9392170377871523, 220.0060791740759782 12.9675078899464129, 220.0125259482794604 12.9957892678082967, 220.0204798708710712 13.0240294902412526, 220.0303293169093024 13.0522308973718033, 220.0363637763307167 13.0805716599938826, 220.0435221785276383 13.1088831468612046, 220.0503444747572246 13.1372106969061573, 220.0554559745506822 13.1655969103811312, 220.0637152729870252 13.1938911364857212, 220.0719544405740180 13.2221916259964800, 220.0809450262833309 13.2504744742211606, 220.0855198220701539 13.2788996751998649, 220.0951748736929687 13.3071731967088791, 220.1002723968982480 13.3355840088870146, 220.1073650534361832 13.3639288227772877, 220.1144815965231203 13.3922785024813304, 220.1215875627314631 13.4206341037762353, 220.1287352846985073 13.4489940062221827, 220.1370402478150368 13.4773238026688098, 220.1447839371536190 13.5056765103977554, 220.1521111758974030 13.5340476370338614, 220.1594759153635721 13.5624231738013563, 220.1672083183461552 13.5907929546773065, 220.1735074970197275 13.6191997958310758, 220.1797183181128901 13.6476015911061896, 220.1873653702023717 13.6759648320780816, 220.1929970821997813 13.7043955201351562, 220.2002836979509937 13.7327809783765069, 220.2072371134695459 13.7611822222090758, 220.2143098338185894 13.7895853680132188, 220.2215409215835393 13.8179892236931927, 220.2286146028019118 13.8464034430197174, 220.2359968999590762 13.8748137746858955, 220.2429905146004501 13.9032506380188661, 220.2501006641976460 13.9316990778372300, 220.2572072438011901 13.9601531118914846, 220.2642324533995009 13.9886151017755545, 220.2713546031071132 14.0170796063823264, 220.2784888315825356 14.0455492056894755, 220.2854618046473831 14.0740291667353681, 220.2923997653498702 14.1025156367928943, 220.2996432287141317 14.1309982528014633, 220.3069647400963333 14.1594839346048786, 220.3142063436781086 14.1879636486693315, 220.3212788516617024 14.2164393475970794, 220.3285570372971449 14.2449142697162543, 220.3357705557098143 14.2733966112673905, 220.3430038919728702 14.3018838043373702, 220.3501936696853534 14.3303777594724142, 220.3574521197704996 14.3588750715236309, 220.3646056907982995 14.3873809839935713, 220.3714125046764707 14.4159027845413750, 220.3785545330334514 14.4444198669506587, 220.3856337203785074 14.4729600246978407, 220.3927611377524443 14.5015207375726973, 220.4001050934609509 14.5300802439584977, 220.4070157681905755 14.5586581172829845, 220.4141741432308095 14.5872338303264506, 220.4213520871849141 14.6158142500114394, 220.4283400945614630 14.6444056727811596, 220.4351961118798897 14.6730063437207310, 220.4419879938532461 14.7016142082228782, 220.4491297929428981 14.7302168129408759, 220.4562863979076610 14.7588242338492535, 220.4632064462008714 14.7874440135878071, 220.4702124056549906 14.8160664517127341, 220.4773075834508518 14.8446914417330778, 220.4839436386864122 14.8733354359420638, 220.4909400903970891 14.9019738273440865, 220.4976830000880739 14.9306250291691658, 220.5046871348686750 14.9592735965149828, 220.5120298151077236 14.9879172093816564, 220.5191431519799039 15.0165728860575438, 220.5262490346293021 15.0452192621456042, 220.5332207140164940 15.0738593391697986, 220.5401179893822246 15.1025068648033880, 220.5471624568289997 15.1311551999620360, 220.5542495222690604 15.1598074720371656, 220.5611462413826303 15.1884706315084692, 220.5679511426332340 15.2171417190662908, 220.5747134505176348 15.2458192561079890, 220.5815516684503450 15.2744996976014473, 220.5883461731253874 15.3031866064603737, 220.5952718642558068 15.3318669232528215, 220.6021707513029355 15.3605449415493212, 220.6091175731324370 15.3892267260807643, 220.6161856753946324 15.4179100901230601, 220.6230988133778794 15.4466032396069934, 220.6301581991951650 15.4752972166398166, 220.6372147493088676 15.5039964428243238, 220.6444441173819655 15.5326957055445494, 220.6513662352306255 15.5614092260747796, 220.6584249247968899 15.5901238420788903, 220.6656150398821978 15.6188559149160699, 220.6725666950571849 15.6476172350376039, 220.6794748557452692 15.6763848777368864, 220.6865817603947448 15.7051516699670355, 220.6936357219268530 15.7339250504649577, 220.7007661075990370 15.7627011861934037, 220.7078723698223257 15.7914830405681812, 220.7148087277777790 15.8202749132805156, 220.7215739629540110 15.8490768264030688, 220.7283696406998388 15.8778828200969766, 220.7350802981803497 15.9066906070165039, 220.7416702149446621 15.9355009309045688, 220.7481918200303994 15.9643182514411510, 220.7548889450912384 15.9931353700775798, 220.7613380772241953 16.0219647647033483, 220.7677626895963670 16.0507998367200386, 220.7746364759823621 16.0796266326420110, 220.7812760232888820 16.1084652723297452, 220.7879783038013954 16.1373070026573338, 220.7945420931276601 16.1661577372383469, 220.8003749787557979 16.1950206146459834, 220.8065617770233189 16.2238629585585379, 220.8128621962586067 16.2527069130919699, 220.8191817783076658 16.2815552455657553, 220.8255725903351845 16.3104064260858870, 220.8322066932024370 16.3392554115519708, 220.8387268830609855 16.3681126611654619, 220.8455734890393387 16.3969652843257201, 220.8521103356239621 16.4258318846550289, 220.8587076065097392 16.4547016259001531, 220.8645847861091625 16.4836114738970636, 220.8712379212902022 16.5125184939384688, 220.8780366530769754 16.5414260976919891, 220.8844439642249426 16.5703499435244410, 220.8910779639868736 16.5992719914096014, 220.8980535532646456 16.6281888885597589, 220.9049801592676090 16.6571120172564200, 220.9120543712106723 16.6860356421274822, 220.9194018676946314 16.7149560938374400, 220.9275853959155995 16.7438569741192573, 220.9337514394953814 16.7728073784391256, 220.9389458502036803 16.8017760251284329, 220.9442633220138248 16.8307458475437279, 220.9495797699727291 16.8597204500586813, 220.9576980262959296 16.8886184324824242, 220.9646433114295974 16.9175552949130577, 220.9706915457650780 16.9465229737779737, 220.9797360850323855 16.9754084989699301, 220.9858503433434009 17.0043838123042050, 220.9958092375155729 17.0332524232458873, 221.0051547335982036 17.0621516661764971, 221.0123955262187678 17.0911251846374519, 221.0184945335432474 17.1201365064761539, 221.0265358816035928 17.1490962372719267, 221.0342592253194596 17.1780698849983899, 221.0416971727682380 17.2070564924296505, 221.0492649291077214 17.2360440208405272, 221.0574163923749325 17.2650193214497740, 221.0642376488161744 17.2940378145763525, 221.0712507676574603 17.3230554066094271, 221.0750035062377208 17.3521530122707013, 221.0833825988925696 17.3811014280375105, 221.1012000644046509 17.4097816163127987, 221.1234697965101645 17.4383372243239663, 221.1446009054772617 17.4669299946672929, 221.1659814117942346 17.4955196829087960, 221.1862074954466379 17.5241471727198963, 221.1957570597425047 17.5530905107879924, 221.2038686917591974 17.5820804814770568, 221.2080601841900318 17.6111893255309795, 221.1988433217773036 17.6407165962590256, 221.1916363252985036 17.6702144710442255, 221.1877485889076809 17.6996199313129061, 221.1891656918670037 17.7288761976824603, 221.1968354294687913 17.7579563475155240, 221.2025406653730215 17.7870977089870159, 221.2096147695653201 17.8162040253518192, 221.2165160144454603 17.8453198053554338, 221.2224942250372237 17.8744666958604519, 221.2277119721113934 17.9036399876070469, 221.2332821024614873 17.9327909627808992, 221.2383170207892249 17.9619443244375567, 221.2442905429176676 17.9910751116440970, 221.2498363552460887 18.0202227058669280, 221.2557305329598307 18.0493647450156516, 221.2621416431596799 18.0784963863439252, 221.2691430205308336 18.1076155304318078, 221.2754988091505197 18.1367577198945398, 221.2813337868578287 18.1659193359031335, 221.2877855767731887 18.1950676779960361, 221.2953253954281365 18.2241907180674119, 221.3013599379729328 18.2533629946000495, 221.3064374135869343 18.2825671410003530, 221.3124537532020213 18.3117487397487686, 221.3182281062903485 18.3409416696727341, 221.3250634190554251 18.3701085798518697, 221.3330656596799031 18.3992464481771663, 221.3374356808525647 18.4284927545661539, 221.3395300095251912 18.4578084755441338, 221.3458224373307246 18.4870083936197460, 221.3522630305629093 18.5162084244384424, 221.3577068641920107 18.5454412769644357, 221.3641904027647058 18.5746487548991901, 221.3715279113331178 18.6038361782572075, 221.3767990325112009 18.6330869316119241, 221.3800267736432659 18.6624002608480133, 221.3827362012217748 18.6917325592284307, 221.3870286300991097 18.7210239622508823, 221.3954345647359503 18.7502025136229946, 221.3995412875319175 18.7795077425839771, 221.4052686290156089 18.8087667835239962, 221.4116141406183260 18.8380079578304738, 221.4182075524130653 18.8672463620028914, 221.4234075464069917 18.8965286224053557, 221.4297424897585813 18.9257828880718897, 221.4381330035353130 18.9549830454225763, 221.4437786011409628 18.9842653899860636, 221.4516916823562553 19.0134876142634610, 221.4581724334677517 19.0427547245433537, 221.4643258335165683 19.0720353410303787, 221.4703040024018605 19.1013190922888008, 221.4757366352769736 19.1306161364696443, 221.4827138452384645 19.1598736469144661, 221.4886341156465619 19.1891653109675993, 221.4939175151725124 19.2184791926537457, 221.4996824222843372 19.2477836348834508, 221.5040993847280220 19.2771303360983666, 221.5096515244819102 19.3064491172807706, 221.5157897919053198 19.3357555187522046, 221.5254028690784764 19.3649680591620559, 221.5379303710355430 19.3941024987874222, 221.5502966625255965 19.4232455910307031, 221.5569858010043731 19.4525532672247863, 221.5662602301570416 19.4817920506938584, 221.5778712909811645 19.5109689307779881, 221.5906471456263773 19.5401169398491810, 221.6024846425621888 19.5692955530695549, 221.6125339523005664 19.5985288924105312, 221.6228556391052962 19.6277586118567875, 221.6323660626076730 19.6570154156721202, 221.6415036194281072 19.6862868957955186, 221.6440994496165331 19.7157478620347923, 221.6431790142311513 19.7453121776283353, 221.6474316282330221 19.7747340489961303, 221.6570225245225174 19.8040091392092137, 221.6647075508695082 19.8333421333557389, 221.6736770574902664 19.8626428790710392, 221.6816534358866875 19.8919757276629383, 221.6864937930701558 19.9214011979869525, 221.6879797049289209 19.9509252780549389, 221.6950232773449443 19.9803103315518520, 221.7007288046107192 20.0097516794640704, 221.7040268219716665 20.0392648174781414, 221.7074732178250542 20.0687776378866189, 221.7106187017003549 20.0983027921591741, 221.7176740679890941 20.1277217371706669, 221.7230474806044356 20.1571919248215679, 221.7277670535394805 20.1866843938526301, 221.7319372793065497 20.2161961795330143, 221.7405646672224293 20.2455863928381312, 221.7463882445141508 20.2750552241943964, 221.7538847958166457 20.3044764360793124, 221.7622793455343242 20.3338762064548320, 221.7701565146116707 20.3632943759725151, 221.7734189146283370 20.3928463602206236, 221.7781702147772194 20.4223602164826765, 221.7857704918945672 20.4517976945089401, 221.7905756424046331 20.4813176640664665, 221.7934115372622443 20.5108968160158120, 221.7963450989159071 20.5404769505775811, 221.8001359603279354 20.5700367281890628, 221.8054088754265081 20.5995586336503891, 221.8103228716607873 20.6290943849494539, 221.8166331240383329 20.6585946947209713, 221.8221241242964936 20.6881217626415683, 221.8259241658649898 20.7177000295338338, 221.8288535881722225 20.7473064169434060, 221.8317732953119048 20.7769167504077252, 221.8434864832525193 20.8062842965649040, 221.8548980732984148 20.8356638511278476, 221.8497146824853701 20.8655018098821827, 221.8425379707960872 20.8953868195347248, 221.8373773924683974 20.9252182013111181, 221.8382192560088129 20.9548855526717617, 221.8489009231472266 20.9842827887193870, 221.8672566919577207 21.0134697677843576, 221.8797273719325744 21.0428242377920007, 221.8887999810042686 21.0722772505930465, 221.8917645082245826 21.1019045711431907, 221.8997328109844602 21.1313958605496310, 221.8990926618291724 21.1611280411137237, 221.9019993444164811 21.1907616766640849, 221.9051040779272626 21.2203933633164255, 221.9093557913321320 21.2499967314855986, 221.9134297178846396 21.2796086471933421, 221.9116007489075173 21.3093879023960717, 221.9032882877899908 21.3393495525534895, 221.9060520607352771 21.3690080227605748, 221.9051334272910481 21.3987714956553354, 221.9034009241744343 21.4285605665808703, 221.9100285267176105 21.4581261493741309, 221.9160069827211714 21.4877163657336219, 221.9238932399040038 21.5172577422916156, 221.9293998902381873 21.5468681209350876, 221.9330707636211457 21.5765324977498807, 221.9363254486283097 21.6062118074008929, 221.9410037369304973 21.6358555651428652, 221.9455408147354092 21.6655067257743461, 221.9489016120366500 21.6951936277865087, 221.9527587731917890 21.7248704150393621, 221.9568600871938884 21.7545531875111280, 221.9622411699627946 21.7842141222439700, 221.9689664639304851 21.8138417551273918, 221.9756209612246778 21.8434747837706063, 221.9818735094069382 21.8731222677031809, 221.9874059330027194 21.9027929105330124, 221.9923440429898562 21.9324832583258242, 221.9971277815419626 21.9621812611599090, 222.0022569686276483 21.9918732335909617, 222.0073470416925829 22.0215696931690523, 222.0125447730543442 22.0512545134973372, 222.0181706962175383 22.0809182668990545, 222.0238933056502901 22.1105828124295201, 222.0295305341456071 22.1402531168903707, 222.0351237484508715 22.1699280425233560, 222.0404257554211540 22.1996143288699344, 222.0459155989807130 22.2292988829795952, 222.0512924341140035 22.2589899133886711, 222.0566673648044116 22.2886843762515738, 222.0618862307206882 22.3183864694176712, 222.0670553472533015 22.3480957599216943, 222.0723717417823480 22.3778070085798433, 222.0777839748901954 22.4075189964093298, 222.0831798394412999 22.4372347713885887, 222.0886434003047896 22.4669520384429156, 222.0940816858582139 22.4966733208646978, 222.0994527850592419 22.5263997498348019, 222.1047812729934776 22.5561306496470415, 222.1101155305294128 22.5858646931989853, 222.1154152125551207 22.6156029721982748, 222.1204420127930348 22.6453400486665366, 222.1255646964550010 22.6750652359120757, 222.1305329997020408 22.7047979140034606, 222.1355847787701236 22.7345316112044280, 222.1406216272308427 22.7642689945996679, 222.1456386712231108 22.7940101865939404, 222.1506385132327352 22.8237551067842261, 222.1555893546876064 22.8535046094059879, 222.1605043394521033 22.8832583260641407, 222.1653877636704806 22.9130161310442269, 222.1701197628285342 22.9427889792997277, 222.1746776287420460 22.9725778901872602, 222.1789441576504203 23.0023778463962252, 222.1836557252892987 23.0321689614480754, 222.1902440398286274 23.0619126297839259, 222.1954526487301109 23.0916966954934288, 222.2010831637109618 23.1214725486922141, 222.2083216384725119 23.1512082124632634, 222.2139515806102850 23.1809904050361695, 222.2171221060486914 23.2108420163699627, 222.2209885173431871 23.2406820491138504, 222.2264371355994967 23.2704868989222291, 222.2313264837684983 23.3003099104321585, 222.2360295055708832 23.3301410280497308, 222.2416143589899207 23.3599515095395667, 222.2470280979290180 23.3897696783524971, 222.2519457695078415 23.4196042623493632, 222.2572284978178629 23.4494320946218942, 222.2625351292319067 23.4792623412355930, 222.2678234450957575 23.5090961313971469, 222.2731187338746679 23.5389287176773294, 222.2783913237996956 23.5687606663922864, 222.2836896458202887 23.5985949595753439, 222.2889783774910200 23.6284325359269758, 222.2942692541417387 23.6582730742638745, 222.2995474628026216 23.6881169629623720, 222.3048186546048441 23.7179640408533103, 222.3100880876171175 23.7478141608096216, 222.3153559270981532 23.7776673079717895, 222.3206150332030404 23.8075236678525748, 222.3258698866435168 23.8373906038255718, 222.3311162163473966 23.8672686258960880, 222.3363674375100345 23.8971494473812527, 222.3416002240587375 23.9270336833286592, 222.3468409731699182 23.9569206200426699, 222.3520781787404417 23.9868105567601511, 222.3572950908845485 24.0167039333042780, 222.3625011870320805 24.0466004896445860, 222.3677192511185581 24.0764996045117954, 222.3729424320191015 24.1064014556798760, 222.3781468771423704 24.1362901048424803, 222.3833649201491767 24.1661637831187051, 222.3885678890137001 24.1960407688332424, 222.3937637687527626 24.2259208372428745, 222.3989420319153396 24.2558042638083400, 222.4041440838418282 24.2856899311823646, 222.4093321917397645 24.3155788396142292, 222.4144990636221451 24.3454711774863419, 222.4196730904269543 24.3753661752947544, 222.4248346881902307 24.4052643501693147, 222.4300062062717132 24.4351764710664803, 222.4351870687680162 24.4651031621802808, 222.4403525020867676 24.4950330549062940, 222.4455026491757792 24.5249661348580901, 222.4506599244405436 24.5549017979669024, 222.4558229849399140 24.5848400707973234, 222.4609842278302381 24.6147811468647504, 222.4661284181207179 24.6447254265187077, 222.4713101840497416 24.6746714423507356, 222.4764591914561720 24.7046210641846464, 222.4815193387960335 24.7345653487702606, 222.4865942845428890 24.7645009503149645, 222.4916659845742402 24.7944393662112184, 222.4967339978794314 24.8243805976587915, 222.5017992758810976 24.8543246132578624, 222.5068766617123117 24.8842710086783008, 222.5120706242933011 24.9142169964455888, 222.5176992594136323 24.9441541158756088, 222.5230551169359501 24.9741011721433921, 222.5290723867522047 25.0040333259218883, 222.5331869879559576 25.0340250877719299, 222.5376183126456908 25.0640178059903214, 222.5426224342267290 25.0939979417774381, 222.5478384861640961 25.1239750739483441, 222.5527734021357276 25.1539622860461627, 222.5574433522509423 25.1839591349760674, 222.5625189750431332 25.2139478159431718, 222.5680865705771225 25.2439260391509634, 222.5750931585015167 25.2738686682064397, 222.5818713705537277 25.3038199264691315, 222.5873131975623664 25.3338052353980103, 222.5917661569066013 25.3638151369705831, 222.5953573557681580 25.3938504355635146, 222.5981423237566332 25.4239096057939236, 222.6021066629562029 25.4539400323271892, 222.6070875480329789 25.4839460669213196, 222.6120740674625722 25.5139544753542999, 222.6170732825590335 25.5439650649896528, 222.6222362522800324 25.5739738306894786, 222.6271684386293543 25.6039912012273092, 222.6335610291737623 25.6339683652455435, 222.6407584509559001 25.6639224326588149, 222.6425063814833436 25.6940230383128174, 222.6465820115638792 25.7240645598688396, 222.6516161452648817 25.7540832404217248, 222.6567612330741497 25.7841014576707011, 222.6622771705746118 25.8141123513063775, 222.6675096863310159 25.8441331729110537, 222.6724462652234706 25.8741642349645424, 222.6771134454122318 25.9042048235666122, 222.6827850674766580 25.9342363968775302, 222.6931165988777366 25.9641633520258601, 222.6998107997744683 25.9941885112906661, 222.6993812296677504 26.0244039700569125, 222.7004828501633256 26.0545812838950326, 222.7068412637907215 26.0846224342125836, 222.7151250248850261 26.1146151271205404, 222.7223428546015214 26.1446381900068268, 222.7233614602515672 26.1748271205919316, 222.7251698747904243 26.2049974649508677, 222.7297580672415620 26.2350818940931845, 222.7350401377152593 26.2651345787107786, 222.7397478569982070 26.2952047135490368, 222.7441890163588027 26.3252841708795238, 222.7490415028016457 26.3553551043257102, 222.7538245647999986 26.3854301586473454, 222.7585301990661719 26.4155095328346015, 222.7633657664723330 26.4455877699967168, 222.7688255310053194 26.4756518789740127, 222.7734841245274708 26.5057393017668623, 222.7804994013292799 26.5357699997111389, 222.7892222416250263 26.5657611258525037, 222.7934201840520245 26.5958734025664825, 222.7976525279802047 26.6259869814647203, 222.8061529184204801 26.6559906322473736, 222.8082111146133855 26.6861657600068938, 222.8108775599047249 26.7163270320472712, 222.8149933055477163 26.7464524254111709, 222.8202949000982755 26.7765488881277172, 222.8301151846121400 26.8065289627933829, 222.8347576221901534 26.8366503143100523, 222.8375201821876885 26.8668265546276395, 222.8418110343396847 26.8969648288669170, 222.8465067625856193 26.9270946182803321, 222.8524537725384675 26.9571937291370851, 222.8574636362439207 26.9873195346867831, 222.8620005207342842 27.0174598522939284, 222.8671731236854612 27.0475856079338897, 222.8726715768086990 27.0777049164258159, 222.8775474502902796 27.1078426359435340, 222.8816119755332181 27.1380004347667914, 222.8869882261955695 27.1681224764912024, 222.8926632525074183 27.1982387554859777, 222.8956791014889518 27.2284267497753270, 222.8990635443852568 27.2586071020030083, 222.9037992898206824 27.2887541107411238, 222.9093687180935035 27.3188813346966022, 222.9147563759039485 27.3490153396147129, 222.9196081766303905 27.3791653776126509, 222.9243436031770216 27.4093204644372115, 222.9286080088542121 27.4394937878516565, 222.9336119064177808 27.4696539013430332, 222.9389694547837451 27.4998067414069318, 222.9467971585075929 27.5298969245199565, 222.9536775696169855 27.5600138137988289, 222.9590786061792187 27.5901713708442351, 222.9649273858052254 27.6203191385870497, 222.9707788876332302 27.6504687616998091, 222.9779598201737087 27.6805854587132423, 222.9832825767003328 27.7107527614628246, 222.9817568406568853 27.7410883808228768, 222.9874565001069868 27.7712230016882522, 222.9936425870742482 27.8013468434569759, 222.9960558499005003 27.8315712512584490, 223.0003219092032793 27.8617491055375837, 223.0057706188702582 27.8918979783849821, 223.0108205033237994 27.9220591651377141, 223.0159954833848133 27.9522189808714110, 223.0194101868325163 27.9824265788414159, 223.0236278179942246 28.0126150871196664, 223.0270783276952216 28.0428260124679731, 223.0284527756684838 28.0730933626770600, 223.0310594806987865 28.1033303987746379, 223.0333322930894724 28.1335778457447887, 223.0341180624720323 28.1638655435949694, 223.0377939193720067 28.1940800787344692, 223.0423453188257099 28.2242737368825765, 223.0473563566852704 28.2544573009177533, 223.0475810350740460 28.2847663252395058, 223.0468242129837790 28.3151021837157657, 223.0494697180606067 28.3453669498318845, 223.0551226685687141 28.3755718417018308, 223.0596599616456501 28.4058071837445603, 223.0644130602050836 28.4360386740747870, 223.0699211842023431 28.4662524123565284, 223.0775607745895570 28.4964128803651526, 223.0834267667080439 28.5266207293507961, 223.0946602925923514 28.5566915950313671, 223.1011121708191638 28.5868875504529001, 223.1057514664018413 28.6171320328370165, 223.1092717803553569 28.6474026359030205, 223.1131858521137303 28.6776599785361803, 223.1175135978419064 28.7079082719772458, 223.1224011054471248 28.7381437355216320, 223.1295408824391302 28.7683226027755978, 223.1386439433995577 28.7984522355940413, 223.1466096978197129 28.8286128295860884, 223.1512039324807120 28.8588623697961175, 223.1491767764528049 28.8892849121626583, 223.1495096696987730 28.9196477562610816, 223.1531510946215917 28.9499227439951632, 223.1593084066995232 28.9801302235178468, 223.1671463731093752 29.0102958476445423, 223.1733378307814633 29.0405055589089827, 223.1762893691844170 29.0708005572484467, 223.1797411591123534 29.1010841479297575, 223.1842105395181193 29.1313429880265531, 223.1897492654337611 29.1615757529559332, 223.1968336860489330 29.1917701214391982, 223.2007111469344807 29.2220488212368714, 223.2065521127375689 29.2522700368019706, 223.2119706505060890 29.2824949298750319, 223.2143181739405975 29.3128005757675894, 223.2145049372267067 29.3431632754399629, 223.2130727083799400 29.3735688214291137, 223.2169012501132954 29.4038404960306856, 223.2205048495329152 29.4341193922091762, 223.2231762087316156 29.4644236196080946, 223.2286000314316823 29.4946587355534788, 223.2310513877485789 29.5249714294954018, 223.2344723717499733 29.5552689830075757, 223.2401364427243493 29.5855193241839665, 223.2452585570237318 29.6157849349408515, 223.2505202413070720 29.6460483698967572, 223.2559231593347135 29.6763095798524041, 223.2644027871221795 29.7064934052381062, 223.2627241956078876 29.7369385494086700, 223.2645402237930057 29.7672955192597151, 223.2677335536144199 29.7976186173721906, 223.2703656238754206 29.8279573493982966, 223.2756273227971349 29.8582220782055394, 223.2844765439493528 29.8883879235143297, 223.2937085860437492 29.9185452807982983, 223.2973081015805406 29.9488478138785723, 223.2936631005052845 29.9793362624003343, 223.2960666519461199 30.0096716675618822, 223.3009400212254150 30.0399455321170663, 223.3025870375495288 30.0703026550889234, 223.3057019420284917 30.1006237111833883, 223.3089129363760605 30.1309435671565922, 223.3150049755914779 30.1612022619481941, 223.3234217233952279 30.1914144151318169, 223.3234210094943535 30.2218413027351538, 223.3217310036492904 30.2523119774260358, 223.3241338861791974 30.2826801517841027, 223.3291361017602412 30.3129838017813924, 223.3335691814666006 30.3433030311341483, 223.3376879267507036 30.3736313903895585, 223.3415822010214242 30.4039665939569446, 223.3428527313638483 30.4343692093283416, 223.3463046577959119 30.4647139764403754, 223.3516152151367749 30.4950088855972581, 223.3563567921310096 30.5253193044814317, 223.3591806847722694 30.5556792231967940, 223.3633551843234670 30.5860062097663246, 223.3673017153174101 30.6163400617374002, 223.3700134643006265 30.6467061128488147, 223.3771472685137383 30.6769619187146567, 223.3826102810353404 30.7072608971903769, 223.3886354466583271 30.7375468061244703, 223.3920631849453571 30.7678988088006875, 223.3948340483456434 30.7982679488012323, 223.3964740350774605 30.8286665606172718, 223.3988015833816974 30.8590488763677833, 223.4054640309857689 30.8893233212344889, 223.4110113026206079 30.9196268339053155, 223.4122686163119340 30.9500391594668827, 223.4185862540229266 30.9803254154219658, 223.4253672463590590 31.0106010422639322, 223.4280655144074501 31.0409802449639898, 223.4338793837549417 31.0712782786190367, 223.4368728738980963 31.1016439799744369, 223.4352648020414733 31.1321259385368165, 223.4366125414503301 31.1625346166880348, 223.4396705389226838 31.1929014229039439, 223.4456438373482570 31.2231963322768493, 223.4505941710129946 31.2535177729686175, 223.4547715708266935 31.2838594812816666, 223.4577739516391830 31.3142314599850486, 223.4600217044295221 31.3446231542552987, 223.4635365292320728 31.3749880885431551, 223.4679250724919939 31.4053363295084900, 223.4717664816919864 31.4356991045685845, 223.4748831801429390 31.4660808082941479, 223.4799487654643713 31.4964148775685189, 223.4840292327695579 31.5267743476384155, 223.4865411911619333 31.5571736951986388, 223.4883032670517196 31.5875924900986753, 223.4923952323851495 31.6179542209252666, 223.4970672524644328 31.6483023929509031, 223.5030692210505094 31.6786209217388759, 223.5066616283142196 31.7090028002147264, 223.5106210413823362 31.7393763676496015, 223.5132764001971566 31.7697830874807003, 223.5179240398600484 31.8001411574942452, 223.5195254158442140 31.8305755440645903, 223.5239434375313579 31.8609408591624259, 223.5282886785034577 31.8913087442676790, 223.5322519417453861 31.9216868480441498, 223.5347617094257373 31.9521016879863211, 223.5380353071004436 31.9824836882649954, 223.5428282743981185 32.0128133802272430, 223.5480508269670565 32.0431332222472349, 223.5497441169615058 32.0735409978522270, 223.5553057804664263 32.1038539700301016, 223.5598384268535881 32.1341930832612661, 223.5624288051742212 32.1645807930955741, 223.5652337762755906 32.1949638621259524, 223.5678286491418589 32.2253527382871567, 223.5695560421223433 32.2557635380633627, 223.5752088569645366 32.2860971656535369, 223.5778937031500675 32.3165239135065860, 223.5812675754343957 32.3469343758281980, 223.5848566389719849 32.3773401796878062, 223.5891675860983128 32.4077288948879030, 223.5927666199704902 32.4381356808599435, 223.5971664748019236 32.4685234266738192, 223.6018897195259569 32.4989038349033379, 223.6036667978909236 32.5293570670729224, 223.6064949112673332 32.5597850850799659, 223.6116324578020453 32.5901446220759752, 223.6140456300390724 32.6205582901027782, 223.6180710912269092 32.6509330396607425, 223.6211992806995852 32.6813302883187689, 223.6282270303249788 32.7116327514627514, 223.6317729060406236 32.7420209117044507, 223.6357729383524600 32.7723985009571308, 223.6368325295503041 32.8028483884673605, 223.6411096371763563 32.8332202356979082, 223.6439910882040749 32.8636266156867123, 223.6481310195877086 32.8940028179196347, 223.6509936165338104 32.9244106061581405, 223.6553899144079480 32.9547815456590243, 223.6596968044144944 32.9851551442577957, 223.6612145715821498 33.0155969875223576, 223.6650693763939444 33.0459824801913911, 223.6692659409714850 33.0763601294171679, 223.6716695758493643 33.1067817005986456, 223.6751523009409368 33.1371775151216497, 223.6790842134866750 33.1675628698264759, 223.6817299554946317 33.1979800536689709, 223.6840029478087502 33.2284069152961834, 223.6869551521492383 33.2588177146786137, 223.6903565456445051 33.2892180314227915, 223.6936834072822933 33.3196205103363639, 223.6971029050550612 33.3500211100688588, 223.7007701587213830 33.3804160897484863, 223.7044837207082537 33.4108103024752126, 223.7075120344256334 33.4412213365115178, 223.7108808174372996 33.4716244979182633, 223.7150218024641788 33.5020111063703752, 223.7185127413576993 33.5324154287190694, 223.7220915424194345 33.5628179458101741, 223.7256487173189896 33.5932212766860943, 223.7286216236610983 33.6236389013519670, 223.7320216440893148 33.6540465564206670, 223.7369843538813257 33.6844170563033813, 223.7396632576619027 33.7148425178093021, 223.7417605710046757 33.7452821084065206, 223.7453063421154127 33.7756872889352167, 223.7483122061553047 33.8061098598384433, 223.7517120547620664 33.8365277389875274, 223.7558255243394569 33.8669288053235746, 223.7594854651125900 33.8973409052722801, 223.7624929837062950 33.9277687623950541, 223.7659937331060291 33.9581850448707883, 223.7683016722576497 33.9886299134953447, 223.7717654102397944 34.0190474189640639, 223.7746851068746992 34.0494780279845841, 223.7778200650010660 34.0799036630295475, 223.7815767483879199 34.1103144298280796, 223.7849598453518638 34.1407339699114161, 223.7886890994549276 34.1711454269250154, 223.7929755563177423 34.2015437888474807, 223.7950123858878442 34.2319956601868967, 223.7976542511011360 34.2624332578238366, 223.8008059636455869 34.2928588582611269, 223.8038189435971788 34.3232878312866134, 223.8070197677527915 34.3537124336828299, 223.8102919260166743 34.3841354218809698, 223.8132599669528702 34.4145658933153129, 223.8172826870554388 34.4551387030861491))) +MULTIPOLYGON (((225.6590116066086011 15.2022751781288630, 225.8184285319980802 15.1938011437427107, 225.9815607786718488 15.1849941022049926, 226.1537479980599414 15.1755636254992901, 226.3305987100000323 15.1657156107401683, 226.5161948590464078 15.1552163682550063, 226.7132602789062901 15.1438893478077468, 226.9261988964304351 15.1314506126365309, 227.1499418813374973 15.1181384848977540, 227.3887605669753214 15.1036654662162260, 227.6457676404389190 15.0877902093839538, 227.9238726251499827 15.0702639425568172, 228.2357698245607480 15.0502006375273023, 228.5715407538234274 15.0280865132481658, 228.9475901297275584 15.0027161002309199, 229.3712716345860088 14.9733679200999035, 229.9511930049727368 14.9320537002732596, 230.4883212838945781 14.8922542020580906, 231.1136532000215027 14.8443022653531198, 231.8633228532418400 14.7845460924271297, 232.7891574029212052 14.7073522924876734, 233.9942664759018385 14.6013042631466625, 234.4965294627785397 14.5504706067190579, 234.5208110638523067 14.5099689962529279, 234.5313044299073795 14.4803171724793245, 234.5416131312027801 14.4506850418484909, 234.5520779977871371 14.4210415870330468, 234.5623431784188710 14.3914232575198362, 234.5724238845463105 14.3618286535965378, 234.5827882789665750 14.3322149027208052, 234.5929578113344860 14.3026258488927525, 234.6030683507545973 14.2730490546493467, 234.6134058750884037 14.2434583659015832, 234.6236678287416737 14.2138814837024583, 234.6339787538766188 14.1843070299267406, 234.6442862284248463 14.1547369879349692, 234.6547188863688120 14.1251597335973766, 234.6648922775195842 14.0956130658841658, 234.6753260761099114 14.0660495235981191, 234.6864368112473471 14.0364311267002382, 234.6957686604494029 14.0069820247430616, 234.7061404536003124 13.9774449561658081, 234.7168562105069327 13.9478834920582333, 234.7270224975896724 13.9183791086254836, 234.7372048991153406 13.8888802351922376, 234.7477636671920322 13.8593540754838518, 234.7584817061348872 13.8298204455798839, 234.7691873583667359 13.8002949950470803, 234.7803650551794590 13.7707336568590062, 234.7916750860140098 13.7411673885779937, 234.8029058064372521 13.7116154576392404, 234.8142170604288594 13.6820633420075843, 234.8253048384432020 13.6525386874369357, 234.8363381012698596 13.6230261366839027, 234.8474859593540600 13.5935103445255336, 234.8586521615224001 13.5639727104256469, 234.8698086919266927 13.5344171571079581, 234.8810402760219631 13.5048618785192716, 234.8921633384625238 13.4753235398173157, 234.9036036680469692 13.4457635458124809, 234.9148787480722262 13.4162256650294367, 234.9262976243366836 13.3866818976443849, 234.9378525857910063 13.3571329686720333, 234.9491438202866220 13.3276151019577185, 234.9605851734783073 13.2980908305402235, 234.9714051171723952 13.2686329662724400, 234.9829107510691983 13.2391230511010320, 234.9953247709164827 13.2095381986057330, 235.0050945465017662 13.1801996367152601, 235.0136741450404543 13.1509757163783760, 235.0235876197880316 13.1216383624306303, 235.0329511591612004 13.0923577945443821, 235.0428529669675299 13.0630357717848380, 235.0521842656136187 13.0337723688292204, 235.0625643579875259 13.0044215484787493, 235.0718456764101347 12.9752026574268378, 235.0824545378013113 12.9458957824717462, 235.0941279042510530 12.9165005022008916, 235.1065853378691486 12.8870421851470827, 235.1158685212187436 12.8578770132341944, 235.1267432519177305 12.8285760999852005, 235.1379548440312988 12.7992524166110737, 235.1493796188802321 12.7699171276532759, 235.1597708587534044 12.7406822108994700, 235.1712990013349156 12.7113527637885788, 235.1827906320188504 12.6820275613200071, 235.1941656390224580 12.6527141312217779, 235.2050650309431603 12.6234509249003697, 235.2163653275223396 12.5941593716165769, 235.2278129164640745 12.5648622450461041, 235.2385899990798066 12.5356327691044349, 235.2509196533849263 12.5062719956791586, 235.2633495959182142 12.4769099908336152, 235.2728707652433116 12.4478157344413844, 235.2843018911919444 12.4185583774315713, 235.2958612619559915 12.3892706547972598, 235.3093903391809363 12.3597895148684760, 235.3187948284902404 12.3306840978547765, 235.3306973300513221 12.3013633115279610, 235.3409552423264586 12.2721967439647628, 235.3501958576858613 12.2431283054920037, 235.3613910460340719 12.2138932347157887, 235.3730447116263065 12.1846249559616240, 235.3841076194497646 12.1554168855521159, 235.3951457454282092 12.1262186343150464, 235.4062396923713436 12.0970204529142116, 235.4175034828008393 12.0678123993142545, 235.4293245043034517 12.0385625702422665, 235.4421181444995455 12.0092341707538317, 235.4552959271689474 11.9798795410635694, 235.4690679156001920 11.9504801024310261, 235.4834853052213646 11.9210313918726634, 235.4960974300517194 11.8917506964105861, 235.5075487335812454 11.8625807321371077, 235.5232045964962140 11.8330462747001270, 235.5346764929361711 11.8038936247787731, 235.5484769103933615 11.7745459193172586, 235.5600500490689910 11.7454032067389971, 235.5703027538093295 11.7163850530546778, 235.5839099151444316 11.6870783106887632, 235.5954261043269753 11.6579642551851776, 235.6091634785259430 11.6286620492115951, 235.6216120131801404 11.5994816340206004, 235.6324251515997616 11.5704534114552082, 235.6427681559864027 11.5414744763687072, 235.6568231608829649 11.5121696292982847, 235.6720114138059898 11.4827667117629471, 235.6855534378352104 11.4535169164043698, 235.6985976230074584 11.4243190426234822, 235.7101697741603061 11.3952586967556808, 235.7212865677433342 11.3662463475955882, 235.7336848210081257 11.3371294098704496, 235.7467824959671248 11.3079591641786763, 235.7608802892358426 11.2787093286096738, 235.7716222748915129 11.2497620499109825, 235.7842032100647600 11.2206891920149054, 235.7973313753711295 11.1916028404769996, 235.8104867447166839 11.1625225099613452, 235.8248992522363210 11.1333405976275657, 235.8395596186140324 11.1041455608978925, 235.8525266395224662 11.0751071281319753, 235.8667638348769628 11.0459661778884932, 235.8799840523980720 11.0169226049946332, 235.8933575463018997 10.9878741537475353, 235.9056857922247730 10.9589253856028837, 235.9193690857337913 10.9298457604617205, 235.9332202571170001 10.9007399237256113, 235.9474135600875115 10.8716127613864284, 235.9606689831861672 10.8425757207401006, 235.9745891351863349 10.8134893032569899, 235.9749642465138209 10.7716809281121115, 234.3062264801246215 10.9140277809663164, 233.0568672341268268 11.0146280042103246, 232.0879579900140470 11.0891193379889383, 231.2922763752978028 11.1479476252960712, 230.6222024977036256 11.1958368476612140, 230.0451126661331500 11.2358585089279366, 229.5399124326933418 11.2699591633018521, 229.0910977852267933 11.2995144425208256, 228.6886580791888548 11.3254217054343105, 228.3230615139313500 11.3484629748790748, 227.9885578563481374 11.3691297953353825, 227.6794424865351800 11.3878696987312100, 227.3925662525225562 11.4049521734577617, 227.1244248889419168 11.4206460692728164, 226.8725374557904217 11.4351462062810540, 226.6348499723003727 11.4486118924843705, 226.4089327375767766 11.4612113075361997, 226.1941018513785480 11.4730141135445951, 225.9885536989861805 11.4841415383496983, 225.7906841315510462 11.4946974768467634, 225.5999034371527046 11.5047316362642924, 225.5366590428407676 11.5127499139751173, 225.5372155286837028 11.5505123386258806, 225.5385771173869216 11.5787917807373031, 225.5399422790694928 11.6070769021958249, 225.5412964706850119 11.6353683683259401, 225.5426724692719347 11.6636646542798825, 225.5440051181480214 11.6919712226446801, 225.5452754778033579 11.7202890826927817, 225.5466283640396057 11.7486089150217499, 225.5479733512320877 11.7769349109975465, 225.5492620732997580 11.8052693182655215, 225.5505841234978277 11.8336079601987194, 225.5519462019553600 11.8619505139251853, 225.5533034114788222 11.8902990653271896, 225.5546573357829629 11.9186535319933640, 225.5560296401821176 11.9470128979944885, 225.5574630380517647 11.9753825153277855, 225.5590145865995453 12.0037600937422599, 225.5604603602513691 12.0321483085082885, 225.5618766106162241 12.0605435905483933, 225.5632235046636538 12.0889478001605273, 225.5646322492728189 12.1173547927717884, 225.5660183351829744 12.1457685136433842, 225.5674524000941119 12.1741856511797124, 225.5688591210027312 12.2026097227448993, 225.5703066480778034 12.2310375312635973, 225.5717059626002481 12.2594635287660125, 225.5731135142524977 12.2878845469914122, 225.5745000480431770 12.3163122245770751, 225.5759250961868645 12.3447437585488196, 225.5773924999224107 12.3731789608056744, 225.5788485201462947 12.4016203465804544, 225.5803384550112014 12.4300657782762727, 225.5816851396154448 12.4585235859629435, 225.5830893136675286 12.4869843196153401, 225.5845898505328648 12.5154461391776994, 225.5860380816324664 12.5439157417238452, 225.5874589809734232 12.5723919342328792, 225.5889159822422414 12.6008720348057395, 225.5903500433967963 12.6293588187895907, 225.5917512819598585 12.6578527497401971, 225.5931498469038843 12.6863523975501753, 225.5945936511308787 12.7148554897243873, 225.5960004208644420 12.7433659092357914, 225.5974035727396938 12.7718820685236683, 225.5988234672666408 12.8004029993498278, 225.6002725682347716 12.8289353398050423, 225.6017372705671562 12.8574801026263330, 225.6031663907919835 12.8860320507559170, 225.6045230142199500 12.9145929257661702, 225.6058813437432775 12.9431592082911244, 225.6072542184839165 12.9717302815183047, 225.6086155626813365 13.0003073734616503, 225.6099855929491866 13.0288895207329229, 225.6113301413350882 13.0574783349659143, 225.6125573731443410 13.0860781699462745, 225.6138059179633331 13.1146685837733763, 225.6150812749465899 13.1432485812774420, 225.6162458519782774 13.1718393536475027, 225.6173776523386891 13.2004371911819636, 225.6185740510497624 13.2290374592872606, 225.6198200700041809 13.2576408579599132, 225.6210454851929796 13.2862507192776924, 225.6223709718760801 13.3148612908315283, 225.6236531533329810 13.3434793901493354, 225.6249325723329093 13.3721030820185831, 225.6260928567572819 13.4007285591032215, 225.6271536834223639 13.4293543931465571, 225.6282124972139798 13.4579858251888869, 225.6292645314285892 13.4866230739553483, 225.6301804105962958 13.5152723244987154, 225.6310913323260934 13.5439273004220890, 225.6319395686368807 13.5725907590492518, 225.6327541317145062 13.6012613101755644, 225.6337718649642170 13.6299275878090551, 225.6347506831084502 13.6586011866152237, 225.6357740723692018 13.6872915145011298, 225.6369158381051250 13.7159957103282348, 225.6377194029691964 13.7447214977765864, 225.6381065136039865 13.7734726404849450, 225.6384486634579218 13.8022312915639596, 225.6384696572111466 13.8310107208009665, 225.6377164794393764 13.8598327075708507, 225.6365675112162137 13.8886790652427319, 225.6366436889486238 13.9174718431418274, 225.6368569804845379 13.9462633389480182, 225.6372512893272528 13.9750446861622404, 225.6375598958670992 14.0038283677250330, 225.6379232729383091 14.0326147566449215, 225.6383897344348384 14.0614015134760155, 225.6384870229912565 14.0902113783666270, 225.6385225417334937 14.1190295454278179, 225.6386422674683558 14.1478489717101485, 225.6388548745616731 14.1766692294529761, 225.6393899644289718 14.2054792305965023, 225.6400017789805759 14.2342908119101423, 225.6406354379116408 14.2631066557045862, 225.6413569018558860 14.2919235676818044, 225.6418737897815276 14.3207556083426546, 225.6423091415276758 14.3495968327812928, 225.6427227612253432 14.3784443487517848, 225.6431399559387501 14.4072969248162668, 225.6435643091585348 14.4361543784162514, 225.6439996403331634 14.4650165186353359, 225.6444242554794926 14.4938843841154803, 225.6447387703332197 14.5227627774815407, 225.6449631350287177 14.5516507312391443, 225.6451722610784714 14.5805446133494030, 225.6453957579692826 14.6094429811145208, 225.6457542898072575 14.6383399809685368, 225.6462420940192146 14.6672358817340580, 225.6469402654511782 14.6961267415683761, 225.6476430843318326 14.7250225124654772, 225.6482912662952458 14.7539260617623214, 225.6489832267797624 14.7828326103256256, 225.6497656768799516 14.8117398861253111, 225.6506424444196739 14.8406387378099005, 225.6513629139793977 14.8695408561432583, 225.6517777322902418 14.8984629714063477, 225.6521804907180808 14.9273908337275234, 225.6524924020781384 14.9563282654052863, 225.6529946843869538 14.9852615950152952, 225.6535087791164358 15.0141994839657045, 225.6541740532657343 15.0431351470923698, 225.6549119926503124 15.0720723858902090, 225.6554983620026746 15.1010221054608973, 225.6560601547267595 15.1299724947379310, 225.6566877994991955 15.1589188520153222, 225.6590116066086011 15.2022751781288630))) +MULTIPOLYGON (((222.1624644986581814 22.8951608776491611, 222.3339278053147439 22.8936291249977337, 222.4918214735398294 22.8892887248560974, 222.6447347625093585 22.8849225118103874, 222.7860232522739352 22.8807537877385627, 222.9282491754742637 22.8764117840873134, 223.0766244984219497 22.8717204866312542, 223.2163755016696030 22.8671671507805847, 223.3566763952025553 22.8624540093662851, 223.4933003437754166 22.8577319700323365, 223.5898184185919604 22.8543578550741238, 223.6952462098100511 22.8505806048140343, 223.7986314112134494 22.8468004169646264, 223.8996071437270245 22.8430363019214759, 223.9985409791389088 22.8392789938655092, 224.0959564206264076 22.8355116831515161, 224.1910355953448857 22.8317716008955180, 224.2846905331636549 22.8280253855071535, 224.3794591431320669 22.8241662736667266, 224.4717633562828496 22.8203486473478740, 224.5633375179995141 22.8165001434515133, 224.6543476105477737 22.8126140286554602, 224.7440401314165683 22.8087272357695596, 224.8325041708505694 22.8048422966027005, 224.9212556591315035 22.8008911950998439, 225.0106581698765069 22.7968452216291411, 225.1000007997412240 22.7927430513065232, 225.1888277899536774 22.7886040403501653, 225.2781779860744393 22.7843853505198553, 225.3686923868877443 22.7800551110823477, 225.4590163590555392 22.7756725361697896, 225.5508196988385805 22.7711599175616826, 225.6422475001495513 22.7666030802101886, 225.7360430349211811 22.7618690698426107, 225.8308944078887066 22.7570178539048058, 225.9265645398400011 22.7520593284113843, 226.0249049679701727 22.7468968896814552, 226.1249454787566151 22.7415751879109003, 226.2278086015192287 22.7360312020369442, 226.3331090916952917 22.7302792144843444, 226.4411376184330038 22.7242978235364390, 226.5516842589036344 22.7180922185925418, 226.6656163593179940 22.7116078268158503, 226.7845301475643680 22.7047457109732385, 226.9071475647440082 22.6975670621508918, 227.0314410381741368 22.6901810095987315, 227.1839792061757635 22.6810029064036662, 227.3309878641620116 22.6719940160821523, 227.4852574295552756 22.6623834900507148, 227.6478981924533969 22.6520789916308729, 227.8244753455144860 22.6406976405487157, 228.0131819147794658 22.6283077428341599, 228.2162925672537597 22.6147123261545140, 228.4292029370799639 22.6001656944389318, 228.6562565745130939 22.5843249428905182, 228.9060279701273828 22.5665175964537390, 229.1825161010338832 22.5463403908074760, 229.4889073173454221 22.5234095910938485, 229.8235975094182777 22.4976688768649389, 230.1950353289553561 22.4682622756183576, 230.6140350097421958 22.4340362400728921, 231.0891086675366921 22.3938791162801358, 231.6395867000892963 22.3455627542399640, 232.2933600728475199 22.2857009540908528, 233.0468719139713585 22.2096336010235156, 233.0786160068223012 21.8362790738185488, 233.1128703125103243 21.4745535124936815, 233.1496154961199068 21.1131520453783281, 233.1847240764050753 20.7523849749798011, 233.2282694104284246 20.3912575382026056, 233.2729399482114445 20.0308241593004865, 233.3250709695567195 19.6705333692279147, 233.3796821891314153 19.3110185896687021, 233.4385722855595304 18.9512397884117547, 233.5048315554937517 18.5912746804041298, 233.5705679155844336 18.2318918456861674, 233.6451980358387175 17.8721782134278087, 233.7217275105666374 17.5133469216293420, 233.8008596200677118 17.1546858578329271, 233.8864271812514630 16.7969322128191010, 233.9697189392310577 16.4397036867625808, 234.0828109349569672 16.0803141029273924, 234.1849920604828981 15.7230496510434978, 234.2920854371644168 15.3662472678846687, 234.4024907287821406 15.0099336756868329, 234.5149128953590321 14.6540024086710705, 234.6379311549195563 14.2984584660047442, 234.7623775574046192 13.9436811555426505, 234.8942578953382849 13.5892102038194693, 235.0288272435886654 13.2349149251491323, 235.1521051678167282 12.8828891503746785, 235.2867725902066240 12.5312613935276858, 235.4233087209121322 12.1800902645324101, 235.5708596306865275 11.8287640872622148, 235.7235065834900070 11.4781679472531195, 235.8797318094724460 11.1284757052297607, 236.0525313246161261 10.7671682736166101, 234.5539738435558093 10.8934756928844845, 233.4407131631531342 10.9842712723458380, 232.5469229652644003 11.0542229776369396, 231.8057772059842137 11.1102241836769355, 231.1727759778428322 11.1565989553883824, 230.6222024977036256 11.1958368476612140, 230.1360978920992579 11.2296246903222858, 229.7011060076216040 11.2591734075647292, 229.3092627460586925 11.2852352682155690, 228.9523786369052232 11.3085085479037950, 228.6255699416117295 11.3294320811030449, 228.3230615139313500 11.3484629748790748, 228.0424929933010674 11.3658248267683515, 227.7797848238544418 11.3818240807472453, 227.5335303503320290 11.3965959501297025, 227.3013618133047657 11.4103203927839978, 227.0813921445934511 11.4231400422407940, 226.8725374557904217 11.4351462062810540, 226.6735784057233900 11.4464323335892999, 226.4830830479979795 11.4570977194829009, 226.3002739486506414 11.4672030229303132, 226.1246140672749334 11.4767939954809481, 225.9550662527160227 11.4859387811263254, 225.7906841315510462 11.4946974768467634, 225.6312478555471444 11.5030927722663758, 225.4762447625155630 11.5111601660448795, 225.3250842761325714 11.5189369296321988, 225.1774439551024329 11.5264465188783927, 225.0328448252998612 11.5337180770247567, 224.8908763596490132 11.5407761760249468, 224.7513584997161615 11.5476346729728849, 224.6139594562434354 11.5543129777076068, 224.4784375362918922 11.5608260941027599, 224.3444652819509599 11.5671914448426509, 224.2117774258863392 11.5734232007857347, 224.0801718772106028 11.5795330298010271, 223.9493664901763452 11.5855344995887286, 223.8191624724294684 11.5914391819224125, 223.6892422590746605 11.5972592901497720, 223.5594084415180305 11.6030053638277568, 223.4294005333650546 11.6086896685705661, 223.2989722102144583 11.6143216904755153, 223.1678913125285533 11.6199107220438496, 223.0358968024115143 11.6254674694465869, 222.9027074603658320 11.6310028545879938, 222.7681514532162907 11.6365211163933093, 222.6319141538503459 11.6420339437049929, 222.4937638625373211 11.6475477129612344, 222.3535187113662914 11.6530658977189141, 222.2106332312139614 11.6586083764543069, 222.0649326370137260 11.6641761438836653, 221.9159984711464233 11.6697805626031830, 221.7637180402751653 11.6754184975181392, 221.6071946734351457 11.6811193203291595, 221.4462705120642738 11.6868790352296799, 221.2800176036289201 11.6927238980664399, 221.1082343240076113 11.6986486654835566, 220.9302181846813085 11.7046664470968480, 220.7448115762643397 11.7108046009476432, 220.5512576667543385 11.7170716871744123, 220.3489604038595360 11.7234675875962715, 220.1364090861300156 11.7300207161521133, 219.9120955538532485 11.7367529071512759, 219.6885215783216552 11.7467999825000646, 219.7800022085723128 12.0939667193786491, 219.8674454814815817 12.4316594206823332, 219.9609663348926460 12.7696974746051932, 220.0435221785276383 13.1088831468612046, 220.1287352846985073 13.4489940062221827, 220.2143098338185894 13.7895853680132188, 220.2996432287141317 14.1309982528014633, 220.3856337203785074 14.4729600246978407, 220.4702124056549906 14.8160664517127341, 220.5542495222690604 15.1598074720371656, 220.6372147493088676 15.5039964428243238, 220.7215739629540110 15.8490768264030688, 220.8003749787557979 16.1950206146459834, 220.8780366530769754 16.5414260976919891, 220.9576980262959296 16.8886184324824242, 221.0492649291077214 17.2360440208405272, 221.2038686917591974 17.5820804814770568, 221.2332821024614873 17.9327909627808992, 221.3064374135869343 18.2825671410003530, 221.3767990325112009 18.6330869316119241, 221.4437786011409628 18.9842653899860636, 221.5157897919053198 19.3357555187522046, 221.6415036194281072 19.6862868957955186, 221.7040268219716665 20.0392648174781414, 221.7734189146283370 20.3928463602206236, 221.8288535881722225 20.7473064169434060, 221.8917645082245826 21.1019045711431907, 221.9100285267176105 21.4581261493741309, 221.9689664639304851 21.8138417551273918, 222.0351237484508715 22.1699280425233560, 222.0994527850592419 22.5263997498348019, 222.1624644986581814 22.8951608776491611))) diff --git a/isis/src/base/objs/ImagePolygon/ImagePolygon_Darwin_i386.truth b/isis/src/base/objs/ImagePolygon/ImagePolygon_Darwin_i386.truth new file mode 100644 index 0000000000000000000000000000000000000000..8a604f3441a153ad73a17f6cb1fd6cc6ad3418e7 --- /dev/null +++ b/isis/src/base/objs/ImagePolygon/ImagePolygon_Darwin_i386.truth @@ -0,0 +1,3 @@ +MULTIPOLYGON (((223.8172826870554388 34.4551387030861704, 223.8417027793910279 34.4596506066820183, 223.8575436553176701 34.4592772202857915, 223.8731987947955417 34.4589061403268389, 223.8888001595454966 34.4585342458576420, 223.9044019981010365 34.4581602382883290, 223.9200661671754347 34.4577826049052902, 223.9355075424467429 34.4574083328669047, 223.9508457646257682 34.4570345511811738, 223.9660146266157881 34.4566629441688548, 223.9810473116613707 34.4562927476240262, 223.9957878473876747 34.4559279256363027, 224.0106582442351453 34.4555579476699165, 224.0255459276724821 34.4551856180930827, 224.0403444766045311 34.4548136399185481, 224.0550707902558258 34.4544416140812331, 224.0696826278450260 34.4540706528633152, 224.0842130299532755 34.4536999451661927, 224.0986612451087865 34.4533295402476938, 224.1130364689869339 34.4529592283796191, 224.1273202299933018 34.4525895194552731, 224.1415662443043573 34.4522190340582526, 224.1557339918608420 34.4518488559867677, 224.1698107918541609 34.4514793494806355, 224.1838116920665982 34.4511101458139279, 224.1977227034556961 34.4507416459917764, 224.2115924901468702 34.4503725738795978, 224.2254006440637397 34.4500034947196099, 224.2391929104324504 34.4496331904990001, 224.2529511041107355 34.4492621618859047, 224.2666975062502672 34.4488898121368408, 224.2803860065775154 34.4485174107729009, 224.2940079847231800 34.4481452153055514, 224.3075938798835978 34.4477724066462940, 224.3210795841726224 34.4474007776906106, 224.3344990942370032 34.4470294144046818, 224.3478450164772369 34.4466585461289512, 224.3611125161780251 34.4462883334162910, 224.3742955932223424 34.4459189716523113, 224.3874260849249254 34.4455495872321151, 224.4004958875964064 34.4451804279779736, 224.4135260618142240 34.4448109130246038, 224.4264828608789628 34.4444420219817715, 224.4393721008836167 34.4440736115621888, 224.4522012232876307 34.4437054889999175, 224.4649910968735753 34.4433370695209575, 224.4777393619483519 34.4429684345123590, 224.4904489206230380 34.4425995128584645, 224.5030718093266842 34.4422317208438145, 224.5156259768878328 34.4418645587055465, 224.5281770921911857 34.4414961127534767, 224.5407219882328320 34.4411264780584929, 224.5531975742495661 34.4407575293592885, 224.5656264624743415 34.4403886150134397, 224.5780227094808765 34.4400193297392363, 224.5903757296815400 34.4396500013147389, 224.6026728254119291 34.4392810252896453, 224.6148668913132838 34.4389138407199553, 224.6269709753681809 34.4385480837916518, 224.6390599334172578 34.4381815076603104, 224.6511372139618175 34.4378140121817324, 224.6632067785040476 34.4374454801668293, 224.6751614661697261 34.4370792014152940, 224.6870933909597738 34.4367123756374767, 224.6989898632547238 34.4363454016597146, 224.7108678965473132 34.4359777634713211, 224.7226881483722991 34.4356106889183309, 224.7344958302550708 34.4352427865472706, 224.7462652761358015 34.4348748626036851, 224.7579793002169026 34.4345074672970739, 224.7696431367291154 34.4341404523806602, 224.7812728007805561 34.4337733275599049, 224.7928435543977344 34.4334068854894184, 224.8043847867216130 34.4330402109262153, 224.8157283419619716 34.4326786627865076, 224.8270886232841690 34.4323154551121036, 224.8384166745431685 34.4319521503576311, 224.8497524406567436 34.4315874760106411, 224.8610108250075541 34.4312241690653664, 224.8722867697038623 34.4308591870978731, 224.8835699922025810 34.4304928586050352, 224.8948651191152521 34.4301250319575729, 224.9061662755833879 34.4297558956339884, 224.9173542816715781 34.4293893381866241, 224.9284086365155133 34.4290260616188135, 224.9394220907865360 34.4286630586182127, 224.9504388176640077 34.4282988871562949, 224.9614347391278102 34.4279343412270080, 224.9724090215291596 34.4275694544292605, 224.9833614191804259 34.4272042411422561, 224.9942931924667278 34.4268386657352323, 225.0052127357932932 34.4264724542664311, 225.0161268911519983 34.4261053817509719, 225.0270072241578134 34.4257384031269353, 225.0379099782836647 34.4253696378408307, 225.0487812548770989 34.4250008963959999, 225.0595876459126430 34.4246333158877462, 225.0703030756958185 34.4242677965401214, 225.0809691073864656 34.4239029512769505, 225.0916138569805298 34.4235378364048259, 225.1022391575891959 34.4231723953056346, 225.1128542317258336 34.4228063180293233, 225.1234516167740480 34.4224398635157698, 225.1340217161871919 34.4220733665334322, 225.1445720848678604 34.4217065741965982, 225.1551012336083772 34.4213395433927403, 225.1655864785901997 34.4209730651206627, 225.1760248993641085 34.4206072521104929, 225.1864409930021793 34.4202412644615521, 225.1968389824640724 34.4198749609670074, 225.2072200098035353 34.4195083066778267, 225.2175785697109234 34.4191414990643878, 225.2279161215415968 34.4187744928887369, 225.2382328071076927 34.4184072887788730, 225.2485261485682315 34.4180399796766849, 225.2587970262709973 34.4176725406107664, 225.2690410352409458 34.4173051335256091, 225.2792535965254217 34.4169379279162939, 225.2894249396076418 34.4165712794060639, 225.2995612323753960 34.4162049783027442, 225.3096797795340080 34.4158384149443748, 225.3197769941242257 34.4154717224572551, 225.3298508715159585 34.4151049782719767, 225.3399032249868128 34.4147381230933931, 225.3499338576569073 34.4143711695009245, 225.3599442461228932 34.4140040696646921, 225.3699387631349111 34.4136366704509484, 225.3799126564553319 34.4132691483703610, 225.3898592055629706 34.4129017528991099, 225.3997746327033838 34.4125346283236624, 225.4096413759663164 34.4121684231094491, 225.4194664480515939 34.4118028921399528, 225.4292333250849936 34.4114386506334213, 225.4389847119238937 34.4110741438095005, 225.4487227950546355 34.4107092950618778, 225.4584529700451867 34.4103439088415826, 225.4681791118237868 34.4099778441967530, 225.4779501834397024 34.4096092904921136, 225.4877658689309783 34.4092382501921463, 225.4975606253910030 34.4088671491674845, 225.5073160520562112 34.4084966774081309, 225.5170945589490259 34.4081245163349720, 225.5268331233619961 34.4077530164326717, 225.5365021994056747 34.4073832928032246, 225.5461190551147297 34.4070147129218284, 225.5556995064936814 34.4066466938671809, 225.5652214497690409 34.4062800756482901, 225.5747432098429783 34.4059126712269077, 225.5842560908538417 34.4055448095740246, 225.5937778006128553 34.4051758227699338, 225.6033009157918059 34.4048059909125286, 225.6128238278372748 34.4044353752724348, 225.6223471750254532 34.4040639520834759, 225.6318758783412193 34.4036915342067431, 225.6414016415698995 34.4033184378166652, 225.6509363628046003 34.4029442090107622, 225.6604947562084647 34.4025682829215498, 225.6700415056936606 34.4021920106849777, 225.6795791566649996 34.4018152973413507, 225.6890709330758114 34.4014395611739303, 225.6985268750812565 34.4010644243483483, 225.7079299361909648 34.4006905526265570, 225.7172925180968832 34.4003174765961717, 225.7266351872193013 34.3999444072983067, 225.7359624913239884 34.3995711723548681, 225.7452560214270250 34.3991984905109618, 225.7545267975710317 34.3988259392688889, 225.7637889836344414 34.3984529709160398, 225.7730507645073317 34.3980792678529355, 225.7823252012635180 34.3977043199699963, 225.7916004169035205 34.3973285906499200, 225.8008725342959622 34.3969522323247858, 225.8101369195184134 34.3965754280254572, 225.8193892451850218 34.3961983497526589, 225.8286274988493858 34.3958210792869679, 225.8378496687657275 34.3954436987810226, 225.8470551995606286 34.3950662332777455, 225.8562326011003734 34.3946891400830523, 225.8653930029058188 34.3943119835577349, 225.8745410760741379 34.3939345816839008, 225.8836776373499617 34.3935569043987499, 225.8928019411091839 34.3931789835027857, 225.9019194640785599 34.3928006034879843, 225.9110308751989749 34.3924217392180154, 225.9201549499623809 34.3920416439267171, 225.9292743320435193 34.3916610090137098, 225.9383845714556003 34.3912800134750327, 225.9474795314178266 34.3908989044373499, 225.9565581779352499 34.3905177257819261, 225.9656244992437450 34.3901363203602415, 225.9746802477525875 34.3897546199894322, 225.9837284337445169 34.3893725057496482, 225.9927658599886797 34.3889901074684872, 226.0017891753058166 34.3886075615055518, 226.0108161763018018 34.3882241545240248, 226.0198457173549969 34.3878399331655586, 226.0288659304852672 34.3874553757630395, 226.0378750537378778 34.3870705548477176, 226.0468586590083930 34.3866860531593730, 226.0558323074971554 34.3863012459153126, 226.0647969809047027 34.3859160948656708, 226.0737494779210124 34.3855307302515456, 226.0826909505214246 34.3851451068040674, 226.0916392243316864 34.3847585069560466, 226.1005846293875834 34.3843713215450038, 226.1095237944467726 34.3839836875571905, 226.1184552396198910 34.3835956656763031, 226.1273766599848898 34.3832073496778676, 226.1362843513687153 34.3828188893593136, 226.1451789838363595 34.3824302579892986, 226.1540696341189687 34.3820410907883058, 226.1629557016454157 34.3816514125989414, 226.1718415645501068 34.3812610485457952, 226.1807230054455999 34.3808701688271583, 226.1896010103693300 34.3804787347539005, 226.1984731024689950 34.3800868460323130, 226.2073393250070410 34.3796945012310857, 226.2162010894380444 34.3793016444903827, 226.2250584402766265 34.3789082745362151, 226.2339210610063560 34.3785140099352162, 226.2427791039827127 34.3781192423320050, 226.2516314343282886 34.3777240168995633, 226.2604782195338942 34.3773283272095398, 226.2693193564055321 34.3769321772336909, 226.2781549132746193 34.3765355639964554, 226.2869854330353121 34.3761384661654077, 226.2958114626155748 34.3757408625677101, 226.3046334835679545 34.3753427349446667, 226.3134536502138019 34.3749440038212342, 226.3222666039530395 34.3745448675868772, 226.3310674200903350 34.3741454965105575, 226.3398662973730495 34.3737455139908121, 226.3486632146650379 34.3733449207269430, 226.3574580470379658 34.3729437205966377, 226.3662507195154205 34.3725419149321638, 226.3750416931271161 34.3721394877985134, 226.3838307521521074 34.3717364446175608, 226.3926183115015363 34.3713327721326252, 226.4014042158760844 34.3709284729463604, 226.4101886820603227 34.3705235397049265, 226.4189713667341266 34.3701179688710923, 226.4277528949788518 34.3697117359899522, 226.4365339441873743 34.3693048460954742, 226.4453141371841696 34.3688973009585936, 226.4540932758034444 34.3684891262239773, 226.4628714412387751 34.3680802909390195, 226.4716492125770628 34.3676707554958512, 226.4804266127447647 34.3672605340832789, 226.4892039200612430 34.3668496114387167, 226.4979812270886157 34.3664379860401539, 226.5067586403042696 34.3660256539005715, 226.5155350783787753 34.3656126841276190, 226.5243113274158588 34.3651990254046922, 226.5330863836773290 34.3647847378262910, 226.5418613931196887 34.3643697520982982, 226.5506364357558766 34.3639540648019022, 226.5594125115484587 34.3635376201859799, 226.5681899791629235 34.3631204005482687, 226.5769703953518786 34.3627023214856848, 226.5857530174790213 34.3622834276467799, 226.5945393457379566 34.3618636384960396, 226.6033280976941739 34.3614430267662812, 226.6121204829055102 34.3610215277182363, 226.6209149844707156 34.3605992248942869, 226.6297112468443800 34.3601761375813552, 226.6385086581271366 34.3597522984601582, 226.6473076484998614 34.3593276840231709, 226.6561088518905933 34.3589022601831786, 226.6649128221872047 34.3584759974264884, 226.6737198569121006 34.3580488800412951, 226.6825293890375974 34.3576209381841196, 226.6913400811723420 34.3571922425097185, 226.7001540295673294 34.3567626816807490, 226.7089712049645414 34.3563322571851799, 226.7177870375159330 34.3559012099767855, 226.7266041828078187 34.3554693992389275, 226.7354247297398331 34.3550367145667934, 226.7442492611458249 34.3546031251241786, 226.7530788598978972 34.3541685737675593, 226.7619128745805597 34.3537330945820614, 226.7707514832060269 34.3532966779085598, 226.7795960290009418 34.3528592527794885, 226.7884459906872507 34.3524208461996068, 226.7973003349381997 34.3519815119965415, 226.8061593642061098 34.3515412337322559, 226.8150233317537925 34.3510999975136855, 226.8238934698196658 34.3506577379326572, 226.8327720567338872 34.3502143344743445, 226.8416573813208856 34.3497698762915959, 226.8505497655341117 34.3493243455891317, 226.8594358490680065 34.3488784447268785, 226.8683250410213361 34.3484316781252872, 226.8772265484987827 34.3479835600551411, 226.8861363120287820 34.3475343031321643, 226.8950567593712151 34.3470837781792824, 226.9039829499012342 34.3466322445209613, 226.9129146680944586 34.3461797125383796, 226.9218556874094190 34.3457259818489007, 226.9308045477948212 34.3452711282402134, 226.9397756292526935 34.3448143895302991, 226.9487603184134628 34.3443562188081941, 226.9577713539454749 34.3438959389133132, 226.9667906962734207 34.3434345027779955, 226.9758185915864317 34.3429718957263219, 226.9848216200828119 34.3425098913908968, 226.9938252716434022 34.3420471374260643, 227.0028484628032004 34.3415826267594255, 227.0118809439680376 34.3411169021389426, 227.0209235817709157 34.3406499156234730, 227.0299791780944076 34.3401815158194665, 227.0390478252961657 34.3397116954514985, 227.0481467096626034 34.3392395333766274, 227.0572602651047589 34.3387658574176697, 227.0663771858033613 34.3382912703768000, 227.0755008947110412 34.3378155877346387, 227.0846303913073996 34.3373388616534214, 227.0937637964039197 34.3368611917211055, 227.1029086135041268 34.3363821733254326, 227.1120687985143718 34.3359015911654453, 227.1212359111418095 34.3354198971173048, 227.1304019305064799 34.3349375223436510, 227.1395758196006227 34.3344539825447868, 227.1487597349276939 34.3339691593657577, 227.1579902583263788 34.3334810704758411, 227.1672328061905830 34.3329915812163549, 227.1764712676953764 34.3325015630313501, 227.1857181919765196 34.3320103346922068, 227.1949746843040998 34.3315178341563794, 227.2042427831847817 34.3310239482966324, 227.2135235122840982 34.3305286187725258, 227.2228146140698470 34.3300319660012221, 227.2321158182128897 34.3295340024028306, 227.2414261879402773 34.3290347769038178, 227.2507440105588898 34.3285343811480317, 227.2600744088126987 34.3280325324944329, 227.2694283383975744 34.3275286268106896, 227.2787965981402749 34.3270231647175663, 227.2881796631106397 34.3265161168640063, 227.2975768164326098 34.3260075194109433, 227.3069878365900536 34.3254973813716404, 227.3164104609731169 34.3249858245099517, 227.3258502854863821 34.3244725367080363, 227.3353080996716926 34.3239574703683132, 227.3447883387066213 34.3234403755930231, 227.3542849111706516 34.3229215853954415, 227.3637955610474251 34.3224012213397103, 227.3733236581833523 34.3218790926137487, 227.3828696239687588 34.3213551716833152, 227.3924291244551910 34.3208296960990893, 227.4020038477916614 34.3203025683132452, 227.4115915765664226 34.3197739086688500, 227.4211903006604700 34.3192438265212800, 227.4308034100351108 34.3187121290632149, 227.4404322668985969 34.3181787363226363, 227.4500783315635317 34.3176435624042711, 227.4597408211544121 34.3171066472117232, 227.4694373999262496 34.3165669913512517, 227.4791525994612869 34.3160254597000787, 227.4888678788144887 34.3154830952473446, 227.4985957069042684 34.3149391921614608, 227.5083373853137800 34.3143936735035950, 227.5181018062716021 34.3138460313881026, 227.5278825759429822 34.3132966234387382, 227.5376789842294727 34.3127454859353378, 227.5475028125167114 34.3121919440087666, 227.5573500149448023 34.3116362217108275, 227.5672257339052180 34.3110780196529106, 227.5771363516663257 34.3105169659525515, 227.5870780116667618 34.3099532729218311, 227.5970431329253074 34.3093873675369423, 227.6070304509327400 34.3088193164755637, 227.6170402145462504 34.3082490997872753, 227.6270614888811394 34.3076773412008720, 227.6371021487410076 34.3071035836203464, 227.6471620472045174 34.3065278304867505, 227.6572333482910437 34.3059505296988334, 227.6673250879570389 34.3053711550848206, 227.6774425887975610 34.3047893928164669, 227.6875956283761582 34.3042046687850117, 227.6977747165031190 34.3036175255403322, 227.7079695685462184 34.3030285548813652, 227.7181855113298639 34.3024374420603095, 227.7284236548779006 34.3018441166910364, 227.7386810962439370 34.3012487425373109, 227.7489607488712977 34.3006511438890129, 227.7592652945483849 34.3000511576431890, 227.7696049562804603 34.2994481772121560, 227.7799661327425724 34.2988429927923590, 227.7903495499146800 34.2982355558256629, 227.8007531420874443 34.2976259820287197, 227.8111804588932046 34.2970140563683117, 227.8216354765219762 34.2963995373976971, 227.8321461589635248 34.2957807625226110, 227.8426781272081598 34.2951597549060097, 227.8532313530564579 34.2945365103118931, 227.8637943594835917 34.2939117050406637, 227.8743681842870501 34.2932852743100653, 227.8849595330413251 34.2926568151129274, 227.8955699765630243 34.2920262286820332, 227.9062407193817990 34.2913910462529827, 227.9169476338818185 34.2907526962728824, 227.9276713907391070 34.2901123277707356, 227.9383745218270860 34.2894721855654225, 227.9490646281740283 34.2888318174488731, 227.9597329801610215 34.2881917519580668, 227.9704830712439048 34.2875457532931449, 227.9813063056426188 34.2868943187016839, 227.9922004455595754 34.2862375637549519, 228.0031311318133760 34.2855775502002302, 228.0140933799731044 34.2849145701223961, 228.0250913628472631 34.2842483610777151, 228.0361342648420191 34.2835783542064476, 228.0472235719963976 34.2829044463309032, 228.0583488204560183 34.2822272628250815, 228.0695055535578035 34.2815470657209929, 228.0806796288568989 34.2808647114042770, 228.0918858625025791 34.2801792865075825, 228.1031233132273712 34.2794908394530964, 228.1143887119357885 34.2787995620820993, 228.1256453028393310 34.2781077090887294, 228.1369030524184041 34.2774146678620184, 228.1481798443664104 34.2767193332270281, 228.1595524441736416 34.2760169519050635, 228.1709717099908232 34.2753105403553633, 228.1824155794452338 34.2746014535234238, 228.1938803829937683 34.2738899119351714, 228.2054189265468267 34.2731726235595744, 228.2170280980613768 34.2724497608496819, 228.2287243266976020 34.2717202776986980, 228.2405154509019098 34.2709836584986931, 228.2523281114683300 34.2702444678746687, 228.2641942766789498 34.2695006944830141, 228.2760966165555772 34.2687534104679585, 228.2880311232885049 34.2680028567511314, 228.3000080489240418 34.2672483774467551, 228.3120073191867618 34.2664912261055008, 228.3240136615007714 34.2657323607450550, 228.3360270491550921 34.2649717804313312, 228.3480846101073496 34.2642071288155847, 228.3601573792798547 34.2634402313342648, 228.3722738818091784 34.2626692688684500, 228.3844436938969977 34.2618936178110403, 228.3966618612765558 34.2611135776316118, 228.4089824127830468 34.2603256808090748, 228.4213463879687822 34.2595336690666841, 228.4337530236520877 34.2587375774856469, 228.4462104847059720 34.2579368681707450, 228.4587268133269902 34.2571310076858353, 228.4712928807757635 34.2563205652335157, 228.4839104809788068 34.2555054090235060, 228.4966228686224952 34.2546827270764354, 228.5094182245555317 34.2538532539691332, 228.5222741771181632 34.2530184132892686, 228.5351729278072810 34.2521793410413267, 228.5481108241752963 34.2513362605627520, 228.5610933369306963 34.2504888022590066, 228.5740744626591265 34.2496399537063994, 228.5870890608425441 34.2487874359030613, 228.6001377310801672 34.2479311982219414, 228.6132200400504360 34.2470712574983622, 228.6263499085960404 34.2462066876372617, 228.6395379494453266 34.2453367741268764, 228.6528307701242682 34.2444584248850319, 228.6663763632237476 34.2435618321321016, 228.6803617216070279 34.2426345403196351, 228.6952015541801302 34.2416489116415192, 228.7105525888537727 34.2406274235319827, 228.7265499348228559 34.2395608902071800, 228.7421439706192814 34.2385190300592157, 228.7570825716228455 34.2375188386586942, 228.7710598753439228 34.2365810240280624, 228.7833530683670631 34.2357543577948604, 228.7952800700753357 34.2349509230007385, 228.8072627602488183 34.2341424759791622, 228.8196514308424128 34.2333054216225534, 228.8331287442263147 34.2323936078462552, 228.8473922131469180 34.2314270979658133, 228.8618442087490621 34.2304460497711887, 228.8763439298241735 34.2294599387118552, 228.8909482643397268 34.2284648839076766, 228.9056482136823263 34.2274614587343677, 228.9203772896302098 34.2264541587582869, 228.9351647839141037 34.2254409727997029, 228.9499300140618345 34.2244273972624811, 228.9641311146921510 34.2234505681393131, 228.9782062980468424 34.2224806099825472, 228.9925852306206764 34.2214880257807579, 229.0081810669700531 34.2204098059550645, 229.0243240483496265 34.2192917030580972, 229.0404841060924355 34.2181701533111990, 229.0561546197716325 34.2170802519520976, 229.0718159793608208 34.2159888444595737, 229.0875983321437843 34.2148868823154046, 229.1034887026832507 34.2137752211917672, 229.1195460111437114 34.2126497038870951, 229.1358158382292629 34.2115070741072174, 229.1519329161566247 34.2103728455040539, 229.1680640638790010 34.2092353650361005, 229.1841528314637060 34.2080985980235468, 229.1997352210103145 34.2069952675949978, 229.2145400585607717 34.2059447195264852, 229.2300224803216508 34.2048443142916696, 229.2467979267665044 34.2036501662420633, 229.2636965491348917 34.2024448212972558, 229.2805688058051317 34.2012388685525011, 229.2975531551136896 34.2000224457224959, 229.3153572084256382 34.1987449442457603, 229.3330755456162251 34.1974708312596292, 229.3499864414941953 34.1962519261839191, 229.3671162393675331 34.1950147939656546, 229.3845622241133242 34.1937523319198320, 229.4014568277655997 34.1925270212032402, 229.4184179979918952 34.1912944082571215, 229.4358437587445394 34.1900256223241072, 229.4537366314563940 34.1887202761169675, 229.4717783256412247 34.1874013196511939, 229.4899255387612413 34.1860718421937406, 229.5081725982472847 34.1847322093503720, 229.5265398704868574 34.1833808832578541, 229.5450922295952694 34.1820130472502939, 229.5638787832904484 34.1806250030229961, 229.5833013117678263 34.1791870290051136, 229.6027619755459170 34.1777429731368159, 229.6217226068972934 34.1763326527843745, 229.6405847438497290 34.1749265203990760, 229.6596052490852458 34.1735055273339228, 229.6788397630404006 34.1720654517922497, 229.6983584810002696 34.1706009483857684, 229.7180957279716438 34.1691167911206364, 229.7380788626514345 34.1676108188229648, 229.7584117626756210 34.1660750989131259, 229.7790969056334802 34.1645092649619997, 229.7996369176232463 34.1629506915650722, 229.8203742932615512 34.1613735311362419, 229.8416825811018498 34.1597493412739510, 229.8624957634657164 34.1581588785920403, 229.8824174025879756 34.1566326127752475, 229.9024284096594783 34.1550960778054815, 229.9235693656282535 34.1534695744186010, 229.9452549994915955 34.1517974116376450, 229.9672683739203762 34.1500959777487836, 229.9895003849197224 34.1483735025366997, 230.0115335641944796 34.1466621287872911, 230.0333871041715099 34.1449604786041974, 230.0555507514620786 34.1432306179808407, 230.0779079317051412 34.1414814475757851, 230.1005423000427754 34.1397063292869731, 230.1238833343684291 34.1378715064769978, 230.1469833844930122 34.1360508854267479, 230.1701524619105328 34.1342202325622850, 230.1934678024694279 34.1323734190311470, 230.2165682856712294 34.1305388895062976, 230.2389046257694076 34.1287602695710035, 230.2627494181147654 34.1268575757473442, 230.2877550267185427 34.1248575756020784, 230.3121994425740695 34.1228969831179754, 230.3374538174993802 34.1208664279544891, 230.3631413116128499 34.1187956310739864, 230.3880206607561831 34.1167841714593507, 230.4129740677024358 34.1147614026916202, 230.4381720996264562 34.1127134836086441, 230.4639006138211812 34.1106170798747215, 230.4899617774171361 34.1084879303946877, 230.5160751630245670 34.1063486758618524, 230.5424933623011725 34.1041786332810304, 230.5692512088523074 34.1019747430087889, 230.5962633488587699 34.0997437898786657, 230.6233712572403647 34.0974986647174276, 230.6505324126961796 34.0952428144590982, 230.6778991777003398 34.0929635734629102, 230.7056768660073374 34.0906437346523887, 230.7338743165616108 34.0882822719610346, 230.7624290256065365 34.0858841097945344, 230.7912515729211691 34.0834564851068578, 230.8203176007895649 34.0810012491227425, 230.8496066250636716 34.0785199485613148, 230.8792222279614919 34.0760036572390916, 230.9092353385915999 34.0734461133305189, 230.9394837891279906 34.0708608099390275, 230.9699110764533998 34.0682523865333948, 231.0006928671984952 34.0656056693742713, 231.0318850272019233 34.0629155853065342, 231.0635571686675860 34.0601758150416671, 231.0955368340583789 34.0574008701335060, 231.1277395308280802 34.0545978214642844, 231.1598263150311539 34.0517959464564015, 231.1923731408356559 34.0489451184199368, 231.2256091620638188 34.0460249133125856, 231.2592693972243580 34.0430580047345259, 231.2932997455176576 34.0400487929999827, 231.3276773418911603 34.0369989773430746, 231.3623788652666065 34.0339103205237308, 231.3976872584197793 34.0307573786865305, 231.4333912448704211 34.0275584578910824, 231.4693555746214315 34.0243253059693487, 231.5059110724441780 34.0210279683690331, 231.5428878342104326 34.0176812112379210, 231.5803120488249078 34.0142822697343732, 231.6182257696958402 34.0108269012199926, 231.6563923558109366 34.0073361889261463, 231.6951328869912459 34.0037805360141618, 231.7344016753486926 34.0001635696370954, 231.7741163313663151 33.9964923488039332, 231.8144687461388287 33.9927486901787290, 231.8555242505667309 33.9889258811518715, 231.8967616380454047 33.9850717164516425, 231.9384874592085453 33.9811573545970305, 231.9810031243091828 33.9771540024940819, 232.0239997222591910 33.9730898996244832, 232.0678388327740720 33.9689303372334805, 232.1123373517177413 33.9646917582200558, 232.1571892772059869 33.9604025762483914, 232.2028902909401324 33.9560149644208167, 232.2491821770346974 33.9515527435586009, 232.2960411962056355 33.9470175078809291, 232.3439306823368327 33.9423637057928005, 232.3925149926277811 33.9376227334373510, 232.4421795019375736 33.9327560903860643, 232.4923819961781533 33.9278156109878992, 232.5436698047475943 33.9227466787318193, 232.5951687842305660 33.9176343955933461, 232.6475716307096491 33.9124096239597890, 232.7012278930365596 33.9070362580221811, 232.7556828037685932 33.9015582139110450, 232.8111272810814398 33.8959551460956590, 232.8675924455159532 33.8902225111619728, 232.9251556044690972 33.8843509815862447, 232.9836292775250968 33.8783581195322014, 233.0432332674061513 33.8722199923502529, 233.1036814246761537 33.8659644314339587, 233.1655576137215462 33.8595295606770179, 233.2282972755570540 33.8529720149463103, 233.2926253692118621 33.8462144248317642, 233.3579653179138234 33.8393149568009406, 233.4238324437535539 33.8323232701533883, 233.4921199961581237 33.8250368578670972, 233.5612785481834237 33.8176174604834756, 233.6323604437994561 33.8099502308987780, 233.7049545857545922 33.8020762209203056, 233.8182991445546293 33.7896946458198926, 233.8076868009974589 33.7447711158304671, 233.7998795211174752 33.7148904495256687, 233.7932833621273403 33.6848666704869686, 233.7861879662788169 33.6548975267118280, 233.7790138732385969 33.6249371303082398, 233.7721258780048856 33.5949457573666024, 233.7653244276447708 33.5649451761957351, 233.7589504395879203 33.5348983219310597, 233.7517922485339170 33.5049370175201418, 233.7451099030573687 33.4749242024867826, 233.7380079968496034 33.4449572273965501, 233.7308913047606325 33.4150038906189266, 233.7242842861141980 33.3850066679223403, 233.7177523609356058 33.3550016102456155, 233.7105361718773224 33.3250710555783343, 233.7038713781764727 33.2950810138029354, 233.6970686629649663 33.2651062318509503, 233.6905337589383009 33.2351027782129904, 233.6840504442202189 33.2050940973791882, 233.6777241043450886 33.1750688063842745, 233.6714174242954982 33.1450417812508462, 233.6651265169321618 33.1149842339623106, 233.6589877929609145 33.0848829896515539, 233.6524321129587634 33.0548271749566993, 233.6459016739153185 33.0247690228650370, 233.6397274744219033 32.9946728445241391, 233.6329292366539221 32.9646443836585377, 233.6264198619547301 32.9345851795598108, 233.6202087451694069 32.9044942683736679, 233.6139880511334468 32.8744048430015070, 233.6079852678255975 32.8442924251869286, 233.6024480633732310 32.8141580578265248, 233.5966311951530656 32.7840805084876692, 233.5901811265881349 32.7540715696615052, 233.5840609929455240 32.7240276623761233, 233.5780234847293855 32.6939754071204192, 233.5723051528725591 32.6638894275744747, 233.5666017738128630 32.6338024224210770, 233.5607542214522141 32.6037314697343916, 233.5546837866806982 32.5736849918668696, 233.5486024506201943 32.5436402502741871, 233.5424177865809554 32.5135952203075078, 233.5365716068125437 32.4835032167910924, 233.5315060001448160 32.4533282705142696, 233.5261496479418497 32.4231850921035161, 233.5203742088707770 32.3930873794257010, 233.5147182819266050 32.3629775113514810, 233.5094845867136542 32.3328231673348157, 233.5039894605985182 32.3026974293673987, 233.4978335602601760 32.2726429029673625, 233.4931590406256134 32.2424309058476695, 233.4878027400857547 32.2122923883547898, 233.4822943077738842 32.1821707946306717, 233.4769428295691398 32.1520331688125083, 233.4715484852565623 32.1219008274845379, 233.4659832529781340 32.0917874105425511, 233.4604242299232908 32.0616740463839420, 233.4547057474827625 32.0315783749592171, 233.4493448635817572 32.0014453815873736, 233.4439538849541975 31.9713163426437035, 233.4388438489372675 31.9411582034324724, 233.4333516271451003 31.9110653070441082, 233.4279989231125114 31.8809809552748931, 233.4229566390458501 31.8508644672416104, 233.4183811248644531 31.8206993019833213, 233.4138877626305373 31.7905263247609859, 233.4092102827143265 31.7603737819017375, 233.4050516566461511 31.7301671582915610, 233.4001074317153552 31.7000447186518528, 233.3957145715358195 31.6698647915971598, 233.3913100753762535 31.6396870518093785, 233.3864447837854073 31.6095336382647432, 233.3812875214192673 31.5793879738905261, 233.3764952550197904 31.5492046024446182, 233.3713681256496670 31.5190575396905999, 233.3665069083577919 31.4888832848857625, 233.3615529342137336 31.4587197535848944, 233.3563206750544055 31.4285865290605138, 233.3514797003734884 31.3984129292956879, 233.3465577546590453 31.3682488232810783, 233.3417228713095142 31.3380764927870921, 233.3370904021178944 31.3078918587356796, 233.3327447691412431 31.2776856492184869, 233.3284034057362533 31.2474800412854954, 233.3238447530990811 31.2172983697557100, 233.3202001870982656 31.1870215346005644, 233.3161949179906856 31.1567837769810794, 233.3117460132445729 31.1265937910656838, 233.3074302664846300 31.0963908863597638, 233.3031004202551912 31.0661905619150183, 233.2993877463871968 31.0359264957760104, 233.2953127272745064 31.0057054347712793, 233.2898951298278121 30.9756300525318728, 233.2854622844924677 30.9454523392395302, 233.2811087260189424 30.9152674167444452, 233.2766787725826418 30.8850916312266435, 233.2723182338893366 30.8549096935436857, 233.2680625875141800 30.8247179031670875, 233.2636594360838558 30.7945427206847739, 233.2591073856077344 30.7643842796401081, 233.2546430265682602 30.7342178079628638, 233.2506548072817054 30.7039852299420346, 233.2467326449200016 30.6737304211930564, 233.2427735884617448 30.6434806792112795, 233.2385419917316085 30.6132606393829576, 233.2344263708046128 30.5830296838953331, 233.2299724550055373 30.5528352857998122, 233.2257801219477926 30.5226147735751283, 233.2217008351062191 30.4923836900467329, 233.2176536181539745 30.4621505031472850, 233.2137701089007464 30.4319014927329583, 233.2097164924721255 30.4016889943031465, 233.2057273903701571 30.3714876142137022, 233.2018315928332299 30.3412778047890264, 233.1982994816496557 30.3110314135098449, 233.1949660442565744 30.2807656745234262, 233.1909995460327423 30.2505672081964114, 233.1869329125315176 30.2203804896412507, 233.1830432862202258 30.1901766843428980, 233.1794294371081833 30.1599455462454884, 233.1757256558106803 30.1297251350849358, 233.1722016871892151 30.0994998764303290, 233.1687265873930528 30.0692827643050364, 233.1657971256008182 30.0390104336791275, 233.1620197155411915 30.0088276220406023, 233.1588110553900606 29.9785872276917402, 233.1558657451028012 29.9483210009432987, 233.1526520127786171 29.9180841251987353, 233.1489461530049994 29.8878997696919164, 233.1453943524933834 29.8577009226217918, 233.1419015804141281 29.8274974560065331, 233.1385470571378278 29.7972455511092846, 233.1353455350549098 29.7669455615295924, 233.1321205569724100 29.7366494892085349, 233.1286857503216936 29.7063766210425086, 233.1248502693015041 29.6761466884616851, 233.1219322346422587 29.6458233627628012, 233.1187887011244015 29.6155248850105295, 233.1158036471032915 29.5852115613275579, 233.1128189974455722 29.5548997434324079, 233.1096148239391823 29.5246121600670683, 233.1059421915823009 29.4943963291804003, 233.1029253621703106 29.4641350065372620, 233.1002381417609115 29.4338412716992508, 233.0969753054017133 29.4036085512195093, 233.0938295190734380 29.3733653616549155, 233.0913472163580877 29.3430553834513610, 233.0892058098987150 29.3127119349485312, 233.0863428536627850 29.2824445349018490, 233.0832116703717247 29.2522064239827877, 233.0797675612365367 29.2220021876053160, 233.0766708226278467 29.1917583918291292, 233.0740702319781121 29.1614600580752850, 233.0714565710502484 29.1311647753719036, 233.0690128690097254 29.1008537235290277, 233.0668902691573123 29.0705113857552107, 233.0645048567228059 29.0401978200036268, 233.0622308672101894 29.0098745532464193, 233.0598776027648569 28.9795611971523535, 233.0578674387814431 28.9492143655959921, 233.0557478222018517 28.9188805699689802, 233.0535026840542514 28.8885669116903188, 233.0508429036587472 28.8583027762556696, 233.0484008302832137 28.8280180911296426, 233.0460454447872394 28.7977263211071275, 233.0438808462369593 28.7674168095387621, 233.0413729393396807 28.7371443319296063, 233.0390306784818790 28.7068567067617160, 233.0369262675736195 28.6765465604866243, 233.0347470633701619 28.6462459426569716, 233.0329268350126029 28.6159104396724437, 233.0304011304855862 28.5856435995657812, 233.0285767800049257 28.5553016797995802, 233.0267613739302988 28.5249607573186275, 233.0251239162247714 28.4946035505017150, 233.0235861249787490 28.4642380888183872, 233.0216106034007453 28.4339193332019953, 233.0189545611982282 28.4036720750902205, 233.0154885602265438 28.3735094844721587, 233.0142983651934117 28.3431162820911773, 233.0278250723133340 28.3112211640409903, 233.0452282676278060 28.2789483187385748, 233.0538325274342526 28.2475942808530363, 233.0539975568602529 28.2171064726347609, 233.0513725666164362 28.1869063911917372, 233.0495940247802196 28.1566216920424672, 233.0476156283758939 28.1263594901667915, 233.0441012164610015 28.0962563986380189, 233.0341267619562586 28.0668153191363956, 233.0153669885793022 28.0382716562388339, 233.0004310857394785 28.0093374012700345, 232.9972907785160885 27.9791790793518587, 232.9993492557859440 27.9484712223743585, 232.9984005080535496 27.9180717344066736, 232.9974307125876010 27.8876765098116621, 232.9972130492358815 27.8572068668353197, 232.9974480176594227 27.8266933234033189, 232.9991589372485805 27.7960317666082908, 232.9989280134374212 27.7655700234398815, 232.9984242466583737 27.7351382270208759, 232.9981795284512032 27.7046822703976972, 232.9979878384328060 27.6742274580723340, 232.9973841036610338 27.6438208719064171, 232.9969627048609482 27.6133979690381395, 232.9956424441186300 27.5830686696756793, 232.9942467721440096 27.5527492409820809, 232.9928294278056455 27.5224342236380650, 232.9910051527021437 27.4921627558273016, 232.9892752252020500 27.4618839132446162, 232.9876407499817219 27.4315975974861708, 232.9860500535251049 27.4013090709267217, 232.9845431092235799 27.3710008489806320, 232.9832144523942645 27.3406640377758414, 232.9813211962325852 27.3103867100814455, 232.9796046601171611 27.2800936680540822, 232.9778668740795524 27.2498050024457434, 232.9760812623404718 27.2195234107069091, 232.9744936225158938 27.1892239957064348, 232.9725389188245686 27.1589640136283386, 232.9710993706607098 27.1286541056528883, 232.9695310658502763 27.0983595097532017, 232.9678740179837177 27.0681026007772161, 232.9664105876216240 27.0378534557890511, 232.9648174107140619 27.0076198078588909, 232.9633173341063355 26.9773791166742747, 232.9625444737612270 26.9470672981345629, 232.9609409653380681 26.9168418629002275, 232.9596090239890316 26.8865913871609834, 232.9583747341857531 26.8563334706206511, 232.9570418888882273 26.8260879392119520, 232.9556783045243833 26.7958479490301684, 232.9541208556610741 26.7656115503644969, 232.9529072543819552 26.7353254479201290, 232.9513372321579538 26.7050777308408698, 232.9496721067915246 26.6748420272619029, 232.9482697864152385 26.6445822619811636, 232.9469308519850301 26.6143185587787592, 232.9456308588750346 26.5840533948264977, 232.9445891873294840 26.5537646856055431, 232.9435705002171630 26.5234761549716502, 232.9424930684088508 26.4931960433853853, 232.9411883949197204 26.4629460272430457, 232.9404661357677355 26.4326443638835720, 232.9397077071034801 26.4023488673881523, 232.9389590229795886 26.3720549233583981, 232.9380771814587092 26.3417769121321328, 232.9371118552418238 26.3115098363031592, 232.9363055939249421 26.2812293227256610, 232.9349899869485796 26.2510025504793276, 232.9335253420537128 26.2207932922122957, 232.9325013463743232 26.1905423329594917, 232.9312666334036805 26.1603104013804000, 232.9304842317118300 26.1300312111249937, 232.9301915141380164 26.0997055104343687, 232.9294881720715580 26.0694236562425132, 232.9290727465349846 26.0391155705938289, 232.9284303149261177 26.0088329122040740, 232.9279035226248311 25.9785413248613928, 232.9273612165927716 25.9482539711809004, 232.9268538349265896 25.9179658022049786, 232.9262752018361766 25.8876874677902222, 232.9258886605539374 25.8574103205503327, 232.9254503185429996 25.8271578908256885, 232.9251078811092270 25.7968986263608109, 232.9246578931967804 25.7666529016120904, 232.9240220891967397 25.7364285482954038, 232.9236035390601955 25.7061852433478570, 232.9230685584527407 25.6759563790138863, 232.9227337276141725 25.6457103098245049, 232.9226746290124197 25.6154395052224828, 232.9151284100966564 25.5859193756643037, 232.8937666408189102 25.5577604985455409, 232.8940638254573230 25.5274256431740447, 232.8871864394731119 25.4978083491673289, 232.8887549686981515 25.4673523877789023, 232.8922447980335733 25.4367079618528074, 232.8868549805569899 25.4069505089107963, 232.8862070943299614 25.3767236846523367, 232.8896433829220882 25.3460933179366066, 232.8904085764630736 25.3157316467882119, 232.8749355209038185 25.2869872854492073, 232.8752451627682944 25.2566951708063492, 232.8833426366030039 25.2256500908747370, 232.8835253170702515 25.1953944684774278, 232.8791674520630863 25.1655927164424611, 232.8897864848735821 25.1343065993527688, 232.8853793269061612 25.1045158111557178, 232.8872412250228479 25.0741054813627002, 232.8902504012405075 25.0435843557223841, 232.8862819506680353 25.0137587009765774, 232.8849165371166805 24.9836776255639847, 232.8615444346234540 24.9557405574212225, 232.8678957260945026 24.9248252132858035, 232.8743003819387809 24.8939074623086505, 232.8845451260537232 24.8626121460513616, 232.8855114925713110 24.8322389783660284, 232.8777786943020374 24.8027302997633363, 232.8784494298064658 24.7723922672678682, 232.8786766284533201 24.7421011266518249, 232.8815821188912594 24.7115479150936821, 232.8784798199646389 24.6815922415318738, 232.8815210228855790 24.6510507831176042, 232.8869507733595299 24.6202941881330766, 232.8897516433328008 24.5898008393355454, 232.8918981621112039 24.5593753741429559, 232.8953447470361766 24.5288244473084909, 232.9021256321721296 24.4979467948482466, 232.9055803921938264 24.4674014151714623, 232.9256796376523369 24.4352113534178343, 232.9278143680417656 24.4048031511445132, 232.9273308331783596 24.3746574337605217, 232.9233851757292086 24.3448714448659054, 232.9184915904676814 24.3151952701589558, 232.9128735282994000 24.2855934651471266, 232.9070168457516559 24.2560179019932782, 232.8961245154026756 24.2269419337473444, 232.9056956381911334 24.1958493513260890, 232.9163992201185920 24.1646481367450399, 232.9148753749125262 24.1346574495095076, 232.9260392073335311 24.1034175400766664, 232.9206813332552031 24.0738120737350272, 232.9204495721024557 24.0437090839679151, 232.9242943937483687 24.0132123141866138, 232.9256437470649246 23.9829650936419547, 232.9266377200116835 23.9527562658711197, 232.9335016546866370 23.9219720544854937, 232.9350094751260940 23.8917194173821841, 232.9318311548631470 23.8619319937482324, 232.9368722189848881 23.8313379252621615, 232.9450679386291085 23.8004364540855136, 232.9487612036170390 23.7699821915590945, 232.9457539898387495 23.7401711441849521, 232.9427211904169894 23.7103463853456695, 232.9402080397393888 23.6804735786337730, 232.9433835896780352 23.6500442500705326, 232.9429844400121965 23.6199700523985072, 232.9448047522230922 23.5896808975073995, 232.9476776161833982 23.5592916672883561, 232.9482010012357023 23.5291369223764057, 232.9512697054896080 23.4987353646153210, 232.9482075711342759 23.4689398428672398, 232.9524304169726179 23.4384270363305838, 232.9546730816441027 23.4081077648677862, 232.9582883792437826 23.3776571360643501, 232.9647493345424039 23.3469304505496922, 232.9703738878391732 23.3162894618000216, 232.9749310818776848 23.2857568940812207, 232.9745359585149913 23.2557144437894898, 232.9767231067804687 23.2254218015470215, 232.9747120127888138 23.1955449257939925, 232.9822413993305190 23.1647348153342882, 232.9804333913460255 23.1348442843248776, 232.9799632302537304 23.1048251182840687, 232.9861015984569690 23.0741610276239513, 232.9875906071483769 23.0439567789152626, 232.9885163914815678 23.0138113509045859, 232.9880927479807724 22.9838018051451805, 232.9920786516129283 22.9533634401114774, 232.9956900448753458 22.9229654565282175, 232.9980286669976977 22.8926959143639941, 232.9994463255823121 22.8625202868843544, 233.0007273528797214 22.8323817678633709, 233.0026223772322567 22.8022057942484118, 233.0043541575535926 22.7720495280457627, 233.0056855084943663 22.7419361868120475, 233.0075168388989937 22.7117776143631822, 233.0086972640626470 22.6816864800318925, 233.0110141290699062 22.6514878823163492, 233.0150980296511420 22.6211202179953688, 233.0183630377297845 22.5908364989234300, 233.0205235277441886 22.5606646286184329, 233.0226990889819945 22.5304748350743864, 233.0250312227692007 22.5002543316308490, 233.0273417265109401 22.4700397096754543, 233.0294322534792286 22.4398503559635571, 233.0316537241797050 22.4096519869835333, 233.0341646708320127 22.3794291320634606, 233.0365342747200543 22.3492238899732065, 233.0390090295576329 22.3190121956477334, 233.0410423262773918 22.2888474231631406, 233.0431049504354633 22.2586836085089494, 233.0454588239587679 22.2284945391122122, 233.0478015507949863 22.1983097810625374, 233.0502410036448282 22.1681194492568316, 233.0528960638682747 22.1379119636236830, 233.0557407392531672 22.1076898814232585, 233.0583526795629723 22.0774943964448340, 233.0611965970119286 22.0472802075900809, 233.0637667924078755 22.0170966232015282, 233.0661707317356957 21.9869331635871568, 233.0688355155518252 21.9567482211745499, 233.0712133980820795 21.9266163988525697, 233.0735932642361945 21.8965084710525879, 233.0760567739936846 21.8663964169623064, 233.0786160068223012 21.8362790738185488, 233.0813521306658913 21.8061485618539201, 233.0841934460657967 21.7760118752912923, 233.0868186398116109 21.7459002817007985, 233.0896572715981847 21.7157720084171970, 233.0925606006185831 21.6856415363909605, 233.0953944803874549 21.6555219187505443, 233.0982658468537352 21.6253757162664293, 233.1010684296372801 21.5952146479776665, 233.1039565019003135 21.5650493241765950, 233.1070084941937068 21.5348721394971925, 233.1101013321711548 21.5046950639544967, 233.1128703125102675 21.4745535124936850, 233.1158241929650785 21.4443980967747798, 233.1188318357311005 21.4142415632226992, 233.1218563893511373 21.3840874972769868, 233.1246794786605392 21.3539570957466438, 233.1274225833886931 21.3238601080463575, 233.1306370619428208 21.2937419769091925, 233.1338110029607549 21.2636319987268081, 233.1368714757588236 21.2335372461872005, 233.1401888172864005 21.2034218385370075, 233.1433772706163268 21.1733231701487874, 233.1465315269799419 21.1432320716031548, 233.1496154961199068 21.1131520453783352, 233.1523256640593331 21.0831124742891234, 233.1550432763680192 21.0530764455185277, 233.1579828491569231 21.0230058062467613, 233.1607722023841234 20.9929374507901869, 233.1636624180470108 20.9628635552655389, 233.1666398146293204 20.9327854558763065, 233.1696517888767062 20.9027082544394709, 233.1726003364720725 20.8726414315883027, 233.1758702061451345 20.8425478178669259, 233.1788078856152140 20.8124905745848992, 233.1817470920860274 20.7824374565909480, 233.1847240764050753 20.7523849749798082, 233.1882571694646629 20.7222788476118609, 233.1922497393497906 20.6921286818578203, 233.1963717973546864 20.6619703873674609, 233.1999109853458094 20.6318727135351807, 233.2035406237866653 20.6017706851485940, 233.2070288687683330 20.5716866761621162, 233.2105921939143514 20.5415998140439626, 233.2140636677692953 20.5115262079037137, 233.2178119026467868 20.4814303279723511, 233.2217592402049036 20.4513196856889081, 233.2251909010724376 20.4212673943469092, 233.2282694104284246 20.3912575382026091, 233.2318419184239815 20.3612045154493551, 233.2355239631731934 20.3311453845283800, 233.2391586893154454 20.3010952640841857, 233.2428990778608409 20.2710394342439209, 233.2464567058851799 20.2410056660194115, 233.2499761034000585 20.2109800535650557, 233.2536732782447757 20.1809418254342710, 233.2573748161999561 20.1509076803071849, 233.2610258437933908 20.1208946526018622, 233.2648839717270732 20.0908774183957277, 233.2690707989333987 20.0608332119564245, 233.2729399482114729 20.0308241593004865, 233.2766399932764330 20.0008359799500468, 233.2812975167479408 19.9707604951296211, 233.2864835103322889 19.9406389605168357, 233.2910589909978398 19.9105807426328667, 233.2951517126284102 19.8805735518180349, 233.2994281961467209 19.8505534223365530, 233.3035672940375491 19.8205511747602010, 233.3079874496854131 19.7905266854675403, 233.3129269618572437 19.7604571404375058, 233.3212816261195712 19.7300649786178361, 233.3230339210745683 19.7003105135329939, 233.3250709695567195 19.6705333692279076, 233.3296297888962556 19.6405193531334881, 233.3340604185272014 19.6105224014149755, 233.3383183316778968 19.5805467749155397, 233.3428179007618439 19.5505528168766070, 233.3472901991912636 19.5205884333304596, 233.3519547731943362 19.4906315127633185, 233.3565130545534316 19.4606896820815152, 233.3611875776566364 19.4307416675757452, 233.3661894040620268 19.4007673213283738, 233.3703364722979359 19.3708796063483994, 233.3750997856716083 19.3409379714334939, 233.3796821891314153 19.3110185896687092, 233.3838727404156259 19.2811415854923105, 233.3885341449363864 19.2512246218168066, 233.3933864583176216 19.2212534982861243, 233.3986811268006818 19.1912063079851407, 233.4036949063699069 19.1611907724062256, 233.4090010487341260 19.1311522333228261, 233.4132186008963572 19.1012223437114059, 233.4123898127269570 19.0717780874003857, 233.4234938187712487 19.0412018332193078, 233.4281136087350319 19.0112482688797293, 233.4325499943371369 18.9813170712391042, 233.4385722855595304 18.9512397884117654, 233.4443472688414545 18.9211910404438690, 233.4496096001402634 18.8911960802090277, 233.4547716285619288 18.8612156352242870, 233.4583507146321324 18.8313907512366896, 233.4655539292224091 18.8012260954862001, 233.4711278176775977 18.7712214498370962, 233.4767412811399936 18.7412180638716279, 233.4825004788563945 18.7112058596042878, 233.4883578875892454 18.6811893699161615, 233.4930940637389085 18.6512844874408472, 233.4992980387236230 18.6212451930439258, 233.5048315554937517 18.5912746804041475, 233.5077083127482638 18.5615615247289583, 233.5090647555902592 18.5319976053133928, 233.5185189872614160 18.5016701736141833, 233.5255892488342226 18.4715741711933923, 233.5300607514989792 18.4417298953676436, 233.5355540632440920 18.4117937924144925, 233.5416644756876678 18.3818043137723670, 233.5436055658501289 18.3522152471283633, 233.5514883548236185 18.3220390661888821, 233.5588538183609444 18.2918895888480471, 233.5647531547829772 18.2618841625459254, 233.5705679155844336 18.2318918456861674, 233.5766138328914394 18.2018827384108697, 233.5826686372002428 18.1718779111117286, 233.5888785936488432 18.1418635244059807, 233.5951383721327375 18.1118495698595829, 233.6014674713914019 18.0818342119676281, 233.6076764094576106 18.0518354029397550, 233.6140209223674447 18.0218522835348942, 233.6204423275639499 17.9918892523867555, 233.6265487122047375 17.9619613307537307, 233.6313515417370468 17.9321620036408724, 233.6386754118331623 17.9021295475461208, 233.6451980358386891 17.8721782134278229, 233.6513777074440270 17.8422646488141154, 233.6535623902091174 17.8127339294621407, 233.6609506865577828 17.7827168172390735, 233.6699594117104652 17.7525520608943062, 233.6710216303398511 17.7231431656523668, 233.6718987092317263 17.6937567665132818, 233.6886100264511015 17.6628813678102041, 233.6960663227023360 17.6328849764937026, 233.7026278411701696 17.6029784898318908, 233.7090592952019392 17.5730897219913338, 233.7159774810301656 17.5431605027643300, 233.7217275105666658 17.5133469216293491, 233.7187734896178881 17.4843590860856430, 233.7270853483592816 17.4543148473689627, 233.7331808847967238 17.4244650559017842, 233.7435127694119501 17.3942028951404559, 233.7536136123764550 17.3639679699225304, 233.7604356213903998 17.3340473252823202, 233.7671770100476181 17.3041397118946279, 233.7740217614510811 17.2742278149319262, 233.7808503086502583 17.2443229050392972, 233.7874669746069003 17.2144434060500267, 233.7940569940029150 17.1845718878380964, 233.8008596200677403 17.1546858578329271, 233.8077378287035799 17.1248364577722327, 233.8147908320279384 17.0950124866517008, 233.8216472061115496 17.0652127325247527, 233.8287550488172997 17.0353950862872061, 233.8358236301640147 17.0055868895558788, 233.8429318876114280 16.9757807353721617, 233.8498250513235348 16.9460005561536065, 233.8567982136574130 16.9162186517835664, 233.8644027751852263 16.8863833032129627, 233.8717789030441736 16.8565752238198172, 233.8787743155450869 16.8267903345429843, 233.8864271812514346 16.7969322128191187, 233.8943020020596748 16.7670590848810335, 233.9020234295209661 16.7372061476229561, 233.9097388861925424 16.7073595931650267, 233.9174310488908475 16.6775210529157718, 233.9253368298226405 16.6476683527042368, 233.9331359103080388 16.6178315076893384, 233.9401620368684860 16.5880728789070986, 233.9480199084255219 16.5582422694894404, 233.9556240340308193 16.5284143707426239, 233.9629611951967263 16.4985917371493827, 233.9680858443129523 16.4689817308657247, 233.9697189392310293 16.4397036867625950, 233.9810825587126999 16.4095219192687409, 233.9908561410638583 16.3794945960977181, 233.9882558493688407 16.3506288802557158, 234.0070396851330088 16.3197717513132687, 234.0069713596252257 16.2906809733634645, 234.0202313686372690 16.2603515811765043, 234.0396206151059175 16.2294769327835269, 234.0450716390547257 16.1999297991625184, 234.0561919768812231 16.1698594103722328, 234.0658256080933484 16.1399339059125637, 234.0741862230366053 16.1101332895480986, 234.0828109349569388 16.0803141029273959, 234.0913423001478861 16.0505097118435671, 234.0998453011710581 16.0207140639358840, 234.1085331389405724 15.9909072930984184, 234.1171059035083317 15.9611173752930284, 234.1257060288378398 15.9313287300367410, 234.1339610710348325 15.9015761555191926, 234.1421311326384966 15.8718375959232461, 234.1504002194577083 15.8420959238435071, 234.1587546085733038 15.8123524373627689, 234.1674495379575944 15.7825834029317171, 234.1763947301172379 15.7527972553046673, 234.1849920604829549 15.7230496510434978, 234.1933783950208010 15.6933278489870141, 234.2016682323672399 15.6636212039726974, 234.2106661097371330 15.6338573919411754, 234.2195850300125812 15.6041094923900445, 234.2284696625345362 15.5743710696477020, 234.2372546655175825 15.5446481978355635, 234.2462970033934653 15.5149077482144548, 234.2553563453492700 15.4851720525691974, 234.2644515611109171 15.4554393745744640, 234.2736445746276672 15.4257039865255372, 234.2828900285930445 15.3959701114112715, 234.2920854371643600 15.3662472678846918, 234.3013275319601121 15.3365240160720102, 234.3104684925448282 15.3068141675627576, 234.3196567184559171 15.2771063205312636, 234.3288051980732121 15.2474085454701420, 234.3378564288254040 15.2177261763429676, 234.3470450329756147 15.1880375021932217, 234.3562524198230790 15.1583535186594638, 234.3654777340127566 15.1286743193465885, 234.3747378383685600 15.0989983562836780, 234.3840812970269099 15.0693211572941888, 234.3931289741022397 15.0396512747805424, 234.4024907287820838 15.0099336756868436, 234.4122604228975320 14.9801847782135837, 234.4219977290714496 14.9504452810051323, 234.4316158209413175 14.9207232126728684, 234.4409823334430314 14.8910307928157444, 234.4498350286750110 14.8613922148236579, 234.4587414390796880 14.8317550981146464, 234.4679675142334077 14.8020949297871471, 234.4770902761938487 14.7724507458019882, 234.4864736837242276 14.7428161287315724, 234.4957933007898987 14.7132196608638868, 234.5055218334094320 14.6835921627047021, 234.5149128953590321 14.6540024086710705, 234.5240841556149007 14.6244395506431939, 234.5338855759494265 14.5948253658854963, 234.5441277226521208 14.5651773496976809, 234.5546148319625388 14.5355135559399802, 234.5650071680218787 14.5058652497170044, 234.5754239649154727 14.4762214794163899, 234.5860298977281388 14.4465631054023973, 234.5967350007561549 14.4168986450669667, 234.6069521162467595 14.3872858480204027, 234.6171532254527108 14.3576813563411001, 234.6275466840538684 14.3280660629932619, 234.6379311549196132 14.2984584660047549, 234.6483279323177840 14.2688566256103471, 234.6586953208047248 14.2392643795011899, 234.6688702844758154 14.2096966780773801, 234.6792465114648394 14.1801174490024717, 234.6895268513892461 14.1505511408581999, 234.6998289448953869 14.1209871012067207, 234.7101500394397249 14.0914282330706850, 234.7207265989751477 14.0618529129046621, 234.7321276646645174 14.0322091287124753, 234.7421715987841822 14.0026964529921525, 234.7518848038956207 13.9732209508361525, 234.7623775574045908 13.9436811555426505, 234.7730116684240329 13.9141354451606869, 234.7836780932641432 13.8845938046600299, 234.7943396384987409 13.8550596462965867, 234.8051586487551106 13.8255181701178120, 234.8160814495536499 13.7959742975977520, 234.8270783532049677 13.7664307564641781, 234.8381481281384708 13.7368876812022336, 234.8493417347459626 13.7073404461621493, 234.8606864116887891 13.6777865960779810, 234.8720570722587695 13.6482375497503181, 234.8830833189579153 13.6187270373040779, 234.8942578953382849 13.5892102038194746, 234.9053801461334103 13.5596778327200713, 234.9167589090509409 13.5301032210258434, 234.9279630753756862 13.5005515901187998, 234.9394192259657075 13.4709841685230565, 234.9508887087120570 13.4414226749875407, 234.9626309708700092 13.4118435574707444, 234.9742477492847001 13.3822830146718683, 234.9858310012523361 13.3527327037391963, 234.9970791621786645 13.3232199972591179, 235.0084942258517060 13.2936993449303262, 235.0186419320547770 13.2643038493261933, 235.0288272435886654 13.2349149251491429, 235.0401198038483130 13.2054328062422535, 235.0532620142338942 13.1757903601525115, 235.0624271207734637 13.1465153770093188, 235.0713600064045181 13.1172684942958018, 235.0793940337581773 13.0881099968979449, 235.0890500815441442 13.0588118576902463, 235.1001302405501292 13.0293921653006670, 235.1114135822560058 12.9999613922397987, 235.1209243695386135 12.9707237606482622, 235.1309020897631967 12.9414756651344671, 235.1414756816764111 12.9121812018778357, 235.1521051678167282 12.8828891503746874, 235.1634486045849428 12.8535402164776311, 235.1748378334555696 12.8241946968538798, 235.1866932396247023 12.7948147508486230, 235.1962591085319332 12.7656485146804908, 235.2079865863656210 12.7362952189512431, 235.2197326745993564 12.7069478740712292, 235.2313225714797227 12.6776155785111655, 235.2423722895124456 12.6483331654411657, 235.2530634947058275 12.6190905340401507, 235.2639518184354870 12.5898377702199067, 235.2744025913661972 12.5606318600724833, 235.2867725902066240 12.5312613935276893, 235.2991023661358554 12.5019022719193416, 235.3116716233483317 12.4725294411014680, 235.3219926188672559 12.4433657659187435, 235.3334198864922939 12.4141106633753413, 235.3448295691033252 12.3848381641287766, 235.3590631815229699 12.3552954059736244, 235.3671572189190329 12.3263093688257435, 235.3791241623066526 12.2969845357516654, 235.3921032498335251 12.2675769255236968, 235.4040318790397635 12.2382708372973283, 235.4133898124759412 12.2092018441388941, 235.4233087209120754 12.1800902645324154, 235.4339080982001633 12.1509255317515059, 235.4452235714741732 12.1217045744836511, 235.4567443232773485 12.0924703557183673, 235.4687492488390603 12.0631982531233284, 235.4810288736117343 12.0339094861732558, 235.4933593765949809 12.0046240088453988, 235.5055131845066398 11.9753620783452046, 235.5183936065197372 11.9460434002548155, 235.5313914411344456 11.9167221953183766, 235.5445277549280831 11.8873966213114510, 235.5579758498066951 11.8580513221761468, 235.5708596306864138 11.8287640872622291, 235.5855568213401057 11.7993272975650001, 235.5997530464832153 11.7699461618724968, 235.6118792697535014 11.7407565433221990, 235.6222863798969911 11.7117271087385006, 235.6370065829994473 11.6823236091034826, 235.6501351704513638 11.6530691110666691, 235.6620788997951479 11.6239274594960467, 235.6746660023580091 11.5947368831364361, 235.6884231603173134 11.5654509339622127, 235.7004295445095465 11.5363277616853921, 235.7116587816107085 11.5072743978115124, 235.7235065834900070 11.4781679472531284, 235.7365096550366843 11.4489676032006518, 235.7509681343241255 11.4196470655214046, 235.7663406602953842 11.3902542183865680, 235.7777363714225487 11.3612199442138877, 235.7886739885624081 11.3322339874387712, 235.8008113264958752 11.3031504556224576, 235.8129270658486121 11.2740769145439135, 235.8254455463137447 11.2449760862040176, 235.8379734894969602 11.2159103138021745, 235.8515159915447725 11.1867900343017315, 235.8657944078324533 11.1576136472878034, 235.8797318094723323 11.1284757052297838, 235.8937716656566295 11.0993373101821948, 235.9083287918834912 11.0701621525964011, 235.9230551242763454 11.0409807942013884, 235.9376740007390367 11.0118174850440660, 235.9515272763334792 10.9827297851711894, 235.9638445602315073 10.9537849358168433, 235.9770623676747050 10.9247485593648115, 235.9907218608971675 10.8956618895965978, 236.0047319410548710 10.8665530900764757, 236.0183309333028205 10.8374886511489024, 236.0323861690051217 10.8083929297519816, 236.0537151650576106 10.7647439316584101, 235.8067955133562918 10.7864349997890745, 235.6404746257549050 10.8009251269224666, 235.4886934161562522 10.8140812538426001, 235.3440743681632910 10.8265506526397761, 235.2013541677872581 10.8387871303979466, 235.0605785760558319 10.8507895528866278, 234.9266644391591967 10.8621511165544629, 234.7983134326682091 10.8729887160327809, 234.6742684848875911 10.8834132357187165, 234.5539738435557524 10.8934756928844916, 234.4326844057642347 10.9035680020157439, 234.3062264801245078 10.9140277809663289, 234.1842183967321489 10.9240715931274881, 234.0687460570583767 10.9335373293069242, 233.9561439769058779 10.9427259417912897, 233.8474210956630941 10.9515604135292630, 233.7435151522079764 10.9599707574291010, 233.6385624025285779 10.9684248104055762, 233.5358140067684758 10.9766660933000040, 233.4407131631531342 10.9842712723458433, 233.3422237141446089 10.9921074822156939, 233.2513957968607770 10.9993144684110025, 233.1514470230774236 11.0071956760767744, 233.0568672341267700 11.0146280042103317, 232.9714593141206933 11.0213255319050134, 232.8803341230172634 11.0284323244548670, 232.7943082344645234 11.0351214682081267, 232.7094524258487809 11.0416948896581584, 232.6269891539108698 11.0480614832231296, 232.5469229652644003 11.0542229776369414, 232.4651981313369333 11.0604848215878420, 232.3872682244125372 11.0664391550579371, 232.3089820002455212 11.0723973916104068, 232.2344266808471787 11.0780568263891777, 232.1612777882611454 11.0835918116323047, 232.0879579900140470 11.0891193379889472, 232.0165771813887829 11.0944847829273954, 231.9444953164244225 11.0998822668698853, 231.8732154220784025 11.1052019606563341, 231.8057772059842137 11.1102241836769391, 231.7386284223711357 11.1152083218847455, 231.6726527935735476 11.1200909547501503, 231.6064561948248581 11.1249729598940039, 231.5413069011224252 11.1297634611436891, 231.4780838222075090 11.1344005203999075, 231.4150219500249648 11.1390109034253282, 231.3534789037249766 11.1434985250687841, 231.2922763752978028 11.1479476252960801, 231.2321986804804794 11.1523031971319337, 231.1727759778428037 11.1565989553883913, 231.1144830584675276 11.1608020872514313, 231.0567419751282898 11.1649536385302959, 231.0002949603130560 11.1690023089595822, 230.9442330255996012 11.1730119569343636, 230.8887529573796940 11.1769692032438535, 230.8340953656556849 11.1808578017260682, 230.7801047938849308 11.1846889342734368, 230.7267933250105045 11.1884621644695308, 230.6741394301091361 11.1921793597281169, 230.6222024977036256 11.1958368476612193, 230.5710284673361059 11.1994319110143277, 230.5203688901636383 11.2029818304628161, 230.4702850162541097 11.2064827482238254, 230.4211332149626514 11.2099109379551614, 230.3722347960806189 11.2133125718895528, 230.3238995148835784 11.2166669987468914, 230.2759727552658831 11.2199848672525331, 230.2288337046632591 11.2232410798017437, 230.1821784107610824 11.2264562859122705, 230.1360978920992295 11.2296246903222858, 230.0904502464934467 11.2327559867974252, 230.0451126661331216 11.2358585089279455, 230.0005121694859724 11.2389042679665572, 229.9563201538430519 11.2419152341142556, 229.9126038169200399 11.2448872011781855, 229.8693914420420299 11.2478185506001704, 229.8266141936523184 11.2507140176866294, 229.7844926752366916 11.2535594487218482, 229.7426279584758220 11.2563810618782654, 229.7011060076215756 11.2591734075647345, 229.6601354388773188 11.2619231614147370, 229.6197463420439533 11.2646286372140843, 229.5797488137789628 11.2673023162466013, 229.5399124326933133 11.2699591633018610, 229.5003744155729350 11.2725904639326817, 229.4613780020150386 11.2751808122651163, 229.4229479289658684 11.2777288707496979, 229.3846678777049135 11.2802613604144675, 229.3465203971843209 11.2827794526095389, 229.3092627460586925 11.2852352682155725, 229.2721541795518476 11.2876759727222726, 229.2355028971691127 11.2900822055293482, 229.1990236077021166 11.2924720971991874, 229.1627789235925547 11.2948417900818434, 229.1268004674420808 11.2971894009668841, 229.0910977852267649 11.2995144425208274, 229.0558429789198271 11.3018062999761106, 229.0210984390745352 11.3040612741786060, 228.9866394069139233 11.3062935182293387, 228.9523786369051948 11.3085085479038057, 228.9184628476472199 11.3106973739286527, 228.8847576778029236 11.3128684166009155, 228.8514037966496630 11.3150131009844550, 228.8184344402529860 11.3171295215195844, 228.7856962146676381 11.3192272249858732, 228.7530968391201327 11.3213119416410706, 228.7207523182538011 11.3233766438682970, 228.6886580791888548 11.3254217054343140, 228.6568808000468778 11.3274431670293065, 228.6255699416117011 11.3294320811030538, 228.5943557727714790 11.3314109976706181, 228.5633199203958270 11.3333750202067787, 228.5325366678410148 11.3353197346958279, 228.5019329259168614 11.3372496289070188, 228.4715394680731606 11.3391629188288920, 228.4413945509302266 11.3410573865418609, 228.4114629408679491 11.3429352267224708, 228.3817510016923791 11.3447961341414132, 228.3522475214008693 11.3466408530271430, 228.3230615139313500 11.3484629748790802, 228.2940740736262910 11.3502696640891205, 228.2653336387764398 11.3520581199518507, 228.2367430860684010 11.3538341663080313, 228.2082916103083221 11.3555984904766412, 228.1800368130793402 11.3573477475009152, 228.1520392237875967 11.3590784464209342, 228.1243947354929844 11.3607850493464380, 228.0969443603398190 11.3624769794781848, 228.0696393456295255 11.3641571482644714, 228.0424929933010674 11.3658248267683568, 228.0154106641673479 11.3674855738926137, 227.9885578563481090 11.3691297953353860, 227.9618650794203916 11.3707615940505704, 227.9353348111912396 11.3723808773608184, 227.9089933044639338 11.3739861801390099, 227.8828228745905733 11.3755785815541994, 227.8568634996864830 11.3771558345525570, 227.8309964239465444 11.3787248265649747, 227.8053094676684509 11.3802805503758560, 227.7797848238544418 11.3818240807472488, 227.7544332388526129 11.3833548536377425, 227.7292690741705030 11.3848721031830866, 227.7042771343951131 11.3863767513912482, 227.6794424865351800 11.3878696987312154, 227.6547547108986294 11.3893515833046521, 227.6302153125810150 11.3908223637586836, 227.6058446822487724 11.3922809322129392, 227.5815837284553709 11.3937306712760567, 227.5574768187678671 11.3951691152893577, 227.5335303503320290 11.3965959501297078, 227.5097275399109833 11.3980121642247632, 227.4860553007756891 11.3994185320559449, 227.4625029322769194 11.4008156893181010, 227.4390700032307677 11.4022036943794802, 227.4157514915798401 11.4035828609687275, 227.3925662525225277 11.4049521734577688, 227.3695676411404634 11.4063087093438345, 227.3466880305276732 11.4076562680175844, 227.3239817936694465 11.4089918766877361, 227.3013618133047657 11.4103203927839996, 227.2788626998101620 11.4116399330742162, 227.2564905837951414 11.4129501940545595, 227.2341471861246589 11.4142566063190998, 227.2119503831800671 11.4155527167828215, 227.1898755316235281 11.4168399144063599, 227.1679212759821098 11.4181183068057468, 227.1461045130937180 11.4193870060476002, 227.1244248889418884 11.4206460692728200, 227.1028554367262871 11.4218969988970223, 227.0813921445934511 11.4231400422407976, 227.0600099683260851 11.4243765834220206, 227.0387800565269458 11.4256027995308020, 227.0176858866700798 11.4268196232913724, 226.9967364182923575 11.4280266090250606, 226.9758565799991175 11.4292278308048427, 226.9550385935661438 11.4304237238046955, 226.9342329016709527 11.4316169579053160, 226.9135052379866693 11.4328040202277581, 226.8929749480163025 11.4339785612803286, 226.8725374557903933 11.4351462062810594, 226.8522123581975904 11.4363059371368614, 226.8319968195319518 11.4374579339902080, 226.8118864201212830 11.4386024598112943, 226.7918595656044261 11.4397406845203591, 226.7719343835057941 11.4408716721278090, 226.7520928931478466 11.4419963969853455, 226.7323585007384281 11.4431136486025746, 226.7126918304146841 11.4442255234732162, 226.6930802682913395 11.4453327000192520, 226.6735784057233900 11.4464323335893088, 226.6541678320585618 11.4475254147592338, 226.6348499723003442 11.4486118924843758, 226.6156086420497218 11.4496926332811135, 226.5964513089176933 11.4507672681177564, 226.5773802830670434 11.4518356983188632, 226.5583938982732661 11.4528980320230023, 226.5394514986686545 11.4539563930335220, 226.5205720112754193 11.4550098145010288, 226.5017744116908602 11.4560573339612244, 226.4830830479979795 11.4570977194829062, 226.4644630477073406 11.4581327889146110, 226.4458929607677931 11.4591636593943669, 226.4273420018058687 11.4601919179165428, 226.4089327375767766 11.4612113075362014, 226.3905321797895454 11.4622286455691960, 226.3721760724194212 11.4632421133368112, 226.3540415653064031 11.4642427211329796, 226.3361333516311902 11.4652302892907620, 226.3181669859138481 11.4662192771337370, 226.3002739486506414 11.4672030229303150, 226.2824320913041447 11.4681826620260043, 226.2646422367273829 11.4691581650756813, 226.2469095834710231 11.4701292830936161, 226.2292344049313613 11.4710960160787412, 226.2116353879809196 11.4720574419513905, 226.1941018513785195 11.4730141135446058, 226.1766306716312727 11.4739662026907254, 226.1592231105851738 11.4749136616605600, 226.1418925461004221 11.4758558407877338, 226.1246140672749334 11.4767939954809552, 226.1074024905080080 11.4777274041137787, 226.0902695214729761 11.4786555042624911, 226.0731674626638892 11.4795806696773699, 226.0561148944823913 11.4805019915790982, 226.0391203976545000 11.4814190596774139, 226.0221853383609414 11.4823318209273602, 226.0053302814410472 11.4832392822302296, 225.9885536989861521 11.4841415383497054, 225.9718003975521015 11.4850413028381251, 225.9550662527160227 11.4859387811263272, 225.9383869128336073 11.4868322431797392, 225.9217536701517588 11.4877221247833088, 225.9051656781826694 11.4886084777220994, 225.8886411839913251 11.4894904303538112, 225.8721818201436236 11.4903679195340374, 225.8557774564195881 11.4912414492684523, 225.8394241488462342 11.4921112224597586, 225.8231345766302809 11.4929766430547815, 225.8068834000255265 11.4938389401884038, 225.7906841315510178 11.4946974768467598, 225.7745264906764078 11.4955527558965223, 225.7584156584574941 11.4964045403774655, 225.7423465946611998 11.4972530808697773, 225.7263306551080575 11.4980978487034413, 225.7103637501312221 11.4989390503598727, 225.6944403535995036 11.4997769586268923, 225.6785731333571050 11.5006109868028865, 225.6627606321937378 11.5014412173606573, 225.6469855377227418 11.5022684764026728, 225.6312478555471159 11.5030927722663776, 225.6155505187072094 11.5039139764720364, 225.5999034371527046 11.5047316362642942, 225.5843036923893692 11.5055458998858171, 225.5687372937127009 11.5063574287637689, 225.5532030184862720 11.5071662870658162, 225.5377227249349801 11.5079714709681884, 225.5222898787807537 11.5087732956897497, 225.5069090090448185 11.5095715644164116, 225.4915549235061576 11.5103674479623646, 225.4762447625155630 11.5111601660448812, 225.4609749326394876 11.5119498938921581, 225.4457365038286696 11.5127370489375576, 225.4305250723075176 11.5135218388493641, 225.4153505895338014 11.5143038171213359, 225.4002092546284359 11.5150831649119514, 225.3851016085638150 11.5158598654166955, 225.3700330195549384 11.5166336842014942, 225.3550142447406586 11.5174041464428125, 225.3400350352184205 11.5181717255856153, 225.3250842761325714 11.5189369296322024, 225.3101705090110158 11.5196993830200647, 225.2952945149411903 11.5204590600189825, 225.2804449879828610 11.5212164731226459, 225.2656236019600158 11.5219715538163481, 225.2508347977898495 11.5227241118038251, 225.2360836991653628 11.5234739286072880, 225.2213701223723774 11.5242210218960768, 225.2066922232504851 11.5249654822953609, 225.1920523314319951 11.5257072167190113, 225.1774439551024329 11.5264465188783944, 225.1628688639239897 11.5271833193508328, 225.1483231609231552 11.5279177960269053, 225.1338080113099807 11.5286499054819824, 225.1193156868255869 11.5293799895936147, 225.1048406914377722 11.5301082903483749, 225.0903927203169417 11.5308343935948976, 225.0759731997245012 11.5315582445592408, 225.0615726061136002 11.5322802576213750, 225.0471948914249083 11.5330002677360390, 225.0328448252998612 11.5337180770247585, 225.0185250472492839 11.5344335803454978, 225.0042336758090187 11.5351468651000371, 224.9899666840133534 11.5358581082564022, 224.9757293128520246 11.5365670952889214, 224.9615188349451955 11.5372739482831097, 224.9473343603615376 11.5379787112424026, 224.9331867189993375 11.5386809398550962, 224.9190651590855339 11.5393810912804309, 224.9049589851288147 11.5400796146826767, 224.8908763596490132 11.5407761760249503, 224.8768203267520391 11.5414706560850604, 224.8627911626610114 11.5421630507503572, 224.8487873231403000 11.5428534304463426, 224.8348025935591181 11.5435420547040781, 224.8208432662325720 11.5442286728549526, 224.8069064464880853 11.5449134088086414, 224.7929952890946197 11.5455961415900230, 224.7790961745715776 11.5462774242074886, 224.7652157298564077 11.5469569934464307, 224.7513584997161331 11.5476346729728920, 224.7375268209599426 11.5483103768095692, 224.7237220902749186 11.5489840576781049, 224.7099413765578788 11.5496558393060678, 224.6961637810832997 11.5503265461398499, 224.6824171483842463 11.5509950911857651, 224.6686890557816412 11.5516619670139438, 224.6549772382032870 11.5523272659126732, 224.6412812909752574 11.5529910072087638, 224.6276091034430635 11.5536528929961193, 224.6139594562434354 11.5543129777076103, 224.6003182497858006 11.5549718025661790, 224.5867005368061768 11.5556288004452163, 224.5731010661888547 11.5562841764879369, 224.5595318451174194 11.5569374888469998, 224.5459817047643298 11.5575891644451580, 224.5324427190798815 11.5582395019069590, 224.5189143401576359 11.5588885230225653, 224.5054022183505253 11.5595360233582785, 224.4919123846902949 11.5601817896909882, 224.4784375362918638 11.5608260941027616, 224.4649757674625334 11.5614690093643926, 224.4515271517104509 11.5621105363191763, 224.4380954082653261 11.5627505474210590, 224.4246791510040566 11.5633890977002647, 224.4112755960885579 11.5640262896198038, 224.3978846737749677 11.5646621293277576, 224.3845066428580992 11.5652966117857332, 224.3711457528072515 11.5659295968898927, 224.3577977362114098 11.5665612362847945, 224.3444652819509599 11.5671914448426545, 224.3311485458355321 11.5678202246618902, 224.3178463670823248 11.5684476215481666, 224.3045557510947106 11.5690737397450363, 224.2912636805589273 11.5696990018417232, 224.2779812886721800 11.5703230455083013, 224.2647169075775651 11.5709456114698312, 224.2514653724537084 11.5715668719248761, 224.2382246445113196 11.5721868961343315, 224.2249954647936079 11.5728056663857917, 224.2117774258863392 11.5734232007857401, 224.1985677641189909 11.5740395865862702, 224.1853739310522826 11.5746546100326633, 224.1721921301367502 11.5752683925175557, 224.1590180429048473 11.5758810639248129, 224.1458517540414732 11.5764926247077877, 224.1326993443369702 11.5771029132241079, 224.1195552562867022 11.5777120902351882, 224.1064199000637984 11.5783201500287358, 224.0932922280786954 11.5789271253157224, 224.0801718772106028 11.5795330298010377, 224.0670575303311693 11.5801378996871751, 224.0539473086338944 11.5807417811292535, 224.0408440714013807 11.5813446074145912, 224.0277532395568016 11.5819462641689164, 224.0146726415863156 11.5825468155354798, 224.0016005777064834 11.5831463107815456, 223.9885357303068645 11.5837447873712964, 223.9754767473346249 11.5843422797721392, 223.9624200726210574 11.5849388562089182, 223.9493664901763452 11.5855344995887322, 223.9363221822940204 11.5861291150833985, 223.9232837412836545 11.5867227707854603, 223.9102514687331791 11.5873154735646100, 223.8972278339569755 11.5879072106724532, 223.8842074228040815 11.5884980596409797, 223.8711897945744056 11.5890880278296748, 223.8581768384303530 11.5896771077336158, 223.8451691054746391 11.5902653131262348, 223.8321650096247595 11.5908526677192896, 223.8191624724294400 11.5914391819224214, 223.8061618009816982 11.5920248568798332, 223.7931629563942124 11.5926096948298980, 223.7801640483884000 11.5931936738872050, 223.7671670080404738 11.5937768052707177, 223.7541730621465206 11.5943591186183355, 223.7411823205447945 11.5949406428819639, 223.7281945822350337 11.5955214095179322, 223.7152092203544385 11.5961014400467324, 223.7022255713048651 11.5966807498982512, 223.6892422590746605 11.5972592901497755, 223.6762589726454564 11.5978370356977827, 223.6632763821540379 11.5984140565029339, 223.6502941596612857 11.5989903554735552, 223.6373122485578335 11.5995659928018640, 223.6243300457994962 11.6001409101370658, 223.6113474183802055 11.6007150945084003, 223.5983643014758400 11.6012885646784696, 223.5853804742061470 11.6018613807905986, 223.5723949789524738 11.6024337740613070, 223.5594084415180305 11.6030053638277604, 223.5464202437128449 11.6035763342790688, 223.5334298265300106 11.6041467476564506, 223.5204368671151371 11.6047166055491360, 223.5074413311777732 11.6052858741608844, 223.4944432982260878 11.6058545207539812, 223.4814424785570282 11.6064225703277106, 223.4684383277615609 11.6069900726994284, 223.4554303426207014 11.6075570640144381, 223.4424179562216466 11.6081235823802729, 223.4294005333650261 11.6086896685705749, 223.4163767564448335 11.6092554251278610, 223.4033493491632782 11.6098205677991153, 223.3903182963025813 11.6103850983762680, 223.3772834961584977 11.6109490258485462, 223.3642450371687289 11.6115123420402675, 223.3512033206641831 11.6120750138095037, 223.3381552833168939 11.6126372900905022, 223.3251009602240629 11.6131991535604495, 223.3120397912722694 11.6137606354717011, 223.2989722102144583 11.6143216904755171, 223.2858985034930583 11.6148822884616827, 223.2728171532845636 11.6154425337012217, 223.2597285678833714 11.6160023858956460, 223.2466317184563422 11.6165619095860269, 223.2335277664742250 11.6171210135472638, 223.2204169764052324 11.6176796739022219, 223.2072988293887477 11.6182379214719891, 223.1941722853877934 11.6187958206584732, 223.1810361052811231 11.6193534462392414, 223.1678913125285533 11.6199107220438567, 223.1547381380195532 11.6204676270151754, 223.1415754377214569 11.6210242292760277, 223.1284015147909088 11.6215806294669566, 223.1152151257165031 11.6221368962333464, 223.1020209030151591 11.6226927309393702, 223.0888180899143265 11.6232481781277563, 223.0756052319343894 11.6238033234461149, 223.0623811454720169 11.6243582333811339, 223.0491451294242324 11.6249129434947029, 223.0358968024115143 11.6254674694465940, 223.0226367869014155 11.6260217673261099, 223.0093615337405595 11.6265760397115319, 222.9960678207878289 11.6271304645774993, 222.9827655838388409 11.6276844535504686, 222.9694554206592443 11.6282379715212940, 222.9561342545880791 11.6287911941992874, 222.9427998983100281 11.6293442422904629, 222.9294510268497618 11.6298971849420401, 222.9160884180228379 11.6304499718435075, 222.9027074603658320 11.6310028545879973, 222.8893176033846544 11.6315552994956750, 222.8759211426458364 11.6321071794923281, 222.8625124070450170 11.6326588071240913, 222.8490832134943105 11.6332106252390162, 222.8356348319159679 11.6337625545310193, 222.8221730868960435 11.6343142716203864, 222.8086998368628429 11.6348656728460096, 222.7952032410204595 11.6354173891255144, 222.7816844858264176 11.6359693461022591, 222.7681514532162907 11.6365211163933147, 222.7546094596874582 11.6370724158921028, 222.7410496054532985 11.6376237118726849, 222.7274689117783737 11.6381751538626546, 222.7138741945792617 11.6387263791939706, 222.7002655263075610 11.6392773809061207, 222.6866375324841840 11.6398284332340385, 222.6729866912269813 11.6403797107135620, 222.6593141329908860 11.6409311470154808, 222.6456207319734517 11.6414826900451747, 222.6319141538503459 11.6420339437049947, 222.6181898888893045 11.6425851339993081, 222.6044497077721189 11.6431361669500131, 222.5906859946134375 11.6436874213117392, 222.5768997746839659 11.6442388379762196, 222.5630916264516372 11.6447903810373106, 222.5492639055905215 11.6453419268843490, 222.5354268513513034 11.6458929634969479, 222.5215672763436032 11.6464441414374651, 222.5076782329797993 11.6469957955481860, 222.4937638625373211 11.6475477129612379, 222.4798292363327619 11.6480996383395325, 222.4658732608350817 11.6486516197575565, 222.4519005455341585 11.6492034280487893, 222.4379138599454393 11.6497549259658353, 222.4239108831781380 11.6503062232925174, 222.4098822394056754 11.6508577672794100, 222.3958278149365810 11.6514095559922719, 222.3817501135733607 11.6519614625816654, 222.3676471868176634 11.6525135736721577, 222.3535187113662914 11.6530658977189212, 222.3393601721830919 11.6536186413768217, 222.3251663416662041 11.6541720424480708, 222.3109466623485559 11.6547256460647510, 222.2967040816845383 11.6552793072737142, 222.2824345096863681 11.6558332118137340, 222.2681376654342955 11.6563873656892198, 222.2537934125679442 11.6569426977978026, 222.2394296278611137 11.6574979009509132, 222.2250456168251276 11.6580530033632179, 222.2106332312139614 11.6586083764543140, 222.1961901634210790 11.6591641190119333, 222.1817259895384495 11.6597197839798365, 222.1672323459239919 11.6602757492673135, 222.1527060469091452 11.6608321525715173, 222.1381498752822381 11.6613888587151209, 222.1235645886078771 11.6619458257867201, 222.1089488152713898 11.6625031085844739, 222.0943054474923883 11.6630605689785227, 222.0796369850662870 11.6636180879175448, 222.0649326370137260 11.6641761438836671, 222.0501916741791320 11.6647347600561417, 222.0354200415976607 11.6652936614482083, 222.0206255050637481 11.6658524948229125, 222.0058055009189957 11.6664113692121774, 221.9909317003400986 11.6669715336748272, 221.9760187813593575 11.6675323245008205, 221.9610674740678178 11.6680936993382627, 221.9460834295299492 11.6686553999180322, 221.9310575638693024 11.6692178165951645, 221.9159984711464233 11.6697805626031919, 221.9009259266182426 11.6703427671831417, 221.8858296896012519 11.6709048744380794, 221.8706995944909295 11.6714673207546387, 221.8555326260521667 11.6720302285182029, 221.8403304885907517 11.6725935149842552, 221.8250972499780858 11.6731569963145798, 221.8098195614849146 11.6737212391111864, 221.7944889260287198 11.6742865963530384, 221.7791202134376647 11.6748524179258073, 221.7637180402751653 11.6754184975181445, 221.7482700456498321 11.6759853535227798, 221.7327669514012030 11.6765533683532645, 221.7172115229149085 11.6771224104259019, 221.7016211571622364 11.6776917309401611, 221.6860028019623599 11.6782610287884925, 221.6703447482998399 11.6788307904525208, 221.6546244431601451 11.6794019527549224, 221.6388611839099951 11.6799736915289696, 221.6230487052656883 11.6805462579599428, 221.6071946734351457 11.6811193203291648, 221.5913075585570766 11.6816925165768932, 221.5753864703937950 11.6822658761466585, 221.5594131535227973 11.6828401465026861, 221.5433904492085446 11.6834151972955773, 221.5273308964312662 11.6839905000419062, 221.5112244756874702 11.6845664577698987, 221.4950649900496273 11.6851433129840245, 221.4788646116655002 11.6857205548552301, 221.4626020103548569 11.6862990436845795, 221.4462705120642738 11.6868790352296799, 221.4298859924444685 11.6874598673674512, 221.4134506856227631 11.6880414365501029, 221.3969754781630286 11.6886232905391090, 221.3804605137580950 11.6892054142711981, 221.3638996850384331 11.6897880441024036, 221.3472772159424551 11.6903718019422342, 221.3305813530331534 11.6909571427404071, 221.3137711140890929 11.6915456840148959, 221.2969116219956334 11.6921348014644710, 221.2800176036289201 11.6927238980664523, 221.2630934336351345 11.6933127927512892, 221.2461192125688001 11.6939022660947209, 221.2290863538791825 11.6944926448374797, 221.2119945040117273 11.6950839284474739, 221.1948675705588698 11.6956751636056886, 221.1776935519540359 11.6962668126450478, 221.1604303534508347 11.6968605094593201, 221.1430823375198713 11.6974560609985421, 221.1256729793842624 11.6980525325018565, 221.1082343240075829 11.6986486654835620, 221.0907777951840103 11.6992440115853782, 221.0732731529905379 11.6998397354871226, 221.0556760649134560 11.7004375334853208, 221.0379809653511245 11.7010375956553805, 221.0201910780052401 11.7016397730643700, 221.0023326505245791 11.7022430374960322, 220.9844141227260934 11.7028470498581818, 220.9664267865848046 11.7034521267778491, 220.9483618371737066 11.7040585853194123, 220.9302181846813085 11.7046664470968551, 220.9120117963100824 11.7052750889533552, 220.8937461626249217 11.7058843638380683, 220.8754296372306953 11.7064939431866915, 220.8570353831397597 11.7071048211080821, 220.8385387414589900 11.7077179002450720, 220.8199419597744964 11.7083330701137118, 220.8012542966671958 11.7089499601075602, 220.7824976140121294 11.7095677351636294, 220.7636932618528647 11.7101855873258351, 220.7448115762643397 11.7108046009476432, 220.7258449069571213 11.7114250382026341, 220.7067902066008855 11.7120469892192549, 220.6876435492166593 11.7126705751678788, 220.6684018412074693 11.7132958852828555, 220.6490775002795317 11.7139224419230334, 220.6296751617481959 11.7145500551708555, 220.6101884901048891 11.7151789348560165, 220.5906226553490228 11.7158088720504878, 220.5709709286416000 11.7164400891991463, 220.5512576667543385 11.7170716871744176, 220.5314614383957803 11.7177044199496585, 220.5115590022694505 11.7183390981715050, 220.4915452243125742 11.7189758769615562, 220.4714307799496567 11.7196143463289317, 220.4512468588935121 11.7202533715732269, 220.4309992066251311 11.7208927312610243, 220.4106498399640373 11.7215337511258380, 220.3901880983314356 11.7221767796033038, 220.3696269742773950 11.7228213298105359, 220.3489604038595360 11.7234675875962768, 220.3281690552250609 11.7241162000845698, 220.3072756756521926 11.7247663403802918, 220.2862824116052138 11.7254179062594428, 220.2651764715898821 11.7260713139578279, 220.2439627765912178 11.7267263625395923, 220.2226597862525637 11.7273823863475286, 220.2012604090777756 11.7280396048920075, 220.1797602368997104 11.7286981429012691, 220.1581417345539080 11.7293585718169098, 220.1364090861300156 11.7300207161521186, 220.1145235049643247 11.7306858616742762, 220.0924773395380214 11.7313542240955648, 220.0703026463924346 11.7320246749398347, 220.0480152578872435 11.7326966446454559, 220.0256193313570066 11.7333699618091121, 220.0031393234807240 11.7340437771874182, 219.9805459909590581 11.7347190432092230, 219.9578262375317195 11.7353961632534425, 219.9350228461180166 11.7360736819629690, 219.9120955538532201 11.7367529071512831, 219.8890352094778962 11.7374341046332837, 219.8658230573190906 11.7381178519633735, 219.8424378550888889 11.7388048002984284, 219.8189420393960916 11.7394928593078181, 219.7954051231398296 11.7401797339112850, 219.7717126788431301 11.7408691262396196, 219.7478364883703819 11.7415619025074367, 219.7238247217930223 11.7422564541995804, 219.6876080273489436 11.7432997520176716, 219.6987523783379856 11.7853029348258183, 219.7061791771063213 11.8133127052587579, 219.7135986549952520 11.8413287509520604, 219.7210947404886099 11.8693483800486117, 219.7285881728001300 11.8973741241781958, 219.7359476924907256 11.9254261184903658, 219.7433492070103682 11.9534995743589434, 219.7507477436034549 11.9815790420371595, 219.7579850993488151 12.0096695496526973, 219.7652250045894959 12.0377658721436891, 219.7725553247495327 12.0658652068473060, 219.7800022085723413 12.0939667193786544, 219.7873408945879987 12.1220775512080383, 219.7950743482600444 12.1501817176683833, 219.8021390085208395 12.1783129843083486, 219.8093731982236250 12.2064422366432606, 219.8167053718840123 12.2345716176753587, 219.8241449129442060 12.2627034586213366, 219.8313191007843272 12.2908495551188111, 219.8387108569059478 12.3189946084991693, 219.8460894153435277 12.3471459191465058, 219.8532640727768239 12.3753095044270260, 219.8601696000010008 12.4034874078262014, 219.8674454814815817 12.4316594206823421, 219.8745707847417350 12.4598419912327945, 219.8816850375779950 12.4880175631037620, 219.8889121190733533 12.5161815294953218, 219.8961929096689403 12.5443496532151979, 219.9035207112792421 12.5725221393741400, 219.9108000505651717 12.6007019865559382, 219.9180033534095458 12.6288900488054914, 219.9252926238032160 12.6570812286973613, 219.9325837931077388 12.6852781631490341, 219.9416672226408593 12.7134247385197341, 219.9543961129569709 12.7414629673091664, 219.9609663348926460 12.7696974746052021, 219.9637127244800467 12.7980546219476476, 219.9693396485585026 12.8263272759272802, 219.9763389820033410 12.8545627691681386, 219.9873479021010496 12.8826789123672079, 219.9942663403161589 12.9109285110434602, 220.0001191110418972 12.9392170377871576, 220.0060791740759782 12.9675078899464147, 220.0125259482794604 12.9957892678083056, 220.0204798708710712 13.0240294902412526, 220.0303293169093024 13.0522308973718140, 220.0363637763307167 13.0805716599938897, 220.0435221785276383 13.1088831468612099, 220.0503444747572246 13.1372106969061697, 220.0554559745506822 13.1655969103811366, 220.0637152729870536 13.1938911364857177, 220.0719544405739896 13.2221916259964836, 220.0809450262833025 13.2504744742211660, 220.0855198220701254 13.2788996751998667, 220.0951748736929972 13.3071731967088862, 220.1002723968982480 13.3355840088870234, 220.1073650534362116 13.3639288227772877, 220.1144815965231203 13.3922785024813376, 220.1215875627314631 13.4206341037762407, 220.1287352846985073 13.4489940062221862, 220.1370402478150368 13.4773238026688151, 220.1447839371536475 13.5056765103977678, 220.1521111758974030 13.5340476370338720, 220.1594759153635721 13.5624231738013652, 220.1672083183461552 13.5907929546773101, 220.1735074970197275 13.6191997958310775, 220.1797183181128901 13.6476015911061932, 220.1873653702023717 13.6759648320780922, 220.1929970821997813 13.7043955201351562, 220.2002836979509937 13.7327809783765140, 220.2072371134695743 13.7611822222090847, 220.2143098338185894 13.7895853680132241, 220.2215409215835393 13.8179892236932034, 220.2286146028019118 13.8464034430197227, 220.2359968999591047 13.8748137746859079, 220.2429905146004501 13.9032506380188714, 220.2501006641976744 13.9316990778372372, 220.2572072438011901 13.9601531118914952, 220.2642324533995293 13.9886151017755545, 220.2713546031071132 14.0170796063823371, 220.2784888315825071 14.0455492056894791, 220.2854618046474116 14.0740291667353770, 220.2923997653498702 14.1025156367929014, 220.2996432287141317 14.1309982528014721, 220.3069647400963618 14.1594839346048857, 220.3142063436781086 14.1879636486693368, 220.3212788516616740 14.2164393475970812, 220.3285570372971449 14.2449142697162650, 220.3357705557098143 14.2733966112673958, 220.3430038919728702 14.3018838043373773, 220.3501936696853534 14.3303777594724284, 220.3574521197704712 14.3588750715236415, 220.3646056907983279 14.3873809839935785, 220.3714125046764707 14.4159027845413714, 220.3785545330334230 14.4444198669506729, 220.3856337203785074 14.4729600246978425, 220.3927611377524443 14.5015207375727115, 220.4001050934609509 14.5300802439584995, 220.4070157681905755 14.5586581172829916, 220.4141741432308095 14.5872338303264470, 220.4213520871849141 14.6158142500114483, 220.4283400945614915 14.6444056727811667, 220.4351961118798897 14.6730063437207381, 220.4419879938532176 14.7016142082228836, 220.4491297929428981 14.7302168129408813, 220.4562863979076610 14.7588242338492606, 220.4632064462008714 14.7874440135878196, 220.4702124056549621 14.8160664517127358, 220.4773075834508518 14.8446914417330778, 220.4839436386864122 14.8733354359420797, 220.4909400903970891 14.9019738273440971, 220.4976830000881023 14.9306250291691622, 220.5046871348686750 14.9592735965149846, 220.5120298151077236 14.9879172093816528, 220.5191431519799039 15.0165728860575474, 220.5262490346293305 15.0452192621456238, 220.5332207140164940 15.0738593391698092, 220.5401179893821961 15.1025068648033898, 220.5471624568289997 15.1311551999620413, 220.5542495222690889 15.1598074720371745, 220.5611462413826018 15.1884706315084639, 220.5679511426332056 15.2171417190662979, 220.5747134505176632 15.2458192561080086, 220.5815516684503450 15.2744996976014562, 220.5883461731254158 15.3031866064603790, 220.5952718642558068 15.3318669232528322, 220.6021707513029355 15.3605449415493354, 220.6091175731324370 15.3892267260807749, 220.6161856753946608 15.4179100901230619, 220.6230988133779078 15.4466032396069970, 220.6301581991951366 15.4752972166398326, 220.6372147493088676 15.5039964428243273, 220.6444441173819655 15.5326957055445494, 220.6513662352306255 15.5614092260747814, 220.6584249247968899 15.5901238420788957, 220.6656150398821978 15.6188559149160788, 220.6725666950571849 15.6476172350376110, 220.6794748557452692 15.6763848777368988, 220.6865817603947448 15.7051516699670515, 220.6936357219268530 15.7339250504649613, 220.7007661075990370 15.7627011861934072, 220.7078723698223257 15.7914830405681883, 220.7148087277778075 15.8202749132805174, 220.7215739629539826 15.8490768264030795, 220.7283696406998104 15.8778828200969873, 220.7350802981803497 15.9066906070165093, 220.7416702149446905 15.9355009309045741, 220.7481918200303710 15.9643182514411706, 220.7548889450912384 15.9931353700775922, 220.7613380772242238 16.0219647647033696, 220.7677626895963670 16.0507998367200457, 220.7746364759823905 16.0796266326420181, 220.7812760232888820 16.1084652723297594, 220.7879783038013954 16.1373070026573373, 220.7945420931276601 16.1661577372383505, 220.8003749787557979 16.1950206146460012, 220.8065617770233189 16.2238629585585379, 220.8128621962586067 16.2527069130919699, 220.8191817783076658 16.2815552455657588, 220.8255725903351561 16.3104064260858941, 220.8322066932024370 16.3392554115519815, 220.8387268830610140 16.3681126611654655, 220.8455734890393387 16.3969652843257307, 220.8521103356239621 16.4258318846550431, 220.8587076065097108 16.4547016259001566, 220.8645847861091625 16.4836114738970672, 220.8712379212901737 16.5125184939384759, 220.8780366530769754 16.5414260976919820, 220.8844439642249711 16.5703499435244446, 220.8910779639868736 16.5992719914096050, 220.8980535532646172 16.6281888885597695, 220.9049801592676090 16.6571120172564306, 220.9120543712106723 16.6860356421274894, 220.9194018676946882 16.7149560938374471, 220.9275853959155995 16.7438569741192573, 220.9337514394953814 16.7728073784391292, 220.9389458502036803 16.8017760251284436, 220.9442633220138532 16.8307458475437457, 220.9495797699727007 16.8597204500586884, 220.9576980262959296 16.8886184324824313, 220.9646433114296258 16.9175552949130612, 220.9706915457650780 16.9465229737779772, 220.9797360850324139 16.9754084989699301, 220.9858503433434009 17.0043838123042157, 220.9958092375155729 17.0332524232458873, 221.0051547335982036 17.0621516661765042, 221.0123955262187678 17.0911251846374554, 221.0184945335432474 17.1201365064761575, 221.0265358816036212 17.1490962372719302, 221.0342592253194312 17.1780698849984077, 221.0416971727682665 17.2070564924296576, 221.0492649291077498 17.2360440208405343, 221.0574163923749325 17.2650193214497847, 221.0642376488161744 17.2940378145763631, 221.0712507676574603 17.3230554066094378, 221.0750035062377776 17.3521530122707013, 221.0833825988925980 17.3811014280375140, 221.1012000644046509 17.4097816163128094, 221.1234697965101930 17.4383372243239734, 221.1446009054772333 17.4669299946673000, 221.1659814117942346 17.4955196829087996, 221.1862074954466379 17.5241471727199070, 221.1957570597425331 17.5530905107880031, 221.2038686917591974 17.5820804814770639, 221.2080601841900034 17.6111893255309901, 221.1988433217773320 17.6407165962590362, 221.1916363252985036 17.6702144710442290, 221.1877485889076524 17.6996199313129097, 221.1891656918670037 17.7288761976824780, 221.1968354294688197 17.7579563475155311, 221.2025406653730215 17.7870977089870124, 221.2096147695652917 17.8162040253518299, 221.2165160144454603 17.8453198053554445, 221.2224942250372237 17.8744666958604519, 221.2277119721113934 17.9036399876070469, 221.2332821024614873 17.9327909627809063, 221.2383170207892249 17.9619443244375638, 221.2442905429176676 17.9910751116441041, 221.2498363552460603 18.0202227058669422, 221.2557305329598307 18.0493647450156551, 221.2621416431596799 18.0784963863439394, 221.2691430205308336 18.1076155304318149, 221.2754988091505197 18.1367577198945469, 221.2813337868578571 18.1659193359031370, 221.2877855767731887 18.1950676779960396, 221.2953253954281365 18.2241907180674154, 221.3013599379729328 18.2533629946000460, 221.3064374135869343 18.2825671410003565, 221.3124537532020213 18.3117487397487828, 221.3182281062903485 18.3409416696727448, 221.3250634190553683 18.3701085798518839, 221.3330656596799031 18.3992464481771698, 221.3374356808525363 18.4284927545661610, 221.3395300095252196 18.4578084755441409, 221.3458224373307246 18.4870083936197460, 221.3522630305629093 18.5162084244384495, 221.3577068641920675 18.5454412769644499, 221.3641904027647058 18.5746487548991901, 221.3715279113331746 18.6038361782572146, 221.3767990325112009 18.6330869316119490, 221.3800267736432943 18.6624002608480168, 221.3827362012217748 18.6917325592284413, 221.3870286300991097 18.7210239622508858, 221.3954345647359503 18.7502025136230017, 221.3995412875319175 18.7795077425839843, 221.4052686290156089 18.8087667835240033, 221.4116141406182976 18.8380079578304809, 221.4182075524130937 18.8672463620029056, 221.4234075464069917 18.8965286224053628, 221.4297424897585813 18.9257828880718968, 221.4381330035352846 18.9549830454225798, 221.4437786011409628 18.9842653899860707, 221.4516916823562553 19.0134876142634681, 221.4581724334677801 19.0427547245433644, 221.4643258335165683 19.0720353410303787, 221.4703040024018605 19.1013190922888008, 221.4757366352769736 19.1306161364696550, 221.4827138452384929 19.1598736469144697, 221.4886341156465619 19.1891653109676028, 221.4939175151725124 19.2184791926537528, 221.4996824222843372 19.2477836348834508, 221.5040993847280504 19.2771303360983701, 221.5096515244819102 19.3064491172807848, 221.5157897919053198 19.3357555187522081, 221.5254028690785049 19.3649680591620701, 221.5379303710355430 19.3941024987874364, 221.5502966625256249 19.4232455910307173, 221.5569858010044015 19.4525532672247969, 221.5662602301570416 19.4817920506938691, 221.5778712909811361 19.5109689307780059, 221.5906471456263773 19.5401169398491916, 221.6024846425621888 19.5692955530695656, 221.6125339523005664 19.5985288924105419, 221.6228556391052962 19.6277586118567982, 221.6323660626076446 19.6570154156721273, 221.6415036194281356 19.6862868957955293, 221.6440994496165331 19.7157478620347995, 221.6431790142311229 19.7453121776283425, 221.6474316282330221 19.7747340489961374, 221.6570225245225458 19.8040091392092137, 221.6647075508695082 19.8333421333557425, 221.6736770574902664 19.8626428790710392, 221.6816534358866875 19.8919757276629454, 221.6864937930701558 19.9214011979869667, 221.6879797049289493 19.9509252780549424, 221.6950232773449727 19.9803103315518591, 221.7007288046107476 20.0097516794640882, 221.7040268219716665 20.0392648174781556, 221.7074732178250258 20.0687776378866225, 221.7106187017003549 20.0983027921591813, 221.7176740679891225 20.1277217371706740, 221.7230474806044356 20.1571919248215714, 221.7277670535394805 20.1866843938526479, 221.7319372793065497 20.2161961795330214, 221.7405646672224293 20.2455863928381419, 221.7463882445141508 20.2750552241944000, 221.7538847958166457 20.3044764360793089, 221.7622793455343526 20.3338762064548391, 221.7701565146116707 20.3632943759725293, 221.7734189146283370 20.3928463602206200, 221.7781702147772478 20.4223602164826836, 221.7857704918945956 20.4517976945089401, 221.7905756424046331 20.4813176640664700, 221.7934115372622443 20.5108968160158298, 221.7963450989159071 20.5404769505775988, 221.8001359603279354 20.5700367281890664, 221.8054088754265649 20.5995586336503997, 221.8103228716607873 20.6290943849494575, 221.8166331240383613 20.6585946947209713, 221.8221241242965220 20.6881217626415825, 221.8259241658650183 20.7177000295338409, 221.8288535881722225 20.7473064169434167, 221.8317732953118764 20.7769167504077394, 221.8434864832524909 20.8062842965649075, 221.8548980732984433 20.8356638511278582, 221.8497146824853701 20.8655018098821969, 221.8425379707961156 20.8953868195347319, 221.8373773924683974 20.9252182013111252, 221.8382192560088413 20.9548855526717688, 221.8489009231472266 20.9842827887193941, 221.8672566919577207 21.0134697677843647, 221.8797273719326029 21.0428242377920007, 221.8887999810042686 21.0722772505930536, 221.8917645082245826 21.1019045711432049, 221.8997328109844602 21.1313958605496417, 221.8990926618291439 21.1611280411137344, 221.9019993444164811 21.1907616766640956, 221.9051040779272626 21.2203933633164361, 221.9093557913321604 21.2499967314856093, 221.9134297178846396 21.2796086471933563, 221.9116007489075173 21.3093879023960824, 221.9032882877899908 21.3393495525534931, 221.9060520607352771 21.3690080227605783, 221.9051334272910481 21.3987714956553425, 221.9034009241744343 21.4285605665808703, 221.9100285267176105 21.4581261493741380, 221.9160069827211714 21.4877163657336290, 221.9238932399040323 21.5172577422916227, 221.9293998902381873 21.5468681209350876, 221.9330707636211741 21.5765324977498878, 221.9363254486283381 21.6062118074009035, 221.9410037369304689 21.6358555651428830, 221.9455408147354092 21.6655067257743497, 221.9489016120366500 21.6951936277865123, 221.9527587731917890 21.7248704150393692, 221.9568600871939168 21.7545531875111315, 221.9622411699628231 21.7842141222439771, 221.9689664639304851 21.8138417551274060, 221.9756209612246778 21.8434747837706169, 221.9818735094069382 21.8731222677031809, 221.9874059330027194 21.9027929105330337, 221.9923440429898847 21.9324832583258242, 221.9971277815419626 21.9621812611599196, 222.0022569686276483 21.9918732335909688, 222.0073470416925829 22.0215696931690559, 222.0125447730543442 22.0512545134973443, 222.0181706962175383 22.0809182668990651, 222.0238933056503186 22.1105828124295165, 222.0295305341456356 22.1402531168903742, 222.0351237484508715 22.1699280425233560, 222.0404257554211540 22.1996143288699344, 222.0459155989807130 22.2292988829796059, 222.0512924341139751 22.2589899133886711, 222.0566673648044116 22.2886843762515916, 222.0618862307206882 22.3183864694176677, 222.0670553472532731 22.3480957599217085, 222.0723717417823480 22.3778070085798397, 222.0777839748901954 22.4075189964093404, 222.0831798394412999 22.4372347713886029, 222.0886434003048180 22.4669520384429369, 222.0940816858582423 22.4966733208646978, 222.0994527850592419 22.5263997498348054, 222.1047812729935060 22.5561306496470522, 222.1101155305294128 22.5858646931989888, 222.1154152125551207 22.6156029721982748, 222.1204420127930632 22.6453400486665437, 222.1255646964550010 22.6750652359120757, 222.1305329997020408 22.7047979140034641, 222.1355847787701236 22.7345316112044458, 222.1406216272308427 22.7642689945996821, 222.1456386712231108 22.7940101865939475, 222.1506385132327352 22.8237551067842332, 222.1555893546876348 22.8535046094059986, 222.1605043394521033 22.8832583260641478, 222.1653877636704806 22.9130161310442269, 222.1701197628285342 22.9427889792997348, 222.1746776287420460 22.9725778901872673, 222.1789441576504487 23.0023778463962323, 222.1836557252892987 23.0321689614480825, 222.1902440398285989 23.0619126297839436, 222.1954526487300825 23.0916966954934324, 222.2010831637109334 23.1214725486922212, 222.2083216384725404 23.1512082124632776, 222.2139515806103134 23.1809904050361730, 222.2171221060487198 23.2108420163699769, 222.2209885173431871 23.2406820491138610, 222.2264371355994967 23.2704868989222327, 222.2313264837684983 23.3003099104321585, 222.2360295055708832 23.3301410280497343, 222.2416143589899491 23.3599515095395809, 222.2470280979290465 23.3897696783524971, 222.2519457695078700 23.4196042623493739, 222.2572284978178629 23.4494320946219048, 222.2625351292319067 23.4792623412356001, 222.2678234450957575 23.5090961313971576, 222.2731187338746679 23.5389287176773259, 222.2783913237997240 23.5687606663922935, 222.2836896458203171 23.5985949595753439, 222.2889783774910200 23.6284325359269793, 222.2942692541417387 23.6582730742638745, 222.2995474628026216 23.6881169629623862, 222.3048186546048441 23.7179640408533174, 222.3100880876171175 23.7478141608096358, 222.3153559270981532 23.7776673079717895, 222.3206150332030404 23.8075236678525854, 222.3258698866435168 23.8373906038255825, 222.3311162163473682 23.8672686258960880, 222.3363674375100629 23.8971494473812527, 222.3416002240587375 23.9270336833286628, 222.3468409731698898 23.9569206200426770, 222.3520781787404701 23.9868105567601582, 222.3572950908845201 24.0167039333042780, 222.3625011870320805 24.0466004896446037, 222.3677192511185581 24.0764996045117989, 222.3729424320191299 24.1064014556798796, 222.3781468771423988 24.1362901048424909, 222.3833649201492051 24.1661637831187122, 222.3885678890137285 24.1960407688332495, 222.3937637687527626 24.2259208372428816, 222.3989420319153680 24.2558042638083542, 222.4041440838417998 24.2856899311823682, 222.4093321917397645 24.3155788396142469, 222.4144990636221451 24.3454711774863384, 222.4196730904269543 24.3753661752947579, 222.4248346881902023 24.4052643501693360, 222.4300062062717132 24.4351764710664909, 222.4351870687680162 24.4651031621802915, 222.4403525020867960 24.4950330549062940, 222.4455026491757792 24.5249661348580972, 222.4506599244405436 24.5549017979669095, 222.4558229849398856 24.5848400707973305, 222.4609842278302381 24.6147811468647681, 222.4661284181207179 24.6447254265187219, 222.4713101840497131 24.6746714423507427, 222.4764591914561720 24.7046210641846500, 222.4815193387960335 24.7345653487702748, 222.4865942845428890 24.7645009503149822, 222.4916659845742402 24.7944393662112326, 222.4967339978794314 24.8243805976587986, 222.5017992758810976 24.8543246132578695, 222.5068766617123401 24.8842710086783079, 222.5120706242933011 24.9142169964455960, 222.5176992594136607 24.9441541158756159, 222.5230551169359501 24.9741011721434063, 222.5290723867522047 25.0040333259218990, 222.5331869879559292 25.0340250877719370, 222.5376183126456908 25.0640178059903320, 222.5426224342267290 25.0939979417774595, 222.5478384861640961 25.1239750739483512, 222.5527734021357276 25.1539622860461556, 222.5574433522509423 25.1839591349760852, 222.5625189750431332 25.2139478159431825, 222.5680865705771225 25.2439260391509634, 222.5750931585015167 25.2738686682064539, 222.5818713705537562 25.3038199264691386, 222.5873131975623664 25.3338052353980245, 222.5917661569066013 25.3638151369706009, 222.5953573557681864 25.3938504355635217, 222.5981423237566332 25.4239096057939271, 222.6021066629561744 25.4539400323271927, 222.6070875480329789 25.4839460669213302, 222.6120740674626006 25.5139544753543177, 222.6170732825590335 25.5439650649896670, 222.6222362522800324 25.5739738306894857, 222.6271684386293259 25.6039912012273234, 222.6335610291737908 25.6339683652455541, 222.6407584509559285 25.6639224326588256, 222.6425063814833436 25.6940230383128245, 222.6465820115638792 25.7240645598688502, 222.6516161452649101 25.7540832404217426, 222.6567612330741497 25.7841014576707153, 222.6622771705746118 25.8141123513063810, 222.6675096863309875 25.8441331729110537, 222.6724462652234706 25.8741642349645389, 222.6771134454122034 25.9042048235666194, 222.6827850674766864 25.9342363968775409, 222.6931165988777366 25.9641633520258779, 222.6998107997744683 25.9941885112906768, 222.6993812296677504 26.0244039700569161, 222.7004828501633540 26.0545812838950468, 222.7068412637907215 26.0846224342125979, 222.7151250248850545 26.1146151271205404, 222.7223428546015214 26.1446381900068445, 222.7233614602515956 26.1748271205919423, 222.7251698747904527 26.2049974649508677, 222.7297580672415620 26.2350818940931916, 222.7350401377152878 26.2651345787107857, 222.7397478569982354 26.2952047135490545, 222.7441890163587743 26.3252841708795273, 222.7490415028016457 26.3553551043257173, 222.7538245647999702 26.3854301586473454, 222.7585301990661719 26.4155095328346157, 222.7633657664723614 26.4455877699967239, 222.7688255310053194 26.4756518789740305, 222.7734841245274993 26.5057393017668659, 222.7804994013292799 26.5357699997111638, 222.7892222416250263 26.5657611258525144, 222.7934201840520529 26.5958734025664896, 222.7976525279802331 26.6259869814647345, 222.8061529184205085 26.6559906322473879, 222.8082111146133855 26.6861657600069009, 222.8108775599046965 26.7163270320472783, 222.8149933055477163 26.7464524254111780, 222.8202949000983040 26.7765488881277314, 222.8301151846121400 26.8065289627933971, 222.8347576221901534 26.8366503143100701, 222.8375201821877170 26.8668265546276501, 222.8418110343396847 26.8969648288669205, 222.8465067625856477 26.9270946182803463, 222.8524537725384675 26.9571937291370958, 222.8574636362439207 26.9873195346867867, 222.8620005207343127 27.0174598522939498, 222.8671731236854328 27.0475856079339003, 222.8726715768086706 27.0777049164258194, 222.8775474502902796 27.1078426359435340, 222.8816119755332181 27.1380004347667985, 222.8869882261955695 27.1681224764912130, 222.8926632525074183 27.1982387554859919, 222.8956791014889518 27.2284267497753341, 222.8990635443852568 27.2586071020030190, 222.9037992898207108 27.2887541107411309, 222.9093687180935035 27.3188813346966164, 222.9147563759039485 27.3490153396147129, 222.9196081766303905 27.3791653776126616, 222.9243436031769932 27.4093204644372150, 222.9286080088542121 27.4394937878516778, 222.9336119064177808 27.4696539013430439, 222.9389694547837451 27.4998067414069354, 222.9467971585075929 27.5298969245199672, 222.9536775696169855 27.5600138137988395, 222.9590786061792187 27.5901713708442458, 222.9649273858052254 27.6203191385870532, 222.9707788876332302 27.6504687616998233, 222.9779598201737372 27.6805854587132423, 222.9832825767003044 27.7107527614628353, 222.9817568406569137 27.7410883808228697, 222.9874565001069868 27.7712230016882593, 222.9936425870742482 27.8013468434569937, 222.9960558499005003 27.8315712512584632, 223.0003219092032793 27.8617491055375872, 223.0057706188702866 27.8918979783849927, 223.0108205033237994 27.9220591651377283, 223.0159954833848133 27.9522189808714145, 223.0194101868325163 27.9824265788414301, 223.0236278179942246 28.0126150871196700, 223.0270783276952216 28.0428260124679909, 223.0284527756684838 28.0730933626770600, 223.0310594806987865 28.1033303987746450, 223.0333322930894440 28.1335778457448136, 223.0341180624720039 28.1638655435949907, 223.0377939193720067 28.1940800787344799, 223.0423453188257099 28.2242737368825729, 223.0473563566852988 28.2544573009177569, 223.0475810350740460 28.2847663252395201, 223.0468242129837790 28.3151021837157764, 223.0494697180605783 28.3453669498318952, 223.0551226685686856 28.3755718417018450, 223.0596599616456217 28.4058071837445851, 223.0644130602050836 28.4360386740748048, 223.0699211842023431 28.4662524123565284, 223.0775607745895286 28.4964128803651633, 223.0834267667080724 28.5266207293508067, 223.0946602925923230 28.5566915950313849, 223.1011121708191922 28.5868875504529036, 223.1057514664018697 28.6171320328370271, 223.1092717803553569 28.6474026359030276, 223.1131858521137303 28.6776599785361874, 223.1175135978419064 28.7079082719772565, 223.1224011054471248 28.7381437355216534, 223.1295408824391302 28.7683226027756120, 223.1386439433995577 28.7984522355940626, 223.1466096978197129 28.8286128295861097, 223.1512039324807120 28.8588623697961353, 223.1491767764528049 28.8892849121626796, 223.1495096696987446 28.9196477562610887, 223.1531510946215917 28.9499227439951703, 223.1593084066995232 28.9801302235178611, 223.1671463731093752 29.0102958476445494, 223.1733378307814917 29.0405055589089827, 223.1762893691844170 29.0708005572484645, 223.1797411591123534 29.1010841479297682, 223.1842105395181193 29.1313429880265602, 223.1897492654337611 29.1615757529559474, 223.1968336860489330 29.1917701214392054, 223.2007111469345091 29.2220488212368927, 223.2065521127375689 29.2522700368019741, 223.2119706505060890 29.2824949298750461, 223.2143181739405975 29.3128005757675894, 223.2145049372266783 29.3431632754399807, 223.2130727083799684 29.3735688214291280, 223.2169012501132954 29.4038404960307034, 223.2205048495329152 29.4341193922091833, 223.2231762087316156 29.4644236196081089, 223.2286000314316823 29.4946587355534788, 223.2310513877485789 29.5249714294954124, 223.2344723717499733 29.5552689830075828, 223.2401364427243777 29.5855193241839842, 223.2452585570237602 29.6157849349408728, 223.2505202413070720 29.6460483698967749, 223.2559231593347135 29.6763095798524112, 223.2644027871221795 29.7064934052381133, 223.2627241956078876 29.7369385494086842, 223.2645402237930057 29.7672955192597257, 223.2677335536144483 29.7976186173721942, 223.2703656238754206 29.8279573493983037, 223.2756273227971349 29.8582220782055501, 223.2844765439493528 29.8883879235143297, 223.2937085860437207 29.9185452807983161, 223.2973081015805406 29.9488478138785723, 223.2936631005052845 29.9793362624003557, 223.2960666519461199 30.0096716675619035, 223.3009400212254150 30.0399455321170734, 223.3025870375495288 30.0703026550889412, 223.3057019420284917 30.1006237111833990, 223.3089129363760605 30.1309435671565957, 223.3150049755914779 30.1612022619482154, 223.3234217233952563 30.1914144151318204, 223.3234210094943535 30.2218413027351680, 223.3217310036492620 30.2523119774260358, 223.3241338861792258 30.2826801517841098, 223.3291361017602696 30.3129838017814031, 223.3335691814666006 30.3433030311341660, 223.3376879267507036 30.3736313903895656, 223.3415822010214526 30.4039665939569588, 223.3428527313638767 30.4343692093283416, 223.3463046577959119 30.4647139764403860, 223.3516152151367464 30.4950088855972758, 223.3563567921310096 30.5253193044814459, 223.3591806847722694 30.5556792231968117, 223.3633551843234670 30.5860062097663281, 223.3673017153173816 30.6163400617374144, 223.3700134643006265 30.6467061128488147, 223.3771472685137098 30.6769619187146567, 223.3826102810353689 30.7072608971903698, 223.3886354466583271 30.7375468061244774, 223.3920631849453571 30.7678988088007088, 223.3948340483456150 30.7982679488012465, 223.3964740350774605 30.8286665606172861, 223.3988015833817258 30.8590488763678010, 223.4054640309857689 30.8893233212344960, 223.4110113026205795 30.9196268339053262, 223.4122686163119340 30.9500391594668898, 223.4185862540229266 30.9803254154219800, 223.4253672463590590 31.0106010422639251, 223.4280655144074501 31.0409802449639898, 223.4338793837549417 31.0712782786190438, 223.4368728738980963 31.1016439799744440, 223.4352648020414733 31.1321259385368307, 223.4366125414503585 31.1625346166880490, 223.4396705389226838 31.1929014229039510, 223.4456438373482570 31.2231963322768564, 223.4505941710129946 31.2535177729686318, 223.4547715708267219 31.2838594812816808, 223.4577739516391546 31.3142314599850557, 223.4600217044295505 31.3446231542552951, 223.4635365292320728 31.3749880885431622, 223.4679250724920223 31.4053363295085184, 223.4717664816919864 31.4356991045685845, 223.4748831801429674 31.4660808082941550, 223.4799487654643713 31.4964148775685189, 223.4840292327695863 31.5267743476384261, 223.4865411911619617 31.5571736951986601, 223.4883032670517480 31.5875924900986824, 223.4923952323851779 31.6179542209252773, 223.4970672524644328 31.6483023929509208, 223.5030692210505379 31.6786209217389043, 223.5066616283142196 31.7090028002147584, 223.5106210413823362 31.7393763676496157, 223.5132764001971566 31.7697830874807003, 223.5179240398600484 31.8001411574942594, 223.5195254158442140 31.8305755440646045, 223.5239434375313579 31.8609408591624330, 223.5282886785034577 31.8913087442676826, 223.5322519417453861 31.9216868480441569, 223.5347617094257657 31.9521016879863282, 223.5380353071004720 31.9824836882650096, 223.5428282743981185 32.0128133802272430, 223.5480508269670565 32.0431332222472420, 223.5497441169615058 32.0735409978522341, 223.5553057804664263 32.1038539700301087, 223.5598384268536165 32.1341930832612874, 223.5624288051742212 32.1645807930955741, 223.5652337762755906 32.1949638621259524, 223.5678286491418874 32.2253527382871638, 223.5695560421223433 32.2557635380633627, 223.5752088569645366 32.2860971656535511, 223.5778937031500675 32.3165239135066074, 223.5812675754343957 32.3469343758282122, 223.5848566389719849 32.3773401796878204, 223.5891675860983128 32.4077288948879101, 223.5927666199704902 32.4381356808599577, 223.5971664748019236 32.4685234266738121, 223.6018897195259569 32.4989038349033450, 223.6036667978909520 32.5293570670729295, 223.6064949112673332 32.5597850850799730, 223.6116324578020453 32.5901446220759752, 223.6140456300390724 32.6205582901027853, 223.6180710912269092 32.6509330396607638, 223.6211992806995852 32.6813302883187760, 223.6282270303249504 32.7116327514627656, 223.6317729060406236 32.7420209117044578, 223.6357729383524600 32.7723985009571379, 223.6368325295503041 32.8028483884673605, 223.6411096371763847 32.8332202356979366, 223.6439910882040465 32.8636266156867265, 223.6481310195876802 32.8940028179196489, 223.6509936165338104 32.9244106061581547, 223.6553899144079764 32.9547815456590385, 223.6596968044144660 32.9851551442578170, 223.6612145715821498 33.0155969875223647, 223.6650693763939444 33.0459824801913911, 223.6692659409714850 33.0763601294171679, 223.6716695758493643 33.1067817005986527, 223.6751523009409368 33.1371775151216852, 223.6790842134867034 33.1675628698264902, 223.6817299554946317 33.1979800536689780, 223.6840029478087502 33.2284069152961976, 223.6869551521492383 33.2588177146786208, 223.6903565456445051 33.2892180314227986, 223.6936834072822933 33.3196205103363567, 223.6971029050550612 33.3500211100688730, 223.7007701587213830 33.3804160897485005, 223.7044837207082537 33.4108103024752410, 223.7075120344256618 33.4412213365115321, 223.7108808174373280 33.4716244979182633, 223.7150218024642072 33.5020111063703894, 223.7185127413576993 33.5324154287190765, 223.7220915424194061 33.5628179458101883, 223.7256487173190180 33.5932212766861014, 223.7286216236611267 33.6236389013519741, 223.7320216440893148 33.6540465564206741, 223.7369843538813257 33.6844170563033956, 223.7396632576619027 33.7148425178093163, 223.7417605710047042 33.7452821084065278, 223.7453063421154411 33.7756872889352380, 223.7483122061553331 33.8061098598384433, 223.7517120547620664 33.8365277389875345, 223.7558255243394569 33.8669288053235888, 223.7594854651125900 33.8973409052722943, 223.7624929837062666 33.9277687623950541, 223.7659937331060576 33.9581850448707954, 223.7683016722576781 33.9886299134953518, 223.7717654102397660 34.0190474189640710, 223.7746851068746992 34.0494780279845912, 223.7778200650010660 34.0799036630295547, 223.7815767483879483 34.1103144298280867, 223.7849598453518638 34.1407339699114232, 223.7886890994548992 34.1711454269250368, 223.7929755563177139 34.2015437888475020, 223.7950123858878442 34.2319956601869038, 223.7976542511011644 34.2624332578238366, 223.8008059636456153 34.2928588582611340, 223.8038189435971788 34.3232878312866205, 223.8070197677527631 34.3537124336828441, 223.8102919260166743 34.3841354218809698, 223.8132599669528702 34.4145658933153271, 223.8172826870554388 34.4551387030861704))) +MULTIPOLYGON (((225.6590116066086011 15.2022751781288790, 225.8184285319980802 15.1938011437427214, 225.9815607786718488 15.1849941022049979, 226.1537479980599414 15.1755636254992954, 226.3305987100000323 15.1657156107401772, 226.5161948590464078 15.1552163682550187, 226.7132602789062901 15.1438893478077521, 226.9261988964304351 15.1314506126365362, 227.1499418813374973 15.1181384848977594, 227.3887605669752929 15.1036654662162384, 227.6457676404389190 15.0877902093839591, 227.9238726251499827 15.0702639425568297, 228.2357698245607480 15.0502006375273076, 228.5715407538233990 15.0280865132481711, 228.9475901297275584 15.0027161002309253, 229.3712716345860088 14.9733679200999088, 229.9511930049727368 14.9320537002732614, 230.4883212838945497 14.8922542020580941, 231.1136532000215027 14.8443022653531269, 231.8633228532418400 14.7845460924271404, 232.7891574029211483 14.7073522924876805, 233.9942664759018385 14.6013042631466732, 234.4965294627785397 14.5504706067190703, 234.5208110638522783 14.5099689962529332, 234.5313044299073226 14.4803171724793369, 234.5416131312027801 14.4506850418485016, 234.5520779977870802 14.4210415870330539, 234.5623431784188710 14.3914232575198557, 234.5724238845463105 14.3618286535965467, 234.5827882789665750 14.3322149027207999, 234.5929578113345144 14.3026258488927596, 234.6030683507545405 14.2730490546493591, 234.6134058750884037 14.2434583659015850, 234.6236678287416737 14.2138814837024672, 234.6339787538766188 14.1843070299267513, 234.6442862284248463 14.1547369879349692, 234.6547188863688120 14.1251597335973749, 234.6648922775194421 14.0956130658841872, 234.6753260761099682 14.0660495235981156, 234.6864368112472903 14.0364311267002471, 234.6957686604493745 14.0069820247430687, 234.7061404536003693 13.9774449561658045, 234.7168562105069327 13.9478834920582333, 234.7270224975895871 13.9183791086254978, 234.7372048991153406 13.8888802351922518, 234.7477636671919754 13.8593540754838660, 234.7584817061348872 13.8298204455798928, 234.7691873583667643 13.8002949950470910, 234.7803650551794021 13.7707336568590133, 234.7916750860139814 13.7411673885780026, 234.8029058064372521 13.7116154576392404, 234.8142170604288026 13.6820633420075914, 234.8253048384431736 13.6525386874369428, 234.8363381012699165 13.6230261366839080, 234.8474859593540600 13.5935103445255336, 234.8586521615223717 13.5639727104256611, 234.8698086919267212 13.5344171571079563, 234.8810402760219347 13.5048618785192769, 234.8921633384625238 13.4753235398173246, 234.9036036680469692 13.4457635458124880, 234.9148787480721126 13.4162256650294545, 234.9262976243365983 13.3866818976443955, 234.9378525857910063 13.3571329686720421, 234.9491438202865936 13.3276151019577238, 234.9605851734781936 13.2980908305402394, 234.9714051171723099 13.2686329662724525, 234.9829107510691983 13.2391230511010356, 234.9953247709165112 13.2095381986057365, 235.0050945465017662 13.1801996367152636, 235.0136741450404543 13.1509757163783796, 235.0235876197879179 13.1216383624306463, 235.0329511591612004 13.0923577945443821, 235.0428529669674731 13.0630357717848451, 235.0521842656135902 13.0337723688292240, 235.0625643579874122 13.0044215484787653, 235.0718456764101347 12.9752026574268520, 235.0824545378012829 12.9458957824717462, 235.0941279042510814 12.9165005022008970, 235.1065853378691486 12.8870421851470844, 235.1158685212187152 12.8578770132342068, 235.1267432519176737 12.8285760999852148, 235.1379548440312988 12.7992524166110808, 235.1493796188802605 12.7699171276532795, 235.1597708587534044 12.7406822108994717, 235.1712990013349156 12.7113527637885877, 235.1827906320188504 12.6820275613200177, 235.1941656390224011 12.6527141312217992, 235.2050650309431887 12.6234509249003715, 235.2163653275223396 12.5941593716165876, 235.2278129164640745 12.5648622450461041, 235.2385899990798066 12.5356327691044473, 235.2509196533849547 12.5062719956791675, 235.2633495959182710 12.4769099908336205, 235.2728707652432547 12.4478157344413951, 235.2843018911920012 12.4185583774315731, 235.2958612619559631 12.3892706547972740, 235.3093903391809647 12.3597895148684778, 235.3187948284901552 12.3306840978547978, 235.3306973300512368 12.3013633115279735, 235.3409552423264586 12.2721967439647663, 235.3501958576858613 12.2431283054920090, 235.3613910460340435 12.2138932347158029, 235.3730447116262781 12.1846249559616275, 235.3841076194497077 12.1554168855521301, 235.3951457454282092 12.1262186343150535, 235.4062396923714005 12.0970204529142062, 235.4175034828008393 12.0678123993142634, 235.4293245043035085 12.0385625702422647, 235.4421181444995455 12.0092341707538353, 235.4552959271688906 11.9798795410635801, 235.4690679156001920 11.9504801024310332, 235.4834853052213361 11.9210313918726705, 235.4960974300517762 11.8917506964105950, 235.5075487335811886 11.8625807321371131, 235.5232045964961003 11.8330462747001430, 235.5346764929361711 11.8038936247787749, 235.5484769103933331 11.7745459193172746, 235.5600500490689910 11.7454032067389971, 235.5703027538092726 11.7163850530546831, 235.5839099151444316 11.6870783106887757, 235.5954261043270037 11.6579642551851848, 235.6091634785258861 11.6286620492116040, 235.6216120131801404 11.5994816340206004, 235.6324251515997616 11.5704534114552136, 235.6427681559864027 11.5414744763687072, 235.6568231608829365 11.5121696292982936, 235.6720114138059898 11.4827667117629559, 235.6855534378352104 11.4535169164043715, 235.6985976230074584 11.4243190426234946, 235.7101697741603061 11.3952586967556826, 235.7212865677432774 11.3662463475955970, 235.7336848210081257 11.3371294098704496, 235.7467824959670679 11.3079591641786816, 235.7608802892358995 11.2787093286096738, 235.7716222748914561 11.2497620499109914, 235.7842032100646179 11.2206891920149250, 235.7973313753711295 11.1916028404770049, 235.8104867447165987 11.1625225099613523, 235.8248992522362073 11.1333405976275852, 235.8395596186140324 11.1041455608978978, 235.8525266395224662 11.0751071281319806, 235.8667638348769913 11.0459661778884950, 235.8799840523980720 11.0169226049946403, 235.8933575463018997 10.9878741537475406, 235.9056857922247161 10.9589253856028943, 235.9193690857337344 10.9298457604617330, 235.9332202571170285 10.9007399237256202, 235.9474135600875115 10.8716127613864479, 235.9606689831861672 10.8425757207401041, 235.9745891351863349 10.8134893032569970, 235.9749642465137640 10.7716809281121151, 234.3062264801245078 10.9140277809663289, 233.0568672341267700 11.0146280042103317, 232.0879579900140470 11.0891193379889472, 231.2922763752978028 11.1479476252960801, 230.6222024977036256 11.1958368476612193, 230.0451126661331216 11.2358585089279455, 229.5399124326933133 11.2699591633018610, 229.0910977852267649 11.2995144425208274, 228.6886580791888548 11.3254217054343140, 228.3230615139313500 11.3484629748790802, 227.9885578563481090 11.3691297953353860, 227.6794424865351800 11.3878696987312154, 227.3925662525225277 11.4049521734577688, 227.1244248889418884 11.4206460692728200, 226.8725374557903933 11.4351462062810594, 226.6348499723003442 11.4486118924843758, 226.4089327375767766 11.4612113075362014, 226.1941018513785195 11.4730141135446058, 225.9885536989861521 11.4841415383497054, 225.7906841315510178 11.4946974768467598, 225.5999034371527046 11.5047316362642942, 225.5366590428407676 11.5127499139751190, 225.5372155286837028 11.5505123386258859, 225.5385771173869216 11.5787917807373049, 225.5399422790694928 11.6070769021958409, 225.5412964706850119 11.6353683683259490, 225.5426724692719347 11.6636646542798914, 225.5440051181479930 11.6919712226446855, 225.5452754778033579 11.7202890826927870, 225.5466283640395773 11.7486089150217552, 225.5479733512320877 11.7769349109975465, 225.5492620732997580 11.8052693182655286, 225.5505841234978277 11.8336079601987230, 225.5519462019553600 11.8619505139251959, 225.5533034114788222 11.8902990653271967, 225.5546573357829629 11.9186535319933675, 225.5560296401821176 11.9470128979944921, 225.5574630380517362 11.9753825153277962, 225.5590145865995453 12.0037600937422670, 225.5604603602513691 12.0321483085082939, 225.5618766106161956 12.0605435905484040, 225.5632235046636538 12.0889478001605344, 225.5646322492728189 12.1173547927717955, 225.5660183351829460 12.1457685136433966, 225.5674524000941119 12.1741856511797124, 225.5688591210027312 12.2026097227449029, 225.5703066480778034 12.2310375312635990, 225.5717059626002481 12.2594635287660125, 225.5731135142524977 12.2878845469914175, 225.5745000480431770 12.3163122245770751, 225.5759250961868361 12.3447437585488249, 225.5773924999224107 12.3731789608056815, 225.5788485201462947 12.4016203465804651, 225.5803384550112014 12.4300657782762727, 225.5816851396154448 12.4585235859629435, 225.5830893136675286 12.4869843196153578, 225.5845898505328364 12.5154461391777048, 225.5860380816324664 12.5439157417238558, 225.5874589809734232 12.5723919342328845, 225.5889159822422414 12.6008720348057537, 225.5903500433967963 12.6293588187895995, 225.5917512819598585 12.6578527497401989, 225.5931498469038559 12.6863523975501824, 225.5945936511308787 12.7148554897243926, 225.5960004208644705 12.7433659092358020, 225.5974035727396938 12.7718820685236771, 225.5988234672666408 12.8004029993498278, 225.6002725682347716 12.8289353398050547, 225.6017372705671562 12.8574801026263454, 225.6031663907919835 12.8860320507559223, 225.6045230142199500 12.9145929257661809, 225.6058813437432775 12.9431592082911369, 225.6072542184839165 12.9717302815183047, 225.6086155626813365 13.0003073734616610, 225.6099855929491866 13.0288895207329318, 225.6113301413350882 13.0574783349659196, 225.6125573731443410 13.0860781699462851, 225.6138059179633046 13.1146685837733834, 225.6150812749465615 13.1432485812774509, 225.6162458519782774 13.1718393536475116, 225.6173776523386891 13.2004371911819796, 225.6185740510497624 13.2290374592872642, 225.6198200700041809 13.2576408579599114, 225.6210454851929796 13.2862507192777066, 225.6223709718760801 13.3148612908315407, 225.6236531533329810 13.3434793901493425, 225.6249325723329093 13.3721030820185973, 225.6260928567572819 13.4007285591032268, 225.6271536834223639 13.4293543931465589, 225.6282124972139513 13.4579858251888993, 225.6292645314285608 13.4866230739553536, 225.6301804105962958 13.5152723244987261, 225.6310913323261218 13.5439273004220944, 225.6319395686368807 13.5725907590492589, 225.6327541317145062 13.6012613101755768, 225.6337718649642170 13.6299275878090640, 225.6347506831084502 13.6586011866152344, 225.6357740723691734 13.6872915145011422, 225.6369158381051250 13.7159957103282366, 225.6377194029691964 13.7447214977765899, 225.6381065136040149 13.7734726404849468, 225.6384486634578934 13.8022312915639684, 225.6384696572111181 13.8310107208009736, 225.6377164794394048 13.8598327075708667, 225.6365675112162137 13.8886790652427319, 225.6366436889485954 13.9174718431418363, 225.6368569804845379 13.9462633389480235, 225.6372512893272244 13.9750446861622386, 225.6375598958670707 14.0038283677250384, 225.6379232729382807 14.0326147566449340, 225.6383897344348100 14.0614015134760191, 225.6384870229912281 14.0902113783666341, 225.6385225417334937 14.1190295454278214, 225.6386422674683558 14.1478489717101557, 225.6388548745616731 14.1766692294529779, 225.6393899644289718 14.2054792305965041, 225.6400017789805759 14.2342908119101494, 225.6406354379116408 14.2631066557045862, 225.6413569018558860 14.2919235676818150, 225.6418737897815276 14.3207556083426581, 225.6423091415276758 14.3495968327812982, 225.6427227612253716 14.3784443487517883, 225.6431399559387501 14.4072969248162703, 225.6435643091585348 14.4361543784162585, 225.6439996403331634 14.4650165186353465, 225.6444242554794926 14.4938843841154874, 225.6447387703332197 14.5227627774815442, 225.6449631350287177 14.5516507312391479, 225.6451722610784714 14.5805446133494083, 225.6453957579692826 14.6094429811145208, 225.6457542898072859 14.6383399809685439, 225.6462420940192146 14.6672358817340704, 225.6469402654511782 14.6961267415683920, 225.6476430843318326 14.7250225124654772, 225.6482912662952742 14.7539260617623302, 225.6489832267797908 14.7828326103256273, 225.6497656768799516 14.8117398861253182, 225.6506424444196739 14.8406387378099094, 225.6513629139793977 14.8695408561432654, 225.6517777322902418 14.8984629714063477, 225.6521804907180808 14.9273908337275358, 225.6524924020781668 14.9563282654052987, 225.6529946843869254 14.9852615950152863, 225.6535087791164358 15.0141994839657169, 225.6541740532657627 15.0431351470923822, 225.6549119926503124 15.0720723858902144, 225.6554983620026746 15.1010221054609115, 225.6560601547267595 15.1299724947379399, 225.6566877994991955 15.1589188520153293, 225.6590116066086011 15.2022751781288790))) +MULTIPOLYGON (((222.1624644986581814 22.8951608776491682, 222.3339278053147154 22.8936291249977444, 222.4918214735398010 22.8892887248561081, 222.6447347625093585 22.8849225118103980, 222.7860232522739352 22.8807537877385698, 222.9282491754742921 22.8764117840873240, 223.0766244984219497 22.8717204866312613, 223.2163755016696030 22.8671671507805954, 223.3566763952025269 22.8624540093663029, 223.4933003437754166 22.8577319700323471, 223.5898184185919320 22.8543578550741309, 223.6952462098100227 22.8505806048140450, 223.7986314112134210 22.8468004169646370, 223.8996071437270245 22.8430363019214830, 223.9985409791389088 22.8392789938655163, 224.0959564206264076 22.8355116831515232, 224.1910355953448857 22.8317716008955287, 224.2846905331636265 22.8280253855071642, 224.3794591431320669 22.8241662736667443, 224.4717633562828496 22.8203486473478847, 224.5633375179994857 22.8165001434515204, 224.6543476105477453 22.8126140286554744, 224.7440401314165683 22.8087272357695667, 224.8325041708505410 22.8048422966027147, 224.9212556591315035 22.8008911950998545, 225.0106581698765069 22.7968452216291482, 225.1000007997411956 22.7927430513065374, 225.1888277899536774 22.7886040403501653, 225.2781779860744109 22.7843853505198659, 225.3686923868877443 22.7800551110823548, 225.4590163590555107 22.7756725361698003, 225.5508196988385521 22.7711599175616932, 225.6422475001495513 22.7666030802101957, 225.7360430349211526 22.7618690698426214, 225.8308944078886782 22.7570178539048200, 225.9265645398400011 22.7520593284113914, 226.0249049679701443 22.7468968896814623, 226.1249454787566151 22.7415751879109145, 226.2278086015192287 22.7360312020369584, 226.3331090916952633 22.7302792144843551, 226.4411376184329754 22.7242978235364461, 226.5516842589036060 22.7180922185925489, 226.6656163593179940 22.7116078268158610, 226.7845301475643396 22.7047457109732562, 226.9071475647440082 22.6975670621508989, 227.0314410381741084 22.6901810095987422, 227.1839792061757350 22.6810029064036804, 227.3309878641619832 22.6719940160821594, 227.4852574295552472 22.6623834900507255, 227.6478981924533969 22.6520789916308765, 227.8244753455144860 22.6406976405487228, 228.0131819147794374 22.6283077428341635, 228.2162925672537028 22.6147123261545353, 228.4292029370799071 22.6001656944389460, 228.6562565745130655 22.5843249428905253, 228.9060279701273828 22.5665175964537532, 229.1825161010338832 22.5463403908074866, 229.4889073173453937 22.5234095910938592, 229.8235975094182209 22.4976688768649531, 230.1950353289553561 22.4682622756183683, 230.6140350097421958 22.4340362400728992, 231.0891086675366637 22.3938791162801500, 231.6395867000892963 22.3455627542399782, 232.2933600728475199 22.2857009540908635, 233.0468719139714437 22.2096336010235262, 233.0786160068223012 21.8362790738185488, 233.1128703125102675 21.4745535124936850, 233.1496154961199068 21.1131520453783352, 233.1847240764050753 20.7523849749798082, 233.2282694104284246 20.3912575382026091, 233.2729399482114729 20.0308241593004865, 233.3250709695567195 19.6705333692279076, 233.3796821891314153 19.3110185896687092, 233.4385722855595304 18.9512397884117654, 233.5048315554937517 18.5912746804041475, 233.5705679155844336 18.2318918456861674, 233.6451980358386891 17.8721782134278229, 233.7217275105666658 17.5133469216293491, 233.8008596200677403 17.1546858578329271, 233.8864271812514346 16.7969322128191187, 233.9697189392310293 16.4397036867625950, 234.0828109349569388 16.0803141029273959, 234.1849920604829549 15.7230496510434978, 234.2920854371643600 15.3662472678846918, 234.4024907287820838 15.0099336756868436, 234.5149128953590321 14.6540024086710705, 234.6379311549196132 14.2984584660047549, 234.7623775574045908 13.9436811555426505, 234.8942578953382849 13.5892102038194746, 235.0288272435886654 13.2349149251491429, 235.1521051678167282 12.8828891503746874, 235.2867725902066240 12.5312613935276893, 235.4233087209120754 12.1800902645324154, 235.5708596306864138 11.8287640872622291, 235.7235065834900070 11.4781679472531284, 235.8797318094723323 11.1284757052297838, 236.0525313246160977 10.7671682736166154, 234.5539738435557524 10.8934756928844916, 233.4407131631531342 10.9842712723458433, 232.5469229652644003 11.0542229776369414, 231.8057772059842137 11.1102241836769391, 231.1727759778428037 11.1565989553883913, 230.6222024977036256 11.1958368476612193, 230.1360978920992295 11.2296246903222858, 229.7011060076215756 11.2591734075647345, 229.3092627460586925 11.2852352682155725, 228.9523786369051948 11.3085085479038057, 228.6255699416117011 11.3294320811030538, 228.3230615139313500 11.3484629748790802, 228.0424929933010674 11.3658248267683568, 227.7797848238544418 11.3818240807472488, 227.5335303503320290 11.3965959501297078, 227.3013618133047657 11.4103203927839996, 227.0813921445934511 11.4231400422407976, 226.8725374557903933 11.4351462062810594, 226.6735784057233900 11.4464323335893088, 226.4830830479979795 11.4570977194829062, 226.3002739486506414 11.4672030229303150, 226.1246140672749334 11.4767939954809552, 225.9550662527160227 11.4859387811263272, 225.7906841315510178 11.4946974768467598, 225.6312478555471159 11.5030927722663776, 225.4762447625155630 11.5111601660448812, 225.3250842761325714 11.5189369296322024, 225.1774439551024329 11.5264465188783944, 225.0328448252998612 11.5337180770247585, 224.8908763596490132 11.5407761760249503, 224.7513584997161331 11.5476346729728920, 224.6139594562434354 11.5543129777076103, 224.4784375362918638 11.5608260941027616, 224.3444652819509599 11.5671914448426545, 224.2117774258863392 11.5734232007857401, 224.0801718772106028 11.5795330298010377, 223.9493664901763452 11.5855344995887322, 223.8191624724294400 11.5914391819224214, 223.6892422590746605 11.5972592901497755, 223.5594084415180305 11.6030053638277604, 223.4294005333650261 11.6086896685705749, 223.2989722102144583 11.6143216904755171, 223.1678913125285533 11.6199107220438567, 223.0358968024115143 11.6254674694465940, 222.9027074603658320 11.6310028545879973, 222.7681514532162907 11.6365211163933147, 222.6319141538503459 11.6420339437049947, 222.4937638625373211 11.6475477129612379, 222.3535187113662914 11.6530658977189212, 222.2106332312139614 11.6586083764543140, 222.0649326370137260 11.6641761438836671, 221.9159984711464233 11.6697805626031919, 221.7637180402751653 11.6754184975181445, 221.6071946734351457 11.6811193203291648, 221.4462705120642738 11.6868790352296799, 221.2800176036289201 11.6927238980664523, 221.1082343240075829 11.6986486654835620, 220.9302181846813085 11.7046664470968551, 220.7448115762643397 11.7108046009476432, 220.5512576667543385 11.7170716871744176, 220.3489604038595360 11.7234675875962768, 220.1364090861300156 11.7300207161521186, 219.9120955538532201 11.7367529071512831, 219.6885215783216552 11.7467999825000735, 219.7800022085723413 12.0939667193786544, 219.8674454814815817 12.4316594206823421, 219.9609663348926460 12.7696974746052021, 220.0435221785276383 13.1088831468612099, 220.1287352846985073 13.4489940062221862, 220.2143098338185894 13.7895853680132241, 220.2996432287141317 14.1309982528014721, 220.3856337203785074 14.4729600246978425, 220.4702124056549621 14.8160664517127358, 220.5542495222690889 15.1598074720371745, 220.6372147493088676 15.5039964428243273, 220.7215739629539826 15.8490768264030795, 220.8003749787557979 16.1950206146460012, 220.8780366530769754 16.5414260976919820, 220.9576980262959296 16.8886184324824313, 221.0492649291077498 17.2360440208405343, 221.2038686917591974 17.5820804814770639, 221.2332821024614873 17.9327909627809063, 221.3064374135869343 18.2825671410003565, 221.3767990325112009 18.6330869316119490, 221.4437786011409628 18.9842653899860707, 221.5157897919053198 19.3357555187522081, 221.6415036194281356 19.6862868957955293, 221.7040268219716665 20.0392648174781556, 221.7734189146283370 20.3928463602206200, 221.8288535881722225 20.7473064169434167, 221.8917645082245826 21.1019045711432049, 221.9100285267176105 21.4581261493741380, 221.9689664639304851 21.8138417551274060, 222.0351237484508715 22.1699280425233560, 222.0994527850592419 22.5263997498348054, 222.1624644986581814 22.8951608776491682))) diff --git a/isis/src/base/objs/ImagePolygon/ImagePolygon_Darwin_i386_10_5.truth b/isis/src/base/objs/ImagePolygon/ImagePolygon_Darwin_i386_10_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..8a604f3441a153ad73a17f6cb1fd6cc6ad3418e7 --- /dev/null +++ b/isis/src/base/objs/ImagePolygon/ImagePolygon_Darwin_i386_10_5.truth @@ -0,0 +1,3 @@ +MULTIPOLYGON (((223.8172826870554388 34.4551387030861704, 223.8417027793910279 34.4596506066820183, 223.8575436553176701 34.4592772202857915, 223.8731987947955417 34.4589061403268389, 223.8888001595454966 34.4585342458576420, 223.9044019981010365 34.4581602382883290, 223.9200661671754347 34.4577826049052902, 223.9355075424467429 34.4574083328669047, 223.9508457646257682 34.4570345511811738, 223.9660146266157881 34.4566629441688548, 223.9810473116613707 34.4562927476240262, 223.9957878473876747 34.4559279256363027, 224.0106582442351453 34.4555579476699165, 224.0255459276724821 34.4551856180930827, 224.0403444766045311 34.4548136399185481, 224.0550707902558258 34.4544416140812331, 224.0696826278450260 34.4540706528633152, 224.0842130299532755 34.4536999451661927, 224.0986612451087865 34.4533295402476938, 224.1130364689869339 34.4529592283796191, 224.1273202299933018 34.4525895194552731, 224.1415662443043573 34.4522190340582526, 224.1557339918608420 34.4518488559867677, 224.1698107918541609 34.4514793494806355, 224.1838116920665982 34.4511101458139279, 224.1977227034556961 34.4507416459917764, 224.2115924901468702 34.4503725738795978, 224.2254006440637397 34.4500034947196099, 224.2391929104324504 34.4496331904990001, 224.2529511041107355 34.4492621618859047, 224.2666975062502672 34.4488898121368408, 224.2803860065775154 34.4485174107729009, 224.2940079847231800 34.4481452153055514, 224.3075938798835978 34.4477724066462940, 224.3210795841726224 34.4474007776906106, 224.3344990942370032 34.4470294144046818, 224.3478450164772369 34.4466585461289512, 224.3611125161780251 34.4462883334162910, 224.3742955932223424 34.4459189716523113, 224.3874260849249254 34.4455495872321151, 224.4004958875964064 34.4451804279779736, 224.4135260618142240 34.4448109130246038, 224.4264828608789628 34.4444420219817715, 224.4393721008836167 34.4440736115621888, 224.4522012232876307 34.4437054889999175, 224.4649910968735753 34.4433370695209575, 224.4777393619483519 34.4429684345123590, 224.4904489206230380 34.4425995128584645, 224.5030718093266842 34.4422317208438145, 224.5156259768878328 34.4418645587055465, 224.5281770921911857 34.4414961127534767, 224.5407219882328320 34.4411264780584929, 224.5531975742495661 34.4407575293592885, 224.5656264624743415 34.4403886150134397, 224.5780227094808765 34.4400193297392363, 224.5903757296815400 34.4396500013147389, 224.6026728254119291 34.4392810252896453, 224.6148668913132838 34.4389138407199553, 224.6269709753681809 34.4385480837916518, 224.6390599334172578 34.4381815076603104, 224.6511372139618175 34.4378140121817324, 224.6632067785040476 34.4374454801668293, 224.6751614661697261 34.4370792014152940, 224.6870933909597738 34.4367123756374767, 224.6989898632547238 34.4363454016597146, 224.7108678965473132 34.4359777634713211, 224.7226881483722991 34.4356106889183309, 224.7344958302550708 34.4352427865472706, 224.7462652761358015 34.4348748626036851, 224.7579793002169026 34.4345074672970739, 224.7696431367291154 34.4341404523806602, 224.7812728007805561 34.4337733275599049, 224.7928435543977344 34.4334068854894184, 224.8043847867216130 34.4330402109262153, 224.8157283419619716 34.4326786627865076, 224.8270886232841690 34.4323154551121036, 224.8384166745431685 34.4319521503576311, 224.8497524406567436 34.4315874760106411, 224.8610108250075541 34.4312241690653664, 224.8722867697038623 34.4308591870978731, 224.8835699922025810 34.4304928586050352, 224.8948651191152521 34.4301250319575729, 224.9061662755833879 34.4297558956339884, 224.9173542816715781 34.4293893381866241, 224.9284086365155133 34.4290260616188135, 224.9394220907865360 34.4286630586182127, 224.9504388176640077 34.4282988871562949, 224.9614347391278102 34.4279343412270080, 224.9724090215291596 34.4275694544292605, 224.9833614191804259 34.4272042411422561, 224.9942931924667278 34.4268386657352323, 225.0052127357932932 34.4264724542664311, 225.0161268911519983 34.4261053817509719, 225.0270072241578134 34.4257384031269353, 225.0379099782836647 34.4253696378408307, 225.0487812548770989 34.4250008963959999, 225.0595876459126430 34.4246333158877462, 225.0703030756958185 34.4242677965401214, 225.0809691073864656 34.4239029512769505, 225.0916138569805298 34.4235378364048259, 225.1022391575891959 34.4231723953056346, 225.1128542317258336 34.4228063180293233, 225.1234516167740480 34.4224398635157698, 225.1340217161871919 34.4220733665334322, 225.1445720848678604 34.4217065741965982, 225.1551012336083772 34.4213395433927403, 225.1655864785901997 34.4209730651206627, 225.1760248993641085 34.4206072521104929, 225.1864409930021793 34.4202412644615521, 225.1968389824640724 34.4198749609670074, 225.2072200098035353 34.4195083066778267, 225.2175785697109234 34.4191414990643878, 225.2279161215415968 34.4187744928887369, 225.2382328071076927 34.4184072887788730, 225.2485261485682315 34.4180399796766849, 225.2587970262709973 34.4176725406107664, 225.2690410352409458 34.4173051335256091, 225.2792535965254217 34.4169379279162939, 225.2894249396076418 34.4165712794060639, 225.2995612323753960 34.4162049783027442, 225.3096797795340080 34.4158384149443748, 225.3197769941242257 34.4154717224572551, 225.3298508715159585 34.4151049782719767, 225.3399032249868128 34.4147381230933931, 225.3499338576569073 34.4143711695009245, 225.3599442461228932 34.4140040696646921, 225.3699387631349111 34.4136366704509484, 225.3799126564553319 34.4132691483703610, 225.3898592055629706 34.4129017528991099, 225.3997746327033838 34.4125346283236624, 225.4096413759663164 34.4121684231094491, 225.4194664480515939 34.4118028921399528, 225.4292333250849936 34.4114386506334213, 225.4389847119238937 34.4110741438095005, 225.4487227950546355 34.4107092950618778, 225.4584529700451867 34.4103439088415826, 225.4681791118237868 34.4099778441967530, 225.4779501834397024 34.4096092904921136, 225.4877658689309783 34.4092382501921463, 225.4975606253910030 34.4088671491674845, 225.5073160520562112 34.4084966774081309, 225.5170945589490259 34.4081245163349720, 225.5268331233619961 34.4077530164326717, 225.5365021994056747 34.4073832928032246, 225.5461190551147297 34.4070147129218284, 225.5556995064936814 34.4066466938671809, 225.5652214497690409 34.4062800756482901, 225.5747432098429783 34.4059126712269077, 225.5842560908538417 34.4055448095740246, 225.5937778006128553 34.4051758227699338, 225.6033009157918059 34.4048059909125286, 225.6128238278372748 34.4044353752724348, 225.6223471750254532 34.4040639520834759, 225.6318758783412193 34.4036915342067431, 225.6414016415698995 34.4033184378166652, 225.6509363628046003 34.4029442090107622, 225.6604947562084647 34.4025682829215498, 225.6700415056936606 34.4021920106849777, 225.6795791566649996 34.4018152973413507, 225.6890709330758114 34.4014395611739303, 225.6985268750812565 34.4010644243483483, 225.7079299361909648 34.4006905526265570, 225.7172925180968832 34.4003174765961717, 225.7266351872193013 34.3999444072983067, 225.7359624913239884 34.3995711723548681, 225.7452560214270250 34.3991984905109618, 225.7545267975710317 34.3988259392688889, 225.7637889836344414 34.3984529709160398, 225.7730507645073317 34.3980792678529355, 225.7823252012635180 34.3977043199699963, 225.7916004169035205 34.3973285906499200, 225.8008725342959622 34.3969522323247858, 225.8101369195184134 34.3965754280254572, 225.8193892451850218 34.3961983497526589, 225.8286274988493858 34.3958210792869679, 225.8378496687657275 34.3954436987810226, 225.8470551995606286 34.3950662332777455, 225.8562326011003734 34.3946891400830523, 225.8653930029058188 34.3943119835577349, 225.8745410760741379 34.3939345816839008, 225.8836776373499617 34.3935569043987499, 225.8928019411091839 34.3931789835027857, 225.9019194640785599 34.3928006034879843, 225.9110308751989749 34.3924217392180154, 225.9201549499623809 34.3920416439267171, 225.9292743320435193 34.3916610090137098, 225.9383845714556003 34.3912800134750327, 225.9474795314178266 34.3908989044373499, 225.9565581779352499 34.3905177257819261, 225.9656244992437450 34.3901363203602415, 225.9746802477525875 34.3897546199894322, 225.9837284337445169 34.3893725057496482, 225.9927658599886797 34.3889901074684872, 226.0017891753058166 34.3886075615055518, 226.0108161763018018 34.3882241545240248, 226.0198457173549969 34.3878399331655586, 226.0288659304852672 34.3874553757630395, 226.0378750537378778 34.3870705548477176, 226.0468586590083930 34.3866860531593730, 226.0558323074971554 34.3863012459153126, 226.0647969809047027 34.3859160948656708, 226.0737494779210124 34.3855307302515456, 226.0826909505214246 34.3851451068040674, 226.0916392243316864 34.3847585069560466, 226.1005846293875834 34.3843713215450038, 226.1095237944467726 34.3839836875571905, 226.1184552396198910 34.3835956656763031, 226.1273766599848898 34.3832073496778676, 226.1362843513687153 34.3828188893593136, 226.1451789838363595 34.3824302579892986, 226.1540696341189687 34.3820410907883058, 226.1629557016454157 34.3816514125989414, 226.1718415645501068 34.3812610485457952, 226.1807230054455999 34.3808701688271583, 226.1896010103693300 34.3804787347539005, 226.1984731024689950 34.3800868460323130, 226.2073393250070410 34.3796945012310857, 226.2162010894380444 34.3793016444903827, 226.2250584402766265 34.3789082745362151, 226.2339210610063560 34.3785140099352162, 226.2427791039827127 34.3781192423320050, 226.2516314343282886 34.3777240168995633, 226.2604782195338942 34.3773283272095398, 226.2693193564055321 34.3769321772336909, 226.2781549132746193 34.3765355639964554, 226.2869854330353121 34.3761384661654077, 226.2958114626155748 34.3757408625677101, 226.3046334835679545 34.3753427349446667, 226.3134536502138019 34.3749440038212342, 226.3222666039530395 34.3745448675868772, 226.3310674200903350 34.3741454965105575, 226.3398662973730495 34.3737455139908121, 226.3486632146650379 34.3733449207269430, 226.3574580470379658 34.3729437205966377, 226.3662507195154205 34.3725419149321638, 226.3750416931271161 34.3721394877985134, 226.3838307521521074 34.3717364446175608, 226.3926183115015363 34.3713327721326252, 226.4014042158760844 34.3709284729463604, 226.4101886820603227 34.3705235397049265, 226.4189713667341266 34.3701179688710923, 226.4277528949788518 34.3697117359899522, 226.4365339441873743 34.3693048460954742, 226.4453141371841696 34.3688973009585936, 226.4540932758034444 34.3684891262239773, 226.4628714412387751 34.3680802909390195, 226.4716492125770628 34.3676707554958512, 226.4804266127447647 34.3672605340832789, 226.4892039200612430 34.3668496114387167, 226.4979812270886157 34.3664379860401539, 226.5067586403042696 34.3660256539005715, 226.5155350783787753 34.3656126841276190, 226.5243113274158588 34.3651990254046922, 226.5330863836773290 34.3647847378262910, 226.5418613931196887 34.3643697520982982, 226.5506364357558766 34.3639540648019022, 226.5594125115484587 34.3635376201859799, 226.5681899791629235 34.3631204005482687, 226.5769703953518786 34.3627023214856848, 226.5857530174790213 34.3622834276467799, 226.5945393457379566 34.3618636384960396, 226.6033280976941739 34.3614430267662812, 226.6121204829055102 34.3610215277182363, 226.6209149844707156 34.3605992248942869, 226.6297112468443800 34.3601761375813552, 226.6385086581271366 34.3597522984601582, 226.6473076484998614 34.3593276840231709, 226.6561088518905933 34.3589022601831786, 226.6649128221872047 34.3584759974264884, 226.6737198569121006 34.3580488800412951, 226.6825293890375974 34.3576209381841196, 226.6913400811723420 34.3571922425097185, 226.7001540295673294 34.3567626816807490, 226.7089712049645414 34.3563322571851799, 226.7177870375159330 34.3559012099767855, 226.7266041828078187 34.3554693992389275, 226.7354247297398331 34.3550367145667934, 226.7442492611458249 34.3546031251241786, 226.7530788598978972 34.3541685737675593, 226.7619128745805597 34.3537330945820614, 226.7707514832060269 34.3532966779085598, 226.7795960290009418 34.3528592527794885, 226.7884459906872507 34.3524208461996068, 226.7973003349381997 34.3519815119965415, 226.8061593642061098 34.3515412337322559, 226.8150233317537925 34.3510999975136855, 226.8238934698196658 34.3506577379326572, 226.8327720567338872 34.3502143344743445, 226.8416573813208856 34.3497698762915959, 226.8505497655341117 34.3493243455891317, 226.8594358490680065 34.3488784447268785, 226.8683250410213361 34.3484316781252872, 226.8772265484987827 34.3479835600551411, 226.8861363120287820 34.3475343031321643, 226.8950567593712151 34.3470837781792824, 226.9039829499012342 34.3466322445209613, 226.9129146680944586 34.3461797125383796, 226.9218556874094190 34.3457259818489007, 226.9308045477948212 34.3452711282402134, 226.9397756292526935 34.3448143895302991, 226.9487603184134628 34.3443562188081941, 226.9577713539454749 34.3438959389133132, 226.9667906962734207 34.3434345027779955, 226.9758185915864317 34.3429718957263219, 226.9848216200828119 34.3425098913908968, 226.9938252716434022 34.3420471374260643, 227.0028484628032004 34.3415826267594255, 227.0118809439680376 34.3411169021389426, 227.0209235817709157 34.3406499156234730, 227.0299791780944076 34.3401815158194665, 227.0390478252961657 34.3397116954514985, 227.0481467096626034 34.3392395333766274, 227.0572602651047589 34.3387658574176697, 227.0663771858033613 34.3382912703768000, 227.0755008947110412 34.3378155877346387, 227.0846303913073996 34.3373388616534214, 227.0937637964039197 34.3368611917211055, 227.1029086135041268 34.3363821733254326, 227.1120687985143718 34.3359015911654453, 227.1212359111418095 34.3354198971173048, 227.1304019305064799 34.3349375223436510, 227.1395758196006227 34.3344539825447868, 227.1487597349276939 34.3339691593657577, 227.1579902583263788 34.3334810704758411, 227.1672328061905830 34.3329915812163549, 227.1764712676953764 34.3325015630313501, 227.1857181919765196 34.3320103346922068, 227.1949746843040998 34.3315178341563794, 227.2042427831847817 34.3310239482966324, 227.2135235122840982 34.3305286187725258, 227.2228146140698470 34.3300319660012221, 227.2321158182128897 34.3295340024028306, 227.2414261879402773 34.3290347769038178, 227.2507440105588898 34.3285343811480317, 227.2600744088126987 34.3280325324944329, 227.2694283383975744 34.3275286268106896, 227.2787965981402749 34.3270231647175663, 227.2881796631106397 34.3265161168640063, 227.2975768164326098 34.3260075194109433, 227.3069878365900536 34.3254973813716404, 227.3164104609731169 34.3249858245099517, 227.3258502854863821 34.3244725367080363, 227.3353080996716926 34.3239574703683132, 227.3447883387066213 34.3234403755930231, 227.3542849111706516 34.3229215853954415, 227.3637955610474251 34.3224012213397103, 227.3733236581833523 34.3218790926137487, 227.3828696239687588 34.3213551716833152, 227.3924291244551910 34.3208296960990893, 227.4020038477916614 34.3203025683132452, 227.4115915765664226 34.3197739086688500, 227.4211903006604700 34.3192438265212800, 227.4308034100351108 34.3187121290632149, 227.4404322668985969 34.3181787363226363, 227.4500783315635317 34.3176435624042711, 227.4597408211544121 34.3171066472117232, 227.4694373999262496 34.3165669913512517, 227.4791525994612869 34.3160254597000787, 227.4888678788144887 34.3154830952473446, 227.4985957069042684 34.3149391921614608, 227.5083373853137800 34.3143936735035950, 227.5181018062716021 34.3138460313881026, 227.5278825759429822 34.3132966234387382, 227.5376789842294727 34.3127454859353378, 227.5475028125167114 34.3121919440087666, 227.5573500149448023 34.3116362217108275, 227.5672257339052180 34.3110780196529106, 227.5771363516663257 34.3105169659525515, 227.5870780116667618 34.3099532729218311, 227.5970431329253074 34.3093873675369423, 227.6070304509327400 34.3088193164755637, 227.6170402145462504 34.3082490997872753, 227.6270614888811394 34.3076773412008720, 227.6371021487410076 34.3071035836203464, 227.6471620472045174 34.3065278304867505, 227.6572333482910437 34.3059505296988334, 227.6673250879570389 34.3053711550848206, 227.6774425887975610 34.3047893928164669, 227.6875956283761582 34.3042046687850117, 227.6977747165031190 34.3036175255403322, 227.7079695685462184 34.3030285548813652, 227.7181855113298639 34.3024374420603095, 227.7284236548779006 34.3018441166910364, 227.7386810962439370 34.3012487425373109, 227.7489607488712977 34.3006511438890129, 227.7592652945483849 34.3000511576431890, 227.7696049562804603 34.2994481772121560, 227.7799661327425724 34.2988429927923590, 227.7903495499146800 34.2982355558256629, 227.8007531420874443 34.2976259820287197, 227.8111804588932046 34.2970140563683117, 227.8216354765219762 34.2963995373976971, 227.8321461589635248 34.2957807625226110, 227.8426781272081598 34.2951597549060097, 227.8532313530564579 34.2945365103118931, 227.8637943594835917 34.2939117050406637, 227.8743681842870501 34.2932852743100653, 227.8849595330413251 34.2926568151129274, 227.8955699765630243 34.2920262286820332, 227.9062407193817990 34.2913910462529827, 227.9169476338818185 34.2907526962728824, 227.9276713907391070 34.2901123277707356, 227.9383745218270860 34.2894721855654225, 227.9490646281740283 34.2888318174488731, 227.9597329801610215 34.2881917519580668, 227.9704830712439048 34.2875457532931449, 227.9813063056426188 34.2868943187016839, 227.9922004455595754 34.2862375637549519, 228.0031311318133760 34.2855775502002302, 228.0140933799731044 34.2849145701223961, 228.0250913628472631 34.2842483610777151, 228.0361342648420191 34.2835783542064476, 228.0472235719963976 34.2829044463309032, 228.0583488204560183 34.2822272628250815, 228.0695055535578035 34.2815470657209929, 228.0806796288568989 34.2808647114042770, 228.0918858625025791 34.2801792865075825, 228.1031233132273712 34.2794908394530964, 228.1143887119357885 34.2787995620820993, 228.1256453028393310 34.2781077090887294, 228.1369030524184041 34.2774146678620184, 228.1481798443664104 34.2767193332270281, 228.1595524441736416 34.2760169519050635, 228.1709717099908232 34.2753105403553633, 228.1824155794452338 34.2746014535234238, 228.1938803829937683 34.2738899119351714, 228.2054189265468267 34.2731726235595744, 228.2170280980613768 34.2724497608496819, 228.2287243266976020 34.2717202776986980, 228.2405154509019098 34.2709836584986931, 228.2523281114683300 34.2702444678746687, 228.2641942766789498 34.2695006944830141, 228.2760966165555772 34.2687534104679585, 228.2880311232885049 34.2680028567511314, 228.3000080489240418 34.2672483774467551, 228.3120073191867618 34.2664912261055008, 228.3240136615007714 34.2657323607450550, 228.3360270491550921 34.2649717804313312, 228.3480846101073496 34.2642071288155847, 228.3601573792798547 34.2634402313342648, 228.3722738818091784 34.2626692688684500, 228.3844436938969977 34.2618936178110403, 228.3966618612765558 34.2611135776316118, 228.4089824127830468 34.2603256808090748, 228.4213463879687822 34.2595336690666841, 228.4337530236520877 34.2587375774856469, 228.4462104847059720 34.2579368681707450, 228.4587268133269902 34.2571310076858353, 228.4712928807757635 34.2563205652335157, 228.4839104809788068 34.2555054090235060, 228.4966228686224952 34.2546827270764354, 228.5094182245555317 34.2538532539691332, 228.5222741771181632 34.2530184132892686, 228.5351729278072810 34.2521793410413267, 228.5481108241752963 34.2513362605627520, 228.5610933369306963 34.2504888022590066, 228.5740744626591265 34.2496399537063994, 228.5870890608425441 34.2487874359030613, 228.6001377310801672 34.2479311982219414, 228.6132200400504360 34.2470712574983622, 228.6263499085960404 34.2462066876372617, 228.6395379494453266 34.2453367741268764, 228.6528307701242682 34.2444584248850319, 228.6663763632237476 34.2435618321321016, 228.6803617216070279 34.2426345403196351, 228.6952015541801302 34.2416489116415192, 228.7105525888537727 34.2406274235319827, 228.7265499348228559 34.2395608902071800, 228.7421439706192814 34.2385190300592157, 228.7570825716228455 34.2375188386586942, 228.7710598753439228 34.2365810240280624, 228.7833530683670631 34.2357543577948604, 228.7952800700753357 34.2349509230007385, 228.8072627602488183 34.2341424759791622, 228.8196514308424128 34.2333054216225534, 228.8331287442263147 34.2323936078462552, 228.8473922131469180 34.2314270979658133, 228.8618442087490621 34.2304460497711887, 228.8763439298241735 34.2294599387118552, 228.8909482643397268 34.2284648839076766, 228.9056482136823263 34.2274614587343677, 228.9203772896302098 34.2264541587582869, 228.9351647839141037 34.2254409727997029, 228.9499300140618345 34.2244273972624811, 228.9641311146921510 34.2234505681393131, 228.9782062980468424 34.2224806099825472, 228.9925852306206764 34.2214880257807579, 229.0081810669700531 34.2204098059550645, 229.0243240483496265 34.2192917030580972, 229.0404841060924355 34.2181701533111990, 229.0561546197716325 34.2170802519520976, 229.0718159793608208 34.2159888444595737, 229.0875983321437843 34.2148868823154046, 229.1034887026832507 34.2137752211917672, 229.1195460111437114 34.2126497038870951, 229.1358158382292629 34.2115070741072174, 229.1519329161566247 34.2103728455040539, 229.1680640638790010 34.2092353650361005, 229.1841528314637060 34.2080985980235468, 229.1997352210103145 34.2069952675949978, 229.2145400585607717 34.2059447195264852, 229.2300224803216508 34.2048443142916696, 229.2467979267665044 34.2036501662420633, 229.2636965491348917 34.2024448212972558, 229.2805688058051317 34.2012388685525011, 229.2975531551136896 34.2000224457224959, 229.3153572084256382 34.1987449442457603, 229.3330755456162251 34.1974708312596292, 229.3499864414941953 34.1962519261839191, 229.3671162393675331 34.1950147939656546, 229.3845622241133242 34.1937523319198320, 229.4014568277655997 34.1925270212032402, 229.4184179979918952 34.1912944082571215, 229.4358437587445394 34.1900256223241072, 229.4537366314563940 34.1887202761169675, 229.4717783256412247 34.1874013196511939, 229.4899255387612413 34.1860718421937406, 229.5081725982472847 34.1847322093503720, 229.5265398704868574 34.1833808832578541, 229.5450922295952694 34.1820130472502939, 229.5638787832904484 34.1806250030229961, 229.5833013117678263 34.1791870290051136, 229.6027619755459170 34.1777429731368159, 229.6217226068972934 34.1763326527843745, 229.6405847438497290 34.1749265203990760, 229.6596052490852458 34.1735055273339228, 229.6788397630404006 34.1720654517922497, 229.6983584810002696 34.1706009483857684, 229.7180957279716438 34.1691167911206364, 229.7380788626514345 34.1676108188229648, 229.7584117626756210 34.1660750989131259, 229.7790969056334802 34.1645092649619997, 229.7996369176232463 34.1629506915650722, 229.8203742932615512 34.1613735311362419, 229.8416825811018498 34.1597493412739510, 229.8624957634657164 34.1581588785920403, 229.8824174025879756 34.1566326127752475, 229.9024284096594783 34.1550960778054815, 229.9235693656282535 34.1534695744186010, 229.9452549994915955 34.1517974116376450, 229.9672683739203762 34.1500959777487836, 229.9895003849197224 34.1483735025366997, 230.0115335641944796 34.1466621287872911, 230.0333871041715099 34.1449604786041974, 230.0555507514620786 34.1432306179808407, 230.0779079317051412 34.1414814475757851, 230.1005423000427754 34.1397063292869731, 230.1238833343684291 34.1378715064769978, 230.1469833844930122 34.1360508854267479, 230.1701524619105328 34.1342202325622850, 230.1934678024694279 34.1323734190311470, 230.2165682856712294 34.1305388895062976, 230.2389046257694076 34.1287602695710035, 230.2627494181147654 34.1268575757473442, 230.2877550267185427 34.1248575756020784, 230.3121994425740695 34.1228969831179754, 230.3374538174993802 34.1208664279544891, 230.3631413116128499 34.1187956310739864, 230.3880206607561831 34.1167841714593507, 230.4129740677024358 34.1147614026916202, 230.4381720996264562 34.1127134836086441, 230.4639006138211812 34.1106170798747215, 230.4899617774171361 34.1084879303946877, 230.5160751630245670 34.1063486758618524, 230.5424933623011725 34.1041786332810304, 230.5692512088523074 34.1019747430087889, 230.5962633488587699 34.0997437898786657, 230.6233712572403647 34.0974986647174276, 230.6505324126961796 34.0952428144590982, 230.6778991777003398 34.0929635734629102, 230.7056768660073374 34.0906437346523887, 230.7338743165616108 34.0882822719610346, 230.7624290256065365 34.0858841097945344, 230.7912515729211691 34.0834564851068578, 230.8203176007895649 34.0810012491227425, 230.8496066250636716 34.0785199485613148, 230.8792222279614919 34.0760036572390916, 230.9092353385915999 34.0734461133305189, 230.9394837891279906 34.0708608099390275, 230.9699110764533998 34.0682523865333948, 231.0006928671984952 34.0656056693742713, 231.0318850272019233 34.0629155853065342, 231.0635571686675860 34.0601758150416671, 231.0955368340583789 34.0574008701335060, 231.1277395308280802 34.0545978214642844, 231.1598263150311539 34.0517959464564015, 231.1923731408356559 34.0489451184199368, 231.2256091620638188 34.0460249133125856, 231.2592693972243580 34.0430580047345259, 231.2932997455176576 34.0400487929999827, 231.3276773418911603 34.0369989773430746, 231.3623788652666065 34.0339103205237308, 231.3976872584197793 34.0307573786865305, 231.4333912448704211 34.0275584578910824, 231.4693555746214315 34.0243253059693487, 231.5059110724441780 34.0210279683690331, 231.5428878342104326 34.0176812112379210, 231.5803120488249078 34.0142822697343732, 231.6182257696958402 34.0108269012199926, 231.6563923558109366 34.0073361889261463, 231.6951328869912459 34.0037805360141618, 231.7344016753486926 34.0001635696370954, 231.7741163313663151 33.9964923488039332, 231.8144687461388287 33.9927486901787290, 231.8555242505667309 33.9889258811518715, 231.8967616380454047 33.9850717164516425, 231.9384874592085453 33.9811573545970305, 231.9810031243091828 33.9771540024940819, 232.0239997222591910 33.9730898996244832, 232.0678388327740720 33.9689303372334805, 232.1123373517177413 33.9646917582200558, 232.1571892772059869 33.9604025762483914, 232.2028902909401324 33.9560149644208167, 232.2491821770346974 33.9515527435586009, 232.2960411962056355 33.9470175078809291, 232.3439306823368327 33.9423637057928005, 232.3925149926277811 33.9376227334373510, 232.4421795019375736 33.9327560903860643, 232.4923819961781533 33.9278156109878992, 232.5436698047475943 33.9227466787318193, 232.5951687842305660 33.9176343955933461, 232.6475716307096491 33.9124096239597890, 232.7012278930365596 33.9070362580221811, 232.7556828037685932 33.9015582139110450, 232.8111272810814398 33.8959551460956590, 232.8675924455159532 33.8902225111619728, 232.9251556044690972 33.8843509815862447, 232.9836292775250968 33.8783581195322014, 233.0432332674061513 33.8722199923502529, 233.1036814246761537 33.8659644314339587, 233.1655576137215462 33.8595295606770179, 233.2282972755570540 33.8529720149463103, 233.2926253692118621 33.8462144248317642, 233.3579653179138234 33.8393149568009406, 233.4238324437535539 33.8323232701533883, 233.4921199961581237 33.8250368578670972, 233.5612785481834237 33.8176174604834756, 233.6323604437994561 33.8099502308987780, 233.7049545857545922 33.8020762209203056, 233.8182991445546293 33.7896946458198926, 233.8076868009974589 33.7447711158304671, 233.7998795211174752 33.7148904495256687, 233.7932833621273403 33.6848666704869686, 233.7861879662788169 33.6548975267118280, 233.7790138732385969 33.6249371303082398, 233.7721258780048856 33.5949457573666024, 233.7653244276447708 33.5649451761957351, 233.7589504395879203 33.5348983219310597, 233.7517922485339170 33.5049370175201418, 233.7451099030573687 33.4749242024867826, 233.7380079968496034 33.4449572273965501, 233.7308913047606325 33.4150038906189266, 233.7242842861141980 33.3850066679223403, 233.7177523609356058 33.3550016102456155, 233.7105361718773224 33.3250710555783343, 233.7038713781764727 33.2950810138029354, 233.6970686629649663 33.2651062318509503, 233.6905337589383009 33.2351027782129904, 233.6840504442202189 33.2050940973791882, 233.6777241043450886 33.1750688063842745, 233.6714174242954982 33.1450417812508462, 233.6651265169321618 33.1149842339623106, 233.6589877929609145 33.0848829896515539, 233.6524321129587634 33.0548271749566993, 233.6459016739153185 33.0247690228650370, 233.6397274744219033 32.9946728445241391, 233.6329292366539221 32.9646443836585377, 233.6264198619547301 32.9345851795598108, 233.6202087451694069 32.9044942683736679, 233.6139880511334468 32.8744048430015070, 233.6079852678255975 32.8442924251869286, 233.6024480633732310 32.8141580578265248, 233.5966311951530656 32.7840805084876692, 233.5901811265881349 32.7540715696615052, 233.5840609929455240 32.7240276623761233, 233.5780234847293855 32.6939754071204192, 233.5723051528725591 32.6638894275744747, 233.5666017738128630 32.6338024224210770, 233.5607542214522141 32.6037314697343916, 233.5546837866806982 32.5736849918668696, 233.5486024506201943 32.5436402502741871, 233.5424177865809554 32.5135952203075078, 233.5365716068125437 32.4835032167910924, 233.5315060001448160 32.4533282705142696, 233.5261496479418497 32.4231850921035161, 233.5203742088707770 32.3930873794257010, 233.5147182819266050 32.3629775113514810, 233.5094845867136542 32.3328231673348157, 233.5039894605985182 32.3026974293673987, 233.4978335602601760 32.2726429029673625, 233.4931590406256134 32.2424309058476695, 233.4878027400857547 32.2122923883547898, 233.4822943077738842 32.1821707946306717, 233.4769428295691398 32.1520331688125083, 233.4715484852565623 32.1219008274845379, 233.4659832529781340 32.0917874105425511, 233.4604242299232908 32.0616740463839420, 233.4547057474827625 32.0315783749592171, 233.4493448635817572 32.0014453815873736, 233.4439538849541975 31.9713163426437035, 233.4388438489372675 31.9411582034324724, 233.4333516271451003 31.9110653070441082, 233.4279989231125114 31.8809809552748931, 233.4229566390458501 31.8508644672416104, 233.4183811248644531 31.8206993019833213, 233.4138877626305373 31.7905263247609859, 233.4092102827143265 31.7603737819017375, 233.4050516566461511 31.7301671582915610, 233.4001074317153552 31.7000447186518528, 233.3957145715358195 31.6698647915971598, 233.3913100753762535 31.6396870518093785, 233.3864447837854073 31.6095336382647432, 233.3812875214192673 31.5793879738905261, 233.3764952550197904 31.5492046024446182, 233.3713681256496670 31.5190575396905999, 233.3665069083577919 31.4888832848857625, 233.3615529342137336 31.4587197535848944, 233.3563206750544055 31.4285865290605138, 233.3514797003734884 31.3984129292956879, 233.3465577546590453 31.3682488232810783, 233.3417228713095142 31.3380764927870921, 233.3370904021178944 31.3078918587356796, 233.3327447691412431 31.2776856492184869, 233.3284034057362533 31.2474800412854954, 233.3238447530990811 31.2172983697557100, 233.3202001870982656 31.1870215346005644, 233.3161949179906856 31.1567837769810794, 233.3117460132445729 31.1265937910656838, 233.3074302664846300 31.0963908863597638, 233.3031004202551912 31.0661905619150183, 233.2993877463871968 31.0359264957760104, 233.2953127272745064 31.0057054347712793, 233.2898951298278121 30.9756300525318728, 233.2854622844924677 30.9454523392395302, 233.2811087260189424 30.9152674167444452, 233.2766787725826418 30.8850916312266435, 233.2723182338893366 30.8549096935436857, 233.2680625875141800 30.8247179031670875, 233.2636594360838558 30.7945427206847739, 233.2591073856077344 30.7643842796401081, 233.2546430265682602 30.7342178079628638, 233.2506548072817054 30.7039852299420346, 233.2467326449200016 30.6737304211930564, 233.2427735884617448 30.6434806792112795, 233.2385419917316085 30.6132606393829576, 233.2344263708046128 30.5830296838953331, 233.2299724550055373 30.5528352857998122, 233.2257801219477926 30.5226147735751283, 233.2217008351062191 30.4923836900467329, 233.2176536181539745 30.4621505031472850, 233.2137701089007464 30.4319014927329583, 233.2097164924721255 30.4016889943031465, 233.2057273903701571 30.3714876142137022, 233.2018315928332299 30.3412778047890264, 233.1982994816496557 30.3110314135098449, 233.1949660442565744 30.2807656745234262, 233.1909995460327423 30.2505672081964114, 233.1869329125315176 30.2203804896412507, 233.1830432862202258 30.1901766843428980, 233.1794294371081833 30.1599455462454884, 233.1757256558106803 30.1297251350849358, 233.1722016871892151 30.0994998764303290, 233.1687265873930528 30.0692827643050364, 233.1657971256008182 30.0390104336791275, 233.1620197155411915 30.0088276220406023, 233.1588110553900606 29.9785872276917402, 233.1558657451028012 29.9483210009432987, 233.1526520127786171 29.9180841251987353, 233.1489461530049994 29.8878997696919164, 233.1453943524933834 29.8577009226217918, 233.1419015804141281 29.8274974560065331, 233.1385470571378278 29.7972455511092846, 233.1353455350549098 29.7669455615295924, 233.1321205569724100 29.7366494892085349, 233.1286857503216936 29.7063766210425086, 233.1248502693015041 29.6761466884616851, 233.1219322346422587 29.6458233627628012, 233.1187887011244015 29.6155248850105295, 233.1158036471032915 29.5852115613275579, 233.1128189974455722 29.5548997434324079, 233.1096148239391823 29.5246121600670683, 233.1059421915823009 29.4943963291804003, 233.1029253621703106 29.4641350065372620, 233.1002381417609115 29.4338412716992508, 233.0969753054017133 29.4036085512195093, 233.0938295190734380 29.3733653616549155, 233.0913472163580877 29.3430553834513610, 233.0892058098987150 29.3127119349485312, 233.0863428536627850 29.2824445349018490, 233.0832116703717247 29.2522064239827877, 233.0797675612365367 29.2220021876053160, 233.0766708226278467 29.1917583918291292, 233.0740702319781121 29.1614600580752850, 233.0714565710502484 29.1311647753719036, 233.0690128690097254 29.1008537235290277, 233.0668902691573123 29.0705113857552107, 233.0645048567228059 29.0401978200036268, 233.0622308672101894 29.0098745532464193, 233.0598776027648569 28.9795611971523535, 233.0578674387814431 28.9492143655959921, 233.0557478222018517 28.9188805699689802, 233.0535026840542514 28.8885669116903188, 233.0508429036587472 28.8583027762556696, 233.0484008302832137 28.8280180911296426, 233.0460454447872394 28.7977263211071275, 233.0438808462369593 28.7674168095387621, 233.0413729393396807 28.7371443319296063, 233.0390306784818790 28.7068567067617160, 233.0369262675736195 28.6765465604866243, 233.0347470633701619 28.6462459426569716, 233.0329268350126029 28.6159104396724437, 233.0304011304855862 28.5856435995657812, 233.0285767800049257 28.5553016797995802, 233.0267613739302988 28.5249607573186275, 233.0251239162247714 28.4946035505017150, 233.0235861249787490 28.4642380888183872, 233.0216106034007453 28.4339193332019953, 233.0189545611982282 28.4036720750902205, 233.0154885602265438 28.3735094844721587, 233.0142983651934117 28.3431162820911773, 233.0278250723133340 28.3112211640409903, 233.0452282676278060 28.2789483187385748, 233.0538325274342526 28.2475942808530363, 233.0539975568602529 28.2171064726347609, 233.0513725666164362 28.1869063911917372, 233.0495940247802196 28.1566216920424672, 233.0476156283758939 28.1263594901667915, 233.0441012164610015 28.0962563986380189, 233.0341267619562586 28.0668153191363956, 233.0153669885793022 28.0382716562388339, 233.0004310857394785 28.0093374012700345, 232.9972907785160885 27.9791790793518587, 232.9993492557859440 27.9484712223743585, 232.9984005080535496 27.9180717344066736, 232.9974307125876010 27.8876765098116621, 232.9972130492358815 27.8572068668353197, 232.9974480176594227 27.8266933234033189, 232.9991589372485805 27.7960317666082908, 232.9989280134374212 27.7655700234398815, 232.9984242466583737 27.7351382270208759, 232.9981795284512032 27.7046822703976972, 232.9979878384328060 27.6742274580723340, 232.9973841036610338 27.6438208719064171, 232.9969627048609482 27.6133979690381395, 232.9956424441186300 27.5830686696756793, 232.9942467721440096 27.5527492409820809, 232.9928294278056455 27.5224342236380650, 232.9910051527021437 27.4921627558273016, 232.9892752252020500 27.4618839132446162, 232.9876407499817219 27.4315975974861708, 232.9860500535251049 27.4013090709267217, 232.9845431092235799 27.3710008489806320, 232.9832144523942645 27.3406640377758414, 232.9813211962325852 27.3103867100814455, 232.9796046601171611 27.2800936680540822, 232.9778668740795524 27.2498050024457434, 232.9760812623404718 27.2195234107069091, 232.9744936225158938 27.1892239957064348, 232.9725389188245686 27.1589640136283386, 232.9710993706607098 27.1286541056528883, 232.9695310658502763 27.0983595097532017, 232.9678740179837177 27.0681026007772161, 232.9664105876216240 27.0378534557890511, 232.9648174107140619 27.0076198078588909, 232.9633173341063355 26.9773791166742747, 232.9625444737612270 26.9470672981345629, 232.9609409653380681 26.9168418629002275, 232.9596090239890316 26.8865913871609834, 232.9583747341857531 26.8563334706206511, 232.9570418888882273 26.8260879392119520, 232.9556783045243833 26.7958479490301684, 232.9541208556610741 26.7656115503644969, 232.9529072543819552 26.7353254479201290, 232.9513372321579538 26.7050777308408698, 232.9496721067915246 26.6748420272619029, 232.9482697864152385 26.6445822619811636, 232.9469308519850301 26.6143185587787592, 232.9456308588750346 26.5840533948264977, 232.9445891873294840 26.5537646856055431, 232.9435705002171630 26.5234761549716502, 232.9424930684088508 26.4931960433853853, 232.9411883949197204 26.4629460272430457, 232.9404661357677355 26.4326443638835720, 232.9397077071034801 26.4023488673881523, 232.9389590229795886 26.3720549233583981, 232.9380771814587092 26.3417769121321328, 232.9371118552418238 26.3115098363031592, 232.9363055939249421 26.2812293227256610, 232.9349899869485796 26.2510025504793276, 232.9335253420537128 26.2207932922122957, 232.9325013463743232 26.1905423329594917, 232.9312666334036805 26.1603104013804000, 232.9304842317118300 26.1300312111249937, 232.9301915141380164 26.0997055104343687, 232.9294881720715580 26.0694236562425132, 232.9290727465349846 26.0391155705938289, 232.9284303149261177 26.0088329122040740, 232.9279035226248311 25.9785413248613928, 232.9273612165927716 25.9482539711809004, 232.9268538349265896 25.9179658022049786, 232.9262752018361766 25.8876874677902222, 232.9258886605539374 25.8574103205503327, 232.9254503185429996 25.8271578908256885, 232.9251078811092270 25.7968986263608109, 232.9246578931967804 25.7666529016120904, 232.9240220891967397 25.7364285482954038, 232.9236035390601955 25.7061852433478570, 232.9230685584527407 25.6759563790138863, 232.9227337276141725 25.6457103098245049, 232.9226746290124197 25.6154395052224828, 232.9151284100966564 25.5859193756643037, 232.8937666408189102 25.5577604985455409, 232.8940638254573230 25.5274256431740447, 232.8871864394731119 25.4978083491673289, 232.8887549686981515 25.4673523877789023, 232.8922447980335733 25.4367079618528074, 232.8868549805569899 25.4069505089107963, 232.8862070943299614 25.3767236846523367, 232.8896433829220882 25.3460933179366066, 232.8904085764630736 25.3157316467882119, 232.8749355209038185 25.2869872854492073, 232.8752451627682944 25.2566951708063492, 232.8833426366030039 25.2256500908747370, 232.8835253170702515 25.1953944684774278, 232.8791674520630863 25.1655927164424611, 232.8897864848735821 25.1343065993527688, 232.8853793269061612 25.1045158111557178, 232.8872412250228479 25.0741054813627002, 232.8902504012405075 25.0435843557223841, 232.8862819506680353 25.0137587009765774, 232.8849165371166805 24.9836776255639847, 232.8615444346234540 24.9557405574212225, 232.8678957260945026 24.9248252132858035, 232.8743003819387809 24.8939074623086505, 232.8845451260537232 24.8626121460513616, 232.8855114925713110 24.8322389783660284, 232.8777786943020374 24.8027302997633363, 232.8784494298064658 24.7723922672678682, 232.8786766284533201 24.7421011266518249, 232.8815821188912594 24.7115479150936821, 232.8784798199646389 24.6815922415318738, 232.8815210228855790 24.6510507831176042, 232.8869507733595299 24.6202941881330766, 232.8897516433328008 24.5898008393355454, 232.8918981621112039 24.5593753741429559, 232.8953447470361766 24.5288244473084909, 232.9021256321721296 24.4979467948482466, 232.9055803921938264 24.4674014151714623, 232.9256796376523369 24.4352113534178343, 232.9278143680417656 24.4048031511445132, 232.9273308331783596 24.3746574337605217, 232.9233851757292086 24.3448714448659054, 232.9184915904676814 24.3151952701589558, 232.9128735282994000 24.2855934651471266, 232.9070168457516559 24.2560179019932782, 232.8961245154026756 24.2269419337473444, 232.9056956381911334 24.1958493513260890, 232.9163992201185920 24.1646481367450399, 232.9148753749125262 24.1346574495095076, 232.9260392073335311 24.1034175400766664, 232.9206813332552031 24.0738120737350272, 232.9204495721024557 24.0437090839679151, 232.9242943937483687 24.0132123141866138, 232.9256437470649246 23.9829650936419547, 232.9266377200116835 23.9527562658711197, 232.9335016546866370 23.9219720544854937, 232.9350094751260940 23.8917194173821841, 232.9318311548631470 23.8619319937482324, 232.9368722189848881 23.8313379252621615, 232.9450679386291085 23.8004364540855136, 232.9487612036170390 23.7699821915590945, 232.9457539898387495 23.7401711441849521, 232.9427211904169894 23.7103463853456695, 232.9402080397393888 23.6804735786337730, 232.9433835896780352 23.6500442500705326, 232.9429844400121965 23.6199700523985072, 232.9448047522230922 23.5896808975073995, 232.9476776161833982 23.5592916672883561, 232.9482010012357023 23.5291369223764057, 232.9512697054896080 23.4987353646153210, 232.9482075711342759 23.4689398428672398, 232.9524304169726179 23.4384270363305838, 232.9546730816441027 23.4081077648677862, 232.9582883792437826 23.3776571360643501, 232.9647493345424039 23.3469304505496922, 232.9703738878391732 23.3162894618000216, 232.9749310818776848 23.2857568940812207, 232.9745359585149913 23.2557144437894898, 232.9767231067804687 23.2254218015470215, 232.9747120127888138 23.1955449257939925, 232.9822413993305190 23.1647348153342882, 232.9804333913460255 23.1348442843248776, 232.9799632302537304 23.1048251182840687, 232.9861015984569690 23.0741610276239513, 232.9875906071483769 23.0439567789152626, 232.9885163914815678 23.0138113509045859, 232.9880927479807724 22.9838018051451805, 232.9920786516129283 22.9533634401114774, 232.9956900448753458 22.9229654565282175, 232.9980286669976977 22.8926959143639941, 232.9994463255823121 22.8625202868843544, 233.0007273528797214 22.8323817678633709, 233.0026223772322567 22.8022057942484118, 233.0043541575535926 22.7720495280457627, 233.0056855084943663 22.7419361868120475, 233.0075168388989937 22.7117776143631822, 233.0086972640626470 22.6816864800318925, 233.0110141290699062 22.6514878823163492, 233.0150980296511420 22.6211202179953688, 233.0183630377297845 22.5908364989234300, 233.0205235277441886 22.5606646286184329, 233.0226990889819945 22.5304748350743864, 233.0250312227692007 22.5002543316308490, 233.0273417265109401 22.4700397096754543, 233.0294322534792286 22.4398503559635571, 233.0316537241797050 22.4096519869835333, 233.0341646708320127 22.3794291320634606, 233.0365342747200543 22.3492238899732065, 233.0390090295576329 22.3190121956477334, 233.0410423262773918 22.2888474231631406, 233.0431049504354633 22.2586836085089494, 233.0454588239587679 22.2284945391122122, 233.0478015507949863 22.1983097810625374, 233.0502410036448282 22.1681194492568316, 233.0528960638682747 22.1379119636236830, 233.0557407392531672 22.1076898814232585, 233.0583526795629723 22.0774943964448340, 233.0611965970119286 22.0472802075900809, 233.0637667924078755 22.0170966232015282, 233.0661707317356957 21.9869331635871568, 233.0688355155518252 21.9567482211745499, 233.0712133980820795 21.9266163988525697, 233.0735932642361945 21.8965084710525879, 233.0760567739936846 21.8663964169623064, 233.0786160068223012 21.8362790738185488, 233.0813521306658913 21.8061485618539201, 233.0841934460657967 21.7760118752912923, 233.0868186398116109 21.7459002817007985, 233.0896572715981847 21.7157720084171970, 233.0925606006185831 21.6856415363909605, 233.0953944803874549 21.6555219187505443, 233.0982658468537352 21.6253757162664293, 233.1010684296372801 21.5952146479776665, 233.1039565019003135 21.5650493241765950, 233.1070084941937068 21.5348721394971925, 233.1101013321711548 21.5046950639544967, 233.1128703125102675 21.4745535124936850, 233.1158241929650785 21.4443980967747798, 233.1188318357311005 21.4142415632226992, 233.1218563893511373 21.3840874972769868, 233.1246794786605392 21.3539570957466438, 233.1274225833886931 21.3238601080463575, 233.1306370619428208 21.2937419769091925, 233.1338110029607549 21.2636319987268081, 233.1368714757588236 21.2335372461872005, 233.1401888172864005 21.2034218385370075, 233.1433772706163268 21.1733231701487874, 233.1465315269799419 21.1432320716031548, 233.1496154961199068 21.1131520453783352, 233.1523256640593331 21.0831124742891234, 233.1550432763680192 21.0530764455185277, 233.1579828491569231 21.0230058062467613, 233.1607722023841234 20.9929374507901869, 233.1636624180470108 20.9628635552655389, 233.1666398146293204 20.9327854558763065, 233.1696517888767062 20.9027082544394709, 233.1726003364720725 20.8726414315883027, 233.1758702061451345 20.8425478178669259, 233.1788078856152140 20.8124905745848992, 233.1817470920860274 20.7824374565909480, 233.1847240764050753 20.7523849749798082, 233.1882571694646629 20.7222788476118609, 233.1922497393497906 20.6921286818578203, 233.1963717973546864 20.6619703873674609, 233.1999109853458094 20.6318727135351807, 233.2035406237866653 20.6017706851485940, 233.2070288687683330 20.5716866761621162, 233.2105921939143514 20.5415998140439626, 233.2140636677692953 20.5115262079037137, 233.2178119026467868 20.4814303279723511, 233.2217592402049036 20.4513196856889081, 233.2251909010724376 20.4212673943469092, 233.2282694104284246 20.3912575382026091, 233.2318419184239815 20.3612045154493551, 233.2355239631731934 20.3311453845283800, 233.2391586893154454 20.3010952640841857, 233.2428990778608409 20.2710394342439209, 233.2464567058851799 20.2410056660194115, 233.2499761034000585 20.2109800535650557, 233.2536732782447757 20.1809418254342710, 233.2573748161999561 20.1509076803071849, 233.2610258437933908 20.1208946526018622, 233.2648839717270732 20.0908774183957277, 233.2690707989333987 20.0608332119564245, 233.2729399482114729 20.0308241593004865, 233.2766399932764330 20.0008359799500468, 233.2812975167479408 19.9707604951296211, 233.2864835103322889 19.9406389605168357, 233.2910589909978398 19.9105807426328667, 233.2951517126284102 19.8805735518180349, 233.2994281961467209 19.8505534223365530, 233.3035672940375491 19.8205511747602010, 233.3079874496854131 19.7905266854675403, 233.3129269618572437 19.7604571404375058, 233.3212816261195712 19.7300649786178361, 233.3230339210745683 19.7003105135329939, 233.3250709695567195 19.6705333692279076, 233.3296297888962556 19.6405193531334881, 233.3340604185272014 19.6105224014149755, 233.3383183316778968 19.5805467749155397, 233.3428179007618439 19.5505528168766070, 233.3472901991912636 19.5205884333304596, 233.3519547731943362 19.4906315127633185, 233.3565130545534316 19.4606896820815152, 233.3611875776566364 19.4307416675757452, 233.3661894040620268 19.4007673213283738, 233.3703364722979359 19.3708796063483994, 233.3750997856716083 19.3409379714334939, 233.3796821891314153 19.3110185896687092, 233.3838727404156259 19.2811415854923105, 233.3885341449363864 19.2512246218168066, 233.3933864583176216 19.2212534982861243, 233.3986811268006818 19.1912063079851407, 233.4036949063699069 19.1611907724062256, 233.4090010487341260 19.1311522333228261, 233.4132186008963572 19.1012223437114059, 233.4123898127269570 19.0717780874003857, 233.4234938187712487 19.0412018332193078, 233.4281136087350319 19.0112482688797293, 233.4325499943371369 18.9813170712391042, 233.4385722855595304 18.9512397884117654, 233.4443472688414545 18.9211910404438690, 233.4496096001402634 18.8911960802090277, 233.4547716285619288 18.8612156352242870, 233.4583507146321324 18.8313907512366896, 233.4655539292224091 18.8012260954862001, 233.4711278176775977 18.7712214498370962, 233.4767412811399936 18.7412180638716279, 233.4825004788563945 18.7112058596042878, 233.4883578875892454 18.6811893699161615, 233.4930940637389085 18.6512844874408472, 233.4992980387236230 18.6212451930439258, 233.5048315554937517 18.5912746804041475, 233.5077083127482638 18.5615615247289583, 233.5090647555902592 18.5319976053133928, 233.5185189872614160 18.5016701736141833, 233.5255892488342226 18.4715741711933923, 233.5300607514989792 18.4417298953676436, 233.5355540632440920 18.4117937924144925, 233.5416644756876678 18.3818043137723670, 233.5436055658501289 18.3522152471283633, 233.5514883548236185 18.3220390661888821, 233.5588538183609444 18.2918895888480471, 233.5647531547829772 18.2618841625459254, 233.5705679155844336 18.2318918456861674, 233.5766138328914394 18.2018827384108697, 233.5826686372002428 18.1718779111117286, 233.5888785936488432 18.1418635244059807, 233.5951383721327375 18.1118495698595829, 233.6014674713914019 18.0818342119676281, 233.6076764094576106 18.0518354029397550, 233.6140209223674447 18.0218522835348942, 233.6204423275639499 17.9918892523867555, 233.6265487122047375 17.9619613307537307, 233.6313515417370468 17.9321620036408724, 233.6386754118331623 17.9021295475461208, 233.6451980358386891 17.8721782134278229, 233.6513777074440270 17.8422646488141154, 233.6535623902091174 17.8127339294621407, 233.6609506865577828 17.7827168172390735, 233.6699594117104652 17.7525520608943062, 233.6710216303398511 17.7231431656523668, 233.6718987092317263 17.6937567665132818, 233.6886100264511015 17.6628813678102041, 233.6960663227023360 17.6328849764937026, 233.7026278411701696 17.6029784898318908, 233.7090592952019392 17.5730897219913338, 233.7159774810301656 17.5431605027643300, 233.7217275105666658 17.5133469216293491, 233.7187734896178881 17.4843590860856430, 233.7270853483592816 17.4543148473689627, 233.7331808847967238 17.4244650559017842, 233.7435127694119501 17.3942028951404559, 233.7536136123764550 17.3639679699225304, 233.7604356213903998 17.3340473252823202, 233.7671770100476181 17.3041397118946279, 233.7740217614510811 17.2742278149319262, 233.7808503086502583 17.2443229050392972, 233.7874669746069003 17.2144434060500267, 233.7940569940029150 17.1845718878380964, 233.8008596200677403 17.1546858578329271, 233.8077378287035799 17.1248364577722327, 233.8147908320279384 17.0950124866517008, 233.8216472061115496 17.0652127325247527, 233.8287550488172997 17.0353950862872061, 233.8358236301640147 17.0055868895558788, 233.8429318876114280 16.9757807353721617, 233.8498250513235348 16.9460005561536065, 233.8567982136574130 16.9162186517835664, 233.8644027751852263 16.8863833032129627, 233.8717789030441736 16.8565752238198172, 233.8787743155450869 16.8267903345429843, 233.8864271812514346 16.7969322128191187, 233.8943020020596748 16.7670590848810335, 233.9020234295209661 16.7372061476229561, 233.9097388861925424 16.7073595931650267, 233.9174310488908475 16.6775210529157718, 233.9253368298226405 16.6476683527042368, 233.9331359103080388 16.6178315076893384, 233.9401620368684860 16.5880728789070986, 233.9480199084255219 16.5582422694894404, 233.9556240340308193 16.5284143707426239, 233.9629611951967263 16.4985917371493827, 233.9680858443129523 16.4689817308657247, 233.9697189392310293 16.4397036867625950, 233.9810825587126999 16.4095219192687409, 233.9908561410638583 16.3794945960977181, 233.9882558493688407 16.3506288802557158, 234.0070396851330088 16.3197717513132687, 234.0069713596252257 16.2906809733634645, 234.0202313686372690 16.2603515811765043, 234.0396206151059175 16.2294769327835269, 234.0450716390547257 16.1999297991625184, 234.0561919768812231 16.1698594103722328, 234.0658256080933484 16.1399339059125637, 234.0741862230366053 16.1101332895480986, 234.0828109349569388 16.0803141029273959, 234.0913423001478861 16.0505097118435671, 234.0998453011710581 16.0207140639358840, 234.1085331389405724 15.9909072930984184, 234.1171059035083317 15.9611173752930284, 234.1257060288378398 15.9313287300367410, 234.1339610710348325 15.9015761555191926, 234.1421311326384966 15.8718375959232461, 234.1504002194577083 15.8420959238435071, 234.1587546085733038 15.8123524373627689, 234.1674495379575944 15.7825834029317171, 234.1763947301172379 15.7527972553046673, 234.1849920604829549 15.7230496510434978, 234.1933783950208010 15.6933278489870141, 234.2016682323672399 15.6636212039726974, 234.2106661097371330 15.6338573919411754, 234.2195850300125812 15.6041094923900445, 234.2284696625345362 15.5743710696477020, 234.2372546655175825 15.5446481978355635, 234.2462970033934653 15.5149077482144548, 234.2553563453492700 15.4851720525691974, 234.2644515611109171 15.4554393745744640, 234.2736445746276672 15.4257039865255372, 234.2828900285930445 15.3959701114112715, 234.2920854371643600 15.3662472678846918, 234.3013275319601121 15.3365240160720102, 234.3104684925448282 15.3068141675627576, 234.3196567184559171 15.2771063205312636, 234.3288051980732121 15.2474085454701420, 234.3378564288254040 15.2177261763429676, 234.3470450329756147 15.1880375021932217, 234.3562524198230790 15.1583535186594638, 234.3654777340127566 15.1286743193465885, 234.3747378383685600 15.0989983562836780, 234.3840812970269099 15.0693211572941888, 234.3931289741022397 15.0396512747805424, 234.4024907287820838 15.0099336756868436, 234.4122604228975320 14.9801847782135837, 234.4219977290714496 14.9504452810051323, 234.4316158209413175 14.9207232126728684, 234.4409823334430314 14.8910307928157444, 234.4498350286750110 14.8613922148236579, 234.4587414390796880 14.8317550981146464, 234.4679675142334077 14.8020949297871471, 234.4770902761938487 14.7724507458019882, 234.4864736837242276 14.7428161287315724, 234.4957933007898987 14.7132196608638868, 234.5055218334094320 14.6835921627047021, 234.5149128953590321 14.6540024086710705, 234.5240841556149007 14.6244395506431939, 234.5338855759494265 14.5948253658854963, 234.5441277226521208 14.5651773496976809, 234.5546148319625388 14.5355135559399802, 234.5650071680218787 14.5058652497170044, 234.5754239649154727 14.4762214794163899, 234.5860298977281388 14.4465631054023973, 234.5967350007561549 14.4168986450669667, 234.6069521162467595 14.3872858480204027, 234.6171532254527108 14.3576813563411001, 234.6275466840538684 14.3280660629932619, 234.6379311549196132 14.2984584660047549, 234.6483279323177840 14.2688566256103471, 234.6586953208047248 14.2392643795011899, 234.6688702844758154 14.2096966780773801, 234.6792465114648394 14.1801174490024717, 234.6895268513892461 14.1505511408581999, 234.6998289448953869 14.1209871012067207, 234.7101500394397249 14.0914282330706850, 234.7207265989751477 14.0618529129046621, 234.7321276646645174 14.0322091287124753, 234.7421715987841822 14.0026964529921525, 234.7518848038956207 13.9732209508361525, 234.7623775574045908 13.9436811555426505, 234.7730116684240329 13.9141354451606869, 234.7836780932641432 13.8845938046600299, 234.7943396384987409 13.8550596462965867, 234.8051586487551106 13.8255181701178120, 234.8160814495536499 13.7959742975977520, 234.8270783532049677 13.7664307564641781, 234.8381481281384708 13.7368876812022336, 234.8493417347459626 13.7073404461621493, 234.8606864116887891 13.6777865960779810, 234.8720570722587695 13.6482375497503181, 234.8830833189579153 13.6187270373040779, 234.8942578953382849 13.5892102038194746, 234.9053801461334103 13.5596778327200713, 234.9167589090509409 13.5301032210258434, 234.9279630753756862 13.5005515901187998, 234.9394192259657075 13.4709841685230565, 234.9508887087120570 13.4414226749875407, 234.9626309708700092 13.4118435574707444, 234.9742477492847001 13.3822830146718683, 234.9858310012523361 13.3527327037391963, 234.9970791621786645 13.3232199972591179, 235.0084942258517060 13.2936993449303262, 235.0186419320547770 13.2643038493261933, 235.0288272435886654 13.2349149251491429, 235.0401198038483130 13.2054328062422535, 235.0532620142338942 13.1757903601525115, 235.0624271207734637 13.1465153770093188, 235.0713600064045181 13.1172684942958018, 235.0793940337581773 13.0881099968979449, 235.0890500815441442 13.0588118576902463, 235.1001302405501292 13.0293921653006670, 235.1114135822560058 12.9999613922397987, 235.1209243695386135 12.9707237606482622, 235.1309020897631967 12.9414756651344671, 235.1414756816764111 12.9121812018778357, 235.1521051678167282 12.8828891503746874, 235.1634486045849428 12.8535402164776311, 235.1748378334555696 12.8241946968538798, 235.1866932396247023 12.7948147508486230, 235.1962591085319332 12.7656485146804908, 235.2079865863656210 12.7362952189512431, 235.2197326745993564 12.7069478740712292, 235.2313225714797227 12.6776155785111655, 235.2423722895124456 12.6483331654411657, 235.2530634947058275 12.6190905340401507, 235.2639518184354870 12.5898377702199067, 235.2744025913661972 12.5606318600724833, 235.2867725902066240 12.5312613935276893, 235.2991023661358554 12.5019022719193416, 235.3116716233483317 12.4725294411014680, 235.3219926188672559 12.4433657659187435, 235.3334198864922939 12.4141106633753413, 235.3448295691033252 12.3848381641287766, 235.3590631815229699 12.3552954059736244, 235.3671572189190329 12.3263093688257435, 235.3791241623066526 12.2969845357516654, 235.3921032498335251 12.2675769255236968, 235.4040318790397635 12.2382708372973283, 235.4133898124759412 12.2092018441388941, 235.4233087209120754 12.1800902645324154, 235.4339080982001633 12.1509255317515059, 235.4452235714741732 12.1217045744836511, 235.4567443232773485 12.0924703557183673, 235.4687492488390603 12.0631982531233284, 235.4810288736117343 12.0339094861732558, 235.4933593765949809 12.0046240088453988, 235.5055131845066398 11.9753620783452046, 235.5183936065197372 11.9460434002548155, 235.5313914411344456 11.9167221953183766, 235.5445277549280831 11.8873966213114510, 235.5579758498066951 11.8580513221761468, 235.5708596306864138 11.8287640872622291, 235.5855568213401057 11.7993272975650001, 235.5997530464832153 11.7699461618724968, 235.6118792697535014 11.7407565433221990, 235.6222863798969911 11.7117271087385006, 235.6370065829994473 11.6823236091034826, 235.6501351704513638 11.6530691110666691, 235.6620788997951479 11.6239274594960467, 235.6746660023580091 11.5947368831364361, 235.6884231603173134 11.5654509339622127, 235.7004295445095465 11.5363277616853921, 235.7116587816107085 11.5072743978115124, 235.7235065834900070 11.4781679472531284, 235.7365096550366843 11.4489676032006518, 235.7509681343241255 11.4196470655214046, 235.7663406602953842 11.3902542183865680, 235.7777363714225487 11.3612199442138877, 235.7886739885624081 11.3322339874387712, 235.8008113264958752 11.3031504556224576, 235.8129270658486121 11.2740769145439135, 235.8254455463137447 11.2449760862040176, 235.8379734894969602 11.2159103138021745, 235.8515159915447725 11.1867900343017315, 235.8657944078324533 11.1576136472878034, 235.8797318094723323 11.1284757052297838, 235.8937716656566295 11.0993373101821948, 235.9083287918834912 11.0701621525964011, 235.9230551242763454 11.0409807942013884, 235.9376740007390367 11.0118174850440660, 235.9515272763334792 10.9827297851711894, 235.9638445602315073 10.9537849358168433, 235.9770623676747050 10.9247485593648115, 235.9907218608971675 10.8956618895965978, 236.0047319410548710 10.8665530900764757, 236.0183309333028205 10.8374886511489024, 236.0323861690051217 10.8083929297519816, 236.0537151650576106 10.7647439316584101, 235.8067955133562918 10.7864349997890745, 235.6404746257549050 10.8009251269224666, 235.4886934161562522 10.8140812538426001, 235.3440743681632910 10.8265506526397761, 235.2013541677872581 10.8387871303979466, 235.0605785760558319 10.8507895528866278, 234.9266644391591967 10.8621511165544629, 234.7983134326682091 10.8729887160327809, 234.6742684848875911 10.8834132357187165, 234.5539738435557524 10.8934756928844916, 234.4326844057642347 10.9035680020157439, 234.3062264801245078 10.9140277809663289, 234.1842183967321489 10.9240715931274881, 234.0687460570583767 10.9335373293069242, 233.9561439769058779 10.9427259417912897, 233.8474210956630941 10.9515604135292630, 233.7435151522079764 10.9599707574291010, 233.6385624025285779 10.9684248104055762, 233.5358140067684758 10.9766660933000040, 233.4407131631531342 10.9842712723458433, 233.3422237141446089 10.9921074822156939, 233.2513957968607770 10.9993144684110025, 233.1514470230774236 11.0071956760767744, 233.0568672341267700 11.0146280042103317, 232.9714593141206933 11.0213255319050134, 232.8803341230172634 11.0284323244548670, 232.7943082344645234 11.0351214682081267, 232.7094524258487809 11.0416948896581584, 232.6269891539108698 11.0480614832231296, 232.5469229652644003 11.0542229776369414, 232.4651981313369333 11.0604848215878420, 232.3872682244125372 11.0664391550579371, 232.3089820002455212 11.0723973916104068, 232.2344266808471787 11.0780568263891777, 232.1612777882611454 11.0835918116323047, 232.0879579900140470 11.0891193379889472, 232.0165771813887829 11.0944847829273954, 231.9444953164244225 11.0998822668698853, 231.8732154220784025 11.1052019606563341, 231.8057772059842137 11.1102241836769391, 231.7386284223711357 11.1152083218847455, 231.6726527935735476 11.1200909547501503, 231.6064561948248581 11.1249729598940039, 231.5413069011224252 11.1297634611436891, 231.4780838222075090 11.1344005203999075, 231.4150219500249648 11.1390109034253282, 231.3534789037249766 11.1434985250687841, 231.2922763752978028 11.1479476252960801, 231.2321986804804794 11.1523031971319337, 231.1727759778428037 11.1565989553883913, 231.1144830584675276 11.1608020872514313, 231.0567419751282898 11.1649536385302959, 231.0002949603130560 11.1690023089595822, 230.9442330255996012 11.1730119569343636, 230.8887529573796940 11.1769692032438535, 230.8340953656556849 11.1808578017260682, 230.7801047938849308 11.1846889342734368, 230.7267933250105045 11.1884621644695308, 230.6741394301091361 11.1921793597281169, 230.6222024977036256 11.1958368476612193, 230.5710284673361059 11.1994319110143277, 230.5203688901636383 11.2029818304628161, 230.4702850162541097 11.2064827482238254, 230.4211332149626514 11.2099109379551614, 230.3722347960806189 11.2133125718895528, 230.3238995148835784 11.2166669987468914, 230.2759727552658831 11.2199848672525331, 230.2288337046632591 11.2232410798017437, 230.1821784107610824 11.2264562859122705, 230.1360978920992295 11.2296246903222858, 230.0904502464934467 11.2327559867974252, 230.0451126661331216 11.2358585089279455, 230.0005121694859724 11.2389042679665572, 229.9563201538430519 11.2419152341142556, 229.9126038169200399 11.2448872011781855, 229.8693914420420299 11.2478185506001704, 229.8266141936523184 11.2507140176866294, 229.7844926752366916 11.2535594487218482, 229.7426279584758220 11.2563810618782654, 229.7011060076215756 11.2591734075647345, 229.6601354388773188 11.2619231614147370, 229.6197463420439533 11.2646286372140843, 229.5797488137789628 11.2673023162466013, 229.5399124326933133 11.2699591633018610, 229.5003744155729350 11.2725904639326817, 229.4613780020150386 11.2751808122651163, 229.4229479289658684 11.2777288707496979, 229.3846678777049135 11.2802613604144675, 229.3465203971843209 11.2827794526095389, 229.3092627460586925 11.2852352682155725, 229.2721541795518476 11.2876759727222726, 229.2355028971691127 11.2900822055293482, 229.1990236077021166 11.2924720971991874, 229.1627789235925547 11.2948417900818434, 229.1268004674420808 11.2971894009668841, 229.0910977852267649 11.2995144425208274, 229.0558429789198271 11.3018062999761106, 229.0210984390745352 11.3040612741786060, 228.9866394069139233 11.3062935182293387, 228.9523786369051948 11.3085085479038057, 228.9184628476472199 11.3106973739286527, 228.8847576778029236 11.3128684166009155, 228.8514037966496630 11.3150131009844550, 228.8184344402529860 11.3171295215195844, 228.7856962146676381 11.3192272249858732, 228.7530968391201327 11.3213119416410706, 228.7207523182538011 11.3233766438682970, 228.6886580791888548 11.3254217054343140, 228.6568808000468778 11.3274431670293065, 228.6255699416117011 11.3294320811030538, 228.5943557727714790 11.3314109976706181, 228.5633199203958270 11.3333750202067787, 228.5325366678410148 11.3353197346958279, 228.5019329259168614 11.3372496289070188, 228.4715394680731606 11.3391629188288920, 228.4413945509302266 11.3410573865418609, 228.4114629408679491 11.3429352267224708, 228.3817510016923791 11.3447961341414132, 228.3522475214008693 11.3466408530271430, 228.3230615139313500 11.3484629748790802, 228.2940740736262910 11.3502696640891205, 228.2653336387764398 11.3520581199518507, 228.2367430860684010 11.3538341663080313, 228.2082916103083221 11.3555984904766412, 228.1800368130793402 11.3573477475009152, 228.1520392237875967 11.3590784464209342, 228.1243947354929844 11.3607850493464380, 228.0969443603398190 11.3624769794781848, 228.0696393456295255 11.3641571482644714, 228.0424929933010674 11.3658248267683568, 228.0154106641673479 11.3674855738926137, 227.9885578563481090 11.3691297953353860, 227.9618650794203916 11.3707615940505704, 227.9353348111912396 11.3723808773608184, 227.9089933044639338 11.3739861801390099, 227.8828228745905733 11.3755785815541994, 227.8568634996864830 11.3771558345525570, 227.8309964239465444 11.3787248265649747, 227.8053094676684509 11.3802805503758560, 227.7797848238544418 11.3818240807472488, 227.7544332388526129 11.3833548536377425, 227.7292690741705030 11.3848721031830866, 227.7042771343951131 11.3863767513912482, 227.6794424865351800 11.3878696987312154, 227.6547547108986294 11.3893515833046521, 227.6302153125810150 11.3908223637586836, 227.6058446822487724 11.3922809322129392, 227.5815837284553709 11.3937306712760567, 227.5574768187678671 11.3951691152893577, 227.5335303503320290 11.3965959501297078, 227.5097275399109833 11.3980121642247632, 227.4860553007756891 11.3994185320559449, 227.4625029322769194 11.4008156893181010, 227.4390700032307677 11.4022036943794802, 227.4157514915798401 11.4035828609687275, 227.3925662525225277 11.4049521734577688, 227.3695676411404634 11.4063087093438345, 227.3466880305276732 11.4076562680175844, 227.3239817936694465 11.4089918766877361, 227.3013618133047657 11.4103203927839996, 227.2788626998101620 11.4116399330742162, 227.2564905837951414 11.4129501940545595, 227.2341471861246589 11.4142566063190998, 227.2119503831800671 11.4155527167828215, 227.1898755316235281 11.4168399144063599, 227.1679212759821098 11.4181183068057468, 227.1461045130937180 11.4193870060476002, 227.1244248889418884 11.4206460692728200, 227.1028554367262871 11.4218969988970223, 227.0813921445934511 11.4231400422407976, 227.0600099683260851 11.4243765834220206, 227.0387800565269458 11.4256027995308020, 227.0176858866700798 11.4268196232913724, 226.9967364182923575 11.4280266090250606, 226.9758565799991175 11.4292278308048427, 226.9550385935661438 11.4304237238046955, 226.9342329016709527 11.4316169579053160, 226.9135052379866693 11.4328040202277581, 226.8929749480163025 11.4339785612803286, 226.8725374557903933 11.4351462062810594, 226.8522123581975904 11.4363059371368614, 226.8319968195319518 11.4374579339902080, 226.8118864201212830 11.4386024598112943, 226.7918595656044261 11.4397406845203591, 226.7719343835057941 11.4408716721278090, 226.7520928931478466 11.4419963969853455, 226.7323585007384281 11.4431136486025746, 226.7126918304146841 11.4442255234732162, 226.6930802682913395 11.4453327000192520, 226.6735784057233900 11.4464323335893088, 226.6541678320585618 11.4475254147592338, 226.6348499723003442 11.4486118924843758, 226.6156086420497218 11.4496926332811135, 226.5964513089176933 11.4507672681177564, 226.5773802830670434 11.4518356983188632, 226.5583938982732661 11.4528980320230023, 226.5394514986686545 11.4539563930335220, 226.5205720112754193 11.4550098145010288, 226.5017744116908602 11.4560573339612244, 226.4830830479979795 11.4570977194829062, 226.4644630477073406 11.4581327889146110, 226.4458929607677931 11.4591636593943669, 226.4273420018058687 11.4601919179165428, 226.4089327375767766 11.4612113075362014, 226.3905321797895454 11.4622286455691960, 226.3721760724194212 11.4632421133368112, 226.3540415653064031 11.4642427211329796, 226.3361333516311902 11.4652302892907620, 226.3181669859138481 11.4662192771337370, 226.3002739486506414 11.4672030229303150, 226.2824320913041447 11.4681826620260043, 226.2646422367273829 11.4691581650756813, 226.2469095834710231 11.4701292830936161, 226.2292344049313613 11.4710960160787412, 226.2116353879809196 11.4720574419513905, 226.1941018513785195 11.4730141135446058, 226.1766306716312727 11.4739662026907254, 226.1592231105851738 11.4749136616605600, 226.1418925461004221 11.4758558407877338, 226.1246140672749334 11.4767939954809552, 226.1074024905080080 11.4777274041137787, 226.0902695214729761 11.4786555042624911, 226.0731674626638892 11.4795806696773699, 226.0561148944823913 11.4805019915790982, 226.0391203976545000 11.4814190596774139, 226.0221853383609414 11.4823318209273602, 226.0053302814410472 11.4832392822302296, 225.9885536989861521 11.4841415383497054, 225.9718003975521015 11.4850413028381251, 225.9550662527160227 11.4859387811263272, 225.9383869128336073 11.4868322431797392, 225.9217536701517588 11.4877221247833088, 225.9051656781826694 11.4886084777220994, 225.8886411839913251 11.4894904303538112, 225.8721818201436236 11.4903679195340374, 225.8557774564195881 11.4912414492684523, 225.8394241488462342 11.4921112224597586, 225.8231345766302809 11.4929766430547815, 225.8068834000255265 11.4938389401884038, 225.7906841315510178 11.4946974768467598, 225.7745264906764078 11.4955527558965223, 225.7584156584574941 11.4964045403774655, 225.7423465946611998 11.4972530808697773, 225.7263306551080575 11.4980978487034413, 225.7103637501312221 11.4989390503598727, 225.6944403535995036 11.4997769586268923, 225.6785731333571050 11.5006109868028865, 225.6627606321937378 11.5014412173606573, 225.6469855377227418 11.5022684764026728, 225.6312478555471159 11.5030927722663776, 225.6155505187072094 11.5039139764720364, 225.5999034371527046 11.5047316362642942, 225.5843036923893692 11.5055458998858171, 225.5687372937127009 11.5063574287637689, 225.5532030184862720 11.5071662870658162, 225.5377227249349801 11.5079714709681884, 225.5222898787807537 11.5087732956897497, 225.5069090090448185 11.5095715644164116, 225.4915549235061576 11.5103674479623646, 225.4762447625155630 11.5111601660448812, 225.4609749326394876 11.5119498938921581, 225.4457365038286696 11.5127370489375576, 225.4305250723075176 11.5135218388493641, 225.4153505895338014 11.5143038171213359, 225.4002092546284359 11.5150831649119514, 225.3851016085638150 11.5158598654166955, 225.3700330195549384 11.5166336842014942, 225.3550142447406586 11.5174041464428125, 225.3400350352184205 11.5181717255856153, 225.3250842761325714 11.5189369296322024, 225.3101705090110158 11.5196993830200647, 225.2952945149411903 11.5204590600189825, 225.2804449879828610 11.5212164731226459, 225.2656236019600158 11.5219715538163481, 225.2508347977898495 11.5227241118038251, 225.2360836991653628 11.5234739286072880, 225.2213701223723774 11.5242210218960768, 225.2066922232504851 11.5249654822953609, 225.1920523314319951 11.5257072167190113, 225.1774439551024329 11.5264465188783944, 225.1628688639239897 11.5271833193508328, 225.1483231609231552 11.5279177960269053, 225.1338080113099807 11.5286499054819824, 225.1193156868255869 11.5293799895936147, 225.1048406914377722 11.5301082903483749, 225.0903927203169417 11.5308343935948976, 225.0759731997245012 11.5315582445592408, 225.0615726061136002 11.5322802576213750, 225.0471948914249083 11.5330002677360390, 225.0328448252998612 11.5337180770247585, 225.0185250472492839 11.5344335803454978, 225.0042336758090187 11.5351468651000371, 224.9899666840133534 11.5358581082564022, 224.9757293128520246 11.5365670952889214, 224.9615188349451955 11.5372739482831097, 224.9473343603615376 11.5379787112424026, 224.9331867189993375 11.5386809398550962, 224.9190651590855339 11.5393810912804309, 224.9049589851288147 11.5400796146826767, 224.8908763596490132 11.5407761760249503, 224.8768203267520391 11.5414706560850604, 224.8627911626610114 11.5421630507503572, 224.8487873231403000 11.5428534304463426, 224.8348025935591181 11.5435420547040781, 224.8208432662325720 11.5442286728549526, 224.8069064464880853 11.5449134088086414, 224.7929952890946197 11.5455961415900230, 224.7790961745715776 11.5462774242074886, 224.7652157298564077 11.5469569934464307, 224.7513584997161331 11.5476346729728920, 224.7375268209599426 11.5483103768095692, 224.7237220902749186 11.5489840576781049, 224.7099413765578788 11.5496558393060678, 224.6961637810832997 11.5503265461398499, 224.6824171483842463 11.5509950911857651, 224.6686890557816412 11.5516619670139438, 224.6549772382032870 11.5523272659126732, 224.6412812909752574 11.5529910072087638, 224.6276091034430635 11.5536528929961193, 224.6139594562434354 11.5543129777076103, 224.6003182497858006 11.5549718025661790, 224.5867005368061768 11.5556288004452163, 224.5731010661888547 11.5562841764879369, 224.5595318451174194 11.5569374888469998, 224.5459817047643298 11.5575891644451580, 224.5324427190798815 11.5582395019069590, 224.5189143401576359 11.5588885230225653, 224.5054022183505253 11.5595360233582785, 224.4919123846902949 11.5601817896909882, 224.4784375362918638 11.5608260941027616, 224.4649757674625334 11.5614690093643926, 224.4515271517104509 11.5621105363191763, 224.4380954082653261 11.5627505474210590, 224.4246791510040566 11.5633890977002647, 224.4112755960885579 11.5640262896198038, 224.3978846737749677 11.5646621293277576, 224.3845066428580992 11.5652966117857332, 224.3711457528072515 11.5659295968898927, 224.3577977362114098 11.5665612362847945, 224.3444652819509599 11.5671914448426545, 224.3311485458355321 11.5678202246618902, 224.3178463670823248 11.5684476215481666, 224.3045557510947106 11.5690737397450363, 224.2912636805589273 11.5696990018417232, 224.2779812886721800 11.5703230455083013, 224.2647169075775651 11.5709456114698312, 224.2514653724537084 11.5715668719248761, 224.2382246445113196 11.5721868961343315, 224.2249954647936079 11.5728056663857917, 224.2117774258863392 11.5734232007857401, 224.1985677641189909 11.5740395865862702, 224.1853739310522826 11.5746546100326633, 224.1721921301367502 11.5752683925175557, 224.1590180429048473 11.5758810639248129, 224.1458517540414732 11.5764926247077877, 224.1326993443369702 11.5771029132241079, 224.1195552562867022 11.5777120902351882, 224.1064199000637984 11.5783201500287358, 224.0932922280786954 11.5789271253157224, 224.0801718772106028 11.5795330298010377, 224.0670575303311693 11.5801378996871751, 224.0539473086338944 11.5807417811292535, 224.0408440714013807 11.5813446074145912, 224.0277532395568016 11.5819462641689164, 224.0146726415863156 11.5825468155354798, 224.0016005777064834 11.5831463107815456, 223.9885357303068645 11.5837447873712964, 223.9754767473346249 11.5843422797721392, 223.9624200726210574 11.5849388562089182, 223.9493664901763452 11.5855344995887322, 223.9363221822940204 11.5861291150833985, 223.9232837412836545 11.5867227707854603, 223.9102514687331791 11.5873154735646100, 223.8972278339569755 11.5879072106724532, 223.8842074228040815 11.5884980596409797, 223.8711897945744056 11.5890880278296748, 223.8581768384303530 11.5896771077336158, 223.8451691054746391 11.5902653131262348, 223.8321650096247595 11.5908526677192896, 223.8191624724294400 11.5914391819224214, 223.8061618009816982 11.5920248568798332, 223.7931629563942124 11.5926096948298980, 223.7801640483884000 11.5931936738872050, 223.7671670080404738 11.5937768052707177, 223.7541730621465206 11.5943591186183355, 223.7411823205447945 11.5949406428819639, 223.7281945822350337 11.5955214095179322, 223.7152092203544385 11.5961014400467324, 223.7022255713048651 11.5966807498982512, 223.6892422590746605 11.5972592901497755, 223.6762589726454564 11.5978370356977827, 223.6632763821540379 11.5984140565029339, 223.6502941596612857 11.5989903554735552, 223.6373122485578335 11.5995659928018640, 223.6243300457994962 11.6001409101370658, 223.6113474183802055 11.6007150945084003, 223.5983643014758400 11.6012885646784696, 223.5853804742061470 11.6018613807905986, 223.5723949789524738 11.6024337740613070, 223.5594084415180305 11.6030053638277604, 223.5464202437128449 11.6035763342790688, 223.5334298265300106 11.6041467476564506, 223.5204368671151371 11.6047166055491360, 223.5074413311777732 11.6052858741608844, 223.4944432982260878 11.6058545207539812, 223.4814424785570282 11.6064225703277106, 223.4684383277615609 11.6069900726994284, 223.4554303426207014 11.6075570640144381, 223.4424179562216466 11.6081235823802729, 223.4294005333650261 11.6086896685705749, 223.4163767564448335 11.6092554251278610, 223.4033493491632782 11.6098205677991153, 223.3903182963025813 11.6103850983762680, 223.3772834961584977 11.6109490258485462, 223.3642450371687289 11.6115123420402675, 223.3512033206641831 11.6120750138095037, 223.3381552833168939 11.6126372900905022, 223.3251009602240629 11.6131991535604495, 223.3120397912722694 11.6137606354717011, 223.2989722102144583 11.6143216904755171, 223.2858985034930583 11.6148822884616827, 223.2728171532845636 11.6154425337012217, 223.2597285678833714 11.6160023858956460, 223.2466317184563422 11.6165619095860269, 223.2335277664742250 11.6171210135472638, 223.2204169764052324 11.6176796739022219, 223.2072988293887477 11.6182379214719891, 223.1941722853877934 11.6187958206584732, 223.1810361052811231 11.6193534462392414, 223.1678913125285533 11.6199107220438567, 223.1547381380195532 11.6204676270151754, 223.1415754377214569 11.6210242292760277, 223.1284015147909088 11.6215806294669566, 223.1152151257165031 11.6221368962333464, 223.1020209030151591 11.6226927309393702, 223.0888180899143265 11.6232481781277563, 223.0756052319343894 11.6238033234461149, 223.0623811454720169 11.6243582333811339, 223.0491451294242324 11.6249129434947029, 223.0358968024115143 11.6254674694465940, 223.0226367869014155 11.6260217673261099, 223.0093615337405595 11.6265760397115319, 222.9960678207878289 11.6271304645774993, 222.9827655838388409 11.6276844535504686, 222.9694554206592443 11.6282379715212940, 222.9561342545880791 11.6287911941992874, 222.9427998983100281 11.6293442422904629, 222.9294510268497618 11.6298971849420401, 222.9160884180228379 11.6304499718435075, 222.9027074603658320 11.6310028545879973, 222.8893176033846544 11.6315552994956750, 222.8759211426458364 11.6321071794923281, 222.8625124070450170 11.6326588071240913, 222.8490832134943105 11.6332106252390162, 222.8356348319159679 11.6337625545310193, 222.8221730868960435 11.6343142716203864, 222.8086998368628429 11.6348656728460096, 222.7952032410204595 11.6354173891255144, 222.7816844858264176 11.6359693461022591, 222.7681514532162907 11.6365211163933147, 222.7546094596874582 11.6370724158921028, 222.7410496054532985 11.6376237118726849, 222.7274689117783737 11.6381751538626546, 222.7138741945792617 11.6387263791939706, 222.7002655263075610 11.6392773809061207, 222.6866375324841840 11.6398284332340385, 222.6729866912269813 11.6403797107135620, 222.6593141329908860 11.6409311470154808, 222.6456207319734517 11.6414826900451747, 222.6319141538503459 11.6420339437049947, 222.6181898888893045 11.6425851339993081, 222.6044497077721189 11.6431361669500131, 222.5906859946134375 11.6436874213117392, 222.5768997746839659 11.6442388379762196, 222.5630916264516372 11.6447903810373106, 222.5492639055905215 11.6453419268843490, 222.5354268513513034 11.6458929634969479, 222.5215672763436032 11.6464441414374651, 222.5076782329797993 11.6469957955481860, 222.4937638625373211 11.6475477129612379, 222.4798292363327619 11.6480996383395325, 222.4658732608350817 11.6486516197575565, 222.4519005455341585 11.6492034280487893, 222.4379138599454393 11.6497549259658353, 222.4239108831781380 11.6503062232925174, 222.4098822394056754 11.6508577672794100, 222.3958278149365810 11.6514095559922719, 222.3817501135733607 11.6519614625816654, 222.3676471868176634 11.6525135736721577, 222.3535187113662914 11.6530658977189212, 222.3393601721830919 11.6536186413768217, 222.3251663416662041 11.6541720424480708, 222.3109466623485559 11.6547256460647510, 222.2967040816845383 11.6552793072737142, 222.2824345096863681 11.6558332118137340, 222.2681376654342955 11.6563873656892198, 222.2537934125679442 11.6569426977978026, 222.2394296278611137 11.6574979009509132, 222.2250456168251276 11.6580530033632179, 222.2106332312139614 11.6586083764543140, 222.1961901634210790 11.6591641190119333, 222.1817259895384495 11.6597197839798365, 222.1672323459239919 11.6602757492673135, 222.1527060469091452 11.6608321525715173, 222.1381498752822381 11.6613888587151209, 222.1235645886078771 11.6619458257867201, 222.1089488152713898 11.6625031085844739, 222.0943054474923883 11.6630605689785227, 222.0796369850662870 11.6636180879175448, 222.0649326370137260 11.6641761438836671, 222.0501916741791320 11.6647347600561417, 222.0354200415976607 11.6652936614482083, 222.0206255050637481 11.6658524948229125, 222.0058055009189957 11.6664113692121774, 221.9909317003400986 11.6669715336748272, 221.9760187813593575 11.6675323245008205, 221.9610674740678178 11.6680936993382627, 221.9460834295299492 11.6686553999180322, 221.9310575638693024 11.6692178165951645, 221.9159984711464233 11.6697805626031919, 221.9009259266182426 11.6703427671831417, 221.8858296896012519 11.6709048744380794, 221.8706995944909295 11.6714673207546387, 221.8555326260521667 11.6720302285182029, 221.8403304885907517 11.6725935149842552, 221.8250972499780858 11.6731569963145798, 221.8098195614849146 11.6737212391111864, 221.7944889260287198 11.6742865963530384, 221.7791202134376647 11.6748524179258073, 221.7637180402751653 11.6754184975181445, 221.7482700456498321 11.6759853535227798, 221.7327669514012030 11.6765533683532645, 221.7172115229149085 11.6771224104259019, 221.7016211571622364 11.6776917309401611, 221.6860028019623599 11.6782610287884925, 221.6703447482998399 11.6788307904525208, 221.6546244431601451 11.6794019527549224, 221.6388611839099951 11.6799736915289696, 221.6230487052656883 11.6805462579599428, 221.6071946734351457 11.6811193203291648, 221.5913075585570766 11.6816925165768932, 221.5753864703937950 11.6822658761466585, 221.5594131535227973 11.6828401465026861, 221.5433904492085446 11.6834151972955773, 221.5273308964312662 11.6839905000419062, 221.5112244756874702 11.6845664577698987, 221.4950649900496273 11.6851433129840245, 221.4788646116655002 11.6857205548552301, 221.4626020103548569 11.6862990436845795, 221.4462705120642738 11.6868790352296799, 221.4298859924444685 11.6874598673674512, 221.4134506856227631 11.6880414365501029, 221.3969754781630286 11.6886232905391090, 221.3804605137580950 11.6892054142711981, 221.3638996850384331 11.6897880441024036, 221.3472772159424551 11.6903718019422342, 221.3305813530331534 11.6909571427404071, 221.3137711140890929 11.6915456840148959, 221.2969116219956334 11.6921348014644710, 221.2800176036289201 11.6927238980664523, 221.2630934336351345 11.6933127927512892, 221.2461192125688001 11.6939022660947209, 221.2290863538791825 11.6944926448374797, 221.2119945040117273 11.6950839284474739, 221.1948675705588698 11.6956751636056886, 221.1776935519540359 11.6962668126450478, 221.1604303534508347 11.6968605094593201, 221.1430823375198713 11.6974560609985421, 221.1256729793842624 11.6980525325018565, 221.1082343240075829 11.6986486654835620, 221.0907777951840103 11.6992440115853782, 221.0732731529905379 11.6998397354871226, 221.0556760649134560 11.7004375334853208, 221.0379809653511245 11.7010375956553805, 221.0201910780052401 11.7016397730643700, 221.0023326505245791 11.7022430374960322, 220.9844141227260934 11.7028470498581818, 220.9664267865848046 11.7034521267778491, 220.9483618371737066 11.7040585853194123, 220.9302181846813085 11.7046664470968551, 220.9120117963100824 11.7052750889533552, 220.8937461626249217 11.7058843638380683, 220.8754296372306953 11.7064939431866915, 220.8570353831397597 11.7071048211080821, 220.8385387414589900 11.7077179002450720, 220.8199419597744964 11.7083330701137118, 220.8012542966671958 11.7089499601075602, 220.7824976140121294 11.7095677351636294, 220.7636932618528647 11.7101855873258351, 220.7448115762643397 11.7108046009476432, 220.7258449069571213 11.7114250382026341, 220.7067902066008855 11.7120469892192549, 220.6876435492166593 11.7126705751678788, 220.6684018412074693 11.7132958852828555, 220.6490775002795317 11.7139224419230334, 220.6296751617481959 11.7145500551708555, 220.6101884901048891 11.7151789348560165, 220.5906226553490228 11.7158088720504878, 220.5709709286416000 11.7164400891991463, 220.5512576667543385 11.7170716871744176, 220.5314614383957803 11.7177044199496585, 220.5115590022694505 11.7183390981715050, 220.4915452243125742 11.7189758769615562, 220.4714307799496567 11.7196143463289317, 220.4512468588935121 11.7202533715732269, 220.4309992066251311 11.7208927312610243, 220.4106498399640373 11.7215337511258380, 220.3901880983314356 11.7221767796033038, 220.3696269742773950 11.7228213298105359, 220.3489604038595360 11.7234675875962768, 220.3281690552250609 11.7241162000845698, 220.3072756756521926 11.7247663403802918, 220.2862824116052138 11.7254179062594428, 220.2651764715898821 11.7260713139578279, 220.2439627765912178 11.7267263625395923, 220.2226597862525637 11.7273823863475286, 220.2012604090777756 11.7280396048920075, 220.1797602368997104 11.7286981429012691, 220.1581417345539080 11.7293585718169098, 220.1364090861300156 11.7300207161521186, 220.1145235049643247 11.7306858616742762, 220.0924773395380214 11.7313542240955648, 220.0703026463924346 11.7320246749398347, 220.0480152578872435 11.7326966446454559, 220.0256193313570066 11.7333699618091121, 220.0031393234807240 11.7340437771874182, 219.9805459909590581 11.7347190432092230, 219.9578262375317195 11.7353961632534425, 219.9350228461180166 11.7360736819629690, 219.9120955538532201 11.7367529071512831, 219.8890352094778962 11.7374341046332837, 219.8658230573190906 11.7381178519633735, 219.8424378550888889 11.7388048002984284, 219.8189420393960916 11.7394928593078181, 219.7954051231398296 11.7401797339112850, 219.7717126788431301 11.7408691262396196, 219.7478364883703819 11.7415619025074367, 219.7238247217930223 11.7422564541995804, 219.6876080273489436 11.7432997520176716, 219.6987523783379856 11.7853029348258183, 219.7061791771063213 11.8133127052587579, 219.7135986549952520 11.8413287509520604, 219.7210947404886099 11.8693483800486117, 219.7285881728001300 11.8973741241781958, 219.7359476924907256 11.9254261184903658, 219.7433492070103682 11.9534995743589434, 219.7507477436034549 11.9815790420371595, 219.7579850993488151 12.0096695496526973, 219.7652250045894959 12.0377658721436891, 219.7725553247495327 12.0658652068473060, 219.7800022085723413 12.0939667193786544, 219.7873408945879987 12.1220775512080383, 219.7950743482600444 12.1501817176683833, 219.8021390085208395 12.1783129843083486, 219.8093731982236250 12.2064422366432606, 219.8167053718840123 12.2345716176753587, 219.8241449129442060 12.2627034586213366, 219.8313191007843272 12.2908495551188111, 219.8387108569059478 12.3189946084991693, 219.8460894153435277 12.3471459191465058, 219.8532640727768239 12.3753095044270260, 219.8601696000010008 12.4034874078262014, 219.8674454814815817 12.4316594206823421, 219.8745707847417350 12.4598419912327945, 219.8816850375779950 12.4880175631037620, 219.8889121190733533 12.5161815294953218, 219.8961929096689403 12.5443496532151979, 219.9035207112792421 12.5725221393741400, 219.9108000505651717 12.6007019865559382, 219.9180033534095458 12.6288900488054914, 219.9252926238032160 12.6570812286973613, 219.9325837931077388 12.6852781631490341, 219.9416672226408593 12.7134247385197341, 219.9543961129569709 12.7414629673091664, 219.9609663348926460 12.7696974746052021, 219.9637127244800467 12.7980546219476476, 219.9693396485585026 12.8263272759272802, 219.9763389820033410 12.8545627691681386, 219.9873479021010496 12.8826789123672079, 219.9942663403161589 12.9109285110434602, 220.0001191110418972 12.9392170377871576, 220.0060791740759782 12.9675078899464147, 220.0125259482794604 12.9957892678083056, 220.0204798708710712 13.0240294902412526, 220.0303293169093024 13.0522308973718140, 220.0363637763307167 13.0805716599938897, 220.0435221785276383 13.1088831468612099, 220.0503444747572246 13.1372106969061697, 220.0554559745506822 13.1655969103811366, 220.0637152729870536 13.1938911364857177, 220.0719544405739896 13.2221916259964836, 220.0809450262833025 13.2504744742211660, 220.0855198220701254 13.2788996751998667, 220.0951748736929972 13.3071731967088862, 220.1002723968982480 13.3355840088870234, 220.1073650534362116 13.3639288227772877, 220.1144815965231203 13.3922785024813376, 220.1215875627314631 13.4206341037762407, 220.1287352846985073 13.4489940062221862, 220.1370402478150368 13.4773238026688151, 220.1447839371536475 13.5056765103977678, 220.1521111758974030 13.5340476370338720, 220.1594759153635721 13.5624231738013652, 220.1672083183461552 13.5907929546773101, 220.1735074970197275 13.6191997958310775, 220.1797183181128901 13.6476015911061932, 220.1873653702023717 13.6759648320780922, 220.1929970821997813 13.7043955201351562, 220.2002836979509937 13.7327809783765140, 220.2072371134695743 13.7611822222090847, 220.2143098338185894 13.7895853680132241, 220.2215409215835393 13.8179892236932034, 220.2286146028019118 13.8464034430197227, 220.2359968999591047 13.8748137746859079, 220.2429905146004501 13.9032506380188714, 220.2501006641976744 13.9316990778372372, 220.2572072438011901 13.9601531118914952, 220.2642324533995293 13.9886151017755545, 220.2713546031071132 14.0170796063823371, 220.2784888315825071 14.0455492056894791, 220.2854618046474116 14.0740291667353770, 220.2923997653498702 14.1025156367929014, 220.2996432287141317 14.1309982528014721, 220.3069647400963618 14.1594839346048857, 220.3142063436781086 14.1879636486693368, 220.3212788516616740 14.2164393475970812, 220.3285570372971449 14.2449142697162650, 220.3357705557098143 14.2733966112673958, 220.3430038919728702 14.3018838043373773, 220.3501936696853534 14.3303777594724284, 220.3574521197704712 14.3588750715236415, 220.3646056907983279 14.3873809839935785, 220.3714125046764707 14.4159027845413714, 220.3785545330334230 14.4444198669506729, 220.3856337203785074 14.4729600246978425, 220.3927611377524443 14.5015207375727115, 220.4001050934609509 14.5300802439584995, 220.4070157681905755 14.5586581172829916, 220.4141741432308095 14.5872338303264470, 220.4213520871849141 14.6158142500114483, 220.4283400945614915 14.6444056727811667, 220.4351961118798897 14.6730063437207381, 220.4419879938532176 14.7016142082228836, 220.4491297929428981 14.7302168129408813, 220.4562863979076610 14.7588242338492606, 220.4632064462008714 14.7874440135878196, 220.4702124056549621 14.8160664517127358, 220.4773075834508518 14.8446914417330778, 220.4839436386864122 14.8733354359420797, 220.4909400903970891 14.9019738273440971, 220.4976830000881023 14.9306250291691622, 220.5046871348686750 14.9592735965149846, 220.5120298151077236 14.9879172093816528, 220.5191431519799039 15.0165728860575474, 220.5262490346293305 15.0452192621456238, 220.5332207140164940 15.0738593391698092, 220.5401179893821961 15.1025068648033898, 220.5471624568289997 15.1311551999620413, 220.5542495222690889 15.1598074720371745, 220.5611462413826018 15.1884706315084639, 220.5679511426332056 15.2171417190662979, 220.5747134505176632 15.2458192561080086, 220.5815516684503450 15.2744996976014562, 220.5883461731254158 15.3031866064603790, 220.5952718642558068 15.3318669232528322, 220.6021707513029355 15.3605449415493354, 220.6091175731324370 15.3892267260807749, 220.6161856753946608 15.4179100901230619, 220.6230988133779078 15.4466032396069970, 220.6301581991951366 15.4752972166398326, 220.6372147493088676 15.5039964428243273, 220.6444441173819655 15.5326957055445494, 220.6513662352306255 15.5614092260747814, 220.6584249247968899 15.5901238420788957, 220.6656150398821978 15.6188559149160788, 220.6725666950571849 15.6476172350376110, 220.6794748557452692 15.6763848777368988, 220.6865817603947448 15.7051516699670515, 220.6936357219268530 15.7339250504649613, 220.7007661075990370 15.7627011861934072, 220.7078723698223257 15.7914830405681883, 220.7148087277778075 15.8202749132805174, 220.7215739629539826 15.8490768264030795, 220.7283696406998104 15.8778828200969873, 220.7350802981803497 15.9066906070165093, 220.7416702149446905 15.9355009309045741, 220.7481918200303710 15.9643182514411706, 220.7548889450912384 15.9931353700775922, 220.7613380772242238 16.0219647647033696, 220.7677626895963670 16.0507998367200457, 220.7746364759823905 16.0796266326420181, 220.7812760232888820 16.1084652723297594, 220.7879783038013954 16.1373070026573373, 220.7945420931276601 16.1661577372383505, 220.8003749787557979 16.1950206146460012, 220.8065617770233189 16.2238629585585379, 220.8128621962586067 16.2527069130919699, 220.8191817783076658 16.2815552455657588, 220.8255725903351561 16.3104064260858941, 220.8322066932024370 16.3392554115519815, 220.8387268830610140 16.3681126611654655, 220.8455734890393387 16.3969652843257307, 220.8521103356239621 16.4258318846550431, 220.8587076065097108 16.4547016259001566, 220.8645847861091625 16.4836114738970672, 220.8712379212901737 16.5125184939384759, 220.8780366530769754 16.5414260976919820, 220.8844439642249711 16.5703499435244446, 220.8910779639868736 16.5992719914096050, 220.8980535532646172 16.6281888885597695, 220.9049801592676090 16.6571120172564306, 220.9120543712106723 16.6860356421274894, 220.9194018676946882 16.7149560938374471, 220.9275853959155995 16.7438569741192573, 220.9337514394953814 16.7728073784391292, 220.9389458502036803 16.8017760251284436, 220.9442633220138532 16.8307458475437457, 220.9495797699727007 16.8597204500586884, 220.9576980262959296 16.8886184324824313, 220.9646433114296258 16.9175552949130612, 220.9706915457650780 16.9465229737779772, 220.9797360850324139 16.9754084989699301, 220.9858503433434009 17.0043838123042157, 220.9958092375155729 17.0332524232458873, 221.0051547335982036 17.0621516661765042, 221.0123955262187678 17.0911251846374554, 221.0184945335432474 17.1201365064761575, 221.0265358816036212 17.1490962372719302, 221.0342592253194312 17.1780698849984077, 221.0416971727682665 17.2070564924296576, 221.0492649291077498 17.2360440208405343, 221.0574163923749325 17.2650193214497847, 221.0642376488161744 17.2940378145763631, 221.0712507676574603 17.3230554066094378, 221.0750035062377776 17.3521530122707013, 221.0833825988925980 17.3811014280375140, 221.1012000644046509 17.4097816163128094, 221.1234697965101930 17.4383372243239734, 221.1446009054772333 17.4669299946673000, 221.1659814117942346 17.4955196829087996, 221.1862074954466379 17.5241471727199070, 221.1957570597425331 17.5530905107880031, 221.2038686917591974 17.5820804814770639, 221.2080601841900034 17.6111893255309901, 221.1988433217773320 17.6407165962590362, 221.1916363252985036 17.6702144710442290, 221.1877485889076524 17.6996199313129097, 221.1891656918670037 17.7288761976824780, 221.1968354294688197 17.7579563475155311, 221.2025406653730215 17.7870977089870124, 221.2096147695652917 17.8162040253518299, 221.2165160144454603 17.8453198053554445, 221.2224942250372237 17.8744666958604519, 221.2277119721113934 17.9036399876070469, 221.2332821024614873 17.9327909627809063, 221.2383170207892249 17.9619443244375638, 221.2442905429176676 17.9910751116441041, 221.2498363552460603 18.0202227058669422, 221.2557305329598307 18.0493647450156551, 221.2621416431596799 18.0784963863439394, 221.2691430205308336 18.1076155304318149, 221.2754988091505197 18.1367577198945469, 221.2813337868578571 18.1659193359031370, 221.2877855767731887 18.1950676779960396, 221.2953253954281365 18.2241907180674154, 221.3013599379729328 18.2533629946000460, 221.3064374135869343 18.2825671410003565, 221.3124537532020213 18.3117487397487828, 221.3182281062903485 18.3409416696727448, 221.3250634190553683 18.3701085798518839, 221.3330656596799031 18.3992464481771698, 221.3374356808525363 18.4284927545661610, 221.3395300095252196 18.4578084755441409, 221.3458224373307246 18.4870083936197460, 221.3522630305629093 18.5162084244384495, 221.3577068641920675 18.5454412769644499, 221.3641904027647058 18.5746487548991901, 221.3715279113331746 18.6038361782572146, 221.3767990325112009 18.6330869316119490, 221.3800267736432943 18.6624002608480168, 221.3827362012217748 18.6917325592284413, 221.3870286300991097 18.7210239622508858, 221.3954345647359503 18.7502025136230017, 221.3995412875319175 18.7795077425839843, 221.4052686290156089 18.8087667835240033, 221.4116141406182976 18.8380079578304809, 221.4182075524130937 18.8672463620029056, 221.4234075464069917 18.8965286224053628, 221.4297424897585813 18.9257828880718968, 221.4381330035352846 18.9549830454225798, 221.4437786011409628 18.9842653899860707, 221.4516916823562553 19.0134876142634681, 221.4581724334677801 19.0427547245433644, 221.4643258335165683 19.0720353410303787, 221.4703040024018605 19.1013190922888008, 221.4757366352769736 19.1306161364696550, 221.4827138452384929 19.1598736469144697, 221.4886341156465619 19.1891653109676028, 221.4939175151725124 19.2184791926537528, 221.4996824222843372 19.2477836348834508, 221.5040993847280504 19.2771303360983701, 221.5096515244819102 19.3064491172807848, 221.5157897919053198 19.3357555187522081, 221.5254028690785049 19.3649680591620701, 221.5379303710355430 19.3941024987874364, 221.5502966625256249 19.4232455910307173, 221.5569858010044015 19.4525532672247969, 221.5662602301570416 19.4817920506938691, 221.5778712909811361 19.5109689307780059, 221.5906471456263773 19.5401169398491916, 221.6024846425621888 19.5692955530695656, 221.6125339523005664 19.5985288924105419, 221.6228556391052962 19.6277586118567982, 221.6323660626076446 19.6570154156721273, 221.6415036194281356 19.6862868957955293, 221.6440994496165331 19.7157478620347995, 221.6431790142311229 19.7453121776283425, 221.6474316282330221 19.7747340489961374, 221.6570225245225458 19.8040091392092137, 221.6647075508695082 19.8333421333557425, 221.6736770574902664 19.8626428790710392, 221.6816534358866875 19.8919757276629454, 221.6864937930701558 19.9214011979869667, 221.6879797049289493 19.9509252780549424, 221.6950232773449727 19.9803103315518591, 221.7007288046107476 20.0097516794640882, 221.7040268219716665 20.0392648174781556, 221.7074732178250258 20.0687776378866225, 221.7106187017003549 20.0983027921591813, 221.7176740679891225 20.1277217371706740, 221.7230474806044356 20.1571919248215714, 221.7277670535394805 20.1866843938526479, 221.7319372793065497 20.2161961795330214, 221.7405646672224293 20.2455863928381419, 221.7463882445141508 20.2750552241944000, 221.7538847958166457 20.3044764360793089, 221.7622793455343526 20.3338762064548391, 221.7701565146116707 20.3632943759725293, 221.7734189146283370 20.3928463602206200, 221.7781702147772478 20.4223602164826836, 221.7857704918945956 20.4517976945089401, 221.7905756424046331 20.4813176640664700, 221.7934115372622443 20.5108968160158298, 221.7963450989159071 20.5404769505775988, 221.8001359603279354 20.5700367281890664, 221.8054088754265649 20.5995586336503997, 221.8103228716607873 20.6290943849494575, 221.8166331240383613 20.6585946947209713, 221.8221241242965220 20.6881217626415825, 221.8259241658650183 20.7177000295338409, 221.8288535881722225 20.7473064169434167, 221.8317732953118764 20.7769167504077394, 221.8434864832524909 20.8062842965649075, 221.8548980732984433 20.8356638511278582, 221.8497146824853701 20.8655018098821969, 221.8425379707961156 20.8953868195347319, 221.8373773924683974 20.9252182013111252, 221.8382192560088413 20.9548855526717688, 221.8489009231472266 20.9842827887193941, 221.8672566919577207 21.0134697677843647, 221.8797273719326029 21.0428242377920007, 221.8887999810042686 21.0722772505930536, 221.8917645082245826 21.1019045711432049, 221.8997328109844602 21.1313958605496417, 221.8990926618291439 21.1611280411137344, 221.9019993444164811 21.1907616766640956, 221.9051040779272626 21.2203933633164361, 221.9093557913321604 21.2499967314856093, 221.9134297178846396 21.2796086471933563, 221.9116007489075173 21.3093879023960824, 221.9032882877899908 21.3393495525534931, 221.9060520607352771 21.3690080227605783, 221.9051334272910481 21.3987714956553425, 221.9034009241744343 21.4285605665808703, 221.9100285267176105 21.4581261493741380, 221.9160069827211714 21.4877163657336290, 221.9238932399040323 21.5172577422916227, 221.9293998902381873 21.5468681209350876, 221.9330707636211741 21.5765324977498878, 221.9363254486283381 21.6062118074009035, 221.9410037369304689 21.6358555651428830, 221.9455408147354092 21.6655067257743497, 221.9489016120366500 21.6951936277865123, 221.9527587731917890 21.7248704150393692, 221.9568600871939168 21.7545531875111315, 221.9622411699628231 21.7842141222439771, 221.9689664639304851 21.8138417551274060, 221.9756209612246778 21.8434747837706169, 221.9818735094069382 21.8731222677031809, 221.9874059330027194 21.9027929105330337, 221.9923440429898847 21.9324832583258242, 221.9971277815419626 21.9621812611599196, 222.0022569686276483 21.9918732335909688, 222.0073470416925829 22.0215696931690559, 222.0125447730543442 22.0512545134973443, 222.0181706962175383 22.0809182668990651, 222.0238933056503186 22.1105828124295165, 222.0295305341456356 22.1402531168903742, 222.0351237484508715 22.1699280425233560, 222.0404257554211540 22.1996143288699344, 222.0459155989807130 22.2292988829796059, 222.0512924341139751 22.2589899133886711, 222.0566673648044116 22.2886843762515916, 222.0618862307206882 22.3183864694176677, 222.0670553472532731 22.3480957599217085, 222.0723717417823480 22.3778070085798397, 222.0777839748901954 22.4075189964093404, 222.0831798394412999 22.4372347713886029, 222.0886434003048180 22.4669520384429369, 222.0940816858582423 22.4966733208646978, 222.0994527850592419 22.5263997498348054, 222.1047812729935060 22.5561306496470522, 222.1101155305294128 22.5858646931989888, 222.1154152125551207 22.6156029721982748, 222.1204420127930632 22.6453400486665437, 222.1255646964550010 22.6750652359120757, 222.1305329997020408 22.7047979140034641, 222.1355847787701236 22.7345316112044458, 222.1406216272308427 22.7642689945996821, 222.1456386712231108 22.7940101865939475, 222.1506385132327352 22.8237551067842332, 222.1555893546876348 22.8535046094059986, 222.1605043394521033 22.8832583260641478, 222.1653877636704806 22.9130161310442269, 222.1701197628285342 22.9427889792997348, 222.1746776287420460 22.9725778901872673, 222.1789441576504487 23.0023778463962323, 222.1836557252892987 23.0321689614480825, 222.1902440398285989 23.0619126297839436, 222.1954526487300825 23.0916966954934324, 222.2010831637109334 23.1214725486922212, 222.2083216384725404 23.1512082124632776, 222.2139515806103134 23.1809904050361730, 222.2171221060487198 23.2108420163699769, 222.2209885173431871 23.2406820491138610, 222.2264371355994967 23.2704868989222327, 222.2313264837684983 23.3003099104321585, 222.2360295055708832 23.3301410280497343, 222.2416143589899491 23.3599515095395809, 222.2470280979290465 23.3897696783524971, 222.2519457695078700 23.4196042623493739, 222.2572284978178629 23.4494320946219048, 222.2625351292319067 23.4792623412356001, 222.2678234450957575 23.5090961313971576, 222.2731187338746679 23.5389287176773259, 222.2783913237997240 23.5687606663922935, 222.2836896458203171 23.5985949595753439, 222.2889783774910200 23.6284325359269793, 222.2942692541417387 23.6582730742638745, 222.2995474628026216 23.6881169629623862, 222.3048186546048441 23.7179640408533174, 222.3100880876171175 23.7478141608096358, 222.3153559270981532 23.7776673079717895, 222.3206150332030404 23.8075236678525854, 222.3258698866435168 23.8373906038255825, 222.3311162163473682 23.8672686258960880, 222.3363674375100629 23.8971494473812527, 222.3416002240587375 23.9270336833286628, 222.3468409731698898 23.9569206200426770, 222.3520781787404701 23.9868105567601582, 222.3572950908845201 24.0167039333042780, 222.3625011870320805 24.0466004896446037, 222.3677192511185581 24.0764996045117989, 222.3729424320191299 24.1064014556798796, 222.3781468771423988 24.1362901048424909, 222.3833649201492051 24.1661637831187122, 222.3885678890137285 24.1960407688332495, 222.3937637687527626 24.2259208372428816, 222.3989420319153680 24.2558042638083542, 222.4041440838417998 24.2856899311823682, 222.4093321917397645 24.3155788396142469, 222.4144990636221451 24.3454711774863384, 222.4196730904269543 24.3753661752947579, 222.4248346881902023 24.4052643501693360, 222.4300062062717132 24.4351764710664909, 222.4351870687680162 24.4651031621802915, 222.4403525020867960 24.4950330549062940, 222.4455026491757792 24.5249661348580972, 222.4506599244405436 24.5549017979669095, 222.4558229849398856 24.5848400707973305, 222.4609842278302381 24.6147811468647681, 222.4661284181207179 24.6447254265187219, 222.4713101840497131 24.6746714423507427, 222.4764591914561720 24.7046210641846500, 222.4815193387960335 24.7345653487702748, 222.4865942845428890 24.7645009503149822, 222.4916659845742402 24.7944393662112326, 222.4967339978794314 24.8243805976587986, 222.5017992758810976 24.8543246132578695, 222.5068766617123401 24.8842710086783079, 222.5120706242933011 24.9142169964455960, 222.5176992594136607 24.9441541158756159, 222.5230551169359501 24.9741011721434063, 222.5290723867522047 25.0040333259218990, 222.5331869879559292 25.0340250877719370, 222.5376183126456908 25.0640178059903320, 222.5426224342267290 25.0939979417774595, 222.5478384861640961 25.1239750739483512, 222.5527734021357276 25.1539622860461556, 222.5574433522509423 25.1839591349760852, 222.5625189750431332 25.2139478159431825, 222.5680865705771225 25.2439260391509634, 222.5750931585015167 25.2738686682064539, 222.5818713705537562 25.3038199264691386, 222.5873131975623664 25.3338052353980245, 222.5917661569066013 25.3638151369706009, 222.5953573557681864 25.3938504355635217, 222.5981423237566332 25.4239096057939271, 222.6021066629561744 25.4539400323271927, 222.6070875480329789 25.4839460669213302, 222.6120740674626006 25.5139544753543177, 222.6170732825590335 25.5439650649896670, 222.6222362522800324 25.5739738306894857, 222.6271684386293259 25.6039912012273234, 222.6335610291737908 25.6339683652455541, 222.6407584509559285 25.6639224326588256, 222.6425063814833436 25.6940230383128245, 222.6465820115638792 25.7240645598688502, 222.6516161452649101 25.7540832404217426, 222.6567612330741497 25.7841014576707153, 222.6622771705746118 25.8141123513063810, 222.6675096863309875 25.8441331729110537, 222.6724462652234706 25.8741642349645389, 222.6771134454122034 25.9042048235666194, 222.6827850674766864 25.9342363968775409, 222.6931165988777366 25.9641633520258779, 222.6998107997744683 25.9941885112906768, 222.6993812296677504 26.0244039700569161, 222.7004828501633540 26.0545812838950468, 222.7068412637907215 26.0846224342125979, 222.7151250248850545 26.1146151271205404, 222.7223428546015214 26.1446381900068445, 222.7233614602515956 26.1748271205919423, 222.7251698747904527 26.2049974649508677, 222.7297580672415620 26.2350818940931916, 222.7350401377152878 26.2651345787107857, 222.7397478569982354 26.2952047135490545, 222.7441890163587743 26.3252841708795273, 222.7490415028016457 26.3553551043257173, 222.7538245647999702 26.3854301586473454, 222.7585301990661719 26.4155095328346157, 222.7633657664723614 26.4455877699967239, 222.7688255310053194 26.4756518789740305, 222.7734841245274993 26.5057393017668659, 222.7804994013292799 26.5357699997111638, 222.7892222416250263 26.5657611258525144, 222.7934201840520529 26.5958734025664896, 222.7976525279802331 26.6259869814647345, 222.8061529184205085 26.6559906322473879, 222.8082111146133855 26.6861657600069009, 222.8108775599046965 26.7163270320472783, 222.8149933055477163 26.7464524254111780, 222.8202949000983040 26.7765488881277314, 222.8301151846121400 26.8065289627933971, 222.8347576221901534 26.8366503143100701, 222.8375201821877170 26.8668265546276501, 222.8418110343396847 26.8969648288669205, 222.8465067625856477 26.9270946182803463, 222.8524537725384675 26.9571937291370958, 222.8574636362439207 26.9873195346867867, 222.8620005207343127 27.0174598522939498, 222.8671731236854328 27.0475856079339003, 222.8726715768086706 27.0777049164258194, 222.8775474502902796 27.1078426359435340, 222.8816119755332181 27.1380004347667985, 222.8869882261955695 27.1681224764912130, 222.8926632525074183 27.1982387554859919, 222.8956791014889518 27.2284267497753341, 222.8990635443852568 27.2586071020030190, 222.9037992898207108 27.2887541107411309, 222.9093687180935035 27.3188813346966164, 222.9147563759039485 27.3490153396147129, 222.9196081766303905 27.3791653776126616, 222.9243436031769932 27.4093204644372150, 222.9286080088542121 27.4394937878516778, 222.9336119064177808 27.4696539013430439, 222.9389694547837451 27.4998067414069354, 222.9467971585075929 27.5298969245199672, 222.9536775696169855 27.5600138137988395, 222.9590786061792187 27.5901713708442458, 222.9649273858052254 27.6203191385870532, 222.9707788876332302 27.6504687616998233, 222.9779598201737372 27.6805854587132423, 222.9832825767003044 27.7107527614628353, 222.9817568406569137 27.7410883808228697, 222.9874565001069868 27.7712230016882593, 222.9936425870742482 27.8013468434569937, 222.9960558499005003 27.8315712512584632, 223.0003219092032793 27.8617491055375872, 223.0057706188702866 27.8918979783849927, 223.0108205033237994 27.9220591651377283, 223.0159954833848133 27.9522189808714145, 223.0194101868325163 27.9824265788414301, 223.0236278179942246 28.0126150871196700, 223.0270783276952216 28.0428260124679909, 223.0284527756684838 28.0730933626770600, 223.0310594806987865 28.1033303987746450, 223.0333322930894440 28.1335778457448136, 223.0341180624720039 28.1638655435949907, 223.0377939193720067 28.1940800787344799, 223.0423453188257099 28.2242737368825729, 223.0473563566852988 28.2544573009177569, 223.0475810350740460 28.2847663252395201, 223.0468242129837790 28.3151021837157764, 223.0494697180605783 28.3453669498318952, 223.0551226685686856 28.3755718417018450, 223.0596599616456217 28.4058071837445851, 223.0644130602050836 28.4360386740748048, 223.0699211842023431 28.4662524123565284, 223.0775607745895286 28.4964128803651633, 223.0834267667080724 28.5266207293508067, 223.0946602925923230 28.5566915950313849, 223.1011121708191922 28.5868875504529036, 223.1057514664018697 28.6171320328370271, 223.1092717803553569 28.6474026359030276, 223.1131858521137303 28.6776599785361874, 223.1175135978419064 28.7079082719772565, 223.1224011054471248 28.7381437355216534, 223.1295408824391302 28.7683226027756120, 223.1386439433995577 28.7984522355940626, 223.1466096978197129 28.8286128295861097, 223.1512039324807120 28.8588623697961353, 223.1491767764528049 28.8892849121626796, 223.1495096696987446 28.9196477562610887, 223.1531510946215917 28.9499227439951703, 223.1593084066995232 28.9801302235178611, 223.1671463731093752 29.0102958476445494, 223.1733378307814917 29.0405055589089827, 223.1762893691844170 29.0708005572484645, 223.1797411591123534 29.1010841479297682, 223.1842105395181193 29.1313429880265602, 223.1897492654337611 29.1615757529559474, 223.1968336860489330 29.1917701214392054, 223.2007111469345091 29.2220488212368927, 223.2065521127375689 29.2522700368019741, 223.2119706505060890 29.2824949298750461, 223.2143181739405975 29.3128005757675894, 223.2145049372266783 29.3431632754399807, 223.2130727083799684 29.3735688214291280, 223.2169012501132954 29.4038404960307034, 223.2205048495329152 29.4341193922091833, 223.2231762087316156 29.4644236196081089, 223.2286000314316823 29.4946587355534788, 223.2310513877485789 29.5249714294954124, 223.2344723717499733 29.5552689830075828, 223.2401364427243777 29.5855193241839842, 223.2452585570237602 29.6157849349408728, 223.2505202413070720 29.6460483698967749, 223.2559231593347135 29.6763095798524112, 223.2644027871221795 29.7064934052381133, 223.2627241956078876 29.7369385494086842, 223.2645402237930057 29.7672955192597257, 223.2677335536144483 29.7976186173721942, 223.2703656238754206 29.8279573493983037, 223.2756273227971349 29.8582220782055501, 223.2844765439493528 29.8883879235143297, 223.2937085860437207 29.9185452807983161, 223.2973081015805406 29.9488478138785723, 223.2936631005052845 29.9793362624003557, 223.2960666519461199 30.0096716675619035, 223.3009400212254150 30.0399455321170734, 223.3025870375495288 30.0703026550889412, 223.3057019420284917 30.1006237111833990, 223.3089129363760605 30.1309435671565957, 223.3150049755914779 30.1612022619482154, 223.3234217233952563 30.1914144151318204, 223.3234210094943535 30.2218413027351680, 223.3217310036492620 30.2523119774260358, 223.3241338861792258 30.2826801517841098, 223.3291361017602696 30.3129838017814031, 223.3335691814666006 30.3433030311341660, 223.3376879267507036 30.3736313903895656, 223.3415822010214526 30.4039665939569588, 223.3428527313638767 30.4343692093283416, 223.3463046577959119 30.4647139764403860, 223.3516152151367464 30.4950088855972758, 223.3563567921310096 30.5253193044814459, 223.3591806847722694 30.5556792231968117, 223.3633551843234670 30.5860062097663281, 223.3673017153173816 30.6163400617374144, 223.3700134643006265 30.6467061128488147, 223.3771472685137098 30.6769619187146567, 223.3826102810353689 30.7072608971903698, 223.3886354466583271 30.7375468061244774, 223.3920631849453571 30.7678988088007088, 223.3948340483456150 30.7982679488012465, 223.3964740350774605 30.8286665606172861, 223.3988015833817258 30.8590488763678010, 223.4054640309857689 30.8893233212344960, 223.4110113026205795 30.9196268339053262, 223.4122686163119340 30.9500391594668898, 223.4185862540229266 30.9803254154219800, 223.4253672463590590 31.0106010422639251, 223.4280655144074501 31.0409802449639898, 223.4338793837549417 31.0712782786190438, 223.4368728738980963 31.1016439799744440, 223.4352648020414733 31.1321259385368307, 223.4366125414503585 31.1625346166880490, 223.4396705389226838 31.1929014229039510, 223.4456438373482570 31.2231963322768564, 223.4505941710129946 31.2535177729686318, 223.4547715708267219 31.2838594812816808, 223.4577739516391546 31.3142314599850557, 223.4600217044295505 31.3446231542552951, 223.4635365292320728 31.3749880885431622, 223.4679250724920223 31.4053363295085184, 223.4717664816919864 31.4356991045685845, 223.4748831801429674 31.4660808082941550, 223.4799487654643713 31.4964148775685189, 223.4840292327695863 31.5267743476384261, 223.4865411911619617 31.5571736951986601, 223.4883032670517480 31.5875924900986824, 223.4923952323851779 31.6179542209252773, 223.4970672524644328 31.6483023929509208, 223.5030692210505379 31.6786209217389043, 223.5066616283142196 31.7090028002147584, 223.5106210413823362 31.7393763676496157, 223.5132764001971566 31.7697830874807003, 223.5179240398600484 31.8001411574942594, 223.5195254158442140 31.8305755440646045, 223.5239434375313579 31.8609408591624330, 223.5282886785034577 31.8913087442676826, 223.5322519417453861 31.9216868480441569, 223.5347617094257657 31.9521016879863282, 223.5380353071004720 31.9824836882650096, 223.5428282743981185 32.0128133802272430, 223.5480508269670565 32.0431332222472420, 223.5497441169615058 32.0735409978522341, 223.5553057804664263 32.1038539700301087, 223.5598384268536165 32.1341930832612874, 223.5624288051742212 32.1645807930955741, 223.5652337762755906 32.1949638621259524, 223.5678286491418874 32.2253527382871638, 223.5695560421223433 32.2557635380633627, 223.5752088569645366 32.2860971656535511, 223.5778937031500675 32.3165239135066074, 223.5812675754343957 32.3469343758282122, 223.5848566389719849 32.3773401796878204, 223.5891675860983128 32.4077288948879101, 223.5927666199704902 32.4381356808599577, 223.5971664748019236 32.4685234266738121, 223.6018897195259569 32.4989038349033450, 223.6036667978909520 32.5293570670729295, 223.6064949112673332 32.5597850850799730, 223.6116324578020453 32.5901446220759752, 223.6140456300390724 32.6205582901027853, 223.6180710912269092 32.6509330396607638, 223.6211992806995852 32.6813302883187760, 223.6282270303249504 32.7116327514627656, 223.6317729060406236 32.7420209117044578, 223.6357729383524600 32.7723985009571379, 223.6368325295503041 32.8028483884673605, 223.6411096371763847 32.8332202356979366, 223.6439910882040465 32.8636266156867265, 223.6481310195876802 32.8940028179196489, 223.6509936165338104 32.9244106061581547, 223.6553899144079764 32.9547815456590385, 223.6596968044144660 32.9851551442578170, 223.6612145715821498 33.0155969875223647, 223.6650693763939444 33.0459824801913911, 223.6692659409714850 33.0763601294171679, 223.6716695758493643 33.1067817005986527, 223.6751523009409368 33.1371775151216852, 223.6790842134867034 33.1675628698264902, 223.6817299554946317 33.1979800536689780, 223.6840029478087502 33.2284069152961976, 223.6869551521492383 33.2588177146786208, 223.6903565456445051 33.2892180314227986, 223.6936834072822933 33.3196205103363567, 223.6971029050550612 33.3500211100688730, 223.7007701587213830 33.3804160897485005, 223.7044837207082537 33.4108103024752410, 223.7075120344256618 33.4412213365115321, 223.7108808174373280 33.4716244979182633, 223.7150218024642072 33.5020111063703894, 223.7185127413576993 33.5324154287190765, 223.7220915424194061 33.5628179458101883, 223.7256487173190180 33.5932212766861014, 223.7286216236611267 33.6236389013519741, 223.7320216440893148 33.6540465564206741, 223.7369843538813257 33.6844170563033956, 223.7396632576619027 33.7148425178093163, 223.7417605710047042 33.7452821084065278, 223.7453063421154411 33.7756872889352380, 223.7483122061553331 33.8061098598384433, 223.7517120547620664 33.8365277389875345, 223.7558255243394569 33.8669288053235888, 223.7594854651125900 33.8973409052722943, 223.7624929837062666 33.9277687623950541, 223.7659937331060576 33.9581850448707954, 223.7683016722576781 33.9886299134953518, 223.7717654102397660 34.0190474189640710, 223.7746851068746992 34.0494780279845912, 223.7778200650010660 34.0799036630295547, 223.7815767483879483 34.1103144298280867, 223.7849598453518638 34.1407339699114232, 223.7886890994548992 34.1711454269250368, 223.7929755563177139 34.2015437888475020, 223.7950123858878442 34.2319956601869038, 223.7976542511011644 34.2624332578238366, 223.8008059636456153 34.2928588582611340, 223.8038189435971788 34.3232878312866205, 223.8070197677527631 34.3537124336828441, 223.8102919260166743 34.3841354218809698, 223.8132599669528702 34.4145658933153271, 223.8172826870554388 34.4551387030861704))) +MULTIPOLYGON (((225.6590116066086011 15.2022751781288790, 225.8184285319980802 15.1938011437427214, 225.9815607786718488 15.1849941022049979, 226.1537479980599414 15.1755636254992954, 226.3305987100000323 15.1657156107401772, 226.5161948590464078 15.1552163682550187, 226.7132602789062901 15.1438893478077521, 226.9261988964304351 15.1314506126365362, 227.1499418813374973 15.1181384848977594, 227.3887605669752929 15.1036654662162384, 227.6457676404389190 15.0877902093839591, 227.9238726251499827 15.0702639425568297, 228.2357698245607480 15.0502006375273076, 228.5715407538233990 15.0280865132481711, 228.9475901297275584 15.0027161002309253, 229.3712716345860088 14.9733679200999088, 229.9511930049727368 14.9320537002732614, 230.4883212838945497 14.8922542020580941, 231.1136532000215027 14.8443022653531269, 231.8633228532418400 14.7845460924271404, 232.7891574029211483 14.7073522924876805, 233.9942664759018385 14.6013042631466732, 234.4965294627785397 14.5504706067190703, 234.5208110638522783 14.5099689962529332, 234.5313044299073226 14.4803171724793369, 234.5416131312027801 14.4506850418485016, 234.5520779977870802 14.4210415870330539, 234.5623431784188710 14.3914232575198557, 234.5724238845463105 14.3618286535965467, 234.5827882789665750 14.3322149027207999, 234.5929578113345144 14.3026258488927596, 234.6030683507545405 14.2730490546493591, 234.6134058750884037 14.2434583659015850, 234.6236678287416737 14.2138814837024672, 234.6339787538766188 14.1843070299267513, 234.6442862284248463 14.1547369879349692, 234.6547188863688120 14.1251597335973749, 234.6648922775194421 14.0956130658841872, 234.6753260761099682 14.0660495235981156, 234.6864368112472903 14.0364311267002471, 234.6957686604493745 14.0069820247430687, 234.7061404536003693 13.9774449561658045, 234.7168562105069327 13.9478834920582333, 234.7270224975895871 13.9183791086254978, 234.7372048991153406 13.8888802351922518, 234.7477636671919754 13.8593540754838660, 234.7584817061348872 13.8298204455798928, 234.7691873583667643 13.8002949950470910, 234.7803650551794021 13.7707336568590133, 234.7916750860139814 13.7411673885780026, 234.8029058064372521 13.7116154576392404, 234.8142170604288026 13.6820633420075914, 234.8253048384431736 13.6525386874369428, 234.8363381012699165 13.6230261366839080, 234.8474859593540600 13.5935103445255336, 234.8586521615223717 13.5639727104256611, 234.8698086919267212 13.5344171571079563, 234.8810402760219347 13.5048618785192769, 234.8921633384625238 13.4753235398173246, 234.9036036680469692 13.4457635458124880, 234.9148787480721126 13.4162256650294545, 234.9262976243365983 13.3866818976443955, 234.9378525857910063 13.3571329686720421, 234.9491438202865936 13.3276151019577238, 234.9605851734781936 13.2980908305402394, 234.9714051171723099 13.2686329662724525, 234.9829107510691983 13.2391230511010356, 234.9953247709165112 13.2095381986057365, 235.0050945465017662 13.1801996367152636, 235.0136741450404543 13.1509757163783796, 235.0235876197879179 13.1216383624306463, 235.0329511591612004 13.0923577945443821, 235.0428529669674731 13.0630357717848451, 235.0521842656135902 13.0337723688292240, 235.0625643579874122 13.0044215484787653, 235.0718456764101347 12.9752026574268520, 235.0824545378012829 12.9458957824717462, 235.0941279042510814 12.9165005022008970, 235.1065853378691486 12.8870421851470844, 235.1158685212187152 12.8578770132342068, 235.1267432519176737 12.8285760999852148, 235.1379548440312988 12.7992524166110808, 235.1493796188802605 12.7699171276532795, 235.1597708587534044 12.7406822108994717, 235.1712990013349156 12.7113527637885877, 235.1827906320188504 12.6820275613200177, 235.1941656390224011 12.6527141312217992, 235.2050650309431887 12.6234509249003715, 235.2163653275223396 12.5941593716165876, 235.2278129164640745 12.5648622450461041, 235.2385899990798066 12.5356327691044473, 235.2509196533849547 12.5062719956791675, 235.2633495959182710 12.4769099908336205, 235.2728707652432547 12.4478157344413951, 235.2843018911920012 12.4185583774315731, 235.2958612619559631 12.3892706547972740, 235.3093903391809647 12.3597895148684778, 235.3187948284901552 12.3306840978547978, 235.3306973300512368 12.3013633115279735, 235.3409552423264586 12.2721967439647663, 235.3501958576858613 12.2431283054920090, 235.3613910460340435 12.2138932347158029, 235.3730447116262781 12.1846249559616275, 235.3841076194497077 12.1554168855521301, 235.3951457454282092 12.1262186343150535, 235.4062396923714005 12.0970204529142062, 235.4175034828008393 12.0678123993142634, 235.4293245043035085 12.0385625702422647, 235.4421181444995455 12.0092341707538353, 235.4552959271688906 11.9798795410635801, 235.4690679156001920 11.9504801024310332, 235.4834853052213361 11.9210313918726705, 235.4960974300517762 11.8917506964105950, 235.5075487335811886 11.8625807321371131, 235.5232045964961003 11.8330462747001430, 235.5346764929361711 11.8038936247787749, 235.5484769103933331 11.7745459193172746, 235.5600500490689910 11.7454032067389971, 235.5703027538092726 11.7163850530546831, 235.5839099151444316 11.6870783106887757, 235.5954261043270037 11.6579642551851848, 235.6091634785258861 11.6286620492116040, 235.6216120131801404 11.5994816340206004, 235.6324251515997616 11.5704534114552136, 235.6427681559864027 11.5414744763687072, 235.6568231608829365 11.5121696292982936, 235.6720114138059898 11.4827667117629559, 235.6855534378352104 11.4535169164043715, 235.6985976230074584 11.4243190426234946, 235.7101697741603061 11.3952586967556826, 235.7212865677432774 11.3662463475955970, 235.7336848210081257 11.3371294098704496, 235.7467824959670679 11.3079591641786816, 235.7608802892358995 11.2787093286096738, 235.7716222748914561 11.2497620499109914, 235.7842032100646179 11.2206891920149250, 235.7973313753711295 11.1916028404770049, 235.8104867447165987 11.1625225099613523, 235.8248992522362073 11.1333405976275852, 235.8395596186140324 11.1041455608978978, 235.8525266395224662 11.0751071281319806, 235.8667638348769913 11.0459661778884950, 235.8799840523980720 11.0169226049946403, 235.8933575463018997 10.9878741537475406, 235.9056857922247161 10.9589253856028943, 235.9193690857337344 10.9298457604617330, 235.9332202571170285 10.9007399237256202, 235.9474135600875115 10.8716127613864479, 235.9606689831861672 10.8425757207401041, 235.9745891351863349 10.8134893032569970, 235.9749642465137640 10.7716809281121151, 234.3062264801245078 10.9140277809663289, 233.0568672341267700 11.0146280042103317, 232.0879579900140470 11.0891193379889472, 231.2922763752978028 11.1479476252960801, 230.6222024977036256 11.1958368476612193, 230.0451126661331216 11.2358585089279455, 229.5399124326933133 11.2699591633018610, 229.0910977852267649 11.2995144425208274, 228.6886580791888548 11.3254217054343140, 228.3230615139313500 11.3484629748790802, 227.9885578563481090 11.3691297953353860, 227.6794424865351800 11.3878696987312154, 227.3925662525225277 11.4049521734577688, 227.1244248889418884 11.4206460692728200, 226.8725374557903933 11.4351462062810594, 226.6348499723003442 11.4486118924843758, 226.4089327375767766 11.4612113075362014, 226.1941018513785195 11.4730141135446058, 225.9885536989861521 11.4841415383497054, 225.7906841315510178 11.4946974768467598, 225.5999034371527046 11.5047316362642942, 225.5366590428407676 11.5127499139751190, 225.5372155286837028 11.5505123386258859, 225.5385771173869216 11.5787917807373049, 225.5399422790694928 11.6070769021958409, 225.5412964706850119 11.6353683683259490, 225.5426724692719347 11.6636646542798914, 225.5440051181479930 11.6919712226446855, 225.5452754778033579 11.7202890826927870, 225.5466283640395773 11.7486089150217552, 225.5479733512320877 11.7769349109975465, 225.5492620732997580 11.8052693182655286, 225.5505841234978277 11.8336079601987230, 225.5519462019553600 11.8619505139251959, 225.5533034114788222 11.8902990653271967, 225.5546573357829629 11.9186535319933675, 225.5560296401821176 11.9470128979944921, 225.5574630380517362 11.9753825153277962, 225.5590145865995453 12.0037600937422670, 225.5604603602513691 12.0321483085082939, 225.5618766106161956 12.0605435905484040, 225.5632235046636538 12.0889478001605344, 225.5646322492728189 12.1173547927717955, 225.5660183351829460 12.1457685136433966, 225.5674524000941119 12.1741856511797124, 225.5688591210027312 12.2026097227449029, 225.5703066480778034 12.2310375312635990, 225.5717059626002481 12.2594635287660125, 225.5731135142524977 12.2878845469914175, 225.5745000480431770 12.3163122245770751, 225.5759250961868361 12.3447437585488249, 225.5773924999224107 12.3731789608056815, 225.5788485201462947 12.4016203465804651, 225.5803384550112014 12.4300657782762727, 225.5816851396154448 12.4585235859629435, 225.5830893136675286 12.4869843196153578, 225.5845898505328364 12.5154461391777048, 225.5860380816324664 12.5439157417238558, 225.5874589809734232 12.5723919342328845, 225.5889159822422414 12.6008720348057537, 225.5903500433967963 12.6293588187895995, 225.5917512819598585 12.6578527497401989, 225.5931498469038559 12.6863523975501824, 225.5945936511308787 12.7148554897243926, 225.5960004208644705 12.7433659092358020, 225.5974035727396938 12.7718820685236771, 225.5988234672666408 12.8004029993498278, 225.6002725682347716 12.8289353398050547, 225.6017372705671562 12.8574801026263454, 225.6031663907919835 12.8860320507559223, 225.6045230142199500 12.9145929257661809, 225.6058813437432775 12.9431592082911369, 225.6072542184839165 12.9717302815183047, 225.6086155626813365 13.0003073734616610, 225.6099855929491866 13.0288895207329318, 225.6113301413350882 13.0574783349659196, 225.6125573731443410 13.0860781699462851, 225.6138059179633046 13.1146685837733834, 225.6150812749465615 13.1432485812774509, 225.6162458519782774 13.1718393536475116, 225.6173776523386891 13.2004371911819796, 225.6185740510497624 13.2290374592872642, 225.6198200700041809 13.2576408579599114, 225.6210454851929796 13.2862507192777066, 225.6223709718760801 13.3148612908315407, 225.6236531533329810 13.3434793901493425, 225.6249325723329093 13.3721030820185973, 225.6260928567572819 13.4007285591032268, 225.6271536834223639 13.4293543931465589, 225.6282124972139513 13.4579858251888993, 225.6292645314285608 13.4866230739553536, 225.6301804105962958 13.5152723244987261, 225.6310913323261218 13.5439273004220944, 225.6319395686368807 13.5725907590492589, 225.6327541317145062 13.6012613101755768, 225.6337718649642170 13.6299275878090640, 225.6347506831084502 13.6586011866152344, 225.6357740723691734 13.6872915145011422, 225.6369158381051250 13.7159957103282366, 225.6377194029691964 13.7447214977765899, 225.6381065136040149 13.7734726404849468, 225.6384486634578934 13.8022312915639684, 225.6384696572111181 13.8310107208009736, 225.6377164794394048 13.8598327075708667, 225.6365675112162137 13.8886790652427319, 225.6366436889485954 13.9174718431418363, 225.6368569804845379 13.9462633389480235, 225.6372512893272244 13.9750446861622386, 225.6375598958670707 14.0038283677250384, 225.6379232729382807 14.0326147566449340, 225.6383897344348100 14.0614015134760191, 225.6384870229912281 14.0902113783666341, 225.6385225417334937 14.1190295454278214, 225.6386422674683558 14.1478489717101557, 225.6388548745616731 14.1766692294529779, 225.6393899644289718 14.2054792305965041, 225.6400017789805759 14.2342908119101494, 225.6406354379116408 14.2631066557045862, 225.6413569018558860 14.2919235676818150, 225.6418737897815276 14.3207556083426581, 225.6423091415276758 14.3495968327812982, 225.6427227612253716 14.3784443487517883, 225.6431399559387501 14.4072969248162703, 225.6435643091585348 14.4361543784162585, 225.6439996403331634 14.4650165186353465, 225.6444242554794926 14.4938843841154874, 225.6447387703332197 14.5227627774815442, 225.6449631350287177 14.5516507312391479, 225.6451722610784714 14.5805446133494083, 225.6453957579692826 14.6094429811145208, 225.6457542898072859 14.6383399809685439, 225.6462420940192146 14.6672358817340704, 225.6469402654511782 14.6961267415683920, 225.6476430843318326 14.7250225124654772, 225.6482912662952742 14.7539260617623302, 225.6489832267797908 14.7828326103256273, 225.6497656768799516 14.8117398861253182, 225.6506424444196739 14.8406387378099094, 225.6513629139793977 14.8695408561432654, 225.6517777322902418 14.8984629714063477, 225.6521804907180808 14.9273908337275358, 225.6524924020781668 14.9563282654052987, 225.6529946843869254 14.9852615950152863, 225.6535087791164358 15.0141994839657169, 225.6541740532657627 15.0431351470923822, 225.6549119926503124 15.0720723858902144, 225.6554983620026746 15.1010221054609115, 225.6560601547267595 15.1299724947379399, 225.6566877994991955 15.1589188520153293, 225.6590116066086011 15.2022751781288790))) +MULTIPOLYGON (((222.1624644986581814 22.8951608776491682, 222.3339278053147154 22.8936291249977444, 222.4918214735398010 22.8892887248561081, 222.6447347625093585 22.8849225118103980, 222.7860232522739352 22.8807537877385698, 222.9282491754742921 22.8764117840873240, 223.0766244984219497 22.8717204866312613, 223.2163755016696030 22.8671671507805954, 223.3566763952025269 22.8624540093663029, 223.4933003437754166 22.8577319700323471, 223.5898184185919320 22.8543578550741309, 223.6952462098100227 22.8505806048140450, 223.7986314112134210 22.8468004169646370, 223.8996071437270245 22.8430363019214830, 223.9985409791389088 22.8392789938655163, 224.0959564206264076 22.8355116831515232, 224.1910355953448857 22.8317716008955287, 224.2846905331636265 22.8280253855071642, 224.3794591431320669 22.8241662736667443, 224.4717633562828496 22.8203486473478847, 224.5633375179994857 22.8165001434515204, 224.6543476105477453 22.8126140286554744, 224.7440401314165683 22.8087272357695667, 224.8325041708505410 22.8048422966027147, 224.9212556591315035 22.8008911950998545, 225.0106581698765069 22.7968452216291482, 225.1000007997411956 22.7927430513065374, 225.1888277899536774 22.7886040403501653, 225.2781779860744109 22.7843853505198659, 225.3686923868877443 22.7800551110823548, 225.4590163590555107 22.7756725361698003, 225.5508196988385521 22.7711599175616932, 225.6422475001495513 22.7666030802101957, 225.7360430349211526 22.7618690698426214, 225.8308944078886782 22.7570178539048200, 225.9265645398400011 22.7520593284113914, 226.0249049679701443 22.7468968896814623, 226.1249454787566151 22.7415751879109145, 226.2278086015192287 22.7360312020369584, 226.3331090916952633 22.7302792144843551, 226.4411376184329754 22.7242978235364461, 226.5516842589036060 22.7180922185925489, 226.6656163593179940 22.7116078268158610, 226.7845301475643396 22.7047457109732562, 226.9071475647440082 22.6975670621508989, 227.0314410381741084 22.6901810095987422, 227.1839792061757350 22.6810029064036804, 227.3309878641619832 22.6719940160821594, 227.4852574295552472 22.6623834900507255, 227.6478981924533969 22.6520789916308765, 227.8244753455144860 22.6406976405487228, 228.0131819147794374 22.6283077428341635, 228.2162925672537028 22.6147123261545353, 228.4292029370799071 22.6001656944389460, 228.6562565745130655 22.5843249428905253, 228.9060279701273828 22.5665175964537532, 229.1825161010338832 22.5463403908074866, 229.4889073173453937 22.5234095910938592, 229.8235975094182209 22.4976688768649531, 230.1950353289553561 22.4682622756183683, 230.6140350097421958 22.4340362400728992, 231.0891086675366637 22.3938791162801500, 231.6395867000892963 22.3455627542399782, 232.2933600728475199 22.2857009540908635, 233.0468719139714437 22.2096336010235262, 233.0786160068223012 21.8362790738185488, 233.1128703125102675 21.4745535124936850, 233.1496154961199068 21.1131520453783352, 233.1847240764050753 20.7523849749798082, 233.2282694104284246 20.3912575382026091, 233.2729399482114729 20.0308241593004865, 233.3250709695567195 19.6705333692279076, 233.3796821891314153 19.3110185896687092, 233.4385722855595304 18.9512397884117654, 233.5048315554937517 18.5912746804041475, 233.5705679155844336 18.2318918456861674, 233.6451980358386891 17.8721782134278229, 233.7217275105666658 17.5133469216293491, 233.8008596200677403 17.1546858578329271, 233.8864271812514346 16.7969322128191187, 233.9697189392310293 16.4397036867625950, 234.0828109349569388 16.0803141029273959, 234.1849920604829549 15.7230496510434978, 234.2920854371643600 15.3662472678846918, 234.4024907287820838 15.0099336756868436, 234.5149128953590321 14.6540024086710705, 234.6379311549196132 14.2984584660047549, 234.7623775574045908 13.9436811555426505, 234.8942578953382849 13.5892102038194746, 235.0288272435886654 13.2349149251491429, 235.1521051678167282 12.8828891503746874, 235.2867725902066240 12.5312613935276893, 235.4233087209120754 12.1800902645324154, 235.5708596306864138 11.8287640872622291, 235.7235065834900070 11.4781679472531284, 235.8797318094723323 11.1284757052297838, 236.0525313246160977 10.7671682736166154, 234.5539738435557524 10.8934756928844916, 233.4407131631531342 10.9842712723458433, 232.5469229652644003 11.0542229776369414, 231.8057772059842137 11.1102241836769391, 231.1727759778428037 11.1565989553883913, 230.6222024977036256 11.1958368476612193, 230.1360978920992295 11.2296246903222858, 229.7011060076215756 11.2591734075647345, 229.3092627460586925 11.2852352682155725, 228.9523786369051948 11.3085085479038057, 228.6255699416117011 11.3294320811030538, 228.3230615139313500 11.3484629748790802, 228.0424929933010674 11.3658248267683568, 227.7797848238544418 11.3818240807472488, 227.5335303503320290 11.3965959501297078, 227.3013618133047657 11.4103203927839996, 227.0813921445934511 11.4231400422407976, 226.8725374557903933 11.4351462062810594, 226.6735784057233900 11.4464323335893088, 226.4830830479979795 11.4570977194829062, 226.3002739486506414 11.4672030229303150, 226.1246140672749334 11.4767939954809552, 225.9550662527160227 11.4859387811263272, 225.7906841315510178 11.4946974768467598, 225.6312478555471159 11.5030927722663776, 225.4762447625155630 11.5111601660448812, 225.3250842761325714 11.5189369296322024, 225.1774439551024329 11.5264465188783944, 225.0328448252998612 11.5337180770247585, 224.8908763596490132 11.5407761760249503, 224.7513584997161331 11.5476346729728920, 224.6139594562434354 11.5543129777076103, 224.4784375362918638 11.5608260941027616, 224.3444652819509599 11.5671914448426545, 224.2117774258863392 11.5734232007857401, 224.0801718772106028 11.5795330298010377, 223.9493664901763452 11.5855344995887322, 223.8191624724294400 11.5914391819224214, 223.6892422590746605 11.5972592901497755, 223.5594084415180305 11.6030053638277604, 223.4294005333650261 11.6086896685705749, 223.2989722102144583 11.6143216904755171, 223.1678913125285533 11.6199107220438567, 223.0358968024115143 11.6254674694465940, 222.9027074603658320 11.6310028545879973, 222.7681514532162907 11.6365211163933147, 222.6319141538503459 11.6420339437049947, 222.4937638625373211 11.6475477129612379, 222.3535187113662914 11.6530658977189212, 222.2106332312139614 11.6586083764543140, 222.0649326370137260 11.6641761438836671, 221.9159984711464233 11.6697805626031919, 221.7637180402751653 11.6754184975181445, 221.6071946734351457 11.6811193203291648, 221.4462705120642738 11.6868790352296799, 221.2800176036289201 11.6927238980664523, 221.1082343240075829 11.6986486654835620, 220.9302181846813085 11.7046664470968551, 220.7448115762643397 11.7108046009476432, 220.5512576667543385 11.7170716871744176, 220.3489604038595360 11.7234675875962768, 220.1364090861300156 11.7300207161521186, 219.9120955538532201 11.7367529071512831, 219.6885215783216552 11.7467999825000735, 219.7800022085723413 12.0939667193786544, 219.8674454814815817 12.4316594206823421, 219.9609663348926460 12.7696974746052021, 220.0435221785276383 13.1088831468612099, 220.1287352846985073 13.4489940062221862, 220.2143098338185894 13.7895853680132241, 220.2996432287141317 14.1309982528014721, 220.3856337203785074 14.4729600246978425, 220.4702124056549621 14.8160664517127358, 220.5542495222690889 15.1598074720371745, 220.6372147493088676 15.5039964428243273, 220.7215739629539826 15.8490768264030795, 220.8003749787557979 16.1950206146460012, 220.8780366530769754 16.5414260976919820, 220.9576980262959296 16.8886184324824313, 221.0492649291077498 17.2360440208405343, 221.2038686917591974 17.5820804814770639, 221.2332821024614873 17.9327909627809063, 221.3064374135869343 18.2825671410003565, 221.3767990325112009 18.6330869316119490, 221.4437786011409628 18.9842653899860707, 221.5157897919053198 19.3357555187522081, 221.6415036194281356 19.6862868957955293, 221.7040268219716665 20.0392648174781556, 221.7734189146283370 20.3928463602206200, 221.8288535881722225 20.7473064169434167, 221.8917645082245826 21.1019045711432049, 221.9100285267176105 21.4581261493741380, 221.9689664639304851 21.8138417551274060, 222.0351237484508715 22.1699280425233560, 222.0994527850592419 22.5263997498348054, 222.1624644986581814 22.8951608776491682))) diff --git a/isis/src/base/objs/ImagePolygon/ImagePolygon_Darwin_powerpc.truth b/isis/src/base/objs/ImagePolygon/ImagePolygon_Darwin_powerpc.truth new file mode 100644 index 0000000000000000000000000000000000000000..2e1833a559c698848d00e72fbab3862964114972 --- /dev/null +++ b/isis/src/base/objs/ImagePolygon/ImagePolygon_Darwin_powerpc.truth @@ -0,0 +1,3 @@ +MULTIPOLYGON (((223.8172830256576731 34.4551389254355271, 223.8417027794004923 34.4596506066819828, 223.8575436553270777 34.4592772202857702, 223.8731987948049493 34.4589061403268175, 223.8888001595549326 34.4585342458576136, 223.9044019981106715 34.4581602382883005, 223.9200661671849275 34.4577826049052618, 223.9355075424562074 34.4574083328668692, 223.9508457646352610 34.4570345511811382, 223.9660146266251388 34.4566629441688335, 223.9810473116705793 34.4562927476240048, 223.9957878473969970 34.4559279256362743, 224.0106582442445529 34.4555579476699094, 224.0255459276818897 34.4551856180930542, 224.0403444766139387 34.4548136399185267, 224.0550707902652334 34.4544416140811975, 224.0696826278544052 34.4540706528632938, 224.0842130299626263 34.4536999451661785, 224.0986612451181657 34.4533295402476725, 224.1130364689962846 34.4529592283796049, 224.1273202300026526 34.4525895194552589, 224.1415662443137080 34.4522190340582313, 224.1557339918701928 34.4518488559867535, 224.1698107918634832 34.4514793494806213, 224.1838116920759205 34.4511101458139137, 224.1977227034650468 34.4507416459917550, 224.2115924901561925 34.4503725738795765, 224.2254006440731189 34.4500034947196099, 224.2391929104418011 34.4496331904989930, 224.2529511041201147 34.4492621618858905, 224.2666975062597032 34.4488898121368337, 224.2803860065869230 34.4485174107728724, 224.2940079847325876 34.4481452153055372, 224.3075938798929769 34.4477724066462798, 224.3210795841820016 34.4474007776905964, 224.3344990942463824 34.4470294144046747, 224.3478450164866160 34.4466585461289299, 224.3611125161874043 34.4462883334162768, 224.3742955932316647 34.4459189716522971, 224.3874260849342761 34.4455495872321080, 224.4004958876057856 34.4451804279779665, 224.4135260618235463 34.4448109130245967, 224.4264828608882851 34.4444420219817644, 224.4393721008929674 34.4440736115621817, 224.4522012232969246 34.4437054889999175, 224.4649910968828976 34.4433370695209646, 224.4777393619576742 34.4429684345123519, 224.4904489206323319 34.4425995128584432, 224.5030718093360065 34.4422317208438216, 224.5156259768971552 34.4418645587055465, 224.5281770922005649 34.4414961127534767, 224.5407219882421543 34.4411264780584858, 224.5531975742589452 34.4407575293592885, 224.5656264624836638 34.4403886150134326, 224.5780227094902557 34.4400193297392363, 224.5903757296908907 34.4396500013147318, 224.6026728254212514 34.4392810252896453, 224.6148668913225777 34.4389138407199553, 224.6269709753774748 34.4385480837916518, 224.6390599334265801 34.4381815076603033, 224.6511372139711682 34.4378140121817324, 224.6632067785133415 34.4374454801668364, 224.6751614661790484 34.4370792014152798, 224.6870933909691246 34.4367123756374696, 224.6989898632640177 34.4363454016597004, 224.7108678965566924 34.4359777634713211, 224.7226881483816214 34.4356106889183309, 224.7344958302644216 34.4352427865472706, 224.7462652761451523 34.4348748626036922, 224.7579793002262250 34.4345074672970668, 224.7696431367384662 34.4341404523806460, 224.7812728007898784 34.4337733275599120, 224.7928435544069998 34.4334068854894326, 224.8043847867309353 34.4330402109262224, 224.8157283419711803 34.4326786627865218, 224.8270886232934060 34.4323154551121036, 224.8384166745524055 34.4319521503576382, 224.8497524406660091 34.4315874760106553, 224.8610108250167912 34.4312241690653735, 224.8722867697131846 34.4308591870978873, 224.8835699922119318 34.4304928586050423, 224.8948651191246029 34.4301250319575729, 224.9061662755927102 34.4297558956340097, 224.9173542816808151 34.4293893381866312, 224.9284086365247788 34.4290260616188277, 224.9394220907957731 34.4286630586182127, 224.9504388176732732 34.4282988871563020, 224.9614347391370757 34.4279343412270151, 224.9724090215384535 34.4275694544292747, 224.9833614191897198 34.4272042411422632, 224.9942931924760217 34.4268386657352465, 225.0052127358026155 34.4264724542664453, 225.0161268911613490 34.4261053817509790, 225.0270072241671642 34.4257384031269424, 225.0379099782930155 34.4253696378408520, 225.0487812548864497 34.4250008963959999, 225.0595876459219085 34.4246333158877533, 225.0703030757051124 34.4242677965401498, 225.0809691073957026 34.4239029512769577, 225.0916138569897953 34.4235378364048401, 225.1022391575984898 34.4231723953056488, 225.1128542317351560 34.4228063180293447, 225.1234516167833704 34.4224398635157769, 225.1340217161965143 34.4220733665334393, 225.1445720848772112 34.4217065741966124, 225.1551012336176711 34.4213395433927616, 225.1655864785994652 34.4209730651206698, 225.1760248993734024 34.4206072521105142, 225.1864409930115016 34.4202412644615734, 225.1968389824733663 34.4198749609670358, 225.2072200098128292 34.4195083066778409, 225.2175785697202173 34.4191414990644020, 225.2279161215508907 34.4187744928887582, 225.2382328071170434 34.4184072887788943, 225.2485261485775254 34.4180399796766920, 225.2587970262803196 34.4176725406107877, 225.2690410352502397 34.4173051335256162, 225.2792535965347156 34.4169379279163223, 225.2894249396169357 34.4165712794060852, 225.2995612323846899 34.4162049783027584, 225.3096797795433019 34.4158384149443961, 225.3197769941335196 34.4154717224572764, 225.3298508715252240 34.4151049782719838, 225.3399032249960783 34.4147381230934144, 225.3499338576661728 34.4143711695009458, 225.3599442461321587 34.4140040696647063, 225.3699387631442050 34.4136366704509840, 225.3799126564645974 34.4132691483703823, 225.3898592055722361 34.4129017528991312, 225.3997746327126492 34.4125346283236908, 225.4096413759755251 34.4121684231094775, 225.4194664480607742 34.4118028921399812, 225.4292333250941738 34.4114386506334498, 225.4389847119331023 34.4110741438095218, 225.4487227950638157 34.4107092950619133, 225.4584529700543953 34.4103439088416181, 225.4681791118330807 34.4099778441967885, 225.4779501834490532 34.4096092904921349, 225.4877658689403006 34.4092382501921534, 225.4975606254003537 34.4088671491675058, 225.5073160520655335 34.4084966774081735, 225.5170945589583482 34.4081245163349934, 225.5268331233713184 34.4077530164327072, 225.5365021994149686 34.4073832928032530, 225.5461190551239667 34.4070147129218711, 225.5556995065028616 34.4066466938672235, 225.5652214497782495 34.4062800756483327, 225.5747432098521870 34.4059126712269503, 225.5842560908630503 34.4055448095740530, 225.5937778006220924 34.4051758227699693, 225.6033009158010714 34.4048059909125641, 225.6128238278465403 34.4044353752724632, 225.6223471750347187 34.4040639520835043, 225.6318758783505132 34.4036915342067857, 225.6414016415792219 34.4033184378166936, 225.6509363628139511 34.4029442090107835, 225.6604947562178154 34.4025682829215782, 225.6700415057030398 34.4021920106849919, 225.6795791566743787 34.4018152973413862, 225.6890709330851621 34.4014395611739729, 225.6985268750905789 34.4010644243483839, 225.7079299362002587 34.4006905526265783, 225.7172925181061487 34.4003174765962214, 225.7266351872285384 34.3999444072983422, 225.7359624913332823 34.3995711723549036, 225.7452560214362620 34.3991984905110115, 225.7545267975802687 34.3988259392689315, 225.7637889836436500 34.3984529709160753, 225.7730507645165687 34.3980792678529639, 225.7823252012727835 34.3977043199700319, 225.7916004169128144 34.3973285906499413, 225.8008725343052561 34.3969522323248214, 225.8101369195277073 34.3965754280255140, 225.8193892451943157 34.3961983497527015, 225.8286274988586797 34.3958210792869892, 225.8378496687750214 34.3954436987810652, 225.8470551995699225 34.3950662332777739, 225.8562326011096388 34.3946891400830950, 225.8653930029150843 34.3943119835577633, 225.8745410760834034 34.3939345816839293, 225.8836776373592272 34.3935569043987925, 225.8928019411184493 34.3931789835028283, 225.9019194640877970 34.3928006034880198, 225.9110308752082403 34.3924217392180580, 225.9201549499716748 34.3920416439267669, 225.9292743320528132 34.3916610090137596, 225.9383845714648942 34.3912800134750611, 225.9474795314271205 34.3908989044373925, 225.9565581779445154 34.3905177257819687, 225.9656244992530389 34.3901363203602841, 225.9746802477618530 34.3897546199894819, 225.9837284337537540 34.3893725057496695, 225.9927658599979452 34.3889901074685227, 226.0017891753150820 34.3886075615055873, 226.0108161763110957 34.3882241545240674, 226.0198457173643192 34.3878399331656013, 226.0288659304945611 34.3874553757630750, 226.0378750537471433 34.3870705548477460, 226.0468586590176585 34.3866860531594227, 226.0558323075063925 34.3863012459153481, 226.0647969809139681 34.3859160948657134, 226.0737494779302779 34.3855307302515882, 226.0826909505306901 34.3851451068041101, 226.0916392243409234 34.3847585069561035, 226.1005846293968773 34.3843713215450464, 226.1095237944560381 34.3839836875572402, 226.1184552396291565 34.3835956656763457, 226.1273766599941553 34.3832073496779174, 226.1362843513779808 34.3828188893593705, 226.1451789838455682 34.3824302579893555, 226.1540696341282057 34.3820410907883414, 226.1629557016546812 34.3816514125989912, 226.1718415645593439 34.3812610485458379, 226.1807230054548370 34.3808701688272080, 226.1896010103785954 34.3804787347539502, 226.1984731024782604 34.3800868460323485, 226.2073393250163065 34.3796945012311426, 226.2162010894473099 34.3793016444904183, 226.2250584402858919 34.3789082745362577, 226.2339210610156215 34.3785140099352446, 226.2427791039919782 34.3781192423320618, 226.2516314343375541 34.3777240168996130, 226.2604782195431596 34.3773283272096037, 226.2693193564147975 34.3769321772337477, 226.2781549132838563 34.3765355639965051, 226.2869854330445492 34.3761384661654574, 226.2958114626248403 34.3757408625677527, 226.3046334835771916 34.3753427349447165, 226.3134536502230674 34.3749440038212839, 226.3222666039622766 34.3745448675869412, 226.3310674200996004 34.3741454965106072, 226.3398662973823150 34.3737455139908690, 226.3486632146742750 34.3733449207269857, 226.3574580470472029 34.3729437205967017, 226.3662507195246860 34.3725419149322065, 226.3750416931363532 34.3721394877985631, 226.3838307521613444 34.3717364446176177, 226.3926183115108017 34.3713327721326820, 226.4014042158853215 34.3709284729464244, 226.4101886820695597 34.3705235397049833, 226.4189713667433921 34.3701179688711562, 226.4277528949880889 34.3697117359900091, 226.4365339441966398 34.3693048460955524, 226.4453141371934350 34.3688973009586505, 226.4540932758127099 34.3684891262240271, 226.4628714412480122 34.3680802909390763, 226.4716492125863283 34.3676707554959009, 226.4804266127540302 34.3672605340833428, 226.4892039200704801 34.3668496114387665, 226.4979812270978812 34.3664379860402107, 226.5067586403135067 34.3660256539006355, 226.5155350783880408 34.3656126841276830, 226.5243113274251243 34.3651990254047561, 226.5330863836865376 34.3647847378263478, 226.5418613931289258 34.3643697520983480, 226.5506364357650853 34.3639540648019590, 226.5594125115576958 34.3635376201860510, 226.5681899791721605 34.3631204005483397, 226.5769703953611440 34.3627023214857346, 226.5857530174882584 34.3622834276468296, 226.5945393457471937 34.3618636384960965, 226.6033280977034110 34.3614430267663522, 226.6121204829147757 34.3610215277183073, 226.6209149844799811 34.3605992248943437, 226.6297112468536454 34.3601761375814263, 226.6385086581363737 34.3597522984602293, 226.6473076485090985 34.3593276840232207, 226.6561088518998304 34.3589022601832568, 226.6649128221964418 34.3584759974265594, 226.6737198569213092 34.3580488800413519, 226.6825293890468345 34.3576209381841835, 226.6913400811815791 34.3571922425097895, 226.7001540295765665 34.3567626816808058, 226.7089712049737784 34.3563322571852368, 226.7177870375251700 34.3559012099768566, 226.7266041828170557 34.3554693992389986, 226.7354247297490417 34.3550367145668503, 226.7442492611550620 34.3546031251242496, 226.7530788599071343 34.3541685737676445, 226.7619128745897967 34.3537330945821253, 226.7707514832152640 34.3532966779086308, 226.7795960290101789 34.3528592527795595, 226.7884459906964878 34.3524208461996707, 226.7973003349474084 34.3519815119966054, 226.8061593642153468 34.3515412337323127, 226.8150233317630295 34.3510999975137565, 226.8238934698289029 34.3506577379327425, 226.8327720567431243 34.3502143344744155, 226.8416573813301227 34.3497698762916741, 226.8505497655433487 34.3493243455891957, 226.8594358490772436 34.3488784447269566, 226.8683250410305448 34.3484316781253654, 226.8772265485079913 34.3479835600552121, 226.8861363120379906 34.3475343031322282, 226.8950567593804521 34.3470837781793534, 226.9039829499104428 34.3466322445210253, 226.9129146681036957 34.3461797125384507, 226.9218556874186561 34.3457259818489788, 226.9308045478040583 34.3452711282402916, 226.9397756292619306 34.3448143895303843, 226.9487603184227282 34.3443562188082510, 226.9577713539547688 34.3438959389133771, 226.9667906962826578 34.3434345027780594, 226.9758185915956972 34.3429718957264001, 226.9848216200920490 34.3425098913909750, 226.9938252716526392 34.3420471374261354, 227.0028484628124374 34.3415826267594966, 227.0118809439772747 34.3411169021390208, 227.0209235817801527 34.3406499156235370, 227.0299791781036731 34.3401815158195447, 227.0390478253054027 34.3397116954515838, 227.0481467096718404 34.3392395333767055, 227.0572602651140244 34.3387658574177408, 227.0663771858125699 34.3382912703768639, 227.0755008947202782 34.3378155877347027, 227.0846303913166366 34.3373388616534996, 227.0937637964131568 34.3368611917211837, 227.1029086135133923 34.3363821733254966, 227.1120687985236088 34.3359015911655234, 227.1212359111510466 34.3354198971173830, 227.1304019305156885 34.3349375223437292, 227.1395758196098598 34.3344539825448578, 227.1487597349369594 34.3339691593658429, 227.1579902583356443 34.3334810704759406, 227.1672328061998201 34.3329915812164259, 227.1764712677046134 34.3325015630314354, 227.1857181919857283 34.3320103346922849, 227.1949746843133369 34.3315178341564717, 227.2042427831939904 34.3310239482967248, 227.2135235122933352 34.3305286187726253, 227.2228146140790557 34.3300319660013002, 227.2321158182220984 34.3295340024028945, 227.2414261879495143 34.3290347769039101, 227.2507440105680985 34.3285343811481169, 227.2600744088219358 34.3280325324945181, 227.2694283384067830 34.3275286268107749, 227.2787965981495120 34.3270231647176587, 227.2881796631198767 34.3265161168640773, 227.2975768164418469 34.3260075194110215, 227.3069878365992622 34.3254973813717328, 227.3164104609823823 34.3249858245100441, 227.3258502854956191 34.3244725367081287, 227.3353080996809297 34.3239574703683985, 227.3447883387158583 34.3234403755931012, 227.3542849111798887 34.3229215853955196, 227.3637955610566621 34.3224012213398026, 227.3733236581925894 34.3218790926138411, 227.3828696239779958 34.3213551716833862, 227.3924291244644280 34.3208296960991746, 227.4020038478008985 34.3203025683133305, 227.4115915765756597 34.3197739086689353, 227.4211903006696787 34.3192438265213653, 227.4308034100443479 34.3187121290633144, 227.4404322669078056 34.3181787363227286, 227.4500783315727404 34.3176435624043492, 227.4597408211635923 34.3171066472118085, 227.4694373999354866 34.3165669913513582, 227.4791525994704955 34.3160254597001710, 227.4888678788237257 34.3154830952474441, 227.4985957069134486 34.3149391921615532, 227.5083373853229887 34.3143936735036874, 227.5181018062808107 34.3138460313881950, 227.5278825759521624 34.3132966234388235, 227.5376789842386813 34.3127454859354302, 227.5475028125259200 34.3121919440088661, 227.5573500149540109 34.3116362217109199, 227.5672257339144551 34.3110780196530101, 227.5771363516755628 34.3105169659526510, 227.5870780116760272 34.3099532729219234, 227.5970431329345729 34.3093873675370276, 227.6070304509420055 34.3088193164756561, 227.6170402145555158 34.3082490997873819, 227.6270614888903765 34.3076773412009715, 227.6371021487502446 34.3071035836204459, 227.6471620472137545 34.3065278304868428, 227.6572333483002808 34.3059505296989400, 227.6673250879662760 34.3053711550849201, 227.6774425888067697 34.3047893928165664, 227.6875956283854237 34.3042046687851183, 227.6977747165123560 34.3036175255404245, 227.7079695685554555 34.3030285548814646, 227.7181855113391009 34.3024374420604161, 227.7284236548871093 34.3018441166911430, 227.7386810962531740 34.3012487425374033, 227.7489607488805348 34.3006511438891124, 227.7592652945576219 34.3000511576432885, 227.7696049562896974 34.2994481772122626, 227.7799661327518095 34.2988429927924514, 227.7903495499238886 34.2982355558257765, 227.8007531420966814 34.2976259820288192, 227.8111804589024416 34.2970140563684183, 227.8216354765312417 34.2963995373978037, 227.8321461589727903 34.2957807625227105, 227.8426781272173969 34.2951597549061091, 227.8532313530656950 34.2945365103119926, 227.8637943594928004 34.2939117050407702, 227.8743681842962587 34.2932852743101577, 227.8849595330505053 34.2926568151130269, 227.8955699765722329 34.2920262286821398, 227.9062407193910076 34.2913910462530893, 227.9169476338910556 34.2907526962729889, 227.9276713907483440 34.2901123277708351, 227.9383745218362662 34.2894721855655291, 227.9490646281831516 34.2888318174489868, 227.9597329801701449 34.2881917519581734, 227.9704830712530566 34.2875457532932586, 227.9813063056518274 34.2868943187017976, 227.9922004455687841 34.2862375637550514, 228.0031311318225562 34.2855775502003368, 228.0140933799823131 34.2849145701225098, 228.0250913628565002 34.2842483610778288, 228.0361342648512561 34.2835783542065613, 228.0472235720056347 34.2829044463310098, 228.0583488204652554 34.2822272628251881, 228.0695055535670406 34.2815470657211065, 228.0806796288661360 34.2808647114043836, 228.0918858625117878 34.2801792865077033, 228.1031233132365514 34.2794908394532101, 228.1143887119449971 34.2787995620822130, 228.1256453028485112 34.2781077090888360, 228.1369030524275274 34.2774146678621392, 228.1481798443755622 34.2767193332271631, 228.1595524441827934 34.2760169519051701, 228.1709717100000319 34.2753105403554841, 228.1824155794543856 34.2746014535235375, 228.1938803830029485 34.2738899119352922, 228.2054189265560353 34.2731726235596810, 228.2170280980706139 34.2724497608497956, 228.2287243267068959 34.2717202776988046, 228.2405154509112037 34.2709836584987997, 228.2523281114776239 34.2702444678747824, 228.2641942766882437 34.2695006944831206, 228.2760966165648711 34.2687534104680722, 228.2880311232977988 34.2680028567512593, 228.3000080489333072 34.2672483774468546, 228.3120073191959989 34.2664912261056216, 228.3240136615099800 34.2657323607451758, 228.3360270491643007 34.2649717804314520, 228.3480846101165582 34.2642071288157126, 228.3601573792890065 34.2634402313343926, 228.3722738818183871 34.2626692688685708, 228.3844436939062348 34.2618936178111539, 228.3966618612857644 34.2611135776317255, 228.4089824127922839 34.2603256808091956, 228.4213463879780193 34.2595336690668120, 228.4337530236612963 34.2587375774857605, 228.4462104847152375 34.2579368681708800, 228.4587268133362272 34.2571310076859561, 228.4712928807849721 34.2563205652336222, 228.4839104809881007 34.2555054090236197, 228.4966228686317891 34.2546827270765490, 228.5094182245648540 34.2538532539692540, 228.5222741771274855 34.2530184132893822, 228.5351729278166033 34.2521793410414617, 228.5481108241845618 34.2513362605628799, 228.5610933369399618 34.2504888022591274, 228.5740744626683636 34.2496399537065201, 228.5870890608517811 34.2487874359031821, 228.6001377310894043 34.2479311982220693, 228.6132200400596162 34.2470712574984901, 228.6263499086052491 34.2462066876373896, 228.6395379494545637 34.2453367741270043, 228.6528307701336189 34.2444584248851456, 228.6663763632333257 34.2435618321322011, 228.6803617216170892 34.2426345403197061, 228.6952015541903620 34.2416489116415832, 228.7105525888642035 34.2406274235320396, 228.7265499348332582 34.2395608902072439, 228.7421439706292858 34.2385190300593010, 228.7570825716324521 34.2375188386587865, 228.7710598753529894 34.2365810240282045, 228.7833530683749075 34.2357543577950807, 228.7952800700831233 34.2349509230009801, 228.8072627602569185 34.2341424759793682, 228.8196514308505414 34.2333054216227595, 228.8331287442352675 34.2323936078464115, 228.8473922131562688 34.2314270979659483, 228.8618442087584413 34.2304460497713166, 228.8763439298335243 34.2294599387119689, 228.8909482643491060 34.2284648839078045, 228.9056482136916770 34.2274614587345098, 228.9203772896395890 34.2264541587584148, 228.9351647839234545 34.2254409727998450, 228.9499300140707589 34.2244273972626445, 228.9641311147009333 34.2234505681394765, 228.9782062980557669 34.2224806099827106, 228.9925852306303398 34.2214880257808645, 229.0081810669800007 34.2204098059551640, 229.0243240483594889 34.2192917030581967, 229.0404841061019283 34.2181701533113198, 229.0561546197810969 34.2170802519522255, 229.0718159793702853 34.2159888444596945, 229.0875983321533056 34.2148868823155254, 229.1034887026928004 34.2137752211918809, 229.1195460111532896 34.2126497038872159, 229.1358158382387558 34.2115070741073524, 229.1519329161660607 34.2103728455041747, 229.1680640638883517 34.2092353650362426, 229.1841528314728578 34.2080985980237031, 229.1997352210188694 34.2069952675951967, 229.2145400585694972 34.2059447195266699, 229.2300224803311437 34.2048443142917975, 229.2467979267760825 34.2036501662421912, 229.2636965491443277 34.2024448212973979, 229.2805688058146245 34.2012388685526361, 229.2975531551233246 34.2000224457226238, 229.3153572084358416 34.1987449442458384, 229.3330755456258885 34.1974708312597429, 229.3499864415034040 34.1962519261840683, 229.3671162393767702 34.1950147939658038, 229.3845622241224191 34.1937523319199954, 229.4014568277746662 34.1925270212033965, 229.4184179980011322 34.1912944082572778, 229.4358437587540038 34.1900256223242351, 229.4537366314658584 34.1887202761171025, 229.4717783256507175 34.1874013196513218, 229.4899255387707058 34.1860718421938827, 229.5081725982567775 34.1847322093504999, 229.5265398704963786 34.1833808832579891, 229.5450922296048759 34.1820130472504360, 229.5638787833001402 34.1806250030231169, 229.5833013117778023 34.1791870290052202, 229.6027619755554099 34.1777429731369509, 229.6217226069066726 34.1763326527845237, 229.6405847438591081 34.1749265203992252, 229.6596052490946533 34.1735055273340578, 229.6788397630498650 34.1720654517923776, 229.6983584810098478 34.1706009483859035, 229.7180957279812219 34.1691167911207643, 229.7380788626611263 34.1676108188230998, 229.7584117626854550 34.1660750989132396, 229.7790969056432289 34.1645092649621276, 229.7996369176329097 34.1629506915652073, 229.8203742932714704 34.1613735311363484, 229.8416825811115984 34.1597493412740860, 229.8624957634752377 34.1581588785921895, 229.8824174025969569 34.1566326127754323, 229.9024284096689144 34.1550960778056378, 229.9235693656378601 34.1534695744187502, 229.9452549995014294 34.1517974116377729, 229.9672683739301817 34.1500959777489044, 229.9895003849294710 34.1483735025368276, 230.0115335642039156 34.1466621287874403, 230.0333871041810596 34.1449604786043466, 230.0555507514716567 34.1432306179809899, 230.0779079317148330 34.1414814475759130, 230.1005423000524388 34.1397063292871081, 230.1238833343782630 34.1378715064771256, 230.1469833845026187 34.1360508854269042, 230.1701524619201678 34.1342202325624200, 230.1934678024790060 34.1323734190313033, 230.2165682856802960 34.1305388895065107, 230.2389046257789005 34.1287602695711669, 230.2627494181247698 34.1268575757474579, 230.2877550267283198 34.1248575756022205, 230.3121994425836476 34.1228969831181317, 230.3374538175096120 34.1208664279546028, 230.3631413116225133 34.1187956310741356, 230.3880206607657612 34.1167841714595141, 230.4129740677120708 34.1147614026917765, 230.4381720996361480 34.1127134836087862, 230.4639006138309298 34.1106170798748565, 230.4899617774267995 34.1084879303948512, 230.5160751630342020 34.1063486758620016, 230.5424933623108927 34.1041786332811867, 230.5692512088620276 34.1019747430089453, 230.5962633488684617 34.0997437898788007, 230.6233712572499996 34.0974986647175911, 230.6505324127057861 34.0952428144592616, 230.6778991777099463 34.0929635734630807, 230.7056768660169723 34.0906437346525522, 230.7338743165713595 34.0882822719611980, 230.7624290256163135 34.0858841097946978, 230.7912515729309462 34.0834564851070070, 230.8203176007993136 34.0810012491228917, 230.8496066250733918 34.0785199485614712, 230.8792222279712973 34.0760036572392337, 230.9092353386013770 34.0734461133306681, 230.9394837891377108 34.0708608099391839, 230.9699110764630632 34.0682523865335725, 231.0006928672082438 34.0656056693744418, 231.0318850272117572 34.0629155853066905, 231.0635571686774483 34.0601758150418163, 231.0955368340681275 34.0574008701336766, 231.1277395308378289 34.0545978214644549, 231.1598263150407888 34.0517959464565934, 231.1923731408454330 34.0489451184201002, 231.2256091620736527 34.0460249133127490, 231.2592693972341920 34.0430580047346893, 231.2932997455274915 34.0400487930001532, 231.3276773419009373 34.0369989773432380, 231.3623788652764688 34.0339103205238871, 231.3976872584296416 34.0307573786866868, 231.4333912448802835 34.0275584578912600, 231.4693555746312938 34.0243253059695263, 231.5059110724540687 34.0210279683691894, 231.5428878342202950 34.0176812112380915, 231.5803120488347986 34.0142822697345366, 231.6182257697056741 34.0108269012201632, 231.6563923558207989 34.0073361889263168, 231.6951328870011366 34.0037805360143324, 231.7344016753585265 34.0001635696372659, 231.7741163313762058 33.9964923488041038, 231.8144687461487479 33.9927486901788853, 231.8555242505766216 33.9889258811520563, 231.8967616380552670 33.9850717164518130, 231.9384874592184360 33.9811573545971939, 231.9810031243190451 33.9771540024942595, 232.0239997222691954 33.9730898996246466, 232.0678388327840196 33.9689303372336511, 232.1123373517277173 33.9646917582202263, 232.1571892772158776 33.9604025762485833, 232.2028902909501653 33.9560149644209943, 232.2491821770447586 33.9515527435587856, 232.2960411962156684 33.9470175078811138, 232.3439306823469224 33.9423637057929639, 232.3925149926378708 33.9376227334375287, 232.4421795019477770 33.9327560903862349, 232.4923819961882998 33.9278156109880626, 232.5436698047576556 33.9227466787319827, 232.5951687842406557 33.9176343955935238, 232.6475716307198240 33.9124096239599595, 232.7012278930467346 33.9070362580223446, 232.7556828037787682 33.9015582139112155, 232.8111272810917001 33.8959551460958295, 232.8675924455262702 33.8902225111621433, 232.9251556044794143 33.8843509815864010, 232.9836292775353286 33.8783581195323649, 233.0432332674164400 33.8722199923504235, 233.1036814246864708 33.8659644314341151, 233.1655576137318917 33.8595295606771813, 233.2282972755673995 33.8529720149464808, 233.2926253692222645 33.8462144248319277, 233.3579653179242541 33.8393149568011040, 233.4238324437640415 33.8323232701535375, 233.4921199961686398 33.8250368578672607, 233.5612785481939682 33.8176174604836248, 233.6323604438100574 33.8099502308989202, 233.7049545857653357 33.8020762209204406, 233.8182991445655148 33.7896946458200134, 233.8076783557392844 33.7447740760724102, 233.7998654011062740 33.7148953256736661, 233.7932629561771023 33.6848734802199203, 233.7861628101647398 33.6549060539809801, 233.7789837255724592 33.6249473535796923, 233.7720906043676337 33.5949576441517905, 233.7652839160762710 33.5649586921184238, 233.7589060738643525 33.5349132706626207, 233.7517431066790436 33.5049534537354603, 233.7450565239172420 33.4749420231280084, 233.7379505258526251 33.4449763723866766, 233.7308295414698023 33.4150243381497702, 233.7242191499058777 33.3850282755635135, 233.7176837140834778 33.3550243508337445, 233.7104637037344332 33.3250949207454283, 233.7037951297865561 33.2951059584761495, 233.6969896131439555 33.2651321095282313, 233.6904520014108471 33.2351295392698205, 233.6839655344220432 33.2051217508838903, 233.6776362432357814 33.1750972922216363, 233.6713273763780592 33.1450709789124218, 233.6650336685162017 33.1150141729347567, 233.6588931500002673 33.0849135251535671, 233.6523355921055440 33.0548582796346082, 233.6458035459005771 33.0248006321385859, 233.6396266475098855 32.9947050417191363, 233.6328262777451528 32.9646770727565652, 233.6263157235730716 32.9346182245408414, 233.6201019862021440 32.9045277918066361, 233.6138813255328728 32.8744385265793895, 233.6078758607291377 32.8443265296595897, 233.6023369694749761 32.8141924448693914, 233.5965215296104134 32.7841148116448693, 233.5900696181316221 32.7541061100910511, 233.5839479134551766 32.7240623816349085, 233.5779092339842009 32.6940102333867202, 233.5721905522068482 32.6639242446676761, 233.5664878180397750 32.6338370959040489, 233.5606393436885071 32.6037661404638328, 233.5545676760823994 32.5737196662976416, 233.5484857501460851 32.5436748334087724, 233.5423010703506748 32.5136296252895605, 233.5364558612425583 32.4835373137503041, 233.5313901280946993 32.4533621535309535, 233.5260353904142221 32.4232185508870856, 233.5202587527669778 32.3931206913267502, 233.5146035194866272 32.3630104515424222, 233.5093712471110621 32.3328556363844797, 233.5038771811895515 32.3027294443701365, 233.4977186320861620 32.2726748383608353, 233.4930474105640883 32.2424621079688691, 233.4876916605201131 32.2123231300434014, 233.4821842764592930 32.1822010034299595, 233.4768335607839731 32.1520628567095486, 233.4714406214751250 32.1219299078722926, 233.4658767395064274 32.0918158715725568, 233.4603193863103456 32.0617018370813724, 233.4546018314543403 32.0316055577751655, 233.4492417169385305 32.0014719577786408, 233.4438519928069127 31.9713422452091862, 233.4387441444417846 31.9411833186332927, 233.4332543976345278 31.9110895894751430, 233.4279025401596073 31.8810045640719721, 233.4228612077933747 31.8508873782874389, 233.4182867799428323 31.8207214887006380, 233.4137958985702994 31.7905476271530638, 233.4091213854783575 31.7603941367911169, 233.4049626521196217 31.7301868809418508, 233.4000218950841088 31.7000634190378570, 233.3956307140700233 31.6698826497173940, 233.3912285526296841 31.6397039887915454, 233.3863654215231236 31.6095496636184876, 233.3812108490931223 31.5794030233037901, 233.3764214930247647 31.5492186450269827, 233.3712958856038995 31.5190707146675706, 233.3664371276188945 31.4888954865047879, 233.3614855759494162 31.4587309793804053, 233.3562559107157881 31.4285967549954783, 233.3514176869535959 31.3984221337599188, 233.3464974125963067 31.3682571153719429, 233.3416649785913819 31.3380837861963180, 233.3370357566033704 31.3078980656429877, 233.3326926000588060 31.2776908477206064, 233.3283543150255923 31.2474841652357931, 233.3237984411670993 31.2173014484270084, 233.3201563733113630 31.1870235961301070, 233.3161539752291844 31.1567847807517389, 233.3117076071284828 31.1265937714017049, 233.3073946046734477 31.0963898212309395, 233.3030678578859920 31.0661884142667795, 233.2993582929980221 31.0359232655235395, 233.2952846677714263 31.0057013032508806, 233.2898706137018507 30.9756247954858921, 233.2854400930214638 30.9454460870698824, 233.2810898426740494 30.9152600689962966, 233.2766627467641456 30.8850832384286491, 233.2723053119124188 30.8549002336086957, 233.2680523728657818 30.8247074218793209, 233.2636521799641685 30.7945311964134980, 233.2591027842478297 30.7643717493903424, 233.2546414050185604 30.7342042433572260, 233.2506562861356940 30.7039706244563426, 233.2467369641307187 30.6737148086030302, 233.2427805480534175 30.6434640874720650, 233.2385517312377772 30.6132430614613469, 233.2344389276111656 30.5830111238563624, 233.2299877366457679 30.5528157618508374, 233.2257982908240876 30.5225942776314305, 233.2217217532980840 30.4923622458843120, 233.2176771245489988 30.4621281374324049, 233.2137964699007853 30.4318781879304439, 233.2097454203957341 30.4016647913437019, 233.2057591351303358 30.3714624983463217, 233.2018658244191442 30.3412518221078713, 233.1983368207843057 30.3110045113542377, 233.1950055562028012 30.2807379628041815, 233.1910414292614746 30.2505386796001474, 233.1869772190646586 30.2203511523385657, 233.1830901402670975 30.1901465393102377, 233.1794783589644737 30.1599146576620107, 233.1757773773749989 30.1296934417632229, 233.1722560009927747 30.0994674152873110, 233.1687829365628488 30.0692496090581187, 233.1658541342196713 30.0389767430632233, 233.1620808955631787 30.0087930485502277, 233.1588749391160036 29.9785519405028396, 233.1559315826975194 29.9482850952164839, 233.1527191120001987 29.9180476908550155, 233.1490152120511539 29.8878627530512802, 233.1454660012045110 29.8576632771394337, 233.1419748986445200 29.8274592962643155, 233.1386221229301157 29.7972068881939443, 233.1354222996520775 29.7669064200697555, 233.1321987806778111 29.7366099145259462, 233.1287646339106061 29.7063367169151213, 233.1249313654054731 29.6761063159270684, 233.1220139236395141 29.6457827103326998, 233.1188729633671528 29.6154837702841469, 233.1158897578935694 29.5851700817296219, 233.1129060558034212 29.5548580151006348, 233.1097027534003132 29.5245702145127638, 233.1060308751670505 29.4943542030171777, 233.1030157298852714 29.4640926276711390, 233.1003286570318096 29.4337988231179217, 233.0970667660271261 29.4035659761816781, 233.0939216354774146 29.3733227154140266, 233.0914405248284140 29.3430126359769723, 233.0892994125091775 29.3126692047905166, 233.0864370860244890 29.2824018148342624, 233.0833059928162925 29.2521637969537380, 233.0798611695786633 29.2219597641900286, 233.0767658946444385 29.1917159752629622, 233.0741653567458229 29.1614178213726909, 233.0714592766690316 29.1311322608294709, 233.0691085548965873 29.1008118859508755, 233.0669859435312219 29.0704698213958359, 233.0646000464743111 29.0401566075977229, 233.0623254502005466 29.0098337354568763, 233.0599712946662407 28.9795208338659016, 233.0579595884441346 28.9491745543564143, 233.0558388365095084 28.9188413004222795, 233.0535929816558962 28.8885281727702647, 233.0509336215500298 28.8582644838345956, 233.0484902872003090 28.8279804501034960, 233.0461331877589259 28.7976894107283243, 233.0439665710967461 28.7673806940561079, 233.0414570010328816 28.7371090088214203, 233.0391116854718234 28.7068223524751680, 233.0370048387185022 28.6765131456987419, 233.0348243775728179 28.6462133813567021, 233.0330010679013242 28.6158789535341676, 233.0304746245395791 28.5856129846313962, 233.0286462270461243 28.5552723099840797, 233.0268282983200834 28.5249325127422111, 233.0251892967659160 28.4945763674655979, 233.0236492160511830 28.4642120804781307, 233.0216710322505662 28.4338945752169856, 233.0190107084426643 28.4036487709723993, 233.0155390262757464 28.3734878154611287, 233.0143448253442386 28.3430961140498887, 233.0278943780121494 28.3111997840711460, 233.0452809698434180 28.2789297974504876, 233.0538801868136716 28.2475774812234555, 233.0540378632448153 28.2170916750566754, 233.0514064044016891 28.1868935460459262, 233.0496229054492687 28.1566106845398991, 233.0476411798062486 28.1263501944621304, 233.0441194682380797 28.0962492620561157, 233.0341409717331373 28.0668100505320304, 233.0153741898771500 28.0382686000289034, 233.0004333567423487 28.0093363854566064, 232.9972881861681913 27.9791801262417223, 232.9993411005298753 27.9484743605224644, 232.9983878809803741 27.9180767981850586, 232.9974132543352994 27.8876834820373602, 232.9971909981366309 27.8572156702974922, 232.9974206262448320 27.8267039819090769, 232.9991271908102703 27.7960441286443896, 232.9988925050664079 27.7655839771085944, 232.9983849067554615 27.7351537289281751, 232.9981358337880124 27.7046993241341077, 232.9979406144902327 27.6742459305966797, 232.9973331043104849 27.6438407396223162, 232.9969083003112758 27.6134191466129373, 232.9955846571345148 27.5830911072028861, 232.9941832110630173 27.5527731349511313, 232.9927614102022062 27.5224593941914435, 232.9909342121382565 27.4921890016659134, 232.9892014227767163 27.4619111836640784, 232.9875646312250410 27.4316257932675889, 232.9859715998679235 27.4013381507594609, 232.9844618800341038 27.3710308152145565, 232.9831301961564236 27.3406948742749663, 232.9812344263087596 27.3104183230413042, 232.9795154248170945 27.2801260120652422, 232.9777760155538999 27.2498379521226610, 232.9759881446979080 27.2195569911253408, 232.9743987955568798 27.1892581126147306, 232.9724422540764692 27.1589986416692817, 232.9710006231002808 27.1286892326648044, 232.9694312398512466 27.0983949971430675, 232.9677718297319586 27.0681385419024529, 232.9663065924550835 27.0378897586984657, 232.9647122084953708 27.0076563768405258, 232.9632108019172563 26.9774159299952423, 232.9624382312054536 26.9471041591346427, 232.9608332108651894 26.9168789199543426, 232.9595006772152317 26.8866285152324522, 232.9582666500766663 26.8563705517459042, 232.9569340897762970 26.8261249400095032, 232.9555697153213600 26.7958849475800811, 232.9540105067477498 26.7656486147443076, 232.9527978929963297 26.7353622722907360, 232.9512285983535378 26.7051143125580559, 232.9495631766029646 26.6748784415665874, 232.9481597763486320 26.6446185607465722, 232.9468211915520328 26.6143545712232701, 232.9455220608922446 26.5840890432255001, 232.9444815503003099 26.5537999146764108, 232.9434632614739087 26.5235110166970252, 232.9423876672174742 26.4932303685438661, 232.9410842157564616 26.4629798539371883, 232.9403624189048969 26.4326777460198521, 232.9396041412685463 26.4023818137952766, 232.9388553652086671 26.3720874366158959, 232.9379739978124064 26.3418089139282472, 232.9370099805134089 26.3115412220007663, 232.9362059739284518 26.2812599774032769, 232.9348916672720122 26.2510325502417778, 232.9334250950644218 26.2208229423210284, 232.9324016334897749 26.1905713682343553, 232.9311704869606103 26.1603384996333119, 232.9303893323872501 26.1300585886270973, 232.9300988483554988 26.0997320521378064, 232.9293959367909110 26.0694495268807742, 232.9289824929020654 26.0391405994968608, 232.9283419497587602 26.0088570938849735, 232.9278165732610546 25.9785646927101510, 232.9272763552040146 25.9482764442996050, 232.9267706905466184 25.9179874048848511, 232.9261942505102638 25.8877081399530056, 232.9258091142976923 25.8574301293123199, 232.9253729631479359 25.8271767461033015, 232.9250322467842409 25.7969165646708269, 232.9245843107218548 25.7666698797693599, 232.9239504593549270 25.7364445666975961, 232.9235341865952478 25.7062002607836533, 232.9230012917690829 25.6759704063114818, 232.9226690193477509 25.6457232921350631, 232.9226132999874892 25.6154513535304353, 232.9150552114602988 25.5859316028602848, 232.8936694310440032 25.5577742986996057, 232.8939981151967231 25.5274354892758844, 232.8871335343198439 25.4978160974558179, 232.8887091718953002 25.4673586054155798, 232.8922064207983169 25.4367126146094762, 232.8868205498047246 25.4069539371533324, 232.8861789771161739 25.3767256515738815, 232.8896075073666907 25.3460952225068219, 232.8903602006875531 25.3157339583677192, 232.8748967990593144 25.2869877947244071, 232.8752235979695229 25.2566931371486589, 232.8833196439118183 25.2256473618161934, 232.8834961134431580 25.1953915187146507, 232.8791447910442685 25.1655882795533792, 232.8897702203602194 25.1343006931767015, 232.8853444316087575 25.1045109216644882, 232.8872280495081100 25.0740976057525522, 232.8902362622278019 25.0435757491991779, 232.8862748867546202 25.0137485696416704, 232.8849087062121725 24.9836667520389497, 232.8615346640524137 24.9557290632232345, 232.8678976818526962 24.9248117500771507, 232.8743034753069878 24.8938930840084680, 232.8845475797327254 24.8625970346218779, 232.8855128348221228 24.8322231886131064, 232.8777881082821182 24.8027129310068233, 232.8784568385611919 24.7723743243434384, 232.8786887745970375 24.7420819508267087, 232.8815993163316591 24.7115274839343435, 232.8784925565861386 24.6815715074198145, 232.8815424169745825 24.6510284568962135, 232.8869768013755674 24.6202706778437523, 232.8897726972001578 24.5897771075858564, 232.8919278220672595 24.5593500892406809, 232.8953674056151613 24.5287991651643615, 232.9021488669385462 24.4979207774778374, 232.9056599565166152 24.4673691600329164, 232.9257127387058972 24.4351830391531237, 232.9278565930877392 24.4047732977111593, 232.9273534146259408 24.3746289061276578, 232.9234286292099796 24.3448402482100512, 232.9185075686192761 24.3151662051370252, 232.9128959411231108 24.2855631931675298, 232.9070540531588165 24.2559856151622277, 232.8961746199531717 24.2269078414204557, 232.9058387542875153 24.1958055537192749, 232.9164472389689990 24.1646132187130291, 232.9149758563926582 24.1346168714037397, 232.9260815435628160 24.1033822324320468, 232.9207352822060670 24.0737751791980372, 232.9205249605221866 24.0436696516653612, 232.9243473319641566 24.0131746924171381, 232.9256990716291398 23.9829268549958208, 232.9266943093088571 23.9527175430449475, 232.9335614596510027 23.9219326738617397, 232.9350630018510628 23.8916803410636582, 232.9319026234074954 23.8618908606751994, 232.9369458976403280 23.8312963045012332, 232.9451355783643862 23.8003951805388709, 232.9488307386481551 23.7699405111194650, 232.9458552029623206 23.7401261529633132, 232.9427960367116839 23.7103038265527815, 232.9403103649489140 23.6804281767151679, 232.9434688610449484 23.6500004099507812, 232.9430508795056198 23.6199279782520222, 232.9449167400061356 23.5896342824512395, 232.9478161718357114 23.5592424061127979, 232.9483322944067822 23.5290883733621499, 232.9513992487298424 23.4986870117375624, 232.9483282172243435 23.4688924243854835, 232.9525160945503899 23.4383831359289658, 232.9547113482703367 23.4080686363405697, 232.9583457493698688 23.3776162741469342, 232.9648502207411411 23.3468854859081070, 232.9704771618850714 23.3162444674107334, 232.9750203030245075 23.2857135186408648, 232.9746258484121313 23.2556712773452965, 232.9768106866467292 23.2253791676924131, 232.9747798685505700 23.1955045709297991, 232.9823272409721540 23.1646930636735782, 232.9805200980053428 23.1348028584585421, 232.9800513110011480 23.1047840021417699, 232.9861834586706664 23.0741209966880341, 232.9876685409769266 23.0439176472688239, 232.9885933742397128 23.0137728631401650, 232.9881698905083454 22.9837638898740160, 232.9921535043644099 22.9533263715530715, 232.9957705717595218 22.9229284916308629, 232.9981062986491054 22.8926599322135971, 232.9995218733844240 22.8624852468942876, 233.0008008871997163 22.8323477021688426, 233.0026935833242305 22.8021727726419385, 233.0044239496947682 22.7720175006826722, 233.0057530373218242 22.7419052771578087, 233.0075806209584925 22.7117480077752987, 233.0087609591471960 22.6816578595238632, 233.0110757672662203 22.6514604813964411, 233.0151590704028024 22.6210939347426994, 233.0184183698698916 22.5908118759575878, 233.0205756674862982 22.5606414628851901, 233.0227480606974382 22.5304531670131603, 233.0250768521223677 22.5002342214980828, 233.0273835969985612 22.4700212420054548, 233.0294706402721943 22.4398335481584006, 233.0316881731028786 22.4096369279992231, 233.0341946654158107 22.3794159172976741, 233.0365603857090093 22.3492125091543272, 233.0390306891929981 22.3190027500447243, 233.0410592766153286 22.2888399842653477, 233.0431174169529527 22.2586782009089497, 233.0454664224558314 22.2284912472965885, 233.0478041316646909 22.1983086670513181, 233.0502384064010357 22.1681205630593254, 233.0528883403844418 22.1379152542831186, 233.0557281583168674 22.1076952640858657, 233.0583352461068785 22.0775018126587632, 233.0611744727687551 22.0472895843784755, 233.0637403214377628 22.0171078704401069, 233.0661397272202180 21.9869462435968970, 233.0688001587987799 21.9567630612074716, 233.0711740440619337 21.9266329096976449, 233.0735499397463855 21.8965265962244473, 233.0760096404507067 21.8664160876867264, 233.0785652638046201 21.8363002183258672, 233.0812976721265102 21.8061711388645953, 233.0841357068294428 21.7760357915747491, 233.0867573444767515 21.7459255136685101, 233.0895927320220267 21.7157984762590708, 233.0924926729639992 21.6856692052388347, 233.0953242476287528 21.6555506351107141, 233.0981926111586802 21.6254055007346722, 233.1009922865536907 21.5952454446686204, 233.1038777321625162 21.5650810597818392, 233.1069268079161816 21.5349047968770648, 233.1100178874991116 21.5047284859612731, 233.1127848752224736 21.4745876776407023, 233.1157363895858339 21.4444329981013908, 233.1187424376983586 21.4142770832329568, 233.1217650249423059 21.3841236300845878, 233.1245863244884617 21.3539937827654960, 233.1273268963726366 21.3238973804095551, 233.1305399482890834 21.2937796874800682, 233.1337143133514473 21.2636699287899447, 233.1367726819510722 21.2335756021661055, 233.1400894411227114 21.2034604352046934, 233.1432770443776690 21.1733619961097617, 233.1464305632870833 21.1432710793482030, 233.1495149588512277 21.1131910862528756, 233.1522235752215124 21.0831517042852035, 233.1549393445594092 21.0531158582212967, 233.1578784004088902 21.0230452398071925, 233.1606670501793985 20.9929768901115033, 233.1635571535953773 20.9629029106699427, 233.1665348174223880 20.9328246588424527, 233.1695475093103767 20.9027472302309931, 233.1724950603652360 20.8726803152671607, 233.1757648549726696 20.8425864906893530, 233.1787021974068921 20.8125290323125753, 233.1816401402157339 20.7824757600829386, 233.1846174932388749 20.7524229386275891, 233.1881504494762680 20.7223164934008004, 233.1921430295234643 20.6921659693291815, 233.1962664407973875 20.6620071609797158, 233.1998063276291191 20.6319090106375818, 233.2034380345778004 20.6018063489747014, 233.2069263662183403 20.5717218737432859, 233.2104907509412897 20.5416344281767920, 233.2139632926385389 20.5115602149603724, 233.2177117299288511 20.4814637894575604, 233.2216593375412117 20.4513525737117519, 233.2250954112953423 20.4212992884368774, 233.2281738095738319 20.3912888538266621, 233.2317469899864477 20.3612351578772213, 233.2354300219240884 20.3311753045732040, 233.2390675346222793 20.3011242701849177, 233.2428088864080564 20.2710676843574937, 233.2463687761196525 20.2410330180378644, 233.2498879821790752 20.2110067271066391, 233.2535871092524644 20.1809675985890244, 233.2572902450487220 20.1509325720348791, 233.2609429238511893 20.1209186431063642, 233.2648017962150959 20.0909005809539210, 233.2689903577137898 20.0608554383382902, 233.2728633418433333 20.0308452349020740, 233.2765641272912660 20.0008561899774868, 233.2812223915826735 19.9707798285930203, 233.2864099439073584 19.9406573283196380, 233.2909890193867852 19.9105979388517440, 233.2950841777730489 19.8805896778848776, 233.2993632066977057 19.8505684590085423, 233.3035043231179202 19.8205651642295493, 233.3079265663008073 19.7905396135329568, 233.3128723121038774 19.7604686027104854, 233.3212245222528622 19.7300758027171099, 233.3229796645339889 19.7003201829757550, 233.3250187359038534 19.6705419579676999, 233.3295794770565976 19.6405268670267148, 233.3340133909965743 19.6105287058962290, 233.3382737275555030 19.5805519489527100, 233.3427754961723224 19.5505568791213129, 233.3472502899585095 19.5205913531204267, 233.3519176262609278 19.4906332628900785, 233.3564781233062604 19.4606903137858538, 233.3611565770676748 19.4307410165034753, 233.3661595846951684 19.4007656505168953, 233.3703104801431323 19.3708766635924832, 233.3750759453373007 19.3409339182512880, 233.3796606407786385 19.3110134145879755, 233.3838533016761971 19.2811353084243073, 233.3885185327488330 19.2512170820800179, 233.3933726859514195 19.2212448892327323, 233.3986665436496537 19.1911968866870950, 233.4036862279155002 19.1611799032164640, 233.4089951198312463 19.1311402225524070, 233.4132100095931435 19.1012097132354555, 233.4123892182743134 19.0717638283208011, 233.4234964591204289 19.0411864055395945, 233.4281169837484811 19.0112319190755770, 233.4325579593636917 18.9812994404361781, 233.4385822536837054 18.9512211316246884, 233.4443597987840917 18.9211713139256652, 233.4496248142866648 18.8911752824109413, 233.4547885793803630 18.8611938669220258, 233.4583687837339312 18.8313680827500853, 233.4655775203490293 18.8012021187732401, 233.4711529541672803 18.7711965558356795, 233.4767692009424422 18.7411921476732637, 233.4825308590468467 18.7111789652769396, 233.4883909046930341 18.6811614946118070, 233.4931291858070779 18.6512556966268157, 233.4993395500702604 18.6212150942635972, 233.5048685308843801 18.5912443274153567, 233.5077531010848020 18.5615297618665807, 233.5091049004011836 18.5319656326906959, 233.5185658770625139 18.5016369242420602, 233.5256367708339553 18.4715402439978256, 233.5301086034677098 18.4416953385034894, 233.5356064714600279 18.4117582234792359, 233.5417223965712310 18.3817676613826038, 233.5436460467195730 18.3521797092590653, 233.5515550723605998 18.3220005203202874, 233.5589133420531880 18.2918512247416238, 233.5648154770379676 18.2618450555454395, 233.5706311380743045 18.2318521979120796, 233.5766783986698556 18.2018425304721880, 233.5827366207531384 18.1718369697726807, 233.5889479384119340 18.1418220681870963, 233.5952096681106696 18.1118075671923755, 233.6015415980776879 18.0817916044220723, 233.6077510808782449 18.0517924324179297, 233.6140975235820747 18.0218088449622549, 233.6205191371487899 17.9918455352792854, 233.6266260837951450 17.9619173288110829, 233.6314207647240551 17.9321185690260378, 233.6387588021336796 17.9020845961539159, 233.6452805855884662 17.8721331937102619, 233.6514590097423252 17.8422196284782473, 233.6536283972934314 17.8126902678771657, 233.6610323497431523 17.7826716167529284, 233.6700474483215260 17.7525062282510895, 233.6710958350960539 17.7230986454165205, 233.6720554060958648 17.6937044996378177, 233.6886973681009749 17.6628357051527267, 233.6961537220093419 17.6328394070019741, 233.7027174712601152 17.6029328422529261, 233.7091451501906363 17.5730445967881366, 233.7160657900107594 17.5431153461530833, 233.7218088442428154 17.5133026583395761, 233.7188552148028862 17.4843150621013450, 233.7271703555094859 17.4542708189167719, 233.7332599408117062 17.4244219302142156, 233.7436008308865212 17.3941592972868158, 233.7537000520072752 17.3639249382731045, 233.7605219667613028 17.3340047558402972, 233.7672620564109138 17.3040977563751461, 233.7741057701255158 17.2741864873563706, 233.7809327553354422 17.2442822939548819, 233.7875483107386003 17.2144035087708893, 233.7941383358663074 17.1845326395309499, 233.8009389222396521 17.1546474914662461, 233.8078159920366375 17.1247989300419441, 233.8148671788214301 17.0949759031170920, 233.8217221649958901 17.0651770950838291, 233.8288283024689918 17.0353604671974814, 233.8358947427699945 17.0055533728241421, 233.8430006848317930 16.9757483808567251, 233.8498908003460599 16.9459694767308946, 233.8568622727080992 16.9161887643550060, 233.8644647285208578 16.8863546914665186, 233.8718372374858347 16.8565480752250991, 233.8788277070707124 16.8267648191269359, 233.8864792058807325 16.7969080412233396, 233.8943514190198982 16.7670364202283579, 233.9020695055140777 16.7371851060098820, 233.9097813333987688 16.7073402493169247, 233.9174700861480574 16.6775034345532873, 233.9253720203781484 16.6476525493578649, 233.9331663377994630 16.6178176543133098, 233.9401878297118742 16.5880610131770432, 233.9480425081271449 16.5582323063645944, 233.9556412546594970 16.5284065652410064, 233.9629737968642758 16.4985860690825987, 233.9680921310491044 16.4689784103428813, 233.9697213479607854 16.4397025376815620, 233.9810796846671792 16.4095231033484197, 233.9908449025241453 16.3794983032502621, 233.9882390150647211 16.3506347332338748, 234.0070231433400636 16.3197790877553253, 234.0069543695200309 16.2906897485448603, 234.0202099267452240 16.2603620613574975, 234.0395938018473885 16.2294890985881750, 234.0450377808692792 16.1999437004385136, 234.0561547506326292 16.1698746037453525, 234.0657880987549788 16.1399500045661242, 234.0741467787784131 16.1101503514505531, 234.0827689780276160 16.0803320887725256, 234.0912986312941086 16.0505284562681574, 234.0997996610001337 16.0207335031229654, 234.1084859987022924 15.9909272977990398, 234.1170575885181506 15.9611378324199666, 234.1256564755075260 15.9313495654430621, 234.1339108562146976 15.9015972378880655, 234.1420802546502387 15.8718588505235765, 234.1503490199092994 15.8421172466510018, 234.1587030134159590 15.8123737656591707, 234.1673976302220694 15.7826046620586595, 234.1763424357527583 15.7528183877812076, 234.1849417847580810 15.7230703711881485, 234.1933282249265744 15.6933482754193712, 234.2016185329786992 15.6636412460365406, 234.2106171187846257 15.6338769736455578, 234.2195368605031831 15.6041285516616739, 234.2284225769665795 15.5743895331352711, 234.2372086911806832 15.5446660165853068, 234.2462523004035688 15.5149248636003936, 234.2553132958508399 15.4851883878478898, 234.2644100756737657 15.4554548993284637, 234.2736046602676652 15.4257186639372303, 234.2828523114264385 15.3959838497762398, 234.2920495505410940 15.3662600700791199, 234.3012936683776388 15.3365358356850816, 234.3104367205658889 15.3068249721657903, 234.3196271964808943 15.2771160719096653, 234.3287777585348692 15.2474172380984374, 234.3378315772185942 15.2177337448744474, 234.3470225913527543 15.1880439471038624, 234.3562324231044158 15.1583588231919482, 234.3654603383477024 15.1286784580226517, 234.3747230124765792 15.0990013234532050, 234.3840690688702466 15.0693229443095333, 234.3931193445802137 15.0396518779770023, 234.4024838161147954 15.0099330830396873, 234.4122562196454851 14.9801829917323381, 234.4219962208916854 14.9504423057803333, 234.4316170042648650 14.9207190552591218, 234.4409861181379142 14.8910254702199367, 234.4498414312987506 14.8613857366758140, 234.4587504871350347 14.8317474754578118, 234.4679793072651819 14.8020861694295878, 234.4771046542925035 14.7724408809426073, 234.4864910605286354 14.7428051421218793, 234.4958127631584262 14.7132076600151365, 234.5055439072372963 14.6835791248018523, 234.5149369367873078 14.6539884211796085, 234.5241105786403750 14.6244246059913117, 234.5339142239975274 14.5948095112820919, 234.5441587295201771 14.5651606080359635, 234.5546480131773421 14.5354959818108664, 234.5650423661182913 14.5058468976702919, 234.5754610355187140 14.4762024051396061, 234.5860688582642695 14.4465433520325632, 234.5967752055062192 14.4168783190438923, 234.6069933554238673 14.3872650182268096, 234.6171960407561983 14.3576600248933914, 234.6275909408981306 14.3280442964112122, 234.6379763594737256 14.2984363661579739, 234.6483740747768820 14.2688342522723133, 234.6587419257140823 14.2392418374867304, 234.6689172495746334 14.2096740403375463, 234.6792935811320717 14.1800948047387561, 234.6895742587339555 14.1505285368724536, 234.6998764433689360 14.1209646305219891, 234.7101973306022842 14.0914059957738669, 234.7207736866026266 14.0618309836400304, 234.7321713553482709 14.0321878767122161, 234.7422176051751421 14.0026754357553020, 234.7519284357929052 13.9732006792802341, 234.7624200521307785 13.9436616004926499, 234.7730528579396037 13.9141167083922728, 234.7837173903436394 13.8845760285143545, 234.7943762589812309 13.8550429933142141, 234.8051931501391891 13.8255026825729246, 234.8161131219390256 13.7959601356991399, 234.8271065982787320 13.7664180724429972, 234.8381729425412345 13.7368765752542998, 234.8493627128006551 13.7073310573832483, 234.8607032897410249 13.6777790528320331, 234.8720694713504145 13.6482319931288494, 234.8830910537650425 13.6187235929828940, 234.8942605546816083 13.5892090201901361, 234.9053774760895408 13.5596790162479035, 234.9167511517720754 13.5301066566130839, 234.9279505694776731 13.5005571268091931, 234.9394021769243750 13.4709916702432064, 234.9508672984820805 13.4414320105289971, 234.9626054479035702 13.4118545923576491, 234.9742186443794481 13.3822955914750352, 234.9857988700492513 13.3527466655368965, 234.9970443743791861 13.3232352066904944, 235.0084582292538755 13.2937155696686453, 235.0186035071427568 13.2643211014270008, 235.0287860913971087 13.2349331360644609, 235.0400758279094475 13.2054518920066410, 235.0532193480717353 13.1758098565562349, 235.0623808490812223 13.1465356407518055, 235.0713089053979559 13.1172895510176257, 235.0793478795862939 13.0881308795317679, 235.0890015169416358 13.0588331529015118, 235.1000812578284638 13.0294136165020209, 235.1113620945289995 12.9999831139233066, 235.1208710581361743 12.9707456190127459, 235.1308498837751131 12.9414973268696496, 235.1414266551485639 12.9122024140004790, 235.1520541038566705 12.8829103201224786, 235.1634014499122998 12.8535607470035131, 235.1747883523980249 12.8242150920803972, 235.1866440079922995 12.7948347231417632, 235.1962114789104135 12.7656678887108210, 235.2079376381157090 12.7363142078543667, 235.2196871123140340 12.7069660068864572, 235.2312774292608424 12.6776330769726151, 235.2423299219807689 12.6483497753649647, 235.2530227031545564 12.6191063233042495, 235.2639126485657926 12.5898526975633196, 235.2743652030817429 12.5606458764525684, 235.2867364532864087 12.5312745148577296, 235.2990700134546671 12.5019142416230427, 235.3116402177408872 12.4725404867273895, 235.3219635475852556 12.4433757384951296, 235.3333921971896530 12.4141196266616110, 235.3448056797797676 12.3848458826281451, 235.3590332335191420 12.3553027454593227, 235.3671381952188426 12.3263147954621655, 235.3791080711625909 12.2969887533940074, 235.3920900296717491 12.2675799308306956, 235.4040194283262508 12.2382728114795736, 235.4133794107393101 12.2092026689056734, 235.4233014408581255 12.1800898429156153, 235.4339037523902789 12.1509238817774854, 235.4452218653501632 12.1217017261880322, 235.4567451865805765 12.0924663216223873, 235.4687528608969274 12.0631930260104347, 235.4810351629814988 12.0339030836567868, 235.4933681702400463 12.0046164600725405, 235.5055246782644076 11.9753533821565021, 235.5184078940019106 11.9460335670121847, 235.5314082453792821 11.9167112708404304, 235.5445464716077595 11.8873846829333019, 235.5579963618936290 11.8580384063581405, 235.5708833501624895 11.8287500973666599, 235.5855844258250045 11.7993122043465029, 235.5997815615453419 11.7699302627525313, 235.6119072769830893 11.7407400002484046, 235.6223150282435483 11.7117098584816048, 235.6370398246845639 11.6823053417586866, 235.6501699538271168 11.6530501405094533, 235.6621169133283331 11.6239076823544440, 235.6747078625160725 11.5947162930887799, 235.6884616266881380 11.5654302213482971, 235.7004696810057283 11.5363065322227509, 235.7117027570573384 11.5072525156614951, 235.7235495084901800 11.4781459017146013, 235.7365550227651454 11.4489451459608844, 235.7510142281088861 11.4196244102570095, 235.7663908710825922 11.3902311310345947, 235.7777853553805585 11.3611969641194950, 235.7887243559131321 11.3322109545492555, 235.8008595376688845 11.3031277532132108, 235.8129754068866077 11.2740544158723424, 235.8254919284307221 11.2449540515659141, 235.8380208743051867 11.2158885622036202, 235.8515631680988065 11.1867687535603633, 235.8656830632303638 11.1576068111614646, 235.8797763957555844 11.1284558105932163, 235.8938131194300354 11.0993184012236146, 235.9083699591712389 11.0701440705685776, 235.9230930845470766 11.0409638880499550, 235.9377092449555846 11.0118018071708317, 235.9515585913452185 10.9827155395166205, 235.9638727960031019 10.9537721481993806, 235.9770882459741870 10.9247372688021613, 235.9907437067807905 10.8956523468860915, 236.0047493839090578 10.8665454343556362, 236.0183438054604039 10.8374830061747325, 236.0323943911155027 10.8083894137876850, 236.0537151650663645 10.7647439316584244, 235.8067955133662394 10.7864349997889875, 235.6404746257634315 10.8009251269225022, 235.4886934161649208 10.8140812538426179, 235.3440743681718175 10.8265506526398081, 235.2013541677959552 10.8387871303979644, 235.0605785760643869 10.8507895528866580, 234.9266644391677801 10.8621511165544913, 234.7983134326763945 10.8729887160328396, 234.6742684848965155 10.8834132357187148, 234.5539738435639094 10.8934756928845555, 234.4326844057727044 10.9035680020157777, 234.3062264801342849 10.9140277809662685, 234.1842183967411302 10.9240715931274845, 234.0687460570664769 10.9335373293069917, 233.9561439769143476 10.9427259417913305, 233.8474210956715069 10.9515604135293039, 233.7435151522167303 10.9599707574291152, 233.6385624025373318 10.9684248104055904, 233.5358140067762065 10.9766660933001035, 233.4407131631619450 10.9842712723458558, 233.3422237141537039 10.9921074822156815, 233.2513957968695308 10.9993144684110149, 233.1514470230872860 11.0071956760767016, 233.0568672341352681 11.0146280042103673, 232.9714593141302430 11.0213255319049601, 232.8803341230253920 11.0284323244549292, 232.7943082344738173 11.0351214682081071, 232.7094524258564832 11.0416948896582507, 232.6269891539207606 11.0480614832230604, 232.5469229652730405 11.0542229776369663, 232.4651981313458862 11.0604848215878437, 232.3872682244211489 11.0664391550579548, 232.3089820002550709 11.0723973916103642, 232.2344266808559041 11.0780568263891919, 232.1612777882697856 11.0835918116323242, 232.0879579900228578 11.0891193379889543, 232.0165771813969968 11.0944847829274487, 231.9444953164336312 11.0998822668698640, 231.8732154220874406 11.1052019606563270, 231.8057772059925981 11.1102241836769817, 231.7386284223796906 11.1152083218847739, 231.6726527935824436 11.1200909547501574, 231.6064561948338394 11.1249729598940004, 231.5413069011313496 11.1297634611436838, 231.4780838222164050 11.1344005203999128, 231.4150219500338608 11.1390109034253335, 231.3534789037338726 11.1434985250687841, 231.2922763753067841 11.1479476252960747, 231.2321986804894038 11.1523031971319302, 231.1727759778516997 11.1565989553883931, 231.1144830584763952 11.1608020872514313, 231.0567419751372142 11.1649536385302959, 231.0002949603219236 11.1690023089595893, 230.9442330256085540 11.1730119569343618, 230.8887529573886468 11.1769692032438481, 230.8340953656646377 11.1808578017260665, 230.7801047938939121 11.1846889342734350, 230.7267933250194858 11.1884621644695272, 230.6741394301180605 11.1921793597281152, 230.6222024977125500 11.1958368476612193, 230.5710284673450019 11.1994319110143277, 230.5203688901725627 11.2029818304628144, 230.4702850162629773 11.2064827482238307, 230.4211332149715474 11.2099109379551667, 230.3722347960895434 11.2133125718895528, 230.3238995148925596 11.2166669987468879, 230.2759727552748359 11.2199848672525349, 230.2288337046721551 11.2232410798017455, 230.1821784107700068 11.2264562859122670, 230.1360978921081824 11.2296246903222876, 230.0904502465023995 11.2327559867974234, 230.0451126661421029 11.2358585089279419, 230.0005121694948969 11.2389042679665607, 229.9563201538520616 11.2419152341142485, 229.9126038169289643 11.2448872011781855, 229.8693914420509827 11.2478185506001722, 229.8266141936612712 11.2507140176866276, 229.7844926752456729 11.2535594487218464, 229.7426279584847748 11.2563810618782654, 229.7011060076305569 11.2591734075647274, 229.6601354388862433 11.2619231614147370, 229.6197463420528493 11.2646286372140878, 229.5797488137878872 11.2673023162466031, 229.5399124327023230 11.2699591633018521, 229.5003744155818879 11.2725904639326817, 229.4613780020239346 11.2751808122651180, 229.4229479289747360 11.2777288707497014, 229.3846678777139232 11.2802613604144586, 229.3465203971932738 11.2827794526095353, 229.3092627460675033 11.2852352682155779, 229.2721541795606868 11.2876759727222762, 229.2355028971780087 11.2900822055293482, 229.1990236077110410 11.2924720971991857, 229.1627789236015360 11.2948417900818434, 229.1268004674510621 11.2971894009668876, 229.0910977852357462 11.2995144425208274, 229.0558429789287516 11.3018062999761089, 229.0210984390833744 11.3040612741786095, 228.9866394069228477 11.3062935182293369, 228.9523786369141760 11.3085085479038074, 228.9184628476561159 11.3106973739286527, 228.8847576778118480 11.3128684166009119, 228.8514037966585306 11.3150131009844603, 228.8184344402619104 11.3171295215195880, 228.7856962146765909 11.3192272249858732, 228.7530968391290855 11.3213119416410706, 228.7207523182627540 11.3233766438682899, 228.6886580791978076 11.3254217054343087, 228.6568808000558022 11.3274431670293101, 228.6255699416205687 11.3294320811030538, 228.5943557727804034 11.3314109976706199, 228.5633199204047514 11.3333750202067787, 228.5325366678499108 11.3353197346958297, 228.5019329259257859 11.3372496289070188, 228.4715394680820850 11.3391629188288867, 228.4413945509391510 11.3410573865418591, 228.4114629408769019 11.3429352267224655, 228.3817510017013319 11.3447961341414079, 228.3522475214098222 11.3466408530271430, 228.3230615139402744 11.3484629748790784, 228.2940740736352154 11.3502696640891223, 228.2653336387853358 11.3520581199518542, 228.2367430860773254 11.3538341663080296, 228.2082916103172749 11.3555984904766465, 228.1800368130882362 11.3573477475009152, 228.1520392237964927 11.3590784464209342, 228.1243947355018520 11.3607850493464397, 228.0969443603487150 11.3624769794781848, 228.0696393456384499 11.3641571482644750, 228.0424929933100202 11.3658248267683604, 228.0154106641763008 11.3674855738926173, 227.9885578563570618 11.3691297953353843, 227.9618650794293728 11.3707615940505651, 227.9353348112001640 11.3723808773608202, 227.9089933044728582 11.3739861801390116, 227.8828228745994977 11.3755785815541994, 227.8568634996954358 11.3771558345525587, 227.8309964239554972 11.3787248265649730, 227.8053094676774037 11.3802805503758524, 227.7797848238633946 11.3818240807472471, 227.7544332388615373 11.3833548536377336, 227.7292690741794274 11.3848721031830866, 227.7042771344040375 11.3863767513912446, 227.6794424865441044 11.3878696987312100, 227.6547547109075538 11.3893515833046539, 227.6302153125899395 11.3908223637586801, 227.6058446822576684 11.3922809322129375, 227.5815837284643237 11.3937306712760584, 227.5574768187767631 11.3951691152893559, 227.5335303503409534 11.3965959501297114, 227.5097275399198793 11.3980121642247685, 227.4860553007846420 11.3994185320559396, 227.4625029322858438 11.4008156893180992, 227.4390700032397206 11.4022036943794784, 227.4157514915887930 11.4035828609687311, 227.3925662525314522 11.4049521734577652, 227.3695676411494162 11.4063087093438309, 227.3466880305365407 11.4076562680175826, 227.3239817936783993 11.4089918766877378, 227.3013618133137186 11.4103203927840031, 227.2788626998190580 11.4116399330742180, 227.2564905838040943 11.4129501940545577, 227.2341471861336402 11.4142566063190927, 227.2119503831889915 11.4155527167828179, 227.1898755316324809 11.4168399144063617, 227.1679212759910342 11.4181183068057432, 227.1461045131026992 11.4193870060476002, 227.1244248889508128 11.4206460692728218, 227.1028554367352115 11.4218969988970169, 227.0813921446024040 11.4231400422407940, 227.0600099683350095 11.4243765834220206, 227.0387800565358418 11.4256027995308038, 227.0176858866789757 11.4268196232913724, 226.9967364183012535 11.4280266090250624, 226.9758565800080135 11.4292278308048374, 226.9550385935750967 11.4304237238046920, 226.9342329016799624 11.4316169579053071, 226.9135052379956221 11.4328040202277563, 226.8929749480252553 11.4339785612803233, 226.8725374557993462 11.4351462062810540, 226.8522123582065149 11.4363059371368649, 226.8319968195408478 11.4374579339902098, 226.8118864201302358 11.4386024598112943, 226.7918595656133505 11.4397406845203555, 226.7719343835147185 11.4408716721278090, 226.7520928931567710 11.4419963969853438, 226.7323585007473241 11.4431136486025729, 226.7126918304236085 11.4442255234732109, 226.6930802683002923 11.4453327000192520, 226.6735784057323144 11.4464323335893017, 226.6541678320674862 11.4475254147592320, 226.6348499723092687 11.4486118924843723, 226.6156086420586746 11.4496926332811135, 226.5964513089266177 11.4507672681177528, 226.5773802830759962 11.4518356983188632, 226.5583938982821905 11.4528980320230058, 226.5394514986775789 11.4539563930335220, 226.5205720112843721 11.4550098145010306, 226.5017744116998131 11.4560573339612244, 226.4830830480069608 11.4570977194829027, 226.4644630477162934 11.4581327889146127, 226.4458929607767743 11.4591636593943687, 226.4273420018148499 11.4601919179165339, 226.4089327375857579 11.4612113075361997, 226.3905321797985835 11.4622286455691835, 226.3721760724284593 11.4632421133368112, 226.3540415653153275 11.4642427211329778, 226.3361333516400293 11.4652302892907620, 226.3181669859228009 11.4662192771337370, 226.3002739486595658 11.4672030229303115, 226.2824320913130975 11.4681826620260043, 226.2646422367363357 11.4691581650756760, 226.2469095834799475 11.4701292830936161, 226.2292344049402857 11.4710960160787376, 226.2116353879898725 11.4720574419513905, 226.1941018513874440 11.4730141135446004, 226.1766306716402255 11.4739662026907236, 226.1592231105941266 11.4749136616605583, 226.1418925461093465 11.4758558407877302, 226.1246140672839147 11.4767939954809552, 226.1074024905169324 11.4777274041137805, 226.0902695214819289 11.4786555042624929, 226.0731674626728136 11.4795806696773717, 226.0561148944913441 11.4805019915790982, 226.0391203976634529 11.4814190596774068, 226.0221853383698942 11.4823318209273602, 226.0053302814499432 11.4832392822302332, 225.9885536989950765 11.4841415383497090, 225.9718003975610259 11.4850413028381215, 225.9550662527250040 11.4859387811263236, 225.9383869128425886 11.4868322431797392, 225.9217536701607401 11.4877221247833052, 225.9051656781916506 11.4886084777220923, 225.8886411840002779 11.4894904303538095, 225.8721818201525764 11.4903679195340391, 225.8557774564285410 11.4912414492684540, 225.8394241488551870 11.4921112224597533, 225.8231345766392337 11.4929766430547797, 225.8068834000345078 11.4938389401884038, 225.7906841315599706 11.4946974768467634, 225.7745264906853890 11.4955527558965187, 225.7584156584664754 11.4964045403774602, 225.7423465946701526 11.4972530808697719, 225.7263306551170103 11.4980978487034378, 225.7103637501401749 11.4989390503598727, 225.6944403536084565 11.4997769586268905, 225.6785731333660578 11.5006109868028847, 225.6627606322026907 11.5014412173606555, 225.6469855377316946 11.5022684764026728, 225.6312478555560688 11.5030927722663794, 225.6155505187161907 11.5039139764720364, 225.5999034371616574 11.5047316362642977, 225.5843036923983220 11.5055458998858118, 225.5687372937216821 11.5063574287637582, 225.5532030184952532 11.5071662870658162, 225.5377227249439613 11.5079714709681848, 225.5222898787896781 11.5087732956897408, 225.5069090090537713 11.5095715644164116, 225.4915549235150820 11.5103674479623592, 225.4762447625245159 11.5111601660448777, 225.4609749326484121 11.5119498938921563, 225.4457365038375940 11.5127370489375611, 225.4305250723164704 11.5135218388493605, 225.4153505895427543 11.5143038171213377, 225.4002092546373888 11.5150831649119443, 225.3851016085727963 11.5158598654166955, 225.3700330195639197 11.5166336842014942, 225.3550142447495830 11.5174041464428125, 225.3400350352273449 11.5181717255856082, 225.3250842761415527 11.5189369296322006, 225.3101705090199971 11.5196993830200665, 225.2952945149501147 11.5204590600189789, 225.2804449879917854 11.5212164731226405, 225.2656236019689686 11.5219715538163445, 225.2508347977988024 11.5227241118038233, 225.2360836991743440 11.5234739286072827, 225.2213701223813302 11.5242210218960714, 225.2066922232594095 11.5249654822953591, 225.1920523314409195 11.5257072167190131, 225.1774439551113858 11.5264465188783962, 225.1628688639329425 11.5271833193508364, 225.1483231609320796 11.5279177960269106, 225.1338080113189335 11.5286499054819771, 225.1193156868345397 11.5293799895936147, 225.1048406914467250 11.5301082903483767, 225.0903927203258661 11.5308343935948940, 225.0759731997334541 11.5315582445592391, 225.0615726061225814 11.5322802576213661, 225.0471948914338611 11.5330002677360390, 225.0328448253088141 11.5337180770247567, 225.0185250472582368 11.5344335803454943, 225.0042336758179715 11.5351468651000353, 224.9899666840223347 11.5358581082564005, 224.9757293128609774 11.5365670952889197, 224.9615188349541484 11.5372739482831079, 224.9473343603705189 11.5379787112424044, 224.9331867190082903 11.5386809398550927, 224.9190651590944867 11.5393810912804273, 224.9049589851377391 11.5400796146826767, 224.8908763596579661 11.5407761760249485, 224.8768203267610204 11.5414706560850586, 224.8627911626699358 11.5421630507503536, 224.8487873231492529 11.5428534304463444, 224.8348025935680710 11.5435420547040799, 224.8208432662415248 11.5442286728549472, 224.8069064464970381 11.5449134088086449, 224.7929952891035441 11.5455961415900177, 224.7790961745805305 11.5462774242074833, 224.7652157298653606 11.5469569934464307, 224.7513584997251144 11.5476346729728920, 224.7375268209689239 11.5483103768095656, 224.7237220902838715 11.5489840576780995, 224.7099413765668601 11.5496558393060607, 224.6961637810922525 11.5503265461398481, 224.6824171483932275 11.5509950911857615, 224.6686890557905940 11.5516619670139402, 224.6549772382122399 11.5523272659126715, 224.6412812909842103 11.5529910072087603, 224.6276091034520164 11.5536528929961175, 224.6139594562524167 11.5543129777076103, 224.6003182497947819 11.5549718025661754, 224.5867005368151297 11.5556288004452146, 224.5731010661978075 11.5562841764879316, 224.5595318451263722 11.5569374888469980, 224.5459817047733111 11.5575891644451580, 224.5324427190888628 11.5582395019069555, 224.5189143401665888 11.5588885230225600, 224.5054022183594782 11.5595360233582785, 224.4919123846992477 11.5601817896909864, 224.4784375363008166 11.5608260941027599, 224.4649757674714579 11.5614690093643837, 224.4515271517194321 11.5621105363191710, 224.4380954082743074 11.5627505474210572, 224.4246791510130379 11.5633890977002647, 224.4112755960974823 11.5640262896198021, 224.3978846737839206 11.5646621293277523, 224.3845066428670521 11.5652966117857332, 224.3711457528162043 11.5659295968898927, 224.3577977362203910 11.5665612362847945, 224.3444652819599128 11.5671914448426563, 224.3311485458444849 11.5678202246618902, 224.3178463670912777 11.5684476215481631, 224.3045557511036634 11.5690737397450345, 224.2912636805678801 11.5696990018417107, 224.2779812886811612 11.5703230455082977, 224.2647169075865179 11.5709456114698259, 224.2514653724626612 11.5715668719248743, 224.2382246445202725 11.5721868961343350, 224.2249954648025891 11.5728056663857899, 224.2117774258953204 11.5734232007857365, 224.1985677641279722 11.5740395865862702, 224.1853739310612639 11.5746546100326579, 224.1721921301457314 11.5752683925175521, 224.1590180429138002 11.5758810639248146, 224.1458517540504261 11.5764926247077860, 224.1326993443459230 11.5771029132240990, 224.1195552562956834 11.5777120902351811, 224.1064199000727513 11.5783201500287358, 224.0932922280876767 11.5789271253157189, 224.0801718772195841 11.5795330298010324, 224.0670575303401506 11.5801378996871733, 224.0539473086428472 11.5807417811292517, 224.0408440714103335 11.5813446074145840, 224.0277532395657545 11.5819462641689093, 224.0146726415952685 11.5825468155354709, 224.0016005777154362 11.5831463107815420, 223.9885357303158457 11.5837447873712911, 223.9754767473435777 11.5843422797721374, 223.9624200726300103 11.5849388562089146, 223.9493664901852981 11.5855344995887286, 223.9363221823029733 11.5861291150834003, 223.9232837412926358 11.5867227707854656, 223.9102514687421319 11.5873154735646100, 223.8972278339659283 11.5879072106724514, 223.8842074228130059 11.5884980596409779, 223.8711897945833584 11.5890880278296748, 223.8581768384393342 11.5896771077336105, 223.8451691054835919 11.5902653131262312, 223.8321650096337407 11.5908526677192807, 223.8191624724384212 11.5914391819224125, 223.8061618009906795 11.5920248568798332, 223.7931629564031653 11.5926096948298980, 223.7801640483973813 11.5931936738872032, 223.7671670080494835 11.5937768052707071, 223.7541730621555018 11.5943591186183337, 223.7411823205537473 11.5949406428819621, 223.7281945822440150 11.5955214095179251, 223.7152092203633913 11.5961014400467288, 223.7022255713138179 11.5966807498982476, 223.6892422590836134 11.5972592901497737, 223.6762589726544377 11.5978370356977827, 223.6632763821629908 11.5984140565029303, 223.6502941596702669 11.5989903554735516, 223.6373122485668148 11.5995659928018586, 223.6243300458084775 11.6001409101370605, 223.6113474183891583 11.6007150945083968, 223.5983643014848212 11.6012885646784678, 223.5853804742151283 11.6018613807905986, 223.5723949789614267 11.6024337740613053, 223.5594084415269833 11.6030053638277568, 223.5464202437218262 11.6035763342790634, 223.5334298265389918 11.6041467476564453, 223.5204368671240900 11.6047166055491289, 223.5074413311867261 11.6052858741608791, 223.4944432982350406 11.6058545207539758, 223.4814424785659810 11.6064225703277071, 223.4684383277705422 11.6069900726994248, 223.4554303426296826 11.6075570640144345, 223.4424179562306279 11.6081235823802746, 223.4294005333740074 11.6086896685705732, 223.4163767564537864 11.6092554251278539, 223.4033493491722595 11.6098205677991135, 223.3903182963115626 11.6103850983762609, 223.3772834961674789 11.6109490258485373, 223.3642450371776818 11.6115123420402675, 223.3512033206731360 11.6120750138095001, 223.3381552833258468 11.6126372900905039, 223.3251009602330157 11.6131991535604495, 223.3120397912812223 11.6137606354716958, 223.2989722102234396 11.6143216904755153, 223.2858985035020396 11.6148822884616809, 223.2728171532935448 11.6154425337012217, 223.2597285678923527 11.6160023858956443, 223.2466317184653235 11.6165619095860233, 223.2335277664831779 11.6171210135472602, 223.2204169764141852 11.6176796739022148, 223.2072988293977005 11.6182379214719873, 223.1941722853967462 11.6187958206584678, 223.1810361052900760 11.6193534462392343, 223.1678913125375061 11.6199107220438531, 223.1547381380285060 11.6204676270151772, 223.1415754377304381 11.6210242292760224, 223.1284015147998900 11.6215806294669548, 223.1152151257254843 11.6221368962333429, 223.1020209030241119 11.6226927309393702, 223.0888180899233078 11.6232481781277546, 223.0756052319433422 11.6238033234461078, 223.0623811454809697 11.6243582333811322, 223.0491451294331853 11.6249129434946958, 223.0358968024204955 11.6254674694465869, 223.0226367869103683 11.6260217673261028, 223.0093615337495123 11.6265760397115265, 222.9960678207968101 11.6271304645774940, 222.9827655838477938 11.6276844535504669, 222.9694554206682255 11.6282379715212922, 222.9561342545970604 11.6287911941992892, 222.9427998983189809 11.6293442422904594, 222.9294510268587430 11.6298971849420347, 222.9160884180318192 11.6304499718435039, 222.9027074603748133 11.6310028545879938, 222.8893176033936072 11.6315552994956750, 222.8759211426547893 11.6321071794923263, 222.8625124070539698 11.6326588071240842, 222.8490832135032633 11.6332106252390108, 222.8356348319249491 11.6337625545310122, 222.8221730869049964 11.6343142716203811, 222.8086998368717957 11.6348656728460096, 222.7952032410294692 11.6354173891255126, 222.7816844858353988 11.6359693461022573, 222.7681514532252720 11.6365211163933129, 222.7546094596964110 11.6370724158920975, 222.7410496054622797 11.6376237118726795, 222.7274689117873550 11.6381751538626510, 222.7138741945882146 11.6387263791939652, 222.7002655263165423 11.6392773809061207, 222.6866375324931653 11.6398284332340349, 222.6729866912359626 11.6403797107135585, 222.6593141329998389 11.6409311470154755, 222.6456207319824330 11.6414826900451711, 222.6319141538593271 11.6420339437049947, 222.6181898888982573 11.6425851339993081, 222.6044497077811002 11.6431361669500077, 222.5906859946224472 11.6436874213117356, 222.5768997746929472 11.6442388379762143, 222.5630916264606185 11.6447903810373052, 222.5492639055994744 11.6453419268843543, 222.5354268513602847 11.6458929634969444, 222.5215672763525845 11.6464441414374598, 222.5076782329887806 11.6469957955481824, 222.4937638625463023 11.6475477129612308, 222.4798292363417147 11.6480996383395308, 222.4658732608440630 11.6486516197575565, 222.4519005455431397 11.6492034280487857, 222.4379138599543921 11.6497549259658317, 222.4239108831870908 11.6503062232925103, 222.4098822394146282 11.6508577672794065, 222.3958278149455055 11.6514095559922648, 222.3817501135823420 11.6519614625816601, 222.3676471868265878 11.6525135736721506, 222.3535187113752443 11.6530658977189194, 222.3393601721920447 11.6536186413768164, 222.3251663416751569 11.6541720424480673, 222.3109466623575372 11.6547256460647493, 222.2967040816935196 11.6552793072737053, 222.2824345096953493 11.6558332118137287, 222.2681376654432768 11.6563873656892110, 222.2537934125769254 11.6569426977977990, 222.2394296278700949 11.6574979009509061, 222.2250456168341373 11.6580530033632179, 222.2106332312229426 11.6586083764543087, 222.1961901634300602 11.6591641190119280, 222.1817259895474308 11.6597197839798294, 222.1672323459329732 11.6602757492673117, 222.1527060469181265 11.6608321525715102, 222.1381498752912478 11.6613888587151138, 222.1235645886168584 11.6619458257867166, 222.1089488152803710 11.6625031085844704, 222.0943054475013696 11.6630605689785174, 222.0796369850752399 11.6636180879175448, 222.0649326370227072 11.6641761438836653, 222.0501916741881132 11.6647347600561382, 222.0354200416066419 11.6652936614482066, 222.0206255050727009 11.6658524948229108, 222.0058055009279485 11.6664113692121720, 221.9909317003490798 11.6669715336748236, 221.9760187813683388 11.6675323245008098, 221.9610674740767990 11.6680936993382556, 221.9460834295389304 11.6686553999180287, 221.9310575638783121 11.6692178165951592, 221.9159984711554046 11.6697805626031812, 221.9009259266272238 11.6703427671831381, 221.8858296896102047 11.6709048744380759, 221.8706995944999107 11.6714673207546333, 221.8555326260611196 11.6720302285181958, 221.8403304885997329 11.6725935149842517, 221.8250972499870386 11.6731569963145745, 221.8098195614938959 11.6737212391111846, 221.7944889260377010 11.6742865963530367, 221.7791202134466175 11.6748524179258037, 221.7637180402841466 11.6754184975181374, 221.7482700456588134 11.6759853535227798, 221.7327669514101558 11.6765533683532592, 221.7172115229238898 11.6771224104259019, 221.7016211571711892 11.6776917309401576, 221.6860028019713127 11.6782610287884907, 221.6703447483088212 11.6788307904525137, 221.6546244431690980 11.6794019527549153, 221.6388611839189764 11.6799736915289660, 221.6230487052746696 11.6805462579599375, 221.6071946734441269 11.6811193203291595, 221.5913075585660295 11.6816925165768932, 221.5753864704027478 11.6822658761466531, 221.5594131535317786 11.6828401465026825, 221.5433904492175259 11.6834151972955720, 221.5273308964402474 11.6839905000419044, 221.5112244756964515 11.6845664577698933, 221.4950649900586086 11.6851433129840228, 221.4788646116744815 11.6857205548552283, 221.4626020103638382 11.6862990436845724, 221.4462705120732551 11.6868790352296763, 221.4298859924534497 11.6874598673674512, 221.4134506856317444 11.6880414365500904, 221.3969754781720098 11.6886232905391001, 221.3804605137670478 11.6892054142711963, 221.3638996850473575 11.6897880441024000, 221.3472772159514363 11.6903718019422271, 221.3305813530421631 11.6909571427403964, 221.3137711140981025 11.6915456840148906, 221.2969116220046715 11.6921348014644710, 221.2800176036379014 11.6927238980664452, 221.2630934336441157 11.6933127927512839, 221.2461192125777814 11.6939022660947209, 221.2290863538881354 11.6944926448374780, 221.2119945040207369 11.6950839284474757, 221.1948675705678227 11.6956751636056850, 221.1776935519630172 11.6962668126450478, 221.1604303534598444 11.6968605094593165, 221.1430823375288526 11.6974560609985403, 221.1256729793932436 11.6980525325018547, 221.1082343240165642 11.6986486654835549, 221.0907777951929631 11.6992440115853746, 221.0732731529994624 11.6998397354871209, 221.0556760649224373 11.7004375334853137, 221.0379809653601058 11.7010375956553769, 221.0201910780142214 11.7016397730643646, 221.0023326505335604 11.7022430374960305, 220.9844141227350462 11.7028470498581783, 220.9664267865937575 11.7034521267778473, 220.9483618371826879 11.7040585853194052, 220.9302181846902897 11.7046664470968551, 220.9120117963190637 11.7052750889533499, 220.8937461626338745 11.7058843638380665, 220.8754296372396482 11.7064939431866932, 220.8570353831487125 11.7071048211080768, 220.8385387414679712 11.7077179002450666, 220.8199419597834776 11.7083330701137083, 220.8012542966761771 11.7089499601075584, 220.7824976140211106 11.7095677351636223, 220.7636932618618175 11.7101855873258280, 220.7448115762732925 11.7108046009476414, 220.7258449069660742 11.7114250382026359, 220.7067902066098668 11.7120469892192531, 220.6876435492256405 11.7126705751678770, 220.6684018412164505 11.7132958852828502, 220.6490775002885414 11.7139224419230352, 220.6296751617571772 11.7145500551708501, 220.6101884901138703 11.7151789348560147, 220.5906226553580041 11.7158088720504878, 220.5709709286505529 11.7164400891991409, 220.5512576667633198 11.7170716871744123, 220.5314614384047616 11.7177044199496549, 220.5115590022784318 11.7183390981715014, 220.4915452243215555 11.7189758769615491, 220.4714307799586379 11.7196143463289282, 220.4512468589024650 11.7202533715732251, 220.4309992066341124 11.7208927312610278, 220.4106498399730185 11.7215337511258397, 220.3901880983403885 11.7221767796032950, 220.3696269742863478 11.7228213298105270, 220.3489604038685172 11.7234675875962697, 220.3281690552340422 11.7241162000845680, 220.3072756756611739 11.7247663403802953, 220.2862824116141951 11.7254179062594410, 220.2651764715988634 11.7260713139578208, 220.2439627766001990 11.7267263625395870, 220.2226597862615449 11.7273823863475268, 220.2012604090867569 11.7280396048920021, 220.1797602369086633 11.7286981429012673, 220.1581417345628893 11.7293585718169062, 220.1364090861389968 11.7300207161521115, 220.1145235049733628 11.7306858616742726, 220.0924773395470027 11.7313542240955613, 220.0703026464014158 11.7320246749398311, 220.0480152578962532 11.7326966446454506, 220.0256193313659878 11.7333699618091050, 220.0031393234897052 11.7340437771874146, 219.9805459909680394 11.7347190432092248, 219.9578262375407007 11.7353961632534372, 219.9350228461269978 11.7360736819629654, 219.9120955538621729 11.7367529071512777, 219.8890352094868774 11.7374341046332820, 219.8658230573280434 11.7381178519633629, 219.8424378550978986 11.7388048002984178, 219.8189420394050444 11.7394928593078145, 219.7954051231487540 11.7401797339112850, 219.7717126788520545 11.7408691262396161, 219.7478364883793347 11.7415619025074367, 219.7238247218019751 11.7422564541995804, 219.6876080273578680 11.7432997520176734, 219.6987502443417384 11.7853002090491579, 219.7061757876889772 11.8133082997274510, 219.7135940509132297 11.8413227759249011, 219.7210889789923272 11.8693409429781784, 219.7285814364998657 11.8973653262090657, 219.7359400486977847 11.9254160621554348, 219.7433406485907881 11.9534883623070129, 219.7507384079413839 11.9815667699549220, 219.7579751712045208 12.0096563093556448, 219.7652143414607053 12.0377517635904443, 219.7725440828455703 12.0658503181884296, 219.7799904234039730 12.0939511402888975, 219.7873287083440914 12.1220613655543552, 219.7950620438456895 12.1501650027041670, 219.8021265118331087 12.1782958258663783, 219.8093603042825919 12.2064247226591380, 219.8166921776443985 12.2345538241170306, 219.8241318386029093 12.2626854488771393, 219.8313059237169682 12.2908314104234435, 219.8386975895845978 12.3189764004657611, 219.8460762774764987 12.3471277103595405, 219.8532512303965518 12.3752913567140599, 219.8601568733219267 12.4034693915310417, 219.8674330692829244 12.4316415920653984, 219.8745585587278129 12.4598244142663557, 219.8816732154036515 12.4880002884619952, 219.8889004634980893 12.5161646198380119, 219.8961816779199694 12.5443331532271021, 219.9035098773560151 12.5725061002442953, 219.9107897370783462 12.6006864523424262, 219.9179935451169001 12.6288750654688204, 219.9252833210713050 12.6570668393318186, 219.9325749638414038 12.6852644093994620, 219.9416561001644652 12.7134117458279796, 219.9543867136669917 12.7414506465262676, 219.9609614049581694 12.7696857712045659, 219.9637075446882761 12.7980437137113494, 219.9693343902920901 12.8263171866397077, 219.9763334615156793 12.8545535307956662, 219.9873420347506112 12.8826705517504987, 219.9942634861872079 12.9109209434826315, 220.0001167669190067 12.9392103597477490, 220.0060773120748934 12.9675021183729466, 220.0125246227255786 12.9957844146314248, 220.0204790498684702 13.0240255676365120, 220.0303292943497979 13.0522279048195919, 220.0363649927845415 13.0805695895775038, 220.0435238279249006 13.1088820272039293, 220.0503468298333871 13.1372105205487628, 220.0554592265420695 13.1655976699509321, 220.0637196797621300 13.1938928198924916, 220.0719591775471145 13.2221942521916933, 220.0809504270771129 13.2504780236563917, 220.0855261981920705 13.2789041270496035, 220.0951810645363764 13.3071785721336990, 220.1002796903679553 13.3355902519529828, 220.1073732202187614 13.3639359210754769, 220.1144903728726376 13.3922864423550969, 220.1215969436844944 13.4206428610129969, 220.1287454668107273 13.4490035478161278, 220.1370509981837529 13.4773341060096019, 220.1447945325965634 13.5056875658187590, 220.1521226692600237 13.5340593775234925, 220.1594878072516508 13.5624355775001302, 220.1672209490637613 13.5908059711628990, 220.1735193282171679 13.6192134305284096, 220.1797316163689686 13.6476157293916334, 220.1873777093113631 13.6759795004141829, 220.1930107859356269 13.7044105976752846, 220.2002984599677404 13.7327964211487039, 220.2072515017236469 13.7611980188111307, 220.2143246165954906 13.7896014367970157, 220.2215554930077701 13.8180055224590550, 220.2286296842064530 13.8464198864545640, 220.2360116622517126 13.8748303220670639, 220.2430051251371310 13.9032672157712671, 220.2501152151649535 13.9317156118441385, 220.2572216299341505 13.9601695314946959, 220.2642465574776907 13.9886313340574393, 220.2713684612565714 14.0170955710232867, 220.2785023219738889 14.0455648245570437, 220.2854747329026566 14.0740443613009454, 220.2924122624940821 14.1025303159028734, 220.2996554937522831 14.1310123204512017, 220.3069763451982226 14.1594973112581783, 220.3142171410073900 14.1879762436704642, 220.3212888449942852 14.2164510630127907, 220.3285662247812411 14.2449250049524494, 220.3357787549943509 14.2734062685860561, 220.3430111141880161 14.3018922774104187, 220.3501997520755253 14.3303849445464522, 220.3574570040200911 14.3588808589513413, 220.3646092574620923 14.3873852632869674, 220.3714147345267520 14.4159054394684674, 220.3785552991164707 14.4444207817512531, 220.3856329594830470 14.4729591087435345, 220.3927589156871250 14.5015180723172286, 220.4001015600089488 14.5300759358654048, 220.4070109460431297 14.5586522743611972, 220.4141681495548823 14.5872265555880922, 220.4213450481187522 14.6158056439496207, 220.4283321193172753 14.6443958341179794, 220.4351872858637194 14.6729953696561850, 220.4419782509905019 14.7016021982790495, 220.4491191995470558 14.7302038605341288, 220.4562753230414955 14.7588104209561255, 220.4631946712390516 14.7874294374998261, 220.4702000948232694 14.8160511960587158, 220.4772950717111826 14.8446755827558619, 220.4839306273961483 14.8733190664181052, 220.4909266829284320 14.9019570260175218, 220.4976694709369269 14.9306078671257954, 220.5046731484034694 14.9592561610596047, 220.5120158653473368 14.9878995606874916, 220.5191292395781772 15.0165550965496895, 220.5262348491487785 15.0452014113067669, 220.5332068980250995 15.0738414755713990, 220.5401041729018630 15.1024890650986521, 220.5471488171812098 15.1311375221949636, 220.5542362850947598 15.1597899704439243, 220.5611333595421684 15.1884533660534053, 220.5679385527571696 15.2171247479027922, 220.5747011526484300 15.2458026331747440, 220.5815398873603783 15.2744834678377455, 220.5883348268939699 15.3031708215565576, 220.5952609830897302 15.3318516292334994, 220.6021604669840599 15.3605301789980313, 220.6091076558739985 15.3892125440353880, 220.6161764141558592 15.4178965198410332, 220.6230901037561978 15.4465903215783982, 220.6301501103358476 15.4752849839106439, 220.6372073271448073 15.5039849266983030, 220.6444374304924168 15.5326849343095184, 220.6513601810807472 15.5613992305727713, 220.6584195817221428 15.5901146455026804, 220.6656104755166439 15.6188475383842658, 220.6725629481119029 15.6476096980340245, 220.6794718237543975 15.6763782015245425, 220.6865795064007045 15.7051458685258982, 220.6936342526857402 15.7339201369744757, 220.7007654345031540 15.7626971712797577, 220.7078725201675979 15.7914799319408594, 220.7148096929188057 15.8202727172665440, 220.7215757287766564 15.8490755470569642, 220.7283721987685112 15.8778824588656065, 220.7350836296570264 15.9066911632053873, 220.7416743562695558 15.9355023997403418, 220.7481966878711717 15.9643206292182978, 220.7548945872244701 15.9931386467348133, 220.7613444567815577 16.0219689302386108, 220.7677698415080272 16.0508048765211129, 220.7746443424170479 16.0796325322694784, 220.7812845457084734 16.1084720149696778, 220.7879876039496594 16.1373145636513406, 220.7945517929814798 16.1661661041699141, 220.8003852058058385 16.1950297579101310, 220.8065727659194124 16.2238728426695040, 220.8128737957989358 16.2527175113965363, 220.8191939110056126 16.2815665267425445, 220.8255853094442500 16.3104183524370931, 220.8322199083716555 16.3392679470010442, 220.8387406011722192 16.3681257643623681, 220.8455876356813690 16.3969789136112638, 220.8521250524045740 16.4258459897285611, 220.8587218667005629 16.4547161879245465, 220.8645994470651601 16.4836264166659774, 220.8712533718762074 16.5125337518294195, 220.8780519442242394 16.5414416418538295, 220.8844592155476789 16.5703657115562599, 220.8910937775164314 16.5992879040301240, 220.8980693087067380 16.6282048995115233, 220.9049961144845611 16.6571280522519878, 220.9120699950305777 16.6860516472141533, 220.9194177422915573 16.7149719799765784, 220.9276001533339127 16.7438727062818487, 220.9337661358018750 16.7728228495608924, 220.9389578083278138 16.8017912337806763, 220.9442769285998054 16.8307605836161116, 220.9495928243461549 16.8597346925637090, 220.9577127122793740 16.8886320293686296, 220.9646546212052556 16.9175683018324889, 220.9707048370613052 16.9465351426090898, 220.9797473556310763 16.9754198494710735, 220.9858600580092229 17.0043942337372620, 220.9958191482403436 17.0332617630856049, 221.0051625286745320 17.0621598883361578, 221.0124021448474139 17.0911321563526641, 221.0184994706509372 17.1201421338824318, 221.0265401097949791 17.1491003805746764, 221.0342616430377518 17.1780724622198377, 221.0416980303219248 17.2070573797195934, 221.0492640309013552 17.2360431262770000, 221.0574138453891067 17.2650166727703045, 221.0642334908641828 17.2940334625386072, 221.0712450094161454 17.3230494023605317, 221.0749963656984676 17.3521453998165214, 221.0833710949558224 17.3810923448500745, 221.1011824942376620 17.4097711645996789, 221.1234492922619665 17.4383253656036494, 221.1445770580369015 17.4669167907658363, 221.1659465838423557 17.4955054061167807, 221.1861886222017972 17.5241310870557143, 221.1957398783415840 17.5530730749277453, 221.2038504548904143 17.5820618221894307, 221.2080494841086420 17.6111692373987765, 221.1988378781663300 17.6406951860111967, 221.1916282429558009 17.6701920142178857, 221.1877364535647246 17.6995965148939973, 221.1891438133449981 17.7288520330254187, 221.1968136068191768 17.7579311995516953, 221.2025182966286252 17.7870716377670490, 221.2095907509219899 17.8161771070568840, 221.2164907417932511 17.8452920714009018, 221.2224705206810142 17.8744381065789284, 221.2276865454103358 17.9036106793866026, 221.2332579885822668 17.9327608896160093, 221.2382920350439406 17.9619135897860147, 221.2442643360619456 17.9910437667454808, 221.2498103058294134 18.0201907506606034, 221.2557031371561038 18.0493322625831176, 221.2621150173605145 18.0784633552205634, 221.2691153440565586 18.1075820420348315, 221.2754697897617007 18.1367238201218441, 221.2813055106691138 18.1658850018857798, 221.2877570248362815 18.1950329766012153, 221.2952951942176298 18.2241557262664315, 221.3013316092948912 18.2533276460353804, 221.3064102416667254 18.2825314909653507, 221.3124256843172191 18.3117128830346196, 221.3181998062505613 18.3409056215009230, 221.3250297702840044 18.3700725218476784, 221.3330359097350879 18.3992101499338574, 221.3374115111108154 18.4284561977538637, 221.3395504030026473 18.4577705759598167, 221.3457908671438190 18.4869719477480778, 221.3522330610475990 18.5161719318872571, 221.3576786768798002 18.5454047626506835, 221.3641619888260834 18.5746123076340659, 221.3714995888928740 18.6037998196632266, 221.3767736088032905 18.6330506091271673, 221.3800031767991072 18.6623640322658915, 221.3827149221609432 18.6916964386121869, 221.3869971799912264 18.7209883345133079, 221.3954106496686620 18.7501669054911879, 221.3995190999239355 18.7794723425555183, 221.4052428972187556 18.8087317692351981, 221.4115868758580348 18.8379732982816073, 221.4181831195022880 18.8672119585484594, 221.4233857645894545 18.8964945037864993, 221.4297173513254791 18.9257492500434310, 221.4381077563503197 18.9549498210419713, 221.4437577954094252 18.9842324709429775, 221.4516685196733761 19.0134552178974268, 221.4581496808990551 19.0427227931948551, 221.4643061422233643 19.0720038207432161, 221.4702844819505287 19.1012880858364191, 221.4757185623708153 19.1305856276462762, 221.4826944683139516 19.1598437346543946, 221.4886184843991543 19.1891358708605004, 221.4939013083927364 19.2184503653944141, 221.4996672947944489 19.2477553922335289, 221.5040832408633662 19.2771027541025148, 221.5096352532663673 19.3064221886952154, 221.5157733841184893 19.3357292607878364, 221.5253826104172674 19.3649425947902820, 221.5379099684408004 19.3940777405995490, 221.5502811788497297 19.4232214105693686, 221.5569709193703716 19.4525297973581957, 221.5662463668698479 19.4817692948528247, 221.5778559125186007 19.5109469749461226, 221.5906337324533695 19.5400956987026397, 221.6024715942947410 19.5692750832819229, 221.6125240950602517 19.5985091244238774, 221.6228475294514340 19.6277395974841120, 221.6323575609016245 19.6569972254708745, 221.6414955699297025 19.6862695154174325, 221.6441014357699544 19.7157310267549057, 221.6431788905937879 19.7452962393540368, 221.6474285048352897 19.7747190426672717, 221.6570202718861538 19.8039949646705367, 221.6647077936957544 19.8333287510324681, 221.6736781942441326 19.8626303408986971, 221.6816552831826641 19.8919640443342836, 221.6864995332405215 19.9213902841940040, 221.6879874478636623 19.9509151914912231, 221.6950302194500466 19.9803011563596762, 221.7007370234501877 20.0097433603399359, 221.7040348686778088 20.0392573980041320, 221.7074811800369503 20.0687711180623758, 221.7106271753666249 20.0982971570569227, 221.7176834712391553 20.1277169764854449, 221.7230577693551368 20.1571880403282222, 221.7277772772460480 20.1866814123584071, 221.7319480614878273 20.2161940829782409, 221.7405773855778932 20.2455851411456607, 221.7464024975941754 20.2750548270084217, 221.7539002818592735 20.3044768993998694, 221.7622961089346916 20.3338775258969804, 221.7701743258854776 20.3632965544232682, 221.7734370623848577 20.3928494143094561, 221.7781903111280712 20.4223640959130961, 221.7857901478931240 20.4518024606101179, 221.7905956914547403 20.4813232880440843, 221.7934330721337233 20.5109032611484672, 221.7963687167685691 20.5404841930716415, 221.8001607379658537 20.5700447861274966, 221.8054346070261147 20.5995675040498547, 221.8103477317131649 20.6291041102544455, 221.8166602060329353 20.6586051780087843, 221.8221517892840495 20.6881330400508894, 221.8259525593682611 20.7177120869086551, 221.8288813389624750 20.7473192817873482, 221.8318044961308999 20.7769302960825435, 221.8435312830480655 20.8062982214935879, 221.8549313336242221 20.8356788471551511, 221.8497364447368057 20.8655178702383246, 221.8425629853566647 20.8954035173439259, 221.8374057078341082 20.9252355199618165, 221.8382513116544317 20.9549034616150962, 221.8489444032812514 20.9843010522090943, 221.8672991638532324 21.0134887095648253, 221.8797684797730199 21.0428438538503748, 221.8888487448002422 21.0722972728106370, 221.8918121764575062 21.1019252294165227, 221.8997900567356396 21.1314168337630335, 221.8991270367588697 21.1611502208354310, 221.9020360600742379 21.1907843361677877, 221.9051409738623306 21.2204165413442496, 221.9093921103614093 21.2500204262898542, 221.9134644850259122 21.2796328633121092, 221.9116312021968440 21.3094126972360378, 221.9033250494503875 21.3393746127079531, 221.9060874410359929 21.3690335286028130, 221.9051570429201945 21.3987977107016469, 221.9034350286596293 21.4285868524563803, 221.9100625117274888 21.4581527655943702, 221.9160434287245209 21.4877432146385949, 221.9239319468220515 21.5172848000619119, 221.9294345203078080 21.5468955351512790, 221.9331047106559822 21.5765601473878483, 221.9363589629506635 21.6062396561209518, 221.9410372989518692 21.6358835682284862, 221.9455708510456873 21.6655349502113737, 221.9489332020140466 21.6952219034755416, 221.9527916213339438 21.7248987173553267, 221.9568923300833490 21.7545815341241386, 221.9622749831027875 21.7842424188079526, 221.9689999677077026 21.8138700176372851, 221.9756541567005286 21.8435029772229505, 221.9819054039660671 21.8731503838905681, 221.9874375588006501 21.9028208854043456, 221.9923744751629044 21.9325110806198644, 221.9971582666386212 21.9622088591800697, 222.0022868647369307 21.9919005862786214, 222.0073763583202151 22.0215967612608061, 222.0125740997378045 22.0512812411997068, 222.0181997696334406 22.0809446208542752, 222.0239219586067065 22.1106087561017866, 222.0295585476059728 22.1402786146141217, 222.0351508916823775 22.1699530582424984, 222.0404526837054675 22.1996388018164730, 222.0459415609462610 22.2293227898002357, 222.0513176339454446 22.2590132041568225, 222.0566915795612601 22.2887070119448190, 222.0619094905600264 22.3184084035169974, 222.0670777004404783 22.3481169446532455, 222.0723932812628902 22.3778273941603310, 222.0778045443080657 22.4075385392143609, 222.0831994160363649 22.4372534235302439, 222.0886618317311445 22.4669697548344942, 222.0940991755599043 22.4966900460909578, 222.0994691521187576 22.5264154382736272, 222.1047964011232239 22.5561452532094471, 222.1101294449684360 22.5858781592319566, 222.1154278858727480 22.6156152488037741, 222.1204533895628686 22.6453510841246022, 222.1255746091792105 22.6750749807143812, 222.1305415331344761 22.7048063111040825, 222.1355918767626179 22.7345386066265576, 222.1406272319893560 22.7642745337338859, 222.1456427355799974 22.7940142138393824, 222.1506409863819727 22.8237575659330716, 222.1555901880873023 22.8535054434831579, 222.1605035063352034 22.8832574902101982, 222.1653853068948195 22.9130136584201516, 222.1701157222859422 22.9427849161477120, 222.1746722368773703 22.9725722771430831, 222.1789372765960593 23.0023707336496663, 222.1836470871942879 23.0321604024212370, 222.1902336447314497 23.0619026706993822, 222.1954412201940556 23.0916853618761309, 222.2010691944255711 23.1214599262805258, 222.2083069956010490 23.1511942960883701, 222.2139381435147811 23.1809751876414474, 222.2171083383337873 23.2108255821092406, 222.2209721212256852 23.2406645033902457, 222.2264188753575525 23.2704682647432861, 222.2313081619016941 23.3002901814835610, 222.2360097318936312 23.3301202836924801, 222.2415927708849495 23.3599298016456380, 222.2470068276271320 23.3897469907030384, 222.2519231346196307 23.4195806807009284, 222.2572050553824567 23.4494076445892041, 222.2625109492722686 23.4792370609050991, 222.2677986183142593 23.5090700578446921, 222.2730932424809396 23.5389018904539746, 222.2783652838151625 23.5687331209974964, 222.2836630221556504 23.5985667352013877, 222.2889512533762968 23.6284036681285592, 222.2942416701861816 23.6582435993144280, 222.2995194589994981 23.6880869167039698, 222.3047902502761985 23.7179334592487940, 222.3100593616908043 23.7477830777868988, 222.3153269114290254 23.7776357582812636, 222.3205857378867165 23.8074916863795991, 222.3258403920029309 23.8373582232058503, 222.3310865114314367 23.8672358807690905, 222.3363375860172937 23.8971163698708544, 222.3415702345400291 23.9270003065682246, 222.3468108928606455 23.9568869757005061, 222.3520480337560912 23.9867766766088764, 222.3572649948951891 24.0166698463006867, 222.3624711044046762 24.0465662283016322, 222.3676891361924390 24.0764652011749902, 222.3729124458868114 24.1063669366874613, 222.3781169700974090 24.1362555015296039, 222.3833351602675918 24.1661291232236017, 222.3885383066309487 24.1960060808038726, 222.3937343595017637 24.2258861500004414, 222.3989128520104543 24.2557696041782442, 222.4041151464220150 24.2856553267139752, 222.4093035830346423 24.3155443154017092, 222.4144707257956100 24.3454367620003289, 222.4196450989011851 24.3753318929984992, 222.4248070428651829 24.4052302270551422, 222.4299789487583894 24.4351425316585171, 222.4351602127394187 24.4650694312737329, 222.4403260978866115 24.4949995557128695, 222.4454766884294372 24.5249328916784641, 222.4506344509231894 24.5548688332494152, 222.4557980073741987 24.5848074074429768, 222.4609597303191038 24.6147488079420249, 222.4661044727569958 24.6446934322527973, 222.4712868514492357 24.6746398128311384, 222.4764363185168747 24.7045898246570417, 222.4814972287935291 24.7345345117169586, 222.4865727297392368 24.7644705414371309, 222.4916450188112549 24.7944094043328427, 222.4967137081081319 24.8243510996974912, 222.5017795692404547 24.8542956004262194, 222.5068576655753532 24.8842424958409545, 222.5120517758201686 24.9141890164011386, 222.5176809717236495 24.9441266751680431, 222.5230371540903889 24.9740742935971944, 222.5290562789999740 25.0040069855241107, 222.5331725719312033 25.0339993044513882, 222.5376046921078341 25.0639926190491131, 222.5426084070970774 25.0939733982111832, 222.5478248201073370 25.1239511677123595, 222.5527619899597767 25.1539389804555498, 222.5574321691784405 25.1839364968434225, 222.5625081546752426 25.2139258546290179, 222.5680755221214326 25.2439047827437690, 222.5750824831743842 25.2738481130903523, 222.5818625379004629 25.3038000446121245, 222.5873061522456169 25.3337860382415521, 222.5917606066306860 25.3637966419744991, 222.5953536371669372 25.3938326431136723, 222.5981389591631512 25.4238925639207309, 222.6021031533214227 25.4539237632668929, 222.6070847876408152 25.4839305553833313, 222.6120722305536503 25.5139397242330510, 222.6170722390390324 25.5439510847080875, 222.6222360504176834 25.5739606264603481, 222.6271691944576219 25.6039787758384030, 222.6335611736570002 25.6339567658889393, 222.6407603688893175 25.6639116012383575, 222.6425105547388625 25.6940129653994269, 222.6465864834586625 25.7240553014443769, 222.6516214059806202 25.7540747869488840, 222.6567675649491775 25.7840938044227421, 222.6622844790668125 25.8141055029751172, 222.6675184738610653 25.8441271178438399, 222.6724559773783767 25.8741589888520309, 222.6771242621088049 25.9042003822150591, 222.6827965639183446 25.9342327714093344, 222.6931312859075263 25.9641604753715036, 222.6998270701091940 25.9941864246734440, 222.6993978976733501 26.0244027037339727, 222.7004975459773277 26.0545808980952387, 222.7068553588959219 26.0846228895172381, 222.7151427015548961 26.1146163096321402, 222.7223599540420196 26.1446402055382379, 222.7233776850086713 26.1748299736118959, 222.7251879472791245 26.2050010786730532, 222.7297770963876928 26.2350862860794258, 222.7350602992664221 26.2651397381910101, 222.7397686357628288 26.2952106475790615, 222.7442111644659519 26.3252908525314240, 222.7490640441702112 26.3553625513960590, 222.7538475221283534 26.3854383622086175, 222.7585537881951154 26.4155184783218679, 222.7633900912936440 26.4455974451520461, 222.7688509189194974 26.4756622648996789, 222.7735093006207876 26.5057504216287789, 222.7805267192553345 26.5357817794606667, 222.7892492800326352 26.5657736164451741, 222.7934436814823300 26.5958866793184541, 222.7976843004084913 26.6260007209833631, 222.8061807560703187 26.6560051397134465, 222.8082383056404865 26.6861809380930346, 222.8109050672998421 26.7163428405375214, 222.8150230962393721 26.7464687967601087, 222.8203312565419196 26.7765656935763658, 222.8301469453586492 26.8065464760137928, 222.8347872576765667 26.8366684564568949, 222.8375492577715136 26.8668452680650844, 222.8418432787356949 26.8969839967528621, 222.8465402299343054 26.9271142726488328, 222.8524894942772221 26.9572138227672085, 222.8574970504626549 26.9873401678349047, 222.8620348585828879 27.0174809199843118, 222.8672071978531051 27.0476071197206167, 222.8727065132209759 27.0777268208111721, 222.8775812159067584 27.1078649642987628, 222.8816454529329576 27.1380231415940472, 222.8870230390222389 27.1681454948167058, 222.8926968201865293 27.1982621285623232, 222.8957109187041681 27.2284504679403838, 222.8990980746668242 27.2586310227793689, 222.9038356622241110 27.2887782300374084, 222.9094055840685940 27.3189056606127068, 222.9147928170306727 27.3490398691285428, 222.9196450114407924 27.3791900619145814, 222.9243798489438859 27.4093453009175292, 222.9286431362256451 27.4395187616344884, 222.9336462509968442 27.4696789734099553, 222.9390049881752702 27.4998318296913133, 222.9468377497608174 27.5299218950147200, 222.9537155573986524 27.5600388362005013, 222.9591150510619855 27.5901963864684348, 222.9649624785249102 27.6203441093956421, 222.9708141666555719 27.6504936140676882, 222.9779961838642350 27.6806101341395312, 222.9833204692884578 27.7107772151063472, 222.9817877510270989 27.7411128056161722, 222.9874917864249824 27.7712470593064502, 222.9936750653952799 27.8013706850331737, 222.9960846761512414 27.8315948643302349, 223.0003529573711774 27.8617722975534363, 223.0057999484166942 27.8919208131025194, 223.0108499094340004 27.9220815569573055, 223.0160223021912032 27.9522409595899610, 223.0194385392753418 27.9824479977886398, 223.0236552105001238 28.0126359698908303, 223.0271042195453219 28.0428463320019112, 223.0284786827389212 28.0731130384559151, 223.0310842918996173 28.1033494160504240, 223.0333545969663191 28.1335961977290125, 223.0341384427306082 28.1638831715695339, 223.0378155610850399 28.1940968538753687, 223.0423656932955510 28.2242896787961328, 223.0473762334318621 28.2544723434078406, 223.0475972960885827 28.2847805041227538, 223.0468404021040953 28.3151153601713652, 223.0494865613966624 28.3453790556206080, 223.0551371767414537 28.3755829039517700, 223.0596730525594182 28.4058171298860991, 223.0644240582413715 28.4360474714709035, 223.0699322065495096 28.4662599556659153, 223.0775690962487658 28.4964191881774589, 223.0834344055897418 28.5266256981769075, 223.0946651132419447 28.5566952268847700, 223.1011146278996193 28.5868897812299814, 223.1057523409179169 28.6171327886123059, 223.1092709064427027 28.6474018785528273, 223.1131832145005376 28.6776577386112841, 223.1175094038491409 28.7079045861702262, 223.1223953550406520 28.7381386456188821, 223.1295327499531993 28.7683161719448890, 223.1386350267546561 28.7984444641743238, 223.1465965331875623 28.8286038480415918, 223.1511925829179575 28.8588520606162398, 223.1491645725207320 28.8892733824435695, 223.1494576262085729 28.9196360530036181, 223.1531335615347587 28.9499089871200042, 223.1592894531403317 28.9801153810099450, 223.1671259234820184 29.0102799609330333, 223.1733196883123469 29.0404885673124618, 223.1762711262445009 29.0707825593768021, 223.1797214251735113 29.1010652174156981, 223.1841873497854181 29.1313232132448583, 223.1897230041456623 29.1615551614089803, 223.1968053103267948 29.1917487258956285, 223.2006868804173791 29.2220264951148252, 223.2065211345049534 29.2522470964100521, 223.2119483584800435 29.2824710126784318, 223.2142946522384932 29.3127759708001463, 223.2144782390876117 29.3431380658541592, 223.2130393666557211 29.3735431289745463, 223.2168691454820078 29.4038141556727197, 223.2204762512732259 29.4340923790989244, 223.2231478975629102 29.4643960488119738, 223.2285682126169206 29.4946307391064941, 223.2310211554441821 29.5249429069383673, 223.2344365060521056 29.5552401518999659, 223.2401021620058543 29.5854900333859412, 223.2452223553252111 29.6157553049271165, 223.2504845763486685 29.6460183687592540, 223.2558883661898506 29.6762792295978031, 223.2643616604857471 29.7064629230798118, 223.2626949831445131 29.7369074892602718, 223.2645028386073420 29.7672644270347284, 223.2677015242095706 29.7975871775896586, 223.2703302763060265 29.8279258114374777, 223.2755883534005932 29.8581904800284157, 223.2844325324304862 29.8883563322757020, 223.2936747638194959 29.9185133353078712, 223.2972834606810864 29.9488155617771667, 223.2936336682216449 29.9793040808535700, 223.2960296761569623 30.0096396572498314, 223.3009087262123273 30.0399133845049739, 223.3025580163686641 30.0702704794178679, 223.3056715772635243 30.1005916254396553, 223.3088784514774829 30.1309116662016976, 223.3149658073646151 30.1611705867107283, 223.3233851522037980 30.1913828068958203, 223.3233981177964154 30.2218094963878769, 223.3217056285715501 30.2522804044821321, 223.3241034886099499 30.2826489019291714, 223.3291038263603241 30.3129528195703450, 223.3335435390446833 30.3432721225039828, 223.3376597523405565 30.3736008078717781, 223.3415591625802676 30.4039361643097088, 223.3428281129214383 30.4343391205256744, 223.3462760504427536 30.4646843106859926, 223.3515886987798353 30.4949795102959342, 223.3563328539658528 30.5252902258846852, 223.3591574672792888 30.5556505053242589, 223.3633305351273748 30.5859779259851585, 223.3672809019568319 30.6163120968456823, 223.3699918224421026 30.6466786007750578, 223.3771227431038824 30.6769349310674748, 223.3825888110609696 30.7072342995678937, 223.3886130845980631 30.7375207142459992, 223.3920462305591457 30.7678730777235536, 223.3948165952044178 30.7982427419904958, 223.3964601454595993 30.8286417898634824, 223.3987826872122753 30.8590247717071762, 223.4054456998846376 30.8892997589071676, 223.4109979227543192 30.9196037162118955, 223.4122540164810289 30.9500166519658571, 223.4185706210730018 30.9803035284749377, 223.4253566752213658 31.0105796348302647, 223.4280535608113496 31.0409594883233879, 223.4338682595162879 31.0712581296756802, 223.4368675732893053 31.1016243226010189, 223.4352590113053338 31.1321069395156620, 223.4366058052039250 31.1625162982494039, 223.4396637199082818 31.1928837732996520, 223.4456372425742359 31.2231793536108171, 223.4505888740725936 31.2535014462047194, 223.4547676580118036 31.2838438117381230, 223.4577717823674448 31.3142164456307839, 223.4600204704543955 31.3446088219300201, 223.4635354957530353 31.3749744632977574, 223.4679252849623765 31.4053233913776957, 223.4717681316908511 31.4356868540419008, 223.4748846054123135 31.4660692915423645, 223.4799523063650213 31.4964040411429416, 223.4840327271754745 31.5267642491154909, 223.4865467825218275 31.5571642845107974, 223.4883090084757953 31.5875838186343429, 223.4924021848507039 31.6179462651279870, 223.4970746201048257 31.6482951746434225, 223.5030775859631547 31.6786144280338071, 223.5066713027941319 31.7089970242375223, 223.5106315479442287 31.7393713218300988, 223.5132883115153675 31.7697787576907658, 223.5179358631718571 31.8001375803185269, 223.5195383342973230 31.8305726893619294, 223.5239571817112392 31.8609387320784840, 223.5283036067957312 31.8913073339899498, 223.5322682995896741 31.9216861461055217, 223.5347786257523239 31.9521017132525209, 223.5380531332908447 31.9824844286489096, 223.5428463170967461 32.0128148488240143, 223.5480686689919025 32.0431354248300480, 223.5497634682617161 32.0735438879374115, 223.5553290140103115 32.1038574828404961, 223.5598607765226120 32.1341973307074724, 223.5624516454064974 32.1645857353276838, 223.5652573177923159 32.1949694869726528, 223.5678523886450080 32.2253590507579091, 223.5695813066742517 32.2557704978966981, 223.5752338788166185 32.2861048062712186, 223.5779209907664438 32.3165321651430233, 223.5812955891685192 32.3469432664980658, 223.5848855214734385 32.3773496957421258, 223.5891971126566773 32.4077390309361490, 223.5927972934820502 32.4381464137500117, 223.5971985029561324 32.4685347392980503, 223.6019213840448003 32.4989157570548670, 223.6036978311209680 32.5293695940369787, 223.6065289349104148 32.5597981143955479, 223.6116668623229771 32.5901582028912387, 223.6140806158670387 32.6205724048605390, 223.6181065570360431 32.6509476751531480, 223.6212352933788452 32.6813454280711539, 223.6282655454013764 32.7116483294680762, 223.6318075728772783 32.7420370688500739, 223.6358101936397702 32.7724150626396806, 223.6368693071332530 32.8028654139237332, 223.6411485253797480 32.8332376417508698, 223.6440275914720814 32.8636444942399990, 223.6481684259177030 32.8940210688776915, 223.6510304932048996 32.9244292455526093, 223.6554270012593975 32.9548005342415138, 223.6597335607240780 32.9851744744439941, 223.6612530216274024 33.0156165906525061, 223.6651104430165447 33.0460023104690777, 223.6693057893046728 33.0763802572629544, 223.6717087694734971 33.1068020905750728, 223.6751911387069640 33.1371981356596095, 223.6791227355741398 33.1675836955171519, 223.6817680844841334 33.1980010626033177, 223.6840418472735053 33.2284280543673489, 223.6869943560483023 33.2588389689041932, 223.6903954623525408 33.2892393884154387, 223.6937223099212417 33.3196419366370478, 223.6971418261729809 33.3500425773433591, 223.7008089529424808 33.3804375732703491, 223.7045225787239247 33.4108317689991523, 223.7075497376883106 33.4412427866517845, 223.7109181391500385 33.4716458830489074, 223.7150606250154681 33.5020323503600395, 223.7185504296025158 33.5324365644178641, 223.7221281125651160 33.5628389412567714, 223.7256839618370066 33.5932421047875565, 223.7286555341690075 33.6236595300260106, 223.7320578395647033 33.6540668654332151, 223.7370176294949715 33.6844371355211649, 223.7396961616843498 33.7148622732817387, 223.7417932061277099 33.7453015030576253, 223.7453383331158818 33.7757062952573506, 223.7483423019239979 33.8061284718324657, 223.7517426309461257 33.8365458628915619, 223.7558536990755442 33.8669464721931774, 223.7595133205840057 33.8973580277689379, 223.7625197090217455 33.9277853217071481, 223.7660190924562187 33.9582010072444689, 223.7683261839892452 33.9886452274591093, 223.7717888925066063 34.0190620479740531, 223.7747071061440636 34.0494919421780864, 223.7778414409083609 34.0799168003566351, 223.7815977378176626 34.1103267423240766, 223.7849778123903945 34.1407454776687302, 223.7887059664865319 34.1711560408472792, 223.7929905032522413 34.2015534843492901, 223.7950256597281395 34.2320043875499493, 223.7976663118239173 34.2624409607912810, 223.8008161442569133 34.2928655067590284, 223.8038276239164475 34.3232933699840856, 223.8070266162924327 34.3537168234242571, 223.8102968484543283 34.3841386173093682, 223.8132629630119936 34.4145678462644184, 223.8172830256576731 34.4551389254355271))) +MULTIPOLYGON (((225.6590152644028535 15.2022608722661996, 225.8184327549809041 15.1937868045745503, 225.9815654786701202 15.1849797337182846, 226.1537532802193198 15.1755492199270314, 226.3306045256466632 15.1657011707254252, 226.5162011653962395 15.1552018946763578, 226.7132671052467003 15.1438748370636826, 226.9262066227588832 15.1314360402160890, 227.1499504463189680 15.1181238527931825, 227.3887690948184854 15.1036508233365492, 227.6457772453920825 15.0877754881293757, 227.9238836494400005 15.0702491179834670, 228.2357813541659084 15.0501857591912476, 228.5715528511513526 15.0280715756586574, 228.9476032947800377 15.0027010650674590, 229.3712862441239508 14.9733527540109002, 229.9512076479521170 14.9320384701617410, 230.4883373767966077 14.8922388259485832, 231.1136713054710867 14.8442866860739198, 231.8633436549179692 14.7845302320708090, 232.7891818416733258 14.7073360347087334, 233.9942957185722889 14.6012874373461674, 234.4965612400175132 14.5504533761608990, 234.5208458508271576 14.5099506890464500, 234.5313412774187327 14.4802981261204220, 234.5416512872136536 14.4506653701304515, 234.5521179867488968 14.4210212889677223, 234.5623844618901899 14.3914024320191114, 234.5724660841073046 14.3618073872274135, 234.5828318551100438 14.3321932074182605, 234.5930024519007020 14.3026038098475130, 234.6031139605006786 14.2730267394798194, 234.6134522356649654 14.2434358557329954, 234.6237144603121010 14.2138588859772490, 234.6340258236134559 14.1842843951816509, 234.6443336723656898 14.1547143901588477, 234.6547659599534654 14.1251373112355321, 234.6649390204146357 14.0955908881393182, 234.6753734549992032 14.0660275771879508, 234.6864856786430664 14.0364094110275150, 234.6958131102133507 14.0069611589922758, 234.7061842212925455 13.9774246809969220, 234.7168982094714238 13.9478639906686102, 234.7270627987847718 13.9183604611140215, 234.7372431466540945 13.8888625626754969, 234.7478000828932068 13.8593374486141556, 234.7585155951863669 13.8298050208142520, 234.7692182296842134 13.8002809125328501, 234.7803931973049316 13.7707209879307459, 234.7916997686063780 13.7411562995981491, 234.8029267464303871 13.7116060765133607, 234.8142339139198498 13.6820558043604041, 234.8253172713576191 13.6525331302293349, 234.8363458380575821 13.6230226937291725, 234.8474886344733932 13.5935091599942535, 234.8586495099669378 13.5639738917449648, 234.8698009571548369 13.5344205891063396, 234.8810277830173163 13.5048674115562370, 234.8921463910269836 13.4753310289138870, 234.9035824054630552 13.4457728636972753, 234.9148537577895866 13.4162366464935445, 234.9262689665585526 13.3866944280526923, 234.9378205228071579 13.3571469178070377, 234.9491086875029850 13.3276303356333283, 234.9605473127224400 13.2981072167973018, 234.9713644883816528 13.2686504102610936, 234.9828696165008637 13.2391412527097092, 234.9952823982227130 13.2095571314674807, 235.0050468585136798 13.1802195785160361, 235.0136287193242595 13.1509958943322758, 235.0235378048001280 13.1216592930154938, 235.0329021842475186 13.0923789231397443, 235.0428057061670870 13.0630569403359651, 235.0521327241830534 13.0337940412378153, 235.0625135585413545 13.0044431978327815, 235.0717953474143371 12.9752242363750199, 235.0824041974599936 12.9459172659310724, 235.0940750611306953 12.9165220486511139, 235.1065367130434538 12.8870631262631701, 235.1158182782193933 12.8578978126154855, 235.1266925973408490 12.8285965912313760, 235.1379058037396419 12.7992723621202824, 235.1493323378101650 12.7699364616138098, 235.1597243389989558 12.7407009724266018, 235.1712532703696752 12.7113709030264008, 235.1827465274411963 12.6820449580672978, 235.1941234200102997 12.6527307198260388, 235.2050247074454887 12.6234666645800822, 235.2163270344595674 12.5941742131890280, 235.2277785289594476 12.5648759860479498, 235.2385543623155684 12.5356458389338687, 235.2508847973742263 12.5062841833256240, 235.2633168672380179 12.4769211489348688, 235.2728422409363418 12.4478256526217539, 235.2842755044437695 12.4185672191257606, 235.2958366454948305 12.3892784337455950, 235.3093707410059778 12.3597959247926550, 235.3187766848186300 12.3306894424851734, 235.3306779349187252 12.3013678208742334, 235.3409393036719734 12.2721999890154496, 235.3501830900792697 12.2431303053602285, 235.3613812715611857 12.2138940015926600, 235.3730377292361027 12.1846245064817111, 235.3841031523518836 12.1554152455634981, 235.3951438601937411 12.1262158016385921, 235.4062404944434377 12.0970164244441882, 235.4175069429075506 12.0678071864317698, 235.4293307085960976 12.0385561765480453, 235.4421268139013819 12.0092266347274368, 235.4553072872581367 11.9798708588786411, 235.4690820770260586 11.9504702829346705, 235.4835006225113148 11.9210206020889959, 235.4961155771548533 11.8917388117403320, 235.5075708156150540 11.8625676810302298, 235.5232281849824574 11.8330323003577558, 235.5347037438566247 11.8038785679843166, 235.5485065160783336 11.7745299290467322, 235.5600805544178797 11.7453864480755730, 235.5703341981817971 11.7163675611314986, 235.5839461654653064 11.6870597840608745, 235.5954648223914205 11.6579449443162755, 235.6092027508724414 11.6286421683112540, 235.6216508278128572 11.5994613207307218, 235.6324629760508742 11.5704327635111550, 235.6428079768970747 11.5414532834834862, 235.6568704546873221 11.5121474637012930, 235.6720551508909693 11.4827446025172453, 235.6855992620544384 11.4534944270637578, 235.6986437499925842 11.4242963929699783, 235.7102185389267390 11.3952357468157128, 235.7213320137738890 11.3662236884557988, 235.7337303976148064 11.3371068076533099, 235.7468324017843884 11.3079363222290397, 235.7609241197101255 11.2786872344088369, 235.7716656140711393 11.2497402908686457, 235.7842478418046426 11.2206676906020739, 235.7973744369537030 11.1915819291138714, 235.8105307899923275 11.1625020488196487, 235.8249424344240310 11.1333208343726557, 235.8395991584713158 11.1041268270855316, 235.8525654519300474 11.0750892599493138, 235.8667968122787499 11.0459497145021359, 235.8800180837417315 11.0169070401683147, 235.8933878033427618 10.9878600068247341, 235.9057151449407854 10.9589125063384909, 235.9193942261307484 10.9298345394041228, 235.9332417115621183 10.9007304194589096, 235.9474303826681876 10.8716051631116191, 235.9606809027555983 10.8425701612107286, 235.9745969210545127 10.8134858268618217, 235.9749642465217789 10.7716809281121915, 234.3062264801342849 10.9140277809662685, 233.0568672341352681 11.0146280042103673, 232.0879579900228578 11.0891193379889543, 231.2922763753067841 11.1479476252960747, 230.6222024977125500 11.1958368476612193, 230.0451126661421029 11.2358585089279419, 229.5399124327023230 11.2699591633018521, 229.0910977852357462 11.2995144425208274, 228.6886580791978076 11.3254217054343087, 228.3230615139402744 11.3484629748790784, 227.9885578563570618 11.3691297953353843, 227.6794424865441044 11.3878696987312100, 227.3925662525314522 11.4049521734577652, 227.1244248889508128 11.4206460692728218, 226.8725374557993462 11.4351462062810540, 226.6348499723092687 11.4486118924843723, 226.4089327375857579 11.4612113075361997, 226.1941018513874440 11.4730141135446004, 225.9885536989950765 11.4841415383497090, 225.7906841315599706 11.4946974768467634, 225.5999034371616574 11.5047316362642977, 225.5366591324245746 11.5127495864397975, 225.5372162978353572 11.5505095085783491, 225.5385783526444357 11.5787872089973352, 225.5399439564289139 11.6070707014818648, 225.5412985550382530 11.6353606495820010, 225.5426749067480046 11.6636555270124038, 225.5440079340318960 11.6919607904039129, 225.5452785827496598 11.7202774520580331, 225.5466317325111163 11.7485961872312483, 225.5479770002908424 11.7769211830304741, 225.5492659393223391 11.8052546885614369, 225.5505881749857622 11.8335925233223165, 225.5519504051864885 11.8619343622035611, 225.5533077637229837 11.8902822873329477, 225.5546618029108004 11.9186362154185161, 225.5560341832702989 11.9469951283911566, 225.5574676202388389 11.9753643758004653, 225.5590191880281168 12.0037416641995005, 225.5604650461106075 12.0321296626578587, 225.5618813353500229 12.0605248048462173, 225.5632281962757872 12.0889289499598043, 225.5646369199462526 12.1173359470051221, 225.5660229391118605 12.1457497416407474, 225.5674569183579194 12.1741670185685997, 225.5688635323882067 12.2025912929272309, 225.5703109884151729 12.2310193625166725, 225.5717101870569650 12.2594456807874739, 225.5731175923956187 12.2878670763541500, 225.5745039964396881 12.3162951832856447, 225.5759288544678611 12.3447271997579406, 225.5773960466558776 12.3731629334220674, 225.5788519147757256 12.4016048933211422, 225.5803416813689353 12.4300509429484372, 225.5816881712830764 12.4585094105300680, 225.5830920732209677 12.4869708458745645, 225.5845923566245972 12.5154334019429090, 225.5860403615774601 12.5439037730187160, 225.5874610048106490 12.5723807663083029, 225.5889177558462961 12.6008616957480903, 225.5903515793980603 12.6293493339278289, 225.5917525550027278 12.6578441437269795, 225.5931508646095836 12.6863446909928665, 225.5945943914247209 12.7148487021393546, 225.5960008914007062 12.7433600562760514, 225.5974037574715112 12.7718771644621114, 225.5988233756805812 12.8003990547538926, 225.6002721985445305 12.8289323632807033, 225.6017366238626209 12.8574781001374152, 225.6031654657655849 12.8860310258692046, 225.6045218087163846 12.9145928795711811, 225.6058798582327256 12.9431601392295903, 225.6072524532902150 12.9717321855179382, 225.6086135210702253 13.0003102437824012, 225.6099832816835260 13.0288933479394586, 225.6113275367279982 13.0574831085252754, 225.6125545095889038 13.0860838740040997, 225.6138028099004487 13.1146752009334939, 225.6150778990239303 13.1432560934036342, 225.6162422079480336 13.1718477388765507, 225.6173737918639972 13.2004464226429015, 225.6185699941046323 13.2290475090887476, 225.6198157863268818 13.2576516980325110, 225.6210409897880425 13.2862623167968366, 225.6223663466021208 13.3148736072723342, 225.6236482962571017 13.3434923930890630, 225.6249275337829943 13.3721167292154703, 225.6260876156256927 13.4007428090886318, 225.6271482815306797 13.4293691988637303, 225.6282069815529780 13.4580011367591332, 225.6292588864900210 13.4866388418782552, 225.6301745217899395 13.5152885013190946, 225.6310854300369613 13.5439438196573718, 225.6319335368581562 13.5726075681328187, 225.6327480637721408 13.6012783439191072, 225.6337658892684601 13.6299447768856581, 225.6347445572798449 13.6586184766783365, 225.6357681744815977 13.6873088187964829, 225.6369098793816477 13.7160129715247390, 225.6377132282490265 13.7447386492292605, 225.6381004489273039 13.7734895897375562, 225.6384425966499521 13.8022479648461314, 225.6384635187985168 13.8310270394557975, 225.6377101170312471 13.8598485939885787, 225.6365618619697102 13.8886943870818591, 225.6366386083671500 13.9174865184715539, 225.6368522670141488 13.9462772851726733, 225.6372469180841165 13.9750578095759828, 225.6375557773037883 14.0038405749019876, 225.6379196200062438 14.0326259369682145, 225.6383864008217586 14.0614115709575014, 225.6384839524231722 14.0902202098120508, 225.6385199698933661 14.1190370310537716, 225.6386402111627945 14.1478549996390157, 225.6388533682960542 14.1766736842509715, 225.6393890846581769 14.2054819921208431, 225.6400014732377883 14.2342917634527293, 225.6406357401889125 14.2631057033773967, 225.6413577972446660 14.2919207956900092, 225.6418752526102196 14.3207511289150276, 225.6423111100062329 14.3495907576735444, 225.6427252197016458 14.3784367852521395, 225.6431428511371848 14.4072879797836073, 225.6435675918646950 14.4361441562654509, 225.6440032993549778 14.4650051196891720, 225.6444282863794513 14.4938719061237027, 225.6447431617766881 14.5227493163251431, 225.6449678238142837 14.5516363830435864, 225.6451771981112131 14.5805294712477540, 225.6454008616848057 14.6094271375165317, 225.6457594677577276 14.6383235264443314, 225.6462473563883577 14.6672188995938093, 225.6469455931328980 14.6961093141824346, 225.6476484941468641 14.7250047183178641, 225.6482967787019618 14.7539079769099715, 225.6489887274379385 14.7828143149827476, 225.6497710824961871 14.8117214566605426, 225.6506478933443134 14.8406202374820904, 225.6513685056088434 14.8695223479765239, 225.6517833687364600 14.8984445258470757, 225.6521860009187606 14.9273725222218285, 225.6524979026756341 14.9563101431619483, 225.6530000040127959 14.9852437286796327, 225.6535139645618244 15.0141819273875878, 225.6541788974428187 15.0431179640211869, 225.6549168074626550 15.0720556125502370, 225.6555029956988676 15.1010057984378250, 225.6560645874875775 15.1299567017406442, 225.6566919791503381 15.1589036199086973, 225.6590152644028535 15.2022608722661996))) +MULTIPOLYGON (((222.1624630089112600 22.8951593815765975, 222.3339262687833298 22.8936274635201933, 222.4918199237260126 22.8892870654137894, 222.6447333639080739 22.8849208495167957, 222.7860219888753193 22.8807521225023223, 222.9282477870870309 22.8764101243668883, 223.0766229276345314 22.8717188352622998, 223.2163749624365039 22.8671654664371253, 223.3566752167436107 22.8624523492497147, 223.4932994496834340 22.8577303021729108, 223.5898174628189281 22.8543561892909572, 223.6952453710475481 22.8505789352643909, 223.7986306393881932 22.8467987454227668, 223.8996064301338151 22.8430346286116439, 223.9985403180926085 22.8392773189229672, 224.0959558234478664 22.8355100060666807, 224.1910351188811603 22.8317699191233139, 224.2846900711769536 22.8280237033391842, 224.3794587089748518 22.8241645908717423, 224.4717629678306992 22.8203469629269193, 224.5633371488343641 22.8164984586216306, 224.6543473834239535 22.8126123378004237, 224.7440398506533654 22.8087255479843911, 224.8325040184724344 22.8048406023555081, 224.9212555339037465 22.8008894991381190, 225.0106580796201285 22.7968435241163121, 225.1000007523969089 22.7927413519529303, 225.1888277939080467 22.7886023389369292, 225.2781780343506455 22.7843836470616807, 225.3686924207756874 22.7800534080020824, 225.4590165302644209 22.7756708267019476, 225.5508198722963016 22.7711582077242767, 225.6422477738819055 22.7666013654949673, 225.7360433563496827 22.7618673524955746, 225.8308947878517756 22.7570161333581531, 225.9265649628134156 22.7520576054340644, 226.0249054597537111 22.7468951627925016, 226.1249460280650965 22.7415734576187667, 226.2278092106255940 22.7360294680846771, 226.3331097609170968 22.7302774767668794, 226.4411383576406251 22.7242960814231623, 226.5516850443091244 22.7180904733142981, 226.6656172308655641 22.7116060760510265, 226.7845310826328102 22.7047439557828277, 226.9071485395683396 22.6975653038123326, 227.0314420891992313 22.6901792460417475, 227.1839803972898721 22.6810011325290652, 227.3309890067329206 22.6719922436194885, 227.4852586254458799 22.6623817127882177, 227.6478995917764507 22.6520771999861843, 227.8244768709272137 22.6406958387339330, 228.0131836014743953 22.6283059281074799, 228.2162944595033309 22.6147104949552720, 228.4292048376534865 22.6001638596067238, 228.6562586366676726 22.5843230936522517, 228.9060301284106345 22.5665157365526738, 229.1825185883826350 22.5463385024831275, 229.4889099643409338 22.5234076852296603, 229.8236002572373025 22.4976669569224619, 230.1950383114757130 22.4682603298959584, 230.6140382404059324 22.4340342653553400, 231.0891122288767292 22.3938771030052273, 231.6395906402595131 22.3455606942543383, 232.2933645144547086 22.2856988304728816, 233.0468764051967696 22.2096316619507910, 233.0785652638046201 21.8363002183258672, 233.1127848752224736 21.4745876776407023, 233.1495149588512277 21.1131910862528756, 233.1846174932388749 20.7524229386275891, 233.2281738095738319 20.3912888538266621, 233.2728633418433333 20.0308452349020740, 233.3250187359038534 19.6705419579676999, 233.3796606407786385 19.3110134145879755, 233.4385822536837054 18.9512211316246884, 233.5048685308843801 18.5912443274153567, 233.5706311380743045 18.2318521979120796, 233.6452805855884662 17.8721331937102619, 233.7218088442428154 17.5133026583395761, 233.8009389222396521 17.1546474914662461, 233.8864792058807325 16.7969080412233396, 233.9697213479607854 16.4397025376815620, 234.0827689780276160 16.0803320887725256, 234.1849417847580810 15.7230703711881485, 234.2920495505410940 15.3662600700791199, 234.4024838161147954 15.0099330830396873, 234.5149369367873078 14.6539884211796085, 234.6379763594737256 14.2984363661579739, 234.7624200521307785 13.9436616004926499, 234.8942605546816083 13.5892090201901361, 235.0287860913971087 13.2349331360644609, 235.1520541038566705 12.8829103201224786, 235.2867364532864087 12.5312745148577296, 235.4233014408581255 12.1800898429156153, 235.5708833501624895 11.8287500973666599, 235.7235495084901800 11.4781459017146013, 235.8797763957555844 11.1284558105932163, 236.0525317933703491 10.7671680704070027, 234.5539738435639094 10.8934756928845555, 233.4407131631619450 10.9842712723458558, 232.5469229652730405 11.0542229776369663, 231.8057772059925981 11.1102241836769817, 231.1727759778516997 11.1565989553883931, 230.6222024977125500 11.1958368476612193, 230.1360978921081824 11.2296246903222876, 229.7011060076305569 11.2591734075647274, 229.3092627460675033 11.2852352682155779, 228.9523786369141760 11.3085085479038074, 228.6255699416205687 11.3294320811030538, 228.3230615139402744 11.3484629748790784, 228.0424929933100202 11.3658248267683604, 227.7797848238633946 11.3818240807472471, 227.5335303503409534 11.3965959501297114, 227.3013618133137186 11.4103203927840031, 227.0813921446024040 11.4231400422407940, 226.8725374557993462 11.4351462062810540, 226.6735784057323144 11.4464323335893017, 226.4830830480069608 11.4570977194829027, 226.3002739486595658 11.4672030229303115, 226.1246140672839147 11.4767939954809552, 225.9550662527250040 11.4859387811263236, 225.7906841315599706 11.4946974768467634, 225.6312478555560688 11.5030927722663794, 225.4762447625245159 11.5111601660448777, 225.3250842761415527 11.5189369296322006, 225.1774439551113858 11.5264465188783962, 225.0328448253088141 11.5337180770247567, 224.8908763596579661 11.5407761760249485, 224.7513584997251144 11.5476346729728920, 224.6139594562524167 11.5543129777076103, 224.4784375363008166 11.5608260941027599, 224.3444652819599128 11.5671914448426563, 224.2117774258953204 11.5734232007857365, 224.0801718772195841 11.5795330298010324, 223.9493664901852981 11.5855344995887286, 223.8191624724384212 11.5914391819224125, 223.6892422590836134 11.5972592901497737, 223.5594084415269833 11.6030053638277568, 223.4294005333740074 11.6086896685705732, 223.2989722102234396 11.6143216904755153, 223.1678913125375061 11.6199107220438531, 223.0358968024204955 11.6254674694465869, 222.9027074603748133 11.6310028545879938, 222.7681514532252720 11.6365211163933129, 222.6319141538593271 11.6420339437049947, 222.4937638625463023 11.6475477129612308, 222.3535187113752443 11.6530658977189194, 222.2106332312229426 11.6586083764543087, 222.0649326370227072 11.6641761438836653, 221.9159984711554046 11.6697805626031812, 221.7637180402841466 11.6754184975181374, 221.6071946734441269 11.6811193203291595, 221.4462705120732551 11.6868790352296763, 221.2800176036379014 11.6927238980664452, 221.1082343240165642 11.6986486654835549, 220.9302181846902897 11.7046664470968551, 220.7448115762732925 11.7108046009476414, 220.5512576667633198 11.7170716871744123, 220.3489604038685172 11.7234675875962697, 220.1364090861389968 11.7300207161521115, 219.9120955538621729 11.7367529071512777, 219.6885213955372649 11.7467997455390734, 219.7799904234039730 12.0939511402888975, 219.8674330692829244 12.4316415920653984, 219.9609614049581694 12.7696857712045659, 220.0435238279249006 13.1088820272039293, 220.1287454668107273 13.4490035478161278, 220.2143246165954906 13.7896014367970157, 220.2996554937522831 14.1310123204512017, 220.3856329594830470 14.4729591087435345, 220.4702000948232694 14.8160511960587158, 220.5542362850947598 15.1597899704439243, 220.6372073271448073 15.5039849266983030, 220.7215757287766564 15.8490755470569642, 220.8003852058058385 16.1950297579101310, 220.8780519442242394 16.5414416418538295, 220.9577127122793740 16.8886320293686296, 221.0492640309013552 17.2360431262770000, 221.2038504548904143 17.5820618221894307, 221.2332579885822668 17.9327608896160093, 221.3064102416667254 18.2825314909653507, 221.3767736088032905 18.6330506091271673, 221.4437577954094252 18.9842324709429775, 221.5157733841184893 19.3357292607878364, 221.6414955699297025 19.6862695154174325, 221.7040348686778088 20.0392573980041320, 221.7734370623848577 20.3928494143094561, 221.8288813389624750 20.7473192817873482, 221.8918121764575062 21.1019252294165227, 221.9100625117274888 21.4581527655943702, 221.9689999677077026 21.8138700176372851, 222.0351508916823775 22.1699530582424984, 222.0994691521187576 22.5264154382736272, 222.1624630089112600 22.8951593815765975))) diff --git a/isis/src/base/objs/ImagePolygon/ImagePolygon_Linux_i686_RedHat5_4.truth b/isis/src/base/objs/ImagePolygon/ImagePolygon_Linux_i686_RedHat5_4.truth new file mode 100644 index 0000000000000000000000000000000000000000..4b1ab6e109a9c48ae4fe4ba6458b3f98608f49a1 --- /dev/null +++ b/isis/src/base/objs/ImagePolygon/ImagePolygon_Linux_i686_RedHat5_4.truth @@ -0,0 +1,3 @@ +MULTIPOLYGON (((223.8172826871150392 34.4551387031975906, 223.8417027794513672 34.4596506067936588, 223.8575436553770714 34.4592772203974533, 223.8731987948544884 34.4589061404385077, 223.8888001596040453 34.4585342459693109, 223.9044019981608358 34.4581602383999694, 223.9200661672346939 34.4577826050169165, 223.9355075425064001 34.4574083329785168, 223.9508457646854538 34.4570345512927645, 223.9660146266744221 34.4566629442804810, 223.9810473117178447 34.4562927477356951, 223.9957878474442339 34.4559279257479716, 224.0106582442915908 34.4555579477815925, 224.0255459277288139 34.4551856182047374, 224.0403444766605787 34.4548136400302099, 224.0550707903117598 34.4544416141928949, 224.0696826279009031 34.4540706529749698, 224.0842130300090105 34.4536999452778474, 224.0986612451643509 34.4533295403593272, 224.1130364690419867 34.4529592284912880, 224.1273202300474452 34.4525895195669563, 224.1415662443576764 34.4522190341699357, 224.1557339919143885 34.4518488560984437, 224.1698107919081906 34.4514793495923044, 224.1838116921205994 34.4511101459255826, 224.1977227035095268 34.4507416461034310, 224.2115924901995356 34.4503725739912667, 224.2254006441162915 34.4500034948312930, 224.2391929104846611 34.4496331906106832, 224.2529511041628325 34.4492621619975878, 224.2666975063020232 34.4488898122485239, 224.2803860066288735 34.4485174108845698, 224.2940079847741686 34.4481452154172487, 224.3075938799341031 34.4477724067580056, 224.3210795842228720 34.4474007778023150, 224.3344990942869401 34.4470294145163933, 224.3478450165269180 34.4466585462406627, 224.3611125162273083 34.4462883335280097, 224.3742955932710856 34.4459189717640371, 224.3874260849736970 34.4455495873438409, 224.4004958876452633 34.4451804280896852, 224.4135260618628820 34.4448109131363154, 224.4264828609272513 34.4444420220934973, 224.4393721009315072 34.4440736116739146, 224.4522012233351234 34.4437054891116503, 224.4649910969210680 34.4433370696326904, 224.4777393619959582 34.4429684346240776, 224.4904489206706444 34.4425995129701761, 224.5030718093741484 34.4422317209555473, 224.5156259769345866 34.4418645588172865, 224.5281770922377120 34.4414961128652166, 224.5407219882790457 34.4411264781702400, 224.5531975742957229 34.4407575294710284, 224.5656264625203562 34.4403886151251726, 224.5780227095267492 34.4400193298509762, 224.5903757297269578 34.4396500014264859, 224.6026728254565228 34.4392810254014137, 224.6148668913573658 34.4389138408317379, 224.6269709754118651 34.4385480839034486, 224.6390599334609988 34.4381815077720930, 224.6511372140055300 34.4378140122935079, 224.6632067785473623 34.4374454802786261, 224.6751614662134671 34.4370792015270695, 224.6870933910036001 34.4367123757492308, 224.6989898632979532 34.4363454017714901, 224.7108678965891500 34.4359777635831534, 224.7226881484133685 34.4356106890301774, 224.7344958302966518 34.4352427866590816, 224.7462652761780646 34.4348748627154819, 224.7579793002597626 34.4345074674088423, 224.7696431367716627 34.4341404524924286, 224.7812728008222791 34.4337733276717159, 224.7928435544382069 34.4334068856012721, 224.8043847867617160 34.4330402110380760, 224.8157283420019041 34.4326786628983683, 224.8270886233244994 34.4323154552239430, 224.8384166745837831 34.4319521504694563, 224.8497524406973866 34.4315874761224663, 224.8610108250487087 34.4312241691771774, 224.8722867697455854 34.4308591872096557, 224.8835699922446452 34.4304928587168035, 224.8948651191569468 34.4301250320693342, 224.9061662756241446 34.4297558957457994, 224.9173542817119369 34.4293893382984280, 224.9284086365550763 34.4290260617306529, 224.9394220908251327 34.4286630587300806, 224.9504388177020076 34.4282988872681628, 224.9614347391653268 34.4279343413389043, 224.9724090215663352 34.4275694545411639, 224.9833614192173457 34.4272042412541666, 224.9942931925034486 34.4268386658471499, 225.0052127358298151 34.4264724543783416, 225.0161268911886054 34.4261053818628895, 225.0270072241944490 34.4257384032388458, 225.0379099783205277 34.4253696379527341, 225.0487812549144735 34.4250008965078678, 225.0595876459501312 34.4246333159996070, 225.0703030757329941 34.4242677966519963, 225.0809691074227601 34.4239029513888539, 225.0916138570161706 34.4235378365167506, 225.1022391576242683 34.4231723954175806, 225.1128542317605081 34.4228063181412836, 225.1234516168084951 34.4224398636277300, 225.1340217162214401 34.4220733666453924, 225.1445720849020802 34.4217065743085584, 225.1551012336424549 34.4213395435047218, 225.1655864786240500 34.4209730652326300, 225.1760248993977882 34.4206072522224815, 225.1864409930356885 34.4202412645735265, 225.1968389824973826 34.4198749610789960, 225.2072200098365897 34.4195083067898224, 225.2175785697437789 34.4191414991763835, 225.2279161215742533 34.4187744930007398, 225.2382328071402071 34.4184072888908830, 225.2485261486005186 34.4180399797886807, 225.2587970263030854 34.4176725407227835, 225.2690410352727781 34.4173051336376261, 225.2792535965569698 34.4169379280283323, 225.2894249396388773 34.4165712795181022, 225.2995612324063188 34.4162049784147968, 225.3096797795645614 34.4158384150564345, 225.3197769941544948 34.4154717225693290, 225.3298508715459150 34.4151049783840435, 225.3399032250165703 34.4147381232054812, 225.3499338576864091 34.4143711696130268, 225.3599442461522528 34.4140040697767873, 225.3699387631642708 34.4136366705630508, 225.3799126564848052 34.4132691484824491, 225.3898592055926997 34.4129017530111838, 225.3997746327333687 34.4125346284357292, 225.4096413759963013 34.4121684232215301, 225.4194664480812378 34.4118028922520267, 225.4292333251142963 34.4114386507455166, 225.4389847119527985 34.4110741439216028, 225.4487227950831709 34.4107092951739943, 225.4584529700733810 34.4103439089537062, 225.4681791118518390 34.4099778443088908, 225.4779501834676410 34.4096092906042443, 225.4877658689587179 34.4092382503042771, 225.4975606254193394 34.4088671492795868, 225.5073160520850308 34.4084966775202332, 225.5170945589782434 34.4081245164470388, 225.5268331233909009 34.4077530165447669, 225.5365021994340680 34.4073832929153340, 225.5461190551428672 34.4070147130339521, 225.5556995065214494 34.4066466939793116, 225.5652214497965247 34.4062800757604279, 225.5747432098701211 34.4059126713390597, 225.5842560908804444 34.4055448096861980, 225.5937778006389749 34.4051758228821214, 225.6033009158175560 34.4048059910247375, 225.6128238278627123 34.4044353753846437, 225.6223471750505212 34.4040639521956990, 225.6318758783661451 34.4036915343189733, 225.6414016415949959 34.4033184379288883, 225.6509363628299241 34.4029442091229640, 225.6604947562338452 34.4025682830337516, 225.6700415057191833 34.4021920107971724, 225.6795791566906360 34.4018152974535525, 225.6890709331013625 34.4014395612861392, 225.6985268751064666 34.4010644244605501, 225.7079299362157485 34.4006905527387730, 225.7172925181210417 34.4003174767084232, 225.7266351872429198 34.3999444074105725, 225.7359624913471805 34.3995711724671480, 225.7452560214498760 34.3991984906232560, 225.7545267975936838 34.3988259393811830, 225.7637889836569514 34.3984529710283411, 225.7730507645297848 34.3980792679652438, 225.7823252012858291 34.3977043200822976, 225.7916004169256610 34.3973285907622284, 225.8008725343179037 34.3969522324371084, 225.8101369195402413 34.3965754281377940, 225.8193892452067359 34.3961983498649957, 225.8286274988710716 34.3958210793992976, 225.8378496687873564 34.3954436988933523, 225.8470551995822007 34.3950662333900752, 225.8562326011218033 34.3946891401953891, 225.8653930029271351 34.3943119836700717, 225.8745410760951984 34.3939345817962447, 225.8836776373707664 34.3935569045111080, 225.8928019411298180 34.3931789836151580, 225.9019194640990804 34.3928006036003566, 225.9110308752194385 34.3924217393303877, 225.9201549499825887 34.3920416440390966, 225.9292743320634145 34.3916610091261106, 225.9383845714752397 34.3912800135874335, 225.9474795314372670 34.3908989045497577, 225.9565581779545482 34.3905177258943411, 225.9656244992629581 34.3901363204726565, 225.9746802477716869 34.3897546201018542, 225.9837284337634173 34.3893725058620632, 225.9927658600073812 34.3889901075809234, 226.0017891753243475 34.3886075616179951, 226.0108161763200769 34.3882241546364895, 226.0198457173729878 34.3878399332780305, 226.0288659305028887 34.3874553758755184, 226.0378750537552150 34.3870705549601965, 226.0468586590255313 34.3866860532718803, 226.0558323075141232 34.3863012460278199, 226.0647969809214999 34.3859160949781852, 226.0737494779376391 34.3855307303640743, 226.0826909505379092 34.3851451069165961, 226.0916392243478583 34.3847585070685895, 226.1005846294034143 34.3843713216575466, 226.1095237944622625 34.3839836876697547, 226.1184552396350682 34.3835956657888744, 226.1273766599998396 34.3832073497904531, 226.1362843513835799 34.3828188894718991, 226.1451789838510820 34.3824302581018841, 226.1540696341334922 34.3820410909009055, 226.1629557016597687 34.3816514127115553, 226.1718415645642324 34.3812610486584163, 226.1807230054595550 34.3808701689397935, 226.1896010103831145 34.3804787348665357, 226.1984731024826090 34.3800868461449554, 226.2073393250205413 34.3796945013437423, 226.2162010894513458 34.3793016446030393, 226.2250584402896720 34.3789082746488859, 226.2339210610192026 34.3785140100478799, 226.2427791039953604 34.3781192424446971, 226.2516314343407373 34.3777240170122553, 226.2604782195461155 34.3773283273222461, 226.2693193564175260 34.3769321773464114, 226.2781549132864427 34.3765355641091688, 226.2869854330468797 34.3761384662781353, 226.2958114626269435 34.3757408626804448, 226.3046334835790958 34.3753427350574086, 226.3134536502247158 34.3749440039339902, 226.3222666039636977 34.3745448676996475, 226.3310674201009078 34.3741454966233277, 226.3398662973834803 34.3737455141035966, 226.3486632146753266 34.3733449208397204, 226.3574580470481123 34.3729437207094293, 226.3662507195254250 34.3725419150449554, 226.3750416931369216 34.3721394879113191, 226.3838307521617708 34.3717364447303808, 226.3926183115110291 34.3713327722454522, 226.4014042158854068 34.3709284730591946, 226.4101886820694745 34.3705235398177749, 226.4189713667430510 34.3701179689839478, 226.4277528949876341 34.3697117361028148, 226.4365339441959577 34.3693048462083510, 226.4453141371926108 34.3688973010714705, 226.4540932758116867 34.3684891263368613, 226.4628714412468469 34.3680802910519034, 226.4716492125849641 34.3676707556087422, 226.4804266127524670 34.3672605341961770, 226.4892039200687748 34.3668496115516149, 226.4979812270960053 34.3664379861530804, 226.5067586403114319 34.3660256540135123, 226.5155350783857955 34.3656126842405598, 226.5243113274227085 34.3651990255176401, 226.5330863836839796 34.3647847379392459, 226.5418613931262257 34.3643697522112461, 226.5506364357621862 34.3639540649148643, 226.5594125115546262 34.3635376202989562, 226.5681899791689489 34.3631204006612592, 226.5769703953577334 34.3627023215986753, 226.5857530174846772 34.3622834277597846, 226.5945393457434420 34.3618636386090444, 226.6033280976995172 34.3614430268793072, 226.6121204829106546 34.3610215278312623, 226.6209149844756610 34.3605992250073129, 226.6297112468491548 34.3601761376944168, 226.6385086581317410 34.3597522985732198, 226.6473076485042952 34.3593276841362254, 226.6561088518948566 34.3589022602962544, 226.6649128221912690 34.3584759975395642, 226.6737198569159943 34.3580488801543851, 226.6825293890413491 34.3576209382972166, 226.6913400811758663 34.3571922426228298, 226.7001540295706832 34.3567626817938603, 226.7089712049677246 34.3563322572982912, 226.7177870375189173 34.3559012100899182, 226.7266041828106324 34.3554693993520672, 226.7354247297424195 34.3550367146799474, 226.7442492611482123 34.3546031252373538, 226.7530788599001141 34.3541685738807345, 226.7619128745825776 34.3537330946952437, 226.7707514832079028 34.3532966780217492, 226.7795960290026471 34.3528592528926850, 226.7884459906888708 34.3524208463128033, 226.7973003349396492 34.3519815121097523, 226.8061593642074172 34.3515412338454738, 226.8150233317549578 34.3510999976269247, 226.8238934698206606 34.3506577380458964, 226.8327720567345978 34.3502143345875908, 226.8416573813213120 34.3497698764048707, 226.8505497655342538 34.3493243457024064, 226.8594358490678644 34.3488784448401674, 226.8683250410209098 34.3484316782386045, 226.8772265484981290 34.3479835601684655, 226.8861363120278725 34.3475343032454887, 226.8950567593701066 34.3470837782926424, 226.9039829498998984 34.3466322446343071, 226.9129146680929807 34.3461797126517538, 226.9218556874078843 34.3457259819622749, 226.9308045477932865 34.3452711283535947, 226.9397756292512156 34.3448143896436733, 226.9487603184119848 34.3443562189215470, 226.9577713539436843 34.3438959390267016, 226.9667906962713460 34.3434345028913981, 226.9758185915840727 34.3429718958397459, 226.9848216200803392 34.3425098915043279, 226.9938252716408158 34.3420471375395024, 227.0028484628004719 34.3415826268728566, 227.0118809439651386 34.3411169022523879, 227.0209235817678177 34.3406499157369396, 227.0299791780909970 34.3401815159329473, 227.0390478252923572 34.3397116955650006, 227.0481467096582833 34.3392395334901579, 227.0572602651000125 34.3387658575312145, 227.0663771857987570 34.3382912704903447, 227.0755008947066642 34.3378155878481692, 227.0846303913033353 34.3373388617669448, 227.0937637963996281 34.3368611918346360, 227.1029086134994657 34.3363821734389703, 227.1120687985093696 34.3359015912790184, 227.1212359111365231 34.3354198972308851, 227.1304019305011082 34.3349375224572597, 227.1395758195951373 34.3344539826583812, 227.1487597349220380 34.3339691594793663, 227.1579902583206376 34.3334810705894782, 227.1672328061847281 34.3329915813299635, 227.1764712676893794 34.3325015631449872, 227.1857181919703237 34.3320103348058581, 227.1949746842976765 34.3315178342700378, 227.2042427831781026 34.3310239484103192, 227.2135235122771917 34.3305286188862198, 227.2228146140626563 34.3300319661149231, 227.2321158182055001 34.3295340025165387, 227.2414261879327171 34.3290347770175401, 227.2507440105512444 34.3285343812617540, 227.2600744088049396 34.3280325326081837, 227.2694283383896732 34.3275286269244333, 227.2787965981322316 34.3270231648313313, 227.2881796631024258 34.3265161169777642, 227.2975768164241970 34.3260075195247154, 227.3069878365814702 34.3254973814854338, 227.3164104609644482 34.3249858246237451, 227.3258502854774861 34.3244725368218511, 227.3353080996625977 34.3239574704821351, 227.3447883386974127 34.3234403757068378, 227.3542849111613009 34.3229215855092846, 227.3637955610379038 34.3224012214535676, 227.3733236581736321 34.3218790927276061, 227.3828696239587828 34.3213551717971868, 227.3924291244449307 34.3208296962129822, 227.4020038477810033 34.3203025684271594, 227.4115915765554234 34.3197739087827998, 227.4211903006491866 34.3192438266352369, 227.4308034100234579 34.3187121291771930, 227.4404322668865461 34.3181787364366357, 227.4500783315511114 34.3176435625182847, 227.4597408211415939 34.3171066473257653, 227.4694373999132608 34.3165669914653151, 227.4791525994482413 34.3160254598141350, 227.4888678788014147 34.3154830953614152, 227.4985957068911944 34.3149391922755242, 227.5083373853007060 34.3143936736176798, 227.5181018062584997 34.3138460315021732, 227.5278825759299082 34.3132966235528087, 227.5376789842163987 34.3127454860494296, 227.5475028125035521 34.3121919441228513, 227.5573500149315294 34.3116362218249122, 227.5672257338917746 34.3110780197670167, 227.5771363516526549 34.3105169660666647, 227.5870780116527783 34.3099532730359726, 227.5970431329110681 34.3093873676510910, 227.6070304509182449 34.3088193165897337, 227.6170402145314711 34.3082490999014738, 227.6270614888661612 34.3076773413150846, 227.6371021487258588 34.3071035837345661, 227.6471620471891413 34.3065278306009773, 227.6572333482755539 34.3059505298130745, 227.6673250879414070 34.3053711551990759, 227.6774425887817301 34.3047893929307435, 227.6875956283597020 34.3042046688993238, 227.6977747164864354 34.3036175256546443, 227.7079695685293927 34.3030285549957057, 227.7181855113128108 34.3024374421746572, 227.7284236548605918 34.3018441168054125, 227.7386810962264576 34.3012487426516728, 227.7489607488535626 34.3006511440034032, 227.7592652945303939 34.3000511577575935, 227.7696049562623273 34.2994481773265747, 227.7799661327243541 34.2988429929067777, 227.7903495498963480 34.2982355559401029, 227.8007531420689702 34.2976259821431668, 227.8111804588746736 34.2970140564827730, 227.8216354765032463 34.2963995375121584, 227.8321461589445107 34.2957807626370936, 227.8426781271888899 34.2951597550205207, 227.8532313530369038 34.2945365104264113, 227.8637943594639239 34.2939117051551818, 227.8743681842673254 34.2932852744245977, 227.8849595330214868 34.2926568152274598, 227.8955699765431575 34.2920262287965869, 227.9062407193617048 34.2913910463675435, 227.9169476338616107 34.2907526963874574, 227.9276713907188707 34.2901123278853248, 227.9383745218067929 34.2894721856800047, 227.9490646281539057 34.2888318175634481, 227.9597329801405579 34.2881917520726702, 227.9704830712227306 34.2875457534077910, 227.9813063056207341 34.2868943188163797, 227.9922004455371223 34.2862375638696832, 228.0031311317907523 34.2855775503149829, 228.0140933799503387 34.2849145702371345, 228.0250913628242984 34.2842483611924891, 228.0361342648187701 34.2835783543212358, 228.0472235719730350 34.2829044464456985, 228.0583488204325704 34.2822272629398910, 228.0695055535343272 34.2815470658358095, 228.0806796288332521 34.2808647115191079, 228.0918858624786196 34.2801792866224346, 228.1031233132032412 34.2794908395679485, 228.1143887119114311 34.2787995621969728, 228.1256453028150872 34.2781077092036028, 228.1369030523943593 34.2774146679768847, 228.1481798443422804 34.2767193333419016, 228.1595524441489999 34.2760169520199653, 228.1709717099658405 34.2753105404703007, 228.1824155794200237 34.2746014536383754, 228.1938803829681888 34.2738899120501515, 228.2054189265202240 34.2731726236746113, 228.2170280980346888 34.2724497609647258, 228.2287243266709140 34.2717202778137491, 228.2405154508755913 34.2709836586137300, 228.2523281114419262 34.2702444679897056, 228.2641942766521197 34.2695006945981007, 228.2760966165281786 34.2687534105830665, 228.2880311232602253 34.2680028568663104, 228.3000080488953643 34.2672483775619554, 228.3120073191576012 34.2664912262207508, 228.3240136614714970 34.2657323608603051, 228.3360270491257609 34.2649717805465883, 228.3480846100778763 34.2642071289308490, 228.3601573792502393 34.2634402314495503, 228.3722738817793640 34.2626692689837498, 228.3844436938668991 34.2618936179263542, 228.3966618612460877 34.2611135777469542, 228.4089824127524366 34.2603256809244385, 228.4213463879382005 34.2595336691820549, 228.4337530236214775 34.2587375776010106, 228.4462104846748218 34.2579368682861514, 228.4587268132951010 34.2571310078012985, 228.4712928807436754 34.2563205653489931, 228.4839104809464061 34.2555054091390190, 228.4966228685898955 34.2546827271919625, 228.5094182245228467 34.2538532540846603, 228.5222741770853645 34.2530184134048241, 228.5351729277744539 34.2521793411568822, 228.5481108241424124 34.2513362606783147, 228.5610933368977840 34.2504888023745764, 228.5740744626261289 34.2496399538219762, 228.5870890608095181 34.2487874360186524, 228.6001377310472265 34.2479311983375254, 228.6132200400176089 34.2470712576139462, 228.6263499085635260 34.2462066877528244, 228.6395379494130680 34.2453367742424319, 228.6528307700917253 34.2444584250006088, 228.6663763631895847 34.2435618322477922, 228.6803617215675217 34.2426345404356880, 228.6952015541297101 34.2416489117582969, 228.7105525887952808 34.2406274236493147, 228.7265499347599302 34.2395608903248387, 228.7421439705677528 34.2385190301761213, 228.7570825715770866 34.2375188387752232, 228.7710598752944691 34.2365810241448401, 228.7833530683239758 34.2357543579112189, 228.7952800700345790 34.2349509231169549, 228.8072627602099942 34.2341424760952293, 228.8196514308075677 34.2333054217383648, 228.8331287441866664 34.2323936079623863, 228.8473922131053655 34.2314270980820723, 228.8618442087083338 34.2304460498874050, 228.8763439297838431 34.2294599388280361, 228.8909482642987996 34.2284648840239214, 228.9056482136413706 34.2274614588506196, 228.9203772895894815 34.2264541588745246, 228.9351647838737165 34.2254409729159406, 228.9499300140235505 34.2244273973785766, 228.9641311146556006 34.2234505682552808, 228.9782062980127080 34.2224806100983585, 228.9925852305867124 34.2214880258965621, 229.0081810669315416 34.2204098060711885, 229.0243240483072213 34.2192917031745054, 229.0404841060492060 34.2181701534276783, 229.0561546197282325 34.2170802520685911, 229.0718159793166819 34.2159888445761311, 229.0875983320990770 34.2148868824320118, 229.1034887026381455 34.2137752213084099, 229.1195460110981230 34.2126497040037805, 229.1358158381831913 34.2115070742239453, 229.1519329161114058 34.2103728456207250, 229.1680640638340094 34.2092353651527787, 229.1841528314203913 34.2080985981401113, 229.1997352209738494 34.2069952677110791, 229.2145400585285984 34.2059447196422752, 229.2300224802753235 34.2048443144084544, 229.2467979267121052 34.2036501663594166, 229.2636965490855232 34.2024448214142751, 229.2805688057605948 34.2012388686691864, 229.2975531550706592 34.2000224458390818, 229.3153572083785150 34.1987449443626517, 229.3330755455613428 34.1974708313770890, 229.3499864414433489 34.1962519263011018, 229.3671162393165446 34.1950147940828515, 229.3845622240634157 34.1937523320369579, 229.4014568277145827 34.1925270213204655, 229.4184179979392582 34.1912944083744819, 229.4358437586914761 34.1900256224414889, 229.4537366314035012 34.1887202762343563, 229.4717783255886729 34.1874013197685613, 229.4899255387092012 34.1860718423110796, 229.5081725981956993 34.1847322094676969, 229.5265398704356130 34.1833808833751647, 229.5450922295438545 34.1820130473676471, 229.5638787832386640 34.1806250031403636, 229.5833013117174062 34.1791870291224100, 229.6027619754956390 34.1777429732541052, 229.6217226068458217 34.1763326529017633, 229.6405847437962109 34.1749265205166282, 229.6596052490299087 34.1735055274516171, 229.6788397629834719 34.1720654519100648, 229.6983584809424030 34.1706009485036830, 229.7180957279129814 34.1691167912386220, 229.7380788625919479 34.1676108189410357, 229.7584117626150544 34.1660750990312749, 229.7790969055735673 34.1645092650801132, 229.7996369175649818 34.1629506916830863, 229.8203742931991655 34.1613735312545757, 229.8416825810410273 34.1597493413921924, 229.8624957634054908 34.1581588787102532, 229.8824174025273237 34.1566326128934890, 229.9024284095941084 34.1550960779241066, 229.9235693655622299 34.1534695745373043, 229.9452549994267088 34.1517974117562630, 229.9672683738575074 34.1500959778672595, 229.9895003848597241 34.1483735026549837, 230.0115335641334582 34.1466621289056462, 230.0333871041056000 34.1449604787229646, 230.0555507513969360 34.1432306180995653, 230.0779079316405955 34.1414814476944599, 230.1005422999793382 34.1397063294055911, 230.1238833343022350 34.1378715065958502, 230.1469833844259369 34.1360508855456928, 230.1701524618428607 34.1342202326812796, 230.1934678024026368 34.1323734191500918, 230.2165682856072806 34.1305388896250506, 230.2389046257025598 34.1287602696899981, 230.2627494180453027 34.1268575758665520, 230.2877550266475737 34.1248575757214354, 230.3121994425046353 34.1228969832372329, 230.3374538174263648 34.1208664280740450, 230.3631413115423925 34.1187956311933505, 230.3880206606859531 34.1167841715787290, 230.4129740676316658 34.1147614028110624, 230.4381720995549188 34.1127134837281716, 230.4639006137480521 34.1106170799943840, 230.4899617773432681 34.1084879305144355, 230.5160751629498748 34.1063486759816996, 230.5424933622251444 34.1041786334010055, 230.5692512087758814 34.1019747431288138, 230.5962633487828271 34.0997437899986693, 230.6233712571642513 34.0974986648374738, 230.6505324126182188 34.0952428145793291, 230.6778991776199348 34.0929635735833614, 230.7056768659263639 34.0906437347729181, 230.7338743164805805 34.0882822720815781, 230.7624290255265862 34.0858841099150212, 230.7912515728409630 34.0834564852273800, 230.8203176007084778 34.0810012492433714, 230.8496066249822150 34.0785199486820005, 230.8792222278794100 34.0760036573598484, 230.9092353385083811 34.0734461134513964, 230.9394837890443739 34.0708608100599832, 230.9699110763695842 34.0682523866543931, 231.0006928671137985 34.0656056694953833, 231.0318850271158908 34.0629155854277812, 231.0635571685805303 34.0601758151630207, 231.0955368339715221 34.0574008702548809, 231.1277395307414224 34.0545978215856735, 231.1598263149443255 34.0517959465778262, 231.1923731407472076 34.0489451185415319, 231.2256091619747167 34.0460249134342732, 231.2592693971341760 34.0430580048563343, 231.2932997454268502 34.0400487931218905, 231.3276773418007224 34.0369989774649824, 231.3623788651742643 34.0339103206458304, 231.3976872583261866 34.0307573788087794, 231.4333912447760611 34.0275584580134378, 231.4693555745259914 34.0243253060918320, 231.5059110723479137 34.0210279684916301, 231.5428878341136851 34.0176812113605962, 231.5803120487275919 34.0142822698571479, 231.6182257695979274 34.0108269013428526, 231.6563923557117732 34.0073361890491626, 231.6951328868908320 34.0037805361373344, 231.7344016752472839 34.0001635697603959, 231.7741163312641959 33.9964923489273474, 231.8144687460353452 33.9927486903022995, 231.8555242504632190 33.9889258812754989, 231.8967616379406707 33.9850717165754332, 231.9384874591021060 33.9811573547210131, 231.9810031242021182 33.9771540026181711, 232.0239997221509896 33.9730898997487358, 232.0678388326644495 33.9689303373579179, 232.1123373516068966 33.9646917583446637, 232.1571892770959664 33.9604025763729709, 232.2028902908268719 33.9560149645457585, 232.2491821769203000 33.9515527436837061, 232.2960411960920908 33.9470175080060130, 232.3439306822214974 33.9423637059180976, 232.3925149925117069 33.9376227335627902, 232.4421795018198509 33.9327560905117309, 232.4923819960596063 33.9278156111136937, 232.5436698046292179 33.9227466788576564, 232.5951687841104842 33.9176343957194177, 232.6475716305862989 33.9124096240862514, 232.7012278929114473 33.9070362581488851, 232.7556828036422303 33.9015582140379479, 232.8111272809534853 33.8959551462227964, 232.8675924453869754 33.8902225112893021, 232.9251556043381015 33.8843509817138369, 232.9836292773927369 33.8783581196600210, 233.0432332672728819 33.8722199924782501, 233.1036814245413780 33.8659644315621762, 233.1655576135860599 33.8595295608053988, 233.2282972754190951 33.8529720150750464, 233.2926253690727378 33.8462144249607135, 233.3579653177716295 33.8393149569302949, 233.4238324436093990 33.8323232702830481, 233.4921199960124909 33.8250368579970129, 233.5612785480354603 33.8176174606137465, 233.6323604436500148 33.8099502310293261, 233.7049545856000634 33.8020762210515144, 233.8182991443937340 33.7896946459519754, 233.8076868008509450 33.7447711159585353, 233.7998795209612979 33.7148904496539430, 233.7932833619625796 33.6848666706177085, 233.7861879661206217 33.6548975268433708, 233.7790138730816238 33.6249371304411468, 233.7721258778470030 33.5949457575010797, 233.7653244274834776 33.5649451763320457, 233.7589504394325957 33.5348983220681589, 233.7517922483768587 33.5049370176588681, 233.7451099029024988 33.4749242026266884, 233.7380079966970072 33.4449572275375928, 233.7308913046056773 33.4150038907599480, 233.7242842859603229 33.3850066680614148, 233.7177523607820149 33.3550016103827929, 233.7105361717234473 33.3250710557136642, 233.7038713780214607 33.2950810139364961, 233.6970686628110343 33.2651062319824931, 233.6905337587843690 33.2351027783426076, 233.6840504440658606 33.2050940975069437, 233.6777241041899913 33.1750688065101542, 233.6714174241416231 33.1450417813746228, 233.6651265167774056 33.1149842340850284, 233.6589877928076646 33.0848829897737033, 233.6524321128083557 33.0548271750781311, 233.6459016737647971 33.0247690229860495, 233.6397274742706998 32.9946728446447679, 233.6329292365037418 32.9646443837786194, 233.6264198618044645 32.9345851796794449, 233.6202087450176350 32.9044942684929751, 233.6139880509850002 32.8744048431199474, 233.6079852676745929 32.8442924253051416, 233.6024480632221128 32.8141580579442405, 233.5966311950082854 32.7840805086041911, 233.5901811264418768 32.7540715697776363, 233.5840609927987259 32.7240276624917570, 233.5780234845818484 32.6939754072355768, 233.5723051527258463 32.6638894276889644, 233.5666017736687934 32.6338024225347070, 233.5607542213080876 32.6037314698474248, 233.5546837865367706 32.5736849919792704, 233.5486024504767215 32.5436402503859412, 233.5424177864383353 32.5135952204185656, 233.5365716066706341 32.4835032169014184, 233.5315060000013148 32.4533282706241195, 233.5261496478028675 32.4231850922122362, 233.5203742087318233 32.3930873795337675, 233.5147182817867417 32.3629775114589648, 233.5094845865763773 32.3328231674413402, 233.5039894604646804 32.3026974294728859, 233.4978335601193464 32.2726429030728994, 233.4931590404903545 32.2424309059519061, 233.4878027399519453 32.2122923884581667, 233.4822943076409274 32.1821707947332527, 233.4769428294368367 32.1520331689142935, 233.4715484851256235 32.1219008275854492, 233.4659832528489858 32.0917874106425174, 233.4604242297955352 32.0616740464830130, 233.4547057473552059 32.0315783750575207, 233.4493448634544279 32.0014453816849027, 233.4439538848272377 31.9713163427404226, 233.4388438488122119 31.9411582035282215, 233.4333516270229723 31.9110653071387809, 233.4279989229896444 31.8809809553688552, 233.4229566389217894 31.8508644673349011, 233.4183811247408471 31.8206993020757771, 233.4138877625083808 31.7905263248524932, 233.4092102825951258 31.7603737819921363, 233.4050516565336579 31.7301671583804179, 233.4001074315976041 31.7000447187404717, 233.3957145714181536 31.6698647916849545, 233.3913100752606340 31.6396870518961428, 233.3864447836710667 31.6095336383505341, 233.3812875213067741 31.5793879739752867, 233.3764952549095710 31.5492046025283273, 233.3713681255396750 31.5190575397734705, 233.3665069082488230 31.4888832849676525, 233.3615529341064416 31.4587197536657825, 233.3563206749479377 31.4285865291404711, 233.3514797002687260 31.3984129293746150, 233.3465577545539134 31.3682488233591918, 233.3417228712048939 31.3380764928643032, 233.3370904020155194 31.3078918588118036, 233.3327447690398628 31.2776856492936552, 233.3284034056367489 31.2474800413596085, 233.3238447530019926 31.2172983698287148, 233.3202001869975390 31.1870215346730824, 233.3161949178957286 31.1567837770521372, 233.3117460131502128 31.1265937911358250, 233.3074302663908668 31.0963908864289600, 233.3031004201629059 31.0661905619832162, 233.2993877462967305 31.0359264958431389, 233.2953127271858875 31.0057054348373704, 233.2898951297387669 30.9756300525971362, 233.2854622844029677 30.9454523393039729, 233.2811087259339331 30.9152674168075556, 233.2766787724962967 30.8850916312890398, 233.2723182338050663 30.8549096936050056, 233.2680625874326665 30.8247179032272562, 233.2636594360020013 30.7945427207441114, 233.2591073855289494 30.7643842796982661, 233.2546430264907542 30.7342178080200377, 233.2506548072034320 30.7039852299984197, 233.2467326448435188 30.6737304212484112, 233.2427735883874220 30.6434806792655507, 233.2385419916588489 30.6132606394362270, 233.2344263707328196 30.5830296839476610, 233.2299724549353641 30.5528352858511347, 233.2257801218785005 30.5226147736255093, 233.2217008350382912 30.4923836900961192, 233.2176536180877520 30.4621505031956623, 233.2137701088354333 30.4319014927804155, 233.2097164924082904 30.4016889943496160, 233.2057273903072883 30.3714876142592480, 233.2018315927718390 30.3412778048335809, 233.1982994815887196 30.3110314135535397, 233.1949660441975709 30.2807656745661049, 233.1909995459751883 30.2505672082381274, 233.1869329124752994 30.2203804896820323, 233.1830432861650308 30.1901766843827808, 233.1794294370546368 30.1599455462843871, 233.1757256557578444 30.1297251351229853, 233.1722016871373455 30.0994998764674975, 233.1687265873427179 30.0692827643412635, 233.1657971255530981 30.0390104337142958, 233.1620197154927894 30.0088276220750814, 233.1588110553424542 29.9785872277253844, 233.1558657450565590 29.9483210009760406, 233.1526520127341655 29.9180841252305392, 233.1489461529616278 29.8878997697228570, 233.1453943524509782 29.8577009226519010, 233.1419015803729451 29.8274974560358004, 233.1385470570977816 29.7972455511376992, 233.1353455350160289 29.7669455615571614, 233.1321205569348365 29.7366494892352904, 233.1286857502857117 29.7063766210683760, 233.1248502692661759 29.6761466884867851, 233.1219322346083231 29.6458233627870875, 233.1187887010911481 29.6155248850340520, 233.1158036470708339 29.5852115613503379, 233.1128189974144220 29.5548997434543850, 233.1096148239092258 29.5246121600882780, 233.1059421915535381 29.4943963292008320, 233.1029253621420025 29.4641350065570151, 233.1002381417339677 29.4338412717182401, 233.0969753053758780 29.4036085512377774, 233.0938295190486258 29.3733653616724482, 233.0913472163338440 29.3430553834682506, 233.0892058098756081 29.3127119349647067, 233.0863428536407014 29.2824445349173530, 233.0832116703506927 29.2522064239976025, 233.0797675612166131 29.2220021876194558, 233.0766708226083779 29.1917583918426793, 233.0740702319595812 29.1614600580882026, 233.0714565710325985 29.1311647753841925, 233.0690128689927576 29.1008537235407303, 233.0668902691410551 29.0705113857663484, 233.0645048567074014 29.0401978200141784, 233.0622308671956944 29.0098745532563846, 233.0598776027511860 28.9795611971617610, 233.0578674387686249 28.9492143656048526, 233.0557478221899146 28.9188805699773148, 233.0535026840429964 28.8885669116981312, 233.0508429036479754 28.8583027762630273, 233.0484008302731525 28.8280180911364923, 233.0460454447779455 28.7977263211135330, 233.0438808462283475 28.7674168095447094, 233.0413729393316942 28.7371443319351094, 233.0390306784746883 28.7068567067667786, 233.0369262675669688 28.6765465604912748, 233.0347470633640796 28.6462459426612384, 233.0329268350070890 28.6159104396763375, 233.0304011304804703 28.5856435995693232, 233.0285767800003214 28.5553016798027670, 233.0267613739262345 28.5249607573214767, 233.0251239162210481 28.4946035505042552, 233.0235861249755089 28.4642380888206468, 233.0216106033979031 28.4339193332039670, 233.0189545611958124 28.4036720750919329, 233.0154885602246111 28.3735094844736260, 233.0142983651916779 28.3431162820924243, 233.0278250723105486 28.3112211640421627, 233.0452282676261007 28.2789483187394843, 233.0538325274330305 28.2475942808537539, 233.0539975568593434 28.2171064726353187, 233.0513725666158678 28.1869063911921387, 233.0495940247798217 28.1566216920427621, 233.0476156283756097 28.1263594901669798, 233.0441012164608594 28.0962563986381291, 233.0341267619562302 28.0668153191364418, 233.0153669885793590 28.0382716562388339, 233.0004310857395353 28.0093374012700345, 232.9972907785160885 27.9791790793518480, 232.9993492557859156 27.9484712223743799, 232.9984005080535212 27.9180717344067304, 232.9974307125874589 27.8876765098117794, 232.9972130492355689 27.8572068668355115, 232.9974480176590248 27.8266933234035996, 232.9991589372480121 27.7960317666086958, 232.9989280134366254 27.7655700234404357, 232.9984242466573505 27.7351382270215581, 232.9981795284499242 27.7046822703985498, 232.9979878384312144 27.6742274580733785, 232.9973841036592148 27.6438208719076783, 232.9969627048587313 27.6133979690396210, 232.9956424441161857 27.5830686696773846, 232.9942467721409969 27.5527492409840562, 232.9928294278021781 27.5224342236403245, 232.9910051526982215 27.4921627558298560, 232.9892752251977015 27.4618839132474726, 232.9876407499768050 27.4315975974893540, 232.9860500535197616 27.4013090709302176, 232.9845431092176398 27.3710008489845045, 232.9832144523877844 27.3406640377800798, 232.9813211962254798 27.3103867100860782, 232.9796046601094304 27.2800936680591022, 232.9778668740711680 27.2498050024511933, 232.9760812623313200 27.2195234107127924, 232.9744936225061167 27.1892239957127586, 232.9725389188140809 27.1589640136351065, 232.9710993706493696 27.1286541056601571, 232.9695310658383107 27.0983595097609289, 232.9678740179707574 27.0681026007854726, 232.9664105876078111 27.0378534557978263, 232.9648174106994247 27.0076198078681955, 232.9633173340908456 26.9773791166841228, 232.9625444737449413 26.9470672981449333, 232.9609409653207877 26.9168418629111947, 232.9596090239708417 26.8865913871725191, 232.9583747341667959 26.8563334706327588, 232.9570418888685026 26.8260879392246423, 232.9556783045036639 26.7958479490434627, 232.9541208556390188 26.7656115503784378, 232.9529072543590758 26.7353254479347022, 232.9513372321344207 26.7050777308560647, 232.9496721067669398 26.6748420272777231, 232.9482697863891190 26.6445822619977086, 232.9469308519579158 26.6143185587959685, 232.9456308588468971 26.5840533948443856, 232.9445891873004371 26.5537646856240990, 232.9435705001869508 26.5234761549909130, 232.9424930683779849 26.4931960434053231, 232.9411883948879733 26.4629460272636905, 232.9404661357344537 26.4326443639049629, 232.9397077070689477 26.4023488674102964, 232.9389590229434361 26.3720549233813237, 232.9380771814213631 26.3417769121558294, 232.9371118552030850 26.3115098363276338, 232.9363055938855496 26.2812293227508285, 232.9349899869084197 26.2510025505052305, 232.9335253420107392 26.2207932922391542, 232.9325013463295591 26.1905423329871923, 232.9312666333587458 26.1603104014087862, 232.9304842316648205 26.1300312111542468, 232.9301915140906090 26.0997055104643607, 232.9294881720221895 26.0694236562733899, 232.9290727464842519 26.0391155706255368, 232.9284303148743334 26.0088329122365636, 232.9279035225714551 25.9785413248947528, 232.9273612165381451 25.9482539712151024, 232.9268538348704851 25.9179658022400368, 232.9262752017791911 25.8876874678260762, 232.9258886604945928 25.8574103205871566, 232.9254503184828593 25.8271578908632939, 232.9251078810469551 25.7968986263993436, 232.9246578931334284 25.7666529016514900, 232.9240220891315971 25.7364285483357058, 232.9236035389937456 25.7061852433890081, 232.9230685583847844 25.6759563790559397, 232.9227337275446814 25.6457103098674501, 232.9226746289442360 25.6154395052660426, 232.9151284100261421 25.5859193757088335, 232.8937666407001927 25.5577604985955915, 232.8940638253671409 25.5274256432220170, 232.8871864393980502 25.4978083492145302, 232.8887549686264435 25.4673523878265264, 232.8922447979715855 25.4367079619002219, 232.8868549804973611 25.4069505089587331, 232.8862070942742832 25.3767236847006394, 232.8896433828423085 25.3460933179880676, 232.8904085763713852 25.3157316468416127, 232.8749355208171608 25.2869872855028568, 232.8752451626990876 25.2566951708590217, 232.8833426365382877 25.2256500909277364, 232.8835253169675639 25.1953944685349569, 232.8791674519990806 25.1655927164969029, 232.8897864847603500 25.1343065994128700, 232.8853793267643084 25.1045158112194073, 232.8872412249220076 25.0741054814230750, 232.8902504011679184 25.0435843557807090, 232.8862819506101118 25.0137587010341953, 232.8849165370428977 24.9836776256239297, 232.8615444344878824 24.9557405574880384, 232.8678957259777746 24.9248252133515251, 232.8743003817854174 24.8939074623787384, 232.8845451259491313 24.8626121461173852, 232.8855114924644738 24.8322389784330113, 232.8777786941511465 24.8027302998354422, 232.8784494296954222 24.7723922673367660, 232.8786766283392922 24.7421011267217601, 232.8815821187694723 24.7115479151651094, 232.8784798198719841 24.6815922416011517, 232.8815210227576245 24.6510507831911276, 232.8869507732288184 24.6202941882075912, 232.8897516432224961 24.5898008394087846, 232.8918981619777924 24.5593753742191865, 232.8953447469445734 24.5288244473813180, 232.9021256320803843 24.4979467949218126, 232.9055803919187895 24.4674014152638897, 232.9256796375334488 24.4352113534955322, 232.9278143679030677 24.4048031512248613, 232.9273308331008536 24.3746574338355266, 232.9233851756903277 24.3448714449377732, 232.9184915904162665 24.3151952702327385, 232.9128735282336322 24.2855934652230268, 232.9070168456449323 24.2560179020738893, 232.8961245152644040 24.2269419338317213, 232.9056956378175869 24.1958493514343687, 232.9163992199943323 24.1646481368294097, 232.9148753746634668 24.1346574496068342, 232.9260392072289392 24.1034175401604038, 232.9206813331250885 24.0738120738219301, 232.9204495719246779 24.0437090840601435, 232.9242943936257006 24.0132123142740319, 232.9256437469389311 23.9829650937303498, 232.9266377198844395 23.9527562659602467, 232.9335016545540498 23.9219720545757646, 232.9350094750091387 23.8917194174715171, 232.9318311547083624 23.8619319938418855, 232.9368722188254139 23.8313379253568662, 232.9450679384852094 23.8004364541792768, 232.9487612034705819 23.7699821916536962, 232.9457539896300773 23.7401711442871743, 232.9427211902646491 23.7103463854447085, 232.9402080395296366 23.6804735787408411, 232.9433835895079312 23.6500442501760695, 232.9429844398777050 23.6199700525028895, 232.9448047519951217 23.5896808976233565, 232.9476776159105498 23.5592916674110846, 232.9482010009696182 23.5291369225008040, 232.9512697052309136 23.4987353647413322, 232.9482075708974946 23.4689398429934144, 232.9524304167965170 23.4384270364512517, 232.9546730815462467 23.4081077649794302, 232.9582883791230756 23.3776571361768752, 232.9647493343327085 23.3469304506696140, 232.9703738876218324 23.3162894619193146, 232.9749310816914658 23.2857568941960480, 232.9745359583259585 23.2557144439031767, 232.9767231065955286 23.2254218016588787, 232.9747120126448010 23.1955449259003750, 232.9822413991412304 23.1647348154436621, 232.9804333911563390 23.1348442844337647, 232.9799632300583312 23.1048251183938760, 232.9861015982691583 23.0741610277334033, 232.9875906069682685 23.0439567790242954, 232.9885163913017152 23.0138113510139206, 232.9880927477933881 22.9838018052555668, 232.9920786514291819 22.9533634402218354, 232.9956900446725570 22.9229654566407355, 232.9980286667984331 22.8926959144764481, 232.9994463253835590 22.8625202869970394, 233.0007273526802010 22.8323817679763863, 233.0026223770331910 22.8022057943616439, 233.0043541573523385 22.7720495281594388, 233.0056855082923448 22.7419361869260008, 233.0075168387004112 22.7117776144770147, 233.0086972638558507 22.6816864801467410, 233.0110141288599834 22.6514878824316952, 233.0150980294305043 22.6211202181119297, 233.0183630375206860 22.5908364990390140, 233.0205235275349764 22.5606646287341768, 233.0226990887721854 22.5304748351912814, 233.0250312225587948 22.5002543317498116, 233.0273417263018416 22.4700397097962856, 233.0294322532687943 22.4398503560864988, 233.0316537239692423 22.4096519871084432, 233.0341646706244774 22.3794291321900545, 233.0365342745103874 22.3492238901019569, 233.0390090293491596 22.3190121957783028, 233.0410423260715618 22.2888474232953939, 233.0431049502272174 22.2586836086433415, 233.0454588237505789 22.2284945392465723, 233.0478015505857456 22.1983097811950536, 233.0502410034338254 22.1681194493875857, 233.0528960636553961 22.1379119637526749, 233.0557407390418518 22.1076898815501366, 233.0583526793505200 22.0774943965698363, 233.0611965967989079 22.0472802077131611, 233.0637667921969296 22.0170966233224057, 233.0661707315231581 21.9869331637061833, 233.0688355153386908 21.9567482212916190, 233.0712133978703946 21.9266163989694398, 233.0735932640259307 21.8965084711711100, 233.0760567737850124 21.8663964170824769, 233.0786160066152775 21.8362790739403536, 233.0813521304598623 21.8061485619774196, 233.0841934458621552 21.7760118754163514, 233.0868186396090209 21.7459002818275557, 233.0896572713970727 21.7157720085455743, 233.0925606004185511 21.6856415365210218, 233.0953944801916293 21.6555219188819841, 233.0982658466593875 21.6253757163975280, 233.1010684294436999 21.5952146481066016, 233.1039565017079269 21.5650493243033381, 233.1070084940014340 21.5348721396217933, 233.1101013319822357 21.5046950640766852, 233.1128703123239063 21.4745535126135110, 233.1158241927793142 21.4443980968924066, 233.1188318355480362 21.4142415633379279, 233.1218563891699773 21.3840874973898849, 233.1246794784815961 21.3539570958571900, 233.1274225832100910 21.3238601081567225, 233.1306370617675157 21.2937419770209679, 233.1338110027921857 21.2636319988396920, 233.1368714755917608 21.2335372463016725, 233.1401888171233736 21.2034218386528366, 233.1433772704574210 21.1733231702659666, 233.1465315268246457 21.1432320717217443, 233.1496154959708065 21.1131520454980688, 233.1523256639130182 21.0831124744103242, 233.1550432762235232 21.0530764456413166, 233.1579828490156387 21.0230058063689711, 233.1607722022461644 20.9929374509098636, 233.1636624179120645 20.9628635553827110, 233.1666398144984100 20.9327854559908850, 233.1696517887513096 20.9027082545512997, 233.1726003363481823 20.8726414316977440, 233.1758702060247401 20.8425478179737880, 233.1788078854982871 20.8124905746892104, 233.1817470919710615 20.7824374566928114, 233.1847240762937474 20.7523849750790745, 233.1882571693559498 20.7222788477096316, 233.1922497392443177 20.6921286819550296, 233.1963717972563472 20.6619703874637324, 233.1999109852516483 20.6318727136307807, 233.2035406236984159 20.6017706852433591, 233.2070288686839490 20.5716866762562312, 233.2105921938348558 20.5415998141373528, 233.2140636676945746 20.5115262079963792, 233.2178119025755336 20.4814303280644161, 233.2217592401371462 20.4513196857803798, 233.2251909010133204 20.4212673944372689, 233.2282694103726897 20.3912575382923755, 233.2318419183720835 20.3612045155384997, 233.2355239631258144 20.3311453846168213, 233.2391586892739781 20.3010952641717957, 233.2428990778244042 20.2710394343307705, 233.2464567058539444 20.2410056661055044, 233.2499761033736831 20.2109800536504096, 233.2536732782234878 20.1809418255188859, 233.2573748161835283 20.1509076803910574, 233.2610258437821074 20.1208946526849886, 233.2648839717209057 20.0908774184780903, 233.2690707989325460 20.0608332120380233, 233.2729399482162762 20.0308241593812788, 233.2766399932848742 20.0008359800302244, 233.2812975167611285 19.9707604952090776, 233.2864835103510757 19.9406389605955141, 233.2910589910247836 19.9105807427105042, 233.2951517126599299 19.8805735518949831, 233.2994281961829017 19.8505534224128048, 233.3035672940802101 19.8205511748355683, 233.3079874497330195 19.7905266855421935, 233.3129269619056743 19.7604571405118357, 233.3212816261563489 19.7300649786930506, 233.3230339211604019 19.7003105136032453, 233.3250709696296212 19.6705333692991715, 233.3296297889724826 19.6405193532041871, 233.3340604186102496 19.6105224014847792, 233.3383183317661747 19.5805467749846187, 233.3428179008550671 19.5505528169449825, 233.3472901992914785 19.5205884333979363, 233.3519547732985586 19.4906315128301806, 233.3565130546640205 19.4606896821475424, 233.3611875777690443 19.4307416676413673, 233.3661894041850076 19.4007673213927738, 233.3703364724232756 19.3708796064123803, 233.3750997858020355 19.3409379714967393, 233.3796821892690616 19.3110185897310593, 233.3838727405633335 19.2811415855535060, 233.3885341450790349 19.2512246218782614, 233.3933864584715820 19.2212534983463215, 233.3986811270121962 19.1912063080396358, 233.4036949065424835 19.1611907724642343, 233.4090010489056510 19.1311522333807353, 233.4132186011130443 19.1012223437648210, 233.4123898128762278 19.0717780874600393, 233.4234938189524655 19.0412018332757356, 233.4281136089198299 19.0112482689356206, 233.4325499945081219 18.9813170712961394, 233.4385722857594772 18.9512397884658697, 233.4443472690545605 18.9211910404965344, 233.4496096003589969 18.8911960802610075, 233.4547716287821686 18.8612156352759506, 233.4583507148462047 18.8313907512887653, 233.4655539294550408 18.8012260955363750, 233.4711278179178464 18.7712214498863723, 233.4767412813863814 18.7412180639201722, 233.4825004791105982 18.7112058596519368, 233.4883578878495314 18.6811893699630893, 233.4930940640239214 18.6512844874852739, 233.4992980389991146 18.6212451930891127, 233.5048315557592673 18.5912746804501623, 233.5077083130712765 18.5615615247693846, 233.5090647558613739 18.5319976053586331, 233.5185189875365666 18.5016701736589049, 233.5255892491283305 18.4715741712361918, 233.5300607517884828 18.4417298954107771, 233.5355540635434579 18.4117937924565673, 233.5416644760110216 18.3818043138120757, 233.5436055661265016 18.3522152471724311, 233.5514883551133494 18.3220390662315573, 233.5588538186819392 18.2918895888876669, 233.5647531551124416 18.2618841625846500, 233.5705679159131591 18.2318918457248778, 233.5766138332255082 18.2018827384489974, 233.5826686375446570 18.1718779111487798, 233.5888785940030914 18.1418635244420230, 233.5951383724894868 18.1118495698953126, 233.6014674717557966 18.0818342120025726, 233.6076764098261833 18.0518354029742305, 233.6140209227432081 18.0218522835686414, 233.6204423279392302 17.9918892524204779, 233.6265487125820925 17.9619613307872079, 233.6313515420965530 17.9321620036759946, 233.6386754122240745 17.9021295475782303, 233.6451980362392078 17.8721782134589731, 233.6513777078440057 17.8422646488452799, 233.6535623905758143 17.8127339294964280, 233.6609506869070287 17.7827168172749950, 233.6699594121416794 17.7525520609224401, 233.6710216308924828 17.7231431656690397, 233.6718987098583682 17.6937567665229594, 233.6886100268676500 17.6628813678396774, 233.6960663231332944 17.6328849765218045, 233.7026278416137188 17.6029784898588098, 233.7090592956413104 17.5730897220186435, 233.7159774814714126 17.5431605027914799, 233.7217275110074581 17.5133469216565452, 233.7187734900754208 17.4843590861112901, 233.7270853487591751 17.4543148474000560, 233.7331808851990047 17.4244650559326750, 233.7435127698205974 17.3942028951707535, 233.7536136128401267 17.3639679699476659, 233.7604356218571127 17.3340473253071927, 233.7671770105191911 17.3041397119190812, 233.7740217619244447 17.2742278149562658, 233.7808503091249293 17.2443229050635445, 233.7874669750843850 17.2144434060740643, 233.7940569944907736 17.1845718878611855, 233.8008596205570200 17.1546858578559593, 233.8077378291946218 17.1248364577951477, 233.8147908325216520 17.0950124866744311, 233.8216472066112317 17.0652127325469856, 233.8287550493209892 17.0353950863091299, 233.8358236306713422 17.0055868895775504, 233.8429318881181871 16.9757807353939576, 233.8498250518302655 16.9460005561754876, 233.8567982141668438 16.9162186518052877, 233.8644027756993751 16.8863833032343358, 233.8717789035609087 16.8565752238410482, 233.8787743160380899 16.8267903345665388, 233.8864271817588190 16.7969322128414085, 233.8943020025787405 16.7670590849023320, 233.9020234300422487 16.7372061476441409, 233.9097388867146208 16.7073595931862542, 233.9174310494171891 16.6775210529367044, 233.9253368303507159 16.6476683527251197, 233.9331359108360573 16.6178315077103491, 233.9401620373827768 16.5880728789295055, 233.9480199089602763 16.5582422695100639, 233.9556240345705191 16.5284143707629028, 233.9629611957227269 16.4985917371710613, 233.9680858448260494 16.4689817308887712, 233.9697189397047907 16.4397036867894251, 233.9810825592319361 16.4095219192914819, 233.9908561421488571 16.3794945960678326, 233.9882558499625418 16.3506288802721613, 234.0070396856991692 16.3197717513327589, 234.0069713601554895 16.2906809733869693, 234.0202313690597578 16.2603515812108093, 234.0396206155035372 16.2294769328209796, 234.0450716397836004 16.1999297991700111, 234.0561919774314674 16.1698594103974891, 234.0658256086437348 16.1399339059389888, 234.0741862235724682 16.1101332895771421, 234.0828109354990261 16.0803141029572600, 234.0913423006932987 16.0505097118745965, 234.0998453017218424 16.0207140639679864, 234.1085331394955062 15.9909072931318139, 234.1171059040658804 15.9611173753279090, 234.1257060293999359 15.9313287300730444, 234.1339610716019308 15.9015761555569703, 234.1421311332078687 15.8718375959628091, 234.1504002200311163 15.8420959238847718, 234.1587546091515435 15.8123524374057407, 234.1674495385412911 15.7825834029764227, 234.1763947307113369 15.7527972553506963, 234.1849920610645768 15.7230496510930529, 234.1933783956116031 15.6933278490381323, 234.2016682329614810 15.6636212040259846, 234.2106661103412080 15.6338573919960844, 234.2195850306243585 15.6041094924468524, 234.2284696631510883 15.5743710697067037, 234.2372546661415527 15.5446481978965938, 234.2462970040240577 15.5149077482776239, 234.2553563459844668 15.4851720526347219, 234.2644515617519687 15.4554393746423013, 234.2736445752768759 15.4257039865954688, 234.2828900292420826 15.3959701114841270, 234.2920854378215267 15.3662472679597375, 234.3013275326234464 15.3365240161494683, 234.3104684932162343 15.3068141676424592, 234.3196567191314728 15.2771063206136155, 234.3288051987633480 15.2474085455542010, 234.3378564295157105 15.2177261764300678, 234.3470450336738793 15.1880375022826879, 234.3562524205285911 15.1583535187513530, 234.3654777347240952 15.1286743194410604, 234.3747378390859524 15.0989983563807133, 234.3840812977530277 15.0693211573935493, 234.3931289748404652 15.0396512748819262, 234.4024907295219009 15.0099336757912152, 234.4122604236426071 14.9801847783205897, 234.4219977298243123 14.9504452811145629, 234.4316158217008876 14.9207232127847984, 234.4409823342089965 14.8910307929301986, 234.4498350294495594 14.8613922149404161, 234.4587414398604324 14.8317550982339306, 234.4679675150275102 14.8020949299082716, 234.4770902769993768 14.7724507459251111, 234.4864736845448761 14.7428161288563455, 234.4957933016077902 14.7132196609919141, 234.5055218342258456 14.6835921628358417, 234.5149128961783731 14.6540024088048977, 234.5240841564354923 14.6244395507798366, 234.5338855767652717 14.5948253660254430, 234.5441277234739630 14.5651773498399315, 234.5546148327972560 14.5355135560838367, 234.5650071688638718 14.5058652498629623, 234.5754239657616438 14.4762214795646678, 234.5860298985859345 14.4465631055522845, 234.5967350016157980 14.4168986452192929, 234.6069521171130816 14.3872858481746757, 234.6171532263267352 14.3576813564971797, 234.6275466849351119 14.3280660631511427, 234.6379311558054326 14.2984584661645968, 234.6483279332099698 14.2688566257719316, 234.6586953216983602 14.2392643796648937, 234.6688702853703603 14.2096966782432101, 234.6792465123588727 14.1801174491704600, 234.6895268522844731 14.1505511410281279, 234.6998289458051090 14.1209871013773025, 234.7101500403533691 14.0914282332427963, 234.7207265998918047 14.0618529130783187, 234.7321276655577265 14.0322091288899919, 234.7421715997281808 14.0026964531666795, 234.7518848048210032 13.9732209510139391, 234.7623775583252552 13.9436811557223272, 234.7730116693621483 13.9141354453401398, 234.7836780942089945 13.8845938048401454, 234.7943396394510387 13.8550596464772120, 234.8051586497037135 13.8255181702998513, 234.8160814505063740 13.7959742977803899, 234.8270783541463231 13.7664307566487150, 234.8381481290801673 13.7368876813875094, 234.8493417356832538 13.7073404463484767, 234.8606864126222717 13.6777865962651966, 234.8720570731951227 13.6482375499376918, 234.8830833198969401 13.6187270374915155, 234.8942578962761161 13.5892102040072000, 234.9053801470764142 13.5596778329073899, 234.9167589099882889 13.5301032212135421, 234.9279630763072362 13.5005515903067401, 234.9394192269006965 13.4709841687102436, 234.9508887096513661 13.4414226751736940, 234.9626309718141783 13.4118435576556774, 234.9742477502246629 13.3822830148562506, 234.9858310021840282 13.3527327039232198, 234.9970791630884435 13.3232199974438803, 235.0084942267340864 13.2936993451161918, 235.0186419329412502 13.2643038495101493, 235.0288272444620077 13.2349149253326068, 235.0401198046571380 13.2054328064297675, 235.0532620150219429 13.1757903603399633, 235.0624271216925081 13.1465153771828209, 235.0713600073557075 13.1172684944642093, 235.0793940345812700 13.0881099970756303, 235.0890500823631157 13.0588118578658747, 235.1001302413494045 13.0293921654755245, 235.1114135830976579 12.9999613924081761, 235.1209243704139737 12.9707237608108290, 235.1309020905796672 12.9414756652994853, 235.1414756824528354 12.9121812020434952, 235.1521051686026453 12.8828891505364300, 235.1634486053033584 12.8535402166422994, 235.1748378342097396 12.8241946970120964, 235.1866932403923727 12.7948147510022956, 235.1962591092761556 12.7656485148328525, 235.2079865871087918 12.7362952191002208, 235.2197326753089612 12.7069478742196740, 235.2313225721933634 12.6776155786555993, 235.2423722902041163 12.6483331655838960, 235.2530634953859305 12.6190905341801578, 235.2639518191064383 12.5898377703569100, 235.2744025920220849 12.5606318602069944, 235.2867725908210446 12.5312613936619748, 235.2991023667242985 12.5019022720519857, 235.3116716239582331 12.4725294412281773, 235.3219926194716152 12.4433657660418966, 235.3334198870870750 12.4141106634952525, 235.3448295696518926 12.3848381642486984, 235.3590631821656700 12.3552954060809768, 235.3671572194415944 12.3263093689396594, 235.3791241627797319 12.2969845358657945, 235.3921032502748858 12.2675769256364440, 235.4040318795581186 12.2382708373989573, 235.4133898130075124 12.2092018442350998, 235.4233087213997351 12.1800902646282907, 235.4339080986466115 12.1509255318467915, 235.4452235719082864 12.1217045745757837, 235.4567443237030773 12.0924703558084179, 235.4687492492635386 12.0631982532119988, 235.4810288740251849 12.0339094862614715, 235.4933593769876836 12.0046240089340035, 235.5055131848779126 11.9753620784343049, 235.5183936068819719 11.9460434003433491, 235.5313914414787746 11.9167221954071394, 235.5445277552505274 11.8873966214008568, 235.5579758501142749 11.8580513222656219, 235.5708596309736720 11.8287640873522850, 235.5855568216224754 11.7993272976514429, 235.5997530467545005 11.7699461619532091, 235.6118792700054314 11.7407565433979375, 235.6222863801276901 11.7117271088094661, 235.6370065832145997 11.6823236091692451, 235.6501351706685341 11.6530691111257187, 235.6620789000052980 11.6239274595492343, 235.6746660025543463 11.5947368831844280, 235.6884231604871331 11.5654509340061882, 235.7004295446835442 11.5363277617227080, 235.7116587817768050 11.5072743978447640, 235.7235065836390788 11.4781679472845699, 235.7365096551736485 11.4489676032299617, 235.7509681344467083 11.4196470655488547, 235.7663406604226850 11.3902542184105808, 235.7777363715495085 11.3612199442349784, 235.7886739886716043 11.3322339874586131, 235.8008113265921963 11.3031504556407096, 235.8129270659356678 11.2740769145603643, 235.8254455463878685 11.2449760862190988, 235.8379734895646891 11.2159103138154315, 235.8515159916051402 11.1867900343133702, 235.8657944078840103 11.1576136472980831, 235.8797318095176365 11.1284757052386034, 235.8937716656943167 11.0993373101898118, 235.9083287919161478 11.0701621526026965, 235.9230551243026355 11.0409807942066465, 235.9376740007601825 11.0118174850483133, 235.9515272763501912 10.9827297851745165, 235.9638445602442971 10.9537849358193409, 235.9770623676844821 10.9247485593680569, 235.9907218609045003 10.8956618896021116, 236.0047319410605553 10.8665530900843592, 236.0183309333073396 10.8374886511592958, 236.0323861690089302 10.8083929297650254, 236.0537151650615897 10.7647439316756586, 235.8067955133633973 10.7864349998059303, 235.6404746257572924 10.8009251269396263, 235.4886934161605154 10.8140812538595235, 235.3440743681663321 10.8265506526567350, 235.2013541677908677 10.8387871304147918, 235.0605785760583331 10.8507895529034926, 234.9266644391624368 10.8621511165711979, 234.7983134326703407 10.8729887160495498, 234.6742684848909448 10.8834132357353326, 234.5539738435579977 10.8934756929011449, 234.4326844057674464 10.9035680020322605, 234.3062264801270658 10.9140277809828401, 234.1842183967351616 10.9240715931438910, 234.0687460570606220 10.9335373293233324, 233.9561439769082654 10.9427259418076375, 233.8474210956636057 10.9515604135457068, 233.7435151522108470 10.9599707574453191, 233.6385624025299990 10.9684248104218582, 233.5358140067679642 10.9766660933163962, 233.4407131631540437 10.9842712723620792, 233.3422237141487017 10.9921074822316367, 233.2513957968668024 10.9993144684267641, 233.1514470230827101 11.0071956760925467, 233.0568672341269121 11.0146280042264575, 232.9714593141212902 11.0213255319210663, 232.8803341230215551 11.0284323244705966, 232.7943082344638981 11.0351214682241956, 232.7094524258490083 11.0416948896741296, 232.6269891539112962 11.0480614832390529, 232.5469229652692320 11.0542229776525041, 232.4651981313407134 11.0604848216034473, 232.3872682244131909 11.0664391550737431, 232.3089820002441002 11.0723973916263372, 232.2344266808455302 11.0780568264050938, 232.1612777882618559 11.0835918116480201, 232.0879579900154397 11.0891193380045809, 232.0165771813923357 11.0944847829428479, 231.9444953164284300 11.0998822668852739, 231.8732154220789994 11.1052019606719448, 231.8057772059855211 11.1102241836924787, 231.7386284223740347 11.1152083219001412, 231.6726527935756792 11.1200909547655851, 231.6064561948269045 11.1249729599094174, 231.5413069011251253 11.1297634611590315, 231.4780838222096122 11.1344005204152676, 231.4150219500268406 11.1390109034406830, 231.3534789037269661 11.1434985250841070, 231.2922763752998208 11.1479476253113834, 231.2321986804822416 11.1523031971472300, 231.1727759778447648 11.1565989554036538, 231.1144830584694887 11.1608020872666742, 231.0567419751295120 11.1649536385455743, 231.0002949603148465 11.1690023089748021, 230.9442330256014770 11.1730119569495638, 230.8887529573815129 11.1769692032590324, 230.8340953656575323 11.1808578017412277, 230.7801047938868351 11.1846889342885731, 230.7267933250123519 11.1884621644846547, 230.6741394301110120 11.1921793597432231, 230.6222024977055014 11.1958368476763042, 230.5710284673378965 11.1994319110294054, 230.5203688901653436 11.2029818304778850, 230.4702850162558434 11.2064827482388765, 230.4211332149644136 11.2099109379701982, 230.3722347960824379 11.2133125719045719, 230.3238995148852553 11.2166669987619017, 230.2759727552675599 11.2199848672675309, 230.2288337046649644 11.2232410798167255, 230.1821784107627877 11.2264562859272328, 230.1360978921009064 11.2296246903372410, 230.0904502464950951 11.2327559868123661, 230.0451126661348269 11.2358585089428757, 230.0005121694876493 11.2389042679814661, 229.9563201538447288 11.2419152341291504, 229.9126038169218020 11.2448872011930661, 229.8693914420437352 11.2478185506150439, 229.8266141936540805 11.2507140177014868, 229.7844926752383685 11.2535594487366986, 229.7426279584774136 11.2563810618931104, 229.7011060076232241 11.2591734075795618, 229.6601354388789673 11.2619231614295536, 229.6197463420455733 11.2646286372288937, 229.5797488137805829 11.2673023162613966, 229.5399124326949050 11.2699591633166492, 229.5003744155744698 11.2725904639474663, 229.4613780020166018 11.2751808122798849, 229.4229479289674032 11.2777288707644558, 229.3846678777064767 11.2802613604292219, 229.3465203971857989 11.2827794526242791, 229.3092627460602273 11.2852352682303039, 229.2721541795532971 11.2876759727370040, 229.2355028971706190 11.2900822055440635, 229.1990236077036229 11.2924720972138957, 229.1627789235940611 11.2948417900965428, 229.1268004674435872 11.2971894009815745, 229.0910977852282429 11.2995144425355125, 229.0558429789213051 11.3018062999907833, 229.0210984390760132 11.3040612741932698, 228.9866394069154012 11.3062935182439883, 228.9523786369067579 11.3085085479184464, 228.9184628476487262 11.3106973739432899, 228.8847576778044015 11.3128684166155438, 228.8514037966511125 11.3150131009990815, 228.8184344402544639 11.3171295215342020, 228.7856962146690876 11.3192272250004820, 228.7530968391216106 11.3213119416556740, 228.7207523182553359 11.3233766438828898, 228.6886580791903896 11.3254217054488961, 228.6568808000483273 11.3274431670438886, 228.6255699416132074 11.3294320811176288, 228.5943557727729285 11.3314109976851860, 228.5633199203972481 11.3333750202213430, 228.5325366678424643 11.3353197347103816, 228.5019329259182825 11.3372496289215654, 228.4715394680745533 11.3391629188434351, 228.4413945509315909 11.3410573865564004, 228.4114629408693133 11.3429352267369978, 228.3817510016937433 11.3447961341559349, 228.3522475214021483 11.3466408530416700, 228.3230615139326005 11.3484629748935983, 228.2940740736275984 11.3502696641036316, 228.2653336387778324 11.3520581199663511, 228.2367430860697368 11.3538341663225300, 228.2082916103096011 11.3555984904911416, 228.1800368130806191 11.3573477475154032, 228.1520392237890462 11.3590784464354115, 228.1243947354944055 11.3607850493609046, 228.0969443603411833 11.3624769794926568, 228.0696393456309181 11.3641571482789345, 228.0424929933024316 11.3658248267828181, 228.0154106641687122 11.3674855739070697, 227.9885578563494164 11.3691297953498367, 227.9618650794217558 11.3707615940650122, 227.9353348111926039 11.3723808773752566, 227.9089933044652696 11.3739861801534410, 227.8828228745919375 11.3755785815686252, 227.8568634996878473 11.3771558345669810, 227.8309964239478518 11.3787248265793970, 227.8053094676697867 11.3802805503902693, 227.7797848238557492 11.3818240807616586, 227.7544332388539488 11.3833548536521434, 227.7292690741718388 11.3848721031974875, 227.7042771343964205 11.3863767514056438, 227.6794424865365158 11.3878696987456021, 227.6547547108999652 11.3893515833190406, 227.6302153125823224 11.3908223637730650, 227.6058446822500514 11.3922809322273206, 227.5815837284566783 11.3937306712904363, 227.5574768187691745 11.3951691153037267, 227.5335303503333364 11.3965959501440786, 227.5097275399122623 11.3980121642391303, 227.4860553007769681 11.3994185320703085, 227.4625029322781415 11.4008156893324628, 227.4390700032320183 11.4022036943938332, 227.4157514915810907 11.4035828609830805, 227.3925662525238351 11.4049521734721111, 227.3695676411417423 11.4063087093581785, 227.3466880305288953 11.4076562680319267, 227.3239817936706970 11.4089918767020748, 227.3013618133060163 11.4103203927983330, 227.2788626998114694 11.4116399330885390, 227.2564905837964488 11.4129501940688858, 227.2341471861257958 11.4142566063334225, 227.2119503831812608 11.4155527167971407, 227.1898755316247218 11.4168399144206791, 227.1679212759833035 11.4181183068200607, 227.1461045130949401 11.4193870060619087, 227.1244248889431105 11.4206460692871250, 227.1028554367275092 11.4218969989113255, 227.0813921445946733 11.4231400422550955, 227.0600099683273072 11.4243765834363167, 227.0387800565281395 11.4256027995450999, 227.0176858866713019 11.4268196233056614, 226.9967364182936080 11.4280266090393461, 226.9758565800003680 11.4292278308191211, 226.9550385935672239 11.4304237238189828, 226.9342329016720612 11.4316169579195979, 226.9135052379878346 11.4328040202420365, 226.8929749480174962 11.4339785612945999, 226.8725374557916155 11.4351462062953271, 226.8522123581987842 11.4363059371511309, 226.8319968195331171 11.4374579340044740, 226.8118864201224483 11.4386024598255549, 226.7918595656055913 11.4397406845346215, 226.7719343835069594 11.4408716721420678, 226.7520928931489834 11.4419963969996026, 226.7323585007395934 11.4431136486168281, 226.7126918304158494 11.4442255234874661, 226.6930802682925616 11.4453327000335001, 226.6735784057245553 11.4464323336035516, 226.6541678320596986 11.4475254147734731, 226.6348499723014811 11.4486118924986169, 226.6156086420508586 11.4496926332953510, 226.5964513089188301 11.4507672681319903, 226.5773802830682087 11.4518356983330936, 226.5583938982743746 11.4528980320372344, 226.5394514986697629 11.4539563930477577, 226.5205720112765277 11.4550098145152575, 226.5017744116919118 11.4560573339754512, 226.4830830479990880 11.4570977194971331, 226.4644630477084490 11.4581327889288342, 226.4458929607690152 11.4591636594085848, 226.4273420018072045 11.4601919179307483, 226.4089327375779703 11.4612113075504123, 226.3905321797907959 11.4622286455833944, 226.3721760724207854 11.4632421133510061, 226.3540415653077389 11.4642427211471709, 226.3361333516323270 11.4652302893049640, 226.3181669859150134 11.4662192771479354, 226.3002739486517783 11.4672030229445188, 226.2824320913053100 11.4681826620402063, 226.2646422367285197 11.4691581650898762, 226.2469095834721315 11.4701292831078110, 226.2292344049324697 11.4710960160929307, 226.2116353879820565 11.4720574419655836, 226.1941018513796280 11.4730141135587900, 226.1766306716323811 11.4739662027049114, 226.1592231105862822 11.4749136616747478, 226.1418925461015306 11.4758558408019180, 226.1246140672760987 11.4767939954951359, 226.1074024905091449 11.4777274041279629, 226.0902695214741414 11.4786555042766718, 226.0731674626649976 11.4795806696915488, 226.0561148944835281 11.4805019915932753, 226.0391203976556085 11.4814190596915857, 226.0221853383620783 11.4823318209415373, 226.0053302814421556 11.4832392822444014, 225.9885536989872605 11.4841415383638772, 225.9718003975531531 11.4850413028522933, 225.9550662527171312 11.4859387811404918, 225.9383869128346873 11.4868322431939074, 225.9217536701528388 11.4877221247974735, 225.9051656781837778 11.4886084777362605, 225.8886411839923767 11.4894904303679706, 225.8721818201447036 11.4903679195481985, 225.8557774564206682 11.4912414492826134, 225.8394241488472858 11.4921112224739144, 225.8231345766313609 11.4929766430689355, 225.8068834000266065 11.4938389402025560, 225.7906841315520694 11.4946974768609138, 225.7745264906774594 11.4955527559106727, 225.7584156584585173 11.4964045403916124, 225.7423465946622230 11.4972530808839259, 225.7263306551091091 11.4980978487175864, 225.7103637501322737 11.4989390503740179, 225.6944403536005268 11.4997769586410374, 225.6785731333581566 11.5006109868170263, 225.6627606321947610 11.5014412173747989, 225.6469855377237934 11.5022684764168162, 225.6312478555481391 11.5030927722805156, 225.6155505187082611 11.5039139764861726, 225.5999034371537562 11.5047316362784287, 225.5843036923903924 11.5055458998999516, 225.5687372937137525 11.5063574287778980, 225.5532030184873520 11.5071662870799507, 225.5377227249360317 11.5079714709823211, 225.5222898787817769 11.5087732957038735, 225.5069090090458701 11.5095715644305443, 225.4915549235071524 11.5103674479764884, 225.4762447625165578 11.5111601660590104, 225.4609749326404540 11.5119498939062872, 225.4457365038296643 11.5127370489516903, 225.4305250723085123 11.5135218388634897, 225.4153505895347962 11.5143038171354597, 225.4002092546294307 11.5150831649260734, 225.3851016085648098 11.5158598654308175, 225.3700330195559616 11.5166336842156163, 225.3550142447416533 11.5174041464569346, 225.3400350352194152 11.5181717255997285, 225.3250842761335662 11.5189369296463209, 225.3101705090120106 11.5196993830341832, 225.2952945149421566 11.5204590600330974, 225.2804449879838273 11.5212164731367626, 225.2656236019609821 11.5219715538304612, 225.2508347977908443 11.5227241118179400, 225.2360836991663291 11.5234739286214012, 225.2213701223733437 11.5242210219101882, 225.2066922232514514 11.5249654823094687, 225.1920523314329614 11.5257072167331263, 225.1774439551033993 11.5264465188925040, 225.1628688639249276 11.5271833193649442, 225.1483231609240931 11.5279177960410184, 225.1338080113109754 11.5286499054960867, 225.1193156868265817 11.5293799896077189, 225.1048406914387385 11.5301082903624863, 225.0903927203178796 11.5308343936089983, 225.0759731997254676 11.5315582445733433, 225.0615726061145381 11.5322802576354757, 225.0471948914258746 11.5330002677501433, 225.0328448253008276 11.5337180770388592, 225.0185250472502503 11.5344335803595950, 225.0042336758099850 11.5351468651141396, 224.9899666840143198 11.5358581082705030, 224.9757293128529625 11.5365670953030204, 224.9615188349461619 11.5372739482972069, 224.9473343603625040 11.5379787112565051, 224.9331867190003038 11.5386809398691899, 224.9190651590865002 11.5393810912945245, 224.9049589851297810 11.5400796146967703, 224.8908763596499512 11.5407761760390457, 224.8768203267530055 11.5414706560991558, 224.8627911626619493 11.5421630507644473, 224.8487873231412664 11.5428534304604344, 224.8348025935600560 11.5435420547181717, 224.8208432662335667 11.5442286728690391, 224.8069064464890232 11.5449134088227350, 224.7929952890955576 11.5455961416041113, 224.7790961745725156 11.5462774242215751, 224.7652157298573457 11.5469569934605225, 224.7513584997170994 11.5476346729869821, 224.7375268209609089 11.5483103768236575, 224.7237220902758565 11.5489840576921914, 224.7099413765588451 11.5496558393201507, 224.6961637810842660 11.5503265461539364, 224.6824171483852126 11.5509950911998516, 224.6686890557825791 11.5516619670280267, 224.6549772382042534 11.5523272659267597, 224.6412812909761669 11.5529910072228450, 224.6276091034440014 11.5536528930102023, 224.6139594562444017 11.5543129777216969, 224.6003182497867385 11.5549718025802619, 224.5867005368071148 11.5556288004592993, 224.5731010661897926 11.5562841765020163, 224.5595318451183573 11.5569374888610756, 224.5459817047652962 11.5575891644592375, 224.5324427190808478 11.5582395019210420, 224.5189143401585454 11.5588885230366429, 224.5054022183514348 11.5595360233723632, 224.4919123846912044 11.5601817897050676, 224.4784375362928017 11.5608260941168410, 224.4649757674634429 11.5614690093784702, 224.4515271517113888 11.5621105363332521, 224.4380954082662356 11.5627505474351384, 224.4246791510049945 11.5633890977143405, 224.4112755960894674 11.5640262896338815, 224.3978846737758772 11.5646621293418335, 224.3845066428590371 11.5652966117998073, 224.3711457528081610 11.5659295969039704, 224.3577977362123761 11.5665612362988721, 224.3444652819518979 11.5671914448567392, 224.3311485458364416 11.5678202246759660, 224.3178463670832343 11.5684476215622389, 224.3045557510956485 11.5690737397591139, 224.2912636805598368 11.5696990018557990, 224.2779812886730895 11.5703230455223807, 224.2647169075784745 11.5709456114839053, 224.2514653724545894 11.5715668719389502, 224.2382246445122291 11.5721868961484091, 224.2249954647945458 11.5728056663998675, 224.2117774258872487 11.5734232007998141, 224.1985677641199004 11.5740395866003460, 224.1853739310532205 11.5746546100467338, 224.1721921301376881 11.5752683925316280, 224.1590180429057853 11.5758810639388887, 224.1458517540423827 11.5764926247218618, 224.1326993443378797 11.5771029132381766, 224.1195552562876117 11.5777120902492623, 224.1064199000646795 11.5783201500428135, 224.0932922280796049 11.5789271253297930, 224.0801718772115123 11.5795330298151136, 224.0670575303321073 11.5801378997012527, 224.0539473086348039 11.5807417811433293, 224.0408440714022333 11.5813446074286652, 224.0277532395576827 11.5819462641829940, 224.0146726415871967 11.5825468155495450, 224.0016005777073929 11.5831463107956161, 223.9885357303077740 11.5837447873853687, 223.9754767473355059 11.5843422797862061, 223.9624200726219385 11.5849388562229869, 223.9493664901772547 11.5855344996028045, 223.9363221822949299 11.5861291150974708, 223.9232837412845640 11.5867227707995344, 223.9102514687340602 11.5873154735786805, 223.8972278339578850 11.5879072106865273, 223.8842074228049341 11.5884980596550555, 223.8711897945752867 11.5890880278437507, 223.8581768384312625 11.5896771077476899, 223.8451691054755202 11.5902653131403053, 223.8321650096256690 11.5908526677333601, 223.8191624724303210 11.5914391819364901, 223.8061618009825793 11.5920248568939055, 223.7931629563950935 11.5926096948439756, 223.7801640483893095 11.5931936739012809, 223.7671670080413833 11.5937768052847883, 223.7541730621474301 11.5943591186324095, 223.7411823205456471 11.5949406428960362, 223.7281945822359148 11.5955214095320009, 223.7152092203553195 11.5961014400608047, 223.7022255713057461 11.5966807499123217, 223.6892422590755416 11.5972592901638460, 223.6762589726463375 11.5978370357118514, 223.6632763821548906 11.5984140565170044, 223.6502941596621667 11.5989903554876275, 223.6373122485587146 11.5995659928159363, 223.6243300458003489 11.6001409101511435, 223.6113474183810581 11.6007150945224744, 223.5983643014767210 11.6012885646925472, 223.5853804742069997 11.6018613808046673, 223.5723949789533549 11.6024337740753829, 223.5594084415188831 11.6030053638418362, 223.5464202437137260 11.6035763342931428, 223.5334298265308917 11.6041467476705247, 223.5204368671160182 11.6047166055632065, 223.5074413311786543 11.6052858741749585, 223.4944432982269404 11.6058545207680535, 223.4814424785578808 11.6064225703417829, 223.4684383277624136 11.6069900727135007, 223.4554303426215824 11.6075570640285157, 223.4424179562224992 11.6081235823943523, 223.4294005333658788 11.6086896685846472, 223.4163767564456577 11.6092554251419369, 223.4033493491641593 11.6098205678131965, 223.3903182963034055 11.6103850983903456, 223.3772834961593503 11.6109490258626220, 223.3642450371695531 11.6115123420543505, 223.3512033206650358 11.6120750138235813, 223.3381552833177466 11.6126372901045816, 223.3251009602248871 11.6131991535745271, 223.3120397912730937 11.6137606354857805, 223.2989722102153110 11.6143216904895947, 223.2858985034939394 11.6148822884757639, 223.2728171532854446 11.6154425337153047, 223.2597285678842525 11.6160023859097290, 223.2466317184571665 11.6165619096001063, 223.2335277664750777 11.6171210135613414, 223.2204169764060566 11.6176796739163031, 223.2072988293896003 11.6182379214860720, 223.1941722853886176 11.6187958206725579, 223.1810361052819758 11.6193534462533226, 223.1678913125293775 11.6199107220579378, 223.1547381380204058 11.6204676270292602, 223.1415754377222811 11.6210242292901071, 223.1284015147917614 11.6215806294810378, 223.1152151257173557 11.6221368962474347, 223.1020209030159833 11.6226927309534513, 223.0888180899151791 11.6232481781418482, 223.0756052319352136 11.6238033234601996, 223.0623811454728411 11.6243582333952205, 223.0491451294250567 11.6249129435087841, 223.0358968024123385 11.6254674694606805, 223.0226367869022113 11.6260217673401947, 223.0093615337413837 11.6265760397256166, 222.9960678207886531 11.6271304645915841, 222.9827655838396936 11.6276844535645623, 222.9694554206600969 11.6282379715353894, 222.9561342545889318 11.6287911942133846, 222.9427998983108523 11.6293442423045565, 222.9294510268505860 11.6298971849561319, 222.9160884180237190 11.6304499718576011, 222.9027074603666563 11.6310028546020856, 222.8893176033855070 11.6315552995097704, 222.8759211426466607 11.6321071795064235, 222.8625124070458412 11.6326588071381831, 222.8490832134951631 11.6332106252531098, 222.8356348319168205 11.6337625545451147, 222.8221730868968393 11.6343142716344818, 222.8086998368636671 11.6348656728601068, 222.7952032410212837 11.6354173891396151, 222.7816844858272418 11.6359693461163598, 222.7681514532171434 11.6365211164074118, 222.7546094596882540 11.6370724159062018, 222.7410496054541227 11.6376237118867820, 222.7274689117791979 11.6381751538767553, 222.7138741945800575 11.6387263792080695, 222.7002655263083852 11.6392773809202303, 222.6866375324850083 11.6398284332481410, 222.6729866912277771 11.6403797107276681, 222.6593141329916534 11.6409311470295815, 222.6456207319742191 11.6414826900592825, 222.6319141538511417 11.6420339437191078, 222.6181898888900719 11.6425851340134141, 222.6044497077729432 11.6431361669641209, 222.5906859946142617 11.6436874213258434, 222.5768997746848186 11.6442388379903292, 222.5630916264524330 11.6447903810514184, 222.5492639055913457 11.6453419268984586, 222.5354268513521276 11.6458929635110628, 222.5215672763444275 11.6464441414515800, 222.5076782329805951 11.6469957955623027, 222.4937638625381169 11.6475477129753546, 222.4798292363335577 11.6480996383536564, 222.4658732608358775 11.6486516197716785, 222.4519005455349543 11.6492034280629078, 222.4379138599462351 11.6497549259799520, 222.4239108831788769 11.6503062233066377, 222.4098822394064712 11.6508577672935250, 222.3958278149373484 11.6514095560063904, 222.3817501135741566 11.6519614625957857, 222.3676471868184592 11.6525135736862762, 222.3535187113670872 11.6530658977330486, 222.3393601721838877 11.6536186413909473, 222.3251663416669999 11.6541720424622000, 222.3109466623493802 11.6547256460788766, 222.2967040816853626 11.6552793072878345, 222.2824345096871639 11.6558332118278578, 222.2681376654351197 11.6563873657033454, 222.2537934125687684 11.6569426978119299, 222.2394296278619663 11.6574979009650406, 222.2250456168259518 11.6580530033773524, 222.2106332312147856 11.6586083764684449, 222.1961901634218748 11.6591641190260660, 222.1817259895392738 11.6597197839939728, 222.1672323459247878 11.6602757492814497, 222.1527060469099695 11.6608321525856535, 222.1381498752830623 11.6613888587292571, 222.1235645886087013 11.6619458258008599, 222.1089488152721856 11.6625031085986155, 222.0943054474932126 11.6630605689926643, 222.0796369850670828 11.6636180879316864, 222.0649326370145218 11.6641761438978122, 222.0501916741798993 11.6647347600702851, 222.0354200415984565 11.6652936614623552, 222.0206255050645439 11.6658524948370594, 222.0058055009197631 11.6664113692263243, 221.9909317003409228 11.6669715336889777, 221.9760187813601533 11.6675323245149656, 221.9610674740686136 11.6680936993524185, 221.9460834295307166 11.6686553999321863, 221.9310575638700982 11.6692178166093186, 221.9159984711472191 11.6697805626173459, 221.9009259266190099 11.6703427671973010, 221.8858296896020477 11.6709048744522352, 221.8706995944916969 11.6714673207687980, 221.8555326260529625 11.6720302285323623, 221.8403304885915759 11.6725935149984181, 221.8250972499788816 11.6731569963287445, 221.8098195614857389 11.6737212391253511, 221.7944889260295156 11.6742865963672013, 221.7791202134384889 11.6748524179399720, 221.7637180402759896 11.6754184975323128, 221.7482700456506564 11.6759853535369480, 221.7327669514019988 11.6765533683674345, 221.7172115229157043 11.6771224104400737, 221.7016211571630038 11.6776917309543347, 221.6860028019631557 11.6782610288026678, 221.6703447483006642 11.6788307904666926, 221.6546244431609409 11.6794019527691013, 221.6388611839107909 11.6799736915431538, 221.6230487052664841 11.6805462579741306, 221.6071946734359415 11.6811193203433437, 221.5913075585578440 11.6816925165910792, 221.5753864703945908 11.6822658761608444, 221.5594131535235931 11.6828401465168774, 221.5433904492093404 11.6834151973097651, 221.5273308964320336 11.6839905000560975, 221.5112244756882376 11.6845664577840918, 221.4950649900503663 11.6851433129982265, 221.4788646116662392 11.6857205548694267, 221.4626020103556243 11.6862990436987797, 221.4462705120650412 11.6868790352438801, 221.4298859924452358 11.6874598673816568, 221.4134506856235589 11.6880414365643013, 221.3969754781638244 11.6886232905533163, 221.3804605137588624 11.6892054142854072, 221.3638996850392004 11.6897880441166127, 221.3472772159433077 11.6903718019564433, 221.3305813530340060 11.6909571427546126, 221.3137711140899171 11.6915456840291085, 221.2969116219964576 11.6921348014786908, 221.2800176036296591 11.6927238980806685, 221.2630934336358735 11.6933127927655107, 221.2461192125695106 11.6939022661089460, 221.2290863538799215 11.6944926448517066, 221.2119945040124946 11.6950839284617025, 221.1948675705596088 11.6956751636199172, 221.1776935519548317 11.6962668126592853, 221.1604303534516021 11.6968605094735594, 221.1430823375206387 11.6974560610127813, 221.1256729793850582 11.6980525325160976, 221.1082343240083787 11.6986486654978012, 221.0907777951847493 11.6992440115996175, 221.0732731529912485 11.6998397355013690, 221.0556760649141665 11.7004375334995672, 221.0379809653518350 11.7010375956696304, 221.0201910780059507 11.7016397730786199, 221.0023326505253749 11.7022430375102857, 220.9844141227268608 11.7028470498724388, 220.9664267865855720 11.7034521267921079, 220.9483618371744740 11.7040585853336694, 220.9302181846820758 11.7046664471111175, 220.9120117963108498 11.7052750889676211, 220.8937461626256891 11.7058843638523342, 220.8754296372314911 11.7064939432009609, 220.8570353831405555 11.7071048211223498, 220.8385387414597858 11.7077179002593432, 220.8199419597752353 11.7083330701279866, 220.8012542966679348 11.7089499601218403, 220.7824976140127831 11.7095677351779131, 220.7636932618535184 11.7101855873401206, 220.7448115762650502 11.7108046009619358, 220.7258449069578603 11.7114250382169285, 220.7067902066016245 11.7120469892335457, 220.6876435492174267 11.7126705751821731, 220.6684018412082366 11.7132958852971534, 220.6490775002803275 11.7139224419373367, 220.6296751617489633 11.7145500551851551, 220.6101884901056565 11.7151789348703232, 220.5906226553498186 11.7158088720647999, 220.5709709286423674 11.7164400892134566, 220.5512576667551059 11.7170716871887297, 220.5314614383965477 11.7177044199639759, 220.5115590022702179 11.7183390981858260, 220.4915452243133416 11.7189758769758754, 220.4714307799504240 11.7196143463432527, 220.4512468588942227 11.7202533715875568, 220.4309992066258417 11.7208927312753612, 220.4106498399647478 11.7215337511401767, 220.3901880983321462 11.7221767796176426, 220.3696269742781340 11.7228213298248747, 220.3489604038603034 11.7234675876106191, 220.3281690552258851 11.7241162000989156, 220.3072756756530168 11.7247663403946412, 220.2862824116060096 11.7254179062737975, 220.2651764715906495 11.7260713139721826, 220.2439627765920136 11.7267263625539524, 220.2226597862533310 11.7273823863618976, 220.2012604090785430 11.7280396049063711, 220.1797602369004778 11.7286981429156398, 220.1581417345546754 11.7293585718312805, 220.1364090861307830 11.7300207161664911, 220.1145235049651490 11.7306858616886558, 220.0924773395388172 11.7313542241099480, 220.0703026463932019 11.7320246749542285, 220.0480152578880109 11.7326966446598480, 220.0256193313577455 11.7333699618235077, 220.0031393234814630 11.7340437772018173, 219.9805459909598255 11.7347190432236310, 219.9578262375325153 11.7353961632678505, 219.9350228461188124 11.7360736819773805, 219.9120955538539874 11.7367529071657000, 219.8890352094786351 11.7374341046477060, 219.8658230573198296 11.7381178519777958, 219.8424378550896279 11.7388048003128542, 219.8189420393968305 11.7394928593222510, 219.7954051231405685 11.7401797339257250, 219.7717126788438691 11.7408691262540579, 219.7478364883711208 11.7415619025218767, 219.7238247217937896 11.7422564542140329, 219.6876080273496825 11.7432997520321258, 219.6987523783389520 11.7853029348368352, 219.7061791771076571 11.8133127052677054, 219.7135986549972699 11.8413287509590859, 219.7210947404915657 11.8693483800538981, 219.7285881728042796 11.8973741241818960, 219.7359476924964099 11.9254261184938049, 219.7433492070179000 11.9534995743634784, 219.7507477436130330 11.9815790420429416, 219.7579850993606385 12.0096695496598649, 219.7652250046039342 12.0377658721523719, 219.7725553247667563 12.0658652068576604, 219.7800022085925491 12.0939667193907923, 219.7873408946113614 12.1220775512220698, 219.7950743482863629 12.1501817176844593, 219.8021390085507676 12.1783129843265812, 219.8093731982575889 12.2064422366637455, 219.8167053719220974 12.2345716176982222, 219.8241449129861564 12.2627034586466905, 219.8313191008305978 12.2908495551467496, 219.8387108569568795 12.3189946085297830, 219.8460894153990637 12.3471459191799120, 219.8532640728367369 12.3753095044633206, 219.8601696000659160 12.4034874078654624, 219.8674454815513286 12.4316594207246638, 219.8745707848169104 12.4598419912782550, 219.8816850376582863 12.4880175631535977, 219.8889121191596416 12.5161815295508241, 219.8961929097609413 12.5443496532764520, 219.9035207113772401 12.5725221394411850, 219.9108000506688256 12.6007019866288559, 219.9180033535190546 12.6288900488843403, 219.9252926239190629 12.6570812287821681, 219.9325837932304353 12.6852781632398539, 219.9416672227909828 12.7134247386159469, 219.9543961131030585 12.7414629674117563, 219.9609663350123014 12.7696974747126752, 219.9637127246121509 12.7980546220564388, 219.9693396487065513 12.8263272760372882, 219.9763389821717681 12.8545627692792479, 219.9873479022917024 12.8826789124793954, 219.9942663404656287 12.9109285111587457, 220.0001191112024514 12.9392170379039477, 220.0060791742523350 12.9675078900646081, 220.0125259484729838 12.9957892679278366, 220.0204798710784360 13.0240294903622651, 220.0303293171268990 13.0522308974955514, 220.0363637765321414 13.0805716601223949, 220.0435221787505213 13.1088831469933211, 220.0503444749545849 13.1372106970433347, 220.0554559747872645 13.1655969105213551, 220.0637152732548998 13.1938911366292153, 220.0719544408212869 13.2221916261448413, 220.0809450265347778 13.2504744743735987, 220.0855198223371190 13.2788996753560333, 220.0951748739387028 13.3071731968698597, 220.1002723971644173 13.3355840090515123, 220.1073650537146023 13.3639288229455033, 220.1144815968071384 13.3922785026534399, 220.1215875630216487 13.4206341039521941, 220.1287352849993226 13.4489940064017972, 220.1370402481172732 13.4773238028523235, 220.1447839374467890 13.5056765105854222, 220.1521111762056648 13.5340476372248997, 220.1594759156825489 13.5624231739958425, 220.1672083186715554 13.5907929548752993, 220.1735074973374822 13.6191997960329587, 220.1797183184499715 13.6476015913110622, 220.1873653705166589 13.6759648322871517, 220.1929970825444229 13.7043955203467398, 220.2002836983144221 13.7327809785908634, 220.2072371138302174 13.7611822224267666, 220.2143098341883558 13.7895853682338103, 220.2215409219504920 13.8179892239169551, 220.2286146031840701 13.8464034432460039, 220.2359969003394440 13.8748137749151255, 220.2429905149833758 13.9032506382508085, 220.2501006645853749 13.9316990780717074, 220.2572072441929834 13.9601531121284097, 220.2642324537942500 13.9886151020148333, 220.2713546035055572 14.0170796066238470, 220.2784888319845038 14.0455492059331011, 220.2854618050496072 14.0740291669810969, 220.2923997657556754 14.1025156370404776, 220.2996432291302824 14.1309982530505547, 220.3069647405167757 14.1594839348555368, 220.3142063440979825 14.1879636489215741, 220.3212788520830827 14.2164393478506881, 220.3285570377223621 14.2449142699710301, 220.3357705561347473 14.2733966115232889, 220.3430038924011285 14.3018838045941319, 220.3501936701142938 14.3303777597299629, 220.3574521201990422 14.3588750717818545, 220.3646056912263020 14.3873809842522782, 220.3714125051088502 14.4159027848002559, 220.3785545334652625 14.4444198672097279, 220.3856337208090963 14.4729600249569028, 220.3927611381831184 14.5015207378316209, 220.4001050938870776 14.5300802442172756, 220.4070157686177538 14.5586581175413450, 220.4141741436548045 14.5872338305843900, 220.4213520876047312 14.6158142502689010, 220.4283400949778695 14.6444056730379835, 220.4351961122930561 14.6730063439768230, 220.4419879942652756 14.7016142084780572, 220.4491297933535918 14.7302168131950566, 220.4562863983109935 14.7588242341025122, 220.4632064466015891 14.7874440138399041, 220.4702124060514450 14.8160664519636125, 220.4773075838372449 14.8446914419828282, 220.4839436390709864 14.8733354361903700, 220.4909400907793326 14.9019738275908438, 220.4976830004601425 14.9306250294145304, 220.5046871352374751 14.9592735967586723, 220.5120298154663772 14.9879172096237898, 220.5191431523294341 15.0165728862980128, 220.5262490349775248 15.0452192623841103, 220.5332207143513585 15.0738593394066136, 220.5401179897107227 15.1025068650382295, 220.5471624571489713 15.1311552001949128, 220.5542495225764128 15.1598074722681364, 220.5611462416796371 15.1884706317373812, 220.5679511429215438 15.2171417192930516, 220.5747134507969065 15.2458192563325561, 220.5815516687183049 15.2744996978238152, 220.5883461733833144 15.3031866066804731, 220.5952718645040704 15.3318669234705656, 220.6021707515394894 15.3605449417647471, 220.6091175733615160 15.3892267262936802, 220.6161856756119732 15.4179100903335513, 220.6230988135851874 15.4466032398149729, 220.6301581993917296 15.4752972168452896, 220.6372147494944045 15.5039964430272246, 220.6444441175555085 15.5326957057448869, 220.6513662353943062 15.5614092262724686, 220.6584249249493439 15.5901238422739468, 220.6656150400222600 15.6188559151084991, 220.6725666951840594 15.6476172352274006, 220.6794748558619972 15.6763848779239545, 220.6865817604997630 15.7051516701513965, 220.6936357220202467 15.7339250506465902, 220.7007661076806073 15.7627011863723077, 220.7078723698911062 15.7914830407443709, 220.7148087278339403 15.8202749134539626, 220.7215739629969562 15.8490768265738264, 220.7283696407323532 15.8778828202649382, 220.7350802981979427 15.9066906071818064, 220.7416702149522507 15.9355009310670663, 220.7481918200226971 15.9643182516010249, 220.7548889450735601 15.9931353702346524, 220.7613380771931304 16.0219647648577634, 220.7677626895558092 16.0507998368716578, 220.7746364759300377 16.0796266327909585, 220.7812760232247626 16.1084652724760176, 220.7879783037277264 16.1373070028008776, 220.7945420930387002 16.1661577373793826, 220.8003749786528260 16.1950206147845002, 220.8065617769120479 16.2238629586943617, 220.8128621961369333 16.2527069132252286, 220.8191817781748512 16.2815552456965129, 220.8255725901924507 16.3104064262141080, 220.8322066930488177 16.3392554116777653, 220.8387268829000334 16.3681126612887446, 220.8455734888675579 16.3969652844466474, 220.8521103354397894 16.4258318847736930, 220.8587076063147094 16.4547016260165471, 220.8645847859068567 16.4836114740111590, 220.8712379210808763 16.5125184940503225, 220.8780366528559398 16.5414260978017715, 220.8844439639942436 16.5703499436321806, 220.8910779637470796 16.5992719915153337, 220.8980535530162683 16.6281888886635407, 220.9049801590114726 16.6571120173582976, 220.9120543709435367 16.6860356422276155, 220.9194018674333790 16.7149560939354274, 220.9275853956411879 16.7438569742157100, 220.9337514391982040 16.7728073785344201, 220.9389458499302350 16.8017760252213293, 220.9442633217356047 16.8307458476351215, 220.9495797696569923 16.8597204501495881, 220.9576980259738264 16.8886184325720556, 220.9646433111029467 16.9175552950014456, 220.9706915454232785 16.9465229738655516, 220.9797360847118171 16.9754084990557104, 220.9858503429987877 17.0043838123896194, 220.9958092372052647 17.0332524233293618, 221.0051547332684834 17.0621516662596875, 221.0123955258806348 17.0911251847201484, 221.0184945331998847 17.1201365065583708, 221.0265358812493162 17.1490962373539766, 221.0342592249748179 17.1780698850797862, 221.0416971724159225 17.2070564925110219, 221.0492649287550080 17.2360440209217529, 221.0574163920278750 17.2650193215307297, 221.0642376484496765 17.2940378146577451, 221.0712507672822369 17.3230554066909477, 221.0750035058534024 17.3521530123523817, 221.0833825984780106 17.3811014281199263, 221.1012000639443045 17.4097816163964545, 221.1234697960219933 17.4383372244083148, 221.1446009049126360 17.4669299947537660, 221.1659814111733908 17.4955196829968251, 221.1862074950514341 17.5241471728012712, 221.1957570593854427 17.5530905108681665, 221.2038686914070240 17.5820804815569822, 221.2080601838380858 17.6111893256108196, 221.1988433214207248 17.6407165963388977, 221.1916363249929702 17.6702144711225309, 221.1877485885951558 17.6996199313913323, 221.1891656915406088 17.7288761977612204, 221.1968354291195453 17.7579563475948667, 221.2025406650257082 17.7870977090662272, 221.2096147692232648 17.8162040254308245, 221.2165160141038598 17.8453198054343645, 221.2224942246927526 17.8744666959394074, 221.2277119717738856 17.9036399876857466, 221.2332821021322786 17.9327909628593183, 221.2383170204656722 17.9619443245157626, 221.2442905425824904 17.9910751117225907, 221.2498363549150611 18.0202227059452653, 221.2557305326318726 18.0493647450938646, 221.2621416428434600 18.0784963864217474, 221.2691430202075935 18.1076155305098077, 221.2754988088338735 18.1367577199723300, 221.2813337865354413 18.1659193359810658, 221.2877855764635342 18.1950676780735883, 221.2953253951094723 18.2241907181451985, 221.3013599376515970 18.2533629946779001, 221.3064374132812020 18.2825671410777524, 221.3124537528991596 18.3117487398260970, 221.3182281059690695 18.3409416697505847, 221.3250634187268986 18.3701085799299300, 221.3330656593484491 18.3992464482553046, 221.3374356805543925 18.4284927546433543, 221.3395300092193736 18.4578084756215759, 221.3458224370075129 18.4870083936977103, 221.3522630302541927 18.5162084245159981, 221.3577068639017398 18.5454412770415153, 221.3641904024743212 18.5746487549762911, 221.3715279110405447 18.6038361783344079, 221.3767990322102150 18.6330869316894123, 221.3800267733186331 18.6624002609262085, 221.3827362009375577 18.6917325593055210, 221.3870286297943437 18.7210239623286085, 221.3954345644621355 18.7502025136998931, 221.3995412872705231 18.7795077426605879, 221.4052686287405720 18.8087667836010581, 221.4116141403480924 18.8380079579074753, 221.4182075521312925 18.8672463620802873, 221.4234075461477289 18.8965286224821760, 221.4297424895057134 18.9257828881485999, 221.4381330032734922 18.9549830454996382, 221.4437786009013962 18.9842653900625713, 221.4516916820943777 19.0134876143406935, 221.4581724332157364 19.0427547246203943, 221.4643258332748417 19.0720353411072203, 221.4703040021612424 19.1013190923657241, 221.4757366350390271 19.1306161365466032, 221.4827138450010011 19.1598736469915174, 221.4886341154185061 19.1891653110444977, 221.4939175149503114 19.2184791927305980, 221.4996824220591805 19.2477836349604914, 221.5040993844800425 19.2771303361761817, 221.5096515242152009 19.3064491173592501, 221.5157897916339209 19.3357555188309327, 221.5254028688229937 19.3649680592404678, 221.5379303707704821 19.3941024988662392, 221.5502966622345014 19.4232455911104083, 221.5569858007410176 19.4525532673038555, 221.5662602299367734 19.4817920507718547, 221.5778712907634826 19.5109689308560554, 221.5906471454106281 19.5401169399273584, 221.6024846423248960 19.5692955531484998, 221.6125339520685600 19.5985288924894832, 221.6228556388711013 19.6277586119359704, 221.6323660623660317 19.6570154157516725, 221.6415036192033199 19.6862868958747796, 221.6440994493522965 19.7157478621153466, 221.6431790139832003 19.7453121777085840, 221.6474316280026073 19.7747340490760877, 221.6570225243102072 19.8040091392888229, 221.6647075506523663 19.8333421334356821, 221.6736770572801163 19.8626428791509682, 221.6816534356838986 19.8919757277428566, 221.6864937928417305 19.9214011980678016, 221.6879797046681517 19.9509252781368964, 221.6950232771162632 19.9803103316330919, 221.7007288044115398 20.0097516795446992, 221.7040268217931498 20.0392648175583936, 221.7074732176745897 20.0687776379662850, 221.7106187015569674 20.0983027922388793, 221.7176740678478097 20.1277217372505213, 221.7230474804684377 20.1571919249014684, 221.7277670534129754 20.1866843939325022, 221.7319372791985188 20.2161961796125986, 221.7405646670954127 20.2455863929184758, 221.7463882443915111 20.2750552242748441, 221.7538847956957397 20.3044764361599270, 221.7622793454201258 20.3338762065354963, 221.7701565144907363 20.3632943760536058, 221.7734189145131722 20.3928463603017818, 221.7781702146661189 20.4223602165639591, 221.7857704917922774 20.4517976945902156, 221.7905756422969432 20.4813176641481398, 221.7934115371495238 20.5108968160978833, 221.7963450988040961 20.5404769506598548, 221.8001359602207003 20.5700367282714680, 221.8054088753309259 20.5995586337327090, 221.8103228715708326 20.6290943850318556, 221.8166331239539772 20.6585946948034866, 221.8221241242079316 20.6881217627244531, 221.8259241657792984 20.7177000296168892, 221.8288535880878953 20.7473064170266852, 221.8317732952318693 20.7769167504911394, 221.8434864831883147 20.8062842966481227, 221.8548980732345797 20.8356638512113008, 221.8497146823973480 20.8655018099665917, 221.8425379707036313 20.8953868196195387, 221.8373773923880208 20.9252182013958574, 221.8382192559556358 20.9548855527560143, 221.8489009231280136 20.9842827888029326, 221.8672566919480857 21.0134697678678819, 221.8797273718959673 21.0428242378765376, 221.8887999809484199 21.0722772506783684, 221.8917645081734804 21.1019045712286442, 221.8997328109513774 21.1313958606348358, 221.8990926617780701 21.1611280411997136, 221.9019993443867236 21.1907616767497267, 221.9051040779034452 21.2203933634021809, 221.9093557913155053 21.2499967315714251, 221.9134297178703150 21.2796086472793569, 221.9116007488572677 21.3093879024833477, 221.9032882877631039 21.3393495526403925, 221.9060520607276032 21.3690080228472183, 221.9051334272646727 21.3987714957427535, 221.9034009241673573 21.4285605666680112, 221.9100285267250285 21.4581261494620072, 221.9160069827354107 21.4877163658233172, 221.9238932399250928 21.5172577423831370, 221.9293998902476801 21.5468681210289148, 221.9330707636324860 21.5765324978456761, 221.9363254486435721 21.6062118074986067, 221.9410037369507052 21.6358555652424549, 221.9455408147520643 21.6655067258760141, 221.9489016120563178 21.6951936278900881, 221.9527587732168001 21.7248704151448102, 221.9568600872159436 21.7545531876169207, 221.9622411699986344 21.7842141223478478, 221.9689664639684850 21.8138417552296744, 221.9756209612638997 21.8434747838713079, 221.9818735094456201 21.8731222678023371, 221.9874059330416856 21.9027929106306374, 221.9923440430283677 21.9324832584219216, 221.9971277815838278 21.9621812612543970, 222.0022569686708778 21.9918732336838509, 222.0073470417372619 22.0215696932603784, 222.0125447731021211 22.0512545135887450, 222.0181706962674753 22.0809182669923452, 222.0238933057023587 22.1105828125246830, 222.0295305341986136 22.1402531169874308, 222.0351237485043043 22.1699280426223453, 222.0404257554776848 22.1996143289707462, 222.0459155990378690 22.2292988830823006, 222.0512924341725807 22.2589899134932558, 222.0566673648636140 22.2886843763580522, 222.0618862307806296 22.3183864695259970, 222.0670553473142945 22.3480957600301977, 222.0723717418445631 22.3778070086866983, 222.0777839749534337 22.4075189965145825, 222.0831798395055046 22.4372347714922391, 222.0886434003691363 22.4669520385449459, 222.0940816859240101 22.4966733209650762, 222.0994527851256350 22.5263997499335709, 222.1047812730600697 22.5561306497441905, 222.1101155305965165 22.5858646932945106, 222.1154152126226791 22.6156029722921659, 222.1204420128612753 22.6453400487604668, 222.1255646965227015 22.6750652360078497, 222.1305329997703950 22.7047979141010146, 222.1355847788389895 22.7345316113037761, 222.1406216272999359 22.7642689947007923, 222.1456386712924882 22.7940101866968448, 222.1506385133021979 22.8237551068888891, 222.1555893547568417 22.8535046095124379, 222.1605043395214523 22.8832583261723137, 222.1653877637397443 22.9130161311541372, 222.1701197628978548 22.9427889794096842, 222.1746776288089222 22.9725778902955824, 222.1789441577180355 23.0023778465027746, 222.1836557253604099 23.0321689615527880, 222.1902440399031207 23.0619126298867805, 222.1954526487997725 23.0916966955946314, 222.2010831637907131 23.1214725487913562, 222.2083216385476589 23.1512082125607428, 222.2139515806716474 23.1809904051321993, 222.2171221061061317 23.2108420164642872, 222.2209885174087560 23.2406820492069599, 222.2264371356683625 23.2704868990150970, 222.2313264838332429 23.3003099105249731, 222.2360295056382427 23.3301410281423109, 222.2416143590607192 23.3599515096318804, 222.2470280979947290 23.3897696784447255, 222.2519457695757410 23.4196042624413252, 222.2572284978857340 23.4494320947136323, 222.2625351292995788 23.4792623413270860, 222.2678234451631738 23.5090961314884019, 222.2731187339419421 23.5389287177683109, 222.2783913238666287 23.5687606664830014, 222.2836896458870797 23.5985949596657747, 222.2889783775574983 23.6284325360171366, 222.2942692542079612 23.6582730743537084, 222.2995474628685599 23.6881169630518933, 222.3048186546705551 23.7179640409425119, 222.3100880876824306 23.7478141608984963, 222.3153559271631536 23.7776673080602770, 222.3206150332677282 23.8075236679407176, 222.3258698867078920 23.8373906039141410, 222.3311162164115444 23.8672686259859290, 222.3363674375739549 23.8971494474723585, 222.3416002241224021 23.9270336834210156, 222.3468409732332702 23.9569206201362341, 222.3520781788035947 23.9868105568549552, 222.3572950909472468 24.0167039334002865, 222.3625011870945229 24.0466004897417847, 222.3677192511808869 24.0764996046101665, 222.3729424320810040 24.1064014557794373, 222.3781468772039318 24.1362901049415974, 222.3833649202102833 24.1661637832156728, 222.3885678890742952 24.1960407689280856, 222.3937637688128746 24.2259208373355825, 222.3989420319749399 24.2558042638988809, 222.4041440839009169 24.2856899312707419, 222.4093321917982280 24.3155788397004535, 222.4144990636801822 24.3454711775703885, 222.4196730904844230 24.3753661753766302, 222.4248346882471878 24.4052643502490199, 222.4300062063282155 24.4351764711447856, 222.4351870688240922 24.4651031622580106, 222.4403525021423036 24.4950330549834590, 222.4455026492308889 24.5249661349346759, 222.4506599244951701 24.5549017980429021, 222.4558229849940574 24.5848400708727297, 222.4609842278840119 24.6147811469395705, 222.4661284181740086 24.6447254265929203, 222.4713101841024070 24.6746714424243159, 222.4764591915086385 24.7046210642576014, 222.4815193388476189 24.7345653488426223, 222.4865942845941618 24.7645009503866795, 222.4916659846251434 24.7944393662822975, 222.4967339979297662 24.8243805977292276, 222.5017992759311483 24.8543246133276234, 222.5068766617617939 24.8842710087474046, 222.5120706243436643 24.9142169965140106, 222.5176992594639671 24.9441541159433555, 222.5230551169869386 24.9741011722104318, 222.5290723867995268 25.0040333259883418, 222.5331869880003524 25.0340250878377617, 222.5376183126892897 25.0640178060554746, 222.5426224342733974 25.0939979418418204, 222.5478384862114467 25.1239750740119945, 222.5527734021785307 25.1539622861092163, 222.5574433522948254 25.1839591350383962, 222.5625189750877837 25.2139478160047545, 222.5680865706248426 25.2439260392117397, 222.5750931585504020 25.2738686682664557, 222.5818713705985488 25.3038199265285257, 222.5873131976027821 25.3338052354567935, 222.5917661569435779 25.3638151370287233, 222.5953573558004734 25.3938504356210331, 222.5981423237900287 25.4239096058506853, 222.6021066629948564 25.4539400323830769, 222.6070875480717746 25.4839460669764506, 222.6120740675006573 25.5139544754087133, 222.6170732825968344 25.5439650650433165, 222.6222362523172649 25.5739738307424211, 222.6271684386658478 25.6039912012795128, 222.6335610292155991 25.6339683652968340, 222.6407584509890683 25.6639224327095832, 222.6425063815139254 25.6940230383629142, 222.6465820115975021 25.7240645599181050, 222.6516161452992719 25.7540832404702051, 222.6567612331085684 25.7841014577184247, 222.6622771706098831 25.8141123513533195, 222.6675096863649514 25.8441331729572639, 222.6724462652574914 25.8741642350099852, 222.6771134454449168 25.9042048236113409, 222.6827850675147147 25.9342363969213565, 222.6931165989195733 25.9641633520688302, 222.6998107998099670 25.9941885113330500, 222.6993812296911130 26.0244039700988594, 222.7004828501916052 26.0545812839361020, 222.7068412638190296 26.0846224342528856, 222.7151250249200416 26.1146151271599116, 222.7223428546290904 26.1446381900456508, 222.7233614602698140 26.1748271206302583, 222.7251698748148669 26.2049974649882707, 222.7297580672671131 26.2350818941298201, 222.7350401377404410 26.2651345787466823, 222.7397478570217118 26.2952047135842477, 222.7441890163832170 26.3252841709139602, 222.7490415028251221 26.3553551043594396, 222.7538245648224802 26.3854301586803643, 222.7585301990882272 26.4155095328669063, 222.7633657664942177 26.4455877700282933, 222.7688255310274030 26.4756518790048681, 222.7734841245476787 26.5057393017970639, 222.7804994013528130 26.5357699997405270, 222.7892222416466268 26.5657611258812274, 222.7934201840647859 26.5958734025947372, 222.7976525280050168 26.6259869814919448, 222.8061529184382721 26.6559906322740723, 222.8082111146292732 26.6861657600329600, 222.8108775599187936 26.7163270320726909, 222.8149933055637462 26.7464524254358622, 222.8202949001197624 26.7765488881515772, 222.8301151846285961 26.8065289628167065, 222.8347576222037389 26.8366503143328003, 222.8375201822001657 26.8668265546497302, 222.8418110343539524 26.8969648288883043, 222.8465067625999154 26.9270946183010693, 222.8524537725533889 26.9571937291571544, 222.8574636362567389 26.9873195347062804, 222.8620005207471593 27.0174598523127969, 222.8671731236977678 27.0475856079521364, 222.8726715768208635 27.0777049164434551, 222.8775474503010514 27.1078426359606084, 222.8816119755437342 27.1380004347832653, 222.8869882262066255 27.1681224765070546, 222.8926632525168827 27.1982387555012899, 222.8956791014973078 27.2284267497900814, 222.8990635443943518 27.2586071020171801, 222.9037992898300047 27.2887541107547165, 222.9093687181026837 27.3188813347096549, 222.9147563759125603 27.3490153396272326, 222.9196081766385760 27.3791653776246413, 222.9243436031846386 27.4093204644486867, 222.9286080088612607 27.4394937878626308, 222.9336119064245736 27.4696539013534995, 222.9389694547906515 27.4998067414168901, 222.9467971585153805 27.5298969245293961, 222.9536775696234372 27.5600138138078385, 222.9590786061853294 27.5901713708527616, 222.9649273858108245 27.6203191385951392, 222.9707788876386587 27.6504687617074580, 222.9779598201788247 27.6805854587204365, 222.9832825767054203 27.7107527614695996, 222.9817568406602675 27.7410883808292539, 222.9874565001115059 27.7712230016942243, 222.9936425870779999 27.8013468434625679, 222.9960558499033709 27.8315712512636928, 223.0003219092063773 27.8617491055424331, 223.0057706188730720 27.8918979783894976, 223.0108205033266415 27.9220591651418673, 223.0159954833870017 27.9522189808752479, 223.0194101868348184 27.9824265788449296, 223.0236278179963563 28.0126150871228674, 223.0270783276969269 28.0428260124708935, 223.0284527756701323 28.0730933626796926, 223.0310594807002644 28.1033303987770076, 223.0333322930906093 28.1335778457469274, 223.0341180624730271 28.1638655435968630, 223.0377939193730583 28.1940800787361177, 223.0423453188266478 28.2242737368840118, 223.0473563566861230 28.2544573009189826, 223.0475810350745860 28.2847663252405717, 223.0468242129842622 28.3151021837166397, 223.0494697180610899 28.3453669498325986, 223.0551226685691404 28.3755718417024134, 223.0596599616459059 28.4058071837450221, 223.0644130602052826 28.4360386740751281, 223.0699211842025136 28.4662524123567628, 223.0775607745896423 28.4964128803653232, 223.0834267667081861 28.5266207293508955, 223.0946602925923798 28.5566915950314275, 223.1011121708191922 28.5868875504529214, 223.1057514664018413 28.6171320328370271, 223.1092717803553853 28.6474026359030276, 223.1131858521137303 28.6776599785361910, 223.1175135978419064 28.7079082719773027, 223.1224011054472101 28.7381437355217422, 223.1295408824392155 28.7683226027757506, 223.1386439433996998 28.7984522355943042, 223.1466096978199971 28.8286128295864472, 223.1512039324809678 28.8588623697965829, 223.1491767764530323 28.8892849121632658, 223.1495096696992277 28.9196477562618064, 223.1531510946221886 28.9499227439960407, 223.1593084067002906 28.9801302235189091, 223.1671463731102847 29.0102958476457857, 223.1733378307822875 29.0405055589104215, 223.1762893691852980 29.0708005572501200, 223.1797411591134050 29.1010841479316511, 223.1842105395194835 29.1313429880286847, 223.1897492654354380 29.1615757529583242, 223.1968336860509510 29.1917701214418592, 223.2007111469362144 29.2220488212398450, 223.2065521127401837 29.2522700368052213, 223.2119706505079080 29.2824949298786201, 223.2143181739425302 29.3128005757714760, 223.2145049372286962 29.3431632754442226, 223.2130727083830095 29.3735688214337003, 223.2169012501166776 29.4038404960356416, 223.2205048495359563 29.4341193922145052, 223.2231762087349409 29.4644236196138216, 223.2286000314355476 29.4946587355595966, 223.2310513877523022 29.5249714295019459, 223.2344723717550892 29.5552689830145106, 223.2401364427293800 29.5855193241913597, 223.2452585570293593 29.6157849349486888, 223.2505202413127563 29.6460483699050634, 223.2559231593407674 29.6763095798611687, 223.2644027871297965 29.7064934052473184, 223.2627241956122077 29.7369385494184755, 223.2645402238002248 29.7672955192699540, 223.2677335536205305 29.7976186173829838, 223.2703656238828387 29.8279573494095835, 223.2756273228060593 29.8582220782173451, 223.2844765439608352 29.8883879235266221, 223.2937085860519630 29.9185452808112444, 223.2973081015859407 29.9488478138921579, 223.2936631005122763 29.9793362624144635, 223.2960666519568633 30.0096716675765087, 223.3009400212339415 30.0399455321323572, 223.3025870375581121 30.0703026551048325, 223.3057019420378992 30.1006237111998871, 223.3089129363874861 30.1309435671736630, 223.3150049756058309 30.1612022619658475, 223.3234217234096093 30.1914144151501098, 223.3234210095013736 30.2218413027543100, 223.3217310036584706 30.2523119774457854, 223.3241338861918166 30.2826801518044384, 223.3291361017755321 30.3129838018023321, 223.3335691814783672 30.3433030311558909, 223.3376879267651702 30.3736313904119228, 223.3415822010329066 30.4039665939800763, 223.3428527313766097 30.4343692093521518, 223.3463046578129365 30.4647139764648003, 223.3516152151530321 30.4950088856224291, 223.3563567921461299 30.5253193045073523, 223.3591806847876740 30.5556792232234464, 223.3633551843414011 30.5860062097936520, 223.3673017153327294 30.6163400617655554, 223.3700134643178785 30.6467061128776557, 223.3771472685353956 30.6769619187441549, 223.3826102810548377 30.7072608972207064, 223.3886354466804676 30.7375468061555068, 223.3920631849616996 30.7678988088326477, 223.3948340483643449 30.7982679488339173, 223.3964740350932345 30.8286665606508272, 223.3988015834056000 30.8590488764019213, 223.4054640310108368 30.8893233212693943, 223.4110113026400199 30.9196268339411588, 223.4122686163350409 30.9500391595034401, 223.4185862540497851 30.9803254154592445, 223.4253672463790679 31.0106010423021878, 223.4280655144321486 31.0409802450029346, 223.4338793837801518 31.0712782786587987, 223.4368728739135861 31.1016439800152682, 223.4352648020607148 31.1321259385783939, 223.4366125414744033 31.1625346167303299, 223.4396705389495708 31.1929014229470027, 223.4456438373769345 31.2231963323206827, 223.4505941710413879 31.2535177730133178, 223.4547715708542057 31.2838594813272053, 223.4577739516643362 31.3142314600314897, 223.4600217044558974 31.3446231543025569, 223.4635365292612903 31.3749880885911949, 223.4679250725203588 31.4053363295574073, 223.4717664817196408 31.4356991046183545, 223.4748831801738049 31.4660808083446888, 223.4799487654960330 31.4964148776198982, 223.4840292327997133 31.5267743476906972, 223.4865411911889623 31.5571736952518300, 223.4883032670847456 31.5875924901525806, 223.4923952324174650 31.6179542209800530, 223.4970672525005568 31.6483023930064604, 223.5030692210884524 31.6786209217952361, 223.5066616283447729 31.7090028002721205, 223.5106210414199381 31.7393763677076528, 223.5132764002270278 31.7697830875398139, 223.5179240399021978 31.8001411575539024, 223.5195254158730336 31.8305755441254412, 223.5239434375728536 31.8609408592237848, 223.5282886785425660 31.8913087443299545, 223.5322519417814817 31.9216868481073490, 223.5347617094650161 31.9521016880502948, 223.5380353071365676 31.9824836883298858, 223.5428282744416038 32.0128133802927906, 223.5480508269973257 32.0431332223139407, 223.5497441169928550 32.0735409979197428, 223.5553057805198591 32.1038539700979157, 223.5598384268915879 32.1341930833302882, 223.5624288052136706 32.1645807931653849, 223.5652337763135336 32.1949638621966159, 223.5678286491805409 32.2253527383586302, 223.5695560421614800 32.2557635381356320, 223.5752088570122851 32.2860971657264244, 223.5778937031911653 32.3165239135804541, 223.5812675754776535 32.3469343759028192, 223.5848566390171470 32.3773401797631806, 223.5891675861419685 32.4077288949641087, 223.5927666200163060 32.4381356809368810, 223.5971664748506100 32.4685234267514531, 223.6018897195696979 32.4989038349818813, 223.6036667979318509 32.5293570671523327, 223.6064949113190323 32.5597850851598665, 223.6116324578511296 32.5901446221567141, 223.6140456300912831 32.6205582901842064, 223.6180710912757377 32.6509330397430162, 223.6211992807537570 32.6813302884016323, 223.6282270303815096 32.7116327515463041, 223.6317729060839383 32.7420209117890408, 223.6357729384005211 32.7723985010423533, 223.6368325295955231 32.8028483885533575, 223.6411096372302154 32.8332202357844309, 223.6439910882512550 32.8636266157740948, 223.6481310196402319 32.8940028180075927, 223.6509936165835200 32.9244106062468376, 223.6553899144587376 32.9547815457483892, 223.6596968044630103 32.9851551443478925, 223.6612145716325131 33.0155969876130797, 223.6650693764509015 33.0459824802825963, 223.6692659410257420 33.0763601295090908, 223.6716695759030529 33.1067817006912222, 223.6751523009949381 33.1371775152148800, 223.6790842135375783 33.1675628699203884, 223.6817299555439718 33.1979800537635299, 223.6840029478613872 33.2284069153912540, 223.6869551522037796 33.2588177147742314, 223.6903565456991032 33.2892180315189918, 223.6936834073373461 33.3196205104331185, 223.6971029051111373 33.3500211101661606, 223.7007701587775159 33.3804160898463422, 223.7044837207658361 33.4108103025735730, 223.7075120344809989 33.4412213366104680, 223.7108808174928640 33.4716244980177109, 223.7150218025271045 33.5020111064701567, 223.7185127414146848 33.5324154288194762, 223.7220915424775853 33.5628179459110427, 223.7256487173764015 33.5932212767874603, 223.7286216237151564 33.6236389014538517, 223.7320216441544289 33.6540465565227436, 223.7369843539350995 33.6844170564061542, 223.7396632577163587 33.7148425179124871, 223.7417605710628266 33.7452821085100041, 223.7453063421751835 33.7756872890390909, 223.7483122062117786 33.8061098599434615, 223.7517120548250489 33.8365277390942296, 223.7558255243959024 33.8669288054322521, 223.7594854651726166 33.8973409053826700, 223.7624929837646164 33.9277687625072559, 223.7659937331654874 33.9581850449847380, 223.7683016723167668 33.9886299136110850, 223.7717654102991389 34.0190474190815451, 223.7746851069329352 34.0494780281038132, 223.7778200650627412 34.0799036631504322, 223.7815767484544267 34.1103144299491063, 223.7849598454090767 34.1407339700314196, 223.7886890995187343 34.1711454270436050, 223.7929755563749268 34.2015437889649405, 223.7950123859445171 34.2319956603030846, 223.7976542511609637 34.2624332579386390, 223.8008059637030556 34.2928588583746645, 223.8038189436577738 34.3232878313987229, 223.8070197678133582 34.3537124337935751, 223.8102919260756209 34.3841354219903863, 223.8132599670128400 34.4145658934247152, 223.8172826871150392 34.4551387031975906))) +MULTIPOLYGON (((225.6590116069496332 15.2022751783289749, 225.8184285323443135 15.1938011439423235, 225.9815607790280581 15.1849941024038380, 226.1537479984186234 15.1755636256977411, 226.3305987103622101 15.1657156109381503, 226.5161948594225123 15.1552163684519368, 226.7132602792806040 15.1438893480044516, 226.9261988968144408 15.1314506128323636, 227.1499418817269316 15.1181384850929099, 227.3887605673780286 15.1036654664102183, 227.6457676408483621 15.0877902095771024, 227.9238726255883307 15.0702639427477045, 228.2357698250011140 15.0502006377175022, 228.5715407542897708 15.0280865134360671, 228.9475901302254215 15.0027161004160057, 229.3712716350795233 14.9733679202844066, 229.9511930054955826 14.9320537004547287, 230.4883212844398770 14.8922542022366784, 231.1136532006034088 14.8443022655274142, 231.8633228538656681 14.7845460925961838, 232.7891574036120517 14.7073522926485882, 233.9942664766833786 14.6013042632958854, 234.4965294635921680 14.5504706068641187, 234.5208110646848638 14.5099689963999161, 234.5313044307453652 14.4803171726285242, 234.5416131320472743 14.4506850419997708, 234.5520779986402147 14.4210415871861439, 234.5623431792820952 14.3914232576745800, 234.5724238854104442 14.3618286537537010, 234.5827882798384678 14.3322149028797057, 234.5929578122126600 14.3026258490534754, 234.6030683516360682 14.2730490548120876, 234.6134058759765253 14.2434583660659655, 234.6236678296300795 14.2138814838690237, 234.6339787547713343 14.1843070300948444, 234.6442862293286566 14.1547369881042862, 234.6547188872675065 14.1251597337691344, 234.6648922784237072 14.0956130660573216, 234.6753260770241241 14.0660495237721683, 234.6864368122618316 14.0364311268668658, 234.6957686613596934 14.0069820249208483, 234.7061404545204937 13.9774449563442484, 234.7168562114414385 13.9478834922368211, 234.7270224985275888 13.9183791088051372, 234.7372049000421725 13.8888802353741898, 234.7477636681231274 13.8593540756665892, 234.7584817070679151 13.8298204457635237, 234.7691873592963532 13.8002949952320169, 234.7803650561162385 13.7707336570441434, 234.7916750869490841 13.7411673887640564, 234.8029058073712747 13.7116154578260421, 234.8142170613676001 13.6820633421945015, 234.8253048393833069 13.6525386876241441, 234.8363381022113003 13.6230261368713048, 234.8474859602987124 13.5935103447128149, 234.8586521624573891 13.5639727106138768, 234.8698086928625059 13.5344171572959713, 234.8810402769611301 13.5048618787067021, 234.8921633393982233 13.4753235400046201, 234.9036036689824414 13.4457635459991671, 234.9148787490042878 13.4162256652156433, 234.9262976252631177 13.3866818978301705, 234.9378525867176108 13.3571329688567086, 234.9491438212119476 13.3276151021412534, 234.9605851744020129 13.2980908307225132, 234.9714051180906438 13.2686329664536888, 234.9829107519212243 13.2391230512865921, 234.9953247717635634 13.2095381987899341, 235.0050945474888522 13.1801996368848702, 235.0136741458930487 13.1509757165580634, 235.0235876206720604 13.1216383626052853, 235.0329511600260446 13.0923577947184526, 235.0428529677785718 13.0630357719613439, 235.0521842664741428 13.0337723689987097, 235.0625643588351181 13.0044215486467589, 235.0718456772173113 12.9752026575957213, 235.0824545385907243 12.9458957826393526, 235.0941279050537958 12.9165005023643378, 235.1065853385751154 12.8870421853161687, 235.1158685220012785 12.8578770133932370, 235.1267432526933021 12.8285761001416407, 235.1379548447789034 12.7992524167666950, 235.1493796196099879 12.7699171278070818, 235.1597708594709673 12.7406822110508919, 235.1712990020443783 12.7113527639371746, 235.1827906327161770 12.6820275614660449, 235.1941656397088991 12.6527141313651210, 235.2050650316088536 12.6234509250417926, 235.2163653281609186 12.5941593717566178, 235.2278129170846341 12.5648622451838943, 235.2385899997154013 12.5356327692369511, 235.2509196540145524 12.5062719958082358, 235.2633495965479824 12.4769099909586600, 235.2728707658307599 12.4478157345661558, 235.2843018917575648 12.4185583775542057, 235.2958612625120054 12.3892706549166327, 235.3093903396573410 12.3597895149907959, 235.3187948289964879 12.3306840979702574, 235.3306973306444547 12.3013633116314818, 235.3409552429090468 12.2721967440650062, 235.3501958582132545 12.2431283055929345, 235.3613910465265349 12.2138932348155915, 235.3730447120910583 12.1846249560596309, 235.3841076199099689 12.1554168856462663, 235.3951457458792333 12.1262186344057685, 235.4062396928094358 12.0970204530032373, 235.4175034832148583 12.0678123994039375, 235.4293245046916638 12.0385625703327914, 235.4421181448695393 12.0092341708445201, 235.4552959275237072 11.9798795411541885, 235.4690679159375577 11.9504801025218139, 235.4834853055173198 11.9210313919657640, 235.4960974303484704 11.8917506965023225, 235.5075487338667983 11.8625807322285564, 235.5232045968097907 11.8330462747878666, 235.5346764932195072 11.8038936248651414, 235.5484769106767544 11.7745459193969246, 235.5600500493502807 11.7454032068121563, 235.5703027540562857 11.7163850531242257, 235.5839099153991469 11.6870783107510565, 235.5954261045663145 11.6579642552422929, 235.6091634787426301 11.6286620492642268, 235.6216120133803429 11.5994816340682760, 235.6324251517819164 11.5704534114981232, 235.6427681561548582 11.5414744764065418, 235.6568231610475834 11.5121696293317068, 235.6720114139477857 11.4827667117950689, 235.6855534379756421 11.4535169164333990, 235.6985976231398183 11.4243190426501098, 235.7101697742900228 11.3952586967795071, 235.7212865678495746 11.3662463476185298, 235.7336848211043900 11.3371294098914515, 235.7467824960610017 11.3079591641971682, 235.7608802893133486 11.2787093286269826, 235.7716222749621409 11.2497620499263871, 235.7842032101285952 11.2206891920285248, 235.7973313754250455 11.1916028404892263, 235.8104867447666777 11.1625225099717724, 235.8248992522797494 11.1333405976365700, 235.8395596186489911 11.1041455609057547, 235.8525266395528206 11.0751071281384803, 235.8667638349001834 11.0459661778940248, 235.8799840524185640 11.0169226049989497, 235.8933575463182422 10.9878741537508979, 235.9056857922374775 10.9589253856053972, 235.9193690857431704 10.9298457604650068, 235.9332202571240487 10.9007399237311553, 235.9474135600927411 10.8716127613943527, 235.9606689831901747 10.8425757207505278, 235.9745891351899729 10.8134893032700230, 235.9749642465170609 10.7716809281293759, 234.3062264801270658 10.9140277809828401, 233.0568672341269121 11.0146280042264575, 232.0879579900154397 11.0891193380045809, 231.2922763752998208 11.1479476253113834, 230.6222024977055014 11.1958368476763042, 230.0451126661348269 11.2358585089428757, 229.5399124326949050 11.2699591633166492, 229.0910977852282429 11.2995144425355125, 228.6886580791903896 11.3254217054488961, 228.3230615139326005 11.3484629748935983, 227.9885578563494164 11.3691297953498367, 227.6794424865365158 11.3878696987456021, 227.3925662525238351 11.4049521734721111, 227.1244248889431105 11.4206460692871250, 226.8725374557916155 11.4351462062953271, 226.6348499723014811 11.4486118924986169, 226.4089327375779703 11.4612113075504123, 226.1941018513796280 11.4730141135587900, 225.9885536989872605 11.4841415383638772, 225.7906841315520694 11.4946974768609138, 225.5999034371537562 11.5047316362784287, 225.5366590428417908 11.5127499139888521, 225.5372155286848397 11.5505123386366488, 225.5385771173884848 11.5787917807460410, 225.5399422790718234 11.6070769022026852, 225.5412964706883940 11.6353683683310756, 225.5426724692766527 11.6636646542834583, 225.5440051181544163 11.6919712226479628, 225.5452754778118276 11.7202890826971338, 225.5466283640503775 11.7486089150272832, 225.5479733512454459 11.7769349110044050, 225.5492620733159299 11.8052693182738349, 225.5505841235170692 11.8336079602086279, 225.5519462019779553 11.8619505139368027, 225.5533034115049986 11.8902990653406153, 225.5546573358129194 11.9186535320087330, 225.5560296402161100 11.9470128980119092, 225.5574630380900487 11.9753825153473716, 225.5590145866423484 12.0037600937641198, 225.5604603602986913 12.0321483085325323, 225.5618766106682358 12.0605435905751133, 225.5632235047208098 12.0889478001897945, 225.5646322493352045 12.1173547928037380, 225.5660183352506749 12.1457685136780800, 225.5674524001674399 12.1741856512172308, 225.5688591210818288 12.2026097227853292, 225.5703066481627843 12.2310375313070310, 225.5717059626913112 12.2594635288136420, 225.5731135143499273 12.2878845470445004, 225.5745000481469731 12.3163122246356878, 225.5759250962974249 12.3447437586129958, 225.5773925000398208 12.3731789608754816, 225.5788485202704692 12.4016203466559691, 225.5803384551418844 12.4300657783575321, 225.5816851397536311 12.4585235860499672, 225.5830893138132183 12.4869843197081938, 225.5845898506858873 12.5154461392763974, 225.5860380817925375 12.5439157418262273, 225.5874589811405428 12.5723919343366166, 225.5889159824166654 12.6008720349108785, 225.5903500435784110 12.6293588188961490, 225.5917512821488060 12.6578527498482263, 225.5931498471001078 12.6863523976596984, 225.5945936513341508 12.7148554898354504, 225.5960004210751038 12.7433659093484160, 225.5974035729581715 12.7718820686378116, 225.5988234674924229 12.8004029994655610, 225.6002725684679433 12.8289353399234827, 225.6017372708080018 12.8574801027486334, 225.6031663910407872 12.8860320508820667, 225.6045230144762570 12.9145929258961942, 225.6058813440074289 12.9431592084249925, 225.6072542187562817 12.9717302816559918, 225.6086155629616314 13.0003073736031514, 225.6099855932373544 13.0288895208782218, 225.6113301416302193 13.0574783351150430, 225.6125573734466627 13.0860781700991904, 225.6138059182740392 13.1146685839299817, 225.6150812752645152 13.1432485814377760, 225.6162458523031660 13.1718393538115368, 225.6173776526709105 13.2004371913496481, 225.6185740513896576 13.2290374594585156, 225.6198200703518353 13.2576408581347014, 225.6210454855481373 13.2862507194559658, 225.6223709722382864 13.3148612910132691, 225.6236531537022643 13.3434793903344762, 225.6249325727087012 13.3721030822070848, 225.6260928571377633 13.4007285592951106, 225.6271536838081886 13.4293543933417254, 225.6282124976070804 13.4579858253871780, 225.6292645318286247 13.4866230741567108, 225.6301804110024136 13.5152723247030888, 225.6310913327383219 13.5439273006293899, 225.6319395690546230 13.5725907592594286, 225.6327541321401782 13.6012613103884163, 225.6337718653989839 13.6299275880244135, 225.6347506835452634 13.6586011868333443, 225.6357740728154511 13.6872915147215632, 225.6369158385559786 13.7159957105510788, 225.6377194034149625 13.7447214980022157, 225.6381065140526232 13.7734726407128552, 225.6384486639109923 13.8022312917939587, 225.6384696576625970 13.8310107210332234, 225.6377164798742854 13.8598327078059746, 225.6365675116648504 13.8886790654790975, 225.6366436894022058 13.9174718433797455, 225.6368569809392284 13.9462633391875563, 225.6372512897805791 13.9750446864033755, 225.6375598963244613 14.0038283679673583, 225.6379232733982292 14.0326147568883712, 225.6383897348957248 14.0614015137205151, 225.6384870234559514 14.0902113786118672, 225.6385225422024234 14.1190295456736390, 225.6386422679394741 14.1478489719565079, 225.6388548750343546 14.1766692296997032, 225.6393899649038417 14.2054792308434106, 225.6400017794549910 14.2342908121572211, 225.6406354383889550 14.2631066559514661, 225.6413569023304149 14.2919235679286665, 225.6418737902540670 14.3207556085893160, 225.6423091419993341 14.3495968330276007, 225.6427227616953246 14.3784443489976486, 225.6431399564071967 14.4072969250615799, 225.6435643096251908 14.4361543786609037, 225.6439996407971762 14.4650165188792776, 225.6444242559419422 14.4938843843585552, 225.6447387707936514 14.5227627777236634, 225.6449631354863357 14.5516507314802457, 225.6451722615322808 14.5805446135894456, 225.6453957584195393 14.6094429813533875, 225.6457542902550415 14.6383399812061086, 225.6462420944643554 14.6672358819702477, 225.6469402658949832 14.6961267418030221, 225.6476430847723407 14.7250225126985868, 225.6482912667314622 14.7539260619938783, 225.6489832272112039 14.7828326105555625, 225.6497656773054530 14.8117398863536138, 225.6506424448378993 14.8406387380365601, 225.6513629143920809 14.8695408563681148, 225.6517777326999976 14.8984629716291774, 225.6521804911266145 14.9273908339482322, 225.6524924024801919 14.9563282656240322, 225.6529946847831525 14.9852615952319770, 225.6535087795084848 15.0141994841802013, 225.6541740536502800 15.0431351473047741, 225.6549119930294864 15.0720723861003538, 225.6554983623736916 15.1010221056688980, 225.6560601550888236 15.1299724949437415, 225.6566877998535006 15.1589188522188678, 225.6590116069496332 15.2022751783289749))) +MULTIPOLYGON (((222.1624644987274735 22.8951608777580375, 222.3339278053788917 22.8936291251068376, 222.4918214736053699 22.8892887249650485, 222.6447347625685325 22.8849225119194131, 222.7860232523261459 22.8807537878477198, 222.9282491755332387 22.8764117841961223, 223.0766244984883997 22.8717204867395267, 223.2163755016804316 22.8671671508905092, 223.3566763952527197 22.8624540094745328, 223.4933003438143828 22.8577319701406125, 223.5898184186347919 22.8543578551823892, 223.6952462098461751 22.8505806049225235, 223.7986314112467028 22.8468004170732009, 223.8996071437578905 22.8430363020301144, 223.9985409791676716 22.8392789939742009, 224.0959564206523567 22.8355116832603002, 224.1910355953645535 22.8317716010045579, 224.2846905331828111 22.8280253856162325, 224.3794591431511947 22.8241662737757345, 224.4717633563003290 22.8203486474569281, 224.5633375180167945 22.8165001435605177, 224.6543476105572950 22.8126140287647665, 224.7440401314307223 22.8087272358785960, 224.8325041708576180 22.8048422967121454, 224.9212556591380121 22.8008911952094380, 225.0106581698819639 22.7968452217387672, 225.1000007997450894 22.7927430514162239, 225.1888277899554112 22.7886040404598802, 225.2781779860745246 22.7843853506296270, 225.3686923868900180 22.7800551111920484, 225.4590163590499117 22.7756725362798349, 225.5508196988342036 22.7711599176716817, 225.6422475001399732 22.7666030803204116, 225.7360430349097840 22.7618690699529438, 225.8308944078747231 22.7570178540152632, 225.9265645398245965 22.7520593285219199, 226.0249049679516702 22.7468968897921613, 226.1249454787357820 22.7415751880217485, 226.2278086014960081 22.7360312021479380, 226.3331090916695700 22.7302792145955159, 226.4411376184042979 22.7242978236477953, 226.5516842588731947 22.7180922187040188, 226.6656163592838027 22.7116078269275548, 226.7845301475277040 22.7047457110851525, 226.9071475647060652 22.6975670622629160, 227.0314410381330958 22.6901810097109546, 227.1839792061291519 22.6810029065164471, 227.3309878641200044 22.6719940161947768, 227.4852574295117620 22.6623834901635632, 227.6478981924011009 22.6520789917443750, 227.8244753454561931 22.6406976406627756, 228.0131819147138117 22.6283077429488948, 228.2162925671777600 22.6147123262701619, 228.4292029370038222 22.6001656945547893, 228.6562565744310689 22.5843249430069939, 228.9060279700422313 22.5665175965706943, 229.1825161009347198 22.5463403909257636, 229.4889073172393807 22.5234095912130243, 229.8235975093082004 22.4976688769848394, 230.1950353288360134 22.4682622757394483, 230.6140350096124507 22.4340362401953612, 231.0891086673919972 22.3938791164045092, 231.6395866999296516 22.3455627543664406, 232.2933600726683778 22.2857009542201325, 233.0468719137620894 22.2096336011567779, 233.0786160066152775 21.8362790739403536, 233.1128703123239063 21.4745535126135110, 233.1496154959708065 21.1131520454980688, 233.1847240762937474 20.7523849750790745, 233.2282694103726897 20.3912575382923755, 233.2729399482162762 20.0308241593812788, 233.3250709696296212 19.6705333692991715, 233.3796821892690616 19.3110185897310593, 233.4385722857594772 18.9512397884658697, 233.5048315557592673 18.5912746804501623, 233.5705679159131591 18.2318918457248778, 233.6451980362392078 17.8721782134589731, 233.7217275110074581 17.5133469216565452, 233.8008596205570200 17.1546858578559593, 233.8864271817588190 16.7969322128414085, 233.9697189397047907 16.4397036867894251, 234.0828109354990261 16.0803141029572600, 234.1849920610645768 15.7230496510930529, 234.2920854378215267 15.3662472679597375, 234.4024907295219009 15.0099336757912152, 234.5149128961783731 14.6540024088048977, 234.6379311558054326 14.2984584661645968, 234.7623775583252552 13.9436811557223272, 234.8942578962761161 13.5892102040072000, 235.0288272444620077 13.2349149253326068, 235.1521051686026453 12.8828891505364300, 235.2867725908210446 12.5312613936619748, 235.4233087213997351 12.1800902646282907, 235.5708596309736720 11.8287640873522850, 235.7235065836390788 11.4781679472845699, 235.8797318095176365 11.1284757052386034, 236.0525313246200767 10.7671682736336187, 234.5539738435579977 10.8934756929011449, 233.4407131631540437 10.9842712723620792, 232.5469229652692320 11.0542229776525041, 231.8057772059855211 11.1102241836924787, 231.1727759778447648 11.1565989554036538, 230.6222024977055014 11.1958368476763042, 230.1360978921009064 11.2296246903372410, 229.7011060076232241 11.2591734075795618, 229.3092627460602273 11.2852352682303039, 228.9523786369067579 11.3085085479184464, 228.6255699416132074 11.3294320811176288, 228.3230615139326005 11.3484629748935983, 228.0424929933024316 11.3658248267828181, 227.7797848238557492 11.3818240807616586, 227.5335303503333364 11.3965959501440786, 227.3013618133060163 11.4103203927983330, 227.0813921445946733 11.4231400422550955, 226.8725374557916155 11.4351462062953271, 226.6735784057245553 11.4464323336035516, 226.4830830479990880 11.4570977194971331, 226.3002739486517783 11.4672030229445188, 226.1246140672760987 11.4767939954951359, 225.9550662527171312 11.4859387811404918, 225.7906841315520694 11.4946974768609138, 225.6312478555481391 11.5030927722805156, 225.4762447625165578 11.5111601660590104, 225.3250842761335662 11.5189369296463209, 225.1774439551033993 11.5264465188925040, 225.0328448253008276 11.5337180770388592, 224.8908763596499512 11.5407761760390457, 224.7513584997170994 11.5476346729869821, 224.6139594562444017 11.5543129777216969, 224.4784375362928017 11.5608260941168410, 224.3444652819518979 11.5671914448567392, 224.2117774258872487 11.5734232007998141, 224.0801718772115123 11.5795330298151136, 223.9493664901772547 11.5855344996028045, 223.8191624724303210 11.5914391819364901, 223.6892422590755416 11.5972592901638460, 223.5594084415188831 11.6030053638418362, 223.4294005333658788 11.6086896685846472, 223.2989722102153110 11.6143216904895947, 223.1678913125293775 11.6199107220579378, 223.0358968024123385 11.6254674694606805, 222.9027074603666563 11.6310028546020856, 222.7681514532171434 11.6365211164074118, 222.6319141538511417 11.6420339437191078, 222.4937638625381169 11.6475477129753546, 222.3535187113670872 11.6530658977330486, 222.2106332312147856 11.6586083764684449, 222.0649326370145218 11.6641761438978122, 221.9159984711472191 11.6697805626173459, 221.7637180402759896 11.6754184975323128, 221.6071946734359415 11.6811193203433437, 221.4462705120650412 11.6868790352438801, 221.2800176036296591 11.6927238980806685, 221.1082343240083787 11.6986486654978012, 220.9302181846820758 11.7046664471111175, 220.7448115762650502 11.7108046009619358, 220.5512576667551059 11.7170716871887297, 220.3489604038603034 11.7234675876106191, 220.1364090861307830 11.7300207161664911, 219.9120955538539874 11.7367529071657000, 219.6885215783223657 11.7467999825142257, 219.7800022085925491 12.0939667193907923, 219.8674454815513286 12.4316594207246638, 219.9609663350123014 12.7696974747126752, 220.0435221787505213 13.1088831469933211, 220.1287352849993226 13.4489940064017972, 220.2143098341883558 13.7895853682338103, 220.2996432291302824 14.1309982530505547, 220.3856337208090963 14.4729600249569028, 220.4702124060514450 14.8160664519636125, 220.5542495225764128 15.1598074722681364, 220.6372147494944045 15.5039964430272246, 220.7215739629969562 15.8490768265738264, 220.8003749786528260 16.1950206147845002, 220.8780366528559398 16.5414260978017715, 220.9576980259738264 16.8886184325720556, 221.0492649287550080 17.2360440209217529, 221.2038686914070240 17.5820804815569822, 221.2332821021322786 17.9327909628593183, 221.3064374132812020 18.2825671410777524, 221.3767990322102150 18.6330869316894123, 221.4437786009013962 18.9842653900625713, 221.5157897916339209 19.3357555188309327, 221.6415036192033199 19.6862868958747796, 221.7040268217931498 20.0392648175583936, 221.7734189145131722 20.3928463603017818, 221.8288535880878953 20.7473064170266852, 221.8917645081734804 21.1019045712286442, 221.9100285267250285 21.4581261494620072, 221.9689664639684850 21.8138417552296744, 222.0351237485043043 22.1699280426223453, 222.0994527851256350 22.5263997499335709, 222.1624644987274735 22.8951608777580375))) diff --git a/isis/src/base/objs/ImagePolygon/ImagePolygon_Linux_i686_RedHat5_5.truth b/isis/src/base/objs/ImagePolygon/ImagePolygon_Linux_i686_RedHat5_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..4b1ab6e109a9c48ae4fe4ba6458b3f98608f49a1 --- /dev/null +++ b/isis/src/base/objs/ImagePolygon/ImagePolygon_Linux_i686_RedHat5_5.truth @@ -0,0 +1,3 @@ +MULTIPOLYGON (((223.8172826871150392 34.4551387031975906, 223.8417027794513672 34.4596506067936588, 223.8575436553770714 34.4592772203974533, 223.8731987948544884 34.4589061404385077, 223.8888001596040453 34.4585342459693109, 223.9044019981608358 34.4581602383999694, 223.9200661672346939 34.4577826050169165, 223.9355075425064001 34.4574083329785168, 223.9508457646854538 34.4570345512927645, 223.9660146266744221 34.4566629442804810, 223.9810473117178447 34.4562927477356951, 223.9957878474442339 34.4559279257479716, 224.0106582442915908 34.4555579477815925, 224.0255459277288139 34.4551856182047374, 224.0403444766605787 34.4548136400302099, 224.0550707903117598 34.4544416141928949, 224.0696826279009031 34.4540706529749698, 224.0842130300090105 34.4536999452778474, 224.0986612451643509 34.4533295403593272, 224.1130364690419867 34.4529592284912880, 224.1273202300474452 34.4525895195669563, 224.1415662443576764 34.4522190341699357, 224.1557339919143885 34.4518488560984437, 224.1698107919081906 34.4514793495923044, 224.1838116921205994 34.4511101459255826, 224.1977227035095268 34.4507416461034310, 224.2115924901995356 34.4503725739912667, 224.2254006441162915 34.4500034948312930, 224.2391929104846611 34.4496331906106832, 224.2529511041628325 34.4492621619975878, 224.2666975063020232 34.4488898122485239, 224.2803860066288735 34.4485174108845698, 224.2940079847741686 34.4481452154172487, 224.3075938799341031 34.4477724067580056, 224.3210795842228720 34.4474007778023150, 224.3344990942869401 34.4470294145163933, 224.3478450165269180 34.4466585462406627, 224.3611125162273083 34.4462883335280097, 224.3742955932710856 34.4459189717640371, 224.3874260849736970 34.4455495873438409, 224.4004958876452633 34.4451804280896852, 224.4135260618628820 34.4448109131363154, 224.4264828609272513 34.4444420220934973, 224.4393721009315072 34.4440736116739146, 224.4522012233351234 34.4437054891116503, 224.4649910969210680 34.4433370696326904, 224.4777393619959582 34.4429684346240776, 224.4904489206706444 34.4425995129701761, 224.5030718093741484 34.4422317209555473, 224.5156259769345866 34.4418645588172865, 224.5281770922377120 34.4414961128652166, 224.5407219882790457 34.4411264781702400, 224.5531975742957229 34.4407575294710284, 224.5656264625203562 34.4403886151251726, 224.5780227095267492 34.4400193298509762, 224.5903757297269578 34.4396500014264859, 224.6026728254565228 34.4392810254014137, 224.6148668913573658 34.4389138408317379, 224.6269709754118651 34.4385480839034486, 224.6390599334609988 34.4381815077720930, 224.6511372140055300 34.4378140122935079, 224.6632067785473623 34.4374454802786261, 224.6751614662134671 34.4370792015270695, 224.6870933910036001 34.4367123757492308, 224.6989898632979532 34.4363454017714901, 224.7108678965891500 34.4359777635831534, 224.7226881484133685 34.4356106890301774, 224.7344958302966518 34.4352427866590816, 224.7462652761780646 34.4348748627154819, 224.7579793002597626 34.4345074674088423, 224.7696431367716627 34.4341404524924286, 224.7812728008222791 34.4337733276717159, 224.7928435544382069 34.4334068856012721, 224.8043847867617160 34.4330402110380760, 224.8157283420019041 34.4326786628983683, 224.8270886233244994 34.4323154552239430, 224.8384166745837831 34.4319521504694563, 224.8497524406973866 34.4315874761224663, 224.8610108250487087 34.4312241691771774, 224.8722867697455854 34.4308591872096557, 224.8835699922446452 34.4304928587168035, 224.8948651191569468 34.4301250320693342, 224.9061662756241446 34.4297558957457994, 224.9173542817119369 34.4293893382984280, 224.9284086365550763 34.4290260617306529, 224.9394220908251327 34.4286630587300806, 224.9504388177020076 34.4282988872681628, 224.9614347391653268 34.4279343413389043, 224.9724090215663352 34.4275694545411639, 224.9833614192173457 34.4272042412541666, 224.9942931925034486 34.4268386658471499, 225.0052127358298151 34.4264724543783416, 225.0161268911886054 34.4261053818628895, 225.0270072241944490 34.4257384032388458, 225.0379099783205277 34.4253696379527341, 225.0487812549144735 34.4250008965078678, 225.0595876459501312 34.4246333159996070, 225.0703030757329941 34.4242677966519963, 225.0809691074227601 34.4239029513888539, 225.0916138570161706 34.4235378365167506, 225.1022391576242683 34.4231723954175806, 225.1128542317605081 34.4228063181412836, 225.1234516168084951 34.4224398636277300, 225.1340217162214401 34.4220733666453924, 225.1445720849020802 34.4217065743085584, 225.1551012336424549 34.4213395435047218, 225.1655864786240500 34.4209730652326300, 225.1760248993977882 34.4206072522224815, 225.1864409930356885 34.4202412645735265, 225.1968389824973826 34.4198749610789960, 225.2072200098365897 34.4195083067898224, 225.2175785697437789 34.4191414991763835, 225.2279161215742533 34.4187744930007398, 225.2382328071402071 34.4184072888908830, 225.2485261486005186 34.4180399797886807, 225.2587970263030854 34.4176725407227835, 225.2690410352727781 34.4173051336376261, 225.2792535965569698 34.4169379280283323, 225.2894249396388773 34.4165712795181022, 225.2995612324063188 34.4162049784147968, 225.3096797795645614 34.4158384150564345, 225.3197769941544948 34.4154717225693290, 225.3298508715459150 34.4151049783840435, 225.3399032250165703 34.4147381232054812, 225.3499338576864091 34.4143711696130268, 225.3599442461522528 34.4140040697767873, 225.3699387631642708 34.4136366705630508, 225.3799126564848052 34.4132691484824491, 225.3898592055926997 34.4129017530111838, 225.3997746327333687 34.4125346284357292, 225.4096413759963013 34.4121684232215301, 225.4194664480812378 34.4118028922520267, 225.4292333251142963 34.4114386507455166, 225.4389847119527985 34.4110741439216028, 225.4487227950831709 34.4107092951739943, 225.4584529700733810 34.4103439089537062, 225.4681791118518390 34.4099778443088908, 225.4779501834676410 34.4096092906042443, 225.4877658689587179 34.4092382503042771, 225.4975606254193394 34.4088671492795868, 225.5073160520850308 34.4084966775202332, 225.5170945589782434 34.4081245164470388, 225.5268331233909009 34.4077530165447669, 225.5365021994340680 34.4073832929153340, 225.5461190551428672 34.4070147130339521, 225.5556995065214494 34.4066466939793116, 225.5652214497965247 34.4062800757604279, 225.5747432098701211 34.4059126713390597, 225.5842560908804444 34.4055448096861980, 225.5937778006389749 34.4051758228821214, 225.6033009158175560 34.4048059910247375, 225.6128238278627123 34.4044353753846437, 225.6223471750505212 34.4040639521956990, 225.6318758783661451 34.4036915343189733, 225.6414016415949959 34.4033184379288883, 225.6509363628299241 34.4029442091229640, 225.6604947562338452 34.4025682830337516, 225.6700415057191833 34.4021920107971724, 225.6795791566906360 34.4018152974535525, 225.6890709331013625 34.4014395612861392, 225.6985268751064666 34.4010644244605501, 225.7079299362157485 34.4006905527387730, 225.7172925181210417 34.4003174767084232, 225.7266351872429198 34.3999444074105725, 225.7359624913471805 34.3995711724671480, 225.7452560214498760 34.3991984906232560, 225.7545267975936838 34.3988259393811830, 225.7637889836569514 34.3984529710283411, 225.7730507645297848 34.3980792679652438, 225.7823252012858291 34.3977043200822976, 225.7916004169256610 34.3973285907622284, 225.8008725343179037 34.3969522324371084, 225.8101369195402413 34.3965754281377940, 225.8193892452067359 34.3961983498649957, 225.8286274988710716 34.3958210793992976, 225.8378496687873564 34.3954436988933523, 225.8470551995822007 34.3950662333900752, 225.8562326011218033 34.3946891401953891, 225.8653930029271351 34.3943119836700717, 225.8745410760951984 34.3939345817962447, 225.8836776373707664 34.3935569045111080, 225.8928019411298180 34.3931789836151580, 225.9019194640990804 34.3928006036003566, 225.9110308752194385 34.3924217393303877, 225.9201549499825887 34.3920416440390966, 225.9292743320634145 34.3916610091261106, 225.9383845714752397 34.3912800135874335, 225.9474795314372670 34.3908989045497577, 225.9565581779545482 34.3905177258943411, 225.9656244992629581 34.3901363204726565, 225.9746802477716869 34.3897546201018542, 225.9837284337634173 34.3893725058620632, 225.9927658600073812 34.3889901075809234, 226.0017891753243475 34.3886075616179951, 226.0108161763200769 34.3882241546364895, 226.0198457173729878 34.3878399332780305, 226.0288659305028887 34.3874553758755184, 226.0378750537552150 34.3870705549601965, 226.0468586590255313 34.3866860532718803, 226.0558323075141232 34.3863012460278199, 226.0647969809214999 34.3859160949781852, 226.0737494779376391 34.3855307303640743, 226.0826909505379092 34.3851451069165961, 226.0916392243478583 34.3847585070685895, 226.1005846294034143 34.3843713216575466, 226.1095237944622625 34.3839836876697547, 226.1184552396350682 34.3835956657888744, 226.1273766599998396 34.3832073497904531, 226.1362843513835799 34.3828188894718991, 226.1451789838510820 34.3824302581018841, 226.1540696341334922 34.3820410909009055, 226.1629557016597687 34.3816514127115553, 226.1718415645642324 34.3812610486584163, 226.1807230054595550 34.3808701689397935, 226.1896010103831145 34.3804787348665357, 226.1984731024826090 34.3800868461449554, 226.2073393250205413 34.3796945013437423, 226.2162010894513458 34.3793016446030393, 226.2250584402896720 34.3789082746488859, 226.2339210610192026 34.3785140100478799, 226.2427791039953604 34.3781192424446971, 226.2516314343407373 34.3777240170122553, 226.2604782195461155 34.3773283273222461, 226.2693193564175260 34.3769321773464114, 226.2781549132864427 34.3765355641091688, 226.2869854330468797 34.3761384662781353, 226.2958114626269435 34.3757408626804448, 226.3046334835790958 34.3753427350574086, 226.3134536502247158 34.3749440039339902, 226.3222666039636977 34.3745448676996475, 226.3310674201009078 34.3741454966233277, 226.3398662973834803 34.3737455141035966, 226.3486632146753266 34.3733449208397204, 226.3574580470481123 34.3729437207094293, 226.3662507195254250 34.3725419150449554, 226.3750416931369216 34.3721394879113191, 226.3838307521617708 34.3717364447303808, 226.3926183115110291 34.3713327722454522, 226.4014042158854068 34.3709284730591946, 226.4101886820694745 34.3705235398177749, 226.4189713667430510 34.3701179689839478, 226.4277528949876341 34.3697117361028148, 226.4365339441959577 34.3693048462083510, 226.4453141371926108 34.3688973010714705, 226.4540932758116867 34.3684891263368613, 226.4628714412468469 34.3680802910519034, 226.4716492125849641 34.3676707556087422, 226.4804266127524670 34.3672605341961770, 226.4892039200687748 34.3668496115516149, 226.4979812270960053 34.3664379861530804, 226.5067586403114319 34.3660256540135123, 226.5155350783857955 34.3656126842405598, 226.5243113274227085 34.3651990255176401, 226.5330863836839796 34.3647847379392459, 226.5418613931262257 34.3643697522112461, 226.5506364357621862 34.3639540649148643, 226.5594125115546262 34.3635376202989562, 226.5681899791689489 34.3631204006612592, 226.5769703953577334 34.3627023215986753, 226.5857530174846772 34.3622834277597846, 226.5945393457434420 34.3618636386090444, 226.6033280976995172 34.3614430268793072, 226.6121204829106546 34.3610215278312623, 226.6209149844756610 34.3605992250073129, 226.6297112468491548 34.3601761376944168, 226.6385086581317410 34.3597522985732198, 226.6473076485042952 34.3593276841362254, 226.6561088518948566 34.3589022602962544, 226.6649128221912690 34.3584759975395642, 226.6737198569159943 34.3580488801543851, 226.6825293890413491 34.3576209382972166, 226.6913400811758663 34.3571922426228298, 226.7001540295706832 34.3567626817938603, 226.7089712049677246 34.3563322572982912, 226.7177870375189173 34.3559012100899182, 226.7266041828106324 34.3554693993520672, 226.7354247297424195 34.3550367146799474, 226.7442492611482123 34.3546031252373538, 226.7530788599001141 34.3541685738807345, 226.7619128745825776 34.3537330946952437, 226.7707514832079028 34.3532966780217492, 226.7795960290026471 34.3528592528926850, 226.7884459906888708 34.3524208463128033, 226.7973003349396492 34.3519815121097523, 226.8061593642074172 34.3515412338454738, 226.8150233317549578 34.3510999976269247, 226.8238934698206606 34.3506577380458964, 226.8327720567345978 34.3502143345875908, 226.8416573813213120 34.3497698764048707, 226.8505497655342538 34.3493243457024064, 226.8594358490678644 34.3488784448401674, 226.8683250410209098 34.3484316782386045, 226.8772265484981290 34.3479835601684655, 226.8861363120278725 34.3475343032454887, 226.8950567593701066 34.3470837782926424, 226.9039829498998984 34.3466322446343071, 226.9129146680929807 34.3461797126517538, 226.9218556874078843 34.3457259819622749, 226.9308045477932865 34.3452711283535947, 226.9397756292512156 34.3448143896436733, 226.9487603184119848 34.3443562189215470, 226.9577713539436843 34.3438959390267016, 226.9667906962713460 34.3434345028913981, 226.9758185915840727 34.3429718958397459, 226.9848216200803392 34.3425098915043279, 226.9938252716408158 34.3420471375395024, 227.0028484628004719 34.3415826268728566, 227.0118809439651386 34.3411169022523879, 227.0209235817678177 34.3406499157369396, 227.0299791780909970 34.3401815159329473, 227.0390478252923572 34.3397116955650006, 227.0481467096582833 34.3392395334901579, 227.0572602651000125 34.3387658575312145, 227.0663771857987570 34.3382912704903447, 227.0755008947066642 34.3378155878481692, 227.0846303913033353 34.3373388617669448, 227.0937637963996281 34.3368611918346360, 227.1029086134994657 34.3363821734389703, 227.1120687985093696 34.3359015912790184, 227.1212359111365231 34.3354198972308851, 227.1304019305011082 34.3349375224572597, 227.1395758195951373 34.3344539826583812, 227.1487597349220380 34.3339691594793663, 227.1579902583206376 34.3334810705894782, 227.1672328061847281 34.3329915813299635, 227.1764712676893794 34.3325015631449872, 227.1857181919703237 34.3320103348058581, 227.1949746842976765 34.3315178342700378, 227.2042427831781026 34.3310239484103192, 227.2135235122771917 34.3305286188862198, 227.2228146140626563 34.3300319661149231, 227.2321158182055001 34.3295340025165387, 227.2414261879327171 34.3290347770175401, 227.2507440105512444 34.3285343812617540, 227.2600744088049396 34.3280325326081837, 227.2694283383896732 34.3275286269244333, 227.2787965981322316 34.3270231648313313, 227.2881796631024258 34.3265161169777642, 227.2975768164241970 34.3260075195247154, 227.3069878365814702 34.3254973814854338, 227.3164104609644482 34.3249858246237451, 227.3258502854774861 34.3244725368218511, 227.3353080996625977 34.3239574704821351, 227.3447883386974127 34.3234403757068378, 227.3542849111613009 34.3229215855092846, 227.3637955610379038 34.3224012214535676, 227.3733236581736321 34.3218790927276061, 227.3828696239587828 34.3213551717971868, 227.3924291244449307 34.3208296962129822, 227.4020038477810033 34.3203025684271594, 227.4115915765554234 34.3197739087827998, 227.4211903006491866 34.3192438266352369, 227.4308034100234579 34.3187121291771930, 227.4404322668865461 34.3181787364366357, 227.4500783315511114 34.3176435625182847, 227.4597408211415939 34.3171066473257653, 227.4694373999132608 34.3165669914653151, 227.4791525994482413 34.3160254598141350, 227.4888678788014147 34.3154830953614152, 227.4985957068911944 34.3149391922755242, 227.5083373853007060 34.3143936736176798, 227.5181018062584997 34.3138460315021732, 227.5278825759299082 34.3132966235528087, 227.5376789842163987 34.3127454860494296, 227.5475028125035521 34.3121919441228513, 227.5573500149315294 34.3116362218249122, 227.5672257338917746 34.3110780197670167, 227.5771363516526549 34.3105169660666647, 227.5870780116527783 34.3099532730359726, 227.5970431329110681 34.3093873676510910, 227.6070304509182449 34.3088193165897337, 227.6170402145314711 34.3082490999014738, 227.6270614888661612 34.3076773413150846, 227.6371021487258588 34.3071035837345661, 227.6471620471891413 34.3065278306009773, 227.6572333482755539 34.3059505298130745, 227.6673250879414070 34.3053711551990759, 227.6774425887817301 34.3047893929307435, 227.6875956283597020 34.3042046688993238, 227.6977747164864354 34.3036175256546443, 227.7079695685293927 34.3030285549957057, 227.7181855113128108 34.3024374421746572, 227.7284236548605918 34.3018441168054125, 227.7386810962264576 34.3012487426516728, 227.7489607488535626 34.3006511440034032, 227.7592652945303939 34.3000511577575935, 227.7696049562623273 34.2994481773265747, 227.7799661327243541 34.2988429929067777, 227.7903495498963480 34.2982355559401029, 227.8007531420689702 34.2976259821431668, 227.8111804588746736 34.2970140564827730, 227.8216354765032463 34.2963995375121584, 227.8321461589445107 34.2957807626370936, 227.8426781271888899 34.2951597550205207, 227.8532313530369038 34.2945365104264113, 227.8637943594639239 34.2939117051551818, 227.8743681842673254 34.2932852744245977, 227.8849595330214868 34.2926568152274598, 227.8955699765431575 34.2920262287965869, 227.9062407193617048 34.2913910463675435, 227.9169476338616107 34.2907526963874574, 227.9276713907188707 34.2901123278853248, 227.9383745218067929 34.2894721856800047, 227.9490646281539057 34.2888318175634481, 227.9597329801405579 34.2881917520726702, 227.9704830712227306 34.2875457534077910, 227.9813063056207341 34.2868943188163797, 227.9922004455371223 34.2862375638696832, 228.0031311317907523 34.2855775503149829, 228.0140933799503387 34.2849145702371345, 228.0250913628242984 34.2842483611924891, 228.0361342648187701 34.2835783543212358, 228.0472235719730350 34.2829044464456985, 228.0583488204325704 34.2822272629398910, 228.0695055535343272 34.2815470658358095, 228.0806796288332521 34.2808647115191079, 228.0918858624786196 34.2801792866224346, 228.1031233132032412 34.2794908395679485, 228.1143887119114311 34.2787995621969728, 228.1256453028150872 34.2781077092036028, 228.1369030523943593 34.2774146679768847, 228.1481798443422804 34.2767193333419016, 228.1595524441489999 34.2760169520199653, 228.1709717099658405 34.2753105404703007, 228.1824155794200237 34.2746014536383754, 228.1938803829681888 34.2738899120501515, 228.2054189265202240 34.2731726236746113, 228.2170280980346888 34.2724497609647258, 228.2287243266709140 34.2717202778137491, 228.2405154508755913 34.2709836586137300, 228.2523281114419262 34.2702444679897056, 228.2641942766521197 34.2695006945981007, 228.2760966165281786 34.2687534105830665, 228.2880311232602253 34.2680028568663104, 228.3000080488953643 34.2672483775619554, 228.3120073191576012 34.2664912262207508, 228.3240136614714970 34.2657323608603051, 228.3360270491257609 34.2649717805465883, 228.3480846100778763 34.2642071289308490, 228.3601573792502393 34.2634402314495503, 228.3722738817793640 34.2626692689837498, 228.3844436938668991 34.2618936179263542, 228.3966618612460877 34.2611135777469542, 228.4089824127524366 34.2603256809244385, 228.4213463879382005 34.2595336691820549, 228.4337530236214775 34.2587375776010106, 228.4462104846748218 34.2579368682861514, 228.4587268132951010 34.2571310078012985, 228.4712928807436754 34.2563205653489931, 228.4839104809464061 34.2555054091390190, 228.4966228685898955 34.2546827271919625, 228.5094182245228467 34.2538532540846603, 228.5222741770853645 34.2530184134048241, 228.5351729277744539 34.2521793411568822, 228.5481108241424124 34.2513362606783147, 228.5610933368977840 34.2504888023745764, 228.5740744626261289 34.2496399538219762, 228.5870890608095181 34.2487874360186524, 228.6001377310472265 34.2479311983375254, 228.6132200400176089 34.2470712576139462, 228.6263499085635260 34.2462066877528244, 228.6395379494130680 34.2453367742424319, 228.6528307700917253 34.2444584250006088, 228.6663763631895847 34.2435618322477922, 228.6803617215675217 34.2426345404356880, 228.6952015541297101 34.2416489117582969, 228.7105525887952808 34.2406274236493147, 228.7265499347599302 34.2395608903248387, 228.7421439705677528 34.2385190301761213, 228.7570825715770866 34.2375188387752232, 228.7710598752944691 34.2365810241448401, 228.7833530683239758 34.2357543579112189, 228.7952800700345790 34.2349509231169549, 228.8072627602099942 34.2341424760952293, 228.8196514308075677 34.2333054217383648, 228.8331287441866664 34.2323936079623863, 228.8473922131053655 34.2314270980820723, 228.8618442087083338 34.2304460498874050, 228.8763439297838431 34.2294599388280361, 228.8909482642987996 34.2284648840239214, 228.9056482136413706 34.2274614588506196, 228.9203772895894815 34.2264541588745246, 228.9351647838737165 34.2254409729159406, 228.9499300140235505 34.2244273973785766, 228.9641311146556006 34.2234505682552808, 228.9782062980127080 34.2224806100983585, 228.9925852305867124 34.2214880258965621, 229.0081810669315416 34.2204098060711885, 229.0243240483072213 34.2192917031745054, 229.0404841060492060 34.2181701534276783, 229.0561546197282325 34.2170802520685911, 229.0718159793166819 34.2159888445761311, 229.0875983320990770 34.2148868824320118, 229.1034887026381455 34.2137752213084099, 229.1195460110981230 34.2126497040037805, 229.1358158381831913 34.2115070742239453, 229.1519329161114058 34.2103728456207250, 229.1680640638340094 34.2092353651527787, 229.1841528314203913 34.2080985981401113, 229.1997352209738494 34.2069952677110791, 229.2145400585285984 34.2059447196422752, 229.2300224802753235 34.2048443144084544, 229.2467979267121052 34.2036501663594166, 229.2636965490855232 34.2024448214142751, 229.2805688057605948 34.2012388686691864, 229.2975531550706592 34.2000224458390818, 229.3153572083785150 34.1987449443626517, 229.3330755455613428 34.1974708313770890, 229.3499864414433489 34.1962519263011018, 229.3671162393165446 34.1950147940828515, 229.3845622240634157 34.1937523320369579, 229.4014568277145827 34.1925270213204655, 229.4184179979392582 34.1912944083744819, 229.4358437586914761 34.1900256224414889, 229.4537366314035012 34.1887202762343563, 229.4717783255886729 34.1874013197685613, 229.4899255387092012 34.1860718423110796, 229.5081725981956993 34.1847322094676969, 229.5265398704356130 34.1833808833751647, 229.5450922295438545 34.1820130473676471, 229.5638787832386640 34.1806250031403636, 229.5833013117174062 34.1791870291224100, 229.6027619754956390 34.1777429732541052, 229.6217226068458217 34.1763326529017633, 229.6405847437962109 34.1749265205166282, 229.6596052490299087 34.1735055274516171, 229.6788397629834719 34.1720654519100648, 229.6983584809424030 34.1706009485036830, 229.7180957279129814 34.1691167912386220, 229.7380788625919479 34.1676108189410357, 229.7584117626150544 34.1660750990312749, 229.7790969055735673 34.1645092650801132, 229.7996369175649818 34.1629506916830863, 229.8203742931991655 34.1613735312545757, 229.8416825810410273 34.1597493413921924, 229.8624957634054908 34.1581588787102532, 229.8824174025273237 34.1566326128934890, 229.9024284095941084 34.1550960779241066, 229.9235693655622299 34.1534695745373043, 229.9452549994267088 34.1517974117562630, 229.9672683738575074 34.1500959778672595, 229.9895003848597241 34.1483735026549837, 230.0115335641334582 34.1466621289056462, 230.0333871041056000 34.1449604787229646, 230.0555507513969360 34.1432306180995653, 230.0779079316405955 34.1414814476944599, 230.1005422999793382 34.1397063294055911, 230.1238833343022350 34.1378715065958502, 230.1469833844259369 34.1360508855456928, 230.1701524618428607 34.1342202326812796, 230.1934678024026368 34.1323734191500918, 230.2165682856072806 34.1305388896250506, 230.2389046257025598 34.1287602696899981, 230.2627494180453027 34.1268575758665520, 230.2877550266475737 34.1248575757214354, 230.3121994425046353 34.1228969832372329, 230.3374538174263648 34.1208664280740450, 230.3631413115423925 34.1187956311933505, 230.3880206606859531 34.1167841715787290, 230.4129740676316658 34.1147614028110624, 230.4381720995549188 34.1127134837281716, 230.4639006137480521 34.1106170799943840, 230.4899617773432681 34.1084879305144355, 230.5160751629498748 34.1063486759816996, 230.5424933622251444 34.1041786334010055, 230.5692512087758814 34.1019747431288138, 230.5962633487828271 34.0997437899986693, 230.6233712571642513 34.0974986648374738, 230.6505324126182188 34.0952428145793291, 230.6778991776199348 34.0929635735833614, 230.7056768659263639 34.0906437347729181, 230.7338743164805805 34.0882822720815781, 230.7624290255265862 34.0858841099150212, 230.7912515728409630 34.0834564852273800, 230.8203176007084778 34.0810012492433714, 230.8496066249822150 34.0785199486820005, 230.8792222278794100 34.0760036573598484, 230.9092353385083811 34.0734461134513964, 230.9394837890443739 34.0708608100599832, 230.9699110763695842 34.0682523866543931, 231.0006928671137985 34.0656056694953833, 231.0318850271158908 34.0629155854277812, 231.0635571685805303 34.0601758151630207, 231.0955368339715221 34.0574008702548809, 231.1277395307414224 34.0545978215856735, 231.1598263149443255 34.0517959465778262, 231.1923731407472076 34.0489451185415319, 231.2256091619747167 34.0460249134342732, 231.2592693971341760 34.0430580048563343, 231.2932997454268502 34.0400487931218905, 231.3276773418007224 34.0369989774649824, 231.3623788651742643 34.0339103206458304, 231.3976872583261866 34.0307573788087794, 231.4333912447760611 34.0275584580134378, 231.4693555745259914 34.0243253060918320, 231.5059110723479137 34.0210279684916301, 231.5428878341136851 34.0176812113605962, 231.5803120487275919 34.0142822698571479, 231.6182257695979274 34.0108269013428526, 231.6563923557117732 34.0073361890491626, 231.6951328868908320 34.0037805361373344, 231.7344016752472839 34.0001635697603959, 231.7741163312641959 33.9964923489273474, 231.8144687460353452 33.9927486903022995, 231.8555242504632190 33.9889258812754989, 231.8967616379406707 33.9850717165754332, 231.9384874591021060 33.9811573547210131, 231.9810031242021182 33.9771540026181711, 232.0239997221509896 33.9730898997487358, 232.0678388326644495 33.9689303373579179, 232.1123373516068966 33.9646917583446637, 232.1571892770959664 33.9604025763729709, 232.2028902908268719 33.9560149645457585, 232.2491821769203000 33.9515527436837061, 232.2960411960920908 33.9470175080060130, 232.3439306822214974 33.9423637059180976, 232.3925149925117069 33.9376227335627902, 232.4421795018198509 33.9327560905117309, 232.4923819960596063 33.9278156111136937, 232.5436698046292179 33.9227466788576564, 232.5951687841104842 33.9176343957194177, 232.6475716305862989 33.9124096240862514, 232.7012278929114473 33.9070362581488851, 232.7556828036422303 33.9015582140379479, 232.8111272809534853 33.8959551462227964, 232.8675924453869754 33.8902225112893021, 232.9251556043381015 33.8843509817138369, 232.9836292773927369 33.8783581196600210, 233.0432332672728819 33.8722199924782501, 233.1036814245413780 33.8659644315621762, 233.1655576135860599 33.8595295608053988, 233.2282972754190951 33.8529720150750464, 233.2926253690727378 33.8462144249607135, 233.3579653177716295 33.8393149569302949, 233.4238324436093990 33.8323232702830481, 233.4921199960124909 33.8250368579970129, 233.5612785480354603 33.8176174606137465, 233.6323604436500148 33.8099502310293261, 233.7049545856000634 33.8020762210515144, 233.8182991443937340 33.7896946459519754, 233.8076868008509450 33.7447711159585353, 233.7998795209612979 33.7148904496539430, 233.7932833619625796 33.6848666706177085, 233.7861879661206217 33.6548975268433708, 233.7790138730816238 33.6249371304411468, 233.7721258778470030 33.5949457575010797, 233.7653244274834776 33.5649451763320457, 233.7589504394325957 33.5348983220681589, 233.7517922483768587 33.5049370176588681, 233.7451099029024988 33.4749242026266884, 233.7380079966970072 33.4449572275375928, 233.7308913046056773 33.4150038907599480, 233.7242842859603229 33.3850066680614148, 233.7177523607820149 33.3550016103827929, 233.7105361717234473 33.3250710557136642, 233.7038713780214607 33.2950810139364961, 233.6970686628110343 33.2651062319824931, 233.6905337587843690 33.2351027783426076, 233.6840504440658606 33.2050940975069437, 233.6777241041899913 33.1750688065101542, 233.6714174241416231 33.1450417813746228, 233.6651265167774056 33.1149842340850284, 233.6589877928076646 33.0848829897737033, 233.6524321128083557 33.0548271750781311, 233.6459016737647971 33.0247690229860495, 233.6397274742706998 32.9946728446447679, 233.6329292365037418 32.9646443837786194, 233.6264198618044645 32.9345851796794449, 233.6202087450176350 32.9044942684929751, 233.6139880509850002 32.8744048431199474, 233.6079852676745929 32.8442924253051416, 233.6024480632221128 32.8141580579442405, 233.5966311950082854 32.7840805086041911, 233.5901811264418768 32.7540715697776363, 233.5840609927987259 32.7240276624917570, 233.5780234845818484 32.6939754072355768, 233.5723051527258463 32.6638894276889644, 233.5666017736687934 32.6338024225347070, 233.5607542213080876 32.6037314698474248, 233.5546837865367706 32.5736849919792704, 233.5486024504767215 32.5436402503859412, 233.5424177864383353 32.5135952204185656, 233.5365716066706341 32.4835032169014184, 233.5315060000013148 32.4533282706241195, 233.5261496478028675 32.4231850922122362, 233.5203742087318233 32.3930873795337675, 233.5147182817867417 32.3629775114589648, 233.5094845865763773 32.3328231674413402, 233.5039894604646804 32.3026974294728859, 233.4978335601193464 32.2726429030728994, 233.4931590404903545 32.2424309059519061, 233.4878027399519453 32.2122923884581667, 233.4822943076409274 32.1821707947332527, 233.4769428294368367 32.1520331689142935, 233.4715484851256235 32.1219008275854492, 233.4659832528489858 32.0917874106425174, 233.4604242297955352 32.0616740464830130, 233.4547057473552059 32.0315783750575207, 233.4493448634544279 32.0014453816849027, 233.4439538848272377 31.9713163427404226, 233.4388438488122119 31.9411582035282215, 233.4333516270229723 31.9110653071387809, 233.4279989229896444 31.8809809553688552, 233.4229566389217894 31.8508644673349011, 233.4183811247408471 31.8206993020757771, 233.4138877625083808 31.7905263248524932, 233.4092102825951258 31.7603737819921363, 233.4050516565336579 31.7301671583804179, 233.4001074315976041 31.7000447187404717, 233.3957145714181536 31.6698647916849545, 233.3913100752606340 31.6396870518961428, 233.3864447836710667 31.6095336383505341, 233.3812875213067741 31.5793879739752867, 233.3764952549095710 31.5492046025283273, 233.3713681255396750 31.5190575397734705, 233.3665069082488230 31.4888832849676525, 233.3615529341064416 31.4587197536657825, 233.3563206749479377 31.4285865291404711, 233.3514797002687260 31.3984129293746150, 233.3465577545539134 31.3682488233591918, 233.3417228712048939 31.3380764928643032, 233.3370904020155194 31.3078918588118036, 233.3327447690398628 31.2776856492936552, 233.3284034056367489 31.2474800413596085, 233.3238447530019926 31.2172983698287148, 233.3202001869975390 31.1870215346730824, 233.3161949178957286 31.1567837770521372, 233.3117460131502128 31.1265937911358250, 233.3074302663908668 31.0963908864289600, 233.3031004201629059 31.0661905619832162, 233.2993877462967305 31.0359264958431389, 233.2953127271858875 31.0057054348373704, 233.2898951297387669 30.9756300525971362, 233.2854622844029677 30.9454523393039729, 233.2811087259339331 30.9152674168075556, 233.2766787724962967 30.8850916312890398, 233.2723182338050663 30.8549096936050056, 233.2680625874326665 30.8247179032272562, 233.2636594360020013 30.7945427207441114, 233.2591073855289494 30.7643842796982661, 233.2546430264907542 30.7342178080200377, 233.2506548072034320 30.7039852299984197, 233.2467326448435188 30.6737304212484112, 233.2427735883874220 30.6434806792655507, 233.2385419916588489 30.6132606394362270, 233.2344263707328196 30.5830296839476610, 233.2299724549353641 30.5528352858511347, 233.2257801218785005 30.5226147736255093, 233.2217008350382912 30.4923836900961192, 233.2176536180877520 30.4621505031956623, 233.2137701088354333 30.4319014927804155, 233.2097164924082904 30.4016889943496160, 233.2057273903072883 30.3714876142592480, 233.2018315927718390 30.3412778048335809, 233.1982994815887196 30.3110314135535397, 233.1949660441975709 30.2807656745661049, 233.1909995459751883 30.2505672082381274, 233.1869329124752994 30.2203804896820323, 233.1830432861650308 30.1901766843827808, 233.1794294370546368 30.1599455462843871, 233.1757256557578444 30.1297251351229853, 233.1722016871373455 30.0994998764674975, 233.1687265873427179 30.0692827643412635, 233.1657971255530981 30.0390104337142958, 233.1620197154927894 30.0088276220750814, 233.1588110553424542 29.9785872277253844, 233.1558657450565590 29.9483210009760406, 233.1526520127341655 29.9180841252305392, 233.1489461529616278 29.8878997697228570, 233.1453943524509782 29.8577009226519010, 233.1419015803729451 29.8274974560358004, 233.1385470570977816 29.7972455511376992, 233.1353455350160289 29.7669455615571614, 233.1321205569348365 29.7366494892352904, 233.1286857502857117 29.7063766210683760, 233.1248502692661759 29.6761466884867851, 233.1219322346083231 29.6458233627870875, 233.1187887010911481 29.6155248850340520, 233.1158036470708339 29.5852115613503379, 233.1128189974144220 29.5548997434543850, 233.1096148239092258 29.5246121600882780, 233.1059421915535381 29.4943963292008320, 233.1029253621420025 29.4641350065570151, 233.1002381417339677 29.4338412717182401, 233.0969753053758780 29.4036085512377774, 233.0938295190486258 29.3733653616724482, 233.0913472163338440 29.3430553834682506, 233.0892058098756081 29.3127119349647067, 233.0863428536407014 29.2824445349173530, 233.0832116703506927 29.2522064239976025, 233.0797675612166131 29.2220021876194558, 233.0766708226083779 29.1917583918426793, 233.0740702319595812 29.1614600580882026, 233.0714565710325985 29.1311647753841925, 233.0690128689927576 29.1008537235407303, 233.0668902691410551 29.0705113857663484, 233.0645048567074014 29.0401978200141784, 233.0622308671956944 29.0098745532563846, 233.0598776027511860 28.9795611971617610, 233.0578674387686249 28.9492143656048526, 233.0557478221899146 28.9188805699773148, 233.0535026840429964 28.8885669116981312, 233.0508429036479754 28.8583027762630273, 233.0484008302731525 28.8280180911364923, 233.0460454447779455 28.7977263211135330, 233.0438808462283475 28.7674168095447094, 233.0413729393316942 28.7371443319351094, 233.0390306784746883 28.7068567067667786, 233.0369262675669688 28.6765465604912748, 233.0347470633640796 28.6462459426612384, 233.0329268350070890 28.6159104396763375, 233.0304011304804703 28.5856435995693232, 233.0285767800003214 28.5553016798027670, 233.0267613739262345 28.5249607573214767, 233.0251239162210481 28.4946035505042552, 233.0235861249755089 28.4642380888206468, 233.0216106033979031 28.4339193332039670, 233.0189545611958124 28.4036720750919329, 233.0154885602246111 28.3735094844736260, 233.0142983651916779 28.3431162820924243, 233.0278250723105486 28.3112211640421627, 233.0452282676261007 28.2789483187394843, 233.0538325274330305 28.2475942808537539, 233.0539975568593434 28.2171064726353187, 233.0513725666158678 28.1869063911921387, 233.0495940247798217 28.1566216920427621, 233.0476156283756097 28.1263594901669798, 233.0441012164608594 28.0962563986381291, 233.0341267619562302 28.0668153191364418, 233.0153669885793590 28.0382716562388339, 233.0004310857395353 28.0093374012700345, 232.9972907785160885 27.9791790793518480, 232.9993492557859156 27.9484712223743799, 232.9984005080535212 27.9180717344067304, 232.9974307125874589 27.8876765098117794, 232.9972130492355689 27.8572068668355115, 232.9974480176590248 27.8266933234035996, 232.9991589372480121 27.7960317666086958, 232.9989280134366254 27.7655700234404357, 232.9984242466573505 27.7351382270215581, 232.9981795284499242 27.7046822703985498, 232.9979878384312144 27.6742274580733785, 232.9973841036592148 27.6438208719076783, 232.9969627048587313 27.6133979690396210, 232.9956424441161857 27.5830686696773846, 232.9942467721409969 27.5527492409840562, 232.9928294278021781 27.5224342236403245, 232.9910051526982215 27.4921627558298560, 232.9892752251977015 27.4618839132474726, 232.9876407499768050 27.4315975974893540, 232.9860500535197616 27.4013090709302176, 232.9845431092176398 27.3710008489845045, 232.9832144523877844 27.3406640377800798, 232.9813211962254798 27.3103867100860782, 232.9796046601094304 27.2800936680591022, 232.9778668740711680 27.2498050024511933, 232.9760812623313200 27.2195234107127924, 232.9744936225061167 27.1892239957127586, 232.9725389188140809 27.1589640136351065, 232.9710993706493696 27.1286541056601571, 232.9695310658383107 27.0983595097609289, 232.9678740179707574 27.0681026007854726, 232.9664105876078111 27.0378534557978263, 232.9648174106994247 27.0076198078681955, 232.9633173340908456 26.9773791166841228, 232.9625444737449413 26.9470672981449333, 232.9609409653207877 26.9168418629111947, 232.9596090239708417 26.8865913871725191, 232.9583747341667959 26.8563334706327588, 232.9570418888685026 26.8260879392246423, 232.9556783045036639 26.7958479490434627, 232.9541208556390188 26.7656115503784378, 232.9529072543590758 26.7353254479347022, 232.9513372321344207 26.7050777308560647, 232.9496721067669398 26.6748420272777231, 232.9482697863891190 26.6445822619977086, 232.9469308519579158 26.6143185587959685, 232.9456308588468971 26.5840533948443856, 232.9445891873004371 26.5537646856240990, 232.9435705001869508 26.5234761549909130, 232.9424930683779849 26.4931960434053231, 232.9411883948879733 26.4629460272636905, 232.9404661357344537 26.4326443639049629, 232.9397077070689477 26.4023488674102964, 232.9389590229434361 26.3720549233813237, 232.9380771814213631 26.3417769121558294, 232.9371118552030850 26.3115098363276338, 232.9363055938855496 26.2812293227508285, 232.9349899869084197 26.2510025505052305, 232.9335253420107392 26.2207932922391542, 232.9325013463295591 26.1905423329871923, 232.9312666333587458 26.1603104014087862, 232.9304842316648205 26.1300312111542468, 232.9301915140906090 26.0997055104643607, 232.9294881720221895 26.0694236562733899, 232.9290727464842519 26.0391155706255368, 232.9284303148743334 26.0088329122365636, 232.9279035225714551 25.9785413248947528, 232.9273612165381451 25.9482539712151024, 232.9268538348704851 25.9179658022400368, 232.9262752017791911 25.8876874678260762, 232.9258886604945928 25.8574103205871566, 232.9254503184828593 25.8271578908632939, 232.9251078810469551 25.7968986263993436, 232.9246578931334284 25.7666529016514900, 232.9240220891315971 25.7364285483357058, 232.9236035389937456 25.7061852433890081, 232.9230685583847844 25.6759563790559397, 232.9227337275446814 25.6457103098674501, 232.9226746289442360 25.6154395052660426, 232.9151284100261421 25.5859193757088335, 232.8937666407001927 25.5577604985955915, 232.8940638253671409 25.5274256432220170, 232.8871864393980502 25.4978083492145302, 232.8887549686264435 25.4673523878265264, 232.8922447979715855 25.4367079619002219, 232.8868549804973611 25.4069505089587331, 232.8862070942742832 25.3767236847006394, 232.8896433828423085 25.3460933179880676, 232.8904085763713852 25.3157316468416127, 232.8749355208171608 25.2869872855028568, 232.8752451626990876 25.2566951708590217, 232.8833426365382877 25.2256500909277364, 232.8835253169675639 25.1953944685349569, 232.8791674519990806 25.1655927164969029, 232.8897864847603500 25.1343065994128700, 232.8853793267643084 25.1045158112194073, 232.8872412249220076 25.0741054814230750, 232.8902504011679184 25.0435843557807090, 232.8862819506101118 25.0137587010341953, 232.8849165370428977 24.9836776256239297, 232.8615444344878824 24.9557405574880384, 232.8678957259777746 24.9248252133515251, 232.8743003817854174 24.8939074623787384, 232.8845451259491313 24.8626121461173852, 232.8855114924644738 24.8322389784330113, 232.8777786941511465 24.8027302998354422, 232.8784494296954222 24.7723922673367660, 232.8786766283392922 24.7421011267217601, 232.8815821187694723 24.7115479151651094, 232.8784798198719841 24.6815922416011517, 232.8815210227576245 24.6510507831911276, 232.8869507732288184 24.6202941882075912, 232.8897516432224961 24.5898008394087846, 232.8918981619777924 24.5593753742191865, 232.8953447469445734 24.5288244473813180, 232.9021256320803843 24.4979467949218126, 232.9055803919187895 24.4674014152638897, 232.9256796375334488 24.4352113534955322, 232.9278143679030677 24.4048031512248613, 232.9273308331008536 24.3746574338355266, 232.9233851756903277 24.3448714449377732, 232.9184915904162665 24.3151952702327385, 232.9128735282336322 24.2855934652230268, 232.9070168456449323 24.2560179020738893, 232.8961245152644040 24.2269419338317213, 232.9056956378175869 24.1958493514343687, 232.9163992199943323 24.1646481368294097, 232.9148753746634668 24.1346574496068342, 232.9260392072289392 24.1034175401604038, 232.9206813331250885 24.0738120738219301, 232.9204495719246779 24.0437090840601435, 232.9242943936257006 24.0132123142740319, 232.9256437469389311 23.9829650937303498, 232.9266377198844395 23.9527562659602467, 232.9335016545540498 23.9219720545757646, 232.9350094750091387 23.8917194174715171, 232.9318311547083624 23.8619319938418855, 232.9368722188254139 23.8313379253568662, 232.9450679384852094 23.8004364541792768, 232.9487612034705819 23.7699821916536962, 232.9457539896300773 23.7401711442871743, 232.9427211902646491 23.7103463854447085, 232.9402080395296366 23.6804735787408411, 232.9433835895079312 23.6500442501760695, 232.9429844398777050 23.6199700525028895, 232.9448047519951217 23.5896808976233565, 232.9476776159105498 23.5592916674110846, 232.9482010009696182 23.5291369225008040, 232.9512697052309136 23.4987353647413322, 232.9482075708974946 23.4689398429934144, 232.9524304167965170 23.4384270364512517, 232.9546730815462467 23.4081077649794302, 232.9582883791230756 23.3776571361768752, 232.9647493343327085 23.3469304506696140, 232.9703738876218324 23.3162894619193146, 232.9749310816914658 23.2857568941960480, 232.9745359583259585 23.2557144439031767, 232.9767231065955286 23.2254218016588787, 232.9747120126448010 23.1955449259003750, 232.9822413991412304 23.1647348154436621, 232.9804333911563390 23.1348442844337647, 232.9799632300583312 23.1048251183938760, 232.9861015982691583 23.0741610277334033, 232.9875906069682685 23.0439567790242954, 232.9885163913017152 23.0138113510139206, 232.9880927477933881 22.9838018052555668, 232.9920786514291819 22.9533634402218354, 232.9956900446725570 22.9229654566407355, 232.9980286667984331 22.8926959144764481, 232.9994463253835590 22.8625202869970394, 233.0007273526802010 22.8323817679763863, 233.0026223770331910 22.8022057943616439, 233.0043541573523385 22.7720495281594388, 233.0056855082923448 22.7419361869260008, 233.0075168387004112 22.7117776144770147, 233.0086972638558507 22.6816864801467410, 233.0110141288599834 22.6514878824316952, 233.0150980294305043 22.6211202181119297, 233.0183630375206860 22.5908364990390140, 233.0205235275349764 22.5606646287341768, 233.0226990887721854 22.5304748351912814, 233.0250312225587948 22.5002543317498116, 233.0273417263018416 22.4700397097962856, 233.0294322532687943 22.4398503560864988, 233.0316537239692423 22.4096519871084432, 233.0341646706244774 22.3794291321900545, 233.0365342745103874 22.3492238901019569, 233.0390090293491596 22.3190121957783028, 233.0410423260715618 22.2888474232953939, 233.0431049502272174 22.2586836086433415, 233.0454588237505789 22.2284945392465723, 233.0478015505857456 22.1983097811950536, 233.0502410034338254 22.1681194493875857, 233.0528960636553961 22.1379119637526749, 233.0557407390418518 22.1076898815501366, 233.0583526793505200 22.0774943965698363, 233.0611965967989079 22.0472802077131611, 233.0637667921969296 22.0170966233224057, 233.0661707315231581 21.9869331637061833, 233.0688355153386908 21.9567482212916190, 233.0712133978703946 21.9266163989694398, 233.0735932640259307 21.8965084711711100, 233.0760567737850124 21.8663964170824769, 233.0786160066152775 21.8362790739403536, 233.0813521304598623 21.8061485619774196, 233.0841934458621552 21.7760118754163514, 233.0868186396090209 21.7459002818275557, 233.0896572713970727 21.7157720085455743, 233.0925606004185511 21.6856415365210218, 233.0953944801916293 21.6555219188819841, 233.0982658466593875 21.6253757163975280, 233.1010684294436999 21.5952146481066016, 233.1039565017079269 21.5650493243033381, 233.1070084940014340 21.5348721396217933, 233.1101013319822357 21.5046950640766852, 233.1128703123239063 21.4745535126135110, 233.1158241927793142 21.4443980968924066, 233.1188318355480362 21.4142415633379279, 233.1218563891699773 21.3840874973898849, 233.1246794784815961 21.3539570958571900, 233.1274225832100910 21.3238601081567225, 233.1306370617675157 21.2937419770209679, 233.1338110027921857 21.2636319988396920, 233.1368714755917608 21.2335372463016725, 233.1401888171233736 21.2034218386528366, 233.1433772704574210 21.1733231702659666, 233.1465315268246457 21.1432320717217443, 233.1496154959708065 21.1131520454980688, 233.1523256639130182 21.0831124744103242, 233.1550432762235232 21.0530764456413166, 233.1579828490156387 21.0230058063689711, 233.1607722022461644 20.9929374509098636, 233.1636624179120645 20.9628635553827110, 233.1666398144984100 20.9327854559908850, 233.1696517887513096 20.9027082545512997, 233.1726003363481823 20.8726414316977440, 233.1758702060247401 20.8425478179737880, 233.1788078854982871 20.8124905746892104, 233.1817470919710615 20.7824374566928114, 233.1847240762937474 20.7523849750790745, 233.1882571693559498 20.7222788477096316, 233.1922497392443177 20.6921286819550296, 233.1963717972563472 20.6619703874637324, 233.1999109852516483 20.6318727136307807, 233.2035406236984159 20.6017706852433591, 233.2070288686839490 20.5716866762562312, 233.2105921938348558 20.5415998141373528, 233.2140636676945746 20.5115262079963792, 233.2178119025755336 20.4814303280644161, 233.2217592401371462 20.4513196857803798, 233.2251909010133204 20.4212673944372689, 233.2282694103726897 20.3912575382923755, 233.2318419183720835 20.3612045155384997, 233.2355239631258144 20.3311453846168213, 233.2391586892739781 20.3010952641717957, 233.2428990778244042 20.2710394343307705, 233.2464567058539444 20.2410056661055044, 233.2499761033736831 20.2109800536504096, 233.2536732782234878 20.1809418255188859, 233.2573748161835283 20.1509076803910574, 233.2610258437821074 20.1208946526849886, 233.2648839717209057 20.0908774184780903, 233.2690707989325460 20.0608332120380233, 233.2729399482162762 20.0308241593812788, 233.2766399932848742 20.0008359800302244, 233.2812975167611285 19.9707604952090776, 233.2864835103510757 19.9406389605955141, 233.2910589910247836 19.9105807427105042, 233.2951517126599299 19.8805735518949831, 233.2994281961829017 19.8505534224128048, 233.3035672940802101 19.8205511748355683, 233.3079874497330195 19.7905266855421935, 233.3129269619056743 19.7604571405118357, 233.3212816261563489 19.7300649786930506, 233.3230339211604019 19.7003105136032453, 233.3250709696296212 19.6705333692991715, 233.3296297889724826 19.6405193532041871, 233.3340604186102496 19.6105224014847792, 233.3383183317661747 19.5805467749846187, 233.3428179008550671 19.5505528169449825, 233.3472901992914785 19.5205884333979363, 233.3519547732985586 19.4906315128301806, 233.3565130546640205 19.4606896821475424, 233.3611875777690443 19.4307416676413673, 233.3661894041850076 19.4007673213927738, 233.3703364724232756 19.3708796064123803, 233.3750997858020355 19.3409379714967393, 233.3796821892690616 19.3110185897310593, 233.3838727405633335 19.2811415855535060, 233.3885341450790349 19.2512246218782614, 233.3933864584715820 19.2212534983463215, 233.3986811270121962 19.1912063080396358, 233.4036949065424835 19.1611907724642343, 233.4090010489056510 19.1311522333807353, 233.4132186011130443 19.1012223437648210, 233.4123898128762278 19.0717780874600393, 233.4234938189524655 19.0412018332757356, 233.4281136089198299 19.0112482689356206, 233.4325499945081219 18.9813170712961394, 233.4385722857594772 18.9512397884658697, 233.4443472690545605 18.9211910404965344, 233.4496096003589969 18.8911960802610075, 233.4547716287821686 18.8612156352759506, 233.4583507148462047 18.8313907512887653, 233.4655539294550408 18.8012260955363750, 233.4711278179178464 18.7712214498863723, 233.4767412813863814 18.7412180639201722, 233.4825004791105982 18.7112058596519368, 233.4883578878495314 18.6811893699630893, 233.4930940640239214 18.6512844874852739, 233.4992980389991146 18.6212451930891127, 233.5048315557592673 18.5912746804501623, 233.5077083130712765 18.5615615247693846, 233.5090647558613739 18.5319976053586331, 233.5185189875365666 18.5016701736589049, 233.5255892491283305 18.4715741712361918, 233.5300607517884828 18.4417298954107771, 233.5355540635434579 18.4117937924565673, 233.5416644760110216 18.3818043138120757, 233.5436055661265016 18.3522152471724311, 233.5514883551133494 18.3220390662315573, 233.5588538186819392 18.2918895888876669, 233.5647531551124416 18.2618841625846500, 233.5705679159131591 18.2318918457248778, 233.5766138332255082 18.2018827384489974, 233.5826686375446570 18.1718779111487798, 233.5888785940030914 18.1418635244420230, 233.5951383724894868 18.1118495698953126, 233.6014674717557966 18.0818342120025726, 233.6076764098261833 18.0518354029742305, 233.6140209227432081 18.0218522835686414, 233.6204423279392302 17.9918892524204779, 233.6265487125820925 17.9619613307872079, 233.6313515420965530 17.9321620036759946, 233.6386754122240745 17.9021295475782303, 233.6451980362392078 17.8721782134589731, 233.6513777078440057 17.8422646488452799, 233.6535623905758143 17.8127339294964280, 233.6609506869070287 17.7827168172749950, 233.6699594121416794 17.7525520609224401, 233.6710216308924828 17.7231431656690397, 233.6718987098583682 17.6937567665229594, 233.6886100268676500 17.6628813678396774, 233.6960663231332944 17.6328849765218045, 233.7026278416137188 17.6029784898588098, 233.7090592956413104 17.5730897220186435, 233.7159774814714126 17.5431605027914799, 233.7217275110074581 17.5133469216565452, 233.7187734900754208 17.4843590861112901, 233.7270853487591751 17.4543148474000560, 233.7331808851990047 17.4244650559326750, 233.7435127698205974 17.3942028951707535, 233.7536136128401267 17.3639679699476659, 233.7604356218571127 17.3340473253071927, 233.7671770105191911 17.3041397119190812, 233.7740217619244447 17.2742278149562658, 233.7808503091249293 17.2443229050635445, 233.7874669750843850 17.2144434060740643, 233.7940569944907736 17.1845718878611855, 233.8008596205570200 17.1546858578559593, 233.8077378291946218 17.1248364577951477, 233.8147908325216520 17.0950124866744311, 233.8216472066112317 17.0652127325469856, 233.8287550493209892 17.0353950863091299, 233.8358236306713422 17.0055868895775504, 233.8429318881181871 16.9757807353939576, 233.8498250518302655 16.9460005561754876, 233.8567982141668438 16.9162186518052877, 233.8644027756993751 16.8863833032343358, 233.8717789035609087 16.8565752238410482, 233.8787743160380899 16.8267903345665388, 233.8864271817588190 16.7969322128414085, 233.8943020025787405 16.7670590849023320, 233.9020234300422487 16.7372061476441409, 233.9097388867146208 16.7073595931862542, 233.9174310494171891 16.6775210529367044, 233.9253368303507159 16.6476683527251197, 233.9331359108360573 16.6178315077103491, 233.9401620373827768 16.5880728789295055, 233.9480199089602763 16.5582422695100639, 233.9556240345705191 16.5284143707629028, 233.9629611957227269 16.4985917371710613, 233.9680858448260494 16.4689817308887712, 233.9697189397047907 16.4397036867894251, 233.9810825592319361 16.4095219192914819, 233.9908561421488571 16.3794945960678326, 233.9882558499625418 16.3506288802721613, 234.0070396856991692 16.3197717513327589, 234.0069713601554895 16.2906809733869693, 234.0202313690597578 16.2603515812108093, 234.0396206155035372 16.2294769328209796, 234.0450716397836004 16.1999297991700111, 234.0561919774314674 16.1698594103974891, 234.0658256086437348 16.1399339059389888, 234.0741862235724682 16.1101332895771421, 234.0828109354990261 16.0803141029572600, 234.0913423006932987 16.0505097118745965, 234.0998453017218424 16.0207140639679864, 234.1085331394955062 15.9909072931318139, 234.1171059040658804 15.9611173753279090, 234.1257060293999359 15.9313287300730444, 234.1339610716019308 15.9015761555569703, 234.1421311332078687 15.8718375959628091, 234.1504002200311163 15.8420959238847718, 234.1587546091515435 15.8123524374057407, 234.1674495385412911 15.7825834029764227, 234.1763947307113369 15.7527972553506963, 234.1849920610645768 15.7230496510930529, 234.1933783956116031 15.6933278490381323, 234.2016682329614810 15.6636212040259846, 234.2106661103412080 15.6338573919960844, 234.2195850306243585 15.6041094924468524, 234.2284696631510883 15.5743710697067037, 234.2372546661415527 15.5446481978965938, 234.2462970040240577 15.5149077482776239, 234.2553563459844668 15.4851720526347219, 234.2644515617519687 15.4554393746423013, 234.2736445752768759 15.4257039865954688, 234.2828900292420826 15.3959701114841270, 234.2920854378215267 15.3662472679597375, 234.3013275326234464 15.3365240161494683, 234.3104684932162343 15.3068141676424592, 234.3196567191314728 15.2771063206136155, 234.3288051987633480 15.2474085455542010, 234.3378564295157105 15.2177261764300678, 234.3470450336738793 15.1880375022826879, 234.3562524205285911 15.1583535187513530, 234.3654777347240952 15.1286743194410604, 234.3747378390859524 15.0989983563807133, 234.3840812977530277 15.0693211573935493, 234.3931289748404652 15.0396512748819262, 234.4024907295219009 15.0099336757912152, 234.4122604236426071 14.9801847783205897, 234.4219977298243123 14.9504452811145629, 234.4316158217008876 14.9207232127847984, 234.4409823342089965 14.8910307929301986, 234.4498350294495594 14.8613922149404161, 234.4587414398604324 14.8317550982339306, 234.4679675150275102 14.8020949299082716, 234.4770902769993768 14.7724507459251111, 234.4864736845448761 14.7428161288563455, 234.4957933016077902 14.7132196609919141, 234.5055218342258456 14.6835921628358417, 234.5149128961783731 14.6540024088048977, 234.5240841564354923 14.6244395507798366, 234.5338855767652717 14.5948253660254430, 234.5441277234739630 14.5651773498399315, 234.5546148327972560 14.5355135560838367, 234.5650071688638718 14.5058652498629623, 234.5754239657616438 14.4762214795646678, 234.5860298985859345 14.4465631055522845, 234.5967350016157980 14.4168986452192929, 234.6069521171130816 14.3872858481746757, 234.6171532263267352 14.3576813564971797, 234.6275466849351119 14.3280660631511427, 234.6379311558054326 14.2984584661645968, 234.6483279332099698 14.2688566257719316, 234.6586953216983602 14.2392643796648937, 234.6688702853703603 14.2096966782432101, 234.6792465123588727 14.1801174491704600, 234.6895268522844731 14.1505511410281279, 234.6998289458051090 14.1209871013773025, 234.7101500403533691 14.0914282332427963, 234.7207265998918047 14.0618529130783187, 234.7321276655577265 14.0322091288899919, 234.7421715997281808 14.0026964531666795, 234.7518848048210032 13.9732209510139391, 234.7623775583252552 13.9436811557223272, 234.7730116693621483 13.9141354453401398, 234.7836780942089945 13.8845938048401454, 234.7943396394510387 13.8550596464772120, 234.8051586497037135 13.8255181702998513, 234.8160814505063740 13.7959742977803899, 234.8270783541463231 13.7664307566487150, 234.8381481290801673 13.7368876813875094, 234.8493417356832538 13.7073404463484767, 234.8606864126222717 13.6777865962651966, 234.8720570731951227 13.6482375499376918, 234.8830833198969401 13.6187270374915155, 234.8942578962761161 13.5892102040072000, 234.9053801470764142 13.5596778329073899, 234.9167589099882889 13.5301032212135421, 234.9279630763072362 13.5005515903067401, 234.9394192269006965 13.4709841687102436, 234.9508887096513661 13.4414226751736940, 234.9626309718141783 13.4118435576556774, 234.9742477502246629 13.3822830148562506, 234.9858310021840282 13.3527327039232198, 234.9970791630884435 13.3232199974438803, 235.0084942267340864 13.2936993451161918, 235.0186419329412502 13.2643038495101493, 235.0288272444620077 13.2349149253326068, 235.0401198046571380 13.2054328064297675, 235.0532620150219429 13.1757903603399633, 235.0624271216925081 13.1465153771828209, 235.0713600073557075 13.1172684944642093, 235.0793940345812700 13.0881099970756303, 235.0890500823631157 13.0588118578658747, 235.1001302413494045 13.0293921654755245, 235.1114135830976579 12.9999613924081761, 235.1209243704139737 12.9707237608108290, 235.1309020905796672 12.9414756652994853, 235.1414756824528354 12.9121812020434952, 235.1521051686026453 12.8828891505364300, 235.1634486053033584 12.8535402166422994, 235.1748378342097396 12.8241946970120964, 235.1866932403923727 12.7948147510022956, 235.1962591092761556 12.7656485148328525, 235.2079865871087918 12.7362952191002208, 235.2197326753089612 12.7069478742196740, 235.2313225721933634 12.6776155786555993, 235.2423722902041163 12.6483331655838960, 235.2530634953859305 12.6190905341801578, 235.2639518191064383 12.5898377703569100, 235.2744025920220849 12.5606318602069944, 235.2867725908210446 12.5312613936619748, 235.2991023667242985 12.5019022720519857, 235.3116716239582331 12.4725294412281773, 235.3219926194716152 12.4433657660418966, 235.3334198870870750 12.4141106634952525, 235.3448295696518926 12.3848381642486984, 235.3590631821656700 12.3552954060809768, 235.3671572194415944 12.3263093689396594, 235.3791241627797319 12.2969845358657945, 235.3921032502748858 12.2675769256364440, 235.4040318795581186 12.2382708373989573, 235.4133898130075124 12.2092018442350998, 235.4233087213997351 12.1800902646282907, 235.4339080986466115 12.1509255318467915, 235.4452235719082864 12.1217045745757837, 235.4567443237030773 12.0924703558084179, 235.4687492492635386 12.0631982532119988, 235.4810288740251849 12.0339094862614715, 235.4933593769876836 12.0046240089340035, 235.5055131848779126 11.9753620784343049, 235.5183936068819719 11.9460434003433491, 235.5313914414787746 11.9167221954071394, 235.5445277552505274 11.8873966214008568, 235.5579758501142749 11.8580513222656219, 235.5708596309736720 11.8287640873522850, 235.5855568216224754 11.7993272976514429, 235.5997530467545005 11.7699461619532091, 235.6118792700054314 11.7407565433979375, 235.6222863801276901 11.7117271088094661, 235.6370065832145997 11.6823236091692451, 235.6501351706685341 11.6530691111257187, 235.6620789000052980 11.6239274595492343, 235.6746660025543463 11.5947368831844280, 235.6884231604871331 11.5654509340061882, 235.7004295446835442 11.5363277617227080, 235.7116587817768050 11.5072743978447640, 235.7235065836390788 11.4781679472845699, 235.7365096551736485 11.4489676032299617, 235.7509681344467083 11.4196470655488547, 235.7663406604226850 11.3902542184105808, 235.7777363715495085 11.3612199442349784, 235.7886739886716043 11.3322339874586131, 235.8008113265921963 11.3031504556407096, 235.8129270659356678 11.2740769145603643, 235.8254455463878685 11.2449760862190988, 235.8379734895646891 11.2159103138154315, 235.8515159916051402 11.1867900343133702, 235.8657944078840103 11.1576136472980831, 235.8797318095176365 11.1284757052386034, 235.8937716656943167 11.0993373101898118, 235.9083287919161478 11.0701621526026965, 235.9230551243026355 11.0409807942066465, 235.9376740007601825 11.0118174850483133, 235.9515272763501912 10.9827297851745165, 235.9638445602442971 10.9537849358193409, 235.9770623676844821 10.9247485593680569, 235.9907218609045003 10.8956618896021116, 236.0047319410605553 10.8665530900843592, 236.0183309333073396 10.8374886511592958, 236.0323861690089302 10.8083929297650254, 236.0537151650615897 10.7647439316756586, 235.8067955133633973 10.7864349998059303, 235.6404746257572924 10.8009251269396263, 235.4886934161605154 10.8140812538595235, 235.3440743681663321 10.8265506526567350, 235.2013541677908677 10.8387871304147918, 235.0605785760583331 10.8507895529034926, 234.9266644391624368 10.8621511165711979, 234.7983134326703407 10.8729887160495498, 234.6742684848909448 10.8834132357353326, 234.5539738435579977 10.8934756929011449, 234.4326844057674464 10.9035680020322605, 234.3062264801270658 10.9140277809828401, 234.1842183967351616 10.9240715931438910, 234.0687460570606220 10.9335373293233324, 233.9561439769082654 10.9427259418076375, 233.8474210956636057 10.9515604135457068, 233.7435151522108470 10.9599707574453191, 233.6385624025299990 10.9684248104218582, 233.5358140067679642 10.9766660933163962, 233.4407131631540437 10.9842712723620792, 233.3422237141487017 10.9921074822316367, 233.2513957968668024 10.9993144684267641, 233.1514470230827101 11.0071956760925467, 233.0568672341269121 11.0146280042264575, 232.9714593141212902 11.0213255319210663, 232.8803341230215551 11.0284323244705966, 232.7943082344638981 11.0351214682241956, 232.7094524258490083 11.0416948896741296, 232.6269891539112962 11.0480614832390529, 232.5469229652692320 11.0542229776525041, 232.4651981313407134 11.0604848216034473, 232.3872682244131909 11.0664391550737431, 232.3089820002441002 11.0723973916263372, 232.2344266808455302 11.0780568264050938, 232.1612777882618559 11.0835918116480201, 232.0879579900154397 11.0891193380045809, 232.0165771813923357 11.0944847829428479, 231.9444953164284300 11.0998822668852739, 231.8732154220789994 11.1052019606719448, 231.8057772059855211 11.1102241836924787, 231.7386284223740347 11.1152083219001412, 231.6726527935756792 11.1200909547655851, 231.6064561948269045 11.1249729599094174, 231.5413069011251253 11.1297634611590315, 231.4780838222096122 11.1344005204152676, 231.4150219500268406 11.1390109034406830, 231.3534789037269661 11.1434985250841070, 231.2922763752998208 11.1479476253113834, 231.2321986804822416 11.1523031971472300, 231.1727759778447648 11.1565989554036538, 231.1144830584694887 11.1608020872666742, 231.0567419751295120 11.1649536385455743, 231.0002949603148465 11.1690023089748021, 230.9442330256014770 11.1730119569495638, 230.8887529573815129 11.1769692032590324, 230.8340953656575323 11.1808578017412277, 230.7801047938868351 11.1846889342885731, 230.7267933250123519 11.1884621644846547, 230.6741394301110120 11.1921793597432231, 230.6222024977055014 11.1958368476763042, 230.5710284673378965 11.1994319110294054, 230.5203688901653436 11.2029818304778850, 230.4702850162558434 11.2064827482388765, 230.4211332149644136 11.2099109379701982, 230.3722347960824379 11.2133125719045719, 230.3238995148852553 11.2166669987619017, 230.2759727552675599 11.2199848672675309, 230.2288337046649644 11.2232410798167255, 230.1821784107627877 11.2264562859272328, 230.1360978921009064 11.2296246903372410, 230.0904502464950951 11.2327559868123661, 230.0451126661348269 11.2358585089428757, 230.0005121694876493 11.2389042679814661, 229.9563201538447288 11.2419152341291504, 229.9126038169218020 11.2448872011930661, 229.8693914420437352 11.2478185506150439, 229.8266141936540805 11.2507140177014868, 229.7844926752383685 11.2535594487366986, 229.7426279584774136 11.2563810618931104, 229.7011060076232241 11.2591734075795618, 229.6601354388789673 11.2619231614295536, 229.6197463420455733 11.2646286372288937, 229.5797488137805829 11.2673023162613966, 229.5399124326949050 11.2699591633166492, 229.5003744155744698 11.2725904639474663, 229.4613780020166018 11.2751808122798849, 229.4229479289674032 11.2777288707644558, 229.3846678777064767 11.2802613604292219, 229.3465203971857989 11.2827794526242791, 229.3092627460602273 11.2852352682303039, 229.2721541795532971 11.2876759727370040, 229.2355028971706190 11.2900822055440635, 229.1990236077036229 11.2924720972138957, 229.1627789235940611 11.2948417900965428, 229.1268004674435872 11.2971894009815745, 229.0910977852282429 11.2995144425355125, 229.0558429789213051 11.3018062999907833, 229.0210984390760132 11.3040612741932698, 228.9866394069154012 11.3062935182439883, 228.9523786369067579 11.3085085479184464, 228.9184628476487262 11.3106973739432899, 228.8847576778044015 11.3128684166155438, 228.8514037966511125 11.3150131009990815, 228.8184344402544639 11.3171295215342020, 228.7856962146690876 11.3192272250004820, 228.7530968391216106 11.3213119416556740, 228.7207523182553359 11.3233766438828898, 228.6886580791903896 11.3254217054488961, 228.6568808000483273 11.3274431670438886, 228.6255699416132074 11.3294320811176288, 228.5943557727729285 11.3314109976851860, 228.5633199203972481 11.3333750202213430, 228.5325366678424643 11.3353197347103816, 228.5019329259182825 11.3372496289215654, 228.4715394680745533 11.3391629188434351, 228.4413945509315909 11.3410573865564004, 228.4114629408693133 11.3429352267369978, 228.3817510016937433 11.3447961341559349, 228.3522475214021483 11.3466408530416700, 228.3230615139326005 11.3484629748935983, 228.2940740736275984 11.3502696641036316, 228.2653336387778324 11.3520581199663511, 228.2367430860697368 11.3538341663225300, 228.2082916103096011 11.3555984904911416, 228.1800368130806191 11.3573477475154032, 228.1520392237890462 11.3590784464354115, 228.1243947354944055 11.3607850493609046, 228.0969443603411833 11.3624769794926568, 228.0696393456309181 11.3641571482789345, 228.0424929933024316 11.3658248267828181, 228.0154106641687122 11.3674855739070697, 227.9885578563494164 11.3691297953498367, 227.9618650794217558 11.3707615940650122, 227.9353348111926039 11.3723808773752566, 227.9089933044652696 11.3739861801534410, 227.8828228745919375 11.3755785815686252, 227.8568634996878473 11.3771558345669810, 227.8309964239478518 11.3787248265793970, 227.8053094676697867 11.3802805503902693, 227.7797848238557492 11.3818240807616586, 227.7544332388539488 11.3833548536521434, 227.7292690741718388 11.3848721031974875, 227.7042771343964205 11.3863767514056438, 227.6794424865365158 11.3878696987456021, 227.6547547108999652 11.3893515833190406, 227.6302153125823224 11.3908223637730650, 227.6058446822500514 11.3922809322273206, 227.5815837284566783 11.3937306712904363, 227.5574768187691745 11.3951691153037267, 227.5335303503333364 11.3965959501440786, 227.5097275399122623 11.3980121642391303, 227.4860553007769681 11.3994185320703085, 227.4625029322781415 11.4008156893324628, 227.4390700032320183 11.4022036943938332, 227.4157514915810907 11.4035828609830805, 227.3925662525238351 11.4049521734721111, 227.3695676411417423 11.4063087093581785, 227.3466880305288953 11.4076562680319267, 227.3239817936706970 11.4089918767020748, 227.3013618133060163 11.4103203927983330, 227.2788626998114694 11.4116399330885390, 227.2564905837964488 11.4129501940688858, 227.2341471861257958 11.4142566063334225, 227.2119503831812608 11.4155527167971407, 227.1898755316247218 11.4168399144206791, 227.1679212759833035 11.4181183068200607, 227.1461045130949401 11.4193870060619087, 227.1244248889431105 11.4206460692871250, 227.1028554367275092 11.4218969989113255, 227.0813921445946733 11.4231400422550955, 227.0600099683273072 11.4243765834363167, 227.0387800565281395 11.4256027995450999, 227.0176858866713019 11.4268196233056614, 226.9967364182936080 11.4280266090393461, 226.9758565800003680 11.4292278308191211, 226.9550385935672239 11.4304237238189828, 226.9342329016720612 11.4316169579195979, 226.9135052379878346 11.4328040202420365, 226.8929749480174962 11.4339785612945999, 226.8725374557916155 11.4351462062953271, 226.8522123581987842 11.4363059371511309, 226.8319968195331171 11.4374579340044740, 226.8118864201224483 11.4386024598255549, 226.7918595656055913 11.4397406845346215, 226.7719343835069594 11.4408716721420678, 226.7520928931489834 11.4419963969996026, 226.7323585007395934 11.4431136486168281, 226.7126918304158494 11.4442255234874661, 226.6930802682925616 11.4453327000335001, 226.6735784057245553 11.4464323336035516, 226.6541678320596986 11.4475254147734731, 226.6348499723014811 11.4486118924986169, 226.6156086420508586 11.4496926332953510, 226.5964513089188301 11.4507672681319903, 226.5773802830682087 11.4518356983330936, 226.5583938982743746 11.4528980320372344, 226.5394514986697629 11.4539563930477577, 226.5205720112765277 11.4550098145152575, 226.5017744116919118 11.4560573339754512, 226.4830830479990880 11.4570977194971331, 226.4644630477084490 11.4581327889288342, 226.4458929607690152 11.4591636594085848, 226.4273420018072045 11.4601919179307483, 226.4089327375779703 11.4612113075504123, 226.3905321797907959 11.4622286455833944, 226.3721760724207854 11.4632421133510061, 226.3540415653077389 11.4642427211471709, 226.3361333516323270 11.4652302893049640, 226.3181669859150134 11.4662192771479354, 226.3002739486517783 11.4672030229445188, 226.2824320913053100 11.4681826620402063, 226.2646422367285197 11.4691581650898762, 226.2469095834721315 11.4701292831078110, 226.2292344049324697 11.4710960160929307, 226.2116353879820565 11.4720574419655836, 226.1941018513796280 11.4730141135587900, 226.1766306716323811 11.4739662027049114, 226.1592231105862822 11.4749136616747478, 226.1418925461015306 11.4758558408019180, 226.1246140672760987 11.4767939954951359, 226.1074024905091449 11.4777274041279629, 226.0902695214741414 11.4786555042766718, 226.0731674626649976 11.4795806696915488, 226.0561148944835281 11.4805019915932753, 226.0391203976556085 11.4814190596915857, 226.0221853383620783 11.4823318209415373, 226.0053302814421556 11.4832392822444014, 225.9885536989872605 11.4841415383638772, 225.9718003975531531 11.4850413028522933, 225.9550662527171312 11.4859387811404918, 225.9383869128346873 11.4868322431939074, 225.9217536701528388 11.4877221247974735, 225.9051656781837778 11.4886084777362605, 225.8886411839923767 11.4894904303679706, 225.8721818201447036 11.4903679195481985, 225.8557774564206682 11.4912414492826134, 225.8394241488472858 11.4921112224739144, 225.8231345766313609 11.4929766430689355, 225.8068834000266065 11.4938389402025560, 225.7906841315520694 11.4946974768609138, 225.7745264906774594 11.4955527559106727, 225.7584156584585173 11.4964045403916124, 225.7423465946622230 11.4972530808839259, 225.7263306551091091 11.4980978487175864, 225.7103637501322737 11.4989390503740179, 225.6944403536005268 11.4997769586410374, 225.6785731333581566 11.5006109868170263, 225.6627606321947610 11.5014412173747989, 225.6469855377237934 11.5022684764168162, 225.6312478555481391 11.5030927722805156, 225.6155505187082611 11.5039139764861726, 225.5999034371537562 11.5047316362784287, 225.5843036923903924 11.5055458998999516, 225.5687372937137525 11.5063574287778980, 225.5532030184873520 11.5071662870799507, 225.5377227249360317 11.5079714709823211, 225.5222898787817769 11.5087732957038735, 225.5069090090458701 11.5095715644305443, 225.4915549235071524 11.5103674479764884, 225.4762447625165578 11.5111601660590104, 225.4609749326404540 11.5119498939062872, 225.4457365038296643 11.5127370489516903, 225.4305250723085123 11.5135218388634897, 225.4153505895347962 11.5143038171354597, 225.4002092546294307 11.5150831649260734, 225.3851016085648098 11.5158598654308175, 225.3700330195559616 11.5166336842156163, 225.3550142447416533 11.5174041464569346, 225.3400350352194152 11.5181717255997285, 225.3250842761335662 11.5189369296463209, 225.3101705090120106 11.5196993830341832, 225.2952945149421566 11.5204590600330974, 225.2804449879838273 11.5212164731367626, 225.2656236019609821 11.5219715538304612, 225.2508347977908443 11.5227241118179400, 225.2360836991663291 11.5234739286214012, 225.2213701223733437 11.5242210219101882, 225.2066922232514514 11.5249654823094687, 225.1920523314329614 11.5257072167331263, 225.1774439551033993 11.5264465188925040, 225.1628688639249276 11.5271833193649442, 225.1483231609240931 11.5279177960410184, 225.1338080113109754 11.5286499054960867, 225.1193156868265817 11.5293799896077189, 225.1048406914387385 11.5301082903624863, 225.0903927203178796 11.5308343936089983, 225.0759731997254676 11.5315582445733433, 225.0615726061145381 11.5322802576354757, 225.0471948914258746 11.5330002677501433, 225.0328448253008276 11.5337180770388592, 225.0185250472502503 11.5344335803595950, 225.0042336758099850 11.5351468651141396, 224.9899666840143198 11.5358581082705030, 224.9757293128529625 11.5365670953030204, 224.9615188349461619 11.5372739482972069, 224.9473343603625040 11.5379787112565051, 224.9331867190003038 11.5386809398691899, 224.9190651590865002 11.5393810912945245, 224.9049589851297810 11.5400796146967703, 224.8908763596499512 11.5407761760390457, 224.8768203267530055 11.5414706560991558, 224.8627911626619493 11.5421630507644473, 224.8487873231412664 11.5428534304604344, 224.8348025935600560 11.5435420547181717, 224.8208432662335667 11.5442286728690391, 224.8069064464890232 11.5449134088227350, 224.7929952890955576 11.5455961416041113, 224.7790961745725156 11.5462774242215751, 224.7652157298573457 11.5469569934605225, 224.7513584997170994 11.5476346729869821, 224.7375268209609089 11.5483103768236575, 224.7237220902758565 11.5489840576921914, 224.7099413765588451 11.5496558393201507, 224.6961637810842660 11.5503265461539364, 224.6824171483852126 11.5509950911998516, 224.6686890557825791 11.5516619670280267, 224.6549772382042534 11.5523272659267597, 224.6412812909761669 11.5529910072228450, 224.6276091034440014 11.5536528930102023, 224.6139594562444017 11.5543129777216969, 224.6003182497867385 11.5549718025802619, 224.5867005368071148 11.5556288004592993, 224.5731010661897926 11.5562841765020163, 224.5595318451183573 11.5569374888610756, 224.5459817047652962 11.5575891644592375, 224.5324427190808478 11.5582395019210420, 224.5189143401585454 11.5588885230366429, 224.5054022183514348 11.5595360233723632, 224.4919123846912044 11.5601817897050676, 224.4784375362928017 11.5608260941168410, 224.4649757674634429 11.5614690093784702, 224.4515271517113888 11.5621105363332521, 224.4380954082662356 11.5627505474351384, 224.4246791510049945 11.5633890977143405, 224.4112755960894674 11.5640262896338815, 224.3978846737758772 11.5646621293418335, 224.3845066428590371 11.5652966117998073, 224.3711457528081610 11.5659295969039704, 224.3577977362123761 11.5665612362988721, 224.3444652819518979 11.5671914448567392, 224.3311485458364416 11.5678202246759660, 224.3178463670832343 11.5684476215622389, 224.3045557510956485 11.5690737397591139, 224.2912636805598368 11.5696990018557990, 224.2779812886730895 11.5703230455223807, 224.2647169075784745 11.5709456114839053, 224.2514653724545894 11.5715668719389502, 224.2382246445122291 11.5721868961484091, 224.2249954647945458 11.5728056663998675, 224.2117774258872487 11.5734232007998141, 224.1985677641199004 11.5740395866003460, 224.1853739310532205 11.5746546100467338, 224.1721921301376881 11.5752683925316280, 224.1590180429057853 11.5758810639388887, 224.1458517540423827 11.5764926247218618, 224.1326993443378797 11.5771029132381766, 224.1195552562876117 11.5777120902492623, 224.1064199000646795 11.5783201500428135, 224.0932922280796049 11.5789271253297930, 224.0801718772115123 11.5795330298151136, 224.0670575303321073 11.5801378997012527, 224.0539473086348039 11.5807417811433293, 224.0408440714022333 11.5813446074286652, 224.0277532395576827 11.5819462641829940, 224.0146726415871967 11.5825468155495450, 224.0016005777073929 11.5831463107956161, 223.9885357303077740 11.5837447873853687, 223.9754767473355059 11.5843422797862061, 223.9624200726219385 11.5849388562229869, 223.9493664901772547 11.5855344996028045, 223.9363221822949299 11.5861291150974708, 223.9232837412845640 11.5867227707995344, 223.9102514687340602 11.5873154735786805, 223.8972278339578850 11.5879072106865273, 223.8842074228049341 11.5884980596550555, 223.8711897945752867 11.5890880278437507, 223.8581768384312625 11.5896771077476899, 223.8451691054755202 11.5902653131403053, 223.8321650096256690 11.5908526677333601, 223.8191624724303210 11.5914391819364901, 223.8061618009825793 11.5920248568939055, 223.7931629563950935 11.5926096948439756, 223.7801640483893095 11.5931936739012809, 223.7671670080413833 11.5937768052847883, 223.7541730621474301 11.5943591186324095, 223.7411823205456471 11.5949406428960362, 223.7281945822359148 11.5955214095320009, 223.7152092203553195 11.5961014400608047, 223.7022255713057461 11.5966807499123217, 223.6892422590755416 11.5972592901638460, 223.6762589726463375 11.5978370357118514, 223.6632763821548906 11.5984140565170044, 223.6502941596621667 11.5989903554876275, 223.6373122485587146 11.5995659928159363, 223.6243300458003489 11.6001409101511435, 223.6113474183810581 11.6007150945224744, 223.5983643014767210 11.6012885646925472, 223.5853804742069997 11.6018613808046673, 223.5723949789533549 11.6024337740753829, 223.5594084415188831 11.6030053638418362, 223.5464202437137260 11.6035763342931428, 223.5334298265308917 11.6041467476705247, 223.5204368671160182 11.6047166055632065, 223.5074413311786543 11.6052858741749585, 223.4944432982269404 11.6058545207680535, 223.4814424785578808 11.6064225703417829, 223.4684383277624136 11.6069900727135007, 223.4554303426215824 11.6075570640285157, 223.4424179562224992 11.6081235823943523, 223.4294005333658788 11.6086896685846472, 223.4163767564456577 11.6092554251419369, 223.4033493491641593 11.6098205678131965, 223.3903182963034055 11.6103850983903456, 223.3772834961593503 11.6109490258626220, 223.3642450371695531 11.6115123420543505, 223.3512033206650358 11.6120750138235813, 223.3381552833177466 11.6126372901045816, 223.3251009602248871 11.6131991535745271, 223.3120397912730937 11.6137606354857805, 223.2989722102153110 11.6143216904895947, 223.2858985034939394 11.6148822884757639, 223.2728171532854446 11.6154425337153047, 223.2597285678842525 11.6160023859097290, 223.2466317184571665 11.6165619096001063, 223.2335277664750777 11.6171210135613414, 223.2204169764060566 11.6176796739163031, 223.2072988293896003 11.6182379214860720, 223.1941722853886176 11.6187958206725579, 223.1810361052819758 11.6193534462533226, 223.1678913125293775 11.6199107220579378, 223.1547381380204058 11.6204676270292602, 223.1415754377222811 11.6210242292901071, 223.1284015147917614 11.6215806294810378, 223.1152151257173557 11.6221368962474347, 223.1020209030159833 11.6226927309534513, 223.0888180899151791 11.6232481781418482, 223.0756052319352136 11.6238033234601996, 223.0623811454728411 11.6243582333952205, 223.0491451294250567 11.6249129435087841, 223.0358968024123385 11.6254674694606805, 223.0226367869022113 11.6260217673401947, 223.0093615337413837 11.6265760397256166, 222.9960678207886531 11.6271304645915841, 222.9827655838396936 11.6276844535645623, 222.9694554206600969 11.6282379715353894, 222.9561342545889318 11.6287911942133846, 222.9427998983108523 11.6293442423045565, 222.9294510268505860 11.6298971849561319, 222.9160884180237190 11.6304499718576011, 222.9027074603666563 11.6310028546020856, 222.8893176033855070 11.6315552995097704, 222.8759211426466607 11.6321071795064235, 222.8625124070458412 11.6326588071381831, 222.8490832134951631 11.6332106252531098, 222.8356348319168205 11.6337625545451147, 222.8221730868968393 11.6343142716344818, 222.8086998368636671 11.6348656728601068, 222.7952032410212837 11.6354173891396151, 222.7816844858272418 11.6359693461163598, 222.7681514532171434 11.6365211164074118, 222.7546094596882540 11.6370724159062018, 222.7410496054541227 11.6376237118867820, 222.7274689117791979 11.6381751538767553, 222.7138741945800575 11.6387263792080695, 222.7002655263083852 11.6392773809202303, 222.6866375324850083 11.6398284332481410, 222.6729866912277771 11.6403797107276681, 222.6593141329916534 11.6409311470295815, 222.6456207319742191 11.6414826900592825, 222.6319141538511417 11.6420339437191078, 222.6181898888900719 11.6425851340134141, 222.6044497077729432 11.6431361669641209, 222.5906859946142617 11.6436874213258434, 222.5768997746848186 11.6442388379903292, 222.5630916264524330 11.6447903810514184, 222.5492639055913457 11.6453419268984586, 222.5354268513521276 11.6458929635110628, 222.5215672763444275 11.6464441414515800, 222.5076782329805951 11.6469957955623027, 222.4937638625381169 11.6475477129753546, 222.4798292363335577 11.6480996383536564, 222.4658732608358775 11.6486516197716785, 222.4519005455349543 11.6492034280629078, 222.4379138599462351 11.6497549259799520, 222.4239108831788769 11.6503062233066377, 222.4098822394064712 11.6508577672935250, 222.3958278149373484 11.6514095560063904, 222.3817501135741566 11.6519614625957857, 222.3676471868184592 11.6525135736862762, 222.3535187113670872 11.6530658977330486, 222.3393601721838877 11.6536186413909473, 222.3251663416669999 11.6541720424622000, 222.3109466623493802 11.6547256460788766, 222.2967040816853626 11.6552793072878345, 222.2824345096871639 11.6558332118278578, 222.2681376654351197 11.6563873657033454, 222.2537934125687684 11.6569426978119299, 222.2394296278619663 11.6574979009650406, 222.2250456168259518 11.6580530033773524, 222.2106332312147856 11.6586083764684449, 222.1961901634218748 11.6591641190260660, 222.1817259895392738 11.6597197839939728, 222.1672323459247878 11.6602757492814497, 222.1527060469099695 11.6608321525856535, 222.1381498752830623 11.6613888587292571, 222.1235645886087013 11.6619458258008599, 222.1089488152721856 11.6625031085986155, 222.0943054474932126 11.6630605689926643, 222.0796369850670828 11.6636180879316864, 222.0649326370145218 11.6641761438978122, 222.0501916741798993 11.6647347600702851, 222.0354200415984565 11.6652936614623552, 222.0206255050645439 11.6658524948370594, 222.0058055009197631 11.6664113692263243, 221.9909317003409228 11.6669715336889777, 221.9760187813601533 11.6675323245149656, 221.9610674740686136 11.6680936993524185, 221.9460834295307166 11.6686553999321863, 221.9310575638700982 11.6692178166093186, 221.9159984711472191 11.6697805626173459, 221.9009259266190099 11.6703427671973010, 221.8858296896020477 11.6709048744522352, 221.8706995944916969 11.6714673207687980, 221.8555326260529625 11.6720302285323623, 221.8403304885915759 11.6725935149984181, 221.8250972499788816 11.6731569963287445, 221.8098195614857389 11.6737212391253511, 221.7944889260295156 11.6742865963672013, 221.7791202134384889 11.6748524179399720, 221.7637180402759896 11.6754184975323128, 221.7482700456506564 11.6759853535369480, 221.7327669514019988 11.6765533683674345, 221.7172115229157043 11.6771224104400737, 221.7016211571630038 11.6776917309543347, 221.6860028019631557 11.6782610288026678, 221.6703447483006642 11.6788307904666926, 221.6546244431609409 11.6794019527691013, 221.6388611839107909 11.6799736915431538, 221.6230487052664841 11.6805462579741306, 221.6071946734359415 11.6811193203433437, 221.5913075585578440 11.6816925165910792, 221.5753864703945908 11.6822658761608444, 221.5594131535235931 11.6828401465168774, 221.5433904492093404 11.6834151973097651, 221.5273308964320336 11.6839905000560975, 221.5112244756882376 11.6845664577840918, 221.4950649900503663 11.6851433129982265, 221.4788646116662392 11.6857205548694267, 221.4626020103556243 11.6862990436987797, 221.4462705120650412 11.6868790352438801, 221.4298859924452358 11.6874598673816568, 221.4134506856235589 11.6880414365643013, 221.3969754781638244 11.6886232905533163, 221.3804605137588624 11.6892054142854072, 221.3638996850392004 11.6897880441166127, 221.3472772159433077 11.6903718019564433, 221.3305813530340060 11.6909571427546126, 221.3137711140899171 11.6915456840291085, 221.2969116219964576 11.6921348014786908, 221.2800176036296591 11.6927238980806685, 221.2630934336358735 11.6933127927655107, 221.2461192125695106 11.6939022661089460, 221.2290863538799215 11.6944926448517066, 221.2119945040124946 11.6950839284617025, 221.1948675705596088 11.6956751636199172, 221.1776935519548317 11.6962668126592853, 221.1604303534516021 11.6968605094735594, 221.1430823375206387 11.6974560610127813, 221.1256729793850582 11.6980525325160976, 221.1082343240083787 11.6986486654978012, 221.0907777951847493 11.6992440115996175, 221.0732731529912485 11.6998397355013690, 221.0556760649141665 11.7004375334995672, 221.0379809653518350 11.7010375956696304, 221.0201910780059507 11.7016397730786199, 221.0023326505253749 11.7022430375102857, 220.9844141227268608 11.7028470498724388, 220.9664267865855720 11.7034521267921079, 220.9483618371744740 11.7040585853336694, 220.9302181846820758 11.7046664471111175, 220.9120117963108498 11.7052750889676211, 220.8937461626256891 11.7058843638523342, 220.8754296372314911 11.7064939432009609, 220.8570353831405555 11.7071048211223498, 220.8385387414597858 11.7077179002593432, 220.8199419597752353 11.7083330701279866, 220.8012542966679348 11.7089499601218403, 220.7824976140127831 11.7095677351779131, 220.7636932618535184 11.7101855873401206, 220.7448115762650502 11.7108046009619358, 220.7258449069578603 11.7114250382169285, 220.7067902066016245 11.7120469892335457, 220.6876435492174267 11.7126705751821731, 220.6684018412082366 11.7132958852971534, 220.6490775002803275 11.7139224419373367, 220.6296751617489633 11.7145500551851551, 220.6101884901056565 11.7151789348703232, 220.5906226553498186 11.7158088720647999, 220.5709709286423674 11.7164400892134566, 220.5512576667551059 11.7170716871887297, 220.5314614383965477 11.7177044199639759, 220.5115590022702179 11.7183390981858260, 220.4915452243133416 11.7189758769758754, 220.4714307799504240 11.7196143463432527, 220.4512468588942227 11.7202533715875568, 220.4309992066258417 11.7208927312753612, 220.4106498399647478 11.7215337511401767, 220.3901880983321462 11.7221767796176426, 220.3696269742781340 11.7228213298248747, 220.3489604038603034 11.7234675876106191, 220.3281690552258851 11.7241162000989156, 220.3072756756530168 11.7247663403946412, 220.2862824116060096 11.7254179062737975, 220.2651764715906495 11.7260713139721826, 220.2439627765920136 11.7267263625539524, 220.2226597862533310 11.7273823863618976, 220.2012604090785430 11.7280396049063711, 220.1797602369004778 11.7286981429156398, 220.1581417345546754 11.7293585718312805, 220.1364090861307830 11.7300207161664911, 220.1145235049651490 11.7306858616886558, 220.0924773395388172 11.7313542241099480, 220.0703026463932019 11.7320246749542285, 220.0480152578880109 11.7326966446598480, 220.0256193313577455 11.7333699618235077, 220.0031393234814630 11.7340437772018173, 219.9805459909598255 11.7347190432236310, 219.9578262375325153 11.7353961632678505, 219.9350228461188124 11.7360736819773805, 219.9120955538539874 11.7367529071657000, 219.8890352094786351 11.7374341046477060, 219.8658230573198296 11.7381178519777958, 219.8424378550896279 11.7388048003128542, 219.8189420393968305 11.7394928593222510, 219.7954051231405685 11.7401797339257250, 219.7717126788438691 11.7408691262540579, 219.7478364883711208 11.7415619025218767, 219.7238247217937896 11.7422564542140329, 219.6876080273496825 11.7432997520321258, 219.6987523783389520 11.7853029348368352, 219.7061791771076571 11.8133127052677054, 219.7135986549972699 11.8413287509590859, 219.7210947404915657 11.8693483800538981, 219.7285881728042796 11.8973741241818960, 219.7359476924964099 11.9254261184938049, 219.7433492070179000 11.9534995743634784, 219.7507477436130330 11.9815790420429416, 219.7579850993606385 12.0096695496598649, 219.7652250046039342 12.0377658721523719, 219.7725553247667563 12.0658652068576604, 219.7800022085925491 12.0939667193907923, 219.7873408946113614 12.1220775512220698, 219.7950743482863629 12.1501817176844593, 219.8021390085507676 12.1783129843265812, 219.8093731982575889 12.2064422366637455, 219.8167053719220974 12.2345716176982222, 219.8241449129861564 12.2627034586466905, 219.8313191008305978 12.2908495551467496, 219.8387108569568795 12.3189946085297830, 219.8460894153990637 12.3471459191799120, 219.8532640728367369 12.3753095044633206, 219.8601696000659160 12.4034874078654624, 219.8674454815513286 12.4316594207246638, 219.8745707848169104 12.4598419912782550, 219.8816850376582863 12.4880175631535977, 219.8889121191596416 12.5161815295508241, 219.8961929097609413 12.5443496532764520, 219.9035207113772401 12.5725221394411850, 219.9108000506688256 12.6007019866288559, 219.9180033535190546 12.6288900488843403, 219.9252926239190629 12.6570812287821681, 219.9325837932304353 12.6852781632398539, 219.9416672227909828 12.7134247386159469, 219.9543961131030585 12.7414629674117563, 219.9609663350123014 12.7696974747126752, 219.9637127246121509 12.7980546220564388, 219.9693396487065513 12.8263272760372882, 219.9763389821717681 12.8545627692792479, 219.9873479022917024 12.8826789124793954, 219.9942663404656287 12.9109285111587457, 220.0001191112024514 12.9392170379039477, 220.0060791742523350 12.9675078900646081, 220.0125259484729838 12.9957892679278366, 220.0204798710784360 13.0240294903622651, 220.0303293171268990 13.0522308974955514, 220.0363637765321414 13.0805716601223949, 220.0435221787505213 13.1088831469933211, 220.0503444749545849 13.1372106970433347, 220.0554559747872645 13.1655969105213551, 220.0637152732548998 13.1938911366292153, 220.0719544408212869 13.2221916261448413, 220.0809450265347778 13.2504744743735987, 220.0855198223371190 13.2788996753560333, 220.0951748739387028 13.3071731968698597, 220.1002723971644173 13.3355840090515123, 220.1073650537146023 13.3639288229455033, 220.1144815968071384 13.3922785026534399, 220.1215875630216487 13.4206341039521941, 220.1287352849993226 13.4489940064017972, 220.1370402481172732 13.4773238028523235, 220.1447839374467890 13.5056765105854222, 220.1521111762056648 13.5340476372248997, 220.1594759156825489 13.5624231739958425, 220.1672083186715554 13.5907929548752993, 220.1735074973374822 13.6191997960329587, 220.1797183184499715 13.6476015913110622, 220.1873653705166589 13.6759648322871517, 220.1929970825444229 13.7043955203467398, 220.2002836983144221 13.7327809785908634, 220.2072371138302174 13.7611822224267666, 220.2143098341883558 13.7895853682338103, 220.2215409219504920 13.8179892239169551, 220.2286146031840701 13.8464034432460039, 220.2359969003394440 13.8748137749151255, 220.2429905149833758 13.9032506382508085, 220.2501006645853749 13.9316990780717074, 220.2572072441929834 13.9601531121284097, 220.2642324537942500 13.9886151020148333, 220.2713546035055572 14.0170796066238470, 220.2784888319845038 14.0455492059331011, 220.2854618050496072 14.0740291669810969, 220.2923997657556754 14.1025156370404776, 220.2996432291302824 14.1309982530505547, 220.3069647405167757 14.1594839348555368, 220.3142063440979825 14.1879636489215741, 220.3212788520830827 14.2164393478506881, 220.3285570377223621 14.2449142699710301, 220.3357705561347473 14.2733966115232889, 220.3430038924011285 14.3018838045941319, 220.3501936701142938 14.3303777597299629, 220.3574521201990422 14.3588750717818545, 220.3646056912263020 14.3873809842522782, 220.3714125051088502 14.4159027848002559, 220.3785545334652625 14.4444198672097279, 220.3856337208090963 14.4729600249569028, 220.3927611381831184 14.5015207378316209, 220.4001050938870776 14.5300802442172756, 220.4070157686177538 14.5586581175413450, 220.4141741436548045 14.5872338305843900, 220.4213520876047312 14.6158142502689010, 220.4283400949778695 14.6444056730379835, 220.4351961122930561 14.6730063439768230, 220.4419879942652756 14.7016142084780572, 220.4491297933535918 14.7302168131950566, 220.4562863983109935 14.7588242341025122, 220.4632064466015891 14.7874440138399041, 220.4702124060514450 14.8160664519636125, 220.4773075838372449 14.8446914419828282, 220.4839436390709864 14.8733354361903700, 220.4909400907793326 14.9019738275908438, 220.4976830004601425 14.9306250294145304, 220.5046871352374751 14.9592735967586723, 220.5120298154663772 14.9879172096237898, 220.5191431523294341 15.0165728862980128, 220.5262490349775248 15.0452192623841103, 220.5332207143513585 15.0738593394066136, 220.5401179897107227 15.1025068650382295, 220.5471624571489713 15.1311552001949128, 220.5542495225764128 15.1598074722681364, 220.5611462416796371 15.1884706317373812, 220.5679511429215438 15.2171417192930516, 220.5747134507969065 15.2458192563325561, 220.5815516687183049 15.2744996978238152, 220.5883461733833144 15.3031866066804731, 220.5952718645040704 15.3318669234705656, 220.6021707515394894 15.3605449417647471, 220.6091175733615160 15.3892267262936802, 220.6161856756119732 15.4179100903335513, 220.6230988135851874 15.4466032398149729, 220.6301581993917296 15.4752972168452896, 220.6372147494944045 15.5039964430272246, 220.6444441175555085 15.5326957057448869, 220.6513662353943062 15.5614092262724686, 220.6584249249493439 15.5901238422739468, 220.6656150400222600 15.6188559151084991, 220.6725666951840594 15.6476172352274006, 220.6794748558619972 15.6763848779239545, 220.6865817604997630 15.7051516701513965, 220.6936357220202467 15.7339250506465902, 220.7007661076806073 15.7627011863723077, 220.7078723698911062 15.7914830407443709, 220.7148087278339403 15.8202749134539626, 220.7215739629969562 15.8490768265738264, 220.7283696407323532 15.8778828202649382, 220.7350802981979427 15.9066906071818064, 220.7416702149522507 15.9355009310670663, 220.7481918200226971 15.9643182516010249, 220.7548889450735601 15.9931353702346524, 220.7613380771931304 16.0219647648577634, 220.7677626895558092 16.0507998368716578, 220.7746364759300377 16.0796266327909585, 220.7812760232247626 16.1084652724760176, 220.7879783037277264 16.1373070028008776, 220.7945420930387002 16.1661577373793826, 220.8003749786528260 16.1950206147845002, 220.8065617769120479 16.2238629586943617, 220.8128621961369333 16.2527069132252286, 220.8191817781748512 16.2815552456965129, 220.8255725901924507 16.3104064262141080, 220.8322066930488177 16.3392554116777653, 220.8387268829000334 16.3681126612887446, 220.8455734888675579 16.3969652844466474, 220.8521103354397894 16.4258318847736930, 220.8587076063147094 16.4547016260165471, 220.8645847859068567 16.4836114740111590, 220.8712379210808763 16.5125184940503225, 220.8780366528559398 16.5414260978017715, 220.8844439639942436 16.5703499436321806, 220.8910779637470796 16.5992719915153337, 220.8980535530162683 16.6281888886635407, 220.9049801590114726 16.6571120173582976, 220.9120543709435367 16.6860356422276155, 220.9194018674333790 16.7149560939354274, 220.9275853956411879 16.7438569742157100, 220.9337514391982040 16.7728073785344201, 220.9389458499302350 16.8017760252213293, 220.9442633217356047 16.8307458476351215, 220.9495797696569923 16.8597204501495881, 220.9576980259738264 16.8886184325720556, 220.9646433111029467 16.9175552950014456, 220.9706915454232785 16.9465229738655516, 220.9797360847118171 16.9754084990557104, 220.9858503429987877 17.0043838123896194, 220.9958092372052647 17.0332524233293618, 221.0051547332684834 17.0621516662596875, 221.0123955258806348 17.0911251847201484, 221.0184945331998847 17.1201365065583708, 221.0265358812493162 17.1490962373539766, 221.0342592249748179 17.1780698850797862, 221.0416971724159225 17.2070564925110219, 221.0492649287550080 17.2360440209217529, 221.0574163920278750 17.2650193215307297, 221.0642376484496765 17.2940378146577451, 221.0712507672822369 17.3230554066909477, 221.0750035058534024 17.3521530123523817, 221.0833825984780106 17.3811014281199263, 221.1012000639443045 17.4097816163964545, 221.1234697960219933 17.4383372244083148, 221.1446009049126360 17.4669299947537660, 221.1659814111733908 17.4955196829968251, 221.1862074950514341 17.5241471728012712, 221.1957570593854427 17.5530905108681665, 221.2038686914070240 17.5820804815569822, 221.2080601838380858 17.6111893256108196, 221.1988433214207248 17.6407165963388977, 221.1916363249929702 17.6702144711225309, 221.1877485885951558 17.6996199313913323, 221.1891656915406088 17.7288761977612204, 221.1968354291195453 17.7579563475948667, 221.2025406650257082 17.7870977090662272, 221.2096147692232648 17.8162040254308245, 221.2165160141038598 17.8453198054343645, 221.2224942246927526 17.8744666959394074, 221.2277119717738856 17.9036399876857466, 221.2332821021322786 17.9327909628593183, 221.2383170204656722 17.9619443245157626, 221.2442905425824904 17.9910751117225907, 221.2498363549150611 18.0202227059452653, 221.2557305326318726 18.0493647450938646, 221.2621416428434600 18.0784963864217474, 221.2691430202075935 18.1076155305098077, 221.2754988088338735 18.1367577199723300, 221.2813337865354413 18.1659193359810658, 221.2877855764635342 18.1950676780735883, 221.2953253951094723 18.2241907181451985, 221.3013599376515970 18.2533629946779001, 221.3064374132812020 18.2825671410777524, 221.3124537528991596 18.3117487398260970, 221.3182281059690695 18.3409416697505847, 221.3250634187268986 18.3701085799299300, 221.3330656593484491 18.3992464482553046, 221.3374356805543925 18.4284927546433543, 221.3395300092193736 18.4578084756215759, 221.3458224370075129 18.4870083936977103, 221.3522630302541927 18.5162084245159981, 221.3577068639017398 18.5454412770415153, 221.3641904024743212 18.5746487549762911, 221.3715279110405447 18.6038361783344079, 221.3767990322102150 18.6330869316894123, 221.3800267733186331 18.6624002609262085, 221.3827362009375577 18.6917325593055210, 221.3870286297943437 18.7210239623286085, 221.3954345644621355 18.7502025136998931, 221.3995412872705231 18.7795077426605879, 221.4052686287405720 18.8087667836010581, 221.4116141403480924 18.8380079579074753, 221.4182075521312925 18.8672463620802873, 221.4234075461477289 18.8965286224821760, 221.4297424895057134 18.9257828881485999, 221.4381330032734922 18.9549830454996382, 221.4437786009013962 18.9842653900625713, 221.4516916820943777 19.0134876143406935, 221.4581724332157364 19.0427547246203943, 221.4643258332748417 19.0720353411072203, 221.4703040021612424 19.1013190923657241, 221.4757366350390271 19.1306161365466032, 221.4827138450010011 19.1598736469915174, 221.4886341154185061 19.1891653110444977, 221.4939175149503114 19.2184791927305980, 221.4996824220591805 19.2477836349604914, 221.5040993844800425 19.2771303361761817, 221.5096515242152009 19.3064491173592501, 221.5157897916339209 19.3357555188309327, 221.5254028688229937 19.3649680592404678, 221.5379303707704821 19.3941024988662392, 221.5502966622345014 19.4232455911104083, 221.5569858007410176 19.4525532673038555, 221.5662602299367734 19.4817920507718547, 221.5778712907634826 19.5109689308560554, 221.5906471454106281 19.5401169399273584, 221.6024846423248960 19.5692955531484998, 221.6125339520685600 19.5985288924894832, 221.6228556388711013 19.6277586119359704, 221.6323660623660317 19.6570154157516725, 221.6415036192033199 19.6862868958747796, 221.6440994493522965 19.7157478621153466, 221.6431790139832003 19.7453121777085840, 221.6474316280026073 19.7747340490760877, 221.6570225243102072 19.8040091392888229, 221.6647075506523663 19.8333421334356821, 221.6736770572801163 19.8626428791509682, 221.6816534356838986 19.8919757277428566, 221.6864937928417305 19.9214011980678016, 221.6879797046681517 19.9509252781368964, 221.6950232771162632 19.9803103316330919, 221.7007288044115398 20.0097516795446992, 221.7040268217931498 20.0392648175583936, 221.7074732176745897 20.0687776379662850, 221.7106187015569674 20.0983027922388793, 221.7176740678478097 20.1277217372505213, 221.7230474804684377 20.1571919249014684, 221.7277670534129754 20.1866843939325022, 221.7319372791985188 20.2161961796125986, 221.7405646670954127 20.2455863929184758, 221.7463882443915111 20.2750552242748441, 221.7538847956957397 20.3044764361599270, 221.7622793454201258 20.3338762065354963, 221.7701565144907363 20.3632943760536058, 221.7734189145131722 20.3928463603017818, 221.7781702146661189 20.4223602165639591, 221.7857704917922774 20.4517976945902156, 221.7905756422969432 20.4813176641481398, 221.7934115371495238 20.5108968160978833, 221.7963450988040961 20.5404769506598548, 221.8001359602207003 20.5700367282714680, 221.8054088753309259 20.5995586337327090, 221.8103228715708326 20.6290943850318556, 221.8166331239539772 20.6585946948034866, 221.8221241242079316 20.6881217627244531, 221.8259241657792984 20.7177000296168892, 221.8288535880878953 20.7473064170266852, 221.8317732952318693 20.7769167504911394, 221.8434864831883147 20.8062842966481227, 221.8548980732345797 20.8356638512113008, 221.8497146823973480 20.8655018099665917, 221.8425379707036313 20.8953868196195387, 221.8373773923880208 20.9252182013958574, 221.8382192559556358 20.9548855527560143, 221.8489009231280136 20.9842827888029326, 221.8672566919480857 21.0134697678678819, 221.8797273718959673 21.0428242378765376, 221.8887999809484199 21.0722772506783684, 221.8917645081734804 21.1019045712286442, 221.8997328109513774 21.1313958606348358, 221.8990926617780701 21.1611280411997136, 221.9019993443867236 21.1907616767497267, 221.9051040779034452 21.2203933634021809, 221.9093557913155053 21.2499967315714251, 221.9134297178703150 21.2796086472793569, 221.9116007488572677 21.3093879024833477, 221.9032882877631039 21.3393495526403925, 221.9060520607276032 21.3690080228472183, 221.9051334272646727 21.3987714957427535, 221.9034009241673573 21.4285605666680112, 221.9100285267250285 21.4581261494620072, 221.9160069827354107 21.4877163658233172, 221.9238932399250928 21.5172577423831370, 221.9293998902476801 21.5468681210289148, 221.9330707636324860 21.5765324978456761, 221.9363254486435721 21.6062118074986067, 221.9410037369507052 21.6358555652424549, 221.9455408147520643 21.6655067258760141, 221.9489016120563178 21.6951936278900881, 221.9527587732168001 21.7248704151448102, 221.9568600872159436 21.7545531876169207, 221.9622411699986344 21.7842141223478478, 221.9689664639684850 21.8138417552296744, 221.9756209612638997 21.8434747838713079, 221.9818735094456201 21.8731222678023371, 221.9874059330416856 21.9027929106306374, 221.9923440430283677 21.9324832584219216, 221.9971277815838278 21.9621812612543970, 222.0022569686708778 21.9918732336838509, 222.0073470417372619 22.0215696932603784, 222.0125447731021211 22.0512545135887450, 222.0181706962674753 22.0809182669923452, 222.0238933057023587 22.1105828125246830, 222.0295305341986136 22.1402531169874308, 222.0351237485043043 22.1699280426223453, 222.0404257554776848 22.1996143289707462, 222.0459155990378690 22.2292988830823006, 222.0512924341725807 22.2589899134932558, 222.0566673648636140 22.2886843763580522, 222.0618862307806296 22.3183864695259970, 222.0670553473142945 22.3480957600301977, 222.0723717418445631 22.3778070086866983, 222.0777839749534337 22.4075189965145825, 222.0831798395055046 22.4372347714922391, 222.0886434003691363 22.4669520385449459, 222.0940816859240101 22.4966733209650762, 222.0994527851256350 22.5263997499335709, 222.1047812730600697 22.5561306497441905, 222.1101155305965165 22.5858646932945106, 222.1154152126226791 22.6156029722921659, 222.1204420128612753 22.6453400487604668, 222.1255646965227015 22.6750652360078497, 222.1305329997703950 22.7047979141010146, 222.1355847788389895 22.7345316113037761, 222.1406216272999359 22.7642689947007923, 222.1456386712924882 22.7940101866968448, 222.1506385133021979 22.8237551068888891, 222.1555893547568417 22.8535046095124379, 222.1605043395214523 22.8832583261723137, 222.1653877637397443 22.9130161311541372, 222.1701197628978548 22.9427889794096842, 222.1746776288089222 22.9725778902955824, 222.1789441577180355 23.0023778465027746, 222.1836557253604099 23.0321689615527880, 222.1902440399031207 23.0619126298867805, 222.1954526487997725 23.0916966955946314, 222.2010831637907131 23.1214725487913562, 222.2083216385476589 23.1512082125607428, 222.2139515806716474 23.1809904051321993, 222.2171221061061317 23.2108420164642872, 222.2209885174087560 23.2406820492069599, 222.2264371356683625 23.2704868990150970, 222.2313264838332429 23.3003099105249731, 222.2360295056382427 23.3301410281423109, 222.2416143590607192 23.3599515096318804, 222.2470280979947290 23.3897696784447255, 222.2519457695757410 23.4196042624413252, 222.2572284978857340 23.4494320947136323, 222.2625351292995788 23.4792623413270860, 222.2678234451631738 23.5090961314884019, 222.2731187339419421 23.5389287177683109, 222.2783913238666287 23.5687606664830014, 222.2836896458870797 23.5985949596657747, 222.2889783775574983 23.6284325360171366, 222.2942692542079612 23.6582730743537084, 222.2995474628685599 23.6881169630518933, 222.3048186546705551 23.7179640409425119, 222.3100880876824306 23.7478141608984963, 222.3153559271631536 23.7776673080602770, 222.3206150332677282 23.8075236679407176, 222.3258698867078920 23.8373906039141410, 222.3311162164115444 23.8672686259859290, 222.3363674375739549 23.8971494474723585, 222.3416002241224021 23.9270336834210156, 222.3468409732332702 23.9569206201362341, 222.3520781788035947 23.9868105568549552, 222.3572950909472468 24.0167039334002865, 222.3625011870945229 24.0466004897417847, 222.3677192511808869 24.0764996046101665, 222.3729424320810040 24.1064014557794373, 222.3781468772039318 24.1362901049415974, 222.3833649202102833 24.1661637832156728, 222.3885678890742952 24.1960407689280856, 222.3937637688128746 24.2259208373355825, 222.3989420319749399 24.2558042638988809, 222.4041440839009169 24.2856899312707419, 222.4093321917982280 24.3155788397004535, 222.4144990636801822 24.3454711775703885, 222.4196730904844230 24.3753661753766302, 222.4248346882471878 24.4052643502490199, 222.4300062063282155 24.4351764711447856, 222.4351870688240922 24.4651031622580106, 222.4403525021423036 24.4950330549834590, 222.4455026492308889 24.5249661349346759, 222.4506599244951701 24.5549017980429021, 222.4558229849940574 24.5848400708727297, 222.4609842278840119 24.6147811469395705, 222.4661284181740086 24.6447254265929203, 222.4713101841024070 24.6746714424243159, 222.4764591915086385 24.7046210642576014, 222.4815193388476189 24.7345653488426223, 222.4865942845941618 24.7645009503866795, 222.4916659846251434 24.7944393662822975, 222.4967339979297662 24.8243805977292276, 222.5017992759311483 24.8543246133276234, 222.5068766617617939 24.8842710087474046, 222.5120706243436643 24.9142169965140106, 222.5176992594639671 24.9441541159433555, 222.5230551169869386 24.9741011722104318, 222.5290723867995268 25.0040333259883418, 222.5331869880003524 25.0340250878377617, 222.5376183126892897 25.0640178060554746, 222.5426224342733974 25.0939979418418204, 222.5478384862114467 25.1239750740119945, 222.5527734021785307 25.1539622861092163, 222.5574433522948254 25.1839591350383962, 222.5625189750877837 25.2139478160047545, 222.5680865706248426 25.2439260392117397, 222.5750931585504020 25.2738686682664557, 222.5818713705985488 25.3038199265285257, 222.5873131976027821 25.3338052354567935, 222.5917661569435779 25.3638151370287233, 222.5953573558004734 25.3938504356210331, 222.5981423237900287 25.4239096058506853, 222.6021066629948564 25.4539400323830769, 222.6070875480717746 25.4839460669764506, 222.6120740675006573 25.5139544754087133, 222.6170732825968344 25.5439650650433165, 222.6222362523172649 25.5739738307424211, 222.6271684386658478 25.6039912012795128, 222.6335610292155991 25.6339683652968340, 222.6407584509890683 25.6639224327095832, 222.6425063815139254 25.6940230383629142, 222.6465820115975021 25.7240645599181050, 222.6516161452992719 25.7540832404702051, 222.6567612331085684 25.7841014577184247, 222.6622771706098831 25.8141123513533195, 222.6675096863649514 25.8441331729572639, 222.6724462652574914 25.8741642350099852, 222.6771134454449168 25.9042048236113409, 222.6827850675147147 25.9342363969213565, 222.6931165989195733 25.9641633520688302, 222.6998107998099670 25.9941885113330500, 222.6993812296911130 26.0244039700988594, 222.7004828501916052 26.0545812839361020, 222.7068412638190296 26.0846224342528856, 222.7151250249200416 26.1146151271599116, 222.7223428546290904 26.1446381900456508, 222.7233614602698140 26.1748271206302583, 222.7251698748148669 26.2049974649882707, 222.7297580672671131 26.2350818941298201, 222.7350401377404410 26.2651345787466823, 222.7397478570217118 26.2952047135842477, 222.7441890163832170 26.3252841709139602, 222.7490415028251221 26.3553551043594396, 222.7538245648224802 26.3854301586803643, 222.7585301990882272 26.4155095328669063, 222.7633657664942177 26.4455877700282933, 222.7688255310274030 26.4756518790048681, 222.7734841245476787 26.5057393017970639, 222.7804994013528130 26.5357699997405270, 222.7892222416466268 26.5657611258812274, 222.7934201840647859 26.5958734025947372, 222.7976525280050168 26.6259869814919448, 222.8061529184382721 26.6559906322740723, 222.8082111146292732 26.6861657600329600, 222.8108775599187936 26.7163270320726909, 222.8149933055637462 26.7464524254358622, 222.8202949001197624 26.7765488881515772, 222.8301151846285961 26.8065289628167065, 222.8347576222037389 26.8366503143328003, 222.8375201822001657 26.8668265546497302, 222.8418110343539524 26.8969648288883043, 222.8465067625999154 26.9270946183010693, 222.8524537725533889 26.9571937291571544, 222.8574636362567389 26.9873195347062804, 222.8620005207471593 27.0174598523127969, 222.8671731236977678 27.0475856079521364, 222.8726715768208635 27.0777049164434551, 222.8775474503010514 27.1078426359606084, 222.8816119755437342 27.1380004347832653, 222.8869882262066255 27.1681224765070546, 222.8926632525168827 27.1982387555012899, 222.8956791014973078 27.2284267497900814, 222.8990635443943518 27.2586071020171801, 222.9037992898300047 27.2887541107547165, 222.9093687181026837 27.3188813347096549, 222.9147563759125603 27.3490153396272326, 222.9196081766385760 27.3791653776246413, 222.9243436031846386 27.4093204644486867, 222.9286080088612607 27.4394937878626308, 222.9336119064245736 27.4696539013534995, 222.9389694547906515 27.4998067414168901, 222.9467971585153805 27.5298969245293961, 222.9536775696234372 27.5600138138078385, 222.9590786061853294 27.5901713708527616, 222.9649273858108245 27.6203191385951392, 222.9707788876386587 27.6504687617074580, 222.9779598201788247 27.6805854587204365, 222.9832825767054203 27.7107527614695996, 222.9817568406602675 27.7410883808292539, 222.9874565001115059 27.7712230016942243, 222.9936425870779999 27.8013468434625679, 222.9960558499033709 27.8315712512636928, 223.0003219092063773 27.8617491055424331, 223.0057706188730720 27.8918979783894976, 223.0108205033266415 27.9220591651418673, 223.0159954833870017 27.9522189808752479, 223.0194101868348184 27.9824265788449296, 223.0236278179963563 28.0126150871228674, 223.0270783276969269 28.0428260124708935, 223.0284527756701323 28.0730933626796926, 223.0310594807002644 28.1033303987770076, 223.0333322930906093 28.1335778457469274, 223.0341180624730271 28.1638655435968630, 223.0377939193730583 28.1940800787361177, 223.0423453188266478 28.2242737368840118, 223.0473563566861230 28.2544573009189826, 223.0475810350745860 28.2847663252405717, 223.0468242129842622 28.3151021837166397, 223.0494697180610899 28.3453669498325986, 223.0551226685691404 28.3755718417024134, 223.0596599616459059 28.4058071837450221, 223.0644130602052826 28.4360386740751281, 223.0699211842025136 28.4662524123567628, 223.0775607745896423 28.4964128803653232, 223.0834267667081861 28.5266207293508955, 223.0946602925923798 28.5566915950314275, 223.1011121708191922 28.5868875504529214, 223.1057514664018413 28.6171320328370271, 223.1092717803553853 28.6474026359030276, 223.1131858521137303 28.6776599785361910, 223.1175135978419064 28.7079082719773027, 223.1224011054472101 28.7381437355217422, 223.1295408824392155 28.7683226027757506, 223.1386439433996998 28.7984522355943042, 223.1466096978199971 28.8286128295864472, 223.1512039324809678 28.8588623697965829, 223.1491767764530323 28.8892849121632658, 223.1495096696992277 28.9196477562618064, 223.1531510946221886 28.9499227439960407, 223.1593084067002906 28.9801302235189091, 223.1671463731102847 29.0102958476457857, 223.1733378307822875 29.0405055589104215, 223.1762893691852980 29.0708005572501200, 223.1797411591134050 29.1010841479316511, 223.1842105395194835 29.1313429880286847, 223.1897492654354380 29.1615757529583242, 223.1968336860509510 29.1917701214418592, 223.2007111469362144 29.2220488212398450, 223.2065521127401837 29.2522700368052213, 223.2119706505079080 29.2824949298786201, 223.2143181739425302 29.3128005757714760, 223.2145049372286962 29.3431632754442226, 223.2130727083830095 29.3735688214337003, 223.2169012501166776 29.4038404960356416, 223.2205048495359563 29.4341193922145052, 223.2231762087349409 29.4644236196138216, 223.2286000314355476 29.4946587355595966, 223.2310513877523022 29.5249714295019459, 223.2344723717550892 29.5552689830145106, 223.2401364427293800 29.5855193241913597, 223.2452585570293593 29.6157849349486888, 223.2505202413127563 29.6460483699050634, 223.2559231593407674 29.6763095798611687, 223.2644027871297965 29.7064934052473184, 223.2627241956122077 29.7369385494184755, 223.2645402238002248 29.7672955192699540, 223.2677335536205305 29.7976186173829838, 223.2703656238828387 29.8279573494095835, 223.2756273228060593 29.8582220782173451, 223.2844765439608352 29.8883879235266221, 223.2937085860519630 29.9185452808112444, 223.2973081015859407 29.9488478138921579, 223.2936631005122763 29.9793362624144635, 223.2960666519568633 30.0096716675765087, 223.3009400212339415 30.0399455321323572, 223.3025870375581121 30.0703026551048325, 223.3057019420378992 30.1006237111998871, 223.3089129363874861 30.1309435671736630, 223.3150049756058309 30.1612022619658475, 223.3234217234096093 30.1914144151501098, 223.3234210095013736 30.2218413027543100, 223.3217310036584706 30.2523119774457854, 223.3241338861918166 30.2826801518044384, 223.3291361017755321 30.3129838018023321, 223.3335691814783672 30.3433030311558909, 223.3376879267651702 30.3736313904119228, 223.3415822010329066 30.4039665939800763, 223.3428527313766097 30.4343692093521518, 223.3463046578129365 30.4647139764648003, 223.3516152151530321 30.4950088856224291, 223.3563567921461299 30.5253193045073523, 223.3591806847876740 30.5556792232234464, 223.3633551843414011 30.5860062097936520, 223.3673017153327294 30.6163400617655554, 223.3700134643178785 30.6467061128776557, 223.3771472685353956 30.6769619187441549, 223.3826102810548377 30.7072608972207064, 223.3886354466804676 30.7375468061555068, 223.3920631849616996 30.7678988088326477, 223.3948340483643449 30.7982679488339173, 223.3964740350932345 30.8286665606508272, 223.3988015834056000 30.8590488764019213, 223.4054640310108368 30.8893233212693943, 223.4110113026400199 30.9196268339411588, 223.4122686163350409 30.9500391595034401, 223.4185862540497851 30.9803254154592445, 223.4253672463790679 31.0106010423021878, 223.4280655144321486 31.0409802450029346, 223.4338793837801518 31.0712782786587987, 223.4368728739135861 31.1016439800152682, 223.4352648020607148 31.1321259385783939, 223.4366125414744033 31.1625346167303299, 223.4396705389495708 31.1929014229470027, 223.4456438373769345 31.2231963323206827, 223.4505941710413879 31.2535177730133178, 223.4547715708542057 31.2838594813272053, 223.4577739516643362 31.3142314600314897, 223.4600217044558974 31.3446231543025569, 223.4635365292612903 31.3749880885911949, 223.4679250725203588 31.4053363295574073, 223.4717664817196408 31.4356991046183545, 223.4748831801738049 31.4660808083446888, 223.4799487654960330 31.4964148776198982, 223.4840292327997133 31.5267743476906972, 223.4865411911889623 31.5571736952518300, 223.4883032670847456 31.5875924901525806, 223.4923952324174650 31.6179542209800530, 223.4970672525005568 31.6483023930064604, 223.5030692210884524 31.6786209217952361, 223.5066616283447729 31.7090028002721205, 223.5106210414199381 31.7393763677076528, 223.5132764002270278 31.7697830875398139, 223.5179240399021978 31.8001411575539024, 223.5195254158730336 31.8305755441254412, 223.5239434375728536 31.8609408592237848, 223.5282886785425660 31.8913087443299545, 223.5322519417814817 31.9216868481073490, 223.5347617094650161 31.9521016880502948, 223.5380353071365676 31.9824836883298858, 223.5428282744416038 32.0128133802927906, 223.5480508269973257 32.0431332223139407, 223.5497441169928550 32.0735409979197428, 223.5553057805198591 32.1038539700979157, 223.5598384268915879 32.1341930833302882, 223.5624288052136706 32.1645807931653849, 223.5652337763135336 32.1949638621966159, 223.5678286491805409 32.2253527383586302, 223.5695560421614800 32.2557635381356320, 223.5752088570122851 32.2860971657264244, 223.5778937031911653 32.3165239135804541, 223.5812675754776535 32.3469343759028192, 223.5848566390171470 32.3773401797631806, 223.5891675861419685 32.4077288949641087, 223.5927666200163060 32.4381356809368810, 223.5971664748506100 32.4685234267514531, 223.6018897195696979 32.4989038349818813, 223.6036667979318509 32.5293570671523327, 223.6064949113190323 32.5597850851598665, 223.6116324578511296 32.5901446221567141, 223.6140456300912831 32.6205582901842064, 223.6180710912757377 32.6509330397430162, 223.6211992807537570 32.6813302884016323, 223.6282270303815096 32.7116327515463041, 223.6317729060839383 32.7420209117890408, 223.6357729384005211 32.7723985010423533, 223.6368325295955231 32.8028483885533575, 223.6411096372302154 32.8332202357844309, 223.6439910882512550 32.8636266157740948, 223.6481310196402319 32.8940028180075927, 223.6509936165835200 32.9244106062468376, 223.6553899144587376 32.9547815457483892, 223.6596968044630103 32.9851551443478925, 223.6612145716325131 33.0155969876130797, 223.6650693764509015 33.0459824802825963, 223.6692659410257420 33.0763601295090908, 223.6716695759030529 33.1067817006912222, 223.6751523009949381 33.1371775152148800, 223.6790842135375783 33.1675628699203884, 223.6817299555439718 33.1979800537635299, 223.6840029478613872 33.2284069153912540, 223.6869551522037796 33.2588177147742314, 223.6903565456991032 33.2892180315189918, 223.6936834073373461 33.3196205104331185, 223.6971029051111373 33.3500211101661606, 223.7007701587775159 33.3804160898463422, 223.7044837207658361 33.4108103025735730, 223.7075120344809989 33.4412213366104680, 223.7108808174928640 33.4716244980177109, 223.7150218025271045 33.5020111064701567, 223.7185127414146848 33.5324154288194762, 223.7220915424775853 33.5628179459110427, 223.7256487173764015 33.5932212767874603, 223.7286216237151564 33.6236389014538517, 223.7320216441544289 33.6540465565227436, 223.7369843539350995 33.6844170564061542, 223.7396632577163587 33.7148425179124871, 223.7417605710628266 33.7452821085100041, 223.7453063421751835 33.7756872890390909, 223.7483122062117786 33.8061098599434615, 223.7517120548250489 33.8365277390942296, 223.7558255243959024 33.8669288054322521, 223.7594854651726166 33.8973409053826700, 223.7624929837646164 33.9277687625072559, 223.7659937331654874 33.9581850449847380, 223.7683016723167668 33.9886299136110850, 223.7717654102991389 34.0190474190815451, 223.7746851069329352 34.0494780281038132, 223.7778200650627412 34.0799036631504322, 223.7815767484544267 34.1103144299491063, 223.7849598454090767 34.1407339700314196, 223.7886890995187343 34.1711454270436050, 223.7929755563749268 34.2015437889649405, 223.7950123859445171 34.2319956603030846, 223.7976542511609637 34.2624332579386390, 223.8008059637030556 34.2928588583746645, 223.8038189436577738 34.3232878313987229, 223.8070197678133582 34.3537124337935751, 223.8102919260756209 34.3841354219903863, 223.8132599670128400 34.4145658934247152, 223.8172826871150392 34.4551387031975906))) +MULTIPOLYGON (((225.6590116069496332 15.2022751783289749, 225.8184285323443135 15.1938011439423235, 225.9815607790280581 15.1849941024038380, 226.1537479984186234 15.1755636256977411, 226.3305987103622101 15.1657156109381503, 226.5161948594225123 15.1552163684519368, 226.7132602792806040 15.1438893480044516, 226.9261988968144408 15.1314506128323636, 227.1499418817269316 15.1181384850929099, 227.3887605673780286 15.1036654664102183, 227.6457676408483621 15.0877902095771024, 227.9238726255883307 15.0702639427477045, 228.2357698250011140 15.0502006377175022, 228.5715407542897708 15.0280865134360671, 228.9475901302254215 15.0027161004160057, 229.3712716350795233 14.9733679202844066, 229.9511930054955826 14.9320537004547287, 230.4883212844398770 14.8922542022366784, 231.1136532006034088 14.8443022655274142, 231.8633228538656681 14.7845460925961838, 232.7891574036120517 14.7073522926485882, 233.9942664766833786 14.6013042632958854, 234.4965294635921680 14.5504706068641187, 234.5208110646848638 14.5099689963999161, 234.5313044307453652 14.4803171726285242, 234.5416131320472743 14.4506850419997708, 234.5520779986402147 14.4210415871861439, 234.5623431792820952 14.3914232576745800, 234.5724238854104442 14.3618286537537010, 234.5827882798384678 14.3322149028797057, 234.5929578122126600 14.3026258490534754, 234.6030683516360682 14.2730490548120876, 234.6134058759765253 14.2434583660659655, 234.6236678296300795 14.2138814838690237, 234.6339787547713343 14.1843070300948444, 234.6442862293286566 14.1547369881042862, 234.6547188872675065 14.1251597337691344, 234.6648922784237072 14.0956130660573216, 234.6753260770241241 14.0660495237721683, 234.6864368122618316 14.0364311268668658, 234.6957686613596934 14.0069820249208483, 234.7061404545204937 13.9774449563442484, 234.7168562114414385 13.9478834922368211, 234.7270224985275888 13.9183791088051372, 234.7372049000421725 13.8888802353741898, 234.7477636681231274 13.8593540756665892, 234.7584817070679151 13.8298204457635237, 234.7691873592963532 13.8002949952320169, 234.7803650561162385 13.7707336570441434, 234.7916750869490841 13.7411673887640564, 234.8029058073712747 13.7116154578260421, 234.8142170613676001 13.6820633421945015, 234.8253048393833069 13.6525386876241441, 234.8363381022113003 13.6230261368713048, 234.8474859602987124 13.5935103447128149, 234.8586521624573891 13.5639727106138768, 234.8698086928625059 13.5344171572959713, 234.8810402769611301 13.5048618787067021, 234.8921633393982233 13.4753235400046201, 234.9036036689824414 13.4457635459991671, 234.9148787490042878 13.4162256652156433, 234.9262976252631177 13.3866818978301705, 234.9378525867176108 13.3571329688567086, 234.9491438212119476 13.3276151021412534, 234.9605851744020129 13.2980908307225132, 234.9714051180906438 13.2686329664536888, 234.9829107519212243 13.2391230512865921, 234.9953247717635634 13.2095381987899341, 235.0050945474888522 13.1801996368848702, 235.0136741458930487 13.1509757165580634, 235.0235876206720604 13.1216383626052853, 235.0329511600260446 13.0923577947184526, 235.0428529677785718 13.0630357719613439, 235.0521842664741428 13.0337723689987097, 235.0625643588351181 13.0044215486467589, 235.0718456772173113 12.9752026575957213, 235.0824545385907243 12.9458957826393526, 235.0941279050537958 12.9165005023643378, 235.1065853385751154 12.8870421853161687, 235.1158685220012785 12.8578770133932370, 235.1267432526933021 12.8285761001416407, 235.1379548447789034 12.7992524167666950, 235.1493796196099879 12.7699171278070818, 235.1597708594709673 12.7406822110508919, 235.1712990020443783 12.7113527639371746, 235.1827906327161770 12.6820275614660449, 235.1941656397088991 12.6527141313651210, 235.2050650316088536 12.6234509250417926, 235.2163653281609186 12.5941593717566178, 235.2278129170846341 12.5648622451838943, 235.2385899997154013 12.5356327692369511, 235.2509196540145524 12.5062719958082358, 235.2633495965479824 12.4769099909586600, 235.2728707658307599 12.4478157345661558, 235.2843018917575648 12.4185583775542057, 235.2958612625120054 12.3892706549166327, 235.3093903396573410 12.3597895149907959, 235.3187948289964879 12.3306840979702574, 235.3306973306444547 12.3013633116314818, 235.3409552429090468 12.2721967440650062, 235.3501958582132545 12.2431283055929345, 235.3613910465265349 12.2138932348155915, 235.3730447120910583 12.1846249560596309, 235.3841076199099689 12.1554168856462663, 235.3951457458792333 12.1262186344057685, 235.4062396928094358 12.0970204530032373, 235.4175034832148583 12.0678123994039375, 235.4293245046916638 12.0385625703327914, 235.4421181448695393 12.0092341708445201, 235.4552959275237072 11.9798795411541885, 235.4690679159375577 11.9504801025218139, 235.4834853055173198 11.9210313919657640, 235.4960974303484704 11.8917506965023225, 235.5075487338667983 11.8625807322285564, 235.5232045968097907 11.8330462747878666, 235.5346764932195072 11.8038936248651414, 235.5484769106767544 11.7745459193969246, 235.5600500493502807 11.7454032068121563, 235.5703027540562857 11.7163850531242257, 235.5839099153991469 11.6870783107510565, 235.5954261045663145 11.6579642552422929, 235.6091634787426301 11.6286620492642268, 235.6216120133803429 11.5994816340682760, 235.6324251517819164 11.5704534114981232, 235.6427681561548582 11.5414744764065418, 235.6568231610475834 11.5121696293317068, 235.6720114139477857 11.4827667117950689, 235.6855534379756421 11.4535169164333990, 235.6985976231398183 11.4243190426501098, 235.7101697742900228 11.3952586967795071, 235.7212865678495746 11.3662463476185298, 235.7336848211043900 11.3371294098914515, 235.7467824960610017 11.3079591641971682, 235.7608802893133486 11.2787093286269826, 235.7716222749621409 11.2497620499263871, 235.7842032101285952 11.2206891920285248, 235.7973313754250455 11.1916028404892263, 235.8104867447666777 11.1625225099717724, 235.8248992522797494 11.1333405976365700, 235.8395596186489911 11.1041455609057547, 235.8525266395528206 11.0751071281384803, 235.8667638349001834 11.0459661778940248, 235.8799840524185640 11.0169226049989497, 235.8933575463182422 10.9878741537508979, 235.9056857922374775 10.9589253856053972, 235.9193690857431704 10.9298457604650068, 235.9332202571240487 10.9007399237311553, 235.9474135600927411 10.8716127613943527, 235.9606689831901747 10.8425757207505278, 235.9745891351899729 10.8134893032700230, 235.9749642465170609 10.7716809281293759, 234.3062264801270658 10.9140277809828401, 233.0568672341269121 11.0146280042264575, 232.0879579900154397 11.0891193380045809, 231.2922763752998208 11.1479476253113834, 230.6222024977055014 11.1958368476763042, 230.0451126661348269 11.2358585089428757, 229.5399124326949050 11.2699591633166492, 229.0910977852282429 11.2995144425355125, 228.6886580791903896 11.3254217054488961, 228.3230615139326005 11.3484629748935983, 227.9885578563494164 11.3691297953498367, 227.6794424865365158 11.3878696987456021, 227.3925662525238351 11.4049521734721111, 227.1244248889431105 11.4206460692871250, 226.8725374557916155 11.4351462062953271, 226.6348499723014811 11.4486118924986169, 226.4089327375779703 11.4612113075504123, 226.1941018513796280 11.4730141135587900, 225.9885536989872605 11.4841415383638772, 225.7906841315520694 11.4946974768609138, 225.5999034371537562 11.5047316362784287, 225.5366590428417908 11.5127499139888521, 225.5372155286848397 11.5505123386366488, 225.5385771173884848 11.5787917807460410, 225.5399422790718234 11.6070769022026852, 225.5412964706883940 11.6353683683310756, 225.5426724692766527 11.6636646542834583, 225.5440051181544163 11.6919712226479628, 225.5452754778118276 11.7202890826971338, 225.5466283640503775 11.7486089150272832, 225.5479733512454459 11.7769349110044050, 225.5492620733159299 11.8052693182738349, 225.5505841235170692 11.8336079602086279, 225.5519462019779553 11.8619505139368027, 225.5533034115049986 11.8902990653406153, 225.5546573358129194 11.9186535320087330, 225.5560296402161100 11.9470128980119092, 225.5574630380900487 11.9753825153473716, 225.5590145866423484 12.0037600937641198, 225.5604603602986913 12.0321483085325323, 225.5618766106682358 12.0605435905751133, 225.5632235047208098 12.0889478001897945, 225.5646322493352045 12.1173547928037380, 225.5660183352506749 12.1457685136780800, 225.5674524001674399 12.1741856512172308, 225.5688591210818288 12.2026097227853292, 225.5703066481627843 12.2310375313070310, 225.5717059626913112 12.2594635288136420, 225.5731135143499273 12.2878845470445004, 225.5745000481469731 12.3163122246356878, 225.5759250962974249 12.3447437586129958, 225.5773925000398208 12.3731789608754816, 225.5788485202704692 12.4016203466559691, 225.5803384551418844 12.4300657783575321, 225.5816851397536311 12.4585235860499672, 225.5830893138132183 12.4869843197081938, 225.5845898506858873 12.5154461392763974, 225.5860380817925375 12.5439157418262273, 225.5874589811405428 12.5723919343366166, 225.5889159824166654 12.6008720349108785, 225.5903500435784110 12.6293588188961490, 225.5917512821488060 12.6578527498482263, 225.5931498471001078 12.6863523976596984, 225.5945936513341508 12.7148554898354504, 225.5960004210751038 12.7433659093484160, 225.5974035729581715 12.7718820686378116, 225.5988234674924229 12.8004029994655610, 225.6002725684679433 12.8289353399234827, 225.6017372708080018 12.8574801027486334, 225.6031663910407872 12.8860320508820667, 225.6045230144762570 12.9145929258961942, 225.6058813440074289 12.9431592084249925, 225.6072542187562817 12.9717302816559918, 225.6086155629616314 13.0003073736031514, 225.6099855932373544 13.0288895208782218, 225.6113301416302193 13.0574783351150430, 225.6125573734466627 13.0860781700991904, 225.6138059182740392 13.1146685839299817, 225.6150812752645152 13.1432485814377760, 225.6162458523031660 13.1718393538115368, 225.6173776526709105 13.2004371913496481, 225.6185740513896576 13.2290374594585156, 225.6198200703518353 13.2576408581347014, 225.6210454855481373 13.2862507194559658, 225.6223709722382864 13.3148612910132691, 225.6236531537022643 13.3434793903344762, 225.6249325727087012 13.3721030822070848, 225.6260928571377633 13.4007285592951106, 225.6271536838081886 13.4293543933417254, 225.6282124976070804 13.4579858253871780, 225.6292645318286247 13.4866230741567108, 225.6301804110024136 13.5152723247030888, 225.6310913327383219 13.5439273006293899, 225.6319395690546230 13.5725907592594286, 225.6327541321401782 13.6012613103884163, 225.6337718653989839 13.6299275880244135, 225.6347506835452634 13.6586011868333443, 225.6357740728154511 13.6872915147215632, 225.6369158385559786 13.7159957105510788, 225.6377194034149625 13.7447214980022157, 225.6381065140526232 13.7734726407128552, 225.6384486639109923 13.8022312917939587, 225.6384696576625970 13.8310107210332234, 225.6377164798742854 13.8598327078059746, 225.6365675116648504 13.8886790654790975, 225.6366436894022058 13.9174718433797455, 225.6368569809392284 13.9462633391875563, 225.6372512897805791 13.9750446864033755, 225.6375598963244613 14.0038283679673583, 225.6379232733982292 14.0326147568883712, 225.6383897348957248 14.0614015137205151, 225.6384870234559514 14.0902113786118672, 225.6385225422024234 14.1190295456736390, 225.6386422679394741 14.1478489719565079, 225.6388548750343546 14.1766692296997032, 225.6393899649038417 14.2054792308434106, 225.6400017794549910 14.2342908121572211, 225.6406354383889550 14.2631066559514661, 225.6413569023304149 14.2919235679286665, 225.6418737902540670 14.3207556085893160, 225.6423091419993341 14.3495968330276007, 225.6427227616953246 14.3784443489976486, 225.6431399564071967 14.4072969250615799, 225.6435643096251908 14.4361543786609037, 225.6439996407971762 14.4650165188792776, 225.6444242559419422 14.4938843843585552, 225.6447387707936514 14.5227627777236634, 225.6449631354863357 14.5516507314802457, 225.6451722615322808 14.5805446135894456, 225.6453957584195393 14.6094429813533875, 225.6457542902550415 14.6383399812061086, 225.6462420944643554 14.6672358819702477, 225.6469402658949832 14.6961267418030221, 225.6476430847723407 14.7250225126985868, 225.6482912667314622 14.7539260619938783, 225.6489832272112039 14.7828326105555625, 225.6497656773054530 14.8117398863536138, 225.6506424448378993 14.8406387380365601, 225.6513629143920809 14.8695408563681148, 225.6517777326999976 14.8984629716291774, 225.6521804911266145 14.9273908339482322, 225.6524924024801919 14.9563282656240322, 225.6529946847831525 14.9852615952319770, 225.6535087795084848 15.0141994841802013, 225.6541740536502800 15.0431351473047741, 225.6549119930294864 15.0720723861003538, 225.6554983623736916 15.1010221056688980, 225.6560601550888236 15.1299724949437415, 225.6566877998535006 15.1589188522188678, 225.6590116069496332 15.2022751783289749))) +MULTIPOLYGON (((222.1624644987274735 22.8951608777580375, 222.3339278053788917 22.8936291251068376, 222.4918214736053699 22.8892887249650485, 222.6447347625685325 22.8849225119194131, 222.7860232523261459 22.8807537878477198, 222.9282491755332387 22.8764117841961223, 223.0766244984883997 22.8717204867395267, 223.2163755016804316 22.8671671508905092, 223.3566763952527197 22.8624540094745328, 223.4933003438143828 22.8577319701406125, 223.5898184186347919 22.8543578551823892, 223.6952462098461751 22.8505806049225235, 223.7986314112467028 22.8468004170732009, 223.8996071437578905 22.8430363020301144, 223.9985409791676716 22.8392789939742009, 224.0959564206523567 22.8355116832603002, 224.1910355953645535 22.8317716010045579, 224.2846905331828111 22.8280253856162325, 224.3794591431511947 22.8241662737757345, 224.4717633563003290 22.8203486474569281, 224.5633375180167945 22.8165001435605177, 224.6543476105572950 22.8126140287647665, 224.7440401314307223 22.8087272358785960, 224.8325041708576180 22.8048422967121454, 224.9212556591380121 22.8008911952094380, 225.0106581698819639 22.7968452217387672, 225.1000007997450894 22.7927430514162239, 225.1888277899554112 22.7886040404598802, 225.2781779860745246 22.7843853506296270, 225.3686923868900180 22.7800551111920484, 225.4590163590499117 22.7756725362798349, 225.5508196988342036 22.7711599176716817, 225.6422475001399732 22.7666030803204116, 225.7360430349097840 22.7618690699529438, 225.8308944078747231 22.7570178540152632, 225.9265645398245965 22.7520593285219199, 226.0249049679516702 22.7468968897921613, 226.1249454787357820 22.7415751880217485, 226.2278086014960081 22.7360312021479380, 226.3331090916695700 22.7302792145955159, 226.4411376184042979 22.7242978236477953, 226.5516842588731947 22.7180922187040188, 226.6656163592838027 22.7116078269275548, 226.7845301475277040 22.7047457110851525, 226.9071475647060652 22.6975670622629160, 227.0314410381330958 22.6901810097109546, 227.1839792061291519 22.6810029065164471, 227.3309878641200044 22.6719940161947768, 227.4852574295117620 22.6623834901635632, 227.6478981924011009 22.6520789917443750, 227.8244753454561931 22.6406976406627756, 228.0131819147138117 22.6283077429488948, 228.2162925671777600 22.6147123262701619, 228.4292029370038222 22.6001656945547893, 228.6562565744310689 22.5843249430069939, 228.9060279700422313 22.5665175965706943, 229.1825161009347198 22.5463403909257636, 229.4889073172393807 22.5234095912130243, 229.8235975093082004 22.4976688769848394, 230.1950353288360134 22.4682622757394483, 230.6140350096124507 22.4340362401953612, 231.0891086673919972 22.3938791164045092, 231.6395866999296516 22.3455627543664406, 232.2933600726683778 22.2857009542201325, 233.0468719137620894 22.2096336011567779, 233.0786160066152775 21.8362790739403536, 233.1128703123239063 21.4745535126135110, 233.1496154959708065 21.1131520454980688, 233.1847240762937474 20.7523849750790745, 233.2282694103726897 20.3912575382923755, 233.2729399482162762 20.0308241593812788, 233.3250709696296212 19.6705333692991715, 233.3796821892690616 19.3110185897310593, 233.4385722857594772 18.9512397884658697, 233.5048315557592673 18.5912746804501623, 233.5705679159131591 18.2318918457248778, 233.6451980362392078 17.8721782134589731, 233.7217275110074581 17.5133469216565452, 233.8008596205570200 17.1546858578559593, 233.8864271817588190 16.7969322128414085, 233.9697189397047907 16.4397036867894251, 234.0828109354990261 16.0803141029572600, 234.1849920610645768 15.7230496510930529, 234.2920854378215267 15.3662472679597375, 234.4024907295219009 15.0099336757912152, 234.5149128961783731 14.6540024088048977, 234.6379311558054326 14.2984584661645968, 234.7623775583252552 13.9436811557223272, 234.8942578962761161 13.5892102040072000, 235.0288272444620077 13.2349149253326068, 235.1521051686026453 12.8828891505364300, 235.2867725908210446 12.5312613936619748, 235.4233087213997351 12.1800902646282907, 235.5708596309736720 11.8287640873522850, 235.7235065836390788 11.4781679472845699, 235.8797318095176365 11.1284757052386034, 236.0525313246200767 10.7671682736336187, 234.5539738435579977 10.8934756929011449, 233.4407131631540437 10.9842712723620792, 232.5469229652692320 11.0542229776525041, 231.8057772059855211 11.1102241836924787, 231.1727759778447648 11.1565989554036538, 230.6222024977055014 11.1958368476763042, 230.1360978921009064 11.2296246903372410, 229.7011060076232241 11.2591734075795618, 229.3092627460602273 11.2852352682303039, 228.9523786369067579 11.3085085479184464, 228.6255699416132074 11.3294320811176288, 228.3230615139326005 11.3484629748935983, 228.0424929933024316 11.3658248267828181, 227.7797848238557492 11.3818240807616586, 227.5335303503333364 11.3965959501440786, 227.3013618133060163 11.4103203927983330, 227.0813921445946733 11.4231400422550955, 226.8725374557916155 11.4351462062953271, 226.6735784057245553 11.4464323336035516, 226.4830830479990880 11.4570977194971331, 226.3002739486517783 11.4672030229445188, 226.1246140672760987 11.4767939954951359, 225.9550662527171312 11.4859387811404918, 225.7906841315520694 11.4946974768609138, 225.6312478555481391 11.5030927722805156, 225.4762447625165578 11.5111601660590104, 225.3250842761335662 11.5189369296463209, 225.1774439551033993 11.5264465188925040, 225.0328448253008276 11.5337180770388592, 224.8908763596499512 11.5407761760390457, 224.7513584997170994 11.5476346729869821, 224.6139594562444017 11.5543129777216969, 224.4784375362928017 11.5608260941168410, 224.3444652819518979 11.5671914448567392, 224.2117774258872487 11.5734232007998141, 224.0801718772115123 11.5795330298151136, 223.9493664901772547 11.5855344996028045, 223.8191624724303210 11.5914391819364901, 223.6892422590755416 11.5972592901638460, 223.5594084415188831 11.6030053638418362, 223.4294005333658788 11.6086896685846472, 223.2989722102153110 11.6143216904895947, 223.1678913125293775 11.6199107220579378, 223.0358968024123385 11.6254674694606805, 222.9027074603666563 11.6310028546020856, 222.7681514532171434 11.6365211164074118, 222.6319141538511417 11.6420339437191078, 222.4937638625381169 11.6475477129753546, 222.3535187113670872 11.6530658977330486, 222.2106332312147856 11.6586083764684449, 222.0649326370145218 11.6641761438978122, 221.9159984711472191 11.6697805626173459, 221.7637180402759896 11.6754184975323128, 221.6071946734359415 11.6811193203433437, 221.4462705120650412 11.6868790352438801, 221.2800176036296591 11.6927238980806685, 221.1082343240083787 11.6986486654978012, 220.9302181846820758 11.7046664471111175, 220.7448115762650502 11.7108046009619358, 220.5512576667551059 11.7170716871887297, 220.3489604038603034 11.7234675876106191, 220.1364090861307830 11.7300207161664911, 219.9120955538539874 11.7367529071657000, 219.6885215783223657 11.7467999825142257, 219.7800022085925491 12.0939667193907923, 219.8674454815513286 12.4316594207246638, 219.9609663350123014 12.7696974747126752, 220.0435221787505213 13.1088831469933211, 220.1287352849993226 13.4489940064017972, 220.2143098341883558 13.7895853682338103, 220.2996432291302824 14.1309982530505547, 220.3856337208090963 14.4729600249569028, 220.4702124060514450 14.8160664519636125, 220.5542495225764128 15.1598074722681364, 220.6372147494944045 15.5039964430272246, 220.7215739629969562 15.8490768265738264, 220.8003749786528260 16.1950206147845002, 220.8780366528559398 16.5414260978017715, 220.9576980259738264 16.8886184325720556, 221.0492649287550080 17.2360440209217529, 221.2038686914070240 17.5820804815569822, 221.2332821021322786 17.9327909628593183, 221.3064374132812020 18.2825671410777524, 221.3767990322102150 18.6330869316894123, 221.4437786009013962 18.9842653900625713, 221.5157897916339209 19.3357555188309327, 221.6415036192033199 19.6862868958747796, 221.7040268217931498 20.0392648175583936, 221.7734189145131722 20.3928463603017818, 221.8288535880878953 20.7473064170266852, 221.8917645081734804 21.1019045712286442, 221.9100285267250285 21.4581261494620072, 221.9689664639684850 21.8138417552296744, 222.0351237485043043 22.1699280426223453, 222.0994527851256350 22.5263997499335709, 222.1624644987274735 22.8951608777580375))) diff --git a/isis/src/base/objs/ImagePolygon/ImagePolygon_Linux_i686_SUSE10_1.truth b/isis/src/base/objs/ImagePolygon/ImagePolygon_Linux_i686_SUSE10_1.truth new file mode 100644 index 0000000000000000000000000000000000000000..962f2607906811a7c6fa40ceb7c0597dfb1c1f3c --- /dev/null +++ b/isis/src/base/objs/ImagePolygon/ImagePolygon_Linux_i686_SUSE10_1.truth @@ -0,0 +1,3 @@ +MULTIPOLYGON (((223.8172826871150392 34.4551387031975835, 223.8417027794513956 34.4596506067936588, 223.8575436553770714 34.4592772203974533, 223.8731987948544884 34.4589061404385077, 223.8888001596040453 34.4585342459693109, 223.9044019981608642 34.4581602383999694, 223.9200661672346939 34.4577826050169165, 223.9355075425064001 34.4574083329785168, 223.9508457646854538 34.4570345512927787, 223.9660146266744221 34.4566629442804810, 223.9810473117178447 34.4562927477356951, 223.9957878474442339 34.4559279257479716, 224.0106582442915908 34.4555579477815925, 224.0255459277288139 34.4551856182047374, 224.0403444766605787 34.4548136400302170, 224.0550707903117598 34.4544416141928878, 224.0696826279009031 34.4540706529749627, 224.0842130300090105 34.4536999452778474, 224.0986612451643509 34.4533295403593272, 224.1130364690419867 34.4529592284912809, 224.1273202300474452 34.4525895195669563, 224.1415662443576764 34.4522190341699286, 224.1557339919143601 34.4518488560984437, 224.1698107919081622 34.4514793495922902, 224.1838116921205994 34.4511101459255826, 224.1977227035095268 34.4507416461034168, 224.2115924901995356 34.4503725739912667, 224.2254006441162915 34.4500034948312930, 224.2391929104846611 34.4496331906106832, 224.2529511041628325 34.4492621619975878, 224.2666975063020232 34.4488898122485239, 224.2803860066288451 34.4485174108845698, 224.2940079847741686 34.4481452154172416, 224.3075938799341031 34.4477724067579985, 224.3210795842228720 34.4474007778023221, 224.3344990942869401 34.4470294145163862, 224.3478450165269180 34.4466585462406556, 224.3611125162273083 34.4462883335280097, 224.3742955932710856 34.4459189717640371, 224.3874260849736970 34.4455495873438409, 224.4004958876452918 34.4451804280896781, 224.4135260618628536 34.4448109131363154, 224.4264828609272513 34.4444420220935044, 224.4393721009314788 34.4440736116739217, 224.4522012233351234 34.4437054891116503, 224.4649910969210680 34.4433370696326975, 224.4777393619959582 34.4429684346240776, 224.4904489206706444 34.4425995129701761, 224.5030718093741200 34.4422317209555402, 224.5156259769345866 34.4418645588172865, 224.5281770922377120 34.4414961128652166, 224.5407219882790457 34.4411264781702400, 224.5531975742957229 34.4407575294710213, 224.5656264625203562 34.4403886151251797, 224.5780227095267492 34.4400193298509620, 224.5903757297269578 34.4396500014264859, 224.6026728254564944 34.4392810254014208, 224.6148668913573658 34.4389138408317379, 224.6269709754118651 34.4385480839034486, 224.6390599334609988 34.4381815077720859, 224.6511372140055300 34.4378140122935150, 224.6632067785473339 34.4374454802786332, 224.6751614662134671 34.4370792015270695, 224.6870933910036285 34.4367123757492379, 224.6989898632979532 34.4363454017714901, 224.7108678965891500 34.4359777635831534, 224.7226881484133685 34.4356106890301774, 224.7344958302966518 34.4352427866590887, 224.7462652761780646 34.4348748627154819, 224.7579793002597626 34.4345074674088352, 224.7696431367716912 34.4341404524924286, 224.7812728008222791 34.4337733276717159, 224.7928435544382069 34.4334068856012721, 224.8043847867617160 34.4330402110380760, 224.8157283420019041 34.4326786628983683, 224.8270886233244994 34.4323154552239430, 224.8384166745837831 34.4319521504694563, 224.8497524406973866 34.4315874761224592, 224.8610108250487087 34.4312241691771774, 224.8722867697455570 34.4308591872096557, 224.8835699922446452 34.4304928587168035, 224.8948651191569468 34.4301250320693342, 224.9061662756241446 34.4297558957457994, 224.9173542817119369 34.4293893382984280, 224.9284086365550763 34.4290260617306600, 224.9394220908251327 34.4286630587300735, 224.9504388177020076 34.4282988872681628, 224.9614347391652984 34.4279343413389043, 224.9724090215663352 34.4275694545411639, 224.9833614192173457 34.4272042412541737, 224.9942931925034486 34.4268386658471499, 225.0052127358298151 34.4264724543783345, 225.0161268911886054 34.4261053818628895, 225.0270072241944490 34.4257384032388529, 225.0379099783205277 34.4253696379527270, 225.0487812549144735 34.4250008965078678, 225.0595876459501028 34.4246333159996141, 225.0703030757329941 34.4242677966520034, 225.0809691074227601 34.4239029513888539, 225.0916138570161706 34.4235378365167506, 225.1022391576242683 34.4231723954175806, 225.1128542317605081 34.4228063181412836, 225.1234516168084951 34.4224398636277300, 225.1340217162214401 34.4220733666453995, 225.1445720849020802 34.4217065743085584, 225.1551012336424549 34.4213395435047218, 225.1655864786240500 34.4209730652326371, 225.1760248993977882 34.4206072522224744, 225.1864409930356885 34.4202412645735265, 225.1968389824973826 34.4198749610789960, 225.2072200098365897 34.4195083067898224, 225.2175785697437789 34.4191414991763835, 225.2279161215742533 34.4187744930007469, 225.2382328071402071 34.4184072888908830, 225.2485261486005186 34.4180399797886878, 225.2587970263030854 34.4176725407227835, 225.2690410352727781 34.4173051336376261, 225.2792535965569698 34.4169379280283323, 225.2894249396388773 34.4165712795181093, 225.2995612324063188 34.4162049784147825, 225.3096797795645614 34.4158384150564345, 225.3197769941544948 34.4154717225693147, 225.3298508715458865 34.4151049783840435, 225.3399032250165703 34.4147381232054741, 225.3499338576864375 34.4143711696130268, 225.3599442461522244 34.4140040697767731, 225.3699387631642708 34.4136366705630508, 225.3799126564848052 34.4132691484824491, 225.3898592055926997 34.4129017530111767, 225.3997746327333687 34.4125346284357292, 225.4096413759963013 34.4121684232215230, 225.4194664480812378 34.4118028922520267, 225.4292333251142963 34.4114386507455023, 225.4389847119527985 34.4110741439216028, 225.4487227950831709 34.4107092951740015, 225.4584529700733810 34.4103439089537062, 225.4681791118518390 34.4099778443088979, 225.4779501834676410 34.4096092906042514, 225.4877658689587179 34.4092382503042771, 225.4975606254193394 34.4088671492795939, 225.5073160520850308 34.4084966775202261, 225.5170945589782434 34.4081245164470459, 225.5268331233909009 34.4077530165447598, 225.5365021994340680 34.4073832929153340, 225.5461190551428672 34.4070147130339521, 225.5556995065214210 34.4066466939793045, 225.5652214497965247 34.4062800757604350, 225.5747432098701211 34.4059126713390597, 225.5842560908804444 34.4055448096861980, 225.5937778006389749 34.4051758228821214, 225.6033009158175560 34.4048059910247375, 225.6128238278627123 34.4044353753846508, 225.6223471750505212 34.4040639521956990, 225.6318758783661451 34.4036915343189733, 225.6414016415950243 34.4033184379288954, 225.6509363628299241 34.4029442091229711, 225.6604947562338452 34.4025682830337516, 225.6700415057191833 34.4021920107971795, 225.6795791566906360 34.4018152974535525, 225.6890709331013625 34.4014395612861392, 225.6985268751064666 34.4010644244605430, 225.7079299362157485 34.4006905527387659, 225.7172925181210417 34.4003174767084232, 225.7266351872429198 34.3999444074105725, 225.7359624913471805 34.3995711724671480, 225.7452560214498476 34.3991984906232631, 225.7545267975936838 34.3988259393811830, 225.7637889836569514 34.3984529710283340, 225.7730507645297848 34.3980792679652367, 225.7823252012858291 34.3977043200823118, 225.7916004169256610 34.3973285907622284, 225.8008725343179037 34.3969522324371155, 225.8101369195402413 34.3965754281377940, 225.8193892452067359 34.3961983498649957, 225.8286274988710716 34.3958210793992976, 225.8378496687873564 34.3954436988933523, 225.8470551995822007 34.3950662333900752, 225.8562326011218033 34.3946891401953891, 225.8653930029271351 34.3943119836700717, 225.8745410760951984 34.3939345817962447, 225.8836776373707664 34.3935569045111080, 225.8928019411298180 34.3931789836151509, 225.9019194640990804 34.3928006036003637, 225.9110308752194101 34.3924217393303877, 225.9201549499825887 34.3920416440390966, 225.9292743320634145 34.3916610091261106, 225.9383845714752397 34.3912800135874335, 225.9474795314372670 34.3908989045497577, 225.9565581779545482 34.3905177258943482, 225.9656244992629581 34.3901363204726565, 225.9746802477716869 34.3897546201018471, 225.9837284337634173 34.3893725058620632, 225.9927658600073812 34.3889901075809306, 226.0017891753243475 34.3886075616179951, 226.0108161763201053 34.3882241546364824, 226.0198457173729878 34.3878399332780234, 226.0288659305028887 34.3874553758755184, 226.0378750537551866 34.3870705549601965, 226.0468586590255313 34.3866860532718732, 226.0558323075141232 34.3863012460278128, 226.0647969809214999 34.3859160949781781, 226.0737494779376391 34.3855307303640672, 226.0826909505379092 34.3851451069165890, 226.0916392243478583 34.3847585070685966, 226.1005846294034143 34.3843713216575466, 226.1095237944622625 34.3839836876697476, 226.1184552396350682 34.3835956657888744, 226.1273766599998396 34.3832073497904531, 226.1362843513835514 34.3828188894718991, 226.1451789838510820 34.3824302581018841, 226.1540696341335206 34.3820410909009126, 226.1629557016597687 34.3816514127115482, 226.1718415645642608 34.3812610486584163, 226.1807230054595550 34.3808701689397935, 226.1896010103831145 34.3804787348665286, 226.1984731024826090 34.3800868461449483, 226.2073393250205129 34.3796945013437423, 226.2162010894513458 34.3793016446030393, 226.2250584402896720 34.3789082746488859, 226.2339210610192026 34.3785140100478728, 226.2427791039953604 34.3781192424447042, 226.2516314343407373 34.3777240170122553, 226.2604782195461155 34.3773283273222532, 226.2693193564175260 34.3769321773464114, 226.2781549132864427 34.3765355641091617, 226.2869854330468797 34.3761384662781353, 226.2958114626269435 34.3757408626804377, 226.3046334835790958 34.3753427350574086, 226.3134536502247158 34.3749440039339902, 226.3222666039636977 34.3745448676996475, 226.3310674201009078 34.3741454966233277, 226.3398662973834803 34.3737455141035966, 226.3486632146753266 34.3733449208397275, 226.3574580470481123 34.3729437207094222, 226.3662507195254250 34.3725419150449554, 226.3750416931369216 34.3721394879113262, 226.3838307521617708 34.3717364447303808, 226.3926183115110291 34.3713327722454522, 226.4014042158854068 34.3709284730591946, 226.4101886820694745 34.3705235398177749, 226.4189713667430794 34.3701179689839478, 226.4277528949876341 34.3697117361028077, 226.4365339441959577 34.3693048462083510, 226.4453141371926108 34.3688973010714705, 226.4540932758116867 34.3684891263368613, 226.4628714412468469 34.3680802910519034, 226.4716492125849641 34.3676707556087351, 226.4804266127524954 34.3672605341961770, 226.4892039200687748 34.3668496115516220, 226.4979812270960053 34.3664379861530733, 226.5067586403114319 34.3660256540135052, 226.5155350783857955 34.3656126842405598, 226.5243113274227085 34.3651990255176401, 226.5330863836839796 34.3647847379392388, 226.5418613931262257 34.3643697522112461, 226.5506364357621862 34.3639540649148643, 226.5594125115546262 34.3635376202989562, 226.5681899791689489 34.3631204006612663, 226.5769703953577050 34.3627023215986753, 226.5857530174846772 34.3622834277597846, 226.5945393457434420 34.3618636386090444, 226.6033280976995172 34.3614430268793143, 226.6121204829106830 34.3610215278312623, 226.6209149844756610 34.3605992250073200, 226.6297112468491548 34.3601761376944168, 226.6385086581317410 34.3597522985732056, 226.6473076485042952 34.3593276841362325, 226.6561088518948566 34.3589022602962544, 226.6649128221912690 34.3584759975395713, 226.6737198569159943 34.3580488801543851, 226.6825293890413491 34.3576209382972237, 226.6913400811758663 34.3571922426228369, 226.7001540295706832 34.3567626817938603, 226.7089712049677246 34.3563322572982983, 226.7177870375189173 34.3559012100899110, 226.7266041828106324 34.3554693993520743, 226.7354247297424195 34.3550367146799474, 226.7442492611482123 34.3546031252373609, 226.7530788599001141 34.3541685738807345, 226.7619128745825776 34.3537330946952437, 226.7707514832079028 34.3532966780217492, 226.7795960290026471 34.3528592528926922, 226.7884459906888708 34.3524208463128105, 226.7973003349396492 34.3519815121097665, 226.8061593642074172 34.3515412338454809, 226.8150233317549578 34.3510999976269176, 226.8238934698206606 34.3506577380458893, 226.8327720567345693 34.3502143345875979, 226.8416573813213404 34.3497698764048565, 226.8505497655342538 34.3493243457023993, 226.8594358490678644 34.3488784448401745, 226.8683250410209098 34.3484316782385974, 226.8772265484981290 34.3479835601684655, 226.8861363120278725 34.3475343032454958, 226.8950567593701351 34.3470837782926424, 226.9039829498998984 34.3466322446343071, 226.9129146680929807 34.3461797126517610, 226.9218556874078843 34.3457259819622820, 226.9308045477932865 34.3452711283535876, 226.9397756292512156 34.3448143896436733, 226.9487603184119848 34.3443562189215470, 226.9577713539436843 34.3438959390267016, 226.9667906962713460 34.3434345028913981, 226.9758185915840727 34.3429718958397530, 226.9848216200803392 34.3425098915043279, 226.9938252716408158 34.3420471375394882, 227.0028484628004719 34.3415826268728566, 227.0118809439651386 34.3411169022523808, 227.0209235817677893 34.3406499157369325, 227.0299791780909970 34.3401815159329473, 227.0390478252923572 34.3397116955650006, 227.0481467096582833 34.3392395334901579, 227.0572602651000125 34.3387658575312216, 227.0663771857987570 34.3382912704903376, 227.0755008947066926 34.3378155878481692, 227.0846303913033353 34.3373388617669448, 227.0937637963996281 34.3368611918346431, 227.1029086134994657 34.3363821734389703, 227.1120687985093696 34.3359015912790184, 227.1212359111365231 34.3354198972308780, 227.1304019305011082 34.3349375224572597, 227.1395758195951373 34.3344539826583812, 227.1487597349220380 34.3339691594793663, 227.1579902583206376 34.3334810705894711, 227.1672328061846997 34.3329915813299493, 227.1764712676893794 34.3325015631449872, 227.1857181919703237 34.3320103348058581, 227.1949746842976765 34.3315178342700378, 227.2042427831781026 34.3310239484103121, 227.2135235122771917 34.3305286188862198, 227.2228146140626563 34.3300319661149231, 227.2321158182055001 34.3295340025165387, 227.2414261879327171 34.3290347770175401, 227.2507440105512160 34.3285343812617683, 227.2600744088049396 34.3280325326081694, 227.2694283383896732 34.3275286269244404, 227.2787965981322316 34.3270231648313313, 227.2881796631024258 34.3265161169777642, 227.2975768164241970 34.3260075195247154, 227.3069878365814702 34.3254973814854338, 227.3164104609644198 34.3249858246237523, 227.3258502854774576 34.3244725368218440, 227.3353080996625977 34.3239574704821351, 227.3447883386974127 34.3234403757068378, 227.3542849111613009 34.3229215855092846, 227.3637955610379038 34.3224012214535676, 227.3733236581736321 34.3218790927276061, 227.3828696239587828 34.3213551717971797, 227.3924291244449307 34.3208296962129822, 227.4020038477810033 34.3203025684271665, 227.4115915765554234 34.3197739087827998, 227.4211903006491866 34.3192438266352298, 227.4308034100234579 34.3187121291771930, 227.4404322668865461 34.3181787364366357, 227.4500783315511114 34.3176435625182918, 227.4597408211415939 34.3171066473257653, 227.4694373999132608 34.3165669914653151, 227.4791525994482413 34.3160254598141350, 227.4888678788014147 34.3154830953614081, 227.4985957068911944 34.3149391922755242, 227.5083373853007060 34.3143936736176798, 227.5181018062584997 34.3138460315021732, 227.5278825759299082 34.3132966235528087, 227.5376789842163987 34.3127454860494296, 227.5475028125035521 34.3121919441228442, 227.5573500149315294 34.3116362218249122, 227.5672257338918030 34.3110780197670167, 227.5771363516526549 34.3105169660666647, 227.5870780116527783 34.3099532730359655, 227.5970431329110681 34.3093873676510910, 227.6070304509182449 34.3088193165897337, 227.6170402145314711 34.3082490999014738, 227.6270614888661612 34.3076773413150846, 227.6371021487258588 34.3071035837345661, 227.6471620471891413 34.3065278306009773, 227.6572333482755539 34.3059505298130674, 227.6673250879414070 34.3053711551990759, 227.6774425887817301 34.3047893929307435, 227.6875956283596736 34.3042046688993238, 227.6977747164864354 34.3036175256546443, 227.7079695685293927 34.3030285549957057, 227.7181855113128108 34.3024374421746572, 227.7284236548605918 34.3018441168054053, 227.7386810962264576 34.3012487426516728, 227.7489607488535626 34.3006511440034032, 227.7592652945303939 34.3000511577575935, 227.7696049562623273 34.2994481773265747, 227.7799661327243541 34.2988429929067777, 227.7903495498963480 34.2982355559400958, 227.8007531420689702 34.2976259821431668, 227.8111804588746736 34.2970140564827730, 227.8216354765032463 34.2963995375121513, 227.8321461589445107 34.2957807626371007, 227.8426781271888899 34.2951597550205207, 227.8532313530369322 34.2945365104264113, 227.8637943594639239 34.2939117051551889, 227.8743681842673254 34.2932852744245977, 227.8849595330214868 34.2926568152274598, 227.8955699765431859 34.2920262287965869, 227.9062407193617048 34.2913910463675435, 227.9169476338616107 34.2907526963874574, 227.9276713907188707 34.2901123278853248, 227.9383745218067929 34.2894721856800118, 227.9490646281539057 34.2888318175634481, 227.9597329801405579 34.2881917520726702, 227.9704830712227306 34.2875457534077910, 227.9813063056207341 34.2868943188163726, 227.9922004455371507 34.2862375638696761, 228.0031311317907523 34.2855775503149829, 228.0140933799503387 34.2849145702371416, 228.0250913628242984 34.2842483611924891, 228.0361342648187701 34.2835783543212358, 228.0472235719730065 34.2829044464456985, 228.0583488204325704 34.2822272629398910, 228.0695055535343556 34.2815470658358024, 228.0806796288332521 34.2808647115191079, 228.0918858624786196 34.2801792866224346, 228.1031233132032412 34.2794908395679485, 228.1143887119114311 34.2787995621969728, 228.1256453028151157 34.2781077092035957, 228.1369030523943593 34.2774146679768918, 228.1481798443422804 34.2767193333419016, 228.1595524441489999 34.2760169520199653, 228.1709717099658405 34.2753105404703007, 228.1824155794200237 34.2746014536383754, 228.1938803829681888 34.2738899120501443, 228.2054189265202240 34.2731726236746113, 228.2170280980346888 34.2724497609647329, 228.2287243266709140 34.2717202778137491, 228.2405154508755913 34.2709836586137300, 228.2523281114419262 34.2702444679897056, 228.2641942766521197 34.2695006945980865, 228.2760966165281786 34.2687534105830665, 228.2880311232602253 34.2680028568663175, 228.3000080488953643 34.2672483775619412, 228.3120073191576012 34.2664912262207508, 228.3240136614714970 34.2657323608602979, 228.3360270491257609 34.2649717805465883, 228.3480846100778763 34.2642071289308490, 228.3601573792502393 34.2634402314495503, 228.3722738817793640 34.2626692689837498, 228.3844436938668991 34.2618936179263542, 228.3966618612460877 34.2611135777469613, 228.4089824127524366 34.2603256809244385, 228.4213463879382005 34.2595336691820549, 228.4337530236214775 34.2587375776010177, 228.4462104846747934 34.2579368682861514, 228.4587268132951010 34.2571310078012985, 228.4712928807436754 34.2563205653489931, 228.4839104809464061 34.2555054091390190, 228.4966228685898955 34.2546827271919625, 228.5094182245228467 34.2538532540846603, 228.5222741770853645 34.2530184134048241, 228.5351729277744539 34.2521793411568822, 228.5481108241424124 34.2513362606783147, 228.5610933368977840 34.2504888023745764, 228.5740744626261289 34.2496399538219762, 228.5870890608095181 34.2487874360186524, 228.6001377310472265 34.2479311983375254, 228.6132200400176089 34.2470712576139462, 228.6263499085635544 34.2462066877528315, 228.6395379494130680 34.2453367742424319, 228.6528307700917253 34.2444584250006088, 228.6663763631895847 34.2435618322477922, 228.6803617215675217 34.2426345404356880, 228.6952015541297101 34.2416489117582969, 228.7105525887952808 34.2406274236493218, 228.7265499347599018 34.2395608903248387, 228.7421439705677813 34.2385190301761213, 228.7570825715770866 34.2375188387752161, 228.7710598752944691 34.2365810241448401, 228.7833530683239758 34.2357543579112189, 228.7952800700345790 34.2349509231169549, 228.8072627602099942 34.2341424760952293, 228.8196514308075677 34.2333054217383648, 228.8331287441866664 34.2323936079623863, 228.8473922131053655 34.2314270980820723, 228.8618442087083338 34.2304460498874050, 228.8763439297838431 34.2294599388280432, 228.8909482642987996 34.2284648840239214, 228.9056482136413706 34.2274614588506196, 228.9203772895894815 34.2264541588745246, 228.9351647838737165 34.2254409729159406, 228.9499300140235505 34.2244273973785766, 228.9641311146556006 34.2234505682552808, 228.9782062980127080 34.2224806100983585, 228.9925852305867124 34.2214880258965621, 229.0081810669315416 34.2204098060711885, 229.0243240483072213 34.2192917031745054, 229.0404841060492060 34.2181701534276783, 229.0561546197282325 34.2170802520685982, 229.0718159793166819 34.2159888445761240, 229.0875983320990770 34.2148868824320118, 229.1034887026381455 34.2137752213084028, 229.1195460110981230 34.2126497040037805, 229.1358158381831913 34.2115070742239524, 229.1519329161114058 34.2103728456207250, 229.1680640638340094 34.2092353651527716, 229.1841528314203629 34.2080985981401113, 229.1997352209738494 34.2069952677110791, 229.2145400585285984 34.2059447196422752, 229.2300224802753235 34.2048443144084544, 229.2467979267121052 34.2036501663594166, 229.2636965490855232 34.2024448214142751, 229.2805688057605948 34.2012388686691864, 229.2975531550706592 34.2000224458390818, 229.3153572083785150 34.1987449443626588, 229.3330755455613144 34.1974708313770819, 229.3499864414433489 34.1962519263011018, 229.3671162393165446 34.1950147940828515, 229.3845622240634157 34.1937523320369579, 229.4014568277145827 34.1925270213204655, 229.4184179979392297 34.1912944083744748, 229.4358437586914761 34.1900256224414889, 229.4537366314035012 34.1887202762343634, 229.4717783255886729 34.1874013197685613, 229.4899255387092012 34.1860718423110796, 229.5081725981956993 34.1847322094676969, 229.5265398704356130 34.1833808833751647, 229.5450922295438545 34.1820130473676471, 229.5638787832386640 34.1806250031403636, 229.5833013117174062 34.1791870291224100, 229.6027619754956675 34.1777429732541052, 229.6217226068458501 34.1763326529017633, 229.6405847437962109 34.1749265205166282, 229.6596052490299087 34.1735055274516242, 229.6788397629834719 34.1720654519100648, 229.6983584809424030 34.1706009485036830, 229.7180957279129814 34.1691167912386220, 229.7380788625919479 34.1676108189410357, 229.7584117626150544 34.1660750990312749, 229.7790969055735673 34.1645092650801132, 229.7996369175649534 34.1629506916830792, 229.8203742931991655 34.1613735312545685, 229.8416825810410273 34.1597493413921924, 229.8624957634054908 34.1581588787102532, 229.8824174025273237 34.1566326128934890, 229.9024284095941084 34.1550960779241066, 229.9235693655622299 34.1534695745373043, 229.9452549994267088 34.1517974117562630, 229.9672683738575074 34.1500959778672595, 229.9895003848597241 34.1483735026549837, 230.0115335641334582 34.1466621289056462, 230.0333871041056000 34.1449604787229646, 230.0555507513969360 34.1432306180995653, 230.0779079316405955 34.1414814476944599, 230.1005422999793382 34.1397063294055911, 230.1238833343022350 34.1378715065958502, 230.1469833844259369 34.1360508855456928, 230.1701524618428607 34.1342202326812796, 230.1934678024026084 34.1323734191500989, 230.2165682856072806 34.1305388896250506, 230.2389046257025598 34.1287602696899981, 230.2627494180453027 34.1268575758665520, 230.2877550266476021 34.1248575757214425, 230.3121994425046353 34.1228969832372258, 230.3374538174263648 34.1208664280740450, 230.3631413115423925 34.1187956311933505, 230.3880206606859531 34.1167841715787290, 230.4129740676316658 34.1147614028110624, 230.4381720995549188 34.1127134837281645, 230.4639006137480521 34.1106170799943840, 230.4899617773432681 34.1084879305144355, 230.5160751629498748 34.1063486759816996, 230.5424933622251444 34.1041786334010055, 230.5692512087759098 34.1019747431288138, 230.5962633487828271 34.0997437899986693, 230.6233712571642229 34.0974986648374738, 230.6505324126182188 34.0952428145793291, 230.6778991776199348 34.0929635735833614, 230.7056768659263355 34.0906437347729181, 230.7338743164805805 34.0882822720815781, 230.7624290255265862 34.0858841099150212, 230.7912515728409915 34.0834564852273800, 230.8203176007084778 34.0810012492433714, 230.8496066249822150 34.0785199486820005, 230.8792222278794100 34.0760036573598484, 230.9092353385083527 34.0734461134514106, 230.9394837890443739 34.0708608100599832, 230.9699110763695842 34.0682523866543931, 231.0006928671137985 34.0656056694953762, 231.0318850271158908 34.0629155854277812, 231.0635571685805303 34.0601758151630207, 231.0955368339715221 34.0574008702548809, 231.1277395307414224 34.0545978215856664, 231.1598263149443255 34.0517959465778262, 231.1923731407471791 34.0489451185415390, 231.2256091619747167 34.0460249134342661, 231.2592693971341760 34.0430580048563414, 231.2932997454268502 34.0400487931218905, 231.3276773418007508 34.0369989774649824, 231.3623788651742643 34.0339103206458304, 231.3976872583261866 34.0307573788087794, 231.4333912447760611 34.0275584580134378, 231.4693555745259914 34.0243253060918320, 231.5059110723479137 34.0210279684916301, 231.5428878341136851 34.0176812113605962, 231.5803120487275919 34.0142822698571479, 231.6182257695979274 34.0108269013428526, 231.6563923557117732 34.0073361890491626, 231.6951328868908320 34.0037805361373344, 231.7344016752473124 34.0001635697603888, 231.7741163312641959 33.9964923489273474, 231.8144687460353452 33.9927486903022995, 231.8555242504632190 33.9889258812754989, 231.8967616379406707 33.9850717165754332, 231.9384874591021060 33.9811573547210131, 231.9810031242021182 33.9771540026181711, 232.0239997221509896 33.9730898997487358, 232.0678388326644495 33.9689303373579179, 232.1123373516068966 33.9646917583446637, 232.1571892770959664 33.9604025763729709, 232.2028902908268719 33.9560149645457585, 232.2491821769203000 33.9515527436836990, 232.2960411960920908 33.9470175080060130, 232.3439306822214974 33.9423637059180976, 232.3925149925117353 33.9376227335627831, 232.4421795018198509 33.9327560905117309, 232.4923819960596063 33.9278156111136937, 232.5436698046292179 33.9227466788576564, 232.5951687841104842 33.9176343957194177, 232.6475716305862989 33.9124096240862514, 232.7012278929114473 33.9070362581488851, 232.7556828036422303 33.9015582140379479, 232.8111272809534853 33.8959551462227964, 232.8675924453869754 33.8902225112892950, 232.9251556043381015 33.8843509817138298, 232.9836292773927369 33.8783581196600210, 233.0432332672728819 33.8722199924782501, 233.1036814245413780 33.8659644315621762, 233.1655576135860599 33.8595295608053988, 233.2282972754190951 33.8529720150750393, 233.2926253690727378 33.8462144249607135, 233.3579653177716295 33.8393149569302949, 233.4238324436093990 33.8323232702830481, 233.4921199960124909 33.8250368579970129, 233.5612785480354319 33.8176174606137465, 233.6323604436500148 33.8099502310293190, 233.7049545856000634 33.8020762210515144, 233.8182991443937340 33.7896946459519754, 233.8076868008509450 33.7447711159585353, 233.7998795209612979 33.7148904496539359, 233.7932833619625796 33.6848666706177085, 233.7861879661206217 33.6548975268433708, 233.7790138730816238 33.6249371304411468, 233.7721258778469746 33.5949457575010726, 233.7653244274834776 33.5649451763320528, 233.7589504394325957 33.5348983220681589, 233.7517922483768587 33.5049370176588681, 233.7451099029024988 33.4749242026266884, 233.7380079966969788 33.4449572275375928, 233.7308913046056773 33.4150038907599480, 233.7242842859603229 33.3850066680614148, 233.7177523607820149 33.3550016103827929, 233.7105361717234473 33.3250710557136642, 233.7038713780214607 33.2950810139364961, 233.6970686628110343 33.2651062319824931, 233.6905337587843690 33.2351027783426076, 233.6840504440658606 33.2050940975069437, 233.6777241041899913 33.1750688065101542, 233.6714174241416231 33.1450417813746228, 233.6651265167774056 33.1149842340850284, 233.6589877928076646 33.0848829897737033, 233.6524321128083557 33.0548271750781311, 233.6459016737647971 33.0247690229860495, 233.6397274742706998 32.9946728446447679, 233.6329292365037418 32.9646443837786194, 233.6264198618044645 32.9345851796794449, 233.6202087450176350 32.9044942684929751, 233.6139880509850002 32.8744048431199474, 233.6079852676745929 32.8442924253051416, 233.6024480632221128 32.8141580579442405, 233.5966311950082854 32.7840805086041911, 233.5901811264418768 32.7540715697776363, 233.5840609927987259 32.7240276624917570, 233.5780234845818484 32.6939754072355768, 233.5723051527258463 32.6638894276889644, 233.5666017736687934 32.6338024225347070, 233.5607542213080876 32.6037314698474248, 233.5546837865367706 32.5736849919792704, 233.5486024504767215 32.5436402503859412, 233.5424177864383353 32.5135952204185656, 233.5365716066706341 32.4835032169014184, 233.5315060000013148 32.4533282706241195, 233.5261496478028675 32.4231850922122362, 233.5203742087318233 32.3930873795337675, 233.5147182817867417 32.3629775114589648, 233.5094845865763773 32.3328231674413402, 233.5039894604646804 32.3026974294728859, 233.4978335601193464 32.2726429030728994, 233.4931590404903545 32.2424309059519061, 233.4878027399519453 32.2122923884581667, 233.4822943076409558 32.1821707947332456, 233.4769428294368367 32.1520331689142935, 233.4715484851255951 32.1219008275854492, 233.4659832528489858 32.0917874106425174, 233.4604242297955636 32.0616740464830201, 233.4547057473552059 32.0315783750575207, 233.4493448634544279 32.0014453816849027, 233.4439538848272377 31.9713163427404155, 233.4388438488122119 31.9411582035282215, 233.4333516270229723 31.9110653071387809, 233.4279989229896444 31.8809809553688552, 233.4229566389217894 31.8508644673349011, 233.4183811247408471 31.8206993020757771, 233.4138877625083808 31.7905263248524932, 233.4092102825951258 31.7603737819921292, 233.4050516565336579 31.7301671583804321, 233.4001074315975757 31.7000447187404717, 233.3957145714181252 31.6698647916849545, 233.3913100752606340 31.6396870518961428, 233.3864447836710667 31.6095336383505341, 233.3812875213067741 31.5793879739752867, 233.3764952549095710 31.5492046025283273, 233.3713681255396750 31.5190575397734705, 233.3665069082488230 31.4888832849676525, 233.3615529341064416 31.4587197536657825, 233.3563206749479377 31.4285865291404711, 233.3514797002687260 31.3984129293746150, 233.3465577545539134 31.3682488233591918, 233.3417228712048939 31.3380764928643032, 233.3370904020155194 31.3078918588118036, 233.3327447690398628 31.2776856492936552, 233.3284034056367489 31.2474800413596085, 233.3238447530019926 31.2172983698287148, 233.3202001869975390 31.1870215346730824, 233.3161949178957286 31.1567837770521372, 233.3117460131502128 31.1265937911358250, 233.3074302663908668 31.0963908864289600, 233.3031004201629059 31.0661905619832162, 233.2993877462967305 31.0359264958431389, 233.2953127271858875 31.0057054348373704, 233.2898951297387669 30.9756300525971362, 233.2854622844029677 30.9454523393039729, 233.2811087259339331 30.9152674168075556, 233.2766787724962967 30.8850916312890398, 233.2723182338050663 30.8549096936050056, 233.2680625874326665 30.8247179032272562, 233.2636594360020013 30.7945427207441114, 233.2591073855289494 30.7643842796982661, 233.2546430264907542 30.7342178080200377, 233.2506548072034320 30.7039852299984197, 233.2467326448435188 30.6737304212484112, 233.2427735883874220 30.6434806792655507, 233.2385419916588489 30.6132606394362270, 233.2344263707328196 30.5830296839476610, 233.2299724549353641 30.5528352858511347, 233.2257801218785005 30.5226147736255093, 233.2217008350382912 30.4923836900961192, 233.2176536180877520 30.4621505031956623, 233.2137701088354333 30.4319014927804155, 233.2097164924082904 30.4016889943496160, 233.2057273903072883 30.3714876142592480, 233.2018315927718390 30.3412778048335809, 233.1982994815887196 30.3110314135535397, 233.1949660441975709 30.2807656745661049, 233.1909995459751883 30.2505672082381274, 233.1869329124752994 30.2203804896820323, 233.1830432861650308 30.1901766843827808, 233.1794294370546368 30.1599455462843871, 233.1757256557578444 30.1297251351229853, 233.1722016871373455 30.0994998764674975, 233.1687265873427179 30.0692827643412635, 233.1657971255530981 30.0390104337142958, 233.1620197154927894 30.0088276220750814, 233.1588110553424542 29.9785872277253844, 233.1558657450565590 29.9483210009760406, 233.1526520127341655 29.9180841252305392, 233.1489461529616278 29.8878997697228570, 233.1453943524509782 29.8577009226519010, 233.1419015803729451 29.8274974560358004, 233.1385470570977816 29.7972455511376992, 233.1353455350160289 29.7669455615571614, 233.1321205569348365 29.7366494892352904, 233.1286857502857117 29.7063766210683760, 233.1248502692661759 29.6761466884867851, 233.1219322346083231 29.6458233627870875, 233.1187887010911481 29.6155248850340520, 233.1158036470708339 29.5852115613503379, 233.1128189974144220 29.5548997434543921, 233.1096148239091974 29.5246121600882780, 233.1059421915535381 29.4943963292008320, 233.1029253621420025 29.4641350065570151, 233.1002381417339677 29.4338412717182401, 233.0969753053758780 29.4036085512377774, 233.0938295190486258 29.3733653616724588, 233.0913472163338440 29.3430553834682506, 233.0892058098756365 29.3127119349646996, 233.0863428536407014 29.2824445349173530, 233.0832116703506927 29.2522064239976096, 233.0797675612166131 29.2220021876194558, 233.0766708226084063 29.1917583918426793, 233.0740702319596096 29.1614600580881955, 233.0714565710325985 29.1311647753841925, 233.0690128689927576 29.1008537235407303, 233.0668902691410551 29.0705113857663484, 233.0645048567074298 29.0401978200141855, 233.0622308671956944 29.0098745532563811, 233.0598776027511860 28.9795611971617610, 233.0578674387686249 28.9492143656048597, 233.0557478221899146 28.9188805699773148, 233.0535026840429964 28.8885669116981312, 233.0508429036479754 28.8583027762630202, 233.0484008302731525 28.8280180911364923, 233.0460454447779455 28.7977263211135330, 233.0438808462283475 28.7674168095447023, 233.0413729393316942 28.7371443319351094, 233.0390306784746883 28.7068567067667786, 233.0369262675669688 28.6765465604912748, 233.0347470633640796 28.6462459426612384, 233.0329268350070890 28.6159104396763375, 233.0304011304804703 28.5856435995693232, 233.0285767800002930 28.5553016798027670, 233.0267613739262345 28.5249607573214767, 233.0251239162210481 28.4946035505042587, 233.0235861249755089 28.4642380888206468, 233.0216106033979031 28.4339193332039777, 233.0189545611958124 28.4036720750919400, 233.0154885602245827 28.3735094844736153, 233.0142983651916779 28.3431162820924243, 233.0278250723105486 28.3112211640421627, 233.0452282676261007 28.2789483187394843, 233.0538325274330589 28.2475942808537539, 233.0539975568593434 28.2171064726353187, 233.0513725666158678 28.1869063911921387, 233.0495940247798217 28.1566216920427621, 233.0476156283756097 28.1263594901669798, 233.0441012164608594 28.0962563986381255, 233.0341267619562302 28.0668153191364418, 233.0153669885793590 28.0382716562388339, 233.0004310857395353 28.0093374012700345, 232.9972907785160885 27.9791790793518480, 232.9993492557859156 27.9484712223743834, 232.9984005080535212 27.9180717344067304, 232.9974307125874589 27.8876765098117794, 232.9972130492355689 27.8572068668355186, 232.9974480176590248 27.8266933234036031, 232.9991589372480121 27.7960317666086958, 232.9989280134366254 27.7655700234404321, 232.9984242466573505 27.7351382270215510, 232.9981795284499242 27.7046822703985498, 232.9979878384312144 27.6742274580733785, 232.9973841036592148 27.6438208719076712, 232.9969627048587597 27.6133979690396210, 232.9956424441161857 27.5830686696773810, 232.9942467721409969 27.5527492409840562, 232.9928294278021781 27.5224342236403245, 232.9910051526982215 27.4921627558298596, 232.9892752251977015 27.4618839132474726, 232.9876407499768050 27.4315975974893540, 232.9860500535197616 27.4013090709302176, 232.9845431092176398 27.3710008489845045, 232.9832144523877844 27.3406640377800798, 232.9813211962254798 27.3103867100860782, 232.9796046601094588 27.2800936680591022, 232.9778668740711680 27.2498050024511933, 232.9760812623313200 27.2195234107127924, 232.9744936225061167 27.1892239957127515, 232.9725389188140809 27.1589640136351100, 232.9710993706493696 27.1286541056601607, 232.9695310658383107 27.0983595097609289, 232.9678740179707574 27.0681026007854726, 232.9664105876078111 27.0378534557978263, 232.9648174106994247 27.0076198078681955, 232.9633173340908456 26.9773791166841264, 232.9625444737449413 26.9470672981449368, 232.9609409653207877 26.9168418629111947, 232.9596090239708417 26.8865913871725191, 232.9583747341667959 26.8563334706327588, 232.9570418888685026 26.8260879392246387, 232.9556783045036639 26.7958479490434627, 232.9541208556390472 26.7656115503784413, 232.9529072543590758 26.7353254479347022, 232.9513372321343923 26.7050777308560647, 232.9496721067669398 26.6748420272777231, 232.9482697863891190 26.6445822619977086, 232.9469308519579442 26.6143185587959685, 232.9456308588468687 26.5840533948443891, 232.9445891873004371 26.5537646856240990, 232.9435705001869508 26.5234761549909059, 232.9424930683779849 26.4931960434053231, 232.9411883948879733 26.4629460272636905, 232.9404661357344253 26.4326443639049629, 232.9397077070689477 26.4023488674103000, 232.9389590229434361 26.3720549233813237, 232.9380771814213631 26.3417769121558294, 232.9371118552031135 26.3115098363276267, 232.9363055938855496 26.2812293227508356, 232.9349899869084197 26.2510025505052305, 232.9335253420107108 26.2207932922391471, 232.9325013463295591 26.1905423329871958, 232.9312666333587458 26.1603104014087862, 232.9304842316648205 26.1300312111542468, 232.9301915140905805 26.0997055104643714, 232.9294881720221895 26.0694236562733899, 232.9290727464842234 26.0391155706255368, 232.9284303148743334 26.0088329122365565, 232.9279035225714836 25.9785413248947492, 232.9273612165381451 25.9482539712151024, 232.9268538348704851 25.9179658022400403, 232.9262752017792195 25.8876874678260762, 232.9258886604946213 25.8574103205871531, 232.9254503184828593 25.8271578908632939, 232.9251078810469551 25.7968986263993507, 232.9246578931334284 25.7666529016514900, 232.9240220891315971 25.7364285483357094, 232.9236035389937456 25.7061852433890081, 232.9230685583847560 25.6759563790559397, 232.9227337275447098 25.6457103098674466, 232.9226746289442360 25.6154395052660426, 232.9151284100261705 25.5859193757088370, 232.8937666407002212 25.5577604985955951, 232.8940638253671409 25.5274256432220170, 232.8871864393980502 25.4978083492145373, 232.8887549686264435 25.4673523878265264, 232.8922447979715855 25.4367079619002290, 232.8868549804973611 25.4069505089587331, 232.8862070942742832 25.3767236847006359, 232.8896433828422516 25.3460933179880818, 232.8904085763714136 25.3157316468416127, 232.8749355208171608 25.2869872855028532, 232.8752451626990876 25.2566951708590217, 232.8833426365382877 25.2256500909277364, 232.8835253169675639 25.1953944685349569, 232.8791674519990806 25.1655927164969029, 232.8897864847603500 25.1343065994128700, 232.8853793267643084 25.1045158112194073, 232.8872412249220076 25.0741054814230750, 232.8902504011679184 25.0435843557807090, 232.8862819506101118 25.0137587010341953, 232.8849165370428977 24.9836776256239297, 232.8615444344878824 24.9557405574880384, 232.8678957259777746 24.9248252133515251, 232.8743003817854174 24.8939074623787384, 232.8845451259491313 24.8626121461173852, 232.8855114924644738 24.8322389784330113, 232.8777786941511465 24.8027302998354422, 232.8784494296954222 24.7723922673367660, 232.8786766283392922 24.7421011267217601, 232.8815821187694723 24.7115479151651094, 232.8784798198719841 24.6815922416011517, 232.8815210227576245 24.6510507831911276, 232.8869507732288184 24.6202941882075912, 232.8897516432224961 24.5898008394087846, 232.8918981619777924 24.5593753742191865, 232.8953447469445734 24.5288244473813180, 232.9021256320803843 24.4979467949218126, 232.9055803919187895 24.4674014152638897, 232.9256796375334488 24.4352113534955322, 232.9278143679030677 24.4048031512248613, 232.9273308331008536 24.3746574338355266, 232.9233851756903277 24.3448714449377732, 232.9184915904162665 24.3151952702327385, 232.9128735282336322 24.2855934652230268, 232.9070168456449323 24.2560179020738893, 232.8961245152644040 24.2269419338317213, 232.9056956378175869 24.1958493514343687, 232.9163992199943323 24.1646481368294062, 232.9148753746634668 24.1346574496068342, 232.9260392072289392 24.1034175401604038, 232.9206813331250885 24.0738120738219301, 232.9204495719246779 24.0437090840601435, 232.9242943936257006 24.0132123142740319, 232.9256437469389311 23.9829650937303498, 232.9266377198844395 23.9527562659602467, 232.9335016545540498 23.9219720545757646, 232.9350094750091387 23.8917194174715100, 232.9318311547083624 23.8619319938418819, 232.9368722188254139 23.8313379253568662, 232.9450679384852094 23.8004364541792732, 232.9487612034705819 23.7699821916536962, 232.9457539896300773 23.7401711442871708, 232.9427211902646491 23.7103463854447050, 232.9402080395296366 23.6804735787408447, 232.9433835895079312 23.6500442501760695, 232.9429844398777618 23.6199700525028859, 232.9448047519951217 23.5896808976233565, 232.9476776159105498 23.5592916674110846, 232.9482010009696182 23.5291369225008005, 232.9512697052308852 23.4987353647413286, 232.9482075708974946 23.4689398429934215, 232.9524304167965454 23.4384270364512481, 232.9546730815462467 23.4081077649794267, 232.9582883791230756 23.3776571361768752, 232.9647493343327085 23.3469304506696140, 232.9703738876218324 23.3162894619193146, 232.9749310816914658 23.2857568941960480, 232.9745359583259585 23.2557144439031767, 232.9767231065955286 23.2254218016588858, 232.9747120126448010 23.1955449259003750, 232.9822413991412304 23.1647348154436621, 232.9804333911563390 23.1348442844337647, 232.9799632300583312 23.1048251183938760, 232.9861015982691583 23.0741610277334033, 232.9875906069682969 23.0439567790242954, 232.9885163913017152 23.0138113510139206, 232.9880927477934165 22.9838018052555668, 232.9920786514292104 22.9533634402218389, 232.9956900446725570 22.9229654566407355, 232.9980286667984331 22.8926959144764481, 232.9994463253835590 22.8625202869970394, 233.0007273526802010 22.8323817679763827, 233.0026223770331910 22.8022057943616439, 233.0043541573523385 22.7720495281594388, 233.0056855082923164 22.7419361869260115, 233.0075168387004112 22.7117776144770147, 233.0086972638558791 22.6816864801467410, 233.0110141288599834 22.6514878824316952, 233.0150980294305043 22.6211202181119297, 233.0183630375206860 22.5908364990390211, 233.0205235275349764 22.5606646287341768, 233.0226990887721854 22.5304748351912814, 233.0250312225587948 22.5002543317498116, 233.0273417263018416 22.4700397097962856, 233.0294322532687943 22.4398503560864988, 233.0316537239692423 22.4096519871084432, 233.0341646706244774 22.3794291321900545, 233.0365342745103874 22.3492238901019569, 233.0390090293491596 22.3190121957782992, 233.0410423260715618 22.2888474232953939, 233.0431049502272174 22.2586836086433451, 233.0454588237505789 22.2284945392465687, 233.0478015505857741 22.1983097811950500, 233.0502410034338254 22.1681194493875857, 233.0528960636553961 22.1379119637526749, 233.0557407390418234 22.1076898815501366, 233.0583526793505200 22.0774943965698363, 233.0611965967989363 22.0472802077131540, 233.0637667921969012 22.0170966233224057, 233.0661707315231581 21.9869331637061833, 233.0688355153386908 21.9567482212916190, 233.0712133978703946 21.9266163989694398, 233.0735932640259307 21.8965084711711100, 233.0760567737850124 21.8663964170824769, 233.0786160066152775 21.8362790739403572, 233.0813521304598623 21.8061485619774231, 233.0841934458621552 21.7760118754163514, 233.0868186396090209 21.7459002818275557, 233.0896572713970727 21.7157720085455743, 233.0925606004185511 21.6856415365210218, 233.0953944801916293 21.6555219188819841, 233.0982658466593875 21.6253757163975280, 233.1010684294436999 21.5952146481066016, 233.1039565017079269 21.5650493243033381, 233.1070084940014340 21.5348721396217897, 233.1101013319822357 21.5046950640766852, 233.1128703123239063 21.4745535126135110, 233.1158241927793142 21.4443980968924066, 233.1188318355480362 21.4142415633379244, 233.1218563891699773 21.3840874973898849, 233.1246794784816245 21.3539570958571829, 233.1274225832100910 21.3238601081567190, 233.1306370617675157 21.2937419770209679, 233.1338110027921857 21.2636319988396920, 233.1368714755917608 21.2335372463016760, 233.1401888171233736 21.2034218386528366, 233.1433772704574494 21.1733231702659630, 233.1465315268246457 21.1432320717217443, 233.1496154959708065 21.1131520454980688, 233.1523256639130466 21.0831124744103207, 233.1550432762235232 21.0530764456413202, 233.1579828490156387 21.0230058063689711, 233.1607722022461644 20.9929374509098636, 233.1636624179120645 20.9628635553827110, 233.1666398144984100 20.9327854559908850, 233.1696517887513096 20.9027082545512961, 233.1726003363481823 20.8726414316977440, 233.1758702060247117 20.8425478179737915, 233.1788078854982871 20.8124905746892104, 233.1817470919710615 20.7824374566928078, 233.1847240762937474 20.7523849750790745, 233.1882571693559498 20.7222788477096316, 233.1922497392443177 20.6921286819550332, 233.1963717972563472 20.6619703874637395, 233.1999109852516483 20.6318727136307807, 233.2035406236984159 20.6017706852433626, 233.2070288686839490 20.5716866762562276, 233.2105921938348274 20.5415998141373564, 233.2140636676945746 20.5115262079963792, 233.2178119025755336 20.4814303280644161, 233.2217592401371462 20.4513196857803798, 233.2251909010133204 20.4212673944372689, 233.2282694103726897 20.3912575382923755, 233.2318419183720835 20.3612045155384997, 233.2355239631258144 20.3311453846168178, 233.2391586892739497 20.3010952641717921, 233.2428990778244042 20.2710394343307705, 233.2464567058539444 20.2410056661055044, 233.2499761033736831 20.2109800536504132, 233.2536732782234878 20.1809418255188824, 233.2573748161835283 20.1509076803910609, 233.2610258437821074 20.1208946526849886, 233.2648839717209057 20.0908774184780903, 233.2690707989325460 20.0608332120380233, 233.2729399482162762 20.0308241593812788, 233.2766399932848742 20.0008359800302244, 233.2812975167611285 19.9707604952090776, 233.2864835103510757 19.9406389605955141, 233.2910589910247836 19.9105807427105042, 233.2951517126599299 19.8805735518949831, 233.2994281961829017 19.8505534224128048, 233.3035672940802101 19.8205511748355683, 233.3079874497330195 19.7905266855421935, 233.3129269619056743 19.7604571405118357, 233.3212816261563489 19.7300649786930506, 233.3230339211604019 19.7003105136032453, 233.3250709696296497 19.6705333692991715, 233.3296297889724826 19.6405193532041906, 233.3340604186102496 19.6105224014847792, 233.3383183317661747 19.5805467749846187, 233.3428179008550671 19.5505528169449825, 233.3472901992914785 19.5205884333979363, 233.3519547732985586 19.4906315128301806, 233.3565130546640205 19.4606896821475424, 233.3611875777690443 19.4307416676413673, 233.3661894041850076 19.4007673213927738, 233.3703364724232756 19.3708796064123803, 233.3750997858020355 19.3409379714967358, 233.3796821892690616 19.3110185897310593, 233.3838727405633620 19.2811415855535024, 233.3885341450790349 19.2512246218782614, 233.3933864584715820 19.2212534983463215, 233.3986811270121962 19.1912063080396358, 233.4036949065424835 19.1611907724642343, 233.4090010489056510 19.1311522333807353, 233.4132186011130443 19.1012223437648210, 233.4123898128762278 19.0717780874600393, 233.4234938189524655 19.0412018332757356, 233.4281136089198299 19.0112482689356206, 233.4325499945081219 18.9813170712961394, 233.4385722857594772 18.9512397884658697, 233.4443472690545605 18.9211910404965309, 233.4496096003589969 18.8911960802610075, 233.4547716287821686 18.8612156352759506, 233.4583507148462047 18.8313907512887653, 233.4655539294550408 18.8012260955363750, 233.4711278179178464 18.7712214498863723, 233.4767412813863814 18.7412180639201722, 233.4825004791105982 18.7112058596519368, 233.4883578878495314 18.6811893699630893, 233.4930940640239214 18.6512844874852739, 233.4992980389991146 18.6212451930891127, 233.5048315557592673 18.5912746804501623, 233.5077083130713049 18.5615615247693881, 233.5090647558613739 18.5319976053586331, 233.5185189875365666 18.5016701736589049, 233.5255892491283305 18.4715741712361989, 233.5300607517884828 18.4417298954107771, 233.5355540635434579 18.4117937924565673, 233.5416644760109932 18.3818043138120792, 233.5436055661265016 18.3522152471724311, 233.5514883551133494 18.3220390662315573, 233.5588538186819392 18.2918895888876669, 233.5647531551124416 18.2618841625846500, 233.5705679159131591 18.2318918457248778, 233.5766138332255082 18.2018827384489974, 233.5826686375446570 18.1718779111487798, 233.5888785940030914 18.1418635244420230, 233.5951383724894868 18.1118495698953126, 233.6014674717557966 18.0818342120025726, 233.6076764098261833 18.0518354029742305, 233.6140209227432081 18.0218522835686414, 233.6204423279392302 17.9918892524204779, 233.6265487125820925 17.9619613307872079, 233.6313515420965530 17.9321620036759981, 233.6386754122240745 17.9021295475782303, 233.6451980362392078 17.8721782134589731, 233.6513777078439773 17.8422646488452870, 233.6535623905758143 17.8127339294964280, 233.6609506869070287 17.7827168172749950, 233.6699594121416794 17.7525520609224401, 233.6710216308924544 17.7231431656690432, 233.6718987098583682 17.6937567665229594, 233.6886100268676500 17.6628813678396774, 233.6960663231332944 17.6328849765218045, 233.7026278416137188 17.6029784898588098, 233.7090592956413104 17.5730897220186435, 233.7159774814714126 17.5431605027914799, 233.7217275110074581 17.5133469216565452, 233.7187734900754208 17.4843590861112936, 233.7270853487591751 17.4543148474000560, 233.7331808851990047 17.4244650559326786, 233.7435127698205974 17.3942028951707535, 233.7536136128401267 17.3639679699476694, 233.7604356218571127 17.3340473253071998, 233.7671770105191911 17.3041397119190847, 233.7740217619244163 17.2742278149562694, 233.7808503091249293 17.2443229050635445, 233.7874669750843282 17.2144434060740714, 233.7940569944907736 17.1845718878611855, 233.8008596205570200 17.1546858578559558, 233.8077378291946218 17.1248364577951477, 233.8147908325216520 17.0950124866744311, 233.8216472066112317 17.0652127325469856, 233.8287550493209892 17.0353950863091299, 233.8358236306713422 17.0055868895775504, 233.8429318881181871 16.9757807353939576, 233.8498250518302370 16.9460005561754876, 233.8567982141668722 16.9162186518052877, 233.8644027756993751 16.8863833032343429, 233.8717789035609087 16.8565752238410482, 233.8787743160380899 16.8267903345665388, 233.8864271817588190 16.7969322128414085, 233.8943020025787405 16.7670590849023320, 233.9020234300422487 16.7372061476441409, 233.9097388867146208 16.7073595931862542, 233.9174310494171891 16.6775210529366973, 233.9253368303507159 16.6476683527251197, 233.9331359108360573 16.6178315077103491, 233.9401620373827768 16.5880728789295020, 233.9480199089602763 16.5582422695100639, 233.9556240345705191 16.5284143707629028, 233.9629611957227553 16.4985917371710613, 233.9680858448260494 16.4689817308887676, 233.9697189397047907 16.4397036867894251, 233.9810825592319361 16.4095219192914819, 233.9908561421488571 16.3794945960678326, 233.9882558499625418 16.3506288802721613, 234.0070396856991124 16.3197717513327625, 234.0069713601554611 16.2906809733869657, 234.0202313690597578 16.2603515812108093, 234.0396206155035372 16.2294769328209796, 234.0450716397836004 16.1999297991700111, 234.0561919774314674 16.1698594103974891, 234.0658256086437063 16.1399339059389888, 234.0741862235724966 16.1101332895771421, 234.0828109354990545 16.0803141029572600, 234.0913423006933272 16.0505097118745965, 234.0998453017218424 16.0207140639679864, 234.1085331394955062 15.9909072931318139, 234.1171059040658804 15.9611173753279019, 234.1257060293999359 15.9313287300730444, 234.1339610716019308 15.9015761555569703, 234.1421311332078687 15.8718375959628091, 234.1504002200311163 15.8420959238847718, 234.1587546091515435 15.8123524374057407, 234.1674495385412911 15.7825834029764227, 234.1763947307113369 15.7527972553506963, 234.1849920610645768 15.7230496510930529, 234.1933783956116031 15.6933278490381323, 234.2016682329614810 15.6636212040259846, 234.2106661103412080 15.6338573919960844, 234.2195850306243585 15.6041094924468524, 234.2284696631510883 15.5743710697067037, 234.2372546661415527 15.5446481978965938, 234.2462970040240577 15.5149077482776239, 234.2553563459844668 15.4851720526347219, 234.2644515617519687 15.4554393746422996, 234.2736445752768759 15.4257039865954653, 234.2828900292420826 15.3959701114841270, 234.2920854378215267 15.3662472679597375, 234.3013275326234464 15.3365240161494683, 234.3104684932162343 15.3068141676424592, 234.3196567191314728 15.2771063206136155, 234.3288051987633480 15.2474085455542010, 234.3378564295157105 15.2177261764300678, 234.3470450336738793 15.1880375022826879, 234.3562524205285911 15.1583535187513530, 234.3654777347240952 15.1286743194410604, 234.3747378390860092 15.0989983563807062, 234.3840812977530277 15.0693211573935493, 234.3931289748404652 15.0396512748819191, 234.4024907295219009 15.0099336757912134, 234.4122604236426071 14.9801847783205861, 234.4219977298243407 14.9504452811145558, 234.4316158217009445 14.9207232127847913, 234.4409823342089965 14.8910307929301950, 234.4498350294495594 14.8613922149404161, 234.4587414398604324 14.8317550982339306, 234.4679675150275386 14.8020949299082680, 234.4770902769993768 14.7724507459251111, 234.4864736845448761 14.7428161288563455, 234.4957933016077618 14.7132196609919141, 234.5055218342258740 14.6835921628358417, 234.5149128961783731 14.6540024088048977, 234.5240841564354923 14.6244395507798366, 234.5338855767652717 14.5948253660254430, 234.5441277234739630 14.5651773498399315, 234.5546148327972560 14.5355135560838367, 234.5650071688638718 14.5058652498629623, 234.5754239657616154 14.4762214795646713, 234.5860298985859345 14.4465631055522845, 234.5967350016157980 14.4168986452192929, 234.6069521171130816 14.3872858481746757, 234.6171532263267352 14.3576813564971797, 234.6275466849351119 14.3280660631511427, 234.6379311558054326 14.2984584661645968, 234.6483279332099698 14.2688566257719334, 234.6586953216983318 14.2392643796648954, 234.6688702853703603 14.2096966782432101, 234.6792465123589011 14.1801174491704600, 234.6895268522844731 14.1505511410281279, 234.6998289458050806 14.1209871013773061, 234.7101500403533976 14.0914282332427909, 234.7207265998918047 14.0618529130783187, 234.7321276655577265 14.0322091288899919, 234.7421715997281808 14.0026964531666795, 234.7518848048210032 13.9732209510139391, 234.7623775583252552 13.9436811557223272, 234.7730116693621483 13.9141354453401398, 234.7836780942089945 13.8845938048401454, 234.7943396394510387 13.8550596464772120, 234.8051586497037135 13.8255181702998513, 234.8160814505063740 13.7959742977803899, 234.8270783541463231 13.7664307566487150, 234.8381481290801673 13.7368876813875094, 234.8493417356832538 13.7073404463484767, 234.8606864126223002 13.6777865962651948, 234.8720570731951227 13.6482375499376882, 234.8830833198969401 13.6187270374915155, 234.8942578962761161 13.5892102040071983, 234.9053801470764142 13.5596778329073899, 234.9167589099882889 13.5301032212135421, 234.9279630763072362 13.5005515903067401, 234.9394192269006965 13.4709841687102436, 234.9508887096513661 13.4414226751736940, 234.9626309718141783 13.4118435576556774, 234.9742477502246629 13.3822830148562506, 234.9858310021840282 13.3527327039232198, 234.9970791630884435 13.3232199974438803, 235.0084942267340864 13.2936993451161918, 235.0186419329412502 13.2643038495101493, 235.0288272444620077 13.2349149253326068, 235.0401198046571380 13.2054328064297675, 235.0532620150219429 13.1757903603399633, 235.0624271216925081 13.1465153771828209, 235.0713600073557075 13.1172684944642111, 235.0793940345812700 13.0881099970756303, 235.0890500823631157 13.0588118578658747, 235.1001302413494045 13.0293921654755245, 235.1114135830976579 12.9999613924081725, 235.1209243704139737 12.9707237608108290, 235.1309020905796956 12.9414756652994871, 235.1414756824528354 12.9121812020434952, 235.1521051686026453 12.8828891505364300, 235.1634486053033868 12.8535402166422994, 235.1748378342097396 12.8241946970120999, 235.1866932403923727 12.7948147510022991, 235.1962591092761841 12.7656485148328542, 235.2079865871087918 12.7362952191002208, 235.2197326753089612 12.7069478742196704, 235.2313225721933634 12.6776155786555993, 235.2423722902041163 12.6483331655838960, 235.2530634953859305 12.6190905341801578, 235.2639518191064383 12.5898377703569100, 235.2744025920220849 12.5606318602069944, 235.2867725908210446 12.5312613936619748, 235.2991023667242985 12.5019022720519857, 235.3116716239582615 12.4725294412281666, 235.3219926194716152 12.4433657660418930, 235.3334198870870750 12.4141106634952507, 235.3448295696518926 12.3848381642486984, 235.3590631821656700 12.3552954060809768, 235.3671572194415944 12.3263093689396559, 235.3791241627797319 12.2969845358657945, 235.3921032502748858 12.2675769256364440, 235.4040318795581186 12.2382708373989573, 235.4133898130075124 12.2092018442350998, 235.4233087213997067 12.1800902646282925, 235.4339080986466115 12.1509255318467915, 235.4452235719082864 12.1217045745757819, 235.4567443237030773 12.0924703558084179, 235.4687492492635670 12.0631982532119988, 235.4810288740251849 12.0339094862614715, 235.4933593769877120 12.0046240089340053, 235.5055131848779126 11.9753620784343049, 235.5183936068819435 11.9460434003433491, 235.5313914414788030 11.9167221954071394, 235.5445277552505274 11.8873966214008568, 235.5579758501142749 11.8580513222656219, 235.5708596309736720 11.8287640873522850, 235.5855568216224185 11.7993272976514501, 235.5997530467545005 11.7699461619532091, 235.6118792700054598 11.7407565433979393, 235.6222863801276901 11.7117271088094679, 235.6370065832145997 11.6823236091692451, 235.6501351706685341 11.6530691111257187, 235.6620789000052980 11.6239274595492343, 235.6746660025543463 11.5947368831844280, 235.6884231604871331 11.5654509340061900, 235.7004295446835158 11.5363277617227080, 235.7116587817768050 11.5072743978447640, 235.7235065836390788 11.4781679472845699, 235.7365096551736485 11.4489676032299617, 235.7509681344467083 11.4196470655488547, 235.7663406604226850 11.3902542184105808, 235.7777363715495085 11.3612199442349784, 235.7886739886716043 11.3322339874586131, 235.8008113265921963 11.3031504556407096, 235.8129270659356678 11.2740769145603643, 235.8254455463878685 11.2449760862190988, 235.8379734895646891 11.2159103138154315, 235.8515159916051402 11.1867900343133702, 235.8657944078840103 11.1576136472980831, 235.8797318095176365 11.1284757052386034, 235.8937716656943451 11.0993373101898083, 235.9083287919161478 11.0701621526027001, 235.9230551243026355 11.0409807942066465, 235.9376740007601825 11.0118174850483133, 235.9515272763501912 10.9827297851745165, 235.9638445602442971 10.9537849358193409, 235.9770623676844821 10.9247485593680569, 235.9907218609045003 10.8956618896021116, 236.0047319410605269 10.8665530900843592, 236.0183309333073396 10.8374886511592994, 236.0323861690089302 10.8083929297650290, 236.0537151650615897 10.7647439316756586, 235.8067955133633973 10.7864349998059303, 235.6404746257572924 10.8009251269396263, 235.4886934161605154 10.8140812538595235, 235.3440743681663321 10.8265506526567350, 235.2013541677908677 10.8387871304147918, 235.0605785760583046 10.8507895529034926, 234.9266644391624368 10.8621511165711979, 234.7983134326703407 10.8729887160495498, 234.6742684848909448 10.8834132357353326, 234.5539738435579977 10.8934756929011449, 234.4326844057674464 10.9035680020322605, 234.3062264801270658 10.9140277809828365, 234.1842183967351616 10.9240715931438945, 234.0687460570606220 10.9335373293233324, 233.9561439769082369 10.9427259418076410, 233.8474210956636057 10.9515604135457085, 233.7435151522108470 10.9599707574453173, 233.6385624025299990 10.9684248104218582, 233.5358140067679642 10.9766660933163926, 233.4407131631540437 10.9842712723620792, 233.3422237141487017 10.9921074822316367, 233.2513957968668024 10.9993144684267641, 233.1514470230827101 11.0071956760925467, 233.0568672341269121 11.0146280042264575, 232.9714593141212902 11.0213255319210663, 232.8803341230215551 11.0284323244705966, 232.7943082344638981 11.0351214682241974, 232.7094524258490083 11.0416948896741332, 232.6269891539112962 11.0480614832390529, 232.5469229652692320 11.0542229776525041, 232.4651981313407134 11.0604848216034473, 232.3872682244131909 11.0664391550737502, 232.3089820002441002 11.0723973916263372, 232.2344266808455302 11.0780568264050938, 232.1612777882618559 11.0835918116480201, 232.0879579900154397 11.0891193380045809, 232.0165771813923357 11.0944847829428479, 231.9444953164284300 11.0998822668852739, 231.8732154220789994 11.1052019606719465, 231.8057772059855211 11.1102241836924787, 231.7386284223740347 11.1152083219001430, 231.6726527935756792 11.1200909547655851, 231.6064561948269045 11.1249729599094174, 231.5413069011251253 11.1297634611590279, 231.4780838222096122 11.1344005204152676, 231.4150219500268406 11.1390109034406830, 231.3534789037269661 11.1434985250841070, 231.2922763752998208 11.1479476253113834, 231.2321986804822416 11.1523031971472300, 231.1727759778447648 11.1565989554036538, 231.1144830584694887 11.1608020872666742, 231.0567419751295120 11.1649536385455743, 231.0002949603148465 11.1690023089748021, 230.9442330256015055 11.1730119569495585, 230.8887529573815129 11.1769692032590324, 230.8340953656575323 11.1808578017412295, 230.7801047938868351 11.1846889342885767, 230.7267933250123519 11.1884621644846547, 230.6741394301110120 11.1921793597432231, 230.6222024977055014 11.1958368476763059, 230.5710284673378965 11.1994319110294054, 230.5203688901653436 11.2029818304778850, 230.4702850162558434 11.2064827482388729, 230.4211332149644136 11.2099109379701982, 230.3722347960824379 11.2133125719045719, 230.3238995148852553 11.2166669987618999, 230.2759727552675599 11.2199848672675291, 230.2288337046649644 11.2232410798167255, 230.1821784107627877 11.2264562859272328, 230.1360978921009348 11.2296246903372410, 230.0904502464950951 11.2327559868123661, 230.0451126661348269 11.2358585089428740, 230.0005121694876493 11.2389042679814661, 229.9563201538447572 11.2419152341291522, 229.9126038169218020 11.2448872011930661, 229.8693914420437352 11.2478185506150439, 229.8266141936540805 11.2507140177014850, 229.7844926752383685 11.2535594487366986, 229.7426279584774420 11.2563810618931122, 229.7011060076232241 11.2591734075795635, 229.6601354388789673 11.2619231614295536, 229.6197463420455733 11.2646286372288937, 229.5797488137805829 11.2673023162613966, 229.5399124326949050 11.2699591633166492, 229.5003744155744698 11.2725904639474663, 229.4613780020166018 11.2751808122798849, 229.4229479289674032 11.2777288707644558, 229.3846678777064767 11.2802613604292219, 229.3465203971857989 11.2827794526242791, 229.3092627460602273 11.2852352682303056, 229.2721541795532687 11.2876759727370040, 229.2355028971706190 11.2900822055440635, 229.1990236077036229 11.2924720972138957, 229.1627789235940611 11.2948417900965428, 229.1268004674435872 11.2971894009815763, 229.0910977852282429 11.2995144425355125, 229.0558429789213335 11.3018062999907833, 229.0210984390760132 11.3040612741932716, 228.9866394069154012 11.3062935182439883, 228.9523786369067579 11.3085085479184446, 228.9184628476487262 11.3106973739432899, 228.8847576778044015 11.3128684166155420, 228.8514037966511125 11.3150131009990815, 228.8184344402544639 11.3171295215342020, 228.7856962146691160 11.3192272250004802, 228.7530968391216106 11.3213119416556740, 228.7207523182553359 11.3233766438828916, 228.6886580791903896 11.3254217054488961, 228.6568808000483557 11.3274431670438851, 228.6255699416132074 11.3294320811176288, 228.5943557727729001 11.3314109976851860, 228.5633199203972481 11.3333750202213412, 228.5325366678424643 11.3353197347103816, 228.5019329259182825 11.3372496289215654, 228.4715394680745817 11.3391629188434351, 228.4413945509315909 11.3410573865564004, 228.4114629408693133 11.3429352267370014, 228.3817510016937433 11.3447961341559385, 228.3522475214021483 11.3466408530416665, 228.3230615139326005 11.3484629748935966, 228.2940740736275984 11.3502696641036316, 228.2653336387778324 11.3520581199663511, 228.2367430860697368 11.3538341663225264, 228.2082916103096011 11.3555984904911433, 228.1800368130806191 11.3573477475154032, 228.1520392237890462 11.3590784464354098, 228.1243947354944339 11.3607850493609046, 228.0969443603411833 11.3624769794926568, 228.0696393456309181 11.3641571482789345, 228.0424929933024316 11.3658248267828199, 228.0154106641687122 11.3674855739070715, 227.9885578563494448 11.3691297953498367, 227.9618650794217558 11.3707615940650122, 227.9353348111926039 11.3723808773752566, 227.9089933044652696 11.3739861801534410, 227.8828228745919091 11.3755785815686270, 227.8568634996878473 11.3771558345669810, 227.8309964239478518 11.3787248265793970, 227.8053094676697867 11.3802805503902693, 227.7797848238557492 11.3818240807616586, 227.7544332388539488 11.3833548536521398, 227.7292690741718388 11.3848721031974858, 227.7042771343964205 11.3863767514056438, 227.6794424865365158 11.3878696987456021, 227.6547547108999652 11.3893515833190406, 227.6302153125823224 11.3908223637730615, 227.6058446822500514 11.3922809322273224, 227.5815837284566783 11.3937306712904363, 227.5574768187691745 11.3951691153037267, 227.5335303503333364 11.3965959501440786, 227.5097275399122623 11.3980121642391321, 227.4860553007769681 11.3994185320703085, 227.4625029322781415 11.4008156893324628, 227.4390700032320183 11.4022036943938314, 227.4157514915810907 11.4035828609830805, 227.3925662525238351 11.4049521734721129, 227.3695676411417423 11.4063087093581785, 227.3466880305288953 11.4076562680319284, 227.3239817936706970 11.4089918767020748, 227.3013618133060163 11.4103203927983330, 227.2788626998114694 11.4116399330885390, 227.2564905837964488 11.4129501940688858, 227.2341471861257958 11.4142566063334225, 227.2119503831812608 11.4155527167971407, 227.1898755316247218 11.4168399144206774, 227.1679212759833035 11.4181183068200607, 227.1461045130949401 11.4193870060619087, 227.1244248889431105 11.4206460692871250, 227.1028554367275092 11.4218969989113255, 227.0813921445946448 11.4231400422550973, 227.0600099683273072 11.4243765834363167, 227.0387800565281395 11.4256027995450964, 227.0176858866713019 11.4268196233056631, 226.9967364182936365 11.4280266090393461, 226.9758565800003680 11.4292278308191211, 226.9550385935672239 11.4304237238189828, 226.9342329016720612 11.4316169579195979, 226.9135052379878346 11.4328040202420347, 226.8929749480174962 11.4339785612945999, 226.8725374557916155 11.4351462062953271, 226.8522123581987842 11.4363059371511344, 226.8319968195331171 11.4374579340044740, 226.8118864201224483 11.4386024598255549, 226.7918595656055913 11.4397406845346215, 226.7719343835069594 11.4408716721420642, 226.7520928931490118 11.4419963969996026, 226.7323585007395934 11.4431136486168281, 226.7126918304158494 11.4442255234874661, 226.6930802682925616 11.4453327000335001, 226.6735784057245553 11.4464323336035516, 226.6541678320596986 11.4475254147734731, 226.6348499723015095 11.4486118924986187, 226.6156086420508871 11.4496926332953510, 226.5964513089188301 11.4507672681319903, 226.5773802830682087 11.4518356983330953, 226.5583938982743746 11.4528980320372344, 226.5394514986697629 11.4539563930477577, 226.5205720112765277 11.4550098145152610, 226.5017744116919403 11.4560573339754512, 226.4830830479991164 11.4570977194971331, 226.4644630477084490 11.4581327889288342, 226.4458929607690152 11.4591636594085848, 226.4273420018072045 11.4601919179307483, 226.4089327375779703 11.4612113075504123, 226.3905321797907959 11.4622286455833962, 226.3721760724207854 11.4632421133510061, 226.3540415653077389 11.4642427211471745, 226.3361333516323270 11.4652302893049658, 226.3181669859150134 11.4662192771479354, 226.3002739486517783 11.4672030229445170, 226.2824320913053100 11.4681826620402063, 226.2646422367285197 11.4691581650898744, 226.2469095834721315 11.4701292831078110, 226.2292344049324697 11.4710960160929343, 226.2116353879820565 11.4720574419655836, 226.1941018513796280 11.4730141135587900, 226.1766306716323811 11.4739662027049150, 226.1592231105862822 11.4749136616747478, 226.1418925461015306 11.4758558408019180, 226.1246140672760987 11.4767939954951359, 226.1074024905091449 11.4777274041279629, 226.0902695214741414 11.4786555042766718, 226.0731674626649976 11.4795806696915506, 226.0561148944835281 11.4805019915932736, 226.0391203976556369 11.4814190596915857, 226.0221853383620783 11.4823318209415355, 226.0053302814421556 11.4832392822444014, 225.9885536989872605 11.4841415383638772, 225.9718003975531531 11.4850413028522933, 225.9550662527171312 11.4859387811404936, 225.9383869128346873 11.4868322431939074, 225.9217536701528388 11.4877221247974717, 225.9051656781837778 11.4886084777362623, 225.8886411839923767 11.4894904303679706, 225.8721818201447036 11.4903679195481985, 225.8557774564206682 11.4912414492826116, 225.8394241488472858 11.4921112224739144, 225.8231345766313609 11.4929766430689337, 225.8068834000266349 11.4938389402025560, 225.7906841315520694 11.4946974768609138, 225.7745264906774594 11.4955527559106745, 225.7584156584585457 11.4964045403916142, 225.7423465946622230 11.4972530808839242, 225.7263306551091091 11.4980978487175864, 225.7103637501322737 11.4989390503740232, 225.6944403536005268 11.4997769586410374, 225.6785731333581566 11.5006109868170299, 225.6627606321947610 11.5014412173748006, 225.6469855377237650 11.5022684764168144, 225.6312478555481675 11.5030927722805192, 225.6155505187082611 11.5039139764861762, 225.5999034371537562 11.5047316362784322, 225.5843036923903639 11.5055458998999516, 225.5687372937137525 11.5063574287778980, 225.5532030184873520 11.5071662870799507, 225.5377227249360317 11.5079714709823264, 225.5222898787817769 11.5087732957038735, 225.5069090090458701 11.5095715644305443, 225.4915549235071524 11.5103674479764901, 225.4762447625165862 11.5111601660590104, 225.4609749326404540 11.5119498939062836, 225.4457365038296643 11.5127370489516920, 225.4305250723085123 11.5135218388634897, 225.4153505895347962 11.5143038171354615, 225.4002092546294307 11.5150831649260734, 225.3851016085648098 11.5158598654308193, 225.3700330195559616 11.5166336842156181, 225.3550142447416533 11.5174041464569328, 225.3400350352194152 11.5181717255997285, 225.3250842761335662 11.5189369296463209, 225.3101705090120106 11.5196993830341849, 225.2952945149421566 11.5204590600330974, 225.2804449879838273 11.5212164731367626, 225.2656236019609821 11.5219715538304612, 225.2508347977908443 11.5227241118179400, 225.2360836991663291 11.5234739286213994, 225.2213701223733437 11.5242210219101899, 225.2066922232514514 11.5249654823094705, 225.1920523314329614 11.5257072167331263, 225.1774439551033993 11.5264465188925040, 225.1628688639249276 11.5271833193649424, 225.1483231609240931 11.5279177960410184, 225.1338080113109470 11.5286499054960867, 225.1193156868265817 11.5293799896077189, 225.1048406914387385 11.5301082903624863, 225.0903927203178796 11.5308343936089983, 225.0759731997254676 11.5315582445733433, 225.0615726061145665 11.5322802576354793, 225.0471948914258746 11.5330002677501433, 225.0328448253008276 11.5337180770388592, 225.0185250472502503 11.5344335803595950, 225.0042336758099850 11.5351468651141396, 224.9899666840143198 11.5358581082705030, 224.9757293128529625 11.5365670953030204, 224.9615188349461619 11.5372739482972069, 224.9473343603625040 11.5379787112565051, 224.9331867190003038 11.5386809398691916, 224.9190651590865002 11.5393810912945298, 224.9049589851297810 11.5400796146967703, 224.8908763596499512 11.5407761760390493, 224.8768203267530055 11.5414706560991558, 224.8627911626619493 11.5421630507644490, 224.8487873231412664 11.5428534304604344, 224.8348025935600845 11.5435420547181717, 224.8208432662335667 11.5442286728690409, 224.8069064464890232 11.5449134088227350, 224.7929952890955576 11.5455961416041060, 224.7790961745725156 11.5462774242215751, 224.7652157298573457 11.5469569934605225, 224.7513584997170994 11.5476346729869785, 224.7375268209609089 11.5483103768236575, 224.7237220902758565 11.5489840576921914, 224.7099413765588451 11.5496558393201507, 224.6961637810842660 11.5503265461539328, 224.6824171483852126 11.5509950911998516, 224.6686890557825791 11.5516619670280303, 224.6549772382042534 11.5523272659267597, 224.6412812909761954 11.5529910072228468, 224.6276091034440014 11.5536528930102058, 224.6139594562444017 11.5543129777216951, 224.6003182497867385 11.5549718025802619, 224.5867005368071148 11.5556288004592993, 224.5731010661897926 11.5562841765020163, 224.5595318451183573 11.5569374888610792, 224.5459817047652678 11.5575891644592392, 224.5324427190808478 11.5582395019210384, 224.5189143401585454 11.5588885230366465, 224.5054022183514348 11.5595360233723632, 224.4919123846912044 11.5601817897050676, 224.4784375362928017 11.5608260941168393, 224.4649757674634429 11.5614690093784702, 224.4515271517113888 11.5621105363332557, 224.4380954082662356 11.5627505474351384, 224.4246791510049945 11.5633890977143405, 224.4112755960894674 11.5640262896338797, 224.3978846737758772 11.5646621293418335, 224.3845066428590371 11.5652966117998126, 224.3711457528081610 11.5659295969039704, 224.3577977362123761 11.5665612362988721, 224.3444652819518979 11.5671914448567392, 224.3311485458364416 11.5678202246759660, 224.3178463670832343 11.5684476215622389, 224.3045557510956485 11.5690737397591157, 224.2912636805598368 11.5696990018557972, 224.2779812886730895 11.5703230455223807, 224.2647169075784745 11.5709456114839018, 224.2514653724545894 11.5715668719389466, 224.2382246445122291 11.5721868961484091, 224.2249954647945458 11.5728056663998640, 224.2117774258872487 11.5734232007998141, 224.1985677641199004 11.5740395866003496, 224.1853739310532205 11.5746546100467338, 224.1721921301376881 11.5752683925316280, 224.1590180429057853 11.5758810639388869, 224.1458517540423827 11.5764926247218565, 224.1326993443378797 11.5771029132381820, 224.1195552562876117 11.5777120902492605, 224.1064199000646795 11.5783201500428081, 224.0932922280796049 11.5789271253297947, 224.0801718772115123 11.5795330298151118, 224.0670575303321073 11.5801378997012510, 224.0539473086348039 11.5807417811433275, 224.0408440714022333 11.5813446074286652, 224.0277532395576827 11.5819462641829940, 224.0146726415871967 11.5825468155495450, 224.0016005777073929 11.5831463107956179, 223.9885357303077740 11.5837447873853687, 223.9754767473355059 11.5843422797862097, 223.9624200726219385 11.5849388562229869, 223.9493664901772263 11.5855344996028062, 223.9363221822949299 11.5861291150974708, 223.9232837412845640 11.5867227707995379, 223.9102514687340602 11.5873154735786841, 223.8972278339578850 11.5879072106865273, 223.8842074228049626 11.5884980596550538, 223.8711897945752867 11.5890880278437507, 223.8581768384312625 11.5896771077476899, 223.8451691054755202 11.5902653131403053, 223.8321650096256690 11.5908526677333583, 223.8191624724303210 11.5914391819364901, 223.8061618009825793 11.5920248568939073, 223.7931629563950935 11.5926096948439774, 223.7801640483892811 11.5931936739012844, 223.7671670080413833 11.5937768052847883, 223.7541730621474301 11.5943591186324095, 223.7411823205456756 11.5949406428960344, 223.7281945822359148 11.5955214095320009, 223.7152092203553195 11.5961014400608100, 223.7022255713057461 11.5966807499123234, 223.6892422590755416 11.5972592901638460, 223.6762589726463375 11.5978370357118550, 223.6632763821548906 11.5984140565170009, 223.6502941596621667 11.5989903554876257, 223.6373122485587146 11.5995659928159345, 223.6243300458003489 11.6001409101511399, 223.6113474183810581 11.6007150945224744, 223.5983643014767210 11.6012885646925437, 223.5853804742069997 11.6018613808046673, 223.5723949789533549 11.6024337740753829, 223.5594084415188831 11.6030053638418362, 223.5464202437137260 11.6035763342931393, 223.5334298265308917 11.6041467476705211, 223.5204368671160182 11.6047166055632065, 223.5074413311786543 11.6052858741749585, 223.4944432982269404 11.6058545207680535, 223.4814424785578808 11.6064225703417829, 223.4684383277624420 11.6069900727134989, 223.4554303426215824 11.6075570640285175, 223.4424179562224992 11.6081235823943505, 223.4294005333658788 11.6086896685846472, 223.4163767564456577 11.6092554251419333, 223.4033493491641593 11.6098205678131965, 223.3903182963034055 11.6103850983903456, 223.3772834961593503 11.6109490258626220, 223.3642450371695531 11.6115123420543505, 223.3512033206650358 11.6120750138235795, 223.3381552833177466 11.6126372901045816, 223.3251009602248871 11.6131991535745271, 223.3120397912730937 11.6137606354857805, 223.2989722102153110 11.6143216904896001, 223.2858985034939394 11.6148822884757621, 223.2728171532854446 11.6154425337153011, 223.2597285678842525 11.6160023859097290, 223.2466317184571665 11.6165619096001080, 223.2335277664750777 11.6171210135613396, 223.2204169764060566 11.6176796739163031, 223.2072988293896003 11.6182379214860685, 223.1941722853886461 11.6187958206725579, 223.1810361052819758 11.6193534462533208, 223.1678913125293775 11.6199107220579343, 223.1547381380204058 11.6204676270292619, 223.1415754377222811 11.6210242292901054, 223.1284015147917614 11.6215806294810413, 223.1152151257173557 11.6221368962474347, 223.1020209030160117 11.6226927309534513, 223.0888180899151791 11.6232481781418482, 223.0756052319352136 11.6238033234601996, 223.0623811454728695 11.6243582333952187, 223.0491451294250567 11.6249129435087859, 223.0358968024123385 11.6254674694606823, 223.0226367869022113 11.6260217673401964, 223.0093615337413837 11.6265760397256201, 222.9960678207886531 11.6271304645915823, 222.9827655838396936 11.6276844535645623, 222.9694554206600969 11.6282379715353876, 222.9561342545889318 11.6287911942133846, 222.9427998983108807 11.6293442423045548, 222.9294510268505860 11.6298971849561319, 222.9160884180237190 11.6304499718576047, 222.9027074603666563 11.6310028546020909, 222.8893176033855070 11.6315552995097704, 222.8759211426466607 11.6321071795064235, 222.8625124070458412 11.6326588071381796, 222.8490832134951631 11.6332106252531116, 222.8356348319168205 11.6337625545451147, 222.8221730868968393 11.6343142716344854, 222.8086998368636387 11.6348656728601103, 222.7952032410212837 11.6354173891396151, 222.7816844858272418 11.6359693461163598, 222.7681514532171434 11.6365211164074118, 222.7546094596882540 11.6370724159062036, 222.7410496054541227 11.6376237118867856, 222.7274689117791979 11.6381751538767517, 222.7138741945800575 11.6387263792080713, 222.7002655263083852 11.6392773809202303, 222.6866375324850083 11.6398284332481357, 222.6729866912278055 11.6403797107276699, 222.6593141329916534 11.6409311470295815, 222.6456207319742191 11.6414826900592843, 222.6319141538511417 11.6420339437191078, 222.6181898888900719 11.6425851340134159, 222.6044497077729432 11.6431361669641227, 222.5906859946142617 11.6436874213258434, 222.5768997746848186 11.6442388379903292, 222.5630916264524330 11.6447903810514166, 222.5492639055913457 11.6453419268984604, 222.5354268513521276 11.6458929635110646, 222.5215672763443990 11.6464441414515729, 222.5076782329805951 11.6469957955622991, 222.4937638625381169 11.6475477129753546, 222.4798292363335577 11.6480996383536564, 222.4658732608358775 11.6486516197716803, 222.4519005455349543 11.6492034280629042, 222.4379138599462351 11.6497549259799520, 222.4239108831788769 11.6503062233066359, 222.4098822394064712 11.6508577672935250, 222.3958278149373484 11.6514095560063904, 222.3817501135741566 11.6519614625957821, 222.3676471868184876 11.6525135736862779, 222.3535187113670872 11.6530658977330432, 222.3393601721838593 11.6536186413909473, 222.3251663416669999 11.6541720424621964, 222.3109466623493802 11.6547256460788748, 222.2967040816853626 11.6552793072878362, 222.2824345096871639 11.6558332118278596, 222.2681376654350913 11.6563873657033454, 222.2537934125687684 11.6569426978119299, 222.2394296278619663 11.6574979009650406, 222.2250456168259518 11.6580530033773524, 222.2106332312147856 11.6586083764684467, 222.1961901634218748 11.6591641190260678, 222.1817259895392738 11.6597197839939692, 222.1672323459247878 11.6602757492814497, 222.1527060469099695 11.6608321525856535, 222.1381498752830623 11.6613888587292625, 222.1235645886087013 11.6619458258008599, 222.1089488152721856 11.6625031085986137, 222.0943054474932126 11.6630605689926643, 222.0796369850670828 11.6636180879316864, 222.0649326370145218 11.6641761438978122, 222.0501916741798993 11.6647347600702833, 222.0354200415984565 11.6652936614623552, 222.0206255050645439 11.6658524948370594, 222.0058055009197915 11.6664113692263243, 221.9909317003409228 11.6669715336889777, 221.9760187813601533 11.6675323245149674, 221.9610674740686136 11.6680936993524185, 221.9460834295307166 11.6686553999321863, 221.9310575638700982 11.6692178166093186, 221.9159984711472191 11.6697805626173459, 221.9009259266190099 11.6703427671973010, 221.8858296896020477 11.6709048744522352, 221.8706995944916969 11.6714673207687980, 221.8555326260529625 11.6720302285323623, 221.8403304885915759 11.6725935149984181, 221.8250972499788816 11.6731569963287445, 221.8098195614857389 11.6737212391253511, 221.7944889260295156 11.6742865963672013, 221.7791202134384889 11.6748524179399720, 221.7637180402759896 11.6754184975323128, 221.7482700456506564 11.6759853535369480, 221.7327669514019988 11.6765533683674345, 221.7172115229157043 11.6771224104400737, 221.7016211571630038 11.6776917309543382, 221.6860028019631557 11.6782610288026678, 221.6703447483006642 11.6788307904666944, 221.6546244431609409 11.6794019527690978, 221.6388611839107909 11.6799736915431538, 221.6230487052664841 11.6805462579741306, 221.6071946734359415 11.6811193203433437, 221.5913075585578724 11.6816925165910810, 221.5753864703945908 11.6822658761608444, 221.5594131535235931 11.6828401465168756, 221.5433904492093404 11.6834151973097651, 221.5273308964320336 11.6839905000560993, 221.5112244756882376 11.6845664577840900, 221.4950649900503663 11.6851433129982265, 221.4788646116662392 11.6857205548694267, 221.4626020103556243 11.6862990436987797, 221.4462705120650412 11.6868790352438818, 221.4298859924452358 11.6874598673816550, 221.4134506856235589 11.6880414365643013, 221.3969754781638244 11.6886232905533145, 221.3804605137588624 11.6892054142854072, 221.3638996850392004 11.6897880441166144, 221.3472772159433077 11.6903718019564451, 221.3305813530340060 11.6909571427546126, 221.3137711140899171 11.6915456840291085, 221.2969116219964576 11.6921348014786908, 221.2800176036296591 11.6927238980806685, 221.2630934336358735 11.6933127927655107, 221.2461192125695106 11.6939022661089460, 221.2290863538799215 11.6944926448517084, 221.2119945040124946 11.6950839284617025, 221.1948675705596088 11.6956751636199208, 221.1776935519548317 11.6962668126592835, 221.1604303534516021 11.6968605094735594, 221.1430823375206387 11.6974560610127813, 221.1256729793850582 11.6980525325160976, 221.1082343240083787 11.6986486654978012, 221.0907777951847493 11.6992440115996175, 221.0732731529912485 11.6998397355013690, 221.0556760649141665 11.7004375334995672, 221.0379809653518350 11.7010375956696304, 221.0201910780059507 11.7016397730786199, 221.0023326505253465 11.7022430375102857, 220.9844141227268608 11.7028470498724388, 220.9664267865855720 11.7034521267921079, 220.9483618371744740 11.7040585853336694, 220.9302181846820758 11.7046664471111157, 220.9120117963108214 11.7052750889676176, 220.8937461626256891 11.7058843638523342, 220.8754296372314911 11.7064939432009609, 220.8570353831405555 11.7071048211223516, 220.8385387414597858 11.7077179002593432, 220.8199419597752637 11.7083330701279849, 220.8012542966679348 11.7089499601218403, 220.7824976140127831 11.7095677351779131, 220.7636932618535184 11.7101855873401206, 220.7448115762650502 11.7108046009619358, 220.7258449069578603 11.7114250382169285, 220.7067902066015961 11.7120469892335475, 220.6876435492174267 11.7126705751821731, 220.6684018412082366 11.7132958852971552, 220.6490775002803275 11.7139224419373367, 220.6296751617489633 11.7145500551851551, 220.6101884901056565 11.7151789348703232, 220.5906226553498186 11.7158088720647999, 220.5709709286423674 11.7164400892134566, 220.5512576667551343 11.7170716871887315, 220.5314614383965477 11.7177044199639759, 220.5115590022702179 11.7183390981858260, 220.4915452243133416 11.7189758769758754, 220.4714307799503956 11.7196143463432563, 220.4512468588942227 11.7202533715875568, 220.4309992066258417 11.7208927312753612, 220.4106498399647478 11.7215337511401767, 220.3901880983321462 11.7221767796176426, 220.3696269742781340 11.7228213298248747, 220.3489604038603034 11.7234675876106191, 220.3281690552258851 11.7241162000989156, 220.3072756756530168 11.7247663403946412, 220.2862824116060096 11.7254179062737975, 220.2651764715906495 11.7260713139721826, 220.2439627765920136 11.7267263625539524, 220.2226597862533310 11.7273823863618976, 220.2012604090785430 11.7280396049063711, 220.1797602369004778 11.7286981429156398, 220.1581417345546754 11.7293585718312805, 220.1364090861307830 11.7300207161664964, 220.1145235049651490 11.7306858616886558, 220.0924773395388172 11.7313542241099480, 220.0703026463932019 11.7320246749542285, 220.0480152578880393 11.7326966446598462, 220.0256193313577455 11.7333699618235077, 220.0031393234814630 11.7340437772018173, 219.9805459909598255 11.7347190432236310, 219.9578262375325153 11.7353961632678505, 219.9350228461188124 11.7360736819773805, 219.9120955538539874 11.7367529071657000, 219.8890352094786351 11.7374341046477060, 219.8658230573198296 11.7381178519777958, 219.8424378550896279 11.7388048003128507, 219.8189420393968305 11.7394928593222510, 219.7954051231405685 11.7401797339257250, 219.7717126788438691 11.7408691262540561, 219.7478364883711208 11.7415619025218767, 219.7238247217937896 11.7422564542140329, 219.6876080273496825 11.7432997520321258, 219.6987523783389520 11.7853029348368334, 219.7061791771076571 11.8133127052677036, 219.7135986549972699 11.8413287509590859, 219.7210947404915657 11.8693483800538964, 219.7285881728043080 11.8973741241818960, 219.7359476924964099 11.9254261184938049, 219.7433492070179000 11.9534995743634820, 219.7507477436130330 11.9815790420429416, 219.7579850993606385 12.0096695496598649, 219.7652250046039342 12.0377658721523702, 219.7725553247667563 12.0658652068576604, 219.7800022085925491 12.0939667193907923, 219.7873408946113614 12.1220775512220698, 219.7950743482863629 12.1501817176844593, 219.8021390085507676 12.1783129843265812, 219.8093731982575889 12.2064422366637455, 219.8167053719220974 12.2345716176982222, 219.8241449129861564 12.2627034586466905, 219.8313191008305978 12.2908495551467496, 219.8387108569568795 12.3189946085297830, 219.8460894153990637 12.3471459191799120, 219.8532640728367369 12.3753095044633206, 219.8601696000659160 12.4034874078654624, 219.8674454815513286 12.4316594207246638, 219.8745707848169104 12.4598419912782550, 219.8816850376582863 12.4880175631535977, 219.8889121191596416 12.5161815295508241, 219.8961929097609413 12.5443496532764467, 219.9035207113772401 12.5725221394411832, 219.9108000506688256 12.6007019866288559, 219.9180033535190262 12.6288900488843367, 219.9252926239190629 12.6570812287821681, 219.9325837932304353 12.6852781632398539, 219.9416672227909828 12.7134247386159451, 219.9543961131030585 12.7414629674117528, 219.9609663350123014 12.7696974747126717, 219.9637127246121509 12.7980546220564388, 219.9693396487065513 12.8263272760372846, 219.9763389821717681 12.8545627692792479, 219.9873479022917309 12.8826789124793937, 219.9942663404656287 12.9109285111587422, 220.0001191112024514 12.9392170379039477, 220.0060791742523350 12.9675078900646081, 220.0125259484729838 12.9957892679278348, 220.0204798710784360 13.0240294903622651, 220.0303293171268706 13.0522308974955514, 220.0363637765321414 13.0805716601223949, 220.0435221787505213 13.1088831469933211, 220.0503444749545849 13.1372106970433347, 220.0554559747872645 13.1655969105213533, 220.0637152732548998 13.1938911366292153, 220.0719544408212869 13.2221916261448413, 220.0809450265347778 13.2504744743735987, 220.0855198223371190 13.2788996753560333, 220.0951748739387028 13.3071731968698579, 220.1002723971644173 13.3355840090515105, 220.1073650537146023 13.3639288229455051, 220.1144815968071384 13.3922785026534434, 220.1215875630216487 13.4206341039521906, 220.1287352849992942 13.4489940064017972, 220.1370402481172732 13.4773238028523270, 220.1447839374467890 13.5056765105854204, 220.1521111762056648 13.5340476372248997, 220.1594759156825489 13.5624231739958461, 220.1672083186715554 13.5907929548752975, 220.1735074973374822 13.6191997960329587, 220.1797183184499715 13.6476015913110622, 220.1873653705166589 13.6759648322871517, 220.1929970825444229 13.7043955203467398, 220.2002836983144221 13.7327809785908617, 220.2072371138302174 13.7611822224267684, 220.2143098341883558 13.7895853682338103, 220.2215409219504920 13.8179892239169551, 220.2286146031840701 13.8464034432460039, 220.2359969003394440 13.8748137749151255, 220.2429905149833758 13.9032506382508085, 220.2501006645853749 13.9316990780717074, 220.2572072441929834 13.9601531121284097, 220.2642324537942500 13.9886151020148333, 220.2713546035055572 14.0170796066238523, 220.2784888319845038 14.0455492059331029, 220.2854618050496072 14.0740291669810969, 220.2923997657557038 14.1025156370404829, 220.2996432291302824 14.1309982530505547, 220.3069647405167757 14.1594839348555368, 220.3142063440979825 14.1879636489215741, 220.3212788520830827 14.2164393478506881, 220.3285570377223621 14.2449142699710301, 220.3357705561347473 14.2733966115232889, 220.3430038924011285 14.3018838045941319, 220.3501936701142938 14.3303777597299629, 220.3574521201990422 14.3588750717818545, 220.3646056912263020 14.3873809842522782, 220.3714125051088502 14.4159027848002559, 220.3785545334652625 14.4444198672097279, 220.3856337208090963 14.4729600249569028, 220.3927611381831184 14.5015207378316209, 220.4001050938870776 14.5300802442172738, 220.4070157686177538 14.5586581175413485, 220.4141741436548045 14.5872338305843900, 220.4213520876047312 14.6158142502689010, 220.4283400949778695 14.6444056730379835, 220.4351961122930561 14.6730063439768230, 220.4419879942652756 14.7016142084780572, 220.4491297933535918 14.7302168131950566, 220.4562863983109935 14.7588242341025122, 220.4632064466015891 14.7874440138399041, 220.4702124060514450 14.8160664519636125, 220.4773075838372733 14.8446914419828317, 220.4839436390709864 14.8733354361903700, 220.4909400907793326 14.9019738275908438, 220.4976830004601425 14.9306250294145322, 220.5046871352374751 14.9592735967586723, 220.5120298154663772 14.9879172096237916, 220.5191431523294341 15.0165728862980128, 220.5262490349775248 15.0452192623841103, 220.5332207143513585 15.0738593394066136, 220.5401179897107227 15.1025068650382295, 220.5471624571489713 15.1311552001949128, 220.5542495225764128 15.1598074722681364, 220.5611462416796371 15.1884706317373812, 220.5679511429215438 15.2171417192930516, 220.5747134507969065 15.2458192563325561, 220.5815516687183049 15.2744996978238134, 220.5883461733833144 15.3031866066804731, 220.5952718645040704 15.3318669234705656, 220.6021707515394894 15.3605449417647435, 220.6091175733615160 15.3892267262936802, 220.6161856756119732 15.4179100903335549, 220.6230988135851874 15.4466032398149764, 220.6301581993917296 15.4752972168452896, 220.6372147494944045 15.5039964430272246, 220.6444441175555085 15.5326957057448869, 220.6513662353943062 15.5614092262724633, 220.6584249249493439 15.5901238422739503, 220.6656150400222600 15.6188559151085027, 220.6725666951840594 15.6476172352274006, 220.6794748558619688 15.6763848779239581, 220.6865817604997630 15.7051516701513947, 220.6936357220202467 15.7339250506465902, 220.7007661076806073 15.7627011863723077, 220.7078723698910778 15.7914830407443674, 220.7148087278339403 15.8202749134539626, 220.7215739629969278 15.8490768265738229, 220.7283696407323532 15.8778828202649382, 220.7350802981979427 15.9066906071818064, 220.7416702149522507 15.9355009310670663, 220.7481918200226971 15.9643182516010249, 220.7548889450735601 15.9931353702346524, 220.7613380771931304 16.0219647648577599, 220.7677626895558092 16.0507998368716578, 220.7746364759300377 16.0796266327909585, 220.7812760232247626 16.1084652724760176, 220.7879783037277264 16.1373070028008776, 220.7945420930387002 16.1661577373793826, 220.8003749786528260 16.1950206147845002, 220.8065617769120479 16.2238629586943617, 220.8128621961369333 16.2527069132252286, 220.8191817781748512 16.2815552456965094, 220.8255725901924507 16.3104064262141080, 220.8322066930488177 16.3392554116777653, 220.8387268829000334 16.3681126612887446, 220.8455734888675579 16.3969652844466474, 220.8521103354397894 16.4258318847736895, 220.8587076063147094 16.4547016260165471, 220.8645847859068567 16.4836114740111590, 220.8712379210808763 16.5125184940503225, 220.8780366528559398 16.5414260978017715, 220.8844439639942436 16.5703499436321806, 220.8910779637470796 16.5992719915153337, 220.8980535530162683 16.6281888886635407, 220.9049801590114726 16.6571120173582976, 220.9120543709435367 16.6860356422276155, 220.9194018674333790 16.7149560939354274, 220.9275853956411879 16.7438569742157100, 220.9337514391982040 16.7728073785344201, 220.9389458499302066 16.8017760252213257, 220.9442633217356047 16.8307458476351215, 220.9495797696569923 16.8597204501495881, 220.9576980259738264 16.8886184325720521, 220.9646433111029467 16.9175552950014456, 220.9706915454232785 16.9465229738655516, 220.9797360847118455 16.9754084990557104, 220.9858503429987877 17.0043838123896194, 220.9958092372052647 17.0332524233293618, 221.0051547332684834 17.0621516662596875, 221.0123955258806348 17.0911251847201449, 221.0184945331998847 17.1201365065583673, 221.0265358812493162 17.1490962373539766, 221.0342592249747895 17.1780698850797791, 221.0416971724159225 17.2070564925110219, 221.0492649287550080 17.2360440209217529, 221.0574163920278750 17.2650193215307297, 221.0642376484496765 17.2940378146577451, 221.0712507672822369 17.3230554066909477, 221.0750035058534024 17.3521530123523817, 221.0833825984780106 17.3811014281199263, 221.1012000639442761 17.4097816163964509, 221.1234697960219933 17.4383372244083148, 221.1446009049126360 17.4669299947537660, 221.1659814111733908 17.4955196829968251, 221.1862074950514341 17.5241471728012712, 221.1957570593854427 17.5530905108681665, 221.2038686914070240 17.5820804815569822, 221.2080601838380858 17.6111893256108196, 221.1988433214207248 17.6407165963389048, 221.1916363249929702 17.6702144711225309, 221.1877485885951558 17.6996199313913323, 221.1891656915406088 17.7288761977612168, 221.1968354291195453 17.7579563475948667, 221.2025406650257082 17.7870977090662272, 221.2096147692232648 17.8162040254308245, 221.2165160141038598 17.8453198054343645, 221.2224942246927526 17.8744666959394074, 221.2277119717738856 17.9036399876857466, 221.2332821021322786 17.9327909628593183, 221.2383170204656722 17.9619443245157591, 221.2442905425824904 17.9910751117225907, 221.2498363549150326 18.0202227059452689, 221.2557305326318726 18.0493647450938610, 221.2621416428434600 18.0784963864217474, 221.2691430202075935 18.1076155305098041, 221.2754988088338450 18.1367577199723335, 221.2813337865354413 18.1659193359810658, 221.2877855764635342 18.1950676780735812, 221.2953253951094723 18.2241907181451985, 221.3013599376515970 18.2533629946779001, 221.3064374132812020 18.2825671410777524, 221.3124537528991596 18.3117487398260970, 221.3182281059690695 18.3409416697505776, 221.3250634187268986 18.3701085799299371, 221.3330656593484491 18.3992464482553046, 221.3374356805543641 18.4284927546433472, 221.3395300092193736 18.4578084756215759, 221.3458224370075129 18.4870083936977103, 221.3522630302541927 18.5162084245159981, 221.3577068639017398 18.5454412770415153, 221.3641904024743212 18.5746487549762911, 221.3715279110405447 18.6038361783344079, 221.3767990322102150 18.6330869316894123, 221.3800267733186331 18.6624002609262085, 221.3827362009375577 18.6917325593055210, 221.3870286297943437 18.7210239623286085, 221.3954345644621355 18.7502025136998931, 221.3995412872705231 18.7795077426605879, 221.4052686287405720 18.8087667836010581, 221.4116141403480924 18.8380079579074753, 221.4182075521312925 18.8672463620802873, 221.4234075461477289 18.8965286224821760, 221.4297424895057134 18.9257828881485999, 221.4381330032734922 18.9549830454996382, 221.4437786009013962 18.9842653900625713, 221.4516916820943777 19.0134876143406935, 221.4581724332157364 19.0427547246203943, 221.4643258332748417 19.0720353411072203, 221.4703040021612708 19.1013190923657241, 221.4757366350390271 19.1306161365466068, 221.4827138450010011 19.1598736469915139, 221.4886341154185061 19.1891653110444977, 221.4939175149503114 19.2184791927305980, 221.4996824220591805 19.2477836349604914, 221.5040993844800425 19.2771303361761817, 221.5096515242152009 19.3064491173592501, 221.5157897916339209 19.3357555188309291, 221.5254028688229937 19.3649680592404678, 221.5379303707704821 19.3941024988662392, 221.5502966622345014 19.4232455911104083, 221.5569858007410176 19.4525532673038555, 221.5662602299367734 19.4817920507718547, 221.5778712907634826 19.5109689308560554, 221.5906471454106281 19.5401169399273584, 221.6024846423248960 19.5692955531484998, 221.6125339520685600 19.5985288924894832, 221.6228556388711013 19.6277586119359704, 221.6323660623660317 19.6570154157516725, 221.6415036192033199 19.6862868958747796, 221.6440994493523249 19.7157478621153430, 221.6431790139832003 19.7453121777085947, 221.6474316280026073 19.7747340490760877, 221.6570225243102072 19.8040091392888229, 221.6647075506523663 19.8333421334356821, 221.6736770572801163 19.8626428791509682, 221.6816534356838986 19.8919757277428566, 221.6864937928417305 19.9214011980677981, 221.6879797046681517 19.9509252781368964, 221.6950232771162632 19.9803103316330919, 221.7007288044115398 20.0097516795447063, 221.7040268217931782 20.0392648175583936, 221.7074732176745613 20.0687776379662814, 221.7106187015569674 20.0983027922388793, 221.7176740678478097 20.1277217372505213, 221.7230474804684377 20.1571919249014684, 221.7277670534129754 20.1866843939325022, 221.7319372791985188 20.2161961796125986, 221.7405646670954411 20.2455863929184758, 221.7463882443915111 20.2750552242748441, 221.7538847956957397 20.3044764361599235, 221.7622793454201258 20.3338762065354963, 221.7701565144907363 20.3632943760536058, 221.7734189145131722 20.3928463603017818, 221.7781702146661189 20.4223602165639591, 221.7857704917922774 20.4517976945902156, 221.7905756422969432 20.4813176641481363, 221.7934115371495238 20.5108968160978833, 221.7963450988041245 20.5404769506598512, 221.8001359602207003 20.5700367282714680, 221.8054088753309259 20.5995586337327090, 221.8103228715708326 20.6290943850318556, 221.8166331239539772 20.6585946948034866, 221.8221241242079316 20.6881217627244531, 221.8259241657792984 20.7177000296168892, 221.8288535880878953 20.7473064170266852, 221.8317732952318693 20.7769167504911394, 221.8434864831883147 20.8062842966481227, 221.8548980732345797 20.8356638512113008, 221.8497146823973480 20.8655018099665917, 221.8425379707036313 20.8953868196195387, 221.8373773923880208 20.9252182013958574, 221.8382192559556358 20.9548855527560143, 221.8489009231280136 20.9842827888029326, 221.8672566919480857 21.0134697678678819, 221.8797273718959673 21.0428242378765376, 221.8887999809484199 21.0722772506783684, 221.8917645081734804 21.1019045712286442, 221.8997328109514058 21.1313958606348358, 221.8990926617780701 21.1611280411997136, 221.9019993443866952 21.1907616767497267, 221.9051040779034452 21.2203933634021773, 221.9093557913154768 21.2499967315714180, 221.9134297178703150 21.2796086472793569, 221.9116007488572677 21.3093879024833477, 221.9032882877631323 21.3393495526403925, 221.9060520607276032 21.3690080228472183, 221.9051334272646727 21.3987714957427535, 221.9034009241673573 21.4285605666680112, 221.9100285267250285 21.4581261494620072, 221.9160069827354107 21.4877163658233172, 221.9238932399250928 21.5172577423831370, 221.9293998902476801 21.5468681210289184, 221.9330707636324576 21.5765324978456796, 221.9363254486435721 21.6062118074986067, 221.9410037369507052 21.6358555652424478, 221.9455408147520643 21.6655067258760141, 221.9489016120562894 21.6951936278900916, 221.9527587732168001 21.7248704151448102, 221.9568600872159436 21.7545531876169207, 221.9622411699986344 21.7842141223478478, 221.9689664639684850 21.8138417552296708, 221.9756209612638997 21.8434747838713079, 221.9818735094456201 21.8731222678023371, 221.9874059330416856 21.9027929106306409, 221.9923440430283677 21.9324832584219251, 221.9971277815838278 21.9621812612543970, 222.0022569686708778 21.9918732336838509, 222.0073470417372619 22.0215696932603784, 222.0125447731021211 22.0512545135887414, 222.0181706962674753 22.0809182669923452, 222.0238933057023587 22.1105828125246830, 222.0295305341986136 22.1402531169874308, 222.0351237485043043 22.1699280426223453, 222.0404257554776848 22.1996143289707462, 222.0459155990378690 22.2292988830823042, 222.0512924341725807 22.2589899134932558, 222.0566673648636140 22.2886843763580522, 222.0618862307806296 22.3183864695259970, 222.0670553473142945 22.3480957600301977, 222.0723717418445631 22.3778070086866983, 222.0777839749534337 22.4075189965145825, 222.0831798395055046 22.4372347714922391, 222.0886434003691363 22.4669520385449424, 222.0940816859240101 22.4966733209650762, 222.0994527851256350 22.5263997499335709, 222.1047812730600697 22.5561306497441905, 222.1101155305965165 22.5858646932945106, 222.1154152126226791 22.6156029722921659, 222.1204420128612753 22.6453400487604668, 222.1255646965227015 22.6750652360078462, 222.1305329997703950 22.7047979141010181, 222.1355847788389895 22.7345316113037761, 222.1406216272999643 22.7642689947007959, 222.1456386712924882 22.7940101866968448, 222.1506385133021979 22.8237551068888926, 222.1555893547568417 22.8535046095124343, 222.1605043395214523 22.8832583261723137, 222.1653877637397443 22.9130161311541407, 222.1701197628978548 22.9427889794096878, 222.1746776288089222 22.9725778902955824, 222.1789441577180355 23.0023778465027746, 222.1836557253604099 23.0321689615527880, 222.1902440399031207 23.0619126298867876, 222.1954526487997725 23.0916966955946314, 222.2010831637907131 23.1214725487913597, 222.2083216385476589 23.1512082125607392, 222.2139515806716474 23.1809904051321993, 222.2171221061061317 23.2108420164642872, 222.2209885174087844 23.2406820492069563, 222.2264371356683625 23.2704868990151006, 222.2313264838332714 23.3003099105249767, 222.2360295056382427 23.3301410281423145, 222.2416143590607192 23.3599515096318804, 222.2470280979947290 23.3897696784447184, 222.2519457695757410 23.4196042624413181, 222.2572284978857340 23.4494320947136323, 222.2625351292995788 23.4792623413270860, 222.2678234451631738 23.5090961314884019, 222.2731187339419421 23.5389287177683109, 222.2783913238666287 23.5687606664830014, 222.2836896458870797 23.5985949596657747, 222.2889783775575268 23.6284325360171366, 222.2942692542079612 23.6582730743537084, 222.2995474628685599 23.6881169630518968, 222.3048186546705551 23.7179640409425119, 222.3100880876824306 23.7478141608984963, 222.3153559271631536 23.7776673080602770, 222.3206150332677282 23.8075236679407141, 222.3258698867078920 23.8373906039141410, 222.3311162164115444 23.8672686259859255, 222.3363674375739265 23.8971494474723585, 222.3416002241224021 23.9270336834210156, 222.3468409732332987 23.9569206201362306, 222.3520781788036231 23.9868105568549552, 222.3572950909472468 24.0167039334002865, 222.3625011870945229 24.0466004897417882, 222.3677192511808869 24.0764996046101700, 222.3729424320810324 24.1064014557794373, 222.3781468772039318 24.1362901049415939, 222.3833649202102833 24.1661637832156764, 222.3885678890742952 24.1960407689280856, 222.3937637688128461 24.2259208373355825, 222.3989420319749399 24.2558042638988809, 222.4041440839009169 24.2856899312707348, 222.4093321917982280 24.3155788397004464, 222.4144990636801822 24.3454711775703885, 222.4196730904844230 24.3753661753766302, 222.4248346882471878 24.4052643502490199, 222.4300062063282155 24.4351764711447856, 222.4351870688240922 24.4651031622580106, 222.4403525021423320 24.4950330549834590, 222.4455026492308889 24.5249661349346759, 222.4506599244951701 24.5549017980429021, 222.4558229849940574 24.5848400708727297, 222.4609842278840119 24.6147811469395741, 222.4661284181739802 24.6447254265929168, 222.4713101841024070 24.6746714424243159, 222.4764591915086385 24.7046210642576050, 222.4815193388476189 24.7345653488426223, 222.4865942845941618 24.7645009503866795, 222.4916659846251434 24.7944393662822975, 222.4967339979297662 24.8243805977292276, 222.5017992759311483 24.8543246133276234, 222.5068766617617939 24.8842710087474046, 222.5120706243436643 24.9142169965140106, 222.5176992594639671 24.9441541159433555, 222.5230551169869386 24.9741011722104318, 222.5290723867995268 25.0040333259883418, 222.5331869880003524 25.0340250878377617, 222.5376183126892897 25.0640178060554746, 222.5426224342733974 25.0939979418418204, 222.5478384862114467 25.1239750740119945, 222.5527734021785307 25.1539622861092163, 222.5574433522948254 25.1839591350383962, 222.5625189750877837 25.2139478160047545, 222.5680865706248426 25.2439260392117397, 222.5750931585504020 25.2738686682664557, 222.5818713705985488 25.3038199265285257, 222.5873131976027821 25.3338052354567935, 222.5917661569435779 25.3638151370287233, 222.5953573558004734 25.3938504356210331, 222.5981423237900287 25.4239096058506853, 222.6021066629948564 25.4539400323830769, 222.6070875480717746 25.4839460669764506, 222.6120740675006573 25.5139544754087133, 222.6170732825968344 25.5439650650433165, 222.6222362523172649 25.5739738307424211, 222.6271684386658478 25.6039912012795128, 222.6335610292155991 25.6339683652968340, 222.6407584509890683 25.6639224327095832, 222.6425063815139254 25.6940230383629142, 222.6465820115975021 25.7240645599181050, 222.6516161452992719 25.7540832404702051, 222.6567612331085684 25.7841014577184247, 222.6622771706098831 25.8141123513533195, 222.6675096863649514 25.8441331729572639, 222.6724462652574914 25.8741642350099852, 222.6771134454449168 25.9042048236113409, 222.6827850675147431 25.9342363969213565, 222.6931165989195733 25.9641633520688302, 222.6998107998099670 25.9941885113330464, 222.6993812296911130 26.0244039700988594, 222.7004828501916052 26.0545812839361091, 222.7068412638190296 26.0846224342528892, 222.7151250249200416 26.1146151271599081, 222.7223428546290904 26.1446381900456508, 222.7233614602698140 26.1748271206302583, 222.7251698748148669 26.2049974649882707, 222.7297580672671131 26.2350818941298165, 222.7350401377404410 26.2651345787466823, 222.7397478570216833 26.2952047135842442, 222.7441890163832454 26.3252841709139567, 222.7490415028251221 26.3553551043594361, 222.7538245648224802 26.3854301586803679, 222.7585301990882272 26.4155095328669063, 222.7633657664941893 26.4455877700282933, 222.7688255310274030 26.4756518790048681, 222.7734841245476503 26.5057393017970604, 222.7804994013528130 26.5357699997405341, 222.7892222416466268 26.5657611258812238, 222.7934201840647859 26.5958734025947443, 222.7976525280050168 26.6259869814919448, 222.8061529184382721 26.6559906322740723, 222.8082111146292732 26.6861657600329671, 222.8108775599187936 26.7163270320726909, 222.8149933055637462 26.7464524254358622, 222.8202949001197624 26.7765488881515772, 222.8301151846285961 26.8065289628167100, 222.8347576222037389 26.8366503143328003, 222.8375201822001657 26.8668265546497302, 222.8418110343539524 26.8969648288883043, 222.8465067625999154 26.9270946183010764, 222.8524537725534174 26.9571937291571579, 222.8574636362567389 26.9873195347062840, 222.8620005207471593 27.0174598523127933, 222.8671731236977394 27.0475856079521435, 222.8726715768208635 27.0777049164434551, 222.8775474503010514 27.1078426359606048, 222.8816119755437342 27.1380004347832653, 222.8869882262066255 27.1681224765070439, 222.8926632525168543 27.1982387555012863, 222.8956791014972794 27.2284267497900778, 222.8990635443943518 27.2586071020171801, 222.9037992898300047 27.2887541107547200, 222.9093687181026837 27.3188813347096549, 222.9147563759125603 27.3490153396272326, 222.9196081766385760 27.3791653776246378, 222.9243436031846386 27.4093204644486832, 222.9286080088612607 27.4394937878626308, 222.9336119064245736 27.4696539013534995, 222.9389694547906515 27.4998067414168901, 222.9467971585153805 27.5298969245293961, 222.9536775696234372 27.5600138138078385, 222.9590786061853294 27.5901713708527616, 222.9649273858108245 27.6203191385951321, 222.9707788876386587 27.6504687617074580, 222.9779598201788247 27.6805854587204365, 222.9832825767054203 27.7107527614695996, 222.9817568406602675 27.7410883808292539, 222.9874565001115059 27.7712230016942172, 222.9936425870779999 27.8013468434625715, 222.9960558499033709 27.8315712512636928, 223.0003219092063773 27.8617491055424331, 223.0057706188730720 27.8918979783894940, 223.0108205033266415 27.9220591651418637, 223.0159954833870017 27.9522189808752479, 223.0194101868348184 27.9824265788449296, 223.0236278179963563 28.0126150871228674, 223.0270783276969269 28.0428260124708899, 223.0284527756701323 28.0730933626796890, 223.0310594807002644 28.1033303987770076, 223.0333322930906093 28.1335778457469274, 223.0341180624730271 28.1638655435968630, 223.0377939193730583 28.1940800787361177, 223.0423453188266194 28.2242737368840046, 223.0473563566860946 28.2544573009189754, 223.0475810350745860 28.2847663252405717, 223.0468242129842622 28.3151021837166361, 223.0494697180611183 28.3453669498326128, 223.0551226685691404 28.3755718417024134, 223.0596599616459343 28.4058071837450221, 223.0644130602052826 28.4360386740751281, 223.0699211842025136 28.4662524123567700, 223.0775607745896423 28.4964128803653232, 223.0834267667081861 28.5266207293508955, 223.0946602925923798 28.5566915950314275, 223.1011121708191922 28.5868875504529214, 223.1057514664018413 28.6171320328370271, 223.1092717803553853 28.6474026359030276, 223.1131858521137303 28.6776599785361910, 223.1175135978419064 28.7079082719773027, 223.1224011054472101 28.7381437355217422, 223.1295408824392155 28.7683226027757506, 223.1386439433996998 28.7984522355943042, 223.1466096978199687 28.8286128295864472, 223.1512039324809678 28.8588623697965829, 223.1491767764530607 28.8892849121632587, 223.1495096696992562 28.9196477562618064, 223.1531510946221886 28.9499227439960336, 223.1593084067002621 28.9801302235188949, 223.1671463731102847 29.0102958476457857, 223.1733378307823159 29.0405055589104215, 223.1762893691852980 29.0708005572501271, 223.1797411591134335 29.1010841479316511, 223.1842105395194835 29.1313429880286776, 223.1897492654354380 29.1615757529583242, 223.1968336860509794 29.1917701214418592, 223.2007111469362144 29.2220488212398450, 223.2065521127401837 29.2522700368052213, 223.2119706505079080 29.2824949298786201, 223.2143181739425302 29.3128005757714796, 223.2145049372286962 29.3431632754442226, 223.2130727083830095 29.3735688214336932, 223.2169012501166776 29.4038404960356345, 223.2205048495359563 29.4341193922145052, 223.2231762087349409 29.4644236196138216, 223.2286000314355476 29.4946587355595966, 223.2310513877523022 29.5249714295019459, 223.2344723717550607 29.5552689830145177, 223.2401364427293800 29.5855193241913597, 223.2452585570293593 29.6157849349486888, 223.2505202413127279 29.6460483699050599, 223.2559231593407674 29.6763095798611687, 223.2644027871297965 29.7064934052473255, 223.2627241956122077 29.7369385494184684, 223.2645402238002248 29.7672955192699540, 223.2677335536205305 29.7976186173829838, 223.2703656238828671 29.8279573494095835, 223.2756273228060309 29.8582220782173380, 223.2844765439608352 29.8883879235266221, 223.2937085860519630 29.9185452808112444, 223.2973081015859407 29.9488478138921508, 223.2936631005122763 29.9793362624144706, 223.2960666519568633 30.0096716675765087, 223.3009400212339415 30.0399455321323643, 223.3025870375581121 30.0703026551048396, 223.3057019420378992 30.1006237111998942, 223.3089129363874861 30.1309435671736701, 223.3150049756058309 30.1612022619658475, 223.3234217234095809 30.1914144151501098, 223.3234210095013736 30.2218413027543100, 223.3217310036584706 30.2523119774457854, 223.3241338861918166 30.2826801518044384, 223.3291361017755321 30.3129838018023321, 223.3335691814783672 30.3433030311558909, 223.3376879267651702 30.3736313904119228, 223.3415822010329066 30.4039665939800763, 223.3428527313765812 30.4343692093521447, 223.3463046578129365 30.4647139764648003, 223.3516152151530321 30.4950088856224291, 223.3563567921461299 30.5253193045073523, 223.3591806847876740 30.5556792232234464, 223.3633551843414011 30.5860062097936520, 223.3673017153327294 30.6163400617655554, 223.3700134643178785 30.6467061128776557, 223.3771472685353956 30.6769619187441549, 223.3826102810548377 30.7072608972207064, 223.3886354466804676 30.7375468061555068, 223.3920631849616996 30.7678988088326477, 223.3948340483643449 30.7982679488339173, 223.3964740350932345 30.8286665606508272, 223.3988015834056000 30.8590488764019213, 223.4054640310108368 30.8893233212693943, 223.4110113026400199 30.9196268339411588, 223.4122686163350409 30.9500391595034401, 223.4185862540497851 30.9803254154592445, 223.4253672463790679 31.0106010423021878, 223.4280655144321486 31.0409802450029346, 223.4338793837801518 31.0712782786587987, 223.4368728739135861 31.1016439800152682, 223.4352648020607148 31.1321259385783939, 223.4366125414744033 31.1625346167303299, 223.4396705389495708 31.1929014229470027, 223.4456438373769345 31.2231963323206827, 223.4505941710413879 31.2535177730133178, 223.4547715708542057 31.2838594813272053, 223.4577739516643362 31.3142314600314897, 223.4600217044558974 31.3446231543025569, 223.4635365292612903 31.3749880885911949, 223.4679250725203588 31.4053363295574073, 223.4717664817196408 31.4356991046183545, 223.4748831801738049 31.4660808083446888, 223.4799487654960330 31.4964148776198982, 223.4840292327997133 31.5267743476906972, 223.4865411911889623 31.5571736952518300, 223.4883032670847456 31.5875924901525806, 223.4923952324174650 31.6179542209800530, 223.4970672525005568 31.6483023930064604, 223.5030692210884524 31.6786209217952361, 223.5066616283447729 31.7090028002721205, 223.5106210414199381 31.7393763677076528, 223.5132764002270278 31.7697830875398139, 223.5179240399021978 31.8001411575539024, 223.5195254158730336 31.8305755441254412, 223.5239434375728536 31.8609408592237848, 223.5282886785425660 31.8913087443299545, 223.5322519417814817 31.9216868481073490, 223.5347617094650161 31.9521016880502948, 223.5380353071365676 31.9824836883298858, 223.5428282744416038 32.0128133802927906, 223.5480508269973257 32.0431332223139407, 223.5497441169928550 32.0735409979197428, 223.5553057805198591 32.1038539700979157, 223.5598384268915879 32.1341930833302882, 223.5624288052136706 32.1645807931653849, 223.5652337763135336 32.1949638621966159, 223.5678286491805409 32.2253527383586302, 223.5695560421614800 32.2557635381356320, 223.5752088570122851 32.2860971657264244, 223.5778937031911369 32.3165239135804541, 223.5812675754776251 32.3469343759028192, 223.5848566390171470 32.3773401797631806, 223.5891675861419685 32.4077288949641087, 223.5927666200163060 32.4381356809368810, 223.5971664748506100 32.4685234267514531, 223.6018897195696979 32.4989038349818813, 223.6036667979318793 32.5293570671523398, 223.6064949113190323 32.5597850851598665, 223.6116324578511296 32.5901446221567141, 223.6140456300912831 32.6205582901841993, 223.6180710912757377 32.6509330397430162, 223.6211992807537570 32.6813302884016323, 223.6282270303815096 32.7116327515463041, 223.6317729060839383 32.7420209117890479, 223.6357729384005211 32.7723985010423533, 223.6368325295955231 32.8028483885533575, 223.6411096372302154 32.8332202357844309, 223.6439910882512550 32.8636266157740948, 223.6481310196402319 32.8940028180075927, 223.6509936165835200 32.9244106062468376, 223.6553899144587376 32.9547815457483892, 223.6596968044630103 32.9851551443478925, 223.6612145716325131 33.0155969876130797, 223.6650693764509015 33.0459824802825963, 223.6692659410257420 33.0763601295090908, 223.6716695759030529 33.1067817006912222, 223.6751523009949381 33.1371775152148800, 223.6790842135375783 33.1675628699203884, 223.6817299555439718 33.1979800537635299, 223.6840029478613872 33.2284069153912540, 223.6869551522037796 33.2588177147742314, 223.6903565456991032 33.2892180315189918, 223.6936834073373461 33.3196205104331185, 223.6971029051111373 33.3500211101661606, 223.7007701587775159 33.3804160898463422, 223.7044837207658361 33.4108103025735730, 223.7075120344809989 33.4412213366104680, 223.7108808174928640 33.4716244980177109, 223.7150218025271045 33.5020111064701567, 223.7185127414146848 33.5324154288194762, 223.7220915424775853 33.5628179459110427, 223.7256487173764015 33.5932212767874603, 223.7286216237151564 33.6236389014538517, 223.7320216441544289 33.6540465565227436, 223.7369843539350995 33.6844170564061542, 223.7396632577163587 33.7148425179124871, 223.7417605710628266 33.7452821085100041, 223.7453063421751835 33.7756872890390909, 223.7483122062117786 33.8061098599434615, 223.7517120548250489 33.8365277390942296, 223.7558255243959024 33.8669288054322521, 223.7594854651726166 33.8973409053826700, 223.7624929837646164 33.9277687625072559, 223.7659937331654874 33.9581850449847380, 223.7683016723167668 33.9886299136110850, 223.7717654102991389 34.0190474190815451, 223.7746851069329352 34.0494780281038132, 223.7778200650627412 34.0799036631504322, 223.7815767484544267 34.1103144299491063, 223.7849598454090767 34.1407339700314196, 223.7886890995187343 34.1711454270436050, 223.7929755563749268 34.2015437889649405, 223.7950123859445171 34.2319956603030775, 223.7976542511609637 34.2624332579386390, 223.8008059637030556 34.2928588583746645, 223.8038189436577738 34.3232878313987229, 223.8070197678133582 34.3537124337935751, 223.8102919260756209 34.3841354219903863, 223.8132599670128400 34.4145658934247152, 223.8172826871150392 34.4551387031975835))) +MULTIPOLYGON (((225.6590116069496332 15.2022751783289785, 225.8184285323443135 15.1938011439423235, 225.9815607790280581 15.1849941024038344, 226.1537479984186234 15.1755636256977464, 226.3305987103622101 15.1657156109381503, 226.5161948594225123 15.1552163684519332, 226.7132602792806040 15.1438893480044516, 226.9261988968144408 15.1314506128323636, 227.1499418817269316 15.1181384850929152, 227.3887605673780286 15.1036654664102112, 227.6457676408483621 15.0877902095770988, 227.9238726255883023 15.0702639427477045, 228.2357698250011140 15.0502006377175022, 228.5715407542897708 15.0280865134360671, 228.9475901302254215 15.0027161004160057, 229.3712716350795233 14.9733679202844066, 229.9511930054955826 14.9320537004547287, 230.4883212844398770 14.8922542022366819, 231.1136532006033804 14.8443022655274177, 231.8633228538656681 14.7845460925961838, 232.7891574036120517 14.7073522926485882, 233.9942664766833502 14.6013042632958854, 234.4965294635921680 14.5504706068641187, 234.5208110646848638 14.5099689963999161, 234.5313044307453367 14.4803171726285242, 234.5416131320472743 14.4506850419997690, 234.5520779986402147 14.4210415871861439, 234.5623431792820952 14.3914232576745800, 234.5724238854104442 14.3618286537537010, 234.5827882798384678 14.3322149028797057, 234.5929578122126600 14.3026258490534754, 234.6030683516360682 14.2730490548120841, 234.6134058759765253 14.2434583660659655, 234.6236678296300795 14.2138814838690237, 234.6339787547713343 14.1843070300948462, 234.6442862293286566 14.1547369881042862, 234.6547188872675065 14.1251597337691344, 234.6648922784237072 14.0956130660573216, 234.6753260770241241 14.0660495237721701, 234.6864368122618316 14.0364311268668658, 234.6957686613596934 14.0069820249208483, 234.7061404545204937 13.9774449563442520, 234.7168562114414385 13.9478834922368211, 234.7270224985275888 13.9183791088051372, 234.7372049000421725 13.8888802353741898, 234.7477636681231274 13.8593540756665892, 234.7584817070679151 13.8298204457635237, 234.7691873592963532 13.8002949952320169, 234.7803650561162385 13.7707336570441470, 234.7916750869490841 13.7411673887640564, 234.8029058073712747 13.7116154578260421, 234.8142170613676001 13.6820633421945015, 234.8253048393833069 13.6525386876241424, 234.8363381022113288 13.6230261368713013, 234.8474859602987408 13.5935103447128149, 234.8586521624573891 13.5639727106138768, 234.8698086928625059 13.5344171572959713, 234.8810402769611301 13.5048618787067021, 234.8921633393982233 13.4753235400046201, 234.9036036689824414 13.4457635459991671, 234.9148787490042878 13.4162256652156433, 234.9262976252631177 13.3866818978301705, 234.9378525867176108 13.3571329688567086, 234.9491438212119476 13.3276151021412534, 234.9605851744020129 13.2980908307225132, 234.9714051180906438 13.2686329664536888, 234.9829107519212243 13.2391230512865921, 234.9953247717635634 13.2095381987899341, 235.0050945474888522 13.1801996368848702, 235.0136741458930203 13.1509757165580634, 235.0235876206720604 13.1216383626052853, 235.0329511600260446 13.0923577947184526, 235.0428529677785718 13.0630357719613439, 235.0521842664741428 13.0337723689987097, 235.0625643588351181 13.0044215486467554, 235.0718456772173113 12.9752026575957213, 235.0824545385907243 12.9458957826393544, 235.0941279050537958 12.9165005023643378, 235.1065853385751154 12.8870421853161687, 235.1158685220012785 12.8578770133932370, 235.1267432526933305 12.8285761001416407, 235.1379548447788466 12.7992524167667021, 235.1493796196099879 12.7699171278070818, 235.1597708594709673 12.7406822110508919, 235.1712990020444067 12.7113527639371728, 235.1827906327161486 12.6820275614660503, 235.1941656397088991 12.6527141313651210, 235.2050650316088536 12.6234509250417943, 235.2163653281609186 12.5941593717566178, 235.2278129170846341 12.5648622451838943, 235.2385899997154013 12.5356327692369511, 235.2509196540145240 12.5062719958082358, 235.2633495965479540 12.4769099909586600, 235.2728707658307883 12.4478157345661558, 235.2843018917575364 12.4185583775542039, 235.2958612625120054 12.3892706549166327, 235.3093903396573410 12.3597895149907959, 235.3187948289964595 12.3306840979702557, 235.3306973306444547 12.3013633116314818, 235.3409552429090468 12.2721967440650062, 235.3501958582132545 12.2431283055929345, 235.3613910465265349 12.2138932348155915, 235.3730447120910583 12.1846249560596274, 235.3841076199099689 12.1554168856462663, 235.3951457458792618 12.1262186344057596, 235.4062396928094358 12.0970204530032373, 235.4175034832148583 12.0678123994039357, 235.4293245046916638 12.0385625703327914, 235.4421181448695393 12.0092341708445183, 235.4552959275237072 11.9798795411541921, 235.4690679159375861 11.9504801025218104, 235.4834853055173198 11.9210313919657640, 235.4960974303484704 11.8917506965023225, 235.5075487338667699 11.8625807322285581, 235.5232045968097907 11.8330462747878666, 235.5346764932195072 11.8038936248651432, 235.5484769106767544 11.7745459193969246, 235.5600500493502807 11.7454032068121563, 235.5703027540563141 11.7163850531242257, 235.5839099153991469 11.6870783107510565, 235.5954261045663429 11.6579642552422946, 235.6091634787426301 11.6286620492642268, 235.6216120133803429 11.5994816340682760, 235.6324251517819164 11.5704534114981232, 235.6427681561548582 11.5414744764065400, 235.6568231610475834 11.5121696293317068, 235.6720114139477857 11.4827667117950689, 235.6855534379756421 11.4535169164333990, 235.6985976231398183 11.4243190426501098, 235.7101697742900228 11.3952586967795071, 235.7212865678495746 11.3662463476185298, 235.7336848211043900 11.3371294098914515, 235.7467824960610017 11.3079591641971682, 235.7608802893133486 11.2787093286269826, 235.7716222749621409 11.2497620499263871, 235.7842032101285952 11.2206891920285248, 235.7973313754250455 11.1916028404892263, 235.8104867447666777 11.1625225099717724, 235.8248992522797494 11.1333405976365700, 235.8395596186489911 11.1041455609057547, 235.8525266395528206 11.0751071281384856, 235.8667638349001834 11.0459661778940248, 235.8799840524185640 11.0169226049989497, 235.8933575463182422 10.9878741537509068, 235.9056857922374775 10.9589253856053954, 235.9193690857431704 10.9298457604650068, 235.9332202571240771 10.9007399237311553, 235.9474135600927411 10.8716127613943545, 235.9606689831901747 10.8425757207505278, 235.9745891351899729 10.8134893032700230, 235.9749642465170609 10.7716809281293759, 234.3062264801270658 10.9140277809828365, 233.0568672341269121 11.0146280042264575, 232.0879579900154397 11.0891193380045809, 231.2922763752998208 11.1479476253113834, 230.6222024977055014 11.1958368476763059, 230.0451126661348269 11.2358585089428740, 229.5399124326949050 11.2699591633166492, 229.0910977852282429 11.2995144425355125, 228.6886580791903896 11.3254217054488961, 228.3230615139326005 11.3484629748935966, 227.9885578563494448 11.3691297953498367, 227.6794424865365158 11.3878696987456021, 227.3925662525238351 11.4049521734721129, 227.1244248889431105 11.4206460692871250, 226.8725374557916155 11.4351462062953271, 226.6348499723015095 11.4486118924986187, 226.4089327375779703 11.4612113075504123, 226.1941018513796280 11.4730141135587900, 225.9885536989872605 11.4841415383638772, 225.7906841315520694 11.4946974768609138, 225.5999034371537562 11.5047316362784322, 225.5366590428417908 11.5127499139888538, 225.5372155286848113 11.5505123386366542, 225.5385771173884848 11.5787917807460392, 225.5399422790718234 11.6070769022026870, 225.5412964706883940 11.6353683683310756, 225.5426724692766527 11.6636646542834530, 225.5440051181544163 11.6919712226479628, 225.5452754778118276 11.7202890826971338, 225.5466283640503775 11.7486089150272832, 225.5479733512454459 11.7769349110044050, 225.5492620733159299 11.8052693182738349, 225.5505841235170692 11.8336079602086315, 225.5519462019779553 11.8619505139368027, 225.5533034115049986 11.8902990653406153, 225.5546573358129194 11.9186535320087330, 225.5560296402161100 11.9470128980119092, 225.5574630380900487 11.9753825153473716, 225.5590145866423484 12.0037600937641198, 225.5604603602986913 12.0321483085325323, 225.5618766106682358 12.0605435905751133, 225.5632235047208098 12.0889478001897945, 225.5646322493352045 12.1173547928037380, 225.5660183352506749 12.1457685136780800, 225.5674524001674399 12.1741856512172308, 225.5688591210818288 12.2026097227853292, 225.5703066481627843 12.2310375313070310, 225.5717059626913112 12.2594635288136420, 225.5731135143499273 12.2878845470445004, 225.5745000481469731 12.3163122246356878, 225.5759250962974249 12.3447437586129976, 225.5773925000398208 12.3731789608754816, 225.5788485202704692 12.4016203466559691, 225.5803384551419128 12.4300657783575303, 225.5816851397536311 12.4585235860499672, 225.5830893138132183 12.4869843197081938, 225.5845898506858873 12.5154461392763992, 225.5860380817925375 12.5439157418262273, 225.5874589811405428 12.5723919343366166, 225.5889159824166654 12.6008720349108767, 225.5903500435784110 12.6293588188961490, 225.5917512821488060 12.6578527498482298, 225.5931498471001078 12.6863523976596984, 225.5945936513341508 12.7148554898354504, 225.5960004210751038 12.7433659093484160, 225.5974035729581715 12.7718820686378116, 225.5988234674924229 12.8004029994655610, 225.6002725684679433 12.8289353399234827, 225.6017372708080018 12.8574801027486316, 225.6031663910407872 12.8860320508820649, 225.6045230144762286 12.9145929258961978, 225.6058813440074289 12.9431592084249925, 225.6072542187562817 12.9717302816559918, 225.6086155629616314 13.0003073736031514, 225.6099855932373544 13.0288895208782165, 225.6113301416302193 13.0574783351150430, 225.6125573734466627 13.0860781700991904, 225.6138059182740392 13.1146685839299817, 225.6150812752645152 13.1432485814377742, 225.6162458523031376 13.1718393538115350, 225.6173776526709105 13.2004371913496446, 225.6185740513896576 13.2290374594585156, 225.6198200703518353 13.2576408581346996, 225.6210454855481373 13.2862507194559640, 225.6223709722382864 13.3148612910132620, 225.6236531537022643 13.3434793903344762, 225.6249325727087012 13.3721030822070848, 225.6260928571377633 13.4007285592951106, 225.6271536838081886 13.4293543933417254, 225.6282124976070804 13.4579858253871745, 225.6292645318286247 13.4866230741567108, 225.6301804110024136 13.5152723247030888, 225.6310913327383219 13.5439273006293899, 225.6319395690546230 13.5725907592594286, 225.6327541321401497 13.6012613103884146, 225.6337718653989839 13.6299275880244135, 225.6347506835452634 13.6586011868333443, 225.6357740728154795 13.6872915147215632, 225.6369158385559786 13.7159957105510735, 225.6377194034149625 13.7447214980022157, 225.6381065140526232 13.7734726407128552, 225.6384486639109923 13.8022312917939587, 225.6384696576625970 13.8310107210332234, 225.6377164798742854 13.8598327078059746, 225.6365675116648504 13.8886790654790975, 225.6366436894022058 13.9174718433797455, 225.6368569809392284 13.9462633391875563, 225.6372512897805791 13.9750446864033755, 225.6375598963244613 14.0038283679673583, 225.6379232733982292 14.0326147568883712, 225.6383897348957248 14.0614015137205151, 225.6384870234559514 14.0902113786118672, 225.6385225422024234 14.1190295456736390, 225.6386422679394741 14.1478489719565079, 225.6388548750343546 14.1766692296997032, 225.6393899649038417 14.2054792308434106, 225.6400017794549910 14.2342908121572211, 225.6406354383889550 14.2631066559514643, 225.6413569023304149 14.2919235679286665, 225.6418737902540670 14.3207556085893160, 225.6423091419993341 14.3495968330275954, 225.6427227616953246 14.3784443489976486, 225.6431399564071967 14.4072969250615799, 225.6435643096251908 14.4361543786609037, 225.6439996407971762 14.4650165188792776, 225.6444242559419422 14.4938843843585552, 225.6447387707936514 14.5227627777236634, 225.6449631354863357 14.5516507314802457, 225.6451722615322808 14.5805446135894456, 225.6453957584195393 14.6094429813533875, 225.6457542902550415 14.6383399812061050, 225.6462420944643554 14.6672358819702477, 225.6469402658950116 14.6961267418030239, 225.6476430847723407 14.7250225126985868, 225.6482912667314622 14.7539260619938783, 225.6489832272112039 14.7828326105555625, 225.6497656773054530 14.8117398863536138, 225.6506424448378993 14.8406387380365601, 225.6513629143920809 14.8695408563681148, 225.6517777326999976 14.8984629716291845, 225.6521804911266145 14.9273908339482286, 225.6524924024801919 14.9563282656240322, 225.6529946847831525 14.9852615952319770, 225.6535087795084848 15.0141994841802013, 225.6541740536502800 15.0431351473047741, 225.6549119930294864 15.0720723861003538, 225.6554983623736916 15.1010221056688980, 225.6560601550888236 15.1299724949437451, 225.6566877998535006 15.1589188522188660, 225.6590116069496332 15.2022751783289785))) +MULTIPOLYGON (((222.1624644987274735 22.8951608777580375, 222.3339278053788917 22.8936291251068340, 222.4918214736053699 22.8892887249650521, 222.6447347625685325 22.8849225119194060, 222.7860232523261459 22.8807537878477234, 222.9282491755332387 22.8764117841961223, 223.0766244984884281 22.8717204867395303, 223.2163755016804316 22.8671671508905057, 223.3566763952527197 22.8624540094745363, 223.4933003438143828 22.8577319701406161, 223.5898184186347635 22.8543578551823892, 223.6952462098461751 22.8505806049225200, 223.7986314112466744 22.8468004170732009, 223.8996071437578905 22.8430363020301179, 223.9985409791676716 22.8392789939742080, 224.0959564206523567 22.8355116832603073, 224.1910355953645535 22.8317716010045615, 224.2846905331828111 22.8280253856162254, 224.3794591431511947 22.8241662737757416, 224.4717633563003290 22.8203486474569317, 224.5633375180167945 22.8165001435605141, 224.6543476105572950 22.8126140287647630, 224.7440401314307223 22.8087272358785889, 224.8325041708576180 22.8048422967121454, 224.9212556591380121 22.8008911952094380, 225.0106581698819639 22.7968452217387743, 225.1000007997450894 22.7927430514162239, 225.1888277899553827 22.7886040404598802, 225.2781779860744962 22.7843853506296270, 225.3686923868900180 22.7800551111920520, 225.4590163590499117 22.7756725362798278, 225.5508196988342036 22.7711599176716817, 225.6422475001399732 22.7666030803204116, 225.7360430349097840 22.7618690699529438, 225.8308944078747231 22.7570178540152668, 225.9265645398245965 22.7520593285219199, 226.0249049679516702 22.7468968897921648, 226.1249454787357820 22.7415751880217485, 226.2278086014960081 22.7360312021479416, 226.3331090916695700 22.7302792145955088, 226.4411376184042979 22.7242978236477988, 226.5516842588731947 22.7180922187040188, 226.6656163592838027 22.7116078269275619, 226.7845301475277040 22.7047457110851489, 226.9071475647060652 22.6975670622629160, 227.0314410381331243 22.6901810097109511, 227.1839792061291519 22.6810029065164471, 227.3309878641200044 22.6719940161947804, 227.4852574295117620 22.6623834901635597, 227.6478981924011009 22.6520789917443821, 227.8244753454561931 22.6406976406627720, 228.0131819147138117 22.6283077429488948, 228.2162925671777600 22.6147123262701584, 228.4292029370038222 22.6001656945547929, 228.6562565744310689 22.5843249430069939, 228.9060279700422313 22.5665175965706943, 229.1825161009347198 22.5463403909257636, 229.4889073172393807 22.5234095912130243, 229.8235975093082004 22.4976688769848394, 230.1950353288359565 22.4682622757394519, 230.6140350096124507 22.4340362401953577, 231.0891086673919972 22.3938791164045128, 231.6395866999296516 22.3455627543664477, 232.2933600726683778 22.2857009542201254, 233.0468719137620610 22.2096336011567779, 233.0786160066152775 21.8362790739403572, 233.1128703123239063 21.4745535126135110, 233.1496154959708065 21.1131520454980688, 233.1847240762937474 20.7523849750790745, 233.2282694103726897 20.3912575382923755, 233.2729399482162762 20.0308241593812788, 233.3250709696296497 19.6705333692991715, 233.3796821892690616 19.3110185897310593, 233.4385722857594772 18.9512397884658697, 233.5048315557592673 18.5912746804501623, 233.5705679159131591 18.2318918457248778, 233.6451980362392078 17.8721782134589731, 233.7217275110074581 17.5133469216565452, 233.8008596205570200 17.1546858578559558, 233.8864271817588190 16.7969322128414085, 233.9697189397047907 16.4397036867894251, 234.0828109354990545 16.0803141029572600, 234.1849920610645768 15.7230496510930529, 234.2920854378215267 15.3662472679597375, 234.4024907295219009 15.0099336757912134, 234.5149128961783731 14.6540024088048977, 234.6379311558054326 14.2984584661645968, 234.7623775583252552 13.9436811557223272, 234.8942578962761161 13.5892102040071983, 235.0288272444620077 13.2349149253326068, 235.1521051686026453 12.8828891505364300, 235.2867725908210446 12.5312613936619748, 235.4233087213997067 12.1800902646282925, 235.5708596309736720 11.8287640873522850, 235.7235065836390788 11.4781679472845699, 235.8797318095176365 11.1284757052386034, 236.0525313246200483 10.7671682736336223, 234.5539738435579977 10.8934756929011449, 233.4407131631540437 10.9842712723620792, 232.5469229652692320 11.0542229776525041, 231.8057772059855211 11.1102241836924787, 231.1727759778447648 11.1565989554036538, 230.6222024977055014 11.1958368476763059, 230.1360978921009348 11.2296246903372410, 229.7011060076232241 11.2591734075795635, 229.3092627460602273 11.2852352682303056, 228.9523786369067579 11.3085085479184446, 228.6255699416132074 11.3294320811176288, 228.3230615139326005 11.3484629748935966, 228.0424929933024316 11.3658248267828199, 227.7797848238557492 11.3818240807616586, 227.5335303503333364 11.3965959501440786, 227.3013618133060163 11.4103203927983330, 227.0813921445946448 11.4231400422550973, 226.8725374557916155 11.4351462062953271, 226.6735784057245553 11.4464323336035516, 226.4830830479991164 11.4570977194971331, 226.3002739486517783 11.4672030229445170, 226.1246140672760987 11.4767939954951359, 225.9550662527171312 11.4859387811404936, 225.7906841315520694 11.4946974768609138, 225.6312478555481675 11.5030927722805192, 225.4762447625165862 11.5111601660590104, 225.3250842761335662 11.5189369296463209, 225.1774439551033993 11.5264465188925040, 225.0328448253008276 11.5337180770388592, 224.8908763596499512 11.5407761760390493, 224.7513584997170994 11.5476346729869785, 224.6139594562444017 11.5543129777216951, 224.4784375362928017 11.5608260941168393, 224.3444652819518979 11.5671914448567392, 224.2117774258872487 11.5734232007998141, 224.0801718772115123 11.5795330298151118, 223.9493664901772263 11.5855344996028062, 223.8191624724303210 11.5914391819364901, 223.6892422590755416 11.5972592901638460, 223.5594084415188831 11.6030053638418362, 223.4294005333658788 11.6086896685846472, 223.2989722102153110 11.6143216904896001, 223.1678913125293775 11.6199107220579343, 223.0358968024123385 11.6254674694606823, 222.9027074603666563 11.6310028546020909, 222.7681514532171434 11.6365211164074118, 222.6319141538511417 11.6420339437191078, 222.4937638625381169 11.6475477129753546, 222.3535187113670872 11.6530658977330432, 222.2106332312147856 11.6586083764684467, 222.0649326370145218 11.6641761438978122, 221.9159984711472191 11.6697805626173459, 221.7637180402759896 11.6754184975323128, 221.6071946734359415 11.6811193203433437, 221.4462705120650412 11.6868790352438818, 221.2800176036296591 11.6927238980806685, 221.1082343240083787 11.6986486654978012, 220.9302181846820758 11.7046664471111157, 220.7448115762650502 11.7108046009619358, 220.5512576667551343 11.7170716871887315, 220.3489604038603034 11.7234675876106191, 220.1364090861307830 11.7300207161664964, 219.9120955538539874 11.7367529071657000, 219.6885215783223657 11.7467999825142257, 219.7800022085925491 12.0939667193907923, 219.8674454815513286 12.4316594207246638, 219.9609663350123014 12.7696974747126717, 220.0435221787505213 13.1088831469933211, 220.1287352849992942 13.4489940064017972, 220.2143098341883558 13.7895853682338103, 220.2996432291302824 14.1309982530505547, 220.3856337208090963 14.4729600249569028, 220.4702124060514450 14.8160664519636125, 220.5542495225764128 15.1598074722681364, 220.6372147494944045 15.5039964430272246, 220.7215739629969278 15.8490768265738229, 220.8003749786528260 16.1950206147845002, 220.8780366528559398 16.5414260978017715, 220.9576980259738264 16.8886184325720521, 221.0492649287550080 17.2360440209217529, 221.2038686914070240 17.5820804815569822, 221.2332821021322786 17.9327909628593183, 221.3064374132812020 18.2825671410777524, 221.3767990322102150 18.6330869316894123, 221.4437786009013962 18.9842653900625713, 221.5157897916339209 19.3357555188309291, 221.6415036192033199 19.6862868958747796, 221.7040268217931782 20.0392648175583936, 221.7734189145131722 20.3928463603017818, 221.8288535880878953 20.7473064170266852, 221.8917645081734804 21.1019045712286442, 221.9100285267250285 21.4581261494620072, 221.9689664639684850 21.8138417552296708, 222.0351237485043043 22.1699280426223453, 222.0994527851256350 22.5263997499335709, 222.1624644987274735 22.8951608777580375))) diff --git a/isis/src/base/objs/ImagePolygon/ImagePolygon_Linux_x86_64_SUSE10_1.truth b/isis/src/base/objs/ImagePolygon/ImagePolygon_Linux_x86_64_SUSE10_1.truth new file mode 100644 index 0000000000000000000000000000000000000000..2142e016a5159aa60eb286e5bf28f397d09123ee --- /dev/null +++ b/isis/src/base/objs/ImagePolygon/ImagePolygon_Linux_x86_64_SUSE10_1.truth @@ -0,0 +1,3 @@ +MULTIPOLYGON (((223.8172826870554388 34.4551387030861562, 223.8417027793910279 34.4596506066820112, 223.8575436553176701 34.4592772202857844, 223.8731987947955702 34.4589061403268389, 223.8888001595454966 34.4585342458576349, 223.9044019981010649 34.4581602382883219, 223.9200661671754347 34.4577826049052831, 223.9355075424467429 34.4574083328668834, 223.9508457646257682 34.4570345511811595, 223.9660146266157881 34.4566629441688406, 223.9810473116613707 34.4562927476240120, 223.9957878473876747 34.4559279256362956, 224.0106582442351453 34.4555579476699165, 224.0255459276724821 34.4551856180930614, 224.0403444766045311 34.4548136399185410, 224.0550707902558543 34.4544416140812260, 224.0696826278450544 34.4540706528633081, 224.0842130299532755 34.4536999451661856, 224.0986612451088149 34.4533295402476867, 224.1130364689869623 34.4529592283796191, 224.1273202299933018 34.4525895194552731, 224.1415662443043573 34.4522190340582313, 224.1557339918608704 34.4518488559867606, 224.1698107918541609 34.4514793494806284, 224.1838116920665982 34.4511101458139208, 224.1977227034556961 34.4507416459917692, 224.2115924901468702 34.4503725738795836, 224.2254006440637681 34.4500034947196099, 224.2391929104324504 34.4496331904990001, 224.2529511041107355 34.4492621618858976, 224.2666975062502672 34.4488898121368337, 224.2803860065775439 34.4485174107728724, 224.2940079847231800 34.4481452153055372, 224.3075938798835978 34.4477724066462869, 224.3210795841726224 34.4474007776905964, 224.3344990942370032 34.4470294144046818, 224.3478450164772369 34.4466585461289370, 224.3611125161780251 34.4462883334162839, 224.3742955932223424 34.4459189716523113, 224.3874260849249538 34.4455495872321151, 224.4004958875964064 34.4451804279779594, 224.4135260618142524 34.4448109130245967, 224.4264828608789912 34.4444420219817644, 224.4393721008836167 34.4440736115621888, 224.4522012232876591 34.4437054889999104, 224.4649910968735753 34.4433370695209504, 224.4777393619483519 34.4429684345123448, 224.4904489206230380 34.4425995128584503, 224.5030718093267126 34.4422317208438145, 224.5156259768878328 34.4418645587055465, 224.5281770921911857 34.4414961127534696, 224.5407219882328320 34.4411264780584858, 224.5531975742495661 34.4407575293592743, 224.5656264624743699 34.4403886150134326, 224.5780227094808765 34.4400193297392221, 224.5903757296815400 34.4396500013147318, 224.6026728254119291 34.4392810252896382, 224.6148668913133122 34.4389138407199553, 224.6269709753682093 34.4385480837916376, 224.6390599334172578 34.4381815076602962, 224.6511372139618175 34.4378140121817182, 224.6632067785040476 34.4374454801668293, 224.6751614661697261 34.4370792014152798, 224.6870933909598023 34.4367123756374625, 224.6989898632547238 34.4363454016597004, 224.7108678965473416 34.4359777634713211, 224.7226881483722991 34.4356106889183167, 224.7344958302550708 34.4352427865472563, 224.7462652761358015 34.4348748626036780, 224.7579793002169026 34.4345074672970526, 224.7696431367291439 34.4341404523806460, 224.7812728007805561 34.4337733275598907, 224.7928435543977344 34.4334068854894113, 224.8043847867216130 34.4330402109262153, 224.8157283419619716 34.4326786627865005, 224.8270886232841690 34.4323154551120965, 224.8384166745431685 34.4319521503576169, 224.8497524406567720 34.4315874760106411, 224.8610108250075541 34.4312241690653593, 224.8722867697038623 34.4308591870978660, 224.8835699922025810 34.4304928586050210, 224.8948651191152521 34.4301250319575658, 224.9061662755833879 34.4297558956339884, 224.9173542816715781 34.4293893381866098, 224.9284086365155417 34.4290260616188064, 224.9394220907865360 34.4286630586182127, 224.9504388176640077 34.4282988871562736, 224.9614347391278102 34.4279343412270009, 224.9724090215291596 34.4275694544292463, 224.9833614191804259 34.4272042411422490, 224.9942931924667278 34.4268386657352323, 225.0052127357933216 34.4264724542664169, 225.0161268911519983 34.4261053817509719, 225.0270072241578134 34.4257384031269211, 225.0379099782836647 34.4253696378408165, 225.0487812548770989 34.4250008963959786, 225.0595876459126430 34.4246333158877320, 225.0703030756958185 34.4242677965401143, 225.0809691073864656 34.4239029512769363, 225.0916138569805582 34.4235378364048117, 225.1022391575891959 34.4231723953056203, 225.1128542317258336 34.4228063180293233, 225.1234516167740765 34.4224398635157556, 225.1340217161871919 34.4220733665334180, 225.1445720848678889 34.4217065741965840, 225.1551012336083772 34.4213395433927403, 225.1655864785901997 34.4209730651206414, 225.1760248993641085 34.4206072521104787, 225.1864409930022077 34.4202412644615379, 225.1968389824640724 34.4198749609670074, 225.2072200098035353 34.4195083066778125, 225.2175785697109234 34.4191414990643736, 225.2279161215415968 34.4187744928887298, 225.2382328071077211 34.4184072887788659, 225.2485261485682315 34.4180399796766565, 225.2587970262709973 34.4176725406107664, 225.2690410352409742 34.4173051335255948, 225.2792535965254217 34.4169379279162868, 225.2894249396076418 34.4165712794060497, 225.2995612323753960 34.4162049783027371, 225.3096797795340080 34.4158384149443748, 225.3197769941242257 34.4154717224572408, 225.3298508715159585 34.4151049782719625, 225.3399032249868128 34.4147381230933931, 225.3499338576569073 34.4143711695009245, 225.3599442461228932 34.4140040696646849, 225.3699387631349111 34.4136366704509413, 225.3799126564553319 34.4132691483703610, 225.3898592055629706 34.4129017528991028, 225.3997746327033838 34.4125346283236553, 225.4096413759663164 34.4121684231094349, 225.4194664480515655 34.4118028921399457, 225.4292333250850220 34.4114386506334142, 225.4389847119238937 34.4110741438094863, 225.4487227950546355 34.4107092950618778, 225.4584529700451867 34.4103439088415755, 225.4681791118237868 34.4099778441967459, 225.4779501834397308 34.4096092904921065, 225.4877658689309783 34.4092382501921250, 225.4975606253910314 34.4088671491674702, 225.5073160520562396 34.4084966774081309, 225.5170945589489975 34.4081245163349578, 225.5268331233620245 34.4077530164326788, 225.5365021994056747 34.4073832928032175, 225.5461190551147297 34.4070147129218213, 225.5556995064936814 34.4066466938671667, 225.5652214497690409 34.4062800756482829, 225.5747432098429783 34.4059126712269006, 225.5842560908538417 34.4055448095740175, 225.5937778006128553 34.4051758227699267, 225.6033009157918059 34.4048059909125215, 225.6128238278373033 34.4044353752724277, 225.6223471750254532 34.4040639520834688, 225.6318758783412477 34.4036915342067431, 225.6414016415699280 34.4033184378166581, 225.6509363628046003 34.4029442090107551, 225.6604947562084647 34.4025682829215427, 225.6700415056936606 34.4021920106849635, 225.6795791566649996 34.4018152973413507, 225.6890709330758114 34.4014395611739303, 225.6985268750812850 34.4010644243483270, 225.7079299361909932 34.4006905526265498, 225.7172925180968832 34.4003174765961646, 225.7266351872193013 34.3999444072982925, 225.7359624913239884 34.3995711723548609, 225.7452560214270534 34.3991984905109618, 225.7545267975710601 34.3988259392688747, 225.7637889836344414 34.3984529709160256, 225.7730507645073317 34.3980792678529141, 225.7823252012635180 34.3977043199699821, 225.7916004169035205 34.3973285906499058, 225.8008725342959622 34.3969522323247858, 225.8101369195184134 34.3965754280254501, 225.8193892451850218 34.3961983497526589, 225.8286274988493858 34.3958210792869465, 225.8378496687657275 34.3954436987810084, 225.8470551995606286 34.3950662332777384, 225.8562326011004018 34.3946891400830452, 225.8653930029058472 34.3943119835577278, 225.8745410760741379 34.3939345816838795, 225.8836776373499617 34.3935569043987428, 225.8928019411091839 34.3931789835027715, 225.9019194640785599 34.3928006034879772, 225.9110308751989749 34.3924217392180083, 225.9201549499623809 34.3920416439267100, 225.9292743320435477 34.3916610090137027, 225.9383845714556003 34.3912800134750256, 225.9474795314178550 34.3908989044373357, 225.9565581779352499 34.3905177257819048, 225.9656244992437450 34.3901363203602273, 225.9746802477525875 34.3897546199894251, 225.9837284337445169 34.3893725057496198, 225.9927658599887081 34.3889901074684872, 226.0017891753058166 34.3886075615055375, 226.0108161763018302 34.3882241545240106, 226.0198457173550253 34.3878399331655515, 226.0288659304852672 34.3874553757630252, 226.0378750537378778 34.3870705548477034, 226.0468586590083930 34.3866860531593659, 226.0558323074971554 34.3863012459153055, 226.0647969809047027 34.3859160948656566, 226.0737494779210124 34.3855307302515385, 226.0826909505214530 34.3851451068040603, 226.0916392243316864 34.3847585069560395, 226.1005846293875834 34.3843713215449966, 226.1095237944467726 34.3839836875571763, 226.1184552396198910 34.3835956656762889, 226.1273766599849182 34.3832073496778676, 226.1362843513687437 34.3828188893592923, 226.1451789838363595 34.3824302579892915, 226.1540696341189687 34.3820410907882916, 226.1629557016454157 34.3816514125989272, 226.1718415645501068 34.3812610485457881, 226.1807230054455999 34.3808701688271512, 226.1896010103693300 34.3804787347538792, 226.1984731024690234 34.3800868460323059, 226.2073393250070410 34.3796945012310715, 226.2162010894380444 34.3793016444903685, 226.2250584402766265 34.3789082745362009, 226.2339210610063560 34.3785140099351949, 226.2427791039827127 34.3781192423319908, 226.2516314343283170 34.3777240168995561, 226.2604782195339226 34.3773283272095398, 226.2693193564055321 34.3769321772336838, 226.2781549132746193 34.3765355639964483, 226.2869854330353121 34.3761384661654006, 226.2958114626155748 34.3757408625676888, 226.3046334835679545 34.3753427349446667, 226.3134536502138019 34.3749440038212271, 226.3222666039530395 34.3745448675868772, 226.3310674200903350 34.3741454965105504, 226.3398662973730779 34.3737455139907979, 226.3486632146650379 34.3733449207269217, 226.3574580470379658 34.3729437205966306, 226.3662507195154205 34.3725419149321496, 226.3750416931271161 34.3721394877984991, 226.3838307521521074 34.3717364446175608, 226.3926183115015363 34.3713327721326252, 226.4014042158760844 34.3709284729463391, 226.4101886820603227 34.3705235397049265, 226.4189713667341266 34.3701179688710852, 226.4277528949788518 34.3697117359899522, 226.4365339441874028 34.3693048460954742, 226.4453141371841980 34.3688973009585865, 226.4540932758034728 34.3684891262239631, 226.4628714412388035 34.3680802909390195, 226.4716492125770628 34.3676707554958369, 226.4804266127447647 34.3672605340832646, 226.4892039200612430 34.3668496114386883, 226.4979812270886441 34.3664379860401468, 226.5067586403042696 34.3660256539005715, 226.5155350783788037 34.3656126841276048, 226.5243113274158588 34.3651990254046851, 226.5330863836773290 34.3647847378262838, 226.5418613931196887 34.3643697520982840, 226.5506364357558766 34.3639540648018951, 226.5594125115484587 34.3635376201859799, 226.5681899791629235 34.3631204005482616, 226.5769703953518786 34.3627023214856777, 226.5857530174790213 34.3622834276467799, 226.5945393457379566 34.3618636384960254, 226.6033280976941739 34.3614430267662812, 226.6121204829055102 34.3610215277182292, 226.6209149844707156 34.3605992248942727, 226.6297112468444084 34.3601761375813552, 226.6385086581271366 34.3597522984601511, 226.6473076484998614 34.3593276840231567, 226.6561088518905933 34.3589022601831786, 226.6649128221872047 34.3584759974264813, 226.6737198569121006 34.3580488800412880, 226.6825293890375974 34.3576209381841053, 226.6913400811723420 34.3571922425097114, 226.7001540295673578 34.3567626816807206, 226.7089712049645414 34.3563322571851657, 226.7177870375159330 34.3559012099767713, 226.7266041828078187 34.3554693992389133, 226.7354247297398331 34.3550367145667792, 226.7442492611458533 34.3546031251241786, 226.7530788598978972 34.3541685737675522, 226.7619128745805881 34.3537330945820614, 226.7707514832060269 34.3532966779085598, 226.7795960290009418 34.3528592527794885, 226.7884459906872507 34.3524208461995855, 226.7973003349381997 34.3519815119965344, 226.8061593642061098 34.3515412337322488, 226.8150233317537925 34.3510999975136926, 226.8238934698196942 34.3506577379326501, 226.8327720567338872 34.3502143344743303, 226.8416573813208856 34.3497698762915888, 226.8505497655341401 34.3493243455891317, 226.8594358490680065 34.3488784447268642, 226.8683250410213361 34.3484316781252730, 226.8772265484987827 34.3479835600551269, 226.8861363120287820 34.3475343031321501, 226.8950567593712151 34.3470837781792824, 226.9039829499012342 34.3466322445209400, 226.9129146680944871 34.3461797125383654, 226.9218556874094190 34.3457259818489007, 226.9308045477948497 34.3452711282402134, 226.9397756292526935 34.3448143895302991, 226.9487603184134912 34.3443562188081657, 226.9577713539455033 34.3438959389133061, 226.9667906962734207 34.3434345027779884, 226.9758185915864317 34.3429718957263219, 226.9848216200828404 34.3425098913908897, 226.9938252716434022 34.3420471374260501, 227.0028484628032004 34.3415826267594184, 227.0118809439680376 34.3411169021389355, 227.0209235817709157 34.3406499156234659, 227.0299791780944361 34.3401815158194594, 227.0390478252961657 34.3397116954514985, 227.0481467096626034 34.3392395333766132, 227.0572602651047589 34.3387658574176626, 227.0663771858033613 34.3382912703767857, 227.0755008947110412 34.3378155877346103, 227.0846303913073996 34.3373388616534214, 227.0937637964039482 34.3368611917210984, 227.1029086135041553 34.3363821733254184, 227.1120687985143718 34.3359015911654311, 227.1212359111418095 34.3354198971172906, 227.1304019305065083 34.3349375223436439, 227.1395758196006227 34.3344539825447796, 227.1487597349276939 34.3339691593657577, 227.1579902583264072 34.3334810704758411, 227.1672328061905830 34.3329915812163335, 227.1764712676953764 34.3325015630313359, 227.1857181919765196 34.3320103346922068, 227.1949746843040998 34.3315178341563865, 227.2042427831847817 34.3310239482966324, 227.2135235122841266 34.3305286187725329, 227.2228146140698470 34.3300319660012079, 227.2321158182128897 34.3295340024028164, 227.2414261879402773 34.3290347769038107, 227.2507440105588898 34.3285343811480175, 227.2600744088126987 34.3280325324944187, 227.2694283383975744 34.3275286268106896, 227.2787965981403033 34.3270231647175663, 227.2881796631106397 34.3265161168639992, 227.2975768164326098 34.3260075194109362, 227.3069878365900536 34.3254973813716262, 227.3164104609731453 34.3249858245099446, 227.3258502854863821 34.3244725367080221, 227.3353080996716926 34.3239574703682919, 227.3447883387066213 34.3234403755929947, 227.3542849111706516 34.3229215853954273, 227.3637955610474251 34.3224012213397032, 227.3733236581833523 34.3218790926137274, 227.3828696239687872 34.3213551716832939, 227.3924291244552194 34.3208296960990751, 227.4020038477916899 34.3203025683132310, 227.4115915765664226 34.3197739086688429, 227.4211903006604985 34.3192438265212729, 227.4308034100351392 34.3187121290632149, 227.4404322668985969 34.3181787363226363, 227.4500783315635317 34.3176435624042711, 227.4597408211544121 34.3171066472117161, 227.4694373999262780 34.3165669913512446, 227.4791525994612869 34.3160254597000716, 227.4888678788144887 34.3154830952473375, 227.4985957069042399 34.3149391921614466, 227.5083373853138085 34.3143936735035808, 227.5181018062715737 34.3138460313880955, 227.5278825759429537 34.3132966234387382, 227.5376789842295011 34.3127454859353236, 227.5475028125167398 34.3121919440087666, 227.5573500149448023 34.3116362217108133, 227.5672257339052180 34.3110780196529035, 227.5771363516663541 34.3105169659525373, 227.5870780116667618 34.3099532729218311, 227.5970431329253074 34.3093873675369281, 227.6070304509327684 34.3088193164755495, 227.6170402145462788 34.3082490997872682, 227.6270614888811394 34.3076773412008720, 227.6371021487410076 34.3071035836203393, 227.6471620472045458 34.3065278304867363, 227.6572333482910437 34.3059505296988263, 227.6673250879570389 34.3053711550848135, 227.6774425887975610 34.3047893928164669, 227.6875956283761582 34.3042046687850117, 227.6977747165031190 34.3036175255403180, 227.7079695685462184 34.3030285548813652, 227.7181855113298639 34.3024374420603024, 227.7284236548779006 34.3018441166910293, 227.7386810962439654 34.3012487425372896, 227.7489607488712977 34.3006511438889916, 227.7592652945483849 34.3000511576431748, 227.7696049562804603 34.2994481772121489, 227.7799661327425724 34.2988429927923519, 227.7903495499146516 34.2982355558256558, 227.8007531420874443 34.2976259820286913, 227.8111804588932330 34.2970140563683188, 227.8216354765219762 34.2963995373976758, 227.8321461589635533 34.2957807625226039, 227.8426781272081598 34.2951597549059954, 227.8532313530564579 34.2945365103118789, 227.8637943594835917 34.2939117050406495, 227.8743681842870785 34.2932852743100582, 227.8849595330412967 34.2926568151128990, 227.8955699765630243 34.2920262286820261, 227.9062407193817990 34.2913910462529685, 227.9169476338818185 34.2907526962728753, 227.9276713907391354 34.2901123277707356, 227.9383745218270860 34.2894721855654012, 227.9490646281740283 34.2888318174488589, 227.9597329801610215 34.2881917519580597, 227.9704830712439048 34.2875457532931378, 227.9813063056426188 34.2868943187016697, 227.9922004455596038 34.2862375637549448, 228.0031311318133760 34.2855775502002231, 228.0140933799731044 34.2849145701223819, 228.0250913628472631 34.2842483610777151, 228.0361342648420191 34.2835783542064405, 228.0472235719963976 34.2829044463308890, 228.0583488204560183 34.2822272628250673, 228.0695055535578035 34.2815470657209858, 228.0806796288569274 34.2808647114042699, 228.0918858625025791 34.2801792865075754, 228.1031233132273712 34.2794908394530822, 228.1143887119357885 34.2787995620820851, 228.1256453028393594 34.2781077090887152, 228.1369030524184325 34.2774146678620184, 228.1481798443663820 34.2767193332270139, 228.1595524441736416 34.2760169519050493, 228.1709717099908517 34.2753105403553633, 228.1824155794452338 34.2746014535234167, 228.1938803829937683 34.2738899119351572, 228.2054189265468267 34.2731726235595602, 228.2170280980613484 34.2724497608496677, 228.2287243266976020 34.2717202776986909, 228.2405154509019098 34.2709836584986789, 228.2523281114683300 34.2702444678746545, 228.2641942766789498 34.2695006944830070, 228.2760966165556056 34.2687534104679514, 228.2880311232885049 34.2680028567511243, 228.3000080489240418 34.2672483774467338, 228.3120073191867618 34.2664912261054937, 228.3240136615007714 34.2657323607450479, 228.3360270491550921 34.2649717804313170, 228.3480846101073780 34.2642071288155847, 228.3601573792798547 34.2634402313342505, 228.3722738818091784 34.2626692688684358, 228.3844436938970262 34.2618936178110189, 228.3966618612765558 34.2611135776316047, 228.4089824127830468 34.2603256808090606, 228.4213463879687822 34.2595336690666770, 228.4337530236520877 34.2587375774856255, 228.4462104847060004 34.2579368681707308, 228.4587268133269902 34.2571310076858282, 228.4712928807757919 34.2563205652334943, 228.4839104809788353 34.2555054090234847, 228.4966228686225236 34.2546827270764211, 228.5094182245555317 34.2538532539691261, 228.5222741771181916 34.2530184132892543, 228.5351729278072810 34.2521793410413196, 228.5481108241753248 34.2513362605627520, 228.5610933369307247 34.2504888022589995, 228.5740744626591265 34.2496399537063851, 228.5870890608425441 34.2487874359030542, 228.6001377310801956 34.2479311982219343, 228.6132200400504360 34.2470712574983480, 228.6263499085960689 34.2462066876372475, 228.6395379494453266 34.2453367741268693, 228.6528307701242682 34.2444584248850177, 228.6663763632237476 34.2435618321320945, 228.6803617216070279 34.2426345403196279, 228.6952015541801018 34.2416489116415121, 228.7105525888537727 34.2406274235319827, 228.7265499348228843 34.2395608902071729, 228.7421439706193098 34.2385190300592086, 228.7570825716228740 34.2375188386586800, 228.7710598753439228 34.2365810240280624, 228.7833530683670915 34.2357543577948604, 228.7952800700753357 34.2349509230007385, 228.8072627602488183 34.2341424759791479, 228.8196514308424128 34.2333054216225463, 228.8331287442263147 34.2323936078462410, 228.8473922131469180 34.2314270979658062, 228.8618442087490621 34.2304460497711815, 228.8763439298241451 34.2294599387118268, 228.8909482643396984 34.2284648839076837, 228.9056482136823263 34.2274614587343677, 228.9203772896302098 34.2264541587582727, 228.9351647839141037 34.2254409727997029, 228.9499300140618629 34.2244273972624740, 228.9641311146921510 34.2234505681392989, 228.9782062980468424 34.2224806099825472, 228.9925852306207048 34.2214880257807508, 229.0081810669700531 34.2204098059550574, 229.0243240483496265 34.2192917030580901, 229.0404841060924355 34.2181701533111919, 229.0561546197716325 34.2170802519520976, 229.0718159793608208 34.2159888444595595, 229.0875983321438127 34.2148868823153975, 229.1034887026832507 34.2137752211917530, 229.1195460111437399 34.2126497038870880, 229.1358158382292629 34.2115070741072032, 229.1519329161566532 34.2103728455040397, 229.1680640638790010 34.2092353650360934, 229.1841528314637060 34.2080985980235397, 229.1997352210103145 34.2069952675949907, 229.2145400585607717 34.2059447195264852, 229.2300224803216508 34.2048443142916554, 229.2467979267665044 34.2036501662420562, 229.2636965491348633 34.2024448212972416, 229.2805688058051032 34.2012388685525011, 229.2975531551136896 34.2000224457224888, 229.3153572084256666 34.1987449442457461, 229.3330755456161967 34.1974708312596221, 229.3499864414941669 34.1962519261839191, 229.3671162393675331 34.1950147939656333, 229.3845622241133242 34.1937523319198036, 229.4014568277656281 34.1925270212032331, 229.4184179979918952 34.1912944082571215, 229.4358437587445678 34.1900256223240930, 229.4537366314563656 34.1887202761169675, 229.4717783256412531 34.1874013196511797, 229.4899255387612413 34.1860718421937335, 229.5081725982472847 34.1847322093503649, 229.5265398704868574 34.1833808832578470, 229.5450922295952978 34.1820130472502939, 229.5638787832904484 34.1806250030229819, 229.5833013117678547 34.1791870290051136, 229.6027619755459170 34.1777429731368088, 229.6217226068972934 34.1763326527843674, 229.6405847438497574 34.1749265203990618, 229.6596052490852458 34.1735055273338943, 229.6788397630403722 34.1720654517922213, 229.6983584810002981 34.1706009483857613, 229.7180957279716438 34.1691167911206222, 229.7380788626514345 34.1676108188229577, 229.7584117626756210 34.1660750989131117, 229.7790969056334802 34.1645092649619926, 229.7996369176232463 34.1629506915650651, 229.8203742932615512 34.1613735311362277, 229.8416825811018498 34.1597493412739439, 229.8624957634657449 34.1581588785920331, 229.8824174025879756 34.1566326127752262, 229.9024284096595068 34.1550960778054673, 229.9235693656282535 34.1534695744186010, 229.9452549994916524 34.1517974116376379, 229.9672683739203762 34.1500959777487694, 229.9895003849197508 34.1483735025366926, 230.0115335641944796 34.1466621287872840, 230.0333871041715099 34.1449604786041903, 230.0555507514621070 34.1432306179808407, 230.0779079317051696 34.1414814475757709, 230.1005423000428038 34.1397063292869589, 230.1238833343684291 34.1378715064769835, 230.1469833844930122 34.1360508854267408, 230.1701524619105044 34.1342202325622708, 230.1934678024694563 34.1323734190311399, 230.2165682856712010 34.1305388895063047, 230.2389046257694361 34.1287602695710035, 230.2627494181147370 34.1268575757473371, 230.2877550267185711 34.1248575756020855, 230.3121994425740979 34.1228969831179683, 230.3374538174993518 34.1208664279545033, 230.3631413116128499 34.1187956310739793, 230.3880206607562116 34.1167841714593436, 230.4129740677024358 34.1147614026916131, 230.4381720996264562 34.1127134836086370, 230.4639006138211812 34.1106170798747144, 230.4899617774171361 34.1084879303946877, 230.5160751630245954 34.1063486758618453, 230.5424933623011441 34.1041786332810304, 230.5692512088523074 34.1019747430087818, 230.5962633488587983 34.0997437898786515, 230.6233712572403647 34.0974986647174276, 230.6505324126961796 34.0952428144590840, 230.6778991777003398 34.0929635734629102, 230.7056768660073374 34.0906437346523816, 230.7338743165616393 34.0882822719610203, 230.7624290256065365 34.0858841097945273, 230.7912515729211975 34.0834564851068436, 230.8203176007895934 34.0810012491227283, 230.8496066250636432 34.0785199485613006, 230.8792222279615203 34.0760036572390774, 230.9092353385915999 34.0734461133305047, 230.9394837891280190 34.0708608099390204, 230.9699110764533714 34.0682523865333948, 231.0006928671985236 34.0656056693742499, 231.0318850272019517 34.0629155853065200, 231.0635571686676144 34.0601758150416529, 231.0955368340583789 34.0574008701334989, 231.1277395308281086 34.0545978214642773, 231.1598263150311539 34.0517959464563944, 231.1923731408357128 34.0489451184199226, 231.2256091620638472 34.0460249133125785, 231.2592693972243296 34.0430580047345188, 231.2932997455176860 34.0400487929999755, 231.3276773418911603 34.0369989773430675, 231.3623788652666065 34.0339103205237095, 231.3976872584197793 34.0307573786865163, 231.4333912448704211 34.0275584578910752, 231.4693555746214315 34.0243253059693487, 231.5059110724441780 34.0210279683690260, 231.5428878342104326 34.0176812112379139, 231.5803120488249078 34.0142822697343661, 231.6182257696958402 34.0108269012199855, 231.6563923558109366 34.0073361889261321, 231.6951328869912459 34.0037805360141476, 231.7344016753486926 34.0001635696370883, 231.7741163313663151 33.9964923488039190, 231.8144687461388287 33.9927486901787077, 231.8555242505667024 33.9889258811518644, 231.8967616380454331 33.9850717164516354, 231.9384874592085453 33.9811573545970163, 231.9810031243091828 33.9771540024940606, 232.0239997222592194 33.9730898996244619, 232.0678388327741004 33.9689303372334663, 232.1123373517177697 33.9646917582200416, 232.1571892772059869 33.9604025762483772, 232.2028902909401040 33.9560149644208167, 232.2491821770346974 33.9515527435585938, 232.2960411962056355 33.9470175078809362, 232.3439306823368327 33.9423637057927863, 232.3925149926278095 33.9376227334373368, 232.4421795019375736 33.9327560903860643, 232.4923819961781533 33.9278156109878850, 232.5436698047475943 33.9227466787318050, 232.5951687842305660 33.9176343955933319, 232.6475716307096491 33.9124096239597819, 232.7012278930365596 33.9070362580221598, 232.7556828037685932 33.9015582139110379, 232.8111272810814398 33.8959551460956590, 232.8675924455159816 33.8902225111619586, 232.9251556044691256 33.8843509815862305, 232.9836292775250968 33.8783581195321943, 233.0432332674061513 33.8722199923502458, 233.1036814246760969 33.8659644314339374, 233.1655576137215462 33.8595295606769966, 233.2282972755570256 33.8529720149463031, 233.2926253692118621 33.8462144248317571, 233.3579653179138518 33.8393149568009335, 233.4238324437535823 33.8323232701533669, 233.4921199961581237 33.8250368578670901, 233.5612785481834237 33.8176174604834614, 233.6323604437994845 33.8099502308987709, 233.7049545857546491 33.8020762209202985, 233.8182991445546577 33.7896946458198784, 233.8076868009974589 33.7447711158304671, 233.7998795211175320 33.7148904495256616, 233.7932833621273119 33.6848666704869686, 233.7861879662788454 33.6548975267118138, 233.7790138732386254 33.6249371303082327, 233.7721258780049141 33.5949457573665811, 233.7653244276447140 33.5649451761957351, 233.7589504395879771 33.5348983219310384, 233.7517922485339454 33.5049370175201346, 233.7451099030573118 33.4749242024867826, 233.7380079968495465 33.4449572273965430, 233.7308913047606893 33.4150038906188911, 233.7242842861141980 33.3850066679223403, 233.7177523609356058 33.3550016102456084, 233.7105361718773793 33.3250710555783130, 233.7038713781764727 33.2950810138029354, 233.6970686629649947 33.2651062318509361, 233.6905337589382725 33.2351027782129762, 233.6840504442202189 33.2050940973791811, 233.6777241043450886 33.1750688063842745, 233.6714174242955551 33.1450417812508391, 233.6651265169321618 33.1149842339622964, 233.6589877929609713 33.0848829896515255, 233.6524321129587634 33.0548271749566851, 233.6459016739153753 33.0247690228650228, 233.6397274744219601 32.9946728445241177, 233.6329292366539221 32.9646443836585377, 233.6264198619547301 32.9345851795598108, 233.6202087451694069 32.9044942683736537, 233.6139880511333615 32.8744048430015070, 233.6079852678255975 32.8442924251869215, 233.6024480633732878 32.8141580578265177, 233.5966311951531225 32.7840805084876550, 233.5901811265881065 32.7540715696615052, 233.5840609929455809 32.7240276623760948, 233.5780234847293855 32.6939754071204050, 233.5723051528725591 32.6638894275744747, 233.5666017738128915 32.6338024224210770, 233.5607542214523278 32.6037314697343774, 233.5546837866806982 32.5736849918668483, 233.5486024506201943 32.5436402502741728, 233.5424177865809554 32.5135952203075078, 233.5365716068125153 32.4835032167910711, 233.5315060001448160 32.4533282705142625, 233.5261496479418497 32.4231850921035090, 233.5203742088707770 32.3930873794257081, 233.5147182819266618 32.3629775113514597, 233.5094845867136542 32.3328231673348014, 233.5039894605985467 32.3026974293673916, 233.4978335602601760 32.2726429029673483, 233.4931590406256134 32.2424309058476481, 233.4878027400856979 32.2122923883547898, 233.4822943077738842 32.1821707946306645, 233.4769428295691682 32.1520331688125083, 233.4715484852565339 32.1219008274845450, 233.4659832529781056 32.0917874105425440, 233.4604242299232908 32.0616740463839278, 233.4547057474827341 32.0315783749592171, 233.4493448635818140 32.0014453815873523, 233.4439538849541975 31.9713163426436822, 233.4388438489372675 31.9411582034324582, 233.4333516271450435 31.9110653070441082, 233.4279989231125114 31.8809809552748860, 233.4229566390458501 31.8508644672415961, 233.4183811248644531 31.8206993019833142, 233.4138877626305373 31.7905263247609824, 233.4092102827142980 31.7603737819017198, 233.4050516566460942 31.7301671582915539, 233.4001074317153552 31.7000447186518208, 233.3957145715358479 31.6698647915971421, 233.3913100753762819 31.6396870518093642, 233.3864447837853504 31.6095336382647432, 233.3812875214192673 31.5793879738905119, 233.3764952550197904 31.5492046024446289, 233.3713681256496670 31.5190575396906105, 233.3665069083577919 31.4888832848857305, 233.3615529342137052 31.4587197535848766, 233.3563206750544055 31.4285865290605066, 233.3514797003734316 31.3984129292956951, 233.3465577546590453 31.3682488232810641, 233.3417228713095142 31.3380764927870743, 233.3370904021178944 31.3078918587356796, 233.3327447691412999 31.2776856492184727, 233.3284034057362533 31.2474800412854812, 233.3238447530990811 31.2172983697557100, 233.3202001870982656 31.1870215346005537, 233.3161949179906856 31.1567837769810723, 233.3117460132445729 31.1265937910656625, 233.3074302664846300 31.0963908863597460, 233.3031004202551912 31.0661905619150076, 233.2993877463872536 31.0359264957759784, 233.2953127272744496 31.0057054347712580, 233.2898951298277552 30.9756300525318586, 233.2854622844924393 30.9454523392395160, 233.2811087260189993 30.9152674167444381, 233.2766787725826703 30.8850916312266328, 233.2723182338893366 30.8549096935436786, 233.2680625875142084 30.8247179031670910, 233.2636594360837989 30.7945427206847562, 233.2591073856077344 30.7643842796401081, 233.2546430265682602 30.7342178079628567, 233.2506548072817054 30.7039852299420275, 233.2467326449200016 30.6737304211930422, 233.2427735884617448 30.6434806792112653, 233.2385419917315517 30.6132606393829505, 233.2344263708046697 30.5830296838953224, 233.2299724550055089 30.5528352857997980, 233.2257801219477642 30.5226147735751212, 233.2217008351061622 30.4923836900467258, 233.2176536181539745 30.4621505031472743, 233.2137701089008033 30.4319014927329441, 233.2097164924721255 30.4016889943031359, 233.2057273903702423 30.3714876142136916, 233.2018315928332299 30.3412778047890157, 233.1982994816497126 30.3110314135098342, 233.1949660442566028 30.2807656745234013, 233.1909995460327423 30.2505672081963901, 233.1869329125315176 30.2203804896412329, 233.1830432862202258 30.1901766843428980, 233.1794294371081264 30.1599455462454706, 233.1757256558107088 30.1297251350849109, 233.1722016871892436 30.0994998764303112, 233.1687265873930528 30.0692827643050293, 233.1657971256008466 30.0390104336791062, 233.1620197155411915 30.0088276220406094, 233.1588110553900322 29.9785872276917402, 233.1558657451028012 29.9483210009432845, 233.1526520127786171 29.9180841251987211, 233.1489461530049425 29.8878997696919093, 233.1453943524933834 29.8577009226217811, 233.1419015804141281 29.8274974560065331, 233.1385470571378562 29.7972455511092846, 233.1353455350549098 29.7669455615295817, 233.1321205569724384 29.7366494892085207, 233.1286857503217504 29.7063766210424909, 233.1248502693014757 29.6761466884616709, 233.1219322346422018 29.6458233627627941, 233.1187887011243447 29.6155248850105153, 233.1158036471033483 29.5852115613275402, 233.1128189974455722 29.5548997434324079, 233.1096148239391823 29.5246121600670683, 233.1059421915823577 29.4943963291803932, 233.1029253621701969 29.4641350065372549, 233.1002381417609399 29.4338412716992366, 233.0969753054017701 29.4036085512195093, 233.0938295190734380 29.3733653616548978, 233.0913472163580593 29.3430553834513503, 233.0892058098987150 29.3127119349485170, 233.0863428536628135 29.2824445349018241, 233.0832116703717247 29.2522064239827806, 233.0797675612365651 29.2220021876052947, 233.0766708226278183 29.1917583918291292, 233.0740702319781690 29.1614600580752779, 233.0714565710503052 29.1311647753718894, 233.0690128690097254 29.1008537235290135, 233.0668902691572271 29.0705113857552107, 233.0645048567228059 29.0401978200036126, 233.0622308672101894 29.0098745532463980, 233.0598776027648569 28.9795611971523428, 233.0578674387814431 28.9492143655959779, 233.0557478222019085 28.9188805699689659, 233.0535026840542230 28.8885669116903081, 233.0508429036588041 28.8583027762556554, 233.0484008302832422 28.8280180911296142, 233.0460454447872962 28.7977263211071275, 233.0438808462369309 28.7674168095387550, 233.0413729393396807 28.7371443319295992, 233.0390306784818790 28.7068567067617089, 233.0369262675736479 28.6765465604866172, 233.0347470633701619 28.6462459426569609, 233.0329268350126029 28.6159104396724331, 233.0304011304856431 28.5856435995657741, 233.0285767800048120 28.5553016797995802, 233.0267613739302988 28.5249607573186239, 233.0251239162247430 28.4946035505017079, 233.0235861249787490 28.4642380888183837, 233.0216106034008021 28.4339193332019669, 233.0189545611982567 28.4036720750902134, 233.0154885602265438 28.3735094844721552, 233.0142983651934401 28.3431162820911595, 233.0278250723133340 28.3112211640409832, 233.0452282676277491 28.2789483187385642, 233.0538325274343094 28.2475942808530149, 233.0539975568602529 28.2171064726347396, 233.0513725666164362 28.1869063911917266, 233.0495940247801911 28.1566216920424530, 233.0476156283759224 28.1263594901667702, 233.0441012164610015 28.0962563986380012, 233.0341267619562586 28.0668153191363920, 233.0153669885792738 28.0382716562388197, 233.0004310857394785 28.0093374012700203, 232.9972907785160601 27.9791790793518445, 232.9993492557859440 27.9484712223743550, 232.9984005080535496 27.9180717344066807, 232.9974307125876010 27.8876765098116586, 232.9972130492358247 27.8572068668353161, 232.9974480176594227 27.8266933234033083, 232.9991589372485805 27.7960317666082872, 232.9989280134374212 27.7655700234398743, 232.9984242466584305 27.7351382270208582, 232.9981795284512316 27.7046822703976723, 232.9979878384327492 27.6742274580723340, 232.9973841036610906 27.6438208719064029, 232.9969627048609766 27.6133979690381288, 232.9956424441186300 27.5830686696756686, 232.9942467721440380 27.5527492409820631, 232.9928294278056455 27.5224342236380508, 232.9910051527021437 27.4921627558272910, 232.9892752252020500 27.4618839132446020, 232.9876407499817219 27.4315975974861637, 232.9860500535251049 27.4013090709267040, 232.9845431092235799 27.3710008489806249, 232.9832144523942645 27.3406640377758308, 232.9813211962325568 27.3103867100814384, 232.9796046601171327 27.2800936680540786, 232.9778668740795808 27.2498050024457292, 232.9760812623403865 27.2195234107069197, 232.9744936225158938 27.1892239957064312, 232.9725389188245686 27.1589640136283244, 232.9710993706607098 27.1286541056528847, 232.9695310658502763 27.0983595097531946, 232.9678740179837177 27.0681026007771948, 232.9664105876216240 27.0378534557890475, 232.9648174107140619 27.0076198078588838, 232.9633173341063355 26.9773791166742747, 232.9625444737612554 26.9470672981345558, 232.9609409653380112 26.9168418629002275, 232.9596090239890316 26.8865913871609727, 232.9583747341857531 26.8563334706206511, 232.9570418888882273 26.8260879392119449, 232.9556783045244401 26.7958479490301471, 232.9541208556610741 26.7656115503644898, 232.9529072543819552 26.7353254479201219, 232.9513372321579823 26.7050777308408733, 232.9496721067915814 26.6748420272618745, 232.9482697864153238 26.6445822619811459, 232.9469308519850870 26.6143185587787521, 232.9456308588750346 26.5840533948264905, 232.9445891873294840 26.5537646856055289, 232.9435705002171630 26.5234761549716360, 232.9424930684089077 26.4931960433853639, 232.9411883949197772 26.4629460272430315, 232.9404661357677355 26.4326443638835542, 232.9397077071035085 26.4023488673881417, 232.9389590229797022 26.3720549233583768, 232.9380771814587661 26.3417769121321328, 232.9371118552418238 26.3115098363031592, 232.9363055939249421 26.2812293227256468, 232.9349899869485796 26.2510025504793205, 232.9335253420537128 26.2207932922122922, 232.9325013463742948 26.1905423329594775, 232.9312666334037374 26.1603104013803893, 232.9304842317117732 26.1300312111249866, 232.9301915141380164 26.0997055104343616, 232.9294881720715580 26.0694236562425061, 232.9290727465349278 26.0391155705938253, 232.9284303149261461 26.0088329122040527, 232.9279035226248311 25.9785413248613892, 232.9273612165927716 25.9482539711808862, 232.9268538349265896 25.9179658022049715, 232.9262752018361766 25.8876874677902151, 232.9258886605539374 25.8574103205503185, 232.9254503185429996 25.8271578908256707, 232.9251078811091702 25.7968986263608180, 232.9246578931968656 25.7666529016120727, 232.9240220891967965 25.7364285482953861, 232.9236035390602524 25.7061852433478357, 232.9230685584527407 25.6759563790138827, 232.9227337276142293 25.6457103098244836, 232.9226746290123629 25.6154395052224721, 232.9151284100965995 25.5859193756642966, 232.8937666408189386 25.5577604985455196, 232.8940638254572661 25.5274256431740376, 232.8871864394730835 25.4978083491673111, 232.8887549686981799 25.4673523877788810, 232.8922447980336017 25.4367079618528003, 232.8868549805569899 25.4069505089107857, 232.8862070943299898 25.3767236846523225, 232.8896433829220882 25.3460933179365959, 232.8904085764630452 25.3157316467882083, 232.8749355209038185 25.2869872854491931, 232.8752451627683229 25.2566951708063385, 232.8833426366030608 25.2256500908747263, 232.8835253170702799 25.1953944684774207, 232.8791674520630863 25.1655927164424504, 232.8897864848736390 25.1343065993527439, 232.8853793269061612 25.1045158111557143, 232.8872412250227626 25.0741054813626967, 232.8902504012405075 25.0435843557223734, 232.8862819506680353 25.0137587009765561, 232.8849165371166805 24.9836776255639741, 232.8615444346234824 24.9557405574212190, 232.8678957260945594 24.9248252132857893, 232.8743003819388377 24.8939074623086256, 232.8845451260537516 24.8626121460513509, 232.8855114925712826 24.8322389783660178, 232.8777786943019805 24.8027302997633399, 232.8784494298064658 24.7723922672678611, 232.8786766284533769 24.7421011266518107, 232.8815821188912878 24.7115479150936572, 232.8784798199646957 24.6815922415318632, 232.8815210228855790 24.6510507831175936, 232.8869507733595299 24.6202941881330695, 232.8897516433328008 24.5898008393355489, 232.8918981621112039 24.5593753741429381, 232.8953447470361766 24.5288244473084802, 232.9021256321721580 24.4979467948482359, 232.9055803921938832 24.4674014151714516, 232.9256796376523369 24.4352113534178201, 232.9278143680417088 24.4048031511444989, 232.9273308331784165 24.3746574337605182, 232.9233851757292086 24.3448714448658983, 232.9184915904676814 24.3151952701589487, 232.9128735282994285 24.2855934651471159, 232.9070168457516559 24.2560179019932747, 232.8961245154026187 24.2269419337473373, 232.9056956381912471 24.1958493513260677, 232.9163992201185636 24.1646481367450328, 232.9148753749125831 24.1346574495094899, 232.9260392073335311 24.1034175400766486, 232.9206813332552315 24.0738120737350201, 232.9204495721024557 24.0437090839679222, 232.9242943937483687 24.0132123141866103, 232.9256437470648962 23.9829650936419547, 232.9266377200116835 23.9527562658711091, 232.9335016546866370 23.9219720544854724, 232.9350094751261224 23.8917194173821663, 232.9318311548631470 23.8619319937482217, 232.9368722189848881 23.8313379252621438, 232.9450679386290517 23.8004364540854993, 232.9487612036169821 23.7699821915590910, 232.9457539898387495 23.7401711441849308, 232.9427211904170463 23.7103463853456446, 232.9402080397393888 23.6804735786337801, 232.9433835896780352 23.6500442500705255, 232.9429844400121681 23.6199700523985001, 232.9448047522230922 23.5896808975073959, 232.9476776161833982 23.5592916672883526, 232.9482010012357307 23.5291369223763986, 232.9512697054896080 23.4987353646153103, 232.9482075711343327 23.4689398428672362, 232.9524304169726179 23.4384270363305625, 232.9546730816440743 23.4081077648677791, 232.9582883792438111 23.3776571360643324, 232.9647493345424039 23.3469304505496851, 232.9703738878391732 23.3162894618000038, 232.9749310818776564 23.2857568940812207, 232.9745359585149913 23.2557144437894792, 232.9767231067804687 23.2254218015470144, 232.9747120127887570 23.1955449257939854, 232.9822413993304906 23.1647348153342918, 232.9804333913460539 23.1348442843248563, 232.9799632302537020 23.1048251182840616, 232.9861015984569690 23.0741610276239371, 232.9875906071483769 23.0439567789152555, 232.9885163914815394 23.0138113509045752, 232.9880927479807724 22.9838018051451627, 232.9920786516129283 22.9533634401114597, 232.9956900448752890 22.9229654565282139, 232.9980286669976408 22.8926959143639905, 232.9994463255823121 22.8625202868843473, 233.0007273528797214 22.8323817678633567, 233.0026223772322567 22.8022057942484011, 233.0043541575535926 22.7720495280457556, 233.0056855084943663 22.7419361868120333, 233.0075168388990221 22.7117776143631644, 233.0086972640626470 22.6816864800318783, 233.0110141290699062 22.6514878823163421, 233.0150980296511989 22.6211202179953652, 233.0183630377297845 22.5908364989234265, 233.0205235277442171 22.5606646286184223, 233.0226990889820513 22.5304748350743687, 233.0250312227692291 22.5002543316308454, 233.0273417265109117 22.4700397096754436, 233.0294322534792286 22.4398503559635607, 233.0316537241797050 22.4096519869835191, 233.0341646708320695 22.3794291320634464, 233.0365342747201112 22.3492238899731959, 233.0390090295576613 22.3190121956477192, 233.0410423262773918 22.2888474231631264, 233.0431049504354633 22.2586836085089459, 233.0454588239587679 22.2284945391122264, 233.0478015507949863 22.1983097810625374, 233.0502410036448282 22.1681194492568139, 233.0528960638682747 22.1379119636236723, 233.0557407392532241 22.1076898814232550, 233.0583526795629439 22.0774943964448305, 233.0611965970119286 22.0472802075900702, 233.0637667924078755 22.0170966232015246, 233.0661707317356672 21.9869331635871532, 233.0688355155518821 21.9567482211745428, 233.0712133980820226 21.9266163988525697, 233.0735932642362229 21.8965084710525772, 233.0760567739937130 21.8663964169622957, 233.0786160068223012 21.8362790738185488, 233.0813521306658913 21.8061485618539130, 233.0841934460657967 21.7760118752912746, 233.0868186398116393 21.7459002817007843, 233.0896572715981847 21.7157720084171899, 233.0925606006185262 21.6856415363909711, 233.0953944803874833 21.6555219187505301, 233.0982658468537920 21.6253757162664222, 233.1010684296373654 21.5952146479776523, 233.1039565019003135 21.5650493241765950, 233.1070084941936784 21.5348721394971818, 233.1101013321710980 21.5046950639545003, 233.1128703125103243 21.4745535124936815, 233.1158241929650217 21.4443980967747834, 233.1188318357311005 21.4142415632226886, 233.1218563893511941 21.3840874972769690, 233.1246794786605676 21.3539570957466367, 233.1274225833886931 21.3238601080463503, 233.1306370619428208 21.2937419769091889, 233.1338110029608401 21.2636319987267903, 233.1368714757588236 21.2335372461871934, 233.1401888172863437 21.2034218385369968, 233.1433772706163268 21.1733231701487838, 233.1465315269799419 21.1432320716031548, 233.1496154961199068 21.1131520453783281, 233.1523256640593331 21.0831124742891163, 233.1550432763680760 21.0530764455185277, 233.1579828491568946 21.0230058062467613, 233.1607722023841802 20.9929374507901692, 233.1636624180470676 20.9628635552655247, 233.1666398146294057 20.9327854558762887, 233.1696517888767346 20.9027082544394602, 233.1726003364721009 20.8726414315882920, 233.1758702061451345 20.8425478178669259, 233.1788078856151856 20.8124905745848885, 233.1817470920860274 20.7824374565909338, 233.1847240764050753 20.7523849749798011, 233.1882571694646344 20.7222788476118502, 233.1922497393497622 20.6921286818578096, 233.1963717973547432 20.6619703873674538, 233.1999109853457526 20.6318727135351736, 233.2035406237867221 20.6017706851485762, 233.2070288687683330 20.5716866761621020, 233.2105921939143514 20.5415998140439520, 233.2140636677692385 20.5115262079037066, 233.2178119026467868 20.4814303279723475, 233.2217592402049036 20.4513196856889081, 233.2251909010724944 20.4212673943468950, 233.2282694104284246 20.3912575382026056, 233.2318419184239815 20.3612045154493515, 233.2355239631732502 20.3311453845283658, 233.2391586893154454 20.3010952640841786, 233.2428990778608977 20.2710394342439066, 233.2464567058851799 20.2410056660194080, 233.2499761034001153 20.2109800535650379, 233.2536732782447757 20.1809418254342638, 233.2573748161999561 20.1509076803071778, 233.2610258437933908 20.1208946526018622, 233.2648839717271301 20.0908774183957135, 233.2690707989333987 20.0608332119564174, 233.2729399482114445 20.0308241593004865, 233.2766399932764330 20.0008359799500361, 233.2812975167479976 19.9707604951296069, 233.2864835103322889 19.9406389605168357, 233.2910589909977830 19.9105807426328631, 233.2951517126284102 19.8805735518180278, 233.2994281961467209 19.8505534223365459, 233.3035672940376344 19.8205511747601868, 233.3079874496854131 19.7905266854675261, 233.3129269618572721 19.7604571404374916, 233.3212816261195712 19.7300649786178290, 233.3230339210745399 19.7003105135329868, 233.3250709695567195 19.6705333692279147, 233.3296297888962272 19.6405193531334774, 233.3340604185271729 19.6105224014149684, 233.3383183316778968 19.5805467749155291, 233.3428179007618439 19.5505528168765963, 233.3472901991913204 19.5205884333304382, 233.3519547731943362 19.4906315127633114, 233.3565130545534316 19.4606896820815081, 233.3611875776566933 19.4307416675757381, 233.3661894040619700 19.4007673213283738, 233.3703364722979643 19.3708796063483923, 233.3750997856715230 19.3409379714334904, 233.3796821891314153 19.3110185896687021, 233.3838727404156259 19.2811415854923034, 233.3885341449362727 19.2512246218168102, 233.3933864583176216 19.2212534982861172, 233.3986811268007102 19.1912063079851336, 233.4036949063699069 19.1611907724062220, 233.4090010487341829 19.1311522333228119, 233.4132186008963572 19.1012223437113988, 233.4123898127269854 19.0717780874003857, 233.4234938187712487 19.0412018332192972, 233.4281136087350319 19.0112482688797080, 233.4325499943371369 18.9813170712390935, 233.4385722855595304 18.9512397884117547, 233.4443472688414261 18.9211910404438655, 233.4496096001402066 18.8911960802090242, 233.4547716285619288 18.8612156352242870, 233.4583507146321608 18.8313907512366683, 233.4655539292224091 18.8012260954861965, 233.4711278176775693 18.7712214498370962, 233.4767412811398799 18.7412180638716350, 233.4825004788564229 18.7112058596042665, 233.4883578875892454 18.6811893699161473, 233.4930940637389085 18.6512844874408437, 233.4992980387236230 18.6212451930439151, 233.5048315554937517 18.5912746804041298, 233.5077083127482638 18.5615615247289476, 233.5090647555902592 18.5319976053133892, 233.5185189872614160 18.5016701736141833, 233.5255892488341942 18.4715741711933816, 233.5300607514989224 18.4417298953676472, 233.5355540632440920 18.4117937924144890, 233.5416644756876394 18.3818043137723670, 233.5436055658501573 18.3522152471283597, 233.5514883548236185 18.3220390661888750, 233.5588538183609160 18.2918895888480471, 233.5647531547830340 18.2618841625459112, 233.5705679155844336 18.2318918456861674, 233.5766138328914110 18.2018827384108697, 233.5826686372002996 18.1718779111117179, 233.5888785936488432 18.1418635244059807, 233.5951383721327943 18.1118495698595687, 233.6014674713914019 18.0818342119676174, 233.6076764094576390 18.0518354029397443, 233.6140209223674447 18.0218522835348871, 233.6204423275639783 17.9918892523867520, 233.6265487122046807 17.9619613307537271, 233.6313515417370752 17.9321620036408689, 233.6386754118331623 17.9021295475461137, 233.6451980358387175 17.8721782134278087, 233.6513777074440270 17.8422646488141012, 233.6535623902091743 17.8127339294621265, 233.6609506865578396 17.7827168172390664, 233.6699594117104652 17.7525520608942990, 233.6710216303398511 17.7231431656523597, 233.6718987092318116 17.6937567665132640, 233.6886100264510446 17.6628813678101864, 233.6960663227023360 17.6328849764936990, 233.7026278411701128 17.6029784898318944, 233.7090592952019676 17.5730897219913196, 233.7159774810301371 17.5431605027643300, 233.7217275105666374 17.5133469216293420, 233.7187734896178881 17.4843590860856359, 233.7270853483593100 17.4543148473689484, 233.7331808847967523 17.4244650559017700, 233.7435127694119501 17.3942028951404453, 233.7536136123764550 17.3639679699225233, 233.7604356213904566 17.3340473252823131, 233.7671770100476749 17.3041397118946207, 233.7740217614510243 17.2742278149319297, 233.7808503086502583 17.2443229050392830, 233.7874669746069003 17.2144434060500231, 233.7940569940029434 17.1845718878380751, 233.8008596200677118 17.1546858578329271, 233.8077378287036368 17.1248364577722185, 233.8147908320279384 17.0950124866516973, 233.8216472061116065 17.0652127325247385, 233.8287550488172997 17.0353950862871919, 233.8358236301641000 17.0055868895558753, 233.8429318876115133 16.9757807353721333, 233.8498250513236201 16.9460005561535851, 233.8567982136573846 16.9162186517835593, 233.8644027751852263 16.8863833032129627, 233.8717789030442304 16.8565752238198030, 233.8787743155451437 16.8267903345429772, 233.8864271812514630 16.7969322128191010, 233.8943020020596748 16.7670590848810228, 233.9020234295209946 16.7372061476229348, 233.9097388861926277 16.7073595931650090, 233.9174310488908759 16.6775210529157647, 233.9253368298226974 16.6476683527042297, 233.9331359103080672 16.6178315076893348, 233.9401620368684576 16.5880728789070986, 233.9480199084255219 16.5582422694894262, 233.9556240340307625 16.5284143707426274, 233.9629611951966979 16.4985917371493649, 233.9680858443129523 16.4689817308657247, 233.9697189392310577 16.4397036867625808, 233.9810825587126999 16.4095219192687374, 233.9908561410638583 16.3794945960977074, 233.9882558493688407 16.3506288802557087, 234.0070396851330088 16.3197717513132616, 234.0069713596252541 16.2906809733634645, 234.0202313686372975 16.2603515811764971, 234.0396206151058891 16.2294769327835162, 234.0450716390547257 16.1999297991625113, 234.0561919768812231 16.1698594103722293, 234.0658256080933484 16.1399339059125637, 234.0741862230366053 16.1101332895480844, 234.0828109349569672 16.0803141029273924, 234.0913423001479430 16.0505097118435671, 234.0998453011710581 16.0207140639358698, 234.1085331389406292 15.9909072930984113, 234.1171059035082749 15.9611173752930284, 234.1257060288378398 15.9313287300367410, 234.1339610710347756 15.9015761555191943, 234.1421311326385535 15.8718375959232336, 234.1504002194577367 15.8420959238434982, 234.1587546085733038 15.8123524373627653, 234.1674495379574523 15.7825834029317260, 234.1763947301172664 15.7527972553046585, 234.1849920604828981 15.7230496510434978, 234.1933783950207726 15.6933278489870016, 234.2016682323672399 15.6636212039726868, 234.2106661097371330 15.6338573919411701, 234.2195850300125812 15.6041094923900445, 234.2284696625345646 15.5743710696476931, 234.2372546655175825 15.5446481978355600, 234.2462970033934084 15.5149077482144495, 234.2553563453492700 15.4851720525691867, 234.2644515611109455 15.4554393745744552, 234.2736445746277525 15.4257039865255212, 234.2828900285930445 15.3959701114112644, 234.2920854371644168 15.3662472678846687, 234.3013275319602258 15.3365240160719942, 234.3104684925447430 15.3068141675627647, 234.3196567184559171 15.2771063205312547, 234.3288051980732121 15.2474085454701331, 234.3378564288254324 15.2177261763429605, 234.3470450329756432 15.1880375021932092, 234.3562524198230790 15.1583535186594478, 234.3654777340128135 15.1286743193465743, 234.3747378383685600 15.0989983562836674, 234.3840812970269099 15.0693211572941852, 234.3931289741021828 15.0396512747805424, 234.4024907287821406 15.0099336756868329, 234.4122604228975320 14.9801847782135766, 234.4219977290714780 14.9504452810051252, 234.4316158209413743 14.9207232126728560, 234.4409823334430598 14.8910307928157444, 234.4498350286750963 14.8613922148236419, 234.4587414390796880 14.8317550981146429, 234.4679675142334077 14.8020949297871400, 234.4770902761938487 14.7724507458019794, 234.4864736837242845 14.7428161287315600, 234.4957933007898987 14.7132196608638797, 234.5055218334094320 14.6835921627046986, 234.5149128953590321 14.6540024086710705, 234.5240841556149007 14.6244395506431832, 234.5338855759494550 14.5948253658854856, 234.5441277226521493 14.5651773496976791, 234.5546148319625672 14.5355135559399677, 234.5650071680218787 14.5058652497170009, 234.5754239649155579 14.4762214794163704, 234.5860298977280820 14.4465631054023937, 234.5967350007561834 14.4168986450669578, 234.6069521162467311 14.3872858480203902, 234.6171532254527108 14.3576813563410912, 234.6275466840538684 14.3280660629932619, 234.6379311549195563 14.2984584660047442, 234.6483279323177840 14.2688566256103382, 234.6586953208047248 14.2392643795011846, 234.6688702844757586 14.2096966780773784, 234.6792465114648394 14.1801174490024575, 234.6895268513892461 14.1505511408581963, 234.6998289448953585 14.1209871012067207, 234.7101500394396680 14.0914282330706779, 234.7207265989751477 14.0618529129046710, 234.7321276646646311 14.0322091287124575, 234.7421715987841822 14.0026964529921418, 234.7518848038956207 13.9732209508361471, 234.7623775574046192 13.9436811555426505, 234.7730116684240897 13.9141354451606745, 234.7836780932642000 13.8845938046600228, 234.7943396384986841 13.8550596462965832, 234.8051586487551958 13.8255181701178014, 234.8160814495535931 13.7959742975977431, 234.8270783532049961 13.7664307564641728, 234.8381481281385277 13.7368876812022247, 234.8493417347460195 13.7073404461621440, 234.8606864116887891 13.6777865960779792, 234.8720570722587695 13.6482375497503181, 234.8830833189578584 13.6187270373040761, 234.8942578953382849 13.5892102038194693, 234.9053801461334388 13.5596778327200553, 234.9167589090509409 13.5301032210258434, 234.9279630753756578 13.5005515901187945, 234.9394192259657075 13.4709841685230476, 234.9508887087120570 13.4414226749875336, 234.9626309708700660 13.4118435574707284, 234.9742477492846433 13.3822830146718665, 234.9858310012523930 13.3527327037391768, 234.9970791621787498 13.3232199972591054, 235.0084942258517913 13.2936993449303102, 235.0186419320547770 13.2643038493261933, 235.0288272435886654 13.2349149251491323, 235.0401198038483130 13.2054328062422517, 235.0532620142338374 13.1757903601525044, 235.0624271207734068 13.1465153770093117, 235.0713600064045750 13.1172684942957840, 235.0793940337581489 13.0881099968979413, 235.0890500815442010 13.0588118576902303, 235.1001302405501860 13.0293921653006581, 235.1114135822560343 12.9999613922397916, 235.1209243695386135 12.9707237606482515, 235.1309020897632820 12.9414756651344565, 235.1414756816763543 12.9121812018778321, 235.1521051678167282 12.8828891503746785, 235.1634486045849712 12.8535402164776222, 235.1748378334555696 12.8241946968538763, 235.1866932396247023 12.7948147508486176, 235.1962591085319900 12.7656485146804730, 235.2079865863655925 12.7362952189512431, 235.2197326745993564 12.7069478740712203, 235.2313225714797227 12.6776155785111495, 235.2423722895124456 12.6483331654411533, 235.2530634947058275 12.6190905340401454, 235.2639518184354870 12.5898377702198960, 235.2744025913662256 12.5606318600724816, 235.2867725902066240 12.5312613935276858, 235.2991023661358554 12.5019022719193309, 235.3116716233483317 12.4725294411014591, 235.3219926188672559 12.4433657659187435, 235.3334198864923508 12.4141106633753289, 235.3448295691033536 12.3848381641287659, 235.3590631815229415 12.3552954059736280, 235.3671572189190897 12.3263093688257310, 235.3791241623067663 12.2969845357516512, 235.3921032498335535 12.2675769255236897, 235.4040318790397635 12.2382708372973177, 235.4133898124759412 12.2092018441388799, 235.4233087209121322 12.1800902645324101, 235.4339080982001633 12.1509255317514953, 235.4452235714742301 12.1217045744836369, 235.4567443232773485 12.0924703557183673, 235.4687492488390603 12.0631982531233231, 235.4810288736117343 12.0339094861732487, 235.4933593765950093 12.0046240088453882, 235.5055131845066398 11.9753620783452011, 235.5183936065197088 11.9460434002548137, 235.5313914411344172 11.9167221953183660, 235.5445277549281400 11.8873966213114315, 235.5579758498066951 11.8580513221761432, 235.5708596306865275 11.8287640872622148, 235.5855568213401057 11.7993272975649965, 235.5997530464831868 11.7699461618724861, 235.6118792697535014 11.7407565433222043, 235.6222863798969911 11.7117271087384989, 235.6370065829994473 11.6823236091034719, 235.6501351704513638 11.6530691110666655, 235.6620788997951479 11.6239274594960431, 235.6746660023580375 11.5947368831364290, 235.6884231603173134 11.5654509339622074, 235.7004295445096318 11.5363277616853797, 235.7116587816107653 11.5072743978115017, 235.7235065834900070 11.4781679472531195, 235.7365096550367127 11.4489676032006464, 235.7509681343241823 11.4196470655213886, 235.7663406602954126 11.3902542183865609, 235.7777363714225771 11.3612199442138770, 235.7886739885623797 11.3322339874387712, 235.8008113264958183 11.3031504556224558, 235.8129270658486121 11.2740769145439081, 235.8254455463137731 11.2449760862040069, 235.8379734894969602 11.2159103138021727, 235.8515159915447725 11.1867900343017261, 235.8657944078324817 11.1576136472877927, 235.8797318094724460 11.1284757052297607, 235.8937716656566295 11.0993373101821966, 235.9083287918834912 11.0701621525963976, 235.9230551242763454 11.0409807942013884, 235.9376740007390936 11.0118174850440553, 235.9515272763334792 10.9827297851711894, 235.9638445602315073 10.9537849358168398, 235.9770623676747618 10.9247485593648044, 235.9907218608971675 10.8956618895965960, 236.0047319410548994 10.8665530900764598, 236.0183309333028205 10.8374886511489006, 236.0323861690052070 10.8083929297519710, 236.0537151650576106 10.7647439316584066, 235.8067955133563487 10.7864349997890709, 235.6404746257549050 10.8009251269224613, 235.4886934161563090 10.8140812538425877, 235.3440743681633194 10.8265506526397672, 235.2013541677872581 10.8387871303979448, 235.0605785760558604 10.8507895528866261, 234.9266644391592536 10.8621511165544540, 234.7983134326682091 10.8729887160327756, 234.6742684848876479 10.8834132357187077, 234.5539738435558093 10.8934756928844845, 234.4326844057642347 10.9035680020157386, 234.3062264801246215 10.9140277809663164, 234.1842183967322342 10.9240715931274739, 234.0687460570583767 10.9335373293069207, 233.9561439769059348 10.9427259417912808, 233.8474210956631509 10.9515604135292577, 233.7435151522079764 10.9599707574291010, 233.6385624025285779 10.9684248104055708, 233.5358140067685326 10.9766660933000004, 233.4407131631531342 10.9842712723458362, 233.3422237141446089 10.9921074822156886, 233.2513957968607770 10.9993144684109971, 233.1514470230774236 11.0071956760767709, 233.0568672341268268 11.0146280042103246, 232.9714593141207217 11.0213255319050045, 232.8803341230172919 11.0284323244548599, 232.7943082344645518 11.0351214682081213, 232.7094524258487809 11.0416948896581566, 232.6269891539108698 11.0480614832231261, 232.5469229652644003 11.0542229776369396, 232.4651981313369902 11.0604848215878366, 232.3872682244125656 11.0664391550579264, 232.3089820002455212 11.0723973916104050, 232.2344266808472071 11.0780568263891706, 232.1612777882611454 11.0835918116322976, 232.0879579900140470 11.0891193379889383, 232.0165771813888114 11.0944847829273883, 231.9444953164244794 11.0998822668698729, 231.8732154220784309 11.1052019606563253, 231.8057772059842137 11.1102241836769355, 231.7386284223711641 11.1152083218847366, 231.6726527935735476 11.1200909547501485, 231.6064561948248581 11.1249729598940004, 231.5413069011224252 11.1297634611436838, 231.4780838222075090 11.1344005203999021, 231.4150219500249648 11.1390109034253264, 231.3534789037249482 11.1434985250687806, 231.2922763752978028 11.1479476252960712, 231.2321986804804794 11.1523031971319266, 231.1727759778428322 11.1565989553883824, 231.1144830584675844 11.1608020872514171, 231.0567419751282898 11.1649536385302941, 231.0002949603130560 11.1690023089595805, 230.9442330255996296 11.1730119569343600, 230.8887529573797224 11.1769692032438481, 230.8340953656557133 11.1808578017260594, 230.7801047938849592 11.1846889342734332, 230.7267933250105045 11.1884621644695219, 230.6741394301091646 11.1921793597281063, 230.6222024977036256 11.1958368476612140, 230.5710284673361343 11.1994319110143241, 230.5203688901636383 11.2029818304628126, 230.4702850162541097 11.2064827482238183, 230.4211332149626514 11.2099109379551578, 230.3722347960806474 11.2133125718895510, 230.3238995148835784 11.2166669987468861, 230.2759727552659399 11.2199848672525260, 230.2288337046632876 11.2232410798017348, 230.1821784107610824 11.2264562859122670, 230.1360978920992579 11.2296246903222858, 230.0904502464934467 11.2327559867974180, 230.0451126661331500 11.2358585089279366, 230.0005121694860009 11.2389042679665501, 229.9563201538430803 11.2419152341142503, 229.9126038169200683 11.2448872011781784, 229.8693914420420299 11.2478185506001704, 229.8266141936523184 11.2507140176866258, 229.7844926752367201 11.2535594487218447, 229.7426279584758220 11.2563810618782671, 229.7011060076216040 11.2591734075647292, 229.6601354388773188 11.2619231614147282, 229.6197463420439817 11.2646286372140789, 229.5797488137789912 11.2673023162465977, 229.5399124326933418 11.2699591633018521, 229.5003744155729066 11.2725904639326817, 229.4613780020150102 11.2751808122651145, 229.4229479289658684 11.2777288707496943, 229.3846678777049419 11.2802613604144639, 229.3465203971843209 11.2827794526095353, 229.3092627460586925 11.2852352682155690, 229.2721541795518476 11.2876759727222673, 229.2355028971691127 11.2900822055293411, 229.1990236077021166 11.2924720971991803, 229.1627789235925832 11.2948417900818434, 229.1268004674420808 11.2971894009668805, 229.0910977852267933 11.2995144425208256, 229.0558429789198556 11.3018062999761035, 229.0210984390745352 11.3040612741786077, 228.9866394069139233 11.3062935182293298, 228.9523786369052516 11.3085085479037968, 228.9184628476472483 11.3106973739286509, 228.8847576778029236 11.3128684166009119, 228.8514037966496630 11.3150131009844515, 228.8184344402530144 11.3171295215195773, 228.7856962146676665 11.3192272249858679, 228.7530968391201611 11.3213119416410635, 228.7207523182538296 11.3233766438682917, 228.6886580791888548 11.3254217054343105, 228.6568808000469062 11.3274431670293048, 228.6255699416117295 11.3294320811030449, 228.5943557727715074 11.3314109976706128, 228.5633199203958270 11.3333750202067769, 228.5325366678410148 11.3353197346958243, 228.5019329259168614 11.3372496289070153, 228.4715394680731890 11.3391629188288814, 228.4413945509302266 11.3410573865418574, 228.4114629408679491 11.3429352267224637, 228.3817510016924075 11.3447961341414043, 228.3522475214008693 11.3466408530271394, 228.3230615139313500 11.3484629748790748, 228.2940740736263194 11.3502696640891187, 228.2653336387764398 11.3520581199518453, 228.2367430860684010 11.3538341663080260, 228.2082916103083505 11.3555984904766376, 228.1800368130793117 11.3573477475009099, 228.1520392237875967 11.3590784464209307, 228.1243947354929844 11.3607850493464291, 228.0969443603398190 11.3624769794781795, 228.0696393456295539 11.3641571482644679, 228.0424929933010674 11.3658248267683515, 228.0154106641673764 11.3674855738926084, 227.9885578563481374 11.3691297953353825, 227.9618650794204200 11.3707615940505633, 227.9353348111912680 11.3723808773608113, 227.9089933044639054 11.3739861801390099, 227.8828228745905733 11.3755785815541977, 227.8568634996865114 11.3771558345525552, 227.8309964239465728 11.3787248265649676, 227.8053094676684509 11.3802805503758524, 227.7797848238544418 11.3818240807472453, 227.7544332388526129 11.3833548536377336, 227.7292690741705314 11.3848721031830813, 227.7042771343951415 11.3863767513912375, 227.6794424865351800 11.3878696987312100, 227.6547547108986294 11.3893515833046468, 227.6302153125810435 11.3908223637586765, 227.6058446822487724 11.3922809322129357, 227.5815837284553993 11.3937306712760531, 227.5574768187678387 11.3951691152893524, 227.5335303503320290 11.3965959501297025, 227.5097275399109833 11.3980121642247596, 227.4860553007757460 11.3994185320559378, 227.4625029322769194 11.4008156893180974, 227.4390700032307961 11.4022036943794731, 227.4157514915798401 11.4035828609687258, 227.3925662525225562 11.4049521734577617, 227.3695676411404918 11.4063087093438291, 227.3466880305276732 11.4076562680175844, 227.3239817936694749 11.4089918766877290, 227.3013618133047657 11.4103203927839978, 227.2788626998101904 11.4116399330742109, 227.2564905837951699 11.4129501940545577, 227.2341471861246589 11.4142566063190909, 227.2119503831800671 11.4155527167828144, 227.1898755316235565 11.4168399144063564, 227.1679212759821098 11.4181183068057379, 227.1461045130937464 11.4193870060475948, 227.1244248889419168 11.4206460692728164, 227.1028554367262871 11.4218969988970116, 227.0813921445934511 11.4231400422407940, 227.0600099683261135 11.4243765834220152, 227.0387800565269458 11.4256027995307967, 227.0176858866700798 11.4268196232913724, 226.9967364182923575 11.4280266090250535, 226.9758565799991175 11.4292278308048303, 226.9550385935661438 11.4304237238046849, 226.9342329016709527 11.4316169579053124, 226.9135052379866977 11.4328040202277510, 226.8929749480163025 11.4339785612803233, 226.8725374557904217 11.4351462062810540, 226.8522123581976189 11.4363059371368561, 226.8319968195319518 11.4374579339901992, 226.8118864201212830 11.4386024598112925, 226.7918595656044261 11.4397406845203573, 226.7719343835058226 11.4408716721278054, 226.7520928931478750 11.4419963969853402, 226.7323585007384281 11.4431136486025657, 226.7126918304146841 11.4442255234732126, 226.6930802682913395 11.4453327000192484, 226.6735784057233900 11.4464323335892999, 226.6541678320585618 11.4475254147592285, 226.6348499723003727 11.4486118924843705, 226.6156086420497218 11.4496926332811118, 226.5964513089176933 11.4507672681177546, 226.5773802830670718 11.4518356983188578, 226.5583938982732946 11.4528980320229987, 226.5394514986686545 11.4539563930335184, 226.5205720112754193 11.4550098145010253, 226.5017744116908602 11.4560573339612208, 226.4830830479979795 11.4570977194829009, 226.4644630477073406 11.4581327889146145, 226.4458929607677931 11.4591636593943669, 226.4273420018058687 11.4601919179165357, 226.4089327375767766 11.4612113075361997, 226.3905321797895738 11.4622286455691889, 226.3721760724194496 11.4632421133368112, 226.3540415653064031 11.4642427211329760, 226.3361333516311902 11.4652302892907549, 226.3181669859138481 11.4662192771337264, 226.3002739486506414 11.4672030229303132, 226.2824320913041731 11.4681826620260043, 226.2646422367273829 11.4691581650756707, 226.2469095834710231 11.4701292830936108, 226.2292344049313897 11.4710960160787430, 226.2116353879809196 11.4720574419513870, 226.1941018513785480 11.4730141135445951, 226.1766306716312727 11.4739662026907236, 226.1592231105851738 11.4749136616605600, 226.1418925461004221 11.4758558407877249, 226.1246140672749334 11.4767939954809481, 226.1074024905080080 11.4777274041137769, 226.0902695214729761 11.4786555042624894, 226.0731674626638892 11.4795806696773699, 226.0561148944824197 11.4805019915790982, 226.0391203976545000 11.4814190596774068, 226.0221853383609698 11.4823318209273602, 226.0053302814410472 11.4832392822302278, 225.9885536989861805 11.4841415383496983, 225.9718003975521015 11.4850413028381215, 225.9550662527160227 11.4859387811263254, 225.9383869128336073 11.4868322431797356, 225.9217536701517588 11.4877221247833017, 225.9051656781826978 11.4886084777220923, 225.8886411839913251 11.4894904303538077, 225.8721818201436236 11.4903679195340356, 225.8557774564196166 11.4912414492684487, 225.8394241488462342 11.4921112224597479, 225.8231345766302809 11.4929766430547744, 225.8068834000255549 11.4938389401884038, 225.7906841315510462 11.4946974768467634, 225.7745264906764078 11.4955527558965187, 225.7584156584575226 11.4964045403774602, 225.7423465946611998 11.4972530808697719, 225.7263306551080575 11.4980978487034342, 225.7103637501312221 11.4989390503598727, 225.6944403535995320 11.4997769586268870, 225.6785731333571334 11.5006109868028794, 225.6627606321937378 11.5014412173606519, 225.6469855377227418 11.5022684764026693, 225.6312478555471444 11.5030927722663758, 225.6155505187072094 11.5039139764720328, 225.5999034371527046 11.5047316362642924, 225.5843036923893692 11.5055458998858136, 225.5687372937127293 11.5063574287637636, 225.5532030184863004 11.5071662870658145, 225.5377227249349801 11.5079714709681848, 225.5222898787807537 11.5087732956897408, 225.5069090090448469 11.5095715644164081, 225.4915549235061292 11.5103674479623592, 225.4762447625155630 11.5111601660448795, 225.4609749326394876 11.5119498938921492, 225.4457365038286696 11.5127370489375540, 225.4305250723075460 11.5135218388493605, 225.4153505895338014 11.5143038171213341, 225.4002092546284359 11.5150831649119425, 225.3851016085638435 11.5158598654166937, 225.3700330195549668 11.5166336842014907, 225.3550142447406586 11.5174041464428090, 225.3400350352184205 11.5181717255856064, 225.3250842761325714 11.5189369296321988, 225.3101705090110443 11.5196993830200629, 225.2952945149411903 11.5204590600189807, 225.2804449879828610 11.5212164731226441, 225.2656236019600158 11.5219715538163427, 225.2508347977898495 11.5227241118038215, 225.2360836991653912 11.5234739286072809, 225.2213701223724058 11.5242210218960714, 225.2066922232504851 11.5249654822953591, 225.1920523314320235 11.5257072167190060, 225.1774439551024329 11.5264465188783927, 225.1628688639239613 11.5271833193508293, 225.1483231609231552 11.5279177960268999, 225.1338080113100091 11.5286499054819789, 225.1193156868255869 11.5293799895936093, 225.1048406914377722 11.5301082903483714, 225.0903927203169417 11.5308343935948869, 225.0759731997245296 11.5315582445592355, 225.0615726061136002 11.5322802576213679, 225.0471948914249083 11.5330002677360355, 225.0328448252998612 11.5337180770247567, 225.0185250472492839 11.5344335803454925, 225.0042336758090187 11.5351468651000317, 224.9899666840133534 11.5358581082563951, 224.9757293128520246 11.5365670952889197, 224.9615188349451955 11.5372739482831079, 224.9473343603615376 11.5379787112424008, 224.9331867189993659 11.5386809398550945, 224.9190651590855623 11.5393810912804238, 224.9049589851288147 11.5400796146826714, 224.8908763596490132 11.5407761760249468, 224.8768203267520391 11.5414706560850586, 224.8627911626610114 11.5421630507503536, 224.8487873231403000 11.5428534304463373, 224.8348025935591181 11.5435420547040746, 224.8208432662326004 11.5442286728549455, 224.8069064464881137 11.5449134088086396, 224.7929952890946197 11.5455961415900141, 224.7790961745715776 11.5462774242074797, 224.7652157298564077 11.5469569934464271, 224.7513584997161615 11.5476346729728849, 224.7375268209599710 11.5483103768095621, 224.7237220902749186 11.5489840576780978, 224.7099413765578788 11.5496558393060589, 224.6961637810833281 11.5503265461398446, 224.6824171483842463 11.5509950911857580, 224.6686890557816412 11.5516619670139367, 224.6549772382032870 11.5523272659126715, 224.6412812909752574 11.5529910072087549, 224.6276091034430920 11.5536528929961140, 224.6139594562434354 11.5543129777076068, 224.6003182497858006 11.5549718025661718, 224.5867005368061768 11.5556288004452110, 224.5731010661888547 11.5562841764879352, 224.5595318451174194 11.5569374888469927, 224.5459817047643298 11.5575891644451509, 224.5324427190798815 11.5582395019069519, 224.5189143401576359 11.5588885230225600, 224.5054022183505253 11.5595360233582749, 224.4919123846902949 11.5601817896909829, 224.4784375362918922 11.5608260941027599, 224.4649757674625334 11.5614690093643855, 224.4515271517104793 11.5621105363191763, 224.4380954082653545 11.5627505474210537, 224.4246791510040566 11.5633890977002594, 224.4112755960885295 11.5640262896197967, 224.3978846737749677 11.5646621293277523, 224.3845066428580992 11.5652966117857297, 224.3711457528072799 11.5659295968898910, 224.3577977362114098 11.5665612362847892, 224.3444652819509599 11.5671914448426509, 224.3311485458355321 11.5678202246618813, 224.3178463670823248 11.5684476215481595, 224.3045557510947106 11.5690737397450327, 224.2912636805589273 11.5696990018417161, 224.2779812886722084 11.5703230455082942, 224.2647169075775651 11.5709456114698224, 224.2514653724536799 11.5715668719248708, 224.2382246445113481 11.5721868961343297, 224.2249954647936079 11.5728056663857863, 224.2117774258863392 11.5734232007857347, 224.1985677641190193 11.5740395865862666, 224.1853739310522826 11.5746546100326597, 224.1721921301367502 11.5752683925175521, 224.1590180429048473 11.5758810639248129, 224.1458517540414732 11.5764926247077806, 224.1326993443369702 11.5771029132241008, 224.1195552562867306 11.5777120902351882, 224.1064199000637984 11.5783201500287358, 224.0932922280787238 11.5789271253157189, 224.0801718772106028 11.5795330298010271, 224.0670575303311978 11.5801378996871716, 224.0539473086338944 11.5807417811292463, 224.0408440714013807 11.5813446074145894, 224.0277532395568016 11.5819462641689093, 224.0146726415863156 11.5825468155354745, 224.0016005777064834 11.5831463107815384, 223.9885357303068645 11.5837447873712911, 223.9754767473346249 11.5843422797721338, 223.9624200726210574 11.5849388562089111, 223.9493664901763452 11.5855344995887286, 223.9363221822940204 11.5861291150833914, 223.9232837412836545 11.5867227707854603, 223.9102514687331791 11.5873154735646064, 223.8972278339570039 11.5879072106724461, 223.8842074228040815 11.5884980596409761, 223.8711897945744056 11.5890880278296695, 223.8581768384303530 11.5896771077336140, 223.8451691054746391 11.5902653131262241, 223.8321650096247595 11.5908526677192825, 223.8191624724294684 11.5914391819224125, 223.8061618009817266 11.5920248568798314, 223.7931629563942124 11.5926096948298962, 223.7801640483884000 11.5931936738872050, 223.7671670080405022 11.5937768052707160, 223.7541730621465206 11.5943591186183301, 223.7411823205447945 11.5949406428819604, 223.7281945822350622 11.5955214095179251, 223.7152092203544385 11.5961014400467270, 223.7022255713048651 11.5966807498982440, 223.6892422590746605 11.5972592901497720, 223.6762589726454848 11.5978370356977791, 223.6632763821540379 11.5984140565029268, 223.6502941596612857 11.5989903554735516, 223.6373122485578335 11.5995659928018569, 223.6243300457994962 11.6001409101370623, 223.6113474183802055 11.6007150945083968, 223.5983643014758400 11.6012885646784660, 223.5853804742061470 11.6018613807905879, 223.5723949789524738 11.6024337740613035, 223.5594084415180305 11.6030053638277568, 223.5464202437128733 11.6035763342790617, 223.5334298265300106 11.6041467476564453, 223.5204368671151371 11.6047166055491324, 223.5074413311778017 11.6052858741608773, 223.4944432982260878 11.6058545207539758, 223.4814424785570282 11.6064225703277071, 223.4684383277615893 11.6069900726994231, 223.4554303426207014 11.6075570640144345, 223.4424179562216750 11.6081235823802746, 223.4294005333650546 11.6086896685705661, 223.4163767564448335 11.6092554251278521, 223.4033493491633067 11.6098205677991118, 223.3903182963025813 11.6103850983762644, 223.3772834961584977 11.6109490258485373, 223.3642450371687289 11.6115123420402657, 223.3512033206642116 11.6120750138094984, 223.3381552833168939 11.6126372900905022, 223.3251009602240629 11.6131991535604477, 223.3120397912722694 11.6137606354716958, 223.2989722102144583 11.6143216904755153, 223.2858985034930868 11.6148822884616791, 223.2728171532845636 11.6154425337012182, 223.2597285678833714 11.6160023858956460, 223.2466317184563422 11.6165619095860251, 223.2335277664742250 11.6171210135472585, 223.2204169764052324 11.6176796739022148, 223.2072988293887192 11.6182379214719873, 223.1941722853877934 11.6187958206584696, 223.1810361052811231 11.6193534462392343, 223.1678913125285533 11.6199107220438496, 223.1547381380195532 11.6204676270151737, 223.1415754377214853 11.6210242292760242, 223.1284015147909372 11.6215806294669530, 223.1152151257165031 11.6221368962333358, 223.1020209030151591 11.6226927309393666, 223.0888180899143265 11.6232481781277510, 223.0756052319343894 11.6238033234461131, 223.0623811454720169 11.6243582333811322, 223.0491451294242040 11.6249129434946941, 223.0358968024115143 11.6254674694465869, 223.0226367869014155 11.6260217673261028, 223.0093615337405595 11.6265760397115301, 222.9960678207878289 11.6271304645774922, 222.9827655838388409 11.6276844535504598, 222.9694554206592443 11.6282379715212905, 222.9561342545880791 11.6287911941992892, 222.9427998983100281 11.6293442422904576, 222.9294510268497618 11.6298971849420312, 222.9160884180228663 11.6304499718435022, 222.9027074603658320 11.6310028545879938, 222.8893176033846828 11.6315552994956750, 222.8759211426458364 11.6321071794923245, 222.8625124070450170 11.6326588071240860, 222.8490832134943105 11.6332106252390091, 222.8356348319159679 11.6337625545310122, 222.8221730868960435 11.6343142716203776, 222.8086998368628429 11.6348656728460060, 222.7952032410204879 11.6354173891255126, 222.7816844858264176 11.6359693461022538, 222.7681514532162907 11.6365211163933093, 222.7546094596874582 11.6370724158920975, 222.7410496054532985 11.6376237118726813, 222.7274689117784021 11.6381751538626439, 222.7138741945792617 11.6387263791939652, 222.7002655263075610 11.6392773809061207, 222.6866375324842124 11.6398284332340332, 222.6729866912269813 11.6403797107135603, 222.6593141329908860 11.6409311470154773, 222.6456207319734517 11.6414826900451711, 222.6319141538503459 11.6420339437049929, 222.6181898888893045 11.6425851339993027, 222.6044497077721189 11.6431361669500060, 222.5906859946134375 11.6436874213117303, 222.5768997746839943 11.6442388379762196, 222.5630916264516372 11.6447903810373035, 222.5492639055905215 11.6453419268843490, 222.5354268513513034 11.6458929634969444, 222.5215672763436032 11.6464441414374580, 222.5076782329797993 11.6469957955481807, 222.4937638625373211 11.6475477129612344, 222.4798292363327619 11.6480996383395290, 222.4658732608350817 11.6486516197575565, 222.4519005455341585 11.6492034280487822, 222.4379138599454677 11.6497549259658317, 222.4239108831781380 11.6503062232925103, 222.4098822394056754 11.6508577672794029, 222.3958278149365810 11.6514095559922666, 222.3817501135733607 11.6519614625816583, 222.3676471868176634 11.6525135736721523, 222.3535187113662914 11.6530658977189141, 222.3393601721830919 11.6536186413768181, 222.3251663416662041 11.6541720424480655, 222.3109466623485844 11.6547256460647457, 222.2967040816845383 11.6552793072737035, 222.2824345096863681 11.6558332118137287, 222.2681376654342955 11.6563873656892145, 222.2537934125679442 11.6569426977978008, 222.2394296278611137 11.6574979009509079, 222.2250456168251276 11.6580530033632179, 222.2106332312139614 11.6586083764543069, 222.1961901634210790 11.6591641190119280, 222.1817259895384495 11.6597197839798312, 222.1672323459239919 11.6602757492673099, 222.1527060469091452 11.6608321525715102, 222.1381498752822665 11.6613888587151155, 222.1235645886079055 11.6619458257867166, 222.1089488152713898 11.6625031085844704, 222.0943054474924168 11.6630605689785138, 222.0796369850662870 11.6636180879175431, 222.0649326370137260 11.6641761438836653, 222.0501916741791320 11.6647347600561329, 222.0354200415976607 11.6652936614482048, 222.0206255050637481 11.6658524948229037, 222.0058055009189957 11.6664113692121720, 221.9909317003400986 11.6669715336748201, 221.9760187813593575 11.6675323245008133, 221.9610674740678178 11.6680936993382627, 221.9460834295299492 11.6686553999180251, 221.9310575638693024 11.6692178165951557, 221.9159984711464233 11.6697805626031830, 221.9009259266182426 11.6703427671831381, 221.8858296896012519 11.6709048744380706, 221.8706995944909295 11.6714673207546262, 221.8555326260521667 11.6720302285181958, 221.8403304885907517 11.6725935149842535, 221.8250972499780858 11.6731569963145727, 221.8098195614849146 11.6737212391111793, 221.7944889260287198 11.6742865963530384, 221.7791202134376647 11.6748524179258037, 221.7637180402751653 11.6754184975181392, 221.7482700456498321 11.6759853535227798, 221.7327669514012030 11.6765533683532627, 221.7172115229149085 11.6771224104258984, 221.7016211571622364 11.6776917309401540, 221.6860028019623599 11.6782610287884872, 221.6703447482998399 11.6788307904525137, 221.6546244431601451 11.6794019527549153, 221.6388611839099951 11.6799736915289696, 221.6230487052656883 11.6805462579599411, 221.6071946734351457 11.6811193203291595, 221.5913075585570766 11.6816925165768879, 221.5753864703937950 11.6822658761466514, 221.5594131535227973 11.6828401465026843, 221.5433904492085446 11.6834151972955738, 221.5273308964312662 11.6839905000419026, 221.5112244756874702 11.6845664577698898, 221.4950649900496273 11.6851433129840192, 221.4788646116655002 11.6857205548552265, 221.4626020103548569 11.6862990436845706, 221.4462705120642738 11.6868790352296799, 221.4298859924444685 11.6874598673674459, 221.4134506856227631 11.6880414365500922, 221.3969754781630286 11.6886232905391001, 221.3804605137580950 11.6892054142711928, 221.3638996850384046 11.6897880441023982, 221.3472772159424551 11.6903718019422271, 221.3305813530331818 11.6909571427403947, 221.3137711140890644 11.6915456840148906, 221.2969116219956618 11.6921348014644693, 221.2800176036289201 11.6927238980664399, 221.2630934336351345 11.6933127927512874, 221.2461192125688001 11.6939022660947209, 221.2290863538791825 11.6944926448374780, 221.2119945040117273 11.6950839284474686, 221.1948675705588698 11.6956751636056868, 221.1776935519540359 11.6962668126450460, 221.1604303534508631 11.6968605094593148, 221.1430823375198713 11.6974560609985367, 221.1256729793842908 11.6980525325018565, 221.1082343240076113 11.6986486654835566, 221.0907777951840387 11.6992440115853711, 221.0732731529905379 11.6998397354871173, 221.0556760649134560 11.7004375334853155, 221.0379809653511245 11.7010375956553752, 221.0201910780052401 11.7016397730643664, 221.0023326505245791 11.7022430374960269, 220.9844141227260934 11.7028470498581800, 220.9664267865848046 11.7034521267778491, 220.9483618371737066 11.7040585853194052, 220.9302181846813085 11.7046664470968480, 220.9120117963100540 11.7052750889533517, 220.8937461626249217 11.7058843638380630, 220.8754296372306953 11.7064939431866843, 220.8570353831397597 11.7071048211080768, 220.8385387414590184 11.7077179002450666, 220.8199419597744964 11.7083330701137101, 220.8012542966671958 11.7089499601075566, 220.7824976140121294 11.7095677351636258, 220.7636932618528647 11.7101855873258316, 220.7448115762643397 11.7108046009476379, 220.7258449069571213 11.7114250382026324, 220.7067902066008855 11.7120469892192514, 220.6876435492166593 11.7126705751678752, 220.6684018412074693 11.7132958852828502, 220.6490775002795601 11.7139224419230299, 220.6296751617481959 11.7145500551708484, 220.6101884901048891 11.7151789348560165, 220.5906226553490512 11.7158088720504860, 220.5709709286415716 11.7164400891991374, 220.5512576667543385 11.7170716871744123, 220.5314614383958087 11.7177044199496514, 220.5115590022694505 11.7183390981714997, 220.4915452243125742 11.7189758769615491, 220.4714307799496567 11.7196143463289246, 220.4512468588935121 11.7202533715732216, 220.4309992066251311 11.7208927312610225, 220.4106498399640373 11.7215337511258344, 220.3901880983314356 11.7221767796032985, 220.3696269742773666 11.7228213298105270, 220.3489604038595360 11.7234675875962715, 220.3281690552250609 11.7241162000845627, 220.3072756756521926 11.7247663403802900, 220.2862824116052138 11.7254179062594375, 220.2651764715898821 11.7260713139578225, 220.2439627765912178 11.7267263625395888, 220.2226597862525637 11.7273823863475251, 220.2012604090778041 11.7280396048920039, 220.1797602368997104 11.7286981429012638, 220.1581417345539080 11.7293585718169044, 220.1364090861300156 11.7300207161521133, 220.1145235049643532 11.7306858616742744, 220.0924773395380214 11.7313542240955595, 220.0703026463924346 11.7320246749398329, 220.0480152578872719 11.7326966446454506, 220.0256193313570066 11.7333699618091085, 220.0031393234807240 11.7340437771874129, 219.9805459909590581 11.7347190432092177, 219.9578262375317195 11.7353961632534389, 219.9350228461180166 11.7360736819629636, 219.9120955538532485 11.7367529071512759, 219.8890352094778962 11.7374341046332820, 219.8658230573190906 11.7381178519633629, 219.8424378550888889 11.7388048002984231, 219.8189420393960916 11.7394928593078127, 219.7954051231398012 11.7401797339112797, 219.7717126788431301 11.7408691262396143, 219.7478364883703819 11.7415619025074314, 219.7238247217930223 11.7422564541995786, 219.6876080273489720 11.7432997520176645, 219.6987523783379856 11.7853029348258183, 219.7061791771063213 11.8133127052587561, 219.7135986549952236 11.8413287509520497, 219.7210947404886099 11.8693483800486010, 219.7285881728001016 11.8973741241781905, 219.7359476924907540 11.9254261184903640, 219.7433492070103682 11.9534995743589398, 219.7507477436034549 11.9815790420371542, 219.7579850993488151 12.0096695496526920, 219.7652250045894959 12.0377658721436855, 219.7725553247495327 12.0658652068473007, 219.7800022085723413 12.0939667193786491, 219.7873408945879703 12.1220775512080277, 219.7950743482600728 12.1501817176683744, 219.8021390085208395 12.1783129843083415, 219.8093731982236250 12.2064422366432552, 219.8167053718840123 12.2345716176753569, 219.8241449129442060 12.2627034586213259, 219.8313191007843272 12.2908495551188075, 219.8387108569059478 12.3189946084991604, 219.8460894153435277 12.3471459191464970, 219.8532640727768239 12.3753095044270172, 219.8601696000010008 12.4034874078261979, 219.8674454814815817 12.4316594206823332, 219.8745707847417066 12.4598419912327856, 219.8816850375779950 12.4880175631037602, 219.8889121190733249 12.5161815294953165, 219.8961929096689687 12.5443496532151961, 219.9035207112792421 12.5725221393741382, 219.9108000505651717 12.6007019865559293, 219.9180033534095458 12.6288900488054807, 219.9252926238032160 12.6570812286973560, 219.9325837931077388 12.6852781631490377, 219.9416672226408593 12.7134247385197234, 219.9543961129569709 12.7414629673091611, 219.9609663348926460 12.7696974746051932, 219.9637127244800752 12.7980546219476423, 219.9693396485584742 12.8263272759272695, 219.9763389820033410 12.8545627691681350, 219.9873479021010496 12.8826789123672043, 219.9942663403161589 12.9109285110434495, 220.0001191110418972 12.9392170377871505, 220.0060791740759782 12.9675078899464093, 220.0125259482794604 12.9957892678082931, 220.0204798708710712 13.0240294902412526, 220.0303293169092740 13.0522308973718015, 220.0363637763307167 13.0805716599938826, 220.0435221785276383 13.1088831468612046, 220.0503444747572246 13.1372106969061555, 220.0554559745506822 13.1655969103811294, 220.0637152729870252 13.1938911364857177, 220.0719544405740180 13.2221916259964853, 220.0809450262833309 13.2504744742211606, 220.0855198220701539 13.2788996751998667, 220.0951748736929972 13.3071731967088756, 220.1002723968982480 13.3355840088870181, 220.1073650534362116 13.3639288227772823, 220.1144815965231203 13.3922785024813287, 220.1215875627314631 13.4206341037762336, 220.1287352846985073 13.4489940062221862, 220.1370402478150083 13.4773238026688098, 220.1447839371536475 13.5056765103977572, 220.1521111758974030 13.5340476370338632, 220.1594759153635721 13.5624231738013545, 220.1672083183461552 13.5907929546773047, 220.1735074970197559 13.6191997958310740, 220.1797183181128901 13.6476015911061932, 220.1873653702023717 13.6759648320780780, 220.1929970821997813 13.7043955201351526, 220.2002836979509937 13.7327809783765069, 220.2072371134695175 13.7611822222090741, 220.2143098338185894 13.7895853680132223, 220.2215409215835393 13.8179892236931909, 220.2286146028019118 13.8464034430197191, 220.2359968999590762 13.8748137746858919, 220.2429905146004785 13.9032506380188590, 220.2501006641976460 13.9316990778372318, 220.2572072438011901 13.9601531118914810, 220.2642324533995009 13.9886151017755527, 220.2713546031071132 14.0170796063823282, 220.2784888315825356 14.0455492056894737, 220.2854618046473831 14.0740291667353681, 220.2923997653498986 14.1025156367928961, 220.2996432287141317 14.1309982528014668, 220.3069647400963333 14.1594839346048804, 220.3142063436780802 14.1879636486693332, 220.3212788516617024 14.2164393475970758, 220.3285570372971449 14.2449142697162561, 220.3357705557098143 14.2733966112673905, 220.3430038919728702 14.3018838043373702, 220.3501936696853534 14.3303777594724178, 220.3574521197704712 14.3588750715236344, 220.3646056907983279 14.3873809839935678, 220.3714125046764707 14.4159027845413714, 220.3785545330334799 14.4444198669506587, 220.3856337203785074 14.4729600246978372, 220.3927611377524443 14.5015207375727009, 220.4001050934609793 14.5300802439584942, 220.4070157681905755 14.5586581172829845, 220.4141741432308095 14.5872338303264470, 220.4213520871849141 14.6158142500114394, 220.4283400945614915 14.6444056727811578, 220.4351961118798897 14.6730063437207345, 220.4419879938532176 14.7016142082228747, 220.4491297929428981 14.7302168129408795, 220.4562863979076610 14.7588242338492499, 220.4632064462008714 14.7874440135878071, 220.4702124056549906 14.8160664517127341, 220.4773075834508518 14.8446914417330760, 220.4839436386864122 14.8733354359420638, 220.4909400903971175 14.9019738273440865, 220.4976830000880739 14.9306250291691658, 220.5046871348686750 14.9592735965149757, 220.5120298151077236 14.9879172093816493, 220.5191431519799039 15.0165728860575438, 220.5262490346293305 15.0452192621456078, 220.5332207140164940 15.0738593391698057, 220.5401179893822246 15.1025068648033898, 220.5471624568289712 15.1311551999620360, 220.5542495222690889 15.1598074720371656, 220.5611462413826303 15.1884706315084657, 220.5679511426332340 15.2171417190662872, 220.5747134505176632 15.2458192561079926, 220.5815516684503166 15.2744996976014438, 220.5883461731253874 15.3031866064603737, 220.5952718642558068 15.3318669232528180, 220.6021707513029355 15.3605449415493194, 220.6091175731324370 15.3892267260807643, 220.6161856753946324 15.4179100901230566, 220.6230988133778794 15.4466032396069899, 220.6301581991951650 15.4752972166398202, 220.6372147493088676 15.5039964428243202, 220.6444441173819655 15.5326957055445458, 220.6513662352306540 15.5614092260747814, 220.6584249247968899 15.5901238420788868, 220.6656150398821978 15.6188559149160699, 220.6725666950571565 15.6476172350376075, 220.6794748557452408 15.6763848777368935, 220.6865817603947448 15.7051516699670337, 220.6936357219268530 15.7339250504649577, 220.7007661075990370 15.7627011861934001, 220.7078723698223257 15.7914830405681847, 220.7148087277778075 15.8202749132805156, 220.7215739629539826 15.8490768264030688, 220.7283696406998388 15.8778828200969766, 220.7350802981803497 15.9066906070165039, 220.7416702149446905 15.9355009309045688, 220.7481918200303710 15.9643182514411546, 220.7548889450912384 15.9931353700775798, 220.7613380772241953 16.0219647647033518, 220.7677626895963670 16.0507998367200351, 220.7746364759823621 16.0796266326420110, 220.7812760232888820 16.1084652723297488, 220.7879783038013670 16.1373070026573302, 220.7945420931276601 16.1661577372383469, 220.8003749787557979 16.1950206146459905, 220.8065617770233189 16.2238629585585379, 220.8128621962586067 16.2527069130919664, 220.8191817783076658 16.2815552455657588, 220.8255725903351561 16.3104064260858870, 220.8322066932024370 16.3392554115519744, 220.8387268830609855 16.3681126611654619, 220.8455734890393387 16.3969652843257272, 220.8521103356239621 16.4258318846550360, 220.8587076065097392 16.4547016259001531, 220.8645847861091625 16.4836114738970636, 220.8712379212902022 16.5125184939384688, 220.8780366530769754 16.5414260976919820, 220.8844439642249711 16.5703499435244410, 220.8910779639868736 16.5992719914096050, 220.8980535532645888 16.6281888885597589, 220.9049801592676090 16.6571120172564200, 220.9120543712106723 16.6860356421274787, 220.9194018676946598 16.7149560938374400, 220.9275853959155711 16.7438569741192573, 220.9337514394953814 16.7728073784391292, 220.9389458502036803 16.8017760251284400, 220.9442633220138248 16.8307458475437279, 220.9495797699727291 16.8597204500586848, 220.9576980262959296 16.8886184324824242, 220.9646433114295974 16.9175552949130505, 220.9706915457650496 16.9465229737779772, 220.9797360850324139 16.9754084989699301, 220.9858503433434009 17.0043838123042050, 220.9958092375155729 17.0332524232458873, 221.0051547335982036 17.0621516661765007, 221.0123955262187678 17.0911251846374519, 221.0184945335432474 17.1201365064761504, 221.0265358816036212 17.1490962372719231, 221.0342592253194596 17.1780698849983899, 221.0416971727682665 17.2070564924296505, 221.0492649291077214 17.2360440208405308, 221.0574163923749325 17.2650193214497740, 221.0642376488161744 17.2940378145763596, 221.0712507676574603 17.3230554066094307, 221.0750035062377208 17.3521530122707048, 221.0833825988925696 17.3811014280375176, 221.1012000644046509 17.4097816163128023, 221.1234697965102214 17.4383372243239592, 221.1446009054772333 17.4669299946673036, 221.1659814117942346 17.4955196829087924, 221.1862074954466379 17.5241471727198928, 221.1957570597425331 17.5530905107879924, 221.2038686917591974 17.5820804814770604, 221.2080601841900318 17.6111893255309795, 221.1988433217773036 17.6407165962590220, 221.1916363252985036 17.6702144710442255, 221.1877485889076809 17.6996199313129061, 221.1891656918670037 17.7288761976824603, 221.1968354294687913 17.7579563475155275, 221.2025406653730215 17.7870977089870124, 221.2096147695653201 17.8162040253518192, 221.2165160144454887 17.8453198053554267, 221.2224942250372237 17.8744666958604519, 221.2277119721113934 17.9036399876070433, 221.2332821024614873 17.9327909627808992, 221.2383170207892533 17.9619443244375532, 221.2442905429176676 17.9910751116440970, 221.2498363552460603 18.0202227058669315, 221.2557305329598307 18.0493647450156480, 221.2621416431597083 18.0784963863439252, 221.2691430205308336 18.1076155304318078, 221.2754988091504913 18.1367577198945398, 221.2813337868578571 18.1659193359031335, 221.2877855767732171 18.1950676779960325, 221.2953253954281365 18.2241907180674048, 221.3013599379729328 18.2533629946000460, 221.3064374135869627 18.2825671410003530, 221.3124537532020213 18.3117487397487757, 221.3182281062903485 18.3409416696727341, 221.3250634190554251 18.3701085798518733, 221.3330656596799031 18.3992464481771627, 221.3374356808525647 18.4284927545661503, 221.3395300095252196 18.4578084755441303, 221.3458224373307530 18.4870083936197460, 221.3522630305629093 18.5162084244384424, 221.3577068641920107 18.5454412769644392, 221.3641904027647058 18.5746487548991901, 221.3715279113331462 18.6038361782572075, 221.3767990325112009 18.6330869316119312, 221.3800267736432943 18.6624002608480133, 221.3827362012217748 18.6917325592284307, 221.3870286300991097 18.7210239622508823, 221.3954345647359503 18.7502025136229911, 221.3995412875318891 18.7795077425839771, 221.4052686290156373 18.8087667835239998, 221.4116141406183260 18.8380079578304738, 221.4182075524130937 18.8672463620028950, 221.4234075464069917 18.8965286224053521, 221.4297424897585813 18.9257828880718861, 221.4381330035352846 18.9549830454225727, 221.4437786011409628 18.9842653899860565, 221.4516916823562838 19.0134876142634610, 221.4581724334677517 19.0427547245433573, 221.4643258335165967 19.0720353410303822, 221.4703040024018605 19.1013190922888043, 221.4757366352769736 19.1306161364696479, 221.4827138452384929 19.1598736469144661, 221.4886341156465619 19.1891653109676064, 221.4939175151725124 19.2184791926537457, 221.4996824222843372 19.2477836348834472, 221.5040993847280220 19.2771303360983630, 221.5096515244819102 19.3064491172807706, 221.5157897919053198 19.3357555187522010, 221.5254028690785049 19.3649680591620559, 221.5379303710355714 19.3941024987874222, 221.5502966625256249 19.4232455910307031, 221.5569858010044015 19.4525532672247863, 221.5662602301570416 19.4817920506938620, 221.5778712909811645 19.5109689307779846, 221.5906471456263773 19.5401169398491881, 221.6024846425621888 19.5692955530695585, 221.6125339523005664 19.5985288924105419, 221.6228556391053246 19.6277586118567839, 221.6323660626076730 19.6570154156721131, 221.6415036194281356 19.6862868957955222, 221.6440994496165047 19.7157478620347959, 221.6431790142311513 19.7453121776283318, 221.6474316282330221 19.7747340489961267, 221.6570225245225458 19.8040091392092137, 221.6647075508695082 19.8333421333557354, 221.6736770574902664 19.8626428790710357, 221.6816534358866875 19.8919757276629383, 221.6864937930701274 19.9214011979869596, 221.6879797049289493 19.9509252780549353, 221.6950232773449443 19.9803103315518449, 221.7007288046107192 20.0097516794640775, 221.7040268219716665 20.0392648174781520, 221.7074732178250542 20.0687776378866189, 221.7106187017003549 20.0983027921591670, 221.7176740679890941 20.1277217371706669, 221.7230474806044640 20.1571919248215643, 221.7277670535394805 20.1866843938526337, 221.7319372793065497 20.2161961795330107, 221.7405646672224293 20.2455863928381312, 221.7463882445141508 20.2750552241943964, 221.7538847958166457 20.3044764360793089, 221.7622793455343242 20.3338762064548320, 221.7701565146116707 20.3632943759725151, 221.7734189146283370 20.3928463602206271, 221.7781702147772478 20.4223602164826765, 221.7857704918945672 20.4517976945089366, 221.7905756424046331 20.4813176640664665, 221.7934115372622159 20.5108968160158120, 221.7963450989159071 20.5404769505775811, 221.8001359603279354 20.5700367281890664, 221.8054088754265365 20.5995586336503891, 221.8103228716608157 20.6290943849494468, 221.8166331240383613 20.6585946947209784, 221.8221241242964936 20.6881217626415754, 221.8259241658650183 20.7177000295338374, 221.8288535881722225 20.7473064169434060, 221.8317732953118764 20.7769167504077217, 221.8434864832525477 20.8062842965649075, 221.8548980732984148 20.8356638511278476, 221.8497146824853417 20.8655018098821863, 221.8425379707960872 20.8953868195347354, 221.8373773924683974 20.9252182013111145, 221.8382192560088413 20.9548855526717617, 221.8489009231472266 20.9842827887193870, 221.8672566919577491 21.0134697677843612, 221.8797273719326029 21.0428242377920007, 221.8887999810042686 21.0722772505930536, 221.8917645082245826 21.1019045711431943, 221.8997328109844602 21.1313958605496346, 221.8990926618291724 21.1611280411137237, 221.9019993444164811 21.1907616766640849, 221.9051040779272626 21.2203933633164255, 221.9093557913321320 21.2499967314856093, 221.9134297178846964 21.2796086471933421, 221.9116007489075457 21.3093879023960788, 221.9032882877899624 21.3393495525534895, 221.9060520607352771 21.3690080227605748, 221.9051334272910481 21.3987714956553354, 221.9034009241744343 21.4285605665808703, 221.9100285267176105 21.4581261493741309, 221.9160069827211714 21.4877163657336219, 221.9238932399040038 21.5172577422916156, 221.9293998902381873 21.5468681209350770, 221.9330707636211457 21.5765324977498807, 221.9363254486283381 21.6062118074008929, 221.9410037369304689 21.6358555651428652, 221.9455408147354092 21.6655067257743426, 221.9489016120366500 21.6951936277865052, 221.9527587731917890 21.7248704150393657, 221.9568600871938884 21.7545531875111315, 221.9622411699628231 21.7842141222439736, 221.9689664639304851 21.8138417551273953, 221.9756209612246778 21.8434747837706063, 221.9818735094069382 21.8731222677031809, 221.9874059330027194 21.9027929105330124, 221.9923440429898562 21.9324832583258171, 221.9971277815419626 21.9621812611599090, 222.0022569686276483 21.9918732335909617, 222.0073470416925829 22.0215696931690523, 222.0125447730543442 22.0512545134973408, 222.0181706962175383 22.0809182668990545, 222.0238933056503186 22.1105828124295201, 222.0295305341456071 22.1402531168903636, 222.0351237484508715 22.1699280425233560, 222.0404257554211540 22.1996143288699308, 222.0459155989807130 22.2292988829795952, 222.0512924341140035 22.2589899133886746, 222.0566673648044116 22.2886843762515738, 222.0618862307206882 22.3183864694176712, 222.0670553472533015 22.3480957599217014, 222.0723717417823480 22.3778070085798433, 222.0777839748901670 22.4075189964093333, 222.0831798394412999 22.4372347713885887, 222.0886434003048180 22.4669520384429156, 222.0940816858582139 22.4966733208646943, 222.0994527850592419 22.5263997498348054, 222.1047812729934776 22.5561306496470415, 222.1101155305294412 22.5858646931989853, 222.1154152125551207 22.6156029721982748, 222.1204420127930348 22.6453400486665366, 222.1255646964550010 22.6750652359120757, 222.1305329997020408 22.7047979140034606, 222.1355847787701236 22.7345316112044280, 222.1406216272308427 22.7642689945996679, 222.1456386712231108 22.7940101865939475, 222.1506385132327637 22.8237551067842261, 222.1555893546876064 22.8535046094059879, 222.1605043394520749 22.8832583260641407, 222.1653877636704806 22.9130161310442304, 222.1701197628285058 22.9427889792997313, 222.1746776287420460 22.9725778901872602, 222.1789441576504487 23.0023778463962252, 222.1836557252892987 23.0321689614480754, 222.1902440398285989 23.0619126297839330, 222.1954526487301109 23.0916966954934253, 222.2010831637109618 23.1214725486922141, 222.2083216384725404 23.1512082124632670, 222.2139515806102850 23.1809904050361695, 222.2171221060486914 23.2108420163699556, 222.2209885173431871 23.2406820491138433, 222.2264371355994967 23.2704868989222255, 222.2313264837684983 23.3003099104321585, 222.2360295055708832 23.3301410280497237, 222.2416143589899207 23.3599515095395667, 222.2470280979290465 23.3897696783524935, 222.2519457695078700 23.4196042623493703, 222.2572284978178629 23.4494320946218942, 222.2625351292319067 23.4792623412355859, 222.2678234450957575 23.5090961313971469, 222.2731187338746679 23.5389287176773223, 222.2783913237996956 23.5687606663922935, 222.2836896458202887 23.5985949595753404, 222.2889783774910200 23.6284325359269722, 222.2942692541417387 23.6582730742638709, 222.2995474628026216 23.6881169629623720, 222.3048186546048441 23.7179640408533103, 222.3100880876171175 23.7478141608096252, 222.3153559270981532 23.7776673079717789, 222.3206150332030404 23.8075236678525748, 222.3258698866435168 23.8373906038255718, 222.3311162163473966 23.8672686258960809, 222.3363674375100345 23.8971494473812491, 222.3416002240587375 23.9270336833286592, 222.3468409731699182 23.9569206200426663, 222.3520781787404417 23.9868105567601475, 222.3572950908845201 24.0167039333042744, 222.3625011870320805 24.0466004896445824, 222.3677192511185581 24.0764996045117847, 222.3729424320191015 24.1064014556798760, 222.3781468771423988 24.1362901048424909, 222.3833649201491767 24.1661637831187015, 222.3885678890137285 24.1960407688332424, 222.3937637687527626 24.2259208372428745, 222.3989420319153396 24.2558042638083400, 222.4041440838418282 24.2856899311823646, 222.4093321917397645 24.3155788396142292, 222.4144990636221451 24.3454711774863419, 222.4196730904269543 24.3753661752947544, 222.4248346881902023 24.4052643501693183, 222.4300062062717416 24.4351764710664803, 222.4351870687680162 24.4651031621802808, 222.4403525020867960 24.4950330549062905, 222.4455026491758076 24.5249661348580865, 222.4506599244405720 24.5549017979669024, 222.4558229849398856 24.5848400707973234, 222.4609842278302381 24.6147811468647646, 222.4661284181207179 24.6447254265187077, 222.4713101840497416 24.6746714423507321, 222.4764591914561720 24.7046210641846393, 222.4815193387960335 24.7345653487702641, 222.4865942845428890 24.7645009503149645, 222.4916659845742686 24.7944393662112113, 222.4967339978794314 24.8243805976587879, 222.5017992758810976 24.8543246132578624, 222.5068766617123401 24.8842710086782972, 222.5120706242933011 24.9142169964455888, 222.5176992594136323 24.9441541158756088, 222.5230551169359785 24.9741011721433921, 222.5290723867522047 25.0040333259218812, 222.5331869879559292 25.0340250877719264, 222.5376183126456908 25.0640178059903214, 222.5426224342267290 25.0939979417774310, 222.5478384861640961 25.1239750739483334, 222.5527734021357276 25.1539622860461556, 222.5574433522509423 25.1839591349760674, 222.5625189750431048 25.2139478159431754, 222.5680865705771225 25.2439260391509634, 222.5750931585015167 25.2738686682064433, 222.5818713705537562 25.3038199264691279, 222.5873131975623664 25.3338052353980174, 222.5917661569066013 25.3638151369705795, 222.5953573557681864 25.3938504355635075, 222.5981423237566332 25.4239096057939236, 222.6021066629562029 25.4539400323271892, 222.6070875480329789 25.4839460669213231, 222.6120740674626006 25.5139544753542999, 222.6170732825590335 25.5439650649896528, 222.6222362522800324 25.5739738306894715, 222.6271684386293543 25.6039912012273128, 222.6335610291737623 25.6339683652455506, 222.6407584509559285 25.6639224326588149, 222.6425063814833436 25.6940230383128245, 222.6465820115638792 25.7240645598688396, 222.6516161452648817 25.7540832404217248, 222.6567612330741497 25.7841014576707046, 222.6622771705746118 25.8141123513063739, 222.6675096863309875 25.8441331729110537, 222.6724462652234706 25.8741642349645389, 222.6771134454122034 25.9042048235666122, 222.6827850674766864 25.9342363968775302, 222.6931165988777366 25.9641633520258601, 222.6998107997744398 25.9941885112906732, 222.6993812296677504 26.0244039700569019, 222.7004828501633540 26.0545812838950290, 222.7068412637907215 26.0846224342125872, 222.7151250248850261 26.1146151271205440, 222.7223428546015214 26.1446381900068268, 222.7233614602515956 26.1748271205919316, 222.7251698747904527 26.2049974649508641, 222.7297580672415336 26.2350818940931845, 222.7350401377152878 26.2651345787107751, 222.7397478569982354 26.2952047135490403, 222.7441890163588027 26.3252841708795167, 222.7490415028016457 26.3553551043257031, 222.7538245647999986 26.3854301586473383, 222.7585301990661719 26.4155095328345944, 222.7633657664723330 26.4455877699967203, 222.7688255310053194 26.4756518789740127, 222.7734841245274708 26.5057393017668552, 222.7804994013292799 26.5357699997111425, 222.7892222416250263 26.5657611258525037, 222.7934201840520245 26.5958734025664825, 222.7976525279802047 26.6259869814647203, 222.8061529184204801 26.6559906322473736, 222.8082111146133855 26.6861657600068867, 222.8108775599046965 26.7163270320472712, 222.8149933055477163 26.7464524254111744, 222.8202949000982755 26.7765488881277207, 222.8301151846121400 26.8065289627933794, 222.8347576221901534 26.8366503143100488, 222.8375201821877170 26.8668265546276430, 222.8418110343396847 26.8969648288669170, 222.8465067625856193 26.9270946182803357, 222.8524537725384675 26.9571937291370851, 222.8574636362439207 26.9873195346867760, 222.8620005207342842 27.0174598522939391, 222.8671731236854612 27.0475856079338861, 222.8726715768086706 27.0777049164258052, 222.8775474502902796 27.1078426359435340, 222.8816119755332181 27.1380004347667914, 222.8869882261955695 27.1681224764912024, 222.8926632525074183 27.1982387554859741, 222.8956791014889802 27.2284267497753270, 222.8990635443852568 27.2586071020030154, 222.9037992898207108 27.2887541107411167, 222.9093687180935035 27.3188813346966022, 222.9147563759039485 27.3490153396147129, 222.9196081766303905 27.3791653776126473, 222.9243436031770216 27.4093204644372150, 222.9286080088542121 27.4394937878516600, 222.9336119064177808 27.4696539013430403, 222.9389694547837166 27.4998067414069283, 222.9467971585075645 27.5298969245199601, 222.9536775696169855 27.5600138137988324, 222.9590786061791903 27.5901713708442387, 222.9649273858052254 27.6203191385870532, 222.9707788876332302 27.6504687616998197, 222.9779598201737372 27.6805854587132423, 222.9832825767003328 27.7107527614628246, 222.9817568406569137 27.7410883808228625, 222.9874565001069868 27.7712230016882486, 222.9936425870742482 27.8013468434569795, 222.9960558499005003 27.8315712512584490, 223.0003219092032793 27.8617491055375872, 223.0057706188702866 27.8918979783849821, 223.0108205033237994 27.9220591651377141, 223.0159954833848133 27.9522189808714074, 223.0194101868325447 27.9824265788414195, 223.0236278179942246 28.0126150871196664, 223.0270783276952216 28.0428260124679767, 223.0284527756685122 28.0730933626770494, 223.0310594806987865 28.1033303987746415, 223.0333322930894440 28.1335778457447923, 223.0341180624720323 28.1638655435949730, 223.0377939193720067 28.1940800787344727, 223.0423453188257099 28.2242737368825729, 223.0473563566852704 28.2544573009177569, 223.0475810350740460 28.2847663252395094, 223.0468242129838075 28.3151021837157622, 223.0494697180605783 28.3453669498318810, 223.0551226685687141 28.3755718417018272, 223.0596599616456217 28.4058071837445638, 223.0644130602050836 28.4360386740747870, 223.0699211842023146 28.4662524123565248, 223.0775607745895286 28.4964128803651597, 223.0834267667080439 28.5266207293507925, 223.0946602925923514 28.5566915950313707, 223.1011121708191922 28.5868875504528930, 223.1057514664018413 28.6171320328370165, 223.1092717803553569 28.6474026359030169, 223.1131858521137303 28.6776599785361732, 223.1175135978418780 28.7079082719772458, 223.1224011054471532 28.7381437355216320, 223.1295408824391302 28.7683226027755978, 223.1386439433995577 28.7984522355940484, 223.1466096978197129 28.8286128295860955, 223.1512039324807120 28.8588623697961246, 223.1491767764528049 28.8892849121626583, 223.1495096696988014 28.9196477562610710, 223.1531510946216201 28.9499227439951561, 223.1593084066995232 28.9801302235178611, 223.1671463731093752 29.0102958476445494, 223.1733378307814917 29.0405055589089827, 223.1762893691844170 29.0708005572484467, 223.1797411591123534 29.1010841479297575, 223.1842105395181193 29.1313429880265531, 223.1897492654337611 29.1615757529559403, 223.1968336860489330 29.1917701214392054, 223.2007111469345091 29.2220488212368714, 223.2065521127375689 29.2522700368019706, 223.2119706505060890 29.2824949298750248, 223.2143181739406259 29.3128005757675822, 223.2145049372267067 29.3431632754399629, 223.2130727083799400 29.3735688214291208, 223.2169012501132954 29.4038404960306927, 223.2205048495329152 29.4341193922091691, 223.2231762087316156 29.4644236196080875, 223.2286000314316823 29.4946587355534717, 223.2310513877485789 29.5249714294954018, 223.2344723717499733 29.5552689830075686, 223.2401364427243493 29.5855193241839736, 223.2452585570237602 29.6157849349408515, 223.2505202413070720 29.6460483698967643, 223.2559231593347135 29.6763095798524112, 223.2644027871221510 29.7064934052381027, 223.2627241956079160 29.7369385494086664, 223.2645402237930341 29.7672955192597151, 223.2677335536144199 29.7976186173721906, 223.2703656238754206 29.8279573493982966, 223.2756273227971349 29.8582220782055394, 223.2844765439493528 29.8883879235143297, 223.2937085860437492 29.9185452807982983, 223.2973081015805406 29.9488478138785794, 223.2936631005052845 29.9793362624003414, 223.2960666519461199 30.0096716675618822, 223.3009400212254150 30.0399455321170663, 223.3025870375495288 30.0703026550889163, 223.3057019420284917 30.1006237111833812, 223.3089129363760605 30.1309435671565957, 223.3150049755914495 30.1612022619482083, 223.3234217233952563 30.1914144151318169, 223.3234210094943535 30.2218413027351609, 223.3217310036492904 30.2523119774260358, 223.3241338861792258 30.2826801517841098, 223.3291361017602412 30.3129838017813853, 223.3335691814666291 30.3433030311341518, 223.3376879267506752 30.3736313903895585, 223.3415822010214242 30.4039665939569446, 223.3428527313638483 30.4343692093283416, 223.3463046577959119 30.4647139764403789, 223.3516152151367749 30.4950088855972581, 223.3563567921310380 30.5253193044814317, 223.3591806847722694 30.5556792231967869, 223.3633551843234670 30.5860062097663175, 223.3673017153174101 30.6163400617373931, 223.3700134643006550 30.6467061128488218, 223.3771472685137098 30.6769619187146567, 223.3826102810353689 30.7072608971903698, 223.3886354466583271 30.7375468061244668, 223.3920631849453287 30.7678988088006946, 223.3948340483456434 30.7982679488012252, 223.3964740350774605 30.8286665606172789, 223.3988015833816974 30.8590488763677833, 223.4054640309857689 30.8893233212344853, 223.4110113026205795 30.9196268339053155, 223.4122686163119624 30.9500391594668898, 223.4185862540229266 30.9803254154219729, 223.4253672463590590 31.0106010422639251, 223.4280655144074501 31.0409802449639898, 223.4338793837549417 31.0712782786190367, 223.4368728738980963 31.1016439799744298, 223.4352648020414733 31.1321259385368165, 223.4366125414503301 31.1625346166880490, 223.4396705389226554 31.1929014229039367, 223.4456438373482570 31.2231963322768564, 223.4505941710129946 31.2535177729686104, 223.4547715708266935 31.2838594812816666, 223.4577739516391546 31.3142314599850486, 223.4600217044295221 31.3446231542552951, 223.4635365292321012 31.3749880885431551, 223.4679250724919939 31.4053363295084900, 223.4717664816919864 31.4356991045685845, 223.4748831801429390 31.4660808082941479, 223.4799487654643713 31.4964148775685153, 223.4840292327695863 31.5267743476384190, 223.4865411911619617 31.5571736951986459, 223.4883032670517196 31.5875924900986753, 223.4923952323851779 31.6179542209252666, 223.4970672524644328 31.6483023929509102, 223.5030692210505094 31.6786209217388759, 223.5066616283142196 31.7090028002147299, 223.5106210413823078 31.7393763676496015, 223.5132764001971566 31.7697830874807003, 223.5179240398600484 31.8001411574942452, 223.5195254158442424 31.8305755440645903, 223.5239434375313579 31.8609408591624259, 223.5282886785034577 31.8913087442676790, 223.5322519417453861 31.9216868480441498, 223.5347617094257373 31.9521016879863211, 223.5380353071004436 31.9824836882649954, 223.5428282743981185 32.0128133802272288, 223.5480508269670565 32.0431332222472349, 223.5497441169615058 32.0735409978522270, 223.5553057804664263 32.1038539700300873, 223.5598384268535881 32.1341930832612732, 223.5624288051742212 32.1645807930955741, 223.5652337762755906 32.1949638621259524, 223.5678286491418874 32.2253527382871567, 223.5695560421223433 32.2557635380633556, 223.5752088569645082 32.2860971656535369, 223.5778937031500675 32.3165239135065789, 223.5812675754343957 32.3469343758281909, 223.5848566389719849 32.3773401796878062, 223.5891675860983128 32.4077288948879030, 223.5927666199704902 32.4381356808599506, 223.5971664748019236 32.4685234266738121, 223.6018897195259569 32.4989038349033450, 223.6036667978909236 32.5293570670729295, 223.6064949112673332 32.5597850850799730, 223.6116324578020453 32.5901446220759823, 223.6140456300391008 32.6205582901027782, 223.6180710912269092 32.6509330396607425, 223.6211992806995568 32.6813302883187617, 223.6282270303249788 32.7116327514627585, 223.6317729060406236 32.7420209117044507, 223.6357729383524600 32.7723985009571379, 223.6368325295503041 32.8028483884673676, 223.6411096371763563 32.8332202356979153, 223.6439910882040749 32.8636266156867194, 223.6481310195877086 32.8940028179196418, 223.6509936165338104 32.9244106061581263, 223.6553899144079480 32.9547815456590314, 223.6596968044144660 32.9851551442578028, 223.6612145715821214 33.0155969875223505, 223.6650693763939444 33.0459824801913911, 223.6692659409714850 33.0763601294171607, 223.6716695758493643 33.1067817005986385, 223.6751523009409368 33.1371775151216497, 223.6790842134867034 33.1675628698264759, 223.6817299554946601 33.1979800536689638, 223.6840029478087502 33.2284069152961763, 223.6869551521492383 33.2588177146786137, 223.6903565456445051 33.2892180314227915, 223.6936834072822933 33.3196205103363567, 223.6971029050550612 33.3500211100688375, 223.7007701587213546 33.3804160897484863, 223.7044837207082537 33.4108103024752197, 223.7075120344256618 33.4412213365115178, 223.7108808174373280 33.4716244979182633, 223.7150218024641788 33.5020111063703752, 223.7185127413576993 33.5324154287190694, 223.7220915424194061 33.5628179458101741, 223.7256487173189896 33.5932212766860943, 223.7286216236610699 33.6236389013519741, 223.7320216440893432 33.6540465564206670, 223.7369843538813257 33.6844170563033742, 223.7396632576619027 33.7148425178093021, 223.7417605710046757 33.7452821084065206, 223.7453063421154127 33.7756872889352167, 223.7483122061553331 33.8061098598384433, 223.7517120547620664 33.8365277389875274, 223.7558255243394569 33.8669288053235746, 223.7594854651125900 33.8973409052722872, 223.7624929837062382 33.9277687623950470, 223.7659937331060291 33.9581850448707883, 223.7683016722576497 33.9886299134953376, 223.7717654102397944 34.0190474189640710, 223.7746851068746992 34.0494780279845770, 223.7778200650010376 34.0799036630295475, 223.7815767483879199 34.1103144298280725, 223.7849598453518922 34.1407339699114232, 223.7886890994548992 34.1711454269250297, 223.7929755563177423 34.2015437888474807, 223.7950123858878442 34.2319956601868967, 223.7976542511011644 34.2624332578238224, 223.8008059636456153 34.2928588582611340, 223.8038189435971788 34.3232878312866134, 223.8070197677527915 34.3537124336828299, 223.8102919260166743 34.3841354218809698, 223.8132599669528702 34.4145658933153200, 223.8172826870554388 34.4551387030861562))) +MULTIPOLYGON (((225.6590116066086011 15.2022751781288630, 225.8184285319980802 15.1938011437427107, 225.9815607786718488 15.1849941022049926, 226.1537479980599414 15.1755636254992901, 226.3305987100000323 15.1657156107401683, 226.5161948590464078 15.1552163682550063, 226.7132602789062901 15.1438893478077468, 226.9261988964304351 15.1314506126365309, 227.1499418813374973 15.1181384848977540, 227.3887605669753214 15.1036654662162260, 227.6457676404389190 15.0877902093839538, 227.9238726251499827 15.0702639425568172, 228.2357698245607480 15.0502006375273023, 228.5715407538234274 15.0280865132481587, 228.9475901297275584 15.0027161002309199, 229.3712716345860088 14.9733679200999035, 229.9511930049727368 14.9320537002732596, 230.4883212838945781 14.8922542020580906, 231.1136532000215027 14.8443022653531198, 231.8633228532418400 14.7845460924271297, 232.7891574029212052 14.7073522924876734, 233.9942664759018385 14.6013042631466625, 234.4965294627785397 14.5504706067190579, 234.5208110638523067 14.5099689962529279, 234.5313044299073795 14.4803171724793245, 234.5416131312027801 14.4506850418484909, 234.5520779977871371 14.4210415870330468, 234.5623431784188710 14.3914232575198362, 234.5724238845463105 14.3618286535965378, 234.5827882789665750 14.3322149027208052, 234.5929578113344860 14.3026258488927525, 234.6030683507545973 14.2730490546493467, 234.6134058750884037 14.2434583659015832, 234.6236678287416737 14.2138814837024583, 234.6339787538766188 14.1843070299267406, 234.6442862284248463 14.1547369879349692, 234.6547188863688120 14.1251597335973766, 234.6648922775195842 14.0956130658841658, 234.6753260761099114 14.0660495235981191, 234.6864368112473471 14.0364311267002382, 234.6957686604494029 14.0069820247430616, 234.7061404536003124 13.9774449561658081, 234.7168562105069327 13.9478834920582333, 234.7270224975896724 13.9183791086254836, 234.7372048991153406 13.8888802351922376, 234.7477636671920322 13.8593540754838518, 234.7584817061348872 13.8298204455798839, 234.7691873583667359 13.8002949950470803, 234.7803650551794590 13.7707336568590062, 234.7916750860140098 13.7411673885779937, 234.8029058064372521 13.7116154576392404, 234.8142170604288594 13.6820633420075843, 234.8253048384432020 13.6525386874369357, 234.8363381012698596 13.6230261366839027, 234.8474859593540600 13.5935103445255336, 234.8586521615224001 13.5639727104256469, 234.8698086919266927 13.5344171571079581, 234.8810402760219631 13.5048618785192716, 234.8921633384625238 13.4753235398173157, 234.9036036680469692 13.4457635458124809, 234.9148787480722262 13.4162256650294367, 234.9262976243366836 13.3866818976443849, 234.9378525857910063 13.3571329686720333, 234.9491438202866220 13.3276151019577185, 234.9605851734783073 13.2980908305402235, 234.9714051171723952 13.2686329662724400, 234.9829107510691983 13.2391230511010320, 234.9953247709164827 13.2095381986057330, 235.0050945465017662 13.1801996367152601, 235.0136741450404543 13.1509757163783760, 235.0235876197880316 13.1216383624306303, 235.0329511591612004 13.0923577945443821, 235.0428529669675299 13.0630357717848380, 235.0521842656136187 13.0337723688292204, 235.0625643579875259 13.0044215484787493, 235.0718456764101347 12.9752026574268378, 235.0824545378013113 12.9458957824717462, 235.0941279042510530 12.9165005022008916, 235.1065853378691486 12.8870421851470827, 235.1158685212187436 12.8578770132341944, 235.1267432519177305 12.8285760999852005, 235.1379548440312988 12.7992524166110737, 235.1493796188802321 12.7699171276532759, 235.1597708587534044 12.7406822108994700, 235.1712990013349156 12.7113527637885788, 235.1827906320188504 12.6820275613200071, 235.1941656390224580 12.6527141312217779, 235.2050650309431603 12.6234509249003697, 235.2163653275223396 12.5941593716165769, 235.2278129164640745 12.5648622450461041, 235.2385899990798066 12.5356327691044349, 235.2509196533849263 12.5062719956791586, 235.2633495959182142 12.4769099908336152, 235.2728707652433116 12.4478157344413844, 235.2843018911919444 12.4185583774315713, 235.2958612619559915 12.3892706547972598, 235.3093903391809363 12.3597895148684760, 235.3187948284902404 12.3306840978547765, 235.3306973300513221 12.3013633115279610, 235.3409552423264586 12.2721967439647628, 235.3501958576858613 12.2431283054920037, 235.3613910460340719 12.2138932347157887, 235.3730447116263065 12.1846249559616240, 235.3841076194497646 12.1554168855521159, 235.3951457454282092 12.1262186343150464, 235.4062396923713436 12.0970204529142116, 235.4175034828008393 12.0678123993142545, 235.4293245043034517 12.0385625702422665, 235.4421181444995455 12.0092341707538317, 235.4552959271689474 11.9798795410635694, 235.4690679156001920 11.9504801024310261, 235.4834853052213646 11.9210313918726634, 235.4960974300517194 11.8917506964105861, 235.5075487335812454 11.8625807321371077, 235.5232045964962140 11.8330462747001270, 235.5346764929361711 11.8038936247787731, 235.5484769103933615 11.7745459193172586, 235.5600500490689910 11.7454032067389971, 235.5703027538093295 11.7163850530546778, 235.5839099151444316 11.6870783106887632, 235.5954261043269753 11.6579642551851776, 235.6091634785259430 11.6286620492115951, 235.6216120131801404 11.5994816340206004, 235.6324251515997616 11.5704534114552082, 235.6427681559864027 11.5414744763687072, 235.6568231608829649 11.5121696292982847, 235.6720114138059898 11.4827667117629471, 235.6855534378352104 11.4535169164043698, 235.6985976230074584 11.4243190426234822, 235.7101697741603061 11.3952586967556808, 235.7212865677433342 11.3662463475955882, 235.7336848210081257 11.3371294098704496, 235.7467824959671248 11.3079591641786763, 235.7608802892358426 11.2787093286096738, 235.7716222748915129 11.2497620499109825, 235.7842032100647600 11.2206891920149054, 235.7973313753711295 11.1916028404769996, 235.8104867447166839 11.1625225099613452, 235.8248992522363210 11.1333405976275657, 235.8395596186140324 11.1041455608978925, 235.8525266395224662 11.0751071281319753, 235.8667638348769628 11.0459661778884932, 235.8799840523980720 11.0169226049946332, 235.8933575463018997 10.9878741537475353, 235.9056857922247730 10.9589253856028837, 235.9193690857337913 10.9298457604617205, 235.9332202571170001 10.9007399237256113, 235.9474135600875115 10.8716127613864284, 235.9606689831861672 10.8425757207401006, 235.9745891351863349 10.8134893032569899, 235.9749642465138209 10.7716809281121115, 234.3062264801246215 10.9140277809663164, 233.0568672341268268 11.0146280042103246, 232.0879579900140470 11.0891193379889383, 231.2922763752978028 11.1479476252960712, 230.6222024977036256 11.1958368476612140, 230.0451126661331500 11.2358585089279366, 229.5399124326933418 11.2699591633018521, 229.0910977852267933 11.2995144425208256, 228.6886580791888548 11.3254217054343105, 228.3230615139313500 11.3484629748790748, 227.9885578563481374 11.3691297953353825, 227.6794424865351800 11.3878696987312100, 227.3925662525225562 11.4049521734577617, 227.1244248889419168 11.4206460692728164, 226.8725374557904217 11.4351462062810540, 226.6348499723003727 11.4486118924843705, 226.4089327375767766 11.4612113075361997, 226.1941018513785480 11.4730141135445951, 225.9885536989861805 11.4841415383496983, 225.7906841315510462 11.4946974768467634, 225.5999034371527046 11.5047316362642924, 225.5366590428407676 11.5127499139751173, 225.5372155286837028 11.5505123386258806, 225.5385771173869216 11.5787917807373031, 225.5399422790694928 11.6070769021958249, 225.5412964706850119 11.6353683683259401, 225.5426724692719347 11.6636646542798825, 225.5440051181480214 11.6919712226446801, 225.5452754778033579 11.7202890826927817, 225.5466283640396057 11.7486089150217499, 225.5479733512320877 11.7769349109975465, 225.5492620732997580 11.8052693182655215, 225.5505841234978277 11.8336079601987194, 225.5519462019553600 11.8619505139251853, 225.5533034114788222 11.8902990653271896, 225.5546573357829629 11.9186535319933640, 225.5560296401821176 11.9470128979944885, 225.5574630380517647 11.9753825153277855, 225.5590145865995453 12.0037600937422599, 225.5604603602513691 12.0321483085082885, 225.5618766106162241 12.0605435905483933, 225.5632235046636538 12.0889478001605273, 225.5646322492728189 12.1173547927717884, 225.5660183351829744 12.1457685136433842, 225.5674524000941119 12.1741856511797124, 225.5688591210027312 12.2026097227448993, 225.5703066480778034 12.2310375312635973, 225.5717059626002481 12.2594635287660125, 225.5731135142524977 12.2878845469914122, 225.5745000480431770 12.3163122245770751, 225.5759250961868645 12.3447437585488196, 225.5773924999224107 12.3731789608056744, 225.5788485201462947 12.4016203465804544, 225.5803384550112014 12.4300657782762727, 225.5816851396154448 12.4585235859629435, 225.5830893136675286 12.4869843196153401, 225.5845898505328648 12.5154461391776994, 225.5860380816324664 12.5439157417238452, 225.5874589809734232 12.5723919342328792, 225.5889159822422414 12.6008720348057395, 225.5903500433967963 12.6293588187895907, 225.5917512819598585 12.6578527497401971, 225.5931498469038843 12.6863523975501753, 225.5945936511308787 12.7148554897243873, 225.5960004208644420 12.7433659092357914, 225.5974035727396938 12.7718820685236683, 225.5988234672666408 12.8004029993498278, 225.6002725682347716 12.8289353398050423, 225.6017372705671562 12.8574801026263330, 225.6031663907919835 12.8860320507559170, 225.6045230142199500 12.9145929257661702, 225.6058813437432775 12.9431592082911244, 225.6072542184839165 12.9717302815183047, 225.6086155626813365 13.0003073734616503, 225.6099855929491866 13.0288895207329229, 225.6113301413350882 13.0574783349659143, 225.6125573731443410 13.0860781699462745, 225.6138059179633331 13.1146685837733763, 225.6150812749465899 13.1432485812774420, 225.6162458519782774 13.1718393536475027, 225.6173776523386891 13.2004371911819636, 225.6185740510497624 13.2290374592872606, 225.6198200700041809 13.2576408579599132, 225.6210454851929796 13.2862507192776924, 225.6223709718760801 13.3148612908315283, 225.6236531533329810 13.3434793901493354, 225.6249325723329093 13.3721030820185831, 225.6260928567572819 13.4007285591032215, 225.6271536834223639 13.4293543931465571, 225.6282124972139798 13.4579858251888869, 225.6292645314285892 13.4866230739553483, 225.6301804105962958 13.5152723244987154, 225.6310913323260934 13.5439273004220890, 225.6319395686368807 13.5725907590492518, 225.6327541317145062 13.6012613101755644, 225.6337718649642170 13.6299275878090551, 225.6347506831084502 13.6586011866152237, 225.6357740723692018 13.6872915145011298, 225.6369158381051250 13.7159957103282348, 225.6377194029691964 13.7447214977765864, 225.6381065136039865 13.7734726404849450, 225.6384486634579218 13.8022312915639596, 225.6384696572111466 13.8310107208009665, 225.6377164794393764 13.8598327075708507, 225.6365675112162137 13.8886790652427319, 225.6366436889486238 13.9174718431418274, 225.6368569804845379 13.9462633389480182, 225.6372512893272528 13.9750446861622404, 225.6375598958670992 14.0038283677250330, 225.6379232729383091 14.0326147566449215, 225.6383897344348384 14.0614015134760155, 225.6384870229912565 14.0902113783666270, 225.6385225417334937 14.1190295454278179, 225.6386422674683558 14.1478489717101485, 225.6388548745616731 14.1766692294529761, 225.6393899644289718 14.2054792305965023, 225.6400017789805759 14.2342908119101423, 225.6406354379116408 14.2631066557045862, 225.6413569018558860 14.2919235676818044, 225.6418737897815276 14.3207556083426546, 225.6423091415276758 14.3495968327812928, 225.6427227612253432 14.3784443487517848, 225.6431399559387501 14.4072969248162668, 225.6435643091585348 14.4361543784162514, 225.6439996403331634 14.4650165186353359, 225.6444242554794926 14.4938843841154803, 225.6447387703332197 14.5227627774815407, 225.6449631350287177 14.5516507312391443, 225.6451722610784714 14.5805446133494030, 225.6453957579692826 14.6094429811145208, 225.6457542898072575 14.6383399809685368, 225.6462420940192146 14.6672358817340580, 225.6469402654511782 14.6961267415683761, 225.6476430843318326 14.7250225124654772, 225.6482912662952458 14.7539260617623214, 225.6489832267797624 14.7828326103256256, 225.6497656768799516 14.8117398861253111, 225.6506424444196739 14.8406387378099005, 225.6513629139793977 14.8695408561432583, 225.6517777322902418 14.8984629714063477, 225.6521804907180808 14.9273908337275234, 225.6524924020781384 14.9563282654052863, 225.6529946843869538 14.9852615950152952, 225.6535087791164358 15.0141994839657045, 225.6541740532657343 15.0431351470923698, 225.6549119926503124 15.0720723858902090, 225.6554983620026746 15.1010221054608973, 225.6560601547267595 15.1299724947379310, 225.6566877994991955 15.1589188520153222, 225.6590116066086011 15.2022751781288630))) +MULTIPOLYGON (((222.1624644986581814 22.8951608776491611, 222.3339278053147439 22.8936291249977337, 222.4918214735398294 22.8892887248560974, 222.6447347625093585 22.8849225118103874, 222.7860232522739352 22.8807537877385627, 222.9282491754742637 22.8764117840873134, 223.0766244984219497 22.8717204866312542, 223.2163755016696030 22.8671671507805847, 223.3566763952025553 22.8624540093662851, 223.4933003437754166 22.8577319700323365, 223.5898184185919604 22.8543578550741238, 223.6952462098100511 22.8505806048140343, 223.7986314112134494 22.8468004169646264, 223.8996071437270245 22.8430363019214759, 223.9985409791389088 22.8392789938655092, 224.0959564206264076 22.8355116831515161, 224.1910355953448857 22.8317716008955180, 224.2846905331636549 22.8280253855071535, 224.3794591431320669 22.8241662736667266, 224.4717633562828496 22.8203486473478740, 224.5633375179995141 22.8165001434515133, 224.6543476105477737 22.8126140286554602, 224.7440401314165683 22.8087272357695596, 224.8325041708505694 22.8048422966027005, 224.9212556591315035 22.8008911950998439, 225.0106581698765069 22.7968452216291411, 225.1000007997412240 22.7927430513065232, 225.1888277899536774 22.7886040403501653, 225.2781779860744393 22.7843853505198553, 225.3686923868877443 22.7800551110823477, 225.4590163590555392 22.7756725361697896, 225.5508196988385805 22.7711599175616826, 225.6422475001495513 22.7666030802101886, 225.7360430349211811 22.7618690698426107, 225.8308944078887066 22.7570178539048058, 225.9265645398400011 22.7520593284113843, 226.0249049679701727 22.7468968896814552, 226.1249454787566151 22.7415751879109003, 226.2278086015192287 22.7360312020369442, 226.3331090916952917 22.7302792144843444, 226.4411376184330038 22.7242978235364390, 226.5516842589036344 22.7180922185925418, 226.6656163593179940 22.7116078268158503, 226.7845301475643680 22.7047457109732385, 226.9071475647440082 22.6975670621508918, 227.0314410381741368 22.6901810095987315, 227.1839792061757635 22.6810029064036662, 227.3309878641620116 22.6719940160821523, 227.4852574295552756 22.6623834900507148, 227.6478981924533969 22.6520789916308729, 227.8244753455144860 22.6406976405487157, 228.0131819147794658 22.6283077428341599, 228.2162925672537597 22.6147123261545140, 228.4292029370799639 22.6001656944389318, 228.6562565745130939 22.5843249428905182, 228.9060279701273828 22.5665175964537390, 229.1825161010338832 22.5463403908074760, 229.4889073173454221 22.5234095910938485, 229.8235975094182777 22.4976688768649389, 230.1950353289553561 22.4682622756183576, 230.6140350097421958 22.4340362400728921, 231.0891086675366921 22.3938791162801358, 231.6395867000893247 22.3455627542399640, 232.2933600728475199 22.2857009540908528, 233.0468719139713585 22.2096336010235156, 233.0786160068223012 21.8362790738185488, 233.1128703125103243 21.4745535124936815, 233.1496154961199068 21.1131520453783281, 233.1847240764050753 20.7523849749798011, 233.2282694104284246 20.3912575382026056, 233.2729399482114445 20.0308241593004865, 233.3250709695567195 19.6705333692279147, 233.3796821891314153 19.3110185896687021, 233.4385722855595304 18.9512397884117547, 233.5048315554937517 18.5912746804041298, 233.5705679155844336 18.2318918456861674, 233.6451980358387175 17.8721782134278087, 233.7217275105666374 17.5133469216293420, 233.8008596200677118 17.1546858578329271, 233.8864271812514630 16.7969322128191010, 233.9697189392310577 16.4397036867625808, 234.0828109349569672 16.0803141029273924, 234.1849920604828981 15.7230496510434978, 234.2920854371644168 15.3662472678846687, 234.4024907287821406 15.0099336756868329, 234.5149128953590321 14.6540024086710705, 234.6379311549195563 14.2984584660047442, 234.7623775574046192 13.9436811555426505, 234.8942578953382849 13.5892102038194693, 235.0288272435886654 13.2349149251491323, 235.1521051678167282 12.8828891503746785, 235.2867725902066240 12.5312613935276858, 235.4233087209121322 12.1800902645324101, 235.5708596306865275 11.8287640872622148, 235.7235065834900070 11.4781679472531195, 235.8797318094724460 11.1284757052297607, 236.0525313246161261 10.7671682736166101, 234.5539738435558093 10.8934756928844845, 233.4407131631531342 10.9842712723458362, 232.5469229652644003 11.0542229776369396, 231.8057772059842137 11.1102241836769355, 231.1727759778428322 11.1565989553883824, 230.6222024977036256 11.1958368476612140, 230.1360978920992579 11.2296246903222858, 229.7011060076216040 11.2591734075647292, 229.3092627460586925 11.2852352682155690, 228.9523786369052516 11.3085085479037968, 228.6255699416117295 11.3294320811030449, 228.3230615139313500 11.3484629748790748, 228.0424929933010674 11.3658248267683515, 227.7797848238544418 11.3818240807472453, 227.5335303503320290 11.3965959501297025, 227.3013618133047657 11.4103203927839978, 227.0813921445934511 11.4231400422407940, 226.8725374557904217 11.4351462062810540, 226.6735784057233900 11.4464323335892999, 226.4830830479979795 11.4570977194829009, 226.3002739486506414 11.4672030229303132, 226.1246140672749334 11.4767939954809481, 225.9550662527160227 11.4859387811263254, 225.7906841315510462 11.4946974768467634, 225.6312478555471444 11.5030927722663758, 225.4762447625155630 11.5111601660448795, 225.3250842761325714 11.5189369296321988, 225.1774439551024329 11.5264465188783927, 225.0328448252998612 11.5337180770247567, 224.8908763596490132 11.5407761760249468, 224.7513584997161615 11.5476346729728849, 224.6139594562434354 11.5543129777076068, 224.4784375362918922 11.5608260941027599, 224.3444652819509599 11.5671914448426509, 224.2117774258863392 11.5734232007857347, 224.0801718772106028 11.5795330298010271, 223.9493664901763452 11.5855344995887286, 223.8191624724294684 11.5914391819224125, 223.6892422590746605 11.5972592901497720, 223.5594084415180305 11.6030053638277568, 223.4294005333650546 11.6086896685705661, 223.2989722102144583 11.6143216904755153, 223.1678913125285533 11.6199107220438496, 223.0358968024115143 11.6254674694465869, 222.9027074603658320 11.6310028545879938, 222.7681514532162907 11.6365211163933093, 222.6319141538503459 11.6420339437049929, 222.4937638625373211 11.6475477129612344, 222.3535187113662914 11.6530658977189141, 222.2106332312139614 11.6586083764543069, 222.0649326370137260 11.6641761438836653, 221.9159984711464233 11.6697805626031830, 221.7637180402751653 11.6754184975181392, 221.6071946734351457 11.6811193203291595, 221.4462705120642738 11.6868790352296799, 221.2800176036289201 11.6927238980664399, 221.1082343240076113 11.6986486654835566, 220.9302181846813085 11.7046664470968480, 220.7448115762643397 11.7108046009476379, 220.5512576667543385 11.7170716871744123, 220.3489604038595360 11.7234675875962715, 220.1364090861300156 11.7300207161521133, 219.9120955538532485 11.7367529071512759, 219.6885215783216552 11.7467999825000611, 219.7800022085723413 12.0939667193786491, 219.8674454814815817 12.4316594206823332, 219.9609663348926460 12.7696974746051932, 220.0435221785276383 13.1088831468612046, 220.1287352846985073 13.4489940062221862, 220.2143098338185894 13.7895853680132223, 220.2996432287141317 14.1309982528014668, 220.3856337203785074 14.4729600246978372, 220.4702124056549906 14.8160664517127341, 220.5542495222690889 15.1598074720371656, 220.6372147493088676 15.5039964428243202, 220.7215739629539826 15.8490768264030688, 220.8003749787557979 16.1950206146459905, 220.8780366530769754 16.5414260976919820, 220.9576980262959296 16.8886184324824242, 221.0492649291077214 17.2360440208405308, 221.2038686917591974 17.5820804814770604, 221.2332821024614873 17.9327909627808992, 221.3064374135869627 18.2825671410003530, 221.3767990325112009 18.6330869316119312, 221.4437786011409628 18.9842653899860565, 221.5157897919053198 19.3357555187522010, 221.6415036194281356 19.6862868957955222, 221.7040268219716665 20.0392648174781520, 221.7734189146283370 20.3928463602206271, 221.8288535881722225 20.7473064169434060, 221.8917645082245826 21.1019045711431943, 221.9100285267176105 21.4581261493741309, 221.9689664639304851 21.8138417551273953, 222.0351237484508715 22.1699280425233560, 222.0994527850592419 22.5263997498348054, 222.1624644986581814 22.8951608776491611))) diff --git a/isis/src/base/objs/ImagePolygon/Makefile b/isis/src/base/objs/ImagePolygon/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3fa60599211cadbee740d56e2cd18a8a599932fd --- /dev/null +++ b/isis/src/base/objs/ImagePolygon/Makefile @@ -0,0 +1,5 @@ +INCS = ImagePolygon.h +SRCS = ImagePolygon.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ImagePolygon/unitTest.cpp b/isis/src/base/objs/ImagePolygon/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9c91a4ba3374b1f2a25c422c12defe2c162670fc --- /dev/null +++ b/isis/src/base/objs/ImagePolygon/unitTest.cpp @@ -0,0 +1,95 @@ +#include "ImagePolygon.h" +#include "PolygonTools.h" +#include "Preference.h" +#include "geos/geom/MultiPolygon.h" + +using namespace std; +using namespace Isis; + + +int main() { + Isis::Preference::Preferences(true); + + /** + * @brief Test ImagePolygon object for accuracy and correct behavior. + * + * @author 2005-11-22 Tracie Sucharski + * + * @history 2007-01-19 Tracie Sucharski, Removed ToGround method (for now) + * because of round off problems going back and forth between + * lat/lon,line/samp. + * @history 2007-01-31 Tracie Sucharski, Added WKT method to return polygon + * in string as WKT. + * @history 2007-11-09 Tracie Sucharski, Remove WKT method, geos now has + * a method to return a WKT string. + * @history 2007-11-20 Tracie Sucharski, Added test for sub-polys + */ + + // simple MOC image + string inFile = "/usgs/cpkgs/isis3/data/mgs/testData/ab102401.cub"; + //string inFile = "/work1/tsucharski/poly/I17621017RDR_lev2.cub"; + // same MOC image, but sinusoidal projection + //string inFile = "/farm/prog1/tsucharski/isis3/ab102401.lev2.cub"; + + // same MOC image, but sinusoidal projection , doctored left edge + //string inFile = "/farm/prog1/tsucharski/isis3/ab102401.lev2.leftTrim.cub"; + + // MOC north pole image + //string inFile = "/work1/tsucharski/isis3/poly/e0202226.lev1.cub"; + + // MOC image with 0/360 boundary + // orkin + //string inFile = "/farm/prog1/tsucharski/isis3/cubes/m0101631.lev1.cub"; + // blackflag + //string inFile = "/work1/tsucharski/isis3/poly/m0101631.lev1.cub"; + + // galileo ssi image + //string inFile = "/farm/prog1/tsucharski/isis3/6700r.cub"; + + + // Open the cube + Cube cube; + Cube cube1; + cube.Open(inFile, "r"); + + ImagePolygon poly; + try { + poly.Create(cube); + } + catch(iException &e) { + std::string msg = "Cannot create polygon for [" + cube.Filename() + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + + // write poly as WKT + std::cout << poly.Polys()->toString() << std::endl; + + // Test sub-poly option + try { + poly.Create(cube, 12, 1, 384, 640, 385); + } + catch(iException &e) { + std::string msg = "Cannot create sub-polygon for [" + cube.Filename() + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + // write poly as WKT + std::cout << poly.Polys()->toString() << std::endl; + + + // Test lower quality option + try { + poly.Create(cube, 10, 12, 1, 384, 640, 385); + } + catch(iException &e) { + std::string msg = "Cannot create lower quality polygon for [" + cube.Filename() + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + // write poly as WKT + std::cout << poly.Polys()->toString() << std::endl; + + + + cube.Close(); +} + diff --git a/isis/src/base/objs/InfixToPostfix/InfixToPostfix.cpp b/isis/src/base/objs/InfixToPostfix/InfixToPostfix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a867465872bec62797ec116f7fb3fcb10cfb191 --- /dev/null +++ b/isis/src/base/objs/InfixToPostfix/InfixToPostfix.cpp @@ -0,0 +1,680 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/04/08 15:14:13 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "InfixToPostfix.h" +#include "iException.h" +#include + +using namespace std; + +namespace Isis { + //! Constructor + InfixToPostfix::InfixToPostfix() { + Initialize(); + } + + InfixToPostfix::~InfixToPostfix() { + Uninitialize(); + } + + /** + * This populates the known operators/functions list. If the operators list + * is not empty, this function will do nothing. + */ + void InfixToPostfix::Initialize() { + p_operators.push_back(new InfixOperator(7, "^")); + p_operators.push_back(new InfixOperator(5, "/")); + p_operators.push_back(new InfixOperator(5, "*")); + p_operators.push_back(new InfixOperator(3, "<<")); + p_operators.push_back(new InfixOperator(3, ">>")); + p_operators.push_back(new InfixOperator(2, "+")); + p_operators.push_back(new InfixOperator(2, "-")); + p_operators.push_back(new InfixOperator(1, ">")); + p_operators.push_back(new InfixOperator(1, "<")); + p_operators.push_back(new InfixOperator(1, ">=")); + p_operators.push_back(new InfixOperator(1, "<=")); + p_operators.push_back(new InfixOperator(1, "==")); + p_operators.push_back(new InfixOperator(1, "!=")); + p_operators.push_back(new InfixOperator(-1, "(")); + + // This makes multiple argument functions work + p_operators.push_back(new InfixOperator(-1, ",")); + + p_operators.push_back(new InfixFunction("--", 1)); + p_operators.push_back(new InfixFunction("sqrt", 1)); + p_operators.push_back(new InfixFunction("abs", 1)); + p_operators.push_back(new InfixFunction("sin", 1)); + p_operators.push_back(new InfixFunction("cos", 1)); + p_operators.push_back(new InfixFunction("tan", 1)); + p_operators.push_back(new InfixFunction("csc", 1)); + p_operators.push_back(new InfixFunction("sec", 1)); + p_operators.push_back(new InfixFunction("cot", 1)); + p_operators.push_back(new InfixFunction("asin", 1)); + p_operators.push_back(new InfixFunction("acos", 1)); + p_operators.push_back(new InfixFunction("atan", 1)); + p_operators.push_back(new InfixFunction("atan2", 2)); + p_operators.push_back(new InfixFunction("sinh", 1)); + p_operators.push_back(new InfixFunction("cosh", 1)); + p_operators.push_back(new InfixFunction("tanh", 1)); + p_operators.push_back(new InfixFunction("asinh", 1)); + p_operators.push_back(new InfixFunction("acosh", 1)); + p_operators.push_back(new InfixFunction("atanh", 1)); + p_operators.push_back(new InfixFunction("log", 1)); + p_operators.push_back(new InfixFunction("log10", 1)); + p_operators.push_back(new InfixFunction("ln", 1)); + p_operators.push_back(new InfixFunction("cubemin", 1)); + p_operators.push_back(new InfixFunction("cubemax", 1)); + p_operators.push_back(new InfixFunction("linemin", 1)); + p_operators.push_back(new InfixFunction("linemax", 1)); + p_operators.push_back(new InfixFunction("min", 2)); + p_operators.push_back(new InfixFunction("max", 2)); + p_operators.push_back(new InfixFunction("line", 0)); + p_operators.push_back(new InfixFunction("sample", 0)); + p_operators.push_back(new InfixFunction("band", 0)); + p_operators.push_back(new InfixFunction("pi", 0)); + p_operators.push_back(new InfixFunction("e", 0)); + } + + /** + * This cleans the known operators/functions list. + */ + void InfixToPostfix::Uninitialize() { + for(int i = 0; i < p_operators.size(); i ++) { + delete p_operators[i]; + } + + p_operators.clear(); + } + + /** + * This function takes a space-delimited string and removes empty + * delimiters. In order words, it compresses the spaces. This is used + * to keep strings small, clean, and remove the necessity to check for + * empty tokens constantly. + * + * That is, if your string is "a b" the result will be "a b". + * + * @param equation A space-delimited string with excessive spaces + * + * @return iString A space-delimited string with data between every pair of spaces + */ + iString InfixToPostfix::CleanSpaces(iString equation) { + iString clean = ""; + while(!equation.empty()) { + iString data = equation.Token(" "); + if(data.empty()) { + continue; + } + + if(clean.empty()){ + clean = data; + } + else { + clean += " " + data; + } + } + + return clean; + } + + /** + * This method converts infix to postfix. It uses an enhanced verion of + * the algorithm found on page 159 of "Data Structures & Algorithms in Java" + * Second Edition by Robert Lafore. First, we prep the equation with + * TokenizeEquation and then parse through it using the known-good algorithm. + * + * @param infix The infix equation + * + * @return iString The postfix equation + */ + iString InfixToPostfix::Convert(const iString &infix) { + // Prep our equation for the conversion + iString equation = TokenizeEquation(infix); + iString postfix = ""; + + // The algorithm uses a stack + std::stack theStack; + + // Use this to look for two operands in a row. If we find such, + // then we know the infix equation is bogus. + int numConsecutiveOperands = 0; + + // Use this to look for two operators in a row. If we find such, + // then we know the infix equation is bogus. + int numConsecutiveOperators = 0; + + // We'll use tokens to get through the entire equation, which is space-delimited + // because of TokenizeEquation. So continue processing until we're out of tokens + // and the string is empty. + while(!equation.empty()) { + + // There will be no empty tokens, so don't worry about checking for it. + // TokenizeEquation cleans excess spaces in it's return value. + iString data = equation.Token(" "); + + if(data.compare("(") == 0) { + theStack.push(*FindOperator(data)); + } + else if(data.compare(")") == 0) { + CloseParenthesis(postfix, theStack); + } + else if(IsKnownSymbol(data)) { + AddOperator(postfix, *FindOperator(data), theStack); + + if(IsFunction(data)) { + // For a general check, zero single argument functions the + // same as an operand. + if(((InfixFunction*)FindOperator(data))->ArgumentCount() == 0) { + numConsecutiveOperators = 0; + numConsecutiveOperands ++; + } + else { + // We have a function with arguments, an operand or function call is expected next + numConsecutiveOperators = 1; + numConsecutiveOperands = 0; + } + } + else { + // We found an operator, not a function, so we expect a number next + numConsecutiveOperators ++; + numConsecutiveOperands = 0; + } + } + else { + try { + // Make sure this is truly an operand and not an operator by casting it + (double)data; + } + catch(iException e) { + iException::Clear(); + throw iException::Message(iException::User, "The operator '" + data + "' is not recognized.", _FILEINFO_); + } + + // This was clearly an operand at this point + numConsecutiveOperators = 0; + numConsecutiveOperands ++; + + postfix += ' ' + data + ' '; + } + + // If we found consecutive operators or operands, tell the user + if(numConsecutiveOperators > 1) { + throw iException::Message(iException::User, "Missing an operand near the operator '" + data + "'.", _FILEINFO_); + } + else if(numConsecutiveOperands > 1) { + throw iException::Message(iException::User, "Missing an operator before " + data + ".", _FILEINFO_); + } + } + + while(!theStack.empty()) { + iString op = theStack.top().OutputString(); + + // Any opening parentheses here are invalid at this point + if(op == "(") { + throw iException::Message(iException::User, + "There are too many opening parentheses ('(') in the equation.", + _FILEINFO_); + } + + postfix += ' ' + op + ' '; + theStack.pop(); + } + + // The , is set to an operator that causes multiple-argument functions to work, but + // it needs to be stripped out for postfix. This is the correct way to do it. + postfix = postfix.Remove(","); + + // Clean spaces just to double check and return our postfix answer + return CleanSpaces(postfix); + } + + /** + * This method will return true if it believes the argument represents + * a valid function or operator. + * + * @param representation The symbolic representation of the operator, such as 'sin' + * + * @return bool True if it looks valid, false if it's not known + */ + bool InfixToPostfix::IsKnownSymbol(iString representation) { + for(int i = 0; i < p_operators.size(); i++) { + if(representation.compare(p_operators[i]->InputString()) == 0) { + return true; + } + } + + return false; + } + + /** + * This method will return true if 'representation' is a known function. + * + * @param representation The symbolic representation of a function, such as 'abs' + * + * @return bool True if it's a known function, false otherwise + */ + bool InfixToPostfix::IsFunction(iString representation) { + if(IsKnownSymbol(representation)) { + return FindOperator(representation)->IsFunction(); + } + else { + return false; + } + } + + /** + * This is straight from the algorithm found on page 159 of "Data Structures & Algorithms in Java" + * Second Edition by Robert Lafore. + * + * @param postfix The postix generated thus far + * @param op The operator + * @param theStack The operator stack + */ + void InfixToPostfix::AddOperator(iString &postfix, const InfixOperator &op, std::stack &theStack) { + while(!theStack.empty()) { + InfixOperator top = theStack.top(); + theStack.pop(); + + if(top.InputString().compare("(") == 0) { + theStack.push(top); + break; + } + + if(top.Precedence() < op.Precedence()) { + theStack.push(top); + break; + } + else { + postfix += ' ' + top.OutputString() + ' '; + } + } + + theStack.push(op); + } + + /** + * This is straight from the algorithm found on page 159 of "Data Structures & Algorithms in Java" + * Second Edition by Robert Lafore. + * + * @param postfix The postix generated thus far + * @param theStack The operator stack + */ + void InfixToPostfix::CloseParenthesis(iString &postfix, std::stack &theStack) { + bool openingFound = false; + while(!theStack.empty()) { + InfixOperator op = theStack.top(); + theStack.pop(); + + if(op.InputString().compare("(") == 0) { + openingFound = true; + break; + } + else { + postfix += ' ' + op.OutputString() + ' '; + } + } + + if(!openingFound) { + throw iException::Message(iException::User, + "There are too many closing parentheses (')') in the equation.", + _FILEINFO_); + } + } + + /** + * This method will return a pointer to the operator represented by + * 'representation.' Because in this model a function is an operator, + * this will return a pointer to functions as well (in a base class pointer). + * + * @param representation The symbolic representation of the operator, such as '+' + * + * @return InfixOperator* A pointer to the operator object that contains known information about the operator + */ + InfixOperator *InfixToPostfix::FindOperator(iString representation) { + for(int i = 0; i < p_operators.size(); i++) { + if(representation.compare(p_operators[i]->InputString()) == 0) { + return p_operators[i]; + } + } + + // Nothing found + throw iException::Message(iException::User, "The operator '" + representation + "' is not recognized.", _FILEINFO_); + } + + /** + * This method will add spaces between all operators and numbers, making it + * possible to get each element of the equation one by one. It will also parse + * out the function calls, adding parenthesis where needed so the user doesn't + * have to. The result is an equation ready for parsing (but NOT fully parenthesized, + * just enough to make sure our algorithm makes no mistakes). + * + * @param equation An unformatted infix equation + * + * @return iString A tokenized equation with additional parentheses + */ + iString InfixToPostfix::TokenizeEquation(const iString &equation) { + iString output = ""; + + // Insert whitespace, make everything lowercase, and change all braces to + // parenthesis + for(unsigned int i = 0; i < equation.size(); i++) { + // Ensure there is whitespace in the equation + if(!isalnum(equation[i]) && !isspace(equation[i]) && equation[i] != '.') { + // Convert all braces to parens + if(equation[i] == '[' || equation[i] == '{') { + output += " ( "; + } + else if(equation[i] == ']' || equation[i] == '}') { + output += " ) "; + } + // Test for multicharacter operators + else if(i < equation.size()-1 && equation[i] == '-' && equation[i+1] == '-') { + output += " -- "; + i++; + } + else if(i < equation.size()-1 && equation[i] == '<' && equation[i+1] == '<') { + output += " << "; + i++; + } + else if(i < equation.size()-1 && equation[i] == '>' && equation[i+1] == '>') { + output += " >> "; + i++; + } + else if(i < equation.size()-1 && equation[i] == '>' && equation[i+1] == '=') { + output += " >= "; + i++; + } + else if(i < equation.size()-1 && equation[i] == '<' && equation[i+1] == '=') { + output += " <= "; + i++; + } + else if(i < equation.size()-1 && equation[i] == '=' && equation[i+1] == '=') { + output += " == "; + i++; + } + else if(i < equation.size()-1 && equation[i] == '!' && equation[i+1] == '=') { + output += " != "; + i++; + } + // Take care of scientific notiation where the exponent is negative + else if((i > 1) && equation[i] == '-' && tolower(equation[i-1]) == 'e' && isalnum(equation[i-2])) { + output += equation[i]; + } + // Look for negative operator disguised as '-' + else if(equation[i] == '-') { + bool isNegative = true; + + // If we run into a '(' or the beginning, then the '-' must mean '--' really. + for(int index = i - 1; index >= 0; index --) { + if(equation[index] == ' ') { + continue; + } + + if(equation[index] != '(' && equation[index] != '/' && + equation[index] != '*' && equation[index] != '+') { + isNegative = false; + break; + } + + break; + } + + if(isNegative) { + output += " -- "; + } + else { + output += " - "; + } + } + else { + output += ' '; + output += equation[i]; + output += ' '; + } + } + else { + output += equation[i]; + } + } + + iString cleanedEquation = CleanSpaces(FormatFunctionCalls(output.DownCase())); + + return cleanedEquation; + } + + /** + * This method looks through equation for function calls, parenthesizes them, + * and calls itself again with each argument in order to parse any embedded functions. + * This ensures order of operations holds for cases like sin(.5)^2. This method might add + * too many parentheses, but that is harmless. This does not affect operators (excepting --) or + * numbers. Only functions. The input should be space-delimited. + * + * @param equation The unparenthesized equation + * + * @return iString The parenthesized equation + */ + iString InfixToPostfix::FormatFunctionCalls(iString equation) { + // Clean our space-delimited equation + equation = CleanSpaces(equation); + iString output = ""; + + // We'll use tokens to get through the entire equation, which is space-delimited. + // So continue processing until we're out of tokens and the string is empty. + while(!equation.empty()) { + iString element = equation.Token(" "); + + // Did we find a function? Figure out what it is! + if(IsFunction(element)) { + // Point to the function. We know if IsFunction returned true, + // the result is really a InfixFunction* + InfixFunction *func = (InfixFunction*)FindOperator(element); + + // We want to wrap the entire thing in parentheses, and it's argument string. + // So sin(.5)^2 becomes (sin(.5))^2 + output += " ( " + func->InputString() + " ("; + + // Deal with 0-argument functions + if(func->ArgumentCount() == 0) { + iString next = equation.Token(" "); + + // If they didn't add parentheses around the zero-argument + // function, we still know what they mean. Close the arguments + // and the wrapping parentheses. + if(next != "(") { + output += " ) ) "; + + // Step back, we did too much + equation = next + " " + equation; + } + else { + // We see a zero-arg function, and we grabbed an open parenthesis from it. + // Make sure the next thing is a close or we have a problem. + if(equation.Token(" ") != ")") { + throw iException::Message(iException::User, + "The function " + func->InputString() + " should not have any arguments.", + _FILEINFO_); + } + + // Close the arguments and the wrapping parentheses. They wrote their call correct :) + output += " ) ) "; + } + } + else { + // Deal with 1+ argument functions by parsing out the arguments + + // Make sure the user put parentheses around these, otherwise we're left in the dark. + if(func->ArgumentCount() > 1 && equation.Token(" ") != "(") { + throw iException::Message(iException::User, + "Missing parenthesis after " + func->InputString(), + _FILEINFO_); + } + + // Single argument missing parenthesis? + else if(func->ArgumentCount() == 1) { + iString argument = equation.Token(" "); + + if(argument != "(") { + // We might have a problem. They're calling a function without adding parentheses.... + // unless it's a negate, because we insert those, tell them their mistake. It's not + // my job to figure out what they mean! + if(func->InputString() != "--") { + throw iException::Message(iException::User, + "Missing parenthesis after " + func->InputString(), + _FILEINFO_); + } + + // It's a negate without parentheses, so they mean the next term? + if(!IsFunction(argument)) { + // If it isn't a function, it's safe to just append + output += " " + FormatFunctionCalls(argument) + " ) ) "; + continue; + } + else { + // We are negating a function result. We must do a mini-parse to figure out + // the function and resursively call, then append the negation. + iString functionName = argument; + iString openParen = equation.Token(" "); + + // No open parens? Call ourself again with this supposed function + if(openParen != "(") { + output += " " + FormatFunctionCalls(functionName) + " ) ) "; + equation = openParen + " " + equation; + continue; + } + else { + functionName += " ("; + } + + // Parse out our equation quickly, call ourself with it to properly handle it, + // and append the negation. + int numParens = 0; + while(numParens > -1) { + iString newElem = equation.Token(" "); + + if(newElem == "") { + throw iException::Message(iException::User, + "Missing closing parentheses after '" + argument + "'.", + _FILEINFO_); + } + + if(newElem == "(") numParens++; + else if(newElem == ")") numParens--; + + functionName += " " + newElem; + } + + output += " " + FormatFunctionCalls(functionName) + " ) ) "; + continue; + } + } + } + + /** + * This code block is for multi-parameter functions. Functions with 1+ parameters + * are parsed here, excepting the negation (with no parentheses) which is done just above. + * + * We figure out the arguments by looking for commas, outside of all parentheses, for each argument + * up until the last one. We look for an extra closing parenthesis for the last argument. When we figure + * out what an argument is, we recursively call FormatFunctionCalls to format any and all functionality + * inside of the argument. + */ + iString argument = ""; + int numParens = 0; + int argNum = 0; + while(argNum < func->ArgumentCount()) { + iString elem = equation.Token(" "); + + // Ran out of data, the function call is not complete. + if(elem == "") { + throw iException::Message(iException::User, + "The definition of '" + func->InputString() + "' is not complete.", + _FILEINFO_); + } + + if(elem == "(") { + numParens ++; + argument += " ("; + } + else if(elem == ")") { + numParens --; + + // Ignore last close, it's not part of the argument and will be added later + if(numParens != -1) { + argument += " )"; + } + } + else if(elem == "," && numParens == 0) { + CheckArgument(func->InputString(), argNum, argument); + argument = FormatFunctionCalls(argument); + output += " ( " + argument + " ) , "; + argNum++; + argument = ""; + + // Too many arguments? We don't expect a comma delimiter on the last argument. + if(argNum == func->ArgumentCount()) { + throw iException::Message(iException::User, + "There were too many arguments supplied to the function '" + func->InputString() + "'.", + _FILEINFO_); + } + } + else { + argument += " " + elem; + } + + if(argNum == func->ArgumentCount() - 1 && numParens == -1) { + CheckArgument(func->InputString(), argNum, argument); + argument = FormatFunctionCalls(argument); + // close function call & function wrap + output += " " + argument + " ) ) "; + argNum++; + argument = ""; + } + // Closed the function early? + else if(numParens == -1) { + throw iException::Message(iException::User, + "There were not enough arguments supplied to the function '" + func->InputString() + "'.", + _FILEINFO_); + } + } + } + } + // Not a function, preserve & ignore + else { + output = output + " " + element; + } + } + + return output; + } + + void InfixToPostfix::CheckArgument(iString funcName, int argNum, iString argument) { + argument = argument.Remove(" "); + argument = argument.Remove("("); + argument = argument.Remove(")"); + + if(argument == "") { + throw iException::Message(iException::User, + "Argument " + (iString)(argNum+1) + " in function " + funcName + " must not be empty.", + _FILEINFO_); + } + } +} diff --git a/isis/src/base/objs/InfixToPostfix/InfixToPostfix.h b/isis/src/base/objs/InfixToPostfix/InfixToPostfix.h new file mode 100644 index 0000000000000000000000000000000000000000..4235894e2bc1e7e2c564494cfe9cd47b72043d88 --- /dev/null +++ b/isis/src/base/objs/InfixToPostfix/InfixToPostfix.h @@ -0,0 +1,144 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/04/08 15:14:13 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef INFIXTOPOSTFIX_H_ +#define INFIXTOPOSTFIX_H_ + +#include "iString.h" +#include +#include + +namespace Isis { + class InfixOperator; + class InfixFunction; + +/** + * @brief Converter for math equations + * + * This class converts infix equations to postfix + * + * @ingroup Math + * + * @author 2007-08-21 Steven Lambright + * + * @internal + * @history 2007-08-22 Steven Lambright - Changed p_operators from + * vector to QList (static std::vector is unsafe) + * @history 2008-01-23 Steven Lambright - Added the operators (constants) + * PI and e + * @history 2010-02-23 Steven Lambright - Operator/Function input strings and + * output strings now separated + * @history 2010-04-08 Steven Lambright - Min, max functions expanded upon + */ + class InfixToPostfix { + public: + InfixToPostfix(); + virtual ~InfixToPostfix(); + + iString Convert(const iString &infix); + iString TokenizeEquation(const iString &equation); + + protected: + + virtual bool IsKnownSymbol(iString representation); + virtual InfixOperator *FindOperator(iString representation); + + QList p_operators; + private: + void Initialize(); + void Uninitialize(); + + iString FormatFunctionCalls(iString equation); + iString CleanSpaces(iString equation); + + void CloseParenthesis(iString &postfix, std::stack &theStack); + void AddOperator(iString &postfix, const InfixOperator &op, std::stack &theStack); + bool IsFunction(iString representation); + void CheckArgument(iString funcName, int argNum, iString argument); + }; + + /** + * InfixOperator and InfixFunction are helper classes for InfixToPostfix + */ + class InfixOperator { + public: + InfixOperator(int prec, iString inString, bool isFunc = false) { + m_precedence = prec; + m_inputString = inString; + m_outputString = inString; + m_isFunction = isFunc; + } + + InfixOperator(int prec, iString inString, iString outString, + bool isFunc = false) { + m_precedence = prec; + m_inputString = inString; + m_outputString = outString; + m_isFunction = isFunc; + } + + const iString &InputString() const { + return m_inputString; + } + + const iString &OutputString() const { + return m_outputString; + } + + int Precedence() const { + return m_precedence; + } + + bool IsFunction() const { + return m_isFunction; + } + + + private: + int m_precedence; + iString m_inputString; + iString m_outputString; + bool m_isFunction; + }; + + class InfixFunction : public InfixOperator { + public: + InfixFunction(iString inString, int argCount) : + InfixOperator(-1,inString,true) { + m_numArguments = argCount; + } + + InfixFunction(iString inString, iString outString, int argCount) : + InfixOperator(-1,inString,outString,true) { + m_numArguments = argCount; + } + + int ArgumentCount() const { + return m_numArguments; + } + + private: + int m_numArguments; + }; +}; + +#endif diff --git a/isis/src/base/objs/InfixToPostfix/InfixToPostfix.truth b/isis/src/base/objs/InfixToPostfix/InfixToPostfix.truth new file mode 100644 index 0000000000000000000000000000000000000000..dfdc9099399a47db5fc7492e3098509f51629554 --- /dev/null +++ b/isis/src/base/objs/InfixToPostfix/InfixToPostfix.truth @@ -0,0 +1,122 @@ +------------------------------------------------------- +Test InfixToPostfix + + +1: Convert '-4' to postfix + Tokenized equation: '( -- ( 4 ) )' + Postfix: '4 --' + + +2: Convert '1*2' to postfix + Tokenized equation: '1 * 2' + Postfix: '1 2 *' + + +3: Convert '((1)+(1))' to postfix + Tokenized equation: '( ( 1 ) + ( 1 ) )' + Postfix: '1 1 +' + + +4: Convert '1*2/2-2' to postfix + Tokenized equation: '1 * 2 / 2 - 2' + Postfix: '1 2 * 2 / 2 -' + + +5: Convert 'sin(5)' to postfix + Tokenized equation: '( sin ( 5 ) )' + Postfix: '5 sin' + + +6: Convert 'sin 5' to postfix +**USER ERROR** Missing parenthesis after sin + + +7: Convert '--sin(-(54+65))' to postfix + Tokenized equation: '( -- ( ( sin ( ( -- ( 54 + 65 ) ) ) ) ) )' + Postfix: '54 65 + -- sin --' + + +8: Convert '--sin(-54+--65)' to postfix + Tokenized equation: '( -- ( ( sin ( ( -- ( 54 ) ) + ( -- ( 65 ) ) ) ) ) )' + Postfix: '54 -- 65 -- + sin --' + + +9: Convert '2/3^6' to postfix + Tokenized equation: '2 / 3 ^ 6' + Postfix: '2 3 6 ^ /' + + +10: Convert 'atan2(5,--4)' to postfix + Tokenized equation: '( atan2 ( ( 5 ) , ( -- ( 4 ) ) ) )' + Postfix: '5 4 -- atan2' + + +11: Convert 'atan2(--5)' to postfix +**USER ERROR** There were not enough arguments supplied to the function 'atan2'. + + +12: Convert 'atan2(1,2,3)' to postfix +**USER ERROR** There were too many arguments supplied to the function 'atan2'. + + +13: Convert 'atan2(1,)' to postfix +**USER ERROR** Argument 2 in function atan2 must not be empty. + + +14: Convert 'atan2(1,2' to postfix +**USER ERROR** The definition of 'atan2' is not complete. + + +15: Convert '999-548-126^2' to postfix + Tokenized equation: '999 - 548 - 126 ^ 2' + Postfix: '999 548 - 126 2 ^ -' + + +16: Convert 'sin(0)^2' to postfix + Tokenized equation: '( sin ( 0 ) ) ^ 2' + Postfix: '0 sin 2 ^' + + +17: Convert 'somefunc(5)' to postfix + Tokenized equation: 'somefunc ( 5 )' +**USER ERROR** The operator 'somefunc' is not recognized. + + +18: Convert '3#3' to postfix + Tokenized equation: '3 # 3' +**USER ERROR** The operator '#' is not recognized. + + +19: Convert '(3)(2)' to postfix + Tokenized equation: '( 3 ) ( 2 )' +**USER ERROR** Missing an operator before 2. + + +20: Convert '(3)(2)' to postfix + Tokenized equation: '( 3 ) ( 2 )' +**USER ERROR** Missing an operator before 2. + + +21: Convert 'atan2(1+2/3^(--6), 5^ (tan ( 42 ^ (1 / --264) / 4 ) - 65 ) != 0)' to postfix + Tokenized equation: '( atan2 ( ( 1 + 2 / 3 ^ ( ( -- ( 6 ) ) ) ) , 5 ^ ( ( tan ( 42 ^ ( 1 / ( -- ( 264 ) ) ) / 4 ) ) - 65 ) != 0 ) )' + Postfix: '1 2 3 6 -- ^ / + 5 42 1 264 -- / ^ 4 / tan 65 - ^ 0 != atan2' + + +22: Convert '1++2' to postfix + Tokenized equation: '1 + + 2' +**USER ERROR** Missing an operand near the operator '+'. + + +23: Convert '1+-2' to postfix + Tokenized equation: '1 + ( -- ( 2 ) )' + Postfix: '1 2 -- +' + + +24: Convert '(1+3*(4)' to postfix + Tokenized equation: '( 1 + 3 * ( 4 )' +**USER ERROR** There are too many opening parentheses ('(') in the equation. + + +25: Convert '(1+3*(4)))' to postfix + Tokenized equation: '( 1 + 3 * ( 4 ) ) )' +**USER ERROR** There are too many closing parentheses (')') in the equation. diff --git a/isis/src/base/objs/InfixToPostfix/Makefile b/isis/src/base/objs/InfixToPostfix/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c613025ae8718edab222ef70b43696ef17c40847 --- /dev/null +++ b/isis/src/base/objs/InfixToPostfix/Makefile @@ -0,0 +1,5 @@ +INCS = InfixToPostfix.h +SRCS = InfixToPostfix.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/InfixToPostfix/unitTest.cpp b/isis/src/base/objs/InfixToPostfix/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ff43319a6ca370aac0b2b57505c6d60f4e14eeae --- /dev/null +++ b/isis/src/base/objs/InfixToPostfix/unitTest.cpp @@ -0,0 +1,60 @@ +#include "Calculator.h" +#include "InfixToPostfix.h" +#include "Preference.h" +#include + +using namespace std; +using namespace Isis; + +int main(int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + + cout << "-------------------------------------------------------" << endl; + cout << "Test InfixToPostfix" << endl; + + const int NUM_EQUATIONS = 25; + iString equations[NUM_EQUATIONS] = { + "-4", + "1*2", + "((1)+(1))", + "1*2/2-2", + "sin(5)", + "sin 5", + "--sin(-(54+65))", + "--sin(-54+--65)", + "2/3^6", + "atan2(5,--4)", + "atan2(--5)", + "atan2(1,2,3)", + "atan2(1,)", + "atan2(1,2", + "999-548-126^2", + "sin(0)^2", + "somefunc(5)", + "3#3", + "(3)(2)", // Can't detect the problem here yet because f3 and f2 are functions/operators + "(3)(2)", + "atan2(1+2/3^(--6), 5^ (tan ( 42 ^ (1 / --264) / 4 ) - 65 ) != 0)", + "1++2", // This doesn't work + "1+-2", // This does work, however, because -2 is a negation and not a subtract. + "(1+3*(4)", + "(1+3*(4)))" + }; + + InfixToPostfix converter; + for(int equation = 0; equation < NUM_EQUATIONS; equation ++) { + cout << endl << endl << equation+1 << ": Convert '" << equations[equation] << "' to postfix" << endl; + + try { + iString tokenized = converter.TokenizeEquation(equations[equation]); + cout << " Tokenized equation: '" << tokenized << "'" << endl; + iString postfix = converter.Convert(equations[equation]); + cout << " Postfix: '" << postfix << "'" << endl; + } + catch(iException e) { + e.Report(false); + iException::Clear(); + } + } +} diff --git a/isis/src/base/objs/InterestOperator/InterestOperator.cpp b/isis/src/base/objs/InterestOperator/InterestOperator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bc9186bc6fc5e4ac447bf2a2acc2620f8161fdc6 --- /dev/null +++ b/isis/src/base/objs/InterestOperator/InterestOperator.cpp @@ -0,0 +1,784 @@ +#include "Chip.h" +#include "Pvl.h" +#include "InterestOperator.h" +#include "Plugin.h" +#include "iException.h" +#include "Filename.h" +#include "Statistics.h" +#include "PolygonTools.h" +#include "SpecialPixel.h" +#include "ControlNet.h" +#include "ImageOverlapSet.h" +#include "ImagePolygon.h" +#include "PolygonTools.h" + +//#define _DEBUG_ + +namespace Isis { + +#ifdef _DEBUG_ + //debugging + fstream ostm; + + void StartDebug() { + ostm.open("Debug.log", std::ios::out | std::ios::app); + ostm << "\n*************************\n"; + } + + void CloseDebug() { + ostm << "\n*************************\n"; + ostm.close(); + } +#endif + + /** + * Create InterestOperator object. Because this is a pure virtual class you can + * not create an InterestOperator class directly. Instead, see the InterestOperatorFactory + * class. + * + * @param pvl A pvl object containing a valid InterestOperator specification + * + * @see automaticRegistration.doc + */ + InterestOperator::InterestOperator(Pvl &pPvl): CnetValidMeasure(pPvl) { + p_interestAmount = 0.0; + p_worstInterest = 0.0; + p_lines = 1; + p_samples = 1; + p_deltaSamp = 0; + p_deltaLine = 0; + p_clipPolygon = NULL; + mbOverlaps = false; + + mOperatorGrp = PvlGroup("InterestOptions"); + Parse(pPvl); + +#ifdef _DEBUG_ + StartDebug(); +#endif + } + + + //! Destroy InterestOperator object + InterestOperator::~InterestOperator() { + if(p_clipPolygon != NULL) delete p_clipPolygon; +#ifdef _DEBUG_ + CloseDebug(); +#endif + } + + + /** + * Create an InterestOperator object using a PVL specification. + * An example of the PVL required for this is: + * + * @code + * Object = InterestOperator + * Group = Operator + * Name = StandardDeviation + * Samples = 21 + * Lines = 21 + * DeltaLine = 50 + * DeltaSamp = 25 + * EndGroup + * EndObject + * @endcode + * + * There are many other options that can be set via the pvl and are + * described in other documentation (see below). + * + *@param pvl The pvl object containing the specification + * + * @history 2010-04-09 Sharmila Prasad Check for validity of new keyword "MaxEmissionAngle" + * @history 2010-06-10 Sharmila Prasad Parse only Interest specific keywords and store in Operator group + **/ + void InterestOperator::Parse(Pvl &pPvl) { + try { + // Get info from the operator group + // Required Parameters + PvlGroup &op = pPvl.FindGroup("Operator", Pvl::Traverse); + + mOperatorGrp += Isis::PvlKeyword(op["Name"]); + + p_samples = op["Samples"]; + mOperatorGrp += Isis::PvlKeyword("Samples", p_samples); + + p_lines = op["Lines"]; + mOperatorGrp += Isis::PvlKeyword("Lines", p_lines); + + p_deltaLine = op["DeltaLine"]; + mOperatorGrp += Isis::PvlKeyword("DeltaLine", p_deltaLine); + + p_deltaSamp = op["DeltaSamp"]; + mOperatorGrp += Isis::PvlKeyword("DeltaSamp", p_deltaSamp); + + p_minimumInterest = op["MinimumInterest"]; + mOperatorGrp += Isis::PvlKeyword("MinimumInterest", p_minimumInterest); + + } + catch(iException &e) { + std::string msg = "Improper format for InterestOperator PVL [" + pPvl.Filename() + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + /** + * Initialise the InterestResults structure given the index + * + * @author Sharmila Prasad (6/8/2010) + * + * @param piIndex + */ + void InterestOperator::InitInterestResults(int piIndex) { + mtInterestResults[piIndex].msSerialNum = ""; + mtInterestResults[piIndex].mdInterest = Isis::Null; + mtInterestResults[piIndex].mdBestSample = Isis::Null; + mtInterestResults[piIndex].mdBestLine = Isis::Null; + mtInterestResults[piIndex].mdOrigSample = Isis::Null; + mtInterestResults[piIndex].mdOrigLine = Isis::Null; + mtInterestResults[piIndex].mdEmission = 135; + mtInterestResults[piIndex].mdIncidence = 135; + mtInterestResults[piIndex].mdDn = Isis::ValidMinimum; + mtInterestResults[piIndex].mdResolution = DBL_MAX ; + mtInterestResults[piIndex].miDeltaSample = 0; + mtInterestResults[piIndex].miDeltaLine = 0; + mtInterestResults[piIndex].mbValid = false; + } + + /** + * Walk the pattern chip through the search chip to find the best interest + * + * @param cube [in] The Isis::Cube to look for an interesting area in + * @param piSample [in] The sample postion in the cube where the chip is located + * @param piLine [in] The line postion in the cube where the chip is located + * @param pUnivGrndMap Reference to the Universal Ground map of this image + * @return Returns the status of the operation. The following conditions can + * occur true=Success, false=Failed + * + * @history 2010-03-30 Sharmila Prasad - Check for valid DN Value and Emission Angle in + * the user defined ValidMin-ValidMax range when selecting point of interest + * in a Control Measure + * @history 2010-06-23 Sharmila Prasad - Validate for Resolution Range and Pixels/Meters from edge options + */ + bool InterestOperator::Operate(Cube &pCube, UniversalGroundMap &pUnivGrndMap, int piSample, int piLine) { + + if(!pUnivGrndMap.HasCamera()) { // Level 3 images/mosaic or bad image + std::string msg = "Cannot run interest on images with no camera. Image " + pCube.Filename() + " has no Camera"; + throw Isis::iException::Message(Isis::iException::Programmer, msg, _FILEINFO_); + } + + int pad = Padding(); + Chip chip(2 * p_deltaSamp + p_samples + pad, 2 * p_deltaLine + p_lines + pad); + chip.TackCube(piSample, piLine); + if(p_clipPolygon != NULL) chip.SetClipPolygon(*p_clipPolygon); + chip.Load(pCube); + + // Walk the search chip and find the best interest + int iBestSamp = 0; + int iBestLine = 0; + double dSmallestDist = DBL_MAX; + double dBestInterest = Isis::Null; + int iLines = 2 * p_deltaLine + p_lines / 2 + 1; + int iSamples = 2 * p_deltaSamp + p_samples / 2 + 1; + bool bCalculateInterest = false; + + for(int lin = p_lines / 2 + 1; lin <= iLines; lin++) { + for(int samp = p_samples / 2 + 1; samp <= iSamples; samp++) { + // Cannot take dnValues from the chip as it contains the interpolated dnValue + // hence get the dn values directly from the cube + chip.SetChipPosition((double)samp, (double)lin); + + bCalculateInterest = false; + if(ValidStandardOptions(chip.CubeSample(), chip.CubeLine(), &pCube)) { + bCalculateInterest = true; + } + + if(bCalculateInterest) { + Chip subChip = chip.Extract(p_samples + pad, p_lines + pad, samp, lin); + double interest = Interest(subChip); + if(interest != Isis::Null) { + if((dBestInterest == Isis::Null) || CompareInterests(interest, dBestInterest)) { + double dist = std::sqrt(std::pow(piSample - samp, 2.0) + std::pow(piLine - lin, 2.0)); + if(interest == dBestInterest && dist > dSmallestDist) { + continue; + } + else { + dBestInterest = interest; + iBestSamp = samp; + iBestLine = lin; + dSmallestDist = dist; + } + } + } + } + } + } + + // Check to see if we went through the interest chip and never got a interest at + // any location. + if(dBestInterest == Isis::Null || dBestInterest < p_minimumInterest) { + if(pUnivGrndMap.SetImage(piSample, piLine)) { + p_interestAmount = dBestInterest; + } + return false; + } + + p_interestAmount = dBestInterest; + chip.SetChipPosition(iBestSamp, iBestLine); + p_cubeSample = chip.CubeSample(); + p_cubeLine = chip.CubeLine(); + + return true; + } + + /** + * Read the Serial#'s and overlaplist if any and call API to find the reference + * for all the points in the network + * + * @author Sharmila Prasad (6/9/2010) + * + * @param psSerialNumFile + * @param psOverlapListFile + * @param pOrigNet + * @param pNewNet + */ + void InterestOperator::Operate(const ControlNet &pOrigNet, ControlNet &pNewNet, std::string psSerialNumFile, std::string psOverlapListFile) { + ReadSerialNumbers(psSerialNumFile); + + // Find all the overlaps between the images in the FROMLIST + // The overlap polygon coordinates are in Lon/Lat order + if(psOverlapListFile != "") { + mOverlaps.ReadImageOverlaps(psOverlapListFile); + mbOverlaps = true; + } + + // Process the entire control net by calculating interest and moving the + // point to a more interesting area + FindCnetRef(pOrigNet, pNewNet); + } + + /** + * This traverses all the control points and measures in the network and + * checks for valid Measure which passes the Emission Incidence Angle, DN value tests + * and picks the Measure with the best Interest as the Reference + * + * @author Sharmila Prasad (5/14/2010) + * + * @return none + */ + void InterestOperator::FindCnetRef(const ControlNet &pOrigNet, ControlNet &pNewNet) { + int iPointsModified = 0; + int iMeasuresModified = 0; + int iRefChanged = 0; + + //Status Report + mStatus.SetText("Choosing Reference by Interest..."); + mStatus.SetMaximumSteps(pOrigNet.Size()); + mStatus.CheckStatus(); + + // Process each existing control point in the network + for(int point = 0; point < pOrigNet.Size(); ++point) { + ControlPoint &origPnt = ((ControlNet &) pOrigNet)[point]; + + // Logging + PvlObject pvlPointObj("PointDetails"); + pvlPointObj += Isis::PvlKeyword("PointId", origPnt.Id()); + + // Create a new control point + ControlPoint newPnt; + newPnt.SetId(origPnt.Id()); + newPnt.SetType(origPnt.Type()); + + int iOrigRefIndex = origPnt.ReferenceIndexNoException(); + + // Only perform the interest operation on points of type "Tie" and + // Points having atleast 1 measure and Point is not Ignored + if(!origPnt.Ignore() && origPnt.Type() == ControlPoint::Tie && iOrigRefIndex >= 0) { + + int iBestMeasureIndex = InterestByPoint(origPnt); + + // Process for point with good interest and a best index + double dReferenceLat = 0, dReferenceLon = 0; + if(iBestMeasureIndex >= 0) { + std::string sn = mtInterestResults[iBestMeasureIndex].msSerialNum; + Cube *bestCube = mCubeMgr.OpenCube(mSerialNumbers.Filename(sn)); + + // Get the Camera for the reference image and get the lat/lon from that measurment + Camera *bestCamera; + try { + bestCamera = bestCube->Camera(); + } + catch(Isis::iException &e) { + std::string msg = "Cannot Create Camera for Image:" + mSerialNumbers.Filename(sn); + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + + double dBestSample = mtInterestResults[iBestMeasureIndex].mdBestSample; + double dBestLine = mtInterestResults[iBestMeasureIndex].mdBestLine; + + bestCamera->SetImage(dBestSample, dBestLine); + dReferenceLat = bestCamera->UniversalLatitude(); + dReferenceLon = bestCamera->UniversalLongitude(); + } + + // Create a measurment for each image in this point using + // the reference lat/lon. + int iNumIgnore = 0; + for(int measure = 0; measure < origPnt.Size(); ++measure) { + ControlMeasure newMeasure(origPnt[measure]); + newMeasure.SetDateTime(); + newMeasure.SetChooserName("Application cnetref(interest)"); + std::string sn = newMeasure.CubeSerialNumber(); + + // Log + PvlGroup pvlMeasureGrp("MeasureDetails"); + pvlMeasureGrp += Isis::PvlKeyword("SerialNum", sn); + pvlMeasureGrp += Isis::PvlKeyword("OriginalLocation", LocationString(newMeasure.Sample(), newMeasure.Line())); + + // Initialize the UGM of this cube with the reference lat/lon + if(!newMeasure.Ignore() && iBestMeasureIndex >= 0 && mtInterestResults[iBestMeasureIndex].mdInterest != WorstInterest()) { + Cube *measureCube = mCubeMgr.OpenCube(mSerialNumbers.Filename(sn)); + + // default setting + newMeasure.SetIgnore(false); + newMeasure.SetReference(false); + + // Get the Camera + Camera *measureCamera; + try { + measureCamera = measureCube->Camera(); + } + catch(Isis::iException &e) { + std::string msg = "Cannot Create Camera for Image:" + mSerialNumbers.Filename(sn); + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + + if(measureCamera->SetUniversalGround(dReferenceLat, dReferenceLon) && measureCamera->InCube()) { + // Check for reference, Put the corresponding line/samp into a newMeasure + if(measure == iBestMeasureIndex) { + newMeasure.SetCoordinate(mtInterestResults[measure].mdBestSample, mtInterestResults[measure].mdBestLine, ControlMeasure::Estimated); + newMeasure.SetReference(true); + + pvlMeasureGrp += Isis::PvlKeyword("NewLocation", LocationString(mtInterestResults[measure].mdBestSample, mtInterestResults[measure].mdBestLine)); + pvlMeasureGrp += Isis::PvlKeyword("DeltaSample", mtInterestResults[measure].miDeltaSample); + pvlMeasureGrp += Isis::PvlKeyword("DeltaLine", mtInterestResults[measure].miDeltaLine); + pvlMeasureGrp += Isis::PvlKeyword("Reference", "true"); + } + else { + double dSample = measureCamera->Sample(); + double dLine = measureCamera->Line(); + if(!ValidStandardOptions(dSample, dLine, measureCube)) { + iNumIgnore++; + pvlMeasureGrp += Isis::PvlKeyword("Ignored", "Failed Emission, Incidence, Resolution and/or Dn Value Test"); + newMeasure.SetIgnore(true); + } + pvlMeasureGrp += Isis::PvlKeyword("NewLocation", LocationString(dSample, dLine)); + pvlMeasureGrp += Isis::PvlKeyword("DeltaSample", (int)abs((int)dSample - (int)origPnt[measure].Sample())); + pvlMeasureGrp += Isis::PvlKeyword("DeltaLine", (int)abs((int)dLine - (int)origPnt[measure].Line())); + pvlMeasureGrp += Isis::PvlKeyword("Reference", "false"); + newMeasure.SetCoordinate(dSample, dLine, origPnt[measure].Type()); + } + } + else { + iNumIgnore++; + pvlMeasureGrp += Isis::PvlKeyword("Ignored", "True"); + newMeasure.SetIgnore(true); + if(!measureCamera->InCube()) { + pvlMeasureGrp += Isis::PvlKeyword("Comments", "New location is not in the Image"); + } + } + } + // no best interest, ignore the measure + else { + iNumIgnore++; + pvlMeasureGrp += Isis::PvlKeyword("Ignored", "True"); + newMeasure.SetIgnore(true); + } + newPnt.Add(newMeasure); + + if(newMeasure != origPnt[measure]) { + iMeasuresModified ++; + } + + pvlMeasureGrp += Isis::PvlKeyword("BestInterest", mtInterestResults[measure].mdInterest); + pvlMeasureGrp += Isis::PvlKeyword("EmissionAngle", mtInterestResults[measure].mdEmission); + pvlMeasureGrp += Isis::PvlKeyword("IncidenceAngle", mtInterestResults[measure].mdIncidence); + pvlMeasureGrp += Isis::PvlKeyword("Resolution", mtInterestResults[measure].mdResolution); + pvlMeasureGrp += Isis::PvlKeyword("DNValue", mtInterestResults[measure].mdDn); + pvlPointObj += pvlMeasureGrp; + } // Measures Loop + + //check the ignored measures number + if((origPnt.Size() - iNumIgnore) < 2) { + newPnt.SetIgnore(true); + pvlPointObj += Isis::PvlKeyword("Ignored", "Good Measures less than 2"); + } + + pNewNet.Add(newPnt); + iNumIgnore = 0; + + if(newPnt != origPnt) { + iPointsModified ++; + } + + if(!newPnt.Ignore() && iBestMeasureIndex != iOrigRefIndex) { + iRefChanged ++; + PvlGroup pvlRefChangeGrp("ReferenceChangeDetails"); + pvlRefChangeGrp += Isis::PvlKeyword("PrevSerialNumber", mtInterestResults[iOrigRefIndex].msSerialNum); + pvlRefChangeGrp += Isis::PvlKeyword("PrevBestInterest", mtInterestResults[iOrigRefIndex].mdInterest); + pvlRefChangeGrp += Isis::PvlKeyword("PrevLocation", LocationString(mtInterestResults[iOrigRefIndex].mdOrigSample, mtInterestResults[iOrigRefIndex].mdOrigLine)); + pvlRefChangeGrp += Isis::PvlKeyword("NewSerialNumber", mtInterestResults[iBestMeasureIndex].msSerialNum); + pvlRefChangeGrp += Isis::PvlKeyword("NewBestInterest", mtInterestResults[iBestMeasureIndex].mdInterest); + pvlRefChangeGrp += Isis::PvlKeyword("NewLocation", LocationString(mtInterestResults[iBestMeasureIndex].mdBestSample, mtInterestResults[iBestMeasureIndex].mdBestLine)); + + pvlPointObj += pvlRefChangeGrp; + } + else { + pvlPointObj += Isis::PvlKeyword("Reference", "No Change"); + } + //Clean up the results structure + delete [] mtInterestResults; + } + else { + // Process Ignored, non Tie points or Measures=0 + newPnt = origPnt; + + if(iOrigRefIndex < 0) { + pvlPointObj += Isis::PvlKeyword("Comments", "No Measures in the Point"); + } + else if(newPnt.Ignore()) { + pvlPointObj += Isis::PvlKeyword("Comments", "Point was originally Ignored"); + } + else { + pvlPointObj += Isis::PvlKeyword("Comments", "Not Tie Point"); + } + + for(int measure = 0; measure < newPnt.Size(); measure++) { + newPnt[measure].SetDateTime(); + newPnt[measure].SetChooserName("Application cnetref(Interest)"); + } + pNewNet.Add(newPnt); + } // End of if point is of type tie + + mPvlLog += pvlPointObj; + + mStatus.CheckStatus(); + } // Point loop + + // Basic Statistics + mStatisticsGrp += Isis::PvlKeyword("TotalPoints", pNewNet.Size()); + mStatisticsGrp += Isis::PvlKeyword("PointsIgnored", (pNewNet.Size() - pNewNet.NumValidPoints())); + mStatisticsGrp += Isis::PvlKeyword("PointsModified", iPointsModified); + mStatisticsGrp += Isis::PvlKeyword("ReferenceChanged", iRefChanged); + mStatisticsGrp += Isis::PvlKeyword("TotalMeasures", pNewNet.NumMeasures()); + mStatisticsGrp += Isis::PvlKeyword("MeasuresModified", iMeasuresModified); + + mPvlLog += mStatisticsGrp; + } + + /** + * InterestByPoint - Find the interest of all measures in a Point + * and store all the results in Interest Results structure. + * + * @author Sharmila Prasad (6/8/2010) + * + * @param pCnetPoint + */ + int InterestOperator::InterestByPoint(ControlPoint &pCnetPoint) { + // Find the overlap this point is inside of if the overlap list is entered + const geos::geom::MultiPolygon *overlapPoly = NULL; + if(mbOverlaps) { + overlapPoly = FindOverlap(pCnetPoint); + + if(overlapPoly == NULL) { + string msg = "Unable to find overlap polygon for point [" + pCnetPoint.Id() + "]"; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + } + + std::vector pvlGrpVector; + + // Create an array of Interest Results structure of measures size + mtInterestResults = new InterestResults[pCnetPoint.Size()]; + + int iBestMeasureIndex = -1; + double dBestInterestValue = Isis::Null; + + for(int measure = 0; measure < pCnetPoint.Size(); ++measure) { + ControlMeasure &origMsr = pCnetPoint[measure]; + std::string sn = origMsr.CubeSerialNumber(); + + // Do not process Ignored Measures + if(!origMsr.Ignore()) { + InitInterestResults(measure); + Cube *inCube = mCubeMgr.OpenCube(mSerialNumbers.Filename(sn)); + + // Set the clipping polygon for this point + // Convert the lon/lat overlap polygon to samp/line using the UGM for + // this image + if(mbOverlaps) { + UniversalGroundMap unvGround = UniversalGroundMap(*inCube); + geos::geom::MultiPolygon *poly = PolygonTools::LatLonToSampleLine(*overlapPoly, &unvGround); + SetClipPolygon(*poly); + delete poly; + } + + // Run the interest operator on this measurment + if(InterestByMeasure(measure, origMsr, *inCube)) { + if(dBestInterestValue == Isis::Null || CompareInterests(mtInterestResults[measure].mdInterest, dBestInterestValue)) { + dBestInterestValue = mtInterestResults[measure].mdInterest; + iBestMeasureIndex = measure; + } + } + } + } + return iBestMeasureIndex; + } + + /** + * Find the interest by Measure given the index to store the results in the + * InterestResults structure + * + * @author Sharmila Prasad (6/10/2010) + * + * @param piMeasure + * @param pCnetMeasure + * + * @return bool + */ + bool InterestOperator::InterestByMeasure(int piMeasure, ControlMeasure &pCnetMeasure, Cube &pCube) { + std::string serialNum = pCnetMeasure.CubeSerialNumber(); + + int iOrigSample = (int)(pCnetMeasure.Sample() + 0.5); + int iOrigLine = (int)(pCnetMeasure.Line() + 0.5); + + mtInterestResults[piMeasure].msSerialNum = serialNum; + mtInterestResults[piMeasure].mdOrigSample = pCnetMeasure.Sample(); + mtInterestResults[piMeasure].mdOrigLine = pCnetMeasure.Line(); + + int pad = Padding(); + Chip chip(2 * p_deltaSamp + p_samples + pad, 2 * p_deltaLine + p_lines + pad); + chip.TackCube(iOrigSample, iOrigLine); + if(p_clipPolygon != NULL) chip.SetClipPolygon(*p_clipPolygon); + chip.Load(pCube); + + // Walk the search chip and find the best interest + int iBestSamp = 0; + int iBestLine = 0; + double dSmallestDist = DBL_MAX; + double dBestInterest = Isis::Null; + int iLines = 2 * p_deltaLine + p_lines / 2 + 1; + int iSamples = 2 * p_deltaSamp + p_samples / 2 + 1; + bool bCalculateInterest = false; + for(int lin = p_lines / 2 + 1; lin <= iLines; lin++) { + for(int samp = p_samples / 2 + 1; samp <= iSamples; samp++) { + // Cannot take dnValues from the chip as it contains the interpolated dnValue + // hence get the dn values directly from the cube + chip.SetChipPosition((double)samp, (double)lin); + + bCalculateInterest = false; + if(ValidStandardOptions(chip.CubeSample(), chip.CubeLine(), &pCube)) { + bCalculateInterest = true; + } + + if(bCalculateInterest) { + Chip subChip = chip.Extract(p_samples + pad, p_lines + pad, samp, lin); + double interest = Interest(subChip); + + if(interest != Isis::Null) { + if((dBestInterest == Isis::Null) || CompareInterests(interest, dBestInterest)) { + double dist = std::sqrt(std::pow(iOrigSample - samp, 2.0) + std::pow(iOrigLine - lin, 2.0)); + if(interest == dBestInterest && dist > dSmallestDist) { + continue; + } + else { + dBestInterest = interest; + dSmallestDist = dist; + iBestSamp = samp; + iBestLine = lin; + + mtInterestResults[piMeasure].mdEmission = mdEmissionAngle; + mtInterestResults[piMeasure].mdIncidence = mdIncidenceAngle; + mtInterestResults[piMeasure].mdDn = mdDnValue; + mtInterestResults[piMeasure].mdResolution = mdResolution ; + mtInterestResults[piMeasure].mbValid = true; + } + } + } + } + } + } + + // Check to see if we went through the interest chip and never got a interest at + // any location.But record the Emission, Incidence Angles and DN Value for the failed Measure + // at the original location + if(dBestInterest == Isis::Null || dBestInterest < p_minimumInterest) { + // Get the Camera + Camera *camera; + try { + camera = pCube.Camera(); + } + catch(Isis::iException &e) { + std::string msg = "Cannot Create Camera for Image:" + mSerialNumbers.Filename(serialNum); + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + + if(camera->SetImage(iOrigSample, iOrigLine)) { + Portal inPortal(1, 1, pCube.PixelType()); + inPortal.SetPosition(iOrigSample, iOrigLine, 1); + pCube.Read(inPortal); + + mtInterestResults[piMeasure].mdInterest = dBestInterest; + mtInterestResults[piMeasure].mdBestSample = Isis::Null; + mtInterestResults[piMeasure].mdBestLine = Isis::Null; + mtInterestResults[piMeasure].mdOrigSample = iOrigSample; + mtInterestResults[piMeasure].mdOrigLine = iOrigLine; + mtInterestResults[piMeasure].mdEmission = camera->EmissionAngle(); + mtInterestResults[piMeasure].mdIncidence = camera->IncidenceAngle(); + mtInterestResults[piMeasure].mdDn = inPortal[0]; + mtInterestResults[piMeasure].mdResolution = camera->PixelResolution(); + mtInterestResults[piMeasure].mbValid = false; + } + return false; + } + + chip.SetChipPosition(iBestSamp, iBestLine); + mtInterestResults[piMeasure].mdInterest = dBestInterest; + mtInterestResults[piMeasure].mdBestSample = chip.CubeSample(); + mtInterestResults[piMeasure].mdBestLine = chip.CubeLine(); + mtInterestResults[piMeasure].miDeltaSample = (int)abs(mtInterestResults[piMeasure].mdBestSample - iOrigSample); + mtInterestResults[piMeasure].miDeltaLine = (int)abs(mtInterestResults[piMeasure].mdBestLine - iOrigLine); + return true; + } + + /** + * This method searches for an overlap in the ImageOverlapSet that belongs + * to the given control point. Only exact SN matches are accepted. + * + */ + const geos::geom::MultiPolygon *InterestOperator::FindOverlap(ControlPoint &pCnetPoint) { + int exactMatchIndex = -1; + + for(int overlapIndex = 0; ((exactMatchIndex == -1) && (overlapIndex < mOverlaps.Size())); overlapIndex ++) { + const Isis::ImageOverlap *overlap = mOverlaps[overlapIndex]; + + // Exact matches only; skip if # SNs don't match + if(overlap->Size() != pCnetPoint.Size()) continue; + + // If # SNs match and each SN is contained in both then we're good, there + // should never be two measures with the same SN + int numMatches = 0; + + for(int measureIndex = 0; measureIndex < pCnetPoint.Size(); measureIndex ++) { + if(measureIndex == numMatches) { + ControlMeasure &controlMeasure = pCnetPoint[measureIndex]; + iString serialNum = controlMeasure.CubeSerialNumber(); + if(overlap->HasSerialNumber(serialNum)) { + numMatches++; + } + } + } + + if(numMatches == pCnetPoint.Size()) { + exactMatchIndex = overlapIndex; + } + } + + if(exactMatchIndex < 0) { + return (FindOverlapByImageFootPrint(pCnetPoint)); + } + + return mOverlaps[exactMatchIndex]->Polygon(); + } + + /** + * Find image overlaps by getting intersection of the individual image footprints + * when an exact match in the overlaplist fails + * + * @author sprasad (7/1/2010) + * + * @param pCnetPoint + * + * @return const geos::geom::MultiPolygon* + */ + const geos::geom::MultiPolygon *InterestOperator::FindOverlapByImageFootPrint(Isis::ControlPoint &pCnetPoint) + { + ImagePolygon measPolygon1, measPolygon2, measPolygon3; + geos::geom::Geometry* geomIntersect1, *geomIntersect2; + + // Create Multipolygon for the first Control Measure + std::string sn1 = pCnetPoint[0].CubeSerialNumber(); + Cube *inCube1 = mCubeMgr.OpenCube(mSerialNumbers.Filename(sn1)); + inCube1->Read((Blob &)measPolygon1); + + // Create Multipolygon for the Second Control Measure + std::string sn2 = pCnetPoint[1].CubeSerialNumber(); + Cube *inCube2 = mCubeMgr.OpenCube(mSerialNumbers.Filename(sn2)); + inCube2->Read((Blob &)measPolygon2); + + // Get the interesection for the first 2 polgons + geomIntersect1 = PolygonTools::Intersect((const geos::geom::Geometry*)measPolygon1.Polys(), (const geos::geom::Geometry*)measPolygon2.Polys()); + + for(int measureIndex = 2; measureIndex < pCnetPoint.Size(); measureIndex ++) { + std::string sn3 = pCnetPoint[measureIndex].CubeSerialNumber(); + Cube *inCube3 = mCubeMgr.OpenCube(mSerialNumbers.Filename(sn3)); + inCube3->Read((Blob &)measPolygon3); + + // Get the intersection of the intersection and the measure Image Polygon + geomIntersect2 = PolygonTools::Intersect(geomIntersect1, (const geos::geom::Geometry*)measPolygon3.Polys()); + geomIntersect1 = geomIntersect2; + } + return (geos::geom::MultiPolygon*)geomIntersect1; + } + + /** + * This virtual method must return if the 1st fit is equal to or better + * than the second fit. + * + * @param int1 1st interestAmount + * @param int2 2nd interestAmount + */ + bool InterestOperator::CompareInterests(double int1, double int2) { + return(int1 >= int2); + } + + + // add this object's group to the pvl + void InterestOperator::AddGroup(Isis::PvlObject &obj) { + Isis::PvlGroup group; + obj.AddGroup(group); + } + + + /** + * Sets the clipping polygon for the chip. The coordinates must be in + * (sample,line) order. + * + * @param clipPolygon The polygons used to clip the chip + */ + void InterestOperator::SetClipPolygon(const geos::geom::MultiPolygon &clipPolygon) { + if(p_clipPolygon != NULL) delete p_clipPolygon; + p_clipPolygon = PolygonTools::CopyMultiPolygon(clipPolygon); + } + + /** + * Sets an offset to pass in larger chips if operator requires it + * This is used to offset the subchip size passed into Interest + * + * @return int Amount to add to both x & y total sizes + */ + int InterestOperator::Padding() { + return 0; + } + + /** + * This function returns the keywords that this object was + * created from. + * + * @return PvlGroup The keywords this object used in + * initialization + */ + PvlGroup InterestOperator::Operator() { + return mOperatorGrp; + } +} diff --git a/isis/src/base/objs/InterestOperator/InterestOperator.h b/isis/src/base/objs/InterestOperator/InterestOperator.h new file mode 100644 index 0000000000000000000000000000000000000000..88845e8e46a99f1cd05cc23aa39bdd9739707f1a --- /dev/null +++ b/isis/src/base/objs/InterestOperator/InterestOperator.h @@ -0,0 +1,204 @@ +#ifndef InterestOperator_h +#define InterestOperator_h +/** + * @file + * $Revision: 1.20 $ + * $Date: 2010/07/02 23:38:14 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "PvlGroup.h" +#include "Camera.h" +#include "UniversalGroundMap.h" +#include "CnetValidMeasure.h" +#include "ImageOverlapSet.h" + +#include "geos/geom/Point.h" +#include "geos/geom/Coordinate.h" +#include "geos/geom/MultiPolygon.h" +#include "geos/util/GEOSException.h" + +namespace Isis { + class Chip; + class Pvl; + class Cube; + class PvlObject; + class ControlNet; + class ControlPoint; + class ControlMeasure; + + typedef struct { + std::string msSerialNum; //!< Serial Number of the Measure + double mdInterest; //!< Resulting interest amt from InterestOperator + double mdBestSample; //!< Most interesting sample + double mdBestLine; //!< Most interesting line + double mdOrigSample; //!< Control Measure's original sample + double mdOrigLine; //!< Control Measure's original line + double mdEmission; //!< Emission angle at most interesting sample,line + double mdIncidence; //!< Incidence angle at most interesting sample,line + double mdDn; //!< Cube DN value at most interesting sample,line + double mdResolution; //!< Camera resolution at most interesting sample,line + bool mbValid; //!< Value of the interest operator result (success) + int miDeltaSample; //!< The number of Samples the point has been moved + int miDeltaLine; //!< The number of Lines the point has been moved + } InterestResults; + + /** + * @brief Interest Operator class + * + * Create InterestOperator object. Because this is a pure virtual class you + * can not create an InterestOperator class directly. Instead, see the + * InterestOperatorFactory class. + * + * @see StandardDeviationOperator GradientOperator + * + * @internal + * @history 2006-02-11 Jacob Danton - Original Version + * @history 2007-08-02 Steven Koechle - Added better + * documentation to CompareInterests(). + * @history 2007-08-02 Steven Koechle - Fixed looping error + * that caused subchip to go outside the chip to the + * left and top, and not check the bottom and right. + * @history 2007-08-14 Steven Koechle - Added virtual method + * Padding() which default returns 0. + * @history 2007-08-16 Steven Koechle - Fixed Looping error + * in Operate. Made the loops <= instead of just <. + * Changed from accepting one delta to accepting a + * deltaSamp and a deltaLine. + * @history 2008-06-18 Stuart Sides - Fixed doc error + * @history 2008-08-19 Steven Koechle - Updated to work with + * Geos3.0.0 + * @history 2009-08-11 Travis Addair - Added functionality allowing it and all its + * subclasses to return the pvl group that they were initialized from + * @history 2010-04-09 Sharmila Prasad - API's to check valid DN and Emission Angle. + * Also changed functionality of Operate and made it overloaded. + * @history 2010-04-30 Sharmila Prasad - Added class members mdBestEmissionAngle, mdBestDnValue + * and their access functions.Also added member mUnusedParamGrp to check for the default + * values used for the operator. + * @history 2010-04-30 Sharmila Prasad - 1. Interest Operator a child of CnetValidMeasure which validates + * all the standard control network options. Changed functionality to accomadate CnetValidMeasure + * 2. Removed class members mdBestEmissionAngle, mdBestDnValue..., instead stored in + * structure InterestResults structure + * 3. Move processing ImageOverlaps from app to here + * 4. Added API's to compute Interest by point and by measure + * @history 2010-06-18 Sharmila Prasad - 1. Fixed Bug to ignore Points with no good interest + * 2. Do not process previously Ignored points in the Original Control Net + * @history 2010-06-21 Sharmila Prasad - Remove references to UniversalGroundMap and Cubes + * use CubeManager instead + * @history 2010-06-23 Sharmila Prasad - Use CnetValidMeasure's Validate Standard Options & + * Std Options Pixels/Meters from Edge + */ + class InterestOperator : public CnetValidMeasure { + public: + InterestOperator(Pvl &pPvl); + virtual ~InterestOperator(); + + void SetPatternValidPercent(const double percent); + void SetPatternSampling(const double percent); + void SetSearchSampling(const double percent); + void SetTolerance(double tolerance); + void SetPatternReduction(std::vector samples, std::vector lines); + + //!< Return name of the matching operator + inline std::string operatorName() const { + return mOperatorGrp["Name"]; + }; + + //!< Operate used by the app interestcube- to calculate interest by sample,line + bool Operate(Cube &pCube, UniversalGroundMap &pUnivGrndMap, int piSample, int piLine); + + //!< Operate - to calculate interest for entire control net to get better reference + void Operate(const ControlNet &pOrigNet, ControlNet &pNewNet, std::string psSerialNumFile, std::string psOverlapListFile = ""); + + //!< Return the goodness of fit of the match operator + inline double InterestAmount() const { + return p_interestAmount; + }; + + inline double WorstInterest() const { + return p_worstInterest; + } + + //!< Return the search chip cube sample that best matched + inline double CubeSample() const { + return p_cubeSample; + }; + + //!< Return the search chip cube line that best matched + inline double CubeLine() const { + return p_cubeLine; + }; + + //!< Compare for int1 greater than / equal to int2 + virtual bool CompareInterests(double int1, double int2); + void AddGroup(Isis::PvlObject &obj); //???? check if used + + //!< Set the Clip Polygon for points to be contained in the overlaps + void SetClipPolygon(const geos::geom::MultiPolygon &clipPolygon); + + //!< Return the Operator name + Isis::PvlGroup Operator(); + + protected: + //!< Parse the Interest specific keywords + void Parse(Pvl &pPvl); + + //!< Calculate the interest + virtual double Interest(Chip &subCube) = 0; + + //!< Find if a point is in the overlap + const geos::geom::MultiPolygon *FindOverlap(Isis::ControlPoint &pCnetPoint); + + // +#include +#include "InterestOperator.h" +#include "InterestOperatorFactory.h" +#include "StandardDeviationOperator.h" +#include "Chip.h" +#include "Cube.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Preference.h" +#include "UniversalGroundMap.h" +#include "CnetValidMeasure.h" + +using namespace Isis; + +int main() { + Isis::Preference::Preferences(true); + try { + PvlGroup op("Operator"); + op += PvlKeyword("Name", "StandardDeviation"); + op += PvlKeyword("DeltaLine", 100); + op += PvlKeyword("DeltaSamp", 100); + op += PvlKeyword("Samples", 15); + op += PvlKeyword("Lines", 15); + op += PvlKeyword("MinDN", 0.0); + op += PvlKeyword("MaxDN", 1.0); + op += PvlKeyword("MinimumInterest", 0.01); + op += PvlKeyword("MinEmission", 15.0); + op += PvlKeyword("MaxEmission", 25.0); + op += PvlKeyword("MinIncidence", 0.0); + op += PvlKeyword("MaxIncidence", 135.0); + //op += PvlKeyword("MinResolution", 100); + //op += PvlKeyword("MaxResolution", 300); + + PvlObject o("InterestOperator"); + o.AddGroup(op); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl; + + InterestOperator *iop = InterestOperatorFactory::Create(pvl); + + Cube c; + c.Open("$mgs/testData/ab102401.cub"); + + UniversalGroundMap univGrndMap(c); + iop->Operate(c, univGrndMap, 100, 350); + + std::cout << "Sample: " << iop->CubeSample() << std::endl + << "Line : " << iop->CubeLine() << std::endl + << "Interest: " << iop->InterestAmount() << std::endl; + } + catch(iException &e) { + e.Report(); + } + + + + return 0; +} diff --git a/isis/src/base/objs/InterestOperatorFactory/InterestOperatorFactory.cpp b/isis/src/base/objs/InterestOperatorFactory/InterestOperatorFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..455f36f60188526606e473c236850eace760c060 --- /dev/null +++ b/isis/src/base/objs/InterestOperatorFactory/InterestOperatorFactory.cpp @@ -0,0 +1,73 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/06/10 23:42:31 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "InterestOperatorFactory.h" +#include "InterestOperator.h" +#include "Plugin.h" +#include "iException.h" +#include "Filename.h" + +namespace Isis { + /** + * Create an InterestOperator object using a PVL specification. + * An example of the PVL required for this is: + * + * @code + * Object = InterestOperator + * Group = Operator + * Name = StandardDeviation + * Samples = 21 + * Lines = 21 + * Delta = 50 + * EndGroup + * EndObject + * @endcode + * + * There are many other options that can be set via the pvl and are + * described in other documentation (see below). + * + * @param pvl The pvl object containing the specification + * + * @see automaticRegistration.doc + **/ + InterestOperator *InterestOperatorFactory::Create(Pvl &pPvl) { + // Get the algorithm name to create + PvlGroup &op = pPvl.FindGroup("Operator", Pvl::Traverse); + std::string operatorName = op["Name"]; + + // Open the factory plugin file + Plugin p; + Filename f("InterestOperator.plugin"); + if(f.Exists()) { + p.Read("InterestOperator.plugin"); + } + else { + p.Read("$ISISROOT/lib/InterestOperator.plugin"); + } + + // Get the algorithm specific plugin and return it + InterestOperator * (*plugin)(Pvl & pPvl); + plugin = (InterestOperator * ( *)(Pvl & pPvl)) p.GetPlugin(operatorName); + return (*plugin)(pPvl); + } +} // end namespace isis diff --git a/isis/src/base/objs/InterestOperatorFactory/InterestOperatorFactory.h b/isis/src/base/objs/InterestOperatorFactory/InterestOperatorFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..9802b97a0133d10811a278538b9c0ec6b26d5ddd --- /dev/null +++ b/isis/src/base/objs/InterestOperatorFactory/InterestOperatorFactory.h @@ -0,0 +1,58 @@ +#if !defined(InterestOperatorFactory_h) +#define InterestOperatorFactory_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/06/10 23:42:31 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { + class Pvl; + class InterestOperator; + + /** + * This class is used to create InterestOperator objects. Typically applications which + * need use InterestOperators would like to use different techniques such as + * Standard Deviation or Gradient. If this factory is given a Pvl + * object which contains a InterestOperator definition it will create that specific + * instance of the class. + * + * @author 2006-02-04 Jacob Danton + * @internal + * @history 2009-01-16 Steven Koechle - Fixed memory leak + */ + + class InterestOperatorFactory { + public: + static InterestOperator *Create(Pvl &pPvl); + + private: + /** + * Constructor (its private so you can't use it). Use the Create Method + * instead. + */ + InterestOperatorFactory() {}; + + //! Destroys the InterestOperatorFactory + ~InterestOperatorFactory() {}; + }; +}; + +#endif diff --git a/isis/src/base/objs/InterestOperatorFactory/InterestOperatorFactory.truth b/isis/src/base/objs/InterestOperatorFactory/InterestOperatorFactory.truth new file mode 100644 index 0000000000000000000000000000000000000000..ea99e74917add2fbed757fa8b8f92d7162c44a4a --- /dev/null +++ b/isis/src/base/objs/InterestOperatorFactory/InterestOperatorFactory.truth @@ -0,0 +1 @@ +All testing differed to InterestOperator and it's extended classes. diff --git a/isis/src/base/objs/InterestOperatorFactory/Makefile b/isis/src/base/objs/InterestOperatorFactory/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..55aa44a90f54c17ac9fa82ac0ba25cd3c1157ad3 --- /dev/null +++ b/isis/src/base/objs/InterestOperatorFactory/Makefile @@ -0,0 +1,5 @@ +INCS = InterestOperatorFactory.h +SRCS = InterestOperatorFactory.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/InterestOperatorFactory/unitTest.cpp b/isis/src/base/objs/InterestOperatorFactory/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c9c9e567548bf1e9413ba604330f648c8ca4dbc6 --- /dev/null +++ b/isis/src/base/objs/InterestOperatorFactory/unitTest.cpp @@ -0,0 +1,12 @@ +#include +#include +#include "Preference.h" + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + cout << "All testing differed to InterestOperator and it's extended classes." << endl; + + return 0; +} diff --git a/isis/src/base/objs/Interpolator/Interpolator.cpp b/isis/src/base/objs/Interpolator/Interpolator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2803cfe9c9ff93444603b8d290e98d8806f89246 --- /dev/null +++ b/isis/src/base/objs/Interpolator/Interpolator.cpp @@ -0,0 +1,338 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/11/06 15:53:53 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "iException.h" +#include "Interpolator.h" + +using namespace std; +namespace Isis { +/** + * Constructs an empty Interpolator object. + */ + Interpolator::Interpolator () { + Init (); + } + +/** + * Constructs an Interpolator object, and sets the type of interpolation. + * + * @param type The type of interpolation to be performed. (NearestNeighbor, + * BiLinear or CubicConvulsion) + * @see Interpolator.h + */ + Interpolator::Interpolator (const interpType &type) { + Init (); + p_type = type; + } + + //! Destroys the Interpolator object. + Interpolator::~Interpolator () {} + + //! Initializes the object data members. + void Interpolator::Init () { + p_type = None; + } + +/** + * Performs an interpolation on the data according to the parameters set in the + * constructor. If the buffer contains special pixel values then the current + * interpolation is abandoned and the next lower type of interpolation is + * attempted. The order from highest to lowest is (Cubic Convolution, Bi-linear + * and Nearest Neighbor). + * + * @param isamp The exact sample position being interpolated within the image. + * @param iline The exact line position being interpolated within the image. + * @param buf[] The buffer of data to be interpolated. The buffer is assumed + * to be the correct dimensions for the interpolator. + * + * @internal + * @todo Add a @return statement to this method. + */ + double Interpolator::Interpolate(const double isamp, const double iline, + const double buf[]) { + + switch (p_type) { + case None: { + string message = "Interpolator type not set"; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + break; + } + case NearestNeighborType: + return NearestNeighbor (isamp, iline, buf); + break; + case BiLinearType: + return BiLinear (isamp, iline, buf); + break; + case CubicConvolutionType: + return CubicConvolution (isamp, iline, buf); + break; + } + + string message = "Invalid interpolator"; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } +/** + * Sets the type of interpolation. (NearestNeighbor, BiLinear, CubicConvulsion). + * @see Interpolator.h + * + * @param type The type of interpolation to be set. + */ + void Interpolator::SetType (const interpType &type) { + p_type = type; + } + + +/** + * Performs a nearest-neighbor interpolation on the buffer data. + * + * @param isamp The input sample/column/x coordinate. + * @param iline The input line/row/y coordinate. + * @param buf[] The data buffer to be interpolated. For nearest-neighbor + * there is only one value, the pixel of interest. + * + * @internal + * @todo Add a @return tag to this method. + */ + double Interpolator::NearestNeighbor (const double isamp, const double iline, + const double buf[]) { + return buf[0]; + } + + +/** + * Performs a bi-linear interpolation on the buffer data. + * + * @param isamp The input sample/column/x coordinate. + * @param iline The input line/row/y coordinate. + * @param buf[] The data buffer to be interpolated. For bi-linear there are four + * values with the pixel of interest in the upper left corner of a 2x2 window. + * + * @internal + * @todo Add a @return tag to this method. + */ + double Interpolator::BiLinear (const double isamp, const double iline, + const double buf[]) { + + // Get the fractional portions of the sample and line coordinates + double j = int (isamp); + double k = int (iline); + double a = isamp - j; + double b = iline - k; + + // If any of the 4 pixels are special pixels, drop down to a nearest neighbor + for (int i=0; i<4; i++) { + if (Isis::IsSpecial(buf[i])) { + return NearestNeighbor (isamp, iline, + &buf[(int)(a + 0.5) + 2 * (int)(b+0.5)]); + break; + } + } + + // Otherwise do the bilinear + return (1.0-a) * (1.0-b) * buf[0] + + a * (1.0-b) * buf[1] + + (1.0-a) * b * buf[2] + + a * b * buf[3]; + + } + +/** + * Performs a cubic-convulsion interpolation on the buffer data. + * + * @param isamp The input sample/column/x coordinate. + * @param iline The input line/row/y coordinate. + * @param buf[] The data buffer to be interpolated. For cubic-convultion + * there are sixteen values with the pixel of interest in the second row and + * second column of a 4x4 window. + * + * @internal + * @todo Add a @return tag to this method. + */ + double Interpolator::CubicConvolution (const double isamp, + const double iline, + const double buf[]) { + + // If any of the 16 pixels are special pixels, drop down to a bilinear + for (int i=0; i<16; i++) { + if (Isis::IsSpecial(buf[i])) { + double tbuf[4] = {buf[5], buf[6], buf[9], buf[10]}; + return BiLinear (isamp, iline, tbuf); + break; + } + } + + double j = int (isamp); + double k = int (iline); + double a = isamp - j; + double b = iline - k; + + /** + * This algorithm has been checked extensively, and is correctly coded! + * + * This algorithm works by modeling the picture locally with a polynomial + * surface, which means DNs less than all inputs or greater than all inputs are + * possible. + */ + return -b * (1.0-b)*(1.0-b) * (-a * (1.0-a)*(1.0-a) * buf[0] + + (1.0 - 2.0 * a*a + a*a*a) * buf[1] + + a * (1.0 + a - a*a) * buf[2] - + a*a * (1.0 - a) * buf[3]) + + + (1.0 - 2.0 * b*b + b*b*b) * (-a * (1.0-a)*(1.0-a) * buf[4] + + (1.0 - 2.0 * a*a + a*a*a) * buf[5] + + a * (1.0 + a - a*a) * buf[6] - + a*a * (1.0 - a) * buf[7]) + + + b * (1.0 + b - b*b) * (-a * (1.0-a)*(1.0-a) * buf[8] + + (1.0 - 2.0 * a*a + a*a*a) * buf[9] + + a * (1.0 + a - a*a) * buf[10] - + a*a * (1.0 - a) * buf[11]) + + + b*b * (b-1.0) * (-a * (1.0-a)*(1.0-a) * buf[12] + + (1.0 - 2.0 * a*a + a*a*a) * buf[13] + + a * (1.0 + a - a*a) * buf[14] - + a*a * (1.0 - a) * buf[15]); + + } + +/** + * Returns the number of samples needed by the interpolator. + * + * @return The number of samples needed. + */ + int Interpolator::Samples () { + + switch (p_type) { + case None: { + string message = "Interpolator type not set"; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + break; + } + case NearestNeighborType: + return 1; + break; + case BiLinearType: + return 2; + break; + case CubicConvolutionType: + return 4; + break; + } + + string message = "Invalid interpolator"; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + +/** + * Returns the number of lines needed by the interpolator. + * + * @return The number of lines needed. + */ + int Interpolator::Lines () { + + switch (p_type) { + case None: { + string message = "Interpolator type not set"; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + break; + } + case NearestNeighborType: + return 1; + break; + case BiLinearType: + return 2; + break; + case CubicConvolutionType: + return 4; + break; + } + + string message = "Invalid interpolator"; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + +/** + * Returns the sample coordinate of the center pixel in the buffer for the + * interpolator. + * + * @return The sample coordinate of the center pixel. + */ + double Interpolator::HotSample () { + + switch (p_type) { + case None: { + string message = "Interpolator type not set"; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + break; + } + // To get the correct pixel for NN you have to round the sample + case NearestNeighborType: + return -0.5; + break; + // To get the correct pixel for BL you have to truncate the sample + case BiLinearType: + return 0.0; + break; + // To get the correct pixel for CC you have to truncate the sample + case CubicConvolutionType: + return 1.0; + break; + } + + string message = "Invalid interpolator"; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + +/** + * Returns the line coordinate of the center pixel in the buffer for the + * interpolator. + * + * @return The line coordinate of the center pixel. + */ + double Interpolator::HotLine () { + + switch (p_type) { + case None: { + string message = "Interpolator type not set"; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + break; + } + // To get the correct pixel for NN you have to round the line + case NearestNeighborType: + return -0.5; + break; + // To get the correct pixel for BL you have to truncate the line + case BiLinearType: + return 0.0; + break; + // To get the correct pixel for CC you have to truncate the line + case CubicConvolutionType: + return 1.0; + break; + } + + string message = "Invalid interpolator"; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } +} diff --git a/isis/src/base/objs/Interpolator/Interpolator.h b/isis/src/base/objs/Interpolator/Interpolator.h new file mode 100644 index 0000000000000000000000000000000000000000..45b0930d2ced1acaa9d3a62167eb6dda1b81208f --- /dev/null +++ b/isis/src/base/objs/Interpolator/Interpolator.h @@ -0,0 +1,113 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef Interpolator_h +#define Interpolator_h + +#include "SpecialPixel.h" + +namespace Isis { +/** + * @brief Pixel interpolator. + * + * This class is used for interpolating buffers of pixel data. It is usually + * associated with spacial translation, rotations and scaling in geometric + * warping algorithums (i.e., rubber sheeting). When special-pixel values are + * found in the data buffer the current interpolator is abandonded and the next + * lower interpolator is used instead (i.e.; if Cubic-convolution can not be + * performed then a bi-linear is used and if the bi-linear can not be performed + * then nearest-neighbor will be used. + * + * @ingroup Geometry + * + * @author 2002-10-09 Stuart Sides + * + * @internal + * @todo This class needs an example. + * @history 2003-02-12 Stuart Sides Fixed misspelling of object name in XML + * file. (Note: XML files no longer used in documentation.) + * @history 2003-05-16 Stuart Sides modified schema from + * astrogeology...isis.astrogeology. + */ + class Interpolator { + public: + /** + * The interpolator type, including: None, Nearest Neighbor, BiLinear + * or Cubic Convultion. + */ + enum interpType { + None=0, + NearestNeighborType=1, + BiLinearType=2, + CubicConvolutionType=4 + }; + + private: + /** + * The type of interpolation to be performed. (NearestNeighbor, BiLinear + * or CubicConvultion + */ + interpType p_type; + + + void Init (); + + + double NearestNeighbor (const double isamp, const double iline, + const double buf[]); + + // Do a bilinear interpolation on the buf + double BiLinear (const double isamp, const double iline, + const double buf[]); + + // Do a cubic convolution on the buf + double CubicConvolution (const double isamp, const double iline, + const double buf[]); + + + public: + // Constructores / destructores + Interpolator (); + Interpolator (const interpType &type); + ~Interpolator (); + + + // Perform the interpolation with the current settings + double Interpolate (const double isamp, const double iline, + const double buf[]); + + + // Set the type of interpolation + void SetType (const interpType &type); + + + // Return sizes needed by the interpolator + int Samples (); + int Lines(); + + + // Return the hot spot (center pixel) of the interpolator zero based + double HotSample(); + double HotLine(); + }; +}; +#endif diff --git a/isis/src/base/objs/Interpolator/Interpolator.truth b/isis/src/base/objs/Interpolator/Interpolator.truth new file mode 100644 index 0000000000000000000000000000000000000000..d2c31f6b38597af7fc825addcc9f3b95eb1f570a --- /dev/null +++ b/isis/src/base/objs/Interpolator/Interpolator.truth @@ -0,0 +1,16 @@ +Testing invalid interpolator + Cought invalid interpolator error. +**PROGRAMMER ERROR** Interpolator type not set +Testing Nearest Neighbor + 99.5 = 99.5000000000000 +Testing Bilinear + 1.0 = 1.00000000000000 + 2.5 = 2.50000000000000 + 4.0 = 3.99999999999970 + 1.0 = 1.00000000000000 +Testing Cubic Convolution + 6.0 = 6.00000000000000 + 8.50000000000000 = 8.50000000000000 + 11.0000000000000 = 10.9999999999990 + 10.0 = 9.99999999999960 + 6.0 = 11.0000000000000 diff --git a/isis/src/base/objs/Interpolator/Makefile b/isis/src/base/objs/Interpolator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5af1852fb46ceb5ae4e66c44bdb6e0ffbcb3c234 --- /dev/null +++ b/isis/src/base/objs/Interpolator/Makefile @@ -0,0 +1,5 @@ +INCS = Interpolator.h +SRCS = Interpolator.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Interpolator/unitTest.cpp b/isis/src/base/objs/Interpolator/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13416c472f91c217abe2589ad70a9e27f0cbd1a2 --- /dev/null +++ b/isis/src/base/objs/Interpolator/unitTest.cpp @@ -0,0 +1,72 @@ +#include +#include +#include +#include "iException.h" +#include "Interpolator.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + + // Test for an invalid interpolator + cout.setf(ios::showpoint); + cout << setprecision(15) << setw(17); + cout << "Testing invalid interpolator" << endl; + double buf[] = {99.5}; + + Isis::Interpolator *interp = new Isis::Interpolator (); + try { + double val = interp->Interpolate (10.0, 25.0, buf); + cout << " " << 99.5 << " = " << val << endl; + } + catch (Isis::iException &e) { + cout << " Cought invalid interpolator error." << endl; + e.Report (false); + } + + // Test Nearest Neighbor + cout << "Testing Nearest Neighbor" << endl; + interp->SetType (Isis::Interpolator::NearestNeighborType); + cout << " 99.5 = " << interp->Interpolate (25.99, 10.0, buf) << endl; + delete interp; + + + // Test BiLinear with a good buffer + cout << "Testing Bilinear" << endl; + double buf2[] = {1.0, 2.0, + 3.0, 4.0}; + interp = new Isis::Interpolator (Isis::Interpolator::BiLinearType); + cout << " 1.0 = " << interp->Interpolate (25.0, 10.0, buf2) << endl; + cout << " 2.5 = " << interp->Interpolate (25.5, 10.5, buf2) << endl; + cout << " 4.0 = " << interp->Interpolate (25.9999999999999, 10.9999999999999, + buf2) << endl; + + // Test BiLinear with invalid data in buffer + buf2[1] = Isis::NULL8; + cout << " 1.0 = " << interp->Interpolate (25.0, 10.0, buf2) << endl; + delete interp; + + + // Test Cubic Convolution with a good buffer + cout << "Testing Cubic Convolution" << endl; + double buf3[] = { 1.0, 2.0, 3.0, 4.0, + 5.0, 6.0, 7.0, 8.0, + 9.0, 10.0, 11.0, 12.0, + 13.0, 14.0, 15.0, 16.0}; + interp = new Isis::Interpolator (Isis::Interpolator::CubicConvolutionType); + cout << " 6.0 = " << interp->Interpolate (25.0, 10.0, buf3) << endl; + cout << " " << 8.5 << " = " << interp->Interpolate (25.5, 10.5, buf3) << endl; + cout << " " << 11.0 << " = " << + interp->Interpolate (25.9999999999999, 10.9999999999999, buf3) << endl; + + // Test Cubic Convolution with invalid data in edge of buffer + buf3[7] = Isis::HIGH_INSTR_SAT8; + cout << " 10.0 = " << interp->Interpolate (25.0, 10.9999999999999, buf3) << endl; + + // Test Cubic Convolution with invalid data in middle of buffer + buf3[7] = 8.0; + buf3[6] = Isis::LOW_INSTR_SAT8; + cout << " 6.0 = " << interp->Interpolate (25.999, 10.999, buf3) << endl; +} diff --git a/isis/src/base/objs/Isis/Isis.h b/isis/src/base/objs/Isis/Isis.h new file mode 100644 index 0000000000000000000000000000000000000000..55030350aefa4820e560c480367608d66670c814 --- /dev/null +++ b/isis/src/base/objs/Isis/Isis.h @@ -0,0 +1,193 @@ +/** + * @file + * $Revision: 1.7 $ + * $Date: 2009/07/29 21:14:35 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifdef __GTHREADS +#error *****Isis.h MUST be included before any other files!***** +#endif + +#include "IsisDebug.h" + +#include + +#include + +#include "Application.h" +#include "UserInterface.h" // this is an unnecessary include + +#ifndef APPLICATION +#define APPLICATION IsisMain +#endif + +/** + * @brief Base include file for all Isis applications + * + * This is not technically a class. Instead it is the main include file + * the must be placed at the beginning of every executable program. For + * example: + * @code + * using namespace std; + * #include "Isis.h" + * @endcode + * The include file + * handles starting the Isis GUI, error messages, and a host of other + * Isis related duties that should be performed in all Isis programs. + * It actually contains the standard C++ + * declaration of main (i.e., int main (int argc, char *argv[])) and + * invokes the function IsisMain which must + * be supplied by the programmer. Therefore, your program should + * always start as follows: + * @code + * using namespace std; + * #include "Isis.h" + * void IsisMain() { + * ... + * } + * @endcode + * The Isis.h file includes code that catches all thrown exceptions. It + * first trys to catch and report Isis specific errors. That is, + * those thrown + * within IsisMain or by Isis objects created in IsisMain. It will + * then catch C++ system type errors and respond accordingly. This + * eliminates the need for the application programmer to trap errors. + * They may however, throw errors as necessary to indicate error + * conditions within their application. + * + * @ingroup Utility + * + * @author 2002-01-01 Jeff Anderson + * + * @internal + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2006-03-18 Elizabeth Miller - Added gui helper stuff + * @history 2006-05-17 Elizabeth Miller - Removed .xml and documented .h file + */ +std::map GuiHelpers(); +#ifndef GUIHELPERS +std::map GuiHelpers() { + std::map empty; + return empty; +} +#endif + +void APPLICATION (); + +void startMonitoringMemory(); +void stopMonitoringMemory(); +void SegmentationFault(int); +void Abort(int); +void InterruptSignal(int); + +/** + * The programmer supplied main function + * + * @param argc - The application + * @param argv - The parameter string for the application + * + * @return int + */ +int main (int argc, char *argv[]) { +#ifdef CWDEBUG + startMonitoringMemory(); + signal(SIGSEGV, SegmentationFault); + signal(SIGABRT, Abort); + signal(SIGINT, InterruptSignal); +#endif + + Isis::Application *app = new Isis::Application(argc,argv); + app->RegisterGuiHelpers(GuiHelpers()); + int status = app->Exec(APPLICATION); + delete app; + delete QCoreApplication::instance(); + return status; +} + +#ifdef CWDEBUG +void startMonitoringMemory() { +#ifndef NOMEMCHECK + MyMutex *mutex = new MyMutex(); + std::fstream *alloc_output = new std::fstream("/dev/null"); + Debug( make_all_allocations_invisible_except(NULL) ); + ForAllDebugChannels( if (debugChannel.is_on()) debugChannel.off() ); + Debug( dc::malloc.on() ); + Debug( libcw_do.on() ); + Debug( libcw_do.set_ostream(alloc_output) ); + Debug( libcw_do.set_ostream(alloc_output, mutex) ); + atexit(stopMonitoringMemory); +#endif +} + + +void stopMonitoringMemory() { +#ifndef NOMEMCHECK + Debug( + alloc_filter_ct alloc_filter; + std::vector objmasks; + objmasks.push_back("libc.so*"); + objmasks.push_back("libstdc++*"); + std::vector srcmasks; + srcmasks.push_back("*new_allocator.h*"); + srcmasks.push_back("*set_ostream.inl*"); + alloc_filter.hide_objectfiles_matching(objmasks); + alloc_filter.hide_sourcefiles_matching(srcmasks); + alloc_filter.hide_unknown_locations(); + delete libcw_do.get_ostream(); + libcw_do.set_ostream(&std::cout); + list_allocations_on(libcw_do, alloc_filter); + dc::malloc.off(); + libcw_do.off() + ); +#endif +} + + +void SegmentationFault(int) { + std::vector currentStack; + StackTrace::GetStackTrace(¤tStack); + + std::cerr << "Segmentation Fault" << std::endl; + for(unsigned int i = 1; i < currentStack.size(); i++) { + std::cerr << currentStack[i] << std::endl; + } + + exit(1); +} + +void Abort(int) { + std::vector currentStack; + StackTrace::GetStackTrace(¤tStack); + + std::cerr << "Abort" << std::endl; + for(unsigned int i = 1; i < currentStack.size(); i++) { + std::cerr << currentStack[i] << std::endl; + } + + exit(1); +} + + +void InterruptSignal(int) { + exit(1); +} + +#endif diff --git a/isis/src/base/objs/Isis/Isis.truth b/isis/src/base/objs/Isis/Isis.truth new file mode 100644 index 0000000000000000000000000000000000000000..f688f11cdece56501e7ed93e7a785ca6c09872a7 --- /dev/null +++ b/isis/src/base/objs/Isis/Isis.truth @@ -0,0 +1 @@ +That's all folks diff --git a/isis/src/base/objs/Isis/IsisDebug.h b/isis/src/base/objs/Isis/IsisDebug.h new file mode 100644 index 0000000000000000000000000000000000000000..649bbf4fbcc453da4f8bbe9e612b471043d0f7a1 --- /dev/null +++ b/isis/src/base/objs/Isis/IsisDebug.h @@ -0,0 +1,116 @@ +#ifndef IsisDebug_h +#define IsisDebug_h + +#ifdef __GTHREADS +#error *****IsisDebug.h MUST be included before any system header files!***** +#endif + +void startMonitoringMemory(); +void stopMonitoringMemory(); +void SegmentationFault(int); +void Abort(int); +void InterruptSignal(int); + +#ifdef CWDEBUG + /** + * These includes may seem out of order but are necessary to be in this order + * for our debugging library libcwd + */ + #include + #include + #include + #include + + #include + #include + + /** + * The next two includes are bad, but are necessary without complicating code to + * an extreme. These shouldn't cause an issue because they are not included in + * release mode, or ever on systems without libcwd. iString is necessary for + * string conversions and Constants.h for the definition of BigInt. + */ + #include "iString.h" + #include "Constants.h" + + #define ASSERT(x) \ + if (!(x)) \ + { \ + std::cerr << ">> " << __FILE__ << ":" << __LINE__ << \ + " error: ASSERT " << #x << " FAILED\n"; \ + } + + /** + * This asserts the pointer is delete-able + */ + #define ASSERT_PTR(x) \ + if (libcwd::test_delete(x)) \ + { \ + std::cerr << ">> " << __FILE__ << ":" << __LINE__ << \ + " error: ASSERT POINTER " << #x << " FAILED\n"; \ + } + + class MyMutex : public QMutex { + public: + bool trylock() { + return tryLock(); + } + }; + + + class StackTrace { + public: + /** + * This returns the current stack trace. This must be + * done avoiding extra includes and inside this header + * file to accomplish stack traces with only the application + * in debug mode and not adding extra includes. + * + * Caller takes ownership of the return value. + * + * @return char* String containing stack trace + */ + static void GetStackTrace(std::vector *stackTraceResult) { + stackTraceResult->clear(); + const int MAX_STACK_DEPTH = 1024; + + void *stackTrace[MAX_STACK_DEPTH]; + int stackSize = backtrace(stackTrace, MAX_STACK_DEPTH); + + for (int stackEl = 2; stackEl < stackSize; stackEl ++) { + std::string currElement; + void *addr = stackTrace[stackEl]; + + libcwd::location_ct addrInfo(addr); + std::string demangled_name; + libcwd::demangle_symbol(addrInfo.mangled_function_name(), demangled_name); + + currElement = ">> "; + + if (addrInfo.is_known()) { + currElement += + std::string(addrInfo.file()) + + std::string(":") + + Isis::iString((Isis::BigInt)addrInfo.line()) + + std::string(" --- ") + + demangled_name; + } + else { + currElement += "?????:0 --- " + demangled_name; + } + + stackTraceResult->push_back(currElement); + } + } + }; + +#else + #define ASSERT(x) + #define ASSERT_PTR(x) + + class StackTrace { + public: + static void GetStackTrace(const void *) {} + }; +#endif +#endif diff --git a/isis/src/base/objs/Isis/Makefile b/isis/src/base/objs/Isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a0d57f72e6e172087ca23101c7b5a69f8477237e --- /dev/null +++ b/isis/src/base/objs/Isis/Makefile @@ -0,0 +1,5 @@ +INCS = Isis.h IsisDebug.h +SRCS = +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Isis/unitTest.cpp b/isis/src/base/objs/Isis/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4f61a5d3993a0d23b0b100a16fc31964a389a4a5 --- /dev/null +++ b/isis/src/base/objs/Isis/unitTest.cpp @@ -0,0 +1,40 @@ +#include "Isis.h" +#include "Preference.h" + +#include + +using namespace std; +void IsisMain () { + Isis::Preference::Preferences(true); + cout << "That's all folks" << endl; + + vector stackTrace; + StackTrace::GetStackTrace(&stackTrace); + + if(stackTrace.size()) { + cout << endl; + cout << "----- Stack Trace -----" << endl; + for(unsigned int i = 0; i < stackTrace.size(); i++) { + cout << stackTrace[i] << endl; + } + + cout << endl; + cout << "----- ASSERTS -----" << endl; + ASSERT(0); + ASSERT(1); + + cout << endl; + cout << "----- POINTER ASSERTS -----" << endl; + int *test = new int[5]; + cout << "VALID:" << endl; + ASSERT_PTR(test); + cout << "INVALID:" << endl; + ASSERT_PTR(test+1); + cout << "NULL:" << endl; + ASSERT_PTR(0); + + test[0] = 5; + + } + +} diff --git a/isis/src/base/objs/Isis/unitTest.xml b/isis/src/base/objs/Isis/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..4e2bf591954785465bbb701b41be210b6685bf9d --- /dev/null +++ b/isis/src/base/objs/Isis/unitTest.xml @@ -0,0 +1,41 @@ + + + + Unit test for IsisProcess class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + Modified schema from astrogeology... isis.astrogeology... + + + + + + + filename + + Test cube + + + Test cube + + + *.cub + + $ISISROOT/testData/base/isisTruth.cub + + + + diff --git a/isis/src/base/objs/IsisAml/IsisAml.cpp b/isis/src/base/objs/IsisAml/IsisAml.cpp new file mode 100644 index 0000000000000000000000000000000000000000..abd6434904eb751699fc86d0133f812e7cf7e897 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisAml.cpp @@ -0,0 +1,2900 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2007/10/17 22:45:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +using namespace std; + +#include +#include +#include +#include + +#include "iException.h" +#include "IsisAml.h" +#include "IsisXMLChTrans.h" +#include "Filename.h" +#include "iString.h" + +/** + * @internal + * @todo This namespace needs documentation. + */ +namespace XERCES = XERCES_CPP_NAMESPACE; + +/** + * Constructs an IsisAml object and internalizes the XML data in the given file + * name. + * + * @param xmlfile Indicates the pull path of the XML file to be parsed. + */ +IsisAml::IsisAml (const std::string &xmlfile) { + StartParser (xmlfile.c_str()); +} + +/** + * Destructs an IsisAml object. + */ +IsisAml::~IsisAml () { +} + +/** + * Allows the insertion of a value for any parameter. No validity check is + * performed on the value passed in. + * + * @param paramName The partial or full name of the parameter to be modified. + * @param value The string representation of the value to be placed in the + * parameters value data member. For parameters of type integer, the string + * must be convertable to an integer. For parameters of type double, the string + * must be convertable to a double. For parameters of type boolean, the string + * must be one of: (TRUE, FALSE, YES, NO, or a partial match of any of these + * beginning with the first character). + * + * @throws iException (IsisUserError) The parameter already has a value in its + * "value" data member.Overwriting an existing value is not allowed. Use "Clear" + * to erase all values in the value data member instead of overwriting an + * existing value. + */ +void IsisAml::PutAsString (const std::string ¶mName, + const std::string &value) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if (param->values.size () > 0) { + string message = "A value for this parameter [" + paramName + "] has " + "already been entered."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + + param->values.clear(); + param->values.push_back (value); + +} + +/** + * Allows the insertion of a value for any parameter. No validity check is + * performed on the value passed in. + * + * @param paramName The partial or full name of the parameter to be modified. + * @param value The string vector representation of the value to be placed in + * the parameters value data member. For parameters of type integer, the string + * must be convertable to an integer. For parameters of type double, the string + * must be convertable to a double. For parameters of type boolean, the string + * must be one of: (TRUE, FALSE, YES, NO, or a partial match of any of these + * beginning with the first character). + */ +void IsisAml::PutAsString (const std::string ¶mName, + const std::vector &value) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if (param->values.size () > 0) { + string message = "A value for this parameter [" + paramName + "] has " + "already been entered."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + + param->values.resize(value.size()); + param->values = value; + +} + + +// Public: Sets the value member of a parameter of type string whos name +// starts with paramName + +/** + * Allows the insertion of a value for any parameter. No validity check + * is + * performed on the value passed in. + * + * @param paramName The partial or full name of the parameter to be modified. + * @param value The string representation of the value to be placed in the + * parameters value data member. For parameters of type integer, the + * string + * must be convertable to an integer. For parameters of type double, the string + * must be convertable to a double. For parameters of type boolean, the string + * must be one of: (TRUE, FALSE, YES, NO, or a partial match of any of these + * beginning with the first character). + * + */ +void IsisAml::PutString (const std::string ¶mName, const std::string &value) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if (param->type != "string") { + string message = "Parameter [" + paramName + "] is not a string."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + if (param->values.size () > 0) { + string message = "A value for this parameter [" + paramName + "] has " + "already been saved (possibly by IsisGui). If you need to " + "change the value use \"Clear\" before the Put."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + param->values.clear(); + param->values.push_back (value); + + Verify (param); +} + + +// Public: Sets the value member of a parameter of type string whos name +// starts with paramName +/** + * Allows the insertion of a value for a parameter of type "string". A validity + * check is performed on the value passed in, but all strings are allowed. + * + * @param paramName The partial or full name of the parameter to be modified. + * @param value The string value to be placed in the string's value data member. + */ +void IsisAml::PutString (const std::string ¶mName, + const std::vector &value) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if (param->type != "string") { + string message = "Parameter [" + paramName + "] is not a string."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + if (param->values.size () > 0) { + string message = "A value for this parameter [" + paramName + "] has " + "already been saved (possibly by IsisGui). If you need to " + "change the value use \"Clear\" before the Put."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + param->values.resize(value.size()); + param->values = value; + + Verify (param); +} + + +// Public: Sets the value member of a parameter of type filename whos name +// starts with paramName + +/** + * Allows the insertion of a value for a parameter of type "filename". A + * validity check is performed on the value passed in. + * + * @param paramName The partial or full name of the parameter to be modified. + * @param value The string representation of the value to be placed in the + * filename's value data member. + */ +void IsisAml::PutFilename (const std::string ¶mName, + const std::string &value) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if ((param->type != "filename") && (param->type != "cube")) { + string message = "Parameter [" + paramName + "] is not a filename."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + if (param->values.size () > 0) { + string message = "A value for this parameter [" + paramName + "] has " + "already been saved (possibly by IsisGui). If you need to " + "change the value use \"Clear\" before the Put."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + param->values.clear(); + param->values.push_back (value); + + Verify (param); +} + + +// Public: Sets the value member of a parameter of type filename whos name +// starts with paramName + +/** + * Allows the insertion of a value for a parameter of type "filename". A + * validity check is performed on the value passed in. + * + * @param paramName The partial or full name of the parameter to be modified. + * @param value The string vector representation of the value to be placed in + * the filename's value data member. + * + * @throws iException (IsisProgrammerError) The parameter is not of type + * "filename". + * @throws iException (IsisProgrammerError) The parameter already has a value + * in its "value" data member. Overwriting an existing value is not allowed. + * Use "Clear" to erase all values in the value data member instead of + * overwriting an existing value. + */ +void IsisAml::PutFilename (const std::string ¶mName, + const std::vector &value) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if ((param->type != "filename") && (param->type != "cube")) { + string message = "Parameter [" + paramName + "] is not a filename."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + if (param->values.size () > 0) { + string message = "A value for this parameter [" + paramName + "] has " + "already been saved (possibly by IsisGui). If you need to " + "change the value use \"Clear\" before the Put."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + param->values.resize(value.size()); + param->values = value; + + Verify (param); +} + + +// Public: Sets the value member of a parameter of type integer whos name +// starts with paramName + +/** + * Allows the insertion of a value for a parameter of type "integer". A + * validity check is performed on the value passed in. + * + * @param paramName The partial or full name of the parameter to be modified. + * @param value The integer value to be placed in the integer's value data + * member. + * + * @throws iException (IsisProgrammerError) The parameter is not of type + * "int". + */ +void IsisAml::PutInteger (const std::string ¶mName, + const int &value) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if (param->type != "integer") { + string message = "Parameter [" + paramName + "] is not an integer."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + if (param->values.size () > 0) { + string message = "A value for this parameter [" + paramName + "] has " + "already been saved (possibly by IsisGui). If you need to " + "change the value use \"Clear\" before the Put."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + param->values.clear(); + param->values.push_back (Isis::iString(value)); + + Verify (param); +} + + +// Public: Sets the value member of a parameter of type integer whos name +// starts with paramName + +/** + * Allows the insertion of a value for a parameter of type "integer". A + * validity check is performed on the value passed in. + * + * @param paramName The partial or full name of the parameter to be modified. + * @param value The integer vector to be placed in the integer's value data + * member. + * + * @throws iException (IsisProgrammerError) The parameter already has a value + * in its "value" data member.Overwriting an existing value is not allowed. Use + * "Clear" to erase all values in the value data member instead of overwriting + * an existing value. + * @throws iException (IsisProgrammerError) The parameter is not of type "int". + */ +void IsisAml::PutInteger (const std::string ¶mName, + const std::vector &value) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if (param->type != "integer") { + string message = "Parameter [" + paramName + "] is not an integer."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + if (param->values.size () > 0) { + string message = "A value for this parameter [" + paramName + "] has " + "already been saved (possibly by IsisGui). If you need to " + "change the value use \"Clear\" before the Put."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + param->values.resize (value.size()); + for (unsigned int i = 0; i < value.size(); i++) { + param->values[i] = Isis::iString(value[i]); + } + + Verify (param); +} + + + + +// Public: Sets the value member of a parameter of type double whos name +// starts with paramName +/** + * Allows the insertion of a value for a parameter of type "double". A + * validity check is performed on the value passed in. + * + * @param paramName The partial or full name of the parameter to be modified. + * @param value The double value to be placed in the double's value data + * member. + * + * @throws iException (IsisProgrammerError) The parameter already has a value + * in its "value" data member.Overwriting an existing value is not allowed. Use + * "Clear" to erase all values in the value data member instead of overwriting + * an existing value. + * @throws iException (IsisProgrammerError) The parameter is not of type + * "double". + */ +void IsisAml::PutDouble (const std::string ¶mName, + const double &value) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if (param->type != "double") { + string message = "Parameter [" + paramName + "] is not a double."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + if (param->values.size () > 0) { + string message = "A value for this parameter [" + paramName + "] has " + "already been saved (possibly by IsisGui). If you need to " + "change the value use \"Clear\" before the Put."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + param->values.clear(); + param->values.push_back (Isis::iString(value)); + + Verify (param); +} + + +// Public: Sets the value member of a parameter of type double whos name +// starts with paramName +/** + * Allows the insertion of a value for a parameter of type "double". A + * validity check is performed on the value passed in. + * + * @param paramName The partial or full name of the parameter to be modified. + * @param value The double vector to be placed in the double's value data + * member. + * + * @throws iException (IsisProgrammerError) The parameter already has a value + * in its "value" data member.Overwriting an existing value is not allowed. Use + * "Clear" to erase all values in the value data member instead of overwriting + * an existing value. + * @throws iException (IsisProgrammerError) The parameter is not of type + * "double". + */ +void IsisAml::PutDouble (const std::string ¶mName, + const std::vector &value) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if (param->type != "double") { + string message = "Parameter [" + paramName + "] is not a double."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + if (param->values.size () > 0) { + string message = "A value for this parameter [" + paramName + "] has " + "already been saved (possibly by IsisGui). If you need to " + "change the value use \"Clear\" before the Put."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + param->values.resize (value.size()); + for (unsigned int i = 0; i < value.size(); i++) { + param->values[i] = Isis::iString(value[i]); + } + + Verify (param); +} + + + +// Public: Sets the value member of a parameter of type boolean whos name +// starts with paramName +/** + * Allows the insertion of a value for a parameter of type "boolean". A + * validity check is performed on the value passed in. + * + * @param paramName The partial or full name of the parameter to be modified. + * @param value The boolean value to be placed in the boolean's value data + * member. + * + * @throws iException (IsisProgrammerError) The parameter already has a value + * in its "value" data member.Overwriting an existing value is not allowed. Use + * "Clear" to erase all values in the value data member instead of overwriting + * an existing value. + * @throws iException (IsisProgrammerError) The parameter is not of type + * "boolean". + */ +void IsisAml::PutBoolean (const std::string ¶mName, + const bool &value) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if (param->type != "boolean") { + string message = "Parameter [" + paramName + "] is not a boolean."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + if (param->values.size () > 0) { + string message = "A value for this parameter [" + paramName + "] has " + "already been saved (possibly by IsisGui). If you need to " + "change the value use \"Clear\" before the Put."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + param->values.clear(); + if (value) { + param->values.push_back ("YES"); + } + else { + param->values.push_back ("NO"); + } + + Verify (param); +} + + +// Public: Sets the value member of a parameter of type boolean whos name +// starts with paramName +/** + * Allows the insertion of a value for a parameter of type "boolean". A + * validity check is performed on the value passed in. + * + * @param paramName The partial or full name of the parameter to be modified. + * @param value The boolean vector to be placed in the boolean's value data + * member. + * + * @throws iException (IsisProgrammerError) The parameter already has a value + * in its "value" data member.Overwriting an existing value is not allowed. Use + * "Clear" to erase all values in the value data member instead of overwriting + * an existing value. + * @throws iException (IsisProgrammerError) The parameter is not of type + * "boolean". + */ +void IsisAml::PutBoolean (const std::string ¶mName, + const std::vector &value) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if (param->type != "boolean") { + string message = "Parameter [" + paramName + "] is not a boolean."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + if (param->values.size () > 0) { + string message = "A value for this parameter [" + paramName + "] has " + "already been saved (possibly by IsisGui). If you need to " + "change the value use \"Clear\" before the Put."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + param->values.resize (value.size()); + for (unsigned int i = 0; i < value.size(); i++) { + if (value[i]) { + param->values.push_back ("YES"); + } + else { + param->values.push_back ("NO"); + } + } + + Verify (param); +} + + +// Accessor methods for getting the value(s) of a parameter + +// Public: Returns the first element of the value member of a parameter whos +// name starts with paramName as a string. Any type can be retrieve with this member. +/** + * Allows the retrieval of a value for a parameter of any type. The value will + * be returned as a string no matter what the parameter type is. + * + * @param paramName The partial or full name of the parameter to be retrieved. + * + * @return A string representation of the value for the specified parameter. + * + * @throws iException (IsisProgrammerError) The parameter has no value. + */ +string IsisAml::GetAsString (const std::string ¶mName) const { + + const IsisParameterData *param = ReturnParam (paramName); + string value; + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + string message = "Parameter [" + paramName + "] has no value."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + else { + value = param->defaultValues[0]; + } + } + else { + value = param->values[0]; + } + + return value; +} + +// Public: Returns the value member of a parameter whos name starts with paramName +// as a vector +/** + * Allows the retrieval of a value for a parameter of any type. The value will + * be returned as a string no matter what the parameter type is. + * + * @param paramName The partial or full name of the parameter to be retrieved. + * @param values The value member of the parameter whose name starts with + * paramName. + * + * @throws iException (IsisProgrammerError) The parameter has no value. + */ +void IsisAml::GetAsString (const std::string ¶mName, + std::vector &values) const{ + + const IsisParameterData *param = ReturnParam (paramName); + + values.clear(); + string value; + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + string message = "Parameter [" + paramName + "] has no value."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + for (unsigned int i = 0; idefaultValues.size(); i++) + values.push_back (param->defaultValues[i]); + } + } + else { + for (unsigned int i = 0; ivalues.size(); i++) + values.push_back (param->values[i]); + } + + return; +} + + +// Public: Returns the first element of the value member of a parameter whos +// name starts with paramName as a string/filename +/** + * Allows the retrieval of a value for a parameter of type "filename". + * + * @param paramName The partial or full name of the parameter to be retrieved. + * @param extension A default extension to add if it does not already exist on + * the file name. For example, "txt" will make /mydir/myfile into + * /mydir/myfile.txt + * + * @return The value of the parameter. + */ +string IsisAml::GetFilename (const std::string ¶mName, std::string extension) const { + + const IsisParameterData *param = ReturnParam (paramName); + + if ((param->type != "filename") && (param->type != "cube")) { + string message = "Parameter [" + paramName + "] is not a filename."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + string value; + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + string message = "Parameter [" + paramName + "] has no value."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + value = param->defaultValues[0]; + } + } + else { + value = param->values[0]; + } + + Isis::Filename name(value); + if (extension != "") name.AddExtension(extension); + value = name.Expanded(); + + return value; +} + + +// Public: Returns the value member of a parameter whos name starts with paramName +// as a vector +/** + * Allows the retrieval of a value for a parameter of type "filename". + * + * @param paramName The partial or full name of the parameter to be retrieved. + * @param values The value membet of the parameter whose name starts with + * paramName. + */ +void IsisAml::GetFilename (const std::string ¶mName, + std::vector &values) const { + + const IsisParameterData *param = ReturnParam (paramName); + + if ((param->type != "filename") && (param->type != "cube")) { + string message = "Parameter [" + paramName + "] is not a filename."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + values.clear(); + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + string message = "Parameter [" + paramName + "] has no value."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + for (unsigned int i=0; idefaultValues.size(); i++) { + Isis::Filename name(param->defaultValues[i]); + values.push_back (name.Expanded()); + } + } + } + else { + for (unsigned int i=0; ivalues.size(); i++) { + Isis::Filename name(param->values[i]); + values.push_back (name.Expanded()); + } + } + + return; +} + + +// Public: Returns the first element of the value member of a parameter whos +// name starts with paramName as a string +/** + * Allows the retrieval of a value for a parameter of type "string". + * + * @param paramName The partial or full name of the parameter to be retrieved. + * + * @return The value of the parameter. + * + * @throws iException::Programmer (IsisErrorUser) The parameter has no value. + */ +string IsisAml::GetString (const std::string ¶mName) const { + + const IsisParameterData *param = ReturnParam (paramName); + Isis::iString value; + + if (param->type != "string") { + string message = "Parameter [" + paramName + "] is not a string."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + string message = "Parameter [" + paramName + "] has no value."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + value = param->defaultValues[0]; + } + } + else { + value = param->values[0]; + // If there is a list of legal values return the list option that matches + // or begins with what was entered rather than exactly what was entered + if (param->listOptions.size () > 0) { + value = value.UpCase(); + int found = -1; + for (unsigned int p=0; plistOptions.size (); p++) { + Isis::iString option = param->listOptions[p].value; + option = option.UpCase(); + if (value == option) { + return value; + } + else if (value.compare(0, min(value.size(), option.size()), + option ,0, min(value.size(), option.size())) == 0) { + if (found != -1) { + string message = "Value [" + value + "] for parameter [" + + paramName + "] is not unique."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + found = p; + } + } + return param->listOptions[found].value; + } + + // Just return what is in the value + else { + value = param->values[0]; + } + } + return value; +} + + +// Public: Returns the value member of a parameter whos name starts with paramName +// as a vector +/** + * Allows the retrieval of a value for a parameter of type "string". + * + * @param paramName The partial or full name of the parameter to be retrieved. + * + * @param values The value member of a parameter whose name starts with + * paramName. + * + * @throws iException::Programmer (IsisErrorUser) The parameter has no value. + */ +void IsisAml::GetString (const std::string ¶mName, + std::vector &values) const { + + const IsisParameterData *param = ReturnParam (paramName); + + if (param->type != "string") { + string message = "Parameter [" + paramName + "] is not a string."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + values.clear(); + string value; + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + string message = "Parameter [" + paramName + "] has no value."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + for (unsigned int i = 0; idefaultValues.size(); i++) + values.push_back (param->defaultValues[i]); + } + } + else { + for (unsigned int i = 0; ivalues.size(); i++) + values.push_back (param->values[i]); + } + + return; +} + + + +// Public: Returns the first element of the value member of a parameter whos +// name starts with paramName as an integer +/** + * Allows the retrieval of a value for a parameter of type "integer". + * + * @param paramName The partial or full name of the parameter to be retrieved. + * + * @return The value of the parameter. + * + * @throws iException::Programmer (IsisErrorUser) The parameter has no value. + */ +int IsisAml::GetInteger (const std::string ¶mName) const { + + const IsisParameterData *param = ReturnParam (paramName); + + if (param->type != "integer") { + string message = "Parameter [" + paramName + "] is not an integer."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + Isis::iString value; + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + string message = "Parameter [" + paramName + "] has no value."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + value = param->defaultValues[0]; + } + } + else { + value = param->values[0]; + } + + return value.ToInteger(); +} + + +// Public: Returns the value member of a parameter whos name starts with paramName +// as a vector +/** + * Allows the retrieval of a value for a parameter of type "integer". + * + * @param paramName The partial or full name of the parameter to be retrieved. + * + * @param values The value member of a parameter whose name starts with + * paramName. + * + * @throws iException::Programmer (IsisErrorUser) The parameter has no value. + */ +void IsisAml::GetInteger (const std::string ¶mName, + std::vector &values) const { + + const IsisParameterData *param = ReturnParam (paramName); + + if (param->type != "integer") { + string message = "Parameter [" + paramName + "] is not an integer."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + values.clear(); + Isis::iString value; + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + string message = "Parameter [" + paramName + "] has no value."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + for (unsigned int i = 0; idefaultValues.size(); i++) + value = param->defaultValues[i]; + values.push_back (value.ToInteger()); + } + } + else { + for (unsigned int i = 0; ivalues.size(); i++) + value = param->values[i]; + values.push_back (value.ToInteger()); + } + + return; +} + + + + // Public: Returns the first element of the value member of a parameter whos + // name starts with paramName as a doubble +/** + * Allows the retrieval of a value for a parameter of type "double". + * + * @param paramName The partial or full name of the parameter to be retrieved. + * + * @return The value of the parameter. + * + * @throws iException::Programmer (IsisErrorUser) The parameter has no value. + */ +double IsisAml::GetDouble (const std::string ¶mName) const { + + const IsisParameterData *param = ReturnParam (paramName); + + if (param->type != "double") { + string message = "Parameter [" + paramName + "] is not a double."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + Isis::iString value; + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + string message = "Parameter [" + paramName + "] has no value."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + value = param->defaultValues[0]; + } + } + else { + value = param->values[0]; + } + + return value.ToDouble(); +} + +// Public: Returns the value member of a parameter whos name starts with paramName +// as a vector +/** + * Allows the retrieval of a value for a parameter of type "double". + * + * @param paramName The partial or full name of the parameter to be retrieved. + * + * @param values The value member of a parameter whose name starts with + * paramName. + * + * @throws iException::Programmer (IsisErrorUser) The parameter has no value. + */ +void IsisAml::GetDouble (const std::string ¶mName, + std::vector &values) const { + + const IsisParameterData *param = ReturnParam (paramName); + + if (param->type != "double") { + string message = "Parameter [" + paramName + "] is not a double."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + values.clear(); + Isis::iString value; + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + string message = "Parameter [" + paramName + "] has no value."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + for (unsigned int i = 0; idefaultValues.size(); i++) + value = param->defaultValues[i]; + values.push_back (value.ToDouble()); + } + } + else { + for (unsigned int i = 0; ivalues.size(); i++) + value = param->values[i]; + values.push_back (value.ToDouble()); + } + + return; +} + + +// Public: Returns the first element of the value member of a parameter whos +// name starts with paramName as a bool +/** + * Allows the retrieval of a value for a parameter of type "boolean". + * + * @param paramName The partial or full name of the parameter to be retrieved. + * + * @return The value of the parameter. + * + * @throws iException::Programmer (IsisErrorUser) The parameter has no value. + */ +bool IsisAml::GetBoolean (const std::string ¶mName) const { + + const IsisParameterData *param = ReturnParam (paramName); + + if (param->type != "boolean") { + string message = "Parameter [" + paramName + "] is not a boolean."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + Isis::iString value; + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + string message = "Parameter [" + paramName + "] has no value."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + value = param->defaultValues[0]; + } + } + else { + value = param->values[0]; + } + + return StringToBool (value); + +} + + +// Public: Returns the value member of a parameter whos name starts with paramName +// as a vector +/** + * Allows the retrieval of a value for a parameter of type "boolean". + * + * @param paramName The partial or full name of the parameter to be retrieved. + * + * @param values The member value of a parameter whose name starts with + * paramName.. + * + * @throws iException::Programmer (IsisErrorUser) The parameter has no value. + */ +void IsisAml::GetBoolean (const std::string ¶mName, + std::vector &values) const { + + const IsisParameterData *param = ReturnParam (paramName); + + if (param->type != "boolean") { + string message = "Parameter [" + paramName + "] is not a boolean."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + values.clear(); + vector value; + Isis::iString tmp; + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + string message = "Parameter [" + paramName + "] has no value."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + for (unsigned int i = 0; idefaultValues.size(); i++) { + tmp = param->defaultValues[i]; + tmp.UpCase(); + value.push_back (tmp); + } + } + } + else { + for (unsigned int i = 0; ivalues.size(); i++) { + tmp = param->values[i]; + tmp.UpCase(); + value.push_back (tmp); + } + } + + for (unsigned int i = 0; ivalues.size() == 0) { + return false; + } + + return true; +} + +/** + * Clears the value(s) in the named parameter + * + * @param paramName The name of the parameter to clear + */ +void IsisAml::Clear (const std::string ¶mName) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + param->values.clear(); + + param->outCubeAtt.Reset(); + param->outCubeAtt.Set("+"+param->pixelType); + param->inCubeAtt.Reset(); + + return; +} + + +/** + * Gets the attributes for an input cube + * + * @param paramName The name of the parameter to get the attributes for + * + * @return CubeAttributeInput + * + * @throws iException::Programmer (Parameter is not a cube) + * @throws iException::Programmer (Parameter does nto contain an input file) + */ +Isis::CubeAttributeInput& IsisAml::GetInputAttribute (const std::string ¶mName) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if (param->type != "cube") { + string message = "Parameter [" + paramName + "] is not a cube."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + string value; + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + value.clear(); +// string message = "Parameter [" + paramName + "] has no value."; +// throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + value = param->defaultValues[0]; + } + } + else { + value = param->values[0]; + } + if (param->fileMode == "input") { + param->inCubeAtt.Reset(); + param->inCubeAtt.Set(value); + } + else { + string message = "Parameter [" + paramName + "] does not contain an [input] file"; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + return param->inCubeAtt; +} + +/** + * Gets the attributes for an output cube + * + * @param paramName The name of the parameter to get the attributes for + * + * @return CubeAttributeOutput + * + * @throws iException::Programmer (Parameter is not a cube) + * @throws iException::Programmer (Parameter does nto contain an output file) + */ +Isis::CubeAttributeOutput& IsisAml::GetOutputAttribute (const std::string ¶mName) { + + IsisParameterData *param = const_cast (ReturnParam (paramName)); + + if (param->type != "cube") { + string message = "Parameter [" + paramName + "] is not a cube."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + + string value; + if (param->values.size() == 0) { + if (param->defaultValues.size() == 0) { + value.clear(); +// string message = "Parameter [" + paramName + "] has no value."; +// throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else { + value = param->defaultValues[0]; + } + } + else { + value = param->values[0]; + } + if (param->fileMode == "output") { + param->outCubeAtt.Reset(); + param->outCubeAtt.Set("+"+param->pixelType); + param->outCubeAtt.Set(value); + } + else { + string message = "Parameter [" + paramName + "] does not contain an [output] file"; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + return param->outCubeAtt; +} + +/** + * Returns a pointer to a parameter whos name starts with paramName + * + * @param paramName The name of the parameter to return + * + * @return IsisParameterData + * + * @throws iException::User (Parameter is not unique) + * @throws iException::User (Unknown Parameter) + */ +const IsisParameterData *IsisAml::ReturnParam (const std::string ¶mName) const { + Isis::iString pn = paramName; + pn.UpCase(); + int found = 0; + bool exact = false; + const IsisParameterData *param = NULL; + Isis::iString cur_pn; + + for (unsigned int g=0; g 1) && (!exact)) { + string message = "Parameter [" + paramName + "] is not unique."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + return param; +} + +/** + * Throws an Isis::iExceptionXxxxxxxx if the parameter value(s) is invalid + * + * @param param The parameter data + * + * @throws iException::User + */ +void IsisAml::Verify (const IsisParameterData *param) { + + // Check to make sure the value string can be converted to the correct type + for (unsigned int i=0; ivalues.size (); i++) { + if (param->type == "integer") { + try { + Isis::iString value (param->values[i]); + value.ToInteger(); + } + catch (Isis::iException &e) { + string message = "Unable to convert [" + param->values[i] + "] to an integer," + " parameter [" + param->name + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + else if (param->type == "double") { + try { + Isis::iString value (param->values[i]); + value.ToDouble(); + } + catch (Isis::iException &e) { + string message = "Unable to convert [" + param->values[i] + "] to a double," + " parameter [" + param->name + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + else if (param->type == "boolean") { + Isis::iString v = param->values[i]; + v.UpCase(); + + try { + StringToBool (v); + } + catch (Isis::iException &e) { + string message = "Illegal value for [" + param->name + "], [" + param->values[i] + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + else if (param->type == "filename") { + // Put something here once we figure out what to do with filenames + } + } + + // Check the default values if there were no values + if (param->values.size () == 0) { + for (unsigned int i=0; idefaultValues.size (); i++) { + // Check to make sure the DefaultValue string can be converted to the + // correct type + if (param->type == "integer") { + try { + Isis::iString value (param->defaultValues[i]); + value.ToInteger(); + } + catch (Isis::iException &e) { + string message = "Unable to convert default [" + param->defaultValues[i] + + "] to an integer, parameter [" + param->name + "]."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + } + else if (param->type == "double") { + try { + Isis::iString value (param->defaultValues[i]); + value.ToDouble(); + } + catch (Isis::iException &e) { + string message = "Unable to convert default [" + param->defaultValues[i] + + "] to a double, parameter [" + param->name + "]."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + } + else if (param->type == "boolean") { + Isis::iString v = param->defaultValues[i]; + v.UpCase(); + + try { + StringToBool (v); + } + catch (Isis::iException &e) { + string message = "Illegal default value for [" + param->name + "], [" + + param->defaultValues[i] + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + else if (param->type == "filename") { + // Put something here once we figure out what to do with filenames + } + } + } + + // Check the values against the values list if there is one + if (param->listOptions.size () > 0) { + for (unsigned int i=0; ivalues.size (); i++) { + Isis::iString value = param->values[i]; + value = value.UpCase(); + int partial = 0; + bool exact = false; + for (unsigned int p=0; plistOptions.size (); p++) { + Isis::iString option = param->listOptions[p].value; + option = option.UpCase(); + // Check to see if the value matches the list option exactly + if (value == option) { + // If we already have one exact match then there is an error + if (exact) { + string message = "Duplicate list options [" + + param->listOptions[p].value + + "] in parameter [" + param->name + "]."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + exact = true; + } + // Check for a partial match + // Compare the shorter of the two (values[i]) to a substring of the + // longer string (listOptions[p].value) + else if (option.compare(0, min(value.size(),option.size()), + value, 0, min(value.size(),option.size())) == 0) { + partial++; + } + } + if (!exact && partial == 0) { + string message = "Value of [" + param->name + "] must be one of [" + + param->listOptions[0].value; + for (unsigned int p=1; plistOptions.size (); p++) { + message += ", " + param->listOptions[p].value; + } + message += "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else if (!exact && partial > 1) { + string msg = "Value of [" + param->name + + "] does not match a list option uniquely."; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + } + } + + // Check the values against the minimum + if (param->minimum.length () > 0) { + Isis::iString incl = param->minimum_inclusive; + for (unsigned int i=0; ivalues.size (); i++) { + if (param->type == "integer") { + Isis::iString value (param->values[i]); + int temp = value.ToInteger(); + value = param->minimum; + int min = value.ToInteger(); + if (StringToBool(incl) && (temp < min)) { + string message = "Parameter [" + param->name + + "] must be greater than or equal to [" + param->minimum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else if (!StringToBool(incl) && (temp <= min)) { + string message = "Parameter [" + param->name + + "] must be greater than [" + param->minimum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + else if (param->type == "double") { + Isis::iString value (param->values[i]); + double temp = value.ToDouble(); + value = param->minimum; + double min = value.ToDouble(); + if (StringToBool(incl) && (temp < min)) { + string message = "Parameter [" + param->name + + "] must be greater than or equal to [" + param->minimum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else if (!StringToBool(incl) && (temp <= min)) { + string message = "Parameter [" + param->name + + "] must be greater than [" + param->minimum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + if (param->values.size () == 0) { + for (unsigned int i=0; idefaultValues.size (); i++) { + if (param->type == "integer") { + Isis::iString value (param->defaultValues[i]); + int temp = value.ToInteger(); + value = param->minimum; + int min = value.ToInteger(); + if (StringToBool(incl) && (temp < min)) { + string message = "Parameter [" + param->name + + "] must be greater than or equal to [" + param->minimum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else if (!StringToBool(incl) && (temp <= min)) { + string message = "Parameter [" + param->name + + "] must be greater than [" + param->minimum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + else if (param->type == "double") { + Isis::iString value (param->defaultValues[i]); + double temp = value.ToDouble(); + value = param->minimum; + double min = value.ToDouble(); + if (StringToBool(incl) && (temp < min)) { + string message = "Parameter [" + param->name + + "] must be greater than or equal to [" + param->minimum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else if (!StringToBool(incl) && (temp <= min)) { + string message = "Parameter [" + param->name + + "] must be greater than [" + param->minimum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } + } + + // Check the values against the maximum + if (param->maximum.length () > 0) { + Isis::iString incl = param->maximum_inclusive; + incl.DownCase(); + for (unsigned int i=0; ivalues.size (); i++) { + if (param->type == "integer") { + Isis::iString value (param->values[i]); + int temp = value.ToInteger(); + value = param->maximum; + int max = value.ToInteger(); + if (StringToBool(incl) && (temp > max)) { + string message = "Parameter [" + param->name + + "] must be less than or equal to [" + param->maximum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else if (!StringToBool(incl) && (temp >= max)) { + string message = "Parameter [" + param->name + + "] must be less than [" + param->maximum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + else if (param->type == "double") { + Isis::iString value (param->values[i]); + double temp = value.ToDouble(); + value = param->maximum; + double max = value.ToDouble(); + if (StringToBool(incl) && (temp > max)) { + string message = "Parameter [" + param->name + + "] must be less than or equal to [" + param->maximum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else if (!StringToBool(incl) && (temp >= max)) { + string message = "Parameter [" + param->name + + "] must be less than [" + param->maximum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + if (param->values.size () == 0) { + for (unsigned int i=0; idefaultValues.size (); i++) { + if (param->type == "integer") { + Isis::iString value (param->defaultValues[i]); + int temp = value.ToInteger(); + value = param->maximum; + int max = value.ToInteger(); + if (StringToBool(incl) && (temp > max)) { + string message = "Parameter [" + param->name + + "] must be less than or equal to [" + param->maximum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else if (!StringToBool(incl) && (temp >= max)) { + string message = "Parameter [" + param->name + + "] must be less than [" + param->maximum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + else if (param->type == "double") { + Isis::iString value (param->defaultValues[i]); + double temp = value.ToDouble(); + value = param->maximum; + double max = value.ToDouble(); + if (StringToBool(incl) && (temp > max)) { + string message = "Parameter [" + param->name + + "] must be less than or equal to [" + param->maximum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + else if (!StringToBool(incl) && (temp >= max)) { + string message = "Parameter [" + param->name + + "] must be less than [" + param->maximum + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } + } + + // Check the value for an odd test + Isis::iString odd = param->odd; + odd.DownCase(); + + if ((odd != "") || StringToBool(odd)) { + if (param->type != "integer") { + string message = "Parameter [" + param->name + + "] must be of type integer to have an [odd] test."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + else { + for (unsigned int i=0; ivalues.size (); i++) { + Isis::iString value (param->values[i]); + if ((value.ToInteger() % 2) != 1) { + string message = "Value for [" + param->name + "] must be odd."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } + return; +} + + +//! Verify all parameters +void IsisAml::VerifyAll () { + for (unsigned int g=0; ggroups[g].parameters[p]); + + Verify (param); + + // Check the values for inclusive clauses + for (unsigned int item=0; iteminclude.size(); item++) { + // If this parameter is a boolean and it is true/yes + // all included parameters must have some type of value + if (param->type == "boolean") { + if (((param->values.size() > 0) && StringToBool(param->values[0])) || + ((param->values.size() == 0) && (param->defaultValues.size() > 0) + && StringToBool(param->defaultValues[0]))) { + + const IsisParameterData *param2 = ReturnParam (param->include[item]); + if ((param2->values.size()) == 0 && + (param2->defaultValues.size() == 0) && + (param2->internalDefault.size() == 0)) { + string message = "Parameter [" + param2->name + + "] must be used if parameter [" + + param->name + "] equates to true."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + // This parameter is NOT a boolean but the other one might be + else { + // If the other parameter is a boolean and it is true/yes + // then this parameter must have some type of value + const IsisParameterData *param2 = ReturnParam (param->include[item]); + if (param2->type == "boolean") { + if (((param2->values.size() > 0) && StringToBool(param2->values[0])) || + ((param2->values.size() == 0) && (param2->defaultValues.size() > 0) && + StringToBool(param2->defaultValues[0]))) { + if ((param->values.size()) == 0 && + (param->defaultValues.size() == 0) && + (param->internalDefault.size() == 0)) { + string message = "Parameter [" + param2->name + + "] must be used if parameter [" + + param->name + "] is used."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + // Neithter parameter is a boolean so + // If this one has a value the other parameter must have some type of value + else { + if (param->values.size() > 0 && + param2->values.size() == 0 && + param2->defaultValues.size() == 0 && + param2->internalDefault.size() == 0) { + string message = "Parameter [" + param2->name + + "] must be used if parameter [" + + param->name + "] is used."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } + // Check the values for exclusive clauses + for (unsigned int item=0; itemexclude.size(); item++) { + // If this parameter is a boolean that is true/yes + // the other parameter should not have a value + if (param->type == "boolean") { + if (((param->values.size() > 0) && StringToBool(param->values[0])) || + ((param->values.size() == 0) && (param->defaultValues.size() > 0) && + StringToBool(param->defaultValues[0]))) { + + const IsisParameterData *param2 = ReturnParam (param->exclude[item]); + if (param2->values.size() > 0) { + string message = "Parameter [" + param2->name + + "] must NOT be used if parameter [" + + param->name + "] equates to true."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + // This parameter is NOT a boolean but the other one might be + else { + const IsisParameterData *param2 = ReturnParam (param->exclude[item]); + if (param2->type == "boolean") { + if (((param2->values.size() > 0) && StringToBool(param2->values[0])) || + ((param2->values.size() == 0) && (param2->defaultValues.size() > 0) && + StringToBool(param2->defaultValues[0]))) { + if (param->values.size() > 0) { + string message = "Parameter [" + param2->name + + "] must be used if parameter [" + + param->name + "] is used."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + // Neither parameter is a boolean + else { + if (param->values.size() > 0 && param2->values.size() > 0) { + string message = "Parameter [" + param2->name + + "] must NOT be used if parameter [" + + param->name + "] is used."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } + + // Check the values for greaterThan clauses + if (param->values.size() > 0) { + for (unsigned int item=0; itemgreaterThan.size(); item++) { + const IsisParameterData *param2 = ReturnParam (param->greaterThan[item]); + if (param2->values.size() != 0) { + double double1, double2; + if (param->type == "integer") { + double1 = (double) GetInteger (param->name); + } + else if (param->type == "double") { + double1 = GetDouble (param->name); + } + else { + string msg = "Parameter is not INTEGER or DOUBLE type [" + + param->name + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (param2->type == "integer") { + double2 = GetInteger (param2->name); + } + else if (param2->type == "double") { + double2 = GetDouble (param2->name); + } + else { + string msg = "Parameter is not INTEGER or DOUBLE type [" + + param->name + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (double2 >= double1) { + string message = "Parameter [" + param->name + + "] must be greater than parameter [" + + param2->name + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } + + // Check the values for greaterThanOrEqual clauses + if (param->values.size() > 0) { + for (unsigned int item=0; itemgreaterThanOrEqual.size(); item++) { + const IsisParameterData *param2 = + ReturnParam(param->greaterThanOrEqual[item]); + if (param2->values.size() != 0) { + double double1, double2; + if (param->type == "integer") { + double1 = (double) GetInteger (param->name); + } + else if (param->type == "double") { + double1 = GetDouble (param->name); + } + else { + string msg = "Parameter is not INTEGER or DOUBLE type [" + + param->name + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (param2->type == "integer") { + double2 = GetInteger (param2->name); + } + else if (param2->type == "double") { + double2 = GetDouble (param2->name); + } + else { + string msg = "Parameter is not INTEGER or DOUBLE type [" + + param->name + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (double2 > double1) { + string message = "Parameter [" + param->name + + "] must be greater than or equal to parameter [" + + param2->name + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } + // Check the values for lessThan clauses + if (param->values.size() > 0) { + for (unsigned int item=0; itemlessThan.size(); item++) { + const IsisParameterData *param2 = ReturnParam (param->lessThan[item]); + if (param2->values.size() != 0) { + double double1, double2; + if (param->type == "integer") { + double1 = (double) GetInteger (param->name); + } + else if (param->type == "double") { + double1 = GetDouble (param->name); + } + else { + string msg = "Parameter is not INTEGER or DOUBLE type [" + + param->name + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (param2->type == "integer") { + double2 = GetInteger (param2->name); + } + else if (param2->type == "double") { + double2 = GetDouble (param2->name); + } + else { + string msg = "Parameter is not INTEGER or DOUBLE type [" + + param->name + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (double2 <= double1) { + string message = "Parameter [" + param->name + + "] must be less than parameter [" + + param2->name + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } + + // Check the values for lessThanOrEqual clauses + if (param->values.size() > 0) { + for (unsigned int item=0; itemlessThanOrEqual.size(); item++) { + const IsisParameterData *param2 = + ReturnParam(param->lessThanOrEqual[item]); + if (param2->values.size() != 0) { + double double1, double2; + if (param->type == "integer") { + double1 = (double) GetInteger (param->name); + } + else if (param->type == "double") { + double1 = GetDouble (param->name); + } + else { + string msg = "Parameter is not INTEGER or DOUBLE type [" + + param->name + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (param2->type == "integer") { + double2 = GetInteger (param2->name); + } + else if (param2->type == "double") { + double2 = GetDouble (param2->name); + } + else { + string msg = "Parameter is not INTEGER or DOUBLE type [" + + param->name + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (double2 < double1) { + string message = "Parameter [" + param->name + + "] must be less than or equal to parameter [" + + param2->name + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } + + // Check the values for notEqual clauses + if (param->values.size() > 0) { + for (unsigned int item=0; itemnotEqual.size(); item++) { + const IsisParameterData *param2 = ReturnParam (param->notEqual[item]); + if (param2->values.size() != 0) { + double double1, double2; + if (param->type == "integer") { + double1 = (double) GetInteger (param->name); + } + else if (param->type == "double") { + double1 = GetDouble (param->name); + } + else { + string msg = "Parameter is not INTEGER or DOUBLE type [" + + param->name + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (param2->type == "integer") { + double2 = GetInteger (param2->name); + } + else if (param2->type == "double") { + double2 = GetDouble (param2->name); + } + else { + string msg = "Parameter is not INTEGER or DOUBLE type [" + + param->name + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (double2 == double1) { + string message = "Parameter [" + param->name + + "] must NOT be equal to parameter [" + + param2->name + "]."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } + + // If this parameter has a value, and a list/option/exclude, make sure + // the excluded parameter has NO value + if (((param->values.size() > 0) || (param->defaultValues.size())) > 0) { + for (unsigned int o2=0; o2listOptions.size(); o2++) { + Isis::iString value, option; + if (param->type == "string") { + value = GetString (param->name); + value = value.UpCase (); + option = param->listOptions[o2].value; + option = option.UpCase (); + } + else if (param->type == "integer") { + value = GetAsString (param->name); + value = value.Trim ("\n\r\t\f\v\b"); + option = param->listOptions[o2].value; + option = option.Trim ("\n\r\t\f\v\b"); + } + if (value == option) { + for (unsigned int e2=0;e2listOptions[o2].exclude.size();e2++) { + const IsisParameterData *param2 = + ReturnParam (param->listOptions[o2].exclude[e2]); + if (param2->values.size() > 0) { + string message = "Parameter [" + param2->name + + "] can not be entered if parameter [" + + param->name + "] is equal to [" + + value + "]"; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } + } + + // If this parameter has a value, and a list/option/include, make sure + // the included parameter has a value + if (((param->values.size() > 0) || (param->defaultValues.size())) > 0) { + for (unsigned int o2=0; o2listOptions.size(); o2++) { + Isis::iString value, option; + if (param->type == "string") { + value = GetString (param->name); + value = value.UpCase (); + option = param->listOptions[o2].value; + option = option.UpCase (); + } + else if (param->type == "integer") { + value = GetAsString (param->name); + value = value.Trim ("\n\r\t\f\v\b"); + option = param->listOptions[o2].value; + option = option.Trim ("\n\r\t\f\v\b"); + } + if (value == option) { + for (unsigned int e2=0;e2listOptions[o2].include.size();e2++) { + const IsisParameterData *param2 = + ReturnParam (param->listOptions[o2].include[e2]); + if ((param2->values.size() == 0) && + (param2->defaultValues.size() == 0)) { + string message = "Parameter [" + param2->name + + "] must be entered if parameter [" + + param->name + "] is equal to [" + + value + "]"; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } + } + + // If this parameter has no value, default value or internal default + // value then it must be excluded by some other parameter with an + // exclude or list/option/exclude + // OR + // it must include a boolean which is false + if ((param->values.size() == 0) && (param->defaultValues.size() == 0) && + (param->internalDefault.size() == 0)) { + bool excluded = false; + // See if another parameter has a list option excluding this parameter + for (unsigned int g2=0; g2groups[g2].parameters[p2].listOptions[o2].exclude[e2]; + if (excl == param->name) { + excluded = true; + break; + } + } + } + + if(groups[g2].parameters[p2].type == "boolean") { + const IsisParameterData *param2 = &groups[g2].parameters[p2]; + if (((param2->values.size() > 0) && !StringToBool(param2->values[0])) || + ((param2->values.size() == 0) && (param2->defaultValues.size() > 0) && + !StringToBool(param2->defaultValues[0]))) { + for(unsigned int e2=0; e2groups[g2].parameters[p2].include[e2]; + if (incl == param->name) { + excluded = true; + } + } + } + else if (((param2->values.size() > 0) && StringToBool(param2->values[0])) || + ((param2->values.size() == 0) && (param2->defaultValues.size() > 0) && + StringToBool(param2->defaultValues[0]))) { + for(unsigned int e2=0; e2groups[g2].parameters[p2].exclude[e2]; + if (excl == param->name) { + excluded = true; + } + } + } + } + } + } + + // See if this parameter excludes any other (this implies the other + // one also excludes this one too + for (unsigned int item=0; itemexclude.size(); item++) { + const IsisParameterData *param2 = ReturnParam(param->exclude[item]); + if ((param2->values.size() != 0) || + (param2->defaultValues.size() != 0) || + (param2->internalDefault.size() != 0)) { + if (param2->type != "boolean") { + excluded = true; + } + else { + if (((param2->values.size() > 0) && !StringToBool(param2->values[0])) || + ((param2->values.size() == 0) && (param2->defaultValues.size() > 0) && + !StringToBool(param2->defaultValues[0]))) { + excluded = true; + } + } + } + } + + // See if this parameter includes a boolean that is false + // then it doesn't need a value + for (unsigned int item=0; iteminclude.size(); item++) { + const IsisParameterData *param2 = ReturnParam(param->include[item]); + if (param2->type == "boolean") { + if (((param2->values.size() > 0) && !StringToBool(param2->values[0])) || + ((param2->values.size() == 0) && (param2->defaultValues.size() > 0) && + !StringToBool(param2->defaultValues[0]))) { + excluded = true; + } + } + } + + if (!excluded) { + string message = "Parameter [" + param->name + "] must be entered."; + throw Isis::iException::Message(Isis::iException::User,message, _FILEINFO_); + } + } + } + } +} + +/** + * Returns a boolean value based on the string contents + * + * @param value The value to convert to a boolean + * + * @return boolean value based on string contents + * + * @throws iException::Programmer (Invalid boolean value) + */ +bool IsisAml::StringToBool (Isis::iString value) const { + + value.UpCase (); + if (value == "") { + return false; + } + else if (!value.compare ("NO")) { + return false; + } + else if (!value.compare ("FALSE")) { + return false; + } + else if (!value.compare ("F")) { + return false; + } + else if (!value.compare ("N")) { + return false; + } + else if (!value.compare ("YES")) { + return true; + } + else if (!value.compare ("TRUE")) { + return true; + } + else if (!value.compare ("Y")) { + return true; + } + else if (!value.compare ("T")) { + return true; + } + else { + string message = "Invalid boolean value [" + value + "]."; + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + } + return false; +} + + +/** + * Creates a string which could be used as a command line + * + * @param cont Pvl to put command line information in + */ +void IsisAml::CommandLine (Isis::Pvl &cont) const { + Isis::PvlGroup group("UserParameters"); + + // Add appropriate keywords + for (unsigned int g=0; gvalues.size() > 0) { + group += Isis::PvlKeyword(param->name, param->values[0]); + } + + // Or if it has a default value add it to the command line + else if (param->defaultValues.size() > 0) { + group += Isis::PvlKeyword(param->name, param->defaultValues[0]); + } + } + } + // Remove excluded keywords + for (unsigned int g=0; gvalues.size() > 0) || (param->defaultValues.size())) > 0) { + for (unsigned int o2=0; o2listOptions.size(); o2++) { + Isis::iString value, option; + if (param->type == "string") { + value = GetAsString (param->name); + value = value.UpCase (); + option = param->listOptions[o2].value; + option = option.UpCase (); + } + else if (param->type == "integer") { + value = GetAsString (param->name); + value = value.Trim ("\n\r\t\f\v\b"); + option = param->listOptions[o2].value; + option = option.Trim ("\n\r\t\f\v\b"); + } + if (value == option) { + for (unsigned int e2=0;e2listOptions[o2].exclude.size();e2++) { + const IsisParameterData *param2 = + ReturnParam (param->listOptions[o2].exclude[e2]); + if (group.HasKeyword(param2->name)) { + group.DeleteKeyword(param2->name); + } + } + } + } + } + } + } + + cont.Clear(); + cont.AddGroup(group); + return; +} + + +/** + * Returns the application version date + * + * @return The application version date + */ +string IsisAml::Version () const { + string st = "000-00-00"; + for (unsigned int i=0; i st ) st = changes[i].date; + } + return st; +} + + +/** + * Starts parsing an application xml file + * + * @param xmlfile The xml file to parse + * + * @throws iException::Programmer (Error during XML parser initialization) + */ +void IsisAml::StartParser (const char *xmlfile) { + + // Initialize the XML system + try { + XERCES::XMLPlatformUtils::Initialize(); + } + + catch (const XERCES::XMLException& toCatch) { + string message = "Error during XML parser initialization" + + (string)XERCES::XMLString::transcode(toCatch.getMessage()); + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + return; + } + + // + // Create a SAX parser object. Then, set it to validate for an IsisAml file + // + parser = XERCES::XMLReaderFactory::createXMLReader(); + +// SAX2XMLReader::ValSchemes valScheme = SAX2XMLReader::Val_Auto; + XERCES::SAX2XMLReader::ValSchemes valScheme = XERCES::SAX2XMLReader::Val_Never; + if (valScheme == XERCES::SAX2XMLReader::Val_Auto) { + parser->setFeature(XERCES::XMLString::transcode("http://xml.org/sax/features/validation"), true); + parser->setFeature(XERCES::XMLString::transcode("http://apache.org/xml/features/validation/dynamic"), true); + } + else if (valScheme == XERCES::SAX2XMLReader::Val_Never) { + parser->setFeature(XERCES::XMLString::transcode("http://xml.org/sax/features/validation"), false); + } + + else if (valScheme == XERCES::SAX2XMLReader::Val_Always) { + parser->setFeature(XERCES::XMLString::transcode("http://xml.org/sax/features/validation"), true); + parser->setFeature(XERCES::XMLString::transcode("http://apache.org/xml/features/validation/dynamic"), false); + } + +// bool doSchema = true; + bool doSchema = false; + parser->setFeature(XERCES::XMLString::transcode("http://apache.org/xml/features/validation/schema"), doSchema); + + bool schemaFullChecking = false; + parser->setFeature(XERCES::XMLString::transcode("http://apache.org/xml/features/validation/schema-full-checking"), schemaFullChecking); + + // Create the handler object for an application + // Then parse the file + char* encodingName = "LATIN1"; + bool expandNamespaces = false ; + + try { + IsisAmlData *mydata = this; + appHandler = new IsisXMLApplication (encodingName, expandNamespaces, parser, mydata); + parser->parse(xmlfile); + } + catch (const XERCES::XMLException& toCatch) { + string message = "Error in application XML file: " + + (string)XERCES::XMLString::transcode(toCatch.getMessage()); + throw Isis::iException::Message(Isis::iException::Programmer,message, _FILEINFO_); + XERCES::XMLPlatformUtils::Terminate(); + return; + } + + // Delete the parser + delete parser; + XERCES::XMLPlatformUtils::Terminate(); + delete appHandler; + return; +} + diff --git a/isis/src/base/objs/IsisAml/IsisAml.h b/isis/src/base/objs/IsisAml/IsisAml.h new file mode 100644 index 0000000000000000000000000000000000000000..e085f0dc87bb1fd310b9ace29fd7aaa9620f3838 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisAml.h @@ -0,0 +1,334 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2007/10/17 22:45:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef IsisAml_h +#define IsisAml_h + +#include +#include + +#include + +#include "IsisXMLApplication.h" +#include "IsisAmlData.h" +#include "Pvl.h" +#include "iString.h" + +/** + * @brief Application program XML file parameter manager. + * + * This class is used to manage the data in an application XML file pertaining + * to the program parameters. The data is stored, accessed, and modified + * through this class and its helper classes. + * + * @ingroup ApplicationInterface + * + * @author 2002-05-30 Stuart Sides + * + * @internal + * @todo This class needs an example. + * @history 2002-10-31 Stuart Sides - Added check to make sure all parameters + * have some type of value or are excluded + * by some other parameter. + * @history 2002-11-05 Stuart Sides - Modified GetString member to return the + * matching list member (if a list + * exists) instead of the value itself. + * @history 2002-12-10 Stuart Sides - modified GetFilename member to return + * the filename(s) with environment + * variables expanded. + * @history 2003-01-24 Stuart Sides - took out schema checking for the time + * being. It will need to be put back in + * after the user preferences object is + * finished. + * @history 2003-01-27 Stuart Sides - modified GetFilename. + * @history 2003-02-07 Stuart Sides - fixed VerifyAll to better check + * list/option/includes,excludes + * @history 2003-02-13 Stuart Sides - allowed list/option/included parameters + * to use the default value instead of + * just the value. + * @history 2003-02-20 Stuart Sides - fixed problem where excludes/includes + * were throwing an error when they should + * not have. + * @history 2003-03-12 Stuart Sides - added member to construct a command line + * from the internalized data and return + * it as a string (CommandLine). + * @history 2003-03-12 Stuart Sides - added member to construct a command line + * from the internalized data and return it + * as a string (CommandLine). + * @history 2003-03-13 Stuart Sides - modified member CommandLine to take a + * Label reference instead of returning a + * Label. + * @history 2003-03-13 Stuart Sides - socumented new member CommandLine. + * @history 2003-04-03 Stuart Sides - fixed bug where integer parameters that + * need to be odd were not being checked. + * @history 2003-05-16 Stuart Sides - modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-05-30 Stuart Sides - fixed uninitialized variable compiler + * error when -O1 flag was added. + * @history 2003-06-04 Stuart Sides - fixed a problem where the GetString + * member was not returning the full list + * option value. + * @history 2003-06-05 Stuart Sides - added the member "Version" to the class. + * It will return the date of the most + * recent change to the application. This + * involved parsing the history/change + * entries, which was being ignored + * previously. + * @history 2003-07-02 Stuart Sides - added the new parameter type "cube" + * @history 2003-07-03 Stuart Sides - added the members "Brief and + * Description" to return the application + * brief and full description. + * @history 2003-08-01 Stuart Sides - made get and put Filename work for cubes + * too. + * @history 2003-08-26 Jeff Anderson - added extension option to GetFilename + * method. + * @history 2003-08-27 Stuart Sides - fixed bug where not all parameters would + * get internalized if there where html + * tags inside a description of a parameter + * @history 2003-12-03 Jeff Anderson - modified CommandLine method to output + * all parameters except those in option + * list excludes. + * @history 2004-01-21 Stuart Sides - added members for accessing a parameters + * exclude(s). + * @history 2004-02-26 Stuart Sides - added parsing and get members for the + * default path in the XML + * @history 2004-03-03 Stuart Sides - added member function PixelType so + * IsisGui can get the pixel type of a cube + * @history 2004-09-01 Stuart Sides - modified so the parameter names don't + * get capitalized as they are read from + * the applications xml file. This caused + * other modifications to the ReturnParam + * member, so it would find the requested + * parameter in a case insensitive way. + * @history 2005-10-03 Elizabeth Miller - changed @ingroup tag + * @history 2005-12-13 Stuart Sides - Took out an "exit(1)" in the GetString + * method. Couldn't find a reason for it + * to be there. + * @history 2005-12-28 Elizabeth Miller - Added extra methods and private vars + * to retrieve info needed for gui and + * command line help + * @history 2006-02-13 Elizabeth Miller - Added GuiHelper Capabilities + * @history 2006-10-17 Steven Lambright - Fixed problem with boolean inclusion/exclusion + */ +class IsisAml : protected IsisAmlData { + +// Public section +public: + + IsisAml (const std::string &xmlfile); + + ~IsisAml (); + + + // Methods for searching and retrieving application info + // via the parameter name + + void PutAsString (const std::string ¶mName, const std::string &value); + void PutAsString (const std::string ¶mName, const std::vector &value); + + void PutFilename (const std::string ¶mName, const std::string &value); + void PutFilename (const std::string ¶mName, const std::vector &value); + + void PutDouble (const std::string ¶mName, const double &value); + void PutDouble (const std::string ¶mName, const std::vector &value); + + void PutInteger (const std::string ¶mName, const int &value); + void PutInteger (const std::string ¶mName, const std::vector &value); + + void PutBoolean (const std::string ¶mName, const bool &value); + void PutBoolean (const std::string ¶mName, const std::vector &value); + + void PutString (const std::string ¶mName, const std::string &value); + void PutString (const std::string ¶mName, const std::vector &value); + + std::string GetAsString (const std::string ¶mName) const; + void GetAsString (const std::string ¶mName, std::vector &values) const; + + std::string GetFilename (const std::string ¶mName, std::string extension="") const; + void GetFilename (const std::string ¶mName, std::vector &values) const; + + std::string GetString (const std::string ¶mName) const; + void GetString (const std::string ¶mName, std::vector &values) const; + + int GetInteger (const std::string ¶mName) const; + void GetInteger (const std::string ¶mName, std::vector &values) const; + + bool GetBoolean (const std::string ¶mName) const; + + void GetBoolean (const std::string ¶mName, std::vector &values) const; + + double GetDouble (const std::string ¶mName) const; + void GetDouble (const std::string ¶mName, std::vector &values) const; + + bool WasEntered (const std::string ¶mName) const; + void Clear (const std::string ¶mName); + + Isis::CubeAttributeInput& GetInputAttribute (const std::string ¶mName); + Isis::CubeAttributeOutput& GetOutputAttribute (const std::string ¶mName); + + // Methods for retrieving application info not inside a group + + std::string ProgramName () const; + std::string Brief () const; + std::string Description () const; + + // Methods for searching and retrieving application info + // via the index into groups and parameters + + int NumGroups () const; + + std::string GroupName (const int &group) const; + + int NumParams (const int &) const; + + std::string ParamName (const int &group, const int ¶m) const; + + std::string ParamType (const int &group, const int ¶m) const; + + std::string ParamBrief (const int &group, const int ¶m) const; + + std::string ParamDescription (const int &group, const int ¶m) const; + + std::string ParamMinimum (const int &group, const int ¶m) const; + + std::string ParamMinimumInclusive (const int &group, const int ¶m) const; + + std::string ParamMaximum (const int &group, const int ¶m) const; + + std::string ParamMaximumInclusive (const int &group, const int ¶m) const; + + std::string ParamOdd (const int &group, const int ¶m) const; + + int ParamGreaterThanSize (const int &group, const int ¶m) const; + + int ParamGreaterThanOrEqualSize (const int &group, const int ¶m) const; + + int ParamLessThanSize (const int &group, const int ¶m) const; + + int ParamLessThanOrEqualSize (const int &group, const int ¶m) const; + + int ParamNotEqualSize (const int &group, const int ¶m) const; + + std::string ParamGreaterThan (const int &group, const int ¶m, + const int &great) const; + + std::string ParamGreaterThanOrEqual (const int &group, const int ¶m, + const int &great) const; + + std::string ParamLessThan (const int &group, const int ¶m, + const int &great) const; + + std::string ParamLessThanOrEqual (const int &group, const int ¶m, + const int &les) const; + + std::string ParamNotEqual (const int &group, const int ¶m, + const int ¬Eq) const; + + int ParamListSize (const int &group, const int ¶m) const; + + std::string ParamListValue (const int &group, const int ¶m, + const int &option) const; + + std::string ParamListBrief (const int &group, const int ¶m, + const int &option) const; + + std::string ParamListDescription (const int &group, const int ¶m, + const int &option) const; + + int ParamListExcludeSize (const int &group, const int ¶m, + const int &option) const; + + std::string ParamListExclude (const int &group, const int ¶m, + const int &option, const int &exclude) const; + + int ParamListIncludeSize (const int &group, const int ¶m, + const int &option) const; + + std::string ParamListInclude (const int &group, const int ¶m, + const int &option, const int &include) const; + + std::string ParamDefault (const int &group, const int ¶m) const; + + std::string ParamInternalDefault (const int &group, const int ¶m) const; + + std::string ParamFilter (const int &group, const int ¶m) const; + + std::string ParamPath (const int &group, const int ¶m) const; + + std::string ParamFileMode (const int &group, const int ¶m) const; + + int ParamExcludeSize (const int &group, const int ¶m) const; + + std::string ParamExclude (const int &group, const int ¶m, + const int &exclude) const; + int ParamIncludeSize (const int &group, const int ¶m) const; + + std::string ParamInclude (const int &group, const int ¶m, + const int &include) const; + + std::string PixelType (const int &group, const int ¶m) const; + + int HelpersSize(const int &group, const int ¶m) const; + + std::string HelperButtonName(const int &group, const int ¶m, + const int &helper) const; + + std::string HelperFunction(const int &group, const int ¶m, + const int &helper) const; + + std::string HelperBrief(const int &group, const int ¶m, + const int &helper) const; + + std::string HelperDescription(const int &group, const int ¶m, + const int &helper) const; + + std::string HelperIcon(const int &group, const int ¶m, + const int &helper) const; + + // Test all parameters for valid values and conditions + void VerifyAll (); + + bool StringToBool (Isis::iString value) const; + + void CommandLine (Isis::Pvl &lab) const; + + std::string Version () const; + + +// Private section +private: + + //! The XML file parser. + XERCES::SAX2XMLReader *parser; + //! The application handler. + IsisXMLApplication *appHandler; + + // Member functions + void StartParser (const char *xmlfile); + + const IsisParameterData *ReturnParam (const std::string ¶mName) const; + + void Verify (const IsisParameterData *param); +}; + + +#endif diff --git a/isis/src/base/objs/IsisAml/IsisAml.truth b/isis/src/base/objs/IsisAml/IsisAml.truth new file mode 100644 index 0000000000000000000000000000000000000000..bb2f8f1f19be7b8e4010003c37d26e49b9d4f42b --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisAml.truth @@ -0,0 +1,1547 @@ +Create the aml object +--------- Tests for private data ---------- + App name = unittest + App brief = Brief description + App description = This program tests the IsisAml class and its supporting classes. + group 0 name = GROUP 0 + parameter 0, name = G0p0 + type = filename + brief = G0P0 Filename + description = Description for G0P0

    Paragraph 2 of description for G0P0

    End of description for G0P0 + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = *.cub + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 1, name = G0P1 + type = filename + brief = G0P1 Filename + description = Description for G0P0, + line 2 of the description, + line 3 of the description + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + [0] = /my/dir/file.cub + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + group 1 name = Group 1, string list test + parameter 0, name = G1P0 + type = string + brief = Brief for parameter G1P0 + description = Description for G1P0. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + [0] = G1P0L0 + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + value [0] = G1P0L0 + brief [0] = Brief for list item G1P0L0 + description [0] = Description for list item G1P0L0 + exclude = G1P1 + exclude = G1P2 + exclude = G2P0 + value [1] = G1P0L1 + brief [1] = Brief for list item G1P0L1 + description [1] = Description for list item G1P0L1 + exclude = G2P1 + exclude = G2P2 + exclude = G3P0 + value [2] = G1P0L1X + brief [2] = Brief for list item G1P0L2 + description [2] = Description for list item G1P0L2 + parameter 1, name = G1P1 + type = integer + brief = Brief for G1P1 + description = Description for G1P1 + internal def = + helpers = 2 + name = H1 + brief = Helper 1 + description = This helper button does..... + function = myHelper + icon = + name = H2 + brief = Helper 2 + description = This helper buttion will... + function = myHelper2 + icon = $ISIS3DATA/base/icons/back.png + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + [0] = 0 + Greater Than: + Greater or Equal Than: + Less Than: + [0] = G1P2 + [1] = G1P3 + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 2, name = G1P2 + type = double + brief = Brief for G1P2 + description = Description for G1P2 + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + [0] = 10.5 + Greater Than: + [0] = G1P1 + Greater or Equal Than: + Less Than: + [0] = G1P2 + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 3, name = G1P3 + type = double + brief = Brief for G1P3 + description = Description for G1P3 + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + [0] = G1P1 + [1] = G1P2 + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + group 2 name = Group 2, integer tests + parameter 0, name = G2P0 + type = integer + brief = Brief for parameter G2P0 + description = Description for G2P0. + internal def = Calculated inside program + helpers = 0 + count = + minimum = 0 + minimum inclusive = false + maximum = 999 + maximum inclusive = yes + filter = + file mode = + odd = TRUE + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + [0] = G2P1 + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 1, name = G2P1 + type = integer + brief = Brief for parameter G2P1 + description = Description for G2P1. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + [0] = G2P0 + Greater or Equal Than: + Less Than: + Less Than or Equal: + [0] = G2P2 + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 2, name = G2P2 + type = integer + brief = Brief for parameter G2P2 + description = Description for G2P2. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + [0] = G2P1 + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 3, name = G2P3 + type = integer + brief = Brief for parameter G2P3 + description = Description for G2P3. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + [0] = g2p4 + Include parameters: + Exclude parameters: + List data: + parameter 4, name = g2P4 + type = integer + brief = Brief for parameter G2P4 + description = Description for G2P4. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + [0] = G2P3 + Include parameters: + Exclude parameters: + List data: + group 3 name = Group 3, double tests + parameter 0, name = G3P0 + type = double + brief = Brief for parameter G3P0 + description = Description for G3P0. + internal def = Calculated inside program + helpers = 0 + count = + minimum = -0.5 + minimum inclusive = false + maximum = 999.5 + maximum inclusive = yes + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + [0] = G3P1 + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 1, name = G3P1 + type = double + brief = Brief for parameter G3P1 + description = Description for G3P1. + internal def = + helpers = 1 + name = H3 + brief = Helper 3 + description = Long Description for Helper 3 + function = myHelper3 + icon = $ISIS3DATA/base/icons/up.png + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + [0] = G3P0 + Greater or Equal Than: + Less Than: + Less Than or Equal: + [0] = G3P2 + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 2, name = G3P2 + type = double + brief = Brief for parameter G3P2 + description = Description for G3P2. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + [0] = G3P1 + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 3, name = G3P3 + type = double + brief = Brief for parameter G3P3 + description = Description for G3P3. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + [0] = G3P4 + Include parameters: + Exclude parameters: + List data: + parameter 4, name = G3P4 + type = double + brief = Brief for parameter G3P4 + description = Description for G3P4. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + [0] = G3P3 + Include parameters: + Exclude parameters: + List data: + group 4 name = Group 4, double -vs- integer tests + parameter 0, name = G4P0 + type = double + brief = Brief for parameter G4P0 + description = Description for G4P0. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + [0] = G4P1 + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 1, name = G4P1 + type = integer + brief = Brief for parameter G4P1 + description = Description for G4P1. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + [0] = G4P0 + Less Than: + Less Than or Equal: + [0] = G4P2 + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 2, name = G4P2 + type = double + brief = Brief for parameter G4P2 + description = Description for G4P2. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + [0] = G4P1 + Less Than: + [0] = G4P3 + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 3, name = G4P3 + type = integer + brief = Brief for parameter G4P3 + description = Description for G4P3. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + [0] = G4P2 + Greater or Equal Than: + Less Than: + [0] = G4P4 + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 4, name = G4P4 + type = double + brief = Brief for parameter G4P4 + description = Description for G4P4. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + [0] = G4P3 + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + [0] = G4P5 + Include parameters: + Exclude parameters: + List data: + parameter 5, name = G4P5 + type = integer + brief = Brief for parameter G4P5 + description = Description for G4P5. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + [0] = G4P4 + Include parameters: + Exclude parameters: + List data: + group 5 name = Group 5, in/exclusive tests + parameter 0, name = G5P0 + type = integer + brief = Brief for parameter G5P0 + description = Description for G5P0. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + [0] = G5P1 + [1] = G5P2 + Exclude parameters: + [0] = G5P3 + List data: + parameter 1, name = G5P1 + type = integer + brief = Brief for parameter G5P1 + description = Description for G5P1. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + [0] = G5P0 + [1] = G5P2 + Exclude parameters: + List data: + parameter 2, name = G5P2 + type = integer + brief = Brief for parameter G5P2 + description = Description for G5P2. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + [0] = G5P0 + Exclude parameters: + List data: + parameter 3, name = G5P3 + type = integer + brief = Brief for parameter G5P3 + description = Description for G5P3. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + [0] = G5P0 + [1] = G5P1 + [2] = G5P2 + List data: + group 6 name = Group 6, boolean tests + parameter 0, name = G6P0 + type = boolean + brief = Brief for parameter G6P0 + description = Description for G6P0. + internal def = + helpers = 1 + name = H4 + brief = Helper 4 + description = Long Description for Helper 4... + function = myHelper4 + icon = + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + [0] = G6P1 + Exclude parameters: + [0] = G6P2 + List data: + parameter 1, name = G6P1 + type = integer + brief = Brief for parameter G6P1 + description = Description for G6P1. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 2, name = G6P2 + type = integer + brief = Brief for parameter G6P2 + description = Description for G6P2. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + [0] = 100 + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 3, name = G6P3 + type = string + brief = Brief for parameter G6P3 + description = Description for G6P3. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + group 7 name = Group 7, name search test + parameter 0, name = FROM + type = string + brief = Brief for parameter FROM + description = Description for FROM. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + [0] = FROM + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 1, name = FROM1 + type = string + brief = Brief for parameter FROM1 + description = Description for FROM1. + internal def = + helpers = 1 + name = H5 + brief = Helper 5 + description = Long Description for Helper 5... + function = myHelper5 + icon = $ISIS3DATA/base/icons/link.png + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + [0] = FROM1 + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 2, name = FR + type = string + brief = Brief for parameter FR + description = Description for FR. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + [0] = FR + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + group 8 name = Group 8, Cube test + parameter 0, name = CUBE1 + type = cube + brief = Brief for parameter CUBE1 + description = Description for CUBE1. + internal def = + helpers = 1 + name = H6 + brief = Helper 6 + description = Long Description for Helper 6... + function = myHelper6 + icon = + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: + parameter 1, name = CUBE2 + type = cube + brief = Brief for parameter CUBE2 + description = Description for CUBE2. + internal def = + helpers = 0 + count = + minimum = + minimum inclusive = + maximum = + maximum inclusive = + filter = + file mode = + odd = + Values: + Default Values: + Greater Than: + Greater or Equal Than: + Less Than: + Less Than or Equal: + Not equal to: + Include parameters: + Exclude parameters: + List data: +Application information +Program name : unittest +Brief description: Brief description +Full description: This program tests the IsisAml class and its supporting classes. +Version date: 2003-05-16 + +Number of parameter groups : 9 + +Parameter information: + Group number: 0 + Group name : GROUP 0 + Parameter number: 0 + Name: G0p0 + Type: filename + Brief: G0P0 Filename + Default: + Internal default: + Filter: *.cub + File Mode: + Helper Information: + List Information: + Parameter number: 1 + Name: G0P1 + Type: filename + Brief: G0P1 Filename + Default: /my/dir/file.cub + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Group number: 1 + Group name : Group 1, string list test + Parameter number: 0 + Name: G1P0 + Type: string + Brief: Brief for parameter G1P0 + Default: G1P0L0 + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Value: G1P0L0 + Brief: Brief for list item G1P0L0 + Description: Description for list item G1P0L0 + List exclusions: + Exclude parameter: G1P1 + Exclude parameter: G1P2 + Exclude parameter: G2P0 + List inclusions: + Value: G1P0L1 + Brief: Brief for list item G1P0L1 + Description: Description for list item G1P0L1 + List exclusions: + Exclude parameter: G2P1 + Exclude parameter: G2P2 + Exclude parameter: G3P0 + List inclusions: + Value: G1P0L1X + Brief: Brief for list item G1P0L2 + Description: Description for list item G1P0L2 + List exclusions: + List inclusions: + Include parameter: G1P1 + Include parameter: G1P3 + Parameter number: 1 + Name: G1P1 + Type: integer + Brief: Brief for G1P1 + Default: 0 + Internal default: + Filter: + File Mode: + Helper Information: + Name: H1 + Brief: Helper 1 + Description: This helper button does..... + Function: myHelper + Icon: + Name: H2 + Brief: Helper 2 + Description: This helper buttion will... + Function: myHelper2 + Icon: $ISIS3DATA/base/icons/back.png + List Information: + Parameter number: 2 + Name: G1P2 + Type: double + Brief: Brief for G1P2 + Default: 10.5 + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 3 + Name: G1P3 + Type: double + Brief: Brief for G1P3 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Group number: 2 + Group name : Group 2, integer tests + Parameter number: 0 + Name: G2P0 + Type: integer + Brief: Brief for parameter G2P0 + Default: + Internal default: Calculated inside program + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 1 + Name: G2P1 + Type: integer + Brief: Brief for parameter G2P1 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 2 + Name: G2P2 + Type: integer + Brief: Brief for parameter G2P2 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 3 + Name: G2P3 + Type: integer + Brief: Brief for parameter G2P3 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 4 + Name: g2P4 + Type: integer + Brief: Brief for parameter G2P4 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Group number: 3 + Group name : Group 3, double tests + Parameter number: 0 + Name: G3P0 + Type: double + Brief: Brief for parameter G3P0 + Default: + Internal default: Calculated inside program + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 1 + Name: G3P1 + Type: double + Brief: Brief for parameter G3P1 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + Name: H3 + Brief: Helper 3 + Description: Long Description for Helper 3 + Function: myHelper3 + Icon: $ISIS3DATA/base/icons/up.png + List Information: + Parameter number: 2 + Name: G3P2 + Type: double + Brief: Brief for parameter G3P2 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 3 + Name: G3P3 + Type: double + Brief: Brief for parameter G3P3 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 4 + Name: G3P4 + Type: double + Brief: Brief for parameter G3P4 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Group number: 4 + Group name : Group 4, double -vs- integer tests + Parameter number: 0 + Name: G4P0 + Type: double + Brief: Brief for parameter G4P0 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 1 + Name: G4P1 + Type: integer + Brief: Brief for parameter G4P1 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 2 + Name: G4P2 + Type: double + Brief: Brief for parameter G4P2 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 3 + Name: G4P3 + Type: integer + Brief: Brief for parameter G4P3 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 4 + Name: G4P4 + Type: double + Brief: Brief for parameter G4P4 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 5 + Name: G4P5 + Type: integer + Brief: Brief for parameter G4P5 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Group number: 5 + Group name : Group 5, in/exclusive tests + Parameter number: 0 + Name: G5P0 + Type: integer + Brief: Brief for parameter G5P0 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 1 + Name: G5P1 + Type: integer + Brief: Brief for parameter G5P1 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 2 + Name: G5P2 + Type: integer + Brief: Brief for parameter G5P2 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 3 + Name: G5P3 + Type: integer + Brief: Brief for parameter G5P3 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Group number: 6 + Group name : Group 6, boolean tests + Parameter number: 0 + Name: G6P0 + Type: boolean + Brief: Brief for parameter G6P0 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + Name: H4 + Brief: Helper 4 + Description: Long Description for Helper 4... + Function: myHelper4 + Icon: + List Information: + Parameter number: 1 + Name: G6P1 + Type: integer + Brief: Brief for parameter G6P1 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 2 + Name: G6P2 + Type: integer + Brief: Brief for parameter G6P2 + Default: 100 + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 3 + Name: G6P3 + Type: string + Brief: Brief for parameter G6P3 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Group number: 7 + Group name : Group 7, name search test + Parameter number: 0 + Name: FROM + Type: string + Brief: Brief for parameter FROM + Default: FROM + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Parameter number: 1 + Name: FROM1 + Type: string + Brief: Brief for parameter FROM1 + Default: FROM1 + Internal default: + Filter: + File Mode: + Helper Information: + Name: H5 + Brief: Helper 5 + Description: Long Description for Helper 5... + Function: myHelper5 + Icon: $ISIS3DATA/base/icons/link.png + List Information: + Parameter number: 2 + Name: FR + Type: string + Brief: Brief for parameter FR + Default: FR + Internal default: + Filter: + File Mode: + Helper Information: + List Information: + Group number: 8 + Group name : Group 8, Cube test + Parameter number: 0 + Name: CUBE1 + Type: cube + Brief: Brief for parameter CUBE1 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + Name: H6 + Brief: Helper 6 + Description: Long Description for Helper 6... + Function: myHelper6 + Icon: + List Information: + Parameter number: 1 + Name: CUBE2 + Type: cube + Brief: Brief for parameter CUBE2 + Default: + Internal default: + Filter: + File Mode: + Helper Information: + List Information: +Get/Put/Clear/WasEntered tests +Default value of G0P1 is /my/dir/file.cub +G0P1 WasEntered value 0 +G0P1 WasEntered value 1 +The value of G0P1 is /home/user/file1.cub +Default value of G0P1 is /my/dir/file.cub +The value of G0P1 is /home/user/file2.dat + +The value of G0P1 is /home/user/file2.dat.txt + +Default value of G1P1 is 0 +The value of G1P1 is 33 + +Default value of G1P2 is 10.5 +The value of G1P2 is 1e-09 + +Default value of G1P0 is G1P0L0 +The value of G1P0 is G1P0L1 + +The value of G6P0 is 1 + +The value of G6P0 is 0 + +The value of G6P0 is 1 + +The value of G6P0 is 0 + +The value of G6P0 is 1 + +The value of G6P0 is 0 + +The value of G6P0 is 1 + +The value of G6P0 is 0 + +The value of G6P0 is 1 + +The value of G6P0 is 0 + +The value of G6P0 is 1 + +The value of G6P0 is 0 + +The value of G6P0 is 1 + +The value of G6P0 is 0 + +The value of G6P0 is 1 + +The value of G6P0 is 0 + +The value of G6P0 is 1 + +The value of G6P0 is 0 + +Exact and partial name match tests: + FROM's value = FROM + FROM1's value = FROM1 + FR's value = FR + + +---------- Test error throwing ---------- PutAsString: +**USER ERROR** A value for this parameter [G1P0] has already been entered. + + PutString: +**PROGRAMMER ERROR** A value for this parameter [G1P0] has already been saved (possibly by IsisGui). If you need to change the value use "Clear" before the Put. + +**PROGRAMMER ERROR** Parameter [G2P4] is not a string. + + PutFilename: +**PROGRAMMER ERROR** A value for this parameter [G0P0] has already been saved (possibly by IsisGui). If you need to change the value use "Clear" before the Put. + +**PROGRAMMER ERROR** Parameter [G2P4] is not a filename. + + Cube tests: +**PROGRAMMER ERROR** Parameter [CUBE1] does not contain an [input] file +**PROGRAMMER ERROR** Parameter [CUBE2] does not contain an [output] file + + PutInteger: +**PROGRAMMER ERROR** A value for this parameter [G6P2] has already been saved (possibly by IsisGui). If you need to change the value use "Clear" before the Put. + +**PROGRAMMER ERROR** Parameter [G6P0] is not an integer. + + PutDouble: +**PROGRAMMER ERROR** A value for this parameter [G1P2] has already been saved (possibly by IsisGui). If you need to change the value use "Clear" before the Put. + +**PROGRAMMER ERROR** Parameter [G0P0] is not a double. + + PutBoolean: +**PROGRAMMER ERROR** A value for this parameter [G6P0] has already been saved (possibly by IsisGui). If you need to change the value use "Clear" before the Put. + +**PROGRAMMER ERROR** Parameter [G0P0] is not a boolean. + + GetAsString: +**PROGRAMMER ERROR** Parameter [G2P0] has no value. + + GetFilename: +**USER ERROR** Parameter [G0P0] has no value. + +**PROGRAMMER ERROR** Parameter [G2P4] is not a filename. + + GetString: +**USER ERROR** Parameter [G6P3] has no value. + +**PROGRAMMER ERROR** Parameter [G2P4] is not a string. + + GetInteger: +**USER ERROR** Parameter [G2P0] has no value. + +**PROGRAMMER ERROR** Parameter [G0P0] is not an integer. + + GetDouble: +**USER ERROR** Parameter [G1P3] has no value. + +**PROGRAMMER ERROR** Parameter [G0P1] is not a double. + + GetBoolean: +**USER ERROR** Parameter [G6P0] has no value. +**PROGRAMMER ERROR** Invalid boolean value [CCCC]. + +**PROGRAMMER ERROR** Parameter [G1P1] is not a boolean. +**USER ERROR** Parameter [F] is not unique. + +---------- Validate a correctly loaded set of parameters ---------- + +The current command line: +Group = UserParameters + G0p0 = FILE1 + G0P1 = FILE2 + G1P0 = G1P0L0 + G1P3 = 1.1 + G2P1 = 1 + G2P2 = 3 + G2P3 = 4 + g2P4 = 5 + G3P1 = 1.2 + G3P2 = 1.3 + G3P3 = 1.4 + G3P4 = 1.5 + G4P0 = 1.6 + G4P1 = 6 + G4P2 = 6.7 + G4P3 = 7 + G4P4 = 7.8 + G4P5 = 8 + G5P0 = 9 + G5P1 = 10 + G5P2 = 11 + G6P0 = yes + G6P1 = 13 + G6P2 = 100 + G6P3 = STRING2 + FROM = STRING3 + FROM1 = STRING4 + FR = STRING4 + CUBE1 = CUBE.DAT + CUBE2 = CUBE2.DAT +End_Group +End + + +--- Check for NO value in an option/list/included parameter --- +**USER ERROR** Parameter [G1P3] must be entered if parameter [G1P0] is equal to [G1P0L1X] + +----- Check for value in an option/list/excluded parameter ----- +**USER ERROR** Parameter [G2P0] can not be entered if parameter [G1P0] is equal to [G1P0L0] + +---------- Check error for unknow parameter ---------- +**USER ERROR** Unknown parameter [xyz]. diff --git a/isis/src/base/objs/IsisAml/IsisAmlData.cpp b/isis/src/base/objs/IsisAml/IsisAmlData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dfb0ef915d6d5bdd6c687901f79ba7de55bef6f9 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisAmlData.cpp @@ -0,0 +1,112 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "iException.h" +#include "IsisAmlData.h" + +// Constructors + IsisAmlData::IsisAmlData () { + name.erase(); + brief.erase(); + description.erase(); + groups.clear(); + categorys.clear(); + } + + IsisAmlData::~IsisAmlData () { + } + + +// Helper classes + IsisHelperData::IsisHelperData () { + name.erase(); + icon.erase(); + brief.erase(); + description.erase(); + function.erase(); + } + + IsisHelperData::~IsisHelperData () { + } + + + IsisGroupData::IsisGroupData () { + name.erase(); + } + + IsisGroupData::~IsisGroupData () { + } + + + IsisParameterData::IsisParameterData () { + values.clear(); + name.erase(); + brief.erase(); + description.erase(); + type.erase(); + internalDefault.erase(); + count.erase(); + defaultValues.clear(); + exclude.clear(); + include.clear(); + filter.erase(); + greaterThan.clear(); + greaterThanOrEqual.clear(); + lessThan.clear(); + lessThanOrEqual.clear(); + internalDefault.erase(); + notEqual.clear(); + maximum.erase(); + maximum_inclusive.erase(); + minimum.erase(); + minimum_inclusive.erase(); + odd.erase(); + helpers.clear(); + } + + IsisParameterData::~IsisParameterData () { + } + + + IsisListOptionData::IsisListOptionData () { + value.erase(); + brief.erase(); + description.erase(); + exclude.clear(); + } + + IsisListOptionData::~IsisListOptionData () { + } + + + IsisChangeData::IsisChangeData () { + name.erase(); + date.erase(); + description.erase(); + } + + IsisChangeData::~IsisChangeData () { + } + diff --git a/isis/src/base/objs/IsisAml/IsisAmlData.h b/isis/src/base/objs/IsisAml/IsisAmlData.h new file mode 100644 index 0000000000000000000000000000000000000000..ad8578365a3d2dd0778149853430fbb77ea0c634 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisAmlData.h @@ -0,0 +1,126 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisAmlData_h +#define IsisAmlData_h + +#include +#include + +#include "CubeAttribute.h" + +class IsisListOptionData { + public: + std::string value; + std::string brief; + std::string description; + std::vector exclude; + std::vector include; + + IsisListOptionData (); + ~IsisListOptionData (); +}; + +class IsisHelperData { + public: + std::string name; + std::string icon; + std::string brief; + std::string description; + std::string function; + + IsisHelperData(); + ~IsisHelperData(); +}; + +class IsisParameterData { + public: + std::vector values; + std::string name; + std::string brief; + std::string description; + std::string type; + std::vector defaultValues; + std::string internalDefault; + std::string count; + std::vector listOptions; + std::string minimum_inclusive; + std::string minimum; + std::string maximum_inclusive; + std::string maximum; + std::vector greaterThan; + std::vector greaterThanOrEqual; + std::vector lessThan; + std::vector lessThanOrEqual; + std::vector notEqual; + std::vector exclude; + std::vector include; + std::string odd; + std::string filter; + std::string path; + std::string fileMode; + Isis::CubeAttributeOutput outCubeAtt; + Isis::CubeAttributeInput inCubeAtt; + std::string pixelType; + std::vector helpers; + + IsisParameterData (); + ~IsisParameterData (); +}; + + +class IsisGroupData { + public: + std::string name; + std::vector parameters; + + IsisGroupData (); + ~IsisGroupData (); +}; + +class IsisChangeData { + public: + std::string name; + std::string date; + std::string description; + + IsisChangeData (); + ~IsisChangeData (); +}; + + +class IsisAmlData { + public: + std::string name; + std::string brief; + std::string description; + std::vector groups; + std::vector categorys; + std::vector changes; + + IsisAmlData (); + ~IsisAmlData (); + +}; + +#endif diff --git a/isis/src/base/objs/IsisAml/IsisXMLApplication.cpp b/isis/src/base/objs/IsisAml/IsisXMLApplication.cpp new file mode 100644 index 0000000000000000000000000000000000000000..185012aba876210ca0409d7ee95d6fc6d224b7f3 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLApplication.cpp @@ -0,0 +1,150 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include + +#include +#include +#include + +#include "IsisXMLApplication.h" +#include "IsisXMLChTrans.h" + +#include "iString.h" + + // Constructors + IsisXMLApplication::IsisXMLApplication (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + IsisAmlData *PappData) { + encodingName = PencodingName; + expandNamespaces = PexpandNamespaces; + parser = Pparser; + appData = PappData; + + parser->setContentHandler(this); + parser->setErrorHandler(this); + + briefHandler = NULL; + descriptionHandler = NULL; + groupsHandler = NULL; + multipleValuesHandler = NULL; + ignoreHandler = NULL; + historyHandler = NULL; + } + + IsisXMLApplication::~IsisXMLApplication () { + + if (briefHandler != NULL) delete briefHandler; + if (descriptionHandler != NULL) delete descriptionHandler; + if (groupsHandler != NULL) delete groupsHandler; + if (multipleValuesHandler != NULL) delete multipleValuesHandler; + if (ignoreHandler != NULL) delete ignoreHandler; + if (historyHandler != NULL) delete historyHandler; + } + + + // Callback methodes for handling pieces of the xml file + + // IsisXMLApplication: Overrides of the SAX DocumentHandler interface + void IsisXMLApplication::characters(const XMLCh* const chars, + const unsigned int length) {} + + + + void IsisXMLApplication::endDocument() {} + + + void IsisXMLApplication::endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname) { + } + + + void IsisXMLApplication::processingInstruction(const XMLCh* const target, + const XMLCh* const data) {} + + + void IsisXMLApplication::startDocument() {} + + + void IsisXMLApplication::startElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes) { + + if ((string)XERCES::XMLString::transcode(localname) == (string)"application") { + Isis::iString name = XERCES::XMLString::transcode (attributes.getValue((unsigned int)0)); + appData->name = name.DownCase(); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"brief") { + if (briefHandler != NULL) { + delete briefHandler; + briefHandler = NULL; + } + briefHandler = new IsisXMLHandler (encodingName, expandNamespaces, + parser, &appData->brief); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"description") { + if (descriptionHandler != NULL) { + delete descriptionHandler; + descriptionHandler = NULL; + } + descriptionHandler = new IsisXMLHandler (encodingName, expandNamespaces, + parser, &appData->description); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"groups") { + if (groupsHandler != NULL) { + delete groupsHandler; + groupsHandler = NULL; + } + groupsHandler = new IsisXMLGroups (encodingName, expandNamespaces, parser, + &appData->groups); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"category") { + if (multipleValuesHandler != NULL) { + delete multipleValuesHandler; + multipleValuesHandler = NULL; + } + multipleValuesHandler = new IsisXMLMultipleValues (encodingName, expandNamespaces, + parser, &appData->categorys); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"history") { + if (historyHandler != NULL) { + delete historyHandler; + historyHandler = NULL; + } + historyHandler = new IsisXMLHistory (encodingName, expandNamespaces, + parser, &appData->changes); + } + else { + if (ignoreHandler != NULL) { + delete ignoreHandler; + ignoreHandler = NULL; + } + ignoreHandler = new IsisXMLIgnore (encodingName, expandNamespaces, parser, + (string)XERCES::XMLString::transcode(localname)); + } + } diff --git a/isis/src/base/objs/IsisAml/IsisXMLApplication.h b/isis/src/base/objs/IsisAml/IsisXMLApplication.h new file mode 100644 index 0000000000000000000000000000000000000000..3b1fb78743a6a935f6e624c174bd978091f23f65 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLApplication.h @@ -0,0 +1,88 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisXMLApplication_h +#define IsisXMLApplication_h + +//#include + +#include "IsisAmlData.h" +#include "IsisXMLGroups.h" +#include "IsisXMLHandler.h" +#include "IsisXMLIgnore.h" +#include "IsisXMLHistory.h" + +class IsisXMLApplication : public IsisXMLHandler { + +public: + + // Constructors + IsisXMLApplication (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + IsisAmlData *PappData); + + ~IsisXMLApplication (); + + + // SAX DocumentHandler interface + void endDocument(); + + void endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname); + + void characters(const XMLCh* const chars, + const unsigned int length); + + void processingInstruction (const XMLCh* const target, + const XMLCh* const data); + + void startDocument(); + + void startElement (const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes); + + + +private: + + // Saved argument from the constructor + char* encodingName; + bool expandNamespaces; + XERCES::SAX2XMLReader *parser; + IsisAmlData *appData; + + // Handlers this handler knows how to create + IsisXMLHandler *briefHandler; + IsisXMLHandler *descriptionHandler; + IsisXMLGroups *groupsHandler; + IsisXMLMultipleValues *multipleValuesHandler; + IsisXMLIgnore *ignoreHandler; + IsisXMLHistory *historyHandler; +}; + + +#endif diff --git a/isis/src/base/objs/IsisAml/IsisXMLChTrans.h b/isis/src/base/objs/IsisAml/IsisXMLChTrans.h new file mode 100644 index 0000000000000000000000000000000000000000..4d9f67deb73b44975ac60c5c42e96393256a8ce7 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLChTrans.h @@ -0,0 +1,66 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisXMLChTrans_h +#define IsisXMLChTrans_h + +#include +#include +#include + +namespace XERCES = XERCES_CPP_NAMESPACE; + +// This class converts from the internal XMLCh character format to simple c strings + +class XMLChTrans { +public : + // Constructors and Destructor + XMLChTrans(const XMLCh* const toTranscode) + { + // Call the private transcoding method + fLocalForm = XERCES::XMLString::transcode(toTranscode); + } + + ~XMLChTrans() + { + delete [] fLocalForm; + } + + // Getter methods + const char* localForm() const + { + return fLocalForm; + } + +private : + char* fLocalForm; +}; + + +inline std::ostream& operator<<(std::ostream& target, const XMLChTrans& toDump) +{ + target << toDump.localForm(); + return target; +} + +#endif diff --git a/isis/src/base/objs/IsisAml/IsisXMLGroup.cpp b/isis/src/base/objs/IsisAml/IsisXMLGroup.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5811ca44f9442160012a1391db216711b17314e --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLGroup.cpp @@ -0,0 +1,107 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include + +#include +#include +#include + +#include "IsisXMLGroup.h" +#include "IsisXMLChTrans.h" + +#include "iString.h" + +namespace XERCES = XERCES_CPP_NAMESPACE; + + // Constructors + IsisXMLGroup::IsisXMLGroup (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + IsisGroupData *Pgroup) { + + encodingName = PencodingName; + expandNamespaces = PexpandNamespaces; + parser = Pparser; + group = Pgroup; + + prevDocHandler = parser->getContentHandler(); + prevErrorHandler = parser->getErrorHandler(); + + parser->setContentHandler(this); + parser->setErrorHandler(this); + + parameterHandler = NULL; + ignoreHandler = NULL; + + } + + IsisXMLGroup::~IsisXMLGroup () { + + if (parameterHandler != NULL) delete parameterHandler; + if (ignoreHandler != NULL) delete ignoreHandler; + } + + + // IsisXMLGroup: Overrides of the SAX DocumentHandler interface + void IsisXMLGroup::characters(const XMLCh* const chars, + const unsigned int length) { + } + + + void IsisXMLGroup::endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname) { + parser->setContentHandler(prevDocHandler); + parser->setErrorHandler(prevErrorHandler); + } + + void IsisXMLGroup::startElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes) { + + if ((string)XERCES::XMLString::transcode(localname) == (string)"parameter") { + if (parameterHandler != NULL) { + delete parameterHandler; + parameterHandler = NULL; + } + unsigned int index = group->parameters.size(); + group->parameters.resize(index+1); + Isis::iString name = XERCES::XMLString::transcode (attributes.getValue((unsigned int)0)); +// Taken out after PVL refactor name.UpCase(); + group->parameters[index].name = name; + parameterHandler = new IsisXMLParameter (encodingName, expandNamespaces, + parser, &group->parameters[index]); + } + else { + if (ignoreHandler != NULL) { + delete ignoreHandler; + ignoreHandler = NULL; + } + ignoreHandler = new IsisXMLIgnore (encodingName, expandNamespaces, parser, + (string)XERCES::XMLString::transcode(localname)); + } + } diff --git a/isis/src/base/objs/IsisAml/IsisXMLGroup.h b/isis/src/base/objs/IsisAml/IsisXMLGroup.h new file mode 100644 index 0000000000000000000000000000000000000000..88ac23c79175445aee197b6e11892d6da6f84fa9 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLGroup.h @@ -0,0 +1,78 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisXMLGroup_h +#define IsisXMLGroup_h + +//#include + +#include "IsisAmlData.h" +#include "IsisXMLParameter.h" +#include "IsisXMLIgnore.h" + +class IsisXMLGroup : public IsisXMLHandler { + +public: + + ContentHandler *prevDocHandler; + ErrorHandler *prevErrorHandler; + + + IsisXMLGroup (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + IsisGroupData *Group); + + ~IsisXMLGroup (); + + void endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname); + + void characters(const XMLCh* const chars, + const unsigned int length); + + void startElement (const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes); + + +private: + + // Saved argument from the constructor + char* encodingName; + bool expandNamespaces; + XERCES::SAX2XMLReader *parser; + IsisGroupData *group; + + // Handlers this handler knows how to create + IsisXMLParameter *parameterHandler; + IsisXMLIgnore *ignoreHandler; +}; + + +#endif + + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLGroups.cpp b/isis/src/base/objs/IsisAml/IsisXMLGroups.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a78d25af1c16c600fc582c915037429b64aba50 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLGroups.cpp @@ -0,0 +1,110 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include + +#include +#include +#include + +#include "IsisXMLGroups.h" +#include "IsisXMLChTrans.h" + +namespace XERCES = XERCES_CPP_NAMESPACE; + + + // Constructors + + IsisXMLGroups::IsisXMLGroups (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + std::vector *Pgroups) { + + encodingName = PencodingName; + expandNamespaces = PexpandNamespaces; + parser = Pparser; + groups = Pgroups; + + prevDocHandler = parser->getContentHandler (); + prevErrorHandler = parser->getErrorHandler (); + + parser->setContentHandler (this); + parser->setErrorHandler (this); + + groupHandler = NULL; + ignoreHandler = NULL; + } + + IsisXMLGroups::~IsisXMLGroups () { + if (groupHandler != NULL) delete groupHandler; + if (ignoreHandler != NULL) delete ignoreHandler; + } + + + // IsisXMLGroups: Overrides of the SAX DocumentHandler interface + void IsisXMLGroups::characters(const XMLCh* const chars, + const unsigned int length) {} + + + void IsisXMLGroups::endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname) { + parser->setContentHandler(prevDocHandler); + parser->setErrorHandler(prevErrorHandler); + } + + + void IsisXMLGroups::startElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes) { + + if ((string)XERCES::XMLString::transcode(localname) == (string)"group") { + if (groupHandler != NULL) { + delete groupHandler; + groupHandler = NULL; + } + unsigned int index = groups->size(); + groups->resize(index+1); + (*groups)[index].name = XERCES::XMLString::transcode (attributes.getValue((unsigned int)0)); + groupHandler = new IsisXMLGroup (encodingName, expandNamespaces, parser, + &(*groups)[index]); + } + else { + if (ignoreHandler != NULL) { + delete ignoreHandler; + ignoreHandler = NULL; + } + ignoreHandler = new IsisXMLIgnore (encodingName, expandNamespaces, parser, + (string)XERCES::XMLString::transcode(localname)); + } + + } + + + + + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLGroups.h b/isis/src/base/objs/IsisAml/IsisXMLGroups.h new file mode 100644 index 0000000000000000000000000000000000000000..5db46253c7c28a616b09543ee6e47bfb41219a9d --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLGroups.h @@ -0,0 +1,81 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisXMLGroups_h +#define IsisXMLGroups_h + +//#include + +#include "IsisAmlData.h" +#include "IsisXMLGroup.h" +#include "IsisXMLIgnore.h" + +class IsisXMLGroups : public IsisXMLHandler { + +public: + + ContentHandler *prevDocHandler; + ErrorHandler *prevErrorHandler; + + + IsisXMLGroups (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + std::vector *Pgroups); + + ~IsisXMLGroups (); + +// void endDocument(); + + void endElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname); + + void characters(const XMLCh* const chars, const unsigned int length); + + + void startElement (const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes); + + +private: + + // Saved arguments from constructor + char* encodingName; + bool expandNamespaces; + XERCES::SAX2XMLReader *parser; + std::vector *groups; + + // Handlers this handler knows how to create + IsisXMLGroup *groupHandler; + IsisXMLIgnore *ignoreHandler; + +}; + + +#endif + + + + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLHandler.cpp b/isis/src/base/objs/IsisAml/IsisXMLHandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..375abd8afc0b4d0d5019621edc7cb3c280ee61b1 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLHandler.cpp @@ -0,0 +1,183 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include + +#include +#include + +#include + +#include "iException.h" +#include "iException.h" + +#include "iString.h" + +#include "IsisXMLHandler.h" +#include "IsisXMLChTrans.h" + +namespace XERCES = XERCES_CPP_NAMESPACE; + + + // Constructors + + IsisXMLHandler::IsisXMLHandler () { + value=NULL; + outputEndTag = 0; + } + + + IsisXMLHandler::IsisXMLHandler (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + std::string *Pvalue) { + + encodingName = PencodingName; + expandNamespaces = PexpandNamespaces; + parser = Pparser; + value = Pvalue; + + outputEndTag = 0; + + prevDocHandler = parser->getContentHandler(); + prevErrorHandler = parser->getErrorHandler(); + + parser->setContentHandler(this); + parser->setErrorHandler(this); + } + + + IsisXMLHandler::IsisXMLHandler (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser) { + + value = NULL; + outputEndTag = 0; + + encodingName = PencodingName; + expandNamespaces = PexpandNamespaces; + parser = Pparser; + + prevDocHandler = parser->getContentHandler(); + prevErrorHandler = parser->getErrorHandler(); + + parser->setContentHandler(this); + parser->setErrorHandler(this); + } + + + IsisXMLHandler::~IsisXMLHandler () {} + + + // IsisXMLHandler: Overrides the SAX ErrorHandler + void IsisXMLHandler::error(const XERCES::SAXParseException& e) { + ostringstream os; + os << "Error in application XML file line: " << e.getLineNumber () + << " char: " << e.getColumnNumber() << ". " + << XERCES::XMLString::transcode(e.getMessage()); + throw Isis::iException::Message(Isis::iException::Programmer,os.str(), _FILEINFO_); + } + + void IsisXMLHandler::fatalError(const XERCES::SAXParseException& e) { + ostringstream os; + os << "Error in application XML file line: " << e.getLineNumber () + << " char: " << e.getColumnNumber() << ". " + << XERCES::XMLString::transcode(e.getMessage()); + throw Isis::iException::Message(Isis::iException::Programmer,os.str(), _FILEINFO_); + } + + void IsisXMLHandler::warning(const XERCES::SAXParseException& e) { + ostringstream os; + os << "Error in application XML file line: " << e.getLineNumber () + << " char: " << e.getColumnNumber() << ". " + << XERCES::XMLString::transcode(e.getMessage()); + throw Isis::iException::Message(Isis::iException::Programmer,os.str(), _FILEINFO_); + } + + + // IsisXMLHandler: Overrides of the SAX DocumentHandler interface + void IsisXMLHandler::characters(const XMLCh* const chars, + const unsigned int length) { + + if (value != NULL) { + Isis::iString str; + str = (string)XERCES::XMLString::transcode(chars); + str.Trim (" \n\r"); + *value += str; + } + } + + + void IsisXMLHandler::endDocument() { + } + + + void IsisXMLHandler::endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname) { + + if (outputEndTag > 0) { + Isis::iString str; + str = (string)XERCES::XMLString::transcode(localname); + *value += ""; + outputEndTag--; + } + else { + parser->setContentHandler(prevDocHandler); + parser->setErrorHandler(prevErrorHandler); + } + } + + + void IsisXMLHandler::ignorableWhitespace(const XMLCh* const chars, + const unsigned int length) { + } + + + + void IsisXMLHandler::processingInstruction(const XMLCh* const target, + const XMLCh* const data) { + } + + + void IsisXMLHandler::startDocument() { + } + + + void IsisXMLHandler::startElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes) { + + if (value != NULL) { + Isis::iString str; + str = (string)XERCES::XMLString::transcode(localname); + // Note: need to build the attributes into the string too + *value += "<" + str + ">"; + outputEndTag++; + } + } + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLHandler.h b/isis/src/base/objs/IsisAml/IsisXMLHandler.h new file mode 100644 index 0000000000000000000000000000000000000000..389b00160354a90f14ada2a8604a84e733c4a20e --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLHandler.h @@ -0,0 +1,94 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisXMLHandler_h +#define IsisXMLHandler_h + +#include + +namespace XERCES = XERCES_CPP_NAMESPACE; + +class IsisXMLHandler : public XERCES::DefaultHandler { + +public: + + ContentHandler *prevDocHandler; + ErrorHandler *prevErrorHandler; + + IsisXMLHandler (); + + IsisXMLHandler (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + std::string *chars); + + IsisXMLHandler (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser); + + ~IsisXMLHandler (); + + void endDocument(); + + void endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname); + + void characters(const XMLCh* const chars, + const unsigned int length); + + void ignorableWhitespace (const XMLCh* const chars, + const unsigned int length); + + void processingInstruction (const XMLCh* const target, + const XMLCh* const data); + + void startDocument(); + + void startElement (const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes); + + + // SAX ErrorHandler interface + void warning (const XERCES::SAXParseException& exception); + void error (const XERCES::SAXParseException& exception); + void fatalError (const XERCES::SAXParseException& exception); + + +private: + + // Saved argument from the constructor + char* encodingName; + bool expandNamespaces; + XERCES::SAX2XMLReader *parser; + std::string *value; + int outputEndTag; +}; + + +#endif + + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLHelper.cpp b/isis/src/base/objs/IsisAml/IsisXMLHelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a5def064fa4466c0b8943284e5ee10a203eb146 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLHelper.cpp @@ -0,0 +1,125 @@ + +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include + +#include +#include +#include + +#include "IsisXMLHelper.h" +#include "IsisXMLChTrans.h" + +#include "iString.h" + +namespace XERCES = XERCES_CPP_NAMESPACE; + + // Constructors + IsisXMLHelper::IsisXMLHelper (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + IsisHelperData *Phelper) { + + encodingName = PencodingName; + expandNamespaces = PexpandNamespaces; + parser = Pparser; + helper = Phelper; + + prevDocHandler = parser->getContentHandler(); + prevErrorHandler = parser->getErrorHandler(); + + parser->setContentHandler(this); + parser->setErrorHandler(this); + + ignoreHandler = NULL; + generalHandler = NULL; + } + + IsisXMLHelper::~IsisXMLHelper () { + if (ignoreHandler != NULL) delete ignoreHandler; + if (generalHandler != NULL) delete generalHandler; + } + + + // IsisXMLHelper: Overrides of the SAX DocumentHandler interface + void IsisXMLHelper::characters(const XMLCh* const chars, + const unsigned int length) { + } + + + void IsisXMLHelper::endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname) { + parser->setContentHandler(prevDocHandler); + parser->setErrorHandler(prevErrorHandler); + } + + void IsisXMLHelper::startElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes) { + + if ((string)XERCES::XMLString::transcode(localname) == (string)"brief") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, + parser, &helper->brief); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"description") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, + parser, &helper->description); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"function") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, + parser, &helper->function); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"icon") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, + parser, &helper->icon); + } + else { + if (ignoreHandler != NULL) { + delete ignoreHandler; + ignoreHandler = NULL; + } + ignoreHandler = new IsisXMLIgnore (encodingName, expandNamespaces, parser, + (string)XERCES::XMLString::transcode(localname)); + } + } diff --git a/isis/src/base/objs/IsisAml/IsisXMLHelper.h b/isis/src/base/objs/IsisAml/IsisXMLHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..5cc9cf16fc3e8c808cc8c1eef6f5b8b2b490aed8 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLHelper.h @@ -0,0 +1,77 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisXMLHelper_h +#define IsisXMLHelper_h + +//#include + +#include "IsisAmlData.h" +#include "IsisXMLIgnore.h" +#include "IsisXMLHandler.h" + + +class IsisXMLHelper : public IsisXMLHandler { + +public: + + ContentHandler *prevDocHandler; + ErrorHandler *prevErrorHandler; + + + IsisXMLHelper (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + IsisHelperData *Helper); + + ~IsisXMLHelper (); + + void endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname); + + void characters(const XMLCh* const chars, + const unsigned int length); + + void startElement (const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes); + + +private: + + // Saved argument from the constructor + char* encodingName; + bool expandNamespaces; + XERCES::SAX2XMLReader *parser; + IsisHelperData *helper; + + // Handler this handler knows how to create + IsisXMLHandler *generalHandler; + IsisXMLIgnore *ignoreHandler; +}; + + +#endif + diff --git a/isis/src/base/objs/IsisAml/IsisXMLHelpers.cpp b/isis/src/base/objs/IsisAml/IsisXMLHelpers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0499c62e3e16f13e66be5d39c22b2f7e6342d135 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLHelpers.cpp @@ -0,0 +1,106 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include + +#include +#include +#include + +#include "IsisXMLHelpers.h" +#include "IsisXMLChTrans.h" + +namespace XERCES = XERCES_CPP_NAMESPACE; + + + // Constructors + + IsisXMLHelpers::IsisXMLHelpers (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + std::vector *Phelpers) { + + encodingName = PencodingName; + expandNamespaces = PexpandNamespaces; + parser = Pparser; + helpers = Phelpers; + + prevDocHandler = parser->getContentHandler (); + prevErrorHandler = parser->getErrorHandler (); + + parser->setContentHandler (this); + parser->setErrorHandler (this); + + helperHandler = NULL; + ignoreHandler = NULL; + } + + IsisXMLHelpers::~IsisXMLHelpers () { + if (helperHandler != NULL) delete helperHandler; + if (ignoreHandler != NULL) delete ignoreHandler; + } + + + // IsisXMLHelpers: Overrides of the SAX DocumentHandler interface + void IsisXMLHelpers::characters(const XMLCh* const chars, + const unsigned int length) {} + + + void IsisXMLHelpers::endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname) { + parser->setContentHandler(prevDocHandler); + parser->setErrorHandler(prevErrorHandler); + } + + + void IsisXMLHelpers::startElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes) { + + if ((string)XERCES::XMLString::transcode(localname) == (string)"helper") { + if (helperHandler != NULL) { + delete helperHandler; + helperHandler = NULL; + } + unsigned int index = helpers->size(); + helpers->resize(index+1); + (*helpers)[index].name = XERCES::XMLString::transcode (attributes.getValue((unsigned int)0)); + helperHandler = new IsisXMLHelper (encodingName, expandNamespaces, parser, + &(*helpers)[index]); + } + else { + if (ignoreHandler != NULL) { + delete ignoreHandler; + ignoreHandler = NULL; + } + ignoreHandler = new IsisXMLIgnore (encodingName, expandNamespaces, parser, + (string)XERCES::XMLString::transcode(localname)); + } + + } + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLHelpers.h b/isis/src/base/objs/IsisAml/IsisXMLHelpers.h new file mode 100644 index 0000000000000000000000000000000000000000..08435d85eed83b9eba5f5487a9f0982e95dfafcb --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLHelpers.h @@ -0,0 +1,77 @@ + +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisXMLHelpers_h +#define IsisXMLHelpers_h + +//#include + +#include "IsisAmlData.h" +#include "IsisXMLHelper.h" +#include "IsisXMLIgnore.h" + +class IsisXMLHelpers : public IsisXMLHandler { + +public: + + ContentHandler *prevDocHandler; + ErrorHandler *prevErrorHandler; + + + IsisXMLHelpers (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + std::vector *Phelpers); + + ~IsisXMLHelpers (); + +// void endDocument(); + + void endElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname); + + void characters(const XMLCh* const chars, const unsigned int length); + + + void startElement (const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes); + + +private: + + // Saved arguments from constructor + char* encodingName; + bool expandNamespaces; + XERCES::SAX2XMLReader *parser; + std::vector *helpers; + + // Handlers this handler knows how to create + IsisXMLHelper *helperHandler; + IsisXMLIgnore *ignoreHandler; + +}; + + +#endif diff --git a/isis/src/base/objs/IsisAml/IsisXMLHistory.cpp b/isis/src/base/objs/IsisAml/IsisXMLHistory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..deca6f6c98593ec6384e69c78b496ce5fd1ebb27 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLHistory.cpp @@ -0,0 +1,124 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include + +#include +#include +#include + +#include "IsisXMLHistory.h" +#include "IsisXMLChTrans.h" + +namespace XERCES = XERCES_CPP_NAMESPACE; + + + // Constructors + + IsisXMLHistory::IsisXMLHistory (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + std::vector *Pchanges) { + + encodingName = PencodingName; + expandNamespaces = PexpandNamespaces; + parser = Pparser; + changes = Pchanges; + + prevDocHandler = parser->getContentHandler (); + prevErrorHandler = parser->getErrorHandler (); + + parser->setContentHandler (this); + parser->setErrorHandler (this); + + generalHandler = NULL; + ignoreHandler = NULL; + } + + IsisXMLHistory::~IsisXMLHistory () { + if (generalHandler != NULL) delete generalHandler; + if (ignoreHandler != NULL) delete ignoreHandler; + } + + + // IsisXMLHistory: Overrides of the SAX DocumentHandler interface + void IsisXMLHistory::characters(const XMLCh* const chars, + const unsigned int length) {} + + + void IsisXMLHistory::endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname) { + parser->setContentHandler(prevDocHandler); + parser->setErrorHandler(prevErrorHandler); + } + + + void IsisXMLHistory::startElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes) { + + if ((string)XERCES::XMLString::transcode(localname) == (string)"change") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + + // Pull the attributes out and save them + unsigned int index = changes->size(); + changes->resize(index+1); + + // Get the name and date attributes + string st; + for (unsigned int i=0; i<2; i++) { + st = XERCES::XMLString::transcode (attributes.getQName(i)); + if (st == "name") { + (*changes)[index].name = XERCES::XMLString::transcode(attributes.getValue(i)); + } + else if (st == "date") { + (*changes)[index].date = XERCES::XMLString::transcode(attributes.getValue(i)); + } + } + + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, + parser, &(*changes)[index].description); + } + else { + if (ignoreHandler != NULL) { + delete ignoreHandler; + ignoreHandler = NULL; + } + ignoreHandler = new IsisXMLIgnore (encodingName, expandNamespaces, parser, + (string)XERCES::XMLString::transcode(localname)); + } + + } + + + + + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLHistory.h b/isis/src/base/objs/IsisAml/IsisXMLHistory.h new file mode 100644 index 0000000000000000000000000000000000000000..2aa268b5173514e83d767d2b73ab58c9cff3e344 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLHistory.h @@ -0,0 +1,81 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisXMLHistory_h +#define IsisXMLHistory_h + +//#include + +#include "IsisAmlData.h" +#include "IsisXMLHandler.h" +#include "IsisXMLIgnore.h" + +class IsisXMLHistory : public IsisXMLHandler { + +public: + + ContentHandler *prevDocHandler; + ErrorHandler *prevErrorHandler; + + + IsisXMLHistory (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + std::vector *PChanges); + + ~IsisXMLHistory (); + +// void endDocument(); + + void endElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname); + + void characters(const XMLCh* const chars, const unsigned int length); + + + void startElement (const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes); + + +private: + + // Saved arguments from constructor + char* encodingName; + bool expandNamespaces; + XERCES::SAX2XMLReader *parser; + std::vector *changes; + + // Handlers this handler knows how to create + IsisXMLHandler *generalHandler; + IsisXMLIgnore *ignoreHandler; + +}; + + +#endif + + + + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLIgnore.cpp b/isis/src/base/objs/IsisAml/IsisXMLIgnore.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a940bfc4dc0925624d9b391572d5ffd6624661e4 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLIgnore.cpp @@ -0,0 +1,81 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include + +#include +#include + +#include "IsisXMLIgnore.h" +#include "IsisXMLChTrans.h" + + +namespace XERCES = XERCES_CPP_NAMESPACE; + + // Constructors + + IsisXMLIgnore::IsisXMLIgnore (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + const std::string Pignore) { + + encodingName = PencodingName; + expandNamespaces = PexpandNamespaces; + parser = Pparser; + ignore = Pignore; + + prevDocHandler = parser->getContentHandler (); + prevErrorHandler = parser->getErrorHandler (); + + parser->setContentHandler (this); + parser->setErrorHandler (this); + + } + + + IsisXMLIgnore::~IsisXMLIgnore () {} + + + void IsisXMLIgnore::characters(const XMLCh* const chars, + const unsigned int length) { + } + + void IsisXMLIgnore::endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname) { + + if ((string)XERCES::XMLString::transcode(localname) == ignore) { + parser->setContentHandler(prevDocHandler); + parser->setErrorHandler(prevErrorHandler); + } + } + + + + + + + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLIgnore.h b/isis/src/base/objs/IsisAml/IsisXMLIgnore.h new file mode 100644 index 0000000000000000000000000000000000000000..78c88258d0439404c01c4137de78c6c74b28a813 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLIgnore.h @@ -0,0 +1,70 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisXMLIgnore_h +#define IsisXMLIgnore_h + +//#include + +#include "IsisAmlData.h" +#include "IsisXMLHandler.h" + +class IsisXMLIgnore : public IsisXMLHandler { + +public: + + ContentHandler *prevDocHandler; + ErrorHandler *prevErrorHandler; + + + IsisXMLIgnore (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + const std::string Pignore); + + ~IsisXMLIgnore (); + + void characters(const XMLCh* const chars, + const unsigned int length); + + void endElement(const XMLCh* const uri, const XMLCh* const localname, + const XMLCh* const qname); + +private: + + // Saved arguments from constructor + char* encodingName; + bool expandNamespaces; + XERCES::SAX2XMLReader *parser; + std::string ignore; + +}; + + +#endif + + + + + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLList.cpp b/isis/src/base/objs/IsisAml/IsisXMLList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f5285eea2077dfa7aa6a0632077b1e0e3ef0cfde --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLList.cpp @@ -0,0 +1,134 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include + +#include +#include +#include + +#include "IsisXMLList.h" +#include "IsisXMLChTrans.h" + + +namespace XERCES = XERCES_CPP_NAMESPACE; + + // Constructors + IsisXMLList::IsisXMLList (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + IsisListOptionData *Plist) { + + encodingName = PencodingName; + expandNamespaces = PexpandNamespaces; + parser = Pparser; + list = Plist; + + prevDocHandler = parser->getContentHandler(); + prevErrorHandler = parser->getErrorHandler(); + + parser->setContentHandler(this); + parser->setErrorHandler(this); + + generalHandler = NULL; + multipleValuesHandler = NULL; + ignoreHandler = NULL; + + } + + IsisXMLList::~IsisXMLList () { + + if (generalHandler) delete generalHandler; + if (multipleValuesHandler != NULL) delete multipleValuesHandler; + if (ignoreHandler != NULL) delete ignoreHandler; + } + + + // IsisXMLList: Overrides of the SAX DocumentHandler interface + void IsisXMLList::characters(const XMLCh* const chars, + const unsigned int length) { + } + + + void IsisXMLList::endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname) { + parser->setContentHandler(prevDocHandler); + parser->setErrorHandler(prevErrorHandler); + } + + void IsisXMLList::startElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes) { + + if ((string)XERCES::XMLString::transcode(localname) == (string)"brief") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, parser, + &list->brief); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"description") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, parser, + &list->description); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"exclusions") { + if (multipleValuesHandler != NULL) { + delete multipleValuesHandler; + multipleValuesHandler = NULL; + } + multipleValuesHandler = + new IsisXMLMultipleValues (encodingName, expandNamespaces, + parser, &list->exclude); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"inclusions") { + if (multipleValuesHandler != NULL) { + delete multipleValuesHandler; + multipleValuesHandler = NULL; + } + multipleValuesHandler = + new IsisXMLMultipleValues (encodingName, expandNamespaces, + parser, &list->include); + } + else { + if (ignoreHandler != NULL) { + delete ignoreHandler; + ignoreHandler = NULL; + } + ignoreHandler = + new IsisXMLIgnore (encodingName, expandNamespaces, parser, + (string)XERCES::XMLString::transcode(localname)); + } + + + + + } diff --git a/isis/src/base/objs/IsisAml/IsisXMLList.h b/isis/src/base/objs/IsisAml/IsisXMLList.h new file mode 100644 index 0000000000000000000000000000000000000000..d7bcd7ac205d0e02281a9cf63defb47c49d3d7f8 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLList.h @@ -0,0 +1,79 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisXMLList_h +#define IsisXMLList_h + +//#include + +#include "IsisAmlData.h" +#include "IsisXMLMultipleValues.h" +#include "IsisXMLIgnore.h" + +class IsisXMLList : public IsisXMLHandler { + +public: + + ContentHandler *prevDocHandler; + ErrorHandler *prevErrorHandler; + + + IsisXMLList (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + IsisListOptionData *Plist); + + ~IsisXMLList (); + + void endElement (const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname); + + void characters (const XMLCh* const chars, + const unsigned int length); + + void startElement (const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes); + + +private: + + // Saved argument from the constructor + char* encodingName; + bool expandNamespaces; + XERCES::SAX2XMLReader *parser; + IsisListOptionData *list; + + // Handlers this handler knows how to create + IsisXMLHandler *generalHandler; + IsisXMLMultipleValues *multipleValuesHandler; + IsisXMLIgnore *ignoreHandler; +}; + + +#endif + + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLMultipleValues.cpp b/isis/src/base/objs/IsisAml/IsisXMLMultipleValues.cpp new file mode 100644 index 0000000000000000000000000000000000000000..20192e2d92c33866a5dcb4d0ac64992200bb5448 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLMultipleValues.cpp @@ -0,0 +1,104 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include + +#include +#include + +#include "IsisXMLMultipleValues.h" +#include "IsisXMLChTrans.h" + + // Constructors + + IsisXMLMultipleValues::IsisXMLMultipleValues (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + std::vector *PmultipleValues) { + + encodingName = PencodingName; + expandNamespaces = PexpandNamespaces; + parser = Pparser; + multipleValues = PmultipleValues; + + prevDocHandler = parser->getContentHandler (); + prevErrorHandler = parser->getErrorHandler (); + + parser->setContentHandler (this); + parser->setErrorHandler (this); + + generalHandler = NULL; + ignoreHandler = NULL; + } + + IsisXMLMultipleValues::~IsisXMLMultipleValues () { + if (generalHandler != NULL) delete generalHandler; + if (ignoreHandler != NULL) delete ignoreHandler; + } + + + // IsisXMLMultipleValues: Overrides of the SAX DocumentHandler interface + void IsisXMLMultipleValues::characters(const XMLCh* const chars, + const unsigned int length) {} + + + void IsisXMLMultipleValues::endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname) { + parser->setContentHandler(prevDocHandler); + parser->setErrorHandler(prevErrorHandler); + } + + + void IsisXMLMultipleValues::startElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes) { + + if ((string)XERCES::XMLString::transcode(localname) == (string)"item") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + unsigned int index = multipleValues->size(); + multipleValues->resize(index+1); + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, + parser, &(*multipleValues)[index]); + } + else { + if (ignoreHandler != NULL) { + delete ignoreHandler; + ignoreHandler = NULL; + } + ignoreHandler = new IsisXMLIgnore (encodingName, expandNamespaces, parser, + (string)XERCES::XMLString::transcode(localname)); + } + } + + + + + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLMultipleValues.h b/isis/src/base/objs/IsisAml/IsisXMLMultipleValues.h new file mode 100644 index 0000000000000000000000000000000000000000..1e1d8af25b51ccc89a893279cd67148ea3244f50 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLMultipleValues.h @@ -0,0 +1,79 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisXMLMultipleValues_h +#define IsisXMLMultipleValues_h + +//#include + +#include "IsisAmlData.h" +#include "IsisXMLHandler.h" +#include "IsisXMLIgnore.h" + +class IsisXMLMultipleValues : public IsisXMLHandler { + +public: + + ContentHandler *prevDocHandler; + ErrorHandler *prevErrorHandler; + + + IsisXMLMultipleValues (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + std::vector *PmultipleValues); + + ~IsisXMLMultipleValues (); + +// void endDocument(); + + + void endElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname); + + void characters(const XMLCh* const chars, const unsigned int length); + + + void startElement (const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes); + + +private: + + // Saved arguments from constructor + char* encodingName; + bool expandNamespaces; + XERCES::SAX2XMLReader *parser; + std::vector *multipleValues; + + // Handlers this handler knows how to create + IsisXMLHandler *generalHandler; + IsisXMLIgnore *ignoreHandler; + +}; + + +#endif + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLParameter.cpp b/isis/src/base/objs/IsisAml/IsisXMLParameter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e966ac90be7fa9d1908bf7a4d19972270791fcb3 --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLParameter.cpp @@ -0,0 +1,305 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include + +#include +#include +#include + +#include "iString.h" + +#include "IsisXMLParameter.h" +#include "IsisXMLChTrans.h" + + + // Constructors + + IsisXMLParameter::IsisXMLParameter (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + IsisParameterData *Pparameter) { + + encodingName = PencodingName; + expandNamespaces = PexpandNamespaces; + parser = Pparser; + parameter = Pparameter; + + prevDocHandler = parser->getContentHandler(); + prevErrorHandler = parser->getErrorHandler(); + + parser->setContentHandler(this); + parser->setErrorHandler(this); + + generalHandler = NULL; + multipleValuesHandler = NULL; + ignoreHandler = NULL; + listHandler = NULL; + helpersHandler = NULL; + } + + IsisXMLParameter::~IsisXMLParameter () { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + if (multipleValuesHandler != NULL) { + delete multipleValuesHandler; + multipleValuesHandler = NULL; + } + if (ignoreHandler != NULL) { + delete ignoreHandler; + ignoreHandler = NULL; + } + if (listHandler != NULL) { + delete listHandler; + listHandler = NULL; + } + if (helpersHandler != NULL) { + delete helpersHandler; + helpersHandler = NULL; + } + } + + + // IsisXMLParameter: Overrides of the SAX DocumentHandler interface + void IsisXMLParameter::characters(const XMLCh* const chars, + const unsigned int length) {} + + + void IsisXMLParameter::endElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname) { + if ((string)XERCES::XMLString::transcode(localname) != "list") { + parser->setContentHandler(prevDocHandler); + parser->setErrorHandler(prevErrorHandler); + } + } + + void IsisXMLParameter::startElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes) { + + if ((string)XERCES::XMLString::transcode(localname) == (string)"type") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, + parser, ¶meter->type); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"brief") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, + parser, ¶meter->brief); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"description") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, + parser, ¶meter->description); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"default") { + if (multipleValuesHandler != NULL) { + delete multipleValuesHandler; + multipleValuesHandler = NULL; + } + multipleValuesHandler = new IsisXMLMultipleValues (encodingName, expandNamespaces, + parser, ¶meter->defaultValues); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"internalDefault") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, parser, + ¶meter->internalDefault); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"count") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, parser, + ¶meter->count); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"list") { + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"option") { + if (listHandler != NULL) { + delete listHandler; + listHandler = NULL; + } + unsigned int index = parameter->listOptions.size(); + parameter->listOptions.resize (index + 1); + Isis::iString lo = XERCES::XMLString::transcode (attributes.getValue((unsigned int)0)); + lo.UpCase(); + parameter->listOptions[index].value = lo; + listHandler = new IsisXMLList (encodingName, expandNamespaces, parser, + ¶meter->listOptions[index]); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"minimum") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + Isis::iString mi = XERCES::XMLString::transcode (attributes.getValue((unsigned int)0)); + mi.DownCase(); + parameter->minimum_inclusive = mi; + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, + parser, ¶meter->minimum); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"maximum") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + Isis::iString mi = XERCES::XMLString::transcode (attributes.getValue((unsigned int)0)); + mi.DownCase(); + parameter->maximum_inclusive = mi; + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, parser, + ¶meter->maximum); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"greaterThan") { + if (multipleValuesHandler != NULL) { + delete multipleValuesHandler; + multipleValuesHandler = NULL; + } + multipleValuesHandler = new IsisXMLMultipleValues (encodingName, expandNamespaces, + parser, ¶meter->greaterThan); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"greaterThanOrEqual") { + if (multipleValuesHandler != NULL) { + delete multipleValuesHandler; + multipleValuesHandler = NULL; + } + multipleValuesHandler = new IsisXMLMultipleValues (encodingName, expandNamespaces, + parser, ¶meter->greaterThanOrEqual); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"lessThan") { + if (multipleValuesHandler != NULL) { + delete multipleValuesHandler; + multipleValuesHandler = NULL; + } + multipleValuesHandler = new IsisXMLMultipleValues (encodingName, expandNamespaces, + parser, ¶meter->lessThan); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"lessThanOrEqual") { + if (multipleValuesHandler != NULL) { + delete multipleValuesHandler; + multipleValuesHandler = NULL; + } + multipleValuesHandler = new IsisXMLMultipleValues (encodingName, expandNamespaces, + parser, ¶meter->lessThanOrEqual); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"notEqual") { + if (multipleValuesHandler != NULL) { + delete multipleValuesHandler; + multipleValuesHandler = NULL; + } + multipleValuesHandler = new IsisXMLMultipleValues (encodingName, expandNamespaces, + parser, ¶meter->notEqual); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"odd") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + parameter->odd = "TRUE"; + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, parser); + + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"exclusions") { + if (multipleValuesHandler != NULL) { + delete multipleValuesHandler; + multipleValuesHandler = NULL; + } + multipleValuesHandler = new IsisXMLMultipleValues (encodingName, expandNamespaces, + parser, ¶meter->exclude); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"inclusions") { + if (multipleValuesHandler != NULL) { + delete multipleValuesHandler; + multipleValuesHandler = NULL; + } + multipleValuesHandler = new IsisXMLMultipleValues (encodingName, expandNamespaces, + parser, ¶meter->include); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"filter") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, parser, ¶meter->filter); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"defaultPath") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, parser, + ¶meter->path); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"fileMode") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, parser, ¶meter->fileMode); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"pixelType") { + if (generalHandler != NULL) { + delete generalHandler; + generalHandler = NULL; + } + generalHandler = new IsisXMLHandler (encodingName, expandNamespaces, parser, ¶meter->pixelType); + } + else if ((string)XERCES::XMLString::transcode(localname) == (string)"helpers") { + if (helpersHandler != NULL) { + delete helpersHandler; + helpersHandler = NULL; + } + helpersHandler = new IsisXMLHelpers (encodingName, expandNamespaces, parser, + ¶meter->helpers); + } + else { + if (ignoreHandler != NULL) { + delete ignoreHandler; + ignoreHandler = NULL; + } + ignoreHandler = new IsisXMLIgnore (encodingName, expandNamespaces, parser, + (string)XERCES::XMLString::transcode(localname)); + } + } + + + + diff --git a/isis/src/base/objs/IsisAml/IsisXMLParameter.h b/isis/src/base/objs/IsisAml/IsisXMLParameter.h new file mode 100644 index 0000000000000000000000000000000000000000..3ba9577a2416e5f24980aeb222ef8e6820dc1dab --- /dev/null +++ b/isis/src/base/objs/IsisAml/IsisXMLParameter.h @@ -0,0 +1,81 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef IsisXMLParameter_h +#define IsisXMLParameter_h + +//#include + +#include "IsisAmlData.h" +#include "IsisXMLHandler.h" +#include "IsisXMLMultipleValues.h" +#include "IsisXMLIgnore.h" +#include "IsisXMLList.h" +#include "IsisXMLHelpers.h" + +class IsisXMLParameter : public IsisXMLHandler { + +public: + + ContentHandler *prevDocHandler; + ErrorHandler *prevErrorHandler; + + + IsisXMLParameter (char* PencodingName, + bool &PexpandNamespaces, + XERCES::SAX2XMLReader* &Pparser, + IsisParameterData *Pparameter); + + ~IsisXMLParameter (); + +// void endDocument(); + + void endElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname); + + void characters(const XMLCh* const chars, const unsigned int length); + + void startElement (const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const XERCES::Attributes& attributes); + + +private: + + // Saved arguments from constructor + char* encodingName; + bool expandNamespaces; + XERCES::SAX2XMLReader *parser; + IsisParameterData *parameter; + + // Handlers this handler knows how to create + IsisXMLHandler *generalHandler; + IsisXMLMultipleValues *multipleValuesHandler; + IsisXMLIgnore *ignoreHandler; + IsisXMLList *listHandler; + IsisXMLHelpers *helpersHandler; +}; + + +#endif + diff --git a/isis/src/base/objs/IsisAml/Makefile b/isis/src/base/objs/IsisAml/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..205faace2eb30ed807ae27a1f9319b286f82b138 --- /dev/null +++ b/isis/src/base/objs/IsisAml/Makefile @@ -0,0 +1,5 @@ +INCS = $(wildcard Isis*.h) +SRCS = $(wildcard Isis*.cpp) +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/IsisAml/unitTest.cpp b/isis/src/base/objs/IsisAml/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de838ad1a5421d3b1f5c5409a56c015b864c430e --- /dev/null +++ b/isis/src/base/objs/IsisAml/unitTest.cpp @@ -0,0 +1,734 @@ +#include +#include +#include +#include "IsisAml.h" +#include "iException.h" +#include "Filename.h" +#include "Pvl.h" +#include "Preference.h" + + +using namespace std; +class Inheritor : public IsisAml { + public: + Inheritor (const char *xmlfile); + ~Inheritor (); +}; + +Inheritor::Inheritor (const char *xmlfile): IsisAml (xmlfile) { + + try { + cout << "--------- Tests for private data ----------" << endl; + + cout << " App name = " << name << endl; + cout << " App brief = " << brief << endl; + cout << " App description = " << description << endl; + + // Print categories + for (unsigned int l=0; lProgramName () << endl; + cout << "Brief description: " << aml->Brief() << endl; + cout << "Full description: " << aml->Description() << endl; + cout << "Version date: " << aml->Version() << endl << endl; + + cout << "Number of parameter groups : " << aml->NumGroups () << endl << endl; + cout << "Parameter information:" << endl; + for (int g=0; gNumGroups(); g++) { + cout << " Group number: " << g << endl; + cout << " Group name : " << aml->GroupName (g) << endl; + for (int p=0; pNumParams(g); p++) { + cout << " Parameter number: " << p << endl; + cout << " Name: " << aml->ParamName(g,p) << endl; + cout << " Type: " << aml->ParamType(g,p) << endl; + cout << " Brief: " << aml->ParamBrief(g,p) << endl; + cout << " Default: " << aml->ParamDefault(g,p) << endl; + cout << " Internal default: " << aml->ParamInternalDefault(g,p) << endl; + cout << " Filter: " << aml->ParamFilter(g,p) << endl; + cout << " File Mode: " << aml->ParamFileMode(g,p) << endl; + cout << " Helper Information:" << endl; + for (int h=0; hHelpersSize(g,p); h++) { + cout << " Name: " << aml->HelperButtonName(g,p,h) << endl; + cout << " Brief: " << aml->HelperBrief(g,p,h) << endl; + cout << " Description: " << aml->HelperDescription(g,p,h) << endl; + cout << " Function: " << aml->HelperFunction(g,p,h) << endl; + cout << " Icon: " << aml->HelperIcon(g,p,h) << endl; + } + cout << " List Information:" << endl; + for (int o=0; oParamListSize (g,p); o++) { + cout << " Value: " << aml->ParamListValue (g,p,o) << endl; + cout << " Brief: " << aml->ParamListBrief (g,p,o) << endl; + cout << " Description: " << aml->ParamListDescription(g,p,o) << endl; + cout << " List exclusions: " << endl; + for (int e=0; eParamListExcludeSize (g,p,o); e++) { + cout << " Exclude parameter: " << aml->ParamListExclude (g,p, o,e) << endl; + } + cout << " List inclusions: " << endl; + for (int i=0; iParamListIncludeSize (g,p,o); i++) { + cout << " Include parameter: " << aml->ParamListInclude (g,p, o,i) << endl; + } + } + } + } + + cout << "Get/Put/Clear/WasEntered tests" << endl; + cout << "Default value of G0P1 is " << aml->GetFilename ("G0P1") << endl; + cout << "G0P1 WasEntered value " << aml->WasEntered ("G0P1") << endl; + aml->PutAsString ("G0P1", "/home/user/file1.cub"); + cout << "G0P1 WasEntered value " << aml->WasEntered ("G0P1") << endl; + cout << "The value of G0P1 is " << aml->GetFilename ("G0P1") << endl; + aml->Clear ("G0P1"); + cout << "Default value of G0P1 is " << aml->GetFilename ("G0P1") << endl; + aml->PutFilename ("G0P1", "/home/user/file2.dat"); + cout << "The value of G0P1 is " << aml->GetFilename ("G0P1") << endl << endl; + cout << "The value of G0P1 is " << aml->GetFilename ("G0P1","txt") << endl << endl; + aml->Clear ("G0P1"); + + cout << "Default value of G1P1 is " << aml->GetInteger("G1P1") << endl; + aml->PutInteger ("G1P1", 33); + cout << "The value of G1P1 is " << aml->GetInteger("G1P1") << endl << endl; + aml->Clear ("G1P1"); + + cout << "Default value of G1P2 is " << aml->GetDouble("G1P2") << endl; + aml->PutDouble ("G1P2", 0.000000001); + cout << "The value of G1P2 is " << aml->GetDouble("G1P2") << endl << endl; + aml->Clear ("G1P2"); + + cout << "Default value of G1P0 is " << aml->GetString("G1P0") << endl; + aml->PutString ("G1P0", "G1p0L1"); + cout << "The value of G1P0 is " << aml->GetString("G1P0") << endl << endl; + aml->Clear ("G1P0"); + + aml->PutBoolean ("G6P0", true); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutBoolean ("G6P0", false); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + + aml->PutAsString ("G6P0", "TRUE"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "FALSE"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "true"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "false"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + + aml->PutAsString ("G6P0", "YES"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "NO"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "yes"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "no"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + + aml->PutAsString ("G6P0", "T"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "F"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "t"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "f"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + + aml->PutAsString ("G6P0", "Y"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "N"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "y"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "n"); + cout << "The value of G6P0 is " << aml->GetBoolean("G6P0") << endl << endl; + aml->Clear ("G6P0"); + + cout << "Exact and partial name match tests:" << endl; + cout << " FROM's value = " << aml->GetString ("from") << endl; + cout << " FROM1's value = " << aml->GetString ("from1") << endl; + cout << " FR's value = " << aml->GetString ("fr") << endl; + cout << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl; + + // Test the error catching for public members + + cout << "---------- Test error throwing ----------"; + + try { + cout << " PutAsString:" << endl; + try { + aml->PutAsString ("G1P0", "11111"); + aml->PutAsString ("G1P0", "22222"); + } + catch (Isis::iException &error) { + error.Report (false); + } + aml->Clear ("G1P0"); + + cout << endl << " PutString:" << endl; + try { + aml->PutString ("G1P0", "G1P0L0"); + aml->PutString ("G1P0", "22222"); + } + catch (Isis::iException &error) { + error.Report (false); + } + aml->Clear ("G1P0"); + + cout << endl; + try { + aml->PutString ("G2P4", "xxxxxx"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl << " PutFilename:" << endl; + try { + aml->PutFilename ("G0P0", "xxxxxxx"); + aml->PutFilename ("G0P0", "yyyyyyy"); + } + catch (Isis::iException &error) { + error.Report (false); + } + aml->Clear ("G0P0"); + + cout << endl; + try { + aml->PutFilename ("G2P4", "xxxxxx"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl << " Cube tests:" << endl; + try { + aml->PutFilename ("CUBE1", "xxxxxxx.cub+1,2-4"); + Isis::CubeAttributeInput &att = aml->GetInputAttribute("CUBE1"); + cout << " " << att.BandsStr() << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + aml->Clear ("CUBE1"); + + try { + aml->PutFilename ("CUBE2", "yyyyyyy.cub+8-bit+BSQ+detached"); + Isis::CubeAttributeOutput &att = aml->GetOutputAttribute("CUBE2"); + string strng; + att.Write(strng); + cout << " Att string = " << strng << endl; + cout << " File format = " << att.FileFormatStr() << endl; + cout << " Pixel type = " << Isis::PixelTypeName(att.PixelType()) << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + aml->Clear ("CUBE2"); + + + + + cout << endl << " PutInteger:" << endl; + try { + aml->PutInteger ("G6P2", 1); + aml->PutInteger ("G6P2", 1); + } + catch (Isis::iException &error) { + error.Report (false); + } + aml->Clear ("G6P2"); + + cout << endl; + try { + aml->PutInteger ("G6P0", 1); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl << " PutDouble:" << endl; + try { + aml->PutDouble ("G1P2", 1.0); + aml->PutDouble ("G1P2", 1.0); + } + catch (Isis::iException &error) { + error.Report (false); + } + aml->Clear ("G1P2"); + + cout << endl; + try { + aml->PutDouble ("G0P0", 1.0); + } + catch (Isis::iException &error) { + error.Report (false); + } + + + cout << endl << " PutBoolean:" << endl; + try { + aml->PutBoolean ("G6P0", true); + aml->PutBoolean ("G6P0", false); + } + catch (Isis::iException &error) { + error.Report (false); + } + aml->Clear ("G6P0"); + + cout << endl; + try { + aml->PutBoolean ("G0P0", false); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl << " GetAsString:" << endl; + try { + string s = aml->GetAsString ("G2P0"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl << " GetFilename:" << endl; + try { + string s = aml->GetFilename ("G0P0"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl; + try { + string s = aml->GetFilename ("G2P4"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + #if 0 + cout << endl << " GetCube:" << endl; + try { + string s = aml->GetCube ("CUBE1"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl; + try { + string s = aml->GetCube ("G2P4"); + } + catch (Isis::iException &error) { + error.Report (false); + } + #endif + + cout << endl << " GetString:" << endl; + try { + string s = aml->GetString ("G6P3"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl; + try { + string s = aml->GetString ("G2P4"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl << " GetInteger:" << endl; + try { + aml->GetInteger ("G2P0"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl; + try { + aml->GetInteger ("G0P0"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl << " GetDouble:" << endl; + try { + aml->GetDouble ("G1P3"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl; + try { + aml->GetDouble ("G0P1"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl << " GetBoolean:" << endl; + try { + aml->GetBoolean ("G6P0"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + try { + aml->PutAsString("G6P0", "cccc"); + aml->GetBoolean ("G6P0"); + } + catch (Isis::iException &error) { + error.Report (false); + } + aml->Clear ("G6P0"); + + cout << endl; + try { + aml->GetBoolean ("G1P1"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + try { + string s = aml->GetString("F"); + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + // Load up a valid set of parameters + + cout << "---------- Validate a correctly loaded set of parameters ----------" << endl; + aml->Clear ("G0P0"); + aml->PutAsString ("G0P0", "FILE1"); + + aml->Clear ("G0P1"); + aml->PutAsString ("G0P1", "FILE2"); + + aml->Clear ("G1P0"); + aml->PutAsString ("G1P0", "G1P0L0"); + + aml->Clear ("G1P1"); + + aml->Clear ("G1P2"); + + aml->Clear ("G1P3"); + aml->PutAsString ("G1P3", "1.1"); + + aml->Clear ("G2P0"); + + aml->Clear ("G2P1"); + aml->PutAsString ("G2P1", "1"); + + aml->Clear ("G2P2"); + aml->PutAsString ("G2P2", "3"); + + aml->Clear ("G2P3"); + aml->PutAsString ("G2P3", "4"); + + aml->Clear ("G2P4"); + aml->PutAsString ("G2P4", "5"); + + aml->Clear ("G3P0"); + + aml->Clear ("G3P1"); + aml->PutAsString ("G3P1", "1.2"); + + aml->Clear ("G3P2"); + aml->PutAsString ("G3P2", "1.3"); + + aml->Clear ("G3P3"); + aml->PutAsString ("G3P3", "1.4"); + + aml->Clear ("G3P4"); + aml->PutAsString ("G3P4", "1.5"); + + aml->Clear ("G4P0"); + aml->PutAsString ("G4P0", "1.6"); + + aml->Clear ("G4P1"); + aml->PutAsString ("G4P1", "6"); + + aml->Clear ("G4P2"); + aml->PutAsString ("G4P2", "6.7"); + + aml->Clear ("G4P3"); + aml->PutAsString ("G4P3", "7"); + + aml->Clear ("G4P4"); + aml->PutAsString ("G4P4", "7.8"); + + aml->Clear ("G4P5"); + aml->PutAsString ("G4P5", "8"); + + aml->Clear ("G5P0"); + aml->PutAsString ("G5P0", "9"); + + aml->Clear ("G5P1"); + aml->PutAsString ("G5P1", "10"); + + aml->Clear ("G5P2"); + aml->PutAsString ("G5P2", "11"); + + aml->Clear ("G5P3"); + + aml->Clear ("G6P0"); + aml->PutAsString ("G6P0", "yes"); + + aml->Clear ("G6P1"); + aml->PutAsString ("G6P1", "13"); + + aml->Clear ("G6P2"); + + aml->Clear ("G6P3"); + aml->PutAsString ("G6P3", "STRING2"); + + aml->Clear ("FROM"); + aml->PutAsString ("FROM", "STRING3"); + + aml->Clear ("FROM1"); + aml->PutAsString ("FROM1", "STRING4"); + + aml->Clear ("FR"); + aml->PutAsString ("FR", "STRING4"); + + aml->Clear ("CUBE1"); + aml->PutAsString ("CUBE1", "CUBE.DAT"); + + aml->Clear ("CUBE2"); + aml->PutAsString ("CUBE2", "CUBE2.DAT"); + + try { + aml->VerifyAll(); + } + catch (Isis::iException &error) { + error.Report (false); + } + cout << endl; + + // Test the command line member + cout << "The current command line:" << endl; + try { + Isis::Pvl lab; + aml->CommandLine(lab); + cout << lab << endl << endl; + } + catch (Isis::iException &error) { + error.Report(false); + } + + cout << endl; + + cout << "--- Check for NO value in an option/list/included parameter ---" << endl; + aml->Clear ("G1P0"); + aml->PutAsString ("G1P0", "G1P0L1X"); + aml->Clear ("G1P3"); + try { + aml->VerifyAll(); + } + catch (Isis::iException &error) { + error.Report (false); + } + aml->Clear("G1P0"); + aml->PutAsString ("G1P3", "1.1"); + aml->PutAsString ("G1P0", "G1P0L0"); + cout << endl; + + cout << "----- Check for value in an option/list/excluded parameter -----" << endl; + aml->PutAsString ("G2P0", "0"); + try { + aml->VerifyAll(); + } + catch (Isis::iException &error) { + error.Report (false); + } + aml->Clear("G2P0"); + cout << endl; + + cout << "---------- Check error for unknow parameter ----------" << endl; + try { + aml->Clear ("xyz"); + } + catch (Isis::iException &error) { + error.Report (false); + } +} + diff --git a/isis/src/base/objs/IsisAml/unitTest.xml b/isis/src/base/objs/IsisAml/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..6d564079ade46e8fc0bb5d3506ce8a4a7b6b06ba --- /dev/null +++ b/isis/src/base/objs/IsisAml/unitTest.xml @@ -0,0 +1,582 @@ + + + + + + Brief description + + + + This program tests the IsisAml class and its supporting classes. + + + + + Original version + + + Added more parameters for a more complete test + + + Modified schema from astrogeology... isis.astrogeology... + + + + + Scripting + Utility + + + + + + filename + input + + G0P0 Filename + + + Description for G0P0 +

    + Paragraph 2 of description for G0P0 +

    + End of description for G0P0 +
    + + *.cub + +
    + + + filename + output + + G0P1 Filename + + + Description for G0P0, + line 2 of the description, + line 3 of the description + + + /my/dir/file.cub + + +
    + + + + string + Brief for parameter G1P0 + + Description for G1P0. + + + + G1P0L0 + + + + + + + + + + + integer + Brief for G1P1 + + Description for G1P1 + + + + Helper 1 + + This helper button does..... + + myHelper + + + Helper 2 + + This helper buttion will... + + myHelper2 + $ISIS3DATA/base/icons/back.png + + + + 0 + + + G1P2 + G1P3 + + + + + double + Brief for G1P2 + + Description for G1P2 + + + 10.5 + + + G1P1 + + + G1P2 + + + + + double + Brief for G1P3 + + Description for G1P3 + + + G1P1 + G1P2 + + + + + + + integer + Brief for parameter G2P0 + + Description for G2P0. + + + + Calculated inside program + + + 0 + 999 + + + + G2P1 + + + + + integer + Brief for parameter G2P1 + + Description for G2P1. + + + G2P0 + + + G2P2 + + + + + integer + Brief for parameter G2P2 + + Description for G2P2. + + + G2P1 + + + + + integer + Brief for parameter G2P3 + + Description for G2P3. + + + g2p4 + + + + + integer + Brief for parameter G2P4 + + Description for G2P4. + + + G2P3 + + + + + + + double + Brief for parameter G3P0 + + Description for G3P0. + + + Calculated inside program + + -0.5 + 999.5 + + G3P1 + + + + + double + Brief for parameter G3P1 + + Description for G3P1. + + + + Helper 3 + + Long Description for Helper 3 + + myHelper3 + $ISIS3DATA/base/icons/up.png + + + + G3P0 + + + G3P2 + + + + + double + Brief for parameter G3P2 + + Description for G3P2. + + + G3P1 + + + + + double + Brief for parameter G3P3 + + Description for G3P3. + + + G3P4 + + + + + double + Brief for parameter G3P4 + + Description for G3P4. + + + + G3P3 + + + + + + + double + Brief for parameter G4P0 + + Description for G4P0. + + + G4P1 + + + + + integer + Brief for parameter G4P1 + + Description for G4P1. + + + G4P2 + + + G4P0 + + + + + double + Brief for parameter G4P2 + + Description for G4P2. + + + G4P3 + + + G4P1 + + + + + integer + Brief for parameter G4P3 + + Description for G4P3. + + + G4P4 + + + G4P2 + + + + + double + Brief for parameter G4P4 + + Description for G4P4. + + + G4P3 + + + G4P5 + + + + + integer + Brief for parameter G4P5 + + Description for G4P5. + + + G4P4 + + + + + + + integer + Brief for parameter G5P0 + + Description for G5P0. + + + G5P1 + G5P2 + + + G5P3 + + + + + integer + Brief for parameter G5P1 + + Description for G5P1. + + + G5P0 + G5P2 + + + + + integer + Brief for parameter G5P2 + + Description for G5P2. + + + G5P0 + + + + + integer + Brief for parameter G5P3 + + Description for G5P3. + + + G5P0 + G5P1 + G5P2 + + + + + + + boolean + Brief for parameter G6P0 + + Description for G6P0. + + + + Helper 4 + + Long Description for Helper 4... + + myHelper4 + + + + G6P1 + + + G6P2 + + + + + integer + Brief for parameter G6P1 + + Description for G6P1. + + + + + integer + Brief for parameter G6P2 + + Description for G6P2. + + + 100 + + + + string + Brief for parameter G6P3 + + Description for G6P3. + + + + + + + string + Brief for parameter FROM + + Description for FROM. + + + FROM + + + + + string + Brief for parameter FROM1 + + Description for FROM1. + + + + Helper 5 + + Long Description for Helper 5... + + myHelper5 + $ISIS3DATA/base/icons/link.png + + + + FROM1 + + + + + string + Brief for parameter FR + + Description for FR. + + + FR + + + + + + + cube + input + Brief for parameter CUBE1 + + Description for CUBE1. + + + + Helper 6 + + Long Description for Helper 6... + + myHelper6 + + + + + + cube + output + Brief for parameter CUBE2 + + Description for CUBE2. + + + + +
    + +
    diff --git a/isis/src/base/objs/Isotropic1/AtmosModel.plugin b/isis/src/base/objs/Isotropic1/AtmosModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..98044871c47617e7dd02af99e2408a94b8489a8b --- /dev/null +++ b/isis/src/base/objs/Isotropic1/AtmosModel.plugin @@ -0,0 +1,4 @@ +Group = Isotropic1 + Library = Isotropic1 + Routine = Isotropic1Plugin +End_Group diff --git a/isis/src/base/objs/Isotropic1/Isotropic1.cpp b/isis/src/base/objs/Isotropic1/Isotropic1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eb7ab6763bb05623bf74f43d4af3b34136f0a1c5 --- /dev/null +++ b/isis/src/base/objs/Isotropic1/Isotropic1.cpp @@ -0,0 +1,203 @@ +#include +#include "AtmosModel.h" +#include "Constants.h" +#include "Isotropic1.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "iString.h" + +using std::max; + +namespace Isis { + Isotropic1::Isotropic1 (Pvl &pvl, PhotoModel &pmodel) : AtmosModel(pvl,pmodel) { + PvlGroup &algorithm = pvl.FindObject("AtmosphericModel").FindGroup("Algorithm",Pvl::Traverse); + + SetAtmosHnorm(0.003); + + // Get value from user + if (algorithm.HasKeyword("Hnorm")) { + SetAtmosHnorm(algorithm["Hnorm"]); + } + } + + /** + * Isotropic atmospheric scattering in the first approximation + * The model for scattering for a general, non-Lambertian surface with + * an atmosphere looks like this: + * + * P = Pstd + trans*(rho*Ah*munot)/(1.d0-rho*Ab*sbar) + * trans0*rho*(Psurf-Ah*munot) + * + * where P is the overall photometric function (the model of the data), + * PSTD is the pure atmospheric-scattering term, PSURF is the surface + * photometric function, AH*MUNOT is a Lambertian approximation to this + * with hemispheric albedo AH, TRANS and TRANS0 quantify transmission + * of surface reflected light through the atmosphere overall and with + * no scatterings in the atmosphere, and finally SBAR quantifies the + * illumination of the ground by the sky. RHO is the ratio of the sur- + * face albedo to the albedo assumed in the functional form of PSURF. + * + * @param phase Value of the phase angle. + * @param incidence Value of the incidence angle. + * @param emission Value of the emission angle. + * + * @history 1998-12-21 Randy Kirk - USGS, Flagstaff - Original + * code + * @history 1999-03-12 K Teal Thompson Port to Unix/ISIS; + * declare vars; add implicit none. + * @history 2007-02-20 Janet Barrett - Imported from Isis2 + * pht_atm_functions to Isis3. + * @history 2008-11-05 Jeannie Walldren - Replaced + * NumericalMethods::r8expint() with AtmosModel::En(). + * Replaced Isis::PI with PI since this is in Isis + * namespace. + */ + void Isotropic1::AtmosModelAlgorithm (double phase, double incidence, double emission) + { + double hpsq1; + double mu,munot; + double mup,munotp; + double xx; + double maxval; + double emu,emunot; + double xmu,xmunot; + double ymu,ymunot; + double fix; + double gmunot,gmu; + + if (p_atmosTau == 0.0) { + p_pstd = 0.0; + p_trans = 1.0; + p_trans0 = 1.0; + p_sbar = 0.0; + return; + } + + if (TauOrWhaChanged()) { + // preparation includes exponential integrals e sub 2 through 4 + p_wha2 = 0.5 * p_atmosWha; + p_e2 = AtmosModel::En(2,p_atmosTau); + p_e3 = AtmosModel::En(3,p_atmosTau); + p_e4 = AtmosModel::En(4,p_atmosTau); + + // zeroth moments of (uncorrected) x and y times characteristic fn + p_x0 = p_wha2; + p_y0 = p_wha2 * p_e2; + + // higher-order correction term for x and y + p_delta = (1.0 - (p_x0 + p_y0) - (1.0 - p_atmosWha) / (1.0 - (p_x0 - p_y0))) / (p_atmosWha * (0.5 - p_e3)); + + // moments of (corrected) x and y + p_alpha0 = 1.0 + p_delta * (0.5 - p_e3); + p_alpha1 = 0.5 + p_delta * ((1.0/3.0) - p_e4); + p_beta0 = p_e2 + p_delta * (0.5 - p_e3); + p_beta1 = p_e3 + p_delta * ((1.0/3.0) - p_e4); + + // prepare to find correct mixture of x and y in conservative case + if (p_atmosWha == 1.0) { + p_e5 = AtmosModel::En(5,p_atmosTau); + p_alpha2 = (1.0/3.0) + p_delta * (0.25 - p_e5); + p_beta2 = p_e4 + p_delta * (0.25 - p_e5); + p_fixcon = (p_beta0 * p_atmosTau - p_alpha1 + p_beta1) / ((p_alpha1 + p_beta1) * p_atmosTau + 2.0 * (p_alpha2 + p_beta2)); + } + + // gamma will be a weighted sum of x and y functions + p_gammax = p_wha2 * p_beta0; + p_gammay = 1.0 - p_wha2 * p_alpha0; + + // sbar is total diffuse illumination and comes from moments + p_sbar = 1.0 - ((2.0 - p_atmosWha * p_alpha0) * p_alpha1 + p_atmosWha * p_beta0 * p_beta1); + + SetOldTau(p_atmosTau); + SetOldWha(p_atmosWha); + } + + // correct the path lengths for planetary curvature + hpsq1 = pow((1.0+p_atmosHnorm),2.0) - 1.0; + munot = cos((PI/180.0)*incidence); + maxval = max(1.0e-30,hpsq1+munot*munot); + munotp = p_atmosHnorm / (sqrt(maxval) - munot); + munotp = max(munotp,p_atmosTau/69.0); + mu = cos((PI/180.0)*emission); + maxval = max(1.0e-30,hpsq1+mu*mu); + mup = p_atmosHnorm / (sqrt(maxval) - mu); + mup = max(mup,p_atmosTau/69.0); + + // build the x and y functions of mu0 and mu + maxval = max(1.0e-30,munotp); + xx = -p_atmosTau / maxval; + if (xx < -69.0) { + emunot = 0.0; + } + else if (xx > 69.0) { + emunot = 1.0e30; + } + else { + emunot = exp(-p_atmosTau/munotp); + } + + maxval = max(1.0e-30,mup); + xx = -p_atmosTau / maxval; + + if (xx < -69.0) { + emu = 0.0; + } + else if (xx > 69.0) { + emu = 1.0e30; + } + else { + emu = exp(-p_atmosTau/mup); + } + + xmunot = 1.0 + p_delta * munotp * (1.0 - emunot); + ymunot = emunot + p_delta * munotp * (1.0 - emunot); + xmu = 1.0 + p_delta * mup * (1.0 - emu); + ymu = emu + p_delta * mup * (1.0 - emu); + + // mix the x and y as required in the conservative case + if (p_atmosWha == 1.0) { + fix = p_fixcon * munotp * (xmunot + ymunot); + xmunot = xmunot + fix; + ymunot = ymunot + fix; + fix = p_fixcon * mup * (xmu + ymu); + xmu = xmu + fix; + ymu = ymu + fix; + } + + // gamma1 functions come from x and y + gmunot = p_gammax * xmunot + p_gammay * ymunot; + gmu = p_gammax * xmu + p_gammay * ymu; + + // purely atmos term uses x and y, xmitted surface term uses gammas + p_pstd = 0.25 * p_atmosWha * munotp / (munotp + mup) * (xmunot * xmu - ymunot * ymu); + p_trans = gmunot * gmu; + + // finally, never-scattered term is given by pure attenuation + p_trans0 = emunot * emu; + } + + /** + * Set the Atmospheric function parameter. This is the + * atmospheric shell thickness normalized to the planet radius + * and is used to modify angles to get more accurate path + * lengths near the terminator (ratio of scale height to the + * planetary radius). This parameter is limited to values that + * are >=0. + * + * @param hnorm Atmospheric function parameter, default is 0.003 + */ + void Isotropic1::SetAtmosHnorm (const double hnorm) { + if (hnorm < 0.0) { + std::string msg = "Invalid value of Atmospheric hnorm [" + iString(hnorm) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_atmosHnorm = hnorm; + } +} + +extern "C" Isis::AtmosModel *Isotropic1Plugin (Isis::Pvl &pvl, + Isis::PhotoModel &pmodel) { + return new Isis::Isotropic1(pvl,pmodel); +} diff --git a/isis/src/base/objs/Isotropic1/Isotropic1.h b/isis/src/base/objs/Isotropic1/Isotropic1.h new file mode 100644 index 0000000000000000000000000000000000000000..076fac0f72b0b16f60b447c885295106859a2c2a --- /dev/null +++ b/isis/src/base/objs/Isotropic1/Isotropic1.h @@ -0,0 +1,75 @@ +#ifndef Isotropic1_h +#define Isotropic1_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/11/05 23:37:09 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "AtmosModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief + * + * @ingroup RadiometricAndPhotometricCorrection + * @author 1998-12-21 Randy Kirk + * + * @internal + * @history 1998-12-21 Randy Kirk - USGS, Flagstaff - Original + * code + * @history 2007-02-20 Janet Barrett - Imported from Isis2. + * @history 2007-08-15 Steven Lambright - Refactored code + * @history 2008-03-07 Janet Barrett - Moved code to set standard + * conditions to the AtmosModel class + * @history 2008-06-18 Stuart Sides - Fixed doc error + * @history 2008-11-05 Jeannie Walldren - Replaced reference to + * NumericalMethods::r8expint() with AtmosModel::En(). + * Added documentation from Isis2. + */ + class Isotropic1 : public AtmosModel { + public: + Isotropic1 (Pvl &pvl, PhotoModel &pmodel); + virtual ~Isotropic1() {}; + + //! Return atmospheric Hnorm value + inline double AtmosHnorm () const { return p_atmosHnorm; }; + + protected: + virtual void AtmosModelAlgorithm (double phase, double incidence, double emission); + + private: + void SetAtmosHnorm(const double hnorm); + + double p_atmosHnorm; + double p_wha2; + double p_delta; + double p_fixcon; + double p_gammax,p_gammay; + double p_e2,p_e3,p_e4,p_e5; + double p_x0,p_y0; + double p_alpha0,p_alpha1,p_alpha2; + double p_beta0,p_beta1,p_beta2; + }; +}; + +#endif diff --git a/isis/src/base/objs/Isotropic1/Isotropic1.truth b/isis/src/base/objs/Isotropic1/Isotropic1.truth new file mode 100644 index 0000000000000000000000000000000000000000..0ee0f5c6b5cd2c074fe8e74640582bd6e2a705f7 --- /dev/null +++ b/isis/src/base/objs/Isotropic1/Isotropic1.truth @@ -0,0 +1,33 @@ +UNIT TEST for Isotropic1 atmospheric function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = AtmosphericModel + Group = Algorithm + Name = Isotropic1 + End_Group +End_Object +End + +Test phase=0.0, incidence=0.0, emission=0.0 (standard conditions) ... +Pstd = 0 +Trans = 1 +Trans0 = 1 +Sbar = 0 + +Test phase=86.7226722, incidence=51.7002388, emission=38.9414439 ... +Pstd = 0.0788489 +Trans = 0.703373 +Trans0 = 0.444706 +Sbar = 0.165084 + +Test phase=180.0, incidence=90.0, emission=90.0 ... +Pstd = 0.130281 +Trans = 0.1462 +Trans0 = 5.19719e-07 +Sbar = 0.165084 + diff --git a/isis/src/base/objs/Isotropic1/Makefile b/isis/src/base/objs/Isotropic1/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7bb111ed9395dddd2cc7f62316de3b840386ce13 --- /dev/null +++ b/isis/src/base/objs/Isotropic1/Makefile @@ -0,0 +1,5 @@ +INCS = Isotropic1.h +SRCS = Isotropic1.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Isotropic1/unitTest.cpp b/isis/src/base/objs/Isotropic1/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e47182562cea1a805ca33b19aac415c807588a82 --- /dev/null +++ b/isis/src/base/objs/Isotropic1/unitTest.cpp @@ -0,0 +1,76 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "Isotropic1.h" +#include "AtmosModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + double pstd; + double trans; + double trans0; + double sbar; + Isis::Preference::Preferences(true); + + std::cout << "UNIT TEST for Isotropic1 atmospheric function" << + std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup alga("Algorithm"); + alga += PvlKeyword("Name","Isotropic1"); + + PvlObject oa("AtmosphericModel"); + oa.AddGroup(alga); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(oa); + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + Isotropic1 *am = (Isotropic1*)AtmosModelFactory::Create(pvl,*pm); + + am->SetStandardConditions(true); + am->CalcAtmEffect(0.0,0.0,0.0,&pstd,&trans,&trans0,&sbar); + am->SetStandardConditions(false); + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 (standard conditions) ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + + am->CalcAtmEffect(86.7226722,51.7002388,38.9414439,&pstd,&trans,&trans0,&sbar); + + std::cout << "Test phase=86.7226722, incidence=51.7002388, emission=38.9414439 ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + + am->CalcAtmEffect(180.0,90.0,90.0,&pstd,&trans,&trans0,&sbar); + + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/Isotropic2/AtmosModel.plugin b/isis/src/base/objs/Isotropic2/AtmosModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..24efaa905d196acbe031693cb93e62692c92e6d0 --- /dev/null +++ b/isis/src/base/objs/Isotropic2/AtmosModel.plugin @@ -0,0 +1,4 @@ +Group = Isotropic2 + Library = Isotropic2 + Routine = Isotropic2Plugin +End_Group diff --git a/isis/src/base/objs/Isotropic2/Isotropic2.cpp b/isis/src/base/objs/Isotropic2/Isotropic2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d1445201b007befb02bd1598597d12943e1c3b6 --- /dev/null +++ b/isis/src/base/objs/Isotropic2/Isotropic2.cpp @@ -0,0 +1,275 @@ +#include +#include "AtmosModel.h" +#include "Isotropic2.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "iString.h" + +using std::min; +using std::max; + +namespace Isis { + Isotropic2::Isotropic2 (Pvl &pvl, PhotoModel &pmodel) : AtmosModel(pvl,pmodel) { + PvlGroup &algorithm = pvl.FindObject("AtmosphericModel").FindGroup("Algorithm",Pvl::Traverse); + SetAtmosHnorm(0.003); + + if (algorithm.HasKeyword("Hnorm")) { + SetAtmosHnorm(algorithm["Hnorm"]); + } + } + + /** + * Isotropic atmospheric scattering in the first approximation + * The model for scattering for a general, non-Lambertian surface with + * an atmosphere looks like this: + * + * P = Pstd + trans*(rho*Ah*munot)/(1.d0-rho*Ab*sbar) + * trans0*rho*(psurf-Ah*munot) + * + * where P is the overall photometric function (the model of the data), + * PSTD is the pure atmospheric-scattering term, PSURF is the surface + * photometric function, AH*MUNOT is a Lambertian approximation to this + * with hemispheric albedo AH, TRANS and TRANS0 quantify transmission + * of surface reflected light through the atmosphere overall and with + * no scatterings in the atmosphere, and finally SBAR quantifies the + * illumination of the ground by the sky. RHO is the ratio of the sur- + * face albedo to the albedo assumed in the functional form of PSURF. + * + * @param phase Value of the phase angle. + * @param incidence Value of the incidence angle. + * @param emission Value of the emission angle. + * + * @history 1998-12-21 Randy Kirk, USGS, Flagstaff - Original + * code + * @history 1999-03-12 K Teal Thompson Port to Unix/ISIS; + * declare vars; add implicit none. + * @history 2007-02-20 Janet Barrett - Imported from Isis2 + * pht_atm_functions to Isis3. + * @history 2008-11-05 Jeannie Walldren - Replaced reference to + * NumericalMethods::r8expint() with AtmosModel::En(), + * NumericalMethods::G11Prime() with + * AtmosModel::G11Prime(), and NumericalMethods::r8ei() + * with AtmosModel::Ei(). Replaced Isis::PI with PI + * since this is in Isis namespace. + * + */ + + void Isotropic2::AtmosModelAlgorithm (double phase, double incidence, + double emission) + { + double xx; + double fix; + double hpsq1; + double munot,munotp; + double mu,mup; + double emu,emunot; + double f1munot,f1mmunot,f1mmu,f1mu; + double xmunot,ymunot; + double xmu,ymu; + double gmu,gmunot; + double maxval; + + if (p_atmosTau == 0.0) { + p_pstd = 0.0; + p_trans = 1.0; + p_trans0 = 1.0; + p_sbar = 0.0; + return; + } + + if (TauOrWhaChanged()) { + // preparation includes exponential integrals p_e sub 2 through 4 + p_wha2 = 0.5 * p_atmosWha; + p_e1 = AtmosModel::En(1,p_atmosTau); + p_e1_2 = AtmosModel::En(1,2.0*p_atmosTau); + p_e2 = AtmosModel::En(2,p_atmosTau); + p_e3 = AtmosModel::En(3,p_atmosTau); + p_e4 = AtmosModel::En(4,p_atmosTau); + + // chandra's gmn functions require fm and fn at mu=-1 + xx = -p_atmosTau; + if (xx < -69.0) { + p_em = 0.0; + } else if (xx > 69.0) { + p_em = 1.0e30; + } else { + p_em = exp(xx); + } + p_f1m = log(2.0) - p_em * p_e1 + p_e1_2; + p_f2m = -1.0 * (p_f1m + p_em * p_e2 - 1.0); + p_f3m = -1.0 * (p_f2m + p_em * p_e3 - 0.5); + p_g12 = (p_atmosTau * p_e1 * p_e2 + p_f1m + p_f2m) * 0.5; + p_g13 = (p_atmosTau * p_e1 * p_e3 + p_f1m + p_f3m) * (1.0/3.0); + + // chandra's g'mn functions require g'11 and f at mu=1 + xx = p_atmosTau; + if (xx < -69.0) { + p_e = 0.0; + } + else if (xx > 69.0) { + p_e = 1.0e30; + } + else { + p_e = exp(xx); + } + + p_f1 = Eulgam() + log(p_atmosTau) + p_e * p_e1; + p_f2 = p_f1 + p_e * p_e2 - 1.0; + p_f3 = p_f2 + p_e * p_e3 - 0.5; + p_g11p = AtmosModel::G11Prime(p_atmosTau); + p_g12p = (p_atmosTau * (p_e1 - p_g11p) + p_em * (p_f1 + p_f2)) * 0.25; + p_g13p = (p_atmosTau * (0.5 * p_e1 - p_g12p) + p_em * (p_f1 + p_f3)) * 0.2; + + // zeroth moments of (uncorrected) x and y times characteristic fn + p_x0 = p_wha2 * (1.0 + p_wha2 * p_g12); + p_y0 = p_wha2 * (p_e2 + p_wha2 * p_g12p); + + // higher-order correction term for x and y + p_delta = (1.0 - (p_x0 + p_y0) - (1.0 - p_atmosWha) / (1.0 - (p_x0 - p_y0))) / (p_atmosWha * (0.5 - p_e3)); + + // moments of (corrected) x and y + p_alpha0 = 1.0 + p_wha2 * p_g12 + p_delta * (0.5 - p_e3); + p_alpha1 = 0.5 + p_wha2 * p_g13 + p_delta * ((1.0/3.0) - p_e4); + p_beta0 = p_e2 + p_wha2 * p_g12p + p_delta * (0.5 - p_e3); + p_beta1 = p_e3 + p_wha2 * p_g13p + p_delta * ((1.0/3.0) - p_e4); + + // prepare to find correct mixture of x and y in conservative case + if (p_atmosWha == 1.0) { + p_e5 = AtmosModel::En(5,p_atmosTau); + p_f4m = -1.0 * (p_f3m + p_em * p_e4 - (1.0/3.0)); + p_g14 = (p_atmosTau * p_e1 * p_e4 + p_f1m + p_f4m) * 0.25; + p_f4 = p_f3 + p_e * p_e4 - (1.0/3.0); + p_g14p = (p_atmosTau * (0.5 * p_e1 - p_g13p) + p_em * (p_f1 + p_f4)) * (1.0/6.0); + p_alpha2 = (1.0/3.0) + p_wha2 * p_g14 + p_delta * (0.25 - p_e5); + p_beta2 = p_e4 + p_wha2 * p_g14p + p_delta * (0.25 - p_e5); + p_fixcon = (p_beta0 * p_atmosTau - p_alpha1 + p_beta1) / ((p_alpha1 + p_beta1) * p_atmosTau + 2.0 * (p_alpha2 + p_beta2)); + } + + // gamma will be a weighted sum of x and y functions + p_gammax = p_wha2 * p_beta0; + p_gammay = 1.0 - p_wha2 * p_alpha0; + + // sbar is total diffuse illumination and comes from moments + p_sbar = 1.0 - ((2.0 - p_atmosWha * p_alpha0) * p_alpha1 + p_atmosWha * p_beta0 * p_beta1); + + SetOldTau(p_atmosTau); + SetOldWha(p_atmosWha); + } + + // correct the path lengths for planetary curvature + hpsq1 = pow((1.0+p_atmosHnorm),2.0) - 1.0; + munot = cos((PI/180.0)*incidence); + maxval = max(1.0e-30,hpsq1+munot*munot); + munotp = p_atmosHnorm / (sqrt(maxval) - munot); + munotp = max(munotp,p_atmosTau/69.0); + mu = cos((PI/180.0)*emission); + maxval = max(1.0e-30,hpsq1+mu*mu); + mup = p_atmosHnorm / (sqrt(maxval) - mu); + mup = max(mup,p_atmosTau/69.0); + + // build the x and y functions of mu0 and mu + xx = -p_atmosTau / max(munotp,1.0e-30); + if (xx < -69.0) { + emunot = 0.0; + } + else if (xx > 69.0) { + emunot = 1.0e30; + } + else { + emunot = exp(-p_atmosTau/munotp); + } + + xx = -p_atmosTau / max(mup,1.0e-30); + if (xx < -69.0) { + emu = 0.0; + } + else if (xx > 69.0) { + emu = 1.0e30; + } + else { + emu = exp(-p_atmosTau/mup); + } + + // in the second approximation the x and y include the p_f1 function + xx = munotp; + if (fabs(xx-1.0) < 1.0e-10) { + f1munot = p_f1; + f1mmunot = xx * (log(1.0+1.0/xx) - p_e1 * emunot + + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); + } + else if (xx > 0.0) { + f1munot = xx * (log(xx/(1.0-xx)) + p_e1 / emunot + + AtmosModel::Ei(p_atmosTau*(1.0/xx-1.0))); + f1mmunot = xx * (log(1.0+1.0/xx) - p_e1 * emunot + + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); + } + else { + std::string msg = "Negative length of planetary curvature "; + msg += "encountered"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + + xx = mup; + if (fabs(xx-1.0) < 1.0e-10) { + f1mu = p_f1; + f1mmu = xx * (log(1.0+1.0/xx) - p_e1 * emu + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); + } + else if (xx > 0.0) { + f1mu = xx * (log(xx/(1.0-xx)) + p_e1 / emu + AtmosModel::Ei(p_atmosTau*(1.0/xx-1.0))); + f1mmu = xx * (log(1.0+1.0/xx) - p_e1 * emu + AtmosModel::En(1,p_atmosTau*(1.0+1.0/xx))); + } + else { + std::string msg = "Negative length of planetary curvature encountered"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + + xmunot = 1.0 + p_wha2 * f1mmunot + p_delta * munotp * (1.0 - emunot); + ymunot = emunot * (1.0 + p_wha2 * f1munot) + p_delta * munotp * (1.0 - emunot); + xmu = 1.0 + p_wha2 * f1mmu + p_delta * mup * (1.0 - emu); + ymu = emu * (1.0 + p_wha2 * f1mu) + p_delta * mup * (1.0 - emu); + + // mix the x and y as required in the conservative case + if (p_atmosWha == 1.0) { + fix = p_fixcon * munotp * (xmunot + ymunot); + xmunot = xmunot + fix; + ymunot = ymunot + fix; + fix = p_fixcon * mup * (xmu + ymu); + xmu = xmu + fix; + ymu = ymu + fix; + } + + // gamma1 functions come from x and y + gmunot = p_gammax * xmunot + p_gammay * ymunot; + gmu = p_gammax * xmu + p_gammay * ymu; + + // purely atmos term uses x and y, xmitted surface term uses gammas + p_pstd = 0.25 * p_atmosWha * munotp / (munotp + mup) * (xmunot * xmu - ymunot * ymu); + p_trans = gmunot * gmu; + + // finally, never-scattered term is given by pure attenuation + p_trans0 = emunot * emu; + } + + /** + * Set the Atmospheric function parameter. This is the + * atmospheric shell thickness normalized to the planet radius + * and is used to modify angles to get more accurate path + * lengths near the terminator (ratio of scale height to the + * planetary radius). This parameter is limited to values that + * are >=0. + * + * @param hnorm Atmospheric function parameter, default is 0.003 + */ + void Isotropic2::SetAtmosHnorm (const double hnorm) { + if (hnorm < 0.0) { + std::string msg = "Invalid value of Atmospheric hnorm [" + iString(hnorm) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_atmosHnorm = hnorm; + } +} + +extern "C" Isis::AtmosModel *Isotropic2Plugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel) { + return new Isis::Isotropic2(pvl,pmodel); +} diff --git a/isis/src/base/objs/Isotropic2/Isotropic2.h b/isis/src/base/objs/Isotropic2/Isotropic2.h new file mode 100644 index 0000000000000000000000000000000000000000..fef5307e920936a2fb449b1c9fb6fe64d5b05fb7 --- /dev/null +++ b/isis/src/base/objs/Isotropic2/Isotropic2.h @@ -0,0 +1,83 @@ +#ifndef Isotropic2_h +#define Isotropic2_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/11/05 23:37:17 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "AtmosModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief + * @ingroup RadiometricAndPhotometricCorrection + * @author 1998-12-21 Randy Kirk + * + * @internal + * @history 1998-12-21 Randy Kirk - USGS, Flagstaff - Original + * code + * @history 2007-02-20 Janet Barrett - Imported from Isis2. + * @history 2007-08-15 Steven Lambright - Refactored code + * @history 2008-03-07 Janet Barrett - Moved code to set standard + * conditions to the AtmosModel class + * @history 2008-06-18 Stuart Sides - Fixed doc error + * @history 2008-11-05 Jeannie Walldren - Replaced reference to + * NumericalMethods::r8expint() with AtmosModel::En(), + * NumericalMethods::G11Prime() with + * AtmosModel::G11Prime(), and NumericalMethods::r8ei() + * with AtmosModel::Ei(). Added documentation from + * Isis2. + */ + class Isotropic2 : public AtmosModel { + public: + Isotropic2 (Pvl &pvl, PhotoModel &pmodel); + virtual ~Isotropic2() {}; + + //! Return atmospheric Hnorm value + double AtmosHnorm () const { return p_atmosHnorm; }; + + protected: + virtual void AtmosModelAlgorithm (double phase, double incidence, double emission); + + private: + void SetAtmosHnorm(const double hnorm); + + double p_atmosHnorm; + double p_delta; + double p_fixcon; + double p_gammax,p_gammay; + double p_wha2; + double p_e1,p_e1_2,p_e2,p_e3,p_e4,p_e5; + double p_em; + double p_f1m,p_f2m,p_f3m,p_f4m; + double p_g12,p_g13,p_g14; + double p_e; + double p_f1,p_f2,p_f3,p_f4; + double p_g11p,p_g12p,p_g13p,p_g14p; + double p_x0,p_y0; + double p_alpha0,p_alpha1,p_alpha2; + double p_beta0,p_beta1,p_beta2; + }; +}; + +#endif diff --git a/isis/src/base/objs/Isotropic2/Isotropic2.truth b/isis/src/base/objs/Isotropic2/Isotropic2.truth new file mode 100644 index 0000000000000000000000000000000000000000..c6e6bc1af1e45befae5fbf7b1b9626e318021a53 --- /dev/null +++ b/isis/src/base/objs/Isotropic2/Isotropic2.truth @@ -0,0 +1,33 @@ +UNIT TEST for Isotropic2 atmospheric function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = AtmosphericModel + Group = Algorithm + Name = Isotropic2 + End_Group +End_Object +End + +Test phase=0.0, incidence=0.0, emission=0.0 (standard conditions) ... +Pstd = 0 +Trans = 1 +Trans0 = 1 +Sbar = 0 + +Test phase=86.7226722, incidence=51.7002388, emission=38.9414439 ... +Pstd = 0.0865225 +Trans = 0.654112 +Trans0 = 0.444706 +Sbar = 0.211278 + +Test phase=180.0, incidence=90.0, emission=90.0 ... +Pstd = 0.138797 +Trans = 0.12999 +Trans0 = 5.19719e-07 +Sbar = 0.211278 + diff --git a/isis/src/base/objs/Isotropic2/Makefile b/isis/src/base/objs/Isotropic2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..aa5b485043cfac4417278df2fea1f08c493d7f99 --- /dev/null +++ b/isis/src/base/objs/Isotropic2/Makefile @@ -0,0 +1,5 @@ +INCS = Isotropic2.h +SRCS = Isotropic2.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Isotropic2/unitTest.cpp b/isis/src/base/objs/Isotropic2/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b576f121fa8ad0b70db91967957ad28b1bde366d --- /dev/null +++ b/isis/src/base/objs/Isotropic2/unitTest.cpp @@ -0,0 +1,75 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "AtmosModel.h" +#include "AtmosModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + double pstd; + double trans; + double trans0; + double sbar; + Isis::Preference::Preferences(true); + + std::cout << "UNIT TEST for Isotropic2 atmospheric function" << std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup alga("Algorithm"); + alga += PvlKeyword("Name","Isotropic2"); + + PvlObject oa("AtmosphericModel"); + oa.AddGroup(alga); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(oa); + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + AtmosModel *am = AtmosModelFactory::Create(pvl,*pm); + + am->SetStandardConditions(true); + am->CalcAtmEffect(0.0,0.0,0.0,&pstd,&trans,&trans0,&sbar); + am->SetStandardConditions(false); + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 (standard conditions) ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + + am->CalcAtmEffect(86.7226722,51.7002388,38.9414439,&pstd,&trans,&trans0,&sbar); + + std::cout << "Test phase=86.7226722, incidence=51.7002388, emission=38.9414439 ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + + am->CalcAtmEffect(180.0,90.0,90.0,&pstd,&trans,&trans0,&sbar); + + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << std::endl; + std::cout << "Pstd = " << pstd << std::endl; + std::cout << "Trans = " << trans << std::endl; + std::cout << "Trans0 = " << trans0 << std::endl; + std::cout << "Sbar = " << sbar << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/JP2Decoder/JP2Decoder.cpp b/isis/src/base/objs/JP2Decoder/JP2Decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..edcb8ca1e40b257e70b1cfca92b0fc293a90d3ce --- /dev/null +++ b/isis/src/base/objs/JP2Decoder/JP2Decoder.cpp @@ -0,0 +1,230 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/02/22 02:14:26 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include + +#include "iException.h" +#include "iString.h" +#include "JP2Decoder.h" +#include "JP2Error.h" + +using namespace std; +namespace Isis { + + /** + * Constructs a JPEG2000 decoder object + * + * @param jp2file The name of the JP2 file that needs to be decoded. + * + */ + JP2Decoder::JP2Decoder (const std::string &jp2file) { + +#if ENABLEJP2K + p_jp2File = jp2file; + p_resolutionLevel = 1; + JP2_Source = NULL; + + // Register the Kakadu error handler + Kakadu_Error = new JP2Error; + kdu_customize_errors(Kakadu_Error); +#else + std::string msg = "JPEG2000 has not been enabled with this build of ISIS3"; + throw iException::Message(iException::System,msg,_FILEINFO_); +#endif + } + + /** + * Open the JPEG2000 file + * + */ + void JP2Decoder::OpenFile () { +#if ENABLEJP2K + // Make sure file isn't already open + if (JP2_Source == NULL) { + + // Open the JP2 file stream + JP2_Stream = new jp2_family_src(); + JP2_Stream->open(p_jp2File.c_str()); + + // Open the JP2 source + JP2_Source = new jp2_source(); + if (!JP2_Source->open(JP2_Stream)) { + std::string msg = "Unable to open the decoder because the source file "; + msg += "does not have valid JP2 format content [" + p_jp2File + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Initialize the JP2 header boxes up to the first codestream box + JP2_Source->read_header(); + + // Open the JP2 codestream + JPEG2000_Codestream = new kdu_codestream(); + JPEG2000_Codestream->create(JP2_Source); + + // Get the image characteristics + // Number of components (bands) + p_numBands = JPEG2000_Codestream->get_num_components(true); + + // Image dimensions (sample offset, line offset, number of samples, + // number of lines) at full resolution + JPEG2000_Codestream->get_dims(0,p_imageDims,true); //dims.pos.x, dims.size.x + + // Pixel data structure + p_pixelBits = JPEG2000_Codestream->get_bit_depth(0,true); + p_pixelBytes = (p_pixelBits >> 3) + ((p_pixelBits % 8) ? 1 : 0); + if (p_pixelBytes == 3) p_pixelBytes = 4; + if (p_pixelBits > 16 || p_pixelBytes > 2) { + std::string msg = "The source file has unsupported pixel type "; + msg += "[" + p_jp2File + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_signedData = JPEG2000_Codestream->get_signed(0,true); + + // Check all bands in the JP2 file to make sure they all have the same + // dimensions, bit depth, and signedness + kdu_dims dims; + unsigned int pixel_bits; + bool signed_data; + for (unsigned int band=1; bandget_dims(band,dims,true); + pixel_bits = JPEG2000_Codestream->get_bit_depth(band,true); + signed_data = JPEG2000_Codestream->get_signed(band,true); + if (dims.size.x != p_imageDims.size.x || dims.size.y != p_imageDims.size.y || + dims.pos.x != p_imageDims.pos.x || dims.pos.y != p_imageDims.pos.y || + pixel_bits != p_pixelBits || signed_data != p_signedData) { + std::string msg = "The source file does not have bands with matching "; + msg += "characteristics"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + // Get the total available resolution levels and set the effective + // resolution and image region + p_highestResLevel = JPEG2000_Codestream->get_min_dwt_levels() + 1; + SetResolutionAndRegion(); + + // Initialize the JP2 decoder + // Initialize the codestream stripe decompressor + p_decompressor.start(*JPEG2000_Codestream); + + // Determine optimum stripe heights for accessing data - the + // optimum stripe heights are ignored. We are instead reading + // the file a line at a time. + p_stripeHeights = new int[p_numBands]; + p_maxStripeHeights = new int[p_numBands]; + p_precisions = new int[p_numBands]; + p_isSigned = new bool[p_numBands]; + p_decompressor.get_recommended_stripe_heights(MIN_STRIPE_HEIGHT, + MAX_STRIPE_HEIGHT,p_stripeHeights,p_maxStripeHeights); + for (unsigned int i=0; iapply_input_restrictions(0,0,p_resolutionLevel-1,0,NULL, + KDU_WANT_OUTPUT_COMPONENTS); + + JPEG2000_Codestream->get_dims(0,p_imageDims,true); + p_numSamples = p_imageDims.size.x; + p_numLines = p_imageDims.size.y; +#endif + } + + /** + * Read data from JP2 file containing 8-bit data + * + * @param inbuf The array of pointers to byte buffers that will be used to read + * in the image data. One byte buffer is required for each band in + * the image. Kakadu reads in a BIL manner. It is up to the calling + * routine to do the casting necessary to convert the byte data to + * the actual pixel type (UnsignedByte, UnsignedWord, SignedWord). + * + */ + void JP2Decoder::Read (unsigned char **inbuf) { +#if ENABLEJP2K + p_readStripes = p_decompressor.pull_stripe(inbuf,p_stripeHeights,NULL,NULL, + p_precisions); +#endif + } + + /** + * Read data from JP2 file containing 16-bit data + * + * @param inbuf The array of pointers to byte buffers that will be used to read + * in the image data. One byte buffer is required for each band in + * the image. Kakadu reads in a BIL manner. It is up to the calling + * routine to do the casting necessary to convert the byte data to + * the actual pixel type (UnsignedByte, UnsignedWord, SignedWord). + * + */ + void JP2Decoder::Read (short int **inbuf) { +#if ENABLEJP2K + p_readStripes = p_decompressor.pull_stripe(inbuf,p_stripeHeights,NULL,NULL, + p_precisions,p_isSigned); +#endif + } + + /** + * JP2Decoder destructor + * + */ + JP2Decoder::~JP2Decoder () { +#if ENABLEJP2K + if (JPEG2000_Codestream) JPEG2000_Codestream->destroy(); + JPEG2000_Codestream = NULL; + if (JP2_Source) { + JP2_Source->close(); + delete JP2_Source; + } + JP2_Source = NULL; + if (JP2_Stream) { + JP2_Stream->close(); + delete JP2_Stream; + } + JP2_Stream = NULL; + p_decompressor.finish(); + if (Kakadu_Error) { + delete Kakadu_Error; + } + delete [] p_stripeHeights; + delete [] p_maxStripeHeights; + delete [] p_precisions; + delete [] p_isSigned; +#endif + } +} diff --git a/isis/src/base/objs/JP2Decoder/JP2Decoder.h b/isis/src/base/objs/JP2Decoder/JP2Decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..48b673eb49e5cab363c82500a792ed7f36ba97b0 --- /dev/null +++ b/isis/src/base/objs/JP2Decoder/JP2Decoder.h @@ -0,0 +1,157 @@ +#ifndef JP2Decoder_h +#define JP2Decoder_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/02/22 02:15:24 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#if ENABLEJP2K +#include "jp2.h" +#include "kdu_stripe_decompressor.h" +#endif + +#define MIN_STRIPE_HEIGHT 256 +#define MAX_STRIPE_HEIGHT 8192 + +namespace Isis { +/** + * @brief JPEG2000 decoder class + * + * This class is used to decode a JPEG2000 image. + * + * Here is an example of how to use JP2Decoder + * @code + * JP2Decoder *JP2_decoder; + * JP2_decoder = new JP2Decoder(iString(ui.GetFilename("FROM"))); + * JP2_decoder->OpenFile(); + * int nsamps = JP2_decoder->GetSampleDimension(); + * int nlines = JP2_decoder->GetLineDimension(); + * int nbands = JP2_decoder->GetBandDimension(); + * int pixelbytes = JP2_decoder->GetPixelBytes(); + * bool is_signed = JP2_decoder->GetSignedData(); + * delete JP2_decoder; + * ProcessImport jp; + * jp.SetDimensions(nsamps,nlines,nbands); + * if (pixelbytes == 1) { + * jp.SetPixelType(Isis::UnsignedByte); + * } else if (pixelbytes == 2) { + * if (is_signed) { + * jp.SetPixelType(Isis::SignedWord); + * } else { + * jp.SetPixelType(Isis::UnsignedWord); + * } + * } else { + * throw iException::Message(iException::User, + * "The file [" + ui.GetFilename("FROM") + "] contains unsupported data type.", + * _FILEINFO_); + * } + * jp.SetInputFile(iString(ui.GetFilename("FROM"))); + * jp.SetOutputCube("TO"); + * jp.SetOrganization(ProcessImport::JP2); + * jp.StartProcess(); + * jp.EndProcess(); + * @endcode + * + * If you would like to see JP2Decoder being used in implementation, + * see std2isis.cpp or for a class that implements JP2Decoder, + * see ProcessImport + * + * @ingroup HighLevelCubeIO + * + * @author 2009-12-18 Janet Barrett + * + * @internal + * @history 2009-12-18 Janet Barrett - Original version. + * + */ + +class JP2Error; +class JP2Decoder { + public: + JP2Decoder (const std::string &jp2file); + ~JP2Decoder (); + + // Register with the Kakadu error facility + JP2Error *kakadu_error () const {return Kakadu_Error;}; + + // Open and initialize the JP2 file for reading + void OpenFile (); + + // Get the sample dimension of the JP2 file + inline int GetSampleDimension() const { return ((int) p_numSamples); } + + // Get the line dimension of the JP2 file + inline int GetLineDimension() const { return ((int) p_numLines); } + + // Get the band dimension of the JP2 file + inline int GetBandDimension() const { return ((int) p_numBands); } + + // Get number of bytes per pixel in the JP2 file + inline int GetPixelBytes() const { return (p_pixelBytes); } + + // Determine if data in JP2 file is signed + inline bool GetSignedData() const { return (p_signedData); } + + // Read byte data from the JP2 file + void Read (unsigned char **inbuf); + + // Read 16-bit data from the JP2 file + void Read (short int **inbuf); + + private: + std::string p_jp2File; //! +#include "Preference.h" + +using namespace std; + +int main(){ + Isis::Preference::Preferences(true); + + cout << "Testing Isis::JP2Decoder ..." < +#include +#include +#include + +#include "iException.h" +#include "iString.h" +#include "JP2Encoder.h" +#include "JP2Error.h" + +using namespace std; +namespace Isis { + + /** + * Constructs a JPEG2000 encoder object + * + * @param jp2file Name of file where the encoded JP2 data will be stored. + * @param nsamps Sample dimension of image that will be encoded. + * @param nlines Line dimension of image that will be encoded. + * @param nbands Band dimension of image that will be encoded. + * @param type Pixel type of data that will be encoded. + * + */ + JP2Encoder::JP2Encoder (const std::string &jp2file, const unsigned int nsamps, + const unsigned int nlines, const unsigned int nbands, + const Isis::PixelType type) { + +#if ENABLEJP2K + p_jp2File = jp2file; + p_sampleDimension = nsamps; + p_lineDimension = nlines; + p_bandDimension = nbands; + + if (p_sampleDimension == 0 || p_lineDimension == 0 || p_bandDimension == 0) { + string msg = "Invalid sample/line/band dimensions specified for output file"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (type == Isis::SignedWord) { + p_signedData = true; + p_pixelBits = 16; + p_pixelBytes = 2; + } else if (type == Isis::UnsignedWord) { + p_signedData = false; + p_pixelBits = 16; + p_pixelBytes = 2; + } else if (type == Isis::UnsignedByte) { + p_signedData = false; + p_pixelBits = 8; + p_pixelBytes = 1; + } else { + string msg = "Invalid pixel type specified for output file"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Determine number of resolution levels. The sample/line dimension at the + // smallest resolution must not be smaller than 64. The number of resolution + // levels must not exceed 32. + p_resolutionLevels = 1; + int mindim = + (p_sampleDimension > p_lineDimension) ? p_lineDimension : p_sampleDimension; + while (mindim > 64 && p_resolutionLevels < 32) { + ++p_resolutionLevels; + mindim >>= 1; + } + + // Precinct size will be set to 256 for all resolution levels + p_precinctSize.resize(p_resolutionLevels,256); + + // The progression order, code block size, and tile size are all set to + // values that allow incremental flushing to work. Incremental flushing + // prevents us from having to store the entire compressed codestream in + // memory before writing it to disk. + p_progressionOrder = "PCRL"; + p_codeBlockSize = 64; + p_tileSizeWidth = p_sampleDimension; // untiled - size of image + p_tileSizeHeight = p_lineDimension; + + // Register the Kakadu error handler + Kakadu_Error = new JP2Error; + kdu_customize_errors(Kakadu_Error); +#else + std::string msg = "JPEG2000 has not been enabled with this build of ISIS3"; + throw iException::Message(iException::System,msg,_FILEINFO_); +#endif + } + + + /** + * Open the JPEG2000 file and initialize it + * + */ + void JP2Encoder::OpenFile () { +#if ENABLEJP2K + // Open the JP2 file stream + JP2_Stream = new jp2_family_tgt(); + JP2_Stream->open(p_jp2File.c_str()); + + // Open the JP2 boxes + JP2_Boxes = new jp2_target(); + JP2_Boxes->open(JP2_Stream); + + // Configure and write all required JP2 boxes up to, but not including, + // the JPEG2000 codestream (jp2c) box. This includes the Signature, + // File_Type, and JP2_Header boxes with the latter including the + // Image_Header and Colour_Specification subboxes. + + // Set the codestream SIZ parameters - this includes the image data + // organization, resolution levels, reversible (lossless) discrete + // wavelet transform, and encoding progression order. + siz_params *codestream_parameters = new siz_params(); + codestream_parameters->set(Sdims,0,0,(int)p_lineDimension); + codestream_parameters->set(Sdims,0,1,(int)p_sampleDimension); + codestream_parameters->set(Sprecision,0,0,(int)p_pixelBits); + codestream_parameters->set(Stiles,0,0,(int)p_tileSizeHeight); + codestream_parameters->set(Stiles,0,1,(int)p_tileSizeWidth); + codestream_parameters->set(Ssigned,0,0,p_signedData); + codestream_parameters->set(Scomponents,0,0,(int)p_bandDimension); + ostringstream levels; + levels << "Clevels=" << (p_resolutionLevels - 1); + codestream_parameters->parse_string(levels.str().c_str()); + codestream_parameters->parse_string("Creversible=yes"); + string progression = "Corder=" + p_progressionOrder; + codestream_parameters->parse_string(progression.c_str()); + + // Determine the number of tile length marker segments. This is + // necessary if incremental flushing of the codestream is to be + // employed. Incremental flushing prevents the software from + // having to store the entire codestream in memory before writing + // it to disk. The number of tile length marker segments is + // estimated by dividing the tile height by the number of lines + // requested for incremental flushing rounded up to the next whole + // number. + int TLM_segments; + int p_flushLines = 0; + long long line_bytes = (long long)p_sampleDimension * p_pixelBytes; + if (INCREMENTAL_FLUSH_BYTES < (p_lineDimension * line_bytes)) { + p_flushLines = p_tileSizeHeight; + while ((p_flushLines * line_bytes) > INCREMENTAL_FLUSH_BYTES) { + p_flushLines -= 1024; + if (p_flushLines < 0) p_flushLines = 0; + } + } + if (p_flushLines) { + TLM_segments = (int)(((double)p_tileSizeHeight / (double)p_flushLines) + 0.5); + if (!TLM_segments) TLM_segments = 1; + } else { + TLM_segments = 1; + } + + ostringstream segments; + segments << "ORGgen_tlm=" << TLM_segments; + codestream_parameters->parse_string(segments.str().c_str()); + + // Include packet length markers in tile headers + codestream_parameters->parse_string("ORGgen_plt=yes"); + + // Finalize the codestream parameters + codestream_parameters->finalize_all(); + + // Construct the JPEG2000 codestream object + JPEG2000_Codestream = new kdu_codestream(); + JPEG2000_Codestream->create(codestream_parameters,JP2_Boxes); + + // Some parameters must be set again after creating the codestream. + // It was not clear if they need to be set twice or only after + // creating the codestream. + codestream_parameters = JPEG2000_Codestream->access_siz(); + codestream_parameters->parse_string(levels.str().c_str()); + codestream_parameters->parse_string("Creversible=yes"); + codestream_parameters->parse_string(progression.c_str()); + codestream_parameters->parse_string(segments.str().c_str()); + codestream_parameters->parse_string("ORGgen_plt=yes"); + + // Set precinct sizes - vertical dimension gets set first. In our + // case, both dimensions are the same. + ostringstream sizes; + sizes << "Cprecincts="; + for (unsigned int i=0; iparse_string(sizes.str().c_str()); + + // Set code block size - vertical dimension gets set first. In our + // case, both dimensions are the same. + ostringstream size; + size << "Cblk={" << p_codeBlockSize << "," << p_codeBlockSize << "}"; + codestream_parameters->parse_string(size.str().c_str()); + + codestream_parameters->finalize_all(); + + // Finalize image dimensions + jp2_dimensions dimensions = JP2_Boxes->access_dimensions(); + dimensions.init(codestream_parameters); + dimensions.finalize_compatibility(codestream_parameters); + + // Set colour definition + jp2_colour colour = JP2_Boxes->access_colour(); + colour.init((p_bandDimension >= 3) ? JP2_sRGB_SPACE : JP2_sLUM_SPACE); + + // Write all JP2 boxes up to, but not including, the codestream box + JP2_Boxes->write_header(); + + // Initialize the encoder + // Open the JPEG2000 codestream (jp2c) box + JP2_Boxes->open_codestream(); + + // Set number of quality layers to 1 + int layers; + kdu_params *COD = JPEG2000_Codestream->access_siz()->access_cluster(COD_params); + if (!(COD->get(Clayers,0,0,layers) && (layers > 0))) + COD->set(Clayers,0,0,layers=1); + kdu_long *layer_sizes = new kdu_long[layers]; + memset(layer_sizes,0,sizeof(kdu_long)*layers); + + // Initialize the codestream stripe compressor + p_compressor.start(*JPEG2000_Codestream,layers,layer_sizes,NULL,0,false, + p_pixelBytes==4); // Force precise for 32-bit values + + // Determine optimum stripe heights for accessing data + p_stripeHeights = new int[p_bandDimension]; + p_maxStripeHeights = new int[p_bandDimension]; + p_precisions = new int[p_bandDimension]; + p_isSigned = new bool[p_bandDimension]; + p_compressor.get_recommended_stripe_heights(MIN_STRIPE_HEIGHT, + MAX_STRIPE_HEIGHT,p_stripeHeights,p_maxStripeHeights); + for (unsigned int i=0; idestroy(); + JP2_Boxes->close(); + JP2_Stream->close(); + delete [] p_stripeHeights; + delete [] p_maxStripeHeights; + delete [] p_precisions; + delete [] p_isSigned; +#endif + } +} diff --git a/isis/src/base/objs/JP2Encoder/JP2Encoder.h b/isis/src/base/objs/JP2Encoder/JP2Encoder.h new file mode 100644 index 0000000000000000000000000000000000000000..f5c13121e4fd31dce833292c248387c4be6d8452 --- /dev/null +++ b/isis/src/base/objs/JP2Encoder/JP2Encoder.h @@ -0,0 +1,134 @@ +#ifndef JP2Encoder_h +#define JP2Encoder_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/02/22 02:17:32 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#include "PixelType.h" + +#if ENABLEJP2K +#include "jp2.h" +#include "kdu_stripe_compressor.h" +#endif +#define MIN_STRIPE_HEIGHT 256 +#define MAX_STRIPE_HEIGHT 8192 +#define INCREMENTAL_FLUSH_BYTES (256 * 1024 * 1024) + +namespace Isis { +/** + * @brief JPEG2000 encoder class + * + * This class is used to convert image data into JPEG2000 format. + * + * Here is an example of how to use JP2Encoder + * @code + * char **jp2buf; + * ProcessExport p; + * Cube *icube; + * JP2Encoder *JP2_encoder; + * icube = p.SetInputCube("FROM",Isis::OneBand); + * p.SetInputRange(); + * p.SetFormat(ProcessExport::BIL); + * jp2buf = new char* [1]; + * jp2buf[0] = new char[icube->Samples()]; + * p.SetOutputType(Isis::UnsignedByte); + * p.SetOutputRange(1.0,255.0); + * p.SetOutputNull(0.0); + * JP2_encoder = new JP2Encoder(ui.GetFilename("TO"),icube->Samples(), + * icube->Lines(),icube->Bands(),Isis::UnsignedByte); + * JP2_encoder->OpenFile(); + * p.StartProcess(toJP2); + * p.EndProcess(); + * delete JP2_encoder; + * @endcode + * + * If you would like to see JP2Encoder being used in implementation, + * see isis2std.cpp + * + * @ingroup HighLevelCubeIO + * + * @author 2009-1-11 Janet Barrett + * + * @internal + * @history 2009-1-11 Janet Barrett - Original version. + * + */ + +class JP2Error; +class JP2Encoder { + public: + JP2Encoder (const std::string &jp2file, const unsigned int nsamps, + const unsigned int nlines, const unsigned int nbands, + const Isis::PixelType type); + ~JP2Encoder (); + + // Register with the Kakadu error facility + JP2Error *kakadu_error () const {return Kakadu_Error;}; + + // Open and initialize the JP2 file for writing + void OpenFile (); + + // Write byte data to the JP2 file + void Write (unsigned char **inbuf); + + // Write 16-bit data to the JP2 file + void Write (short int **inbuf); + + private: + std::string p_jp2File; //! p_precinctSize; //! +#include "Preference.h" + +using namespace std; + +int main(){ + Isis::Preference::Preferences(true); + + cout << "Testing Isis::JP2Encoder ..." < +#include +#include + +#include "iException.h" +#include "JP2Error.h" + +using namespace std; +namespace Isis { + + /** + * This class is necessary to catch the error messages produced by + * Kakadu so that they can be output using ISIS3 methods. If these + * routines are not registered with the Kakadu error handling facility, + * then the Kakadu errors will be lost and not reported to the user. + * + */ + + /** + * Register put_text routine with Kakadu error and warning handling + * facility. This routine saves the text from a Kakadu produced error + * message. + * + */ + void JP2Error::put_text (const char *message) { + Message += message; + } + + /** + * Register add_text routine with Kakadu error and warning handling + * facility. This routine places newline character between successive + * Kakadu produced error messages. + * + */ + void JP2Error::add_text (const std::string &message) { + if (!Message.empty()) Message += '\n'; + Message += message; + } + + /** + * Register flush routine with Kakadu error and warning handling + * facility. This routine writes Kakadu error messages out using + * ISIS3 preferred method. + * + */ + void JP2Error::flush (bool end_of_message) { + throw iException::Message(iException::User,Message,_FILEINFO_); + } +} diff --git a/isis/src/base/objs/JP2Error/JP2Error.h b/isis/src/base/objs/JP2Error/JP2Error.h new file mode 100644 index 0000000000000000000000000000000000000000..8366c66b41a85189ea208f6b2ec0e3c173142ea3 --- /dev/null +++ b/isis/src/base/objs/JP2Error/JP2Error.h @@ -0,0 +1,68 @@ +#ifndef JP2Error_h +#define JP2Error_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/02/22 02:12:38 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#if ENABLEJP2K +#include "jp2.h" +#endif + +namespace Isis { +/** + * @brief Kakadu error messaging class + * + * This class is used to register a Kakadu error handler. It is + * necessary to register the routines put_text, add_text, and + * flush with the Kakadu error handler in order for the Kakadu + * error messages to get reported to the user. + * + * @ingroup HighLevelCubeIO + * + * @author 2009-12-18 Janet Barrett + * + * @internal + * @history 2009-12-18 Janet Barrett - Original version. + * + */ + +#if ENABLEJP2K +class JP2Error : public kdu_thread_safe_message { +#else +class JP2Error { +#endif + public: + //! +#include "Preference.h" + +using namespace std; + +int main(){ + Isis::Preference::Preferences(true); + + cout << "Testing Isis::JP2Error ..." < +#include "Lambert.h" + +namespace Isis { + double Lambert::PhotoModelAlgorithm (double phase, double incidence, + double emission) { + double pht_lambert; + double incrad = incidence * Isis::PI / 180.0; + double munot = cos(incrad); + + if (munot <= 0.0 || incidence == 90.0) { + pht_lambert = 0.0; + } else { + pht_lambert = munot; + } + + return pht_lambert; + } +} + +extern "C" Isis::PhotoModel *LambertPlugin (Isis::Pvl &pvl) { + return new Isis::Lambert(pvl); +} diff --git a/isis/src/base/objs/Lambert/Lambert.h b/isis/src/base/objs/Lambert/Lambert.h new file mode 100644 index 0000000000000000000000000000000000000000..1f920b52cfe9c4e524e6b6a4915dae26d375badc --- /dev/null +++ b/isis/src/base/objs/Lambert/Lambert.h @@ -0,0 +1,43 @@ +#if !defined(Lambert_h) +#define Lambert_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2007/02/20 16:55:11 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PhotoModel.h" + +namespace Isis { + class Pvl; + + class Lambert : public PhotoModel { + public: + Lambert (Pvl &pvl) : PhotoModel(pvl) {}; + virtual ~Lambert() {}; + + protected: + virtual double PhotoModelAlgorithm (double phase, double incidence, + double emission); + + }; +}; + +#endif diff --git a/isis/src/base/objs/Lambert/Lambert.truth b/isis/src/base/objs/Lambert/Lambert.truth new file mode 100644 index 0000000000000000000000000000000000000000..27559c64e68f8c8f180002f3923650130686c8b0 --- /dev/null +++ b/isis/src/base/objs/Lambert/Lambert.truth @@ -0,0 +1,18 @@ +UNIT TEST for Lambert photometric function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object +End + +Test phase=0.0, incidence=0.0, emission=0.0 ... +Albedo = 1 + +Test phase=60.0, incidence=45.0, emission=30.0 ... +Albedo = 0.707107 + +Test phase=180.0, incidence=90.0, emission=90.0 ... +Albedo = 0 + diff --git a/isis/src/base/objs/Lambert/Makefile b/isis/src/base/objs/Lambert/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2206dc47f6a5bd0909f40ec714fcfbef2700f4f2 --- /dev/null +++ b/isis/src/base/objs/Lambert/Makefile @@ -0,0 +1,5 @@ +INCS = Lambert.h +SRCS = Lambert.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Lambert/PhotoModel.plugin b/isis/src/base/objs/Lambert/PhotoModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..f0bf82f9fb9693c62d7b9254b97b468ad67b2fca --- /dev/null +++ b/isis/src/base/objs/Lambert/PhotoModel.plugin @@ -0,0 +1,4 @@ +Group = Lambert + Library = Lambert + Routine = LambertPlugin +End_Group diff --git a/isis/src/base/objs/Lambert/unitTest.cpp b/isis/src/base/objs/Lambert/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..15b3f3aa6d8b9e5d0f5f128d2fab63aab68f1276 --- /dev/null +++ b/isis/src/base/objs/Lambert/unitTest.cpp @@ -0,0 +1,48 @@ +#include +#include +#include "Preference.h" +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + std::cout << "UNIT TEST for Lambert photometric function" << + std::endl << std::endl; + + try { + PvlGroup alg("Algorithm"); + alg += PvlKeyword("Name","Lambert"); + + PvlObject o("PhotometricModel"); + o.AddGroup(alg); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl << std::endl; + + PhotoModel *pm = PhotoModelFactory::Create(pvl); + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(0.0,0.0,0.0) << + std::endl << std::endl; + std::cout << "Test phase=60.0, incidence=45.0, emission=30.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(60.0,45.0,30.0) << + std::endl << std::endl; + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(180.0,90.0,90.0) << + std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/LambertConformal/LambertConformal.cpp b/isis/src/base/objs/LambertConformal/LambertConformal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f73cac01812f815aed9bd7c81ae1d9787bfa53f0 --- /dev/null +++ b/isis/src/base/objs/LambertConformal/LambertConformal.cpp @@ -0,0 +1,506 @@ +/** + * @file + * $Revision: 1.8 $ + * $Date: 2009/03/20 22:30:23 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "LambertConformal.h" +#include "iException.h" +#include "Constants.h" +#include "iString.h" + +using namespace std; +namespace Isis { + /** + * Constructs a Lambert Conformal object + * + * @param label This argument must be a Label containing the proper mapping + * information as indicated in the Projection class. Additionally, + * the lambertconformal projection requires the center longitude + * to be defined in the keyword CenterLongitude, and the first and + * second standard parallels defined in the keywords + * FirstStandardParallel and SecondStandardParallel. + * + * @param allowDefaults If set to false the constructor expects that a keyword + * of CenterLongitude, FirstStandardParallel, and + * SecondStandardParallel will be in the label. Otherwise + * it will attempt to compute the center longitude using + * the middle of the longitude range specified in the + * labels. Defaults to false. + * + * @throws Isis::iException::Io + */ + LambertConformal::LambertConformal(Isis::Pvl &label, bool allowDefaults) : + Isis::Projection::Projection (label) { + try { + // Try to read the mapping group + Isis::PvlGroup &mapGroup = label.FindGroup ("Mapping",Isis::Pvl::Traverse); + + // Compute and write the default center longitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLongitude"))) { + double lon = (p_minimumLongitude + p_maximumLongitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLongitude",lon); + } + + // Compute and write the default center latitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLatitude"))) { + double lat = (p_minimumLatitude + p_maximumLatitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLatitude",lat); + } + + // Get the center longitude & latitude + p_centerLongitude = mapGroup["CenterLongitude"]; + p_centerLatitude = mapGroup["CenterLatitude"]; + if (this->IsPlanetocentric()) { + p_centerLatitude = this->ToPlanetographic(p_centerLatitude); + } + + // Test to make sure center longitude is valid + if (fabs(p_centerLongitude) > 360.0) { + iString message = "Central Longitude [" + iString(p_centerLongitude); + message += "] must be between -360 and 360"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + + // convert to radians, adjust for longitude direction + p_centerLongitude *= Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) p_centerLongitude *= -1.0; + + // Get the standard parallels & convert them to ographic + p_par1 = mapGroup["FirstStandardParallel"]; + if (this->IsPlanetocentric()) { + p_par1 = this->ToPlanetographic(p_par1); + } + p_par2 = mapGroup["SecondStandardParallel"]; + if (this->IsPlanetocentric()) { + p_par2 = this->ToPlanetographic(p_par2); + } + + // Test to make sure standard parallels are valid + if (fabs(p_par1) > 90.0 || fabs(p_par2) > 90.0) { + string message = "Standard Parallels must between -90 and 90"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + if (fabs(p_par1 + p_par2) < DBL_EPSILON) { + string message = "Standard Parallels cannot be symmetric to the equator"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + // Removed because this test only works for northern hemisphere + // Just reorder the parallels so p1 is at the larger radius of the two + //if (p_par1 > p_par2) { + // string message = "Standard Parallels must be ordered"; + // throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + //} + + // Reorder the parallels so p1 is closer to the equator than p2 + // Therefore p2 is nearest the apex of the cone + if (fabs(p_par1) > fabs(p_par2)) { + double tmp = p_par2; + p_par2 = p_par1; + p_par1 = tmp; + } + + // Test to make sure center latitude is valid + // The pole opposite the apex can not be used as the clat (i.e., origin of + // the projection) it projects to infinity + // Given: p2 is closer to the apex than p1, and p2 must be on the same + // side of the equator as the apex (due to the reording of p1 and p2 above) + // Test for cone pointed south "v" + if ((p_par2 < 0.0) && (fabs(90.0-p_centerLatitude) < DBL_EPSILON)) { + iString message = "Center Latitude [" + iString(p_centerLatitude); + message += "] is not valid, it projects to infinity for standard parallels ["; + message += iString(p_par1) + "," + iString(p_par2) + "]"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + // Test for cone pointed north "^" + else if ((p_par2 > 0.0) && (fabs(-90.0-p_centerLatitude) < DBL_EPSILON)) { + iString message = "Center Latitude [" + iString(p_centerLatitude); + message += "] is not valid, it projects to infinity for standard parallels ["; + message += iString(p_par1) + "," + iString(p_par2) + "]"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + // convert clat to radians + p_centerLatitude *= Isis::PI / 180.0; + + // Convert standard parallels to radians + p_par1 *= Isis::PI / 180.0; + p_par2 *= Isis::PI / 180.0; + + // Compute the Snyder's m and t values for the standard parallels and the + // center latitude + double sinpar1 = sin(p_par1); + double cospar1 = cos(p_par1); + double m1 = mCompute(sinpar1, cospar1); + double t1 = tCompute(p_par1, sinpar1); + + double sinpar2 = sin(p_par2); + double cospar2 = cos(p_par2); + double m2 = mCompute(sinpar2, cospar2); + double t2 = tCompute(p_par2, sinpar2); + + double sinclat = sin(p_centerLatitude); + double tclat = tCompute(p_centerLatitude, sinclat); + + // Calculate Snyder's n, f, and rho + if(fabs(p_par1 - p_par2) >= DBL_EPSILON) { + p_n = log(m1 / m2) / log(t1 / t2); + } + else { + p_n = sinpar1; + } + p_f = m1 / (p_n * pow(t1, p_n)); + p_rho = p_equatorialRadius * p_f * pow(tclat, p_n); + } + catch (Isis::iException &e) { + string message = "Invalid label group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + //! Destroys the LambertConformal object + LambertConformal::~LambertConformal() { + } + + /** + * This method is used to set the latitude/longitude (assumed to be of the + * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. + * + * @param lat Latitude value to project + * + * @param lon Longitude value to project + * + * @return bool + */ + bool LambertConformal::SetGround(const double lat,const double lon) { + // Convert longitude to radians & clean up + p_longitude = lon; + double lonRadians = lon * Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) lonRadians *= -1.0; + + // Now convert latitude to radians & clean up ... it must be planetographic + p_latitude = lat; + double latRadians = lat; + if (IsPlanetocentric()) latRadians = ToPlanetographic(latRadians); + latRadians *= Isis::PI / 180.0; + + // Check for special cases & calculate rh, theta, and snyder t + double rh; + if (fabs(fabs(latRadians) - Isis::HALFPI) < DBL_EPSILON) { + // Lat/Lon point cannot be projected + if (latRadians * p_n <= 0.0) { + p_good = false; + return p_good; + } + else rh = 0.0; + } + else { + double sinlat = sin(latRadians); + // Lat/Lon point cannot be projected + double t = tCompute(latRadians, sinlat); + rh = p_equatorialRadius * p_f * pow(t, p_n); + } + double theta = p_n * (lonRadians - p_centerLongitude); + + // Compute the coordinate + double x = rh * sin(theta); + double y = p_rho - rh * cos(theta); + SetComputedXY(x,y); + + p_good = true; + return p_good; + } + + /** + * This method is used to set the projection x/y. The Set forces an attempted + * calculation of the corresponding latitude/longitude position. This may or + * may not be successful and a status is returned as such. + * + * @param x X coordinate of the projection in units that are the same as the + * radii in the label + * + * @param y Y coordinate of the projection in units that are the same as the + * radii in the label + * + * @return bool + */ + bool LambertConformal::SetCoordinate(const double x, const double y) { + // Save the coordinate + SetXY(x,y); + + // Get the sign of Snyder's n + double sign; + if (p_n >= 0) sign = 1.0; + else sign = -1.0; + + double temp = p_rho - GetY(); + double rh = sign * sqrt(GetX() * GetX() + temp * temp); + + double theta; + if (rh != 0) theta = atan2(sign * GetX(), sign * temp); + else theta = 0.0; + + // Compute latitude and longitude + if (rh != 0 || p_n > 0) { + double t = pow(rh / (p_equatorialRadius * p_f), 1.0 / p_n); + p_latitude = phi2Compute(t); + } + else p_latitude = -Isis::HALFPI; + p_longitude = theta / p_n + p_centerLongitude; + + + // Convert to degrees + p_latitude *= 180.0 / Isis::PI; + p_longitude *= 180.0 / Isis::PI; + + // Cleanup the longitude + if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; + // These need to be done for circular type projections + // p_longitude = To360Domain (p_longitude); + // if (p_longitudeDomain == 180) p_longitude = To180Domain(p_longitude); + + // Cleanup the latitude + if (IsPlanetocentric()) p_latitude = ToPlanetocentric(p_latitude); + + p_good = true; + return p_good; + } + + /** + * This method is used to determine the x/y range which completely covers the + * area of interest specified by the lat/lon range. The latitude/longitude + * range may be obtained from the labels. The purpose of this method is to + * return the x/y range so it can be used to compute how large a map may need + * to be. For example, how big a piece of paper is needed or how large of an + * image needs to be created. The method may fail as indicated by its return + * value. + * + * @param minX Minimum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxX Maximum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param minY Minimum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxY Maximum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @return bool + * + * @history 2009-03-03 Tracie Sucharski, Undo the PositiveWest adjustment to + * the center longitude because it is done twice, once + * in the constructor and again in SetGround. + * + * @history 2009-03-20 Stuart Sides, Modified the validity check for center + * latitude. It now only tests for the pole opposite the + * apex of the cone. + */ + bool LambertConformal::XYRange(double &minX, double &maxX, double &minY, double &maxY){ + + // Test the four corners + XYRangeCheck(p_minimumLatitude, p_minimumLongitude); + XYRangeCheck(p_minimumLatitude, p_maximumLongitude); + XYRangeCheck(p_maximumLatitude, p_minimumLongitude); + XYRangeCheck(p_maximumLatitude, p_maximumLongitude); + + // Decide which pole the apex of the cone is above + // Remember p1 is now closest to the equator and p2 is closest to one of the poles + bool north_hemi = true; + // Stuart Sides 2008-08-15 + // This test was removed because the reordering of p1 and p2 in the + // constructor made it incorrect + //if (fabs(p_par1) > fabs(p_par2)) north_hemi = false; + if (p_par2 < 0.0) north_hemi = false; + if ((p_par1 == p_par2) && (p_par1 < 0.0)) north_hemi = false; + + double cLonDeg = p_centerLongitude * 180.0 / Isis::PI; + + // This is needed because the SetGround class applies the PositiveWest + // adjustment which was already done in the constructor. + if (p_longitudeDirection == PositiveWest) cLonDeg = cLonDeg * -1.0; + + double pole_north, min_lat_north, max_lat_north, londiff; + // North Pole + if (north_hemi) { + p_latitude = 90.0; + p_longitude = cLonDeg; + + //Unable to project at the pole + if (!SetGround(p_latitude,p_longitude)) { + p_good = false; + return p_good; + } + + pole_north = YCoord(); + p_latitude = p_minimumLatitude; + + //Unable to project at the pole + if (!SetGround(p_latitude,p_longitude)) { + p_good = false; + return p_good; + } + + min_lat_north = YCoord(); + double y = min_lat_north + 2.0 * (pole_north - min_lat_north); + + //Unable to project opposite the center longitude + if (!SetCoordinate(XCoord(),y)) { + p_good = false; + return p_good; + } + + londiff = fabs(cLonDeg - p_longitude) / 2.0; + p_longitude = cLonDeg - londiff; + for (int i=0; i<3; i++) { + if ((p_longitude >=p_minimumLongitude) && (p_longitude <= p_maximumLongitude)) { + p_latitude = p_minimumLatitude; + XYRangeCheck(p_latitude, p_longitude); + } + p_longitude += londiff; + } + + } + // South Pole + else { + p_latitude = -90.0; + p_longitude = cLonDeg; + + //Unable to project at the pole + if (!SetGround(p_latitude,p_longitude)) { + p_good = false; + return p_good; + } + + pole_north = YCoord(); + p_latitude = p_maximumLatitude; + + //Unable to project at the pole + if (!SetGround(p_latitude,p_longitude)) { + p_good = false; + return p_good; + } + + max_lat_north = YCoord(); + double y = max_lat_north - 2.0 * (max_lat_north - pole_north); + + //Unable to project opposite the center longitude + if (!SetCoordinate(XCoord(),y)) { + p_good = false; + return p_good; + } + + londiff = fabs(cLonDeg - p_longitude) / 2.0; + p_longitude = cLonDeg - londiff; + for (int i=0; i<3; i++) { + if ((p_longitude >=p_minimumLongitude) && (p_longitude <= p_maximumLongitude)) { + p_latitude = p_maximumLatitude; + XYRangeCheck(p_latitude, p_longitude); + } + p_longitude += londiff; + } + } + + // Make sure everything is ordered + if (p_minimumX >= p_maximumX) return false; + if (p_minimumY >= p_maximumY) return false; + + // Return X/Y min/maxs + minX = p_minimumX; + maxX = p_maximumX; + minY = p_minimumY; + maxY = p_maximumY; + return true; + } + + + /** + * This function returns the keywords that this projection uses. + * + * @return PvlGroup The keywords that this projection uses + */ + PvlGroup LambertConformal::Mapping() { + PvlGroup mapping = Projection::Mapping(); + + mapping += p_mappingGrp["CenterLatitude"]; + mapping += p_mappingGrp["CenterLongitude"]; + mapping += p_mappingGrp["FirstStandardParallel"]; + mapping += p_mappingGrp["SecondStandardParallel"]; + + return mapping; + } + + /** + * This function returns the latitude keywords that this projection uses + * + * @return PvlGroup The latitude keywords that this projection uses + */ + PvlGroup LambertConformal::MappingLatitudes() { + PvlGroup mapping = Projection::MappingLatitudes(); + + mapping += p_mappingGrp["CenterLatitude"]; + mapping += p_mappingGrp["FirstStandardParallel"]; + mapping += p_mappingGrp["SecondStandardParallel"]; + + return mapping; + } + + /** + * This function returns the longitude keywords that this projection uses + * + * @return PvlGroup The longitude keywords that this projection uses + */ + PvlGroup LambertConformal::MappingLongitudes() { + PvlGroup mapping = Projection::MappingLongitudes(); + + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * Compares two Projection objects to see if they are equal + * + * @param proj Projection object to do comparison on + * + * @return bool Returns true if the Projection objects are equal, and false if + * they are not + */ + bool LambertConformal::operator== (const Isis::Projection &proj) { + if (!Isis::Projection::operator==(proj)) return false; + // dont do the below it is a recusive plunge + // if (Isis::Projection::operator!=(proj)) return false; + LambertConformal *lamb = (LambertConformal *) &proj; + if ((lamb->p_centerLongitude != this->p_centerLongitude) || + (lamb->p_centerLatitude != this->p_centerLatitude)) return false; + return true; + } +} // end namespace isis + +extern "C" Isis::Projection *LambertConformalPlugin (Isis::Pvl &lab, + bool allowDefaults) { + return new Isis::LambertConformal(lab,allowDefaults); +} + diff --git a/isis/src/base/objs/LambertConformal/LambertConformal.h b/isis/src/base/objs/LambertConformal/LambertConformal.h new file mode 100644 index 0000000000000000000000000000000000000000..c550ac51055c95ce8334f79e47788720c46811df --- /dev/null +++ b/isis/src/base/objs/LambertConformal/LambertConformal.h @@ -0,0 +1,105 @@ +#ifndef LambertConformal_h +#define LambertConformal_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2009/03/20 22:30:23 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Projection.h" +#include "Constants.h" + +namespace Isis { +/** + * @brief Lambert Conformal Map Projection + * + * This class provides methods for the forward and inverse equations of a + * Lambert Conformal map projection (for an ellipse). The code was converted + * to C++ from the C version of the USGS General Cartographic Transformation + * Package (GCTP). This class inherits Projection and provides the two virtual + * methods SetGround (forward) and SetCoordinate (inverse) and a third virtual + * method, XYRange, for obtaining projection coordinate coverage for a + * latitude/longitude window. Please see the Projection class for a full + * accounting of all the methods available. + * + * @ingroup MapProjection + * + * @author 2005-03-29 Elizabeth Ribelin + * + * @internal + * @history 2007-06-29 Steven Lambright - Added Mapping, MappingLatitudes and + * MappingLongitudes methods. + * @history 2008-05-09 Steven Lambright - Added Name, Version methods + * @history 2008-08-15 Stuart Sides - Modified to allow standard parallels to + * be in any order. Modified to not accept center latitudes too close + * to either pole. + * @history 2009-03-20 Stuart Sides - Modified to not accept center latitudes + * near the pole opposite the apex of the cone + */ + class LambertConformal : public Isis::Projection { + public: + LambertConformal(Isis::Pvl &label, bool allowDefaults=false); + ~LambertConformal(); + bool SetGround (const double lat, const double lon); + bool SetCoordinate (const double x, const double y); + bool XYRange (double &minX, double &maxX, double &minY, double &maxY); + PvlGroup Mapping(); + PvlGroup MappingLatitudes(); + PvlGroup MappingLongitudes(); + + /** + * Returns the name of the map projection + * + * @return string Name of projection + */ + std::string Name() const { return "LambertConformal"; } + + /** + * Returns the version of the map projection + * + * + * @return std::string Version number + */ + std::string Version () const { return "1.0"; } + + bool operator== (const Isis::Projection &proj); + + /** + * Returns the latitude of true scale (in the case of LambertConformal + * it is the smaller of the two standard parallels) + * + * @return double + */ + double TrueScaleLatitude () const { + if (p_par1 > p_par2) return p_par2 * 180.0 / Isis::PI; + else return p_par1 * 180.0 / Isis::PI; + }; + + + private: + double p_centerLongitude; //! +#include +#include "LambertConformal.h" +#include "iException.h" +#include "ProjectionFactory.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "UNIT TEST FOR LambertConformal" << endl << endl; + + Isis::Pvl lab; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = lab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",1.0); + mapGroup += Isis::PvlKeyword("PolarRadius",1.0); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetographic"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",180); + mapGroup += Isis::PvlKeyword("MinimumLatitude",20.0); + mapGroup += Isis::PvlKeyword("MaximumLatitude",80.0); + mapGroup += Isis::PvlKeyword("MinimumLongitude",-180.0); + mapGroup += Isis::PvlKeyword("MaximumLongitude",180.0); + mapGroup += Isis::PvlKeyword("ProjectionName","LambertConformal"); + + cout << "Test missing center longitude keyword ..." << endl; + try { + Isis::LambertConformal p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("CenterLongitude",-96.0); + + cout << "Test missing center latitude keyword..." << endl; + try { + Isis::LambertConformal p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("CenterLatitude", 23.0); + + cout << "Test missing first standard parallel keyword..." << endl; + try { + Isis::LambertConformal p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("FirstStandardParallel",33); + + cout << "Test missing second standard parallel keyword..." << endl; + try { + Isis::LambertConformal p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("SecondStandardParallel",45); + + try { + Isis::Projection &p = *Isis::ProjectionFactory::Create(lab); + // Isis::LambertConformal p(lab); + + cout << "Test SetGround method ... " << endl; + cout << std::setprecision(9); + cout << "Setting ground to (35,-75)" << endl; + p.SetGround(35.0,-75.0); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + + cout << "Test SetCoordinate method ... " << endl; + cout << "Setting coordinate to (0.29667846, 0.246211229)" << endl; + p.SetCoordinate(0.29667846, 0.246211229); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + p.SetCoordinate(0.0,0.0); + + cout << "Test XYRange method ... " << endl; + double minX,maxX,minY,maxY; + p.XYRange(minX,maxX,minY,maxY); + cout << "Minimum X: " << minX << endl; + cout << "Maximum X: " << maxX << endl; + cout << "Minimum Y: " << minY << endl; + cout << "Maximum Y: " << maxY << endl; + cout << endl; + + Isis::Projection *s = &p; + cout << "Test Name and comparision method ... " << endl; + cout << "Name: " << s->Name() << endl; + cout << "operator== " << (*s == *s) << endl; + cout << endl; + + cout << "Test default computation ... " << endl; + mapGroup.DeleteKeyword("CenterLongitude"); + mapGroup.DeleteKeyword("CenterLatitude"); + Isis::LambertConformal p2(lab,true); + cout << lab << endl; + cout << endl; + + cout << "Test TrueScaleLatitude method... " << endl; + cout << "TrueScaleLatitude = " << p.TrueScaleLatitude() << endl; + cout << endl; + + cout << "Testing Mapping() methods ... " << endl; + + Isis::Pvl tmp1; + Isis::Pvl tmp2; + Isis::Pvl tmp3; + tmp1.AddGroup(p.Mapping()); + tmp2.AddGroup(p.MappingLatitudes()); + tmp3.AddGroup(p.MappingLongitudes()); + + cout << "Mapping() = " << endl; + cout << tmp1 << endl; + cout << "MappingLatitudes() = " << endl; + cout << tmp2 << endl; + cout << "MappingLongitudes() = " << endl; + cout << tmp3 << endl; + cout << endl; + + cout << "Test invalid combinations of mapping parameters ..." << endl; + + mapGroup.DeleteKeyword("CenterLatitude"); + mapGroup += Isis::PvlKeyword("CenterLatitude", -90.0); + try { + Isis::LambertConformal p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup.DeleteKeyword("CenterLatitude"); + mapGroup += Isis::PvlKeyword("CenterLatitude", 90.0); + mapGroup.DeleteKeyword("FirstStandardParallel"); + mapGroup += Isis::PvlKeyword("FirstStandardParallel",-60); + + try { + Isis::LambertConformal p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + + + + + cout << "Unit test was obtained from:" << endl << endl; + cout << " Map Projections - A Working Manual" << endl; + cout << " USGS Professional Paper 1395 by John P. Snyder" << endl; + cout << " Pages 295-297" << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } +} + diff --git a/isis/src/base/objs/LeastSquares/LeastSquares.cpp b/isis/src/base/objs/LeastSquares/LeastSquares.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f7a93081de2b848e82d1572ac7849af132a2eb7 --- /dev/null +++ b/isis/src/base/objs/LeastSquares/LeastSquares.cpp @@ -0,0 +1,537 @@ +/** + * @file + * $Revision: 1.11 $ + * $Date: 2009/12/22 02:09:54 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "jama/jama_svd.h" +#include "jama/jama_qr.h" + +#if !defined(__sun__) +#include "gmm/gmm_superlu_interface.h" +#endif + +#include +#include "LeastSquares.h" +#include "iException.h" +#include "iString.h" + +namespace Isis { +/** + * Creates a LeastSquares Object. + * + * @param basis A BasisFunction. This parameter allows for the least squares + * fitting to be applied to arbitrary equations. + */ + LeastSquares::LeastSquares (Isis::BasisFunction &basis,bool sparse, + int sparseRows,int sparseCols) { + p_basis = &basis; + p_solved = false; + + p_sparse = sparse; +#if defined(__sun__) + p_sparse = false; +#endif + if (p_sparse) { + // make sure sparse nrows/ncols have been set + if (sparseRows == 0 || sparseCols == 0) { + std::string msg = "If solving using sparse matrices, you must enter"; + msg += " the number of rows/columns"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, + _FILEINFO_); + } +#if !defined(__sun__) + gmm::resize(p_sparseA,sparseRows,sparseCols); +#endif + p_sparseRows = sparseRows; + p_sparseCols = sparseCols; + } + p_currentFillRow = -1; + } + + //! Destroys the LeastSquares object. + LeastSquares::~LeastSquares () { + } + +/** + * Invoke this method for each set of knowns. Given our example in the + * description, we have three knowns and expecteds. They are + * @f[ + * (1,1) = 3 + * @f] + * @f[ + * (-2,3) = 1 + * @f] + * @f[ + * (2,-1) = 2 + * @f] + * + * @param data A vector of knowns. + * + * @param result The expected value for the knowns. + * + * @param weight (Default = 1.0) How strongly to weight this known. Weight less + * than 1 increases residual for this known, while weight greater + * than 1 decreases the residual for this known. + * + * @throws Isis::iException::Programmer - Number of elements in data does not + * match basis requirements + * + * @internal + * @history 2008-04-22 Tracie Sucharski, Fill sparse matrix. + * @history 2009-12-21 Jeannie Walldren, Modified code to add + * the square root of the weight to the vector + * p_sqrtweight. + * + */ + void LeastSquares::AddKnown (const std::vector &data, double result, + double weight) { + if ((int) data.size() != p_basis->Variables()) { + std::string msg = "Number of elements in data does not match basis [" + + p_basis->Name() + "] requirements"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + p_expected.push_back(result); + if (weight == 1) { + p_sqrtweight.push_back(weight); + } + else { + p_sqrtweight.push_back(sqrt(weight)); + } + + if (p_sparse) { +#if !defined(__sun__) + FillSparseA (data); +#endif + } + else { + p_input.push_back(data); + } + } + + + +/** + * Invoke this method for each set of knowns for sparse solutions. The A + * sparse matrix must be filled as we go or we will quickly run out of memory + * for large solutions. So, expand the basis function, apply weights (which is + * done in the Solve method for the non-sparse case. + * + * @param data A vector of knowns. + * + * @internal + * @history 2008-04-22 Tracie Sucharski - New method for sparse solutions. + * @history 2009-12-21 Jeannie Walldren - Changed variable name + * from p_weight to p_sqrtweight. + * + */ +#if !defined(__sun__) + void LeastSquares::FillSparseA (const std::vector &data) { + + p_basis->Expand(data); + p_currentFillRow++; + // ??? Speed this up using iterator instead of array indices??? + for (int c=0; c<(int)data.size(); c++) { + p_sparseA(p_currentFillRow,c) = p_basis->Term(c) * p_sqrtweight[p_currentFillRow]; + } + } +#endif + + +/** + * This method returns the data at the given row. + * + * @param row + * + * @return std::vector + */ + std::vector LeastSquares::GetInput(int row) const { + if((row >= Rows()) || (row < 0)) { + std::string msg = "Index out of bounds "; + msg += "[Given = " + Isis::iString(row) + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_input[row]; + } + +/** + * This method returns the expected value at the given row. + * + * @param row + * + * @return double + */ + double LeastSquares::GetExpected(int row) const { + if((row >= Rows()) || (row < 0)) { + std::string msg = "Index out of bounds "; + msg += "[Given = " + Isis::iString(row) + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_expected[row]; + } + +/** + * This methods returns the number of rows in the matrix. + * + * + * @return int + */ + int LeastSquares::Rows() const { + return (int)p_input.size(); + } + +/** + * After all the data has been registered through AddKnown, invoke this + * method to solve the system of equations. You can then use the Evaluate + * and Residual methods freely. + * + * @internal + * @history 2008-04-16 Debbie Dook / Tracie Sucharski, Added SolveSparse. + * @history 2009-04-08 Tracie Sucharski - Added return value which will + * pass on what is returned from SolveSparse which + * is a column number of a column that contained + * all zeros. + */ + int LeastSquares::Solve (Isis::LeastSquares::SolveMethod method) { + +#if defined(__sun__) + if (method == SPARSE) method = QRD; +#endif + + if (method == SVD) { + SolveSVD (); + } + else if (method == QRD) { + SolveQRD (); + } + else if (method == SPARSE) { +#if !defined(__sun__) + int column = SolveSparse (); + return column; +#endif + } + return 0; + } + +/** + * After all the data has been registered through AddKnown, invoke this + * method to solve the system of equations. You can then use the Evaluate + * and Residual methods freely. + * @internal + * @history 2009-12-21 Jeannie Walldren - Changed variable name + * from p_weight to p_sqrtweight. + * + */ + void LeastSquares::SolveSVD () { + + // We are solving Ax=b ... start by creating A + TNT::Array2D A(p_input.size(),p_basis->Coefficients()); + for (int r=0; rExpand(p_input[r]); + for (int c=0; cTerm(c) * p_sqrtweight[r]; + } + } + + // Ok use singular value decomposition to solve for the coefficients + // A = [U][S][V'] where [U] is MxN, [S] is NxN, [V'] is NxN transpose + // of [V]. We are solving for [A]x=b and need inverse of [A] such + // that x = [invA]b. Since inverse may not exist we use the + // pseudo-inverse [A+] from SVD which is [A+] = [V][invS][U'] + // Our coefficents are then x = [A+]b where b is p_b. + JAMA::SVD svd(A); + + TNT::Array2D V; + svd.getV(V); + + // The inverse of S is the 1 over each diagonal element of S + TNT::Array2D invS; + svd.getS(invS); + for (int i=0; i U; + svd.getU(U); + TNT::Array2D transU(U.dim2(),U.dim1()); + for (int r=0; r VinvS = TNT::matmult(V,invS); + TNT::Array2D Aplus = TNT::matmult(VinvS,transU); + + // Using Aplus and our b we can solve for the coefficients + TNT::Array2D b(p_expected.size(),1); + for (int r=0; r<(int)p_expected.size(); r++) { + b[r][0] = p_expected[r] * p_sqrtweight[r]; + } + TNT::Array2D coefs = TNT::matmult(Aplus,b); + + // If the rank of the matrix is not large enough we don't + // have enough coefficients for the solution + if (coefs.dim1() < p_basis->Coefficients()) { + std::string msg = "No solution available ... "; + msg += "Not enough knowns or knowns are co-linear ... "; + msg += "[Unknowns = " + Isis::iString(p_basis->Coefficients()) + "] "; + msg += "[Knowns = " + Isis::iString(coefs.dim1()) + "]"; + throw Isis::iException::Message(Isis::iException::Math,msg,_FILEINFO_); + } + + // Set the coefficients in our basis equation + std::vector bcoefs; + for (int i=0; iSetCoefficients(bcoefs); + + // Compute the errors + for (int i=0; i<(int)p_input.size(); i++) { + double value = p_basis->Evaluate(p_input[i]); + p_residuals.push_back(value-p_expected[i]); + } + + // All done + p_solved = true; + } + +/** + * After all the data has been registered through AddKnown, invoke this + * method to solve the system of equations with a QR + * decomposition of A = QR. You can then use the Evaluate and + * Residual methods freely. The QR decomposition is only slightly + * less reliable than the SVD, but much faster. + * @internal + * @history 2009-12-21 Jeannie Walldren - Changed variable name + * from p_weight to p_sqrtweight. + * + */ + void LeastSquares::SolveQRD () { + + // We are solving Ax=b ... start by creating A + TNT::Array2D A(p_input.size(),p_basis->Coefficients()); + for (int r=0; rExpand(p_input[r]); + for (int c=0; cTerm(c) * p_sqrtweight[r]; + } + } + + // Ok use to solve for the coefficients + // [A] = [Q][R] where [Q] is MxN and orthogonal and [R] is an NxN, + // upper triangular matrix. TNT provides the solve method that inverts + // [Q] and backsolves [R] to get the coefficients in the vector x + JAMA::QR qr(A); + + // Using A and our b we can solve for the coefficients + TNT::Array1D b(p_expected.size()); + for (int r=0; r<(int)p_expected.size();r++) { + b[r] = p_expected[r] * p_sqrtweight[r]; + } + +// Check to make sure the matrix is full rank before solving -- rectangular matrices must +// be full rank in order for the solve method to be successful +// + int full = qr.isFullRank(); + if (full == 0) { + std::string msg = "Not full rank"; + throw Isis::iException::Message(Isis::iException::Math,msg,_FILEINFO_); + } + + TNT::Array1D coefs = qr.solve(b); + + // Set the coefficients in our basis equation + std::vector bcoefs; + for (int i=0; iSetCoefficients(bcoefs); + + // Compute the errors + for (int i=0; i<(int)p_input.size(); i++) { + double value = p_basis->Evaluate(p_input[i]); + p_residuals.push_back(value-p_expected[i]); + } + + // All done + p_solved = true; + } + + + + +/** + * @brief Solve using sparse class + * + * After all the data has been registered through AddKnown, invoke this + * method to solve the system of equations Ax = b, with a sparse solver which + * solves the matrix by factorizing A. You can then use the Evaluate and + * Residual methods freely. + * + * @internal + * @history 2008-04-16 Debbie Cook / Tracie Sucharski, New method + * @history 2008-04-23 Tracie Sucharski, Fill sparse matrix as we go in + * AddKnown method rather than in the solve method, + * otherwise we run out of memory very quickly. + * @history 2009-04-08 Tracie Sucharski - Added return value which is a + * column number of a column that contained all zeros. + * @history 2009-12-21 Jeannie Walldren - Changed variable name + * from p_weight to p_sqrtweight. + * + */ +#if !defined(__sun__) + int LeastSquares::SolveSparse () { + + //??? Resize sparse to correct rows , accounting for held,ground,ignored + //gmm::resize(p_sparseA,p_sparseRows,p_sparseCols); + // We are solving Ax=b + + // Create the right-hand-side column matrix B now. Using A and our B we + // can solve for the coefficients + gmm::dense_matrix b(p_sparseRows,1); + std::vector x(p_sparseCols); + + for (int r=0; r > Asquare(p_sparseCols,p_sparseCols); + gmm::mult(gmm::transposed(p_sparseA),p_sparseA,Asquare); + + // Test for any columns with all 0's + // Return column number so caller can determine the appropriate error. + int numNonZeros; + for (int c=0; c bAtrans(p_sparseCols,1); + + gmm::mult(gmm::transposed(p_sparseA),b,bAtrans); +// int perm = 0; // use natural ordering + int perm = 2; // use mmd_at_plus_a ordering + double recond; + + gmm::SuperLU_solve(Asquare,x,gmm::mat_const_col(bAtrans,0),recond,perm); + + // Set the coefficients in our basis equation + std::vector bcoefs; + + for (int i=0; iSetCoefficients(bcoefs); + + // Compute the errors + for (int i=0; i data(p_sparseCols); + gmm::copy(gmm::mat_row(p_sparseA,i),data); + double value = p_basis->Evaluate(data); + p_residuals.push_back(value-p_expected[i]); + } + // All done + p_solved = true; + return 0; + } +#endif + + +/** + * Invokes the BasisFunction Evaluate method. + * + * @param data The input variables to evaluate. + * + * @return The evaluation for the input variable. + * + * @throws Isis::iException::Programmer - Unable to evaluate until a + * solution has been computed + */ + double LeastSquares::Evaluate (const std::vector &data) { + if (!p_solved) { + std::string msg = "Unable to evaluate until a solution has been computed"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_basis->Evaluate(data); + } + +/** + * Returns a vector of residuals (errors). That is, the difference between the + * evaluation of a known with the solution against the expected value. + * + * @return The vector of residuals. + * + * @throws Isis::iException::Programmer - Unable to return residuals until a + * solution has been computed + */ + std::vector LeastSquares::Residuals () const { + if (!p_solved) { + std::string msg = "Unable to return residuals until a solution has been computed"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_residuals; + } + +/** + * Returns the ith residual. That is, the difference between the evaluation of + * a known with the solution against the expected value. There is one residual + * for each time AddKnown was invoked. + * + * @param i The number of times AddKnown was invoked to be evaluated. + * + * @return The output value of the residual. + * + * @throws Isis::iException::Programmer - Unable to return residuals until a + * solution has been computed + */ + double LeastSquares::Residual (int i) const { + if (!p_solved) { + std::string msg = "Unable to return residuals until a solution has been computed"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_residuals[i]; + } + +/** + * Reset the weight for the ith known. This weight will not be used unless + * the system is resolved using the Solve method. + * + * @param index The position in the array to assign the given weight value + * @param weight A weight factor to apply to the ith known. A weight less + * than one increase the residual for this known while a + * weight greater than one decrease the residual for this + * known. + * @internal + * @history 2009-12-21 Jeannie Walldren, Modified code to add + * the square root of the weight to the vector + * p_sqrtweight. + * + */ + void LeastSquares::Weight (int index, double weight) { + if (weight == 1) { + p_sqrtweight[index] = weight; + } + else{ + p_sqrtweight[index] = sqrt(weight); + } + } + +} // end namespace isis diff --git a/isis/src/base/objs/LeastSquares/LeastSquares.h b/isis/src/base/objs/LeastSquares/LeastSquares.h new file mode 100644 index 0000000000000000000000000000000000000000..f497970af681d49175d047e1fa5b6394ccb99e4f --- /dev/null +++ b/isis/src/base/objs/LeastSquares/LeastSquares.h @@ -0,0 +1,178 @@ +#ifndef LeastSquares_h +#define LeastSquares_h +/** + * @file + * $Revision: 1.9 $ + * $Date: 2009/12/22 02:09:54 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include + +#include "tnt/tnt_array2d.h" + +#if !defined(__sun__) +#include "gmm/gmm.h" +#endif + +#include "BasisFunction.h" + +namespace Isis { +/** + * @brief Generic least square fitting class + * + * This class can be used to solved systems of linear equations through least + * squares fitting. The solution is derived through + * singular value decomposition or QR decomposition. For example: + * @f[ + * x + y = 3 + * @f] + * @f[ + * -2x + 3y = 1 + * @f] + * @f[ + * 2x - y = 2 + * @f] + * Is a simple system of equations that can be solved using this class. + * @code + * Isis::BasisFunction b("Linear",2,2); + * Isis::LeastSquares lsq(b); + * + * std::vector one; + * one.push_back(1.0); + * one.push_back(1.0); + * lsq.AddKnown(one,3.0); + * + * std::vector two; + * two.push_back(-2.0); + * two.push_back(3.0); + * lsq.AddKnown(two,1.0); + * + * std::vector tre; + * tre.push_back(2.0); + * tre.push_back(-1.0); + * lsq.AddKnown(tre,2.0); + * + * lsq.Solve(); + * + * double out1 = lsq.Evaluate(one); + * double out2 = lsq.Evaluate(two); + * double out3 = lsq.Evaluate(tre); + * @endcode + * + * @see PolynomialUnivariate + * @see PolynomialBiVariate + * @see BasisFunction + * + * @ingroup Math + * + * @author 2004-06-24 Jeff Anderson + * + * @internal + * @history 2004-06-24 Jeff Anderson, Original version + * @history 2007-11-16 Tracie Sucharski and Debbie A. Cook Added SolveQRD + * method for a faster solve + * @history 2008-02-06 Tracie Sucharski, Renamed Solve to SolveSVD and make + * private. Add public Solve, with a new parameter, + * method which defaults to SVD. This calls the + * correct solution method. This was done for + * documentation purposes-clarifies the default + * solves by SVD. + * @history 2008-04-16 Debbie Dook / Tracie Sucharski, Added SolveSparse. + * @history 2008-06-09 Tracie Sucharski, Added conditional compilations + * for Solaris. We could not get SuperLu to build + * under Solaris due to a confilict with Complex + * definitions. + * @history 2009-04-06 Tracie Sucharski, Added return value to SolveSparse, + * which indicates a column containing all zeroes + * which causes superlu to bomb. + * @history 2009-12-21 Jeannie Walldren, Changed p_weight to + * p_sqrtweight. Modified Weight() + * and AddKnown() to take the square + * root of the given weight and add + * it to the p_sqrtweight vector. + * + */ + class LeastSquares { + public: + + LeastSquares (Isis::BasisFunction &basis,bool sparse = false, + int sparseRows=0,int sparseCols=0); + ~LeastSquares (); + void AddKnown (const std::vector &input, double expected, + double weight = 1.0); + + std::vector GetInput(int row) const; + double GetExpected(int row) const; + int Rows() const; + + enum SolveMethod { SVD, //!< Singular Value Decomposition + QRD, //!< QR Decomposition + SPARSE //!< Sparse + }; + + int Solve (Isis::LeastSquares::SolveMethod method = SVD); + double Evaluate (const std::vector &input); + std::vector Residuals () const; + double Residual (int i) const; + void Weight (int index, double weight); + + /** + * The number of knowns (or times AddKnown was invoked) linear combination + * of the variables. + * + * @return int The number of knowns + */ + int Knowns () const { return p_expected.size(); }; + + private: + void SolveSVD (); + void SolveQRD (); + +#if !defined(__sun__) + int SolveSparse (); + void FillSparseA (const std::vector &data); + gmm::row_matrix > p_sparseA; +#endif + bool p_sparse; + int p_sparseRows; + int p_sparseCols; + int p_currentFillRow; + + bool p_solved; /** > p_input; /** p_expected; /** p_sqrtweight; /** p_residuals; /** +#include "iException.h" +#include "LeastSquares.h" +#include "Preference.h" + +int main () { + Isis::Preference::Preferences(true); + try { + std::cout << "Unit Test for LeastSquares:" << std::endl; + std::cout << std::endl; + Isis::BasisFunction b("Linear",2,2); + + Isis::LeastSquares lsq(b); + + std::vector one; + one.push_back(1.0); + one.push_back(1.0); + + std::vector two; + two.push_back(-2.0); + two.push_back(3.0); + + std::vector tre; + tre.push_back(2.0); + tre.push_back(-1.0); + + lsq.AddKnown(one,3.0); + lsq.AddKnown(two,1.0); + lsq.AddKnown(tre,2.0); + + int knowns = lsq.Knowns();; + double evalSVD1, evalSVD2, evalSVD3, resSVD1, resSVD2, resSVD3; + double evalQRD1, evalQRD2, evalQRD3, resQRD1, resQRD2, resQRD3; + double xcoefSVD, ycoefSVD, xcoefQRD, ycoefQRD; + lsq.Solve(); + evalSVD1 = lsq.Evaluate(one); + evalSVD2 = lsq.Evaluate(two); + evalSVD3 = lsq.Evaluate(tre); + resSVD1 = lsq.Residual(0); + resSVD2 = lsq.Residual(1); + resSVD3 = lsq.Residual(2); + xcoefSVD = b.Coefficient(0); + ycoefSVD = b.Coefficient(1); + lsq.Solve(Isis::LeastSquares::QRD); + evalQRD1 = lsq.Evaluate(one); + evalQRD2 = lsq.Evaluate(two); + evalQRD3 = lsq.Evaluate(tre); + resQRD1 = lsq.Residual(0); + resQRD2 = lsq.Residual(1); + resQRD3 = lsq.Residual(2); + xcoefQRD = b.Coefficient(0); + ycoefQRD = b.Coefficient(1); + + std::cout << "*** TEST 1: 3 POINTS, NO WEIGHTS ***************************" << std::endl; + std::cout << "Number of Knowns = " << knowns << std::endl; + std::cout << " SVD\tresidual\tQRD\tresidual" << std::endl; + std::cout << " one = " << evalSVD1 << "\t" << resSVD1 << "\t\t" << evalQRD1 <<"\t" << resQRD1 << std::endl; + std::cout << " two = " << evalSVD2 << "\t" << resSVD2 << "\t\t" << evalQRD2 <<"\t" << resQRD2 << std::endl; + std::cout << " tre = " << evalSVD3 << "\t" << resSVD3 << "\t\t" << evalQRD3 <<"\t" << resQRD3 << std::endl; + + std::cout << "---" << std::endl; + std::cout << "Test from Linear Algebra with Applications, 2nd Edition" << std::endl; + std::cout << "Steven J. Leon, page 191, 83/50=1.66 71/50=1.42" << std::endl; + std::cout << xcoefSVD << std::endl; + std::cout << ycoefSVD << std::endl ; + std::cout << "---" << std::endl; + + std::cout << "*** TEST 2: SAME 3 POINTS, MIDDLE POINT HAS WEIGHT 5 *******" << std::endl; + lsq.Weight(1,5); + knowns = lsq.Knowns();; + lsq.Solve(Isis::LeastSquares::SVD); + evalSVD1 = lsq.Evaluate(one); + evalSVD2 = lsq.Evaluate(two); + evalSVD3 = lsq.Evaluate(tre); + xcoefSVD = b.Coefficient(0); + ycoefSVD = b.Coefficient(1); + lsq.Solve(Isis::LeastSquares::QRD); + evalQRD1 = lsq.Evaluate(one); + evalQRD2 = lsq.Evaluate(two); + evalQRD3 = lsq.Evaluate(tre); + xcoefQRD = b.Coefficient(0); + ycoefQRD = b.Coefficient(1); + std::cout << "Number of Knowns = " << knowns << std::endl; + std::cout << " SVD\t\tQRD" << std::endl; + std::cout << " one = " << evalSVD1 << "\t\t" << evalQRD1 << std::endl; + std::cout << " two = " << evalSVD2 << "\t" << evalQRD2 << std::endl; + std::cout << " tre = " << evalSVD3 << "\t\t" << evalQRD3 << std::endl; + std::cout << " x = " << xcoefSVD << "\t\t" << xcoefQRD << std::endl; + std::cout << " y = " << ycoefSVD << "\t\t" << ycoefQRD << std::endl ; + std::cout << "---" << std::endl; + + std::cout << "*** TEST 3: SAME 3 POINTS, MIDDLE POINT REPEATED 5 TIMES ***" << std::endl; + lsq.Weight(1,1); + lsq.AddKnown(two,1.0); + lsq.AddKnown(two,1.0); + lsq.AddKnown(two,1.0); + lsq.AddKnown(two,1.0); + knowns = lsq.Knowns();; + lsq.Solve(Isis::LeastSquares::SVD); + evalSVD1 = lsq.Evaluate(one); + evalSVD2 = lsq.Evaluate(two); + evalSVD3 = lsq.Evaluate(tre); + xcoefSVD = b.Coefficient(0); + ycoefSVD = b.Coefficient(1); + lsq.Solve(Isis::LeastSquares::QRD); + evalQRD1 = lsq.Evaluate(one); + evalQRD2 = lsq.Evaluate(two); + evalQRD3 = lsq.Evaluate(tre); + xcoefQRD = b.Coefficient(0); + ycoefQRD = b.Coefficient(1); + std::cout << "Number of Knowns = " << knowns << std::endl; + std::cout << " SVD\t\tQRD" << std::endl; + std::cout << " one = " << evalSVD1 << "\t\t" << evalQRD1 << std::endl; + std::cout << " two = " << evalSVD2 << "\t" << evalQRD2 << std::endl; + std::cout << " tre = " << evalSVD3 << "\t\t" << evalQRD3 << std::endl; + std::cout << " x = " << xcoefSVD << "\t\t" << xcoefQRD << std::endl; + std::cout << " y = " << ycoefSVD << "\t\t" << ycoefQRD << std::endl ; + } + catch (Isis::iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/LimitPolygonSeeder/LimitPolygonSeeder.cpp b/isis/src/base/objs/LimitPolygonSeeder/LimitPolygonSeeder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f236f2258b8ddebbf2299cc95f1b798aab5cb985 --- /dev/null +++ b/isis/src/base/objs/LimitPolygonSeeder/LimitPolygonSeeder.cpp @@ -0,0 +1,249 @@ +/** + * @file + * $Revision: 1.11 $ + * $Date: 2010/05/05 21:24:30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include + +#include "geos/util/TopologyException.h" + +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "PolygonTools.h" +#include "LimitPolygonSeeder.h" + +namespace Isis { + + /** + * @brief Construct a LimitPolygonSeeder algorithm + * + * + * @param pvl A Pvl object that contains a valid polygon point seeding + * definition + */ + LimitPolygonSeeder::LimitPolygonSeeder (Pvl &pvl) : PolygonSeeder(pvl) { + Parse(pvl); + }; + + + /** + * @brief Seed a polygon with points + * + * Seed the supplied polygon with points in a staggered pattern. The spacing + * is determined by the PVL group "PolygonSeederAlgorithm" + * + * @param lonLatPoly geos::MultiPolygon The polygon to be seeded with points. + * + * @return std::vector A vector of points which have been + * seeded into the polygon. The caller assumes responsibility for deleteing + * these. + */ + std::vector LimitPolygonSeeder::Seed(const geos::geom::MultiPolygon *multiPoly) { + + // Storage for the points to be returned + std::vector points; + + // Create some things we will need shortly + const geos::geom::Envelope *polyBoundBox = multiPoly->getEnvelopeInternal(); + + // Call the parents standardTests member + std::string msg = StandardTests (multiPoly, polyBoundBox); + if (!msg.empty()) { + return points; + } + + // Do limit seeder specific tests to make sure this poly should be seeded + // (none for now) + + int xSteps = 0; + int ySteps = 0; + + // Test if X is major axis + if(fabs(polyBoundBox->getMaxX()-polyBoundBox->getMinX()) > fabs((polyBoundBox->getMaxY()-polyBoundBox->getMinY()))) { + xSteps = p_majorAxisPts; + ySteps = p_minorAxisPts; + } + else { + xSteps = p_minorAxisPts; + ySteps = p_majorAxisPts; + } + + double xSpacing = (polyBoundBox->getMaxX()-polyBoundBox->getMinX()) / (xSteps); + double ySpacing = (polyBoundBox->getMaxY()-polyBoundBox->getMinY()) / (ySteps); + + double realMinX = polyBoundBox->getMinX() + xSpacing/2; + double realMinY = polyBoundBox->getMinY() + ySpacing/2; + double maxY = polyBoundBox->getMaxY(); + double maxX = polyBoundBox->getMaxX(); + + for (double y=realMinY; y < maxY; y += ySpacing) { + for (double x=realMinX; x < maxX; x += xSpacing) { + geos::geom::Geometry *gridSquarePolygon = GetMultiPolygon(x-xSpacing/2.0,y-ySpacing/2, + x+xSpacing/2.0,y+ySpacing/2, *multiPoly); + + geos::geom::Point *centroid = gridSquarePolygon->getCentroid(); + + delete gridSquarePolygon; + if(centroid == NULL) continue; + + double gridCenterX = centroid->getX(); + double gridCenterY = centroid->getY(); + delete centroid; + + geos::geom::Coordinate c(gridCenterX,gridCenterY); + points.push_back(Isis::globalFactory.createPoint(c)); + } + } + + return points; + } + + /** + * This method returns the overlap between the x/y range specified and the + * "orig" polygon. This is used to get polygons that represent the overlap + * polygons in individual grid squares. + * + * @param dMinX Left side of rectangle + * @param dMinY Bottom side of rectangle + * @param dMaxX Right side of rectangle + * @param dMaxY Top side of the rectangle + * @param orig Multiplygon to intersect the square with + * + * @return geos::geom::Geometry* The portion of "orig" that intersects the + * square + */ + geos::geom::Geometry *LimitPolygonSeeder::GetMultiPolygon(double dMinX, double dMinY, + double dMaxX, double dMaxY, + const geos::geom::MultiPolygon &orig) { + geos::geom::CoordinateSequence *points = new geos::geom::CoordinateArraySequence(); + + points->add(geos::geom::Coordinate(dMinX,dMinY)); + points->add(geos::geom::Coordinate(dMaxX,dMinY)); + points->add(geos::geom::Coordinate(dMaxX,dMaxY)); + points->add(geos::geom::Coordinate(dMinX,dMaxY)); + points->add(geos::geom::Coordinate(dMinX,dMinY)); + + geos::geom::Polygon *poly = Isis::globalFactory.createPolygon(Isis::globalFactory.createLinearRing(points), NULL); + geos::geom::Geometry *overlap = poly->intersection(&orig); + + return overlap; + } + + /** + * @brief Parse the LimitPolygonSeeder spicific parameters from the PVL + * + * @param pvl The PVL object containing the control parameters for this + * polygon seeder. + */ + void LimitPolygonSeeder::Parse(Pvl &pvl) { + // Call the parents Parse method + PolygonSeeder::Parse(pvl); + + // Pull parameters specific to this algorithm out + try { + // Get info from Algorithm group + PvlGroup &algo = pvl.FindGroup("PolygonSeederAlgorithm",Pvl::Traverse); + PvlGroup & invalgo = invalidInput->FindGroup("PolygonSeederAlgorithm", + Pvl::Traverse); + + // Set the spacing + p_majorAxisPts = 0; + if (algo.HasKeyword("MajorAxisPoints")) { + p_majorAxisPts = (int) algo["MajorAxisPoints"]; + if (invalgo.HasKeyword("MajorAxisPoints")) { + invalgo.DeleteKeyword("MajorAxisPoints"); + } + } + else { + std::string msg = "PVL for LimitPolygonSeeder must contain [MajorAxisPoints] in ["; + msg += pvl.Filename() + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + p_minorAxisPts = 0; + if (algo.HasKeyword("MinorAxisPoints")) { + p_minorAxisPts = (int) algo["MinorAxisPoints"]; + if (invalgo.HasKeyword("MinorAxisPoints")) { + invalgo.DeleteKeyword("MinorAxisPoints"); + } + } + else { + std::string msg = "PVL for LimitPolygonSeeder must contain [MinorAxisPoints] in ["; + msg += pvl.Filename() + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + catch (iException &e) { + std::string msg = "Improper format for PolygonSeeder PVL ["+pvl.Filename()+"]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + if (p_majorAxisPts < 1.0) { + iString msg = "Major axis points must be greater that 0.0 [(" + iString(p_majorAxisPts) + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + if (p_minorAxisPts <= 0.0) { + iString msg = "Minor axis points must be greater that 0.0 [(" + iString(p_minorAxisPts) + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + PvlGroup LimitPolygonSeeder::PluginParameters(std::string grpName) { + PvlGroup pluginInfo(grpName); + + PvlKeyword name("Name", Algorithm()); + PvlKeyword minThickness("MinimumThickness", MinimumThickness()); + PvlKeyword minArea("MinimumArea", MinimumArea()); + PvlKeyword majAxis("MajorAxisPoints", p_majorAxisPts); + PvlKeyword minAxis("MinorAxisPoints", p_minorAxisPts); + + pluginInfo.AddKeyword(name); + pluginInfo.AddKeyword(minThickness); + pluginInfo.AddKeyword(minArea); + pluginInfo.AddKeyword(majAxis); + pluginInfo.AddKeyword(minAxis); + + return pluginInfo; + } + +}; // End of namespace Isis + + +/** + * @brief Create a LimitPolygonSeeder object + * + * Used to create a LimitPolygonSeeder object from a PolygonSeeder plugin PVL + * file. + * + * @param pvl The Pvl object that describes how the new object should be + * initialized. + * + * @return A pointer to the new object + */ +extern "C" Isis::PolygonSeeder *LimitPolygonSeederPlugin (Isis::Pvl &pvl) { + return new Isis::LimitPolygonSeeder(pvl); +} + diff --git a/isis/src/base/objs/LimitPolygonSeeder/LimitPolygonSeeder.h b/isis/src/base/objs/LimitPolygonSeeder/LimitPolygonSeeder.h new file mode 100644 index 0000000000000000000000000000000000000000..8e59114e327ef0a772dd83869d26ba551cd26d2b --- /dev/null +++ b/isis/src/base/objs/LimitPolygonSeeder/LimitPolygonSeeder.h @@ -0,0 +1,85 @@ +#ifndef LimitPolygonSeeder_h +#define LimitPolygonSeeder_h +/** + * @file + * $Revision: 1.8 $ + * $Date: 2010/05/05 21:24:30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "geos/geom/Point.h" +#include "geos/geom/MultiPolygon.h" +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/geom/Polygon.h" +#include "PolygonSeeder.h" + +namespace Isis { + class Pvl; + + /** + * @brief Seed points using a grid + * + * This class seeds the polygons with Control Points by creating a grid + * centered on the polygon. For each grid square, if it contains any overlap, a + * box is then created within the grid square, surrounding the valid data. The + * point checked is the center of this box, and if this point is within the + * overlap polygon then this point is returned, otherwise the grid square does + * not have a point. + * + * @ingroup PatternMatching + * + * @author 2008-04-21 Steven Lambright + * + * @internal + * @history 2008-08-18 Christopher Austin - Upgraded to geos3.0.0 + * @history 2008-11-12 Steven Lambright - Fixed documentation + * @history 2008-11-25 Steven Lambright - Added error checking + * @history 2008-12-23 Steven Lambright - Fixed problem with finding points in + * polygons that caused this algorithm to miss some. + * @history 2009-08-05 Travis Addair - Encapsulated group + * creation for seed definition group + * @history 2010-04-15 Eric Hyer - Now updates parent's invalidInput + * variable + * @history 2010-04-20 Christopher Austin - adapted for generic/unitless + * seeding + */ + class LimitPolygonSeeder : public PolygonSeeder { + public: + LimitPolygonSeeder (Pvl &pvl); + + //! Destructor + virtual ~LimitPolygonSeeder() {}; + + std::vector Seed(const geos::geom::MultiPolygon *mp); + + virtual PvlGroup PluginParameters(std::string grpName); + + protected: + virtual void Parse(Pvl &pvl); + + private: + geos::geom::Geometry *GetMultiPolygon(double dMinX, double dMinY, + double dMaxX, double dMaxY, + const geos::geom::MultiPolygon &orig); + int p_majorAxisPts; //!< Number of points to place on major axis + int p_minorAxisPts; //!< Number of points to place on minor axis + }; +}; + +#endif diff --git a/isis/src/base/objs/LimitPolygonSeeder/LimitPolygonSeeder.truth b/isis/src/base/objs/LimitPolygonSeeder/LimitPolygonSeeder.truth new file mode 100644 index 0000000000000000000000000000000000000000..c2b45b7f8b3537cff7d64e6f52425e70e7646708 --- /dev/null +++ b/isis/src/base/objs/LimitPolygonSeeder/LimitPolygonSeeder.truth @@ -0,0 +1,22 @@ +Test 1, create a seeder +Object = AutoSeed + Group = PolygonSeederAlgorithm + Name = Limit + MinimumThickness = 0.3 + MinimumArea = 5 + MajorAxisPoints = 2 + MinorAxisPoints = 2 + End_Group +End_Object +End + +Test to make sure Parse did it's job +MinimumThickness = 0.3 +MinimumArea = 5 +Test 2, test a triangular polygon +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 0.5000000000000000 0.5000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000))) + POINT (0.2500023796612 0.2499999998188) + POINT (0.6666694869935 0.1666603207523) + POINT (0.1666716028442 0.6666666666667) +Test 3, test for too thin +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.5000000000000000, 0.0125000000000000 0.5000000000000000, 0.0125000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000))) diff --git a/isis/src/base/objs/LimitPolygonSeeder/Makefile b/isis/src/base/objs/LimitPolygonSeeder/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5b2553973f8f6339c5a7f89941a498884dc96d97 --- /dev/null +++ b/isis/src/base/objs/LimitPolygonSeeder/Makefile @@ -0,0 +1,5 @@ +INCS = LimitPolygonSeeder.h +SRCS = LimitPolygonSeeder.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/LimitPolygonSeeder/PolygonSeeder.plugin b/isis/src/base/objs/LimitPolygonSeeder/PolygonSeeder.plugin new file mode 100644 index 0000000000000000000000000000000000000000..3f419571da250319a8562259a3193cf3c0d31da7 --- /dev/null +++ b/isis/src/base/objs/LimitPolygonSeeder/PolygonSeeder.plugin @@ -0,0 +1,4 @@ +Group = Limit + Library = LimitPolygonSeeder + Routine = LimitPolygonSeederPlugin +End_Group diff --git a/isis/src/base/objs/LimitPolygonSeeder/unitTest.cpp b/isis/src/base/objs/LimitPolygonSeeder/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f8f1e213b4b730e8bfde7c555c0dfdba35ac4249 --- /dev/null +++ b/isis/src/base/objs/LimitPolygonSeeder/unitTest.cpp @@ -0,0 +1,165 @@ +#include +#include +#include +#include + +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/geom/Geometry.h" +#include "geos/geom/Polygon.h" + +#include "iException.h" +#include "PolygonTools.h" +#include "PolygonSeeder.h" +#include "PolygonSeederFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "ProjectionFactory.h" +#include "GridPolygonSeeder.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + try { + cout << "Test 1, create a seeder" << endl; + + PvlGroup alg("PolygonSeederAlgorithm"); + + if(!alg.HasKeyword("Name")) { + alg += PvlKeyword("Name","Limit"); + alg += PvlKeyword("MinimumThickness", 0.3); + alg += PvlKeyword("MinimumArea", 5); + alg += PvlKeyword("MajorAxisPoints", 2); + alg += PvlKeyword("MinorAxisPoints", 2); + } + + PvlObject o("AutoSeed"); + o.AddGroup(alg); + + Pvl pvl; + pvl.AddObject(o); + cout << pvl << endl << endl; + + PolygonSeeder *ps = PolygonSeederFactory::Create(pvl); + + std::cout << "Test to make sure Parse did it's job" << std::endl; + std::cout << "MinimumThickness = " << ps->MinimumThickness() << std::endl; + std::cout << "MinimumArea = " << ps->MinimumArea() << std::endl; + + + cout << "Test 2, test a triangular polygon" << endl; + try { + // Call the seed member with a polygon + geos::geom::CoordinateSequence *pts; + vector polys; + + // Create the A polygon + pts = new geos::geom::CoordinateArraySequence (); + pts->add (geos::geom::Coordinate (0, 0)); + pts->add (geos::geom::Coordinate (0, 1)); + pts->add (geos::geom::Coordinate (0.5, 0.5)); + pts->add (geos::geom::Coordinate (1, 0)); + pts->add (geos::geom::Coordinate (0, 0)); + + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing(pts),NULL)); + + geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon (polys); + + cout << "Lon/Lat polygon = " << mp->toString() << endl; + // Create the projection necessary for seeding + PvlGroup radii = Projection::TargetRadii("MARS"); + Isis::Pvl maplab; + maplab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = maplab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",(string)radii["EquatorialRadius"]); + mapGroup += Isis::PvlKeyword("PolarRadius",(string)radii["PolarRadius"]); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetocentric"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",360); + mapGroup += Isis::PvlKeyword("CenterLatitude",0); + mapGroup += Isis::PvlKeyword("CenterLongitude",0); + mapGroup += Isis::PvlKeyword("ProjectionName","Sinusoidal"); + + Projection *proj = Isis::ProjectionFactory::Create(maplab); + + geos::geom::MultiPolygon *xymp = PolygonTools::LatLonToXY(*mp, proj); + vector seedValues = ps->Seed(xymp); + + vector points; + for( unsigned int pt = 0; pt < seedValues.size(); pt ++) { + if (proj->SetCoordinate(seedValues[pt]->getX(),seedValues[pt]->getY())) { + points.push_back(Isis::globalFactory.createPoint( + geos::geom::Coordinate(proj->UniversalLongitude(), + proj->UniversalLatitude()))); + } + else { + iString msg = "Unable to convert to a (lon,lat)"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + cout << setprecision(13); + for (unsigned int i=0; igetX() << " " << points[i]->getY() << ")" << endl; + } + } + catch (iException &e) { + e.Report(); + } + + cout << "Test 3, test for too thin" << endl; + try { + // Call the seed member with a polygon + geos::geom::CoordinateSequence *pts; + vector polys; + + // Create the A polygon + pts = new geos::geom::CoordinateArraySequence (); + pts->add (geos::geom::Coordinate (0, 0)); + pts->add (geos::geom::Coordinate (0, 0.5)); + pts->add (geos::geom::Coordinate (0.0125, 0.5)); + pts->add (geos::geom::Coordinate (0.0125, 0)); + pts->add (geos::geom::Coordinate (0, 0)); + + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing(pts),NULL)); + + geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon (polys); + + cout << "Lon/Lat polygon = " << mp->toString() << endl; + + // Create the projection necessary for seeding + PvlGroup radii = Projection::TargetRadii("MARS"); + Isis::Pvl maplab; + maplab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = maplab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",(string)radii["EquatorialRadius"]); + mapGroup += Isis::PvlKeyword("PolarRadius",(string)radii["PolarRadius"]); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetocentric"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",360); + mapGroup += Isis::PvlKeyword("CenterLatitude",0); + mapGroup += Isis::PvlKeyword("CenterLongitude",0); + mapGroup += Isis::PvlKeyword("ProjectionName","Sinusoidal"); + //Projection *proj = Isis::ProjectionFactory::Create(maplab); + + // NOTHING SHOULD BE PRINTED (the thickness test should not have been met) + vector seedValues = ps->Seed(mp); + for (unsigned int i=0; i +#include + +using namespace std; + +namespace Isis { + /** + * Construct an empty LineEquation object + */ + LineEquation::LineEquation() { + p_defined = false; + p_slopeDefined = false; + p_interceptDefined = false; + } + + /** + * Construct and fill LineEquation object + * @param x1 Double First independent variable + * @param y1 Double First dependent variable + * @param x2 Double Second independent variable + * @param y2 Double Second dependent variable + */ + LineEquation::LineEquation(double x1, double y1, double x2, double y2) { + p_defined = false; + p_slopeDefined = false; + p_interceptDefined = false; + AddPoint(x1, y1); + AddPoint(x2, y2); + p_defined = true; + p_slope = Slope(); + p_intercept = Intercept(); + } + + /** + * Add a point to the object. The object is considered filled + * once 2 points have been added (the line is defined). + * + * @param x Double Independent variable + * @param y Double Dependent variable + * + */ + void LineEquation::AddPoint(double x, double y) { + if (p_defined) { + std::string msg = "Line equation is already defined with 2 points"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + p_x.push_back(x); + p_y.push_back(y); + if ( Points() == 2) p_defined = true; + } + + /** + * Compute the slope of the line + * + * @return double The slope of the line if it exists + */ + double LineEquation::Slope() { + if (!p_defined) { + std::string msg = "Line equation undefined: 2 points are required"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + else if (p_x[0] == p_x[1]) { + std::string msg = "Points have identical independent variables -- no slope"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + else if (!p_slopeDefined) { + p_slope = (p_y[0] - p_y[1]) / (p_x[0] - p_x[1]); + } + return p_slope; + } + + /** + * Compute the intercept of the line + * + * @return double The y-intercept of the line if it exists + */ + double LineEquation::Intercept() { + if (!p_defined) { + std::string msg = "Line equation undefined: 2 points are required"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + else if (p_x[0] == p_x[1]) { + std::string msg = "Points have identical independent variables -- no intercept"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + else if (!p_interceptDefined) { + p_intercept = p_y[0] - Slope()*p_x[0]; + } + + return p_intercept; + } + +} diff --git a/isis/src/base/objs/LineEquation/LineEquation.h b/isis/src/base/objs/LineEquation/LineEquation.h new file mode 100644 index 0000000000000000000000000000000000000000..6db8b1a97294dfd493d0a8262d1c685a52d164a9 --- /dev/null +++ b/isis/src/base/objs/LineEquation/LineEquation.h @@ -0,0 +1,70 @@ +#if !defined(LineEquation_h) +#define LineEquation_h +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +namespace Isis { + /** + * @brief Utility class for creating and using cartesean line equations + * + * This class contains utility methods for creating and using cartesean + * line equations. If both points have the same value for the independent + * variable (vertical line) an error is thrown. + * + * @ingroup Utility + * + * @author 2006-10-19 Debbie A. Cook + * + * @todo Add constructor with arguments (double slope, double intercept) + * Add method to double y = EvaluateLine( double x ) + * + */ + class LineEquation { + public: +//! Constructors + LineEquation(); + LineEquation( double x1, double y1, double x2, double y2 ); + +//! Destroys the LineEquation object + ~LineEquation() {} + void AddPoint(double x, double y); + double Slope(); + double Intercept(); + int Points() { return p_x.size(); }; + bool HaveSlope() { return p_slopeDefined; }; + bool HaveIntercept() { return p_interceptDefined; }; + bool Defined() { return p_defined; }; + + private: + std::vector p_x; //!< Independent variables + std::vector p_y; //!< Dependent variables + bool p_defined; //!< Variable indicating if line is defined yet + bool p_slopeDefined; //!< Variable indicating if slope is defined yet + bool p_interceptDefined; //!< Variable indicating if intercept is defined yet + double p_slope; + double p_intercept; + + }; // end of LineEquation class +} +#endif diff --git a/isis/src/base/objs/LineEquation/LineEquation.truth b/isis/src/base/objs/LineEquation/LineEquation.truth new file mode 100644 index 0000000000000000000000000000000000000000..29e90dc1fe46f16cf390ced1d1108897678e735b --- /dev/null +++ b/isis/src/base/objs/LineEquation/LineEquation.truth @@ -0,0 +1,7 @@ +Unit test for LineEquation +Testing first constructor... + Slope = 2.5 + Intercept = -1.5 +Testing second constructor... + Slope = -0.5 + Intercept = 0.5 diff --git a/isis/src/base/objs/LineEquation/Makefile b/isis/src/base/objs/LineEquation/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3ee8d709bc351a1bc7d0c840e35bf7fec0f7a619 --- /dev/null +++ b/isis/src/base/objs/LineEquation/Makefile @@ -0,0 +1,5 @@ +INCS = LineEquation.h +SRCS = LineEquation.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/LineEquation/unitTest.cpp b/isis/src/base/objs/LineEquation/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..917c51a398fa29b3b3fe5d9c2149020c2c211dff --- /dev/null +++ b/isis/src/base/objs/LineEquation/unitTest.cpp @@ -0,0 +1,30 @@ +#include +#include +#include "LineEquation.h" +#include "Filename.h" +#include "Preference.h" +#include "Table.h" + + + +using namespace std; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << setprecision(8); + cout << "Unit test for LineEquation" << endl; + + cout << "Testing first constructor..." << endl; + Isis::LineEquation line1; + line1.AddPoint(1.,1.); + line1.AddPoint(3.,6.); + cout << " Slope = " << line1.Slope() << endl; + cout << " Intercept = " << line1.Intercept() << endl; + + cout << "Testing second constructor..." << endl; + Isis::LineEquation line2(-1.,1.,-3.,2.); + cout << " Slope = " << line2.Slope() << endl; + cout << " Intercept = " << line2.Intercept() << endl; + +} diff --git a/isis/src/base/objs/LineManager/LineManager.cpp b/isis/src/base/objs/LineManager/LineManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8148f5f36415889ecfcb73b427ca46ef8f61c4b6 --- /dev/null +++ b/isis/src/base/objs/LineManager/LineManager.cpp @@ -0,0 +1,71 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/12/06 23:51:31 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "LineManager.h" + +using namespace std; +namespace Isis { + + /** + * Constructs a LineManager object + * + * @param cube The cube this buffer manager will be associated with. + * + * @param reverse Modifies the order of progression LineManager + * takes through the cube. By default, progresses + * lines first then bands. If reverse = true, then + * the buffer progresses bands first, then lines. + */ + + LineManager::LineManager(const Isis::Cube &cube, const bool reverse) : + Isis::BufferManager(cube.Samples(),cube.Lines(), + cube.Bands(),cube.Samples(),1,1, + cube.PixelType(), reverse ) { + } + + /** + * Positions the buffer at the requested line and returns a status indicator + * if the set was succesful or not + * + * @param line The line number within a band (1-based). + * + * @param band The band number within the cube (1-based). Defaults to 1 + * + * @return bool Status indicator of the set being successful or not + */ + + bool LineManager::SetLine (const int line, const int band) { + if (line < 1) { + string message = "Invalid value for argument [line]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + if (band < 1) { + string message = "Invalid value for argument [band]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + int map = (band - 1) * MaxLines() + line - 1; + return setpos(map); + } + +} // end namespace isis diff --git a/isis/src/base/objs/LineManager/LineManager.h b/isis/src/base/objs/LineManager/LineManager.h new file mode 100644 index 0000000000000000000000000000000000000000..cf96c7523a96fd2fb3e21cb7ea0315f5cd4c1423 --- /dev/null +++ b/isis/src/base/objs/LineManager/LineManager.h @@ -0,0 +1,68 @@ +#if !defined(LineManager_h) +#define LineManager_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/12/06 23:51:31 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "BufferManager.h" +#include "Cube.h" + +namespace Isis { +/** + * @brief Buffer manager, for moving through a cube in lines + * + * This class is used as a manager for moving through a cube one line at a time. + * A line is defined as a one dimensional sub-area of a cube. That is, the + * number of samples by 1 line by 1 band (ns,1,1). The manager moves this + * (ns,1,1) shape through the cube sequentially accessing all the lines in the + * first band before proceeding to the second band. + * + * If you would like to see LineManager being used in implementation, + * see the ProcessByLine class. + * + * @ingroup LowLevelCubeIO + * + * @author 2003-02-13 Jeff Anderson + * + * @internal + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2005-02-28 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2007-12-06 Chris Austin - Added option + * to constructor to change the order of the + * progression through the cube + */ + class LineManager : public Isis::BufferManager { + + public: + // Constructors and Destructors + LineManager(const Isis::Cube &cube, const bool reverse=false); + + //! Destroys the LineManager object + ~LineManager() {}; + + bool SetLine(const int line, const int band=1 ); + }; +}; + +#endif + diff --git a/isis/src/base/objs/LineManager/LineManager.truth b/isis/src/base/objs/LineManager/LineManager.truth new file mode 100644 index 0000000000000000000000000000000000000000..9b4c2aa2b69377ccadb708570618a99629f48376 --- /dev/null +++ b/isis/src/base/objs/LineManager/LineManager.truth @@ -0,0 +1,518 @@ +Buffer Size: 126 1 1 + + Current sample, line, band is: 1 1 1 + Current sample, line, band is: 1 2 1 + Current sample, line, band is: 1 3 1 + Current sample, line, band is: 1 4 1 + Current sample, line, band is: 1 5 1 + Current sample, line, band is: 1 6 1 + Current sample, line, band is: 1 7 1 + Current sample, line, band is: 1 8 1 + Current sample, line, band is: 1 9 1 + Current sample, line, band is: 1 10 1 + Current sample, line, band is: 1 11 1 + Current sample, line, band is: 1 12 1 + Current sample, line, band is: 1 13 1 + Current sample, line, band is: 1 14 1 + Current sample, line, band is: 1 15 1 + Current sample, line, band is: 1 16 1 + Current sample, line, band is: 1 17 1 + Current sample, line, band is: 1 18 1 + Current sample, line, band is: 1 19 1 + Current sample, line, band is: 1 20 1 + Current sample, line, band is: 1 21 1 + Current sample, line, band is: 1 22 1 + Current sample, line, band is: 1 23 1 + Current sample, line, band is: 1 24 1 + Current sample, line, band is: 1 25 1 + Current sample, line, band is: 1 26 1 + Current sample, line, band is: 1 27 1 + Current sample, line, band is: 1 28 1 + Current sample, line, band is: 1 29 1 + Current sample, line, band is: 1 30 1 + Current sample, line, band is: 1 31 1 + Current sample, line, band is: 1 32 1 + Current sample, line, band is: 1 33 1 + Current sample, line, band is: 1 34 1 + Current sample, line, band is: 1 35 1 + Current sample, line, band is: 1 36 1 + Current sample, line, band is: 1 37 1 + Current sample, line, band is: 1 38 1 + Current sample, line, band is: 1 39 1 + Current sample, line, band is: 1 40 1 + Current sample, line, band is: 1 41 1 + Current sample, line, band is: 1 42 1 + Current sample, line, band is: 1 43 1 + Current sample, line, band is: 1 44 1 + Current sample, line, band is: 1 45 1 + Current sample, line, band is: 1 46 1 + Current sample, line, band is: 1 47 1 + Current sample, line, band is: 1 48 1 + Current sample, line, band is: 1 49 1 + Current sample, line, band is: 1 50 1 + Current sample, line, band is: 1 51 1 + Current sample, line, band is: 1 52 1 + Current sample, line, band is: 1 53 1 + Current sample, line, band is: 1 54 1 + Current sample, line, band is: 1 55 1 + Current sample, line, band is: 1 56 1 + Current sample, line, band is: 1 57 1 + Current sample, line, band is: 1 58 1 + Current sample, line, band is: 1 59 1 + Current sample, line, band is: 1 60 1 + Current sample, line, band is: 1 61 1 + Current sample, line, band is: 1 62 1 + Current sample, line, band is: 1 63 1 + Current sample, line, band is: 1 64 1 + Current sample, line, band is: 1 65 1 + Current sample, line, band is: 1 66 1 + Current sample, line, band is: 1 67 1 + Current sample, line, band is: 1 68 1 + Current sample, line, band is: 1 69 1 + Current sample, line, band is: 1 70 1 + Current sample, line, band is: 1 71 1 + Current sample, line, band is: 1 72 1 + Current sample, line, band is: 1 73 1 + Current sample, line, band is: 1 74 1 + Current sample, line, band is: 1 75 1 + Current sample, line, band is: 1 76 1 + Current sample, line, band is: 1 77 1 + Current sample, line, band is: 1 78 1 + Current sample, line, band is: 1 79 1 + Current sample, line, band is: 1 80 1 + Current sample, line, band is: 1 81 1 + Current sample, line, band is: 1 82 1 + Current sample, line, band is: 1 83 1 + Current sample, line, band is: 1 84 1 + Current sample, line, band is: 1 85 1 + Current sample, line, band is: 1 86 1 + Current sample, line, band is: 1 87 1 + Current sample, line, band is: 1 88 1 + Current sample, line, band is: 1 89 1 + Current sample, line, band is: 1 90 1 + Current sample, line, band is: 1 91 1 + Current sample, line, band is: 1 92 1 + Current sample, line, band is: 1 93 1 + Current sample, line, band is: 1 94 1 + Current sample, line, band is: 1 95 1 + Current sample, line, band is: 1 96 1 + Current sample, line, band is: 1 97 1 + Current sample, line, band is: 1 98 1 + Current sample, line, band is: 1 99 1 + Current sample, line, band is: 1 100 1 + Current sample, line, band is: 1 101 1 + Current sample, line, band is: 1 102 1 + Current sample, line, band is: 1 103 1 + Current sample, line, band is: 1 104 1 + Current sample, line, band is: 1 105 1 + Current sample, line, band is: 1 106 1 + Current sample, line, band is: 1 107 1 + Current sample, line, band is: 1 108 1 + Current sample, line, band is: 1 109 1 + Current sample, line, band is: 1 110 1 + Current sample, line, band is: 1 111 1 + Current sample, line, band is: 1 112 1 + Current sample, line, band is: 1 113 1 + Current sample, line, band is: 1 114 1 + Current sample, line, band is: 1 115 1 + Current sample, line, band is: 1 116 1 + Current sample, line, band is: 1 117 1 + Current sample, line, band is: 1 118 1 + Current sample, line, band is: 1 119 1 + Current sample, line, band is: 1 120 1 + Current sample, line, band is: 1 121 1 + Current sample, line, band is: 1 122 1 + Current sample, line, band is: 1 123 1 + Current sample, line, band is: 1 124 1 + Current sample, line, band is: 1 125 1 + Current sample, line, band is: 1 126 1 + Current sample, line, band is: 1 1 2 + Current sample, line, band is: 1 2 2 + Current sample, line, band is: 1 3 2 + Current sample, line, band is: 1 4 2 + Current sample, line, band is: 1 5 2 + Current sample, line, band is: 1 6 2 + Current sample, line, band is: 1 7 2 + Current sample, line, band is: 1 8 2 + Current sample, line, band is: 1 9 2 + Current sample, line, band is: 1 10 2 + Current sample, line, band is: 1 11 2 + Current sample, line, band is: 1 12 2 + Current sample, line, band is: 1 13 2 + Current sample, line, band is: 1 14 2 + Current sample, line, band is: 1 15 2 + Current sample, line, band is: 1 16 2 + Current sample, line, band is: 1 17 2 + Current sample, line, band is: 1 18 2 + Current sample, line, band is: 1 19 2 + Current sample, line, band is: 1 20 2 + Current sample, line, band is: 1 21 2 + Current sample, line, band is: 1 22 2 + Current sample, line, band is: 1 23 2 + Current sample, line, band is: 1 24 2 + Current sample, line, band is: 1 25 2 + Current sample, line, band is: 1 26 2 + Current sample, line, band is: 1 27 2 + Current sample, line, band is: 1 28 2 + Current sample, line, band is: 1 29 2 + Current sample, line, band is: 1 30 2 + Current sample, line, band is: 1 31 2 + Current sample, line, band is: 1 32 2 + Current sample, line, band is: 1 33 2 + Current sample, line, band is: 1 34 2 + Current sample, line, band is: 1 35 2 + Current sample, line, band is: 1 36 2 + Current sample, line, band is: 1 37 2 + Current sample, line, band is: 1 38 2 + Current sample, line, band is: 1 39 2 + Current sample, line, band is: 1 40 2 + Current sample, line, band is: 1 41 2 + Current sample, line, band is: 1 42 2 + Current sample, line, band is: 1 43 2 + Current sample, line, band is: 1 44 2 + Current sample, line, band is: 1 45 2 + Current sample, line, band is: 1 46 2 + Current sample, line, band is: 1 47 2 + Current sample, line, band is: 1 48 2 + Current sample, line, band is: 1 49 2 + Current sample, line, band is: 1 50 2 + Current sample, line, band is: 1 51 2 + Current sample, line, band is: 1 52 2 + Current sample, line, band is: 1 53 2 + Current sample, line, band is: 1 54 2 + Current sample, line, band is: 1 55 2 + Current sample, line, band is: 1 56 2 + Current sample, line, band is: 1 57 2 + Current sample, line, band is: 1 58 2 + Current sample, line, band is: 1 59 2 + Current sample, line, band is: 1 60 2 + Current sample, line, band is: 1 61 2 + Current sample, line, band is: 1 62 2 + Current sample, line, band is: 1 63 2 + Current sample, line, band is: 1 64 2 + Current sample, line, band is: 1 65 2 + Current sample, line, band is: 1 66 2 + Current sample, line, band is: 1 67 2 + Current sample, line, band is: 1 68 2 + Current sample, line, band is: 1 69 2 + Current sample, line, band is: 1 70 2 + Current sample, line, band is: 1 71 2 + Current sample, line, band is: 1 72 2 + Current sample, line, band is: 1 73 2 + Current sample, line, band is: 1 74 2 + Current sample, line, band is: 1 75 2 + Current sample, line, band is: 1 76 2 + Current sample, line, band is: 1 77 2 + Current sample, line, band is: 1 78 2 + Current sample, line, band is: 1 79 2 + Current sample, line, band is: 1 80 2 + Current sample, line, band is: 1 81 2 + Current sample, line, band is: 1 82 2 + Current sample, line, band is: 1 83 2 + Current sample, line, band is: 1 84 2 + Current sample, line, band is: 1 85 2 + Current sample, line, band is: 1 86 2 + Current sample, line, band is: 1 87 2 + Current sample, line, band is: 1 88 2 + Current sample, line, band is: 1 89 2 + Current sample, line, band is: 1 90 2 + Current sample, line, band is: 1 91 2 + Current sample, line, band is: 1 92 2 + Current sample, line, band is: 1 93 2 + Current sample, line, band is: 1 94 2 + Current sample, line, band is: 1 95 2 + Current sample, line, band is: 1 96 2 + Current sample, line, band is: 1 97 2 + Current sample, line, band is: 1 98 2 + Current sample, line, band is: 1 99 2 + Current sample, line, band is: 1 100 2 + Current sample, line, band is: 1 101 2 + Current sample, line, band is: 1 102 2 + Current sample, line, band is: 1 103 2 + Current sample, line, band is: 1 104 2 + Current sample, line, band is: 1 105 2 + Current sample, line, band is: 1 106 2 + Current sample, line, band is: 1 107 2 + Current sample, line, band is: 1 108 2 + Current sample, line, band is: 1 109 2 + Current sample, line, band is: 1 110 2 + Current sample, line, band is: 1 111 2 + Current sample, line, band is: 1 112 2 + Current sample, line, band is: 1 113 2 + Current sample, line, band is: 1 114 2 + Current sample, line, band is: 1 115 2 + Current sample, line, band is: 1 116 2 + Current sample, line, band is: 1 117 2 + Current sample, line, band is: 1 118 2 + Current sample, line, band is: 1 119 2 + Current sample, line, band is: 1 120 2 + Current sample, line, band is: 1 121 2 + Current sample, line, band is: 1 122 2 + Current sample, line, band is: 1 123 2 + Current sample, line, band is: 1 124 2 + Current sample, line, band is: 1 125 2 + Current sample, line, band is: 1 126 2 + +Buffer Size: 126 1 1 + + Current sample, line, band is: 1 1 1 + Current sample, line, band is: 1 1 2 + Current sample, line, band is: 1 2 1 + Current sample, line, band is: 1 2 2 + Current sample, line, band is: 1 3 1 + Current sample, line, band is: 1 3 2 + Current sample, line, band is: 1 4 1 + Current sample, line, band is: 1 4 2 + Current sample, line, band is: 1 5 1 + Current sample, line, band is: 1 5 2 + Current sample, line, band is: 1 6 1 + Current sample, line, band is: 1 6 2 + Current sample, line, band is: 1 7 1 + Current sample, line, band is: 1 7 2 + Current sample, line, band is: 1 8 1 + Current sample, line, band is: 1 8 2 + Current sample, line, band is: 1 9 1 + Current sample, line, band is: 1 9 2 + Current sample, line, band is: 1 10 1 + Current sample, line, band is: 1 10 2 + Current sample, line, band is: 1 11 1 + Current sample, line, band is: 1 11 2 + Current sample, line, band is: 1 12 1 + Current sample, line, band is: 1 12 2 + Current sample, line, band is: 1 13 1 + Current sample, line, band is: 1 13 2 + Current sample, line, band is: 1 14 1 + Current sample, line, band is: 1 14 2 + Current sample, line, band is: 1 15 1 + Current sample, line, band is: 1 15 2 + Current sample, line, band is: 1 16 1 + Current sample, line, band is: 1 16 2 + Current sample, line, band is: 1 17 1 + Current sample, line, band is: 1 17 2 + Current sample, line, band is: 1 18 1 + Current sample, line, band is: 1 18 2 + Current sample, line, band is: 1 19 1 + Current sample, line, band is: 1 19 2 + Current sample, line, band is: 1 20 1 + Current sample, line, band is: 1 20 2 + Current sample, line, band is: 1 21 1 + Current sample, line, band is: 1 21 2 + Current sample, line, band is: 1 22 1 + Current sample, line, band is: 1 22 2 + Current sample, line, band is: 1 23 1 + Current sample, line, band is: 1 23 2 + Current sample, line, band is: 1 24 1 + Current sample, line, band is: 1 24 2 + Current sample, line, band is: 1 25 1 + Current sample, line, band is: 1 25 2 + Current sample, line, band is: 1 26 1 + Current sample, line, band is: 1 26 2 + Current sample, line, band is: 1 27 1 + Current sample, line, band is: 1 27 2 + Current sample, line, band is: 1 28 1 + Current sample, line, band is: 1 28 2 + Current sample, line, band is: 1 29 1 + Current sample, line, band is: 1 29 2 + Current sample, line, band is: 1 30 1 + Current sample, line, band is: 1 30 2 + Current sample, line, band is: 1 31 1 + Current sample, line, band is: 1 31 2 + Current sample, line, band is: 1 32 1 + Current sample, line, band is: 1 32 2 + Current sample, line, band is: 1 33 1 + Current sample, line, band is: 1 33 2 + Current sample, line, band is: 1 34 1 + Current sample, line, band is: 1 34 2 + Current sample, line, band is: 1 35 1 + Current sample, line, band is: 1 35 2 + Current sample, line, band is: 1 36 1 + Current sample, line, band is: 1 36 2 + Current sample, line, band is: 1 37 1 + Current sample, line, band is: 1 37 2 + Current sample, line, band is: 1 38 1 + Current sample, line, band is: 1 38 2 + Current sample, line, band is: 1 39 1 + Current sample, line, band is: 1 39 2 + Current sample, line, band is: 1 40 1 + Current sample, line, band is: 1 40 2 + Current sample, line, band is: 1 41 1 + Current sample, line, band is: 1 41 2 + Current sample, line, band is: 1 42 1 + Current sample, line, band is: 1 42 2 + Current sample, line, band is: 1 43 1 + Current sample, line, band is: 1 43 2 + Current sample, line, band is: 1 44 1 + Current sample, line, band is: 1 44 2 + Current sample, line, band is: 1 45 1 + Current sample, line, band is: 1 45 2 + Current sample, line, band is: 1 46 1 + Current sample, line, band is: 1 46 2 + Current sample, line, band is: 1 47 1 + Current sample, line, band is: 1 47 2 + Current sample, line, band is: 1 48 1 + Current sample, line, band is: 1 48 2 + Current sample, line, band is: 1 49 1 + Current sample, line, band is: 1 49 2 + Current sample, line, band is: 1 50 1 + Current sample, line, band is: 1 50 2 + Current sample, line, band is: 1 51 1 + Current sample, line, band is: 1 51 2 + Current sample, line, band is: 1 52 1 + Current sample, line, band is: 1 52 2 + Current sample, line, band is: 1 53 1 + Current sample, line, band is: 1 53 2 + Current sample, line, band is: 1 54 1 + Current sample, line, band is: 1 54 2 + Current sample, line, band is: 1 55 1 + Current sample, line, band is: 1 55 2 + Current sample, line, band is: 1 56 1 + Current sample, line, band is: 1 56 2 + Current sample, line, band is: 1 57 1 + Current sample, line, band is: 1 57 2 + Current sample, line, band is: 1 58 1 + Current sample, line, band is: 1 58 2 + Current sample, line, band is: 1 59 1 + Current sample, line, band is: 1 59 2 + Current sample, line, band is: 1 60 1 + Current sample, line, band is: 1 60 2 + Current sample, line, band is: 1 61 1 + Current sample, line, band is: 1 61 2 + Current sample, line, band is: 1 62 1 + Current sample, line, band is: 1 62 2 + Current sample, line, band is: 1 63 1 + Current sample, line, band is: 1 63 2 + Current sample, line, band is: 1 64 1 + Current sample, line, band is: 1 64 2 + Current sample, line, band is: 1 65 1 + Current sample, line, band is: 1 65 2 + Current sample, line, band is: 1 66 1 + Current sample, line, band is: 1 66 2 + Current sample, line, band is: 1 67 1 + Current sample, line, band is: 1 67 2 + Current sample, line, band is: 1 68 1 + Current sample, line, band is: 1 68 2 + Current sample, line, band is: 1 69 1 + Current sample, line, band is: 1 69 2 + Current sample, line, band is: 1 70 1 + Current sample, line, band is: 1 70 2 + Current sample, line, band is: 1 71 1 + Current sample, line, band is: 1 71 2 + Current sample, line, band is: 1 72 1 + Current sample, line, band is: 1 72 2 + Current sample, line, band is: 1 73 1 + Current sample, line, band is: 1 73 2 + Current sample, line, band is: 1 74 1 + Current sample, line, band is: 1 74 2 + Current sample, line, band is: 1 75 1 + Current sample, line, band is: 1 75 2 + Current sample, line, band is: 1 76 1 + Current sample, line, band is: 1 76 2 + Current sample, line, band is: 1 77 1 + Current sample, line, band is: 1 77 2 + Current sample, line, band is: 1 78 1 + Current sample, line, band is: 1 78 2 + Current sample, line, band is: 1 79 1 + Current sample, line, band is: 1 79 2 + Current sample, line, band is: 1 80 1 + Current sample, line, band is: 1 80 2 + Current sample, line, band is: 1 81 1 + Current sample, line, band is: 1 81 2 + Current sample, line, band is: 1 82 1 + Current sample, line, band is: 1 82 2 + Current sample, line, band is: 1 83 1 + Current sample, line, band is: 1 83 2 + Current sample, line, band is: 1 84 1 + Current sample, line, band is: 1 84 2 + Current sample, line, band is: 1 85 1 + Current sample, line, band is: 1 85 2 + Current sample, line, band is: 1 86 1 + Current sample, line, band is: 1 86 2 + Current sample, line, band is: 1 87 1 + Current sample, line, band is: 1 87 2 + Current sample, line, band is: 1 88 1 + Current sample, line, band is: 1 88 2 + Current sample, line, band is: 1 89 1 + Current sample, line, band is: 1 89 2 + Current sample, line, band is: 1 90 1 + Current sample, line, band is: 1 90 2 + Current sample, line, band is: 1 91 1 + Current sample, line, band is: 1 91 2 + Current sample, line, band is: 1 92 1 + Current sample, line, band is: 1 92 2 + Current sample, line, band is: 1 93 1 + Current sample, line, band is: 1 93 2 + Current sample, line, band is: 1 94 1 + Current sample, line, band is: 1 94 2 + Current sample, line, band is: 1 95 1 + Current sample, line, band is: 1 95 2 + Current sample, line, band is: 1 96 1 + Current sample, line, band is: 1 96 2 + Current sample, line, band is: 1 97 1 + Current sample, line, band is: 1 97 2 + Current sample, line, band is: 1 98 1 + Current sample, line, band is: 1 98 2 + Current sample, line, band is: 1 99 1 + Current sample, line, band is: 1 99 2 + Current sample, line, band is: 1 100 1 + Current sample, line, band is: 1 100 2 + Current sample, line, band is: 1 101 1 + Current sample, line, band is: 1 101 2 + Current sample, line, band is: 1 102 1 + Current sample, line, band is: 1 102 2 + Current sample, line, band is: 1 103 1 + Current sample, line, band is: 1 103 2 + Current sample, line, band is: 1 104 1 + Current sample, line, band is: 1 104 2 + Current sample, line, band is: 1 105 1 + Current sample, line, band is: 1 105 2 + Current sample, line, band is: 1 106 1 + Current sample, line, band is: 1 106 2 + Current sample, line, band is: 1 107 1 + Current sample, line, band is: 1 107 2 + Current sample, line, band is: 1 108 1 + Current sample, line, band is: 1 108 2 + Current sample, line, band is: 1 109 1 + Current sample, line, band is: 1 109 2 + Current sample, line, band is: 1 110 1 + Current sample, line, band is: 1 110 2 + Current sample, line, band is: 1 111 1 + Current sample, line, band is: 1 111 2 + Current sample, line, band is: 1 112 1 + Current sample, line, band is: 1 112 2 + Current sample, line, band is: 1 113 1 + Current sample, line, band is: 1 113 2 + Current sample, line, band is: 1 114 1 + Current sample, line, band is: 1 114 2 + Current sample, line, band is: 1 115 1 + Current sample, line, band is: 1 115 2 + Current sample, line, band is: 1 116 1 + Current sample, line, band is: 1 116 2 + Current sample, line, band is: 1 117 1 + Current sample, line, band is: 1 117 2 + Current sample, line, band is: 1 118 1 + Current sample, line, band is: 1 118 2 + Current sample, line, band is: 1 119 1 + Current sample, line, band is: 1 119 2 + Current sample, line, band is: 1 120 1 + Current sample, line, band is: 1 120 2 + Current sample, line, band is: 1 121 1 + Current sample, line, band is: 1 121 2 + Current sample, line, band is: 1 122 1 + Current sample, line, band is: 1 122 2 + Current sample, line, band is: 1 123 1 + Current sample, line, band is: 1 123 2 + Current sample, line, band is: 1 124 1 + Current sample, line, band is: 1 124 2 + Current sample, line, band is: 1 125 1 + Current sample, line, band is: 1 125 2 + Current sample, line, band is: 1 126 1 + Current sample, line, band is: 1 126 2 + + Current sample, line, band is: 1 50 1 + +Testing errors ... +**PROGRAMMER ERROR** Invalid value for argument [line] + +Testing errors ... +**PROGRAMMER ERROR** Invalid value for argument [band] + diff --git a/isis/src/base/objs/LineManager/Makefile b/isis/src/base/objs/LineManager/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..41512d955d3b28fb8e5bde64a215324a131a805a --- /dev/null +++ b/isis/src/base/objs/LineManager/Makefile @@ -0,0 +1,5 @@ +INCS = LineManager.h +SRCS = LineManager.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/LineManager/unitTest.cpp b/isis/src/base/objs/LineManager/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c409e89892cb4609e5c0436945fde03ecdc5d30 --- /dev/null +++ b/isis/src/base/objs/LineManager/unitTest.cpp @@ -0,0 +1,75 @@ +#include +#include +#include + +#include "Preference.h" +#include "iException.h" +#include "Cube.h" +#include "LineManager.h" + +using namespace std; +int main (int argc, char *argv[]) { + + Isis::Preference::Preferences(true); + + string fname = "$base/testData/isisTruth.cub"; + Isis::Cube cube; + cube.Open (fname); + + Isis::LineManager line(cube); + cout << "Buffer Size: " << + line.SampleDimension() << " " << + line.LineDimension() << " " << + line.BandDimension() << endl; + cout << endl; + + for (line.begin(); !line.end(); line++) { + cout << " Current sample, line, band is: " + << line.Sample() << " " + << line.Line() << " " + << line.Band() << endl; + } + cout << endl; + + Isis::LineManager lineReverse(cube,true); + cout << "Buffer Size: " << + lineReverse.SampleDimension() << " " << + lineReverse.LineDimension() << " " << + lineReverse.BandDimension() << endl; + cout << endl; + + for (lineReverse.begin(); !lineReverse.end(); lineReverse++) { + cout << " Current sample, line, band is: " + << lineReverse.Sample() << " " + << lineReverse.Line() << " " + << lineReverse.Band() << endl; + } + cout << endl; + + line.SetLine(50); + cout << " Current sample, line, band is: " + << line.Sample() << " " + << line.Line() << " " + << line.Band() << endl; + cout << endl; + + try { + cout << "Testing errors ... " << endl; + line.SetLine(0,0); + } + catch (Isis::iException &e) { + e.Report(false); + cout << endl; + } + + try { + cout << "Testing errors ... " << endl; + line.SetLine(1,0); + } + catch (Isis::iException &e) { + e.Report(false); + cout << endl; + } + + cube.Close (); +} diff --git a/isis/src/base/objs/LineScanCamera/LineScanCamera.cpp b/isis/src/base/objs/LineScanCamera/LineScanCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..26cc1f0c0594e7ef6703f0cad51f92c5256424a2 --- /dev/null +++ b/isis/src/base/objs/LineScanCamera/LineScanCamera.cpp @@ -0,0 +1,35 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/08/31 15:11:49 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "LineScanCamera.h" + +namespace Isis { + /** + * Constructs the LineScanCamera object + * + * @param lab Pvl label used to create the parent Camera object + */ + LineScanCamera::LineScanCamera (Isis::Pvl &lab) : Camera (lab) { + } +}; + diff --git a/isis/src/base/objs/LineScanCamera/LineScanCamera.h b/isis/src/base/objs/LineScanCamera/LineScanCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..7b72b013c1ecbcc77562d71c986039b82f1a5b87 --- /dev/null +++ b/isis/src/base/objs/LineScanCamera/LineScanCamera.h @@ -0,0 +1,86 @@ +#ifndef FramingCamera_h +#define FramingCamera_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/08/31 15:11:49 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Camera.h" + +namespace Isis { + class LineScanCameraGroundMap; + class LineScanCameraDetectorMap; + class LineScanCameraSkyMap; + +/** + * @brief Generic class for Line Scan Cameras + * + * This class is used to abstract out line scan camera functionality from + * children classes. + * + * @author 2009-08-26 Steven Lambright + * + * @internal + * @todo Implement more functionality in this class and abstract away from the children + */ + + class LineScanCamera : public Camera { + public: + LineScanCamera(Isis::Pvl &lab); + + virtual CameraType GetCameraType() const { return LineScan; } + + /** + * Returns a pointer to the LineScanCameraGroundMap object + * + * @return LineScanCameraGroundMap* + */ + LineScanCameraGroundMap *GroundMap() { + return (LineScanCameraGroundMap *)Camera::GroundMap(); + }; + + /** + * Returns a pointer to the LineScanCameraSkyMap object + * + * @return LineScanCameraSkyMap* + */ + LineScanCameraSkyMap *SkyMap() { + return (LineScanCameraSkyMap *)Camera::SkyMap(); + }; + + /** + * Returns a pointer to the LineScanCameraDetectorMap object + * + * @return LineScanCameraDetectorMap* + */ + LineScanCameraDetectorMap *DetectorMap() { + return (LineScanCameraDetectorMap *)Camera::DetectorMap(); + }; + + private: + //! Copying cameras is not allowed + LineScanCamera(const LineScanCamera &); + //! Assigning cameras is not allowed + LineScanCamera &operator=(const LineScanCamera&); + }; +}; + +#endif diff --git a/isis/src/base/objs/LineScanCamera/LineScanCamera.truth b/isis/src/base/objs/LineScanCamera/LineScanCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..ed64237ffae45dcdb0e9d297560b7b0f6039583b --- /dev/null +++ b/isis/src/base/objs/LineScanCamera/LineScanCamera.truth @@ -0,0 +1,4 @@ +Camera = Framing? 0 +Camera = LineScan? 1 +Camera = PushFrame? 0 +Camera = Radar? 0 diff --git a/isis/src/base/objs/LineScanCamera/Makefile b/isis/src/base/objs/LineScanCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..244db800d571cc72d2fb1e56416aaa0bb00502cf --- /dev/null +++ b/isis/src/base/objs/LineScanCamera/Makefile @@ -0,0 +1,5 @@ +INCS = LineScanCamera.h +SRCS = LineScanCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/LineScanCamera/unitTest.cpp b/isis/src/base/objs/LineScanCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8223cb24e3864d7eac81f4f8a6df54227a9583b --- /dev/null +++ b/isis/src/base/objs/LineScanCamera/unitTest.cpp @@ -0,0 +1,22 @@ +#include "LineScanCamera.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +class MyCamera : public LineScanCamera { + public: + MyCamera(Isis::Pvl& lab) : Isis::LineScanCamera(lab) { } +}; + +int main() { + Isis::Preference::Preferences(true); + string inputFile = "$ISIS3DATA/mgs/testData/ab102401.lev2.cub"; + Pvl pvl(inputFile); + MyCamera cam(pvl); + + cout << "Camera = Framing? " << (cam.GetCameraType() == Camera::Framing) << std::endl; + cout << "Camera = LineScan? " << (cam.GetCameraType() == Camera::LineScan) << std::endl; + cout << "Camera = PushFrame? " << (cam.GetCameraType() == Camera::PushFrame) << std::endl; + cout << "Camera = Radar? " << (cam.GetCameraType() == Camera::Radar) << std::endl; +} diff --git a/isis/src/base/objs/LineScanCameraDetectorMap/LineScanCameraDetectorMap.cpp b/isis/src/base/objs/LineScanCameraDetectorMap/LineScanCameraDetectorMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f7e984efbdb765c3d970c363cca7b7fd9223e38 --- /dev/null +++ b/isis/src/base/objs/LineScanCameraDetectorMap/LineScanCameraDetectorMap.cpp @@ -0,0 +1,66 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "LineScanCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" + +namespace Isis { + /** Compute parent position from a detector coordinate + * + * This method will compute a parent sample given a + * detector coordinate. The parent line will be computed using the + * the time in the parent camera + * + * @param sample Sample number in the detector + * @param line Line number in the detector + * + * @return conversion successful + */ + bool LineScanCameraDetectorMap::SetDetector(const double sample, + const double line) { + if (!CameraDetectorMap::SetDetector(sample,line)) return false; + double etDiff = p_camera->EphemerisTime() - p_etStart; + p_parentLine = etDiff / p_lineRate + 0.5; + return true; + } + + /** Compute detector position from a parent image coordinate + * + * This method will compute the detector position from the parent + * line/sample coordinate. The parent line will be used to set the + * appropriate time in the parent camera. + * + * @param sample Sample number in the parent image + * @param line Line number in the parent image + * + * @return conversion successful + */ + bool LineScanCameraDetectorMap::SetParent(const double sample, + const double line) { + if (!CameraDetectorMap::SetParent(sample,line)) return false; + p_detectorLine = p_camera->FocalPlaneMap()->DetectorLineOffset(); + double etLine = p_etStart + p_lineRate * (line - 0.5); + p_camera->SetEphemerisTime(etLine); + return true; + } +} diff --git a/isis/src/base/objs/LineScanCameraDetectorMap/LineScanCameraDetectorMap.h b/isis/src/base/objs/LineScanCameraDetectorMap/LineScanCameraDetectorMap.h new file mode 100644 index 0000000000000000000000000000000000000000..016c929bbeb302ef8217b5ae0bb5c4e2f4857a4b --- /dev/null +++ b/isis/src/base/objs/LineScanCameraDetectorMap/LineScanCameraDetectorMap.h @@ -0,0 +1,100 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/03/07 17:57:27 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef LineScanCameraDetectorMap_h +#define LineScanCameraDetectorMap_h + +#include "CameraDetectorMap.h" + +namespace Isis { + /** Convert between parent image coordinates and detector coordinates + * + * This class is used to convert between parent dector coordinates + * (sample/line) and detector coordinates for a line scan camera. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2005-02-09 Jeff Anderson + * Original version + * @history 2009-03-07 Debbie A. Cook Removed reference to obsolute CameraDetectorMap methods + * + */ + class LineScanCameraDetectorMap : public CameraDetectorMap { + public: + /** Construct a detector map for line scan cameras + * + * @param parent The parent camera model for the detector map + * @param etStart starting ephemeris time in seconds + * at the top of the first line + * @param lineRate the time in seconds between lines + * + */ + LineScanCameraDetectorMap(Camera *parent, const double etStart, + const double lineRate) : + CameraDetectorMap(parent) { + p_etStart = etStart; + p_lineRate = lineRate; + } + + //! Destructor + virtual ~LineScanCameraDetectorMap() {}; + + /** Reset the starting ephemeris time + * + * Use this method to reset the starting time of the top edge of + * the first line in the parent image. That is the time, prior + * to cropping, scaling, or padding. Usually this will not need + * to be done unless the time changes between bands. + * + * @param etStart starting ephemeris time in seconds + * + */ + void SetStartTime (const double etStart) { p_etStart = etStart; }; + + /** Reset the line rate + * + * Use this method to reset the time between lines. Usually this + * will not need to be done unless the rate changes between bands. + * + * @param lineRate the time in seconds between lines + * + */ + void SetLineRate (const double lineRate) { p_lineRate = lineRate; }; + + //! Return the time in seconds between scan lines + double LineRate () const { return p_lineRate; }; + + virtual bool SetParent(const double sample, const double line); + + virtual bool SetDetector(const double sample, const double line); + + private: + double p_etStart; //!< Starting time at the top of the 1st parent line + double p_lineRate; //!< iTime between lines in parent cube + }; +}; +#endif diff --git a/isis/src/base/objs/LineScanCameraDetectorMap/LineScanCameraDetectorMap.truth b/isis/src/base/objs/LineScanCameraDetectorMap/LineScanCameraDetectorMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..6347fe6d38f458077e14c2efcd5624b000c19da3 --- /dev/null +++ b/isis/src/base/objs/LineScanCameraDetectorMap/LineScanCameraDetectorMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Camera models. diff --git a/isis/src/base/objs/LineScanCameraDetectorMap/Makefile b/isis/src/base/objs/LineScanCameraDetectorMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0c0526094af32fc8e26b9923668aaca2eea45332 --- /dev/null +++ b/isis/src/base/objs/LineScanCameraDetectorMap/Makefile @@ -0,0 +1,5 @@ +INCS = LineScanCameraDetectorMap.h +SRCS = LineScanCameraDetectorMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/LineScanCameraDetectorMap/unitTest.cpp b/isis/src/base/objs/LineScanCameraDetectorMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1e796681f5572ea434cc9d3b182886357352364 --- /dev/null +++ b/isis/src/base/objs/LineScanCameraDetectorMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/LineScanCameraGroundMap/LineScanCameraGroundMap.cpp b/isis/src/base/objs/LineScanCameraGroundMap/LineScanCameraGroundMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f8f2b4e3788b3ec40ccfb28d82871bd2240f962b --- /dev/null +++ b/isis/src/base/objs/LineScanCameraGroundMap/LineScanCameraGroundMap.cpp @@ -0,0 +1,355 @@ +/** + * @file + * $Revision: 1.7 $ + * $Date: 2010/06/17 18:59:11 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "LineScanCameraGroundMap.h" + +#include "CameraDistortionMap.h" +#include "LineScanCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "Statistics.h" + +namespace Isis { + /** Compute undistorted focal plane coordinate from ground position + * + * @param lat planetocentric latitude in degrees + * @param lon planetocentric longitude in degrees + * + * @return conversion was successful + */ + bool LineScanCameraGroundMap::SetGround(const double lat, const double lon) { + // Set a time in order to get Spice so SetUniversalGround will not fail + // We are only interested in getting the radius for this lat/lon and + // calling the overload SetGround to do the work. + p_camera->Sensor::SetEphemerisTime(p_camera->Spice::CacheStartTime()); + if(!p_camera->Sensor::SetUniversalGround(lat, lon, false)) return false; + // Get radius in meters + double radius = p_camera->Sensor::LocalRadius(); + return SetGround(lat, lon, radius); + } + + /** Compute undistorted focal plane coordinate from ground position + * + * @param lat planetocentric latitude in degrees + * @param lon planetocentric longitude in degrees + * @param radius local radius in meters + * + * @return conversion was successful + */ + bool LineScanCameraGroundMap::SetGround(const double lat, const double lon, const double radius) { + FindFocalPlaneStatus status = FindFocalPlane(-1, lat, lon, radius); + + if(status == Success) return true; + if(status == Failure) return false; + + if(status == BoundingProblem) { + // Get ending bounding framelets and distances for iterative loop to minimize the spacecraft distance + int startLine = 1; + double startDist = FindSpacecraftDistance(startLine, lat, lon); + + int endLine = p_camera->Lines(); + double endDist = FindSpacecraftDistance(endLine, lat, lon); + + int deltaX = abs(startLine - endLine) / 2; + + // start + deltaX = middle framelet. + // We're able to optimize this modified binary search + // because the 'V' shape -- it's mostly parallel. Meaning, + // if the left side is higher than the right, then the + // solution is closer to the right. The bias factor will + // determine how much closer. + double biasFactor = startDist / endDist; + + if(biasFactor < 1.0) { + biasFactor = -1.0 / biasFactor; + biasFactor = -(biasFactor + 1) / biasFactor; + } + else { + biasFactor = (biasFactor - 1) / biasFactor; + } + + int middleLine = startLine + (int)(deltaX + biasFactor * deltaX); + + if(FindFocalPlane(middleLine, lat, lon, radius) == Success) { + return true; + } + else { + return false; + } + } + + return false; + } + + double LineScanCameraGroundMap::FindSpacecraftDistance(int line, const double lat, const double lon) { + CameraDetectorMap *detectorMap = p_camera->DetectorMap(); + detectorMap->SetParent(p_camera->ParentSamples() / 2, line); + if(!p_camera->Sensor::SetUniversalGround(lat, lon, false)) return DBL_MAX; + + return p_camera->SlantDistance(); + } + + LineScanCameraGroundMap::FindFocalPlaneStatus + LineScanCameraGroundMap::FindFocalPlane(const int &approxLine, const double &lat, + const double &lon, const double &radius) { + // find middle time; cache time starting points vary + double approxTime = 0.0; + double lineRate = 0.0; + + CameraDistortionMap *distortionMap = p_camera->DistortionMap(); + CameraFocalPlaneMap *focalMap = p_camera->FocalPlaneMap(); + + double startOffset = 0.0, endOffset = 0.0; + double startTime = 0.0, endTime = 0.0; + double lookC[3] = {0.0, 0.0, 0.0}; + double ux = 0.0, uy = 0.0; + double dx = 0.0, dy = 0.0; + const double cacheStart = p_camera->Spice::CacheStartTime(); + const double cacheEnd = p_camera->Spice::CacheEndTime(); + unsigned long lineTolerance = 100; + bool startTimeMaxed = false, endTimeMaxed = false; + + if(approxLine >= 0) { + p_camera->DetectorMap()->SetParent(p_camera->ParentSamples() / 2, approxLine); + approxTime = p_camera->EphemerisTime(); + lineRate = ((LineScanCameraDetectorMap *)p_camera->DetectorMap())->LineRate(); + } + + bool bounded = false; + while(!bounded) { + if(approxTime != 0.0) { + startTime = approxTime - lineTolerance * lineRate; + endTime = approxTime + lineTolerance * lineRate; + } + else { + startTime = cacheStart; + endTime = cacheEnd; + } + + if(startTime <= cacheStart) { + startTimeMaxed = true; + startTime = cacheStart; + } + + if(endTime >= cacheEnd) { + endTimeMaxed = true; + endTime = cacheEnd; + } + + bounded = true; + + // Get beginning bounding time and offset for iterative loop + p_camera->Sensor::SetEphemerisTime(startTime); + if(!p_camera->Sensor::SetUniversalGround(lat, lon, false)) { + return Failure; + } + + p_camera->Sensor::LookDirection(lookC); + double ux = p_camera->FocalLength() * lookC[0] / lookC[2]; + double uy = p_camera->FocalLength() * lookC[1] / lookC[2]; + + double s[3], p[3]; + p_camera->InstrumentPosition(s); + p_camera->Coordinate(p); + double distStart = sqrt((s[0] - p[0]) * (s[0] - p[0]) + + (s[1] - p[1]) * (s[1] - p[1]) + + (s[2] - p[2]) * (s[2] - p[2])); + + int backCheck = 0; + p_camera->SetLookDirection(lookC); + if((fabs(p_camera->UniversalLatitude() - lat) > 45.0) || + (fabs(p_camera->UniversalLongitude() - lon) > 180.0)) backCheck++; + + double dx, dy; + CameraDistortionMap *distortionMap = p_camera->DistortionMap(); + if(!distortionMap->SetUndistortedFocalPlane(ux, uy)) { + dx = ux; + dy = uy; + } + else { + dx = distortionMap->FocalPlaneX(); + dy = distortionMap->FocalPlaneY(); + } + + CameraFocalPlaneMap *focalMap = p_camera->FocalPlaneMap(); + if(!focalMap->SetFocalPlane(dx, dy)) { + return Failure; + } + startOffset = focalMap->DetectorLineOffset() - + focalMap->DetectorLine(); + + // Get ending bounding time and offset for iterative loop + p_camera->Sensor::SetEphemerisTime(endTime); + if(!p_camera->Sensor::SetUniversalGround(lat, lon, false)) { + return Failure; + } + + p_camera->Sensor::LookDirection(lookC); + ux = p_camera->FocalLength() * lookC[0] / lookC[2]; + uy = p_camera->FocalLength() * lookC[1] / lookC[2]; + + p_camera->InstrumentPosition(s); + p_camera->Coordinate(p); + double distEnd = sqrt((s[0] - p[0]) * (s[0] - p[0]) + + (s[1] - p[1]) * (s[1] - p[1]) + + (s[2] - p[2]) * (s[2] - p[2])); + + p_camera->SetLookDirection(lookC); + if((fabs(p_camera->UniversalLatitude() - lat) > 45.0) || + (fabs(p_camera->UniversalLongitude() - lon) > 180.0)) backCheck++; + + if(!distortionMap->SetUndistortedFocalPlane(ux, uy)) { + dx = ux; + dy = uy; + } + else { + dx = distortionMap->FocalPlaneX(); + dy = distortionMap->FocalPlaneY(); + } + + if(!focalMap->SetFocalPlane(dx, dy)) return Failure; + endOffset = focalMap->DetectorLineOffset() - + focalMap->DetectorLine(); + + // Deal with images that have two roots + if(backCheck == 1) { + if(distStart < distEnd) { + endTime = startTime + (endTime - startTime) / 2.0; + p_camera->Sensor::SetEphemerisTime(endTime); + if(!p_camera->Sensor::SetUniversalGround(lat, lon, false)) return Failure; + + p_camera->Sensor::LookDirection(lookC); + ux = p_camera->FocalLength() * lookC[0] / lookC[2]; + uy = p_camera->FocalLength() * lookC[1] / lookC[2]; + + if(!distortionMap->SetUndistortedFocalPlane(ux, uy)) return Failure; + dx = distortionMap->FocalPlaneX(); + dy = distortionMap->FocalPlaneY(); + + if(!focalMap->SetFocalPlane(dx, dy)) return Failure; + endOffset = focalMap->DetectorLineOffset() - + focalMap->DetectorLine(); + + } + else { + startTime = endTime - (endTime - startTime) / 2.0; + p_camera->Sensor::SetEphemerisTime(startTime); + if(!p_camera->Sensor::SetUniversalGround(lat, lon, false)) return Failure; + + p_camera->Sensor::LookDirection(lookC); + ux = p_camera->FocalLength() * lookC[0] / lookC[2]; + uy = p_camera->FocalLength() * lookC[1] / lookC[2]; + + if(!distortionMap->SetUndistortedFocalPlane(ux, uy)) return Failure; + dx = distortionMap->FocalPlaneX(); + dy = distortionMap->FocalPlaneY(); + + if(!focalMap->SetFocalPlane(dx, dy)) return Failure; + startOffset = focalMap->DetectorLineOffset() - + focalMap->DetectorLine(); + } + } + + // Make sure we are in the image + if((startOffset < 0.0) && (endOffset < 0.0)) bounded = false; + if((startOffset > 0.0) && (endOffset > 0.0)) bounded = false; + + if(!bounded) { + if(startTimeMaxed || endTimeMaxed) { + return BoundingProblem; + } + + lineTolerance *= 2; + + if(lineTolerance == 0) return Failure; + } + } + + // Get everything ordered for iteration + double fl, fh, xl, xh; + if(startOffset < endOffset) { + fl = startOffset; + fh = endOffset; + xl = startTime; + xh = endTime; + } + else { + fl = endOffset; + fh = startOffset; + xl = endTime; + xh = startTime; + } + + // Iterate to find the time at which the instrument imaged the ground point + LineScanCameraDetectorMap *detectorMap = + (LineScanCameraDetectorMap *) p_camera->DetectorMap(); + double timeTol = detectorMap->LineRate() / 10.0; + bool checkHidden = false; + for(int j = 0; j < 30; j++) { + double etGuess = xl + (xh - xl) * fl / (fl - fh); + p_camera->Sensor::SetEphemerisTime(etGuess); + if(!p_camera->Sensor::SetUniversalGround(lat, lon, checkHidden)) return Failure; + p_camera->Sensor::LookDirection(lookC); + ux = p_camera->FocalLength() * lookC[0] / lookC[2]; + uy = p_camera->FocalLength() * lookC[1] / lookC[2]; + + if(!distortionMap->SetUndistortedFocalPlane(ux, uy)) { + return Failure; + } + dx = distortionMap->FocalPlaneX(); + dy = distortionMap->FocalPlaneY(); + + if(!focalMap->SetFocalPlane(dx, dy)) { + return Failure; + } + double f = focalMap->DetectorLineOffset() - + focalMap->DetectorLine(); + + double delTime; + if(f < 0.0) { + delTime = xl - etGuess; + xl = etGuess; + fl = f; + } + else { + delTime = xh - etGuess; + xh = etGuess; + fh = f; + } + + // See if we converged on the point so set up the undistorted + // focal plane values and return + if(fabs(delTime) < timeTol || f == 0.0) { + if(checkHidden) { + p_focalPlaneX = ux; + p_focalPlaneY = uy; + return Success; + } + else { + checkHidden = true; + } + } + } + + return Failure; + } +} diff --git a/isis/src/base/objs/LineScanCameraGroundMap/LineScanCameraGroundMap.h b/isis/src/base/objs/LineScanCameraGroundMap/LineScanCameraGroundMap.h new file mode 100644 index 0000000000000000000000000000000000000000..41f3fede60721c606375072b13420b6605070f35 --- /dev/null +++ b/isis/src/base/objs/LineScanCameraGroundMap/LineScanCameraGroundMap.h @@ -0,0 +1,86 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2010/06/17 18:59:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef LineScanCameraGroundMap_h +#define LineScanCameraGroundMap_h + +#include "CameraGroundMap.h" + +namespace Isis { + /** Convert between undistorted focal plane and ground coordinates + * + * This class is used to convert between undistorted focal plane + * coordinates (x/y) in millimeters and ground coordinates lat/lon + * for line scan cameras. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2005-02-08 Jeff Anderson - Original version + * @history 2005-08-24 Jeff Anderson - Fixed bug when algorithm was checking + * for the backside of the planet and convergence failed (checkHidden) + * @history 2005-11-16 Jeff Anderson - Fixed bug when a image covers more + * than 180 degrees in an orbit which would cause two focal plane roots + * to be inside the start/end time range. + * @history 2007-12-21 Debbie A. Cook - Added overloaded method SetGround that + * includes a radius argument + * @history 2009-03-02 Steven Lambright - Added an additional method of + * finding the point in SetGround(...) if the original algorithm + * fails. The spacecraft position at the beginning and end of the + * image are now being used to estimate the correct line if the + * bounding check fails the first time through. + * @history 2010-06-17 Steven Lambright - More tolerant of failures in the + * distortion models for finding the bounds of the search in + * FindSpacecraftDistance + * + */ + class LineScanCameraGroundMap : public CameraGroundMap { + public: + /** Constructor + * + * @param cam pointer to camera model + */ + LineScanCameraGroundMap(Camera *cam) : CameraGroundMap(cam) {}; + + //! Destructor + virtual ~LineScanCameraGroundMap() {}; + + virtual bool SetGround(const double lat, const double lon); + virtual bool SetGround(const double lat, const double lon, const double radius); + + protected: + enum FindFocalPlaneStatus { + Success, + BoundingProblem, + Failure + }; + + FindFocalPlaneStatus FindFocalPlane(const int &approxLine, + const double &lat, const double &lon, const double &radius); + double FindSpacecraftDistance(int line, const double lat, const double lon); + }; +}; +#endif diff --git a/isis/src/base/objs/LineScanCameraGroundMap/LineScanCameraGroundMap.truth b/isis/src/base/objs/LineScanCameraGroundMap/LineScanCameraGroundMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..6347fe6d38f458077e14c2efcd5624b000c19da3 --- /dev/null +++ b/isis/src/base/objs/LineScanCameraGroundMap/LineScanCameraGroundMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Camera models. diff --git a/isis/src/base/objs/LineScanCameraGroundMap/Makefile b/isis/src/base/objs/LineScanCameraGroundMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8ce3cfb75cbff7337090ae9446476749b8e23aa6 --- /dev/null +++ b/isis/src/base/objs/LineScanCameraGroundMap/Makefile @@ -0,0 +1,5 @@ +INCS = LineScanCameraGroundMap.h +SRCS = LineScanCameraGroundMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/LineScanCameraGroundMap/unitTest.cpp b/isis/src/base/objs/LineScanCameraGroundMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c523edab9cf6057bad4d45c4ce96a7a448493f7f --- /dev/null +++ b/isis/src/base/objs/LineScanCameraGroundMap/unitTest.cpp @@ -0,0 +1,9 @@ +#include "Preference.h" +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/LineScanCameraSkyMap/LineScanCameraSkyMap.cpp b/isis/src/base/objs/LineScanCameraSkyMap/LineScanCameraSkyMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e374006d6e57f51ab16e078442b6a776d0ed0146 --- /dev/null +++ b/isis/src/base/objs/LineScanCameraSkyMap/LineScanCameraSkyMap.cpp @@ -0,0 +1,139 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "LineScanCameraSkyMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraDistortionMap.h" +#include "LineScanCameraDetectorMap.h" + +namespace Isis { + /** Compute undistorted focal plane coordinate from ra/dec + * + * @param ra right ascension in degrees + * @param dec declination in degrees + * + * @return conversion was successful + * @todo what happens if we are looking behind the focal plane????? + * @todo what happens if we are looking parallel to the focal plane?? + * @todo can lookC[2] == zero imply parallel + * @todo can this all be solved by restricting the physical size of + * the focal plane? + */ + bool LineScanCameraSkyMap::SetSky(const double ra, const double dec) { + // Get beginning bounding time and offset for iterative loop + p_camera->Sensor::SetEphemerisTime(p_camera->Spice::CacheStartTime()); + p_camera->Sensor::SetRightAscensionDeclination(ra,dec); + + double lookC[3]; + p_camera->Sensor::LookDirection(lookC); + double ux = p_camera->FocalLength() * lookC[0] / lookC[2]; + double uy = p_camera->FocalLength() * lookC[1] / lookC[2]; + + CameraDistortionMap *distortionMap = p_camera->DistortionMap(); + if (!distortionMap->SetUndistortedFocalPlane(ux,uy)) return false; + double dx = distortionMap->FocalPlaneX(); + double dy = distortionMap->FocalPlaneY(); + + CameraFocalPlaneMap *focalMap = p_camera->FocalPlaneMap(); + if (!focalMap->SetFocalPlane(dx,dy)) return false; + double startOffset = focalMap->DetectorLineOffset() - + focalMap->DetectorLine(); + + // Get ending bounding time and offset for iterative loop + p_camera->Sensor::SetEphemerisTime(p_camera->Spice::CacheEndTime()); + p_camera->Sensor::SetRightAscensionDeclination(ra,dec); + + p_camera->Sensor::LookDirection(lookC); + ux = p_camera->FocalLength() * lookC[0] / lookC[2]; + uy = p_camera->FocalLength() * lookC[1] / lookC[2]; + + if (!distortionMap->SetUndistortedFocalPlane(ux,uy)) return false; + dx = distortionMap->FocalPlaneX(); + dy = distortionMap->FocalPlaneY(); + + if (!focalMap->SetFocalPlane(dx,dy)) return false; + double endOffset = focalMap->DetectorLineOffset() - + focalMap->DetectorLine(); + + // Make sure we are in the image + if ((startOffset < 0.0) && (endOffset < 0.0)) return false; + if ((startOffset > 0.0) && (endOffset > 0.0)) return false; + + // Get everything ordered for iteration + double fl,fh,xl,xh; + if (startOffset < endOffset) { + fl = startOffset; + fh = endOffset; + xl = p_camera->Spice::CacheStartTime(); + xh = p_camera->Spice::CacheEndTime(); + } + else { + fl = endOffset; + fh = startOffset; + xl = p_camera->Spice::CacheEndTime(); + xh = p_camera->Spice::CacheStartTime(); + } + + // Iterate to find the time at which the instrument imaged the ground point + LineScanCameraDetectorMap *detectorMap = + (LineScanCameraDetectorMap *) p_camera->DetectorMap(); + double timeTol = detectorMap->LineRate() / 10.0; + for (int j=0; j<30; j++) { + double etGuess = xl + (xh - xl) * fl / (fl - fh); + p_camera->Sensor::SetEphemerisTime(etGuess); + p_camera->Sensor::SetRightAscensionDeclination(ra,dec); + p_camera->Sensor::LookDirection(lookC); + ux = p_camera->FocalLength() * lookC[0] / lookC[2]; + uy = p_camera->FocalLength() * lookC[1] / lookC[2]; + + if (!distortionMap->SetUndistortedFocalPlane(ux,uy)) return false; + dx = distortionMap->FocalPlaneX(); + dy = distortionMap->FocalPlaneY(); + + if (!focalMap->SetFocalPlane(dx,dy)) return false; + double f = focalMap->DetectorLineOffset() - + focalMap->DetectorLine(); + + double delTime; + if (f < 0.0) { + delTime = xl - etGuess; + xl = etGuess; + fl = f; + } + else { + delTime = xh - etGuess; + xh = etGuess; + fh = f; + } + + // See if we converged on the point so set up the undistorted + // focal plane values and return + if (fabs(delTime) < timeTol || f == 0.0) { + p_focalPlaneX = ux; + p_focalPlaneY = uy; + return true; + } + } + return false; + } +} diff --git a/isis/src/base/objs/LineScanCameraSkyMap/LineScanCameraSkyMap.h b/isis/src/base/objs/LineScanCameraSkyMap/LineScanCameraSkyMap.h new file mode 100644 index 0000000000000000000000000000000000000000..1dfa767f51c01fc158e8af541d94c70fe0aff934 --- /dev/null +++ b/isis/src/base/objs/LineScanCameraSkyMap/LineScanCameraSkyMap.h @@ -0,0 +1,63 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef LineScanCameraSkyMap_h +#define LineScanCameraSkyMap_h + +#include "CameraSkyMap.h" + +namespace Isis { + /** Convert between undistorted focal plane and ra/dec coordinates + * + * This class is used to convert between undistorted focal plane + * coordinates (x/y) in millimeters and sky (ra/dec). This + * class handles the case of line scan cameras. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2005-02-08 Jeff Anderson + * Original version + * + * @history 2005-10-13 Jeff Anderson + * Fixed a bug. Removed failure comparsion test on + * Sensor::SetRightAscensionDeclination calls. A failure indicated we + * didn't hit the target but we don't care here since the target is the + * sky. + * + */ + class LineScanCameraSkyMap : public CameraSkyMap { + public: + //! Constructor + LineScanCameraSkyMap(Camera *parent) : CameraSkyMap(parent) {}; + + //! Destructor + virtual ~LineScanCameraSkyMap() {}; + + virtual bool SetSky(const double ra, const double dec); + }; +}; +#endif diff --git a/isis/src/base/objs/LineScanCameraSkyMap/LineScanCameraSkyMap.truth b/isis/src/base/objs/LineScanCameraSkyMap/LineScanCameraSkyMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..6347fe6d38f458077e14c2efcd5624b000c19da3 --- /dev/null +++ b/isis/src/base/objs/LineScanCameraSkyMap/LineScanCameraSkyMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Camera models. diff --git a/isis/src/base/objs/LineScanCameraSkyMap/Makefile b/isis/src/base/objs/LineScanCameraSkyMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c5a5283a06a5ff819fb0a1eb1c64ba56b4c1ebbd --- /dev/null +++ b/isis/src/base/objs/LineScanCameraSkyMap/Makefile @@ -0,0 +1,5 @@ +INCS = LineScanCameraSkyMap.h +SRCS = LineScanCameraSkyMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/LineScanCameraSkyMap/unitTest.cpp b/isis/src/base/objs/LineScanCameraSkyMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af56e7a2e697c11d09fb5d8d4ca960a7faa53ba9 --- /dev/null +++ b/isis/src/base/objs/LineScanCameraSkyMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include "Preference.h" +#include + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/LommelSeeliger/LommelSeeliger.cpp b/isis/src/base/objs/LommelSeeliger/LommelSeeliger.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3022ace0a7bb171f2565024f119f903404c868a --- /dev/null +++ b/isis/src/base/objs/LommelSeeliger/LommelSeeliger.cpp @@ -0,0 +1,26 @@ +#include +#include "LommelSeeliger.h" + +namespace Isis { + double LommelSeeliger::PhotoModelAlgorithm (double phase, double incidence, + double emission) { + double pht_lomsel; + double incrad = incidence * Isis::PI / 180.0; + double emarad = emission * Isis::PI / 180.0; + double munot = cos(incrad); + double mu = cos(emarad); + + if (munot <= 0.0 || mu <= 0.0 || incidence == 90.0 || + emission == 90.0) { + pht_lomsel = 0.0; + } else { + pht_lomsel = 2.0 * munot / (munot + mu); + } + + return pht_lomsel; + } +} + +extern "C" Isis::PhotoModel *LommelSeeligerPlugin (Isis::Pvl &pvl) { + return new Isis::LommelSeeliger(pvl); +} diff --git a/isis/src/base/objs/LommelSeeliger/LommelSeeliger.h b/isis/src/base/objs/LommelSeeliger/LommelSeeliger.h new file mode 100644 index 0000000000000000000000000000000000000000..51934687a020826a75f817485a634c21baa57526 --- /dev/null +++ b/isis/src/base/objs/LommelSeeliger/LommelSeeliger.h @@ -0,0 +1,43 @@ +#if !defined(LommelSeeliger_h) +#define LommelSeeliger_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2007/02/20 16:55:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PhotoModel.h" + +namespace Isis { + class Pvl; + + class LommelSeeliger : public PhotoModel { + public: + LommelSeeliger (Pvl &pvl) : PhotoModel(pvl) {}; + virtual ~LommelSeeliger() {}; + + protected: + virtual double PhotoModelAlgorithm (double phase, double incidence, + double emission); + + }; +}; + +#endif diff --git a/isis/src/base/objs/LommelSeeliger/LommelSeeliger.truth b/isis/src/base/objs/LommelSeeliger/LommelSeeliger.truth new file mode 100644 index 0000000000000000000000000000000000000000..14eaa43032a182677860a9cedfd1b893229d6d3f --- /dev/null +++ b/isis/src/base/objs/LommelSeeliger/LommelSeeliger.truth @@ -0,0 +1,18 @@ +UNIT TEST for LommelSeeliger photometric function + +Object = PhotometricModel + Group = Algorithm + Name = LommelSeeliger + End_Group +End_Object +End + +Test phase=0.0, incidence=0.0, emission=0.0 ... +Albedo = 1 + +Test phase=60.0, incidence=45.0, emission=30.0 ... +Albedo = 0.898979 + +Test phase=180.0, incidence=90.0, emission=90.0 ... +Albedo = 0 + diff --git a/isis/src/base/objs/LommelSeeliger/Makefile b/isis/src/base/objs/LommelSeeliger/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3cbbdc7990200c908ee6328d1a03f9bd8b8d253d --- /dev/null +++ b/isis/src/base/objs/LommelSeeliger/Makefile @@ -0,0 +1,5 @@ +INCS = LommelSeeliger.h +SRCS = LommelSeeliger.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/LommelSeeliger/PhotoModel.plugin b/isis/src/base/objs/LommelSeeliger/PhotoModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..c5bc5c89d0e550b5012a6ddf29a6d62b8d75f6a8 --- /dev/null +++ b/isis/src/base/objs/LommelSeeliger/PhotoModel.plugin @@ -0,0 +1,4 @@ +Group = LommelSeeliger + Library = LommelSeeliger + Routine = LommelSeeligerPlugin +End_Group diff --git a/isis/src/base/objs/LommelSeeliger/unitTest.cpp b/isis/src/base/objs/LommelSeeliger/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95ae5a5f3ffd1b5df9e4ef4b66e2c9ef97e4bfb0 --- /dev/null +++ b/isis/src/base/objs/LommelSeeliger/unitTest.cpp @@ -0,0 +1,49 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + std::cout << "UNIT TEST for LommelSeeliger photometric function" << + std::endl << std::endl; + + try { + PvlGroup alg("Algorithm"); + alg += PvlKeyword("Name","LommelSeeliger"); + + PvlObject o("PhotometricModel"); + o.AddGroup(alg); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl << std::endl; + + PhotoModel *pm = PhotoModelFactory::Create(pvl); + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(0.0,0.0,0.0) << + std::endl << std::endl; + std::cout << "Test phase=60.0, incidence=45.0, emission=30.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(60.0,45.0,30.0) << + std::endl << std::endl; + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(180.0,90.0,90.0) << + std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/LunarAzimuthalEqualArea/LunarAzimuthalEqualArea.cpp b/isis/src/base/objs/LunarAzimuthalEqualArea/LunarAzimuthalEqualArea.cpp new file mode 100755 index 0000000000000000000000000000000000000000..2c6d79971e0d9742cd15cf5ba287a39e7498831f --- /dev/null +++ b/isis/src/base/objs/LunarAzimuthalEqualArea/LunarAzimuthalEqualArea.cpp @@ -0,0 +1,306 @@ +/** +* @file +* $Revision: 1.1 $ +* $Date: 2009/08/07 22:52:23 $ +* +* Unless noted otherwise, the portions of Isis written by the USGS are public +* domain. See individual third-party library and package descriptions for +* intellectual property information,user agreements, and related information. +* +* Although Isis has been used by the USGS, no warranty, expressed or implied, +* is made by the USGS as to the accuracy and functioning of such software +* and related material nor shall the fact of distribution constitute any such +* warranty, and no responsibility is assumed by the USGS in connection +* therewith. +* +* For additional information, launch +* $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see +* the Privacy & Disclaimers page on the Isis website, +* http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on +* http://www.usgs.gov/privacy.html. +*/ + +#include +#include +#include "LunarAzimuthalEqualArea.h" +#include "iException.h" +#include "Constants.h" + +using namespace std; +namespace Isis +{ + /** + * Constructs a LunarAzimuthalEqualArea object + * + * @param label This argument must be a Label containing the proper mapping + * information as indicated in the Projection class. Additionally, + * the LunarAzimuthalEqualArea projection requires the + * center longitude to be defined in the keyword CenterLongitude. + * + * @throws Isis::iException::Io + */ + LunarAzimuthalEqualArea::LunarAzimuthalEqualArea( + Isis::Pvl & label) : Isis::Projection::Projection(label) + { + try + { + // Try to read the mapping group + Isis::PvlGroup & mapGroup = label.FindGroup("Mapping", + Isis::Pvl::Traverse); + + // Get the max libration + p_maxLibration = mapGroup["MaximumLibration"]; + p_maxLibration *= PI / 180.0; + } + catch (Isis::iException & e) + { + string message = "Invalid label group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Io, message, + _FILEINFO_); + } + } + + //! Destroys the LunarAzimuthalEqualArea object + LunarAzimuthalEqualArea::~LunarAzimuthalEqualArea() + { + } + + /** + * This method is used to set the latitude/longitude (assumed to be of the + * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. + * + * @param lat Latitude value to project + * + * @param lon Longitude value to project + * + * @return bool + */ + bool LunarAzimuthalEqualArea::SetGround(const double lat, + const double lon) + { + // Convert longitude to radians + p_longitude = lon; + double lonRadians = lon * Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) + lonRadians *= -1.0; + + // Now convert latitude to radians... it must be planetographic + p_latitude = lat; + double latRadians = lat; + if (IsPlanetocentric()) + latRadians = ToPlanetographic(latRadians); + latRadians *= Isis::PI / 180.0; + + double x, y; + if (lonRadians == 0.0 && latRadians == 0.0) + { + x = 0.0; + y = 0.0; + SetComputedXY(x, y); + p_good = true; + return true; + } + + double E = acos(cos(latRadians) * cos(lonRadians)); + double test = (sin(lonRadians) * cos(latRadians)) / sin(E); + + if (test > 1.0) test = 1.0; + else if (test < -1.0) test = -1.0; + + double D = HALFPI - asin(test); + if (latRadians < 0.0) + D = -D; + + double radius = p_equatorialRadius; + double PFAC = (HALFPI + p_maxLibration) / HALFPI; + double RP = radius * sin(E / PFAC); + + x = RP * cos(D); + y = RP * sin(D); + + SetComputedXY(x, y); + p_good = true; + return true; + + } // of SetGround + + + /** + * This method is used to set the projection x/y. The Set forces an attempted + * calculation of the corresponding latitude/longitude position. This may or + * may not be successful and a status is returned as such. + * + * @param x X coordinate of the projection in units that are the same as the + * radii in the label + * + * @param y Y coordinate of the projection in units that are the same as the + * radii in the label + * + * @return bool + */ + bool LunarAzimuthalEqualArea::SetCoordinate(const double x, + const double y) + { + // Save the coordinate + SetXY(x, y); + + double RP = sqrt((x * x) + (y * y)); + + double lat, lon; + if (y == 0.0 && x == 0.0) + { + lat = 0.0; + lon = 0.0; + return true; + } + + double radius = p_equatorialRadius; + + double D = atan2(y, x); + double test = RP / radius; + double IERROR; + if (abs(test) > 1.0) + { + IERROR = 1001; // throw exception or something ?? + return false; + } + + double EPSILON = 0.0000000001; + double PFAC = (HALFPI + p_maxLibration) / HALFPI; + double E = PFAC * asin(RP / radius); + + lat = HALFPI - (acos(sin(D) * sin(E))); + + if (abs(HALFPI - abs(lat)) <= EPSILON) + { + lon = 0.0; + } + else + { + test = sin(E) * cos(D) / sin(HALFPI - lat); + if (test > 1.0) test = 1.0; + else if (test < -1.0) test = -1.0; + + lon = asin(test); + } + + if (E >= HALFPI) + { + if (lon <= 0.0) lon = -PI - lon; + else lon = PI - lon; + } + + // Convert to degrees + p_latitude = lat * 180.0 / Isis::PI; + p_longitude = lon * 180.0 / Isis::PI; + + // Cleanup the latitude + if (IsPlanetocentric()) + p_latitude = ToPlanetocentric(p_latitude); + + p_good = true; + return p_good; + } + + + /** + * This method is used to determine the x/y range which completely covers the + * area of interest specified by the lat/lon range. The latitude/longitude + * range may be obtained from the labels. The purpose of this method is to + * return the x/y range so it can be used to compute how large a map may need + * to be. For example, how big a piece of paper is needed or how large of an + * image needs to be created. The method may fail as indicated by its return + * value. + * + * @param minX Minimum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxX Maximum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param minY Minimum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxY Maximum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @return bool + */ + bool LunarAzimuthalEqualArea::XYRange(double & minX, double & maxX, + double & minY, double & maxY) + { + // Check the corners of the lat/lon range + XYRangeCheck (p_minimumLatitude,p_minimumLongitude); + XYRangeCheck (p_maximumLatitude,p_minimumLongitude); + XYRangeCheck (p_minimumLatitude,p_maximumLongitude); + XYRangeCheck (p_maximumLatitude,p_maximumLongitude); + + // If the latitude range contains 0 + if ((p_minimumLatitude < 0.0) && (p_maximumLatitude > 0.0)) + { + XYRangeCheck (0.0, p_minimumLongitude); + XYRangeCheck (0.0, p_maximumLongitude); + } + + // If the longitude range contains 0 + if ((p_minimumLongitude < 0.0) && (p_maximumLongitude > 0.0)) + { + XYRangeCheck (p_minimumLatitude, 0.0); + XYRangeCheck (p_maximumLatitude, 0.0); + } + + // Make sure everything is ordered + if (p_minimumX >= p_maximumX) return false; + if (p_minimumY >= p_maximumY) return false; + + // Return X/Y min/maxs + minX = p_minimumX; + maxX = p_maximumX; + minY = p_minimumY; + maxY = p_maximumY; + return true; + } + + /** + * This function returns the keywords that this projection uses. + * + * @return PvlGroup The keywords that this projection uses + */ + PvlGroup LunarAzimuthalEqualArea::Mapping() + { + PvlGroup mapping = Projection::Mapping(); + mapping += p_mappingGrp["MaximumLibration"]; + return mapping; + } + + /** + * Compares two Projection objects to see if they are equal + * + * @param proj Projection object to do comparison on + * + * @return bool Returns true if the Projection objects are equal, and false if + * they are not + */ + bool LunarAzimuthalEqualArea::operator== (const Isis::Projection & proj) + { + if (!Isis::Projection::operator==(proj)) + return false; + // dont use != (it is a recusive plunge) + // if (Isis::Projection::operator!=(proj)) return false; + + LunarAzimuthalEqualArea * LKAEA = (LunarAzimuthalEqualArea *) &proj; + if (LKAEA->p_maxLibration != this->p_maxLibration) + return false; + return true; + } + + +} // end namespace isis + +extern "C" Isis::Projection *LunarAzimuthalEqualAreaPlugin (Isis::Pvl &lab, + bool allowDefaults) +{ + return new Isis::LunarAzimuthalEqualArea(lab); +} diff --git a/isis/src/base/objs/LunarAzimuthalEqualArea/LunarAzimuthalEqualArea.h b/isis/src/base/objs/LunarAzimuthalEqualArea/LunarAzimuthalEqualArea.h new file mode 100755 index 0000000000000000000000000000000000000000..2bfb2b5d45cec3a4fb3054c79334cbc5c9f7b9cf --- /dev/null +++ b/isis/src/base/objs/LunarAzimuthalEqualArea/LunarAzimuthalEqualArea.h @@ -0,0 +1,90 @@ +#ifndef LunarAzimuthalEqualArea_h +#define LunarAzimuthalEqualArea_h +/** +* @file +* $Revision: 1.1 $ +* $Date: 2009/08/07 22:52:23 $ + +* +* Unless noted otherwise, the portions of Isis written by the USGS are public +* domain. See individual third-party library and package descriptions for +* intellectual property information,user agreements, and related information. +* +* Although Isis has been used by the USGS, no warranty, expressed or implied, +* is made by the USGS as to the accuracy and functioning of such software +* and related material nor shall the fact of distribution constitute any such +* warranty, and no responsibility is assumed by the USGS in connection +* therewith. +* +* For additional information, launch +* $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see +* the Privacy & Disclaimers page on the Isis website, +* http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on +* http://www.usgs.gov/privacy.html. +*/ + +#include "Projection.h" +#include "Constants.h" +#include + + +namespace Isis +{ + + /** + * @brief Modified Lambert Azimuthal Equal-Area Map Projection + * + * This class provides methods for the forward and inverse equations of a + * Lunar Azimuthal Equal-Area map projection. The code was converted + * to C++ from the Fortran version of Isis2. This class inherits Projection + * and provides the two virtual methods SetGround (forward) and SetCoordinate + * (inverse) and a third virtual method, XYRange, for obtaining projection + * coordinate coverage for a latitude/longitude window. Please see the + * Projection class for a full accounting of all the methods available. + * + * + * @ingroup MapProjection + * + * @author 15 MAY 2009 Eric Hyer + * + */ + class LunarAzimuthalEqualArea : public Isis::Projection + { + public: + LunarAzimuthalEqualArea(Isis::Pvl & label); + ~LunarAzimuthalEqualArea(); + + bool SetGround (const double lat, const double lon); + bool SetCoordinate (const double x, const double y); + bool XYRange(double & minX, double & maxX, double & minY, double & maxY); + PvlGroup Mapping(); + bool operator== (const Isis::Projection & proj); + + /** + * Returns the name of the map projection + * + * @return string Name of projection + */ + std::string Name() const + { + return "LunarAzimuthalEqualArea"; + } + + /** + * Returns the version of the map projection + * + * + * @return std::string Version number + */ + std::string Version () const + { + return "0.1"; + } + + + private: + double p_maxLibration; + }; +} + +#endif diff --git a/isis/src/base/objs/LunarAzimuthalEqualArea/LunarAzimuthalEqualArea.truth b/isis/src/base/objs/LunarAzimuthalEqualArea/LunarAzimuthalEqualArea.truth new file mode 100644 index 0000000000000000000000000000000000000000..a355eded50306dffdda8e8079d84d5c6a9a35d35 --- /dev/null +++ b/isis/src/base/objs/LunarAzimuthalEqualArea/LunarAzimuthalEqualArea.truth @@ -0,0 +1,122 @@ +UNIT TEST FOR LunarAzimuthalEqualArea + + +******* Test SetGround and SetCoordinate methods ******** + +for all lat and lon in [-90..90] step 45 + first call SetGround + then call SetCoordinate + trigger fail if SetCoordinate doesn't + return the original coordinate + note that at the poles the lon is not relevant! + + original Lat: -90 original Lon: -90 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: -90 original Lon: -45 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: -90 original Lon: 0 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: -90 original Lon: 45 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: -90 original Lon: 90 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: -45 original Lon: -90 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: -45 original Lon: -45 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: -45 original Lon: 0 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: -45 original Lon: 45 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: -45 original Lon: 90 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 0 original Lon: -90 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 0 original Lon: -45 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 0 original Lon: 0 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 0 original Lon: 45 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 0 original Lon: 90 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 45 original Lon: -90 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 45 original Lon: -45 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 45 original Lon: 0 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 45 original Lon: 45 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 45 original Lon: 90 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 90 original Lon: -90 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 90 original Lon: -45 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 90 original Lon: 0 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 90 original Lon: 45 +testing SetCoordinate and SetGround ......................... [ OK ] + + original Lat: 90 original Lon: 90 +testing SetCoordinate and SetGround ......................... [ OK ] + + +Testing for SetGround and SetCoordiante done! +Now test the Name method, the == operator and finally +print the output of the XYRange and Mapping methods... + + +Name method returns "LunarAzimuthalEqualArea"................ [ OK ] + +Isis::Projection * s = &p; // p is this projection +(*s == p) returns true! ..................................... [ OK ] +created a second Projection reference p2 +using the same pvl as p except for that PolarRadius = 42 +Pvl for p2... +Group = Mapping + ProjectionName = LunarAzimuthalEqualArea + EquatorialRadius = 6378206.4 + PolarRadius = 42 + LatitudeType = Planetographic + LongitudeDirection = PositiveEast + LongitudeDomain = 180 + MinimumLatitude = -30.0 + MaximumLatitude = -15.0 + MinimumLongitude = -30.0 + MaximumLongitude = -15.0 + MaximumLibration = 1 +End_Group +End +s = &p2 +(*s == p) returns false! .................................... [ OK ] + +XYRange... + Minimum X: -3050406.2705 + Maximum X: -1415698.4769 + Minimum Y: -3160283.3444 + Maximum Y: -1633473.9958 diff --git a/isis/src/base/objs/LunarAzimuthalEqualArea/Makefile b/isis/src/base/objs/LunarAzimuthalEqualArea/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..7e13a6c3d16211b9615e18de71f6e08fd489b518 --- /dev/null +++ b/isis/src/base/objs/LunarAzimuthalEqualArea/Makefile @@ -0,0 +1,5 @@ +INCS = LunarAzimuthalEqualArea.h +SRCS = LunarAzimuthalEqualArea.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/LunarAzimuthalEqualArea/Projection.plugin b/isis/src/base/objs/LunarAzimuthalEqualArea/Projection.plugin new file mode 100755 index 0000000000000000000000000000000000000000..8438da43881d4cfcd35eb8d5f976d65b2ce24a83 --- /dev/null +++ b/isis/src/base/objs/LunarAzimuthalEqualArea/Projection.plugin @@ -0,0 +1,4 @@ +Group = LunarAzimuthalEqualArea + Library = LunarAzimuthalEqualArea + Routine = LunarAzimuthalEqualAreaPlugin +EndGroup diff --git a/isis/src/base/objs/LunarAzimuthalEqualArea/unitTest.cpp b/isis/src/base/objs/LunarAzimuthalEqualArea/unitTest.cpp new file mode 100755 index 0000000000000000000000000000000000000000..4f7bf89dea29be871561e39615d281b56ad19722 --- /dev/null +++ b/isis/src/base/objs/LunarAzimuthalEqualArea/unitTest.cpp @@ -0,0 +1,111 @@ + + +#include +#include +#include +#include "LunarAzimuthalEqualArea.h" +#include "iException.h" +#include "ProjectionFactory.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "UNIT TEST FOR LunarAzimuthalEqualArea\n\n"; + + Isis::Pvl lab; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup & mapGroup = lab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",6378206.4); + mapGroup += Isis::PvlKeyword("PolarRadius",6378206.4); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetographic"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",180); + mapGroup += Isis::PvlKeyword("MinimumLatitude",-30.0); + mapGroup += Isis::PvlKeyword("MaximumLatitude",-15.0); + mapGroup += Isis::PvlKeyword("MinimumLongitude",-30.0); + mapGroup += Isis::PvlKeyword("MaximumLongitude",-15.0); + mapGroup += Isis::PvlKeyword("MaximumLibration", 1); + mapGroup += Isis::PvlKeyword("ProjectionName", + "LunarAzimuthalEqualArea"); + + try { + Isis::Projection & p = *Isis::ProjectionFactory::Create(lab); + + cout << "\n******* Test SetGround and SetCoordinate methods ********" + << "\n\nfor all lat and lon in [-90..90] step 45" + << "\n first call SetGround" + << "\n then call SetCoordinate" + << "\n trigger fail if SetCoordinate doesn't" + << "\n return the original coordinate" + << "\n note that at the poles the lon is not relevant!\n\n"; + + cout << std::setprecision(11); + for (int i = -90; i <= 90; i += 45) + { + for (int j = -90; j <= 90; j+= 45) + { + cout << " original Lat: " << setw(4) << i << " original Lon: " + << setw(4) << j << "\n" + << "testing SetCoordinate and SetGround"; + + p.SetGround(i * 1.0, j * 1.0); + p.SetCoordinate(p.XCoord(), p.YCoord()); + + if ((fabs(fabs(p.Latitude()) - fabs(i)) > 0.00001) || + (fabs(i) != 90 && fabs(fabs(p.Longitude()) - fabs(j)) > 0.00001)) + cout << " ......................... [ FAILED ]\n\n"; + else + cout << " ......................... [ OK ]\n\n"; + } + } + cout << "\nTesting for SetGround and SetCoordiante done!" + << "\nNow test the Name method, the == operator and finally" + << "\nprint the output of the XYRange and Mapping methods...\n\n\n"; + + cout << "Name method returns \"LunarAzimuthalEqualArea\"................ "; + if (p.Name() == "LunarAzimuthalEqualArea") + cout << "[ OK ]\n"; + else + cout << "[ FAILED ]\n"; + + Isis::Projection *s = &p; + cout << "\nIsis::Projection * s = &p; // p is this projection" + << "\n(*s == p) returns "; + if (*s == p) + cout << "true! ..................................... [ OK ]\n"; + else + cout << "false! .................................... [ FAILED ]\n"; + mapGroup["PolarRadius"].SetValue(42); + Isis::Pvl tmp1; + Isis::Projection & p2 = *Isis::ProjectionFactory::Create(lab); + tmp1.AddGroup(p2.Mapping()); + s = &p2; + cout << "created a second Projection reference p2" + << "\nusing the same pvl as p except for that PolarRadius = 42" + << "\nPvl for p2...\n" << tmp1 + << "\ns = &p2" + << "\n(*s == p) returns "; + if (*s == p) + cout << "true! ..................................... [ FAILED ]\n"; + else + cout << "false! .................................... [ OK ]\n"; + + double minX, maxX, minY, maxY; + p.XYRange(minX,maxX,minY,maxY); + cout << "\nXYRange..." + << "\n Minimum X: " << minX + << "\n Maximum X: " << maxX + << "\n Minimum Y: " << minY + << "\n Maximum Y: " << maxY << "\n"; + + Isis::Pvl tmp2; + tmp2.AddGroup(p.Mapping()); + + } + catch (Isis::iException &e) { + e.Report(false); + } +} + diff --git a/isis/src/base/objs/LunarLambert/LunarLambert.cpp b/isis/src/base/objs/LunarLambert/LunarLambert.cpp new file mode 100644 index 0000000000000000000000000000000000000000..917aeb49df2068589cc3aac7917c01c532258e65 --- /dev/null +++ b/isis/src/base/objs/LunarLambert/LunarLambert.cpp @@ -0,0 +1,55 @@ +#include +#include "LunarLambert.h" + +namespace Isis { + LunarLambert::LunarLambert (Pvl &pvl) : PhotoModel(pvl) { + PvlGroup &algo = pvl.FindObject("PhotometricModel") + .FindGroup("Algorithm",Pvl::Traverse); + // Set default value + SetPhotoL(1.0); + + // Get value from user + if (algo.HasKeyword("L")) SetPhotoL(algo["L"]); + } + + /** + * Set the Lunar-Lambert function weight. This is used to govern the + * limb-darkening in the Lunar-Lambert photometric function. Values of + * the Lunar-Lambert weight generally fall in the range from 0.0 + * (Lambert function) to 1.0 (Lommel-Seeliger or "lunar" function). + * There are no limits on the value of this parameter, but values far + * outside the 0 to 1 range will not be very useful. + * + * @param l Lunar-Lambert function weight, default is 1.0 + */ + void LunarLambert::SetPhotoL (const double l) { + p_photoL = l; + } + + double LunarLambert::PhotoModelAlgorithm (double phase, double incidence, + double emission) { + double pht_lunlam; + double incrad = incidence * Isis::PI / 180.0; + double emarad = emission * Isis::PI / 180.0; + double munot = cos(incrad); + double mu = cos(emarad); + + if (munot <= 0.0 || mu <= 0.0 || incidence == 90.0 || + emission == 90.0) { + pht_lunlam = 0.0; + } else if (p_photoL == 0.0) { + pht_lunlam = munot; + } else if (p_photoL == 1.0) { + pht_lunlam = 2.0 * munot / (munot + mu); + } else { + pht_lunlam = munot * ((1.0 - p_photoL) + 2.0 * + p_photoL / (munot + mu)); + } + + return pht_lunlam; + } +} + +extern "C" Isis::PhotoModel *LunarLambertPlugin (Isis::Pvl &pvl) { + return new Isis::LunarLambert(pvl); +} diff --git a/isis/src/base/objs/LunarLambert/LunarLambert.h b/isis/src/base/objs/LunarLambert/LunarLambert.h new file mode 100644 index 0000000000000000000000000000000000000000..2c15d1b715248f70a038f68c9dd0b705a084420d --- /dev/null +++ b/isis/src/base/objs/LunarLambert/LunarLambert.h @@ -0,0 +1,68 @@ +#if !defined(LunarLambert_h) +#define LunarLambert_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/06/19 14:34:21 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PhotoModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief Lunar (Lommel-Seeliger)-Lambert law photometric model + * Derive model albedo for Lunar (Lommel-Seeliger)-Lambert law. + * Phase independent and calculated analytically. + * Lommel-Seeliger law: + * + * Reflectance=1/(1+cos(E)/cos(I)) + * + * Where: E=the angle between the observer and the slope normal + * I=the angle between the sun and the slope normal + * + * @author 1999-01-08 Randy Kirk + * + * @internal + * @history 2007-07-31 Steven Lambright - Moved PhotoL from base PhotoModel class + * to this child. + */ + class LunarLambert : public PhotoModel { + public: + LunarLambert (Pvl &pvl); + virtual ~LunarLambert() {}; + + void SetPhotoL (const double l); + + //! Return photometric L value + inline double PhotoL () const { return p_photoL; }; + + private: + double p_photoL; + + protected: + virtual double PhotoModelAlgorithm (double phase, double incidence, + double emission); + + }; +}; + +#endif diff --git a/isis/src/base/objs/LunarLambert/LunarLambert.truth b/isis/src/base/objs/LunarLambert/LunarLambert.truth new file mode 100644 index 0000000000000000000000000000000000000000..b83978d63b5ffa03a32aa79af3207c4caa306f8a --- /dev/null +++ b/isis/src/base/objs/LunarLambert/LunarLambert.truth @@ -0,0 +1,41 @@ +UNIT TEST for LunarLambert photometric function + +Object = PhotometricModel + Group = Algorithm + Name = LunarLambert + End_Group +End_Object +End + +PhotoL = 1 +Test phase=0.0, incidence=0.0, emission=0.0 ... +Albedo = 1 +Test phase=60.0, incidence=45.0, emission=30.0 ... +Albedo = 0.898979 +Test phase=180.0, incidence=90.0, emission=90.0 ... +Albedo = 0 + +PhotoL = 0 +Test phase=0.0, incidence=0.0, emission=0.0 ... +Albedo = 1 +Test phase=60.0, incidence=45.0, emission=30.0 ... +Albedo = 0.707107 +Test phase=180.0, incidence=90.0, emission=90.0 ... +Albedo = 0 + +PhotoL = 0.5 +Test phase=0.0, incidence=0.0, emission=0.0 ... +Albedo = 1 +Test phase=60.0, incidence=45.0, emission=30.0 ... +Albedo = 0.803043 +Test phase=180.0, incidence=90.0, emission=90.0 ... +Albedo = 0 + +PhotoL = 2 +Test phase=0.0, incidence=0.0, emission=0.0 ... +Albedo = 1 +Test phase=60.0, incidence=45.0, emission=30.0 ... +Albedo = 1.09085 +Test phase=180.0, incidence=90.0, emission=90.0 ... +Albedo = 0 + diff --git a/isis/src/base/objs/LunarLambert/Makefile b/isis/src/base/objs/LunarLambert/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e0cac5bfa8d19c02d95e8d407dfcddf19daa1a5b --- /dev/null +++ b/isis/src/base/objs/LunarLambert/Makefile @@ -0,0 +1,5 @@ +INCS = LunarLambert.h +SRCS = LunarLambert.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/LunarLambert/PhotoModel.plugin b/isis/src/base/objs/LunarLambert/PhotoModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..1f9f7d6406c3331122be00ff3384b5bee5390fc9 --- /dev/null +++ b/isis/src/base/objs/LunarLambert/PhotoModel.plugin @@ -0,0 +1,4 @@ +Group = LunarLambert + Library = LunarLambert + Routine = LunarLambertPlugin +End_Group diff --git a/isis/src/base/objs/LunarLambert/unitTest.cpp b/isis/src/base/objs/LunarLambert/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b14863cd87f758115274f9494cfa461ebc64333 --- /dev/null +++ b/isis/src/base/objs/LunarLambert/unitTest.cpp @@ -0,0 +1,99 @@ +#include +#include +#include "LunarLambert.h" +#include "PhotoModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + std::cout << "UNIT TEST for LunarLambert photometric function" << + std::endl << std::endl; + + PvlGroup alg("Algorithm"); + alg += PvlKeyword("Name","LunarLambert"); + + PvlObject o("PhotometricModel"); + o.AddGroup(alg); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl << std::endl; + + try { + LunarLambert *pm = (LunarLambert*)PhotoModelFactory::Create(pvl); + + std::cout << "PhotoL = " << pm->PhotoL() << std::endl; + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(0.0,0.0,0.0) << + std::endl; + std::cout << "Test phase=60.0, incidence=45.0, emission=30.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(60.0,45.0,30.0) << + std::endl; + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(180.0,90.0,90.0) << + std::endl << std::endl; + + pm->SetPhotoL(0.0); + std::cout << "PhotoL = " << pm->PhotoL() << std::endl; + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(0.0,0.0,0.0) << + std::endl; + std::cout << "Test phase=60.0, incidence=45.0, emission=30.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(60.0,45.0,30.0) << + std::endl; + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(180.0,90.0,90.0) << + std::endl << std::endl; + + pm->SetPhotoL(0.5); + std::cout << "PhotoL = " << pm->PhotoL() << std::endl; + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(0.0,0.0,0.0) << + std::endl; + std::cout << "Test phase=60.0, incidence=45.0, emission=30.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(60.0,45.0,30.0) << + std::endl; + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(180.0,90.0,90.0) << + std::endl << std::endl; + + pm->SetPhotoL(2.0); + std::cout << "PhotoL = " << pm->PhotoL() << std::endl; + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(0.0,0.0,0.0) << + std::endl; + std::cout << "Test phase=60.0, incidence=45.0, emission=30.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(60.0,45.0,30.0) << + std::endl; + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(180.0,90.0,90.0) << + std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/LunarLambertMcEwen/LunarLambertMcEwen.cpp b/isis/src/base/objs/LunarLambertMcEwen/LunarLambertMcEwen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4520606467bd7ab32d503507ac0b947ae9a41a22 --- /dev/null +++ b/isis/src/base/objs/LunarLambertMcEwen/LunarLambertMcEwen.cpp @@ -0,0 +1,41 @@ +#include +#include "LunarLambertMcEwen.h" +#include "iException.h" + +namespace Isis { + LunarLambertMcEwen::LunarLambertMcEwen (Pvl &pvl) : PhotoModel(pvl) { + p_photoM1 = -0.019; + p_photoM2 = 0.000242; + p_photoM3 = -0.00000146; + + double c30 = cos(30.0*Isis::PI/180.0); + double xl30 = 1.0 + p_photoM1 * 30.0 + p_photoM2 * pow(30.0,2.0) + + p_photoM3 * pow(30.0,3); + p_photoR30 = 2.0 * xl30 * c30 / (1.0 + c30) + (1.0 - xl30) * c30; + } + + double LunarLambertMcEwen::PhotoModelAlgorithm (double phase, double incidence, + double emission) { + double pht_moonpr; + double incrad = incidence * Isis::PI / 180.0; + double emarad = emission * Isis::PI / 180.0; + double munot = cos(incrad); + double mu = cos(emarad); + + double xl = 1.0 + p_photoM1 * phase + p_photoM2 * pow(phase,2) + + p_photoM3 * pow(phase,3); + double r = 2.0 * xl * munot / (mu + munot) + (1.0 - xl) * munot; + + if (r <= 0.0) { + pht_moonpr = 0.0; + } else { + pht_moonpr = p_photoR30 / r; + } + + return pht_moonpr; + } +} + +extern "C" Isis::PhotoModel *LunarLambertMcEwenPlugin (Isis::Pvl &pvl) { + return new Isis::LunarLambertMcEwen(pvl); +} diff --git a/isis/src/base/objs/LunarLambertMcEwen/LunarLambertMcEwen.h b/isis/src/base/objs/LunarLambertMcEwen/LunarLambertMcEwen.h new file mode 100644 index 0000000000000000000000000000000000000000..3651d205b4ac20fc126c0d05594e2bee43a9884e --- /dev/null +++ b/isis/src/base/objs/LunarLambertMcEwen/LunarLambertMcEwen.h @@ -0,0 +1,58 @@ +#ifndef LunarLambertMcEwen_h +#define LunarLambertMcEwen_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/10/24 15:35:42 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PhotoModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief Moonpr photometric model + * Computes normalized albedo for the Moon, + * normalized to 0 degrees emission angle and + * 30 degrees illumination and phase angles. + * + * @author 1995-11-27 Alfred McEwen + * + * @internal + */ + class LunarLambertMcEwen : public PhotoModel { + public: + LunarLambertMcEwen (Pvl &pvl); + virtual ~LunarLambertMcEwen () {}; + + protected: + virtual double PhotoModelAlgorithm (double phase, double incidence, + double emission); + + private: + double p_photoM1; + double p_photoM2; + double p_photoM3; + double p_photoR30; + }; +}; + +#endif diff --git a/isis/src/base/objs/LunarLambertMcEwen/LunarLambertMcEwen.truth b/isis/src/base/objs/LunarLambertMcEwen/LunarLambertMcEwen.truth new file mode 100644 index 0000000000000000000000000000000000000000..e56da7fefffc96868d5c03b4d4070e2f49f57023 --- /dev/null +++ b/isis/src/base/objs/LunarLambertMcEwen/LunarLambertMcEwen.truth @@ -0,0 +1,16 @@ +UNIT TEST for LunarLambertMcEwen photometric function + +Object = PhotometricModel + Group = Algorithm + Name = LunarLambertMcEwen + End_Group +End_Object +End + +Test phase=0.0, incidence=0.0, emission=0.0 ... +Albedo = 0.903853 +Test phase=60.0, incidence=45.0, emission=30.0 ... +Albedo = 1.14863 +Test phase=180.0, incidence=90.0, emission=90.0 ... +Albedo = 0 + diff --git a/isis/src/base/objs/LunarLambertMcEwen/Makefile b/isis/src/base/objs/LunarLambertMcEwen/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5cfc5851b4e854d504bf4af51d71c60f49bc939f --- /dev/null +++ b/isis/src/base/objs/LunarLambertMcEwen/Makefile @@ -0,0 +1,5 @@ +INCS = LunarLambertMcEwen.h +SRCS = LunarLambertMcEwen.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/LunarLambertMcEwen/PhotoModel.plugin b/isis/src/base/objs/LunarLambertMcEwen/PhotoModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..34c69804dac9ecaec11b4e391c9411d1c902c7cf --- /dev/null +++ b/isis/src/base/objs/LunarLambertMcEwen/PhotoModel.plugin @@ -0,0 +1,4 @@ +Group = LunarLambertMcEwen + Library = LunarLambertMcEwen + Routine = LunarLambertMcEwenPlugin +End_Group diff --git a/isis/src/base/objs/LunarLambertMcEwen/unitTest.cpp b/isis/src/base/objs/LunarLambertMcEwen/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..705ca414656efc674512ed37a1abe20ef3da57ac --- /dev/null +++ b/isis/src/base/objs/LunarLambertMcEwen/unitTest.cpp @@ -0,0 +1,49 @@ +#include +#include +#include "LunarLambertMcEwen.h" +#include "PhotoModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + std::cout << "UNIT TEST for LunarLambertMcEwen photometric function" << + std::endl << std::endl; + + PvlGroup alg("Algorithm"); + alg += PvlKeyword("Name","LunarLambertMcEwen"); + + PvlObject o("PhotometricModel"); + o.AddGroup(alg); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl << std::endl; + + try { + LunarLambertMcEwen *pm = (LunarLambertMcEwen*)PhotoModelFactory::Create(pvl); + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(0.0,0.0,0.0) << + std::endl; + std::cout << "Test phase=60.0, incidence=45.0, emission=30.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(60.0,45.0,30.0) << + std::endl; + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(180.0,90.0,90.0) << + std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/Makefile b/isis/src/base/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/base/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/base/objs/Matrix/Makefile b/isis/src/base/objs/Matrix/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6c47ac6d14e4ee11cf23df22c393deb90b65a86a --- /dev/null +++ b/isis/src/base/objs/Matrix/Makefile @@ -0,0 +1,5 @@ +INCS = Matrix.h +SRCS = Matrix.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Matrix/Matrix.cpp b/isis/src/base/objs/Matrix/Matrix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1050a068fcc01412b2710a9d2f275de7576323a2 --- /dev/null +++ b/isis/src/base/objs/Matrix/Matrix.cpp @@ -0,0 +1,264 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2009/12/22 02:09:54 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "jama/jama_svd.h" +#include "jama/jama_eig.h" +#include "jama/jama_lu.h" + +#include "Matrix.h" +#include "iException.h" +#include "Constants.h" + +namespace Isis { + /** + * Constructs an n x m Matrix containing the specified default + * value. + */ + Matrix::Matrix (const int n, const int m, const double value) { + if (n <1 || m < 1) { + std::string m="Invalid matrix dimensions"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + p_matrix = TNT::Array2D(n,m,value); + } + + /** + * Constructs a Matrix from the specified TNT Array2D + */ + Matrix::Matrix (TNT::Array2D matrix) { + p_matrix = matrix.copy(); + } + + //! Destroys the Matrix object + Matrix::~Matrix() {} + + /** + * Create an n x n identity matrix + */ + Matrix Matrix::Identity(const int n) { + if (n<1) { + std::string m="Invalid matrix dimensions"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + Matrix identity(n,n); + for (int i=0; i lu(p_matrix); + return lu.det(); + } + + /** + * Compute the determinant of the matrix + */ + double Matrix::Trace() { + if (Rows() != Columns()) { + std::string m="Unable to calculate the trace, the matrix is not square."; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + double trace = 0.0; + for (int i=0; i m(matrix.Rows(), matrix.Columns()); + for (int i=0; i m(matrix.Rows(), matrix.Columns()); + for (int i=0; i m(matrix.Rows(), matrix.Columns()); + for (int i=0; i m(matrix.Rows(), matrix.Columns()); + for (int i=0; i transpose(p_matrix.dim2(), p_matrix.dim1()); + for (int i=0; i< transpose.dim1(); i++) { + for (int j=0; j id(p_matrix.dim1(), p_matrix.dim2(), 0.0); + for (int i = 0; i < p_matrix.dim1(); i++) id[i][i] = 1; + + JAMA::LU lu(p_matrix); + if (lu.det() == 0.0) { + std::string m="Cannot take the inverse of the matrix"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + return Matrix( lu.solve(id) ); + } + +/** + * Compute the eigenvalues of the matrix + */ + std::vector Matrix::Eigenvalues() { + if (Rows() != Columns()) { + std::string m="Unable to calculate eigenvalues, the matrix is not square."; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + JAMA::Eigenvalue E(p_matrix); + TNT::Array2D D; + E.getD(D); + + std::vector eigenvalues(D.dim1()); + for (int i=0; i E(p_matrix); + TNT::Array2D V; + E.getV(V); + + return Matrix(V); + } + + /** + * Write the matrix to the output stream + */ + ostream& operator<<(ostream &os, Matrix &matrix) { + for (int i=0; i +#include "tnt/tnt_array2d.h" + +namespace Isis { +/** + * @brief Matrix class + * + * A Matrix + * + * This class stores a matrix and compute matrix calculations + * such as addition, subtraction,multiplication, transposes, + * inverses, and eigenvalues. + * + * @ingroup Math + * + * @author 2006-05-19 Jacob Danton + * + * @internal + * @history 2006-05-19 Jacob Danton Original Version + * + * @history 2007-07-11 Brendan George Fixed unitTest to print values in + * "fixed" (non-scientific) format, added system specific unitTest + * for Linux i686 systems + */ + + class Matrix { + public: + Matrix (const int n, const int m, const double value = 0.0); + Matrix (TNT::Array2D matrix); + ~Matrix (); + + static Matrix Identity(const int n); + + inline int Rows() { return p_matrix.dim1();}; + inline int Columns() { return p_matrix.dim2();}; + + double Determinant(); + double Trace();; + + std::vector Eigenvalues(); + + Matrix Add(Matrix &matrix); + Matrix Subtract(Matrix &matrix); + Matrix Multiply(Matrix &matrix); + Matrix Multiply(double scalar); + Matrix MultiplyElementWise(Matrix &matrix); + Matrix Transpose(); + Matrix Inverse(); + Matrix Eigenvectors(); + + inline double * operator[] (int index) { return p_matrix[index];}; + Matrix operator+ (Matrix &matrix) { return Add(matrix);}; + Matrix operator- (Matrix &matrix) { return Subtract(matrix);}; + Matrix operator* (Matrix &matrix) { return Multiply(matrix);}; + Matrix operator* (double scalar) { return Multiply(scalar);}; + + private: + TNT::Array2D p_matrix; + }; + + std::ostream& operator<<(std::ostream &os, Matrix &matrix); +}; + +#endif diff --git a/isis/src/base/objs/Matrix/Matrix.truth b/isis/src/base/objs/Matrix/Matrix.truth new file mode 100644 index 0000000000000000000000000000000000000000..aa9a6bd4dd703b5412da84f551cbc05a8cb6bc83 --- /dev/null +++ b/isis/src/base/objs/Matrix/Matrix.truth @@ -0,0 +1,43 @@ +Identity: +1.000000000000 0.000000000000 +0.000000000000 1.000000000000 +A: +1.000000000000 2.000000000000 +3.000000000000 4.000000000000 +A+I: +2.000000000000 2.000000000000 +3.000000000000 5.000000000000 +A-I: +0.000000000000 2.000000000000 +3.000000000000 3.000000000000 +2.0*A: +2.000000000000 4.000000000000 +6.000000000000 8.000000000000 +A~ (transpose): +1.000000000000 3.000000000000 +2.000000000000 4.000000000000 +AI: +1.000000000000 2.000000000000 +3.000000000000 4.000000000000 +det(A)=-2.000000000000 +trace(A)=5.000000000000 +A': +-2.000000000000 1.000000000000 +1.500000000000 -0.500000000000 +AA': +1.000000000000 0.000000000000 +0.000000000000 1.000000000000 +Eigenvalues: -0.372281323269, 5.372281323269 +EigenVectors: +-0.824564840132 -0.422229150415 +0.565767464969 -0.923052314250 +B: +1.000000000000 1.000000000000 1.000000000000 +1.000000000000 1.000000000000 1.000000000000 +AB: +3.000000000000 3.000000000000 3.000000000000 +7.000000000000 7.000000000000 7.000000000000 +B~A: +4.000000000000 6.000000000000 +4.000000000000 6.000000000000 +4.000000000000 6.000000000000 diff --git a/isis/src/base/objs/Matrix/Matrix_Linux_i686_RedHat5_4.truth b/isis/src/base/objs/Matrix/Matrix_Linux_i686_RedHat5_4.truth new file mode 100644 index 0000000000000000000000000000000000000000..6f964a05023dc958dfa721b31a71f95ae18fe934 --- /dev/null +++ b/isis/src/base/objs/Matrix/Matrix_Linux_i686_RedHat5_4.truth @@ -0,0 +1,43 @@ +Identity: +1.000000000000 0.000000000000 +0.000000000000 1.000000000000 +A: +1.000000000000 2.000000000000 +3.000000000000 4.000000000000 +A+I: +2.000000000000 2.000000000000 +3.000000000000 5.000000000000 +A-I: +0.000000000000 2.000000000000 +3.000000000000 3.000000000000 +2.0*A: +2.000000000000 4.000000000000 +6.000000000000 8.000000000000 +A~ (transpose): +1.000000000000 3.000000000000 +2.000000000000 4.000000000000 +AI: +1.000000000000 2.000000000000 +3.000000000000 4.000000000000 +det(A)=-2.000000000000 +trace(A)=5.000000000000 +A': +-2.000000000000 1.000000000000 +1.500000000000 -0.500000000000 +AA': +1.000000000000 0.000000000000 +-0.000000000000 1.000000000000 +Eigenvalues: -0.372281323269, 5.372281323269 +EigenVectors: +-0.824564840132 -0.422229150415 +0.565767464969 -0.923052314250 +B: +1.000000000000 1.000000000000 1.000000000000 +1.000000000000 1.000000000000 1.000000000000 +AB: +3.000000000000 3.000000000000 3.000000000000 +7.000000000000 7.000000000000 7.000000000000 +B~A: +4.000000000000 6.000000000000 +4.000000000000 6.000000000000 +4.000000000000 6.000000000000 diff --git a/isis/src/base/objs/Matrix/Matrix_Linux_i686_RedHat5_5.truth b/isis/src/base/objs/Matrix/Matrix_Linux_i686_RedHat5_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..6f964a05023dc958dfa721b31a71f95ae18fe934 --- /dev/null +++ b/isis/src/base/objs/Matrix/Matrix_Linux_i686_RedHat5_5.truth @@ -0,0 +1,43 @@ +Identity: +1.000000000000 0.000000000000 +0.000000000000 1.000000000000 +A: +1.000000000000 2.000000000000 +3.000000000000 4.000000000000 +A+I: +2.000000000000 2.000000000000 +3.000000000000 5.000000000000 +A-I: +0.000000000000 2.000000000000 +3.000000000000 3.000000000000 +2.0*A: +2.000000000000 4.000000000000 +6.000000000000 8.000000000000 +A~ (transpose): +1.000000000000 3.000000000000 +2.000000000000 4.000000000000 +AI: +1.000000000000 2.000000000000 +3.000000000000 4.000000000000 +det(A)=-2.000000000000 +trace(A)=5.000000000000 +A': +-2.000000000000 1.000000000000 +1.500000000000 -0.500000000000 +AA': +1.000000000000 0.000000000000 +-0.000000000000 1.000000000000 +Eigenvalues: -0.372281323269, 5.372281323269 +EigenVectors: +-0.824564840132 -0.422229150415 +0.565767464969 -0.923052314250 +B: +1.000000000000 1.000000000000 1.000000000000 +1.000000000000 1.000000000000 1.000000000000 +AB: +3.000000000000 3.000000000000 3.000000000000 +7.000000000000 7.000000000000 7.000000000000 +B~A: +4.000000000000 6.000000000000 +4.000000000000 6.000000000000 +4.000000000000 6.000000000000 diff --git a/isis/src/base/objs/Matrix/Matrix_Linux_i686_SUSE10_1.truth b/isis/src/base/objs/Matrix/Matrix_Linux_i686_SUSE10_1.truth new file mode 100644 index 0000000000000000000000000000000000000000..6f964a05023dc958dfa721b31a71f95ae18fe934 --- /dev/null +++ b/isis/src/base/objs/Matrix/Matrix_Linux_i686_SUSE10_1.truth @@ -0,0 +1,43 @@ +Identity: +1.000000000000 0.000000000000 +0.000000000000 1.000000000000 +A: +1.000000000000 2.000000000000 +3.000000000000 4.000000000000 +A+I: +2.000000000000 2.000000000000 +3.000000000000 5.000000000000 +A-I: +0.000000000000 2.000000000000 +3.000000000000 3.000000000000 +2.0*A: +2.000000000000 4.000000000000 +6.000000000000 8.000000000000 +A~ (transpose): +1.000000000000 3.000000000000 +2.000000000000 4.000000000000 +AI: +1.000000000000 2.000000000000 +3.000000000000 4.000000000000 +det(A)=-2.000000000000 +trace(A)=5.000000000000 +A': +-2.000000000000 1.000000000000 +1.500000000000 -0.500000000000 +AA': +1.000000000000 0.000000000000 +-0.000000000000 1.000000000000 +Eigenvalues: -0.372281323269, 5.372281323269 +EigenVectors: +-0.824564840132 -0.422229150415 +0.565767464969 -0.923052314250 +B: +1.000000000000 1.000000000000 1.000000000000 +1.000000000000 1.000000000000 1.000000000000 +AB: +3.000000000000 3.000000000000 3.000000000000 +7.000000000000 7.000000000000 7.000000000000 +B~A: +4.000000000000 6.000000000000 +4.000000000000 6.000000000000 +4.000000000000 6.000000000000 diff --git a/isis/src/base/objs/Matrix/unitTest.cpp b/isis/src/base/objs/Matrix/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1fbe67847c8355141271a7a6a9287f894caabd14 --- /dev/null +++ b/isis/src/base/objs/Matrix/unitTest.cpp @@ -0,0 +1,49 @@ +#include "Matrix.h" +#include +#include +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + Matrix I = Matrix::Identity(2); + cout << fixed << setprecision(12) << "Identity:" << endl << I << endl; + Matrix A(2, 2); + + A[0][0] = 1; A[0][1] = 2; + A[1][0] = 3; A[1][1] = 4; + + cout << "A:" << endl << A << endl; + Matrix ApI = A+I, + AmI = A-I, + A2 = A*2.0; + cout << "A+I:" << endl << ApI << endl; + cout << "A-I:" << endl << AmI << endl; + cout << "2.0*A:" << endl << A2 << endl; + Matrix At = A.Transpose(); + cout << "A~ (transpose):" << endl << At << endl; + Matrix AI = A*I; + cout << "AI:" << endl << AI << endl; + cout << "det(A)=" << A.Determinant() << endl; + cout << "trace(A)=" << A.Trace() << endl; + Matrix Ai = A.Inverse(); + cout << "A':" << endl << Ai << endl; + Matrix AAi = A*Ai; + cout << "AA':" << endl << AAi << endl; + vector evals = A.Eigenvalues(); + cout << "Eigenvalues: " << evals[0] << ", " << evals[1] << endl; + Matrix E = A.Eigenvectors(); + cout << "EigenVectors:" << endl << E << endl; + + Matrix B(2, 3, 1); + cout << "B:" << endl << B << endl; + Matrix Bt = B.Transpose(), + AB = A*B, + BtA = Bt*A; + + cout << "AB:" << endl << AB << endl; + cout << "B~A:" << endl << BtA << endl; +} diff --git a/isis/src/base/objs/MaximumCorrelation/AutoReg.plugin b/isis/src/base/objs/MaximumCorrelation/AutoReg.plugin new file mode 100644 index 0000000000000000000000000000000000000000..26485b3f98f9bf118907c7bb7dd9cb5e78720e1e --- /dev/null +++ b/isis/src/base/objs/MaximumCorrelation/AutoReg.plugin @@ -0,0 +1,4 @@ +Group = MaximumCorrelation + Library = MaximumCorrelation + Routine = MaximumCorrelationPlugin +End_Group diff --git a/isis/src/base/objs/MaximumCorrelation/Makefile b/isis/src/base/objs/MaximumCorrelation/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..96c75329adedff1139a435c6c6d8fa962143a156 --- /dev/null +++ b/isis/src/base/objs/MaximumCorrelation/Makefile @@ -0,0 +1,5 @@ +INCS = MaximumCorrelation.h +SRCS = MaximumCorrelation.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/MaximumCorrelation/MaximumCorrelation.cpp b/isis/src/base/objs/MaximumCorrelation/MaximumCorrelation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9bd5ae35ad8f1a1173c7ab744c744679a8751623 --- /dev/null +++ b/isis/src/base/objs/MaximumCorrelation/MaximumCorrelation.cpp @@ -0,0 +1,43 @@ +#include "MaximumCorrelation.h" +#include "Chip.h" +#include "MultivariateStatistics.h" + +namespace Isis { + double MaximumCorrelation::MatchAlgorithm (Chip &pattern, Chip &subsearch) { + MultivariateStatistics mv; + std::vector pdn, sdn; + pdn.resize(pattern.Samples()); + sdn.resize(pattern.Samples()); + + for (int l=1; l<=pattern.Lines(); l++) { + for (int s=1; s<=pattern.Samples(); s++) { + pdn[s-1] = pattern.GetValue(s,l); + sdn[s-1] = subsearch.GetValue(s,l); + } + mv.AddData(&pdn[0],&sdn[0], pattern.Samples()); + } + double percentValid = (double) mv.ValidPixels() / + (pattern.Lines() * pattern.Samples()); + if (percentValid * 100.0 < this->PatternValidPercent()) return Isis::Null; + + double r = mv.Correlation(); + if (r == Isis::Null) return Isis::Null; + return fabs(r); + } + + /** + * This virtual method must return if the 1st fit is equal to or better + * than the second fit. + * + * @param fit1 1st goodness of fit + * @param fit2 2nd goodness of fit + */ + bool MaximumCorrelation::CompareFits (double fit1, double fit2) { + return (fit1 >= fit2); + } +} + +extern "C" Isis::AutoReg *MaximumCorrelationPlugin (Isis::Pvl &pvl) { + return new Isis::MaximumCorrelation(pvl); +} + diff --git a/isis/src/base/objs/MaximumCorrelation/MaximumCorrelation.h b/isis/src/base/objs/MaximumCorrelation/MaximumCorrelation.h new file mode 100644 index 0000000000000000000000000000000000000000..eb6fb4c2bab26deeae0e7ea58ee57ed85818fdd8 --- /dev/null +++ b/isis/src/base/objs/MaximumCorrelation/MaximumCorrelation.h @@ -0,0 +1,64 @@ +#if !defined(MaximumCorrelation_h) +#define MaximumCorrelation_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2009/06/16 16:12:10 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "AutoReg.h" + +namespace Isis { + class Pvl; + class Chip; + + /** + * @brief Maximum correlation pattern matching + * + * This class is used to construct a maximum correlation pattern matching + * algorith. That is, given a search chip and a pattern chip, the pattern + * chip is walked through the search chip. At each position the a sub-search + * chip is extracted which is the same size as the pattern chip. Then the + * correlation between the two is computed. The best fit = 1.0 which means + * the pattern chip and sub-search chip are identical + * + * @ingroup PatternMatching + * + * @see MinimumDifference AutoReg + * + * @internal + * @history 2006-01-11 Jacob Danton Added idealFit value, unitTest + * @history 2006-03-08 Jacob Danton Added sampling options + */ + class MaximumCorrelation : public AutoReg { + public: + MaximumCorrelation (Pvl &pvl) : AutoReg(pvl) { }; + virtual ~MaximumCorrelation() {}; + + protected: + virtual double MatchAlgorithm (Chip &pattern, Chip &subsearch); + virtual bool CompareFits(double fit1, double fit2); + virtual double IdealFit() const { return 1.0;}; + virtual std::string AlgorithmName() const {return "MaximumCorrelation";}; + + }; +}; + +#endif diff --git a/isis/src/base/objs/MaximumCorrelation/MaximumCorrelation.truth b/isis/src/base/objs/MaximumCorrelation/MaximumCorrelation.truth new file mode 100644 index 0000000000000000000000000000000000000000..81a62d5bbfdf9db67cef94fa6d8909acd305c6e8 --- /dev/null +++ b/isis/src/base/objs/MaximumCorrelation/MaximumCorrelation.truth @@ -0,0 +1,22 @@ +Object = AutoRegistration + Group = Algorithm + Name = MaximumCorrelation + Tolerance = 0.1 + SubpixelAccuracy = True + End_Group + + Group = PatternChip + Samples = 15 + Lines = 15 + Sampling = 50 + ValidPercent = 10 + End_Group + + Group = SearchChip + Samples = 35 + Lines = 35 + End_Group +End_Object +End +Register = 0 +Position = 120 45 diff --git a/isis/src/base/objs/MaximumCorrelation/unitTest.cpp b/isis/src/base/objs/MaximumCorrelation/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fde386debb7ededce73d7071dcfbef0d4341e7ce --- /dev/null +++ b/isis/src/base/objs/MaximumCorrelation/unitTest.cpp @@ -0,0 +1,60 @@ +#include +#include +#include "AutoReg.h" +#include "AutoRegFactory.h" +#include "Chip.h" +#include "Cube.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + try { + PvlGroup alg("Algorithm"); + alg += PvlKeyword("Name","MaximumCorrelation"); + alg += PvlKeyword("Tolerance",0.1); + alg += PvlKeyword("SubpixelAccuracy", "True"); + + PvlGroup pchip("PatternChip"); + pchip += PvlKeyword("Samples",15); + pchip += PvlKeyword("Lines",15); + pchip += PvlKeyword("Sampling",50); + pchip += PvlKeyword("ValidPercent", 10); + + PvlGroup schip("SearchChip"); + schip += PvlKeyword("Samples",35); + schip += PvlKeyword("Lines",35); + + PvlObject o("AutoRegistration"); + o.AddGroup(alg); + o.AddGroup(pchip); + o.AddGroup(schip); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl; + + AutoReg *ar = AutoRegFactory::Create(pvl); + + Cube c; + c.Open("$mgs/testData/ab102401.cub"); + + ar->SearchChip()->TackCube(125.0,50.0); + ar->SearchChip()->Load(c); + ar->PatternChip()->TackCube(120.0,45.0); + ar->PatternChip()->Load(c); + + std::cout << "Register = " << ar->Register() << std::endl; + std::cout << "Position = " << ar->CubeSample() << " " << + ar->CubeLine() << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/Mercator/Makefile b/isis/src/base/objs/Mercator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f8a81c2f3627e653fce9c78edae2f09962bf48ef --- /dev/null +++ b/isis/src/base/objs/Mercator/Makefile @@ -0,0 +1,5 @@ +INCS = Mercator.h +SRCS = Mercator.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Mercator/Mercator.cpp b/isis/src/base/objs/Mercator/Mercator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..40ca487e67bb2a06b79a950dc985edf5cf6770e0 --- /dev/null +++ b/isis/src/base/objs/Mercator/Mercator.cpp @@ -0,0 +1,304 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/05/09 18:49:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Mercator.h" +#include "iException.h" +#include "Constants.h" + +using namespace std; +namespace Isis { + /** + * Constructs a Mercator object + * + * @param label This argument must be a Label containing the proper mapping + * information as indicated in the Projection class. Additionally, + * the mercator projection requires the center longitude to be + * defined in the keyword CenterLongitude. + * + * @param allowDefaults If set to false the constructor expects that a keyword + * of CenterLongitude will be in the label. Otherwise it + * will attempt to compute the center longitude using the + * middle of the longitude range specified in the labels. + * Defaults to false. + * + * @throws Isis::iException::Io + */ + Mercator::Mercator(Isis::Pvl &label, bool allowDefaults) : + Isis::Projection::Projection (label) { + try { + // Try to read the mapping group + Isis::PvlGroup &mapGroup = label.FindGroup ("Mapping",Isis::Pvl::Traverse); + + // Compute and write the default center longitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLongitude"))) { + double lon = (p_minimumLongitude + p_maximumLongitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLongitude",lon); + } + + // Compute and write the default center latitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLatitude"))) { + double lat = (p_minimumLatitude + p_maximumLatitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLatitude",lat); + } + + // Get the center longitude & latitude + p_centerLongitude = mapGroup["CenterLongitude"]; + p_centerLatitude = mapGroup["CenterLatitude"]; + if (this->IsPlanetocentric()) { + p_centerLatitude = this->ToPlanetographic(p_centerLatitude); + } + + // convert to radians, adjust for longitude direction + p_centerLongitude *= Isis::PI / 180.0; + p_centerLatitude *= Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) p_centerLongitude *= -1.0; + + // Compute the scale factor + double cos_clat = cos(p_centerLatitude); + double sin_clat = sin(p_centerLatitude); + double p_eccsq = Eccentricity() * Eccentricity(); + p_scalefactor = cos_clat / sqrt(1.0 - p_eccsq * sin_clat * sin_clat); + } + catch (Isis::iException &e) { + string message = "Invalid label group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + //! Destroys the Mercator object + Mercator::~Mercator() { + } + + /** + * This method is used to set the latitude/longitude (assumed to be of the + * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. + * + * @param lat Latitude value to project + * + * @param lon Longitude value to project + * + * @return bool + */ + bool Mercator::SetGround(const double lat,const double lon) { + // Convert longitude to radians & clean up + p_longitude = lon; + double lonRadians = lon * Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) lonRadians *= -1.0; + + // Now convert latitude to radians & clean up ... it must be planetographic + p_latitude = lat; + double latRadians = lat; + if (IsPlanetocentric()) latRadians = ToPlanetographic(latRadians); + latRadians *= Isis::PI / 180.0; + + // Make sure latitude value is not too close to either pole + if (fabs( fabs(p_latitude) - 90.0) <= DBL_EPSILON) { + p_good = false; + return p_good; + } + + // Compute the coordinate + double deltaLon = (lonRadians - p_centerLongitude); + double x = p_equatorialRadius * deltaLon * p_scalefactor; + double sinphi = sin(latRadians); + double t = tCompute(latRadians, sinphi); + double y = -p_equatorialRadius * p_scalefactor * log(t); + SetComputedXY(x,y); + p_good = true; + return p_good; + } + + /** + * This method is used to set the projection x/y. The Set forces an attempted + * calculation of the corresponding latitude/longitude position. This may or + * may not be successful and a status is returned as such. + * + * @param x X coordinate of the projection in units that are the same as the + * radii in the label + * + * @param y Y coordinate of the projection in units that are the same as the + * radii in the label + * + * @return bool + */ + bool Mercator::SetCoordinate(const double x, const double y) { + // Save the coordinate + SetXY(x,y); + + // Compute Snyder's t + double snyders_t = exp(-GetY()/(p_equatorialRadius * p_scalefactor)); + + // Compute latitude and make sure it is not above 90 + p_latitude = phi2Compute(snyders_t); + if (fabs(p_latitude) > Isis::HALFPI) { + if (fabs(Isis::HALFPI - fabs(p_latitude)) > DBL_EPSILON) { + p_good = false; + return p_good; + } + else if (p_latitude < 0.0) { + p_latitude = -Isis::HALFPI; + } + else { + p_latitude = Isis::HALFPI; + } + } + + // Compute longitude + double coslat = cos(p_latitude); + if (coslat <= DBL_EPSILON) { + p_longitude = p_centerLongitude; + } + else { + p_longitude = p_centerLongitude + GetX() / + (p_equatorialRadius * p_scalefactor); + } + + // Convert to degrees + p_latitude *= 180.0 / Isis::PI; + p_longitude *= 180.0 / Isis::PI; + + // Cleanup the longitude + if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; + // These need to be done for circular type projections + // p_longitude = To360Domain (p_longitude); + // if (p_longitudeDomain == 180) p_longitude = To180Domain(p_longitude); + + // Cleanup the latitude + if (IsPlanetocentric()) p_latitude = ToPlanetocentric(p_latitude); + + p_good = true; + return p_good; + } + + /** + * This method is used to determine the x/y range which completely covers the + * area of interest specified by the lat/lon range. The latitude/longitude + * range may be obtained from the labels. The purpose of this method is to + * return the x/y range so it can be used to compute how large a map may need + * to be. For example, how big a piece of paper is needed or how large of an + * image needs to be created. The method may fail as indicated by its return + * value. + * + * @param minX Minimum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxX Maximum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param minY Minimum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxY Maximum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @return bool + */ + bool Mercator::XYRange(double &minX, double &maxX, double &minY, double&maxY){ + // Check the corners of the lat/lon range + XYRangeCheck (p_minimumLatitude,p_minimumLongitude); + XYRangeCheck (p_maximumLatitude,p_minimumLongitude); + XYRangeCheck (p_minimumLatitude,p_maximumLongitude); + XYRangeCheck (p_maximumLatitude,p_maximumLongitude); + + // Make sure everything is ordered + if (p_minimumX >= p_maximumX) return false; + if (p_minimumY >= p_maximumY) return false; + + // Return X/Y min/maxs + minX = p_minimumX; + maxX = p_maximumX; + minY = p_minimumY; + maxY = p_maximumY; + return true; + } + + /** + * This function returns the keywords that this projection uses. + * + * @return PvlGroup The keywords that this projection uses + */ + PvlGroup Mercator::Mapping() { + PvlGroup mapping = Projection::Mapping(); + + mapping += p_mappingGrp["CenterLatitude"]; + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * This function returns the latitude keywords that this projection uses + * + * @return PvlGroup The latitude keywords that this projection uses + */ + PvlGroup Mercator::MappingLatitudes() { + PvlGroup mapping = Projection::MappingLatitudes(); + + mapping += p_mappingGrp["CenterLatitude"]; + + return mapping; + } + + /** + * This function returns the longitude keywords that this projection uses + * + * @return PvlGroup The longitude keywords that this projection uses + */ + PvlGroup Mercator::MappingLongitudes() { + PvlGroup mapping = Projection::MappingLongitudes(); + + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * Compares two Projection objects to see if they are equal + * + * @param proj Projection object to do comparison on + * + * @return bool Returns true if the Projection objects are equal, and false if + * they are not + */ + bool Mercator::operator== (const Isis::Projection &proj) { + if (!Isis::Projection::operator==(proj)) return false; + // dont do the below it is a recusive plunge + // if (Isis::Projection::operator!=(proj)) return false; + Mercator *merc = (Mercator *) &proj; + if ((merc->p_centerLongitude != this->p_centerLongitude) || + (merc->p_centerLatitude != this->p_centerLatitude)) return false; + return true; + } +} // end namespace isis + +extern "C" Isis::Projection *MercatorPlugin (Isis::Pvl &lab, + bool allowDefaults) { + return new Isis::Mercator(lab,allowDefaults); +} + + diff --git a/isis/src/base/objs/Mercator/Mercator.h b/isis/src/base/objs/Mercator/Mercator.h new file mode 100644 index 0000000000000000000000000000000000000000..60d09a3ec1349f0a8ee985fd08c0cbd9aac78ca7 --- /dev/null +++ b/isis/src/base/objs/Mercator/Mercator.h @@ -0,0 +1,101 @@ +#ifndef Mercator_h +#define Mercator_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/05/09 18:49:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Projection.h" +#include "Constants.h" + +namespace Isis { +/** + * @brief Mercator Map Projection + * + * This class provides methods for the forward and inverse equations of a + * Mercator map projection (for an ellipse). The code was converted + * to C++ from the C version of the USGS General Cartographic Transformation + * Package (GCTP). This class inherits Projection and provides the two virtual + * methods SetGround (forward) and SetCoordinate (inverse) and a third virtual + * method, XYRange, for obtaining projection coordinate coverage for a + * latitude/longitude window. Please see the Projection class for a full + * accounting of all the methods available. + * + * @ingroup MapProjection + * + * @author 2005-02-25 Elizabeth Ribelin + * + * @internal + * @history 2005-03-18 Elizabeth Ribelin - added TrueScaleLatitude method to + * class and tested in unitTest + * @history 2007-06-29 Steven Lambright - Added Mapping, MappingLatitudes and + * MappingLongitudes methods. + * @history 2008-05-09 Steven Lambright - Added Name, Version, IsEquatorialCylindrical methods + */ + class Mercator : public Isis::Projection { + public: + Mercator(Isis::Pvl &label, bool allowDefaults=false); + ~Mercator(); + + bool SetGround (const double lat, const double lon); + bool SetCoordinate (const double x, const double y); + bool XYRange (double &minX, double &maxX, double &minY, double &maxY); + PvlGroup Mapping(); + PvlGroup MappingLatitudes(); + PvlGroup MappingLongitudes(); + + bool IsEquatorialCylindrical() { return true; } + + /** + * Returns the name of the map projection + * + * @return string Name of projection + */ + std::string Name() const { return "Mercator"; } + + /** + * Returns the version of the map projection + * + * + * @return std::string Version number + */ + std::string Version () const { return "1.0"; } + + bool operator== (const Isis::Projection &proj); + + /** + * Returns the latitude of true scale (in the case of Mercator + * it is the center latitude) + * + * @return double + */ + double TrueScaleLatitude () const { + return p_centerLatitude * 180.0 / Isis::PI; + }; + + + private: + double p_centerLongitude; //! +#include +#include "Mercator.h" +#include "iException.h" +#include "ProjectionFactory.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "UNIT TEST FOR Mercator" << endl << endl; + + Isis::Pvl lab; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = lab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",6378206.4); + mapGroup += Isis::PvlKeyword("PolarRadius",6356583.8); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetographic"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",180); + mapGroup += Isis::PvlKeyword("MinimumLatitude",-70.0); + mapGroup += Isis::PvlKeyword("MaximumLatitude",70.0); + mapGroup += Isis::PvlKeyword("MinimumLongitude",-180.0); + mapGroup += Isis::PvlKeyword("MaximumLongitude",180.0); + mapGroup += Isis::PvlKeyword("ProjectionName","Mercator"); + + cout << "Test missing center longitude keyword ..." << endl; + try { + Isis::Mercator p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("CenterLongitude",-180.0); + + cout << "Test missing center latitude keyword..." << endl; + try { + Isis::Mercator p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("CenterLatitude", 0.0); + + try { + Isis::Projection &p = *Isis::ProjectionFactory::Create(lab); + // Isis::Mercator p(lab); + + cout << "Test SetGround method ... " << endl; + cout << std::setprecision(9); + cout << "Setting ground to (35,-75)" << endl; + p.SetGround(35.0,-75.0); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + + cout << "Test SetCoordinate method ... " << endl; + cout << "Setting coordinate to (11688673.7,4139145.66)" << endl; + p.SetCoordinate(11688673.7,4139145.66); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + cout << "Test XYRange method ... " << endl; + double minX,maxX,minY,maxY; + p.XYRange(minX,maxX,minY,maxY); + cout << "Minimum X: " << minX << endl; + cout << "Maximum X: " << maxX << endl; + cout << "Minimum Y: " << minY << endl; + cout << "Maximum Y: " << maxY << endl; + cout << endl; + + Isis::Projection *s = &p; + cout << "Test Name and comparision method ... " << endl; + cout << "Name: " << s->Name() << endl; + cout << "operator== " << (*s == *s) << endl; + cout << endl; + + cout << "Test default computation ... " << endl; + mapGroup.DeleteKeyword("CenterLongitude"); + mapGroup.DeleteKeyword("CenterLatitude"); + Isis::Mercator p2(lab,true); + cout << lab << endl; + cout << endl; + + cout << "Test TrueScaleLatitude method... " << endl; + cout << "TrueScaleLatitude = " << p.TrueScaleLatitude() << endl; + cout << endl; + + cout << "Testing Mapping() methods ... " << endl; + + Isis::Pvl tmp1; + Isis::Pvl tmp2; + Isis::Pvl tmp3; + tmp1.AddGroup(p.Mapping()); + tmp2.AddGroup(p.MappingLatitudes()); + tmp3.AddGroup(p.MappingLongitudes()); + + cout << "Mapping() = " << endl; + cout << tmp1 << endl; + cout << "MappingLatitudes() = " << endl; + cout << tmp2 << endl; + cout << "MappingLongitudes() = " << endl; + cout << tmp3 << endl; + cout << endl; + + cout << "Unit test was obtained from:" << endl << endl; + cout << " Map Projections - A Working Manual" << endl; + cout << " USGS Professional Paper 1395 by John P. Snyder" << endl; + cout << " Pages 267-268" << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } +} + diff --git a/isis/src/base/objs/Message/ArraySubscriptNotInRange.cpp b/isis/src/base/objs/Message/ArraySubscriptNotInRange.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ea1fca7aca8963cd007fc44388c7d56e82e3b02a --- /dev/null +++ b/isis/src/base/objs/Message/ArraySubscriptNotInRange.cpp @@ -0,0 +1,33 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include +#include "Message.h" + +string Isis::Message::ArraySubscriptNotInRange(const int index) { + ostringstream os; + os << "Array subscript [" << index << "] is out of array bounds"; + return os.str(); +} diff --git a/isis/src/base/objs/Message/FileCreate.cpp b/isis/src/base/objs/Message/FileCreate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a2bdd8d99bcfcafcd6eca756770d4c52fffb9b2b --- /dev/null +++ b/isis/src/base/objs/Message/FileCreate.cpp @@ -0,0 +1,32 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::FileCreate (const string &filename) { + string message; + message = "Unable to create [" + filename + "]"; + return message; +} diff --git a/isis/src/base/objs/Message/FileOpen.cpp b/isis/src/base/objs/Message/FileOpen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5d769c335c31cab2a88c6711c9b6b75f586769f5 --- /dev/null +++ b/isis/src/base/objs/Message/FileOpen.cpp @@ -0,0 +1,32 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::FileOpen (const string &filename) { + string message; + message = "Unable to open [" + filename + "]"; + return message; +} diff --git a/isis/src/base/objs/Message/FileRead.cpp b/isis/src/base/objs/Message/FileRead.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8b9bca6d0ff3d207836d518d8ea88e253701b64 --- /dev/null +++ b/isis/src/base/objs/Message/FileRead.cpp @@ -0,0 +1,32 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::FileRead (const string &filename) { + string message; + message = "Unable to read [" + filename + "]"; + return message; +} diff --git a/isis/src/base/objs/Message/FileWrite.cpp b/isis/src/base/objs/Message/FileWrite.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d427bd591f61fca0841739ac01534142f40af4c7 --- /dev/null +++ b/isis/src/base/objs/Message/FileWrite.cpp @@ -0,0 +1,32 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::FileWrite (const string &filename) { + string message; + message = "Unable to write [" + filename + "]"; + return message; +} diff --git a/isis/src/base/objs/Message/KeywordAmbiguous.cpp b/isis/src/base/objs/Message/KeywordAmbiguous.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e33fed6138a73539be62616e0ea39f9f0f832e2 --- /dev/null +++ b/isis/src/base/objs/Message/KeywordAmbiguous.cpp @@ -0,0 +1,34 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +using namespace std; + +#include "Message.h" + +string Isis::Message::KeywordAmbiguous (const string &key) { + string message; + message = "Keyword [" + key + "] ambiguous"; + return message; +} diff --git a/isis/src/base/objs/Message/KeywordBlockEndMissing.cpp b/isis/src/base/objs/Message/KeywordBlockEndMissing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18b45948f7b311b399b836686c45776b80d12742 --- /dev/null +++ b/isis/src/base/objs/Message/KeywordBlockEndMissing.cpp @@ -0,0 +1,34 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::KeywordBlockEndMissing + (const string &block, const string &found) { + string message; + message = "Expecting end of keyword block [" + block + "] " + + "but found [" + found + "]"; + return message; +} diff --git a/isis/src/base/objs/Message/KeywordBlockInvalid.cpp b/isis/src/base/objs/Message/KeywordBlockInvalid.cpp new file mode 100644 index 0000000000000000000000000000000000000000..386f3688550bcc3f8d371dc4cbaa11ebfb391b49 --- /dev/null +++ b/isis/src/base/objs/Message/KeywordBlockInvalid.cpp @@ -0,0 +1,32 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::KeywordBlockInvalid (const string &block) { + string message; + message = "Keyword block [" + block + "] is invalid"; + return message; +} diff --git a/isis/src/base/objs/Message/KeywordBlockStartMissing.cpp b/isis/src/base/objs/Message/KeywordBlockStartMissing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f3b57f74878313c3c3daa1599bc0b2bdd6c5307c --- /dev/null +++ b/isis/src/base/objs/Message/KeywordBlockStartMissing.cpp @@ -0,0 +1,34 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::KeywordBlockStartMissing + (const string &block, const string &found) { + string message; + message = "Expecting start of keyword block [" + block + "] " + + "but found [" + found + "]"; + return message; +} diff --git a/isis/src/base/objs/Message/KeywordDuplicated.cpp b/isis/src/base/objs/Message/KeywordDuplicated.cpp new file mode 100644 index 0000000000000000000000000000000000000000..93c63c6322f39c09b28c9bb3a1ef7fc4b6982417 --- /dev/null +++ b/isis/src/base/objs/Message/KeywordDuplicated.cpp @@ -0,0 +1,32 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::KeywordDuplicated (const string &key) { + string message; + message = "Keyword [" + key + "] duplicated"; + return message; +} diff --git a/isis/src/base/objs/Message/KeywordNotArray.cpp b/isis/src/base/objs/Message/KeywordNotArray.cpp new file mode 100644 index 0000000000000000000000000000000000000000..572431bf88774e71952d13b4a462d320b730cf41 --- /dev/null +++ b/isis/src/base/objs/Message/KeywordNotArray.cpp @@ -0,0 +1,32 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::KeywordNotArray (const string &key) { + string message; + message = "Keyword [" + key + "] is not an array"; + return message; +} diff --git a/isis/src/base/objs/Message/KeywordNotFound.cpp b/isis/src/base/objs/Message/KeywordNotFound.cpp new file mode 100644 index 0000000000000000000000000000000000000000..342f265a54a5a30759a53e531fa49986f2a47afd --- /dev/null +++ b/isis/src/base/objs/Message/KeywordNotFound.cpp @@ -0,0 +1,32 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::KeywordNotFound (const string &key) { + string message; + message = "Keyword [" + key + "] required but was not found"; + return message; +} diff --git a/isis/src/base/objs/Message/KeywordUnrecognized.cpp b/isis/src/base/objs/Message/KeywordUnrecognized.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a35c6171c48141389f41ec87478aac8c647377a4 --- /dev/null +++ b/isis/src/base/objs/Message/KeywordUnrecognized.cpp @@ -0,0 +1,32 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::KeywordUnrecognized (const string &key) { + string message; + message = "Keyword [" + key + "] unrecognized"; + return message; +} diff --git a/isis/src/base/objs/Message/KeywordValueBad.cpp b/isis/src/base/objs/Message/KeywordValueBad.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8704c45b223f8d3176ce7b82ae9b48e2224483b0 --- /dev/null +++ b/isis/src/base/objs/Message/KeywordValueBad.cpp @@ -0,0 +1,45 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::KeywordValueBad (const string &key) { + string message; + message = "Keyword [" + key + "] has bad value"; + return message; +} + +string Isis::Message::KeywordValueBad (const string &key, const string &value) { + string message; + + message = "Keyword [" + key + "] has bad value ["; + if (value.size () <= 20) { + message += value + "]"; + } + else { + message += value.substr(0,20) + " ...]"; + } + return message; +} diff --git a/isis/src/base/objs/Message/KeywordValueExpected.cpp b/isis/src/base/objs/Message/KeywordValueExpected.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad4db3ef48d7f45a43b4ff76ae7be8bcfea22b89 --- /dev/null +++ b/isis/src/base/objs/Message/KeywordValueExpected.cpp @@ -0,0 +1,32 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::KeywordValueExpected (const string &key) { + string message; + message = "Keyword value for [" + key + "] expected but was not found"; + return message; +} diff --git a/isis/src/base/objs/Message/KeywordValueNotInList.cpp b/isis/src/base/objs/Message/KeywordValueNotInList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..002fb33e073e5c621ff2a4ba9b8a72cbf0c17e56 --- /dev/null +++ b/isis/src/base/objs/Message/KeywordValueNotInList.cpp @@ -0,0 +1,39 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +using namespace std; + +#include "Message.h" + +string Isis::Message::KeywordValueNotInList + (const string &key, const string &value, const vector &list) { + string message; + message = "Keyword [" + key + "=" + value + "] must be one of ["; + for (unsigned int i=0; i +#include + +namespace Isis { + /* Documentation for this namespaceis in: + * isis/src/docsys/Object/build/isisDoxyDefs.doxydef + */ + namespace Message { + using namespace std; + /** + * This error should be used when an Isis object or application is checking + * array bounds and the legal range has been violated. + * + * @param index - Array index which is out of bounds + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string ArraySubscriptNotInRange (const int index); + + /** + * This error should be used when a supplied keyword for an Isis application + * parameter does not contain enough characters to distinguish it from + * another keyword. + * + * @param key - The name of the keyword which is ambiguous + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordAmbiguous (const string &key); + + /** + * This error should be used when a supplied keyword for an Isis application + * parameter does not match any of the parameters for that application. + * + * @param key - The name of the keyword which is unrecognized + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordUnrecognized (const string &key); + + /** + * This error should be used when a supplied keyword for an Isis application + * parameter is the same as one previously supplied. + * + * @param key - The name of the keyword which has been duplicated + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordDuplicated (const string &key); + + /** + * This error should be used when a supplied keyword is being used as an + * array (i.e., with a subscript) but is only a scaler entity. + * + * @param key - The name of the keyword which is not an array + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordNotArray (const string &key); + + /** + * This error should be used when a supplied keyword is not defined in the + * application. + * + * @param key - The name of the keyword which was not found + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordNotFound (const string &key); + + /** + * This error has been deprecated and should not be used in new code. + * + * @param block - The name of the invalid keyword block + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordBlockInvalid (const string &block); + + /** + * This error has been deprecated and should not be used in new code. + * + * @param block - The name of the block with the missing start tag + * @param found - The string found in the place of the missing block start + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordBlockStartMissing (const string &block, const string &found); + + /** + * This error has been deprecated and should not be used in new code. + * + * @param block - The name of the block with the missing end tag + * @param found - The string found in the place of the missing block end + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordBlockEndMissing (const string &block, const string &found); + + /** + * This error should be used when a supplied keyword does not appear in + * the list (e.g., an Isis cube label). + * + * @param key - The name of the keyword which is bad + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordValueBad (const string &key); + + /** + * This error should be used when the value of a supplied keyword is + * incorrect. + * + * @param key - The keyword name which is bad + * @param value - The value of the keyword which is bad + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordValueBad (const string &key, const string &value); + + /** + * This error should be used when the value of a supplied keyword was + * expected but not present. + * + * @param key - The keyword name which is bad + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordValueExpected (const string &key); + + /** + * This error should be used when the value of a supplied keyword is + * not within a specific range. + * + * @param key - The keyword name which has a bad value + * @param value - The value of the keyword + * @param range - The minimum and maximum allowed values for the keyword + * formatted and inserted into a string + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordValueNotInRange (const string &key, const string &value, + const string &range); + + /** + * This error should be used when the value of a supplied keyword is + * not one of a specific list of possible values. + * + * @param key - The keyword name which has a bad value + * @param value - The value of the keyword + * @param list - A vector of all the legal values for the keyword + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string KeywordValueNotInList (const string &key, const string &value, + const vector &list); + + /** + * This error should be used when a delimiter is missing. + * + * @param delimiter - The delimiter that is missing + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string MissingDelimiter (const char delimiter); + + /** + * This error should be used when a delimiter is missing. + * + * @param delimiter - The delimiter that is missing + * @param near - The value the missing delimiter is near + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string MissingDelimiter (const char delimiter, const string &near); + + /** + * This error should be used when a file could not be opened. + * + * @param filename - The name of the file + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string FileOpen (const string &filename); + + /** + * This error should be used when a file could not be created. + * + * @param filename - The name of the file + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string FileCreate (const string &filename); + + /** + * This error should be used when an error accrues during a read of a file. + * + * @param filename - The name of the file + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string FileRead (const string &filename); + + /** + * This error should be used when an error accrues during a write to a file. + * + * @param filename - The name of the file + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string FileWrite (const string &filename); + + /** + * This error should be used when an error accrues during a memory + * allocation such as "new". + * + * @return string - A standardized Isis error message with the parameter + * inserted + */ + string MemoryAllocationFailed (); + } +} + +#endif diff --git a/isis/src/base/objs/Message/Message.truth b/isis/src/base/objs/Message/Message.truth new file mode 100644 index 0000000000000000000000000000000000000000..214622816172473e6daf89e2e20f498d456e7c23 --- /dev/null +++ b/isis/src/base/objs/Message/Message.truth @@ -0,0 +1,28 @@ +Array subscript [100000] is out of array bounds + +Keyword [KEY] ambiguous +Keyword [KEY] unrecognized +Keyword [KEY] duplicated +Keyword [KEY] is not an array +Keyword [KEY] required but was not found + +Keyword block [BLOCK] is invalid +Expecting start of keyword block [BLOCK] but found [FOUND] +Expecting end of keyword block [BLOCK] but found [FOUND] + +Keyword [KEY] has bad value +Keyword [KEY] has bad value [12345678901234567890] +Keyword [KEY] has bad value [abcdefghijklmnopqrst ...] +Keyword value for [KEY] expected but was not found +Keyword [KEY=0] is not in the range of (0,20] +Keyword [KEY=A] must be one of [X,Y,Z] + +Missing delimiter [)] +Missing delimiter [)] at or near [12345678901234567890] +Missing delimiter [)] at or near [abcdefghijklmnopqrst ...] + +Unable to open [test.dat] +Unable to create [test.dat] +Unable to read [test.dat] +Unable to write [test.dat] + diff --git a/isis/src/base/objs/Message/MissingDelimiter.cpp b/isis/src/base/objs/Message/MissingDelimiter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30b3ca60b070aa0674c3ff0af243fe4483b79512 --- /dev/null +++ b/isis/src/base/objs/Message/MissingDelimiter.cpp @@ -0,0 +1,23 @@ +using namespace std; + +#include +#include "Message.h" + +string Isis::Message::MissingDelimiter (const char d) { + ostringstream os; + os << "Missing delimiter [" << d << "]"; + return os.str(); +} + +string Isis::Message::MissingDelimiter (const char d, const string &near) { + ostringstream os; + + os << "Missing delimiter [" << d << "] at or near ["; + if (near.size () <= 20) { + os << near << "]"; + } + else { + os << near.substr(0,20) << " ...]"; + } + return os.str(); +} diff --git a/isis/src/base/objs/Message/unitTest.cpp b/isis/src/base/objs/Message/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f4a3284b442e309d670a7abed666c1ae358eacd --- /dev/null +++ b/isis/src/base/objs/Message/unitTest.cpp @@ -0,0 +1,94 @@ +#include +#include "Message.h" +#include "Preference.h" + +using namespace std; +int main (void) { + Isis::Preference::Preferences(true); + + +//*************************************************************************** + + cout << Isis::Message::ArraySubscriptNotInRange (100000) + << endl; + + cout << endl; + +//*************************************************************************** + + cout << Isis::Message::KeywordAmbiguous ("KEY") + << endl; + + cout << Isis::Message::KeywordUnrecognized ("KEY") + << endl; + + cout << Isis::Message::KeywordDuplicated ("KEY") + << endl; + + cout << Isis::Message::KeywordNotArray ("KEY") + << endl; + + cout << Isis::Message::KeywordNotFound ("KEY") + << endl; + + cout << endl; + +//*************************************************************************** + + cout << Isis::Message::KeywordBlockInvalid ("BLOCK") + << endl; + + cout << Isis::Message::KeywordBlockStartMissing ("BLOCK","FOUND") + << endl; + + cout << Isis::Message::KeywordBlockEndMissing ("BLOCK","FOUND") + << endl; + + cout << endl; + +//*************************************************************************** + + cout << Isis::Message::KeywordValueBad ("KEY") + << endl; + + cout << Isis::Message::KeywordValueBad ("KEY","12345678901234567890") + << endl; + + cout << Isis::Message::KeywordValueBad ("KEY","abcdefghijklmnopqrstuvwxyz") + < list; + list.push_back ("X"); list.push_back ("Y"); list.push_back ("Z"); + cout << Isis::Message::KeywordValueNotInList ("KEY","A",list) + < +#include +#include "AutoReg.h" +#include "AutoRegFactory.h" +#include "Chip.h" +#include "Cube.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + try { + PvlGroup alg("Algorithm"); + alg += PvlKeyword("Name","MinimumDifference"); + alg += PvlKeyword("Tolerance",5.0); + alg += PvlKeyword("SubpixelAccuracy", "True"); + + PvlGroup pchip("PatternChip"); + pchip += PvlKeyword("Samples",15); + pchip += PvlKeyword("Lines",15); + pchip += PvlKeyword("Sampling",25); + pchip += PvlKeyword("ValidPercent", 10); + + PvlGroup schip("SearchChip"); + schip += PvlKeyword("Samples",35); + schip += PvlKeyword("Lines",35); + schip += PvlKeyword("Sampling", 50); + + PvlObject o("AutoRegistration"); + o.AddGroup(alg); + o.AddGroup(pchip); + o.AddGroup(schip); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl; + + AutoReg *ar = AutoRegFactory::Create(pvl); + + Cube c; + c.Open("$mgs/testData/ab102401.cub"); + + ar->SearchChip()->TackCube(125.0,50.0); + ar->SearchChip()->Load(c); + ar->PatternChip()->TackCube(120.0,45.0); + ar->PatternChip()->Load(c); + + std::cout << "Register = " << ar->Register() << std::endl; + std::cout << "Position = " << ar->CubeSample() << " " << + ar->CubeLine() << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/Minnaert/Makefile b/isis/src/base/objs/Minnaert/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a999fe6d984c3974270d6a3ad8fa5fa3f6423fec --- /dev/null +++ b/isis/src/base/objs/Minnaert/Makefile @@ -0,0 +1,5 @@ +INCS = Minnaert.h +SRCS = Minnaert.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Minnaert/Minnaert.cpp b/isis/src/base/objs/Minnaert/Minnaert.cpp new file mode 100644 index 0000000000000000000000000000000000000000..68e772bc38fc76032cf78ce6c7c73794eb35d81a --- /dev/null +++ b/isis/src/base/objs/Minnaert/Minnaert.cpp @@ -0,0 +1,56 @@ +#include +#include "Minnaert.h" +#include "iException.h" + +namespace Isis { + Minnaert::Minnaert (Pvl &pvl) : PhotoModel(pvl) { + PvlGroup &algo = pvl.FindObject("PhotometricModel") + .FindGroup("Algorithm",Pvl::Traverse); + // Set default value + SetPhotoK(1.0); + // Get value from user + if (algo.HasKeyword("K")) SetPhotoK(algo["K"]); + } + + /** + * Set the Minnaert function exponent. This is used to govern the limb- + * darkening in the Minnaert photometric function. Values of the + * Minnaert exponent generally fall in the range from 0.5 ("lunar-like", + * almost no limb darkening) to 1.0 (Lambert function). This + * parameter is limited to values that are >=0. + * + * @param k Minnaert function exponent, default is 1.0 + */ + void Minnaert::SetPhotoK (const double k) { + if (k < 0.0) { + std::string msg = "Invalid value of Minnaert k [" + + iString(k) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_photoK = k; + } + + double Minnaert::PhotoModelAlgorithm (double phase, double incidence, + double emission) { + double pht_minnaert; + double incrad = incidence * Isis::PI / 180.0; + double emarad = emission * Isis::PI / 180.0; + double munot = cos(incrad); + double mu = cos(emarad); + + if (munot <= 0.0 || mu <= 0.0 || incidence == 90.0 || + emission == 90.0) { + pht_minnaert = 0.0; + } else if (p_photoK == 1.0) { + pht_minnaert = munot; + } else { + pht_minnaert = munot * pow((munot*mu),(p_photoK-1.0)); + } + + return pht_minnaert; + } +} + +extern "C" Isis::PhotoModel *MinnaertPlugin (Isis::Pvl &pvl) { + return new Isis::Minnaert(pvl); +} diff --git a/isis/src/base/objs/Minnaert/Minnaert.h b/isis/src/base/objs/Minnaert/Minnaert.h new file mode 100644 index 0000000000000000000000000000000000000000..3f7223fc422b22d2306ccaa111b17228e239270a --- /dev/null +++ b/isis/src/base/objs/Minnaert/Minnaert.h @@ -0,0 +1,77 @@ +#if !defined(Minnaert_h) +#define Minnaert_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/06/19 15:18:26 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PhotoModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief Minnaert photometric model + * Derive model albedo using Minnaert equation. + * Phase independent and calculated analytically. + * Limb-darkening k is a constant. + * \code + * albedo = brightness*[mu / (mu*munot)**k)] + * assumptions: + * 1. bidirectional reflectance + * 2. semi-infinite medium + * k k-1 + * reflectance (inc,ema,phase)=albedo * munot * mu + * Minnaert Minnaert + * \endcode + * + * Where k is the Minnaert index, an empirical constant (called nu in Hapke) + * + * If k (nu) = 1, Minnaert's law reduces to Lambert's law. + * See Theory of Reflectance and Emittance Spectroscopy, 1993; + * Bruce Hapke; pg. 191-192. + * + * @author 1989-08-02 Tammy Becker + * + * @internal + * @history 2007-07-31 Steven Lambright - Moved PhotoK from base PhotoModel class to this + * child. + */ + class Minnaert : public PhotoModel { + public: + Minnaert (Pvl &pvl); + virtual ~Minnaert() {}; + + void SetPhotoK(const double k); + //! Return photometric K value + inline double PhotoK () const { return p_photoK; }; + + private: + double p_photoK; + + protected: + virtual double PhotoModelAlgorithm (double phase, double incidence, + double emission); + + }; +}; + +#endif diff --git a/isis/src/base/objs/Minnaert/Minnaert.truth b/isis/src/base/objs/Minnaert/Minnaert.truth new file mode 100644 index 0000000000000000000000000000000000000000..7a70914997e2cdb31990e20bae72aa46e850b878 --- /dev/null +++ b/isis/src/base/objs/Minnaert/Minnaert.truth @@ -0,0 +1,44 @@ +UNIT TEST for Minnaert photometric function + +Object = PhotometricModel + Group = Algorithm + Name = Minnaert + End_Group +End_Object +End + +PhotoK = 1 +Test phase=0.0, incidence=0.0, emission=0.0 ... +Albedo = 1 +Test phase=60.0, incidence=45.0, emission=30.0 ... +Albedo = 0.707107 +Test phase=180.0, incidence=90.0, emission=90.0 ... +Albedo = 0 + +Test negative K value ... +**USER ERROR** Invalid value of Minnaert k [-1.0] + +PhotoK = 0 +Test phase=0.0, incidence=0.0, emission=0.0 ... +Albedo = 1 +Test phase=60.0, incidence=45.0, emission=30.0 ... +Albedo = 1.1547 +Test phase=180.0, incidence=90.0, emission=90.0 ... +Albedo = 0 + +PhotoK = 0.5 +Test phase=0.0, incidence=0.0, emission=0.0 ... +Albedo = 1 +Test phase=60.0, incidence=45.0, emission=30.0 ... +Albedo = 0.903602 +Test phase=180.0, incidence=90.0, emission=90.0 ... +Albedo = 0 + +PhotoK = 2 +Test phase=0.0, incidence=0.0, emission=0.0 ... +Albedo = 1 +Test phase=60.0, incidence=45.0, emission=30.0 ... +Albedo = 0.433013 +Test phase=180.0, incidence=90.0, emission=90.0 ... +Albedo = 0 + diff --git a/isis/src/base/objs/Minnaert/PhotoModel.plugin b/isis/src/base/objs/Minnaert/PhotoModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..31070d37dc43b1b268c4af51165db7201e426a3c --- /dev/null +++ b/isis/src/base/objs/Minnaert/PhotoModel.plugin @@ -0,0 +1,4 @@ +Group = Minnaert + Library = Minnaert + Routine = MinnaertPlugin +End_Group diff --git a/isis/src/base/objs/Minnaert/unitTest.cpp b/isis/src/base/objs/Minnaert/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7c3794794203bd8a4261ee8c3825684d7a56a9a --- /dev/null +++ b/isis/src/base/objs/Minnaert/unitTest.cpp @@ -0,0 +1,108 @@ +#include +#include +#include "Minnaert.h" +#include "PhotoModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + std::cout << "UNIT TEST for Minnaert photometric function" << + std::endl << std::endl; + + PvlGroup alg("Algorithm"); + alg += PvlKeyword("Name","Minnaert"); + + PvlObject o("PhotometricModel"); + o.AddGroup(alg); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl << std::endl; + + try { + Minnaert *pm = (Minnaert*)PhotoModelFactory::Create(pvl); + + std::cout << "PhotoK = " << pm->PhotoK() << std::endl; + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(0.0,0.0,0.0) << + std::endl; + std::cout << "Test phase=60.0, incidence=45.0, emission=30.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(60.0,45.0,30.0) << + std::endl; + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(180.0,90.0,90.0) << + std::endl << std::endl; + + std::cout << "Test negative K value ..." << std::endl; + try { + pm->SetPhotoK(-1.0); + } + catch (Isis::iException &e) { + e.Report(false); + } + std::cout << std::endl; + + pm->SetPhotoK(0.0); + std::cout << "PhotoK = " << pm->PhotoK() << std::endl; + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(0.0,0.0,0.0) << + std::endl; + std::cout << "Test phase=60.0, incidence=45.0, emission=30.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(60.0,45.0,30.0) << + std::endl; + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(180.0,90.0,90.0) << + std::endl << std::endl; + + pm->SetPhotoK(0.5); + std::cout << "PhotoK = " << pm->PhotoK() << std::endl; + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(0.0,0.0,0.0) << + std::endl; + std::cout << "Test phase=60.0, incidence=45.0, emission=30.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(60.0,45.0,30.0) << + std::endl; + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(180.0,90.0,90.0) << + std::endl << std::endl; + + pm->SetPhotoK(2.0); + std::cout << "PhotoK = " << pm->PhotoK() << std::endl; + + std::cout << "Test phase=0.0, incidence=0.0, emission=0.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(0.0,0.0,0.0) << + std::endl; + std::cout << "Test phase=60.0, incidence=45.0, emission=30.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(60.0,45.0,30.0) << + std::endl; + std::cout << "Test phase=180.0, incidence=90.0, emission=90.0 ..." << + std::endl; + std::cout << "Albedo = " << pm->CalcSurfAlbedo(180.0,90.0,90.0) << + std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/Mixed/Makefile b/isis/src/base/objs/Mixed/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ef56544b0de060f6e173e79625175d8afdbaa0d3 --- /dev/null +++ b/isis/src/base/objs/Mixed/Makefile @@ -0,0 +1,5 @@ +INCS = Mixed.h +SRCS = Mixed.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Mixed/Mixed.cpp b/isis/src/base/objs/Mixed/Mixed.cpp new file mode 100644 index 0000000000000000000000000000000000000000..abf0f9c57ac2736e31fd07ee18a058095ed1ae95 --- /dev/null +++ b/isis/src/base/objs/Mixed/Mixed.cpp @@ -0,0 +1,159 @@ +#include +#include "Mixed.h" +#include "SpecialPixel.h" +#include "iException.h" + +namespace Isis { + Mixed::Mixed (Pvl &pvl, PhotoModel &pmodel) : NormModel(pvl,pmodel) { + PvlGroup &algorithm = pvl.FindObject("NormalizationModel").FindGroup("Algorithm",Pvl::Traverse); + + // Set default value + SetNormIncref(0.0); + SetNormIncmat(0.0); + SetNormThresh(30.0); + SetNormAlbedo(1.0); + + // Get value from user + if (algorithm.HasKeyword("Incref")) { + SetNormIncref(algorithm["Incref"]); + } + if (algorithm.HasKeyword("Incmat")) { + SetNormIncmat(algorithm["Incmat"]); + } + + if (algorithm.HasKeyword("Thresh")) { + SetNormThresh(algorithm["Thresh"]); + } + + if (algorithm.HasKeyword("Albedo")) { + SetNormAlbedo(algorithm["Albedo"]); + } + + // First-time setup + // Calculate normalization at standard conditions + // Turn off Hapke opposition effect + GetPhotoModel()->SetStandardConditions(true); + p_psurfref = GetPhotoModel()->CalcSurfAlbedo(0.0, p_normIncref, 0.0); + double pprimeref = GetPhotoModel()->PhtTopder(0.0, p_normIncref, 0.0); + + if (p_psurfref == 0.0) { + std::string err = "Divide by zero error"; + throw iException::Message(iException::Math, err, _FILEINFO_); + } + else { + p_rhobar = p_normAlbedo / p_psurfref; + } + + // Calculate brightness and topo derivative at matchpoint incidence + p_psurfmatch = GetPhotoModel()->CalcSurfAlbedo(p_normIncmat, p_normIncmat, 0.0); + p_pprimematch = GetPhotoModel()->PhtTopder(p_normIncmat, p_normIncmat, 0.0); + + // Calculate numerator of the stretch coeff. a; if it is very + // large or small we haven't chosen a good reference state + double arg = pow(p_psurfref,2.0) + pow(p_psurfmatch*pprimeref / std::max(1.0e-30,p_pprimematch),2.0); + if ((arg < 1.0e-10) || (arg > 1.0e10)) { + std::string err = "Bad reference state encountered"; + throw iException::Message(iException::Math, err, _FILEINFO_); + } + + p_anum = sqrt(arg); + GetPhotoModel()->SetStandardConditions(false); + } + + void Mixed::NormModelAlgorithm (double phase, double incidence, + double emission, double dn, double &albedo, double &mult, + double &base) + { + double psurf; + double pprime; + double aden; + + // code for scaling each pixel + psurf = GetPhotoModel()->CalcSurfAlbedo(phase, incidence, emission); + pprime = GetPhotoModel()->PhtTopder(phase, incidence, emission); + double arg = pow(psurf,2.0) + pow(p_psurfmatch*pprime / std::max(1.0e-30, p_pprimematch), 2.0); + aden = sqrt(std::max(1.0e-30,arg)); + + // thresh is a parameter limiting how much we amplify the dns + // shouldn't actually get a large amplification in this mode because + // of the growing pprime term in the denominator. + + if (aden > p_anum*p_normThresh) { + albedo = NULL8; + } + else { + albedo = dn * p_anum / aden + p_rhobar * (p_psurfref - p_anum / aden * psurf); + } + } + + /** + * Set the normalization function parameter. This is the + * reference incidence angle to which the image photometry will + * be normalized. This parameter is limited to values that are + * >=0 and <90. + * + * @param incref Normalization function parameter, default + * is 0.0 + */ + void Mixed::SetNormIncref (const double incref) { + if (incref < 0.0 || incref >= 90.0) { + std::string msg = "Invalid value of normalization incref [" + + iString(incref) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_normIncref = incref; + } + + /** + * Set the normalization function parameter. The image will be normalized + * so that albedo variations are constant for small incidence angles and + * topographic shading is constant for large incidence angles. The transition + * from albedo normalization to incidence normalization occurs around + * the incidence angle represented by this parameter. This + * parameter is limited to values that are >=0 and <90. + * + * @param incmat Normalization function parameter + */ + void Mixed::SetNormIncmat (const double incmat) { + if (incmat < 0.0 || incmat >= 90.0) { + std::string msg = "Invalid value of normalization incmat [" + + iString(incmat) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_normIncmat = incmat; + } + + /** + * Set the normalization function parameter. + * + * @param albedo Normalization function parameter, default + * is 0.0690507 + */ + void Mixed::SetNormAlbedo (const double albedo) { + p_normAlbedo = albedo; + } + + /** + * Set the normalization function parameter. + * It is used to amplify variations in the input image in regions + * of small incidence angle where the shading in the input + * image is weak. This parameter sets the upper limit on the + * amount of amplification that will be attempted. If it is + * set too low, low incidence areas of the image may appear + * bland. If it is set too high, then low incidence areas of + * the image may contain amplified noise rather than useful + * shading information. + * + * @param thresh Normalization function parameter, default + * is 30.0 + */ + void Mixed::SetNormThresh (const double thresh) { + p_normThresh = thresh; + } +} + +extern "C" Isis::NormModel *MixedPlugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel) { + return new Isis::Mixed(pvl,pmodel); +} diff --git a/isis/src/base/objs/Mixed/Mixed.h b/isis/src/base/objs/Mixed/Mixed.h new file mode 100644 index 0000000000000000000000000000000000000000..c3e07525dc5bc9db60f78649990913db2679ee7d --- /dev/null +++ b/isis/src/base/objs/Mixed/Mixed.h @@ -0,0 +1,87 @@ +#if !defined(Mixed_h) +#define Mixed_h +/** + * @file + * $Revision: 1.6 $ + * $Date: 2008/07/08 18:43:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "NormModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief Mixed albedo/topo normalization without atmosphere + * + * This mode will do albedo normalization over most of the planet + * but near the terminator it will normalize topographic contrast to + * avoid the "seams" we are currently getting with the plain albedo + * normalization. The two effects will be joined seamlessly. + * In addition to the parameters for no-atmosphere albedo normaliza- + * tion (i.e., the photometric parameters and the choice of angles + * for normal albedo calculation) this mode needs two more parameters. + * INCMAT is the incidence angle at which the RMS contrast from al- + * bedo matches the RMS contrast from topography. (Could input a + * full 3-angle geometry at which the contrasts are equal but since + * the user is probably going to find this parameter by trial and er- + * ror it's easier to specify only incidence and use emission=0, + * phase=incidence for this second reference state.) ALBEDO, the av- + * erage normal albedo, is also needed. + * + * @author 1998-12-21 Randy Kirk + * + * @internal + * @history 2007-07-31 Steven Lambright - Refactored code + * @history 2008-03-07 Janet Barrett - Changed name of Incmatch variable + * to Incmat + */ + class Mixed : public NormModel { + public: + Mixed (Pvl &pvl, PhotoModel &pmodel); + virtual ~Mixed() {}; + + protected: + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double dn, double &albedo, double &mult, double &base); + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double deminc, double demema, double dn, double &albedo, + double &mult, double &base) {}; + + private: + //! Set parameters needed for albedo normalization + void SetNormIncref(const double incref); + void SetNormIncmat(const double incmat); + void SetNormThresh(const double thresh); + void SetNormAlbedo(const double albedo); + + double p_psurfmatch; + double p_pprimematch; + double p_anum; + double p_rhobar; + double p_psurfref; + double p_normIncref; + double p_normThresh; + double p_normIncmat; + double p_normAlbedo; + }; +}; + +#endif diff --git a/isis/src/base/objs/Mixed/Mixed.truth b/isis/src/base/objs/Mixed/Mixed.truth new file mode 100644 index 0000000000000000000000000000000000000000..d54e2386157f5448a910a34790db0b368d37fb3b --- /dev/null +++ b/isis/src/base/objs/Mixed/Mixed.truth @@ -0,0 +1,26 @@ +UNIT TEST for Mixed normalization function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = NormalizationModel + Group = Algorithm + Name = Mixed + Albedo = 0.0690507 + Incmat = 51.0 + End_Group +End_Object +End + +Test phase=86.7226722, incidence=51.7002388, emission=38.9414439, dn=.0800618902 ... +Normalization value = 0.111032 + +Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0797334611 ... +Normalization value = 0.110665 + +Test phase=86.7187773, incidence=51.7060221, emission=38.9331391, dn=.0794225037 ... +Normalization value = 0.110319 + diff --git a/isis/src/base/objs/Mixed/NormModel.plugin b/isis/src/base/objs/Mixed/NormModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..c030729ddfdf6f0bd4063deb73d0833192d92c9e --- /dev/null +++ b/isis/src/base/objs/Mixed/NormModel.plugin @@ -0,0 +1,4 @@ +Group = Mixed + Library = Mixed + Routine = MixedPlugin +End_Group diff --git a/isis/src/base/objs/Mixed/unitTest.cpp b/isis/src/base/objs/Mixed/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..56390bbbf9b403b24eccc052cd90c1816b8dd110 --- /dev/null +++ b/isis/src/base/objs/Mixed/unitTest.cpp @@ -0,0 +1,66 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "NormModel.h" +#include "NormModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + double result; + double mult; + double base; + + std::cout << "UNIT TEST for Mixed normalization function" << std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup algn("Algorithm"); + algn += PvlKeyword("Name", "Mixed"); + algn += PvlKeyword("Albedo", .0690507); + algn += PvlKeyword("Incmat", 51.0); + + PvlObject on("NormalizationModel"); + on.AddGroup(algn); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(on); + + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + NormModel *nm = NormModelFactory::Create(pvl,*pm); + + nm->CalcNrmAlbedo(86.7226722,51.7002388,38.9414439,.0800618902,result,mult,base); + + std::cout << "Test phase=86.7226722, incidence=51.7002388, emission=38.9414439, dn=.0800618902 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + + nm->CalcNrmAlbedo(86.7207248,51.7031305,38.9372914,.0797334611,result,mult,base); + + std::cout << "Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0797334611 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + + nm->CalcNrmAlbedo(86.7187773,51.7060221,38.9331391,.0794225037,result,mult,base); + + std::cout << "Test phase=86.7187773, incidence=51.7060221, emission=38.9331391, dn=.0794225037 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + } catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/MoonAlbedo/Makefile b/isis/src/base/objs/MoonAlbedo/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1fc3aa3fa5fe5eed2f47594785118cfaec95893b --- /dev/null +++ b/isis/src/base/objs/MoonAlbedo/Makefile @@ -0,0 +1,5 @@ +INCS = MoonAlbedo.h +SRCS = MoonAlbedo.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/MoonAlbedo/MoonAlbedo.cpp b/isis/src/base/objs/MoonAlbedo/MoonAlbedo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd527ccc535b033a0b440a1346ce4b320831c6f9 --- /dev/null +++ b/isis/src/base/objs/MoonAlbedo/MoonAlbedo.cpp @@ -0,0 +1,319 @@ +#include +#include "MoonAlbedo.h" +#include "SpecialPixel.h" +#include "iException.h" + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) + +namespace Isis { + MoonAlbedo::MoonAlbedo (Pvl &pvl, PhotoModel &pmodel) : + NormModel(pvl,pmodel) { + PvlGroup &algo = pvl.FindObject("NormalizationModel") + .FindGroup("Algorithm",Pvl::Traverse); + // Set default values + SetNormD(0.14); + SetNormE(-0.4179); + SetNormF(0.55); + SetNormG2(0.02); + SetNormXmul(1.0); + SetNormWl(p_normWavelength); + SetNormH(0.048); + SetNormBsh1(0.08); + SetNormXb1(-0.0817); + SetNormXb2(0.0081); + + // Get values from user + if (algo.HasKeyword("D")) { + SetNormD(algo["D"]); + } + + if (algo.HasKeyword("Wl")) { + SetNormWl(algo["Wl"]); + } + + if (algo.HasKeyword("E")) { + SetNormE(algo["E"]); + } else { + if (p_normWl < 1.0) { + p_normE = -0.3575 * p_normWl - 0.0607; + } else { + p_normE = -0.4179; + } + } + + if (algo.HasKeyword("F")) { + SetNormF(algo["F"]); + } + + if (algo.HasKeyword("G2")) { + SetNormG2(algo["G2"]); + } else { + if (p_normWl < 1.0) { + p_normG2 = -0.9585 * p_normWl + 0.98; + } else { + p_normG2 = 0.02; + } + } + + if (algo.HasKeyword("Xmul")) { + SetNormXmul(algo["Xmul"]); + } + + if (algo.HasKeyword("H")) { + SetNormH(algo["H"]); + } + + if (algo.HasKeyword("Bsh1")) { + SetNormBsh1(algo["Bsh1"]); + } else { + p_normBsh1 = 19.89 - 59.58 * p_normWl + 59.86 * pow(p_normWl,2) - + 20.09 * pow(p_normWl,3); + if (p_normBsh1 < 0.0) { + p_normBsh1 = 0.0; + } + } + + if (algo.HasKeyword("Xb1")) { + SetNormXb1(algo["Xb1"]); + } + + if (algo.HasKeyword("Xb2")) { + SetNormXb2(algo["Xb2"]); + } + + // Initialize values that will be needed to normalize to a + // Buratti function at phase = 2.0 degrees + p_normF1 = 1.0 - p_normF; + double g1 = p_normD * 0.1 + p_normE; + double g1sq = g1 * g1; + p_normG2sq = p_normG2 * p_normG2; + double c30 = cos(30.0 * Isis::PI / 180.0); + if (1.0 + g1sq + 2.0 * g1 * c30 <= 0.0) { + std::string msg = "Error while initializing Buratti function"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + double pg130 = p_normF1 * (1.0 - g1sq) / (pow((1.0+g1sq+2.0*g1*c30),1.5)); + if (1.0 + p_normG2sq + 2.0 * p_normG2 * c30 <= 0.0) { + std::string msg = "Error while initializing Buratti function"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + double pg230 = p_normF * (1.0 - p_normG2sq) / (pow((1.0+p_normG2sq+2.0*p_normG2*c30),1.5)); + if (p_normBsh1 < 0.0) p_normBsh1 = 0.0; + if (1.0 + tan(15.0 * Isis::PI / 180.0) / p_normH == 0.0) { + std::string msg = "Error while initializing Buratti function"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + double bshad30 = 1.0 + p_normBsh1 / (1.0 + tan(15.0 * Isis::PI / 180.0) / p_normH); + p_normPg30 = (pg130 + pg230) * bshad30; + p_normBc1 = p_normXb1 + p_normXb2 * p_normWl; + p_normFbc3 = 1.0 + p_normBc1 * 2.0; + if (p_normFbc3 == 0.0) { + std::string msg = "Error while initializing Buratti function"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + p_normC3 = cos(2.0 * Isis::PI / 180.0); + if (1.0 + p_normG2sq + 2.0 * p_normG2 * p_normC3 <= 0.0) { + std::string msg = "Error while initializing Buratti function"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + p_normPg32 = p_normF * (1.0 - p_normG2sq) / (pow((1.0+p_normG2sq+2.0*p_normG2*p_normC3),1.5)); + if (1.0 + tan(Isis::PI / 180.0) / p_normH == 0.0) { + std::string msg = "Error while initializing Buratti function"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + p_normBshad3 = 1.0 + p_normBsh1 / (1.0 + tan(Isis::PI / 180.0) / p_normH); + } + + void MoonAlbedo::NormModelAlgorithm (double phase, double incidence, + double emission, double dn, double &albedo, double &mult, + double &base) + { + double a; + double cosa; + double pg2; + double bshad; + double r; + double g1; + double g1sq; + double pg1; + double pg; + double fbc; + double pg31; + double pg3; + + a = GetPhotoModel()->CalcSurfAlbedo(phase,incidence,emission); + + if (a != 0.0) { + cosa = cos(phase * Isis::PI/180.0); + if (1.0+p_normG2sq+2.0*p_normG2*cosa <= 0.0) { + albedo = NULL8; + return; + } + pg2 = p_normF * (1.0 - p_normG2sq) / (pow((1.0+p_normG2sq+2.0*p_normG2*cosa),1.5)); + if (1.0 + tan(phase*.5*Isis::PI/180.0) / p_normH == 0.0) { + albedo = NULL8; + return; + } + bshad = 1.0 + p_normBsh1 / (1.0 + tan(phase*.5*Isis::PI/180.0) / p_normH); + r = dn * p_normXmul; + // Estimate the albedo at 0.1, then iterate + albedo = 0.1; + for (int i=0; i<6; i++) { + g1 = p_normD * albedo + p_normE; + g1sq = g1 * g1; + if (1.0 + g1sq + 2.0 * g1 * cosa <= 0.0) { + albedo = NULL8; + return; + } + pg1 = p_normF1 * (1.0 - g1sq) / (pow((1.0+g1sq+2.0*g1*cosa),1.5)); + pg = (pg1 + pg2) * bshad; + if (phase <= 2.0) { + fbc = 1.0 + p_normBc1 * phase; + if (1.0 + g1sq + 2.0 * g1 * p_normC3 <= 0.0) { + albedo = NULL8; + return; + } + pg31 = p_normF1 * (1.0 - g1sq) / (pow((1.0+g1sq+2.0*g1*p_normC3),1.5)); + pg3 = (pg31 + p_normPg32) * p_normBshad3; + pg = fbc * (pg3 / p_normFbc3); + } + if (pg == 0.0) { + albedo = NULL8; + return; + } + albedo = r * a * p_normPg30 / pg; + } + } else { + albedo = NULL8; + return; + } + } + + /** + * Set the albedo dependent phase function normalization parameter. + * This is an emperically derived coefficient. This parameter has + * no limits. + * + * @param d Normalization function parameter, default is 0.14 + */ + void MoonAlbedo::SetNormD (const double d) { + p_normD = d; + } + + /** + * Set the albedo dependent phase function normalization parameter. + * This is the wavelength in micrometers of the image being + * normalized (found in the BandBin Center keyword of the image). + * This parameter has no limits. + * + * @param wl Normalization function parameter, default is 1.0 + */ + void MoonAlbedo::SetNormWl (const double wl) { + p_normWl = wl; + } + + /** + * Set the albedo dependent phase function normalization parameter. + * This is an emperically derived coefficient. This parameter has + * no limits. + * + * @param e Normalization function parameter, default is -0.4179 + */ + void MoonAlbedo::SetNormE (const double e) { + p_normE = e; + } + + /** + * Set the albedo dependent phase function normalization parameter. + * This is an emperically derived coefficient. This parameter has + * no limits. + * + * @param f Normalization function parameter, default is 0.55 + */ + void MoonAlbedo::SetNormF (const double f) { + p_normF = f; + } + + /** + * Set the albedo dependent phase function normalization parameter. + * This is an emperically derived coefficient. This parameter has + * no limits. + * + * @param g2 Normalization function parameter, default is 0.02 + */ + void MoonAlbedo::SetNormG2 (const double g2) { + p_normG2 = g2; + } + + /** + * Set the albedo dependent phase function normalization parameter. + * This parameter is used to convert radiance to reflectance or + * apply a calibration fudge factor. This parameter has no limits. + * + * @param xmul Normalization function parameter, default is 1.0 + */ + void MoonAlbedo::SetNormXmul (const double xmul) { + p_normXmul = xmul; + } + + /** + * Set the albedo dependent phase function normalization parameter. + * This is an emperically derived coefficient. This parameter + * is limited to non-zero values. + * + * @param h Normalization function parameter, default is 0.048 + */ + void MoonAlbedo::SetNormH (const double h) { + if (h == 0.0) { + std::string msg = "Invalid value of normalization h [" + + iString(h) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_normH = h; + } + + /** + * Set the albedo dependent phase function normalization parameter. + * This is an emperically derived coefficient. This parameter is + * limited to values >= 0. + * + * @param bsh1 Normalization function parameter, default is 0.08 + */ + void MoonAlbedo::SetNormBsh1 (const double bsh1) { + if (bsh1 < 0.0) { + std::string msg = "Invalid value of normalization bsh1 [" + + iString(bsh1) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_normBsh1 = bsh1; + } + + /** + * Set the albedo dependent phase function normalization parameter. + * This is an emperically derived coefficient. This parameter has + * no limits. + * + * @param xb1 Normalization function parameter, default is -0.0817 + */ + void MoonAlbedo::SetNormXb1 (const double xb1) { + p_normXb1 = xb1; + } + + /** + * Set the albedo dependent phase function normalization parameter. + * This is an emperically derived coefficient. This parameter has + * no limits. + * + * @param xb2 Normalization function parameter, default is 0.0081 + */ + void MoonAlbedo::SetNormXb2 (const double xb2) { + p_normXb2 = xb2; + } +} + +extern "C" Isis::NormModel *MoonAlbedoPlugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel) { + return new Isis::MoonAlbedo(pvl,pmodel); +} diff --git a/isis/src/base/objs/MoonAlbedo/MoonAlbedo.h b/isis/src/base/objs/MoonAlbedo/MoonAlbedo.h new file mode 100644 index 0000000000000000000000000000000000000000..0abdd381c22dc0a17e6a139a188b29cf13e1746f --- /dev/null +++ b/isis/src/base/objs/MoonAlbedo/MoonAlbedo.h @@ -0,0 +1,85 @@ +#if !defined(MoonAlbedo_h) +#define MoonAlbedo_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/19 15:25:40 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "NormModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief Albedo dependent phase function normalization for the Moon + * + * @author 1998-12-21 Randy Kirk + * + * @internal + */ + class MoonAlbedo : public NormModel { + public: + MoonAlbedo (Pvl &pvl, PhotoModel &pmodel); + virtual ~MoonAlbedo() {}; + + protected: + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double dn, double &albedo, double &mult, double &base); + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double deminc, double demema, double dn, double &albedo, + double &mult, double &base) {}; + + private: + //! Set parameters needed for albedo dependent phase function + //! normalization for the Moon + void SetNormD(const double d); + void SetNormE(const double e); + void SetNormF(const double f); + void SetNormG2(const double g2); + void SetNormXmul(const double xmul); + void SetNormWl(const double wl); + void SetNormH(const double h); + void SetNormBsh1(const double bsh1); + void SetNormXb1(const double xb1); + void SetNormXb2(const double xb2); + + double p_normD; + double p_normE; + double p_normF; + double p_normG2; + double p_normXmul; + double p_normWl; + double p_normH; + double p_normBsh1; + double p_normXb1; + double p_normXb2; + double p_normF1; + double p_normG2sq; + double p_normPg30; + double p_normBc1; + double p_normFbc3; + double p_normC3; + double p_normPg32; + double p_normBshad3; + }; +}; + +#endif diff --git a/isis/src/base/objs/MoonAlbedo/MoonAlbedo.truth b/isis/src/base/objs/MoonAlbedo/MoonAlbedo.truth new file mode 100644 index 0000000000000000000000000000000000000000..689dc63d1dfc18184a4c414ddf955b9b87a2f128 --- /dev/null +++ b/isis/src/base/objs/MoonAlbedo/MoonAlbedo.truth @@ -0,0 +1,30 @@ +UNIT TEST for MoonAlbedo normalization function + +Object = PhotometricModel + Group = Algorithm + Name = LunarLambertMcEwen + End_Group +End_Object + +Object = NormalizationModel + Group = Algorithm + Name = MoonAlbedo + D = 0.0 + E = -0.218 + F = 0.5 + G2 = 0.4 + H = 0.054 + Bsh1 = 1.6 + End_Group +End_Object +End + +Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0800618902 ... +Normalization value = 0.165677 + +Test phase=75.7207248, incidence=41.7031305, emission=28.9372914, dn=.0697334611 ... +Normalization value = 0.118661 + +Test phase=53.7187773, incidence=31.7060221, emission=18.9331391, dn=.0194225037 ... +Normalization value = 0.0253739 + diff --git a/isis/src/base/objs/MoonAlbedo/NormModel.plugin b/isis/src/base/objs/MoonAlbedo/NormModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..934ac752967dd7c4ec733796e6104795d983e854 --- /dev/null +++ b/isis/src/base/objs/MoonAlbedo/NormModel.plugin @@ -0,0 +1,4 @@ +Group = MoonAlbedo + Library = MoonAlbedo + Routine = MoonAlbedoPlugin +End_Group diff --git a/isis/src/base/objs/MoonAlbedo/unitTest.cpp b/isis/src/base/objs/MoonAlbedo/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a0392ea6cc5ac9b8f7828c8cd32a548262abe3a2 --- /dev/null +++ b/isis/src/base/objs/MoonAlbedo/unitTest.cpp @@ -0,0 +1,71 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "MoonAlbedo.h" +#include "NormModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + double result; + double mult; + double base; + + std::cout << "UNIT TEST for MoonAlbedo normalization function" << + std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","LunarLambertMcEwen"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup algn("Algorithm"); + algn += PvlKeyword("Name","MoonAlbedo"); + algn += PvlKeyword("D","0.0"); + algn += PvlKeyword("E","-0.218"); + algn += PvlKeyword("F","0.5"); + algn += PvlKeyword("G2","0.4"); + algn += PvlKeyword("H","0.054"); + algn += PvlKeyword("Bsh1","1.6"); + + PvlObject on("NormalizationModel"); + on.AddGroup(algn); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(on); + + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + MoonAlbedo *nm = (MoonAlbedo*)NormModelFactory::Create(pvl,*pm); + + std::cout << "Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, " << + "dn=.0800618902 ..." << std::endl; + nm->CalcNrmAlbedo(86.7207248,51.7031305,38.9372914,.0800618902,result,mult,base); + std::cout << "Normalization value = " << result << std::endl << std::endl; + + std::cout << "Test phase=75.7207248, incidence=41.7031305, emission=28.9372914, " << + "dn=.0697334611 ..." << std::endl; + nm->CalcNrmAlbedo(75.7207248,41.7031305,28.9372914,.0697334611,result,mult,base); + std::cout << "Normalization value = " << result << std::endl << std::endl; + + std::cout << "Test phase=53.7187773, incidence=31.7060221, emission=18.9331391, " << + "dn=.0194225037 ..." << std::endl; + nm->CalcNrmAlbedo(53.7187773,31.7060221,18.9331391,.0194225037,result,mult,base); + std::cout << "Normalization value = " << result << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/MoravecOperator/InterestOperator.plugin b/isis/src/base/objs/MoravecOperator/InterestOperator.plugin new file mode 100644 index 0000000000000000000000000000000000000000..cdaf359c9216c2ad524dd2eed70c9f421e4a3342 --- /dev/null +++ b/isis/src/base/objs/MoravecOperator/InterestOperator.plugin @@ -0,0 +1,4 @@ +Group = Moravec + Library = MoravecOperator + Routine = MoravecOperatorPlugin +End_Group diff --git a/isis/src/base/objs/MoravecOperator/Makefile b/isis/src/base/objs/MoravecOperator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a50b034dcd24d6698d6938b03c3ce683f333e6b1 --- /dev/null +++ b/isis/src/base/objs/MoravecOperator/Makefile @@ -0,0 +1,5 @@ +INCS = MoravecOperator.h +SRCS = MoravecOperator.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/MoravecOperator/MoravecOperator.cpp b/isis/src/base/objs/MoravecOperator/MoravecOperator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d8a4a522c15bbd7845ac96e76817e48cf116378 --- /dev/null +++ b/isis/src/base/objs/MoravecOperator/MoravecOperator.cpp @@ -0,0 +1,61 @@ +#include "MoravecOperator.h" +#include "Chip.h" + +namespace Isis { + /** + * This method returns the amount of interest for the given chip. + * + * @param chip The chip to calculate the interest value of + * + * @return the amount of interest for this chip + */ + double MoravecOperator::Interest(Chip &chip) { + int height = chip.Lines(); + int width = chip.Samples(); + std::vector interests; + double smallestInterest = 0.0; + + // Create offsets for comparison of different areas of the chip + for(int offX = -1; offX <= 1; offX++) { + for(int offY = -1; offY <= 1; offY++) { + // doesnt do work if offset would be center chip + if(offX == 0 && offY == 0) continue; + // Do interest computation between center and offset areas and store into array + double interest = 0.0; + for(int y = 2; y <= height - 1; y++) { + for(int x = 2; x <= width - 1; x++) { + // If either pixel is special ignore difference + if(ValidDnValue(chip.GetValue(x, y)) && ValidDnValue(chip.GetValue(x + offX, y + offY))) { + interest += std::pow(chip.GetValue(x, y) - chip.GetValue(x + offX, y + offY), 2); + } + } + } + // Initialize smallest interest with first value + if(interests.size() == 1) { + smallestInterest = interest; + } + interests.push_back(interest); + } + } + // find smallest interest and return + for(unsigned int i = 0; i < interests.size(); i++) { + if(interests[i] < smallestInterest) { + smallestInterest = interests[i]; + } + } + return smallestInterest; + } + + /** + * Sets an offset to pass in larger chips if operator requires it + * This is used to offset the subchip size passed into Interest + * + * @return int Amount to add to both x & y total sizes + */ + int MoravecOperator::Padding() { + return 2; + } +} +extern "C" Isis::InterestOperator *MoravecOperatorPlugin(Isis::Pvl &pPvl) { + return new Isis::MoravecOperator(pPvl); +} diff --git a/isis/src/base/objs/MoravecOperator/MoravecOperator.h b/isis/src/base/objs/MoravecOperator/MoravecOperator.h new file mode 100644 index 0000000000000000000000000000000000000000..0a0e225dac5e536dcc16ec574442975d499162f6 --- /dev/null +++ b/isis/src/base/objs/MoravecOperator/MoravecOperator.h @@ -0,0 +1,56 @@ +#ifndef MoravecOperator_h +#define MoravecOperator_h + +#include "InterestOperator.h" + +namespace Isis { + class Pvl; + class Chip; + + /** + * @brief Moravec Interest Operator + * + * This class is used to construct a Moravec interest operator. + * For this class, the interest is always positive with the worst + * interest amount being 0. The higher the interest, the better. + * + * This is more commonly refered to as Moravec Corner Detection. + * The algorithm was taken from the following website: + * http://www.cim.mcgill.ca/~dparks/CornerDetector/mainMoravec.htm + * + * Moravec Interest Operator works by creating a N x N size + * boxcar around the "point of interest." Then it walks another + * boxcar of the same size around the center point, computing + * the interest of that comparison by the equation: the sum of + * pow(An-Bn,2) from 1 to the number of pixels in the boxcar, + * where A1 and B1 are the top left pixel. By walking the boxcar + * around the edges it will create 8 comparisons. It will then + * take the smallest value out of the 8 comparisons and that + * will be the interest value of the "point of interest." + * + * @see InterestOperator + * + * @author 2007-08-02 Steven Koechle + * + * @internal + * @history 2007-08-02 Steven Koechle - Original Version + * @history 2008-08-16 Steven Koechle - Fixed Documentation + */ + class MoravecOperator : public InterestOperator { + public: + /** + * This constructor creates a Moravec Interest Operator + * + * @param pvl Pvl to create MoravecOperator from + */ + MoravecOperator(Pvl &pPvl) : InterestOperator(pPvl) {}; + /** This is the virtual destructor for MoravecOperator */ + virtual ~MoravecOperator() {}; + + protected: + virtual double Interest(Chip &chip); + virtual int Padding(); + }; +}; + +#endif diff --git a/isis/src/base/objs/MoravecOperator/MoravecOperator.truth b/isis/src/base/objs/MoravecOperator/MoravecOperator.truth new file mode 100644 index 0000000000000000000000000000000000000000..a7864b6817b160372dd707c27f3b6510b830836e --- /dev/null +++ b/isis/src/base/objs/MoravecOperator/MoravecOperator.truth @@ -0,0 +1,16 @@ +Object = InterestOperator + Group = Operator + Name = Moravec + DeltaSamp = 100 + DeltaLine = 100 + Samples = 15 + Lines = 15 + MinimumDN = 0.0 + MaximumDN = 1.0 + MinimumInterest = 0.0 + End_Group +End_Object +End +Sample: 87 +Line : 379 +Interest: 0.0112082 diff --git a/isis/src/base/objs/MoravecOperator/unitTest.cpp b/isis/src/base/objs/MoravecOperator/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0598d357fd73e3ea128a27c6d394639c1851c0b2 --- /dev/null +++ b/isis/src/base/objs/MoravecOperator/unitTest.cpp @@ -0,0 +1,55 @@ +#include +#include +#include "InterestOperator.h" +#include "InterestOperatorFactory.h" +#include "MoravecOperator.h" +#include "Chip.h" +#include "Cube.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "PvlObject.h" +#include "Preference.h" +#include "UniversalGroundMap.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + try { + PvlGroup op("Operator"); + op += PvlKeyword("Name","Moravec"); + op += PvlKeyword("DeltaSamp", 100); + op += PvlKeyword("DeltaLine", 100); + op += PvlKeyword("Samples", 15); + op += PvlKeyword("Lines", 15); + op += PvlKeyword("MinimumDN", 0.0); + op += PvlKeyword("MaximumDN", 1.0); + op += PvlKeyword("MinimumInterest", 0.0); + + PvlObject o("InterestOperator"); + o.AddGroup(op); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl; + + InterestOperator *iop = InterestOperatorFactory::Create(pvl); + + Cube c; + c.Open("$mgs/testData/ab102401.cub"); + + //iop->Operate(c, 100, 350); + UniversalGroundMap univGrndMap(c); + iop->Operate(c, univGrndMap, 100, 350); + + std::cout << "Sample: " << iop->CubeSample() << std::endl + << "Line : " << iop->CubeLine() << std::endl + << "Interest: " << iop->InterestAmount() << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/MultivariateStatistics/Makefile b/isis/src/base/objs/MultivariateStatistics/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..765c001a5d3f4f70eef6d2a98cd3206f465b26d9 --- /dev/null +++ b/isis/src/base/objs/MultivariateStatistics/Makefile @@ -0,0 +1,5 @@ +INCS = MultivariateStatistics.h +SRCS = MultivariateStatistics.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/MultivariateStatistics/MultivariateStatistics.cpp b/isis/src/base/objs/MultivariateStatistics/MultivariateStatistics.cpp new file mode 100644 index 0000000000000000000000000000000000000000..249cb95f632199f24e8ad1ed4a22801979fa196e --- /dev/null +++ b/isis/src/base/objs/MultivariateStatistics/MultivariateStatistics.cpp @@ -0,0 +1,222 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/05/14 20:41:01 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "MultivariateStatistics.h" +#include "iException.h" + + +namespace Isis { +/** + * Constructs a Multivariate Statistics object with accumulators and counters + * set to zero. + */ + MultivariateStatistics::MultivariateStatistics () { + Reset (); + } + + //! Resets all accumulators to zero + void MultivariateStatistics::Reset() { + p_x.Reset(); + p_y.Reset(); + p_sumxy = 0.0; + + p_validPixels = 0; + p_invalidPixels = 0; + p_totalPixels = 0; + } + + //! Destructs a MultivariateStatistics object. + MultivariateStatistics::~MultivariateStatistics () {}; +/** + * Add two arrays of doubles to the accumulators and counters. This method can + * be invoked multiple times, for example, once for each line in a cube, before + * obtaining statistics. + * + * @param x Array of doubles to add. + * @param y Array of doubles to add. + * @param count Number of doubles to process. + */ + void MultivariateStatistics::AddData (const double *x, const double *y, + const unsigned int count) { + for (unsigned int i=0; i +#include "MultivariateStatistics.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + + Isis::MultivariateStatistics s; + + double x[10] = { 3,4,4,2,5,3,4,5,3,2 }; + double y[10] = {57,78,72,58,89,63,73,84,75,48}; + + s.AddData(x,y,10); + cout << "SumX = " << s.X().Sum() << endl; + cout << "SumY = " << s.Y().Sum() << endl; + cout << "SumXY = " << s.SumXY() << endl; + cout << "SumXX = " << s.X().SumSquare() << endl; + cout << "SumYY = " << s.Y().SumSquare() << endl; + cout << endl; + cout << "Covariance = " << s.Covariance() << endl; + cout << "VarianceX = " << s.X().Variance() << endl; + cout << "VarianceY = " << s.Y().Variance() << endl; + cout << "Correlation = " << s.Correlation() << endl; + cout << endl; + cout << "Valid Pixels = " << s.ValidPixels() << endl; + cout << "Invalid Pixels = " << s.InvalidPixels() << endl; + cout << "Total Pixels = " << s.TotalPixels() << endl; + cout << endl; + double a,b; + s.LinearRegression(a,b); + cout << "Linear Regression Y = aX + b" << endl; + cout << "a = " << a << endl; + cout << "b = " << b << endl; + +} diff --git a/isis/src/base/objs/NaifStatus/Makefile b/isis/src/base/objs/NaifStatus/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8131aa540fd42b491c35519c5ea697035614473e --- /dev/null +++ b/isis/src/base/objs/NaifStatus/Makefile @@ -0,0 +1,5 @@ +INCS = NaifStatus.h +SRCS = NaifStatus.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/NaifStatus/NaifStatus.cpp b/isis/src/base/objs/NaifStatus/NaifStatus.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60a4150cee747ae5fcfe94a213e7797b6ffb6372 --- /dev/null +++ b/isis/src/base/objs/NaifStatus/NaifStatus.cpp @@ -0,0 +1,116 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2009/12/28 20:18:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "NaifStatus.h" +#include "naif/SpiceUsr.h" +#include "iException.h" +#include "iString.h" +#include "Pvl.h" +#include "PvlTranslationManager.h" +#include + +namespace Isis { + bool NaifStatus::initialized = false; + + /** + * This method looks for any naif errors that might have occurred. It + * then compares the error to a list of known naif errors and converts + * the error into an iException. + * + * @param resetNaif True if the NAIF error status should be reset (naif calls valid) + */ + void NaifStatus::CheckErrors(bool resetNaif) { + if(!initialized) { + SpiceChar returnAct[32] = "RETURN"; + SpiceChar printAct[32] = "NONE"; + erract_c ( "SET", sizeof(returnAct), returnAct); // Reset action to return + errprt_c ( "SET", sizeof(printAct), printAct); // ... and print nothing + initialized = true; + } + + // Do nothing if NAIF didn't fail + //getmsg_c("", 0, NULL); + if(!failed_c()) return; + + // This method has been documented with the information provided + // from the NAIF documentation at: + // naif/cspice61/packages/cspice/doc/html/req/error.html + + + // This message is a character string containing a very terse, usually + // abbreviated, description of the problem. The message is a character + // string of length not more than 25 characters. It always has the form: + // SPICE(...) + // Short error messages used in CSPICE are CONSTANT, since they are + // intended to be used in code. That is, they don't contain any data which + // varies with the specific instance of the error they indicate. + // Because of the brief format of the short error messages, it is practical + // to use them in a test to determine which type of error has occurred. + const int SHORT_DESC_LEN = 26; + SpiceChar naifShort[SHORT_DESC_LEN]; + getmsg_c("SHORT", SHORT_DESC_LEN, naifShort); + + // This message may be up to 1840 characters long. The CSPICE error handling + // mechanism makes no use of its contents. Its purpose is to provide human-readable + // information about errors. Long error messages generated by CSPICE routines often + // contain data relevant to the specific error they describe. + const int LONG_DESC_LEN = 1841; + SpiceChar naifLong[LONG_DESC_LEN]; + getmsg_c("LONG", LONG_DESC_LEN, naifLong); + + // Search for known naif errors... + iString errMsg; + + Pvl error; + PvlGroup errorDescription("ErrorDescription"); + errorDescription.AddKeyword(PvlKeyword("ShortMessage", naifShort)); + errorDescription.AddKeyword(PvlKeyword("LongMessage", naifLong)); + error.AddGroup(errorDescription); + + PvlTranslationManager trans(error, "$base/translations/NaifErrors.trn"); + + try { + errMsg = trans.Translate("ShortMessage"); + } + catch(iException &e) { + e.Clear(); + errMsg = "An unknown NAIF error has been encountered."; + } + + try { + errMsg += " " + trans.Translate("LongMessage"); + } + catch(iException &e) { + e.Clear(); + } + + // Now process the error + if(resetNaif) { + reset_c(); + } + + errMsg += " The short explanation "; + errMsg += "provided by NAIF is [" + iString(naifShort) + "]. "; + errMsg += "The Naif error is [" + iString(naifLong) + "]"; + + throw iException::Message(iException::Spice, errMsg, _FILEINFO_); + } +} diff --git a/isis/src/base/objs/NaifStatus/NaifStatus.h b/isis/src/base/objs/NaifStatus/NaifStatus.h new file mode 100644 index 0000000000000000000000000000000000000000..c43c309de70cc06001d291a754780758a1f8f16f --- /dev/null +++ b/isis/src/base/objs/NaifStatus/NaifStatus.h @@ -0,0 +1,44 @@ +#ifndef NaifStatus_h +#define NaifStatus_h + +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/06/17 21:26:19 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { +/** + * @brief Class for checking for errors in the NAIF library + * + * The Naif Status class looks for errors that have occurred in NAIF calls. If + * an error has occurred, it will be converted to an iException. + * + * @author 2008-06-13 Steven Lambright + * + */ + class NaifStatus { + public: + static void CheckErrors(bool resetNaif = true); + private: + static bool initialized; + }; +}; + +#endif diff --git a/isis/src/base/objs/NaifStatus/NaifStatus.truth b/isis/src/base/objs/NaifStatus/NaifStatus.truth new file mode 100644 index 0000000000000000000000000000000000000000..90eebbd8a25f4aed1201f573c96cdda0be91043a --- /dev/null +++ b/isis/src/base/objs/NaifStatus/NaifStatus.truth @@ -0,0 +1,5 @@ +Unit Test for NaifStatus +No Errors + +Empty String Error +**SPICE ERROR** An empty string was passed into a naif routine. The short explanation provided by NAIF is [SPICE(EMPTYSTRING)]. The Naif error is [String "action" has length zero.] diff --git a/isis/src/base/objs/NaifStatus/unitTest.cpp b/isis/src/base/objs/NaifStatus/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47d9a102f847cb26b668cc3771b97c95e634ce76 --- /dev/null +++ b/isis/src/base/objs/NaifStatus/unitTest.cpp @@ -0,0 +1,25 @@ +#include "NaifStatus.h" +#include "naif/SpiceUsr.h" +#include "Preference.h" +#include "iException.h" + +using namespace Isis; + +int main() { + Isis::Preference::Preferences(true); + + std::cout << "Unit Test for NaifStatus" << std::endl; + + std::cout << "No Errors" << std::endl; + NaifStatus::CheckErrors(); + + std::cout << std::endl << "Empty String Error" << std::endl; + try { + erract_c("SET", (SpiceInt)0, ""); + NaifStatus::CheckErrors(); + } + catch (iException &e) { + e.Report(false); + } + +} diff --git a/isis/src/base/objs/NoNormalization/Makefile b/isis/src/base/objs/NoNormalization/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1084b8dae27d0597b42d04a2fd2c12dddaaa4525 --- /dev/null +++ b/isis/src/base/objs/NoNormalization/Makefile @@ -0,0 +1,5 @@ +INCS = NoNormalization.h +SRCS = NoNormalization.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/NoNormalization/NoNormalization.cpp b/isis/src/base/objs/NoNormalization/NoNormalization.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9f6f18c270982d3a3f11cb649a89339f660470f --- /dev/null +++ b/isis/src/base/objs/NoNormalization/NoNormalization.cpp @@ -0,0 +1,21 @@ +#include +#include "NoNormalization.h" +#include "SpecialPixel.h" +#include "iException.h" + +namespace Isis { + NoNormalization::NoNormalization (Pvl &pvl, PhotoModel &pmodel) : + NormModel(pvl,pmodel) { + } + + void NoNormalization::NormModelAlgorithm (double phase, double incidence, + double emission, double dn, double &albedo, double &mult, + double &base) + { + albedo = dn; + } +} + +extern "C" Isis::NormModel *NoNormalizationPlugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel) { + return new Isis::NoNormalization(pvl,pmodel); +} diff --git a/isis/src/base/objs/NoNormalization/NoNormalization.h b/isis/src/base/objs/NoNormalization/NoNormalization.h new file mode 100644 index 0000000000000000000000000000000000000000..5bc67d92a14f0e40fb2e0fee6cf0677a3db6dfcd --- /dev/null +++ b/isis/src/base/objs/NoNormalization/NoNormalization.h @@ -0,0 +1,58 @@ +#if !defined(NoNormalization_h) +#define NoNormalization_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/05/18 18:10:58 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "NormModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief NoNormalization - perform simple correction without normalization (a*dn +b) + * + * @author 2008-03-17 Janet Barrett + * + * @internal + * @history 2008-03-17 Janet Barrett - Original version + * @history 2008-06-18 Steven Koechle - Fixed Documentation Errors + * @history 2010-05-18 Janet Barrett - Modified class so that it does nothing to + * the incoming dn value. The outgoing albedo value will be + * the same as the incoming dn value. + * + */ + class NoNormalization : public NormModel { + public: + NoNormalization (Pvl &pvl, PhotoModel &pmodel); + virtual ~NoNormalization() {}; + + protected: + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double dn, double &albedo, double &mult, double &base); + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double deminc, double demema, double dn, double &albedo, + double &mult, double &base) {}; + }; +}; + +#endif diff --git a/isis/src/base/objs/NoNormalization/NoNormalization.truth b/isis/src/base/objs/NoNormalization/NoNormalization.truth new file mode 100644 index 0000000000000000000000000000000000000000..9cf02d76322dbf2e076ae90e41d0be18011686ce --- /dev/null +++ b/isis/src/base/objs/NoNormalization/NoNormalization.truth @@ -0,0 +1,24 @@ +UNIT TEST for NoNormalization normalization function + +Object = PhotometricModel + Group = Algorithm + Name = LunarLambertMcEwen + End_Group +End_Object + +Object = NormalizationModel + Group = Algorithm + Name = NoNormalization + End_Group +End_Object +End + +Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0800618902 ... +Normalization value = 0.0800619 + +Test phase=75.7207248, incidence=41.7031305, emission=28.9372914, dn=.6973346110 ... +Normalization value = 0.697335 + +Test phase=53.7187773, incidence=31.7060221, emission=18.9331391, dn=.1942250370 ... +Normalization value = 0.194225 + diff --git a/isis/src/base/objs/NoNormalization/NormModel.plugin b/isis/src/base/objs/NoNormalization/NormModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..276f52dde4837c4f6e714ca285764442e83f3d5c --- /dev/null +++ b/isis/src/base/objs/NoNormalization/NormModel.plugin @@ -0,0 +1,4 @@ +Group = NoNormalization + Library = NoNormalization + Routine = NoNormalizationPlugin +End_Group diff --git a/isis/src/base/objs/NoNormalization/unitTest.cpp b/isis/src/base/objs/NoNormalization/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c4bbf4ac6e32d8f32c9166cb3e23d82903f181f --- /dev/null +++ b/isis/src/base/objs/NoNormalization/unitTest.cpp @@ -0,0 +1,65 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "NoNormalization.h" +#include "NormModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + double result; + double mult; + double base; + + std::cout << "UNIT TEST for NoNormalization normalization function" << + std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name", "LunarLambertMcEwen"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup algn("Algorithm"); + algn += PvlKeyword("Name","NoNormalization"); + + PvlObject on("NormalizationModel"); + on.AddGroup(algn); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(on); + + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + NoNormalization *nm = (NoNormalization*)NormModelFactory::Create(pvl,*pm); + + std::cout << "Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, " << + "dn=.0800618902 ..." << std::endl; + nm->CalcNrmAlbedo(86.7207248,51.7031305,38.9372914,.0800618902,result,mult,base); + std::cout << "Normalization value = " << result << std::endl << std::endl; + + std::cout << "Test phase=75.7207248, incidence=41.7031305, emission=28.9372914, " << + "dn=.6973346110 ..." << std::endl; + nm->CalcNrmAlbedo(75.7207248,41.7031305,28.9372914,.6973346110,result,mult,base); + std::cout << "Normalization value = " << result << std::endl << std::endl; + + std::cout << "Test phase=53.7187773, incidence=31.7060221, emission=18.9331391, " << + "dn=.1942250370 ..." << std::endl; + nm->CalcNrmAlbedo(53.7187773,31.7060221,18.9331391,.1942250370,result,mult,base); + std::cout << "Normalization value = " << result << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/NoOperator/InterestOperator.plugin b/isis/src/base/objs/NoOperator/InterestOperator.plugin new file mode 100644 index 0000000000000000000000000000000000000000..ea3fcb9b0888953ed484d2ef8ea4d12453eed6e9 --- /dev/null +++ b/isis/src/base/objs/NoOperator/InterestOperator.plugin @@ -0,0 +1,4 @@ +Group = No + Library = NoOperator + Routine = NoOperatorPlugin +End_Group diff --git a/isis/src/base/objs/NoOperator/Makefile b/isis/src/base/objs/NoOperator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..de144d4425e601c71ffdceee1168d94a5612eaad --- /dev/null +++ b/isis/src/base/objs/NoOperator/Makefile @@ -0,0 +1,5 @@ +INCS = NoOperator.h +SRCS = NoOperator.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/NoOperator/NoOperator.cpp b/isis/src/base/objs/NoOperator/NoOperator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d01d7402b4603a3627789225882eefcef68151f6 --- /dev/null +++ b/isis/src/base/objs/NoOperator/NoOperator.cpp @@ -0,0 +1,22 @@ +#include "NoOperator.h" +#include "Chip.h" +#include "Statistics.h" + +namespace Isis { + /** + * This method returns a constant so all points have equal interest + * + * @param chip + * + * @return pi * e + */ + double NoOperator::Interest (Chip &chip) { + // Important: Interest = pi * e + return Isis::PI * Isis::E; + } +} + +extern "C" Isis::InterestOperator *NoOperatorPlugin (Isis::Pvl &pvl) { + return new Isis::NoOperator(pvl); +} + diff --git a/isis/src/base/objs/NoOperator/NoOperator.h b/isis/src/base/objs/NoOperator/NoOperator.h new file mode 100644 index 0000000000000000000000000000000000000000..befec1955b4bc2fd6215b01d522699e642d785ab --- /dev/null +++ b/isis/src/base/objs/NoOperator/NoOperator.h @@ -0,0 +1,55 @@ +#ifndef NoOperator_h +#define NoOperator_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/12/12 21:55:56 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "InterestOperator.h" + +namespace Isis { + class Pvl; + class Chip; + + /** + * @brief no interest operator + * + * This class is used to construct a no interest operator. + * For this class, the interest returned is the constant pi * e + * + * @see InterestOperator + * + * @author 2008-12-12 Christopher Austin + * + * @internal + * @history 2008-12-12 Jacob Danton - Original Version + */ + class NoOperator : public InterestOperator { + public: + NoOperator (Pvl &pvl) : InterestOperator(pvl) {p_worstInterest = 0.0;}; + virtual ~NoOperator() {}; + + protected: + virtual double Interest (Chip &chip); + }; +}; + +#endif diff --git a/isis/src/base/objs/NoOperator/NoOperator.truth b/isis/src/base/objs/NoOperator/NoOperator.truth new file mode 100644 index 0000000000000000000000000000000000000000..940007ff7b4e772c7efda842bd7ec7f50f71096b --- /dev/null +++ b/isis/src/base/objs/NoOperator/NoOperator.truth @@ -0,0 +1,16 @@ +Object = InterestOperator + Group = Operator + Name = No + DeltaLine = 100 + DeltaSamp = 100 + Samples = 15 + Lines = 15 + MinimumDN = 0.0 + MaximumDN = 1.0 + MinimumInterest = 0.01 + End_Group +End_Object +End +Sample: 92 +Line : 450 +Interest: 8.53973 diff --git a/isis/src/base/objs/NoOperator/unitTest.cpp b/isis/src/base/objs/NoOperator/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62d890af0ba13abf387e38b7a6f3220a35458639 --- /dev/null +++ b/isis/src/base/objs/NoOperator/unitTest.cpp @@ -0,0 +1,54 @@ +#include +#include +#include "InterestOperator.h" +#include "InterestOperatorFactory.h" +#include "NoOperator.h" +#include "Chip.h" +#include "Cube.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "PvlObject.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + try { + PvlGroup op("Operator"); + op += PvlKeyword("Name","No"); + op += PvlKeyword("DeltaLine", 100); + op += PvlKeyword("DeltaSamp", 100); + op += PvlKeyword("Samples", 15); + op += PvlKeyword("Lines", 15); + op += PvlKeyword("MinimumDN", 0.0); + op += PvlKeyword("MaximumDN", 1.0); + op += PvlKeyword("MinimumInterest", 0.01); + + PvlObject o("InterestOperator"); + o.AddGroup(op); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl; + + InterestOperator *iop = InterestOperatorFactory::Create(pvl); + + Cube c; + c.Open("$mgs/testData/ab102401.cub"); + + //iop->Operate(c, 100, 350); + UniversalGroundMap univGrndMap(c); + iop->Operate(c, univGrndMap, 100, 350); + + std::cout << "Sample: " << iop->CubeSample() << std::endl + << "Line : " << iop->CubeLine() << std::endl + << "Interest: " << iop->InterestAmount() << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/NormModel/Makefile b/isis/src/base/objs/NormModel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2a76bb0b4696c6dc8a55e602111a953c5a4b1611 --- /dev/null +++ b/isis/src/base/objs/NormModel/Makefile @@ -0,0 +1,5 @@ +INCS = NormModel.h +SRCS = NormModel.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/NormModel/NormModel.cpp b/isis/src/base/objs/NormModel/NormModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e083770d6e2760fb32647b5636b06df631b7f20b --- /dev/null +++ b/isis/src/base/objs/NormModel/NormModel.cpp @@ -0,0 +1,97 @@ +#include "Pvl.h" +#include "NormModel.h" +#include "PhotoModel.h" +#include "AtmosModel.h" +#include "iException.h" + +namespace Isis { + /** + * Create a NormModel object. Because this is a pure virtual class you can + * not create a NormModel class directly. Instead, see the NormModelFactory + * class. + * + * @param pvl A pvl object containing a valid NormModel specification + * + * @see normalizationModels.doc + */ + NormModel::NormModel (Pvl &pvl, PhotoModel &pmodel) { + p_normAlgorithmName = "Unknown"; + p_normPM = &pmodel; + p_normAM = NULL; + p_normWavelength = 1.0; + } + + /** + * Create a NormModel object. Because this is a pure virtual class you can + * not create a NormModel class directly. Instead, see the NormModelFactory + * class. + * + * @param pvl A pvl object containing a valid NormModel specification + * + * @see normalizationModels.doc + */ + NormModel::NormModel (Pvl &pvl, PhotoModel &pmodel, AtmosModel &amodel) { + p_normAlgorithmName = "Unknown"; + p_normPM = &pmodel; + p_normAM = &amodel; + p_normWavelength = 1.0; + } + + /** + * Set the wavelength parameter. This value is obtained + * from the BandBin Center keyword of the image. This must + * be set by the application. + */ + void NormModel::SetNormWavelength(double wavelength) { + p_normWavelength = wavelength; + } + + /** + * Calculate the normalization albedo using photometric angle information + * + * @param pha input phase angle + * @param inc input incidence angle + * @param ema input emission angle + * @param dn input albedo value + * + */ + void NormModel::CalcNrmAlbedo(double pha, double inc, double ema, double dn, + double &albedo, double &mult, double &base) { + + // Check validity of photometric angles + //if (pha > 180.0 || inc > 90.0 || ema > 90.0 || pha < 0.0 || + // inc < 0.0 || ema < 0.0) { + // std::string msg = "Invalid photometric angles"; + // throw iException::Message(iException::Programmer,msg,_FILEINFO_); + //} + + // Perform normalization + NormModelAlgorithm(pha,inc,ema,dn,albedo,mult,base); + } + + /** + * Calculate the normalization albedo using photometric angle information + * + * @param pha input phase angle + * @param inc input incidence angle for ellipsoid + * @param ema input emission angle for ellipsoid + * @param deminc input incidence angle for dem + * @param demema input emission angle for dem + * @param dn input albedo value + * + */ + void NormModel::CalcNrmAlbedo(double pha, double inc, double ema, + double deminc, double demema, double dn, double &albedo, + double &mult, double &base) { + + // Check validity of photometric angles + //if (pha > 180.0 || inc > 90.0 || ema > 90.0 || pha < 0.0 || + // inc < 0.0 || ema < 0.0) { + // std::string msg = "Invalid photometric angles"; + // throw iException::Message(iException::Programmer,msg,_FILEINFO_); + //} + + // Perform normalization + NormModelAlgorithm(pha,inc,ema,deminc,demema,dn,albedo,mult,base); + } +} diff --git a/isis/src/base/objs/NormModel/NormModel.h b/isis/src/base/objs/NormModel/NormModel.h new file mode 100644 index 0000000000000000000000000000000000000000..34d3946af56ac678e15f2f787b4b644525760b46 --- /dev/null +++ b/isis/src/base/objs/NormModel/NormModel.h @@ -0,0 +1,89 @@ +#if !defined(NormModel_h) +#define NormModel_h +/** + * @file + * $Revision: 1.6 $ + * $Date: 2008/07/09 20:06:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Pvl.h" +#include "PhotoModel.h" +#include "AtmosModel.h" + +namespace Isis { + +/** + * @brief + * + * @author 1998-12-21 Randy Kirk + * + * @internal + * @history 2007-08-15 Steven Lambright - Refactored + * @history 2008-03-07 Janet Barrett - Added p_normWavelength + * variable and SetNormWavelength method to + * allow an application to set this value to + * the BandBin Center keyword value for use + * with MoonAlbedo normalization. The application + * needs to call the SetPhotomWl method in the + * Photometry class and the SetNormWavelength + * method is called from the Photometry class. + * @history 2008-06-18 Steven Koechle - Fixed Documentation Errors + * @history 2008-07-09 Steven Lambright - Fixed unit test + */ + class NormModel { + public: + NormModel (Pvl &pvl, PhotoModel &pmodel); + NormModel (Pvl &pvl, PhotoModel &pmodel, AtmosModel &amodel); + virtual ~NormModel() {}; + + //! Return normalization algorithm name + std::string AlgorithmName () const { return p_normAlgorithmName; }; + + //! Calculate the albedo normalization + void CalcNrmAlbedo(double pha, double inc, double ema, double dn, + double &albedo, double &mult, double &base); + void CalcNrmAlbedo(double pha, double inc, double ema, double deminc, + double demema, double dn, double &albedo, + double &mult, double &base); + virtual void SetNormWavelength(double wavelength); + + protected: + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double dn, double &albedo, double &mult, double &base) = 0; + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double deminc, double demema, double dn, double &albedo, + double &mult, double &base) = 0; + + void SetAlgorithmName(std::string name) { p_normAlgorithmName = name; } + PhotoModel *GetPhotoModel() { return p_normPM; } + AtmosModel *GetAtmosModel() { return p_normAM; } + + double p_normWavelength; + + private: + std::string p_normAlgorithmName; + PhotoModel *p_normPM; + AtmosModel *p_normAM; + }; +}; + +#endif diff --git a/isis/src/base/objs/NormModel/NormModel.truth b/isis/src/base/objs/NormModel/NormModel.truth new file mode 100644 index 0000000000000000000000000000000000000000..4d01986f6743a16b2e0cb7948f781daba237f9b7 --- /dev/null +++ b/isis/src/base/objs/NormModel/NormModel.truth @@ -0,0 +1,23 @@ +UNIT TEST for Isis::NormModel + +Testing missing NormalizationModel object ... +**PVL ERROR** Unable to find object [NormalizationModel] + +**PVL ERROR** Unable to find object [NormalizationModel] + +Testing missing Algorithm group ... +**PVL ERROR** Unable to find group [Algorithm] + +**PVL ERROR** Unable to find group [Algorithm] + +Testing missing Name keyword ... +**PVL ERROR** Keyword [Name] does not exist in [Group = Algorithm] + +**PVL ERROR** Keyword [Name] does not exist in [Group = Algorithm] + +Testing supported normalization model ... + + +Testing normalization model get methods ... +AlgorithmName = Unknown + diff --git a/isis/src/base/objs/NormModel/unitTest.cpp b/isis/src/base/objs/NormModel/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf8fd011f743b2db559da14839860a43214bcb04 --- /dev/null +++ b/isis/src/base/objs/NormModel/unitTest.cpp @@ -0,0 +1,90 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "AtmosModel.h" +#include "AtmosModelFactory.h" +#include "NormModel.h" +#include "NormModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +void doit(Pvl &lab,PhotoModel &pm); +void doit(Pvl &lab,PhotoModel &pm,AtmosModel &am); + +int main () { + Isis::Preference::Preferences(true); + + std::cout << "UNIT TEST for Isis::NormModel" << std::endl << std::endl; + + Pvl lab; + lab.AddObject(PvlObject("PhotometricModel")); + lab.FindObject("PhotometricModel").AddGroup(PvlGroup("Algorithm")); + lab.FindObject("PhotometricModel").FindGroup("Algorithm").AddKeyword(PvlKeyword("Name","Lambert")); + PhotoModel *pm = PhotoModelFactory::Create(lab); + + lab.AddObject(PvlObject("AtmosphericModel")); + lab.FindObject("AtmosphericModel").AddGroup(PvlGroup("Algorithm")); + lab.FindObject("AtmosphericModel").FindGroup("Algorithm").AddKeyword(PvlKeyword("Name","Anisotropic1")); + AtmosModel *am = AtmosModelFactory::Create(lab,*pm); + + std::cout << "Testing missing NormalizationModel object ..." << std::endl; + + doit(lab,*pm); + doit(lab,*pm,*am); + + lab.AddObject(PvlObject("NormalizationModel")); + std::cout << "Testing missing Algorithm group ..." << std::endl; + + doit(lab,*pm); + doit(lab,*pm,*am); + + lab.FindObject("NormalizationModel").AddGroup(PvlGroup("Algorithm")); + + std::cout << "Testing missing Name keyword ..." << std::endl; + doit(lab,*pm); + doit(lab,*pm,*am); + + lab.FindObject("NormalizationModel").FindGroup("Algorithm").AddKeyword(PvlKeyword("Name","Albedo"), Pvl::Replace); + std::cout << "Testing supported normalization model ..." << std::endl; + doit(lab,*pm); + doit(lab,*pm,*am); + + NormModel *nm = NormModelFactory::Create(lab,*pm); + + try { + std::cout << "Testing normalization model get methods ..." << std::endl; + std::cout << "AlgorithmName = " << nm->AlgorithmName() << std::endl; + } + catch (iException &e) { + e.Report(false); + } + + std::cout << std::endl; + + return 0; +} + +void doit(Pvl &lab,PhotoModel &pm) { + try { + NormModelFactory::Create(lab,pm); + } + catch (iException &error) { + error.Report(false); + } + std::cout << std::endl; +} + +void doit(Pvl &lab,PhotoModel &pm,AtmosModel &am) { + try { + NormModelFactory::Create(lab,pm,am); + } + catch (iException &error) { + error.Report(false); + } + std::cout << std::endl; +} diff --git a/isis/src/base/objs/NormModelFactory/Makefile b/isis/src/base/objs/NormModelFactory/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5d30e7ac81d0b230afeb7158fff2fc61be4da071 --- /dev/null +++ b/isis/src/base/objs/NormModelFactory/Makefile @@ -0,0 +1,5 @@ +INCS = NormModelFactory.h +SRCS = NormModelFactory.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/NormModelFactory/NormModelFactory.cpp b/isis/src/base/objs/NormModelFactory/NormModelFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a32760ab95762369b6d63855b79c4995b9ac9a9 --- /dev/null +++ b/isis/src/base/objs/NormModelFactory/NormModelFactory.cpp @@ -0,0 +1,121 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2007/02/20 16:55:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "NormModelFactory.h" +#include "NormModel.h" +#include "Plugin.h" +#include "iException.h" +#include "Filename.h" + +namespace Isis { + /** + * Create a NormModel object using a PVL specification. + * An example of the PVL required for this is: + * + * @code + * Object = NormalizationModel + * Group = Algorithm + * Name = ShadeAtm + * PhotoModel = Minnaert + * AtmosModel = Isotropic1 + * EndGroup + * EndObject + * @endcode + * + * There are many other options that can be set via the pvl and are + * described in other documentation (see below). + * + * @param pvl The pvl object containing the specification + * + * @see normalizationModels.doc + **/ + NormModel *NormModelFactory::Create(Pvl &pvl, PhotoModel &pmodel) { + // Get the algorithm name to create + PvlGroup &algo = pvl.FindObject("NormalizationModel") + .FindGroup("Algorithm",Pvl::Traverse); + std::string algorithm = algo["Name"]; + + // Open the factory plugin file + Plugin *p = new Plugin; + Filename f("NormModel.plugin"); + if (f.Exists()) { + p->Read("NormModel.plugin"); + } + else { + p->Read("$ISISROOT/lib/NormModel.plugin"); + } + + // Get the algorithm specific plugin and return it + NormModel * (*plugin) (Pvl &pvl, PhotoModel &pmodel); + plugin = (NormModel * (*)(Pvl &pvl, PhotoModel &pmodel)) + p->GetPlugin(algorithm); + return (*plugin)(pvl, pmodel); + } + + /** + * Create a NormModel object using a PVL specification. + * An example of the PVL required for this is: + * + * @code + * Object = NormalizationModel + * Group = Algorithm + * Name = ShadeAtm + * PhotoModel = Minnaert + * AtmosModel = Isotropic1 + * EndGroup + * EndObject + * @endcode + * + * There are many other options that can be set via the pvl and are + * described in other documentation (see below). + * + * @param pvl The pvl object containing the specification + * + * @see normalizationModels.doc + **/ + NormModel *NormModelFactory::Create(Pvl &pvl, PhotoModel &pmodel, + AtmosModel &amodel) { + // Get the algorithm name to create + PvlGroup &algo = pvl.FindObject("NormalizationModel") + .FindGroup("Algorithm",Pvl::Traverse); + std::string algorithm = algo["Name"]; + + // Open the factory plugin file + Plugin *p = new Plugin; + Filename f("NormModel.plugin"); + if (f.Exists()) { + p->Read("NormModel.plugin"); + } + else { + p->Read("$ISISROOT/lib/NormModel.plugin"); + } + + // Get the algorithm specific plugin and return it + NormModel * (*plugin) (Pvl &pvl, PhotoModel &pmodel, + AtmosModel &amodel); + plugin = (NormModel * (*)(Pvl &pvl, PhotoModel &pmodel, + AtmosModel &amodel)) + p->GetPlugin(algorithm); + return (*plugin)(pvl, pmodel, amodel); + } +} // end namespace isis diff --git a/isis/src/base/objs/NormModelFactory/NormModelFactory.h b/isis/src/base/objs/NormModelFactory/NormModelFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..0cc782ac4210b266d544a5e91c9a5d943f28a12e --- /dev/null +++ b/isis/src/base/objs/NormModelFactory/NormModelFactory.h @@ -0,0 +1,85 @@ +#ifndef NormModelFactory_h +#define NormModelFactory_h + +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/18 17:35:09 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { + class Pvl; + class PhotoModel; + class AtmosModel; + class NormModel; + + /** + * This class is used to create NormModel objects. Typically, applications which + * perform normalization corrections need to use different methods such as + * Shade, ShadeAtm, Albedo, etc. If this factory is given a Pvl object which + * contains a NormModel definition, it will create that specific instance of the + * class. For example, + * + * @code + * Object = NormalizationModel + * Group = Algorithm + * Name = Shade + * ... + * EndGroup + * ... + * EndObject + * End + * @endcode + * + * Will create a Shade normalization object (which is derived from + * NormModel). The simplest way to create a NormModel class is to use + * the static Create method. + * + * @code + * Pvl p("mynormmodel.pvl"); + * NormModel *ar = NormModelFactory::Create(p); + * @endcode + * + * @ingroup PatternMatching + * + * @author 2006-01-23 Janet Barrett + * + * @internal + * @history 2006-01-23 Janet Barrett - Original version + * @history 2008-06-18 Steven Koechle - Fixed Documentation Errors + */ + class NormModelFactory { + public: + static NormModel *Create(Pvl &pvl, PhotoModel &pmodel); + static NormModel *Create(Pvl &pvl, PhotoModel &pmodel, AtmosModel &amodel); + + private: + /** + * Constructor (its private so you can't use it). Use the Create Method + * instead. + */ + NormModelFactory() {}; + + //! Destroys the NormModelFactory + ~NormModelFactory() {}; + }; +}; + +#endif diff --git a/isis/src/base/objs/NormModelFactory/NormModelFactory.truth b/isis/src/base/objs/NormModelFactory/NormModelFactory.truth new file mode 100644 index 0000000000000000000000000000000000000000..424657ba6c68a05cd929a158ff111a8891761a56 --- /dev/null +++ b/isis/src/base/objs/NormModelFactory/NormModelFactory.truth @@ -0,0 +1 @@ +All testing deferred to NormModel and it's extended classes. diff --git a/isis/src/base/objs/NormModelFactory/unitTest.cpp b/isis/src/base/objs/NormModelFactory/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..53b50658b3d6dba7068c4ab111890d73dad465e0 --- /dev/null +++ b/isis/src/base/objs/NormModelFactory/unitTest.cpp @@ -0,0 +1,14 @@ +#include +#include + +#include "Preference.h" + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + + cout << "All testing deferred to NormModel and it's extended classes." << endl; + + return 0; +} diff --git a/isis/src/base/objs/NumericalApproximation/Makefile b/isis/src/base/objs/NumericalApproximation/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fcf5245b23a4627c57937d84175e15006fd74207 --- /dev/null +++ b/isis/src/base/objs/NumericalApproximation/Makefile @@ -0,0 +1,6 @@ +INCS = NumericalApproximation.h +SRCS = NumericalApproximation.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/base/objs/NumericalApproximation/NumericalApproximation.cpp b/isis/src/base/objs/NumericalApproximation/NumericalApproximation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1775902c0c229ce0fab3eeeebf2403709cc1022c --- /dev/null +++ b/isis/src/base/objs/NumericalApproximation/NumericalApproximation.cpp @@ -0,0 +1,3288 @@ +#include +#include +#include +#include +#include +#include +#include "NumericalApproximation.h" +#include "SpecialPixel.h" +#include "iException.h" +#include "iString.h" + +using namespace std; +namespace Isis { + /** + * Default constructor creates NumericalApproximation object. + * Sets the NumericalApproximation::InterpType to the + * enumerated value of @a itype. Default is @a CubicNatural. + * + * @param itype NumericalApproximation::InterpType enum value to + * be assigned to this object (Default: + * @a CubicNatural) + * @throws Isis::iException::Programmer "Unable to construct + * NumericalApproximation object" + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. Original name DataInterp(). + * @history 2008-11-05 Jeannie Walldren - Changed name and + * modified to allow for interpolation types other than + * those supported by GSL. + */ + NumericalApproximation::NumericalApproximation(const NumericalApproximation::InterpType &itype)throw (iException &) { + // Validate parameter and initialize class variables + try { + Init(itype); + p_dataValidated = false; + } + catch (iException e) { // catch exception from Init() + throw iException::Message(e.Type(), + "NumericalApproximation() - Unable to construct NumericalApproximation object", + _FILEINFO_); + } + } + + /** + * @brief Constructs NumericalApproximation object, sets + * interpolation type, populates the data set with + * pointer values. + * + * This constructor verifies the + * NumericalApproximation::InterpType passed in as a + * parameter. If it passes, it assigns this type to the object + * and @a x and @a y are added to the data set and validated. If + * the interpolation type is @a CubicClamped, first derivatives + * of the endpoints are required before Evaluate() may be + * called. If no value for itype is given, the default is + * @a CubicNatural. + * + * @param n Number of data points to be used. + * @param x Array of domain values to add to data set + * @param y Array of range values corresponding to each + * domain value in @a x + * @param itype NumericalApproximation::InterpType enum + * value to be assigned to this object (Default: + * @a CubicNatural) + * @throws Isis::iException::Programmer "Unable to construct + * NumericalApproximation object" + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. Original name DataInterp(). + * @history 2008-11-05 Jeannie Walldren - Changed name and + * modified to allow for interpolation types other than + * those supported by GSL. + * @history 2008-12-18 Jeannie Walldren - Added address + * operator (&) to input variables of type + * NumericalApproximation::InterpType. + */ + NumericalApproximation::NumericalApproximation(unsigned int n, double *x, double *y, + const NumericalApproximation::InterpType &itype) throw (iException &){ + try{ + Init(itype); + AddData(n,x,y); + ValidateDataSet(); + } + catch (iException e){ // catch exception from Init(), AddData(), ValidateDataSet() + throw iException::Message(e.Type(), + "NumericalApproximation() - Unable to construct object using the given arrays, size and interpolation type", + _FILEINFO_); + } + } + + /** + * @brief Constructs NumericalApproximation object, sets + * interpolation type, populates the data set with vector + * values. + * + * This constructor verifies the interpolation type and checks + * that the @a x and @a y vectors have the same number of + * elements. If so, the object is assigned the + * NumericalApproximation::InterpType passed in as a + * parameter and @a x and @a y are added + * to the data set and validated. If the interpolation type is + * @a CubicClamped, first derivatives of the + * endpoints are required before evaluation is allowed. If no + * value for itype is given, the default + * is @a CubicNatural. + * + * @param x Vector of domain values to add to data set + * @param y Vector of range values corresponding to each + * domain value in @a x + * @param itype NumericalApproximation::InterpType enum + * value to be assigned to this object (Default: + * @a CubicNatural) + * @throws Isis::iException::Programmer "Unable to construct + * NumericalApproximation object" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + * @history 2008-12-18 Jeannie Walldren - Added address + * operator (&) to input variables of type vector and + * NumericalApproximation::InterpType. + */ + NumericalApproximation::NumericalApproximation(const vector &x, const vector &y, + const NumericalApproximation::InterpType &itype) throw (iException &){ + try{ + Init(itype); + AddData(x,y); // size of x = size of y validated in this method + ValidateDataSet(); + } + catch (iException e){ // catch exception from Init(), AddData(), ValidateDataSet() + throw iException::Message(e.Type(), + "NumericalApproximation() - Unable to construct an object using the given vectors and interpolation type", + _FILEINFO_); + } + } + + /** + * @brief Copy constructor creates NumericalApproximation object + * and sets the copies the class variable values and + * state of input NumericalApproximation object to the + * new object. + * + * Copying of class objects must be handled explicitly in order + * for it to be completed properly. The data, interpolator type + * and other class variables are copied from the supplied + * object. + * + * @param oldObject NumericalApproximation object to gleen data + * from for creation of this object + * @throws Isis::iException::Programmer "Unable to construct + * NumericalApproximation object" + * @internal + * @history 2006-06-14 Kris Becker - Original version + * created in DataInterp class. Original name + * DataInterp(). + * @history 2008-11-05 Jeannie Walldren - Changed name and + * modified to allow for interpolation types other than + * those supported by GSL. + * @history 2009-06-10 Jeannie Walldren - Set new variable, + * p_fprimeOfx. + */ + NumericalApproximation::NumericalApproximation(const NumericalApproximation &oldObject) { + try{ + // initialize new object and set type to that of old object + Init(oldObject.p_itype); + // fill data set of new object + p_x = oldObject.p_x; + p_y = oldObject.p_y; + // if this data was previously validated, no need to do this again + p_dataValidated = oldObject.p_dataValidated; + // copy values for interpolation-specific variables + p_clampedComputed = oldObject.p_clampedComputed; + p_clampedEndptsSet = oldObject.p_clampedEndptsSet; + p_clampedSecondDerivs = oldObject.p_clampedSecondDerivs; + p_clampedDerivFirstPt = oldObject.p_clampedDerivFirstPt; + p_clampedDerivLastPt = oldObject.p_clampedDerivLastPt; + p_polyNevError = oldObject.p_polyNevError; + p_fprimeOfx = oldObject.p_fprimeOfx; + } + catch (iException e){ // catch exception from Init() + throw iException::Message(e.Type(), + "NumericalApproximation() - Unable to copy the given object", + _FILEINFO_); + } + } + + /** + * @brief NumericalApproximation assigmment operator sets this + * object "equal to" another + * + * Assigning one object to the other requires a deallocation of + * the current state of this object and reinitialization of data + * from the right hand object. This may be a bit costly if the + * number of values is large. + * + * @param oldObject NumericalApproximation object to copy data + * from for initialization + * @throws Isis::iException::Programmer "Unable to copy + * NumericalApproximation object" + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Changed name and + * modified to allow for interpolation types other + * than those supported by GSL. + * @history 2009-06-10 Jeannie Walldren - Set new variable, + * p_fprimeOfx. + * @history 2010-06-25 Eric Hyer - Returns a NumericalApproximation now + * instead of a NumericalApproximation constructor + */ + NumericalApproximation & NumericalApproximation::operator=(const NumericalApproximation &oldObject) { + try{ + if (&oldObject != this) { + if (GslInterpType(p_itype)) GslDeallocation(); + SetInterpType(oldObject.p_itype); + // set class variables + p_x = oldObject.p_x; + p_y = oldObject.p_y; + p_dataValidated = oldObject.p_dataValidated; + p_clampedSecondDerivs = oldObject.p_clampedSecondDerivs; + p_clampedDerivFirstPt = oldObject.p_clampedDerivFirstPt; + p_clampedDerivLastPt = oldObject.p_clampedDerivLastPt; + p_polyNevError = oldObject.p_polyNevError; + p_fprimeOfx = oldObject.p_fprimeOfx; + } + return (*this); + } + catch (iException e){ // catch exception from SetInterpType() + throw iException::Message(e.Type(), + "operator=() - Unable to copy the given object", + _FILEINFO_); + } + + } + + /** + * @brief Destructor deallocates memory being used + * + * Explicit operations are required to free resources of the + * interpolation + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. Original name ~DataInterp(). + * @history 2008-11-05 Jeannie Walldren - Changed name. + */ + NumericalApproximation::~NumericalApproximation() { + if (GslInterpType(p_itype)) GslDeallocation(); + } + + /** + * @brief Get name of interpolating function assigned to object. + * + * This method returns the name of the interpolation type + * that is currently assigned to this object as a + * @b std::string. This may be called without adding any + * points. If called before computation, the result reflects the + * name of the function chosen at instantiation. + * + * @return @b std::string Name of the interpolation function + * used/to be used. + * @throws Isis::iException::Programmer "Unable to retrieve + * numerical approximation name", + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Modified to allow for + * interpolation types other than those supported by + * GSL. + * @history 2009-06-10 Jeannie Walldren - Added CubicHermite + * name. + */ + string NumericalApproximation::Name() const { + if (p_itype == NumericalApproximation::CubicNeighborhood) { + return "cspline-neighborhood"; + } + else if (p_itype == NumericalApproximation::CubicClamped) { + return "cspline-clamped"; + } + else if (p_itype == NumericalApproximation::PolynomialNeville) { + return "polynomial-Neville's"; + } + else if (p_itype == NumericalApproximation::CubicHermite) { + return "cspline-Hermite"; + } + try{ + string name = (string(GslFunctor(p_itype)->name)); + if (p_itype == NumericalApproximation::CubicNatural) { + return name + "-natural"; + } + else return name; + } + catch (iException e){ // catch exception from GslFunctor() + throw iException::Message(e.Type(), + "Name() - GSL interpolation type not found", + _FILEINFO_); + } + } + + /** + * @brief Minimum number of points required by interpolating + * function + * + * This method returns the minimum number of points that are + * required by the interpolating function in order for it to be + * applied to a data set. It returns the number of the of the + * currently selected/active interpolation function. + * + * @return @b int Minimum number of data points required for the + * interpolation function + * @throws Isis::iException::Programmer "Unable to calculate + * minimum points." + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Modified to allow for + * interpolation types other than those supported by + * GSL. + * @history 2009-06-10 Jeannie Walldren - Added min points for + * CubicHermite. + * + */ + int NumericalApproximation::MinPoints() { + if (p_itype == NumericalApproximation::CubicNeighborhood) { + return 4; + } + else if (p_itype == NumericalApproximation::CubicClamped) { + return 3; + } + else if (p_itype == NumericalApproximation::PolynomialNeville) { + return 3; + } + else if (p_itype == NumericalApproximation::CubicHermite) { + return 2; + } + try{ + return (GslFunctor(p_itype)->min_size); + } + catch (iException e){ // catch exception from GslFunctor() + throw iException::Message(e.Type(), + "MinPoints() - GSL interpolation not found", + _FILEINFO_); + } + } + + /** + * @brief Minimum number of points required by interpolating + * function + * + * This method returns the minimum number of points that are + * required by the interpolating function in order for it to be + * applied to a data set. It returns the minimum number for the + * specifed interpolation function as specified by the caller. + * + * @param itype Type of interpolation function for which to + * return minimum points + * @return @b int Minimum number of data points required for the + * interpolation function + * + * @throws Isis::iException::Programmer "Invalid argument. + * Unknown interpolation type" + * @throws Isis::iException::Programmer "Unable to calculate + * minimum points" + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Modified to allow for + * interpolation types other than those supported by + * GSL. + * @history 2009-06-10 Jeannie Walldren - Added min points for + * CubicHermite. + */ + int NumericalApproximation::MinPoints(NumericalApproximation::InterpType itype) throw (iException &){ + //Validates the parameter + if (GslInterpType(itype)) { + try{ + //GslFunctor() Validates parameter for Gsl interp types + NumericalApproximation nam(itype); + return (nam.GslFunctor(itype)->min_size); + } + catch (iException e){ // catch exception from GslFunctor() + throw iException::Message(e.Type(), + "MinPoints() - GSL interpolation type not found", + _FILEINFO_); + } + } + else if (itype == NumericalApproximation::CubicNeighborhood) { + return 4; + } + else if (itype == NumericalApproximation::CubicClamped) { + return 3; + } + else if (itype == NumericalApproximation::PolynomialNeville) { + return 3; + } + else if (itype == NumericalApproximation::CubicHermite) { + return 2; + } + throw iException::Message(iException::Programmer, + "MinPoints() - Invalid argument. Unknown interpolation type: " + + iString(NumericalApproximation::InterpType(itype)), + _FILEINFO_); + } + + /** + * @brief Add a datapoint to the set + * + * This method allows the user to add a point to the set of data + * in preparation for interpolation over an interval. + * + * @b Note: All data sets must have unique @a x values. If the + * interpolation type is not @a PolynomialNeville, + * @a x values must be sorted in ascending order. If + * @a CubicNatPeriodic interpolation type is used, the first and + * last points added to the data set + * must have the same @a y value. + * + * @param x Domain value to add to data set + * @param y Range value corresponding to domain value + * @a x + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Modified to reset + * class variables for interpolation types other than + * those supported by GSL. + */ + void NumericalApproximation::AddData(const double x, const double y) { + p_x.push_back(x); + p_y.push_back(y); + p_clampedComputed = false; + p_clampedEndptsSet = false; + p_dataValidated = false; + p_clampedSecondDerivs.clear(); + p_clampedDerivFirstPt = 0; + p_clampedDerivLastPt = 0; + p_polyNevError.clear(); + p_interp = 0; + p_acc = 0; + return; + } + + /** + * @brief Add set of points to the data set using pointer arrays + * + * This method allows the user to add a set of points to the set + * of data in preparation for interpolation over an interval. + * This method does not overwrite previously added data. Rather, + * it adds the new data to the end of the existing data set. + * + * @b Note: Behavior is undefined if the domain is not + * sorted in ascending or descending order. + * + * @param n Number of data points to be used. + * @param x Array of domain values to add to data set + * @param y Array of range values corresponding to each + * domain value in @a x + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + void NumericalApproximation::AddData(unsigned int n, double *x, double *y) { + for (unsigned int i = 0; i < n; i++) { + p_x.push_back(x[i]); + p_y.push_back(y[i]); + } + p_clampedComputed = false; + p_clampedEndptsSet = false; + p_dataValidated = false; + p_clampedSecondDerivs.clear(); + p_clampedDerivFirstPt = 0; + p_clampedDerivLastPt = 0; + p_polyNevError.clear(); + p_interp = 0; + p_acc = 0; + return; + } + + /** + * @brief Add set of points to the data set using vectors + * + * This method allows the user to add a set of points to the set + * of data in preparation for interpolation over an interval. + * This method does not overwrite previously added data. Rather, + * it adds the new data to the end of the existing data set. + * + * @b Note: Behavior is undefined if the domain is not + * sorted in ascending or descending order. + * + * @param x Vector of domain values to add to data set + * @param y Vector of range values corresponding to each + * domain value in @a x + * @throws Isis::iException::Programmer "Invalid arguments. The + * number of x-values does not equal the + * number of y-values." + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + * @history 2008-12-18 Jeannie Walldren - Added address + * operator (&) to input variables of type vector. + */ + void NumericalApproximation::AddData(const vector &x, const vector &y) throw (iException &) { + int n = x.size(); + int m = y.size(); + if (n != m) { + ReportException(iException::Programmer,"AddData()", + "Invalid arguments. The sizes of the input vectors do not match", + _FILEINFO_); + } + for (int i = 0; i < n; i++) { + p_x.push_back(x[i]); + p_y.push_back(y[i]); + } + p_clampedComputed = false; + p_clampedEndptsSet = false; + p_dataValidated = false; + p_clampedSecondDerivs.clear(); + p_clampedDerivFirstPt = 0; + p_clampedDerivLastPt = 0; + p_polyNevError.clear(); + p_interp = 0; + p_acc = 0; + return; + } + + /** + * Sets the values for the first derivatives of the endpoints of + * the data set. This method can only be called for cubic + * splines with clamped boundary conditions, i.e. if + * NumericalApproximation::InterpType is + * @a CubicClamped. + * + * @param yp1 First derivative of the function evaluated at the + * domain minimum. + * @param ypn First derivative of the function evaluated at the + * domain maximum. + * @throws Isis::iException::Programmer "Method only used for + * cspline-clamped interpolation type" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original verison. + */ + void NumericalApproximation::SetCubicClampedEndptDeriv(double yp1, double ypn) throw (iException &){ + if (p_itype != NumericalApproximation::CubicClamped) { + ReportException(iException::Programmer, "SetCubicClampedEndptDeriv()", + "This method is only valid for cspline-clamped interpolation, may not be used for " + + Name() + " interpolation", + _FILEINFO_); + } + p_clampedDerivFirstPt = yp1; + p_clampedDerivLastPt = ypn; + p_clampedEndptsSet = true; + return; + } + + /** + * Adds values for the first derivatives of the data points. + * This method can only be called for cubic Hermite splines, + * i.e. if NumericalApproximation::InterpType is + * @a CubicHermite. These values should be entered in the order + * of the corresponding data points. + * + * @param n Number of derivative values to be added. + * @param fprimeOfx Array of derivative values to be added. + * @throws Isis::iException::Programmer "Method only used for + * cspline-Hermite interpolation type" + * @internal + * @history 2009-06-10 Jeannie Walldren - Original version + */ + void NumericalApproximation::AddCubicHermiteDeriv(unsigned int n, double *fprimeOfx) throw (iException &){ + if (p_itype != NumericalApproximation::CubicHermite) { + ReportException(iException::Programmer, "SetCubicHermiteDeriv()", + "This method is only valid for cspline-Hermite interpolation, may not be used for " + + Name() + " interpolation", + _FILEINFO_); + } + for (unsigned int i = 0; i < n; i++) { + p_fprimeOfx.push_back(fprimeOfx[i]); + } + return; + } + /** + * Adds values for the first derivatives of the data points. + * This method can only be called for cubic Hermite splines, + * i.e. if NumericalApproximation::InterpType is + * @a CubicHermite. These values should be entered in the order + * of the corresponding data points. + * + * @param fprimeOfx Vector of derivative values to be added. + * @throws Isis::iException::Programmer "Method only used for + * cspline-Hermite interpolation type" + * @internal + * @history 2009-06-10 Jeannie Walldren - Original version + */ + void NumericalApproximation::AddCubicHermiteDeriv(const vector &fprimeOfx) throw (iException &){ + if (p_itype != NumericalApproximation::CubicHermite) { + ReportException(iException::Programmer, "SetCubicHermiteDeriv()", + "This method is only valid for cspline-Hermite interpolation, may not be used for " + + Name() + " interpolation", + _FILEINFO_); + } + for (unsigned int i = 0; i < fprimeOfx.size(); i++) { + p_fprimeOfx.push_back(fprimeOfx[i]); + } + return; + } + /** + * Adds value of a first derivative of a data point. This method + * can only be called for cubic Hermite splines, i.e. if + * NumericalApproximation::InterpType is + * @a CubicHermite. Values should be entered in the order + * of the corresponding data points. + * + * @param fprimeOfx Derivative value to be added. + * @throws Isis::iException::Programmer "Method only used for + * cspline-Hermite interpolation type" + * @internal + * @history 2009-06-10 Jeannie Walldren - Original version + */ + void NumericalApproximation::AddCubicHermiteDeriv(double fprimeOfx) throw (iException &){ + if (p_itype != NumericalApproximation::CubicHermite) { + ReportException(iException::Programmer, "SetCubicHermiteDeriv()", + "This method is only valid for cspline-Hermite interpolation, may not be used for " + + Name() + " interpolation", + _FILEINFO_); + } + p_fprimeOfx.push_back(fprimeOfx); + return; + } + + /** + * @brief Retrieves the second derivatives of the data set. + * + * This method returns a vector of the same size as the data + * set. Each component is the second derivative of the + * corresponding @a p_x value , as estimated by the + * ComputeCubicClamped() method. + * + * @return @b vector @b \ List of second derivatives + * for each @a p_x value in the data set. + * @throws Isis::iException::Programmer "Method only used for + * cspline-clamped interpolation type" + * @throws Isis::iException::Programmer "Unable to calculate the + * second derivatives of the data set for a clamped + * cubic spline." + * @see ComputeCubicClamped() + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + * written to save off the error estimate found by + * EvaluatePolynomialNeville() + * @history 2009-06-10 Jeannie Walldren - Moved itype + * verification to beginning of method. + * + */ + vector NumericalApproximation::CubicClampedSecondDerivatives() throw (iException &){ + try{ + if (p_itype != NumericalApproximation::CubicClamped) + ReportException(iException::Programmer, "CubicClampedSecondDerivatives()", + "This method is only valid for cspline-clamped interpolation type may not be used for " + + Name() + " interpolation", + _FILEINFO_); + if (!p_clampedComputed) ComputeCubicClamped(); + return p_clampedSecondDerivs; + } + catch (iException e) { // catch exception from ComputeCubicClamped() + throw iException::Message(e.Type(), + "CubicClampedSecondDerivatives() - Unable to compute clamped cubic spline interpolation", + _FILEINFO_); + } + } + + /** + * @brief Input data domain minimum value + * + * This method validates the data set for the assigned + * interpolation type and returns the smallest value in + * @a p_x of the data set. + * + * @return @b double Minimum domain value + * @throws Isis::iException::Programmer "Unable to calculate the + * domain maximum for the data set." + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Modified to allow for + * interpolation types other than those supported by + * GSL. + * + */ + double NumericalApproximation::DomainMinimum() { + try{ + if (GslInterpType(p_itype)){ + // if GSL interpolation type, we need to compute, if not already done + if (!GslComputed()) ComputeGsl(); + return (p_interp->interp->xmin); + } + else{ + if (!p_dataValidated) ValidateDataSet(); + return *min_element(p_x.begin(),p_x.end()); + } + } + catch(iException e) { // catch exception from ComputeGsl() or ValidateDataSet() + throw iException::Message(e.Type(), + "DomainMinimum() - Unable to calculate the domain minimum for the data set", + _FILEINFO_); + } + } + + /** + * @brief Input data domain maximum value + * + * This method validates the data set for the assigned + * interpolation type and returns the largest value in + * @a p_x of the data set. + * + * @return @b double Maximum domain value + * @throws Isis::iException::Programmer "Unable to calculate the + * domain minimum for the data set." + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Modified to allow for + * interpolation types other than those supported by + * GSL. + */ + double NumericalApproximation::DomainMaximum() { + try{ + if (GslInterpType(p_itype)){ + // if GSL interpolation type, we need to compute, if not already done + if (!GslComputed()) ComputeGsl(); + return (p_interp->interp->xmax); + } + else{ + if (!p_dataValidated) ValidateDataSet(); + return *max_element(p_x.begin(),p_x.end()); + } + } + catch(iException e) { // catch exception from ComputeGsl() or ValidateDataSet() + throw iException::Message(e.Type(), + "DomainMaximum() - Unable to calculate the domain maximum for the data set", + _FILEINFO_); + } + } + + /** + * Returns whether the passed value is an element of the set of + * x-values in the data set. This method uses a binary search of + * the set of x-values to determine whether the input is + * contained in this set. + * + * @param x Value to search for in the data set. + * @return @b bool Whether the passed value is contained in the + * x-values of the data set. + * @internal + * @history 2009-06-19 Jeannie Walldren - Original version. + * + */ + bool NumericalApproximation::Contains(double x){ + return binary_search(p_x.begin(),p_x.end(),x); + } + + /** + *@brief Calculates interpolated or extrapolated value of + * tabulated data set for given domain value. + * + * This method returns the approximate value for @e f(@a a), + * where @a a is an element near the domain and @e f is the + * approximated function for the given data set. If the + * given value, @a a, falls outside of the domain, then the + * extrapoltion type is examined to determine the result. + * @a CubicNeighborhood and GSL interpolation types can not + * extrapolate, so the user must choose to throw an error or + * return @e f evaluated at the nearest domain boundary. + * @a CubicClamped, @a CubicHermite, and @a PolynomialNeville + * interpolation types can extrapolate a value with accuracy + * only if @a a is near enough to the domain boundary. Default + * NumericalApproximation::ExtrapType is @a ThrowError. + * + * @param a Domain value from which to interpolate a + * corresponding range value + * @param etype NumericalApproximation::ExtrapType enum + * value indicates how to evaluate if @a a + * falls outside of the domain. (Default: + * @a ThrowError) + * @return @b double Range value interpolated or extrapolated + * for the given domain value + * @throws Isis::iException::Programmer "Unable to evaluate the + * function at the point a" + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Modified to allow for + * interpolation types other than those supported by + * GSL. + * @history 2008-12-18 Jeannie Walldren - Added address + * operator (&) to input variables of type + * NumericalApproximation::ExtrapType. + * @history 2009-06-10 Jeannie Walldren - Added functionality + * for CubicHermite evaluation. + */ + double NumericalApproximation::Evaluate(const double a, const ExtrapType &etype) throw (iException &) { + try{ + // a is const, so we must set up temporary variable in case value needs to be changed + double a0; + if (InsideDomain(a)) // this will validate data set, if not already done + a0 = a; + else a0 = ValueToExtrapolate(a,etype); + // perform interpolation/extrapoltion + if (p_itype == NumericalApproximation::CubicNeighborhood) { + return EvaluateCubicNeighborhood(a0); + } + else if (p_itype == NumericalApproximation::PolynomialNeville) { + p_polyNevError.clear(); + return EvaluatePolynomialNeville(a0); + } + else if (p_itype == NumericalApproximation::CubicClamped) { + // if cubic clamped, we need to compute, if not already done + if (!p_clampedComputed) ComputeCubicClamped(); + return EvaluateCubicClamped(a0); + } + else if (p_itype == NumericalApproximation::CubicHermite) { + return EvaluateCubicHermite(a0); + } + // if GSL interpolation type we need to compute, if not already done + if (!GslComputed()) ComputeGsl(); + double result; + GslIntegrityCheck(gsl_spline_eval_e(p_interp, a0, p_acc, &result), _FILEINFO_); + return (result); + } + catch (iException e){ // catch exception from EvaluateCubicNeighborhood(), EvaluateCubicClamped(), EvaluatePolynomialNeville(), GslIntegrityCheck() + throw iException::Message(e.Type(), + "Evaluate() - Unable to evaluate the function at the point a = " + + iString(a), + _FILEINFO_); + } + } + + /** + *@brief Calculates interpolated value for given set of domain + * values + * + * This method returns the approximate values for + * @e f(@a ai), where @a ai is an + * element in the domain and @e f is the interpolated function + * for the given data set. If any of the given + * values in @a a fall outside of the domain, then the + * extrapoltion type is examined to determine the result. + * @a CubicNeighborhood and GSL interpolation types can not + * extrapolate, so the user must choose to throw an error or + * return f evaluated at the nearest domain boundary. + * @a CubicClamped and @a PolynomialNeville interpolation types + * can extrapolate a value with accuracy only if + * @a a@a i is near enough to the domain boundary. + * + * + * @param a Vector of domain values from which to + * interpolate a vector of corresponding + * range values + * @param etype NumericalApproximation::ExtrapType enum value + * indicates how to evaluate any + * value of @a a that falls outside of the + * domain. (Default: @a ThrowError) + * @return @b vector @b \ Set of interpolated range + * values corresponding to the elements of the vector of + * domain values given + * @throws Isis::iException::Programmer "Unable to evaluate the + * function at the vector of points, a." + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + * @history 2008-12-18 Jeannie Walldren - Added address + * operator (&) to input variables of type vector and + * NumericalApproximation::ExtrapType. + * @history 2009-06-10 Jeannie Walldren - Added functionality + * for CubicHermite evaluation. + */ + vector NumericalApproximation::Evaluate(const vector &a, const ExtrapType &etype) throw (iException &) { + try{ + if (p_itype == NumericalApproximation::CubicNeighborhood) { + // cubic neighborhood has it's own method that will take entire vector + // this is faster than looping through values calling Evaluate(double) + // for each component of the passed in vector + return EvaluateCubicNeighborhood(a,etype); + } + vector result(a.size()); + if(p_itype == NumericalApproximation::PolynomialNeville) { + // cannot loop through values calling Evaluate(double) + // because it will clear the p_polyNevError vector each time + p_polyNevError.clear(); + for (unsigned int i = 0; i < result.size(); i++) { + double a0; + if (InsideDomain(a[i])) + a0 = a[i]; + else a0 = ValueToExtrapolate(a[i],etype); + result[i] = EvaluatePolynomialNeville(a0); + } + return result; + } + // cubic-clamped, cubic-Hermite and gsl types can be done by calling Evaluate(double) + // for each value of the passed in vector + for (unsigned int i = 0; i < result.size(); i++) { + result[i] = Evaluate(a[i],etype); + } + return result; + } + catch (iException e){ // catch exception from EvaluateCubicNeighborhood(), EvaluateCubicClamped(), EvaluatePolynomialNeville(), GslIntegrityCheck() + throw iException::Message(e.Type(), + "Evaluate() - Unable to evaluate the function at the given vector of points", + _FILEINFO_); + } + } + + /** + * Retrieves the error estimate for the Neville's polynomial + * interpolation type. This method must be called after the + * Evaluate() method has been invoked. If the Evaluate() method + * is passed a vector, this error will contain an error estimate + * for each of the values of the passed in vector. Otherwise, it + * will contain a single value. + * + * @return @b vector @b \ Estimation of difference + * between actual value of + * @e f(a) and the polynomial Neville interpolated + * return value of Evaluate(), where @e f is the function + * that defines the given data set. + * @throws Isis::iException::Programmer "Method only used for + * polynomial-Neville's interpolation type" + * @throws Isis::iException::Programmer "Error not calculated" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + * written to save off the error estimate found by + * EvaluatePolynomialNeville() + */ + vector NumericalApproximation::PolynomialNevilleErrorEstimate() throw (iException &){ + if (p_itype != NumericalApproximation::PolynomialNeville) { + ReportException(iException::Programmer, "PolynomialNevilleErrorEstimate()", + "This method is only valid for polynomial-Neville's, may not be used for " + + Name() + " interpolation", + _FILEINFO_); + } + if (p_polyNevError.empty()) { + ReportException(iException::Programmer, "PolynomialNevilleErrorEstimate()", + "Error not calculated. This method only valid after Evaluate() has been called", + _FILEINFO_); + } + return p_polyNevError; + } + + /** + * @brief Approximates the first derivative of the data set + * function evaluated at the given domain value for GSL + * supported interpolation types. + * + * This method returns an approximation of the first derivative + * evaluated at given a valid domain value, @a a. It + * is a wrapper for the GSL subroutine + * gsl_spline_eval_deriv_e(). If the + * NumericalApproximation::InterpType is not a GSL type, then + * this method throws an error. No documentation was found + * concerning the algorithm used by this method. + * + * @param a Domain value at which first deriviative is + * evaluated. + * @return @b double First derivative approximation for the + * given domain value, if valid. + * @throws Isis::iException::Programmer "Invalid argument. Value + * entered is outside of domain." + * @throws Isis::iException::Programmer "Cannot use this method + * for interpolation type" (If the interpolation + * type is not GSL) + * @throws Isis::iException::Programmer "Unable to compute the + * first derivative at a using the GSL + * interpolation" + * @throws Isis::iException::Programmer "Unable to compute the + * first derivative at a. GSL integrity check + * failed" + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. Original name firstDerivative(). + * @history 2008-11-05 Jeannie Walldren - Modified to throw + * errors if passed value is out of domain or if + * interpolation type is not supported by GSL. + */ + double NumericalApproximation::GslFirstDerivative(const double a) throw (iException &) { + try{ // we need to compute, if not already done + if (!GslComputed()) ComputeGsl(); + } + catch (iException e){ // catch exception from ComputeGsl() + throw iException::Message(e.Type(), + "GslFirstDerivative() - Unable to compute the first derivative at a = " + + iString(a) + " using the GSL interpolation", + _FILEINFO_); + } + if(!InsideDomain(a)) { + ReportException(iException::Programmer,"GslFirstDerivative()", + "Invalid argument. Value entered, a = " + + iString(a) + ", is outside of domain = [" + + iString(DomainMinimum()) + ", " + + iString(DomainMaximum()) + "]", + _FILEINFO_); + } + if (!GslInterpType(p_itype)) { + ReportException(iException::Programmer,"GslFirstDerivative()", + "Method only valid for GSL interpolation types, may not be used for " + + Name() + " interpolation", + _FILEINFO_); + } + try{ + double value; + GslIntegrityCheck(gsl_spline_eval_deriv_e(p_interp, a, p_acc, &value), _FILEINFO_); + return (value); + } + catch (iException e){ // catch exception from GslIntegrityCheck() + throw iException::Message(e.Type(), + "GslFirstDerivative() - Unable to compute the first derivative at a = " + + iString(a) + ". GSL integrity check failed", + _FILEINFO_); + } + } + + /** + * @brief Approximates the first derivative of the data set + * function evaluated at the given domain value for + * @a CubicHermite interpolation type. + * + * This method returns an approximation of the first derivative + * evaluated at given a valid domain value, @a a. It is able to + * extrapolate for values not far outside of the domain + * + * @internal + * @history 2009-07-30 Debbie Cook - Original Version + */ + double NumericalApproximation::EvaluateCubicHermiteFirstDeriv(const double a){ + if (p_itype != NumericalApproximation::CubicHermite) {//??? is this necessary??? create single derivative method with GSL? + ReportException(iException::User,"EvaluateCubicHermiteFirstDeriv()", + "This method is only valid for cspline-Hermite interpolation, may not be used for " + + Name() + " interpolation", + _FILEINFO_); + } + if (p_fprimeOfx.size() != Size()) { + ReportException(iException::User,"EvaluateCubicHermiteFirstDeriv()", + "Invalid arguments. The size of the first derivative vector does not match the number of (x,y) data points.", + _FILEINFO_); + } + // find the interval in which "a" exists + int lowerIndex = FindIntervalLowerIndex(a); + + // we know that "a" is within the domain since this is verified in + // Evaluate() before this method is called, thus n <= Size() + if (a == p_x[lowerIndex]) { + return p_fprimeOfx[lowerIndex]; + } + if (a == p_x[lowerIndex+1]) { + return p_fprimeOfx[lowerIndex+1]; + } + + double x0, x1, y0, y1, m0, m1; + // a is contained within the interval (x0,x1) + x0 = p_x[lowerIndex]; + x1 = p_x[lowerIndex+1]; + // the corresponding known y-values for x0 and x1 + y0 = p_y[lowerIndex]; + y1 = p_y[lowerIndex+1]; + // the corresponding known tangents (slopes) at (x0,y0) and (x1,y1) + m0 = p_fprimeOfx[lowerIndex]; + m1 = p_fprimeOfx[lowerIndex+1]; + + double h, t; + h = x1-x0; + t = (a - x0)/h; + if (h != 0.) { + return ( (6*t*t-6*t)*y0 + (3*t*t-4*t+1)*h*m0 + (-6*t*t+6*t)*y1 + (3*t*t-2*t)*h*m1 ) / h; + } + else { + return 0; // Should never happen + } + } + + /** + * @brief Uses an @a n point backward first + * difference formula to approximate the first derivative + * evaluated at a given domain value. + * + * This method uses backward first difference formulas to return + * an approximation of the first derivative of the interpolated + * data set function evaluated at given a valid domain value, + * @a a. Backward difference formulas use + * @a n points, with the largest @e x value at + * @a a, for numerical differentiation approximation. + * This method uses one of the following formulas: + *
      + *
    • 2-point backward difference. + * @f[ + * f\prime(a) \approx \frac{1}{h}[f(a) - f(a - h)] + * @f] + *
    • 3-point backward difference. + * @f[ + * f\prime(a) \approx \frac{1}{2h}[3f(a) - 4f(a - h) + + * f(a - 2h)] + * @f] + *
    + * + * @param a Domain value at which first deriviative is + * evaluated. + * @param n The number of points used in the formula + * @param h Distance between nearest points in the formula + * @return @b double First derivative approximation for the + * given domain value + * @throws Isis::iException::Programmer "Invalid argument. Value + * entered is outside of domain." + * @throws Isis::iException::Programmer "Formula steps outside + * of domain." If a-(n-1)h is less than domain min. + * @throws Isis::iException::Programmer "Invalid argument. There + * is no n-point backward difference formula in + * use." + * @throws Isis::iException::Programmer "Unable to calculate + * backward first difference for given (a,n,h)" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + double NumericalApproximation::BackwardFirstDifference(const double a, const unsigned int n, const double h) throw (iException &) { + if(!InsideDomain(a)) { + ReportException(iException::Programmer,"BackwardFirstDifference()", + "Invalid argument. Value entered, a = " + + iString(a) + ", is outside of domain = [" + + iString(DomainMinimum()) + ", " + + iString(DomainMaximum()) + "]", + _FILEINFO_); + } + if(!InsideDomain(a - (n-1)*h)) { + ReportException(iException::Programmer, "BackwardFirstDifference()", + "Formula steps outside of domain. For " + + iString((int) n) + "-point backward difference, a-(n-1)h = " + + iString(a-(n-1)*h) + " is smaller than domain min = " + + iString(DomainMinimum()) + + ". Try forward difference or use smaller value for h or n", + _FILEINFO_); + } + if (!p_dataValidated) ValidateDataSet(); + vector f; + double xi; + try{ + for(double i = 0; i < n; i++) { + xi = a + h*(i-(n-1)); + f.push_back(Evaluate(xi)); // allow ExtrapType = ThrowError (default) + } + } + catch (iException e){ // catch exception from Evaluate() + throw iException::Message(e.Type(), + "BackwardFirstDifference() - Unable to calculate backward first difference for (a, n, h) = (" + + iString(a) + ", " + iString((int) n) + ", " + iString(h) + ")", + _FILEINFO_); + } + switch (n){ + case 2: return (-f[0] + f[1])/h; //2pt backward + case 3: return ( 3*f[2] - 4*f[1] + f[0])/(2*h); //3pt backward + default: throw iException::Message(iException::Programmer, + "BackwardFirstDifference() - Invalid argument. There is no " + + iString((int) n) + "-point backward difference formula in use", + _FILEINFO_); + } + } + + + /** + * @brief Uses an @a n point forward first difference + * formula to approximate the first derivative evaluated + * at a given domain value. + * This method uses forward first difference formulas to return + * an approximation of the first derivative of the interpolated + * data set function evaluated at given a valid domain value, + * @a a. Forward difference formulas use + * @a n points, with the smallest @e x value at + * @a a, for numerical differentiation approximation. + * This method uses one of the following formulas: + *
      + *
    • 2-point forward difference. + * @f[ + * f\prime(a) \approx \frac{1}{h}[f(a + h) - f(a)] + * @f] + *
    • 3-point forward difference. + * @f[ + * f\prime(a) \approx \frac{1}{2h}[-f(a + 2h) + + * 4f(a + h) - 3f(a)] + * @f] + *
    + * + * @param a Domain value at which first deriviative is + * evaluated. + * @param n The number of points used in the formula. + * @param h Distance between nearest points in the formula. + * @return @b double First derivative approximation for the + * given domain value + * @throws Isis::iException::Programmer "Invalid argument. Value + * entered is outside of domain." + * @throws Isis::iException::Programmer "Formula steps outside + * of domain." If a+(n-1)h is greater than domain + * max. + * @throws Isis::iException::Programmer "Invalid argument. There + * is no n-point forward difference formula in use." + * @throws Isis::iException::Programmer "Unable to calculate + * forward first difference for (a,n,h)" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + double NumericalApproximation::ForwardFirstDifference(const double a, const unsigned int n, const double h) throw (iException &) { + if(!InsideDomain(a)) { + ReportException(iException::Programmer,"ForwardFirstDifference()", + "Invalid argument. Value entered, a = " + + iString(a) + ", is outside of domain = [" + + iString(DomainMinimum()) + ", " + + iString(DomainMaximum()) + "]", + _FILEINFO_); + } + if(!InsideDomain(a + (n-1)*h)) { + ReportException(iException::Programmer,"ForwardFirstDifference()", + "Formula steps outside of domain. For " + + iString((int) n) + "-point forward difference, a+(n-1)h = " + + iString(a+(n-1)*h) + " is greater than domain max = " + + iString(DomainMaximum()) + + ". Try backward difference or use smaller value for h or n", + _FILEINFO_); + } + if (!p_dataValidated) ValidateDataSet(); + vector f; + double xi; + try{ + for(double i = 0; i < n; i++) { + xi = a + h*i; + f.push_back(Evaluate(xi));// allow ExtrapType = ThrowError (default) + } + } + catch (iException e){ // catch exception from Evaluate() + throw iException::Message(e.Type(), + "ForwardFirstDifference() - Unable to calculate forward first difference for (a, n, h) = (" + + iString(a) + ", " + iString((int) n) + ", " + iString(h) + ")", + _FILEINFO_); + } + switch (n){ + case 2: return (-f[0] + f[1])/h; //2pt forward + case 3: return (-3*f[0] + 4*f[1] - f[2])/(2*h); //3pt forward + default: throw iException::Message(iException::Programmer, + "ForwardFirstDifference() - Invalid argument. There is no " + + iString((int) n) + "-point forward difference formula in use", + _FILEINFO_); + } + } + + + /** + * @brief Uses an @a n point center first difference + * formula to approximate the first derivative evaluated + * at a given domain value. + * This method uses center first difference formulas to return + * an approximation of the first derivative of the interpolated + * data set function evaluated at given a valid domain value, + * @a a. Center difference formulas use + * @a n points, centered at @a a, for + * numerical differentiation approximation. This method uses one + * of the following formulas: + *
      + *
    • 3-point center difference. + * @f[ + * f\prime(a) \approx \frac{1}{2h}[f(a + h) - + * f(a - h)] + * @f] + *
    • 5-point center difference. + * @f[ + * f\prime(a) \approx \frac{1}{12h}[-f(a + 2h) + + * 8f(a +h) - 8f(a - h) + f(a - 2h)] + * @f] + *
    + * + * @param a Domain value at which first deriviative is + * evaluated. + * @param n The number of points used in the formula. + * @param h Distance between nearest points in the formula. + * @return @b double First derivative approximation for the + * given domain value + * @throws Isis::iException::Programmer "Invalid argument. Value + * entered is outside of domain." + * @throws Isis::iException::Programmer "Formula steps outside + * of domain." If a+(n-1)h is greater than domain + * max or a-(n-1)h is less than domain min. + * @throws Isis::iException::Programmer "Invalid argument. There + * is no n-point center difference formula in use." + * @throws Isis::iException::Programmer "Unable to calculate + * center first difference for (a,n,h)" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + double NumericalApproximation::CenterFirstDifference(const double a, const unsigned int n, const double h) throw (iException &) { + if(!InsideDomain(a)) { + ReportException(iException::Programmer,"CenterFirstDifference()", + "Invalid argument. Value entered, a = " + + iString(a) + ", is outside of domain = [" + + iString(DomainMinimum()) + ", " + + iString(DomainMaximum()) + "]", + _FILEINFO_); + } + if(!InsideDomain(a + (n-1)*h) || !InsideDomain(a - (n-1)*h)) { + ReportException(iException::Programmer,"CenterFirstDifference()", + "Formula steps outside of domain. For " + + iString((int) n) + "-point center difference, a-(n-1)h = " + + iString(a-(n-1)*h) + " or a+(n-1)h = " + + iString(a+(n-1)*h) + " is out of domain = [" + + iString(DomainMinimum()) + ", " + iString(DomainMaximum()) + + "]. Use smaller value for h or n", + _FILEINFO_); + } + if (!p_dataValidated) ValidateDataSet(); + vector f; + double xi; + try{ + for(double i = 0; i < n; i++) { + xi = a + h*(i-(n-1)/2); + f.push_back(Evaluate(xi));// allow ExtrapType = ThrowError (default) + } + } + catch (iException e){ // catch exception from Evaluate() + throw iException::Message(e.Type(), + "CenterFirstDifference() - Unable to calculate center first difference for (a, n, h) = (" + + iString(a) + ", " + iString((int) n) + ", " + iString(h) + ")", + _FILEINFO_); + } + switch (n){ + case 3: return (-f[0] + f[2])/(2*h); //3pt center + case 5: return (f[0] - 8*f[1] + 8*f[3] - f[4])/(12*h);//5pt center + default: throw iException::Message(iException::Programmer, + "CenterFirstDifference() - Invalid argument. There is no " + + iString((int) n) + "-point center difference formula in use", + _FILEINFO_); + } + } + + /** + * @brief Approximates the second derivative of the + * interpolated data set function evaluated at the given domain value + * for GSL supported interpolation types. + * + * This method returns an approximation of the second derivative + * evaluated at given a valid domain value, @a a. It + * is a wrapper for the GSL subroutine + * gsl_spline_eval_deriv2_e(). If the + * NumericalApproximation::InterpType is not a GSL type, then + * this method throws an error. No documentation was found + * concerning the algorithm used by this method. + * + * + * @param a Domain value at which second deriviative is + * evaluated. + * @return @b double Second derivative approximation for the + * given domain value, if valid. + * @throws Isis::iException::Programmer "Invalid argument. Value + * entered is outside of domain." + * @throws Isis::iException::Programmer "Cannot use this method + * for interpolation type" (If the interpolation + * type is not GSL) + * @throws Isis::iException::Programmer "Unable to compute the + * second derivative at a using GSL interpolation" + * @throws Isis::iException::Programmer "Unable to compute the + * second derivative at a. GSL integrity check + * failed" + * @internal + * @history 2006-06-14 Kris Becker - Original version created + * in DataInterp class. Original name + * secondDerivative(). + * @history 2008-11-05 Jeannie Walldren - Modified to throw + * errors if passed value is out of domain or if + * interpolation type is not supported by GSL. + */ + double NumericalApproximation::GslSecondDerivative(const double a) throw (iException &) { + try{ // we need to compute, if not already done + if (!GslComputed()) ComputeGsl(); + } + catch (iException e){ // catch exception from ComputeGsl() + throw iException::Message(e.Type(), + "GslSecondDerivative() - Unable to compute the second derivative at a = " + + iString(a) + " using the GSL interpolation", + _FILEINFO_); + } + if(!InsideDomain(a)) + ReportException(iException::Programmer,"GslSecondDerivative()", + "Invalid argument. Value entered, a = " + + iString(a) + ", is outside of domain = [" + + iString(DomainMinimum()) + ", " + + iString(DomainMaximum()) + "]", + _FILEINFO_); + if (!GslInterpType(p_itype)) + ReportException(iException::Programmer,"GslSecondDerivative()", + "Method only valid for GSL interpolation types, may not be used for " + + Name() + " interpolation", + _FILEINFO_); + try{ + // we need to compute, if not already done + if(!GslComputed()) ComputeGsl(); + double value; + GslIntegrityCheck(gsl_spline_eval_deriv2_e(p_interp, a, p_acc, &value), _FILEINFO_); + return (value); + } + catch (iException e){ // catch exception from GslIntegrityCheck() + throw iException::Message(e.Type(), + "GslSecondDerivative() - Unable to compute the second derivative at a = " + + iString(a) + ". GSL integrity check failed", + _FILEINFO_); + } + } + + + /** + * @brief Approximates the second derivative of the data set + * function evaluated at the given domain value for + * @a CubicHermite interpolation type. + * + * This method returns an approximation of the second derivative + * evaluated at given a valid domain value, @a a. It is able to + * extrapolate for values not far outside of the domain + * + * @internal + * @history 2009-07-30 Debbie Cook - Original Version + */ + double NumericalApproximation::EvaluateCubicHermiteSecDeriv(const double a){ + if (p_itype != NumericalApproximation::CubicHermite) { + ReportException(iException::User,"EvaluateCubicHermiteSecDeriv()", + "This method is only valid for cspline-Hermite interpolation, may not be used for " + + Name() + " interpolation", + _FILEINFO_); + } + if (p_fprimeOfx.size() != Size()) { + ReportException(iException::User,"EvaluateCubicHermiteSecDeriv()", + "Invalid arguments. The size of the first derivative vector does not match the number of (x,y) data points.", + _FILEINFO_); + } + // find the interval in which "a" exists + int lowerIndex = FindIntervalLowerIndex(a); + double x0, x1, y0, y1, m0, m1; + // a is contained within the interval (x0,x1) + x0 = p_x[lowerIndex]; + x1 = p_x[lowerIndex+1]; + // the corresponding known y-values for x0 and x1 + y0 = p_y[lowerIndex]; + y1 = p_y[lowerIndex+1]; + // the corresponding known tangents (slopes) at (x0,y0) and (x1,y1) + m0 = p_fprimeOfx[lowerIndex]; + m1 = p_fprimeOfx[lowerIndex+1]; + + double h, t; + h = x1-x0; + t = (a - x0)/h; + if (h != 0.) { + return ( (12*t-6)*y0 + (6*t-4)*h*m0 + (-12*t+6)*y1 + (6*t-2)*h*m1 ) / h; + } + else { + return 0; // Should never happen + } + } + + /** + * @brief Uses an @a n point backward second difference + * formula to approximate the second derivative evaluated + * at a given domain value. + * This method uses backward second difference formulas to + * return an approximation of the second derivative of the + * interpolated data set function evaluated at given a + * valid domain value, @a a. Backward second + * difference formulas use @a n points, with the + * largest @e x value at @a a, for numerical differentiation + * approximation. This method uses the following formula: + *
      + *
    • 3-point backward second difference. + * @f[ + * f\prime\prime(a) \approx \frac{1}{h^2}[f(a) + * - 2f(a - h) + f(a - 2h)] + * @f] + *
    + * + * @param a Domain value at which second deriviative is + * evaluated. + * @param n The number of points used in the formula. + * @param h Distance between nearest points in the formula. + * @return @b double Second derivative approximation for the + * given domain value + * @throws Isis::iException::Programmer "Invalid argument. Value + * entered is outside of domain." + * @throws Isis::iException::Programmer "Formula steps outside + * of domain." If a-(n-1)h is less than domain min. + * @throws Isis::iException::Programmer "Invalid argument. There + * is no n-point backward difference formula in + * use." + * @throws Isis::iException::Programmer + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + double NumericalApproximation::BackwardSecondDifference(const double a, const unsigned int n, const double h) throw (iException &) { + if(!InsideDomain(a)) { + ReportException(iException::Programmer,"BackwardSecondDifference()", + "Invalid argument. Value entered, a = " + + iString(a) + ", is outside of domain = [" + + iString(DomainMinimum()) + ", " + + iString(DomainMaximum()) + "]", + _FILEINFO_); + } + if(!InsideDomain(a - (n-1)*h)) { + ReportException(iException::Programmer,"BackwardSecondDifference()", + "Formula steps outside of domain. For " + + iString((int) n) + "-point backward difference, a-(n-1)h = " + + iString(a-(n-1)*h) + " is smaller than domain min = " + + iString(DomainMinimum()) + + ". Try forward difference or use smaller value for h or n", + _FILEINFO_); + } + if (!p_dataValidated) ValidateDataSet(); + vector f; + double xi; + try{ + for(double i = 0; i < n; i++) { + xi = a + h*(i-(n-1)); + f.push_back(Evaluate(xi));// allow ExtrapType = ThrowError (default) + } + } + catch (iException e){ // catch exception from Evaluate() + throw iException::Message(e.Type(), + "BackwardSecondDifference() - Unable to calculate backward second difference for (a, n, h) = (" + + iString(a) + ", " + iString((int) n) + ", " + iString(h) + ")", + _FILEINFO_); + } + switch (n){ + case 3: return (f[0] - 2*f[1] + f[2])/(h*h); //3pt backward + default: throw iException::Message(iException::Programmer, + "BackwardSecondDifference() - Invalid argument. There is no " + + iString((int) n) + "-point backward second difference formula in use", + _FILEINFO_); + } + } + + + /** + * @brief Uses an @a n point forward second difference + * formula to approximate the second derivative evaluated at a + * given domain value. + * This method uses forward second difference formulas to return + * an approximation of the second derivative of the interpolated + * data set function evaluated at given a valid domain value, + * @a a. Forward second difference formulas use + * @a n points, with the smallest @e x value at + * @a a, for numerical differentiation approximation. + * This method uses the following formula: + *
      + *
    • 3-point forward second difference. + * @f[ + * f\prime\prime(a) \approx \frac{1}{h^2}[f(a + + * 2h) - 2f(a + h) + f(a)] + * @f] + *
    + * + * @param a Domain value at which second deriviative is evaluated. + * @param n The number of points used in the formula. + * @param h Distance between nearest points in the formula. + * @return @b double Second derivative approximation for the + * given domain value + * @throws Isis::iException::Programmer "Invalid argument. Value + * entered is outside of domain." + * @throws Isis::iException::Programmer "Formula steps outside + * of domain." If a+(n-1)h is greater than domain + * max. + * @throws Isis::iException::Programmer "Invalid argument. There + * is no n-point forward difference formula in use." + * @throws Isis::iException::Programmer "Unable to calculate + * forward second difference for (a,n,h)" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + double NumericalApproximation::ForwardSecondDifference(const double a, const unsigned int n, const double h) throw (iException &) { + if(!InsideDomain(a)) { + ReportException(iException::Programmer,"ForwardSecondDifference()", + "Invalid argument. Value entered, a = " + + iString(a) + ", is outside of domain = [" + + iString(DomainMinimum()) + ", " + + iString(DomainMaximum()) + "]", + _FILEINFO_); + } + if(!InsideDomain(a + (n-1)*h)) { + ReportException(iException::Programmer,"ForwardSecondDifference()", + "Formula steps outside of domain. For " + + iString((int) n) + "-point forward difference, a+(n-1)h = " + + iString(a+(n-1)*h) + " is greater than domain max = " + + iString(DomainMaximum()) + + ". Try backward difference or use smaller value for h or n", + _FILEINFO_); + } + if (!p_dataValidated) ValidateDataSet(); + vector f; + double xi; + try{ + for(double i = 0; i < n; i++) { + xi = a + h*i; + f.push_back(Evaluate(xi));// allow ExtrapType = ThrowError (default) + } + } + catch (iException e){ // catch exception from Evaluate() + throw iException::Message(e.Type(), + "ForwardSecondDifference() - Unable to calculate forward second difference for (a, n, h) = (" + + iString(a) + ", " + iString((int) n) + ", " + iString(h) + ")", + _FILEINFO_); + } + switch (n){ + case 3: return (f[0] - 2*f[1] + f[2])/(h*h); //3pt forward + default: throw iException::Message(iException::Programmer, + "ForwardSecondDifference() - Invalid argument. There is no " + + iString((int) n) + "-point forward second difference formula in use", + _FILEINFO_); + } + } + + + /** + * @brief Uses an @a n point center second difference + * formula to approximate the second derivative evaluated at a + * given domain value. + * This method uses center second difference formulas to return + * an approximation of the second derivative of the interpolated + * data set function evaluated at given a valid domain value, + * @a a. Center second difference formulas use + * @a n points, centered at @a a, for + * numerical differentiation approximation. This method uses one + * of the following formulas: + *
      + *
    • 3-point center second difference. + * @f[ + * f\prime\prime(a) \approx \frac{1}{h^2}[f(a + h) + * - 2f(a) + f(a - h)] + * @f] + *
    • 5-point center second difference. + * @f[ + * f\prime\prime(a) \approx \frac{1}{12h^2}[-f(a + + * 2h) + 16f(a +h) - 30f(a) + 16f(a - h) - f(a + * - 2h)] + * @f] + *
    + * + * @param a Domain value at which second deriviative is evaluated. + * @param n The number of points used in the formula. + * @param h Distance between nearest points in the formula. + * @return @b double Second derivative approximation for the + * given domain value + * @throws Isis::iException::Programmer "Invalid argument. Value + * entered is outside of domain." + * @throws Isis::iException::Programmer "Formula steps outside + * of domain." If a+(n-1)h is greater than domain + * max or a-(n-1)h is less than domain min. + * @throws Isis::iException::Programmer "Invalid argument. There + * is no n-point center difference formula in use." + * @throws Isis::iException::Programmer "Unable to calculate + * center second difference for (a,n,h)" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + double NumericalApproximation::CenterSecondDifference(const double a, const unsigned int n, const double h) throw (iException &) { + if(!InsideDomain(a)) { + ReportException(iException::Programmer,"CenterSecondDifference()", + "Invalid argument. Value entered, a = " + + iString(a) + ", is outside of domain = [" + + iString(DomainMinimum()) + ", " + + iString(DomainMaximum()) + "]", + _FILEINFO_); + } + if(!InsideDomain(a + (n-1)*h) || !InsideDomain(a - (n-1)*h)) { + ReportException(iException::Programmer,"CenterSecondDifference()", + "Formula steps outside of domain. For " + + iString((int) n) + "-point center difference, a-(n-1)h = " + + iString(a-(n-1)*h) + " or a+(n-1)h = " + + iString(a+(n-1)*h) + " is out of domain = [" + + iString(DomainMinimum()) + ", " + iString(DomainMaximum()) + + "]. Use smaller value for h or n", + _FILEINFO_); + } + if (!p_dataValidated) ValidateDataSet(); + vector f; + double xi; + try{ + for(double i = 0; i < n; i++) { + xi = a + h*(i-(n-1)/2); + f.push_back(Evaluate(xi));// allow ExtrapType = ThrowError (default) + } + } + catch (iException e){ // catch exception from Evaluate() + throw iException::Message(e.Type(), + "CenterSecondDifference() - Unable to calculate center second difference for (a, n, h) = (" + + iString(a) + ", " + iString((int) n) + ", " + iString(h) + ")", + _FILEINFO_); + } + switch (n){ + case 3: return (f[0] - 2*f[1] + f[2])/(h*h); //3pt center + case 5: return (-f[0] + 16*f[1] - 30*f[2] + 16*f[3] - f[4])/(12*h*h);//5pt center + default: throw iException::Message(iException::Programmer, + "CenterSecondDifference() - Invalid argument. There is no " + + iString((int) n) + "-point center second difference formula in use", + _FILEINFO_); + } + } + + /** + * @brief Approximates the integral of the data set + * function evaluated on the given interval for GSL + * supported interpolation types. + * + * This method returns an approximation of the integral + * evaluated on a given valid domain interval, + * (@a a,@a b). It is a wrapper for the GSL subroutine + * gsl_spline_eval_integ_e(). If the + * NumericalApproximation::InterpType is not a GSL type, then + * this method throws an error. No documentation was found + * concerning the algorithm used by this method. + * + * @param a Lower endpoint at which integral is evaluated. + * @param b Upper endpoint at which integral is evaluated. + * @return @b double Integral approximation for the given + * interval, if valid. + * @throws Isis::iException::Programmer (When a > b) "Invalid + * interval entered" + * @throws Isis::iException::Programmer "Invalid arguments. + * Interval entered is not contained within domain" + * @throws Isis::iException::Programmer "Cannot use this method + * for interpolation type" (If the interpolation + * type is not GSL) + * @throws Isis::iException::Programmer "Unable to compute the + * integral on the interval (a,b) using GSL + * interpolation" + * @throws Isis::iException::Programmer "Unable to compute the + * integral on the interval (a,b). GSL integrity + * check failed." + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + double NumericalApproximation::GslIntegral(const double a, const double b) throw (iException &) { + try{ // we need to compute, if not already done + if (!GslComputed()) ComputeGsl(); + } + catch (iException e){ // catch exception from ComputeGsl() + throw iException::Message(e.Type(), + "GslIntegral() - Unable to compute the integral on the interval (a,b) = (" + + iString(a) + ", " + iString(b) + + ") using the GSL interpolation", + _FILEINFO_); + } + if (a > b) { + ReportException(iException::Programmer,"GslIntegral()", + "Invalid interval entered: [a,b] = [" + + iString(a) + ", " + iString(b) + "]", + _FILEINFO_); + } + if (!InsideDomain(a) || !InsideDomain(b)) { + ReportException(iException::Programmer,"GslIntegral()", + "Invalid arguments. Interval entered [" + + iString(a) + ", " + iString(b) + + "] is not contained within domain [" + + iString(DomainMinimum()) + ", " + + iString(DomainMaximum()) + "]", + _FILEINFO_); + } + if (!GslInterpType(p_itype)) { + ReportException(iException::Programmer,"GslIntegral()", + "Method only valid for GSL interpolation types, may not be used for " + + Name() + " interpolation", + _FILEINFO_); + } + try{ + double value; + GslIntegrityCheck(gsl_spline_eval_integ_e(p_interp, a, b, p_acc, &value), _FILEINFO_); + return (value); + } + catch (iException e){ // catch exception from GslIntegrityCheck() + throw iException::Message(e.Type(), + "GslIntegral() - Unable to compute the integral on the interval (a,b) = (" + + iString(a) + ", " + iString(b) + + "). GSL integrity check failed", + _FILEINFO_); + } + } + + /** + * @brief Uses the trapezoidal rule to approximate the + * integral of the interpolated data set function on the interval + * (@a a, @a b). + * The trapeziod rule for integration approximation uses a + * 2-point Newton-Cote formula. This rule states: + * @f[ + * \int_{a}^b f(x)dx \approx \frac{h}{2}[f(a) + f(b)] + * @f] + * where @e h = @a b - @a a. + * This method uses a composite, or extended, trapeziodal rule + * algorithm to approximate the integral. + * + * @param a Lower bound of interval. + * @param b Upper bound of interval. + * @return @b double Approximate integral of data set function + * from a to b. + * @throws Isis::iException::Programmer "Unable to calculate the + * integral on the interval (a,b) + * using the trapezoidal rule" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + double NumericalApproximation::TrapezoidalRule(const double a, const double b){ + try{ + //n is the number of points used in the formula of the integration type chosen + unsigned int n = 2; + double result = 0; + vector f = EvaluateForIntegration(a,b,n); + double h = f.back(); + f.pop_back(); + //Compute the integral using composite trapezoid formula + int ii; + for (unsigned int i = 0; i < (f.size()-1)/(n-1); i++ ) { + ii = (i+1)*(n-1); + result += (f[ii-1] + f[ii])*h/2; + } + return result; + } + catch (iException e){ // catch exception from EvaluateForIntegration() + throw iException::Message(e.Type(), + "TrapezoidalRule() - Unable to calculate the integral on the interval (a,b) = (" + + iString(a) + ", " + iString(b) + + ") using the trapeziodal rule", + _FILEINFO_); + } + } + + /** + * @brief Uses Simpson's 3-point rule to approximate the + * integral of the interpolated data set function on the interval + * (@a a,@a b). + * + * The Simpson's 3-Point Rule for numerical integration uses a + * 3-point Newton-Cote formula. This rule states: + * @f[ + * \int_{a}^b f(x)dx \approx \frac{h}{3}[f(a) + f(a+h) + * + 4*f(a+2h)] + * @f] + * where @e h = (@a b - @a a)/2. + * This method uses a composite, or extended, Simpson's rule + * algorithm to approximate the integral. + * + * + * @param a Lower bound of interval. + * @param b Upper bound of interval. + * @return @b double Approximate integral of data set function + * from a to b. + * @throws Isis::iException::Programmer "Unable to calculate the + * integral on the interval (a,b) + * using Simpson's 3 point rule" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + double NumericalApproximation::Simpsons3PointRule(const double a, const double b){ + try{ + //n is the number of points used in the formula of the integration type chosen + unsigned int n = 3; + double result = 0; + vector f = EvaluateForIntegration(a,b,n); + double h = f.back(); + f.pop_back(); + int ii; + for (unsigned int i = 0; i < (f.size()-1)/(n-1); i++ ) { + ii = (i+1)*(n-1); + result += (f[ii-2] + 4*f[ii-1] + f[ii])*h/3; + } + return result; + } + catch (iException e){ // catch exception from EvaluateForIntegration() + throw iException::Message(e.Type(), + "Simpsons3PointRule() - Unable to calculate the integral on the interval (a,b) = (" + + iString(a) + ", " + iString(b) + + ") using Simpson's 3 point rule", + _FILEINFO_); + } + } + + + /** + * @brief Uses Simpson's 4-point rule to approximate the + * integral of the interpolated data set function on the interval + * (@a a,@a b). + * + * The Simpson's 4-point Rule for numerical integration + * uses a 4-point Newton-Cote formula and is sometimes + * called the Simpson's 3/8 Rule. This rule states: + * @f[ + * \int_{a}^b f(x)dx \approx \frac{3h}{8}[f(a) + + * 3f(a+h) + 3f(a+2h) + f(a+3h)] + * @f] + * where @e h = (@a b - @a a)/3. + * This method uses a composite, or extended, Simpson's 3/8 rule + * algorithm to approximate the integral. + * + * @param a Lower bound of interval. + * @param b Upper bound of interval. + * @return @b double Approximate integral of data set function + * from a to b. + * @throws Isis::iException::Programmer "Unable to calculate the + * integral on the interval (a,b) + * using Simpson's 4 point rule" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + double NumericalApproximation::Simpsons4PointRule(const double a, const double b){ + try{ + //n is the number of points used in the formula of the integration type chosen + unsigned int n = 4; + double result = 0; + vector f = EvaluateForIntegration(a,b,n); + double h = f.back(); + f.pop_back(); + int ii; + for (unsigned int i = 0; i < (f.size()-1)/(n-1); i++ ) { + ii = (i+1)*(n-1); + result += (f[ii-3] + 3*f[ii-2] + 3*f[ii-1] + f[ii])*h*3/8; + } + return result; + } + catch (iException e){ // catch exception from EvaluateForIntegration() + throw iException::Message(e.Type(), + "Simpsons4PointRule() - Unable to calculate the integral on the interval (a,b) = (" + + iString(a) + ", " + iString(b) + + ") using Simpson's 4 point rule", + _FILEINFO_); + } + } + + + /** + * @brief Uses Boole's Rule to approximate the integral of + * the interpolated data set function on the interval (@a + * a,@a b). + * + * The Boole's Rule for integration approximation uses a 5-point + * Newton-Cote formula. This rule states: + * @f[ + * \int_{a}^b f(x)dx \approx \frac{2h}{45}[7f(a) + + * 32f(a+h) + 12f(a+2h) + 32f(a+3h) + 7f(a+4h)] + * @f] + * where @e h = (@a b - @a a)/4. + * + * This method uses a composite, or extended, Boole's rule + * formula to approximate the integral. + * + * @b Note: The method uses an algorithm that is adapted from + * the IDL function int_tabulated.pro. + * + * @param a Lower bound of interval. + * @param b Upper bound of interval. + * @return @b double Approximate integral of data set function + * from a to b. + * @throws Isis::iException::Programmer "Unable to calculate the + * integral on the interval (a,b) + * using Boole's rule" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + double NumericalApproximation::BoolesRule(const double a, const double b){ + try{ + //n is the number of points used in the formula of the integration type chosen + unsigned int n = 5; + double result = 0; + vector f = EvaluateForIntegration(a,b,n); + double h = f.back(); + f.pop_back(); + int ii; + for (unsigned int i = 0; i < (f.size()-1)/(n-1); i++ ) { + ii = (i+1)*(n-1); + result += (7*f[ii-4] + 32*f[ii-3] + 12*f[ii-2] + 32*f[ii-1] + 7*f[ii])*h*2/45; + } + return result; + } + catch (iException e){ // catch exception from EvaluateForIntegration() + throw iException::Message(e.Type(), + "BoolesRule() - Unable to calculate the integral on the interval (a,b) = (" + + iString(a) + ", " + iString(b) + + ") using Boole's rule", + _FILEINFO_); + } + } + + /** + * @brief Calculates refinements extended trapezoidal rule to + * approximate the integral of the interpolated + * data set function on the interval (@a a,@a b). + * + * This method calculates the @a nth stage of + * refinement of an extended trapezoidal rule. When called with + * @a n = 1, the method returns the non-composite + * trapezoidal estimate of the integral. Subsequent calls with + * @a n = 2, 3, ... (in sequential order) will improve the + * accuracy by adding 2@a n-2 additional interior + * points. This method can be used to integrate by the extended + * trapeziodal rule if you know the number of steps you want to + * take. For example, if you want 2@e M + 1, use + * the following code: + * @code + * double result; + * for(int j = 1; j <= M+1; j++){ + * result = RefineExtendedTrap(a,b,result,j); + * } + * @endcode + * @b Note: Although this method may be used to approximate + * an integral, as described above, it is most often used by + * RombergsMethod() to integrate. + * + * @param a Lower limit of integration + * @param b Upper limit of integration + * @param s Previous value of refinement + * @param n Number of partitions to use when integrating + * @return @b double Integral (refined) approximation of the + * function on the interval (a, b) + * @throws Isis::iException::Programmer "Unable to calculate the + * integral on the interval (a,b) + * using the extended trapezoidal + * rule" + * @see RombergsMethod() + * @internal + * @history 1999-08-11 K Teal Thompson - Original version in + * Isis2. + * @history 2007-02-20 Janet Barrett - Imported to Isis3 in AtmosModel class. Original name r8trapzd(). + * @history 2008-11-05 Jeannie Walldren - Renamed, modified + * input parameters, adapted to be used with data set. + * + */ + double NumericalApproximation::RefineExtendedTrap(double a, double b, double s, unsigned int n) throw (iException &){ + // This method was derived from an algorithm in the text + // Numerical Recipes in C: The Art of Scientific Computing + // Section 4.2 by Flannery, Press, Teukolsky, and Vetterling + try{ + if (n == 1) { + double begin, end; + if (GslInterpType(p_itype) || p_itype == NumericalApproximation::CubicNeighborhood) { + // if a or b are outside the domain, return y-value of nearest endpoint + begin = Evaluate(a,NumericalApproximation::NearestEndpoint); + end = Evaluate(b,NumericalApproximation::NearestEndpoint); + } + else { + // if a or b are outside the domain, return extrapolated y-value + begin = Evaluate(a,NumericalApproximation::Extrapolate); + end = Evaluate(b,NumericalApproximation::Extrapolate); + } + return (0.5 * (b - a) * (begin + end)); + } + else { + int it; + double delta,tnm,x,sum; + it = (int)(pow(2.0,(double)(n-2))); + tnm = it; + delta = (b - a) / tnm; // spacing of the points to be added + x = a + 0.5 * delta; + sum = 0.0; + for (int i=0; i= 4) { + interp.AddData(5, &h[i-4], &trap[i-4]); + // PolynomialNeville can extrapolate data outside of domain + ss = interp.Evaluate(0.0,NumericalApproximation::Extrapolate); + dss = interp.PolynomialNevilleErrorEstimate()[0]; + interp.Reset(); + // we work only until our necessary accuracy is achieved + if (fabs(dss) <= epsilon*fabs(ss)) return ss; + if (fabs(dss) <= epsilon2) return ss; + } + trap[i+1] = trap[i]; + h[i+1] = 0.25 * h[i]; + // This is a key step: the factor is 0.25d0 even though + // the stepsize is decreased by 0.5d0. This makes the + // extraplolation a polynomial in h-squared as allowed + // by the equation from Numerical Recipes 4.2.1 pg.132, + // not just a polynomial in h. + } + } + catch (iException e){ // catch error from RefineExtendedTrap, Constructor, Evaluate, PolynomialNevilleErrorEstimate + throw iException::Message(e.Type(), + "RombergsMethod() - Unable to calculate the integral on the interval (a,b) = (" + + iString(a) + ", " + iString(b) + + ") using Romberg's method", + _FILEINFO_); + } + throw iException::Message(iException::Programmer, + "RombergsMethod() - Unable to calculate the integral using RombergsMethod() - Failed to converge in " + + iString(maxits) + " iterations", + _FILEINFO_); + } + + /** + * @brief Resets the state of the object + * + * This method deallocates the internal state of the object and + * clears the data set and class variables. The object is + * returned to its original state, so data points must be + * entered before computing again. This does not clear or reset + * the interpolation type. + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Modified to reset class + * variables related to interpolation types not + * supported by GSL. + * @history 2009-06-10 Jeannie Walldren - Reset new variable, + * p_fprimeOfx. + */ + void NumericalApproximation::Reset() { + if (GslInterpType(p_itype)) GslDeallocation(); + p_clampedComputed = false; + p_clampedEndptsSet = false; + p_dataValidated = false; + p_x.clear(); + p_y.clear(); + p_clampedSecondDerivs.clear(); + p_clampedDerivFirstPt = 0; + p_clampedDerivLastPt = 0; + p_polyNevError.clear(); + p_fprimeOfx.clear(); + return; + } + + /** + * @brief Resets the state of the object and resets + * interpolation type. + * + * This method will clear the data set, reset the validation + * status of the data to false, reset the interpolation type, + * clear class variables and deallocate (inactivate) the + * internal state of the object. The object is returned to its + * original state, so data points must be entered before + * computing again. + * @param itype NumericalApproximation::InterpType enum value to be assigned to this + * object + * @throws Isis::iException::Programmer "Unable to reset + * interpolation type" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + void NumericalApproximation::Reset(NumericalApproximation::InterpType itype) throw (iException &){ + try{ + Reset(); + SetInterpType(itype); + return; + } + catch (iException e){ // catch exception from SetInterpType() + throw iException::Message(e.Type(), + "Reset() - Unable to reset interpolation type", + _FILEINFO_); + } + } + + /** + * @brief Sets interpolation type. + * This method will reset the interpolation type to that of the + * input parameter and deallocate memory. Unlike the + * Reset() method, this method does NOT discard the data set. However, since + * interpolations have differing requirements for valid data + * sets, the data set stored is not yet validated for the new + * interpolation type. Other class variables are cleared if + * they are interpolation type dependent. + * + * @param itype NumericalApproximation::InterpType enum value to be assigned to this + * object + * @throws Isis::iException::Programmer "Invalid argument. + * Unknown interpolation type" + * @throws Isis::iException::Programmer "Unable to set + * interpolation type" + * @see Reset() + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + * @history 2009-06-10 Jeannie Walldren - Reset new variable, + * p_fprimeOfx. + */ + void NumericalApproximation::SetInterpType(NumericalApproximation::InterpType itype) throw (iException &){ + // Validates the parameter + if (GslInterpType(itype)) { + try{ + GslFunctor(itype); + } + catch (iException e){ // catch exception from GslFunctor() + throw iException::Message(e.Type(), + "SetInterpType() - Unable to set interpolation type", + _FILEINFO_); + } + } else if (itype > 9) { // there are currently 9 interpolation types + ReportException(iException::Programmer,"SetInterpType()", + "Invalid argument. Unknown interpolation type: " + + iString(NumericalApproximation::InterpType(itype)), + _FILEINFO_); + } + // p_x, p_y are kept and p_itype is replaced + p_itype = itype; + // reset state of class variables that are InterpType dependent //??? should we keep some of this info? + p_dataValidated = false; + p_clampedComputed = false; + p_clampedEndptsSet = false; + p_clampedSecondDerivs.clear(); + p_clampedDerivFirstPt = 0; + p_clampedDerivLastPt = 0; + p_polyNevError.clear(); + p_fprimeOfx.clear(); + } + + /** + * @brief Initializes the object upon instantiation + * + * This method sets up the initial state of the object, typically at + * instantiation. It populates the interpolation function + * table identifying which options are available to the users of + * this class. + * + * GSL error handling is turned off - upon repeated instantiation of this + * object. The GSL default error handling, termination of the application via + * an abort() is unacceptable. This calls adopts an alternative policy provided + * by the GSL whereby error checking must be done by the calling environment. + * This has an unfortunate drawback in that it is not enforceable in an object + * oriented environment that utilizes the GSL in disjoint classes. + * @param itype NumericalApproximation::InterpType enum value to + * be assigned to this object + * @throws Isis::iException::Programmer "Unable to initialize + * NumericalApproximation object" + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. Original name initInterp(). + * @history 2008-11-05 Jeannie Walldren - Modified to allow for + * interpolation types not supported by GSL. + */ + void NumericalApproximation::Init(NumericalApproximation::InterpType itype) { + p_interpFunctors.insert(make_pair(Linear,gsl_interp_linear)); + p_interpFunctors.insert(make_pair(Polynomial,gsl_interp_polynomial)); + p_interpFunctors.insert(make_pair(CubicNatural,gsl_interp_cspline)); + p_interpFunctors.insert(make_pair(CubicNatPeriodic,gsl_interp_cspline_periodic)); + p_interpFunctors.insert(make_pair(Akima,gsl_interp_akima)); + p_interpFunctors.insert(make_pair(AkimaPeriodic,gsl_interp_akima_periodic)); + p_acc = 0; + p_interp = 0; + try{ + SetInterpType(itype); + } + catch (iException e){ // catch exception from SetInterpType() + throw iException::Message(e.Type(), + "Init() - Unable to initialize NumericalApproximation object", + _FILEINFO_); + } + // Turn all GSL error handling off...repeatedly, every time this routine is + // called. + gsl_set_error_handler_off(); + } + + /** + * Returns whether an interpolation type is adapted from the GSL + * library. GSL interpolation types include the following: + *
      + *
    • @a Linear = 0 + *
    • @a Polynomial = 1 + *
    • @a CubicNatural = 3 + *
    • @a CubicNatPeriodic = 5 + *
    • @a Akima = 7 + *
    • @a AkimaPeriodic = 8 + *
    + * + * @param itype Interpolation type to be compared to GSL list + * @return @b bool True if interpolation type is GSL + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + */ + bool NumericalApproximation::GslInterpType(NumericalApproximation::InterpType itype) const { + if (itype == NumericalApproximation::Linear) return true; + if (itype == NumericalApproximation::Polynomial) return true; + if (itype == NumericalApproximation::CubicNatural) return true; + if (itype == NumericalApproximation::CubicNatPeriodic) return true; + if (itype == NumericalApproximation::Akima) return true; + if (itype == NumericalApproximation::AkimaPeriodic) return true; + return false; + } + + /** + * @brief Allocates GSL interpolation functions + * + * This method is called within Compute to allocate pointers + * to a GSL interpolation object and to a GSL accelerator object + * (for interpolation look-ups). This is only called for the + * GSL interpolation types. If it is deemed invalid, an + * exception will be thrown. + * + * @param npoints Number of points to allocate for the GSL + * interpolator + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. Original name allocate(). + * @history 2008-11-05 Jeannie Walldren - Renamed. + */ + void NumericalApproximation::GslAllocation(unsigned int npoints) { + GslDeallocation(); + //get pointer to accelerator object (iterator for interpolation lookups) + p_acc = gsl_interp_accel_alloc(); + //get pointer to interpolation object of interp type given for npoints datapoints + p_interp = gsl_spline_alloc(GslFunctor(p_itype), npoints); + return; + } + + /** + * @brief Deallocate GSL interpolator resources, if used + * + * If a GSL interpolator function has been allocated, this + * routine will free its resources and reset internal pointers + * to reflect this state and provide a mechanism to test its + * state. Otherwise, this method sets the internal GSL pointers + * to their default, 0. + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. Original name deallocate(). + * @history 2008-11-05 Jeannie Walldren - Renamed. + */ + void NumericalApproximation::GslDeallocation() { + if (p_interp) gsl_spline_free(p_interp); + if (p_acc) gsl_interp_accel_free(p_acc); + p_acc = 0; + p_interp = 0; + return; + } + + /** + * @brief Search for a GSL interpolation function + * + * This method searches the supported GSL options table for a + * given interpolation function as requested by the caller. If + * it is not found, an exception will be thrown indicating the + * erroneous request. + * + * @param itype Type of GSL interpolator to find + * + * @return NumericalApproximation::InterpFunctor Pointer to the + * GSL spline interpolator construct. + * @throws Isis::iException::Programmer "Invalid argument. + * Unable to find GSL interpolator" + * @internal + * @history 2006-06-14 Kris Becker - Original version created + * in DataInterp class. + */ + NumericalApproximation::InterpFunctor NumericalApproximation::GslFunctor(NumericalApproximation::InterpType itype) + const throw (iException &) { + FunctorConstIter fItr = p_interpFunctors.find(itype); + if (fItr == p_interpFunctors.end()) { + ReportException(iException::Programmer,"GslFunctor()", + "Invalid argument. Unable to find GSL interpolator with id = " + + iString(NumericalApproximation::InterpType(itype)), + _FILEINFO_); + } + return (fItr->second); + } + + /** + * @brief Checks the status of the GSL interpolation operations + * + * This method takes a return status from a GSL call and determines if it is + * completed successfully. This implementation currently allows the GSL_DOMAIN + * error to propagate through sucessfully as the domain can be checked by the + * caller if they deem this necessary. + * + * @param gsl_status Return status of a GSL function call + * @param src Name of the calling source invoking the check. This allows more + * precise determination of the error. + * @param line Line of the calling source that invoked the check + * @throws Isis::iException::Programmer "GSL error occured" + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. Original name integrityCheck(). + * @history 2008-11-05 Jeannie Walldren - Renamed. + * + */ + void NumericalApproximation::GslIntegrityCheck(int gsl_status, char *src, int line) + throw (iException &) { + if (gsl_status != GSL_SUCCESS) { + if (gsl_status != GSL_EDOM) { + ReportException(iException::Programmer,"GslIntegrityCheck(int,char,int)", + "GslIntegrityCheck(): GSL error occured: " + + string(gsl_strerror(gsl_status)), src,line); + } + } + return; + } + + /** + *@brief Validates the data set before computing interpolation. + * + * This method is called from the ComputeCubicClamped() and + * ComputeGsl() methods to verify that the data set contains the + * minimum number of required points and that the components of + * the vector of domain values are unique. For all + * interpolation types other than polynomial-Neville's, the + * method verifies that the vector of domain values are also + * sorted in ascending order. For @a CubicNatPeriodic + * interpolation type, this method verifies that the first and + * last @a p_y values are equal, i.e. @f$ f(x_0) = f(x_{n-1}) + * @f$. + * + * + * @throws Isis::iException::Programmer "Interpolation requires + * a minimim of data points" + * @throws Isis::iException::Programmer "Invalid data set, + * x-values must be unique" + * @throws Isis::iException::Programmer "Invalid data set, + * x-values must be in ascending order" (if + * interpolation type is not polynomial-Neville's) + * @throws Isis::iException::Programmer "First and last points + * of the data set must have the same y-value" (if + * interpolation type is cubic-periodic) + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + void NumericalApproximation::ValidateDataSet() throw (iException &) { + if ((int) Size() < MinPoints()) { + ReportException(iException::Programmer,"ValidateDataSet()", + Name() + " interpolation requires a minimum of " + + iString(MinPoints()) + " data points - currently have " + + iString((int) Size()), + _FILEINFO_); + } + for (unsigned int i = 1; i < Size(); i++) { + // Check for uniqueness -- this applies to all interpolation types + if (p_x[i-1] == p_x[i]) { + ReportException(iException::Programmer, "ValidateDataSet()", + "Invalid data set, x-values must be unique: \n\t\tp_x[" + + iString((int) i-1) + "] = " + iString(p_x[i-1]) + + " = p_x[" + iString((int) i) + "]", + _FILEINFO_); + } + if (p_x[i-1] > p_x[i]) { + // Verify that data set is in ascending order -- + // this does not apply to PolynomialNeville, which appears to get the same results with unsorted data + if (p_itype != NumericalApproximation::PolynomialNeville) { + ReportException(iException::Programmer, "ValidateDataSet()", + "Invalid data set, x-values must be in ascending order for " + + Name() + " interpolation: \n\t\tx[" + + iString((int) i-1) + "] = " + iString(p_x[i-1]) + " > x[" + + iString((int) i) + "] = " + iString(p_x[i]), + _FILEINFO_); + } + } + } + if (p_itype == NumericalApproximation::CubicNatPeriodic) { + if (p_y[0] != p_y[Size()-1]) { + ReportException(iException::Programmer, "ValidateDataSet()", + "First and last points of the data set must have the same y-value for " + + Name() + "interpolation to prevent discontinuity at the boundary", + _FILEINFO_); + } + } + p_dataValidated = true; + return; + } + + + /** + * Returns whether the passed value is greater than or equal to + * the domain minimum and less than or equal to the domain + * maximum. + * + * @param a Value to be verified as valid domain value. + * @return @b bool True if passed parameter is within the + * domain. + * @throws Isis::iException::Programmer "Unable to compute + * domain boundaries" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + bool NumericalApproximation::InsideDomain(const double a) { + try{ + if (a+DBL_EPSILON < DomainMinimum()) { + return false; + } + if (a-DBL_EPSILON > DomainMaximum()){ + return false; + } + } + catch (iException e){ // catch exception from DomainMinimum(), DomainMaximum() + throw iException::Message(e.Type(), + "InsideDomain() - Unable to compute domain boundaries", + _FILEINFO_); + } + return true; + } + + /** + * Returns whether a GSL interpolation computation of the data + * set has been performed. This method is only applicable to GSL + * interpolation types. + * + * @return @b bool True if GSL interpolation has been + * computed. + * @throws Isis::iException::Programmer "Method only valid for + * GSL interpolation types" + * @see ComputeGsl() + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Renamed, added + * iException. + */ + bool NumericalApproximation::GslComputed() const { + if (GslInterpType(p_itype)) return ((p_interp) && (p_acc)); + else + throw iException::Message(iException::Programmer, + "GslComputed() - Method only valid for GSL interpolation types, may not be used for " + + Name() + " interpolation", + _FILEINFO_); + } + + /** + *@brief Computes the GSL interpolation for a set of + * (x,y) data points + * + * This protected method is called only if the object is + * assigned a GSL interpolation type and if it has not already + * been computed on the given data set. It will compute the + * interval of interpolated range values over the given domain. + * A copy of this data is maintained in the object so the data + * points do not need to be interpolated on each evaluation of a + * point unless the data set changes. + * + * @throws Isis::iException::Programmer "Unable to compute GSL + * interpolation" + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Modified to allow + * for computation of interpolation types other than + * those supported by GSL. + */ + void NumericalApproximation::ComputeGsl() throw (iException &) { + try{ + if (GslComputed()) return; + if (!p_dataValidated) ValidateDataSet(); + GslAllocation(Size()); + GslIntegrityCheck(gsl_spline_init(p_interp, &p_x[0], &p_y[0], Size()), _FILEINFO_); + return; + } + catch (iException e){ // catch exception from ValidateDataSet(), GslIntegrityCheck() + throw iException::Message(e.Type(), + "ComputeGsl() - Unable to compute GSL interpolation", + _FILEINFO_); + } + } + + /** + * @brief Computes the cubic clamped interpolation for a + * set of (x,y) data points, given the first derivatives of the + * endpoints of the data set. + * + * This protected method is called only if the object is + * assigned a cubic clamped interpolation type and if it has not + * already been computed for the given data set. It calculates + * the second derivatives for each @e p_x value of the known + * data set and stores these values in + * @a p_clampedSecondDerivs so that the + * EvaluateCubicClamped() method may be called to interpolate + * the set using clamped boundary conditions, if possible. This + * method must be called when all the data points have been + * added to the object for the data set and after + * SetCubicClampedEndptDeriv() has been called. If the endpoint + * derivatives are greater than or equal to 1 x + * 1030, the routine is signaled to set the + * corresponding boundary condition for a natural spline, with + * zero second derivative on that boundary. + * + * @throws Issis::iException::Programmer "Must use + * SetCubicClampedEndptDeriv() before computing + * cubic spline with clamped boundary" + * @throws Issis::iException::Programmer "Unable to compute + * cubic clamped interpolation" + * @see SetCubicClampedEndptDeriv() + * @see EvaluateCubicClamped() + * @internal + * @history 1999-08-11 K Teal Thompson - Original version in + * Isis2. + * @history 2007-02-20 Janet Barrett - Imported to Isis3 in + * NumericalMethods class. Original name r8spline(). + * @history 2008-11-05 Jeannie Walldren - Renamed and modified + * input parameters. + */ + void NumericalApproximation::ComputeCubicClamped() throw (iException &){ + // This method was derived from an algorithm in the text + // Numerical Recipes in C: The Art of Scientific Computing + // Section 3.3 by Flannery, Press, Teukolsky, and Vetterling + + if(!p_dataValidated){ + try{ ValidateDataSet();} + catch (iException e) { // catch exception from ValidateDataSet() + throw iException::Message(e.Type(), + "ComputeCubicClamped() - Unable to compute cubic clamped interpolation", + _FILEINFO_); + } + } + if(!p_clampedEndptsSet) { + ReportException(iException::Programmer, "ComputeCubicClamped()", + "Must set endpoint derivative values after adding data in order to compute cubic spline with clamped boundary conditions", + _FILEINFO_); + } + int n = Size(); + p_clampedSecondDerivs.resize(n); + double u[n]; + double p,sig,qn,un; + + if (p_clampedDerivFirstPt > 0.99e30) { + p_clampedSecondDerivs[0] = 0.0;//natural boundary conditions are used if deriv of first value is greater than 10^30 + u[0] = 0.0; + } + else { + p_clampedSecondDerivs[0] = -0.5;// clamped conditions are used + u[0] = (3.0 / (p_x[1] - p_x[0])) * ((p_y[1] - p_y[0]) / (p_x[1] - p_x[0]) - p_clampedDerivFirstPt); + } + for (int i=1; i 0.99e30) {// upper boundary is natural + qn = 0.0; + un = 0.0; + } + else {// upper boundary is clamped + qn = 0.5; + un = (3.0 / (p_x[n-1] - p_x[n-2])) * (p_clampedDerivLastPt - (p_y[n-1] - p_y[n-2]) / + (p_x[n-1] - p_x[n-2])); + } + p_clampedSecondDerivs[n-1] = (un - qn * u[n-2]) / (qn * p_clampedSecondDerivs[n-2] + 1.0); + for (int i=n-2; i>=0; i--) {// backsubstitution loop of the tridiagonal algorithm + p_clampedSecondDerivs[i] = p_clampedSecondDerivs[i] * p_clampedSecondDerivs[i+1] + u[i]; + } + p_clampedComputed = true; + return; + } + + /** + * @brief Returns the domain value at which to evaluate. + * + * This protected method is called by Evaluate() if @a a + * falls outside of the domain of @e p_x values in the data set. + * The return value is determined by the + * NumericalApproximation::ExtrapType. If it is @a ThrowError, an + * error is thrown indicating that @a a is out of the domain. If + * it is @a NearestEndpoint, then the nearest domain boundary value + * is returned. Otherwise, i.e. @a Extrapolate, @a a is returned + * as long as the NumericalApproximation::InterpType is not GSL + * or cubic neighborhood. + * + * @param a Value passed into Evaluate() that falls outside of + * domain. + * @param etype NumericalApproximation::ExtrapType enum + * value indicates how to evaluate if @a a + * falls outside of the domain. (Default: + * @a ThrowError) + * @return @b double Value returned to Evaluate() to be + * extrapolated. + * @throws Isis::iException::Programmer "Invalid argument. Value + * entered is outside of domain + * @throws Isis::iException::Programmer "Invalid argument. + * Cannot extrapolate for interpolation type" (GSL + * or @a CubicNeighborhood) + * @see Evaluate() + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Modified to allow for + * computation of interpolation types other than those + * supported by GSL. + * @history 2008-12-18 Jeannie Walldren - Added address + * operator (&) to input variables of type + * NumericalApproximation::ExtrapType. + */ + double NumericalApproximation::ValueToExtrapolate(const double a, const ExtrapType &etype){ + if (etype == NumericalApproximation::ThrowError) { + ReportException(iException::Programmer,"Evaluate()", + "Invalid argument. Value entered, a = " + + iString(a) + ", is outside of domain = [" + + iString(DomainMinimum()) + ", " + + iString(DomainMaximum()) + "]", + _FILEINFO_); + } + if (etype == NumericalApproximation::NearestEndpoint) { + if (a+DBL_EPSILON < DomainMinimum()) { + return DomainMinimum(); + } + else { + return DomainMaximum(); // (a > DomainMaximum()) + } + } + else { // gsl interpolations and CubicNeighborhood cannot extrapolate + if (GslInterpType(p_itype) + || p_itype == NumericalApproximation::CubicNeighborhood) { + ReportException(iException::Programmer,"Evaluate()", + "Invalid argument. Cannot extrapolate for type " + + Name() + ", must choose to throw error or return nearest neighbor", + _FILEINFO_); + } + return a; + } + } + + /** + * @brief Performs cubic spline interpolation for a neighborhood + * about @a a. + * + * This is a protected method called by Evaluate() if the + * NumericalApproximation::InterpType is + * @a CubicNeighborhood. It uses an algorithm that + * is adapted from the IDL interpol.pro application using the + * "/spline" keyword on an irregular grid. This type of cubic + * spline fits a natural cubic spline to the 4-point + * neighborhood of known data points surrounding @a a. For + * example, suppose {@e x0, @e x1, ..., + * @e xn} is the array of known domain values + * in the data set and @f$ x_i \leq a < x_{i+1}@f$ for some + * @e i such that @f$ 0 \leq i \leq n @f$, then + * @e f(@a a) is evaluated by interpolating the natural + * cubic spline consisting of the data set + * {@e xi-1, @e xi, + * @e xi+1, @e xi+2} at + * @a a. + * + * @b Note: If the given value, @a a, falls outside of the + * domain, then @e f evaluated at the nearest domain boundary + * is returned. + * + * @param a Domain value from which to interpolate a + * corresponding range value. + * @return @b double Result of interpolated value of f(a). + * @throws Isis::iException::Programmer "Unable to evaluate + * cubic neighborhood interpolation at a" + * @see Evaluate() + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + double NumericalApproximation::EvaluateCubicNeighborhood(const double a) { + try{ + int s=0, s_old, s0; + vector x0(4), y0(4); + NumericalApproximation spline(NumericalApproximation::CubicNatural); + for (unsigned int n = 0; n < Size(); n++){ + if (p_x[n] < a) s = n; + else break; + } + if (s < 1) s = 1; + else if (s > (int) Size()-3) s = Size()-3; + s_old = -1; + s0 = s-1; + if (s_old != s0 ){ + for (int n = 0; n < 4; n++) { + x0[n] = p_x[n+s0]; + y0[n] = p_y[n+s0]; + spline.AddData(x0[n],y0[n]); + } + s_old = s0; + } + // use nearest endpoint extrapolation method for neighborhood spline + // since CubicNatural can do no other + return spline.Evaluate(a,NumericalApproximation::NearestEndpoint); + } + catch (iException e){ // catch exception from Constructor, ComputeGsl(), Evaluate() + throw iException::Message(e.Type(), + "EvaluateCubicNeighborhood() - Unable to evaluate cubic neighborhood interpolation at a = " + + iString(a), + _FILEINFO_); + } + } + + /** + * @brief Performs cubic spline interpolations for neighborhoods + * about each value of @a a. + * + * This is a protected method called by Evaluate() if the + * NumericalApproximation::InterpType is + * @a CubicNeighborhood. It uses an algorithm that + * is adapted from the IDL interpol.pro application using the + * "/spline" keyword on an irregular grid. + * For each component of @a a, this method fits a natural + * cubic spline using the 4-point neighborhood of known data + * points surrounding that component. For example, suppose + * {@e x0, @e x1, ..., + * @e xn} is the array of known domain values + * in the data set, then for + * each component of @a a, @e ak, in the domain, + * there is an @e i such that @f$ 0 \leq i \leq n + * @f$ and @f$ x_i \leq a_k < x_{i+1}@f$. Then, + * @e f(@a ak) is evaluated by interpolating the + * natural cubic spline consisting of the data set + * {@e xi-1, @e xi, + * @e xi+1, @e xi+2} at + * @e ak. + * + * @b Note: If any given value, @a ai, falls + * outside of the domain, then @e f is evaluated at the nearest + * domain boundary. + * + * @param a Vector of domain values from which to interpolate a + * vector of corresponding range values + * @param etype NumericalApproximation::ExtrapType enum + * value indicates how to evaluate if @a a + * falls outside of the domain. (Default: + * @a ThrowError) + * @return @b vector @b \ Result of interpolated value + * of f at each value of a. + * @throws Isis::iException::Programmer "Unable to evaluate + * cubic neighborhood interpolation at the values in + * the vector, a" + * @see Evaluate() + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + * @history 2008-12-18 Jeannie Walldren - Added address + * operator (&) to input variables of type vector and + * NumericalApproximation::ExtrapType. + */ + vector NumericalApproximation::EvaluateCubicNeighborhood(const vector &a, + const NumericalApproximation::ExtrapType &etype) { + vector result(a.size()); + int s_old, s0; + vector x0(4), y0(4); + vector s; + s.clear(); + s.resize(a.size()); + for (unsigned int i = 0; i < a.size(); i++) { + for (unsigned int n = 0; n < Size(); n++){ + if (p_x[n] < a[i]) { + s[i] = n; + } + } + if (s[i] < 1) { + s[i] = 1; + } + if (s[i] > ((int) Size())-3) { + s[i] = Size()-3; + } + } + s_old = -1; + try{ + NumericalApproximation spline(NumericalApproximation::CubicNatural); + for (unsigned int i = 0; i < a.size(); i++) { + s0 = s[i]-1; + if (s_old != s0 ){ + spline.Reset(); + for (int n = 0; n < 4; n++) { + x0[n] = p_x[n+s0]; + y0[n] = p_y[n+s0]; + spline.AddData(x0[n],y0[n]); + } + s_old = s0; + } + double a0; + // checks whether this value is in domain of the main spline + if (InsideDomain(a[i])) + a0 = a[i]; + else a0 = ValueToExtrapolate(a[i],etype); + // since neighborhood spline is CubicNatural, the only extrapolation possible is NearestEndpoint + result[i] = spline.Evaluate(a0,NumericalApproximation::NearestEndpoint); + } + return result; + } + catch (iException e){ // catch exception from Constructor, ComputeGsl(), Evaluate() + throw iException::Message(e.Type(), + "EvaluateCubicNeighborhood() - Unable to evaluate the function at the given vector of points using cubic neighborhood interpolation", + _FILEINFO_); + } + } + + /** + * @brief Performs cubic spline interpolation with + * clamped boundary conditions, if possible. + * + * This is a protected method called by Evaluate() if the + * NumericalApproximation::InterpType is + * @a CubicClamped and SetCubicClampedEndptDeriv() has + * been called. It uses the second derivative vector, + * @a p_clampedSecondDerivs, to interpolate the value for + * @e f(@a a) using a clamped cubic spline formula, + * + * @b Note: If the given value, @a a, falls outside of the + * domain, then extrapolation is attempted and the result is + * accurate only if @a a is near enough to the domain + * boundary. + * + * + * @param a Domain value from which to interpolate a + * corresponding range value + * @return @b double Value returned from interpolation or + * extrapolation. + * @see Evaluate() + * @see ComputeCubicClamped() + * @see SetCubicClampedEndptDeriv() + * @internal + * @history 1999-08-11 K Teal Thompson - Original version in + * Isis2. + * @history 2007-02-20 Janet Barrett - Imported to Isis3 in + * NumericalMethods class. Original name r8splint(). + * @history 2008-11-05 Jeannie Walldren - Renamed and modified + * input parameters, removed iException and replaced it + * with ValidateDataSet() method. + * + */ + double NumericalApproximation::EvaluateCubicClamped(double a) throw (iException &){ + // This method was derived from an algorithm in the text + // Numerical Recipes in C: The Art of Scientific Computing + // Section 3.3 by Flannery, Press, Teukolsky, and Vetterling + int n = Size(); + double result = 0; + + int k; + int k_Lo; + int k_Hi; + double h; + double A; + double B; + + k_Lo = 0; + k_Hi = n - 1; + while (k_Hi-k_Lo > 1) { + k = (k_Hi + k_Lo) / 2; + if (p_x[k] > a) { + k_Hi = k; + } + else { + k_Lo = k; + } + } + + h = p_x[k_Hi] - p_x[k_Lo]; + A = (p_x[k_Hi] - a) / h; + B = (a - p_x[k_Lo]) / h; + result = A * p_y[k_Lo] + B * p_y[k_Hi] + ((pow(A,3.0) - A) * + p_clampedSecondDerivs[k_Lo] + (pow(B,3.0) - B) * p_clampedSecondDerivs[k_Hi]) * pow(h,2.0) / 6.0; + return result; + } + + /** + * @brief Performs interpolation using the Hermite cubic + * polynomial. + * + * This is a protected method called by Evaluate() if the + * NumericalApproximation::InterpType is + * @a CubicHermite. It returns an approximate value for + * @e f(@a a) by using the Hermite cubic polynomial, which uses + * Lagrange coefficient polynomials. The data points and each + * corresponding first derivative should have been already + * added. + * + * @param a Domain value from which to interpolate a + * corresponding range value + * @return @b double Value returned from interpolation or + * extrapolation + * @throw Isis::iException::User "Invalid arguments. The size of + * the first derivative vector does not match the number + * of (x,y) data points." + * @see http://mathworld.wolfram.com/HermitesInterpolatingPolynomial.html + * @see http://en.wikipedia.org/wiki/Lagrange_Polynomial + * @see Evaluate() + * @see AddCubicHermiteDeriv() + * @internal + * @history 2009-06-10 Jeannie Walldren - Original version. + * + */ + double NumericalApproximation::EvaluateCubicHermite(const double a) throw (iException &){ + // algorithm was found at en.wikipedia.org/wiki/Cubic_Hermite_spline + // it seems to produce same answers, as the NumericalAnalysis book + + if (p_fprimeOfx.size() != Size()) { + ReportException(iException::User,"EvaluateCubicHermite()", + "Invalid arguments. The size of the first derivative vector does not match the number of (x,y) data points.", + _FILEINFO_); + } + // find the interval in which "a" exists + int lowerIndex = FindIntervalLowerIndex(a); + + // we know that "a" is within the domain since this is verified in + // Evaluate() before this method is called, thus n <= Size() + if (a == p_x[lowerIndex]) { + return p_y[lowerIndex]; + } + if (a == p_x[lowerIndex+1]) { + return p_y[lowerIndex+1]; + } + + double x0, x1, y0, y1, m0, m1; + // a is contained within the interval (x0,x1) + x0 = p_x[lowerIndex]; + x1 = p_x[lowerIndex+1]; + // the corresponding known y-values for x0 and x1 + y0 = p_y[lowerIndex]; + y1 = p_y[lowerIndex+1]; + // the corresponding known tangents (slopes) at (x0,y0) and (x1,y1) + m0 = p_fprimeOfx[lowerIndex]; + m1 = p_fprimeOfx[lowerIndex+1]; + + + // following algorithm found at en.wikipedia.org/wiki/Cubic_Hermite_spline + // seems to produce same answers, is it faster? + + double h, t; + h = x1-x0; + t = (a - x0)/h; + return (2*t*t*t-3*t*t+1)*y0 + (t*t*t-2*t*t+t)*h*m0 + (-2*t*t*t+3*t*t)*y1 + (t*t*t-t*t)*h*m1; + } + + /** + * Find the index of the x-value in the data set that is just + * below the input value, a. This method is used by + * EvaluateCubicHermite(), EvaluateCubFirstDeriv() and + * EvaluateCubicHermiteSecDeriv() to determine in which interval + * of x-values a lies. It returns the index of the lower + * endpoint of the interval. If a is below the domain minimum, + * the method returns 0 as the lower index. If a is above the + * domain maximum, it returns the second to last index of the + * data set, Size()-2, as the lower index. + * + * @param a Domain value around which the interval lies + * @return @b int Index of the x-value that is the lower + * endpoint of the interval of data points that + * surrounds a. Returns 0 if a is below domain min and + * Size()-2 if a is above domain max. + * @internal + * @history 2009-06-10 Jeannie Walldren - Original Version + * + */ + int NumericalApproximation::FindIntervalLowerIndex(const double a){ + if (InsideDomain(a)) { + // find the interval in which "a" exists + std::vector::iterator pos; + // find position in vector that is greater than or equal to "a" + pos = upper_bound(p_x.begin(),p_x.end(),a); + int upperIndex = 0; + if (pos != p_x.end()) { + upperIndex = distance(p_x.begin(),pos); + } + else { + upperIndex = Size() - 1; + } + return upperIndex-1; + } + else if ((a+DBL_EPSILON) < DomainMinimum()) { + return 0; + } + else { + return Size() - 2; + } + } + + + /** + * @brief Performs polynomial interpolation using Neville's + * algorithm. + * + * This is a protected method called by Evaluate() if the + * NumericalApproximation::InterpType is + * @a PolynomialNeville. It uses Neville's + * algorithm for Lagrange polynomials. It returns a value + * @e f(@a a) and sets the error estimate + * @a p_polyNevError. After this method is called, the user + * may access this error estimate by calling + * PolynomialNevilleErrorEstimate(). + * + * @b Note: If the given value, @a a, falls outside of the + * domain, then extrapolation is attempted and the result is + * accurate only if @a a is near enough to the domain + * boundary. + * + * @param a Domain value from which to interpolate a + * corresponding range value + * @return @b double Value returned from interpolation or + * extrapolation + * @see http://mathworld.wolfram.com/NevillesAlgorithm.html + * @see Evaluate() + * @see PolynomialNevilleErrorEstimate() + * @internal + * @history 1999-08-11 K Teal Thompson - Original version in + * Isis2. + * @history 2007-02-20 Janet Barrett - Imported to Isis3 in + * NumericalMethods class. Original name r8polint() + * @history 2008-11-05 Jeannie Walldren - Renamed and modified + * input/output parameters, removed iException and + * replaced it with ValidateDataSet() method. + * + */ + double NumericalApproximation::EvaluatePolynomialNeville(const double a) throw (iException &){ + // This method was derived from an algorithm in the text + // Numerical Recipes in C: The Art of Scientific Computing + // Section 3.1 by Flannery, Press, Teukolsky, and Vetterling + int n = Size(); + double y; + + int ns; + double den,dif,dift,c[n],d[n],ho,hp,w; + double *err = 0; + ns = 1; + dif = fabs(a - p_x[0]); + for (int i=0; i Array of y values to be used + * in numerical integration + * @throws Isis::iException::Programmer (When a > b) "Invalid + * interval entered" + * @throws Isis::iException::Programmer "Invalid arguments. + * Interval entered is not contained within domain" + * @throws Isis::iException::Programmer "Unable to evaluate the + * data set for integration" + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version. + */ + vector NumericalApproximation::EvaluateForIntegration(const double a, const double b, const unsigned int n) throw (iException &) { + if (a > b) { + ReportException(iException::Programmer,"EvaluatedForIntegration()", + "Invalid interval entered: [a,b] = [" + + iString(a) + ", " + iString(b) + "]", + _FILEINFO_); + } + if (!InsideDomain(a) || !InsideDomain(b)) { + ReportException(iException::Programmer,"EvaluateForIntegration()", + "Invalid arguments. Interval entered [" + + iString(a) + ", " + iString(b) + + "] is not contained within domain [" + + iString(DomainMinimum()) + ", " + + iString(DomainMaximum()) + "]", + _FILEINFO_); + } + vector f; + //need total number of segments to be divisible by n-1 + // This way we can use the formula for each interval: 0 to n, n to 2n, 2n to 3n, etc. + // Notice interval endpoints will overlap for these composite formulas + int xSegments = Size()-1; + while (xSegments%(n-1) != 0) { + xSegments++; + } + // x must be sorted and unique + double xMin = a; + double xMax = b; + //Uniform step size. + double h = (xMax-xMin)/xSegments; + //Compute the interpolates using spline. + try{ + for(double i = 0; i < (xSegments+1); i++) { + double xi = h*i + xMin; + f.push_back(Evaluate(xi)); // validate data set here, allow default ThrowError extrap type + } + f.push_back(h); + return f; + } + catch (iException e){ // catch exception from Evaluate() + throw iException::Message(e.Type(), + "EvaluateForIntegration() - Unable to evaluate the data set for integration", + _FILEINFO_); + } + }// for integration using composite of spline (creates evenly spaced points) + + /** + * @brief Generalized error report generator + * + * This method is used throughout this class to standardize error reporting as a + * convenience to its implementor. + * + * @param type Type of @b Isis::iException + * @param methodName Name of method where exception originated + * @param message Error context string provided by the caller + * @param filesrc Name of the file the error occured in. + * @param lineno Line number of the calling source where the error occured. + * @throws Isis::iException::errType equal to + * @a type and error message equal to + * (@a methodName + " - " + @a message) + * @internal + * @history 2006-06-14 Kris Becker - Original version created in + * DataInterp class. + * @history 2008-11-05 Jeannie Walldren - Modified to take + * iException::errType as input parameter. + */ + void NumericalApproximation::ReportException(iException::errType type, const string &methodName, const string &message, + char *filesrc, int lineno) + const throw (iException &) { + string msg = methodName + " - " + message; + throw iException::Message(type,msg.c_str(),filesrc,lineno); + return; + } + +} diff --git a/isis/src/base/objs/NumericalApproximation/NumericalApproximation.h b/isis/src/base/objs/NumericalApproximation/NumericalApproximation.h new file mode 100644 index 0000000000000000000000000000000000000000..21bcbf515549f5fa15093b9022646aa91cb482b9 --- /dev/null +++ b/isis/src/base/objs/NumericalApproximation/NumericalApproximation.h @@ -0,0 +1,901 @@ +#ifndef NumericalApproximation_h +#define NumericalApproximation_h + +#include +#include +#include +#include +#include +#include "iException.h" + +using namespace std; + +namespace Isis { + /** + * @brief NumericalApproximation provides various numerical + * analysis methods of interpolation, extrapolation and + * approximation of a tabulated set of @a x, @a y data. + * + * This class contains a merged version of the Isis3 classes + * @b DataInterp and @b NumericalMethods. In addition, + * some methods from @b AtmosModel were moved to this class, the + * @a CubicNeighborhood interpolation type was + * adapted from the IDL routine called @b interpol (using the + * "/spline" keyword), and several differentiation and + * integration approximation methods were created. + * + * NumericalApproximation contains 9 types of data interpolation + * routines. These routines act on x, y pairs of data points. + * The following forms of data interpolation are supported: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    NameType (enum)MinPointsDescription
    Linear@a Linear2 + * Linear interpolation approximates a curve by + * concatinating line segments between known data + * points. This results in a continuous curve with a + * discontinuities of the derivative at the known data + * points. This interpolation type uses the GSL + * library routines. + * + *
    Polynomial@a Polynomial3 + * Computes a polynomial interpolation. This method + * should only be used for interpolating small numbers + * of points because polynomial interpolation introduces + * large oscillations, even for well-behaved datasets. + * The number of terms in the interpolating polynomial + * is equal to the number of points. This interpolation + * type uses the GSL library routines. + *
    Neville's Algorithm for Polynomial Interpolation@a PolynomialNeville3 + * Polynomial interpolation using Neville's algorithm. This + * first fits a polynomial of degree 0 through each point. + * On the second iteration, the polynomial of adjoining + * indices are combined to fit through pairs of points. + * This process repeats until a pyramid of approximations is + * reached. This is based on the Newton form of the + * interpolating polynomial and the recursion relation of + * the divided differences. + *
    Natural Cubic Spline@a CubicNatural3 + * Cubic spline with natural boundary conditions. The + * resulting curve is piecewise cubic on each interval + * with matching first and second derivatives at the + * supplied data points. The second derivative is chosen + * to be zero at the endpoints, i.e. the first and last + * points of the data set. This is also refered to as + * free boundary condtions. This interpolation type uses + * the GSL + * library routines. + *
    Clamped Cubic Spline@a CubicClamped3 + * Cubic Spline interpolation with clamped boundary + * conditions. The resulting curve is piecewise cubic on + * each interval. For this type of boundary condition to + * hold, it is necessary to have either the values of the + * derivative at the endpoints or an accurate approximation + * to those values. In general, clamped boundary conditions + * lead to more accurate approximations since they include + * more information about the function. + *
    Periodic Natural Cubic Spline@a CubicNatPeriodic2 + * Cubic spline with periodic boundary conditions. The + * resulting curve is piecewise cubic on each interval + * with matching first and second derivatives at the + * supplied data points. The derivatives at the first + * and last points are also matched. Note that the last + * point in the data must have the same y-value as the + * first point, otherwise the resulting periodic + * interpolation will have a discontinuity at the + * boundary. This interpolation type uses the GSL + * library routines. + *
    Cubic Spline about 4-point Neighborhood@a CubicNeighborhood4 + * Cubic Spline interpolation using 4-pt Neighborhoods + * with natural boundary conditions. This interpolation + * type is adapted from the IDL interpol.pro application + * using the "/spline" keyword on an irregular grid. + * This type of cubic spline fits a natural cubic spline + * to the 4-point neighborhood of known data points + * surrounding the @a x value at which we wish to + * evaluate. For example, suppose {@a x0, + * @a x1, ..., @a xn} is the + * array of known domain values in the data set and @f$ + * x_i \leq u < x_{i+1} @f$ for some @e i such that + * @f$ 0 \leq i \leq n @f$, then to evaluate the + * @a y value at @e u, this method of interpolation + * evaluates the ordinary cubic spline consisting of the + * data set {@a xi-1, @a xi, + * @a xi+1, @a xi+2} at + * @e u. + *
    Cubic Spline using Hermite cubic polynomial@a CubicHermite2 + * Cubic Spline interpolation using the Hermite cubic + * polynomial (also called the unique Hermite + * interpolating fundamental polynomial of degree 3). + * This method requires the input of the slopes of the + * tangent lines of the curve (i.e. velocities, or first + * derivatives) at each of the data points. This ensures + * that the approximation has the same "shape" as the + * curve at the known data points. This interpolation type + * uses piecewise Hermite cubic polynomials for each + * interval, (@a x0, @a x1), using + * the known data points, (@a + * x0,@a f(@a x0)) and + * (@a x1,@a f(@a x1)), and their + * derivatives, + * @a f '(@a x0) and @a f '(@a + * x1). The Hermite cubic polynomial is defined + * @f[ H_3(x) = + * f(x_0)h_0(x)+f(x_1)h_1(x) + * +f\prime(x_0)\hat{h}_0(x)+f\prime(x_1)\hat{h}_1(x) + * @f] + * where + * @f$ h_k(x) = + * [1-2(x-x_k)L\prime_k(x_k)](L_k(x))^2 + * @f$ + * and + * @f$ \hat{h}_k(x) = + * (x-x_k)(L_k(x))^2 + * @f$ + * for the kth-Lagrange coefficient polynomials of degree + * n = 1, + * @f$ L_0(x) = \frac{x- x_1}{x_0-x_1}@f$ and + * @f$ L_1(x) = \frac{x- x_0}{x_1-x_0}@f$. + * + *
    Akima@a Akima5 + * Non-rounded Akima spline with natural boundary + * conditions. This method uses non-rounded corner + * algorithm of Wodicka. This interpolation type uses the + * GSL library routines. + *
    Periodic Akima@a AkimaPeriodic5 + * Non-rounded Akima spline with periodic boundary + * conditions. This method uses non-rounded corner + * algorithm of Wodicka. This interpolation type uses + * the GSL library routines. + *
    + * + * + * Numerical analysis approximation methods for differentiating + * and integrating unknown functions represented by a data set + * are implemented by using the interpolations on the data set + * created with a NumericalApproximation object. The Lagrange polynomial, + * @f[ L(x) = + * \sum_{k=0}^{n} \left(f(x_k) \prod_{i=0,i \neq k}^{n} + * \frac{x- x_i}{x_k-x_i}\right) + * @f] + * is used to determine formulas for numerical differentiation + * and integration. + * @n + * @b Numerical Differentiation + * @n + * The differentiation methods use difference formulas to + * approximate first and second derivatives at a domain value + * for a given a set of known (@a x,@a y) data points. Once all + * of the data points are added, a Isis::NumericalApproximation + * interpolation is used on the dataset to estimate the + * function, @f$f:x \to y@f$, mapping @a x values to + * corresponding @a y values. Then, the derivative of + * @e f evaluated at @a x0 is approximated. + * To do so, a uniform step size of @a h is chosen to + * determine the distance between @a xi and @a + * xi+1. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Differentiation methods require the parameters + * @a a (domain value at which the derivative will be + * evaluated), @a n (number of points used in the difference + * formula), and @a h (step size of points). Note: @a a + * is denoted @a x0 in the above formulas. + *
    Numerical Differentiation TypeDifference FormulasMethods AvailableDescription
    Backward Difference + *
      + *
    • 2-point backward difference. + * @f[ + * f\prime(x_0) \approx \frac{1}{h}[f(x_0) - f(x_0 - h)] + * @f] + *
    • 3-point backward difference. + * @f[ + * f\prime(x_0) \approx \frac{1}{2h}[3f(x_0) - 4f(x_0 - h) + + * f(x_0 - 2h)] + * @f] + *
    • 3-point backward second difference. + * @f[ + * f\prime\prime(x_0) \approx \frac{1}{h^2}[f(x_0) + * - 2f(x_0 - h) + f(x_0 - 2h)] + * @f] + *
    + *
    + *
      + *
    • BackwardFirstDifference() + *
    • BackwardSecondDifference() + *
    + *
    + * Backward difference formulas use a uniform step-size + * moving in the negative direction from the + * given @a x0. These formulas are derived + * by differentiating the Lagrange polynomials for + * @a xi = @a x0 - @a ih + * and evaluating them at@a x0. + *
    Forward Difference + *
      + *
    • 2-point forward difference. + * @f[ + * f\prime(x_0) \approx \frac{1}{h}[f(x_0 + h) - f(x_0)] + * @f] + *
    • 3-point forward difference. + * @f[ + * f\prime(x_0) \approx \frac{1}{2h}[-f(x_0 + 2h) + + * 4f(x_0 + h) - 3f(x_0)] + * @f] + *
    • 3-point forward second difference. + * @f[ + * f\prime\prime(x_0) \approx \frac{1}{h^2}[f(x_0 + + * 2h) - 2f(x_0 + h) + f(x_0)] + * @f] + *
    + *
    + *
      + *
    • ForwardFirstDifference() + *
    • ForwardSecondDifference() + *
    + *
    + * Forward difference formulas use a uniform step-size + * moving in the positive direction from + * @a x0. These formulas are derived by + * differentiating the Lagrange polynomials for + * @a xi = @a x0 + @a ih + * and evaluating them at@a x0. + *
    Center Difference + *
      + *
    • 3-point center difference. + * @f[ + * f\prime(x_0) \approx \frac{1}{2h}[f(x_0 + h) - + * f(x_0 - h)] + * @f] + *
    • 5-point center difference. + * @f[ + * f\prime(x_0) \approx \frac{1}{12h}[-f(x_0 + 2h) + + * 8f(x_0 +h) - 8f(x_0 - h) + f(x_0 - 2h)] + * @f] + *
    • 3-point center second difference. + * @f[ + * f\prime\prime(x_0) \approx \frac{1}{h^2}[f(x_0 + h) + * - 2f(x_0) + f(x_0 - h)] + * @f] + *
    • 5-point center second difference. + * @f[ + * f\prime\prime(x_0) \approx \frac{1}{12h^2}[-f(x_0 + + * 2h) + 16f(x_0 +h) - 30f(x_0) + 16f(x_0 - h) - f(x_0 + * - 2h)] + * @f] + *
    + *
    + *
      + *
    • CenterFirstDifference() + *
    • CenterSecondDifference() + *
    + *
    + * Center difference formulas use a uniform step-size + * moving in both directions from @a x0 so this + * point stays centered. These formulas are derived by + * differentiating the Lagrange polynomials for + * @a xi = @a x0 + * + (@e i - (@a n - 1)/2)@a h and evaluating them + * at @a x0. + *
    GSL Differentiation Unknown + *
      + *
    • GslFirstDerivative() + *
    • GslSecondDerivative() + *
    + *
    + * No documentation was found about the algorithms used + * for these methods. They may only be called when + * interpolation type is one of the following: @a Linear, + * @a Polynomial, @a CubicNatural, @a CubicNatPeriodic, @a Akima, or + * @a AkimaPeriodic. + *
    + * @n + * @b Numerical Integration + * @n + * The integration methods were derived using + * @b Newton-Cotes, or @a quadrature, formulas for + * approximating integrals given a set of known (@a x,@a y) + * data points. The @a x values may be irregularly spaced, but + * must be unique and added to the dataset in ascending order. + * Once all of the data points are added, a + * Isis::NumericalApproximation interpolation is used on + * the dataset to estimate the function, @f$f:x \to y@f$, + * mapping @a x values to corresponding @a y values. + * Then, the integral of @e f on the interval from @a a + * to @a b is approximated. To do so, an algorithm for creating + * a composite formula by applying the original formula to + * segments that share a boundary point is used. The + * NumericalApproximation::InterpType chosen for + * interpolation computation seems to have little affect on the + * error between the actual integral and the return values of + * the integration methods. The BoolesRule() method varies the + * most in error. Although errors are not high for any of the + * interpolation types, + * @a CubicNatural spline interpolations seem to + * have the smallest error most often with BoolesRule(). For any + * other numerical integration method, the errors appear to be + * identical for any NumericalApproximation::InterpType except + * @a Polynomial, which usually has a slightly larger + * error than the other interpolation types. Note: A portion of + * this algorithm is derived from the IDL function int_tabulated + * for Boole's Method. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Integration methods require the parameters @a a, + * @a b (interval of domain over which to integrate). + *
    Numerical Integration TypeIntegration FormulasMethods AvailableDescription
    Trapezoidal Rule + *
      + *
    • 2-point Newton-Cotes trapezoidal rule: + * @f[ + * \int_{a}^b f(x)dx \approx \frac{h}{2}[f(a) + f(b)] + * @f] + * where @e h = @a b - @a a. + *
    + *
    + *
      + *
    • TrapezoidalRule() + *
    + *
    + * The 2-point closed rule, known as the trapezoidal + * rule, uses straight line segments between known data + * points to estimate the area under the curve (integral). + * This Newton-Cotes formula uses a uniform step-size of + * @e h = @a b - @a a and is derived by integrating the + * Lagrange polynomials over the closed interval [@a a, + * @a a+h] for @a xi = + * @a x0 + @e ih. + *
    Simpson's Rule, or Simpson's 3-Point Rule + *
      + *
    • 3-point Newton-Cotes, Simpson's Rule + * @f[ + * \int_{a}^b f(x)dx \approx \frac{h}{3}[f(a) + + * 4f(a+h) + f(a+2h)] + * @f] + * where @e h = (@a b - @a a)/2. + *
    + *
    + *
      + *
    • Simpsons3PointRule() + *
    + *
    + * The 3-point closed rule, known as Simpson's Rule or + * Simpson's 3-Point Rule, uses parabolic arcs between + * known data points to estimate the area under the curve + * (integral). This Newton-Cotes formula uses a uniform + * step-size of @e h = (@a b - @a a)/2 and is derived by + * integrating the Lagrange polynomials over the closed + * interval [@a a, @a a+2h] for @a xi = + * @a x0 + @e ih. + *
    Simpson's 3/8 Rule, or Simpson's 4-Point Rule + *
      + *
    • 4-point Newton-Cotes, Simpson's 3/8 Rule + * @f[ + * \int_{a}^b f(x)dx \approx \frac{3h}{8}[f(a) + + * 3f(a+h) + 3f(a+2h) + f(a+3h)] + * @f] + * where @e h = (@a b - @a a)/3. + *
    + *
    + *
      + *
    • Simpsons4PointRule() + *
    + *
    + * The 4-point closed rule, known as Simpson's 3/8 Rule or + * Simpson's 4-Point Rule, uses cubic curves between + * known data points to estimate the area under the curve + * (integral). This Newton-Cotes formula uses a uniform + * step-size of @e h = (@a b - @a a)/3 and is derived by + * integrating the Lagrange polynomials over the closed + * interval [@a a, @a a+3h] for @a xi = + * @a x0 + @e ih. + *
    Boole's Rule + *
      + *
    • 5-point Newton-Cotes, Boole's Rule + * @f[ + * \int_{a}^b f(x)dx \approx \frac{2h}{45}[7f(a) + + * 32f(a+h) + 12f(a+2h) + 32f(a+3h) + 7f(a+4h)] + * @f] + * where @e h = (@a b - @a a)/4. + *
    + *
    + *
      + *
    • BoolesRule() + *
    + *
    + * The 5-point closed rule, known as Boole's Rule, uses + * quartic curves between known data points to estimate + * the area under the curve (integral). This Newton-Cotes + * formula uses a uniform step-size of @e h = (@a b - + * @a a)/4 and is derived by integrating the Lagrange + * polynomials over the closed interval [@a a, @a a+4h] + * for @a xi = @a x0 + + * @a ih. + *
    Refinements of Extended Trapezoidal Rule + *
      + *
    • Extended closed trapezoidal rule + * @f[ + * \int_{a}^b f(x)dx \approx h[\frac12 f(x_0) + + * f(x_1) + ... + f(x_{n-2} + \frac12 + * f(x_{n-1})] + * @f] + * where @e h = (@a b - @a a)/4, @a x0 = + * @a a, and @a xn-1 = @a b. + *
    + *
    + *
      + *
    • RefineExtendedTrap() + *
    + *
    + * The extended (or composite) trapezoidal rule can be + * used to with a series of refinements to approximate the + * integral. The first stage of refinement returns the + * ordinary trapezoidal estimate of the integral. + * Subsequent stages will improve the accuracy, where, for + * the @a nth stage 2@a n-2 interior + * points are added. + *
    Romberg's Method + *
      + *
    • Romberg's Method for Integration
    + *
      + *
    • RombergsMethod() + *
    + *
    + * Romberg's Method is a potent numerical integration + * tool. It uses the extended trapezoidal rule and + * Neville's algorithm for polynomial interpolation. + *
    GSL Integration Unknown + *
      + *
    • GslIntegral() + *
    + *
    + * No documentation was found about the algorithm used for + * this methods. They may only be called when + * interpolation type is one of the following: @a Linear, + * @a Polynomial, @a CubicNatural, @a CubicNatPeriodic, @a Akima, or + * @a AkimaPeriodic. + *
    + * + * + * Below is an example demonstating the use of this class: + * @code + * inline double f(double x) { return (x + cos ((x * x))); } + * + * NumericalApproximation + * spline(NumericalApproximation::CubicClamped); + * for (int x = 0; x < 200 ; x++) { + * spline.addPoint(x, f(x)); + * } + * spline.SetCubicClampedEndptDeriv(0,0); + * double yinterp = spline.Evaluate(50.7); + * double yextrap = + * spline.Evaluate(201,NumericalApproximation::Extrapolate); + * double deriv = spline.CenterFirstDifference(10); + * double integ = + * spline.RombergsMethod(spline.DomainMinimum(),spline.DomainMaximum()); + * @endcode + * + * To compute the same data set using the Akima spline, just use the following: + * @code + * spline.Reset(NumericalApproximation::Akima); + * double yinterp = spline.Evaluate(50.7); + * double yextrap = + * spline.Evaluate(201,NumericalApproximation::NearestEndpoint); + * double deriv = spline.CenterFirstDifference(10); + * double integ = + * spline.RombergsMethod(spline.DomainMinimum(),spline.DomainMaximum()); + * @endcode + * + *

    Caveats

    + * When using this class, there are some important details that + * require consideration. Several interpolation types of this + * class use the GSL library. In addition, the GSL library + * default error handling scheme has implications when used in + * C++ objects. The default behavior is to terminate the + * application when an error occurs. Options for developers are + * to turn off error trapping within the GSL, which means users + * of the library must do their own error checking, or a + * specific handler can be specified to replace the default + * mode. Neither option is well suited in object-oriented + * implementations because they apply globally, to all users of + * the library. The approach used here is to turn off error + * handling and require users to handle their own error + * checking. This is not entirely safe as any user that does + * not follow this strategy could change this behavior at + * runtime. Other options should be explored. An additional + * option is that the default behavior can be altered prior to + * building GSL but this is also problematic since this behavior + * cannot be guaranteed universally. + * + * For these types, interpolation is strictly adhered to and + * extrapolation is not handled well. If the input to be + * evaluated is outside of the + * minimum and maximum @a x values of the original data + * points, then the @a y value corresponding to the + * @a x value that is nearest to that input is returned. + * However, for sufficiently close values, the clamped cubic and + * polynomial Neville's types are fairly accurate in their + * extrapolation techniques. All differentiation and + * integration methods throw an error if the value passed is + * outside of the domain. + * + * @ingroup Math + * @author 2008-11-05 Janet Barrett, Kris Becker, K Teal + * Thompson, Jeannie Walldren + * @internal + * @history 1999-08-11 K Teal Thompson - Original version of + * NumericalMethods subroutines in Isis2. + * @history 2006-06-14 Kris Becker - Created DataInterp class + * @history 2007-02-20 Janet Barrett - Created NumericalMethods + * class from Isis2 subroutines + * @history 2007-02-20 Janet Barrett - Created AtmosModel class + * from Isis2 subroutines + * @history 2008-06-18 Christopher Austin - Fixed documentation + * for DataInterp + * @history 2008-06-18 Steven Koechle - Updated NumericalMethods + * unitTest. + * @history 2008-11-05 Jeannie Walldren - Merged DataInterp + * class, NumericalMethods class, and methods from + * AtmosModel. Modified methods from various classes + * to be able to function similarly. Added InterpType + * @a CubicNeighborhood, difference formula methods, and + * integration methods. Created new unitTest. + * @history 2008-11-12 Jeannie Walldren - Fixed documentation. + * @history 2008-12-18 Jeannie Walldren - Added address + * operator (&) to input variables of type vector, + * NumericalApproximation::InterpType, and + * NumericalApproximation::ExtrapType in + * Constructors, AddData(), Evaluate(), + * ValueToExtrapolate(), EvaluateCubicNeighborhood(), + * @history 2009-01-26 Jeannie Walldren - Fixed error + * documentation. + * @history 2009-02-12 Jeannie Walldren - Fixed documentation + * to include weblinks. + * @history 2009-07-17 Steven Lambright - Added algorithm include, + * removed macro MAX + * @history 2009-06-10 Jeannie Walldren - Added interpolation + * type CubicHermite. This involved modifying some + * methods, as well as adding variable p_fprimeOfx + * and methods AddCubicHermiteDeriv() and + * EvaluateCubicHermite(). Added Contains() method. + * @history 2009-07-02 Jeannie Walldren - Replaced Hermite + * interpolation algorithm with simpler version and + * added methods EvaluateCubicHermiteFirstDeriv and + * EvaluateCubicHermiteSecDeriv + * @history 2009-07-09 Debbie Cook - Finished Jeannie's + * modifications. + * @history 2009-08-03 Jeannie Walldren - Clean up code, + * documentation and check in changes from + * 2009-06-10, 2009-07-02, 2009-07-09 + * + */ + + class NumericalApproximation { + public: + /** + * This enum defines the types of interpolation supported in this class + */ + enum InterpType { Linear, //!< Linear interpolation. + Polynomial, //!< Polynomial interpolation. + PolynomialNeville, //!< Polynomial interpolation using Neville's algorithm. + CubicNatural, //!< Cubic Spline interpolation with natural boundary conditions. + CubicClamped, //!< Cubic Spline interpolation with clamped boundary conditions. + CubicNatPeriodic, //!< Cubic Spline interpolation with periodic boundary conditions. + CubicNeighborhood, //!< Cubic Spline interpolation using 4-pt Neighborhoods with natural boundary conditions. + CubicHermite, //!< Cubic Spline interpolation using the Hermite cubic polynomial. + Akima, //!< Non-rounded Akima Spline interpolation with natural boundary conditions. + AkimaPeriodic //!< Non-rounded Akima Spline interpolation with periodic boundary conditions. + }; + + // CONSTRUCTORS + NumericalApproximation(const InterpType &itype=CubicNatural) throw (iException &); + NumericalApproximation(unsigned int n, double *x, double *y, + const InterpType &itype=CubicNatural) throw (iException &); + NumericalApproximation(const vector &x, const vector &y, + const InterpType &itype=CubicNatural)throw (iException &); + NumericalApproximation(const NumericalApproximation &dint); + // ASSIGNMENT OPERATOR + NumericalApproximation &operator=(const NumericalApproximation &numApMeth); + // DESTRUCTOR + virtual ~NumericalApproximation (); + + + // ACCESSOR METHODS FOR OBJECT PROPERTIES + string Name() const; + /** + * @brief Returns the enumerated type of interpolation chosen + * + * This method can be selected after all the points are added in the + * interpolation by using Compute() method. + * Note that this prints out as an integer representaion of the + * enumerated type: + *
      + *
    • Linear = 0 + *
    • Polynomial = 1 + *
    • PolynomialNeville = 2 + *
    • CubicNatural = 3 + *
    • CubicClamped = 4 + *
    • CubicNatPeriodic = 5 + *
    • CubicNeighborhood = 6 + *
    • CubicHermite = 7 + *
    • Akima = 8 + *
    • AkimaPeriodic = 9 + *
    + * + * @return NumericalApproximation::InterpType Currently assigned + * interpolation type + */ + inline InterpType InterpolationType() { return (p_itype); } + int MinPoints(); + int MinPoints(InterpType itype) throw (iException &); + + // ADD DATA TO OBJECT + void AddData(const double x, const double y); + void AddData(unsigned int n, double *x, double *y); + void AddData(const vector &x, const vector &y) throw (iException &); + void SetCubicClampedEndptDeriv(const double yp1, const double ypn) throw (iException &); + void AddCubicHermiteDeriv(unsigned int n, double *fprimeOfx) throw (iException &); + void AddCubicHermiteDeriv(const vector &fprimeOfx) throw (iException &); + void AddCubicHermiteDeriv(const double fprimeOfx) throw (iException &); + + //ACCESSOR METHODS AFTER DATA IS ENTERED + double DomainMinimum(); + double DomainMaximum(); + bool Contains(double x); + /** + * Returns the number of the coordinates added to the data set. + * + * @return @b unsigned @b int Size of data set. + */ + inline unsigned int Size() { return(p_x.size()); } + + /** + * This enum defines the manner in which a value outside of the + * domain should be handled if passed to the Evaluate() method. + */ + enum ExtrapType { ThrowError, //!< Evaluate() throws an error if @a a is outside of the domain. + Extrapolate, //!< Evaluate() attempts to extrapolate if @a a is outside of the domain. + //!< This is only valid for NumericalApproximation::InterpType @a CubicClamped or @a PolynomialNeville + //!< and the result will be accurate only if sufficiently close to the domain boundary. + NearestEndpoint //!< Evaluate() returns the y-value of the nearest endpoint if @a a is outside of the domain. + }; + // INTERPOLATION AND EXTRAPOLATION RESULTS + double Evaluate (const double a, const ExtrapType &etype=ThrowError) throw (iException &); + vector Evaluate (const vector &a, const ExtrapType &etype=ThrowError) throw (iException &); + vector PolynomialNevilleErrorEstimate() throw (iException &); + vector CubicClampedSecondDerivatives() throw (iException &); + double EvaluateCubicHermiteFirstDeriv(const double a); + double EvaluateCubicHermiteSecDeriv(const double a); + + // DIFFERENTIATION METHODS + double GslFirstDerivative(const double a) throw (iException &); + double BackwardFirstDifference(const double a, const unsigned int n=3, + const double h=0.1) throw (iException &); + double ForwardFirstDifference(const double a, const unsigned int n=3, + const double h=0.1) throw (iException &); + double CenterFirstDifference(const double a, const unsigned int n=5, + const double h=0.1) throw (iException &); + + double GslSecondDerivative(const double a) throw (iException &); + double BackwardSecondDifference(const double a, const unsigned int n=3, + const double h=0.1) throw (iException &); + double ForwardSecondDifference(const double a, const unsigned int n=3, + const double h=0.1) throw (iException &); + double CenterSecondDifference(const double a, const unsigned int n=5, + const double h=0.1) throw (iException &); + + // INTERGRATION METHODS + double GslIntegral(const double a, const double b) throw (iException &); + double TrapezoidalRule(const double a, const double b); + double Simpsons3PointRule(const double a, const double b); + double Simpsons4PointRule(const double a, const double b); + double BoolesRule(const double a, const double b); + double RefineExtendedTrap (double a, double b, double s, unsigned int n) throw (iException &); + double RombergsMethod (double a, double b) throw (iException &); + + // ASSIGNMENT OPERATORS + void Reset(); + void Reset(InterpType itype) throw (iException &); + void SetInterpType(InterpType itype) throw (iException &); + + protected: + // == CLASS VARIABLES + // VARIABLES FOR ALL INTERP TYPES + InterpType p_itype; //!< Interpolation type + vector p_x; //!< List of X values + vector p_y; //!< List of Y values + bool p_dataValidated; //!< Flag variable to determine whether ValidateDataSet() has been called + // GSL INTERP VARIABLES + typedef const gsl_interp_type * InterpFunctor; //!< GSL Interpolation specs + typedef map FunctorList; //!< Set up a std::map of GSL interpolator functors. List of function types + typedef FunctorList::const_iterator FunctorConstIter; //!< GSL Iterator + gsl_interp_accel *p_acc; //!< Lookup accelorator + gsl_spline *p_interp; //!< Currently active interpolator + FunctorList p_interpFunctors; //!< Maintains list of interpolator options + // CUBIC CLAMPED VARIABLES + bool p_clampedEndptsSet; //!< Flag variable to determine whether SetCubicClampedEndptDeriv() has been called after all data was added for @a CubicClamped interpolation. + bool p_clampedComputed; //!< Flag variable to determine whether ComputeCubicClamped() has been called. + double p_clampedDerivFirstPt; //!< First derivative of first x-value, p_x[0]. This is only used for the @a CubicClamped interpolation type. + double p_clampedDerivLastPt; //!< First derivative of last x-value, p_x[n-1]. This is only used for the @a CubicClamped interpolation type. + vector p_clampedSecondDerivs; //!< List of second derivatives evaluated at p_x values. This is only used for the @a CubicClamped interpolation type. + // POLYNOMIAL NEVILLE VARIABLES + vector p_polyNevError; //!< Estimate of error for interpolation evaluated at x. This is only used for the @a PolynomialNeville interpolation type. 91 taken from AtmosModel. + // CUBIC HERMITE VARIABLES + vector p_fprimeOfx; //!< List of first derivatives corresponding to each x value in the data set (i.e. each value in p_x) + + + // == PROTECTED METHODS + // CREATING, DESTROYING OBJECT + void Init(InterpType itype); + bool GslInterpType(InterpType itype) const; + void GslAllocation(unsigned int npoints); + void GslDeallocation(); + InterpFunctor GslFunctor(InterpType itype) const throw (iException &); + // VERIFICATION METHODS + void GslIntegrityCheck(int gsl_status, char *src, + int line) throw (iException &); + void ValidateDataSet() throw (iException &); + bool InsideDomain(const double a); + // COMPUTATION AND EVALUATION METHODS + bool GslComputed() const; + void ComputeGsl() throw (iException &); + void ComputeCubicClamped() throw (iException &); + double ValueToExtrapolate(const double a, const ExtrapType &etype); + double EvaluateCubicNeighborhood(const double a); + vector EvaluateCubicNeighborhood(const vector &a, const ExtrapType &etype); + double EvaluateCubicClamped(const double a) throw (iException &); + double EvaluateCubicHermite(const double a) throw (iException &); + double EvaluatePolynomialNeville(const double a) throw (iException &); + vector EvaluateForIntegration(const double a, const double b, + const unsigned int n) throw (iException &); + int FindIntervalLowerIndex(const double a); + // STANDARDIZE ERRORS + void ReportException(iException::errType type, const string &method, + const string &message, char *filesrc, + int lineno) const throw (iException &); + }; +}; + +#endif diff --git a/isis/src/base/objs/NumericalApproximation/NumericalApproximation.truth b/isis/src/base/objs/NumericalApproximation/NumericalApproximation.truth new file mode 100644 index 0000000000000000000000000000000000000000..553ab8b5e89a81cc02c3619a49f3b473440fc144 --- /dev/null +++ b/isis/src/base/objs/NumericalApproximation/NumericalApproximation.truth @@ -0,0 +1,225 @@ + +Unit test for NumericalApproximation +Using the function f(x) = x^3 + x^2 + x + +1) Creating objects, accessing properties +Valid interpolation types include: +type name minpoints +0 linear 2 +1 polynomial 3 +2 polynomial-Neville's 3 +3 cspline-natural 3 +4 cspline-clamped 3 +5 cspline-periodic 2 +6 cspline-neighborhood 4 +7 cspline-Hermite 2 +8 akima 5 +9 akima-periodic 5 +EXCEPTIONS: +**PROGRAMMER ERROR** SetInterpType() - Invalid argument. Unknown interpolation type: 11 + ************************************************ + +Test constructors: +object type name +interp1 3 cspline-natural +interp2 3 cspline-natural +interp3 3 cspline-natural +interp4 4 cspline-clamped +interp5 2 polynomial-Neville's +interp6 7 cspline-Hermite + +EXCEPTIONS: +**PROGRAMMER ERROR** NumericalApproximation() - Unable to construct an object using the given vectors and interpolation type +**PROGRAMMER ERROR** AddData() - Invalid arguments. The sizes of the input vectors do not match + ************************************************ + +Add data, set properties: +d = 0 is an x element of dataset? 1 +d = 0.01 is an x element of dataset? 0 +d = 0.02 is an x element of dataset? 0 +d = 0.03 is an x element of dataset? 0 +d = 0.04 is an x element of dataset? 1 + +description size domain +cspline-natural, regularly spaced 21 [0, 0.8] +cspline-natural, irregularly spaced 21 [0, 0.8] +cspline-neighborhood, irregularly spaced 21 [0, 0.8] +cspline-clamped, irregularly spaced 21 [0, 0.8] +polynomial-Neville's, irregularly spaced 21 [0, 0.8] + +EXCEPTIONS: +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - Invalid data set, x-values must be in ascending order for cspline-natural interpolation: + x[20] = 0.8 > x[21] = 0.0 +**PROGRAMMER ERROR** DomainMaximum() - Unable to calculate the domain maximum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - cspline-natural interpolation requires a minimum of 3 data points - currently have 0 +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.5 +**PROGRAMMER ERROR** ComputeCubicClamped() - Must set endpoint derivative values after adding data in order to compute cubic spline with clamped boundary conditions +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.5 +**PROGRAMMER ERROR** ComputeCubicClamped() - Must set endpoint derivative values after adding data in order to compute cubic spline with clamped boundary conditions +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ValidateDataSet() - Invalid data set, x-values must be in ascending order for cspline-clamped interpolation: + x[21] = 0.9 > x[22] = 0.5 +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - First and last points of the data set must have the same y-value for cspline-periodicinterpolation to prevent discontinuity at the boundary + ************************************************ + + +2) Dataset Interpolation: +Evaluated points: +x y c-nat-regular c-nat-irreg c-neigh c-clamped p-neville c-hermite +0.05 0.052625 0.0525871 0.0528784 0.0529363 0.052625 0.052625 0.052625 +0.15 0.175875 0.175873 0.175905 0.175647 0.175875 0.175875 0.175875 +0.25 0.328125 0.328125 0.328125 0.32802 0.328125 0.328125 0.328125 +0.35 0.515375 0.515375 0.515375 0.515329 0.515375 0.515375 0.515375 +0.45 0.743625 0.743625 0.743625 0.743474 0.743625 0.743625 0.743625 +0.55 1.01887 1.01888 1.01887 1.01867 1.01887 1.01888 1.01887 +0.65 1.34712 1.34712 1.34712 1.34697 1.34712 1.34713 1.34712 +0.75 1.73437 1.73425 1.73424 1.73407 1.73438 1.73438 1.73437 +Errors: (difference from y-value) +x c-nat-regular c-nat-irreg c-neigh c-clamped p-neville-trueErr p-neville-estimErr c-herm +0.05 -3.79165e-05 0.000253378 0.00031133 -6.93889e-18 -1.7107e-10 -8.06534e-11 0 +0.15 -1.50265e-06 2.9835e-05 -0.00022794 0 -1.04902e-12 -4.10234e-13 2.77556e-17 +0.25 5.23612e-08 -3.65474e-07 -0.000105006 0 9.82547e-15 2.78089e-15 0 +0.35 1.82955e-09 -2.65526e-09 -4.63289e-05 1.11022e-16 0 5.22482e-18 1.11022e-16 +0.45 6.98432e-09 -5.86827e-09 -0.000151105 0 3.33067e-16 -6.89075e-17 -1.11022e-16 +0.55 1.78058e-07 -9.69423e-08 -0.0002096 0 7.10543e-15 -4.58751e-15 0 +0.65 -5.10901e-06 -1.30783e-06 -0.00015885 0 6.75016e-14 -1.11913e-13 -2.22045e-16 +0.75 -0.000128916 -0.000133122 -0.000302098 6.66134e-16 2.71994e-11 -1.8922e-10 0 + +3) Dataset Extrapolation: + Notice: Clamped cubic spline accurate if extrapolating cubic function. +type a Domain {ymin,ymax} NearestEndpoint Extrapolate y(a) +cspline-clamped -1.5 [0,0.8] {0,1.952} 0 -2.625 -2.625 +cspline-clamped -1.3 [0,0.8] {0,1.952} 0 -1.807 -1.807 +cspline-clamped -1.1 [0,0.8] {0,1.952} 0 -1.221 -1.221 +cspline-clamped -0.9 [0,0.8] {0,1.952} 0 -0.819 -0.819 +cspline-clamped -0.7 [0,0.8] {0,1.952} 0 -0.553 -0.553 +cspline-clamped -0.5 [0,0.8] {0,1.952} 0 -0.375 -0.375 +cspline-clamped -0.3 [0,0.8] {0,1.952} 0 -0.237 -0.237 +cspline-clamped -0.1 [0,0.8] {0,1.952} 0 -0.091 -0.091 +polynomial-Neville's 0.801 [0,0.8] {0,1.952} 1.952 1.95652 1.95652 +polynomial-Neville's 0.901 [0,0.8] {0,1.952} 1.952 2.44423 2.44423 +polynomial-Neville's 1.001 [0,0.8] {0,1.952} 1.952 3.00598 3.006 +polynomial-Neville's 1.101 [0,0.8] {0,1.952} 1.952 3.64691 3.64783 +polynomial-Neville's 1.201 [0,0.8] {0,1.952} 1.952 4.35663 4.37572 +polynomial-Neville's 1.301 [0,0.8] {0,1.952} 1.952 4.8834 5.19567 +polynomial-Neville's 1.401 [0,0.8] {0,1.952} 1.952 -130.307 6.11369 + Notice: In general, accuracy declines farther from domain endpoints. + ************************************************ +EXCEPTIONS: +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Value entered, a = 0.9, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Cannot extrapolate for type cspline-natural, must choose to throw error or return nearest neighbor +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Cannot extrapolate for type cspline-neighborhood, must choose to throw error or return nearest neighbor +**PROGRAMMER ERROR** PolynomialNevilleErrorEstimate() - This method is only valid for polynomial-Neville's, may not be used for cspline-natural interpolation +**PROGRAMMER ERROR** PolynomialNevilleErrorEstimate() - Error not calculated. This method only valid after Evaluate() has been called + ************************************************ + +4) Differentiation Approximation: +GSL First derivative method errors: +a y'(a) Err:natural-reg Err:natural-irreg +0.05 1.1075 -0.0016784 -0.0138232 +0.35 2.0675 -2.11708e-07 1.40745e-07 +0.65 3.5675 -0.000547938 -0.000136049 +First difference method errors: +a y'(a) 2ptBack-Neigh 3ptBack-Neigh 2ptFor-Clamp 3ptFor-Clamp 3ptCtr-Neville 5ptCtr-Neville +0.15 1.3675 -0.0180999 -0.00196076 0.0146 -0.0002 0.0001 1.56131e-10 +0.45 2.5075 -0.0385105 -0.0271011 0.0236 -0.0002 0.0001 5.06262e-14 +0.75 4.1875 -0.0309367 0.00292015 0.0326 -0.0002 0.000100001 1.09721e-09 + + -------------------------- +GSL Second derivative method errors: +a y''(a) Err:natural-reg Err:natural-irreg +0.15 2.9 0.00188678 -0.0590771 +0.45 4.7 -8.16229e-06 -1.0402e-05 +0.75 6.5 1.24449 0.155058 +Second difference method errors: +a y'(a) 3ptBack-Neigh 3ptFor-Clamp 3ptCtr-Neville 5ptCtr-Neville +0.15 2.9 0.327829 0.06 3.12551e-08 3.73296e-08 +0.45 4.7 -2.41811 0.06 4.14602e-12 3.68416e-12 +0.75 6.5 0.271365 0.06 -1.42282e-08 -1.23749e-08 +CubicClampedSecondDerivatives(): +xi actual2ndDeriv calculated2ndDeriv +0 2 2 +0.07 2.42 2.42 +0.12 2.72 2.72 +0.19 3.14 3.14 +0.22 3.32 3.32 +0.23 3.38 3.38 +0.32 3.92 3.92 +0.34 4.04 4.04 +0.36 4.16 4.16 +0.39 4.34 4.34 +0.4 4.4 4.4 +0.41 4.46 4.46 +0.44 4.64 4.64 +0.49 4.94 4.94 +0.54 5.24 5.24 +0.59 5.54 5.54 +0.64 5.84 5.84 +0.68 6.08 6.08 +0.7 6.2 6.2 +0.79 6.74 6.74 +0.8 6.8 6.8 + +EXCEPTIONS: +**PROGRAMMER ERROR** GslFirstDerivative() - Invalid argument. Value entered, a = 1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** GslFirstDerivative() - Unable to compute the first derivative at a = 0.2 using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** BackwardFirstDifference() - Invalid argument. Value entered, a = -1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** BackwardFirstDifference() - Formula steps outside of domain. For 2-point backward difference, a-(n-1)h = -0.09 is smaller than domain min = 0.0. Try forward difference or use smaller value for h or n +**PROGRAMMER ERROR** BackwardFirstDifference() - Invalid argument. There is no 4-point backward difference formula in use +**PROGRAMMER ERROR** ForwardFirstDifference() - Invalid argument. Value entered, a = -0.01, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** ForwardFirstDifference() - Formula steps outside of domain. For 3-point forward difference, a+(n-1)h = 0.95 is greater than domain max = 0.8. Try backward difference or use smaller value for h or n +**PROGRAMMER ERROR** ForwardFirstDifference() - Invalid argument. There is no 4-point forward difference formula in use +**PROGRAMMER ERROR** CenterFirstDifference() - Invalid argument. Value entered, a = 0.81, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** CenterFirstDifference() - Formula steps outside of domain. For 5-point center difference, a-(n-1)h = -0.39 or a+(n-1)h = 0.41 is out of domain = [0.0, 0.8]. Use smaller value for h or n +**PROGRAMMER ERROR** CenterFirstDifference() - Invalid argument. There is no 4-point center difference formula in use +**PROGRAMMER ERROR** GslSecondDerivative() - Invalid argument. Value entered, a = 1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** GslSecondDerivative() - Unable to compute the second derivative at a = 0.8 using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** BackwardSecondDifference() - Invalid argument. Value entered, a = -1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** BackwardSecondDifference() - Formula steps outside of domain. For 3-point backward difference, a-(n-1)h = -0.19 is smaller than domain min = 0.0. Try forward difference or use smaller value for h or n +**PROGRAMMER ERROR** BackwardSecondDifference() - Invalid argument. There is no 2-point backward second difference formula in use +**PROGRAMMER ERROR** ForwardSecondDifference() - Invalid argument. Value entered, a = -0.01, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** ForwardSecondDifference() - Formula steps outside of domain. For 3-point forward difference, a+(n-1)h = 0.95 is greater than domain max = 0.8. Try backward difference or use smaller value for h or n +**PROGRAMMER ERROR** ForwardSecondDifference() - Invalid argument. There is no 2-point forward second difference formula in use +**PROGRAMMER ERROR** CenterSecondDifference() - Invalid argument. Value entered, a = 0.81, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** CenterSecondDifference() - Formula steps outside of domain. For 5-point center difference, a-(n-1)h = -0.39 or a+(n-1)h = 0.41 is out of domain = [0.0, 0.8]. Use smaller value for h or n +**PROGRAMMER ERROR** CenterSecondDifference() - Invalid argument. There is no 4-point center second difference formula in use + ************************************************ + +5) Integration Approximation: +GSL Integral method errors: +(a,b) Y(b)-Y(a) Err:c-nat-reg Err:c-nat-irreg +(0,0.8) 0.593067 1.35485e-05 1.14534e-05 +(0,0.5) 0.182292 3.07896e-06 1.86016e-05 +(0,0.2) 0.0230667 3.08345e-06 1.86464e-05 +(0.3,0.8) 0.537042 1.04692e-05 -7.14968e-06 +(0.3,0.5) 0.126267 -3.07786e-10 -1.40653e-09 +(0.6,0.8) 0.308667 1.04837e-05 -7.1442e-06 +Quadrature method errors: +(a,b) Y(b)-Y(a) Trap-Neigh Simp3pt-Neigh Simp4pt-Clamp Boole-Clamp ExtTrap-Nev Romberg-Nev +(0,0.8) 0.593067 0.000400496 -6.1384e-05 0 -1.11022e-16 -0.296534 -1.05869e-11 +(0,0.5) 0.182292 6.36444e-05 -2.47352e-05 -2.77556e-17 2.77556e-17 -0.091146 -2.98287e-11 +(0,0.2) 0.0230667 9.49862e-06 5.4552e-06 0 -6.93889e-18 -0.0115333 -2.19562e-11 +(0.3,0.8) 0.537042 6.04423e-05 -8.09038e-05 -2.22045e-16 -1.11022e-16 -0.268521 2.04381e-12 +(0.3,0.5) 0.126267 -7.1205e-06 -1.45287e-05 0 0 -0.0631333 8.32667e-17 +(0.6,0.8) 0.308667 -2.36812e-05 -3.50883e-05 -5.55112e-17 -5.55112e-17 -0.154333 1.56219e-12 + +EXCEPTIONS: +**PROGRAMMER ERROR** GslIntegral() - Invalid interval entered: [a,b] = [1.1, 1.0] +**PROGRAMMER ERROR** GslIntegral() - Invalid arguments. Interval entered [1.0, 1.1] is not contained within domain [0.0, 0.8] +**PROGRAMMER ERROR** GslIntegral() - Unable to compute the integral on the interval (a,b) = (0.0, 0.8) using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** TrapezoidalRule() - Unable to calculate the integral on the interval (a,b) = (0.81, 0.7) using the trapeziodal rule +**PROGRAMMER ERROR** EvaluatedForIntegration() - Invalid interval entered: [a,b] = [0.81, 0.7] +**PROGRAMMER ERROR** TrapezoidalRule() - Unable to calculate the integral on the interval (a,b) = (-0.1, 0.7) using the trapeziodal rule +**PROGRAMMER ERROR** EvaluateForIntegration() - Invalid arguments. Interval entered [-0.1, 0.7] is not contained within domain [0.0, 0.8] + ************************************************ diff --git a/isis/src/base/objs/NumericalApproximation/NumericalApproximation_Darwin_powerpc.truth b/isis/src/base/objs/NumericalApproximation/NumericalApproximation_Darwin_powerpc.truth new file mode 100644 index 0000000000000000000000000000000000000000..2f10cad7a8057f1fd8c3db51023e470011524bc1 --- /dev/null +++ b/isis/src/base/objs/NumericalApproximation/NumericalApproximation_Darwin_powerpc.truth @@ -0,0 +1,225 @@ + +Unit test for NumericalApproximation +Using the function f(x) = x^3 + x^2 + x + +1) Creating objects, accessing properties +Valid interpolation types include: +type name minpoints +0 linear 2 +1 polynomial 3 +2 polynomial-Neville's 3 +3 cspline-natural 3 +4 cspline-clamped 3 +5 cspline-periodic 2 +6 cspline-neighborhood 4 +7 cspline-Hermite 2 +8 akima 5 +9 akima-periodic 5 +EXCEPTIONS: +**PROGRAMMER ERROR** SetInterpType() - Invalid argument. Unknown interpolation type: 11 + ************************************************ + +Test constructors: +object type name +interp1 3 cspline-natural +interp2 3 cspline-natural +interp3 3 cspline-natural +interp4 4 cspline-clamped +interp5 2 polynomial-Neville's +interp6 7 cspline-Hermite + +EXCEPTIONS: +**PROGRAMMER ERROR** NumericalApproximation() - Unable to construct an object using the given vectors and interpolation type +**PROGRAMMER ERROR** AddData() - Invalid arguments. The sizes of the input vectors do not match + ************************************************ + +Add data, set properties: +d = 0 is an x element of dataset? 1 +d = 0.01 is an x element of dataset? 0 +d = 0.02 is an x element of dataset? 0 +d = 0.03 is an x element of dataset? 0 +d = 0.04 is an x element of dataset? 1 + +description size domain +cspline-natural, regularly spaced 21 [0, 0.8] +cspline-natural, irregularly spaced 21 [0, 0.8] +cspline-neighborhood, irregularly spaced 21 [0, 0.8] +cspline-clamped, irregularly spaced 21 [0, 0.8] +polynomial-Neville's, irregularly spaced 21 [0, 0.8] + +EXCEPTIONS: +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - Invalid data set, x-values must be in ascending order for cspline-natural interpolation: + x[20] = 0.8 > x[21] = 0.0 +**PROGRAMMER ERROR** DomainMaximum() - Unable to calculate the domain maximum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - cspline-natural interpolation requires a minimum of 3 data points - currently have 0 +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.5 +**PROGRAMMER ERROR** ComputeCubicClamped() - Must set endpoint derivative values after adding data in order to compute cubic spline with clamped boundary conditions +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.5 +**PROGRAMMER ERROR** ComputeCubicClamped() - Must set endpoint derivative values after adding data in order to compute cubic spline with clamped boundary conditions +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ValidateDataSet() - Invalid data set, x-values must be in ascending order for cspline-clamped interpolation: + x[21] = 0.9 > x[22] = 0.5 +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - First and last points of the data set must have the same y-value for cspline-periodicinterpolation to prevent discontinuity at the boundary + ************************************************ + + +2) Dataset Interpolation: +Evaluated points: +x y c-nat-regular c-nat-irreg c-neigh c-clamped p-neville c-hermite +0.05 0.052625 0.0525871 0.0528784 0.0529363 0.052625 0.052625 0.052625 +0.15 0.175875 0.175873 0.175905 0.175647 0.175875 0.175875 0.175875 +0.25 0.328125 0.328125 0.328125 0.32802 0.328125 0.328125 0.328125 +0.35 0.515375 0.515375 0.515375 0.515329 0.515375 0.515375 0.515375 +0.45 0.743625 0.743625 0.743625 0.743474 0.743625 0.743625 0.743625 +0.55 1.01887 1.01888 1.01887 1.01867 1.01887 1.01888 1.01887 +0.65 1.34712 1.34712 1.34712 1.34697 1.34712 1.34713 1.34712 +0.75 1.73437 1.73425 1.73424 1.73407 1.73437 1.73438 1.73437 +Errors: (difference from y-value) +x c-nat-regular c-nat-irreg c-neigh c-clamped p-neville-trueErr p-neville-estimErr c-herm +0.05 -3.79165e-05 0.000253378 0.00031133 -6.93889e-18 -1.71228e-10 -8.0756e-11 0 +0.15 -1.50265e-06 2.9835e-05 -0.00022794 0 -1.04994e-12 -4.10756e-13 0 +0.25 5.23612e-08 -3.65474e-07 -0.000105006 0 9.88098e-15 2.78443e-15 0 +0.35 1.82955e-09 -2.65526e-09 -4.63289e-05 1.11022e-16 0 5.23176e-18 1.11022e-16 +0.45 6.98432e-09 -5.86827e-09 -0.000151105 1.11022e-16 3.33067e-16 -6.89934e-17 -1.11022e-16 +0.55 1.78058e-07 -9.69423e-08 -0.0002096 2.22045e-16 7.32747e-15 -4.59239e-15 0 +0.65 -5.10901e-06 -1.30783e-06 -0.00015885 0 6.72795e-14 -1.12044e-13 0 +0.75 -0.000128916 -0.000133122 -0.000302098 0 2.72515e-11 -1.89444e-10 0 + +3) Dataset Extrapolation: + Notice: Clamped cubic spline accurate if extrapolating cubic function. +type a Domain {ymin,ymax} NearestEndpoint Extrapolate y(a) +cspline-clamped -1.5 [0,0.8] {0,1.952} 0 -2.625 -2.625 +cspline-clamped -1.3 [0,0.8] {0,1.952} 0 -1.807 -1.807 +cspline-clamped -1.1 [0,0.8] {0,1.952} 0 -1.221 -1.221 +cspline-clamped -0.9 [0,0.8] {0,1.952} 0 -0.819 -0.819 +cspline-clamped -0.7 [0,0.8] {0,1.952} 0 -0.553 -0.553 +cspline-clamped -0.5 [0,0.8] {0,1.952} 0 -0.375 -0.375 +cspline-clamped -0.3 [0,0.8] {0,1.952} 0 -0.237 -0.237 +cspline-clamped -0.1 [0,0.8] {0,1.952} 0 -0.091 -0.091 +polynomial-Neville's 0.801 [0,0.8] {0,1.952} 1.952 1.95652 1.95652 +polynomial-Neville's 0.901 [0,0.8] {0,1.952} 1.952 2.44423 2.44423 +polynomial-Neville's 1.001 [0,0.8] {0,1.952} 1.952 3.00598 3.006 +polynomial-Neville's 1.101 [0,0.8] {0,1.952} 1.952 3.64692 3.64783 +polynomial-Neville's 1.201 [0,0.8] {0,1.952} 1.952 4.35679 4.37572 +polynomial-Neville's 1.301 [0,0.8] {0,1.952} 1.952 4.88529 5.19567 +polynomial-Neville's 1.401 [0,0.8] {0,1.952} 1.952 -130.286 6.11369 + Notice: In general, accuracy declines farther from domain endpoints. + ************************************************ +EXCEPTIONS: +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Value entered, a = 0.9, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Cannot extrapolate for type cspline-natural, must choose to throw error or return nearest neighbor +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Cannot extrapolate for type cspline-neighborhood, must choose to throw error or return nearest neighbor +**PROGRAMMER ERROR** PolynomialNevilleErrorEstimate() - This method is only valid for polynomial-Neville's, may not be used for cspline-natural interpolation +**PROGRAMMER ERROR** PolynomialNevilleErrorEstimate() - Error not calculated. This method only valid after Evaluate() has been called + ************************************************ + +4) Differentiation Approximation: +GSL First derivative method errors: +a y'(a) Err:natural-reg Err:natural-irreg +0.05 1.1075 -0.0016784 -0.0138232 +0.35 2.0675 -2.11708e-07 1.40745e-07 +0.65 3.5675 -0.000547938 -0.000136049 +First difference method errors: +a y'(a) 2ptBack-Neigh 3ptBack-Neigh 2ptFor-Clamp 3ptFor-Clamp 3ptCtr-Neville 5ptCtr-Neville +0.15 1.3675 -0.0180999 -0.00196076 0.0146 -0.0002 0.0001 1.56173e-10 +0.45 2.5075 -0.0385105 -0.0271011 0.0236 -0.0002 0.0001 5.06262e-14 +0.75 4.1875 -0.0309367 0.00292015 0.0326 -0.0002 0.000100001 1.09908e-09 + + -------------------------- +GSL Second derivative method errors: +a y''(a) Err:natural-reg Err:natural-irreg +0.15 2.9 0.00188678 -0.0590771 +0.45 4.7 -8.16229e-06 -1.0402e-05 +0.75 6.5 1.24449 0.155058 +Second difference method errors: +a y'(a) 3ptBack-Neigh 3ptFor-Clamp 3ptCtr-Neville 5ptCtr-Neville +0.15 2.9 0.327829 0.06 3.12551e-08 3.73286e-08 +0.45 4.7 -2.41811 0.06 4.14602e-12 5.16387e-12 +0.75 6.5 0.271365 0.06 -1.42304e-08 -1.2369e-08 +CubicClampedSecondDerivatives(): +xi actual2ndDeriv calculated2ndDeriv +0 2 2 +0.07 2.42 2.42 +0.12 2.72 2.72 +0.19 3.14 3.14 +0.22 3.32 3.32 +0.23 3.38 3.38 +0.32 3.92 3.92 +0.34 4.04 4.04 +0.36 4.16 4.16 +0.39 4.34 4.34 +0.4 4.4 4.4 +0.41 4.46 4.46 +0.44 4.64 4.64 +0.49 4.94 4.94 +0.54 5.24 5.24 +0.59 5.54 5.54 +0.64 5.84 5.84 +0.68 6.08 6.08 +0.7 6.2 6.2 +0.79 6.74 6.74 +0.8 6.8 6.8 + +EXCEPTIONS: +**PROGRAMMER ERROR** GslFirstDerivative() - Invalid argument. Value entered, a = 1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** GslFirstDerivative() - Unable to compute the first derivative at a = 0.2 using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** BackwardFirstDifference() - Invalid argument. Value entered, a = -1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** BackwardFirstDifference() - Formula steps outside of domain. For 2-point backward difference, a-(n-1)h = -0.09 is smaller than domain min = 0.0. Try forward difference or use smaller value for h or n +**PROGRAMMER ERROR** BackwardFirstDifference() - Invalid argument. There is no 4-point backward difference formula in use +**PROGRAMMER ERROR** ForwardFirstDifference() - Invalid argument. Value entered, a = -0.01, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** ForwardFirstDifference() - Formula steps outside of domain. For 3-point forward difference, a+(n-1)h = 0.95 is greater than domain max = 0.8. Try backward difference or use smaller value for h or n +**PROGRAMMER ERROR** ForwardFirstDifference() - Invalid argument. There is no 4-point forward difference formula in use +**PROGRAMMER ERROR** CenterFirstDifference() - Invalid argument. Value entered, a = 0.81, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** CenterFirstDifference() - Formula steps outside of domain. For 5-point center difference, a-(n-1)h = -0.39 or a+(n-1)h = 0.41 is out of domain = [0.0, 0.8]. Use smaller value for h or n +**PROGRAMMER ERROR** CenterFirstDifference() - Invalid argument. There is no 4-point center difference formula in use +**PROGRAMMER ERROR** GslSecondDerivative() - Invalid argument. Value entered, a = 1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** GslSecondDerivative() - Unable to compute the second derivative at a = 0.8 using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** BackwardSecondDifference() - Invalid argument. Value entered, a = -1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** BackwardSecondDifference() - Formula steps outside of domain. For 3-point backward difference, a-(n-1)h = -0.19 is smaller than domain min = 0.0. Try forward difference or use smaller value for h or n +**PROGRAMMER ERROR** BackwardSecondDifference() - Invalid argument. There is no 2-point backward second difference formula in use +**PROGRAMMER ERROR** ForwardSecondDifference() - Invalid argument. Value entered, a = -0.01, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** ForwardSecondDifference() - Formula steps outside of domain. For 3-point forward difference, a+(n-1)h = 0.95 is greater than domain max = 0.8. Try backward difference or use smaller value for h or n +**PROGRAMMER ERROR** ForwardSecondDifference() - Invalid argument. There is no 2-point forward second difference formula in use +**PROGRAMMER ERROR** CenterSecondDifference() - Invalid argument. Value entered, a = 0.81, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** CenterSecondDifference() - Formula steps outside of domain. For 5-point center difference, a-(n-1)h = -0.39 or a+(n-1)h = 0.41 is out of domain = [0.0, 0.8]. Use smaller value for h or n +**PROGRAMMER ERROR** CenterSecondDifference() - Invalid argument. There is no 4-point center second difference formula in use + ************************************************ + +5) Integration Approximation: +GSL Integral method errors: +(a,b) Y(b)-Y(a) Err:c-nat-reg Err:c-nat-irreg +(0,0.8) 0.593067 1.35485e-05 1.14534e-05 +(0,0.5) 0.182292 3.07896e-06 1.86016e-05 +(0,0.2) 0.0230667 3.08345e-06 1.86464e-05 +(0.3,0.8) 0.537042 1.04692e-05 -7.14968e-06 +(0.3,0.5) 0.126267 -3.07786e-10 -1.40653e-09 +(0.6,0.8) 0.308667 1.04837e-05 -7.1442e-06 +Quadrature method errors: +(a,b) Y(b)-Y(a) Trap-Neigh Simp3pt-Neigh Simp4pt-Clamp Boole-Clamp ExtTrap-Nev Romberg-Nev +(0,0.8) 0.593067 0.000400496 -6.1384e-05 -1.11022e-16 -2.22045e-16 -0.296534 -1.05946e-11 +(0,0.5) 0.182292 6.36444e-05 -2.47352e-05 -2.77556e-17 2.77556e-17 -0.091146 -2.98565e-11 +(0,0.2) 0.0230667 9.49862e-06 5.4552e-06 0 -6.93889e-18 -0.0115333 -2.19879e-11 +(0.3,0.8) 0.537042 6.04423e-05 -8.09038e-05 -2.22045e-16 -1.11022e-16 -0.268521 2.04792e-12 +(0.3,0.5) 0.126267 -7.1205e-06 -1.45287e-05 2.77556e-17 0 -0.0631333 8.32667e-17 +(0.6,0.8) 0.308667 -2.36812e-05 -3.50883e-05 -1.11022e-16 -1.11022e-16 -0.154333 1.56536e-12 + +EXCEPTIONS: +**PROGRAMMER ERROR** GslIntegral() - Invalid interval entered: [a,b] = [1.1, 1.0] +**PROGRAMMER ERROR** GslIntegral() - Invalid arguments. Interval entered [1.0, 1.1] is not contained within domain [0.0, 0.8] +**PROGRAMMER ERROR** GslIntegral() - Unable to compute the integral on the interval (a,b) = (0.0, 0.8) using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** TrapezoidalRule() - Unable to calculate the integral on the interval (a,b) = (0.81, 0.7) using the trapeziodal rule +**PROGRAMMER ERROR** EvaluatedForIntegration() - Invalid interval entered: [a,b] = [0.81, 0.7] +**PROGRAMMER ERROR** TrapezoidalRule() - Unable to calculate the integral on the interval (a,b) = (-0.1, 0.7) using the trapeziodal rule +**PROGRAMMER ERROR** EvaluateForIntegration() - Invalid arguments. Interval entered [-0.1, 0.7] is not contained within domain [0.0, 0.8] + ************************************************ diff --git a/isis/src/base/objs/NumericalApproximation/NumericalApproximation_Linux_i686_RedHat5_4.truth b/isis/src/base/objs/NumericalApproximation/NumericalApproximation_Linux_i686_RedHat5_4.truth new file mode 100644 index 0000000000000000000000000000000000000000..03a23099b49f5b5481819a06ea4dc403de8dfb48 --- /dev/null +++ b/isis/src/base/objs/NumericalApproximation/NumericalApproximation_Linux_i686_RedHat5_4.truth @@ -0,0 +1,225 @@ + +Unit test for NumericalApproximation +Using the function f(x) = x^3 + x^2 + x + +1) Creating objects, accessing properties +Valid interpolation types include: +type name minpoints +0 linear 2 +1 polynomial 3 +2 polynomial-Neville's 3 +3 cspline-natural 3 +4 cspline-clamped 3 +5 cspline-periodic 2 +6 cspline-neighborhood 4 +7 cspline-Hermite 2 +8 akima 5 +9 akima-periodic 5 +EXCEPTIONS: +**PROGRAMMER ERROR** SetInterpType() - Invalid argument. Unknown interpolation type: 11 + ************************************************ + +Test constructors: +object type name +interp1 3 cspline-natural +interp2 3 cspline-natural +interp3 3 cspline-natural +interp4 4 cspline-clamped +interp5 2 polynomial-Neville's +interp6 7 cspline-Hermite + +EXCEPTIONS: +**PROGRAMMER ERROR** NumericalApproximation() - Unable to construct an object using the given vectors and interpolation type +**PROGRAMMER ERROR** AddData() - Invalid arguments. The sizes of the input vectors do not match + ************************************************ + +Add data, set properties: +d = 0 is an x element of dataset? 1 +d = 0.01 is an x element of dataset? 0 +d = 0.02 is an x element of dataset? 0 +d = 0.03 is an x element of dataset? 0 +d = 0.04 is an x element of dataset? 1 + +description size domain +cspline-natural, regularly spaced 21 [0, 0.8] +cspline-natural, irregularly spaced 21 [0, 0.8] +cspline-neighborhood, irregularly spaced 21 [0, 0.8] +cspline-clamped, irregularly spaced 21 [0, 0.8] +polynomial-Neville's, irregularly spaced 21 [0, 0.8] + +EXCEPTIONS: +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - Invalid data set, x-values must be in ascending order for cspline-natural interpolation: + x[20] = 0.8 > x[21] = 0.0 +**PROGRAMMER ERROR** DomainMaximum() - Unable to calculate the domain maximum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - cspline-natural interpolation requires a minimum of 3 data points - currently have 0 +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.5 +**PROGRAMMER ERROR** ComputeCubicClamped() - Must set endpoint derivative values after adding data in order to compute cubic spline with clamped boundary conditions +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.5 +**PROGRAMMER ERROR** ComputeCubicClamped() - Must set endpoint derivative values after adding data in order to compute cubic spline with clamped boundary conditions +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ValidateDataSet() - Invalid data set, x-values must be in ascending order for cspline-clamped interpolation: + x[21] = 0.9 > x[22] = 0.5 +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - First and last points of the data set must have the same y-value for cspline-periodicinterpolation to prevent discontinuity at the boundary + ************************************************ + + +2) Dataset Interpolation: +Evaluated points: +x y c-nat-regular c-nat-irreg c-neigh c-clamped p-neville c-hermite +0.05 0.052625 0.0525871 0.0528784 0.0529363 0.052625 0.052625 0.052625 +0.15 0.175875 0.175873 0.175905 0.175647 0.175875 0.175875 0.175875 +0.25 0.328125 0.328125 0.328125 0.32802 0.328125 0.328125 0.328125 +0.35 0.515375 0.515375 0.515375 0.515329 0.515375 0.515375 0.515375 +0.45 0.743625 0.743625 0.743625 0.743474 0.743625 0.743625 0.743625 +0.55 1.01887 1.01888 1.01887 1.01867 1.01887 1.01887 1.01887 +0.65 1.34712 1.34712 1.34712 1.34697 1.34712 1.34712 1.34712 +0.75 1.73437 1.73425 1.73424 1.73407 1.73437 1.73437 1.73437 +Errors: (difference from y-value) +x c-nat-regular c-nat-irreg c-neigh c-clamped p-neville-trueErr p-neville-estimErr c-herm +0.05 -3.79165e-05 0.000253378 0.00031133 -4.90601e-18 2.68408e-10 1.24404e-10 -4.90601e-18 +0.15 -1.50265e-06 2.9835e-05 -0.00022794 9.48677e-19 1.72651e-12 6.57385e-13 9.48677e-19 +0.25 5.23612e-08 -3.65474e-07 -0.000105006 0 -1.67089e-14 -4.50315e-15 0 +0.35 1.82955e-09 -2.65526e-09 -4.63289e-05 -3.75676e-17 -1.4859e-16 -8.44769e-18 -3.75676e-17 +0.45 6.98432e-09 -5.86827e-09 -0.000151105 -1.91904e-17 -9.07369e-16 1.0563e-16 -1.91904e-17 +0.55 1.78058e-07 -9.69423e-08 -0.0002096 -4.66207e-17 -1.24811e-14 7.20647e-15 -4.66207e-17 +0.65 -5.10901e-06 -1.30783e-06 -0.00015885 6.50521e-19 -1.05693e-13 1.77221e-13 6.50521e-19 +0.75 -0.000128916 -0.000133122 -0.000302098 2.08167e-17 -4.22318e-11 2.96468e-10 2.08167e-17 + +3) Dataset Extrapolation: + Notice: Clamped cubic spline accurate if extrapolating cubic function. +type a Domain {ymin,ymax} NearestEndpoint Extrapolate y(a) +cspline-clamped -1.5 [0,0.8] {0,1.952} 0 -2.625 -2.625 +cspline-clamped -1.3 [0,0.8] {0,1.952} 0 -1.807 -1.807 +cspline-clamped -1.1 [0,0.8] {0,1.952} 0 -1.221 -1.221 +cspline-clamped -0.9 [0,0.8] {0,1.952} 0 -0.819 -0.819 +cspline-clamped -0.7 [0,0.8] {0,1.952} 0 -0.553 -0.553 +cspline-clamped -0.5 [0,0.8] {0,1.952} 0 -0.375 -0.375 +cspline-clamped -0.3 [0,0.8] {0,1.952} 0 -0.237 -0.237 +cspline-clamped -0.1 [0,0.8] {0,1.952} 0 -0.091 -0.091 +polynomial-Neville's 0.801 [0,0.8] {0,1.952} 1.952 1.95652 1.95652 +polynomial-Neville's 0.901 [0,0.8] {0,1.952} 1.952 2.44423 2.44423 +polynomial-Neville's 1.001 [0,0.8] {0,1.952} 1.952 3.00584 3.006 +polynomial-Neville's 1.101 [0,0.8] {0,1.952} 1.952 3.641 3.64783 +polynomial-Neville's 1.201 [0,0.8] {0,1.952} 1.952 4.22704 4.37572 +polynomial-Neville's 1.301 [0,0.8] {0,1.952} 1.952 3.15934 5.19567 +polynomial-Neville's 1.401 [0,0.8] {0,1.952} 1.952 -14.0584 6.11369 + Notice: In general, accuracy declines farther from domain endpoints. + ************************************************ +EXCEPTIONS: +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Value entered, a = 0.9, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Cannot extrapolate for type cspline-natural, must choose to throw error or return nearest neighbor +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Cannot extrapolate for type cspline-neighborhood, must choose to throw error or return nearest neighbor +**PROGRAMMER ERROR** PolynomialNevilleErrorEstimate() - This method is only valid for polynomial-Neville's, may not be used for cspline-natural interpolation +**PROGRAMMER ERROR** PolynomialNevilleErrorEstimate() - Error not calculated. This method only valid after Evaluate() has been called + ************************************************ + +4) Differentiation Approximation: +GSL First derivative method errors: +a y'(a) Err:natural-reg Err:natural-irreg +0.05 1.1075 -0.0016784 -0.0138232 +0.35 2.0675 -2.11708e-07 1.40745e-07 +0.65 3.5675 -0.000547938 -0.000136049 +First difference method errors: +a y'(a) 2ptBack-Neigh 3ptBack-Neigh 2ptFor-Clamp 3ptFor-Clamp 3ptCtr-Neville 5ptCtr-Neville +0.15 1.3675 -0.0180999 -0.00196076 0.0146 -0.0002 9.99999e-05 -7.33331e-11 +0.45 2.5075 -0.0385105 -0.0271011 0.0236 -0.0002 0.0001 -1.02141e-13 +0.75 4.1875 -0.0309367 0.00292015 0.0326 -0.0002 9.99984e-05 -1.74694e-09 + + -------------------------- +GSL Second derivative method errors: +a y''(a) Err:natural-reg Err:natural-irreg +0.15 2.9 0.00188678 -0.0590771 +0.45 4.7 -8.16229e-06 -1.0402e-05 +0.75 6.5 1.24449 0.155058 +Second difference method errors: +a y'(a) 3ptBack-Neigh 3ptFor-Clamp 3ptCtr-Neville 5ptCtr-Neville +0.15 2.9 0.327829 0.06 -1.21057e-09 -8.53521e-10 +0.45 4.7 -2.41811 0.06 -2.94875e-13 -2.94875e-13 +0.75 6.5 0.271365 0.06 3.93413e-10 -7.98118e-09 +CubicClampedSecondDerivatives(): +xi actual2ndDeriv calculated2ndDeriv +0 2 2 +0.07 2.42 2.42 +0.12 2.72 2.72 +0.19 3.14 3.14 +0.22 3.32 3.32 +0.23 3.38 3.38 +0.32 3.92 3.92 +0.34 4.04 4.04 +0.36 4.16 4.16 +0.39 4.34 4.34 +0.4 4.4 4.4 +0.41 4.46 4.46 +0.44 4.64 4.64 +0.49 4.94 4.94 +0.54 5.24 5.24 +0.59 5.54 5.54 +0.64 5.84 5.84 +0.68 6.08 6.08 +0.7 6.2 6.2 +0.79 6.74 6.74 +0.8 6.8 6.8 + +EXCEPTIONS: +**PROGRAMMER ERROR** GslFirstDerivative() - Invalid argument. Value entered, a = 1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** GslFirstDerivative() - Unable to compute the first derivative at a = 0.2 using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** BackwardFirstDifference() - Invalid argument. Value entered, a = -1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** BackwardFirstDifference() - Formula steps outside of domain. For 2-point backward difference, a-(n-1)h = -0.09 is smaller than domain min = 0.0. Try forward difference or use smaller value for h or n +**PROGRAMMER ERROR** BackwardFirstDifference() - Invalid argument. There is no 4-point backward difference formula in use +**PROGRAMMER ERROR** ForwardFirstDifference() - Invalid argument. Value entered, a = -0.01, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** ForwardFirstDifference() - Formula steps outside of domain. For 3-point forward difference, a+(n-1)h = 0.95 is greater than domain max = 0.8. Try backward difference or use smaller value for h or n +**PROGRAMMER ERROR** ForwardFirstDifference() - Invalid argument. There is no 4-point forward difference formula in use +**PROGRAMMER ERROR** CenterFirstDifference() - Invalid argument. Value entered, a = 0.81, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** CenterFirstDifference() - Formula steps outside of domain. For 5-point center difference, a-(n-1)h = -0.39 or a+(n-1)h = 0.41 is out of domain = [0.0, 0.8]. Use smaller value for h or n +**PROGRAMMER ERROR** CenterFirstDifference() - Invalid argument. There is no 4-point center difference formula in use +**PROGRAMMER ERROR** GslSecondDerivative() - Invalid argument. Value entered, a = 1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** GslSecondDerivative() - Unable to compute the second derivative at a = 0.8 using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** BackwardSecondDifference() - Invalid argument. Value entered, a = -1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** BackwardSecondDifference() - Formula steps outside of domain. For 3-point backward difference, a-(n-1)h = -0.19 is smaller than domain min = 0.0. Try forward difference or use smaller value for h or n +**PROGRAMMER ERROR** BackwardSecondDifference() - Invalid argument. There is no 2-point backward second difference formula in use +**PROGRAMMER ERROR** ForwardSecondDifference() - Invalid argument. Value entered, a = -0.01, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** ForwardSecondDifference() - Formula steps outside of domain. For 3-point forward difference, a+(n-1)h = 0.95 is greater than domain max = 0.8. Try backward difference or use smaller value for h or n +**PROGRAMMER ERROR** ForwardSecondDifference() - Invalid argument. There is no 2-point forward second difference formula in use +**PROGRAMMER ERROR** CenterSecondDifference() - Invalid argument. Value entered, a = 0.81, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** CenterSecondDifference() - Formula steps outside of domain. For 5-point center difference, a-(n-1)h = -0.39 or a+(n-1)h = 0.41 is out of domain = [0.0, 0.8]. Use smaller value for h or n +**PROGRAMMER ERROR** CenterSecondDifference() - Invalid argument. There is no 4-point center second difference formula in use + ************************************************ + +5) Integration Approximation: +GSL Integral method errors: +(a,b) Y(b)-Y(a) Err:c-nat-reg Err:c-nat-irreg +(0,0.8) 0.593067 1.35485e-05 1.14534e-05 +(0,0.5) 0.182292 3.07896e-06 1.86016e-05 +(0,0.2) 0.0230667 3.08345e-06 1.86464e-05 +(0.3,0.8) 0.537042 1.04692e-05 -7.14968e-06 +(0.3,0.5) 0.126267 -3.07786e-10 -1.40653e-09 +(0.6,0.8) 0.308667 1.04837e-05 -7.1442e-06 +Quadrature method errors: +(a,b) Y(b)-Y(a) Trap-Neigh Simp3pt-Neigh Simp4pt-Clamp Boole-Clamp ExtTrap-Nev Romberg-Nev +(0,0.8) 0.593067 0.000400496 -6.1384e-05 1.11022e-16 0 -0.296534 1.6196e-11 +(0,0.5) 0.182292 6.36444e-05 -2.47352e-05 0 2.77556e-17 -0.091146 4.58905e-11 +(0,0.2) 0.0230667 9.49862e-06 5.4552e-06 3.46945e-18 -3.46945e-18 -0.0115333 5.5672e-11 +(0.3,0.8) 0.537042 6.04423e-05 -8.09038e-05 0 -1.11022e-16 -0.268521 -3.09897e-12 +(0.3,0.5) 0.126267 -7.1205e-06 -1.45287e-05 0 0 -0.0631333 -2.77556e-17 +(0.6,0.8) 0.308667 -2.36812e-05 -3.50883e-05 5.55112e-17 5.55112e-17 -0.154333 -2.41507e-12 + +EXCEPTIONS: +**PROGRAMMER ERROR** GslIntegral() - Invalid interval entered: [a,b] = [1.1, 1.0] +**PROGRAMMER ERROR** GslIntegral() - Invalid arguments. Interval entered [1.0, 1.1] is not contained within domain [0.0, 0.8] +**PROGRAMMER ERROR** GslIntegral() - Unable to compute the integral on the interval (a,b) = (0.0, 0.8) using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** TrapezoidalRule() - Unable to calculate the integral on the interval (a,b) = (0.81, 0.7) using the trapeziodal rule +**PROGRAMMER ERROR** EvaluatedForIntegration() - Invalid interval entered: [a,b] = [0.81, 0.7] +**PROGRAMMER ERROR** TrapezoidalRule() - Unable to calculate the integral on the interval (a,b) = (-0.1, 0.7) using the trapeziodal rule +**PROGRAMMER ERROR** EvaluateForIntegration() - Invalid arguments. Interval entered [-0.1, 0.7] is not contained within domain [0.0, 0.8] + ************************************************ diff --git a/isis/src/base/objs/NumericalApproximation/NumericalApproximation_Linux_i686_RedHat5_5.truth b/isis/src/base/objs/NumericalApproximation/NumericalApproximation_Linux_i686_RedHat5_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..03a23099b49f5b5481819a06ea4dc403de8dfb48 --- /dev/null +++ b/isis/src/base/objs/NumericalApproximation/NumericalApproximation_Linux_i686_RedHat5_5.truth @@ -0,0 +1,225 @@ + +Unit test for NumericalApproximation +Using the function f(x) = x^3 + x^2 + x + +1) Creating objects, accessing properties +Valid interpolation types include: +type name minpoints +0 linear 2 +1 polynomial 3 +2 polynomial-Neville's 3 +3 cspline-natural 3 +4 cspline-clamped 3 +5 cspline-periodic 2 +6 cspline-neighborhood 4 +7 cspline-Hermite 2 +8 akima 5 +9 akima-periodic 5 +EXCEPTIONS: +**PROGRAMMER ERROR** SetInterpType() - Invalid argument. Unknown interpolation type: 11 + ************************************************ + +Test constructors: +object type name +interp1 3 cspline-natural +interp2 3 cspline-natural +interp3 3 cspline-natural +interp4 4 cspline-clamped +interp5 2 polynomial-Neville's +interp6 7 cspline-Hermite + +EXCEPTIONS: +**PROGRAMMER ERROR** NumericalApproximation() - Unable to construct an object using the given vectors and interpolation type +**PROGRAMMER ERROR** AddData() - Invalid arguments. The sizes of the input vectors do not match + ************************************************ + +Add data, set properties: +d = 0 is an x element of dataset? 1 +d = 0.01 is an x element of dataset? 0 +d = 0.02 is an x element of dataset? 0 +d = 0.03 is an x element of dataset? 0 +d = 0.04 is an x element of dataset? 1 + +description size domain +cspline-natural, regularly spaced 21 [0, 0.8] +cspline-natural, irregularly spaced 21 [0, 0.8] +cspline-neighborhood, irregularly spaced 21 [0, 0.8] +cspline-clamped, irregularly spaced 21 [0, 0.8] +polynomial-Neville's, irregularly spaced 21 [0, 0.8] + +EXCEPTIONS: +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - Invalid data set, x-values must be in ascending order for cspline-natural interpolation: + x[20] = 0.8 > x[21] = 0.0 +**PROGRAMMER ERROR** DomainMaximum() - Unable to calculate the domain maximum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - cspline-natural interpolation requires a minimum of 3 data points - currently have 0 +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.5 +**PROGRAMMER ERROR** ComputeCubicClamped() - Must set endpoint derivative values after adding data in order to compute cubic spline with clamped boundary conditions +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.5 +**PROGRAMMER ERROR** ComputeCubicClamped() - Must set endpoint derivative values after adding data in order to compute cubic spline with clamped boundary conditions +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ValidateDataSet() - Invalid data set, x-values must be in ascending order for cspline-clamped interpolation: + x[21] = 0.9 > x[22] = 0.5 +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - First and last points of the data set must have the same y-value for cspline-periodicinterpolation to prevent discontinuity at the boundary + ************************************************ + + +2) Dataset Interpolation: +Evaluated points: +x y c-nat-regular c-nat-irreg c-neigh c-clamped p-neville c-hermite +0.05 0.052625 0.0525871 0.0528784 0.0529363 0.052625 0.052625 0.052625 +0.15 0.175875 0.175873 0.175905 0.175647 0.175875 0.175875 0.175875 +0.25 0.328125 0.328125 0.328125 0.32802 0.328125 0.328125 0.328125 +0.35 0.515375 0.515375 0.515375 0.515329 0.515375 0.515375 0.515375 +0.45 0.743625 0.743625 0.743625 0.743474 0.743625 0.743625 0.743625 +0.55 1.01887 1.01888 1.01887 1.01867 1.01887 1.01887 1.01887 +0.65 1.34712 1.34712 1.34712 1.34697 1.34712 1.34712 1.34712 +0.75 1.73437 1.73425 1.73424 1.73407 1.73437 1.73437 1.73437 +Errors: (difference from y-value) +x c-nat-regular c-nat-irreg c-neigh c-clamped p-neville-trueErr p-neville-estimErr c-herm +0.05 -3.79165e-05 0.000253378 0.00031133 -4.90601e-18 2.68408e-10 1.24404e-10 -4.90601e-18 +0.15 -1.50265e-06 2.9835e-05 -0.00022794 9.48677e-19 1.72651e-12 6.57385e-13 9.48677e-19 +0.25 5.23612e-08 -3.65474e-07 -0.000105006 0 -1.67089e-14 -4.50315e-15 0 +0.35 1.82955e-09 -2.65526e-09 -4.63289e-05 -3.75676e-17 -1.4859e-16 -8.44769e-18 -3.75676e-17 +0.45 6.98432e-09 -5.86827e-09 -0.000151105 -1.91904e-17 -9.07369e-16 1.0563e-16 -1.91904e-17 +0.55 1.78058e-07 -9.69423e-08 -0.0002096 -4.66207e-17 -1.24811e-14 7.20647e-15 -4.66207e-17 +0.65 -5.10901e-06 -1.30783e-06 -0.00015885 6.50521e-19 -1.05693e-13 1.77221e-13 6.50521e-19 +0.75 -0.000128916 -0.000133122 -0.000302098 2.08167e-17 -4.22318e-11 2.96468e-10 2.08167e-17 + +3) Dataset Extrapolation: + Notice: Clamped cubic spline accurate if extrapolating cubic function. +type a Domain {ymin,ymax} NearestEndpoint Extrapolate y(a) +cspline-clamped -1.5 [0,0.8] {0,1.952} 0 -2.625 -2.625 +cspline-clamped -1.3 [0,0.8] {0,1.952} 0 -1.807 -1.807 +cspline-clamped -1.1 [0,0.8] {0,1.952} 0 -1.221 -1.221 +cspline-clamped -0.9 [0,0.8] {0,1.952} 0 -0.819 -0.819 +cspline-clamped -0.7 [0,0.8] {0,1.952} 0 -0.553 -0.553 +cspline-clamped -0.5 [0,0.8] {0,1.952} 0 -0.375 -0.375 +cspline-clamped -0.3 [0,0.8] {0,1.952} 0 -0.237 -0.237 +cspline-clamped -0.1 [0,0.8] {0,1.952} 0 -0.091 -0.091 +polynomial-Neville's 0.801 [0,0.8] {0,1.952} 1.952 1.95652 1.95652 +polynomial-Neville's 0.901 [0,0.8] {0,1.952} 1.952 2.44423 2.44423 +polynomial-Neville's 1.001 [0,0.8] {0,1.952} 1.952 3.00584 3.006 +polynomial-Neville's 1.101 [0,0.8] {0,1.952} 1.952 3.641 3.64783 +polynomial-Neville's 1.201 [0,0.8] {0,1.952} 1.952 4.22704 4.37572 +polynomial-Neville's 1.301 [0,0.8] {0,1.952} 1.952 3.15934 5.19567 +polynomial-Neville's 1.401 [0,0.8] {0,1.952} 1.952 -14.0584 6.11369 + Notice: In general, accuracy declines farther from domain endpoints. + ************************************************ +EXCEPTIONS: +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Value entered, a = 0.9, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Cannot extrapolate for type cspline-natural, must choose to throw error or return nearest neighbor +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Cannot extrapolate for type cspline-neighborhood, must choose to throw error or return nearest neighbor +**PROGRAMMER ERROR** PolynomialNevilleErrorEstimate() - This method is only valid for polynomial-Neville's, may not be used for cspline-natural interpolation +**PROGRAMMER ERROR** PolynomialNevilleErrorEstimate() - Error not calculated. This method only valid after Evaluate() has been called + ************************************************ + +4) Differentiation Approximation: +GSL First derivative method errors: +a y'(a) Err:natural-reg Err:natural-irreg +0.05 1.1075 -0.0016784 -0.0138232 +0.35 2.0675 -2.11708e-07 1.40745e-07 +0.65 3.5675 -0.000547938 -0.000136049 +First difference method errors: +a y'(a) 2ptBack-Neigh 3ptBack-Neigh 2ptFor-Clamp 3ptFor-Clamp 3ptCtr-Neville 5ptCtr-Neville +0.15 1.3675 -0.0180999 -0.00196076 0.0146 -0.0002 9.99999e-05 -7.33331e-11 +0.45 2.5075 -0.0385105 -0.0271011 0.0236 -0.0002 0.0001 -1.02141e-13 +0.75 4.1875 -0.0309367 0.00292015 0.0326 -0.0002 9.99984e-05 -1.74694e-09 + + -------------------------- +GSL Second derivative method errors: +a y''(a) Err:natural-reg Err:natural-irreg +0.15 2.9 0.00188678 -0.0590771 +0.45 4.7 -8.16229e-06 -1.0402e-05 +0.75 6.5 1.24449 0.155058 +Second difference method errors: +a y'(a) 3ptBack-Neigh 3ptFor-Clamp 3ptCtr-Neville 5ptCtr-Neville +0.15 2.9 0.327829 0.06 -1.21057e-09 -8.53521e-10 +0.45 4.7 -2.41811 0.06 -2.94875e-13 -2.94875e-13 +0.75 6.5 0.271365 0.06 3.93413e-10 -7.98118e-09 +CubicClampedSecondDerivatives(): +xi actual2ndDeriv calculated2ndDeriv +0 2 2 +0.07 2.42 2.42 +0.12 2.72 2.72 +0.19 3.14 3.14 +0.22 3.32 3.32 +0.23 3.38 3.38 +0.32 3.92 3.92 +0.34 4.04 4.04 +0.36 4.16 4.16 +0.39 4.34 4.34 +0.4 4.4 4.4 +0.41 4.46 4.46 +0.44 4.64 4.64 +0.49 4.94 4.94 +0.54 5.24 5.24 +0.59 5.54 5.54 +0.64 5.84 5.84 +0.68 6.08 6.08 +0.7 6.2 6.2 +0.79 6.74 6.74 +0.8 6.8 6.8 + +EXCEPTIONS: +**PROGRAMMER ERROR** GslFirstDerivative() - Invalid argument. Value entered, a = 1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** GslFirstDerivative() - Unable to compute the first derivative at a = 0.2 using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** BackwardFirstDifference() - Invalid argument. Value entered, a = -1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** BackwardFirstDifference() - Formula steps outside of domain. For 2-point backward difference, a-(n-1)h = -0.09 is smaller than domain min = 0.0. Try forward difference or use smaller value for h or n +**PROGRAMMER ERROR** BackwardFirstDifference() - Invalid argument. There is no 4-point backward difference formula in use +**PROGRAMMER ERROR** ForwardFirstDifference() - Invalid argument. Value entered, a = -0.01, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** ForwardFirstDifference() - Formula steps outside of domain. For 3-point forward difference, a+(n-1)h = 0.95 is greater than domain max = 0.8. Try backward difference or use smaller value for h or n +**PROGRAMMER ERROR** ForwardFirstDifference() - Invalid argument. There is no 4-point forward difference formula in use +**PROGRAMMER ERROR** CenterFirstDifference() - Invalid argument. Value entered, a = 0.81, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** CenterFirstDifference() - Formula steps outside of domain. For 5-point center difference, a-(n-1)h = -0.39 or a+(n-1)h = 0.41 is out of domain = [0.0, 0.8]. Use smaller value for h or n +**PROGRAMMER ERROR** CenterFirstDifference() - Invalid argument. There is no 4-point center difference formula in use +**PROGRAMMER ERROR** GslSecondDerivative() - Invalid argument. Value entered, a = 1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** GslSecondDerivative() - Unable to compute the second derivative at a = 0.8 using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** BackwardSecondDifference() - Invalid argument. Value entered, a = -1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** BackwardSecondDifference() - Formula steps outside of domain. For 3-point backward difference, a-(n-1)h = -0.19 is smaller than domain min = 0.0. Try forward difference or use smaller value for h or n +**PROGRAMMER ERROR** BackwardSecondDifference() - Invalid argument. There is no 2-point backward second difference formula in use +**PROGRAMMER ERROR** ForwardSecondDifference() - Invalid argument. Value entered, a = -0.01, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** ForwardSecondDifference() - Formula steps outside of domain. For 3-point forward difference, a+(n-1)h = 0.95 is greater than domain max = 0.8. Try backward difference or use smaller value for h or n +**PROGRAMMER ERROR** ForwardSecondDifference() - Invalid argument. There is no 2-point forward second difference formula in use +**PROGRAMMER ERROR** CenterSecondDifference() - Invalid argument. Value entered, a = 0.81, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** CenterSecondDifference() - Formula steps outside of domain. For 5-point center difference, a-(n-1)h = -0.39 or a+(n-1)h = 0.41 is out of domain = [0.0, 0.8]. Use smaller value for h or n +**PROGRAMMER ERROR** CenterSecondDifference() - Invalid argument. There is no 4-point center second difference formula in use + ************************************************ + +5) Integration Approximation: +GSL Integral method errors: +(a,b) Y(b)-Y(a) Err:c-nat-reg Err:c-nat-irreg +(0,0.8) 0.593067 1.35485e-05 1.14534e-05 +(0,0.5) 0.182292 3.07896e-06 1.86016e-05 +(0,0.2) 0.0230667 3.08345e-06 1.86464e-05 +(0.3,0.8) 0.537042 1.04692e-05 -7.14968e-06 +(0.3,0.5) 0.126267 -3.07786e-10 -1.40653e-09 +(0.6,0.8) 0.308667 1.04837e-05 -7.1442e-06 +Quadrature method errors: +(a,b) Y(b)-Y(a) Trap-Neigh Simp3pt-Neigh Simp4pt-Clamp Boole-Clamp ExtTrap-Nev Romberg-Nev +(0,0.8) 0.593067 0.000400496 -6.1384e-05 1.11022e-16 0 -0.296534 1.6196e-11 +(0,0.5) 0.182292 6.36444e-05 -2.47352e-05 0 2.77556e-17 -0.091146 4.58905e-11 +(0,0.2) 0.0230667 9.49862e-06 5.4552e-06 3.46945e-18 -3.46945e-18 -0.0115333 5.5672e-11 +(0.3,0.8) 0.537042 6.04423e-05 -8.09038e-05 0 -1.11022e-16 -0.268521 -3.09897e-12 +(0.3,0.5) 0.126267 -7.1205e-06 -1.45287e-05 0 0 -0.0631333 -2.77556e-17 +(0.6,0.8) 0.308667 -2.36812e-05 -3.50883e-05 5.55112e-17 5.55112e-17 -0.154333 -2.41507e-12 + +EXCEPTIONS: +**PROGRAMMER ERROR** GslIntegral() - Invalid interval entered: [a,b] = [1.1, 1.0] +**PROGRAMMER ERROR** GslIntegral() - Invalid arguments. Interval entered [1.0, 1.1] is not contained within domain [0.0, 0.8] +**PROGRAMMER ERROR** GslIntegral() - Unable to compute the integral on the interval (a,b) = (0.0, 0.8) using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** TrapezoidalRule() - Unable to calculate the integral on the interval (a,b) = (0.81, 0.7) using the trapeziodal rule +**PROGRAMMER ERROR** EvaluatedForIntegration() - Invalid interval entered: [a,b] = [0.81, 0.7] +**PROGRAMMER ERROR** TrapezoidalRule() - Unable to calculate the integral on the interval (a,b) = (-0.1, 0.7) using the trapeziodal rule +**PROGRAMMER ERROR** EvaluateForIntegration() - Invalid arguments. Interval entered [-0.1, 0.7] is not contained within domain [0.0, 0.8] + ************************************************ diff --git a/isis/src/base/objs/NumericalApproximation/NumericalApproximation_Linux_i686_SUSE10_1.truth b/isis/src/base/objs/NumericalApproximation/NumericalApproximation_Linux_i686_SUSE10_1.truth new file mode 100644 index 0000000000000000000000000000000000000000..ec2e24e8deebc59d88515c83fc57d4c669f0aecb --- /dev/null +++ b/isis/src/base/objs/NumericalApproximation/NumericalApproximation_Linux_i686_SUSE10_1.truth @@ -0,0 +1,225 @@ + +Unit test for NumericalApproximation +Using the function f(x) = x^3 + x^2 + x + +1) Creating objects, accessing properties +Valid interpolation types include: +type name minpoints +0 linear 2 +1 polynomial 3 +2 polynomial-Neville's 3 +3 cspline-natural 3 +4 cspline-clamped 3 +5 cspline-periodic 2 +6 cspline-neighborhood 4 +7 cspline-Hermite 2 +8 akima 5 +9 akima-periodic 5 +EXCEPTIONS: +**PROGRAMMER ERROR** SetInterpType() - Invalid argument. Unknown interpolation type: 11 + ************************************************ + +Test constructors: +object type name +interp1 3 cspline-natural +interp2 3 cspline-natural +interp3 3 cspline-natural +interp4 4 cspline-clamped +interp5 2 polynomial-Neville's +interp6 7 cspline-Hermite + +EXCEPTIONS: +**PROGRAMMER ERROR** NumericalApproximation() - Unable to construct an object using the given vectors and interpolation type +**PROGRAMMER ERROR** AddData() - Invalid arguments. The sizes of the input vectors do not match + ************************************************ + +Add data, set properties: +d = 0 is an x element of dataset? 1 +d = 0.01 is an x element of dataset? 0 +d = 0.02 is an x element of dataset? 0 +d = 0.03 is an x element of dataset? 0 +d = 0.04 is an x element of dataset? 1 + +description size domain +cspline-natural, regularly spaced 21 [0, 0.8] +cspline-natural, irregularly spaced 21 [0, 0.8] +cspline-neighborhood, irregularly spaced 21 [0, 0.8] +cspline-clamped, irregularly spaced 21 [0, 0.8] +polynomial-Neville's, irregularly spaced 21 [0, 0.8] + +EXCEPTIONS: +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - Invalid data set, x-values must be in ascending order for cspline-natural interpolation: + x[20] = 0.8 > x[21] = 0.0 +**PROGRAMMER ERROR** DomainMaximum() - Unable to calculate the domain maximum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - cspline-natural interpolation requires a minimum of 3 data points - currently have 0 +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.5 +**PROGRAMMER ERROR** ComputeCubicClamped() - Must set endpoint derivative values after adding data in order to compute cubic spline with clamped boundary conditions +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.5 +**PROGRAMMER ERROR** ComputeCubicClamped() - Must set endpoint derivative values after adding data in order to compute cubic spline with clamped boundary conditions +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ValidateDataSet() - Invalid data set, x-values must be in ascending order for cspline-clamped interpolation: + x[21] = 0.9 > x[22] = 0.5 +**PROGRAMMER ERROR** DomainMinimum() - Unable to calculate the domain minimum for the data set +**PROGRAMMER ERROR** ComputeGsl() - Unable to compute GSL interpolation +**PROGRAMMER ERROR** ValidateDataSet() - First and last points of the data set must have the same y-value for cspline-periodicinterpolation to prevent discontinuity at the boundary + ************************************************ + + +2) Dataset Interpolation: +Evaluated points: +x y c-nat-regular c-nat-irreg c-neigh c-clamped p-neville c-hermite +0.05 0.052625 0.0525871 0.0528784 0.0529363 0.052625 0.052625 0.052625 +0.15 0.175875 0.175873 0.175905 0.175647 0.175875 0.175875 0.175875 +0.25 0.328125 0.328125 0.328125 0.32802 0.328125 0.328125 0.328125 +0.35 0.515375 0.515375 0.515375 0.515329 0.515375 0.515375 0.515375 +0.45 0.743625 0.743625 0.743625 0.743474 0.743625 0.743625 0.743625 +0.55 1.01887 1.01888 1.01887 1.01867 1.01887 1.01887 1.01887 +0.65 1.34712 1.34712 1.34712 1.34697 1.34712 1.34712 1.34712 +0.75 1.73437 1.73425 1.73424 1.73407 1.73437 1.73437 1.73437 +Errors: (difference from y-value) +x c-nat-regular c-nat-irreg c-neigh c-clamped p-neville-trueErr p-neville-estimErr c-herm +0.05 -3.79165e-05 0.000253378 0.00031133 -4.90601e-18 2.68408e-10 1.24404e-10 -4.90601e-18 +0.15 -1.50265e-06 2.9835e-05 -0.00022794 9.48677e-19 1.72651e-12 6.57385e-13 9.48677e-19 +0.25 5.23612e-08 -3.65474e-07 -0.000105006 0 -1.67089e-14 -4.50315e-15 0 +0.35 1.82955e-09 -2.65526e-09 -4.63289e-05 -3.75676e-17 -1.4859e-16 -8.44769e-18 -3.75676e-17 +0.45 6.98432e-09 -5.86827e-09 -0.000151105 -1.91904e-17 -9.07369e-16 1.0563e-16 -1.91904e-17 +0.55 1.78058e-07 -9.69423e-08 -0.0002096 -4.66207e-17 -1.24811e-14 7.20647e-15 -4.66207e-17 +0.65 -5.10901e-06 -1.30783e-06 -0.00015885 6.50521e-19 -1.05693e-13 1.77221e-13 6.50521e-19 +0.75 -0.000128916 -0.000133122 -0.000302098 2.08167e-17 -4.22318e-11 2.96468e-10 2.08167e-17 + +3) Dataset Extrapolation: + Notice: Clamped cubic spline accurate if extrapolating cubic function. +type a Domain {ymin,ymax} NearestEndpoint Extrapolate y(a) +cspline-clamped -1.5 [0,0.8] {0,1.952} 0 -2.625 -2.625 +cspline-clamped -1.3 [0,0.8] {0,1.952} 0 -1.807 -1.807 +cspline-clamped -1.1 [0,0.8] {0,1.952} 0 -1.221 -1.221 +cspline-clamped -0.9 [0,0.8] {0,1.952} 0 -0.819 -0.819 +cspline-clamped -0.7 [0,0.8] {0,1.952} 0 -0.553 -0.553 +cspline-clamped -0.5 [0,0.8] {0,1.952} 0 -0.375 -0.375 +cspline-clamped -0.3 [0,0.8] {0,1.952} 0 -0.237 -0.237 +cspline-clamped -0.1 [0,0.8] {0,1.952} 0 -0.091 -0.091 +polynomial-Neville's 0.801 [0,0.8] {0,1.952} 1.952 1.95652 1.95652 +polynomial-Neville's 0.901 [0,0.8] {0,1.952} 1.952 2.44423 2.44423 +polynomial-Neville's 1.001 [0,0.8] {0,1.952} 1.952 3.00584 3.006 +polynomial-Neville's 1.101 [0,0.8] {0,1.952} 1.952 3.641 3.64783 +polynomial-Neville's 1.201 [0,0.8] {0,1.952} 1.952 4.22704 4.37572 +polynomial-Neville's 1.301 [0,0.8] {0,1.952} 1.952 3.15934 5.19567 +polynomial-Neville's 1.401 [0,0.8] {0,1.952} 1.952 -14.0584 6.11369 + Notice: In general, accuracy declines farther from domain endpoints. + ************************************************ +EXCEPTIONS: +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Value entered, a = 0.9, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Cannot extrapolate for type cspline-natural, must choose to throw error or return nearest neighbor +**PROGRAMMER ERROR** Evaluate() - Unable to evaluate the function at the point a = 0.9 +**PROGRAMMER ERROR** Evaluate() - Invalid argument. Cannot extrapolate for type cspline-neighborhood, must choose to throw error or return nearest neighbor +**PROGRAMMER ERROR** PolynomialNevilleErrorEstimate() - This method is only valid for polynomial-Neville's, may not be used for cspline-natural interpolation +**PROGRAMMER ERROR** PolynomialNevilleErrorEstimate() - Error not calculated. This method only valid after Evaluate() has been called + ************************************************ + +4) Differentiation Approximation: +GSL First derivative method errors: +a y'(a) Err:natural-reg Err:natural-irreg +0.05 1.1075 -0.0016784 -0.0138232 +0.35 2.0675 -2.11708e-07 1.40745e-07 +0.65 3.5675 -0.000547938 -0.000136049 +First difference method errors: +a y'(a) 2ptBack-Neigh 3ptBack-Neigh 2ptFor-Clamp 3ptFor-Clamp 3ptCtr-Neville 5ptCtr-Neville +0.15 1.3675 -0.0180999 -0.00196076 0.0146 -0.0002 9.99999e-05 -7.33331e-11 +0.45 2.5075 -0.0385105 -0.0271011 0.0236 -0.0002 1e-04 -1.02141e-13 +0.75 4.1875 -0.0309367 0.00292015 0.0326 -0.0002 9.99984e-05 -1.74694e-09 + + -------------------------- +GSL Second derivative method errors: +a y''(a) Err:natural-reg Err:natural-irreg +0.15 2.9 0.00188678 -0.0590771 +0.45 4.7 -8.16229e-06 -1.0402e-05 +0.75 6.5 1.24449 0.155058 +Second difference method errors: +a y'(a) 3ptBack-Neigh 3ptFor-Clamp 3ptCtr-Neville 5ptCtr-Neville +0.15 2.9 0.327829 0.06 -1.21057e-09 -8.53521e-10 +0.45 4.7 -2.41811 0.06 -2.94875e-13 -2.94875e-13 +0.75 6.5 0.271365 0.06 3.93413e-10 -7.98118e-09 +CubicClampedSecondDerivatives(): +xi actual2ndDeriv calculated2ndDeriv +0 2 2 +0.07 2.42 2.42 +0.12 2.72 2.72 +0.19 3.14 3.14 +0.22 3.32 3.32 +0.23 3.38 3.38 +0.32 3.92 3.92 +0.34 4.04 4.04 +0.36 4.16 4.16 +0.39 4.34 4.34 +0.4 4.4 4.4 +0.41 4.46 4.46 +0.44 4.64 4.64 +0.49 4.94 4.94 +0.54 5.24 5.24 +0.59 5.54 5.54 +0.64 5.84 5.84 +0.68 6.08 6.08 +0.7 6.2 6.2 +0.79 6.74 6.74 +0.8 6.8 6.8 + +EXCEPTIONS: +**PROGRAMMER ERROR** GslFirstDerivative() - Invalid argument. Value entered, a = 1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** GslFirstDerivative() - Unable to compute the first derivative at a = 0.2 using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** BackwardFirstDifference() - Invalid argument. Value entered, a = -1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** BackwardFirstDifference() - Formula steps outside of domain. For 2-point backward difference, a-(n-1)h = -0.09 is smaller than domain min = 0.0. Try forward difference or use smaller value for h or n +**PROGRAMMER ERROR** BackwardFirstDifference() - Invalid argument. There is no 4-point backward difference formula in use +**PROGRAMMER ERROR** ForwardFirstDifference() - Invalid argument. Value entered, a = -0.01, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** ForwardFirstDifference() - Formula steps outside of domain. For 3-point forward difference, a+(n-1)h = 0.95 is greater than domain max = 0.8. Try backward difference or use smaller value for h or n +**PROGRAMMER ERROR** ForwardFirstDifference() - Invalid argument. There is no 4-point forward difference formula in use +**PROGRAMMER ERROR** CenterFirstDifference() - Invalid argument. Value entered, a = 0.81, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** CenterFirstDifference() - Formula steps outside of domain. For 5-point center difference, a-(n-1)h = -0.39 or a+(n-1)h = 0.41 is out of domain = [0.0, 0.8]. Use smaller value for h or n +**PROGRAMMER ERROR** CenterFirstDifference() - Invalid argument. There is no 4-point center difference formula in use +**PROGRAMMER ERROR** GslSecondDerivative() - Invalid argument. Value entered, a = 1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** GslSecondDerivative() - Unable to compute the second derivative at a = 0.8 using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** BackwardSecondDifference() - Invalid argument. Value entered, a = -1.0, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** BackwardSecondDifference() - Formula steps outside of domain. For 3-point backward difference, a-(n-1)h = -0.19 is smaller than domain min = 0.0. Try forward difference or use smaller value for h or n +**PROGRAMMER ERROR** BackwardSecondDifference() - Invalid argument. There is no 2-point backward second difference formula in use +**PROGRAMMER ERROR** ForwardSecondDifference() - Invalid argument. Value entered, a = -0.01, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** ForwardSecondDifference() - Formula steps outside of domain. For 3-point forward difference, a+(n-1)h = 0.95 is greater than domain max = 0.8. Try backward difference or use smaller value for h or n +**PROGRAMMER ERROR** ForwardSecondDifference() - Invalid argument. There is no 2-point forward second difference formula in use +**PROGRAMMER ERROR** CenterSecondDifference() - Invalid argument. Value entered, a = 0.81, is outside of domain = [0.0, 0.8] +**PROGRAMMER ERROR** CenterSecondDifference() - Formula steps outside of domain. For 5-point center difference, a-(n-1)h = -0.39 or a+(n-1)h = 0.41 is out of domain = [0.0, 0.8]. Use smaller value for h or n +**PROGRAMMER ERROR** CenterSecondDifference() - Invalid argument. There is no 4-point center second difference formula in use + ************************************************ + +5) Integration Approximation: +GSL Integral method errors: +(a,b) Y(b)-Y(a) Err:c-nat-reg Err:c-nat-irreg +(0,0.8) 0.593067 1.35485e-05 1.14534e-05 +(0,0.5) 0.182292 3.07896e-06 1.86016e-05 +(0,0.2) 0.0230667 3.08345e-06 1.86464e-05 +(0.3,0.8) 0.537042 1.04692e-05 -7.14968e-06 +(0.3,0.5) 0.126267 -3.07786e-10 -1.40653e-09 +(0.6,0.8) 0.308667 1.04837e-05 -7.1442e-06 +Quadrature method errors: +(a,b) Y(b)-Y(a) Trap-Neigh Simp3pt-Neigh Simp4pt-Clamp Boole-Clamp ExtTrap-Nev Romberg-Nev +(0,0.8) 0.593067 0.000400496 -6.1384e-05 1.11022e-16 0 -0.296534 1.6196e-11 +(0,0.5) 0.182292 6.36444e-05 -2.47352e-05 0 2.77556e-17 -0.091146 4.58905e-11 +(0,0.2) 0.0230667 9.49862e-06 5.4552e-06 3.46945e-18 -3.46945e-18 -0.0115333 5.5672e-11 +(0.3,0.8) 0.537042 6.04423e-05 -8.09038e-05 0 -1.11022e-16 -0.268521 -3.09897e-12 +(0.3,0.5) 0.126267 -7.1205e-06 -1.45287e-05 0 0 -0.0631333 -2.77556e-17 +(0.6,0.8) 0.308667 -2.36812e-05 -3.50883e-05 5.55112e-17 5.55112e-17 -0.154333 -2.41507e-12 + +EXCEPTIONS: +**PROGRAMMER ERROR** GslIntegral() - Invalid interval entered: [a,b] = [1.1, 1.0] +**PROGRAMMER ERROR** GslIntegral() - Invalid arguments. Interval entered [1.0, 1.1] is not contained within domain [0.0, 0.8] +**PROGRAMMER ERROR** GslIntegral() - Unable to compute the integral on the interval (a,b) = (0.0, 0.8) using the GSL interpolation +**PROGRAMMER ERROR** GslComputed() - Method only valid for GSL interpolation types, may not be used for cspline-neighborhood interpolation +**PROGRAMMER ERROR** TrapezoidalRule() - Unable to calculate the integral on the interval (a,b) = (0.81, 0.7) using the trapeziodal rule +**PROGRAMMER ERROR** EvaluatedForIntegration() - Invalid interval entered: [a,b] = [0.81, 0.7] +**PROGRAMMER ERROR** TrapezoidalRule() - Unable to calculate the integral on the interval (a,b) = (-0.1, 0.7) using the trapeziodal rule +**PROGRAMMER ERROR** EvaluateForIntegration() - Invalid arguments. Interval entered [-0.1, 0.7] is not contained within domain [0.0, 0.8] + ************************************************ diff --git a/isis/src/base/objs/NumericalApproximation/unitTest.cpp b/isis/src/base/objs/NumericalApproximation/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ec2b0946917d6d37cb420db5390fd7d111e998d5 --- /dev/null +++ b/isis/src/base/objs/NumericalApproximation/unitTest.cpp @@ -0,0 +1,424 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "NumericalApproximation.h" +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "AtmosModel.h" +#include "AtmosModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Anisotropic1.h" +#include "Preference.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +//create a cubic polynomial to test interpolation, extrapolation +inline double f(double x) { return x*x*x + x*x + x; } +inline vector f(vector x) { + vector y(x.size()); + for(unsigned int i=0;i fstderiv(vector x) { + vector y(x.size()); + for(unsigned int i=0;i x, y; + x.push_back(0.00); x.push_back(0.07); x.push_back(0.12); x.push_back(0.19); + x.push_back(0.22); x.push_back(0.23); x.push_back(0.32); x.push_back(0.34); + x.push_back(0.36); x.push_back(0.39); x.push_back(0.40); x.push_back(0.41); + x.push_back(0.44); x.push_back(0.49); x.push_back(0.54); x.push_back(0.59); + x.push_back(0.64); x.push_back(0.68); x.push_back(0.70); x.push_back(0.79); + x.push_back(0.80); + y = f(x); + //------------------------------------------------------------ + try{ + cout << "1) Creating objects, accessing properties" << endl; + cout << "Valid interpolation types include: " << endl; + cout << "type \t name \t\t minpoints" << endl; + NumericalApproximation interp; + for(int i = 0; i < 10; i++) { + interp.SetInterpType(NumericalApproximation::InterpType(i)); + cout << interp.InterpolationType() << "\t" << interp.Name() << "\t"; + if(interp.Name().length() < 16){ + cout << "\t"; + if(interp.Name().length() < 8) cout << "\t"; + } + cout << interp.MinPoints() << endl; + } + cout << "EXCEPTIONS:" << endl; + try{ interp.SetInterpType(NumericalApproximation::InterpType(11));} + catch(iException e){ e.Report(); } + cout << "\t************************************************" << endl; + + cout << endl; + cout << "Test constructors: " << endl; + // Create NumericalApproximation objects + NumericalApproximation interp1; // CubicNatural by default + NumericalApproximation interp2(interp1); // CubicNatural by copy + NumericalApproximation interp3 = interp1; // CubicNatural by assignment operator + NumericalApproximation interp4(NumericalApproximation::CubicClamped); // CubicClamped by interpType parameter + NumericalApproximation interp5(x,y,NumericalApproximation::PolynomialNeville); // PolynomialNeville by x,y,interpType parameters + NumericalApproximation interp6(x,y,NumericalApproximation::CubicHermite); // CubicHermite by x,y,interpType parameters + + // Check properties of objects created + cout << "object \t type \t name" << endl; + cout << "interp1 " << interp1.InterpolationType() << " \t " << interp1.Name() << endl; + cout << "interp2 " << interp2.InterpolationType() << " \t " << interp2.Name() << endl; + cout << "interp3 " << interp3.InterpolationType() << " \t " << interp3.Name() << endl; + cout << "interp4 " << interp4.InterpolationType() << " \t " << interp4.Name() << endl; + cout << "interp5 " << interp5.InterpolationType() << " \t " << interp5.Name() << endl; + cout << "interp6 " << interp6.InterpolationType() << " \t " << interp6.Name() << endl; + cout << endl; + cout << "EXCEPTIONS:" << endl; + try{// SIZE OF X IS NOT EQUAL TO THE SIZE OF Y + y.pop_back(); + NumericalApproximation uneven(x,y); + }catch(iException e){ e.Report(); } + cout << "\t************************************************" << endl; + cout << endl; + // restore y-vector + y.push_back(f(.8)); + + //------------------------------------------------------------ + cout << "Add data, set properties: " << endl; + // Adding Data... + // by individual evenly spaced points + for(double d = 0.0; d < 0.84; d+=.04) { + interp1.AddData(d,f(d)); + } + // by pointer containing irregularly spaced points + interp2.AddData(x.size(), &x[0], &y[0]); + // by vectors containing irregularly spaced points + interp3.AddData(x,y); + interp4.AddData(x,y); + // interp5 and interp6 already contain data from constructors + + // Test Contains() method + for(double d = 0.0; d < 0.05; d+=.01) { + cout << "d = " << d << " is an x element of dataset? " << interp1.Contains(d) << endl; + } + cout << endl; + + // Setting interpolation... + interp3.SetInterpType(NumericalApproximation::CubicNeighborhood); + + cout << "description \t\t\t\t\t size \t domain" << endl; + cout << interp1.Name() << ", regularly spaced\t\t " << interp1.Size() << " \t[" << interp1.DomainMinimum() << ", " << interp1.DomainMaximum() << "]" << endl; + cout << interp2.Name() << ", irregularly spaced\t\t " << interp2.Size() << " \t[" << interp2.DomainMinimum() << ", " << interp2.DomainMaximum() << "]" << endl; + cout << interp3.Name() << ", irregularly spaced\t " << interp3.Size() << " \t[" << interp3.DomainMinimum() << ", " << interp3.DomainMaximum() << "]" << endl; + cout << interp4.Name() << ", irregularly spaced\t\t " << interp4.Size() << " \t[" << interp4.DomainMinimum() << ", " << interp4.DomainMaximum() << "]" << endl; + cout << interp5.Name() << ", irregularly spaced\t " << interp5.Size() << " \t[" << interp5.DomainMinimum() << ", " << interp5.DomainMaximum() << "]" << endl; + cout << endl; + + // Computing interpolations + cout << "EXCEPTIONS:" << endl; + // Test ValidateDataSet(), MinPoints() exceptions + try{ // DATA SET IS NOT IN UNIQUE + interp2.AddData(0,.8); + interp2.DomainMinimum(); + }catch(iException e){ e.Report(); } + interp2.Reset(); + try{ // DATA SET IS LESS THAN MINPOINTS + interp2.DomainMaximum(); + }catch(iException e){ e.Report(); } + interp2.AddData(x,y); + + // Test CubicClamped exceptions + // ENDPOINT DERIVATIVES ARE NOT SET YET + try{ interp4.Evaluate(.5);}catch(iException e){ e.Report(); } + interp4.SetCubicClampedEndptDeriv(fstderiv(x[0]),fstderiv(x[x.size()-1])); + try{ // NEW DATA HAS BEEN ADDED TO SET CAUSES ENDPT DERIVATIVES TO BE RESET + interp4.AddData(.9,f(.9)); + interp4.Evaluate(.5); + }catch(iException e){ e.Report(); } + try{ // CubicClamped DATA SET IS NOT IN ASCENDING ORDER + interp4.AddData(.5,f(.5)); + interp4.DomainMinimum(); + }catch(iException e){ e.Report(); } + // restore interp4 object + interp4.Reset(); + interp4.AddData(x,y); + interp4.SetCubicClampedEndptDeriv(fstderiv(x[0]),fstderiv(x[x.size()-1])); + + // Test PolynomialNeville exceptions + try{ // CubicPeriodic DATA SET DOESN'T HAVE FIRST AND LAST Y-VALUES EQUAL + interp5.SetInterpType(NumericalApproximation::CubicNatPeriodic); + interp5.DomainMinimum(); + }catch(iException e){ e.Report(); } + interp5.Reset(NumericalApproximation::PolynomialNeville); + interp5.AddData(x,y); + + // Test CubicHermite exceptions + try{ // DATA SET SIZE DOESN'T MATCH NUMBER OF DERIVATIVES ADDED + interp6.AddCubicHermiteDeriv(fstderiv(3)); + }catch(iException e){ e.Report(); } + interp6.Reset(); + interp6.AddData(x,y); + interp6.AddCubicHermiteDeriv(fstderiv(x)); + cout << "\t************************************************" << endl; + cout << endl; + //------------------------------------------------------------ + // Evaluating the interpolations + cout << endl; + cout << "2) Dataset Interpolation: " << endl; + vector points,interppts1,interppts2,interppts3,interppts4,interppts5,interppts6; + for(double p = .05; p < .8; p+=.1) { + points.push_back(p); + //Evaluate individual points + interppts1.push_back(interp1.Evaluate(p)); //natural, reg + } + // Evaluate vectors + interppts2 = interp2.Evaluate(points); // natural, irreg + interppts3 = interp3.Evaluate(points); // neighbor, irreg + interppts4 = interp4.Evaluate(points); // clamped, irreg + interppts5 = interp5.Evaluate(points); // neville, irreg + interppts6 = interp6.Evaluate(points); // hermite, irreg + cout << "Evaluated points:" << endl; + cout << "x \t y \t\t c-nat-regular \t c-nat-irreg \t c-neigh \t c-clamped \t p-neville \t c-hermite" << endl; + for(unsigned int i = 0; i error = interp5.PolynomialNevilleErrorEstimate(); + cout << "Errors: (difference from y-value)" << endl; + cout << "x \tc-nat-regular\tc-nat-irreg\tc-neigh\t\tc-clamped\tp-neville-trueErr\tp-neville-estimErr\tc-herm" << endl; + for(unsigned int i = 0; i yDoublePrime = interp4.CubicClampedSecondDerivatives(); + cout << "xi \t actual2ndDeriv \t calculated2ndDeriv" << endl; + for(unsigned int i = 0; i < x.size(); i++) { + cout << x[i] << " \t " << scndderiv(x[i]) << " \t\t\t " << yDoublePrime[i] << endl; + } + cout << endl; + cout << "EXCEPTIONS:" << endl; + try{interp2.GslFirstDerivative(1.0);} // outside domain + catch(iException e){ e.Report(); } + try{interp3.GslFirstDerivative(0.2);} // not GSL supported + catch(iException e){ e.Report(); } + try{interp3.BackwardFirstDifference(-1.0);} // outside domain + catch(iException e){ e.Report(); } + try{interp3.BackwardFirstDifference(0.01,2,.1);} // steps outside domain + catch(iException e){ e.Report(); } + try{interp3.BackwardFirstDifference(0.1,4,.01);} // no 4pt formula + catch(iException e){ e.Report(); } + try{interp3.ForwardFirstDifference(-0.01);} // outside domain + catch(iException e){ e.Report(); } + try{interp3.ForwardFirstDifference(0.75,3,.1);} // steps outside domain + catch(iException e){ e.Report(); } + try{interp3.ForwardFirstDifference(0.1,4,.01);} // no 4pt formula + catch(iException e){ e.Report(); } + try{interp3.CenterFirstDifference(.81);} // outside domain + catch(iException e){ e.Report(); } + try{interp3.CenterFirstDifference(0.01,5,.1);} // steps outside domain + catch(iException e){ e.Report(); } + try{interp3.CenterFirstDifference(0.1,4,.01);} // no 4pt formula + catch(iException e){ e.Report(); } + try{interp1.GslSecondDerivative(1.0);} // outside domain + catch(iException e){ e.Report(); } + try{interp3.GslSecondDerivative(0.8);} // not GSL supported + catch(iException e){ e.Report(); } + try{interp3.BackwardSecondDifference(-1.0);} // outside domain + catch(iException e){ e.Report(); } + try{interp3.BackwardSecondDifference(0.01,3,.1);} // steps outside domain + catch(iException e){ e.Report(); } + try{interp3.BackwardSecondDifference(0.1,2,.01);} // no 2pt formula + catch(iException e){ e.Report(); } + try{interp3.ForwardSecondDifference(-0.01);} // outside domain + catch(iException e){ e.Report(); } + try{interp3.ForwardSecondDifference(0.75,3,.1);} // steps outside domain + catch(iException e){ e.Report(); } + try{interp3.ForwardSecondDifference(0.1,2,.01);} // no 2pt formula + catch(iException e){ e.Report(); } + try{interp3.CenterSecondDifference(.81);} // outside domain + catch(iException e){ e.Report(); } + try{interp3.CenterSecondDifference(0.01,5,.1);} // steps outside domain + catch(iException e){ e.Report(); } + try{interp3.CenterSecondDifference(0.1,4,.01);} // no 4pt formula + catch(iException e){ e.Report(); } + //interp2.AddData(x,y); + cout << "\t************************************************" << endl; + + // Integration Methods + cout << endl; + cout << "5) Integration Approximation: " << endl; + cout << "GSL Integral method errors: " << endl; + cout << "(a,b)\t\tY(b)-Y(a)\tErr:c-nat-reg\t\tErr:c-nat-irreg" << endl; + for(double a = 0.0; a < 0.8; a+=.3) { + for(double b = 0.8; b > a; b-=.3) { + cout << "(" << a << "," << b << ")\t"; + if(a == 0) cout << "\t"; + cout << integral(a,b) << " \t"; + cout << interp1.GslIntegral(a,b)-integral(a,b) << "\t\t"; + cout << interp2.GslIntegral(a,b)-integral(a,b) << endl; + } + } + cout << "Quadrature method errors: " << endl; + cout << "(a,b)\t\tY(b)-Y(a)\tTrap-Neigh\tSimp3pt-Neigh\tSimp4pt-Clamp\tBoole-Clamp\tExtTrap-Nev\tRomberg-Nev" << endl; + double s; + for(double a = 0.0; a < 0.8; a+=.3) { + for(double b = 0.8; b > a; b-=.3) { + s=0; + s = interp5.RefineExtendedTrap(a,b,s,10); + cout << "(" << a << "," << b << ")\t"; + if(a == 0) cout << "\t"; + cout << integral(a,b) << " \t"; + cout << interp3.TrapezoidalRule(a,b) - integral(a,b) << "\t"; + if (interp3.TrapezoidalRule(a,b) - integral(a,b) == 0) cout <<"\t"; + cout << interp3.Simpsons3PointRule(a,b) - integral(a,b) << "\t"; + if (interp3.Simpsons3PointRule(a,b) - integral(a,b) == 0) cout <<"\t"; + cout << interp4.Simpsons4PointRule(a,b) - integral(a,b) << "\t"; + if (interp4.Simpsons4PointRule(a,b) - integral(a,b) == 0) cout <<"\t"; + cout << interp4.BoolesRule(a,b) - integral(a,b) << "\t"; + if ( interp4.BoolesRule(a,b) - integral(a,b) == 0) cout <<"\t"; + cout << s - integral(a,b) << "\t"; + if ( s - integral(a,b) == 0) cout <<"\t"; + cout << interp5.RombergsMethod(a,b) - integral(a,b) << endl; + } + } + cout << endl; + cout << "EXCEPTIONS:" << endl; + try{cout << interp1.GslIntegral(1.1,1.0) << endl;} // invalid interval + catch(iException e){ e.Report(); } + try{cout << interp1.GslIntegral(1.0,1.1) << endl;} // outside domain + catch(iException e){ e.Report(); } + try{cout << interp3.GslIntegral(0.0,0.8) << endl;} // not GSL supported + catch(iException e){ e.Report(); } + try{cout << interp1.TrapezoidalRule(.81,.70) << endl;} // invalid interval + catch(iException e){ e.Report(); } + try{cout << interp1.TrapezoidalRule(-.1,.70) << endl;} // outside domain + catch(iException e){ e.Report(); } + cout << "\t************************************************" << endl; + } + catch (iException &e) { + e.Report(false); + } + return 0; +} diff --git a/isis/src/base/objs/ObliqueCylindrical/Makefile b/isis/src/base/objs/ObliqueCylindrical/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..17cf78cb755daa13d35322f13de5daa0172f916f --- /dev/null +++ b/isis/src/base/objs/ObliqueCylindrical/Makefile @@ -0,0 +1,5 @@ +INCS = ObliqueCylindrical.h +SRCS = ObliqueCylindrical.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ObliqueCylindrical/ObliqueCylindrical.cpp b/isis/src/base/objs/ObliqueCylindrical/ObliqueCylindrical.cpp new file mode 100644 index 0000000000000000000000000000000000000000..49363de82d6914b1286c38bcba09caa6ce09e0f0 --- /dev/null +++ b/isis/src/base/objs/ObliqueCylindrical/ObliqueCylindrical.cpp @@ -0,0 +1,633 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2010/02/08 19:02:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "ObliqueCylindrical.h" +#include "iException.h" +#include "Constants.h" +#include "naif/SpiceUsr.h" + +using namespace std; +namespace Isis { + /** + * Constructs an ObliqueCylindrical object. + * + * @param label This argument must be a Label containing the proper mapping + * information as indicated in the Projection class. + * Additionally, the Oblique cylindrical projection + * requires the Pole latitude, longitude and + * rotation. + * + * @param allowDefaults This does nothing currently + * + * @throws Isis::iException::Io + */ + ObliqueCylindrical::ObliqueCylindrical(Isis::Pvl &label, bool allowDefaults) : + Isis::Projection::Projection (label) { + try { + // Try to read the mapping group + Isis::PvlGroup &mapGroup = label.FindGroup ("Mapping", Isis::Pvl::Traverse); + + p_poleLatitude = mapGroup["PoleLatitude"]; + + // All latitudes must be planetographic + if (this->IsPlanetocentric()) { + p_poleLatitude = this->ToPlanetographic(p_poleLatitude); + } + + if(p_poleLatitude < -90 || p_poleLatitude > 90) { + throw iException::Message(iException::Pvl, + "Pole latitude must be between -90 and 90.", + _FILEINFO_); + } + + p_poleLongitude = mapGroup["PoleLongitude"]; + + if(p_poleLongitude < -360 || p_poleLongitude > 360) { + throw iException::Message(iException::Pvl, + "Pole longitude must be between -360 and 360.", + _FILEINFO_); + } + + p_poleRotation = mapGroup["PoleRotation"]; + + if(p_poleRotation < -360 || p_poleRotation > 360) { + throw iException::Message(iException::Pvl, + "Pole rotation must be between -360 and 360.", + _FILEINFO_); + } + + bool calculateVectors = false; + + // Check vectors for the right array size + if(!mapGroup.HasKeyword("XAxisVector") || mapGroup["XAxisVector"].Size() != 3) { + calculateVectors = true; + } + + if(!mapGroup.HasKeyword("YAxisVector") || mapGroup["YAxisVector"].Size() != 3) { + calculateVectors = true; + } + + if(!mapGroup.HasKeyword("ZAxisVector") || mapGroup["ZAxisVector"].Size() != 3) { + calculateVectors = true; + } + + if(!calculateVectors) { + // Read in vectors + p_xAxisVector.push_back(mapGroup["XAxisVector"][0]); + p_xAxisVector.push_back(mapGroup["XAxisVector"][1]); + p_xAxisVector.push_back(mapGroup["XAxisVector"][2]); + + p_yAxisVector.push_back(mapGroup["YAxisVector"][0]); + p_yAxisVector.push_back(mapGroup["YAxisVector"][1]); + p_yAxisVector.push_back(mapGroup["YAxisVector"][2]); + + p_zAxisVector.push_back(mapGroup["ZAxisVector"][0]); + p_zAxisVector.push_back(mapGroup["ZAxisVector"][1]); + p_zAxisVector.push_back(mapGroup["ZAxisVector"][2]); + } else { + // Calculate the vectors and store them in the labels + // The vectors are useful for processing later on, but are + // not actually used here + double rotationAngle = p_poleRotation * (Isis::PI / 180.0); + double latitudeAngle = (90.0 - p_poleLatitude) * (Isis::PI / 180.0); + double longitudeAngle = (360.0 - p_poleLongitude) * (Isis::PI / 180.0); + double pvec[3][3]; + + eul2m_c(rotationAngle,latitudeAngle,longitudeAngle,3,2,3,pvec); + + // Reset the vector keywords + if(mapGroup.HasKeyword("XAxisVector")) { + mapGroup.DeleteKeyword("XAxisVector"); + } + if(mapGroup.HasKeyword("YAxisVector")) { + mapGroup.DeleteKeyword("YAxisVector"); + } + if(mapGroup.HasKeyword("ZAxisVector")) { + mapGroup.DeleteKeyword("ZAxisVector"); + } + + mapGroup += Isis::PvlKeyword("XAxisVector"); + mapGroup += Isis::PvlKeyword("YAxisVector"); + mapGroup += Isis::PvlKeyword("ZAxisVector"); + + // Store calculations both in vector and PVL + for(int i = 0; i < 3; i++) { + p_xAxisVector.push_back(pvec[0][i]); //X[i] + p_yAxisVector.push_back(pvec[1][i]); //Y[i] + p_zAxisVector.push_back(pvec[2][i]); //Z[i] + + mapGroup["XAxisVector"] += pvec[0][i]; //X[i] + mapGroup["YAxisVector"] += pvec[1][i]; //Y[i] + mapGroup["ZAxisVector"] += pvec[2][i]; //Z[i] + } + } + + init(); + } + catch (Isis::iException &e) { + string message = "Invalid label group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + //! Destroys the ObliqueCylindrical object + ObliqueCylindrical::~ObliqueCylindrical() { + } + + /** + * This method is used to set the latitude/longitude (assumed to be of the + * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. + * + * @param lat Latitude value to project + * + * @param lon Longitude value to project + * + * @return bool + */ + bool ObliqueCylindrical::SetGround(const double lat,const double lon) { + double normalLat, normalLon; // normal lat/lon + double obliqueLat, obliqueLon; // oblique lat/lon copy + + // Store lat,lon + p_latitude = lat; + p_longitude = lon; + + // Use oblat,oblon as radians version of lat,lon now for calculations + normalLat = p_latitude * Isis::PI / 180.0; + normalLon = p_longitude * Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) normalLon *= -1.0; + + + /******************************************************************************* + * Calculate the oblique lat/lon from the normal lat/lon + *******************************************************************************/ + double poleLatitude = (p_poleLatitude * Isis::PI / 180.0); + double poleLongitude = (p_poleLongitude * Isis::PI / 180.0); + double poleRotation = (p_poleRotation * Isis::PI / 180.0); + + obliqueLat = asin (sin(poleLatitude) * sin(normalLat) + + cos(poleLatitude) * cos(normalLat) * cos(normalLon - poleLongitude)); + + obliqueLon = atan2 (cos(normalLat) * sin(normalLon - poleLongitude), + sin(poleLatitude) * cos(normalLat) * cos (normalLon - poleLongitude) - + cos(poleLatitude) * sin(normalLat)) - poleRotation; + + while (obliqueLon < - Isis::PI) { + obliqueLon += (2.0 * Isis::PI); + } + + while (obliqueLon >= Isis::PI) { + obliqueLon -= (2.0 * Isis::PI); + } + + // Compute the coordinate + double x = p_equatorialRadius * obliqueLon; + double y = p_equatorialRadius * obliqueLat; + SetComputedXY(x,y); + + p_good = true; + return p_good; + } + + /** + * This method is used to set the projection x/y. The Set forces an attempted + * calculation of the corresponding latitude/longitude position. This may or + * may not be successful and a status is returned as such. + * + * @param x X coordinate of the projection in units that are the same as the + * radii in the label + * + * @param y Y coordinate of the projection in units that are the same as the + * radii in the label + * + * @return bool + */ + bool ObliqueCylindrical::SetCoordinate(const double x, const double y) { + // Save the coordinate + SetXY(x,y); + + /******************************************************************************* + * Calculate the oblique latitude and check to see if it is outside or equal + * to [-90,90]. If it is, return with an error. + *******************************************************************************/ + p_latitude = GetY() / p_equatorialRadius; + + if (abs(abs(p_latitude) - Isis::HALFPI) < DBL_EPSILON) { + p_good = false; + return p_good; + } + + /******************************************************************************* + * The check to see if p_equatorialRadius == 0 is done in the init function + *******************************************************************************/ + p_longitude = GetX() / p_equatorialRadius; + + /******************************************************************************* + * Convert the oblique lat/lon to normal lat/lon + *******************************************************************************/ + double obliqueLat, obliqueLon; + double poleLatitude = (p_poleLatitude * Isis::PI / 180.0); + double poleLongitude = (p_poleLongitude * Isis::PI / 180.0); + double poleRotation = (p_poleRotation * Isis::PI / 180.0); + + obliqueLat = asin (sin(poleLatitude) * sin(p_latitude) - + cos(poleLatitude) * cos(p_latitude) * cos(p_longitude + poleRotation)); + + obliqueLon = atan2(cos(p_latitude) * sin(p_longitude + poleRotation), + sin(poleLatitude) * cos(p_latitude) * cos(p_longitude + poleRotation) + + cos(poleLatitude) * sin(p_latitude)) + poleLongitude; + + /******************************************************************************* + * Convert the latitude/longitude to degrees and apply target longitude direction + * correction to the longitude + *******************************************************************************/ + p_latitude = obliqueLat * 180.0 / Isis::PI; + p_longitude = obliqueLon * 180.0 / Isis::PI; + + // Cleanup the longitude + if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; + + p_good = true; + return p_good; + } + + /** + * This method is used to determine the x/y range which completely covers the + * area of interest specified by the lat/lon range. The latitude/longitude + * range may be obtained from the labels. The purpose of this method is to + * return the x/y range so it can be used to compute how large a map may need + * to be. For example, how big a piece of paper is needed or how large of an + * image needs to be created. The method may fail as indicated by its return + * value. + * + * This function works for most cases, especially on smaller areas. However, + * larger areas are likely to fail due to numerous discontinuities and a lack + * of a mathematical algorithm to solve the range. This method works by searching + * the boundaries, using DoSearch, and then searching lines tangent to discontinuities. + * + * @param minX Minimum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxX Maximum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param minY Minimum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxY Maximum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @return bool + */ + bool ObliqueCylindrical::XYRange(double &minX, double &maxX, + double &minY, double&maxY) { + // For oblique cylindrical, we'll have to walk all 4 sides to find out min/max x/y values. + if(!HasGroundRange()) return false; // Don't have min/max lat/longs, can't continue + + p_specialLatCases.clear(); + p_specialLonCases.clear(); + + // First, search longitude for min X/Y + double minFoundX1, minFoundX2; + double minFoundY1, minFoundY2; + + doSearch(MinimumLatitude(), MaximumLatitude(), minFoundX1, MinimumLongitude(), true, true, true); + doSearch(MinimumLatitude(), MaximumLatitude(), minFoundX2, MaximumLongitude(), true, true, true); + doSearch(MinimumLatitude(), MaximumLatitude(), minFoundY1, MinimumLongitude(), false, true, true); + doSearch(MinimumLatitude(), MaximumLatitude(), minFoundY2, MaximumLongitude(), false, true, true); + + // Second, search latitude for min X/Y + double minFoundX3, minFoundX4; + double minFoundY3, minFoundY4; + + doSearch(MinimumLongitude(), MaximumLongitude(), minFoundX3, MinimumLatitude(), true, false, true); + doSearch(MinimumLongitude(), MaximumLongitude(), minFoundX4, MaximumLatitude(), true, false, true); + doSearch(MinimumLongitude(), MaximumLongitude(), minFoundY3, MinimumLatitude(), false, false, true); + doSearch(MinimumLongitude(), MaximumLongitude(), minFoundY4, MaximumLatitude(), false, false, true); + + // We've searched all possible minimums, go ahead and store the lowest + double minFoundX5 = min(minFoundX1, minFoundX2); + double minFoundX6 = min(minFoundX3, minFoundX4); + p_minimumX = min(minFoundX5, minFoundX6); + + double minFoundY5 = min(minFoundY1, minFoundY2); + double minFoundY6 = min(minFoundY3, minFoundY4); + p_minimumY = min(minFoundY5, minFoundY6); + + // Search longitude for max X/Y + double maxFoundX1, maxFoundX2; + double maxFoundY1, maxFoundY2; + + doSearch(MinimumLatitude(), MaximumLatitude(), maxFoundX1, MinimumLongitude(), true, true, false); + doSearch(MinimumLatitude(), MaximumLatitude(), maxFoundX2, MaximumLongitude(), true, true, false); + doSearch(MinimumLatitude(), MaximumLatitude(), maxFoundY1, MinimumLongitude(), false, true, false); + doSearch(MinimumLatitude(), MaximumLatitude(), maxFoundY2, MaximumLongitude(), false, true, false); + + // Search latitude for max X/Y + double maxFoundX3, maxFoundX4; + double maxFoundY3, maxFoundY4; + + doSearch(MinimumLongitude(), MaximumLongitude(), maxFoundX3, MinimumLatitude(), true, false, false); + doSearch(MinimumLongitude(), MaximumLongitude(), maxFoundX4, MaximumLatitude(), true, false, false); + doSearch(MinimumLongitude(), MaximumLongitude(), maxFoundY3, MinimumLatitude(), false, false, false); + doSearch(MinimumLongitude(), MaximumLongitude(), maxFoundY4, MaximumLatitude(), false, false, false); + + // We've searched all possible maximums, go ahead and store the highest + double maxFoundX5 = max(maxFoundX1, maxFoundX2); + double maxFoundX6 = max(maxFoundX3, maxFoundX4); + p_maximumX = max(maxFoundX5, maxFoundX6); + + double maxFoundY5 = max(maxFoundY1, maxFoundY2); + double maxFoundY6 = max(maxFoundY3, maxFoundY4); + p_maximumY = max(maxFoundY5, maxFoundY6); + + // Look along discontinuities for more extremes + std::vector specialLatCases = p_specialLatCases; + for(unsigned int specialLatCase = 0; specialLatCase < specialLatCases.size(); specialLatCase ++) { + double minX, maxX, minY, maxY; + + doSearch(MinimumLongitude(), MaximumLongitude(), minX, specialLatCases[specialLatCase], true, false, true); + doSearch(MinimumLongitude(), MaximumLongitude(), minY, specialLatCases[specialLatCase], false, false, true); + doSearch(MinimumLongitude(), MaximumLongitude(), maxX, specialLatCases[specialLatCase], true, false, false); + doSearch(MinimumLongitude(), MaximumLongitude(), maxY, specialLatCases[specialLatCase], false, false, false); + + p_minimumX = min(minX, p_minimumX); + p_maximumX = max(maxX, p_maximumX); + p_minimumY = min(minY, p_minimumY); + p_maximumY = max(maxY, p_maximumY); + } + + std::vector specialLonCases = p_specialLonCases; + for(unsigned int specialLonCase = 0; specialLonCase < specialLonCases.size(); specialLonCase ++) { + double minX, maxX, minY, maxY; + + doSearch(MinimumLatitude(), MaximumLatitude(), minX, specialLonCases[specialLonCase], true, true, true); + doSearch(MinimumLatitude(), MaximumLatitude(), minY, specialLonCases[specialLonCase], false, true, true); + doSearch(MinimumLatitude(), MaximumLatitude(), maxX, specialLonCases[specialLonCase], true, true, false); + doSearch(MinimumLatitude(), MaximumLatitude(), maxY, specialLonCases[specialLonCase], false, true, false); + + p_minimumX = min(minX, p_minimumX); + p_maximumX = max(maxX, p_maximumX); + p_minimumY = min(minY, p_minimumY); + p_maximumY = max(maxY, p_maximumY); + } + + p_specialLatCases.clear(); + p_specialLonCases.clear(); + + // Make sure everything is ordered + if (p_minimumX >= p_maximumX) return false; + if (p_minimumY >= p_maximumY) return false; + + // Return X/Y min/maxs + minX = p_minimumX; + maxX = p_maximumX; + minY = p_minimumY; + maxY = p_maximumY; + + return true; + } + + + /** + * This function returns the keywords that this projection uses. + * + * @return PvlGroup The keywords that this projection uses + */ + PvlGroup ObliqueCylindrical::Mapping() { + PvlGroup mapping = Projection::Mapping(); + + mapping += p_mappingGrp["PoleLatitude"]; + mapping += p_mappingGrp["PoleLongitude"]; + mapping += p_mappingGrp["PoleRotation"]; + + return mapping; + } + + /** + * This function returns the latitude keywords that this projection uses + * + * @return PvlGroup The latitude keywords that this projection uses + */ + PvlGroup ObliqueCylindrical::MappingLatitudes() { + PvlGroup mapping = Projection::MappingLatitudes(); + + return mapping; + } + + /** + * This function returns the longitude keywords that this projection uses + * + * @return PvlGroup The longitude keywords that this projection uses + */ + PvlGroup ObliqueCylindrical::MappingLongitudes() { + PvlGroup mapping = Projection::MappingLongitudes(); + + return mapping; + } + + /** + * Searches for extreme (min/max/discontinuity) values across lat/lons. Discontinuities are + * stored in p_specialLatCases and p_specialLonCases so they may be checked again later, which + * creates significantly more accuracy in some cases. This method utilizes findExtreme to locate + * extreme values. + * + * @param minBorder Minimum lat or lon to start searching from + * @param maxBorder Maximum lat or lon to start searching from + * @param extremeVal The resulting global min/max on this line + * @param constBorder The lat or lon that stays constant + * @param searchLongitude True if you're searching along a longitude (constBorder is a lon, other borders lats). + * False if you're searching a latitude (constBorder is a lat, other borders lons). + * @param findMin True if looking for a minimum, false if looking for a maximum. + */ + void ObliqueCylindrical::doSearch(double minBorder, double maxBorder, double &extremeVal, + const double constBorder, bool searchX, bool searchLongitude, bool findMin) { + const double TOLERANCE = 0.5; + const int NUM_ATTEMPTS = (unsigned int)DBL_DIG; // It's unsafe to go past this precision + + double minFoundVal, maxFoundVal; + int attempts = 0; + + do { + findExtreme(minBorder, maxBorder, minFoundVal, maxFoundVal, constBorder, searchX, searchLongitude, findMin); + attempts ++; + } while((abs(minFoundVal - maxFoundVal) > TOLERANCE) && (attempts < NUM_ATTEMPTS)); + + if(attempts >= NUM_ATTEMPTS) { + // We zoomed in on a discontinuity because our range never shrank, this will need to be rechecked later. + // *min and max border should be nearly identicle, so it doesnt matter which is used here + if(searchLongitude) { + p_specialLatCases.push_back(minBorder); + } + else { + p_specialLonCases.push_back(minBorder); + } + } + + // These values will always be accurate, even over a discontinuity + if(findMin) { + extremeVal = min(maxFoundVal, minFoundVal); + } + else { + extremeVal = max(maxFoundVal, minFoundVal); + } + } + + /** + * Compares two Projection objects to see if they are equal + * + * @param proj Projection object to do comparison on + * + * @return bool Returns true if the Projection objects are equal, and false if + * they are not + */ + bool ObliqueCylindrical::operator== (const Isis::Projection &proj) { + if (!Isis::Projection::operator==(proj)) return false; + + ObliqueCylindrical *obProjection = (ObliqueCylindrical *) &proj; + + if(obProjection->GetPoleLatitude() != GetPoleLatitude()) return false; + if(obProjection->GetPoleLongitude() != GetPoleLongitude()) return false; + if(obProjection->GetPoleRotation() != GetPoleRotation()) return false; + + return true; + } + + void ObliqueCylindrical::init() { + /******************************************************************************* + * Apply target correction for longitude direction + *******************************************************************************/ + if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; + if (p_longitudeDirection == PositiveWest) p_poleLongitude *= -1.0; + + /******************************************************************************* + * Check that p_equatorialRadius isn't zero because we'll divide by it later + *******************************************************************************/ + if(abs(p_equatorialRadius) <= DBL_EPSILON) { + throw iException::Message(iException::Pvl, + "The input center latitude is too close to a pole which will result in a division by zero.", + _FILEINFO_); + } + } + + /** + * Searches for extreme (min/max/discontinuity) values across lat/lons. Discontinuities will cause + * the minVal and maxVal to never converge. This works by stepping (10 times) between the minBorder + * and maxBorder to find an extreme. Then, the range of this extreme is recorder in minBorder and + * maxBorder and the values on these new borders are stored in minVal or maxVal (could be X or Y depending + * on searchX). This function should be used by calling it repeatidly until minVal ~= maxVal. If minVal never + * comes close to maxVal, then between minBorder and maxBorder is the value of the most extreme value and either + * minVal or maxVal will be correct (whichever is smaller or bigger depending on findMin). + * + * @param minBorder Minimum lat or lon to start searching from, which gets updated to a more precise range + * @param maxBorder Maximum lat or lon to start searching from, which gets updated to a more precise range + * @param minVal The lower resultant, which is more accurate when nearly equal to maxVal + * @param maxVal The higher resultant, which is more accurate when nearly equal to minVal + * @param constBorder The lat or lon that stays constant + * @param searchX True if searching X Coordinates, False if searching Y Coordinates + * @param searchLongitude True if you're searching along a longitude (constBorder is a lon, other borders lats). + * False if you're searching a latitude (constBorder is a lat, other borders lons). + * @param findMin True if looking for a minimum, false if looking for a maximum. + */ + void ObliqueCylindrical::findExtreme(double &minBorder, double &maxBorder, + double &minVal, double &maxVal, const double constBorder, + bool searchX, bool searchLongitude, bool findMin) { + // Always do 10 steps + const double STEP_SIZE = (maxBorder - minBorder) / 10.0; + const double LOOP_END = maxBorder + (STEP_SIZE / 2.0); // This ensures we do all of the steps properly + double currBorderVal = minBorder; + + SetSearchGround(minBorder, constBorder, searchLongitude); + double value1 = (searchX)? XCoord() : YCoord(); + double value2 = value1; + double value3 = value1; + + double border1 = minBorder; + double border2 = minBorder; + double border3 = minBorder; + + double extremeVal1 = value1; + double extremeVal2 = value1; + double extremeVal3 = value1; + + double extremeBorder1 = minBorder; + double extremeBorder2 = minBorder; + double extremeBorder3 = minBorder; + + while(currBorderVal <= LOOP_END) { + SetSearchGround(currBorderVal, constBorder, searchLongitude); + + value3 = value2; + value2 = value1; + value1 = (searchX)? XCoord() : YCoord(); + border3 = border2; + border2 = border1; + border1 = currBorderVal; + + if((findMin && value2 < extremeVal2) || (!findMin && value2 > extremeVal2)) { + extremeVal1 = value1; + extremeVal2 = value2; + extremeVal3 = value3; + + extremeBorder3 = border3; + extremeBorder2 = border2; + extremeBorder1 = border1; + } + + currBorderVal += STEP_SIZE; + } + + minBorder = extremeBorder3; // Border 3 is lagging and thus smaller + maxBorder = extremeBorder1; // Border 1 is leading and thus larger + + SetSearchGround(minBorder, constBorder, searchLongitude); + minVal = (searchX)? XCoord() : YCoord(); + SetSearchGround(maxBorder, constBorder, searchLongitude); + maxVal = (searchX)? XCoord() : YCoord(); + } + + /** + * This function sets the ground based on two variables and a boolean. This is meant + * for use by DoSearch and findExtreme in order to set the ground correctly each time. + * + * @param variableBorder The lat/lon that is variable in the search methods + * @param constBorder The lat/lon that is constant in the search methods + * @param variableIsLat True if variableBorder is a lat, False if variableBorder is a lon + */ + void ObliqueCylindrical::SetSearchGround(const double variableBorder, const double constBorder, bool variableIsLat) { + if(variableIsLat) { + SetGround(variableBorder, constBorder); + } + else { + SetGround(constBorder, variableBorder); + } + } +} // end namespace isis + +extern "C" Isis::Projection *ObliqueCylindricalPlugin (Isis::Pvl &lab, + bool allowDefaults) { + return new Isis::ObliqueCylindrical(lab,allowDefaults); +} diff --git a/isis/src/base/objs/ObliqueCylindrical/ObliqueCylindrical.h b/isis/src/base/objs/ObliqueCylindrical/ObliqueCylindrical.h new file mode 100644 index 0000000000000000000000000000000000000000..0403f91b94c054efa12087ad60d00af0a07e8ec9 --- /dev/null +++ b/isis/src/base/objs/ObliqueCylindrical/ObliqueCylindrical.h @@ -0,0 +1,116 @@ +#ifndef ObliqueCylindrical_h +#define ObliqueCylindrical_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/02/08 19:02:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Projection.h" + +namespace Isis { +/** + * @brief Oblique Cylindrical Map Projection + * + * This class provides methods for the forward and inverse equations of a Oblique + * Cylindrical map projection (for a sphere). The code was converted to C++ from + * the Fortran version of the USGS General Cartographic Transformation Package + * (GCTP). In particular it was modified from the Simple + * Cylindrical code. This class inherits Projection and provides + * the four virtual methods Name(), SetGround (forward) and + * SetCoordinate (inverse), XYRange (for obtaining projection + * coordinate coverage for a latitude/longitude window) and the + * == operator. Please see the Projection class for a full + * accounting of all the methods available. + * + * This projection works by moving the north pole of the simple cylindrical projection. + * The pole latitude and longitude are the location of the new north pole, and the rotation + * is the equivalent to the center longitude in simple cylindrical. + * + * @ingroup MapProjection + * + * @author 2000-02-09 Jeff Anderson + * + * @internal + * @history 2007-06-19 Steven Lambright, Converted to ISIS3 and created XY Range search implementation + * @history 2007-06-29 Steven Lambright - Added Mapping, MappingLatitudes and + * MappingLongitudes methods. + * @history 2008-05-09 Steven Lambright - Added Name, Version methods + * @history 2010-02-08 Sharmila Prasad - Removed testing p_latitude and p_longitude in operator "==" + */ + class ObliqueCylindrical : public Isis::Projection { + public: + ObliqueCylindrical (Isis::Pvl &label, bool allowDefaults=false); + ~ObliqueCylindrical (); + bool SetGround (const double lat, const double lon); + bool SetCoordinate (const double x, const double y); + bool XYRange (double &minX, double &maxX, double &minY, double &maxY); + PvlGroup Mapping(); + PvlGroup MappingLatitudes(); + PvlGroup MappingLongitudes(); + + /** + * Returns the name of the map projection + * + * @return string Name of projection + */ + std::string Name() const { return "ObliqueCylindrical"; } + + /** + * Returns the version of the map projection + * + * + * @return std::string Version number + */ + std::string Version () const { return "1.0"; } + + bool operator==(const Isis::Projection &proj); + + double GetPoleLatitude() const { return p_poleLatitude; }; + double GetPoleLongitude() const { return p_poleLongitude; }; + double GetPoleRotation() const { return p_poleRotation; }; + + private: + void init(); + + void doSearch(double minBorder, double maxBorder, double &extremeVal, const double constBorder, + bool searchX, bool searchLongitude, bool findMin); + + void findExtreme(double &newMinBorder, double &newMaxBorder, double &minVal, double &maxVal, const double constBorder, + bool searchX, bool searchLongitude, bool findMin); + inline void SetSearchGround(const double variableBorder, const double constBorder, bool variableIsLat); + + // These are the oblique projection pole values in degrees. + double p_poleLatitude; //!< The Oblique Pole Latitude + double p_poleLongitude; //!< The Oblique Pole Longitude + double p_poleRotation; //!< The Oblique Pole Rotation + + // These are necessary for calculating X/Y range with discontinuity + std::vector p_specialLatCases; //!< Constant Latitudes that intersect a discontinuitiy + std::vector p_specialLonCases; //!< Constant Longitudes that intersect a discontinuitiy + + // These vectors are not used by the projection + std::vector p_xAxisVector; + std::vector p_yAxisVector; + std::vector p_zAxisVector; + }; +}; + +#endif + diff --git a/isis/src/base/objs/ObliqueCylindrical/ObliqueCylindrical.truth b/isis/src/base/objs/ObliqueCylindrical/ObliqueCylindrical.truth new file mode 100644 index 0000000000000000000000000000000000000000..cb370ddd4e99f92ea6284863456a5a5d33a66e57 --- /dev/null +++ b/isis/src/base/objs/ObliqueCylindrical/ObliqueCylindrical.truth @@ -0,0 +1,81 @@ +UNIT TEST FOR ObliqueCylindrical + +Test missing pole rotation keyword ... +**I/O ERROR** Invalid label group [Mapping] +**PVL ERROR** Keyword [PoleRotation] does not exist in [Group = Mapping] + +Testing operator == ... +(p1==p2) = True + +Test X,Y,Z Axis Vector Calculations ... +Map Group Data (X[0]): -0.514035 +Map Group Data (X[1]): 0.568173 +Map Group Data (X[2]): -0.64261 +Map Group Data (Y[0]): -0.747567 +Map Group Data (Y[1]): 0.0706105 +Map Group Data (Y[2]): 0.660423 +Map Group Data (Z[0]): 0.420609 +Map Group Data (Z[1]): 0.819874 +Map Group Data (Z[2]): 0.388451 + +Test SetCoordinate method ... +Setting coordinate to (-2646.237039,-537.814519) +Latitude: -40.04353207704 +Longitude: 227.8893979987 +XCoord: -2646.237039 +YCoord: -537.814519 + +Test SetGround method ... +Setting ground to (-40.04353208,227.889398) +Latitude: -40.04353208 +Longitude: 227.889398 +XCoord: -2646.237039 +YCoord: -537.814519 + +Test XYRange method ... + + +Minimum X: -8089601.1 +Maximum X: 8089601.1 +Minimum Y: -3113684.4 +Maximum Y: 1169055.3 + +Test Name and comparision method ... +Name: ObliqueCylindrical +operator== 1 + +Test Name and comparision method with differing data... +Name: ObliqueCylindrical +operator== 0 + +Testing Mapping() methods ... +Mapping() = +Group = Mapping + ProjectionName = ObliqueCylindrical + EquatorialRadius = 2575000.0 + PolarRadius = 2575000.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveWest + LongitudeDomain = 360 + MinimumLatitude = -90 + MaximumLatitude = 0.92523 + MinimumLongitude = -0.8235 + MaximumLongitude = 180.5 + PoleLatitude = 22.858149 + PoleLongitude = 297.158602 + PoleRotation = 45.7832 +End_Group +End +MappingLatitudes() = +Group = Mapping + MinimumLatitude = -90 + MaximumLatitude = 0.92523 +End_Group +End +MappingLongitudes() = +Group = Mapping + MinimumLongitude = -0.8235 + MaximumLongitude = 180.5 +End_Group +End + diff --git a/isis/src/base/objs/ObliqueCylindrical/Projection.plugin b/isis/src/base/objs/ObliqueCylindrical/Projection.plugin new file mode 100644 index 0000000000000000000000000000000000000000..7999d2b8bca07ecc09f2e2faefb0914e6a0a2106 --- /dev/null +++ b/isis/src/base/objs/ObliqueCylindrical/Projection.plugin @@ -0,0 +1,6 @@ +Group = ObliqueCylindrical + Library = ObliqueCylindrical + Routine = ObliqueCylindricalPlugin + Keyword = CenterLongitude +EndGroup + diff --git a/isis/src/base/objs/ObliqueCylindrical/unitTest.cpp b/isis/src/base/objs/ObliqueCylindrical/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dde0d9505d41454eb93e2c20c4dd47744bd8513d --- /dev/null +++ b/isis/src/base/objs/ObliqueCylindrical/unitTest.cpp @@ -0,0 +1,148 @@ +#include +#include +#include +#include "iException.h" +#include "ObliqueCylindrical.h" +#include "ProjectionFactory.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "UNIT TEST FOR ObliqueCylindrical" << endl << endl; + + Isis::Pvl lab; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGrp = lab.FindGroup("Mapping"); + + mapGrp += Isis::PvlKeyword("EquatorialRadius",2575000.0); + mapGrp += Isis::PvlKeyword("PolarRadius",2575000.0); + + mapGrp += Isis::PvlKeyword("PoleLatitude", 22.858149); + mapGrp += Isis::PvlKeyword("PoleLongitude", 297.158602); + + mapGrp += Isis::PvlKeyword("LatitudeType","Planetocentric"); + mapGrp += Isis::PvlKeyword("LongitudeDirection","PositiveWest"); + mapGrp += Isis::PvlKeyword("LongitudeDomain",360); + mapGrp += Isis::PvlKeyword("ProjectionName","ObliqueCylindrical"); + + mapGrp += Isis::PvlKeyword("MinimumLatitude",-90); + mapGrp += Isis::PvlKeyword("MaximumLatitude",0.92523); + mapGrp += Isis::PvlKeyword("MinimumLongitude",-0.8235); + mapGrp += Isis::PvlKeyword("MaximumLongitude",180.5); + + cout << "Test missing pole rotation keyword ..." << endl; + try { + Isis::ObliqueCylindrical p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + // Add the missing keyword "PoleRotation" + mapGrp += Isis::PvlKeyword("PoleRotation", 45.7832); + + // testing operator == + cout << "Testing operator == ..." << endl; + try { + Isis::ObliqueCylindrical p1(lab); + Isis::ObliqueCylindrical p2(lab); + bool flag = (p1 == p2); + if (flag) { + cout << "(p1==p2) = True" << endl; + } + else { + cout << "*** Error ****"<< endl; + } + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + try { + + Isis::Projection &p = *Isis::ProjectionFactory::Create(lab); + + cout << "Test X,Y,Z Axis Vector Calculations ... " << endl; + cout << "Map Group Data (X[0]): " << (double)mapGrp["XAxisVector"][0] << endl; + cout << "Map Group Data (X[1]): " << (double)mapGrp["XAxisVector"][1] << endl; + cout << "Map Group Data (X[2]): " << (double)mapGrp["XAxisVector"][2] << endl; + cout << "Map Group Data (Y[0]): " << (double)mapGrp["YAxisVector"][0] << endl; + cout << "Map Group Data (Y[1]): " << (double)mapGrp["YAxisVector"][1] << endl; + cout << "Map Group Data (Y[2]): " << (double)mapGrp["YAxisVector"][2] << endl; + cout << "Map Group Data (Z[0]): " << (double)mapGrp["ZAxisVector"][0] << endl; + cout << "Map Group Data (Z[1]): " << (double)mapGrp["ZAxisVector"][1] << endl; + cout << "Map Group Data (Z[2]): " << (double)mapGrp["ZAxisVector"][2] << endl; + cout << endl; + + const double X = -2646.237039, Y = -537.814519; + cout << setprecision(13); + cout << "Test SetCoordinate method ... " << endl; + cout << "Setting coordinate to (" << X << "," << Y << ")" << endl; + p.SetCoordinate(X,Y); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + cout << "Test SetGround method ... " << endl; + cout << std::setprecision(10); + cout << "Setting ground to (" << p.Latitude() << "," << p.Longitude() << ")" << endl; + p.SetGround(p.Latitude(),p.Longitude()); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + cout << "Test XYRange method ... " << endl; + cout << std::setprecision(8); + double minX = 0.0,maxX = 1.0,minY = 2.0,maxY = 3.0; + p.XYRange(minX,maxX,minY,maxY); + cout << "\n\nMinimum X: " << minX << endl; + cout << "Maximum X: " << maxX << endl; + cout << "Minimum Y: " << minY << endl; + cout << "Maximum Y: " << maxY << endl; + cout << endl; + + Isis::Projection *s = &p; + cout << "Test Name and comparision method ... " << endl; + cout << "Name: " << s->Name() << endl; + cout << "operator== " << (*s == *s) << endl; + cout << endl; + + mapGrp["PoleRotation"] = 43.8423; + Isis::ObliqueCylindrical different(lab); + cout << "Test Name and comparision method with differing data... " << endl; + cout << "Name: " << s->Name() << endl; + cout << "operator== " << (different == *s) << endl; + cout << endl; + + cout << "Testing Mapping() methods ... " << endl; + + Isis::Pvl tmp1; + Isis::Pvl tmp2; + Isis::Pvl tmp3; + tmp1.AddGroup(p.Mapping()); + tmp2.AddGroup(p.MappingLatitudes()); + tmp3.AddGroup(p.MappingLongitudes()); + + cout << "Mapping() = " << endl; + cout << tmp1 << endl; + cout << "MappingLatitudes() = " << endl; + cout << tmp2 << endl; + cout << "MappingLongitudes() = " << endl; + cout << tmp3 << endl; + cout << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } +} + + + diff --git a/isis/src/base/objs/ObservationNumber/Makefile b/isis/src/base/objs/ObservationNumber/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..956baacf1be0cd325b64114ef4aac5cb4cff76d7 --- /dev/null +++ b/isis/src/base/objs/ObservationNumber/Makefile @@ -0,0 +1,5 @@ +INCS = ObservationNumber.h +SRCS = ObservationNumber.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ObservationNumber/ObservationNumber.cpp b/isis/src/base/objs/ObservationNumber/ObservationNumber.cpp new file mode 100644 index 0000000000000000000000000000000000000000..defc590bb5b8ba57144c06299849735a5da20a69 --- /dev/null +++ b/isis/src/base/objs/ObservationNumber/ObservationNumber.cpp @@ -0,0 +1,158 @@ +#include "ObservationNumber.h" +#include "iException.h" +#include "Pvl.h" +#include "Cube.h" +#include "Process.h" +#include "PvlTranslationManager.h" +#include "Filename.h" + +namespace Isis { + /** + * Create an empty SerialNumber object. + */ + ObservationNumber::ObservationNumber () {} + + /** + * Destroy a SerialNumber object. + */ + ObservationNumber::~ObservationNumber () {} + + /** + * Compose a ObservationNumber from a PVL. + * + * @param label A pvl formatted label to be used to generate the serial number + */ + std::string ObservationNumber::Compose (Pvl &label, bool def2filename) { + std::string sn; + try { + PvlGroup snGroup = FindObservationTranslation (label); + sn = CreateSerialNumber (snGroup,(int)snGroup["ObservationKeys"]); + } + catch (iException &e) { + e.Clear(); + if (def2filename) { + // Try to return the filename if it exists in the label, otherwise use + // "Unknown" as a last resort. + std::string snTemp = label.Filename(); + if (!snTemp.empty()) { + sn = Filename(snTemp).Name(); + } + else { + sn = "Unknown"; + } + } + else { + sn = "Unknown"; + } + } + + return sn; + } + + /** + * Compose a SerialNumber fPvlGroup snGrouprom a Cube. + * + * @param cube An opened Isis cube + */ + std::string ObservationNumber::Compose (Cube &cube, bool def2filename) { + return Compose(*cube.Label(), def2filename); + } + + /** + * Compose a SerialNumber from a file. + * + * @param filename a filename to open + */ + std::string ObservationNumber::Compose (const std::string &filename, bool def2filename) { + Pvl p(filename); + return Compose(p, def2filename); + } + + /** + * Get Groups by translating from correct Translation table + * + * @param label A pvl formatted label to be used to generate the serial number + */ + PvlGroup ObservationNumber::FindObservationTranslation (Pvl &label) { + Pvl outLabel; + static PvlGroup dataDir (Preference::Preferences().FindGroup("DataDirectory")); + + // Get the mission name + static std::string missionTransFile = (std::string) dataDir["base"] + "/translations/MissionName2DataDir.trn"; + static PvlTranslationManager missionXlater (missionTransFile); + missionXlater.SetLabel(label); + std::string mission = missionXlater.Translate ("MissionName"); + + // Get the instrument name + static std::string instTransFile = (std::string) dataDir["base"] + "/translations/Instruments.trn"; + static PvlTranslationManager instrumentXlater (instTransFile); + instrumentXlater.SetLabel(label); + std::string instrument = instrumentXlater.Translate ("InstrumentName"); + + // We want to use this instrument's translation manager. It's much faster for + // ObservationNumberList if we keep the translation manager in memory, so re-reading + // from the disk is not necessary every time. To do this, we'll use a map to store + // the translation managers and observation number keys with a string identifier to find them. + // This identifier needs to have the mission name and the instrument name. + static std::map > missionTranslators; + std::string key = mission + "_" + instrument; + std::map >::iterator + translationIterator = missionTranslators.find(key); + + if(translationIterator == missionTranslators.end()) { + // Get the file + Filename snFile = (std::string) dataDir[mission] + "/translations/" + instrument + "SerialNumber????.trn"; + snFile.HighestVersion(); + + // Delets the extra + Pvl translation(snFile.Expanded()); + PvlKeyword observationKeys; + if (translation.HasKeyword("ObservationKeys")) { + observationKeys = translation["ObservationKeys"]; + } + + // use the translation file to generate keywords + missionTranslators.insert( + std::pair > + (key, std::pair(PvlTranslationManager(snFile.Expanded()), observationKeys)) + ); + + translationIterator = missionTranslators.find(key); + } + + translationIterator->second.first.SetLabel(label); + translationIterator->second.first.Auto(outLabel); + PvlGroup snGroup = outLabel.FindGroup("SerialNumberKeywords"); + + // Delets the extra + if (!translationIterator->second.second.Name().empty()) { + snGroup += translationIterator->second.second; + } + else { + snGroup += PvlKeyword("ObservationKeys", snGroup.Keywords()); + } + + return snGroup; + } + + /** + * Creates a vector of plasible SerialNumbers from a string + * representing the ObservationNumber and a SerialList. + * + * @param on the string representing the ObservationNumber + * + * @param list the SerialNumberList + */ + std::vector ObservationNumber::PossibleSerial (const std::string &on, SerialNumberList &list ) { + std::vector sn; + for( int i=0; i + +#include "SerialNumber.h" +#include "SerialNumberList.h" + +namespace Isis { + +/** + * @brief Serial Number composer + * + * A Serial Number is a unique identification for some object such as an + * Isis cube. A Serial Number for a specific object must be repeatable. This + * class is intended to be used to create all Serial Numbers for Isis. + * + * @ingroup ControlNetworks + * + * @author 2008-??-?? Christopher Austin + * + * @internal + * + * @todo This is only a temporary version. The code needs to be modified + * to use a PVL file to determine which keywords to use to create the + * Serial Number + * + * @history 2008-01-08 Christpher Austin - Original Version, + * a derivative of the previous SerialNumber class + * + * @history 2008-05-09 Steven Lambright - Optimized the + * FindObservationTranslation method + */ + + // Forward declarations + class Pvl; + class PvlGroup; + class Cube; + + class ObservationNumber : public Isis::SerialNumber { + public: + ObservationNumber (); + + virtual ~ObservationNumber (); + + static std::string Compose (Pvl &label, bool def2filename=false); + + static std::string Compose (Cube &cube, bool def2filename=false); + + static std::string Compose (const std::string &filename, bool def2filename=false); + + std::vector PossibleSerial (const std::string &on, SerialNumberList &list ); + + private: + + static PvlGroup FindObservationTranslation (Pvl &label); + + }; // End of Class +}; // End of namespace + +#endif diff --git a/isis/src/base/objs/ObservationNumber/ObservationNumber.truth b/isis/src/base/objs/ObservationNumber/ObservationNumber.truth new file mode 100644 index 0000000000000000000000000000000000000000..5fabb2a64134222f3f82e79b14557502a5108694 --- /dev/null +++ b/isis/src/base/objs/ObservationNumber/ObservationNumber.truth @@ -0,0 +1 @@ +LO3/HRC/3133 diff --git a/isis/src/base/objs/ObservationNumber/unitTest.cpp b/isis/src/base/objs/ObservationNumber/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..534f2e367e228205c312fffe09fab78356d07616 --- /dev/null +++ b/isis/src/base/objs/ObservationNumber/unitTest.cpp @@ -0,0 +1,18 @@ +#include +#include "Filename.h" +#include "Pvl.h" +#include "ObservationNumber.h" +#include "Cube.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + Isis::Filename file("$lo/testData/3133_h1.cub"); + Isis::Pvl p1(file.Expanded()); + + std::cout << Isis::ObservationNumber::Compose(p1) << std::endl; + + return (0); +} diff --git a/isis/src/base/objs/ObservationNumberList/Makefile b/isis/src/base/objs/ObservationNumberList/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..345784725f2b44aa6a9a44db7742b1c475353da6 --- /dev/null +++ b/isis/src/base/objs/ObservationNumberList/Makefile @@ -0,0 +1,5 @@ +INCS = ObservationNumberList.h +SRCS = ObservationNumberList.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ObservationNumberList/ObservationNumberList.cpp b/isis/src/base/objs/ObservationNumberList/ObservationNumberList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b0bfc5b231915344207c915da38bd9ba40a1c309 --- /dev/null +++ b/isis/src/base/objs/ObservationNumberList/ObservationNumberList.cpp @@ -0,0 +1,257 @@ +#include "ObservationNumberList.h" +#include "iException.h" +#include "FileList.h" +#include "Filename.h" +#include "SerialNumberList.h" +#include "iString.h" +#include "Pvl.h" + +namespace Isis { + /** + * Creates an ObservationNumberList from a filename + * + * @param listfile The list of files to be given observation + * numbers + * @param checkTarget Boolean value that specifies whether or not to check + * to make sure the target names match between files added + * to the observationnumber list + */ + ObservationNumberList::ObservationNumberList (const std::string &listfile, bool checkTarget) : + SerialNumberList( listfile, checkTarget ) { + init ( this ); + } + + /** + * Creates an ObservationNumberList from a SerialNumberList + * + * @param snlist The serial number list from which to generate an observation number list + */ + ObservationNumberList::ObservationNumberList (Isis::SerialNumberList *snlist) : + SerialNumberList(*snlist) { + init ( snlist ); + } + + /** + * Initiates the ObservationNumberList + * + * @param snlist The already created SerialNumberList used to + * create the ObservationNumberList object + */ + void ObservationNumberList::init ( Isis::SerialNumberList *snlist ) { + + if (snlist->Size() == 0) { + std::string msg = "Serial number list is empty"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + std::map observationMap; + std::string observationNumber; + int currentIndex = 0; + int observationIndex; + + // Fill the temporary map to generate observation sets + for (int isn=0; isn < snlist->Size(); isn++) { + observationNumber = snlist->ObservationNumber(isn); + + if (observationMap.find(observationNumber) == observationMap.end()) { + observationMap.insert(std::pair(observationNumber, currentIndex)); + observationIndex = currentIndex++; + } + else { + observationIndex = observationMap.find(observationNumber)->second; + } + + Add (isn, observationIndex, observationNumber); + } + p_numberObservations = currentIndex; + } + + /** + * Destructor + */ + ObservationNumberList::~ObservationNumberList () { + } + + /** + * Removes all of the listed serial numbers from the observation + * + * @param snlist The list of SerialNumbers to remove + */ + void ObservationNumberList::Remove( Isis::SerialNumberList *snlist ) { + + if (snlist->Size() == 0) { + std::string msg = "Removing serial number list is empty"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_sets.clear(); + p_indexMap.clear(); + + std::map observationMap; + std::string observationNumber; + int currentIndex = 0; + int observationIndex; + + // Fill the temporary map to generate observation sets + for (int isn=0; isn < this->Size(); isn++) { + if ((snlist->HasSerialNumber(this->SerialNumber(isn)))) continue; + observationNumber = this->ObservationNumber(isn); + + if (observationMap.find(observationNumber) == observationMap.end()) { + observationMap.insert(std::pair(observationNumber, currentIndex)); + observationIndex = currentIndex++; + } + else { + observationIndex = observationMap.find(observationNumber)->second; + } + + Add (isn, observationIndex, observationNumber); + } + p_numberObservations = currentIndex; + } + + + /** + * Removes all of the listed serial numbers from the observation + * + * @param listfile The list of SerialNumbers to remove + */ + void ObservationNumberList::Remove (const std::string &listfile) { + Isis::SerialNumberList snlist( listfile ); + Remove( &snlist ); + } + + + /** + * Adds a new serial number index / observation number index / observation + * number to the SerialNumberList + * + * @param isn The serial number index of the observation set to be added + * @param observationIndex The observation number index of the observation set + * to be added + * @param observationNumber The observation number of the observation set to + * be added + * + */ + void ObservationNumberList::Add (const int isn, const int observationIndex, + std::string observationNumber) { + + ObservationSet nextset; + nextset.serialNumberIndex = isn; + nextset.observationNumberIndex = observationIndex; + nextset.observationNumber = observationNumber; + + p_sets.push_back(nextset); + p_indexMap.insert(std::pair(isn,observationIndex)); + } + + /** + * How many unique observations are in the list? + * + * @return int Returns number of unique observations currently in the list + */ + int ObservationNumberList::ObservationSize () const { + return p_numberObservations; + } + + + /** + * Determines whether or not the requested observation number + * exists in the list + * + * @param on The observation number to be checked for + * + * @return bool + */ + bool ObservationNumberList::HasObservationNumber (const std::string &on) { + for ( unsigned index=0; index= 0 && serialNumberIndex < (int) p_indexMap.size()) { + if (serialNumberIndex >= 0 ) { + return p_indexMap.find(serialNumberIndex)->second; + } + else { + iString num = iString(serialNumberIndex); + std::string msg = "Serial Number Index [" + (std::string) num + "] is invalid"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + + + /** + * return an observation number given a filename + * + * @param filename The filename to be matched + * + * @return std::string The observation number corresponding to + * the input filename + */ + std::string ObservationNumberList::ObservationNumber(const std::string &filename){ + if (p_fileMap.find(Isis::Filename(filename).Expanded()) == p_fileMap.end()) { + std::string msg = "Requested filename [" + + Isis::Filename(filename).Expanded() + "]"; + msg += "does not exist in the list"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + int index = FilenameIndex(filename); + return p_pairs[index].observationNumber; + } + + /** + * Return a observation number given an index + * + * @param index The index of the desired observation number + * + * @return std::string The observation number returned + */ + std::string ObservationNumberList::ObservationNumber (int index) { + if (index >= 0 && index < (int) p_pairs.size()) { + return p_pairs[index].observationNumber; + } + else { + iString num = iString(index); + std::string msg = "Index [" + (std::string) num + "] is invalid"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + + /** + * Return possible filenames given an observation number + * + * @param on The observation number of the desired filename + * + * @return vector The list of possible filenames + * matching the input observation number + */ + std::vector ObservationNumberList::PossibleFilenames (const std::string &on) { + std::vector filenames; + for( unsigned index=0; index 0 ) { + return filenames; + } + else { + std::string msg = "Requested observation number [" + on + "] "; + msg += "does not exist in the list"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + +} diff --git a/isis/src/base/objs/ObservationNumberList/ObservationNumberList.h b/isis/src/base/objs/ObservationNumberList/ObservationNumberList.h new file mode 100644 index 0000000000000000000000000000000000000000..292f10e353b985ae0eb735655d3084f97e1c454d --- /dev/null +++ b/isis/src/base/objs/ObservationNumberList/ObservationNumberList.h @@ -0,0 +1,90 @@ +#ifndef ObservationNumberList_h +#define ObservationNumberList_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/10/30 16:19:46 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + * + */ + +#include +#include +#include + +#include "SerialNumberList.h" + +namespace Isis { + + /** + * @brief Needs Documentation + * + * Needs Documentation + * + * @author 2007-09-17 Debbie A. Cook + * + * @internal + * @history 2007-09-17 Debbie A. Cook - Original version + * @history 2008-01-11 Christopher Austin - Made class more + * general, inheriting SerialNumberList among others + * @history 2008-05-01 Debbie A. Cook - Removed upper bound check + * in ObservationNumberMapIndex because when entries are + * removed from the observation list, the serialNumberIndex + * may exceed the size of the map + * @history 2008-06-18 Steven Koechle - Fixed Documentation Errors + * @history 2008-10-30 Steven Lambright - Fixed problem with definition + * of struct quad, pointed out by "novus0x2a" (Support Board Member) + */ + class ObservationNumberList : public Isis::SerialNumberList { + public: + ObservationNumberList (const std::string &list, bool checkTarget=true); + ObservationNumberList(Isis::SerialNumberList *snlist); + ~ObservationNumberList(); + + void Add (int isn, const int observationIndex,std::string observationNumber) ; + int ObservationSize () const; + + int ObservationNumberMapIndex(const int serialNumberIndex ); + + void Remove ( Isis::SerialNumberList *snlist ); + void Remove (const std::string &listfile); + + bool HasObservationNumber (const std::string &on); + + std::string ObservationNumber(const std::string &filename); + std::string ObservationNumber (int index); + std::vector PossibleFilenames (const std::string &on); + + private: + struct ObservationSet { + int serialNumberIndex; + int observationNumberIndex; + std::string observationNumber; + }; + + void init ( Isis::SerialNumberList *snlist ); + + std::vector p_sets; + std::multimap p_indexMap; + int p_numberObservations; + }; +}; + +#endif + diff --git a/isis/src/base/objs/ObservationNumberList/ObservationNumberList.truth b/isis/src/base/objs/ObservationNumberList/ObservationNumberList.truth new file mode 100644 index 0000000000000000000000000000000000000000..1615461687d0f541b15c4592df3d3f9df148943a --- /dev/null +++ b/isis/src/base/objs/ObservationNumberList/ObservationNumberList.truth @@ -0,0 +1,18 @@ +size = 4 +hasXYZ = 0 +/usgs/cpkgs/isis3/data/mgs/testData/ab102401.cub = MGS/561812335:32/MOC-WA +/usgs/cpkgs/isis3/data/mgs/testData/m0402852.cub = MGS/619971158:28/MOC-NA +/usgs/cpkgs/isis3/data/lo/testData/3133_h1.cub = LO3/HRC/3133 +/usgs/cpkgs/isis3/data/odyssey/testData/I00824006RDR.lev2.cub = Odyssey/THEMIS_IR/698670100.051 + +Possible filename for [LO3/HRC/3133]: /usgs/cpkgs/isis3/data/lo/testData/3133_h1.cub +Possible serial number for [LO3/HRC/3133]: LO3/HRC/3133/1 +File->ON:MGS/561812335:32/MOC-WA + +SN->File (0): /usgs/cpkgs/isis3/data/mgs/testData/ab102401.cub +SN->File (1): /usgs/cpkgs/isis3/data/mgs/testData/m0402852.cub +SN->File (2): /usgs/cpkgs/isis3/data/lo/testData/3133_h1.cub + +[NotAnObservation] is not an existing ObservationNumber + + diff --git a/isis/src/base/objs/ObservationNumberList/unitTest.cpp b/isis/src/base/objs/ObservationNumberList/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a197128612473abaffe4206b2a89d6c5fe654686 --- /dev/null +++ b/isis/src/base/objs/ObservationNumberList/unitTest.cpp @@ -0,0 +1,56 @@ +#include +#include "ObservationNumberList.h" +#include "SerialNumberList.h" +#include "iException.h" + +using namespace std; +int main (int argc, char *argv[]) { + + try { + Isis::SerialNumberList snl(false); + + snl.Add("$mgs/testData/ab102401.cub"); + snl.Add("$mgs/testData/m0402852.cub"); + snl.Add("$lo/testData/3133_h1.cub"); + snl.Add("$odyssey/testData/I00824006RDR.lev2.cub"); + + Isis::ObservationNumberList onl( &snl ); + + cout << "size = " << onl.Size() << endl; + cout << "hasXYZ = " << onl.HasObservationNumber("XYZ") << endl; + + for (int i=0; i serials = onl.PossibleSerialNumbers( onl.ObservationNumber(2) ); + for( unsigned i=0; iON:" << onl.ObservationNumber("$mgs/testData/ab102401.cub") << endl; + + cout << endl << "SN->File (0): " << snl.Filename(0) << endl; + cout << "SN->File (1): " << snl.Filename(1) << endl; + cout << "SN->File (2): " << snl.Filename(2) << endl << endl; + + if( onl.HasObservationNumber("NotAnObservation") ) + cout << "This line shouldn't be showing!" << endl; + else + cout << "[NotAnObservation] is not an existing ObservationNumber" << endl; + + } + catch (Isis::iException &e) { + e.Report(false); + } + + cout << endl << endl;; + +} diff --git a/isis/src/base/objs/OriginalLabel/Makefile b/isis/src/base/objs/OriginalLabel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bebd8d2780a821f35416a375ca06c18e308e1c69 --- /dev/null +++ b/isis/src/base/objs/OriginalLabel/Makefile @@ -0,0 +1,5 @@ +INCS = OriginalLabel.h +SRCS = OriginalLabel.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/OriginalLabel/OriginalLabel.cpp b/isis/src/base/objs/OriginalLabel/OriginalLabel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a82030601eb49b0217125aa2efc83f0d07b2c3c --- /dev/null +++ b/isis/src/base/objs/OriginalLabel/OriginalLabel.cpp @@ -0,0 +1,109 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/05/14 19:20:28 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include "OriginalLabel.h" +#include "Application.h" +#include "PvlObject.h" + +using namespace std; +namespace Isis { + /** + * Constructor for creating an original blob with a given name + */ + OriginalLabel::OriginalLabel() : Isis::Blob("IsisCube", "OriginalLabel") { + m_originalLabel.SetTerminator(""); + } + + /** + * Constructor for creating an original blob with a given name and file to + * read labels from. + * + * @param file File to read labels from + */ + OriginalLabel::OriginalLabel(const std::string &file) : + Isis::Blob("IsisCube", "OriginalLabel") { + Blob::Read(file); + } + + /** + * Constructor for creating an original blob with a given name and Pvl + * container. + * + * @param pvl Pvl containing labels of the source + */ + OriginalLabel::OriginalLabel(Pvl pvl) : Isis::Blob("IsisCube", "OriginalLabel") { + m_originalLabel = pvl; + } + + // Destructor + OriginalLabel::~OriginalLabel() { + } + + /** + * Prepare labels for writing to the output cube. + */ + void OriginalLabel::WriteInit() { + ostringstream ostr; + if(p_nbytes > 0) ostr << std::endl; + + // store labels + ostr << m_originalLabel; + string orglblStr = ostr.str(); + int bytes = orglblStr.size(); + + // Copy label data to bytes variable + char *temp = p_buffer; + p_buffer = new char[p_nbytes+bytes]; + if(temp != NULL) memcpy(p_buffer, temp, p_nbytes); + const char *ptr = orglblStr.c_str(); + memcpy(&p_buffer[p_nbytes], (void *)ptr, bytes); + p_nbytes += bytes; + + if(temp != NULL) delete [] temp; + } + + /** + * Returns the labels in a Pvl object + * + * @return (Isis::Pvl) original labels + */ + Pvl OriginalLabel::ReturnLabels() { + Pvl pvl; + stringstream os; + for(int i = 0; i < p_nbytes; i++) os << p_buffer[i]; + os >> pvl; + return pvl; + } + + /** + * Fill pvl with original label data. + * + * @param[out] pvl Pvl to store original label data + * @param[out] is file stream to get data from + */ + void OriginalLabel::Read(Isis::Pvl &pvl, std::istream &is) { + Blob::Read(pvl, is); + } +} diff --git a/isis/src/base/objs/OriginalLabel/OriginalLabel.h b/isis/src/base/objs/OriginalLabel/OriginalLabel.h new file mode 100644 index 0000000000000000000000000000000000000000..d5e1f79bf3caf236d6793cd2c7c3f56c111f413d --- /dev/null +++ b/isis/src/base/objs/OriginalLabel/OriginalLabel.h @@ -0,0 +1,74 @@ +#ifndef OriginalLabel_h +#define OriginalLabel_h + +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/05/14 19:20:28 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Blob.h" +#include "Pvl.h" + +namespace Isis { + /** + * @brief Read and store original labels. + * + * This class provides a means to read and store the labels from the original + * source. The labels can be retreived in a Pvl object. + * + * @ingroup LowLevelCubeIO + * + * @author 2006-02-23 Robert Wallace and Brian Lipkowitz + * + * @history 2006-06-13 Brendan George - Modified to throw error when called + * file does not contain an Original Label + * @history 2006-12-11 Kris Becker - Fixed bug in WriteInit method using a + * temporary string to reference a char pointer + * to its contents. The string remain after the + * reference or its toast. + * @history 2008-06-18 Steven Koechle - Fixed Documentation Errors + * + */ + class OriginalLabel : public Isis::Blob { + public: + OriginalLabel(); + OriginalLabel(const std::string &file); + OriginalLabel(Pvl pvl); + ~OriginalLabel(); + + // Return the original labels + Pvl ReturnLabels(); + + // Read original labels from file + void Read(Isis::Pvl &pvl, std::istream &is); + + protected: + // prepare data for writing + void WriteInit(); + + private: + // labels of original source + Pvl m_originalLabel; + }; +}; + +#endif + diff --git a/isis/src/base/objs/OriginalLabel/OriginalLabel.truth b/isis/src/base/objs/OriginalLabel/OriginalLabel.truth new file mode 100644 index 0000000000000000000000000000000000000000..e851492e75be9581df99d7f8a5010dd506e87790 --- /dev/null +++ b/isis/src/base/objs/OriginalLabel/OriginalLabel.truth @@ -0,0 +1,10 @@ +Group = Test + Keyword = Value +End_Group +End + +Group = Test + Keyword = Value +End_Group +End +Same pvls diff --git a/isis/src/base/objs/OriginalLabel/unitTest.cpp b/isis/src/base/objs/OriginalLabel/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1dee48189a5a23438daeab2d7638ea8ca0d9fddd --- /dev/null +++ b/isis/src/base/objs/OriginalLabel/unitTest.cpp @@ -0,0 +1,41 @@ +/** + * Unit Test for OriginalLabel class. + */ + + +#include +#include +#include "Pvl.h" +#include "OriginalLabel.h" +#include "Preference.h" + +using namespace std; +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + Isis::Pvl p; + + Isis::PvlGroup g("Test"); + g += Isis::PvlKeyword("Keyword", "Value"); + p.AddGroup(g); + + cout << p << endl; + Isis::OriginalLabel ol(p); + + ol.Write("olTemp"); + + Isis::OriginalLabel ol2("olTemp"); + + Isis::Pvl test = ol2.ReturnLabels(); + + cout << endl; + cout << test << endl; + + if(p == test) { + cout << "Same pvls" << endl; + } + else { + cout << "different pvls" << endl; + } + remove("olTemp"); +} diff --git a/isis/src/base/objs/Orthographic/Makefile b/isis/src/base/objs/Orthographic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..dab6ac697490ebc31dd1a9fccc9e3421274c2fbf --- /dev/null +++ b/isis/src/base/objs/Orthographic/Makefile @@ -0,0 +1,5 @@ +INCS = Orthographic.h +SRCS = Orthographic.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Orthographic/Orthographic.cpp b/isis/src/base/objs/Orthographic/Orthographic.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af60b21d226213886695ab689d903c39f49124ff --- /dev/null +++ b/isis/src/base/objs/Orthographic/Orthographic.cpp @@ -0,0 +1,360 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/05/09 18:49:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Orthographic.h" +#include "iException.h" +#include "Constants.h" + +using namespace std; +namespace Isis { + /** + * Constructs an Orthographic object + * + * @param label This argument must be a Label containing the proper mapping + * information as indicated in the Projection class. Additionally, + * the orthographic projection requires the center longitude to be + * defined in the keyword CenterLongitude. + * + * @param allowDefaults If set to false the constructor expects that a keyword + * of CenterLongitude will be in the label. Otherwise it + * will attempt to compute the center longitude using the + * middle of the longitude range specified in the labels. + * Defaults to false. + * + * @throws Isis::iException::Io + */ + Orthographic::Orthographic(Isis::Pvl &label, bool allowDefaults) : + Isis::Projection::Projection (label) { + try { + // Try to read the mapping group + Isis::PvlGroup &mapGroup = label.FindGroup ("Mapping",Isis::Pvl::Traverse); + + // Compute and write the default center longitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLongitude"))) { + double lon = (p_minimumLongitude + p_maximumLongitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLongitude",lon); + } + + // Compute and write the default center latitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLatitude"))) { + double lat = (p_minimumLatitude + p_maximumLatitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLatitude",lat); + } + + // Get the center longitude & latitude + p_centerLongitude = mapGroup["CenterLongitude"]; + p_centerLatitude = mapGroup["CenterLatitude"]; + if (this->IsPlanetocentric()) { + p_centerLatitude = this->ToPlanetographic(p_centerLatitude); + } + + // convert to radians, adjust for longitude direction + p_centerLongitude *= Isis::PI / 180.0; + p_centerLatitude *= Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) p_centerLongitude *= -1.0; + + // Calculate sine & cosine of center latitude + sinph0 = sin(p_centerLatitude); + cosph0 = cos(p_centerLatitude); + + } + catch (Isis::iException &e) { + string message = "Invalid label group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + //! Destroys the Orthographic object + Orthographic::~Orthographic() { + } + + /** + * This method is used to set the latitude/longitude (assumed to be of the + * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. + * + * @param lat Latitude value to project + * + * @param lon Longitude value to project + * + * @return bool + */ + bool Orthographic::SetGround(const double lat,const double lon) { + // Convert longitude to radians & clean up + p_longitude = lon; + double lonRadians = lon * Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) lonRadians *= -1.0; + + // Now convert latitude to radians & clean up ... it must be planetographic + p_latitude = lat; + double latRadians = lat; + if (IsPlanetocentric()) latRadians = ToPlanetographic(latRadians); + latRadians *= Isis::PI / 180.0; + + // Compute helper variables + double deltaLon = (lonRadians - p_centerLongitude); + double sinphi = sin(latRadians); + double cosphi = cos(latRadians); + double coslon = cos(deltaLon); + + // Lat/Lon cannot be projected + double g = sinph0*sinphi + cosph0*cosphi*coslon; + if ((g <= 0.0) && (fabs(g) > 1.0e-10)) { + p_good = false; + return p_good; + } + + // Compute the coordinates + double x = p_equatorialRadius * cosphi * sin(deltaLon); + double y = p_equatorialRadius * (cosph0 * sinphi - sinph0 * cosphi * coslon); + SetComputedXY(x,y); + p_good = true; + return p_good; + } + + /** + * This method is used to set the projection x/y. The Set forces an attempted + * calculation of the corresponding latitude/longitude position. This may or + * may not be successful and a status is returned as such. + * + * @param x X coordinate of the projection in units that are the same as the + * radii in the label + * + * @param y Y coordinate of the projection in units that are the same as the + * radii in the label + * + * @return bool + */ + bool Orthographic::SetCoordinate(const double x, const double y) { + // Save the coordinate + SetXY(x,y); + + // Declare instance variables and calculate rho + double rho,con,z,sinz,cosz; + const double epsilon = 1.0e-10; + rho = sqrt(GetX()*GetX() + GetY()*GetY()); + + // Error calculating rho - should be less than equatorial radius + if (rho > p_equatorialRadius) { + p_good = false; + return p_good; + } + + // Calculate the latitude and longitude + p_longitude = p_centerLongitude; + if (fabs(rho) <= epsilon) { + p_latitude = p_centerLatitude; + } + else { + con = rho / p_equatorialRadius; + if (con > 1.0) con = 1.0; + if (con < -1.0) con = -1.0; + z = asin(con); + sinz = sin(z); + cosz = cos(z); + con = cosz*sinph0 + GetY()*sinz*cosph0 / rho; + if (con > 1.0) con = 1.0; + if (con < -1.0) con = -1.0; + p_latitude = asin(con); + con = fabs(p_centerLatitude) - Isis::HALFPI; + if (fabs(con) <= epsilon) { + if(p_centerLatitude >= 0.0) { + p_longitude += atan2(GetX(), -GetY()); + } + else { + p_longitude += atan2(-GetX(), GetY()); + } + } + else { + con = cosz - sinph0 * sin(p_latitude); + if ((fabs(con) >= epsilon) || (fabs(GetX()) >= epsilon)) { + p_longitude += atan2(GetX()*sinz*cosph0, con*rho); + } + } + } + + // Convert to degrees + p_latitude *= 180.0 / Isis::PI; + p_longitude *= 180.0 / Isis::PI; + + // Cleanup the longitude + if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; + // These need to be done for circular type projections + p_longitude = To360Domain (p_longitude); + if (p_longitudeDomain == 180) p_longitude = To180Domain(p_longitude); + + // Cleanup the latitude + if (IsPlanetocentric()) p_latitude = ToPlanetocentric(p_latitude); + + p_good = true; + return p_good; + } + + /** + * This method is used to determine the x/y range which completely covers the + * area of interest specified by the lat/lon range. The latitude/longitude + * range may be obtained from the labels. The purpose of this method is to + * return the x/y range so it can be used to compute how large a map may need + * to be. For example, how big a piece of paper is needed or how large of an + * image needs to be created. The method may fail as indicated by its return + * value. + * + * @param minX Minimum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxX Maximum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param minY Minimum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxY Maximum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @return bool + */ + bool Orthographic::XYRange(double &minX, double &maxX, double &minY, double&maxY){ + double lat, lon; + + // Check the corners of the lat/lon range + XYRangeCheck (p_minimumLatitude,p_minimumLongitude); + XYRangeCheck (p_maximumLatitude,p_minimumLongitude); + XYRangeCheck (p_minimumLatitude,p_maximumLongitude); + XYRangeCheck (p_maximumLatitude,p_maximumLongitude); + + // Walk top and bottom edges + for (lat=p_minimumLatitude; lat<=p_maximumLatitude; lat+=0.01) { + lat = lat; + lon = p_minimumLongitude; + XYRangeCheck(lat,lon); + + lat = lat; + lon = p_maximumLongitude; + XYRangeCheck(lat,lon); + } + + // Walk left and right edges + for (lon=p_minimumLongitude; lon<=p_maximumLongitude; lon+=0.01) { + lat = p_minimumLatitude; + lon = lon; + XYRangeCheck(lat,lon); + + lat = p_maximumLatitude; + lon = lon; + XYRangeCheck(lat,lon); + } + + // Walk the limb + for (double angle=0.0; angle<=360.0; angle+=0.01) { + double x = p_equatorialRadius * cos(angle * Isis::PI / 180.0); + double y = p_equatorialRadius * sin(angle * Isis::PI / 180.0); + if (SetCoordinate(x,y) == 0) { + if (p_latitude > p_maximumLatitude) continue; + if (p_longitude > p_maximumLongitude) continue; + if (p_latitude < p_minimumLatitude) continue; + if (p_longitude < p_minimumLongitude) continue; + XYRangeCheck(p_latitude, p_longitude); + } + } + + // Make sure everything is ordered + if (p_minimumX >= p_maximumX) return false; + if (p_minimumY >= p_maximumY) return false; + + // Return X/Y min/maxs + minX = p_minimumX; + maxX = p_maximumX; + minY = p_minimumY; + maxY = p_maximumY; + return true; + } + + + /** + * This function returns the keywords that this projection uses. + * + * @return PvlGroup The keywords that this projection uses + */ + PvlGroup Orthographic::Mapping() { + PvlGroup mapping = Projection::Mapping(); + + mapping += p_mappingGrp["CenterLatitude"]; + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * This function returns the latitude keywords that this projection uses + * + * @return PvlGroup The latitude keywords that this projection uses + */ + PvlGroup Orthographic::MappingLatitudes() { + PvlGroup mapping = Projection::MappingLatitudes(); + + mapping += p_mappingGrp["CenterLatitude"]; + + return mapping; + } + + /** + * This function returns the longitude keywords that this projection uses + * + * @return PvlGroup The longitude keywords that this projection uses + */ + PvlGroup Orthographic::MappingLongitudes() { + PvlGroup mapping = Projection::MappingLongitudes(); + + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * Compares two Projection objects to see if they are equal + * + * @param proj Projection object to do comparison on + * + * @return bool Returns true if the Projection objects are equal, and false if + * they are not + */ + bool Orthographic::operator== (const Isis::Projection &proj) { + if (!Isis::Projection::operator==(proj)) return false; + // dont do the below it is a recusive plunge + // if (Isis::Projection::operator!=(proj)) return false; + Orthographic *ortho = (Orthographic *) &proj; + if ((ortho->p_centerLongitude != this->p_centerLongitude) || + (ortho->p_centerLatitude != this->p_centerLatitude)) return false; + return true; + } +} // end namespace isis + +extern "C" Isis::Projection *OrthographicPlugin (Isis::Pvl &lab, + bool allowDefaults) { + return new Isis::Orthographic(lab,allowDefaults); +} + diff --git a/isis/src/base/objs/Orthographic/Orthographic.h b/isis/src/base/objs/Orthographic/Orthographic.h new file mode 100644 index 0000000000000000000000000000000000000000..454197122fce57fc7859c0d93a5daba8fa9889ec --- /dev/null +++ b/isis/src/base/objs/Orthographic/Orthographic.h @@ -0,0 +1,99 @@ +#ifndef Orthographic_h +#define Orthographic_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/05/09 18:49:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Projection.h" +#include "Constants.h" + +namespace Isis { +/** + * @brief Orthographic Map Projection + * + * This class provides methods for the forward and inverse equations of an + * Orthographic map projection (for a sphere). The code was converted + * to C++ from the C version of the USGS General Cartographic Transformation + * Package (GCTP). This class inherits Projection and provides the two virtual + * methods SetGround (forward) and SetCoordinate (inverse) and a third virtual + * method, XYRange, for obtaining projection coordinate coverage for a + * latitude/longitude window. Please see the Projection class for a full + * accounting of all the methods available. + * + * @ingroup MapProjection + * + * @author 2005-03-04 Elizabeth Ribelin + * + * @internal + * @history 2005-08-22 Kris Becker - Fixed bug in XYRange method that computes + * the line/samp ranges as it was not + * correctly computing limb limits + * @history 2007-06-29 Steven Lambright - Added Mapping, MappingLatitudes and + * MappingLongitudes methods. + * @history 2008-05-09 Steven Lambright - Added Name, Version methods + */ + class Orthographic : public Isis::Projection { + public: + Orthographic(Isis::Pvl &label, bool allowDefaults=false); + ~Orthographic(); + bool SetGround (const double lat, const double lon); + bool SetCoordinate (const double x, const double y); + bool XYRange (double &minX, double &maxX, double &minY, double &maxY); + PvlGroup Mapping(); + PvlGroup MappingLatitudes(); + PvlGroup MappingLongitudes(); + + /** + * Returns the name of the map projection + * + * @return string Name of projection + */ + std::string Name() const { return "Orthographic"; } + + /** + * Returns the version of the map projection + * + * + * @return std::string Version number + */ + std::string Version () const { return "1.0"; } + + bool operator== (const Isis::Projection &proj); + + /** + * Returns the latitude of true scale (in the case of Orthographic + * it is the center latitude) + * + * @return double + */ + double TrueScaleLatitude () const { + return p_centerLatitude * 180.0 / Isis::PI; + }; + + + private: + double p_centerLongitude; //! +#include +#include "Orthographic.h" +#include "iException.h" +#include "ProjectionFactory.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "UNIT TEST FOR Orthographic" << endl << endl; + + Isis::Pvl lab; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = lab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",1.0); + mapGroup += Isis::PvlKeyword("PolarRadius",1.0); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetographic"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",180); + mapGroup += Isis::PvlKeyword("MinimumLatitude",-70.0); + mapGroup += Isis::PvlKeyword("MaximumLatitude",70.0); + mapGroup += Isis::PvlKeyword("MinimumLongitude",-180.0); + mapGroup += Isis::PvlKeyword("MaximumLongitude",180.0); + mapGroup += Isis::PvlKeyword("ProjectionName","Orthographic"); + + cout << "Test missing center longitude keyword ..." << endl; + try { + Isis::Orthographic p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("CenterLongitude",-100.0); + + cout << "Test missing center latitude keyword..." << endl; + try { + Isis::Orthographic p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("CenterLatitude", 40.0); + + try { + Isis::Projection &p = *Isis::ProjectionFactory::Create(lab); + // Isis::Orthographic p(lab); + + cout << "Test TrueScaleLatitude method... " << endl; + cout << "TrueScaleLatitude = " << p.TrueScaleLatitude() << endl; + cout << endl; + + cout << "Test SetGround method ... " << endl; + cout << std::setprecision(9); + cout << "Setting ground to (30,-110)" << endl; + p.SetGround(30.0,-110.0); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + + cout << "Test SetCoordinate method ... " << endl; + cout << "Setting coordinate to (-0.150383733, -0.165191103)" << endl; + p.SetCoordinate(-0.150383733, -0.165191103); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + cout << "Test XYRange method ... " << endl; + double minX,maxX,minY,maxY; + p.XYRange(minX,maxX,minY,maxY); + cout << "Minimum X: " << minX << endl; + cout << "Maximum X: " << maxX << endl; + cout << "Minimum Y: " << minY << endl; + cout << "Maximum Y: " << maxY << endl; + cout << endl; + + Isis::Projection *s = &p; + cout << "Test Name and comparision method ... " << endl; + cout << "Name: " << s->Name() << endl; + cout << "operator== " << (*s == *s) << endl; + cout << endl; + + cout << "Test default computation ... " << endl; + mapGroup.DeleteKeyword("CenterLongitude"); + mapGroup.DeleteKeyword("CenterLatitude"); + Isis::Orthographic p2(lab,true); + cout << lab << endl; + cout << endl; + + cout << "Testing Mapping() methods ... " << endl; + + Isis::Pvl tmp1; + Isis::Pvl tmp2; + Isis::Pvl tmp3; + tmp1.AddGroup(p.Mapping()); + tmp2.AddGroup(p.MappingLatitudes()); + tmp3.AddGroup(p.MappingLongitudes()); + + cout << "Mapping() = " << endl; + cout << tmp1 << endl; + cout << "MappingLatitudes() = " << endl; + cout << tmp2 << endl; + cout << "MappingLongitudes() = " << endl; + cout << tmp3 << endl; + cout << endl; + + cout << "Unit test was obtained from:" << endl << endl; + cout << " Map Projections - A Working Manual" << endl; + cout << " USGS Professional Paper 1395 by John P. Snyder" << endl; + cout << " Pages 311-312" << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } +} diff --git a/isis/src/base/objs/OverlapNormalization/Makefile b/isis/src/base/objs/OverlapNormalization/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..affbff2ad97f639e54291f7aff76b90e129facb3 --- /dev/null +++ b/isis/src/base/objs/OverlapNormalization/Makefile @@ -0,0 +1,5 @@ +INCS = OverlapNormalization.h +SRCS = OverlapNormalization.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/OverlapNormalization/OverlapNormalization.cpp b/isis/src/base/objs/OverlapNormalization/OverlapNormalization.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fcd567c9504f8426c5e1938ea34258dd39ebe4a8 --- /dev/null +++ b/isis/src/base/objs/OverlapNormalization/OverlapNormalization.cpp @@ -0,0 +1,349 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/11/25 22:09:21 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "OverlapNormalization.h" +#include "iException.h" +#include + +using namespace std; +namespace Isis { + + /** + * Constructs an OverlapNormalization object. Compares and + * stores the vector, and initializes the basis and least + * squares functions. + * + * @param statsList The list of Statistics objects corresponding + * to specific data sets (e.g., cubes) + */ + OverlapNormalization::OverlapNormalization (std::vector statsList) { + p_gainFunction = NULL; + p_gainLsq = NULL; + p_offsetFunction = NULL; + p_offsetLsq = NULL; + + p_statsList = statsList; + p_gainFunction = new BasisFunction ("BasisFunction", + statsList.size(),statsList.size()); + p_gainLsq = new LeastSquares (*p_gainFunction); + p_offsetFunction = new BasisFunction ("BasisFunction", + statsList.size(),statsList.size()); + p_offsetLsq = new LeastSquares (*p_offsetFunction); + + p_gains.resize(statsList.size()); + p_offsets.resize(statsList.size()); + for (unsigned int i=0; i= p_statsList.size()) { + string msg = "The index 1 is outside the bounds of the list."; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + if (index2 >= p_statsList.size()) { + string msg = "The index 2 is outside the bounds of the list."; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + // If there is no overlapping area, then the overlap is invalid + if (area1.ValidPixels() == 0 || area2.ValidPixels() == 0) { + return NoOverlap; + } + + // The weight must be a positive real number + if (weight <= 0.0) { + string msg = "All weights must be positive real numbers."; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + OverlapNormalization::Overlap o; + o.area1 = area1; + o.area2 = area2; + o.index1 = index1; + o.index2 = index2; + + double avg1 = area1.Average(); + double avg2 = area2.Average(); + + // Averages must not be 0 to avoid messing up least squares + if (avg1 == 0 || avg2 == 0) return NoContrast; + + p_overlapList.push_back(o); + p_deltas.push_back(avg2 - avg1); + p_weights.push_back(weight); + p_solved = false; + return Success; + } + + /** + * Attempts to solve the least squares equation for all data + * sets, and returns the success or failure of that attempt. + * + * @param type The enumeration clarifying whether the offset, + * gain, or both should be solved here + * + * @return bool Is the least squares equation now solved + * + * @throws Isis::iException::User - Number of overlaps and + * holds must be greater than the number of data + * sets + */ + void OverlapNormalization::Solve(SolutionType type) { + // Make sure that there is at least one overlap + if (p_overlapList.size() == 0) { + std::string msg = "None of the input images overlap"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Make sure the number of valid overlaps + hold images is greater than the + // number of input images (otherwise the least squares equation will be + // unsolvable due to having more unknowns than knowns) + if (p_overlapList.size() + p_idHoldList.size() < p_statsList.size()) { + std::string msg = "The number of overlaps and holds must be greater than"; + msg += " the number of input images"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Calculate offsets + if (type != Gains) { + // Add knowns to least squares for each overlap + for (int overlap=0; overlap<(int)p_overlapList.size(); overlap++) { + Overlap curOverlap = p_overlapList[overlap]; + int id1 = curOverlap.index1; + int id2 = curOverlap.index2; + + vector input; + input.resize(p_statsList.size()); + for (int i=0; i<(int)input.size(); i++) input[i] = 0.0; + input[id1] = 1.0; + input[id2] = -1.0; + + p_offsetLsq->AddKnown(input,p_deltas[overlap],p_weights[overlap]); + } + + // Add a known to the least squares for each hold image + for (int h=0; h<(int)p_idHoldList.size(); h++) { + int hold = p_idHoldList[h]; + + vector input; + input.resize(p_statsList.size()); + for (int i=0; i<(int)input.size(); i++) input[i] = 0.0; + input[hold] = 1.0; + p_offsetLsq->AddKnown(input,0.0,1e30); + } + + // Solve the least squares and get the offset coefficients to apply to the + // images + p_offsets.resize(p_statsList.size()); + p_offsetLsq->Solve(Isis::LeastSquares::QRD); + for (int i=0; iCoefficients(); i++) { + p_offsets[i] = p_offsetFunction->Coefficient(i); + } + } + + // Calculate Gains + if (type != Offsets) { + // Add knowns to least squares for each overlap + for (int overlap=0; overlap<(int)p_overlapList.size(); overlap++) { + Overlap curOverlap = p_overlapList[overlap]; + int id1 = curOverlap.index1; + int id2 = curOverlap.index2; + + vector input; + input.resize(p_statsList.size()); + for (int i=0; i<(int)input.size(); i++) input[i] = 0.0; + input[id1] = 1.0; + input[id2] = -1.0; + + double tanp; + + if (curOverlap.area1.StandardDeviation() == 0.0) { + tanp = 0.0; // Set gain to 1.0 + } + else { + tanp = curOverlap.area2.StandardDeviation() + / curOverlap.area1.StandardDeviation(); + } + + if (tanp > 0.0) { + p_gainLsq->AddKnown(input,log(tanp),p_weights[overlap]); + } + else { + p_gainLsq->AddKnown(input,0.0,1e30); // Set gain to 1.0 + } + } + + // Add a known to the least squares for each hold image + for (int h=0; h<(int)p_idHoldList.size(); h++) { + int hold = p_idHoldList[h]; + + vector input; + input.resize(p_statsList.size()); + for (int i=0; i<(int)input.size(); i++) input[i] = 0.0; + input[hold] = 1.0; + p_gainLsq->AddKnown(input,0.0,1e30); + } + + // Solve the least squares and get the gain coefficients to apply to the + // images + p_gains.resize(p_statsList.size()); + p_gainLsq->Solve(Isis::LeastSquares::QRD); + for (int i=0; iCoefficients(); i++) { + p_gains[i] = exp(p_gainFunction->Coefficient(i)); + } + } + + p_solved = true; + } + + /** + * Returns the calculated average DN value for the given + * data set + * + * @param index The index in the Statistics list corresponding + * to the data set desired + * + * @return double The average for the data + * + * @throws Isis::iException::Programmer - Identifying index must + * exist in the statsList + */ + double OverlapNormalization::Average (const unsigned index) const { + if (index >= p_statsList.size()) { + string msg = "The index was out of bounds for the list of statistics."; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + return p_statsList[index].Average(); + } + + /** + * Returns the calculated gain (multiplier) for the given + * data set + * + * @param index The index in the Statistics list corresponding + * to the data set desired + * + * @return double The gain for the data + * + * @throws Isis::iException::Programmer - Identifying index must + * exist in the statsList + */ + double OverlapNormalization::Gain (const unsigned index) const { + if (index >= p_statsList.size()) { + string msg = "The index was out of bounds for the list of statistics."; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + return p_gains[index]; + } + + /** + * Returns the calculated offset (base) for the given + * data set + * + * @param index The index in the Statistics list corresponding + * to the data set desired + * + * @return double The offset for the data + * + * @throws Isis::iException::Programmer - Identifying index must + * exist in the statsList + */ + double OverlapNormalization::Offset (const unsigned index) const { + if (index >= p_statsList.size()) { + string msg = "The index was out of bounds for the list of statistics."; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + return p_offsets[index]; + } + + /** + * Returns a new DN from an old using the calculated gains and + * offsets of the data set the pixel belongs to + * + * @param dn The value of the pixel prior to equalization + * + * @param index The index in the Statistics list corresponding + * to the data set for the pixel + * + * @return double The newly calculated DN value + * + * @throws Isis::iException::Programmer - Least Squares equation + * must be solved before returning the gain + */ + double OverlapNormalization::Evaluate (double dn, unsigned index) const { + if (!p_solved) { + string msg = "The least squares equation has not been successfully "; + msg += "solved yet."; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + if (Isis::IsSpecial(dn)) return dn; + return (dn - Average(index)) * Gain(index) + Average(index) + Offset(index); + } +} diff --git a/isis/src/base/objs/OverlapNormalization/OverlapNormalization.h b/isis/src/base/objs/OverlapNormalization/OverlapNormalization.h new file mode 100644 index 0000000000000000000000000000000000000000..cfc1466d63174f05968548fef7522eaedec843aa --- /dev/null +++ b/isis/src/base/objs/OverlapNormalization/OverlapNormalization.h @@ -0,0 +1,255 @@ +#ifndef OverlapNormalization_h +#define OverlapNormalization_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2009/11/25 22:09:21 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Statistics.h" +#include "BasisFunction.h" +#include "LeastSquares.h" + +namespace Isis { + +/** + * Calculate the bases and multipliers for normalizing + * overlapping "data sets" (e.g., cubes). Specifically, this + * class is designed for normalizing data in equalization + * applications such as equalizer and hiequal. Given collections + * for statistical data sets, overlapping statistics between + * these sets, and at least one data set to be "held", this + * class will use a least squares solution to calculate gain and + * offset coefficients for every set of data in the collection. + * + * Once the multiplicative and additive corrections have been + * derived, this class can then be used to calculate new DN + * values for a known data set. The actual equation to be used + * for calculating new DN values with the derived gains and + * offsets is: + * + * @f[ + * newDN = (oldDN - avg(i)) * MULT(i) + avg(i) + BASE(i) + * @f] + * + * where i is the index of a known data set from the statistics + * list. + * + * @author 2009-05-07 Travis Addair + * + * @internal + * @history 2009-06-05 Mackenzie Boyd - fixed unittest to work on all systems + * @history 2009-06-12 Travis Addair - changed public interface + * to use indices instead of file names and renamed + * from IntersectionStatistics + * @history 2009-06-15 Travis Addair - documented all + * variables/enums + * @history 2009-06-24 Travis Addair - changed gain and offset vectors to + * itialize to 1.0 and 0.0, respectively + * @history 2009-11-25 Travis Addair - held images are now + * weighted to ensure gain and offset of 1.0 and 0.0, + * respectively + */ + + class OverlapNormalization { + public: + + OverlapNormalization (std::vector statsList); + + virtual ~OverlapNormalization(); + + /** + * The result of the attempt to add overlap data to the list of + * valid overlaps, where Success is a successful add, NoOverlap + * is a failure due to one or both Statistics objects containing + * no data, and NoContrast is a failure due to one or both + * averages being 0 + */ + enum AddStatus { + + /** + * Overlap is valid and was added successfully + */ + Success, + + /** + * Data sets do not overlap one another + */ + NoOverlap, + + /** + * One or both areas contain no valid average + */ + NoContrast + }; + + AddStatus AddOverlap (const Statistics &area1, const unsigned index1, + const Statistics &area2, const unsigned index2, + double weight=1.0); + + /** + * Sets the list of files to be held during the solving process. + * + * @param holdIndex The index of a set of data from the list of + * Statistics objects to be held + */ + inline void AddHold (unsigned holdIndex) { p_idHoldList.push_back(holdIndex); }; + + /** + * Enumeration for whether user/programmer wants to calculate + * new gains, offsets, or both when solving + */ + enum SolutionType { + + /** + * Calculate only the gains + */ + Gains, + + /** + * Calculate only the offsets + */ + Offsets, + + /** + * Calculate both gains and offsets + */ + Both + }; + + void Solve (SolutionType type=Both); + + double Average (const unsigned index) const; + double Gain (const unsigned index) const; + double Offset (const unsigned index) const; + + double Evaluate (double dn, unsigned index) const; + + private: + + /** + * Vector of Statistics objects for each data set + */ + std::vector p_statsList; + + /** + * Vector of indices corresponding to the p_statsList vector + * representing data sets to be held in solution + */ + std::vector p_idHoldList; + + /** + * Store statistics pertaining to the overlapping areas and + * indices (corresponding to the statistics list) for two data + * sets + */ + class Overlap { + public: + + /** + * Overlapping area for the first data set + */ + Statistics area1; + + /** + * Overlapping area for the second data set + */ + Statistics area2; + + /** + * Index corresponding to p_statsList for the first + * overlapping data set + */ + int index1; + + /** + * Index corresponding to p_statsList for the second + * overlapping data set + */ + int index2; + }; + + /** + * Vector of valid overlaps collected + */ + std::vector p_overlapList; + + /** + * Vector of delta values (differences between the averages of + * two overlapping data sets) for every valid overlap + */ + std::vector p_deltas; + + /** + * Vector of weights for every valid overlap + */ + std::vector p_weights; + + + /** + * Whether or not the least squares solution has been solved + */ + bool p_solved; + + /** + * Whether the user of this class wants to solve for the + * offsets, the gains, or both + */ + SolutionType p_solutionType; + + /** + * Vector of calculated gains filled by the Solve method + */ + std::vector p_gains; + + /** + * Vector of calculated offsets filled by the Solve method + */ + std::vector p_offsets; + + + /** + * The gain function to be solved + */ + Isis::BasisFunction *p_gainFunction; + + /** + * The offset function to be solved + */ + Isis::BasisFunction *p_offsetFunction; + + /** + * The least squares object that solves for the new gains + */ + Isis::LeastSquares *p_gainLsq; + + /** + * The least squares object that calculates offsets + */ + Isis::LeastSquares *p_offsetLsq; + + //! Cannot copy this object + OverlapNormalization &operator=(const OverlapNormalization &); + + //! Cannot copy this object + OverlapNormalization (const OverlapNormalization &); + }; +}; + +#endif diff --git a/isis/src/base/objs/OverlapNormalization/OverlapNormalization.truth b/isis/src/base/objs/OverlapNormalization/OverlapNormalization.truth new file mode 100644 index 0000000000000000000000000000000000000000..892f0e548c046c9db6e415a1a504a914ebfac0e3 --- /dev/null +++ b/isis/src/base/objs/OverlapNormalization/OverlapNormalization.truth @@ -0,0 +1,21 @@ +UnitTest for Overlap Normalization +Gathering statistics +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Gathering statistics +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Gathering statistics +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +statsList size: 3 +oNorm creation == SUCCESS +Gathering Overlap Statistics +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Gathering Overlap Statistics +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Gathering Overlap Statistics +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +I00824006RDR.lev2.cub : Gathered Offset: -6.418653512314e-05 +I00824006RDR.lev2.cub : Gathered Gain: 0.8024773380228 +I01523019RDR.lev2.cub : Gathered Offset: 0 +I01523019RDR.lev2.cub : Gathered Gain: 1 +I02609002RDR.lev2.cub : Gathered Offset: 0.0001596195090359 +I02609002RDR.lev2.cub : Gathered Gain: 1.931615747861 diff --git a/isis/src/base/objs/OverlapNormalization/unitTest.cpp b/isis/src/base/objs/OverlapNormalization/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..edbf6140c128665b651d01d8af5731b5cab33716 --- /dev/null +++ b/isis/src/base/objs/OverlapNormalization/unitTest.cpp @@ -0,0 +1,88 @@ +#include +#include "iException.h" +#include "Cube.h" +#include "OverlapStatistics.h" +#include "Statistics.h" +#include "OverlapNormalization.h" +#include "Preference.h" + +using namespace std; + +void PrintResults(string, const unsigned, Isis::OverlapNormalization &); + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + try{ + cout << "UnitTest for Overlap Normalization" << endl; + Isis::Cube cube1,cube2,cube3; + cube1.Open("$odyssey/testData/I00824006RDR.lev2.cub"); + cube2.Open("$odyssey/testData/I01523019RDR.lev2.cub"); + cube3.Open("$odyssey/testData/I02609002RDR.lev2.cub"); + Isis::Statistics *stats1 = cube1.Statistics(); + Isis::Statistics *stats2 = cube2.Statistics(); + Isis::Statistics *stats3 = cube3.Statistics(); + + vector statsList; + statsList.push_back(*stats1); + statsList.push_back(*stats2); + statsList.push_back(*stats3); + cout << "statsList size: " << statsList.size() << endl; + + Isis::OverlapNormalization oNorm(statsList); + + cout << "oNorm creation == SUCCESS" << endl; + cout << setprecision(13); + + Isis::OverlapStatistics oStats1(cube1,cube2); + Isis::OverlapStatistics oStats2(cube1,cube3); + Isis::OverlapStatistics oStats3(cube2,cube3); + + Isis::MultivariateStatistics mStats1; + Isis::MultivariateStatistics mStats2; + Isis::MultivariateStatistics mStats3; + mStats1 = oStats1.GetMStats(1); + mStats2 = oStats2.GetMStats(1); + mStats3 = oStats3.GetMStats(1); + + Isis::Statistics overlap11 = mStats1.X(); + Isis::Statistics overlap12 = mStats1.Y(); + oNorm.AddOverlap(overlap11, 0, + overlap12, 1, overlap11.ValidPixels()); + Isis::Statistics overlap21 = mStats2.X(); + Isis::Statistics overlap22 = mStats2.Y(); + oNorm.AddOverlap(overlap21, 0, + overlap22, 2, overlap21.ValidPixels()); + Isis::Statistics overlap31 = mStats3.X(); + Isis::Statistics overlap32 = mStats3.Y(); + oNorm.AddOverlap(overlap31, 1, + overlap32, 2, overlap31.ValidPixels()); + oNorm.AddHold(1); + + oNorm.Solve(); + + PrintResults("I00824006RDR.lev2.cub", 0, oNorm); + PrintResults("I01523019RDR.lev2.cub", 1, oNorm); + PrintResults("I02609002RDR.lev2.cub", 2, oNorm); + } + catch (Isis::iException &e) { + e.Report(); + } +} + + +void PrintResults(string filename, const unsigned index, + Isis::OverlapNormalization &oNorm) { + double offset = oNorm.Offset(index); + double gain = oNorm.Gain(index); + + if (fabs(offset) < 1e-15) { + offset = 0.0; + } + if (fabs(gain) < 1e-15) { + gain = 0.0; + } + + cout << filename << " : Gathered Offset: " << offset << endl; + cout << filename << " : Gathered Gain: " << gain << endl; +} diff --git a/isis/src/base/objs/OverlapStatistics/Makefile b/isis/src/base/objs/OverlapStatistics/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a8cfc0be9bdbc9faf923ec37383d7cce8e010792 --- /dev/null +++ b/isis/src/base/objs/OverlapStatistics/Makefile @@ -0,0 +1,5 @@ +INCS = OverlapStatistics.h +SRCS = OverlapStatistics.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/OverlapStatistics/OverlapStatistics.cpp b/isis/src/base/objs/OverlapStatistics/OverlapStatistics.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a896bf249a3c13c898b02ab667106c3670c22365 --- /dev/null +++ b/isis/src/base/objs/OverlapStatistics/OverlapStatistics.cpp @@ -0,0 +1,303 @@ +/** + * @file + * $Revision: 1.11 $ + * $Date: 2009/06/26 17:08:30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "OverlapStatistics.h" +#include "MultivariateStatistics.h" +#include "Cube.h" +#include "Filename.h" +#include "Projection.h" +#include "ProjectionFactory.h" +#include "iException.h" +#include "Brick.h" +#include "Progress.h" +#include +#include + +using namespace std; +namespace Isis { + + /** + * Constructs an OverlapStatistics object. Compares the two input cubes and + * finds where they overlap. + * + * @param x The first input cube + * @param y The second input cube + * @param progressMsg (Default value of "Gathering Overlap Statistics") Text + * for indicating progress during statistic gathering + * @param sampPercent (Default value of 100.0) Sampling percent, or the percentage + * of lines to consider during the statistic gathering procedure + * + * @throws Isis::iException::User - All images must have the same number of + * bands + */ + OverlapStatistics::OverlapStatistics(Isis::Cube &x, Isis::Cube &y, + std::string progressMsg, double sampPercent) { + // Test to ensure sampling percent in bound + if (sampPercent <= 0.0 || sampPercent > 100.0) { + string msg = "The sampling percent must be a decimal (0.0, 100.0]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + p_sampPercent = sampPercent; + + // Extract filenames and band number from cubes + p_xFile = x.Filename(); + p_yFile = y.Filename(); + + // Make sure number of bands match + if (x.Bands() != y.Bands()) { + string msg = "Number of bands do not match between cubes [" + + p_xFile.Name() + "] and [" + p_yFile.Name() + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + p_bands = x.Bands(); + p_stats.resize(p_bands); + + //Create projection from each cube + Projection *projX = x.Projection(); + Projection *projY = y.Projection(); + + // Test to make sure projection parameters match + if (*projX != *projY) { + string msg = "Mapping groups do not match between cubes [" + + p_xFile.Name() + "] and [" + p_yFile.Name() + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + // Figure out the x/y range for both images to find the overlap + double Xmin1 = projX->ToProjectionX(0.5); + double Ymax1 = projX->ToProjectionY(0.5); + double Xmax1 = projX->ToProjectionX(x.Samples()+0.5); + double Ymin1 = projX->ToProjectionY(x.Lines()+0.5); + + double Xmin2 = projY->ToProjectionX(0.5); + double Ymax2 = projY->ToProjectionY(0.5); + double Xmax2 = projY->ToProjectionX(y.Samples()+0.5); + double Ymin2 = projY->ToProjectionY(y.Lines()+0.5); + + // Find overlap + if ((Xmin1Xmin2) && (Ymin1Ymin2)) { + double minX = Xmin1 > Xmin2 ? Xmin1 : Xmin2; + double minY = Ymin1 > Ymin2 ? Ymin1 : Ymin2; + double maxX = Xmax1 < Xmax2 ? Xmax1 : Xmax2; + double maxY = Ymax1 < Ymax2 ? Ymax1 : Ymax2; + + // Find Sample range of the overlap + p_minSampX = (int)(projX->ToWorldX(minX) + 0.5); + p_maxSampX = (int)(projX->ToWorldX(maxX) + 0.5); + p_minSampY = (int)(projY->ToWorldX(minX) + 0.5); + p_maxSampY = (int)(projY->ToWorldX(maxX) + 0.5); + p_sampRange = p_maxSampX - p_minSampX + 1; + + // Test to see if there was only sub-pixel overlap + if (p_sampRange <= 0) return; + + // Find Line range of overlap + p_minLineX = (int)(projX->ToWorldY(maxY) + 0.5); + p_maxLineX = (int)(projX->ToWorldY(minY) + 0.5); + p_minLineY = (int)(projY->ToWorldY(maxY) + 0.5); + p_maxLineY = (int)(projY->ToWorldY(minY) + 0.5); + p_lineRange = p_maxLineX - p_minLineX + 1; + + // Print percent processed + Progress progress; + progress.SetText(progressMsg); + + int linc = (int)(100.0 / sampPercent + 0.5); // Calculate our line increment + + // Define the maximum number of steps to be our line range divided by the + // line increment, but if they do not divide evenly, then because of + // rounding, we need to do an additional step for each band + int maxSteps = (int)(p_lineRange / linc + 0.5); + + if (p_lineRange % linc != 0) maxSteps += 1; + maxSteps *= p_bands; + + + progress.SetMaximumSteps(maxSteps); + progress.CheckStatus(); + + // Collect and store off the overlap statistics + for (int band=1; band<=p_bands; band++) { + Brick b1(p_sampRange,1,1,x.PixelType()); + Brick b2(p_sampRange,1,1,y.PixelType()); + + int i=0; + while (i p_lineRange-1 && i != p_lineRange-1) { + i = p_lineRange-1; + progress.AddSteps(1); + } + else i+=linc; // Increment the current line by our incrementer + + progress.CheckStatus(); + } + } + } + } + + /** + * Checks all bands of the cubes for an overlap, and will only return false + * if none of the bands overlap + * + * @return bool Returns true if any of the bands overlap, and false if none + * of the bands overlap + */ + bool OverlapStatistics::HasOverlap() { + for (int b=0; b0) return true; + } + return false; + } + + /** + * Creates a pvl of various useful data obtained by the overlap statistics + * class. The pvl is returned in an output stream + * + * @param os The output stream to write to + * @param stats The OverlapStatistics object to write to os + * @return ostream Pvl of useful statistics + */ + std::ostream& operator<<(std::ostream &os, Isis::OverlapStatistics &stats) { + // Output the private variables + try { + PvlObject o ("OverlapStatistics"); + PvlGroup gX ("File1"); + PvlKeyword stsX ("StartSample", stats.StartSampleX()); + PvlKeyword ensX ("EndSample", stats.EndSampleX()); + PvlKeyword stlX ("StartLine", stats.StartLineX()); + PvlKeyword enlX ("EndLine", stats.EndLineX()); + PvlKeyword avgX ("Average"); + PvlKeyword stdX ("StandardDeviation"); + PvlKeyword varX ("Variance"); + for (int band=1; band<=stats.Bands(); band++) { + if (stats.HasOverlap(band)) { + avgX += stats.GetMStats(band).X().Average(); + stdX += stats.GetMStats(band).X().StandardDeviation(); + varX += stats.GetMStats(band).X().Variance(); + } + } + gX += stsX; + gX += ensX; + gX += stlX; + gX += enlX; + gX += avgX; + gX += stdX; + gX += varX; + + PvlGroup gY ("File2"); + PvlKeyword stsY ("StartSample", stats.StartSampleY()); + PvlKeyword ensY ("EndSample", stats.EndSampleY()); + PvlKeyword stlY ("StartLine", stats.StartLineY()); + PvlKeyword enlY ("EndLine", stats.EndLineY()); + PvlKeyword avgY ("Average"); + PvlKeyword stdY ("StandardDeviation"); + PvlKeyword varY ("Variance"); + for (int band=1; band<=stats.Bands(); band++) { + if (stats.HasOverlap(band)) { + avgY += stats.GetMStats(band).Y().Average(); + stdY += stats.GetMStats(band).Y().StandardDeviation(); + varY += stats.GetMStats(band).Y().Variance(); + } + } + gY += stsY; + gY += ensY; + gY += stlY; + gY += enlY; + gY += avgY; + gY += stdY; + gY += varY; + + o += PvlKeyword("File1", stats.FilenameX().Name()); + o += PvlKeyword("File2", stats.FilenameY().Name()); + o += PvlKeyword("Width", stats.Samples()); + o += PvlKeyword("Height", stats.Lines()); + o += PvlKeyword("SamplingPercent", stats.SampPercent()); + o.AddGroup(gX); + o.AddGroup(gY); + + PvlKeyword cov ("Covariance"); + PvlKeyword cor ("Correlation"); + + PvlKeyword valid ("ValidOverlap"); + PvlKeyword val ("ValidPixels"); + PvlKeyword inv ("InvalidPixels"); + PvlKeyword tot ("TotalPixels"); + for (int band=1; band<=stats.Bands(); band++) { + if (stats.HasOverlap(band)) { + std::string validStr = "false"; + if (stats.IsValid(band)) validStr = "true"; + valid += validStr; + cov += stats.GetMStats(band).Covariance(); + cor += stats.GetMStats(band).Correlation(); + val += stats.GetMStats(band).ValidPixels(); + inv += stats.GetMStats(band).InvalidPixels(); + tot += stats.GetMStats(band).TotalPixels(); + } + } + o += valid; + o += cov; + o += cor; + o += val; + o += inv; + o += tot; + + for (int band=1; band<=stats.Bands(); band++) { + if (stats.HasOverlap(band)) { + iString bandNum (band); + std::string bandStr = "LinearRegression" + bandNum; + PvlKeyword LinReg(bandStr); + double a,b; + try { + stats.GetMStats(band).LinearRegression(a,b); + LinReg += a; + LinReg += b; + } + catch (iException &e) { + // It is possible one of the overlaps was constant and therefore + // the regression would be a vertical line (x=c instead of y=ax+b) + e.Clear(); + } + o += LinReg; + } + } + + os << o << endl; + return os; + } + catch (iException &e) { + string msg = "Trivial overlap between [" + stats.FilenameX().Name(); + msg += "] and [" + stats.FilenameY().Name() + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + } + + +} diff --git a/isis/src/base/objs/OverlapStatistics/OverlapStatistics.h b/isis/src/base/objs/OverlapStatistics/OverlapStatistics.h new file mode 100644 index 0000000000000000000000000000000000000000..7f2ec470e7c1db0e637840621ddabfd33299b56c --- /dev/null +++ b/isis/src/base/objs/OverlapStatistics/OverlapStatistics.h @@ -0,0 +1,237 @@ +#ifndef OverlapStatistics_h +#define OverlapStatistics_h +/** + * @file + * $Revision: 1.7 $ + * $Date: 2009/06/24 22:03:01 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + #include "Cube.h" + #include "Filename.h" + #include "Projection.h" + #include "MultivariateStatistics.h" + +namespace Isis { +/** + * @brief Calculates statistics in the area of overlap between two projected cubes + * + * This class finds the overlap between two cubes. It allows the user to check + * whether or not two cubes overlap, and also creates a MultivariateStatistics + * object containing the data from each cube in the overlapping area. The cubes + * entered into the constructor for this class must both be projections, and + * must have the same projection parameters. + * + * If you would like to see OverlapStatistics + * being used in implementation, see equalizer.cpp + * + * @ingroup Statistics + * + * @author 2005-07-18 Elizabeth Ribelin + * + * @internal + * @history 2005-11-18 Elizabeth Miller - added 1e-9 to the min and max values + * when computing the ranges to fix rounding issue + * @history 2006-01-12 Elizabeth Miller - removed unwanted print statements + * @history 2006-03-31 Elizabeth Miller - added unitTest + * @history 2006-04-03 Elizabeth Miller - added .001 to the min and max values + * when computing the ranges to re-fix rounding issue + * @history 2007-08-27 Steven Koechle - removed space from standard deviation + * keyword + * @history 2008-06-18 Steven Koechle - fixed Documentation Errors + * @history 2009-03-12 Travis Addair - added tracking for + * percent processed + * @history 2009-06-24 Travis Addair - optimized statistic gathering, changed + * PVL print-out for readability, and added functionality to allow the + * user to specify a "sampling percent" when gathering statistics to + * save processing time + * + */ + + class OverlapStatistics { + public: + OverlapStatistics(Isis::Cube &x, Isis::Cube &y, + std::string progressMsg="Gathering Overlap Statistics", + double sampPercent=100.0); + + /** + * Checks the specified band for an overlap + * + * @param band The band number of the cubes to be checked for an overlap + * + * @returns bool Returns true if the cubes overlap in the specified band, + * and false if they do not overlap + */ + bool HasOverlap(int band) { return (p_stats[band-1].ValidPixels()>0); }; + bool HasOverlap(); + + /** + * Returns the filename of the first cube + * + * @return string The name of the first cube + */ + Isis::Filename FilenameX() { return p_xFile; }; + + /** + * Returns the filename of the second cube + * + * @return string The name of the second cube + */ + Isis::Filename FilenameY() { return p_yFile; }; + + /** + * Returns the MultivariateStatistics object containing all the data from + * both cubes in the overlapping area + * + * @param band The band number the MultivariateStatistics object needs to + * contain data from + * + * @return MultivariateStatistics The MultivariateStatistics object + * containing all data from both cubes in the overlapping area from + * the specified band + */ + Isis::MultivariateStatistics GetMStats(int band) { + return p_stats[band-1]; + }; + + /** + * Returns the number of lines in the overlapping area + * + * @return int The number of lines in the overlapping area + */ + int Lines() { return p_lineRange; }; + + /** + * Returns the number of samples in the overlapping area + * + * @return int The number of samples in the overlapping area + */ + int Samples() { return p_sampRange; }; + + /** + * Returns the number of bands both cubes have + * + * @return int The number of bands both cubes have + */ + int Bands() { return p_bands; }; + + /** + * Returns the percentage of cube lines sampled + * + * @return int The percentage of lines sampled + */ + double SampPercent() { return p_sampPercent; }; + + /** + * Returns the starting sample position of the overlap in the first cube + * + * @return int The starting sample of the overlap in the first cube + */ + int StartSampleX() { return p_minSampX; }; + + /** + * Returns the ending sample position of the overlap in the first cube + * + * @return int The ending sample of the overlap in the first cube + */ + int EndSampleX() { return p_maxSampX; }; + + /** + * Returns the starting line position of the overlap in the first cube + * + * @return int The starting line of the overlap in the first cube + */ + int StartLineX() { return p_minLineX; }; + + /** + * Returns the ending line position of the overlap in the first cube + * + * @return int The ending line of the overlap in the first cube + */ + int EndLineX() { return p_maxLineX; }; + + /** + * Returns the starting sample position of the overlap in the second cube + * + * @return int The starting sample of the overlap in the second cube + */ + int StartSampleY() { return p_minSampY; }; + + /** + * Returns the ending sample position of the overlap in the second cube + * + * @return int The ending sample of the overlap in the second cube + */ + int EndSampleY() { return p_maxSampY; }; + + /** + * Returns the starting line position of the overlap in the second cube + * + * @return int The starting line of the overlap in the second cube + */ + int StartLineY() { return p_minLineY; }; + + /** + * Returns the ending line position of the overlap in the second cube + * + * @return int The ending line of the overlap in the second cube + */ + int EndLineY() { return p_maxLineY; }; + + /** + * Sets the minimum number of valid pixels for the overlap to be + * considered valid for PVL output + * + * @param mincnt The minimum valid pixel value to set + */ + void SetMincount(unsigned int mincnt) { p_mincnt = mincnt; }; + + /** + * Returns whether the overlap meets the minimum valid pixel requirement + * + * @param band The band to check + * + * @return bool Is minimum requirement met + */ + bool IsValid(unsigned int band) { return GetMStats(band).ValidPixels()>p_mincnt; }; + + + private: + int p_bands; //! p_stats; + }; + std::ostream& operator<<(std::ostream &os, Isis::OverlapStatistics &stats); +}; + +#endif diff --git a/isis/src/base/objs/OverlapStatistics/OverlapStatistics.truth b/isis/src/base/objs/OverlapStatistics/OverlapStatistics.truth new file mode 100644 index 0000000000000000000000000000000000000000..c939d88a1642fc9f21201f3efa166d3c633a246a --- /dev/null +++ b/isis/src/base/objs/OverlapStatistics/OverlapStatistics.truth @@ -0,0 +1,24 @@ +UnitTest for Overlap Statistics +Gathering Overlap Statistics +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +For Overlap of I00824006RDR.lev2.cub & I02609002RDR.lev2.cub... +Has Overlap? = 0 + +Overlap Dimensions: + Samples = 46 + Lines = 340 + Bands = 10 + +Overlap Areas: + Filename = I00824006RDR.lev2.cub + Start Sample = 38 + End Sample = 83 + Start Line = 1 + End Line = 340 + + Filename = I02609002RDR.lev2.cub + Start Sample = 1 + End Sample = 46 + Start Line = 380 + End Line = 719 + diff --git a/isis/src/base/objs/OverlapStatistics/unitTest.cpp b/isis/src/base/objs/OverlapStatistics/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..426305b04b827ea393621204fdb4416036fc1b70 --- /dev/null +++ b/isis/src/base/objs/OverlapStatistics/unitTest.cpp @@ -0,0 +1,52 @@ +#include +#include "iException.h" +#include "Cube.h" +#include "OverlapStatistics.h" +#include "Preference.h" + +using namespace std; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + try{ + cout << "UnitTest for Overlap Statistics" << endl; + Isis::Cube cube1,cube2; + cube1.Open("$odyssey/testData/I00824006RDR.lev2.cub"); + cube2.Open("$odyssey/testData/I02609002RDR.lev2.cub"); + cout << setprecision(9); + + // Check to make sure the overlap calculation is working correctly + Isis::OverlapStatistics oStats(cube1,cube2); + cout << "For Overlap of I00824006RDR.lev2.cub & I02609002RDR.lev2.cub..." + << endl; + cout << "Has Overlap? = " << oStats.HasOverlap() << endl << endl; + cout << "Overlap Dimensions: " << endl; + cout << " Samples = " << oStats.Samples() << endl; + cout << " Lines = " << oStats.Lines() << endl; + cout << " Bands = " << oStats.Bands() << endl << endl; + + cout << "Overlap Areas:" << endl; + cout << " Filename = " << Isis::Filename(oStats.FilenameX()).Name() << endl; + cout << " Start Sample = " << oStats.StartSampleX() << endl; + cout << " End Sample = " << oStats.EndSampleX() << endl; + cout << " Start Line = " << oStats.StartLineX() << endl; + cout << " End Line = " << oStats.EndLineX() << endl << endl; + + cout << " Filename = " << Isis::Filename(oStats.FilenameY()).Name() << endl; + cout << " Start Sample = " << oStats.StartSampleY() << endl; + cout << " End Sample = " << oStats.EndSampleY() << endl; + cout << " Start Line = " << oStats.StartLineY() << endl; + cout << " End Line = " << oStats.EndLineY() << endl << endl; + } + catch (Isis::iException &e) { + e.Report(); + } +} + + + + + + + diff --git a/isis/src/base/objs/Parabola/Makefile b/isis/src/base/objs/Parabola/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..88f4c7da4a2de1d471a577c0aac044382cc5c660 --- /dev/null +++ b/isis/src/base/objs/Parabola/Makefile @@ -0,0 +1,5 @@ +INCS = Parabola.h +SRCS = Parabola.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Parabola/Parabola.cpp b/isis/src/base/objs/Parabola/Parabola.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1dc4ab47a1413e5a8c33ec3db9a56d07b0912d4 --- /dev/null +++ b/isis/src/base/objs/Parabola/Parabola.cpp @@ -0,0 +1,57 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Filename.h" +#include "Constants.h" +#include "iException.h" +#include "Parabola.h" + +namespace Isis { + + /** + * This is the the overriding virtual function that provides the expansion into + * the parabolic equation. + * See BasisFunction for more information. + * + * @param vars A vector of double values to use for the expansion. + */ + void Parabola::Expand(const std::vector &vars) { + + if ((int) vars.size() != Variables()) { + std::ostringstream msg; + msg << "Number of variables given (" << vars.size() + << ") does not match expected (" << Variables() <<")!" + << std::ends; +// std::cout << msg.str << std::endl; +// throw Isis::iException::Message("Isis::iException::Programmer",msg.str, +// _FILEINFO_); + } + p_terms.clear(); + p_terms.push_back(1.0); + p_terms.push_back(vars[0]); + p_terms.push_back(vars[0] * vars[0]); + return; + } +} // end namespace isis + diff --git a/isis/src/base/objs/Parabola/Parabola.h b/isis/src/base/objs/Parabola/Parabola.h new file mode 100644 index 0000000000000000000000000000000000000000..f7795009836f38a4d396a2cfaf07ed2cf23b187e --- /dev/null +++ b/isis/src/base/objs/Parabola/Parabola.h @@ -0,0 +1,68 @@ + +#ifndef Parabola_h +#define Parabola_h +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "BasisFunction.h" + +namespace Isis { + +/** + * @brief Parabola basis function + * + * This is a derived class from the BasisFunction class which creates a parabola + * (second degree equation in 1 variable). The parabolic function has the + * following form: + * + * @f[ + * x = A + B*y + C*y**2 + * @f] + * + * @ingroup Math + * + * @author 2005-06-09 Kris Becker + * + * @internal + * @history 2006-04-15 Debbie A. Cook - Imported from ISIS2 to Isis 3 + */ + + class Parabola : public Isis::BasisFunction { + public: + //! Create a Parabola object + + // Get help to figure out why I have to pass the name in even with the + // default set + Parabola(const std::string &bname = "Parabola") : + Isis::BasisFunction(bname, 1, 3) { } + + //! Destroys the Parabola object + ~Parabola() {} + + void Expand(const std::vector &vars); + + }; + +} +#endif + diff --git a/isis/src/base/objs/Parabola/Parabola.truth b/isis/src/base/objs/Parabola/Parabola.truth new file mode 100644 index 0000000000000000000000000000000000000000..4e5cd85a3656e20d406fefb01676bc4ca74a2949 --- /dev/null +++ b/isis/src/base/objs/Parabola/Parabola.truth @@ -0,0 +1,16 @@ +Name = Parabola +Ncoefs = 3 +Vars = 1 +-6 +5 +1 +--- +8 +1 +2 +4 +--- +-12 +1 +-2 +4 diff --git a/isis/src/base/objs/Parabola/unitTest.cpp b/isis/src/base/objs/Parabola/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..feadf29bdc2f5cfc677e8d3ef6e87801a5046c85 --- /dev/null +++ b/isis/src/base/objs/Parabola/unitTest.cpp @@ -0,0 +1,38 @@ +#include "Parabola.h" +#include +#include "Preference.h" + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + + Isis::Parabola b("Parabola"); + vector coefs; + coefs.push_back(-6.0); + coefs.push_back(5.0); + coefs.push_back(1.0); + b.SetCoefficients(coefs); + + cout << "Name = " << b.Name() << endl; + cout << "Ncoefs = " << b.Coefficients() << endl; + cout << "Vars = " << b.Variables() << endl; + for (int i=0; i vars; + vars.push_back(2.0); + cout << b.Evaluate(vars) << endl; + for (int i=0; i +#include "Filename.h" +#include "PhotoModel.h" +#include "Plugin.h" +#include "Pvl.h" +#include "iException.h" + +using namespace std; + +namespace Isis { + /** + * Create a PhotoModel object. Because this is a pure virtual + * class you can not create a PhotoModel class directly. Instead, + * see the PhotoModelFactory class. + * + * @param pvl A pvl object containing a valid PhotoModel specification + * + * @see photometricModels.doc + */ + PhotoModel::PhotoModel (Pvl &pvl) { + PvlGroup &algorithm = pvl.FindObject("PhotometricModel").FindGroup("Algorithm",Pvl::Traverse); + + if (algorithm.HasKeyword("Name")) { + p_photoAlgorithmName = string(algorithm["Name"]); + } + + p_standardConditions = false; + } + + /** + * Sets whether standard conditions will be used. + * @param standard True if standard conditions are used. + */ + void PhotoModel::SetStandardConditions(bool standard) { + p_standardConditions = standard; + } + + /** + * Obtain topographic derivative of an arbitrary photometric + * function + * + * @param phase Input phase angle + * @param incidence Input incidence angle + * @param emission Input emission angle + * @returns double Gradient + * + */ + double PhotoModel::PhtTopder(double phase, double incidence, + double emission) + { + double xi,zi; + double cphi; + double phi; + double xe,ye,ze; + double epsh; + double xy,z; + double cinc; + double inc1,inc2,inc3,inc4; + double cema; + double ema1,ema2,ema3,ema4; + double d1,d2; + double result; + double eps; + + eps = 0.04; + + // set up incidence vector + xi = sin((Isis::PI/180.0)*incidence); + zi = cos((Isis::PI/180.0)*incidence); + + // phi is the azimuth from xz plane to emission direction; if + // either incidence or emission is zero, it's arbitrary and gets + // set to zero. Thus cos(phi), cphi, is set to one. + if ((incidence == 0.0) || (emission == 0.0)) { + cphi = 1.0; + } + else { + cphi = (cos((Isis::PI/180.0)*phase) - + cos((Isis::PI/180.0)*incidence) * + cos((Isis::PI/180.0)*emission)) / + (sin((Isis::PI/180.0)*incidence) * + sin((Isis::PI/180.0)*emission)); + } + + // now calculate the emission vector + phi = PhtAcos(cphi) * (180.0/Isis::PI); + xe = cphi * sin((Isis::PI/180.0)*emission); + ye = sin((Isis::PI/180.0)*phi) * sin((Isis::PI/180.0)*emission); + ze = cos((Isis::PI/180.0)*emission); + + // now evaluate two orthogonal derivatives + epsh = eps * 0.5; + xy = sin((Isis::PI/180.0)*epsh); + z = cos((Isis::PI/180.0)*epsh); + + cinc = max(-1.0,min(xy*xi+z*zi,1.0)); + inc1 = PhtAcos(cinc) * (180.0/Isis::PI); + cema = max(-1.0,min(xy*xe+z*ze,1.0)); + ema1 = PhtAcos(cema) * (180.0/Isis::PI); + + cinc = max(-1.0,min(-xy*xi+z*zi,1.0)); + inc2 = PhtAcos(cinc) * (180.0/Isis::PI); + cema = max(-1.0,min(-xy*xe+z*ze,1.0)); + ema2 = PhtAcos(cema) * (180.0/Isis::PI); + + cinc = max(-1.0,min(z*zi,1.0)); + inc3 = PhtAcos(cinc) * (180.0/Isis::PI); + cema = max(-1.0,min(xy*ye+z*ze,1.0)); + ema3 = PhtAcos(cema) * (180.0/Isis::PI); + + cinc = max(-1.0,min(z*zi,1.0)); + inc4 = PhtAcos(cinc) * (180.0/Isis::PI); + cema = max(-1.0,min(-xy*ye+z*ze,1.0)); + ema4 = PhtAcos(cema) * (180.0/Isis::PI); + + d1 = (CalcSurfAlbedo(phase,inc1,ema1) - CalcSurfAlbedo(phase,inc2,ema2)) / eps; + d2 = (CalcSurfAlbedo(phase,inc3,ema3) - CalcSurfAlbedo(phase,inc4,ema4)) / eps; + + // Combine these two derivatives and return the gradient + result = sqrt(max(1.0e-30,d1*d1+d2*d2)); + return result; + } + + /** + * Obtain arccosine of input value. If the input value is outside + * of the valid range (-1 to 1), then obtain the arccosine of the + * closest valid value. + * + * @param cosang input value to obtain arccosine of (in radians) + * @returns double Arccosine of cosang, if valid. + * @history 2008-11-05 Jeannie Walldren - This method was + * moved from NumericalMethods class. + * + */ + double PhotoModel::PhtAcos(double cosang) + { + double result; + + if (fabs(cosang) <= 1.0) { + result = acos(cosang); + } + else { + if (cosang < -1.0) { + result = acos(-1.0); + } + else { + result = acos(1.0); + } + } + + return result; + } + + /** + * Calculate the surface brightness using photometric angle information + * @param pha Phase angle + * @param inc Incidence angle + * @param ema Emission angle + * @returns double Surface brightness + * calculated by the photometric function + * + */ + double PhotoModel::CalcSurfAlbedo(double pha, double inc, double ema) { + + // Check validity of photometric angles + //if (pha > 180.0 || inc > 90.0 || ema > 90.0 || pha < 0.0 || + // inc < 0.0 || ema < 0.0) { + // std::string msg = "Invalid photometric angles"; + // throw iException::Message(iException::Programmer,msg,_FILEINFO_); + //} + + // Apply photometric function + double albedo = PhotoModelAlgorithm(pha,inc,ema); + return albedo; + } +} diff --git a/isis/src/base/objs/PhotoModel/PhotoModel.h b/isis/src/base/objs/PhotoModel/PhotoModel.h new file mode 100644 index 0000000000000000000000000000000000000000..1a69c1bed71bc42de9aaf1f33d85ce6905960abd --- /dev/null +++ b/isis/src/base/objs/PhotoModel/PhotoModel.h @@ -0,0 +1,87 @@ +#ifndef PhotoModel_h +#define PhotoModel_h +/** + * @file + * $Revision: 1.8 $ + * $Date: 2008/11/05 23:38:02 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Pvl.h" + +namespace Isis { +/** + * @brief + * + * @ingroup RadiometricAndPhotometricCorrection + * @author 1998-12-21 Randy Kirk + * + * @internal + * @history 1998-12-21 Randy Kirk - USGS, Flagstaff - Original + * code + * @history 2007-02-20 Janet Barrett - Imported from Isis2. + * @history 2007-07-31 Steven Lambright - Moved children methods out of this + * class and into the children classes + * @history 2008-03-07 Janet Barrett - Moved variables and related + * methods that pertain to Hapke specific parameters + * to this class from the HapkeHen class. Also added + * the code to set standard conditions. + * @history 2008-06-18 Steven Koechle - Fixed Documentation Errors + * @history 2008-07-09 Steven Lambright - Fixed unit test + * @history 2008-10-17 Steven Lambright - Moved Hapke-specific methods out of + * this class and into children classes. + * @history 2008-11-05 Jeannie Walldren - Moved PhtAcos() from + * NumericalMethods class. + */ + class PhotoModel { + public: + PhotoModel (Pvl &pvl); + virtual ~PhotoModel() {}; + + //! Return algorithm name found in Pvl file from constructor + inline std::string AlgorithmName () const { return p_photoAlgorithmName; }; + + virtual void SetStandardConditions(bool standard); + //! Returns true if standard conditions are used, i.e., if SetStandardConditions(true) has been called. This is initialized to false in the constructor. + bool StandardConditions() const { return p_standardConditions; } + + // Obtain topographic derivative + double PhtTopder(double phase, double incidence, double emission); + + // Obtain arccosine + static double PhtAcos(double cosang); + + // Calculate the surface brightness + double CalcSurfAlbedo(double pha, double inc, double ema); + + protected: + virtual double PhotoModelAlgorithm (double phase, + double incidence, double emission) = 0; + + private: + //! Unique name of the photometric model + std::string p_photoAlgorithmName; + //! Indicates whether standard conditions are used + bool p_standardConditions; + }; +}; + +#endif diff --git a/isis/src/base/objs/PhotoModel/PhotoModel.truth b/isis/src/base/objs/PhotoModel/PhotoModel.truth new file mode 100644 index 0000000000000000000000000000000000000000..519f28d0085a2dab56be12cf076fbf1d6d98bb8b --- /dev/null +++ b/isis/src/base/objs/PhotoModel/PhotoModel.truth @@ -0,0 +1,29 @@ +UNIT TEST for Isis::PhotoModel + +Testing missing PhotometricModel object ... +**PVL ERROR** Unable to find object [PhotometricModel] + +Testing missing Algorithm group ... +**PVL ERROR** Unable to find group [Algorithm] + +Testing missing Name keyword ... +**PVL ERROR** Keyword [Name] does not exist in [Group = Algorithm] + +Testing supported photometric model ... + +Testing photometric model PhtTopder method ... +Results from PhtTopder = 1e-15 + +Results from PhtTopder = 0.013697 + +Test PhtAcos ... +Results from PhtAcos = 0 + Actual value = 0 + +Results from PhtAcos = 0.000349285 + Actual value = 0.000349285 + +Results from PhtAcos = 2.6088 + Actual value = 2.6088 + + diff --git a/isis/src/base/objs/PhotoModel/unitTest.cpp b/isis/src/base/objs/PhotoModel/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc51007b47788b924df54e3189b2f6ccb00772fa --- /dev/null +++ b/isis/src/base/objs/PhotoModel/unitTest.cpp @@ -0,0 +1,100 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + void doit(Pvl &lab); + + std::cout << "UNIT TEST for Isis::PhotoModel" << + std::endl << std::endl; + + std::cout << "Testing missing PhotometricModel object ..." << + std::endl; + Pvl lab; + doit(lab); + + lab.AddObject(PvlObject("PhotometricModel")); + std::cout << "Testing missing Algorithm group ..." << + std::endl; + doit(lab); + + lab.FindObject("PhotometricModel").AddGroup(PvlGroup("Algorithm")); + std::cout << "Testing missing Name keyword ..." << std::endl; + doit(lab); + + // We can't do this in the unit test because it prints out an absolute path + // to the isis root which changes. + //lab.FindObject("PhotometricModel").FindGroup("Algorithm"). + // AddKeyword(PvlKeyword("Name","Bogus")); + //std::cout << "Testing unsupported photometric model ..." << std::endl; + //doit(lab); + + lab.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Name","Minnaert"), Pvl::Replace); + + std::cout << "Testing supported photometric model ..." << std::endl; + doit(lab); + + lab.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Name","Lambert"), Pvl::Replace); + PhotoModel *pm = PhotoModelFactory::Create(lab); + + std::cout << "Testing photometric model PhtTopder method ..." << std::endl; + try { + double result; + result = pm->PhtTopder(0.0,0.0,0.0); + std::cout << "Results from PhtTopder = " << result << + std::endl << std::endl; + result = pm->PhtTopder(86.7226722,51.7002388,38.9414439); + std::cout << "Results from PhtTopder = " << result << + std::endl << std::endl; + } + catch (iException &e) { + e.Report(false); + } + + std::cout << "Test PhtAcos ..." << std::endl; + try { + double result; + + result = PhotoModel::PhtAcos(1.0); + std::cout << "Results from PhtAcos = " << result << std::endl; + std::cout << " Actual value = " << 0 << std::endl + << std::endl; + result = PhotoModel::PhtAcos(.999999939); + std::cout << "Results from PhtAcos = " << result << std::endl; + std::cout << " Actual value = " << 0.000349285 << std::endl + << std::endl; + result = PhotoModel::PhtAcos(-.861393443); + std::cout << "Results from PhtAcos = " << result << std::endl; + std::cout << " Actual value = " << 2.608802982 << std::endl + << std::endl; + } + catch (iException &e) { + e.Report(); + } + + std::cout << std::endl; + + return 0; +} + +void doit(Pvl &lab) { + try { + //PhotoModel *pm = PhotoModelFactory::Create(lab); + PhotoModelFactory::Create(lab); + } + catch (iException &error) { + error.Report(false); + } + std::cout << std::endl; +} diff --git a/isis/src/base/objs/PhotoModelFactory/Makefile b/isis/src/base/objs/PhotoModelFactory/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f348eb7ab1573c88a7171b752cff4300e2f4874e --- /dev/null +++ b/isis/src/base/objs/PhotoModelFactory/Makefile @@ -0,0 +1,5 @@ +INCS = PhotoModelFactory.h +SRCS = PhotoModelFactory.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PhotoModelFactory/PhotoModelFactory.cpp b/isis/src/base/objs/PhotoModelFactory/PhotoModelFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..565260191ba436e1ad97dda1a418c988060c6519 --- /dev/null +++ b/isis/src/base/objs/PhotoModelFactory/PhotoModelFactory.cpp @@ -0,0 +1,72 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2007/02/20 16:55:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PhotoModelFactory.h" +#include "PhotoModel.h" +#include "Plugin.h" +#include "iException.h" +#include "Filename.h" + +namespace Isis { + /** + * Create a PhotoModel object using a PVL specification. + * An example of the PVL required for this is: + * + * @code + * Object = PhotometricModel + * Group = Algorithm + * Name = Minnaert + * K = 0.7 + * EndGroup + * EndObject + * @endcode + * + * There are many other options that can be set via the pvl and are + * described in other documentation (see below). + * + * @param pvl The pvl object containing the specification + * + * @see photometricModels.doc + **/ + PhotoModel *PhotoModelFactory::Create(Pvl &pvl) { + // Get the algorithm name to create + PvlGroup &algo = pvl.FindObject("PhotometricModel") + .FindGroup("Algorithm",Pvl::Traverse); + std::string algorithm = algo["Name"]; + + // Open the factory plugin file + Plugin *p = new Plugin; + Filename f("PhotoModel.plugin"); + if (f.Exists()) { + p->Read("PhotoModel.plugin"); + } + else { + p->Read("$ISISROOT/lib/PhotoModel.plugin"); + } + + // Get the algorithm specific plugin and return it + PhotoModel * (*plugin) (Pvl &pvl); + plugin = (PhotoModel * (*)(Pvl &pvl)) p->GetPlugin(algorithm); + return (*plugin)(pvl); + } +} // end namespace isis diff --git a/isis/src/base/objs/PhotoModelFactory/PhotoModelFactory.h b/isis/src/base/objs/PhotoModelFactory/PhotoModelFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..0f7b266b91e6184ea322d35e9bd10e39f12d3a1e --- /dev/null +++ b/isis/src/base/objs/PhotoModelFactory/PhotoModelFactory.h @@ -0,0 +1,82 @@ +#ifndef PhotoModelFactory_h +#define PhotoModelFactory_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/18 19:31:34 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { + class Pvl; + class PhotoModel; + + /** + * This class is used to create PhotoModel objects. Typically, applications which + * perform photometric corrections need to use different types of photometric + * function such as Lambert, Minnaert, HapkeLegendre, etc. If this factory is + * given a Pvl object which contains a PhotoModel definition, it will create that + * specific instance of the class. For example, + * + * @code + * Object = PhotometricModel + * Group = Algorithm + * Name = Minnaert + * ... + * EndGroup + * ... + * EndObject + * End + * @endcode + * + * Will create a Minnaert object (which is derived from PhotoModel). The + * simplest way to create a PhotoModel class is to use the static Create + * method. + * + * @code + * Pvl p("myphotmodel.pvl"); + * PhotoModel *ar = PhotoModelFactory::Create(p); + * @endcode + * + * @ingroup PatternMatching + * + * @author 2006-01-23 Janet Barrett + * + * @internal + * @history 2006-01-23 Janet Barrett - Original version + * @history 2008-06-18 Steven Koechle - Fixed Documentation Errors + * + */ + class PhotoModelFactory { + public: + static PhotoModel *Create(Pvl &pvl); + + private: + /** + * Constructor (its private so you can't use it). Use the Create Method + * instead. + */ + PhotoModelFactory() {}; + + //! Destroys the PhotoModelFactory + ~PhotoModelFactory() {}; + }; +}; + +#endif diff --git a/isis/src/base/objs/PhotoModelFactory/PhotoModelFactory.truth b/isis/src/base/objs/PhotoModelFactory/PhotoModelFactory.truth new file mode 100644 index 0000000000000000000000000000000000000000..635b210dfb07f57dd619b1c905adbb74a8460a58 --- /dev/null +++ b/isis/src/base/objs/PhotoModelFactory/PhotoModelFactory.truth @@ -0,0 +1 @@ +All testing deferred to PhotoModel and it's extended classes. diff --git a/isis/src/base/objs/PhotoModelFactory/unitTest.cpp b/isis/src/base/objs/PhotoModelFactory/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a8e6c93d40d741fc69b66c690ebe55041900da9 --- /dev/null +++ b/isis/src/base/objs/PhotoModelFactory/unitTest.cpp @@ -0,0 +1,13 @@ +#include +#include +#include "Preference.h" + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + + cout << "All testing deferred to PhotoModel and it's extended classes." << endl; + + return 0; +} diff --git a/isis/src/base/objs/Photometry/Makefile b/isis/src/base/objs/Photometry/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6730367bf965ca4080cf46dd6cc1734b246e8129 --- /dev/null +++ b/isis/src/base/objs/Photometry/Makefile @@ -0,0 +1,5 @@ +INCS = Photometry.h +SRCS = Photometry.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Photometry/Photometry.cpp b/isis/src/base/objs/Photometry/Photometry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f4adaac42a58120d96285144d38443e6226e133e --- /dev/null +++ b/isis/src/base/objs/Photometry/Photometry.cpp @@ -0,0 +1,90 @@ +#include "Pvl.h" +#include "Photometry.h" +#include "PhotoModelFactory.h" +#include "PhotoModel.h" +#include "AtmosModelFactory.h" +#include "AtmosModel.h" +#include "NormModelFactory.h" +#include "NormModel.h" +#include "Plugin.h" +#include "Filename.h" + +namespace Isis { + /** + * Create Photometry object. + * + * @param pvl A pvl object containing a valid Photometry specification + * + * @see photometry.doc + */ + Photometry::Photometry (Pvl &pvl) { + p_phtAmodel = NULL; + p_phtPmodel = NULL; + p_phtNmodel = NULL; + p_phtPmodel = PhotoModelFactory::Create(pvl); + if (pvl.HasObject("AtmosphericModel")) { + p_phtAmodel = AtmosModelFactory::Create(pvl, *p_phtPmodel); + p_phtNmodel = NormModelFactory::Create(pvl, *p_phtPmodel, + *p_phtAmodel); + } else { + p_phtNmodel = NormModelFactory::Create(pvl, *p_phtPmodel); + } + } + + //! Destroy Photometry object + Photometry::~Photometry() { + if(p_phtAmodel != NULL) { + delete p_phtAmodel; + p_phtAmodel = NULL; + } + + if(p_phtPmodel != NULL) { + delete p_phtPmodel; + p_phtPmodel = NULL; + } + + if(p_phtNmodel != NULL) { + delete p_phtNmodel; + p_phtNmodel = NULL; + } + } + + /** + * Set the wavelength parameter. This value is obtained + * from the BandBin Center keyword of the image. + * + */ + void Photometry::SetPhotomWl(double wl) { + p_phtNmodel->SetNormWavelength(wl); + } + + /** + * Calculate the surface brightness using only ellipsoid + * + * @return Returns the surface brightness + * + */ + void Photometry::Compute(double pha, double inc, double ema, + double dn, double &albedo, double &mult, + double &base) { + + // Calculate the surface brightness + p_phtNmodel->CalcNrmAlbedo(pha,inc,ema,dn,albedo,mult,base); + return; + } + + /** + * Calculate the surface brightness using ellipsoid and dem + * + * @return Returns the surface brightness + * + */ + void Photometry::Compute(double pha, double inc, double ema, + double deminc, double demema, double dn, + double &albedo, double &mult, double &base) { + + // Calculate the surface brightness + p_phtNmodel->CalcNrmAlbedo(pha,inc,ema,deminc,demema,dn,albedo,mult,base); + return; + } +} diff --git a/isis/src/base/objs/Photometry/Photometry.h b/isis/src/base/objs/Photometry/Photometry.h new file mode 100644 index 0000000000000000000000000000000000000000..ecbaa91e41c034eb35d357e3c16f7fbf94a267bd --- /dev/null +++ b/isis/src/base/objs/Photometry/Photometry.h @@ -0,0 +1,65 @@ +#ifndef Photometry_h +#define Photometry_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/07/09 19:40:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +namespace Isis { + class Pvl; + class PhotoModel; + class AtmosModel; + class NormModel; +/** + * @internal + * @history 2007-08-02 Steven Lambright - Fixed memory leak + * @history 2008-03-07 Janet Barrett - Added SetPhotomWl method to allow + * the application to set the p_normWavelength variable for + * use by MoonAlbedo normalization. + * @history 2008-06-18 Steven Koechle - Fixed Documentation Errors + * @history 2008-07-09 Steven Lambright - Fixed unit test + */ + class Photometry { + public: + Photometry (Pvl &pvl); + virtual ~Photometry(); + + //! Calculate the surface brightness + void Compute(double pha, double inc, double ema, double dn, + double &albedo, double &mult, double &base); + void Compute(double pha, double inc, double ema, double deminc, + double demema, double dn, double &albedo, + double &mult, double &base); + + //! Set the wavelength + virtual void SetPhotomWl(double wl); + + protected: + AtmosModel *p_phtAmodel; + PhotoModel *p_phtPmodel; + NormModel *p_phtNmodel; + }; +}; + +#endif diff --git a/isis/src/base/objs/Photometry/Photometry.truth b/isis/src/base/objs/Photometry/Photometry.truth new file mode 100644 index 0000000000000000000000000000000000000000..90bdd22327783bd49b03c01de866b3506ca58783 --- /dev/null +++ b/isis/src/base/objs/Photometry/Photometry.truth @@ -0,0 +1,13 @@ +UNIT TEST for Isis::Photometry + +Testing creation of photometry object ... +Testing photometry method without dem ... +Photometric brightness value = 0.111872 + +Photometric brightness value = 0.11142 + +Testing photometry method with dem ... +Photometric brightness value = 0.0531455 + +Photometric brightness value = 0.0524591 + diff --git a/isis/src/base/objs/Photometry/unitTest.cpp b/isis/src/base/objs/Photometry/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4c0ee714faac3d558c953ed3fbb8b6cccf31b2b9 --- /dev/null +++ b/isis/src/base/objs/Photometry/unitTest.cpp @@ -0,0 +1,164 @@ +#include +#include +#include "Photometry.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + std::cout << "UNIT TEST for Isis::Photometry" << + std::endl << std::endl; + + Pvl lab; + lab.AddObject(PvlObject("PhotometricModel")); + lab.FindObject("PhotometricModel").AddGroup(PvlGroup("Algorithm")); + lab.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Name","Minnaert")); + lab.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Wh","0.52")); + lab.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("B0","0.0")); + lab.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Hh","0.0")); + lab.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Theta","30.0")); + lab.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Hg1","0.213")); + lab.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Hg2","1.0")); + + lab.AddObject(PvlObject("AtmosphericModel")); + lab.FindObject("AtmosphericModel").AddGroup(PvlGroup("Algorithm")); + lab.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Name","Anisotropic1")); + lab.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Tau","0.28")); + lab.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Tauref","0.001")); + lab.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Wha","0.95")); + lab.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Bha","0.85")); + lab.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Hga","0.68")); + lab.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Hnorm","0.003")); + lab.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Nulneg","NO")); + + lab.AddObject(PvlObject("NormalizationModel")); + lab.FindObject("NormalizationModel").AddGroup(PvlGroup("Algorithm")); + lab.FindObject("NormalizationModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Name","Albedo")); + lab.FindObject("NormalizationModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Incref","30.0")); + lab.FindObject("NormalizationModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Albedo","0.0690507")); + lab.FindObject("NormalizationModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Thresh","30.0")); + + Pvl labdem; + labdem.AddObject(PvlObject("PhotometricModel")); + labdem.FindObject("PhotometricModel").AddGroup(PvlGroup("Algorithm")); + labdem.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Name","Lambert")); + labdem.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Wh","0.52")); + labdem.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("B0","0.0")); + labdem.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Hh","0.0")); + labdem.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Theta","30.0")); + labdem.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Hg1","0.213")); + labdem.FindObject("PhotometricModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Hg2","1.0")); + + labdem.AddObject(PvlObject("AtmosphericModel")); + labdem.FindObject("AtmosphericModel").AddGroup(PvlGroup("Algorithm")); + labdem.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Name","Anisotropic1")); + labdem.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Tau","0.28")); + labdem.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Tauref","0.001")); + labdem.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Wha","0.95")); +// labdem.FindObject("AtmosphericModel").FindGroup("Algorithm"). +// AddKeyword(PvlKeyword("Wharef","0.95")); + labdem.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Bha","0.85")); +// labdem.FindObject("AtmosphericModel").FindGroup("Algorithm"). +// AddKeyword(PvlKeyword("Bharef","0.85")); + labdem.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Hga","0.68")); +// labdem.FindObject("AtmosphericModel").FindGroup("Algorithm"). +// AddKeyword(PvlKeyword("Hgaref","0.68")); + labdem.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Hnorm","0.003")); + labdem.FindObject("AtmosphericModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Nulneg","NO")); + + labdem.AddObject(PvlObject("NormalizationModel")); + labdem.FindObject("NormalizationModel").AddGroup(PvlGroup("Algorithm")); + labdem.FindObject("NormalizationModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Name","AlbedoAtm")); + labdem.FindObject("NormalizationModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Incref","0.0")); + labdem.FindObject("NormalizationModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Albedo","0.0690507")); + labdem.FindObject("NormalizationModel").FindGroup("Algorithm"). + AddKeyword(PvlKeyword("Thresh","30.0")); + + std::cout << "Testing creation of photometry object ..." << std::endl; + try { +// double result; + double albedo,mult,base; + Photometry *pho = new Photometry(lab); + Photometry *phodem = new Photometry(labdem); + std::cout << "Testing photometry method without dem ..." << std::endl; +// result = pho->Compute(86.722672229212051,51.7002388445338,38.94144389777756, +// 0.080061890184879303); + pho->Compute(86.722672229212051,51.7002388445338,38.94144389777756, + 0.080061890184879303,albedo,mult,base); +// std::cout << "Photometric brightness value = " << result << std::endl << +// std::endl; + std::cout << "Photometric brightness value = " << albedo << std::endl << + std::endl; +// result = pho->Compute(86.7207248,51.7031305,38.9372914,.0797334611); + pho->Compute(86.7207248,51.7031305,38.9372914,.0797334611,albedo,mult, + base); +// std::cout << "Photometric brightness value = " << result << std::endl << +// std::endl; + std::cout << "Photometric brightness value = " << albedo << std::endl << + std::endl; + std::cout << "Testing photometry method with dem ..." << std::endl; +// result = phodem->Compute(86.7226722,51.7002388,38.9414439,51.7910076, +// 39.0176048,.0800618902); + phodem->Compute(86.7226722,51.7002388,38.9414439, + .0800618902,albedo,mult,base); +// std::cout << "Photometric brightness value = " << result << std::endl << +// std::endl; + std::cout << "Photometric brightness value = " << albedo << std::endl << + std::endl; +// result = phodem->Compute(86.7207248,51.7031305,38.9372914,51.8776595, +// 38.9719125,.0797334611); + phodem->Compute(86.7207248,51.7031305,38.9372914, + .0797334611,albedo,mult,base); +// std::cout << "Photometric brightness value = " << result << std::endl << +// std::endl; + std::cout << "Photometric brightness value = " << albedo << std::endl << + std::endl; + } + catch (iException &e) { + e.Report(false); + } + + return 0; +} diff --git a/isis/src/base/objs/Pipeline/Makefile b/isis/src/base/objs/Pipeline/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e5c332fab6621a58aeaf9c73dddb126bd198fc32 --- /dev/null +++ b/isis/src/base/objs/Pipeline/Makefile @@ -0,0 +1,5 @@ +INCS = Pipeline.h PipelineApplication.h +SRCS = Pipeline.cpp PipelineApplication.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Pipeline/Pipeline.cpp b/isis/src/base/objs/Pipeline/Pipeline.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ec073dc227e2abe05515f24da4d8c1cef2423031 --- /dev/null +++ b/isis/src/base/objs/Pipeline/Pipeline.cpp @@ -0,0 +1,756 @@ +#include + +#include "Pipeline.h" +#include "PipelineApplication.h" +#include "iException.h" +#include "Application.h" +#include "Preference.h" +#include "TextFile.h" +#include "Filename.h" + +using namespace Isis; +using namespace std; + +namespace Isis { + + + /** + * This is the one and only Pipeline constructor. This will initialize a + * pipeline object. + * + * @param procAppName This is an option parameter that gives the pipeline a name + */ + Pipeline::Pipeline(const iString &procAppName) { + p_procAppName = procAppName; + p_addedCubeatt = false; + p_outputListNeedsModifiers = false; + } + + + /** + * This destroys the pipeline + * + */ + Pipeline::~Pipeline(){ + for(int i = 0; i < (int)p_apps.size(); i++) { + delete p_apps[i]; + } + + p_apps.clear(); + } + + + /** + * This method is the core of the pipeline class. This method tells each + * PipelineApplication to learn about itself and calculate necessary filenames, + * execution calls, etc... Pipeline error checking happens in here, so if a + * Pipeline is invalid this method will throw the iException. + * + */ + void Pipeline::Prepare() { + // Nothing in the pipeline? quit + if(p_apps.size() == 0) return; + + // We might have to modify the pipeline and try again, so keep track of if this is necessary + bool successfulPrepare = false; + + while(!successfulPrepare) { + // Assume we'll be successful + successfulPrepare = true; + bool foundFirst = false; + + // Keep track of whether or not we must remove virtual bands + bool mustElimBands = false; + + // Look to see if we need to eliminate virtual bands... + for(unsigned int i = 0; i < p_virtualBands.size(); i++) { + mustElimBands |= !p_virtualBands[i].empty(); + } + + // Keep track of temp files for conflicts + vector tmpFiles; + + // Loop through all the pipeline apps, look for a good place to remove virtual + // bands and tell the apps the prepare themselves. Double check the first program + // is not branched (expecting multiple inputs). + for(int i = 0; i < (int)p_apps.size() && successfulPrepare; i++) { + if(mustElimBands && p_apps[i]->SupportsVirtualBands()) { + if(i != 0 && p_virtualBands.size() != 1) { + iString message = "If multiple original inputs were set in the pipeline, the first application must support virtual bands."; + throw iException::Message(iException::Programmer, message, _FILEINFO_); + } + + p_apps[i]->SetVirtualBands(p_virtualBands); + mustElimBands = false; + + // We might have added the "cubeatt" program to eliminate bands, + // remove it if we found something else to do the virtual bands. + // **This causes a failure in our calculations, start over. + if(p_addedCubeatt && i != (int)p_apps.size() - 1) { + delete p_apps[p_apps.size() - 1]; + p_apps.resize(p_apps.size() - 1); + p_appIdentifiers.resize(p_appIdentifiers.size() - 1); + p_apps[p_apps.size() - 1]->SetNext(NULL); + p_addedCubeatt = false; + successfulPrepare = false; + continue; + } + } + else { + // Pipeline is responsible for the virtual bands, reset any apps + // who have an old virtual bands setting. + vector empty; + p_apps[i]->SetVirtualBands(empty); + } + + // This instructs the pipeline app to prepare itself; all previous pipeline apps must + // be already prepared. Future pipeline apps do not have to be. + p_apps[i]->BuildParamString(); + + // keep track of tmp files + vector theseTempFiles = p_apps[i]->TemporaryFiles(); + for(int tmpFile = 0; tmpFile < (int)theseTempFiles.size(); tmpFile++) { + tmpFiles.push_back(theseTempFiles[tmpFile]); + } + + if(!foundFirst && p_apps[i]->Enabled()) { + foundFirst = true; + + if(p_apps[i]->InputBranches().size() != OriginalBranches().size()) { + string msg = "The program [" + p_apps[i]->Name() + "] can not be the first in the pipeline"; + msg += " because it must be run multiple times with unspecified varying inputs"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + } + + // Make sure we found an app! + if(!foundFirst) { + string msg = "No applications are enabled in the pipeline"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + // Make sure all tmp files are unique! + for(int i = 0; successfulPrepare && i < (int)tmpFiles.size(); i++) { + for(int j = i+1; j < (int)tmpFiles.size(); j++) { + if(tmpFiles[i] == tmpFiles[j]) { + string msg = "There is a conflict with the temporary file naming. The temporary file ["; + msg += tmpFiles[i] + "] is created twice."; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + } + + // We failed at eliminating bands, add stretch to our programs and try again + if(successfulPrepare && mustElimBands) { + AddToPipeline("cubeatt", "~PIPELINE_RESERVED_FOR_BANDS~"); + Application("~PIPELINE_RESERVED_FOR_BANDS~").SetInputParameter("FROM", true); + Application("~PIPELINE_RESERVED_FOR_BANDS~").SetOutputParameter("TO", "final"); + p_addedCubeatt = true; + successfulPrepare = false; + } + + if(p_apps[p_apps.size()-1]->GetOutputs().size() == 0) { + string msg = "There are no outputted files in the pipeline. At least one program must generate an output file."; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + } + + + /** + * This method executes the pipeline. When you're ready to start your proc + * program, call this method. + */ + void Pipeline::Run(){ + // Prepare the pipeline programs + Prepare(); + + // Go through these programs, executing them + for(int i = 0; i < Size(); i++) { + if(Application(i).Enabled()) { + // grab the sets of parameters this program needs to be run with + const vector ¶ms = Application(i).ParamString(); + for(int j = 0; j < (int)params.size(); j++) { + + // check for non-program run special strings + iString special(params[j].substr(0,7)); + + // If ">>LIST", then we need to make a list file + if(special == ">>LIST ") { + iString cmd = params[j].substr(7); + iString listFilename = cmd.Token(" "); + TextFile listFile(listFilename, "overwrite"); + + while(!cmd.empty()) { + listFile.PutLine(cmd.Token(" ")); + } + + listFile.Close(); + } + else { + // Nothing special is happening, just execute the program + Isis::iApp->Exec(Application(i).Name(), params[j]); + } + } + } + } + + // Remove temporary files now + if(!KeepTemporaryFiles()) { + for(int i = 0; i < Size(); i++) { + if(Application(i).Enabled()) { + vector tmpFiles = Application(i).TemporaryFiles(); + for(int file = 0; file < (int)tmpFiles.size(); file++) { + remove(tmpFiles[file].c_str()); + } + } + } + } + } + + + /** + * This method is used to set the original input file. This file is the first + * program's input, and the virtual bands will be taken directly from this + * parameter. + * + * @param inputParam The parameter to get from the user interface that contains + * the input file + */ + void Pipeline::SetInputFile(const iString &inputParam) { + UserInterface &ui = Application::GetUserInterface(); + p_originalInput.push_back(ui.GetFilename(inputParam)); + p_originalBranches.push_back(inputParam); + p_virtualBands.push_back(ui.GetInputAttribute(inputParam).BandsStr()); + } + + + /** + * This method is used to set the original input file. No virtual bands will + * be read, and the inputFile parameter will be read as a path to a file instead + * of as a parameter. + * + * @param inputParam A filename object containing the location of the input file + */ + void Pipeline::SetInputFile(const Filename &inputFile) { + p_originalInput.push_back(inputFile.Expanded()); + p_originalBranches.push_back(inputFile.Expanded()); + p_virtualBands.push_back(""); + } + + + /** + * This method is used to set the original input files. These files are the + * first program's input, a branch will be added for every line in the file, and + * the virtual bands will be taken directly from this parameter. + * + * @param inputParam The parameter to get from the user interface that contains + * the input file + */ + void Pipeline::SetInputListFile(const iString &inputParam) { + UserInterface &ui = Application::GetUserInterface(); + + TextFile filelist( Filename(ui.GetFilename(inputParam)).Expanded() ); + string filename; + int branch = 1; + + while(filelist.GetLineNoFilter(filename)) { + p_originalInput.push_back(filename); + p_originalBranches.push_back(inputParam + iString(branch)); + p_virtualBands.push_back(""); + p_finalOutput.push_back(Filename(filename).Name()); + + branch ++; + } + + p_outputListNeedsModifiers = true; + } + + + /** + * This method is used to set the original input files. These files are the + * first program's input, a branch will be added for every line in the file. + * + * @param inputParam The filename of the list file contains the input files + */ + void Pipeline::SetInputListFile(const Filename &inputFilename) { + TextFile filelist( inputFilename.Expanded() ); + string filename; + int branch = 1; + + while(filelist.GetLineNoFilter(filename)) { + p_originalInput.push_back(filename); + p_originalBranches.push_back(Filename(inputFilename).Expanded() + " " + iString(branch)); + p_finalOutput.push_back(Filename(filename).Name()); + p_virtualBands.push_back(""); + + branch ++; + } + + p_outputListNeedsModifiers = true; + } + + + /** + * This method is used to set the original input file. This file is the first + * program's input. + * + * @param inputParam The parameter to get from the user interface that contains + * the input file + * @param virtualBandsParam The parameter to get from the user interface that + * contains the virtual bands list; internal default is + * supported. Empty string if no virtual bands + * parameter exists. + */ + void Pipeline::SetInputFile(const iString &inputParam, const iString &virtualBandsParam) { + UserInterface &ui = Application::GetUserInterface(); + p_originalInput.push_back(ui.GetAsString(inputParam)); + p_originalBranches.push_back(inputParam); + + if(!virtualBandsParam.empty() && ui.WasEntered(virtualBandsParam)) { + p_virtualBands.push_back(ui.GetAsString(virtualBandsParam)); + } + else { + p_virtualBands.push_back(""); + } + } + + + /** + * This method is used to set the final output file. If no programs generate + * output, the final output file will not be used. If the output file was not + * entered, one will be generated automatically and placed into the current + * working folder. + * + * @param outputParam The parameter to get from the user interface that contains + * the output file; internal default is supported. + */ + void Pipeline::SetOutputFile(const iString &outputParam) { + UserInterface &ui = Application::GetUserInterface(); + p_finalOutput.clear(); + + if(ui.WasEntered(outputParam)) { + p_finalOutput.push_back(ui.GetAsString(outputParam)); + } + } + + + /** + * This method is used to set the final output file. If no programs generate + * output, the final output file will not be used. If the output file was not + * entered, one will be generated automatically and placed into the current + * working folder. + * + * @param outputFile The filename of the output file; NOT the parameter name. + */ + void Pipeline::SetOutputFile(const Filename &outputFile) { + p_finalOutput.clear(); + p_finalOutput.push_back(outputFile.Expanded()); + } + + + /** + * This method is used to set an output list file. Basically, this means the + * output filenames are specified in the list file. Internal defaults/automatic + * name calculations are supported. + * + * @param outputFilenameList Parameter name containing the path to the output + * list file + */ + void Pipeline::SetOutputListFile(const iString &outputFilenameParam) { + UserInterface &ui = Application::GetUserInterface(); + + if(ui.WasEntered(outputFilenameParam)) { + SetOutputListFile(Filename(ui.GetFilename(outputFilenameParam))); + } + else { + p_finalOutput.clear(); + + // Calculate output files + for(unsigned int i = 0; i < p_originalInput.size(); i++) { + p_finalOutput.push_back(Filename(p_originalInput[i]).Name()); + } + + p_outputListNeedsModifiers = true; + } + } + + + /** + * This method is used to set an output list file. Basically, this means the + * output filenames are specified in the list file. + * + * @param outputFilenameList List file with output cube names + */ + void Pipeline::SetOutputListFile(const Filename &outputFilenameList) { + p_finalOutput.clear(); + + TextFile filelist( outputFilenameList.Expanded() ); + string filename; + + while(filelist.GetLineNoFilter(filename)) { + p_finalOutput.push_back(filename); + } + + p_outputListNeedsModifiers = false; + } + + + /** + * Set whether or not to keep temporary files (files generated in the middle of + * the pipeline that are neither the original input nor the final output). + * + * @param keep True means don't delete, false means delete. + */ + void Pipeline::KeepTemporaryFiles(bool keep) { + p_keepTemporary = keep; + } + + + /** + * Add a new program to the pipeline. This method must be called before calling + * Pipeline::Application(...) to access it. The string identifier will access + * this program. + * + * @param appname The name of the new application + * @param identifier The program's identifier for when calling + * Pipeline::Application + */ + void Pipeline::AddToPipeline(const iString &appname, const iString &identifier) { + // Check uniqueness first + for(unsigned int appIdentifier = 0; appIdentifier < p_appIdentifiers.size(); appIdentifier++) { + if(p_appIdentifiers[appIdentifier] == identifier) { + iString message = "The application identifier [" + identifier + "] is not unique. " + + "Please providing a unique identifier"; + throw iException::Message(iException::Programmer, message, _FILEINFO_); + } + } + + // If we've got cubeatt on our list of applications for band eliminating, take it away temporarily + PipelineApplication *cubeAtt = NULL; + iString cubeAttId = ""; + if(p_addedCubeatt) { + cubeAtt = p_apps[p_apps.size()-1]; + cubeAttId = p_appIdentifiers[p_appIdentifiers.size()-1]; + p_apps.resize(p_apps.size()-1); + p_appIdentifiers.resize(p_appIdentifiers.size()-1); + p_apps[p_apps.size()-1]->SetNext(NULL); + } + + // Add the new application + if(p_apps.size() == 0) { + p_apps.push_back(new PipelineApplication(appname, this)); + } + else { + p_apps.push_back(new PipelineApplication(appname, p_apps[p_apps.size()-1])); + } + + p_appIdentifiers.push_back(identifier); + + // If we have stretch, put it back where it belongs + if(cubeAtt) { + p_apps[p_apps.size()-1]->SetNext(cubeAtt); + cubeAtt->SetPrevious(p_apps[p_apps.size()-1]); + p_apps.push_back(cubeAtt); + p_appIdentifiers.push_back(cubeAttId); + } + } + + + /** + * Add a new program to the pipeline. This method must be called before calling + * Pipeline::Application(...) to access it. The string used to access this + * program will be the program's name. + * + * @param appname The name of the new application + */ + void Pipeline::AddToPipeline(const iString &appname) { + // Check uniqueness first + for(unsigned int appIdentifier = 0; appIdentifier < p_appIdentifiers.size(); appIdentifier++) { + if(p_appIdentifiers[appIdentifier] == appname) { + iString message = "The application identifier [" + appname + "] is not unique. Please use " + + "the other AddToPipeline method providing a unique identifier"; + throw iException::Message(iException::Programmer, message, _FILEINFO_); + } + } + + // If we've got cubeatt on our list of applications for band eliminating, take it away temporarily + PipelineApplication *cubeAtt = NULL; + iString cubeAttId = ""; + if(p_addedCubeatt) { + cubeAtt = p_apps[p_apps.size()-1]; + cubeAttId = p_appIdentifiers[p_appIdentifiers.size()-1]; + p_apps.resize(p_apps.size()-1); + p_appIdentifiers.resize(p_appIdentifiers.size()-1); + p_apps[p_apps.size()-1]->SetNext(NULL); + } + + // Add the new application + if(p_apps.size() == 0) { + p_apps.push_back(new PipelineApplication(appname, this)); + } + else { + p_apps.push_back(new PipelineApplication(appname, p_apps[p_apps.size()-1])); + } + + p_appIdentifiers.push_back(appname); + + // If we have stretch, put it back where it belongs + if(cubeAtt) { + p_apps[p_apps.size()-1]->SetNext(cubeAtt); + cubeAtt->SetPrevious(p_apps[p_apps.size()-1]); + p_apps.push_back(cubeAtt); + p_appIdentifiers.push_back(cubeAttId); + } + } + + + /** + * This is an accessor to get a specific PipelineApplication. This is the + * recommended accessor. + * + * @param identifier The identifier (usually name) of the application to access, + * such as "spiceinit" + * + * @return PipelineApplication& The application's representation in the pipeline + */ + PipelineApplication &Pipeline::Application(const iString &identifier) { + int index = 0; + bool found = false; + + while(!found && index < Size()) { + if(p_appIdentifiers[index] == identifier) { + found = true; + } + else { + index ++; + } + } + + if(!found) { + iString msg = "Application identified by [" + identifier + "] has not been added to the pipeline"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + return *p_apps[index]; + } + + + /** + * This is an accessor to get a specific PipelineApplication. This accessor is + * mainly in place for the output operator; it is not recommended. + * + * @param index The index of the pipeline application + * + * @return PipelineApplication& The pipeline application + */ + PipelineApplication &Pipeline::Application(const int &index) { + if(index > Size()) { + iString msg = "Index [" + iString(index) + "] out of bounds"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + return *p_apps[index]; + } + + + /** + * This method disables all applications up to this one. Effectively, the + * application specified becomes the first application. This is not a guarantee + * that the application specified is enabled, it only guarantees no applications + * before it will be run. + * + * @param appname The program to start with + */ + void Pipeline::SetFirstApplication(const iString &appname) { + int appIndex = 0; + for(appIndex = 0; appIndex < (int)p_apps.size() && p_apps[appIndex]->Name() != appname; appIndex++) { + p_apps[appIndex]->Disable(); + } + + if(appIndex >= (int)p_apps.size()) { + string msg = "Pipeline could not find application [" + appname + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + /** + * This method disables all applications after to this one. Effectively, the + * application specified becomes the last application. This is not a guarantee + * that the application specified is enabled, it only guarantees no applications + * after it will be run. + * + * @param appname The program to end with + */ + void Pipeline::SetLastApplication(const iString &appname) { + int appIndex = p_apps.size() - 1; + for(appIndex = p_apps.size() - 1; appIndex >= 0 && p_apps[appIndex]->Name() != appname; appIndex --) { + p_apps[appIndex]->Disable(); + } + + if(appIndex < 0) { + string msg = "Pipeline could not find application [" + appname + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + /** + * This gets the final output for the specified branch; this is necessary for + * the PipelineApplications to calculate the correct outputs to use. + * + * @param branch Branch index to get the final output for + * @param addModifiers Whether or not to add the last name modifier + * + * @return iString The final output string + */ + iString Pipeline::FinalOutput(int branch, bool addModifiers) { + iString output = ((p_finalOutput.size() != 0)? p_finalOutput[0] : ""); + + if(p_apps.size() == 0) return output; + + if(p_finalOutput.size() > 1) { + if((unsigned int)branch >= p_finalOutput.size()) { + iString msg = "Output not set for branch [" + iString(branch) + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + if(!p_outputListNeedsModifiers) { + return p_finalOutput[branch]; + } + else { + output = p_finalOutput[branch]; + addModifiers = true; + } + } + + PipelineApplication *last = p_apps[p_apps.size()-1]; + if(!last->Enabled()) last = last->Previous(); + + if(output == "" || p_finalOutput.size() > 1) { + if(output == "") { + output = "./" + Filename(p_originalInput[0]).Basename(); + } + else { + output = "./" + Filename(p_originalInput[branch]).Basename(); + } + + // Base filename off of first input file + if(!addModifiers || last->OutputBranches().size() == 1) { + if(addModifiers && p_finalOutput.size() > 1) + output += "." + last->OutputNameModifier(); + + output += "." + last->OutputExtension(); + } + else { + // If we have multuple final outputs, rely on them to + // differentiate the branches + if(p_finalOutput.size() <= 1) { + output += "." + last->OutputBranches()[branch]; + } + + if(addModifiers && p_finalOutput.size() > 1) + output += "." + last->OutputNameModifier(); + + output += "." + last->OutputExtension(); + } + } + else if(addModifiers) { + PipelineApplication *last = p_apps[p_apps.size()-1]; + if(!last->Enabled()) last = last->Previous(); + + output = Filename(p_finalOutput[0]).Path() + "/" + + Filename(p_finalOutput[0]).Basename() + "." + + last->OutputBranches()[branch] + "."; + + if(p_finalOutput.size() > 1) { + output += last->OutputNameModifier() + "."; + } + + output += last->OutputExtension(); + } + + return output; + } + + + /** + * This method returns the user's temporary folder for temporary files. It's + * simply a conveinient accessor to the user's preferences. + * + * @return iString The temporary folder + */ + iString Pipeline::TemporaryFolder() { + Pvl &pref = Preference::Preferences(); + return (string)pref.FindGroup("DataDirectory")["Temporary"]; + } + + + /** + * This method re-enables all applications. This resets the effects of + * PipelineApplication::Disable, SetFirstApplication and SetLastApplication. + * + */ + void Pipeline::EnableAllApplications() { + for(int i = 0; i < Size(); i++) { + p_apps[i]->Enable(); + } + } + + + /** + * This is the output operator for a Pipeline, which enables things such as: + * @code + * Pipeline p; + * cout << p << endl; + * @endcode + * + * @param os The output stream (usually cout) + * @param pipeline The pipeline object to output + * + * @return ostream& The modified output stream + */ + ostream &operator<<(ostream &os, Pipeline &pipeline) { + pipeline.Prepare(); + + if(!pipeline.Name().empty()) { + os << "PIPELINE -------> " << pipeline.Name() << " <------- PIPELINE" < ¶ms = pipeline.Application(i).ParamString(); + for(int j = 0; j < (int)params.size(); j++) { + iString special(params[j].substr(0,7)); + if(special == ">>LIST ") { + iString cmd = params[j].substr(7); + iString file = cmd.Token(" "); + os << "echo " << cmd << " > " << file << endl; + } + else { + os << pipeline.Application(i).Name() << " " << params[j] << endl; + } + } + } + } + + if(!pipeline.KeepTemporaryFiles()) { + for(int i = 0; i < pipeline.Size(); i++) { + if(pipeline.Application(i).Enabled()) { + vector tmpFiles = pipeline.Application(i).TemporaryFiles(); + for(int file = 0; file < (int)tmpFiles.size(); file++) { + os << "rm " << tmpFiles[file] << endl; + } + } + } + } + + if(!pipeline.Name().empty()) { + os << "PIPELINE -------> " << pipeline.Name() << " <------- PIPELINE" < + +#include "iString.h" +#include "PipelineApplication.h" + +using namespace std; + +namespace Isis { + class Filename; + +/** + * This class is designed to do most of the work in the "proc" programs, such as + * thmproc and mocproc. This object works by setting the initial input, final + * output, and every program in between. It is suggested that you "cout" this + * object in order to debug you're usage of the class. + * + * Here's an example usage of this class: + * @code + * UserInterface &ui = Application::GetUserInterface(); + * Pipeline p("YourAppName"); + * + * p.SetInputFile("FROM", "BANDS"); + * p.SetOutputFile("TO"); + * + * p.KeepTemporaryFiles(!ui.GetBoolean("REMOVE")); + * + * p.AddToPipeline("mission2isis"); + * p.Application("mission2isis").SetInputParameter("FROM", false); + * p.Application("mission2isis").SetOutputParameter("TO", "raw"); + + * p.AddToPipeline("spiceinit"); + * p.Application("spiceinit").SetInputParameter("FROM", false); + * p.Application("spiceinit").AddParameter("PCK", "PCK"); + * p.Application("spiceinit").AddParameter("CK", "CK"); + * + * p.AddToPipeline("cam2map"); + * p.Application("cam2map").SetInputParameter("FROM", true); + * p.Application("cam2map").SetOutputParameter("TO", "lev2"); + * p.Application("cam2map").AddParameter("MAP", "MAP"); + * p.Application("cam2map").AddParameter("PIXRES", "RESOLUTION"); + + * if(ui.WasEntered("PIXRES")) { + * p.Application("cam2map").AddConstParameter("PIXRES", "MPP"); + * } + + * if(ui.GetBoolean("INGESTION")) { + * p.SetFirstApplication("mission2isis"); + * } + * else{ + * p.SetFirstApplication("spiceinit"); + * } + + * if(ui.GetBoolean("MAPPING")) { + * p.SetLastApplication("cam2map"); + * } + * else { + * p.SetLastApplication("spiceinit"); + * } + * + * p.Run(); + * + * @endcode + * + * @author 2008-08-04 Steven Lambright + * + * @internal + * @history 2008-09-25 Added features: Application identifiers other than the + * application names, branched original input, branching from + * branches, partial branch merging (discontinuing branches*) + * @history 2008-10-28 The input no longer has to have virtual bands if the + * SetInputFile(iString,iString) has an empty parameter name for the + * virtual bands parameter. SetInputListFile(...) method added. + * @history 2008-12-19 List files are now fully supported, along with output + * list files. + */ + class Pipeline { + public: + Pipeline(const iString &procAppName = ""); + ~Pipeline(); + + void Prepare(); + void Run(); + + void SetInputFile(const iString &inputParam); + void SetInputFile(const iString &inputParam, const iString &virtualBandsParam); + void SetInputListFile(const iString &inputParam); + void SetInputFile(const Filename &inputFilename); + void SetInputListFile(const Filename &inputFilename); + + void SetOutputFile(const iString &outputParam); + void SetOutputFile(const Filename &outputFile); + void SetOutputListFile(const iString &outputFilenameParam); + void SetOutputListFile(const Filename &outputFilenameList); + void KeepTemporaryFiles(bool keep); + //! Returns true if temporary files will not be deleted, false if they will + bool KeepTemporaryFiles() { return p_keepTemporary; } + + void AddToPipeline(const iString &appname); + void AddToPipeline(const iString &appname, const iString &identifier); + PipelineApplication &Application(const iString &identifier); + PipelineApplication &Application(const int &index); + + void SetFirstApplication(const iString &appname); + void SetLastApplication(const iString &appname); + + friend ostream &operator<<(ostream &os, Pipeline &pipeline); + + //! Returns the name of the pipeline + iString Name() const { return p_procAppName; } + //! Returns the number of applications in the pipeline + int Size() const { return (int)p_apps.size(); } + + /** + * Returns the initial input file for the pipeline + * + * @param branch Branch of the original input to get the filename from + * + * @return iString Name of the original input file + */ + iString OriginalInput(unsigned int branch) { return ((branch < p_originalInput.size())? p_originalInput[branch] : ""); } + + //! Returns the names of the original branches of the pipeline (multiple input files) + vector OriginalBranches() { return p_originalBranches; } + iString FinalOutput(int branch = 0, bool addModifiers = true); + iString TemporaryFolder(); + + void EnableAllApplications(); + + private: + iString p_procAppName; //!< The name of the pipeline + vector p_originalInput; //!< The original input file + vector p_originalBranches; //!< The original branch names + vector p_finalOutput; //!< The final output file (empty if needs calculated) + vector p_virtualBands; //!< The virtual bands string + bool p_keepTemporary; //!< True if keeping temporary files + bool p_addedCubeatt; //!< True if the "cubeatt" program was added + vector< PipelineApplication * > p_apps; //!< The pipeline applications + vector< iString > p_appIdentifiers; //!< The strings to identify the pipeline applications + bool p_outputListNeedsModifiers; + }; +}; + +#endif diff --git a/isis/src/base/objs/Pipeline/Pipeline.truth b/isis/src/base/objs/Pipeline/Pipeline.truth new file mode 100644 index 0000000000000000000000000000000000000000..2ba3a38472a6dc9f5c04eda86a58da358e613cd1 --- /dev/null +++ b/isis/src/base/objs/Pipeline/Pipeline.truth @@ -0,0 +1,439 @@ +Simple Pipe +PIPELINE -------> unitTest2 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="/work1/out.cub" +PIPELINE -------> unitTest2 <------- PIPELINE + +PIPELINE -------> unitTest2 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="/work1/out.cub" +spiceinit FROM="/work1/out.cub" SHAPE="ELLIPSOID" +PIPELINE -------> unitTest2 <------- PIPELINE + +PIPELINE -------> unitTest2 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.cub" SHAPE="ELLIPSOID" +cam2map FROM="./out.lev1.cub" TO="/work1/out.cub" +rm ./out.lev1.cub +PIPELINE -------> unitTest2 <------- PIPELINE + +PIPELINE -------> unitTest2 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.cub" SHAPE="ELLIPSOID" +cam2map FROM="./out.lev1.cub" TO="/work1/out.cub" +rm ./out.lev1.cub +PIPELINE -------> unitTest2 <------- PIPELINE + +PIPELINE -------> unitTest2 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.cub" SHAPE="ELLIPSOID" +cam2map FROM="./out.lev1.cub" TO="/work1/out.cub" +rm ./out.lev1.cub +PIPELINE -------> unitTest2 <------- PIPELINE + +PIPELINE -------> unitTest2 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.cub" SHAPE="ELLIPSOID" +cam2map FROM="./out.lev1.cub" TO="/work1/out.cub" +rm ./out.lev1.cub +PIPELINE -------> unitTest2 <------- PIPELINE + +Simple Pipe 2 +PIPELINE -------> unitTest2 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +cubeatt FROM="./out.lev1.cub+2,4-5" TO="/work1/out.cub" +rm ./out.lev1.cub +PIPELINE -------> unitTest2 <------- PIPELINE + +PIPELINE -------> unitTest2 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.cub" SHAPE="ELLIPSOID" +cubeatt FROM="./out.lev1.cub+2,4-5" TO="/work1/out.cub" +rm ./out.lev1.cub +PIPELINE -------> unitTest2 <------- PIPELINE + +PIPELINE -------> unitTest2 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.cub" SHAPE="ELLIPSOID" +cam2map FROM="./out.lev1.cub+2,4-5" TO="/work1/out.cub" +rm ./out.lev1.cub +PIPELINE -------> unitTest2 <------- PIPELINE + +PIPELINE -------> unitTest2 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.cub" SHAPE="ELLIPSOID" +cam2map FROM="./out.lev1.cub+2,4-5" TO="/work1/out.cub" +rm ./out.lev1.cub +PIPELINE -------> unitTest2 <------- PIPELINE + +PIPELINE -------> unitTest2 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.cub" SHAPE="ELLIPSOID" +cam2map FROM="./out.lev1.cub+2,4-5" TO="/work1/out.cub" +rm ./out.lev1.cub +PIPELINE -------> unitTest2 <------- PIPELINE + +PIPELINE -------> unitTest2 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.cub" SHAPE="ELLIPSOID" +cubeatt FROM="./out.lev1.cub+2,4-5" TO="/work1/out.cub" +rm ./out.lev1.cub +PIPELINE -------> unitTest2 <------- PIPELINE + +Non-Merging Branching Pipe +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +cubeatt FROM="./out.lev1.even.cub+2,4-5" TO="/work1/out.even.cub" +cubeatt FROM="./out.lev1.odd.cub+2,4-5" TO="/work1/out.odd.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +cubeatt FROM="./out.lev1.even.cub+2,4-5" TO="/work1/out.even.cub" +cubeatt FROM="./out.lev1.odd.cub+2,4-5" TO="/work1/out.odd.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="/work1/out.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="/work1/out.odd.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="./out.flat.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="./out.flat.odd.cub" +thmvistrim FROM="./out.flat.even.cub" TO="/work1/out.even.cub" +thmvistrim FROM="./out.flat.odd.cub" TO="/work1/out.odd.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +rm ./out.flat.even.cub +rm ./out.flat.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="./out.flat.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="./out.flat.odd.cub" +thmvistrim FROM="./out.flat.even.cub" TO="./out.cal.even.cub" +thmvistrim FROM="./out.flat.odd.cub" TO="./out.cal.odd.cub" +cam2map FROM="./out.cal.even.cub" TO="/work1/out.even.cub" +cam2map FROM="./out.cal.odd.cub" TO="/work1/out.odd.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +rm ./out.flat.even.cub +rm ./out.flat.odd.cub +rm ./out.cal.even.cub +rm ./out.cal.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="./out.flat.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="./out.flat.odd.cub" +thmvistrim FROM="./out.flat.even.cub" TO="./out.cal.even.cub" +thmvistrim FROM="./out.flat.odd.cub" TO="./out.cal.odd.cub" +cam2map FROM="./out.cal.even.cub" TO="/work1/out.even.cub" +cam2map FROM="./out.cal.odd.cub" TO="/work1/out.odd.cub" MAP="/work1/out.even.cub" PIXRES="MAP" DEFAULTRANGE="MAP" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +rm ./out.flat.even.cub +rm ./out.flat.odd.cub +rm ./out.cal.even.cub +rm ./out.cal.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="./out.flat.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="./out.flat.odd.cub" +thmvistrim FROM="./out.flat.even.cub" TO="./out.cal.even.cub" +thmvistrim FROM="./out.flat.odd.cub" TO="./out.cal.odd.cub" +cam2map FROM="./out.cal.even.cub" TO="./out.lev2.even.cub" +cam2map FROM="./out.cal.odd.cub" TO="./out.lev2.odd.cub" MAP="./out.lev2.even.cub" PIXRES="MAP" DEFAULTRANGE="MAP" +echo ./out.lev2.even.cub ./out.lev2.odd.cub > ./out.lis +automos FROMLIST="./out.lis" TO="/work1/out.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +rm ./out.flat.even.cub +rm ./out.flat.odd.cub +rm ./out.cal.even.cub +rm ./out.cal.odd.cub +rm ./out.lev2.even.cub +rm ./out.lev2.odd.cub +rm ./out.lis +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="./out.flat.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="./out.flat.odd.cub" +thmvistrim FROM="./out.flat.even.cub" TO="./out.cal.even.cub" +thmvistrim FROM="./out.flat.odd.cub" TO="./out.cal.odd.cub" +cam2map FROM="./out.cal.even.cub" TO="./out.lev2.even.cub" +cam2map FROM="./out.cal.odd.cub" TO="./out.lev2.odd.cub" MAP="./out.lev2.even.cub" PIXRES="MAP" DEFAULTRANGE="MAP" +echo ./out.lev2.even.cub ./out.lev2.odd.cub > ./out.lis +automos FROMLIST="./out.lis" TO="/work1/out.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +rm ./out.flat.even.cub +rm ./out.flat.odd.cub +rm ./out.cal.even.cub +rm ./out.cal.odd.cub +rm ./out.lev2.even.cub +rm ./out.lev2.odd.cub +rm ./out.lis +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="./out.flat.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="./out.flat.odd.cub" +thmvistrim FROM="./out.flat.even.cub" TO="./out.cal.even.cub" +thmvistrim FROM="./out.flat.odd.cub" TO="./out.cal.odd.cub" +cam2map FROM="./out.cal.even.cub" TO="./out.lev2.even.cub" +cam2map FROM="./out.cal.odd.cub" TO="./out.lev2.odd.cub" MAP="./out.lev2.even.cub" PIXRES="MAP" DEFAULTRANGE="MAP" +echo ./out.lev2.even.cub ./out.lev2.odd.cub > ./out.lis +automos FROMLIST="./out.lis" TO="/work1/out.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +rm ./out.flat.even.cub +rm ./out.flat.odd.cub +rm ./out.cal.even.cub +rm ./out.cal.odd.cub +rm ./out.lev2.even.cub +rm ./out.lev2.odd.cub +rm ./out.lis +PIPELINE -------> unitTest1 <------- PIPELINE + +Standard Branching Pipe +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +cubeatt FROM="./out.lev1.even.cub+2,4-5" TO="/work1/out.even.cub" +cubeatt FROM="./out.lev1.odd.cub+2,4-5" TO="/work1/out.odd.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +cubeatt FROM="./out.lev1.even.cub+2,4-5" TO="/work1/out.even.cub" +cubeatt FROM="./out.lev1.odd.cub+2,4-5" TO="/work1/out.odd.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="/work1/out.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="/work1/out.odd.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="./out.flat.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="./out.flat.odd.cub" +thmvistrim FROM="./out.flat.even.cub" TO="/work1/out.even.cub" +thmvistrim FROM="./out.flat.odd.cub" TO="/work1/out.odd.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +rm ./out.flat.even.cub +rm ./out.flat.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="./out.flat.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="./out.flat.odd.cub" +thmvistrim FROM="./out.flat.even.cub" TO="./out.cal.even.cub" +thmvistrim FROM="./out.flat.odd.cub" TO="./out.cal.odd.cub" +cam2map FROM="./out.cal.even.cub" TO="/work1/out.even.cub" +cam2map FROM="./out.cal.odd.cub" TO="/work1/out.odd.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +rm ./out.flat.even.cub +rm ./out.flat.odd.cub +rm ./out.cal.even.cub +rm ./out.cal.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="./out.flat.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="./out.flat.odd.cub" +thmvistrim FROM="./out.flat.even.cub" TO="./out.cal.even.cub" +thmvistrim FROM="./out.flat.odd.cub" TO="./out.cal.odd.cub" +cam2map FROM="./out.cal.even.cub" TO="/work1/out.even.cub" +cam2map FROM="./out.cal.odd.cub" TO="/work1/out.odd.cub" MAP="/work1/out.even.cub" PIXRES="MAP" DEFAULTRANGE="MAP" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +rm ./out.flat.even.cub +rm ./out.flat.odd.cub +rm ./out.cal.even.cub +rm ./out.cal.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="./out.flat.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="./out.flat.odd.cub" +thmvistrim FROM="./out.flat.even.cub" TO="./out.cal.even.cub" +thmvistrim FROM="./out.flat.odd.cub" TO="./out.cal.odd.cub" +cam2map FROM="./out.cal.even.cub" TO="./out.lev2.even.cub" +cam2map FROM="./out.cal.odd.cub" TO="./out.lev2.odd.cub" MAP="./out.lev2.even.cub" PIXRES="MAP" DEFAULTRANGE="MAP" +echo ./out.lev2.even.cub ./out.lev2.odd.cub > ./out.lis +automos FROMLIST="./out.lis" TO="/work1/out.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +rm ./out.flat.even.cub +rm ./out.flat.odd.cub +rm ./out.cal.even.cub +rm ./out.cal.odd.cub +rm ./out.lev2.even.cub +rm ./out.lev2.odd.cub +rm ./out.lis +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="./out.flat.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="./out.flat.odd.cub" +thmvistrim FROM="./out.flat.even.cub" TO="./out.cal.even.cub" +thmvistrim FROM="./out.flat.odd.cub" TO="./out.cal.odd.cub" +cam2map FROM="./out.cal.even.cub" TO="./out.lev2.even.cub" +cam2map FROM="./out.cal.odd.cub" TO="./out.lev2.odd.cub" MAP="./out.lev2.even.cub" PIXRES="MAP" DEFAULTRANGE="MAP" +echo ./out.lev2.even.cub ./out.lev2.odd.cub > ./out.lis +automos FROMLIST="./out.lis" TO="/work1/out.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +rm ./out.flat.even.cub +rm ./out.flat.odd.cub +rm ./out.cal.even.cub +rm ./out.cal.odd.cub +rm ./out.lev2.even.cub +rm ./out.lev2.odd.cub +rm ./out.lis +PIPELINE -------> unitTest1 <------- PIPELINE + +PIPELINE -------> unitTest1 <------- PIPELINE +thm2isis FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub" TO="./out.lev1.cub" +spiceinit FROM="./out.lev1.even.cub" SHAPE="ELLIPSOID" +spiceinit FROM="./out.lev1.odd.cub" SHAPE="ELLIPSOID" +thmvisflat FROM="./out.lev1.even.cub+2,4-5" TO="./out.flat.even.cub" +thmvisflat FROM="./out.lev1.odd.cub+2,4-5" TO="./out.flat.odd.cub" +thmvistrim FROM="./out.flat.even.cub" TO="/work1/out.even.cub" +thmvistrim FROM="./out.flat.odd.cub" TO="/work1/out.odd.cub" +rm ./out.lev1.even.cub +rm ./out.lev1.odd.cub +rm ./out.flat.even.cub +rm ./out.flat.odd.cub +PIPELINE -------> unitTest1 <------- PIPELINE + +Complicated Branching Pipe +PIPELINE -------> unitTest3 <------- PIPELINE +fft FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub+2,4-5" MAGNITUDE="/work1/out.FROM.mag.cub" MAGNITUDE="/work1/out.FROM2.mag.cub" PHASE="/work1/out.FROM2.phase.cub" PHASE="/work1/out.FROM.phase.cub" +fft FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.odd.cub+2,4-5" MAGNITUDE="/work1/out.FROM2.mag.cub" PHASE="/work1/out.FROM2.phase.cub" +PIPELINE -------> unitTest3 <------- PIPELINE + +PIPELINE -------> unitTest3 <------- PIPELINE +fft FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub+2,4-5" MAGNITUDE="./out.fft.FROM.mag.cub" MAGNITUDE="./out.fft.FROM2.mag.cub" PHASE="./out.fft.FROM2.phase.cub" PHASE="./out.fft.FROM.phase.cub" +fft FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.odd.cub+2,4-5" MAGNITUDE="./out.fft.FROM2.mag.cub" PHASE="./out.fft.FROM2.phase.cub" +echo ./out.fft.FROM.mag.cub ./out.fft.FROM2.mag.cub ./out.fft.FROM2.phase.cub ./out.fft.FROM.phase.cub > ./out.FROM.mag.lis +fx FILELIST="./out.FROM.mag.lis" TO="/work1/out.FROM.mag.cub" equation="1+2" MODE="list" +fx FILELIST="./out.FROM.mag.lis" TO="/work1/out.FROM2.phase.cub" MODE="list" equation="1+3" +rm ./out.fft.FROM.mag.cub +rm ./out.fft.FROM2.mag.cub +rm ./out.fft.FROM2.phase.cub +rm ./out.fft.FROM.phase.cub +rm ./out.FROM.mag.lis +PIPELINE -------> unitTest3 <------- PIPELINE + +PIPELINE -------> unitTest3 <------- PIPELINE +fft FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub+2,4-5" MAGNITUDE="./out.fft.FROM.mag.cub" MAGNITUDE="./out.fft.FROM2.mag.cub" PHASE="./out.fft.FROM2.phase.cub" PHASE="./out.fft.FROM.phase.cub" +fft FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.odd.cub+2,4-5" MAGNITUDE="./out.fft.FROM2.mag.cub" PHASE="./out.fft.FROM2.phase.cub" +echo ./out.fft.FROM.mag.cub ./out.fft.FROM2.mag.cub ./out.fft.FROM2.phase.cub ./out.fft.FROM.phase.cub > ./out.fx2.FROM.mag.lis +fx FILELIST="./out.fx2.FROM.mag.lis" TO="./out.fx2.FROM.mag.cub" equation="1+2" MODE="list" +fx FILELIST="./out.fx2.FROM.mag.lis" TO="./out.fx2.FROM2.phase.cub" MODE="list" equation="1+3" +ifft MAGNITUDE="./out.fx2.FROM.mag.cub" TO="/work1/out.cub" PHASE="./out.fx2.FROM2.phase.cub" +rm ./out.fft.FROM.mag.cub +rm ./out.fft.FROM2.mag.cub +rm ./out.fft.FROM2.phase.cub +rm ./out.fft.FROM.phase.cub +rm ./out.fx2.FROM.mag.cub +rm ./out.fx2.FROM2.phase.cub +rm ./out.fx2.FROM.mag.lis +PIPELINE -------> unitTest3 <------- PIPELINE + +PIPELINE -------> unitTest3 <------- PIPELINE +fft FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub+2,4-5" MAGNITUDE="./out.fft.FROM.mag.cub" MAGNITUDE="./out.fft.FROM2.mag.cub" PHASE="./out.fft.FROM2.phase.cub" PHASE="./out.fft.FROM.phase.cub" +fft FROM="$ISIS3DATA/odyssey/testData/I00831002RDR.odd.cub+2,4-5" MAGNITUDE="./out.fft.FROM2.mag.cub" PHASE="./out.fft.FROM2.phase.cub" +echo ./out.fft.FROM.mag.cub ./out.fft.FROM2.mag.cub ./out.fft.FROM2.phase.cub ./out.fft.FROM.phase.cub > ./out.fx2.FROM.mag.lis +fx FILELIST="./out.fx2.FROM.mag.lis" TO="./out.fx2.FROM.mag.cub" equation="1+2" MODE="list" +fx FILELIST="./out.fx2.FROM.mag.lis" TO="./out.fx2.FROM2.phase.cub" MODE="list" equation="1+3" +ifft MAGNITUDE="./out.fx2.FROM.mag.cub" TO="./out.untranslated.cub" PHASE="./out.fx2.FROM2.phase.cub" +translate FROM="./out.untranslated.cub" TO="/work1/out.cub" STRANS="-1" LTRANS="-1" INTERP="near" +rm ./out.fft.FROM.mag.cub +rm ./out.fft.FROM2.mag.cub +rm ./out.fft.FROM2.phase.cub +rm ./out.fft.FROM.phase.cub +rm ./out.fx2.FROM.mag.cub +rm ./out.fx2.FROM2.phase.cub +rm ./out.fx2.FROM.mag.lis +rm ./out.untranslated.cub +PIPELINE -------> unitTest3 <------- PIPELINE + +Testing listing methods +PIPELINE -------> unitTest4 <------- PIPELINE +cubeatt FROM="fileA" TO="./fileA.jitter.copy.FROM1.cub" +cubeatt FROM="fileB" TO="./fileB.jitter.copy.FROM2.cub" +cubeatt FROM="fileC" TO="./fileC.jitter.copy.FROM3.cub" +spiceinit FROM="./fileA.jitter.copy.FROM1.cub" ATTACH="NO" +spiceinit FROM="./fileB.jitter.copy.FROM2.cub" ATTACH="NO" +spiceinit FROM="./fileC.jitter.copy.FROM3.cub" ATTACH="NO" +echo ./fileA.jitter.copy.FROM1.cub ./fileB.jitter.copy.FROM2.cub ./fileC.jitter.copy.FROM3.cub > ./appjit.lis +appjit FROMLIST="./appjit.lis" MASTER="MASTER.cub" DEGREE="1" +noproj FROM="./fileA.jitter.copy.FROM1.cub" TO="./fileA.jitter.cub" MATCH="MATCH.cub" +noproj FROM="./fileB.jitter.copy.FROM2.cub" TO="./fileB.jitter.cub" MATCH="MATCH.cub" +noproj FROM="./fileC.jitter.copy.FROM3.cub" TO="./fileC.jitter.cub" MATCH="MATCH.cub" +rm ./fileA.jitter.copy.FROM1.cub +rm ./fileB.jitter.copy.FROM2.cub +rm ./fileC.jitter.copy.FROM3.cub +rm ./appjit.lis +PIPELINE -------> unitTest4 <------- PIPELINE + diff --git a/isis/src/base/objs/Pipeline/PipelineApplication.cpp b/isis/src/base/objs/Pipeline/PipelineApplication.cpp new file mode 100644 index 0000000000000000000000000000000000000000..798a02574dd28c3bfc478cce4c644abfd3f266b2 --- /dev/null +++ b/isis/src/base/objs/Pipeline/PipelineApplication.cpp @@ -0,0 +1,785 @@ +#include + +#include "PipelineApplication.h" +#include "Pipeline.h" +#include "iException.h" +#include "Application.h" + +using namespace Isis; +using namespace std; + +namespace Isis { + /** + * Constructs the first pipeline application. + * + * @param appName The name of this application + * @param pipe The pipeline + */ + PipelineApplication::PipelineApplication(iString appName, Pipeline *pipe) { + p_name = appName; + p_enabled = true; + p_previous = NULL; + p_next = NULL; + p_pipeline = pipe; + + if(p_pipeline->OriginalBranches().size() == 1) { + p_inBranches.push_back(""); + p_outBranches.push_back(""); + } + else { + p_inBranches = p_pipeline->OriginalBranches(); + p_outBranches = p_pipeline->OriginalBranches(); + } + }; + + + /** + * Constructs subsequent pipeline applications + * + * @param appName The name of this application + * @param previous The previously last pipeline application + */ + PipelineApplication::PipelineApplication(iString appName, PipelineApplication *previous) { + p_name = appName; + p_enabled = true; + p_previous = previous; + p_next = NULL; + p_pipeline = p_previous->GetPipeline(); + + p_inBranches = p_previous->OutputBranches(); + p_outBranches = p_previous->OutputBranches(); + p_previous->SetNext(this); + } + + + /** + * Set the input parameter for this application and whether or not this + * application supports the virtual bands functionality. It supports the virtual + * bands functionality if the input is an Isis 3 cube. + * + * @param inputParamName Name of the input parameter, typically "FROM" + * @param supportsVirtualBands True if this application supports virtual bands + */ + void PipelineApplication::SetInputParameter(const iString &inputParamName, bool supportsVirtualBands) { + p_input.clear(); + p_input.push_back(PipelineParameter(inputParamName)); + p_supportsVirtualBands = supportsVirtualBands; + } + + + /** + * Set the input parameter for this application and whether or not this + * application supports the virtual bands functionality. It supports the virtual + * bands functionality if the input is an Isis 3 cube. + * + * @param inputParamName Name of the input parameter, typically "FROM" + * @param value Custom parameter value; Recommended to use an alternate + * SetInputParameter instead of specifying LastOutput + * @param supportsVirtualBands True if this application supports virtual bands + */ + void PipelineApplication::SetInputParameter(const iString &inputParamName, CustomParameterValue value, bool supportsVirtualBands) { + if(value == LastAppOutputList) { + // Merge + p_outBranches.clear(); + p_outBranches.push_back(""); + } + else if(value == LastAppOutputListNoMerge) { + // No merge + value = LastAppOutputList; + } + + p_input.push_back(PipelineParameter(inputParamName, value)); + p_supportsVirtualBands = supportsVirtualBands; + } + + + /** + * Set the output parameter for a branch of this application and it's naming + * convention. This is meant for an application that splits the input into two + * output files via two output parameters. + * + * @param branch Branch this output parameter applies to + * @param outputParamName Name of the output parameter + * @param outNameModifier Modifier to add to the cube name, such as "lev1" + * @param outFileExtension Extension of the output file (usually "cub" for cube) + */ + void PipelineApplication::SetOutputParameter(const iString &branch, const iString &outputParamName, + const iString &outNameModifier, const iString &outFileExtension) { + p_output.push_back(PipelineParameter(FindBranch(branch, false), outputParamName)); + p_outputMod = outNameModifier; + p_outputExtension = outFileExtension; + } + + + /** + * Set the output parameter for this application and it's naming convention. + * + * @param outputParamName Name of the output parameter + * @param outNameModifier Modifier to add to the cube name, such as "lev1" + * @param outFileExtension Extension of the output file (usually "cub" for cube) + */ + void PipelineApplication::SetOutputParameter(const iString &outputParamName, const iString &outNameModifier, const iString &outFileExtension) { + p_output.clear(); + p_output.push_back(PipelineParameter(outputParamName)); + p_outputMod = outNameModifier; + p_outputExtension = outFileExtension; + } + + + /** + * This method adds branch to this program. A branch means with one input, + * multiple outputs are automatically created. + * + * Example: + * @code + * thm2isis from=input.img to=output.cub + * @endcode + * + * In this code, thm2isis could actually create output.even.cub and + * output.odd.cub. The branches are then "even" and "odd". This is used only for + * the case where the program outputs multiple images based upon one "TO" + * parameter. + * + * @param modString Branch name + * @param type Modifier type; currently only supports constant strings + */ + void PipelineApplication::AddBranch(const iString &modString, NameModifierType type) { + if(modString == "") { + string msg = "Can not add empty branch to pipeline"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + //if(p_inBranches.size() != 1 || p_inBranches[0] != "") { + // string msg = "Can not branch an already branched pipeline"; + // throw iException::Message(iException::Programmer, msg, _FILEINFO_); + //} + + if(p_outBranches[0] == "") p_outBranches.clear(); + + if(p_inBranches.size() == 1) { + p_outBranches.push_back(modString); + } + else if(p_inBranches.size() == p_outBranches.size()) { + for(int outBranch = p_outBranches.size()-1; outBranch >= 0; outBranch --) { + if(p_inBranches[outBranch] == p_outBranches[outBranch]) { + p_outBranches[outBranch] = p_inBranches[outBranch] + "." + modString; + } + else { + p_outBranches.push_back(p_inBranches[outBranch] + "." + modString); + } + } + } + else { + for(unsigned int inBranch = 0; inBranch < p_inBranches.size(); inBranch ++) { + p_outBranches.push_back(p_inBranches[inBranch] + "." + modString); + } + } + } + + + /** + * This method adds knowledge of a parameter to the application. The + * parameter value is taken directly from the user interface. + * + * @param inputParamName Parameter in the proc program + * @param appParamName Parameter in this application + */ + void PipelineApplication::AddParameter(const iString &inputParamName, const iString &appParamName) { + UserInterface &ui = Application::GetUserInterface(); + + if(ui.WasEntered(inputParamName)) { + p_params.push_back(PipelineParameter(appParamName, ui.GetAsString(inputParamName))); + } + } + + + /** + * This method adds knowledge of a parameter to this application, that will only + * affect the specified branch. The parameter value is taken directly from the + * user interface; internal defaults are supported by not using the parameter. + * + * @param branch The branch this parameter affects + * @param inputParamName Parameter in the proc program + * @param appParamName Parameter in the this application + */ + void PipelineApplication::AddParameter(const iString &branch, const iString &inputParamName, const iString &appParamName) { + UserInterface &ui = Application::GetUserInterface(); + + if(ui.WasEntered(inputParamName)) { + p_params.push_back(PipelineParameter(FindBranch(branch, false), appParamName, ui.GetAsString(inputParamName))); + } + } + + + /** + * This method adds a parameter to this application with a known value (does not + * get it from the user interface, must be specified). + * + * @param appParamName Name of the parameter + * @param appParamValue Value of the parameter + */ + void PipelineApplication::AddConstParameter(const iString &appParamName, const iString &appParamValue) { + bool added = false; + + for(unsigned int i = 0; !added && i < p_params.size(); i++) { + if(p_params[i].Name() == appParamName) { + p_params[i] = PipelineParameter(appParamName, appParamValue); + added = true; + } + } + + if(!added) { + p_params.push_back(PipelineParameter(appParamName, appParamValue)); + added = true; + } + } + + + /** + * This method adds a parameter to this application with a known value (does not + * get it from the user interface, must be specified) that only affects a single + * branch. + * + * @param branch Branch this parameter affects + * @param appParamName Name of the parameter + * @param appParamValue Value of the parameter + */ + void PipelineApplication::AddConstParameter(const iString &branch, const iString &appParamName, const iString &appParamValue) { + p_params.push_back(PipelineParameter(FindBranch(branch, false), appParamName, appParamValue)); + } + + + /** + * This method adds a parameter with a calculated value (special) to this + * application. + * + * @param appParamName Parameter name + * @param value Value type + */ + void PipelineApplication::AddParameter(const iString &appParamName, CustomParameterValue value) { + p_params.push_back(PipelineParameter(appParamName, value)); + } + + + /** + * This method adds a parameter with a calculated value (special) to this + * application that only affects the specified branch + * + * @param branch Branch this parameter affects + * @param appParamName Parameter name + * @param value Value type + */ + void PipelineApplication::AddParameter(const iString &branch, const iString &appParamName, CustomParameterValue value) { + p_params.push_back(PipelineParameter(FindBranch(branch, false), appParamName, value)); + } + + + /** + * This method calculates the inputs, outputs and necessary calls to this + * program for the pipeline. This should only be used by Pipeline. + * + */ + void PipelineApplication::BuildParamString() { + p_paramString.clear(); + p_outputs.clear(); + p_tempFiles.clear(); + + if(!Enabled()) return; + + // These are used if the pipeline needs a list file; must be out here in case multiple branches use + // the list file. + bool needList = false; + iString listFile; + + bool runOnce = Merges() && !Branches(); + + // Make sure we have different inputs for different runs... + if(!runOnce && p_input.size() == 1) { + PipelineParameter &inputParam = p_input[0]; + if(inputParam.IsSpecial() && inputParam.Special() == LastAppOutputList) { + runOnce = true; + + for(int param = 0; param < (int)p_params.size() && runOnce; param++) { + runOnce = (p_params[param].IsSpecial() && p_params[param].Special() == LastAppOutputList) || + (!p_params[param].IsSpecial() && p_params[param].AffectsAllBranches()); + } + } + } + + // We need to build execute calls for all of the branches + for(int branch = 0; branch < (int)p_inBranches.size(); branch ++) { + if(runOnce && branch > 0) { + return; + } + + // Figure out the input file; could throw an exception if the user didnt set it + iString inputFile = CalculateInputFile(branch); + // Figure out the output file; This adds the output to the output list* + iString outputFile = CalculateOutputFile(branch); + // This parameter gives us more detail about the input parameter + PipelineParameter &inputParam = GetInputParameter(branch); + + string params = ""; + + // If we havent needed a list yet, let's see if we need one now + if(!needList) { + // We need to know if we need a list file ahead of time; look at input and parameters + needList = (inputParam.IsSpecial() && inputParam.Special() == LastAppOutputList); + + for(int param = 0; param < (int)p_params.size() && !needList; param++) { + needList = (p_params[param].IsSpecial() && p_params[param].Special() == LastAppOutputList); + } + + // If we need a list file, create a parameter that starts with ">>LIST" to say it's a list file. + // The first element is the list file, the rest is the contents of the list file. + if(needList) { + iString listName = outputFile; + + if(listName.empty()) { + // This might have to become more robust in the future, we + // have an input list but no outputs to the program for + // this case. This is the naming of the list. + listName = Name(); + } + + iString input = p_pipeline->TemporaryFolder() + "/" + Filename(listName).Basename() + ".lis"; + params = ">>LIST " + input + " "; + + for(int i = 0; i < (int)Previous()->GetOutputs().size(); i++) { + params += " " + Previous()->GetOutputs()[i]; + } + + p_tempFiles.push_back(input); + p_paramString.push_back(params); + params = ""; + listFile = input; + } + } + + // If the input is a list file, set it to the list file + if(inputParam.IsSpecial() && inputParam.Special() == LastAppOutputList) { + params = GetInputParameter(branch).Name() + "=\"" + listFile + "\""; + } + else { + // Otherwise it's the input file. Try to add virtual bands. + // Pipeline will set p_virtualBands to an empty string if we are to not apply it. + params = GetInputParameter(branch).Name() + "=\"" + inputFile; + if(p_virtualBands.size() == 1) { + params += "+" + p_virtualBands[0]; + } + else if(p_virtualBands.size() == p_inBranches.size() && !p_virtualBands[branch].empty()) { + params += "+" + p_virtualBands[branch]; + } + + params += "\""; + } + + // If we have output, add it on to our parameters + if(p_output.size() != 0) { + if(Branches() && p_output.size() != 1) { + // Set output variable for every branch + for(unsigned int outBranch = 0; outBranch < p_outBranches.size(); outBranch ++) { + // Each branch should have at least 1 output file + bool outputSet = false; + + // ... unless there is a split, look for the split (check name start) + if(p_inBranches.size() > 1) { + if(!StringStartsWith(p_outBranches[outBranch], p_inBranches[branch])) { + continue; + } + } + + // Match the output variable with it's param name + for(unsigned int outParam = 0; outParam < p_output.size(); outParam++) { + if(p_output[outParam].AppliesToBranch(outBranch)) { + params += " " + p_output[outParam].Name() + "=\"" + p_outputs[outBranch] + "\""; + + if(outputSet) { + iString message = "Application [" + Name() + "] in the pipeline branches with an "; + message += "output parameter for each branch, but branch [" + p_outBranches[outBranch]; + message += "] has multiple output files specified."; + throw iException::Message(iException::Programmer, message, _FILEINFO_); + } + + outputSet = true; + } + } + + if(!outputSet) { + iString message = "Application [" + Name() + "] in the pipeline branches with an "; + message += "output parameter for each branch, but branch [" + p_outBranches[outBranch]; + message += "] has no output files specified."; + throw iException::Message(iException::Programmer, message, _FILEINFO_); + } + } + } + else { + bool foundBranch = false; + + // Find the output parameter name that is acceptable. If we cant find an output branch, then there isnt one! + for(unsigned int outputParam = 0; outputParam < p_output.size(); outputParam++) { + if(p_output[outputParam].AppliesToBranch(branch)) { + params += " " + p_output[0].Name() + "=\"" + outputFile + "\""; + foundBranch = true; + } + } + + if(!foundBranch) continue; + } + } + + // Add the remaining parameters + for(int i = 0; i < (int)p_params.size() && i < (int)p_params.size(); i++) { + if(p_params[i].AppliesToBranch(branch)) { + if(!p_params[i].IsSpecial()) { + params += " " + p_params[i].Name() + "=\"" + p_params[i].Value() + "\""; + } + else if(p_params[i].Special() == LastOutput) { + params += " " + p_params[i].Name() + "=\"" + GetRealLastOutput(true) + "\""; + } + else if(p_params[i].Special() == LastAppOutputList) { + params += " " + p_params[i].Name() + "=\"" + listFile + "\""; + } + } + } + + if(inputFile.empty()) { + iString message = "There was a problem with calculating the inputs for program [" + Name(); + message += "]. Please verify your program is not setting outputs for branches that "; + message += "don't have input."; + throw iException::Message(iException::Programmer, message, _FILEINFO_); + } + + // Remember this parameter string + p_paramString.push_back(params); + } + } + + + /** + * This method calculates the input file for the specified branch. + * + * @param branch Branch this input file affects + * + * @return iString Input filename + */ + iString PipelineApplication::CalculateInputFile(int branch) { + iString file = ""; + + if(Previous() != NULL) { + // The last app exists, look for output on this branch + if(branch < (int)Previous()->GetOutputs().size()) { + file = Previous()->GetOutputs()[branch]; + } + } + + // We're either the first program, or nothing has generated output yet. + if(file.empty()) { + file = p_pipeline->OriginalInput(branch); + } + + // deal with special cases + for(int i = 0; i < (int)p_input.size(); i++) { + if(p_input[i].AppliesToBranch(branch) && p_input[i].IsSpecial()) { + if(p_input[i].Special() == LastOutput) { + return GetRealLastOutput(); + } + } + } + + return file; + } + + + /** + * This method calculates the output file for the specified branch + * + * @param branch Branch this output file is for + * + * @return iString The output file + */ + iString PipelineApplication::CalculateOutputFile(int branch) { + iString outputFile; + iString outFolder = p_pipeline->TemporaryFolder(); + + // We need to know this to know if we actually need to add modifiers to the + // output name + bool usedBranch = false; + unsigned int usedBranchIndex = 0; + unsigned int numUsedBranches = 0; + + for(unsigned int outputBranch = 0; outputBranch < p_outBranches.size(); outputBranch++) { + bool outBranchUsed = false; + + for(unsigned int outputParam = 0; outputParam < p_output.size(); outputParam ++) { + if(p_output[outputParam].AppliesToBranch(outputBranch)) { + outBranchUsed = true; + } + } + + if(outBranchUsed) { + if(outputBranch < (unsigned int)branch) { + usedBranchIndex ++; + } + + if((unsigned int)branch == outputBranch) { + usedBranch = true; + } + + numUsedBranches ++; + } + } + + if(!usedBranch) return ""; + + if(!LastApplicationWithOutput()) { + iString lastOutput = p_pipeline->FinalOutput(branch, false); + outputFile = outFolder + "/" + + Filename(lastOutput).Basename() + "." + p_outputMod + "." + p_outputExtension; + + if(p_outputMod.empty()) { + outputFile = outFolder + "/" + + Filename(lastOutput).Basename() + "." + p_outputExtension; + } + } + else { + outputFile = p_pipeline->FinalOutput(branch, numUsedBranches > 1); + outFolder = Filename(outputFile).Path(); + } + + if(!LastApplicationWithOutput() && numUsedBranches != 1 && !p_outputMod.empty()) { + Filename outfile(outputFile); + + iString realOut(outFolder + "/" + outfile.Basename() + "." + p_outBranches[branch] + "." + p_outputExtension); + + if(usedBranch) { + + // This assumes CalculateOutputFile is called in order (branch 0,1,2...n) + if(p_outputs.size() == usedBranchIndex) { + p_outputs.push_back(realOut); + } + + // If we're only run once, but we branch, we need to store the rest of these real output files... + // recursively call to get them stored away. Also we could be run twice, but really have 4 outputs, + // so always do this if we branch. + if(branch == 0 && Branches()) { + for(unsigned int i = 1; i < OutputBranches().size(); i++) { + CalculateOutputFile(i); + } + } + + // If branches is false, then we need to tell the truth about the output file. + // REASONING: thm2isis needs to be lied to (Branches() == true), for example, + // because it modifies output names on its own. + if(!Branches()) { + // tell the truth + outputFile = realOut; + } + } + } + else if(!p_outputMod.empty()) { + if(p_outputs.size() == usedBranchIndex) { + p_outputs.push_back(outputFile); + } + + // If we're only run once, but we branch, we need to store the rest of these real output files... + // recursively call to get them stored away. Also we could be run twice, but really have 4 outputs, + // so always do this if we branch. + if(branch == 0 && Branches()) { + for(unsigned int i = 1; i < OutputBranches().size(); i++) { + CalculateOutputFile(i); + } + } + } + + return outputFile; + } + + + /** + * Returns true if this is the last application with output + * + * + * @return bool False if another application later on creates output + */ + bool PipelineApplication::LastApplicationWithOutput() { + if(!Next() && !p_output.empty()) { + return true; + } + if(!Next() && p_output.empty()) { + return false; + } + + // If any future app creates output, then I'm not last + return !Next()->FutureOutputFileCreated(); + } + + + /** + * Returns true if a future application creates output + * + * + * @return bool Future application creates output + */ + bool PipelineApplication::FutureOutputFileCreated() { + if(!p_output.empty()) { + return true; + } + + if(!Next() && p_output.empty()) { + return false; + } + + return Next()->FutureOutputFileCreated(); + } + + + /** + * This gets the input parameter for the specified branch + * + * @param branch Branch the input parameter is for + * + * @return PipelineParameter& The input parameter + */ + PipelineParameter &PipelineApplication::GetInputParameter(int branch) { + for(int i = 0; i < (int)p_input.size(); i++) { + if(p_input[i].AppliesToBranch(branch)) { + return p_input[i]; + } + } + + if(p_inBranches[0] != "") { + string msg = "Application [" + Name() + "] in the pipeline does not have an input for branch [" + p_inBranches[branch] + "]"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + else { + string msg = "Application [" + Name() + "] in the pipeline does not have an input"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + + + /** + * The method, given a string, finds the index of a branch + * + * @param name Branch name + * @param input True if input branch, false if output branch + * + * @return int Branch index + */ + int PipelineApplication::FindBranch(iString name, bool input) { + int branchIndex = 0; + bool found = false; + + if(input) { + while(!found && branchIndex < (int)p_inBranches.size()) { + if(p_inBranches[branchIndex] == name) { + found = true; + } + else { + branchIndex ++; + } + } + } + else { + while(!found && branchIndex < (int)p_outBranches.size()) { + if(p_outBranches[branchIndex] == name) { + found = true; + } + else { + branchIndex ++; + } + } + } + + if(!found) { + string msg = "Branch [" + name + "] does not exist in the pipeline application [" + Name() + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + return branchIndex; + } + + + /** + * This method returns a list of the temporary files generated by this program + * + * + * @return vector The temporary files + */ + vector PipelineApplication::TemporaryFiles() { + vector tmp; + + if(!LastApplicationWithOutput()) { + for(int i = 0; i < (int)p_outputs.size(); i++) { + tmp.push_back(p_outputs[i]); + } + } + + for(int i = 0; i < (int)p_tempFiles.size(); i++) { + tmp.push_back(p_tempFiles[i]); + } + + return tmp; + } + + + /** + * This method is used to calculate the value for + * CustomParameterValue::LastOutput + * + * @param skipOne Skip the very last output; this is used to skip the output of + * the current run + * + * @return iString The last output file + */ + iString PipelineApplication::GetRealLastOutput(bool skipOne) { + if(!skipOne) { + return GetOutputs()[GetOutputs().size()-1]; + } + + if(p_outputs.size() > 1) { + return GetOutputs()[GetOutputs().size()-2]; + } + + return Previous()->GetOutputs()[Previous()->GetOutputs().size()-1]; + } + + + /** + * Returns true if virtual bands are supported + * + * + * @return bool Virtual bands supported + */ + bool PipelineApplication::SupportsVirtualBands() { + if(!Enabled()) return false; + return p_supportsVirtualBands; + } + + + /** + * Set the virtual bands that this application is to apply. Empty for none. + * + * @param bands The virtual bands string, excluding the "+". For example, + * "2,4-5,8" + */ + void PipelineApplication::SetVirtualBands(vector bands) { + p_virtualBands = bands; + } + + //! This returns this application's output files. Only valid after BuildParamString is called. + vector &PipelineApplication::GetOutputs() { + if(Enabled() && p_outputs.size() != 0) { + return p_outputs; + } + else if(Previous()) { + return Previous()->GetOutputs(); + } + else { + // no outputs yet... not sure if an exception should be thrown, sometimes + // things such as list files will fail when this returns nothing. + return p_outputs; + } + } +}; // end namespace Isis diff --git a/isis/src/base/objs/Pipeline/PipelineApplication.h b/isis/src/base/objs/Pipeline/PipelineApplication.h new file mode 100644 index 0000000000000000000000000000000000000000..904fd8cafa486a7c74469b99ee255eb5abc0b15a --- /dev/null +++ b/isis/src/base/objs/Pipeline/PipelineApplication.h @@ -0,0 +1,373 @@ +#ifndef PipelineApplication_h +#define PipelineApplication_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/12/19 21:13:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "iString.h" + +using namespace std; + +namespace Isis { + class Pipeline; + class PipelineParameter; + +/** + * This class represents one application in the pipeline. This contains methods + * for setting application-specific parameters, such as application inputs and + * outputs. Only pipeline should be instantiating these! + * + * The applications work as a doubly-linked list in order to calculate inputs + * and outputs correctly. Calling SetNext or SetPrevious is not recommended. + * + * + * @author 2008-08-04 Steven Lambright + * + * @internal + * @history 2008-09-25 Added features: Application identifiers other than the + * application names, branched original input, branching from + * branches, partial branch merging (discontinuing branches*) + * @history 2008-09-26 Steven Lambright Fixed introduced bug where input data + * was not being found when no previous programs in the pipeline + * generated output (needed to go back to original input). + * @history 2008-09-26 Steven Lambright Changed CalculateOutputFile(...) + * to work in more cases. Pipeline::FinalOutput is relied upon more + * heavily now to do the right thing. + */ + class PipelineApplication { + public: + PipelineApplication(iString appName, Pipeline *pipe); + PipelineApplication(iString appName, PipelineApplication *previous); + + //! This is the destructor + ~PipelineApplication() {}; + + /** + * This is used for branches. Right now, only known strings can be used to + * specify each branch. + */ + enum NameModifierType { + //! Known strings + ConstantStrings + }; + + /** + * This is used to set custom values that must be calculated on the fly + */ + enum CustomParameterValue { + //! The very last output file. Do not use this for input parameters if it's not necessary, that is done automatically + LastOutput, + //! A list of files from the last run application's output. + // Implies branches will be merged if this is set as an input parameter. + LastAppOutputList, + //! A list of files from the last run application's output. + // Implies branches will NOT be merged if this is set as an input parameter. + LastAppOutputListNoMerge + }; + + //! Get the name of this pipeline application + const iString &Name() const { return p_name; } + //! Get the parameters for running this program; one element in the vector per run + const vector &ParamString() const { return p_paramString; } + //! Get the branches this program expects as input + const vector &InputBranches() const { return p_inBranches; } + //! Get the branches this program has as output + const vector &OutputBranches() const { + if(!Enabled() && Previous()) { + return Previous()->OutputBranches(); + } + else if(Enabled()) { + return p_outBranches; + } + else { + return p_inBranches; + } + } + + //! This method enables this program to be run + void Enable() { p_enabled = true; }; + + //! This method disables this program, causing it to be ignored + void Disable() { p_enabled = false; }; + + //! Returns true if this program will be run + const bool &Enabled() const { return p_enabled; } + + void SetInputParameter(const iString &inputParamName, bool supportsVirtualBands); + void SetInputParameter(const iString &inputParamName, CustomParameterValue value, bool supportsVirtualBands); + + void SetOutputParameter(const iString &outputParamName, const iString &outNameModifier, const iString &outFileExtension = "cub"); + void SetOutputParameter(const iString &branch, const iString &outputParamName, + const iString &outNameModifier, const iString &outFileExtension); + + void AddBranch(const iString &modString, NameModifierType type); + + void AddParameter(const iString &inputParamName, const iString &appParamName); + void AddParameter(const iString &branch, const iString &inputParamName, const iString &appParamName); + + void AddConstParameter(const iString &appParamName, const iString &appParamValue); + void AddConstParameter(const iString &branch, const iString &appParamName, const iString &appParamValue); + + void AddParameter(const iString &appParamName, CustomParameterValue value); + void AddParameter(const iString &branch, const iString &appParamName, CustomParameterValue value); + + //! This returns this application's output name modifier + iString OutputNameModifier() { return (!p_outputMod.empty() || !Previous())? p_outputMod : Previous()->OutputNameModifier(); } + //! This returns this application's output file name's extension + iString OutputExtension() { return (!p_outputExtension.empty() || !Previous())? p_outputExtension : Previous()->OutputExtension(); } + + //! This returns this application's output files. Only valid after BuildParamString is called. + vector &GetOutputs(); + + vector TemporaryFiles(); + + /** + * Link to the next application in the pipeline + * + * @param next The next pipeline application + */ + void SetNext(PipelineApplication *next) { p_next = next; } + + + /** + * Link to the previous application in the pipeline + * + * @param prev The previous pipeline application + */ + void SetPrevious(PipelineApplication *prev) { p_previous = prev; } + + void BuildParamString(); + + //!This returns the next enabled pipeline application or null + PipelineApplication *Next() const { + if(p_next == NULL) return p_next; + if(!p_next->Enabled()) return p_next->Next(); + return p_next; + } + + //!This returns the last enabled pipeline application or null + PipelineApplication *Previous() const { + if(p_previous == NULL) return p_previous; + if(!p_previous->Enabled()) return p_previous->Previous(); + return p_previous; + } + + //!This returns the previous enabled pipeline application that makes output or null + PipelineApplication *PreviousOutputer() const { + if(p_previous == NULL) return p_previous; + if(!p_previous->Enabled()) return p_previous->Previous(); + if(p_previous->p_output.empty()) return p_previous->Previous(); + return p_previous; + } + + bool SupportsVirtualBands(); + void SetVirtualBands(vector bands); + + private: + bool FutureOutputFileCreated(); + bool LastApplicationWithOutput(); + //! Returns the pipeline + Pipeline *GetPipeline() { return p_pipeline; } + + //! Return true is this application does branch (one input branch, multiple output) + bool Branches() { + if(p_inBranches.size() >= p_outBranches.size()) return false; + return true; + } + + //! Returns true if this application does merge branches (multiple input branches, one output) + bool Merges() { + if(p_inBranches.size() == 1) return false; + if(p_outBranches.size() == 1) return true; + return false; + } + + /** + * String comparison helper, returns true if from starts with compare bool + * + * @param from Longer string ("abcdef") + * @param compare String to compare against ("abc") + */ + bool StringStartsWith(iString from, iString compare) { + if(compare.size() > from.size()) return false; + + for(unsigned int index = 0; index < compare.size(); index++) + if(from[index] != compare[index]) return false; + + return true; + } + + iString CalculateInputFile(int branch); + iString CalculateOutputFile(int branch); + iString GetRealLastOutput(bool skipOne = false); + PipelineParameter &GetInputParameter(int branch); + + int FindBranch(iString name, bool input = true); + + bool p_enabled; //!< This application enabled? + bool p_supportsVirtualBands; //!< This application supports virtual bands? + iString p_name; //!< Name of this application + vector p_outputs; //!< Actual output files + vector p_tempFiles; //!< Actial temporary files + vector p_paramString; //!< Built parameter strings + vector p_inBranches; //!< Input branches + vector p_outBranches; //!< Output branches + + vector p_output; //!< Output parameters + iString p_outputMod; //!< Output file name modifier + iString p_outputExtension; //!< Output file name extension + vector p_virtualBands; //!< Virtual bands string to add (empty if none) + + vector p_input; //!< Input parameters + vector p_params; //!< Regular parameters + + PipelineApplication *p_previous; //!< Previous pipeline application + PipelineApplication *p_next; //!< Next pipeline application + Pipeline *p_pipeline; //!< The pipeline + }; + + /** + * This class represents a parameter of some type for the PipelineApplication. + * This class simply helps to store multiple pieces of data and provide quick + * access to them, and should never be used outside of the PipelineApplication + * class. + * + * @author 2008-08-01 Steven Lambright + */ + class PipelineParameter { + public: + /** + * Construct the parameter with only a parameter name; affects all branches and + * is not a special value. + * + * @param paramName Parameter name + */ + PipelineParameter(iString paramName) { + p_paramName = paramName; + p_special = (PipelineApplication::CustomParameterValue)-1; + p_branch = -1; + } + + + /** + * Construct the parameter with a parameter name and value; affects all branches + * and is not special + * + * @param paramName Parameter name + * @param value Parameter value + */ + PipelineParameter(iString paramName, iString value) { + p_paramName = paramName; + p_paramValue = value; + p_special = (PipelineApplication::CustomParameterValue)-1; + p_branch = -1; + } + + + /** + * Construct the parameter with only a parameter name; affects only the + * specified branch and is not a special value. + * + * @param branch Branch this parameter affects + * @param paramName Parameter name + */ + PipelineParameter(int branch, iString paramName) { + p_branch = branch; + p_paramName = paramName; + p_special = (PipelineApplication::CustomParameterValue)-1; + } + + + /** + * Construct the parameter with a parameter name and value; affects only the + * specified branch and is not a special value. + * + * @param branch Branch this parameter affects + * @param paramName Parameter name + * @param paramValue Special parameter value + */ + PipelineParameter(int branch, iString paramName, iString paramValue) { + p_branch = branch; + p_paramValue = paramValue; + p_paramName = paramName; + p_special = (PipelineApplication::CustomParameterValue)-1; + } + + + /** + * Construct the parameter with a parameter name and special value; affects all + * branches + * + * @param paramName Parameter name + * @param special Special value + */ + PipelineParameter(iString paramName, PipelineApplication::CustomParameterValue special) { + p_paramName = paramName; + p_special = special; + p_branch = -1; + } + + + /** + * Construct the parameter with a parameter name and special value; affects only + * the specified branch + * + * @param branch Branch this parameter affects + * @param paramName Parameter name + * @param special Special parameter value + */ + PipelineParameter(int branch, iString paramName, PipelineApplication::CustomParameterValue special) { + p_paramName = paramName; + p_special = special; + p_branch = branch; + } + + + /** + * Returns whether or not the specified branch is affected. + * + * @param branch Branch to test + * + * @return bool Whether or not the specified branch is affected. + */ + bool AppliesToBranch(int branch) { return (p_branch == -1 || p_branch == branch); } + + //! Name of the parameter + iString Name() { return p_paramName; } + //! Non-special value of the parameter + iString Value() { return p_paramValue; } + //! True if the parameter value is special + bool IsSpecial() { return (p_special != (PipelineApplication::CustomParameterValue)-1); }; + //! Special value of the parameter + PipelineApplication::CustomParameterValue Special() { return p_special; } + //! True if branch-independant + bool AffectsAllBranches() { return p_branch == -1; } + + private: + int p_branch; //!< Branch this affects + iString p_paramName; //!< Parameter name + iString p_paramValue; //!< Parameter non-special value + PipelineApplication::CustomParameterValue p_special; //!< Parameter special value + }; +}; +#endif diff --git a/isis/src/base/objs/Pipeline/unitTest.cpp b/isis/src/base/objs/Pipeline/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8bab22e8b639ca21d59c3609e42f3e518f9bf81 --- /dev/null +++ b/isis/src/base/objs/Pipeline/unitTest.cpp @@ -0,0 +1,271 @@ +#include "Isis.h" +#include "Pipeline.h" +#include "UserInterface.h" + +using namespace Isis; + +void PipeBranched(); +void PipeMultiBranched(); +void PipeSimple(); +void PipeListed(); + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + ui.PutFilename("FROM", "$ISIS3DATA/odyssey/testData/I00831002RDR.even.cub"); + ui.PutFilename("FROM2", "$ISIS3DATA/odyssey/testData/I00831002RDR.odd.cub"); + ui.PutFilename("TO", "/work1/out.cub"); + ui.PutString("SHAPE", "ELLIPSOID"); + + ui.Clear("MAPPING"); + ui.PutBoolean("MAPPING", true); + std::cout << "Simple Pipe" << std::endl; + PipeSimple(); + std::cout << "Simple Pipe 2" << std::endl; + ui.Clear("MAPPING"); + ui.PutBoolean("MAPPING", false); + ui.PutString("BANDS", "2,4-5"); + PipeSimple(); + + ui.Clear("MAPPING"); + ui.PutBoolean("MAPPING", true); + std::cout << "Non-Merging Branching Pipe" << std::endl; + PipeBranched(); + std::cout << "Standard Branching Pipe" << std::endl; + ui.Clear("MAPPING"); + ui.PutBoolean("MAPPING", false); + PipeBranched(); + + std::cout << "Complicated Branching Pipe" << std::endl; + PipeMultiBranched(); + + ui.Clear("FROM"); + ui.Clear("TO"); + ui.PutFilename("FROM", "unitTest.lis"); + std::cout << "Testing listing methods" << std::endl; + PipeListed(); +} + +void PipeBranched() { + UserInterface &ui = Application::GetUserInterface(); + Pipeline p("unitTest1"); + + p.SetInputFile("FROM", "BANDS"); + p.SetOutputFile("TO"); + p.KeepTemporaryFiles(!ui.GetBoolean("REMOVE")); + + p.AddToPipeline("thm2isis"); + p.Application("thm2isis").SetInputParameter("FROM", false); + p.Application("thm2isis").SetOutputParameter("TO", "lev1"); + p.Application("thm2isis").AddBranch("even", PipelineApplication::ConstantStrings); + p.Application("thm2isis").AddBranch("odd", PipelineApplication::ConstantStrings); + + cout << p << endl; + + p.AddToPipeline("spiceinit"); + p.Application("spiceinit").SetInputParameter("FROM", false); + p.Application("spiceinit").AddParameter("PCK", "PCK"); + p.Application("spiceinit").AddParameter("CK", "CK"); + p.Application("spiceinit").AddParameter("SPK", "SPK"); + p.Application("spiceinit").AddParameter("SHAPE", "SHAPE"); + p.Application("spiceinit").AddParameter("MODEL", "MODEL"); + p.Application("spiceinit").AddParameter("CKNADIR", "CKNADIR"); + + cout << p << endl; + + p.AddToPipeline("thmvisflat"); + p.Application("thmvisflat").SetInputParameter("FROM", true); + p.Application("thmvisflat").SetOutputParameter("TO", "flat"); + + cout << p << endl; + + p.AddToPipeline("thmvistrim"); + p.Application("thmvistrim").SetInputParameter("FROM", true); + p.Application("thmvistrim").SetOutputParameter("TO", "cal"); + + if(!ui.GetBoolean("VISCLEANUP")) { + p.Application("thmvisflat").Disable(); + p.Application("thmvistrim").Disable(); + } + + cout << p << endl; + + p.AddToPipeline("cam2map"); + p.Application("cam2map").SetInputParameter("FROM", true); + p.Application("cam2map").SetOutputParameter("TO", "lev2"); + + p.Application("cam2map").AddParameter("even", "MAP", "MAP"); + p.Application("cam2map").AddParameter("even", "PIXRES", "RESOLUTION"); + + if(ui.WasEntered("PIXRES")) { + p.Application("cam2map").AddConstParameter("even", "PIXRES", "MPP"); + } + + cout << p << endl; + + p.Application("cam2map").AddParameter("odd", "MAP", PipelineApplication::LastOutput); + p.Application("cam2map").AddConstParameter("odd", "PIXRES", "MAP"); + p.Application("cam2map").AddConstParameter("odd", "DEFAULTRANGE", "MAP"); + + cout << p << endl; + + p.AddToPipeline("automos"); + p.Application("automos").SetInputParameter("FROMLIST", PipelineApplication::LastAppOutputList, false); + p.Application("automos").SetOutputParameter("TO", "mos"); + + cout << p << endl; + + if(ui.GetBoolean("INGESTION")) { + p.SetFirstApplication("thm2isis"); + } + else{ + p.SetFirstApplication("spiceinit"); + } + + cout << p << endl; + + if(ui.GetBoolean("MAPPING")) { + p.SetLastApplication("automos"); + } + else { + p.SetLastApplication("thmvistrim"); + } + + cout << p << endl; +} + +void PipeSimple() { + UserInterface &ui = Application::GetUserInterface(); + Pipeline p("unitTest2"); + + p.SetInputFile("FROM", "BANDS"); + p.SetOutputFile("TO"); + + p.KeepTemporaryFiles(!ui.GetBoolean("REMOVE")); + + p.AddToPipeline("thm2isis"); + p.Application("thm2isis").SetInputParameter("FROM", false); + p.Application("thm2isis").SetOutputParameter("TO", "lev1"); + + cout << p << endl; + + p.AddToPipeline("spiceinit"); + p.Application("spiceinit").SetInputParameter("FROM", false); + p.Application("spiceinit").AddParameter("PCK", "PCK"); + p.Application("spiceinit").AddParameter("CK", "CK"); + p.Application("spiceinit").AddParameter("SPK", "SPK"); + p.Application("spiceinit").AddParameter("SHAPE", "SHAPE"); + p.Application("spiceinit").AddParameter("MODEL", "MODEL"); + p.Application("spiceinit").AddParameter("CKNADIR", "CKNADIR"); + + cout << p << endl; + + p.AddToPipeline("cam2map"); + p.Application("cam2map").SetInputParameter("FROM", true); + p.Application("cam2map").SetOutputParameter("TO", "lev2"); + p.Application("cam2map").AddParameter("MAP", "MAP"); + p.Application("cam2map").AddParameter("PIXRES", "RESOLUTION"); + + cout << p << endl; + + if(ui.WasEntered("PIXRES")) { + p.Application("cam2map").AddConstParameter("PIXRES", "MPP"); + } + + cout << p << endl; + + if(ui.GetBoolean("INGESTION")) { + p.SetFirstApplication("thm2isis"); + } + else{ + p.SetFirstApplication("spiceinit"); + } + + cout << p << endl; + + if(ui.GetBoolean("MAPPING")) { + p.SetLastApplication("cam2map"); + } + else { + p.SetLastApplication("spiceinit"); + } + + cout << p << endl; +} + +void PipeMultiBranched() { + Pipeline p("unitTest3"); + + p.SetInputFile("FROM", "BANDS"); + p.SetInputFile("FROM2", "BANDS"); + p.SetOutputFile("TO"); + + p.KeepTemporaryFiles(false); + + p.AddToPipeline("fft"); + p.Application("fft").SetInputParameter("FROM", true); + p.Application("fft").AddBranch("mag", PipelineApplication::ConstantStrings); + p.Application("fft").AddBranch("phase", PipelineApplication::ConstantStrings); + p.Application("fft").SetOutputParameter("FROM.mag", "MAGNITUDE", "fft", "cub"); + p.Application("fft").SetOutputParameter("FROM.phase", "PHASE", "fft", "cub"); + p.Application("fft").SetOutputParameter("FROM2.mag", "MAGNITUDE", "fft", "cub"); + p.Application("fft").SetOutputParameter("FROM2.phase", "PHASE", "fft", "cub"); + + cout << p << endl; + + p.AddToPipeline("fx"); + p.Application("fx").SetInputParameter("FILELIST", PipelineApplication::LastAppOutputListNoMerge, false); + p.Application("fx").SetOutputParameter("FROM.mag", "TO", "fx2", "cub"); + p.Application("fx").SetOutputParameter("FROM2.phase", "TO", "fx2", "cub"); + p.Application("fx").AddConstParameter("FROM.mag", "equation", "1+2"); + p.Application("fx").AddConstParameter("MODE", "list"); + p.Application("fx").AddConstParameter("FROM2.phase", "equation", "1+3"); + + cout << p << endl; + + p.AddToPipeline("ifft"); + p.Application("ifft").SetInputParameter("MAGNITUDE", true); + p.Application("ifft").AddParameter("PHASE", PipelineApplication::LastOutput); + p.Application("ifft").SetOutputParameter("FROM.mag", "TO", "untranslated", "cub"); + + cout << p << endl; + + p.AddToPipeline("translate"); + p.Application("translate").SetInputParameter("FROM", true); + p.Application("translate").AddConstParameter("STRANS", "-1"); + p.Application("translate").AddConstParameter("LTRANS", "-1"); + p.Application("translate").AddConstParameter("INTERP", "near"); + p.Application("translate").SetOutputParameter("FROM.mag", "TO", "final", "cub"); + + cout << p << endl; +} + +void PipeListed() { + Pipeline p("unitTest4"); + + p.SetInputListFile("FROM"); + p.SetOutputListFile("TO"); + + p.KeepTemporaryFiles(false); + + p.AddToPipeline("cubeatt"); + p.Application("cubeatt").SetInputParameter("FROM", true); + p.Application("cubeatt").SetOutputParameter("TO", "copy"); + + p.AddToPipeline("spiceinit"); + p.Application("spiceinit").SetInputParameter("FROM", false); + p.Application("spiceinit").AddConstParameter("ATTACH", "NO"); + + p.AddToPipeline("appjit"); + p.Application("appjit").SetInputParameter("FROMLIST", PipelineApplication::LastAppOutputListNoMerge, false); + + p.Application("appjit").AddConstParameter("MASTER", "MASTER.cub"); + p.Application("appjit").AddConstParameter("DEGREE", "1"); + + p.AddToPipeline("noproj"); + p.Application("noproj").SetInputParameter("FROM", true); + p.Application("noproj").AddConstParameter("MATCH", "MATCH.cub"); + p.Application("noproj").SetOutputParameter("TO", "noproj"); + p.Application("noproj").SetOutputParameter("TO", "jitter"); + + std::cout << p << std::endl; +} diff --git a/isis/src/base/objs/Pipeline/unitTest.lis b/isis/src/base/objs/Pipeline/unitTest.lis new file mode 100644 index 0000000000000000000000000000000000000000..73b03f0ce835cf4925d836357fcbcce786e9d4c4 --- /dev/null +++ b/isis/src/base/objs/Pipeline/unitTest.lis @@ -0,0 +1,3 @@ +fileA +fileB +fileC diff --git a/isis/src/base/objs/Pipeline/unitTest.xml b/isis/src/base/objs/Pipeline/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..e8c66247b538dbd3ac3f5b90ac5003149dd19c9e --- /dev/null +++ b/isis/src/base/objs/Pipeline/unitTest.xml @@ -0,0 +1,367 @@ + + + + + + + + + + + + Original version + + + + + + + filename + input + + Input Themis PDS RDR or an ISIS Themis level 1 cube + + + Input filename. This file can be in one of two stages. A raw PDS Themis RDR or + an ISIS Level 0/1 cube. The level 0/1 cube is assumed to have been run + through thm2isis and spiceinit. + + + *.QUB *.imq *.img *.cub + + fromValue + + + + filename + input + + Input Themis PDS RDR or an ISIS Themis level 1 cube + + + Input filename. This file can be in one of two stages. A raw PDS Themis RDR or + an ISIS Level 0/1 cube. The level 0/1 cube is assumed to have been run + through thm2isis and spiceinit. + + + *.QUB *.imq *.img *.cub + + fromValue2 + + + + cube + output + Automatic + + Final output filename. + + + Output filename from the last enabled processing sequence. By + default the filename will be generated from the input filename with + ".lev#" appended to the name, where "#" is the last level of + processing (i.e., INGESTION = "lev1" or MAPPING = "lev2"). + For ThemisVIS images, if processing is stopped at the ingestion + phase, there will be an output cube for each frame in the image, + with a ".frame#" appended to the end of the filename. + + + + + string + All + + Process a subset of bands + + + This parameter allows the user to specify a sub-set of + bands to process. Enter bands separated by commas (no spaces + allowed). For example, 1,3,8 or 1-3,9 or 5 + + + + + boolean + Remove Intermediate Files + + This option allows the user to decide whether the intermediate files + created in the thmproc application are to be deleted. The default value + is TRUE. + + TRUE + + + + + + boolean + + YES + + + Import and initialize a Themis RDR file. + + + Process the input file through all level0 steps. This includes "thm2isis" and " + spiceinit". + + + PCK + CK + SPK + SHAPE + CKNADIR + + + + + boolean + + YES + + + Process the input file through the map projection phase. + + + Process the input file through level2. This includes cam2map. + + + MAP + PIXRES + + + + + + + filename + none + input + + User defined target attitude and shape kernel file. + + + Naif kernel file to be used for the target attitude and shape. + + + $BASE/kernels/pck/ + + + INGESTION + + + + + filename + none + input + + User defined spacecraft pointing kernel file. + + + Naif kernel file to be used for the spacecraft pointing. + + + $odyssey/kernels/ck/ + + + INGESTION + + + + + filename + none + input + + + User defined spacecraaft position kernel file. + + + Naif kernel file to be used for the spacecraft position. + + + $odyessy/kernels/spk/ + + + INGESTION + + + + + boolean + false + + Compute nadir pointing if no other kernels exist + + + Compute nadir pointing if no other kernels exist + + + + + string + SYSTEM + + INGESTION + + + Select the definition of the shape model + + + ISIS camera models can use a shape model (a projected ISIS cube that defines the radii for a global or regional area). You can choose + to select a shape model or to use the definition of the ellipsoid found in the planetary constants (PCK) file. + + + + + + + + + + cube + input + + User defined ISIS cube shape model. + + + A map projected ISIS cube which contains the radii of the target. The file can + cover more than the input cube (FROM) but must minimally cover the data in the input cube. + + $base//dems/ + *.cub + + + + + + filename + Sinusoidal + + File containing mapping parameters + + + A file containing the desired output mapping parameters in PVL form. This + file can be a simple hand produced label file. It can also be an existing cube + label which contains a Mapping group. + + *.map + + MAPPING + + + + + double + Pixel resolution in meters + Automatic + + Specifies the resolution in meters per pixel. + If not in the MAP file the resolution will be computed from + the themis level 1 cube. + + 0.0 + + MAPPING + + + + + + + boolean + Run thmvistrim and thmvisflat + + thmvistrim removes the overlap between framelets, which often contains both valid and + invalid data. Set this to false to preserve this data. thmvisflat applies a flat-field + correction to the data. + + true + + + + + + + + Running this program on a Themis VIS EDR + + + This program will process this themis edr from ingestion to mapping. + Since the file is a VIS file, the intermediate processes will split the + image into even and odd framelets which are recombined once mapped. + Since this file is an EDR, thmvistrim and thmvisflat will be run by + default to clean up the image. + + + from=V20018003EDR.QUB + + This runs this program with the defaults; the output is automatically + determined. + + + + + + + This is the default GUI + + + This is what the GUI looks like when running this program with + default parameters + + + + + + + + + Raw Input Data + + + This is the raw input data + + + + + + + + The projected image (final output) + + + This is the output from this program. It was cleaned up and + projected. + + + + + + + diff --git a/isis/src/base/objs/Pixel/Makefile b/isis/src/base/objs/Pixel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1656d75f0e35e20a28803f99bd16bc9d0dc9d257 --- /dev/null +++ b/isis/src/base/objs/Pixel/Makefile @@ -0,0 +1,5 @@ +INCS = Pixel.h +SRCS = Pixel.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Pixel/Pixel.cpp b/isis/src/base/objs/Pixel/Pixel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34aa07cfaf10bd7668f179e85b112fdfc2eac963 --- /dev/null +++ b/isis/src/base/objs/Pixel/Pixel.cpp @@ -0,0 +1,261 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "Pixel.h" + +using namespace std; + +namespace Isis { + /** + * Converts double pixels to unsigned char pixels with special pixel + * translations + * + * @param d Double pixel value to be converted to a double + * + * @return unsigned char The unsigned char pixel value + */ + unsigned char Pixel::To8Bit(const double d) { + if (d < VALID_MIN8) { + if (d == NULL8) return NULL1; + else if (d == LOW_INSTR_SAT8) return LOW_INSTR_SAT1; + else if (d == LOW_REPR_SAT8) return LOW_REPR_SAT1; + else if (d == HIGH_INSTR_SAT8) return HIGH_INSTR_SAT1; + else if (d == HIGH_REPR_SAT8) return HIGH_REPR_SAT1; + else return LOW_REPR_SAT1; + } + else { + if (d < VALID_MIN1 - 0.5) return LOW_REPR_SAT1; + else if (d > VALID_MAX1 + 0.5) return HIGH_REPR_SAT1; + + else { + int itemp = (int) (d + 0.5); + if (itemp < VALID_MIN1) return LOW_REPR_SAT1; + else if (itemp > VALID_MAX1) return HIGH_REPR_SAT1; + else return (unsigned char) (d + 0.5); + } + } + } + + /** + * Converts double pixels to short int pixels with special pixel translations + * + * @param d Double pixel value to be converted to a double + * + * @return short int The short int pixel value + */ + short int Pixel::To16Bit(const double d) { + if (d < VALID_MIN8) { + if (d == NULL8) return NULL2; + else if (d == LOW_INSTR_SAT8) return LOW_INSTR_SAT2; + else if (d == LOW_REPR_SAT8) return LOW_REPR_SAT2; + else if (d == HIGH_INSTR_SAT8) return HIGH_INSTR_SAT2; + else if (d == HIGH_REPR_SAT8) return HIGH_REPR_SAT2; + else return LOW_REPR_SAT2; + } + else { + if (d < VALID_MIN2 - 0.5) return LOW_REPR_SAT2; + else if (d > VALID_MAX2 + 0.5) return HIGH_REPR_SAT2; + + else { + int itemp; + if (d < 0.0) { + itemp = (int) (d - 0.5); + } + else { + itemp = (int) (d + 0.5); + } + + if (itemp < VALID_MIN2) return LOW_REPR_SAT2; + else if (itemp > VALID_MAX2) return HIGH_REPR_SAT2; + else if (d < 0.0) return (short) (d - 0.5); + else return (short) (d + 0.5); + } + } + } + + /** + * Converts double pixels to float pixels with special pixel translations + * + * @param d Double pixel value to be converted to a double + * + * @return float The float pixel value + */ + float Pixel::To32Bit(const double d) { + if (d < (double) VALID_MIN8) { + if (d == NULL8) return(NULL4); + else if (d == LOW_REPR_SAT8) return(LOW_REPR_SAT4); + else if (d == LOW_INSTR_SAT8) return(LOW_INSTR_SAT4); + else if (d == HIGH_INSTR_SAT8) return(HIGH_INSTR_SAT4); + else if (d == HIGH_REPR_SAT8) return(HIGH_REPR_SAT4); + else return(LOW_REPR_SAT4); + } + else if (d > (double) VALID_MAX8) return(HIGH_REPR_SAT8); + else return((float) d); + } + + /** + * Converts unsigned char pixels to double pixels with special pixel + * translations + * + * @param d Unsigned char pixel value to be converted to a double + * + * @return double The double pixel value + */ + double Pixel::ToDouble(const unsigned char d) { + if (d < VALID_MIN1) { + if (d == NULL1) return(NULL8); + else if (d == LOW_REPR_SAT1) return(LOW_REPR_SAT8); + else if (d == LOW_INSTR_SAT1) return(LOW_INSTR_SAT8); + else if (d == HIGH_REPR_SAT1) return(HIGH_REPR_SAT8); + else if (d == HIGH_INSTR_SAT1) return(HIGH_INSTR_SAT8); + else return(LOW_REPR_SAT8); + } + else if (d > VALID_MAX1) return(HIGH_REPR_SAT8); + else return((double) d); + } + + /** + * Converts short int pixels to double pixels with special pixel translations + * + * @param d Short int pixel value to be converted to a double + * + * @return double The double pixel value + */ + double Pixel::ToDouble(const short int d) { + if (d < VALID_MIN2) { + if (d == NULL2) return(NULL8); + else if (d == LOW_REPR_SAT2) return(LOW_REPR_SAT8); + else if (d == LOW_INSTR_SAT2) return(LOW_INSTR_SAT8); + else if (d == HIGH_REPR_SAT2) return(HIGH_REPR_SAT8); + else if (d == HIGH_INSTR_SAT2) return(HIGH_INSTR_SAT8); + else return(LOW_REPR_SAT8); + } + else return((double) d); + } + + /** + * Converts float pixels to double pixels with special pixel translations + * + * @param d Float pixel value to be converted to a double + * + * @return double The double pixel value + */ + double Pixel::ToDouble(const float d) { + if (d < VALID_MIN4) { + if (d == NULL4) return(NULL8); + else if (d == LOW_REPR_SAT4) return(LOW_REPR_SAT8); + else if (d == LOW_INSTR_SAT4) return(LOW_INSTR_SAT8); + else if (d == HIGH_REPR_SAT4) return(HIGH_REPR_SAT8); + else if (d == HIGH_INSTR_SAT4) return(HIGH_INSTR_SAT8); + else return(LOW_REPR_SAT8); + } + else if (d > VALID_MAX4) return(HIGH_REPR_SAT8); + else return((double) d); + } + + /** + * Converts unsigned char to float with pixel translations + * and care for overflows (underflows are assumed to cast to + * 0!) + * + * @param t Unsigned char pixel value to be converted to a + * float + * + * @return float The float pixel value + */ + float Pixel::ToFloat(const unsigned char t) { + if (t < (double) VALID_MIN1) { + if (t == NULL1) return(NULL4); + else if (t == LOW_REPR_SAT1) return(LOW_REPR_SAT4); + else if (t == LOW_INSTR_SAT1) return(LOW_INSTR_SAT4); + else if (t == HIGH_INSTR_SAT1) return(HIGH_INSTR_SAT4); + else if (t == HIGH_REPR_SAT1) return(HIGH_REPR_SAT4); + else return(LOW_REPR_SAT4); + } + else if (t > (double) VALID_MAX1) return(HIGH_REPR_SAT8); + else return((float) t); + } + + /** + * Converts short int to float with pixel translations and + * care for overflows (underflows are assumed to cast to 0!) + * + * @param t Short int pixel value to be converted to a float + * + * @return float The float pixel value + */ + float Pixel::ToFloat(const short int t) { + if (t < (double) VALID_MIN2) { + if (t == NULL2) return(NULL4); + else if (t == LOW_REPR_SAT2) return(LOW_REPR_SAT4); + else if (t == LOW_INSTR_SAT2) return(LOW_INSTR_SAT4); + else if (t == HIGH_INSTR_SAT2) return(HIGH_INSTR_SAT4); + else if (t == HIGH_REPR_SAT2) return(HIGH_REPR_SAT4); + else return(LOW_REPR_SAT4); + } + else if (t > (double) VALID_MAX2) return(HIGH_REPR_SAT8); + else return((float) t); + } + + /** + * Converts double to float with pixel translations and + * care for overflows (underflows are assumed to cast to 0!) + * + * @param t Double pixel value to be converted to a float + * + * @return float The float pixel value + */ + float Pixel::ToFloat(const double t) { + if (t < (double) VALID_MIN8) { + if (t == NULL8) return(NULL4); + else if (t == LOW_REPR_SAT8) return(LOW_REPR_SAT4); + else if (t == LOW_INSTR_SAT8) return(LOW_INSTR_SAT4); + else if (t == HIGH_INSTR_SAT8) return(HIGH_INSTR_SAT4); + else if (t == HIGH_REPR_SAT8) return(HIGH_REPR_SAT4); + else return(LOW_REPR_SAT4); + } + else if (t > (double) VALID_MAX8) return(HIGH_REPR_SAT8); + else return((float) t); + } + + /** + * Takes a double pixel value and returns the name of the pixel type as a + * string + * + * @param d Pixel value + * + * @return string The name of the pixel type + */ + string Pixel::ToString(double d) { + if (IsSpecial(d)) { + if (IsNull(d)) return string("Null"); + else if (IsLrs(d)) return string("Lrs"); + else if (IsHrs(d)) return string("Hrs"); + else if (IsHis(d)) return string("His"); + else if (IsLis(d)) return string("Lis"); + else return string("Invalid"); + } + + QString result; + return result.setNum(d).toStdString(); + } +} diff --git a/isis/src/base/objs/Pixel/Pixel.h b/isis/src/base/objs/Pixel/Pixel.h new file mode 100644 index 0000000000000000000000000000000000000000..76c11d28ef1c020671e76958998e55ba3c2e6c42 --- /dev/null +++ b/isis/src/base/objs/Pixel/Pixel.h @@ -0,0 +1,183 @@ +#ifndef Pixel_h +#define Pixel_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2009/02/03 23:14:47 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + #include "SpecialPixel.h" + +namespace Isis { + /** + * @brief Manipulate pixel values + * + * This class contains utility methods for testing and modifying pixel and + * special pixel values. + * + * @ingroup Utility + * + * @author 2002-04-11 Kris Becker + * + * @internal + * @history 2003-02-11 Jeff Anderson - Wrote unitTest and documentation + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2005-02-15 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-05-18 Jeff Anderson - Changed long to int for 64-bit port + * @history 2006-06-21 Elizabeth Miller - Copied SpecialPixel methods into + * into the Pixel class for easy + * refactoring later and added + * several conversion methods + * @history 2009-02-03 Travis Addair - Modified documentation + * for clarity + */ + class Pixel { + public: + static unsigned char To8Bit(const double d); + static short int To16Bit(const double d); + static float To32Bit(const double d); + + static double ToDouble(const unsigned char t); + static double ToDouble(const short int t); + static double ToDouble(const float t); + + static float ToFloat(const unsigned char d); + static float ToFloat(const short int d); + static float ToFloat(const double d); + + static std::string ToString(double d); + + /** + * Returns true if the input pixel is special. Not special implies it is valid to + * use in computations. + * + * @param d Pixel value to test + * + * @return bool + */ + static inline bool IsSpecial(const double d) { + return(d < VALID_MIN8); + } + + /** + * Returns true if the input pixel is special. Not special implies it is valid to + * use in computations. This method applies to a 4-byte floating point rather + * than an 8-byte double. + * + * @param f Pixel value to test + * + * @return bool + */ + static inline bool IsSpecial(const float f) { + return(f < VALID_MIN4); + } + + /** + * Returns true if the input pixel is valid. Valid implies the + * pixel is neither hrs, lrs, his, lis, nor null. + * + * @param d Pixel value to test + * + * @return bool + */ + static inline bool IsValid(const double d) { + return(d >= VALID_MIN8); + } + + /** + * Returns true if the input pixel is null + * + * @param d Pixel value to test + * + * @return bool + */ + static inline bool IsNull(const double d) { + return(d == NULL8); + } + + /** + * Returns true if the input pixel is one of the high saturation types + * + * @param d Pixel value to test + * + * @return bool + */ + static inline bool IsHigh(const double d) { + return(d == HIGH_REPR_SAT8) || (d == HIGH_INSTR_SAT8); + } + + /** + * Returns true if the input pixel is one of the low saturation types + * + * @param d Pixel value to test + * + * @return bool + */ + static inline bool IsLow(const double d) { + return(d == LOW_REPR_SAT8) || (d == LOW_INSTR_SAT8); + } + + /** + * Returns true if the input pixel is high representation saturation + * + * @param d Pixel value to test + * + * @return bool + */ + static inline bool IsHrs(const double d) { + return(d == HIGH_REPR_SAT8); + } + + /** + * Returns true if the input pixel is high instrument saturation + * + * @param d Pixel value to test + * + * @return bool + */ + static inline bool IsHis(const double d) { + return(d == HIGH_INSTR_SAT8); + } + + /** + * Returns true if the input pixel is low instrument saturation + * + * @param d Pixel value to test + * + * @return bool + */ + static inline bool IsLis(const double d) { + return(d == LOW_INSTR_SAT8); + } + + /** + * Returns true if the input pixel is low representation saturation + * + * @param d Pixel value to test + * + * @return bool + */ + static inline bool IsLrs(const double d) { + return(d == LOW_REPR_SAT8); + } + + }; // end of pixel class +} +#endif diff --git a/isis/src/base/objs/Pixel/Pixel.truth b/isis/src/base/objs/Pixel/Pixel.truth new file mode 100644 index 0000000000000000000000000000000000000000..50bac0a0124a4d8fdd7837e13b6ec970fdc2065a --- /dev/null +++ b/isis/src/base/objs/Pixel/Pixel.truth @@ -0,0 +1,67 @@ +Unit test for Pixel +Testing 0.0 ... +IsSpecial: 0 +IsValid: 1 +IsNull: 0 +IsLow: 0 +IsHigh: 0 +IsHrs: 0 +IsHis: 0 +IsLrs: 0 +IsLis: 0 + +Testing Isis::Null ... +IsSpecial: 1 +IsValid: 0 +IsNull: 1 +IsLow: 0 +IsHigh: 0 +IsHrs: 0 +IsHis: 0 +IsLrs: 0 +IsLis: 0 + +Testing Isis::Lis ... +IsSpecial: 1 +IsValid: 0 +IsNull: 0 +IsLow: 1 +IsHigh: 0 +IsHrs: 0 +IsHis: 0 +IsLrs: 0 +IsLis: 1 + +Testing Isis::Lrs ... +IsSpecial: 1 +IsValid: 0 +IsNull: 0 +IsLow: 1 +IsHigh: 0 +IsHrs: 0 +IsHis: 0 +IsLrs: 1 +IsLis: 0 + +Testing Isis::His ... +IsSpecial: 1 +IsValid: 0 +IsNull: 0 +IsLow: 0 +IsHigh: 1 +IsHrs: 0 +IsHis: 1 +IsLrs: 0 +IsLis: 0 + +Testing Hrs ... +IsSpecial: 1 +IsValid: 0 +IsNull: 0 +IsLow: 0 +IsHigh: 1 +IsHrs: 1 +IsHis: 0 +IsLrs: 0 +IsLis: 0 + diff --git a/isis/src/base/objs/Pixel/unitTest.cpp b/isis/src/base/objs/Pixel/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34bbc6ce99358a69b972eac8f68509e7788f7eb5 --- /dev/null +++ b/isis/src/base/objs/Pixel/unitTest.cpp @@ -0,0 +1,91 @@ +#include +#include +#include "iException.h" +#include "Pixel.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Unit test for Pixel" << endl; + + double d = 0.0; + cout << "Testing 0.0 ... " << endl; + cout << "IsSpecial: " << Isis::Pixel::IsSpecial(d) << endl; + cout << "IsValid: " << Isis::Pixel::IsValid(d) << endl; + cout << "IsNull: " << Isis::Pixel::IsNull(d) << endl; + cout << "IsLow: " << Isis::Pixel::IsLow(d) << endl; + cout << "IsHigh: " << Isis::Pixel::IsHigh(d) << endl; + cout << "IsHrs: " << Isis::Pixel::IsHrs(d) << endl; + cout << "IsHis: " << Isis::Pixel::IsHis(d) << endl; + cout << "IsLrs: " << Isis::Pixel::IsLrs(d) << endl; + cout << "IsLis: " << Isis::Pixel::IsLis(d) << endl; + cout << endl; + + d = Isis::Null; + cout << "Testing Isis::Null ... " << endl; + cout << "IsSpecial: " << Isis::Pixel::IsSpecial(d) << endl; + cout << "IsValid: " << Isis::Pixel::IsValid(d) << endl; + cout << "IsNull: " << Isis::Pixel::IsNull(d) << endl; + cout << "IsLow: " << Isis::Pixel::IsLow(d) << endl; + cout << "IsHigh: " << Isis::Pixel::IsHigh(d) << endl; + cout << "IsHrs: " << Isis::Pixel::IsHrs(d) << endl; + cout << "IsHis: " << Isis::Pixel::IsHis(d) << endl; + cout << "IsLrs: " << Isis::Pixel::IsLrs(d) << endl; + cout << "IsLis: " << Isis::Pixel::IsLis(d) << endl; + cout << endl; + + d = Isis::Lis; + cout << "Testing Isis::Lis ... " << endl; + cout << "IsSpecial: " << Isis::Pixel::IsSpecial(d) << endl; + cout << "IsValid: " << Isis::Pixel::IsValid(d) << endl; + cout << "IsNull: " << Isis::Pixel::IsNull(d) << endl; + cout << "IsLow: " << Isis::Pixel::IsLow(d) << endl; + cout << "IsHigh: " << Isis::Pixel::IsHigh(d) << endl; + cout << "IsHrs: " << Isis::Pixel::IsHrs(d) << endl; + cout << "IsHis: " << Isis::Pixel::IsHis(d) << endl; + cout << "IsLrs: " << Isis::Pixel::IsLrs(d) << endl; + cout << "IsLis: " << Isis::Pixel::IsLis(d) << endl; + cout << endl; + + d = Isis::Lrs; + cout << "Testing Isis::Lrs ... " << endl; + cout << "IsSpecial: " << Isis::Pixel::IsSpecial(d) << endl; + cout << "IsValid: " << Isis::Pixel::IsValid(d) << endl; + cout << "IsNull: " << Isis::Pixel::IsNull(d) << endl; + cout << "IsLow: " << Isis::Pixel::IsLow(d) << endl; + cout << "IsHigh: " << Isis::Pixel::IsHigh(d) << endl; + cout << "IsHrs: " << Isis::Pixel::IsHrs(d) << endl; + cout << "IsHis: " << Isis::Pixel::IsHis(d) << endl; + cout << "IsLrs: " << Isis::Pixel::IsLrs(d) << endl; + cout << "IsLis: " << Isis::Pixel::IsLis(d) << endl; + cout << endl; + + d = Isis::His; + cout << "Testing Isis::His ... " << endl; + cout << "IsSpecial: " << Isis::Pixel::IsSpecial(d) << endl; + cout << "IsValid: " << Isis::Pixel::IsValid(d) << endl; + cout << "IsNull: " << Isis::Pixel::IsNull(d) << endl; + cout << "IsLow: " << Isis::Pixel::IsLow(d) << endl; + cout << "IsHigh: " << Isis::Pixel::IsHigh(d) << endl; + cout << "IsHrs: " << Isis::Pixel::IsHrs(d) << endl; + cout << "IsHis: " << Isis::Pixel::IsHis(d) << endl; + cout << "IsLrs: " << Isis::Pixel::IsLrs(d) << endl; + cout << "IsLis: " << Isis::Pixel::IsLis(d) << endl; + cout << endl; + + d = Isis::Hrs; + cout << "Testing Hrs ... " << endl; + cout << "IsSpecial: " << Isis::Pixel::IsSpecial(d) << endl; + cout << "IsValid: " << Isis::Pixel::IsValid(d) << endl; + cout << "IsNull: " << Isis::Pixel::IsNull(d) << endl; + cout << "IsLow: " << Isis::Pixel::IsLow(d) << endl; + cout << "IsHigh: " << Isis::Pixel::IsHigh(d) << endl; + cout << "IsHrs: " << Isis::Pixel::IsHrs(d) << endl; + cout << "IsHis: " << Isis::Pixel::IsHis(d) << endl; + cout << "IsLrs: " << Isis::Pixel::IsLrs(d) << endl; + cout << "IsLis: " << Isis::Pixel::IsLis(d) << endl; + cout << endl; +} + diff --git a/isis/src/base/objs/PixelType/Makefile b/isis/src/base/objs/PixelType/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..dae5aab4343358289ef333b04b808c4ecee785bb --- /dev/null +++ b/isis/src/base/objs/PixelType/Makefile @@ -0,0 +1,5 @@ +INCS = PixelType.h +SRCS = +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PixelType/PixelType.h b/isis/src/base/objs/PixelType/PixelType.h new file mode 100644 index 0000000000000000000000000000000000000000..a5c6c5dd8e771f858d5033972f28a5ac79f4c16b --- /dev/null +++ b/isis/src/base/objs/PixelType/PixelType.h @@ -0,0 +1,122 @@ +#if !defined(PixelType_h) +#define PixelType_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "iString.h" + +namespace Isis { + /** + * @brief Enumerations for Isis Pixel Types + * + * This enumeration is for defining pixel types of cubes. UnsignedByte, + * SignedWord, and Real are the only three pixel types currently supported. + * The range for UnsignedBytes is 0 to 255, the range for SignedWord is -32768 + * to 32767, and the range for Real is -FLT_MAX to FLT_MAX as defined in + * the include file, float.h. + * + * @author 2004-10-14 Stuart Sides + * + * @internal + * @history 2005-03-01 Elizabeth Ribelin - Added documentation in Doxygen + * format + */ + enum PixelType { + None=0, + UnsignedByte, + SignedByte, + UnsignedWord, + SignedWord, + UnsignedInteger, + SignedInteger, + Real, + Double + }; + + /** + * Returns the number of bytes of the specified PixelType + * + * @param pixelType PixelType enumeration + * + * @return int Size of pixel type byte + */ + inline int SizeOf(Isis::PixelType pixelType) { + if (pixelType == Isis::None) return 0; + if (pixelType == Isis::UnsignedByte) return sizeof(unsigned char); + if (pixelType == Isis::SignedByte) return sizeof(char); + if (pixelType == Isis::UnsignedWord) return sizeof(unsigned short); + if (pixelType == Isis::SignedWord) return sizeof(short); + if (pixelType == Isis::UnsignedInteger) return sizeof(unsigned int); + if (pixelType == Isis::SignedInteger) return sizeof(int); + if (pixelType == Isis::Real) return sizeof(float); + if (pixelType == Isis::Double) return sizeof(double); + return -1; + } + + /** + * Returns string name of PixelType enumeration entered as input parameter + * + * @param pixelType PixelType enumeration + * + * @return string Name of PixelType + */ + inline std::string PixelTypeName (Isis::PixelType pixelType) { + if (pixelType == Isis::None) return "None"; + if (pixelType == Isis::UnsignedByte) return "UnsignedByte"; + if (pixelType == Isis::SignedByte) return "SignedByte"; + if (pixelType == Isis::UnsignedWord) return "UnsignedWord"; + if (pixelType == Isis::SignedWord) return "SignedWord"; + if (pixelType == Isis::UnsignedInteger) return "UnsignedInteger"; + if (pixelType == Isis::SignedInteger) return "SignedInteger"; + if (pixelType == Isis::Real) return "Real"; + if (pixelType == Isis::Double) return "Double"; + return "Error"; + } + + /** + * Returns PixelType enumeration given a string + * + * @param type iString containing the name of pixel type. Acceptable values are + * UnsignedByte, SignedByte, UnsignedWord, SignedWord, + * UnsignedInteger, SignedInteger, Read, and Double (not case + * sensitive) + * + * @return Isis::PixelType + */ + inline Isis::PixelType PixelTypeEnumeration(const std::string &type) { + Isis::iString temp(type); + temp = temp.UpCase(); + if (temp == "UNSIGNEDBYTE" || temp == "8BIT" || temp == "8-BIT") return Isis::UnsignedByte; + if (temp == "SIGNEDBYTE") return Isis::SignedByte; + if (temp == "UNSIGNEDWORD") return Isis::UnsignedWord; + if (temp == "SIGNEDWORD") return Isis::SignedWord; + if (temp == "UNSIGNEDINTEGER") return Isis::UnsignedInteger; + if (temp == "SIGNEDINTEGER") return Isis::SignedInteger; + if (temp == "REAL") return Isis::Real; + if (temp == "DOUBLE") return Isis::Double; + return Isis::None; + } +} + +#endif + diff --git a/isis/src/base/objs/PixelType/PixelType.truth b/isis/src/base/objs/PixelType/PixelType.truth new file mode 100644 index 0000000000000000000000000000000000000000..a1cfec91c4a3fa094a5c633bc9cb2e6f71c4a96b --- /dev/null +++ b/isis/src/base/objs/PixelType/PixelType.truth @@ -0,0 +1,29 @@ +0 +1 +1 +2 +2 +4 +4 +4 +8 + +None +UnsignedByte +SignedByte +UnsignedWord +SignedWord +UnsignedInteger +SignedInteger +Real +Double + +0 +1 +2 +3 +4 +5 +6 +7 +8 diff --git a/isis/src/base/objs/PixelType/unitTest.cpp b/isis/src/base/objs/PixelType/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5dd1d3aaebc61267cb919e8c5f5abeee66c9d8e9 --- /dev/null +++ b/isis/src/base/objs/PixelType/unitTest.cpp @@ -0,0 +1,39 @@ +#include +#include "PixelType.h" +#include "Preference.h" + +using namespace std; +int main () { + Isis::Preference::Preferences(true); + + cout << Isis::SizeOf(Isis::None) << endl; + cout << Isis::SizeOf(Isis::UnsignedByte) << endl; + cout << Isis::SizeOf(Isis::SignedByte) << endl; + cout << Isis::SizeOf(Isis::UnsignedWord) << endl; + cout << Isis::SizeOf(Isis::SignedWord) << endl; + cout << Isis::SizeOf(Isis::UnsignedInteger) << endl; + cout << Isis::SizeOf(Isis::SignedInteger) << endl; + cout << Isis::SizeOf(Isis::Real) << endl; + cout << Isis::SizeOf(Isis::Double) << endl; + cout << endl; + cout << Isis::PixelTypeName(Isis::None) << endl; + cout << Isis::PixelTypeName(Isis::UnsignedByte) << endl; + cout << Isis::PixelTypeName(Isis::SignedByte) << endl; + cout << Isis::PixelTypeName(Isis::UnsignedWord) << endl; + cout << Isis::PixelTypeName(Isis::SignedWord) << endl; + cout << Isis::PixelTypeName(Isis::UnsignedInteger) << endl; + cout << Isis::PixelTypeName(Isis::SignedInteger) << endl; + cout << Isis::PixelTypeName(Isis::Real) << endl; + cout << Isis::PixelTypeName(Isis::Double) << endl; + cout << endl; + cout << Isis::PixelTypeEnumeration("None") << endl; + cout << Isis::PixelTypeEnumeration("UnsignedByte") << endl; + cout << Isis::PixelTypeEnumeration("SignedByte") << endl; + cout << Isis::PixelTypeEnumeration("UnsignedWord") << endl; + cout << Isis::PixelTypeEnumeration("SignedWord") << endl; + cout << Isis::PixelTypeEnumeration("UnsignedInteger") << endl; + cout << Isis::PixelTypeEnumeration("SignedInteger") << endl; + cout << Isis::PixelTypeEnumeration("Real") << endl; + cout << Isis::PixelTypeEnumeration("Double") << endl; +} + diff --git a/isis/src/base/objs/Plugin/Makefile b/isis/src/base/objs/Plugin/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9b8a311e880a63f334b346b34008bede57e9b7fd --- /dev/null +++ b/isis/src/base/objs/Plugin/Makefile @@ -0,0 +1,5 @@ +INCS = Plugin.h +SRCS = Plugin.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Plugin/Plugin.cpp b/isis/src/base/objs/Plugin/Plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4b71ae0ec1b56ce4ece401cb088f300f7d8d5f5c --- /dev/null +++ b/isis/src/base/objs/Plugin/Plugin.cpp @@ -0,0 +1,88 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/03/16 18:45:00 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include "iException.h" +#include "Plugin.h" +#include "Filename.h" + +using namespace std; +namespace Isis { + //! Constructs a Plugin object. + Plugin::Plugin () : Isis::Pvl() { + } + +/** + * This method returns a void pointer to a C function (i.e., the plugin) It + * does this by looking in itself (Pvl) for the keyword LIBRARY and the + * keyword ROUTINE. When you write this function make sure to place extern + * "C" infront of it to eliminate C++ symbol mangling. + * + * @param group The group name. + * + * @return A void pointer to a C function (i.e., the plugin) + * + * @history 2010-03-16 Tracie Sucharski, Added paths to plugin. First + * try to load from current working directory, + * then from $ISISROOT/lib. + */ + void *Plugin::GetPlugin (const std::string &group) { + // Get the library and plugin to load + Isis::PvlGroup &g = FindGroup(group); + string library = g["Library"]; + + string path = "./"; + Isis::Filename libraryFile(path + library); + + string pluginName = g["Routine"]; + + // Open the library, resolve the routine name, and return the function + // address. The function will stay in memory until the application exists + // so the scope of lib does not matter. + QLibrary lib(libraryFile.Expanded().c_str()); + bool loadedOk = lib.load(); + if (!loadedOk) { + path = "$ISISROOT/lib/"; + libraryFile = path + library; + } + lib.setFileName(libraryFile.Expanded().c_str()); + + void *plugin = lib.resolve(pluginName.c_str()); + if (plugin == 0) { + string msg = "Unable to find plugin [" + pluginName + + "] in shared library [" + lib.fileName().toStdString() + "]"; + throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); + } + + return plugin; + } +} // end namespace isis + +extern "C" int *PluginPlugin () { + cout << "Hello world" << endl; + static int k = 5; + return &k; +} diff --git a/isis/src/base/objs/Plugin/Plugin.h b/isis/src/base/objs/Plugin/Plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..0632eaf00394c42b5b67cd4b99e9daee2d1bb255 --- /dev/null +++ b/isis/src/base/objs/Plugin/Plugin.h @@ -0,0 +1,82 @@ +#ifndef Plugin_h +#define Plugin_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/07/19 22:49:55 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Pvl.h" + +namespace Isis { +/** + * @brief Loads plugins from a shared library + * + * This class is used to handle dynamic loading of module/classes. It is + * rarely used directly but instead is inherited for a particular purpose such + * as managing class specific map projections or camera models. + * The class is derived from a PVL which aides in the selection of the + * shared library and plugin routine to load. For example, assume the file + * my.plugin contained: + * @code + * OBJECT=SINUSOIDAL + * LIBRARY=libisis3.so + * ROUTINE=SinusoidalPlugin + * END_OBJECT + * OBJECT=SIMPLECYLINDRICAL + * LIBRARY=libisis3.so + * ROUTINE=SimpleCylindricalPlugin + * END_OBJECT + * @endcode + * The desired routine can be selected in code as follows: + * @code + * Plugin p; + * p.Read("my.plugin"); + * string proj; + * cin >> proj; // Enter either SINUSOIDAL or SIMPLECYLINDRICAL + * p.Find(proj); + * void *ptr = p.GetPlugin(); + * @endcode + * Obtaining plugins can be difficult to understand. It is suggested you + * look at ProjectionFactory to get a better understanding of how they are used. + * + * @see ProjectionFactory + * @see CameraFactory + * + * @ingroup System + * + * @author 2004-02-07 Jeff Anderson + * + * @internal + * @history 2005-02-15 Jeff Anderson refactored to use Qt Qlibrary class. + * @history 2007-07-19 Steven Lambright Fixed memory leak + */ + class Plugin : public Isis::Pvl { + public: + Plugin (); + + //! Destroys the Plugin object. + virtual ~Plugin () {}; + + void *GetPlugin( const std::string &group); + }; +}; + +#endif diff --git a/isis/src/base/objs/Plugin/Plugin.truth b/isis/src/base/objs/Plugin/Plugin.truth new file mode 100644 index 0000000000000000000000000000000000000000..0c91bc7040cd79c12fdb3f26e5b919fa4ebe5244 --- /dev/null +++ b/isis/src/base/objs/Plugin/Plugin.truth @@ -0,0 +1,2 @@ +Hello world +5 diff --git a/isis/src/base/objs/Plugin/unitTest.cpp b/isis/src/base/objs/Plugin/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..495f9f179cbb7c7342bd1f5768bdf3d54f29f1d7 --- /dev/null +++ b/isis/src/base/objs/Plugin/unitTest.cpp @@ -0,0 +1,29 @@ +#include +#include +#include "Plugin.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + try { + stringstream temp; + temp << "Group = Plugin" << endl; + temp << " Library = isis3" << endl; + temp << " Routine = PluginPlugin" << endl; + temp << "EndGroup" << endl; + + Isis::Plugin p; + temp >> p; + void *ptr = p.GetPlugin("Plugin"); + + int * (*module)(); + module = (int * (*)()) ptr; + cout << *(*module)() << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } +} diff --git a/isis/src/base/objs/PointPerspective/Makefile b/isis/src/base/objs/PointPerspective/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4a837488ef922cd683e8096c9183d4b6cd10d799 --- /dev/null +++ b/isis/src/base/objs/PointPerspective/Makefile @@ -0,0 +1,5 @@ +INCS = PointPerspective.h +SRCS = PointPerspective.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PointPerspective/PointPerspective.cpp b/isis/src/base/objs/PointPerspective/PointPerspective.cpp new file mode 100644 index 0000000000000000000000000000000000000000..601671d5b7dbc0b24f3e29f42d00655875706e2f --- /dev/null +++ b/isis/src/base/objs/PointPerspective/PointPerspective.cpp @@ -0,0 +1,377 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/06/13 19:35:00 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "PointPerspective.h" +#include "iException.h" +#include "Constants.h" + +using namespace std; +namespace Isis { + /** + * Constructs an PointPerspective object + * + * @param label This argument must be a Label containing the proper mapping + * information as indicated in the Projection class. Additionally, + * the point perspective projection requires the center longitude + * to be defined in the keyword CenterLongitude. + * + * @param allowDefaults If set to false the constructor expects that a keyword + * of CenterLongitude will be in the label. Otherwise it + * will attempt to compute the center longitude using the + * middle of the longitude range specified in the labels. + * Defaults to false. + * + * @throws Isis::iException::Io + */ + PointPerspective::PointPerspective(Isis::Pvl &label, bool allowDefaults) : + Isis::Projection::Projection (label) { + try { + // Try to read the mapping group + Isis::PvlGroup &mapGroup = label.FindGroup ("Mapping",Isis::Pvl::Traverse); + + // Compute and write the default center longitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLongitude"))) { + double lon = (p_minimumLongitude + p_maximumLongitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLongitude",lon); + } + + // Compute and write the default center latitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLatitude"))) { + double lat = (p_minimumLatitude + p_maximumLatitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLatitude",lat); + } + + // Get the center longitude & latitude + p_centerLongitude = mapGroup["CenterLongitude"]; + p_centerLatitude = mapGroup["CenterLatitude"]; + if (this->IsPlanetocentric()) { + p_centerLatitude = this->ToPlanetographic(p_centerLatitude); + } + + // convert to radians, adjust for longitude direction + p_centerLongitude *= Isis::PI / 180.0; + p_centerLatitude *= Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) p_centerLongitude *= -1.0; + + // Calculate sine & cosine of center latitude + sinph0 = sin(p_centerLatitude); + cosph0 = cos(p_centerLatitude); + + // Get the distance above planet center (the point of perspective from + // the center of planet), and calculate P + p_distance = mapGroup["Distance"]; + p_distance *= 1000.; + p_P = 1.0 + (p_distance / p_equatorialRadius); + + } + catch (Isis::iException &e) { + string message = "Invalid label group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + //! Destroys the PointPerspective object + PointPerspective::~PointPerspective() { + } + + /** + * This method is used to set the latitude/longitude (assumed to be of the + * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. + * + * @param lat Latitude value to project + * + * @param lon Longitude value to project + * + * @return bool + */ + bool PointPerspective::SetGround(const double lat,const double lon) { + // Convert longitude to radians & clean up + p_longitude = lon; + double lonRadians = lon * Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) lonRadians *= -1.0; + + // Now convert latitude to radians & clean up ... it must be planetographic + p_latitude = lat; + double latRadians = lat; + if (IsPlanetocentric()) latRadians = ToPlanetographic(latRadians); + latRadians *= Isis::PI / 180.0; + + // Compute helper variables + double deltaLon = (lonRadians - p_centerLongitude); + double sinphi = sin(latRadians); + double cosphi = cos(latRadians); + double coslon = cos(deltaLon); + + // Lat/Lon cannot be projected + double g = sinph0*sinphi + cosph0*cosphi*coslon; + if ( g < (1.0/p_P) ) { + p_good = false; + return p_good; + } + + // Compute the coordinates + double ksp = (p_P - 1.0) / (p_P - g); + double x = p_equatorialRadius * ksp * cosphi * sin(deltaLon); + double y = p_equatorialRadius * ksp * + (cosph0 * sinphi - sinph0 * cosphi * coslon); + SetComputedXY(x,y); + p_good = true; + return p_good; + } + + /** + * This method is used to set the projection x/y. The Set forces an attempted + * calculation of the corresponding latitude/longitude position. This may or + * may not be successful and a status is returned as such. + * + * @param x X coordinate of the projection in units that are the same as the + * radii in the label + * + * @param y Y coordinate of the projection in units that are the same as the + * radii in the label + * + * @return bool + */ + bool PointPerspective::SetCoordinate(const double x, const double y) { + // Save the coordinate + SetXY(x,y); + + // Declare instance variables and calculate rho + double rho,rp,con,com,z,sinz,cosz; + const double epsilon = 1.0e-10; + rho = sqrt(GetX()*GetX() + GetY()*GetY()); + rp = rho / p_equatorialRadius; + con = p_P - 1.0; + com = p_P + 1.0; + + // Error calculating rho - should be less than equatorial radius + if (rp > (sqrt(con/com))) { + p_good = false; + return p_good; + } + + // Calculate the latitude and longitude + p_longitude = p_centerLongitude; + if (fabs(rho) <= epsilon) { + p_latitude = p_centerLatitude; + } + else { + if (rp <= epsilon) { + sinz = 0.0; + } + else { + sinz = (p_P - sqrt(1.0-rp*rp*com / con)) / (con / rp + rp / con); + } + z = asin(sinz); + sinz = sin(z); + cosz = cos(z); + con = cosz*sinph0 + GetY()*sinz*cosph0 / rho; + if (con > 1.0) con = 1.0; + if (con < -1.0) con = -1.0; + p_latitude = asin(con); + + con = fabs(p_centerLatitude) - Isis::HALFPI; + if (fabs(con) <= epsilon) { + if(p_centerLatitude >= 0.0) { + p_longitude += atan2(GetX(), -GetY()); + } + else { + p_longitude += atan2(-GetX(), GetY()); + } + } + else { + con = cosz - sinph0 * sin(p_latitude); + if ((fabs(con) >= epsilon) || (fabs(GetX()) >= epsilon)) { + p_longitude += atan2(GetX()*sinz*cosph0, con*rho); + } + } + } + + // Convert to degrees + p_latitude *= 180.0 / Isis::PI; + p_longitude *= 180.0 / Isis::PI; + + // Cleanup the longitude + if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; + // These need to be done for circular type projections + p_longitude = To360Domain (p_longitude); + if (p_longitudeDomain == 180) p_longitude = To180Domain(p_longitude); + + // Cleanup the latitude + if (IsPlanetocentric()) p_latitude = ToPlanetocentric(p_latitude); + + p_good = true; + return p_good; + } + + /** + * This method is used to determine the x/y range which completely covers the + * area of interest specified by the lat/lon range. The latitude/longitude + * range may be obtained from the labels. The purpose of this method is to + * return the x/y range so it can be used to compute how large a map may need + * to be. For example, how big a piece of paper is needed or how large of an + * image needs to be created. The method may fail as indicated by its return + * value. + * + * @param minX Minimum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxX Maximum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param minY Minimum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxY Maximum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @return bool + */ + bool PointPerspective::XYRange(double &minX, double &maxX, double &minY, double&maxY){ + double lat, lon; + + // Check the corners of the lat/lon range + XYRangeCheck (p_minimumLatitude,p_minimumLongitude); + XYRangeCheck (p_maximumLatitude,p_minimumLongitude); + XYRangeCheck (p_minimumLatitude,p_maximumLongitude); + XYRangeCheck (p_maximumLatitude,p_maximumLongitude); + + // Walk top and bottom edges + for (lat=p_minimumLatitude; lat<=p_maximumLatitude; lat+=0.01) { + lat = lat; + lon = p_minimumLongitude; + XYRangeCheck(lat,lon); + + lat = lat; + lon = p_maximumLongitude; + XYRangeCheck(lat,lon); + } + + // Walk left and right edges + for (lon=p_minimumLongitude; lon<=p_maximumLongitude; lon+=0.01) { + lat = p_minimumLatitude; + lon = lon; + XYRangeCheck(lat,lon); + + lat = p_maximumLatitude; + lon = lon; + XYRangeCheck(lat,lon); + } + + // Walk the limb + for (double angle=0.0; angle<=360.0; angle+=0.01) { + double x = p_equatorialRadius * cos(angle * Isis::PI / 180.0); + double y = p_equatorialRadius * sin(angle * Isis::PI / 180.0); + if (SetCoordinate(x,y) == 0) { + if (p_latitude > p_maximumLatitude) continue; + if (p_longitude > p_maximumLongitude) continue; + if (p_latitude < p_minimumLatitude) continue; + if (p_longitude < p_minimumLongitude) continue; + XYRangeCheck(p_latitude, p_longitude); + } + } + + // Make sure everything is ordered + if (p_minimumX >= p_maximumX) return false; + if (p_minimumY >= p_maximumY) return false; + + // Return X/Y min/maxs + minX = p_minimumX; + maxX = p_maximumX; + minY = p_minimumY; + maxY = p_maximumY; + return true; + } + + + /** + * This function returns the keywords that this projection uses. + * + * @return PvlGroup The keywords that this projection uses + */ + PvlGroup PointPerspective::Mapping() { + PvlGroup mapping = Projection::Mapping(); + + mapping += p_mappingGrp["CenterLatitude"]; + mapping += p_mappingGrp["CenterLongitude"]; + mapping += p_mappingGrp["Distance"]; + + return mapping; + } + + /** + * This function returns the latitude keywords that this projection uses + * + * @return PvlGroup The latitude keywords that this projection uses + */ + PvlGroup PointPerspective::MappingLatitudes() { + PvlGroup mapping = Projection::MappingLatitudes(); + + mapping += p_mappingGrp["CenterLatitude"]; + + return mapping; + } + + /** + * This function returns the longitude keywords that this projection uses + * + * @return PvlGroup The longitude keywords that this projection uses + */ + PvlGroup PointPerspective::MappingLongitudes() { + PvlGroup mapping = Projection::MappingLongitudes(); + + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * Compares two Projection objects to see if they are equal + * + * @param proj Projection object to do comparison on + * + * @return bool Returns true if the Projection objects are equal, and false if + * they are not + */ + bool PointPerspective::operator== (const Isis::Projection &proj) { + if (!Isis::Projection::operator==(proj)) return false; + // dont do the below it is a recusive plunge + // if (Isis::Projection::operator!=(proj)) return false; + PointPerspective *point = (PointPerspective *) &proj; + if ((point->p_centerLongitude != this->p_centerLongitude) || + (point->p_centerLatitude != this->p_centerLatitude) || + (point->p_distance != this->p_distance)) return false; + return true; + } +} // end namespace isis + +extern "C" Isis::Projection *PointPerspectivePlugin (Isis::Pvl &lab, + bool allowDefaults) { + return new Isis::PointPerspective(lab,allowDefaults); +} + diff --git a/isis/src/base/objs/PointPerspective/PointPerspective.h b/isis/src/base/objs/PointPerspective/PointPerspective.h new file mode 100644 index 0000000000000000000000000000000000000000..ba00de4229e02f6d1a01536fffbfadb7fc6490a9 --- /dev/null +++ b/isis/src/base/objs/PointPerspective/PointPerspective.h @@ -0,0 +1,96 @@ +#ifndef PointPerspective_h +#define PointPerspective_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/13 20:02:20 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Projection.h" +#include "Constants.h" + +namespace Isis { +/** + * @brief PointPerspective Map Projection + * + * This class provides methods for the forward and inverse equations of an + * PointPerspective map projection (for a sphere). The code was converted + * to C++ from the C version of the USGS General Cartographic Transformation + * Package (GCTP). This class inherits Projection and provides the two virtual + * methods SetGround (forward) and SetCoordinate (inverse) and a third virtual + * method, XYRange, for obtaining projection coordinate coverage for a + * latitude/longitude window. Please see the Projection class for a full + * accounting of all the methods available. + * + * @ingroup MapProjection + * + * @author 2008-06-13 Tracie Sucharski + * + * @internal + */ + class PointPerspective : public Isis::Projection { + public: + PointPerspective(Isis::Pvl &label, bool allowDefaults=false); + ~PointPerspective(); + bool SetGround (const double lat, const double lon); + bool SetCoordinate (const double x, const double y); + bool XYRange (double &minX, double &maxX, double &minY, double &maxY); + PvlGroup Mapping(); + PvlGroup MappingLatitudes(); + PvlGroup MappingLongitudes(); + + /** + * Returns the name of the map projection + * + * @return string Name of projection + */ + std::string Name() const { return "PointPerspective"; } + + /** + * Returns the version of the map projection + * + * + * @return std::string Version number + */ + std::string Version () const { return "1.0"; } + + bool operator== (const Isis::Projection &proj); + + /** + * Returns the latitude of true scale (in the case of PointPerspective + * it is the center latitude) + * + * @return double + */ + double TrueScaleLatitude () const { + return p_centerLatitude * 180.0 / Isis::PI; + }; + + + private: + double p_centerLongitude; //! +#include +#include "PointPerspective.h" +#include "iException.h" +#include "ProjectionFactory.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "UNIT TEST FOR PointPerspective" << endl << endl; + + Isis::Pvl lab; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = lab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",6371000.); + mapGroup += Isis::PvlKeyword("PolarRadius",6371000.); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetographic"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",180); + mapGroup += Isis::PvlKeyword("MinimumLatitude",-90.0); + mapGroup += Isis::PvlKeyword("MaximumLatitude",90.0); + mapGroup += Isis::PvlKeyword("MinimumLongitude",-180.0); + mapGroup += Isis::PvlKeyword("MaximumLongitude",180.0); + mapGroup += Isis::PvlKeyword("ProjectionName","PointPerspective"); + + cout << "Test missing center longitude keyword ..." << endl; + try { + Isis::PointPerspective p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("CenterLongitude",-77.0); + + cout << "Test missing center latitude keyword..." << endl; + try { + Isis::PointPerspective p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("CenterLatitude", 39.0); + + cout << "Test missing distance keyword..." << endl; + try { + Isis::PointPerspective p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("Distance", 500000.0); + + try { + Isis::Projection &p = *Isis::ProjectionFactory::Create(lab); + // Isis::PointPerspective p(lab); + + cout << "Test TrueScaleLatitude method... " << endl; + cout << "TrueScaleLatitude = " << p.TrueScaleLatitude() << endl; + cout << endl; + + cout << "Test SetGround method ... " << endl; + cout << std::setprecision(9); + cout << "Setting ground to (41,-74)" << endl; + p.SetGround(41.0,-74.0); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + + cout << "Test SetCoordinate method ... " << endl; + cout << "Setting coordinate to (251640.079, 226487.551)" << endl; + p.SetCoordinate(251640.079, 226487.551); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + cout << "Test XYRange method ... " << endl; + double minX,maxX,minY,maxY; + p.XYRange(minX,maxX,minY,maxY); + cout << "Minimum X: " << minX << endl; + cout << "Maximum X: " << maxX << endl; + cout << "Minimum Y: " << minY << endl; + cout << "Maximum Y: " << maxY << endl; + cout << endl; + + Isis::Projection *s = &p; + cout << "Test Name and comparision method ... " << endl; + cout << "Name: " << s->Name() << endl; + cout << "operator== " << (*s == *s) << endl; + cout << endl; + + cout << "Test default computation ... " << endl; + mapGroup.DeleteKeyword("CenterLongitude"); + mapGroup.DeleteKeyword("CenterLatitude"); + Isis::PointPerspective p2(lab,true); + cout << lab << endl; + cout << endl; + + cout << "Testing Mapping() methods ... " << endl; + + Isis::Pvl tmp1; + Isis::Pvl tmp2; + Isis::Pvl tmp3; + tmp1.AddGroup(p.Mapping()); + tmp2.AddGroup(p.MappingLatitudes()); + tmp3.AddGroup(p.MappingLongitudes()); + + cout << "Mapping() = " << endl; + cout << tmp1 << endl; + cout << "MappingLatitudes() = " << endl; + cout << tmp2 << endl; + cout << "MappingLongitudes() = " << endl; + cout << tmp3 << endl; + cout << endl; + + cout << "Unit test was obtained from:" << endl << endl; + cout << " Map Projections - A Working Manual" << endl; + cout << " USGS Professional Paper 1395 by John P. Snyder" << endl; + cout << " Pages 320-321" << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } +} diff --git a/isis/src/base/objs/PolarStereographic/Makefile b/isis/src/base/objs/PolarStereographic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6b4484834d6d477a4c9233ed89b507d6d9166855 --- /dev/null +++ b/isis/src/base/objs/PolarStereographic/Makefile @@ -0,0 +1,5 @@ +INCS = PolarStereographic.h +SRCS = PolarStereographic.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PolarStereographic/PolarStereographic.cpp b/isis/src/base/objs/PolarStereographic/PolarStereographic.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e73462ffa1286fbd09e67e577d7fc237727d3779 --- /dev/null +++ b/isis/src/base/objs/PolarStereographic/PolarStereographic.cpp @@ -0,0 +1,350 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/05/09 18:49:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "PolarStereographic.h" +#include "iException.h" +#include "Constants.h" + +using namespace std; +namespace Isis { + /** + * Constructs a PolarStereographic object. + * + * @param label This argument must be a Pvl containing the proper mapping + * information as indicated in the Projection class. Additionally, + * the polar stereographic projection requires the center + * longitude and latitude to be defined in the keyword + * CenterLongitude and CenterLatitude respectively. + * + * @param allowDefaults If set to false the constructor expects that a keyword + * of CenterLongitude and CenterLatitude will be in the + * label. Otherwise it will attempt to compute them using + * the middle of the longitude range specified in the + * labels. The center latitude will be set to one of the + * poles depending on the average of the latitude range. + * Defaults to false. + * + * @throws Isis::iException::Projection - An error is thrown if the label does + * not contain the keyword + * CenterLongitude or latitude. + */ + PolarStereographic::PolarStereographic(Isis::Pvl &label, bool allowDefaults) : + Isis::Projection::Projection (label) { + try { + // Try to read the mapping group + Isis::PvlGroup &mapGroup = label.FindGroup ("Mapping",Isis::Pvl::Traverse); + + // Compute and write the default center longitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLongitude"))) { + double lon = (p_minimumLongitude + p_maximumLongitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLongitude",lon); + } + + // Compute and write the default center latitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLatitude"))) { + double lat = (p_minimumLatitude + p_maximumLatitude) / 2.0; + if (lat > 0.0) { + mapGroup += Isis::PvlKeyword("CenterLatitude",90.0); + } + else { + mapGroup += Isis::PvlKeyword("CenterLatitude",-90.0); + } + } + + // Get the center longitude, convert to radians and adjust for longitude + // direction + p_centerLongitude = mapGroup["CenterLongitude"]; + p_centerLongitude *= Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) p_centerLongitude *= -1.0; + + // Get the center latitude, make sure it is ographic, and convert to + // radians. + p_centerLatitude = mapGroup["CenterLatitude"]; + if (p_centerLatitude == 0) { + string msg = "Invalid value for keyword [CenterLatitude] in map file."; + msg += " CenterLatitude cannot equal 0.0"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + if (this->IsPlanetocentric()) { + p_centerLatitude = this->ToPlanetographic(p_centerLatitude); + } + p_centerLatitude *= Isis::PI / 180.0; + + // Compute some constants + p_e4 = e4Compute (); + p_signFactor = 1.0; + if (p_centerLatitude < 0.0) p_signFactor = -1.0; + + if ((Isis::HALFPI - fabs(p_centerLatitude)) > DBL_EPSILON) { + p_poleFlag = true; // We are not at a pole + double phi = p_signFactor * p_centerLatitude; + double sinphi = sin(phi); + double cosphi = cos(phi); + p_m = mCompute (sinphi,cosphi); + p_t = tCompute (phi,sinphi); + if (fabs(p_t) < DBL_EPSILON) p_poleFlag = false; + } + else { + p_poleFlag = false; // Implies we are at a pole + } + } + catch (Isis::iException &e) { + string message = "Invalid label group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + } + + //! Destroys the PolarStereographic object + PolarStereographic::~PolarStereographic() { + } + + /** + * This method is used to set the latitude/longitude (assumed to be of the + * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. + * + * @param lat Latitude value to project + * + * @param lon Longitude value to project + * + * @return bool + */ + bool PolarStereographic::SetGround(const double lat,const double lon) { + // Fix up longitude + p_longitude = lon; + double lonRadians = lon * Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) lonRadians *= -1.0; + + // Now do latitude ... it must be planetographic + p_latitude = lat; + double latRadians = lat; + if (IsPlanetocentric()) latRadians = ToPlanetographic(latRadians); + latRadians = latRadians * Isis::PI / 180.0; + + // Compute easting and northing + double lamda = p_signFactor * (lonRadians - p_centerLongitude); + double phi = p_signFactor * latRadians; + double sinphi = sin(phi); + double t = tCompute (phi,sinphi); + + double dist; + if (p_poleFlag) { + dist = p_equatorialRadius * p_m * t / p_t; + } + else { + dist = p_equatorialRadius * 2.0 * t / p_e4; + } + + double x = p_signFactor * dist * sin(lamda); + double y = -(p_signFactor * dist * cos(lamda)); + SetComputedXY(x,y); + + p_good = true; + return p_good; + } + + /** + * This method is used to set the projection x/y. The Set forces an attempted + * calculation of the corresponding latitude/longitude position. This may or + * may not be successful and a status is returned as such. + * + * @param x X coordinate of the projection in units that are the same as the + * radii in the label + * + * @param y Y coordinate of the projection in units that are the same as the + * radii in the label + * + * @return bool + */ + bool PolarStereographic::SetCoordinate(const double x, const double y) { + // Save the coordinate + SetXY(x,y); + + double east = p_signFactor * GetX(); + double north = p_signFactor * GetY(); + double dist = sqrt (east * east + north * north); + + double t; + if(p_poleFlag) { + t = dist * p_t / (p_m * p_equatorialRadius); + } + else { + t = dist * p_e4 / (2.0 * p_equatorialRadius); + } + + // Compute the latitude + double phi = phi2Compute(t); + p_latitude = p_signFactor * phi; + + if (fabs(p_latitude) > Isis::HALFPI) { + string msg = "X,Y causes latitude to be outside [-90,90] in PolarStereographic Class"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Compute the longitude + if (dist == 0.0) { + p_longitude = p_signFactor * p_centerLongitude; + } + else { + p_longitude = p_signFactor * atan2(east,-north) + p_centerLongitude; + } + + // Cleanup the longitude + p_longitude *= 180.0 / Isis::PI; + if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; + p_longitude = To360Domain (p_longitude); + if (p_longitudeDomain == 180) p_longitude = To180Domain(p_longitude); + + // Cleanup the latitude + p_latitude *= 180.0 / Isis::PI; + if (IsPlanetocentric()) p_latitude = ToPlanetocentric(p_latitude); + + p_good = true; + return p_good; + } + + /** + * This method is used to determine the x/y range which completely covers the + * area of interest specified by the lat/lon range. The latitude/longitude + * range may be obtained from the labels. The purpose of this method is to + * return the x/y range so it can be used to compute how large a map may need + * to be. For example, how big a piece of paper is needed or how large of an + * image needs to be created. The method may fail as indicated by its return + * value. + * + * @param minX Minimum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxX Maximum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param minY Minimum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxY Maximum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @return bool + */ + bool PolarStereographic::XYRange(double &minX, double &maxX, + double &minY, double&maxY) { + // Check the corners of the lat/lon range + XYRangeCheck (p_minimumLatitude,p_minimumLongitude); + XYRangeCheck (p_maximumLatitude,p_minimumLongitude); + XYRangeCheck (p_minimumLatitude,p_maximumLongitude); + XYRangeCheck (p_maximumLatitude,p_maximumLongitude); + + // Find the closest longitude >= to the minimum longitude that is offset from + // the center longitude by a multiple of 90. + double lon1 = p_centerLongitude * 180.0 / Isis::PI; + if (p_longitudeDirection == PositiveWest) lon1 *= -1.0; + while (lon1 > p_minimumLongitude) lon1 -= 90.0; + while (lon1 < p_minimumLongitude) lon1 += 90.0; + + while (lon1 <= p_maximumLongitude) { + XYRangeCheck(p_minimumLatitude,lon1); + XYRangeCheck(p_maximumLatitude,lon1); + lon1 += 90.0; + } + + // Make sure everything is ordered + if (p_minimumX >= p_maximumX) return false; + if (p_minimumY >= p_maximumY) return false; + + // Return X/Y min/maxs + minX = p_minimumX; + maxX = p_maximumX; + minY = p_minimumY; + maxY = p_maximumY; + return true; + } + + + /** + * This function returns the keywords that this projection uses. + * + * @return PvlGroup The keywords that this projection uses + */ + PvlGroup PolarStereographic::Mapping() { + PvlGroup mapping = Projection::Mapping(); + + mapping += p_mappingGrp["CenterLatitude"]; + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * This function returns the latitude keywords that this projection uses + * + * @return PvlGroup The latitude keywords that this projection uses + */ + PvlGroup PolarStereographic::MappingLatitudes() { + PvlGroup mapping = Projection::MappingLatitudes(); + + mapping += p_mappingGrp["CenterLatitude"]; + + return mapping; + } + + /** + * This function returns the longitude keywords that this projection uses + * + * @return PvlGroup The longitude keywords that this projection uses + */ + PvlGroup PolarStereographic::MappingLongitudes() { + PvlGroup mapping = Projection::MappingLongitudes(); + + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * Compares two Projection objects to see if they are equal + * + * @param proj Projection object to do comparison on + * + * @return bool Returns true if the Projection objects are equal, and false if + * they are not + */ + bool PolarStereographic::operator== (const Isis::Projection &proj) { + if (!Isis::Projection::operator==(proj)) return false; + // dont do the below it is a recusive plunge + // if (Isis::Projection::operator!=(proj)) return false; + PolarStereographic *pola = (PolarStereographic *) &proj; + if (pola->p_centerLongitude != this->p_centerLongitude) return false; + if (pola->p_centerLatitude != this->p_centerLatitude) return false; + return true; + } +} + +extern "C" Isis::Projection *PolarStereographicPlugin (Isis::Pvl &lab, + bool allowDefaults) { + return new Isis::PolarStereographic(lab,allowDefaults); +} diff --git a/isis/src/base/objs/PolarStereographic/PolarStereographic.h b/isis/src/base/objs/PolarStereographic/PolarStereographic.h new file mode 100644 index 0000000000000000000000000000000000000000..1679183e221b8a5619b6352dd430fba9f7517aac --- /dev/null +++ b/isis/src/base/objs/PolarStereographic/PolarStereographic.h @@ -0,0 +1,111 @@ +#ifndef PolarStereographic_h +#define PolarStereographic_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/05/09 18:49:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Projection.h" +#include "Constants.h" + +namespace Isis { +/** + * @brief Stereographic Map Projection + * + * This class provides methods for the forward and inverse equations of a Polar + * Stereographic map projection (for an ellipsoid). The code was converted to + * C++ from the Fortran version of the USGS General Cartographic Transformation + * Package (GCTP). This class inherits Projection and provides the two virtual + * methods SetGround (forward) and SetCoordinate (inverse) and a third virtual + * method, XYRange, for obtaining projection coordinate coverage for a + * latitude/longitude window. Please see the Projection class for a full + * accounting of all the methods available. + * + * @ingroup MapProjection + * + * @author 2004-02-24 Jeff Anderson + * + * @internal + * @history 2004-02-24 Jeff Anderson - Fixed a bug in TrueScaleLatitude and + * changed default computation for + * CenterLatitude + * @history 2005-03-01 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-03-11 Elizabeth Ribelin - added TrueScaleLatitude method test + * to unitTest + * @history 2006-06-14 Elizabeth Miller - Added error check to make sure the + * center latitude is not zero + * @history 2007-06-29 Steven Lambright - Added Mapping, MappingLatitudes and + * MappingLongitudes methods. + * @history 2008-05-09 Steven Lambright - Added Name, Version methods + */ + class PolarStereographic : public Isis::Projection { + public: + PolarStereographic (Isis::Pvl &label, bool allowDefaults=false); + ~PolarStereographic (); + bool SetGround (const double lat, const double lon); + bool SetCoordinate (const double x, const double y); + bool XYRange (double &minX, double &maxX, double &minY, double &maxY); + + PvlGroup Mapping(); + PvlGroup MappingLatitudes(); + PvlGroup MappingLongitudes(); + + /** + * Returns the name of the map projection + * + * @return string Name of projection + */ + std::string Name() const { return "PolarStereographic"; } + + /** + * Returns the version of the map projection + * + * + * @return std::string Version number + */ + std::string Version () const { return "1.0"; } + + bool operator== (const Isis::Projection &proj); + + /** + * Returns the latitude of true scale (in the case of Polar Stereographic + * it is the center latitude) + * + * @return double + */ + double TrueScaleLatitude () const { + return p_centerLatitude * 180.0 / Isis::PI; + }; + + private: + double p_centerLongitude; //! +#include +#include "iException.h" +#include "PolarStereographic.h" +#include "ProjectionFactory.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Unit Test For PolarStereographic" << endl << endl; + cout << std::setprecision(14); + + Isis::Pvl lab; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mg = lab.FindGroup("Mapping"); + mg += Isis::PvlKeyword("EquatorialRadius",6378388.0); + mg += Isis::PvlKeyword("PolarRadius",6356911.9); + mg += Isis::PvlKeyword("LatitudeType","Planetographic"); + mg += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mg += Isis::PvlKeyword("LongitudeDomain",180); + mg += Isis::PvlKeyword("MinimumLatitude",-90.0); + mg += Isis::PvlKeyword("MaximumLatitude",0.0); + mg += Isis::PvlKeyword("MinimumLongitude",-180.0); + mg += Isis::PvlKeyword("MaximumLongitude",180.0); + mg += Isis::PvlKeyword("ProjectionName","PolarStereographic"); + + cout << "Test missing center longitude keyword ..." << endl; + try { + Isis::PolarStereographic p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + mg += Isis::PvlKeyword("CenterLongitude",-100.0); + + cout << "Test missing center latitude keyword ..." << endl; + try { + Isis::PolarStereographic p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + cout << "Test invalid center latitude keyword ..." << endl; + mg += Isis::PvlKeyword("CenterLatitude",0.0); + try { + Isis::PolarStereographic p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + mg.AddKeyword(Isis::PvlKeyword("CenterLatitude",-71.0),Isis::PvlGroup::Replace); + + try { + Isis::Projection &p = *Isis::ProjectionFactory::Create(lab); + // Isis::PolarStereographic p(lab); + + cout << "Test SetGround method ... " << endl; + cout << "Setting ground to (-75,150)" << endl; + p.SetGround(-75.0,150.0); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + + cout << "Test SetCoordinate method ... " << endl; + cout << "Setting coordinate to (-1540033.620970689,-560526.3978025292)" << endl; + p.SetCoordinate(-1540033.620970689,-560526.3978025292); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + cout << "Test XYRange method ... " << endl; + double minX,maxX,minY,maxY; + p.XYRange(minX,maxX,minY,maxY); + cout << "Minimum X: " << minX << endl; + cout << "Maximum X: " << maxX << endl; + cout << "Minimum Y: " << minY << endl; + cout << "Maximum Y: " << maxY << endl; + cout << endl; + + cout << "Test TrueScaleLatitude method... " << endl; + cout << "TrueScaleLatitude = " << p.TrueScaleLatitude() << endl; + cout << endl; + + Isis::Projection *s = &p; + cout << "Test Name and comparision method ... " << endl; + cout << "Name: " << s->Name() << endl; + cout << "operator== " << (*s == *s) << endl; + cout << endl; + + cout << "Test default computation ... " << endl; + mg.DeleteKeyword("CenterLongitude"); + mg.DeleteKeyword("CenterLatitude"); + Isis::PolarStereographic p2(lab,true); + cout << lab << endl; + cout << endl; + + cout << "Testing Mapping() methods ... " << endl; + + Isis::Pvl tmp1; + Isis::Pvl tmp2; + Isis::Pvl tmp3; + tmp1.AddGroup(p.Mapping()); + tmp2.AddGroup(p.MappingLatitudes()); + tmp3.AddGroup(p.MappingLongitudes()); + + cout << "Mapping() = " << endl; + cout << tmp1 << endl; + cout << "MappingLatitudes() = " << endl; + cout << tmp2 << endl; + cout << "MappingLongitudes() = " << endl; + cout << tmp3 << endl; + cout << endl; + + cout << "Unit test was obtained from:" << endl << endl; + cout << " Map Projections - A Working Manual" << endl; + cout << " USGS Professional Paper 1395 by John P. Snyder" << endl; + cout << " Pages 315-319" << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } +} diff --git a/isis/src/base/objs/PolygonSeeder/Makefile b/isis/src/base/objs/PolygonSeeder/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..96ea213468b13df9711ca79e4888cd2b1d6a2856 --- /dev/null +++ b/isis/src/base/objs/PolygonSeeder/Makefile @@ -0,0 +1,5 @@ +INCS = $(wildcard PolygonSeeder*.h) +SRCS = $(wildcard PolygonSeeder*.cpp) +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PolygonSeeder/PolygonSeeder.cpp b/isis/src/base/objs/PolygonSeeder/PolygonSeeder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e59bbcee79e78f89fa51893161049d87b8359d6 --- /dev/null +++ b/isis/src/base/objs/PolygonSeeder/PolygonSeeder.cpp @@ -0,0 +1,202 @@ +#include "Pvl.h" +#include "PvlGroup.h" +#include "Plugin.h" +#include "iException.h" +#include "PolynomialBivariate.h" +#include "LeastSquares.h" +#include "Filename.h" +#include "ProjectionFactory.h" +#include "PolygonTools.h" + +#include "PolygonSeeder.h" + + +namespace Isis { + /** + * Create PolygonSeeder object. Because this is a pure virtual class you can + * not create an PolygonSeeder class directly. Instead, see the + * PolygonSeederFactory class. + * + * @param pvl A pvl object containing a valid PolygonSeeder specification + * + * @todo + */ + PolygonSeeder::PolygonSeeder (Pvl &pvl) { + invalidInput = NULL; + invalidInput = new Pvl(pvl); + + p_algorithmName = "Unknown"; + + Parse(pvl); + } + + + //! Copy constructor + PolygonSeeder::PolygonSeeder(const PolygonSeeder & other) { + p_algorithmName = other.p_algorithmName; + p_minimumThickness = other.p_minimumThickness; + p_minimumArea = other.p_minimumArea; + } + + + //! Destroy PolygonSeeder object + PolygonSeeder::~PolygonSeeder() { + if (invalidInput) { + delete invalidInput; + invalidInput = NULL; + } + } + + + /** + * Initialize parameters in the PolygonSeeder class using a PVL specification. + * An example of the PVL required for this is: + * + * @code + * Object = AutoSeed + * Group = Algorithm + * Name = Grid + * Tolerance = 0.7 + * EndGroup + * EndObject + * @endcode + * + * There are many other options that can be set via the pvl and are + * described in other documentation (see below). + * + * @param pvl The pvl object containing the specification + **/ + void PolygonSeeder::Parse(Pvl &pvl) { + + std::string errorSpot; + + try { + // Get info from Algorithm group + errorSpot = "Algorithm"; + PvlGroup &algo = pvl.FindGroup("PolygonSeederAlgorithm",Pvl::Traverse); + + // algo is such a cool name for a PvlGroup that it begs to be out done + PvlGroup & invalgo = invalidInput->FindGroup("PolygonSeederAlgorithm", + Pvl::Traverse); + + // Set the algorithm name + errorSpot = "Name"; + p_algorithmName = (std::string) algo["Name"]; + + if (invalgo.HasKeyword("Name")) + invalgo.DeleteKeyword("Name"); + + // Set the minimum thickness (Area / max(extent X, extent Y)**2 + errorSpot = "MinimumThickness"; + p_minimumThickness = 0.0; + if (algo.HasKeyword("MinimumThickness")) { + p_minimumThickness = (double) algo["MinimumThickness"]; + } + + if (invalgo.HasKeyword("MinimumThickness")) + invalgo.DeleteKeyword("MinimumThickness"); + + // Set the minimum area + errorSpot = "MinimumArea"; + p_minimumArea = 0.0; + if (algo.HasKeyword("MinimumArea")) { + p_minimumArea = (double) algo["MinimumArea"]; + } + + if (invalgo.HasKeyword("MinimumArea")) + invalgo.DeleteKeyword("MinimumArea"); + } + catch (iException &e) { + std::string msg = "Improper format for PolygonSeeder PVL ["; + msg += pvl.Filename() + "]. Location [" + errorSpot + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + return; + } + + + /** + * Check the polygon to see if it meets standard criteria. + * + * @param xymp The multipoly containing the coordinates in x/y units instead + * of lon/lat + * @param xyBoundBox The bounding box of the multipoly + * + * @return std::string A string with an appropriate message to throw if + * a test was unsuccessful or an empty string if all tests passed. + */ + std::string PolygonSeeder::StandardTests(const geos::geom::MultiPolygon *xymp, + const geos::geom::Envelope *xyBoundBox) { + if (xymp->getArea() < MinimumArea()) { + std::string msg = "Polygon did not meet the minimum area of ["; + msg += Isis::iString(MinimumArea()) + "]"; + return msg; + } + + double thickness = + xymp->getArea() / + pow(std::max(xyBoundBox->getWidth(), xyBoundBox->getHeight()), 2.0); + if (thickness < MinimumThickness()) { + std::string msg = "Polygon did not meet the minimum thickness ratio of ["; + msg += Isis::iString(MinimumThickness()) + "]"; + return msg; + } + + return ""; + } + + + /** + * Return the minimum allowed thickness of the polygon. This value is set + * from the "MinimumThickness" keyword in the PVL. The seeding algorithm + * will not seed polygons that have a thickness ratio less than this + */ + double PolygonSeeder::MinimumThickness() { + return p_minimumThickness; + } + + + /** + * Return the minimum allowed area of the polygon. This value is set + * from the "MinimumArea" keyword in the PVL. The seeding algorithm will + * not seed polygons that have an area less than this. + */ + double PolygonSeeder::MinimumArea() { + return p_minimumArea; + } + + PvlGroup PolygonSeeder::PluginParameters(std::string grpName) { + PvlGroup pluginInfo(grpName); + + PvlKeyword name("Name", p_algorithmName); + PvlKeyword minThickness("MinimumThickness", p_minimumThickness); + PvlKeyword minArea("MinimumArea", p_minimumArea); + + pluginInfo.AddKeyword(name); + pluginInfo.AddKeyword(minThickness); + pluginInfo.AddKeyword(minArea); + + return pluginInfo; + } + + + /** + * The constructor was passed a pvl (from a def file probably) + * Returns a copy of this pvl minus what was used + */ + Pvl PolygonSeeder::InvalidInput() { + return *invalidInput; + } + + + //! Assignment operator + const PolygonSeeder & PolygonSeeder::operator=(const PolygonSeeder & other) { + p_algorithmName = other.p_algorithmName; + p_minimumThickness = other.p_minimumThickness; + p_minimumArea = other.p_minimumArea; + + return *this; + } + +} diff --git a/isis/src/base/objs/PolygonSeeder/PolygonSeeder.h b/isis/src/base/objs/PolygonSeeder/PolygonSeeder.h new file mode 100644 index 0000000000000000000000000000000000000000..93f826f601e81267212dcac20defc3d80c38a9ab --- /dev/null +++ b/isis/src/base/objs/PolygonSeeder/PolygonSeeder.h @@ -0,0 +1,89 @@ +#ifndef PolygonSeeder_h +#define PolygonSeeder_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/05/05 21:22:10 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "geos/geom/Point.h" +#include "geos/geom/MultiPolygon.h" + +#include "Projection.h" + +namespace Isis { + class Pvl; + class PolygonTools; + + /** + * This class is used as the base class for all PolygonSeeder objects. The + * class is pure virtual. + * + * @ingroup PatternMatching + * + * @author 2006-01-20 Stuart Sides + * + * @history 2008-08-18 Christopher Austin - Upgraded to + * geos3.0.0, removed Chip.h include, fixed ifndef + * @history 2009-08-05 Travis Addair - Encapsulated group + * creation for seed definition group + * @history 2009-04-15 Eric Hyer - Now stores invalid input + * - Added Copy constructor, destructor, and + * assignment operator + * @history 2010-04-20 Christopher Austin - adapted for generic/unitless + * seeding + */ + class PolygonSeeder { + public: + PolygonSeeder(Pvl &pvl); + PolygonSeeder(const PolygonSeeder & other); + virtual ~PolygonSeeder(); + + virtual std::vector Seed(const geos::geom::MultiPolygon *mp) = 0; + + std::string Name(); + double MinimumThickness(); + double MinimumArea(); + inline std::string Algorithm() const { return p_algorithmName; } + virtual PvlGroup PluginParameters(std::string grpName); + Pvl InvalidInput(); + + const PolygonSeeder & operator=(const PolygonSeeder & other); + + protected: + virtual void Parse(Pvl &pvl); + std::string StandardTests(const geos::geom::MultiPolygon *multiPoly, + const geos::geom::Envelope *polyBoundBox); + + protected: + Pvl * invalidInput; + + private: + std::string p_algorithmName; + double p_minimumThickness; + double p_minimumArea; + + }; +}; + +#endif diff --git a/isis/src/base/objs/PolygonSeeder/PolygonSeeder.truth b/isis/src/base/objs/PolygonSeeder/PolygonSeeder.truth new file mode 100644 index 0000000000000000000000000000000000000000..de7922e8e2b36e5b3c8ca09dd0a8d83c95863128 --- /dev/null +++ b/isis/src/base/objs/PolygonSeeder/PolygonSeeder.truth @@ -0,0 +1,22 @@ +Object = AutoSeed + Group = PolygonSeederAlgorithm + Name = Grid + MinimumThickness = 0.5 + MinimumArea = 10 + XSpacing = 11 + YSpacing = 11 + End_Group +End_Object +End + +Test invalidInput() ... +Object = AutoSeed + Group = PolygonSeederAlgorithm + End_Group +End_Object +End + +Test to make sure Parse did it's job +MinimumThickness = 0.5 +MinimumArea = 10 +No reason to test GridPolygonSeeder, so we're done diff --git a/isis/src/base/objs/PolygonSeeder/unitTest.cpp b/isis/src/base/objs/PolygonSeeder/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ed05520460c4c3a55b3aae8400de7b59cbda69a --- /dev/null +++ b/isis/src/base/objs/PolygonSeeder/unitTest.cpp @@ -0,0 +1,49 @@ +#include +#include + +#include "iException.h" +#include "PolygonSeeder.h" +#include "PolygonSeederFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Preference.h" + +using namespace Isis; +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + + try { + PvlGroup alg("PolygonSeederAlgorithm"); + alg += PvlKeyword("Name","Grid"); + alg += PvlKeyword("MinimumThickness", 0.5); + alg += PvlKeyword("MinimumArea", 10); + alg += PvlKeyword("XSpacing", 11); + alg += PvlKeyword("YSpacing", 11); + + PvlObject o("AutoSeed"); + o.AddGroup(alg); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl << std::endl; + + PolygonSeeder *ps = PolygonSeederFactory::Create(pvl); + + Pvl p = ps->InvalidInput(); + cout << "Test invalidInput() ...\n" << p << "\n\n"; + + std::cout << "Test to make sure Parse did it's job" << std::endl; + std::cout << "MinimumThickness = " << ps->MinimumThickness() << std::endl; + std::cout << "MinimumArea = " << ps->MinimumArea() << std::endl; + + std::cout << "No reason to test GridPolygonSeeder, so we're done" << std::endl; + + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/PolygonSeederFactory/Makefile b/isis/src/base/objs/PolygonSeederFactory/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6b1c13e847bf2a932e6a191b5747d5a4ca53b304 --- /dev/null +++ b/isis/src/base/objs/PolygonSeederFactory/Makefile @@ -0,0 +1,5 @@ +INCS = PolygonSeederFactory.h +SRCS = PolygonSeederFactory.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PolygonSeederFactory/PolygonSeederFactory.cpp b/isis/src/base/objs/PolygonSeederFactory/PolygonSeederFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..49c5280e3284de56fb5927657c66b2f5aaf00d1d --- /dev/null +++ b/isis/src/base/objs/PolygonSeederFactory/PolygonSeederFactory.cpp @@ -0,0 +1,72 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/12/17 21:43:53 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PolygonSeederFactory.h" +#include "Plugin.h" +#include "iException.h" +#include "Filename.h" + +namespace Isis { + /** + * Create a PolygonSeeder object using a PVL specification. + * An example of the PVL required for this is: + * + * @code + * Object = AutoSeed + * Group = PolygonSeederAlgorithm + * Name = Grid + * Tolerance = 0.7 + * EndGroup + * + * Group = InterestOperatorAlgorithm + * Name = StandardDeviation + * Tolerance = 10 + * EndGroup + * + * EndObject + * @endcode + * + * @param pvl The pvl object containing the PolygonSeeder specification + * + **/ + PolygonSeeder *PolygonSeederFactory::Create(Pvl &pvl) { + // Get the algorithm name to create + PvlGroup &algo = pvl.FindGroup("PolygonSeederAlgorithm",Pvl::Traverse); + std::string algorithm = algo["Name"]; + + // Open the factory plugin file + Plugin p; + Filename f("PolygonSeeder.plugin"); + if (f.Exists()) { + p.Read("PolygonSeeder.plugin"); + } + else { + p.Read("$ISISROOT/lib/PolygonSeeder.plugin"); + } + + // Get the algorithm specific plugin and return it + PolygonSeeder* (*plugin) (Pvl &pvl); + plugin = (PolygonSeeder * (*)(Pvl &pvl)) p.GetPlugin(algorithm); + return (*plugin)(pvl); + } +} // end namespace isis diff --git a/isis/src/base/objs/PolygonSeederFactory/PolygonSeederFactory.h b/isis/src/base/objs/PolygonSeederFactory/PolygonSeederFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..21654a148bf100dc580205d69ffb1e73a45818e6 --- /dev/null +++ b/isis/src/base/objs/PolygonSeederFactory/PolygonSeederFactory.h @@ -0,0 +1,80 @@ +#if !defined(PolygonSeederFactory_h) +#define PolygonSeederFactory_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/12/17 21:43:54 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { + class Pvl; + class PolygonSeeder; + + /** + * This class is used to create PolygonSeeder objects. Applications which + * use autoseeding of points in polygons can use different techniques such as + * Grid or ????. If this factory is given a Pvl + * object which contains a PolygonSeeder definition it will create that specific + * instance of the class. For example, + * + * @code + * Object = PolygonSeeder + * Group = Algorithm + * Name = Grid + * ... + * EndGroup + * ... + * EndObject + * End + * @endcode + * + * Will create a GridPolygonSeeder object (which is derived from PolygonSeeder). + * The simplest way to create an PolygonSeeder class is to use the static Create + * method + * + * @code + * Pvl p("myPolygonSeeder.pvl"); + * PolygonSeeder *ps = PolygonSeederFactory::Create(p); + * @endcode + * + * @ingroup PatternMatching + * + * @author 2006-01-20 Stuart Sides + * + * @internal + * @history 2008-12-17 Christopher Austin - Fixed memory leak + */ + class PolygonSeederFactory { + public: + static PolygonSeeder *Create(Pvl &pvl); + + private: + /** + * Constructor (its private so you can't use it). Use the Create Method + * instead. + */ + PolygonSeederFactory() {}; + + //! Destroys the PolygonSeederFactory + ~PolygonSeederFactory() {}; + }; +}; + +#endif diff --git a/isis/src/base/objs/PolygonSeederFactory/PolygonSeederFactory.truth b/isis/src/base/objs/PolygonSeederFactory/PolygonSeederFactory.truth new file mode 100644 index 0000000000000000000000000000000000000000..b07c36a6d5a16fecb63ece02a8de248446f93a65 --- /dev/null +++ b/isis/src/base/objs/PolygonSeederFactory/PolygonSeederFactory.truth @@ -0,0 +1 @@ +All testing differed to PolygonSeeder and it's extended classes. diff --git a/isis/src/base/objs/PolygonSeederFactory/unitTest.cpp b/isis/src/base/objs/PolygonSeederFactory/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e812b010a73861b96a9f278ab6be17023b934dd0 --- /dev/null +++ b/isis/src/base/objs/PolygonSeederFactory/unitTest.cpp @@ -0,0 +1,13 @@ +#include +#include + +#include "Preference.h" + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + + cout << "All testing differed to PolygonSeeder and it's extended classes." << endl; + return 0; +} diff --git a/isis/src/base/objs/PolygonTools/Makefile b/isis/src/base/objs/PolygonTools/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b60d597c9edd0fd4c36f2ea0477c583964c980d8 --- /dev/null +++ b/isis/src/base/objs/PolygonTools/Makefile @@ -0,0 +1,5 @@ +INCS = PolygonTools.h +SRCS = PolygonTools.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PolygonTools/PolygonTools.cpp b/isis/src/base/objs/PolygonTools/PolygonTools.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f0cfddcdb6befd1c805ccdceb9a2aaa1e3b1d5d --- /dev/null +++ b/isis/src/base/objs/PolygonTools/PolygonTools.cpp @@ -0,0 +1,1743 @@ +/** + * @file + * $Revision: 1.26 $ + * $Date: 2010/02/24 01:11:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +#include +#include +#include +#include +#include +#include + +#include "geos/geom/BinaryOp.h" +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/geom/LinearRing.h" +#include "geos/geom/Point.h" +#include "geos/geom/Polygon.h" +#include "geos/operation/distance/DistanceOp.h" +#include "geos/opOverlay.h" +#include "geos/operation/overlay/snap/GeometrySnapper.h" + +#include "SpecialPixel.h" +#include "PolygonTools.h" +#include "ProjectionFactory.h" +#include "UniversalGroundMap.h" + +using namespace std; +namespace Isis { + /** + * This method will return a geos::geom::MultiPolygon which contains the X/Y + * coordinates of the LonLat polygon. The Lat/Lon polygon must + * have coordinates (x direction, y direction) or (Lon,Lat). + * + * @param lonLatPolygon A multipolygon in (Lon,Lat) order + * @param projection The projection to be used to convert the Lons and Lat + * to X and Y + * + * @return Returns a multipolygon which is the result of converting the input + * multipolygon from (Lon,Lat) to (X,Y). + */ + geos::geom::MultiPolygon *PolygonTools::LatLonToXY( + const geos::geom::MultiPolygon &lonLatPolygon, Projection *projection) { + if (projection == NULL) { + string msg = "Unable to convert Lon/Lat polygon to X/Y. "; + msg += "No projection has was supplied"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Convert the Lat/Lon poly coordinates to X/Y coordinates + if (lonLatPolygon.isEmpty()) { + return globalFactory.createMultiPolygon(); + } + else { + vector *xyPolys = new vector; + // Convert each polygon in this multi-polygon + for (unsigned int g=0; g *holes = new vector; + for (unsigned int h=0; hgetNumInteriorRing(); ++h) { + geos::geom::CoordinateSequence *xycoords = new geos::geom::CoordinateArraySequence (); + geos::geom::CoordinateSequence *llcoords = + poly->getInteriorRingN(h)->getCoordinates(); + + // Convert each coordinate in this hole + for (unsigned int cord=0; cord < llcoords->getSize(); ++cord) { + projection->SetGround(llcoords->getAt(cord).y, + llcoords->getAt(cord).x); + xycoords->add(geos::geom::Coordinate(projection->XCoord(), + projection->YCoord())); + } // end num coords in hole loop + + geos::geom::LinearRing *hole = globalFactory.createLinearRing(xycoords); + + if(hole->isValid() && !hole->isEmpty()) { + holes->push_back(hole); + } + else { + delete hole; + } + } // end num holes in polygon loop + + // Convert the exterior ring of this polygon + geos::geom::CoordinateSequence *xycoords = new geos::geom::CoordinateArraySequence (); + geos::geom::CoordinateSequence *llcoords = + poly->getExteriorRing()->getCoordinates(); + + // Convert each coordinate in the exterior ring of this polygon + for (unsigned int cord=0; cord < llcoords->getSize(); ++cord) { + projection->SetGround(llcoords->getAt(cord).y, + llcoords->getAt(cord).x); + xycoords->add(geos::geom::Coordinate(projection->XCoord(), + projection->YCoord())); + } // end exterior ring coordinate loop + + geos::geom::Polygon *newPoly = globalFactory.createPolygon( + globalFactory.createLinearRing(xycoords), holes); + + if(newPoly->isValid() && !newPoly->isEmpty() && newPoly->getArea() > 1.0e-14) { + xyPolys->push_back(newPoly); + } + else { + delete newPoly; + } + } // end num geometry in multi-poly + + // Create a new multipoly from all the new X/Y polygon(s) + geos::geom::MultiPolygon *spikedPoly = globalFactory.createMultiPolygon(xyPolys); + + if(spikedPoly->isValid() && !spikedPoly->isEmpty()) { + return spikedPoly; + } + else { + try { + geos::geom::MultiPolygon *despikedPoly = Despike(spikedPoly); + + delete spikedPoly; + spikedPoly = NULL; + + return despikedPoly; + } + catch (iException &e) { + iString msg = "Unable to convert polygon from Lat/Lon to X/Y"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + } // end else + } + + + /** + * This method will return a geos::geom::MultiPolygon which contains the + * (Lon,Lat) coordinates of the XY polygon. The Lat/Lon polygon will + * have coordinates (x direction, y direction) or (Lon,Lat). + * + * @param xYPolygon A multipolygon in (X,Y) order + * @param projection The projection to be used to convert the Xs and Ys to Lon + * and Lats + * + * @return Returns a multipolygon which is the result of converting the input + * multipolygon from (X,Y) to (Lon,Lat). + */ + geos::geom::MultiPolygon *PolygonTools::XYToLatLon( + const geos::geom::MultiPolygon &xYPolygon, Projection *projection) { + + if (projection == NULL) { + string msg = "Unable to convert X/Y polygon to Lon/Lat. "; + msg += "No projection was supplied"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Convert the X/Y poly coordinates to Lat/Lon coordinates + if (xYPolygon.isEmpty()) { + return globalFactory.createMultiPolygon(); + } + else { + vector *llPolys = new vector; + // Convert each polygon in this multi-polygon + for (unsigned int g=0; g *holes = new vector; + for (unsigned int h=0; hgetNumInteriorRing(); ++h) { + geos::geom::CoordinateSequence *llcoords = new geos::geom::CoordinateArraySequence (); + geos::geom::CoordinateSequence *xycoords = + poly->getInteriorRingN(h)->getCoordinates(); + + // Convert each coordinate in this hole + for (unsigned int cord=0; cord < xycoords->getSize(); ++cord) { + projection->SetWorld(xycoords->getAt(cord).x, + xycoords->getAt(cord).y); + llcoords->add(geos::geom::Coordinate(projection->Longitude(), + projection->Latitude())); + } // end num coords in hole loop + holes->push_back(globalFactory.createLinearRing(llcoords)); + } // end num holes in polygon loop + + // Convert the exterior ring of this polygon + geos::geom::CoordinateSequence *llcoords = new geos::geom::DefaultCoordinateSequence (); + geos::geom::CoordinateSequence *xycoords = + poly->getExteriorRing()->getCoordinates(); + + // Convert each coordinate in the exterior ring of this polygon + for (unsigned int cord=0; cord < xycoords->getSize(); ++cord) { + projection->SetWorld(xycoords->getAt(cord).x, + xycoords->getAt(cord).y); + llcoords->add(geos::geom::Coordinate(projection->Longitude(), + projection->Latitude())); + } // end exterior ring coordinate loop + + llPolys->push_back(globalFactory.createPolygon( + globalFactory.createLinearRing(llcoords), holes)); + } // end num geometry in multi-poly + + + // Create a new multipoly from all the new Lat/Lon polygon(s) + geos::geom::MultiPolygon *spikedPoly = globalFactory.createMultiPolygon(llPolys); + + if(spikedPoly->isValid() && !spikedPoly->isEmpty()) { + return spikedPoly; + } + else { + try { + geos::geom::MultiPolygon *despikedPoly = Despike(spikedPoly); + + delete spikedPoly; + spikedPoly = NULL; + + return despikedPoly; + } + catch (iException &e) { + iString msg = "Unable to convert polygon from X/Y to Lat/Lon"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + } // end else + } + + + /** + * This method will return a geos::geom::MultiPolygon which contains the + * sample/line coordinates of the Lat/Lon polygon. The Lat/Lon polygon must + * have coordinates (x direction, y direction) or (Lon,Lat). + * + * @param lonLatPolygon A multipolygon in (Lon,Lat order) + * @param ugm The UniversalGroundMap to be used to convert the Lons + * and Lat to Samples and Lines + * + * @return Returns a multipolygon which is the result of converting the input + * multipolygon from (Lon,Lat) to (Sample,Line). + */ + geos::geom::MultiPolygon *PolygonTools::LatLonToSampleLine( + const geos::geom::MultiPolygon &lonLatPolygon, UniversalGroundMap *ugm) { + + if (ugm == NULL) { + string msg = "Unable to convert Lon/Lat polygon to Sample/Line. "; + msg += "No UniversalGroundMap was supplied"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Convert the Lon/Lat poly coordinates to Sample/Line coordinates + if (lonLatPolygon.isEmpty()) { + return globalFactory.createMultiPolygon(); + } + else { + vector *slPolys = new vector; + // Convert each polygon in this multi-polygon + for (unsigned int g = 0; g < lonLatPolygon.getNumGeometries(); g++) { + geos::geom::Polygon *poly = (geos::geom::Polygon*)(lonLatPolygon.getGeometryN(g)); + + // Convert each hole inside this polygon + vector *holes = new vector; + for (unsigned int h=0; hgetNumInteriorRing(); ++h) { + geos::geom::CoordinateSequence *slcoords = new geos::geom::DefaultCoordinateSequence (); + geos::geom::CoordinateSequence *llcoords = + poly->getInteriorRingN(h)->getCoordinates(); + + // Convert each coordinate in this hole + for (unsigned int cord=0; cord < llcoords->getSize(); ++cord) { + ugm->SetUniversalGround(llcoords->getAt(cord).y, + llcoords->getAt(cord).x); + slcoords->add(geos::geom::Coordinate(ugm->Sample(), + ugm->Line())); + } // end num coords in hole loop + holes->push_back(globalFactory.createLinearRing(slcoords)); + delete slcoords; + delete llcoords; + } // end num holes in polygon loop + + // Convert the exterior ring of this polygon + geos::geom::CoordinateSequence *slcoords = new geos::geom::CoordinateArraySequence (); + geos::geom::CoordinateSequence *llcoords = + poly->getExteriorRing()->getCoordinates(); + + // Convert each coordinate in the exterior ring of this polygon + for (unsigned int cord=0; cord < llcoords->getSize(); ++cord) { + ugm->SetUniversalGround(llcoords->getAt(cord).y, + llcoords->getAt(cord).x); + slcoords->add(geos::geom::Coordinate(ugm->Sample(), + ugm->Line())); + } // end exterior ring coordinate loop + + slPolys->push_back(globalFactory.createPolygon( + globalFactory.createLinearRing(slcoords), holes)); + delete llcoords; + } // end num geometry in multi-poly + + // Create a new multipoly from all the new Sample/Line polygon(s) + geos::geom::MultiPolygon *spikedPoly = globalFactory.createMultiPolygon(slPolys); + + if(spikedPoly->isValid() && !spikedPoly->isEmpty()) { + return spikedPoly; + } + else { + try { + geos::geom::MultiPolygon *despikedPoly = Despike(spikedPoly); + + delete spikedPoly; + spikedPoly = NULL; + + return despikedPoly; + } + catch (iException &e) { + iString msg = "Unable to convert polygon from Lat/Lon to Sample/Line"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + } // end else + } + + + /** + * This static method will create a deep copy of a geos::geom::MultiPolygon. The + * caller assumes responsibility for the memory associated with the new + * polygon. + * + * @param mpolygon The multipolygon to be copied. + * + * @return Returns a pointer to a multipolygon which is a deep copy of the + * input multipolygon. This is necessary because at the time of + * writing the geos package does not create multipolygons when + * copying. It produdes geometryCollections + */ + geos::geom::MultiPolygon* PolygonTools::CopyMultiPolygon(const geos::geom::MultiPolygon *mpolygon) { + + vector *polys = new vector; + for (unsigned int i=0; igetNumGeometries(); ++i) { + polys->push_back((mpolygon->getGeometryN(i))->clone()); + } + return globalFactory.createMultiPolygon (polys); + } + + + /** + * This static method will create a deep copy of a geos::geom::MultiPolygon. The + * caller assumes responsibility for the memory associated with the new + * polygon. + * + * @param mpolygon The multipolygon to be copied. + * + * @return Returns a pointer to a multipolygon which is a deep copy of the + * input multipolygon. This is necessary because at the time of + * writing the geos package does not create multipolygons when + * copying. It produdes geometryCollections + */ + geos::geom::MultiPolygon* PolygonTools::CopyMultiPolygon(const geos::geom::MultiPolygon &mpolygon) { + + vector *polys = new vector; + for (unsigned int i=0; ipush_back((mpolygon.getGeometryN(i))->clone()); + } + return globalFactory.createMultiPolygon (polys); + } + + + /** + * Write out the polygon with gml header + * + * + * @param [in] mpolygon Polygon with lat/lon vertices + * @param idString mpolygon's Id + * @return istrean Returns the polygon with lon,lat + * lon,lat format vertices and GML header + */ + + string PolygonTools::ToGML (const geos::geom::MultiPolygon *mpolygon, string idString) { + + ostringstream os; + + //Write out the GML header + os << "" << endl; + os << "" << endl; + os << " " << endl; + os << " " << endl; + os << " 0.0-90.0" << endl; + os << " 360.090.0" << endl; + os << " " << endl; + os << " " << endl; + os << " " << endl; + os << " " << endl; + os << " "<< idString << "" << endl; + os << " " << + ""; + + + for (unsigned int polyN=0; polyNgetNumGeometries(); polyN++) { + geos::geom::CoordinateSequence *pts = mpolygon->getGeometryN(polyN)->getCoordinates(); + + for (unsigned int i=0; igetSize(); i++) { + double lon = pts->getAt(i).x; + double lat = pts->getAt(i).y; + + os << setprecision(15) << lon << ","<< setprecision(15) << lat << " "; + } + } + + os <<""<< + ""<< + "" << endl; + os << "" << endl; + os << "" << endl; + os << "" << endl; + + return os.str(); + } + + + /** + * Convert polygon coordinates from 360 system to 180. If polygon is split + * into 2 polygons due to crossing the 360 boundary, convert the polygon + * less than 360 to 180, then union together to merge the polygons. + * If the polygon was one poly, but crosses the -180/180 + * boundary after it's converted, then we need to split it up to + * 2 polygons before we return the multipolygon. + * + * @param[in] poly360 (geos::geom::MultiPolygon) polys split by 360 boundary + * + * @return geos::geom::MultiPolygon Returns a single polygon (Note: Longitude + * coordinates will be less than 0. + */ + + geos::geom::MultiPolygon *PolygonTools::To180 (geos::geom::MultiPolygon *poly360) { + + geos::geom::CoordinateSequence *convPts; + std::vector polys; + bool greater180 = false; + bool less180 = false; + //--------------------------------------------------------------------- + //We need to know if the poly360 came in as 1 or 2 polygons. + //If it came in as 2 polys, then we need to union it before we return + //because it was a polygon that crossed the 0/360 boundary. + //--------------------------------------------------------------------- + int initialNumPolys = poly360->getNumGeometries(); + + //------------------------------------------------------------------------ + // If single poly, and points in the single polygon are less than + // 180 AND greater than 180, then we know we need to split this polygon up. + //------------------------------------------------------------------------ + if (initialNumPolys == 1) { + convPts = poly360->getGeometryN(0)->getCoordinates(); + + //----------------------------------------------------------------- + //Handling the case when a polygon will cross the -180/180 boundary + //----------------------------------------------------------------- + for (unsigned int i = 0; i < convPts->getSize(); i++) { + if (convPts->getAt(i).x > 180) greater180 = true; + if (convPts->getAt(i).x < 180) less180 = true; + } + + //----------------------------------------------------------------------- + // IF we do have a poly that crosses the -180/180 bndry... + // THEN go thru the convPts and if any points are greater than 180, then + // we'll put the > 180 in one poly and the < 180 in another poly and + // convert both. + //---------------------------------------------------------------------- + if (greater180 && less180) { + geos::geom::CoordinateSequence *pts1 = new geos::geom::DefaultCoordinateSequence (); + geos::geom::CoordinateSequence *pts2 = new geos::geom::DefaultCoordinateSequence (); + std::vector case4polys; + for (unsigned int i = 0; i < convPts->getSize(); i++) { + if (convPts->getAt(i).x <= 180) { + pts1->add (geos::geom::Coordinate(convPts->getAt(i).x,convPts->getAt(i).y)); + } + if (convPts->getAt(i).x >= 180) { + pts2->add (geos::geom::Coordinate(convPts->getAt(i).x,convPts->getAt(i).y)); + } + } + + pts1->add (geos::geom::Coordinate(pts1->getX(0),pts1->getY(0))); + pts2->add (geos::geom::Coordinate(pts2->getX(0),pts2->getY(0))); + + case4polys.push_back (Isis::globalFactory.createPolygon + (Isis::globalFactory.createLinearRing(pts1),NULL)); + case4polys.push_back (Isis::globalFactory.createPolygon + (Isis::globalFactory.createLinearRing(pts2),NULL)); + poly360 = Isis::globalFactory.createMultiPolygon (case4polys); + } + } + + //-------------------------------------------------------- + // If we still only have one single poly, simply convert + // coordinates to 180 system + //-------------------------------------------------------- + if (poly360->getNumGeometries() == 1) { + convPts = poly360->getGeometryN(0)->getCoordinates(); + } + else { + // Find the poly that needs to be converted to 180 coordinates + if ((poly360->getGeometryN(0)->getCoordinate()->x - + poly360->getGeometryN(1)->getCoordinate()->x) > 0) { + polys.push_back(poly360->getGeometryN(1)->clone()); + convPts = poly360->getGeometryN(0)->getCoordinates(); + } + else { + polys.push_back(poly360->getGeometryN(0)->clone()); + convPts = poly360->getGeometryN(1)->getCoordinates(); + for (unsigned int i=0; igetSize(); i++) { + } + } + } + + //Convert poly to greater than 180 + geos::geom::CoordinateSequence *newPts = new geos::geom::CoordinateArraySequence(); + for (unsigned int i=0; igetSize(); i++) { + if(convPts->getAt(i).x > 180){ + newPts->add (geos::geom::Coordinate(convPts->getAt(i).x - 360.,convPts->getAt(i).y)); + } else { + newPts->add (geos::geom::Coordinate(convPts->getAt(i).x,convPts->getAt(i).y)); + } + } + + polys.push_back (Isis::globalFactory.createPolygon + (Isis::globalFactory.createLinearRing(newPts),NULL)); + + //-------------------------------------------------------------- + //If the poly360 was initially 2 polygons, then we know that we + //need to union them now. + //-------------------------------------------------------------- + if(initialNumPolys > 1) { + geos::geom::GeometryCollection *polyCollection = + Isis::globalFactory.createGeometryCollection(polys); + geos::geom::Geometry *unionPoly = polyCollection->buffer(0); + return (geos::geom::MultiPolygon *) unionPoly; + } else { + return Isis::globalFactory.createMultiPolygon (polys); + } + } + + + /** + * Calculates the thickness of a polygon using: + * thickness = area / max(Xextent,Yextent)**2 + * The provided polygon SHOULD be an XY polygon, not a lat/lon polygon, but this + * is not enforced. + * + * @param mpolygon The XY polygon to calculate the thickness of + * + * @return double The thikness of the provided polygon + */ + double PolygonTools::Thickness(const geos::geom::MultiPolygon *mpolygon ) { + const geos::geom::Envelope *envelope = mpolygon->getEnvelopeInternal(); + + double x = fabs( envelope->getMaxX() - envelope->getMinX() ); + double y = fabs( envelope->getMaxY() - envelope->getMinY() ); + double extent = max( x, y ); + + return mpolygon->getArea() / (extent*extent); + } + + + /** + * This method attempts to convert the geom to a MultiPolygon and then despike + * it. + * + * This method does not take ownership of the argument geom. The ownership + * of the return value is given to the caller. + * + * @param geom + * + * @return geos::geom::MultiPolygon* + */ + geos::geom::MultiPolygon* PolygonTools::Despike (const geos::geom::Geometry *geom) { + geos::geom::MultiPolygon *spiked = MakeMultiPolygon(geom); + geos::geom::MultiPolygon *despiked = Despike(spiked); + + delete spiked; + spiked = NULL; + + return despiked; + } + + /** + * Create a new multipolygon without the spikes associated with + * some versions of the geos package. + * + * This method does not take ownership of the argument multiPoly. The ownership + * of the return value is given to the caller. + * + * @param multiPoly The original geos::geom::MultiPolygon to be despiked. + * + */ + geos::geom::MultiPolygon* PolygonTools::Despike (const geos::geom::MultiPolygon *multiPoly) { + // Despike each polygon in the multipolygon + vector *newPolys = new vector; + for (unsigned int g=0; ggetNumGeometries(); ++g) { + geos::geom::Polygon *poly = (geos::geom::Polygon*)(multiPoly->getGeometryN(g)); + + // Despike each hole inside this polygon + vector *holes = new vector; + for (unsigned int h=0; hgetNumInteriorRing(); ++h) { + const geos::geom::LineString *ls = poly->getInteriorRingN(h); + geos::geom::LinearRing *lr; + + // If the hole is not valid fix it + // If the hole is NOT valid despike it + lr = Despike(ls); + + if(!lr->isValid()) { + geos::geom::LinearRing *fixed = FixGeometry(lr); + delete lr; + lr = fixed; + } + + // Save this hole if it is not too small + if (!lr->isEmpty()) { + holes->push_back(lr); + } + else { + delete lr; + } + } // End holes loop + + // Work on the main polygon + const geos::geom::LineString* ls = poly->getExteriorRing(); + geos::geom::LinearRing *lr; + + lr = Despike(ls); + + try { + if(!lr->isValid()) { + geos::geom::LinearRing *fixed = FixGeometry(lr); + delete lr; + lr = fixed; + } + } + catch(iException &e) { + // Sometimes despike and fix fail, but the input is really valid. We can just go + // with the non-despiked polygon. + if(ls->isValid() && ls->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) { + lr = (geos::geom::LinearRing *)ls->clone(); + e.Clear(); + } + else { + throw; + } + } + + // Create a new polygon with the holes and save it + if (!lr->isEmpty()) { + geos::geom::Polygon *tp = Isis::globalFactory.createPolygon(lr, holes); + + if (tp->isEmpty() || !tp->isValid()) { + delete tp; + newPolys->push_back (poly->clone()); + } + else { + newPolys->push_back (tp); + } + } + } // End polygons loop + + // Create a new multipoly from the polygon(s) + geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon(newPolys); + + if(!mp->isValid() || mp->isEmpty()) { + delete mp; + mp = NULL; + iString msg = "Despike failed to correct the polygon"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + // if multipoly area changes more than 25% we did something bad to the multipolygon + if(fabs((mp->getArea() / multiPoly->getArea()) - 1.0) > 0.50) { + iString msg = "Despike failed to correct the polygon " + mp->toString(); + delete mp; + + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + return mp; + } + + + /** + * Create a new LinearRing from a LineString without the spikes associated + * with some versions of the geos package. These "spikes" are created when + * intersections and differences are calculated. + * + * @param lineString The original geos::geom::lineString to be despiked. This + * can be the lineString associated with the outside of a polygon or one of its + * holes. + * + * @return A pointer to a LinearRing. If the despiking causes the number of + * unique verticies to fall below 3, an empty LinearRing will be + * returned. + */ + geos::geom::LinearRing* PolygonTools::Despike (const geos::geom::LineString *lineString) { + geos::geom::CoordinateSequence *vertices = lineString->getCoordinates(); + + // We need a full polygon to despike = 3 points (+1 for end==first) = at least 4 points + if (vertices->getSize() < 4) { + delete vertices; + return Isis::globalFactory.createLinearRing (geos::geom::CoordinateArraySequence()); + } + + // delete one of the duplicate first/end coordinates, + // spikes can occur here and the duplicate points throws off the test + vertices->deleteAt(vertices->getSize()-1); + + // Index will become negative if our first points are spiked, so we need + // to make it big enough to encapsulate the (unsigned int) from getSize() + // and allow negative numbers. + for(long index = 0; index < (long)vertices->getSize(); index++) { + // If we're under 3 vertices, we've despiked all the points out of the polygon :( + if(vertices->getSize() < 3) { + break; + } + + // These are the array indices that we're going to test for a spike, + // the middle one is the one that's spiked if IsSpiked(...) is true. + long testCoords[3] = { + index-1, + index, + index+1 + }; + + // Make sure the index is inside of our coordinates array (we'll have both too small/too big of an index) + for(int j = 0; j < 3; j++) { + while(testCoords[j] < 0) { + testCoords[j] += vertices->getSize(); + } + + while(testCoords[j] >= (long)vertices->getSize()) { + testCoords[j] -= vertices->getSize(); + } + } + + // Test the middle point for a spike + if(IsSpiked(vertices->getAt(testCoords[0]), + vertices->getAt(testCoords[1]), + vertices->getAt(testCoords[2]))) { + // It's spiked, delete it + vertices->deleteAt(testCoords[1]); + + // Back up to the first test that is affected by this change + index -= 2; + } + } + + if (vertices->getSize() < 3) { + delete vertices; + vertices = NULL; + + return Isis::globalFactory.createLinearRing (geos::geom::CoordinateArraySequence()); + } + else { + // Duplicate the first vertex as the last to close the polygon + vertices->add(vertices->getAt(0)); + return Isis::globalFactory.createLinearRing(vertices); + } + } + + /** + * Returns true if the middle point is spiked. + * + * @param first + * @param middle + * @param last + * + * @return bool Returns true if middle point is spiked + */ + bool PolygonTools::IsSpiked(geos::geom::Coordinate first, geos::geom::Coordinate middle, geos::geom::Coordinate last) { + return TestSpiked(first, middle, last) || TestSpiked(last, middle, first); + } + + /** + * This method tests for spikes. The first/last coordinate matter. If the line + * between the first point and middle point are the base of a triangle, with the + * last point as the tip, then if the base of this triangle is substantially + * larger than the height we have a spike (fig A). If the middle point is near + * the edges of the triangle, however, this is valid data (fig B/C). + * + * (A) (B) (C) + * 1 1 1-2 + * | | | + * | | | + * 3-| | | + * | | | + * | | | + * 2 2-3 3 + * + * *1 is start, 2 is middle, 3 is end + * + * Spikes are a problem because when we convert from lat/lons to meters the + * points get shifted relative to each other (lower points might be shifted + * more right then higher points, for example). + * + * @param first + * @param middle + * @param last + * + * @return bool Returns true if middle point spiked given this first/last pt + */ + bool PolygonTools::TestSpiked(geos::geom::Coordinate first, geos::geom::Coordinate middle, geos::geom::Coordinate last) { + geos::geom::Point *firstPt = Isis::globalFactory.createPoint(first); + geos::geom::Point *middlePt = Isis::globalFactory.createPoint(middle); + geos::geom::Point *lastPt = Isis::globalFactory.createPoint(last); + + geos::geom::CoordinateSequence *coords = new geos::geom::CoordinateArraySequence(); + coords->add(first); + coords->add(middle); + geos::geom::LineString *line = Isis::globalFactory.createLineString(coords); // line takes ownership + + // The lower the tolerance, the less this algorithm removes and thus + // the better chance of success in findimageoverlaps. However, if you + // lower the tolerance then there is also a greater chance of programs + // such as autoseed failing. 1% is the current tolerance. + double tolerance = line->getLength() / 100.0; + + bool spiked = true; + + double distanceLastMiddle = geos::operation::distance::DistanceOp::distance(lastPt, middlePt); + double distanceLastLine = geos::operation::distance::DistanceOp::distance(lastPt, line); + + if(distanceLastMiddle == 0.0) return true; // get rid of same point + + // Checks the ratio of the distance between the last point and the line, and the last point and the middle point + // if the ratio is very small then there is a spike + if(distanceLastLine / distanceLastMiddle >= .05) { + spiked = false; + } + + // If the point is away from the line, keep it + if (spiked && distanceLastLine > tolerance) { + spiked = false; + } + + if(!spiked) { + geos::geom::CoordinateSequence *coords = new geos::geom::CoordinateArraySequence(); + coords->add(first); + coords->add(middle); + coords->add(last); + coords->add(first); + + // shell takes ownership of coords + geos::geom::LinearRing *shell = Isis::globalFactory.createLinearRing(coords); + std::vector *empty = new std::vector; + + // poly takes ownership of shell and empty + geos::geom::Polygon *poly = Isis::globalFactory.createPolygon(shell, empty); + + + // if these 3 points define a straight line then the middle is worthless (defines nothing) or problematic + if(poly->getArea() < 1.0e-10) { + spiked = true; + } + + delete poly; + } + + + delete firstPt; + delete middlePt; + delete lastPt; + delete line; + + return spiked; + } + + + /** + * This applies the geos Intersect operator. Due to "BinaryOp.h" having + * implementations in it, only one Isis object may perform these operations. If + * that file is included anywhere else in Isis, the library will not build! + * Please use this method to intersect two geometries. If the geometry is a + * linear ring or multi polygon, corrections may be applied if the geos + * intersection operator fails. + * + * @param geom1 First geometry to intersect + * @param geom2 Second geometry to intersect + * + * @return geos::geom::Geometry* geom1 intersected with geom2 + */ + geos::geom::Geometry *PolygonTools::Intersect(const geos::geom::Geometry *geom1, const geos::geom::Geometry *geom2) { + try { + return Operate(geom1, geom2, (unsigned int)geos::operation::overlay::OverlayOp::opINTERSECTION); + } + catch (geos::util::GEOSException *exc) { + iString msg = "Intersect operation failed. The reason given was [" + iString(exc->what()) + "]"; + delete exc; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + catch (iException &e) { + iString msg = "Intersect operation failed"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + catch (...) { + iString msg = "Intersect operation failed for an unknown reason"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + geos::geom::Geometry *PolygonTools::Operate(const geos::geom::Geometry *geom1, const geos::geom::Geometry *geom2, unsigned int opcode) { + + geos::operation::overlay::OverlayOp::OpCode code = + (geos::operation::overlay::OverlayOp::OpCode)opcode; + + geos::geom::Geometry *result = NULL; + bool failed = true; + geos::geom::Geometry *geomFirst = MakeMultiPolygon(geom1); + geos::geom::Geometry *geomSecond = MakeMultiPolygon(geom2); + + geos::operation::overlay::snap::GeometrySnapper snap(*geomFirst); + geos::geom::Geometry *geomSnapped = snap.snapTo(*geomSecond, 1.0e-10)->clone(); + if(!geomSnapped->isValid()) { + delete geomSnapped; + } + else { + delete geomFirst; + geomFirst = geomSnapped; + } + + unsigned int precision = 15; + unsigned int minPrecision = 13; + while(failed) { + try { + std::auto_ptr< geos::geom::Geometry > resultAuto = + BinaryOp(geomFirst, geomSecond, geos::operation::overlay::overlayOp(code)); + failed = false; + result = resultAuto->clone(); + } + catch(geos::util::GEOSException *exc) { + // Just in case the clone failed.... + if(!failed || precision == minPrecision) throw; + + delete exc; + } + catch(...) { + if(precision == minPrecision) { + iString msg = "An unknown geos error occurred"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + if(!failed) { + iString msg = "An unknown geos error occurred when attempting to clone a geometry"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + // try reducing the precision + if(failed) { + precision --; + geos::geom::Geometry *tmp = ReducePrecision(geomFirst, precision); + delete geomFirst; + geomFirst = tmp; + + tmp = ReducePrecision(geomSecond, precision); + delete geomSecond; + geomSecond = tmp; + } + } + + delete geomFirst; + geomFirst = NULL; + + delete geomSecond; + geomSecond = NULL; + + if(result && !result->isValid()) { + try { + geos::geom::Geometry *newResult = FixGeometry(result); + + if(fabs(newResult->getArea() / result->getArea() - 1.0) > 0.50) { + delete newResult; + delete result; + + iString msg = "Operation [" + iString((int)opcode) + "] failed"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + delete result; + result = newResult; + } + catch (iException &e) { + iString msg = "Operation [" + iString((int)opcode) + "] failed"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + if(result == NULL) { + iString msg = "Operation [" + iString((int)opcode) + " failed"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + return result; + } + + /** + * This method attempts to seek out known problems with geometries and repair + * them. Currently the only known problem is when two points lie on top of each + * other, which is a result of various operations. Currently only LinearRings + * and MultiPolygons are supported. + * + * @param geom The geometry to be fixed + * + * @return geos::geom::Geometry* A fixed geometry. + */ + geos::geom::Geometry *PolygonTools::FixGeometry(const geos::geom::Geometry *geom) { + if(geom->getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) { + return FixGeometry( (geos::geom::MultiPolygon*)geom ); + } + if(geom->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) { + return FixGeometry( (geos::geom::LinearRing*)geom ); + } + if(geom->getGeometryTypeId() == geos::geom::GEOS_POLYGON) { + return FixGeometry( (geos::geom::Polygon*)geom ); + } + if(geom->getGeometryTypeId() == geos::geom::GEOS_GEOMETRYCOLLECTION) { + return FixGeometry( MakeMultiPolygon(geom) ); + } + else { + iString msg = "PolygonTools::FixGeometry does not support [" + GetGeometryName(geom) + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + /** + * This applies the LinearRing FixGeometry method to all of the interior and + * exterior rings in the multipolygon. See FixGeometry(LinearRing) for more + * explanation. + * + * @param poly An invalid multipolygon + * + * @return geos::geom::MultiPolygon* A possibly valid multipolygon + */ + geos::geom::MultiPolygon *PolygonTools::FixGeometry(const geos::geom::MultiPolygon *poly) { + // Maybe two points are on top of each other + vector *newPolys = new vector; + + // Convert each polygon in this multi-polygon + for (unsigned int geomIndex = 0; geomIndex < poly->getNumGeometries(); geomIndex ++) { + geos::geom::Polygon* fixedpoly = FixGeometry((geos::geom::Polygon*)(poly->getGeometryN(geomIndex))); + if( fixedpoly->isValid() ) { + newPolys->push_back( fixedpoly ); + } + else { + delete fixedpoly; + } + fixedpoly = NULL; + } + + geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon(newPolys); + return mp; + } + + + geos::geom::Polygon *PolygonTools::FixGeometry(const geos::geom::Polygon *poly) { + + // Convert each hole inside this polygon + vector *holes = new vector; + for (unsigned int holeIndex = 0; holeIndex < poly->getNumInteriorRing(); holeIndex ++) { + const geos::geom::LineString *thisHole = poly->getInteriorRingN(holeIndex); + + // We hope they are all linear rings (closed/simple), but if not just leave it be + if(thisHole->getGeometryTypeId() != geos::geom::GEOS_LINEARRING) { + holes->push_back(thisHole->clone()); + continue; + } + + try { + geos::geom::LinearRing *newHole = FixGeometry((geos::geom::LinearRing *)thisHole); + holes->push_back(newHole); + } + catch (iException &e) { + iString msg = "Failed when attempting to fix interior ring of multipolygon"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } // end num holes in polygon loop + + + const geos::geom::LineString *exterior = poly->getExteriorRing(); + + try { + geos::geom::LinearRing *newExterior = NULL; + + if(exterior->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) { + newExterior = FixGeometry((geos::geom::LinearRing *)exterior); + } + else { + iString msg = "Failed when attempting to fix exterior ring of polygon. The exterior ring is not simple and closed"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + return globalFactory.createPolygon(newExterior, holes); + } + catch (iException &e) { + iString msg = "Failed when attempting to fix exterior ring of polygon"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + /** + * One problem we know of seems to happen when two points are right on top of + * each other. We're going to look for those points and remove them, then see if + * the linear ring is valid. Assumes input fails its isValid() test. + * + * Point end up on top of each other for two (2) known reasons. First, Despike + * removes a spike that simply went back and forth. Second, the geos Intersect + * operator can return invalid polygons because of this problem. Every geometry + * thus far is being broken down into LinearRings and this method cleans those + * up. + * + * @param ring An invalid linear ring + * + * @return geos::geom::LinearRing* A possibly valid linear ring + */ + geos::geom::LinearRing *PolygonTools::FixGeometry(const geos::geom::LinearRing *ring) { + + geos::geom::CoordinateSequence *coords = ring->getCoordinates(); + + // Check this, just in case + if(coords->getSize() < 4) { + return globalFactory.createLinearRing(new geos::geom::DefaultCoordinateSequence ()); + } + + geos::geom::CoordinateSequence *newCoords = new geos::geom::DefaultCoordinateSequence (); + const geos::geom::Coordinate *lastCoordinate = &coords->getAt(0); + newCoords->add(*lastCoordinate); + + // Convert each coordinate in this hole + for (unsigned int coordIndex = 1; coordIndex < coords->getSize() - 1; coordIndex ++) { + const geos::geom::Coordinate *thisCoordinate = &coords->getAt(coordIndex); + + // we're going to compare the decimal place of the current point to the decimal place + // of the difference, if they are drastically different then geos might not be seeing them + // correctly. + double difference[2] = { + lastCoordinate->x - thisCoordinate->x, + lastCoordinate->y - thisCoordinate->y, + }; + + // geos isnt differentiating between points this close + double minDiff = fabs(DecimalPlace(thisCoordinate->x) - DecimalPlace(difference[0])); + + minDiff = min(minDiff, fabs(DecimalPlace(thisCoordinate->y) - DecimalPlace(difference[1]))); + + // Cases where the difference in one direction is exactly zero, and the other direction is next to zero + // appear often enough (especially in despike). + if(difference[0] == 0.0 && difference[1] != 0.0) { + // subtracted the two points, got deltaX = 0.0, use the y difference decimal place + minDiff = fabs(DecimalPlace(thisCoordinate->y) - DecimalPlace(difference[1])); + } + else if(difference[1] == 0.0 && difference[0] != 0.0) { + // subtracted the two points, got deltaY = 0.0, use the x difference decimal place + minDiff = fabs(DecimalPlace(thisCoordinate->x) - DecimalPlace(difference[0])); + } + else if(difference[0] == 0.0 && difference[1] == 0.0) { + // subtracted the two points, got 0.0, so it's same point... make sure it gets ignored! + minDiff = 1E99; + } + + // geos has a hard time differentiating when points get too close... + if(minDiff <= 15) { + newCoords->add(*thisCoordinate); + lastCoordinate = thisCoordinate; + } + } // end num coords in hole loop + + newCoords->add(geos::geom::Coordinate(newCoords->getAt(0).x, newCoords->getAt(0).y)); + geos::geom::LinearRing *newRing = NULL; + + // Now that we've weeded out any bad coordinates, let's rebuild the geometry + try { + if(newCoords->getSize() > 3) { + newRing = globalFactory.createLinearRing(newCoords); + } + else { + delete newCoords; + newCoords = NULL; + } + } + catch (geos::util::GEOSException *exc) { + delete exc; + exc = NULL; + + iString msg = "Error when attempting to fix linear ring"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + if(newRing && !newRing->isValid() && ring->isValid()) { + iString msg = "Failed when attempting to fix linear ring"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + else if(!newRing || !newRing->isValid()) { + if(newRing) { + delete newRing; + } + + newRing = (geos::geom::LinearRing*)ring->clone(); + } + + return newRing; + } + + + /** + * This returns the location of the decimal place in the number. This method + * is used as a helper method for FixGeometry(...), to help figure out how close + * two numbers are in significant figures. + * + * 1.0 = decimal place 1, .1 = decimal place 0, 10.0 = decimal place 2 + * + * @param num The number to find the decimal place in + * + * @return int The decimal place relative to the first significant digit + */ + int PolygonTools::DecimalPlace(double num) { + // 0.0 = decimal place 0 + if(num == 0.0) return 0; + + num = fabs(num); + + int decimalPlace = 1; + while(num < 1.0) { + num *= 10.0; + decimalPlace --; + } + + while(num > 10.0) { + num /= 10.0; + decimalPlace ++; + } + + return decimalPlace; + } + + /** + * This method is used to subtract two polygons. + * + * @param geom1 + * @param geom2 + * + * @return geos::geom::Geometry* + */ + geos::geom::Geometry *PolygonTools::Difference(const geos::geom::Geometry *geom1, const geos::geom::Geometry *geom2) { + try { + return Operate(geom1, geom2, (unsigned int)geos::operation::overlay::OverlayOp::opDIFFERENCE); + } + catch (geos::util::GEOSException *exc) { + iString msg = "Difference operation failed. The reason given was [" + iString(exc->what()) + "]"; + delete exc; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + catch (iException &e) { + iString msg = "Difference operation failed"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + catch (...) { + iString msg = "Difference operation failed for an unknown reason"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + /** + * Make a geos::geom::MultiPolygon out of the components of the argument + * + * Create a new geos::geom::MultiPolygon out of the general geometry that is + * passed in. This can be useful after an intersection or some other + * operator on two MultiPolygons. The result of the operator is often a + * collection of different geometries such as points, lines, polygons... + * This member extracts all polygons and multipolygons into a new + * multipolygon. The original geometry is deleted. The resulting multipolygon is + * not necessarily valid. + * + * @param geom The geometry to be converted into a multipolygon + */ + geos::geom::MultiPolygon* PolygonTools::MakeMultiPolygon (const geos::geom::Geometry *geom) { + // The area of the geometry is too small, so just ignore it. + if (geom->isEmpty()) { + return Isis::globalFactory.createMultiPolygon(); + } + + else if (geom->getArea()-DBL_EPSILON <= DBL_EPSILON) { + return Isis::globalFactory.createMultiPolygon(); + } + + else if (geom->getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) { + return (geos::geom::MultiPolygon *)geom->clone(); + } + + else if (geom->getGeometryTypeId() == geos::geom::GEOS_POLYGON) { + vector *polys = new vector; + polys->push_back(geom->clone()); + geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon(polys); + return mp; + } + + else if (geom->getGeometryTypeId() == geos::geom::GEOS_GEOMETRYCOLLECTION) { + vector polys; + geos::geom::GeometryCollection *gc = (geos::geom::GeometryCollection*)geom; + for (unsigned int i=0; i < gc->getNumGeometries(); ++i) { + if ((gc->getGeometryN(i)->getGeometryTypeId() == geos::geom::GEOS_POLYGON) && + (gc->getGeometryN(i)->getArea()-DBL_EPSILON > DBL_EPSILON)) { + polys.push_back(gc->getGeometryN(i)->clone()); + } + } + + geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon (polys); + if (mp->getArea()-DBL_EPSILON <= DBL_EPSILON) { + delete mp; + mp = Isis::globalFactory.createMultiPolygon(); + } + + return mp; + } + // All other geometry types are invalid so ignore them + else { + return Isis::globalFactory.createMultiPolygon(); + } + } + + + /** + * This method reduces the precision of the geometry to precision significant + * figures. + * + * @param geom The geometry to reduce precision on + * @param precision The precision to reduce to + * + * @return geos::geom::Geometry* The lower precision geometry + */ + geos::geom::Geometry *PolygonTools::ReducePrecision(const geos::geom::Geometry *geom, unsigned int precision) { + if(geom->getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) { + return ReducePrecision( (geos::geom::MultiPolygon*)geom, precision ); + } + if(geom->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) { + return ReducePrecision( (geos::geom::LinearRing*)geom, precision ); + } + if(geom->getGeometryTypeId() == geos::geom::GEOS_POLYGON) { + return ReducePrecision( (geos::geom::Polygon*)geom, precision ); + } + if(geom->getGeometryTypeId() == geos::geom::GEOS_GEOMETRYCOLLECTION) { + return ReducePrecision( MakeMultiPolygon(geom), precision ); + } + else { + iString msg = "PolygonTools::ReducePrecision does not support [" + GetGeometryName(geom) + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + /** + * This method reduces the precision of the MultiPolygon to precision + * significant figures. + * + * @param poly The MultiPolygon to reduce precision on + * @param precision The precision to reduce to + * + * @return geos::geom::MultiPolygon* The lower precision MultiPolygon + */ + geos::geom::MultiPolygon *PolygonTools::ReducePrecision(const geos::geom::MultiPolygon *poly, unsigned int precision) { + // Maybe two points are on top of each other + vector *newPolys = new vector; + + // Convert each polygon in this multi-polygon + for (unsigned int geomIndex = 0; geomIndex < poly->getNumGeometries(); geomIndex ++) { + geos::geom::Geometry* lowerPrecision = ReducePrecision((geos::geom::Polygon*)(poly->getGeometryN(geomIndex)), precision); + + if(!lowerPrecision->isEmpty()) { + newPolys->push_back(lowerPrecision); + } + else { + delete lowerPrecision; + } + } + + geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon(newPolys); + return mp; + } + + + /** + * This method reduces the precision of the Polygon to precision significant + * figures. + * + * @param poly The polygon to reduce precision on + * @param precision The precision to reduce to + * + * @return geos::geom::Polygon* The lower precision polygon + */ + geos::geom::Polygon *PolygonTools::ReducePrecision(const geos::geom::Polygon *poly, unsigned int precision) { + // Convert each hole inside this polygon + vector *holes = new vector; + for (unsigned int holeIndex = 0; holeIndex < poly->getNumInteriorRing(); holeIndex ++) { + const geos::geom::LineString *thisHole = poly->getInteriorRingN(holeIndex); + + // We hope they are all linear rings (closed/simple), but if not just leave it be + if(thisHole->getGeometryTypeId() != geos::geom::GEOS_LINEARRING) { + holes->push_back(thisHole->clone()); + continue; + } + + try { + geos::geom::LinearRing *newHole = ReducePrecision((geos::geom::LinearRing *)thisHole, precision); + + if(!newHole->isEmpty()) { + holes->push_back(newHole); + } + else { + delete newHole; + } + + } + catch (iException &e) { + iString msg = "Failed when attempting to fix interior ring of multipolygon"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } // end num holes in polygon loop + + + const geos::geom::LineString *exterior = poly->getExteriorRing(); + + try { + geos::geom::LinearRing *newExterior = NULL; + + if(exterior->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) { + newExterior = ReducePrecision((geos::geom::LinearRing *)exterior, precision); + } + else { + iString msg = "Failed when attempting to fix exterior ring of polygon. The exterior ring is not simple and closed"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + return globalFactory.createPolygon(newExterior, holes); + } + catch (iException &e) { + iString msg = "Failed when attempting to fix exterior ring of polygon"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + /** + * This method reduces the precision of the LinearRing to precision significant + * figures. + * + * @param ring The linear ring to reduce precision on + * @param precision The precision to reduce to + * + * @return geos::geom::LinearRing* The lower precision linear ring + */ + geos::geom::LinearRing *PolygonTools::ReducePrecision(const geos::geom::LinearRing *ring, unsigned int precision) { + geos::geom::CoordinateSequence *coords = ring->getCoordinates(); + + // Check this, just in case + if(coords->getSize() <= 0) return (geos::geom::LinearRing *)ring->clone(); + + geos::geom::CoordinateSequence *newCoords = new geos::geom::DefaultCoordinateSequence (); + geos::geom::Coordinate *coord = ReducePrecision(&coords->getAt(0), precision); + newCoords->add(*coord); + delete coord; + coord = NULL; + + // Convert each coordinate in this ring + for (unsigned int coordIndex = 1; coordIndex < coords->getSize() - 1; coordIndex ++) { + const geos::geom::Coordinate *thisCoordinate = &coords->getAt(coordIndex); + coord = ReducePrecision(thisCoordinate, precision); + newCoords->add(*coord); + delete coord; + coord = NULL; + } + + newCoords->add(geos::geom::Coordinate(newCoords->getAt(0).x, newCoords->getAt(0).y)); + geos::geom::LinearRing *newRing = NULL; + + // Now that we've weeded out any bad coordinates, let's rebuild the geometry + try { + newRing = globalFactory.createLinearRing(newCoords); + } + catch (geos::util::GEOSException *exc) { + delete exc; + exc = NULL; + + iString msg = "Error when attempting to reduce precision of linear ring"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + // try to despike + try { + geos::geom::LinearRing *tmp = Despike(newRing); + delete newRing; + newRing = tmp; + } + catch (iException &e) { + e.Clear(); + } + + if(!newRing->isValid()) { + iString msg = "Failed when attempting to reduce precision of linear ring"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + return newRing; + } + + + /** + * This method reduces the precision of the coordinate to precision significant + * figures. + * + * @param coord The coordinate to reduce precision on + * @param precision The precision to reduce to + * + * @return geos::geom::Coordinate* The lower precision coordinate + */ + geos::geom::Coordinate *PolygonTools::ReducePrecision(const geos::geom::Coordinate *coord, unsigned int precision) { + return new geos::geom::Coordinate( + ReducePrecision(coord->x, precision), + ReducePrecision(coord->y, precision), + ReducePrecision(coord->z, precision) + ); + } + + + /** + * This method will reduce the decimal precision of the inputted num to + * precision decimal places. + * + * @param num The original number + * @param precision The new precision + * + * @return double The reduced precision number + */ + double PolygonTools::ReducePrecision(double num, unsigned int precision) { + int decimalPlace = DecimalPlace(num); + double factor = pow(10.0, (int)decimalPlace); + + // reduced num is in the form 0.nnnnnnnnnn... + double reducedNum = num / factor; + + double cutoff = pow(10.0, (int)precision); + double round_offset = (num < 0)? -0.5 : 0.5; + + // cast off the digits past the precision's place + reducedNum = ((long long)(reducedNum * cutoff + round_offset)) / cutoff; + + return reducedNum*factor; + } + + + /** + * This method returns the name of the type of geometry passed in. This is + * useful for error reporting (i.e. Geometry Type [...] not supported). + * + * @param geom The geometry to test which type it really is + * + * @return std::string + */ + std::string PolygonTools::GetGeometryName(const geos::geom::Geometry *geom) { + switch(geom->getGeometryTypeId()) { + case geos::geom::GEOS_POINT: + return "Point"; + case geos::geom::GEOS_LINESTRING: + return "Line String"; + case geos::geom::GEOS_LINEARRING: + return "Linear Ring"; + case geos::geom::GEOS_POLYGON: + return "Polygon"; + case geos::geom::GEOS_MULTIPOINT: + return "Multi Point"; + case geos::geom::GEOS_MULTILINESTRING: + return "Multi Line String"; + case geos::geom::GEOS_MULTIPOLYGON: + return "Multi Polygon"; + case geos::geom::GEOS_GEOMETRYCOLLECTION: + return "Geometry Collection"; + default: + return "UNKNOWN"; + } + } + + + bool PolygonTools::Equal( const geos::geom::MultiPolygon * poly1, const geos::geom::MultiPolygon * poly2 ) { + + vector polys1; + vector polys2; + + if (poly1->getNumGeometries() != poly2->getNumGeometries()) return false; + + // Convert each polygon in this multi-polygon + for (unsigned int geomIndex = 0; geomIndex < poly1->getNumGeometries(); geomIndex ++) { + polys1.push_back( (geos::geom::Polygon*)poly1->getGeometryN(geomIndex) ); + polys2.push_back( (geos::geom::Polygon*)poly2->getGeometryN(geomIndex) ); + } + + for (int p1 = polys1.size()-1; (p1 >= 0) && polys1.size(); p1 --) { + for (int p2 = polys2.size()-1; (p2 >= 0) && polys2.size(); p2 --) { + if ( Equal(polys1[p1],polys2[p2]) ) { + // Delete polys1[p1] by replacing it with the last Polygon in polys1 + polys1[p1] = polys1[polys1.size()-1]; + polys1.resize( polys1.size()-1 ); + // Delete polys2[p2] by replacing it with the last Polygon in polys2 + polys2[p2] = polys2[polys2.size()-1]; + polys2.resize( polys2.size()-1 ); + } + } + } + + return (polys1.size() == 0) && (polys2.size() == 0); + } + + + bool PolygonTools::Equal( const geos::geom::Polygon * poly1, const geos::geom::Polygon * poly2 ) { + vector holes1; + vector holes2; + + if (poly1->getNumInteriorRing() != poly2->getNumInteriorRing()) return false; + + if ( !Equal(poly1->getExteriorRing(),poly2->getExteriorRing()) ) return false; + + // Convert each hole inside this polygon + for (unsigned int holeIndex = 0; holeIndex < poly1->getNumInteriorRing(); holeIndex ++) { + + // We hope they are all linear rings (closed/simple), but if not just leave it be + if(poly1->getInteriorRingN(holeIndex)->getGeometryTypeId() == geos::geom::GEOS_LINESTRING) { + holes1.push_back( poly1->getInteriorRingN(holeIndex) ); + } + + if(poly2->getInteriorRingN(holeIndex)->getGeometryTypeId() == geos::geom::GEOS_LINESTRING) { + holes2.push_back( poly2->getInteriorRingN(holeIndex) ); + } + + } + + if (holes1.size() != holes2.size()) return false; + + for (int h1 = holes1.size()-1; (h1 >= 0) && holes1.size(); h1 --) { + for (int h2 = holes2.size()-1; (h2 >= 0) && holes2.size(); h2 --) { + if ( Equal(holes1[h1],holes2[h2]) ) { + // Delete holes1[h1] by replacing it with the last Polygon in holes1 + holes1[h1] = holes1[holes1.size()-1]; + holes1.resize( holes1.size()-1 ); + // Delete holes2[h2] by replacing it with the last Polygon in holes2 + holes2[h2] = holes2[holes2.size()-1]; + holes2.resize( holes2.size()-1 ); + } + } + } + + return (holes1.size() == 0) && (holes2.size() == 0); + } + + + bool PolygonTools::Equal( const geos::geom::LineString * lineString1, const geos::geom::LineString * lineString2 ) { + + geos::geom::CoordinateSequence *coords1 = lineString1->getCoordinates(); + geos::geom::CoordinateSequence *coords2 = lineString2->getCoordinates(); + bool isEqual = true; + + if (coords1->getSize() != coords2->getSize() ) isEqual = false; + + unsigned int index1 = 0; + unsigned int index2 = 0; + + // -1 extra for dupicate start/end coordinates + for( ; index2 < coords2->getSize()-1 && isEqual; index2 ++) { + if (Equal(coords1->getAt(index1),coords2->getAt(index2))) break; + } + + if (index2 == coords2->getSize()-1) isEqual = false; + + for ( ; index1 < coords1->getSize()-1 && isEqual; index1 ++, index2 ++) { + if (!Equal(coords1->getAt(index1),coords2->getAt(index2 % (coords2->getSize()-1)))) { + isEqual = false; + } + } + + delete coords1; + delete coords2; + return isEqual; + } + + + bool PolygonTools::Equal( const geos::geom::Coordinate & coord1, const geos::geom::Coordinate & coord2 ) { + + if (!Equal(coord1.x,coord2.x)) return false; + if (!Equal(coord1.y,coord2.y)) return false; + if (!Equal(coord1.y,coord2.y)) return false; + + return true; + } + + + bool PolygonTools::Equal( const double d1, const double d2 ) { + const double cutoff = 1e15; + + if(DecimalPlace(d1) != DecimalPlace(d2)) return false; + + int decimalPlace = DecimalPlace(d1); + double factor = pow(10.0, (int)decimalPlace); + + // reduced num is in the form 0.nnnnnnnnnn... + double reducedNum = d1 / factor; + + double round_offset = (d1 < 0)? -0.5 : 0.5; + + // cast off the digits past the precision's place + long long num1 = ((long long)(reducedNum * cutoff + round_offset)); + + factor = pow(10.0, (int)decimalPlace); + + // reduced num is in the form 0.nnnnnnnnnn... + reducedNum = d2 / factor; + + round_offset = (d2 < 0)? -0.5 : 0.5; + + // cast off the digits past the precision's place + long long num2 = ((long long)(reducedNum * cutoff + round_offset)); + + + return (num1 == num2); + } + + +} // end namespace isis + diff --git a/isis/src/base/objs/PolygonTools/PolygonTools.h b/isis/src/base/objs/PolygonTools/PolygonTools.h new file mode 100644 index 0000000000000000000000000000000000000000..7b2285b050f8ccb82cfccddfdc2ec185a2bf33af --- /dev/null +++ b/isis/src/base/objs/PolygonTools/PolygonTools.h @@ -0,0 +1,195 @@ +#ifndef Polygontools_h +#define Polygontools_h +/** + * @file + * $Revision: 1.23 $ + * $Date: 2009/07/17 16:13:46 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "geos/geom/GeometryFactory.h" +#include "geos/geom/MultiPolygon.h" +#include "geos/geom/CoordinateSequence.h" + +namespace Isis { + +/** + * @brief General tools for manipulating polygons + * + * Tools for manipulating polygons within Isis. These include + * converting a Lon/Lat polygon to X/Y using a projection. + * + * @ingroup Utility + * + * @author 2006-06-22 Stuart Sides + * + * @internal + * @history 2008-08-18 Steven Lambright Updated to work with geos3.0.0 + * @history 2009-02-05 Steven Lambright The FixGeometry methods will no longer + * produce geometries containing empty elements (though they might + * still return a completely empty geos figure). For example, a + * multipolygon will not have "EMPTY" polygons inside of it even + * though the multipolygon itself may be just EMPTY. This fixes + * issues with the geos BinaryOp(...) call. + * @history 2009-02-13 Steven Lambright Despike(geos::geom::MultiPolygon *) is + * now much more accepting of invalid polygons inside of the + * MultiPolygon. Often times perfectly good polygons are mixed with + * tiny, scattered, invalid polygons and this should now just throw + * those out and keep what it can. + * + */ + + class UniversalGroundMap; + class Projection; + + static geos::geom::GeometryFactory globalFactory; + +/** + * @brief Provides various tools to work with geos multipolygons + * + * This class provides methods to that work with geos multipolygons. This + * includes functions to convert from one coordinate system to another and to + * copy multipolygons. + * + * @ingroup Utility + * + * @author 2006-08-07 Stuart Sides + * + * @internal + * @history 2006-08-07 Stuart Sides - Original version + * + * @history 2007-05-04 Robert Sucharski - Moved the method to + * output WKT from ImagePlygon class to this class. + * Also added method to output GML format. + * + * @history 2007-11-09 Tracie Sucharski - Remove ToWKT method, geos + * now has a method (toString) to return a WKT string. + * Added To180 method which converts polygon coordinates from + * 0/360 system to -180/180 system. If polygon was split because + * it crossed the 0/360 seam, the two polys coordinates are + * converted then merged. + * @history 2008-06-18 Steven Koechle - Fixed Documentation Errors + * @history 2008-08-18 Steven Lambright - Updated to work with geos3.0.0 + * instead of geos2. Mostly namespace changes. + * @history 2008-11-10 Christopher Austin - Added Thickness() + * @history 2008-11-25 Steven Koechle - Moved Despike Methods from + * ImageOverlapSet to PolygonTools + * @history 2008-12-01 Steven Lambright - Changed the Despike algorithm to be + * in more methods to clean it up, added the middle point to + * beginning/end of line tests to keep more data. Added "IsSpiked" + * and "TestSpiked." + * @history 2008-12-10 Steven Koechle - Moved MakeMultiPolygon Method from + * ImageOverlapSet to PolygonTools + * @history 2008-12-12 Steven Lambright - Bug fixes, cleaned up + * Despike/MakeMultiPolygon + * @history 2008-12-12 Steven Lambright - Renamed methods, polygon conversion + * methods now throw an iException if they fail, updated + * Despike(...)'s algorithm + * @history 2008-12-19 Steven Lambright - updated Despike(...)'s algorithm + * @history 2008-12-19 Steven Lambright - Added error to Despike (empty or + * invalid result). + * @history 2009-01-16 Steven Koechle - Fixed Memory Leak in + * LatLonToSampleLine method + * @history 2009-01-23 Steven Lambright - Added precision reduction algorithms + * and made the Difference and Intersect operators work in a more + * generic way by calling the new method Operate(...). + * @history 2009-01-28 Steven Lambright - Fixed memory leaks + * @history 2009-02-02 Stacy Alley - updated the To180 method + * to handle 360 multi polys that cross the -180/180 + * boundry. We need to return >1 polygon for these + * type of cases. + * @history 2009-01-28 Steven Lambright - Fixed bug in Operate(...) method + * when reducing precision + * @history 2009-06-09 Steven Lambright - Added a check to Equal(double,double). This + * never caused a problem but could have. + */ + + class PolygonTools { + + public: + PolygonTools (); + ~PolygonTools (); + + static geos::geom::MultiPolygon *LatLonToXY( + const geos::geom::MultiPolygon &lonLatPoly, Projection *proj); + + static geos::geom::MultiPolygon *XYToLatLon( + const geos::geom::MultiPolygon &xYPoly, Projection *proj); + + static geos::geom::MultiPolygon *LatLonToSampleLine( + const geos::geom::MultiPolygon &lonLatPoly, UniversalGroundMap *ugm); + + // Return a deep copy of a multpolygon + static geos::geom::MultiPolygon* CopyMultiPolygon(const geos::geom::MultiPolygon *mpolygon); + static geos::geom::MultiPolygon* CopyMultiPolygon(const geos::geom::MultiPolygon &mpolygon); + + static geos::geom::MultiPolygon* Despike (const geos::geom::Geometry *geom); + static geos::geom::MultiPolygon* Despike (const geos::geom::MultiPolygon *multiPoly); + static geos::geom::LinearRing* Despike (const geos::geom::LineString *linearRing); + + // Return polygon in -180/180 coordinated system and merge split polys + static geos::geom::MultiPolygon *To180 (geos::geom::MultiPolygon *poly360); + + //Return a polygon in GML format + static std::string ToGML(const geos::geom::MultiPolygon *mpolygon, std::string idString="0"); + + //Return the thickness of a polygon + static double Thickness( const geos::geom::MultiPolygon *mpolygon ); + + static geos::geom::Geometry *Intersect(const geos::geom::Geometry *geom1, const geos::geom::Geometry *geom2); + static geos::geom::Geometry *Difference(const geos::geom::Geometry *geom1, const geos::geom::Geometry *geom2); + + static geos::geom::MultiPolygon* MakeMultiPolygon (const geos::geom::Geometry *geom); + + static std::string GetGeometryName(const geos::geom::Geometry *geom); + + static bool Equal( const geos::geom::MultiPolygon * poly1, const geos::geom::MultiPolygon * poly2 ); + static bool Equal( const geos::geom::Polygon * poly1, const geos::geom::Polygon * poly2 ); + static bool Equal( const geos::geom::LineString * lineString1, const geos::geom::LineString * lineString2 ); + static bool Equal( const geos::geom::Coordinate & coord1, const geos::geom::Coordinate & coord2 ); + static bool Equal( const double d1, const double d2 ); + private: + geos::geom::MultiPolygon *p_polygons; + + //! Returns true if the middle point is spiked + static bool IsSpiked(geos::geom::Coordinate first, geos::geom::Coordinate middle, geos::geom::Coordinate last); + //! Used by IsSpiked to directionally test (first/last matter) the spike + static bool TestSpiked(geos::geom::Coordinate first, geos::geom::Coordinate middle, geos::geom::Coordinate last); + + static geos::geom::Geometry *FixGeometry(const geos::geom::Geometry *geom); + static geos::geom::MultiPolygon *FixGeometry(const geos::geom::MultiPolygon *poly); + static geos::geom::Polygon *FixGeometry(const geos::geom::Polygon *poly); + static geos::geom::LinearRing *FixGeometry(const geos::geom::LinearRing *ring); + + public: + static geos::geom::Geometry *ReducePrecision(const geos::geom::Geometry *geom, unsigned int precision); + static geos::geom::MultiPolygon *ReducePrecision(const geos::geom::MultiPolygon *poly, unsigned int precision); + static geos::geom::Polygon *ReducePrecision(const geos::geom::Polygon *poly, unsigned int precision); + static geos::geom::LinearRing *ReducePrecision(const geos::geom::LinearRing *ring, unsigned int precision); + static geos::geom::Coordinate *ReducePrecision(const geos::geom::Coordinate *coord, unsigned int precision); + static double ReducePrecision(double num, unsigned int precision); + private: + + static geos::geom::Geometry *Operate(const geos::geom::Geometry *geom1, const geos::geom::Geometry *geom2, unsigned int opcode); + + static int DecimalPlace(double); + }; +}; + +#endif + diff --git a/isis/src/base/objs/PolygonTools/PolygonTools.truth b/isis/src/base/objs/PolygonTools/PolygonTools.truth new file mode 100644 index 0000000000000000000000000000000000000000..097c5ba1e1ffd36d1085934de4a6832b33b24fe5 --- /dev/null +++ b/isis/src/base/objs/PolygonTools/PolygonTools.truth @@ -0,0 +1,64 @@ +Unit test for PolygonTools + +Coordinates of polygon 1:(0 0, 0 1, 1 1, 1 0, 0 0) + +Coordinates of polygon 2:(360 1, 359 1, 359 0, 360 0, 360 1) + +Coordinates of hole for polygon 2:(359.75 0.75, 359.25 0.75, 359.25 0.25, 359.75 0.25, 359.75 0.75) + +Copy of the multipolygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +X/Y polygon radius (1) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0174532925199433, 0.0174506342989556 0.0174532925199433, 0.0174532925199433 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((6.2822283476240113 0.0174532925199433, 6.2647777133250555 0.0174532925199433, 6.2657320146596422 0.0000000000000000, 6.2831853071795862 0.0000000000000000, 6.2822283476240113 0.0174532925199433), (6.2782840621378480 0.0130899693899575, 6.2695581635108333 0.0130899693899575, 6.2700356510010868 0.0043633231299858, 6.2787622141896753 0.0043633231299858, 6.2782840621378480 0.0130899693899575))) + +X/Y polygon radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.1745329251994329, 0.1745063429895559 0.1745329251994329, 0.1745329251994329 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((62.8222834762401163 0.1745329251994329, 62.6477771332505498 0.1745329251994329, 62.6573201465964189 0.0000000000000000, 62.8318530717958623 0.0000000000000000, 62.8222834762401163 0.1745329251994329), (62.7828406213784831 0.1308996938995747, 62.6955816351083257 0.1308996938995747, 62.7003565100108631 0.0436332312998582, 62.7876221418967546 0.0436332312998582, 62.7828406213784831 0.1308996938995747))) + +Lat/Lon polygon from X/Y with radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 358.9999999999999432 1.0000000000000000, 358.9999999999999432 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7499999999999432 0.7500000000000000, 359.2499999999999432 0.7500000000000000, 359.2499999999999432 0.2500000000000000, 359.7499999999999432 0.2500000000000000, 359.7499999999999432 0.7500000000000000))) + +Coordinates of Lon/Lat polygon:(171.81 -31.2795, 173.661 -13.6618, 188.286 -15.754, 188.142 -33.1118, 171.81 -31.2795) + +Coordinates of Sample/Line polygon:MULTIPOLYGON (((0.9999682378838770 1.0001055500507618, 1204.0000480009603052 0.9999580488017727, 1203.9997839350635331 1056.0000950847540935, 0.9997879613350733 1055.9999158657758471, 0.9999682378838770 1.0001055500507618))) + +Well Knowen Text Polygon: +MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +GML Ploygon: + + + + + 0.0-90.0 + 360.090.0 + + + + + test + 0,0 0,1 1,1 1,0 0,0 360,1 359,1 359,0 360,0 360,1 359.75,0.75 359.25,0.75 359.25,0.25 359.75,0.25 359.75,0.75 + + + + +GML Thickness: +1.35030864197531e-05 + + +Testing Despike +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 -10.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing FixGeometry +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000000 5.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing Equal +Same Poly Equal? 1 - 1 +Rearranged Poly Equal? 1 - 1 +Past 15 Places Equal? 1 - 0 +At 15 Place Difference Equal? 0 - 0 +Significantly Different Equal? 0 - 0 diff --git a/isis/src/base/objs/PolygonTools/PolygonTools_Darwin_i386_10_5.truth b/isis/src/base/objs/PolygonTools/PolygonTools_Darwin_i386_10_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..1b38c0bc4e2aefb5aab98a817cb251b31d395813 --- /dev/null +++ b/isis/src/base/objs/PolygonTools/PolygonTools_Darwin_i386_10_5.truth @@ -0,0 +1,64 @@ +Unit test for PolygonTools + +Coordinates of polygon 1:(0 0, 0 1, 1 1, 1 0, 0 0) + +Coordinates of polygon 2:(360 1, 359 1, 359 0, 360 0, 360 1) + +Coordinates of hole for polygon 2:(359.75 0.75, 359.25 0.75, 359.25 0.25, 359.75 0.25, 359.75 0.75) + +Copy of the multipolygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +X/Y polygon radius (1) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0174532925199433, 0.0174506342989556 0.0174532925199433, 0.0174532925199433 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((6.2822283476240113 0.0174532925199433, 6.2647777133250555 0.0174532925199433, 6.2657320146596422 0.0000000000000000, 6.2831853071795862 0.0000000000000000, 6.2822283476240113 0.0174532925199433), (6.2782840621378480 0.0130899693899575, 6.2695581635108333 0.0130899693899575, 6.2700356510010868 0.0043633231299858, 6.2787622141896753 0.0043633231299858, 6.2782840621378480 0.0130899693899575))) + +X/Y polygon radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.1745329251994329, 0.1745063429895559 0.1745329251994329, 0.1745329251994329 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((62.8222834762401163 0.1745329251994329, 62.6477771332505498 0.1745329251994329, 62.6573201465964189 0.0000000000000000, 62.8318530717958623 0.0000000000000000, 62.8222834762401163 0.1745329251994329), (62.7828406213784831 0.1308996938995747, 62.6955816351083257 0.1308996938995747, 62.7003565100108631 0.0436332312998582, 62.7876221418967546 0.0436332312998582, 62.7828406213784831 0.1308996938995747))) + +Lat/Lon polygon from X/Y with radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 358.9999999999999432 1.0000000000000000, 358.9999999999999432 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7499999999999432 0.7500000000000000, 359.2499999999999432 0.7500000000000000, 359.2499999999999432 0.2500000000000000, 359.7499999999999432 0.2500000000000000, 359.7499999999999432 0.7500000000000000))) + +Coordinates of Lon/Lat polygon:(171.81 -31.2795, 173.661 -13.6618, 188.286 -15.754, 188.142 -33.1118, 171.81 -31.2795) + +Coordinates of Sample/Line polygon:MULTIPOLYGON (((0.9999682378838770 1.0001055500506482, 1204.0000480009568946 0.9999580487848334, 1203.9997839350683080 1056.0000950847629611, 0.9997879613397345 1055.9999158657785756, 0.9999682378838770 1.0001055500506482))) + +Well Knowen Text Polygon: +MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +GML Ploygon: + + + + + 0.0-90.0 + 360.090.0 + + + + + test + 0,0 0,1 1,1 1,0 0,0 360,1 359,1 359,0 360,0 360,1 359.75,0.75 359.25,0.75 359.25,0.25 359.75,0.25 359.75,0.75 + + + + +GML Thickness: +1.35030864197531e-05 + + +Testing Despike +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 -10.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing FixGeometry +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000000 5.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing Equal +Same Poly Equal? 1 - 1 +Rearranged Poly Equal? 1 - 1 +Past 15 Places Equal? 1 - 0 +At 15 Place Difference Equal? 0 - 0 +Significantly Different Equal? 0 - 0 diff --git a/isis/src/base/objs/PolygonTools/PolygonTools_Darwin_i386_10_5_8.truth b/isis/src/base/objs/PolygonTools/PolygonTools_Darwin_i386_10_5_8.truth new file mode 100644 index 0000000000000000000000000000000000000000..1b38c0bc4e2aefb5aab98a817cb251b31d395813 --- /dev/null +++ b/isis/src/base/objs/PolygonTools/PolygonTools_Darwin_i386_10_5_8.truth @@ -0,0 +1,64 @@ +Unit test for PolygonTools + +Coordinates of polygon 1:(0 0, 0 1, 1 1, 1 0, 0 0) + +Coordinates of polygon 2:(360 1, 359 1, 359 0, 360 0, 360 1) + +Coordinates of hole for polygon 2:(359.75 0.75, 359.25 0.75, 359.25 0.25, 359.75 0.25, 359.75 0.75) + +Copy of the multipolygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +X/Y polygon radius (1) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0174532925199433, 0.0174506342989556 0.0174532925199433, 0.0174532925199433 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((6.2822283476240113 0.0174532925199433, 6.2647777133250555 0.0174532925199433, 6.2657320146596422 0.0000000000000000, 6.2831853071795862 0.0000000000000000, 6.2822283476240113 0.0174532925199433), (6.2782840621378480 0.0130899693899575, 6.2695581635108333 0.0130899693899575, 6.2700356510010868 0.0043633231299858, 6.2787622141896753 0.0043633231299858, 6.2782840621378480 0.0130899693899575))) + +X/Y polygon radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.1745329251994329, 0.1745063429895559 0.1745329251994329, 0.1745329251994329 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((62.8222834762401163 0.1745329251994329, 62.6477771332505498 0.1745329251994329, 62.6573201465964189 0.0000000000000000, 62.8318530717958623 0.0000000000000000, 62.8222834762401163 0.1745329251994329), (62.7828406213784831 0.1308996938995747, 62.6955816351083257 0.1308996938995747, 62.7003565100108631 0.0436332312998582, 62.7876221418967546 0.0436332312998582, 62.7828406213784831 0.1308996938995747))) + +Lat/Lon polygon from X/Y with radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 358.9999999999999432 1.0000000000000000, 358.9999999999999432 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7499999999999432 0.7500000000000000, 359.2499999999999432 0.7500000000000000, 359.2499999999999432 0.2500000000000000, 359.7499999999999432 0.2500000000000000, 359.7499999999999432 0.7500000000000000))) + +Coordinates of Lon/Lat polygon:(171.81 -31.2795, 173.661 -13.6618, 188.286 -15.754, 188.142 -33.1118, 171.81 -31.2795) + +Coordinates of Sample/Line polygon:MULTIPOLYGON (((0.9999682378838770 1.0001055500506482, 1204.0000480009568946 0.9999580487848334, 1203.9997839350683080 1056.0000950847629611, 0.9997879613397345 1055.9999158657785756, 0.9999682378838770 1.0001055500506482))) + +Well Knowen Text Polygon: +MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +GML Ploygon: + + + + + 0.0-90.0 + 360.090.0 + + + + + test + 0,0 0,1 1,1 1,0 0,0 360,1 359,1 359,0 360,0 360,1 359.75,0.75 359.25,0.75 359.25,0.25 359.75,0.25 359.75,0.75 + + + + +GML Thickness: +1.35030864197531e-05 + + +Testing Despike +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 -10.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing FixGeometry +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000000 5.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing Equal +Same Poly Equal? 1 - 1 +Rearranged Poly Equal? 1 - 1 +Past 15 Places Equal? 1 - 0 +At 15 Place Difference Equal? 0 - 0 +Significantly Different Equal? 0 - 0 diff --git a/isis/src/base/objs/PolygonTools/PolygonTools_Darwin_powerpc.truth b/isis/src/base/objs/PolygonTools/PolygonTools_Darwin_powerpc.truth new file mode 100644 index 0000000000000000000000000000000000000000..b977ac6d7c6f0eab04a2a4508751b8f45431d27d --- /dev/null +++ b/isis/src/base/objs/PolygonTools/PolygonTools_Darwin_powerpc.truth @@ -0,0 +1,64 @@ +Unit test for PolygonTools + +Coordinates of polygon 1:(0 0, 0 1, 1 1, 1 0, 0 0) + +Coordinates of polygon 2:(360 1, 359 1, 359 0, 360 0, 360 1) + +Coordinates of hole for polygon 2:(359.75 0.75, 359.25 0.75, 359.25 0.25, 359.75 0.25, 359.75 0.75) + +Copy of the multipolygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +X/Y polygon radius (1) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0174532925199433, 0.0174506342989556 0.0174532925199433, 0.0174532925199433 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((6.2822283476240113 0.0174532925199433, 6.2647777133250555 0.0174532925199433, 6.2657320146596422 0.0000000000000000, 6.2831853071795862 0.0000000000000000, 6.2822283476240113 0.0174532925199433), (6.2782840621378480 0.0130899693899575, 6.2695581635108333 0.0130899693899575, 6.2700356510010868 0.0043633231299858, 6.2787622141896753 0.0043633231299858, 6.2782840621378480 0.0130899693899575))) + +X/Y polygon radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.1745329251994329, 0.1745063429895559 0.1745329251994329, 0.1745329251994329 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((62.8222834762401163 0.1745329251994329, 62.6477771332505498 0.1745329251994329, 62.6573201465964189 0.0000000000000000, 62.8318530717958623 0.0000000000000000, 62.8222834762401163 0.1745329251994329), (62.7828406213784831 0.1308996938995747, 62.6955816351083257 0.1308996938995747, 62.7003565100108631 0.0436332312998582, 62.7876221418967546 0.0436332312998582, 62.7828406213784831 0.1308996938995747))) + +Lat/Lon polygon from X/Y with radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 358.9999999999999432 1.0000000000000000, 358.9999999999999432 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7499999999999432 0.7500000000000000, 359.2499999999999432 0.7500000000000000, 359.2499999999999432 0.2500000000000000, 359.7499999999999432 0.2500000000000000, 359.7499999999999432 0.7500000000000000))) + +Coordinates of Lon/Lat polygon:(171.81 -31.2795, 173.661 -13.6618, 188.286 -15.754, 188.142 -33.1118, 171.81 -31.2795) + +Coordinates of Sample/Line polygon:MULTIPOLYGON (((0.9999682378742136 1.0001055500566736, 1204.0000480009464354 0.9999580487922231, 1203.9997839350528466 1056.0000950847588683, 0.9997879613293890 1055.9999158657747103, 0.9999682378742136 1.0001055500566736))) + +Well Knowen Text Polygon: +MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +GML Ploygon: + + + + + 0.0-90.0 + 360.090.0 + + + + + test + 0,0 0,1 1,1 1,0 0,0 360,1 359,1 359,0 360,0 360,1 359.75,0.75 359.25,0.75 359.25,0.25 359.75,0.25 359.75,0.75 + + + + +GML Thickness: +1.35030864197531e-05 + + +Testing Despike +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 -10.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing FixGeometry +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000000 5.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing Equal +Same Poly Equal? 1 - 1 +Rearranged Poly Equal? 1 - 1 +Past 15 Places Equal? 1 - 0 +At 15 Place Difference Equal? 0 - 0 +Significantly Different Equal? 0 - 0 diff --git a/isis/src/base/objs/PolygonTools/PolygonTools_Linux_i686_RedHat5_4.truth b/isis/src/base/objs/PolygonTools/PolygonTools_Linux_i686_RedHat5_4.truth new file mode 100644 index 0000000000000000000000000000000000000000..0c2aa789e563efdfba25046265a7bff32d39f663 --- /dev/null +++ b/isis/src/base/objs/PolygonTools/PolygonTools_Linux_i686_RedHat5_4.truth @@ -0,0 +1,64 @@ +Unit test for PolygonTools + +Coordinates of polygon 1:(0 0, 0 1, 1 1, 1 0, 0 0) + +Coordinates of polygon 2:(360 1, 359 1, 359 0, 360 0, 360 1) + +Coordinates of hole for polygon 2:(359.75 0.75, 359.25 0.75, 359.25 0.25, 359.75 0.25, 359.75 0.75) + +Copy of the multipolygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +X/Y polygon radius (1) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0174532925199433, 0.0174506342989556 0.0174532925199433, 0.0174532925199433 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((6.2822283476240113 0.0174532925199433, 6.2647777133250564 0.0174532925199433, 6.2657320146596431 0.0000000000000000, 6.2831853071795862 0.0000000000000000, 6.2822283476240113 0.0174532925199433), (6.2782840621378488 0.0130899693899575, 6.2695581635108333 0.0130899693899575, 6.2700356510010868 0.0043633231299858, 6.2787622141896762 0.0043633231299858, 6.2782840621378488 0.0130899693899575))) + +X/Y polygon radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.1745329251994329, 0.1745063429895559 0.1745329251994329, 0.1745329251994329 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((62.8222834762401163 0.1745329251994329, 62.6477771332505569 0.1745329251994329, 62.6573201465964331 0.0000000000000000, 62.8318530717958623 0.0000000000000000, 62.8222834762401163 0.1745329251994329), (62.7828406213784902 0.1308996938995747, 62.6955816351083328 0.1308996938995747, 62.7003565100108702 0.0436332312998582, 62.7876221418967617 0.0436332312998582, 62.7828406213784902 0.1308996938995747))) + +Lat/Lon polygon from X/Y with radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 0.9999999999999998 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 358.9999999999999432 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +Coordinates of Lon/Lat polygon:(171.81 -31.2795, 173.661 -13.6618, 188.286 -15.754, 188.142 -33.1118, 171.81 -31.2795) + +Coordinates of Sample/Line polygon:MULTIPOLYGON (((0.9999682378761703 1.0001055500490814, 1204.0000480009509829 0.9999580487903810, 1203.9997839350664890 1056.0000950847563672, 0.9997879613399645 1055.9999158657690259, 0.9999682378761703 1.0001055500490814))) + +Well Knowen Text Polygon: +MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +GML Ploygon: + + + + + 0.0-90.0 + 360.090.0 + + + + + test + 0,0 0,1 1,1 1,0 0,0 360,1 359,1 359,0 360,0 360,1 359.75,0.75 359.25,0.75 359.25,0.25 359.75,0.25 359.75,0.75 + + + + +GML Thickness: +1.35030864197531e-05 + + +Testing Despike +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 -10.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing FixGeometry +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000000 5.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing Equal +Same Poly Equal? 1 - 1 +Rearranged Poly Equal? 1 - 1 +Past 15 Places Equal? 1 - 0 +At 15 Place Difference Equal? 0 - 0 +Significantly Different Equal? 0 - 0 diff --git a/isis/src/base/objs/PolygonTools/PolygonTools_Linux_i686_RedHat5_5.truth b/isis/src/base/objs/PolygonTools/PolygonTools_Linux_i686_RedHat5_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..0c2aa789e563efdfba25046265a7bff32d39f663 --- /dev/null +++ b/isis/src/base/objs/PolygonTools/PolygonTools_Linux_i686_RedHat5_5.truth @@ -0,0 +1,64 @@ +Unit test for PolygonTools + +Coordinates of polygon 1:(0 0, 0 1, 1 1, 1 0, 0 0) + +Coordinates of polygon 2:(360 1, 359 1, 359 0, 360 0, 360 1) + +Coordinates of hole for polygon 2:(359.75 0.75, 359.25 0.75, 359.25 0.25, 359.75 0.25, 359.75 0.75) + +Copy of the multipolygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +X/Y polygon radius (1) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0174532925199433, 0.0174506342989556 0.0174532925199433, 0.0174532925199433 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((6.2822283476240113 0.0174532925199433, 6.2647777133250564 0.0174532925199433, 6.2657320146596431 0.0000000000000000, 6.2831853071795862 0.0000000000000000, 6.2822283476240113 0.0174532925199433), (6.2782840621378488 0.0130899693899575, 6.2695581635108333 0.0130899693899575, 6.2700356510010868 0.0043633231299858, 6.2787622141896762 0.0043633231299858, 6.2782840621378488 0.0130899693899575))) + +X/Y polygon radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.1745329251994329, 0.1745063429895559 0.1745329251994329, 0.1745329251994329 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((62.8222834762401163 0.1745329251994329, 62.6477771332505569 0.1745329251994329, 62.6573201465964331 0.0000000000000000, 62.8318530717958623 0.0000000000000000, 62.8222834762401163 0.1745329251994329), (62.7828406213784902 0.1308996938995747, 62.6955816351083328 0.1308996938995747, 62.7003565100108702 0.0436332312998582, 62.7876221418967617 0.0436332312998582, 62.7828406213784902 0.1308996938995747))) + +Lat/Lon polygon from X/Y with radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 0.9999999999999998 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 358.9999999999999432 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +Coordinates of Lon/Lat polygon:(171.81 -31.2795, 173.661 -13.6618, 188.286 -15.754, 188.142 -33.1118, 171.81 -31.2795) + +Coordinates of Sample/Line polygon:MULTIPOLYGON (((0.9999682378761703 1.0001055500490814, 1204.0000480009509829 0.9999580487903810, 1203.9997839350664890 1056.0000950847563672, 0.9997879613399645 1055.9999158657690259, 0.9999682378761703 1.0001055500490814))) + +Well Knowen Text Polygon: +MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +GML Ploygon: + + + + + 0.0-90.0 + 360.090.0 + + + + + test + 0,0 0,1 1,1 1,0 0,0 360,1 359,1 359,0 360,0 360,1 359.75,0.75 359.25,0.75 359.25,0.25 359.75,0.25 359.75,0.75 + + + + +GML Thickness: +1.35030864197531e-05 + + +Testing Despike +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 -10.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing FixGeometry +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000000 5.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing Equal +Same Poly Equal? 1 - 1 +Rearranged Poly Equal? 1 - 1 +Past 15 Places Equal? 1 - 0 +At 15 Place Difference Equal? 0 - 0 +Significantly Different Equal? 0 - 0 diff --git a/isis/src/base/objs/PolygonTools/PolygonTools_Linux_i686_SUSE10_1.truth b/isis/src/base/objs/PolygonTools/PolygonTools_Linux_i686_SUSE10_1.truth new file mode 100644 index 0000000000000000000000000000000000000000..1df1547e96cf9e333421967cb74b85b1262f0c3d --- /dev/null +++ b/isis/src/base/objs/PolygonTools/PolygonTools_Linux_i686_SUSE10_1.truth @@ -0,0 +1,64 @@ +Unit test for PolygonTools + +Coordinates of polygon 1:(0 0, 0 1, 1 1, 1 0, 0 0) + +Coordinates of polygon 2:(360 1, 359 1, 359 0, 360 0, 360 1) + +Coordinates of hole for polygon 2:(359.75 0.75, 359.25 0.75, 359.25 0.25, 359.75 0.25, 359.75 0.75) + +Copy of the multipolygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +X/Y polygon radius (1) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0174532925199433, 0.0174506342989556 0.0174532925199433, 0.0174532925199433 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((6.2822283476240113 0.0174532925199433, 6.2647777133250564 0.0174532925199433, 6.2657320146596431 0.0000000000000000, 6.2831853071795862 0.0000000000000000, 6.2822283476240113 0.0174532925199433), (6.2782840621378488 0.0130899693899575, 6.2695581635108333 0.0130899693899575, 6.2700356510010868 0.0043633231299858, 6.2787622141896762 0.0043633231299858, 6.2782840621378488 0.0130899693899575))) + +X/Y polygon radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.1745329251994329, 0.1745063429895559 0.1745329251994329, 0.1745329251994329 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((62.8222834762401163 0.1745329251994329, 62.6477771332505569 0.1745329251994329, 62.6573201465964260 0.0000000000000000, 62.8318530717958623 0.0000000000000000, 62.8222834762401163 0.1745329251994329), (62.7828406213784902 0.1308996938995747, 62.6955816351083328 0.1308996938995747, 62.7003565100108702 0.0436332312998582, 62.7876221418967617 0.0436332312998582, 62.7828406213784902 0.1308996938995747))) + +Lat/Lon polygon from X/Y with radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 0.9999999999999998 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 358.9999999999999432 1.0000000000000000, 358.9999999999999432 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +Coordinates of Lon/Lat polygon:(171.81 -31.2795, 173.661 -13.6618, 188.286 -15.754, 188.142 -33.1118, 171.81 -31.2795) + +Coordinates of Sample/Line polygon:MULTIPOLYGON (((0.9999682378761703 1.0001055500487794, 1204.0000480009509829 0.9999580487903810, 1203.9997839350664890 1056.0000950847563672, 0.9997879613399645 1055.9999158657690259, 0.9999682378761703 1.0001055500487794))) + +Well Knowen Text Polygon: +MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +GML Ploygon: + + + + + 0.0-90.0 + 360.090.0 + + + + + test + 0,0 0,1 1,1 1,0 0,0 360,1 359,1 359,0 360,0 360,1 359.75,0.75 359.25,0.75 359.25,0.25 359.75,0.25 359.75,0.75 + + + + +GML Thickness: +1.35030864197531e-05 + + +Testing Despike +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 -10.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing FixGeometry +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000000 5.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing Equal +Same Poly Equal? 1 - 1 +Rearranged Poly Equal? 1 - 1 +Past 15 Places Equal? 1 - 0 +At 15 Place Difference Equal? 0 - 0 +Significantly Different Equal? 0 - 0 diff --git a/isis/src/base/objs/PolygonTools/PolygonTools_Linux_x86_64_SUSE10_1.truth b/isis/src/base/objs/PolygonTools/PolygonTools_Linux_x86_64_SUSE10_1.truth new file mode 100644 index 0000000000000000000000000000000000000000..1c4780cfe6714ef3b75f9e17c77f6145366c280c --- /dev/null +++ b/isis/src/base/objs/PolygonTools/PolygonTools_Linux_x86_64_SUSE10_1.truth @@ -0,0 +1,64 @@ +Unit test for PolygonTools + +Coordinates of polygon 1:(0 0, 0 1, 1 1, 1 0, 0 0) + +Coordinates of polygon 2:(360 1, 359 1, 359 0, 360 0, 360 1) + +Coordinates of hole for polygon 2:(359.75 0.75, 359.25 0.75, 359.25 0.25, 359.75 0.25, 359.75 0.75) + +Copy of the multipolygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +Lon/Lat polygon = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +X/Y polygon radius (1) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0174532925199433, 0.0174506342989556 0.0174532925199433, 0.0174532925199433 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((6.2822283476240113 0.0174532925199433, 6.2647777133250555 0.0174532925199433, 6.2657320146596422 0.0000000000000000, 6.2831853071795862 0.0000000000000000, 6.2822283476240113 0.0174532925199433), (6.2782840621378480 0.0130899693899575, 6.2695581635108333 0.0130899693899575, 6.2700356510010868 0.0043633231299858, 6.2787622141896753 0.0043633231299858, 6.2782840621378480 0.0130899693899575))) + +X/Y polygon radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 0.1745329251994329, 0.1745063429895559 0.1745329251994329, 0.1745329251994329 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((62.8222834762401163 0.1745329251994329, 62.6477771332505498 0.1745329251994329, 62.6573201465964189 0.0000000000000000, 62.8318530717958623 0.0000000000000000, 62.8222834762401163 0.1745329251994329), (62.7828406213784831 0.1308996938995747, 62.6955816351083257 0.1308996938995747, 62.7003565100108631 0.0436332312998582, 62.7876221418967546 0.0436332312998582, 62.7828406213784831 0.1308996938995747))) + +Lat/Lon polygon from X/Y with radius (10) = MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 358.9999999999999432 1.0000000000000000, 358.9999999999999432 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7499999999999432 0.7500000000000000, 359.2499999999999432 0.7500000000000000, 359.2499999999999432 0.2500000000000000, 359.7499999999999432 0.2500000000000000, 359.7499999999999432 0.7500000000000000))) + +Coordinates of Lon/Lat polygon:(171.81 -31.2795, 173.661 -13.6618, 188.286 -15.754, 188.142 -33.1118, 171.81 -31.2795) + +Coordinates of Sample/Line polygon:MULTIPOLYGON (((0.9999682378838770 1.0001055500507618, 1204.0000480009603052 0.9999580488017727, 1203.9997839350635331 1056.0000950847540935, 0.9997879613348459 1055.9999158657785756, 0.9999682378838770 1.0001055500507618))) + +Well Knowen Text Polygon: +MULTIPOLYGON (((0.0000000000000000 0.0000000000000000, 0.0000000000000000 1.0000000000000000, 1.0000000000000000 1.0000000000000000, 1.0000000000000000 0.0000000000000000, 0.0000000000000000 0.0000000000000000)), ((360.0000000000000000 1.0000000000000000, 359.0000000000000000 1.0000000000000000, 359.0000000000000000 0.0000000000000000, 360.0000000000000000 0.0000000000000000, 360.0000000000000000 1.0000000000000000), (359.7500000000000000 0.7500000000000000, 359.2500000000000000 0.7500000000000000, 359.2500000000000000 0.2500000000000000, 359.7500000000000000 0.2500000000000000, 359.7500000000000000 0.7500000000000000))) + +GML Ploygon: + + + + + 0.0-90.0 + 360.090.0 + + + + + test + 0,0 0,1 1,1 1,0 0,0 360,1 359,1 359,0 360,0 360,1 359.75,0.75 359.25,0.75 359.25,0.25 359.75,0.25 359.75,0.75 + + + + +GML Thickness: +1.35030864197531e-05 + + +Testing Despike +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 -10.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000100000 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing FixGeometry +Input: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000000 5.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) +Output: LINEARRING (1.0000000000000000 1.0000000000000000, 5.0000000000000000 1.0000000000000000, 5.0000000000000098 5.0000000000000000, 1.0000000000000000 5.0000000000000000, 1.0000000000000000 1.0000000000000000) + + +Testing Equal +Same Poly Equal? 1 - 1 +Rearranged Poly Equal? 1 - 1 +Past 15 Places Equal? 1 - 0 +At 15 Place Difference Equal? 0 - 0 +Significantly Different Equal? 0 - 0 diff --git a/isis/src/base/objs/PolygonTools/unitTest.cpp b/isis/src/base/objs/PolygonTools/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d535028da5c38b31e44f5db5ce66cd4f0bf8e82d --- /dev/null +++ b/isis/src/base/objs/PolygonTools/unitTest.cpp @@ -0,0 +1,232 @@ +#include "UniversalGroundMap.h" +#include "ProjectionFactory.h" +#include "PolygonTools.h" +#include "Preference.h" +#include "geos/geom/CoordinateSequence.h" +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/geom/LinearRing.h" +#include "geos/geom/Polygon.h" +#include "geos/util/GEOSException.h" + +using namespace std; +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + try { + cout << "Unit test for PolygonTools" << endl << endl; + + // Create coordinate sequence for the first of two polygons + geos::geom::CoordinateSequence *pts = new geos::geom::CoordinateArraySequence (); + pts->add (geos::geom::Coordinate (0.0, 0.0)); + pts->add (geos::geom::Coordinate (0.0, 1.0)); + pts->add (geos::geom::Coordinate (1.0, 1.0)); + pts->add (geos::geom::Coordinate (1.0, 0.0)); + pts->add (geos::geom::Coordinate (0.0, 0.0)); + cout << "Coordinates of polygon 1:" << pts->toString() << endl << endl; + + // Create the first polygon + vector polys; + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing (pts),NULL)); + + // Create coordinate sequence for the second of two polygons + geos::geom::CoordinateSequence *pts2 = new geos::geom::CoordinateArraySequence (); + pts2->add (geos::geom::Coordinate (360.0, 1.0)); + pts2->add (geos::geom::Coordinate (359.0, 1.0)); + pts2->add (geos::geom::Coordinate (359.0, 0.0)); + pts2->add (geos::geom::Coordinate (360.0, 0.0)); + pts2->add (geos::geom::Coordinate (360.0, 1.0)); + cout << "Coordinates of polygon 2:" << pts2->toString() << endl << endl; + + // Create coordinate sequence for the hole in the second polygon + geos::geom::CoordinateSequence *pts3 = new geos::geom::DefaultCoordinateSequence (); + pts3->add (geos::geom::Coordinate (359.75, 0.75)); + pts3->add (geos::geom::Coordinate (359.25, 0.75)); + pts3->add (geos::geom::Coordinate (359.25, 0.25)); + pts3->add (geos::geom::Coordinate (359.75, 0.25)); + pts3->add (geos::geom::Coordinate (359.75, 0.75)); + cout << "Coordinates of hole for polygon 2:" << pts3->toString() << endl << endl; + + vector *hole2 = new vector; + hole2->push_back(Isis::globalFactory.createLinearRing(pts3)); + + // Create the second polygon + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing (pts2), hole2)); + + // Create a multipolygon from the two polygons + geos::geom::MultiPolygon* mPolygon = Isis::globalFactory.createMultiPolygon (polys); + + // Create a copy of the multipolygon + geos::geom::MultiPolygon* tmpMp = PolygonTools::CopyMultiPolygon(mPolygon); + cout << "Copy of the multipolygon = " << tmpMp->toString() << endl << endl; + + Isis::Pvl lab; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = lab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius", 1.0); + mapGroup += Isis::PvlKeyword("PolarRadius", 1.0); + mapGroup += Isis::PvlKeyword("LatitudeType", "Planetocentric"); + mapGroup += Isis::PvlKeyword("LongitudeDirection", "PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain", 360); + mapGroup += Isis::PvlKeyword("CenterLatitude", 0); + mapGroup += Isis::PvlKeyword("CenterLongitude", 0); + mapGroup += Isis::PvlKeyword("ProjectionName", "Sinusoidal"); + + Projection *proj = ProjectionFactory::Create(lab); + + cout << "Lon/Lat polygon = " << mPolygon->toString() << endl << endl; + + cout << "X/Y polygon radius (1) = " + << (PolygonTools::LatLonToXY(*mPolygon, proj))->toString() << endl << endl; + + delete proj; + + // Change the radius and set a new projection + // Then get the XYPolygon again + mapGroup.DeleteKeyword("EquatorialRadius"); + mapGroup += Isis::PvlKeyword("EquatorialRadius", 10.0); + mapGroup.DeleteKeyword("PolarRadius"); + mapGroup += Isis::PvlKeyword("PolarRadius", 10.0); + + proj = ProjectionFactory::Create(lab); + cout << "X/Y polygon radius (10) = " + << (PolygonTools::LatLonToXY(*mPolygon, proj))->toString() << endl << endl; + + // Convert a Lon/Lat poly to X/Y and then back to Lon/Lat + cout << "Lat/Lon polygon from X/Y with radius (10) = " + << PolygonTools::XYToLatLon(*PolygonTools::LatLonToXY(*mPolygon, proj), proj)->toString() + << endl << endl; + + // Create a UniversalGroundMap so we can test the SampleLinePolygon stuff + Pvl pvl("unitTest.lbl"); + UniversalGroundMap ugm = UniversalGroundMap(pvl); + + // Create coordinate sequence for the first of two polygons + geos::geom::CoordinateSequence *llpts = new geos::geom::CoordinateArraySequence (); + ugm.SetImage(1.0, 1.0); + llpts->add (geos::geom::Coordinate (ugm.UniversalLongitude(), ugm.UniversalLatitude())); + ugm.SetImage(1204.0, 1.0); + llpts->add (geos::geom::Coordinate (ugm.UniversalLongitude(), ugm.UniversalLatitude())); + ugm.SetImage(1204.0, 1056.0); + llpts->add (geos::geom::Coordinate (ugm.UniversalLongitude(), ugm.UniversalLatitude())); + ugm.SetImage(1.0, 1056.0); + llpts->add (geos::geom::Coordinate (ugm.UniversalLongitude(), ugm.UniversalLatitude())); + ugm.SetImage(1.0, 1.0); + llpts->add (geos::geom::Coordinate (ugm.UniversalLongitude(), ugm.UniversalLatitude())); + cout << "Coordinates of Lon/Lat polygon:" << llpts->toString() << endl << endl; + + // Create the L/L polygon + vector llpolys; + llpolys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing (llpts),NULL)); + + geos::geom::MultiPolygon* llmPolygon = Isis::globalFactory.createMultiPolygon (llpolys); + + geos::geom::MultiPolygon *slmPolygon = PolygonTools::LatLonToSampleLine(*llmPolygon, &ugm); + cout << "Coordinates of Sample/Line polygon:" << slmPolygon->toString() << endl; + + cout << endl; + + cout << "Well Knowen Text Polygon:" << endl; + std::cout<toString()<add (geos::geom::Coordinate (1.0, 1.0)); + pts->add (geos::geom::Coordinate (5.0, 1.0)); + pts->add (geos::geom::Coordinate (5.00000000001, -10.0)); + pts->add (geos::geom::Coordinate (5.00000000001, 5.0)); + pts->add (geos::geom::Coordinate (1.0, 5.0)); + pts->add (geos::geom::Coordinate (1.0, 1.0)); + cout << "Input: " << Isis::globalFactory.createLinearRing (pts)->toString() << endl; + cout << "Output: " << PolygonTools::Despike(Isis::globalFactory.createLinearRing (pts))->toString() << endl; + + cout << endl << endl; + + cout << "Testing FixGeometry" << endl; + pts = new geos::geom::CoordinateArraySequence (); + pts->add (geos::geom::Coordinate (1.0, 1.0)); + pts->add (geos::geom::Coordinate (5.0, 1.0)); + pts->add (geos::geom::Coordinate (5.0, 5.0)); + pts->add (geos::geom::Coordinate (5.00000000000001, 5.0)); + pts->add (geos::geom::Coordinate (1.0, 5.0)); + pts->add (geos::geom::Coordinate (1.0, 1.0)); + cout << "Input: " << Isis::globalFactory.createLinearRing (pts)->toString() << endl; + cout << "Output: " << PolygonTools::Despike(Isis::globalFactory.createLinearRing (pts))->toString() << endl; + + cout << endl << endl; + + cout << "Testing Equal" << endl; + pts = new geos::geom::CoordinateArraySequence (); + pts->add (geos::geom::Coordinate (1.0, 1.0)); + pts->add (geos::geom::Coordinate (5.0, 1.0)); + pts->add (geos::geom::Coordinate (5.0, 5.0)); + pts->add (geos::geom::Coordinate (1.0, 5.0)); + pts->add (geos::geom::Coordinate (1.0, 1.0)); + geos::geom::Polygon *poly1 = Isis::globalFactory.createPolygon(Isis::globalFactory.createLinearRing (*pts), NULL); + cout << "Same Poly Equal? " << PolygonTools::Equal(poly1, poly1) << " - " << poly1->equals(poly1) << endl; + pts2 = new geos::geom::CoordinateArraySequence (); + pts2->add (geos::geom::Coordinate (5.0, 1.0)); + pts2->add (geos::geom::Coordinate (5.0, 5.0)); + pts2->add (geos::geom::Coordinate (1.0, 5.0)); + pts2->add (geos::geom::Coordinate (1.0, 1.0)); + pts2->add (geos::geom::Coordinate (5.0, 1.0)); + geos::geom::Polygon *poly2 = Isis::globalFactory.createPolygon(Isis::globalFactory.createLinearRing (*pts2), NULL); + cout << "Rearranged Poly Equal? " << PolygonTools::Equal(poly1, poly2) << " - " << poly1->equals(poly2) << endl; + pts2 = new geos::geom::CoordinateArraySequence (); + pts2->add (geos::geom::Coordinate (5.0, 1.0)); + pts2->add (geos::geom::Coordinate (5.0, 5.0)); + pts2->add (geos::geom::Coordinate (1.000000000000001, 5.0)); + pts2->add (geos::geom::Coordinate (1.0, 1.0)); + pts2->add (geos::geom::Coordinate (5.0, 1.0)); + poly2 = Isis::globalFactory.createPolygon(Isis::globalFactory.createLinearRing (*pts2), NULL); + cout << "Past 15 Places Equal? " << PolygonTools::Equal(poly1, poly2) << " - " << poly1->equals(poly2) << endl; + pts2 = new geos::geom::CoordinateArraySequence (); + pts2->add (geos::geom::Coordinate (5.0, 1.0)); + pts2->add (geos::geom::Coordinate (5.0, 5.0)); + pts2->add (geos::geom::Coordinate (1.00000000000001, 5.0)); + pts2->add (geos::geom::Coordinate (1.0, 1.0)); + pts2->add (geos::geom::Coordinate (5.0, 1.0)); + poly2 = Isis::globalFactory.createPolygon(Isis::globalFactory.createLinearRing (*pts2), NULL); + cout << "At 15 Place Difference Equal? " << PolygonTools::Equal(poly1, poly2) << " - " << poly1->equals(poly2) << endl; + pts2 = new geos::geom::CoordinateArraySequence (); + pts2->add (geos::geom::Coordinate (5.0, 1.0)); + pts2->add (geos::geom::Coordinate (5.0, 5.0)); + pts2->add (geos::geom::Coordinate (1.0000000000001, 5.0)); + pts2->add (geos::geom::Coordinate (1.0, 1.0)); + pts2->add (geos::geom::Coordinate (5.0, 1.0)); + poly2 = Isis::globalFactory.createPolygon(Isis::globalFactory.createLinearRing (*pts2), NULL); + cout << "Significantly Different Equal? " << PolygonTools::Equal(poly1, poly2) << " - " << poly1->equals(poly2) << endl; + + return 0; + } + catch (Isis::iException &e) { + cout << "ERROR " << e.what() << endl; + e.Report(); + } + catch (geos::util::GEOSException *exc) { + cout <<"GEOS Exception: " << exc->what() << endl; + delete exc; + } + catch (std::exception const &se) { + cout << "std::exception " << se.what() << endl; + } + catch (...) { + cout << " Other error" << endl; + } +} diff --git a/isis/src/base/objs/PolygonTools/unitTest.lbl b/isis/src/base/objs/PolygonTools/unitTest.lbl new file mode 100644 index 0000000000000000000000000000000000000000..c025c753e935f516697bec51f3d0a45587adf7e3 --- /dev/null +++ b/isis/src/base/objs/PolygonTools/unitTest.lbl @@ -0,0 +1,109 @@ +Object = IsisCube + Object = Core + StartByte = 1 + ^Core = unitTest.lab.cub + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 1204 + Lines = 1056 + Bands = 1 + End_Group + + Group = Pixels + Type = UnsignedByte + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = VIKING_ORBITER_2 + InstrumentId = VISUAL_IMAGING_SUBSYSTEM_CAMERA_B + TargetName = MARS + StartTime = 1977-08-03T15:59:09 + ExposureDuration = 0.135800 + SpacecraftClockCount = 53448121 + FloodModeId = ON + GainModeId = LOW + OffsetModeId = ON + End_Group + + Group = Archive + DataSetId = VO1/VO2-M-VIS-2-EDR-V2.0 + ProductId = 348B26 + MissonPhaseName = EXTENDED_MISSION + ImageNumber = 53448121 + OrbitNumber = 348 + End_Group + + Group = BandBin + FilterName = RED + FilterId = 6 + End_Group + + Group = Kernels + LeapSecond = $base/kernels/lsk/naif0008.tls + TargetAttitudeShape = $base/kernels/pck/pck00008.tpc + TargetPosition = $base/kernels/spk/de405.bsp + InstrumentPointing = $viking2/kernels/ck/vo2_sedr_ck2.bc + Instrument = Null + SpacecraftClock = ($viking2/kernels/sclk/vo2_fict.tsc, + $viking2/kernels/sclk/vo2_fsc.tsc) + InstrumentPosition = $viking2/kernels/spk/vo2_rcon.bsp + Frame = $viking2/kernels/fk/vo2_v10.tf + InstrumentAddendum = $viking2/kernels/iak/vikingAddendum003.ti + ElevationModel = Null + NaifFrameCode = -30002 + End_Group + + Group = Reseaus + Line = (5, 7, 9, 10, 11, 12, 14, 15, 17, 19, 20, 135, 136, 137, 138, + 139, 140, 142, 143, 144, 146, 148, 149, 265, 266, 267, 268, + 269, 270, 271, 272, 274, 276, 278, 395, 395, 397, 398, 398, + 399, 400, 401, 402, 404, 406, 407, 525, 526, 526, 527, 528, + 528, 529, 530, 531, 533, 535, 654, 655, 655, 656, 657, 657, + 658, 659, 660, 661, 663, 664, 784, 784, 785, 785, 786, 786, + 787, 788, 789, 790, 793, 914, 914, 914, 914, 915, 915, 916, + 916, 917, 918, 920, 922, 1043, 1043, 1043, 1043, 1044, 1044, + 1045, 1045, 1046, 1048, 1051) + Sample = (23, 141, 257, 373, 489, 605, 720, 836, 952, 1068, 1185, 23, + 82, 199, 315, 431, 546, 662, 778, 894, 1010, 1126, 1184, 24, + 141, 257, 373, 489, 605, 720, 836, 952, 1068, 1184, 24, 82, + 199, 315, 432, 547, 663, 779, 895, 1011, 1127, 1184, 24, 141, + 258, 374, 490, 605, 721, 837, 953, 1070, 1185, 24, 83, 200, + 316, 432, 548, 664, 780, 896, 1012, 1128, 1185, 24, 142, 258, + 374, 490, 606, 722, 838, 954, 1070, 1186, 23, 82, 199, 316, + 432, 548, 664, 780, 896, 1013, 1129, 1186, 22, 140, 257, 374, + 489, 606, 722, 838, 954, 1071, 1187) + Type = (1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 6, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 4, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 6, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 4, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 6, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, + 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 4, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 6) + Valid = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0) + Template = $viking2/reseaus/vo2.visb.template.cub + Status = Nominal + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = History + Name = IsisCube + StartByte = 1 + Bytes = 805 + ^History = unitTest.IsisCube +End_Object +End diff --git a/isis/src/base/objs/PolynomialBivariate/Makefile b/isis/src/base/objs/PolynomialBivariate/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2223209be4e5b5344feb443de61f1109d3c30b9d --- /dev/null +++ b/isis/src/base/objs/PolynomialBivariate/Makefile @@ -0,0 +1,5 @@ +INCS = PolynomialBivariate.h +SRCS = PolynomialBivariate.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PolynomialBivariate/PolynomialBivariate.cpp b/isis/src/base/objs/PolynomialBivariate/PolynomialBivariate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f81e939675b1d25aeaa6a8efd8be807c24f2625 --- /dev/null +++ b/isis/src/base/objs/PolynomialBivariate/PolynomialBivariate.cpp @@ -0,0 +1,66 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/02/07 18:53:03 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "PolynomialBivariate.h" + +namespace Isis { + /** + * Create a PolynomialBivariate object + * + * @param degree The order/degree of the polynomial + * + */ + PolynomialBivariate::PolynomialBivariate(int degree) : + Isis::BasisFunction("PolynomialBivariate",2,((degree+1)*(degree+2))/2) { + p_degree = degree; + } + + /** + * This is the the overriding virtual function that provides the expansion of + * the two input variables into the polynomial equation. + * See BasisFunction for more information. + * + * @param vars A vector of double values to use for the expansion. + */ + void PolynomialBivariate::Expand(const std::vector &vars) { + std::vector > terms; + terms.resize(p_degree+1); + terms[0].push_back(1.0); + for (int i=1; i<=p_degree; i++) { + for (int t=0; t<(int)terms[i-1].size(); t++) { + terms[i].push_back(terms[i-1][t] * vars[0]); + if (t == ((int)terms[i-1].size() - 1)) { + terms[i].push_back(terms[i-1][t] * vars[1]); + } + } + } + + p_terms.clear(); + for (int i=0; i<=p_degree; i++) { + for (int t=0; t<(int)terms[i].size(); t++) { + p_terms.push_back(terms[i][t]); + } + } + } +} // end namespace isis + diff --git a/isis/src/base/objs/PolynomialBivariate/PolynomialBivariate.h b/isis/src/base/objs/PolynomialBivariate/PolynomialBivariate.h new file mode 100644 index 0000000000000000000000000000000000000000..29b9f9e521d83aaa78d756301bf8df27f86d8fb2 --- /dev/null +++ b/isis/src/base/objs/PolynomialBivariate/PolynomialBivariate.h @@ -0,0 +1,68 @@ +#ifndef PolynomialBivariate_h +#define PolynomialBivariate_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/02/07 18:53:03 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "BasisFunction.h" + +namespace Isis { +/** + * @brief Nth degree Polynomial with two variables + * + * This is a derived class from BasisFunction which provides the capabilities + * of a polynomial equation in two variables with degree n, where n is specified + * during the object construction. For example, Degree = 1 z = a + b*x + c*y + * Degree = 2 z = a + b*x + c*y + d*x**2 + e*x*y + f*y**2 + * Degree = 3 z = a + b*x + c*y + d*x**2 + e*x*y + f*y**2 + g*x**3 + h*x**2*y + * + i*x*y**2 + j*y**3 In general the number of coefficients will be + * ((degree+1)*(degree+2))/2. + * + * @ingroup Math + * + * @author 2004-06-24 Jeff Anderson + * + * @internal + * @history 2005-03-11 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * + * @todo 2005-03-11 Jeff Anderson - add coded and implementation examples to + * class documentation + * @history 2008-02-05 Jeannie Walldren, Renamed from Poly2D. + */ + + class PolynomialBivariate : public Isis::BasisFunction { + public: + PolynomialBivariate(int degree); + + //! Destroys the PolynomialBivariate object + ~PolynomialBivariate() {}; + + void Expand(const std::vector &vars); + + private: + int p_degree; //!< The order/degree of the polynomial + }; +}; + +#endif + diff --git a/isis/src/base/objs/PolynomialBivariate/PolynomialBivariate.truth b/isis/src/base/objs/PolynomialBivariate/PolynomialBivariate.truth new file mode 100644 index 0000000000000000000000000000000000000000..c7ea34bdb65d18c2a839892f41f795da014ccb5f --- /dev/null +++ b/isis/src/base/objs/PolynomialBivariate/PolynomialBivariate.truth @@ -0,0 +1,27 @@ +Name = PolynomialBivariate +Ncoefs = 3 +Vars = 2 +0.5 +0.5 +0.5 +--- +3 +1 +2 +3 +--- +0 +1 +1 +-2 +---- 2nd order ---- +Name = PolynomialBivariate +Ncoefs = 6 +Vars = 2 +3 +1 +1 +-2 +1 +-2 +4 diff --git a/isis/src/base/objs/PolynomialBivariate/unitTest.cpp b/isis/src/base/objs/PolynomialBivariate/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d18411d742fccf9f77a4707386f749e043d84349 --- /dev/null +++ b/isis/src/base/objs/PolynomialBivariate/unitTest.cpp @@ -0,0 +1,56 @@ +#include "PolynomialBivariate.h" +#include +#include "Preference.h" + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + + Isis::PolynomialBivariate b(1); + vector coefs; + coefs.push_back(0.5); + coefs.push_back(0.5); + coefs.push_back(0.5); + b.SetCoefficients(coefs); + + cout << "Name = " << b.Name() << endl; + cout << "Ncoefs = " << b.Coefficients() << endl; + cout << "Vars = " << b.Variables() << endl; + for (int i=0; i vars; + vars.push_back(2.0); + vars.push_back(3.0); + cout << b.Evaluate(vars) << endl; + for (int i=0; i &vars) { + p_terms.clear(); + p_terms.push_back(1.0); + + for (int i=1; i<=p_degree; i++) { + p_terms.push_back(p_terms[i-1]*vars[0]); + } + } + + + /** + * This will take the Derivative with respect to the variable and evaluate at + * given value. + * + * @param [in] value (const double) value at which to evaluate derivative + * + * @history 2008-01-09 Tracie Sucharski, Original Version + * + */ + double PolynomialUnivariate::DerivativeVar(const double value) { + + double derivative = 0; + + for (int i=1; i 0 && coefIndex <= Coefficients()) { + derivative = pow(value, coefIndex); + } + else if (coefIndex == 0) { + derivative = 1; + } + else { + Isis::iString msg = "Coeff index, " + Isis::iString(coefIndex) + " exceeds degree of polynomial"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return derivative; + } + + +} // end namespace isis + diff --git a/isis/src/base/objs/PolynomialUnivariate/PolynomialUnivariate.h b/isis/src/base/objs/PolynomialUnivariate/PolynomialUnivariate.h new file mode 100644 index 0000000000000000000000000000000000000000..6572c71a627db719bc662cf31bc0ada5d3b2748d --- /dev/null +++ b/isis/src/base/objs/PolynomialUnivariate/PolynomialUnivariate.h @@ -0,0 +1,70 @@ +#ifndef PolynomialUnivariate_h +#define PolynomialUnivariate_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/02/07 18:53:03 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "Basis1VariableFunction.h" + +namespace Isis { +/** + * @brief Nth degree Polynomial with one variable + * + * This is a derived class from Basis1VariableFunction which provides the + * capabilities of a polynomial equation in one variable with degree n, where n + * is specified during the object construction. For example, Degree = 1 z = a + + * b*x Degree = 2 z = a + b*x + c*x**2 Degree = 3 z = a + b*x + c*x**2 + d*x**3 + * In general the number of coefficients will be degree + 1. + * + * @ingroup Math + * + * @author Debbie A. Cook 2007-11-19 (modified from Poly2D, now + * named PolynominalBivariate, 2004-06-24 Jeff + * Anderson) + * + * @internal + * + * @history 2008-01-11 Tracie Sucharski, Renamed from Poly1D, add derivative + * methods. + * @history 2008-02-05 Jeannie Walldren,Renamed from + * Polynomial1Variable. + */ + + class PolynomialUnivariate : public Isis::Basis1VariableFunction { + public: + PolynomialUnivariate(int degree); + + //! Destroys the PolynomialUnivariate object + ~PolynomialUnivariate() {}; + + void Expand(const std::vector &vars); + + double DerivativeVar ( const double value ); + double DerivativeCoef ( const double value,const int coefIndex); + + private: + int p_degree; //!< The order/degree of the polynomial + }; +}; + +#endif + diff --git a/isis/src/base/objs/PolynomialUnivariate/PolynomialUnivariate.truth b/isis/src/base/objs/PolynomialUnivariate/PolynomialUnivariate.truth new file mode 100644 index 0000000000000000000000000000000000000000..0b973f8d130c583a2f143d4609202099526499f3 --- /dev/null +++ b/isis/src/base/objs/PolynomialUnivariate/PolynomialUnivariate.truth @@ -0,0 +1,27 @@ +Name = PolynomialUnivariate +Ncoefs = 2 +Vars = 1 +0.5 +0.5 +--- +1.5 +1 +2 +--- +0 +1 +-1 +---- 2nd order ---- +Name = PolynomialUnivariate +Ncoefs = 3 +Vars = 1 +1 +1 +-1 +1 +---- 2nd order ---- +Name = PolynomialUnivariate +Ncoefs = 3 +Vars = 1 +Variable Derivative = 4.5 +Coefficient 2 Derivative = 4 diff --git a/isis/src/base/objs/PolynomialUnivariate/unitTest.cpp b/isis/src/base/objs/PolynomialUnivariate/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..068d41fc16aa713c0eab85ca62d20e6d34a10c08 --- /dev/null +++ b/isis/src/base/objs/PolynomialUnivariate/unitTest.cpp @@ -0,0 +1,57 @@ +#include "PolynomialUnivariate.h" +#include + +using namespace std; + +int main () { + Isis::PolynomialUnivariate b(1); + vector coefs; + coefs.push_back(0.5); + coefs.push_back(0.5); + b.SetCoefficients(coefs); + + cout << "Name = " << b.Name() << endl; + cout << "Ncoefs = " << b.Coefficients() << endl; + cout << "Vars = " << b.Variables() << endl; + for (int i=0; i vars; + vars.push_back(2.0); + cout << b.Evaluate(vars) << endl; + for (int i=0; i +#include +#include +#include "iException.h" +#include "Cube.h" +#include "Portal.h" +#include "Preference.h" + + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + string fname = "$base/testData/isisTruth.cub"; + + // Allocate a cube + Isis::Cube *cube = new Isis::Cube; + try { + cube->Open (fname); + } + catch (Isis::iException &e) { + delete cube; + e.Report(false); + exit (1); + } + + // Create a portal buffer for the cube with a size of 1x1 + Isis::Portal portal(1,1,cube->PixelType()); + + // Get some portals and output the sample, line and band of the upper left corner + cout << "Coordinates and value of upper left pixel in several portals:" << endl; + portal.SetPosition (1,1,1); + cube->Read (portal); + cout << " Corner of portal 1 is: (" + << portal.Sample(0) << ", " + << portal.Line(0) << ", " + << portal.Band() << ")" << " = " << portal.DoubleBuffer()[0] << endl; + + portal.SetPosition (1,1,2); + cube->Read (portal); + cout << " Corner of portal 2 is: (" + << portal.Sample(0) << ", " + << portal.Line(0) << ", " + << portal.Band() << ")" << " = " << portal.DoubleBuffer()[0] << endl; + + portal.SetPosition (10,10,1); + cube->Read (portal); + cout << " Corner of portal 3 is: (" + << portal.Sample(0) << ", " + << portal.Line(0) << ", " + << portal.Band() << ")" << " = " << portal.DoubleBuffer()[0] << endl; + + portal.SetPosition (126,126,2); + cube->Read (portal); + cout << " Corner of portal 4 is: (" + << portal.Sample(0) << ", " + << portal.Line(0) << ", " + << portal.Band() << ")" << " = " << portal.DoubleBuffer()[0] << endl; + + portal.SetPosition (100,101,1); + cube->Read (portal); + cout << " Corner of portal 5 is: (" + << portal.Sample(0) << ", " + << portal.Line(0) << ", " + << portal.Band() << ")" << " = " << portal.DoubleBuffer()[0] << endl; + + portal.SetPosition (126,1,1); + cube->Read (portal); + cout << " Corner of portal 6 is: (" + << portal.Sample(0) << ", " + << portal.Line(0) << ", " + << portal.Band() << ")" << " = " << portal.DoubleBuffer()[0] << endl; + + portal.SetPosition (1,126,1); + cube->Read (portal); + cout << " Corner of portal 7 is: (" + << portal.Sample(0) << ", " + << portal.Line(0) << ", " + << portal.Band() << ")" << " = " << portal.DoubleBuffer()[0] << endl; + + portal.SetPosition (1,1,1); + cube->Read (portal); + cout << " Corner of portal 8 is: (" + << portal.Sample(0) << ", " + << portal.Line(0) << ", " + << portal.Band() << ")" << " = " << portal.DoubleBuffer()[0] << endl; + + portal.SetHotSpot(0,0); + portal.SetPosition(126,126,2); + cube->Read(portal); + cout << " Corner of portal 9 is: (" + << portal.Sample(0) << ", " + << portal.Line(0) << ", " + << portal.Band() << ")" << " = " << portal.DoubleBuffer()[0] << endl; + + portal.SetHotSpot(13,24); + portal.SetPosition(126,126,2); + cube->Read(portal); + cout << " Corner of portal 10 is: (" + << portal.Sample(0) << ", " + << portal.Line(0) << ", " + << portal.Band() << ")" << " = " << portal.DoubleBuffer()[0] << endl; + + cube->Close (); +} diff --git a/isis/src/base/objs/Preference/Makefile b/isis/src/base/objs/Preference/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..21406e095ffa5007a7bcff656dd47b3d4b4d1448 --- /dev/null +++ b/isis/src/base/objs/Preference/Makefile @@ -0,0 +1,5 @@ +INCS = Preference.h +SRCS = Preference.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Preference/Preference.cpp b/isis/src/base/objs/Preference/Preference.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bfe7f47d8aba4a0cdc32d8a39042d527e730fc5b --- /dev/null +++ b/isis/src/base/objs/Preference/Preference.cpp @@ -0,0 +1,124 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/05/28 17:57:03 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + + +#include + +#include "Preference.h" +#include "Filename.h" +#include "iException.h" + +using namespace std; +namespace Isis { + /** + * Constructs a Preference object. + */ + Preference::Preference() : Isis::Pvl() { + atexit(Shutdown); + } + + void Preference::Load(const std::string &file) { + // Read the input PVL preference file + Isis::Pvl pvl; + + if(Isis::Filename(file).Exists()) { + pvl.Read(file); + } + + // Override parameters each time load is called + for(int i = 0; i < pvl.Groups(); i++) { + Isis::PvlGroup &inGroup = pvl.Group(i); + if(this->HasGroup(inGroup.Name())) { + Isis::PvlGroup &outGroup = this->FindGroup(inGroup.Name()); + for(int k = 0; k < inGroup.Keywords(); k++) { + Isis::PvlKeyword &inKey = inGroup[k]; + while(outGroup.HasKeyword(inKey.Name())) { + outGroup.DeleteKeyword(inKey.Name()); + } + outGroup += inKey; + } + } + else { + this->AddGroup(inGroup); + } + } + } + + + // Instantiation and initialization of static member variables + Preference *Preference::p_preference = NULL; + bool Preference::p_unitTest = false; + + + Preference &Preference::Preferences(bool unitTest) { + if(p_preference == NULL) { + p_unitTest = unitTest; + // Create the singleton + p_preference = new Preference(); + + // Make sure the user has a .Isis directory + Isis::Filename setup("$HOME/.Isis"); + if(!setup.Exists()) { + QDir dir; + QString dirName(iString(setup.Expanded()).ToQt()); + dir.mkdir(dirName); + } + + // If its a unitTest then load with the unitTest preference file + if(unitTest) { + p_preference->Load("$ISISROOT/src/base/objs/Preference/TestPreferences"); + } + // Otherwise load the Isis system and personal preferences. + else { + p_preference->Load("$ISISROOT/IsisPreferences"); + + Isis::Filename userPref("$HOME/.Isis/IsisPreferences"); + if(userPref.Exists()) { + p_preference->Load("$HOME/.Isis/IsisPreferences"); + } + } + } + // Note: Keep this here + // During unitTests some other class may call Preferences before the + // unitTest does. This would cause the preferences to be loaded with + // the system and user preferences instead of the TestPreferences. + else if(unitTest) { + p_unitTest = unitTest; + p_preference->Clear(); + p_preference->Load("$ISISROOT/src/base/objs/Preference/TestPreferences"); + } + + return *p_preference; + } + + void Preference::Shutdown() { + if(p_preference) { + delete p_preference; + p_preference = NULL; + } + } +} // end namespace isis diff --git a/isis/src/base/objs/Preference/Preference.h b/isis/src/base/objs/Preference/Preference.h new file mode 100644 index 0000000000000000000000000000000000000000..ca568e0feb6eda70a5c63b2e25c85974b35966bd --- /dev/null +++ b/isis/src/base/objs/Preference/Preference.h @@ -0,0 +1,100 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/05/28 17:57:03 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef Preference_h +#define Preference_h + +#include +#include "Pvl.h" + +namespace Isis { + /** + * @brief Reads user preferences from a data file. + * + * This class is used to load, set, and obtain user preferences for + * the operation of Isis. User preferences for Isis are items such + * as the name of the log file, default data directories, and processing + * status. This is essentially a specialized version of a Label object. It + * reads a system-wide preference file and overwrites values in + * the label with a user preference file. This object does not need + * to be modified to add new prefences ... simply edit the system + * wide preference file, add the new group and keywords, update the + * preference document (user documentation) explaining the new + * keywords. + * + * @ingroup ApplicationInterface + * + * @author 2002-03-13 Jeff Anderson + * + * @internal + * @todo The Preference class needs private methods & variables documented. + * The documentation shows methods that don't exist in the code. It also + * needs an example. + * @history 2003-04-23 Jeff Anderson - reworked the class to use the Label + * object. + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeoloy... + * isis.astrogeology + * @history 2003-12-03 Stuart Sides - added HasGroup member. + * @history 2005-10-03 Elizabeth Miller - changed @ingroup tag + * @history 2008-01-09 Steven Lambright - Made Application a friend + * for destruction purposes + * @history 2008-07-08 Steven Lambright - Now uses atexit for destruction + * @history 2010-05-28 Steven Lambright - More resilient to $HOME/.Isis + * problems + */ + class Application; + + class Preference : public Pvl { + + public: + void Load(const std::string &file); + + /** + * Tests whether or not a file is a unitTest + * + * @return bool True if it is a unitTest, and false if it is not + */ + inline bool IsUnitTest() { + return p_unitTest; + } + + static Preference &Preferences(bool unitTest = false); + + private: + Preference(); + + //! Destroys the Preference object + ~Preference() {}; + + Preference(const Preference &p); + Preference &operator=(const Preference &p); + + static Preference *p_preference; //!< Pointer to a Preference object + static bool p_unitTest; /**< Flag indicating whether the file + is a unitTest or not.*/ + + static void Shutdown(); + }; +}; + +#endif diff --git a/isis/src/base/objs/Preference/Preference.truth b/isis/src/base/objs/Preference/Preference.truth new file mode 100644 index 0000000000000000000000000000000000000000..c4920958f3eedd1c0e0930ef6382c8b04dd857d3 --- /dev/null +++ b/isis/src/base/objs/Preference/Preference.truth @@ -0,0 +1,12 @@ +Testing normally +Group = Junk + Fruit = Tomato + Vegetable = Potato +End_Group +Group = Junk + Fruit = Tomato + Vegetable = Potatoe +End_Group + + +Value of Vegetable is : Potatoe diff --git a/isis/src/base/objs/Preference/TestPreferences b/isis/src/base/objs/Preference/TestPreferences new file mode 100644 index 0000000000000000000000000000000000000000..62d03f46ff83b6d88cb9cd00c90f95cbedbe4293 --- /dev/null +++ b/isis/src/base/objs/Preference/TestPreferences @@ -0,0 +1,118 @@ +####################################################### +# This file allows the user to customize their Isis +# configuration. See the Isis Preference Dictionary +# on our website isis.astrogeology.usgs.gov for a +# full description of each group. +######################################################## + +######################################################## +# Customize elements of the user interface +# +# ProgressBarPercent = 1 | 2 | 5 | 10 +# ProgressBar = On | Off +# GuiStyle = windows | motif | cde | motifplus | +# platinum | sgi | kde | aqua +# GuiHelpBrowser = { your preferred browser, may need path } +# GuiFontName = helvitica | times | charter | any legal font +# GuiFontSize = 10 | 12 | 14 | any font point size +# HistoryPath = { your preferred loaction for the application +# .par files } +# HistoryRecording = On | Off +# HistoryLength = (your preferred count of history entries +# to remember) +######################################################## + +Group=UserInterface + ProgressBarPercent = 10 + ProgressBar = On + GuiHelpBrowser = firefox + GuiFontName = helvitica + GuiFontSize = 10 + GuiWidth = 460 + GuiHeight = 600 + HistoryPath = $HOME/.Isis/history + HistoryRecording = On + HistoryLength = 10 +EndGroup + +######################################################## +# Customize how errors are reported +# +# FileLine = On | Off +# Format = Standard | Pvl +# StackTrace = On | Off +######################################################## + +Group = ErrorFacility + FileLine = Off + Format = Standard + StackTrace = Off +EndGroup + +######################################################## +# Customize how session logging is handled +# +# TerminalOutput = On | Off +# FileOutput = On | Off +# FileName = print.prt | /mydirectory/myfile.prt +# FileAccess = Append | Overwrite +######################################################## + +Group = SessionLog + TerminalOutput = Off + FileOutput = On + FileName = print.prt + FileAccess = Append +EndGroup + +######################################################## +# Customize how cubes are created +# +# Overwrite = Error | Allow +# Format = Attached | Detached +# History = On | Off +# MaximumSize = max # of gigabytes +######################################################## + +Group = CubeCustomization + Overwrite = Allow + Format = Attached + History = On + MaximumSize = 12 +EndGroup + +######################################################## +# Customize the location of mission specific data +# files (calibration and spice kernels). Usually this +# should be left to the Isis administrator +######################################################## + +Group = DataDirectory + Apollo15 = $ISIS3DATA/apollo15 + Apollo16 = $ISIS3DATA/apollo16 + Apollo17 = $ISIS3DATA/apollo17 + Base = $ISIS3DATA/base + Cassini = $ISIS3DATA/cassini + Chan1 = $ISIS3DATA/chan1 + Clementine1 = $ISIS3DATA/clementine1 + Dawn = $ISIS3DATA/dawn + Galileo = $ISIS3DATA/galileo + Lo = $ISIS3DATA/lo + Lro = $ISIS3DATA/lro + Mariner10 = $ISIS3DATA/mariner10 + Mer = $ISIS3DATA/mer + Mex = $ISIS3DATA/mex + Messenger = $ISIS3DATA/messenger + Mgs = $ISIS3DATA/mgs + Mro = $ISIS3DATA/mro + Odyssey = $ISIS3DATA/odyssey + Rolo = $ISIS3DATA/rolo + Smart1 = $ISIS3DATA/smart1 + Viking1 = $ISIS3DATA/viking1 + Viking2 = $ISIS3DATA/viking2 + Voyager1 = $ISIS3DATA/voyager1 + Voyager2 = $ISIS3DATA/voyager2 + Temporary = . +EndGroup + +End diff --git a/isis/src/base/objs/Preference/unitTest.cpp b/isis/src/base/objs/Preference/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83cfbe0d732ee3c473ef5523056a30d7d59345f9 --- /dev/null +++ b/isis/src/base/objs/Preference/unitTest.cpp @@ -0,0 +1,60 @@ +#include + +#include "Preference.h" +#include "iException.h" + +using namespace std; +int main() + +{ + try { + // Note: Normally a call to Preferences in a unitTest would be called + // with a true. In this case however, we can't have the Preferences + // call clearing the the Pvl everytime. We aren't using any keywords + // from the preferences anyway, just the ones we add. + Isis::Preference::Preferences(false); + Isis::Pvl system; + Isis::PvlGroup j1("Junk"); + j1 += Isis::PvlKeyword("Fruit", "Tomato"); + j1 += Isis::PvlKeyword("Vegetable", "Potato"); + system.AddGroup(j1); + system.Write("tmpSystem"); + + Isis::Pvl user; + Isis::PvlGroup j2("Junk"); + j2 += Isis::PvlKeyword("Vegetable", "Potatoe"); + user.AddGroup(j2); + user.Write("tmpUser"); + + cout << "Testing normally" << endl; +#if 0 + Isis::Preference p2; + p2.Load("tmpSystem"); + cout << p2 << endl; + p2.Load("tmpUser"); + cout << p2 << endl; +#endif + + Isis::Preference::Preferences(false).Load("tmpSystem"); + Isis::PvlGroup j3 = Isis::Preference::Preferences(false).FindGroup("Junk"); + cout << j3 << endl; + Isis::Preference::Preferences(false).Load("tmpUser"); + Isis::PvlGroup j4 = Isis::Preference::Preferences(false).FindGroup("Junk"); + cout << j4 << endl; + + cout << endl << endl; + // if (p2.HasGroup("Junk")) { + if(Isis::Preference::Preferences(false).HasGroup("Junk")) { + Isis::PvlGroup &g = Isis::Preference::Preferences(false).FindGroup("Junk"); + cout << "Value of Vegetable is : " << (string) g["Vegetable"] << endl; + } + + remove("tmpSystem"); + remove("tmpUser"); + } + catch(Isis::iException &error) { + error.Report(false); + } + + return 0; +} diff --git a/isis/src/base/objs/PrincipalComponentAnalysis/Makefile b/isis/src/base/objs/PrincipalComponentAnalysis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3fda1a6b4733cc386d62e7aa936758a384aa29b4 --- /dev/null +++ b/isis/src/base/objs/PrincipalComponentAnalysis/Makefile @@ -0,0 +1,5 @@ +INCS = PrincipalComponentAnalysis.h +SRCS = PrincipalComponentAnalysis.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PrincipalComponentAnalysis/PrincipalComponentAnalysis.cpp b/isis/src/base/objs/PrincipalComponentAnalysis/PrincipalComponentAnalysis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3be5d6e3797c77a8458311877abb71e8670bc180 --- /dev/null +++ b/isis/src/base/objs/PrincipalComponentAnalysis/PrincipalComponentAnalysis.cpp @@ -0,0 +1,150 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2009/12/22 02:09:54 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PrincipalComponentAnalysis.h" +#include "jama/jama_eig.h" +#include "jama/jama_lu.h" + +using namespace std; + +namespace Isis +{ + //! Constructs the PrincipalComponentAnalysis object. + PrincipalComponentAnalysis::PrincipalComponentAnalysis (const int n) { + p_dimensions = n; + p_statistics.clear(); + p_statistics.resize(n*n); + for (int i=0; i transform) { + if (transform.dim1() != transform.dim2()) { + std::string m="Illegal transform matrix"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + p_dimensions = transform.dim1(); + p_transform = transform; + ComputeInverse(); + + p_hasTransform = true; + } + + // Add data for all dimensions + // Note: the data should be stored as an array containing + // the first dimension in order, then the second, ... + void PrincipalComponentAnalysis::AddData(const double *data, const unsigned int count) { + // If this PCA object has a transform matrix + // we cannot add more data + if (p_hasTransform) { + std::string m="Cannot add data to a PCA that has a defined transform matrix"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // add the data to the multivariate stats objects + for (int i=0; iAddData(&data[count*i], &data[count*j], count); + } + } + } + + // Use VDV' decomposition to obtain the eigenvectors + void PrincipalComponentAnalysis::ComputeTransform() { + if (p_hasTransform) { + std::string m="This PCA already has a computed transform"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + TNT::Array2D C(p_dimensions,p_dimensions); + for (int i=0; i< p_dimensions; i++) { + for (int j=0; jCorrelation(); + } + } + + JAMA::Eigenvalue E(C); + TNT::Array2D D, V; + + E.getD(D); + E.getV(V); + p_transform = TNT::Array2D(V.dim1(), V.dim2()); + + // The transform matrix needs to have the eigenvectors + // sorted in *descending* order + // So we need to reverse the order of V + // which is sorted in *ascending* order + for (int i=0; i id(p_transform.dim1(), p_transform.dim2(), 0.0); + for (int i = 0; i < p_transform.dim1(); i++) id[i][i] = 1; + + JAMA::LU lu(p_transform); + if (lu.det() == 0.0) { + std::string m="Cannot take the inverse of the transform matrix"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + p_inverse = lu.solve(id); + } + + // Transform the vector into principal component space + TNT::Array2D PrincipalComponentAnalysis::Transform (TNT::Array2D data) { + if (data.dim1() !=1 || data.dim2() != p_dimensions) { + std::string m="Transform input must be of dimension 1 x " + p_dimensions; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // the vector times the transform matrix + return TNT::matmult(data,p_transform); + } + + // Transform the vector from principal component space + TNT::Array2D PrincipalComponentAnalysis::Inverse (TNT::Array2D data) { + if (data.dim1() !=1 || data.dim2() != p_dimensions) { + std::string m="Transform input must be of dimension 1 x " + p_dimensions; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // the vector times the inverse matrix + return TNT::matmult(data,p_inverse); + } +} diff --git a/isis/src/base/objs/PrincipalComponentAnalysis/PrincipalComponentAnalysis.h b/isis/src/base/objs/PrincipalComponentAnalysis/PrincipalComponentAnalysis.h new file mode 100644 index 0000000000000000000000000000000000000000..ecb06f8faf8df43af352f0bcf5295d3beab552c5 --- /dev/null +++ b/isis/src/base/objs/PrincipalComponentAnalysis/PrincipalComponentAnalysis.h @@ -0,0 +1,72 @@ +#ifndef PrincipalComponentAnalysis_h +#define PrincipalComponentAnalysis_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2009/12/22 02:09:54 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "tnt/tnt_array2d.h" +#include "MultivariateStatistics.h" +#include "iException.h" +#include "Constants.h" + +namespace Isis +{ + /** + * @brief Principal Component Analysis class + * + * This class is used to apply Principal Component Analysis + * to transform multivariate data into its principal components + * as well as invert it from component space. + * + * If you would like to see PrincipalComponentAnalysis being used + * in implementation, see pca.cpp or decorstretch.cpp + * + * @ingroup Math and Statistics + * + * @author Jacob Danton - 2006-05-18 + * + * @internal + */ + class PrincipalComponentAnalysis + { + public: + PrincipalComponentAnalysis (const int n); + PrincipalComponentAnalysis (TNT::Array2D transform); + ~PrincipalComponentAnalysis () {}; + void AddData (const double *data, const unsigned int count); + void ComputeTransform (); + TNT::Array2D Transform (TNT::Array2D data); + TNT::Array2D Inverse (TNT::Array2D data); + TNT::Array2D TransformMatrix() {return p_transform;}; + int Dimensions() {return p_dimensions;}; + + private: + void ComputeInverse (); + bool p_hasTransform; + int p_dimensions; + + TNT::Array2D p_transform, p_inverse; + std::vector p_statistics; + }; +} + +#endif diff --git a/isis/src/base/objs/PrincipalComponentAnalysis/PrincipalComponentAnalysis.truth b/isis/src/base/objs/PrincipalComponentAnalysis/PrincipalComponentAnalysis.truth new file mode 100644 index 0000000000000000000000000000000000000000..1883fcad1eda1a583e565817d29048b7242911f6 --- /dev/null +++ b/isis/src/base/objs/PrincipalComponentAnalysis/PrincipalComponentAnalysis.truth @@ -0,0 +1,11 @@ + Original Principal Components Inverted + 0 1 2 -> 1.71044 1.41421 -0.272759 -> 0 1 2 + 1 2 3 -> 3.42088 1.41421 -0.545517 -> 1 2 3 + 2 3 4 -> 5.13132 1.41421 -0.818276 -> 2 3 4 + 3 4 5 -> 6.84176 1.41421 -1.09103 -> 3 4 5 + 4 5 6 -> 8.5522 1.41421 -1.36379 -> 4 5 6 + 5 6 7 -> 10.2626 1.41421 -1.63655 -> 5 6 7 + 6 7 8 -> 11.9731 1.41421 -1.90931 -> 6 7 8 + 7 8 9 -> 13.6835 1.41421 -2.18207 -> 7 8 9 + 8 9 0 -> 10.3354 -5.65685 2.48591 -> 8 9 0 + 9 0 1 -> 5.05857 -5.65685 -4.94074 -> 9 0 1 diff --git a/isis/src/base/objs/PrincipalComponentAnalysis/unitTest.cpp b/isis/src/base/objs/PrincipalComponentAnalysis/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..33dfe84fd5f1bf7fdfa57c0d95ac8109a9dd8b95 --- /dev/null +++ b/isis/src/base/objs/PrincipalComponentAnalysis/unitTest.cpp @@ -0,0 +1,70 @@ +#include +#include "PrincipalComponentAnalysis.h" +#include "Preference.h" + +using namespace std; + +double Round(double n); + +int main(int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + + int n = 10; + int k= 3; + + Isis::PrincipalComponentAnalysis pca(k); + double original[k*n]; + for (int i=0; i x(1, k); + for (int j=0; j y = pca.Transform(x); + for (int j=0; j z = pca.Inverse(y); + for (int j=0; j "; + for (int j=0; j "; + for (int j=0; j +#include + +#include "SessionLog.h" +#include "Process.h" +#include "Filename.h" +#include "Message.h" +#include "iException.h" +#include "iString.h" +#include "Preference.h" +#include "Application.h" +#include "History.h" +#include "OriginalLabel.h" +#include "LineManager.h" + +using namespace std; +namespace Isis { + + //! Constructs a Process Object + Process::Process () { + p_progress = new Isis::Progress (); + p_progress->SetText("Working"); + p_propagateLabels = true; + p_propagateTables = true; + p_propagatePolygons = true; + p_propagateHistory = true; + p_propagateOriginalLabel = true; + } + + //! Destroys the Process Object. It will close all opened cubes + Process::~Process () { + EndProcess (); + delete p_progress; + } + + /** + * Opens an input cube specified by the programmer and verifies requirements + * are met. + * + * @param fname Programmer specified work file. For example, "myfile.cub". + * + * @param att The cube attributes to use when opening the input cube. + * + * @param requirements Same as requirements on SetInputCube. See that method + * for more details. Defaults to 0 + * + * @return Cube* + * + * @throws Isis::iException::Message + */ + Isis::Cube* Process::SetInputCube (const std::string &fname, + const Isis::CubeAttributeInput &att, + int requirements) { + Isis::Cube *cube = new Isis::Cube; + if (att.Bands().size() != 0) { + vector lame = att.Bands(); + cube->SetVirtualBands(lame); + } + + try { + if (requirements & Isis::ReadWrite) { + cube->Open (fname, "rw"); + } + else { + cube->Open (fname); + } + } + catch (Isis::iException &e) { + delete cube; + throw; + } + + // Test for same size or one in all dimensions + if (requirements & Isis::AllMatchOrOne) { + if (InputCubes.size() > 0) { + if (cube->Lines() != 1) { + if (cube->Lines() != InputCubes[0]->Lines()) { + string message = "The number of lines in the secondary input cubes must match"; + message += " the primary input cube or be exactly one"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + } + + if (cube->Samples() != 1) { + if (cube->Samples() != InputCubes[0]->Samples()) { + string message = "The number of samples in the secondary input cubes must match"; + message += " the primary input cube or be exactly one"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + } + if (cube->Bands() != 1) { + if (cube->Bands() != InputCubes[0]->Bands()) { + string message = "The number of bands in the secondary input cubes must match"; + message += " the primary input cube or be exactly one"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + } + + // Do not do a spatial match if this flag was set + requirements = requirements & !Isis::SpatialMatch; + } + } + + // Test for size match if requested + if (requirements & Isis::SizeMatch) { + if (InputCubes.size() > 0) { + if (cube->Lines() != InputCubes[0]->Lines()) { + string message = "The number of lines in the input cubes must match"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + if (cube->Samples() != InputCubes[0]->Samples()) { + string message = "The number of samples in the input cubes must match"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + if (cube->Bands() != InputCubes[0]->Bands()) { + string message = "The number of bands in the input cubes must match"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + } + } + + // Test for spatial match if requested + if (requirements & Isis::SpatialMatch) { + if (InputCubes.size() > 0) { + if (cube->Lines() != InputCubes[0]->Lines()) { + string message = "The number of lines in the input cubes must match"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + if (cube->Samples() != InputCubes[0]->Samples()) { + string message = "The number of samples in the input cubes must match"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + } + } + + // Test for one band + if (requirements & Isis::OneBand) { + if (cube->Bands() != 1) { + string message = "Input cube [" + fname + "] must have one band"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + } + + // Test for same bands or one band + if (requirements & Isis::BandMatchOrOne) { + if (cube->Bands() != 1) { + if (InputCubes.size() > 0) { + if (cube->Bands() != InputCubes[0]->Bands()) { + string message = "The number of bands in the secondary input cubes must match"; + message += " the primary input cube or be exactly one"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + } + } + } + + // Everything is good so save the cube on the stack + InputCubes.push_back(cube); + return cube; + } + + /** + * Opens an input cube specified by the user and verifies requirements are met. + * + * @return Cube* + * + * @param parameter User parameter to obtain file to open. Typically, the value + * is "FROM". For example, the user can specify on the command + * line FROM=myfile.cub and this method will attempt to open + * the cube "myfile.cub" if the parameter was set to "FROM". + * + * + * @param requirements Use to specify requirements for the input file. The + * following are requirments are checked against + * 1) ic_base::SizeMatch checks to make sure the input cube + * has the same bands, samples, and lines as the first + * input cube open using this method, + * 2) ic_base::SpatialMatch checks to make sure the input + * cube has the same samples and lines as the first input + * cube, 3) ic_base::Georeferenced checks to make sure + * latitude/longitudes can be obtained from the input cube, + * 4) ic_base::FullyGeoreferenced checks to make sure + * latitude/longitude, phase/incidence/emission, and other + * geometric parameters can be obtained from the input + * cube, 5) ic_base::OneBand checks to make sure the input + * cube has exactly one band. Note, that these requirements + * can be logically or'ed. For example, + * ic_base::SpatialMatch | ic_base::georeferenced. + * Defaults to 0 + * + * @throws Isis::iException::Message + */ + Isis::Cube* Process::SetInputCube (const std::string ¶meter, + const int requirements) { + string fname = Application::GetUserInterface().GetFilename (parameter); + Isis::CubeAttributeInput &att = Application::GetUserInterface().GetInputAttribute(parameter); + return SetInputCube(fname,att,requirements); + } + + /** + * Allocates a user-specified output cube whose size matches the first input + * cube. + * + * @return Cube* + * + * @param parameter User specified output file. For example, "TO" is a popular + * user parameter. If the user specified TO=output.cub, then + * this routine would allocate the file output.cub with size + * specified by the first opened input cube. The output pixel + * type will be propagated from the first loaded input cube or + * will use the value in the application XML file for + * pixelType. + * + * @throws Isis::iException::Message + */ + Isis::Cube* Process::SetOutputCube (const std::string ¶meter) { + // Make sure we have an input cube to get a default size from + if (InputCubes.size() == 0) { + string message = "No input images have been selected ... therefore"; + message += "the output image size can not be determined"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + int nl = InputCubes[0]->Lines(); + int ns = InputCubes[0]->Samples(); + int nb = InputCubes[0]->Bands(); + return SetOutputCube (parameter,ns,nl,nb); + } + + /** + * Allocates a user specified output cube whose size is specified by the + * programmer. + * + * @return Cube* + * + * @param parameter User specified output file. For example, "TO" is a popular + * user parameter. If the user specified TO=output.cub, then + * this routine would allocate the file output.cub with size + * specified by the first opened input cube. The output pixel + * type will be propagated from the first loaded input cube or + * will use the value in the application XML file for + * pixelType. + * + * @param ns Number of samples to allocate + * + * @param nl Number of lines to allocate + * + * @param nb Number of bands to allocate + * + * @throws Isis::iException::Message + */ + Isis::Cube* Process::SetOutputCube (const std::string ¶meter, const int ns, + const int nl, const int nb) { + // Make sure we have good dimensions + if ((ns <= 0) || (nl <= 0) || (nb <= 0)) { + ostringstream message; + message << "Invalid cube size specifications [ns=" << ns << ",nl=" << nl + << ",nb=" << nb << "]"; + throw Isis::iException::Message(Isis::iException::Programmer,message.str(),_FILEINFO_); + } + + string fname = Application::GetUserInterface().GetFilename (parameter); + Isis::CubeAttributeOutput &atts = Application::GetUserInterface().GetOutputAttribute(parameter); + return SetOutputCube (fname,atts,ns,nl,nb); + } + + /** + * Allocates a output cube whose name and size is specified by the programmer. + * + * @return Cube* + * + * @param fname Name of the output cube to allocate + * + * @param att The cube attributes to use when creating the output cube. + * + * @param ns Number of samples to allocate + * + * @param nl Number of lines to allocate + * + * @param nb Number of bands to allocate + * + * @throws Isis::iException::Message + */ + Isis::Cube* Process::SetOutputCube (const std::string &fname, + const Isis::CubeAttributeOutput &att, + const int ns, const int nl, + const int nb) { + // Make sure we have good dimensions + if ((ns <= 0) || (nl <= 0) || (nb <= 0)) { + ostringstream message; + message << "Invalid cube size specifications [ns=" << ns << ",nl=" << nl + << ",nb=" << nb << "]"; + throw Isis::iException::Message(Isis::iException::Programmer,message.str(),_FILEINFO_); + } + + // Setup the cube + Isis::Cube *cube = new Isis::Cube; + try { + cube->SetDimensions(ns,nl,nb); + cube->SetByteOrder(att.ByteOrder()); + cube->SetCubeFormat(att.FileFormat()); + if (att.DetachedLabel()) cube->SetDetached(); + if (att.AttachedLabel()) cube->SetAttached(); + + if (att.PropagatePixelType()) { + if (InputCubes.size() > 0) { + cube->SetPixelType(InputCubes[0]->PixelType()); + } + else { + string msg = "You told me to propagate PixelType from input to output"; + msg += " cube but there are no input cubes loaded"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + else { + cube->SetPixelType(att.PixelType()); + } + + if (att.PropagateMinimumMaximum()) { + if (cube->PixelType() == Isis::Real) { + cube->SetBaseMultiplier(0.0, 1.0); + } + else if (InputCubes.size() == 0) { + string msg = "You told me to propagate base/multiplier from input to output"; + msg += " cube but there are no input cubes loaded"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + else if (cube->PixelType() >= InputCubes[0]->PixelType()) { + double base = InputCubes[0]->Base(); + double mult = InputCubes[0]->Multiplier(); + cube->SetBaseMultiplier(base, mult); + } + else if ((cube->PixelType() != Isis::Real) && + (cube->PixelType() != Isis::UnsignedByte) && + (cube->PixelType() != Isis::SignedWord)) { + string msg = "Looks like your refactoring to add different pixel types"; + msg += " you'll need to make changes here"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + else { + string msg = "You've chosen to reduce your output PixelType for [" + + fname + "] you must specify the output pixel range too"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + else { + // Not propagating so either the user entered or the programmer did + cube->SetMinMax(att.Minimum(), att.Maximum()); + } + + if (InputCubes.size() > 0) { + int needLabBytes = InputCubes[0]->LabelBytesUsed() + (1024 * 6); + if (needLabBytes > cube->LabelBytes()) { + cube->SetLabelBytes(needLabBytes); + } + } + + // Allocate the cube + cube->Create (fname); + + // Transfer labels from the first input cube + if ((p_propagateLabels) && (InputCubes.size() > 0)) { + Isis::PvlObject &incube = InputCubes[0]->Label()->FindObject("IsisCube"); + Isis::PvlObject &outcube = cube->Label()->FindObject("IsisCube"); + for (int i=0; i 0)) { + Isis::Pvl &inlab = *InputCubes[0]->Label(); + for (int i=0; iRead(t); + cube->Write(t); + } + } + } + + // Transfer blobs from the first input cube + if ((p_propagatePolygons) && (InputCubes.size() > 0)) { + Isis::Pvl &inlab = *InputCubes[0]->Label(); + for (int i=0; iRead(t); + cube->Write(t); + } + } + } + + // Transfer tables from the first input cube + if ((p_propagateOriginalLabel) && (InputCubes.size() > 0)) { + Isis::Pvl &inlab = *InputCubes[0]->Label(); + for (int i=0; iRead(ol); + cube->Write(ol); + } + } + } + + // Transfer history from the first input cube + WriteHistory(*cube); + } + catch (Isis::iException &e) { + delete cube; + throw; + } + + // Everything is fine so save the cube on the stack + OutputCubes.push_back (cube); + return cube; + } + + /** + * End the processing sequence and cleans up by closing cubes, freeing memory, + * etc. + */ + void Process::EndProcess () { + // Close the input cubes + for (int i=0; i<(int)InputCubes.size(); i++) { + InputCubes[i]->Close (); + delete InputCubes[i]; + } + InputCubes.clear(); + + // Close the output cubes + for (int i=0; i<(int)OutputCubes.size(); i++) { + OutputCubes[i]->Close (); + delete OutputCubes[i]; + } + OutputCubes.clear(); + } + + /** + * This method allows the programmer to turn on/off the propagation of labels + * from the 1st input cube to any of the output cubes. By default, propagation + * occurs automatically in the Process class when a call to either of the + * SetOutputCube methods is invoked. If the program * requires no propagation + * then utilize this method. This method can be invoked between successive + * calls of SetOutputCube so that some cube will have labels propagated while + * others will not. + * + * @param prop Flag indicating if labels are be propagated to output cubes. + */ + void Process::PropagateLabels (const bool prop) { + p_propagateLabels = prop; + } + + /** + * This method allows the programmer to propagate labels from a specific + * secondary cube. + * + * @param cube iString containing the name of the cube containing the labels + * to propagate. + */ + void Process::PropagateLabels (const std::string &cube) { + // Open the Pvl file + Isis::Pvl pvl(cube); + + // Loop for each output cube + for (int i=0; i<(int)OutputCubes.size(); i++) { + Isis::PvlObject &incube = pvl.FindObject("IsisCube"); + Isis::PvlObject &outcube = OutputCubes[i]->Label()->FindObject("IsisCube"); + for (int g=0; gClose (); + delete InputCubes[i]; + } + InputCubes.clear(); + } + + /** + * Writes out the History blob to the cube + */ + void Process::WriteHistory(Cube &cube) { + if (p_propagateHistory) { + bool addedHist = false; + if (InputCubes.size() > 0) { + Isis::Pvl &inlab = *InputCubes[0]->Label(); + for (int i=0; iRead(h); + h.AddEntry(); + cube.Write(h); + addedHist = true; + } + } + } + + if (!addedHist) { + Isis::History h("IsisCube"); + h.AddEntry(); + cube.Write(h); + } + } + } + + /** + * Calculates and stores off statistics on every band of every + * cube added to this process via the SetInputCube method. + * + * The newly calculated statistics are stored in two ways: as a + * vector where each entry is a single Statistics object for + * every band of a particular input cube, and as a vector where + * each entry is a vector of Statistics objects, for each band + * separately, of a particular input cube. + */ + void Process::CalculateStatistics() { + for (unsigned cubeNum = 0; cubeNum < InputCubes.size(); cubeNum++) { + Cube *cube = InputCubes[cubeNum]; + + // Construct a line buffer manager and a statistics object + Isis::LineManager line (*cube); + Isis::Statistics *cubeStats = new Isis::Statistics(); + + int bandStart = 1; + int bandStop = cube->Bands(); + int maxSteps = cube->Lines() * cube->Bands(); + + iString cubeNumStr ((int)cubeNum+1); + iString totalCubes ((int)InputCubes.size()); + string msg = "Calculating statistics for cube " + cubeNumStr + " of " + totalCubes; + + Isis::Progress progress; + progress.SetText(msg); + progress.SetMaximumSteps(maxSteps); + progress.CheckStatus(); + + // Loop and get the statistics for a good minimum/maximum + vector allBandStats; + for (int useBand = bandStart; useBand <= bandStop; useBand++) { + Isis::Statistics *bandStats = new Isis::Statistics(); + + for (int i = 1; i <= cube->Lines(); i++) { + line.SetLine(i, useBand); + cube->Read(line); + bandStats->AddData(line.DoubleBuffer(), line.size()); + cubeStats->AddData(line.DoubleBuffer(), line.size()); + progress.CheckStatus(); + } + + allBandStats.push_back(bandStats); + } + + p_bandStats.push_back(allBandStats); + p_cubeStats.push_back(cubeStats); + } + } + +} // end namespace isis + diff --git a/isis/src/base/objs/Process/Process.h b/isis/src/base/objs/Process/Process.h new file mode 100644 index 0000000000000000000000000000000000000000..75b0b7f047a176480a44690343db097352ef3dfa --- /dev/null +++ b/isis/src/base/objs/Process/Process.h @@ -0,0 +1,267 @@ +#ifndef Process_h +#define Process_h +/** + * @file + * $Revision: 1.10 $ + * $Date: 2009/10/31 00:19:38 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Preference.h" + +#include "Cube.h" +#include "Progress.h" +#include "CubeAttribute.h" +#include "Statistics.h" + +namespace Isis { + const int SizeMatch = 1; + const int SpatialMatch = 2; + const int OneBand = 16; + const int BandMatchOrOne = 32; + const int ReadWrite = 64; + const int AllMatchOrOne = 128; +}; + +namespace Isis { + class UserInterface; + +/** + * @brief Base class for all cube processing derivatives + * + * This is the core of the Isis system. Process, a very important base class is + * often used to derive new classes which process cubes in a systematic manner. + * Some of these derived classes include ProcessByLine, FilterProcess, + * RubberSheet, and Export. For history buffs, the Process class equates to + * DOCUBE in Isis 2.0 and DOIO in PICS. Essentially, this class manages much of + * the tedious programming work for cube i/o, user interaction, history, etc. + * + * If you would like to see Process being used in implementation, see stats.cpp. + * For classes that inherit from Process, see ProcessByLine, FilterProcess, + * ProcessByBoxcar, RubberSheet, Export, or Import + * + * A working application example of Process can be found in the @link stats.cpp + * stats class. + * @endlink + * + * @ingroup HighLevelCubeIO + * + * @author 2002-06-21 Jeff Anderson + * + * @internal + * @history 2002-06-24 Jeff Anderson - Added ic_base::OneBand requirement + * option for SetInputCube methods + * @history 2002-07-15 Stuart Sides - Added capabilities for applications to + * log information to standard out or the + * GUI log window (ShowLog and Log). + * @history 2003-02-03 Jeff Anderson - Added propagation of labels from the + * first input cube to each output cube + * @history 2003-02-04 Jeff Anderson - Added PropagateLabels method + * @history 2003-02-04 Jeff Anderson - Fixed bug in propagation of input labels + * to output cube + * @history 2003-02-07 Jeff Anderson - Integrated iString class into the Log + * methods + * @history 2003-04-23 Jeff Anderson - Made accomodations for the updated + * Preference class + * @history 2003-04-28 Jeff Anderson - Added method to Log Label objects + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-06-04 Jeff Anderson - Added Progress method + * @history 2003-06-30 Jeff Anderson - Added MissionData method + * @history 2003-09-02 Jeff Anderson - Added SetOutputWorkCube method + * @history 2003-10-06 Jeff Anderson - Added IsisPvl pointer to the SetOutput + * methods so that the programmer can + * control characteristics of the output + * cube format. + * @history 2003-11-07 Stuart Sides - Added "ReadWrite" capability to the + * requirements parameter on SetInputCube + * and SetInputWorkCube. + * @history 2003-11-07 Jeff Anderson - Modified preference loading order so + * that the Init method will load + * $ISISROOT/testData/base/TestPreferences + * when the application name contains the + * word "unitTest". This forces unit tests + * to use a standard set of system + * preferences. + * @history 2003-12-01 Jeff Anderson - Added ProgagateLabel method to allow for + * propagation from secondary cubes. + * @history 2003-12-18 Jeff Anderson - Modifed preference loading to look for + * the users preference file in the + * directory $HOME/.Isis + * @history 2003-12-18 Jeff Anderson - Modified MissionData method to allow + * searching for the highest version of + * a file + * @history 2004-02-02 Jeff Anderson - Modified SetInputCube and SetOutputCube + * methods to accept CubeAttribute classes. + * Added the ClearInputCubes method. + * @history 2004-02-29 Jeff Anderson - Added ability to send LogResults to the + * parent process + * @history 2004-03-01 Jeff Anderson - Made the Init method check to see if + * .Isis and .Isis/history directories + * exist and if not then create them + * @history 2004-04-17 Stuart Sides - Fixed problem when creating .Isis/history + * directories on Solaris. + * @history 2004-06-30 Jeff Anderson - Added propagation of blobs + * @history 2005-02-08 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2006-09-19 Brendan George - Added WriteHistory function to + * independently write the history to the + * cube + * @history 2007-06-27 Steven Lambright - Added propagation of polygon blobs + * @history 2007-07-19 Steven Lambright - Fixed memory leak + * @history 2007-07-27 Steven Lambright - Updated AllMatchOrOne and BandMatchOrOne + * error messages + * @history 2008-05-12 Steven Lambright - Removed references to CubeInfo + * @history 2009-10-29 Travis Addair - Added method calculating + * statistics on all bands of all cubes + * @history 2009-10-30 Travis Addair - Changed method + * calculating statistics to store off its results in + * both p_bandStats and p_cubeStats, and added methods + * to access those results + * + * @todo 2005-02-08 Jeff Anderson - add an example to the class documentation. + */ + class Process { + protected: + Isis::Progress *p_progress; //!< Pointer to a Progress object + /** + * Flag indicating if labels are be propagated to output cubes. + */ + bool p_propagateLabels; + /** + * Flag indicating if tables are be propagated to output cubes. + */ + bool p_propagateTables; + /** + * Flag indicating if blobs are be propagated to output cubes. + */ + bool p_propagatePolygons; + /** + * Flag indicating if history is to be propagated to output cubes. + */ + bool p_propagateHistory; + /** + * Flag indicating if original lable is to be propagated to output cubes. + */ + bool p_propagateOriginalLabel; + + /** + * Holds the calculated statistics for each band separately of + * every input cubei after the CalculateStatistics method is + * called. + */ + std::vector< std::vector< Isis::Statistics* > > p_bandStats; + + /** + * Holds the calculated statistics for every band together of + * every input cubei after the CalculateStatistics method is + * called. + */ + std::vector< Isis::Statistics* > p_cubeStats; + + /** + * A vector of pointers to opened Cube objects. The pointers are + * established in the SetInputCube/SetInputWorkCube methods. + */ + std::vector InputCubes; + + /** + * A vector of pointers to allocated Cube objects. The pointers are + * established in the SetOutputCube method. + */ + std::vector OutputCubes; + + public: + Process (); + virtual ~Process (); + + /** + * In the base class, this method will invoked a user-specified function + * exactly one time. In derived classes such as ProcessByLine, the + * StartProcess will invoke a user-specified function for every line in a + * cube. + * + * @param funct() Name of your processing function + */ + void StartProcess (void funct ()) { funct(); }; + virtual void EndProcess (); + + + Isis::Cube* SetInputCube (const std::string ¶meter, + const int requirements=0); + Isis::Cube* SetInputCube (const std::string &fname, + const Isis::CubeAttributeInput &att, + int requirements=0); + void ClearInputCubes (); + + Isis::Cube* SetOutputCube (const std::string ¶meter); + Isis::Cube* SetOutputCube (const std::string ¶meter, const int nsamps, + const int nlines, const int nbands = 1); + Isis::Cube* SetOutputCube (const std::string &fname, + const Isis::CubeAttributeOutput &att, + const int nsamps, const int nlines, + const int nbands = 1); + + void PropagateLabels (const bool prop); + void PropagateLabels (const std::string &cube); + void PropagateTables (const bool prop); + void PropagatePolygons (const bool prop); + void PropagateHistory (const bool prop); + void PropagateOriginalLabel (const bool prop); + + /** + * This method returns a pointer to a Progress object + * + * @return Progress* + */ + Isis::Progress *Progress() { return p_progress; }; + + std::string MissionData (const std::string &mission, const std::string &file, + bool highestVersion=false); + + void WriteHistory(Cube &cube); + + void CalculateStatistics(); + + /** + * Get the vector of Statistics objects for each band separately + * of a specified input cube. + * + * @param index The index of the input cube in InputCubes + * + * @return vector A list of statistics ordered by + * band + */ + inline std::vector BandStatistics ( + const unsigned index) { return p_bandStats[index]; } + + /** + * Get the Statistics object for all bands of a specified input + * cube. + * + * @param index The index of the input cube in InputCubes + * + * @return Statistics* Collections of statistics gathered on all + * bands + */ + inline Isis::Statistics* CubeStatistics ( + const unsigned index) { return p_cubeStats[index]; } + }; +} + +#endif diff --git a/isis/src/base/objs/Process/Process.truth b/isis/src/base/objs/Process/Process.truth new file mode 100644 index 0000000000000000000000000000000000000000..c3df1d8af5d95b1afc53364271ab7754372b431e --- /dev/null +++ b/isis/src/base/objs/Process/Process.truth @@ -0,0 +1,105 @@ +Testing Isis::Process Class ... +Testing GetUserInterface ... +unitTest.cub + +Testing SetOutputCube without an input cube ... +**PROGRAMMER ERROR** No input images have been selected ... thereforethe output image size can not be determined + +Testing SetOutputCube with bogus samples ... +**PROGRAMMER ERROR** Invalid cube size specifications [ns=0,nl=1,nb=1] + +Testing SetOutputCube with bogus lines ... +**PROGRAMMER ERROR** Invalid cube size specifications [ns=1,nl=0,nb=1] + +Testing SetOutputCube with bogus bands ... +**PROGRAMMER ERROR** Invalid cube size specifications [ns=1,nl=1,nb=0] + +Testing SetInputCube/SetInputWorkCube ... +Samples: 126 +Lines: 126 +Bands: 2 + +Testing SetInputWorkCube OneBand Error ... +An exception was thrown! + +Testing SetInputWorkCube SizeMatch error for bands ... +**USER ERROR** The number of bands in the input cubes must match + +Testing SetInputWorkCube SizeMatch error for lines ... +**USER ERROR** The number of lines in the input cubes must match + +Testing SetInputWorkCube SizeMatch error for samples ... +**USER ERROR** The number of samples in the input cubes must match + +Testing SetInputWorkCube SpatialMatch error for lines ... +**USER ERROR** The number of lines in the input cubes must match + +Testing SetInputWorkCube SpatialMatch error for samples ... +**USER ERROR** The number of samples in the input cubes must match + +Testing SetInputWorkCube BandMatchOrOne error ... +**USER ERROR** The number of bands in the secondary input cubes must match the primary input cube or be exactly one + +Testing SetInputWorkCube AllMatchOrOne error ... +**USER ERROR** The number of bands in the secondary input cubes must match the primary input cube or be exactly one + +Testing Logging ... +Group = Results + Test = Me + No = Way +End_Group + +Testing label propagation (on) ... +Keyword = "This is a test" + +Testing label propagation (off) ... +Group Test does not exist + +Testing OriginalLabel propagation (on) ... +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 126 + Lines = 126 + Bands = 2 + End_Group + + Group = Pixels + Type = Real + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Test + Keyword = "This is a test" + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object +End + +Testing OriginalLabel propagation (off) ... +Group OriginalLabel does not exist + +Testing Table propagation (on) ... +Number of record = 2 +Record Size = 8 + +Testing Table propagation (off) ... +Group Table does not exist + +Testing Polygon propagation (on) ... +Image Polygon does exist +Size: 60 +Testing Polygon propagation (off) ... +Image Polygon does not exist + diff --git a/isis/src/base/objs/Process/unitTest.cpp b/isis/src/base/objs/Process/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48bb24020a646bbbdf1eadfc5ce3710ee08efe99 --- /dev/null +++ b/isis/src/base/objs/Process/unitTest.cpp @@ -0,0 +1,282 @@ +#include "Isis.h" + +#include +#include + +#include "OriginalLabel.h" +#include "Process.h" +#include "Cube.h" +#include "Pvl.h" +#include "Cube.h" +#include "Application.h" +#include "ImagePolygon.h" + +using namespace std; +void IsisMain() { + Isis::Preference::Preferences(true); + + cout << "Testing Isis::Process Class ... " << endl; + Isis::Process p; + + cout << "Testing GetUserInterface ... " << endl; + Isis::UserInterface &ui = Isis::Application::GetUserInterface(); + cout << ui.GetAsString("FROM") << endl; + cout << endl; + + cout << "Testing SetOutputCube without an input cube ..." << endl; + try { + p.SetOutputCube("TO"); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing SetOutputCube with bogus samples ..." << endl; + try { + p.SetOutputCube("TO",0,1,1); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing SetOutputCube with bogus lines ..." << endl; + try { + p.SetOutputCube("TO",1,0,1); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing SetOutputCube with bogus bands ..." << endl; + try { + p.SetOutputCube("TO",1,1,0); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing SetInputCube/SetInputWorkCube ... " << endl; + Isis::Cube *icube = p.SetInputCube("FROM"); + cout << "Samples: " << icube->Samples() << endl; + cout << "Lines: " << icube->Lines() << endl; + cout << "Bands: " << icube->Bands() << endl; + cout << endl; + + cout << "Testing SetInputWorkCube OneBand Error ..." << endl; + try { + p.SetInputCube("FROM",Isis::OneBand); + } + catch (Isis::iException &e) { + cout << "An exception was thrown!" << endl; + e.Clear(); + } + cout << endl; + + cout << "Testing SetInputWorkCube SizeMatch error for bands ..." << endl; + try { + Isis::CubeAttributeInput att("+1"); + p.SetInputCube("unitTest.cub", + att,Isis::SizeMatch); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing SetInputWorkCube SizeMatch error for lines ..." << endl; + Isis::Cube cube; + cube.SetDimensions(126,100,2); + cube.Create("/tmp/isisprocess_01"); + cube.Close(); + try { + Isis::Process p2; + Isis::CubeAttributeInput att; + p2.SetInputCube("/tmp/isisprocess_01",att); + p2.SetInputCube("unitTest.cub",att, + Isis::SizeMatch); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing SetInputWorkCube SizeMatch error for samples ..." << endl; + cube.SetDimensions(100,126,2); + cube.Create("/tmp/isisprocess_02"); + cube.Close(); + try { + Isis::Process p2; + Isis::CubeAttributeInput att; + p2.SetInputCube("/tmp/isisprocess_02",att); + p2.SetInputCube("unitTest.cub",att, + Isis::SizeMatch); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing SetInputWorkCube SpatialMatch error for lines ..." << endl; + try { + Isis::Process p2; + Isis::CubeAttributeInput att; + p2.SetInputCube("/tmp/isisprocess_01",att); + p2.SetInputCube("unitTest.cub",att, + Isis::SpatialMatch); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing SetInputWorkCube SpatialMatch error for samples ..." << endl; + try { + Isis::Process p2; + Isis::CubeAttributeInput att; + p2.SetInputCube("/tmp/isisprocess_02",att); + p2.SetInputCube("unitTest.cub",att, + Isis::SpatialMatch); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing SetInputWorkCube BandMatchOrOne error ..." << endl; + cube.SetDimensions(126,126,3); + cube.Create("/tmp/isisprocess_03"); + cube.Close(); + try { + Isis::Process p2; + Isis::CubeAttributeInput att; + p2.SetInputCube("/tmp/isisprocess_03",att); + p2.SetInputCube("unitTest.cub",att, + Isis::BandMatchOrOne); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing SetInputWorkCube AllMatchOrOne error ..." << endl; + cube.SetDimensions(126,126,3); + cube.Create("/tmp/isisprocess_03"); + cube.Close(); + try { + Isis::Process p2; + Isis::CubeAttributeInput att; + p2.SetInputCube("/tmp/isisprocess_03",att); + p2.SetInputCube("unitTest.cub",att, + Isis::AllMatchOrOne); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + cout << "Testing Logging ..." << endl; + Isis::PvlGroup results("Results"); + results += Isis::PvlKeyword("Test","Me"); + results += Isis::PvlKeyword("No","Way"); + Isis::Application::Log(results); + cout << endl; + + cout << "Testing label propagation (on) ..." << endl; + Isis::Process p3; + p3.SetInputCube("FROM"); + Isis::Cube *ocube = p3.SetOutputCube("TO"); + Isis::PvlGroup lab = ocube->GetGroup("Test"); + cout << lab["Keyword"] << endl; + cout << endl; + + cout << "Testing label propagation (off) ..." << endl; + p3.PropagateLabels(false); + Isis::Cube *ocube4 = p3.SetOutputCube("TO4",126,126,1); + if (!ocube4->HasGroup("Test")) { + cout << "Group Test does not exist" << endl; + } + p3.EndProcess(); + cout << endl; + + cout << "Testing OriginalLabel propagation (on) ..." << endl; + Isis::Process p4; + p4.SetInputCube("FROM"); + Isis::OriginalLabel ol(ui.GetAsString("FROM")); + Isis::Pvl labels = ol.ReturnLabels(); + cout << labels << endl; + cout << endl; + + cout << "Testing OriginalLabel propagation (off) ..." << endl; + p4.PropagateOriginalLabel(false); + Isis::Cube *ocube5 = p4.SetOutputCube("TO4",126,126,1); + if (!ocube5->HasGroup("OriginalLabel")) { + cout << "Group OriginalLabel does not exist" << endl; + } + p4.EndProcess(); + cout << endl; + + cout << "Testing Table propagation (on) ..." << endl; + Isis::Process p5; + p5.SetInputCube("FROM"); + Isis::Cube *ocube6 = p5.SetOutputCube("TO"); + Isis::Table table("Table"); + ocube6->Read(table); + + cout << "Number of record = " << table.Records() << endl; + cout << "Record Size = " << table.RecordSize() << endl; + cout << endl; + + cout << "Testing Table propagation (off) ..." << endl; + p4.PropagateTables(false); + Isis::Cube *ocube7 = p5.SetOutputCube("TO4",126,126,1); + if (!ocube7->HasGroup("Table")) { + cout << "Group Table does not exist" << endl; + } + p5.EndProcess(); + cout << endl; + + cout << "Testing Polygon propagation (on) ..." << endl; + Isis::Process p6; + p6.SetInputCube("FROM"); + Isis::Cube *ocube8 = p6.SetOutputCube("TO"); + + Isis::Pvl *inlab1 = ocube8->Label(); + for (int i=0; iObjects(); i++) { + if (inlab1->Object(i).IsNamed("Polygon")) { + cout << "Image Polygon does exist" << endl; + cout << "Size: " << (int)inlab1->Object(i)["Bytes"] << endl; + // We cannot instantiate without spice data, so we won't try. + } + } + + cout << "Testing Polygon propagation (off) ..." << endl; + p6.PropagatePolygons(false); + bool exists = false; + Isis::Cube *ocube9 = p6.SetOutputCube("TO4",126,126,1); + Isis::Pvl *inlab2 = ocube9->Label(); + for (int i=0; iObjects(); i++) { + if (inlab2->Object(i).IsNamed("Polygon")) { + cout << "Image Polygon does exist" << endl; + exists = true; + } + } + if(!exists) { + cout << "Image Polygon does not exist" << endl; + } + + p6.EndProcess(); + cout << endl; + + cube.Open("/tmp/isisprocess_01"); + cube.Close(true); + cube.Open("/tmp/isisprocess_02"); + cube.Close(true); + cube.Open("/tmp/isisprocess_03"); + cube.Close(true); + cube.Open("/tmp/isisprocess_04"); + cube.Close(true); +} diff --git a/isis/src/base/objs/Process/unitTest.xml b/isis/src/base/objs/Process/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..b5a5b248fec199b362dbeac600f896b4fb68c859 --- /dev/null +++ b/isis/src/base/objs/Process/unitTest.xml @@ -0,0 +1,98 @@ + + + + Unit test for IsisProcess class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + Modified schema from astrogeology... isis.astrogeology... + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + unitTest.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisprocess_01.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisprocess_02.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisprocess_03.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisprocess_04.cub + + + + diff --git a/isis/src/base/objs/ProcessByBoxcar/Makefile b/isis/src/base/objs/ProcessByBoxcar/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..dfbb8ed0ba0e5c40810eea463dbe6fbb5cd43ba2 --- /dev/null +++ b/isis/src/base/objs/ProcessByBoxcar/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessByBoxcar.h +SRCS = ProcessByBoxcar.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessByBoxcar/ProcessByBoxcar.cpp b/isis/src/base/objs/ProcessByBoxcar/ProcessByBoxcar.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1bcd2901aa674225b57dbd41bbe91946c929bdbc --- /dev/null +++ b/isis/src/base/objs/ProcessByBoxcar/ProcessByBoxcar.cpp @@ -0,0 +1,128 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Process.h" +#include "Buffer.h" +#include "LineManager.h" +#include "ProcessByBoxcar.h" +#include "BoxcarManager.h" + +using namespace std; +namespace Isis { + + /** + * Sets the boxcar size + * + * @param ns Number of samples + * + * @param nl Number of lines + */ + void ProcessByBoxcar::SetBoxcarSize (const int ns, const int nl) { + + p_boxSamples = ns; + p_boxLines = nl; + p_boxsizeSet = true; + } + + /** + * Starts the systematic processing of the input cube by moving a boxcar, + * p_boxSamples by p_boxLines, through the cube one pixel at a time. The input + * and output buffers contain a Boxcar of the size indicated in p_boxSamples + * and p_boxLines. The input and output cube must be initialized prior to + * calling this method. + * + * @param funct (Isis::Buffer &in, double &out) Name of your processing function + * + * @throws Isis::iException::Programmer + */ + void ProcessByBoxcar::StartProcess (void funct(Isis::Buffer &in, double &out)) { + // Error checks ... there must be one input and output + if (InputCubes.size() != 1) { + string m = "You must specify exactly one input cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + else if (OutputCubes.size() != 1) { + string m = "You must specify exactly one output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // The lines in the input and output must match + if (InputCubes[0]->Lines() != OutputCubes[0]->Lines()) { + string m = "The number of lines in the input and output cubes "; + m += "must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // The samples in the input and output must match + if (InputCubes[0]->Samples() != OutputCubes[0]->Samples()) { + string m = "The number of samples in the input and output cubes "; + m += "must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // The bands in the input and output must match + if (InputCubes[0]->Bands() != OutputCubes[0]->Bands()) { + string m = "The number of bands in the input and output cubes "; + m += "must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Make sure the boxcar size has been set + if (!p_boxsizeSet) { + string m = "Use the SetBoxcarSize method to set the boxcar size"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Construct boxcar buffer and line buffer managers + Isis::BoxcarManager box(*InputCubes[0],p_boxSamples,p_boxLines); + Isis::LineManager line(*OutputCubes[0]); + double out; + + // Loop and let the app programmer use the boxcar to change output pixel + p_progress->SetMaximumSteps(InputCubes[0]->Lines()*InputCubes[0]->Bands()); + p_progress->CheckStatus(); + + box.begin(); + for (line.begin(); !line.end(); line.next()) { + for (int i=0; iRead(box); + funct (box,out); + line[i] = out; + box++; + } + OutputCubes[0]->Write(line); + p_progress->CheckStatus(); + } + + } + + /** + * End the boxcar processing sequence and cleans up by closing cubes, freeing + * memory, etc. + */ + void ProcessByBoxcar::EndProcess () { + + p_boxsizeSet = false; + Isis::Process::EndProcess (); + + } +} // end namespace isis diff --git a/isis/src/base/objs/ProcessByBoxcar/ProcessByBoxcar.h b/isis/src/base/objs/ProcessByBoxcar/ProcessByBoxcar.h new file mode 100644 index 0000000000000000000000000000000000000000..0c04ee376cb77c6ddbba4282fe979a178c79a9d4 --- /dev/null +++ b/isis/src/base/objs/ProcessByBoxcar/ProcessByBoxcar.h @@ -0,0 +1,73 @@ +#ifndef ProcessByBoxcar_h +#define ProcessByBoxcar_h +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:08 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Process.h" +#include "Buffer.h" + +namespace Isis { +/** + * @brief Process cubes by boxcar + * + * This is the processing class used to move a boxcar through cube data. This + * class allows only one input cube and one output cube. + * + * @ingroup HighLevelCubeIO + * + * @author 2003-01-03 Tracie Sucharski + * + * @internal + * @history 2003-04-02 Tracie Sucharski - Added unitTest + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2005-02-08 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * + * @todo 2005-02-08 Tracie Sucharski - add code example and implementation + * example to class documentation + */ + + class ProcessByBoxcar : public Isis::Process { + + private: + bool p_boxsizeSet; //!< Indicates whether the boxcar size has been set + int p_boxSamples; //!< Number of samples in boxcar + int p_boxLines; //!< Number of lines in boxcar + + + public: + + //! Constructs a ProcessByBoxcar object + ProcessByBoxcar () {p_boxsizeSet=false;}; + + //! Destroys the ProcessByBoxcar object. + ~ProcessByBoxcar () {}; + + void SetBoxcarSize (const int ns, const int nl); + + void StartProcess (void funct(Isis::Buffer &in, double &out)); + void EndProcess (); + }; +}; + +#endif diff --git a/isis/src/base/objs/ProcessByBoxcar/ProcessByBoxcar.truth b/isis/src/base/objs/ProcessByBoxcar/ProcessByBoxcar.truth new file mode 100644 index 0000000000000000000000000000000000000000..f697f188bc56c8f00d3ce7060a2f39dc010f991f --- /dev/null +++ b/isis/src/base/objs/ProcessByBoxcar/ProcessByBoxcar.truth @@ -0,0 +1,287 @@ +Testing Isis::ProcessByBoxcar Class ... +unittest: Working +0% Processed +Testing one input and output cube ... +Boxcar Samples: 3 +Boxcar Lines: 3 +Boxcar Bands: 1 + +Top Left Sample: 0, Top Left Line: 0, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 1, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 2, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 3, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 4, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 5, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 6, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 7, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 8, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 9, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 10, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 11, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 12, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 13, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 14, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 15, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 16, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 17, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 18, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 19, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 20, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 21, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 22, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 23, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 24, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 25, Top Left Band: 1 +10% Processed Top Left Sample: 0, Top Left Line: 26, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 27, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 28, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 29, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 30, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 31, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 32, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 33, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 34, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 35, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 36, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 37, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 38, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 39, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 40, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 41, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 42, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 43, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 44, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 45, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 46, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 47, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 48, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 49, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 50, Top Left Band: 1 +20% Processed Top Left Sample: 0, Top Left Line: 51, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 52, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 53, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 54, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 55, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 56, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 57, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 58, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 59, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 60, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 61, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 62, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 63, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 64, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 65, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 66, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 67, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 68, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 69, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 70, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 71, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 72, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 73, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 74, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 75, Top Left Band: 1 +30% Processed Top Left Sample: 0, Top Left Line: 76, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 77, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 78, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 79, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 80, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 81, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 82, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 83, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 84, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 85, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 86, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 87, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 88, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 89, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 90, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 91, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 92, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 93, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 94, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 95, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 96, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 97, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 98, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 99, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 100, Top Left Band: 1 +40% Processed Top Left Sample: 0, Top Left Line: 101, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 102, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 103, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 104, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 105, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 106, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 107, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 108, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 109, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 110, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 111, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 112, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 113, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 114, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 115, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 116, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 117, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 118, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 119, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 120, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 121, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 122, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 123, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 124, Top Left Band: 1 +Top Left Sample: 0, Top Left Line: 125, Top Left Band: 1 +50% Processed Top Left Sample: 0, Top Left Line: 0, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 1, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 2, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 3, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 4, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 5, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 6, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 7, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 8, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 9, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 10, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 11, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 12, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 13, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 14, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 15, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 16, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 17, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 18, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 19, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 20, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 21, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 22, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 23, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 24, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 25, Top Left Band: 2 +60% Processed Top Left Sample: 0, Top Left Line: 26, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 27, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 28, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 29, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 30, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 31, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 32, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 33, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 34, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 35, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 36, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 37, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 38, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 39, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 40, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 41, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 42, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 43, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 44, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 45, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 46, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 47, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 48, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 49, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 50, Top Left Band: 2 +70% Processed Top Left Sample: 0, Top Left Line: 51, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 52, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 53, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 54, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 55, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 56, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 57, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 58, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 59, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 60, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 61, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 62, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 63, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 64, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 65, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 66, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 67, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 68, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 69, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 70, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 71, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 72, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 73, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 74, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 75, Top Left Band: 2 +80% Processed Top Left Sample: 0, Top Left Line: 76, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 77, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 78, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 79, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 80, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 81, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 82, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 83, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 84, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 85, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 86, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 87, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 88, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 89, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 90, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 91, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 92, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 93, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 94, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 95, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 96, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 97, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 98, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 99, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 100, Top Left Band: 2 +90% Processed Top Left Sample: 0, Top Left Line: 101, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 102, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 103, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 104, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 105, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 106, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 107, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 108, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 109, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 110, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 111, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 112, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 113, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 114, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 115, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 116, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 117, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 118, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 119, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 120, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 121, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 122, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 123, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 124, Top Left Band: 2 +Top Left Sample: 0, Top Left Line: 125, Top Left Band: 2 +100% Processed +Testing for no inputs/outputs ... +**PROGRAMMER ERROR** You must specify exactly one input cube + +Testing for exactly one input ... +**PROGRAMMER ERROR** You must specify exactly one output cube + +**PROGRAMMER ERROR** No input images have been selected ... thereforethe output image size can not be determined + +Testing for too many input cubes ... +**PROGRAMMER ERROR** You must specify exactly one input cube + +Testing for too many output cubes ... +**PROGRAMMER ERROR** You must specify exactly one output cube + +Testing for lines mismatch ... +**PROGRAMMER ERROR** The number of lines in the input and output cubes must match + +Testing for samples mismatch ... +**PROGRAMMER ERROR** The number of samples in the input and output cubes must match + +Testing for bands mismatch ... +**PROGRAMMER ERROR** The number of bands in the input and output cubes must match + +Testing for boxcar size not set ... +**PROGRAMMER ERROR** Use the SetBoxcarSize method to set the boxcar size + diff --git a/isis/src/base/objs/ProcessByBoxcar/unitTest.cpp b/isis/src/base/objs/ProcessByBoxcar/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ff4e103912e7514d2f4c07a8c23351e5816c8ef --- /dev/null +++ b/isis/src/base/objs/ProcessByBoxcar/unitTest.cpp @@ -0,0 +1,161 @@ +#include "Isis.h" +#include "ProcessByBoxcar.h" +#include + +using namespace std; +void oneInAndOut (Isis::Buffer &ib, double &ob); + +void IsisMain() { + + Isis::Preference::Preferences(true); + + cout << "Testing Isis::ProcessByBoxcar Class ... " << endl; + Isis::ProcessByBoxcar p; + + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + p.SetBoxcarSize (3,3); + p.StartProcess(oneInAndOut); + p.EndProcess(); + + try { + cout << "Testing for no inputs/outputs ..." << endl; + p.SetBoxcarSize (3,3); + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + p.SetInputCube ("FROM"); + p.SetBoxcarSize (3,3); + cout << "Testing for exactly one input ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + p.SetOutputCube("TO"); + p.SetBoxcarSize (3,3); + cout << "Testing for exactly one output ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + p.SetInputCube("FROM"); + p.SetInputCube("FROM2"); + p.SetOutputCube("TO"); + p.SetBoxcarSize (3,3); + cout << "Testing for too many input cubes ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + p.SetOutputCube("TO2"); + p.SetBoxcarSize (3,3); + cout << "Testing for too many output cubes ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + p.SetInputCube("FROM"); + p.SetOutputCube("TO",1,1,1); + p.SetBoxcarSize (3,3); + cout << "Testing for lines mismatch ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + p.SetInputCube("FROM"); + p.SetOutputCube("TO",1,126,1); + p.SetBoxcarSize (3,3); + cout << "Testing for samples mismatch ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + p.SetInputCube("FROM"); + p.SetOutputCube("TO",126,126,1); + p.SetBoxcarSize (3,3); + cout << "Testing for bands mismatch ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + cout << "Testing for boxcar size not set ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + Isis::Cube cube; + cube.Open("/tmp/isisProcessByBoxcar_01"); + cube.Close(true); + cube.Open("/tmp/isisProcessByBoxcar_02"); + cube.Close(true); + +} + +void oneInAndOut (Isis::Buffer &ib, double &ob) { + static bool firstTime = true; + if (firstTime) { + firstTime = false; + cout << endl; + cout << "Testing one input and output cube ... " << endl; + cout << "Boxcar Samples: " << ib.SampleDimension() << endl; + cout << "Boxcar Lines: " << ib.LineDimension() << endl; + cout << "Boxcar Bands: " << ib.BandDimension() << endl; + cout << endl; + } + + if (ib.Sample() < 1) { + cout << "Top Left Sample: " << ib.Sample() + << ", Top Left Line: " << ib.Line() + << ", Top Left Band: " << ib.Band() << endl; + } +} + diff --git a/isis/src/base/objs/ProcessByBoxcar/unitTest.xml b/isis/src/base/objs/ProcessByBoxcar/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..495dc31c5a858d30e22744a1bd08e0433d8e75b6 --- /dev/null +++ b/isis/src/base/objs/ProcessByBoxcar/unitTest.xml @@ -0,0 +1,87 @@ + + + + Unit test for IsisProcessByBoxcar class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + Adapted from unitTest.xml for IsisProcessByLine + + + Modified schema from astrogeology... isis.astrogeology... + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub+1 + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisProcessByBoxcar_01.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisProcessByBoxcar_02.cub + + + + diff --git a/isis/src/base/objs/ProcessByBrick/Makefile b/isis/src/base/objs/ProcessByBrick/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..da4550b0921c085033cf218f3a7299fff998bc37 --- /dev/null +++ b/isis/src/base/objs/ProcessByBrick/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessByBrick.h +SRCS = ProcessByBrick.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessByBrick/ProcessByBrick.cpp b/isis/src/base/objs/ProcessByBrick/ProcessByBrick.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3b86e0d126f788e29d2c983bda0fec62e4e5f678 --- /dev/null +++ b/isis/src/base/objs/ProcessByBrick/ProcessByBrick.cpp @@ -0,0 +1,496 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/05/14 21:07:11 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "ProcessByBrick.h" +#include "Brick.h" +#include "Cube.h" + +using namespace std; +namespace Isis { + + ProcessByBrick::ProcessByBrick () { + p_inputBrickSamples.clear(); + p_inputBrickLines.clear(); + p_inputBrickBands.clear(); + + p_outputBrickSamples.clear(); + p_outputBrickLines.clear(); + p_outputBrickBands.clear(); + + p_inputBrickSizeSet=false; + p_outputBrickSizeSet=false; + p_wrapOption = false; + } + + /** + * Opens an input cube specified by the user and verifies requirements are met. + * This method is overloaded and adds the requirements of ISIS::SpatialMatch + * which requires all input cubes to have the same dimensions or be exactly + * be exactly one. For more information see Process::SetInputCube + * + * @return Cube* + * + * @param parameter User parameter to obtain file to open. Typically, the value + * is "FROM". For example, the user can specify on the command + * line FROM=myfile.cub and this method will attempt to open + * the cube "myfile.cub" if the parameter was set to "FROM". + * + * @param requirements See Process::SetInputCube for more information. + * Defaults to 0 + * + * @throws Isis::iException::Message + */ + Isis::Cube* ProcessByBrick::SetInputCube (const std::string ¶meter, + const int requirements) { + int allRequirements = Isis::AllMatchOrOne; + allRequirements |= requirements; + return Isis::Process::SetInputCube (parameter,allRequirements); + } + + /** + * Opens an input cube specified by the user, sets the attributes, and + * verifies requirements are met. This method is overloaded and adds the + * requirements of ISIS::SpatialMatch which requires all input cubes to + * have the same dimensions or be exactly be exactly one. For more + * information see Process::SetInputCube + * + * @return Cube* + * + * @param file User parameter to obtain file to open. Typically, the + * value is "FROM". For example, the user can specify on the command + * line FROM=myfile.cub and this method will attempt to open + * the cube "myfile.cub" if the parameter was set to "FROM". + * + * @param att See Process::SetInputCube for more information. + * + * @param requirements See Process::SetInputCube for more information. + * Defaults to 0 + * + * @throws Isis::iException::Message + */ + Isis::Cube* ProcessByBrick::SetInputCube (const std::string &file, + const Isis::CubeAttributeInput &att, + const int requirements) { + int allRequirements = Isis::AllMatchOrOne; + allRequirements |= requirements; + return Isis::Process::SetInputCube (file,att,allRequirements); + } + + + /** + * Sets the brick size + * + * @param ns Number of samples + * + * @param nl Number of lines + * + * @param nb Number of bands + */ + void ProcessByBrick::SetBrickSize (const int ns, const int nl, const int nb) { + p_inputBrickSamples.clear(); + p_inputBrickSamples.resize(InputCubes.size()+1, ns); + p_inputBrickLines.clear(); + p_inputBrickLines.resize(InputCubes.size()+1, nl); + p_inputBrickBands.clear(); + p_inputBrickBands.resize(InputCubes.size()+1, nb); + + p_outputBrickSamples.clear(); + p_outputBrickSamples.resize(OutputCubes.size()+1, ns); + p_outputBrickLines.clear(); + p_outputBrickLines.resize(OutputCubes.size()+1, nl); + p_outputBrickBands.clear(); + p_outputBrickBands.resize(OutputCubes.size()+1, nb); + + p_inputBrickSizeSet=true; + p_outputBrickSizeSet=true; + } + + /** + * Sets the size of all input bricks + * + * @param ns Number of samples + * + * @param nl Number of lines + * + * @param nb Number of bands + */ + void ProcessByBrick::SetInputBrickSize (const int ns, const int nl, const int nb){ + p_inputBrickSamples.clear(); + p_inputBrickSamples.resize(InputCubes.size()+1, ns); + p_inputBrickLines.clear(); + p_inputBrickLines.resize(InputCubes.size()+1, nl); + p_inputBrickBands.clear(); + p_inputBrickBands.resize(InputCubes.size()+1, nb); + + p_inputBrickSizeSet=true; + } + + /** + * Sets the brick size of the specified cube + * + * @param ns Number of samples + * + * @param nl Number of lines + * + * @param nb Number of bands + * + * @param cube The index of the cube + */ + void ProcessByBrick::SetInputBrickSize (const int ns, const int nl, const int nb, const int cube){ + if (cube > (int)InputCubes.size()) { + string m = "The specified cube is out of range"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // If a default size has already been set, use it to fill in + if (p_inputBrickSamples.size() > 0) { + p_inputBrickSamples.resize(InputCubes.size()+1, p_inputBrickSamples[0]); + p_inputBrickLines.resize(InputCubes.size()+1, p_inputBrickLines[0]); + p_inputBrickBands.resize(InputCubes.size()+1, p_inputBrickBands[0]); + } + // otherwise, make this the default size + else{ + p_inputBrickSamples.resize(InputCubes.size()+1, ns); + p_inputBrickLines.resize(InputCubes.size()+1, nl); + p_inputBrickBands.resize(InputCubes.size()+1, nb); + } + + p_inputBrickSamples[cube] = ns; + p_inputBrickLines[cube] = nl; + p_inputBrickBands[cube] = nb; + + p_inputBrickSizeSet=true; + } + + /** + * Sets the size of all output bricks + * + * @param ns Number of samples + * + * @param nl Number of lines + * + * @param nb Number of bands + */ + void ProcessByBrick::SetOutputBrickSize (const int ns, const int nl, const int nb){ + p_outputBrickSamples.clear(); + p_outputBrickSamples.resize(OutputCubes.size()+1, ns); + p_outputBrickLines.clear(); + p_outputBrickLines.resize(OutputCubes.size()+1, nl); + p_outputBrickBands.clear(); + p_outputBrickBands.resize(OutputCubes.size()+1, nb); + + p_outputBrickSizeSet=true; + } + + /** + * Sets the brick size of the specified output cube + * + * @param ns Number of samples + * + * @param nl Number of lines + * + * @param nb Number of bands + * + * @param cube The index of the cube + */ + void ProcessByBrick::SetOutputBrickSize (const int ns, const int nl, const int nb, const int cube){ + if (cube > (int)OutputCubes.size()) { + string m = "The specified cube is out of range"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // If a default size has already been set, use it to fill in + if (p_outputBrickSamples.size() > 0) { + p_outputBrickSamples.resize(OutputCubes.size()+1, p_outputBrickSamples[0]); + p_outputBrickLines.resize(OutputCubes.size()+1, p_outputBrickLines[0]); + p_outputBrickBands.resize(OutputCubes.size()+1, p_outputBrickBands[0]); + } + // otherwise, make this the default size + else{ + p_outputBrickSamples.resize(OutputCubes.size()+1, ns); + p_outputBrickLines.resize(OutputCubes.size()+1, nl); + p_outputBrickBands.resize(OutputCubes.size()+1, nb); + } + + p_outputBrickSamples[cube] = ns; + p_outputBrickLines[cube] = nl; + p_outputBrickBands[cube] = nb; + + p_outputBrickSizeSet=true; + } + + /** + * Starts the systematic processing of the input cube by moving an arbitrary + * shaped brick through the cube. This method requires that exactly one input + * cube and one output cube be loaded using the SetInputCube and SetOutputCube + * methods. + * + * @param funct (Isis::Buffer &in, Isis::Buffer &out) Receive an nxm brick in + * the input buffer and output the an nxm brick. If n=1 and m=lines + * this will process by columns. Likewise if n=samples and m=1 + * this will process by lines. + * + * @throws Isis::iException::Programmer + */ + void ProcessByBrick::StartProcess (void + funct(Isis::Buffer &in, Isis::Buffer &out)) { + // Error checks ... there must be one input and output + if (InputCubes.size() != 1) { + string m = "You must specify exactly one input cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } else if (OutputCubes.size() != 1) { + string m = "You must specify exactly one output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Make sure the brick size has been set + if (!p_inputBrickSizeSet || !p_outputBrickSizeSet) { + string m = "Use the SetBrickSize, SetInputBrickSize, or SetOutputBrickSize method to set the brick sizes"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Make all input and/or output cubes have the same size + if (p_outputBrickSamples.size() == 1) { + SetOutputBrickSize(p_outputBrickSamples[0], p_outputBrickLines[0], p_outputBrickBands[0], 1); + } + if (p_inputBrickSamples.size() == 1) { + SetInputBrickSize(p_inputBrickSamples[0], p_inputBrickLines[0], p_inputBrickBands[0], 1); + } + + // Construct brick buffers + Isis::Brick ibrick(*InputCubes[0],p_inputBrickSamples[1],p_inputBrickLines[1], p_inputBrickBands[1]); + Isis::Brick obrick(*OutputCubes[0],p_outputBrickSamples[1],p_outputBrickLines[1], p_outputBrickBands[1]); + + int numBricks; + if (ibrick.Bricks() > obrick.Bricks()) numBricks = ibrick.Bricks(); + else numBricks = obrick.Bricks(); + + // Loop and let the app programmer work with the bricks + p_progress->SetMaximumSteps(numBricks); + p_progress->CheckStatus(); + + ibrick.begin(); + obrick.begin(); + for (int i=0; iRead(ibrick); + funct (ibrick,obrick); + OutputCubes[0]->Write(obrick); + p_progress->CheckStatus(); + ibrick++; + obrick++; + } + } + + /** + * Starts the systematic processing of the input cube by moving an arbitrary + * shaped brick through the cube. This method requires that exactly one input + * cube be loaded. No output cubes are produced. + * + * @param funct (Isis::Buffer &in) Receive an nxm brick in the input buffer. If + * n=1 and m=lines this will process by columns. + * Likewise if n=samples and m=1 this will + * process by lines. + * + * @throws Isis::iException::Programmer + */ + void ProcessByBrick::StartProcess (void funct(Isis::Buffer &in)) { + // Error checks + if ((InputCubes.size() + OutputCubes.size()) != 1) { + string m = "You can only specify exactly one input or output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Determine if we have an input or output + Isis::Cube *cube; + // Construct brick buffers + Isis::Brick *bricks; + bool haveInput; + if (InputCubes.size() == 1) { + // Make sure the brick size has been set + if (!p_inputBrickSizeSet) { + string m = "Use the SetBrickSize or SetInputBrickSize method to set the input brick size"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + // And the size is stored + else if (p_inputBrickSamples.size() == 1) { + SetInputBrickSize(p_inputBrickSamples[0], p_inputBrickLines[0], p_inputBrickBands[0], 1); + } + + haveInput = true; + cube = InputCubes[0]; + bricks = new Isis::Brick(*cube,p_inputBrickSamples[1],p_inputBrickLines[1], p_inputBrickBands[1]); + } + else { + // Make sure the brick size has been set + if (!p_outputBrickSizeSet) { + string m = "Use the SetBrickSize or SetOutputBrickSize method to set the output brick size"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + // And the size is stored + else if (p_outputBrickSamples.size() == 1) { + SetOutputBrickSize(p_outputBrickSamples[0], p_outputBrickLines[0], p_outputBrickBands[0], 1); + } + + haveInput = false; + cube = OutputCubes[0]; + bricks = new Isis::Brick(*cube,p_outputBrickSamples[1],p_outputBrickLines[1], p_outputBrickBands[1]); + } + + // Loop and let the app programmer work with the bricks + p_progress->SetMaximumSteps(bricks->Bricks()); + p_progress->CheckStatus(); + + for (bricks->begin(); !bricks->end(); (*bricks)++) { + if (haveInput) cube->Read(*bricks); // input only + funct (*bricks); + if ((!haveInput) || (cube->IsReadWrite())) cube->Write(*bricks); // output only or input/output + p_progress->CheckStatus(); + } + + delete bricks; + } + + /** + * Starts the systematic processing of the input cube by moving an arbitrary + * shaped brick through the cube. This method allows multiple input and output + * cubes. + * + * @param funct (vector &in, vector &out) Receive + * an nxm brick in the input buffer. If + * n=1 and m=lines this will process by columns. + * Likewise if n=samples and m=1 this will + * process by lines. + * + * @throws Isis::iException::Programmer + */ + void ProcessByBrick::StartProcess (void funct(std::vector &in, + std::vector &out)) { + + // Make sure we had an image + if ( InputCubes.size()==0 && OutputCubes.size()==0) { + string m = "You have not specified any input or output cubes"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Make sure the brick size has been set + if (!p_inputBrickSizeSet && InputCubes.size() >0) { + string m = "Use the SetBrickSize or SetInputBrick method to set the input brick size(s)"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + else if (p_inputBrickSizeSet && p_inputBrickSamples.size() == 1) { + SetInputBrickSize(p_inputBrickSamples[0], p_inputBrickLines[0], p_inputBrickBands[0], InputCubes.size()); + } + if (!p_outputBrickSizeSet && OutputCubes.size() >0) { + string m = "Use the SetBrickSize or SetOutputBrick method to set the output brick size(s)"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + else if (p_outputBrickSizeSet && p_outputBrickSamples.size() == 1) { + SetOutputBrickSize(p_outputBrickSamples[0], p_outputBrickLines[0], p_outputBrickBands[0], OutputCubes.size()); + } + + // this parameter holds the number of bricks to be used in processing + // which is the maximum number of bricks of all the cubes. + int numBricks = 0; + + // Construct two vectors of brick buffer managers + // The input buffer managers + std::vector imgrs; + vector ibufs; + for (unsigned int i=1; i<=InputCubes.size(); i++) { + Isis::Brick *ibrick = new Isis::Brick(*InputCubes[i-1],p_inputBrickSamples[i],p_inputBrickLines[i], p_inputBrickBands[i]); + ibrick->begin(); + ibufs.push_back(ibrick); + imgrs.push_back(ibrick); + if ( numBricks < ibrick->Bricks() ) numBricks = ibrick->Bricks(); + } + + // And the output buffer managers + std::vector omgrs; + vector obufs; + for (unsigned int i=1; i<=OutputCubes.size(); i++) { + Isis::Brick *obrick = new Isis::Brick(*OutputCubes[i-1],p_outputBrickSamples[i],p_outputBrickLines[i], p_outputBrickBands[i]); + obrick->begin(); + obufs.push_back(obrick); + omgrs.push_back(obrick); + if ( numBricks < obrick->Bricks() ) numBricks = obrick->Bricks(); + } + + // Loop and let the app programmer process the bricks + p_progress->SetMaximumSteps(numBricks); + p_progress->CheckStatus(); + + for (int t=0; tRead(*ibufs[i]); + } + + // Pass them to the application function + funct (ibufs,obufs); + + // And copy them into the output cubes + for (unsigned int i=0; iWrite(*obufs[i]); + omgrs[i]->next(); + } + + for (unsigned int i=0; inext(); + // if the manager has reached the end and the + // wrap option is on, wrap around to the beginning + if (Wraps() && imgrs[i]->end()) imgrs[i]->begin(); + + // Enforce same band + if(imgrs[i]->Band() != imgrs[0]->Band() && InputCubes[i]->Bands() != 1) { + imgrs[i]->SetBaseBand(imgrs[0]->Band()); + } + } + + p_progress->CheckStatus(); + } + + for(unsigned int i = 0; i < ibufs.size(); i++) { + delete ibufs[i]; + } + ibufs.clear(); + imgrs.clear(); + + for(unsigned int i = 0; i < obufs.size(); i++) { + delete obufs[i]; + } + obufs.clear(); + omgrs.clear(); + } + + /** + * End the processing sequence and cleans up by closing cubes, freeing memory, + * etc. + */ + void ProcessByBrick::EndProcess () { + + p_inputBrickSizeSet = false; + p_outputBrickSizeSet = false; + Isis::Process::EndProcess (); + + } +} // end namespace isis + diff --git a/isis/src/base/objs/ProcessByBrick/ProcessByBrick.h b/isis/src/base/objs/ProcessByBrick/ProcessByBrick.h new file mode 100644 index 0000000000000000000000000000000000000000..356712dba84cd99de4e42d0c74695bc66635fdbf --- /dev/null +++ b/isis/src/base/objs/ProcessByBrick/ProcessByBrick.h @@ -0,0 +1,115 @@ +#ifndef ProcessByBrick_h +#define ProcessByBrick_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/06/18 20:59:40 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Process.h" +#include "Buffer.h" + +namespace Isis { +/** + * @brief Process cubes by brick + * + * This is the processing class used to move a brick through cube data. This + * class allows only one input cube and one output cube or one input cube. If + * the brick size does not evenly divide into the image the brick will be padded + * with Null pixels as it falls off the right and/or bottom edge of the image. + * The brick shape is only spatial-oriented with one band of data. + * + * @ingroup HighLevelCubeIO + * + * @author 2006-03-24 Jacob Danton + * + * @internal + * @history 2005-02-08 Jacob Danton - Original Version + * @history 2006-08-08 Debbie A. Cook - Added overloaded method + * SetInputCube + * @history 2007-12-14 Steven Lambright - Same band is now forced + * on input cubes when there are multiple input cubes + * @history 2008-01-09 Steven Lambright - Fixed a memory leak + * @history 2008-06-18 Steven Koechle - Fixed Documentation + */ + class ProcessByBrick : public Isis::Process { + + private: + bool p_wrapOption; //! p_inputBrickSamples; //! p_inputBrickLines; //! p_inputBrickBands; //! p_outputBrickSamples; //! p_outputBrickLines; //! p_outputBrickBands; //! &in, + std::vector &out)); + void EndProcess (); + }; +}; + +#endif diff --git a/isis/src/base/objs/ProcessByBrick/ProcessByBrick.truth b/isis/src/base/objs/ProcessByBrick/ProcessByBrick.truth new file mode 100644 index 0000000000000000000000000000000000000000..2e1af5419dfdbf9cc8360ea6cbc461b4e25d9172 --- /dev/null +++ b/isis/src/base/objs/ProcessByBrick/ProcessByBrick.truth @@ -0,0 +1,175 @@ +unittest: Working +0% Processed Testing two input and output cubes ... +Number of input cubes: 2 +Number of output cubes: 2 + +Sample: 1:1 Line: 1:1 Band: 1:1 +Sample: 11:11 Line: 1:1 Band: 1:1 +Sample: 21:21 Line: 1:1 Band: 1:1 +Sample: 31:31 Line: 1:1 Band: 1:1 +Sample: 41:41 Line: 1:1 Band: 1:1 +Sample: 51:51 Line: 1:1 Band: 1:1 +Sample: 61:61 Line: 1:1 Band: 1:1 +Sample: 71:71 Line: 1:1 Band: 1:1 +Sample: 81:81 Line: 1:1 Band: 1:1 +Sample: 91:91 Line: 1:1 Band: 1:1 +Sample: 101:101 Line: 1:1 Band: 1:1 +Sample: 111:111 Line: 1:1 Band: 1:1 +Sample: 121:121 Line: 1:1 Band: 1:1 +Sample: 1:1 Line: 11:11 Band: 1:1 +Sample: 11:11 Line: 11:11 Band: 1:1 +Sample: 21:21 Line: 11:11 Band: 1:1 +Sample: 31:31 Line: 11:11 Band: 1:1 +10% Processed Sample: 41:41 Line: 11:11 Band: 1:1 +Sample: 51:51 Line: 11:11 Band: 1:1 +Sample: 61:61 Line: 11:11 Band: 1:1 +Sample: 71:71 Line: 11:11 Band: 1:1 +Sample: 81:81 Line: 11:11 Band: 1:1 +Sample: 91:91 Line: 11:11 Band: 1:1 +Sample: 101:101 Line: 11:11 Band: 1:1 +Sample: 111:111 Line: 11:11 Band: 1:1 +Sample: 121:121 Line: 11:11 Band: 1:1 +Sample: 1:1 Line: 21:21 Band: 1:1 +Sample: 11:11 Line: 21:21 Band: 1:1 +Sample: 21:21 Line: 21:21 Band: 1:1 +Sample: 31:31 Line: 21:21 Band: 1:1 +Sample: 41:41 Line: 21:21 Band: 1:1 +Sample: 51:51 Line: 21:21 Band: 1:1 +Sample: 61:61 Line: 21:21 Band: 1:1 +Sample: 71:71 Line: 21:21 Band: 1:1 +20% Processed Sample: 81:81 Line: 21:21 Band: 1:1 +Sample: 91:91 Line: 21:21 Band: 1:1 +Sample: 101:101 Line: 21:21 Band: 1:1 +Sample: 111:111 Line: 21:21 Band: 1:1 +Sample: 121:121 Line: 21:21 Band: 1:1 +Sample: 1:1 Line: 31:31 Band: 1:1 +Sample: 11:11 Line: 31:31 Band: 1:1 +Sample: 21:21 Line: 31:31 Band: 1:1 +Sample: 31:31 Line: 31:31 Band: 1:1 +Sample: 41:41 Line: 31:31 Band: 1:1 +Sample: 51:51 Line: 31:31 Band: 1:1 +Sample: 61:61 Line: 31:31 Band: 1:1 +Sample: 71:71 Line: 31:31 Band: 1:1 +Sample: 81:81 Line: 31:31 Band: 1:1 +Sample: 91:91 Line: 31:31 Band: 1:1 +Sample: 101:101 Line: 31:31 Band: 1:1 +Sample: 111:111 Line: 31:31 Band: 1:1 +30% Processed Sample: 121:121 Line: 31:31 Band: 1:1 +Sample: 1:1 Line: 41:41 Band: 1:1 +Sample: 11:11 Line: 41:41 Band: 1:1 +Sample: 21:21 Line: 41:41 Band: 1:1 +Sample: 31:31 Line: 41:41 Band: 1:1 +Sample: 41:41 Line: 41:41 Band: 1:1 +Sample: 51:51 Line: 41:41 Band: 1:1 +Sample: 61:61 Line: 41:41 Band: 1:1 +Sample: 71:71 Line: 41:41 Band: 1:1 +Sample: 81:81 Line: 41:41 Band: 1:1 +Sample: 91:91 Line: 41:41 Band: 1:1 +Sample: 101:101 Line: 41:41 Band: 1:1 +Sample: 111:111 Line: 41:41 Band: 1:1 +Sample: 121:121 Line: 41:41 Band: 1:1 +Sample: 1:1 Line: 51:51 Band: 1:1 +Sample: 11:11 Line: 51:51 Band: 1:1 +Sample: 21:21 Line: 51:51 Band: 1:1 +40% Processed Sample: 31:31 Line: 51:51 Band: 1:1 +Sample: 41:41 Line: 51:51 Band: 1:1 +Sample: 51:51 Line: 51:51 Band: 1:1 +Sample: 61:61 Line: 51:51 Band: 1:1 +Sample: 71:71 Line: 51:51 Band: 1:1 +Sample: 81:81 Line: 51:51 Band: 1:1 +Sample: 91:91 Line: 51:51 Band: 1:1 +Sample: 101:101 Line: 51:51 Band: 1:1 +Sample: 111:111 Line: 51:51 Band: 1:1 +Sample: 121:121 Line: 51:51 Band: 1:1 +Sample: 1:1 Line: 61:61 Band: 1:1 +Sample: 11:11 Line: 61:61 Band: 1:1 +Sample: 21:21 Line: 61:61 Band: 1:1 +Sample: 31:31 Line: 61:61 Band: 1:1 +Sample: 41:41 Line: 61:61 Band: 1:1 +Sample: 51:51 Line: 61:61 Band: 1:1 +Sample: 61:61 Line: 61:61 Band: 1:1 +50% Processed Sample: 71:71 Line: 61:61 Band: 1:1 +Sample: 81:81 Line: 61:61 Band: 1:1 +Sample: 91:91 Line: 61:61 Band: 1:1 +Sample: 101:101 Line: 61:61 Band: 1:1 +Sample: 111:111 Line: 61:61 Band: 1:1 +Sample: 121:121 Line: 61:61 Band: 1:1 +Sample: 1:1 Line: 71:71 Band: 1:1 +Sample: 11:11 Line: 71:71 Band: 1:1 +Sample: 21:21 Line: 71:71 Band: 1:1 +Sample: 31:31 Line: 71:71 Band: 1:1 +Sample: 41:41 Line: 71:71 Band: 1:1 +Sample: 51:51 Line: 71:71 Band: 1:1 +Sample: 61:61 Line: 71:71 Band: 1:1 +Sample: 71:71 Line: 71:71 Band: 1:1 +Sample: 81:81 Line: 71:71 Band: 1:1 +Sample: 91:91 Line: 71:71 Band: 1:1 +Sample: 101:101 Line: 71:71 Band: 1:1 +60% Processed Sample: 111:111 Line: 71:71 Band: 1:1 +Sample: 121:121 Line: 71:71 Band: 1:1 +Sample: 1:1 Line: 81:81 Band: 1:1 +Sample: 11:11 Line: 81:81 Band: 1:1 +Sample: 21:21 Line: 81:81 Band: 1:1 +Sample: 31:31 Line: 81:81 Band: 1:1 +Sample: 41:41 Line: 81:81 Band: 1:1 +Sample: 51:51 Line: 81:81 Band: 1:1 +Sample: 61:61 Line: 81:81 Band: 1:1 +Sample: 71:71 Line: 81:81 Band: 1:1 +Sample: 81:81 Line: 81:81 Band: 1:1 +Sample: 91:91 Line: 81:81 Band: 1:1 +Sample: 101:101 Line: 81:81 Band: 1:1 +Sample: 111:111 Line: 81:81 Band: 1:1 +Sample: 121:121 Line: 81:81 Band: 1:1 +Sample: 1:1 Line: 91:91 Band: 1:1 +Sample: 11:11 Line: 91:91 Band: 1:1 +70% Processed Sample: 21:21 Line: 91:91 Band: 1:1 +Sample: 31:31 Line: 91:91 Band: 1:1 +Sample: 41:41 Line: 91:91 Band: 1:1 +Sample: 51:51 Line: 91:91 Band: 1:1 +Sample: 61:61 Line: 91:91 Band: 1:1 +Sample: 71:71 Line: 91:91 Band: 1:1 +Sample: 81:81 Line: 91:91 Band: 1:1 +Sample: 91:91 Line: 91:91 Band: 1:1 +Sample: 101:101 Line: 91:91 Band: 1:1 +Sample: 111:111 Line: 91:91 Band: 1:1 +Sample: 121:121 Line: 91:91 Band: 1:1 +Sample: 1:1 Line: 101:101 Band: 1:1 +Sample: 11:11 Line: 101:101 Band: 1:1 +Sample: 21:21 Line: 101:101 Band: 1:1 +Sample: 31:31 Line: 101:101 Band: 1:1 +Sample: 41:41 Line: 101:101 Band: 1:1 +Sample: 51:51 Line: 101:101 Band: 1:1 +80% Processed Sample: 61:61 Line: 101:101 Band: 1:1 +Sample: 71:71 Line: 101:101 Band: 1:1 +Sample: 81:81 Line: 101:101 Band: 1:1 +Sample: 91:91 Line: 101:101 Band: 1:1 +Sample: 101:101 Line: 101:101 Band: 1:1 +Sample: 111:111 Line: 101:101 Band: 1:1 +Sample: 121:121 Line: 101:101 Band: 1:1 +Sample: 1:1 Line: 111:111 Band: 1:1 +Sample: 11:11 Line: 111:111 Band: 1:1 +Sample: 21:21 Line: 111:111 Band: 1:1 +Sample: 31:31 Line: 111:111 Band: 1:1 +Sample: 41:41 Line: 111:111 Band: 1:1 +Sample: 51:51 Line: 111:111 Band: 1:1 +Sample: 61:61 Line: 111:111 Band: 1:1 +Sample: 71:71 Line: 111:111 Band: 1:1 +Sample: 81:81 Line: 111:111 Band: 1:1 +Sample: 91:91 Line: 111:111 Band: 1:1 +90% Processed Sample: 101:101 Line: 111:111 Band: 1:1 +Sample: 111:111 Line: 111:111 Band: 1:1 +Sample: 121:121 Line: 111:111 Band: 1:1 +Sample: 1:1 Line: 121:121 Band: 1:1 +Sample: 11:11 Line: 121:121 Band: 1:1 +Sample: 21:21 Line: 121:121 Band: 1:1 +Sample: 31:31 Line: 121:121 Band: 1:1 +Sample: 41:41 Line: 121:121 Band: 1:1 +Sample: 51:51 Line: 121:121 Band: 1:1 +Sample: 61:61 Line: 121:121 Band: 1:1 +Sample: 71:71 Line: 121:121 Band: 1:1 +Sample: 81:81 Line: 121:121 Band: 1:1 +Sample: 91:91 Line: 121:121 Band: 1:1 +Sample: 101:101 Line: 121:121 Band: 1:1 +Sample: 111:111 Line: 121:121 Band: 1:1 +Sample: 121:121 Line: 121:121 Band: 1:1 +100% Processed diff --git a/isis/src/base/objs/ProcessByBrick/unitTest.cpp b/isis/src/base/objs/ProcessByBrick/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8af3d198735d8139da19e2da3ebad175ffc47da --- /dev/null +++ b/isis/src/base/objs/ProcessByBrick/unitTest.cpp @@ -0,0 +1,65 @@ +#include "Isis.h" +#include "ProcessByBrick.h" +#include "Cube.h" +#include + +using namespace std; +void twoInAndOut (vector &ib, vector &ob); + +void IsisMain() +{ + Isis::Preference::Preferences(true); + Isis::ProcessByBrick p; + + Isis::Cube *icube = p.SetInputCube("FROM"); + p.SetInputCube("FROM2"); + p.SetBrickSize(10, 10, 2); + p.SetOutputCube("TO", icube->Samples(), icube->Lines(), icube->Bands()); + p.SetOutputCube("TO2", icube->Samples(), icube->Lines(), icube->Bands()); + p.StartProcess(twoInAndOut); + p.EndProcess(); + + Isis::Cube cube; + cube.Open("/tmp/isisProcessByBrick_01"); + cube.Close(true); + cube.Open("/tmp/isisProcessByBrick_02"); + cube.Close(true); +} + +void twoInAndOut (vector &ib, vector &ob) +{ + static bool firstTime = true; + if (firstTime) { + firstTime = false; + cout << "Testing two input and output cubes ... " << endl; + cout << "Number of input cubes: " << ib.size() << endl; + cout << "Number of output cubes: " << ob.size() << endl; + cout << endl; + } + + Isis::Buffer &inone = *ib[0]; + Isis::Buffer &intwo = *ib[1]; + Isis::Buffer &outone = *ob[0]; + Isis::Buffer &outtwo = *ob[1]; + + cout << "Sample: " << inone.Sample() << ":" << intwo.Sample() + << " Line: " << inone.Line() << ":" << intwo.Line() + << " Band: " << inone.Band() << ":" << intwo.Band() << endl; + + if ((inone.Sample() != intwo.Sample()) || + (inone.Line() != intwo.Line())) { + cout << "Bogus error #1" << endl; + } + + if ((inone.Sample() != outone.Sample()) || + (inone.Line() != outone.Line()) || + (inone.Band() != outone.Band())) { + cout << "Bogus error #2" << endl; + } + + if ((outone.Sample() != outtwo.Sample()) || + (outone.Line() != outtwo.Line()) || + (outone.Band() != outtwo.Band())) { + cout << "Bogus error #3" << endl; + } +} diff --git a/isis/src/base/objs/ProcessByBrick/unitTest.xml b/isis/src/base/objs/ProcessByBrick/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..58a2dc0e08d9ff5b34ed343adaba42a1aa51b311 --- /dev/null +++ b/isis/src/base/objs/ProcessByBrick/unitTest.xml @@ -0,0 +1,81 @@ + + + + ProcessByBrick unitTest. + + + + This is a unit test for ProcessByBrick. + + + + Scripting + + + + + Original Version + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub+2-1 + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisProcessByBrick_01.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisProcessByBrick_02.cub + + + + diff --git a/isis/src/base/objs/ProcessByLine/Makefile b/isis/src/base/objs/ProcessByLine/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..60f3da8a51700fe45c80f19986470da892f54b2a --- /dev/null +++ b/isis/src/base/objs/ProcessByLine/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessByLine.h +SRCS = ProcessByLine.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessByLine/ProcessByLine.cpp b/isis/src/base/objs/ProcessByLine/ProcessByLine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb33fbc6c729b251407ab1b8c5d1c04a06d5d56e --- /dev/null +++ b/isis/src/base/objs/ProcessByLine/ProcessByLine.cpp @@ -0,0 +1,185 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/05/14 21:07:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +#include "ProcessByLine.h" + +using namespace std; +namespace Isis { + /** + * Opens an input cube specified by the user and verifies requirements are met. + * This method is overloaded and adds the requirements of ic_base::SpatialMatch + * which requires all input cubes to have the same number of samples and lines. + * It also added the requirement ic_base::BandMatchOrOne which forces 2nd, 3rd, + * 4th, etc input cubes to match the number of bands in the 1st input cube + * or to have exactly one band. For more information see Process::SetInputCube + * + * @return Cube* + * + * @param parameter User parameter to obtain file to open. Typically, the value + * is "FROM". For example, the user can specify on the command + * line FROM=myfile.cub and this method will attempt to open + * the cube "myfile.cub" if the parameter was set to "FROM". + * + * @param requirements See Process::SetInputCube for more information. + * Defaults to 0 + * + * @throws Isis::iException::Message + */ + Isis::Cube* ProcessByLine::SetInputCube (const std::string ¶meter, + const int requirements) { + int allRequirements = Isis::SpatialMatch | Isis::BandMatchOrOne; + allRequirements |= requirements; + return Isis::Process::SetInputCube (parameter,allRequirements); + } + + + Isis::Cube* ProcessByLine::SetInputCube (const std::string &file, + Isis::CubeAttributeInput &att, + const int requirements) { + int allRequirements = Isis::SpatialMatch | Isis::BandMatchOrOne; + allRequirements |= requirements; + return Isis::Process::SetInputCube (file,att,allRequirements); + } + + /** + * This method invokes the process by line operation over a single input or + * output cube. It will be an input cube if the method SetInputCube was invoked + * exactly one time before calling StartProcess. It will be an output cube if + * the SetOutputCube method was invoked exactly one time. Typically this method + * can be used to obtain statistics, histograms, or other information from + * an input cube. + * + * @param funct (Isis::Buffer &b) Name of your processing function + * + * @throws Isis::iException::Message + * + * @internal + * @history 2005-02-28 Stuart Sides - Modified so cube that are opended + * ReadWrite will be written. Before + * only cube opened Write would be + * written. + */ + void ProcessByLine::StartProcess (void funct(Isis::Buffer &inout)) { + // Error checks + if ((InputCubes.size() + OutputCubes.size()) > 1) { + string m = "You can only specify exactly one input or output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + else if ((InputCubes.size() + OutputCubes.size()) == 0) { + string m = "You haven't specified an input or output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Determine if we have an input or output + if (InputCubes.size() == 1) SetBrickSize(InputCubes[0]->Samples(), 1, 1); + else SetBrickSize(OutputCubes[0]->Samples(), 1, 1); + + Isis::ProcessByBrick::StartProcess(funct); + } + + /** + * This method invokes the process by line operation over exactly one input and + * one output cube. Typically, this method is used for simple operations such + * as stretching a cube or applying various operators to a cube (add constant, + * multiply by constant, etc). + * + * @param funct (Isis::Buffer &in, Isis::Buffer &out) Name of your processing + * function + * + * @throws Isis::iException::Message + */ + void ProcessByLine::StartProcess (void + funct(Isis::Buffer &in, Isis::Buffer &out)) { + // Error checks ... there must be one input and output + if (InputCubes.size() != 1) { + string m = "You must specify exactly one input cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + else if (OutputCubes.size() != 1) { + string m = "You must specify exactly one output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // The lines in the input and output must match + if (InputCubes[0]->Lines() != OutputCubes[0]->Lines()) { + string m = "The number of lines in the input and output cubes "; + m += "must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // The bands in the input and output must match + if (InputCubes[0]->Bands() != OutputCubes[0]->Bands()) { + string m = "The number of bands in the input and output cubes "; + m += "must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + SetInputBrickSize(InputCubes[0]->Samples(), 1, 1); + SetOutputBrickSize(OutputCubes[0]->Samples(), 1, 1); + + Isis::ProcessByBrick::StartProcess(funct); + } + + /** + * This method invokes the process by line operation over multiple input and + * output cubes. Typically, this method is used when two input cubes are + * required for operations like ratios, differences, masking, etc. + * + * @param funct (vector &in, vector &out) Name + * of your processing function + * + * @throws Isis::iException::Message + */ + void ProcessByLine::StartProcess (void + funct(std::vector &in, std::vector &out)) { + // Make sure we had an image + if (InputCubes.size()+OutputCubes.size() < 1) { + string m = "You have not specified any input or output cubes"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Make sure all the output images have the same number of bands as + // the first input/output cube + for (unsigned int i=0; iLines() != OutputCubes[0]->Lines()) { + string m = "All output cubes must have the same number of lines "; + m += "as the first input cube or output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + if (OutputCubes[i]->Bands() != OutputCubes[0]->Bands()) { + string m = "All output cubes must have the same number of bands "; + m += "as the first input cube or output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + } + + for (unsigned int i=0; iSamples(), 1, 1, i+1); + } + for (unsigned int i=0; iSamples(), 1, 1, i+1); + } + + Isis::ProcessByBrick::StartProcess(funct); + } +} diff --git a/isis/src/base/objs/ProcessByLine/ProcessByLine.h b/isis/src/base/objs/ProcessByLine/ProcessByLine.h new file mode 100644 index 0000000000000000000000000000000000000000..13ac348958d6348a7a99af6904f0d49127b01663 --- /dev/null +++ b/isis/src/base/objs/ProcessByLine/ProcessByLine.h @@ -0,0 +1,109 @@ +#ifndef ProcessByLine_h +#define ProcessByLine_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/05/14 21:07:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "ProcessByBrick.h" +#include "Buffer.h" + +namespace Isis { + /** + * @brief Process cubes by line + * + * This class allows a programmer to develop a program which process input and + * output cubes sequentially by line. That is, receive the input data for line + * one, manipulate the data, and pass back the data for output line one. Then + * proceed to the line two and so one. This class is derived from the Process + * class which give many functions for setting up input and output cubes. + * + * Here is an example of how to use ProcessByLine + * @code + * using namespace std; + * #include "Isis.h" + * #include "ProcessByLine.h" + * #include "SpecialPixel.h" + * void mirror (Buffer &in, Buffer &out); + * void IsisMain() { + * // We will be processing by line ProcessByLine p; + * // Setup the input and output cubes + * p.SetInputCube("FROM"); + * p.SetOutputCube ("TO"); + * // Start the processing + * p.StartProcess(mirror); + * p.EndProcess(); + * } . + * // Line processing routine + * void mirror (Buffer &in, Buffer &out) { + * // Loop and flip pixels in the line. + * int index = in.size() - 1; + * for (int i=0; i &in, std::vector &out)); + }; +}; + +#endif diff --git a/isis/src/base/objs/ProcessByLine/ProcessByLine.truth b/isis/src/base/objs/ProcessByLine/ProcessByLine.truth new file mode 100644 index 0000000000000000000000000000000000000000..e0ab7555d7cf7219300d034448af9cfe67c5aad4 --- /dev/null +++ b/isis/src/base/objs/ProcessByLine/ProcessByLine.truth @@ -0,0 +1,873 @@ +Testing Isis::ProcessByLine Class ... +unittest: Working +0% Processed Testing one input cube ... +Buffer Samples: 126 +Buffer Lines: 1 +Buffer Bands: 1 + +Sample: 1 Line: 1 Band: 1 +Sample: 1 Line: 2 Band: 1 +Sample: 1 Line: 3 Band: 1 +Sample: 1 Line: 4 Band: 1 +Sample: 1 Line: 5 Band: 1 +Sample: 1 Line: 6 Band: 1 +Sample: 1 Line: 7 Band: 1 +Sample: 1 Line: 8 Band: 1 +Sample: 1 Line: 9 Band: 1 +Sample: 1 Line: 10 Band: 1 +Sample: 1 Line: 11 Band: 1 +Sample: 1 Line: 12 Band: 1 +Sample: 1 Line: 13 Band: 1 +Sample: 1 Line: 14 Band: 1 +Sample: 1 Line: 15 Band: 1 +Sample: 1 Line: 16 Band: 1 +Sample: 1 Line: 17 Band: 1 +Sample: 1 Line: 18 Band: 1 +Sample: 1 Line: 19 Band: 1 +Sample: 1 Line: 20 Band: 1 +Sample: 1 Line: 21 Band: 1 +Sample: 1 Line: 22 Band: 1 +Sample: 1 Line: 23 Band: 1 +Sample: 1 Line: 24 Band: 1 +Sample: 1 Line: 25 Band: 1 +Sample: 1 Line: 26 Band: 1 +10% Processed Sample: 1 Line: 27 Band: 1 +Sample: 1 Line: 28 Band: 1 +Sample: 1 Line: 29 Band: 1 +Sample: 1 Line: 30 Band: 1 +Sample: 1 Line: 31 Band: 1 +Sample: 1 Line: 32 Band: 1 +Sample: 1 Line: 33 Band: 1 +Sample: 1 Line: 34 Band: 1 +Sample: 1 Line: 35 Band: 1 +Sample: 1 Line: 36 Band: 1 +Sample: 1 Line: 37 Band: 1 +Sample: 1 Line: 38 Band: 1 +Sample: 1 Line: 39 Band: 1 +Sample: 1 Line: 40 Band: 1 +Sample: 1 Line: 41 Band: 1 +Sample: 1 Line: 42 Band: 1 +Sample: 1 Line: 43 Band: 1 +Sample: 1 Line: 44 Band: 1 +Sample: 1 Line: 45 Band: 1 +Sample: 1 Line: 46 Band: 1 +Sample: 1 Line: 47 Band: 1 +Sample: 1 Line: 48 Band: 1 +Sample: 1 Line: 49 Band: 1 +Sample: 1 Line: 50 Band: 1 +Sample: 1 Line: 51 Band: 1 +20% Processed Sample: 1 Line: 52 Band: 1 +Sample: 1 Line: 53 Band: 1 +Sample: 1 Line: 54 Band: 1 +Sample: 1 Line: 55 Band: 1 +Sample: 1 Line: 56 Band: 1 +Sample: 1 Line: 57 Band: 1 +Sample: 1 Line: 58 Band: 1 +Sample: 1 Line: 59 Band: 1 +Sample: 1 Line: 60 Band: 1 +Sample: 1 Line: 61 Band: 1 +Sample: 1 Line: 62 Band: 1 +Sample: 1 Line: 63 Band: 1 +Sample: 1 Line: 64 Band: 1 +Sample: 1 Line: 65 Band: 1 +Sample: 1 Line: 66 Band: 1 +Sample: 1 Line: 67 Band: 1 +Sample: 1 Line: 68 Band: 1 +Sample: 1 Line: 69 Band: 1 +Sample: 1 Line: 70 Band: 1 +Sample: 1 Line: 71 Band: 1 +Sample: 1 Line: 72 Band: 1 +Sample: 1 Line: 73 Band: 1 +Sample: 1 Line: 74 Band: 1 +Sample: 1 Line: 75 Band: 1 +Sample: 1 Line: 76 Band: 1 +30% Processed Sample: 1 Line: 77 Band: 1 +Sample: 1 Line: 78 Band: 1 +Sample: 1 Line: 79 Band: 1 +Sample: 1 Line: 80 Band: 1 +Sample: 1 Line: 81 Band: 1 +Sample: 1 Line: 82 Band: 1 +Sample: 1 Line: 83 Band: 1 +Sample: 1 Line: 84 Band: 1 +Sample: 1 Line: 85 Band: 1 +Sample: 1 Line: 86 Band: 1 +Sample: 1 Line: 87 Band: 1 +Sample: 1 Line: 88 Band: 1 +Sample: 1 Line: 89 Band: 1 +Sample: 1 Line: 90 Band: 1 +Sample: 1 Line: 91 Band: 1 +Sample: 1 Line: 92 Band: 1 +Sample: 1 Line: 93 Band: 1 +Sample: 1 Line: 94 Band: 1 +Sample: 1 Line: 95 Band: 1 +Sample: 1 Line: 96 Band: 1 +Sample: 1 Line: 97 Band: 1 +Sample: 1 Line: 98 Band: 1 +Sample: 1 Line: 99 Band: 1 +Sample: 1 Line: 100 Band: 1 +Sample: 1 Line: 101 Band: 1 +40% Processed Sample: 1 Line: 102 Band: 1 +Sample: 1 Line: 103 Band: 1 +Sample: 1 Line: 104 Band: 1 +Sample: 1 Line: 105 Band: 1 +Sample: 1 Line: 106 Band: 1 +Sample: 1 Line: 107 Band: 1 +Sample: 1 Line: 108 Band: 1 +Sample: 1 Line: 109 Band: 1 +Sample: 1 Line: 110 Band: 1 +Sample: 1 Line: 111 Band: 1 +Sample: 1 Line: 112 Band: 1 +Sample: 1 Line: 113 Band: 1 +Sample: 1 Line: 114 Band: 1 +Sample: 1 Line: 115 Band: 1 +Sample: 1 Line: 116 Band: 1 +Sample: 1 Line: 117 Band: 1 +Sample: 1 Line: 118 Band: 1 +Sample: 1 Line: 119 Band: 1 +Sample: 1 Line: 120 Band: 1 +Sample: 1 Line: 121 Band: 1 +Sample: 1 Line: 122 Band: 1 +Sample: 1 Line: 123 Band: 1 +Sample: 1 Line: 124 Band: 1 +Sample: 1 Line: 125 Band: 1 +Sample: 1 Line: 126 Band: 1 +50% Processed Sample: 1 Line: 1 Band: 2 +Sample: 1 Line: 2 Band: 2 +Sample: 1 Line: 3 Band: 2 +Sample: 1 Line: 4 Band: 2 +Sample: 1 Line: 5 Band: 2 +Sample: 1 Line: 6 Band: 2 +Sample: 1 Line: 7 Band: 2 +Sample: 1 Line: 8 Band: 2 +Sample: 1 Line: 9 Band: 2 +Sample: 1 Line: 10 Band: 2 +Sample: 1 Line: 11 Band: 2 +Sample: 1 Line: 12 Band: 2 +Sample: 1 Line: 13 Band: 2 +Sample: 1 Line: 14 Band: 2 +Sample: 1 Line: 15 Band: 2 +Sample: 1 Line: 16 Band: 2 +Sample: 1 Line: 17 Band: 2 +Sample: 1 Line: 18 Band: 2 +Sample: 1 Line: 19 Band: 2 +Sample: 1 Line: 20 Band: 2 +Sample: 1 Line: 21 Band: 2 +Sample: 1 Line: 22 Band: 2 +Sample: 1 Line: 23 Band: 2 +Sample: 1 Line: 24 Band: 2 +Sample: 1 Line: 25 Band: 2 +Sample: 1 Line: 26 Band: 2 +60% Processed Sample: 1 Line: 27 Band: 2 +Sample: 1 Line: 28 Band: 2 +Sample: 1 Line: 29 Band: 2 +Sample: 1 Line: 30 Band: 2 +Sample: 1 Line: 31 Band: 2 +Sample: 1 Line: 32 Band: 2 +Sample: 1 Line: 33 Band: 2 +Sample: 1 Line: 34 Band: 2 +Sample: 1 Line: 35 Band: 2 +Sample: 1 Line: 36 Band: 2 +Sample: 1 Line: 37 Band: 2 +Sample: 1 Line: 38 Band: 2 +Sample: 1 Line: 39 Band: 2 +Sample: 1 Line: 40 Band: 2 +Sample: 1 Line: 41 Band: 2 +Sample: 1 Line: 42 Band: 2 +Sample: 1 Line: 43 Band: 2 +Sample: 1 Line: 44 Band: 2 +Sample: 1 Line: 45 Band: 2 +Sample: 1 Line: 46 Band: 2 +Sample: 1 Line: 47 Band: 2 +Sample: 1 Line: 48 Band: 2 +Sample: 1 Line: 49 Band: 2 +Sample: 1 Line: 50 Band: 2 +Sample: 1 Line: 51 Band: 2 +70% Processed Sample: 1 Line: 52 Band: 2 +Sample: 1 Line: 53 Band: 2 +Sample: 1 Line: 54 Band: 2 +Sample: 1 Line: 55 Band: 2 +Sample: 1 Line: 56 Band: 2 +Sample: 1 Line: 57 Band: 2 +Sample: 1 Line: 58 Band: 2 +Sample: 1 Line: 59 Band: 2 +Sample: 1 Line: 60 Band: 2 +Sample: 1 Line: 61 Band: 2 +Sample: 1 Line: 62 Band: 2 +Sample: 1 Line: 63 Band: 2 +Sample: 1 Line: 64 Band: 2 +Sample: 1 Line: 65 Band: 2 +Sample: 1 Line: 66 Band: 2 +Sample: 1 Line: 67 Band: 2 +Sample: 1 Line: 68 Band: 2 +Sample: 1 Line: 69 Band: 2 +Sample: 1 Line: 70 Band: 2 +Sample: 1 Line: 71 Band: 2 +Sample: 1 Line: 72 Band: 2 +Sample: 1 Line: 73 Band: 2 +Sample: 1 Line: 74 Band: 2 +Sample: 1 Line: 75 Band: 2 +Sample: 1 Line: 76 Band: 2 +80% Processed Sample: 1 Line: 77 Band: 2 +Sample: 1 Line: 78 Band: 2 +Sample: 1 Line: 79 Band: 2 +Sample: 1 Line: 80 Band: 2 +Sample: 1 Line: 81 Band: 2 +Sample: 1 Line: 82 Band: 2 +Sample: 1 Line: 83 Band: 2 +Sample: 1 Line: 84 Band: 2 +Sample: 1 Line: 85 Band: 2 +Sample: 1 Line: 86 Band: 2 +Sample: 1 Line: 87 Band: 2 +Sample: 1 Line: 88 Band: 2 +Sample: 1 Line: 89 Band: 2 +Sample: 1 Line: 90 Band: 2 +Sample: 1 Line: 91 Band: 2 +Sample: 1 Line: 92 Band: 2 +Sample: 1 Line: 93 Band: 2 +Sample: 1 Line: 94 Band: 2 +Sample: 1 Line: 95 Band: 2 +Sample: 1 Line: 96 Band: 2 +Sample: 1 Line: 97 Band: 2 +Sample: 1 Line: 98 Band: 2 +Sample: 1 Line: 99 Band: 2 +Sample: 1 Line: 100 Band: 2 +Sample: 1 Line: 101 Band: 2 +90% Processed Sample: 1 Line: 102 Band: 2 +Sample: 1 Line: 103 Band: 2 +Sample: 1 Line: 104 Band: 2 +Sample: 1 Line: 105 Band: 2 +Sample: 1 Line: 106 Band: 2 +Sample: 1 Line: 107 Band: 2 +Sample: 1 Line: 108 Band: 2 +Sample: 1 Line: 109 Band: 2 +Sample: 1 Line: 110 Band: 2 +Sample: 1 Line: 111 Band: 2 +Sample: 1 Line: 112 Band: 2 +Sample: 1 Line: 113 Band: 2 +Sample: 1 Line: 114 Band: 2 +Sample: 1 Line: 115 Band: 2 +Sample: 1 Line: 116 Band: 2 +Sample: 1 Line: 117 Band: 2 +Sample: 1 Line: 118 Band: 2 +Sample: 1 Line: 119 Band: 2 +Sample: 1 Line: 120 Band: 2 +Sample: 1 Line: 121 Band: 2 +Sample: 1 Line: 122 Band: 2 +Sample: 1 Line: 123 Band: 2 +Sample: 1 Line: 124 Band: 2 +Sample: 1 Line: 125 Band: 2 +Sample: 1 Line: 126 Band: 2 +100% Processed +unittest: Working +0% Processed +Testing one output cube ... +Buffer Samples: 10 +Buffer Lines: 1 +Buffer Bands: 1 + +Sample: 1 Line: 1 Band: 1 +Sample: 1 Line: 2 Band: 1 +Sample: 1 Line: 3 Band: 1 +Sample: 1 Line: 4 Band: 1 +Sample: 1 Line: 5 Band: 1 +Sample: 1 Line: 6 Band: 1 +10% Processed Sample: 1 Line: 7 Band: 1 +Sample: 1 Line: 8 Band: 1 +Sample: 1 Line: 9 Band: 1 +Sample: 1 Line: 10 Band: 1 +Sample: 1 Line: 11 Band: 1 +Sample: 1 Line: 12 Band: 1 +20% Processed Sample: 1 Line: 13 Band: 1 +Sample: 1 Line: 14 Band: 1 +Sample: 1 Line: 15 Band: 1 +Sample: 1 Line: 16 Band: 1 +Sample: 1 Line: 17 Band: 1 +Sample: 1 Line: 18 Band: 1 +30% Processed Sample: 1 Line: 19 Band: 1 +Sample: 1 Line: 20 Band: 1 +Sample: 1 Line: 1 Band: 2 +Sample: 1 Line: 2 Band: 2 +Sample: 1 Line: 3 Band: 2 +Sample: 1 Line: 4 Band: 2 +40% Processed Sample: 1 Line: 5 Band: 2 +Sample: 1 Line: 6 Band: 2 +Sample: 1 Line: 7 Band: 2 +Sample: 1 Line: 8 Band: 2 +Sample: 1 Line: 9 Band: 2 +Sample: 1 Line: 10 Band: 2 +50% Processed Sample: 1 Line: 11 Band: 2 +Sample: 1 Line: 12 Band: 2 +Sample: 1 Line: 13 Band: 2 +Sample: 1 Line: 14 Band: 2 +Sample: 1 Line: 15 Band: 2 +Sample: 1 Line: 16 Band: 2 +60% Processed Sample: 1 Line: 17 Band: 2 +Sample: 1 Line: 18 Band: 2 +Sample: 1 Line: 19 Band: 2 +Sample: 1 Line: 20 Band: 2 +Sample: 1 Line: 1 Band: 3 +Sample: 1 Line: 2 Band: 3 +70% Processed Sample: 1 Line: 3 Band: 3 +Sample: 1 Line: 4 Band: 3 +Sample: 1 Line: 5 Band: 3 +Sample: 1 Line: 6 Band: 3 +Sample: 1 Line: 7 Band: 3 +Sample: 1 Line: 8 Band: 3 +80% Processed Sample: 1 Line: 9 Band: 3 +Sample: 1 Line: 10 Band: 3 +Sample: 1 Line: 11 Band: 3 +Sample: 1 Line: 12 Band: 3 +Sample: 1 Line: 13 Band: 3 +Sample: 1 Line: 14 Band: 3 +90% Processed Sample: 1 Line: 15 Band: 3 +Sample: 1 Line: 16 Band: 3 +Sample: 1 Line: 17 Band: 3 +Sample: 1 Line: 18 Band: 3 +Sample: 1 Line: 19 Band: 3 +Sample: 1 Line: 20 Band: 3 +100% Processed +unittest: Working +0% Processed +Testing one input and output cube ... +Buffer Samples: 126 +Buffer Lines: 1 +Buffer Bands: 1 + +Sample: 1 Line: 1 Band: 1 +Sample: 1 Line: 2 Band: 1 +Sample: 1 Line: 3 Band: 1 +Sample: 1 Line: 4 Band: 1 +Sample: 1 Line: 5 Band: 1 +Sample: 1 Line: 6 Band: 1 +Sample: 1 Line: 7 Band: 1 +Sample: 1 Line: 8 Band: 1 +Sample: 1 Line: 9 Band: 1 +Sample: 1 Line: 10 Band: 1 +Sample: 1 Line: 11 Band: 1 +Sample: 1 Line: 12 Band: 1 +Sample: 1 Line: 13 Band: 1 +Sample: 1 Line: 14 Band: 1 +Sample: 1 Line: 15 Band: 1 +Sample: 1 Line: 16 Band: 1 +Sample: 1 Line: 17 Band: 1 +Sample: 1 Line: 18 Band: 1 +Sample: 1 Line: 19 Band: 1 +Sample: 1 Line: 20 Band: 1 +Sample: 1 Line: 21 Band: 1 +Sample: 1 Line: 22 Band: 1 +Sample: 1 Line: 23 Band: 1 +Sample: 1 Line: 24 Band: 1 +Sample: 1 Line: 25 Band: 1 +Sample: 1 Line: 26 Band: 1 +10% Processed Sample: 1 Line: 27 Band: 1 +Sample: 1 Line: 28 Band: 1 +Sample: 1 Line: 29 Band: 1 +Sample: 1 Line: 30 Band: 1 +Sample: 1 Line: 31 Band: 1 +Sample: 1 Line: 32 Band: 1 +Sample: 1 Line: 33 Band: 1 +Sample: 1 Line: 34 Band: 1 +Sample: 1 Line: 35 Band: 1 +Sample: 1 Line: 36 Band: 1 +Sample: 1 Line: 37 Band: 1 +Sample: 1 Line: 38 Band: 1 +Sample: 1 Line: 39 Band: 1 +Sample: 1 Line: 40 Band: 1 +Sample: 1 Line: 41 Band: 1 +Sample: 1 Line: 42 Band: 1 +Sample: 1 Line: 43 Band: 1 +Sample: 1 Line: 44 Band: 1 +Sample: 1 Line: 45 Band: 1 +Sample: 1 Line: 46 Band: 1 +Sample: 1 Line: 47 Band: 1 +Sample: 1 Line: 48 Band: 1 +Sample: 1 Line: 49 Band: 1 +Sample: 1 Line: 50 Band: 1 +Sample: 1 Line: 51 Band: 1 +20% Processed Sample: 1 Line: 52 Band: 1 +Sample: 1 Line: 53 Band: 1 +Sample: 1 Line: 54 Band: 1 +Sample: 1 Line: 55 Band: 1 +Sample: 1 Line: 56 Band: 1 +Sample: 1 Line: 57 Band: 1 +Sample: 1 Line: 58 Band: 1 +Sample: 1 Line: 59 Band: 1 +Sample: 1 Line: 60 Band: 1 +Sample: 1 Line: 61 Band: 1 +Sample: 1 Line: 62 Band: 1 +Sample: 1 Line: 63 Band: 1 +Sample: 1 Line: 64 Band: 1 +Sample: 1 Line: 65 Band: 1 +Sample: 1 Line: 66 Band: 1 +Sample: 1 Line: 67 Band: 1 +Sample: 1 Line: 68 Band: 1 +Sample: 1 Line: 69 Band: 1 +Sample: 1 Line: 70 Band: 1 +Sample: 1 Line: 71 Band: 1 +Sample: 1 Line: 72 Band: 1 +Sample: 1 Line: 73 Band: 1 +Sample: 1 Line: 74 Band: 1 +Sample: 1 Line: 75 Band: 1 +Sample: 1 Line: 76 Band: 1 +30% Processed Sample: 1 Line: 77 Band: 1 +Sample: 1 Line: 78 Band: 1 +Sample: 1 Line: 79 Band: 1 +Sample: 1 Line: 80 Band: 1 +Sample: 1 Line: 81 Band: 1 +Sample: 1 Line: 82 Band: 1 +Sample: 1 Line: 83 Band: 1 +Sample: 1 Line: 84 Band: 1 +Sample: 1 Line: 85 Band: 1 +Sample: 1 Line: 86 Band: 1 +Sample: 1 Line: 87 Band: 1 +Sample: 1 Line: 88 Band: 1 +Sample: 1 Line: 89 Band: 1 +Sample: 1 Line: 90 Band: 1 +Sample: 1 Line: 91 Band: 1 +Sample: 1 Line: 92 Band: 1 +Sample: 1 Line: 93 Band: 1 +Sample: 1 Line: 94 Band: 1 +Sample: 1 Line: 95 Band: 1 +Sample: 1 Line: 96 Band: 1 +Sample: 1 Line: 97 Band: 1 +Sample: 1 Line: 98 Band: 1 +Sample: 1 Line: 99 Band: 1 +Sample: 1 Line: 100 Band: 1 +Sample: 1 Line: 101 Band: 1 +40% Processed Sample: 1 Line: 102 Band: 1 +Sample: 1 Line: 103 Band: 1 +Sample: 1 Line: 104 Band: 1 +Sample: 1 Line: 105 Band: 1 +Sample: 1 Line: 106 Band: 1 +Sample: 1 Line: 107 Band: 1 +Sample: 1 Line: 108 Band: 1 +Sample: 1 Line: 109 Band: 1 +Sample: 1 Line: 110 Band: 1 +Sample: 1 Line: 111 Band: 1 +Sample: 1 Line: 112 Band: 1 +Sample: 1 Line: 113 Band: 1 +Sample: 1 Line: 114 Band: 1 +Sample: 1 Line: 115 Band: 1 +Sample: 1 Line: 116 Band: 1 +Sample: 1 Line: 117 Band: 1 +Sample: 1 Line: 118 Band: 1 +Sample: 1 Line: 119 Band: 1 +Sample: 1 Line: 120 Band: 1 +Sample: 1 Line: 121 Band: 1 +Sample: 1 Line: 122 Band: 1 +Sample: 1 Line: 123 Band: 1 +Sample: 1 Line: 124 Band: 1 +Sample: 1 Line: 125 Band: 1 +Sample: 1 Line: 126 Band: 1 +50% Processed Sample: 1 Line: 1 Band: 2 +Sample: 1 Line: 2 Band: 2 +Sample: 1 Line: 3 Band: 2 +Sample: 1 Line: 4 Band: 2 +Sample: 1 Line: 5 Band: 2 +Sample: 1 Line: 6 Band: 2 +Sample: 1 Line: 7 Band: 2 +Sample: 1 Line: 8 Band: 2 +Sample: 1 Line: 9 Band: 2 +Sample: 1 Line: 10 Band: 2 +Sample: 1 Line: 11 Band: 2 +Sample: 1 Line: 12 Band: 2 +Sample: 1 Line: 13 Band: 2 +Sample: 1 Line: 14 Band: 2 +Sample: 1 Line: 15 Band: 2 +Sample: 1 Line: 16 Band: 2 +Sample: 1 Line: 17 Band: 2 +Sample: 1 Line: 18 Band: 2 +Sample: 1 Line: 19 Band: 2 +Sample: 1 Line: 20 Band: 2 +Sample: 1 Line: 21 Band: 2 +Sample: 1 Line: 22 Band: 2 +Sample: 1 Line: 23 Band: 2 +Sample: 1 Line: 24 Band: 2 +Sample: 1 Line: 25 Band: 2 +Sample: 1 Line: 26 Band: 2 +60% Processed Sample: 1 Line: 27 Band: 2 +Sample: 1 Line: 28 Band: 2 +Sample: 1 Line: 29 Band: 2 +Sample: 1 Line: 30 Band: 2 +Sample: 1 Line: 31 Band: 2 +Sample: 1 Line: 32 Band: 2 +Sample: 1 Line: 33 Band: 2 +Sample: 1 Line: 34 Band: 2 +Sample: 1 Line: 35 Band: 2 +Sample: 1 Line: 36 Band: 2 +Sample: 1 Line: 37 Band: 2 +Sample: 1 Line: 38 Band: 2 +Sample: 1 Line: 39 Band: 2 +Sample: 1 Line: 40 Band: 2 +Sample: 1 Line: 41 Band: 2 +Sample: 1 Line: 42 Band: 2 +Sample: 1 Line: 43 Band: 2 +Sample: 1 Line: 44 Band: 2 +Sample: 1 Line: 45 Band: 2 +Sample: 1 Line: 46 Band: 2 +Sample: 1 Line: 47 Band: 2 +Sample: 1 Line: 48 Band: 2 +Sample: 1 Line: 49 Band: 2 +Sample: 1 Line: 50 Band: 2 +Sample: 1 Line: 51 Band: 2 +70% Processed Sample: 1 Line: 52 Band: 2 +Sample: 1 Line: 53 Band: 2 +Sample: 1 Line: 54 Band: 2 +Sample: 1 Line: 55 Band: 2 +Sample: 1 Line: 56 Band: 2 +Sample: 1 Line: 57 Band: 2 +Sample: 1 Line: 58 Band: 2 +Sample: 1 Line: 59 Band: 2 +Sample: 1 Line: 60 Band: 2 +Sample: 1 Line: 61 Band: 2 +Sample: 1 Line: 62 Band: 2 +Sample: 1 Line: 63 Band: 2 +Sample: 1 Line: 64 Band: 2 +Sample: 1 Line: 65 Band: 2 +Sample: 1 Line: 66 Band: 2 +Sample: 1 Line: 67 Band: 2 +Sample: 1 Line: 68 Band: 2 +Sample: 1 Line: 69 Band: 2 +Sample: 1 Line: 70 Band: 2 +Sample: 1 Line: 71 Band: 2 +Sample: 1 Line: 72 Band: 2 +Sample: 1 Line: 73 Band: 2 +Sample: 1 Line: 74 Band: 2 +Sample: 1 Line: 75 Band: 2 +Sample: 1 Line: 76 Band: 2 +80% Processed Sample: 1 Line: 77 Band: 2 +Sample: 1 Line: 78 Band: 2 +Sample: 1 Line: 79 Band: 2 +Sample: 1 Line: 80 Band: 2 +Sample: 1 Line: 81 Band: 2 +Sample: 1 Line: 82 Band: 2 +Sample: 1 Line: 83 Band: 2 +Sample: 1 Line: 84 Band: 2 +Sample: 1 Line: 85 Band: 2 +Sample: 1 Line: 86 Band: 2 +Sample: 1 Line: 87 Band: 2 +Sample: 1 Line: 88 Band: 2 +Sample: 1 Line: 89 Band: 2 +Sample: 1 Line: 90 Band: 2 +Sample: 1 Line: 91 Band: 2 +Sample: 1 Line: 92 Band: 2 +Sample: 1 Line: 93 Band: 2 +Sample: 1 Line: 94 Band: 2 +Sample: 1 Line: 95 Band: 2 +Sample: 1 Line: 96 Band: 2 +Sample: 1 Line: 97 Band: 2 +Sample: 1 Line: 98 Band: 2 +Sample: 1 Line: 99 Band: 2 +Sample: 1 Line: 100 Band: 2 +Sample: 1 Line: 101 Band: 2 +90% Processed Sample: 1 Line: 102 Band: 2 +Sample: 1 Line: 103 Band: 2 +Sample: 1 Line: 104 Band: 2 +Sample: 1 Line: 105 Band: 2 +Sample: 1 Line: 106 Band: 2 +Sample: 1 Line: 107 Band: 2 +Sample: 1 Line: 108 Band: 2 +Sample: 1 Line: 109 Band: 2 +Sample: 1 Line: 110 Band: 2 +Sample: 1 Line: 111 Band: 2 +Sample: 1 Line: 112 Band: 2 +Sample: 1 Line: 113 Band: 2 +Sample: 1 Line: 114 Band: 2 +Sample: 1 Line: 115 Band: 2 +Sample: 1 Line: 116 Band: 2 +Sample: 1 Line: 117 Band: 2 +Sample: 1 Line: 118 Band: 2 +Sample: 1 Line: 119 Band: 2 +Sample: 1 Line: 120 Band: 2 +Sample: 1 Line: 121 Band: 2 +Sample: 1 Line: 122 Band: 2 +Sample: 1 Line: 123 Band: 2 +Sample: 1 Line: 124 Band: 2 +Sample: 1 Line: 125 Band: 2 +Sample: 1 Line: 126 Band: 2 +100% Processed +unittest: Working +0% Processed Testing two input and output cubes ... +Number of input cubes: 2 +Number of output cubes: 2 + +Sample: 1:1 Line: 1:1 Band: 1:1 +Sample: 1:1 Line: 2:2 Band: 1:1 +Sample: 1:1 Line: 3:3 Band: 1:1 +Sample: 1:1 Line: 4:4 Band: 1:1 +Sample: 1:1 Line: 5:5 Band: 1:1 +Sample: 1:1 Line: 6:6 Band: 1:1 +Sample: 1:1 Line: 7:7 Band: 1:1 +Sample: 1:1 Line: 8:8 Band: 1:1 +Sample: 1:1 Line: 9:9 Band: 1:1 +Sample: 1:1 Line: 10:10 Band: 1:1 +Sample: 1:1 Line: 11:11 Band: 1:1 +Sample: 1:1 Line: 12:12 Band: 1:1 +Sample: 1:1 Line: 13:13 Band: 1:1 +Sample: 1:1 Line: 14:14 Band: 1:1 +Sample: 1:1 Line: 15:15 Band: 1:1 +Sample: 1:1 Line: 16:16 Band: 1:1 +Sample: 1:1 Line: 17:17 Band: 1:1 +Sample: 1:1 Line: 18:18 Band: 1:1 +Sample: 1:1 Line: 19:19 Band: 1:1 +Sample: 1:1 Line: 20:20 Band: 1:1 +Sample: 1:1 Line: 21:21 Band: 1:1 +Sample: 1:1 Line: 22:22 Band: 1:1 +Sample: 1:1 Line: 23:23 Band: 1:1 +Sample: 1:1 Line: 24:24 Band: 1:1 +Sample: 1:1 Line: 25:25 Band: 1:1 +Sample: 1:1 Line: 26:26 Band: 1:1 +10% Processed Sample: 1:1 Line: 27:27 Band: 1:1 +Sample: 1:1 Line: 28:28 Band: 1:1 +Sample: 1:1 Line: 29:29 Band: 1:1 +Sample: 1:1 Line: 30:30 Band: 1:1 +Sample: 1:1 Line: 31:31 Band: 1:1 +Sample: 1:1 Line: 32:32 Band: 1:1 +Sample: 1:1 Line: 33:33 Band: 1:1 +Sample: 1:1 Line: 34:34 Band: 1:1 +Sample: 1:1 Line: 35:35 Band: 1:1 +Sample: 1:1 Line: 36:36 Band: 1:1 +Sample: 1:1 Line: 37:37 Band: 1:1 +Sample: 1:1 Line: 38:38 Band: 1:1 +Sample: 1:1 Line: 39:39 Band: 1:1 +Sample: 1:1 Line: 40:40 Band: 1:1 +Sample: 1:1 Line: 41:41 Band: 1:1 +Sample: 1:1 Line: 42:42 Band: 1:1 +Sample: 1:1 Line: 43:43 Band: 1:1 +Sample: 1:1 Line: 44:44 Band: 1:1 +Sample: 1:1 Line: 45:45 Band: 1:1 +Sample: 1:1 Line: 46:46 Band: 1:1 +Sample: 1:1 Line: 47:47 Band: 1:1 +Sample: 1:1 Line: 48:48 Band: 1:1 +Sample: 1:1 Line: 49:49 Band: 1:1 +Sample: 1:1 Line: 50:50 Band: 1:1 +Sample: 1:1 Line: 51:51 Band: 1:1 +20% Processed Sample: 1:1 Line: 52:52 Band: 1:1 +Sample: 1:1 Line: 53:53 Band: 1:1 +Sample: 1:1 Line: 54:54 Band: 1:1 +Sample: 1:1 Line: 55:55 Band: 1:1 +Sample: 1:1 Line: 56:56 Band: 1:1 +Sample: 1:1 Line: 57:57 Band: 1:1 +Sample: 1:1 Line: 58:58 Band: 1:1 +Sample: 1:1 Line: 59:59 Band: 1:1 +Sample: 1:1 Line: 60:60 Band: 1:1 +Sample: 1:1 Line: 61:61 Band: 1:1 +Sample: 1:1 Line: 62:62 Band: 1:1 +Sample: 1:1 Line: 63:63 Band: 1:1 +Sample: 1:1 Line: 64:64 Band: 1:1 +Sample: 1:1 Line: 65:65 Band: 1:1 +Sample: 1:1 Line: 66:66 Band: 1:1 +Sample: 1:1 Line: 67:67 Band: 1:1 +Sample: 1:1 Line: 68:68 Band: 1:1 +Sample: 1:1 Line: 69:69 Band: 1:1 +Sample: 1:1 Line: 70:70 Band: 1:1 +Sample: 1:1 Line: 71:71 Band: 1:1 +Sample: 1:1 Line: 72:72 Band: 1:1 +Sample: 1:1 Line: 73:73 Band: 1:1 +Sample: 1:1 Line: 74:74 Band: 1:1 +Sample: 1:1 Line: 75:75 Band: 1:1 +Sample: 1:1 Line: 76:76 Band: 1:1 +30% Processed Sample: 1:1 Line: 77:77 Band: 1:1 +Sample: 1:1 Line: 78:78 Band: 1:1 +Sample: 1:1 Line: 79:79 Band: 1:1 +Sample: 1:1 Line: 80:80 Band: 1:1 +Sample: 1:1 Line: 81:81 Band: 1:1 +Sample: 1:1 Line: 82:82 Band: 1:1 +Sample: 1:1 Line: 83:83 Band: 1:1 +Sample: 1:1 Line: 84:84 Band: 1:1 +Sample: 1:1 Line: 85:85 Band: 1:1 +Sample: 1:1 Line: 86:86 Band: 1:1 +Sample: 1:1 Line: 87:87 Band: 1:1 +Sample: 1:1 Line: 88:88 Band: 1:1 +Sample: 1:1 Line: 89:89 Band: 1:1 +Sample: 1:1 Line: 90:90 Band: 1:1 +Sample: 1:1 Line: 91:91 Band: 1:1 +Sample: 1:1 Line: 92:92 Band: 1:1 +Sample: 1:1 Line: 93:93 Band: 1:1 +Sample: 1:1 Line: 94:94 Band: 1:1 +Sample: 1:1 Line: 95:95 Band: 1:1 +Sample: 1:1 Line: 96:96 Band: 1:1 +Sample: 1:1 Line: 97:97 Band: 1:1 +Sample: 1:1 Line: 98:98 Band: 1:1 +Sample: 1:1 Line: 99:99 Band: 1:1 +Sample: 1:1 Line: 100:100 Band: 1:1 +Sample: 1:1 Line: 101:101 Band: 1:1 +40% Processed Sample: 1:1 Line: 102:102 Band: 1:1 +Sample: 1:1 Line: 103:103 Band: 1:1 +Sample: 1:1 Line: 104:104 Band: 1:1 +Sample: 1:1 Line: 105:105 Band: 1:1 +Sample: 1:1 Line: 106:106 Band: 1:1 +Sample: 1:1 Line: 107:107 Band: 1:1 +Sample: 1:1 Line: 108:108 Band: 1:1 +Sample: 1:1 Line: 109:109 Band: 1:1 +Sample: 1:1 Line: 110:110 Band: 1:1 +Sample: 1:1 Line: 111:111 Band: 1:1 +Sample: 1:1 Line: 112:112 Band: 1:1 +Sample: 1:1 Line: 113:113 Band: 1:1 +Sample: 1:1 Line: 114:114 Band: 1:1 +Sample: 1:1 Line: 115:115 Band: 1:1 +Sample: 1:1 Line: 116:116 Band: 1:1 +Sample: 1:1 Line: 117:117 Band: 1:1 +Sample: 1:1 Line: 118:118 Band: 1:1 +Sample: 1:1 Line: 119:119 Band: 1:1 +Sample: 1:1 Line: 120:120 Band: 1:1 +Sample: 1:1 Line: 121:121 Band: 1:1 +Sample: 1:1 Line: 122:122 Band: 1:1 +Sample: 1:1 Line: 123:123 Band: 1:1 +Sample: 1:1 Line: 124:124 Band: 1:1 +Sample: 1:1 Line: 125:125 Band: 1:1 +Sample: 1:1 Line: 126:126 Band: 1:1 +50% Processed Sample: 1:1 Line: 1:1 Band: 2:1 +Sample: 1:1 Line: 2:2 Band: 2:1 +Sample: 1:1 Line: 3:3 Band: 2:1 +Sample: 1:1 Line: 4:4 Band: 2:1 +Sample: 1:1 Line: 5:5 Band: 2:1 +Sample: 1:1 Line: 6:6 Band: 2:1 +Sample: 1:1 Line: 7:7 Band: 2:1 +Sample: 1:1 Line: 8:8 Band: 2:1 +Sample: 1:1 Line: 9:9 Band: 2:1 +Sample: 1:1 Line: 10:10 Band: 2:1 +Sample: 1:1 Line: 11:11 Band: 2:1 +Sample: 1:1 Line: 12:12 Band: 2:1 +Sample: 1:1 Line: 13:13 Band: 2:1 +Sample: 1:1 Line: 14:14 Band: 2:1 +Sample: 1:1 Line: 15:15 Band: 2:1 +Sample: 1:1 Line: 16:16 Band: 2:1 +Sample: 1:1 Line: 17:17 Band: 2:1 +Sample: 1:1 Line: 18:18 Band: 2:1 +Sample: 1:1 Line: 19:19 Band: 2:1 +Sample: 1:1 Line: 20:20 Band: 2:1 +Sample: 1:1 Line: 21:21 Band: 2:1 +Sample: 1:1 Line: 22:22 Band: 2:1 +Sample: 1:1 Line: 23:23 Band: 2:1 +Sample: 1:1 Line: 24:24 Band: 2:1 +Sample: 1:1 Line: 25:25 Band: 2:1 +Sample: 1:1 Line: 26:26 Band: 2:1 +60% Processed Sample: 1:1 Line: 27:27 Band: 2:1 +Sample: 1:1 Line: 28:28 Band: 2:1 +Sample: 1:1 Line: 29:29 Band: 2:1 +Sample: 1:1 Line: 30:30 Band: 2:1 +Sample: 1:1 Line: 31:31 Band: 2:1 +Sample: 1:1 Line: 32:32 Band: 2:1 +Sample: 1:1 Line: 33:33 Band: 2:1 +Sample: 1:1 Line: 34:34 Band: 2:1 +Sample: 1:1 Line: 35:35 Band: 2:1 +Sample: 1:1 Line: 36:36 Band: 2:1 +Sample: 1:1 Line: 37:37 Band: 2:1 +Sample: 1:1 Line: 38:38 Band: 2:1 +Sample: 1:1 Line: 39:39 Band: 2:1 +Sample: 1:1 Line: 40:40 Band: 2:1 +Sample: 1:1 Line: 41:41 Band: 2:1 +Sample: 1:1 Line: 42:42 Band: 2:1 +Sample: 1:1 Line: 43:43 Band: 2:1 +Sample: 1:1 Line: 44:44 Band: 2:1 +Sample: 1:1 Line: 45:45 Band: 2:1 +Sample: 1:1 Line: 46:46 Band: 2:1 +Sample: 1:1 Line: 47:47 Band: 2:1 +Sample: 1:1 Line: 48:48 Band: 2:1 +Sample: 1:1 Line: 49:49 Band: 2:1 +Sample: 1:1 Line: 50:50 Band: 2:1 +Sample: 1:1 Line: 51:51 Band: 2:1 +70% Processed Sample: 1:1 Line: 52:52 Band: 2:1 +Sample: 1:1 Line: 53:53 Band: 2:1 +Sample: 1:1 Line: 54:54 Band: 2:1 +Sample: 1:1 Line: 55:55 Band: 2:1 +Sample: 1:1 Line: 56:56 Band: 2:1 +Sample: 1:1 Line: 57:57 Band: 2:1 +Sample: 1:1 Line: 58:58 Band: 2:1 +Sample: 1:1 Line: 59:59 Band: 2:1 +Sample: 1:1 Line: 60:60 Band: 2:1 +Sample: 1:1 Line: 61:61 Band: 2:1 +Sample: 1:1 Line: 62:62 Band: 2:1 +Sample: 1:1 Line: 63:63 Band: 2:1 +Sample: 1:1 Line: 64:64 Band: 2:1 +Sample: 1:1 Line: 65:65 Band: 2:1 +Sample: 1:1 Line: 66:66 Band: 2:1 +Sample: 1:1 Line: 67:67 Band: 2:1 +Sample: 1:1 Line: 68:68 Band: 2:1 +Sample: 1:1 Line: 69:69 Band: 2:1 +Sample: 1:1 Line: 70:70 Band: 2:1 +Sample: 1:1 Line: 71:71 Band: 2:1 +Sample: 1:1 Line: 72:72 Band: 2:1 +Sample: 1:1 Line: 73:73 Band: 2:1 +Sample: 1:1 Line: 74:74 Band: 2:1 +Sample: 1:1 Line: 75:75 Band: 2:1 +Sample: 1:1 Line: 76:76 Band: 2:1 +80% Processed Sample: 1:1 Line: 77:77 Band: 2:1 +Sample: 1:1 Line: 78:78 Band: 2:1 +Sample: 1:1 Line: 79:79 Band: 2:1 +Sample: 1:1 Line: 80:80 Band: 2:1 +Sample: 1:1 Line: 81:81 Band: 2:1 +Sample: 1:1 Line: 82:82 Band: 2:1 +Sample: 1:1 Line: 83:83 Band: 2:1 +Sample: 1:1 Line: 84:84 Band: 2:1 +Sample: 1:1 Line: 85:85 Band: 2:1 +Sample: 1:1 Line: 86:86 Band: 2:1 +Sample: 1:1 Line: 87:87 Band: 2:1 +Sample: 1:1 Line: 88:88 Band: 2:1 +Sample: 1:1 Line: 89:89 Band: 2:1 +Sample: 1:1 Line: 90:90 Band: 2:1 +Sample: 1:1 Line: 91:91 Band: 2:1 +Sample: 1:1 Line: 92:92 Band: 2:1 +Sample: 1:1 Line: 93:93 Band: 2:1 +Sample: 1:1 Line: 94:94 Band: 2:1 +Sample: 1:1 Line: 95:95 Band: 2:1 +Sample: 1:1 Line: 96:96 Band: 2:1 +Sample: 1:1 Line: 97:97 Band: 2:1 +Sample: 1:1 Line: 98:98 Band: 2:1 +Sample: 1:1 Line: 99:99 Band: 2:1 +Sample: 1:1 Line: 100:100 Band: 2:1 +Sample: 1:1 Line: 101:101 Band: 2:1 +90% Processed Sample: 1:1 Line: 102:102 Band: 2:1 +Sample: 1:1 Line: 103:103 Band: 2:1 +Sample: 1:1 Line: 104:104 Band: 2:1 +Sample: 1:1 Line: 105:105 Band: 2:1 +Sample: 1:1 Line: 106:106 Band: 2:1 +Sample: 1:1 Line: 107:107 Band: 2:1 +Sample: 1:1 Line: 108:108 Band: 2:1 +Sample: 1:1 Line: 109:109 Band: 2:1 +Sample: 1:1 Line: 110:110 Band: 2:1 +Sample: 1:1 Line: 111:111 Band: 2:1 +Sample: 1:1 Line: 112:112 Band: 2:1 +Sample: 1:1 Line: 113:113 Band: 2:1 +Sample: 1:1 Line: 114:114 Band: 2:1 +Sample: 1:1 Line: 115:115 Band: 2:1 +Sample: 1:1 Line: 116:116 Band: 2:1 +Sample: 1:1 Line: 117:117 Band: 2:1 +Sample: 1:1 Line: 118:118 Band: 2:1 +Sample: 1:1 Line: 119:119 Band: 2:1 +Sample: 1:1 Line: 120:120 Band: 2:1 +Sample: 1:1 Line: 121:121 Band: 2:1 +Sample: 1:1 Line: 122:122 Band: 2:1 +Sample: 1:1 Line: 123:123 Band: 2:1 +Sample: 1:1 Line: 124:124 Band: 2:1 +Sample: 1:1 Line: 125:125 Band: 2:1 +Sample: 1:1 Line: 126:126 Band: 2:1 +100% Processed +Testing error for no input/output ... +**PROGRAMMER ERROR** You haven't specified an input or output cube + +Testing error for too many input/outputs ... +**PROGRAMMER ERROR** You can only specify exactly one input or output cube + +Testing for exactly one input ... +**PROGRAMMER ERROR** You must specify exactly one input cube + +Testing for exactly one output ... +**PROGRAMMER ERROR** You must specify exactly one output cube + +Testing for lines mismatch ... +**PROGRAMMER ERROR** The number of lines in the input and output cubes must match + +Testing for bands mismatch ... +**PROGRAMMER ERROR** The number of bands in the input and output cubes must match + +Testing for no inputs/outputs ... +**PROGRAMMER ERROR** You have not specified any input or output cubes + +Testing for output lines mismatch ... +**PROGRAMMER ERROR** All output cubes must have the same number of lines as the first input cube or output cube + +Testing for output bands mismatch ... +**PROGRAMMER ERROR** All output cubes must have the same number of bands as the first input cube or output cube + diff --git a/isis/src/base/objs/ProcessByLine/unitTest.cpp b/isis/src/base/objs/ProcessByLine/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..248bd25b928d09f585bac6fc69c764e48ef40237 --- /dev/null +++ b/isis/src/base/objs/ProcessByLine/unitTest.cpp @@ -0,0 +1,258 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "Cube.h" +#include + +using namespace std; +void oneInput (Isis::Buffer &b); +void oneOutput (Isis::Buffer &b); +void oneInAndOut (Isis::Buffer &ob, Isis::Buffer &ib); +void twoInAndOut (vector &ib, vector &ob); + +void IsisMain() { + + Isis::Preference::Preferences(true); + + cout << "Testing Isis::ProcessByLine Class ... " << endl; + Isis::ProcessByLine p; + + p.SetInputCube("FROM"); + p.StartProcess(oneInput); + p.EndProcess(); + + p.SetOutputCube("TO",10,20,3); + p.StartProcess(oneOutput); + p.EndProcess(); + + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + p.StartProcess(oneInAndOut); + p.EndProcess(); + + p.SetInputCube("FROM"); + p.SetInputCube("FROM2"); + p.SetOutputCube("TO"); + p.SetOutputCube("TO2"); + p.StartProcess(twoInAndOut); + p.EndProcess(); + + try { + cout << "Testing error for no input/output ..." << endl; + p.StartProcess(oneInput); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + cout << "Testing error for too many input/outputs ..." << endl; + p.StartProcess(oneInput); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + cout << "Testing for exactly one input ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + p.SetInputCube("FROM"); + cout << "Testing for exactly one output ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + p.SetInputCube("FROM"); + p.SetOutputCube("TO",1,1,1); + cout << "Testing for lines mismatch ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + +#if 0 + try { + p.SetInputCube("FROM"); + p.SetOutputCube("TO",1,126,1); + cout << "Testing for samples mismatch ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } +#endif + + try { + p.SetInputCube("FROM"); + p.SetOutputCube("TO",126,126,1); + cout << "Testing for bands mismatch ..." << endl; + p.StartProcess(oneInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + cout << "Testing for no inputs/outputs ..." << endl; + p.StartProcess(twoInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + +#if 0 + try { + cout << "Testing for output samples mismatch ..." << endl; + p.SetOutputCube("TO",2,2,2); + p.SetOutputCube("TO2",1,1,1); + p.StartProcess(twoInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } +#endif + + try { + cout << "Testing for output lines mismatch ..." << endl; + p.SetOutputCube("TO",2,2,2); + p.SetOutputCube("TO2",2,1,1); + p.StartProcess(twoInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + cout << "Testing for output bands mismatch ..." << endl; + p.SetOutputCube("TO",2,2,2); + p.SetOutputCube("TO2",2,2,1); + p.StartProcess(twoInAndOut); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + + Isis::Cube cube; + cube.Open("/tmp/isisProcessByLine_01"); + cube.Close(true); + cube.Open("/tmp/isisProcessByLine_02"); + cube.Close(true); +} + +void oneInput(Isis::Buffer &b) { + if ((b.Line() == 1) && (b.Band() == 1)) { + cout << "Testing one input cube ... " << endl; + cout << "Buffer Samples: " << b.size() << endl; + cout << "Buffer Lines: " << b.LineDimension() << endl; + cout << "Buffer Bands: " << b.BandDimension() << endl; + cout << endl; + } + cout << "Sample: " << b.Sample() + << " Line: " << b.Line() + << " Band: " << b.Band() << endl; +} + +void oneOutput(Isis::Buffer &b) { + if ((b.Line() == 1) && (b.Band() == 1)) { + cout << endl; + cout << "Testing one output cube ... " << endl; + cout << "Buffer Samples: " << b.size() << endl; + cout << "Buffer Lines: " << b.LineDimension() << endl; + cout << "Buffer Bands: " << b.BandDimension() << endl; + cout << endl; + } + cout << "Sample: " << b.Sample() + << " Line: " << b.Line() + << " Band: " << b.Band() << endl; +} + +void oneInAndOut (Isis::Buffer &ib, Isis::Buffer &ob) { + if ((ib.Line() == 1) && (ib.Band() == 1)) { + cout << endl; + cout << "Testing one input and output cube ... " << endl; + cout << "Buffer Samples: " << ib.size() << endl; + cout << "Buffer Lines: " << ib.LineDimension() << endl; + cout << "Buffer Bands: " << ib.BandDimension() << endl; + cout << endl; + } + cout << "Sample: " << ib.Sample() + << " Line: " << ib.Line() + << " Band: " << ib.Band() << endl; + + if ((ib.Sample() != ob.Sample()) || + (ib.Line() != ob.Line()) || + (ib.Band() != ob.Band())) { + cout << "Bogus error #1" << endl; + } +} + +void twoInAndOut (vector &ib, vector &ob) { + static bool firstTime = true; + if (firstTime) { + firstTime = false; + cout << "Testing two input and output cubes ... " << endl; + cout << "Number of input cubes: " << ib.size() << endl; + cout << "Number of output cubes: " << ob.size() << endl; + cout << endl; + } + + Isis::Buffer *inone = ib[0]; + Isis::Buffer *intwo = ib[1]; + Isis::Buffer *outone = ob[0]; + Isis::Buffer *outtwo = ob[1]; + + cout << "Sample: " << inone->Sample() << ":" << intwo->Sample() + << " Line: " << inone->Line() << ":" << intwo->Line() + << " Band: " << inone->Band() << ":" << intwo->Band() << endl; + + if ((inone->Sample() != intwo->Sample()) || + (inone->Line() != intwo->Line())) { + cout << "Bogus error #1" << endl; + } + + if ((inone->Sample() != outone->Sample()) || + (inone->Line() != outone->Line()) || + (inone->Band() != outone->Band())) { + cout << "Bogus error #2" << endl; + } + + if ((outone->Sample() != outtwo->Sample()) || + (outone->Line() != outtwo->Line()) || + (outone->Band() != outtwo->Band())) { + cout << "Bogus error #3" << endl; + } +} diff --git a/isis/src/base/objs/ProcessByLine/unitTest.xml b/isis/src/base/objs/ProcessByLine/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..a1c5b0ba40a75f0f300be02586c8b809ec56520a --- /dev/null +++ b/isis/src/base/objs/ProcessByLine/unitTest.xml @@ -0,0 +1,86 @@ + + + + Unit test for IsisProcess class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + Modified schema from astrogeology... isis.astrogeology... + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub+1 + + + cube + output + real + + Test cube + + + Test cube + + + *.cub + + /tmp/isisProcessByLine_01.cub + + + cube + output + real + + Test cube + + + Test cube + + + *.cub + + /tmp/isisProcessByLine_02.cub + + + + diff --git a/isis/src/base/objs/ProcessByQuickFilter/Makefile b/isis/src/base/objs/ProcessByQuickFilter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..79aaedb94c609e5fd45f05f56ee6234298b5b6c3 --- /dev/null +++ b/isis/src/base/objs/ProcessByQuickFilter/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessByQuickFilter.h +SRCS = ProcessByQuickFilter.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessByQuickFilter/ProcessByQuickFilter.cpp b/isis/src/base/objs/ProcessByQuickFilter/ProcessByQuickFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06d1d18f30e2e7965ffc31772cec533847d23611 --- /dev/null +++ b/isis/src/base/objs/ProcessByQuickFilter/ProcessByQuickFilter.cpp @@ -0,0 +1,221 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2006/12/15 15:58:39 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Preference.h" +#include "ProcessByQuickFilter.h" +#include "QuickFilter.h" +#include "LineManager.h" +#include "iException.h" +#include "Application.h" + +using namespace std; +namespace Isis { + + //! Constructs a FilterProcess object + ProcessByQuickFilter::ProcessByQuickFilter() : Isis::Process () { + SetFilterParameters(0,0); + p_getParametersFromUser = true; + } + + /** + * This method invokes the process on a line by line basis + * + * @param funct (Isis::Buffer &in, Isis::Buffer &out, Isis::QuickFilter &filter) + * Name of your processing function + * + * @throws Isis::iException::Programmer + */ + void ProcessByQuickFilter::StartProcess (void + funct(Isis::Buffer &in, Isis::Buffer &out, Isis::QuickFilter &filter)) { + // Error checks ... there must be one input and output + if (InputCubes.size() != 1) { + string m = "StartProcess only supports exactly one input file"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + if (OutputCubes.size() != 1) { + string m = "StartProcess only supports exactly one output file"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // The lines in the input and output must match + if (InputCubes[0]->Lines() != OutputCubes[0]->Lines()) { + string m = "The lines in the input and output cube must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // The samples in the input and output must match + if (InputCubes[0]->Samples() != OutputCubes[0]->Samples()) { + string m = "The samples in the input and output cube must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // The bands in the input and output must match + if (InputCubes[0]->Bands() != OutputCubes[0]->Bands()) { + string m = "The bands in the input and output cube must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Construct line buffer managers + Isis::LineManager *topline = new Isis::LineManager(*InputCubes[0]); + Isis::LineManager *iline = new Isis::LineManager(*InputCubes[0]); + Isis::LineManager *botline = new Isis::LineManager(*InputCubes[0]); + Isis::LineManager *oline = new Isis::LineManager(*OutputCubes[0]); + + int lines = InputCubes[0]->Lines(); + int samples = InputCubes[0]->Samples(); + int bands = InputCubes[0]->Bands(); + + // See if we need to get parameters from the user + if (p_getParametersFromUser) GetFilterParameters(); + + // Make sure the boxcar widht and height aren't too big for the image + if (lines*2-1 < p_boxcarLines) { + string msg = "Boxcar height is too big for cube size"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + if (samples*2-1 < p_boxcarSamples) { + string msg = "Boxcar width is too big for cube size"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Create the filter object + Isis::QuickFilter filter(samples,p_boxcarSamples,p_boxcarLines); + filter.SetMinMax(p_low,p_high); + filter.SetMinimumPixels(p_minimum); + + // Loop for each band + p_progress->SetMaximumSteps(lines*bands); + p_progress->CheckStatus(); + for (int band=1; band<=bands; band++) { + // Preload the filter + filter.Reset(); + int top = 1 - filter.HalfHeight(); + int bot; + for (bot = top; bot<=(1+filter.HalfHeight()); bot++) { + int iline = bot; + if (bot <= 0) iline = (-1 * bot + 2); + botline->SetLine(iline,band); + InputCubes[0]->Read(*botline); + filter.AddLine(botline->DoubleBuffer()); + } + bot = 1 + filter.HalfHeight() + 1; + + // Loop for each line + for (int line=1; line<=lines; line++) { + // Process a line + iline->SetLine(line,band); + oline->SetLine(line,band); + InputCubes[0]->Read(*iline); + funct (*iline,*oline,filter); + OutputCubes[0]->Write(*oline); + + // Remove the top line + if (top >= 1) { + topline->SetLine(top,band); + } + else { + topline->SetLine(-1*top+2,band); + } + InputCubes[0]->Read(*topline); + filter.RemoveLine(topline->DoubleBuffer()); + top++; + + // Add the next line + p_progress->CheckStatus(); + if (line == lines) continue; + + if (bot <= InputCubes[0]->Lines()) { + botline->SetLine(bot,band); + } + else { + botline->SetLine(lines - (bot - lines),band); + } + InputCubes[0]->Read(*botline); + filter.AddLine(botline->DoubleBuffer()); + bot++; + + // Update the progress + } + } + + // Free buffers before returning + delete topline; + delete iline; + delete botline; + delete oline; + } + + /** + * This method allows the programmer to set the filter parameters. If this + * method is not invoked then the parameters will be obtained from the user via + * the XML parameters indicate in the class description. + * + * @param samples Number of samples in the boxcar. Must be odd. + * + * @param lines Number of lines in the boxcar. Must be odd. + * + * @param low Minimum valid pixel value to include in statistical computations + * of the boxcar. Defaults to -DBL_MAX + * + * @param high Maximum valid pixel value to include in statistical computations + * of the boxcar. Defaults to DBL_MAX + * + * @param minimum Minimum number of valid pixels in the sample-by-line boxcar + * in order for statistical computations to be valid. + * Defaults to 0 + */ + void ProcessByQuickFilter::SetFilterParameters(int samples, int lines, + double low, double high, int minimum) { + p_getParametersFromUser = false; + p_boxcarSamples = samples; + p_boxcarLines = lines; + p_low = low; + p_high = high; + p_minimum = minimum; + } + + //! This method allows the user to input the filter parameters. + void ProcessByQuickFilter::GetFilterParameters() { + // Get boxcar size + p_boxcarSamples = Application::GetUserInterface().GetInteger("SAMPLES"); + p_boxcarLines = Application::GetUserInterface().GetInteger("LINES"); + + // Get valid pixel range + p_low = -DBL_MAX; + p_high = DBL_MAX; + if (Application::GetUserInterface().WasEntered("LOW")) { + p_low = Application::GetUserInterface().GetDouble("LOW"); + } + + if (Application::GetUserInterface().WasEntered("HIGH")) { + p_high = Application::GetUserInterface().GetDouble("HIGH"); + } + + // Get valid pixel count + p_minimum = 0; + if (Application::GetUserInterface().WasEntered("MINIMUM")) { + p_minimum = Application::GetUserInterface().GetInteger("MINIMUM"); + } + } +} // end namespace isis diff --git a/isis/src/base/objs/ProcessByQuickFilter/ProcessByQuickFilter.h b/isis/src/base/objs/ProcessByQuickFilter/ProcessByQuickFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..c07950803403f750a684d01aefd5831174c6c6ae --- /dev/null +++ b/isis/src/base/objs/ProcessByQuickFilter/ProcessByQuickFilter.h @@ -0,0 +1,101 @@ +#ifndef FilterProcess_h +#define FilterProcess_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2006/12/15 15:58:39 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Process.h" +#include "Buffer.h" +#include "QuickFilter.h" + +namespace Isis { + /** + * @brief Process cubes using a Filter Object + * + * This class processes an entire cube using an Filter object. That is, it + * walks a Filter object line-by-line over an input cube. This allows for the + * development of programs which do spatial filters such as highpass, lowpass, + * and sharpen. Understanding the Filter class is essential in order to utilize + * this class. This class expects the user to define an NxM boxcar size. Using + * that information, a Filter object is created and loaded with the proper cube + * data in order to walk the NxM boxcar through the entire cube in a very + * efficient manner. Currently it is required that the following parameters be + * available in the application XML file: + * LINES - Defines the height of the boxcar to convolve over the cube + * SAMPLES - Defines the width of the boxcar to convoled over the cube + * MINIMUM - Defines the minimum number of pixels in the boxcar in order for + * statistics to be computed (see Filter class) + * LOW - Defines minimum valid pixel value to be included in statistics + * (see Filter class) + * HIGH - Defines maximum valid pixel value to be included in statistics + * (see Filter class) + * + * If you would like to see ProcessByQuickFilter being used in implementation, + * see sharpen.cpp + * + * @ingroup HighLevelCubeIO + * + * @author 2003-03-31 Jeff Anderson + * + * @internal + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-06-02 Jeff Anderson - Fixed a bug where line unfolding at + * the bottom of the cube was always + * using band 1 + * @history 2003-08-28 Jeff Anderson - Added SetFilterParameters method + * @history 2005-02-08 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2006-12-15 Jeff Anderson - Fixed bug for images with 1 line + */ + class ProcessByQuickFilter : public Isis::Process { + + public: + ProcessByQuickFilter (); + + void StartProcess (void funct(Isis::Buffer &in, Isis::Buffer &out, Isis::QuickFilter &filter)); + void SetFilterParameters(int samples, int lines, + double low=-DBL_MAX, double high=DBL_MAX, + int minimum=0); + + private: + bool p_getParametersFromUser; /** + +using namespace std; +void filter (Isis::Buffer &in, Isis::Buffer &out, Isis::QuickFilter &filt); + +void IsisMain() { + + Isis::Preference::Preferences(true); + + cout << "Testing Isis::ProcessByQuickFilter Class ... " << endl; + Isis::ProcessByQuickFilter p; + + // Testing no input cubes + try { + p.StartProcess (filter); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + // Testing no output cubes + try { + p.SetInputCube("FROM"); + p.StartProcess (filter); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + // Testing mismatched samples + try { + p.SetInputCube("FROM"); + p.SetOutputCube("TO",1,1,1); + p.StartProcess (filter); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + // Testing mismatched lines + try { + p.SetInputCube("FROM"); + p.SetOutputCube("TO",1,126,1); + p.StartProcess (filter); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + // Testing mismatched bands + try { + p.SetInputCube("FROM"); + p.SetOutputCube("TO",126,126,1); + p.StartProcess (filter); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + // Testing boxcar size too big + Isis::ProcessByQuickFilter p2; + Isis::Cube temp; + temp.SetDimensions(3,3,1); + temp.Create("/tmp/isisfilterprocess_01"); + temp.Close(); + try { + Isis::CubeAttributeInput att; + p2.SetInputCube("/tmp/isisfilterprocess_01",att); + p2.SetOutputCube("TO"); + p2.StartProcess (filter); + } + catch (Isis::iException &e) { + e.Report(false); + p2.EndProcess(); + cout << endl; + } + + // Testing boxcar size too big + Isis::ProcessByQuickFilter p3; + temp.SetDimensions(2,10,1); + temp.Create("/tmp/isisfilterprocess_01"); + temp.Close(); + try { + Isis::CubeAttributeInput att; + p3.SetInputCube("/tmp/isisfilterprocess_01",att); + p3.SetOutputCube("TO"); + p3.StartProcess (filter); + } + catch (Isis::iException &e) { + e.Report(false); + p3.EndProcess(); + cout << endl; + } + + // Test something normal + Isis::ProcessByQuickFilter p4; + p4.SetInputCube("FROM"); + p4.SetOutputCube("TO"); + p4.StartProcess (filter); + p4.EndProcess(); + cout << endl; + + // Test something normal + Isis::ProcessByQuickFilter p5; + p4.SetInputCube("FROM"); + p4.SetOutputCube("TO"); + p4.SetFilterParameters(9,9); + p4.StartProcess (filter); + p4.EndProcess(); + + temp.Open("/tmp/isisfilterprocess_01"); + temp.Close(true); + temp.Open("/tmp/isisfilterprocess_02"); + temp.Close(true); +} + +void filter (Isis::Buffer &in, Isis::Buffer &out, Isis::QuickFilter &filt) { + if (in.Line()==1&&in.Band()==1) { + cout << endl; + cout << "Boxcar width: " << filt.Width() << endl; + cout << "Boxcar height: " << filt.Height() << endl; + cout << "Low: " << filt.Low() << endl; + cout << "High: " << filt.High() << endl; + cout << "Minimum: " << filt.MinimumPixels() << endl; + cout << "Samples: " << filt.Samples() << endl; + cout << endl; + } + cout << "Working on line: " << in.Line() << endl; +} diff --git a/isis/src/base/objs/ProcessByQuickFilter/unitTest.xml b/isis/src/base/objs/ProcessByQuickFilter/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..dd7436f9cd7a2b661d21d48b7ac815be6165d81c --- /dev/null +++ b/isis/src/base/objs/ProcessByQuickFilter/unitTest.xml @@ -0,0 +1,153 @@ + + + + Unit test for IsisFilterProcess class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + Modified schema from astrogeology... isis.astrogeology... + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisfilterprocess_02.cub + + + + + + integer + 5 + + Number of samples in boxcar + + + + This is the total number of samples in the boxcar. + It must be odd and can not exceed twice the number of samples + in the cube. In general, the size of the boxcar does not + cause the program to operate significantly slower. + + + + + 1 + + + + integer + 7 + + Number of lines in boxcar + + + + This is the total number of lines in the boxcar. + It must be odd and can not exceed twice the number of lines + in the cube. In general, the size of the boxcar does not + cause the program to operate significantly + slower. + + + + + 1 + + + + + + double + + Valid minimum pixel + + + Valid minimum pixel value that will be used in boxcar computation. If + a pixel value is less than LOW then it will not be used when + computing boxcar statistics. + + + Use all pixels + + + HIGH + + 0.0 + + + + double + + Valid maximum pixel + + + Valid maximum pixel value that will be used in boxcar computation. If + a pixel value is greater than HIGH then it will not be used when + computing boxcar statistics. + + + Use all pixels + + + LOW + + 300.0 + + + + integer + + Minimum boxcar pixel count + + + This is the minimum number of valid pixels which must occur inside the + NxM boxcar for filtering to occur. For example, 3x5 boxcar has 15 pixels + inside. If MINIMUM=10 then the filter will occur if there are 10 or + greater valid pixels. A valid pixel is one that is not special (NULL, LIS, + etc) and is in the range defined by LOW to HIGH. + + 3 + 1 + + + + diff --git a/isis/src/base/objs/ProcessBySample/Makefile b/isis/src/base/objs/ProcessBySample/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1ed0b7fe52a462d60d07f71cefe28413a910a1ab --- /dev/null +++ b/isis/src/base/objs/ProcessBySample/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessBySample.h +SRCS = ProcessBySample.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessBySample/ProcessBySample.cpp b/isis/src/base/objs/ProcessBySample/ProcessBySample.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4bf2877747a62a71a6de535b68648d8a3d49ca29 --- /dev/null +++ b/isis/src/base/objs/ProcessBySample/ProcessBySample.cpp @@ -0,0 +1,180 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/05/14 21:07:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +#include "ProcessBySample.h" + +using namespace std; +namespace Isis { + /** + * Opens an input cube specified by the user and verifies requirements are met. + * This method is overloaded and adds the requirements of ic_base::SpatialMatch + * which requires all input cubes to have the same number of samples and lines. + * It also added the requirement ic_base::BandMatchOrOne which forces 2nd, 3rd, + * 4th, etc input cubes to match the number of bands in the 1st input cube + * or to have exactly one band. For more information see Process::SetInputCube + * + * @return Cube* + * + * @param parameter User parameter to obtain file to open. Typically, the value + * is "FROM". For example, the user can specify on the command + * line FROM=myfile.cub and this method will attempt to open + * the cube "myfile.cub" if the parameter was set to "FROM". + * + * @param requirements See Process::SetInputCube for more information. + * Defaults to 0 + * + * @throws Isis::iException::Message + */ + Isis::Cube* ProcessBySample::SetInputCube (const std::string ¶meter, + const int requirements) { + int allRequirements = Isis::SpatialMatch | Isis::BandMatchOrOne; + allRequirements |= requirements; + return Isis::Process::SetInputCube (parameter,allRequirements); + } + + + Isis::Cube* ProcessBySample::SetInputCube (const std::string &file, + Isis::CubeAttributeInput &att, + const int requirements) { + int allRequirements = Isis::SpatialMatch | Isis::BandMatchOrOne; + allRequirements |= requirements; + return Isis::Process::SetInputCube (file,att,allRequirements); + } + + /** + * This method invokes the process by sample operation over a single input or + * output cube. It will be an input cube if the method SetInputCube was invoked + * exactly one time before calling StartProcess. It will be an output cube if + * the SetOutputCube method was invoked exactly one time. Typically this method + * can be used to obtain statistics, histograms, or other information from + * an input cube. + * + * @param funct (Isis::Buffer &b) Name of your processing function + * + * @throws Isis::iException::Message + * + */ + void ProcessBySample::StartProcess (void funct(Isis::Buffer &inout)) { + // Error checks + if ((InputCubes.size() + OutputCubes.size()) > 1) { + string m = "You can only specify exactly one input or output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + else if ((InputCubes.size() + OutputCubes.size()) == 0) { + string m = "You haven't specified an input or output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Determine if we have an input or output + if (InputCubes.size() == 1) SetBrickSize(1, InputCubes[0]->Lines(), 1); + else SetBrickSize(1, OutputCubes[0]->Lines(), 1); + + Isis::ProcessByBrick::StartProcess(funct); + } + + /** + * This method invokes the process by sample operation over exactly one input and + * one output cube. Typically, this method is used for simple operations such + * as stretching a cube or applying various operators to a cube (add constant, + * multiply by constant, etc). + * + * @param funct (Isis::Buffer &in, Isis::Buffer &out) Name of your processing + * function + * + * @throws Isis::iException::Message + */ + void ProcessBySample::StartProcess (void + funct(Isis::Buffer &in, Isis::Buffer &out)) { + // Error checks ... there must be one input and output + if (InputCubes.size() != 1) { + string m = "You must specify exactly one input cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + else if (OutputCubes.size() != 1) { + string m = "You must specify exactly one output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // The samples in the input and output must match + if (InputCubes[0]->Samples() != OutputCubes[0]->Samples()) { + string m = "The number of samples in the input and output cubes "; + m += "must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // The bands in the input and output must match + if (InputCubes[0]->Bands() != OutputCubes[0]->Bands()) { + string m = "The number of bands in the input and output cubes "; + m += "must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + SetInputBrickSize(1, InputCubes[0]->Lines(), 1); + SetOutputBrickSize(1, OutputCubes[0]->Lines(), 1); + + Isis::ProcessByBrick::StartProcess(funct); + } + + /** + * This method invokes the process by sample operation over multiple input and + * output cubes. Typically, this method is used when two input cubes are + * required for operations like ratios, differences, masking, etc. + * + * @param funct (vector &in, vector &out) Name + * of your processing function + * + * @throws Isis::iException::Message + */ + void ProcessBySample::StartProcess (void funct(std::vector &in, + std::vector &out)) { + // Make sure we had an image + if (InputCubes.size()+OutputCubes.size() < 1) { + string m = "You have not specified any input or output cubes"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Make sure all the output images have the same number of bands as + // the first input/output cube + for (unsigned int i=0; iSamples() != OutputCubes[0]->Samples()) { + string m = "All output cubes must have the same number of samples "; + m += "as the first input cube or output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + if (OutputCubes[i]->Bands() != OutputCubes[0]->Bands()) { + string m = "All output cubes must have the same number of bands "; + m += "as the first input cube or output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + } + + for (unsigned int i=0; iLines(), 1, i+1); + } + for (unsigned int i=0; iLines(), 1, i+1); + } + + Isis::ProcessByBrick::StartProcess(funct); + } +} diff --git a/isis/src/base/objs/ProcessBySample/ProcessBySample.h b/isis/src/base/objs/ProcessBySample/ProcessBySample.h new file mode 100644 index 0000000000000000000000000000000000000000..39b411735cc4b70d60e865f143bbc6be7f839fe7 --- /dev/null +++ b/isis/src/base/objs/ProcessBySample/ProcessBySample.h @@ -0,0 +1,68 @@ +#ifndef ProcessBySample_h +#define ProcessBySample_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/05/14 21:07:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "ProcessByBrick.h" +#include "Buffer.h" + +namespace Isis { + /** + * @brief Process cubes by sample + * + * This class allows a programmer to develop a program which process input and + * output cubes sequentially by sample. That is, receive the input data for sample + * one, manipulate the data, and pass back the data for output sample one. Then + * proceed to the sample two and so one. This class is derived from the Process + * class which give many functions for setting up input and output cubes. + * + * + * @ingroup HighLevelCubeIO + * + * @author 2006-03-27 Jacob Danton + * + * @internal + * @history 2006-03-27 Jacob Danton - Original Version + */ + class ProcessBySample : public Isis::ProcessByBrick { + + public: + ProcessBySample():ProcessByBrick(){ + SetWrap(true); + }; + + Isis::Cube* SetInputCube (const std::string ¶meter, + const int requirements=0); + Isis::Cube* SetInputCube (const std::string &file, + Isis::CubeAttributeInput &att, + const int requirements=0); + + void StartProcess (void funct(Isis::Buffer &inout)); + + void StartProcess (void funct(Isis::Buffer &in, Isis::Buffer &out)); + + void StartProcess (void funct(std::vector &in, + std::vector &out)); + }; +}; + +#endif diff --git a/isis/src/base/objs/ProcessBySample/ProcessBySample.truth b/isis/src/base/objs/ProcessBySample/ProcessBySample.truth new file mode 100644 index 0000000000000000000000000000000000000000..83409b6abf06cdb692b005d585f8ed3e0e9c6c1c --- /dev/null +++ b/isis/src/base/objs/ProcessBySample/ProcessBySample.truth @@ -0,0 +1,816 @@ +Testing Isis::ProcessBySample Class ... +unittest: Working +0% Processed Testing one input cube ... +Buffer Samples: 1 +Buffer Lines: 126 +Buffer Bands: 1 + +Sample: 1 Line: 1 Band: 1 +Sample: 2 Line: 1 Band: 1 +Sample: 3 Line: 1 Band: 1 +Sample: 4 Line: 1 Band: 1 +Sample: 5 Line: 1 Band: 1 +Sample: 6 Line: 1 Band: 1 +Sample: 7 Line: 1 Band: 1 +Sample: 8 Line: 1 Band: 1 +Sample: 9 Line: 1 Band: 1 +Sample: 10 Line: 1 Band: 1 +Sample: 11 Line: 1 Band: 1 +Sample: 12 Line: 1 Band: 1 +Sample: 13 Line: 1 Band: 1 +Sample: 14 Line: 1 Band: 1 +Sample: 15 Line: 1 Band: 1 +Sample: 16 Line: 1 Band: 1 +Sample: 17 Line: 1 Band: 1 +Sample: 18 Line: 1 Band: 1 +Sample: 19 Line: 1 Band: 1 +Sample: 20 Line: 1 Band: 1 +Sample: 21 Line: 1 Band: 1 +Sample: 22 Line: 1 Band: 1 +Sample: 23 Line: 1 Band: 1 +Sample: 24 Line: 1 Band: 1 +Sample: 25 Line: 1 Band: 1 +Sample: 26 Line: 1 Band: 1 +10% Processed Sample: 27 Line: 1 Band: 1 +Sample: 28 Line: 1 Band: 1 +Sample: 29 Line: 1 Band: 1 +Sample: 30 Line: 1 Band: 1 +Sample: 31 Line: 1 Band: 1 +Sample: 32 Line: 1 Band: 1 +Sample: 33 Line: 1 Band: 1 +Sample: 34 Line: 1 Band: 1 +Sample: 35 Line: 1 Band: 1 +Sample: 36 Line: 1 Band: 1 +Sample: 37 Line: 1 Band: 1 +Sample: 38 Line: 1 Band: 1 +Sample: 39 Line: 1 Band: 1 +Sample: 40 Line: 1 Band: 1 +Sample: 41 Line: 1 Band: 1 +Sample: 42 Line: 1 Band: 1 +Sample: 43 Line: 1 Band: 1 +Sample: 44 Line: 1 Band: 1 +Sample: 45 Line: 1 Band: 1 +Sample: 46 Line: 1 Band: 1 +Sample: 47 Line: 1 Band: 1 +Sample: 48 Line: 1 Band: 1 +Sample: 49 Line: 1 Band: 1 +Sample: 50 Line: 1 Band: 1 +Sample: 51 Line: 1 Band: 1 +20% Processed Sample: 52 Line: 1 Band: 1 +Sample: 53 Line: 1 Band: 1 +Sample: 54 Line: 1 Band: 1 +Sample: 55 Line: 1 Band: 1 +Sample: 56 Line: 1 Band: 1 +Sample: 57 Line: 1 Band: 1 +Sample: 58 Line: 1 Band: 1 +Sample: 59 Line: 1 Band: 1 +Sample: 60 Line: 1 Band: 1 +Sample: 61 Line: 1 Band: 1 +Sample: 62 Line: 1 Band: 1 +Sample: 63 Line: 1 Band: 1 +Sample: 64 Line: 1 Band: 1 +Sample: 65 Line: 1 Band: 1 +Sample: 66 Line: 1 Band: 1 +Sample: 67 Line: 1 Band: 1 +Sample: 68 Line: 1 Band: 1 +Sample: 69 Line: 1 Band: 1 +Sample: 70 Line: 1 Band: 1 +Sample: 71 Line: 1 Band: 1 +Sample: 72 Line: 1 Band: 1 +Sample: 73 Line: 1 Band: 1 +Sample: 74 Line: 1 Band: 1 +Sample: 75 Line: 1 Band: 1 +Sample: 76 Line: 1 Band: 1 +30% Processed Sample: 77 Line: 1 Band: 1 +Sample: 78 Line: 1 Band: 1 +Sample: 79 Line: 1 Band: 1 +Sample: 80 Line: 1 Band: 1 +Sample: 81 Line: 1 Band: 1 +Sample: 82 Line: 1 Band: 1 +Sample: 83 Line: 1 Band: 1 +Sample: 84 Line: 1 Band: 1 +Sample: 85 Line: 1 Band: 1 +Sample: 86 Line: 1 Band: 1 +Sample: 87 Line: 1 Band: 1 +Sample: 88 Line: 1 Band: 1 +Sample: 89 Line: 1 Band: 1 +Sample: 90 Line: 1 Band: 1 +Sample: 91 Line: 1 Band: 1 +Sample: 92 Line: 1 Band: 1 +Sample: 93 Line: 1 Band: 1 +Sample: 94 Line: 1 Band: 1 +Sample: 95 Line: 1 Band: 1 +Sample: 96 Line: 1 Band: 1 +Sample: 97 Line: 1 Band: 1 +Sample: 98 Line: 1 Band: 1 +Sample: 99 Line: 1 Band: 1 +Sample: 100 Line: 1 Band: 1 +Sample: 101 Line: 1 Band: 1 +40% Processed Sample: 102 Line: 1 Band: 1 +Sample: 103 Line: 1 Band: 1 +Sample: 104 Line: 1 Band: 1 +Sample: 105 Line: 1 Band: 1 +Sample: 106 Line: 1 Band: 1 +Sample: 107 Line: 1 Band: 1 +Sample: 108 Line: 1 Band: 1 +Sample: 109 Line: 1 Band: 1 +Sample: 110 Line: 1 Band: 1 +Sample: 111 Line: 1 Band: 1 +Sample: 112 Line: 1 Band: 1 +Sample: 113 Line: 1 Band: 1 +Sample: 114 Line: 1 Band: 1 +Sample: 115 Line: 1 Band: 1 +Sample: 116 Line: 1 Band: 1 +Sample: 117 Line: 1 Band: 1 +Sample: 118 Line: 1 Band: 1 +Sample: 119 Line: 1 Band: 1 +Sample: 120 Line: 1 Band: 1 +Sample: 121 Line: 1 Band: 1 +Sample: 122 Line: 1 Band: 1 +Sample: 123 Line: 1 Band: 1 +Sample: 124 Line: 1 Band: 1 +Sample: 125 Line: 1 Band: 1 +Sample: 126 Line: 1 Band: 1 +50% Processed Sample: 1 Line: 1 Band: 2 +Sample: 2 Line: 1 Band: 2 +Sample: 3 Line: 1 Band: 2 +Sample: 4 Line: 1 Band: 2 +Sample: 5 Line: 1 Band: 2 +Sample: 6 Line: 1 Band: 2 +Sample: 7 Line: 1 Band: 2 +Sample: 8 Line: 1 Band: 2 +Sample: 9 Line: 1 Band: 2 +Sample: 10 Line: 1 Band: 2 +Sample: 11 Line: 1 Band: 2 +Sample: 12 Line: 1 Band: 2 +Sample: 13 Line: 1 Band: 2 +Sample: 14 Line: 1 Band: 2 +Sample: 15 Line: 1 Band: 2 +Sample: 16 Line: 1 Band: 2 +Sample: 17 Line: 1 Band: 2 +Sample: 18 Line: 1 Band: 2 +Sample: 19 Line: 1 Band: 2 +Sample: 20 Line: 1 Band: 2 +Sample: 21 Line: 1 Band: 2 +Sample: 22 Line: 1 Band: 2 +Sample: 23 Line: 1 Band: 2 +Sample: 24 Line: 1 Band: 2 +Sample: 25 Line: 1 Band: 2 +Sample: 26 Line: 1 Band: 2 +60% Processed Sample: 27 Line: 1 Band: 2 +Sample: 28 Line: 1 Band: 2 +Sample: 29 Line: 1 Band: 2 +Sample: 30 Line: 1 Band: 2 +Sample: 31 Line: 1 Band: 2 +Sample: 32 Line: 1 Band: 2 +Sample: 33 Line: 1 Band: 2 +Sample: 34 Line: 1 Band: 2 +Sample: 35 Line: 1 Band: 2 +Sample: 36 Line: 1 Band: 2 +Sample: 37 Line: 1 Band: 2 +Sample: 38 Line: 1 Band: 2 +Sample: 39 Line: 1 Band: 2 +Sample: 40 Line: 1 Band: 2 +Sample: 41 Line: 1 Band: 2 +Sample: 42 Line: 1 Band: 2 +Sample: 43 Line: 1 Band: 2 +Sample: 44 Line: 1 Band: 2 +Sample: 45 Line: 1 Band: 2 +Sample: 46 Line: 1 Band: 2 +Sample: 47 Line: 1 Band: 2 +Sample: 48 Line: 1 Band: 2 +Sample: 49 Line: 1 Band: 2 +Sample: 50 Line: 1 Band: 2 +Sample: 51 Line: 1 Band: 2 +70% Processed Sample: 52 Line: 1 Band: 2 +Sample: 53 Line: 1 Band: 2 +Sample: 54 Line: 1 Band: 2 +Sample: 55 Line: 1 Band: 2 +Sample: 56 Line: 1 Band: 2 +Sample: 57 Line: 1 Band: 2 +Sample: 58 Line: 1 Band: 2 +Sample: 59 Line: 1 Band: 2 +Sample: 60 Line: 1 Band: 2 +Sample: 61 Line: 1 Band: 2 +Sample: 62 Line: 1 Band: 2 +Sample: 63 Line: 1 Band: 2 +Sample: 64 Line: 1 Band: 2 +Sample: 65 Line: 1 Band: 2 +Sample: 66 Line: 1 Band: 2 +Sample: 67 Line: 1 Band: 2 +Sample: 68 Line: 1 Band: 2 +Sample: 69 Line: 1 Band: 2 +Sample: 70 Line: 1 Band: 2 +Sample: 71 Line: 1 Band: 2 +Sample: 72 Line: 1 Band: 2 +Sample: 73 Line: 1 Band: 2 +Sample: 74 Line: 1 Band: 2 +Sample: 75 Line: 1 Band: 2 +Sample: 76 Line: 1 Band: 2 +80% Processed Sample: 77 Line: 1 Band: 2 +Sample: 78 Line: 1 Band: 2 +Sample: 79 Line: 1 Band: 2 +Sample: 80 Line: 1 Band: 2 +Sample: 81 Line: 1 Band: 2 +Sample: 82 Line: 1 Band: 2 +Sample: 83 Line: 1 Band: 2 +Sample: 84 Line: 1 Band: 2 +Sample: 85 Line: 1 Band: 2 +Sample: 86 Line: 1 Band: 2 +Sample: 87 Line: 1 Band: 2 +Sample: 88 Line: 1 Band: 2 +Sample: 89 Line: 1 Band: 2 +Sample: 90 Line: 1 Band: 2 +Sample: 91 Line: 1 Band: 2 +Sample: 92 Line: 1 Band: 2 +Sample: 93 Line: 1 Band: 2 +Sample: 94 Line: 1 Band: 2 +Sample: 95 Line: 1 Band: 2 +Sample: 96 Line: 1 Band: 2 +Sample: 97 Line: 1 Band: 2 +Sample: 98 Line: 1 Band: 2 +Sample: 99 Line: 1 Band: 2 +Sample: 100 Line: 1 Band: 2 +Sample: 101 Line: 1 Band: 2 +90% Processed Sample: 102 Line: 1 Band: 2 +Sample: 103 Line: 1 Band: 2 +Sample: 104 Line: 1 Band: 2 +Sample: 105 Line: 1 Band: 2 +Sample: 106 Line: 1 Band: 2 +Sample: 107 Line: 1 Band: 2 +Sample: 108 Line: 1 Band: 2 +Sample: 109 Line: 1 Band: 2 +Sample: 110 Line: 1 Band: 2 +Sample: 111 Line: 1 Band: 2 +Sample: 112 Line: 1 Band: 2 +Sample: 113 Line: 1 Band: 2 +Sample: 114 Line: 1 Band: 2 +Sample: 115 Line: 1 Band: 2 +Sample: 116 Line: 1 Band: 2 +Sample: 117 Line: 1 Band: 2 +Sample: 118 Line: 1 Band: 2 +Sample: 119 Line: 1 Band: 2 +Sample: 120 Line: 1 Band: 2 +Sample: 121 Line: 1 Band: 2 +Sample: 122 Line: 1 Band: 2 +Sample: 123 Line: 1 Band: 2 +Sample: 124 Line: 1 Band: 2 +Sample: 125 Line: 1 Band: 2 +Sample: 126 Line: 1 Band: 2 +100% Processed +unittest: Working +0% Processed +Testing one output cube ... +Buffer Samples: 1 +Buffer Lines: 20 +Buffer Bands: 1 + +Sample: 1 Line: 1 Band: 1 +Sample: 2 Line: 1 Band: 1 +Sample: 3 Line: 1 Band: 1 +10% Processed Sample: 4 Line: 1 Band: 1 +Sample: 5 Line: 1 Band: 1 +Sample: 6 Line: 1 Band: 1 +20% Processed Sample: 7 Line: 1 Band: 1 +Sample: 8 Line: 1 Band: 1 +Sample: 9 Line: 1 Band: 1 +30% Processed Sample: 10 Line: 1 Band: 1 +Sample: 1 Line: 1 Band: 2 +Sample: 2 Line: 1 Band: 2 +40% Processed Sample: 3 Line: 1 Band: 2 +Sample: 4 Line: 1 Band: 2 +Sample: 5 Line: 1 Band: 2 +50% Processed Sample: 6 Line: 1 Band: 2 +Sample: 7 Line: 1 Band: 2 +Sample: 8 Line: 1 Band: 2 +60% Processed Sample: 9 Line: 1 Band: 2 +Sample: 10 Line: 1 Band: 2 +Sample: 1 Line: 1 Band: 3 +70% Processed Sample: 2 Line: 1 Band: 3 +Sample: 3 Line: 1 Band: 3 +Sample: 4 Line: 1 Band: 3 +80% Processed Sample: 5 Line: 1 Band: 3 +Sample: 6 Line: 1 Band: 3 +Sample: 7 Line: 1 Band: 3 +90% Processed Sample: 8 Line: 1 Band: 3 +Sample: 9 Line: 1 Band: 3 +Sample: 10 Line: 1 Band: 3 +100% Processed +unittest: Working +0% Processed +Testing one input and output cube ... +Buffer Samples: 1 +Buffer Lines: 126 +Buffer Bands: 1 + +Sample: 1 Line: 1 Band: 1 +Sample: 2 Line: 1 Band: 1 +Sample: 3 Line: 1 Band: 1 +Sample: 4 Line: 1 Band: 1 +Sample: 5 Line: 1 Band: 1 +Sample: 6 Line: 1 Band: 1 +Sample: 7 Line: 1 Band: 1 +Sample: 8 Line: 1 Band: 1 +Sample: 9 Line: 1 Band: 1 +Sample: 10 Line: 1 Band: 1 +Sample: 11 Line: 1 Band: 1 +Sample: 12 Line: 1 Band: 1 +Sample: 13 Line: 1 Band: 1 +Sample: 14 Line: 1 Band: 1 +Sample: 15 Line: 1 Band: 1 +Sample: 16 Line: 1 Band: 1 +Sample: 17 Line: 1 Band: 1 +Sample: 18 Line: 1 Band: 1 +Sample: 19 Line: 1 Band: 1 +Sample: 20 Line: 1 Band: 1 +Sample: 21 Line: 1 Band: 1 +Sample: 22 Line: 1 Band: 1 +Sample: 23 Line: 1 Band: 1 +Sample: 24 Line: 1 Band: 1 +Sample: 25 Line: 1 Band: 1 +Sample: 26 Line: 1 Band: 1 +10% Processed Sample: 27 Line: 1 Band: 1 +Sample: 28 Line: 1 Band: 1 +Sample: 29 Line: 1 Band: 1 +Sample: 30 Line: 1 Band: 1 +Sample: 31 Line: 1 Band: 1 +Sample: 32 Line: 1 Band: 1 +Sample: 33 Line: 1 Band: 1 +Sample: 34 Line: 1 Band: 1 +Sample: 35 Line: 1 Band: 1 +Sample: 36 Line: 1 Band: 1 +Sample: 37 Line: 1 Band: 1 +Sample: 38 Line: 1 Band: 1 +Sample: 39 Line: 1 Band: 1 +Sample: 40 Line: 1 Band: 1 +Sample: 41 Line: 1 Band: 1 +Sample: 42 Line: 1 Band: 1 +Sample: 43 Line: 1 Band: 1 +Sample: 44 Line: 1 Band: 1 +Sample: 45 Line: 1 Band: 1 +Sample: 46 Line: 1 Band: 1 +Sample: 47 Line: 1 Band: 1 +Sample: 48 Line: 1 Band: 1 +Sample: 49 Line: 1 Band: 1 +Sample: 50 Line: 1 Band: 1 +Sample: 51 Line: 1 Band: 1 +20% Processed Sample: 52 Line: 1 Band: 1 +Sample: 53 Line: 1 Band: 1 +Sample: 54 Line: 1 Band: 1 +Sample: 55 Line: 1 Band: 1 +Sample: 56 Line: 1 Band: 1 +Sample: 57 Line: 1 Band: 1 +Sample: 58 Line: 1 Band: 1 +Sample: 59 Line: 1 Band: 1 +Sample: 60 Line: 1 Band: 1 +Sample: 61 Line: 1 Band: 1 +Sample: 62 Line: 1 Band: 1 +Sample: 63 Line: 1 Band: 1 +Sample: 64 Line: 1 Band: 1 +Sample: 65 Line: 1 Band: 1 +Sample: 66 Line: 1 Band: 1 +Sample: 67 Line: 1 Band: 1 +Sample: 68 Line: 1 Band: 1 +Sample: 69 Line: 1 Band: 1 +Sample: 70 Line: 1 Band: 1 +Sample: 71 Line: 1 Band: 1 +Sample: 72 Line: 1 Band: 1 +Sample: 73 Line: 1 Band: 1 +Sample: 74 Line: 1 Band: 1 +Sample: 75 Line: 1 Band: 1 +Sample: 76 Line: 1 Band: 1 +30% Processed Sample: 77 Line: 1 Band: 1 +Sample: 78 Line: 1 Band: 1 +Sample: 79 Line: 1 Band: 1 +Sample: 80 Line: 1 Band: 1 +Sample: 81 Line: 1 Band: 1 +Sample: 82 Line: 1 Band: 1 +Sample: 83 Line: 1 Band: 1 +Sample: 84 Line: 1 Band: 1 +Sample: 85 Line: 1 Band: 1 +Sample: 86 Line: 1 Band: 1 +Sample: 87 Line: 1 Band: 1 +Sample: 88 Line: 1 Band: 1 +Sample: 89 Line: 1 Band: 1 +Sample: 90 Line: 1 Band: 1 +Sample: 91 Line: 1 Band: 1 +Sample: 92 Line: 1 Band: 1 +Sample: 93 Line: 1 Band: 1 +Sample: 94 Line: 1 Band: 1 +Sample: 95 Line: 1 Band: 1 +Sample: 96 Line: 1 Band: 1 +Sample: 97 Line: 1 Band: 1 +Sample: 98 Line: 1 Band: 1 +Sample: 99 Line: 1 Band: 1 +Sample: 100 Line: 1 Band: 1 +Sample: 101 Line: 1 Band: 1 +40% Processed Sample: 102 Line: 1 Band: 1 +Sample: 103 Line: 1 Band: 1 +Sample: 104 Line: 1 Band: 1 +Sample: 105 Line: 1 Band: 1 +Sample: 106 Line: 1 Band: 1 +Sample: 107 Line: 1 Band: 1 +Sample: 108 Line: 1 Band: 1 +Sample: 109 Line: 1 Band: 1 +Sample: 110 Line: 1 Band: 1 +Sample: 111 Line: 1 Band: 1 +Sample: 112 Line: 1 Band: 1 +Sample: 113 Line: 1 Band: 1 +Sample: 114 Line: 1 Band: 1 +Sample: 115 Line: 1 Band: 1 +Sample: 116 Line: 1 Band: 1 +Sample: 117 Line: 1 Band: 1 +Sample: 118 Line: 1 Band: 1 +Sample: 119 Line: 1 Band: 1 +Sample: 120 Line: 1 Band: 1 +Sample: 121 Line: 1 Band: 1 +Sample: 122 Line: 1 Band: 1 +Sample: 123 Line: 1 Band: 1 +Sample: 124 Line: 1 Band: 1 +Sample: 125 Line: 1 Band: 1 +Sample: 126 Line: 1 Band: 1 +50% Processed Sample: 1 Line: 1 Band: 2 +Sample: 2 Line: 1 Band: 2 +Sample: 3 Line: 1 Band: 2 +Sample: 4 Line: 1 Band: 2 +Sample: 5 Line: 1 Band: 2 +Sample: 6 Line: 1 Band: 2 +Sample: 7 Line: 1 Band: 2 +Sample: 8 Line: 1 Band: 2 +Sample: 9 Line: 1 Band: 2 +Sample: 10 Line: 1 Band: 2 +Sample: 11 Line: 1 Band: 2 +Sample: 12 Line: 1 Band: 2 +Sample: 13 Line: 1 Band: 2 +Sample: 14 Line: 1 Band: 2 +Sample: 15 Line: 1 Band: 2 +Sample: 16 Line: 1 Band: 2 +Sample: 17 Line: 1 Band: 2 +Sample: 18 Line: 1 Band: 2 +Sample: 19 Line: 1 Band: 2 +Sample: 20 Line: 1 Band: 2 +Sample: 21 Line: 1 Band: 2 +Sample: 22 Line: 1 Band: 2 +Sample: 23 Line: 1 Band: 2 +Sample: 24 Line: 1 Band: 2 +Sample: 25 Line: 1 Band: 2 +Sample: 26 Line: 1 Band: 2 +60% Processed Sample: 27 Line: 1 Band: 2 +Sample: 28 Line: 1 Band: 2 +Sample: 29 Line: 1 Band: 2 +Sample: 30 Line: 1 Band: 2 +Sample: 31 Line: 1 Band: 2 +Sample: 32 Line: 1 Band: 2 +Sample: 33 Line: 1 Band: 2 +Sample: 34 Line: 1 Band: 2 +Sample: 35 Line: 1 Band: 2 +Sample: 36 Line: 1 Band: 2 +Sample: 37 Line: 1 Band: 2 +Sample: 38 Line: 1 Band: 2 +Sample: 39 Line: 1 Band: 2 +Sample: 40 Line: 1 Band: 2 +Sample: 41 Line: 1 Band: 2 +Sample: 42 Line: 1 Band: 2 +Sample: 43 Line: 1 Band: 2 +Sample: 44 Line: 1 Band: 2 +Sample: 45 Line: 1 Band: 2 +Sample: 46 Line: 1 Band: 2 +Sample: 47 Line: 1 Band: 2 +Sample: 48 Line: 1 Band: 2 +Sample: 49 Line: 1 Band: 2 +Sample: 50 Line: 1 Band: 2 +Sample: 51 Line: 1 Band: 2 +70% Processed Sample: 52 Line: 1 Band: 2 +Sample: 53 Line: 1 Band: 2 +Sample: 54 Line: 1 Band: 2 +Sample: 55 Line: 1 Band: 2 +Sample: 56 Line: 1 Band: 2 +Sample: 57 Line: 1 Band: 2 +Sample: 58 Line: 1 Band: 2 +Sample: 59 Line: 1 Band: 2 +Sample: 60 Line: 1 Band: 2 +Sample: 61 Line: 1 Band: 2 +Sample: 62 Line: 1 Band: 2 +Sample: 63 Line: 1 Band: 2 +Sample: 64 Line: 1 Band: 2 +Sample: 65 Line: 1 Band: 2 +Sample: 66 Line: 1 Band: 2 +Sample: 67 Line: 1 Band: 2 +Sample: 68 Line: 1 Band: 2 +Sample: 69 Line: 1 Band: 2 +Sample: 70 Line: 1 Band: 2 +Sample: 71 Line: 1 Band: 2 +Sample: 72 Line: 1 Band: 2 +Sample: 73 Line: 1 Band: 2 +Sample: 74 Line: 1 Band: 2 +Sample: 75 Line: 1 Band: 2 +Sample: 76 Line: 1 Band: 2 +80% Processed Sample: 77 Line: 1 Band: 2 +Sample: 78 Line: 1 Band: 2 +Sample: 79 Line: 1 Band: 2 +Sample: 80 Line: 1 Band: 2 +Sample: 81 Line: 1 Band: 2 +Sample: 82 Line: 1 Band: 2 +Sample: 83 Line: 1 Band: 2 +Sample: 84 Line: 1 Band: 2 +Sample: 85 Line: 1 Band: 2 +Sample: 86 Line: 1 Band: 2 +Sample: 87 Line: 1 Band: 2 +Sample: 88 Line: 1 Band: 2 +Sample: 89 Line: 1 Band: 2 +Sample: 90 Line: 1 Band: 2 +Sample: 91 Line: 1 Band: 2 +Sample: 92 Line: 1 Band: 2 +Sample: 93 Line: 1 Band: 2 +Sample: 94 Line: 1 Band: 2 +Sample: 95 Line: 1 Band: 2 +Sample: 96 Line: 1 Band: 2 +Sample: 97 Line: 1 Band: 2 +Sample: 98 Line: 1 Band: 2 +Sample: 99 Line: 1 Band: 2 +Sample: 100 Line: 1 Band: 2 +Sample: 101 Line: 1 Band: 2 +90% Processed Sample: 102 Line: 1 Band: 2 +Sample: 103 Line: 1 Band: 2 +Sample: 104 Line: 1 Band: 2 +Sample: 105 Line: 1 Band: 2 +Sample: 106 Line: 1 Band: 2 +Sample: 107 Line: 1 Band: 2 +Sample: 108 Line: 1 Band: 2 +Sample: 109 Line: 1 Band: 2 +Sample: 110 Line: 1 Band: 2 +Sample: 111 Line: 1 Band: 2 +Sample: 112 Line: 1 Band: 2 +Sample: 113 Line: 1 Band: 2 +Sample: 114 Line: 1 Band: 2 +Sample: 115 Line: 1 Band: 2 +Sample: 116 Line: 1 Band: 2 +Sample: 117 Line: 1 Band: 2 +Sample: 118 Line: 1 Band: 2 +Sample: 119 Line: 1 Band: 2 +Sample: 120 Line: 1 Band: 2 +Sample: 121 Line: 1 Band: 2 +Sample: 122 Line: 1 Band: 2 +Sample: 123 Line: 1 Band: 2 +Sample: 124 Line: 1 Band: 2 +Sample: 125 Line: 1 Band: 2 +Sample: 126 Line: 1 Band: 2 +100% Processed +unittest: Working +0% Processed Testing two input and output cubes ... +Number of input cubes: 2 +Number of output cubes: 2 + +Sample: 1:1 Line: 1:1 Band: 1:1 +Sample: 2:2 Line: 1:1 Band: 1:1 +Sample: 3:3 Line: 1:1 Band: 1:1 +Sample: 4:4 Line: 1:1 Band: 1:1 +Sample: 5:5 Line: 1:1 Band: 1:1 +Sample: 6:6 Line: 1:1 Band: 1:1 +Sample: 7:7 Line: 1:1 Band: 1:1 +Sample: 8:8 Line: 1:1 Band: 1:1 +Sample: 9:9 Line: 1:1 Band: 1:1 +Sample: 10:10 Line: 1:1 Band: 1:1 +Sample: 11:11 Line: 1:1 Band: 1:1 +Sample: 12:12 Line: 1:1 Band: 1:1 +Sample: 13:13 Line: 1:1 Band: 1:1 +Sample: 14:14 Line: 1:1 Band: 1:1 +Sample: 15:15 Line: 1:1 Band: 1:1 +Sample: 16:16 Line: 1:1 Band: 1:1 +Sample: 17:17 Line: 1:1 Band: 1:1 +Sample: 18:18 Line: 1:1 Band: 1:1 +Sample: 19:19 Line: 1:1 Band: 1:1 +Sample: 20:20 Line: 1:1 Band: 1:1 +Sample: 21:21 Line: 1:1 Band: 1:1 +Sample: 22:22 Line: 1:1 Band: 1:1 +Sample: 23:23 Line: 1:1 Band: 1:1 +Sample: 24:24 Line: 1:1 Band: 1:1 +Sample: 25:25 Line: 1:1 Band: 1:1 +Sample: 26:26 Line: 1:1 Band: 1:1 +10% Processed Sample: 27:27 Line: 1:1 Band: 1:1 +Sample: 28:28 Line: 1:1 Band: 1:1 +Sample: 29:29 Line: 1:1 Band: 1:1 +Sample: 30:30 Line: 1:1 Band: 1:1 +Sample: 31:31 Line: 1:1 Band: 1:1 +Sample: 32:32 Line: 1:1 Band: 1:1 +Sample: 33:33 Line: 1:1 Band: 1:1 +Sample: 34:34 Line: 1:1 Band: 1:1 +Sample: 35:35 Line: 1:1 Band: 1:1 +Sample: 36:36 Line: 1:1 Band: 1:1 +Sample: 37:37 Line: 1:1 Band: 1:1 +Sample: 38:38 Line: 1:1 Band: 1:1 +Sample: 39:39 Line: 1:1 Band: 1:1 +Sample: 40:40 Line: 1:1 Band: 1:1 +Sample: 41:41 Line: 1:1 Band: 1:1 +Sample: 42:42 Line: 1:1 Band: 1:1 +Sample: 43:43 Line: 1:1 Band: 1:1 +Sample: 44:44 Line: 1:1 Band: 1:1 +Sample: 45:45 Line: 1:1 Band: 1:1 +Sample: 46:46 Line: 1:1 Band: 1:1 +Sample: 47:47 Line: 1:1 Band: 1:1 +Sample: 48:48 Line: 1:1 Band: 1:1 +Sample: 49:49 Line: 1:1 Band: 1:1 +Sample: 50:50 Line: 1:1 Band: 1:1 +Sample: 51:51 Line: 1:1 Band: 1:1 +20% Processed Sample: 52:52 Line: 1:1 Band: 1:1 +Sample: 53:53 Line: 1:1 Band: 1:1 +Sample: 54:54 Line: 1:1 Band: 1:1 +Sample: 55:55 Line: 1:1 Band: 1:1 +Sample: 56:56 Line: 1:1 Band: 1:1 +Sample: 57:57 Line: 1:1 Band: 1:1 +Sample: 58:58 Line: 1:1 Band: 1:1 +Sample: 59:59 Line: 1:1 Band: 1:1 +Sample: 60:60 Line: 1:1 Band: 1:1 +Sample: 61:61 Line: 1:1 Band: 1:1 +Sample: 62:62 Line: 1:1 Band: 1:1 +Sample: 63:63 Line: 1:1 Band: 1:1 +Sample: 64:64 Line: 1:1 Band: 1:1 +Sample: 65:65 Line: 1:1 Band: 1:1 +Sample: 66:66 Line: 1:1 Band: 1:1 +Sample: 67:67 Line: 1:1 Band: 1:1 +Sample: 68:68 Line: 1:1 Band: 1:1 +Sample: 69:69 Line: 1:1 Band: 1:1 +Sample: 70:70 Line: 1:1 Band: 1:1 +Sample: 71:71 Line: 1:1 Band: 1:1 +Sample: 72:72 Line: 1:1 Band: 1:1 +Sample: 73:73 Line: 1:1 Band: 1:1 +Sample: 74:74 Line: 1:1 Band: 1:1 +Sample: 75:75 Line: 1:1 Band: 1:1 +Sample: 76:76 Line: 1:1 Band: 1:1 +30% Processed Sample: 77:77 Line: 1:1 Band: 1:1 +Sample: 78:78 Line: 1:1 Band: 1:1 +Sample: 79:79 Line: 1:1 Band: 1:1 +Sample: 80:80 Line: 1:1 Band: 1:1 +Sample: 81:81 Line: 1:1 Band: 1:1 +Sample: 82:82 Line: 1:1 Band: 1:1 +Sample: 83:83 Line: 1:1 Band: 1:1 +Sample: 84:84 Line: 1:1 Band: 1:1 +Sample: 85:85 Line: 1:1 Band: 1:1 +Sample: 86:86 Line: 1:1 Band: 1:1 +Sample: 87:87 Line: 1:1 Band: 1:1 +Sample: 88:88 Line: 1:1 Band: 1:1 +Sample: 89:89 Line: 1:1 Band: 1:1 +Sample: 90:90 Line: 1:1 Band: 1:1 +Sample: 91:91 Line: 1:1 Band: 1:1 +Sample: 92:92 Line: 1:1 Band: 1:1 +Sample: 93:93 Line: 1:1 Band: 1:1 +Sample: 94:94 Line: 1:1 Band: 1:1 +Sample: 95:95 Line: 1:1 Band: 1:1 +Sample: 96:96 Line: 1:1 Band: 1:1 +Sample: 97:97 Line: 1:1 Band: 1:1 +Sample: 98:98 Line: 1:1 Band: 1:1 +Sample: 99:99 Line: 1:1 Band: 1:1 +Sample: 100:100 Line: 1:1 Band: 1:1 +Sample: 101:101 Line: 1:1 Band: 1:1 +40% Processed Sample: 102:102 Line: 1:1 Band: 1:1 +Sample: 103:103 Line: 1:1 Band: 1:1 +Sample: 104:104 Line: 1:1 Band: 1:1 +Sample: 105:105 Line: 1:1 Band: 1:1 +Sample: 106:106 Line: 1:1 Band: 1:1 +Sample: 107:107 Line: 1:1 Band: 1:1 +Sample: 108:108 Line: 1:1 Band: 1:1 +Sample: 109:109 Line: 1:1 Band: 1:1 +Sample: 110:110 Line: 1:1 Band: 1:1 +Sample: 111:111 Line: 1:1 Band: 1:1 +Sample: 112:112 Line: 1:1 Band: 1:1 +Sample: 113:113 Line: 1:1 Band: 1:1 +Sample: 114:114 Line: 1:1 Band: 1:1 +Sample: 115:115 Line: 1:1 Band: 1:1 +Sample: 116:116 Line: 1:1 Band: 1:1 +Sample: 117:117 Line: 1:1 Band: 1:1 +Sample: 118:118 Line: 1:1 Band: 1:1 +Sample: 119:119 Line: 1:1 Band: 1:1 +Sample: 120:120 Line: 1:1 Band: 1:1 +Sample: 121:121 Line: 1:1 Band: 1:1 +Sample: 122:122 Line: 1:1 Band: 1:1 +Sample: 123:123 Line: 1:1 Band: 1:1 +Sample: 124:124 Line: 1:1 Band: 1:1 +Sample: 125:125 Line: 1:1 Band: 1:1 +Sample: 126:126 Line: 1:1 Band: 1:1 +50% Processed Sample: 1:1 Line: 1:1 Band: 2:1 +Sample: 2:2 Line: 1:1 Band: 2:1 +Sample: 3:3 Line: 1:1 Band: 2:1 +Sample: 4:4 Line: 1:1 Band: 2:1 +Sample: 5:5 Line: 1:1 Band: 2:1 +Sample: 6:6 Line: 1:1 Band: 2:1 +Sample: 7:7 Line: 1:1 Band: 2:1 +Sample: 8:8 Line: 1:1 Band: 2:1 +Sample: 9:9 Line: 1:1 Band: 2:1 +Sample: 10:10 Line: 1:1 Band: 2:1 +Sample: 11:11 Line: 1:1 Band: 2:1 +Sample: 12:12 Line: 1:1 Band: 2:1 +Sample: 13:13 Line: 1:1 Band: 2:1 +Sample: 14:14 Line: 1:1 Band: 2:1 +Sample: 15:15 Line: 1:1 Band: 2:1 +Sample: 16:16 Line: 1:1 Band: 2:1 +Sample: 17:17 Line: 1:1 Band: 2:1 +Sample: 18:18 Line: 1:1 Band: 2:1 +Sample: 19:19 Line: 1:1 Band: 2:1 +Sample: 20:20 Line: 1:1 Band: 2:1 +Sample: 21:21 Line: 1:1 Band: 2:1 +Sample: 22:22 Line: 1:1 Band: 2:1 +Sample: 23:23 Line: 1:1 Band: 2:1 +Sample: 24:24 Line: 1:1 Band: 2:1 +Sample: 25:25 Line: 1:1 Band: 2:1 +Sample: 26:26 Line: 1:1 Band: 2:1 +60% Processed Sample: 27:27 Line: 1:1 Band: 2:1 +Sample: 28:28 Line: 1:1 Band: 2:1 +Sample: 29:29 Line: 1:1 Band: 2:1 +Sample: 30:30 Line: 1:1 Band: 2:1 +Sample: 31:31 Line: 1:1 Band: 2:1 +Sample: 32:32 Line: 1:1 Band: 2:1 +Sample: 33:33 Line: 1:1 Band: 2:1 +Sample: 34:34 Line: 1:1 Band: 2:1 +Sample: 35:35 Line: 1:1 Band: 2:1 +Sample: 36:36 Line: 1:1 Band: 2:1 +Sample: 37:37 Line: 1:1 Band: 2:1 +Sample: 38:38 Line: 1:1 Band: 2:1 +Sample: 39:39 Line: 1:1 Band: 2:1 +Sample: 40:40 Line: 1:1 Band: 2:1 +Sample: 41:41 Line: 1:1 Band: 2:1 +Sample: 42:42 Line: 1:1 Band: 2:1 +Sample: 43:43 Line: 1:1 Band: 2:1 +Sample: 44:44 Line: 1:1 Band: 2:1 +Sample: 45:45 Line: 1:1 Band: 2:1 +Sample: 46:46 Line: 1:1 Band: 2:1 +Sample: 47:47 Line: 1:1 Band: 2:1 +Sample: 48:48 Line: 1:1 Band: 2:1 +Sample: 49:49 Line: 1:1 Band: 2:1 +Sample: 50:50 Line: 1:1 Band: 2:1 +Sample: 51:51 Line: 1:1 Band: 2:1 +70% Processed Sample: 52:52 Line: 1:1 Band: 2:1 +Sample: 53:53 Line: 1:1 Band: 2:1 +Sample: 54:54 Line: 1:1 Band: 2:1 +Sample: 55:55 Line: 1:1 Band: 2:1 +Sample: 56:56 Line: 1:1 Band: 2:1 +Sample: 57:57 Line: 1:1 Band: 2:1 +Sample: 58:58 Line: 1:1 Band: 2:1 +Sample: 59:59 Line: 1:1 Band: 2:1 +Sample: 60:60 Line: 1:1 Band: 2:1 +Sample: 61:61 Line: 1:1 Band: 2:1 +Sample: 62:62 Line: 1:1 Band: 2:1 +Sample: 63:63 Line: 1:1 Band: 2:1 +Sample: 64:64 Line: 1:1 Band: 2:1 +Sample: 65:65 Line: 1:1 Band: 2:1 +Sample: 66:66 Line: 1:1 Band: 2:1 +Sample: 67:67 Line: 1:1 Band: 2:1 +Sample: 68:68 Line: 1:1 Band: 2:1 +Sample: 69:69 Line: 1:1 Band: 2:1 +Sample: 70:70 Line: 1:1 Band: 2:1 +Sample: 71:71 Line: 1:1 Band: 2:1 +Sample: 72:72 Line: 1:1 Band: 2:1 +Sample: 73:73 Line: 1:1 Band: 2:1 +Sample: 74:74 Line: 1:1 Band: 2:1 +Sample: 75:75 Line: 1:1 Band: 2:1 +Sample: 76:76 Line: 1:1 Band: 2:1 +80% Processed Sample: 77:77 Line: 1:1 Band: 2:1 +Sample: 78:78 Line: 1:1 Band: 2:1 +Sample: 79:79 Line: 1:1 Band: 2:1 +Sample: 80:80 Line: 1:1 Band: 2:1 +Sample: 81:81 Line: 1:1 Band: 2:1 +Sample: 82:82 Line: 1:1 Band: 2:1 +Sample: 83:83 Line: 1:1 Band: 2:1 +Sample: 84:84 Line: 1:1 Band: 2:1 +Sample: 85:85 Line: 1:1 Band: 2:1 +Sample: 86:86 Line: 1:1 Band: 2:1 +Sample: 87:87 Line: 1:1 Band: 2:1 +Sample: 88:88 Line: 1:1 Band: 2:1 +Sample: 89:89 Line: 1:1 Band: 2:1 +Sample: 90:90 Line: 1:1 Band: 2:1 +Sample: 91:91 Line: 1:1 Band: 2:1 +Sample: 92:92 Line: 1:1 Band: 2:1 +Sample: 93:93 Line: 1:1 Band: 2:1 +Sample: 94:94 Line: 1:1 Band: 2:1 +Sample: 95:95 Line: 1:1 Band: 2:1 +Sample: 96:96 Line: 1:1 Band: 2:1 +Sample: 97:97 Line: 1:1 Band: 2:1 +Sample: 98:98 Line: 1:1 Band: 2:1 +Sample: 99:99 Line: 1:1 Band: 2:1 +Sample: 100:100 Line: 1:1 Band: 2:1 +Sample: 101:101 Line: 1:1 Band: 2:1 +90% Processed Sample: 102:102 Line: 1:1 Band: 2:1 +Sample: 103:103 Line: 1:1 Band: 2:1 +Sample: 104:104 Line: 1:1 Band: 2:1 +Sample: 105:105 Line: 1:1 Band: 2:1 +Sample: 106:106 Line: 1:1 Band: 2:1 +Sample: 107:107 Line: 1:1 Band: 2:1 +Sample: 108:108 Line: 1:1 Band: 2:1 +Sample: 109:109 Line: 1:1 Band: 2:1 +Sample: 110:110 Line: 1:1 Band: 2:1 +Sample: 111:111 Line: 1:1 Band: 2:1 +Sample: 112:112 Line: 1:1 Band: 2:1 +Sample: 113:113 Line: 1:1 Band: 2:1 +Sample: 114:114 Line: 1:1 Band: 2:1 +Sample: 115:115 Line: 1:1 Band: 2:1 +Sample: 116:116 Line: 1:1 Band: 2:1 +Sample: 117:117 Line: 1:1 Band: 2:1 +Sample: 118:118 Line: 1:1 Band: 2:1 +Sample: 119:119 Line: 1:1 Band: 2:1 +Sample: 120:120 Line: 1:1 Band: 2:1 +Sample: 121:121 Line: 1:1 Band: 2:1 +Sample: 122:122 Line: 1:1 Band: 2:1 +Sample: 123:123 Line: 1:1 Band: 2:1 +Sample: 124:124 Line: 1:1 Band: 2:1 +Sample: 125:125 Line: 1:1 Band: 2:1 +Sample: 126:126 Line: 1:1 Band: 2:1 +100% Processed diff --git a/isis/src/base/objs/ProcessBySample/unitTest.cpp b/isis/src/base/objs/ProcessBySample/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ffa10da042cddb82faf337e7c5454619aead8ee --- /dev/null +++ b/isis/src/base/objs/ProcessBySample/unitTest.cpp @@ -0,0 +1,128 @@ +#include "Isis.h" +#include "ProcessBySample.h" +#include "Cube.h" +#include + +using namespace std; +void oneInput (Isis::Buffer &b); +void oneOutput (Isis::Buffer &b); +void oneInAndOut (Isis::Buffer &ob, Isis::Buffer &ib); +void twoInAndOut (vector &ib, vector &ob); + +void IsisMain() { + + Isis::Preference::Preferences(true); + + cout << "Testing Isis::ProcessBySample Class ... " << endl; + Isis::ProcessBySample p; + + p.SetInputCube("FROM"); + p.StartProcess(oneInput); + p.EndProcess(); + + p.SetOutputCube("TO",10,20,3); + p.StartProcess(oneOutput); + p.EndProcess(); + + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + p.StartProcess(oneInAndOut); + p.EndProcess(); + + p.SetInputCube("FROM"); + p.SetInputCube("FROM2"); + p.SetOutputCube("TO"); + p.SetOutputCube("TO2"); + p.StartProcess(twoInAndOut); + p.EndProcess(); + + Isis::Cube cube; + cube.Open("/tmp/isisProcessBySample_01"); + cube.Close(true); + cube.Open("/tmp/isisProcessBySample_02"); + cube.Close(true); +} + +void oneInput(Isis::Buffer &b) { + if ((b.Sample() == 1) && (b.Band() == 1)) { + cout << "Testing one input cube ... " << endl; + cout << "Buffer Samples: " << b.SampleDimension() << endl; + cout << "Buffer Lines: " << b.LineDimension() << endl; + cout << "Buffer Bands: " << b.BandDimension() << endl; + cout << endl; + } + cout << "Sample: " << b.Sample() + << " Line: " << b.Line() + << " Band: " << b.Band() << endl; +} + +void oneOutput(Isis::Buffer &b) { + if ((b.Sample() == 1) && (b.Band() == 1)) { + cout << endl; + cout << "Testing one output cube ... " << endl; + cout << "Buffer Samples: " << b.SampleDimension() << endl; + cout << "Buffer Lines: " << b.LineDimension() << endl; + cout << "Buffer Bands: " << b.BandDimension() << endl; + cout << endl; + } + cout << "Sample: " << b.Sample() + << " Line: " << b.Line() + << " Band: " << b.Band() << endl; +} + +void oneInAndOut (Isis::Buffer &ib, Isis::Buffer &ob) { + if ((ib.Sample() == 1) && (ib.Band() == 1)) { + cout << endl; + cout << "Testing one input and output cube ... " << endl; + cout << "Buffer Samples: " << ib.SampleDimension() << endl; + cout << "Buffer Lines: " << ib.LineDimension() << endl; + cout << "Buffer Bands: " << ib.BandDimension() << endl; + cout << endl; + } + cout << "Sample: " << ib.Sample() + << " Line: " << ib.Line() + << " Band: " << ib.Band() << endl; + + if ((ib.Sample() != ob.Sample()) || + (ib.Line() != ob.Line()) || + (ib.Band() != ob.Band())) { + cout << "Bogus error #1" << endl; + } +} + +void twoInAndOut (vector &ib, vector &ob) { + static bool firstTime = true; + if (firstTime) { + firstTime = false; + cout << "Testing two input and output cubes ... " << endl; + cout << "Number of input cubes: " << ib.size() << endl; + cout << "Number of output cubes: " << ob.size() << endl; + cout << endl; + } + + Isis::Buffer *inone = ib[0]; + Isis::Buffer *intwo = ib[1]; + Isis::Buffer *outone = ob[0]; + Isis::Buffer *outtwo = ob[1]; + + cout << "Sample: " << inone->Sample() << ":" << intwo->Sample() + << " Line: " << inone->Line() << ":" << intwo->Line() + << " Band: " << inone->Band() << ":" << intwo->Band() << endl; + + if ((inone->Sample() != intwo->Sample()) || + (inone->Line() != intwo->Line())) { + cout << "Bogus error #1" << endl; + } + + if ((inone->Sample() != outone->Sample()) || + (inone->Line() != outone->Line()) || + (inone->Band() != outone->Band())) { + cout << "Bogus error #2" << endl; + } + + if ((outone->Sample() != outtwo->Sample()) || + (outone->Line() != outtwo->Line()) || + (outone->Band() != outtwo->Band())) { + cout << "Bogus error #3" << endl; + } +} diff --git a/isis/src/base/objs/ProcessBySample/unitTest.xml b/isis/src/base/objs/ProcessBySample/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..9b0276643e12c10ab88fc75561b587d08a8a32e5 --- /dev/null +++ b/isis/src/base/objs/ProcessBySample/unitTest.xml @@ -0,0 +1,83 @@ + + + + Unit test for ProcessBySample class + + + + This program test the ProcessBySample class. + + + + Scripting + + + + + Original Version + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub+1 + + + cube + output + real + + Test cube + + + Test cube + + + *.cub + + /tmp/isisProcessBySample_01.cub + + + cube + output + real + + Test cube + + + Test cube + + + *.cub + + /tmp/isisProcessBySample_02.cub + + + + diff --git a/isis/src/base/objs/ProcessBySpectra/Makefile b/isis/src/base/objs/ProcessBySpectra/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ddd57051f59c353f0a8a19cbd8529fab12a9cd48 --- /dev/null +++ b/isis/src/base/objs/ProcessBySpectra/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessBySpectra.h +SRCS = ProcessBySpectra.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessBySpectra/ProcessBySpectra.cpp b/isis/src/base/objs/ProcessBySpectra/ProcessBySpectra.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47998970a438501e12ee74c43338462dcdff4096 --- /dev/null +++ b/isis/src/base/objs/ProcessBySpectra/ProcessBySpectra.cpp @@ -0,0 +1,194 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/05/14 21:07:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +#include "ProcessBySpectra.h" + +using namespace std; +namespace Isis { + /** + * Opens an input cube specified by the user and verifies requirements are met. + * This method is overloaded and adds the requirements of ic_base::SpatialMatch + * which requires all input cubes to have the same number of samples and lines. + * It also added the requirement ic_base::BandMatchOrOne which forces 2nd, 3rd, + * 4th, etc input cubes to match the number of bands in the 1st input cube + * or to have exactly one band. For more information see Process::SetInputCube + * + * @return Cube* + * + * @param parameter User parameter to obtain file to open. Typically, the value + * is "FROM". For example, the user can specify on the command + * line FROM=myfile.cub and this method will attempt to open + * the cube "myfile.cub" if the parameter was set to "FROM". + * + * @param requirements See Process::SetInputCube for more information. + * Defaults to 0 + * + * @throws Isis::iException::Message + */ + Isis::Cube* ProcessBySpectra::SetInputCube (const std::string ¶meter, + const int requirements) { + return Isis::ProcessByBrick::SetInputCube (parameter,Isis::SpatialMatch | requirements); + } + + + Isis::Cube* ProcessBySpectra::SetInputCube (const std::string &file, + Isis::CubeAttributeInput &att, + const int requirements) { + return Isis::ProcessByBrick::SetInputCube (file,att,Isis::SpatialMatch | requirements); + } + + /** + * This method invokes the process by spectra operation over a single input or + * output cube. It will be an input cube if the method SetInputCube was invoked + * exactly one time before calling StartProcess. It will be an output cube if + * the SetOutputCube method was invoked exactly one time. Typically this method + * can be used to obtain statistics, histograms, or other information from + * an input cube. + * + * @param funct (Isis::Buffer &b) Name of your processing function + * + * @throws Isis::iException::Message + */ + void ProcessBySpectra::StartProcess (void funct(Isis::Buffer &in)) { + + // Error checks + if ((InputCubes.size() + OutputCubes.size()) > 1) { + string m = "You can only specify exactly one input or output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + else if ((InputCubes.size() + OutputCubes.size()) == 0) { + string m = "You haven't specified an input or output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + int ns, nl, nb; + if (InputCubes.size() == 1) { + ns = InputCubes[0]->Samples(); + nl = InputCubes[0]->Lines(); + nb = InputCubes[0]->Bands(); + } + else { + ns = OutputCubes[0]->Samples(); + nl = OutputCubes[0]->Lines(); + nb = OutputCubes[0]->Bands(); + } + if (Type() == PerPixel) SetBrickSize(1, 1, nb); + else if (Type() == ByLine) SetBrickSize(ns, 1, nb); + else SetBrickSize(1, nl, nb); + Isis::ProcessByBrick::StartProcess(funct); + } + + /** + * This method invokes the process by spectra operation over exactly one input and + * one output cube. Typically, this method is used for simple operations such + * as stretching a cube or applying various operators to a cube (add constant, + * multiply by constant, etc). + * + * @param funct (Isis::Buffer &in, Isis::Buffer &out) Name of your processing + * function + * + * @throws Isis::iException::Message + */ + void ProcessBySpectra::StartProcess (void + funct(Isis::Buffer &in, Isis::Buffer &out)) { + // Error checks ... there must be one input and output + if (InputCubes.size() != 1) { + string m = "You must specify exactly one input cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } else if (OutputCubes.size() != 1) { + string m = "You must specify exactly one output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + int numLines=1, numSamples=1, numBands=1; + + if (InputCubes[0]->Bands() > OutputCubes[0]->Bands()) + numBands=InputCubes[0]->Bands(); + else numBands = OutputCubes[0]->Bands(); + if (Type() == ByLine) { + numSamples = std::max(InputCubes[0]->Samples(), OutputCubes[0]->Samples()); + } else if (Type() == BySample) { + numLines = std::max(InputCubes[0]->Lines(), OutputCubes[0]->Lines()); + } + + if (Type() == PerPixel) { + SetInputBrickSize(1, 1, InputCubes[0]->Bands()); + SetOutputBrickSize(1, 1, OutputCubes[0]->Bands()); + } + else if (Type() == ByLine) { + SetInputBrickSize(InputCubes[0]->Samples(), 1, InputCubes[0]->Bands()); + SetOutputBrickSize(OutputCubes[0]->Samples(), 1, OutputCubes[0]->Bands()); + } + else { + SetInputBrickSize(1, InputCubes[0]->Lines(), InputCubes[0]->Bands()); + SetOutputBrickSize(1, OutputCubes[0]->Lines(), OutputCubes[0]->Bands()); + } + + Isis::ProcessByBrick::StartProcess(funct); + } + + /** + * This method invokes the process by spectra operation over multiple input and + * output cubes. Typically, this method is used when two input cubes are + * required for operations like ratios, differences, masking, etc. + * + * @param funct (vector &in, vector &out) Name + * of your processing function + * + * @throws Isis::iException::Message + */ + void ProcessBySpectra::StartProcess (void funct(std::vector &in, + std::vector &out)) { + if (Type() == PerPixel) { + for (unsigned int i=0; iBands(), i+1); + } + for (unsigned int i=0; iBands(), i+1); + } + } else if (Type() == ByLine) { + for (unsigned int i=0; iSamples(), 1, InputCubes[i]->Bands(), i+1); + } + for (unsigned int i=0; iSamples(), 1, OutputCubes[i]->Bands(), i+1); + } + } else { + for (unsigned int i=0; iLines(), InputCubes[i]->Bands(), i+1); + } + for (unsigned int i=0; iLines(), OutputCubes[i]->Bands(), i+1); + } + } + + Isis::ProcessByBrick::StartProcess(funct); + } + + void ProcessBySpectra::SetType(const int type){ + if (type !=PerPixel && type!=ByLine && type!=BySample) { + string m = "The specified type is invalid"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } else p_spectraType = type; + } +} diff --git a/isis/src/base/objs/ProcessBySpectra/ProcessBySpectra.h b/isis/src/base/objs/ProcessBySpectra/ProcessBySpectra.h new file mode 100644 index 0000000000000000000000000000000000000000..8347b47df5a30def5c7c147f4969b3f13ced5a1f --- /dev/null +++ b/isis/src/base/objs/ProcessBySpectra/ProcessBySpectra.h @@ -0,0 +1,81 @@ +#ifndef ProcessBySpectra_h +#define ProcessBySpectra_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/05/14 21:07:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "ProcessByBrick.h" +#include "Buffer.h" + +namespace Isis { + /** + * @brief Process cubes by spectra + * + * This class allows a programmer to develop a program which process input and + * output cubes sequentially by spectra. That is, receive the input data for spectra + * one, manipulate the data, and pass back the data for output spectra one. Then + * proceed to the spectra two and so one. This class is derived from the ProcessByBrick + * class which give many functions for setting up input and output cubes. + * + * + * @ingroup HighLevelCubeIO + * + * @author 2006-03-27 Jacob Danton + * + * @internal + * @history 2006-03-27 Jacob Danton - Original Version + * @history 2006-08-07 Tracie Sucharski, Fixed bug in StartProcess with + * a single input buffer. Error checks and set-up + * of brick was not being done correctly. + * + */ + class ProcessBySpectra : public Isis::ProcessByBrick { + private: + int p_spectraType; + + public: + ProcessBySpectra(const int type=PerPixel):ProcessByBrick(){ + SetType(type); + }; + + Isis::Cube* SetInputCube (const std::string ¶meter, + const int requirements=0); + Isis::Cube* SetInputCube (const std::string &file, + Isis::CubeAttributeInput &att, + const int requirements=0); + + void SetType (const int type); + int Type() {return p_spectraType;}; + + void StartProcess (void funct(Isis::Buffer &in)); + + void StartProcess (void funct(Isis::Buffer &in, Isis::Buffer &out)); + + void StartProcess (void funct(std::vector &in, + std::vector &out)); + + static const int PerPixel = 0; + static const int ByLine = 1; + static const int BySample = 2; + }; +}; + +#endif diff --git a/isis/src/base/objs/ProcessBySpectra/ProcessBySpectra.truth b/isis/src/base/objs/ProcessBySpectra/ProcessBySpectra.truth new file mode 100644 index 0000000000000000000000000000000000000000..090341ca082e7f5da0cb90459d83d3d02d997410 --- /dev/null +++ b/isis/src/base/objs/ProcessBySpectra/ProcessBySpectra.truth @@ -0,0 +1,400 @@ +Testing Isis::ProcessBySpectra Class ... +unittest: Working +0% Processed Testing one input cube ... +Buffer Samples: 252 +Buffer Lines: 126 +Buffer Bands: 2 + +Sample: 1 Line: 1 Band: 1 +Sample: 2 Line: 1 Band: 1 +Sample: 3 Line: 1 Band: 1 +Sample: 4 Line: 1 Band: 1 +Sample: 5 Line: 1 Band: 1 +Sample: 6 Line: 1 Band: 1 +Sample: 7 Line: 1 Band: 1 +Sample: 8 Line: 1 Band: 1 +Sample: 9 Line: 1 Band: 1 +Sample: 10 Line: 1 Band: 1 +Sample: 11 Line: 1 Band: 1 +Sample: 12 Line: 1 Band: 1 +Sample: 13 Line: 1 Band: 1 +10% Processed Sample: 14 Line: 1 Band: 1 +Sample: 15 Line: 1 Band: 1 +Sample: 16 Line: 1 Band: 1 +Sample: 17 Line: 1 Band: 1 +Sample: 18 Line: 1 Band: 1 +Sample: 19 Line: 1 Band: 1 +Sample: 20 Line: 1 Band: 1 +Sample: 21 Line: 1 Band: 1 +Sample: 22 Line: 1 Band: 1 +Sample: 23 Line: 1 Band: 1 +Sample: 24 Line: 1 Band: 1 +Sample: 25 Line: 1 Band: 1 +Sample: 26 Line: 1 Band: 1 +20% Processed Sample: 27 Line: 1 Band: 1 +Sample: 28 Line: 1 Band: 1 +Sample: 29 Line: 1 Band: 1 +Sample: 30 Line: 1 Band: 1 +Sample: 31 Line: 1 Band: 1 +Sample: 32 Line: 1 Band: 1 +Sample: 33 Line: 1 Band: 1 +Sample: 34 Line: 1 Band: 1 +Sample: 35 Line: 1 Band: 1 +Sample: 36 Line: 1 Band: 1 +Sample: 37 Line: 1 Band: 1 +Sample: 38 Line: 1 Band: 1 +30% Processed Sample: 39 Line: 1 Band: 1 +Sample: 40 Line: 1 Band: 1 +Sample: 41 Line: 1 Band: 1 +Sample: 42 Line: 1 Band: 1 +Sample: 43 Line: 1 Band: 1 +Sample: 44 Line: 1 Band: 1 +Sample: 45 Line: 1 Band: 1 +Sample: 46 Line: 1 Band: 1 +Sample: 47 Line: 1 Band: 1 +Sample: 48 Line: 1 Band: 1 +Sample: 49 Line: 1 Band: 1 +Sample: 50 Line: 1 Band: 1 +Sample: 51 Line: 1 Band: 1 +40% Processed Sample: 52 Line: 1 Band: 1 +Sample: 53 Line: 1 Band: 1 +Sample: 54 Line: 1 Band: 1 +Sample: 55 Line: 1 Band: 1 +Sample: 56 Line: 1 Band: 1 +Sample: 57 Line: 1 Band: 1 +Sample: 58 Line: 1 Band: 1 +Sample: 59 Line: 1 Band: 1 +Sample: 60 Line: 1 Band: 1 +Sample: 61 Line: 1 Band: 1 +Sample: 62 Line: 1 Band: 1 +Sample: 63 Line: 1 Band: 1 +50% Processed Sample: 64 Line: 1 Band: 1 +Sample: 65 Line: 1 Band: 1 +Sample: 66 Line: 1 Band: 1 +Sample: 67 Line: 1 Band: 1 +Sample: 68 Line: 1 Band: 1 +Sample: 69 Line: 1 Band: 1 +Sample: 70 Line: 1 Band: 1 +Sample: 71 Line: 1 Band: 1 +Sample: 72 Line: 1 Band: 1 +Sample: 73 Line: 1 Band: 1 +Sample: 74 Line: 1 Band: 1 +Sample: 75 Line: 1 Band: 1 +Sample: 76 Line: 1 Band: 1 +60% Processed Sample: 77 Line: 1 Band: 1 +Sample: 78 Line: 1 Band: 1 +Sample: 79 Line: 1 Band: 1 +Sample: 80 Line: 1 Band: 1 +Sample: 81 Line: 1 Band: 1 +Sample: 82 Line: 1 Band: 1 +Sample: 83 Line: 1 Band: 1 +Sample: 84 Line: 1 Band: 1 +Sample: 85 Line: 1 Band: 1 +Sample: 86 Line: 1 Band: 1 +Sample: 87 Line: 1 Band: 1 +Sample: 88 Line: 1 Band: 1 +Sample: 89 Line: 1 Band: 1 +70% Processed Sample: 90 Line: 1 Band: 1 +Sample: 91 Line: 1 Band: 1 +Sample: 92 Line: 1 Band: 1 +Sample: 93 Line: 1 Band: 1 +Sample: 94 Line: 1 Band: 1 +Sample: 95 Line: 1 Band: 1 +Sample: 96 Line: 1 Band: 1 +Sample: 97 Line: 1 Band: 1 +Sample: 98 Line: 1 Band: 1 +Sample: 99 Line: 1 Band: 1 +Sample: 100 Line: 1 Band: 1 +Sample: 101 Line: 1 Band: 1 +80% Processed Sample: 102 Line: 1 Band: 1 +Sample: 103 Line: 1 Band: 1 +Sample: 104 Line: 1 Band: 1 +Sample: 105 Line: 1 Band: 1 +Sample: 106 Line: 1 Band: 1 +Sample: 107 Line: 1 Band: 1 +Sample: 108 Line: 1 Band: 1 +Sample: 109 Line: 1 Band: 1 +Sample: 110 Line: 1 Band: 1 +Sample: 111 Line: 1 Band: 1 +Sample: 112 Line: 1 Band: 1 +Sample: 113 Line: 1 Band: 1 +Sample: 114 Line: 1 Band: 1 +90% Processed Sample: 115 Line: 1 Band: 1 +Sample: 116 Line: 1 Band: 1 +Sample: 117 Line: 1 Band: 1 +Sample: 118 Line: 1 Band: 1 +Sample: 119 Line: 1 Band: 1 +Sample: 120 Line: 1 Band: 1 +Sample: 121 Line: 1 Band: 1 +Sample: 122 Line: 1 Band: 1 +Sample: 123 Line: 1 Band: 1 +Sample: 124 Line: 1 Band: 1 +Sample: 125 Line: 1 Band: 1 +Sample: 126 Line: 1 Band: 1 +100% Processed +unittest: Working +0% Processed +Testing one input and output cube ... +Buffer Samples: 252 +Buffer Lines: 126 +Buffer Bands: 2 + +Sample: 1 Line: 1 Band: 1 +Sample: 2 Line: 1 Band: 1 +Sample: 3 Line: 1 Band: 1 +Sample: 4 Line: 1 Band: 1 +Sample: 5 Line: 1 Band: 1 +Sample: 6 Line: 1 Band: 1 +Sample: 7 Line: 1 Band: 1 +Sample: 8 Line: 1 Band: 1 +Sample: 9 Line: 1 Band: 1 +Sample: 10 Line: 1 Band: 1 +Sample: 11 Line: 1 Band: 1 +Sample: 12 Line: 1 Band: 1 +Sample: 13 Line: 1 Band: 1 +10% Processed Sample: 14 Line: 1 Band: 1 +Sample: 15 Line: 1 Band: 1 +Sample: 16 Line: 1 Band: 1 +Sample: 17 Line: 1 Band: 1 +Sample: 18 Line: 1 Band: 1 +Sample: 19 Line: 1 Band: 1 +Sample: 20 Line: 1 Band: 1 +Sample: 21 Line: 1 Band: 1 +Sample: 22 Line: 1 Band: 1 +Sample: 23 Line: 1 Band: 1 +Sample: 24 Line: 1 Band: 1 +Sample: 25 Line: 1 Band: 1 +Sample: 26 Line: 1 Band: 1 +20% Processed Sample: 27 Line: 1 Band: 1 +Sample: 28 Line: 1 Band: 1 +Sample: 29 Line: 1 Band: 1 +Sample: 30 Line: 1 Band: 1 +Sample: 31 Line: 1 Band: 1 +Sample: 32 Line: 1 Band: 1 +Sample: 33 Line: 1 Band: 1 +Sample: 34 Line: 1 Band: 1 +Sample: 35 Line: 1 Band: 1 +Sample: 36 Line: 1 Band: 1 +Sample: 37 Line: 1 Band: 1 +Sample: 38 Line: 1 Band: 1 +30% Processed Sample: 39 Line: 1 Band: 1 +Sample: 40 Line: 1 Band: 1 +Sample: 41 Line: 1 Band: 1 +Sample: 42 Line: 1 Band: 1 +Sample: 43 Line: 1 Band: 1 +Sample: 44 Line: 1 Band: 1 +Sample: 45 Line: 1 Band: 1 +Sample: 46 Line: 1 Band: 1 +Sample: 47 Line: 1 Band: 1 +Sample: 48 Line: 1 Band: 1 +Sample: 49 Line: 1 Band: 1 +Sample: 50 Line: 1 Band: 1 +Sample: 51 Line: 1 Band: 1 +40% Processed Sample: 52 Line: 1 Band: 1 +Sample: 53 Line: 1 Band: 1 +Sample: 54 Line: 1 Band: 1 +Sample: 55 Line: 1 Band: 1 +Sample: 56 Line: 1 Band: 1 +Sample: 57 Line: 1 Band: 1 +Sample: 58 Line: 1 Band: 1 +Sample: 59 Line: 1 Band: 1 +Sample: 60 Line: 1 Band: 1 +Sample: 61 Line: 1 Band: 1 +Sample: 62 Line: 1 Band: 1 +Sample: 63 Line: 1 Band: 1 +50% Processed Sample: 64 Line: 1 Band: 1 +Sample: 65 Line: 1 Band: 1 +Sample: 66 Line: 1 Band: 1 +Sample: 67 Line: 1 Band: 1 +Sample: 68 Line: 1 Band: 1 +Sample: 69 Line: 1 Band: 1 +Sample: 70 Line: 1 Band: 1 +Sample: 71 Line: 1 Band: 1 +Sample: 72 Line: 1 Band: 1 +Sample: 73 Line: 1 Band: 1 +Sample: 74 Line: 1 Band: 1 +Sample: 75 Line: 1 Band: 1 +Sample: 76 Line: 1 Band: 1 +60% Processed Sample: 77 Line: 1 Band: 1 +Sample: 78 Line: 1 Band: 1 +Sample: 79 Line: 1 Band: 1 +Sample: 80 Line: 1 Band: 1 +Sample: 81 Line: 1 Band: 1 +Sample: 82 Line: 1 Band: 1 +Sample: 83 Line: 1 Band: 1 +Sample: 84 Line: 1 Band: 1 +Sample: 85 Line: 1 Band: 1 +Sample: 86 Line: 1 Band: 1 +Sample: 87 Line: 1 Band: 1 +Sample: 88 Line: 1 Band: 1 +Sample: 89 Line: 1 Band: 1 +70% Processed Sample: 90 Line: 1 Band: 1 +Sample: 91 Line: 1 Band: 1 +Sample: 92 Line: 1 Band: 1 +Sample: 93 Line: 1 Band: 1 +Sample: 94 Line: 1 Band: 1 +Sample: 95 Line: 1 Band: 1 +Sample: 96 Line: 1 Band: 1 +Sample: 97 Line: 1 Band: 1 +Sample: 98 Line: 1 Band: 1 +Sample: 99 Line: 1 Band: 1 +Sample: 100 Line: 1 Band: 1 +Sample: 101 Line: 1 Band: 1 +80% Processed Sample: 102 Line: 1 Band: 1 +Sample: 103 Line: 1 Band: 1 +Sample: 104 Line: 1 Band: 1 +Sample: 105 Line: 1 Band: 1 +Sample: 106 Line: 1 Band: 1 +Sample: 107 Line: 1 Band: 1 +Sample: 108 Line: 1 Band: 1 +Sample: 109 Line: 1 Band: 1 +Sample: 110 Line: 1 Band: 1 +Sample: 111 Line: 1 Band: 1 +Sample: 112 Line: 1 Band: 1 +Sample: 113 Line: 1 Band: 1 +Sample: 114 Line: 1 Band: 1 +90% Processed Sample: 115 Line: 1 Band: 1 +Sample: 116 Line: 1 Band: 1 +Sample: 117 Line: 1 Band: 1 +Sample: 118 Line: 1 Band: 1 +Sample: 119 Line: 1 Band: 1 +Sample: 120 Line: 1 Band: 1 +Sample: 121 Line: 1 Band: 1 +Sample: 122 Line: 1 Band: 1 +Sample: 123 Line: 1 Band: 1 +Sample: 124 Line: 1 Band: 1 +Sample: 125 Line: 1 Band: 1 +Sample: 126 Line: 1 Band: 1 +100% Processed +unittest: Working +0% Processed Testing two input and output cubes ... +Number of input cubes: 2 +Number of output cubes: 2 + +Sample: 1:1 Line: 1:1 Band: 1:1 +Sample: 2:2 Line: 1:1 Band: 1:1 +Sample: 3:3 Line: 1:1 Band: 1:1 +Sample: 4:4 Line: 1:1 Band: 1:1 +Sample: 5:5 Line: 1:1 Band: 1:1 +Sample: 6:6 Line: 1:1 Band: 1:1 +Sample: 7:7 Line: 1:1 Band: 1:1 +Sample: 8:8 Line: 1:1 Band: 1:1 +Sample: 9:9 Line: 1:1 Band: 1:1 +Sample: 10:10 Line: 1:1 Band: 1:1 +Sample: 11:11 Line: 1:1 Band: 1:1 +Sample: 12:12 Line: 1:1 Band: 1:1 +Sample: 13:13 Line: 1:1 Band: 1:1 +10% Processed Sample: 14:14 Line: 1:1 Band: 1:1 +Sample: 15:15 Line: 1:1 Band: 1:1 +Sample: 16:16 Line: 1:1 Band: 1:1 +Sample: 17:17 Line: 1:1 Band: 1:1 +Sample: 18:18 Line: 1:1 Band: 1:1 +Sample: 19:19 Line: 1:1 Band: 1:1 +Sample: 20:20 Line: 1:1 Band: 1:1 +Sample: 21:21 Line: 1:1 Band: 1:1 +Sample: 22:22 Line: 1:1 Band: 1:1 +Sample: 23:23 Line: 1:1 Band: 1:1 +Sample: 24:24 Line: 1:1 Band: 1:1 +Sample: 25:25 Line: 1:1 Band: 1:1 +Sample: 26:26 Line: 1:1 Band: 1:1 +20% Processed Sample: 27:27 Line: 1:1 Band: 1:1 +Sample: 28:28 Line: 1:1 Band: 1:1 +Sample: 29:29 Line: 1:1 Band: 1:1 +Sample: 30:30 Line: 1:1 Band: 1:1 +Sample: 31:31 Line: 1:1 Band: 1:1 +Sample: 32:32 Line: 1:1 Band: 1:1 +Sample: 33:33 Line: 1:1 Band: 1:1 +Sample: 34:34 Line: 1:1 Band: 1:1 +Sample: 35:35 Line: 1:1 Band: 1:1 +Sample: 36:36 Line: 1:1 Band: 1:1 +Sample: 37:37 Line: 1:1 Band: 1:1 +Sample: 38:38 Line: 1:1 Band: 1:1 +30% Processed Sample: 39:39 Line: 1:1 Band: 1:1 +Sample: 40:40 Line: 1:1 Band: 1:1 +Sample: 41:41 Line: 1:1 Band: 1:1 +Sample: 42:42 Line: 1:1 Band: 1:1 +Sample: 43:43 Line: 1:1 Band: 1:1 +Sample: 44:44 Line: 1:1 Band: 1:1 +Sample: 45:45 Line: 1:1 Band: 1:1 +Sample: 46:46 Line: 1:1 Band: 1:1 +Sample: 47:47 Line: 1:1 Band: 1:1 +Sample: 48:48 Line: 1:1 Band: 1:1 +Sample: 49:49 Line: 1:1 Band: 1:1 +Sample: 50:50 Line: 1:1 Band: 1:1 +Sample: 51:51 Line: 1:1 Band: 1:1 +40% Processed Sample: 52:52 Line: 1:1 Band: 1:1 +Sample: 53:53 Line: 1:1 Band: 1:1 +Sample: 54:54 Line: 1:1 Band: 1:1 +Sample: 55:55 Line: 1:1 Band: 1:1 +Sample: 56:56 Line: 1:1 Band: 1:1 +Sample: 57:57 Line: 1:1 Band: 1:1 +Sample: 58:58 Line: 1:1 Band: 1:1 +Sample: 59:59 Line: 1:1 Band: 1:1 +Sample: 60:60 Line: 1:1 Band: 1:1 +Sample: 61:61 Line: 1:1 Band: 1:1 +Sample: 62:62 Line: 1:1 Band: 1:1 +Sample: 63:63 Line: 1:1 Band: 1:1 +50% Processed Sample: 64:64 Line: 1:1 Band: 1:1 +Sample: 65:65 Line: 1:1 Band: 1:1 +Sample: 66:66 Line: 1:1 Band: 1:1 +Sample: 67:67 Line: 1:1 Band: 1:1 +Sample: 68:68 Line: 1:1 Band: 1:1 +Sample: 69:69 Line: 1:1 Band: 1:1 +Sample: 70:70 Line: 1:1 Band: 1:1 +Sample: 71:71 Line: 1:1 Band: 1:1 +Sample: 72:72 Line: 1:1 Band: 1:1 +Sample: 73:73 Line: 1:1 Band: 1:1 +Sample: 74:74 Line: 1:1 Band: 1:1 +Sample: 75:75 Line: 1:1 Band: 1:1 +Sample: 76:76 Line: 1:1 Band: 1:1 +60% Processed Sample: 77:77 Line: 1:1 Band: 1:1 +Sample: 78:78 Line: 1:1 Band: 1:1 +Sample: 79:79 Line: 1:1 Band: 1:1 +Sample: 80:80 Line: 1:1 Band: 1:1 +Sample: 81:81 Line: 1:1 Band: 1:1 +Sample: 82:82 Line: 1:1 Band: 1:1 +Sample: 83:83 Line: 1:1 Band: 1:1 +Sample: 84:84 Line: 1:1 Band: 1:1 +Sample: 85:85 Line: 1:1 Band: 1:1 +Sample: 86:86 Line: 1:1 Band: 1:1 +Sample: 87:87 Line: 1:1 Band: 1:1 +Sample: 88:88 Line: 1:1 Band: 1:1 +Sample: 89:89 Line: 1:1 Band: 1:1 +70% Processed Sample: 90:90 Line: 1:1 Band: 1:1 +Sample: 91:91 Line: 1:1 Band: 1:1 +Sample: 92:92 Line: 1:1 Band: 1:1 +Sample: 93:93 Line: 1:1 Band: 1:1 +Sample: 94:94 Line: 1:1 Band: 1:1 +Sample: 95:95 Line: 1:1 Band: 1:1 +Sample: 96:96 Line: 1:1 Band: 1:1 +Sample: 97:97 Line: 1:1 Band: 1:1 +Sample: 98:98 Line: 1:1 Band: 1:1 +Sample: 99:99 Line: 1:1 Band: 1:1 +Sample: 100:100 Line: 1:1 Band: 1:1 +Sample: 101:101 Line: 1:1 Band: 1:1 +80% Processed Sample: 102:102 Line: 1:1 Band: 1:1 +Sample: 103:103 Line: 1:1 Band: 1:1 +Sample: 104:104 Line: 1:1 Band: 1:1 +Sample: 105:105 Line: 1:1 Band: 1:1 +Sample: 106:106 Line: 1:1 Band: 1:1 +Sample: 107:107 Line: 1:1 Band: 1:1 +Sample: 108:108 Line: 1:1 Band: 1:1 +Sample: 109:109 Line: 1:1 Band: 1:1 +Sample: 110:110 Line: 1:1 Band: 1:1 +Sample: 111:111 Line: 1:1 Band: 1:1 +Sample: 112:112 Line: 1:1 Band: 1:1 +Sample: 113:113 Line: 1:1 Band: 1:1 +Sample: 114:114 Line: 1:1 Band: 1:1 +90% Processed Sample: 115:115 Line: 1:1 Band: 1:1 +Sample: 116:116 Line: 1:1 Band: 1:1 +Sample: 117:117 Line: 1:1 Band: 1:1 +Sample: 118:118 Line: 1:1 Band: 1:1 +Sample: 119:119 Line: 1:1 Band: 1:1 +Sample: 120:120 Line: 1:1 Band: 1:1 +Sample: 121:121 Line: 1:1 Band: 1:1 +Sample: 122:122 Line: 1:1 Band: 1:1 +Sample: 123:123 Line: 1:1 Band: 1:1 +Sample: 124:124 Line: 1:1 Band: 1:1 +Sample: 125:125 Line: 1:1 Band: 1:1 +Sample: 126:126 Line: 1:1 Band: 1:1 +100% Processed diff --git a/isis/src/base/objs/ProcessBySpectra/unitTest.cpp b/isis/src/base/objs/ProcessBySpectra/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..328814239e7d8fdce1c3fb940ab3f50bee67117c --- /dev/null +++ b/isis/src/base/objs/ProcessBySpectra/unitTest.cpp @@ -0,0 +1,109 @@ +#include "Isis.h" +#include "ProcessBySpectra.h" +#include "Cube.h" +#include + +using namespace std; +void oneInput (Isis::Buffer &b); +void oneInAndOut (Isis::Buffer &ob, Isis::Buffer &ib); +void twoInAndOut (vector &ib, vector &ob); + +void IsisMain() { + + Isis::Preference::Preferences(true); + + cout << "Testing Isis::ProcessBySpectra Class ... " << endl; + Isis::ProcessBySpectra p(Isis::ProcessBySpectra::BySample); + + p.SetInputCube("FROM"); + p.StartProcess(oneInput); + p.EndProcess(); + + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + p.StartProcess(oneInAndOut); + p.EndProcess(); + + p.SetInputCube("FROM"); + p.SetInputCube("FROM2"); + p.SetOutputCube("TO"); + p.SetOutputCube("TO2"); + p.StartProcess(twoInAndOut); + p.EndProcess(); + + Isis::Cube cube; + cube.Open("/tmp/isisProcessBySpectra_01"); + cube.Close(true); + cube.Open("/tmp/isisProcessBySpectra_02"); + cube.Close(true); +} + +void oneInput(Isis::Buffer &b) { + if ((b.Line() == 1) && (b.Sample() == 1)) { + cout << "Testing one input cube ... " << endl; + cout << "Buffer Samples: " << b.size() << endl; + cout << "Buffer Lines: " << b.LineDimension() << endl; + cout << "Buffer Bands: " << b.BandDimension() << endl; + cout << endl; + } + cout << "Sample: " << b.Sample() + << " Line: " << b.Line() + << " Band: " << b.Band() << endl; +} + +void oneInAndOut (Isis::Buffer &ib, Isis::Buffer &ob) { + if ((ib.Line() == 1) && (ib.Sample() == 1)) { + cout << endl; + cout << "Testing one input and output cube ... " << endl; + cout << "Buffer Samples: " << ib.size() << endl; + cout << "Buffer Lines: " << ib.LineDimension() << endl; + cout << "Buffer Bands: " << ib.BandDimension() << endl; + cout << endl; + } + cout << "Sample: " << ib.Sample() + << " Line: " << ib.Line() + << " Band: " << ib.Band() << endl; + + if ((ib.Sample() != ob.Sample()) || + (ib.Line() != ob.Line()) || + (ib.Band() != ob.Band())) { + cout << "Bogus error #1" << endl; + } +} + +void twoInAndOut (vector &ib, vector &ob) { + static bool firstTime = true; + if (firstTime) { + firstTime = false; + cout << "Testing two input and output cubes ... " << endl; + cout << "Number of input cubes: " << ib.size() << endl; + cout << "Number of output cubes: " << ob.size() << endl; + cout << endl; + } + + Isis::Buffer &inone = *ib[0]; + Isis::Buffer &intwo = *ib[1]; + Isis::Buffer &outone = *ob[0]; + Isis::Buffer &outtwo = *ob[1]; + + cout << "Sample: " << inone.Sample() << ":" << intwo.Sample() + << " Line: " << inone.Line() << ":" << intwo.Line() + << " Band: " << inone.Band() << ":" << intwo.Band() << endl; + + if ((inone.Sample() != intwo.Sample()) || + (inone.Line() != intwo.Line())) { + cout << "Bogus error #1" << endl; + } + + if ((inone.Sample() != outone.Sample()) || + (inone.Line() != outone.Line()) || + (inone.Band() != outone.Band())) { + cout << "Bogus error #2" << endl; + } + + if ((outone.Sample() != outtwo.Sample()) || + (outone.Line() != outtwo.Line()) || + (outone.Band() != outtwo.Band())) { + cout << "Bogus error #3" << endl; + } +} diff --git a/isis/src/base/objs/ProcessBySpectra/unitTest.xml b/isis/src/base/objs/ProcessBySpectra/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..ed674332836f11f3da8525d109c09591a69685b4 --- /dev/null +++ b/isis/src/base/objs/ProcessBySpectra/unitTest.xml @@ -0,0 +1,83 @@ + + + + Unit test for ProcessBySpectra class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub+2-1 + + + cube + output + real + + Test cube + + + Test cube + + + *.cub + + /tmp/isisProcessBySpectra_01.cub + + + cube + output + real + + Test cube + + + Test cube + + + *.cub + + /tmp/isisProcessBySpectra_02.cub + + + + diff --git a/isis/src/base/objs/ProcessByTile/Makefile b/isis/src/base/objs/ProcessByTile/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3f40a4e550bab8b2aadb5b59f0602d3ab58a42e1 --- /dev/null +++ b/isis/src/base/objs/ProcessByTile/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessByTile.h +SRCS = ProcessByTile.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessByTile/ProcessByTile.cpp b/isis/src/base/objs/ProcessByTile/ProcessByTile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ace1802e4b5e591bab21b612eef3c4839376e40d --- /dev/null +++ b/isis/src/base/objs/ProcessByTile/ProcessByTile.cpp @@ -0,0 +1,161 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:09 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "ProcessByTile.h" +#include "TileManager.h" + +using namespace std; +namespace Isis { + + /** + * Sets the tile size + * + * @param ns Number of samples + * + * @param nl Number of lines + */ + void ProcessByTile::SetTileSize (const int ns, const int nl) { + p_tileSamples = ns; + p_tileLines = nl; + p_tileSizeSet = true; + } + + /** + * Starts the systematic processing of the input cube by moving an arbitrary + * shaped tile through the cube. This method requires that exactly one input + * cube and one output cube be loaded using the SetInputCube and SetOutputCube + * methods. + * + * @param funct (Isis::Buffer &in, Isis::Buffer &out) Receive an nxm tile in + * the input buffer and output the an nxm tile. If n=1 and m=lines + * this will process by columns. Likewise if n=samples and m=1 + * this will process by lines. + * + * @throws Isis::iException::Programmer + */ + void ProcessByTile::StartProcess (void + funct(Isis::Buffer &in, Isis::Buffer &out)) { + // The lines in the input and output must match + if (InputCubes[0]->Lines() != OutputCubes[0]->Lines()) { + string m = "The number of lines in the input and output cubes "; + m += "must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // The samples in the input and output must match + if (InputCubes[0]->Samples() != OutputCubes[0]->Samples()) { + string m = "The number of samples in the input and output cubes "; + m += "must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // The bands in the input and output must match + if (InputCubes[0]->Bands() != OutputCubes[0]->Bands()) { + string m = "The number of bands in the input and output cubes "; + m += "must match"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Make sure the tile size has been set + if (!p_tileSizeSet) { + string m = "Use the SetTileSize method to set the tile size"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + Isis::ProcessByBrick::SetBrickSize(p_tileSamples, p_tileLines, 1); + Isis::ProcessByBrick::StartProcess(funct); + } + + /** + * Starts the systematic processing of the input cube by moving an arbitrary + * shaped tile through the cube. This method requires that exactly one input + * cube be loaded. No output cubes are produced. + * + * @param funct (Isis::Buffer &in) Receive an nxm tile in the input buffer. If + * n=1 and m=lines this will process by columns. + * Likewise if n=samples and m=1 this will + * process by lines. + * + * @throws Isis::iException::Programmer + */ + void ProcessByTile::StartProcess (void funct(Isis::Buffer &in)) { + // Error checks ... there must be one input and output + if (InputCubes.size() != 1) { + string m = "You must specify exactly one input cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Make sure the tile size has been set + if (!p_tileSizeSet) { + string m = "Use the SetTileSize method to set the tile size"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + Isis::ProcessByBrick::SetBrickSize(p_tileSamples, p_tileLines, 1); + Isis::ProcessByBrick::StartProcess(funct); + } + + /** + * Starts the systematic processing of the input cube by moving an arbitrary + * shaped tile through the cube. This method allows multiple input and output + * cubes. + * + * @param funct (vector &in, vector &out) Receive + * an nxm tile in the input buffer. If + * n=1 and m=lines this will process by columns. + * Likewise if n=samples and m=1 this will + * process by lines. + * + * @throws Isis::iException::Programmer + */ + void ProcessByTile::StartProcess (void funct(std::vector &in, + std::vector &out)) { + // Make sure we had an image + if ( InputCubes.size()==0 && OutputCubes.size()==0) { + string m = "You have not specified any input or output cubes"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Make sure all the output images have the same number of bands as + // the first input/output cube + for (unsigned int i=0; iBands() != InputCubes[0]->Bands()) { + string m = "All output cubes must have the same number of bands "; + m += "as the first input cube or output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + } + + Isis::ProcessByBrick::SetBrickSize(p_tileSamples, p_tileLines, 1); + Isis::ProcessByBrick::StartProcess(funct); + } + + /** + * End the processing sequence and cleans up by closing cubes, freeing memory, + * etc. + */ + void ProcessByTile::EndProcess () { + p_tileSizeSet = false; + Isis::ProcessByBrick::EndProcess (); + } +} // end namespace isis + diff --git a/isis/src/base/objs/ProcessByTile/ProcessByTile.h b/isis/src/base/objs/ProcessByTile/ProcessByTile.h new file mode 100644 index 0000000000000000000000000000000000000000..ef9bba6158f051679bc9463b6f24a9f294089758 --- /dev/null +++ b/isis/src/base/objs/ProcessByTile/ProcessByTile.h @@ -0,0 +1,78 @@ +#ifndef ProcessByTile_h +#define ProcessByTile_h +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:09 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "ProcessByBrick.h" +#include "Buffer.h" + +namespace Isis { +/** + * @brief Process cubes by tile + * + * This is the processing class used to move a tile through cube data. This + * class allows only one input cube and one output cube or one input cube. If + * the tile size does not evenly divide into the image the tile will be padded + * with Null pixels as it falls off the right and/or bottom edge of the image. + * The tile shape is only spatial-oriented with one band of data. + * + * @ingroup HighLevelCubeIO + * + * @author 2004-05-14 Jeff Anderson + * + * @internal + * @history 2005-02-08 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-11-28 Jacob Danton - Modified file to allow processing + * with multiple input and output cubes. + * @history 2006-04-03 Jacob Danton - Rewrote the code to extend ProcessByBrick class + * + * @todo 2005-02-08 Jeff Anderson - add coded example, and implementation + * example to class documentation + */ + class ProcessByTile : public Isis::ProcessByBrick { + + private: + bool p_tileSizeSet; //! &in, + std::vector &out)); + void EndProcess (); + }; +}; + +#endif diff --git a/isis/src/base/objs/ProcessByTile/ProcessByTile.truth b/isis/src/base/objs/ProcessByTile/ProcessByTile.truth new file mode 100644 index 0000000000000000000000000000000000000000..96edb49f275d829dba957e27e06b2c9f1d8cb1a1 --- /dev/null +++ b/isis/src/base/objs/ProcessByTile/ProcessByTile.truth @@ -0,0 +1,370 @@ +unittest: Working +0% Processed Testing two input and output cubes ... +Number of input cubes: 2 +Number of output cubes: 2 + +Sample: 1:1 Line: 1:1 Band: 1:1 +Sample: 11:11 Line: 1:1 Band: 1:1 +Sample: 21:21 Line: 1:1 Band: 1:1 +Sample: 31:31 Line: 1:1 Band: 1:1 +Sample: 41:41 Line: 1:1 Band: 1:1 +Sample: 51:51 Line: 1:1 Band: 1:1 +Sample: 61:61 Line: 1:1 Band: 1:1 +Sample: 71:71 Line: 1:1 Band: 1:1 +Sample: 81:81 Line: 1:1 Band: 1:1 +Sample: 91:91 Line: 1:1 Band: 1:1 +Sample: 101:101 Line: 1:1 Band: 1:1 +Sample: 111:111 Line: 1:1 Band: 1:1 +Sample: 121:121 Line: 1:1 Band: 1:1 +Sample: 1:1 Line: 11:11 Band: 1:1 +Sample: 11:11 Line: 11:11 Band: 1:1 +Sample: 21:21 Line: 11:11 Band: 1:1 +Sample: 31:31 Line: 11:11 Band: 1:1 +Sample: 41:41 Line: 11:11 Band: 1:1 +Sample: 51:51 Line: 11:11 Band: 1:1 +Sample: 61:61 Line: 11:11 Band: 1:1 +Sample: 71:71 Line: 11:11 Band: 1:1 +Sample: 81:81 Line: 11:11 Band: 1:1 +Sample: 91:91 Line: 11:11 Band: 1:1 +Sample: 101:101 Line: 11:11 Band: 1:1 +Sample: 111:111 Line: 11:11 Band: 1:1 +Sample: 121:121 Line: 11:11 Band: 1:1 +Sample: 1:1 Line: 21:21 Band: 1:1 +Sample: 11:11 Line: 21:21 Band: 1:1 +Sample: 21:21 Line: 21:21 Band: 1:1 +Sample: 31:31 Line: 21:21 Band: 1:1 +Sample: 41:41 Line: 21:21 Band: 1:1 +Sample: 51:51 Line: 21:21 Band: 1:1 +Sample: 61:61 Line: 21:21 Band: 1:1 +Sample: 71:71 Line: 21:21 Band: 1:1 +Sample: 81:81 Line: 21:21 Band: 1:1 +Sample: 91:91 Line: 21:21 Band: 1:1 +Sample: 101:101 Line: 21:21 Band: 1:1 +10% Processed Sample: 111:111 Line: 21:21 Band: 1:1 +Sample: 121:121 Line: 21:21 Band: 1:1 +Sample: 1:1 Line: 31:31 Band: 1:1 +Sample: 11:11 Line: 31:31 Band: 1:1 +Sample: 21:21 Line: 31:31 Band: 1:1 +Sample: 31:31 Line: 31:31 Band: 1:1 +Sample: 41:41 Line: 31:31 Band: 1:1 +Sample: 51:51 Line: 31:31 Band: 1:1 +Sample: 61:61 Line: 31:31 Band: 1:1 +Sample: 71:71 Line: 31:31 Band: 1:1 +Sample: 81:81 Line: 31:31 Band: 1:1 +Sample: 91:91 Line: 31:31 Band: 1:1 +Sample: 101:101 Line: 31:31 Band: 1:1 +Sample: 111:111 Line: 31:31 Band: 1:1 +Sample: 121:121 Line: 31:31 Band: 1:1 +Sample: 1:1 Line: 41:41 Band: 1:1 +Sample: 11:11 Line: 41:41 Band: 1:1 +Sample: 21:21 Line: 41:41 Band: 1:1 +Sample: 31:31 Line: 41:41 Band: 1:1 +Sample: 41:41 Line: 41:41 Band: 1:1 +Sample: 51:51 Line: 41:41 Band: 1:1 +Sample: 61:61 Line: 41:41 Band: 1:1 +Sample: 71:71 Line: 41:41 Band: 1:1 +Sample: 81:81 Line: 41:41 Band: 1:1 +Sample: 91:91 Line: 41:41 Band: 1:1 +Sample: 101:101 Line: 41:41 Band: 1:1 +Sample: 111:111 Line: 41:41 Band: 1:1 +Sample: 121:121 Line: 41:41 Band: 1:1 +Sample: 1:1 Line: 51:51 Band: 1:1 +Sample: 11:11 Line: 51:51 Band: 1:1 +Sample: 21:21 Line: 51:51 Band: 1:1 +Sample: 31:31 Line: 51:51 Band: 1:1 +Sample: 41:41 Line: 51:51 Band: 1:1 +Sample: 51:51 Line: 51:51 Band: 1:1 +Sample: 61:61 Line: 51:51 Band: 1:1 +Sample: 71:71 Line: 51:51 Band: 1:1 +20% Processed Sample: 81:81 Line: 51:51 Band: 1:1 +Sample: 91:91 Line: 51:51 Band: 1:1 +Sample: 101:101 Line: 51:51 Band: 1:1 +Sample: 111:111 Line: 51:51 Band: 1:1 +Sample: 121:121 Line: 51:51 Band: 1:1 +Sample: 1:1 Line: 61:61 Band: 1:1 +Sample: 11:11 Line: 61:61 Band: 1:1 +Sample: 21:21 Line: 61:61 Band: 1:1 +Sample: 31:31 Line: 61:61 Band: 1:1 +Sample: 41:41 Line: 61:61 Band: 1:1 +Sample: 51:51 Line: 61:61 Band: 1:1 +Sample: 61:61 Line: 61:61 Band: 1:1 +Sample: 71:71 Line: 61:61 Band: 1:1 +Sample: 81:81 Line: 61:61 Band: 1:1 +Sample: 91:91 Line: 61:61 Band: 1:1 +Sample: 101:101 Line: 61:61 Band: 1:1 +Sample: 111:111 Line: 61:61 Band: 1:1 +Sample: 121:121 Line: 61:61 Band: 1:1 +Sample: 1:1 Line: 71:71 Band: 1:1 +Sample: 11:11 Line: 71:71 Band: 1:1 +Sample: 21:21 Line: 71:71 Band: 1:1 +Sample: 31:31 Line: 71:71 Band: 1:1 +Sample: 41:41 Line: 71:71 Band: 1:1 +Sample: 51:51 Line: 71:71 Band: 1:1 +Sample: 61:61 Line: 71:71 Band: 1:1 +Sample: 71:71 Line: 71:71 Band: 1:1 +Sample: 81:81 Line: 71:71 Band: 1:1 +Sample: 91:91 Line: 71:71 Band: 1:1 +Sample: 101:101 Line: 71:71 Band: 1:1 +Sample: 111:111 Line: 71:71 Band: 1:1 +Sample: 121:121 Line: 71:71 Band: 1:1 +Sample: 1:1 Line: 81:81 Band: 1:1 +Sample: 11:11 Line: 81:81 Band: 1:1 +Sample: 21:21 Line: 81:81 Band: 1:1 +Sample: 31:31 Line: 81:81 Band: 1:1 +Sample: 41:41 Line: 81:81 Band: 1:1 +Sample: 51:51 Line: 81:81 Band: 1:1 +30% Processed Sample: 61:61 Line: 81:81 Band: 1:1 +Sample: 71:71 Line: 81:81 Band: 1:1 +Sample: 81:81 Line: 81:81 Band: 1:1 +Sample: 91:91 Line: 81:81 Band: 1:1 +Sample: 101:101 Line: 81:81 Band: 1:1 +Sample: 111:111 Line: 81:81 Band: 1:1 +Sample: 121:121 Line: 81:81 Band: 1:1 +Sample: 1:1 Line: 91:91 Band: 1:1 +Sample: 11:11 Line: 91:91 Band: 1:1 +Sample: 21:21 Line: 91:91 Band: 1:1 +Sample: 31:31 Line: 91:91 Band: 1:1 +Sample: 41:41 Line: 91:91 Band: 1:1 +Sample: 51:51 Line: 91:91 Band: 1:1 +Sample: 61:61 Line: 91:91 Band: 1:1 +Sample: 71:71 Line: 91:91 Band: 1:1 +Sample: 81:81 Line: 91:91 Band: 1:1 +Sample: 91:91 Line: 91:91 Band: 1:1 +Sample: 101:101 Line: 91:91 Band: 1:1 +Sample: 111:111 Line: 91:91 Band: 1:1 +Sample: 121:121 Line: 91:91 Band: 1:1 +Sample: 1:1 Line: 101:101 Band: 1:1 +Sample: 11:11 Line: 101:101 Band: 1:1 +Sample: 21:21 Line: 101:101 Band: 1:1 +Sample: 31:31 Line: 101:101 Band: 1:1 +Sample: 41:41 Line: 101:101 Band: 1:1 +Sample: 51:51 Line: 101:101 Band: 1:1 +Sample: 61:61 Line: 101:101 Band: 1:1 +Sample: 71:71 Line: 101:101 Band: 1:1 +Sample: 81:81 Line: 101:101 Band: 1:1 +Sample: 91:91 Line: 101:101 Band: 1:1 +Sample: 101:101 Line: 101:101 Band: 1:1 +Sample: 111:111 Line: 101:101 Band: 1:1 +Sample: 121:121 Line: 101:101 Band: 1:1 +Sample: 1:1 Line: 111:111 Band: 1:1 +Sample: 11:11 Line: 111:111 Band: 1:1 +Sample: 21:21 Line: 111:111 Band: 1:1 +40% Processed Sample: 31:31 Line: 111:111 Band: 1:1 +Sample: 41:41 Line: 111:111 Band: 1:1 +Sample: 51:51 Line: 111:111 Band: 1:1 +Sample: 61:61 Line: 111:111 Band: 1:1 +Sample: 71:71 Line: 111:111 Band: 1:1 +Sample: 81:81 Line: 111:111 Band: 1:1 +Sample: 91:91 Line: 111:111 Band: 1:1 +Sample: 101:101 Line: 111:111 Band: 1:1 +Sample: 111:111 Line: 111:111 Band: 1:1 +Sample: 121:121 Line: 111:111 Band: 1:1 +Sample: 1:1 Line: 121:121 Band: 1:1 +Sample: 11:11 Line: 121:121 Band: 1:1 +Sample: 21:21 Line: 121:121 Band: 1:1 +Sample: 31:31 Line: 121:121 Band: 1:1 +Sample: 41:41 Line: 121:121 Band: 1:1 +Sample: 51:51 Line: 121:121 Band: 1:1 +Sample: 61:61 Line: 121:121 Band: 1:1 +Sample: 71:71 Line: 121:121 Band: 1:1 +Sample: 81:81 Line: 121:121 Band: 1:1 +Sample: 91:91 Line: 121:121 Band: 1:1 +Sample: 101:101 Line: 121:121 Band: 1:1 +Sample: 111:111 Line: 121:121 Band: 1:1 +Sample: 121:121 Line: 121:121 Band: 1:1 +Sample: 1:1 Line: 1:1 Band: 2:2 +Sample: 11:11 Line: 1:1 Band: 2:2 +Sample: 21:21 Line: 1:1 Band: 2:2 +Sample: 31:31 Line: 1:1 Band: 2:2 +Sample: 41:41 Line: 1:1 Band: 2:2 +Sample: 51:51 Line: 1:1 Band: 2:2 +Sample: 61:61 Line: 1:1 Band: 2:2 +Sample: 71:71 Line: 1:1 Band: 2:2 +Sample: 81:81 Line: 1:1 Band: 2:2 +Sample: 91:91 Line: 1:1 Band: 2:2 +Sample: 101:101 Line: 1:1 Band: 2:2 +Sample: 111:111 Line: 1:1 Band: 2:2 +Sample: 121:121 Line: 1:1 Band: 2:2 +50% Processed Sample: 1:1 Line: 11:11 Band: 2:2 +Sample: 11:11 Line: 11:11 Band: 2:2 +Sample: 21:21 Line: 11:11 Band: 2:2 +Sample: 31:31 Line: 11:11 Band: 2:2 +Sample: 41:41 Line: 11:11 Band: 2:2 +Sample: 51:51 Line: 11:11 Band: 2:2 +Sample: 61:61 Line: 11:11 Band: 2:2 +Sample: 71:71 Line: 11:11 Band: 2:2 +Sample: 81:81 Line: 11:11 Band: 2:2 +Sample: 91:91 Line: 11:11 Band: 2:2 +Sample: 101:101 Line: 11:11 Band: 2:2 +Sample: 111:111 Line: 11:11 Band: 2:2 +Sample: 121:121 Line: 11:11 Band: 2:2 +Sample: 1:1 Line: 21:21 Band: 2:2 +Sample: 11:11 Line: 21:21 Band: 2:2 +Sample: 21:21 Line: 21:21 Band: 2:2 +Sample: 31:31 Line: 21:21 Band: 2:2 +Sample: 41:41 Line: 21:21 Band: 2:2 +Sample: 51:51 Line: 21:21 Band: 2:2 +Sample: 61:61 Line: 21:21 Band: 2:2 +Sample: 71:71 Line: 21:21 Band: 2:2 +Sample: 81:81 Line: 21:21 Band: 2:2 +Sample: 91:91 Line: 21:21 Band: 2:2 +Sample: 101:101 Line: 21:21 Band: 2:2 +Sample: 111:111 Line: 21:21 Band: 2:2 +Sample: 121:121 Line: 21:21 Band: 2:2 +Sample: 1:1 Line: 31:31 Band: 2:2 +Sample: 11:11 Line: 31:31 Band: 2:2 +Sample: 21:21 Line: 31:31 Band: 2:2 +Sample: 31:31 Line: 31:31 Band: 2:2 +Sample: 41:41 Line: 31:31 Band: 2:2 +Sample: 51:51 Line: 31:31 Band: 2:2 +Sample: 61:61 Line: 31:31 Band: 2:2 +Sample: 71:71 Line: 31:31 Band: 2:2 +Sample: 81:81 Line: 31:31 Band: 2:2 +Sample: 91:91 Line: 31:31 Band: 2:2 +Sample: 101:101 Line: 31:31 Band: 2:2 +60% Processed Sample: 111:111 Line: 31:31 Band: 2:2 +Sample: 121:121 Line: 31:31 Band: 2:2 +Sample: 1:1 Line: 41:41 Band: 2:2 +Sample: 11:11 Line: 41:41 Band: 2:2 +Sample: 21:21 Line: 41:41 Band: 2:2 +Sample: 31:31 Line: 41:41 Band: 2:2 +Sample: 41:41 Line: 41:41 Band: 2:2 +Sample: 51:51 Line: 41:41 Band: 2:2 +Sample: 61:61 Line: 41:41 Band: 2:2 +Sample: 71:71 Line: 41:41 Band: 2:2 +Sample: 81:81 Line: 41:41 Band: 2:2 +Sample: 91:91 Line: 41:41 Band: 2:2 +Sample: 101:101 Line: 41:41 Band: 2:2 +Sample: 111:111 Line: 41:41 Band: 2:2 +Sample: 121:121 Line: 41:41 Band: 2:2 +Sample: 1:1 Line: 51:51 Band: 2:2 +Sample: 11:11 Line: 51:51 Band: 2:2 +Sample: 21:21 Line: 51:51 Band: 2:2 +Sample: 31:31 Line: 51:51 Band: 2:2 +Sample: 41:41 Line: 51:51 Band: 2:2 +Sample: 51:51 Line: 51:51 Band: 2:2 +Sample: 61:61 Line: 51:51 Band: 2:2 +Sample: 71:71 Line: 51:51 Band: 2:2 +Sample: 81:81 Line: 51:51 Band: 2:2 +Sample: 91:91 Line: 51:51 Band: 2:2 +Sample: 101:101 Line: 51:51 Band: 2:2 +Sample: 111:111 Line: 51:51 Band: 2:2 +Sample: 121:121 Line: 51:51 Band: 2:2 +Sample: 1:1 Line: 61:61 Band: 2:2 +Sample: 11:11 Line: 61:61 Band: 2:2 +Sample: 21:21 Line: 61:61 Band: 2:2 +Sample: 31:31 Line: 61:61 Band: 2:2 +Sample: 41:41 Line: 61:61 Band: 2:2 +Sample: 51:51 Line: 61:61 Band: 2:2 +Sample: 61:61 Line: 61:61 Band: 2:2 +Sample: 71:71 Line: 61:61 Band: 2:2 +70% Processed Sample: 81:81 Line: 61:61 Band: 2:2 +Sample: 91:91 Line: 61:61 Band: 2:2 +Sample: 101:101 Line: 61:61 Band: 2:2 +Sample: 111:111 Line: 61:61 Band: 2:2 +Sample: 121:121 Line: 61:61 Band: 2:2 +Sample: 1:1 Line: 71:71 Band: 2:2 +Sample: 11:11 Line: 71:71 Band: 2:2 +Sample: 21:21 Line: 71:71 Band: 2:2 +Sample: 31:31 Line: 71:71 Band: 2:2 +Sample: 41:41 Line: 71:71 Band: 2:2 +Sample: 51:51 Line: 71:71 Band: 2:2 +Sample: 61:61 Line: 71:71 Band: 2:2 +Sample: 71:71 Line: 71:71 Band: 2:2 +Sample: 81:81 Line: 71:71 Band: 2:2 +Sample: 91:91 Line: 71:71 Band: 2:2 +Sample: 101:101 Line: 71:71 Band: 2:2 +Sample: 111:111 Line: 71:71 Band: 2:2 +Sample: 121:121 Line: 71:71 Band: 2:2 +Sample: 1:1 Line: 81:81 Band: 2:2 +Sample: 11:11 Line: 81:81 Band: 2:2 +Sample: 21:21 Line: 81:81 Band: 2:2 +Sample: 31:31 Line: 81:81 Band: 2:2 +Sample: 41:41 Line: 81:81 Band: 2:2 +Sample: 51:51 Line: 81:81 Band: 2:2 +Sample: 61:61 Line: 81:81 Band: 2:2 +Sample: 71:71 Line: 81:81 Band: 2:2 +Sample: 81:81 Line: 81:81 Band: 2:2 +Sample: 91:91 Line: 81:81 Band: 2:2 +Sample: 101:101 Line: 81:81 Band: 2:2 +Sample: 111:111 Line: 81:81 Band: 2:2 +Sample: 121:121 Line: 81:81 Band: 2:2 +Sample: 1:1 Line: 91:91 Band: 2:2 +Sample: 11:11 Line: 91:91 Band: 2:2 +Sample: 21:21 Line: 91:91 Band: 2:2 +Sample: 31:31 Line: 91:91 Band: 2:2 +Sample: 41:41 Line: 91:91 Band: 2:2 +Sample: 51:51 Line: 91:91 Band: 2:2 +80% Processed Sample: 61:61 Line: 91:91 Band: 2:2 +Sample: 71:71 Line: 91:91 Band: 2:2 +Sample: 81:81 Line: 91:91 Band: 2:2 +Sample: 91:91 Line: 91:91 Band: 2:2 +Sample: 101:101 Line: 91:91 Band: 2:2 +Sample: 111:111 Line: 91:91 Band: 2:2 +Sample: 121:121 Line: 91:91 Band: 2:2 +Sample: 1:1 Line: 101:101 Band: 2:2 +Sample: 11:11 Line: 101:101 Band: 2:2 +Sample: 21:21 Line: 101:101 Band: 2:2 +Sample: 31:31 Line: 101:101 Band: 2:2 +Sample: 41:41 Line: 101:101 Band: 2:2 +Sample: 51:51 Line: 101:101 Band: 2:2 +Sample: 61:61 Line: 101:101 Band: 2:2 +Sample: 71:71 Line: 101:101 Band: 2:2 +Sample: 81:81 Line: 101:101 Band: 2:2 +Sample: 91:91 Line: 101:101 Band: 2:2 +Sample: 101:101 Line: 101:101 Band: 2:2 +Sample: 111:111 Line: 101:101 Band: 2:2 +Sample: 121:121 Line: 101:101 Band: 2:2 +Sample: 1:1 Line: 111:111 Band: 2:2 +Sample: 11:11 Line: 111:111 Band: 2:2 +Sample: 21:21 Line: 111:111 Band: 2:2 +Sample: 31:31 Line: 111:111 Band: 2:2 +Sample: 41:41 Line: 111:111 Band: 2:2 +Sample: 51:51 Line: 111:111 Band: 2:2 +Sample: 61:61 Line: 111:111 Band: 2:2 +Sample: 71:71 Line: 111:111 Band: 2:2 +Sample: 81:81 Line: 111:111 Band: 2:2 +Sample: 91:91 Line: 111:111 Band: 2:2 +Sample: 101:101 Line: 111:111 Band: 2:2 +Sample: 111:111 Line: 111:111 Band: 2:2 +Sample: 121:121 Line: 111:111 Band: 2:2 +Sample: 1:1 Line: 121:121 Band: 2:2 +Sample: 11:11 Line: 121:121 Band: 2:2 +Sample: 21:21 Line: 121:121 Band: 2:2 +90% Processed Sample: 31:31 Line: 121:121 Band: 2:2 +Sample: 41:41 Line: 121:121 Band: 2:2 +Sample: 51:51 Line: 121:121 Band: 2:2 +Sample: 61:61 Line: 121:121 Band: 2:2 +Sample: 71:71 Line: 121:121 Band: 2:2 +Sample: 81:81 Line: 121:121 Band: 2:2 +Sample: 91:91 Line: 121:121 Band: 2:2 +Sample: 101:101 Line: 121:121 Band: 2:2 +Sample: 111:111 Line: 121:121 Band: 2:2 +Sample: 121:121 Line: 121:121 Band: 2:2 +Sample: 1:1 Line: 1:1 Band: 3:3 +Sample: 11:11 Line: 1:1 Band: 3:3 +Sample: 21:21 Line: 1:1 Band: 3:3 +Sample: 31:31 Line: 1:1 Band: 3:3 +Sample: 41:41 Line: 1:1 Band: 3:3 +Sample: 51:51 Line: 1:1 Band: 3:3 +Sample: 61:61 Line: 1:1 Band: 3:3 +Sample: 71:71 Line: 1:1 Band: 3:3 +Sample: 81:81 Line: 1:1 Band: 3:3 +Sample: 91:91 Line: 1:1 Band: 3:3 +Sample: 101:101 Line: 1:1 Band: 3:3 +Sample: 111:111 Line: 1:1 Band: 3:3 +Sample: 121:121 Line: 1:1 Band: 3:3 +Sample: 1:1 Line: 11:11 Band: 3:3 +Sample: 11:11 Line: 11:11 Band: 3:3 +Sample: 21:21 Line: 11:11 Band: 3:3 +Sample: 31:31 Line: 11:11 Band: 3:3 +Sample: 41:41 Line: 11:11 Band: 3:3 +Sample: 51:51 Line: 11:11 Band: 3:3 +Sample: 61:61 Line: 11:11 Band: 3:3 +Sample: 71:71 Line: 11:11 Band: 3:3 +Sample: 81:81 Line: 11:11 Band: 3:3 +Sample: 91:91 Line: 11:11 Band: 3:3 +Sample: 101:101 Line: 11:11 Band: 3:3 +Sample: 111:111 Line: 11:11 Band: 3:3 +Sample: 121:121 Line: 11:11 Band: 3:3 +100% Processed diff --git a/isis/src/base/objs/ProcessByTile/unitTest.cpp b/isis/src/base/objs/ProcessByTile/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3075a06aea5859d3ac2e6fa10af12d28dab7c72b --- /dev/null +++ b/isis/src/base/objs/ProcessByTile/unitTest.cpp @@ -0,0 +1,59 @@ +#include "Isis.h" +#include "ProcessByTile.h" +#include "Cube.h" +#include + +using namespace std; +void twoInAndOut (vector &ib, vector &ob); + +void IsisMain() +{ + Isis::Preference::Preferences(true); + Isis::ProcessByTile p; + + Isis::Cube *icube = p.SetInputCube("FROM"); + p.SetInputCube("FROM2"); + p.SetTileSize(10, 10); + p.SetOutputCube("TO", icube->Samples()+10, icube->Lines(), icube->Bands()); + p.SetOutputCube("TO2", icube->Samples()+10, icube->Lines(), icube->Bands()); + p.StartProcess(twoInAndOut); + p.EndProcess(); + + Isis::Cube cube; + cube.Open("/tmp/isisProcessByTile_01"); + cube.Close(true); + cube.Open("/tmp/isisProcessByTile_02"); + cube.Close(true); +} + +void twoInAndOut (vector &ib, vector &ob) +{ + static bool firstTime = true; + if (firstTime) { + firstTime = false; + cout << "Testing two input and output cubes ... " << endl; + cout << "Number of input cubes: " << ib.size() << endl; + cout << "Number of output cubes: " << ob.size() << endl; + cout << endl; + } + + Isis::Buffer *inone = ib[0]; + Isis::Buffer *intwo = ib[1]; + Isis::Buffer *outone = ob[0]; + Isis::Buffer *outtwo = ob[1]; + + cout << "Sample: " << inone->Sample() << ":" << intwo->Sample() + << " Line: " << inone->Line() << ":" << intwo->Line() + << " Band: " << inone->Band() << ":" << intwo->Band() << endl; + + if ((inone->Sample() != intwo->Sample()) || + (inone->Line() != intwo->Line())) { + cout << "Bogus error #1" << endl; + } + + if ((outone->Sample() != outtwo->Sample()) || + (outone->Line() != outtwo->Line()) || + (outone->Band() != outtwo->Band())) { + cout << "Bogus error #2" << endl; + } +} diff --git a/isis/src/base/objs/ProcessByTile/unitTest.xml b/isis/src/base/objs/ProcessByTile/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..43096109af0f78d9479a1a977fdc2fdf7f652834 --- /dev/null +++ b/isis/src/base/objs/ProcessByTile/unitTest.xml @@ -0,0 +1,81 @@ + + + + ProcessByTile unitTest. + + + + This is a unit test for ProcessByTile. + + + + Scripting + + + + + Original Version + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub+2-1 + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisProcessByTile_01.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisProcessByTile_02.cub + + + + diff --git a/isis/src/base/objs/ProcessExport/Makefile b/isis/src/base/objs/ProcessExport/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a703dcf84352a526aaf9e891b02d7d81b3c8c40a --- /dev/null +++ b/isis/src/base/objs/ProcessExport/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessExport.h +SRCS = ProcessExport.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessExport/ProcessExport.cpp b/isis/src/base/objs/ProcessExport/ProcessExport.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fccfd66afb49046ffb88b2987d06bd9e62924a0f --- /dev/null +++ b/isis/src/base/objs/ProcessExport/ProcessExport.cpp @@ -0,0 +1,1223 @@ +/** + * @file + * $Revision: 1.10 $ + * $Date: 2010/03/05 17:47:10 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include "ProcessExport.h" +#include "Preference.h" +#include "iException.h" +#include "LineManager.h" +#include "BandManager.h" +#include "SpecialPixel.h" +#include "Histogram.h" +#include "Stretch.h" +#include "Application.h" +#include "EndianSwapper.h" +#include "Projection.h" + +using namespace std; +namespace Isis { + + //! Constructs an Export object + ProcessExport::ProcessExport () : Isis::Process() { + + p_outputMinimum = 0.0; + p_outputMiddle = 0.5; + p_outputMaximum = 1.0; + + p_inputMinimum.clear(); + p_inputMiddle.clear(); + p_inputMaximum.clear(); + + p_endianSwap = NULL; + + SetFormat( BSQ ); + SetOutputEndian(Isis::IsLsb()? Isis::Lsb : Isis::Msb); + SetOutputType(Isis::Real); + + p_Null_Set = false; + p_Lis_Set = false; + p_Lrs_Set = false; + p_His_Set = false; + p_Hrs_Set = false; + + p_progress->SetText ("Exporting"); + } + + + //! Destructor + ProcessExport::~ProcessExport() { + if (p_endianSwap != NULL) { + delete p_endianSwap; + } + for( unsigned int i = 0; i < p_str.size(); i++ ) { + delete p_str[i]; + } + p_str.clear(); + } + + + /** + * @brief Set input pixel range from to a linear stretch + * + * This method allows the programmer to define what range of input pixels in + * the input cube get mapped to the output range in the Buffer. By default the + * output range is 0.0 to 1.0 (can be overridden using the SetOutputRange + * method). This version of SetInputRange allows the programmer to perform a + * simple linear stretch. That is, "minimum:0.0 maximum:1.0" or minimum is + * mapped to 0.0, maximum is mapped to 1.0 everything inbetween is mapped + * linearly (e.g., (minimum+maximum)/2.0:0.5). Also, everything less than the + * minimum is mapped to 0.0 and everything more than the maximum is mapped to + * 1.0. If you are uncertain about how stretches operate see the Stretch + * object. If the input range is never set, no stretch will occur. + * + * @param minimum Minimum pixel value in the input cube to be mapped to the + * minimum value in the Buffer + * + * @param maximum Maximum pixel value in the input cube to be mapped to the + * maximum value in the Buffer + * + * @throws Isis::iException::Message + */ + void ProcessExport::SetInputRange(const double minimum, const double maximum) { + double middle = (minimum+maximum)/2.0; + SetInputRange(minimum, middle, maximum); + } + + /** + * @brief Set input pixel range from to a linear stretch + * + * This method allows the programmer to define what range of input pixels in + * the input cube get mapped to the output range in the Buffer. By default the + * output range is 0.0 to 1.0 (can be overridden using the SetOutputRange + * method). This version of SetInputRange allows the programmer to perform a + * simple linear stretch. That is, "minimum:0.0 maximum:1.0" or minimum is + * mapped to 0.0, maximum is mapped to 1.0 everything inbetween is mapped + * linearly (e.g., (minimum+maximum)/2.0:0.5). Also, everything less than the + * minimum is mapped to 0.0 and everything more than the maximum is mapped to + * 1.0. If you are uncertain about how stretches operate see the Stretch + * object. If the input range is never set, no stretch will occur. + * + * @param minimum Minimum pixel value in the input cube to be mapped to the + * minimum value in the Buffer + * + * @param maximum Maximum pixel value in the input cube to be mapped to the + * maximum value in the Buffer + * + * @param index The index of the channel you are setting + * + * @throws Isis::iException::Message + */ + void ProcessExport::SetInputRange(const double minimum, const double maximum, const int index) { + double middle = (minimum+maximum)/2.0; + SetInputRange(minimum, middle, maximum, index); + } + + /** + * @brief Set input pixel range from to a piecewise linear stretch + * + * This method allows the programmer to define what range of input pixels in + * the input cube get mapped to the output range in the Buffer. By default the + * output range is 0.0 to 1.0 (can be overridden using the SetOutputRange + * method). This version of SetInputRange allows the programmer to perform a + * piecewise linear stretch. That is,"minimum:0.0 middle:0.5 maximum:1.0". The + * pixels from the input cube between minimum and middle are mapped to 0.0 and + * 0.5 linearly, while pixels between middle and maximum are mapped to 0.5 and + * 1.0 linearly. Those outside the range of minimum and maximum are mapped to + * 0.0 and 1.0 respectively. If you are uncertain about how stretches operate + * see the Stretch object. If the input range is never set, no stretch will + * occur. + * + * @param minimum Minimum pixel value in the input cube to be mapped to the + * minimum value in the Buffer + * + * @param middle Middle pixel value in the input cube to be mapped to the + * (minimum+maximum)/2.0 value in the Buffer + * + * @param maximum Maximum pixel value in the input cube to be mapped to the + * maximum value in the Buffer + * + * @throws Isis::iException::Message + */ + void ProcessExport::SetInputRange(const double minimum, const double middle, + const double maximum) { + if (minimum >= middle) { + string message = + "minimum must be less than the middle [ProcessExport::SetInputRange]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + if (middle >= maximum) { + string message = + "middle must be less than the maximum [ProcessExport::SetInputRange]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + p_inputMinimum.clear(); + p_inputMinimum.resize(InputCubes.size(), minimum); + p_inputMiddle.clear(); + p_inputMiddle.resize(InputCubes.size(), middle); + p_inputMaximum.clear(); + p_inputMaximum.resize(InputCubes.size(), maximum); + } + + /** + * @brief Set input pixel range from to a piecewise linear stretch + * + * This method allows the programmer to define what range of input pixels in + * the input cube get mapped to the output range in the Buffer. By default the + * output range is 0.0 to 1.0 (can be overridden using the SetOutputRange + * method). This version of SetInputRange allows the programmer to perform a + * piecewise linear stretch. That is,"minimum:0.0 middle:0.5 maximum:1.0". The + * pixels from the input cube between minimum and middle are mapped to 0.0 and + * 0.5 linearly, while pixels between middle and maximum are mapped to 0.5 and + * 1.0 linearly. Those outside the range of minimum and maximum are mapped to + * 0.0 and 1.0 respectively. If you are uncertain about how stretches operate + * see the Stretch object. If the input range is never set, no stretch will + * occur. + * + * @param minimum Minimum pixel value in the input cube to be mapped to the + * minimum value in the Buffer + * + * @param middle Middle pixel value in the input cube to be mapped to the + * (minimum+maximum)/2.0 value in the Buffer + * + * @param maximum Maximum pixel value in the input cube to be mapped to the + * maximum value in the Buffer + * + * @param index The index of the channel you are setting + * + * @throws Isis::iException::Message + */ + void ProcessExport::SetInputRange(const double minimum, const double middle, + const double maximum, const int index) { + if (minimum >= middle) { + string message = + "minimum must be less than the middle [ProcessExport::SetInputRange]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + if (middle >= maximum) { + string message = + "middle must be less than the maximum [ProcessExport::SetInputRange]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + if (index >= (int)InputCubes.size() || index < 0) { + string message = + "index out of bounds"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + p_inputMinimum.resize(index+1, minimum); + p_inputMiddle.resize(index+1, middle); + p_inputMaximum.resize(index+1, maximum); + p_inputMinimum[index] = minimum; + p_inputMiddle[index] = middle; + p_inputMaximum[index] = maximum; + } + + /** + * @brief Set input pixel range from user + * + * This method performs the same function as SetInputRange(min,max) and + * SetInputRange(min,mid,max). However, the information for min/mid/max is + * obtained from the user via the command line. Therefore you must include + * the following parameter group in your application XML file: + * @code + * + * + * string + * + * LINEAR + * + * Type of stretch + * + * This parameter is used to select one of three ways to stretch + * (or map) output pixels. They are LINEAR, PIECEWISE, or MANUAL. + * + * + * + * + * + * + * + * + * + * + * double + * Minimum pixel value + * + * The minimum input pixel value which will be mapped to black. + * + * + * MAXIMUM + * + * + * + * + * double + * Maximum pixel value + * + * The maximum input pixel value which will be mapped to white. + * + * + * MINIMUM + * + * + * + * + * double + * Minimum Percent + * + * The percentage of data in the histogram used to compute + * the minimum pixel value in the stretch. + * + * 0.5 + * + * MAXPERCENT + * + * + * + * + * double + * Maximum Percent + * + * The percentage of data in the histogram used to compute + * the maximum pixel value in the stretch. + * + * 99.5 + * + * MINPERCENT + * + * + * + * @endcode + */ + void ProcessExport::SetInputRange() { + p_inputMinimum.clear(); + p_inputMiddle.clear(); + p_inputMaximum.clear(); + + for (unsigned int i=0; iHistogram(0); + p_inputMinimum.push_back(hist->Percent( + Application::GetUserInterface().GetDouble("MINPERCENT"))); + p_inputMaximum.push_back(hist->Percent( + Application::GetUserInterface().GetDouble("MAXPERCENT"))); + p_inputMiddle.push_back(Isis::NULL8); + Application::GetUserInterface().Clear("MINIMUM"); + Application::GetUserInterface().Clear("MAXIMUM"); + Application::GetUserInterface().PutDouble ("MINIMUM",p_inputMinimum[i]); + Application::GetUserInterface().PutDouble ("MAXIMUM",p_inputMaximum[i]); + + if (strType == "PIECEWISE") { + p_inputMiddle[i] = hist->Median(); + + // If the median is the min or max, back off to linear + if(p_inputMiddle[i] == p_inputMinimum[i] || + p_inputMiddle[i] == p_inputMaximum[i]) { + p_inputMiddle[i] = Isis::NULL8; + } + } + + // Make sure the image isn't constant + if (p_inputMinimum[i] == p_inputMaximum[i]) { + p_inputMaximum[i] = p_inputMinimum[i] + 1.0; + if (strType == "PIECEWISE") p_inputMiddle[i] = p_inputMinimum[i] + 0.5; + } + } + } + } + + /** + * @brief Set output pixel range in Buffer + * + * This method allows the programmer to specify the acceptable range of values + * contained in the Buffer. If this method is never invoked, all pixel values + * received in the Buffer of the export function will be in the range of 0.0 + * to 1.0. However, this can be overridden, for example, to 0.0 and 255.0, by + * invoking this method. + * + * @param minimum Desired minimum pixel value in the Buffer + * + * @param maximum Desired maximum pixel value in the Buffer + * + * @throws Isis::iException::Message + */ + void ProcessExport::SetOutputRange(const double minimum, const double maximum) { + if (minimum >= maximum) { + string message = + "minimum must be less than the maximum [ProcessExport::SetOutputRange]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + p_outputMinimum = minimum; + p_outputMaximum = maximum; + p_outputMiddle = (p_outputMinimum + p_outputMaximum) / 2.0; + } + + + /** + * Set output special pixel value for NULL + * + * Sets the value for output special pixel NULLs. NULL pixels values from the + * input cube will be set to this value. Be default this value will be set to + * the minimum out value set with SetOutputRange + * + * @param value The output pixel value for all NULL pixels + */ + void ProcessExport::SetOutputNull (const double value) { + p_Null = value; + p_Null_Set = true; + } + + + /** + * Set output special pixel value for LIS + * + * Sets the value for output special pixel LISs. LIS pixels values from the + * input cube will be set to this value. Be default this value will be set to + * the minimum out value set with SetOutputRange + * + * @param value The output pixel value for all LIS pixels + */ + void ProcessExport::SetOutputLis (const double value) { + p_Lis = value; + p_Lis_Set = true; + } + + + /** + * Set output special pixel value for LRS + * + * Sets the value for output special pixel LRSs. LRS8 pixels values from the + * input cube will be set to this value. Be default this value will be set to + * the minimum out value set with SetOutputRange + * + * @param value The output pixel value for all LRS pixels + */ + void ProcessExport::SetOutputLrs (const double value) { + p_Lrs = value; + p_Lrs_Set = true; + } + + + /** + * Set output special pixel value for HIS + * + * Sets the value for output special pixel HISs. HIS pixels values from the + * input cube will be set to this value. Be default this value will be set to + * the maximum out value set with SetOutputRange + * + * @param value The output pixel value for all HIS pixels + */ + void ProcessExport::SetOutputHis (const double value) { + p_His = value; + p_His_Set = true; + } + + + /** + * Set output special pixel value for HRS + * + * Sets the value for output special pixel HRSs. HRS pixels values from the + * input cube will be set to this value. Be default this value will be set to + * the maximum out value set with SetOutputRange + * + * @param value The output pixel value for all HRS pixels + */ + void ProcessExport::SetOutputHrs (const double value) { + p_Hrs = value; + p_Hrs_Set = true; + } + + + /** + * Return the output special pixel value for NULL + */ + double ProcessExport::OutputNull () { + return p_Null_Set ? p_Null : p_outputMinimum; + } + + + /** + * Return the output special pixel value for LIS + */ + double ProcessExport::OutputLis () { + return p_Lis_Set ? p_Lis : p_outputMinimum; + } + + + /** + * Return the output special pixel value for LRS + */ + double ProcessExport::OutputLrs () { + return p_Lrs_Set ? p_Lrs : p_outputMinimum; + } + + + /** + * Return the output special pixel value for HIS + */ + double ProcessExport::OutputHis () { + return p_His_Set ? p_His : p_outputMaximum; + } + + + /** + * Return the output special pixel value for HRS + */ + double ProcessExport::OutputHrs () { + return p_Hrs_Set ? p_Hrs : p_outputMaximum; + } + + + /** + * @brief Set output pixel bit type in Buffer + * + * This method specifies the type of pixel data that is going to be output. + * Essentially, it is a convenience method that will automatically calculate + * the necessary output range based on the minimum and maximum values of the + * bit type that is specified. Currently, the method only supported data types + * are Isis::UnsignedByte (Range of 0 to 255), Isis::SignedWord (Range of + * -32768 to 32767), Isis::UnsignedWord (Range of 0 to 65535), and Isis::Real + * (Range from the minimum floating-point value to the maximum floating-point + * value supported in C++; -FLT_MAX to FLT_MAX), since these are the only + * formats that can be output by ProcessExport. If neither this method nor the + * SetOutputRange method is invoked, all pixel values received in the Buffer + * of the export function will be in the range of 0.0 to 1.0. + * + * NOTE: You must set the format type of the output data with SetFormat before + * calling this method. Otherwise, you will get an error. + * + * @param pixelIn this is an enumeration of the different pixel + * types. The only values that are recognized as valid + * are Isis::UnsignedByte, Isis::SignedWord, + * Isis::UnsignedWord, and Isis::Real. + * + * + * @throws Isis::iException::Message + */ + void ProcessExport::SetOutputType(Isis::PixelType pixelIn) { + p_pixelType = pixelIn; + + if (p_format < 0 || p_format > 3) { + string message = + "Format of the output file must be set prior to calling this method [ProcessExport::SetOutputType]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + if (pixelIn == Isis::UnsignedByte) + SetOutputRange((double)VALID_MIN1, (double)VALID_MAX1); + else if (pixelIn == Isis::UnsignedWord) + SetOutputRange((double)VALID_MINU2, (double)VALID_MAXU2); + else if (pixelIn == Isis::SignedWord) + SetOutputRange((double)VALID_MIN2, (double)VALID_MAX2); + else if (pixelIn == Isis::Real) + if (p_format == JP2) { + string message = + "Unsupported bit type for JP2 formatted files [ProcessExport::SetOutputType]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } else { + SetOutputRange(-DBL_MAX, DBL_MAX); + } + else{ + string message = + "Unsupported bit type [ProcessExport::SetOutputType]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + } + + + /** + * @brief Set byte endianness of the output cube + * + * This method allows the programmer to specify whether the first byte of data + * output from the ProcessExport will be the most significant byte or the least + * significant byte. If the user does not explicitly set the endianness, it + * will default to that of the current system architecture + * + * @param byteOrderIn enumeration of the endianness (MSB or LSB) + */ + void ProcessExport::SetOutputEndian(enum ByteOrder byteOrderIn) { + if (p_endianSwap != NULL) { + delete p_endianSwap; + } + p_endianType = byteOrderIn; + if (byteOrderIn == Isis::NoByteOrder) { + p_endianSwap = new EndianSwapper("NoByteOrder"); + } + else if (byteOrderIn == Isis::Lsb) { + p_endianSwap = new EndianSwapper("LSB"); + } + else if (byteOrderIn == Isis::Msb) { + p_endianSwap = new EndianSwapper("MSB"); + } + } + + + /** + * @brief Set cube up for processing + * + * This method is called from startProcess() to validate the input cube + * before processing and to ready the input cube for reading line + * by line in the cases of BSQ and BIL, or reading band by band + * in the case of BIP. + * + * @throws Isis::iException::Message - No input cube was specified + */ + void ProcessExport::InitProcess() + { + if (InputCubes.size() < 1) { + string m = "You have not specified any input cubes"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Construct a line buffer manager + if( p_format == BIP ) { + p_progress->SetMaximumSteps((InputCubes[0]->Samples())*(InputCubes[0]->Lines())); + } + else { + p_progress->SetMaximumSteps((InputCubes[0]->Lines())*(InputCubes[0]->Bands())); + } + + + // Setup a stretch object + p_str.clear(); + for (unsigned int i=0; i 0) { + if (Isis::IsValidPixel(p_inputMinimum[i])) { + p_str[i]->AddPair (p_inputMinimum[i],p_outputMinimum); + if (Isis::IsValidPixel(p_inputMiddle[i])) { + p_str[i]->AddPair (p_inputMiddle[i],p_outputMiddle); + } + p_str[i]->AddPair (p_inputMaximum[i],p_outputMaximum); + } + } + + p_str[i]->SetNull (p_Null_Set ? p_Null : p_outputMinimum); + p_str[i]->SetLis (p_Lis_Set ? p_Lis : p_outputMinimum); + p_str[i]->SetLrs (p_Lrs_Set ? p_Lrs : p_outputMinimum); + p_str[i]->SetHis (p_His_Set ? p_His : p_outputMaximum); + p_str[i]->SetHrs (p_Hrs_Set ? p_Hrs : p_outputMaximum); + } + + p_progress->CheckStatus(); + return; + } + + + /** + * + * This method invokes the process operation over a single input + * cube. In the cases of BSQ and BIL this is a process by line. + * In the case of BIP, this is a process by band. A single + * buffer of input data will be padd to the buffer processing + * function. Note the data will be stretched based on the + * invocations of the SetInputRange and SetpOutputRange methods. + * + * @param funct (Isis::Buffer &b) Name of your buffer processing + * function. The buffer in will + * contain stretched input cube + * pixels for an entire buffer. + * These pixels must be written to + * the foreign output file (e.g, + * jpg, tif, etc). + * + */ + void ProcessExport::StartProcess (void funct(Isis::Buffer &in)) { + InitProcess(); + + Isis::BufferManager *buff; + if ( p_format == BSQ ) { + buff = new Isis::LineManager(*InputCubes[0]); + } + else if( p_format == BIL || p_format == JP2 ) { + buff = new Isis::LineManager(*InputCubes[0],true); + } + else if( p_format == BIP ) { + buff = new Isis::BandManager(*InputCubes[0]); + } + else { + string m = "Invalid storage order."; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Loop and let the app programmer fiddle with the buffers + for (buff->begin(); !buff->end(); buff->next()) { + // Read a line of data + InputCubes[0]->Read(*buff); + // Stretch the pixels into the desired range + for (int i=0; isize(); i++) { + (*buff)[i] = p_str[0]->Map((*buff)[i]); + } + // Invoke the user function + funct (*buff); + p_progress->CheckStatus(); + } + } + + + /** + * + * This method invokes the process operation over a single input + * cube. In the cases of BSQ and BIL this is a process by line. + * In the case of BIP, this is a process by band. A single + * buffer of input data will be padd to the buffer processing + * function. Note the data will be stretched based on the + * invocations of the SetInputRange and SetpOutputRange methods. + * + * @param funct (Isis::Buffer &b) Name of your buffer processing + * function. The buffer in will + * contain stretched input cube + * pixels for an entire buffer. + * These pixels must be written to + * the foreign output file (e.g, + * jpg, tif, etc). + * + */ + void ProcessExport::StartProcess (void + funct(std::vector &in)) { + + if ( p_format == BSQ ) { + StartProcessBSQ( funct ); + } + else if( p_format == BIL || p_format == JP2 ) { + StartProcessBIL( funct ); + } + else if( p_format == BIP ) { + StartProcessBIP( funct ); + } + else { + string m = "Invalid storage order."; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + } + + + /** + * A single line of input data from each input cube will be + * passed to the line processing function. Note the data will be + * stretched based on the invocations of the SetInputRange and + * SetOutputRange methods. + * + * @param funct (Isis::Buffer &b) Name of your line processing function. The + * buffer in will contain stretched input cube + * pixels for an entire line of + * each input cube. These pixels + * must be written to the foreign + * output file (e.g, jpg, tif, + * etc). + * + */ + void ProcessExport::StartProcessBSQ (void + funct(std::vector &in)) { + InitProcess(); + + int samples = InputCubes[0]->Samples(); + int lines = InputCubes[0]->Lines(); + vector imgrs; + + for (unsigned int i = 0; iSamples() == samples) && (InputCubes[i]->Lines() == lines)) { + Isis::LineManager *iline = new Isis::LineManager(*InputCubes[i]); + iline->begin(); + imgrs.push_back(iline); + } + else { + string m = "All input cubes must have the same dimensions"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + } + + // Loop and let the app programmer fiddle with the lines + for (int line=1; line<=lines; line++) { + std::vector ibufs; + + for (unsigned int j=0; jRead(*imgrs[j]); + // Stretch the pixels into the desired range + for (int i=0; iMap((*imgrs[j])[i]); + } + + ibufs.push_back(imgrs[j]); + } + + // Invoke the user function + funct (ibufs); + + for (unsigned int i=0; inext(); + } + p_progress->CheckStatus(); + } + } + + + /** + * A single line of input data from each input cube will be + * passed to the line processing function. Note the data will be + * stretched based on the invocations of the SetInputRange and + * SetOutputRange methods. + * + * @param funct (Isis::Buffer &b) Name of your line processing + * function. The buffer in will + * contain stretched input cube + * pixels for an entire line of + * each input cube. These pixels + * must be written to the foreign + * output file (e.g, jpg, tif, + * etc). + * + */ + void ProcessExport::StartProcessBIL (void + funct(std::vector &in)) { + InitProcess(); + + int samples = InputCubes[0]->Samples(); + int lines = InputCubes[0]->Lines(); + vector imgrs; + + for (unsigned int i = 0; iSamples() == samples) && (InputCubes[i]->Lines() == lines)) { + Isis::LineManager *iline = new Isis::LineManager(*InputCubes[i],true); + iline->begin(); + imgrs.push_back(iline); + } + else { + string m = "All input cubes must have the same dimensions"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + } + + // Loop and let the app programmer fiddle with the lines + for (int line=1; line<=lines; line++) { + std::vector ibufs; + + for (unsigned int j=0; jRead(*imgrs[j]); + // Stretch the pixels into the desired range + for (int i=0; iMap((*imgrs[j])[i]); + } + + ibufs.push_back(imgrs[j]); + } + + // Invoke the user function + funct (ibufs); + + for (unsigned int i=0; inext(); + } + p_progress->CheckStatus(); + } + } + + /** + * A single band of input data from each input cube will be + * passed to the band processing function. Note the data will be + * stretched based on the invocations of the SetInputRange and + * SetOutputRange methods. + * + * @param funct (Isis::Buffer &b) Name of your band processing + * function. The buffer in will + * contain stretched input cube + * pixels for an entire line of + * each input cube. These pixels + * must be written to the foreign + * output file (e.g, jpg, tif, + * etc). + * + */ + void ProcessExport::StartProcessBIP (void + funct(std::vector &in)) { + InitProcess(); + + int bands = InputCubes[0]->Bands(); + int samples = InputCubes[0]->Samples(); + vector imgrs; + + for (unsigned int i = 0; iBands() == bands) && (InputCubes[i]->Samples() == samples)) { + Isis::BandManager *iband = new Isis::BandManager(*InputCubes[i]); + iband->begin(); + imgrs.push_back(iband); + } + else { + string m = "All input cubes must have the same dimensions"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + } + + // Loop and let the app programmer fiddle with the lines + for (int band=1; band<=bands; band++) { + std::vector ibufs; + + for (unsigned int j=0; jRead(*imgrs[j]); + // Stretch the pixels into the desired range + for (int i=0; iMap((*imgrs[j])[i]); + } + + ibufs.push_back(imgrs[j]); + } + + // Invoke the user function + funct (ibufs); + + for (unsigned int i=0; inext(); + } + p_progress->CheckStatus(); + } + } + + + + + /** + * @brief Write an entire cube to an output file stream + * + * Just as with the other invocation of the StartProcess method, this will + * process an input cube buffer by buffer. Unlike the other invocation, this + * method takes care of writing the input data to an output file stream + * specified by the user instead of relying on an external function. + * + * @param &fout An open stream to which the pixel data will be written. After + * calling this method once, the stream will contain all + * of the pixel data from the input cube. + */ + void ProcessExport::StartProcess(std::ofstream &fout) { + InitProcess(); + + Isis::BufferManager *buff; + if( p_format == BSQ ) { + buff = new Isis::LineManager(*InputCubes[0]); + } + else if( p_format == BIL ) { + buff = new Isis::LineManager(*InputCubes[0],true); + } + else if( p_format == BIP ) { + buff = new Isis::BandManager(*InputCubes[0]); + } + else { + string m = "Output stream cannot be generated for requested storage order type."; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Loop for each line of data + for (buff->begin(); !buff->end(); buff->next()) { + // Read a line of data + InputCubes[0]->Read(*buff); + // Stretch the pixels into the desired range + for (int i=0; isize(); i++) { + (*buff)[i] = p_str[0]->Map((*buff)[i]); + } + if (p_pixelType == Isis::UnsignedByte) + isisOut8(*buff, fout); + else if (p_pixelType == Isis::UnsignedWord) + isisOut16u(*buff, fout); + else if (p_pixelType == Isis::SignedWord) + isisOut16s(*buff, fout); + else if (p_pixelType == Isis::Real) + isisOut32(*buff, fout); + p_progress->CheckStatus(); + } + delete buff; + return; + } + + + /** + * @brief Write a buffer of 8-bit pixel data to a stream + * + * This method takes a buffer of data and assumes that it is 8 bit pixel data. + * It will apply the necessary endian swap to the data and write it out to the + * output file buffer that the user specifies. The user can only expect to + * access this method indirectly by calling the StartProcess method + * + * @param &in Reference to a single buffer of pixel data. Note + * that this buffer will already have had the necessary + * stretching operations, though it will have the + * native endianness of the system. + * + * @param &fout Name of the file stream to which the buffer + * of pixel data will be written. + */ + void ProcessExport::isisOut8 (Buffer &in, std::ofstream &fout) { + char * out8 = new char[in.size()]; + for (int samp=0; samp= 255.0){ + out8[samp] = 255; + } + else{ + out8[samp] = (char)(in[samp]+0.5); //Rounds + } + } + fout.write (out8,in.size()); + delete[] out8; + return; + } + + + /** + * @brief Write a buffer of 16-bit signed pixel data to a stream + * + * This method takes a buffer of data and assumes that it is + * 16-bit signed pixel data. It will apply the necessary endian + * swap to the data and write it out to the output file buffer + * that the user specifies. The user can only expect to access + * this method indirectly by calling the StartProcess method. + * + * @param &in Reference to a single buffer of pixel data. Note + * that this buffer will already have had the + * necessary stretching operations, though it will + * have the native endianness of the system. + * + * @param &fout Name of the file stream to which the buffer of pixel data will + * be written. + */ + void ProcessExport::isisOut16s (Buffer &in, std::ofstream &fout) { + short * out16s = new short[in.size()]; + for (int samp=0; samp= 32767.0){ + tempShort = (short)32767; + } + else{ + //Rounds + if( in[samp] < 0.0 ) { + tempShort = (short)(in[samp]-0.5); + } + else { + tempShort = (short)(in[samp]+0.5); + } + } + void * p_swap = &tempShort; + out16s[samp] = p_endianSwap->ShortInt(p_swap); + } + fout.write ((char*)out16s,in.size()*2); + delete[] out16s; + return; + } + + + /** + * @brief Write a bufferof 16-bit unsigned pixel data to a stream + * + * This method takes a buffer of data and assumes that it is 16-bit + * unsigned pixel data. It will apply the necessary endian swap + * to the data and write it out to the output file buffer that + * the user specifies. The user can only expect to access this + * method indirectly by calling the StartProcess method. + * + * @param &in Reference to a single buffer of pixel data. Note that this buffer + * will already have had the necessary stretching operations, though + * it will have the native endianness of the system. + * + * @param &fout Name of the file stream to which the buffer of pixel data will + * be written. + * + */ + void ProcessExport::isisOut16u (Buffer &in, std::ofstream &fout) { + unsigned short *out16u = new unsigned short[in.size()]; + for (int samp=0; samp= 65535.0) { + tempShort = 65535; + } + else { + tempShort = (unsigned short)(in[samp]+0.5); //Rounds + } + unsigned short * p_swap = &tempShort; + out16u[samp] = p_endianSwap->UnsignedShortInt(p_swap); + } + + fout.write ((char*)out16u,in.size()*2); + delete[] out16u; + return; + } + + + /** + * @brief Write a buffer of 32-bit floating point pixel data to a stream + * + * This method takes a buffer of data and assumes that it is 32-bit floating + * point pixel data. It will apply the necessary endian swap to the data and + * write it out to the output file buffer that the user specifies. The user can only + * expect to access this method indirectly by calling the StartProcess method. + * + * @param &in Reference to a single buffer of pixel data. Note that this buffer + * will already have had the necessary stretching operations, though + * it will have the native endianness of the system. + * + * @param &fout Name of the file stream to which the buffer of pixel data will + * be written. + * + */ + void ProcessExport::isisOut32 (Buffer &in, std::ofstream &fout) { + int * out32 = new int[in.size()]; + for (int samp=0; samp= (double)FLT_MAX){ + tempFloat = (double)FLT_MAX; + } + else { + tempFloat = (double)in[samp]; + } + void * p_swap = &tempFloat; + out32[samp] = p_endianSwap->ExportFloat(p_swap); + } + fout.write ((char*)out32,in.size()*4); + delete[] out32; + return; + } + + + /** + * @brief Create a standard world file for the input cube + * + * This method creates a standard world file from the mapping group of the + * input cube. + * + * @param worldFile [in] Reference to a string containing the name of a file + * to write the world information to. + * + */ + void ProcessExport::CreateWorldFile (const std::string &worldFile) { + try { + Projection *proj = InputCubes[0]->Projection(); + proj->SetWorld(1.0,1.0); + ofstream os; + os.open(worldFile.c_str(),ios::out); + + // X resolution + os << std::fixed << setprecision(15) + << proj->Resolution() << endl; + // scale and rotation + os << 0.0 << endl; + os << 0.0 << endl; + + // Y resolution + os << std::fixed << setprecision(15) + << -proj->Resolution() << endl; + + // Upper left x at pixel middle + os << std::fixed << setprecision(15) + << proj->XCoord() << endl; + + // Upper left y at pixel middle + os << std::fixed << setprecision(15) + << proj->YCoord() << endl; + + os.close(); + } + catch (iException &e) { + e.Clear(); + } + } +} diff --git a/isis/src/base/objs/ProcessExport/ProcessExport.h b/isis/src/base/objs/ProcessExport/ProcessExport.h new file mode 100644 index 0000000000000000000000000000000000000000..4b7ba24f1c8fb0b081ce98e79f7ff1b971b1566a --- /dev/null +++ b/isis/src/base/objs/ProcessExport/ProcessExport.h @@ -0,0 +1,216 @@ +#ifndef ProcessExport_h +#define ProcessExport_h +/** + * @file + * $Revision: 1.8 $ + * $Date: 2010/02/24 17:39:21 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "Process.h" +#include "Buffer.h" +#include "SpecialPixel.h" +#include "Endian.h" +#include "EndianSwapper.h" +#include "Stretch.h" + +namespace Isis { + +/** + * @brief Process class for exporting cubes + * + * This class allows a programmer to develop applications which export Isis + * cubes into another format. For example, isis2jpg or isis2tif. It is highly + * recommended that this object be utilized when developing export applications + * to ensure a consistent look-and-feel for Isis users. The class operates by + * passing the programmer a line of cube data at a time. It is up to the + * programmer to write this data to the foreign output format. An ability exists + * to stretch the data supplied to the programmer in one of three ways. Either + * an automatic linear stretch, an automatic piecewise stretch, or an manual + * linear stretch. There are various methods which specify how the input pixels + * are to be stretched to an output range. You can examine the isis2jpg + * application code as a guide for writing an export program. Currently this + * class only allows for one band of a cube to be exported. + * + * If you would like to see ProcessExport being used in implementation, + * see isis2jpg.cpp + * + * @ingroup HighLevelCubeIO + * + * @author 2003-03-31 Jeff Anderson + * + * @internal + * @todo 2005-02-09 Stuart Sides - write documentation for CreateWorldFile + * method + * @todo 2005-02-09 Jeff Anderson - add coded example to class file and + * implementation examples + * @history 2003-04-03 Jeff Anderson - Added unit test + * @history 2003-04-04 Jeff Anderson - Updated documentation for SetInputRange + * methods + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2005-01-07 Stuart Sides - Added CreateWorldFile method + * @history 2005-02-08 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-06-14 Drew Davidson - Overloaded StartProcess method to output + * directly to a stream. + * @history 2005-06-15 Drew Davidson - Updated to support multi-band output. + * + * @history 2006-02-27 Jacob Danton - Added Multiple input cube support + * @history 2006-05-08 Elizabeth Miller - Modified SetInputRange() to get the + * min and max percent values from the + * userinterface (0.5 and 99.5 are still + * the default values) + * @history 2006-05-15 Jeff Anderson - Fixed bug with multiple input cube + * support when the programmer didn't + * set a input minimum/maximum + * + * @history 2006-05-23 Jacob Danton - Added seperate MIN/MAX + * values for each input channel + * + * @history 2006-08-30 Jeff Anderson - Fixed memory leak + * @history 2007-12-17 Christopher Austin - Added processes for BIL + * and BIP, leaving BSQ as the default, as well as + * fixed rounding accuracy. + * @history 2008-05-12 Steven Lambright - Removed references to CubeInfo + * @history 2008-06-18 Steven Koechle - Fixed Documentation Errors + * @history 2008-08-14 Christopher Austin - Added the Destructor to fix + * memory leaks, as well as changed the EndianSwapper::Float() + * call to EndianSwapper::ExportFloat() in isisOut32() to fix bad + * float casting. + * @history 2008-12-17 Steven Lambright - Changed SetOutputRange calls to use + * constants (i.e. instead of 65535 VALID_MAX2 is used). + * @history 2009-07-27 Steven Lambright - Piecewise stretch backs off to linear + * if Median() == MINPCT or Median() == MAXPCT + * @history 2010-02-24 Janet Barrett - Added code to support JPEG2000 + */ + class ProcessExport : public Isis::Process { + + public: + + //! Storage order enumeration + enum ExportFormat { BSQ, BIL, BIP, JP2 }; + + ProcessExport(); + ~ProcessExport(); + void StartProcess (void funct(Isis::Buffer &in)); + void StartProcess (void funct(std::vector &in)); + void StartProcess (std::ofstream& fout); + void SetOutputRange (const double minimum, const double maximum); + void SetOutputNull (const double value); + void SetOutputLis (const double value); + void SetOutputLrs (const double value); + void SetOutputHis (const double value); + void SetOutputHrs (const double value); + double OutputNull (); + double OutputLis (); + double OutputLrs (); + double OutputHis (); + double OutputHrs (); + void SetInputRange (); + void SetInputRange (const double minimum, const double maximum); + void SetInputRange (const double minimum, const double maximum, const int index); + void SetInputRange (const double minimum, const double middle, + const double maximum); + void SetInputRange (const double minimum, const double middle, + const double maximum, const int index); + void CreateWorldFile (const std::string &worldFile); + void SetOutputEndian(enum ByteOrder endianness); + void SetOutputType(Isis::PixelType pixelIn); + + //! Get the valid minimum pixel value for the Nth input cube + double GetInputMinimum(const int n=0){return (p_inputMinimum[n]);}; + //! Get the valid maximum pixel value for the Nth input cube + double GetInputMaximum(const int n=0){return (p_inputMaximum[n]);}; + //! Get the valid minimum pixel value to be written to the output file + double GetOutputMinimum(){return (p_outputMinimum);}; + //! Get the valid maximum pixel value to be written to the output file + double GetOutputMaximum(){return (p_outputMaximum);}; + + //! Sets the storage order of the output file + void SetFormat( ExportFormat format ) { p_format = format; }; + + protected: + + //! Current storage order + ExportFormat p_format; + + void StartProcessBSQ (void funct(std::vector &in)); + void StartProcessBIL (void funct(std::vector &in)); + void StartProcessBIP (void funct(std::vector &in)); + + double p_outputMinimum; //! p_inputMinimum; /** p_inputMiddle; /** p_inputMaximum; /** p_str; /** +#include "Preference.h" + +using namespace std; + +int main(){ + Isis::Preference::Preferences(true); + + cout << "Testing Isis::ProcessExport ..." < + + + + + UnitTest + + + + UnitTest for IsisExport object + + + + + Original version + + + Modified schema from astrogeology... isis.astrogeology... + + + Added processes for BIL and BIP, leaving BSQ as the default, as well as + fixed rounding accuracy. + + + + + UnitTest + + + + + + cube + $base/testData/isisTruth.cub+1 + input + + Input cube to export + + + stuff + + + *.cub + + + + + cube + $base/testData/isisTruth.cub + input + + Input cube to export + + + stuff + + + *.cub + + + + + + + string + + LINEAR + + Type of stretch + + This parameter is used to select one of three ways to stretch + (or map) output pixels. They are LINEAR, PIECEWISE, or MANUAL. + + + + + + + + + + + double + Minimum pixel value + + The minimum input pixel value which will be mapped to black. + + + MIDDLE + MAXIMUM + + + + + double + Middle pixel value + + The middle pixel value which will be mapped to middle gray or + halfway between black and white. + + + MINIMUM + + + MAXIMUM + + + + + double + Maximum pixel value + + The maximum input pixel value which will be mapped to white. + + + MINIMUM + MIDDLE + + + + + diff --git a/isis/src/base/objs/ProcessExportPds/Makefile b/isis/src/base/objs/ProcessExportPds/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..855f9e1be4bee5258fb3865c0599f6c0ef8c6e33 --- /dev/null +++ b/isis/src/base/objs/ProcessExportPds/Makefile @@ -0,0 +1,6 @@ +INCS = ProcessExportPds.h +SRCS = ProcessExportPds.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/base/objs/ProcessExportPds/ProcessExportPds.cpp b/isis/src/base/objs/ProcessExportPds/ProcessExportPds.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d105502eb7befb40d854ed7298acd06cea103ff --- /dev/null +++ b/isis/src/base/objs/ProcessExportPds/ProcessExportPds.cpp @@ -0,0 +1,882 @@ +/** + * Unless noted otherwise, the portions of Isis written by the + * USGS are public domain. See individual third-party library + * and package descriptions for intellectual property + * information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "Pvl.h" +#include "PvlFormat.h" +#include "iException.h" +#include "PixelType.h" +#include "iString.h" +#include "PvlTranslationManager.h" +#include "Filename.h" +#include "Endian.h" +#include "PvlFormatPds.h" +#include "SpecialPixel.h" +#include "ProjectionFactory.h" +#include "Filename.h" + +#include "ProcessExportPds.h" + +using namespace std; + +namespace Isis { + ProcessExportPds::ProcessExportPds(){ + p_label = NULL; + p_formatter = NULL; + p_exportType = Stream; + meResolution = Meter; + + p_forceBands = true; + p_forceBandName = true; + p_forceCenterFilterWavelength = true; + p_forceBandwidth = true; + p_forceBandStorageType = true; + p_forceOffset = true; + p_forceScalingFactor = true; + p_forceSampleBits = true; + p_forceSampleBitMask = true; + p_forceSampleType = true; + p_forceCoreNull = true; + p_forceCoreLrs = true; + p_forceCoreLis = true; + p_forceCoreHrs = true; + p_forceCoreHis = true; + p_detachedLabel = false; + } + + ProcessExportPds::~ProcessExportPds(){ + if (p_label != NULL) { + delete p_label; + delete p_formatter; + } + } + + /** + * Create a standard PDS label of the type specified + * + * Create a standard PDS label of the type specified. The type must be Image. + * Qube and SpectralQube are not supported. + * + * NOTE: This method should not be called until all setting have been + * finished. For example ProcessExport::SetOutputEndian + * + * @param type The type of PDS label to be created. + * + * @throws Isis::iException::Message + */ + Pvl& ProcessExportPds::StandardPdsLabel(ProcessExportPds::PdsFileType type){ + p_label = new Pvl; + + p_pdsFileType = type; + if (p_pdsFileType == ProcessExportPds::JP2Image) { + SetFormat(JP2); + } + + p_formatter = new PvlFormatPds("$base/translations/pdsExportRootGen.typ"); + p_label->SetFormat(p_formatter); + p_label->SetTerminator("END"); + + if (type == ProcessExportPds::Image || type == ProcessExportPds::JP2Image) { + CreateImageLabel(); + } + else { + string msg = "Unsupported PDS output type"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + return *p_label; + } + + + /** + * Create a standard PDS label for type IMAGE + */ + void ProcessExportPds::CreateImageLabel() { + + Pvl &mainPvl = *p_label; + + if ( p_exportType == Stream ) { + if (p_pdsFileType == ProcessExportPds::Image) { + StreamImageRoot (mainPvl); + } else if (p_pdsFileType == ProcessExportPds::JP2Image) { + StreamJP2ImageRoot (mainPvl); + } + } + else if ( p_exportType == Fixed ) { + if (p_pdsFileType == ProcessExportPds::Image) { + FixedImageRoot (mainPvl); + } else if (p_pdsFileType == ProcessExportPds::JP2Image) { + FixedJP2ImageRoot (mainPvl); + } + } + else { + string msg = "Invalid PDS export type"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (p_pdsFileType == ProcessExportPds::JP2Image) { + StandardJP2Image (mainPvl); + } else { + StandardImageImage (mainPvl); + } + + // The IMAGE_MAP_PROJECTION group is located in the ROOT for PDS IMAGEs. The + // standard routines will add the IMAGE_MAP_PROJECTION correctly + StandardAllMapping (mainPvl); + mainPvl.GetFormat()->Add("$base/translations/pdsExportAllMapping.typ"); + } + + + /** + * Create a standard PDS label for type QUBE + */ + void ProcessExportPds::CreateQubeLabel() { + Pvl &mainPvl = *p_label; + +// StandardQubeRoot (mainPvl); +// StandardQubeQube (mainPvl); + + // The IMAGE_MAP_PROJECTION group is located inside the QUBE object for PDS + // QUBEs. Create a temporary PVL so the StandardAllMapping member can add an + // IMAGE_MAP_PROJECTION group then later it can be extracted and added to + // the output PDS label. + Pvl mapTmp; + StandardAllMapping (mapTmp); + if (mapTmp.HasObject("IMAGE_MAP_PROJECTION")) { + mainPvl.FindObject("QUBE").AddObject(mapTmp.FindObject("IMAGE_MAP_PROJECTION")); + } + } + + + /** + * Create a standard PDS label for type SPECTRAL_QUBE + */ + void ProcessExportPds::CreateSpectralQubeLabel() { + Pvl &mainPvl = *p_label; + +// StandardSpectralQubeRoot (mainPvl); +// StandardSpectralQubeSpectralQube (mainPvl); + + // The IMAGE_MAP_PROJECTION group is located inside the SPECTRAL_QUBE object + // for PDS SPECTRAL_QUBEs. Create a temporary PVL so the StandardAllMapping + // member can add an IMAGE_MAP_PROJECTION group then later it can be + // extracted and added to the output PDS label. + Pvl mapTmp; + StandardAllMapping (mapTmp); + if (mapTmp.HasObject("IMAGE_MAP_PROJECTION")) { + mainPvl.FindObject("QUBE").AddObject(mapTmp.FindObject("IMAGE_MAP_PROJECTION")); + } + } + + + /** + * Create the standard keywords for the ROOT object in a PDS IMAGE file + */ + void ProcessExportPds::StreamImageRoot(Pvl &mainPvl) { + // Create standard ROOT object keywords + mainPvl += PvlKeyword("PDS_VERSION_ID", "PDS3"); + mainPvl += PvlKeyword("RECORD_TYPE","UNDEFINED"); + // NOTE: WARNING: If the number of "?"s in the next few lines changes, you + // must also changes the corresponding lines in the OutputLabel member + mainPvl += PvlKeyword("LABEL_RECORDS", "???????","BYTES"); + if (p_detachedLabel) { + std::string sImageFile = msLabelFile; + size_t iFound = sImageFile.find(".lbl"); + if (iFound != std::string::npos) { + sImageFile.replace(iFound, 4, ".img"); + } + else { + sImageFile += ".img"; + } + Filename outFile(sImageFile); + mainPvl += PvlKeyword("^IMAGE", outFile.Name()); + } + else { + mainPvl += PvlKeyword("^IMAGE", "???????","BYTES"); + } + } + + + /** + * Create the standard keywords for the ROOT object in a PDS JP2 IMAGE file + */ + void ProcessExportPds::StreamJP2ImageRoot(Pvl &mainPvl) { + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageJP2.typ"); + // Create standard ROOT object keywords + mainPvl += PvlKeyword("PDS_VERSION_ID","PDS3"); + std::string sImageFile = msLabelFile; + if (p_detachedLabel) { + size_t iFound = sImageFile.find(".lbl"); + if (iFound != std::string::npos) { + sImageFile.replace(iFound, 4, ".jp2"); + } + else { + sImageFile += ".jp2"; + } + } + else { + string msg = "Labels must be detached for JP2 files"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + Filename outFile(sImageFile); + PvlObject cmpObj("COMPRESSED_FILE"); + cmpObj += PvlKeyword("FILE_NAME",outFile.Name()); + cmpObj += PvlKeyword("RECORD_TYPE","UNDEFINED"); + cmpObj += PvlKeyword("ENCODING_TYPE","JP2"); + cmpObj += PvlKeyword("ENCODING_TYPE_VERSION_NAME","ISO/IEC15444-1:2004"); + cmpObj += PvlKeyword("INTERCHANGE_FORMAT","BINARY"); + Filename infilename(InputCubes[0]->Filename()); + cmpObj += PvlKeyword("UNCOMPRESSED_FILE_NAME",infilename.Name()); + int storagebytes = InputCubes[0]->Samples() * InputCubes[0]->Lines(); + if (p_pixelType == Isis::Real) { + string msg = "JPEG2000 does not support floating point data"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + if (p_pixelType == Isis::UnsignedWord || p_pixelType == Isis::SignedWord) { + storagebytes = storagebytes * 2; + } + cmpObj += PvlKeyword("REQUIRED_STORAGE_BYTES",storagebytes); + mainPvl.AddObject(cmpObj); + PvlObject ucmpObj("UNCOMPRESSED_FILE"); + ucmpObj += PvlKeyword("FILE_NAME",infilename.Name()); + ucmpObj += PvlKeyword("RECORD_TYPE","FIXED_LENGTH"); + int recordbytes = InputCubes[0]->Samples(); + if (p_pixelType == Isis::UnsignedWord || p_pixelType == Isis::SignedWord) { + recordbytes = recordbytes * 2; + } + ucmpObj += PvlKeyword("RECORD_BYTES",recordbytes); + ucmpObj += PvlKeyword("FILE_RECORDS",InputCubes[0]->Lines()); + ucmpObj += PvlKeyword("^IMAGE",infilename.Name()); + mainPvl.AddObject(ucmpObj); + } + + + /** + * Create the fixed keywords for the ROOT object in a PDS IMAGE file + */ + void ProcessExportPds::FixedImageRoot(Pvl &mainPvl) { + //Create fixed ROOT object keywords + mainPvl += PvlKeyword("PDS_VERSION_ID", "PDS3"); + mainPvl += PvlKeyword("RECORD_TYPE","FIXED_LENGTH"); + // NOTE: WARNING: If the number of "?"s in the next few lines changes, you + // must also changes the corresponding lines in the OutputLabel member + mainPvl += PvlKeyword("RECORD_BYTES", "???????"); + mainPvl += PvlKeyword("FILE_RECORDS", "???????"); + mainPvl += PvlKeyword("LABEL_RECORDS", "????"); + if (p_detachedLabel) { + std::string sImageFile = msLabelFile; + size_t iFound = sImageFile.find(".lbl"); + if (iFound != std::string::npos) { + sImageFile.replace(iFound, 4, ".img"); + } + else { + sImageFile += ".img"; + } + Filename outFile(sImageFile); + mainPvl += PvlKeyword("^IMAGE", outFile.Name()); + } + else { + mainPvl += PvlKeyword("^IMAGE", "???"); + } + } + + + /** + * Create the fixed keywords for the ROOT object in a PDS JP2 IMAGE file + */ + void ProcessExportPds::FixedJP2ImageRoot(Pvl &mainPvl) { + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageJP2.typ"); + //Create fixed ROOT object keywords + mainPvl += PvlKeyword("PDS_VERSION_ID","PDS3"); + std::string sImageFile = msLabelFile; + if (p_detachedLabel) { + size_t iFound = sImageFile.find(".lbl"); + if (iFound != std::string::npos) { + sImageFile.replace(iFound, 4, ".jp2"); + } + else { + sImageFile += ".jp2"; + } + } + else { + string msg = "Labels must be detached for JP2 files"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + Filename outFile(sImageFile); + PvlObject cmpObj("COMPRESSED_FILE"); + cmpObj += PvlKeyword("FILE_NAME", outFile.Name()); + cmpObj += PvlKeyword("RECORD_TYPE","UNDEFINED"); + cmpObj += PvlKeyword("ENCODING_TYPE","JP2"); + cmpObj += PvlKeyword("ENCODING_TYPE_VERSION_NAME","ISO/IEC15444-1:2004"); + cmpObj += PvlKeyword("INTERCHANGE_FORMAT","BINARY"); + Filename infilename(InputCubes[0]->Filename()); + cmpObj += PvlKeyword("UNCOMPRESSED_FILE_NAME",infilename.Name()); + int storagebytes = InputCubes[0]->Samples() * InputCubes[0]->Lines(); + if (p_pixelType == Isis::Real) { + string msg = "JPEG2000 does not support floating point data"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + if (p_pixelType == Isis::UnsignedWord || p_pixelType == Isis::SignedWord) { + storagebytes = storagebytes * 2; + } + cmpObj += PvlKeyword("REQUIRED_STORAGE_BYTES",storagebytes); + mainPvl.AddObject(cmpObj); + PvlObject ucmpObj("UNCOMPRESSED_FILE"); + ucmpObj += PvlKeyword("FILE_NAME",infilename.Name()); + ucmpObj += PvlKeyword("RECORD_TYPE","FIXED_LENGTH"); + int recordbytes = InputCubes[0]->Samples(); + if (p_pixelType == Isis::UnsignedWord || p_pixelType == Isis::SignedWord) { + recordbytes = recordbytes * 2; + } + ucmpObj += PvlKeyword("RECORD_BYTES",recordbytes); + ucmpObj += PvlKeyword("FILE_RECORDS",InputCubes[0]->Lines()); + ucmpObj += PvlKeyword("^IMAGE",infilename.Name()); + mainPvl.AddObject(ucmpObj); + } + + + /** + * Create the standard keywords for an IMAGE object in a PDS IMAGE file. + * This should not be called until after all settings have been made. The + * labels may contain the wrong data if it is. + * + * @throws Isis::iException::Message + */ + void ProcessExportPds::StandardImageImage(Pvl & mainPvl) { + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImage.typ"); + // Build up an IMAGE object: + // Auto translate standard keywords for the IMAGE object + Pvl *inputLabel = InputCubes[0]->Label(); + Filename transfile; + transfile = "$base/translations/pdsExportImageImage.trn"; + PvlTranslationManager Xlator(*inputLabel, transfile.Expanded()); + Xlator.Auto(mainPvl); + + // Calculate the core base/mult for this cube + double base = 0.0; + double multiplier = 1.0; + double x1,x2; + + double minimum = (p_inputMinimum.size())? p_inputMinimum[0] : 0.0; + double maximum = (p_inputMaximum.size())? p_inputMaximum[0] : 0.0; + + for(unsigned int i = 0; i < p_inputMinimum.size(); i ++) { + minimum = std::min(minimum, p_inputMinimum[i]); + maximum = std::max(maximum, p_inputMaximum[i]); + } + + x1 = p_outputMinimum; + x2 = p_outputMaximum; + + if (p_inputMinimum.size() && p_pixelType == Isis::UnsignedByte) { + multiplier = (maximum - minimum) / (x2 - x1); + base = minimum - multiplier * x1; + } + else if (p_inputMinimum.size() && p_pixelType == Isis::SignedWord) { + multiplier = (maximum - minimum) / (x2 - x1); + base = minimum - multiplier * x1; + } + else if (p_inputMinimum.size() && p_pixelType == Isis::UnsignedWord) { + multiplier = (maximum - minimum) / (x2 - x1); + base = minimum - multiplier * x1; + } + + // Manually set the keyword for the number of bits in a pixel + // NOTE: this is dependent on settings in ProcessExport and not the cube + PvlObject &imgObj = mainPvl.FindObject("IMAGE"); + + if (!p_forceBands) imgObj.DeleteKeyword("BANDS"); + if (!p_forceBandName && imgObj.HasKeyword("BAND_NAME")) imgObj.DeleteKeyword("BAND_NAME"); + if (!p_forceCenterFilterWavelength && imgObj.HasKeyword("CENTER_FILTER_WAVELENGTH")) imgObj.DeleteKeyword("CENTER_FILTER_WAVELENGTH"); + if (!p_forceBandwidth && imgObj.HasKeyword("BANDWIDTH")) imgObj.DeleteKeyword("BANDWIDTH"); + + if (p_forceBandStorageType) imgObj += PvlKeyword("BAND_STORAGE_TYPE", "BAND_SEQUENTIAL"); + if (p_forceOffset) imgObj += PvlKeyword("OFFSET", base); + if (p_forceScalingFactor) imgObj += PvlKeyword("SCALING_FACTOR", multiplier); + + // Manually set the keyword for pixel type and special pixels + if (p_pixelType == Isis::UnsignedByte) { + if (p_forceSampleBits) imgObj += PvlKeyword("SAMPLE_BITS", "8"); + if (p_forceSampleBitMask) imgObj += PvlKeyword("SAMPLE_BIT_MASK", 0xff); + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "MSB_UNSIGNED_INTEGER"); + if (p_forceCoreNull) imgObj += PvlKeyword("CORE_NULL", (int)OutputNull()); + if (p_forceCoreLrs) imgObj += PvlKeyword("CORE_LOW_REPR_SATURATION", (int)OutputLrs()); + if (p_forceCoreLis) imgObj += PvlKeyword("CORE_LOW_INSTR_SATURATION", (int)OutputLis()); + if (p_forceCoreHrs) imgObj += PvlKeyword("CORE_HIGH_REPR_SATURATION", (int)OutputHrs()); + if (p_forceCoreHis) imgObj += PvlKeyword("CORE_HIGH_INSTR_SATURATION", (int)OutputHis()); + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImagePixel8.typ"); + } + else if ((p_pixelType == Isis::UnsignedWord) && (p_endianType == Isis::Msb)) { + if (p_forceSampleBits) imgObj += PvlKeyword("SAMPLE_BITS", "16"); + if (p_forceSampleBitMask) imgObj += PvlKeyword("SAMPLE_BIT_MASK", 0xffff); + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "MSB_UNSIGNED_INTEGER"); + if (p_forceCoreNull) imgObj += PvlKeyword("CORE_NULL", (int)OutputNull()); + if (p_forceCoreLrs) imgObj += PvlKeyword("CORE_LOW_REPR_SATURATION", (int)OutputLrs()); + if (p_forceCoreLis) imgObj += PvlKeyword("CORE_LOW_INSTR_SATURATION", (int)OutputLis()); + if (p_forceCoreHrs) imgObj += PvlKeyword("CORE_HIGH_REPR_SATURATION", (int)OutputHrs()); + if (p_forceCoreHis) imgObj += PvlKeyword("CORE_HIGH_INSTR_SATURATION", (int)OutputHis()); + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImagePixel16.typ"); + } + else if ((p_pixelType == Isis::UnsignedWord) && (p_endianType == Isis::Lsb)) { + if (p_forceSampleBits) imgObj += PvlKeyword("SAMPLE_BITS", "16"); + if (p_forceSampleBitMask) imgObj += PvlKeyword("SAMPLE_BIT_MASK", 0xffff); + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "LSB_UNSIGNED_INTEGER"); + if (p_forceCoreNull) imgObj += PvlKeyword("CORE_NULL", (int)OutputNull()); + if (p_forceCoreLrs) imgObj += PvlKeyword("CORE_LOW_REPR_SATURATION", (int)OutputLrs()); + if (p_forceCoreLis) imgObj += PvlKeyword("CORE_LOW_INSTR_SATURATION", (int)OutputLis()); + if (p_forceCoreHrs) imgObj += PvlKeyword("CORE_HIGH_REPR_SATURATION", (int)OutputHrs()); + if (p_forceCoreHis) imgObj += PvlKeyword("CORE_HIGH_INSTR_SATURATION",(int)OutputHis()); + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImagePixel16.typ"); + } + else if ((p_pixelType == Isis::SignedWord) && (p_endianType == Isis::Msb)) { + if (p_forceSampleBits) imgObj += PvlKeyword("SAMPLE_BITS", "16"); + if (p_forceSampleBitMask) imgObj += PvlKeyword("SAMPLE_BIT_MASK", 0xffff); + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "MSB_INTEGER"); + if (p_forceCoreNull) imgObj += PvlKeyword("CORE_NULL", (int)OutputNull()); + if (p_forceCoreLrs) imgObj += PvlKeyword("CORE_LOW_REPR_SATURATION", (int)OutputLrs()); + if (p_forceCoreLis) imgObj += PvlKeyword("CORE_LOW_INSTR_SATURATION", (int)OutputLis()); + if (p_forceCoreHrs) imgObj += PvlKeyword("CORE_HIGH_REPR_SATURATION", (int)OutputHrs()); + if (p_forceCoreHis) imgObj += PvlKeyword("CORE_HIGH_INSTR_SATURATION",(int)OutputHis()); + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImagePixel16.typ"); + } + else if ((p_pixelType == Isis::SignedWord) && (p_endianType == Isis::Lsb)) { + if (p_forceSampleBits) imgObj += PvlKeyword("SAMPLE_BITS", "16"); + if (p_forceSampleBitMask) imgObj += PvlKeyword("SAMPLE_BIT_MASK", (BigInt)0xffff); + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "LSB_INTEGER"); + if (p_forceCoreNull) imgObj += PvlKeyword("CORE_NULL", (int)OutputNull()); + if (p_forceCoreLrs) imgObj += PvlKeyword("CORE_LOW_REPR_SATURATION", (int)OutputLrs()); + if (p_forceCoreLis) imgObj += PvlKeyword("CORE_LOW_INSTR_SATURATION", (int)OutputLis()); + if (p_forceCoreHrs) imgObj += PvlKeyword("CORE_HIGH_REPR_SATURATION", (int)OutputHrs()); + if (p_forceCoreHis) imgObj += PvlKeyword("CORE_HIGH_INSTR_SATURATION",(int)OutputHis()); + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImagePixel16.typ"); + } + else if (p_pixelType == Isis::Real) { + if (p_forceSampleBits) imgObj += PvlKeyword("SAMPLE_BITS", "32"); + if (p_forceSampleBitMask) imgObj += PvlKeyword("SAMPLE_BIT_MASK", (BigInt)0xffffffff); + + if (p_endianType == Isis::Msb) { + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "IEEE_REAL"); + } + else { + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "PC_REAL"); + } + if (p_forceCoreNull) imgObj += PvlKeyword("CORE_NULL", Isis::INULL4); + if (p_forceCoreLrs) imgObj += PvlKeyword("CORE_LOW_REPR_SATURATION", Isis::ILOW_REPR_SAT4); + if (p_forceCoreLis) imgObj += PvlKeyword("CORE_LOW_INSTR_SATURATION", Isis::ILOW_INSTR_SAT4); + if (p_forceCoreHrs) imgObj += PvlKeyword("CORE_HIGH_REPR_SATURATION", Isis::IHIGH_REPR_SAT4); + if (p_forceCoreHis) imgObj += PvlKeyword("CORE_HIGH_INSTR_SATURATION", Isis::IHIGH_INSTR_SAT4); + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImagePixel32.typ"); + } + else { + string msg = "Unsupported PDS pixel type or sample size"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + + + /** + * Create the standard keywords for an IMAGE object in a PDS JP2 IMAGE file. + * This should not be called until after all settings have been made. The + * labels may contain the wrong data if it is. + * + * @throws Isis::iException::Message + */ + void ProcessExportPds::StandardJP2Image(Pvl & mainPvl) { + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImage.typ"); + if (p_pdsFileType == ProcessExportPds::JP2Image) { + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageJP2.typ"); + } + // Build up a JP2 IMAGE object: + // Auto translate standard keywords for the IMAGE object + Pvl *inputLabel = InputCubes[0]->Label(); + Filename transfile; + transfile = "$base/translations/pdsExportImageJP2.trn"; + PvlTranslationManager Xlator(*inputLabel, transfile.Expanded()); + Xlator.Auto(mainPvl); + + // Calculate the core base/mult for this cube + double base = 0.0; + double multiplier = 1.0; + double x1,x2; + + double minimum = (p_inputMinimum.size())? p_inputMinimum[0] : 0.0; + double maximum = (p_inputMaximum.size())? p_inputMaximum[0] : 0.0; + + for(unsigned int i = 0; i < p_inputMinimum.size(); i ++) { + minimum = std::min(minimum, p_inputMinimum[i]); + maximum = std::max(maximum, p_inputMaximum[i]); + } + + x1 = p_outputMinimum; + x2 = p_outputMaximum; + + if (p_inputMinimum.size() && p_pixelType == Isis::UnsignedByte) { + multiplier = (maximum - minimum) / (x2 - x1); + base = minimum - multiplier * x1; + } + else if (p_inputMinimum.size() && p_pixelType == Isis::SignedWord) { + multiplier = (maximum - minimum) / (x2 - x1); + base = minimum - multiplier * x1; + } + else if (p_inputMinimum.size() && p_pixelType == Isis::UnsignedWord) { + multiplier = (maximum - minimum) / (x2 - x1); + base = minimum - multiplier * x1; + } + + // Manually set the keyword for the number of bits in a pixel + // NOTE: this is dependent on settings in ProcessExport and not the cube + PvlObject &imgObj = mainPvl.FindObject("UNCOMPRESSED_FILE").FindObject("IMAGE"); + + if (!p_forceBands) imgObj.DeleteKeyword("BANDS"); + if (!p_forceBandName && imgObj.HasKeyword("BAND_NAME")) imgObj.DeleteKeyword("BAND_NAME"); + if (!p_forceCenterFilterWavelength && imgObj.HasKeyword("CENTER_FILTER_WAVELENGTH")) imgObj.DeleteKeyword("CENTER_FILTER_WAVELENGTH"); + if (!p_forceBandwidth && imgObj.HasKeyword("BANDWIDTH")) imgObj.DeleteKeyword("BANDWIDTH"); + + if (p_forceBandStorageType) imgObj += PvlKeyword("BAND_STORAGE_TYPE", "BAND_SEQUENTIAL"); + if (p_forceOffset) imgObj += PvlKeyword("OFFSET", base); + if (p_forceScalingFactor) imgObj += PvlKeyword("SCALING_FACTOR", multiplier); + + // Manually set the keyword for pixel type and special pixels + if (p_pixelType == Isis::UnsignedByte) { + if (p_forceSampleBits) imgObj += PvlKeyword("SAMPLE_BITS", "8"); + if (p_forceSampleBitMask) imgObj += PvlKeyword("SAMPLE_BIT_MASK", 0xff); + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "MSB_UNSIGNED_INTEGER"); + if (p_forceCoreNull) imgObj += PvlKeyword("CORE_NULL", (int)OutputNull()); + if (p_forceCoreLrs) imgObj += PvlKeyword("CORE_LOW_REPR_SATURATION", (int)OutputLrs()); + if (p_forceCoreLis) imgObj += PvlKeyword("CORE_LOW_INSTR_SATURATION", (int)OutputLis()); + if (p_forceCoreHrs) imgObj += PvlKeyword("CORE_HIGH_REPR_SATURATION", (int)OutputHrs()); + if (p_forceCoreHis) imgObj += PvlKeyword("CORE_HIGH_INSTR_SATURATION", (int)OutputHis()); + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImagePixel8.typ"); + } + else if ((p_pixelType == Isis::UnsignedWord) && (p_endianType == Isis::Msb)) { + if (p_forceSampleBits) imgObj += PvlKeyword("SAMPLE_BITS", "16"); + if (p_forceSampleBitMask) imgObj += PvlKeyword("SAMPLE_BIT_MASK", 0xffff); + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "MSB_UNSIGNED_INTEGER"); + if (p_forceCoreNull) imgObj += PvlKeyword("CORE_NULL", (int)OutputNull()); + if (p_forceCoreLrs) imgObj += PvlKeyword("CORE_LOW_REPR_SATURATION", (int)OutputLrs()); + if (p_forceCoreLis) imgObj += PvlKeyword("CORE_LOW_INSTR_SATURATION", (int)OutputLis()); + if (p_forceCoreHrs) imgObj += PvlKeyword("CORE_HIGH_REPR_SATURATION", (int)OutputHrs()); + if (p_forceCoreHis) imgObj += PvlKeyword("CORE_HIGH_INSTR_SATURATION", (int)OutputHis()); + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImagePixel16.typ"); + } + else if ((p_pixelType == Isis::UnsignedWord) && (p_endianType == Isis::Lsb)) { + if (p_forceSampleBits) imgObj += PvlKeyword("SAMPLE_BITS", "16"); + if (p_forceSampleBitMask) imgObj += PvlKeyword("SAMPLE_BIT_MASK", 0xffff); + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "LSB_UNSIGNED_INTEGER"); + if (p_forceCoreNull) imgObj += PvlKeyword("CORE_NULL", (int)OutputNull()); + if (p_forceCoreLrs) imgObj += PvlKeyword("CORE_LOW_REPR_SATURATION", (int)OutputLrs()); + if (p_forceCoreLis) imgObj += PvlKeyword("CORE_LOW_INSTR_SATURATION", (int)OutputLis()); + if (p_forceCoreHrs) imgObj += PvlKeyword("CORE_HIGH_REPR_SATURATION", (int)OutputHrs()); + if (p_forceCoreHis) imgObj += PvlKeyword("CORE_HIGH_INSTR_SATURATION",(int)OutputHis()); + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImagePixel16.typ"); + } + else if ((p_pixelType == Isis::SignedWord) && (p_endianType == Isis::Msb)) { + if (p_forceSampleBits) imgObj += PvlKeyword("SAMPLE_BITS", "16"); + if (p_forceSampleBitMask) imgObj += PvlKeyword("SAMPLE_BIT_MASK", 0xffff); + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "MSB_INTEGER"); + if (p_forceCoreNull) imgObj += PvlKeyword("CORE_NULL", (int)OutputNull()); + if (p_forceCoreLrs) imgObj += PvlKeyword("CORE_LOW_REPR_SATURATION", (int)OutputLrs()); + if (p_forceCoreLis) imgObj += PvlKeyword("CORE_LOW_INSTR_SATURATION", (int)OutputLis()); + if (p_forceCoreHrs) imgObj += PvlKeyword("CORE_HIGH_REPR_SATURATION", (int)OutputHrs()); + if (p_forceCoreHis) imgObj += PvlKeyword("CORE_HIGH_INSTR_SATURATION",(int)OutputHis()); + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImagePixel16.typ"); + } + else if ((p_pixelType == Isis::SignedWord) && (p_endianType == Isis::Lsb)) { + if (p_forceSampleBits) imgObj += PvlKeyword("SAMPLE_BITS", "16"); + if (p_forceSampleBitMask) imgObj += PvlKeyword("SAMPLE_BIT_MASK", (BigInt)0xffff); + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "LSB_INTEGER"); + if (p_forceCoreNull) imgObj += PvlKeyword("CORE_NULL", (int)OutputNull()); + if (p_forceCoreLrs) imgObj += PvlKeyword("CORE_LOW_REPR_SATURATION", (int)OutputLrs()); + if (p_forceCoreLis) imgObj += PvlKeyword("CORE_LOW_INSTR_SATURATION", (int)OutputLis()); + if (p_forceCoreHrs) imgObj += PvlKeyword("CORE_HIGH_REPR_SATURATION", (int)OutputHrs()); + if (p_forceCoreHis) imgObj += PvlKeyword("CORE_HIGH_INSTR_SATURATION",(int)OutputHis()); + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImagePixel16.typ"); + } + else if (p_pixelType == Isis::Real) { + if (p_forceSampleBits) imgObj += PvlKeyword("SAMPLE_BITS", "32"); + if (p_forceSampleBitMask) imgObj += PvlKeyword("SAMPLE_BIT_MASK", (BigInt)0xffffffff); + + if (p_endianType == Isis::Msb) { + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "IEEE_REAL"); + } + else { + if (p_forceSampleType) imgObj += PvlKeyword("SAMPLE_TYPE", "PC_REAL"); + } + if (p_forceCoreNull) imgObj += PvlKeyword("CORE_NULL", Isis::INULL4); + if (p_forceCoreLrs) imgObj += PvlKeyword("CORE_LOW_REPR_SATURATION", Isis::ILOW_REPR_SAT4); + if (p_forceCoreLis) imgObj += PvlKeyword("CORE_LOW_INSTR_SATURATION", Isis::ILOW_INSTR_SAT4); + if (p_forceCoreHrs) imgObj += PvlKeyword("CORE_HIGH_REPR_SATURATION", Isis::IHIGH_REPR_SAT4); + if (p_forceCoreHis) imgObj += PvlKeyword("CORE_HIGH_INSTR_SATURATION", Isis::IHIGH_INSTR_SAT4); + mainPvl.GetFormat()->Add("$base/translations/pdsExportImageImagePixel32.typ"); + } + else { + string msg = "Unsupported PDS pixel type or sample size"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + + + /** + * Create the standard keywords for the IMAGE_MAP_PROJECTION group in a PDS + * label + * + * @throws Isis::iException::Message + */ + void ProcessExportPds::StandardAllMapping(Pvl &outputPvl) { + + // Get the input Isis cube label and find the Mapping group if it has one + Pvl *inputLabel = InputCubes[0]->Label(); + if (inputLabel->HasObject("IsisCube") && + !(inputLabel->FindObject("IsisCube").HasGroup("Mapping"))) return; + PvlGroup &inputMapping = inputLabel->FindGroup("Mapping",Pvl::Traverse); + // Translate the common keywords for a PDS IMAGE_MAP_PROJECTION + PvlTranslationManager xlatGenProj(*inputLabel, + "$base/translations/pdsExportAllMapping.trn"); + xlatGenProj.Auto(outputPvl); + + // Translate the projection specific keywords for a PDS IMAGE_MAP_PROJECTION + iString projName = ProjectionName (*inputLabel); + PvlTranslationManager xlatSpecProj(*inputLabel, + "$base/translations/pdsExport"+ projName+".trn"); + xlatSpecProj.Auto(outputPvl); + + // Translate the target name + PvlTranslationManager xlatTarget(*inputLabel, + "$base/translations/pdsExportTarget.trn"); + xlatTarget.Auto(outputPvl); + + // Add keywords to the PDS labels that could not be handled automatically + PvlObject &pdsMapObj = outputPvl.FindObject("IMAGE_MAP_PROJECTION"); + + // Add the projection name +// pdsMapObj += PvlKeyword ("MAP_PROJECTION_TYPE", projName.UpCase()); + + // Modify the radii to be km + PvlKeyword &aRadius = pdsMapObj["A_AXIS_RADIUS"]; + iString unit = aRadius.Unit(); + if (unit.UpCase() == "METERS") { + aRadius.SetValue((double)aRadius/1000.0, "KM"); + } + PvlKeyword &bRadius = pdsMapObj["B_AXIS_RADIUS"]; + unit = bRadius.Unit(); + if (unit.UpCase() == "METERS") { + bRadius.SetValue((double)bRadius/1000.0, "KM"); + } + PvlKeyword &cRadius = pdsMapObj["C_AXIS_RADIUS"]; + unit = cRadius.Unit(); + if (unit.UpCase() == "METERS") { + cRadius.SetValue((double)cRadius/1000.0, "KM"); + } + + // Modify the units on MAP_SCALE and MAP_RESOLUTION + PvlKeyword &mapScale = pdsMapObj["MAP_SCALE"]; + unit = mapScale.Unit(); + if ((unit.UpCase() == "METERS/PIX") || (unit.UpCase() == "METERS/PIXEL")) { + if (meResolution == Kilometer) { + mapScale.SetValue((double)mapScale/1000.0, "KM/PIXEL"); + } + else { + mapScale.SetValue((double)mapScale, "METERS/PIXEL"); + } + } + PvlKeyword &mapRes = pdsMapObj["MAP_RESOLUTION"]; + unit = mapRes.Unit(); + if (unit.UpCase() == "PIXELS/DEGREE") { + mapRes.SetValue((string)mapRes, "PIX/DEG"); + } + + + // Add the EASTERNMOST AND WESTERNMOST LONGITUDE keywords + PvlKeyword &isisLonDir = inputMapping.FindKeyword("LongitudeDirection"); + iString lonDir = isisLonDir[0]; + lonDir.UpCase(); + if (lonDir == "POSITIVEEAST") { + double maxLon = inputMapping.FindKeyword("MaximumLongitude"); + pdsMapObj += PvlKeyword("EASTERNMOST_LONGITUDE", maxLon); + double minLon = inputMapping.FindKeyword("MinimumLongitude"); + pdsMapObj += PvlKeyword("WESTERNMOST_LONGITUDE", minLon); + } + else { + double minLon = inputMapping.FindKeyword("MinimumLongitude"); + pdsMapObj += PvlKeyword("EASTERNMOST_LONGITUDE", minLon); + double maxLon = inputMapping.FindKeyword("MaximumLongitude"); + pdsMapObj += PvlKeyword("WESTERNMOST_LONGITUDE", maxLon); + } + + // Add the LINE_PROJECTION_OFFSET and SAMPLE_PROJECTION_OFFSET keywords + // These keywords are the distance from the origin of the image to the + // origin of the projection. The units are line or samples. The image origin + // is the middle of pixel (1,1) + double lineOffset = inputMapping.FindKeyword("UpperLeftCornerY"); + lineOffset /= (double)inputMapping.FindKeyword("PixelResolution"); + lineOffset *= 1.0; + lineOffset += 0.5; // Add half a line to get to the center of (1,1) + pdsMapObj += PvlKeyword("LINE_PROJECTION_OFFSET", lineOffset,"PIXEL"); + double sampleOffset = inputMapping.FindKeyword("UpperLeftCornerX"); + sampleOffset /= (double)inputMapping.FindKeyword("PixelResolution"); + sampleOffset *= -1.0; + sampleOffset += 0.5; // Add half a sample to get to the center of (1,1) + pdsMapObj += PvlKeyword("SAMPLE_PROJECTION_OFFSET", sampleOffset,"PIXEL"); + + // Add units to keywords already in the IMAGE_MAP_PROJECTION object as necessary + if (pdsMapObj.HasKeyword("CENTER_LATITUDE")) { + PvlKeyword &tempKey = pdsMapObj.FindKeyword("CENTER_LATITUDE"); + tempKey.SetValue(tempKey[0], "DEG"); + } + if (pdsMapObj.HasKeyword("CENTER_LONGITUDE")) { + PvlKeyword &tempKey = pdsMapObj.FindKeyword("CENTER_LONGITUDE"); + tempKey.SetValue(tempKey[0], "DEG"); + } +// if (pdsMapObj.HasKeyword("REFERENCE_LATITUDE")) { +// PvlKeyword &tempKey = pdsMapObj.FindKeyword("REFERENCE_LATITUDE"); +// tempKey.SetValue(tempKey[0], "DEG"); +// } + if (pdsMapObj.HasKeyword("REFERENCE_LONGITUDE")) { + PvlKeyword &tempKey = pdsMapObj.FindKeyword("REFERENCE_LONGITUDE"); + tempKey.SetValue(tempKey[0], "DEG"); + } + if (pdsMapObj.HasKeyword("MAXIMUM_LATITUDE")) { + PvlKeyword &tempKey = pdsMapObj.FindKeyword("MAXIMUM_LATITUDE"); + tempKey.SetValue(tempKey[0], "DEG"); + } + if (pdsMapObj.HasKeyword("MINIMUM_LATITUDE")) { + PvlKeyword &tempKey = pdsMapObj.FindKeyword("MINIMUM_LATITUDE"); + tempKey.SetValue(tempKey[0], "DEG"); + } + if (pdsMapObj.HasKeyword("EASTERNMOST_LONGITUDE")) { + PvlKeyword &tempKey = pdsMapObj.FindKeyword("EASTERNMOST_LONGITUDE"); + tempKey.SetValue(tempKey[0], "DEG"); + } + if (pdsMapObj.HasKeyword("WESTERNMOST_LONGITUDE")) { + PvlKeyword &tempKey = pdsMapObj.FindKeyword("WESTERNMOST_LONGITUDE"); + tempKey.SetValue(tempKey[0], "DEG"); + } + if (pdsMapObj.HasKeyword("MAP_PROJECTION_ROTATION")) { + PvlKeyword &tempKey = pdsMapObj.FindKeyword("MAP_PROJECTION_ROTATION"); + tempKey.SetValue(tempKey[0], "DEG"); + } + + } + + + /** + * Return a projection name + */ + string ProcessExportPds::ProjectionName(Pvl &inputLabel) { + Projection *proj = ProjectionFactory::Create(inputLabel); + string name = proj->Name(); + delete proj; + return name; + } + + + /** + * Return the line bytes (record size) for the input cube, at present this is + * based on the number of samples and the bytes per pixel. + */ + int ProcessExportPds::LineBytes(){ + Cube *cube = InputCubes[0]; + int a = SizeOf(p_pixelType); + int b = cube->Samples(); + return b * a ; + } + + + /** + * Return the size of the output PDS label. + */ + int ProcessExportPds::LabelSize(){ + ostringstream temp; + if( p_label->GetFormat() != NULL ) { + temp << *p_label << p_label->GetFormat()->FormatEOL(); + } + else { + temp << *p_label << endl; + } + return temp.tellp(); + } + + void ProcessExportPds::OutputDetatchedLabel(void) + { + std::ofstream sOutLabelStream(msLabelFile.c_str()); + OutputLabel(sOutLabelStream); + sOutLabelStream.close(); + } + + /** + * Write the PDS label to the supplied stream. The PDS keywords that have place + * holder "?" for their values (such as LABEL_RECORDS and ^IMAGE) will + * be updated to their correct values before they are written. + */ + void ProcessExportPds::OutputLabel(std::ofstream &os) { + int labSize = LabelSize(); // labSize will be the old label size with "?" + // NOTE: WARNING: If anything changes in the next two lines, you must also changes the + // corresponding lines in the StandardImageRoot member + if ( p_exportType == Stream ) { + if (p_pdsFileType != ProcessExportPds::JP2Image) { + (*p_label)["LABEL_RECORDS"].SetValue(iString(labSize), "BYTES"); + if (!p_detachedLabel) { + (*p_label)["^IMAGE"].SetValue(iString(labSize+1), "BYTES"); + } + } + if( p_label->GetFormat() != NULL ) { + os << *p_label << p_label->GetFormat()->FormatEOL(); + } + else { + os << *p_label << endl; + } + // Fill the difference between the old and new label size with nulls. + if (p_pdsFileType != ProcessExportPds::JP2Image) { + for (int i=LabelSize(); iHasKeyword("LABEL_RECORDS")) {//LRO MRF doesn't have this keyword + (*p_label)["LABEL_RECORDS"].SetValue( iString(labelRecords) ); + } + (*p_label)["FILE_RECORDS"].SetValue( iString(labelRecords + (InputCubes[0])->Lines() * + InputCubes[0]->Bands()) ); + if (!p_detachedLabel) { + (*p_label)["^IMAGE"].SetValue( iString(labelRecords+1) ); + } + } + if( p_label->GetFormat() != NULL ) { + os << *p_label << p_label->GetFormat()->FormatEOL(); + } + else { + os << *p_label << endl; + } + if (p_pdsFileType != ProcessExportPds::JP2Image) { + for (int i=LabelSize(); i +#include "Preference.h" + +using namespace std; + +int main(){ + Isis::Preference::Preferences(true); + + cout << "Testing Isis::ProcessExportPds ..." < &lat, + std::vector &lon, + std::vector &values) { + Convert(lat, lon); + ProcessPolygons::Rasterize(p_samples, p_lines, values); + + } + + /** + * This method gets called from the application with the lat/lon + * verticies of a polygon along with the band number and the + * value for the polygon. + * + * @param lat + * @param lon + * @param band + * @param value + */ + void ProcessGroundPolygons::Rasterize (std::vector &lat, + std::vector &lon, + int &band, double &value) { + + Convert(lat, lon); + ProcessPolygons::Rasterize(p_samples, p_lines, band, value); + + } + + void ProcessGroundPolygons::Rasterize (double &lat, double &lon, + int &band, double &value) { + + Convert(lat, lon); + ProcessPolygons::Rasterize(p_samples, p_lines, band, value); + + } + + /** + * Converts lat/long to line/sample using the universal ground + * map object. + * + * @param lat + * @param lon + */ + void ProcessGroundPolygons::Convert(std::vector &lat, + std::vector &lon){ + + p_samples.clear(); + p_lines.clear(); + double sample = 1; + double line = 1; + //double midSample, midLine; + for(unsigned int i = 0; iProcessPolygons::SetOutputCube(avgFilename, countFilename, atts, + samples, lines, bands); + + /*Write the pvl group to the cube files.*/ + + PvlGroup group = map.FindGroup("Mapping", Pvl::Traverse); + + OutputCubes[0]->PutGroup(group); + OutputCubes[1]->PutGroup(group); + + /*We need a ground map for converting lat/long to line/sample see Convert()*/ + p_groundMap = new UniversalGroundMap(*OutputCubes[0]->Label()); + + delete proj; + } + + +} /* end namespace isis*/ + diff --git a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.h b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.h new file mode 100644 index 0000000000000000000000000000000000000000..c559c366d23821efd6324572736c4d00ccbbaadb --- /dev/null +++ b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.h @@ -0,0 +1,69 @@ +#ifndef ProcessGroundPolygons_h +#define ProcessGroundPolygons_h + +#include "ProjectionFactory.h" +#include "Process.h" +#include "Brick.h" +#include "Filename.h" +#include "ProcessPolygons.h" +#include "UniversalGroundMap.h" + +namespace Isis { + /** + * @brief Process cube polygons to map or camera projections + * + * This class allows a programmer to develop a program which + * @ingroup HighLevelCubeIO + * + * @author 2008-12-14 Stacy Alley + * + * @internal + * @history 2008-05-12 Steven Lambright - Removed references to CubeInfo + * @history 2008-08-18 Steven Lambright - Updated to work with geos3.0.0 + * instead of geos2. Mostly namespace changes. + */ + class ProcessGroundPolygons : public ProcessPolygons { + public: + ProcessGroundPolygons(); + + //Cube is an existing camera cube or projection cube + void SetOutputCube (const std::string ¶meter, std::string &cube); + + //Determine cube size from the projection map + void SetOutputCube (const std::string ¶meter,Isis::Pvl &map, int bands); + + void SetOutputCube(const std::string &avgFilename, const std::string + &countFilename, Isis::CubeAttributeOutput &atts, + std::string &cube); + + void SetOutputCube(const std::string &avgFilename, const std::string + &countFilename, Isis::CubeAttributeOutput &atts, + Isis::Pvl &map, int bands); + + void AppendOutputCube(std::string &cube, const std::string &avgFilename, + const std::string &countFilename=""); + + void Rasterize (std::vector &lat, + std::vector &lon, + std::vector &values); + + void Rasterize (std::vector &lat, + std::vector &lon, + int &band, double &value); + + void Rasterize (double &lat, double &lon,int &band, double &value); + + void EndProcess(); + UniversalGroundMap *GetUniversalGroundMap(){ return p_groundMap;}; + + private: + void Convert(std::vector &lat, std::vector &lon); + void Convert(double &lat, double &lon); + UniversalGroundMap *p_groundMap; + std::vector p_samples, p_lines; + + }; + +}; + +#endif diff --git a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.truth b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.truth new file mode 100644 index 0000000000000000000000000000000000000000..f34638eef5d30c2fbf604d3dd88c31326a78a5fc --- /dev/null +++ b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.truth @@ -0,0 +1,77 @@ +Testing Isis::ProcessGroundPolygons Class ... +unittest: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +unittest: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +unittest: Working +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +File Name: ProcessGroundPolygonsTest.cub +unittest: Working +0% Processed Band: 1 DN: 0.0692156 Band: 1 DN: 0.0692156 Band: 1 DN: 0.0715228 Band: 1 DN: 0.0715228 Band: 1 DN: 0.0715228 Band: 1 DN: 0.0726764 +Band: 1 DN: 0.0726764 Band: 1 DN: 0.0726764 Band: 1 DN: 0.0715228 Band: 1 DN: 0.0715228 Band: 1 DN: 0.0719842 Band: 1 DN: 0.0719842 Band: 1 DN: 0.0719842 Band: 1 DN: 0.0726764 +Band: 1 DN: 0.0726764 Band: 1 DN: 0.0726764 Band: 1 DN: 0.0719842 Band: 1 DN: 0.0719842 Band: 1 DN: 0.0720996 Band: 1 DN: 0.0715228 Band: 1 DN: 0.0715228 Band: 1 DN: 0.0715228 +Band: 1 DN: 0.0715228 Band: 1 DN: 0.0715228 Band: 1 DN: 0.0719842 Band: 1 DN: 0.0726764 Band: 1 DN: 0.0726764 Band: 1 DN: 0.0732532 Band: 1 DN: 0.0732532 Band: 1 DN: 0.0726764 +10% Processed Band: 1 DN: 0.0715228 Band: 1 DN: 0.070946 Band: 1 DN: 0.0712921 Band: 1 DN: 0.072182 Band: 1 DN: 0.072182 Band: 1 DN: 0.0732532 Band: 1 DN: 0.0732532 Band: 1 DN: 0.0726764 +Band: 1 DN: 0.070946 Band: 1 DN: 0.070946 Band: 1 DN: 0.070946 Band: 1 DN: 0.072182 Band: 1 DN: 0.072182 Band: 1 DN: 0.07383 Band: 1 DN: 0.07383 Band: 1 DN: 0.07383 +Band: 1 DN: 0.0692156 Band: 1 DN: 0.070946 Band: 1 DN: 0.070946 Band: 1 DN: 0.0711932 Band: 1 DN: 0.0711932 Band: 1 DN: 0.0715228 Band: 1 DN: 0.0715228 Band: 1 DN: 0.070946 +20% Processed Band: 1 DN: 0.0718112 Band: 1 DN: 0.0718112 Band: 1 DN: 0.072182 Band: 1 DN: 0.072182 Band: 1 DN: 0.0715228 Band: 1 DN: 0.0715228 Band: 1 DN: 0.0712921 +Band: 1 DN: 0.0718112 Band: 1 DN: 0.0718112 Band: 1 DN: 0.0716876 Band: 1 DN: 0.0716876 Band: 1 DN: 0.06971 Band: 1 DN: 0.0697924 Band: 1 DN: 0.0697924 +Band: 1 DN: 0.070946 Band: 1 DN: 0.070946 Band: 1 DN: 0.072182 Band: 1 DN: 0.072182 Band: 1 DN: 0.070946 Band: 1 DN: 0.0715228 Band: 1 DN: 0.0715228 +30% Processed Band: 1 DN: 0.070946 Band: 1 DN: 0.070946 Band: 1 DN: 0.0716876 Band: 1 DN: 0.0716876 Band: 1 DN: 0.0696001 Band: 1 DN: 0.0692156 Band: 1 DN: 0.0692156 +Band: 1 DN: 0.0700808 Band: 1 DN: 0.0700808 Band: 1 DN: 0.0711932 Band: 1 DN: 0.0711932 Band: 1 DN: 0.0699847 Band: 1 DN: 0.0699078 Band: 1 DN: 0.0699078 +Band: 1 DN: 0.0700808 Band: 1 DN: 0.0700808 Band: 1 DN: 0.0703692 Band: 1 DN: 0.0703692 Band: 1 DN: 0.0687212 Band: 1 DN: 0.0669084 Band: 1 DN: 0.0669084 +40% Processed Band: 1 DN: 0.0703692 Band: 1 DN: 0.0703692 Band: 1 DN: 0.0705999 Band: 1 DN: 0.0705999 Band: 1 DN: 0.0705999 Band: 1 DN: 0.070946 Band: 1 DN: 0.070946 +Band: 1 DN: 0.0692156 Band: 1 DN: 0.0692156 Band: 1 DN: 0.0692156 Band: 1 DN: 0.0692156 Band: 1 DN: 0.0692156 Band: 1 DN: 0.0692156 Band: 1 DN: 0.0692156 +Band: 1 DN: 0.0692156 Band: 1 DN: 0.0692156 Band: 1 DN: 0.0692156 Band: 1 DN: 0.0692156 Band: 1 DN: 0.0692156 +50% Processed Band: 2 DN: 0.126674 Band: 2 DN: 0.126674 Band: 2 DN: 0.114 Band: 2 DN: 0.114 Band: 2 DN: 0.114 Band: 2 DN: 0.107663 +Band: 2 DN: 0.126674 Band: 2 DN: 0.126674 Band: 2 DN: 0.11475 Band: 2 DN: 0.11475 Band: 2 DN: 0.111915 Band: 2 DN: 0.104761 Band: 2 DN: 0.104761 Band: 2 DN: 0.102076 +Band: 2 DN: 0.105757 Band: 2 DN: 0.105757 Band: 2 DN: 0.10218 Band: 2 DN: 0.10218 Band: 2 DN: 0.100805 Band: 2 DN: 0.0953482 Band: 2 DN: 0.0953482 Band: 2 DN: 0.0909011 +Band: 2 DN: 0.0997953 Band: 2 DN: 0.0997953 Band: 2 DN: 0.0944196 Band: 2 DN: 0.0933281 Band: 2 DN: 0.0933281 Band: 2 DN: 0.088881 Band: 2 DN: 0.088881 Band: 2 DN: 0.0909011 +60% Processed Band: 2 DN: 0.0997953 Band: 2 DN: 0.0960567 Band: 2 DN: 0.0932076 Band: 2 DN: 0.0916828 Band: 2 DN: 0.0916828 Band: 2 DN: 0.087366 Band: 2 DN: 0.087366 Band: 2 DN: 0.088881 +Band: 2 DN: 0.086356 Band: 2 DN: 0.0855985 Band: 2 DN: 0.0855985 Band: 2 DN: 0.0870053 Band: 2 DN: 0.0870053 Band: 2 DN: 0.089386 Band: 2 DN: 0.089386 Band: 2 DN: 0.089891 +Band: 2 DN: 0.087871 Band: 2 DN: 0.0855985 Band: 2 DN: 0.0855985 Band: 2 DN: 0.0870053 Band: 2 DN: 0.0870053 Band: 2 DN: 0.088376 Band: 2 DN: 0.088376 Band: 2 DN: 0.087871 +70% Processed Band: 2 DN: 0.0855985 Band: 2 DN: 0.0855985 Band: 2 DN: 0.0865724 Band: 2 DN: 0.0865724 Band: 2 DN: 0.087366 Band: 2 DN: 0.087366 Band: 2 DN: 0.086659 +Band: 2 DN: 0.086356 Band: 2 DN: 0.086356 Band: 2 DN: 0.0870053 Band: 2 DN: 0.0870053 Band: 2 DN: 0.0870053 Band: 2 DN: 0.086861 Band: 2 DN: 0.086861 +Band: 2 DN: 0.086356 Band: 2 DN: 0.086356 Band: 2 DN: 0.0870053 Band: 2 DN: 0.0870053 Band: 2 DN: 0.0867348 Band: 2 DN: 0.086861 Band: 2 DN: 0.086861 +80% Processed Band: 2 DN: 0.0871135 Band: 2 DN: 0.0871135 Band: 2 DN: 0.0874382 Band: 2 DN: 0.0874382 Band: 2 DN: 0.0875343 Band: 2 DN: 0.087871 Band: 2 DN: 0.087871 +Band: 2 DN: 0.086356 Band: 2 DN: 0.086356 Band: 2 DN: 0.0865724 Band: 2 DN: 0.0865724 Band: 2 DN: 0.086861 Band: 2 DN: 0.087265 Band: 2 DN: 0.087265 +Band: 2 DN: 0.0855985 Band: 2 DN: 0.0855985 Band: 2 DN: 0.085851 Band: 2 DN: 0.085851 Band: 2 DN: 0.0861396 Band: 2 DN: 0.086861 Band: 2 DN: 0.086861 +90% Processed Band: 2 DN: 0.085851 Band: 2 DN: 0.085851 Band: 2 DN: 0.086053 Band: 2 DN: 0.086053 Band: 2 DN: 0.086053 Band: 2 DN: 0.086356 Band: 2 DN: 0.086356 +Band: 2 DN: 0.084841 Band: 2 DN: 0.084841 Band: 2 DN: 0.085851 Band: 2 DN: 0.085851 Band: 2 DN: 0.085851 Band: 2 DN: 0.087871 Band: 2 DN: 0.087871 +Band: 2 DN: 0.084841 Band: 2 DN: 0.084841 Band: 2 DN: 0.084841 Band: 2 DN: 0.084841 Band: 2 DN: 0.084841 +100% Processed +File Name: ProcessGroundPolygonsTest_count.cub +unittest: Working +0% Processed Band: 1 DN: 1 Band: 1 DN: 1 Band: 1 DN: 3 Band: 1 DN: 3 Band: 1 DN: 3 Band: 1 DN: 2 +Band: 1 DN: 1 Band: 1 DN: 1 Band: 1 DN: 3 Band: 1 DN: 3 Band: 1 DN: 5 Band: 1 DN: 5 Band: 1 DN: 5 Band: 1 DN: 3 +Band: 1 DN: 2 Band: 1 DN: 2 Band: 1 DN: 5 Band: 1 DN: 5 Band: 1 DN: 6 Band: 1 DN: 6 Band: 1 DN: 6 Band: 1 DN: 3 +Band: 1 DN: 3 Band: 1 DN: 3 Band: 1 DN: 5 Band: 1 DN: 6 Band: 1 DN: 6 Band: 1 DN: 6 Band: 1 DN: 6 Band: 1 DN: 3 +10% Processed Band: 1 DN: 3 Band: 1 DN: 4 Band: 1 DN: 5 Band: 1 DN: 7 Band: 1 DN: 7 Band: 1 DN: 6 Band: 1 DN: 6 Band: 1 DN: 3 +Band: 1 DN: 2 Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 7 Band: 1 DN: 7 Band: 1 DN: 6 Band: 1 DN: 6 Band: 1 DN: 3 +Band: 1 DN: 1 Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 7 Band: 1 DN: 7 Band: 1 DN: 6 Band: 1 DN: 6 Band: 1 DN: 4 +20% Processed Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 7 Band: 1 DN: 7 Band: 1 DN: 6 Band: 1 DN: 6 Band: 1 DN: 5 +Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 7 Band: 1 DN: 7 Band: 1 DN: 7 Band: 1 DN: 6 Band: 1 DN: 6 +Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 7 Band: 1 DN: 7 Band: 1 DN: 8 Band: 1 DN: 6 Band: 1 DN: 6 +30% Processed Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 7 Band: 1 DN: 7 Band: 1 DN: 9 Band: 1 DN: 6 Band: 1 DN: 6 +Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 7 Band: 1 DN: 7 Band: 1 DN: 9 Band: 1 DN: 5 Band: 1 DN: 5 +Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 6 Band: 1 DN: 6 Band: 1 DN: 7 Band: 1 DN: 3 Band: 1 DN: 3 +40% Processed Band: 1 DN: 3 Band: 1 DN: 3 Band: 1 DN: 5 Band: 1 DN: 5 Band: 1 DN: 5 Band: 1 DN: 2 Band: 1 DN: 2 +Band: 1 DN: 2 Band: 1 DN: 2 Band: 1 DN: 3 Band: 1 DN: 3 Band: 1 DN: 3 Band: 1 DN: 1 Band: 1 DN: 1 +Band: 1 DN: 1 Band: 1 DN: 1 Band: 1 DN: 1 Band: 1 DN: 1 Band: 1 DN: 1 +50% Processed Band: 2 DN: 1 Band: 2 DN: 1 Band: 2 DN: 3 Band: 2 DN: 3 Band: 2 DN: 3 Band: 2 DN: 2 +Band: 2 DN: 1 Band: 2 DN: 1 Band: 2 DN: 3 Band: 2 DN: 3 Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 3 +Band: 2 DN: 2 Band: 2 DN: 2 Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 6 Band: 2 DN: 6 Band: 2 DN: 6 Band: 2 DN: 3 +Band: 2 DN: 3 Band: 2 DN: 3 Band: 2 DN: 5 Band: 2 DN: 6 Band: 2 DN: 6 Band: 2 DN: 6 Band: 2 DN: 6 Band: 2 DN: 3 +60% Processed Band: 2 DN: 3 Band: 2 DN: 4 Band: 2 DN: 5 Band: 2 DN: 7 Band: 2 DN: 7 Band: 2 DN: 6 Band: 2 DN: 6 Band: 2 DN: 3 +Band: 2 DN: 2 Band: 2 DN: 4 Band: 2 DN: 4 Band: 2 DN: 7 Band: 2 DN: 7 Band: 2 DN: 6 Band: 2 DN: 6 Band: 2 DN: 3 +Band: 2 DN: 1 Band: 2 DN: 4 Band: 2 DN: 4 Band: 2 DN: 7 Band: 2 DN: 7 Band: 2 DN: 6 Band: 2 DN: 6 Band: 2 DN: 4 +70% Processed Band: 2 DN: 4 Band: 2 DN: 4 Band: 2 DN: 7 Band: 2 DN: 7 Band: 2 DN: 6 Band: 2 DN: 6 Band: 2 DN: 5 +Band: 2 DN: 4 Band: 2 DN: 4 Band: 2 DN: 7 Band: 2 DN: 7 Band: 2 DN: 7 Band: 2 DN: 6 Band: 2 DN: 6 +Band: 2 DN: 4 Band: 2 DN: 4 Band: 2 DN: 7 Band: 2 DN: 7 Band: 2 DN: 8 Band: 2 DN: 6 Band: 2 DN: 6 +80% Processed Band: 2 DN: 4 Band: 2 DN: 4 Band: 2 DN: 7 Band: 2 DN: 7 Band: 2 DN: 9 Band: 2 DN: 6 Band: 2 DN: 6 +Band: 2 DN: 4 Band: 2 DN: 4 Band: 2 DN: 7 Band: 2 DN: 7 Band: 2 DN: 9 Band: 2 DN: 5 Band: 2 DN: 5 +Band: 2 DN: 4 Band: 2 DN: 4 Band: 2 DN: 6 Band: 2 DN: 6 Band: 2 DN: 7 Band: 2 DN: 3 Band: 2 DN: 3 +90% Processed Band: 2 DN: 3 Band: 2 DN: 3 Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 2 Band: 2 DN: 2 +Band: 2 DN: 2 Band: 2 DN: 2 Band: 2 DN: 3 Band: 2 DN: 3 Band: 2 DN: 3 Band: 2 DN: 1 Band: 2 DN: 1 +Band: 2 DN: 1 Band: 2 DN: 1 Band: 2 DN: 1 Band: 2 DN: 1 Band: 2 DN: 1 +100% Processed diff --git a/isis/src/base/objs/ProcessGroundPolygons/unitTest.cpp b/isis/src/base/objs/ProcessGroundPolygons/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..156828b81e80990cd18c8b78b1234e365b69a143 --- /dev/null +++ b/isis/src/base/objs/ProcessGroundPolygons/unitTest.cpp @@ -0,0 +1,195 @@ +#include "Isis.h" +#include "ProcessGroundPolygons.h" +#include "ProcessByLine.h" +#include "ProcessByBrick.h" +#include "SpecialPixel.h" +#include "TextFile.h" + +using namespace Isis; +using namespace std; + +void writeAscii(Isis::Buffer &in); +void readValues(Isis::Buffer &in); + +std::vectorlat, lon, values, vimsValues; + +void IsisMain() { + + PvlGroup mapping("Mapping"); + { + mapping += PvlKeyword("ProjectionName","SimpleCylindrical"); + mapping += PvlKeyword("CenterLongitude","227.83197474005"); + mapping += PvlKeyword("TargetName","Mars"); + mapping += PvlKeyword("EquatorialRadius", "3396190.0"); + mapping += PvlKeyword("PolarRadius","3376200.0"); + mapping += PvlKeyword("LatitudeType","Planetocentric"); + mapping += PvlKeyword("LongitudeDirection","PositiveEast"); + mapping += PvlKeyword("LongitudeDomain","360"); + mapping += PvlKeyword("MinimumLatitude","10.786871290848"); + mapping += PvlKeyword("MaximumLatitude","34.44480953463"); + mapping += PvlKeyword("MinimumLongitude", "219.70338590854"); + mapping += PvlKeyword("MaximumLongitude","235.96056357156"); + mapping += PvlKeyword("UpperLeftCornerX","-483000.0"); + mapping += PvlKeyword("UpperLeftCornerY","2043000.0 "); + mapping += PvlKeyword("PixelResolution","1000.0"); + mapping += PvlKeyword("Scale","59.274697523306"); + } + + Pvl pvl; + pvl.AddGroup(mapping); + + PvlGroup vimsMapping("Mapping"); + { + vimsMapping += PvlKeyword("ProjectionName","Sinusoidal"); + vimsMapping += PvlKeyword("CenterLongitude","308.47990638953"); + vimsMapping += PvlKeyword("TargetName","TITAN"); + vimsMapping += PvlKeyword("EquatorialRadius", "2575000.0"); + vimsMapping += PvlKeyword("PolarRadius","575000.0"); + vimsMapping += PvlKeyword("LatitudeType","Planetocentric"); + vimsMapping += PvlKeyword("LongitudeDirection","PositiveEast"); + vimsMapping += PvlKeyword("LongitudeDomain","360"); + + vimsMapping += PvlKeyword("MinimumLatitude","9.916425315167"); + vimsMapping += PvlKeyword("MaximumLatitude","10.087679837429"); + vimsMapping += PvlKeyword("MinimumLongitude", "308.42684479508"); + vimsMapping += PvlKeyword("MaximumLongitude","308.53296798387"); + + vimsMapping += PvlKeyword("PixelResolution","498.46721637851"); + vimsMapping += PvlKeyword("Scale","90.160850627992"); + } + + cout << "Testing Isis::ProcessGroundPolygons Class ... " << endl; + + ProcessGroundPolygons p; + ProcessByLine pbl; + CubeAttributeInput atts0; + + QStringList vimsCube; + vimsCube << "$Cassini/testData/CM_1540484927_1_001.ir.cub" + << "$Cassini/testData/CM_1540484927_1_002.ir.cub" + << "$Cassini/testData/CM_1540484927_1_003.ir.cub"; + + std::vector vimsSamps, vimsLines, vect; + Pvl vimsPvl; + vimsPvl.AddGroup(vimsMapping); + + CubeAttributeOutput out_atts; + out_atts.PixelType(Real); + + const string output1 = "ProcessGroundPolygonsTest.cub"; + const string output2 = "ProcessGroundPolygonsTest_count.cub"; + + p.SetOutputCube(output1 , output2 , out_atts, vimsPvl, 2); + + for (int f = 0; fSetImage(vimsSamps[j], vimsLines[j])) { + latitude = groundMap->UniversalLatitude(); + longitude = groundMap->UniversalLongitude(); + lat.push_back(latitude); + lon.push_back(longitude); + } + + } + + if (lat.size() > 3) { + p.Rasterize(lat, lon, b, vimsValues[i]); + } + + lat.clear(); + lon.clear(); + vimsSamps.clear(); + vimsLines.clear(); + i++; + + }//end for each s -- sample + }// end for each l -- line + }//end for each b -- band + + delete groundMap; + + } //end for each vims file. + + p.EndProcess(); + + /* Write out the data */ + + CubeAttributeInput atts; + + std::cout << "File Name: " << output1 << std::endl; + pbl.SetInputCube(output1, atts, 0); + pbl.StartProcess(writeAscii); + pbl.EndProcess(); + + std::cout << "File Name: " << output2 << std::endl; + pbl.SetInputCube(output2, atts, 0); + pbl.StartProcess(writeAscii); + pbl.EndProcess(); + + remove(output1.c_str()); + remove(output2.c_str()); + + +} + +/** + * This method reads in the cube file line by line and prints + * out the DN value of each non-null pixel. + * + * @param in + */ +void writeAscii (Isis::Buffer &in) { + bool notNull= false; + int index = in.size() - 1; + for (int i=0; i 0) { + cout <<"Band: " << in.Band() << " DN: " << in[index -i] << " "; + notNull = true; + } + } + if(notNull) { + cout << std::endl; + } + +} + +void readValues (Isis::Buffer &in) { + //int index = in.size() - 1; + + for (int i=0; i + + + Unit test for Isis::ProcessGroundPolygons class + + + Just a test only a test + + + Scripting + + + + Original Version + + + diff --git a/isis/src/base/objs/ProcessImport/Makefile b/isis/src/base/objs/ProcessImport/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5052f936ea326fad68886550d4b47b477be63a11 --- /dev/null +++ b/isis/src/base/objs/ProcessImport/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessImport.h +SRCS = ProcessImport.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessImport/ProcessImport.cpp b/isis/src/base/objs/ProcessImport/ProcessImport.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dcea5071520a29adfafe2c3702804af901621c25 --- /dev/null +++ b/isis/src/base/objs/ProcessImport/ProcessImport.cpp @@ -0,0 +1,1935 @@ +/** + * @file + * $Revision: 1.13 $ + * $Date: 2010/02/22 02:24:59 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include + +#include "Preference.h" +#include "Brick.h" +#include "ProcessImport.h" +#include "iException.h" +#include "LineManager.h" +#include "Pvl.h" +#include "PvlTokenizer.h" +#include "PixelType.h" +#include "SpecialPixel.h" +#include "iString.h" +#include "PixelType.h" +#include "Application.h" +#include "JP2Decoder.h" + +using namespace std; +namespace Isis { + + //! Constructs an Import object. + ProcessImport::ProcessImport () : Isis::Process() { + + p_progress->SetText ("Importing"); + + // Initialize input file information + p_inFile = ""; + p_pixelType = Isis::None; + p_ns = p_nl = p_nb = 0; + p_byteOrder = Isis::NoByteOrder; + p_fileHeaderBytes = 0; + p_dataHeaderBytes = 0; + p_dataTrailerBytes = 0; + p_dataPreBytes = 0; + p_dataPostBytes = 0; + p_organization = ProcessImport::BSQ; + p_base.push_back(0.0); + p_mult.push_back(1.0); + // Make all special pixels invalid + SetNull(DBL_MAX,-DBL_MAX); + SetHRS(DBL_MAX,-DBL_MAX); + SetLRS(DBL_MAX,-DBL_MAX); + SetHIS(DBL_MAX,-DBL_MAX); + SetLIS(DBL_MAX,-DBL_MAX); + + p_saveFileHeader = false; + p_saveDataHeader = false; + p_saveDataTrailer = false; + p_saveDataPre = false; + p_saveDataPost = false; + p_saveFileTrailer = false; + + p_fileHeader = NULL; + p_fileTrailer = NULL; + } + + //! Destroys the Import object + ProcessImport::~ProcessImport () { + if (p_fileHeader) { + delete [] p_fileHeader; + p_fileHeader = NULL; + } + + for (unsigned int i=0; i temp; + for (unsigned int j=0; j 0 && nl >0 && nb>0) { + p_ns = ns; + p_nl = nl; + p_nb = nb; + } + else { + string msg = "Illegal dimension [" + Isis::iString(ns) + ", " + + Isis::iString(nl) + ", " + Isis::iString(nb) + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + }; + + /** + * Sets the byte order of the input file. This must be invoked prior to + * SetOutputCube. + * + * @param order The enumerated byte order Isis::Lsb or Isis::Msb + */ + void ProcessImport::SetByteOrder (const Isis::ByteOrder order) { + p_byteOrder = order; + }; + + /** + * This method sets the number of bytes in the header of a file. + * The file header is a block of non-image data at the beginning + * of the entire file. This does not include any section + * headers, such as band headers or line prefixes. Typically it + * is used to delineate the boundary of the binary or ascii + * labels. It must be called before StartProcess(). This data + * will only be available if saved via SaveFileHeader() and may + * be accessed via FileHeader() after StartProcess() has + * returned and before EndProcess() is called. If not invoked + * the default is 0. + * + * @param bytes Number of bytes + * + * @throws Isis::iException::Message "Illegal file header size." + * (when bytes < 0) + * @see SaveFileHeader() + * @see FileHeader() + * + */ + void ProcessImport::SetFileHeaderBytes (const int bytes) { + if (bytes >= 0) { + p_fileHeaderBytes = bytes; + } + else { + string msg = "Illegal file header size [" + Isis::iString(bytes) + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + }; + + /** + * This method sets the number of bytes in the trailer of a file. + * The trailer is a block of non-image data at the end of the + * entire file. This does not include any section trailers, + * such as band trailers or line suffixes. It must be called + * before StartProcess(). This data will only be available if + * saved via SaveFileTrailer() and may be accessed via + * FileTrailer() after StartProcess() has returned and before + * EndProcess() is called. If not invoked the default is 0. + * + * @param bytes Number of bytes + * + * @throws Isis::iException::Message "Illegal file trailer size." + * (when bytes < 0) + * @see SaveFileTrailer() + * @see FileTrailer() + * @history 2008-08-12 Jeannie Walldren, Method created + * + */ + void ProcessImport::SetFileTrailerBytes (const int bytes) { + if (bytes >= 0) { + p_fileTrailerBytes = bytes; + } + else { + string msg = "Illegal file trailer size [" + Isis::iString(bytes) + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + }; + + /** + * This method sets the number of bytes in the header of each + * datablock of a file. A data header is a block of non-image + * data at the beginning of each data block (for BSQ data blocks + * are bands). This is not included in the file header and does + * not include any record headers, such as line prefixes. It + * must be called before StartProcess(). This data will only be + * available if saved via SaveDataHeader() and may be accessed + * via DataHeader() after StartProcess() has returned and before + * EndProcess() is called. If not invoked the default is 0. + * + * @param bytes Number of bytes + * + * @throws Isis::iException::Message "Illegal data header size." + * (when bytes < 0) + * @see SaveDataHeader() + * @see DataHeader() + */ + void ProcessImport::SetDataHeaderBytes (const int bytes) { + if (bytes >= 0) { + p_dataHeaderBytes = bytes; + } + else { + string msg = "Illegal data header size [" + Isis::iString(bytes) + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + }; + + /** + * This method sets the number of bytes in the trailer of each + * datablock of a file. A data trailer is a block of non-image + * data at the end of each data block (for BSQ data blocks + * are bands). This is not included in the file trailer and + * does not include any record trailers, such as line suffixes. + * It must be called before StartProcess(). This data will only + * be available if saved via SaveDataTrailer() and may be + * accessed via DataTrailer() after StartProcess() has returned + * and before EndProcess() is called. If not invoked the default + * is 0. + * + * @param bytes Number of bytes + * + * @throws Isis::iException::Message "Illegal data trailer + * size." (when bytes < 0) + * @see SaveDataTrailer() + * @see DataTrailer() + */ + void ProcessImport::SetDataTrailerBytes (const int bytes) { + + if (bytes >= 0) { + p_dataTrailerBytes = bytes; + } + else { + string msg = "Illegal data trailer size [" + Isis::iString(bytes) + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + }; + + /** + * This method sets the number of bytes at the beginning of each + * data record of a file. A data prefix is a block of non-image + * data at the beginning of each data record (for BSQ data + * records are lines). This is not included in the file header + * or the data header. It must be called before StartProcess(). + * This data will only be available if saved via + * SaveDataPrefix() and may be accessed via DataPrefix() after + * StartProcess() has returned and before EndProcess() is + * called. If not invoked the default is 0. + * + * @param bytes Number of bytes + * + * @throws Isis::iException::Message "Illegal data prefix size." + * (when bytes < 0) + * @see SaveDataPrefix() + * @see DataPrefix() + */ + void ProcessImport::SetDataPrefixBytes (const int bytes) { + + if (bytes >= 0) { + p_dataPreBytes = bytes; + } + else { + string msg = "Illegal data prefix size [" + Isis::iString(bytes) + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + }; + + /** + * This method sets the number of bytes at the end of each + * data record of a file. A data suffix is a block of non-image + * data at the end of each data record (for BSQ data records are + * lines). This is not included in the file trailer or the data + * trailer. It must be called before StartProcess(). This data + * will only be available if saved via SaveDataSuffix() and may be + * accessed via DataSuffix() after StartProcess() has returned + * and before EndProcess() is called. If not invoked the default + * is 0. + * + * @param bytes Number of bytes + * + * @throws Isis::iException::Message "Illegal data suffix size." + * (when bytes < 0) + * @see SaveDataSuffix() + * @see DataSuffix() + */ + void ProcessImport::SetDataSuffixBytes (const int bytes) { + + if (bytes >= 0) { + p_dataPostBytes = bytes; + } + else { + string msg = "Illegal data suffix size [" + Isis::iString(bytes) + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + }; + + /** + * This method marks the file header to be saved. A file + * header is a block of non-image data at the beginning of the + * entire file. This does not include any section headers, such + * as band headers or line prefixes. The file header will be + * saved inside StartProcess(). It must be called after setting + * the size with SetFileHeaderBytes() and before StartProcess() + * is called. This data will only be available via FileHeader() + * after StartProcess() has returned and before EndProcess() is + * called. + * + * @throws Isis::iException::Message "File header bytes equals + * 0. There is nothing to save. Use + * SetFileHeaderBytes() first." + * @see SetFileHeaderBytes() + * @see FileHeader() + */ + void ProcessImport::SaveFileHeader () { + if (p_fileHeaderBytes == 0){ + iString msg = "File header bytes equals 0. There is nothing to save. Use SetFileHeaderBytes() first."; + throw iException::Message(iException::Programmer,msg.c_str(),_FILEINFO_); + } + p_saveFileHeader = true; + }; + + /** + * This method marks the file trailer to be saved. A file + * trailer is a block of non-image data at the end of the entire + * file. This does not include any section trailers, such as + * band trailers or line suffixes. The file trailer will be + * saved inside StartProcess(). It must be called after setting + * the size with SetFileTrailerBytes() and before StartProcess() + * is called. This data will only be available via FileTrailer() + * after StartProcess() has returned and before EndProcess() is + * called. + * + * @throws Isis::iException::Message "File trailer bytes equals + * 0. There is nothing to save. Use + * SetFileTrailerBytes() first." + * @see SetFileTrailerBytes() + * @see FileTrailer() + */ + void ProcessImport::SaveFileTrailer () { + if (p_fileTrailerBytes == 0){ + iString msg = "File trailer bytes equals 0. There is nothing to save. Use SetFileTrailerBytes() first."; + throw iException::Message(iException::Programmer,msg.c_str(),_FILEINFO_); + } + p_saveFileTrailer = true; + }; + + /** + * This method marks the data block headers to be saved. A data + * header is a block of non-image data at the beginning of each + * data block (for BSQ data blocks are bands). This is not + * included in the file header and does not include any record + * headers, such as line prefixes. Each of the header blocks + * will be saved inside StartProcess(). It must be called after + * setting the size with SetDataHeaderBytes() and before + * StartProcess() is called. This data will only be available + * via DataHeader() after StartProcess() has returned and before + * EndProcess() is called. + * + * @throws Isis::iException::Message "Data header bytes equals + * 0. There is nothing to save. Use + * SetDataHeaderBytes() first." + * @see SetDataHeaderBytes() + * @see DataHeader() + */ + void ProcessImport::SaveDataHeader () { + if (p_dataHeaderBytes == 0){ + iString msg = "Data header bytes equals 0. There is nothing to save. Use SetDataHeaderBytes() first."; + throw iException::Message(iException::Programmer,msg.c_str(),_FILEINFO_); + } + p_saveDataHeader = true; + }; + + /** + * This method marks the data block trailers to be saved. A data + * trailer is a block of non-image data at the end of each data + * block (for BSQ data blocks are bands). This is not included + * in the file trailer and does not include any record trailers, + * such as line suffixes. Each of the trailer blocks will be + * saved inside StartProcess(). It must be called after setting + * the size with SetDataTrailerBytes() and before StartProcess() + * is called. This data will only be available via DataTrailer() + * after StartProcess() has returned and before EndProcess() is + * called. + * + * @throws Isis::iException::Message "Data trailer bytes equals + * 0. There is nothing to save. Use + * SetDataTrailerBytes() first." + * @see SetDataTrailerBytes() + * @see DataTrailer() + */ + void ProcessImport::SaveDataTrailer () { + if (p_dataTrailerBytes == 0){ + iString msg = "Data trailer bytes equals 0. There is nothing to save. Use SetDataTrailerBytes() first."; + throw iException::Message(iException::Programmer,msg.c_str(),_FILEINFO_); + } + p_saveDataTrailer = true; + }; + + /** + * This method marks the data prefix to be saved. A data prefix + * is a block of non-image data at the beginning of each data + * record (for BSQ data records are lines). This is not + * included in the file header or the data header. Each of the + * data prefixes will be saved inside StartProcess(). It must + * be called after setting the size with SetDataPrefixBytes() + * and before StartProcess() is called. This data will only be + * available via DataPrefix() after StartProcess() has returned + * and before EndProcess() is called. + * + * @throws Isis::iException::Message "Data prefix bytes equals + * 0. There is nothing to save. Use + * SetDataPrefixBytes() first." + * @see SetDataPrefixBytes() + * @see DataPrefix() + */ + void ProcessImport::SaveDataPrefix () { + if (p_dataPreBytes == 0){ + iString msg = "Data prefix bytes equals 0. There is nothing to save. Use SetDataPrefixBytes() first."; + throw iException::Message(iException::Programmer,msg.c_str(),_FILEINFO_); + } + p_saveDataPre = true; + }; + + /** + * This method marks the data suffix to be saved. A data + * suffix is a block of non-image data at the end of each data + * record (for BSQ data records are lines). This is not + * included in the file trailer or the data trailer. Each of + * the data suffixes will be saved inside StartProcess(). It + * must be called after setting the size with + * SetDataPrefixBytes() and before StartProcess() is called. + * This data will only be available via DataPrefix() after + * StartProcess() has returned and before EndProcess() is + * called. + * + * @throws Isis::iException::Message "Data suffix bytes equals + * 0. There is nothing to save. Use + * SetDataSuffixBytes() first." + * @see SetDataSuffixBytes() + * @see DataSuffix() + */ + void ProcessImport::SaveDataSuffix () { + if (p_dataPostBytes == 0){ + iString msg = "Data suffix bytes equals 0. There is nothing to save. Use SetDataSuffixBytes() first."; + throw iException::Message(iException::Programmer,msg.c_str(),_FILEINFO_); + } + p_saveDataPost = true; + }; + + /** + * This method returns a pointer to the file header. A file + * header is a block of non-image data at the beginning of the entire + * file. This does not include any section headers, such + * as band headers or line prefixes. In order to retrieve this + * data, the file header bytes must be set and the file header + * must be saved via SetFileHeaderBytes() and SaveFileHeader(), + * respectively. This method must be called only after + * StartProcess() has returned and before EndProcess() is + * called. + * + * @return char* Pointer to file header, if saved. + * @throws Isis::iException::Message "File header was not saved. + * Use SaveFileHeader()." + * + * @see SetFileHeaderBytes() + * @see SaveFileHeader() + */ + char* ProcessImport::FileHeader () { + if (p_saveFileHeader) { + return p_fileHeader; + } + std::string msg = "File header was not saved. Use SaveFileHeader()."; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + }; + + /** + * This method returns a pointer to the file trailer. A file + * trailer is a block of non-image data at the end of the entire + * file. This does not include any section trailers, such as + * band trailers or line suffixes. In order to retrieve this + * data, the file trailer bytes must be set and the file trailer + * must be saved via SetFileTrailerBytes() and + * SaveFileTrailer(), respectively. This method must be called + * only after StartProcess() has returned and before + * EndProcess() is called. + * + * @return char* Pointer to file trailer, if saved. + * @throws Isis::iException::Message "File trailer was not + * saved. Use SaveFileTrailer()." + * @see SetFileTrailerBytes() + * @see SaveFileTrailer() + */ + char* ProcessImport::FileTrailer () { + if (p_saveFileTrailer) { + return p_fileTrailer; + } + std::string msg = "File trailer was not saved. Use SaveFileTrailer()"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + }; + + + /** + * This method returns a pointer to the data header. A data + * header is a block of non-image data at the beginning of each + * data block (for BSQ data blocks are bands). This is not + * included in the file header and does not include any record + * headers, such as line prefixes. In order to retrieve this + * data, the data header bytes must be set and the data header + * must be saved via SetDataHeaderBytes() and SaveDataHeader(), + * respectively. This method must be called only after + * StartProcess() has returned and before EndProcess() is + * called. + * + * @return vector Vector of pointers to data + * headers for each block, if saved. + * @throws Isis::iException::Message "Data header was not saved. + * Use SaveDataHeader()." + * @see SetDataHeaderBytes() + * @see SaveDataHeader() + */ + std::vector ProcessImport::DataHeader () { + if (p_saveDataHeader) { + return p_dataHeader; + } + std::string msg = "Data header was not saved. Use SaveDataHeader()"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + }; + + /** + * This method returns a pointer to the data trailer. A data + * trailer is a block of non-image data at the end each data + * block (for BSQ data blocks are bands). This is not included + * in the file trailer and does not include any record trailers, + * such as line suffixes. In order to retrieve this data, the + * data trailer bytes must be set and the data trailer must be + * saved via SetDataTrailerBytes() and SaveDataTrailer(), + * respectively. This method must be called only after + * StartProcess() has returned and before EndProcess() is + * called. + * + * @return vector Vector of pointers to data + * trailers for each block, if saved. + * @throws Isis::iException::Message "Data trailer was not + * saved. Use SaveDataTrailer()." + * @see SetDataTrailerBytes() + * @see SaveDataTrailer() + */ + std::vector ProcessImport::DataTrailer () { + if (p_saveDataTrailer) { + return p_dataTrailer; + } + std::string msg = "Data trailer was not saved. Use SaveDataTrailer()"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + }; + + /** + * This method returns a pointer to the data prefix. A data + * prefix is a block of non-image data at the beginning of each + * data record (for BSQ data records are lines). This is not + * included in the file header or the data header. In order to + * retrieve this data, the data prefix bytes must be set and + * the data prefix must be saved via SetDataPrefixBytes() and + * SaveDataPrefix(), respectively. This method must be called + * only after StartProcess() has returned and before + * EndProcess() is called. + * + * @return vector > Two-dimensional + * vector of pointers to data prefixes for each record, + * if saved. + * @throws Isis::iException::Message "Data prefix was not saved. + * Use SaveDataPrefix()." + * @see SetDataPrefixBytes() + * @see SaveDataPrefix() + */ + std::vector > ProcessImport::DataPrefix () { + if (p_saveDataPre) { + return p_dataPre; + } + std::string msg = "Data prefix was not saved. Use SaveDataPrefix()"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + }; + + /** + * This method returns a pointer to the data suffix. A data + * suffix is a block of non-image data at the end of each data + * record (for BSQ data records are lines). This is not + * included in the file trailer or the data trailer. In order to + * retrieve this data, the data suffix bytes must be set and the + * data suffix must be saved via SetDataSuffixBytes() and + * SaveDataSuffix(), respectively. This method must be called + * only after StartProcess() has returned and before + * EndProcess() is called. + * + * @return vector > Two-dimensional + * vector of pointers to data suffixes for each record, + * if saved. + * @throws Isis::iException::Message "Data suffix was not saved. + * Use SaveDataSuffix()." + * @see SetDataSuffixBytes() + * @see SaveDataSuffix() + */ + std::vector > ProcessImport::DataSuffix () { + if (p_saveDataPost) { + return p_dataPost; + } + std::string msg = "Data suffix was not saved. Use SaveDataSuffix()"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + }; + + /** + * Sets the organization of the input cube. If not invoked it is assumed + * Isis::Import::Bsq. + * + * @param org The enumerated organizations either Isis::Import::Bsq + * Isis::Import::Bil or Isis::Import::Bip + */ + void ProcessImport::SetOrganization (const ProcessImport::Interleave org) { + p_organization = org; + }; + + /** + * Sets the core base of the input cube. Defaults to zero if not invoked. + * + * @param base Core base + */ + void ProcessImport::SetBase (const double base) { + p_base.clear(); + p_base.push_back(base); + }; + + /** + * Sets band dependent core base + * + * @param base A vector containing the base for each band. + */ + void ProcessImport::SetBase (const std::vector base) { + p_base = base; + }; + + /** + * Sets the core multiplier of the input cube. Defaults to one if not invoked. + * + * @param mult Core base + */ + void ProcessImport::SetMultiplier (const double mult) { + p_mult.clear(); + p_mult.push_back(mult); + }; + + /** + * Sets band dependent core multiplier + * + * @param mult A vector containing the multiplier for each band. + */ + void ProcessImport::SetMultiplier (const std::vector mult) { + p_mult = mult; + }; + + /** + * Sets a mapping of input pixel values to output special pixel values. + * + * @param null The double precision value used to identify null pixels in the + * image being imported. + * + * @param lrs The double precisiion value used to identify low representation + * saturation LRS pixels in the image being imported. + * + * @param lis The double precision value used to identify low instrument + * saturation LIS pixels in the image being imported. + * + * @param hrs The double precision value used to identify high representation + * saturation HRS pixels in the image being imported. + * + * @param his The double precision value used to identify high instrument + * saturation HIS pixels in the image being imported. + */ + void ProcessImport::SetSpecialValues (const double null, const double lrs, + const double lis, const double hrs, + const double his) { + SetNull(null,null); + SetLRS(lrs,lrs); + SetLIS(lis,lis); + SetHRS(hrs,hrs); + SetHIS(his,his); + }; + + /** + * Sets the range that will be considered Isis::Null + * + * @param null_min The double precision value used to identify + * the min range of null pixels in the image being + * imported. + * @param null_max The double precision value used to identify + * the max range of null pixels in the image being + * imported. + */ + void ProcessImport::SetNull(const double null_min, const double null_max){ + CheckPixelRange( "Null", null_min, null_max ); + p_null_min = null_min; + p_null_max = null_max; + } + + /** + * Sets the range that will be considered Isis::Null + * + * @param lrs_min The double precision value used to identify + * the min range of lrs pixels in the image being + * imported. + * @param lrs_max The double precision value used to identify + * the max range of lrs pixels in the image being + * imported. + */ + void ProcessImport::SetLRS(const double lrs_min, const double lrs_max){ + CheckPixelRange( "LRS", lrs_min, lrs_max ); + p_lrs_min = lrs_min; + p_lrs_max = lrs_max; + } + + /** + * Sets the range that will be considered Isis::Null + * + * @param lis_min The double precision value used to identify + * the min range of lis pixels in the image being + * imported. + * @param lis_max The double precision value used to identify + * the max range of lis pixels in the image being + * imported. + */ + void ProcessImport::SetLIS(const double lis_min, const double lis_max){ + CheckPixelRange( "LIS", lis_min, lis_max ); + p_lis_min = lis_min; + p_lis_max = lis_max; + } + + /** + * Sets the range that will be considered Isis::Null + * + * @param hrs_min The double precision value used to identify + * the min range of hrs pixels in the image being + * imported. + * @param hrs_max The double precision value used to identify + * the max range of hrs pixels in the image being + * imported. + */ + void ProcessImport::SetHRS(const double hrs_min, const double hrs_max){ + CheckPixelRange( "HRS", hrs_min, hrs_max ); + p_hrs_min = hrs_min; + p_hrs_max = hrs_max; + } + + /** + * Sets the range that will be considered Isis::Null + * + * @param his_min The double precision value used to identify + * the min range of his pixels in the image being + * imported. + * @param his_max The double precision value used to identify + * the max range of his pixels in the image being + * imported. + */ + void ProcessImport::SetHIS(const double his_min, const double his_max){ + CheckPixelRange( "HIS", his_min, his_max ); + p_his_min = his_min; + p_his_max = his_max; + } + + + /** + * Checks the special pixel range of the given against all other special pixel + * value ranges, making sure none overlap. + * + * @param pixelName Name of the special pixel type to be displayed in the error + * message. + * @param pixelMin The minimum value of the special pixel range + * @param pixelMax The maximum value of the special pixel range + */ + void ProcessImport::CheckPixelRange( string pixelName, double pixelMin, double pixelMax ) { + if( pixelMin == DBL_MAX || pixelMax == -DBL_MAX ) return; + + if( p_null_min != DBL_MAX && p_null_max != -DBL_MAX && ( // Checks if null has been set + (pixelMin > p_null_min && pixelMin < p_null_max) || // Checks for min crossing + (pixelMax > p_null_min && pixelMax < p_null_max) || // Checks for max crossing + (pixelMin < p_null_min && pixelMax > p_null_max) )) { // Checks for straddling values + string msg = "The " + pixelName + " range [" + iString(pixelMin) + + "," + iString(pixelMax) + "] overlaps the NULL range [" + + iString(p_null_min) + "," + iString(p_null_max) + "]"; + throw Isis::iException::Message(Isis::iException::User,msg, _FILEINFO_); + } + + if( p_lrs_min != DBL_MAX && p_lrs_max != -DBL_MAX && ( + (pixelMin > p_lrs_min && pixelMin < p_lrs_max) || + (pixelMax > p_lrs_min && pixelMax < p_lrs_max) || + (pixelMin < p_lrs_min && pixelMax > p_lrs_max) )) { + string msg = "The " + pixelName + " range [" + iString(pixelMin) + + "," + iString(pixelMax) + "] overlaps the LRS range [" + + iString(p_lrs_min) + "," + iString(p_lrs_max) + "]"; + throw Isis::iException::Message(Isis::iException::User,msg, _FILEINFO_); + } + + if( p_lis_min != DBL_MAX && p_lis_max != -DBL_MAX && ( + (pixelMin > p_lis_min && pixelMin < p_lis_max) || + (pixelMax > p_lis_min && pixelMax < p_lis_max) || + (pixelMin < p_lis_min && pixelMax > p_lis_max) )) { + string msg = "The " + pixelName + " range [" + iString(pixelMin) + + "," + iString(pixelMax) + "] overlaps the LIS range [" + + iString(p_lis_min) + "," + iString(p_lis_max) + "]"; + throw Isis::iException::Message(Isis::iException::User,msg, _FILEINFO_); + } + + if( p_hrs_min != DBL_MAX && p_hrs_max != -DBL_MAX && ( + (pixelMin > p_hrs_min && pixelMin < p_hrs_max) || + (pixelMax > p_hrs_min && pixelMax < p_hrs_max) || + (pixelMin < p_hrs_min && pixelMax > p_hrs_max) )) { + string msg = "The " + pixelName + " range [" + iString(pixelMin) + + "," + iString(pixelMax) + "] overlaps the HRS range [" + + iString(p_hrs_min) + "," + iString(p_hrs_max) + "]"; + throw Isis::iException::Message(Isis::iException::User,msg, _FILEINFO_); + } + + if( p_his_min != DBL_MAX && p_his_max != -DBL_MAX && ( + (pixelMin > p_his_min && pixelMin < p_his_max) || + (pixelMax > p_his_min && pixelMax < p_his_max) || + (pixelMin < p_his_min && pixelMax > p_his_max) )) { + string msg = "The " + pixelName + " range [" + iString(pixelMin) + + "," + iString(pixelMax) + "] overlaps the HIS range [" + + iString(p_his_min) + "," + iString(p_his_max) + "]"; + throw Isis::iException::Message(Isis::iException::User,msg, _FILEINFO_); + } + + } + + /** + * Tests the pixel. If it is valid it will return the dn value, + * otherwise it will return the Isis special pixel value that + * corresponds to it + * + * @param pixel The double precision value that represents a + * pixel. + * @return double The double precision value representing the + * pixel will return as a valid dn or changed to an isis + * special pixel. + */ + double ProcessImport::TestPixel(const double pixel){ + if (pixel <= p_null_max && pixel >= p_null_min){ + return Isis::NULL8; + } else if (pixel <= p_hrs_max && pixel >= p_hrs_min){ + return Isis::HIGH_REPR_SAT8; + } else if (pixel <= p_lrs_max && pixel >= p_lrs_min){ + return Isis::LOW_REPR_SAT8; + } else if (pixel <= p_his_max && pixel >= p_his_min){ + return Isis::HIGH_INSTR_SAT8; + } else if (pixel <= p_lis_max && pixel >= p_lis_min){ + return Isis::LOW_INSTR_SAT8; + } else { + return pixel; + } + } + + /** + * Create the output file. Note that all the appropiate calls to at least + * SetDimensions and SetPixelType should be made prior to calling this method. + * + * @param parameter The parameter name that holds the output file name. + * + * @throws Isis::iException::Message "Unsupported pixel type." + */ + Isis::Cube* ProcessImport::SetOutputCube (const std::string ¶meter) { + Isis::CubeAttributeOutput &att = Application::GetUserInterface().GetOutputAttribute(parameter); + + if (att.PropagateMinimumMaximum()) { + double min,max; + if ((p_pixelType == Isis::Real) || + (p_base.size() > 1) || (p_mult.size() > 1)) { + min = Isis::VALID_MIN4; + max = Isis::VALID_MAX4; + } + else if (p_pixelType == Isis::SignedWord) { + min = Isis::VALID_MIN2 * p_mult[0] + p_base[0]; + max = Isis::VALID_MAX2 * p_mult[0] + p_base[0]; + } + else if (p_pixelType == Isis::UnsignedWord) { + min = Isis::VALID_MINU2 * p_mult[0] + p_base[0]; + max = Isis::VALID_MAXU2 * p_mult[0] + p_base[0]; + } + else if (p_pixelType == Isis::UnsignedByte){ + min = Isis::VALID_MIN1 * p_mult[0] + p_base[0]; + max = Isis::VALID_MAX1 * p_mult[0] + p_base[0]; + } + else { + string msg = "Unsupported pixel type [" + + Isis::PixelTypeName(p_pixelType) + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + att.Minimum(min); + att.Maximum(max); + } + + if (att.PropagatePixelType()) { + if ((p_base.size() > 1) || (p_mult.size() > 1)) { + att.PixelType(Isis::Real); + } + else if (p_pixelType == Isis::UnsignedWord) { + att.PixelType(Isis::Real); + } + else { + att.PixelType(p_pixelType); + } + } + + return Isis::Process::SetOutputCube (Application::GetUserInterface().GetFilename(parameter), + att, p_ns, p_nl, p_nb); + } + + /** + * Create the output file. Note that all the appropiate calls to at least + * SetDimensions should be invoked prior to calling this method. + * + * @param parameter The parameter name that holds the output file name. + * + * @param att An output cube attribute to define the characteristics of the + * output cube. + * + * @throws Isis::iException::Message "File is not in a supported + * organization." + */ + Isis::Cube* ProcessImport::SetOutputCube (const std::string ¶meter, + Isis::CubeAttributeOutput &att) { + return Isis::Process::SetOutputCube (parameter, att, p_ns, p_nl, p_nb); + } + + + //! Process the input file and write it to the output. + void ProcessImport::StartProcess() { + if (p_organization == ProcessImport::JP2) { + ProcessJp2 (); + } + else if (p_organization == ProcessImport::BSQ) { + ProcessBsq (); + } + else if (p_organization == ProcessImport::BIL) { + ProcessBil (); + } + else if (p_organization == ProcessImport::BIP) { + ProcessBip (); + } + else { + string msg = "File [" + p_inFile + "] is not in a supported organization."; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + + + /** + * Process the input file and send data to method + * + * @param funct Method that accepts Isis::Buffer as an input + * parameter, processes the image, and has no + * return value. + * @throws Isis::iException::Message "File is not a supported + * organization." + */ + void ProcessImport::StartProcess(void funct(Isis::Buffer &out)) { + if (p_organization == ProcessImport::JP2) { + ProcessJp2 (funct); + } + else if (p_organization == ProcessImport::BSQ) { + ProcessBsq (funct); + } + else if (p_organization == ProcessImport::BIL) { + ProcessBil (funct); + } + else if (p_organization == ProcessImport::BIP) { + ProcessBip (funct); + } + else { + string msg = "File [" + p_inFile + "] is not in a supported organization."; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + + /** + * Process the import data as a band sequential file. + * + * @param funct Method that accepts Isis::Buffer as an input + * parameter, processes the image, and has no + * return value. + * + * @throws Isis::iException::Message "Cannot open input file." + * @throws Isis::iException::Message "Cannot read file. + * Position[]. Byte count[]" + */ + void ProcessImport::ProcessBsq (void funct(Isis::Buffer &out)) { + // Figure out the number of bytes to read for a single line + int readBytes = Isis::SizeOf (p_pixelType); + readBytes = readBytes * p_ns; + char *in = new char [readBytes]; + + // Set up an Isis::EndianSwapper object + Isis::iString tok(Isis::ByteOrderName(p_byteOrder)); + tok.UpCase(); + Isis::EndianSwapper swapper (tok); + + ifstream fin; + // Open input file + Isis::Filename inFile(p_inFile); + string inFilename(inFile.Expanded()); + fin.open (inFilename.c_str(), ios::in|ios::binary); + if (!fin.is_open()) { + string msg = "Cannot open input file [" + p_inFile + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // Handle the file header + streampos pos = fin.tellg(); + if (p_saveFileHeader) { + p_fileHeader = new char[p_fileHeaderBytes]; + fin.read (p_fileHeader, p_fileHeaderBytes); + } + else { + fin.seekg (p_fileHeaderBytes, ios_base::beg); + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_fileHeaderBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + // Construct a line buffer manager + Isis::Buffer *out = NULL; + + if(funct != NULL) { + out = new Isis::Brick (p_ns, 1, 1, p_pixelType); + } + else { + out = new Isis::LineManager (*OutputCubes[0]); + } + + // Loop once for each band in the image + p_progress->SetMaximumSteps(p_nl*p_nb); + p_progress->CheckStatus(); + + // Loop for each band + for (int band=0; band 1) { + base = p_base[band]; + mult = p_mult[band]; + } + else { + base = p_base[0]; + mult = p_mult[0]; + } + + // Handle any data headers (e.g., the data at the beginning of each band) + pos = fin.tellg(); + if (p_saveDataHeader) { + p_dataHeader.push_back(new char[p_dataHeaderBytes]); + fin.read (p_dataHeader.back(), p_dataHeaderBytes); + } + else { + fin.seekg (p_dataHeaderBytes, ios_base::cur); + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_dataHeaderBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + // Space for storing prefix and suffix data pointers + vector tempPre, tempPost; + + // Loop for each line in a band + for (int line=0; lineSetLine ((band * p_nl) + line + 1); + OutputCubes[0]->Write (*out); + } + else { + ((Isis::Brick*)out)->SetBaseSample (1); + ((Isis::Brick*)out)->SetBaseLine (line + 1); + ((Isis::Brick*)out)->SetBaseBand (band + 1); + funct(*out); + } + + p_progress->CheckStatus(); + + // Handle any line suffix bytes + pos = fin.tellg(); + if (p_saveDataPost) { + tempPost.push_back(new char[p_dataPostBytes]); + fin.read (tempPost.back(), p_dataPostBytes); + } + else { + fin.seekg (p_dataPostBytes, ios_base::cur); + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_dataPreBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + } // End line loop + + // Save off the prefix bytes vector + if (p_saveDataPre) { + p_dataPre.push_back(tempPre); + tempPre.clear(); + } + + // Save off the suffix bytes vector + if (p_saveDataPost) { + p_dataPost.push_back(tempPost); + tempPost.clear(); + } + + // Handle the band trailer + pos = fin.tellg(); + if (p_saveDataTrailer) { + p_dataTrailer.push_back(new char[p_dataTrailerBytes]); + fin.read (p_dataTrailer.back(), p_dataTrailerBytes); + } + else { + fin.seekg (p_dataTrailerBytes, ios_base::cur); + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_fileHeaderBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + } // End band loop + + // Handle the file trailer + pos = fin.tellg(); + if (p_saveFileTrailer) { + fin.seekg (0, ios_base::end); + streampos e = fin.tellg(); + p_fileTrailerBytes = (int)(e - pos + (streampos)1); + p_fileTrailer = new char[p_fileTrailerBytes]; + fin.seekg (pos); + fin.read (p_fileTrailer, p_fileTrailerBytes); + + // Check the io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_fileTrailerBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + } + + // Close the file and clean up + fin.close (); + delete [] in; + } + + + /** + * Function to process files stored as Band Interleaved by Line + * + * @param funct Method that accepts Isis::Buffer as an input + * parameter, processes the image, and has no + * return value. + * @throws Isis::iException::Message "Cannot open input file." + * @throws Isis::iException::Message "Cannot read file. + * Position[]. Byte count[]" + */ + void ProcessImport::ProcessBil (void funct(Isis::Buffer &out)) { + + // Figure out the number of bytes to read for a single line + int readBytes = Isis::SizeOf (p_pixelType); + readBytes = readBytes * p_ns; + char *in = new char [readBytes]; + + // Set up an Isis::EndianSwapper object + Isis::iString tok(Isis::ByteOrderName(p_byteOrder)); + tok.UpCase(); + Isis::EndianSwapper swapper (tok); + + ifstream fin; + // Open input file + Isis::Filename inFile(p_inFile); + string inFilename(inFile.Expanded()); + fin.open (inFilename.c_str(), ios::in|ios::binary); + if (!fin.is_open()) { + string msg = "Cannot open input file [" + p_inFile + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // Handle the file header + streampos pos = fin.tellg(); + if (p_saveFileHeader) { + p_fileHeader = new char[p_fileHeaderBytes]; + fin.read (p_fileHeader, p_fileHeaderBytes); + } + else { + fin.seekg (p_fileHeaderBytes, ios_base::beg); + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_fileHeaderBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + // Construct a line buffer manager + Isis::Buffer *out = NULL; + + if(funct != NULL) { + out = new Isis::Buffer (p_ns, p_nl, p_nb, p_pixelType); + } + else { + out = new Isis::LineManager (*OutputCubes[0]); + } + + // Loop once for each line in the image + p_progress->SetMaximumSteps(p_nb*p_nl); + p_progress->CheckStatus(); + + // Loop for each line + for (int line=0; line 1) { + base = p_base[band]; + mult = p_mult[band]; + } + else { + base = p_base[0]; + mult = p_mult[0]; + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_dataHeaderBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + // Space for storing prefix and suffix data pointers + vector tempPre, tempPost; + + + // Handle any line prefix bytes + pos = fin.tellg(); + if (p_saveDataPre) { + tempPre.push_back(new char[p_dataPreBytes]); + fin.read (tempPre.back(), p_dataPreBytes); + } + else { + fin.seekg (p_dataPreBytes, ios_base::cur); + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_dataPreBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + + // Get a line of data from the input file + pos = fin.tellg(); + fin.read (in, readBytes); + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(readBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // Swap the bytes if necessary and convert any out of bounds pixels + // to special pixels + for (int samp=0; sampSetLine ((band * p_nl) + line + 1); + OutputCubes[0]->Write (*out); + } + else { + funct(*out); + } + + p_progress->CheckStatus(); + + // Handle any line suffix bytes + pos = fin.tellg(); + if (p_saveDataPost) { + tempPost.push_back(new char[p_dataPostBytes]); + fin.read (tempPost.back(), p_dataPostBytes); + } + else { + fin.seekg (p_dataPostBytes, ios_base::cur); + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_dataPreBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + + // Save off the prefix bytes vector + if (p_saveDataPre) { + p_dataPre.push_back(tempPre); + tempPre.clear(); + } + + // Save off the suffix bytes vector + if (p_saveDataPost) { + p_dataPost.push_back(tempPost); + tempPost.clear(); + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_fileHeaderBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + } // End band loop + + } // End line loop + + // Handle the file trailer + pos = fin.tellg(); + if (p_saveFileTrailer) { + fin.seekg (0, ios_base::end); + streampos e = fin.tellg(); + p_fileTrailerBytes = (int)(e - pos + (streampos)1); + p_fileTrailer = new char[p_fileTrailerBytes]; + fin.seekg (pos); + fin.read (p_fileTrailer, p_fileTrailerBytes); + + // Check the io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_fileTrailerBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + } + + // Close the file and clean up + fin.close (); + delete [] in; + + } + + + /** + * Function to process files stored as Band Interleaved by Pixel + * + * @param funct Method that accepts Isis::Buffer as an input + * parameter, processes the image, and has no + * return value. + * @throws Isis::iException::Message "Cannot open input file." + * @throws Isis::iException::Message "Cannot read file. + * Position[]. Byte count[]" + */ + void ProcessImport::ProcessBip (void funct(Isis::Buffer &out)) { + + // Figure out the number of bytes to read for a single line + int readBytes = Isis::SizeOf (p_pixelType); + readBytes = readBytes * p_ns * p_nb; + char *in = new char [readBytes]; + + // Set up an Isis::EndianSwapper object + Isis::iString tok(Isis::ByteOrderName(p_byteOrder)); + tok.UpCase(); + Isis::EndianSwapper swapper (tok); + + ifstream fin; + // Open input file + Isis::Filename inFile(p_inFile); + string inFilename(inFile.Expanded()); + fin.open (inFilename.c_str(), ios::in|ios::binary); + if (!fin.is_open()) { + string msg = "Cannot open input file [" + p_inFile + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // Handle the file header + streampos pos = fin.tellg(); + if (p_saveFileHeader) { + p_fileHeader = new char[p_fileHeaderBytes]; + fin.read (p_fileHeader, p_fileHeaderBytes); + } + else { + fin.seekg (p_fileHeaderBytes, ios_base::beg); + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_fileHeaderBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + // Construct a line buffer manager + Isis::Buffer *out = NULL; + + if(funct != NULL) { + out = new Isis::Buffer (p_ns, p_nl, p_nb, p_pixelType); + } + else { + out = new Isis::LineManager (*OutputCubes[0]); + } + + // Loop once for each line in the image + p_progress->SetMaximumSteps(p_nl); + p_progress->CheckStatus(); + + // Loop for each line + for (int line=0; line tempPre, tempPost; + + + // Handle any line prefix bytes + pos = fin.tellg(); + if (p_saveDataPre) { + tempPre.push_back(new char[p_dataPreBytes]); + fin.read (tempPre.back(), p_dataPreBytes); + } + else { + fin.seekg (p_dataPreBytes, ios_base::cur); + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_dataPreBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + // Get a line of data from the input file + pos = fin.tellg(); + fin.read (in, readBytes); + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(readBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // Loop for each band + for (int band=0; band 1) { + base = p_base[band]; + mult = p_mult[band]; + } + else { + base = p_base[0]; + mult = p_mult[0]; + } + + // Swap the bytes if necessary and convert any out of bounds pixels + // to special pixels + int osamp=0; + for (int samp=band; sampSetLine ((band * p_nl) + line + 1); + OutputCubes[0]->Write (*out); + } + else { + funct(*out); + } + + // Handle any line suffix bytes + pos = fin.tellg(); + if (p_saveDataPost) { + tempPost.push_back(new char[p_dataPostBytes]); + fin.read (tempPost.back(), p_dataPostBytes); + } + else { + fin.seekg (p_dataPostBytes, ios_base::cur); + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_dataPreBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + + // Save off the prefix bytes vector + if (p_saveDataPre) { + p_dataPre.push_back(tempPre); + tempPre.clear(); + } + + // Save off the suffix bytes vector + if (p_saveDataPost) { + p_dataPost.push_back(tempPost); + tempPost.clear(); + } + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_fileHeaderBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + } // End band loop + + p_progress->CheckStatus(); + + } // End line loop + + // Handle the file trailer + pos = fin.tellg(); + if (p_saveFileTrailer) { + fin.seekg (0, ios_base::end); + streampos e = fin.tellg(); + p_fileTrailerBytes = (int)(e - pos + (streampos)1); + p_fileTrailer = new char[p_fileTrailerBytes]; + fin.seekg (pos); + fin.read (p_fileTrailer, p_fileTrailerBytes); + + // Check the io + if (!fin.good ()) { + string msg = "Cannot read file [" + p_inFile + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(p_fileTrailerBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + } + + // Close the file and clean up + fin.close (); + delete [] in; + + } + + + /** + * Function to process files containing compressed JPEG2000 data + * (which is always BSQ but is processed as BIL with one or more + * lines stored sequentially for each band). There is no need to + * set up an Isis::EndianSwapper because JP2 data is always + * assumed to be in MSB format. The Kakadu library does an + * automatic byte swap for the current architecture. + * + * @param funct Method that accepts Isis::Buffer as an input + * parameter, processes the image, and has no + * return value. + * @throws Isis::iException::Message "Cannot open input file." + * @throws Isis::iException::Message "Cannot read file. + * Position[]. Byte count[]" + */ + void ProcessImport::ProcessJp2 (void funct(Isis::Buffer &out)) { + + // Set up an Isis::Jp2Decoder object + JP2Decoder *JP2_decoder; + JP2_decoder = new JP2Decoder(p_inFile); + + // Open JP2 file + JP2_decoder->OpenFile(); + + // Make sure JP2 file dimensions match PDS labels + p_ns = JP2_decoder->GetSampleDimension(); + p_nl = JP2_decoder->GetLineDimension(); + p_nb = JP2_decoder->GetBandDimension(); + + // Figure out the number of bytes to read for a single line + // from all bands + int sizeofpixel = Isis::SizeOf (p_pixelType); + int startsamp = p_dataPreBytes / sizeofpixel; + int endsamp = startsamp + p_ns; + int readBytes = sizeofpixel * p_ns * p_nb + p_dataPreBytes + p_dataPostBytes; + char **in = new char* [p_nb]; + for (int i=0; iSetMaximumSteps(p_nb*p_nl); + p_progress->CheckStatus(); + + // Loop for each line + for (int line=0; lineRead((unsigned char**)in); + } else { + JP2_decoder->Read((short int**)in); + } + // Loop for each band + for (int band=0; band 1) { + base = p_base[band]; + mult = p_mult[band]; + } + else { + base = p_base[0]; + mult = p_mult[0]; + } + + // Space for storing prefix and suffix data pointers + vector tempPre, tempPost; + + + // Handle any line prefix bytes + if (p_saveDataPre) { + tempPre.push_back(new char[p_dataPreBytes]); + memcpy(&tempPre[0],in[band],p_dataPreBytes); + } + + // Swap the bytes if necessary and convert any out of bounds pixels + // to special pixels + for (int samp=startsamp; sampSetLine ((band * p_nl) + line + 1); + OutputCubes[0]->Write (*out); + } + else { + funct(*out); + } + + p_progress->CheckStatus(); + + // Handle any line suffix bytes + if (p_saveDataPost) { + tempPost.push_back(new char[p_dataPostBytes]); + memcpy(&tempPost[0],&in[band][p_dataPreBytes+p_ns*sizeofpixel],p_dataPostBytes); + } + + // Save off the prefix bytes vector + if (p_saveDataPre) { + p_dataPre.push_back(tempPre); + tempPre.clear(); + } + + // Save off the suffix bytes vector + if (p_saveDataPost) { + p_dataPost.push_back(tempPost); + tempPost.clear(); + } + + } // End band loop + + } // End line loop + + // Close the file and clean up + delete JP2_decoder; + delete [] in; + } + + + #if 0 + + /** + * Adds a label to the Cube section of the existing cube label using a supplied + * Pvl + * + * @param label The Pvl containing the label to be added. + */ + void ProcessImport::AddLabel (Isis::Pvl &label) { + + label.Root(); + + Isis::Pvl *output = OutputCubes[0]->Label(); + output->Find ("IsisCube"); + output->Insert(label); + } + + /** + * Adds an ImportLabel to the output cube using a supplied Pvl + * + * @param importlab The Pvl containing the original labels from the import file. + */ + void ProcessImport::AddImportLabel (Isis::Pvl &importLab) { + + importLab.Root(); + + Isis::Pvl *output = OutputCubes[0]->Label(); + output->Find ("IsisCube"); + output->AddObject ("ImportLabel"); + output->Insert(importLab); + } + #endif + + + /** + * Sets the name of the input file to be read in the import StartProcess method + * and verifies its existance. + * + * @param file The name of the input file to import. + * + * @throws Isis::iException::Message "File does not exist." + */ + void ProcessImport::SetInputFile (const std::string &file) { + p_inFile = file; + if (!Isis::Filename(file).Exists()) { + string msg = "File [" + file + "] does not exist"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } +} + diff --git a/isis/src/base/objs/ProcessImport/ProcessImport.h b/isis/src/base/objs/ProcessImport/ProcessImport.h new file mode 100644 index 0000000000000000000000000000000000000000..1423a63c18a7aaec19dff55d5de2dff8b16a6dd2 --- /dev/null +++ b/isis/src/base/objs/ProcessImport/ProcessImport.h @@ -0,0 +1,344 @@ +#ifndef ProcessImport_h +#define ProcessImport_h +/** + * @file + * $Revision: 1.11 $ + * $Date: 2010/02/22 02:25:02 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#include "Process.h" +#include "Buffer.h" +#include "PixelType.h" +#include "SpecialPixel.h" +#include "EndianSwapper.h" +#include "PvlTranslationManager.h" +#include "CubeAttribute.h" +#include "JP2Decoder.h" + +namespace Isis { +/** + * @brief Byte swapper + * + * This class is used to import an image into Isis. It is a powerful base class + * which can be used to skip over header bytes, trailer bytes, prefix and/or + * suffix bytes. By deriving off of this class it can be used to Import vicar, + * PDS, fits, or many other standard format images. + * + * Here is an example of how to use ProcessImport + * @code + * Import p; + * p.SetInputFile("myfile.raw"); + * p.SetDimensions(512,512,1); + * p.SetPixelType(Isis::SignedWord); + * p.SetByteOrder(Isis::Lsb); + * p.SetOutputCube("TO"); + * p.StartProcess(); + * p.EndProcess(); + * @endcode + * + * If you would like to see ProcessImport being used in implementation, + * see raw2isis.cpp or for a class that implements ProcessImport, + * see ProcessImportPds + * + * @ingroup HighLevelCubeIO + * + * @author 2002-08-06 Tracie Sucharski + * + * @internal + * @history 2003-01-24 Tracie Sucharski - Fixed bug in processing 8bit data. In + * the Swap method needed to return + * unsigned char, not char. + * @history 2003-02-13 Stuart Sides - Added a unit test. + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-05-30 Stuart Sides - Fixed compiler error after -O1 flag was + * added to g++ + * @history 2003-09-10 Tracie Sucharski - Complete redesign to handle different + * raw file formats. + * @history 2003-10-09 Stuart Sides - Added capabilities for reading PDS files. + * @history 2003-10-10 Stuart Sides - Added capabilities to get the translation + * files from the user preferences BASE + * directory. + * @history 2003-10-10 Stuart Sides - Fixed bug for PDS files. When the image + * name was explicitly given the open + * statement was attempting to open the + * label file. + * @history 2003-10-16 Stuart Sides - Added a section for debuging all the + * parameters which can be set before + * processing starts. + * @history 2003-10-16 Stuart Sides - Added a second parameter to the Pvl + * constructor in SetVicarFile. This allows + * the vicar label to be read into a Pvl + * without modifying the repeated "PROPERTY" + * keyword. + * @history 2003-10-23 Stuart Sides - Added new member functions + * "AddImportLabel()"and"AddImportLabel(Pvl). + * AddImportLabel() uses the original label + * file to create a Pvl and write it to the + * output cube label. AddImportLabel(Pvl) + * uses the Pvl argument to write the import + * label to the output cube. + * @history 2004-01-21 Jeff Anderson - Modified SetOutputCube method to + * propagate the input pixel type, base,and + * multipliers to the output cube. The old + * method always generated real pixel + * values in the output. + * @history 2004-01-22 Jeff Anderson - Modified the SetVicarFile method to + * return the vicar labels + * internalized in a Pvl object. + * @history 2004-02-04 Jeff Anderson - Modified SetPdsFile method to allow for + * SPECTRAL_QUBE objects to handle Themis + * data. + * @history 2004-02-05 Jeff Anderson - Refactored the class + * @history 2004-02-10 Stuart Sides - Added new member AddLabel + * @history 2004-02-10 Stuart Sides - Modified the SetOutputCube member to + * create a real output file by default if + * the number of core base and multipliers + * is more than one. + * @history 2005-02-09 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-04-08 Leah Dahmer - added missing documentation. + * + * @history 2006-04-21 Brendan George - Implemented ProcessBil() + * + * @history 2006-10-26 Stuart Sides - Added unsigned 16 bit ability + * + * @history 2007-10-05 Steven Lambright - Added StartProcess method that + * passes data back to a function instead of writing it + * out to a file. + * @history 2007-11-13 Janet Barrett - Added the ProcessBip capability + * @history 2008-02-22 Steven Lambright - Fixed a memory leak and improved the way the + * destructor detects allocated pointers. + * @history 2008-08-18 Jeannie Walldren - Modified + * documentation and added method + * SetFileTrailerBytes(). + * @history 2008-09-16 Christopher Austin - Added error throwing for the + * setting of special pixel ranges that overlap by adding + * CheckPixelRange(). + * @history 2009-12-14 Janet Barrett - Added capability to import JPEG2000 files. + * + */ + +class ProcessImport : public Isis::Process { + public: + ProcessImport(); + ~ProcessImport (); + void StartProcess (); + void StartProcess (void funct(Isis::Buffer &out)); + void SetInputFile (const std::string &file); + Isis::Cube* SetOutputCube (const std::string ¶meter); + Isis::Cube* SetOutputCube (const std::string ¶meter, + Isis::CubeAttributeOutput &att); + void SetPixelType (const Isis::PixelType type); + /** + * Returns the pixel type + * @return The pixel type of input data + */ + Isis::PixelType PixelType() { return p_pixelType; } + void SetDimensions (const int ns, const int nl, const int nb); + + /** + * Returns the number of samples + * @return The number of samples + */ + int Samples () { return p_ns; } + + /** + * Returns the number of lines + * @return The number of lines + */ + int Lines () { return p_nl; } + + /** + * Returns the number of bands + * @return The number of bands + */ + int Bands () { return p_nb; } + + void SetByteOrder (const Isis::ByteOrder order); + + /** + * Returns the byte order + * @return Byte order of the data + */ + Isis::ByteOrder ByteOrder () { return p_byteOrder; } + + void SetFileHeaderBytes (const int bytes); + void SetFileTrailerBytes (const int bytes); + void SetDataHeaderBytes (const int bytes); + void SetDataTrailerBytes (const int bytes); + void SetDataPrefixBytes (const int bytes); + void SetDataSuffixBytes (const int bytes); + void SaveFileHeader (); + void SaveFileTrailer (); + void SaveDataHeader (); + void SaveDataTrailer (); + void SaveDataPrefix (); + void SaveDataSuffix (); + char* FileHeader (); + char* FileTrailer (); + std::vector DataHeader (); + std::vector DataTrailer (); + std::vector > DataPrefix (); + std::vector > DataSuffix (); + + /** + * This enum includes how the document should be read: by BSQ, BIL, BIP, + * JP2, or InterleaveUndefined. + */ + enum Interleave { + InterleaveUndefined, /** base); + void SetMultiplier (const std::vector mult); + + void SetSpecialValues (const double null, const double lrs, + const double lis, const double hrs, + const double his); + void SetNull(const double null_min, const double null_max); + void SetLRS(const double lrs_min, const double lrs_max); + void SetLIS(const double lis_min, const double lis_max); + void SetHRS(const double hrs_min, const double hrs_max); + void SetHIS(const double his_min, const double his_max); + + double TestPixel(const double pixel); + +#if 0 + void AddImportLabel (Isis::Pvl &importLab); + void AddLabel (Isis::Pvl &label); +#endif + + + private: + std::string p_inFile; //!p_dataHeader; //!p_dataTrailer; //! >p_dataPre; //! >p_dataPost; //! p_base; /** p_mult; /**Statistics(); + cout << stat->Average() << endl; + cout << stat->Variance() << endl; + p2.EndProcess(); + remove(file.c_str()); + cout << endl; + + //Checks the setting of special pixel ranges + + Isis::ProcessImport pNull; + pNull.SetNull( 0.0, 45.0 ); + try { // Should NOT throw an error + pNull.SetNull( 0.0, 45.0 ); + } catch (Isis::iException e) { + cout << e.Errors() << endl; + e.Clear(); + } + cout << endl; + try { // Should throw an error + pNull.SetLRS( 35.0, 55.0 ); + } catch (Isis::iException e) { + cout << e.Errors() << endl; + e.Clear(); + } + cout << endl; + try { // Should NOT throw an error + pNull.SetLIS( 50.0, 52.0 ); + } catch (Isis::iException e) { + cout << e.Errors() << endl; + e.Clear(); + } + cout << endl; + try { // Should throw an error + pNull.SetHRS( -10.0, 5.0 ); + } catch (Isis::iException e) { + cout << e.Errors() << endl; + e.Clear(); + } + cout << endl; + + Isis::ProcessImport pLRS; + pLRS.SetLRS( 10.0, 145.0 ); + try { // Should throw an error + pLRS.SetNull( 35.0, 55.0 ); + } catch (Isis::iException e) { + cout << e.Errors() << endl; + e.Clear(); + } + cout << endl; + try { // Should throw an error + pNull.SetLIS( 0.0, 15.0 ); + } catch (Isis::iException e) { + cout << e.Errors() << endl; + e.Clear(); + } + cout << endl; + try { // Should throw an error + pLRS.SetHIS( -10.0, 155.0 ); + } catch (Isis::iException e) { + cout << e.Errors() << endl; + e.Clear(); + } + cout << endl; + try { // Should NOT throw an error + pLRS.SetHIS( 145.0, 155.0 ); + } catch (Isis::iException e) { + cout << e.Errors() << endl; + e.Clear(); + } + cout << endl; + +} diff --git a/isis/src/base/objs/ProcessImport/unitTest.xml b/isis/src/base/objs/ProcessImport/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..468798b1922a971af0ba1001f6f6e171cbd03658 --- /dev/null +++ b/isis/src/base/objs/ProcessImport/unitTest.xml @@ -0,0 +1,105 @@ + + + + Unit test for IsisImport class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + Modified schema from astrogeology... isis.astrogeology... + + + Added the special pixel range error throwing. + + + + + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isisImport.cub + + + + + + string + + YES + + Create special pixel values (LRS and HRS) + + Create special pixel values for LRS and HRS + + + + + + + + + double + + 0 + + Minimum valid value + + Minimum valid value. Anything below this value will be + set to LRS. + + + + double + + 100 + + Maximum valid value + + Maximum valid value. Anything above this value will be + set to HRS. + + + + + + diff --git a/isis/src/base/objs/ProcessImportPds/Makefile b/isis/src/base/objs/ProcessImportPds/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5b04e5aa057b8fabb7df5753e409fa0d4a91152d --- /dev/null +++ b/isis/src/base/objs/ProcessImportPds/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessImportPds.h +SRCS = ProcessImportPds.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessImportPds/ProcessImportPds.cpp b/isis/src/base/objs/ProcessImportPds/ProcessImportPds.cpp new file mode 100644 index 0000000000000000000000000000000000000000..55b56e8439e78b9a63770546b28d8515fb39bc90 --- /dev/null +++ b/isis/src/base/objs/ProcessImportPds/ProcessImportPds.cpp @@ -0,0 +1,1275 @@ +/** + * @file + * $Revision: 1.35 $ + * $Date: 2010/02/22 02:26:15 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "Preference.h" + +#include "iException.h" +#include "LineManager.h" +#include "Pvl.h" +#include "PvlObject.h" +#include "PvlTokenizer.h" +#include "PixelType.h" +#include "SpecialPixel.h" +#include "iString.h" +#include "ProcessImportPds.h" +#include "UserInterface.h" +#include "OriginalLabel.h" +#include "Projection.h" + +using namespace std; +namespace Isis { + + /** + * Constructor. + */ + ProcessImportPds::ProcessImportPds(){ + p_keepOriginalLabel = true; + p_encodingType = NONE; + p_jp2File.clear(); + + // Set up a translater for PDS file of type IMAGE + Isis::PvlGroup &dataDir = Isis::Preference::Preferences().FindGroup("DataDirectory"); + p_transDir = (string) dataDir["Base"]; + } + + /** + * Set the input label file, data file and initialize a Pvl with the PDS labels. + * + * @param pdsLabelFile The name of the PDS label file.This must be the file + * where the label is. It can be an attached or detached + * label. + * + * @param pdsDataFile The name of the PDS data file where the actual image/cube + * data is stored. This parameter can be an empty string, in + * which case the label information will be searched to find + * the data file name or the data will be assumed to be + * after the label information. + * + * @param pdsLabel The label from the input PDS/Isis2 file + * + * @throws Isis::iException::Message + */ + void ProcessImportPds::SetPdsFile (const std::string &pdsLabelFile, + const std::string &pdsDataFile, + Isis::Pvl &pdsLabel) { + + // Internalize the PDS label in the PVL that was passed in + pdsLabel.Read (pdsLabelFile); + + // Save the label and file for future use + p_pdsLabel = pdsLabel; + p_labelFile = pdsLabelFile; + + // Create a temporary Isis::PvlTranslationManager so we can find out what + // type of PDS file this is (i.e., Qube or Image or SpectralQube) + stringstream trnsStrm; + trnsStrm << "Group = PdsTypeImage" << endl; + trnsStrm << " InputPosition = ROOT" << endl; + trnsStrm << " InputPosition = FILE" << endl; + trnsStrm << " InputPosition = UNCOMPRESSED_FILE" << endl; + trnsStrm << " InputKey = ^IMAGE" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = PdsTypeQube" << endl; + trnsStrm << " InputKey = ^QUBE" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = PdsTypeSpectralQube" << endl; + trnsStrm << " InputKey = ^SPECTRAL_QUBE" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = PdsEncodingType" << endl; + trnsStrm << " InputPosition = COMPRESSED_FILE" << endl; + trnsStrm << " InputKey = ENCODING_TYPE" << endl; + trnsStrm << " Translation = (*,*)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = PdsCompressedFile" << endl; + trnsStrm << " InputPosition = COMPRESSED_FILE" << endl; + trnsStrm << " InputKey = FILE_NAME" << endl; + trnsStrm << " Translation = (*,*)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "END"; + + Isis::PvlTranslationManager pdsXlater (p_pdsLabel, trnsStrm); + + // Check to see if we are dealing with a JPEG2000 file + Isis::iString str; + if (pdsXlater.InputHasKeyword("PdsEncodingType")) { + str = pdsXlater.Translate("PdsEncodingType"); + if (str == "JP2") { + p_encodingType = JP2; + str = pdsXlater.Translate("PdsCompressedFile"); + if (pdsDataFile.empty()) { + Isis::Filename lfile (p_labelFile); + Isis::Filename ifile (lfile.Path() + "/" + str); + if (ifile.Exists()) { + p_jp2File = ifile.Expanded(); + } + else { + string tmp = ifile.Expanded(); + str.DownCase(); + ifile = lfile.Path() + "/" + str; + if (ifile.Exists()) { + p_jp2File = ifile.Expanded(); + } + else { + string msg = "Unable to find input file [" + tmp + "] or [" + + ifile.Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + } + } + else { + string msg = "Unsupported encoding type in [" + p_labelFile + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + + // Call the correct label processing + if (pdsXlater.InputHasKeyword("PdsTypeImage")) { + ProcessPdsImageLabel (pdsDataFile); + } + else if (pdsXlater.InputHasKeyword("PdsTypeQube")) { + ProcessPdsQubeLabel (pdsDataFile, "pdsQube.trn"); + } + else if (pdsXlater.InputHasKeyword("PdsTypeSpectralQube")) { + ProcessPdsQubeLabel (pdsDataFile, "pdsSpectralQube.trn"); + } + else { + string msg = "Unknown label type in [" + p_labelFile + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // Find out if this is a PDS file or an ISIS2 file + IdentifySource(p_pdsLabel); + + return; + } + + /** + * Process the PDS label of type IMAGE. + * + * @param pdsDataFile The name of the PDS data file where the actual image/cube + * data is stored. This parameter can be an empty string, in + * which case the label information will be searched to find + * the data file name or the data will be assumed to be + * after the label information. + * + * @throws Isis::iException::Message + */ + void ProcessImportPds::ProcessPdsImageLabel (const std::string &pdsDataFile) { + Isis::Filename transFile (p_transDir + "/translations/pdsImage.trn"); + Isis::PvlTranslationManager pdsXlater (p_pdsLabel, transFile.Expanded()); + + Isis::iString str; + + str = pdsXlater.Translate("CoreLinePrefixBytes"); + SetDataPrefixBytes(str.ToInteger()); + + str = pdsXlater.Translate("CoreLineSuffixBytes"); + SetDataSuffixBytes(str.ToInteger()); + + str = pdsXlater.Translate ("CoreBitsPerPixel"); + int bitsPerPixel = str.ToInteger(); + str = pdsXlater.Translate ("CorePixelType"); + if ((str == "Real") && (bitsPerPixel == 32)) {SetPixelType (Isis::Real);} + else if ((str == "Integer") && (bitsPerPixel == 8)) {SetPixelType (Isis::UnsignedByte);} + else if ((str == "Integer") && (bitsPerPixel == 16)) {SetPixelType (Isis::SignedWord);} + else if ((str == "Integer") && (bitsPerPixel == 32)) {SetPixelType (Isis::SignedInteger);} + else if ((str == "Natural") && (bitsPerPixel == 8)) {SetPixelType (Isis::UnsignedByte);} + else if ((str == "Natural") && (bitsPerPixel == 16)) {SetPixelType (Isis::UnsignedWord);} + else if ((str == "Natural") && (bitsPerPixel == 16)) {SetPixelType (Isis::SignedWord);} + else if ((str == "Natural") && (bitsPerPixel == 32)) {SetPixelType (Isis::UnsignedInteger);} + else { + string msg = "Invalid PixelType and BitsPerPixel combination [" + str + + ", " + Isis::iString(bitsPerPixel) + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + str = pdsXlater.Translate ("CoreByteOrder"); + SetByteOrder (Isis::ByteOrderEnumeration(str)); + + str = pdsXlater.Translate ("CoreSamples"); + int ns = str.ToInteger(); + str = pdsXlater.Translate ("CoreLines"); + int nl = str.ToInteger(); + str = pdsXlater.Translate ("CoreBands"); + int nb = str.ToInteger(); + SetDimensions (ns, nl, nb); + + // Set any special pixel values + double pdsNull = Isis::NULL8; + if (pdsXlater.InputHasKeyword("CoreNull")) { + str = pdsXlater.Translate("CoreNull"); + if (str != "NULL") { + pdsNull = str.ToDouble(); + } + } + else if (pdsXlater.InputHasKeyword("CoreNull2")) { + str = pdsXlater.Translate("CoreNull2"); + if (str != "NULL") { + pdsNull = str.ToDouble(); + } + } + + double pdsLrs = Isis::Lrs; + if (pdsXlater.InputHasKeyword("CoreLrs")) { + str = pdsXlater.Translate("CoreLrs"); + if (str != "NULL") { + pdsLrs = str.ToDouble(); + } + } + else if (pdsXlater.InputHasKeyword("CoreLrs2")) { + str = pdsXlater.Translate("CoreLrs2"); + if (str != "NULL") { + pdsLrs = str.ToDouble(); + } + } + + double pdsLis = Isis::Lis; + if (pdsXlater.InputHasKeyword("CoreLis")) { + str = pdsXlater.Translate("CoreLis"); + if (str != "NULL") { + pdsLis = str.ToDouble(); + } + } + else if (pdsXlater.InputHasKeyword("CoreLis2")) { + str = pdsXlater.Translate("CoreLis2"); + if (str != "NULL") { + pdsLis = str.ToDouble(); + } + } + + double pdsHrs = Isis::Hrs; + if (pdsXlater.InputHasKeyword("CoreHrs")) { + str = pdsXlater.Translate("CoreHrs"); + if (str != "NULL") { + pdsHrs = str.ToDouble(); + } + } + else if (pdsXlater.InputHasKeyword("CoreHrs2")) { + str = pdsXlater.Translate("CoreHrs2"); + if (str != "NULL") { + pdsHrs = str.ToDouble(); + } + } + + double pdsHis = Isis::His; + if (pdsXlater.InputHasKeyword("CoreHis")) { + str = pdsXlater.Translate("CoreHis"); + if (str != "NULL") { + pdsHis = str.ToDouble(); + } + } + else if (pdsXlater.InputHasKeyword("CoreHis2")) { + str = pdsXlater.Translate("CoreHis2"); + if (str != "NULL") { + pdsHis = str.ToDouble(); + } + } + + SetSpecialValues (pdsNull, pdsLrs, pdsLis, pdsHrs, pdsHis); + + //----------------------------------------------------------------- + // Find the data filename it may be the same as the label file + // OR the label file may contain a pointer to the data + //----------------------------------------------------------------- + + // Use the name supplied by the application if it is there + if (pdsDataFile.length() > 0) { + SetInputFile (pdsDataFile); + } + // If the data is in JPEG 2000 format, then use the name of the file + // from the label + else if (p_jp2File.length() > 0) { + SetInputFile (p_jp2File); + } + // Use the "^IMAGE or ^QUBE" label to get the filename for the image data + // Get the path portion from user entered label file spec + else if (pdsXlater.InputKeyword("DataFilePointer").Size() == 2) { + Isis::iString dataFile; + dataFile = pdsXlater.Translate ("DataFilePointer", 0); + Isis::Filename lfile (p_labelFile); + Isis::Filename ifile (lfile.Path() + "/" + dataFile); + if (ifile.Exists()) { + SetInputFile (ifile.Expanded()); + } + else { + string tmp = ifile.Expanded(); + dataFile.DownCase(); + ifile = lfile.Path() + "/" + dataFile; + if (ifile.Exists()) { + SetInputFile (ifile.Expanded()); + } + else { + string msg = "Unable to find input file [" + tmp + "] or [" + + ifile.Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + } + // The ^IMAGE keyword contains either the filename or the offset + // within this file + else if (pdsXlater.InputKeyword("DataFilePointer").Size() == 1) { + // Try converting the single value to an integer. If that works + // then the iamge data must be in the same file as the labels + try { + str = pdsXlater.Translate("DataFilePointer"); + str.ToInteger(); + SetInputFile (p_labelFile); + } + // If it can't be converted to an integer then it must be + // the name of the file that contains the image data + catch (Isis::iException &e) { + Isis::iString dataFile; + dataFile = pdsXlater.Translate ("DataFilePointer", 0); + Isis::Filename lfile (p_labelFile); + Isis::Filename ifile (lfile.Path() + "/" + dataFile); + if (ifile.Exists()) { + SetInputFile (ifile.Expanded()); + } + else { + string tmp = ifile.Expanded(); + dataFile.DownCase(); + ifile = lfile.Path() + "/" + dataFile; + if (ifile.Exists()) { + SetInputFile (ifile.Expanded()); + } + else { + string msg = "Unable to find input file [" + tmp + "] or [" + + ifile.Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + } + } + + // Could not find a filename for the image data + else { + string msg = "No data filename available on command line or in [" + + p_labelFile + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + //---------------------------------------------------------------- + // Calculate the file header size + //---------------------------------------------------------------- + + Isis::iString units; + if (pdsXlater.InputKeyword ("DataStart").Size() == 1) { + str = pdsXlater.Translate ("DataStart", 0); + units = pdsXlater.InputKeyword ("DataStart").Unit(); + try { + str.ToInteger (); + } + catch (Isis::iException &e) { + str = "1"; + units = "BYTES"; + } + } + else if (pdsXlater.InputKeyword("DataStart").Size() == 2) { + str = pdsXlater.Translate ("DataStart", 1); + units = pdsXlater.InputKeyword ("DataStart").Unit(1); + } + else { + string msg = "Invalid PDS labels in file [" + p_labelFile + + "]. Label value [" + + pdsXlater.InputKeywordName("DataStart") + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + units.Trim(" \t\r\v\n"); + // Set the number of file header bytes using a byte count + // byte counts are 1 based + if ((units == "BYTES") || (units == "B")) { + SetFileHeaderBytes(str.ToInteger() - 1); + } + // Set the number of file header bytes using a record number + else { + Isis::iString recSize = pdsXlater.Translate("DataFileRecordBytes"); + SetFileHeaderBytes ((str.ToInteger() - 1) * recSize.ToInteger()); + } + + //------------------------------------------------------------ + // Find the image data base and multiplier + //------------------------------------------------------------ + str = pdsXlater.Translate ("CoreBase"); + SetBase (str.ToDouble()); + str = pdsXlater.Translate ("CoreMultiplier"); + SetMultiplier (str.ToDouble()); + + // Find the organization of the image data + str =pdsXlater.Translate("CoreOrganization"); + + if (p_encodingType == JP2) { + SetOrganization (ProcessImport::JP2); + } + else if (str == "BSQ") { + SetOrganization (ProcessImport::BSQ); + } + else if (str == "BIP") { + SetOrganization (ProcessImport::BIP); + } + else if (str == "BIL") { + SetOrganization (ProcessImport::BIL); + } + } + + + /** + * Process the PDS label of type QUBE or SPECTRALQUBE. + * + * @param pdsDataFile The name of the PDS data file where the actual image/cube + * data is stored. This parameter can be an empty string, in + * which case the label information will be searched to find + * the data file name or the data will be assumed to be + * after the label information. + * + * @param transFile + * + * @throws Isis::iException::Message + */ + void ProcessImportPds::ProcessPdsQubeLabel (const std::string &pdsDataFile, + const std::string &transFile) { + + Isis::PvlGroup &dataDir = Isis::Preference::Preferences().FindGroup("DataDirectory"); + Isis::iString transDir = (string) dataDir["Base"]; + Isis::Filename tFile (transDir + "/translations/" + transFile); + + Isis::PvlTranslationManager pdsXlater (p_pdsLabel, tFile.Expanded()); + + Isis::iString str; + + // Find the organization of the image data + // Save off which axis the samples, lines and bands are on + int linePos = 0; + int samplePos = 0; + int bandPos = 0; + int val = pdsXlater.InputKeyword("CoreOrganization").Size(); + Isis::iString tmp = ""; + for (int i=0; i 0) { + SetInputFile (pdsDataFile); + } + + // If the data is in JPEG 2000 format, then use the name of the file + // from the label + else if (p_jp2File.length() > 0) { + SetInputFile (p_jp2File); + } + + // Get the filename for the image data + // Get the path portion from user entered label file spec + else if (pdsXlater.InputKeyword("DataFilePointer").Size() == 2) { + Isis::iString dataFile; + dataFile = pdsXlater.Translate ("dataFilePointer", 0); + Isis::Filename lfile (p_labelFile); + Isis::Filename ifile (lfile.Path() + "/" + dataFile); + if (ifile.Exists()) { + SetInputFile (ifile.Expanded()); + } + else { + string tmp = ifile.Expanded(); + dataFile.DownCase(); + ifile = lfile.Path() + "/" + dataFile; + if (ifile.Exists()) { + SetInputFile (ifile.Expanded()); + } + else { + string msg = "Unable to find input file [" + tmp + "] or [" + + ifile.Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + } + + // Use the same name as the label file to get the filename for the image data + else if (pdsXlater.InputKeyword("DataFilePointer").Size() == 1) { + SetInputFile (p_labelFile); + } + + // Could not find a filename for the image data + else { + string msg = "No data filename available on command line or in [" + + p_labelFile + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + //---------------------------------------------------------------- + // Calculate the file header size + //---------------------------------------------------------------- + Isis::iString units; + if (pdsXlater.InputKeyword ("DataFilePointer").Size() == 1) { + str = pdsXlater.Translate ("DataFilePointer", 0); + units = pdsXlater.InputKeyword ("DataFilePointer").Unit(); + } + else if (pdsXlater.InputKeyword("DataFilePointer").Size() == 2) { + str = pdsXlater.Translate ("DataFilePointer", 1); + units = pdsXlater.InputKeyword ("DataFilePointer").Unit(1); + } + else { + string msg = "Invalid PDS labels in file [" + p_labelFile + + "]. Label value [" + + pdsXlater.InputKeywordName("DataFilePointer") + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + units.Trim(" \t\r\v\n"); + // Set the number of file header bytes using a byte count + // Byte positions are 1 based + if (units == "BYTES") { + SetFileHeaderBytes(str.ToInteger() - 1); + } + // Set the number of file header bytes using a record number + else { + Isis::iString recSize = pdsXlater.Translate("DataFileRecordBytes"); + SetFileHeaderBytes ((str.ToInteger() - 1) * recSize.ToInteger()); + } + + //------------------------------------------------------------ + // Find the image data base and multiplier + //------------------------------------------------------------ + // First see if there are base and multiplier in the band bin group + if ((pdsXlater.InputHasKeyword("BandBase")) && + (pdsXlater.InputHasKeyword("BandMultiplier"))) { + vector bases; + vector mults; + for (int i=0; iPutGroup(lab.FindGroup("Mapping")); + } + + /** + * Extract all possible PDS projection parameters from the PDS label + * + * @param pdsXlater + * + * @throws Isis::iException::Message + * + * @history 2007-04-12 Tracie Sucharski - Modified the projection translation + * tables to include additional versions of + * Longitude direction, latitude type and if + * the min or max longitude values is greater than + * 180, change longitude domain to 360. + * Read projection mults/offsets from def file + * so lat/lon values are correct. + * @history 2007-07-12 Stuart Sides- Modified to handle units + * of meters on the pixel + * resolution + * + * @history 2008-06-06 Tracie Sucharski, Added LineProjectionOffset2 for + * Magellan images. + * @history 2008-06-09 Tracie Sucharski, Added MinimumLongitude2 and + * MaximumLongitude2 for Magellan images. + * + */ + void ProcessImportPds::ExtractPdsProjection(Isis::PvlTranslationManager &pdsXlater) { + + Isis::iString str; + + if (pdsXlater.InputHasKeyword("ProjectionName")) { + p_projection = pdsXlater.Translate("ProjectionName"); + } + else { + string message = "No projection name in labels"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + + if (pdsXlater.InputHasKeyword("TargetName")) { + p_targetName = pdsXlater.Translate("TargetName"); + } + else { + string message = "No target name in labels"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + + if (pdsXlater.InputHasKeyword("EquatorialRadius")) { + str = pdsXlater.Translate ("EquatorialRadius"); + p_equatorialRadius = str.ToDouble() * 1000.0; + } + else { + string message = "No equatorial radius name in labels"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + + if (pdsXlater.InputHasKeyword("PolarRadius")) { + str = pdsXlater.Translate ("PolarRadius"); + p_polarRadius = str.ToDouble() * 1000.0; + } + else { + string message = "No polar radius in labels"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + + if (pdsXlater.InputHasKeyword("LongitudeDirection")) { + p_longitudeDirection = pdsXlater.Translate ("LongitudeDirection"); + } + else { + p_longitudeDirection = pdsXlater.Translate ("LongitudeDirection2"); + } + + if(p_polarRadius == p_equatorialRadius) { + p_latitudeType = "Planetocentric"; + } + else if (pdsXlater.InputHasKeyword("LatitudeType2")) { + p_latitudeType = pdsXlater.Translate ("LatitudeType2"); + } + else { + p_latitudeType = pdsXlater.Translate ("LatitudeType"); + } + + if (pdsXlater.InputHasKeyword("MinimumLatitude")) { + str = pdsXlater.Translate ("MinimumLatitude"); + try { + p_minimumLatitude = str.ToDouble(); + } + catch (Isis::iException &e) { + e.Clear(); + p_minimumLatitude = Isis::NULL8; + } + } + else { + p_minimumLatitude = Isis::NULL8; + } + + if (pdsXlater.InputHasKeyword("MaximumLatitude")) { + str = pdsXlater.Translate ("MaximumLatitude"); + try { + p_maximumLatitude = str.ToDouble(); + } + catch (Isis::iException &e) { + e.Clear(); + p_maximumLatitude = Isis::NULL8; + } + } + else { + p_maximumLatitude = Isis::NULL8; + } + + // This variable represents if the longitudes were read in as + // positive west + bool positiveWest = false; + if (pdsXlater.InputHasKeyword("MinimumLongitude")) { + str = pdsXlater.Translate ("MinimumLongitude"); + try { + positiveWest = true; + p_minimumLongitude = str.ToDouble(); + } + catch (Isis::iException &e) { + e.Clear(); + p_minimumLongitude = Isis::NULL8; + } + } + else if (pdsXlater.InputHasKeyword("MinimumLongitude2")) { + str = pdsXlater.Translate ("MinimumLongitude2"); + try { + p_minimumLongitude = str.ToDouble(); + } + catch (Isis::iException &e) { + e.Clear(); + p_minimumLongitude = Isis::NULL8; + } + } + else { + p_minimumLongitude = Isis::NULL8; + } + + if (pdsXlater.InputHasKeyword("MaximumLongitude")) { + str = pdsXlater.Translate ("MaximumLongitude"); + try { + positiveWest = true; + p_maximumLongitude = str.ToDouble(); + } + catch (Isis::iException &e) { + e.Clear(); + p_maximumLongitude = Isis::NULL8; + } + } + else if (pdsXlater.InputHasKeyword("MaximumLongitude2")) { + str = pdsXlater.Translate ("MaximumLongitude2"); + try { + p_maximumLongitude = str.ToDouble(); + } + catch (Isis::iException &e) { + e.Clear(); + p_maximumLongitude = Isis::NULL8; + } + } + else { + p_maximumLongitude = Isis::NULL8; + } + + str = pdsXlater.Translate ("LongitudeDomain"); + p_longitudeDomain = str.ToInteger(); + + /** + * The input file does not have a longitude domain. + * We need to figure it out! + * + * The current process is two-step. First, we use the + * longitude direction to swap into what should be the + * proper order of min,max longitude. Then, if the values + * are still misordered, we have a 180 domain projection. + * Try converting the minimum to 180 domain, which hopefully + * results in ordering the min,max properly. Only do this to + * the minimum because if they are out of order, then it must + * be something like 330-30 which needs to be -30-30. + * + * pdsImageProjection.trn assumes EasternMost is the MINIMUM, + * which is PositiveWest. For a PositiveEast image this + * swap should occur. On a PositiveWest image this swap should not + * occur. + */ + if(positiveWest && (p_longitudeDirection.compare("PositiveEast") == 0)) { + double tmp = p_minimumLongitude; + p_minimumLongitude = p_maximumLongitude; + p_maximumLongitude = tmp; + } + + if(p_minimumLongitude > p_maximumLongitude) { + // Force the change to 180 + p_longitudeDomain = 180; + p_minimumLongitude = Isis::Projection::To180Domain(p_minimumLongitude); + } + + // If either the minimumLongitude or maximumLongitude are < 0, change + // longitude Domain to 180. + if (p_minimumLongitude < 0 || p_maximumLongitude < 0) { + p_longitudeDomain = 180; + } + + str = pdsXlater.Translate ("PixelResolution"); + p_pixelResolution = str.ToDouble(); + str = pdsXlater.InputKeyword ("PixelResolution").Unit(); + str.UpCase(); + // Assume KM/PIXEL if the unit doesn't exist or is not METERS/PIXEL + if ((str != "METERS/PIXEL") && (str != "M/PIXEL")) { + p_pixelResolution *= 1000.0; + } + + str = pdsXlater.Translate ("Scale"); + p_scaleFactor = str.ToDouble(); + + str = pdsXlater.Translate("Rotation"); + p_rotation = str.ToDouble(); + + // Look for projection offsets/mults to convert between line/samp and x/y + double xoff,yoff,xmult,ymult; + GetProjectionOffsetMults(xoff,yoff,xmult,ymult); + + if (pdsXlater.InputHasKeyword("LineProjectionOffset")) { + str = pdsXlater.Translate ("LineProjectionOffset"); + } + else { + str = pdsXlater.Translate ("LineProjectionOffset2"); + } + p_lineProjectionOffset = str.ToDouble(); + p_upperLeftY = ymult * (p_lineProjectionOffset + yoff) * p_pixelResolution; + + if (pdsXlater.InputHasKeyword("SampleProjectionOffset")) { + str = pdsXlater.Translate ("SampleProjectionOffset"); + } + else { + str = pdsXlater.Translate ("SampleProjectionOffset2"); + } + p_sampleProjectionOffset = str.ToDouble(); + p_upperLeftX = xmult * (p_sampleProjectionOffset + xoff) * p_pixelResolution; + + + } + + /** + * End the processing sequence and cleans up by closing cubes, + * freeing memory, etc. Adds the OriginalLabel data to the end + * of the cube file, unless OmitOriginalLabel() has been called. + */ + void ProcessImportPds::EndProcess(){ + if (p_keepOriginalLabel) { + OriginalLabel ol(p_pdsLabel); + for (unsigned int i=0; iWrite(ol); + } + } + Process::EndProcess(); + } + + /** + * Prevents the Original Label blob from being written out to + * the end of the cube. + */ + void ProcessImportPds::OmitOriginalLabel(){ + p_keepOriginalLabel = false; + } + + + /** + * Identify the source of this file PDS or ISIS2. + * + * @param inputLabel The label from the input file. + * + */ + void ProcessImportPds::IdentifySource (Isis::Pvl &inputLabel) { + + // Create a temporary Isis::PvlTranslationManager so we can find out what + // type of input file we have + stringstream trnsStrm; + trnsStrm << "Group = PdsFile" << endl; + trnsStrm << " InputPosition = ROOT" << endl; + trnsStrm << " InputKey = PDS_VERSION_ID" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = Isis2File" << endl; + trnsStrm << " InputPosition = ROOT" << endl; + trnsStrm << " InputKey = CCSD3ZF0000100000001NJPL3IF0PDS200000001" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "END"; + + Isis::PvlTranslationManager sourceXlater (inputLabel, trnsStrm); + + if (sourceXlater.InputHasKeyword("PdsFile")) { + p_source = PDS; + } + else if (sourceXlater.InputHasKeyword("Isis2File")) { + p_source = ISIS2; + } + else { + p_source = NOSOURCE; + } + + } + + /** + * Return true if ISIS2 cube, else return false + * + * @return (bool) returns true if pds file is an Isis2 file + * + * @history 2007-04-12 Tracie Sucharski - New method + * + */ + bool ProcessImportPds::IsIsis2() { + + if (p_source == ISIS2) { + return true; + } + else { + return false; + } + } + + + + /** + * Translate as many of the ISIS2 labels as possible + * + * @param lab The label where the translated Isis2 keywords will + * be placed + * + */ + void ProcessImportPds::TranslateIsis2Labels (Isis::Pvl &lab) { + TranslateIsis2BandBin (lab); + TranslateIsis2Instrument (lab); + } + + + + /** + * Translate as many of the PDS labels as possible + * + * @param lab The label where the translated Isis2 keywords will + * be placed + * + */ + void ProcessImportPds::TranslatePdsLabels (Isis::Pvl &lab) { + TranslatePdsBandBin (lab); + TranslatePdsArchive (lab); + } + + /** + * Fill as many of the Isis3 BandBin labels as possible + * + * @param lab The lable where the translated Isis2 keywords will + * be placed + */ + void ProcessImportPds::TranslateIsis2BandBin (Isis::Pvl &lab) { + // Set up a translater for Isis2 labels + Isis::PvlGroup &dataDir = Isis::Preference::Preferences().FindGroup("DataDirectory"); + Isis::iString transDir = (string) dataDir["Base"]; + + Isis::Filename transFile (transDir + "/" + "translations/isis2bandbin.trn"); + Isis::PvlTranslationManager isis2Xlater (p_pdsLabel, transFile.Expanded()); + + // Add all the Isis2 keywords that can be translated to the requested label + isis2Xlater.Auto(lab); + } + + /** + * Fill as many of the Isis3 instrument labels as possible + * + * @param lab The label where the tramslated Isis2 keywords will + * be placed + */ + void ProcessImportPds::TranslateIsis2Instrument (Isis::Pvl &lab) { + // Set up a translater for Isis2 labels + Isis::PvlGroup &dataDir = Isis::Preference::Preferences().FindGroup("DataDirectory"); + Isis::iString transDir = (string) dataDir["Base"]; + Isis::Filename transFile (transDir + "/" + "translations/isis2instrument.trn"); + Isis::PvlTranslationManager isis2Xlater (p_pdsLabel, transFile.Expanded()); + + // Add all the Isis2 keywords that can be translated to the requested label + isis2Xlater.Auto(lab); + + //Check StartTime for appended 'z' (Zulu time) and remove + Isis::PvlGroup &inst = lab.FindGroup("Instrument"); + + if (inst.HasKeyword("StartTime")) { + Isis::PvlKeyword &stkey = inst["StartTime"]; + Isis::iString stime = stkey[0]; + stime = stime.Trim("Zz"); + stkey = stime; + } + } + + /** + * Fill as many of the Isis3 BandBin labels as possible + * + * @param lab The lable where the translated PDS keywords will + * be placed + */ + void ProcessImportPds::TranslatePdsBandBin (Isis::Pvl &lab) { + // Set up a translater for PDS labels + Isis::Filename transFile (p_transDir + "/" + "translations/pdsImageBandBin.trn"); + Isis::PvlTranslationManager isis2Xlater (p_pdsLabel, transFile.Expanded()); + + // Add all the Isis2 keywords that can be translated to the requested label + isis2Xlater.Auto(lab); + } + + /** + * Fill as many of the Isis3 BandBin labels as possible + * + * @param lab The lable where the translated PDS keywords will + * be placed + */ + void ProcessImportPds::TranslatePdsArchive (Isis::Pvl &lab) { + // Set up a translater for PDS labels + Isis::Filename transFile (p_transDir + "/" + "translations/pdsImageArchive.trn"); + Isis::PvlTranslationManager isis2Xlater (p_pdsLabel, transFile.Expanded()); + + // Add all the Isis2 keywords that can be translated to the requested label + isis2Xlater.Auto(lab); + } + + /** + * Read mults and offsets from a def file in order to calculate the upper + * left x/y. + * + * @param[out] xoff (double &) x offset + * @param[out] yoff (double &) y offset + * @param[out] xmult (double &) x multiplicative factor + * @param[out] ymult (double &) y multiplicative factor + * + * @history 2007-04-12 Tracie Sucharski - New Method + * + */ + void ProcessImportPds::GetProjectionOffsetMults (double &xoff, double &yoff, + double &xmult, double &ymult) { + + xmult = -1.0; + ymult = 1.0; + xoff = -0.5; + yoff = -0.5; + + // Open projectionOffsetMults file + Isis::Pvl p(p_transDir + "/" + "translations/pdsProjectionLineSampToXY.def"); + + Isis::PvlObject &projDef = p.FindObject("ProjectionOffsetMults", + Pvl::Traverse); + + for (int g=0; g + ARTICULATION_DEVICE_ANGLE_NAME = (AZIMUTH-MEASURED, ELEVATION-MEASURED, + AZIMUTH-REQUESTED, ELEVATION-REQUESTED, + AZIMUTH-INITIAL, ELEVATION-INITIAL) + ARTICULATION_DEVICE_MODE = DEPLOYED +End_Group + +/* ARTICULATION DEVICE STATE: HIGH GAIN ANTENNA */ +Group = HGA_ARTICULATION_STATE + ARTICULATION_DEVICE_ID = HGA + ARTICULATION_DEVICE_NAME = "HIGH GAIN ANTENNA" + ARTICULATION_DEVICE_ANGLE = (0.523867, 0.523975) + ARTICULATION_DEVICE_ANGLE_NAME = (AZIMUTH, ELEVATION) +End_Group + +/* ARTICULATION DEVICE STATE: FILTER */ +Group = FILTER_ARTICULATION_STATE + ARTICULATION_DEVICE_ID = FILTER + ARTICULATION_DEVICE_NAME = "FILTER ACTUATORS" + ARTICULATION_DEV_POSITION = (7, 2, 17) + ARTICULATION_DEV_POSITION_ID = (PANCAM_L7_440NM, PANCAM_R2_754NM, + MI_CLOSED) + ARTICULATION_DEV_POSITION_NAME = ("LEFT PANCAM FILTER", + "RIGHT PANCAM FILTER", "MI DUST COVER") +End_Group + +/* ARTICULATION DEVICE STATE: INSTRUMENT DEPLOYMENT DEVICE */ +Group = IDD_ARTICULATION_STATE + ARTICULATION_DEVICE_ID = IDD + ARTICULATION_DEVICE_NAME = "INSTRUMENT DEPLOYMENT DEVICE" + ARTICULATION_DEVICE_ANGLE = (-0.16709, -0.342424, 1.39101, 3.01013, + -2.09443, -0.173267, -0.347162, 1.39253, + 3.02501, -2.12136) + ARTICULATION_DEVICE_ANGLE_NAME = ("JOINT 1 AZIMUTH-ENCODER", + "JOINT 2 ELEVATION-ENCODER", + "JOINT 3 ELBOW-ENCODER", + "JOINT 4 WRIST-ENCODER", + "JOINT 5 TURRET-ENCODER", + "JOINT 1 AZIMUTH-POTENTIOMETER", + "JOINT 2 ELEVATION-POTENTIOMETER", + "JOINT 3 ELBOW-POTENTIOMETER", + "JOINT 4 WRIST-POTENTIOMETER", + "JOINT 5 TURRET-POTENTIOMETER") + ARTICULATION_DEVICE_MODE = GUARDED + ARTICULATION_DEVICE_TEMP = (-30.9296, -22.4574) + ARTICULATION_DEVICE_TEMP_NAME = ("AZIMUTH JOINT 1", "TURRET JOINT 5") + ARTICULATION_DEV_VECTOR = (-0.0353972, 0.00287072, 0.999369) + ARTICULATION_DEV_INSTRUMENT_ID = MI + ARTICULATION_DEV_VECTOR_NAME = GRAVITY + CONTACT_SENSOR_STATE = ("NO CONTACT", "NO CONTACT", CONTACT, + CONTACT, "NO CONTACT", "NO CONTACT", + CLOSED, "NO CONTACT") + CONTACT_SENSOR_STATE_NAME = ("MI SWITCH 1", "MI SWITCH 2", + "RAT SWITCH 1", "RAT SWITCH 2", + "MB SWITCH 1", "MB SWITCH 2", + "APXS DOOR SWITCH", "APXS CONTACT SWITCH") +End_Group + +/* COORDINATE SYSTEM STATE: PANCAM MAST ASSEMBLY */ +Group = PMA_COORDINATE_SYSTEM + COORDINATE_SYSTEM_INDEX = (3, 27, 149, 1886, 1347) + COORDINATE_SYSTEM_INDEX_NAME = (SITE, DRIVE, IDD, PMA, HGA) + COORDINATE_SYSTEM_NAME = MAST_FRAME + ORIGIN_OFFSET_VECTOR = (0.45781, 0.02779, -1.09668) + ORIGIN_ROTATION_QUATERNION = (0.0465651, 0.306669, -0.0150229, 0.950558) + POSITIVE_AZIMUTH_DIRECTION = CLOCKWISE + POSITIVE_ELEVATION_DIRECTION = UP + REFERENCE_COORD_SYSTEM_INDEX = (3, 27, 149, 1886, 1347) + REFERENCE_COORD_SYSTEM_NAME = ROVER_FRAME +End_Group + +/* ARTICULATION DEVICE STATE: MOBILITY CHASSIS */ +Group = CHASSIS_ARTICULATION_STATE + ARTICULATION_DEVICE_ID = CHASSIS + ARTICULATION_DEVICE_NAME = "MOBILITY CHASSIS" + ARTICULATION_DEVICE_ANGLE = (-0.00212176, -0.0059257, -0.00674381, + 0.00963577, 0.0291252, 0.00517551, + 0.0132111) + ARTICULATION_DEVICE_ANGLE_NAME = ("LEFT FRONT WHEEL POTENTIOMETER", + "RIGHT FRONT WHEEL POTENTIOMETER", + "LEFT REAR WHEEL POTENTIOMETER", + "RIGHT REAR WHEEL POTENTIOMETER", + "LEFT BOGIE POTENTIOMETER", + "RIGHT BOGIE POTENTIOMETER", + "DIFFERENTIAL BOGIE POTENTIOMETER") + ARTICULATION_DEVICE_MODE = DEPLOYED +End_Group + +/* OBSERVATION REQUEST */ +Group = OBSERVATION_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + COMMAND_INSTRUMENT_ID = MI + FILTER_NAME = MI_CLOSED + AUTO_EXPOSURE_DATA_CUT = 2500 + AUTO_EXPOSURE_PERCENT = 10.0 + AUTO_EXPOSURE_PIXEL_FRACTION = 1.0 + BAD_PIXEL_REPLACEMENT_FLAG = FALSE + DETECTOR_ERASE_COUNT = 2 + EARLY_PIXEL_SCALE_FLAG = FALSE + EARLY_IMAGE_RETURN_FLAG = FALSE + EXPOSURE_TYPE = AUTO + EXPOSURE_SCALE_FACTOR = 1.0 + EXPOSURE_DURATION_COUNT = 20 + EXPOSURE_TABLE_ID = EDL + EXPOSURE_TBL_UPDATE_FLAG = TRUE + FLAT_FIELD_CORRECTION_FLAG = FALSE + INSTRUMENT_COORDINATE = N/A + INSTRUMENT_COORDINATE_ID = NONE + INSTRUMENT_BORESIGHT_ID = UNK + INSTRUMENT_IDLE_TIMEOUT = 300 + MAX_AUTO_EXPOS_ITERATION_COUNT = 6 + SHUTTER_CORRECTION_MODE_ID = TRUE + SHUTTER_CORRECT_THRESH_COUNT = 0 +End_Group + +/* IMAGE REQUEST */ +Group = IMAGE_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = TRUE + DOWNLOAD_PRIORITY = 44 + PIXEL_DOWNSAMPLE_OPTION = NONE + PIXEL_AVERAGING_HEIGHT = 1 + PIXEL_AVERAGING_WIDTH = 1 + SAMPLE_BIT_MODE_ID = LUT3 + INST_CMPRS_MODE = 1 + INST_CMPRS_RATE = 1.0 + INST_CMPRS_QUALITY = 0 + INST_CMPRS_FILTER = E + INST_DECOMP_STAGES = 4 + INST_CMPRS_SEGMENTS = 32 +End_Group + +/* REFERENCE PIXEL REQUEST */ +Group = REFERENCE_PIXEL_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = FALSE + DOWNLOAD_PRIORITY = 44 + INST_CMPRS_MODE = 1 + INST_CMPRS_RATE = 12.0 + INST_CMPRS_QUALITY = 0 + INST_CMPRS_FILTER = E + INST_DECOMP_STAGES = 4 + INST_CMPRS_SEGMENTS = 1 +End_Group + +/* THUMBNAIL REQUEST */ +Group = THUMBNAIL_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = TRUE + DOWNLOAD_PRIORITY = 0 + LINES = 64 + LINE_SAMPLES = 64 + SAMPLE_BIT_MODE_ID = NONE + INST_CMPRS_MODE = 1 + INST_CMPRS_RATE = 1.0 + INST_CMPRS_QUALITY = 0 + INST_CMPRS_FILTER = E + INST_DECOMP_STAGES = 4 + INST_CMPRS_SEGMENTS = 1 +End_Group + +/* SUBFRAME REQUEST */ +Group = SUBFRAME_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = FALSE + SUBFRAME_TYPE = NONE + FIRST_LINE = 1 + FIRST_LINE_SAMPLE = 1 + LINES = 1024 + LINE_SAMPLES = 1024 +End_Group + +/* ROW SUMMATION REQUEST */ +Group = ROW_SUM_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = FALSE + DOWNLOAD_PRIORITY = 44 +End_Group + +/* COLUMN SUMMATION REQUEST */ +Group = COLUMN_SUM_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = FALSE + DOWNLOAD_PRIORITY = 44 +End_Group + +/* SUN FIND REQUEST */ +Group = SUN_FIND_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = FALSE + LINES = 63 + LINE_SAMPLES = 63 +End_Group + +/* HISTOGRAM REQUEST */ +Group = HISTOGRAM_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = FALSE + DOWNLOAD_PRIORITY = 44 +End_Group + +/* INSTRUMENT STATE RESULTS */ +Group = INSTRUMENT_STATE_PARMS + AZIMUTH_FOV = 37.3734 + ELEVATION_FOV = 37.3734 + BAD_PIXEL_REPLACEMENT_ID = N/A + DETECTOR_FIRST_LINE = 1 + DETECTOR_LINES = 1024 + DETECTOR_TO_IMAGE_ROTATION = 0.0 + DOWNSAMPLE_METHOD = SOFTWARE + EXPOSURE_COUNT = 2 + EXPOSURE_DURATION = 230.4 + EXPOSURE_DURATION_COUNT = 45 + FILTER_NAME = MI_CLOSED + FILTER_NUMBER = 1 + FLAT_FIELD_CORRECTION_FLAG = FALSE + FLAT_FIELD_CORRECTION_PARM = (0.0, 0.0, 0.0, 0.0, 0.0) + INSTRUMENT_MODE_ID = FULL_FRAME + INSTRUMENT_TEMPERATURE = (-26.9828, -15.1587, -8.44871, -15.6144, + -17.9811, 0.0, -18.333, -6.78394, + 0.0) + INSTRUMENT_TEMPERATURE_NAME = ("FRONT HAZ ELECTRONICS", + "REAR HAZ ELECTRONICS", + "LEFT PAN ELECTRONICS", "LEFT PAN CCD", + "RIGHT PAN CCD", "LEFT NAV CCD", "MI CCD", + "MI ELECTRONICS", "EDL CCD") + OFFSET_MODE_ID = 4090 + PIXEL_AVERAGING_HEIGHT = 16 + PIXEL_AVERAGING_WIDTH = 16 + SAMPLE_BIT_METHOD = NONE + SAMPLE_BIT_MODE_ID = NONE + SHUTTER_EFFECT_CORRECTION_FLAG = TRUE + SUN_FIND_FLAG = FALSE + SUN_FIND_PARM = (0.0, 0.0, 0.0) + SUN_FIND_PARM_NAME = ("WINDOW SIZE", "BRIGHTNESS THRESHOLD", + "SUMMED BRIGHTNESS") + SUN_LINE = -1 + SUN_LINE_SAMPLE = -1 + SUN_VIEW_POSITION = (0.0, 0.0, 0.0) + SUN_VIEW_DIRECTION = (0.0, 0.0, 0.0) +End_Group + +/* COMPRESSION RESULTS */ +Group = COMPRESSION_PARMS + ERROR_PIXELS = 0 + INST_CMPRS_DESC = "Lossless compression algorithm developed + at JPL" + INST_CMPRS_FILTER = E + INST_CMPRS_MODE = 1 + INST_CMPRS_NAME = "ICER ADAPTIVE VARIABLE-LENGTH CODING + (ICER)" + INST_CMPRS_RATE = 1.22266 + INST_CMPRS_RATIO = 9.8147 + INST_CMPRS_SEGMENTS = 1 + INST_CMPRS_SEGMENT_STATUS = 0 + INST_CMPRS_SEG_FIRST_LINE = 1 + INST_CMPRS_SEG_FIRST_LINE_SAMP = 1 + INST_CMPRS_SEG_LINES = 64 + INST_CMPRS_SEG_SAMPLES = 64 + INST_CMPRS_SEG_MISSING_PIXELS = N/A + INST_CMPRS_SEGMENT_QUALITY = 6.96875 + INST_DECOMP_STAGES = 4 +End_Group + +/* DERIVED GEOMETRY DATA ELEMENTS: ROVER FRAME */ +Group = ROVER_DERIVED_GEOMETRY_PARMS + INSTRUMENT_AZIMUTH = NULL + INSTRUMENT_ELEVATION = NULL + REFERENCE_COORD_SYSTEM_INDEX = (3, 27, 149, 1886, 1347) + REFERENCE_COORD_SYSTEM_NAME = ROVER_FRAME +End_Group + +/* DERIVED GEOMETRY DATA ELEMENTS: SITE FRAME */ +Group = SITE_DERIVED_GEOMETRY_PARMS + INSTRUMENT_AZIMUTH = NULL + INSTRUMENT_ELEVATION = NULL + REFERENCE_COORD_SYSTEM_INDEX = 3 + REFERENCE_COORD_SYSTEM_NAME = SITE_FRAME + SOLAR_AZIMUTH = 55.6811 + SOLAR_ELEVATION = -74.5811 +End_Group +End +isisimportpds: Gathering statistics +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +687.556 +282178 +PDS_VERSION_ID = PDS3 + +/* FILE DATA ELEMENTS */ +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 128 +FILE_RECORDS = 330 +LABEL_RECORDS = 170 + +/* POINTERS TO DATA OBJECTS */ +^IMAGE_HEADER = 171 +^IMAGE = 267 + +/* IDENTIFICATION DATA ELEMENTS */ +DATA_SET_ID = MER2-M-MI-2-EDR-V1.0 +DATA_SET_NAME = "MARS EXPLORATION ROVER 2 MICROSCOPIC IMAGER + CAMERA V1.0" +COMMAND_SEQUENCE_NUMBER = 1 +FRAME_ID = MONO +FRAME_TYPE = MONO +GEOMETRY_PROJECTION_TYPE = RAW +IMAGE_ID = 229420001 +IMAGE_TYPE = THUMBNAIL +INSTRUMENT_HOST_ID = MER2 +INSTRUMENT_HOST_NAME = "MARS EXPLORATION ROVER 2" +INSTRUMENT_ID = MI +INSTRUMENT_NAME = "MICROSCOPIC IMAGER" +INSTRUMENT_SERIAL_NUMBER = 105 +INSTRUMENT_TYPE = "IMAGING CAMERA" +INSTRUMENT_VERSION_ID = FM +LOCAL_TRUE_SOLAR_TIME = 11:08:59 +MAGNET_ID = NULL +MISSION_NAME = "MARS EXPLORATION ROVER" +MISSION_PHASE_NAME = "PRIMARY MISSION" +OBSERVATION_ID = 301989888 +PLANET_DAY_NUMBER = 35 +PRODUCER_INSTITUTION_NAME = "MULTIMISSION IMAGE PROCESSING SUBSYSTEM , + JET PROPULSION LAB" +PRODUCT_CREATION_TIME = 2004-02-08T03:13:17.000Z +PRODUCT_ID = 2M129469022ETH0327P2942M1M1 +PRODUCT_VERSION_ID = "V3.0 D-22846" +RELEASE_ID = 0001 +ROVER_MOTION_COUNTER = (3, 27, 149, 1886, 1347) +ROVER_MOTION_COUNTER_NAME = (SITE, DRIVE, IDD, PMA, HGA) +SEQUENCE_ID = p2942 +SEQUENCE_VERSION_ID = 1 +SOLAR_LONGITUDE = -13.6249 +SPACECRAFT_CLOCK_CNT_PARTITION = 1 +SPACECRAFT_CLOCK_START_COUNT = 129469022.371 +SPACECRAFT_CLOCK_STOP_COUNT = 129469022.601 +START_TIME = 2004-02-07T23:35:51.722Z +STOP_TIME = 2004-02-07T23:35:51.953Z +TARGET_NAME = MARS +TARGET_TYPE = PLANET + +/* TELEMETRY DATA ELEMENTS */ +APPLICATION_PROCESS_ID = 29 +APPLICATION_PROCESS_NAME = MI +APPLICATION_PROCESS_SUBTYPE_ID = 3 +EARTH_RECEIVED_START_TIME = 2004-02-08T03:13:03.241Z +EARTH_RECEIVED_STOP_TIME = 2004-02-08T03:13:05.487Z +EXPECTED_PACKETS = N/A +PACKET_MAP_MASK = N/A +RECEIVED_PACKETS = N/A +SPICE_FILE_NAME = /oss/mera/ops/ops/surface/strategic/ref/naif- + /misc/chronos/chronos.mer +TELEMETRY_PROVIDER_ID = "SSW MER_DP" +TELEMETRY_SOURCE_NAME = 029_003_p2942-001-0001_002_0129469022-095.dat +TELEMETRY_SOURCE_TYPE = "DATA PRODUCT" + +/* HISTORY DATA ELEMENTS */ +PROCESSING_HISTORY_TEXT = "CODMAC LEVEL 1 to LEVEL 2 CONVERSION VIA + JPL/MIPL MERTELEMPROC" +SOFTWARE_NAME = MERTELEMPROC +SOFTWARE_VERSION_ID = "V3.0 10-31-03" + +/* IMAGE DATA ELEMENTS */ +Object = IMAGE + INTERCHANGE_FORMAT = BINARY + LINES = 64 + LINE_SAMPLES = 64 + SAMPLE_TYPE = MSB_INTEGER + SAMPLE_BITS = 16 + BANDS = 1 + BAND_STORAGE_TYPE = BAND_SEQUENTIAL + CHECKSUM = 2.81623e+06 + FIRST_LINE = 1 + FIRST_LINE_SAMPLE = 1 + INVALID_CONSTANT = 0.0 + MAXIMUM = 2798.0 + MEAN = 687.556 + MEDIAN = 452.0 + MINIMUM = 238.0 + MISSING_CONSTANT = 0.0 + SAMPLE_BIT_MASK = 2#0000111111111111# + STANDARD_DEVIATION = 531.14 +End_Object + +/* IMAGE HEADER DATA ELEMENTS */ +Object = IMAGE_HEADER + HEADER_TYPE = VICAR2 + INTERCHANGE_FORMAT = ASCII + BYTES = 12288 + ^DESCRIPTION = VICAR2.TXT +End_Object + +/* CAMERA_MODEL DATA ELEMENTS */ +Group = GEOMETRIC_CAMERA_MODEL + CALIBRATION_SOURCE_ID = 173 + ^MODEL_DESC = GEOMETRIC_CM.TXT + MODEL_TYPE = CAHVOR + MODEL_COMPONENT_ID = (C, A, H, V, O, R) + MODEL_COMPONENT_NAME = (CENTER, AXIS, HORIZONTAL, VERTICAL, OPTICAL, + RADIAL) + MODEL_COMPONENT_1 = (1.10908, -0.113534, 0.138245) + MODEL_COMPONENT_2 = (0.585857, 0.404665, 0.702152) + MODEL_COMPONENT_3 = (-5.77698, 146.922, -35.9137) + MODEL_COMPONENT_4 = (-98.7607, 30.1022, 110.836) + MODEL_COMPONENT_5 = (0.638367, 0.334388, 0.693305) + MODEL_COMPONENT_6 = (0.007629, -0.104219, 0.624037) + FILTER_NAME = MI_CLOSED + REFERENCE_COORD_SYSTEM_INDEX = (3, 27, 149, 1886, 1347) + REFERENCE_COORD_SYSTEM_NAME = ROVER_FRAME +End_Group + +/* COORDINATE SYSTEM STATE: ROVER */ +Group = ROVER_COORDINATE_SYSTEM + COORDINATE_SYSTEM_INDEX = (3, 27, 149, 1886, 1347) + COORDINATE_SYSTEM_INDEX_NAME = (SITE, DRIVE, IDD, PMA, HGA) + COORDINATE_SYSTEM_NAME = ROVER_FRAME + ORIGIN_OFFSET_VECTOR = (-1.92792, -0.942284, -0.0451125) + ORIGIN_ROTATION_QUATERNION = (0.00913962, 0.0177138, -0.00127372, + -0.999801) + POSITIVE_AZIMUTH_DIRECTION = CLOCKWISE + POSITIVE_ELEVATION_DIRECTION = UP + QUATERNION_MEASUREMENT_METHOD = COARSE + REFERENCE_COORD_SYSTEM_INDEX = 3 + REFERENCE_COORD_SYSTEM_NAME = SITE_FRAME +End_Group + +/* COORDINATE SYSTEM STATE: INSTRUMENT DEPLOYMENT DEVICE */ +Group = IDD_COORDINATE_SYSTEM + COORDINATE_SYSTEM_INDEX = (3, 27, 149, 1886, 1347) + COORDINATE_SYSTEM_INDEX_NAME = (SITE, DRIVE, IDD, PMA, HGA) + COORDINATE_SYSTEM_NAME = MI_FRAME + ORIGIN_OFFSET_VECTOR = (1.14769, -0.0916314, 0.169059) + ORIGIN_ROTATION_QUATERNION = (0.654693, -0.385291, 0.0772833, -0.64572) + POSITIVE_AZIMUTH_DIRECTION = CLOCKWISE + POSITIVE_ELEVATION_DIRECTION = DOWN + REFERENCE_COORD_SYSTEM_INDEX = (3, 27, 149, 1886, 1347) + REFERENCE_COORD_SYSTEM_NAME = ROVER_FRAME +End_Group + +/* ARTICULATION DEVICE STATE: PANCAM MAST ASSEMBLY */ +Group = PMA_ARTICULATION_STATE + ARTICULATION_DEVICE_ID = PMA + ARTICULATION_DEVICE_NAME = "PANCAM MAST ASSEMBLY" + ARTICULATION_DEVICE_ANGLE = (3.03997, -0.677912, 0.0, 0.0, 0.0, + 0.0) + ARTICULATION_DEVICE_ANGLE_NAME = (AZIMUTH-MEASURED, ELEVATION-MEASURED, + AZIMUTH-REQUESTED, ELEVATION-REQUESTED, + AZIMUTH-INITIAL, ELEVATION-INITIAL) + ARTICULATION_DEVICE_MODE = DEPLOYED +End_Group + +/* ARTICULATION DEVICE STATE: HIGH GAIN ANTENNA */ +Group = HGA_ARTICULATION_STATE + ARTICULATION_DEVICE_ID = HGA + ARTICULATION_DEVICE_NAME = "HIGH GAIN ANTENNA" + ARTICULATION_DEVICE_ANGLE = (0.523867, 0.523975) + ARTICULATION_DEVICE_ANGLE_NAME = (AZIMUTH, ELEVATION) +End_Group + +/* ARTICULATION DEVICE STATE: FILTER */ +Group = FILTER_ARTICULATION_STATE + ARTICULATION_DEVICE_ID = FILTER + ARTICULATION_DEVICE_NAME = "FILTER ACTUATORS" + ARTICULATION_DEV_POSITION = (7, 2, 17) + ARTICULATION_DEV_POSITION_ID = (PANCAM_L7_440NM, PANCAM_R2_754NM, + MI_CLOSED) + ARTICULATION_DEV_POSITION_NAME = ("LEFT PANCAM FILTER", + "RIGHT PANCAM FILTER", "MI DUST COVER") +End_Group + +/* ARTICULATION DEVICE STATE: INSTRUMENT DEPLOYMENT DEVICE */ +Group = IDD_ARTICULATION_STATE + ARTICULATION_DEVICE_ID = IDD + ARTICULATION_DEVICE_NAME = "INSTRUMENT DEPLOYMENT DEVICE" + ARTICULATION_DEVICE_ANGLE = (-0.16709, -0.342424, 1.39101, 3.01013, + -2.09443, -0.173267, -0.347162, 1.39253, + 3.02501, -2.12136) + ARTICULATION_DEVICE_ANGLE_NAME = ("JOINT 1 AZIMUTH-ENCODER", + "JOINT 2 ELEVATION-ENCODER", + "JOINT 3 ELBOW-ENCODER", + "JOINT 4 WRIST-ENCODER", + "JOINT 5 TURRET-ENCODER", + "JOINT 1 AZIMUTH-POTENTIOMETER", + "JOINT 2 ELEVATION-POTENTIOMETER", + "JOINT 3 ELBOW-POTENTIOMETER", + "JOINT 4 WRIST-POTENTIOMETER", + "JOINT 5 TURRET-POTENTIOMETER") + ARTICULATION_DEVICE_MODE = GUARDED + ARTICULATION_DEVICE_TEMP = (-30.9296, -22.4574) + ARTICULATION_DEVICE_TEMP_NAME = ("AZIMUTH JOINT 1", "TURRET JOINT 5") + ARTICULATION_DEV_VECTOR = (-0.0353972, 0.00287072, 0.999369) + ARTICULATION_DEV_INSTRUMENT_ID = MI + ARTICULATION_DEV_VECTOR_NAME = GRAVITY + CONTACT_SENSOR_STATE = ("NO CONTACT", "NO CONTACT", CONTACT, + CONTACT, "NO CONTACT", "NO CONTACT", + CLOSED, "NO CONTACT") + CONTACT_SENSOR_STATE_NAME = ("MI SWITCH 1", "MI SWITCH 2", + "RAT SWITCH 1", "RAT SWITCH 2", + "MB SWITCH 1", "MB SWITCH 2", + "APXS DOOR SWITCH", "APXS CONTACT SWITCH") +End_Group + +/* COORDINATE SYSTEM STATE: PANCAM MAST ASSEMBLY */ +Group = PMA_COORDINATE_SYSTEM + COORDINATE_SYSTEM_INDEX = (3, 27, 149, 1886, 1347) + COORDINATE_SYSTEM_INDEX_NAME = (SITE, DRIVE, IDD, PMA, HGA) + COORDINATE_SYSTEM_NAME = MAST_FRAME + ORIGIN_OFFSET_VECTOR = (0.45781, 0.02779, -1.09668) + ORIGIN_ROTATION_QUATERNION = (0.0465651, 0.306669, -0.0150229, 0.950558) + POSITIVE_AZIMUTH_DIRECTION = CLOCKWISE + POSITIVE_ELEVATION_DIRECTION = UP + REFERENCE_COORD_SYSTEM_INDEX = (3, 27, 149, 1886, 1347) + REFERENCE_COORD_SYSTEM_NAME = ROVER_FRAME +End_Group + +/* ARTICULATION DEVICE STATE: MOBILITY CHASSIS */ +Group = CHASSIS_ARTICULATION_STATE + ARTICULATION_DEVICE_ID = CHASSIS + ARTICULATION_DEVICE_NAME = "MOBILITY CHASSIS" + ARTICULATION_DEVICE_ANGLE = (-0.00212176, -0.0059257, -0.00674381, + 0.00963577, 0.0291252, 0.00517551, + 0.0132111) + ARTICULATION_DEVICE_ANGLE_NAME = ("LEFT FRONT WHEEL POTENTIOMETER", + "RIGHT FRONT WHEEL POTENTIOMETER", + "LEFT REAR WHEEL POTENTIOMETER", + "RIGHT REAR WHEEL POTENTIOMETER", + "LEFT BOGIE POTENTIOMETER", + "RIGHT BOGIE POTENTIOMETER", + "DIFFERENTIAL BOGIE POTENTIOMETER") + ARTICULATION_DEVICE_MODE = DEPLOYED +End_Group + +/* OBSERVATION REQUEST */ +Group = OBSERVATION_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + COMMAND_INSTRUMENT_ID = MI + FILTER_NAME = MI_CLOSED + AUTO_EXPOSURE_DATA_CUT = 2500 + AUTO_EXPOSURE_PERCENT = 10.0 + AUTO_EXPOSURE_PIXEL_FRACTION = 1.0 + BAD_PIXEL_REPLACEMENT_FLAG = FALSE + DETECTOR_ERASE_COUNT = 2 + EARLY_PIXEL_SCALE_FLAG = FALSE + EARLY_IMAGE_RETURN_FLAG = FALSE + EXPOSURE_TYPE = AUTO + EXPOSURE_SCALE_FACTOR = 1.0 + EXPOSURE_DURATION_COUNT = 20 + EXPOSURE_TABLE_ID = EDL + EXPOSURE_TBL_UPDATE_FLAG = TRUE + FLAT_FIELD_CORRECTION_FLAG = FALSE + INSTRUMENT_COORDINATE = N/A + INSTRUMENT_COORDINATE_ID = NONE + INSTRUMENT_BORESIGHT_ID = UNK + INSTRUMENT_IDLE_TIMEOUT = 300 + MAX_AUTO_EXPOS_ITERATION_COUNT = 6 + SHUTTER_CORRECTION_MODE_ID = TRUE + SHUTTER_CORRECT_THRESH_COUNT = 0 +End_Group + +/* IMAGE REQUEST */ +Group = IMAGE_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = TRUE + DOWNLOAD_PRIORITY = 44 + PIXEL_DOWNSAMPLE_OPTION = NONE + PIXEL_AVERAGING_HEIGHT = 1 + PIXEL_AVERAGING_WIDTH = 1 + SAMPLE_BIT_MODE_ID = LUT3 + INST_CMPRS_MODE = 1 + INST_CMPRS_RATE = 1.0 + INST_CMPRS_QUALITY = 0 + INST_CMPRS_FILTER = E + INST_DECOMP_STAGES = 4 + INST_CMPRS_SEGMENTS = 32 +End_Group + +/* REFERENCE PIXEL REQUEST */ +Group = REFERENCE_PIXEL_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = FALSE + DOWNLOAD_PRIORITY = 44 + INST_CMPRS_MODE = 1 + INST_CMPRS_RATE = 12.0 + INST_CMPRS_QUALITY = 0 + INST_CMPRS_FILTER = E + INST_DECOMP_STAGES = 4 + INST_CMPRS_SEGMENTS = 1 +End_Group + +/* THUMBNAIL REQUEST */ +Group = THUMBNAIL_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = TRUE + DOWNLOAD_PRIORITY = 0 + LINES = 64 + LINE_SAMPLES = 64 + SAMPLE_BIT_MODE_ID = NONE + INST_CMPRS_MODE = 1 + INST_CMPRS_RATE = 1.0 + INST_CMPRS_QUALITY = 0 + INST_CMPRS_FILTER = E + INST_DECOMP_STAGES = 4 + INST_CMPRS_SEGMENTS = 1 +End_Group + +/* SUBFRAME REQUEST */ +Group = SUBFRAME_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = FALSE + SUBFRAME_TYPE = NONE + FIRST_LINE = 1 + FIRST_LINE_SAMPLE = 1 + LINES = 1024 + LINE_SAMPLES = 1024 +End_Group + +/* ROW SUMMATION REQUEST */ +Group = ROW_SUM_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = FALSE + DOWNLOAD_PRIORITY = 44 +End_Group + +/* COLUMN SUMMATION REQUEST */ +Group = COLUMN_SUM_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = FALSE + DOWNLOAD_PRIORITY = 44 +End_Group + +/* SUN FIND REQUEST */ +Group = SUN_FIND_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = FALSE + LINES = 63 + LINE_SAMPLES = 63 +End_Group + +/* HISTOGRAM REQUEST */ +Group = HISTOGRAM_REQUEST_PARMS + SOURCE_ID = "GROUND COMMANDED" + GROUP_APPLICABILITY_FLAG = FALSE + DOWNLOAD_PRIORITY = 44 +End_Group + +/* INSTRUMENT STATE RESULTS */ +Group = INSTRUMENT_STATE_PARMS + AZIMUTH_FOV = 37.3734 + ELEVATION_FOV = 37.3734 + BAD_PIXEL_REPLACEMENT_ID = N/A + DETECTOR_FIRST_LINE = 1 + DETECTOR_LINES = 1024 + DETECTOR_TO_IMAGE_ROTATION = 0.0 + DOWNSAMPLE_METHOD = SOFTWARE + EXPOSURE_COUNT = 2 + EXPOSURE_DURATION = 230.4 + EXPOSURE_DURATION_COUNT = 45 + FILTER_NAME = MI_CLOSED + FILTER_NUMBER = 1 + FLAT_FIELD_CORRECTION_FLAG = FALSE + FLAT_FIELD_CORRECTION_PARM = (0.0, 0.0, 0.0, 0.0, 0.0) + INSTRUMENT_MODE_ID = FULL_FRAME + INSTRUMENT_TEMPERATURE = (-26.9828, -15.1587, -8.44871, -15.6144, + -17.9811, 0.0, -18.333, -6.78394, + 0.0) + INSTRUMENT_TEMPERATURE_NAME = ("FRONT HAZ ELECTRONICS", + "REAR HAZ ELECTRONICS", + "LEFT PAN ELECTRONICS", "LEFT PAN CCD", + "RIGHT PAN CCD", "LEFT NAV CCD", "MI CCD", + "MI ELECTRONICS", "EDL CCD") + OFFSET_MODE_ID = 4090 + PIXEL_AVERAGING_HEIGHT = 16 + PIXEL_AVERAGING_WIDTH = 16 + SAMPLE_BIT_METHOD = NONE + SAMPLE_BIT_MODE_ID = NONE + SHUTTER_EFFECT_CORRECTION_FLAG = TRUE + SUN_FIND_FLAG = FALSE + SUN_FIND_PARM = (0.0, 0.0, 0.0) + SUN_FIND_PARM_NAME = ("WINDOW SIZE", "BRIGHTNESS THRESHOLD", + "SUMMED BRIGHTNESS") + SUN_LINE = -1 + SUN_LINE_SAMPLE = -1 + SUN_VIEW_POSITION = (0.0, 0.0, 0.0) + SUN_VIEW_DIRECTION = (0.0, 0.0, 0.0) +End_Group + +/* COMPRESSION RESULTS */ +Group = COMPRESSION_PARMS + ERROR_PIXELS = 0 + INST_CMPRS_DESC = "Lossless compression algorithm developed + at JPL" + INST_CMPRS_FILTER = E + INST_CMPRS_MODE = 1 + INST_CMPRS_NAME = "ICER ADAPTIVE VARIABLE-LENGTH CODING + (ICER)" + INST_CMPRS_RATE = 1.22266 + INST_CMPRS_RATIO = 9.8147 + INST_CMPRS_SEGMENTS = 1 + INST_CMPRS_SEGMENT_STATUS = 0 + INST_CMPRS_SEG_FIRST_LINE = 1 + INST_CMPRS_SEG_FIRST_LINE_SAMP = 1 + INST_CMPRS_SEG_LINES = 64 + INST_CMPRS_SEG_SAMPLES = 64 + INST_CMPRS_SEG_MISSING_PIXELS = N/A + INST_CMPRS_SEGMENT_QUALITY = 6.96875 + INST_DECOMP_STAGES = 4 +End_Group + +/* DERIVED GEOMETRY DATA ELEMENTS: ROVER FRAME */ +Group = ROVER_DERIVED_GEOMETRY_PARMS + INSTRUMENT_AZIMUTH = NULL + INSTRUMENT_ELEVATION = NULL + REFERENCE_COORD_SYSTEM_INDEX = (3, 27, 149, 1886, 1347) + REFERENCE_COORD_SYSTEM_NAME = ROVER_FRAME +End_Group + +/* DERIVED GEOMETRY DATA ELEMENTS: SITE FRAME */ +Group = SITE_DERIVED_GEOMETRY_PARMS + INSTRUMENT_AZIMUTH = NULL + INSTRUMENT_ELEVATION = NULL + REFERENCE_COORD_SYSTEM_INDEX = 3 + REFERENCE_COORD_SYSTEM_NAME = SITE_FRAME + SOLAR_AZIMUTH = 55.6811 + SOLAR_ELEVATION = -74.5811 +End_Group +End + +Testing PDS file containing a ^QUBE pointer +isisimportpds: Importing +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +PDS_VERSION_ID = PDS3 + +/* FILE DATA ELEMENTS */ +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 128 +FILE_RECORDS = 330 +LABEL_RECORDS = 170 + +/* POINTERS TO DATA OBJECTS */ +^QUBE = (unitTest.img, 267) + +/* IDENTIFICATION DATA ELEMENTS */ +DATA_SET_ID = MER2-M-MI-2-EDR-V1.0 +DATA_SET_NAME = "MARS EXPLORATION ROVER 2 MICROSCOPIC IMAGER + CAMERA V1.0" +COMMAND_SEQUENCE_NUMBER = 1 +FRAME_ID = MONO +FRAME_TYPE = MONO +GEOMETRY_PROJECTION_TYPE = RAW +IMAGE_ID = 229420001 +IMAGE_TYPE = THUMBNAIL +INSTRUMENT_HOST_ID = MER2 +INSTRUMENT_HOST_NAME = "MARS EXPLORATION ROVER 2" +INSTRUMENT_ID = MI +INSTRUMENT_NAME = "MICROSCOPIC IMAGER" +INSTRUMENT_SERIAL_NUMBER = 105 +INSTRUMENT_TYPE = "IMAGING CAMERA" +INSTRUMENT_VERSION_ID = FM +LOCAL_TRUE_SOLAR_TIME = 11:08:59 +MAGNET_ID = NULL +MISSION_NAME = "MARS EXPLORATION ROVER" +MISSION_PHASE_NAME = "PRIMARY MISSION" +OBSERVATION_ID = 301989888 +PLANET_DAY_NUMBER = 35 +PRODUCER_INSTITUTION_NAME = "MULTIMISSION IMAGE PROCESSING SUBSYSTEM , + JET PROPULSION LAB" +PRODUCT_CREATION_TIME = 2004-02-08T03:13:17.000Z +PRODUCT_ID = 2M129469022ETH0327P2942M1M1 +PRODUCT_VERSION_ID = "V3.0 D-22846" +RELEASE_ID = 0001 +ROVER_MOTION_COUNTER = (3, 27, 149, 1886, 1347) +ROVER_MOTION_COUNTER_NAME = (SITE, DRIVE, IDD, PMA, HGA) +SEQUENCE_ID = p2942 +SEQUENCE_VERSION_ID = 1 +SOLAR_LONGITUDE = -13.6249 +SPACECRAFT_CLOCK_CNT_PARTITION = 1 +SPACECRAFT_CLOCK_START_COUNT = 129469022.371 +SPACECRAFT_CLOCK_STOP_COUNT = 129469022.601 +START_TIME = 2004-02-07T23:35:51.722Z +STOP_TIME = 2004-02-07T23:35:51.953Z +TARGET_NAME = MARS +TARGET_TYPE = PLANET + +Object = QUBE + AXES = 3 + AXIS_NAME = (SAMPLE, LINE, BAND) + CORE_ITEMS = (64, 64, 1) + CORE_ITEM_TYPE = MSB_INTEGER + CORE_ITEM_BYTES = 2 +End_Object +End +isisimportpds: Gathering statistics +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +687.556 +282178 +**I/O ERROR** Unable to open OriginalLabel [IsisCube] in file [/tmp/unitTest.cub] +**I/O ERROR** Unable to read OriginalLabel [IsisCube] +**PROGRAMMER ERROR** Unable to find OriginalLabel [IsisCube] + +Testing Isis2 file +isisimportpds: Importing +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +Group = BandBin + FilterName = B + Center = 0.7500 + Width = 0.0100 + OriginalBand = 1 +End_Group + +Group = Instrument + TargetName = Moon + SpacecraftName = "CLEMENTINE 1" + StartTime = 1994-03-12T23:22:32.848 + InstrumentId = UVVIS +End_Group +End diff --git a/isis/src/base/objs/ProcessImportPds/unitTest.cpp b/isis/src/base/objs/ProcessImportPds/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18052be76298f573128516c91a100cd765657e56 --- /dev/null +++ b/isis/src/base/objs/ProcessImportPds/unitTest.cpp @@ -0,0 +1,93 @@ +#include "Isis.h" +#include "ProcessImportPds.h" +#include "Application.h" +#include "OriginalLabel.h" +#include "Statistics.h" + +using namespace std; +void IsisMain() { + + Isis::Preference::Preferences(true); + + // Test an IMAGE file + try { + cout << "Testing PDS file containing an ^IMAGE pointer" << endl; + Isis::ProcessImportPds p; + Isis::Pvl plab; + p.SetPdsFile("unitTest.img", "unitTest.img", plab); + p.SetOutputCube("TO"); + p.StartProcess(); + p.EndProcess(); + + cout << plab << endl; + Isis::Process p2; + Isis::CubeAttributeInput att; + string file = Isis::Application::GetUserInterface().GetFilename("TO"); + Isis::Cube *cube = p2.SetInputCube(file, att); + Isis::Statistics *stat = cube->Statistics(); + cout << stat->Average() << endl; + cout << stat->Variance() << endl; + p2.EndProcess(); + Isis::OriginalLabel ol(file); + Isis::Pvl label = ol.ReturnLabels(); + cout << label << endl; + remove(file.c_str()); + } + catch (Isis::iException &e) { + e.Report(false); + } + + // Test a QUBE file + try { + cout << endl; + cout << "Testing PDS file containing a ^QUBE pointer" << endl; + Isis::ProcessImportPds p; + Isis::Pvl plab; + p.SetPdsFile("unitTest.lab", "", plab); + p.SetOutputCube("TO"); + p.StartProcess(); + p.OmitOriginalLabel(); + p.EndProcess(); + + cout << plab << endl; + Isis::Process p2; + Isis::CubeAttributeInput att; + string file = Isis::Application::GetUserInterface().GetFilename("TO"); + Isis::Cube *cube = p2.SetInputCube(file, att); + Isis::Statistics *stat = cube->Statistics(); + cout << stat->Average() << endl; + cout << stat->Variance() << endl; + p2.EndProcess(); + try { + Isis::OriginalLabel ol(file); + } + catch (Isis::iException &e) { + e.Report(false); + } + remove(file.c_str()); + } + catch (Isis::iException &e) { + e.Report(false); + } + + // Test an Isis2 file + try { + cout << endl; + cout << "Testing Isis2 file" << endl; + Isis::ProcessImportPds p; + Isis::Pvl plab; + p.SetPdsFile("clemuvvis.cub", "clemuvvis.cub", plab); + p.SetOutputCube("TO"); + p.StartProcess(); + Isis::Pvl ilab; + p.TranslateIsis2Labels (ilab); + p.EndProcess(); + + cout << ilab << endl; + string file = Isis::Application::GetUserInterface().GetFilename("TO"); + remove(file.c_str()); + } + catch (Isis::iException &e) { + e.Report(false); + } +} diff --git a/isis/src/base/objs/ProcessImportPds/unitTest.lab b/isis/src/base/objs/ProcessImportPds/unitTest.lab new file mode 100644 index 0000000000000000000000000000000000000000..98bc9dec53eaa9fd9f13642ff2d1b8ad79b4f9c6 --- /dev/null +++ b/isis/src/base/objs/ProcessImportPds/unitTest.lab @@ -0,0 +1,64 @@ +PDS_VERSION_ID = PDS3 + +/* FILE DATA ELEMENTS */ + +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 128 +FILE_RECORDS = 330 +LABEL_RECORDS = 170 + +/* POINTERS TO DATA OBJECTS */ + +^QUBE = ("unitTest.img", 267) + +/* IDENTIFICATION DATA ELEMENTS */ + + DATA_SET_ID = "MER2-M-MI-2-EDR-V1.0" + DATA_SET_NAME = "MARS EXPLORATION ROVER 2 MICROSCOPIC + IMAGER CAMERA V1.0" + COMMAND_SEQUENCE_NUMBER = 1 + FRAME_ID = MONO + FRAME_TYPE = MONO + GEOMETRY_PROJECTION_TYPE = RAW + IMAGE_ID = 229420001 + IMAGE_TYPE = THUMBNAIL + INSTRUMENT_HOST_ID = MER2 + INSTRUMENT_HOST_NAME = "MARS EXPLORATION ROVER 2" + INSTRUMENT_ID = MI + INSTRUMENT_NAME = "MICROSCOPIC IMAGER" + INSTRUMENT_SERIAL_NUMBER = 105 + INSTRUMENT_TYPE = "IMAGING CAMERA" + INSTRUMENT_VERSION_ID = FM + LOCAL_TRUE_SOLAR_TIME = 11:08:59 + MAGNET_ID = "NULL" + MISSION_NAME = "MARS EXPLORATION ROVER" + MISSION_PHASE_NAME = "PRIMARY MISSION" + OBSERVATION_ID = 301989888 + PLANET_DAY_NUMBER = 35 + PRODUCER_INSTITUTION_NAME = "MULTIMISSION IMAGE PROCESSING SUBSYSTEM + , JET PROPULSION LAB" + PRODUCT_CREATION_TIME = "2004-02-08T03:13:17.000Z" + PRODUCT_ID = 2M129469022ETH0327P2942M1M1 + PRODUCT_VERSION_ID = "V3.0 D-22846" + RELEASE_ID = 0001 + ROVER_MOTION_COUNTER = (3,27,149,1886,1347) + ROVER_MOTION_COUNTER_NAME = (SITE,DRIVE,IDD,PMA,HGA) + SEQUENCE_ID = p2942 + SEQUENCE_VERSION_ID = 1 + SOLAR_LONGITUDE = -13.6249 + SPACECRAFT_CLOCK_CNT_PARTITION = 1 + SPACECRAFT_CLOCK_START_COUNT = 129469022.371 + SPACECRAFT_CLOCK_STOP_COUNT = 129469022.601 + START_TIME = "2004-02-07T23:35:51.722Z" + STOP_TIME = "2004-02-07T23:35:51.953Z" + TARGET_NAME = MARS + TARGET_TYPE = PLANET + +OBJECT = QUBE + AXES = 3 + AXIS_NAME = (SAMPLE, LINE, BAND) + CORE_ITEMS = (64, 64, 1) + CORE_ITEM_TYPE = MSB_INTEGER + CORE_ITEM_BYTES = 2 +END_OBJECT = QUBE +END diff --git a/isis/src/base/objs/ProcessImportPds/unitTest.xml b/isis/src/base/objs/ProcessImportPds/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..e63d56a3e9240f595c3ea8638ef068defff78e74 --- /dev/null +++ b/isis/src/base/objs/ProcessImportPds/unitTest.xml @@ -0,0 +1,39 @@ + + + + Unit test for IsisImportPds class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + + + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/unitTest.cub + + + + diff --git a/isis/src/base/objs/ProcessImportVicar/Makefile b/isis/src/base/objs/ProcessImportVicar/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5d02afcef5bce842a3de21ea9e075d62822fa307 --- /dev/null +++ b/isis/src/base/objs/ProcessImportVicar/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessImportVicar.h +SRCS = ProcessImportVicar.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessImportVicar/ProcessImportVicar.cpp b/isis/src/base/objs/ProcessImportVicar/ProcessImportVicar.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e2a7f98dde20486f770099f7a87ca0dc78ced773 --- /dev/null +++ b/isis/src/base/objs/ProcessImportVicar/ProcessImportVicar.cpp @@ -0,0 +1,194 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2009/12/17 21:13:17 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "Preference.h" + +#include "ProcessImportVicar.h" +#include "iException.h" +#include "iException.h" +#include "iException.h" +#include "LineManager.h" +#include "Pvl.h" +#include "PixelType.h" +#include "SpecialPixel.h" +#include "iString.h" +#include "UserInterface.h" + +using namespace std; +namespace Isis { + /** + * Opens a vicar file which can then be immediately imported by invoking the + * inherited StartProcess method. + * + * @param vicarFile Name of the vicar file to open + * + * @param vicarLab A PVL object which will contain the vicar labels. + * + * @throws Isis::iException::Message + */ + void ProcessImportVicar::SetVicarFile (const std::string &vicarFile, Isis::Pvl &vicarLab) { + + // Open vicar file + ifstream vicFile (vicarFile.c_str (), ios::in); + + if (!vicFile) { + string msg = "Cannot open vicar file [" + vicarFile + "]"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Read the LBLSIZE from Vicar file + try { + // Convert the LBLSIZE to an integer + // theoretically this value is always size 4.... + char *lblSizeValue = new char [1024]; + vicFile.seekg (string("LBLSIZE=").size()); + + for(int pos = 0; pos < 1024-1; pos++) { + if(!vicFile.good()) + break; + + if(vicFile.peek() == ' ') + break; + + lblSizeValue[pos] = vicFile.get(); + lblSizeValue[pos+1] = '\0'; + + // we're totally lost at this point + if(pos == 1023) { + string msg = "Cannot read vicar file [" + vicarFile + "]"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + + int lblSize = iString(lblSizeValue).ToInteger(); + + delete [] lblSizeValue; + lblSizeValue = NULL; + + char *buf = new char[lblSize+1]; + + // Read all of VICAR labels + vicFile.seekg (0); + vicFile.read (buf, lblSize); + buf[lblSize] = '\0'; + vicFile.close (); + + // Transform the vicar labels into valid pvl labels + iString vicLabels = buf; + + bool inQuote = false; + for(unsigned int pos = 0; pos < vicLabels.size(); pos++) { + if(vicLabels[pos] == '\'' || + vicLabels[pos] == '"') { + inQuote = !inQuote; + } + + if(!inQuote && vicLabels[pos] == ' ') { + vicLabels[pos] = '\n'; + } + } + + // Fill temp Pvl label for Isis::ProcessImport startprocess + stringstream lbl; + lbl << vicLabels << " End" << endl; + Isis::Pvl vLab; + lbl >> vLab; + vicarLab = vLab; + + // Set the fileHeaderBytes + SetFileHeaderBytes(vLab["LBLSIZE"]); + + // Set the dataHeaderBytes + SetDataHeaderBytes((int) vLab["NLB"] * (int)vLab["RECSIZE"]); + + // Are there binary prefix bytes on each image line? + SetDataPrefixBytes(vLab["NBB"]); + SetDataSuffixBytes(0); + + SetDimensions(vLab["NS"],vLab["NL"],vLab["NB"]); + + string pixType = vLab["FORMAT"]; + Isis::PixelType pixelType = Isis::None; + if (pixType == "BYTE") pixelType = Isis::UnsignedByte; + if (pixType == "HALF") pixelType = Isis::SignedWord; + if (pixType == "REAL") pixelType = Isis::Real; + if (pixelType == Isis::None) { + string msg = "Unsupported pixel type [FORMAT=" + pixType + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + SetPixelType(pixelType); + + string order = vLab["INTFMT"]; + if (order == "LOW") { + SetByteOrder(Isis::Lsb); + } + else { + SetByteOrder(Isis::Msb); + } + + string organization = vLab["ORG"]; + if (organization == "BSQ") { + SetOrganization(ProcessImport::BSQ); + } + else if (organization == "BIL") { + SetOrganization(ProcessImport::BIL); + } + else if (organization == "BIP") { + SetOrganization(ProcessImport::BIP); + } + else { + string msg = "Unsupported file organization [ORG=" + organization + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // See if there is end-of-dataset labels + // If so read them and merge + if (vLab.HasKeyword("EOL")) { + if ((int) vLab["EOL"] == 1) { + int startByte = (int) vLab["LBLSIZE"] + + (int) vLab["NLB"] * (int) vLab["RECSIZE"] + + (int) vLab["NL"] * (int) vLab["NB"] * + (int) vLab["RECSIZE"]; + ifstream vicFile (vicarFile.c_str (), ios::in); + vicFile.seekg (startByte,ios::beg); + Isis::Pvl endLab; + vicFile >> endLab; + vicFile.close(); + + for (int k=0; kAddGroup(outLab,"VICAR"); + * p.EndProcess(); + * @endcode + * + * @ingroup HighLevelCubeIO + * + * @author 2003-02-13 Jeff Anderson + * + * @internal + * @history 2005-02-11 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2008-06-26 Christopher Austin - Added the termination char to + * SetVicarFile's buf + * + * @todo 2005-02-11 Jeff Anderson - add implementation example to class + * documentation + * @todo 2005-05-23 Jeff Anderson - Currently VICAR files can not exceed 2GB + * however, they may in the future so we should remember to + * look at this + * @todo 2009-12-14 Steven Lambright - No longer using PvlTokenizer and now + * creating a valid Pvl from the label before creating a Pvl + * from it + */ + + class ProcessImportVicar : public ProcessImport { + + public: + void SetVicarFile (const std::string &vicarFile, Isis::Pvl &vicarLab); + + private: + Isis::Pvl p_vicLab; //!
    Statistics(); + cout << stat->Average() << endl; + cout << stat->Variance() << endl; + p2.EndProcess(); + remove(file.c_str()); +} diff --git a/isis/src/base/objs/ProcessImportVicar/unitTest.xml b/isis/src/base/objs/ProcessImportVicar/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..5ae1ca850aa5c78c8e8cc024fdfcd8d1e13bf439 --- /dev/null +++ b/isis/src/base/objs/ProcessImportVicar/unitTest.xml @@ -0,0 +1,39 @@ + + + + Unit test for IsisImportVicar class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + + + + + cube + output + + Test cube + + + Test cube + + + *.cub + + unitTest.cub + + + + diff --git a/isis/src/base/objs/ProcessMapMosaic/Makefile b/isis/src/base/objs/ProcessMapMosaic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b1bd980bbae0af89264c003a7c8ef0cf2fbcfd12 --- /dev/null +++ b/isis/src/base/objs/ProcessMapMosaic/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessMapMosaic.h +SRCS = ProcessMapMosaic.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessMapMosaic/ProcessMapMosaic.cpp b/isis/src/base/objs/ProcessMapMosaic/ProcessMapMosaic.cpp new file mode 100644 index 0000000000000000000000000000000000000000..26197571a5eea9d332c719249401648d4d3180f7 --- /dev/null +++ b/isis/src/base/objs/ProcessMapMosaic/ProcessMapMosaic.cpp @@ -0,0 +1,396 @@ +/** + * @file + * $Revision: 1.11 $ + * $Date: 2010/06/21 18:38:30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "Preference.h" + +#include "ProcessMapMosaic.h" +#include "SpecialPixel.h" +#include "iException.h" +#include "Application.h" +#include "ProcessByLine.h" +#include "Pvl.h" +#include "Projection.h" +#include "ProjectionFactory.h" + +using namespace std; + +namespace Isis { + ProcessMapMosaic::ProcessMapMosaic() { + p_createMosaic = true; + } + + bool ProcessMapMosaic::StartProcess(std::string inputFile) { + if(InputCubes.size() != 0) { + std::string msg = "Input cubes already exist; do not call SetInputCube when using "; + msg += "ProcessMosaic::StartProcess(std::string)"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + if(OutputCubes.size() == 0) { + std::string msg = "An output cube must be set before calling StartProcess"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + CubeAttributeInput inAtt; + Cube *inCube = ProcessMosaic::SetInputCube(inputFile, inAtt); + Cube *mosaicCube = OutputCubes[0]; + Projection *iproj = inCube->Projection(); + Projection *oproj = mosaicCube->Projection(); + int nsMosaic = mosaicCube->Samples(); + int nlMosaic = mosaicCube->Lines(); + + if(*iproj != *oproj) { + string msg = "Mapping groups do not match between cube [" + inputFile + "] and mosaic"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + int outSample, outSampleEnd, outLine, outLineEnd; + outSample = (int)(oproj->ToWorldX(iproj->ToProjectionX(1.0)) + 0.5); + outLine = (int)(oproj->ToWorldY(iproj->ToProjectionY(1.0)) + 0.5); + + outSampleEnd = outSample + InputCubes[0]->Samples(); + outLineEnd = outLine + InputCubes[0]->Lines(); + + bool wrapPossible = iproj->IsEquatorialCylindrical(); + int worldSize = 0; + if(wrapPossible) { + // Figure out how many samples 360 degrees is + wrapPossible = wrapPossible && oproj->SetUniversalGround(0, 0); + int worldStart = (int)(oproj->WorldX() + 0.5); + wrapPossible = wrapPossible && oproj->SetUniversalGround(0, 180); + int worldEnd = (int)(oproj->WorldX() + 0.5); + + worldSize = abs(worldEnd - worldStart) * 2; + + wrapPossible = wrapPossible && (worldSize > 0); + + // This is EquatorialCylindrical, so shift to the left all the way + if(wrapPossible) { + // While some data would still be put in the mosaic, move left + // >1 for end because 0 still means no data, whereas 1 means 1 line of data + while(outSampleEnd - worldSize > 1) { + outSample -= worldSize; + outSampleEnd -= worldSize; + } + // Now we have the sample range to the furthest left + } + } + + if(outSampleEnd < 1 || outLineEnd < 1 || outSample > nsMosaic || outLine > nlMosaic) { + // Add a PvlKeyword naming which files are not included in output mosaic + ClearInputCubes(); + return false; + } + else { + // Place the input in the mosaic + Progress()->SetText("Mosaicking " + Filename(inputFile).Name()); + + try { + do { + int outBand = 1; + + ProcessMosaic::StartProcess(outSample, outLine, outBand); + + // Increment for projections where occurrances may happen multiple times + outSample += worldSize; + outSampleEnd += worldSize; + } + while(wrapPossible && outSample < nsMosaic); + } + catch(iException &e) { + string msg = "Unable to mosaic cube [" + Filename(inputFile).Name() + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + WriteHistory(*mosaicCube); + + // Don't propagate any more histories now that we've done one + p_propagateHistory = false; + + ClearInputCubes(); + + return true; + } + + //************************************************************************************************* + + Isis::Cube *ProcessMapMosaic::SetOutputCube(FileList &propagationCubes, CubeAttributeOutput &oAtt, + const std::string &mosaicFile) { + int bands = 0; + double xmin = DBL_MAX; + double xmax = -DBL_MAX; + double ymin = DBL_MAX; + double ymax = -DBL_MAX; + double slat = DBL_MAX; + double elat = -DBL_MAX; + double slon = DBL_MAX; + double elon = -DBL_MAX; + + Projection *proj = NULL; + + if(propagationCubes.size() < 1) { + string msg = "The list does not contain any data"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + for(unsigned int i = 0; i < propagationCubes.size(); i++) { + // Open the cube and get the maximum number of band in all cubes + Cube cube; + cube.Open(propagationCubes[i]); + bands = max(bands, cube.Bands()); + + // See if the cube has a projection and make sure it matches + // previous input cubes + Projection *projNew = Isis::ProjectionFactory::CreateFromCube(*(cube.Label())); + if((proj != NULL) && (*proj != *projNew)) { + string msg = "Mapping groups do not match between cubes [" + + propagationCubes[0] + "] and [" + propagationCubes[i] + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + // Figure out the x/y range as it may be needed later + double x = projNew->ToProjectionX(0.5); + double y = projNew->ToProjectionY(0.5); + if(x < xmin) xmin = x; + if(y < ymin) ymin = y; + if(x > xmax) xmax = x; + if(y > ymax) ymax = y; + + x = projNew->ToProjectionX(cube.Samples() + 0.5); + y = projNew->ToProjectionY(cube.Lines() + 0.5); + if(x < xmin) xmin = x; + if(y < ymin) ymin = y; + if(x > xmax) xmax = x; + if(y > ymax) ymax = y; + + slat = min(slat, projNew->MinimumLatitude()); + elat = max(elat, projNew->MaximumLatitude()); + slon = min(slon, projNew->MinimumLongitude()); + elon = max(elon, projNew->MaximumLongitude()); + + // Cleanup + cube.Close(); + if(proj) delete proj; + proj = projNew; + } + + if(proj) delete proj; + + return SetOutputCube(propagationCubes[0], xmin, xmax, ymin, ymax, + slat, elat, slon, elon, bands, oAtt, mosaicFile); + } + + //************************************************************************************************* + + Isis::Cube *ProcessMapMosaic::SetOutputCube(FileList &propagationCubes, + double slat, double elat, double slon, double elon, + CubeAttributeOutput &oAtt, const std::string &mosaicFile) { + if(propagationCubes.size() < 1) { + string msg = "The list does not contain any data"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + int samples, lines, bands = 0; + Pvl label; + label.Read(propagationCubes[0]); + PvlGroup mGroup = label.FindGroup("Mapping", Pvl::Traverse); + mGroup.AddKeyword(PvlKeyword("MinimumLatitude", slat), Pvl::Replace); + mGroup.AddKeyword(PvlKeyword("MaximumLatitude", elat), Pvl::Replace); + mGroup.AddKeyword(PvlKeyword("MinimumLongitude", slon), Pvl::Replace); + mGroup.AddKeyword(PvlKeyword("MaximumLongitude", elon), Pvl::Replace); + + if(mGroup.HasKeyword("UpperLeftCornerX")) + mGroup.DeleteKeyword("UpperLeftCornerX"); + + if(mGroup.HasKeyword("UpperLeftCornerY")) + mGroup.DeleteKeyword("UpperLeftCornerY"); + + Pvl mapPvl; + mapPvl += mGroup; + + // Use CreateForCube because our range differs from any of the cubes (manually specified) + Projection *proj = Isis::ProjectionFactory::CreateForCube(mapPvl, samples, lines, false); + + double xmin, xmax, ymin, ymax; + proj->XYRange(xmin, xmax, ymin, ymax); + + // The xmin/ymax should be rounded for the labels + xmin = mapPvl.FindGroup("Mapping")["UpperLeftCornerX"]; + ymax = mapPvl.FindGroup("Mapping")["UpperLeftCornerY"]; + + for(unsigned int i = 0; i < propagationCubes.size(); i++) { + Cube cube; + cube.Open(propagationCubes[i]); + bands = max(cube.Bands(), bands); + + // See if the cube has a projection and make sure it matches + // previous input cubes + Projection *projNew = Isis::ProjectionFactory::CreateFromCube(*(cube.Label())); + + if(proj == NULL) { + } + else if(*proj != *projNew) { + string msg = "Mapping groups do not match between cube [" + propagationCubes[i] + + "] and [" + propagationCubes[0] + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + if(proj) delete proj; + proj = projNew; + } + + if(proj) delete proj; + + return SetOutputCube(propagationCubes[0], xmin, xmax, ymin, ymax, + slat, elat, slon, elon, bands, oAtt, mosaicFile); + } + + //************************************************************************************************* + + Isis::Cube *ProcessMapMosaic::SetOutputCube(const std::string &propagationCube, + double xmin, double xmax, double ymin, double ymax, + double slat, double elat, double slon, double elon, int nbands, + CubeAttributeOutput &oAtt, const std::string &mosaicFile) { + Pvl fileLab(propagationCube); + PvlGroup &mapping = fileLab.FindGroup("Mapping", Pvl::Traverse); + + mapping["UpperLeftCornerX"] = xmin; + mapping["UpperLeftCornerY"] = ymax; + mapping.AddKeyword(PvlKeyword("MinimumLatitude", slat), Pvl::Replace); + mapping.AddKeyword(PvlKeyword("MaximumLatitude", elat), Pvl::Replace); + mapping.AddKeyword(PvlKeyword("MinimumLongitude", slon), Pvl::Replace); + mapping.AddKeyword(PvlKeyword("MaximumLongitude", elon), Pvl::Replace); + + Projection *firstProj = ProjectionFactory::CreateFromCube(fileLab); + int samps = (int)(ceil(firstProj->ToWorldX(xmax) - firstProj->ToWorldX(xmin)) + 0.5); + int lines = (int)(ceil(firstProj->ToWorldY(ymin) - firstProj->ToWorldY(ymax)) + 0.5); + delete firstProj; + + if(p_createMosaic) { + Pvl newMap; + newMap.AddGroup(mapping); + + // Initialize the mosaic + CubeAttributeInput inAtt; + + ProcessByLine p; + p.SetInputCube(propagationCube, inAtt); + p.PropagateHistory(false); + p.PropagateLabels(false); + p.PropagateTables(false); + p.PropagatePolygons(false); + p.PropagateOriginalLabel(false); + + //if track set, create the origin band + if(GetTrackFlag()) { + nbands += 1; + } + + Cube *ocube = p.SetOutputCube(mosaicFile, oAtt, samps, lines, nbands); + p.Progress()->SetText("Initializing mosaic"); + p.ClearInputCubes(); + p.StartProcess(ProcessMapMosaic::FillNull); + + // CreateForCube created some keywords in the mapping group that needs to be added + ocube->PutGroup(newMap.FindGroup("Mapping", Pvl::Traverse)); + p.EndProcess(); + } + + Cube *mosaicCube = new Cube(); + mosaicCube->Open(mosaicFile, "rw"); + + OutputCubes.push_back(mosaicCube); + return mosaicCube; + } + + //************************************************************************************************* + + Isis::Cube *ProcessMapMosaic::SetOutputCube(const std::string &propagationCube, PvlGroup mapping, + CubeAttributeOutput &oAtt, const std::string &mosaicFile) { + if(OutputCubes.size() != 0) { + std::string msg = "You can only specify one output cube and projection"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + if(mapping.HasKeyword("UpperLeftCornerX")) + mapping.DeleteKeyword("UpperLeftCornerX"); + + if(mapping.HasKeyword("UpperLeftCornerY")) + mapping.DeleteKeyword("UpperLeftCornerY"); + + if(p_createMosaic) { + Pvl newMap; + newMap.AddGroup(mapping); + int samps, lines, bands; + delete ProjectionFactory::CreateForCube(newMap, samps, lines, false); + + // Initialize the mosaic + ProcessByLine p; + CubeAttributeInput inAtt; + Cube *propCube = p.SetInputCube(propagationCube, inAtt); + bands = propCube->Bands(); + + //if track set, create the origin band + if(GetTrackFlag()) { + bands += 1; + } + + p.PropagateHistory(false); + p.PropagateLabels(false); + Cube *ocube = p.SetOutputCube(mosaicFile, oAtt, samps, lines, bands); + p.Progress()->SetText("Initializing mosaic"); + p.ClearInputCubes(); + p.StartProcess(ProcessMapMosaic::FillNull); + + // CreateForCube created some keywords in the mapping group that needs to be added + ocube->PutGroup(newMap.FindGroup("Mapping", Pvl::Traverse)); + p.EndProcess(); + } + + Cube *mosaicCube = new Cube(); + OutputCubes.push_back(mosaicCube); + mosaicCube->Open(mosaicFile, "rw"); + + return mosaicCube; + } + + //************************************************************************************************* + + Cube *ProcessMapMosaic::SetOutputCube(const std::string &mosaicFile) { + p_createMosaic = false; + Cube mosaic; + mosaic.Open(mosaicFile); + + PvlGroup &mapping = mosaic.Label()->FindGroup("Mapping", Pvl::Traverse); + CubeAttributeOutput oAtt; + // The other SetOutput will not use the attribute or filename + Cube *ocube = SetOutputCube("", mapping, oAtt, mosaicFile); + p_createMosaic = true; + + return ocube; + } + + //************************************************************************************************* + void ProcessMapMosaic::FillNull(Buffer &data) { + for(int i = 0; i < data.size(); i++) data[i] = Isis::Null; + } +} // end namespace isis diff --git a/isis/src/base/objs/ProcessMapMosaic/ProcessMapMosaic.h b/isis/src/base/objs/ProcessMapMosaic/ProcessMapMosaic.h new file mode 100644 index 0000000000000000000000000000000000000000..fb0d9bda90d25271d1d580305066a02fe520d3e1 --- /dev/null +++ b/isis/src/base/objs/ProcessMapMosaic/ProcessMapMosaic.h @@ -0,0 +1,115 @@ +#ifndef ProcessMapMosaic_h +#define ProcessMapMosaic_h +/** + * @file + * $Revision: 1.9 $ + * $Date: 2010/06/21 18:38:51 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "ProcessMosaic.h" +#include "Buffer.h" +#include "FileList.h" + +namespace Isis { + /** + * @brief Mosaic two cubs together + * + * This class allows a programmer to develop a program which merges two cubes + * together. The application sets the position where input (child) cube will be + * placed in the mosaic (parent) cube and priority. The the Mosaic object will + * merge the overlapping area. + * + * @ingroup HighLevelCubeIO + * + * @author 2003-04-28 Stuart Sides + * + * @internal + * @history 2003-04-28 Stuart Sides - Modified unitTest.cpp to do a better test + * @history 2003-09-04 Jeff Anderson - Added SetInputWorkCube method + * @history 2005-02-11 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2006-09-01 Elizabeth Miller - Added BandBinMatch option to + * propagate the bandbin group to the + * mosaic and make sure the input cube + * bandbin groups match the mosaics + * bandbin group + * @history 2006-10-20 Stuart Sides - Fixed bug BandBin group did not get + * copied to the output mosaic. + * @history 2008-10-03 Steven Lambright - Fixed problem where return values + * from SetUniversalGround were not checked + * @history 2008-11-18 Christopher Austin - Added the first cube's history to + * the mosaic's history along with the history object of the + * application which did the mosaic. + * @history 2008-12-08 Steven Lambright - Fixed one of the SetOutputCube(...) + * methods, a lat/lon range was specified but CreateFromCube was still + * being used (needed CreateFromCube because no cubes existed with the + * correct range). + * @history 2008-12-08 Steven Lambright - MinimumLatitude,MaximumLatitude, + * MinimumLongitude,MaximumLongitude keywords no longer required to + * exist if passed into SetOutputCube + * @todo 2005-02-11 Stuart Sides - add coded example and implementation example + * to class documentation + */ + + class ProcessMapMosaic : public Isis::ProcessMosaic { + + public: + + //! Constructs a Mosaic object + ProcessMapMosaic(); + ~ProcessMapMosaic() { }; + + Isis::Cube *SetOutputCube(FileList &propagationCubes, CubeAttributeOutput &oAtt, + const std::string &mosaicFile); + + Isis::Cube *SetOutputCube(FileList &propagationCubes, + double slat, double elat, double slon, double elon, + CubeAttributeOutput &oAtt, const std::string &mosaicFile); + + Isis::Cube *SetOutputCube(const std::string &propagationCube, + double xmin, double xmax, double ymin, double ymax, + double slat, double elat, double slon, double elon, int nbands, + CubeAttributeOutput &oAtt, const std::string &mosaicFile); + + Isis::Cube *SetOutputCube(const std::string &propagationCube, PvlGroup mapping, + CubeAttributeOutput &oAtt, const std::string &mosaicFile); + + //! Mosaic output method for Mosaic Processing Method, this will use an existing mosaic + Isis::Cube *SetOutputCube(const std::string &mosaicFile); + + Isis::Cube *SetInputCube() { + throw iException::Message(iException::Programmer, + "ProcessMapMosaic does not support the SetInputCube method", + _FILEINFO_); + } + + //! Mosaic Processing method, returns false if the cube is not inside the mosaic + bool StartProcess(std::string inputFile); + + private: + static void FillNull(Buffer &data); + + //! Internal use; SetOutputMosaic (const std::string &) sets to false to + //! not attempt creation when using SetOutputMosaic + bool p_createMosaic; + }; +}; + +#endif + diff --git a/isis/src/base/objs/ProcessMapMosaic/ProcessMapMosaic.truth b/isis/src/base/objs/ProcessMapMosaic/ProcessMapMosaic.truth new file mode 100644 index 0000000000000000000000000000000000000000..c68c3129db1abd79dee31dbde106485bd7d615b0 --- /dev/null +++ b/isis/src/base/objs/ProcessMapMosaic/ProcessMapMosaic.truth @@ -0,0 +1,372 @@ +Testing Isis::ProcessMapMosaic Class ... +Testing Mosaic 1 +unittest: Initializing mosaic +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +unittest: Mosaicking unitTest1.cub +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +./unitTest1.cub is inside the mosaic +unittest: Mosaicking unitTest2.cub +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +./unitTest2.cub is inside the mosaic +Mosaic label: +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 124 + Lines = 125 + Bands = 1 + End_Group + + Group = Pixels + Type = UnsignedByte + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 30.5 + TargetName = MOON + EquatorialRadius = 1737400.0 + PolarRadius = 1737400.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = -5.5 + MaximumLatitude = -4.0 + MinimumLongitude = 29.5 + MaximumLongitude = 31.0 + UpperLeftCornerX = -15195.585618718 + UpperLeftCornerY = -121074.5047685 + PixelResolution = 245.09009062449 + Scale = 123.72328210776 + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = History + Name = IsisCube + StartByte = 81921 + Bytes = 3026 +End_Object +End +Testing Mosaic 2 +unittest: Initializing mosaic +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +unittest: Mosaicking unitTest1.cub +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +./unitTest1.cub is inside the mosaic +unittest: Mosaicking unitTest2.cub +0% Processed 10% Processed 20% Processed 30% Processed 40% Processed 50% Processed 60% Processed 70% Processed 80% Processed 90% Processed 100% Processed +./unitTest2.cub is inside the mosaic +Mosaic label: +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 248 + Lines = 249 + Bands = 1 + End_Group + + Group = Pixels + Type = UnsignedByte + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 30.5 + TargetName = MOON + EquatorialRadius = 1737400.0 + PolarRadius = 1737400.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = -6.0 + MaximumLatitude = -4.0 + MinimumLongitude = 29.0 + MaximumLongitude = 31.0 + UpperLeftCornerX = -45586.756856155 + UpperLeftCornerY = -121074.5047685 + PixelResolution = 245.09009062449 + Scale = 123.72328210776 + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = History + Name = IsisCube + StartByte = 131073 + Bytes = 3026 +End_Object +End +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 10 +Mosaic Data: -1.79769e+308 -1.79769e+308 10 +Mosaic Data: -1.79769e+308 -1.79769e+308 10 +Mosaic Data: -1.79769e+308 -1.79769e+308 13 +Mosaic Data: -1.79769e+308 -1.79769e+308 16 +Mosaic Data: -1.79769e+308 -1.79769e+308 15 +Mosaic Data: -1.79769e+308 -1.79769e+308 14 +Mosaic Data: -1.79769e+308 -1.79769e+308 17 +Mosaic Data: -1.79769e+308 -1.79769e+308 21 +Mosaic Data: -1.79769e+308 -1.79769e+308 20 +Mosaic Data: -1.79769e+308 -1.79769e+308 19 +Mosaic Data: -1.79769e+308 -1.79769e+308 22 +Mosaic Data: -1.79769e+308 31 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 31 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 24 +Mosaic Data: -1.79769e+308 -1.79769e+308 26 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 31 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 39 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 30 +Mosaic Data: -1.79769e+308 -1.79769e+308 31 +Mosaic Data: -1.79769e+308 -1.79769e+308 29 +Mosaic Data: -1.79769e+308 -1.79769e+308 26 +Mosaic Data: -1.79769e+308 -1.79769e+308 24 +Mosaic Data: -1.79769e+308 31 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 31 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 25 +Mosaic Data: -1.79769e+308 -1.79769e+308 26 +Mosaic Data: -1.79769e+308 31 23 +Mosaic Data: -1.79769e+308 -1.79769e+308 19 +Mosaic Data: -1.79769e+308 -1.79769e+308 20 +Mosaic Data: -1.79769e+308 -1.79769e+308 21 +Mosaic Data: -1.79769e+308 -1.79769e+308 19 +Mosaic Data: -1.79769e+308 -1.79769e+308 15 +Mosaic Data: -1.79769e+308 -1.79769e+308 15 +Mosaic Data: -1.79769e+308 -1.79769e+308 15 +Mosaic Data: -1.79769e+308 -1.79769e+308 15 +Mosaic Data: -1.79769e+308 -1.79769e+308 11 +Mosaic Data: -1.79769e+308 -1.79769e+308 9 +Mosaic Data: -1.79769e+308 -1.79769e+308 10 +Mosaic Data: -1.79769e+308 -1.79769e+308 10 +Mosaic Data: -1.79769e+308 -1.79769e+308 33 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 +Mosaic Data: -1.79769e+308 -1.79769e+308 -1.79769e+308 diff --git a/isis/src/base/objs/ProcessMapMosaic/unitTest.cpp b/isis/src/base/objs/ProcessMapMosaic/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f22677d31a355ee5ee84afa639f1c342cd2796a2 --- /dev/null +++ b/isis/src/base/objs/ProcessMapMosaic/unitTest.cpp @@ -0,0 +1,90 @@ +#include "Isis.h" + +#include + +#include "ProcessMapMosaic.h" +#include "Application.h" +#include "CubeAttribute.h" +#include "FileList.h" +#include "ProcessMosaic.h" +#include "LineManager.h" + +using namespace std; + +void IsisMain() { + + Isis::Preference::Preferences(true); + + cout << "Testing Isis::ProcessMapMosaic Class ... " << endl; + + // Create the temp parent cube + Isis::FileList cubes; + cubes.Read("unitTest.lis"); + + std::cout << "Testing Mosaic 1" << std::endl; + Isis::ProcessMapMosaic m1; + Isis::CubeAttributeOutput oAtt; + MosaicPriority priority = input; + m1.SetBandBinMatch(false); + m1.SetOutputCube(cubes, oAtt, "./unitTest.cub"); + + //set priority + m1.SetPriority(priority); + + for(unsigned int i = 0; i < cubes.size(); i++) { + if(m1.StartProcess(cubes[i])) { + std::cout << cubes[i] << " is inside the mosaic" << std::endl; + } + else { + std::cout << cubes[i] << " is outside the mosaic" << std::endl; + } + } + + m1.EndProcess(); + std::cout << "Mosaic label: " << std::endl; + Isis::iApp->Exec("catlab", "FROM=./unitTest.cub"); + + remove("./unitTest.cub"); + + std::cout << "Testing Mosaic 2" << std::endl; + Isis::ProcessMapMosaic m2; + m2.SetBandBinMatch(false); + m2.SetOutputCube(cubes, -6, -4, 29, 31, oAtt, "./unitTest.cub"); + + //set priority + m2.SetPriority(priority); + + for(unsigned int i = 0; i < cubes.size(); i++) { + if(m2.StartProcess(cubes[i])) { + std::cout << cubes[i] << " is inside the mosaic" << std::endl; + } + else { + std::cout << cubes[i] << " is outside the mosaic" << std::endl; + } + } + + m2.EndProcess(); + std::cout << "Mosaic label: " << std::endl; + + Isis::iApp->Exec("catlab", "FROM=./unitTest.cub"); + + + Isis::Cube tmp; + tmp.Open("./unitTest.cub"); + Isis::LineManager lm(tmp); + lm.SetLine(1, 1); + + while(!lm.end()) { + tmp.Read(lm); + std::cout << "Mosaic Data: " << lm[lm.SampleDimension()/4] << '\t' << + lm[lm.SampleDimension()/2] << '\t' << + lm[(3*lm.SampleDimension())/4] << std::endl; + lm++; + } + + tmp.Close(); + remove("./unitTest.cub"); +} + + + diff --git a/isis/src/base/objs/ProcessMapMosaic/unitTest.exclude b/isis/src/base/objs/ProcessMapMosaic/unitTest.exclude new file mode 100644 index 0000000000000000000000000000000000000000..dd5bebc82c58891ab4dcf6a7551e6498f02afd7e --- /dev/null +++ b/isis/src/base/objs/ProcessMapMosaic/unitTest.exclude @@ -0,0 +1,3 @@ +ByteOrder +StartByte +Bytes diff --git a/isis/src/base/objs/ProcessMapMosaic/unitTest.lis b/isis/src/base/objs/ProcessMapMosaic/unitTest.lis new file mode 100644 index 0000000000000000000000000000000000000000..31b241a395d885e94c6394465ce9d7b48a040c6b --- /dev/null +++ b/isis/src/base/objs/ProcessMapMosaic/unitTest.lis @@ -0,0 +1,2 @@ +./unitTest1.cub +./unitTest2.cub diff --git a/isis/src/base/objs/ProcessMapMosaic/unitTest.xml b/isis/src/base/objs/ProcessMapMosaic/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..5d5e03f2cbe4da3da2cb95c8230ac353a5e6fcff --- /dev/null +++ b/isis/src/base/objs/ProcessMapMosaic/unitTest.xml @@ -0,0 +1,54 @@ + + + + Unit test for IsisMosaic class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub + + + cube + output + Real + + Test cube + + + Test cube + + + *.cub + + isisMosaic_01.cub + + + + diff --git a/isis/src/base/objs/ProcessMosaic/Makefile b/isis/src/base/objs/ProcessMosaic/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b7eb95de625c15a25e7cabb0eaec81f25b426a27 --- /dev/null +++ b/isis/src/base/objs/ProcessMosaic/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessMosaic.h +SRCS = ProcessMosaic.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessMosaic/ProcessMosaic.cpp b/isis/src/base/objs/ProcessMosaic/ProcessMosaic.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c5d0aea0a9b59eb9e5314b88dee8eea1983c4180 --- /dev/null +++ b/isis/src/base/objs/ProcessMosaic/ProcessMosaic.cpp @@ -0,0 +1,1529 @@ +/** + * @file + * $Revision: 1.17 $ + * $Date: 2010/06/21 18:39:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "Preference.h" + +#include "Portal.h" +#include "ProcessMosaic.h" +#include "SpecialPixel.h" +#include "iException.h" +#include "Application.h" +#include "Pvl.h" +#include "Table.h" +#include "SerialNumber.h" +#include "iString.h" + +using namespace std; + +//#define _DEBUG_ + +namespace Isis { + +#ifdef _DEBUG_ + //debugging + fstream ostm; + + void StartDebug() { + ostm.open("Debug.log", std::ios::out | std::ios::app); + ostm << "\n*************************\n"; + } + + void CloseDebug() { + ostm << "\n*************************\n"; + ostm.close(); + } +#endif + + /** + * ProcessMosaic Contructor + * + * Initialize the class members to default + */ + ProcessMosaic::ProcessMosaic() { + + // Set the BandBin Match + SetBandBinMatch(true); + + // Initialize the structure Track Info + mtTrackInfo.bTrack = false; + mtTrackInfo.bCreate = false; + mtTrackInfo.iBandNum = 0; + mtTrackInfo.sKeyName = ""; + mtTrackInfo.sKeyValue = ""; + mtTrackInfo.eCriteria = Lesser; + mtTrackInfo.iInBand = 0; + mtTrackInfo.iOutBand = 0; + + // Initialize the Special Pixel Flags + mbHighSat = false; + mbLowSat = false; + mbNull = false; + + // Default Priority OnTop + mePriority = input; + + // Initialize the data members + miOss = -1; + miOsl = -1; + miOsb = -1; + +#ifdef _DEBUG_ + StartDebug(); +#endif + }; + + /** + * ProcessMosaic Destructor + * + */ + ProcessMosaic::~ProcessMosaic() { +#ifdef _DEBUG_ + CloseDebug(); +#endif + } + + + /** + * This method invokes the process by mosaic operation over a single input cube + * and single output cube. Unlike other Isis process objects, no application . + * function will be called. The processing is handled entirely within the + * mosaic object. The input cube must be pixel aligned with the output cube + * before mosaiking. If the input cube does not overlay any of the output cube, + * no processing takes place and no errors are thrown. + * + * @param os The sample position of input cube starting sample relative to + * the output cube. The cordinate is in output cube space and may + * be any integer value negative or positive. + * + * @param ol The line position of input cube starting line relative to the + * output cube. The cordinate is in output cube space and may be + * any integer value negative or positive. + * + * @param ob The band position of input cube starting band relative to the + * output cube. The cordinate is in output cube space and must be + * a legal band number within the output cube. + * + * @param priority This parameter determines which cube takes priority + * when both the input and output cubes contain non null + * data. There ara two possible values (input and mosaic). + * When this parameter is set to input all non null pixels + * will be transfered to the mosaic. Null pixels will not + * be transfered. When this parameter is set to mosaic + * input pixel values will only be transfered to the mosaic + * when the mosaic contains a null value. + * + * @throws Isis::iException::Message + */ + void ProcessMosaic::StartProcess(const int &os, const int &ol, + const int &ob, const MosaicPriority &priority) { + + int outSample = os; + int outLine = ol; + int outFile = ob; + + // Error checks ... there must be one input and one output + if((OutputCubes.size() != 1) || (InputCubes.size() != 1)) { + string m = "You must specify exactly one input and one output cube"; + throw Isis::iException::Message(Isis::iException::Programmer, m, _FILEINFO_); + } + + // Check to make sure the bandbins match if necessary + if(mbBandbinMatch) { + Pvl *inLab = InputCubes[0]->Label(); + Pvl *outLab = OutputCubes[0]->Label(); + + if(inLab->FindObject("IsisCube").HasGroup("BandBin")) { + PvlGroup &inBin = inLab->FindGroup("BandBin", Pvl::Traverse); + // Check to make sure the output cube has a bandbin group & make sure it + // matches the input cube bandbin group + if(outLab->FindObject("IsisCube").HasGroup("BandBin")) { + PvlGroup &outBin = outLab->FindGroup("BandBin", Pvl::Traverse); + if(inBin.Keywords() != outBin.Keywords()) { + string msg = "Pvl Group [BandBin] does not match between the input and output cubes"; + throw Isis::iException::Message(iException::User, msg, _FILEINFO_); + } + for(int i = 0; i < outBin.Keywords(); i++) { + PvlKeyword &outKey = outBin[i]; + if(inBin.HasKeyword(outKey.Name())) { + PvlKeyword &inKey = inBin[outKey.Name()]; + for(int v = 0; v < outKey.Size(); v++) { + if(outKey[v] != inKey[v]) { + string msg = "Pvl Group [BandBin] Keyword[" + outBin[i].Name() + + "] does not match between the input and output cubes"; + throw Isis::iException::Message(iException::User, msg, _FILEINFO_); + } + } + } + else { + string msg = "Pvl Group [BandBin] Keyword[" + outBin[i].Name() + + "] does not match between the input and output cubes"; + throw Isis::iException::Message(iException::User, msg, _FILEINFO_); + } + } + } + // Otherwise copy the input cube bandbin to the output file + else { + outLab->FindObject("IsisCube").AddGroup(inBin); + } + } + } + + if((outFile < 1) || ((outFile + p_inb - 1) > OutputCubes[0]->Bands())) { + string m = "All bands from the input cube must fit within the output mosaic"; + throw Isis::iException::Message(Isis::iException::Programmer, m, _FILEINFO_); + } + + // Set up the input sub cube (This must be a legal sub-area of the input cube) + int ins = p_ins; + int inl = p_inl; + int inb = p_inb; + + if(ins == 0) ins = (int)InputCubes[0]->Samples(); + if(inl == 0) inl = (int)InputCubes[0]->Lines(); + if(inb == 0) inb = (int)InputCubes[0]->Bands(); + + // Adjust the input sub-area if it overlaps any edge of the output cube + + int iss = p_iss; + int isl = p_isl; + + // Left edge + if(outSample < 1) { + iss = iss - outSample + 1; + ins = ins + outSample - 1; + outSample = 1; + } + // Top edge + if(outLine < 1) { + isl = isl - outLine + 1; + inl = inl + outLine - 1; + outLine = 1; + } + // Right edge + if((outSample + ins - 1) > OutputCubes[0]->Samples()) { + ins = OutputCubes[0]->Samples() - outSample + 1; + } + // Bottom edge + if((outLine + inl - 1) > OutputCubes[0]->Lines()) { + inl = OutputCubes[0]->Lines() - outLine + 1; + } + + // Tests for completly off the mosaic + if((ins < 1) || (inl < 1)) { + string m = "The input cube does not overlap the mosaic"; + throw Isis::iException::Message(Isis::iException::User, m, _FILEINFO_); + } + + // Create portal buffers for the input and output files + Isis::Portal iportal(ins, 1, InputCubes[0]->PixelType()); + Isis::Portal oportal(ins, 1, OutputCubes[0]->PixelType()); + + // Start the progress meter + p_progress->SetMaximumSteps(inl * inb); + p_progress->CheckStatus(); + + for(int ib = p_isb, ob = outFile; ib < p_isb + inb; ib++, ob++) { + for(int il = isl, ol = outLine; il < isl + inl; il++, ol++) { + // Set the position of the portals in the input and output cubes + iportal.SetPosition(iss, il, ib); + InputCubes[0]->Read(iportal); + + oportal.SetPosition(outSample, ol, ob); + OutputCubes[0]->Read(oportal); + + // Move the input data to the output + for(int pixel = 0; pixel < oportal.size(); pixel++) { + if(priority == input) { + if(!Isis::IsNullPixel(iportal[pixel])) oportal[pixel] = iportal[pixel]; + } + else if(priority == mosaic) { + if(Isis::IsNullPixel(oportal[pixel])) oportal[pixel] = iportal[pixel]; + } + } // End sample loop + + OutputCubes[0]->Write(oportal); + p_progress->CheckStatus(); + } // End line loop + } // End band loop + } // End StartProcess + + /** + * This method invokes the process by mosaic operation over a single input cube + * and single output cube. Unlike other Isis process objects, no application . + * function will be called. The processing is handled entirely within the + * mosaic object. The input cube must be pixel aligned with the output cube + * before mosaiking. If the input cube does not overlay any of the output cube, + * no processing takes place. There are 3 priorities input, mosaic and band. Has the + * ability to track the origin of the mosaic if the flag is set. Some conditions apply + * like tracking turned off for multiband input with input or mosaic priority. + * + * @param os The sample position of input cube starting sample relative to + * the output cube. The cordinate is in output cube space and may + * be any integer value negative or positive. + * + * @param ol The line position of input cube starting line relative to the + * output cube. The cordinate is in output cube space and may be + * any integer value negative or positive. + * + * @param ob The band position of input cube starting band relative to the + * output cube. The cordinate is in output cube space and must be + * a legal band number within the output cube. + * + * @throws Isis::iException::Message + * + * @author sprasad (8/25/2009) + */ + void ProcessMosaic::StartProcess(const int &os, const int &ol, const int &ob) { + int outSample = os; + int outLine = ol; + int outFile = ob; + + +#ifdef _DEBUG_ + ostm << "\n*********** ProcessMosaic::StartProcess **********\n"; + ostm << "** Parameters **\n"; + ostm << "priority=" << mePriority << " outsample=" << os << " outline=" << ol << " outBand=" << ob << "\n\n"; +#endif + + // Error checks ... there must be one input and one output + if((OutputCubes.size() != 1) || (InputCubes.size() != 1)) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string m = "You must specify exactly one input and one output cube"; + throw Isis::iException::Message(Isis::iException::Programmer, m, _FILEINFO_); + } + + bool bTrackExists = false; + if(!mtTrackInfo.bCreate) { + bTrackExists = GetTrackStatus(); + if(!bTrackExists && mePriority == band) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string m = "Band cannot be a priority if Track Origin is not set"; + throw Isis::iException::Message(Isis::iException::Programmer, m, _FILEINFO_); + } + } + + // ** + // Set up the input sub cube (This must be a legal sub-area of the input cube) + // * + int ins = p_ins; + int inl = p_inl; + int inb = p_inb; + + if(ins == 0) ins = (int)InputCubes[0]->Samples(); + if(inl == 0) inl = (int)InputCubes[0]->Lines(); + if(inb == 0) inb = (int)InputCubes[0]->Bands(); + + // Adjust the input sub-area if it overlaps any edge of the output cube + int iss = p_iss; + int isl = p_isl; + int isb = p_isb; + + miOss = outSample; + miOsl = outLine; + miOsb = outFile; + + // Left edge + if(outSample < 1) { + miOss = outSample - 1; + iss = iss - outSample + 1; + ins = ins + outSample - 1; + outSample = 1; + } + // Top edge + if(outLine < 1) { + miOsl = outLine - 1; + isl = isl - outLine + 1; + inl = inl + outLine - 1; + outLine = 1; + } + // Right edge + if((outSample + ins - 1) > OutputCubes[0]->Samples()) { + ins = OutputCubes[0]->Samples() - outSample + 1; + } + // Bottom edge + if((outLine + inl - 1) > OutputCubes[0]->Lines()) { + inl = OutputCubes[0]->Lines() - outLine + 1; + } + + // Tests for completly off the mosaic + if((ins < 1) || (inl < 1)) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string m = "The input cube does not overlap the mosaic"; + throw Isis::iException::Message(Isis::iException::User, m, _FILEINFO_); + } + + // Band Adjustments + if(outFile < 1) { + miOsb = outFile - 1; + isb = isb - outFile + 1; + inb = inb + outFile - 1; + outFile = 1; + } + + p_progress->SetMaximumSteps((int)InputCubes[0]->Lines() * (int)InputCubes[0]->Bands()); + p_progress->CheckStatus(); + +#ifdef _DEBUG_ + ostm << "\n*** Input Stats *** PixelType=" << InputCubes[0]->PixelType() << "\nBands Start=" << p_isb << " Number=" << inb << "\n"; + ostm << "Samples Start=" << iss << " Number=" << ins << "\n"; + ostm << "Lines Start=" << isl << " Number=" << inl << "\n"; + + + ostm << "*** Output Stats ***\n" << "Bands Start=" << outFile << " Number=" << OutputCubes[0]->Bands() << "\n"; + ostm << "Start Samples= " << outSample << " Lines= " << outLine << "\n"; + +#endif + // ******************************************************************************* + + // Check to make sure the bandbins match if necessary + if(mbBandbinMatch) { + Pvl *inLab = InputCubes[0]->Label(); + Pvl *outLab = OutputCubes[0]->Label(); + +#ifdef _DEBUG_ + ostm << "BandBinMatch Flag is set to true\n"; +#endif + if(inLab->FindObject("IsisCube").HasGroup("BandBin")) { + // Check to make sure the output cube has a bandbin group & make sure it + // matches the input cube bandbin group + if(outLab->FindObject("IsisCube").HasGroup("BandBin")) { + inb = 0; +#ifdef _DEBUG_ + ostm << "\n*** Matching Mosaic label ***\n"; + ostm << "isb=" << isb << " outFile=" << outFile << " inb=" << inb << "\n"; +#endif + MatchBandBinGroup(isb, outFile, inb); + } + // Otherwise copy the input cube bandbin to the output file + else { +#ifdef _DEBUG_ + ostm << "\n*** Creating Mosaic label ***\n"; +#endif + AddBandBinGroup(isb, outFile); + } + } + // BandBin group is not found + else { + string m = "Match BandBin cannot be True when the image does not have the BandBin group"; + throw Isis::iException::Message(Isis::iException::Programmer, m, _FILEINFO_); + } + } + // Match BandBin set to false and CREATE and TRACKING is true + else { + if(mtTrackInfo.bCreate && mtTrackInfo.bTrack) { + AddDefaultBandBinGroup(); + } + } + + // Even if the track flag is off, if the track table exists continue tracking + if(bTrackExists) { + mtTrackInfo.bTrack = true; + } + + int iOriginBand = 0, iChanged = 0; + + // Do this before SetMosaicOrigin as we don't want to set the filename + // in the table unless the band info is valid + if(mePriority == band) { + // Find the band to be compared + FileType eFileType = FileType(0); + GetBandIndex(eFileType); + eFileType = FileType(1); + GetBandIndex(eFileType); + } + + // Image name into the table & Get the index for this input file + int iInNumBands = inb - isb + 1; // actual number of inpur bands being transfered to mosaic + int iIndex = GetIndexOffsetByPixelType(); + + // Tracking is done for: + // (1) Band priority, + // (2) Ontop and Beneath priority with number of bands equal to 1, + // (3) Ontop priority with all the special pixel flags set to true + if(mtTrackInfo.bTrack) { + if(mePriority == band || + ((mePriority == input || mePriority == mosaic) && iInNumBands == 1) || + (mePriority == input && mbHighSat && mbLowSat && mbNull)) { + SetMosaicOrigin(iIndex); + } + else { + mtTrackInfo.bTrack = false; + } + } + +#ifdef _DEBUG_ + ostm << "Track=" << mtTrackInfo.bTrack << " Index=" << iIndex << " Input Bands=" << iInNumBands << "\n"; +#endif + + int iOutNumBands = OutputCubes[0]->Bands(); + + if(mtTrackInfo.bTrack) { + iOriginBand = OutputCubes[0]->Bands(); //Get the last band set aside for "Origin" 1 based + iOutNumBands--; + iChanged = 0; +#ifdef _DEBUG_ + ostm << "iIndex=" << iIndex << " iOriginBand=" << iOriginBand << " Priority=" << mePriority << "\n*********************\n"; +#endif + + // For mosaic creation, the input is copied onto mosaic by default + if(mePriority == band && !mtTrackInfo.bCreate) { + BandComparison(iIndex, ins, inl, iss, isl, outSample, outLine); + } + } + + // Create portal buffers for the input and output files + Isis::Portal iportal(ins, 1, InputCubes[0]->PixelType()); + Isis::Portal oportal(ins, 1, OutputCubes[0]->PixelType()); + Isis::Portal cOrgPortal(ins, 1, OutputCubes[0]->PixelType()); + +#ifdef _DEBUG_ + ostm << "\n*** Input Stats ***\n" << "Bands Start=" << p_isb << " Number=" << inb << " Actual#=" << iInNumBands << "\n"; + ostm << "Samples Start=" << iss << " Number=" << ins << "\n"; + ostm << "Lines Start=" << isl << " Number=" << inl << "\n"; + + ostm << "*** Output Stats ***\n" << "Bands Start=" << outFile << " Number=" << OutputCubes[0]->Bands() << "\n"; + ostm << "Start Samples= " << outSample << " Lines= " << outLine << "\n"; +#endif + + for(int ib = isb, ob = outFile; ib < (isb + inb) && ob <= iOutNumBands; ib++, ob++) { +#ifdef _DEBUG_ + //ostm <<"\nBand Input=" << ib << " Output=" << ob << " priority=" << mePriority << "\n"; +#endif + for(int il = isl, ol = outLine; il < isl + inl; il++, ol++) { +#ifdef _DEBUG_ + //ostm <<"Line Input=" << il << " Output=" << ol << " priority=" << mePriority << "\n"; +#endif + + // Set the position of the portals in the input and output cubes + iportal.SetPosition(iss, il, ib); + InputCubes[0]->Read(iportal); + + oportal.SetPosition(outSample, ol, ob); + OutputCubes[0]->Read(oportal); + + if(mtTrackInfo.bTrack) { + cOrgPortal.SetPosition(outSample, ol, iOriginBand); + OutputCubes[0]->Read(cOrgPortal); + } + + bool bChanged = false; + // Move the input data to the output + for(int pixel = 0; pixel < oportal.size(); pixel++) { + // Creating Mosaic, copy the input onto mosaic + // regardless of the priority + if(mtTrackInfo.bCreate) { + oportal[pixel] = iportal[pixel]; + if(mtTrackInfo.bTrack) { + cOrgPortal[pixel] = iIndex; + bChanged = true; + } + iChanged++; + } + // Band Priority + else if(mtTrackInfo.bTrack && mePriority == band) { + int iPixelOrigin = GetPixelOrigin(ol, outSample, pixel); + if(iPixelOrigin == iIndex) { + oportal[pixel] = iportal[pixel]; + iChanged++; + bChanged = true; + } + } + // OnTop/Input Priority + else if(mePriority == input) { + if(Isis::IsNullPixel(oportal[pixel]) || + Isis::IsValidPixel(iportal[pixel]) || + mbHighSat && Isis::IsHighPixel(iportal[pixel]) || + mbLowSat && Isis::IsLowPixel(iportal[pixel]) || + mbNull && Isis::IsNullPixel(iportal[pixel])) { + oportal[pixel] = iportal[pixel]; + if(mtTrackInfo.bTrack) { + cOrgPortal[pixel] = iIndex; + bChanged = true; + } + iChanged++; + } + } + // Beneath/Mosaic Priority + else if(mePriority == mosaic) { + if(Isis::IsNullPixel(oportal[pixel])) { + oportal[pixel] = iportal[pixel]; + // Set the origin if number of input bands equal to 1 and if the track flag was set + if(mtTrackInfo.bTrack) { + cOrgPortal[pixel] = iIndex; + bChanged = true; + } + iChanged++; + } + } + } // End sample loop + + if(mtTrackInfo.bTrack && bChanged) { + OutputCubes[0]->Write(cOrgPortal); + } + OutputCubes[0]->Write(oportal); + p_progress->CheckStatus(); + } // End line loop + } // End band loop + + if(mtTrackInfo.bTrack) { +#ifdef _DEBUG_ + ostm << "\n****** Changed=" << iChanged << " *************\n"; + //Test(); +#endif + } + } // End StartProcess + + + /** + * This method matches the input BandBin group to the mosaic BandBin Group + * and allows band to be replaced in mosaic if it is NA (not assigned). + * It expects the bands to be contiguous + * + * @piIsb - Input starting Band# + * @piOsb - Output starting Band# + * @piInb - Actual number of bands matching the mosaic + * + * returns None + * + * @throws Isis::iException::Message + * + * @author sprasad (9/25/2009) + */ + void ProcessMosaic::MatchBandBinGroup(const int piIsb, const int piOsb, int &piInb) { + Pvl *inLab = InputCubes[0]->Label(); + Pvl *outLab = OutputCubes[0]->Label(); + + PvlGroup &inBin = inLab->FindGroup("BandBin", Pvl::Traverse); + PvlGroup &outBin = outLab->FindGroup("BandBin", Pvl::Traverse); + if(inBin.Keywords() != outBin.Keywords()) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string msg = "Pvl Group [BandBin] does not match between the input and output cubes"; + throw Isis::iException::Message(iException::User, msg, _FILEINFO_); + } + + //zero based + int iIsb = (piIsb - 1), iOsb = (piOsb - 1); + + for(int i = 0; i < outBin.Keywords(); i++) { + PvlKeyword &outKey = outBin[i]; + if(inBin.HasKeyword(outKey.Name())) { + PvlKeyword &inKey = inBin[outKey.Name()]; + for(int j = iOsb, k = iIsb; j < outKey.Size() && k < inKey.Size(); j++, k++) { + piInb++; + if(outKey[j] == "NA") { + outKey[j] = inKey[k]; + } + else if(outKey[j] != inKey[k]) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string msg = "Pvl Group [BandBin] in Key[" + outKey.Name() + "] In value" + inKey[k] + + "and Out value=" + outKey[j] + " do not match"; + throw Isis::iException::Message(iException::User, msg, _FILEINFO_); + } + } + } + else { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string msg = "Pvl Group [BandBin] In Keyword[" + inBin[i].Name() + "] and Out Keyword[" + outBin[i].Name() + + "] does not match"; + throw Isis::iException::Message(iException::User, msg, _FILEINFO_); + } + } + piInb /= outBin.Keywords(); + } + + /** + * This method adds the BandBin group to the mosaic corresponding + * to the actual bands in the mosaic + * + * @piIsb - Input starting Band# + * @piOsb - Output starting Band# + * + * returns None + * + * @author sprasad (9/24/2009) + */ + void ProcessMosaic::AddBandBinGroup(int piIsb, int piOsb) { + Pvl *inLab = InputCubes[0]->Label(); + Pvl *outLab = OutputCubes[0]->Label(); + + int iOutBands = OutputCubes[0]->Bands(); + + if(mtTrackInfo.bTrack) { + iOutBands -= 1; // leave tracking band + } + + int iIsb = piIsb - 1; // array zero based + int iOsb = piOsb - 1; + +#ifdef _DEBUG_ + ostm << "\n***** AddBandBinGroup *****\nStart Bands Input=" << piIsb << " Output=" << piOsb << "\n\n"; +#endif + PvlGroup &cInBin = inLab->FindGroup("BandBin", Pvl::Traverse); + PvlGroup cOutBin("BandBin"); + + int iInBands = InputCubes[0]->Bands(); + + for(int i = 0; i < cInBin.Keywords(); i++) { + PvlKeyword &cInKey = cInBin[i]; + int iInKeySize = cInKey.Size(); + PvlKeyword cOutKey(cInKey.Name()); + for(int b = 0; b < iOsb; b++) { + cOutKey += "NA"; + } + for(int b = iOsb; b < iOutBands; b++) { + if(iIsb < cInKey.Size()) { + cOutKey += cInKey[iIsb++]; + } + else { + cOutKey += "NA"; + } + } + + // Add the "TRACKING" band to the Keyword if the flag is set and also if the number of + // input cube bands is same as the the keysize of the keyword in the BandBin group. + if(mtTrackInfo.bTrack && iInBands == iInKeySize) { + cOutKey += "TRACKING"; // for the origin band + } + + // Check for units and make sure output keyword units value is set to input + // keyword units value + if(cOutKey.Unit() != cInKey.Unit()) { + cOutKey.SetUnits((iString)(cInKey.Unit())); + } + + cOutBin += cOutKey; + iIsb = piIsb - 1; // reinitialize the input starting band + } + outLab->FindObject("IsisCube").AddGroup(cOutBin); + } + + /** + * AddDefaultBandBinGroup + * + * This method adds a default BandBin group on Mosaic creation + * if the MatchBandBin Group is set to false and Tracking to set + * to true + * + * + * Return void + */ + void ProcessMosaic::AddDefaultBandBinGroup(void) { + Pvl *outLab = OutputCubes[0]->Label(); + + PvlGroup cOutBin("BandBin"); + + int iOutBands = OutputCubes[0]->Bands(); + iOutBands--; // Leave tracking band + + PvlKeyword cOutKey("FilterName"); + + for(int i = 0; i < iOutBands; i++) { + cOutKey += "NA"; + } + + cOutKey += "TRACKING"; + cOutBin += cOutKey; + + outLab->FindObject("IsisCube").AddGroup(cOutBin); + } + /** + * This method gets the origin of a pixel in the mosaic from + * the origin band given the line, sample and starting mosaic + * sample numbers + * + * @piLineNum - Input Line # + * @piSS - Starting Mosaic Sample # + * @piSampleNum - Pixel index (Sample #) + * + * returns the pixel origin + * + * @author sprasad (8/28/2009) + */ + int ProcessMosaic::GetPixelOrigin(int piLineNum, int piSS, int piSampleNum) { + Isis::Portal cOrgPortal((piSampleNum + 1), 1, OutputCubes[0]->PixelType()); + + //Get the last band set aside for "Origin" + int iOriginBand = OutputCubes[0]->Bands(); + + // 1 based + cOrgPortal.SetPosition(piSS, piLineNum, iOriginBand); + OutputCubes[0]->Read(cOrgPortal); + + return (int) cOrgPortal[piSampleNum]; + + } + + /** + * Given filetype(input or output) returns the band index in that file for the + * band info stored in class member trackinfo for band priority + * + * @peFileType- Filetype input or output + * + * @returns Band Index + * + * @throws Isis::iException::Message + * + * @author sprasad (9/04/2009) + */ + int ProcessMosaic::GetBandIndex(const FileType &peFileType) { + bool bFound = false; + int iBandIndex = 0; + + Pvl cPvlLabel; + + if(peFileType == inFile) + cPvlLabel = *(InputCubes[0]->Label()); + else + cPvlLabel = *(OutputCubes[0]->Label()); + +#ifdef _DEBUG_ + ostm << "**GetBandIndex**\n"; +#endif + //if non-zero integer, must be original band #, 1 based + if(mtTrackInfo.iBandNum) { + PvlKeyword cKeyOrigBand; + if(cPvlLabel.FindGroup("BandBin", Pvl::Traverse).HasKeyword("OriginalBand")) { + cKeyOrigBand = cPvlLabel.FindGroup("BandBin", Pvl::Traverse).FindKeyword("OriginalBand"); + } + int iSize = cKeyOrigBand.Size(); +#ifdef _DEBUG_ + ostm << "Num of Original Bands=" << iSize << "\n"; +#endif + char buff[64]; + sprintf(buff, "%d", mtTrackInfo.iBandNum); + for(int i = 0; i < iSize; i++) { + if(std::string(buff) == cKeyOrigBand[i]) { + iBandIndex = i + 1; //1 based get band index + bFound = true; + break; + } + } + } + //key name + else { + PvlKeyword cKeyName; +#ifdef _DEBUG_ + ostm << "Key Name=" << mtTrackInfo.sKeyName << " Value=" << mtTrackInfo.sKeyValue << "\n"; +#endif + if(cPvlLabel.FindGroup("BandBin", Pvl::Traverse).HasKeyword(mtTrackInfo.sKeyName)) { + cKeyName = cPvlLabel.FindGroup("BandBin", Pvl::Traverse).FindKeyword(mtTrackInfo.sKeyName); + } + int iSize = cKeyName.Size(); + for(int i = 0; i < iSize; i++) { +#ifdef _DEBUG_ + ostm << "Band=" << cKeyName[i].c_str() << "\n"; +#endif + if(Isis::iString::Equal(mtTrackInfo.sKeyValue.c_str(), cKeyName[i].c_str())) { + iBandIndex = i + 1; //1 based get key value index + bFound = true; + break; + } + } + } + if(!bFound) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string msg = "Invalid Band / Key Name, Value "; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); +#ifdef _DEBUG_ + CloseDebug(); +#endif + } + +#ifdef _DEBUG_ + ostm << "iBandNum=" << iBandIndex << "\n"; +#endif + if(peFileType == inFile) + mtTrackInfo.iInBand = iBandIndex; + else + mtTrackInfo.iOutBand = iBandIndex; + + return iBandIndex; + } + + /** + * This method compares the specified band of the input and + * output using the criteria (lesser or greater) to assign the + * pixel origin(input fileindex) to the origin band. In the StartProcess(), + * input pixel is assigned to the output if the origin pixel equals the current + * input file index + * + * @piIndex - Filename Index for the origin band (default + + * zero based index) + * @piIns - Number of input samples + * @piInl - Number of input lines + * @piIss - Starting input sample + * @piIsl - Starting input line + * @piOss - Starting output sample + * @piOsl - Starting output line + * + * @throws Isis::iException::Message + * + * @author sprasad (9/04/2009) + */ + void ProcessMosaic::BandComparison(int piIndex, int piIns, int piInl, int piIss, int piIsl, int piOss, int piOsl) { + // + // Create portal buffers for the input and output files + Isis::Portal cIportal(piIns, 1, InputCubes[0]->PixelType()); + Isis::Portal cOportal(piIns, 1, OutputCubes[0]->PixelType()); + Isis::Portal cOrgPortal(piIns, 1, OutputCubes[0]->PixelType()); + + //Get the last band set aside for "Origin" + int iOriginBand = OutputCubes[0]->Bands(); + +#ifdef _DEBUG_ + ostm << "*** Band Comparison ***\npeBCriteria=" << mtTrackInfo.eCriteria << " iOriginBand=" << iOriginBand << " piIndex=" << piIndex << " piIns=" << piIns ; + ostm << " piInl=" << piInl << " piIss=" << piIss << " piIsl=" << piIsl << " piOss=" << piOss << " piOsl=" << piOsl << " Num lines=" << piInl << "\n"; + ostm << " ** Special Pixels ** HS=" << mbHighSat << " LS=" << mbLowSat << " Null=" << mbNull << "\n"; +#endif + + for(int iIL = piIsl, iOL = piOsl; iIL < piIsl + piInl; iIL++, iOL++) { + // Set the position of the portals in the input and output cubes + cIportal.SetPosition(piIss, iIL, mtTrackInfo.iInBand); + InputCubes[0]->Read(cIportal); + + cOportal.SetPosition(piOss, iOL, mtTrackInfo.iOutBand); + OutputCubes[0]->Read(cOportal); + + cOrgPortal.SetPosition(piOss, iOL, iOriginBand); + OutputCubes[0]->Read(cOrgPortal); + + // Move the input data to the output + for(int iPixel = 0; iPixel < cOportal.size(); iPixel++) { +#ifdef _DEBUG_ + //ostm << endl << iIL << ".In="<< (int)cIportal[iPixel] <<" Out="<< (int)cOportal[iPixel] << " IsSpecial(In)=" << Isis::IsSpecial(cIportal[iPixel]) << " Compare=" << (cIportal[iPixel] < cOportal[iPixel]); +#endif + + if(Isis::IsNullPixel(cOrgPortal[iPixel]) || + mbHighSat && Isis::IsHighPixel(cIportal[iPixel]) || + mbLowSat && Isis::IsLowPixel(cIportal[iPixel]) || + mbNull && Isis::IsNullPixel(cIportal[iPixel])) { + cOrgPortal[iPixel] = piIndex; +#ifdef _DEBUG_ + //ostm << " SP >> Origin=" << (int)cOrgPortal[iPixel]; +#endif + } + else { + if(Isis::IsValidPixel(cIportal[iPixel])) { + if(Isis::IsSpecial(cOportal[iPixel]) || + (mtTrackInfo.eCriteria == Lesser && cIportal[iPixel] < cOportal[iPixel]) || + (mtTrackInfo.eCriteria == Greater && cIportal[iPixel] > cOportal[iPixel])) { + cOrgPortal[iPixel] = piIndex; +#ifdef _DEBUG_ + //ostm << " CRITERIA >> Origin=" << (int)cOrgPortal[iPixel]; +#endif + } + } + } + } + OutputCubes[0]->Write(cOrgPortal); + } + } + + /** + * Debugging + * + * @author sprasad (9/2/2009) + */ + void ProcessMosaic::Test(void) { + int iBand = OutputCubes[0]->Bands(); + int iLines = OutputCubes[0]->Lines(); + int iSamples = OutputCubes[0]->Samples(); + int iFileIndex; + + Isis::Portal cOrgPortal(iSamples, 1, OutputCubes[0]->PixelType()); + int iOffset = GetOriginDefaultByPixelType(); + +#ifdef _DEBUG_ + ostm << "\nTesting\nPixel Type=" << SizeOf(OutputCubes[0]->PixelType()) << " Offset=" << iOffset << " OriginBand=" << iBand << "\n"; +#endif + + for(int line = 1; line <= iLines; line++) { + cOrgPortal.SetPosition(1, line, iBand); //sample, line, band position + OutputCubes[0]->Read(cOrgPortal); + for(int iPixel = 0; iPixel < cOrgPortal.size(); iPixel++) { + iFileIndex = (int)cOrgPortal[iPixel] - iOffset; +#ifdef _DEBUG_ + ostm << "Line=" << line << " Value=" << (int)cOrgPortal[iPixel] << " FileIndex=" << iFileIndex << "\n"; +#endif + } + if(line >= 2) { + break; + } + } +#ifdef _DEBUG_ + ostm << "************************************************\n"; +#endif + } + + + /** + * This method returns the start value depending on the pixel + * type 8,16,32 bit. + * + * @returns the start/offset value + * + * @throws Isis::iException::Message + * + * @author sprasad (8/28/2009) + */ + int ProcessMosaic::GetIndexOffsetByPixelType(void) { + int iOffset = 0; + + switch(SizeOf(OutputCubes[0]->PixelType())) { + case 1: + iOffset = VALID_MIN1; + break; + + case 2: + iOffset = VALID_MIN2; + break; + + case 4: + iOffset = FLOAT_MIN; + break; + } + return iOffset; + } + + /** + * This method returns the defaults(unassigned origin value) + * depending on the pixel type. + * + * @No parameters + * + * @returns default value + * + * @throws Isis::iException::Message + * + * @author sprasad (9/10/2009) + */ + int ProcessMosaic::GetOriginDefaultByPixelType(void) { + int iDefault; + + switch(SizeOf(OutputCubes[0]->PixelType())) { + case 1: + iDefault = NULL1; + break; + + case 2: + iDefault = NULL2; + break; + + case 4: + iDefault = INULL4; + break; + + default: +#ifdef _DEBUG_ + CloseDebug(); +#endif + string msg = "ProcessMosaic::GetOriginDefaultByPixelType - Invalid Pixel Type"; + throw Isis::iException::Message(Isis::iException::Programmer, msg, _FILEINFO_); + } + + return iDefault; + } + + /** + * This method sets the origin band to defaults(unassigned value) + * depending on the pixel type. + * + * @No parameters and no return value + * + * @author sprasad (8/28/2009) + */ + void ProcessMosaic::ResetOriginBand(void) { + int iBand = OutputCubes[0]->Bands(); + int iLines = OutputCubes[0]->Lines(); + int iSample = OutputCubes[0]->Samples(); + + int iDefault = GetOriginDefaultByPixelType(); + + Isis::Portal cOrgPortal(iSample, 1, OutputCubes[0]->PixelType()); + +#ifdef _DEBUG_ + ostm << "\n*****ResetOriginBand****\nDefault=" << iDefault << " Band=" << iBand << " Pixels size=" << OutputCubes[0]->PixelType() << " Portal Size=" << cOrgPortal.size() << "\n"; + int iPixelIndex = 0; +#endif + + for(int i = 1; i <= iLines; i++) { + cOrgPortal.SetPosition(1, i, iBand); //sample, line, band position + OutputCubes[0]->Read(cOrgPortal); + for(int iPixel = 0; iPixel < cOrgPortal.size(); iPixel++) { + cOrgPortal[iPixel] = (float)(iDefault); +#ifdef _DEBUG_ + if(iPixel < 10) { + //ostm << iPixelIndex++ <<"."<<(int)cOrgPortal[iPixel] << "\n"; + } +#endif + } + OutputCubes[0]->Write(cOrgPortal); + } + //Test(); + } + + /** + * This method searchs the mosaic label for a table with name + * "InputFile". If found return true else false. Checks for the + * existence of the origin table + * + * @returns the table index of the current image + * + * @author sprasad (9/22/2009) + */ + bool ProcessMosaic::GetTrackStatus(void) { + //get the output label + Pvl *cPvlOut = OutputCubes[0]->Label(); + + bool bTableExists = false; + int iNumObjs = cPvlOut->Objects(); + PvlObject cPvlObj; + + //Check if table already exists + if(cPvlOut->HasObject("Table")) { + for(int i = 0; i < iNumObjs; i++) { + cPvlObj = cPvlOut->Object(i); + if(cPvlObj.HasKeyword("Name", Pvl::Traverse)) { + PvlKeyword cNameKey = cPvlObj.FindKeyword("Name", Pvl::Traverse); + if(cNameKey[0] == SRC_IMAGE_TBL) { + bTableExists = true; + } + } + } + } +#ifdef _DEBUG_ + ostm << "GetTrackStatus, Track Status=" << bTableExists << endl; +#endif + return bTableExists; + } + + /** + * This method creates a table if not already created to hold + * the image file names if the track flag is true. If table + * exists, checks if the image already exists and if it does + * not, then adds the new image file name. If the field size is + * smaller than the new image name, then it resizes all the + * records to new file size. When the table is newly created,it + * resets the origin band to default based on pixel type. + * + * @param piIndex - the input file index + * + * @returns none + * + * @throws an exception if the number of images exceeds the + * pixel size. + * + * @throws Isis::iException::Message + * + * @author sprasad (8/28/2009) + */ + void ProcessMosaic::SetMosaicOrigin(int &piIndex) { + // Get only the file name + std::string sInputFile = Filename(InputCubes[0]->Filename()).Name(); + std::string sTableName = SRC_IMAGE_TBL; + + // Get the serial number + std::string sSerialNumber = SerialNumber::Compose(*(InputCubes[0])); + int iFileNameLen = sInputFile.length(); + int iSerialNumLen = sSerialNumber.length(); + int iFieldLength = iSerialNumLen; + if(iFileNameLen > iSerialNumLen) { + iFieldLength = iFileNameLen; + } + + // Get output file name + std::string sOutputFile = Filename(OutputCubes[0]->Filename()).Name(); + + Pvl *cPvlOut = OutputCubes[0]->Label(); + + // Create a table record with the new image file name and serial number info + TableRecord cFileRecord; + + // Populate with File Name + TableField cFileField("FileName", TableField::Text, iFieldLength); + cFileField = sInputFile; + cFileRecord += cFileField; + + // Populate with Serial Number + TableField cSNField("SerialNumber", TableField::Text, iFieldLength); + cSNField = sSerialNumber; + cFileRecord += cSNField; + +#ifdef _DEBUG_ + ostm << "\n***SetMosaicOrigin***\nFile Name=" << sInputFile << " Length=" << sInputFile.length() << " Track=" << mtTrackInfo.bTrack << "\n"; + //ostm << "Record Size="<< cFileRecord.RecordSize() << "\n"; +#endif + + int iNumObjs = cPvlOut->Objects(); + PvlObject cPvlObj; + + // Check if the Table exists + if(cPvlOut->HasObject("Table")) { +#ifdef _DEBUG_ + ostm << "Table object Exists\n"; +#endif + for(int i = 0; i < iNumObjs; i++) { + cPvlObj = cPvlOut->Object(i); + if(cPvlObj.HasKeyword("Name", Pvl::Traverse)) { + PvlKeyword cNameKey = cPvlObj.FindKeyword("Name", Pvl::Traverse); +#ifdef _DEBUG_ + ostm << "key name=" << cNameKey[0] << " Tablename=" << sTableName << "\n"; +#endif + if(cNameKey[0] == sTableName) { + PvlKeyword cFieldKey = cPvlObj.FindGroup("Field").FindKeyword("Size"); +#ifdef _DEBUG_ + ostm << "Found Table Name = " << cNameKey[0] << "\n"; +#endif + + //set the tracker flag to true as the tracking table exists + mtTrackInfo.bTrack = true; + + // Create a new blank table + Table cFileTable(sTableName); + + // Read and make a copy of the existing tracking table + Table cFileTable_Copy = Table(sTableName); + OutputCubes[0]->Read(cFileTable_Copy); + + // Records count + int iRecs = cFileTable_Copy.Records(); + +#ifdef _DEBUG_ + ostm << "\nRecords =" << iRecs << "\n"; +#endif + + // Check if the image index can be accomadated in the pixel size + bool bFull = false; + switch(sizeof(OutputCubes[0]->PixelType())) { + case 1: + if(iRecs >= (VALID_MAX1 - 1)) // Index is 1 based as 0=Null invalid value + bFull = true; + break; + case 2: + if(iRecs > (VALID_MAX2 - VALID_MIN2 + 1)) // Signed 16bits with some special pixels + bFull = true; + break; + + case 4: + if(iRecs > (FLOAT_MAX - FLOAT_MIN + 1)) // Max float mantissa + bFull = true; + break; + } + + if(bFull) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string msg = "The number of images in the Mosaic exceeds the pixel size"; + throw Isis::iException::Message(Isis::iException::Programmer, msg, _FILEINFO_); + } + + for(int i = 0; i < iRecs; i++) { + // Get the file name and trim out the characters filled due to resizing + string sTableFile = string(cFileTable_Copy[i][0]); + size_t found = sTableFile.rfind(".cub"); + if(found != string::npos) { + sTableFile.erase(found + 4); // clear the packing characters - get only the file name + } + + // ostm << "File=" << string(cFileTable_Copy[i][0]).c_str() << " Length=" << string(cFileTable_Copy[i][0]).length() << " Compare=" << str.compare(sInputFile) << "\n"; + if(sTableFile.compare(sInputFile) == 0) { +#ifdef _DEBUG_ + ostm << "Image file Exists\n"; +#endif + piIndex += i; + return; + } + + // To initialise the new table, on the first file name comparison, + // check the size of the existing table record with the size of the new record being added + if(!i) { + if(iString(cFieldKey[0]).ToInteger() < iFieldLength) { + TableRecord cFileRecordUpdate; + TableField cFileFieldUpdate("FileName", TableField::Text, iFieldLength); + cFileFieldUpdate = cFileTable_Copy[i][0]; + cFileRecordUpdate += cFileFieldUpdate; + + // Populate with Serial Number + TableField cSNFieldUpdate("SerialNumber", TableField::Text, iFieldLength); + cSNFieldUpdate = cFileTable_Copy[i][1]; + cFileRecordUpdate += cSNFieldUpdate; + + cFileTable = Table(sTableName, cFileRecordUpdate); // add new record and set the size for all the other records + } + else { + cFileTable = Table(sTableName, cFileTable_Copy[i]); + } + } + + // Add the existing records into the new table + cFileTable += cFileTable_Copy[i]; + } + // Get the current image file index + piIndex += iRecs; + + // Add the current input image record to the new table + cFileTable += cFileRecord; + + // Copy the new table to the output Mosaic + OutputCubes[0]->Write(cFileTable); + break; //break while loop + } + } + }//end for loop + } + + //creating new table if track flag is true + if(mtTrackInfo.bCreate && mtTrackInfo.bTrack) { +#ifdef _DEBUG_ + ostm << "Creating Table " << SRC_IMAGE_TBL << " \n"; +#endif + Table cFileTable(sTableName, cFileRecord); + cFileTable += cFileRecord; + OutputCubes[0]->Write(cFileTable); + //reset the origin band based on pixel type + ResetOriginBand(); + } + } + + /** + * Opens an input cube specified by the user. This method is overloaded and + * adds the requirement that only one input cube can be specified. + * + * @return Cube* + * + * @param parameter User parameter to obtain file to open. Typically, the value + * is "FROM". For example, the user can specify on the command + * line FROM=myfile.cub and this method will attempt to open + * the cube "myfile.cub" if the parameter was set to "FROM". + * + * @param ss The starting sample within the input cube. This allowd the + * application to choose a sub-area from the input cube to be place + * into the mosaic. Defaults to 1 + * + * @param sl The starting line within the input cube. This allowd the + * application to choose a sub-area from the input cube to be place + * into the mosaic. Defaults to 1 + * + * @param sb The starting band within the input cube. This allowd the + * application to choose a sub-area from the input cube to be place + * into the mosaic. Defaults to 1 + * + * @param ns The number of samples from the input cube. This allowd the + * application to choose a sub-area from the input cube to be place + * into the mosaic. Defaults to number of samples in the cube + * + * @param nl The number of lines from the input cube. This allowd the + * application to choose a sub-area from the input cube to be place + * into the mosaic. Defaults to number of lines in the cube + * + * @param nb The number of bands from the input cube. This allowd the + * application to choose a sub-area from the input cube to be place + * into the mosaic. Defaults to number of bands in the cube + * + * @throws Isis::iException::Message + */ + Isis::Cube *ProcessMosaic::SetInputCube(const std::string ¶meter, + const int ss, const int sl, const int sb, + const int ns, const int nl, const int nb) { + + // Make sure only one input is active at a time +#ifdef _DEBUG_ + ostm << "InputCubes.size()=" << InputCubes.size() << "\n"; +#endif + if(InputCubes.size() > 0) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string m = "You must specify exactly one input cube"; + throw Isis::iException::Message(Isis::iException::Programmer, m, _FILEINFO_); + } + + p_iss = ss; + p_isl = sl; + p_isb = sb; + p_ins = ns; + p_inl = nl; + p_inb = nb; + + Isis::Cube *cInCube = Isis::Process::SetInputCube(parameter); + + //get the output label + Pvl *cInPvl = InputCubes[0]->Label(); + if(cInPvl->FindGroup("Dimensions", Pvl::Traverse).HasKeyword("Bands")) { + PvlKeyword &cBandKey = cInPvl->FindGroup("Dimensions", Pvl::Traverse).FindKeyword("Bands"); + iString sStr(cBandKey[0]); + if(sStr.ToInteger() < nb) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string m = "The parameter number of input bands exceeds the actual number of bands in the input cube"; + throw Isis::iException::Message(Isis::iException::Programmer, m, _FILEINFO_); + } + } + return cInCube; + } + + /** + * Opens an input cube specified by the user. This method is overloaded and + * adds the requirement that only one input cube can be specified. + * + * @return Cube* + * + * @param fname + * + * @param att + * + * @param ss The starting sample within the input cube. This allowd the + * application to choose a sub-area from the input cube to be place + * into the mosaic. Defaults to 1 + * + * @param sl The starting line within the input cube. This allowd the + * application to choose a sub-area from the input cube to be place + * into the mosaic. Defaults to 1 + * + * @param sb The starting band within the input cube. This allowd the + * application to choose a sub-area from the input cube to be place + * into the mosaic. Defaults to 1 + * + * @param ns The number of samples from the input cube. This allowd the + * application to choose a sub-area from the input cube to be place + * into the mosaic. Defaults to number of samples in the cube + * + * @param nl The number of lines from the input cube. This allowd the + * application to choose a sub-area from the input cube to be place + * into the mosaic. Defaults to number of lines in the cube + * + * @param nb The number of bands from the input cube. This allowd the + * application to choose a sub-area from the input cube to be place + * into the mosaic. Defaults to number of bands in the cube + * + * @throws Isis::iException::Message + */ + Isis::Cube *ProcessMosaic::SetInputCube(const std::string &fname, + Isis::CubeAttributeInput &att, + const int ss, const int sl, const int sb, + const int ns, const int nl, const int nb) { + + // Make sure only one input is active at a time + if(InputCubes.size() > 0) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string m = "You must specify exactly one input cube"; + throw Isis::iException::Message(Isis::iException::Programmer, m, _FILEINFO_); + } + + p_iss = ss; + p_isl = sl; + p_isb = sb; + p_ins = ns; + p_inl = nl; + p_inb = nb; + + Isis::Cube *cInCube = Isis::Process::SetInputCube(fname, att); + + //check if the number of bands specified is not greater than the actual number of bands in the input + Pvl *cInPvl = InputCubes[0]->Label(); + if(cInPvl->FindGroup("Dimensions", Pvl::Traverse).HasKeyword("Bands")) { + PvlKeyword &cBandKey = cInPvl->FindGroup("Dimensions", Pvl::Traverse).FindKeyword("Bands"); + iString sStr(cBandKey[0]); + if(sStr.ToInteger() < nb) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string m = "The parameter number of input bands exceeds the actual number of bands in the input cube"; + throw Isis::iException::Message(Isis::iException::Programmer, m, _FILEINFO_); + } + } + return cInCube; + } + + /** + * Opens an output cube specified by the user. This method is overloaded and + * adds the requirement that only one output cube can be specified. The output + * cube must exist before calling SetOutputCube. + * + * @return Cube* + * + * @param psParameter User parameter to obtain file to open. Typically, the value + * is "TO". For example, the user can specify on the command + * line TO=mosaic.cub and this method will attempt to open the + * cube "mosaic.cub" if the parameter was set to "TO". . + * + * @throws Isis::iException::Message + */ + Isis::Cube *ProcessMosaic::SetOutputCube(const std::string &psParameter) { + + // Make sure there is only one output cube +#ifdef _DEBUG_ + ostm << "OutputCubes.size()=" << OutputCubes.size() << "\n"; +#endif + if(OutputCubes.size() > 0) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + string m = "You must specify exactly one output cube"; + throw Isis::iException::Message(Isis::iException::Programmer, m, _FILEINFO_); + } + + // Attempt to open a cube ... get the filename from the user parameter + // (e.g., "TO") and the cube size from an input cube + Isis::Cube *cube = new Isis::Cube; + try { + string fname = Application::GetUserInterface().GetFilename(psParameter); + cube->Open(fname, "rw"); + } + catch(Isis::iException &e) { +#ifdef _DEBUG_ + CloseDebug(); +#endif + delete cube; + throw; + } + + if(mtTrackInfo.bCreate) { + Pvl *outLab = cube->Label(); + if(outLab->FindObject("IsisCube").HasGroup("BandBin")) { + outLab->FindObject("IsisCube").DeleteGroup("BandBin"); + } + } + + // Everything is fine so save the cube on the stack + OutputCubes.push_back(cube); + return cube; + } + +} // end namespace isis diff --git a/isis/src/base/objs/ProcessMosaic/ProcessMosaic.h b/isis/src/base/objs/ProcessMosaic/ProcessMosaic.h new file mode 100644 index 0000000000000000000000000000000000000000..e92a798f4aac6f8ad0776a464d43d3852b22a5d4 --- /dev/null +++ b/isis/src/base/objs/ProcessMosaic/ProcessMosaic.h @@ -0,0 +1,334 @@ +#ifndef ProcessMosaic_h +#define ProcessMosaic_h +/** + * @file + * $Revision: 1.13 $ + * $Date: 2010/06/21 18:39:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Process.h" +#include "Buffer.h" + +enum MosaicPriority { + input, mosaic, band +}; + +enum BandCriteria { + Lesser, Greater +}; +enum FileType { + inFile, outFile +}; + +namespace Isis { + /** + * @brief Mosaic two cubs together + * + * This class allows a programmer to develop a program which merges two cubes + * together. The application sets the position where input (child) cube will be + * placed in the mosaic (parent) cube and priority. The Mosaic object will merge + * the overlapping area. + * + * This class also has the ability to track the origin of the pixel by storing + * the input image names in a table and assigning an index to each unique image + * in the order they were placed on the mosaic. If the priority is input or mosaic + * then tracking is done only for single band input image. Band priority can track + * the origin for multiple bands based on a specified band based on the criteria + * (Lesser or Greater). The specified band can be a number or any keyword in the label. + * + * There are also options to copy High and Low Saturation both for Instrument and + * Representation and Null DN values from the input to the mosaic. These options are + * valid for only input(top) and band priorities. + * + * Following are the values for the origin band depending on the pixel type + * -------------------------------------------------------------- + * Pixel Type Default Start Value Max Value Total Images + * (Bits) (No Origin) Supported + * -------------------------------------------------------------- + * 32 -16777216 -16777215 16777216 33549932 + * 16 -32768 -32767 32767 65535 + * 8 0 1 255 255 + * + * + * Tags: F(FALSE), T(TRUE), V(VALID), S(SPECIAL PIXEL HS, LS, NULL), N(NULL), + * I(INPUT), M(MOSAIC), HL(HS,LS) + * + * For priority=mosaic (beneath), the input is placed beneath the mosaic i.e. the + * input pixel will be copied to the mosaic only if the mosaic pixel is NULL. + * ------------------------ + * Input Mosaic Output + * ------------------------ + * V N I + * S,V HL,V M + * + * For priority=input(on top), following is the criteria for pixel assignment: + * ------------------------------------- + * ---Options--- ---Images---- + * HS LS NULL Input Mosaic Output + * ------------------------------------- + * F F F V S,V I + * F F F S S,V M + * T OR T OR T V S,V I + * T OR T OR T S S,V I(H,L,N) + * + * + * For priority=band, following is the criteria for pixel assignment: + * ----------------------------------------------------- + * ---Options--- ---Images---- + * HS LS NULL Input Mosaic Output + * ----------------------------------------------------- + * F F F V V Criteria based + * F F F V S I + * F F F S S,V M + * T OR T OR T S S,V I(H,L,N) + * T OR T OR T V V Criteria based + * T OR T OR T V S I + * + * + * + * @ingroup HighLevelCubeIO + * + * @author 2003-04-28 Stuart Sides + * + * @internal + * @history 2003-04-28 Stuart Sides - Modified unitTest.cpp to do a better test + * @history 2003-09-04 Jeff Anderson - Added SetInputWorkCube method + * @history 2005-02-11 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2006-09-01 Elizabeth Miller - Added BandBinMatch option to + * propagate the bandbin group to the + * mosaic and make sure the input cube + * bandbin groups match the mosaics + * bandbin group + * @history 2006-10-20 Stuart Sides - Fixed bug BandBin group did not get + * copied to the output mosaic. + * @history 2008-10-03 Steven Lambright - Fixed problem where member variables + * could be corrupted + * @history 2009-09-30 Sharmila Prasad - Added capability to track the pixel origin. + * Priorities Top and Beneath can track origin + * for a single band input image only. Band + * priority can track origin of a multi-band + * input image based on a particular band. + * Also Band placement is flexible and any bands + * from the input cube can fit within the output + * mosaic. Also ability to allow HS, LS or NULL pixels + * from input to the mosaic(output). Added table for + * Origin Default values based on pixel type + * @history 2010-02-25 Sharmila Prasad - Changed stricmp to use iString function "Equal" + * + * @todo 2005-02-11 Stuart Sides - add coded example and implementation example + * to class documentation + */ + + // Constants +#define SRC_IMAGE_TBL "InputImages" +#define FLOAT_MAX 16777216 +#define FLOAT_MIN -16777215 + + // structure for origin tracking information + typedef struct { + //from the GUI-user set parameters + bool bTrack; + bool bCreate; + int iBandNum; + std::string sKeyName; + std::string sKeyValue; + BandCriteria eCriteria; + //used for internal processing + int iInBand; //input band index for the corresponding band in KeyValue + int iOutBand; //output band index for the corresponding band in KeyValue + } TrackInfo; + + class ProcessMosaic : public Isis::Process { + + public: + + //! Constructs a Mosaic object + ProcessMosaic(); + + //! Destroys the Mosaic object. It will close all opened cubes. + ~ProcessMosaic(); + + // Line Processing method for one input and output cube + void StartProcess(const int &outputSample, const int &outputLine, + const int &outputBand, const MosaicPriority &priority); + + // Line Processing method for one input and output cube + void StartProcess(const int &piOutSample, const int &piOutLine, const int &piOutBand); + + Isis::Cube *SetInputCube(const std::string ¶meter, + const int ss = 1, const int sl = 1, + const int sb = 1, + const int ns = 0, const int nl = 0, + const int nb = 0); + + Isis::Cube *SetInputCube(const std::string &fname, + Isis::CubeAttributeInput &att, + const int ss = 1, const int sl = 1, + const int sb = 1, + const int ns = 0, const int nl = 0, + const int nb = 0); + + Isis::Cube *SetOutputCube(const std::string &psParameter); + + /** + * Sets the bandbin match parameter to the input boolean value + * @param b The boolean value to set the bandbin match parameter to + */ + void SetBandBinMatch(bool pbFlag) { + mbBandbinMatch = pbFlag; + }; + + // If Tracking is set, create table and add the input file name + // into the table to track the mosaic origin + void SetMosaicOrigin(int &piIndex); + + //get the file index offset to be saved in the band by pixel type + int GetIndexOffsetByPixelType(void); + + //reset the origin band + void ResetOriginBand(void); + + //Compare the input and mosaic for the specified band based on the criteria and update the mosaic origin band + void BandComparison(int piIndex, int piIns, int piInl, int piIss, int piIsl, int piOss, int piOsl); + + //Get the origin of the pixel given sample, line + int GetPixelOrigin(int piLineNum, int piStartSample, int piSampleNum); + + //Get the default origin value based on pixel type for the origin band + int GetOriginDefaultByPixelType(void); + + //Get the Band Index in an image of type (input/output) + int GetBandIndex(const FileType &peFileType); + + //Checks for the table with name "InputImage" + bool GetTrackStatus(void); + + //New mosaic, add the Band Bin group specific to the mosaic + void AddBandBinGroup(int piIsb, int piOsb); + + // Default BandBin group if Match BandBin is set to False + void AddDefaultBandBinGroup(void); + + //Mosaic exists, match the band with the input image + void MatchBandBinGroup(const int piIsb, const int piOsb, int &piInb); + + // Get/Set HS,LS, NULL Flags. If set true and if the input image has a + // Special Pixel then it is copied to the mosaic irrespective of any condition + // Not supported in mosaic priority + void SetHighSaturationFlag(bool pbFlag) { + mbHighSat = pbFlag; + } ; + void SetLowSaturationFlag(bool pbFlag) { + mbLowSat = pbFlag; + } ; + void SetNullFlag(bool pbFlag) { + mbNull = pbFlag; + } ; + + bool GetHighSaturationFlag(void) { + return mbHighSat; + } ; + bool GetLowSaturationFlag(void) { + return mbLowSat; + } ; + bool GetNullFlag(void) { + return mbNull; + } ; + + // Set the priority input, mosaic, band + void SetPriority(MosaicPriority pePriority) { + mePriority = pePriority; + }; + + // Set/Get the Track Flag + void SetTrackFlag(bool pbFlag) { + mtTrackInfo.bTrack = pbFlag; + }; + bool GetTrackFlag(void) { + return mtTrackInfo.bTrack; + }; + + // Flag to indicate to the Process that the mosaic is being newly created + // Indication that the new label specific to the mosaic needs to be created. + void SetCreateFlag(bool pbFlag) { + mtTrackInfo.bCreate = pbFlag; + }; + + // Set the Band Number for priority Band + void SetBandNumber(int piBandNum) { + mtTrackInfo.iBandNum = piBandNum; + }; + + // Set the keyword for priority Band + void SetBandKeyWord(std::string psKeyName, std::string psKeyValue) { + mtTrackInfo.sKeyName = psKeyName; + mtTrackInfo.sKeyValue = psKeyValue; + }; + + // Set the Band Criteria Lesser/Greater than for Band priority + void SetBandCriteria(BandCriteria peCriteria) { + mtTrackInfo.eCriteria = peCriteria; + }; + + void Test(void); + + int GetInputStartLine(void) { + return miOsl; + }; + int GetInputStartSample(void) { + return miOss; + }; + int GetInputStartBand(void) { + return miOsb; + }; + + private: + int p_iss; //! + +#include "ProcessMosaic.h" +#include "Portal.h" +#include "Application.h" + +using namespace std; + +int giDefault = 0; + +void TestIn(int iss, int isl, int isb, int ins = 0, int inl = 0, int inb = 0); +void TestOut(int piSamples, int piLines, int piBands, int piOffset); + +/** + * Display the contents of Input image with starting and number of + * samples, lines,bands + * + * @author sprasad (10/14/2009) + * + * @param iss - input starting sample + * @param isl - input starting line + * @param isb - input starting band + * @param ins - input number of samples + * @param inl - input number of lines + * @param inb - input number of bands + */ +void TestIn(int iss, int isl, int isb, int ins, int inl, int inb) { + Isis::Cube cInCube; + Isis::UserInterface &ui = Isis::Application::GetUserInterface(); + string sFrom = ui.GetFilename("FROM"); + cInCube.Open(sFrom); + + cout << "\n*** Input Image *** "; + if(ins == 0) ins = cInCube.Samples() - iss + 1; + if(inl == 0) inl = cInCube.Lines() - isl + 1; + if(inb == 0) inb = cInCube.Bands() - isb + 1 ; + + printf("Stats %d, %d, %d, %d, %d, %d\n", iss, isl, isb, ins, inl, inb); + + int iS; + Isis::Portal ciPortal(ins, 1, cInCube.PixelType()); + for(int band = isb; band <= (isb + inb - 1); band++) { + for(int line = isl; line <= (isl + inl - 1); line++) { + iS = iss; + ciPortal.SetPosition(iss, line, band); //sample, line, band position + cInCube.Read(ciPortal); + for(int iPixel = 0; iPixel < ciPortal.size(); iPixel++) { + if(iPixel == 5) { + cout << endl; + } + printf("(%d,%d,%d)=%-11d ", iS++, line, band, (int)ciPortal[iPixel]); + } + cout << "\n"; + } + cout << "\n"; + } + cInCube.Close(); +} + +/** + * Display the contents of Ouput image and display the sample, line and band + * stas for which it the mosaic is tested + * + * @author sprasad (10/14/2009) + * + * @param iss - input starting sample + * @param isl - input starting line + * @param isb - input starting band + */ +void TestOut(int piSamples, int piLines, int piBands, int piOffset) { + int iFileIndex; + + Isis::Cube cOutCube; + Isis::UserInterface &ui = Isis::Application::GetUserInterface(); + string sTo = ui.GetFilename("TO"); + cOutCube.Open(sTo); + + cout << "\n*** Mosaic Image *** "; + printf("Start Stats %d, %d, %d\n", piSamples, piLines, piBands); + Isis::Portal coPortal(5, 1, cOutCube.PixelType()); + for(int band = piBands; band <= 3; band = 3) { + for(int line = 1; line <= 5; line++) { + coPortal.SetPosition(1, line, band); //sample, line, band position + cOutCube.Read(coPortal); + for(int iPixel = 0; iPixel < coPortal.size(); iPixel++) { + iFileIndex = 0; + if(band == 3 && coPortal[iPixel] != giDefault) { + iFileIndex = (int)coPortal[iPixel] - piOffset + 1; + } + if(band == 3) { //origin band + printf("(%d,%d,%d)=%-9d,%-1d ", (iPixel + 1), line, band, (int)coPortal[iPixel], iFileIndex); + } + else + printf("(%d,%d,%d)=%-11d ", (iPixel + 1), line, band, (int)coPortal[iPixel]); + } + cout << "\n"; + } + cout << "\n"; + if(band == 3) { + return; + } + } + cOutCube.Close(); +} +/** + * unitTest for ProcessMosaic + * tests for correct area drop, tracking origin, origin band, + * priorities input, mosaic and band, options to allow HS, LS and NULL + * pixels from input to mosaic, each time displaying the contents of the + * input and mosaic pixels for the area under consideration + * + * Also tests for exceptions like number of input and output images to + * be exactly one each, band cannot be priority if Track is set off and + * more + * + * @author sprasad (10/14/2009) + */ +void IsisMain() { + + Isis::Preference::Preferences(true); + + cout << "Testing Isis::ProcessMosaic Class ... " << endl; + + // Create the temp parent cube + Isis::Process p; + p.SetOutputCube("TO", 5, 5, 3); + p.EndProcess(); + + // *********************************************************** + // Drop a small area into the middle of the output + cout << "Create output mosaic with Tracking set to True\n"; + cout << "1. Drop a small area into the middle of the output\n"; + Isis::ProcessMosaic m1; + m1.SetTrackFlag(true); + m1.SetCreateFlag(true); + m1.SetPriority(input); + + m1.SetInputCube("FROM", 1, 1, 1, 10, 5, 1); + + m1.SetOutputCube("TO"); + + int iDefault = m1.GetIndexOffsetByPixelType(); + giDefault = m1.GetOriginDefaultByPixelType(); + + m1.StartProcess(2, 2, 1); + + // Test for Tracking Table "Input Images" + if(m1.GetTrackStatus()) { + cout << "a. SUCCESS - Track Table Exists\n"; + } + else { + cout << "a. FAILURE - Track Table does not Exist\n"; + } + + // Test for Tracking Band + FileType eBandFile = outFile; //output + m1.SetBandKeyWord("OriginalBand", "TRACKING"); + if(m1.GetBandIndex(eBandFile) == 3) { + cout << "b. SUCCESS - Tracking Band Exists\n\n"; + } + else { + cout << "b. FAILURE - Tracking Band does not Exist\n\n"; + } + m1.EndProcess(); + + TestIn(1, 1, 1, 5, 5, 1); + TestOut(2, 2, 1, iDefault); + + remove("isisMosaic_01.cub"); + + cout << "************************************************************************************************\n"; + + // *********************************************************** + // Drop 2,2,1 into the lower right corner of band 2 + cout << "2. Drop 2,2,1 into the lower right corner of band 2\n"; + cout << "Tracking is set to False\n"; + Isis::ProcessMosaic m2; + m2.SetTrackFlag(false); + m2.SetCreateFlag(true); + m2.SetPriority(input); + + m2.SetInputCube("FROM", 2, 2, 1); + + p.SetOutputCube("TO", 5, 5, 3); + p.EndProcess(); + m2.SetOutputCube("TO"); + + m2.StartProcess(4, 4, 2); + m2.EndProcess(); + + TestIn(2, 2, 1, 5, 5, 1); + TestOut(4, 4, 2, iDefault); + remove("isisMosaic_01.cub"); + cout << "************************************************************************************************\n"; + + // *********************************************************** + // Drop 3,3,1 into the upper right corner of band 1 + cout << "3. Drop 3,3,1 into the upper right corner of band 1\n"; + Isis::ProcessMosaic m3; + m3.SetTrackFlag(true); + m3.SetCreateFlag(true); + m3.SetPriority(mosaic); + + m3.SetInputCube("FROM", 3, 3, 1, 10, 1, 1); + + p.SetOutputCube("TO", 5, 5, 3); + p.EndProcess(); + m3.SetOutputCube("TO"); + + m3.StartProcess(5, 1, 1); + m3.EndProcess(); + + TestIn(3, 3, 1, 5, 5, 1); + TestOut(5, 1, 1, iDefault); + + remove("isisMosaic_01.cub"); + cout << "************************************************************************************************\n"; + + // *********************************************************** + // Drop the first 3x3x1 the upper left corner + cout << "4. Drop the first 3x3x1 to the upper left corner\n"; + Isis::ProcessMosaic m4; + m4.SetTrackFlag(true); + m4.SetCreateFlag(true); + m4.SetPriority(mosaic); + + m4.SetInputCube("FROM", 1, 1, 1, 3, 3, 1); + + p.SetOutputCube("TO", 5, 5, 3); + p.EndProcess(); + m4.SetOutputCube("TO"); + + m4.StartProcess(1, 1, 1); + m4.EndProcess(); + + TestIn(1, 1, 1, 3, 3, 1); + TestOut(1, 1, 1, iDefault); + + //remove("isisMosaic_01.cub"); + cout << "************************************************************************************************\n"; + + // Test for mosaic(beneath) priority + cout << "5. Test for mosaic priority with existing mosaic\n"; + Isis::ProcessMosaic m5; + //m5.SetTrackFlag (true); + //m5.SetCreateFlag(false); + m5.SetPriority(mosaic); + + m5.SetInputCube("FROM", 1, 1, 1, 5, 5, 1); + + m5.SetOutputCube("TO"); + + m5.StartProcess(1, 2, 1); + m5.EndProcess(); + + TestIn(1, 1, 1, 5, 5, 1); + TestOut(1, 2, 1, iDefault); + + cout << "************************************************************************************************\n"; + + + // *********************************************************** + // Test for band priority using Keywords for band id + cout << "6. Test for band priority with Keyname \"FilterName\" and value \"Red\" with Criteria \"Greater\" than in an existing mosaic\n"; + Isis::ProcessMosaic m6; + m6.SetTrackFlag(true); + m6.SetCreateFlag(true); + m6.SetPriority(band); + m6.SetBandKeyWord("FilterName", "red"); + m6.SetBandCriteria(Greater); + + m6.SetInputCube("FROM", 3, 3, 1, 10, 1, 1); + + //p.SetOutputCube("TO", 5, 5, 3); + //p.EndProcess(); + m6.SetOutputCube("TO"); + + m6.StartProcess(1, 1, 1); + m6.EndProcess(); + + TestIn(3, 3, 1, 10, 1, 1); + TestOut(1, 1, 1, iDefault); + + cout << "************************************************************************************************\n"; + + cout << "7. Test for band priority for existing mosaic with Keyname \"OriginalBand\" and value \"1\" and Criteria \"Lesser\" than\n"; + Isis::ProcessMosaic m7; + m7.SetTrackFlag(true); + m7.SetCreateFlag(false); + m7.SetPriority(band); + m7.SetBandKeyWord("OriginalBand", "1"); + m7.SetBandCriteria(Lesser); + m7.SetHighSaturationFlag(false) ; + m7.SetLowSaturationFlag(false) ; + m7.SetNullFlag(false) ; + + m7.SetInputCube("FROM", 1, 1, 1, 10, 1, 1); + + //p.SetOutputCube("TO", 5, 5, 3); + //p.EndProcess(); + m7.SetOutputCube("TO"); + + m7.StartProcess(1, 1, 1); + m7.EndProcess(); + + TestIn(1, 1, 1, 10, 1, 1); + TestOut(1, 1, 1, iDefault); + + //remove("isisMosaic_01.cub"); + cout << "************************************************************************************************\n"; + + // *********************************************************** + // Test for band priority using Band Number + cout << "8. Test for band priority with BandNumber set\n"; + Isis::ProcessMosaic m8; + m8.SetTrackFlag(true); + m8.SetCreateFlag(true); + m8.SetPriority(band); + m8.SetBandNumber(1); + m8.SetBandCriteria(Lesser); + m8.SetHighSaturationFlag(true) ; + m8.SetLowSaturationFlag(false) ; + m8.SetNullFlag(false) ; + + m8.SetInputCube("FROM", 1, 1, 1, 5, 5, 1); + + //p.SetOutputCube("TO", 5, 5, 3); + //p.EndProcess(); + m8.SetOutputCube("TO"); + + m8.StartProcess(1, 3, 1); + m8.EndProcess(); + + TestIn(1, 1, 1, 5, 5, 1); + TestOut(1, 3, 1, iDefault); + + cout << "************************************************************************************************\n"; + + // *********************************************************** + // Test for HS value set with existing mosaic + cout << "9. Test for Null flag set with existing mosaic\n"; + Isis::ProcessMosaic m9; + //m9.SetTrackFlag (true); + m9.SetPriority(band); + m9.SetBandNumber(1); + m9.SetBandCriteria(Greater); + m9.SetHighSaturationFlag(false) ; + m9.SetLowSaturationFlag(false) ; + m9.SetNullFlag(true) ; + + m9.SetInputCube("FROM", 1, 1, 1, 5, 5, 1); + + m9.SetOutputCube("TO"); + + m9.StartProcess(1, 2, 1); + m9.EndProcess(); + + TestIn(1, 1, 1, 5, 5, 1); + TestOut(1, 2, 1, iDefault); + + // *********************************************************** + // Testing Errors + + // Try to open two input cubes + cout << "\n*** Test Error Handling ***\n"; + cout << "Test multiple input error" << endl; + try { + Isis::ProcessMosaic m; + m.SetInputCube("FROM"); + m.SetInputCube("FROM"); + m.StartProcess(1, 1, 1); + m.EndProcess(); + } + catch(Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + // *********************************************************** + // Try to open two output cubes + cout << "Test multiple output error" << endl; + try { + Isis::ProcessMosaic m; + m.SetOutputCube("TO"); + m.SetOutputCube("TO"); + m.StartProcess(1, 1, 1); + m.EndProcess(); + } + catch(Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + // *********************************************************** + // Drop the input completly outside the output + cout << "Test input does not overlap mosaic" << endl; + try { + Isis::ProcessMosaic m; + m.SetInputCube("FROM"); + m.SetOutputCube("TO"); + m.StartProcess(-20, 0, 1); + m.EndProcess(); + } + catch(Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + cout << "Test input does not overlap mosaic" << endl; + try { + Isis::ProcessMosaic m; + m.SetInputCube("FROM"); + m.SetOutputCube("TO"); + m.StartProcess(54, 23, 1); + m.EndProcess(); + } + catch(Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + // *********************************************************** + // Don't open an input cube + cout << "Test no input cube" << endl; + try { + Isis::ProcessMosaic m; + m.SetOutputCube("TO"); + m.StartProcess(1, 1, 1); + m.EndProcess(); + } + catch(Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + //*********************************************************** + // Don't open an output cube + cout << "Test no output cube" << endl; + try { + Isis::ProcessMosaic m; + m.SetInputCube("FROM"); + m.StartProcess(1, 1, 1); + m.EndProcess(); + } + catch(Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + //*********************************************************** + // Band cannot be a priority if Track is not set + cout << "Test Band cannot be a priority if Track is not set" << endl; + try { + Isis::ProcessMosaic m; + m.SetTrackFlag(false); + m.SetPriority(band); + m.SetBandNumber(1); + + m.SetOutputCube("TO"); + m.SetInputCube("FROM"); + m.StartProcess(1, 1, 1); + m.EndProcess(); + } + catch(Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + // *********************************************************** + // Test Band not found with Band as Priority + cout << "Test Band not found with Band as Priority" << endl; + try { + Isis::ProcessMosaic m; + m.SetTrackFlag(true); + m.SetPriority(band); + m.SetBandNumber(10); + + m.SetOutputCube("TO"); + m.SetInputCube("FROM"); + m.StartProcess(1, 1, 1); + //m.Test(); + m.EndProcess(); + } + catch(Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + remove("isisMosaic_01.cub"); +} + diff --git a/isis/src/base/objs/ProcessMosaic/unitTest.xml b/isis/src/base/objs/ProcessMosaic/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..57d87b156734e31566d743629b94e53df48d4719 --- /dev/null +++ b/isis/src/base/objs/ProcessMosaic/unitTest.xml @@ -0,0 +1,54 @@ + + + + Unit test for IsisMosaic class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth2.cub + + + cube + output + Real + + Test cube + + + Test cube + + + *.cub + + isisMosaic_01.cub + + + + diff --git a/isis/src/base/objs/ProcessPolygons/Makefile b/isis/src/base/objs/ProcessPolygons/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..61a309e4c48d2bd9fcea284ed81f152d78869c96 --- /dev/null +++ b/isis/src/base/objs/ProcessPolygons/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessPolygons.h +SRCS = ProcessPolygons.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessPolygons/ProcessPolygons.cpp b/isis/src/base/objs/ProcessPolygons/ProcessPolygons.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34df2d4b07ac06f68b92e5e08186f851163bb14f --- /dev/null +++ b/isis/src/base/objs/ProcessPolygons/ProcessPolygons.cpp @@ -0,0 +1,430 @@ + +#include "ProcessPolygons.h" +#include "PolygonTools.h" +#include "Application.h" +#include "SpecialPixel.h" + +#include "geos/geom/CoordinateSequence.h" +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/geom/Coordinate.h" +#include "geos/geom/Envelope.h" +#include "geos/geom/LineString.h" +#include "geos/geom/Geometry.h" +#include "geos/geom/Point.h" +#include "geos/util/IllegalArgumentException.h" +#include "geos/operation/overlay/snap/GeometrySnapper.h" + +using namespace std; +namespace Isis { + + ProcessPolygons::ProcessPolygons () { + + } + + /** + * + * + * @param samples + * @param lines + * @param values + */ + void ProcessPolygons::Rasterize (std::vector &samples, + std::vector &lines, + std::vector &values) { + p_samples = samples; + p_lines = lines; + p_values = values; + DoWork(0); + //FillPolygon(0); + + } + + /** + * + * + * @param samples + * @param lines + * @param band + * @param value + */ + void ProcessPolygons::Rasterize (std::vector &samples, + std::vector &lines, + int &band, double &value){ + + p_samples = samples; + p_lines = lines; + p_band = band; + p_value = value; + + /*Make sure we only loop thru one time since we only have one band.*/ + p_values.clear(); + p_values.push_back(1.0); + DoWork(1); + //FillPolygon(1); + + + } + + + + void ProcessPolygons::FillPolygon(int Flag){ + + geos::geom::CoordinateSequence *pts = new geos::geom::CoordinateArraySequence(); + for (unsigned int i = 0; i < p_samples.size(); i++ ) { + pts->add(geos::geom::Coordinate(p_samples[i], p_lines[i])); + }/*end for*/ + /*Add the first point again in order to make a closed line string*/ + pts->add(geos::geom::Coordinate(p_samples[0], p_lines[0])); + + try { + geos::geom::Polygon *poly = Isis::globalFactory.createPolygon( + globalFactory.createLinearRing(pts),NULL); + + /*If there is not an intersecting polygon, there is no reason to go on.*/ + if (!poly->intersects(p_imagePoly))return; + + geos::geom::Polygon *intersectPoly = ((geos::geom::Polygon*)p_imagePoly->intersection(poly)); + const geos::geom::Envelope *envelope = intersectPoly->getEnvelopeInternal(); + + for (double y = floor(envelope->getMinY()); y <= ceil(envelope->getMaxY()); y++ ) { + /*create a horizontal line that runs across the entire evelope.*/ + geos::geom::CoordinateSequence *linePts = new geos::geom::CoordinateArraySequence(); + linePts->add(geos::geom::Coordinate(floor(envelope->getMinX()), y)); + linePts->add(geos::geom::Coordinate(floor(envelope->getMaxX()), y)); + + geos::geom::LineString *line = Isis::globalFactory.createLineString(linePts); + + /*intersect the line with the polygon*/ + geos::geom::Geometry *intersects = poly->intersection(line); + + /*find out all the points were the line intersects the polygon*/ + geos::geom::CoordinateSequence *intersectCoords = intersects->getCoordinates(); + + for (unsigned int l = 0; l < intersectCoords->getSize()-1; l++ ) { + + /*now i want to go from coord 1 - coord 2 and do work....*/ + for (int x = (int) intersectCoords->getAt(l*2).x; x < (int)intersectCoords->getAt(l*2+1).x; x++ ) { + + for (unsigned int i = 0; i < p_values.size(); i++ ) { /* for each band */ + + /*write the count file*/ + if (Flag == 0) { + p_brick2->SetBasePosition((int)(x+0.5), (int) (y+0.5), i+1); + } + if (Flag == 1) { + p_brick2->SetBasePosition((int)(x+0.5), (int) (y+0.5), p_band); + } + + this->OutputCubes[1]->Read(*p_brick2); + double previousPixelCount = (*p_brick2)[0]; + + + if ((*p_brick2)[0] != Isis::Null) { + (*p_brick2)[0] += 1; + } else { + (*p_brick2)[0] = 1; + } + + this->OutputCubes[1]->Write(*p_brick2); + double currentCount = (*p_brick2)[0]; + + + /*write the average file*/ + if (Flag == 0) { + p_brick1->SetBasePosition((int)(x+0.5), (int)(y+0.5), i+1); + } + if (Flag == 1) { + p_brick1->SetBasePosition((int)(x+0.5), (int)(y+0.5), p_band); + } + //We need to think about how to handle special pixels in p_values also if + //the read-in value is a special pixel. + this->OutputCubes[0]->Read(*p_brick1); + double previousPixelValue = (*p_brick1)[0]; + if ((*p_brick1)[0] == Isis::Null) { + if (Flag == 0) { + (*p_brick1)[0] = p_values[i]; + } + if (Flag == 1) { + (*p_brick1)[0] = p_value; + } + } else { + /*Calculate the running average.*/ + double avg = 0; + if (Flag == 0) { + avg = (previousPixelCount * previousPixelValue + p_values[i]) + /currentCount; + } + if (Flag == 1) { + avg = (previousPixelCount * previousPixelValue + p_value) + /currentCount; + } + (*p_brick1)[0] = avg; + + } + + /*The new average value is written to the output cube.*/ + this->OutputCubes[0]->Write(*p_brick1); + }/*End for each band*/ + + } /*End for x*/ + } + delete linePts; + }/*End for y*/ + + delete poly; + delete intersectPoly; + + + } /*end try*/ + + catch (geos::util::IllegalArgumentException *ill) { + std::string msg = "ERROR! geos exception 1 ["; + msg += (iString)ill->what() + "]"; + delete ill; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + }/*end catch*/ + + + } + + /** + * This method does the actuall reading and writing to the cube + * file. The Flag parameter is there to help out where the two + * Rasterize method need to behave differently during this + * operation. Most notibly, when we set the position of the + * bricks and when we are calculating the average using the + * given value or values. + * + * @param Flag + */ + void ProcessPolygons::DoWork(int Flag){ + + geos::geom::CoordinateSequence *pts = new geos::geom::CoordinateArraySequence(); + for (unsigned int i = 0; iadd(geos::geom::Coordinate(p_samples[i], p_lines[i])); + }/*end for*/ + /*Add the first point again in order to make a closed line string*/ + pts->add(geos::geom::Coordinate(p_samples[0], p_lines[0])); + + try { + geos::geom::Polygon *poly = Isis::globalFactory.createPolygon( + globalFactory.createLinearRing(pts),NULL); + + /*If there is not an intersecting polygon, there is no reason to go on.*/ + if(!poly->intersects(p_imagePoly))return; + + geos::geom::Polygon *intersectPoly = ((geos::geom::Polygon*)p_imagePoly->intersection(poly)); + const geos::geom::Envelope *envelope = intersectPoly->getEnvelopeInternal(); + + geos::operation::overlay::snap::GeometrySnapper snap(*intersectPoly); + + /*go thru each coord. in the envelope and ask if it is within the polygon*/ + for (double x = floor(envelope->getMinX()); x <= ceil(envelope->getMaxX()); x++) { + if(x == 0 ) continue; + + for (double y = floor(envelope->getMinY()); y <= ceil(envelope->getMaxY()); y++) { + if(y == 0 ) continue; + + geos::geom::Coordinate c(x,y); + geos::geom::Point *p = Isis::globalFactory.createPoint(c); + geos::geom::Geometry *pSnapped = snap.snapTo(*p, 1.0e-10)->clone(); + + bool contains = pSnapped->within(intersectPoly); + + delete p; + delete pSnapped; + + if (contains) { + /*write the count file*/ + for (unsigned int i = 0; iSetBasePosition((int)(x+0.5), (int) (y+0.5), i+1); + + } + if(Flag == 1) { + p_brick2->SetBasePosition((int)(x+0.5), (int) (y+0.5), p_band); + } + + this->OutputCubes[1]->Read(*p_brick2); + double previousPixelCount = (*p_brick2)[0]; + + if ((*p_brick2)[0] != Isis::Null) { + (*p_brick2)[0] += 1; + } else { + (*p_brick2)[0] = 1; + } + + this->OutputCubes[1]->Write(*p_brick2); + double currentCount = (*p_brick2)[0]; + + + /*write the average band*/ + if(Flag == 0) { + p_brick1->SetBasePosition((int)(x+0.5), (int)(y+0.5), i+1); + } + if(Flag == 1) { + p_brick1->SetBasePosition((int)(x+0.5), (int)(y+0.5), p_band); + } + //We need to think about how to handle special pixels in p_values also if + //the read-in value is a special pixel. + this->OutputCubes[0]->Read(*p_brick1); + double previousPixelValue = (*p_brick1)[0]; + if ((*p_brick1)[0] == Isis::Null) { + if(Flag == 0) { + (*p_brick1)[0] = p_values[i]; + } + if(Flag == 1) { + (*p_brick1)[0] = p_value; + } + } else { + /*Calculate the running average.*/ + double avg = 0; + if(Flag == 0) { + avg = (previousPixelCount*previousPixelValue+p_values[i]) + /currentCount; + } + if(Flag == 1) { + avg = (previousPixelCount*previousPixelValue+p_value) + /currentCount; + } + (*p_brick1)[0] = avg; + + } + + /*The new average value is written to the output cube.*/ + this->OutputCubes[0]->Write(*p_brick1); + }/*End for each band*/ + + }/*End if (contains)*/ + + } /*End for y*/ + + }/*End for x*/ + + delete poly; + delete intersectPoly; + + } /*end try*/ + + catch (geos::util::IllegalArgumentException *ill) { + std::string msg = "ERROR! geos exception 1 ["; + msg += (iString)ill->what() + "]"; + delete ill; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + }/*end catch*/ + + } + + /** + * + * + */ + void ProcessPolygons::EndProcess () { + delete p_imagePoly; + delete p_brick1; + delete p_brick2; + Process::EndProcess(); + + } + + /** + * This gives the option to append to the cube + * + * @param avgFilename + * @param countFilename + * + * @return Isis::Cube* + */ + Isis::Cube* ProcessPolygons::AppendOutputCube(const std::string &avgFilename, + const std::string &countFilename){ + + Filename *file = new Filename(avgFilename); + std::string path = file->Path(); + std::string filename = file->Basename(); + std::string extension = file->Extension(); + + /*Open the average file with read/write permission*/ + Cube *averageCube = new Cube(); + averageCube->Open(avgFilename,"rw"); + OutputCubes.push_back(averageCube); + + /*Now open the count file with read/write permission*/ + Cube *countCube = new Cube(); + + if(countFilename == "") { + /*if the countFilename was set to nothing, then we use the default count + file name.*/ + std::string openFile = path + "/" + filename + "-count-." + extension; + countCube->Open(openFile, "rw"); + + } else { + countCube->Open(countFilename, "rw"); + } + + OutputCubes.push_back(countCube); + return countCube; + } + + /** + * + * + * @param avgFilename + * @param countFilename + * @param nsamps + * @param nlines + * @param nbands + */ + void ProcessPolygons::SetOutputCube (const std::string &avgFilename, const + std::string &countFilename, + Isis::CubeAttributeOutput &atts, + const int nsamps,const int nlines, + const int nbands) { + + this->Process::SetOutputCube(avgFilename, atts, nsamps, nlines, nbands); + this->Process::SetOutputCube(countFilename, atts, nsamps, nlines, nbands); + + geos::geom::CoordinateArraySequence imagePts; + + imagePts.add(geos::geom::Coordinate(0.0, 0.0)); + imagePts.add(geos::geom::Coordinate(0.0, this->OutputCubes[0]->Lines())); + imagePts.add(geos::geom::Coordinate(this->OutputCubes[0]->Samples(), + this->OutputCubes[0]->Lines())); + imagePts.add(geos::geom::Coordinate(this->OutputCubes[0]->Samples(), 0.0)); + imagePts.add(geos::geom::Coordinate(0.0, 0.0)); + + p_imagePoly = Isis::globalFactory.createPolygon( + globalFactory.createLinearRing(imagePts),NULL); + + p_brick1 = new Brick(*this->OutputCubes[0], 1, 1, nbands); + p_brick2 = new Brick(*this->OutputCubes[1], 1, 1, nbands); + } + + /** + * + * + * @param parameter + * @param nsamps + * @param nlines + * @param nbands + */ + void ProcessPolygons::SetOutputCube (const std::string ¶meter, + const int nsamps,const int nlines, + const int nbands) { + + std::string avgString = + Application::GetUserInterface().GetFilename(parameter); + + Isis::CubeAttributeOutput atts = + Application::GetUserInterface().GetOutputAttribute(parameter); + + Filename *file = new Filename(avgString); + std::string path = file->Path(); + std::string filename = file->Basename(); + std::string countString = path + "/" + filename + "-count"; + SetOutputCube(avgString, countString, atts, nsamps, nlines, nbands); + + } + + +} /* end namespace isis*/ + diff --git a/isis/src/base/objs/ProcessPolygons/ProcessPolygons.h b/isis/src/base/objs/ProcessPolygons/ProcessPolygons.h new file mode 100644 index 0000000000000000000000000000000000000000..ba3b10148fb7fbed31089b9348e07e9eb5e93029 --- /dev/null +++ b/isis/src/base/objs/ProcessPolygons/ProcessPolygons.h @@ -0,0 +1,66 @@ +#ifndef ProcessPolygons_h +#define ProcessPolygons_h + +#include "ProjectionFactory.h" +#include "Process.h" +#include "Brick.h" +#include "Filename.h" + +#include "geos/geom/Coordinate.h" +#include "geos/geom/Polygon.h" + +namespace Isis { + + /** + * + * @author 2007-12-07 Stacy Alley + * + * @internal + * @history 2010-02-26 Steven Lambright - Now using a geometry snapper on + * points before testing if they are inside a polygon inside + * DoWork(...). + */ + class ProcessPolygons : public Isis::Process { + + public: + ProcessPolygons(); + + void SetOutputCube (const std::string ¶meter, const int nsamps, + const int nlines, int nbands = 1); + + void SetOutputCube(const std::string &avgFilename, const std::string + &countFilename, Isis::CubeAttributeOutput &atts, + const int nsamps, const int nlines, int nbands = 1); + + Isis::Cube* AppendOutputCube(const std::string &avgFilename, + const std::string &countFilename=""); + + void Rasterize (std::vector &samples, + std::vector &lines, + std::vector &values); + + void Rasterize (std::vector &samples, + std::vector &lines, + int &band, double &value); + + + void EndProcess(); + + private: + void DoWork(int Flag); + void FillPolygon(int Flag); + void GetPolygonCoords(); + std::vector p_samples, p_lines, p_values; + std::vector p_polygonCoordinates; + double p_value; + int p_band; + Brick *p_brick1; + Brick *p_brick2; + geos::geom::Polygon *p_imagePoly; + + + }; + +}; + +#endif diff --git a/isis/src/base/objs/ProcessPolygons/ProcessPolygons.truth b/isis/src/base/objs/ProcessPolygons/ProcessPolygons.truth new file mode 100644 index 0000000000000000000000000000000000000000..c8b98daaafc4b7296c60f2a238eecf2f636fe903 --- /dev/null +++ b/isis/src/base/objs/ProcessPolygons/ProcessPolygons.truth @@ -0,0 +1,23 @@ +Testing Isis::ProcessPolygons Class ... +Filename: processPolygonsTest.cub +unittest: Working +0% Processed Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 4 +10% Processed Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 4 +20% Processed Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 4 +30% Processed Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 4 Band: 1 DN: 4 +40% Processed 50% Processed Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 5 +60% Processed Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 5 +70% Processed Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 5 +80% Processed Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 5 Band: 2 DN: 5 +90% Processed 100% Processed +Filename: processPolygonsTest_count.cub +unittest: Working +0% Processed Band: 1 DN: 16 Band: 1 DN: 16 Band: 1 DN: 16 Band: 1 DN: 16 +10% Processed Band: 1 DN: 16 Band: 1 DN: 16 Band: 1 DN: 16 Band: 1 DN: 16 +20% Processed Band: 1 DN: 16 Band: 1 DN: 16 Band: 1 DN: 16 Band: 1 DN: 16 +30% Processed Band: 1 DN: 16 Band: 1 DN: 16 Band: 1 DN: 16 Band: 1 DN: 16 +40% Processed 50% Processed Band: 2 DN: 16 Band: 2 DN: 16 Band: 2 DN: 16 Band: 2 DN: 16 +60% Processed Band: 2 DN: 16 Band: 2 DN: 16 Band: 2 DN: 16 Band: 2 DN: 16 +70% Processed Band: 2 DN: 16 Band: 2 DN: 16 Band: 2 DN: 16 Band: 2 DN: 16 +80% Processed Band: 2 DN: 16 Band: 2 DN: 16 Band: 2 DN: 16 Band: 2 DN: 16 +90% Processed 100% Processed diff --git a/isis/src/base/objs/ProcessPolygons/unitTest.cpp b/isis/src/base/objs/ProcessPolygons/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c43b49f6aae628e2830ee0da5f3fb2ed4f2a017 --- /dev/null +++ b/isis/src/base/objs/ProcessPolygons/unitTest.cpp @@ -0,0 +1,100 @@ +#include "Isis.h" +#include "ProcessPolygons.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "TextFile.h" + +using namespace Isis; +using namespace std; + +bool threeVectors(std::vector &samples, std::vector &lines, + std::vector &value); +bool oneBandOneValue(std::vector &samples, std::vector &lines, + int &band,double &value); +void writeAscii(Isis::Buffer &in); + +std::vector diamondSamples, diamondLines, values1, values2; +std::vector bands; + +void IsisMain() { + std::vector samples, lines, values; + + cout << "Testing Isis::ProcessPolygons Class ... " << endl; + ProcessPolygons p; + ProcessByLine pbl; + + CubeAttributeOutput out_atts; + out_atts.PixelType(Real); + + const string output1 = "processPolygonsTest.cub"; + const string output2 = "processPolygonsTest_count.cub"; + p.SetOutputCube(output1 , output2 , out_atts, 4, 4, 2); + + samples.clear(); + lines.clear(); + + double value = 0; + for (int b = 1; b<3; b++) { + for(int l = 0; l<4; l++) { + for(int s = 0; s<4; s++) { + + samples.push_back(s); + samples.push_back(s+5.0); + samples.push_back(s); + samples.push_back(s-5.0); + + lines.push_back(l-5.0); + lines.push_back(l); + lines.push_back(l+5.0); + lines.push_back(l); + value = s+l+b; + + p.Rasterize(samples, lines, b, value); + + samples.clear(); + lines.clear(); + } + } + } + + p.EndProcess(); + + + /* Write out the data */ + + CubeAttributeInput atts; + + cout << "Filename: " << output1 << endl; + pbl.SetInputCube(output1, atts, 0); + pbl.StartProcess(writeAscii); + pbl.EndProcess(); + + cout << "Filename: " << output2 << endl; + pbl.SetInputCube(output2, atts, 0); + pbl.StartProcess(writeAscii); + pbl.EndProcess(); + + remove(output1.c_str()); + remove(output2.c_str()); +} + +/** + * This method reads in the cube file line by line and prints + * out the DN value of each non-null pixel. + * + * @param in + */ +void writeAscii (Isis::Buffer &in) { + bool notNull= false; + int index = in.size() - 1; + for (int i=0; i 0) { + cout <<"Band: " << in.Band() << " DN: " << in[index -i] << " "; + notNull = true; + } + } + if(notNull) { + cout << std::endl; + } +} + diff --git a/isis/src/base/objs/ProcessPolygons/unitTest.xml b/isis/src/base/objs/ProcessPolygons/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..31db536a0b99207a5b377d910d44855fe728599b --- /dev/null +++ b/isis/src/base/objs/ProcessPolygons/unitTest.xml @@ -0,0 +1,17 @@ + + + + Unit test for Isis::ProcessPolygons class + + + Just a test only a test + + + Scripting + + + + Original Version + + + diff --git a/isis/src/base/objs/ProcessRubberSheet/Makefile b/isis/src/base/objs/ProcessRubberSheet/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..55f620c0cca1b57e7bc1300a9d33db9b385f1f21 --- /dev/null +++ b/isis/src/base/objs/ProcessRubberSheet/Makefile @@ -0,0 +1,5 @@ +INCS = ProcessRubberSheet.h +SRCS = ProcessRubberSheet.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProcessRubberSheet/ProcessRubberSheet.cpp b/isis/src/base/objs/ProcessRubberSheet/ProcessRubberSheet.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f4aef69b716e110777a63e2b2e4ac5f370ae26ee --- /dev/null +++ b/isis/src/base/objs/ProcessRubberSheet/ProcessRubberSheet.cpp @@ -0,0 +1,645 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2009/06/05 16:17:13 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "Portal.h" +#include "Transform.h" +#include "Interpolator.h" +#include "TileManager.h" +#include "ProcessRubberSheet.h" +#include "Portal.h" + +using namespace std; +namespace Isis { + /** + * Applies a Transform and an Interpolator to every pixel in the output cube. + * The output cube is written using an Tile and the input cube is read using + * a Portal. The input cube and output cube must be initialized prior to + * calling this method. Output pixels which come from outside the input cube + * are set to NULL8. + * + * @param trans A fully initialized Transform object. The Transform member of + * this object is used to calculate what input pixel location + * should be used to interpolate the output pixel value. + * + * @param interp A fully initialized Interpolator object. The Interpolate + * member of this object is used to calculate output pixel values. + * + * @throws Isis::iException::Message + */ + void ProcessRubberSheet::StartProcess (Isis::Transform &trans, + Isis::Interpolator &interp) { + // Error checks ... there must be one input and one output + if (InputCubes.size() != 1) { + string m = "You must specify exactly one input cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + else if (OutputCubes.size() != 1) { + string m = "You must specify exactly one output cube"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // allocate the sampMap/lineMap vectors + p_lineMap.resize(p_startQuadSize); + p_sampMap.resize(p_startQuadSize); + + for(unsigned int pos = 0; pos < p_lineMap.size(); pos++) { + p_lineMap[pos].resize(p_startQuadSize); + p_sampMap[pos].resize(p_startQuadSize); + } + + // Create a tile manager for the output file + Isis::TileManager otile (*OutputCubes[0], p_startQuadSize, p_startQuadSize); + + // Create a portal buffer for the input file + Isis::Portal iportal (interp.Samples(), interp.Lines(), + InputCubes[0]->PixelType() , + interp.HotSample(), interp.HotLine()); + + // Start the progress meter + p_progress->SetMaximumSteps (otile.Tiles()); + p_progress->CheckStatus(); + + if (p_bandChangeFunct == NULL) { + int tilesPerBand = otile.Tiles() / OutputCubes[0]->Bands(); + + for (int tile=1; tile<=tilesPerBand; tile++) { + bool useLastTileMap = false; + for (int band=1; band<=OutputCubes[0]->Bands(); band++) { + otile.SetTile(tile,band); + + if(p_startQuadSize == 2) { + SlowGeom (otile,iportal,trans,interp); + } + else { + QuadTree (otile,iportal,trans,interp,useLastTileMap); + } + + useLastTileMap = true; + + OutputCubes[0]->Write(otile); + p_progress->CheckStatus(); + } + } + } + else { + int lastOutputBand = -1; + + for (otile.begin(); !otile.end(); otile++) { + // Keep track of the current band + if (lastOutputBand != otile.Band()) { + lastOutputBand = otile.Band(); + // Call an application function if the band number changes + p_bandChangeFunct (lastOutputBand); + } + + if(p_startQuadSize == 2) { + SlowGeom (otile,iportal,trans,interp); + } + else { + QuadTree (otile,iportal,trans,interp,false); + } + + OutputCubes[0]->Write(otile); + p_progress->CheckStatus(); + } + } + + p_sampMap.clear(); + p_lineMap.clear(); + } + /** + * Registers a function to be called when the current output cube band number + * changes. This includes the first time. If and application does NOT need to + * be notified when the processing is about to proceed to the next band there + * is no need to call this member. The application function will not be called. + * + * @param funct (const int band) An application defined function which will be + * called every time the current band number + * changes. + */ + void ProcessRubberSheet::BandChange (void (*funct)(const int band)) { + p_bandChangeFunct = funct; + } + + void ProcessRubberSheet::SlowGeom(Isis::TileManager &otile, Isis::Portal &iportal, + Isis::Transform &trans, Isis::Interpolator &interp) { + double outputSamp, outputLine; + double inputSamp, inputLine; + int outputBand = otile.Band(); + + for (int i=0; i InputCubes[0]->Lines()+0.5) || + (inputSamp > InputCubes[0]->Samples()+0.5)) { + otile[i] = Isis::NULL8; + } + else { + // Set the position of the portal in the input cube + iportal.SetPosition (inputSamp, inputLine, outputBand); + InputCubes[0]->Read(iportal); + otile[i] = interp.Interpolate (inputSamp, inputLine, iportal.DoubleBuffer()); + } + } + else { + otile[i] = Isis::NULL8; + } + } + } + + void ProcessRubberSheet::QuadTree(Isis::TileManager &otile, Isis::Portal &iportal, + Isis::Transform &trans, Isis::Interpolator &interp, + bool useLastTileMap) { + // Initializations + vector quadTree; + + if (!useLastTileMap) { + // Set up the boundaries of the full tile + Quad *quad = new Quad; + quad->sline = otile.Line(); + quad->ssamp = otile.Sample(); + + quad->eline = otile.Line(otile.size()-1); + quad->esamp = otile.Sample(otile.size()-1); + quad->slineTile = otile.Line(); + quad->ssampTile = otile.Sample(); + + quadTree.push_back(quad); + + // Loop and compute the input coordinates filling the maps + // until the quad tree is empty + while (quadTree.size() > 0) { + ProcessQuad(quadTree,trans,p_lineMap,p_sampMap); + } + } + + // Apply the map to the output tile + int outputBand = otile.Band(); + for (int i=0, line=0; lineRead(iportal); + otile[i] = interp.Interpolate (inputSamp, inputLine, iportal.DoubleBuffer()); + } + else { + otile[i] = Isis::NULL8; + } + } + } + } + + + /** + * This function walks a line (or rectangle) and tests a point every increment pixels. If any of these + * points can transform, then this method will return true. Otherwise, this returns false. + * + * @param trans The Transform object to test on + * @param ssamp Starting Sample + * @param esamp Ending Sample + * @param sline Starting Line + * @param eline Ending Line + * @param increment The increment to step by while walking this line/rectangle + */ + bool ProcessRubberSheet::TestLine(Isis::Transform &trans, int ssamp, int esamp, int sline, int eline, int increment) { + for(int line = sline; line <= eline; line += increment) { + for(int sample = ssamp; sample <= esamp; sample += increment) { + double sjunk = 0.0; + double ljunk = 0.0; + + if(trans.Xform (sjunk, ljunk, sample, line)) { + return true; + } + } + } + + return false; + } + + // Process a quad trying to find input positions for output positions + void ProcessRubberSheet::ProcessQuad (std::vector &quadTree, Isis::Transform &trans, + std::vector< std::vector > &lineMap, + std::vector< std::vector > &sampMap) { + Quad *quad = quadTree[0]; + double oline[4],osamp[4]; + double iline[4],isamp[4]; + + // Try to convert the upper left corner to input coordinates + int badCorner = 0; + oline[0] = quad->sline; + osamp[0] = quad->ssamp; + if (!trans.Xform (isamp[0], iline[0], osamp[0], oline[0])) { + badCorner++; + } + + // Now try the upper right corner + oline[1] = quad->sline; + osamp[1] = quad->esamp; + if (!trans.Xform (isamp[1], iline[1], osamp[1], oline[1])) { + badCorner++; + } + + // Now try the lower left corner + oline[2] = quad->eline; + osamp[2] = quad->ssamp; + if (!trans.Xform (isamp[2], iline[2], osamp[2], oline[2])) { + badCorner++; + } + + // Now try the lower right corner + oline[3] = quad->eline; + osamp[3] = quad->esamp; + if (!trans.Xform (isamp[3], iline[3], osamp[3], oline[3])) { + badCorner++; + } + + // If all four corners are bad then walk the edges. If any points + // on the edges transform we will split the quad or + // if the quad is already small just transform everything + if (badCorner == 4) { + if ((quad->eline - quad->sline) < p_endQuadSize) { + SlowQuad(quadTree,trans,lineMap,sampMap); + } + else { + if (p_forceSamp != Isis::Null && p_forceLine != Isis::Null) { + if (p_forceSamp >= quad->ssamp && p_forceSamp <= quad->esamp && + p_forceLine >= quad->sline && p_forceLine <= quad->eline) { + SplitQuad(quadTree); + return; + } + } + + int centerSample = (quad->ssamp + quad->esamp) / 2; + int centerLine = (quad->sline + quad->eline) / 2; + + // All 4 corner points have failed tests. + // + // If we find data around the quad by walking around a 2x2 grid in the box, then + // we need to split the quad. Check outside the box and interior crosshair. + // + // This is what we're walking: + // ----------- + // | | | + // | | | + // |----|----| + // | | | + // | | | + // ----------- + // Top Edge + if(TestLine(trans, quad->ssamp+1, quad->esamp-1, quad->sline, quad->sline, 4) || + // Bottom Edge + TestLine(trans, quad->ssamp+1, quad->esamp-1, quad->eline, quad->eline, 4) || + // Left Edge + TestLine(trans, quad->ssamp, quad->ssamp, quad->sline+1, quad->eline-1, 4) || + // Right Edge + TestLine(trans, quad->esamp, quad->esamp, quad->sline+1, quad->eline-1, 4) || + // Center Column + TestLine(trans, centerSample, centerSample, quad->sline+1, quad->eline-1, 4) || + // Center Row + TestLine(trans, quad->ssamp+1, quad->esamp-1, centerLine, centerLine, 4)) { + + + SplitQuad(quadTree); + return; + } + + // Nothing in quad, fill with nulls + for (int i=quad->sline; i<=quad->eline; i++) { + for (int j=quad->ssamp; j<=quad->esamp; j++) { + lineMap[i-quad->slineTile][j-quad->ssampTile] = Isis::NULL8; + } + } + delete quad; + quadTree.erase(quadTree.begin()); + } + return; + } + + // If all four corners are bad then assume the whole tile is bad + // Load the maps with nulls and delete the quad from the list + // Free memory too + // if (badCorner == 4) { + // for (int i=quad->sline; i<=quad->eline; i++) { + // for (int j=quad->ssamp; j<=quad->esamp; j++) { + // lineMap[i-quad->slineTile][j-quad->ssampTile] = Isis::NULL8; + // } + // } + // delete quad; + // quadTree.erase(quadTree.begin()); + // return; + // } + + // See if any other corners are bad in which case we will need to + // split the quad into finer pieces. But lets not get ridiculous. + // If the split distance is small we might as well compute at every + // point + if (badCorner > 0) { + if ((quad->eline - quad->sline) < p_endQuadSize) { + SlowQuad(quadTree,trans,lineMap,sampMap); + } + else { + SplitQuad(quadTree); + } + return; + } + + // We have good corners ... create two equations using them + // iline = a*oline + b*osamp + c*oline*osamp + d + // isamp = e*oline + f*osamp + g*oline*osamp + h + // Start by setting up a 4x4 matrix + double A[4][4]; + for (int i=0; i<4; i++) { + A[i][0] = oline[i]; + A[i][1] = osamp[i]; + A[i][2] = oline[i] * osamp[i]; + A[i][3] = 1.0; + } + + // Make sure the determinate is non-zero, otherwise split it up again + // and hope for the best. If this happens it probably is because the + // transform is lame (bugged) + double detA; + if ((detA = Det4x4(A)) == 0.0) { + if ((quad->eline - quad->sline) < p_endQuadSize) { + SlowQuad(quadTree,trans,lineMap,sampMap); + } + else { + SplitQuad(quadTree); + } + return; + } + + // Substitute our desired answers into B to get the coefficients for the line + // dimension (Cramers Rule!!) + double B[4][4]; + double lineCoef[4]; + for (int j=0; j<4; j++) { + memmove (B,A,16*sizeof(double)); + + for (int i=0; i<4; i++) { + B[i][j] = iline[i]; + } + + lineCoef[j] = Det4x4(B) / detA; + } + + // Do it again to get the sample coefficients + double sampCoef[4]; + for (int j=0; j<4; j++) { + memmove (B,A,16*sizeof(double)); + + for (int i=0; i<4; i++) { + B[i][j] = isamp[i]; + } + + sampCoef[j] = Det4x4(B) / detA; + } + + // Test the middle point to see if the equations are good + double quadMidLine = (quad->sline + quad->eline) / 2.0; + double quadMidSamp = (quad->ssamp + quad->esamp) / 2.0; + double midLine,midSamp; + + if (!trans.Xform (midSamp, midLine, quadMidSamp, quadMidLine)) { + if ((quad->eline - quad->sline) < p_endQuadSize) { + SlowQuad(quadTree,trans,lineMap,sampMap); + } + else { + SplitQuad(quadTree); + } + return; + } + + double cmidLine = lineCoef[0] * quadMidLine + + lineCoef[1] * quadMidSamp + + lineCoef[2] * quadMidLine * quadMidSamp + + lineCoef[3]; + + double cmidSamp = sampCoef[0] * quadMidLine + + sampCoef[1] * quadMidSamp + + sampCoef[2] * quadMidLine * quadMidSamp + + sampCoef[3]; + + if ((abs(cmidSamp - midSamp) > 0.5) || (abs(cmidLine - midLine) > 0.5)) { + if ((quad->eline - quad->sline) < p_endQuadSize) { + SlowQuad(quadTree,trans,lineMap,sampMap); + } + else { + SplitQuad(quadTree); + } + return; + } + + // Equations are suitably accurate. + // First compute input at the top corner of the output quad + double ulLine = lineCoef[0] * (double) quad->sline + + lineCoef[1] * (double) quad->ssamp + + lineCoef[2] * (double) quad->sline * (double) quad->ssamp + + lineCoef[3]; + + double ulSamp = sampCoef[0] * (double) quad->sline + + sampCoef[1] * (double) quad->ssamp + + sampCoef[2] * (double) quad->sline * (double) quad->ssamp + + sampCoef[3]; + + // Compute the derivate of the equations with respect to the + // output line as we will be changing the output line in a loop + double lineChangeWrLine = lineCoef[0] + lineCoef[2] * (double) quad->ssamp; + double sampChangeWrLine = sampCoef[0] + sampCoef[2] * (double) quad->ssamp; + + for (int ol=quad->sline; ol<=quad->eline; ol++) { + // Now Compute the derivates of the equations with respect to the + // output sample at the current line + double lineChangeWrSamp = lineCoef[1] + lineCoef[2] * (double) ol; + double sampChangeWrSamp = sampCoef[1] + sampCoef[2] * (double) ol; + + // Set first computed line to the left-edge position + double cline = ulLine; + double csamp = ulSamp; + + // Get pointers to speed processing + int startSamp = quad->ssamp-quad->ssampTile; + std::vector &lineVect = lineMap[ol-quad->slineTile]; + std::vector &sampleVect = sampMap[ol-quad->slineTile]; + + // Loop computing input positions for respective output positions + for (int os=quad->ssamp; os<=quad->esamp; os++) { + lineVect[startSamp] = cline; + sampleVect[startSamp] = csamp; + + startSamp ++; + + cline += lineChangeWrSamp; + csamp += sampChangeWrSamp; + } + + // Reposition at the left edge of the tile for the next line + ulLine += lineChangeWrLine; + ulSamp += sampChangeWrLine; + } + + // All done so remove the quad + delete quad; + quadTree.erase(quadTree.begin()); + } + + // Break input quad into four pieces + void ProcessRubberSheet::SplitQuad (std::vector &quadTree) { + // Get the quad to split + Quad *quad = quadTree[0]; + int n = (quad->eline - quad->sline + 1) / 2; + + // New upper left quad + Quad *q1 = new Quad; + *q1 = *quad; + q1->eline = quad->sline + n - 1; + q1->esamp = quad->ssamp + n - 1; + quadTree.push_back(q1); + + // New upper right quad + Quad *q2 = new Quad; + *q2 = *quad; + q2->eline = quad->sline + n - 1; + q2->ssamp = quad->ssamp + n; + quadTree.push_back(q2); + + // New lower left quad + Quad *q3 = new Quad; + *q3 = *quad; + q3->sline = quad->sline + n; + q3->esamp = quad->ssamp + n - 1; + quadTree.push_back(q3); + + // New lower right quad + Quad *q4 = new Quad; + *q4 = *quad; + q4->sline = quad->sline + n; + q4->ssamp = quad->ssamp + n; + quadTree.push_back(q4); + + // Remove the old quad since it has been split up + delete quad; + quadTree.erase(quadTree.begin()); + } + + + // Slow quad computation for every output pixel + void ProcessRubberSheet::SlowQuad (std::vector &quadTree, Isis::Transform &trans, + std::vector< std::vector > &lineMap, + std::vector< std::vector > &sampMap) { + // Get the quad + Quad *quad = quadTree[0]; + double iline,isamp; + + // Loop and do the slow computation of input position from output position + for (int oline=quad->sline; oline<=quad->eline; oline++) { + int lineIndex = oline - quad->slineTile; + for (int osamp=quad->ssamp; osamp<=quad->esamp; osamp++) { + int sampIndex = osamp - quad->ssampTile; + lineMap[lineIndex][sampIndex] = Isis::NULL8; + if (trans.Xform (isamp, iline, (double) osamp, (double) oline)) { + if ((isamp >= 0.5) || + (iline >= 0.5) || + (iline <= InputCubes[0]->Lines()+0.5) || + (isamp <= InputCubes[0]->Samples()+0.5)) { + lineMap[lineIndex][sampIndex] = iline; + sampMap[lineIndex][sampIndex] = isamp; + } + } + } + } + + // All done with the quad + delete quad; + quadTree.erase(quadTree.begin()); + } + + // Determinate method for 4x4 matrix using cofactor expansion + double ProcessRubberSheet::Det4x4 (double m[4][4]) { + double cofact[3][3]; + + cofact [0][0] = m[1][1]; + cofact [0][1] = m[1][2]; + cofact [0][2] = m[1][3]; + cofact [1][0] = m[2][1]; + cofact [1][1] = m[2][2]; + cofact [1][2] = m[2][3]; + cofact [2][0] = m[3][1]; + cofact [2][1] = m[3][2]; + cofact [2][2] = m[3][3]; + double det = m[0][0] * Det3x3 (cofact); + + cofact [0][0] = m[1][0]; + cofact [0][1] = m[1][2]; + cofact [0][2] = m[1][3]; + cofact [1][0] = m[2][0]; + cofact [1][1] = m[2][2]; + cofact [1][2] = m[2][3]; + cofact [2][0] = m[3][0]; + cofact [2][1] = m[3][2]; + cofact [2][2] = m[3][3]; + det -= m[0][1] * Det3x3 (cofact); + + cofact [0][0] = m[1][0]; + cofact [0][1] = m[1][1]; + cofact [0][2] = m[1][3]; + cofact [1][0] = m[2][0]; + cofact [1][1] = m[2][1]; + cofact [1][2] = m[2][3]; + cofact [2][0] = m[3][0]; + cofact [2][1] = m[3][1]; + cofact [2][2] = m[3][3]; + det += m[0][2] * Det3x3 (cofact); + + cofact [0][0] = m[1][0]; + cofact [0][1] = m[1][1]; + cofact [0][2] = m[1][2]; + cofact [1][0] = m[2][0]; + cofact [1][1] = m[2][1]; + cofact [1][2] = m[2][2]; + cofact [2][0] = m[3][0]; + cofact [2][1] = m[3][1]; + cofact [2][2] = m[3][2]; + det -= m[0][3] * Det3x3 (cofact); + + return det; + } + + // Determinate for 3x3 matrix + double ProcessRubberSheet::Det3x3 (double m[3][3]) { + return m[0][0] * m[1][1] * m[2][2] - + m[0][0] * m[1][2] * m[2][1] - + m[0][1] * m[1][0] * m[2][2] + + m[0][1] * m[1][2] * m[2][0] + + m[0][2] * m[1][0] * m[2][1] - + m[0][2] * m[1][1] * m[2][0]; + } +} // end namespace isis diff --git a/isis/src/base/objs/ProcessRubberSheet/ProcessRubberSheet.h b/isis/src/base/objs/ProcessRubberSheet/ProcessRubberSheet.h new file mode 100644 index 0000000000000000000000000000000000000000..b839062b9f7b5a952978a6197df58e36bb0c8c63 --- /dev/null +++ b/isis/src/base/objs/ProcessRubberSheet/ProcessRubberSheet.h @@ -0,0 +1,174 @@ +#ifndef ProcessRubberSheet_h +#define ProcessRubberSheet_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2009/06/05 16:17:13 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Process.h" +#include "Buffer.h" +#include "Transform.h" +#include "Interpolator.h" +#include "Portal.h" +#include "TileManager.h" + +namespace Isis { +/** + * @brief Derivative of Process, designed for geometric transformations + * + * This is the processing class for geometric transformations of cube data. + * Objects of this class can be used to apply rubber sheet transformations from + * one space to another, such as converting from one map projection to another + * or from instrument space to ground space. Each pixel position in the output + * cube will be processed by querying a transformer to find what input pixel + * should be used and an interpolator to find the value of the pixel. Any + * application using this class must supply a Transform object and an + * Interpolator object. This class allows only one input cube and one output + * cube. + * + * @ingroup HighLevelCubeIO + * + * @author 2002-10-22 Stuart Sides + * + * @internal + * @history 2003-02-13 Stuart Sides - Created a unit test for the object. + * @history 2003-03-31 Stuart Sides - Added false argument to IsisError.report + * call in the unit test. + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-05-28 Stuart Sides - Added a new member function to allow an + * application to be notified when the + * current band number of the output cube + * changes (BandChange). + * @history 2003-10-23 Jeff Anderson - Modified StartProcess method to use a + * quadtree mechanism to speed processing + * of cubes. Essentially it generates an + * internalized file + * @history 2004-03-09 Stuart Sides - Modified quadtree mechanism to not give + * up on a quad unless none of the edge + * pixels transform. This needs to be + * refined even more. + * @history 2005-02-11 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2006-03-28 Tracie Sucharski - Modified the StartProcess to + * process multi-band cubes using the + * same tile map if there is no Band + * dependent function. + * @history 2006-04-04 Tracie Sucharski - Added ForceTile method and two + * private variables to hold the + * sample/line of the input cube position + * which will force tile containing that + * position to be processed in ProcessQuad + * even if all 4 corners of tile are bad. + * @history 2008-09-10 Steven Lambright - Made tiling start and end sizes + * variable + * @history 2009-05-21 Steven Lambright - A tiling hint starting at 2 will now + * automatically jump to doing a SlowGeom instead of not working/being + * a valid option. This fixes 2-line push frame cameras. + * @history 2008-10-30 Steven Lambright - Fixed problem with definition + * of class Quad, pointed out by "novus0x2a" (Support Board Member) + * @todo 2005-02-11 Stuart Sides - finish documentation and add coded and + * implementation example to class documentation + * @history 2009-06-05 Steven Lambright - Added TestLine(...) method and made the checking + * for inserting a null tile more strict (checks the outline of a 2x2 box instead + * of just the outline of the quad). + */ + + class ProcessRubberSheet : public Isis::Process { + public: + //! Constructs a RubberSheet object + ProcessRubberSheet(int startSize = 128, int endSize = 8) { + p_bandChangeFunct = NULL; + p_forceSamp = Isis::Null; + p_forceLine = Isis::Null; + p_startQuadSize = startSize; + p_endQuadSize = endSize; + }; + + //! Destroys the RubberSheet object. + ~ProcessRubberSheet() {}; + + // Line Processing method for one input and output cube + void StartProcess (Isis::Transform &trans, Isis::Interpolator &interp); + + // Register a function to be called when the band number changes + void BandChange (void (*funct)(const int band)); + + void ForceTile (double Samp,double Line) { + p_forceSamp = Samp; + p_forceLine = Line; + } + + /** + * This sets the start and end tile sizes for the rubber sheet; numbers are + * inclusive and must be powers of 2. + * + * @param start Start position; must be at least 4 and a power of 2 + * @param end End position; must be at least 4, a power of 2 and less than start + */ + void SetTiling(int start, int end) { + p_startQuadSize = start; + p_endQuadSize = end; + } + + private: + class Quad { + public: + int slineTile; + int ssampTile; + int sline; + int ssamp; + int eline; + int esamp; + }; + + void ProcessQuad (std::vector &quadTree, Isis::Transform &trans, + std::vector< std::vector > &lineMap, + std::vector< std::vector > &sampMap); + + void SplitQuad (std::vector &quadTree); + void SlowQuad (std::vector &quadTree, Isis::Transform &trans, + std::vector< std::vector > &lineMap, std::vector< std::vector > &sampMap); + double Det4x4 (double m[4][4]); + double Det3x3 (double m[3][3]); + + // SlowGeom method is never used but saved for posterity + void SlowGeom (Isis::TileManager &otile, Isis::Portal &iportal, + Isis::Transform &trans, Isis::Interpolator &interp); + void QuadTree (Isis::TileManager &otile, Isis::Portal &iportal, + Isis::Transform &trans, Isis::Interpolator &interp, + bool useLastTileMap); + + bool TestLine(Isis::Transform &trans, int ssamp, int esamp, int sline, int eline, int increment); + + void (*p_bandChangeFunct) (const int band); + + std::vector< std::vector > p_sampMap; + std::vector< std::vector > p_lineMap; + + double p_forceSamp; + double p_forceLine; + + int p_startQuadSize; + int p_endQuadSize; + }; +}; + +#endif diff --git a/isis/src/base/objs/ProcessRubberSheet/ProcessRubberSheet.truth b/isis/src/base/objs/ProcessRubberSheet/ProcessRubberSheet.truth new file mode 100644 index 0000000000000000000000000000000000000000..983b779f2d8486fa10b3c403e5ef4861c81d29f4 --- /dev/null +++ b/isis/src/base/objs/ProcessRubberSheet/ProcessRubberSheet.truth @@ -0,0 +1,62 @@ +Testing Isis::ProcessRubberSheet Class ... +unittest: Working +0% Processed The band changed to :1 +Output Sample:Line = 1:1 +Output Sample:Line = 128:1 +Output Sample:Line = 1:128 +Output Sample:Line = 128:128 +Output Sample:Line = 64.5:64.5 +Output Sample:Line = 1:1 +Output Sample:Line = 64:1 +Output Sample:Line = 1:64 +Output Sample:Line = 64:64 +Output Sample:Line = 32.5:32.5 +Output Sample:Line = 65:1 +Output Sample:Line = 128:1 +Output Sample:Line = 65:64 +Output Sample:Line = 128:64 +Output Sample:Line = 96.5:32.5 +Output Sample:Line = 1:65 +Output Sample:Line = 64:65 +Output Sample:Line = 1:128 +Output Sample:Line = 64:128 +Output Sample:Line = 32.5:96.5 +Output Sample:Line = 65:65 +Output Sample:Line = 128:65 +Output Sample:Line = 65:128 +Output Sample:Line = 128:128 +Output Sample:Line = 96.5:96.5 +10% Processed 20% Processed 30% Processed 40% Processed 50% Processed The band changed to :2 +Output Sample:Line = 1:1 +Output Sample:Line = 128:1 +Output Sample:Line = 1:128 +Output Sample:Line = 128:128 +Output Sample:Line = 64.5:64.5 +Output Sample:Line = 1:1 +Output Sample:Line = 64:1 +Output Sample:Line = 1:64 +Output Sample:Line = 64:64 +Output Sample:Line = 32.5:32.5 +Output Sample:Line = 65:1 +Output Sample:Line = 128:1 +Output Sample:Line = 65:64 +Output Sample:Line = 128:64 +Output Sample:Line = 96.5:32.5 +Output Sample:Line = 1:65 +Output Sample:Line = 64:65 +Output Sample:Line = 1:128 +Output Sample:Line = 64:128 +Output Sample:Line = 32.5:96.5 +Output Sample:Line = 65:65 +Output Sample:Line = 128:65 +Output Sample:Line = 65:128 +Output Sample:Line = 128:128 +Output Sample:Line = 96.5:96.5 +60% Processed 70% Processed 80% Processed 90% Processed 100% Processed + +Testing NO input with one output error ... +**PROGRAMMER ERROR** You must specify exactly one input cube + +Testing one input with NO output error ... +**PROGRAMMER ERROR** You must specify exactly one output cube + diff --git a/isis/src/base/objs/ProcessRubberSheet/unitTest.cpp b/isis/src/base/objs/ProcessRubberSheet/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5cd236ba2757c7243fab1db4ab3465f9615205ef --- /dev/null +++ b/isis/src/base/objs/ProcessRubberSheet/unitTest.cpp @@ -0,0 +1,102 @@ +#include "Isis.h" +#include "Transform.h" +#include "Interpolator.h" +#include "ProcessRubberSheet.h" + +using namespace std; +class UnitTestTrans : public Isis::Transform { + private: + int p_outSamps; + int p_outLines; + + public: + // constructor + UnitTestTrans (const int inSamps, const int inLines) { + p_outSamps = inSamps; + p_outLines = inLines; + }; + + // destructor + ~UnitTestTrans () {}; + + // Instantiation of pure virtual members + int OutputSamples () const {return p_outSamps;}; + int OutputLines () const {return p_outLines;}; + bool Xform (double &inSample, double &inLine, + const double outSample, + const double outLine) { + inSample = outSample; + if (outSample > 64) { + inSample = 127 - (outSample - 64); + } + + inLine = outLine; + + static int saveSamp = 0; + static int saveLine = 0; + if ((outSample != saveSamp+1) || (outLine != saveLine)) { + cout << "Output Sample:Line = " << outSample << ":" << outLine << endl; + saveSamp = (int)(outSample + 0.5); + saveLine = (int)(outLine + 0.5); + } + else { + saveSamp++; + } + + return true; + }; +}; + +void IsisMain() { + + Isis::Preference::Preferences(true); + + void myBandChange (const int b); + + Isis::ProcessRubberSheet p; + p.BandChange (myBandChange); + Isis::Transform *trans = new UnitTestTrans(126, 126); + + Isis::Interpolator *interp; + interp = new Isis::Interpolator(Isis::Interpolator::NearestNeighborType); + + cout << "Testing Isis::ProcessRubberSheet Class ... " << endl; + p.SetInputCube("FROM"); + p.SetOutputCube ("TO", 126, 126, 2); + p.StartProcess(*trans, *interp); + p.EndProcess(); + cout << endl; + + try { + cout << "Testing NO input with one output error ..." << endl; + p.SetOutputCube ("TO",1,1,1); + p.StartProcess (*trans, *interp); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + try { + cout << "Testing one input with NO output error ..." << endl; + p.SetInputCube ("FROM"); + p.StartProcess (*trans, *interp); + } + catch (Isis::iException &e) { + e.Report(false); + p.EndProcess(); + cout << endl; + } + + delete trans; + delete interp; + remove("/tmp/isisRubberSheet_01.cub"); +} + + +void myBandChange (const int band) { + cout << "The band changed to :" << band << endl; +} + + diff --git a/isis/src/base/objs/ProcessRubberSheet/unitTest.xml b/isis/src/base/objs/ProcessRubberSheet/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..eb9c27b53547b764a339e0c786ae0da4d231beab --- /dev/null +++ b/isis/src/base/objs/ProcessRubberSheet/unitTest.xml @@ -0,0 +1,58 @@ + + + + Unit test for IsisRubberSheet class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + Modified schema from astrogeology... isis.astrogeology... + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + $base/testData/isisTruth.cub + + + cube + output + real + + Test cube + + + Test cube + + + *.cub + + /tmp/isisRubberSheet_01.cub + + + + + diff --git a/isis/src/base/objs/Progress/Makefile b/isis/src/base/objs/Progress/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1b8098820bc2390c28bc7870dd25f683b322607c --- /dev/null +++ b/isis/src/base/objs/Progress/Makefile @@ -0,0 +1,5 @@ +INCS = Progress.h +SRCS = Progress.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Progress/Progress.cpp b/isis/src/base/objs/Progress/Progress.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d5fef573599dd3206cb3740bf09e66b0544d5b55 --- /dev/null +++ b/isis/src/base/objs/Progress/Progress.cpp @@ -0,0 +1,195 @@ +#include +#include +#include +#include +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/12/12 17:17:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Progress.h" +#include "Application.h" +#include "Preference.h" + +using namespace std; +namespace Isis { + /** + * Constructs a Progress object. + * + * @throws Isis::iException::User + */ + Progress::Progress () { + // Get user preferences + int percent; + bool printPercent; + Isis::PvlGroup &group = Isis::Preference::Preferences().FindGroup("UserInterface"); + percent = group["ProgressBarPercent"]; + Isis::iString temp = (string) group["ProgressBar"]; + printPercent = temp.UpCase() == "ON"; + + // Check for an error + if ((percent != 1) && (percent != 2) && + (percent != 5) && (percent != 10)) { + string m = "Invalid preference for [ProgressBarPercent] in "; + m += "group [UserInterface] must be 1, 2, 5, or 10"; + throw Isis::iException::Message(Isis::iException::User,m,_FILEINFO_); + } + + // Initialize private variables + p_text = "Working"; + p_maximumSteps = 0; + p_currentStep = 0; + p_currentPercent = 0; + p_percentIncrement = percent; + p_printPercent = printPercent; + } + + //! Destroys the Progress object + Progress::~Progress () { + } + + /** + * Changes the value of the text string reported just before 0% processed. This + * text is only output under the following condition. After SetMaximumSteps is + * called, the first call to CheckStatus will immediately output the text. By + * default this is set to "Working". + * + * @param text Text to output. + */ + void Progress::SetText(const std::string &text) { + p_text = text; + } + + /** + * Returns the text to output. Generally, this in not needed except rare + * circumstances where an application has multiple steps and the text string + * needs to be saved and restored. For an example, see the Histogram method in + * the CubeInfo class. + * + * @return string + */ + string Progress::Text () const { + return p_text; + } + + /** + * This sets the maximum number of steps in the process. Whenever this is + * invoked it also resets the counters to their initial states. This allows for + * programs which have multiple steps. + * + * @param steps Maximum number of steps + * + * @throws Isis::iException::Programmer Invalid value for step (must be >0) + */ + void Progress::SetMaximumSteps(const int steps) { + if (steps <= 0) { + string m = "Value for [steps] must be greater than "; + m += "zero in [Progress::SetMaximumSteps]"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + p_maximumSteps = steps; + p_currentStep = 0; + p_currentPercent = 0; + } + + /** + * Checks and updates the status. The first time this is invoked, it outputs + * the text from SetText and 0% processed. It should then be invoked for each + * step, for example, a step could be considered processing a line for NL lines + * in the image. If you do not call this enough times you will not reached 100% + * processed. + * + * @throws Isis::iException::Programmer Step exceeds maximumSteps + */ + void Progress::CheckStatus () { + // Error check + //std::cout << p_currentStep << " / " << p_maximumSteps << std::endl; + if (p_currentStep > p_maximumSteps) { + string m = "Step exceeds maximumSteps in [Progress::CheckStatus]"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + if (p_currentStep == 0) { + if (Isis::iApp != NULL) { + Isis::iApp->UpdateProgress(p_text,p_printPercent); + } + else { + if (p_printPercent) { + cout << p_text << endl; + } + } + } + + // See if the percent processed needs to be updated + while (100.0 * p_currentStep / p_maximumSteps >= p_currentPercent) { + if (Isis::iApp != NULL) { + Isis::iApp->UpdateProgress(p_currentPercent,p_printPercent); + } + else { + if (p_printPercent) { + if (p_currentPercent < 100) { + cout << p_currentPercent << "% Processed\r" << flush; + } + else { + cout << p_currentPercent << "% Processed" << endl; + } + } + } + p_currentPercent += p_percentIncrement; + } + + if (Isis::iApp != NULL) { + Isis::iApp->ProcessGuiEvents(); + } + + // Increment to the next step + p_currentStep++; + + return; + } + + /** + * If the initial step size was a guess, it can be modified using this method. + * For example, if you SetMaximumSteps(11) then call AddSteps(1) then the new + * MaximumSteps is 12. The progress bar will not go backwards (it will not drop + * from 10% to 5%). "steps" can be negative to remove steps. + * + * + * @param steps Amount to adjust the MaximumSteps by + */ + void Progress::AddSteps(const int steps) { + if (steps == 0) { + string m = "Value for [steps] must not be zero in [Progress::AddSteps]"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + p_maximumSteps += steps; + + if (p_currentStep > p_maximumSteps) { + string m = "Step exceeds maximumSteps in [Progress::AddSteps]"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + if (p_maximumSteps <= 0) { + string m = "Maximum steps must be greater than zero in [Progress::AddSteps]"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + } +} // end namespace isis diff --git a/isis/src/base/objs/Progress/Progress.h b/isis/src/base/objs/Progress/Progress.h new file mode 100644 index 0000000000000000000000000000000000000000..395ae4d215c2c29f2cafb4e46a498343925bd40a --- /dev/null +++ b/isis/src/base/objs/Progress/Progress.h @@ -0,0 +1,95 @@ +#ifndef Progress_h +#define Progress_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/12/12 17:17:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +namespace Isis { +/** + * @brief Program progress reporter + * + * This class is used to output the percent completion for programs in either + * the command line mode or the graphical user interface. Generally, this object + * is created within a Process derived class. Therefore you should only use this + * object if you are developing such a class. + * + * @ingroup ApplicationInterface + * + * @author 2002-05-22 Jeff Anderson + * + * @internal + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2004-02-29 Jeff Anderson - Added ability to send progress status to + * the parent process + * @history 2005-02-11 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-10-03 Elizabeth Miller - Changed @ingroup tag + * + * @todo 2005-02-11 Jeff Anderson - add coded and implementation example to + * class documentation + */ + + class Progress { + private: + std::string p_text; /** + +#include "Preference.h" +#include "Progress.h" +#include "iException.h" + +using namespace std; +int main () { + Isis::Preference &pref = Isis::Preference::Preferences(true); + Isis::PvlGroup &uip = pref.FindGroup("UserInterface"); + uip["ProgressBarPercent"] = 5; + Isis::Progress p; + + // Check normal operation + p.SetMaximumSteps(1000); + p.CheckStatus(); + for (int i=1; i<=1000; i++) p.CheckStatus(); + cout << endl; + + // Check again but test the text report + p.SetText("Drinking Coffee"); + p.SetMaximumSteps(5); + p.CheckStatus(); + for (int i=1; i<=5; i++) p.CheckStatus(); + cout << endl; + + // Check for error by going too many steps + try { + p.CheckStatus(); + } + catch (Isis::iException &e) { + e.Report (false); + } + + // Check for error on setting the Maximum Steps + try { + p.SetMaximumSteps(0); + } + catch (Isis::iException &e) { + e.Report(false); + } + + // Check for error on bad creation + try { + uip["ProgressBarPercent"] = 3; + Isis::Progress p2; + } + catch (Isis::iException &e) { + e.Report(false); + } +} diff --git a/isis/src/base/objs/Projection/Makefile b/isis/src/base/objs/Projection/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cb4598077e5708a7029bb289c5b31b1418d11c4e --- /dev/null +++ b/isis/src/base/objs/Projection/Makefile @@ -0,0 +1,5 @@ +INCS = Projection.h +SRCS = Projection.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Projection/Projection.cpp b/isis/src/base/objs/Projection/Projection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e4fd9f7e39bb20abe18671f2462c5cbd5242ecb7 --- /dev/null +++ b/isis/src/base/objs/Projection/Projection.cpp @@ -0,0 +1,1233 @@ +/** + * @file + * $Revision: 1.10 $ + * $Date: 2009/12/28 20:56:01 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include "naif/SpiceUsr.h" + +#include "Projection.h" +#include "iException.h" +#include "Constants.h" +#include "Filename.h" + +using namespace std; +namespace Isis { + /** + * Constructs an empty Projection object. + * + * @param label A PVL object containing map projection labels. These labels + * are fully described in the Isis Map Projection Users Guide. + * A brief example follows: + * @code + * Group = Mapping + * EquatorialRadius = 3396190.0 + * PolarRadius = 3376200.0 + * LongitudeDirection = PositiveEast + * LongitudeDomain = 360 + * LatitudeType = Planetographic + * MinimumLatitude = 10.8920539924144 + * MaximumLatitude = 34.7603960060206 + * MinimumLongitude = 219.72432466275 + * MaximumLongitude = 236.186050244411 + * PixelResolution = 1387.31209461362 + * ProjectionName = SimpleCylindrical + * CenterLongitude = 220.0 + * EndGroup + * End + * @endcode + * + * @throws Isis::iException::Projection + */ + Projection::Projection (Isis::Pvl &label) : p_mappingGrp("Mapping") { + try { + // Try to read the mapping group + p_mappingGrp = label.FindGroup ("Mapping",Isis::Pvl::Traverse); + + // Get the radii from the EquatorialRadius and PolarRadius keywords + if ((p_mappingGrp.HasKeyword("EquatorialRadius")) && + (p_mappingGrp.HasKeyword("PolarRadius"))) { + p_equatorialRadius = p_mappingGrp["EquatorialRadius"]; + p_polarRadius = p_mappingGrp["PolarRadius"]; + } + // Get the radii using the "TargetName" keyword and NAIF + else if (p_mappingGrp.HasKeyword("TargetName")) { + PvlGroup radii = TargetRadii ((string)p_mappingGrp["TargetName"]); + p_equatorialRadius = radii["EquatorialRadius"]; + p_polarRadius = radii["PolarRadius"]; + } + else { + string message = "No target radii available through keywords "; + message += "[EquatorialRadius and PolarRadius] or [TargetName]."; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + + // Check the radii for validity + if (p_equatorialRadius <= 0.0) { + string message = "Invalid value for keyword [EquatorialRadius] it must be "; + message += "greater than zero"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + if (p_polarRadius <= 0.0) { + string message = "Invalid value for keyword [PolarRadius] it must be "; + message += "greater than zero"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + + // Get the LatitudeType + if ((string) p_mappingGrp["LatitudeType"] == "Planetographic") { + p_latitudeType = Planetographic; + } + else if ((string) p_mappingGrp["LatitudeType"] == "Planetocentric") { + p_latitudeType = Planetocentric; + } + else { + string message = "Invalid value for keyword [LatitudeType] must be "; + message += "[Planetographic or Planetocentric]"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + + // Get the LongitudeDirection + if ((string) p_mappingGrp["LongitudeDirection"] == "PositiveWest") { + p_longitudeDirection = PositiveWest; + } + else if ((string) p_mappingGrp["LongitudeDirection"] == "PositiveEast") { + p_longitudeDirection = PositiveEast; + } + else { + string message = "Invalid value for keyword [LongitudeDirection] must be "; + message += "[PositiveWest or PositiveEast]"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + + // Get the LongitudeDomain + if ((string) p_mappingGrp["LongitudeDomain"] == "360") { + p_longitudeDomain = 360; + } + else if ((string) p_mappingGrp["LongitudeDomain"] == "180") { + p_longitudeDomain = 180; + } + else { + string message = "Invalid value for keyword [LongitudeDomain] must be "; + message += "[180 or 360]"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + + // Get the ground range if it exists + p_groundRangeGood = false; + if ((p_mappingGrp.HasKeyword("MinimumLatitude")) && + (p_mappingGrp.HasKeyword("MaximumLatitude")) && + (p_mappingGrp.HasKeyword("MinimumLongitude")) && + (p_mappingGrp.HasKeyword("MaximumLongitude"))) { + p_minimumLatitude = p_mappingGrp["MinimumLatitude"]; + p_maximumLatitude = p_mappingGrp["MaximumLatitude"]; + p_minimumLongitude = p_mappingGrp["MinimumLongitude"]; + p_maximumLongitude = p_mappingGrp["MaximumLongitude"]; + + if ((p_minimumLatitude < -90.0) || (p_minimumLatitude > 90.0)) { + string msg = "[MinimumLatitude] of [" + iString(p_minimumLatitude); + msg += "] is outside the range of [-90:90]"; + throw Isis::iException::Message(Isis::iException::Projection,msg,_FILEINFO_); + } + + if ((p_maximumLatitude < -90.0) || (p_maximumLatitude > 90.0)) { + string msg = "[MaximumLatitude] of [" + iString(p_maximumLatitude); + msg += "] is outside the range of [-90:90]"; + throw Isis::iException::Message(Isis::iException::Projection,msg,_FILEINFO_); + } + + if (p_minimumLatitude >= p_maximumLatitude) { + string msg = "[MinimumLatitude,MaximumLatitude] of [" + iString(p_minimumLatitude); + msg += + "," + iString(p_maximumLatitude) + "] are not "; + msg += "properly ordered"; + throw Isis::iException::Message(Isis::iException::Projection,msg,_FILEINFO_); + } + + if (p_minimumLongitude >= p_maximumLongitude) { + string msg = "[MinimumLongitude,MaximumLongitude] of [" + iString(p_minimumLongitude); + msg += + "," + iString(p_maximumLongitude) + "] are not "; + msg += "properly ordered"; + throw Isis::iException::Message(Isis::iException::Projection,msg,_FILEINFO_); + } + + p_groundRangeGood = true; + } + + // Get the map rotation + p_rotation = 0.0; + if (p_mappingGrp.HasKeyword("Rotation")) { + p_rotation = p_mappingGrp["Rotation"]; + } + + + // Initialize miscellaneous protected data elements + p_good = false; + + p_minimumX = DBL_MAX; + p_maximumX = -DBL_MAX; + p_minimumY = DBL_MAX; + p_maximumY = -DBL_MAX; + + p_eccentricity = 1.0 - + (p_polarRadius * p_polarRadius) / + (p_equatorialRadius * p_equatorialRadius); + p_eccentricity = sqrt(p_eccentricity); + + p_mapper = NULL; + + p_sky = false; + if (p_mappingGrp.HasKeyword("TargetName")) { + iString str = (string) p_mappingGrp["TargetName"]; + if (str.UpCase() == "SKY") p_sky = true; + } + } + catch (Isis::iException &e) { + string message = "Invalid label group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Projection,message,_FILEINFO_); + } + } + + /** + * This method is used to set a world coordinate. A world coordinate is a + * different coordinate type that has a one-to-one mapping to the projection + * coordinate system. For example, mapping pixel samples and lines to + * projection x's and y's. The Set forces an attempted calculation of the + * corresponding latitude/longitude position. This may or may not be successful + * and a status is returned as such. Note that is only applies if the + * Projection object was given an WorldMapper object during construction. If + * an WorldMapper was not supplied then SetWorld operates exactly the same as + * SetCoordinate (impling that world coordinate and projection coordinate are + * identical). + * + * @param worldX World X coordinate in units that are specified by the + * WorldMapper object (e.g., pixels, millimeters, etc) + * + * @param worldY World Y coordinate in units that are specified by the + * WorldMapper object (e.g., pixels, millimeters, etc) + * + * @return bool + */ + bool Projection::SetWorld(const double worldX, const double worldY) { + double projectionX; + double projectionY; + + if (p_mapper != NULL) { + projectionX = p_mapper->ProjectionX(worldX); + projectionY = p_mapper->ProjectionY(worldY); + } + else { + projectionX = worldX; + projectionY = worldY; + } + + return SetCoordinate(projectionX,projectionY); + } + + /** + * This returns the world X coordinate provided SetGround, SetCoordinate, + * SetUniversalGround, or SetWorld returned with success. Success can also be + * checked using the IsGood method. The units of X will be in the units as + * specified by the WorldMapper object which was given to the SetWorldMapper + * method. If a mapper object was not given then world coordinates are the same + * as the projection coordinates (i.e., WorldX and XCoord will return the same + * value). + * + * @return double + */ + double Projection::WorldX () const { + if (p_mapper != NULL) { + return p_mapper->WorldX(p_x); + } + else { + return p_x; + } + } + + /** + * This returns the world Y coordinate provided SetGround, SetCoordinate, + * SetUniversalGround, or SetWorld returned with success. Success can also be + * checked using the IsGood method. The units of Y will be in the units as + * specified by the WorldMapper object which was given to the SetWorldMapper. + * If a mapper object was not given then world coordinates are the same as the + * projection coordinates (i.e., WorldY and YCoord will return the same value). + * + * @return double + */ + double Projection::WorldY () const { + if (p_mapper != NULL) { + return p_mapper->WorldY(p_y); + } + else { + return p_y; + } + } + + /** + * This returns a universal longitude (positive east in 0 to 360 domain). The + * method can only be used if SetGround, SetCoordinate, SetUniversalGround, or + * SetWorld return with success. Success can also be checked using the IsGood + * method. + * + * @return double + */ + double Projection::UniversalLongitude() { + double lon = p_longitude; + if (p_longitudeDirection == PositiveWest) lon = -lon; + lon = To360Domain(lon); + return lon; + } + + /** + * This returns a universal latitude (planetocentric). The method can only be + * used if SetGround, SetCoordinate, SetUniversalGround, or SetWorld return + * with success. Success can also be checked using the IsGood method. + * + * @return double + */ + double Projection::UniversalLatitude() { + double lat = p_latitude; + if (p_latitudeType == Planetographic) lat = ToPlanetocentric(lat); + return lat; + } + + /** + * This method is used to set the latitude/longitude which must be + * Planetocentric (latitude) and PositiveEast/Domain360 (longitude). The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. + * + * @param lat Planetocentric Latitude value to project + * + * @param lon PositiveEast, Domain360 Longitude value to project + * + * @return bool + */ + bool Projection::SetUniversalGround (const double lat, const double lon) { + // Deal with the longitude first + p_longitude = lon; + if (p_longitudeDirection == PositiveWest) p_longitude = -lon; + if (p_longitudeDomain == 180) { + p_longitude = To180Domain(p_longitude); + } + else { + // Do this because longitudeDirection could cause (-360,0) + p_longitude = To360Domain(p_longitude); + } + + // Deal with the latitude + if (p_latitudeType == Planetographic) { + p_latitude = ToPlanetographic(lat); + } + else { + p_latitude = lat; + } + + // Now the lat/lon are in user defined coordinates so set them + return SetGround (p_latitude,p_longitude); + } + + /** + * This method converts a planetocentric latitude to a planetographic + * latitude. It utilizes the equatorial and polar radii to perform the + * computation. + * + * @param lat Planetocentric latitude to convert. + * + * @return double + */ + double Projection::ToPlanetographic(const double lat) const { + double mylat = lat; + if (abs(mylat) < 90.0) { // So tan doesn't fail + mylat *= Isis::PI / 180.0; + mylat = atan (tan(mylat) * (p_equatorialRadius / p_polarRadius) * + (p_equatorialRadius / p_polarRadius)); + mylat *= 180.0 / Isis::PI; + } + return mylat; + } + + /** + * This method converts a planetocentric latitude to a planetographic + * latitude. It is static so that a projection object does not need to + * exist. + * + * @param lat Planetocentric latitude to convert. + * @param eRadius Equatorial radius. + * @param pRadius Polar radius + * + * @return double + */ + double Projection::ToPlanetographic(double lat, + double eRadius, double pRadius) { + double mylat = lat; + if (abs(mylat) < 90.0) { // So tan doesn't fail + mylat *= Isis::PI / 180.0; + mylat = atan (tan(mylat) * (eRadius / pRadius) * + (eRadius / pRadius)); + mylat *= 180.0 / Isis::PI; + } + return mylat; + } + + /** + * This method converts a planetographic latitude to a planetocentric latitude. + * It utilizes the equatorial and polar radii to perform the computation. + * + * @param lat Planetographic latitude to convert. + * + * @return double + */ + double Projection::ToPlanetocentric(const double lat) const { + double mylat = lat; + if (abs(mylat) < 90.0) { // So tan doesn't fail + mylat *= Isis::PI / 180.0; + mylat = atan (tan(mylat) * (p_polarRadius / p_equatorialRadius) * + (p_polarRadius / p_equatorialRadius)); + mylat *= 180.0 / Isis::PI; + } + return mylat; + } + + /** + * This method converts a planetographic latitude to a planetocentric latitude. + * + * @param lat Planetographic latitude to convert. + * + * @return double + */ + double Projection::ToPlanetocentric(const double lat, + double eRadius, double pRadius) { + double mylat = lat; + if (abs(mylat) < 90.0) { // So tan doesn't fail + mylat *= Isis::PI / 180.0; + mylat = atan (tan(mylat) * (pRadius / eRadius) * + (pRadius / eRadius)); + mylat *= 180.0 / Isis::PI; + } + return mylat; + } + + /** + * This method converts a longitude into the 0 to 360 domain. It will leave the + * longitude unchanged if it is already in the domain. + * + * @return double + * + * @param lon Longitude to convert into the 0 to 360 domain. + */ + double Projection::To360Domain(const double lon) { + double mylon = lon; + while (mylon < 0.0) mylon += 360.0; + while (mylon > 360.0) mylon -= 360.0; + return mylon; + } + + /** + * This method converts a longitude into the -180 to 180 domain. It will leave + * the longitude unchanged if it is already in the domain. + * + * @return double + * + * @param lon Longitude to convert into the -180 to 180 domain. + */ + double Projection::To180Domain(const double lon) { + double mylon = lon; + while (mylon < -180.0) mylon += 360.0; + while (mylon > 180.0) mylon -= 360.0; + return mylon; + } + + /** + * This method converts a longitude into the positive east direction. + * + * @return double + * + * @param lon Longitude to convert into the positive east direction. + */ + double Projection::ToPositiveEast(const double lon, const int domain) { + double mylon = lon; + + mylon *= -1; + + if(domain == 360) { + mylon = To360Domain(mylon); + } + else if(domain == 180) { + mylon = To180Domain(mylon); + } + else { + iString err = "Domain ["; + err += domain; + err += "] is not 180 or 360."; + throw iException::Message(iException::Programmer, err, _FILEINFO_); + } + + return mylon; + } + + /** + * This method converts a longitude into the positive west direction. + * + * @return double + * + * @param lon Longitude to convert into the positive west direction. + */ + double Projection::ToPositiveWest(const double lon, const int domain) { + double mylon = lon; + + mylon *= -1; + + if(domain == 360) { + mylon = To360Domain(mylon); + } + else if(domain == 180) { + mylon = To180Domain(mylon); + } + else { + iString err = "Domain ["; + err += domain; + err += "] is not 180 or 360."; + throw iException::Message(iException::Programmer, err, _FILEINFO_); + } + + return mylon; + } + + /** + * This convience function is established to assist in the development of the + * XYRange virtual method. It allows the developer to test ground points + * (lat/lon) to see if they produce a minimum/maximum projection coordinate. + * For example in Sinusoidal, + * @code + * bool Sinusoidal::XYRange(double &minX, double &maxX, + * double &minY, double &maxY) { + * // Check the corners of the lat/lon range + * XYRangeCheck (p_minimumLatitude,p_minimumLongitude); + * XYRangeCheck (p_maximumLatitude,p_minimumLongitude); + * XYRangeCheck (p_minimumLatitude,p_maximumLongitude); + * XYRangeCheck (p_maximumLatitude,p_maximumLongitude); + * + * // If the latitude crosses the equator check there + * if ((p_minimumLatitude < 0.0) && (p_maximumLatitude > 0.0)) { + * XYRangeCheck (0.0,p_minimumLongitude); + * XYRangeCheck (0.0,p_maximumLongitude); + * } + * + * // Make sure everything is ordered + * if (p_minimumX >= p_maximumX) return false; + * if (p_minimumY >= p_maximumY) return false; + * + * // Return X/Y min/maxs + * minX = p_minimumX; + * maxX = p_maximumX; + * minY = p_minimumY; + * maxY = p_maximumY; + * return true; + * } + * @endcode + * + * + * @param latitude Test for min/max projection coordinates at this latitude + * + * @param longitude Test for min/max projection coordinates at this longitude + */ + void Projection::XYRangeCheck(const double latitude, const double longitude) { + SetGround(latitude,longitude); + if (!IsGood()) return; + + if (p_x < p_minimumX) p_minimumX = p_x; + if (p_x > p_maximumX) p_maximumX = p_x; + if (p_y < p_minimumY) p_minimumY = p_y; + if (p_y > p_maximumY) p_maximumY = p_y; + } + + /** + * This method returns the latitude type as a string. It will return either + * Planetocentric or Planetographic. + * + * @return string + */ + string Projection::LatitudeTypeString() const { + if (p_latitudeType == Planetographic) return "Planetographic"; + return "Planetocentric"; + } + + /** + * This method returns the longitude direction as a string. It will return + * either PositiveEast or PositiveWest. + * + * @return string + */ + string Projection::LongitudeDirectionString() const { + if (p_longitudeDirection == PositiveEast) return "PositiveEast"; + return "PositiveWest"; + } + + /** + * This method returns the longitude domain as a string. It will return either + * 180 or 360. + * + * @return string + */ + string Projection::LongitudeDomainString() const { + if (p_longitudeDomain == 360) return "360"; + return "180"; + } + + /** + * This method converts a projection x value to a world x value. For example, + * if the world coordinate system is an image then this method converts a + * projection x to a sample position. Note that if SetWorldMapper is not used + * then this routine simply returns the value of the argument. That is, no + * mapping occurs. + * + * @param projectionX Projection x value in meters + * + * @return double + */ + double Projection::ToWorldX (const double projectionX) const { + if (p_mapper != NULL) { + return p_mapper->WorldX(projectionX); + } + else { + return projectionX; + } + } + + /** + * This method converts a projection y value to a world y value. For example, + * if the world coordinate system is an image then this method converts a + * projection y to a line position. Note that if SetWorldMapper is not used + * then this routine simply returns the value of the argument. That is, no + * mapping occurs. + * + * @param projectionY Projection y value in meters + * + * @return double + */ + double Projection::ToWorldY (const double projectionY) const { + if (p_mapper != NULL) { + return p_mapper->WorldY(projectionY); + } + else { + return projectionY; + } + } + + /** + * This method converts a world x value to a projection x value. For example, + * if the world coordinate system is an image then this method converts a + * sample position to a projection x value. Note that if SetWorldMapper is not + * used then this routine simply returns the value of the argument. That is, + * no mapping occurs. + * + * @param worldX World x coordinate + * + * @return double + */ + double Projection::ToProjectionX (const double worldX) const { + if (p_mapper != NULL) { + return p_mapper->ProjectionX(worldX); + } + else { + return worldX; + } + } + + /** + * This method converts a world y value to a projection y value. For example, + * if the world coordinate system is an image then this method converts a line + * position to a projection y value. Note that if SetWorldMapper is not used + * then this routine simply returns the value of the argument. That is, no + * mapping occurs. + * + * @param worldY World y coordinate + * + * @return double + */ + double Projection::ToProjectionY (const double worldY) const { + if (p_mapper != NULL) { + return p_mapper->ProjectionY(worldY); + } + else { + return worldY; + } + } + + /** + * This method returns the resolution for mapping world coordinates into + * projection coordinates. For example, if the world coordinate system is an + * image then this routine returns the number of meters per pixel. Likewise, + * if the world coordinate system is a piece of paper, it might return the + * number of meters per inch of paper. If the SetWorldMapper method is not + * invoked then this method returns 1.0 + * + * @return double + */ + double Projection::Resolution () const { + if (p_mapper != NULL) { + return p_mapper->Resolution(); + } + else { + return 1.0; + } + } + + /** + * This method returns if two map projection objects are equal. That is, they + * have the same radii, latitude type, longitude direction, projection name, + * and projection specific parameters. + * + * @return bool + */ + bool Projection::operator== (const Projection &proj) { + if (this->EquatorialRadius() != proj.EquatorialRadius()) return false; + if (this->PolarRadius() != proj.PolarRadius()) return false; + if (this->IsPlanetocentric() != proj.IsPlanetocentric()) return false; + if (this->IsPositiveWest() != proj.IsPositiveWest()) return false; + if (this->Resolution() != proj.Resolution()) return false; + if (this->Name() != proj.Name()) return false; + return true; + } + + /** + * This method returns if two map projection objects are not equal. That is, they have at least + * some differences in the radii, latitude type, longitude direction, projection name, and + * projection specific parameters. + * + * @return bool + */ + bool Projection::operator!= (const Projection &proj) { + return !(*this == proj); + } + + /** + * This method returns the scale for mapping world coordinates into projection + * coordinates. For example, if the world coordinate system is an image then + * this routine returns the number of pixels per degree. Likewise, if the + * world coordinate system is a piece of paper, it might return the number of + * inches of paper per degree. If the SetWorldMapper method is not invoked + * then this method returns 1.0 + * + * @return double + */ + double Projection::Scale () const { + if (p_mapper != NULL) { + double lat = TrueScaleLatitude() * Isis::PI / 180.0; + double a = p_polarRadius * cos(lat); + double b = p_equatorialRadius * sin(lat); + double localRadius = p_equatorialRadius * p_polarRadius / + sqrt(a*a + b*b); + + return localRadius / p_mapper->Resolution(); + } + else { + return 1.0; + } + } + + /** + * This method returns the latitude of true scale. It is a virtual function and + * if it is not overriden the latitude of true scale is 0. Otherwise it is + * projection specific.For example, the center latitude for Mercator, + * Equidistant, or a parallel for conic projections. This method is used by the + * Scale routine to ensure the local radius is used in the computation. + * + * @return double + */ + double Projection::TrueScaleLatitude () const { + return 0.0; + } + + /** + * This function returns the keywords that this projection uses. + * + * @return PvlGroup The keywords that this projection uses + */ + PvlGroup Projection::Mapping() { + PvlGroup mapping("Mapping"); + + if(p_mappingGrp.HasKeyword("TargetName")) { + mapping += p_mappingGrp["TargetName"]; + } + + mapping += p_mappingGrp["ProjectionName"]; + mapping += p_mappingGrp["EquatorialRadius"]; + mapping += p_mappingGrp["PolarRadius"]; + mapping += p_mappingGrp["LatitudeType"]; + mapping += p_mappingGrp["LongitudeDirection"]; + mapping += p_mappingGrp["LongitudeDomain"]; + + if(HasGroundRange()) { + mapping += p_mappingGrp["MinimumLatitude"]; + mapping += p_mappingGrp["MaximumLatitude"]; + mapping += p_mappingGrp["MinimumLongitude"]; + mapping += p_mappingGrp["MaximumLongitude"]; + } + + if(p_mappingGrp.HasKeyword("Rotation")) { + mapping += p_mappingGrp["Rotation"]; + } + + return mapping; + } + + /** + * This function returns the latitude keywords that this projection uses + * + * @return PvlGroup The latitude keywords that this projection uses + */ + PvlGroup Projection::MappingLatitudes() { + PvlGroup mapping("Mapping"); + + if(HasGroundRange()) { + mapping += p_mappingGrp["MinimumLatitude"]; + mapping += p_mappingGrp["MaximumLatitude"]; + } + + return mapping; + } + + /** + * This function returns the longitude keywords that this projection uses + * + * @return PvlGroup The longitude keywords that this projection uses + */ + PvlGroup Projection::MappingLongitudes() { + PvlGroup mapping("Mapping"); + + if(HasGroundRange()) { + mapping += p_mappingGrp["MinimumLongitude"]; + mapping += p_mappingGrp["MaximumLongitude"]; + } + + return mapping; + } + + /** + * This method is used to set the latitude/longitude (assumed to be of the + * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. Usually this method + * is overridden in a dervied class, for example, Sinusoidal. If not the + * default method simply copies lat/lon to x/y which is no projection. + * + * @param lat Latitude value to project + * + * @param lon Longitude value to project + * + * @return bool + */ + bool Projection::SetGround (const double lat, const double lon) { + p_latitude = lat; + p_longitude = lon; + SetComputedXY(lon,lat); + return true; + } + + /** + * This method is used to set the projection x/y. The Set forces an attempted + * calculation of the corresponding latitude/longitude position. This may or + * may not be successful and a status is returned as such. Usually this method + * is overridden in a dervied class, for example, Sinusoidal. If not the + * default method simply copies x/y to lat/lon to x/y which is no projection. + * + * @param x X coordinate of the projection in units that are the same as the + * radii in the label + * + * @param y Y coordinate of the projection in units that are the same as the + * radii in the label + * + * @return bool + */ + bool Projection::SetCoordinate (const double x, const double y) { + SetXY(x,y); + p_latitude = p_y; + p_longitude = p_x; + return true; + } + + /** + * This method is used to determine the x/y range which completely covers the + * area of interest specified by the lat/lon range. The latitude/longitude + * range may be obtained from the labels. This method should not be used if + * HasGroundRange is false. The purpose of this method is to return the x/y + * range so it can be used to compute how large a map may need to be. For + * example, how big a piece of paper is needed or how large of an image needs + * to be created. This is method and therefore must be written by the derived + * class (e.g., Sinusoidal). The method may fail as indicated by its return + * value. + * + * @param minX Minimum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxX Maximum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param minY Minimum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxY Maximum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @return bool + */ + bool Projection::XYRange (double &minX,double &maxX,double &minY,double &maxY) { + if (p_groundRangeGood) { + minX = p_minimumLongitude; + maxX = p_maximumLongitude; + minY = p_minimumLatitude; + maxY = p_maximumLatitude; + return true; + } + return false; + } + + /** + * This method returns the local radius in meters at the current latitude + * position. This is only usable if the use of SetGround or SetCoordinate was + * successful. + * + * @return double + */ + double Projection::LocalRadius () const { + return LocalRadius(p_latitude); + } + + /** + * This method returns the local radius in meters at the specified latitude + * position. + * + * @param latitude A latitude in degrees (assumed to be of the correct + * LatitudeType). + * + * @return double + */ + double Projection::LocalRadius (double latitude) const { + double a = p_equatorialRadius; + double c = p_polarRadius; + double lat = latitude * Isis::PI / 180.0; + return a*c / sqrt(pow(c*cos(lat),2) + pow(a*sin(lat),2)); + } + + /** + * A convience method to compute m = cosphi/sqrt(1-(ecc*sinphi)**2) + * + * @param sinphi sine of phi + * + * @param cosphi cosine of phi + * + * @return double + */ + double Projection::mCompute(const double sinphi, const double cosphi) const { + double eccTimesSinphi = Eccentricity() * sinphi; + double denominator = sqrt(1.0 - eccTimesSinphi * eccTimesSinphi); + return cosphi / denominator; + } + + /** + * A convience method to compute e4 = sqrt(1+ecc)**(1+ecc)*(1-ecc)**(1-ecc)) + * + * @return double + */ + double Projection::e4Compute() const { + double onePlusEcc = 1.0 + Eccentricity(); + double oneMinusEcc = 1.0 - Eccentricity(); + + return sqrt(pow(onePlusEcc,onePlusEcc) * + pow(oneMinusEcc,oneMinusEcc)); + } + + /** + * A convience method to compute: + * t = tan(.5*(.5PI-phi)/((1-ecc*sinphi)/(1+ecc*sinphi))**(.5*ecc). + * + * @param phi phi + * + * @param sinphi sin of phi + * + * @return double + */ + double Projection::tCompute(const double phi, const double sinphi) const { + if ((Isis::HALFPI) - fabs(phi) < DBL_EPSILON) return 0.0; + + double eccTimesSinphi = Eccentricity() * sinphi; + double denominator = pow( (1.0 - eccTimesSinphi) / + (1.0 + eccTimesSinphi), + 0.5*Eccentricity() ); + return tan(0.5 * (Isis::HALFPI - phi)) / denominator; + } + + /** + * A convience method to compute latitude angle phi2 given small t + * + * @param t small t + * + * @return double + */ + double Projection::phi2Compute(const double t) const { + double localPhi = Isis::HALFPI - 2.0 * atan(t); + double halfEcc = 0.5 * Eccentricity(); + double difference = DBL_MAX; + int iteration = 0; + + while ((iteration < 15) && (difference > 0.0000000001)) { + double eccTimesSinphi = Eccentricity() * sin(localPhi); + double newPhi = Isis::HALFPI - + 2.0 * atan(t * pow((1.0-eccTimesSinphi) / + (1.0+eccTimesSinphi), halfEcc)); + difference = fabs(newPhi - localPhi); + localPhi = newPhi; + iteration++; + } + + if (iteration >= 15) { + string msg = "Failed to converge in Projection::tCompute"; + throw Isis::iException::Message(Isis::iException::Projection,msg,_FILEINFO_); + } + + return localPhi; + } + + /** + * Converts angle(in degrees) to hours + * + * @param angle Angle in degrees to be converted to hours + * + * @return double + */ + double Projection::ToHours(double angle) { + return angle/15.0; + } + + /** + * Converts angle(in degrees) to degrees, minutes, seconds. Outputs in + * the form xxx yym zz.zzzs, for example, 206.291 degrees is + * 206 17m 27.6s + * + * @param angle Angle in degrees to be converted to degrees, minutes, seconds + * + * @return string Degrees, minutes, seconds + */ + string Projection::ToDMS(double angle) { + int iangle = (int)angle; + double mins = abs(angle-iangle)*60.0; + int imins = (int)mins; + double secs = (mins-imins)*60.0; + int isecs = (int)secs; + double frac = (secs-isecs)*1000.0; + if (frac >= 1000.0) { + frac-=1000.0; + isecs++; + } + if (isecs >= 60) { + isecs-=60; + imins++; + } + if (imins >= 60) { + imins-=60; + iangle++; + } + stringstream s; + s << iangle << " " << setw(2) << setfill('0') + << imins << "m " << setw(2) << setfill('0') << isecs << "." << + setprecision(3) << frac << "s"; + return s.str(); + } + + /** + * Converts angle(in degrees) to hours, minutes, seconds. Outputs in + * the form xxh yym zz.zzzs For example, 206.291 will be + * 13h 45m 09.84s + * + * @param angle Angle in degrees to be converted to hours, minutes, seconds + * + * @return string Hours, minutes, seconds + */ + string Projection::ToHMS(double angle) { + double tangle = angle; + while (tangle < 0.0) tangle += 360.0; + while (tangle > 360.0) tangle -=360.0; + double hrs = ToHours(tangle); + int ihrs = (int)(hrs); + double mins = (hrs-ihrs)*60.0; + int imins = (int)(mins); + double secs = (mins-imins)*60.0; + int isecs = (int)(secs); + double msecs = (secs-isecs)*1000.0; + int imsecs = (int)(msecs + 0.5); + if (imsecs >= 1000) { + imsecs-=1000; + isecs++; + } + if (isecs >= 60) { + isecs-=60; + imins++; + } + if (imins >= 60) { + imins-=60; + ihrs++; + } + stringstream s; + s << setw(2) << setfill('0') << ihrs << "h " << setw(2) << setfill('0') << + imins << "m " < +#include "Pvl.h" +#include "WorldMapper.h" + +namespace Isis { + /** + * + * + * @brief Base class for Map Projections + * + * This is a virtual base class for map projections. It must be used to create + * specific map projection classes such as Sinusoidal, Mercator, etc. The + * foundation of this class is the ability to convert ground coordinates + * (latitude and longitude) into projection coordinates (x and y) and vice + * versa. Options exist to allow conversion to and from programmer specified + * world coordinates. The world coordinates can be cube pixels, paper units in + * millimeters, or any other unit the program may need. Generally, you should + * never directly instantiate this class. + * + * Here is an example of how to use Projection + * @code + * Pvl lab; + * lab.Read("projection.map"); + * Projection *p = ProjectionFactory::Create(lab); + * @endcode + * If you would like to see Projection being used in implementation, + * see mappos.cpp + * @ingroup MapProjection + * @author 2003-01-29 Jeff Anderson + * @internal + * @history 2003-01-30 Jeff Anderson - Add the SetWorldMapper method and + * removed setting the mapper from the + * constructor + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-05-30 Jeff Anderson - Updated unit test to fix error for + * optimization + * @history 2003-08-25 Jeff Anderson - Added LatitudeTypeString, + * LongitudeDirectionString, and + * LongitudeDomainString methods + * @history 2003-09-26 Jeff Anderson - Added ToWorldX, ToWorldY, + * ToProjectionX, ToProjectionY, + * and Resolution methods + * @history 2003-09-26 Jeff Anderson - Added virtual Name, operator==, and + * operator!= methods + * @history 2003-09-26 Jeff Anderson - Remove virtual from operator!= + * @history 2003-10-14 Jeff Anderson - Added Scale and TrueScaleLatitude + * methods + * @history 2003-11-04 Jeff Anderson - Replace the pure virtual methods for + * SetGround and SetCoordinate with + * virtual method which simply copy + * lat/lon to x/y and vice versa. This is + * essentially no projection. + * @history 2003-11-04 Jeff Anderson - Added LocalRadius methods + * @history 2004-02-23 Jeff Anderson - Added Eccentricity, tCompute, mCompute, + * e4Compute, and phi2Compute methods + * @history 2004-02-24 Jeff Anderson - Fixed bug in eccentricity computation + * @history 2005-02-11 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-02-25 Elizabeth Ribelin - Added 3 static conversion methods: + * ToHours(), ToDMS(), and ToHMS() + * @history 2005-03-08 Elizabeth Ribelin - Fixed unitTest + * @history 2005-06-24 Jeff Anderson - Tweaked format for DMS and HMS methods + * @history 2005-07-22 Jeff Anderson - Added static ToPlanetographic method + * @history 2006-04-20 Tracie Sucharski - Fixed bug looking at Target instead + * of TargetName for sky. + * @history 2006-06-20 Stuart Sides - Added ability to lookup the radii if given + * a "TargetName" in the mapping group. + * @history 2006-07-10 Elizabeth Miller - Fixed bugs in new static method + * @history 2007-06-27 Steven Lambright - Added static ToPlanetocentric, + * ToPositiveWest and ToPositiveEast methods. + * Changed To180Domain and To360Domain to be static + * instead of const. Added Mapping(), MappingLatitudes() and + * MappingLongitudes() methods for map2map. + * @history 2007-08-14 Steven Lambright - Mapping() fixed: should not return cube specific parameters, because + * they did not go into making the projection. + * @history 2008-05-09 Steven Lambright - Added Name, Version, IsEquatorialCylindrical methods + * @history 2008-06-12 Christopher Austin - Elaborated error messages. + * @history 2008-06-19 Steven Lambright - Fixed memory leak + * @history 2009-01-29 Stacy Alley - added a overloaded STATIC + * method for convenience. TargetRadii, which takes + * a Pvl, the cube label, and a PvlGroup, a mapping + * group. + * + */ + class Projection { + public: + // constructor + Projection (Isis::Pvl &label); + + //! Destroys the Projection object + virtual ~Projection () { if(p_mapper) delete p_mapper; }; + + /** + * If desired the programmer can use this method to set a world mapper to + * be used in the SetWorld, WorldX, and WorldY methods. Mappers typically + * transform a projection coordinate (x/y) into the desired working + * coordinate system, for example, cube pixels or inches on a piece of + * paper. They transform in both directions (world to projection and + * projection to world). This allows for conversions from line/sample to + * latitude/longitude and vice versa. This projection will take ownership + * of the WorldMapper pointer. + * + * @param mapper Pointer to the mapper + */ + void SetWorldMapper(Isis::WorldMapper *mapper) { p_mapper = mapper; }; + + // Set world position + bool SetWorld (const double x, const double y); + + // Set ground position + virtual bool SetGround (const double lat, const double lon); + + // Set x/y coordinate + virtual bool SetCoordinate (const double x, const double y); + + /** + * This indicates if the last invocation of SetGround, SetCoordinate, or + * SetUniversalGround was with successful or not. If there was success then + * the Latitude, Longitude, XCoord, YCoord, UniversalLatitude, + * UniversalLongitude, WorldX, and WorldY methods can be utilized. + * + * @return bool + */ + inline bool IsGood() const { return p_good; }; + + // Return computed world X/Y after successful SetGround + double WorldX() const; + double WorldY() const; + + /** + * This returns a longitude with correct longitude direction and domain as + * specified in the label object. The method can only be used if SetGround, + * SetCoordinate, SetUniversalGround, or SetWorld return with success. + * Success can also be checked using the IsGood method. + * + * @return double + */ + inline double Longitude() const { return p_longitude; }; + + /** + * This returns a latitude with correct latitude type as specified in the + * label object. The method can only be used if SetGround, SetCoordinate, + * SetUniversalGround, or SetWorld return with success. Success can also + * be checked using the IsGood method. + * + * @return double + */ + inline double Latitude() const { return p_latitude; }; + + /** + * This returns the projection X provided SetGround, SetCoordinate, + * SetUniversalGround, or SetWorld returned with success. Success can also + * be checked using the IsGood method. The units of X will be in the same . + * units as the radii obtained from the label. + * + * @return double + */ + inline double XCoord() const { return p_x; }; + + + /** + * This returns the projection Y provided SetGround, SetCoordinate, + * SetUniversalGround, or SetWorld returned with success. Success can also + * be checked using the IsGood method. The units of Y will be in the same + * units as the radii obtained from the label. + * + * @return double + */ + inline double YCoord() const { return p_y; }; + + /** + * This returns the equatorial radius of the target. The radius was + * obtained from the label during object construction. + * + * @return double + */ + inline double EquatorialRadius() const { return p_equatorialRadius; }; + + /** + * This returns the polar radius of the target. The radius was obtained + * from the label during object construction. + * + * @return double + */ + inline double PolarRadius() const { return p_polarRadius; }; + + + /** + * This returns the eccentricity of the target + * + * @return double + */ + inline double Eccentricity() const { return p_eccentricity; }; + + // Obtain latitude type + enum LatitudeType { Planetographic, Planetocentric }; + + /** + * This indicates if the latitude type is planetographic (as opposed to + * planetocentric). The latitude type was obtained from the label during + * object construction. + * + * @return bool + */ + inline bool IsPlanetographic() const { return p_latitudeType == Planetographic; }; + + + /** + * This indicates if the latitude type is planetocentric (as opposed to + * planetographic). The latitude type was obtained from the label during + * object construction. + * + * @return bool + */ + inline bool IsPlanetocentric() const { return p_latitudeType == Planetocentric; }; + + // Obtain latitude type as a string + std::string LatitudeTypeString () const; + + // Obtain longitude directions as a string + std::string LongitudeDirectionString () const; + + // Obtain longitude domain as a string + std::string LongitudeDomainString () const; + + // Obtain longitude direction + enum LongitudeDirection { PositiveEast, PositiveWest }; + + /** + * This indicates if the longitude direction type is positive east (as + * opposed to postive west). The longitude type was obtained from the label + * during object construction. + * + * @return bool + */ + inline bool IsPositiveWest() const { return p_longitudeDirection == PositiveWest; }; + + /** + * This indicates if the longitude direction type is positive west (as + * opposed to postive east). The longitude type was obtained from the label + * during object construction. + * + * @return bool + */ + inline bool IsPositiveEast() const { return p_longitudeDirection == PositiveEast; }; + + /** + * This indicates if the longitude domain is 0 to 360 (as opposed to -180 + * to 180). The longitude domain was obtained from the label during object + * construction. + * + * @return bool + */ + inline bool Has360Domain () const { return p_longitudeDomain == 360; }; + + + /** + * This indicates if the longitude domain is -180 to 180 (as opposed to 0 + * to 360). The longitude domain was obtained from the label during object + * construction. + * + * @return bool + */ + inline bool Has180Domain () const { return p_longitudeDomain == 180; }; + + /** + * This indicates that the labels contained minimum and maximum latitudes + * and longitudes (e.g., a ground range coverage). If the projection has + * ground range coverage then the MinimumLatitude, MaximumLatitude, + * MinimumLongitude, and MaximumLongitude methods can be used. The ground + * range coverage essentially defines the area of user interest. + * + * @return bool + */ + inline bool HasGroundRange() const { return p_groundRangeGood; }; + + /** + * This returns the minimum latitude of the area of interest. The value was + * obtained from the labels during object construction. This method can + * only be used if HasGroundRange returns a true. + * + * @return double + */ + inline double MinimumLatitude() const { return p_minimumLatitude; }; + + /** + * This returns the maximum latitude of the area of interest. The value was + * obtained from the labels during object construction. This method can + * only be used if HasGroundRange returns a true. + * + * @return double + */ + inline double MaximumLatitude() const { return p_maximumLatitude; }; + + /** + * This returns the minimum longitude of the area of interest. The value + * was obtained from the labels during object construction. This method can + * only be used if HasGroundRange returns a true. + * + * @return double + */ + inline double MinimumLongitude() const { return p_minimumLongitude; }; + + /** + * This returns the maximum longitude of the area of interest. The value + * was obtained from the labels during object construction. This method can + * only be used if HasGroundRange returns a true. + * + * @return double + */ + inline double MaximumLongitude() const { return p_maximumLongitude; }; + + // Return the x/y range which covers the lat/lon range in the labels + virtual bool XYRange (double &minX,double &maxX,double &minY,double &maxY); + + + /** + * Return the rotation of the map + * + * @return double + */ + inline double Rotation() const { return p_rotation; }; + + // Return the universal ground coordinate after successful SetCoordinate + double UniversalLatitude(); + double UniversalLongitude(); + + // Set the universal ground coordinate + bool SetUniversalGround (const double lat, const double lon); + + // Convert latitude value from Planetographic to Planetocentric and vice versa + double ToPlanetocentric (const double lat) const; + double ToPlanetographic (const double lat) const; + + // Convert longitude value from (0:360) to (-180:180) or vice versa + static double To360Domain (const double lon); + static double To180Domain (const double lon); + + // Convert longitude value from positive east to positive west or vice verse + static double ToPositiveEast (const double lon, const int domain); + static double ToPositiveWest (const double lon, const int domain); + + double ToWorldX (const double projectionX) const; + double ToWorldY (const double projectionY) const; + double ToProjectionX (const double worldX) const; + double ToProjectionY (const double worldY) const; + double Resolution () const; + double Scale () const; + virtual double TrueScaleLatitude () const; + virtual PvlGroup Mapping(); + virtual PvlGroup MappingLatitudes(); + virtual PvlGroup MappingLongitudes(); + + virtual bool operator== (const Projection &proj); + bool operator!= (const Projection &proj); + + /** + * This method returns true if the projection is + * equatorial cylindrical. In other words, if an image + * projected at 0 is the same as an image projected at 360. + * + * + * @return bool true if the projection is equatorial cylindrical + */ + virtual bool IsEquatorialCylindrical() { return false; } + + /** + * This method returns the name of the map projection + * + * @return string + */ + virtual std::string Name () const = 0; + virtual std::string Version () const = 0; + + double LocalRadius () const; + double LocalRadius (double lat) const; + + //! Returns true if projection is sky and false if it is land + bool IsSky () const { return p_sky; }; + + // Static conversion methods + static double ToHours(double angle); + static std::string ToDMS(double angle); + static std::string ToHMS(double angle); + static double ToPlanetographic(double lat, + double eRadius, double pRadius); + static double ToPlanetocentric(double lat, + double eRadius, double pRadius); + static PvlGroup TargetRadii (std::string target); + static PvlGroup TargetRadii (Pvl &cubeLab, PvlGroup &mapGroup); + + protected: + Isis::WorldMapper *p_mapper; /** +Mars polar radius: PolarRadius = 3376200.0 +Rotation Tests +Rotation: 90 +Testing Ground coordinate routines +Setting latitude to (-91, 0): 0 +Is Good: 0 +Setting latitude to ( 91, 0): 0 +Is Good: 0 +Setting position to (60, -5): 1 +Is Good: 1 +Latitude: 60 +Longitude: -5 +XCoord: 150 +YCoord: 50 +UniversalLatitude: 57.39200572938 +UniversalLongitude: 355 + +Testing projection coordinate routines +Setting x/y position to (150,50): 1 +Is Good: 1 +Latitude: 60 +Longitude: -5 +XCoord: 150 +YCoord: 50 +UniversalLatitude: 57.39200572938 +UniversalLongitude: 355 +WorldX: 150 +WorldY: 50 + +Testing Mapping() methods +Mapping() = +Group = Mapping + TargetName = SKY + ProjectionName = MyProjection + EquatorialRadius = 1.0 + PolarRadius = 0.95 + LatitudeType = Planetographic + LongitudeDirection = PositiveEast + LongitudeDomain = 180 + MinimumLatitude = 45.0 + MaximumLatitude = 80.0 + MinimumLongitude = 15.0 + MaximumLongitude = 190.0 + Rotation = 90.0 +End_Group +End +MappingLatitudes() = +Group = Mapping + MinimumLatitude = 45.0 + MaximumLatitude = 80.0 +End_Group +End +MappingLongitudes() = +Group = Mapping + MinimumLongitude = 15.0 + MaximumLongitude = 190.0 +End_Group +End + diff --git a/isis/src/base/objs/Projection/unitTest.cpp b/isis/src/base/objs/Projection/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c5b212de9199c81f6e7cc1086eb39d2ebe37e1a9 --- /dev/null +++ b/isis/src/base/objs/Projection/unitTest.cpp @@ -0,0 +1,447 @@ +#include +#include +#include +#include +#include "Projection.h" +#include "iException.h" +#include "WorldMapper.h" +#include "Constants.h" +#include "PvlGroup.h" +#include "Preference.h" + +using namespace std; +class MyProjection : public Isis::Projection { + public: + MyProjection (Isis::Pvl &lab) : + Isis::Projection (lab) { + } + bool XYRange(double &minX, double &maxX, double &minY, double &maxY) { + minX = DBL_MAX; + minY = DBL_MAX; + maxX = -DBL_MAX; + maxY = -DBL_MAX; + if (!p_groundRangeGood) return false; + XYRangeCheck(p_minimumLatitude,p_minimumLongitude); + XYRangeCheck(p_minimumLatitude,p_maximumLongitude); + XYRangeCheck(p_maximumLatitude,p_minimumLongitude); + XYRangeCheck(p_maximumLatitude,p_maximumLongitude); + minX = p_minimumX; + minY = p_minimumY; + maxX = p_maximumX; + maxY = p_maximumY; + return true; + } + bool SetGround(const double lat, const double lon) { + if ((lat < -90.0) || (lat > 90.0)) { + p_good = false; + } + else { + p_latitude = lat; + p_longitude = lon; + double x = lon * 10.0; + double y = lat + 90.0; + SetComputedXY(x,y); + p_good = true; + } + return p_good; + } + virtual bool SetCoordinate(const double x, const double y) { + SetXY(x,y); + p_longitude = GetX() / 10.0; + p_latitude = GetY() - 90.0; + p_good = true; + return p_good; + } + + virtual double TrueScaleLatitude() const { + return 45.0; + } + + std::string Name() const { return "None"; } + std::string Version() const { return "1.0"; } + + void Output() const { + cout << tCompute(0.0,0.0) << endl; + cout << tCompute(Isis::HALFPI/2.0,sin(Isis::HALFPI/2.0)) << endl; + cout << tCompute(Isis::HALFPI,sin(Isis::HALFPI)) << endl; + cout << mCompute(sin(0.0),cos(0.0)) << endl; + cout << mCompute(sin(Isis::HALFPI/2.0),cos(Isis::HALFPI/2.0)) << endl; + cout << e4Compute() << endl; + cout << phi2Compute(0.0) << endl; + cout << phi2Compute(10.0) << endl; + cout << phi2Compute(100.0) << endl; + cout << phi2Compute(1000.0) << endl; + } +}; + +class EmptyProjection : public Isis::Projection { + public: + EmptyProjection (Isis::Pvl &lab) : + Isis::Projection (lab) { + } + + std::string Name() const { return "None"; } + std::string Version() const { return "1.0"; } +}; + + +class MyMapper : public Isis::WorldMapper { + public: + MyMapper() : Isis::WorldMapper() {}; + double ProjectionX(const double worldX) const { return worldX / 2.0; }; + double ProjectionY(const double worldY) const { return worldY / 3.0; }; + double WorldX(const double projectionX) const { return projectionX * 2.0; }; + double WorldY(const double projectionY) const { return projectionY * 3.0; }; + virtual double Resolution() const { return 0.5; } +}; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + void Doit(Isis::Pvl &lab); + + cout.precision(13); + cout << "Unit test for Isis::Projection ..." << endl << endl; + + cout << "Test for missing Mapping Group" << endl; + Isis::Pvl lab; + Doit(lab); + cout << endl; + + cout << "Test for missing Equatorial Radius" << endl; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mg = lab.FindGroup("Mapping"); + Doit(lab); + cout << endl; + + cout << "Test for missing polar radius" << endl; + mg += Isis::PvlKeyword("EquatorialRadius", -1.0); + Doit(lab); + cout << endl; + + cout << "Test for invalid Equatoral Radius" << endl; + mg += Isis::PvlKeyword("PolarRadius",-0.95); + Doit(lab); + cout << endl; + + cout << "Test for invalid polar radius" << endl; + mg["EquatorialRadius"] = 1.0; + mg += Isis::PvlKeyword("PolarRadius",-0.95); + Doit(lab); + cout << endl; + + cout << "Test for missing latitude type" << endl; + mg["PolarRadius"] = 0.95; + Doit(lab); + cout << endl; + + cout << "Test for invalid latitude type" << endl; + mg += Isis::PvlKeyword("LatitudeType","Planeto"); + Doit(lab); + cout << endl; + + cout << "Test for missing longitude direction" << endl; + mg["LatitudeType"] = "Planetographic"; + Doit(lab); + cout << endl; + + cout << "Test for invalid longitude direction" << endl; + mg += Isis::PvlKeyword("LongitudeDirection","Up"); + Doit(lab); + cout << endl; + + cout << "Test for missing longitude domain" << endl; + mg["LongitudeDirection"] = "PositiveEast"; + Doit(lab); + cout << endl; + + cout << "Test for invalid longitude domain" << endl; + mg += Isis::PvlKeyword("LongitudeDomain",75); + Doit(lab); + cout << endl; + mg["LongitudeDomain"] = 360; + + mg += Isis::PvlKeyword("ProjectionName", "MyProjection"); + + cout << "Projection Specifications" << endl; + MyProjection p(lab); + cout << "Equatorial Radius: " << p.EquatorialRadius() << endl; + cout << "Polar Radius: " << p.PolarRadius() << endl; + cout << "Eccentricity: " << p.Eccentricity() << endl; + cout << "Is Planetographic: " << p.IsPlanetographic() << endl; + cout << "Is Planetocentric: " << p.IsPlanetocentric() << endl; + cout << "Is PositiveEast: " << p.IsPositiveEast() << endl; + cout << "Is PositiveWest: " << p.IsPositiveWest() << endl; + cout << "Has 360 domain: " << p.Has360Domain() << endl; + cout << "Has 180 domain: " << p.Has180Domain() << endl; + cout << "Has ground range: " << p.HasGroundRange() << endl; + cout << "Rotation: " << p.Rotation() << endl; + cout << endl; + + cout << "Testing conversion methods" << endl; + cout << "Bring -50 into 360 Domain: " << p.To360Domain(-50.0) << endl; + cout << "Bring 50 into 360 Domain: " << p.To360Domain(50.0) << endl; + cout << "Bring 0 into 360 Domain: " << p.To360Domain(0.0) << endl; + cout << "Bring 360 into 360 Domain: " << p.To360Domain(360.0) << endl << endl; + cout << "Bring 240 into 180 Domain: " << p.To180Domain(240.0) << endl; + cout << "Bring 140 into 180 Domain: " << p.To180Domain(140.0) << endl; + cout << "Bring -180 into 180 Domain: " << p.To180Domain(-180.0) << endl; + cout << "Bring 180 into 180 Domain: " << p.To180Domain(180.0) << endl; + cout << endl; + + cout << "Change -90 to planetographic: " << p.ToPlanetographic(-90.0) << endl; + cout << "Change -45 to planetographic: " << p.ToPlanetographic(-45.0) << endl; + cout << "Change 0 to planetographic: " << p.ToPlanetographic(0.0) << endl; + cout << "Change 45 to planetographic: " << p.ToPlanetographic(45.0) << endl; + cout << "Change 90 to planetographic: " << p.ToPlanetographic(90.0) << endl; + + cout << "Change -90 to planetocentric: " << p.ToPlanetocentric(-90.0) << endl; + cout << "Change -45 to planetocentric: " << p.ToPlanetocentric(-45.0) << endl; + cout << "Change 0 to planetocentric: " << p.ToPlanetocentric(0.0) << endl; + cout << "Change 45 to planetocentric: " << p.ToPlanetocentric(45.0) << endl; + cout << "Change 90 to planetocentric: " << p.ToPlanetocentric(90.0) << endl; + cout << endl; + + cout << "ocentric to ographic to ocentric = " << p.ToPlanetocentric(p.ToPlanetographic(45.0)) << endl; + cout << "ographic to ocentric to ographic = " << p.ToPlanetographic(p.ToPlanetocentric(45.0)) << endl; + cout << endl; + + cout << "Testing unordered latitude range" << endl; + mg += Isis::PvlKeyword("MinimumLatitude",45.0); + mg += Isis::PvlKeyword("MaximumLatitude",-80.0); + mg += Isis::PvlKeyword("MinimumLongitude",15.0); + mg += Isis::PvlKeyword("MaximumLongitude",-190.0); + Doit(lab); + cout << endl; + + cout << "Testing invalid minimum latitude" << endl; + mg["MinimumLatitude"] = -95.0; + Doit(lab); + cout << endl; + + cout << "Testing invalid maximum latitude" << endl; + mg["MinimumLatitude"].SetValue(45.0, "units"); + mg["MaximumLatitude"].SetValue(95.0, "units"); + Doit(lab); + cout << endl; + + cout << "Testing unordered longitude range" << endl; + mg["MaximumLatitude"].SetValue(80.0, "units"); + Doit(lab); + cout << endl; + mg["MaximumLongitude"] = 190.0; + + MyProjection p2(lab); + cout << "Has as longitude range: " << p2.HasGroundRange() << endl; + cout << "Minimum latitude: " << p2.MinimumLatitude() << endl; + cout << "Maximum latitude: " << p2.MaximumLatitude() << endl; + cout << "Minimum longitude: " << p2.MinimumLongitude() << endl; + cout << "Maximum longitude: " << p2.MaximumLongitude() << endl; + + double minX,maxX,minY,maxY; + p2.XYRange(minX,maxX,minY,maxY); + cout << "Minimum X: " << minX << endl; + cout << "Maximum X: " << maxX << endl; + cout << "Minimum Y: " << minY << endl; + cout << "Maximum Y: " << maxY << endl; + cout << endl; + + cout << "Testing Ground coordinate routines" << endl; + cout << "Setting latitude to (-91, 0): " << p2.SetGround(-91.0,0.0) << endl; + cout << "Is Good: " << p2.IsGood() << endl; + cout << "Setting latitude to ( 91, 0): " << p2.SetGround(91.0,0.0) << endl; + cout << "Is Good: " << p2.IsGood() << endl; + cout << "Setting position to (60, -5): " << p2.SetGround(60.0,-5.0) << endl; + cout << "Is Good: " << p2.IsGood() << endl; + cout << "Latitude: " << p2.Latitude() << endl; + cout << "Longitude: " << p2.Longitude() << endl; + cout << "XCoord: " << p2.XCoord() << endl; + cout << "YCoord: " << p2.YCoord() << endl; + cout << "UniversalLatitude: " << p2.UniversalLatitude() << endl; + cout << "UniversalLongitude: " << p2.UniversalLongitude() << endl; + cout << endl; + + + cout << "Testing Universal Ground coordinate routines" << endl; + cout << "Setting position to (57.3920057293825, 355): " << p2.SetUniversalGround(57.3920057293825,-5.0) << endl; + cout << "Is Good: " << p2.IsGood() << endl; + cout << "Latitude: " << p2.Latitude() << endl; + cout << "Longitude: " << p2.Longitude() << endl; + cout << "XCoord: " << p2.XCoord() << endl; + cout << "YCoord: " << p2.YCoord() << endl; + cout << "UniversalLatitude: " << p2.UniversalLatitude() << endl; + cout << "UniversalLongitude: " << p2.UniversalLongitude() << endl; + cout << endl; + + cout << "Testing projection coordinate routines" << endl; + cout << "Setting x/y position to (-2550,15): " << p2.SetCoordinate(-2250.0,15.0) << endl; + cout << "Is Good: " << p2.IsGood() << endl; + cout << "Latitude: " << p2.Latitude() << endl; + cout << "Longitude: " << p2.Longitude() << endl; + cout << "XCoord: " << p2.XCoord() << endl; + cout << "YCoord: " << p2.YCoord() << endl; + cout << "UniversalLatitude: " << p2.UniversalLatitude() << endl; + cout << "UniversalLongitude: " << p2.UniversalLongitude() << endl; + cout << "WorldX: " << p2.WorldX() << endl; + cout << "WorldY: " << p2.WorldY() << endl; + cout << endl; + + p2.SetWorldMapper(new MyMapper()); + + cout << "Testing world coordinate routines" << endl; + cout << "Setting world x/y position to (-4500,45): " << p2.SetWorld(-4500.0,45.0) << endl; + cout << "Is Good: " << p2.IsGood() << endl; + cout << "Latitude: " << p2.Latitude() << endl; + cout << "Longitude: " << p2.Longitude() << endl; + cout << "XCoord: " << p2.XCoord() << endl; + cout << "YCoord: " << p2.YCoord() << endl; + cout << "UniversalLatitude: " << p2.UniversalLatitude() << endl; + cout << "UniversalLongitude: " << p2.UniversalLongitude() << endl; + cout << "WorldX: " << p2.WorldX() << endl; + cout << "WorldY: " << p2.WorldY() << endl; + cout << "ToProjectionX (-4500): " << p2.ToProjectionX(-4500.0) << endl; + cout << "ToProjectionY (45): " << p2.ToProjectionY(45.0) << endl; + cout << "ToWorldX: " << p2.ToWorldX(p2.ToProjectionX(-4500.0)) << endl; + cout << "ToWorldY: " << p2.ToWorldY(p2.ToProjectionY(45.0)) << endl; + cout << "Resolution: " << p2.Resolution() << endl; + cout << "Scale: " << p2.Scale() << endl; + cout << "TrueScaleLatitude: " << p2.TrueScaleLatitude() << endl; + cout << endl; + + cout << "Testing IsSky method" << endl; + cout << p2.IsSky() << endl; + mg += Isis::PvlKeyword("TargetName","SKY"); + Doit(lab); + MyProjection p3(lab); + cout << p3.IsSky() << endl; + cout << endl; + + cout << "Testing string routines" << endl; + cout << p2.LatitudeTypeString() << endl; + cout << p2.LongitudeDirectionString() << endl; + cout << p2.LongitudeDomainString() << endl; + cout << endl; + + cout << "Testing Name and comparision routines" << endl; + cout << "Name: " << p2.Name() << endl; + cout << "operator==: " << (p == p2) << endl; + cout << "operator!=: " << (p != p2) << endl; + + mg["LongitudeDirection"] = "PositiveWest"; + mg["LongitudeDomain"] = 180; + EmptyProjection noproj(lab); + cout << endl; + + cout << "Testing no projection" << endl; + noproj.SetUniversalGround(45.0,270.0); + cout << "Latitude: " << noproj.Latitude() << endl; + cout << "Longitude: " << noproj.Longitude() << endl; + cout << endl; + + cout << "Testing radius methods " << endl; + cout << noproj.LocalRadius() << endl; + cout << noproj.LocalRadius(0.0) << endl; + cout << noproj.LocalRadius(90.0) << endl; + cout << noproj.LocalRadius(-90.0) << endl; + + cout << "Testing compute methods " << endl; + p.Output(); + cout << endl; + + cout << "Testing static conversion methods " << endl; + cout << "0 degrees in hours: " << p.ToHours(0.0) << endl; + cout << "0 degrees in HMS format: " << p.ToHMS(0.0) << endl; + cout << "0 degrees in DMS format: " << p.ToDMS(0.0) << endl; + cout << "30.5 degrees in hours: " << p.ToHours(30.5) << endl; + cout << "30.5 degrees in HMS format: " << p.ToHMS(30.5) << endl; + cout << "30.5 degrees in DMS format: " << p.ToDMS(30.5) << endl; + cout << "40.3472 degrees in hours: " << p.ToHours(40.3472) << endl; + cout << "40.3472 degrees in HMS format: " << p.ToHMS(40.3472) << endl; + cout << "40.3472 degrees in DMS format: " << p.ToDMS(40.3472) << endl; + cout << "45 degrees in Hours: " << p.ToHours(45.0) << endl; + cout << "45 degrees in HMS format: " << p.ToHMS(45.0) << endl; + cout << "45 degrees in DMS format: " << p.ToDMS(45.0) << endl; + cout << "180 degrees in Hours: " << p.ToHours(180.0) << endl; + cout << "180 degrees in HMS format: " << p.ToHMS(180.0) << endl; + cout << "180 degrees in DMS format: " << p.ToDMS(180.0) << endl; + cout << "360 degrees in Hours: " << p.ToHours(360.0) << endl; + cout << "360 degrees in HMS format: " << p.ToHMS(360.0) << endl; + cout << "360 degrees in DMS format: " << p.ToDMS(360.0) << endl; + cout << "-390 To180Domain: " << p.To180Domain(-390) << endl; + cout << "-390 To360Domain: " << p.To360Domain(-390) << endl; + cout << "50 to Planetocentric (sphere): " << p.ToPlanetocentric(50, 180000, 180000) << endl; + cout << "50 to Planetographic (sphere): " << p.ToPlanetographic(50, 180000, 180000) << endl; + cout << "-30 ToPositiveEast (180 domain): " << p.ToPositiveEast(-30, 180) << endl; + cout << "30 ToPositiveWest (360 domain): " << p.ToPositiveEast(30, 360) << endl; + cout << endl; + cout << endl; + + cout << "Testing other static methods " << endl; + try { + Isis::PvlGroup radii = Isis::Projection::TargetRadii ("Mars"); + cout << "Mars equatorial radius: " << radii["EquatorialRadius"] << endl; + cout << "Mars polar radius: " << radii["PolarRadius"] << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + + cout << "Rotation Tests" << endl; + mg += Isis::PvlKeyword("Rotation",90.0); + mg["LongitudeDirection"] = "PositiveEast"; + MyProjection p4(lab); + cout << "Rotation: " << p4.Rotation() << endl; + cout << "Testing Ground coordinate routines" << endl; + cout << "Setting latitude to (-91, 0): " << p4.SetGround(-91.0,0.0) << endl; + cout << "Is Good: " << p4.IsGood() << endl; + cout << "Setting latitude to ( 91, 0): " << p4.SetGround(91.0,0.0) << endl; + cout << "Is Good: " << p4.IsGood() << endl; + cout << "Setting position to (60, -5): " << p4.SetGround(60.0,-5.0) << endl; + cout << "Is Good: " << p4.IsGood() << endl; + cout << "Latitude: " << p4.Latitude() << endl; + cout << "Longitude: " << p4.Longitude() << endl; + cout << "XCoord: " << p4.XCoord() << endl; + cout << "YCoord: " << p4.YCoord() << endl; + cout << "UniversalLatitude: " << p4.UniversalLatitude() << endl; + cout << "UniversalLongitude: " << p4.UniversalLongitude() << endl; + cout << endl; + + cout << "Testing projection coordinate routines" << endl; + cout << "Setting x/y position to (150,50): " << p4.SetCoordinate(150.0,50.0) << endl; + cout << "Is Good: " << p4.IsGood() << endl; + cout << "Latitude: " << p4.Latitude() << endl; + cout << "Longitude: " << p4.Longitude() << endl; + cout << "XCoord: " << p4.XCoord() << endl; + cout << "YCoord: " << p4.YCoord() << endl; + cout << "UniversalLatitude: " << p4.UniversalLatitude() << endl; + cout << "UniversalLongitude: " << p4.UniversalLongitude() << endl; + cout << "WorldX: " << p4.WorldX() << endl; + cout << "WorldY: " << p4.WorldY() << endl; + cout << endl; + + Isis::Pvl mapping; + mapping.AddGroup(p4.Mapping()); + cout << "Testing Mapping() methods" << endl; + cout << "Mapping() = " << endl; + cout << mapping << endl; + mapping.DeleteGroup("Mapping"); + mapping.AddGroup(p4.MappingLatitudes()); + cout << "MappingLatitudes() = " << endl; + cout << mapping << endl; + mapping.DeleteGroup("Mapping"); + mapping.AddGroup(p4.MappingLongitudes()); + cout << "MappingLongitudes() = " << endl; + cout << mapping << endl; + mapping.DeleteGroup("Mapping"); + cout << endl; +} + + +void Doit (Isis::Pvl &lab) { + try { + MyProjection p(lab); + } + catch (Isis::iException &error) { + error.Report (false); + } +} diff --git a/isis/src/base/objs/ProjectionFactory/Makefile b/isis/src/base/objs/ProjectionFactory/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4af6cdf77061e112aaa674921a3c1c078545a152 --- /dev/null +++ b/isis/src/base/objs/ProjectionFactory/Makefile @@ -0,0 +1,5 @@ +INCS = ProjectionFactory.h +SRCS = ProjectionFactory.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ProjectionFactory/ProjectionFactory.cpp b/isis/src/base/objs/ProjectionFactory/ProjectionFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aee2c0400604fc4edf19cd99d1b5942d11f476bf --- /dev/null +++ b/isis/src/base/objs/ProjectionFactory/ProjectionFactory.cpp @@ -0,0 +1,553 @@ +/** + * @file + * $Revision: 1.9 $ + * $Date: 2009/06/18 21:49:15 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "ProjectionFactory.h" +#include "Camera.h" +#include "Projection.h" +#include "Cube.h" +#include "iException.h" +#include "Filename.h" +#include "Plugin.h" + +using namespace std; +namespace Isis { + /** + * This method returns a pointer to a Projection object. The projection is + * intialized using information contained in a Label object. The information + * must be a valid Mapping group as defined in the Isis Map Projection Users + * Guide. + * + * @param label The label object containing a valid mapping group. + * + * @param allowDefaults If false then the projection class as indicated by the + * ProjectionName keyword will require that projection + * specific parameters such as CenterLatitude, + * CenterLongitude, etc must be in the Pvl label object. + * Otherwise if true then those parameters that are not in + * the Pvl object will be initialized using the + * latitude/longitude range. + * + * @return A pointer to a Projection object. + * + * @throws Isis::iException::System - Unsupported projection, unable to find + * plugin + */ + Isis::Projection *ProjectionFactory::Create(Isis::Pvl &label, + bool allowDefaults) { + // Try to load a plugin file in the current working directory and then + // load the system file + Plugin p; + Isis::Filename localFile("Projection.plugin"); + if (localFile.Exists()) p.Read(localFile.Expanded()); + Isis::Filename systemFile("$ISISROOT/lib/Projection.plugin"); + if (systemFile.Exists()) p.Read(systemFile.Expanded()); + + try { + // Look for info in the mapping group + Isis::PvlGroup &mapGroup = label.FindGroup("Mapping",Isis::Pvl::Traverse); + string proj = mapGroup["ProjectionName"]; + + // Now get the plugin for the projection + void *ptr; + try { + ptr = p.GetPlugin(proj); + } + catch (Isis::iException &e) { + string msg = "Unsupported projection, unable to find plugin for [" + + proj + "]"; + throw Isis::iException::Message(Isis::iException::System,msg,_FILEINFO_); + } + + // Now cast that pointer in the proper way + Isis::Projection * (*plugin) (Isis::Pvl &label, bool flag); + plugin = (Isis::Projection * (*)(Isis::Pvl &label, bool flag)) ptr; + + // Create the projection as requested + return (*plugin)(label,allowDefaults); + } + catch (Isis::iException &e) { + string message = "Unable to initialize Projection information "; + message += "from group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + /** + * This method creates a map projection for a cube given a label. The label + * must contain all the proper mapping information (radii, projection name, + * parameters, pixel resolution, etc). If the labels contain a Cube group and + * the Mapping group already has the upper left corner, then the values in the + * label will be used to set the cube size. If they don't exist then the + * minimum/maximum latitude/longitude values (ground range) are expected to be + * in the Mapping group and will be used to compute the cube size and upper + * left corner values. + * + * @param label A label containing valid map projection information for a + * cube. + * @param samples The number of samples. This value is calculated in the + * method and returned. + * @param lines The number of lines. This value is calculated in the method + * and returned. + * @param sizeMatch Boolean value that determines whether the method should + * match the size of the output cube to the size of the input + * cube. This parameter defaults to true. + * + * @return A pointer to a Projection object. + * + */ + Isis::Projection *ProjectionFactory::CreateForCube (Isis::Pvl &label, + int &samples, int &lines, + bool sizeMatch) { + // Create a temporary projection and get the radius at the special latitude + Isis::Projection *proj = Create(label,true); + double trueScaleLat = proj->TrueScaleLatitude(); + double localRadius = proj->LocalRadius(trueScaleLat); + delete proj; + + try { + // Try to get the pixel resolution and then compute the scale + double scale, pixelResolution; + Isis::PvlGroup &mapGroup = label.FindGroup("Mapping",Isis::Pvl::Traverse); + try { + pixelResolution = mapGroup["PixelResolution"]; + scale = (2.0 * Isis::PI * localRadius) / (360.0 * pixelResolution); + } + + // If not get the scale and then compute the pixel resolution + catch (Isis::iException &e) { + scale = mapGroup["Scale"]; + e.Clear(); + pixelResolution = (2.0 * Isis::PI * localRadius) / (360.0 * scale); + } + // Write out the scale and resolution with units and truescale latitude + mapGroup.AddKeyword(Isis::PvlKeyword ("PixelResolution",pixelResolution, "meters/pixel"), + Isis::Pvl::Replace); + mapGroup.AddKeyword(Isis::PvlKeyword ("Scale",scale, "pixels/degree"),Isis::Pvl::Replace); + //mapGroup.AddKeyword(Isis::PvlKeyword ("TrueScaleLatitude", trueScaleLat), + // Isis::Pvl::Replace); + + // Get the upper left corner from the labels if possible + // This forces an exact match of projection parameters for + // output cubes + bool sizeFound = false; + double upperLeftX, upperLeftY; + if (label.HasObject("IsisCube")) { + Isis::PvlGroup &dims = label.FindGroup("Dimensions",Isis::Pvl::Traverse); + samples = dims["Samples"]; + lines = dims["Lines"]; + + upperLeftX = mapGroup["UpperLeftCornerX"]; + upperLeftY = mapGroup["UpperLeftCornerY"]; + sizeFound = true; + } + if (!sizeMatch) sizeFound = false; + + // Initialize the rest of the projection + proj = Create(label,true); + + // Couldn't find the cube size from the labels so compute it + if (!sizeFound) { + if (!proj->HasGroundRange()) { + string msg = "Invalid ground range [MinimumLatitude,MaximumLatitude,"; + msg += "MinimumLongitude,MaximumLongitude] missing or invalid"; + throw Isis::iException::Message(Isis::iException::Projection,msg,_FILEINFO_); + } + + double minX,maxX,minY,maxY; + if (!proj->XYRange(minX,maxX,minY,maxY)) { + string msg = "Invalid ground range [MinimumLatitude,MaximumLatitude,"; + msg += "MinimumLongitude,MaximumLongitude] cause invalid computation "; + msg += "of image size"; + throw Isis::iException::Message(Isis::iException::Projection,msg,_FILEINFO_); + } + + // Convert upperleft coordinate to units of pixel + // Truncate it to the nearest whole pixel (floor/ceil) + // Convert it back to meters. But don't do this if + // the X/Y position is already close to a whole pixel because + // the floor/ceil function could cause an extra pixel to be added + // just due to machine precision issues + if (fabs(fmod(minX,pixelResolution)) > 1.0e-6) { + if (pixelResolution - fabs(fmod(minX,pixelResolution)) > 1.0e-6) { + double sampleOffset = floor (minX / pixelResolution); + minX = sampleOffset * pixelResolution; + } + } + + if (fabs(fmod(maxY,pixelResolution)) > 1.0e-6) { + if (pixelResolution - fabs(fmod(maxY,pixelResolution)) > 1.0e-6) { + double lineOffset = -1.0 * ceil(maxY / pixelResolution); + maxY = -1.0 * lineOffset * pixelResolution; + } + } + + // Determine the number of samples and lines + samples = (int) ((maxX - minX) / pixelResolution + 0.5); + lines = (int) ((maxY - minY) / pixelResolution + 0.5); + + // Set the upper left corner and add to the labels + upperLeftX = minX; + mapGroup.AddKeyword(Isis::PvlKeyword("UpperLeftCornerX",upperLeftX), + Isis::Pvl::Replace); + + upperLeftY = maxY; + mapGroup.AddKeyword(Isis::PvlKeyword("UpperLeftCornerY",upperLeftY), + Isis::Pvl::Replace); + + // Write it in pixel units as well +#if 0 + lineOffset += 0.5; // This matches the PDS definition + sampleOffset += 0.5; // of the offsets (center of pixel). This statement is questionable! + mapGroup.AddKeyword(Isis::PvlKeyword("LineProjectionOffset",lineOffset), + Isis::Pvl::Replace); + mapGroup.AddKeyword(Isis::PvlKeyword("SampleProjectionOffset",sampleOffset), + Isis::Pvl::Replace); +#endif + } + + + // Make sure labels have good units + mapGroup.AddKeyword(Isis::PvlKeyword("PixelResolution", + (string) mapGroup["PixelResolution"], + "meters/pixel"),Isis::Pvl::Replace); + + mapGroup.AddKeyword(Isis::PvlKeyword("Scale", + (string) mapGroup["Scale"], + "pixels/degree"),Isis::Pvl::Replace); + + mapGroup.AddKeyword(Isis::PvlKeyword("UpperLeftCornerX", + (string) mapGroup["UpperLeftCornerX"], + "meters"),Isis::Pvl::Replace); + + mapGroup.AddKeyword(Isis::PvlKeyword("UpperLeftCornerY", + (string) mapGroup["UpperLeftCornerY"], + "meters"),Isis::Pvl::Replace); + + mapGroup.AddKeyword(Isis::PvlKeyword("EquatorialRadius", + (string) mapGroup["EquatorialRadius"], + "meters"),Isis::Pvl::Replace); + + mapGroup.AddKeyword(Isis::PvlKeyword("PolarRadius", + (string) mapGroup["PolarRadius"], + "meters"),Isis::Pvl::Replace); + + // Add the mapper from pixel coordinates to projection coordinates + PFPixelMapper *pixelMapper=new PFPixelMapper(pixelResolution,upperLeftX,upperLeftY); + proj->SetWorldMapper(pixelMapper); + } + catch (Isis::iException &e) { + string msg = "Unable to create projection"; + if (label.Filename () != "") msg += " from file [" + label.Filename() + "]"; + throw Isis::iException::Message(Isis::iException::Projection,msg,_FILEINFO_); + } + return proj; + } + + + /** + * @brief Create a map projection group for a cube using a + * camera. + * + * This method walks the boundary of the cube computing lat/lons + * and then uses those lat/lon as input to the projection to + * compute a x/y range. This x/y range will be minimal + * (compared to the alternate CreateForCube method and generates + * significantly small cube size (samples,lines) depending on + * the projection. Projections with curved merdians and/or + * parallels generate larger x/y ranges when only looking at the + * ground range. + * + * @param label A label containing valid map projection information for a + * cube. + * @param samples The number of samples. This value is calculated in the + * method and returned. + * @param lines The number of lines. This value is calculated in the method + * and returned. + * @param cam An initialized camera model + * + * @return A pointer to a Projection object. + * + */ + Isis::Projection *ProjectionFactory::CreateForCube (Isis::Pvl &label, + int &samples, int &lines, + Camera &cam) { + // Create a temporary projection and get the radius at the special latitude + Isis::Projection *proj = Create(label,true); + double trueScaleLat = proj->TrueScaleLatitude(); + double localRadius = proj->LocalRadius(trueScaleLat); + delete proj; + + try { + // Try to get the pixel resolution and then compute the scale + double scale, pixelResolution; + Isis::PvlGroup &mapGroup = label.FindGroup("Mapping",Isis::Pvl::Traverse); + try { + pixelResolution = mapGroup["PixelResolution"]; + scale = (2.0 * Isis::PI * localRadius) / (360.0 * pixelResolution); + } + + // If not get the scale and then compute the pixel resolution + catch (Isis::iException &e) { + scale = mapGroup["Scale"]; + e.Clear(); + pixelResolution = (2.0 * Isis::PI * localRadius) / (360.0 * scale); + } + // Write out the scale and resolution with units and truescale latitude + mapGroup.AddKeyword(Isis::PvlKeyword ("PixelResolution",pixelResolution, "meters/pixel"), + Isis::Pvl::Replace); + mapGroup.AddKeyword(Isis::PvlKeyword ("Scale",scale, "pixels/degree"),Isis::Pvl::Replace); + //mapGroup.AddKeyword(Isis::PvlKeyword ("TrueScaleLatitude", trueScaleLat), + // Isis::Pvl::Replace); + + // Initialize the rest of the projection + proj = Create(label,true); + double minX = DBL_MAX; + double maxX = -DBL_MAX; + double minY = DBL_MAX; + double maxY = -DBL_MAX; + + // Walk the boundaries of the camera to determine the x/y range + int eband = cam.Bands(); + if (cam.IsBandIndependent()) eband = 1; + for (int band=1; band<=eband; band++) { + cam.SetBand(band); + + // Loop for each line testing the left and right sides of the image + for (int line=0; line<=cam.Lines(); line++) { + // Look for the first good lat/lon on the left edge of the image + // If it is the first or last line then test the whole line + int samp; + for (samp=0; samp<=cam.Samples(); samp++) { + if (cam.SetImage((double)samp + 0.5,(double)line + 0.5)) { + double lat = cam.UniversalLatitude(); + double lon = cam.UniversalLongitude(); + proj->SetUniversalGround(lat,lon); + if (proj->IsGood()) { + if (proj->XCoord() < minX) minX = proj->XCoord(); + if (proj->XCoord() > maxX) maxX = proj->XCoord(); + if (proj->YCoord() < minY) minY = proj->YCoord(); + if (proj->YCoord() > maxY) maxY = proj->YCoord(); + if ((line != 0) && (line != cam.Lines())) break; + } + } + } + + // Look for the first good lat/lon on the right edge of the image + if (samp < cam.Samples()) { + for (samp=cam.Samples(); samp>=0; samp--) { + if (cam.SetImage((double)samp+0.5,(double)line+0.5)) { + double lat = cam.UniversalLatitude(); + double lon = cam.UniversalLongitude(); + proj->SetUniversalGround(lat,lon); + if (proj->IsGood()) { + if (proj->XCoord() < minX) minX = proj->XCoord(); + if (proj->XCoord() > maxX) maxX = proj->XCoord(); + if (proj->YCoord() < minY) minY = proj->YCoord(); + if (proj->YCoord() > maxY) maxY = proj->YCoord(); + break; + } + } + } + } + } + + // Special test for ground range to see if either pole is in the image + if (cam.SetUniversalGround(90.0,0.0)) { + if (cam.Sample() >= 0.5 && cam.Line() >= 0.5 && + cam.Sample() <= cam.Samples() + 0.5 && cam.Line() <= cam.Lines() + 0.5) { + double lat = cam.UniversalLatitude(); + double lon = cam.UniversalLongitude(); + proj->SetUniversalGround(lat,lon); + if (proj->IsGood()) { + if (proj->XCoord() < minX) minX = proj->XCoord(); + if (proj->XCoord() > maxX) maxX = proj->XCoord(); + if (proj->YCoord() < minY) minY = proj->YCoord(); + if (proj->YCoord() > maxY) maxY = proj->YCoord(); + } + } + } + + if (cam.SetUniversalGround(-90.0,0.0)) { + if (cam.Sample() >= 0.5 && cam.Line() >= 0.5 && + cam.Sample() <= cam.Samples() + 0.5 && cam.Line() <= cam.Lines() + 0.5) { + double lat = cam.UniversalLatitude(); + double lon = cam.UniversalLongitude(); + proj->SetUniversalGround(lat,lon); + if (proj->IsGood()) { + if (proj->XCoord() < minX) minX = proj->XCoord(); + if (proj->XCoord() > maxX) maxX = proj->XCoord(); + if (proj->YCoord() < minY) minY = proj->YCoord(); + if (proj->YCoord() > maxY) maxY = proj->YCoord(); + } + } + } + +#if 0 + // Another special test for ground range as we could have the + // 0-360 seam running right through the image so + // test it as well (the increment may not be fine enough !!!) + for (double lat=p_minlat; lat<=p_maxlat; lat+=(p_maxlat-p_minlat)/10.0) { + if (SetUniversalGround(lat,0.0)) { + if (Sample() >= 0.5 && Line() >= 0.5 && + Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) { + p_minlon = 0.0; + p_maxlon = 360.0; + break; + } + } + } + + // Another special test for ground range as we could have the + // -180-180 seam running right through the image so + // test it as well (the increment may not be fine enough !!!) + for (double lat=p_minlat; lat<=p_maxlat; lat+=(p_maxlat-p_minlat)/10.0) { + if (SetUniversalGround(lat,180.0)) { + if (Sample() >= 0.5 && Line() >= 0.5 && + Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) { + p_minlon180 = -180.0; + p_maxlon180 = 180.0; + break; + } + } + } +#endif + } + + // Convert upperleft coordinate to units of pixel + // Truncate it to the nearest whole pixel (floor/ceil) + // Convert it back to meters. But don't do this if + // the X/Y position is already close to a whole pixel because + // the floor/ceil function could cause an extra pixel to be added + // just due to machine precision issues + if (fabs(fmod(minX,pixelResolution)) > 1.0e-6) { + if (pixelResolution - fabs(fmod(minX,pixelResolution)) > 1.0e-6) { + double sampleOffset = floor (minX / pixelResolution); + minX = sampleOffset * pixelResolution; + } + } + + if (fabs(fmod(maxY,pixelResolution)) > 1.0e-6) { + if (pixelResolution - fabs(fmod(maxY,pixelResolution)) > 1.0e-6) { + double lineOffset = -1.0 * ceil(maxY / pixelResolution); + maxY = -1.0 * lineOffset * pixelResolution; + } + } + + // Determine the number of samples and lines + samples = (int) ((maxX - minX) / pixelResolution + 0.5); + lines = (int) ((maxY - minY) / pixelResolution + 0.5); + + // Set the upper left corner and add to the labels + double upperLeftX = minX; + mapGroup.AddKeyword(Isis::PvlKeyword("UpperLeftCornerX",upperLeftX), + Isis::Pvl::Replace); + + double upperLeftY = maxY; + mapGroup.AddKeyword(Isis::PvlKeyword("UpperLeftCornerY",upperLeftY), + Isis::Pvl::Replace); + + // Make sure labels have good units + mapGroup.AddKeyword(Isis::PvlKeyword("PixelResolution", + (string) mapGroup["PixelResolution"], + "meters/pixel"),Isis::Pvl::Replace); + + mapGroup.AddKeyword(Isis::PvlKeyword("Scale", + (string) mapGroup["Scale"], + "pixels/degree"),Isis::Pvl::Replace); + + mapGroup.AddKeyword(Isis::PvlKeyword("UpperLeftCornerX", + (string) mapGroup["UpperLeftCornerX"], + "meters"),Isis::Pvl::Replace); + + mapGroup.AddKeyword(Isis::PvlKeyword("UpperLeftCornerY", + (string) mapGroup["UpperLeftCornerY"], + "meters"),Isis::Pvl::Replace); + + mapGroup.AddKeyword(Isis::PvlKeyword("EquatorialRadius", + (string) mapGroup["EquatorialRadius"], + "meters"),Isis::Pvl::Replace); + + mapGroup.AddKeyword(Isis::PvlKeyword("PolarRadius", + (string) mapGroup["PolarRadius"], + "meters"),Isis::Pvl::Replace); + + // Add the mapper from pixel coordinates to projection coordinates + PFPixelMapper *pixelMapper=new PFPixelMapper(pixelResolution,upperLeftX,upperLeftY); + proj->SetWorldMapper(pixelMapper); + } + catch (Isis::iException &e) { + string msg = "Unable to create projection"; + if (label.Filename () != "") msg += " from file [" + label.Filename() + "]"; + throw Isis::iException::Message(Isis::iException::Projection,msg,_FILEINFO_); + } + return proj; + } + + + /** + * This method is a helper method. See CreateFromCube(Pvl). + * + * @param cube A cube containing valid map projection information + * + * @return A pointer to a Projection object + */ + Isis::Projection *ProjectionFactory::CreateFromCube (Isis::Cube &cube) { + return CreateFromCube(*cube.Label()); + } + +/** + * This method loads a map projection from a cube returning a pointer to a + * Projection object. + * + * @param label A label containing valid map projection information for a + * cube. + * + * @return (Isis::Projection) A pointer to a Projection object. + */ + Isis::Projection *ProjectionFactory::CreateFromCube (Isis::Pvl &label) { + Isis::Projection *proj; + try { + // Get the pixel resolution + Isis::PvlGroup &mapGroup = label.FindGroup("Mapping",Isis::Pvl::Traverse); + double pixelResolution = mapGroup["PixelResolution"]; + + // Get the upper left corner + double upperLeftX = mapGroup["UpperLeftCornerX"]; + double upperLeftY = mapGroup["UpperLeftCornerY"]; + + // Initialize the rest of the projection + proj = Create(label,true); + + // Create a mapper to transform pixels into projection x/y and vice versa + PFPixelMapper *pixelMapper = new PFPixelMapper(pixelResolution,upperLeftX,upperLeftY); + proj->SetWorldMapper(pixelMapper); + } + catch (Isis::iException &e) { + string msg = "Unable to initialize cube projection"; + if (label.Filename () != "") msg += " from file [" + label.Filename() + "]"; + throw Isis::iException::Message(Isis::iException::Projection,msg,_FILEINFO_); + } + return proj; + } +} //end namespace isis diff --git a/isis/src/base/objs/ProjectionFactory/ProjectionFactory.h b/isis/src/base/objs/ProjectionFactory/ProjectionFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..5439bce100bff9255d99368ae6a9e6e576b79106 --- /dev/null +++ b/isis/src/base/objs/ProjectionFactory/ProjectionFactory.h @@ -0,0 +1,162 @@ +#ifndef ProjectionFactory_h +#define ProjectionFactory_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2009/06/18 21:24:00 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Projection.h" +#include "Cube.h" + +namespace Isis { + /** + * @brief Initialize a map projection + * + * This factory class is used to obtain a Projection object given a PVL which + * contains a valid Mapping group. The Mapping group can come from an + * image/cube or a hand-created PVL file. The projection is loaded based on + * information using the ProjectionName contained in the Mapping group. It is + * plugin oriented. That is, this class looks in + * $ISISROOT/lib/Projection.plugin to convert the ProjectionName into a + * pointer to the appropriate projection class (e.g., Sinusoidal, + * SimpleCylindrical). This allows programmers who develop new projection to + * create a plugin without the need for recompiling all the Isis cartographic + * programs (cam2map, map2map, mappos, etc). + * + * @ingroup MapProjection + * + * @author 2005-06-22 Elizabeth Ribelin + * + * + * @internal + * @history 2005-06-22 Elizabeth Ribelin - Merged ProjectionManager and + * CubeProjection into a single class + * @history 2006-01-27 Jacob Danton - Renamed PixelMapper to PFPixelMapper\ + * @history 2006-05-19 Elizabeth Miller - Depricated ProjectionManager and + * CubeProjection. Renamed + * ProjectionManager.plugin to + * Projection.plugin + * @history 2006-09-07 Elizabeth Miller - Added the bool sizeMatch + * parameter to CreateForCube() + * @history 2007-03-13 Jeff Anderson - Added new method CreateForCube using a + * camera + * @history 2007-06-29 Steven Lambright - Removed TrueScaleLatitude keyword from CreateForCube + * methods, added units to Scale and PixelResolution + * keywords + * @history 2008-06-18 Steven Koechle - Fixed Documentation Error + * @history 2009-06-18 Jeff Anderson - Modified the CreateForCube method to + * make sure extra pixels were not included in the image size due to + * machine precision roundoff problems. + * + */ + class ProjectionFactory { + public: + static Isis::Projection *Create(Isis::Pvl &label, bool allowDefaults=false); + static Isis::Projection *CreateFromCube(Isis::Cube &cube); + static Isis::Projection *CreateFromCube(Isis::Pvl &label); // Load Method in cm + static Isis::Projection *CreateForCube(Isis::Pvl &label, int &ns, int &nl, + bool sizeMatch=true); // Create method in cm + static Isis::Projection *CreateForCube (Isis::Pvl &label, + int &samples, int &lines, + Camera &cam); + + private: + /** + * Constructor (Its private, so you cannot use it.) Use the Create method + * instead + */ + ProjectionFactory () {}; + + //! Destroys the ProjectionFactory object + ~ProjectionFactory () {}; + + }; + + /// @cond INTERNAL + class PFPixelMapper : public Isis::WorldMapper { + public: + /** + * Constructs a PFFixelMapper object with the given pixel resolution and + * location. + * @param pixelResolution The pixel resolution + * @param upperLeftX The x value for the upper left corner + * @param upperLeftY The y value for the upper left corner + */ + PFPixelMapper(double pixelResolution, double upperLeftX, double upperLeftY) { + p_pixelResolution = pixelResolution; + p_upperLeftX = upperLeftX; + p_upperLeftY = upperLeftY; + }; + + /** + * Returns the world x position for the given x projection value + * @param projX The x projection value to get the world x position for + * + * @return double The world x position + */ + double WorldX(const double projX) const { + return (projX - p_upperLeftX) / p_pixelResolution + 0.5; + }; + + /** + * Returns the world y position for the given y projection value + * @param projY The y projection value to get the world y position for + * + * @return double The world y position + */ + double WorldY(const double projY) const { + return (p_upperLeftY - projY) / p_pixelResolution + 0.5; + }; + + /** + * Returns the x projection of the given sample + * @param sample The sample to get the x projection value for + * + * @return double The x projection value + */ + double ProjectionX(const double sample) const { + return (sample - 0.5) * p_pixelResolution + p_upperLeftX; + }; + + /** + * Returns the y projection of the given line + * @param line The line to get the y projection value for + * + * @return double The y projection value + */ + double ProjectionY(const double line) const { + return p_upperLeftY - (line - 0.5) * p_pixelResolution; + }; + + //! Returns the pixel resolution + double Resolution () const { + return p_pixelResolution; + } + + private: + double p_pixelResolution; + double p_upperLeftX; + double p_upperLeftY; + }; + /// @endcond +}; + +#endif + diff --git a/isis/src/base/objs/ProjectionFactory/ProjectionFactory.truth b/isis/src/base/objs/ProjectionFactory/ProjectionFactory.truth new file mode 100644 index 0000000000000000000000000000000000000000..13148e6f328ead50fa709629a875a28797148b74 --- /dev/null +++ b/isis/src/base/objs/ProjectionFactory/ProjectionFactory.truth @@ -0,0 +1,69 @@ +Unit test for Isis::ProjectionFactory +Test for missing pixel resolution ... +**PROJECTION ERROR** Unable to initialize cube projection +**PVL ERROR** Keyword [PixelResolution] does not exist in [Group = Mapping] + +**PROJECTION ERROR** Unable to create projection +**PVL ERROR** Keyword [Scale] does not exist in [Group = Mapping] +**PVL ERROR** Keyword [PixelResolution] does not exist in [Group = Mapping] + +Test for missing upper left X ... +**PROJECTION ERROR** Unable to initialize cube projection +**PVL ERROR** Keyword [UpperLeftCornerX] does not exist in [Group = Mapping] + +Test for missing upper left Y ... +**PROJECTION ERROR** Unable to initialize cube projection +**PVL ERROR** Keyword [UpperLeftCornerY] does not exist in [Group = Mapping] + +Testing conversion from image to ground ... +Latitude: 22.82592837303 +Longitude: 227.94605488817 + +Testing conversion from ground to image ... +Sample: 244.5 +Line: 354.5 + +Testing missing ground range on create method ... +**PROJECTION ERROR** Unable to create projection +**PROJECTION ERROR** Invalid ground range [MinimumLatitude,MaximumLatitude,MinimumLongitude,MaximumLongitude] missing or invalid + +Testing create method ... +Lines: 708 +Samples: 489 +UpperLeftX: -18000 +UpperLeftY: 2062000 + +Testing create method with existing cube labels +Lines: 400 +Samples: 600 +UpperLeftX: -16000 +UpperLeftY: 2060000 + +Label results +Object = IsisCube + Object = Core + Group = Dimensions + Lines = 400 + Samples = 600 + End_Group + End_Object + + Group = Mapping + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetographic + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + ProjectionName = SimpleCylindrical + CenterLongitude = 220.0 + PixelResolution = 2000.0 + Scale = 29.637348761653 + MinimumLatitude = 10.892053992414 + MaximumLatitude = 34.760396006021 + MinimumLongitude = 219.72432466275 + MaximumLongitude = 236.18605024441 + UpperLeftCornerX = -16000.0 + UpperLeftCornerY = 2060000.0 + End_Group +End_Object +End diff --git a/isis/src/base/objs/ProjectionFactory/unitTest.cpp b/isis/src/base/objs/ProjectionFactory/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..214253ebe8db9ad22ed6f5aa6f6f0678cd94482a --- /dev/null +++ b/isis/src/base/objs/ProjectionFactory/unitTest.cpp @@ -0,0 +1,132 @@ +#include +#include +#include "iException.h" +#include "ProjectionFactory.h" +#include "Pvl.h" +#include "Projection.h" +#include "Preference.h" + +using namespace std; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + void doit (Isis::Pvl &lab); + void doit2 (Isis::Pvl &lab); + + try { + cout << "Unit test for Isis::ProjectionFactory" << endl; + + Isis::Pvl lab; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = lab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",3396190.0); + mapGroup += Isis::PvlKeyword("PolarRadius",3376200.0); + + mapGroup += Isis::PvlKeyword("LatitudeType","Planetographic"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",360); + + mapGroup += Isis::PvlKeyword("ProjectionName","SimpleCylindrical"); + mapGroup += Isis::PvlKeyword("CenterLongitude",220.0); + + cout << "Test for missing pixel resolution ... " << endl; + doit(lab); + doit2(lab); + + mapGroup += Isis::PvlKeyword("PixelResolution",2000.0); + cout << "Test for missing upper left X ... " << endl; + doit(lab); + + mapGroup += Isis::PvlKeyword("UpperLeftCornerX",-18000.0); + cout << "Test for missing upper left Y ... " << endl; + doit(lab); + + mapGroup += Isis::PvlKeyword("UpperLeftCornerY",2062000.0); + + cout << "Testing conversion from image to ground ... " << endl; + Isis::Projection *proj = Isis::ProjectionFactory::CreateFromCube(lab); + proj->SetWorld(245.0,355.0); + cout << setprecision(14); + cout << "Latitude: " << proj->Latitude() << endl; + cout << "Longitude: " << proj->Longitude() << endl; + cout << endl; + + cout << "Testing conversion from ground to image ... " << endl; + proj->SetGround(22.84279897788801,227.9291842833142); + cout << "Sample: " << proj->WorldX() << endl; + cout << "Line: " << proj->WorldY() << endl; + cout << endl; + + cout << "Testing missing ground range on create method ... " << endl; + doit2(lab); + + mapGroup += Isis::PvlKeyword("MinimumLatitude",10.8920539924144); + mapGroup += Isis::PvlKeyword("MaximumLatitude",34.7603960060206); + mapGroup += Isis::PvlKeyword("MinimumLongitude",219.72432466275); + mapGroup += Isis::PvlKeyword("MaximumLongitude",236.186050244411); + mapGroup.DeleteKeyword("UpperLeftCornerX"); + mapGroup.DeleteKeyword("UpperLeftCornerY"); + + cout << "Testing create method ... " << endl; + int lines, samples; + proj = Isis::ProjectionFactory::CreateForCube(lab,samples, lines); + cout << "Lines: " << lines << endl; + cout << "Samples: " << samples << endl; + cout << "UpperLeftX: " << (double) mapGroup["UpperLeftCornerX"] << endl; + cout << "UpperLeftY: " << (double) mapGroup["UpperLeftCornerY"] << endl; + cout << endl; + + cout << "Testing create method with existing cube labels" << endl; + mapGroup.AddKeyword(Isis::PvlKeyword("UpperLeftCornerX",-16000.0),Isis::Pvl::Replace); + mapGroup.AddKeyword(Isis::PvlKeyword("UpperLeftCornerY",2060000.0),Isis::Pvl::Replace); + + Isis::Pvl lab2; + Isis::PvlObject icube("IsisCube"); + Isis::PvlObject core("Core"); + Isis::PvlGroup dims("Dimensions"); + dims += Isis::PvlKeyword("Lines",400); + dims += Isis::PvlKeyword("Samples",600); + core.AddGroup(dims); + icube.AddObject(core); + icube.AddGroup(mapGroup); + lab2.AddObject(icube); + + proj = Isis::ProjectionFactory::CreateForCube(lab2, samples, lines); + cout << "Lines: " << lines << endl; + cout << "Samples: " << samples << endl; + mapGroup = lab2.FindGroup("Mapping",Isis::Pvl::Traverse); + cout << "UpperLeftX: " << (double) mapGroup["UpperLeftCornerX"] << endl; + cout << "UpperLeftY: " << (double) mapGroup["UpperLeftCornerY"] << endl; + cout << endl; + + cout << "Label results" << endl; + cout << lab2 << endl; + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void doit(Isis::Pvl &lab) { + try { + Isis::ProjectionFactory::CreateFromCube(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; +} + +void doit2(Isis::Pvl &lab) { + try { + int lines, samples; + Isis::ProjectionFactory::CreateForCube(lab, samples, lines); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; +} + + diff --git a/isis/src/base/objs/PushFrameCamera/Makefile b/isis/src/base/objs/PushFrameCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d7b8f2183047263969396ec82c2ec887848b84b8 --- /dev/null +++ b/isis/src/base/objs/PushFrameCamera/Makefile @@ -0,0 +1,5 @@ +INCS = PushFrameCamera.h +SRCS = PushFrameCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PushFrameCamera/PushFrameCamera.cpp b/isis/src/base/objs/PushFrameCamera/PushFrameCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0d4ee9935e47f773b5e1c11434a5fbf382d3766 --- /dev/null +++ b/isis/src/base/objs/PushFrameCamera/PushFrameCamera.cpp @@ -0,0 +1,35 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/08/31 15:11:49 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PushFrameCamera.h" + +namespace Isis { + /** + * Constructs the PushFrameCamera object + * + * @param lab Pvl label used to create the parent Camera object + */ + PushFrameCamera::PushFrameCamera (Isis::Pvl &lab) : Camera (lab) { + } +}; + diff --git a/isis/src/base/objs/PushFrameCamera/PushFrameCamera.h b/isis/src/base/objs/PushFrameCamera/PushFrameCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..bcb803e28bfe39058743ce2651d19b6e02853092 --- /dev/null +++ b/isis/src/base/objs/PushFrameCamera/PushFrameCamera.h @@ -0,0 +1,76 @@ +#ifndef FramingCamera_h +#define FramingCamera_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/08/31 15:11:49 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Camera.h" + +namespace Isis { + class PushFrameCameraGroundMap; + class PushFrameCameraDetectorMap; + +/** + * @brief Generic class for Push Frame Cameras + * + * This class is used to abstract out push frame camera functionality from + * children classes. + * + * @author 2009-08-26 Steven Lambright + * + * @internal + * @todo Implement more functionality in this class and abstract away from the children + */ + + class PushFrameCamera : public Camera { + public: + PushFrameCamera(Isis::Pvl &lab); + + virtual CameraType GetCameraType() const { return PushFrame; } + + /** + * Returns a pointer to the PushFrameCameraGroundMap object + * + * @return PushFrameCameraGroundMap* + */ + PushFrameCameraGroundMap *GroundMap() { + return (PushFrameCameraGroundMap *)Camera::GroundMap(); + }; + + /** + * Returns a pointer to the PushFrameCameraDetectorMap object + * + * @return PushFrameCameraDetectorMap* + */ + PushFrameCameraDetectorMap *DetectorMap() { + return (PushFrameCameraDetectorMap *)Camera::DetectorMap(); + }; + + private: + //! Copying cameras is not allowed + PushFrameCamera(const PushFrameCamera &); + //! Assigning cameras is not allowed + PushFrameCamera &operator=(const PushFrameCamera&); + }; +}; + +#endif diff --git a/isis/src/base/objs/PushFrameCamera/PushFrameCamera.truth b/isis/src/base/objs/PushFrameCamera/PushFrameCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..626d305c8e99c1a8b7e660cb5ba8c8ca7af5dfca --- /dev/null +++ b/isis/src/base/objs/PushFrameCamera/PushFrameCamera.truth @@ -0,0 +1,4 @@ +Camera = Framing? 0 +Camera = LineScan? 0 +Camera = PushFrame? 1 +Camera = Radar? 0 diff --git a/isis/src/base/objs/PushFrameCamera/unitTest.cpp b/isis/src/base/objs/PushFrameCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fac30523fa4c3e37f828a5e25a4c60cae842e49b --- /dev/null +++ b/isis/src/base/objs/PushFrameCamera/unitTest.cpp @@ -0,0 +1,22 @@ +#include "PushFrameCamera.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +class MyCamera : public PushFrameCamera { + public: + MyCamera(Isis::Pvl& lab) : Isis::PushFrameCamera(lab) { } +}; + +int main() { + Isis::Preference::Preferences(true); + string inputFile = "$ISIS3DATA/mgs/testData/ab102401.lev2.cub"; + Pvl pvl(inputFile); + MyCamera cam(pvl); + + cout << "Camera = Framing? " << (cam.GetCameraType() == Camera::Framing) << std::endl; + cout << "Camera = LineScan? " << (cam.GetCameraType() == Camera::LineScan) << std::endl; + cout << "Camera = PushFrame? " << (cam.GetCameraType() == Camera::PushFrame) << std::endl; + cout << "Camera = Radar? " << (cam.GetCameraType() == Camera::Radar) << std::endl; +} diff --git a/isis/src/base/objs/PushFrameCameraDetectorMap/Makefile b/isis/src/base/objs/PushFrameCameraDetectorMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..222cc33b8b5b5e747b919e1ebefbf504e4b0e62e --- /dev/null +++ b/isis/src/base/objs/PushFrameCameraDetectorMap/Makefile @@ -0,0 +1,5 @@ +INCS = PushFrameCameraDetectorMap.h +SRCS = PushFrameCameraDetectorMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PushFrameCameraDetectorMap/PushFrameCameraDetectorMap.cpp b/isis/src/base/objs/PushFrameCameraDetectorMap/PushFrameCameraDetectorMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e308a3def20a20765cf7129b1e33527f5e50dcc9 --- /dev/null +++ b/isis/src/base/objs/PushFrameCameraDetectorMap/PushFrameCameraDetectorMap.cpp @@ -0,0 +1,158 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2009/10/21 18:37:02 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "PushFrameCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" + +namespace Isis { + /** Compute parent position from a detector coordinate + * + * This method will compute a parent sample given a + * detector coordinate. The parent line and framelet line + * will be computed. + * + * @param sample Sample number in the detector + * @param line Line number in the detector + * + * @return conversion successful + */ + bool PushFrameCameraDetectorMap::SetDetector(const double sample, + const double line) { + // Sometime folks want to write the framelets flipped in the EDR so + // features match. Take care of this. + double unsummedFrameletLine; + if (p_flippedFramelets) { + unsummedFrameletLine = p_bandStartDetector + p_frameletHeight - line; + } + else { + unsummedFrameletLine = line - p_bandStartDetector; + } + + double unsummedFrameletSample = sample; + + // Convert framelet sample/line to summed framelet sample/line, + // parent sample will be computed correctly + if (!CameraDetectorMap::SetDetector(unsummedFrameletSample,unsummedFrameletLine)) { + return false; + } + + p_frameletSample = p_detectorSample; + p_frameletLine = p_detectorLine; + + // Compute the height of a framelet taking into account the summing mode + int actualFrameletHeight = (int)(p_frameletHeight / LineScaleFactor()); + + p_parentLine = (p_framelet - 1) * actualFrameletHeight + p_parentLine; + + // Save the detector sample/line + p_detectorSample = sample; + p_detectorLine = line; + + // Didn't succeed if framelet line doesn't make sense + if(p_frameletLine > p_frameletHeight + 0.5) { + return false; + } + + if(p_frameletLine < 0.5) { + return false; + } + + return true; + } + + /** Compute detector position from a parent image coordinate + * + * This method will compute the detector position and framelet position + * from the parent line/sample coordinate. The parent line will be used + * to set the appropriate time in the parent camera. + * + * @param sample Sample number in the parent image + * @param line Line number in the parent image + * + * @return conversion successful + */ + bool PushFrameCameraDetectorMap::SetParent(const double sample, + const double line) { + // Compute the height of a framelet taking into account the summing mode + int actualFrameletHeight = (int)(p_frameletHeight / LineScaleFactor()); + + // Compute the framelet number. We could have padded with null framelets + // at the top of the image so take that into account. Setting the framelet + // changes the time for the observation. Line starts at 0.5 (top of first framelet) + // and framelet needs to start at 1. + int framelet = (int)((line - 0.5) / actualFrameletHeight) + 1; + SetFramelet(framelet); + + // Convert the parent line/sample to a framelet line/sample + p_frameletLine = line - actualFrameletHeight * (framelet - 1); + p_frameletSample = sample; + + // Convert the framelet line/sample to an unsummed framelet line/sample + if (!CameraDetectorMap::SetParent(p_frameletSample, p_frameletLine)) return false; + double unsummedFrameletLine = p_detectorLine; + + // Sometime folks want to write the framelets flipped in the EDR so + // features match. Take care of this. p_bandStartDetector is 0-based and + // unsummedFrameletLine is the correct base for p_detectorLine so these calculations + // are valid. + if (p_flippedFramelets) { + p_detectorLine = p_bandStartDetector + p_frameletHeight - unsummedFrameletLine; + } + else { + p_detectorLine = p_bandStartDetector + unsummedFrameletLine; + } + + // Save the parent line/sample + p_parentSample = sample; + p_parentLine = line; + + return true; + } + + /** + * This method changes the current framelet. The camera's ephemeris time + * will be updated to the center of the framelet. + * + * @param framelet Current Framelet + */ + void PushFrameCameraDetectorMap::SetFramelet(int framelet) { + p_framelet = framelet; + + // We can add framelet padding to each band. Compute the adjusted framelet + // number + int adjustedFramelet = (int) framelet - p_frameletOffset; + double etTime = 0.0; + + // Use this information to compute the time of the framelet + if (p_timeAscendingFramelets) { + etTime = p_etStart + (adjustedFramelet - 1) * p_frameletRate; + } + else { + etTime = p_etStart + (p_nframelets - adjustedFramelet) * p_frameletRate; + } + + etTime += p_exposureDuration / 2.0; + p_camera->SetEphemerisTime(etTime); + } +} diff --git a/isis/src/base/objs/PushFrameCameraDetectorMap/PushFrameCameraDetectorMap.h b/isis/src/base/objs/PushFrameCameraDetectorMap/PushFrameCameraDetectorMap.h new file mode 100644 index 0000000000000000000000000000000000000000..465b0d96ddcdde8f54118e896ec7990f3ac53680 --- /dev/null +++ b/isis/src/base/objs/PushFrameCameraDetectorMap/PushFrameCameraDetectorMap.h @@ -0,0 +1,246 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2009/10/21 18:37:02 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef PushFrameCameraDetectorMap_h +#define PushFrameCameraDetectorMap_h + +#include "CameraDetectorMap.h" + +namespace Isis { + /** Convert between parent image coordinates and detector coordinates + * + * This class is used to convert between parent dector coordinates + * (sample/line) and detector coordinates for a push frame camera. + * + * @ingroup Camera + * + * @see Camera + * + * @author 2007-10-15 Steven Lambright + * + * @internal + * @history 2008-06-18 Steven Lambright Added documentation + * @history 2008-10-23 Steven Lambright Added optimizations, fixed misc. bugs + * @history 2009-03-07 Debbie A. Cook Removed reference to obsolute CameraDetectorMap methods + * @history 2009-06-02 Steven Lambright Fixed framelet detection in the + * forward direction and inside framelet check in the reverse + * direction + */ + class PushFrameCameraDetectorMap : public CameraDetectorMap { + public: + /** Construct a detector map for push frame cameras + * + * @param parent The parent camera model for the detector map + * @param etStart starting ephemeris time in seconds + * at the first framelet (not including padded + * framelets). + * @param frameletRate the time in seconds between framelets + * @param frameletHeight Physical height of framelet in lines + * (don't account for summing) + * + */ + PushFrameCameraDetectorMap(Camera *parent, const double etStart, + const double frameletRate, int frameletHeight) : + CameraDetectorMap(parent){ + p_etStart = etStart; + p_exposureDuration = 0.0; + p_frameletRate = frameletRate; + p_frameletHeight = frameletHeight; + p_frameletOffset = 0; + p_flippedFramelets = true; + p_timeAscendingFramelets = true; + p_nframelets = 0; + p_bandStartDetector = 0; + } + + //! Destructor + virtual ~PushFrameCameraDetectorMap() {}; + + /** Reset the starting ephemeris time + * + * Use this method to reset the starting time of the top edge of + * the first line in the parent image. That is the time, prior + * to cropping, scaling, or padding. Usually this will not need + * to be done unless the time changes between bands. + * + * @param etStart starting ephemeris time in seconds + * + */ + void SetStartTime (const double etStart) { p_etStart = etStart;}; + + + /** Change the exposure duration in seconds + * + * Use this method to change the exposure duration of each + * framelet which may be different than the framelet rate. + * + * @param exposureDuration + */ + void SetExposureDuration(double exposureDuration) { + p_exposureDuration = exposureDuration; + } + + + /** Reset the frame rate + * + * Use this method to reset the time between framelets. Usually + * this will not need to be done unless the rate changes between + * bands. + * + * @param frameletRate the time in seconds between framelets + * + */ + void SetFrameletRate (const double frameletRate) { p_frameletRate = frameletRate;}; + + //! Return the time in seconds between framelets + double FrameletRate () const { return p_frameletRate;}; + + /** Reset the frame offset + * + * Use this method to reset the frame offset. Usually this will + * not need to be done unless the offset changes between bands. + * + * @param frameletOffset Number of frames offset in cube + * + */ + void SetFrameletOffset (int frameletOffset) { p_frameletOffset = frameletOffset;}; + + //! Return the frame offset + int FrameletOffset () const { return p_frameletOffset;}; + + virtual bool SetParent(const double sample, const double line); + + virtual bool SetDetector(const double sample, const double line); + + void SetFramelet(int framelet); + + /** + * This method returns the current framelet. This framelet is + * calculated when SetParent is called. + * + * @return int The current framelet + */ + int Framelet() { return p_framelet; } + + + /** Change the starting line in the detector based on band + * + * Use this method to change which line is read out of the + * CCD for any given band. That is, as the virtual SetBand + * method for the specfic camera is invoked this method should + * be called. + * + * @param firstLine 0-based offset to the first line (first line of + * detector = 0) + */ + void SetBandFirstDetectorLine(int firstLine) { p_bandStartDetector = firstLine;} + + //! Return the starting line in the detector for the current band + int GetBandFirstDetectorLine() { return p_bandStartDetector;} + + /** Changes the direction of the framelets + * + * Use this method to change which direction the framelets are ordered. + * In some cases, the top framelet from the raw instrument data has been + * moved to the bottom of the image and this compensates for that. + * + * @param frameletsFlipped False if framelets flipped + * @param nframelets Number of framelets in each band, ignored + * if frameletsFlipped is set to false + */ + void SetFlippedFramelets(bool frameletsFlipped, int nframelets) { + p_timeAscendingFramelets = !frameletsFlipped; + p_nframelets = nframelets; + } + + /** Mirrors the each framelet in the file + * + * Use this method to change which direction the framelets are geometrically + * placed. If the first line in the framelet has been changed to the last line + * in the framelet, then this should be true (DEFAULT). + * + * @param frameletsFlipped True if geometric flip in the framelet + */ + void SetGeometricallyFlippedFramelets(bool frameletsFlipped) { + p_flippedFramelets = frameletsFlipped; + } + + /** + * This returns the starting ET of this band + * + * + * @return double Starting time (often band-dependant) + */ + double StartEphemerisTime () const { return p_etStart; }; + + /** + * Return the total number of framelets including padding + * + * @return int + */ + int TotalFramelets() const + { return (int) (p_camera->ParentLines() / (p_frameletHeight / LineScaleFactor())); }; + + + /** + * This returns the calculated framelet sample + * + * @return double Current framelet sample + */ + double frameletSample() const { return p_frameletSample; }; + + /** + * This returns the calculated framelet line + * + * @return double Current framelet line + */ + double frameletLine() const { return p_frameletLine; }; + + /** + * This returns how many lines are considered a single framelet + * + * @return int Number of lines in a framelet + */ + int frameletHeight() const { return p_frameletHeight; }; + + bool timeAscendingFramelets() { return p_timeAscendingFramelets; } + + private: + double p_etStart; //! +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/PushFrameCameraGroundMap/Makefile b/isis/src/base/objs/PushFrameCameraGroundMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..75bac8069907096c1c7927e2b521c56187ef5e70 --- /dev/null +++ b/isis/src/base/objs/PushFrameCameraGroundMap/Makefile @@ -0,0 +1,5 @@ +INCS = PushFrameCameraGroundMap.h +SRCS = PushFrameCameraGroundMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PushFrameCameraGroundMap/PushFrameCameraGroundMap.cpp b/isis/src/base/objs/PushFrameCameraGroundMap/PushFrameCameraGroundMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c17893b86e33982589ef04edee3ed2bb8472490 --- /dev/null +++ b/isis/src/base/objs/PushFrameCameraGroundMap/PushFrameCameraGroundMap.cpp @@ -0,0 +1,195 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2009/12/07 17:39:26 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "PushFrameCameraGroundMap.h" + +#include "CameraDistortionMap.h" +#include "PushFrameCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" + +namespace Isis { + /** Compute undistorted focal plane coordinate from ground position + * + * @param lat planetocentric latitude in degrees + * @param lon planetocentric longitude in degrees + * + * @return conversion was successful + */ + bool PushFrameCameraGroundMap::SetGround(const double lat, const double lon) { + PushFrameCameraDetectorMap *detectorMap = (PushFrameCameraDetectorMap *) p_camera->DetectorMap(); + + // Get ending bounding framelets and distances for iterative loop to minimize the spacecraft distance + int startFramelet = 1; + double startDist = FindSpacecraftDistance(1, lat, lon); + + int endFramelet = detectorMap->TotalFramelets(); + double endDist = FindSpacecraftDistance(endFramelet, lat, lon); + + bool minimizedSpacecraftDist = false; + + for (int j=0; j<30 && !minimizedSpacecraftDist; j++) { + int deltaX = abs(startFramelet - endFramelet) / 2; + + // start + deltaX = middle framelet. + // We're able to optimize this modified binary search + // because the 'V' shape -- it's mostly parallel. Meaning, + // if the left side is higher than the right, then the + // solution is closer to the right. The bias factor will + // determine how much closer, and then back off a little so + // we dont overshoot it. + double biasFactor = startDist / endDist; + + if(biasFactor < 1.0) { + biasFactor = -1.0 / biasFactor; + biasFactor = -(biasFactor + 1) / biasFactor; + + // The bias is about 50% unsure... sometimes our V is a U + biasFactor = std::min(biasFactor + 0.50, 0.0); + } + else { + biasFactor = (biasFactor - 1) / biasFactor; + + // The bias is about 50% unsure... sometimes our V is a U + biasFactor = std::max(biasFactor - 0.50, 0.0); + } + + int middleFramelet = startFramelet + (int)(deltaX + biasFactor*deltaX); + double middleDist = FindSpacecraftDistance(middleFramelet, lat, lon); + + if(startDist > endDist) { + // This makes sure we don't get stuck halfway between framelets + if(startFramelet == middleFramelet) middleFramelet++; + startFramelet = middleFramelet; + startDist = middleDist; + } + else { + endFramelet = middleFramelet; + endDist = middleDist; + } + + if(startFramelet == endFramelet) { + minimizedSpacecraftDist = true; + } + } + + if(!minimizedSpacecraftDist) { + return false; + } + + int realFramelet = startFramelet; + bool frameletEven = (realFramelet % 2 == 0); + bool timeAscendingFramelets = detectorMap->timeAscendingFramelets(); + + // Do we need to find a neighboring framelet? Get the closest (minimize distance) + if((timeAscendingFramelets && frameletEven != p_evenFramelets) || + (!timeAscendingFramelets && frameletEven == p_evenFramelets)) { + realFramelet ++; // this direction doesnt really matter... it's simply a guess + } + + int direction = 2; + + double realDist = FindDistance(realFramelet, lat, lon); + int guessFramelet = realFramelet + direction; + double guessDist = FindDistance(guessFramelet, lat, lon); + + if(guessDist > realDist) { + direction = -1 * direction; // reverse the search direction + guessFramelet = realFramelet + direction; + guessDist = FindDistance(guessFramelet, lat, lon); + } + + for(int j = 0; (realDist >= guessDist) && (j < 30); j++) { + realFramelet = guessFramelet; + realDist = guessDist; + + guessFramelet = realFramelet + direction; + guessDist = FindDistance(guessFramelet, lat, lon); + + if(realFramelet <= 0 || realFramelet > detectorMap->TotalFramelets()) { + return false; + } + } + + detectorMap->SetFramelet(realFramelet); + + return CameraGroundMap::SetGround(lat,lon); + } + + /** + * This method finds the distance from the center of the framelet to the lat,lon. + * The distance is only in the line direction and is squared. + * + * @param framelet + * @param lat + * @param lon + * + * @return double Y-Distance squared from center of framelet to lat,lon + */ + double PushFrameCameraGroundMap::FindDistance(int framelet, const double lat, const double lon) { + PushFrameCameraDetectorMap *detectorMap = (PushFrameCameraDetectorMap *) p_camera->DetectorMap(); + CameraDistortionMap *distortionMap = (CameraDistortionMap *) p_camera->DistortionMap(); + + detectorMap->SetFramelet(framelet); + if (!p_camera->Sensor::SetUniversalGround (lat,lon,false)) return DBL_MAX; + + double lookC[3]; + p_camera->Sensor::LookDirection(lookC); + double ux = p_camera->FocalLength() * lookC[0] / lookC[2]; + double uy = p_camera->FocalLength() * lookC[1] / lookC[2]; + + if (!distortionMap->SetUndistortedFocalPlane(ux,uy)) return DBL_MAX; + + double dx = distortionMap->FocalPlaneX(); + double dy = distortionMap->FocalPlaneY(); + + CameraFocalPlaneMap *focalMap = p_camera->FocalPlaneMap(); + if (!focalMap->SetFocalPlane(dx,dy)) return DBL_MAX; + + detectorMap->SetDetector(focalMap->DetectorSample(), focalMap->DetectorLine()); + + double actualFrameletHeight = detectorMap->frameletHeight() / detectorMap->LineScaleFactor(); + double frameletDeltaY = detectorMap->frameletLine() - (actualFrameletHeight / 2.0); + + return frameletDeltaY*frameletDeltaY; + } + + /** + * This method finds the distance from the point on the ground to the spacecraft + * at the time the specified framelet was taken. + * + * @param framelet Which framelet was being captured (determines time) + * @param lat Latitude of the point on the ground + * @param lon Longitude of the point on the ground + * + * @return double Distance from spacecraft to the lat,lon + */ + double PushFrameCameraGroundMap::FindSpacecraftDistance(int framelet, const double lat, const double lon) { + PushFrameCameraDetectorMap *detectorMap = (PushFrameCameraDetectorMap *) p_camera->DetectorMap(); + + detectorMap->SetFramelet(framelet); + if (!p_camera->Sensor::SetUniversalGround (lat,lon,false)) return DBL_MAX; + + return p_camera->SlantDistance(); + } +} diff --git a/isis/src/base/objs/PushFrameCameraGroundMap/PushFrameCameraGroundMap.h b/isis/src/base/objs/PushFrameCameraGroundMap/PushFrameCameraGroundMap.h new file mode 100644 index 0000000000000000000000000000000000000000..9a3c39619967a2615e6f955c5f18e799b1f49486 --- /dev/null +++ b/isis/src/base/objs/PushFrameCameraGroundMap/PushFrameCameraGroundMap.h @@ -0,0 +1,76 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2009/12/07 17:39:26 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef PushFrameCameraGroundMap_h +#define PushFrameCameraGroundMap_h + +#include "CameraGroundMap.h" + +namespace Isis { + /** Convert between undistorted focal plane and ground coordinates + * + * This class is used to convert between undistorted focal plane + * coordinates (x/y) in millimeters and ground coordinates lat/lon + * for line scan cameras. + * + * @ingroup Camera + * + * @see Camera + * + * @author 2007-10-17 Steven Lambright and Jeff Anderson + * + * @internal + * @history 2008-06-18 Steven Lambright Fixed documentation + * @history 2008-10-23 Steven Lambright Added optimizations, fixed misc bugs + * @history 2009-11-19 Steven Lambright Removed linear search offset + * @history 2009-12-07 Steven Lambright Increased liklihood that our + * spacecraft distance correctly minimizes for LRO + */ + class PushFrameCameraGroundMap : public CameraGroundMap { + public: + /** + * This is the constructor for the push frame ground map + * + * @param cam Pointer to the camera + * @param evenFramelets True if the image contains even framelets + */ + PushFrameCameraGroundMap(Camera *cam, bool evenFramelets) : + CameraGroundMap(cam) { + p_evenFramelets = evenFramelets; + } + + //! Destructor + virtual ~PushFrameCameraGroundMap() {}; + + virtual bool SetGround(const double lat, const double lon); + + private: + double FindDistance(int framelet, const double lat, const double lon); + double FindSpacecraftDistance(int framelet, + const double lat, + const double lon); + + bool p_evenFramelets; //! +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/Pvl/Makefile b/isis/src/base/objs/Pvl/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..27af515cd83641d23c9baf5e45307379f35da3fc --- /dev/null +++ b/isis/src/base/objs/Pvl/Makefile @@ -0,0 +1,5 @@ +INCS = Pvl.h +SRCS = Pvl.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Pvl/Pvl.cpp b/isis/src/base/objs/Pvl/Pvl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3e63727f3410abee8bfcd4b64d890ac1b48fb50b --- /dev/null +++ b/isis/src/base/objs/Pvl/Pvl.cpp @@ -0,0 +1,497 @@ +/** + * @file + * $Revision: 1.13 $ + * $Date: 2010/06/25 20:40:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "Pvl.h" + +#include +#include + +#include "Filename.h" +#include "iException.h" +#include "Message.h" +#include "PvlTokenizer.h" +#include "PvlFormat.h" + +using namespace std; +namespace Isis { + + //! Constructs an empty Pvl object. + Pvl::Pvl() : Isis::PvlObject("Root") { + Init(); + } + + + /** + * Constructs a Pvl from a file + * + * @param file The file containing the pvl formatted information + */ + Pvl::Pvl(const std::string &file) : Isis::PvlObject("Root") { + Init(); + Read(file); + } + + + //! Copy constructor + Pvl::Pvl(const Pvl &other) : PvlObject::PvlObject(other) { + p_internalTemplate = other.p_internalTemplate; + p_terminator = other.p_terminator; + } + + + //! Initializes the class + void Pvl::Init() { + p_filename = ""; + p_terminator = "End"; + p_internalTemplate = false; + } + + + /** + * Loads PVL information from a stream + * + * @param file A file containing PVL information + * + * @throws Isis::iException::Io + */ + void Pvl::Read(const std::string &file) { + // Expand the filename + Isis::Filename temp(file); + p_filename = temp.Expanded(); + + // Open the file + ifstream istm; + istm.open(p_filename.c_str(), std::ios::in); + if(!istm) { + string message = Isis::Message::FileOpen(temp.Expanded()); + throw Isis::iException::Message(Isis::iException::Io, message, _FILEINFO_); + } + + // Read it + try { + istm >> *this; + } + catch(...) { + istm.close(); + string message = "Unable to read PVL file [" + temp.Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Io, message, _FILEINFO_); + } + istm.close(); + } + + + /** + * Opens and writes PVL information to a file and handles the end of line + * sequence + * + * @param file Name of the file to create. The method will overwrite any + * existing file. + * + * @throws Isis::iException::Io + */ + void Pvl::Write(const std::string &file) { + // Expand the filename + Isis::Filename temp(file); + + // Set up a Formatter + bool removeFormatter = false; + if(GetFormat() == NULL) { + SetFormat(new PvlFormat()); + removeFormatter = true; + } + + // Open the file + ofstream ostm; + string tempName(temp.Expanded()); + ostm.open(tempName.c_str(), std::ios::out); + ostm.seekp(0, std::ios::beg); + if(!ostm) { + string message = Isis::Message::FileCreate(temp.Expanded()); + throw Isis::iException::Message(Isis::iException::Io, message, _FILEINFO_); + } + + // Write the labels + try { + ostm << *this; + if(Terminator() != "") ostm << GetFormat()->FormatEOL(); + } + catch(...) { + ostm.close(); + string message = "Unable to write PVL to file [" + temp.Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Io, message, _FILEINFO_); + } + + if(removeFormatter) { + delete GetFormat(); + SetFormat(NULL); + } + + // Close the file + ostm.close(); + } + + + /** + * Appends PVL information to a file and handles the end of line sequence + * + * @param file Name of the file to append to. + * + * @throws Isis::iException::Io + */ + void Pvl::Append(const std::string &file) { + // Set up for opening and writing + Isis::Filename temp(file); + + // Set up a Formatter + bool removeFormatter = false; + if(GetFormat() == NULL) { + SetFormat(new PvlFormat()); + removeFormatter = true; + } + + // Open the file + ofstream ostm; + string tempName(temp.Expanded()); + ostm.open(tempName.c_str(), std::ios::app); + ostm.seekp(0, std::ios::end); + if(!ostm) { + string message = Isis::Message::FileOpen(temp.Expanded()); + throw Isis::iException::Message(Isis::iException::Io, message, _FILEINFO_); + } + + // Write the labels + try { + ostm << *this; + if(Terminator() != "") ostm << GetFormat()->FormatEOL(); + } + catch(...) { + ostm.close(); + string message = "Unable to append PVL infomation to file [" + + temp.Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Io, message, _FILEINFO_); + } + + if(removeFormatter) { + delete GetFormat(); + SetFormat(NULL); + } + + // Close the file + ostm.close(); + } + + + void Pvl::SetFormatTemplate(Isis::Pvl &temp) { + if(p_internalTemplate) delete p_formatTemplate; + p_internalTemplate = false; + Isis::PvlObject::SetFormatTemplate(temp); + } + + + void Pvl::SetFormatTemplate(const std::string &file) { + if(p_internalTemplate) delete p_formatTemplate; + p_internalTemplate = true; + p_formatTemplate = new Isis::Pvl(file); + } + + + /** + * This stream will not handle the end of line sequence + * + * @param os + * @param pvl + * + * @return ostream& + */ + ostream &operator<<(std::ostream &os, Pvl &pvl) { + // Set up a Formatter + bool removeFormatter = false; + if(pvl.GetFormat() == NULL) { + pvl.SetFormat(new PvlFormat()); + removeFormatter = true; + } + + Isis::Pvl outTemplate; + if(pvl.HasFormatTemplate()) outTemplate = *(Isis::Pvl *)pvl.FormatTemplate(); + + // Look for and process all include files and remove duplicates from the + // format template. Include files take precedence over all other objects and + // groups + Isis::Pvl newTemp; + for(int i = 0; i < outTemplate.Keywords(); i++) { + if(outTemplate[i].IsNamed("Isis:PvlTemplate:File")) { + string filename = outTemplate[i]; + Isis::Filename file(filename); + if(!file.Exists()) { + string message = "Could not open the template file [" + filename + "]"; + throw Isis::iException::Message(Isis::iException::Io, message, _FILEINFO_); + } + Isis::Pvl include(file.Expanded()); + + for(int j = 0; j < include.Keywords(); j++) { + if(!newTemp.HasKeyword(include[j].Name())) + newTemp.AddKeyword(include[j]); + } + + for(int j = 0; j < include.Objects(); j++) { + if(!newTemp.HasObject(include.Object(j).Name())) + newTemp.AddObject(include.Object(j)); + } + + for(int j = 0; j < include.Groups(); j++) { + if(!newTemp.HasGroup(include.Group(j).Name())) + newTemp.AddGroup(include.Group(j)); + } + } + // If it is not an include file add it in place + else if(!newTemp.HasKeyword(outTemplate[i].Name())) + newTemp.AddKeyword(outTemplate[i]); + } + + // copy over the objects + for(int i = 0; i < outTemplate.Objects(); i++) { + if(!newTemp.HasObject(outTemplate.Object(i).Name())) + newTemp.AddObject(outTemplate.Object(i)); + } + + // copy over the groups + for(int i = 0; i < outTemplate.Groups(); i++) { + if(!newTemp.HasGroup(outTemplate.Group(i).Name())) + newTemp.AddGroup(outTemplate.Group(i)); + } + + outTemplate = newTemp; + + // Output the pvl's comments + for(int i = 0; i < pvl.Comments(); i++) { + os << pvl.Comment(i) << pvl.GetFormat()->FormatEOL(); + if(i == (pvl.Comments() - 1)) os << pvl.GetFormat()->FormatEOL(); + } + + // Output the keywords + if(pvl.Keywords() > 0) { + os << (Isis::PvlContainer &) pvl << pvl.GetFormat()->FormatEOL(); + } + + // this number keeps track of the number of objects that have been written + int numObjects = 0; + + // Output the objects using the format template + for(int i = 0; i < outTemplate.Objects(); i++) { + for(int j = 0; j < pvl.Objects(); j++) { + if(outTemplate.Object(i).Name() != pvl.Object(j).Name()) continue; + if(numObjects == 0 && pvl.Keywords() > 0) os << pvl.GetFormat()->FormatEOL(); + pvl.Object(j).SetIndent(pvl.Indent()); + pvl.Object(j).SetFormatTemplate(outTemplate.Object(i)); + pvl.Object(j).SetFormat(pvl.GetFormat()); + os << pvl.Object(j) << pvl.GetFormat()->FormatEOL(); + pvl.Object(j).SetFormat(NULL); + pvl.Object(j).SetIndent(0); + if(++numObjects < pvl.Objects()) os << pvl.GetFormat()->FormatEOL(); + } + } + + // Output the objects that were not included in the format template pvl + for(int i = 0; i < pvl.Objects(); i++) { + if(outTemplate.HasObject(pvl.Object(i).Name())) continue; + if(numObjects == 0 && pvl.Keywords() > 0) os << pvl.GetFormat()->FormatEOL(); + pvl.Object(i).SetIndent(pvl.Indent()); + pvl.Object(i).SetFormat(pvl.GetFormat()); + os << pvl.Object(i) << pvl.GetFormat()->FormatEOL(); + pvl.Object(i).SetFormat(NULL); + pvl.Object(i).SetIndent(0); + if(++numObjects < pvl.Objects()) os << pvl.GetFormat()->FormatEOL(); + } + + // this number keeps track of the number of groups that have been written + int numGroups = 0; + + // Output the groups using the format template + for(int i = 0; i < outTemplate.Groups(); i++) { + for(int j = 0; j < pvl.Groups(); j++) { + if(outTemplate.Group(i).Name() != pvl.Group(j).Name()) continue; + if((numGroups == 0) && + (pvl.Objects() > 0 || pvl.Keywords() > 0)) os << pvl.GetFormat()->FormatEOL(); + pvl.Group(j).SetIndent(pvl.Indent()); + pvl.Group(j).SetFormatTemplate(outTemplate.Group(i)); + pvl.Group(j).SetFormat(pvl.GetFormat()); + os << pvl.Group(j) << pvl.GetFormat()->FormatEOL(); + pvl.Group(j).SetFormat(NULL); + pvl.Group(j).SetIndent(0); + if(++numGroups < pvl.Groups()) os << pvl.GetFormat()->FormatEOL(); + } + } + + // Output the groups that were not in the format template + for(int i = 0; i < pvl.Groups(); i++) { + if(outTemplate.HasGroup(pvl.Group(i).Name())) continue; + if((numGroups == 0) && + (pvl.Objects() > 0 || pvl.Keywords() > 0)) os << pvl.GetFormat()->FormatEOL(); + pvl.Group(i).SetIndent(pvl.Indent()); + pvl.Group(i).SetFormat(pvl.GetFormat()); + os << pvl.Group(i) << pvl.GetFormat()->FormatEOL(); + pvl.Group(i).SetFormat(NULL); + pvl.Group(i).SetIndent(0); + if(++numGroups < pvl.Groups()) os << pvl.GetFormat()->FormatEOL(); + } + + // Output the terminator + if(pvl.Terminator() != "") { + os << pvl.Terminator(); + } + + if(removeFormatter) { + delete pvl.GetFormat(); + pvl.SetFormat(NULL); + } + + return os; + } + + + /** + * Reads keywords from the instream and appends them to the Pvl object. + * + * @param is A specified instream to read from. + * @param pvl The Pvl object to append to. + * @throws iException Invalid PVL format specified. + * @return Returns the entered instream after reading from it. + */ + istream &operator>>(std::istream &is, Pvl &pvl) { + if(!is.good()) { + string msg = "Tried to read input stream with an error state into a Pvl"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + try { + PvlKeyword termination("End"); + + PvlKeyword errorKeywords[] = { + PvlKeyword("EndGroup"), + PvlKeyword("EndObject") + }; + + PvlKeyword readKeyword; + istream::pos_type beforeKeywordPos = is.tellg(); + + is >> readKeyword; + + while(readKeyword != termination) { + for(unsigned int errorKey = 0; + errorKey < sizeof(errorKeywords) / sizeof(PvlKeyword); + errorKey++) { + if(readKeyword == errorKeywords[errorKey]) { + is.seekg(beforeKeywordPos, ios::beg); + + string msg = "Unexpected ["; + msg += readKeyword.Name(); + msg += "] in Object [ROOT]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + } + + if(readKeyword == PvlKeyword("Group")) { + is.seekg(beforeKeywordPos); + PvlGroup newGroup; + is >> newGroup; + pvl.AddGroup(newGroup); + } + else if(readKeyword == PvlKeyword("Object")) { + is.seekg(beforeKeywordPos); + PvlObject newObject; + is >> newObject; + pvl.AddObject(newObject); + } + else { + pvl.AddKeyword(readKeyword); + } + + readKeyword = PvlKeyword(); + beforeKeywordPos = is.tellg(); + + // non-whitespace non-ascii says we're done + if(is.good() && (is.peek() < 32 || is.peek() > 126)) { + // fake eof (binary data) + break; + } + + if(is.good()) { + is >> readKeyword; + } + else { + // eof + break; + } + } + + return is; + } + catch(iException &e) { + if(is.eof() && !is.bad()) { + is.clear(); + is.unget(); + } + + istream::pos_type errorPos = is.tellg(); + if((int)errorPos == -1) throw; + + is.seekg(0, ios::end); + istream::pos_type fileEndPos = is.tellg(); + + is.seekg(0, ios::beg); + long lineNumber = 1; + + if((int)is.tellg() == -1) throw; + + while(is.good() && is.tellg() < errorPos) { + char next = is.get(); + + if(!isprint(next) && !isspace(next)) { + is.seekg(errorPos, ios::beg); + } + else if(next == '\n') { + lineNumber ++; + } + } + + string msg; + if(lineNumber > 0) { + msg = "Error in pvl on line ["; + msg += iString((Isis::BigInt)lineNumber); + msg += "]"; + } + + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + } + + + //! This is an assignment operator + const Pvl &Pvl::operator=(const Pvl &other) { + this->PvlObject::operator=(other); + + p_internalTemplate = other.p_internalTemplate; + p_terminator = other.p_terminator; + + return *this; + } + +} //end namespace isis diff --git a/isis/src/base/objs/Pvl/Pvl.h b/isis/src/base/objs/Pvl/Pvl.h new file mode 100644 index 0000000000000000000000000000000000000000..29cbc1888a421d21a7558ee5737555afd7760a42 --- /dev/null +++ b/isis/src/base/objs/Pvl/Pvl.h @@ -0,0 +1,180 @@ +#ifndef Pvl_h +#define Pvl_h + +/** + * @file + * $Revision: 1.9 $ + * $Date: 2010/06/25 20:40:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "PvlObject.h" + +namespace Isis { + /** + * @brief Container for cube-like labels + * + * This class is used for creating, reading, and writing grouped labels + * generally from a file. An example of a label is: + * @code + * Group = Cube + * Samples = 512 + * Lines = 512 + * Bands = 1 + * EndGroup + * @endcode + * There are three different groupings, "root", "object", and "group". The + * information is stored in "keywords". The root grouping can contain objects, + * groups, and keywords. Object groupings can contain other objects, groups + * and keywords. Group groupings can only contain keywords. Contents within the + * group are called keywords which can have integer, double, string values or + * no value. A keyword with no value is treated as a boolean. + * + * If you would like to see Pvl being used in implementation, + * see class Cube or Preference + * + * @ingroup Parsing + * + * @author 2002-10-11 Jeff Anderson + * + * @internal + * @history 2003-01-31 Jeff Anderson - Added Keywords, Keyword, Groups, Group, + * and CopyGroup methods + * @history 2003-03-27 Jeff Anderson - Fixed problem caused by new compiler + * when attempting to left justify streams. + * Depricated the ReadInternal and + * WriteInternali methods. They were + * replaced by Read and Write methods. + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-08-18 Stuart Sides - Modified so labels with repeated objects, + * groups and keywords could be read in. + * @history 2003-09-25 Stuart Sides - Modified "keyword does not exist message" + * so it has two forms. One which says the + * keyword was not found at all and the + * other says the requested occurance was + * not found. + * @history 2003-09-26 Stuart Sides - Modified constructors to take a bool + * parameter which tells many member + * functions if they should allow + * duplacates or not. Also took the + * allowDuplicates parameter off all of the + * members who used it. + * @history 2003-10-15 Jeff Anderson - Modified write method to place quotes + * around null parameters (e.g. "") + * @history 2003-10-22 Stuart Sides - Added new method Insert. + * @history 2003-11-06 Jeff Anderson - Modify UpdateKeyword methods so that + * they do not throw errors if the keyword + * does not exist. That is, they simply + * add a new keyword. + * @history 2003-11-06 Jeff Anderson - Modify WriteContainer method to put a + * space between the value and unit of + * keywords. + * @history 2003-11-06 Jeff Anderson - Added Merge method + * @history 2003-12-01 Stuart Sides - Added new occurrence parameter to + * UseGroup. And added new member + * GroupOccurrences. + * @history 2004-01-22 Jeff Anderson - Fixed iterator out of bounds when + * parsing for units if the PVL terminated + * with and EOF instead of the usual END + * statement + * @history 2004-02-10 Jeff Anderson - Added new suite of AddKeyword methods + * for vectors which take a single unit + * instead of a vector of units + * @history 2004-02-10 Jeff Anderson - Modified parse and write methods to + * properly handle a single unit on + * vectors + * @history 2004-02-11 Jeff Anderson - Implemented GetUnits method and added + * AddKeyword method with a NULL value + * @history 2004-02-20 Jeff Anderson - Fixed a bug in the Merge method that + * was unwinding the container pointer too + * far. + * @history 2005-02-14 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-02-23 Elizabeth Ribelin - Fixed unitTest + * @history 2005-03-07 Leah Dahmer - Added missing documentation to class. + * @history 2006-04-21 Jacob Danton Added format templates abilities. + * @history 2006-08-30 Stuart Sides & Brendan George - Added ability to output + * in PDS format. + * @history 2007-04-13 Stuart Sides - Added new test for long + * strings + * @history 2008-02-27 Stuart Sides - Fixed memory leak in + * output operator + * @history 2008-07-10 Steven Lambright - Changed StringEqual to use + * PvlKeyword::StringEqual + * @history 2008-10-2 Christopher Austin - Replaced all std::endl in the << + * operator, Write() and Append() with PvlFormat.FormatEOL() + * @history 2009-12-17 Steven Lambright - Rewrote read (istream operator) + * @history 2010-04-13 Eric Hyer - Added copy constructor + * - Added assignment operator + * @history 2010-06-25 Steven Lambright - Quicker to give up + * counting line numbers on error + * + * @todo 2005-02-14 add coded example to class documentation. + */ + class Pvl : public Isis::PvlObject { + public: + Pvl(); + Pvl(const std::string &file); + Pvl(const Pvl &other); + + friend std::istream &operator>>(std::istream &is, Pvl &pvl); + friend std::ostream &operator<<(std::ostream &os, Isis::Pvl &pvl); + + ~Pvl() { + if(p_internalTemplate) delete p_formatTemplate; + }; + + void Read(const std::string &file); + + void Write(const std::string &file); + void Append(const std::string &file); + + /** + * Sets the terminator used to signify the end of the PVL + * informationDefaults to "END" + * + * @param term The user-defined terminator + */ + void SetTerminator(const std::string &term) { + p_terminator = term; + }; + /** + * Returns the terminator used to signify the end of the PVL + * informationDefaults to "END". + * + * @return The terminator used by the Pvl object. + */ + std::string Terminator() const { + return p_terminator; + }; + + void SetFormatTemplate(Isis::Pvl &temp); + void SetFormatTemplate(const std::string &filename); + + const Pvl &operator=(const Pvl &other); + + private: + void Init(); + bool p_internalTemplate; + std::string p_terminator; /** +BIG_HUGE_LONG_NAME_THAT_SHOULD_TEST_OUT_PARSING = "Seven thousand eight + hundred forty three million + seventy four" +ARRAY_TEST = (5.87 , + 5465.6 , + 574.6 , + 42 ) +FIRST_100_DIGITS_OF_PI = 3.1415926535897932384626433- + 832795028841971693993751058- + 209749445923078164062862089- + 986280348253421170679 +A = XXXXXXXXXXxxxxxxxxxxXXXXXXX- + XXXxxxxxxxxxxXXXXXXXXXXxxxx- + xxxxxxXXXXXXXXXXxxxx +UGHHHHHHHHHHHH = (59999.0, 59999.0, 59999.0, + 59999.0, 59999.0, 59999.0, + 59999.0, 59999.0, 59999.0, + 59999.0, 59999.0, 59999.0) +NAME = 5.2 +KEY = Null + +# Hello World! This is a really really long comment that needs to be +# wrapped onto several different lines to make the PVL file look really +# pretty! +KEY = (5, Null, 3.3 , + "Hello World!") + +# Hello World! This is a really really long comment that needs to be +# wrapped onto several different lines to make the PVL file look really +# pretty! +KEY = (5, 88, 3.3 , + "Hello World!") +dog = Big + +# Big +Cat = (Big, Tabby) +key = ((a, b, c), ("Hubba Hubba", + Bubba)) +End + +temp = (a, b, c) +End + +**unitTest2.pvl] +**PVL ERROR** Error in pvl on line [9] +**PVL ERROR** Unable to read keyword [Dog = Big Dog] +**PVL ERROR** Keyword has extraneous data [Dog] at the end + +**unitTest3.pvl] +**PVL ERROR** Error in pvl on line [12] +**PVL ERROR** Unexpected [EndGroup] in Object [A] + +Testing MESSENGER labels with data at bottom... + +PDS_VERSION_ID = PDS3 + +/* ** FILE FORMAT ** */ +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 1024 +FILE_RECORDS = 1031 +LABEL_RECORDS = 0007 + +/* ** POINTERS TO START BYTE OFFSET OF OBJECTS IN IMAGE FILE ** */ +^IMAGE = 0008 + +/* ** GENERAL DATA DESCRIPTION PARAMETERS ** */ +MISSION_NAME = MESSENGER +INSTRUMENT_HOST_NAME = MESSENGER +DATA_SET_ID = MESS-E/V/H-MDIS-2-EDR-RAWDATA-V1.0 +DATA_QUALITY_ID = 0000000000000000 +PRODUCT_ID = EN0131771763M +PRODUCT_VERSION_ID = 3 +SOURCE_PRODUCT_ID = 0131771763_IM5 +PRODUCER_INSTITUTION_NAME = "APPLIED COHERENT TECHNOLOGY CORPORATION" +SOFTWARE_NAME = MDIS2EDR +SOFTWARE_VERSION_ID = 0.7 +MISSION_PHASE_NAME = "MERCURY 2 FLYBY" +TARGET_NAME = MERCURY +SEQUENCE_NAME = 08280_DEP_NAC_MOSAIC_2 +OBSERVATION_ID = 6623 + +/* ** TIME PARAMETERS ** */ +START_TIME = 2008-10-06T09:12:00.325595 +STOP_TIME = 2008-10-06T09:12:00.339595 +SPACECRAFT_CLOCK_START_COUNT = 1/0131771763:976000 +SPACECRAFT_CLOCK_STOP_COUNT = 1/0131771763:990000 +PRODUCT_CREATION_TIME = 2009-12-14T21:38:50 + +/* ** INSTRUMENT ENGINEERING PARAMETERS ** */ +INSTRUMENT_NAME = "MERCURY DUAL IMAGING SYSTEM NARROW ANGLE + CAMERA" +INSTRUMENT_ID = MDIS-NAC +FILTER_NAME = "748 BP 53" +FILTER_NUMBER = N/A +CENTER_FILTER_WAVELENGTH = 747.7 +BANDWIDTH = 52.6 +EXPOSURE_DURATION = 14 +EXPOSURE_TYPE = AUTO +DETECTOR_TEMPERATURE = -37.62 +FOCAL_PLANE_TEMPERATURE = -28.76 +FILTER_TEMPERATURE = N/A +OPTICS_TEMPERATURE = -28.61 + +/* ** INSTRUMENT RAW PARAMETERS ** */ +MESS:MET_EXP = 131771763 +MESS:IMG_ID_LSB = N/A +MESS:IMG_ID_MSB = N/A +MESS:ATT_CLOCK_COUNT = 131771761 +MESS:ATT_Q1 = -0.49568507 +MESS:ATT_Q2 = -0.63451749 +MESS:ATT_Q3 = 0.35215572 +MESS:ATT_Q4 = -0.47714800 +MESS:ATT_FLAG = 7 +MESS:PIV_POS_MOTOR = N/A +MESS:PIV_GOAL = 7895 +MESS:PIV_POS = 7896 +MESS:PIV_READ = 23068 +MESS:PIV_CAL = -26758 +MESS:FW_GOAL = 6492 +MESS:FW_POS = 6436 +MESS:FW_READ = 6436 +MESS:CCD_TEMP = 1044 +MESS:CAM_T1 = 468 +MESS:CAM_T2 = 496 +MESS:EXPOSURE = 14 +MESS:DPU_ID = 0 +MESS:IMAGER = 1 +MESS:SOURCE = 0 +MESS:FPU_BIN = 0 +MESS:COMP12_8 = 1 +MESS:COMP_ALG = 2 +MESS:COMP_FST = 1 +MESS:TIME_PLS = 2 +MESS:LATCH_UP = 0 +MESS:EXP_MODE = 1 +MESS:PIV_STAT = 3 +MESS:PIV_MPEN = 1 +MESS:PIV_PV = 1 +MESS:PIV_RV = 1 +MESS:FW_PV = 1 +MESS:FW_RV = 1 +MESS:AEX_STAT = 512 +MESS:AEX_STHR = 5 +MESS:AEX_TGTB = 2400 +MESS:AEX_BACB = 240 +MESS:AEX_MAXE = 14 +MESS:AEX_MINE = 1 +MESS:DLNKPRIO = 5 +MESS:WVLRATIO = 8 +MESS:PIXELBIN = 0 +MESS:SUBFRAME = 0 +MESS:SUBF_X1 = 4 +MESS:SUBF_Y1 = 0 +MESS:SUBF_DX1 = 0 +MESS:SUBF_DY1 = 0 +MESS:SUBF_X2 = 4 +MESS:SUBF_Y2 = 0 +MESS:SUBF_DX2 = 0 +MESS:SUBF_DY2 = 0 +MESS:SUBF_X3 = 0 +MESS:SUBF_Y3 = 0 +MESS:SUBF_DX3 = 0 +MESS:SUBF_DY3 = 0 +MESS:SUBF_X4 = 0 +MESS:SUBF_Y4 = 0 +MESS:SUBF_DX4 = 0 +MESS:SUBF_DY4 = 0 +MESS:SUBF_X5 = 0 +MESS:SUBF_Y5 = 0 +MESS:SUBF_DX5 = 0 +MESS:SUBF_DY5 = 0 +MESS:CRITOPNV = 0 +MESS:JAILBARS = 0 +MESS:JB_X0 = 0 +MESS:JB_X1 = 0 +MESS:JB_SPACE = 0 + +/* ** GEOMETRY INFORMATION ** */ +RIGHT_ASCENSION = 329.96796 +DECLINATION = -11.56931 +TWIST_ANGLE = 13.73197 +RA_DEC_REF_PIXEL = (512.00000, 512.00000) +RETICLE_POINT_RA = (329.41279, 330.88844, 329.04957, + 330.52952) +RETICLE_POINT_DECLINATION = (-12.47527, -12.12267, -11.02525, + -10.67174) + +/* ** TARGET PARAMETERS ** */ +SC_TARGET_POSITION_VECTOR = (-8919.18729, 5554.99303, 3662.51393) +TARGET_CENTER_DISTANCE = 11127.61690 + +/* ** TARGET WITHIN SENSOR FOV ** */ +SLANT_DISTANCE = 9115.65447 +CENTER_LATITUDE = 24.03182 +CENTER_LONGITUDE = 297.29424 +HORIZONTAL_PIXEL_SCALE = 232.40761 +VERTICAL_PIXEL_SCALE = 232.40761 +SMEAR_MAGNITUDE = 0.10555 +SMEAR_AZIMUTH = 94.46806 +NORTH_AZIMUTH = 108.06205 +RETICLE_POINT_LATITUDE = (21.08301, 20.54907, 27.64956, 27.16452) +RETICLE_POINT_LONGITUDE = (301.32304, 295.12377, 299.48568, + 292.69017) + +/* ** SPACECRAFT POSITION WITH RESPECT TO CENTRAL BODY ** */ +SUB_SPACECRAFT_LATITUDE = -1.04438 +SUB_SPACECRAFT_LONGITUDE = 315.57322 +SPACECRAFT_ALTITUDE = 8687.61690 +SUB_SPACECRAFT_AZIMUTH = 243.13066 + +/* ** SPACECRAFT LOCATION ** */ +SPACECRAFT_SOLAR_DISTANCE = 51220537.58833 +SC_SUN_POSITION_VECTOR = (50079853.32484, 10735834.95784, + 541857.50763) +SC_SUN_VELOCITY_VECTOR = (24.24499, -44.99506, -26.54238) + +/* ** VIEWING AND LIGHTING GEOMETRY (SUN ON TARGET) ** */ +SOLAR_DISTANCE = 51228055.72874 +SUB_SOLAR_AZIMUTH = 194.38217 +SUB_SOLAR_LATITUDE = -0.01056 +SUB_SOLAR_LONGITUDE = 3.05715 +INCIDENCE_ANGLE = 67.98720 +PHASE_ANGLE = 43.57603 +EMISSION_ANGLE = 38.58010 +LOCAL_HOUR_ANGLE = 114.23708 + +Object = IMAGE + LINES = 1024 + LINE_SAMPLES = 1024 + SAMPLE_TYPE = MSB_UNSIGNED_INTEGER + SAMPLE_BITS = 8 + UNIT = N/A + DARK_STRIP_MEAN = 10.107 + + /* ** IMAGE STATISTICS OF ** */ + /* ** THE EXPOSED CCD AREA ** */ + MINIMUM = 16.000 + MAXIMUM = 124.000 + MEAN = 65.736 + STANDARD_DEVIATION = 8.835 + + /* ** PIXEL COUNTS ** */ + SATURATED_PIXEL_COUNT = 0 + MISSING_PIXELS = 0 +End_Object + +/* ** GEOMETRY FOR EACH SUBFRAME ** */ +Group = SUBFRAME1_PARAMETERS + RETICLE_POINT_LATITUDE = (N/A, N/A, N/A, N/A) + RETICLE_POINT_LONGITUDE = (N/A, N/A, N/A, N/A) +End_Group + +Group = SUBFRAME2_PARAMETERS + RETICLE_POINT_LATITUDE = (N/A, N/A, N/A, N/A) + RETICLE_POINT_LONGITUDE = (N/A, N/A, N/A, N/A) +End_Group + +Group = SUBFRAME3_PARAMETERS + RETICLE_POINT_LATITUDE = (N/A, N/A, N/A, N/A) + RETICLE_POINT_LONGITUDE = (N/A, N/A, N/A, N/A) +End_Group + +Group = SUBFRAME4_PARAMETERS + RETICLE_POINT_LATITUDE = (N/A, N/A, N/A, N/A) + RETICLE_POINT_LONGITUDE = (N/A, N/A, N/A, N/A) +End_Group + +Group = SUBFRAME5_PARAMETERS + RETICLE_POINT_LATITUDE = (N/A, N/A, N/A, N/A) + RETICLE_POINT_LONGITUDE = (N/A, N/A, N/A, N/A) +End_Group +End + diff --git a/isis/src/base/objs/Pvl/unitTest.cpp b/isis/src/base/objs/Pvl/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b6e08315a17b677883f50cc498ef436617628d1 --- /dev/null +++ b/isis/src/base/objs/Pvl/unitTest.cpp @@ -0,0 +1,136 @@ +#include "Pvl.h" +#include "iException.h" +#include "Preference.h" + +#include +#include + +using namespace Isis; +using namespace std; + +int main() { + Preference::Preferences(true); + + Pvl p; + p += PvlKeyword("LongKeyword", "This is a very long keyword value which " + "was causing some problems when the Pvl was output." + " The fist couple of lines looked good, but after that " + "things went south. Some lines get nothing, others get" + " bad indenting, most were too short"); + + cout << "p: " << p << "\n"; + Pvl &ref = p; + Pvl copy(p); + copy.DeleteKeyword("LongKeyword"); + cout << "copy deleted a keyword...\np: " << p << "\n\ncopy: " << copy << "\n\n\n"; + + PvlGroup g("Test"); + g += PvlKeyword("Keyword", "Value"); + p.AddGroup(g); + + p.SetTerminator(""); + ref.Write("tmp.unitTest"); + p.Append("tmp.unitTest"); + + Pvl p2; + p2.Read("tmp.unitTest"); + cout << p2 << endl << endl; + + Pvl p3; + p3.Read("unitTest.pvl"); + cout << p3 << endl << endl; + + stringstream os; + os << "temp = (a,b,c)"; + + Pvl p4; + os >> p4; + cout << p4 << endl << endl; + remove("tmp.unitTest"); + + try { + Pvl p5; + p5.Read("unitTest2.pvl"); + cout << p5 << endl << endl; + } + catch(iException &e) { + cout.flush(); + + // make this error work regardless of directory... + string errors = e.Errors(); + + while(errors.find("/") != string::npos) { + int pos = errors.find("/"); + + if(errors.find("/", pos + 1) < errors.find("]")) { + errors = errors.substr(0, pos + 1) + + errors.substr(errors.find("/", pos + 1) + 1); + } + else { + errors = errors.substr(0, pos - 1) + errors.substr(pos + 1); + } + } + + cout << errors; + e.Clear(); + } + + cout << endl << endl; + + try { + Pvl p6; + p6.Read("unitTest3.pvl"); + cout << p6 << endl << endl; + } + catch(iException &e) { + cout.flush(); + + // make this error work regardless of directory... + string errors = e.Errors(); + + while(errors.find("/") != string::npos) { + int pos = errors.find("/"); + + if(errors.find("/", pos + 1) < errors.find("]")) { + errors = errors.substr(0, pos + 1) + + errors.substr(errors.find("/", pos + 1) + 1); + } + else { + errors = errors.substr(0, pos - 1) + errors.substr(pos + 1); + } + } + + cout << errors; + e.Clear(); + } + + cout << endl << endl; + + cout << "Testing MESSENGER labels with data at bottom..." << endl << endl; + try { + Pvl p7; + p7.Read("unitTest4.pvl"); + cout << p7 << endl << endl; + } + catch(iException &e) { + cout.flush(); + + // make this error work regardless of directory... + string errors = e.Errors(); + + while(errors.find("/") != string::npos) { + int pos = errors.find("/"); + + if(errors.find("/", pos + 1) < errors.find("]")) { + errors = errors.substr(0, pos + 1) + + errors.substr(errors.find("/", pos + 1) + 1); + } + else { + errors = errors.substr(0, pos - 1) + errors.substr(pos + 1); + } + } + + cout << errors; + e.Clear(); + } +} diff --git a/isis/src/base/objs/Pvl/unitTest.pvl b/isis/src/base/objs/Pvl/unitTest.pvl new file mode 100644 index 0000000000000000000000000000000000000000..16de2e79bf2b357eea85b7a144c0263aefa4dd67 --- /dev/null +++ b/isis/src/base/objs/Pvl/unitTest.pvl @@ -0,0 +1,34 @@ +THE_INTERNET = "Seven thousand eight hundred forty three million seventy four + nine seventy six forty two eighty nine sixty seven thirty five + million jillion bajillion google six nine four one two three + four five six seven eight nine ten eleven twelve thirteen + fourteen" +BIG_HUGE_LONG_NAME_THAT_SHOULD_TEST_OUT_PARSING = "Seven thousand eight + hundred forty three million + seventy four" +ARRAY_TEST = (5.87 , 5465.6 , 574.6 , + 42 ) +FIRST_100_DIGITS_OF_PI = 3.14159265358979323846264338327950288419716939937510- + 58209749445923078164062862089986280348253421170679 +A = XXXXXXXXXXxxxxxxxxxxXXXXXXXXXXxxxxxxxxxxXXXXXXXXXXxxxxxxxxxxXXXXXXXXXXxxxx +UGHHHHHHHHHHHH = (59999.0, 59999.0, 59999.0, 59999.0, 59999.0, 59999.0, + 59999.0, 59999.0, 59999.0, 59999.0, 59999.0, 59999.0) +NAME = 5.2 +KEY = Null +# Hello World! This is a really really long comment that needs to be +# wrapped onto several different lines to make the PVL file look really +# pretty! +KEY = (5, Null, 3.3 , "Hello World!") + +# Hello World! This is a really really long comment that needs to be +# wrapped onto several different lines to make the PVL file look really +# pretty! +KEY = (5, 88, 3.3 , "Hello World!") +dog = Big + +# Big +Cat = (Big, Tabby) + +key = ((a, b, c), ("Hubba Hubba", Bubba)) + +# Some Junk Comment diff --git a/isis/src/base/objs/Pvl/unitTest2.pvl b/isis/src/base/objs/Pvl/unitTest2.pvl new file mode 100644 index 0000000000000000000000000000000000000000..efb595f0cc667bd85c15c62a5d5db510c1c8d578 --- /dev/null +++ b/isis/src/base/objs/Pvl/unitTest2.pvl @@ -0,0 +1,12 @@ +Object = A + Object = B + + Key = Value + EndObject + + Object = C + Group = D + Dog = Big Dog + EndGroup + EndObject +EndObject diff --git a/isis/src/base/objs/Pvl/unitTest3.pvl b/isis/src/base/objs/Pvl/unitTest3.pvl new file mode 100644 index 0000000000000000000000000000000000000000..95419c9afbdab822da7d330b7c5a28cdb1f24657 --- /dev/null +++ b/isis/src/base/objs/Pvl/unitTest3.pvl @@ -0,0 +1,12 @@ +Object = A + Object = B + + Key = Value + EndObject + + Object = C + Group = D + Dog = Big + EndGroup + EndObject +EndGroup diff --git a/isis/src/base/objs/Pvl/unitTest4.pvl b/isis/src/base/objs/Pvl/unitTest4.pvl new file mode 100644 index 0000000000000000000000000000000000000000..0e5a4e86768f3e15e97bd82e92b960813c878b6d --- /dev/null +++ b/isis/src/base/objs/Pvl/unitTest4.pvl @@ -0,0 +1,224 @@ +PDS_VERSION_ID = PDS3 + +/* ** FILE FORMAT ** */ +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 1024 +FILE_RECORDS = 1031 +LABEL_RECORDS = 0007 + +/* ** POINTERS TO START BYTE OFFSET OF OBJECTS IN IMAGE FILE ** */ +^IMAGE = 0008 + +/* ** GENERAL DATA DESCRIPTION PARAMETERS ** */ +MISSION_NAME = "MESSENGER" +INSTRUMENT_HOST_NAME = "MESSENGER" +DATA_SET_ID = "MESS-E/V/H-MDIS-2-EDR-RAWDATA-V1.0" +DATA_QUALITY_ID = "0000000000000000" +PRODUCT_ID = "EN0131771763M" +PRODUCT_VERSION_ID = "3" +SOURCE_PRODUCT_ID = ("0131771763_IM5") +PRODUCER_INSTITUTION_NAME = "APPLIED COHERENT TECHNOLOGY CORPORATION" +SOFTWARE_NAME = "MDIS2EDR" +SOFTWARE_VERSION_ID = "0.7" +MISSION_PHASE_NAME = "MERCURY 2 FLYBY" +TARGET_NAME = "MERCURY" +SEQUENCE_NAME = "08280_DEP_NAC_MOSAIC_2" +OBSERVATION_ID = "6623" + +/* ** TIME PARAMETERS ** */ +START_TIME = 2008-10-06T09:12:00.325595 +STOP_TIME = 2008-10-06T09:12:00.339595 +SPACECRAFT_CLOCK_START_COUNT = "1/0131771763:976000" +SPACECRAFT_CLOCK_STOP_COUNT = "1/0131771763:990000" +PRODUCT_CREATION_TIME = 2009-12-14T21:38:50 + +/* ** INSTRUMENT ENGINEERING PARAMETERS ** */ +INSTRUMENT_NAME = "MERCURY DUAL IMAGING SYSTEM NARROW ANGLE CAMERA" +INSTRUMENT_ID = "MDIS-NAC" +FILTER_NAME = "748 BP 53" +FILTER_NUMBER = "N/A" +CENTER_FILTER_WAVELENGTH = 747.7 +BANDWIDTH = 52.6 +EXPOSURE_DURATION = 14 +EXPOSURE_TYPE = AUTO +DETECTOR_TEMPERATURE = -37.62 +FOCAL_PLANE_TEMPERATURE = -28.76 +FILTER_TEMPERATURE = "N/A" +OPTICS_TEMPERATURE = -28.61 + +/* ** INSTRUMENT RAW PARAMETERS ** */ +MESS:MET_EXP = 131771763 +MESS:IMG_ID_LSB = "N/A" +MESS:IMG_ID_MSB = "N/A" +MESS:ATT_CLOCK_COUNT = 131771761 +MESS:ATT_Q1 = -0.49568507 +MESS:ATT_Q2 = -0.63451749 +MESS:ATT_Q3 = 0.35215572 +MESS:ATT_Q4 = -0.47714800 +MESS:ATT_FLAG = 7 +MESS:PIV_POS_MOTOR = "N/A" +MESS:PIV_GOAL = 7895 +MESS:PIV_POS = 7896 +MESS:PIV_READ = 23068 +MESS:PIV_CAL = -26758 +MESS:FW_GOAL = 6492 +MESS:FW_POS = 6436 +MESS:FW_READ = 6436 +MESS:CCD_TEMP = 1044 +MESS:CAM_T1 = 468 +MESS:CAM_T2 = 496 +MESS:EXPOSURE = 14 +MESS:DPU_ID = 0 +MESS:IMAGER = 1 +MESS:SOURCE = 0 +MESS:FPU_BIN = 0 +MESS:COMP12_8 = 1 +MESS:COMP_ALG = 2 +MESS:COMP_FST = 1 +MESS:TIME_PLS = 2 +MESS:LATCH_UP = 0 +MESS:EXP_MODE = 1 +MESS:PIV_STAT = 3 +MESS:PIV_MPEN = 1 +MESS:PIV_PV = 1 +MESS:PIV_RV = 1 +MESS:FW_PV = 1 +MESS:FW_RV = 1 +MESS:AEX_STAT = 512 +MESS:AEX_STHR = 5 +MESS:AEX_TGTB = 2400 +MESS:AEX_BACB = 240 +MESS:AEX_MAXE = 14 +MESS:AEX_MINE = 1 +MESS:DLNKPRIO = 5 +MESS:WVLRATIO = 8 +MESS:PIXELBIN = 0 +MESS:SUBFRAME = 0 +MESS:SUBF_X1 = 4 +MESS:SUBF_Y1 = 0 +MESS:SUBF_DX1 = 0 +MESS:SUBF_DY1 = 0 +MESS:SUBF_X2 = 4 +MESS:SUBF_Y2 = 0 +MESS:SUBF_DX2 = 0 +MESS:SUBF_DY2 = 0 +MESS:SUBF_X3 = 0 +MESS:SUBF_Y3 = 0 +MESS:SUBF_DX3 = 0 +MESS:SUBF_DY3 = 0 +MESS:SUBF_X4 = 0 +MESS:SUBF_Y4 = 0 +MESS:SUBF_DX4 = 0 +MESS:SUBF_DY4 = 0 +MESS:SUBF_X5 = 0 +MESS:SUBF_Y5 = 0 +MESS:SUBF_DX5 = 0 +MESS:SUBF_DY5 = 0 +MESS:CRITOPNV = 0 +MESS:JAILBARS = 0 +MESS:JB_X0 = 0 +MESS:JB_X1 = 0 +MESS:JB_SPACE = 0 + +/* ** GEOMETRY INFORMATION ** */ +RIGHT_ASCENSION = 329.96796 +DECLINATION = -11.56931 +TWIST_ANGLE = 13.73197 +RA_DEC_REF_PIXEL = (512.00000,512.00000) +RETICLE_POINT_RA = (329.41279 ,330.88844 ,329.04957 , + 330.52952 ) +RETICLE_POINT_DECLINATION = (-12.47527 ,-12.12267 ,-11.02525 , + -10.67174 ) + +/* ** TARGET PARAMETERS ** */ +SC_TARGET_POSITION_VECTOR = (-8919.18729 ,5554.99303 ,3662.51393 ) +TARGET_CENTER_DISTANCE = 11127.61690 + +/* ** TARGET WITHIN SENSOR FOV ** */ +SLANT_DISTANCE = 9115.65447 +CENTER_LATITUDE = 24.03182 +CENTER_LONGITUDE = 297.29424 +HORIZONTAL_PIXEL_SCALE = 232.40761 +VERTICAL_PIXEL_SCALE = 232.40761 +SMEAR_MAGNITUDE = 0.10555 +SMEAR_AZIMUTH = 94.46806 +NORTH_AZIMUTH = 108.06205 +RETICLE_POINT_LATITUDE = (21.08301 ,20.54907 ,27.64956 , + 27.16452 ) +RETICLE_POINT_LONGITUDE = (301.32304 ,295.12377 ,299.48568 , + 292.69017 ) + +/* ** SPACECRAFT POSITION WITH RESPECT TO CENTRAL BODY ** */ +SUB_SPACECRAFT_LATITUDE = -1.04438 +SUB_SPACECRAFT_LONGITUDE = 315.57322 +SPACECRAFT_ALTITUDE = 8687.61690 +SUB_SPACECRAFT_AZIMUTH = 243.13066 + +/* ** SPACECRAFT LOCATION ** */ +SPACECRAFT_SOLAR_DISTANCE = 51220537.58833 +SC_SUN_POSITION_VECTOR = (50079853.32484 ,10735834.95784 , + 541857.50763 ) +SC_SUN_VELOCITY_VECTOR = (24.24499 ,-44.99506 ,-26.54238 ) + +/* ** VIEWING AND LIGHTING GEOMETRY (SUN ON TARGET) ** */ +SOLAR_DISTANCE = 51228055.72874 +SUB_SOLAR_AZIMUTH = 194.38217 +SUB_SOLAR_LATITUDE = -0.01056 +SUB_SOLAR_LONGITUDE = 3.05715 +INCIDENCE_ANGLE = 67.98720 +PHASE_ANGLE = 43.57603 +EMISSION_ANGLE = 38.58010 +LOCAL_HOUR_ANGLE = 114.23708 + +/* ** GEOMETRY FOR EACH SUBFRAME ** */ +GROUP = SUBFRAME1_PARAMETERS + RETICLE_POINT_LATITUDE = ("N/A","N/A","N/A","N/A") + RETICLE_POINT_LONGITUDE = ("N/A","N/A","N/A","N/A") +END_GROUP = SUBFRAME1_PARAMETERS + +GROUP = SUBFRAME2_PARAMETERS + RETICLE_POINT_LATITUDE = ("N/A","N/A","N/A","N/A") + RETICLE_POINT_LONGITUDE = ("N/A","N/A","N/A","N/A") +END_GROUP = SUBFRAME2_PARAMETERS + +GROUP = SUBFRAME3_PARAMETERS + RETICLE_POINT_LATITUDE = ("N/A","N/A","N/A","N/A") + RETICLE_POINT_LONGITUDE = ("N/A","N/A","N/A","N/A") +END_GROUP = SUBFRAME3_PARAMETERS + +GROUP = SUBFRAME4_PARAMETERS + RETICLE_POINT_LATITUDE = ("N/A","N/A","N/A","N/A") + RETICLE_POINT_LONGITUDE = ("N/A","N/A","N/A","N/A") +END_GROUP = SUBFRAME4_PARAMETERS + +GROUP = SUBFRAME5_PARAMETERS + RETICLE_POINT_LATITUDE = ("N/A","N/A","N/A","N/A") + RETICLE_POINT_LONGITUDE = ("N/A","N/A","N/A","N/A") +END_GROUP = SUBFRAME5_PARAMETERS + + +OBJECT = IMAGE + LINES = 1024 + LINE_SAMPLES = 1024 + SAMPLE_TYPE = MSB_UNSIGNED_INTEGER + SAMPLE_BITS = 8 + UNIT = "N/A" + DARK_STRIP_MEAN = 10.107 + +/* ** IMAGE STATISTICS OF ** */ +/* ** THE EXPOSED CCD AREA ** */ + MINIMUM = 16.000 + MAXIMUM = 124.000 + MEAN = 65.736 + STANDARD_DEVIATION = 8.835 + +/* ** PIXEL COUNTS ** */ + SATURATED_PIXEL_COUNT = 0 + MISSING_PIXELS = 0 +END_OBJECT = IMAGE +END + + + + +<;:764569;<=?>>==<<:;;=>@BBCEDCB?=<:9::;;<<;;<=>>?@A@>?=<<;;;;;;=>?AAAA@><;73.+'$""$&'+-.02468;<>>@BDEFFIFFB?;7410//12110./1358;?@BCCBB?;630..0//00323321333456998766779:;<===;;;:99::;<>>?>;779>@@A<979::;<==<<;::<==>>?@BBA><989;:99;=??=<>==>>?@ABCDDDDFEDFHJKKLKJHFCBA@AAAA?@????@BDECBC@>=:866677766545668:;:;=ADGHJIIHFGGHHGGEDDHIKLJJIIGIHIJKLMOOQRSSSRRPONMKIG=/#)-++36<<<<=>@@CDDDDC@?<96469863-*-3:@FJMORSSSRQJC=63213457:=?BCA@;61.147;>BDD?>@DEHFC@??>==<>>?>;;;;;<==<=>?>=;;;;::::::9876878987878887757699:;:::742112369;=?ADEFFGHHFC?;;<>?=;8633322343236:>=:7658:<;;97544557567:=?CEGHGFD?:86768ABB?<7-'#%*0240*$!#'-2454668999:964335453.*(+/48=ADDEFDB=;:;:::<=<>>>@BBEEFGGGFEEECA>9520000//./022323456767899;;:9::;;=<<<==>?@ABCCCCCBBAA@@?>>===>@?AABBCEEFHHHHDB>;:::9863335544445687553456877797655445678:::9::::;<==<:9853+$!*036888999::;<<=<<<<:97431359<<=>?AA?<;878:=>?ABCDEGGFHHIJKLMNMKHE?;512///,&! !#'-358;=AEGHGEB?;976 diff --git a/isis/src/base/objs/PvlContainer/Makefile b/isis/src/base/objs/PvlContainer/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5bc4fbcbb3cf222ac9ee2af95bda2db12d36471e --- /dev/null +++ b/isis/src/base/objs/PvlContainer/Makefile @@ -0,0 +1,6 @@ +INCS = PvlContainer.h +SRCS = PvlContainer.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/base/objs/PvlContainer/PvlContainer.cpp b/isis/src/base/objs/PvlContainer/PvlContainer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1ac4313ce61bccdf335491751737508cf206706f --- /dev/null +++ b/isis/src/base/objs/PvlContainer/PvlContainer.cpp @@ -0,0 +1,400 @@ +/** + * @file + * $Revision: 1.12 $ + * $Date: 2010/04/14 00:21:53 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#include "PvlContainer.h" +#include "Pvl.h" +#include "Filename.h" +#include "iException.h" +#include "iException.h" +#include "Message.h" +#include "PvlFormat.h" + +using namespace std; + +namespace Isis { + + /** + * Constructs a PvlContainer object with a type. + * @param type The type of the container. + */ + PvlContainer::PvlContainer(const std::string &type) { + Init(); + p_name.SetName(type); + } + + + /** + * Constructs a PvlContainer object with a keyword name and a container name. + * @param type The type of container. + * @param name The name of the container. + */ + PvlContainer::PvlContainer(const std::string &type, const std::string &name) { + Init(); + p_name.SetName(type); + SetName(name); + } + + + PvlContainer::PvlContainer(const PvlContainer & other) + { + *this = other; + } + + + + //! Sets the filename to blank. + void PvlContainer::Init () { + p_filename = ""; + p_formatTemplate = NULL; + } + + + /** + * Find a keyword with a specified name. + * @param name The name of the keyword to look for. + * @return The PvlKeyword object. + * @throws iException::Pvl The keyword doesn't exist. + */ + Isis::PvlKeyword &PvlContainer::FindKeyword(const std::string &name) { + PvlKeywordIterator key = FindKeyword(name,Begin(),End()); + if (key == End()) { + string msg = "Keyword [" + name + "] does not exist in [" + + Type() + " = " + Name() + "]"; + if (p_filename.size() > 0) msg += " in file [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + return *key; + } + + /** + * Find a keyword with a specified name. + * @param name The name of the keyword to look for. + * @return The PvlKeyword object. + * @throws iException::Pvl The keyword doesn't exist. + */ + const Isis::PvlKeyword &PvlContainer::FindKeyword(const std::string &name) const { + ConstPvlKeywordIterator key = FindKeyword(name,Begin(),End()); + if (key == End()) { + string msg = "Keyword [" + name + "] does not exist in [" + + Type() + " = " + Name() + "]"; + if (p_filename.size() > 0) msg += " in file [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + return *key; + } + + /** + * Remove a specified keyword. + * @param name The name of the keyword to remove. + * @throws iException::Pvl Keyword doesn't exist. + */ + void PvlContainer::DeleteKeyword (const std::string &name) { + PvlKeywordIterator key = FindKeyword(name,Begin(),End()); + if (key == End()) { + string msg = "Keyword [" + name + "] does not exist in [" + + Type() + " = " + Name() + "]"; + if (p_filename.size() > 0) msg += " in file [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + p_keywords.erase(key); + } + + + /** + * Remove the specified keyword. + * @param index The index of the keyword to remove. + * @throws iException::Pvl Keyword doesn't exist. + */ + void PvlContainer::DeleteKeyword (const int index) { + if (index >= (int)p_keywords.size() || index < 0) { + string msg = "The specified index is out of bounds in [" + + Type() + " = " + Name() + "]"; + if (p_filename.size() > 0) msg += " in file [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + PvlKeywordIterator key = Begin(); + for(int i=0; i= (int)p_keywords.size()) { + string msg = Isis::Message::ArraySubscriptNotInRange (index); + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return *(p_keywords.begin()+index); + }; + + + /** + * Return the PvlKeyword object at the specified index. + * @param index The index to use. + * @return The PvlKeyword at the specified index. + * @throws iException::Message The index is out of bounds. + */ + const Isis::PvlKeyword &PvlContainer::operator[](const int index) const { + if (index < 0 || index >= (int)p_keywords.size()) { + string msg = Isis::Message::ArraySubscriptNotInRange (index); + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return *(p_keywords.begin()+index); + } + + /** + * Add a keyword to the PvlContainer object. + * @param key The PvlKeyword object to add. + * @param mode The enum InsertMode has two possible values, Append or Replace. + * Use Append if you just want to add it to the end, Replace if you want to + * replace it. + */ + void PvlContainer::AddKeyword(const Isis::PvlKeyword &key, + const InsertMode mode) { + if (mode == Append) { + p_keywords.push_back(key); + } else if (HasKeyword(key.Name())) { + Isis::PvlKeyword &outkey = FindKeyword(key.Name()); + outkey = key; + } else { + p_keywords.push_back(key); + } + } + + /** + * @brief Insert a keyword at the specified iterator position + * + * This method provides the capability to insert a keyword at the specified + * iterator position. The process follows the description of the STL vector + * definition along with all the caveats (e.g., invalidation of iterators upon + * insert operations). + * + * This method will not perform any checks for the existance of the keyword. + * This could lead to multiple instances of the same keyword in the same + * container. It is up to the caller to manage this issue. + * + * @param key Keyword to insert + * @param pos Iterator position where to insert the new keyword + * @return PvlContainer::PvlKeywordIterator Returns the position of the + * inserted keyword per the STL vector documentation. + */ + PvlContainer::PvlKeywordIterator PvlContainer::AddKeyword(const Isis::PvlKeyword &key, + PvlKeywordIterator pos) { + return (p_keywords.insert(pos, key)); + } + + /** + * Output the PvlContainer information. + * + * @param os The preferred output stream. + * @param container The PvlContainer object to output. + */ + ostream& operator<<(std::ostream &os, PvlContainer &container) { + + // Set up a Formatter (This should not be necessary for a container because + // Object or Group should have done this already, but just in case. + bool removeFormatter = false; + if (container.GetFormat() == NULL) { + container.SetFormat(new PvlFormat()); + removeFormatter = true; + } + + Isis::PvlContainer outTemplate("DEFAULT_TEMPLATE"); + if (container.HasFormatTemplate()) outTemplate = *(container.FormatTemplate()); + + // Look for and process all include files inside the template + Isis::PvlContainer newTemp(outTemplate.Type()); + + // Include files take precedence over all other objects and groups + for (int i=0; i width) width = container[i].Name().length(); + } + + // This number keeps track of the number of keywords written + int numKeywords = 0; + + // Write out the container using the output format template + for (int i=0; i 0) os << container.GetFormat()->FormatEOL(); + if (outTemplate[i].Comments() > 0) { + for (int k=0; kFormatEOL(); + } + } + os << container[j]; + container[j].SetFormat(NULL); + container[j].SetIndent(0); + container[j].SetWidth(0); + if (++numKeywords < container.Keywords()) { +// if (j+1 < container.Keywords() && container[j+1].Comments() > 0) os << container.GetFormat()->FormatEOL(); + os << container.GetFormat()->FormatEOL(); + } + } + } + + // Output the keywords in the container that were not specified in the template + for (int i=0; i 0) os << container.GetFormat()->FormatEOL(); + os << container.GetFormat()->FormatEOL(); + } + } + + if (removeFormatter) { + delete container.GetFormat(); + container.SetFormat(NULL); + } + + return os; + } + + + /** + * Find the index of a keyword, using iterators. + * @param name The name of the keyword. + * @param beg The beginning iterator. + * @param end The ending iterator. + * @return The keyword index. + */ + PvlContainer::PvlKeywordIterator PvlContainer::FindKeyword(const std::string &name, + PvlContainer::PvlKeywordIterator beg, + PvlContainer::PvlKeywordIterator end) { + PvlKeyword temp(name); + return find(beg,end,temp); + }; + + + /** + * Find the index of a keyword, using iterators. + * @param name The name of the keyword. + * @param beg The beginning iterator. + * @param end The ending iterator. + * @return The keyword index. + */ + PvlContainer::ConstPvlKeywordIterator PvlContainer::FindKeyword(const std::string &name, + PvlContainer::ConstPvlKeywordIterator beg, + PvlContainer::ConstPvlKeywordIterator end) const { + PvlKeyword temp(name); + return find(beg,end,temp); + }; + + + //! This is an assignment operator + const PvlContainer & PvlContainer::operator=(const PvlContainer & other) + { + p_filename = other.p_filename; + p_name = other.p_name; + p_keywords = other.p_keywords; + p_formatTemplate = other.p_formatTemplate; + + return *this; + } + +} // end namespace isis diff --git a/isis/src/base/objs/PvlContainer/PvlContainer.h b/isis/src/base/objs/PvlContainer/PvlContainer.h new file mode 100644 index 0000000000000000000000000000000000000000..8650cc1caff52f8c4ad7e4a1c388ee2ce2aa0233 --- /dev/null +++ b/isis/src/base/objs/PvlContainer/PvlContainer.h @@ -0,0 +1,265 @@ +#ifndef PvlContainer_h +#define PvlContainer_h +/** + * @file + * $Revision: 1.12 $ + * $Date: 2010/04/14 00:21:53 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PvlKeyword.h" + +namespace Isis { + /** + * @brief Contains more than one keyword-value pair. + * + * This is the container for PvlKeywords. It holds information about more than + * one set of PvlKeywords. + * + * @ingroup Parsing + * + * @author 2002-10-11 Jeff Anderson + * + * @internal + * @history 2005-04-04 Leah Dahmer wrote class documentation. + * @history 2006-04-21 Jacob Danton Added format templates abilities. + * @history 2006-05-17 Jacob Danton Added DeleteKeyword by index method + * @history 2006-09-11 Stuart Sides Added formatting ability + * @history 2008-07-02 Steven Lambright Added const functionality + * @history 2008-07-10 Steven Lambright PvlContainer is no longer a PvlKeyword, + * but rather has a set of pvl keywords + * @history 2008-09-30 Christopher Austin Replaced all std::endl in the << + * operator with PvlFormat.FormatEOL() + * @history 2008-10-30 Steven Lambright Moved Find methods' implementations to + * the cpp file from the header file, added include, + * problem pointed out by "novas0x2a" (Support Forum Member) + * @history 2009-06-01 Kris Becker - Added a new AddKeyword method that + * provides insert capabilities at iterator positions. + * @history 2010-01-06 Christopher Austin - Added CleanDuplicateKeywords() + * @history 2010-04-13 Eric Hyer - Added Copy constructor + * - Added Assignment operator + * + * @todo 2005-04-04 Need coded example. + */ + class PvlContainer { + public: + PvlContainer(const std::string &type); + PvlContainer(const std::string &type, const std::string &name); + PvlContainer(const PvlContainer & other); + + //! Set the name of the container. + void SetName(const std::string &name) { p_name.SetValue(name); }; + /** + * Returns the container name. + * @return The container name. + */ + inline std::string Name() const { return (std::string) p_name; }; + /** + * Returns whether the given string is equal to the container name or not. + * @param match The string to compare to the name. + * @return True if the name and string are the same, false if they are + * not. + */ + bool IsNamed(const std::string &match) { + return PvlKeyword::StringEqual(match, (std::string)p_name); + } + /** + * Returns the container type. + * @return The container type. + */ + inline std::string Type() const { return p_name.Name(); }; + /** + * Returns the number of keywords contained in the PvlContainer. + * @return The number of keywords. + */ + inline int Keywords() const { return p_keywords.size(); }; + + //! Clears PvlKeywords + void Clear() { p_keywords.clear(); }; + //! Contains both modes: Append or Replace. + enum InsertMode { Append, Replace }; + /** + * Add a keyword to the container. + * @param keyword The PvlKeyword object to append. + * @param mode Using the InsertMode value of Append. + */ + void AddKeyword(const PvlKeyword &keyword, + const InsertMode mode = Append); + + + /** + * When you use the += operator with a PvlKeyword, it will call the + * AddKeyword() method. + * @param keyword The PvlKeyword to be added. + */ + void operator+= (const PvlKeyword &keyword) { AddKeyword(keyword); }; + + PvlKeyword &FindKeyword(const std::string &name); + /** + * When you use the [] operator with a (string) name, it will call the + * FindKeyword() method. + * @param name The name of the keyword to find. + */ + PvlKeyword &operator[](const std::string &name) { return FindKeyword(name); }; + PvlKeyword &operator[](const int index); + + /** + * When you use the [] operator with a (char) name, it will call the + * FindKeyword() method. + * @param name The name of the keyword to find. + */ + PvlKeyword &operator[](const char *name) { + return operator[](std::string(name)); + }; + + const PvlKeyword &FindKeyword(const std::string &name) const; + /** + * When you use the [] operator with a (string) name, it will call the + * FindKeyword() method. + * @param name The name of the keyword to find. + */ + + const PvlKeyword &operator[](const std::string &name) const { return FindKeyword(name); }; + const PvlKeyword &operator[](const int index) const; + + /** + * When you use the [] operator with a (char) name, it will call the + * FindKeyword() method. + * @param name The name of the keyword to find. + */ + PvlKeyword operator[](const char *name) const { + return operator[](std::string(name)); + }; + + bool HasKeyword(const std::string &name) const; + //! The keyword iterator. + typedef std::vector::iterator PvlKeywordIterator; + + //! The const keyword iterator + typedef std::vector::const_iterator ConstPvlKeywordIterator; + + + PvlKeywordIterator FindKeyword(const std::string &name, + PvlKeywordIterator beg, + PvlKeywordIterator end); + + ConstPvlKeywordIterator FindKeyword(const std::string &name, + ConstPvlKeywordIterator beg, + ConstPvlKeywordIterator end) const; + + PvlKeywordIterator AddKeyword(const PvlKeyword &keyword, + PvlKeywordIterator pos); + + /** + * Return the beginning iterator. + * @return The beginning iterator. + */ + PvlKeywordIterator Begin() { return p_keywords.begin(); }; + + /** + * Return the const beginning iterator. + * @return The const beginning iterator. + */ + ConstPvlKeywordIterator Begin() const { return p_keywords.begin(); }; + + /** + * Return the ending iterator. + * @return The ending iterator. + */ + PvlKeywordIterator End() { return p_keywords.end(); }; + + /** + * Return the const ending iterator. + * @return The const ending iterator. + */ + ConstPvlKeywordIterator End() const { return p_keywords.end(); }; + + void DeleteKeyword (const std::string &name); + void DeleteKeyword (const int index); + + bool CleanDuplicateKeywords(); + + /** + * When you use the -= operator with a (string) name, it will call the + * DeleteKeyword() method. + * @param name The name of the keyword to remove. + */ + void operator-= (const std::string &name) { DeleteKeyword(name); }; + /** + * When you use the -= operator with a PvlKeyword object, it will call the + * DeleteKeyword() method. + * @param key The PvlKeyword object to remove. + */ + void operator-= (const PvlKeyword &key) { DeleteKeyword(key.Name()); }; + /** + * Returns the filename used to initialise the Pvl object. If the object + * was not initialized using a file, this string is empty. + * @return The filename. + */ + std::string Filename () const { return p_filename; }; + + void SetFormatTemplate (PvlContainer &ref) {p_formatTemplate = &ref;}; + + bool HasFormatTemplate () { return p_formatTemplate != NULL;}; + + PvlContainer* FormatTemplate() {return p_formatTemplate;}; + + PvlFormat *GetFormat() { return p_name.GetFormat(); } + void SetFormat(PvlFormat *format) { p_name.SetFormat(format); } + + int Indent() { return p_name.Indent(); } + void SetIndent(int indent) { p_name.SetIndent(indent); } + + inline int Comments () const { return p_name.Comments(); }; + std::string Comment (const int index) const { return p_name.Comment(index); } + + void AddComment(const std::string &comment) { p_name.AddComment(comment); } + + PvlKeyword &GetNameKeyword() { return p_name; } + const PvlKeyword &GetNameKeyword() const { return p_name; } + + const PvlContainer & operator=(const PvlContainer & other); + + protected: + std::string p_filename; /** p_keywords; /** + +# Cats shed +CATTLE = Meow +5.2 +# Cats shed +CATTLE = Meow + +Test inserter ... +Orangutan = gross +DOG = 5.2 diff --git a/isis/src/base/objs/PvlContainer/unitTest.cpp b/isis/src/base/objs/PvlContainer/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e933243e825bf5774f4f95f756bda32c5dd2c942 --- /dev/null +++ b/isis/src/base/objs/PvlContainer/unitTest.cpp @@ -0,0 +1,37 @@ +#include +#include "PvlContainer.h" +#include "Preference.h" +using namespace std; +int main () { + Isis::Preference::Preferences(true); + + Isis::PvlKeyword dog("DOG",5.2,"meters"); + Isis::PvlKeyword cat("CATTLE"); + cat = "Meow"; + cat.AddComment("Cats shed"); + + Isis::PvlContainer ani("Animals"); + ani += dog; + ani += cat; + ani.AddComment("/* Pets are cool */"); + +// cout << "1 ..." << endl; + cout << ani << endl; + +// cout << "2 ..." << endl; + cout << (double) ani["dog"] << endl; + + ani -= "dog"; +// cout << "3 ..." << endl; + cout << ani << endl; + +// cout << "4 ..." << endl; + ani -= ani[0]; + cout << ani << endl; + + cout << "Test inserter ..." << endl; + Isis::PvlKeyword monkey("Orangutan", "gross"); + ani.AddKeyword(dog, ani.Begin()); + ani.AddKeyword(monkey, ani.Begin()); + cout << ani << endl; +} diff --git a/isis/src/base/objs/PvlEditDialog/Makefile b/isis/src/base/objs/PvlEditDialog/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0a5ad585bf9cd89fa7eb5054b9d756e501fd6897 --- /dev/null +++ b/isis/src/base/objs/PvlEditDialog/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp unitTest.cpp, $(wildcard *.cpp))#no moc+unitTest cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PvlEditDialog/PvlEditDialog.cpp b/isis/src/base/objs/PvlEditDialog/PvlEditDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7aa667feedf2853a01e1c97d7edad51de95dcf24 --- /dev/null +++ b/isis/src/base/objs/PvlEditDialog/PvlEditDialog.cpp @@ -0,0 +1,141 @@ +#include +#include +#include + +#include +#include + +#include "iException.h" +#include "Pvl.h" +#include "PvlEditDialog.h" + +using namespace std; + +namespace Isis { + /** + * This constructor creates a PvlEditDialog object given a + * pointer to a Pvl object. + * + * @param pvl Pvl file to be viewed or edited + * @author 2008-12-10 Jeannie Walldren + * @internal + * @history 2008-12-10 Jeannie Walldren - Original Version + * @history 2008-12-15 Jeannie Walldren - Removed unneccesary + * error catch. + */ + PvlEditDialog::PvlEditDialog (Pvl &pvl, QWidget *parent) : QDialog (parent) { + + // Create text edit box and fill it with pvl file contents + p_textEdit = new QTextEdit(); + fstream input; + + // open as input from pvl file + input.open(pvl.Filename().c_str(),ios::in); + string output; + + // read first line of input and write as first output line + getline(input,output); + while(!input.eof()) { + // append this line of output to the QTextEdit box + p_textEdit->append(QString::fromStdString(output)); + + // read next line of input and write as next output line + getline(input,output); + } + input.close(); + + // Create Close and Save buttons in an QHBoxLayout + p_saveButton = new QPushButton("Save Changes &As..."); + p_saveButton->setEnabled(false); + QPushButton *closeButton = new QPushButton("&Close"); + + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addWidget(p_saveButton); + buttonLayout->addWidget(closeButton); + + // Add QTextEdit box and button layout to QVBoxLayout + // and set this to the layout of the QDialog window + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->addWidget(p_textEdit); + vLayout->addLayout(buttonLayout); + + setLayout(vLayout); + QString titleBar = "Pvl File: " + QString::fromStdString(pvl.Filename()) ; + setWindowTitle(titleBar); + + // Add functionality to buttons + connect(p_textEdit,SIGNAL(textChanged()),this,SLOT(enableSaveButton())); + connect(p_saveButton, SIGNAL(clicked()), this, SLOT(saveTextEdit())); + connect(closeButton, SIGNAL(clicked()), this, SLOT(reject())); + + } + + /** + * Allow the "Save Changes" button to be activated. + * + * @author 2008-12-10 Jeannie Walldren + * @internal + * @history 2008-12-10 Jeannie Walldren - Original Version. + */ + void PvlEditDialog::enableSaveButton () { + p_saveButton->setEnabled(true); + } + + /** + * Save the edited text as a new Pvl file. + * @author 2008-12-10 Jeannie Walldren + * @internal + * @history 2008-12-10 Jeannie Walldren - Original Version. + * @history 2008-12-15 Jeannie Walldren - Added a verification + * that the edited file is in Pvl format before + * allowing save. Replaced error throw with + * QMessageBox warning. + */ + void PvlEditDialog::saveTextEdit(){ + // Check validity of format by placing QTextEdit contents into a Pvl object + Pvl pvl; + stringstream ss; + string textEditContents = p_textEdit->toPlainText().toStdString(); + + //fill stringstream with contents of QTextEdit + ss << textEditContents; + + try{ + // fill pvl with contents of stringstream + ss >> pvl; + } + catch (Isis::iException &e){ + // catch errors in Pvl format when populating pvl object + QString message = e.Errors().c_str(); + e.Clear (); + QMessageBox::warning((QWidget *)parent(),"Error",message); + return; + } + + // get a window to choose a name and location for the saved file + // default: look in user's current directory for *.def or *.pvl files + QString filter = "Select registration template (*.def *.pvl);;"; + filter += "All (*)"; + QString pvlFile = QFileDialog::getSaveFileName((QWidget*)parent(), + "Select a registration template", + ".", + filter); + if (!pvlFile.isEmpty()) { + // convert QString to std::string needed to open file stream + string saveFile = pvlFile.toStdString(); + try{ + pvl.Write(saveFile); + } + catch (Isis::iException &e){ + // report exception(s) to mesage box + QString message = e.Errors().c_str(); + e.Clear (); + QMessageBox::warning((QWidget *)parent(),"Error",message); + return; + } + } + + // refresh titleBar with new file name + setWindowTitle("Pvl File: " + pvlFile); + } +} diff --git a/isis/src/base/objs/PvlEditDialog/PvlEditDialog.h b/isis/src/base/objs/PvlEditDialog/PvlEditDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..547acc2f9a77a1e5fa220297488ccd3764c354df --- /dev/null +++ b/isis/src/base/objs/PvlEditDialog/PvlEditDialog.h @@ -0,0 +1,57 @@ +#ifndef PvlEditDialog_h +#define PvlEditDialog_h + +#include +#include +#include "Pvl.h" + +class QLabel; +class QLineEdit; +class QListWidget; +class QPushButton; +class QTextEdit; + +#include + +namespace Isis { + /** + * PvlEditDialog creates a QDialog window in which a QTextEdit + * box displays the contents of a pvl file. This file may be + * viewed or edited and saved as a new pvl file. + * + * @ingroup ApplicationInterface + * + * @author 2008-12-10 Jeannie Walldren + * @internal + * @history 2008-12-10 Jeannie Walldren - Original version + * written to view and edit the template file in the + * qnet application. + * @history 2008-12-10 Jeannie Walldren - Changed namespace + * from Qisis to Isis + * @history 2008-12-10 Jeannie Walldren - Cleaned up code and + * fixed bugs arising from moving this class from + * Qisis and to Isis. Added moc commands to Makefile. + * @history 2008-12-15 Jeannie Walldren - Added a verification + * that the edited file is in Pvl format. Replaced + * error throws with QMessage warning boxes. + */ + class PvlEditDialog : public QDialog { + Q_OBJECT + + + public: + PvlEditDialog (Pvl &pvl, QWidget *parent=0); + + private: + QTextEdit *p_textEdit; + QPushButton *p_saveButton; + + private slots: + void enableSaveButton(); + void saveTextEdit(); + }; +}; + +#endif + + diff --git a/isis/src/base/objs/PvlEditDialog/PvlEditDialog.truth b/isis/src/base/objs/PvlEditDialog/PvlEditDialog.truth new file mode 100644 index 0000000000000000000000000000000000000000..b41dc856c3c1f764cc3c5b0c4006a7ba6ff466a2 --- /dev/null +++ b/isis/src/base/objs/PvlEditDialog/PvlEditDialog.truth @@ -0,0 +1,3 @@ + +Unit test for PvlEditDialog +Replace this when we decide how to do unit tests for interactive objects diff --git a/isis/src/base/objs/PvlEditDialog/unitTest.cpp b/isis/src/base/objs/PvlEditDialog/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..440f722c0132fcd03fbf29e5a533660a77f19b47 --- /dev/null +++ b/isis/src/base/objs/PvlEditDialog/unitTest.cpp @@ -0,0 +1,14 @@ +#include +#include "PvlEditDialog.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main (int argc, char *argv[]) { + Preference::Preferences(true); + cout << endl << "Unit test for PvlEditDialog" << endl; + cout << "Replace this when we decide how to do unit tests for interactive objects" << endl; + return 0; +} + diff --git a/isis/src/base/objs/PvlFormat/Makefile b/isis/src/base/objs/PvlFormat/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6a2e9f659ea2c88fb2d58e2b2c8addec0648a2cc --- /dev/null +++ b/isis/src/base/objs/PvlFormat/Makefile @@ -0,0 +1,5 @@ +INCS = PvlFormat.h +SRCS = PvlFormat.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PvlFormat/PvlFormat.cpp b/isis/src/base/objs/PvlFormat/PvlFormat.cpp new file mode 100644 index 0000000000000000000000000000000000000000..932fa1ce6b397956d257fa66b9c8854844a1f347 --- /dev/null +++ b/isis/src/base/objs/PvlFormat/PvlFormat.cpp @@ -0,0 +1,316 @@ +/** + * @file + * $Revision: 1.7 $ + * $Date: 2010/02/04 22:36:41 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "iException.h" +#include "Message.h" +#include "iString.h" +#include "Filename.h" +#include "PvlKeyword.h" +#include "TextFile.h" +#include "Pvl.h" +#include "PvlFormat.h" + +using namespace std; + +namespace Isis { + + /* + * Constructs an empty PvlFormat + */ + PvlFormat::PvlFormat() { + Init(); + } + + + /* + * Constructs a PvlFormat using the file name to ingest as the keyword to type + * mapping. This is provided as a convience for child objects. The map is not + * used for output of PvlKeywords in Normal Isis format. + * + * @param file A file name with keyword=type. Where KEYWORD is the name of a + * keyword in this PvlKeyword and TYPE is one of [string | integer | float ] + */ + PvlFormat::PvlFormat(const std::string &file) { + Init(); + Add(file); + } + + + /* + * Constructs a PvlFormat using the specified pre populated Pvl map of keyword + * name (std::string) vs keyword type (KeywordType). + * + * @param keywordType A Pvl with keyword=type. Where keyword is the name of a + * keyword in a PvlKeyword and type is one of [string | integer | float ] + */ + PvlFormat::PvlFormat(Pvl &keywordType) { + Init(); + Add(keywordType); + } + + + //! Clears all PvlFormat data. + void PvlFormat::Init() { + p_keywordMap.Clear(); + p_keywordMapFile.clear(); + p_charLimit = 80; + } + + + /* + * Add the contents of a file to the keyword type mapping. The file should + * contain KEYWORD=TYPE (one per line), where TYPE is one of the strings + * KeywordType can convert. + */ + void PvlFormat::Add(const std::string &file) { + p_keywordMapFile = file; + + // Open the file and internalize it into the Pvl map + try { + Pvl pvl(file); + Add(pvl); + } + catch (iException &e) { + string msg; + msg += "Unable to open or read keyword to type mapping file ["; + msg += file + "]"; + throw iException::Message (Isis::iException::Programmer, msg, _FILEINFO_); + } + } + + + /* + * Add the contents of a Pvl to the keyword type mapping. The pvl should + * contain KEYWORD=TYPE, where TYPE is one of the strings KeywordType can + * convert. + */ + void PvlFormat::Add(Pvl &pvl) { + for (int i=0; i 1) { + return (int)key[1]; + } + } + return -1; + } + + + /* + * Returns the keyword name and value(s) formatted in "Normal" Isis format + * + * @param keyword The PvlKeyword to be formatted + * @param num Use the ith value of the keyword + */ + std::string PvlFormat::FormatValue(const PvlKeyword &keyword, int num) { + + string val; + val.clear(); + + // Find out if the units are the same for all values + bool singleUnit = IsSingleUnit(keyword); + + // Create a Null value if the value index is greater than the number of values + if (num >= keyword.Size()) { + return "Null"; + } + + // Create a Null value if the requested index is an empty string + if (keyword[num].size() == 0) { + val += "Null"; + } + else { + val += keyword[num]; + } + + val = AddQuotes (val); + + // If it is an array start it off with a paren + if ((keyword.Size() > 1) && (num == 0)) { + val = "(" + val; + } + + // Add the units to this value + if ((!singleUnit) && (keyword.Unit(num).size() > 0)) { + val += " <" + keyword.Unit(num) + ">"; + } + + // Add a comma for arrays + if (num != keyword.Size()-1) { + val += ", "; + } + // If it is an array close it off + else if (keyword.Size() > 1) { + val += ")"; + } + + // Add the units to the end if all values have the same units + if ((singleUnit) && (num == keyword.Size()-1) && + (keyword.Unit(num).size() > 0)) { + val += " <" + keyword.Unit(num) + ">"; + } + + return val; + } + + + /* + * Format the name of the container + * + * @param keyword The PvlContainer being closed. + */ + std::string PvlFormat::FormatName(const PvlKeyword &keyword) { + return keyword.Name(); + } + + + /* + * Format the end of a container + * + * @param name The text used to signify the end of a container + * @param keyword The PvlContainer being closed. + */ + std::string PvlFormat::FormatEnd(const std::string name, + const PvlKeyword &keyword) { + return "End_" + FormatName(keyword); + }; + + + /* + * Add single or double quotes around a value if necessary. The Isis definition + * of when quotes are necessary is used. + * + * @param value The PvlKeyword value to be quoted if necessary. + */ + std::string PvlFormat::AddQuotes(const std::string value) { + std::string val = value; + + bool needQuotes = false; + + // find out if we need quotes and what kind of quotes might already exist + char existingQuoteType = '\0'; + for(unsigned int pos = 0; !needQuotes && pos < val.size(); pos++) { + // check for values indicating we need quotes, if we have a sequence + // it should already be properly quoted... + if(pos == 0) { + if(val[pos] == '(' && val[val.size() - 1] == ')') break; + if(val[pos] == '{' && val[val.size() - 1] == '}') break; + } + + if(val[pos] == ' ' || val[pos] == '(' || + val[pos] == '(' || val[pos] == ')' || + val[pos] == '{' || val[pos] == '}' || + val[pos] == ',') { + needQuotes = true; + } + + // remember if we are a quote, what quote type we are + if(existingQuoteType == '\0') { + if(val[pos] == '"') { + existingQuoteType = '"'; + } + else if(val[pos] == '\'') { + existingQuoteType = '\''; + } + } + else { + // make sure we dont have mixing of our outside quote type + if(val[pos] == '"' || val[pos] == '\'') { + val[pos] = existingQuoteType; + } + } + } + + // figure out what kind of quotes we want to add + char quoteValue = '"'; + + if(existingQuoteType == '"') { + quoteValue = '\''; + } + + if(needQuotes) { + val = quoteValue + val + quoteValue; + } + + return val; + } + + + /** + * Returns true if the units are the same for all value in the keyword + * otherwise it returns false + * + * @param keyword The PvlKeyword to be formatted + */ + bool PvlFormat::IsSingleUnit(const PvlKeyword &keyword) { + + // See if the units are all the same + bool singleUnit = true; + for (int i = 0; i < keyword.Size(); i ++) { + if (!keyword.StringEqual(keyword.Unit(i), keyword.Unit(0))) { + singleUnit = false; + } + } + + return singleUnit; + } +} + diff --git a/isis/src/base/objs/PvlFormat/PvlFormat.h b/isis/src/base/objs/PvlFormat/PvlFormat.h new file mode 100644 index 0000000000000000000000000000000000000000..0d1e32a759de98b18c8348c7f907c1fdada6a94e --- /dev/null +++ b/isis/src/base/objs/PvlFormat/PvlFormat.h @@ -0,0 +1,174 @@ +#ifndef PvlFormat_h +#define PvlFormat_h +/** + * @file + * $Revision: 1.7 $ + * $Date: 2010/02/04 22:36:41 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "Pvl.h" + +#include "PvlKeyword.h" + +namespace Isis { + + //! The different types of keywords that can be formatted + enum KeywordType { NoTypeKeyword, + StringKeyword, + BoolKeyword, + IntegerKeyword, + RealKeyword, + OctalKeyword, + HexKeyword, + BinaryKeyword, + EnumKeyword }; + + /** + * Convert a string representing a type of keyword to the corresponding + * enumeration. All white space, quotes, underscores, and dashes will be + * removed from the input string. + * + * @param type The string to be converted. + * @return The corresponding KeywordType enum. + */ + inline KeywordType ToKeywordType (const std::string type) { + + iString t(type); + t.Remove("_- \r\n\f\t\v\"\'"); + t.UpCase(); + + if (t == "STRING") return StringKeyword; + else if (t == "BOOL") return BoolKeyword; + else if (t == "INTEGER") return IntegerKeyword; + else if (t == "REAL") return RealKeyword; + else if (t == "OCTAL") return OctalKeyword; + else if (t == "HEX") return HexKeyword; + else if (t == "BINARY") return BinaryKeyword; + else if (t == "ENUM") return EnumKeyword; + return NoTypeKeyword; + } + +/** + * @brief Formats a Pvl name value pair to Isis standards. + * + * This class is used to format a single PVL keyword-value pair using normal + * Isis formatting. The class serves as a base class for others to override and + * implement their own formatting. + * + * This class uses a Pvl or Pvl formatted file to populate its internal data + * structure. This structure is used to lookup the type of a keyword and/or + * other information for another Pvl{Object|Group|Keyword}. The format of the + * file or Pvl is: + * + * @code + * NAME=TYPE + * NAME2=(TYPE,PLACES) + * @endcode + * + * Example: + * @code + * DESCRIPTION = STRING + * MinimumLatitude = (REAL,5) + * BITTYPE = ENUM + * RECORDS = INTEGER + * @endcode + * + * Where NAME is the name of a keyword in the Pvl to be formatted. TYPE is the + * type of keyword (STRING,BOOL,INTEGER,REAL,OCTAL,HEX,BINARY,ENUM) (see + * ToKeywordType). PLACES is the number of digits to the right of the decimal + * place for a keyword of TYPE REAL. + * + * NOTE: The capabilities to use this Pvl are not implemented in this base + * class. They are provided as a convience for child classes only. This class + * only implements the normal Isis foramatting, which is not dependent on the + * type of the keyword. It is dependent on value of the keyword. + * + * @ingroup Parsing + * + * @author 2006-09-05 Stuart Sides + * + * @internal + * @history 2006-09-05 Stuart Sides - Original version + * @history 2008-09-30 Christopher Austin - added FormatEOL() + * @history 2009-12-17 Steven Lambright - {} are now treated the same as () + * @history 2010-02-04 Travis Addair - Added SetCharLimit + * method allowing users to set the point at which a + * keyword value is output to the next line down. + */ + class PvlFormat { + + public: + + PvlFormat(); + PvlFormat(const std::string &file); + PvlFormat(Pvl &keymap); + virtual ~PvlFormat () {}; + + void Add(const std::string &file); + void Add(Pvl &keymap); + + /** + * Sets the maximum number of characters in a keyword value that + * can be printed to a line before it wraps to the next line. By + * default, the limit is set to 80 characters. + * + * @param limit The new character limit. + */ + void SetCharLimit(const unsigned int limit) { p_charLimit = limit; }; + + /** + * Retrieves the maximum number of characters in a keyword value + * that can be printed to a line before it wraps to the next + * line. By default, the limit is set to 80 characters. + * + * @return unsigned int Maximum number of characters. + */ + unsigned int CharLimit() const { return p_charLimit; }; + + virtual std::string FormatValue (const PvlKeyword &keyword, + int valueIndex = 0); + virtual std::string FormatName (const PvlKeyword &keyword); + virtual std::string FormatEnd (const std::string name, + const PvlKeyword &keyword); + virtual std::string FormatEOL () { return "\n"; } + + virtual KeywordType Type (const PvlKeyword &keyword); + virtual int Accuracy (const PvlKeyword &keyword); + + protected: + + virtual std::string AddQuotes (const std::string value); + bool IsSingleUnit (const PvlKeyword &keyword); + + std::string p_keywordMapFile; + Pvl p_keywordMap; + + //! Maximum number of characters on a single line of a keyword value. + unsigned int p_charLimit; + + private: + void Init(); + }; +}; + +#endif + diff --git a/isis/src/base/objs/PvlFormat/PvlFormat.truth b/isis/src/base/objs/PvlFormat/PvlFormat.truth new file mode 100644 index 0000000000000000000000000000000000000000..85c4b2eb5a4a8539060c2df31b7f92b6d5eb1390 --- /dev/null +++ b/isis/src/base/objs/PvlFormat/PvlFormat.truth @@ -0,0 +1,34 @@ +mystring = stringval +mystring = "string val" +myint = 12345 +myfloat = 1.234567e+93 +myarray = (12345, "a short string", 1.234) +myarray = {12345, "a short string", 1.234} +Group = Group1 + mystring = stringval + mystring = "string val" + myint = 12345 + myfloat = 1.234567e+93 + myarray = (12345,"a short string",1.234) +End_Group +Object = Object1 + Object = Object2 + mystring = stringval + mystring = "string val" + myint = 12345 + myfloat = 1.234567e+93 + myarray = (12345,"a short string",1.234) + End_Object + + Group = Group1 + mystring = stringval + mystring = "string val" + myint = 12345 + myfloat = 1.234567e+93 + myarray = (12345,"a short string",1.234) + End_Group +End_Object +myequation = "(f1-f2) * 5" +myequation = "(f1-f2)*5" +mysequence = ((a,b), (c,d)) +mycommas = ",,," diff --git a/isis/src/base/objs/PvlFormat/unitTest.cpp b/isis/src/base/objs/PvlFormat/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91c041fb70fad64e9a1d21c1c1293c7053f4dcf2 --- /dev/null +++ b/isis/src/base/objs/PvlFormat/unitTest.cpp @@ -0,0 +1,100 @@ +#include "PvlKeyword.h" +#include "PvlGroup.h" +#include "PvlObject.h" +#include "PvlFormat.h" +#include "Preference.h" + +using namespace std; +int main () { + Isis::Preference::Preferences(true); + + // Test keywords + { + Isis::PvlKeyword key("mystring", "stringval"); + cout << key << endl; + } + + { + Isis::PvlKeyword key("mystring", "string val"); + cout << key << endl; + } + + { + Isis::PvlKeyword key("myint", 12345); + cout << key << endl; + } + + { + Isis::PvlKeyword key("myfloat", 12345.67e+89); + cout << key << endl; + } + + { + Isis::PvlKeyword key("myarray", "(12345, \"a short string\", 1.234)"); + cout << key << endl; + } + + + { + Isis::PvlKeyword key("myarray", "{12345, \"a short string\", 1.234}"); + cout << key << endl; + } + + // Test Groups + { + Isis::PvlGroup grp("Group1"); + grp += Isis::PvlKeyword ("mystring", "stringval"); + grp += Isis::PvlKeyword ("mystring", "string val"); + grp += Isis::PvlKeyword ("myint", 12345); + grp += Isis::PvlKeyword ("myfloat", 12345.67e+89); + grp += Isis::PvlKeyword ("myarray", "(12345,\"a short string\",1.234)"); + cout << grp << endl; + } + + + // Test Objects + { + Isis::PvlGroup grp("Group1"); + grp += Isis::PvlKeyword ("mystring", "stringval"); + grp += Isis::PvlKeyword ("mystring", "string val"); + grp += Isis::PvlKeyword ("myint", 12345); + grp += Isis::PvlKeyword ("myfloat", 12345.67e+89); + grp += Isis::PvlKeyword ("myarray", "(12345,\"a short string\",1.234)"); + Isis::PvlObject obj("Object1"); + obj.AddGroup(grp); + + Isis::PvlObject obj2("Object2"); + obj2 += Isis::PvlKeyword ("mystring", "stringval"); + obj2 += Isis::PvlKeyword ("mystring", "string val"); + obj2 += Isis::PvlKeyword ("myint", 12345); + obj2 += Isis::PvlKeyword ("myfloat", 12345.67e+89); + obj2 += Isis::PvlKeyword ("myarray", "(12345,\"a short string\",1.234)"); + obj.AddObject(obj2); + cout << obj << endl; + } + + { + Isis::PvlKeyword key("myequation", "(f1-f2) * 5"); + cout << key << endl; + } + + { + Isis::PvlKeyword key("myequation", "(f1-f2)*5"); + cout << key << endl; + } + + + { + Isis::PvlKeyword key("mysequence"); + key += "(a,b)"; + key += "(c,d)"; + cout << key << endl; + } + + { + Isis::PvlKeyword key("mycommas"); + key += ",,,"; + cout << key << endl; + } +} + diff --git a/isis/src/base/objs/PvlFormatPds/Makefile b/isis/src/base/objs/PvlFormatPds/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5a74e55c6708e4443ec05c58b5f42c866c9e4c74 --- /dev/null +++ b/isis/src/base/objs/PvlFormatPds/Makefile @@ -0,0 +1,5 @@ +INCS = $(wildcard Pvl*.h) +SRCS = $(wildcard Pvl*.cpp) +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PvlFormatPds/PvlFormatPds.cpp b/isis/src/base/objs/PvlFormatPds/PvlFormatPds.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1347dd5b65968476916d7e6aad477c0397581312 --- /dev/null +++ b/isis/src/base/objs/PvlFormatPds/PvlFormatPds.cpp @@ -0,0 +1,723 @@ +/** + * @file + * $Revision: 1.10 $ + * $Date: 2009/09/15 21:13:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "iException.h" +#include "Message.h" +#include "iString.h" +#include "Filename.h" +#include "Constants.h" +#include "TextFile.h" + +#include "PvlFormatPds.h" + +using namespace std; + +namespace Isis { + + /* + * Constructs an empty PvlFormatPds + */ + PvlFormatPds::PvlFormatPds() { + Init(); + } + + + /* + * Constructs a PvlFormatPds using the file name to ingest to fill the keyword + * to type map. + * + * @param file A file name with keyword=type. Where KEYWORD is the name of a + * keyword and TYPE is one of [string | integer | float | ...] + */ + PvlFormatPds::PvlFormatPds(const std::string &file) : PvlFormat(file) { + Init(); + } + + + /* + * Constructs a PvlFormatPds using the specified pre populated map of keyword name + * (std::string) vs keyword type (KeywordType). + * + * @param keywordType A map with keyword, type. Where keyword is the name of a + * keyword in a PvlKeyword and type is one of [string | integer | float ] + */ + PvlFormatPds::PvlFormatPds(Pvl &keywordType) : PvlFormat(keywordType) { + Init(); + } + + + //! Clears all PvlFormatPds specific data. + void PvlFormatPds::Init() { + } + + + /* + * Returns the keyword value formatted in "PDS" format + * + * @param keyword The PvlKeyword to be formatted + * @param num Use the ith value of the keyword + */ + std::string PvlFormatPds::FormatValue (const PvlKeyword &keyword, int num) { + + iString name = keyword.Name(); + name.UpCase(); + if (name == "OBJECT" || (name == "GROUP")) { + iString val = (string)keyword; + return val.UpCase(); + } + + // Find out what type this keyword is + KeywordType type = Type(keyword); + + switch (type) { + case StringKeyword: + return FormatString(keyword, num); + break; + + case RealKeyword: + return FormatReal(keyword, num, Accuracy(keyword)); + break; + + case IntegerKeyword: + return FormatInteger(keyword, num, Accuracy(keyword)); + break; + + case HexKeyword: + return FormatHex(keyword, num, Accuracy(keyword)); + break; + + case BinaryKeyword: + return FormatBinary(keyword, num, Accuracy(keyword)); + break; + + case EnumKeyword: + return FormatEnum(keyword, num); + break; + + case BoolKeyword: + return FormatBool(keyword, num); + break; + + case NoTypeKeyword: + default: + return FormatUnknown(keyword,num); + break; + } + return FormatUnknown(keyword,num); + } + + + /* + * Returns the keyword value formatted as a "PDS" string + * + * @param keyword The PvlKeyword to be formatted + * @param num Use the ith value of the keyword + * @internal + * @history 2009-09-15 Jeannie Walldren - Moved the call to AddQuotes() + * inside the else-statement since + * the if portion of the code already + * adds quotes automatically + */ + std::string PvlFormatPds::FormatString (const PvlKeyword &keyword, int num) { + + iString val; + val.clear(); + bool singleUnit = false; + + // Create a Null value if the value index is greater than the number of values + if ((num >= keyword.Size()) || (keyword[num].size() == 0)) { + return "NULL"; + } + + // Handle PDS special values "N/A" "NULL" "UNK" + iString tmp = keyword[num]; + tmp.UpCase(); + if ((tmp == "N/A") || (tmp == "NULL") || (tmp == "UNK")) { + val += "\"" + tmp + "\""; + } + else { + val += keyword[num]; + val = AddQuotes (val); + } + + + // If it is an array start it off with a paren + if ((keyword.Size() > 1) && (num == 0)) { + val = "(" + val; + } + + // Add the units to this value + if ((!singleUnit) && (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // For now PDS units are case sensitive, so we should not UpCase them + // unit.UpCase(); + val += " <" + unit + ">"; + } + + // Add a comma for arrays + if (num != keyword.Size()-1) { + val += ", "; + } + // If it is an array, close it off + else if (keyword.Size() > 1) { + val += ")"; + } + + // Add the units to the end if all values have the same units + if ((singleUnit) && (num == keyword.Size()-1) && + (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // For now PDS units are case sensitive, so we should not UpCase them + // unit.UpCase(); + val += " <" + unit + ">"; + } + + return val; + } + + + /* + * Returns the keyword value formatted as a "PDS" real number + * + * @param keyword The PvlKeyword to be formatted + * @param num Use the ith value of the keyword + */ + std::string PvlFormatPds::FormatReal(const PvlKeyword &keyword, int num, + int places) { + + iString val; + val.clear(); + bool singleUnit = false; + + // Create a Null value if the value index is greater than the number of values + if ((num >= keyword.Size()) || (keyword[num].size() == 0)) { + return "NULL"; + } + + // If it is an array start it off with a paren + if ((keyword.Size() > 1) && (num == 0)) { + val += "("; + } + + // Handle PDS special values "N/A" "NULL" "UNK" + iString tmp = keyword[num]; + tmp.UpCase(); + if ((tmp == "N/A") || (tmp == "NULL") || (tmp == "UNK")) { + val += "\"" + tmp + "\""; + } + else if (places >= 0) { + stringstream out; + out << setiosflags(ios::fixed) << setprecision(places) << (double)keyword[num]; + val += out.str(); + } + else { + val += keyword[num]; + } + + // Add the units to this value + if ((!singleUnit) && (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // unit.UpCase(); + val += " <" + unit + ">"; + } + + // Add a comma for arrays + if (num != keyword.Size()-1) { + val += ", "; + } + // If it is an array, close it off + else if (keyword.Size() > 1) { + val += ")"; + } + + // Add the units to the end if all values have the same units + if ((singleUnit) && (num == keyword.Size()-1) && + (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // unit.UpCase(); + val += " <" + unit + ">"; + } + + return val; + } + + + /* + * Returns the keyword value formatted as a "PDS" enumeration + * + * @param keyword The PvlKeyword to be formatted + * @param num Use the ith value of the keyword + */ + std::string PvlFormatPds::FormatEnum (const PvlKeyword &keyword, int num) { + + iString val; + val.clear(); + bool singleUnit = false; + + // Create a Null value if the value index is greater than the number of values + if ((num >= keyword.Size()) || (keyword[num].size() == 0)) { + return "NULL"; + } + + // If it is an array start it off with a paren + if ((keyword.Size() > 1) && (num == 0)) { + val += "("; + } + + // Handle PDS special values "N/A" "NULL" "UNK" + iString tmp = keyword[num]; + tmp.UpCase(); + if ((tmp == "N/A") || (tmp == "NULL") || (tmp == "UNK")) { + val += "\"" + tmp + "\""; + } + else { + val += keyword[num]; + } + + // Add the units to this value + if ((!singleUnit) && (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // unit.UpCase(); + val += " <" + unit + ">"; + } + + // Add a comma for arrays + if (num != keyword.Size()-1) { + val += ", "; + } + // If it is an array, close it off + else if (keyword.Size() > 1) { + val += ")"; + } + + // Add the units to the end if all values have the same units + if ((singleUnit) && (num == keyword.Size()-1) && + (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // unit.UpCase(); + val += " <" + unit + ">"; + } + + return val; + } + + + /* + * Returns the keyword value formatted without any knowledge of its type + * + * @param keyword The PvlKeyword to be formatted + * @param num Use the ith value of the keyword + * @internal + * @history 2009-09-15 Jeannie Walldren - Moved the call to AddQuotes() + * inside the else-statement since + * the if portion of the code already + * adds quotes automatically + */ + std::string PvlFormatPds::FormatUnknown (const PvlKeyword &keyword, int num) { + + iString val; + val.clear(); + bool singleUnit = false; + + // Create a Null value if the value index is greater than the number of values + if ((num >= keyword.Size()) || (keyword[num].size() == 0)) { + return "NULL"; + } + + // Handle PDS special values "N/A" "NULL" "UNK" + iString tmp = keyword[num]; + tmp.UpCase(); + if ((tmp == "N/A") || (tmp == "NULL") || (tmp == "UNK")) { + val += "\"" + tmp + "\""; + } + else { + val += keyword[num]; + val = PvlFormat::AddQuotes (val); + } + + + // If it is an array start it off with a paren + if ((keyword.Size() > 1) && (num == 0)) { + val = "(" + val; + } + + // Add the units to this value + if ((!singleUnit) && (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // unit.UpCase(); + val += " <" + unit + ">"; + } + + // Add a comma for arrays + if (num != keyword.Size()-1) { + val += ", "; + } + // If it is an array, close it off + else if (keyword.Size() > 1) { + val += ")"; + } + + // Add the units to the end if all values have the same units + if ((singleUnit) && (num == keyword.Size()-1) && + (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // unit.UpCase(); + val += " <" + unit + ">"; + } + + return val; + } + + + /* + * Returns the keyword value formatted as an integer + * + * @param keyword The PvlKeyword to be formatted + * @param num Use the ith value of the keyword + */ + std::string PvlFormatPds::FormatInteger (const PvlKeyword &keyword, int num, int bytes) { + + iString val; + val.clear(); + bool singleUnit = false; + + // Create a Null value if the value index is greater than the number of values + if ((num >= keyword.Size()) || (keyword[num].size() == 0)) { + return "NULL"; + } + + // If it is an array start it off with a paren + if ((keyword.Size() > 1) && (num == 0)) { + val += "("; + } + + // Handle PDS special values "N/A" "NULL" "UNK" + iString tmp = keyword[num]; + tmp.UpCase(); + if ((tmp == "N/A") || (tmp == "NULL") || (tmp == "UNK")) { + val += "\"" + tmp + "\""; + } + else { + val += keyword[num]; + } + + // Add the units to this value + if ((!singleUnit) && (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // unit.UpCase(); + val += " <" + unit + ">"; + } + + // Add a comma for arrays + if (num != keyword.Size()-1) { + val += ", "; + } + // If it is an array, close it off + else if (keyword.Size() > 1) { + val += ")"; + } + + // Add the units to the end if all values have the same units + if ((singleUnit) && (num == keyword.Size()-1) && + (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // unit.UpCase(); + val += " <" + unit + ">"; + } + + return val; + } + + + /* + * Returns the keyword value formatted as a binary value + * + * @param keyword The PvlKeyword to be formatted + * @param num Use the ith value of the keyword + */ + std::string PvlFormatPds::FormatBinary (const PvlKeyword &keyword, int num, int bits) { + + iString val; + val.clear(); + bool singleUnit = false; + + // Create a Null value if the value index is greater than the number of values + stringstream ss; + if ((num >= keyword.Size()) || (keyword[num].size() == 0)) { + return "NULL"; + } + + // If it is an array start it off with a paren + if ((keyword.Size() > 1) && (num == 0)) { + val += "("; + } + + // Handle PDS special values "N/A" "NULL" "UNK" + iString tmp = keyword[num]; + tmp.UpCase(); + if ((tmp == "N/A") || (tmp == "NULL") || (tmp == "UNK")) { + val += "\"" + tmp + "\""; + } + else { + tmp.clear(); + BigInt value = (BigInt)keyword[num]; + string binDig = "01"; + do { + tmp = binDig[value % 2] + tmp; + value /= 2; + } while (value); + + ss << right << setfill('0') << setw(bits) << tmp; + tmp = ss.str(); + val += "2#" + tmp + "#"; + } + + // Add the units to this value + if ((!singleUnit) && (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // unit.UpCase(); + val += " <" + unit + ">"; + } + + // Add a comma for arrays + if (num != keyword.Size()-1) { + val += ", "; + } + // If it is an array, close it off + else if (keyword.Size() > 1) { + val += ")"; + } + + // Add the units to the end if all values have the same units + if ((singleUnit) && (num == keyword.Size()-1) && + (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // unit.UpCase(); + val += " <" + unit + ">"; + } + + return val; + } + + + /* + * Returns the keyword value formatted as a hexidecimal value + * + * @param keyword The PvlKeyword to be formatted + * @param num Use the ith value of the keyword + */ + + + std::string PvlFormatPds::FormatHex (const PvlKeyword &keyword, int num, int bytes) { + + iString val; + val.clear(); + bool singleUnit = false; + + // Create a Null value if the value index is greater than the number of values + if ((num >= keyword.Size()) || (keyword[num].size() == 0)) { + return "NULL"; + } + + // If it is an array start it off with a paren + if ((keyword.Size() > 1) && (num == 0)) { + val += "("; + } + + // Handle PDS special values "N/A" "NULL" "UNK" + iString tmp = keyword[num]; + tmp.UpCase(); + if ((tmp == "N/A") || (tmp == "NULL") || (tmp == "UNK")) { + val += "\"" + tmp + "\""; + } + else { + stringstream ss; + if (bytes == 2) { + ss << hex << (unsigned short int)(int)keyword[num]; + } + else if (bytes == 4) { + ss << hex << (unsigned int)(int)keyword[num]; + } + else { + ss << hex << (BigInt)keyword[num]; + } + iString h = ss.str(); + h.UpCase(); + val += "16#" + h + "#"; + } + + // Add the units to this value + if ((!singleUnit) && (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // unit.UpCase(); + val += " <" + unit + ">"; + } + + // Add a comma for arrays + if (num != keyword.Size()-1) { + val += ", "; + } + // If it is an array, close it off + else if (keyword.Size() > 1) { + val += ")"; + } + + // Add the units to the end if all values have the same units + if ((singleUnit) && (num == keyword.Size()-1) && + (keyword.Unit(num).size() > 0)) { + iString unit = keyword.Unit(num); + // unit.UpCase(); + val += " <" + unit + ">"; + } + + return val; + } + + + /* + * Returns the keyword value formatted as a boolean value + * + * @param keyword The PvlKeyword to be formatted + * @param num Use the ith value of the keyword + */ + std::string PvlFormatPds::FormatBool (const PvlKeyword &keyword, int num) { + + iString val; + val.clear(); + + // Create a Null value if the value index is greater than the number of values + if ((num >= keyword.Size()) || (keyword[num].size() == 0)) { + return "NULL"; + } + + // If it is an array start it off with a paren + if ((keyword.Size() > 1) && (num == 0)) { + val += "("; + } + + // Handle PDS special values "N/A" "NULL" "UNK" + iString tmp = keyword[num]; + tmp.UpCase(); + if ((tmp == "N/A") || (tmp == "NULL") || (tmp == "UNK")) { + val += "\"" + tmp + "\""; + } + else { + val += keyword[num]; + } + + // Add a comma for arrays + if (num != keyword.Size()-1) { + val += ", "; + } + // If it is an array, close it off + else if (keyword.Size() > 1) { + val += ")"; + } + + return val; + } + + + + + /* + * Format the name of this container + * + * @param keyword The keyword (i.e., the Object or Group) + */ + std::string PvlFormatPds::FormatName (const PvlKeyword &keyword) { + iString text = keyword.Name(); + text.UpCase(); + return text; + }; + + + /* + * Format the end of a group or object + * + * @param name A string representing the end text. + * @param keyword The keyword (i.e., the Object or Group) that is ending + */ + std::string PvlFormatPds::FormatEnd (const std::string name, + const PvlKeyword &keyword) { + iString left = name; + left.UpCase(); + left += " = "; + iString right = (string)keyword; + right.UpCase(); + return left + right; + }; + + + /* + * Put quotes around the value of a keyword of type string according to PDS + * standards. All keywords identified as "string" are quoted for PDS labels. + * + * @param value The value of a PvlKeyword to be formatted. + * @internal + * @history 2009-09-15 Jeannie Walldren - Added case to skip add quotes if + * the first character of the + * string is " or ' + */ + std::string PvlFormatPds::AddQuotes (const std::string value) { + + std::string val = value; + + bool quoteValue = true; + bool singleQuoteValue = false; + if (val.find(" ") != std::string::npos) { + if (val.find("\"") != std::string::npos) { + singleQuoteValue = true; + quoteValue = false; + } + } + + // Turn the quoting back off if this value looks like a sequence + // In this case the internal values should already be quoted. + if (val[0] == '(') { + singleQuoteValue = false; + quoteValue = false; + } + else if (val[0] == '"') { + singleQuoteValue = false; + quoteValue = false; + } + else if (val[0] == '\'') { + singleQuoteValue = false; + quoteValue = false; + } + + if (quoteValue) { + val = "\"" + val + "\""; + } + else if (singleQuoteValue) { + val = "'" + val + "'"; + } + + return val; + } + +} + diff --git a/isis/src/base/objs/PvlFormatPds/PvlFormatPds.h b/isis/src/base/objs/PvlFormatPds/PvlFormatPds.h new file mode 100644 index 0000000000000000000000000000000000000000..6c3f6a9668cbc7dca6aacf99eb91f52575be2717 --- /dev/null +++ b/isis/src/base/objs/PvlFormatPds/PvlFormatPds.h @@ -0,0 +1,93 @@ +#ifndef PvlFormatPds_h +#define PvlFormatPds_h +/** + * @file + * $Revision: 1.6 $ + * $Date: 2009/09/15 21:13:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "PvlFormat.h" + +namespace Isis { +/** + * @brief Formats the value of a PvlKeyword into a PDS complient string + * + * This class is used to format a single PVL keyword-value pair. The supported + * formats are Normal and PDS. The keyword to type mapping is not defined until + * a Pvl or Pvl formatted file is supplied. + * + * @ingroup Parsing + * + * @author 2006-09-05 Stuart Sides + * + * @internal + * @history 2006-09-05 Stuart Sides - Original version + * @history 2006-12-14 Stuart Sides - Took out the upcaseing of units + * @history 2008-09-19 Kris Becker - Put quotes around "N/A", "NULL", "UNK"; + * ensure units are placed after each element + * in array instead of one at the end and + * outside the closing right parenthesis. + * These changes bring us more in line with + * PDS compliancy. + * @history 2008-09-30 Christopher Austin - added FormatEOL() + * @history 2009-09-15 Jeannie Walldren - Fixed bug where code was adding 2 + * sets of quotes to N/A when formatting + * value. These changes were made in + * AddQuotes(), FormatString() and + * FormatUnknown() methods. + */ + + class PvlFormatPds : public PvlFormat { + + public: + + PvlFormatPds(); + PvlFormatPds(const std::string &file); + PvlFormatPds(Pvl &keymap); + virtual ~PvlFormatPds () {}; + + virtual std::string FormatValue (const PvlKeyword &keyword, + int valueIndex = 0); + virtual std::string FormatName (const PvlKeyword &keyword); + virtual std::string FormatEnd (const std::string name, + const PvlKeyword &keyword); + virtual std::string FormatEOL () { return "\015\012"; } + + protected: + virtual std::string AddQuotes (const std::string value); + + std::string FormatString (const PvlKeyword &keyword, int num); + std::string FormatInteger (const PvlKeyword &keyword, int num, int bytes); + std::string FormatReal (const PvlKeyword &keyword, int num, int precision); + std::string FormatEnum (const PvlKeyword &keyword, int num); + std::string FormatBinary (const PvlKeyword &keyword, int num, int bytes); + std::string FormatHex (const PvlKeyword &keyword, int num, int bytes); + std::string FormatBool (const PvlKeyword &keyword, int num); + std::string FormatUnknown (const PvlKeyword &keyword, int num); + + private: + void Init(); + }; +}; + +#endif + diff --git a/isis/src/base/objs/PvlFormatPds/PvlFormatPds.truth b/isis/src/base/objs/PvlFormatPds/PvlFormatPds.truth new file mode 100644 index 0000000000000000000000000000000000000000..c87045875d844cd323158b0dc49d3700c8e37690 --- /dev/null +++ b/isis/src/base/objs/PvlFormatPds/PvlFormatPds.truth @@ -0,0 +1,260 @@ +skey = somestringval +SKEY = "somestringval" +skey = "string val" +SKEY = "string val" +sNAstring = N/A +SNASTRING = "N/A" +sUNKquote = "UNK" +SUNKQUOTE = "UNK" +ssinglequote = 'NA' +SSINGLEQUOTE = 'NA' +notinmap = "junk string" +NOTINMAP = "junk string" +myint = 12345 +MYINT = 12345 +myfloat = -1.234567e+93 +MYFLOAT = -1.234567e+93 +fkey = -12345.6789 +FKEY = -12345.6789 +fkey0 = -9876.543 +FKEY0 = -9877 +fkey0 = -9.876543e-96 +FKEY0 = -0 +fkey2 = 0.123456 +FKEY2 = 0.12 +fkey2 = (0.123456, 987.123) +FKEY2 = (0.12 , 987.12 ) +fkey2 = (0.123456 , 987.123) +FKEY2 = (0.12 , 987.12) +ekey = unsigned +EKEY = unsigned +myarray = (12345,"a short string",1.234) +MYARRAY = (12345,"a short string",1.234) +hkey0 = 1311768467463790335 +HKEY0 = 16#123456789ABCDEFF# +hkey2 = 31371 +HKEY2 = 16#7A8B# +hkey4 = 439041101 +HKEY4 = 16#1A2B3C4D# +binkey = 10 +BINKEY = 2#0001010# +binkey16 = 65535 +BINKEY16 = 2#1111111111111111# +intkeyarray = (1, NULL, 3, NULL) +INTKEYARRAY = (1, "NULL", 3, "NULL") +intkeyarray = (1 , NULL , 3 , N/A, UNK) +INTKEYARRAY = (1 , "NULL" , 3 , "N/A", "UNK") +dblkeyarray = (1.01, NULL, 3.4, UNK) +DBLKEYARRAY = (1.01, "NULL", 3.40, "UNK") +=============================== Before +Group = Group1 + skey = stringval + mystring = "string val" + sNULLstring = NULL + sUNKquote = "UNK" + sNAsingle = 'N/A' + myint = 12345 + myfloat = 1.234567e+93 + myarray = (12345,"a short string",1.234) +End_Group +=============================== After +GROUP = GROUP1 + SKEY = "stringval" + MYSTRING = "string val" + SNULLSTRING = "NULL" + SUNKQUOTE = "UNK" + SNASINGLE = 'N/A' + MYINT = 12345 + MYFLOAT = 1.234567e+93 + MYARRAY = (12345,"a short string",1.234) +END_GROUP = GROUP1 +=============================== Before +Object = Object1 + skey = stringval + mystring = "string val" + sNULLstring = NULL + sUNKquote = "UNK" + sNAsingle = 'N/A' + myint = 12345 + myfloat = 1.234567e+93 + myarray = (12345,"a short string",1.234) + + Object = Object2 + skey = stringval + mystring = "string val" + sNULLstring = NULL + sUNKquote = "UNK" + sNAsingle = 'N/A' + myint = 12345 + myfloat = 1.234567e+93 + myarray = (12345,"a short string",1.234) + End_Object + + Group = Group1 + skey = stringval + mystring = "string val" + sNULLstring = NULL + sUNKquote = "UNK" + sNAsingle = 'N/A' + myint = 12345 + myfloat = 1.234567e+93 + myarray = (12345,"a short string",1.234) + End_Group +End_Object +=============================== After +OBJECT = OBJECT1 + SKEY = "stringval" + MYSTRING = "string val" + SNULLSTRING = "NULL" + SUNKQUOTE = "UNK" + SNASINGLE = 'N/A' + MYINT = 12345 + MYFLOAT = 1.234567e+93 + MYARRAY = (12345,"a short string",1.234) + + OBJECT = OBJECT2 + SKEY = "stringval" + MYSTRING = "string val" + SNULLSTRING = "NULL" + SUNKQUOTE = "UNK" + SNASINGLE = 'N/A' + MYINT = 12345 + MYFLOAT = 1.234567e+93 + MYARRAY = (12345,"a short string",1.234) + END_OBJECT = OBJECT2 + + GROUP = GROUP1 + SKEY = "stringval" + MYSTRING = "string val" + SNULLSTRING = "NULL" + SUNKQUOTE = "UNK" + SNASINGLE = 'N/A' + MYINT = 12345 + MYFLOAT = 1.234567e+93 + MYARRAY = (12345,"a short string",1.234) + END_GROUP = GROUP1 +END_OBJECT = OBJECT1 +=============================== Before +skey = stringval +mystring = "string val" +sNULLstring = NULL +sUNKquote = "UNK" +sNAsingle = 'N/A' +myint = 12345 +myfloat = 1.234567e+93 +myarray = (12345,"a short string",1.234) + +Object = Object1 + skey = stringval + mystring = "string val" + sNULLstring = NULL + sUNKquote = "UNK" + sNAsingle = 'N/A' + myint = 12345 + myfloat = 1.234567e+93 + myarray = (12345,"a short string",1.234) + + Object = Object2 + skey = stringval + mystring = "string val" + sNULLstring = NULL + sUNKquote = "UNK" + sNAsingle = 'N/A' + myint = 12345 + myfloat = 1.234567e+93 + myarray = (12345,"a short string",1.234) + binkey16 = 496 + End_Object + + Group = Group1 + skey = stringval + mystring = "string val" + sNULLstring = NULL + sUNKquote = "UNK" + sNAsingle = 'N/A' + myint = 12345 + myfloat = 1.234567e+93 + myarray = (12345,"a short string",1.234) + End_Group +End_Object + +Group = Group2 + skey = stringval + mystring = "string val" + sNULLstring = NULL + sUNKquote = "UNK" + sNAsingle = 'N/A' + myint = 12345 + myfloat = 1.234567e+93 + myarray = (12345,"a short string",1.234) + binkey16 = 32769 + wrapword = "The quick brown fox jumped over the lazy duck. Repunzel + Repunzel let down your hair. The little toy dog is covered + with dust, but sturdy and staunch he stands; and the little + toy soldier is red with rust." + array = (12345, 67890, 12345, 67890, 12345, 67890, 12345, 67890, + 12345, 67890, 12345, 67890, 12345, 67890, 12345) +End_Group +End +=============================== After +SKEY = "stringval" +MYSTRING = "string val" +SNULLSTRING = "NULL" +SUNKQUOTE = "UNK" +SNASINGLE = 'N/A' +MYINT = 12345 +MYFLOAT = 1.234567e+93 +MYARRAY = (12345,"a short string",1.234) + +OBJECT = OBJECT1 + SKEY = "stringval" + MYSTRING = "string val" + SNULLSTRING = "NULL" + SUNKQUOTE = "UNK" + SNASINGLE = 'N/A' + MYINT = 12345 + MYFLOAT = 1.234567e+93 + MYARRAY = (12345,"a short string",1.234) + + OBJECT = OBJECT2 + SKEY = "stringval" + MYSTRING = "string val" + SNULLSTRING = "NULL" + SUNKQUOTE = "UNK" + SNASINGLE = 'N/A' + MYINT = 12345 + MYFLOAT = 1.234567e+93 + MYARRAY = (12345,"a short string",1.234) + BINKEY16 = 2#0000000111110000# + END_OBJECT = OBJECT2 + + GROUP = GROUP1 + SKEY = "stringval" + MYSTRING = "string val" + SNULLSTRING = "NULL" + SUNKQUOTE = "UNK" + SNASINGLE = 'N/A' + MYINT = 12345 + MYFLOAT = 1.234567e+93 + MYARRAY = (12345,"a short string",1.234) + END_GROUP = GROUP1 +END_OBJECT = OBJECT1 + +GROUP = GROUP2 + SKEY = "stringval" + MYSTRING = "string val" + SNULLSTRING = "NULL" + SUNKQUOTE = "UNK" + SNASINGLE = 'N/A' + MYINT = 12345 + MYFLOAT = 1.234567e+93 + MYARRAY = (12345,"a short string",1.234) + BINKEY16 = 2#1000000000000001# + WRAPWORD = "The quick brown fox jumped over the lazy duck. Repunzel + Repunzel let down your hair. The little toy dog is covered + with dust, but sturdy and staunch he stands; and the little + toy soldier is red with rust." + ARRAY = (12345, 67890, 12345, 67890, 12345, 67890, 12345, 67890, + 12345, 67890, 12345, 67890, 12345, 67890, 12345) +END_GROUP = GROUP2 +End diff --git a/isis/src/base/objs/PvlFormatPds/unitTest.cpp b/isis/src/base/objs/PvlFormatPds/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79873659f02e9c3392e7b7c6607cfc938763bbba --- /dev/null +++ b/isis/src/base/objs/PvlFormatPds/unitTest.cpp @@ -0,0 +1,393 @@ +#include + +#include "Pvl.h" +#include "PvlKeyword.h" +#include "PvlGroup.h" +#include "PvlObject.h" +#include "Filename.h" +#include "iException.h" +#include "Constants.h" +#include "PvlFormatPds.h" +#include "Preference.h" + +using namespace std; +int main () { + Isis::Preference::Preferences(true); + + try { + + Isis::PvlFormatPds *pdsFormatter; + + // Create a temp file for the keyword to type map + { + Isis::Filename fname; + fname.Temporary("tempPvlFormatPDSunitTest_", "map"); + std::string pdsFile = fname.Expanded(); + + ofstream out; + out.open(pdsFile.c_str(), std::ios::out); + + {Isis::PvlKeyword key("skey", "string"); out<FormatEOL(); + } + + { + Isis::PvlKeyword key("skey", "string val","chars"); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("sNAstring", "N/A"); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("sUNKquote", "\"UNK\""); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("ssinglequote", "\'NA\'"); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("notinmap", "junk string"); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("myint", 12345); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("myfloat", -12345.67e+89,"degrees"); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("fkey", -12345.6789); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("fkey0", -9876.543); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("fkey0", -9876.543e-99); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("fkey2", 0.123456); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("fkey2", 0.123456, "goofys"); + key.AddValue(987.123, "goofys"); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("fkey2", 0.123456, "goofys"); + key.AddValue(987.123); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("ekey", "unsigned"); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("myarray", "(12345,\"a short string\",1.234)"); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("hkey0", (Isis::BigInt)0x123456789abcdeffLL); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("hkey2", 0x7a8b); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("hkey4", 0x1a2b3c4d); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("binkey", 0xA); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("binkey16", 0xffff); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("intkeyarray", 1); + key.AddValue("NULL"); + key.AddValue("3"); + key.AddValue("NULL"); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("intkeyarray", 1,"m"); + key.AddValue("NULL","m"); + key.AddValue("3","m"); + key.AddValue("N/A"); + key.AddValue("UNK"); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + { + Isis::PvlKeyword key("dblkeyarray", 1.01); + key.AddValue("NULL"); + key.AddValue("3.4"); + key.AddValue("UNK"); + cout << key << endl; + key.SetFormat(pdsFormatter); + cout << key << pdsFormatter->FormatEOL(); + } + + + // Test Groups + { + Isis::PvlGroup grp("Group1"); + grp += Isis::PvlKeyword ("skey", "stringval"); + grp += Isis::PvlKeyword ("mystring", "string val"); + grp += Isis::PvlKeyword ("sNULLstring", "NULL"); // should add quotes after format set + grp += Isis::PvlKeyword ("sUNKquote", "\"UNK\""); // should not add more quotes + grp += Isis::PvlKeyword ("sNAsingle", "\'N/A\'"); // should not add more quotes + grp += Isis::PvlKeyword ("myint", 12345); + grp += Isis::PvlKeyword ("myfloat", 12345.67e+89); + grp += Isis::PvlKeyword ("myarray", "(12345,\"a short string\",1.234)"); + cout << "=============================== Before" << endl; + cout << grp << endl; + grp.SetFormat(pdsFormatter); + cout << "=============================== After" << endl; + cout << grp << pdsFormatter->FormatEOL(); + } + + + // Test Objects + { + Isis::PvlGroup grp("Group1"); + grp += Isis::PvlKeyword ("skey", "stringval"); + grp += Isis::PvlKeyword ("mystring", "string val"); + grp += Isis::PvlKeyword ("sNULLstring", "NULL"); // should add quotes after format set + grp += Isis::PvlKeyword ("sUNKquote", "\"UNK\""); // should not add more quotes + grp += Isis::PvlKeyword ("sNAsingle", "\'N/A\'"); // should not add more quotes + grp += Isis::PvlKeyword ("myint", 12345); + grp += Isis::PvlKeyword ("myfloat", 12345.67e+89); + grp += Isis::PvlKeyword ("myarray", "(12345,\"a short string\",1.234)"); + Isis::PvlObject obj("Object1"); + obj.AddGroup(grp); + + Isis::PvlObject obj2("Object2"); + obj2 += Isis::PvlKeyword ("skey", "stringval"); + obj2 += Isis::PvlKeyword ("mystring", "string val"); + obj2 += Isis::PvlKeyword ("sNULLstring", "NULL"); // should add quotes after format set + obj2 += Isis::PvlKeyword ("sUNKquote", "\"UNK\""); // should not add more quotes + obj2 += Isis::PvlKeyword ("sNAsingle", "\'N/A\'"); // should not add more quotes + obj2 += Isis::PvlKeyword ("myint", 12345); + obj2 += Isis::PvlKeyword ("myfloat", 12345.67e+89); + obj2 += Isis::PvlKeyword ("myarray", "(12345,\"a short string\",1.234)"); + obj.AddObject(obj2); + + obj += Isis::PvlKeyword ("skey", "stringval"); + obj += Isis::PvlKeyword ("mystring", "string val"); + obj += Isis::PvlKeyword ("sNULLstring", "NULL"); // should add quotes after format set + obj += Isis::PvlKeyword ("sUNKquote", "\"UNK\""); // should not add more quotes + obj += Isis::PvlKeyword ("sNAsingle", "\'N/A\'"); // should not add more quotes + obj += Isis::PvlKeyword ("myint", 12345); + obj += Isis::PvlKeyword ("myfloat", 12345.67e+89); + obj += Isis::PvlKeyword ("myarray", "(12345,\"a short string\",1.234)"); + + + cout << "=============================== Before" << endl; + cout << obj << endl; + obj.SetFormat(pdsFormatter); + cout << "=============================== After" << endl; + cout << obj << pdsFormatter->FormatEOL(); + } + + + // Test Pvl + { + Isis::Pvl pvl; + + Isis::PvlObject obj("Object1"); + + Isis::PvlGroup grp("Group1"); + grp += Isis::PvlKeyword ("skey", "stringval"); + grp += Isis::PvlKeyword ("mystring", "string val"); + grp += Isis::PvlKeyword ("sNULLstring", "NULL"); // should add quotes after format set + grp += Isis::PvlKeyword ("sUNKquote", "\"UNK\""); // should not add more quotes + grp += Isis::PvlKeyword ("sNAsingle", "\'N/A\'"); // should not add more quotes + grp += Isis::PvlKeyword ("myint", 12345); + grp += Isis::PvlKeyword ("myfloat", 12345.67e+89); + grp += Isis::PvlKeyword ("myarray", "(12345,\"a short string\",1.234)"); + obj.AddGroup(grp); + + Isis::PvlObject obj2("Object2"); + obj2 += Isis::PvlKeyword ("skey", "stringval"); + obj2 += Isis::PvlKeyword ("mystring", "string val"); + obj2 += Isis::PvlKeyword ("sNULLstring", "NULL"); // should add quotes after format set + obj2 += Isis::PvlKeyword ("sUNKquote", "\"UNK\""); // should not add more quotes + obj2 += Isis::PvlKeyword ("sNAsingle", "\'N/A\'"); // should not add more quotes + obj2 += Isis::PvlKeyword ("myint", 12345); + obj2 += Isis::PvlKeyword ("myfloat", 12345.67e+89); + obj2 += Isis::PvlKeyword ("myarray", "(12345,\"a short string\",1.234)"); + obj2 += Isis::PvlKeyword ("binkey16", 0x01f0); + obj.AddObject(obj2); + + obj += Isis::PvlKeyword ("skey", "stringval"); + obj += Isis::PvlKeyword ("mystring", "string val"); + obj += Isis::PvlKeyword ("sNULLstring", "NULL"); // should add quotes after format set + obj += Isis::PvlKeyword ("sUNKquote", "\"UNK\""); // should not add more quotes + obj += Isis::PvlKeyword ("sNAsingle", "\'N/A\'"); // should not add more quotes + obj += Isis::PvlKeyword ("myint", 12345); + obj += Isis::PvlKeyword ("myfloat", 12345.67e+89); + obj += Isis::PvlKeyword ("myarray", "(12345,\"a short string\",1.234)"); + + pvl += Isis::PvlKeyword ("skey", "stringval"); + pvl += Isis::PvlKeyword ("mystring", "string val"); + pvl += Isis::PvlKeyword ("sNULLstring", "NULL"); // should add quotes after format set + pvl += Isis::PvlKeyword ("sUNKquote", "\"UNK\""); // should not add more quotes + pvl += Isis::PvlKeyword ("sNAsingle", "\'N/A\'"); // should not add more quotes + pvl += Isis::PvlKeyword ("myint", 12345); + pvl += Isis::PvlKeyword ("myfloat", 12345.67e+89); + pvl += Isis::PvlKeyword ("myarray", "(12345,\"a short string\",1.234)"); + + pvl.AddObject(obj); + + Isis::PvlGroup grp2("Group2"); + grp2 += Isis::PvlKeyword ("skey", "stringval"); + grp2 += Isis::PvlKeyword ("mystring", "string val"); + grp2 += Isis::PvlKeyword ("sNULLstring", "NULL"); // should add quotes after format set + grp2 += Isis::PvlKeyword ("sUNKquote", "\"UNK\""); // should not add more quotes + grp2 += Isis::PvlKeyword ("sNAsingle", "\'N/A\'"); // should not add more quotes + grp2 += Isis::PvlKeyword ("myint", 12345); + grp2 += Isis::PvlKeyword ("myfloat", 12345.67e+89); + grp2 += Isis::PvlKeyword ("myarray", "(12345,\"a short string\",1.234)"); + grp2 += Isis::PvlKeyword ("binkey16", 0x8001); + grp2 += Isis::PvlKeyword ("wrapword", "The quick brown fox jumped over the lazy duck. " + "Repunzel Repunzel let down your hair. The little toy dog is covered with dust," + " but sturdy and staunch he stands; and the little toy soldier is red with rust."); + Isis::PvlKeyword key( Isis::PvlKeyword ("array", 12345) ); + key.AddValue(67890); + key.AddValue(12345); + key.AddValue(67890); + key.AddValue(12345); + key.AddValue(67890); + key.AddValue(12345); + key.AddValue(67890); + key.AddValue(12345); + key.AddValue(67890); + key.AddValue(12345); + key.AddValue(67890); + key.AddValue(12345); + key.AddValue(67890); + key.AddValue(12345); + grp2 += key; + pvl.AddGroup(grp2); + + + cout << "=============================== Before" << endl; + cout << pvl << endl; + pvl.SetFormat(pdsFormatter); + cout << "=============================== After" << endl; + cout << pvl << pdsFormatter->FormatEOL(); + } + + + } + catch (Isis::iException &e) { + e.Report(false); + } + + +} + diff --git a/isis/src/base/objs/PvlGroup/Makefile b/isis/src/base/objs/PvlGroup/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f2d0cbcb60cdf4c7950567c45b41e239d182cfac --- /dev/null +++ b/isis/src/base/objs/PvlGroup/Makefile @@ -0,0 +1,5 @@ +INCS = PvlGroup.h +SRCS = PvlGroup.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PvlGroup/PvlGroup.cpp b/isis/src/base/objs/PvlGroup/PvlGroup.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a044c48b48e9f794ed7aa25f69ad1e63c019599 --- /dev/null +++ b/isis/src/base/objs/PvlGroup/PvlGroup.cpp @@ -0,0 +1,208 @@ +/** + * @file + * $Revision: 1.8 $ + * $Date: 2010/06/16 18:15:21 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PvlKeyword.h" +#include "iException.h" +#include "PvlFormat.h" +#include "PvlGroup.h" + +using namespace std; +namespace Isis { + //! Creates a blank PvlGroup object. + PvlGroup::PvlGroup() : Isis::PvlContainer("Group", "") {} + + /** + * Creates a PvlGroup object with a name. + * @param name The group name. + */ + PvlGroup::PvlGroup(const std::string &name) : + Isis::PvlContainer("Group", name) { + } + + + //! Copy constructor + PvlGroup::PvlGroup(const PvlGroup &other) : PvlContainer(other) {} + + + /** + * Read in a group + * + * @param is The input stream + * @param result The PvlGroup to read into (OUTPUT) + * + */ + std::istream &operator>>(std::istream &is, PvlGroup &result) { + PvlKeyword termination("EndGroup"); + + PvlKeyword errorKeywords[] = { + PvlKeyword("Group"), + PvlKeyword("Object"), + PvlKeyword("EndObject") + }; + + PvlKeyword readKeyword; + + istream::pos_type beforeKeywordPos = is.tellg(); + is >> readKeyword; + + if(readKeyword != PvlKeyword("Group")) { + if(is.eof() && !is.bad()) { + is.clear(); + } + + is.seekg(beforeKeywordPos, ios::beg); + + string msg = "Expected keyword named [Group], found keyword named ["; + msg += readKeyword.Name(); + msg += "]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + if(readKeyword.Size() == 1) { + result.SetName(readKeyword[0]); + } + else { + if(is.eof() && !is.bad()) { + is.clear(); + } + + is.seekg(beforeKeywordPos, ios::beg); + + string msg = "Expected a single value for group name, found [("; + + for(int i = 0; i < readKeyword.Size(); i++) { + if(i != 0) msg += ", "; + + msg += readKeyword[i]; + } + + msg += ")]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + + for(int comment = 0; comment < readKeyword.Comments(); comment++) { + result.AddComment(readKeyword.Comment(comment)); + } + + readKeyword = PvlKeyword(); + beforeKeywordPos = is.tellg(); + + is >> readKeyword; + while(is.good() && readKeyword != termination) { + for(unsigned int errorKey = 0; + errorKey < sizeof(errorKeywords) / sizeof(PvlKeyword); + errorKey++) { + + if(readKeyword == errorKeywords[errorKey]) { + if(is.eof() && !is.bad()) { + is.clear(); + } + + is.seekg(beforeKeywordPos, ios::beg); + + string msg = "Unexpected ["; + msg += readKeyword.Name(); + msg += "] in Group ["; + msg += result.Name(); + msg += "]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + } + + result.AddKeyword(readKeyword); + readKeyword = PvlKeyword(); + beforeKeywordPos = is.tellg(); + + is >> readKeyword; + } + + if(readKeyword != termination) { + if(is.eof() && !is.bad()) { + is.clear(); + is.unget(); + } + + is.seekg(beforeKeywordPos, ios::beg); + + string msg = "Group [" + result.Name(); + msg += "] EndGroup not found before end of file"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + return is; + } + + /** + * Outputs the PvlGroup data to a specified output stream. + * @param os The output stream to output to. + * @param group The PvlGroup object to output. + */ + ostream &operator<<(std::ostream &os, PvlGroup &group) { + + // Set up a Formatter + bool removeFormatter = false; + if(group.GetFormat() == NULL) { + group.SetFormat(new PvlFormat()); + removeFormatter = true; + } + + Isis::PvlGroup temp("DEFAULT"); + if(group.HasFormatTemplate()) temp = *(Isis::PvlGroup *)group.FormatTemplate(); + + // Output comment from the template + if(temp.Comments() > 0) { + for(int k = 0; k < temp.Comments(); k++) { + for(int l = 0; l < group.Indent(); l++) os << " "; + os << temp.Comment(k) << group.GetFormat()->FormatEOL(); + } +// os << group.GetFormat()->FormatEOL(); + } + + // Output the group comments and name + os << group.GetNameKeyword() << group.GetFormat()->FormatEOL(); + group.SetIndent(group.Indent() + 2); + + // Output the keywords in this group + if(group.Keywords() > 0) { + os << (Isis::PvlContainer &) group << group.GetFormat()->FormatEOL(); + } + + // Output the end of the group + group.SetIndent(group.Indent() - 2); + for(int i = 0; i < group.Indent(); i++) os << " "; + os << group.GetFormat()->FormatEnd("End_Group", group.GetNameKeyword()); + + if(removeFormatter) { + delete group.GetFormat(); + group.SetFormat(NULL); + } + + return os; + } + + + //! This is an assignment operator + const PvlGroup &PvlGroup::operator=(const PvlGroup &other) { + this->PvlContainer::operator=(other); + + return *this; + } +} // end namespace isis diff --git a/isis/src/base/objs/PvlGroup/PvlGroup.h b/isis/src/base/objs/PvlGroup/PvlGroup.h new file mode 100644 index 0000000000000000000000000000000000000000..ccd3ca0f3dbd5c62831e8e660ee1321da9c6ce0b --- /dev/null +++ b/isis/src/base/objs/PvlGroup/PvlGroup.h @@ -0,0 +1,76 @@ +#ifndef PvlGroup_h +#define PvlGroup_h +/** + * @file + * $Revision: 1.7 $ + * $Date: 2010/06/16 18:15:21 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PvlContainer.h" + +namespace Isis { + /** + * @brief Contains multiple PvlContainers + * + * Contains multiple PvlContainers so that keyword-value pairs can be organized + * in specific groups. For example, a PvlGroup would be used to group + * all data from a particular mission together. A PvlGroup object will also + * organize (indent) objects on output. + * + * @ingroup Parsing + * + * @author 2002-10-11 Jeff Anderson + * + * @internal + * @history 2005-04-04 Leah Dahmer wrote class documentation. + * @history 2006-04-21 Jacob Danton Added format templates abilities. + * @history 2006-09-11 Stuart Sides Added formatting ability + * @history 2008-07-02 Steven Lambright Added const functionality and fixed += + * @history 2008-07-02 Steven Lambright Updated to compensate for PvlKeyword no + * longer being a parent + * @history 2008-09-30 Christopher Austin Replaced all std::endl in the << + * operator with PvlFormat.FormatEOL() + * @history 2010-04-13 Eric Hyer - Added copy constructor + * Added assignment operator + * + * @todo 2005-04-04 Needs coded example. + */ + class PvlGroup : public Isis::PvlContainer { + public: + PvlGroup(); + PvlGroup(const std::string &name); + PvlGroup(const PvlGroup &other); + + friend std::istream &operator>>(std::istream &is, PvlGroup &result); + friend std::ostream &operator<<(std::ostream &os, PvlGroup &group); + /** + * Whenever the '==' operator is used on a PvlGroup object, it will call + * the StringEqual() method. This returns a boolean value. + * @param group The PvlGroup object to compare. + * @return True if the other PvlGroup has the same name as this one, false + * if not. + */ + bool operator==(const PvlGroup &group) const { + return PvlKeyword::StringEqual(group.Name(), this->Name()); + }; + + const PvlGroup &operator=(const PvlGroup &other); + }; +} +#endif diff --git a/isis/src/base/objs/PvlGroup/PvlGroup.truth b/isis/src/base/objs/PvlGroup/PvlGroup.truth new file mode 100644 index 0000000000000000000000000000000000000000..3ec599a7b11ec63553665fb0981e1be1435ffb89 --- /dev/null +++ b/isis/src/base/objs/PvlGroup/PvlGroup.truth @@ -0,0 +1,36 @@ +/* Pets are cool +Group = Animals + DOG = 5.2 + + # Cats shed + CATTLE = Meow +End_Group +5.2 + +/* Pets are cool +Group = Animals + # Cats shed + CATTLE = Meow +End_Group + +/* Pets are cool +Group = Animals +End_Group + +# Testing +/* 123 */ +Group = POODLE + CAT = TABBY + BIRD = PARROT + REPTILE = (SNAKE, LIZARD) + -VEGGIE = Null + BOVINE = (COW, CAMEL) + TREE = (MAPLE, ELM, PINE) + + # This is a comment + FLOWER = "DAISY & TULIP " + + /* This is another comment */ + BIG = (" NOT ", "REALLY LARGE") +End_Group +**PVL ERROR** Group [POODLE] EndGroup not found before end of file diff --git a/isis/src/base/objs/PvlGroup/unitTest.cpp b/isis/src/base/objs/PvlGroup/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..35fb5bd517d8113637bf3c6f5c4180962eaa731f --- /dev/null +++ b/isis/src/base/objs/PvlGroup/unitTest.cpp @@ -0,0 +1,80 @@ +#include +#include +#include "PvlGroup.h" +#include "PvlTokenizer.h" +#include "Preference.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +int main() { + Isis::Preference::Preferences(true); + + Isis::PvlKeyword dog("DOG", 5.2, "meters"); + Isis::PvlKeyword cat("CATTLE"); + cat = "Meow"; + cat.AddComment("Cats shed"); + + Isis::PvlGroup ani("Animals"); + ani += dog; + ani += cat; + ani.AddComment("/* Pets are cool"); + + cout << ani << endl; + + cout << (double) ani["dog"] << endl << endl; + + ani -= "dog"; + cout << ani << endl << endl; + + ani -= ani[0]; + cout << ani << endl << endl; + + stringstream os; + os << "# Testing" << endl + << "/* 123 */" << endl + << "Group=POODLE " << endl + << "CAT=\"TABBY\" " << endl + << "BIRD=(PARROT) \0" << endl + << "REPTILE={SNAKE,LIZARD} \t" << endl + << "-VEGGIE \n" + << " " + << " BOVINE = ( COW , CAMEL ) \n " + << "TREE = { \"MAPLE\" ,\n \"ELM\" \n, \"PINE\" }" << endl + << "FLOWER = \"DAISY & \nTULIP \"" + << "# This is a comment\n" + << "/* This is another comment */\n" + << "BIG = (\" NOT \",\"REALLY LARGE\")" << endl + << "EndGroup" << endl; + + PvlGroup g; + os >> g; + cout << g << endl; + + try { + stringstream os2; + os2 << "# Testing" << endl + << "/* 123 */" << endl + << "Group=POODLE " << endl + << "CAT=\"TABBY\" " << endl + << "BIRD=(PARROT) \0" << endl + << "REPTILE={SNAKE,LIZARD} \t" << endl + << "-VEGGIE \n" + << " " + << " BOVINE = ( COW , CAMEL ) \n " + << "TREE = { \"MAPLE\" ,\n \"ELM\" \n, \"PINE\" }" << endl + << "FLOWER = \"DAISY & \nTULIP \"" + << "# This is a comment\n" + << "/* This is another comment */\n" + << "BIG = (\" NOT \",\"REALLY LARGE\")" << endl; + + PvlGroup g2; + os2 >> g2; + cout << g2 << endl; + } + catch(iException &e) { + cout.flush(); + e.Report(false); + } +} diff --git a/isis/src/base/objs/PvlKeyword/Makefile b/isis/src/base/objs/PvlKeyword/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08105a7fd479811dd7d1d427fd520b38f9b42aa1 --- /dev/null +++ b/isis/src/base/objs/PvlKeyword/Makefile @@ -0,0 +1,5 @@ +INCS = PvlKeyword.h +SRCS = PvlKeyword.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PvlKeyword/PvlKeyword.cpp b/isis/src/base/objs/PvlKeyword/PvlKeyword.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2430de8657ce512f949b696be1c2eacb4f8f1bb1 --- /dev/null +++ b/isis/src/base/objs/PvlKeyword/PvlKeyword.cpp @@ -0,0 +1,1785 @@ +/** + * @file + * $Revision: 1.20 $ + * $Date: 2010/06/25 20:42:35 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "IsisDebug.h" + +#include "PvlKeyword.h" +#include "iException.h" +#include "Message.h" +#include "iString.h" +#include "PvlSequence.h" +#include "PvlFormat.h" + +using namespace std; +namespace Isis { + //! Constructs a blank PvlKeyword object. + PvlKeyword::PvlKeyword() { + Init(); + } + + + /** + * Constructs a PvlKeyword object with a name. + * + * @param name The keyword name + */ + PvlKeyword::PvlKeyword(const std::string &name) { + Init(); + SetName(name); + } + + + /** + * Constructs a PvlKeyword object with a name, value and units. + * Defaults to unit="". + * + * @param name The keyword name. + * @param value The keyword values. + * @param unit The units the values are given in. + */ + PvlKeyword::PvlKeyword(const std::string &name, const Isis::iString value, + const std::string unit) { + Init(); + SetName(name); + AddValue(value, unit); + } + + + //! Copy constructor + PvlKeyword::PvlKeyword(const PvlKeyword &other) { + *this = other; + } + + + /** + * Destructs a PvlKeyword object. + */ + PvlKeyword::~PvlKeyword() {} + + + //! Clears all PvlKeyword data. + void PvlKeyword::Init() { + Clear(); + ClearComments(); + SetName(""); + p_width = 0; + p_indent = 0; + p_formatter = NULL; + } + + /** + * Decides whether a value is null or not at a given index. + * Defaults to index = 0. + * + * @param index The value index + * @return bool True if the value is null, false if it's + * not. + */ + bool PvlKeyword::IsNull(const int index) const { + if(Size() == 0) return true; + if(index < 0 || index >= (int)p_values.size()) { + string msg = Isis::Message::ArraySubscriptNotInRange(index); + throw Isis::iException::Message(Isis::iException::Programmer, + msg, + _FILEINFO_); + } + if(StringEqual("NULL", p_values[index])) return true; + if(StringEqual("", p_values[index])) return true; + if(StringEqual("\"\"", p_values[index])) return true; + if(StringEqual("''", p_values[index])) return true; + return false; + } + + /** + * Sets the keyword name. + * + * @param name The new keyword name. + */ + void PvlKeyword::SetName(const std::string &name) { + iString final(name); + final.Trim("\n\r\t\f\v\b "); + if(final.find_first_of("\n\r\t\f\v\b ") != std::string::npos) { + string msg = "[" + name + "] is invalid. Keyword name cannot "; + msg += "contain whitespace."; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + p_name = final; + } + + /** + * Sets new values. + * + * If no current value exists, this method sets the given value + * to the PvlKeyword. Otherwise, it clears any existing values + * and resets to the value given using AddValue(). Defaults to + * unit = "" (empty string). + * + * @param value New value to be assigned. + * @param unit Units of measurement corresponding to the value. + * + * @see AddValue() + * @see operator= + * @see operator+= + */ + void PvlKeyword::SetValue(const Isis::iString value, const std::string unit) { + Clear(); + AddValue(value, unit); + } + + + /** + * Sets the unit of measure for all current values if any exist + * + * @param units New units to be assigned. + */ + void PvlKeyword::SetUnits(const iString &units) { + p_units.clear(); + for(unsigned int i = 0; i < p_values.size(); i++) { + p_units.push_back(units); + } + } + + + /** + * Sets the unit of measure for a given value + * + * @param value The value to match + * @param units New units to be assigned. + * + * @throws Isis::iException::Programmer - Given value must exist + */ + void PvlKeyword::SetUnits(const iString &value, const iString &units) { + + bool found = false; + int i = -1; + while(!found && ++i < (int) p_values.size()) { + if(value == p_values[i]) { + found = true; + } + } + + if(found) { + ASSERT(i < (int) p_units.size()); + + p_units[i] = units; + } + else { + iString msg = "PvlKeyword::SetUnits called with value [" + value + + "] which does not exist in this Keyword"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + /** + * + * Sets new values. + * + * Overwrites the '=' operator to add a new value using AddValue(). Like + * SetValue(), this method clears any previously existing values and resets to + * the given value with unit = "" (empty string). + * + * @param value The value to be added. + * @return PvlKeyword& Reference to PvlKeyword object. + * + * @see AddValue() + * @see SetValue() + * @see operator+= + */ + PvlKeyword &PvlKeyword::operator=(const Isis::iString value) { + Clear(); + AddValue(value); + return *this; + } + + /** + * Adds a value with units. + * + * If no current value exists, this method sets the given value. + * Otherwise, it retains any current values and adds the value + * given to the array of values for this PvlKeyword object. + * Defaults to unit = "" (empty string). + * + * @param value New value to be assigned. + * @param unit Units of measurement corresponding to the value. + * + * @see SetValue() + * @see operator= + * @see operator+= + */ + void PvlKeyword::AddValue(const Isis::iString value, const std::string unit) { + p_values.push_back(value); + p_units.push_back(unit); + } + + /** + * Adds a value. + * + * Overwrites the '+=' operators to add a new value. Like + * AddValue(), this method keeps any previously existing values + * and adds the new value with unit = "" (empty string) to the + * array of values for this PvlKeyword object. + * + * @param value The new value. + * @return PvlKeyword& Reference to PvlKeyword object. + * + * @see AddValue() + * @see SetValue() + * @see operator= + */ + PvlKeyword &PvlKeyword::operator+=(const Isis::iString value) { + AddValue(value); + return *this; + } + + //! Clears all values and units for this PvlKeyword object. + void PvlKeyword::Clear() { + p_values.clear(); + p_units.clear(); + } + + /** + * Gets value for this object at specified index. + * + * Overrides the '[]' operator to return the element in the + * array of values at the specified index. + * + * @param index The index of the value. + * @return iString The value at the index. + * @throws iException ArraySubscriptNotInRange (index) Index out of bounds. + * + * @see const operator[] + */ + Isis::iString &PvlKeyword::operator[](const int index) { + if(index < 0 || index >= (int)p_values.size()) { + string msg = (Isis::Message::ArraySubscriptNotInRange(index)) + + "for Keyword [" + p_name + "]"; + throw Isis::iException::Message(Isis::iException::Programmer, + msg, + _FILEINFO_); + } + return p_values[index]; + } + + /** + * Gets value for this object at specified index. + * + * Overrides the '[]' operator to return the element in the + * array of values at the specified index. + * + * @param index The index of the value. + * @return iString The value at the index. + * @throws iException ArraySubscriptNotInRange (index) Index out of bounds. + * + * @see operator[] + */ + const Isis::iString &PvlKeyword::operator[](const int index) const { + if(index < 0 || index >= (int)p_values.size()) { + string msg = Isis::Message::ArraySubscriptNotInRange(index); + throw Isis::iException::Message(Isis::iException::Programmer, + msg, + _FILEINFO_); + } + return p_values[index]; + } + + /** + * Returns the units of measurement of the element of the array + * of values for the object at the specified index. Defaults to + * index = 0. + * + * @param index The index of the unit. + * @return string The unit at the index. + * @throws iException ArraySubscriptNotInRange (index) Index out of bounds. + */ + string PvlKeyword::Unit(const int index) const { + if(index < 0 || index >= (int)p_units.size()) { + string msg = Isis::Message::ArraySubscriptNotInRange(index); + throw Isis::iException::Message(Isis::iException::Programmer, + msg, + _FILEINFO_); + } + return p_units[index]; + } + + /** + * Add a comment to the PvlKeyword. + * + * @param comment The new comment. + * + * @see AddCommentWrapped() + * @see AddComments() + * @see ClearComments() + */ + void PvlKeyword::AddComment(const std::string &comment) { + if(comment.size() == 0) { + p_comments.push_back("#"); + } + if(comment[0] == '#') { + p_comments.push_back(comment); + } + else if(comment.size() == 1) { + p_comments.push_back("# " + comment); + } + else if((comment[0] == '/') && (comment[1] == '*')) { + p_comments.push_back(comment); + } + else if((comment[0] == '/') && (comment[1] == '/')) { + p_comments.push_back(comment); + } + else { + p_comments.push_back("# " + comment); + } + } + + /** + * Automatically wraps and adds long comments to the PvlKeyword + * + * @param comment The new comment to add + * + * @see AddComment() + * @see AddComments() + * @see ClearComments() + */ + void PvlKeyword::AddCommentWrapped(const std::string &comment) { + iString cmt = comment; + string token = cmt.Token(" "); + while(cmt != "") { + string temp = token; + token = cmt.Token(" "); + int length = temp.size() + token.size() + 1; + while((length < 72) && (token.size() > 0)) { + temp += " " + token; + token = cmt.Token(" "); + length = temp.size() + token.size() + 1; + } + AddComment(temp); + } + if(token.size() != 0) AddComment(token); + } + + //! Clears the current comments. + void PvlKeyword::ClearComments() { + p_comments.clear(); + } + + /** + * Return a comment at the specified index. + * @param index The index of the comment. + * @return string The comment at the index. + * @throws iException ArraySubscriptNotInRange (index) Index out of bounds. + */ + string PvlKeyword::Comment(const int index) const { + if(index < 0 || index >= (int)p_comments.size()) { + string msg = Isis::Message::ArraySubscriptNotInRange(index); + throw Isis::iException::Message(Isis::iException::Programmer, + msg, + _FILEINFO_); + } + return p_comments[index]; + }; + + /** + * Checks if the value needs to be converted to PVL or iPVL and returns it in + * the correct format. + * @param value The value to be converted. + * @return string The value in its proper format (iPVL or + * PVL). + */ + string PvlKeyword::Reform(const std::string &value) const { +#if 0 + static bool firstTime = true; + static bool iPVL = true; + if(firstTime) { + firstTime = false; + Isis::PvlGroup &g = Isis::Preference::Preferences().FindGroup( + "UserInterface", Isis::Pvl::Traverse); + + Isis::iString s = (string) g["PvlFormat"]; + s.UpCase(); + if(s == "PVL") iPVL = false; + } + + if(iPVL) return ToIPvl(value); +#endif + return ToPvl(value); + } + + /** + * Converts a value to iPVL format. + * @param value The value to be converted. + * @return string The value in iPVL format. + */ + string PvlKeyword::ToIPvl(const std::string &value) const { + string out; + bool upcase = true; + bool lastlower = true; + for(unsigned int i = 0; i < value.size(); i++) { + if((lastlower) && (isupper(value[i]))) upcase = true; + if(value[i] == '_') { + upcase = true; + } + else if(upcase) { + out += toupper(value[i]); + lastlower = false; + upcase = false; + } + else { + out += tolower(value[i]); + if(islower(value[i])) lastlower = true; + upcase = false; + } + } + return out; + } + + /** + * Converts a value to PVL format. + * @param value The value to be converted. + * @return string The value in PVL format. + */ + string PvlKeyword::ToPvl(const std::string &value) const { + string out; + bool lastlower = false; + for(unsigned int i = 0; i < value.size(); i++) { + if((lastlower) && (isupper(value[i]))) out += "_"; + if(value[i] == '_') { + out += "_"; + lastlower = false; + } + else { + out += toupper(value[i]); + if(islower(value[i])) lastlower = true; + } + } + return out; + } + + /** + * Checks to see if two strings are equal. Each is converted to uppercase + * and removed of underscores and whitespaces. + * @param string1 The first string + * @param string2 The second string + * @return bool True or false, depending on whether + * the string values are equal. + */ + bool PvlKeyword::StringEqual(const std::string &string1, + const std::string &string2) { + Isis::iString s1(string1); + Isis::iString s2(string2); + + s1.ConvertWhiteSpace(); + s2.ConvertWhiteSpace(); + + s1.Remove(" _"); + s2.Remove(" _"); + + s1.UpCase(); + s2.UpCase(); + + if(s1 == s2) return true; + return false; + } + + /** + * Checks to see if a value with a specified index is equivalent to another + * string. + * @param string1 The string to compare the value to. + * @param index The index of the existing value. + * @return bool True if the two strings are equivalent, + * false if they're not. + * @throws iException ArraySubscriptNotInRange (index) Index out of bounds. + */ + bool PvlKeyword::IsEquivalent(const std::string &string1, int index) const { + if(index < 0 || index >= (int)p_values.size()) { + string msg = Isis::Message::ArraySubscriptNotInRange(index); + throw Isis::iException::Message(Isis::iException::Programmer, + msg, + _FILEINFO_); + } + + return StringEqual(p_values[index], string1); + } + + /** + * Add values and units from a PvlSequence. (Clears current values and units) + * @param seq The PvlSequence to add from. + * @return PvlKeyword& Reference to PvlKeyword object. + */ + PvlKeyword &PvlKeyword::operator=(Isis::PvlSequence &seq) { + this->Clear(); + for(int i = 0; i < seq.Size(); i++) { + string temp = "("; + for(int j = 0; j < (int)seq[i].size(); j++) { + string val = seq[i][j]; + if(val.find(" ") != std::string::npos) { + temp += "\"" + val + "\""; + } + else { + temp += val; + } + if(j < (int) seq[i].size() - 1) temp += ", "; + } + temp += ")"; + this->operator+=(temp); + } + + return *this; + } + + /** + * Wraps output so that length doesn't exceed the character + * limit. By default, the character limit is set to 80, and can + * be changed with the method SetCharLimit. Used as a helper + * method for output of PvlKeyword. + * + * @param os Designated output stream + * @param textToWrite The text to be written + * @param startColumn The starting column after the "=" sign. + * @param endOfLine The EOL character + * + * @return ostream& Reference to ostream. + * @see operator<< + */ + ostream &PvlKeyword::WriteWithWrap(std::ostream &os, + const std::string &textToWrite, + int startColumn, + PvlFormat &format) const { + + /* + http://pds.jpl.nasa.gov/tools/standards-reference.shtml + + pds.jpl.nasa.gov/documents/sr/Chapter12.pdf + + Object Description Language Specification and Usage + The following provides a complete specification for Object Description Language + (ODL), the language used to encode data labels for the Planetary Data System + (PDS) and other NASA data systems. This standard contains a formal definition of + the grammar semantics of the language. PDS specific implementation notes and + standards are referenced in separate sections. + + 12.5.3.1 Implementation of String Values + A text string read in from a label is reassembled into a string of characters. + The way in which the string is broken into lines in a label does not affect the + format of the string after it has been reassembled. The following rules are used + when reading text strings: If a format effector or a sequence of + format effectors is encountered within a text string, + the effector (or sequence of effectors) is replaced by a single space + character, unless the last character is a hyphen (dash) character. Any + spacing characters at the end of the line are removed and any spacing + characters at the beginning of the following line are removed. This + allows a text string in a label to appear with the left and right + margins set at arbitrary points without changing the string value. For + example, the following two strings are the same: "To be or + not to be" and + "To be or + not to be" + If the last character on a line prior to a format effector is a hyphen + (dash) character, the hyphen is removed with any spacing characters at + the beginning of the following line. This follows the standard + convention in English of using a hyphen to break a word across lines. + For example, the following two strings are the same: + "The planet Jupiter is very big" and + "The planet Jupi- + ter is very big" + Control codes, other than the horizontal tabulation character and + format effectors, appearing within a text string are removed. + */ + + /* + We will be adding a condition for human-readable purposes: + If a quoted string of text does not fit on the current line, + but will fit on the next line, use the next line. + */ + + // Position set + string remainingText = textToWrite; + int spaceForText = format.CharLimit() - 1 - format.FormatEOL().length() - startColumn; + + // find quote positions to better determine which line to put the + // string on. Data structure: vector< startPos, endPos > where + // remainingText[startPos] and remainingText[endPos] must both be quotes. + vector< pair > quotedAreas; + char endQuoteChar = '\0'; + int quoteStart = -1; + + // if its an array, indent subsequent lines 1 more + if(textToWrite[0] == '(' || textToWrite[0] == '"') { + startColumn ++; + } + + /* Standard 12.3.3.1 -> + A quoted text string may not contain the quotation mark, which is reserved + to be the text string delimiter. + + So we don't have to worry about escaped quotes. + */ + + vector< pair > quoteStartEnds; + quoteStartEnds.push_back(pair('"', '"')); + quoteStartEnds.push_back(pair('\'', '\'')); + quoteStartEnds.push_back(pair('<', '>')); + + // clean up any EOL characters, they mustn't interfere, remove sections of + // multiple spaces (make them into one), and find quoted areas + for(unsigned int pos = 0; pos < remainingText.size(); pos++) { + // remove \r and \n from string + if(remainingText[pos] == '\n' || remainingText[pos] == '\r') { + if(pos != remainingText.length() - 1) { + remainingText = remainingText.substr(0, pos) + + remainingText.substr(pos + 1); + } + else { + remainingText = remainingText.substr(0, pos); + } + } + + // convert " " to " " if not quoted + if(quoteStart == -1) { + while(pos > 0 && + remainingText[pos-1] == ' ' && + remainingText[pos] == ' ') { + remainingText = remainingText.substr(0, pos) + + remainingText.substr(pos + 1); + } + } + + // Find quotes + for(unsigned int i = 0; + (quoteStart < 0) && i < quoteStartEnds.size(); + i++) { + if(quoteStartEnds[i].first == remainingText[pos]) { + endQuoteChar = quoteStartEnds[i].second; + quoteStart = pos; + } + } + + + //bool mismatchQuote = false; + + // Check to see if we're ending a quote if we didn't just + // start the quote and we are inside a quote + if(quoteStart != (int)pos && quoteStart != -1) { + for(unsigned int i = 0; i < quoteStartEnds.size(); i++) { + if(quoteStartEnds[i].second == remainingText[pos]) { + if(quoteStartEnds[i].first != remainingText[quoteStart]) { + continue; + // mismatchQuote = true; + } + + quotedAreas.push_back(pair(quoteStart, pos)); + + quoteStart = -1; + endQuoteChar = '\0'; + } + } + } + + //if(mismatchQuote) { + // iString msg = "Pvl keyword values [" + textToWrite + + // "] can not have embedded quotes"; + // throw iException::Message(iException::Programmer, msg, _FILEINFO_); + //} + } + + int charsLeft = spaceForText; + int printedSoFar = 0; + + // while we have something to write, keep going + while(!remainingText.empty()) { + // search backwards for the last space or comma *in the limit* (80 chars) + int lastSpacePosition = charsLeft; + + // if everything fits into our remaining space, consider the last + // spot in the string to be printed still the split position. + if(lastSpacePosition >= (int)remainingText.length()) { + lastSpacePosition = remainingText.length(); + } + else { + // Everything does not fit; use good space for mediocre splits (inside + // quoted strings), and excellent space for good splits (between array + // values for example) + int goodSpace = -1; + int excellentSpace = -1; + int searchPosition = lastSpacePosition; + bool doneSearching = false; + + while(!doneSearching) { + bool currentPosQuoted = false; + + for(unsigned int i = 0; i < quotedAreas.size(); i++) { + if(searchPosition + printedSoFar >= quotedAreas[i].first && + searchPosition + printedSoFar <= quotedAreas[i].second) { + currentPosQuoted = true; + } + } + + if(remainingText[searchPosition] == ' ') { + bool validSpace = true; + + // this really isn't a good space if the previous character is a + // '-' though - then it would be read wrong when re-imported. + if(searchPosition > 0 && remainingText[searchPosition - 1] == '-') { + validSpace = false; + } + + if(validSpace && goodSpace < 0) { + goodSpace = searchPosition; + } + + // An excellent space is the prefential break - not quoted and + // not units next. + // we were already done if we had an excellent space + if(validSpace && !currentPosQuoted) { + if((unsigned)searchPosition < remainingText.size() - 1 && + remainingText[searchPosition+1] != '<') { + excellentSpace = searchPosition; + } + } + } + + doneSearching = (excellentSpace >= 0 || searchPosition <= 1); + searchPosition --; + } + + // Use the best breaking point we have + if(excellentSpace > 0) { + lastSpacePosition = excellentSpace; + } + else if(goodSpace > 0) { + lastSpacePosition = goodSpace; + } + else { + lastSpacePosition = -1; + } + } + + // we found a space or comma in our limit, write to that chatacter + // and repeat the loop + if(lastSpacePosition >= 0) { + os << remainingText.substr(0, lastSpacePosition); + + remainingText = remainingText.substr(lastSpacePosition); + printedSoFar += lastSpacePosition; + } + // we failed to find a space or a comma in our limit, + // use a hyphen (-) + else { + os << remainingText.substr(0, charsLeft - 1); + os << "-"; + remainingText = remainingText.substr(charsLeft - 1); + printedSoFar += charsLeft - 1; + } + + // we wrote as much as possible, do a newline and repeat + if(!remainingText.empty()) { + os << format.FormatEOL(); + WriteSpaces(os, startColumn); + + // dont allow spaces to begin the next line inside what we're printing + if(remainingText[0] == ' ') { + remainingText = remainingText.substr(1); + printedSoFar += 1; + } + } + + charsLeft = spaceForText; + } + + return os; + } + + + /** + * This writes numSpaces spaces to the ostream. + * + * @param os Stream to write to + * @param numSpaces number of spaces to write + */ + void PvlKeyword::WriteSpaces(std::ostream &os, int numSpaces) const { + for(int space = 0; space < numSpaces; space ++) { + os << " "; + } + } + + + /** + * + * Set the PvlFormatter used to format the keyword name and value(s) + * + * @param formatter A pointer to the formatter to be used + */ + void PvlKeyword::SetFormat(PvlFormat *formatter) { + p_formatter = formatter; + } + + + /** + * + * Get the current PvlFormat or create one + * @return PvlFormat* Pointer to PvlFormat. + * + */ + PvlFormat *PvlKeyword::GetFormat() { + return p_formatter; + }; + + /** + * Read in a keyword + * + * http://pds.jpl.nasa.gov/tools/standards-reference.shtml + * + * @param is The input stream + * @param result The keyword to read into (OUTPUT) + * + */ + std::istream &operator>>(std::istream &is, PvlKeyword &result) { + result = PvlKeyword(); + string line; + iString keywordString; + + bool keywordDone = false; + bool multiLineComment = false; + bool error = !is.good(); + + while(!error && !keywordDone) { + istream::pos_type beforeLine = is.tellg(); + + line = PvlKeyword::ReadLine(is, multiLineComment); + + // We read an empty line (failed to read next non-empty line) + // and didnt complete our keyword, essentially we hit the implicit + // keyword named "End" + if(line.empty() && !is.good()) { + if(keywordString.empty() || + keywordString[keywordString.size()-1] == '\n') { + line = "End"; + + if(multiLineComment) { + error = true; + } + } + else { + error = true; + } + } + + bool comment = false; + + if(!multiLineComment) { + if(line.size() > 0 && line[0] == '#') { + comment = true; + } + + if(line.size() > 1 && line[0] == '/' && + (line[1] == '*' || line[1] == '/')) { + comment = true; + + if(line[1] == '*') { + multiLineComment = true; + keywordString += line.substr(0, 2); + line = iString(line.substr(2)).Trim(" \r\n\t"); + } + } + } + + if(multiLineComment) { + comment = true; + + if(line.find("/*") != string::npos) { + iString msg = "Cannot have ['/*'] inside a multi-line comment"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + if(line.find("*/") != string::npos) { + multiLineComment = false; + + line = iString( + line.substr(0, line.find("*/")) + ).Trim(" \r\n\t") + " */"; + } + } + + if(line.empty()) { + continue; + } + // comment line + else if(comment) { + keywordString += line + '\n'; + continue; + } + // first line of keyword data + else if(keywordString.empty()) { + keywordString = line; + } + // concatenation + else if(!comment && keywordString[keywordString.size()-1] == '-') { + keywordString = keywordString.substr(0, keywordString.size() - 1) + line; + } + // Non-commented and non-concatenation -> put in the space + else { + keywordString += " " + line; + } + // if this line concatenates with the next, read the next + if(line[line.size()-1] == '-') { + continue; + } + + std::vector< std::string > keywordComments; + std::string keywordName; + std::vector< std::pair > keywordValues; + + bool attemptedRead = false; + + try { + attemptedRead = PvlKeyword::ReadCleanKeyword(keywordString, + keywordComments, + keywordName, + keywordValues); + } + catch(iException &e) { + if(is.eof() && !is.bad()) { + is.clear(); + is.unget(); + } + + is.seekg(beforeLine, ios::beg); + + string msg = "Unable to read keyword ["; + msg += keywordString; + msg += "]"; + + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + // Result valid? + if(attemptedRead) { + // if the next line starts with '<' then it should be read too... + // it should be units + // however, you can't have units if there is no value + if(is.good() && is.peek() == '<' && !keywordValues.empty()) { + continue; + } + + result.SetName(keywordName); + result.AddComments(keywordComments); + + for(unsigned int value = 0; value < keywordValues.size(); value++) { + result.AddValue(keywordValues[value].first, + keywordValues[value].second); + } + + keywordDone = true; + } + + if(!attemptedRead) { + error = error || !is.good(); + } + // else we need to keep reading + } + + if(error) { + // skip comments + while(keywordString.find('\n') != string::npos) { + keywordString = keywordString.substr(keywordString.find('\n') + 1); + } + + string msg; + + if(keywordString.empty() && !multiLineComment) { + msg = "Input contains no Pvl Keywords"; + } + else if(multiLineComment) { + msg = "Input ends while still in a multi-line comment"; + } + else { + msg = "The keyword [" + keywordString + "] does not appear to be"; + msg += " a valid Pvl Keyword"; + } + + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + if(!keywordDone) { + // skip comments + while(keywordString.find('\n') != string::npos) + keywordString = keywordString.substr(keywordString.find('\n') + 1); + + string msg; + + if(keywordString.empty()) { + msg = "Error reading keyword"; + } + else { + msg = "The keyword [" + keywordString + "] does not appear to be"; + msg += " complete"; + } + + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + return is; + } + + /** + * This method adds multiple comments at once by calling AddComments on each + * element in the vector. + * + * @param comments Comments to associate with this keyword + */ + void PvlKeyword::AddComments(const std::vector &comments) { + for(unsigned int i = 0; i < comments.size(); i++) { + AddComment(comments[i]); + } + } + + /** + * This reads a keyword compressed back to 1 line of data (excluding comments, + * which are included on separate lines of data before the keyword). Line + * concatenations must have already been handled. This returns the data of the + * keyword (if valid) and its status. + * + * @param keyword Pvl "#COMMENT\n//COMMENT\nKeyword = (Value1,Value2,...)" + * string + * @param keywordComments Output: Lines of data that are comments + * @param keywordName Output: Name of keyword + * @param keywordValues Output: vector< pair > + * + * @return bool false if it is invalid but could become valid given more data, + * true if it is a valid keyword and successful + */ + bool PvlKeyword::ReadCleanKeyword(std::string keyword, + std::vector< std::string > &keywordComments, + std::string &keywordName, + std::vector< std::pair > &keywordValues) { + // Reset outputs + keywordComments.clear(); + keywordName = ""; + keywordValues.clear(); + + // This is in case a close quote doesn't exist + bool explicitIncomplete = false; + + // Possible (known) comment starts in pvl + iString comments[] = { + "#", + "//" + }; + + // Need more data if nothing is here! + if(keyword.empty()) return 0; + + /* + Step 1: Read Comments + + Theoretically, we should have an input that looks like this: + #Comment + //Comment + / * Comment + Comment * / + Keyword = Data + + So we could just grab all of the first lines; however, this method + needs to be as error-proof as possible (it is the basis of reading + all PVLs after all), so verify we have things that look like comments + first, strip them & store them. + */ + + // While we have newlines, we have comments + while(keyword.find("\n") != string::npos) { + // Make sure we strip data every loop of comment types; otherwise we + // have no comment and need to error out. + bool noneStripped = true; + + // Check every comment type now and make sure this line (it isn't the last + // line since a newline exists) starts in a comment + string keywordStart = keyword.substr(0, 2); + + // Handle multi-line comments + if(keywordStart == "/*") { + noneStripped = false; + bool inComment = true; + + while(inComment && keyword.find("*/") != string::npos) { + // Correct the */ to make sure it has a \n after it, + // without this we risk an infinite loop + size_t closePos = keyword.find("*/\n"); + + if(closePos == string::npos) { + closePos = keyword.find("*/") + 2; + keyword = keyword.substr(0, closePos) + "\n" + + keyword.substr(closePos); + } + + string comment = keyword.substr(0, keyword.find("\n")); + comment = iString(comment).Trim(" \r\n\t"); + + // Set these to true if too small, false if not (they need if + // cant currently fit). + bool needsStart = (comment.size() < 2); + bool needsStartSpace = comment.size() < 3; + + int commentEndPos = comment.size() - 2; + bool needsEnd = (commentEndPos < 0); + bool needsEndSpace = comment.size() < 3; + + // Needs are currently set based on string size, apply real logic + // to test for character sequences (try to convert them from false + // to true). + if(!needsStart) { + needsStart = (comment.substr(0, 2) != "/*"); + } + + if(!needsEnd) { + needsEnd = (comment.substr(commentEndPos, 2) != "*/"); + } + + if(!needsStartSpace) { + needsStartSpace = (comment.substr(0, 3) != "/* "); + } + + if(!needsEndSpace) { + needsEndSpace = (comment.substr(commentEndPos - 1, 3) != " */"); + } + + if(needsStart) { + comment = "/* " + comment; + } + else if(needsStartSpace) { + comment = "/* " + comment.substr(2); + } + + if(needsEnd) { + comment = comment + " */"; + } + else if(needsEndSpace) { + comment = comment.substr(0, comment.size() - 2) + " */";; + } + + inComment = needsEnd; + + keywordComments.push_back(comment); + + if(keyword.find("\n") != string::npos) { + keyword = iString( + keyword.substr(keyword.find("\n") + 1) + ).Trim(" \r\n\t"); + } + + // Check for another comment start + if(!inComment) { + if(keyword.size() >= 2) + keywordStart = keyword.substr(0, 2); + + inComment = (keywordStart == "/*"); + } + } + + // So we have a bunch of multi-line commands... make them the same size + // Find longest + unsigned int longest = 0; + for(unsigned int index = 0; index < keywordComments.size(); index++) { + iString comment = keywordComments[index]; + + if(comment.size() > longest) + longest = comment.size(); + } + + // Now make all the sizes match longest + for(unsigned int index = 0; index < keywordComments.size(); index++) { + iString comment = keywordComments[index]; + + while(comment.size() < longest) { + // This adds a space to the end of the comment + comment = comment.substr(0, comment.size() - 2) + " */"; + } + + keywordComments[index] = comment; + } + // They should all be the same length now + } + + // Search for single line comments + for(unsigned int commentType = 0; + commentType < sizeof(comments) / sizeof(iString); + commentType++) { + + if(keywordStart.find(comments[commentType]) == 0) { + // Found a comment start; strip this line out and store it as a + // comment! + string comment = keyword.substr(0, keyword.find("\n")); + keywordComments.push_back(iString(comment).Trim(" \r\n\t")); + + noneStripped = false; + + if(keyword.find("\n") != string::npos) { + keyword = iString( + keyword.substr(keyword.find("\n") + 1) + ).Trim(" \r\n\t"); + } + } + } + + // Does it look like Name=Value/*comm + // mment*/ ? + if(noneStripped && keyword.find("/*") != string::npos && + keyword.find("*/") != string::npos) { + iString firstPart = keyword.substr(0, keyword.find("\n")); + iString lastPart = keyword.substr(keyword.find("\n") + 1); + + keyword = firstPart.Trim(" \r\n\t") + " " + lastPart.Trim(" \r\n\t"); + noneStripped = false; + } + + if(noneStripped) { + string msg = "Expected a comment but found ["; + msg += keyword; + msg += "]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + } + + // Do we have a keyword at all? + if(keyword.empty()) { + return false; // need more data + } + + /* + Step 2: Determine Keyword Format + + Make sure we have a keyword after the comments first. We expect + one of three formats: + KEYWORD PROCESSED IN STEP 3.1 + KEYWORD = (VALUE,VALUE,...) PROCESSED IN STEP 3.2 + KEYWORD = VALUE PROCESSED IN STEP 3.3 + */ + + // Get the keyword name + keywordName = ReadValue(keyword, explicitIncomplete); + + // we have taken the name; if nothing remains then it is value-less + // and we are done. + if(keyword.empty()) { + /* + Step 3.1 + + Format is determined to be: + KEYWORD + + Well, no value/units may exist so we're done processing this keyword. + */ + return 1; // Valid & Successful + } + + // if we don't have an equal, then we have a problem - an invalid symbol. + // Our possible remaining formats both are KEYWORD = ... + if(keyword[0] != '=') { + string msg = "Expected an assignemnt operator [=], but found ["; + msg += keyword[0]; + msg += "]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + keyword = iString(keyword.substr(1)).Trim(" "); + + if(keyword.empty()) { + return false; + } + + // now we need to split into two possibilities: array or non-array + if(keyword[0] == '(' || keyword[0] == '{') { + /* + Step 3.2 + + Our format is confirmed as: + KEYWORD = (...) + + We need to read each value/unit in the array. + */ + + char closingParen = ((keyword[0] == '(') ? ')' : '}'); + char wrongClosingParen = ((keyword[0] == '(') ? '}' : ')'); + bool closedProperly = false; + + vector< pair > extraDelims; + extraDelims.push_back(pair('(', ')')); + extraDelims.push_back(pair('{', '}')); + + // strip '(' - onetime, this makes every element in the array the same + // (except the last) + keyword = iString(keyword.substr(1)).Trim(" "); + + // handle empty arrays: KEYWORD = () + if(!keyword.empty() && keyword[0] == closingParen) { + closedProperly = true; + } + + // Each iteration of this loop should consume 1 value in the array, + // including the comma, i.e. we should start out with: + // 'VALUE,VALUE,...)' until we hit ')' (our exit condition) + while(!keyword.empty() && keyword[0] != closingParen) { + // foundComma delimits the end of this element in the array (remains + // false for last value which has no comma at the end) + bool foundComma = false; + // keyword should be of the format: VALUE ,....) + // Read VALUE from it + string nextItem = ReadValue(keyword, explicitIncomplete, extraDelims); + + if(!keyword.empty() && keyword[0] == wrongClosingParen) { + + string msg = "Incorrect array close; expected ["; + msg += closingParen; + msg += "] but found ["; + msg += wrongClosingParen; + msg += "] in keyword named ["; + msg += keywordName; + msg += "]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + // This contains + pair keywordValue; + + // Store VALUE + keywordValue.first = nextItem; + + // Now there's 2 possibilities: units or no units -> + // if we have units, read them + if(!keyword.empty() && keyword[0] == '<') { + string unitsValue = ReadValue(keyword, explicitIncomplete); + keywordValue.second = unitsValue; + } + + // Now we should* have a comma, strip it + if(!keyword.empty() && keyword[0] == ',') { + foundComma = true; + keyword = iString(keyword.substr(1)).Trim(" "); + } + + // No comma and nothing more in string - we found + // KEYWORD = (VALUE,VALUE\0 + // we need more information to finish this keyword + if(!foundComma && keyword.empty()) { + return false; // could become valid later + } + + bool foundCloseParen = (!keyword.empty() && keyword[0] == closingParen); + + if(foundCloseParen) { + closedProperly = true; + } + + // Check for the condition of: + // keyword = (VALUE,VALUE,) + // which is unrecoverable + if(foundComma && foundCloseParen) { + string msg = "Unexpected close of keyword-value array"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + // Check for (VALUE VALUE + if(!foundComma && !foundCloseParen) { + // We have ("VALUE VALUE + if(explicitIncomplete) return false; + + // We have (VALUE VALUE + string msg = "Found extra data after ["; + msg += nextItem; + msg += "] in array"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + // we're good with this element of the array, remember it + keywordValues.push_back(keywordValue); + } + + if(!closedProperly) { + return false; + } + + // Trim off the closing paren + if(!keyword.empty()) { + keyword = iString(keyword.substr(1)).Trim(" "); + } + + // Read units here if they exist and apply them + // case: (A,B,C) + if(!keyword.empty() && keyword[0] == '<') { + string units = ReadValue(keyword, explicitIncomplete); + for(unsigned int val = 0; val < keywordValues.size(); val++) { + if(keywordValues[val].second.empty()) { + keywordValues[val].second = units; + } + } + } + } + else { + /* + Step 3.3 + + Our format is confirmed as: + "KEYWORD = VALUE " + + We need to read the single value/unit in the keywordValues array. + */ + pair keywordValue; + keywordValue.first = ReadValue(keyword, explicitIncomplete); + + if(!keyword.empty() && keyword[0] == '<') { + keywordValue.second = ReadValue(keyword, explicitIncomplete); + } + + keywordValues.push_back(keywordValue); + } + + /* + This is set when a quote is opened somewhere and never closed, it means + we need more information + */ + if(explicitIncomplete) { + return false; // unclosed quote at end... need more information + } + + /* + See if we have a comment at the end of the keyword... + */ + if(!keyword.empty()) { + // if the data left is a comment, we can handle it probably + if(keyword[0] == '#' || + ((keyword.size() > 1 && keyword[0] == '/') && + (keyword[1] == '/' || keyword[1] == '*'))) { + keywordComments.push_back(keyword); + + if(keyword.size() > 1 && keyword.substr(0, 2) == "/*") { + if(keyword.substr(keyword.size() - 2, 2) != "*/") + return false; // need more comment data + } + + keyword = ""; + } + } + + /* + If more data remains, it is unrecognized. + */ + if(!keyword.empty()) { + string msg = "Keyword has extraneous data ["; + msg += keyword; + msg += "] at the end"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + // We've parsed this keyword! :) + return true; + } + + + std::string PvlKeyword::ReadValue(std::string &keyword, bool "eProblem) { + std::vector< std::pair > otherDelims; + + return ReadValue(keyword, quoteProblem, otherDelims); + } + + /** + * This method looks for a data element in the string. A data element is a + * quoted string, a units value, or one value of an array (not including + * units). As an example, each value in the following string is quoted: + * + * 'VALUE' '=' ('VALUE','VALUE', 'VALUE' '') + * + * The returned values of each of these elements is VALUE. Explicitly defined + * quotes (', ", <>) are stripped from the return value. + * + * @param keyword Input/Output: The keyword to get the next value from + * (DESTRUCTIVE) + * @param quoteProblem Output: The string has an unclosed quote character + * + * @return std::string The stripped out token. + */ + std::string PvlKeyword::ReadValue(std::string &keyword, bool "eProblem, + const std::vector< std::pair > & + otherDelimiters) { + string value = ""; + + // This method ignores spaces except as delimiters; let's trim the string + // to start + keyword = iString(keyword).Trim(" "); + + if(keyword.empty()) { + return ""; + } + + // An implied quote is one that is started without a special character, for + // example HELLO WORLD has HELLO and WORLD separately as implied quotes for + // PVLs. However, "HELLO WORLD" has an explicit (not implied) double quote. + // We do consider <> as quotes. + bool impliedQuote = true; + char quoteEnd = ' '; + bool keepQuotes = false; + size_t currentDelimPos = string::npos; + + if(keyword[0] == '\'' || keyword[0] == '"') { + quoteEnd = keyword[0]; + impliedQuote = false; + currentDelimPos = 0; + } + else if(keyword[0] == '<') { + quoteEnd = '>'; + impliedQuote = false; + currentDelimPos = 0; + } + else { + // we're not quoted, look for alternative delimiters. + char implicitQuotes[] = { + ')', + '}', + ',', + ' ', + '<', + '=' + }; + + bool foundImplicitQuote = false; + + unsigned int currentPos = 0; + while(!foundImplicitQuote && currentPos != keyword.size()) { + for(unsigned int quote = 0; + quote < sizeof(implicitQuotes) / sizeof(char); + quote ++) { + if(keyword[currentPos] == implicitQuotes[quote]) { + currentDelimPos = currentPos; + quoteEnd = implicitQuotes[quote]; + foundImplicitQuote = true; + } + } + + if(!foundImplicitQuote) { + currentPos ++; + } + } + } + + for(unsigned int delim = 0; delim < otherDelimiters.size(); delim ++) { + if(keyword[0] == otherDelimiters[delim].first) { + currentDelimPos = 0; + quoteEnd = otherDelimiters[delim].second; + keepQuotes = true; + impliedQuote = false; + } + } + + string startQuote; + // non-implied delimeters need the opening delimiter ignored. Remember + // startQuote in case of error later on we can reconstruct the original + // string. + if(!impliedQuote) { + startQuote += keyword[0]; + keyword = keyword.substr(1); + } + + // Do we have a known quote end? + size_t quoteEndPos = keyword.find(quoteEnd); + if(quoteEndPos != string::npos) { + value = keyword.substr(0, quoteEndPos); + + // Trim keyword 1 past end delimiter (if end delimiter is last, this + // results in empty string). If the close delimiter is ')' or ',' then + // leave it be however, since we need to preserve that to denote this was + // an end of a valuein array keyword. + if(!impliedQuote) { + keyword = keyword.substr(quoteEndPos + 1); + } + else { + keyword = keyword.substr(quoteEndPos); + } + + // Make sure we dont have padding + keyword = iString(keyword).Trim(" "); + + if(keepQuotes) { + value = startQuote + value + quoteEnd; + } + + return value; + } + // implied quotes terminate at end of keyword; otherwise we have a problem + // (which is this condition) + else if(!impliedQuote) { + // restore the original string + keyword = startQuote + keyword; + quoteProblem = true; + + return ""; + } + + // we have an implied quote but no quote character, the rest must be the + // value. + value = keyword; + keyword = ""; + + return value; + } + + + /** + * This method reads one line of data from the input stream. + * + * All spaces, newlines, returns and tabs are trimmed from the result. + * Once a newline is encountered, if the line we read is blank, we keep + * reading. Once a line with data is encountered, that is the result. All + * newlines, spaces, returns and tabs are consumed past this line of data + * until the next different character (seeks to next valid data). + * + * @param is The stream to read from + * + * @return std::string The first encountered line of data + */ + std::string PvlKeyword::ReadLine(std::istream &is, bool insideComment) { + iString lineOfData; + + while(is.good() && lineOfData.empty()) { + + // read until \n (works for both \r\n and \n) or */ + while(is.good() && + (!lineOfData.size() || lineOfData[lineOfData.size() - 1] != '\n')) { + char next = is.get(); + + // if non-ascii found then we're done... immediately + if(next <= 0) { + is.seekg(0, ios::end); + is.get(); + return lineOfData; + } + + // if any errors (i.e. eof) happen in the get operation then don't + // store this data + if(is.good()) { + lineOfData += next; + } + + if(insideComment && + lineOfData.size() >= 2 && lineOfData[lineOfData.size() - 2] == '*' && + lineOfData[lineOfData.size() - 1] == '/') { + // End of multi-line comment = end of line! + break; + } + else if(lineOfData.size() >= 2 && + lineOfData[lineOfData.size() - 2] == '/' && + lineOfData[lineOfData.size() - 1] == '*') { + insideComment = true; + } + } + + // Trim off non-visible characters from this line of data + lineOfData = lineOfData.Trim(" \r\n\t"); + + // read up to next non-whitespace in input stream + while(is.good() && + (is.peek() == ' ' || + is.peek() == '\r' || + is.peek() == '\n')) { + is.get(); + } + + // if lineOfData is empty (line was empty), we repeat + } + + return lineOfData; + } + + + /** + * Write out the keyword. + * + * @param os The output stream. + * @param keyword The PvlKeyword object to output. + * @return ostream& Reference to ostream. + * @see WriteWithWrap() + */ + ostream &operator<<(std::ostream &os, const Isis::PvlKeyword &keyword) { + // Set up a Formatter + PvlFormat *tempFormat = keyword.p_formatter; + bool removeFormatter = false; + if(tempFormat == NULL) { + tempFormat = new PvlFormat(); + removeFormatter = true; + } + + // Write out the comments + for(int i = 0; i < keyword.Comments(); i++) { + for(int j = 0; j < keyword.Indent(); j++) os << " "; + os << keyword.Comment(i) << tempFormat->FormatEOL(); + } + + // Write the keyword name & add length to startColumn. + int startColumn = 0; + for(int i = 0; i < keyword.Indent(); i++) { + os << " "; + ++startColumn; + } + string keyname = tempFormat->FormatName(keyword); + os << keyname; + startColumn += keyname.length(); + + // Add padding and then write equal sign. + for(int i = 0; i < keyword.Width() - (int)keyname.size(); ++i) { + os << " "; + ++startColumn; + } + os << " = "; + startColumn += 3; + + // If it has no value then write a NULL + if(keyword.Size() == 0) { + os << tempFormat->FormatValue(keyword); + } + + // Loop and write each array value + string stringToWrite; + for(int i = 0; i < keyword.Size(); i ++) { + stringToWrite += tempFormat->FormatValue(keyword, i); + } + + keyword.WriteWithWrap(os, + stringToWrite, + startColumn, + *tempFormat); + + if(removeFormatter) delete tempFormat; + + return os; + } + + + //! This is an assignment operator + const PvlKeyword &PvlKeyword::operator=(const PvlKeyword &other) { + p_formatter = other.p_formatter; + p_name = other.p_name; + p_values = other.p_values; + p_units = other.p_units; + p_comments = other.p_comments; + p_width = other.p_width; + p_indent = other.p_indent; + + return *this; + } + +} diff --git a/isis/src/base/objs/PvlKeyword/PvlKeyword.h b/isis/src/base/objs/PvlKeyword/PvlKeyword.h new file mode 100644 index 0000000000000000000000000000000000000000..ce7f9b3630c9f35995d65ed5d18b625c70bc4e26 --- /dev/null +++ b/isis/src/base/objs/PvlKeyword/PvlKeyword.h @@ -0,0 +1,280 @@ +#ifndef PvlKeyword_h +#define PvlKeyword_h +/** + * @file + * $Revision: 1.16 $ + * $Date: 2010/06/25 20:42:35 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "iString.h" +#include "Constants.h" + +namespace Isis { + /** + * @brief A single keyword-value pair. + * + * This class is used to create a single PVL keyword-value pair. PvlContainer + * can combine PvlKeyword objects and organize them so they look clean on + * output. + * + * @ingroup Parsing + * + * @author 2002-10-11 Jeff Anderson + * + * @internal + * @history 2005-04-08 Leah Dahmer - wrote class documentation. + * @history 2005-04-08 Leah Dahmer - added the WriteWithWrap() method so + * keyword values will now be wrapped when + * the length exceeds 80 characters. + * @history 2005-05-18 Jeff Anderson - Fixed minor problems with wrapping code + * @history 2006-04-05 Elizabeth Miller - Added + * AddCommentWrapped method + * @history 2006-09-05 Stuart Sides - Added ability to format keywords in + * different ways using the PvlFormat class + * @history 2007-08-20 Brendan George - Added checking to ensure Keyword Name + * contains no whitespace + * @history 2008-02-08 Christopher Austin - Altered + * WriteWithWrap to not bomb when 2 or more single + * statement lines in a row are over 78 characters + * long. + * @history 2008-07-03 Steven Lambright - Added const functionality + * @history 2008-07-10 Steven Lambright - StringEqual is now static, all + * AddComments methods are public + * @history 2008-09-30 Christopher Austin - replaced all std::endl in the << + * operator as well as WriteWithWrap() with PvlFormat.FormatEOL(), and + * formatted wraps accordingly + * @history 2009-08-18 Eric Hyer - Added both SetUnits methods and ASSERT macro + * @history 2009-09-09 Steven Lambright - Removed ASSERT macro, fixed + * formatting of error in SetUnits, and fixed text wrapping when a + * single array element needed split up into multiple lines. + * @history 2009-12-07 Steven Lambright - Added stream input operator for + * reading + * @history 2010-01-19 Travis Addair - Added SetCharLimit + * method allowing users to set the point at which a + * keyword value is output to the next line down. + * @history 2010-02-04 Travis Addair - Moved the SetCharLimit + * method to PvlFormat class + * @history 2010-04-13 Eric Hyer - Added copy constructor + * Added assignment operator + * @history 2010-06-25 Steven Lambright - NULLs ('\0') now count as binary + */ + class PvlSequence; + class PvlFormat; + + class PvlKeyword { + public: + PvlKeyword(); + PvlKeyword(const std::string &name); + PvlKeyword(const std::string &name, const Isis::iString value, + const std::string unit = ""); + PvlKeyword(const PvlKeyword &other); + ~PvlKeyword(); + + void SetName(const std::string &name); + + /** + * Returns the keyword name. + * + * @return The name of the keyword. + */ + std::string Name() const { + return p_name; + }; + /** + * Determines whether two PvlKeywords have the same name or not. + * + * @param name The name of the keyword to compare with this one. + * @return True if the names are equal, false if not. + */ + bool IsNamed(const std::string &name) const { + return StringEqual(name, Name()); + }; + + void SetValue(const Isis::iString value, const std::string unit = ""); + + void SetUnits(const iString &units); + void SetUnits(const iString &value, const iString &units); + + PvlKeyword &operator=(const Isis::iString value); + + void AddValue(const Isis::iString value, const std::string unit = ""); + PvlKeyword &operator+=(const Isis::iString value); + + //! Returns the number of values stored in this keyword + int Size() const { + return p_values.size(); + }; + bool IsNull(const int index = 0) const; + void Clear(); + + friend std::istream &operator>>(std::istream &is, PvlKeyword &result); + friend std::ostream &operator<<(std::ostream &os, + const PvlKeyword &keyword); + + //! Returns the first value in this keyword converted to a double + operator double() const { + return (double) operator[](0); + }; + //! Returns the first value in this keyword converted to an integer + operator int() const { + return (int) operator[](0); + }; + //! Returns the first value in this keyword converted to a BigInt + operator Isis::BigInt() const { + return (Isis::BigInt) operator[](0); + }; + //! Returns the first value in this keyword converted to a std::string + operator std::string() const { + return (std::string) operator[](0); + }; + + const Isis::iString &operator[](const int index) const; + Isis::iString &operator[](const int index); + std::string Unit(const int index = 0) const; + + void AddComment(const std::string &comment); + void AddCommentWrapped(const std::string &comment); + + void AddComments(const std::vector &comments); + + //! Returns the number of lines of comments associated with this keyword + int Comments() const { + return p_comments.size(); + }; + std::string Comment(const int index) const; + void ClearComments(); + + /** + * Returns true of the keyword names match + * + * @param key The keyword to compare names with + */ + bool operator==(const PvlKeyword &key) const { + return (StringEqual(p_name, key.p_name)); + }; + + /** + * Returns true of the keyword names do not match + * + * @param key The keyword to compare names with + */ + bool operator!=(const PvlKeyword &key) const { + return (!StringEqual(p_name, key.p_name)); + }; + + bool IsEquivalent(const std::string &string1, int index = 0) const; + + /** + * The width of the longest keyword name (for formatting) + * + * @param width the new width + */ + void SetWidth(int width) { + p_width = width; + }; + + /** + * Sets the indent level when outputted(for formatting) + * + * @param indent The new indent + */ + void SetIndent(int indent) { + p_indent = indent; + }; + + //! Returns the current set longest keyword name + int Width() const { + return p_width; + }; + + //! Returns the current indent level + int Indent() const { + return p_indent; + }; + + PvlKeyword &operator=(Isis::PvlSequence &seq); + + void SetFormat(PvlFormat *formatter); + PvlFormat *GetFormat(); + + static bool StringEqual(const std::string &string1, + const std::string &string2); + + + static std::string ReadLine(std::istream &is, bool insideComment); + + static bool ReadCleanKeyword(std::string keyword, + std::vector< std::string > &keywordComments, + std::string &keywordName, + std::vector< std::pair > + &keywordValues); + + static std::string ReadValue(std::string &keyword, bool "eProblem); + static std::string ReadValue(std::string &keyword, bool "eProblem, + const std::vector< std::pair > & + otherDelimiters); + + const PvlKeyword &operator=(const PvlKeyword &other); + + protected: + std::string Reform(const std::string &value) const; + std::string ToPvl(const std::string &value) const; + std::string ToIPvl(const std::string &value) const; + std::ostream &WriteWithWrap(std::ostream &os, + const std::string &textToWrite, + int startColumn, + PvlFormat &format) const; + + //! Formatter object + PvlFormat *p_formatter; + + private: + + + //! The keyword name + std::string p_name; + //! A vector of values for the keyword. + std::vector p_values; + //! The units for the values. + std::vector p_units; + //! The comments for the keyword. + std::vector p_comments; + + void Init(); + + void WriteSpaces(std::ostream &, int) const; + + /** + * The width of the longest keyword. This is used for spacing out the + * equals signs on output. + */ + int p_width; + /** + * The number of indentations to make. This is based on whether the + * keyword is in a group, etc. + */ + int p_indent; + }; +}; + +#endif + diff --git a/isis/src/base/objs/PvlKeyword/PvlKeyword.truth b/isis/src/base/objs/PvlKeyword/PvlKeyword.truth new file mode 100644 index 0000000000000000000000000000000000000000..42d67c512104112ce7c81a5368ef2e2eaf7f1bf6 --- /dev/null +++ b/isis/src/base/objs/PvlKeyword/PvlKeyword.truth @@ -0,0 +1,541 @@ + + +----- Testing Basic Read/Write ----- +'KEYWORD' -----------------------> VALID + NAME: KEYWORD +'KEYWORD X' ---------------------> INVALID + **PVL ERROR** Expected an assignemnt operator [=], but found [X] +'KEYWORD =' ---------------------> INCOMPLETE +'KEYWORD = SOME_VAL' ------------> VALID + NAME: KEYWORD + VALUE: SOME_VAL +'KEYWORD = " val "' -----------> VALID + NAME: KEYWORD + VALUE: val +'KEYWORD = " 'val' "' -----------> VALID + NAME: KEYWORD + VALUE: 'val' +'KEYWORD = (VAL' ----------------> INCOMPLETE +'KEYWORD = (VAL1,VAL2' ----------> INCOMPLETE +'KEYWORD = (A B,C,D)' -----------> INVALID + **PVL ERROR** Found extra data after [A] in array +'KEYWORD = ((A B),(C),(D' -------> INCOMPLETE +'KEYWORD = (SOME_VAL)' ----------> VALID + NAME: KEYWORD + VALUE: SOME_VAL +'KEYWORD = (SOME_VAL) ' ------> VALID + NAME: KEYWORD + VALUE: SOME_VAL +'KEYWORD=(SOME_VAL)' ---------> VALID + NAME: KEYWORD + VALUE: SOME_VAL +'KEYWORD = (A, )' ---------------> INVALID + **PVL ERROR** Unexpected close of keyword-value array +'KEYWORD = ()' ------------------> VALID + NAME: KEYWORD +'KEYWORD = (A,B)' ---------------> VALID + NAME: KEYWORD + VALUE: A + VALUE: B +'KEYWORD = {A, B}' --------------> VALID + NAME: KEYWORD + VALUE: A + VALUE: B +'KEYWORD = (A,B) #comment this' -> VALID + COMMENT: #comment this + NAME: KEYWORD + VALUE: A + VALUE: B +'KEYWORD = ( A , B )' -----------> VALID + NAME: KEYWORD + VALUE: A + VALUE: B +'KEYWORD = (A, B,C,D,E))' -------> INVALID + **PVL ERROR** Keyword has extraneous data [)] at the end +'KEYWORD = ((1, 2), {3, 4}, (5), 6)' > VALID + NAME: KEYWORD + VALUE: (1, 2) + VALUE: {3, 4} + VALUE: (5) + VALUE: 6 +'KEYWORD = { "VAL1" , "VAL2", "VAL3"}' > VALID + NAME: KEYWORD + VALUE: VAL1 + VALUE: VAL2 + VALUE: VAL3 +'KEYWORD = { "VAL1" , "VAL2", "VAL3")' > INVALID + **PVL ERROR** Incorrect array close; expected [}] but found [)] in keyword named [KEYWORD] +'KEYWORD = { "VAL1" ,' ----------> INCOMPLETE +'KEYWORD = "(A,B,"' -------------> VALID + NAME: KEYWORD + VALUE: (A,B, +'KEYWORD = ',E)'' ---------------> VALID + NAME: KEYWORD + VALUE: ,E) +'KEYWORD = (A , B , C, D )' > VALID + NAME: KEYWORD + VALUE: A + VALUE: B + VALUE: C + VALUE: D +'KEYWORD = (A , B , C, D ) ' > VALID + NAME: KEYWORD + VALUE: A + VALUE: B + VALUE: C + VALUE: D +'KEYWORD = ',E) ' ---------> INCOMPLETE +'KEYWORD = ,E) ' ----------> INVALID + **PVL ERROR** Keyword has extraneous data [,E) ] at the end +#SOMECOMMENT +'KEYWORD = SOME_VAL' ------------> VALID + COMMENT: #SOMECOMMENT + NAME: KEYWORD + VALUE: SOME_VAL +#SOMECOMMENT1 +#SOMECOMMENT2 +'KEYWORD = SOME_VAL' ------------> VALID + COMMENT: #SOMECOMMENT1 + COMMENT: #SOMECOMMENT2 + NAME: KEYWORD + VALUE: SOME_VAL +//SOMECOMMENT1 +#SOMECOMMENT2 +'KEYWORD = SOME_VAL' ------------> VALID + COMMENT: //SOMECOMMENT1 + COMMENT: #SOMECOMMENT2 + NAME: KEYWORD + VALUE: SOME_VAL +/*SOMECOMMENT1*/ +'KEYWORD = SOME_VAL' ------------> VALID + COMMENT: /* SOMECOMMENT1 */ + NAME: KEYWORD + VALUE: SOME_VAL +KEYWORD = '/* +'*/'' ---------------------------> VALID + NAME: KEYWORD + VALUE: /* */ +/* SOMECOMMENT1 + SOMECOMMENT2 +SOMECOMMENT3 */ +'KEYWORD = SOME_VAL' ------------> VALID + COMMENT: /* SOMECOMMENT1 */ + COMMENT: /* SOMECOMMENT2 */ + COMMENT: /* SOMECOMMENT3 */ + NAME: KEYWORD + VALUE: SOME_VAL +/*C1 + +A +/* +C3*/ +'KEYWORD = SOME_VAL' ------------> VALID + COMMENT: /* C1 */ + COMMENT: /* A */ + COMMENT: /* */ + COMMENT: /* C3 */ + NAME: KEYWORD + VALUE: SOME_VAL +/*C1 +/**/ +'KEYWORD = SOME_VAL' ------------> VALID + COMMENT: /* C1 */ + COMMENT: /* */ + NAME: KEYWORD + VALUE: SOME_VAL +/*C1 +A/**/ +'KEYWORD = SOME_VAL' ------------> VALID + COMMENT: /* C1 */ + COMMENT: /* A/* */ + NAME: KEYWORD + VALUE: SOME_VAL +/* A */ +/* B *//*C*/ +'KEYWORD = SOME_VAL' ------------> VALID + COMMENT: /* A */ + COMMENT: /* B *//*C */ + NAME: KEYWORD + VALUE: SOME_VAL +/*C1/**/ +'KEYWORD = SOME_VAL' ------------> VALID + COMMENT: /* C1/* */ + NAME: KEYWORD + VALUE: SOME_VAL +/*C1 + +A + +C3*//*Neato*//*Man*/KEYWORD = (A,B,C) /*Right? +'Yes!*/' ------------------------> VALID + COMMENT: /* C1 */ + COMMENT: /* A */ + COMMENT: /* C3 */ + COMMENT: /* Neato */ + COMMENT: /* Man */ + COMMENT: /*Right? Yes!*/ + NAME: KEYWORD + VALUE: A + VALUE: B + VALUE: C + + +----- Testing Stream Read/Write ----- +Input: +KEYWORD + +Output: +KEYWORD = Null + +Input: +KEYWORD X + +Output: +**PVL ERROR** Unable to read keyword [KEYWORD X] +**PVL ERROR** Expected an assignemnt operator [=], but found [X] + +Input: +KEYWORD = + +Output: +**PVL ERROR** The keyword [KEYWORD =] does not appear to be a valid Pvl Keyword + +Input: +KEYWORD = SOME_VAL + +Output: +KEYWORD = SOME_VAL + +Input: +KEYWORD = " val " + +Output: +KEYWORD = " val " + +Input: +KEYWORD = " 'val' " + +Output: +KEYWORD = " 'val' " + +Input: +KEYWORD = (VAL + +Output: +**PVL ERROR** The keyword [KEYWORD = (VAL] does not appear to be a valid Pvl Keyword + +Input: +KEYWORD = (VAL1,VAL2 + +Output: +**PVL ERROR** The keyword [KEYWORD = (VAL1,VAL2] does not appear to be a valid Pvl Keyword + +Input: +KEYWORD = (A B,C,D) + +Output: +**PVL ERROR** Unable to read keyword [KEYWORD = (A B,C,D)] +**PVL ERROR** Found extra data after [A] in array + +Input: +KEYWORD = ((A B),(C),(D + +Output: +**PVL ERROR** The keyword [KEYWORD = ((A B),(C),(D] does not appear to be a valid Pvl Keyword + +Input: +KEYWORD = (SOME_VAL) + +Output: +KEYWORD = SOME_VAL + +Input: +KEYWORD = (SOME_VAL) + +Output: +KEYWORD = SOME_VAL + +Input: +KEYWORD=(SOME_VAL) + +Output: +KEYWORD = SOME_VAL + +Input: +KEYWORD = (A, ) + +Output: +**PVL ERROR** Unable to read keyword [KEYWORD = (A, )] +**PVL ERROR** Unexpected close of keyword-value array + +Input: +KEYWORD = () + +Output: +KEYWORD = Null + +Input: +KEYWORD = (A,B) + +Output: +KEYWORD = (A, B) + +Input: +KEYWORD = {A, B} + +Output: +KEYWORD = (A, B) + +Input: +KEYWORD = (A,B) #comment this + +Output: +#comment this +KEYWORD = (A, B) + +Input: +KEYWORD = ( A , B ) + +Output: +KEYWORD = (A, B) + +Input: +KEYWORD = (A, B,C,D,E)) + +Output: +**PVL ERROR** Unable to read keyword [KEYWORD = (A, B,C,D,E))] +**PVL ERROR** Keyword has extraneous data [)] at the end + +Input: +KEYWORD = ((1, 2), {3, 4}, (5), 6) + +Output: +KEYWORD = ((1, 2), {3, 4}, (5), 6) + +Input: +KEYWORD = { "VAL1" , "VAL2", "VAL3"} + +Output: +KEYWORD = (VAL1, VAL2, VAL3) + +Input: +KEYWORD = { "VAL1" , "VAL2", "VAL3") + +Output: +**PVL ERROR** Unable to read keyword [KEYWORD = { "VAL1" , "VAL2", "VAL3")] +**PVL ERROR** Incorrect array close; expected [}] but found [)] in keyword named [KEYWORD] + +Input: +KEYWORD = { "VAL1" , + +Output: +**PVL ERROR** The keyword [KEYWORD = { "VAL1" ,] does not appear to be a valid Pvl Keyword + +Input: +KEYWORD = "(A,B," + +Output: +KEYWORD = "(A,B," + +Input: +KEYWORD = ',E)' + +Output: +KEYWORD = ",E)" + +Input: +KEYWORD = (A , B , C, D ) + +Output: +KEYWORD = (A , B , C, D ) + +Input: +KEYWORD = (A , B , C, D ) + +Output: +KEYWORD = (A , B , C , D ) + +Input: +KEYWORD = ',E) + +Output: +**PVL ERROR** The keyword [KEYWORD = ',E) ] does not appear to be a valid Pvl Keyword + +Input: +KEYWORD = ,E) + +Output: +**PVL ERROR** Unable to read keyword [KEYWORD = ,E) ] +**PVL ERROR** Keyword has extraneous data [,E) ] at the end + +Input: +#SOMECOMMENT +KEYWORD = SOME_VAL + +Output: +#SOMECOMMENT +KEYWORD = SOME_VAL + +Input: +#SOMECOMMENT1 +#SOMECOMMENT2 +KEYWORD = SOME_VAL + +Output: +#SOMECOMMENT1 +#SOMECOMMENT2 +KEYWORD = SOME_VAL + +Input: +//SOMECOMMENT1 +#SOMECOMMENT2 +KEYWORD = SOME_VAL + +Output: +//SOMECOMMENT1 +#SOMECOMMENT2 +KEYWORD = SOME_VAL + +Input: +/*SOMECOMMENT1*/ +KEYWORD = SOME_VAL + +Output: +/* SOMECOMMENT1 */ +KEYWORD = SOME_VAL + +Input: +KEYWORD = '/* +*/' + +Output: +KEYWORD = "/* */" + +Input: +/* SOMECOMMENT1 + SOMECOMMENT2 +SOMECOMMENT3 */ +KEYWORD = SOME_VAL + +Output: +/* SOMECOMMENT1 */ +/* SOMECOMMENT2 */ +/* SOMECOMMENT3 */ +KEYWORD = SOME_VAL + +Input: +/*C1 + +A +/* +C3*/ +KEYWORD = SOME_VAL + +Output: +**PVL ERROR** Cannot have ['/*'] inside a multi-line comment + +Input: +/*C1 +/**/ +KEYWORD = SOME_VAL + +Output: +**PVL ERROR** Cannot have ['/*'] inside a multi-line comment + +Input: +/*C1 +A/**/ +KEYWORD = SOME_VAL + +Output: +**PVL ERROR** Cannot have ['/*'] inside a multi-line comment + +Input: +/* A */ +/* B *//*C*/ +KEYWORD = SOME_VAL + +Output: +/* A */ +/* B */ +/* C */ +KEYWORD = SOME_VAL + +Input: +/*C1/**/ +KEYWORD = SOME_VAL + +Output: +**PVL ERROR** Cannot have ['/*'] inside a multi-line comment + +Input: +/*C1 + +A + +C3*//*Neato*//*Man*/KEYWORD = (A,B,C) /*Right? +Yes!*/ + +Output: +/* C1 */ +/* A */ +/* C3 */ +/* Neato */ +/* Man */ +/*Right? Yes!*/ +KEYWORD = (A, B, C) + +----- Testing Difficult Cases Read/Write ----- +THE_INTERNET = "Seven thousand eight hundred forty three million seventy four + nine seventy six forty two eighty nine sixty seven thirty five + million jillion bajillion google six nine four one two three + four five six seven eight nine ten eleven twelve thirteen + fourteen" +BIG_HUGE_LONG_NAME_THAT_SHOULD_TEST_OUT_PARSING = "Seven thousand eight + hundred forty three million + seventy four" +ARRAY_TEST = (5.87, 5465.6, 574.6) +FIRST_100_DIGITS_OF_PI = 3.14159265358979323846264338327950288419716939937510- + 58209749445923078164062862089986280348253421170679 +Raw Data --> +3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679 + +A = XXXXXXXXXXxxxxxxxxxxXXXXXXXXXXxxxxxxxxxxXXXXXXXXXXxxxxxxxxxxXXXXXXXXXXxxxx +TREE = (MAPLE, ELM, PINE) +UGHHHHHHHHHHHH = (59999.0, 59999.0, 59999.0, 59999.0, 59999.0, 59999.0, + 59999.0, 59999.0, 59999.0, 59999.0, 59999.0, 59999.0) +NAME = 5.2 +KEY = Null +# Hello World! This is a really really long comment that needs to be +# wrapped onto several different lines to make the PVL file look really +# pretty! +KEY = (5, Null, 3.3 , "Hello World!") + +# Hello World! This is a really really long comment that needs to be +# wrapped onto several different lines to make the PVL file look really +# pretty! +KEY = (5, 88, 3.3 , "Hello World!") +key = ((a, b, c), ("Hubba Hubba", Bubba)) + + +Test SetUnits methods: + + original condition of Keyword k : + k = (radius, circumference) + + after k.SetUnits("circumference", "Fathoms") : + k = (radius , circumference ) + + after k.SetUnits("TeraFathoms") : + k = (radius, circumference) + + +---------------------------------------- +Testing cast operators +string = I'm being casted +int = 465721 +BigInt = 465721 +double = 131.244 +Test_key_2 = "Might work" +**USER ERROR** [Bob is a name] is invalid. Keyword name cannot contain whitespace. +Test_key_3 = "Might'not work" diff --git a/isis/src/base/objs/PvlKeyword/unitTest.cpp b/isis/src/base/objs/PvlKeyword/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..23c7945ae0af2f22f5fe7b6783106e5be7e03f58 --- /dev/null +++ b/isis/src/base/objs/PvlKeyword/unitTest.cpp @@ -0,0 +1,302 @@ +#include "PvlKeyword.h" +#include "iException.h" +#include "PvlSequence.h" +#include "Preference.h" + +#include +#include + +using namespace std; +using namespace Isis; + +int main() { + Isis::Preference::Preferences(true); + + string keywordsToTry[] = { + "KEYWORD", + "KEYWORD X", + "KEYWORD =", + "KEYWORD = SOME_VAL", + "KEYWORD = \" val \"", + "KEYWORD = \" 'val' \"", + "KEYWORD = (VAL", + "KEYWORD = (VAL1,VAL2", + "KEYWORD = (A B,C,D)", + "KEYWORD = ((A B),(C),(D", + "KEYWORD = (SOME_VAL)", + "KEYWORD = (SOME_VAL) ", + "KEYWORD=(SOME_VAL)", + "KEYWORD = (A, )", + "KEYWORD = ()", + "KEYWORD = (A,B)", + "KEYWORD = {A, B}", + "KEYWORD = (A,B) #comment this", + "KEYWORD = ( A , B )", + "KEYWORD = (A, B,C,D,E))", + "KEYWORD = ((1, 2), {3, 4}, (5), 6)", + "KEYWORD = { \"VAL1\" , \"VAL2\", \"VAL3\"}", + "KEYWORD = { \"VAL1\" , \"VAL2\", \"VAL3\")", + "KEYWORD = { \"VAL1\" ,", + "KEYWORD = \"(A,B,\"", + "KEYWORD = ',E)'", + "KEYWORD = (A , B , C, D )", + "KEYWORD = (A , B , C, D ) ", + "KEYWORD = ',E) ", + "KEYWORD = ,E) ", + "#SOMECOMMENT\nKEYWORD = SOME_VAL", + "#SOMECOMMENT1\n#SOMECOMMENT2\nKEYWORD = SOME_VAL", + "//SOMECOMMENT1\n#SOMECOMMENT2\nKEYWORD = SOME_VAL", + "/*SOMECOMMENT1*/\nKEYWORD = SOME_VAL", + "KEYWORD = '/*\n*/'", + "/* SOMECOMMENT1\n SOMECOMMENT2\nSOMECOMMENT3 */\nKEYWORD = SOME_VAL", + "/*C1\n\nA\n/*\nC3*/\nKEYWORD = SOME_VAL", + "/*C1\n/**/\nKEYWORD = SOME_VAL", + "/*C1\nA/**/\nKEYWORD = SOME_VAL", + "/* A */\n/* B *//*C*/\nKEYWORD = SOME_VAL", + "/*C1/**/\nKEYWORD = SOME_VAL", + "/*C1 \n\nA\n\nC3*//*Neato*//*Man*/KEYWORD = (A,B,C) /*Right?\nYes!*/" + }; + + cout << endl << endl; + cout << "----- Testing Basic Read/Write -----" << endl; + PvlKeyword keyword; + for(unsigned int key = 0; + key < sizeof(keywordsToTry) / sizeof(string); + key++) { + string keywordCpy = keywordsToTry[key]; + while(keywordCpy.find("\n") != string::npos) { + cout << keywordCpy.substr(0, keywordCpy.find("\n") + 1); + keywordCpy = keywordCpy.substr(keywordCpy.find("\n") + 1); + } + + cout << "'" << keywordCpy << "' "; + + for(int pad = keywordCpy.size(); pad < 30; pad++) { + cout << "-"; + } + + cout << "> "; + + vector< string > keywordComments; + string keywordName; + vector< pair > keywordValues; + + bool result = false; + + try { + result = keyword.ReadCleanKeyword(keywordsToTry[key], + keywordComments, + keywordName, + keywordValues); + + if(result) cout << "VALID" << endl; + else cout << "INCOMPLETE" << endl; + } + catch(iException &e) { + cout << "INVALID" << endl; + cout << " "; + cout.flush(); + e.Report(false); + } + + if(result) { + for(unsigned int comment = 0; comment < keywordComments.size(); comment++) + cout << " COMMENT: " << keywordComments[comment] << endl; + + cout << " NAME: " << keywordName << endl; + + for(unsigned int value = 0; value < keywordValues.size(); value++) { + cout << " VALUE: " << keywordValues[value].first; + + if(!keywordValues[value].second.empty()) { + cout << " <" << keywordValues[value].second << ">"; + } + + cout << endl; + } + } + + } + + cout << endl << endl; + cout << "----- Testing Stream Read/Write -----" << endl; + for(unsigned int key = 0; + key < sizeof(keywordsToTry) / sizeof(string); + key ++) { + stringstream stream; + PvlKeyword someKey; + + cout << "Input:\n" << keywordsToTry[key] << endl; + + cout << endl << "Output: " << endl; + try { + stream.write(keywordsToTry[key].c_str(), keywordsToTry[key].size()); + stream >> someKey; + cout << someKey << endl; + } + catch(iException &e) { + e.Report(false); + } + + cout << endl; + } + + cout << "----- Testing Difficult Cases Read/Write -----\n"; + + + try { + + const Isis::PvlKeyword keyN("THE_INTERNET", + "Seven thousand eight hundred forty three million seventy four nine seventy six forty two eighty nine sixty seven thirty five million jillion bajillion google six nine four one two three four five six seven eight nine ten eleven twelve thirteen fourteen", + "terrabytes"); + PvlKeyword keyNRead; + stringstream streamN; + streamN << keyN; + streamN >> keyNRead; + cout << keyNRead << endl; + + const Isis::PvlKeyword keyZ("BIG_HUGE_LONG_NAME_THAT_SHOULD_TEST_OUT_PARSING", + "Seven thousand eight hundred forty three million seventy four", + "bubble baths"); + PvlKeyword keyZRead; + stringstream streamZ; + streamZ << keyZ; + streamZ >> keyZRead; + cout << keyZRead << endl; + + Isis::PvlKeyword keyU("ARRAY_TEST", 5.87, "lightyears"); + keyU.AddValue(5465.6, "lightyears"); + keyU.AddValue(574.6, "lightyears"); + + PvlKeyword keyURead; + stringstream streamU; + streamU << keyU; + streamU >> keyURead; + cout << keyURead << endl; + + const Isis::PvlKeyword keyV("FIRST_100_DIGITS_OF_PI", "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"); + PvlKeyword keyVRead; + stringstream streamV; + streamV << keyV; + streamV >> keyVRead; + cout << keyVRead << endl; + cout << "Raw Data -->" << endl; + cout << keyVRead[0] << endl << endl; + + + const Isis::PvlKeyword keyJ("A", "XXXXXXXXXXxxxxxxxxxxXXXXXXXXXXxxxxxxxxxxXXXXXXXXXXxxxxxxxxxxXXXXXXXXXXxxxx"); + PvlKeyword keyJRead; + stringstream streamJ; + streamJ << keyJ; + streamJ >> keyJRead; + cout << keyJRead << endl; + + string keyB = "TREE = { \"MAPLE\" ,\n \"ELM\" \n, \"PINE\" }"; + PvlKeyword keyBRead; + stringstream streamB; + streamB << keyB; + streamB >> keyBRead; + cout << keyBRead << endl; + + Isis::PvlKeyword keyW("UGHHHHHHHHHHHH"); + keyW += 59999.0; + keyW += 59999.0; + keyW += 59999.0; + keyW += 59999.0; + keyW += 59999.0; + keyW += 59999.0; + keyW += 59999.0; + keyW += 59999.0; + keyW += 59999.0; + keyW += 59999.0; + keyW += 59999.0; + keyW += 59999.0; + + PvlKeyword keyWRead; + stringstream streamW; + streamW << keyW; + streamW >> keyWRead; + cout << keyWRead << endl; + + const Isis::PvlKeyword key("NAME", 5.2, "meters"); + + cout << key << endl; + + Isis::PvlKeyword key2("KEY"); + cout << key2 << endl; + + key2 += 5; + key2 += string(""); + key2.AddValue(3.3, "feet"); + key2.AddValue("Hello World!"); + string str = "Hello World! This is a really really long comment that needs to" + " be wrapped onto several different lines to make the PVL file " + "look really pretty!"; + key2.AddCommentWrapped(str); + cout << key2 << endl; + + cout << key2[1] << endl; + key2[1] = 88; + cout << key2 << endl; + + Isis::PvlSequence seq; + cout.flush(); + seq += "(a,b,c)"; + cout.flush(); + seq += "(\"Hubba Hubba\",\"Bubba\")"; + cout.flush(); + Isis::PvlKeyword k("key"); + k = seq; + cout << k << endl; + + // Test SetUnits methods + k = Isis::PvlKeyword("k", "radius", "meters"); + k.AddValue("circumference", "meters"); + cout << "\n\n" + << "Test SetUnits methods:\n\n" + << " original condition of Keyword k :\n" + << " " << k << "\n\n" + << " after k.SetUnits(\"circumference\", \"Fathoms\") :\n"; + k.SetUnits("circumference", "Fathoms"); + cout << " " << k << "\n\n" + << " after k.SetUnits(\"TeraFathoms\") :\n"; + k.SetUnits("TeraFathoms"); + cout << " " << k << "\n\n\n"; + + //Test casting operators + cout << "----------------------------------------" << endl; + cout << "Testing cast operators" << endl; + Isis::PvlKeyword cast01("cast1", "I'm being casted"); + Isis::PvlKeyword cast02("cast2", "465721"); + Isis::PvlKeyword cast03("cast3", "131.2435"); + cout << "string = " << (string)cast01 << endl; + cout << "int = " << (int)cast02 << endl; + cout << "BigInt = " << (Isis::BigInt)cast02 << endl; + cout << "double = " << (double)cast03 << endl; + + } + catch(Isis::iException &e) { + e.Report(false); + } + catch(...) { + cout << "Unknown error" << endl; + } + + try { + Isis::PvlKeyword key(" Test_key_2 ", "Might work"); + cout << key << endl; + Isis::PvlKeyword key2("Bob is a name", "Yes it is"); + } + catch(Isis::iException &e) { + e.Report(false); + } + + + try { + Isis::PvlKeyword key(" Test_key_3 ", "Might'not work"); + cerr << key << endl; + } + catch(Isis::iException &e) { + e.Report(false); + } +} diff --git a/isis/src/base/objs/PvlObject/Makefile b/isis/src/base/objs/PvlObject/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0f6a74bddaa8b13eb19c46eeaed0a07c7bb2048f --- /dev/null +++ b/isis/src/base/objs/PvlObject/Makefile @@ -0,0 +1,5 @@ +INCS = PvlObject.h +SRCS = PvlObject.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PvlObject/PvlObject.cpp b/isis/src/base/objs/PvlObject/PvlObject.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9232f343dbbbd5f43615f5bcae41b025caf64bf4 --- /dev/null +++ b/isis/src/base/objs/PvlObject/PvlObject.cpp @@ -0,0 +1,811 @@ +/** + * @file + * $Revision: 1.16 $ + * $Date: 2010/04/14 01:56:24 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Filename.h" +#include "Pvl.h" +#include "iException.h" +#include "iException.h" +#include "Message.h" +#include "PvlFormat.h" +#include "PvlObject.h" + +#include +#include + +using namespace std; +namespace Isis { + + //! Creates a blank PvlObject. + PvlObject::PvlObject() : Isis::PvlContainer("Object") { + } + + + /** + * Creates a PvlObject with a specified name. + * + * @param name The name of the PvlObject. + */ + PvlObject::PvlObject(const std::string &name) : + Isis::PvlContainer("Object",name) { + } + + + //! Copy constructor + PvlObject::PvlObject(const PvlObject & other) : + PvlContainer::PvlContainer(other) + { + p_objects = other.p_objects; + p_groups = other.p_groups; + } + + + /** + * Finds a group within the current PvlObject. + * + * @param name The name of the group to look for. + * @param opts The FindOptions option (None or Traverse). + * + * @return The PvlGroup object sought for. + * + * @throws iException::Pvl + */ + Isis::PvlGroup &PvlObject::FindGroup(const std::string &name, + PvlObject::FindOptions opts) { + vector searchList; + searchList.push_back(this); + + while (searchList.size() > 0) { + PvlGroupIterator it = + searchList[0]->FindGroup(name, + searchList[0]->BeginGroup(), + searchList[0]->EndGroup()); + if (it != searchList[0]->EndGroup()) return *it; + if (opts == Traverse) { + for (int i=0; iObjects(); i++) { + searchList.push_back(&searchList[0]->Object(i)); + } + } + searchList.erase(searchList.begin()); + } + + string msg = "Unable to find group [" + name + "]"; + if (p_filename.size() > 0) msg += " in file [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + + /** + * Finds a group within the current PvlObject. + * + * @param name The name of the group to look for. + * @param opts The FindOptions option (None or Traverse). + * + * @return The PvlGroup object sought for. + * + * @throws iException::Pvl + */ + const Isis::PvlGroup &PvlObject::FindGroup(const std::string &name, + PvlObject::FindOptions opts) const { + vector searchList; + searchList.push_back(this); + + while (searchList.size() > 0) { + ConstPvlGroupIterator it = + searchList[0]->FindGroup(name, + searchList[0]->BeginGroup(), + searchList[0]->EndGroup()); + if (it != searchList[0]->EndGroup()) return *it; + if (opts == Traverse) { + for (int i=0; iObjects(); i++) { + searchList.push_back(&searchList[0]->Object(i)); + } + } + searchList.erase(searchList.begin()); + } + + string msg = "Unable to find group [" + name + "]"; + if (p_filename.size() > 0) msg += " in file [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + + /** + * Finds a keyword in the current PvlObject, or deeper inside + * other PvlObjects and PvlGroups within this one. Note: This + * member has the same name as the PvlContainer and hides those + * implementations, but with the using statement the parents + * FindKeyword members ar made visible. Note: If more than one + * occurance of a Keyword appears below this Object no + * guarantee is made as to which one is returned. + * + * @param kname The name of the keyword to look for. + * @param opts The FindOptions option (None or Traverse). + * + * @return The keyword sought + * + * @throws iException::Pvl + */ + PvlKeyword &PvlObject::FindKeyword (const std::string &kname, + FindOptions opts) { + + // Call the parent's version if they don't want to dig deeper + if (opts == None) return FindKeyword (kname); + + // Search this PvlObject, and all PvlObjects and PvlContainers within + // it for the first occurrence of the requested keyword. + vector searchList; + searchList.push_back(this); + + while (searchList.size() > 0) { + PvlKeywordIterator it = + searchList[0]->FindKeyword(kname, searchList[0]->Begin(), + searchList[0]->End()); + if (it != searchList[0]->End()) { + return *it; + } + + // See if the keyword is inside a Group of this Object + for (int g=0; gGroups(); g++) { + PvlKeywordIterator it = + searchList[0]->Group(g).FindKeyword(kname, + searchList[0]->Group(g).Begin(), + searchList[0]->Group(g).End()); + if (it != searchList[0]->Group(g).End()) { + return *it; + } + } + + // It's not in this Object or any Groups in this Object, so + // add all Objects inside this Object to the search list + for (int i=0; iObjects(); i++) { + searchList.push_back(&searchList[0]->Object(i)); + } + + // This Object has been searched to remove it from the list + searchList.erase(searchList.begin()); + } + + // No where else to look for the Keyword so throw an error + string msg = "Unable to find keyword [" + kname + "]"; + if (p_filename.size() > 0) msg += " in file [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + + /** + * See if a keyword is in the current PvlObject, or deeper inside + * other PvlObjects and PvlGroups within this one. Note: This + * member has the same name as the PvlContainer and hides those + * implementations, but with the using statement the parents + * FindKeyword members ar made visible. + * + * @param kname The name of the keyword to look for. + * @param opts The FindOptions option (None or Traverse). + * + * @return True if the Keyword exists False otherwise. + */ + bool PvlObject::HasKeyword (const std::string &kname, + FindOptions opts) const { + + // Call the parent's version if they don't want to dig deeper + if (opts == None) return HasKeyword (kname); + + // Search this PvlObject, and all PvlObjects and PvlContainers within + // it for the first occurrence of the requested keyword. + vector searchList; + searchList.push_back(this); + + while (searchList.size() > 0) { + ConstPvlKeywordIterator it = + searchList[0]->FindKeyword(kname, searchList[0]->Begin(), + searchList[0]->End()); + if (it != searchList[0]->End()) { + return true; + } + + // See if the keyword is inside a Group of this Object + for (int g=0; gGroups(); g++) { + ConstPvlKeywordIterator it = + searchList[0]->Group(g).FindKeyword(kname, + searchList[0]->Group(g).Begin(), + searchList[0]->Group(g).End()); + + if (it != searchList[0]->Group(g).End()) { + return true; + } + } + + // It's not in this Object or any Groups in this Object, so + // add all Objects inside this Object to the search list + for (int i=0; iObjects(); i++) { + searchList.push_back(&searchList[0]->Object(i)); + } + + // This Object has been searched to remove it from the list + searchList.erase(searchList.begin()); + } + return false; + } + + + /** + * Find an object within the current PvlObject. + * + * @param name The object name to look for. + * @param opts The FindOptions option (None or Traverse). + * + * @return The PvlObject sought for. + * + * @throws iException::Pvl + */ + PvlObject &PvlObject::FindObject(const std::string &name, + PvlObject::FindOptions opts) { + vector searchList; + searchList.push_back(this); + + while (searchList.size() > 0) { + PvlObjectIterator it = + searchList[0]->FindObject(name, + searchList[0]->BeginObject(), + searchList[0]->EndObject()); + if (it != searchList[0]->EndObject()) return *it; + if (opts == Traverse) { + for (int i=0; iObjects(); i++) { + searchList.push_back(&searchList[0]->Object(i)); + } + } + searchList.erase(searchList.begin()); + } + + string msg = "Unable to find object [" + name + "]"; + if (p_filename.size() > 0) msg += " in file [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + + /** + * Find an object within the current PvlObject. + * + * @param name The object name to look for. + * @param opts The FindOptions option (None or Traverse). + * + * @return The PvlObject sought for. + * + * @throws iException::Pvl + */ + const PvlObject &PvlObject::FindObject(const std::string &name, + FindOptions opts) const { + vector searchList; + searchList.push_back(this); + + while (searchList.size() > 0) { + ConstPvlObjectIterator it = + searchList[0]->FindObject(name, + searchList[0]->BeginObject(), + searchList[0]->EndObject()); + + if (it != searchList[0]->EndObject()) { + return *it; + } + + if (opts == Traverse) { + for (int i=0; iObjects(); i++) { + searchList.push_back(&searchList[0]->Object(i)); + } + } + + searchList.erase(searchList.begin()); + } + + string msg = "Unable to find object [" + name + "]"; + + if (p_filename.size() > 0) { + msg += " in file [" + p_filename + "]"; + } + + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + + /** + * Remove an object from the current PvlObject. + * + * @param name The name of the PvlObject to remove. + * + * @throws iException::Pvl + */ + void PvlObject::DeleteObject (const std::string &name) { + PvlObjectIterator key = FindObject(name,BeginObject(),EndObject()); + if (key == EndObject()) { + string msg = "Unable to find object [" + name + "] in " + Type() + + " [" + Name() + "]"; + if (p_filename.size() > 0) msg += " in file [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + p_objects.erase(key); + } + + + /** + * Remove an object from the current PvlObject. + * + * @param index The index of the PvlObject to remove. + * + * @throws iException::Pvl + */ + void PvlObject::DeleteObject (const int index) { + if (index >= (int)p_objects.size() || index < 0) { + string msg = "The specified index is out of bounds in " + Type() + + " [" + Name() + "]"; + if (p_filename.size() > 0) msg += " in file [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + PvlObjectIterator key = BeginObject(); + for (int i=0; i 0) msg += " in file [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + p_groups.erase(key); + } + + + /** + * Remove a group from the current PvlObject. + * + * @param index The index of the PvlGroup to remove. + * + * @throws iException::Pvl + */ + void PvlObject::DeleteGroup (const int index) { + if (index >= (int)p_groups.size() || index < 0) { + string msg = "The specified index is out of bounds in " + Type() + + " [" + Name() + "]"; + if (p_filename.size() > 0) msg += " in file [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Pvl,msg,_FILEINFO_); + } + + PvlGroupIterator key = BeginGroup(); + for (int i=0; i= (int)p_groups.size()) { + string msg = Isis::Message::ArraySubscriptNotInRange (index); + throw Isis::iException::Message(Isis::iException::Programmer, + msg, + _FILEINFO_); + } + + return p_groups[index]; + } + + + /** + * Return the group at the specified index. + * + * @param index The index of the group. + * + * @return The PvlGroup sought for. + * + * @throws iException::Pvl + */ + const Isis::PvlGroup &PvlObject::Group(const int index) const { + if (index < 0 || index >= (int)p_groups.size()) { + string msg = Isis::Message::ArraySubscriptNotInRange (index); + throw Isis::iException::Message(Isis::iException::Programmer, + msg, + _FILEINFO_); + } + + return p_groups[index]; + } + + /** + * Return the object at the specified index. + * + * @param index The index of the object. + * + * @return The PvlObject sought for. + * + * @throws iException::Programmer + */ + PvlObject &PvlObject::Object(const int index) { + if (index < 0 || index >= (int)p_objects.size()) { + string msg = Isis::Message::ArraySubscriptNotInRange (index); + throw Isis::iException::Message(Isis::iException::Programmer, + msg, + _FILEINFO_); + } + + return p_objects[index]; + } + + /** + * Return the object at the specified index. + * + * @param index The index of the object. + * + * @return The PvlObject sought for. + * + * @throws iException::Programmer + */ + const PvlObject &PvlObject::Object(const int index) const { + if (index < 0 || index >= (int)p_objects.size()) { + string msg = Isis::Message::ArraySubscriptNotInRange (index); + throw Isis::iException::Message(Isis::iException::Programmer, + msg, + _FILEINFO_); + } + + return p_objects[index]; + } + + + /** + * Outputs the PvlObject data to a specified output stream. + * + * @param os The output stream to write to. + * @param object The PvlObject to send to the output stream. + */ + ostream& operator<<(std::ostream &os, PvlObject &object) { + + // Set up a Formatter + bool removeFormatter = false; + if (object.GetFormat() == NULL) { + object.SetFormat(new PvlFormat()); + removeFormatter = true; + } + + Isis::PvlObject outTemplate("DEFAULT"); + if (object.HasFormatTemplate()) + outTemplate = *(Isis::PvlObject*)object.FormatTemplate(); + + // Look for and process all include files and remove duplicates + Isis::PvlObject newTemp(outTemplate.Name()); + + // Make sure the new template has all the original's comments + for (int i = 0; i < outTemplate.Comments(); i++) { + newTemp.AddComment(outTemplate.Comment(i)); + } + + // Include files take precedence to all other objects and groups + for (int i=0; i 0) { + for (int k=0; kFormatEOL(); + } + //os << object.GetFormat()->FormatEOL(); + } + + // Output the object comments and name + os << object.GetNameKeyword() << object.GetFormat()->FormatEOL(); + object.SetIndent(object.Indent()+2); + + // Output the keywords in this Object + if (object.Keywords() > 0) { + os << (Isis::PvlContainer &) object << object.GetFormat()->FormatEOL(); + } + + // This number keeps track of the number of objects have been written + int numObjects = 0; + + // Output the Objects within this Object using the format template + for (int i=0; i 0) + os << object.GetFormat()->FormatEOL(); + + object.Object(j).SetIndent(object.Indent()); + object.Object(j).SetFormatTemplate(outTemplate.Object(i)); + object.Object(j).SetFormat(object.GetFormat()); + os << object.Object(j) << object.GetFormat()->FormatEOL(); + object.Object(j).SetFormat(NULL); + object.Object(j).SetIndent(0); + + if (++numObjects < object.Objects()) + os << object.GetFormat()->FormatEOL(); + } + } + + // Output the Objects within this Object that were not included in the + // format template pvl + for (int i=0; i 0) + os << object.GetFormat()->FormatEOL(); + + object.Object(i).SetIndent(object.Indent()); + object.Object(i).SetFormat(object.GetFormat()); + os << object.Object(i) << object.GetFormat()->FormatEOL(); + object.Object(i).SetFormat(NULL); + object.Object(i).SetIndent(0); + + if (++numObjects < object.Objects()) + os << object.GetFormat()->FormatEOL(); + + } + + // This number keeps track of the number of Groups that have been written + int numGroups = 0; + + // Output the Groups within this Object using the format template + for (int i=0; i 0 || object.Keywords() > 0)) + os << object.GetFormat()->FormatEOL(); + + object.Group(j).SetIndent(object.Indent()); + object.Group(j).SetFormatTemplate(outTemplate.Group(i)); + object.Group(j).SetFormat(object.GetFormat()); + os << object.Group(j) << object.GetFormat()->FormatEOL(); + object.Group(j).SetFormat(NULL); + object.Group(j).SetIndent(0); + if (++numGroups < object.Groups()) os << object.GetFormat()->FormatEOL(); + } + } + + // Output the groups that were not in the format template + for (int i=0; i 0 || object.Keywords() > 0)) + os << object.GetFormat()->FormatEOL(); + + object.Group(i).SetIndent(object.Indent()); + object.Group(i).SetFormat(object.GetFormat()); + os << object.Group(i) << object.GetFormat()->FormatEOL(); + object.Group(i).SetFormat(NULL); + object.Group(i).SetIndent(0); + + if (++numGroups < object.Groups()) + os << object.GetFormat()->FormatEOL(); + } + + // Output the end of the object + object.SetIndent(object.Indent()-2); + for (int i=0; iFormatEnd("End_Object", object.GetNameKeyword()); + + if (removeFormatter) { + delete object.GetFormat(); + object.SetFormat(NULL); + } + + return os; + } + + + /** + * This method reads a PvlObject from the input stream + * + */ + std::istream& operator>>(std::istream &is, PvlObject &result) { + PvlKeyword termination("EndObject"); + + PvlKeyword errorKeywords[] = { + PvlKeyword("EndGroup") + }; + + PvlKeyword readKeyword; + + istream::pos_type beforeKeywordPos = is.tellg(); + is >> readKeyword; + + if(readKeyword != PvlKeyword("Object")) { + if(is.eof() && !is.bad()) { + is.clear(); + } + + is.seekg(beforeKeywordPos, ios::beg); + + string msg = "Expected keyword named [Object], found keyword named ["; + msg += readKeyword.Name(); + msg += "]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + if(readKeyword.Size() == 1) { + result.SetName(readKeyword[0]); + } + else { + is.seekg(beforeKeywordPos, ios::beg); + + string msg = "Expected a single value for object name, found [("; + + for(int i = 0; i < readKeyword.Size(); i++) { + if(i != 0) msg += ", "; + + msg += readKeyword[i]; + } + + msg += ")]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + for(int comment = 0; comment < readKeyword.Comments(); comment++) { + result.AddComment(readKeyword.Comment(comment)); + } + + readKeyword = PvlKeyword(); + beforeKeywordPos = is.tellg(); + + is >> readKeyword; + while(readKeyword != termination) { + for(unsigned int errorKey = 0; + errorKey < sizeof(errorKeywords)/sizeof(PvlKeyword); + errorKey++) { + if(readKeyword == errorKeywords[errorKey]) { + if(is.eof() && !is.bad()) { + is.clear(); + } + + is.seekg(beforeKeywordPos, ios::beg); + + string msg = "Unexpected ["; + msg += readKeyword.Name(); + msg += "] in Object ["; + msg += result.Name(); + msg += "]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + } + + if(readKeyword == PvlKeyword("Group")) { + is.seekg(beforeKeywordPos); + PvlGroup newGroup; + is >> newGroup; + result.AddGroup(newGroup); + } + else if(readKeyword == PvlKeyword("Object")) { + is.seekg(beforeKeywordPos); + PvlObject newObject; + is >> newObject; + result.AddObject(newObject); + } + else { + result.AddKeyword(readKeyword); + } + + readKeyword = PvlKeyword(); + beforeKeywordPos = is.tellg(); + + if(is.good()) { + is >> readKeyword; + } + else { + // eof found + break; + } + } + + if(readKeyword != termination) { + if(is.eof() && !is.bad()) { + is.clear(); + } + + is.seekg(beforeKeywordPos, ios::beg); + + string msg = "Object [" + result.Name(); + msg += "] EndObject not found before end of file"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + return is; + } + + + //! This is an assignment operator + const PvlObject & PvlObject::operator=(const PvlObject & other) + { + this->PvlContainer::operator=(other); + + p_objects = other.p_objects; + p_groups = other.p_groups; + + return *this; + } + +} // end namespace isis diff --git a/isis/src/base/objs/PvlObject/PvlObject.h b/isis/src/base/objs/PvlObject/PvlObject.h new file mode 100644 index 0000000000000000000000000000000000000000..d26b388a3e755eee99753cb075d102a69291aa3c --- /dev/null +++ b/isis/src/base/objs/PvlObject/PvlObject.h @@ -0,0 +1,332 @@ +#ifndef PvlObject_h +#define PvlObject_h +/** + * @file + * $Revision: 1.16 $ + * $Date: 2010/04/14 01:11:17 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "PvlContainer.h" +#include "PvlGroup.h" + +namespace Isis { + /** + * @brief Contains Pvl Groups and Pvl Objects. + * + * Contains Pvl groups and objects. Organizes text on output to be indented + * correctly. + * + * @ingroup Parsing + * + * @author 2002-10-11 Jeff Anderson + * + * @internal + * @history 2005-04-04 Leah Dahmer wrote class documentation. + * @history 2006-04-21 Jacob Danton Added format templates abilities. + * @history 2006-05-18 Jacob Danton Added DeleteGroup by index @history + * @history 2006-09-11 Stuart Sides Added formatting ability + * @history 2007-08-11 Stuart Sides Added recursive FindKeyword and + * HasKeyword + * @history 2007-08-14 Steven Koechle Fixed missing pointers in FindKeyword + * and HasKeyword + * @history 2008-06-18 Steven Lambright Fixed documentation + * @history 2008-07-03 Steven Lambright Added const functionality and fixed += + * @history 2008-07-10 Steven Lambright Compensated for PvlKeyword no longer + * being a parent + * @history 2008-09-30 Christopher Austin Replaced all std::endl in the << + * operator with PvlFormat.FormatEOL() + * @history 2009-10-28 Travis Addair Fixed bug causing a format + * template's object comments to not appear in the output + * @history 2009-12-17 Steven Lambright Added reading methods + * @history 2009-12-28 Steven Lambright Implemented const FindObject + * @history 2010-04-13 Eric Hyer - Added copy constructor + * Added assignment operator + * + */ + class PvlObject : public Isis::PvlContainer { + public: + PvlObject(); + PvlObject(const std::string &name); + PvlObject(const PvlObject & other); + + friend std::ostream& operator<<(std::ostream &os, Isis::PvlObject &object); + friend std::istream& operator>>(std::istream &is, PvlObject &result); + + /** + * Returns the number of groups contained. + * @return The number of groups. + */ + int Groups () const { return p_groups.size(); }; + + PvlGroup &Group(const int index); + const PvlGroup &Group(const int index) const; + + //! The counter for groups. + typedef std::vector::iterator PvlGroupIterator; + typedef std::vector::const_iterator ConstPvlGroupIterator; + + + /** + * Returns the beginning group index. + * @return The iterator of the beginning group.. + */ + PvlGroupIterator BeginGroup() { return p_groups.begin(); }; + + + /** + * Returns the beginning group index. + * @return The iterator of the beginning group.. + */ + ConstPvlGroupIterator BeginGroup() const { return p_groups.begin(); }; + + + /** + * Returns the ending group index. + * @return The iterator of the ending group. + */ + PvlGroupIterator EndGroup() { return p_groups.end(); }; + + + /** + * Returns the const ending group index. + * @return The iterator of the ending group. + */ + ConstPvlGroupIterator EndGroup() const { return p_groups.end(); }; + + + /** + * Find a group with the specified name, within these indexes. + * @param name The name of the group to look for. + * @param beg The lower index + * @param end The higher index + */ + PvlGroupIterator FindGroup(const std::string &name, + PvlGroupIterator beg, + PvlGroupIterator end) { + Isis::PvlGroup temp(name); + return find(beg,end,temp); + } + + + /** + * Find a group with the specified name, within these indexes. + * @param name The name of the group to look for. + * @param beg The lower index + * @param end The higher index + */ + ConstPvlGroupIterator FindGroup(const std::string &name, + ConstPvlGroupIterator beg, + ConstPvlGroupIterator end) const { + Isis::PvlGroup temp(name); + return find(beg,end,temp); + } + + + /** + * A collection of options to use when finding. + */ + enum FindOptions { + //! Search only the current level + None, + //! Search child objects + Traverse + }; + + // The using statements below are used to make the PvlContainer's version + // of FindKeyword and HasKeyword vissible to other code that otherwise would not be + // able to see those versions. + using PvlContainer::FindKeyword; + + + PvlKeyword &FindKeyword (const std::string &kname, + FindOptions opts); + + + using PvlContainer::HasKeyword; + + + bool HasKeyword (const std::string &kname, + FindOptions opts) const; + + Isis::PvlGroup &FindGroup(const std::string &name, + FindOptions opts = None); + + const Isis::PvlGroup &FindGroup(const std::string &name, + FindOptions opts = None) const; + /** + * Add a group to the object. + * @param group The PvlGroup object to add. + */ + void AddGroup(const Isis::PvlGroup &group) { + p_groups.push_back(group); + //p_groups[p_groups.size()-1].SetFilename(Filename()); + }; + + using PvlContainer::operator+=; + void operator+= (const Isis::PvlGroup &group) { AddGroup(group); } + void operator+= (const Isis::PvlObject &obj) { AddObject(obj); } + + void DeleteGroup(const std::string &name); + + void DeleteGroup(const int index); + + + /** + * Returns a boolean value based on whether the object has the specified + * group or not. + * @param name The name of the group to look for. + * @return True if the object has the group, false if not. + */ + bool HasGroup(const std::string &name) const { + if (FindGroup(name,BeginGroup(),EndGroup()) == EndGroup()) return false; + return true; + } + + /** + * Returns the number of objects. + * @return The number of objects. + */ + int Objects () const { return p_objects.size(); }; + + PvlObject &Object(const int index); + const PvlObject &Object(const int index) const; + + //! The counter for objects. + typedef std::vector::iterator PvlObjectIterator; + typedef std::vector::const_iterator ConstPvlObjectIterator; + + + /** + * Returns the index of the beginning object. + * @return The beginning object's index. + */ + PvlObjectIterator BeginObject() { return p_objects.begin(); }; + + + /** + * Returns the const index of the beginning object. + * @return The beginning object's index. + */ + ConstPvlObjectIterator BeginObject() const { return p_objects.begin(); }; + + + /** + * Returns the index of the ending object. + * @return The ending object's index. + */ + PvlObjectIterator EndObject() { return p_objects.end(); }; + + + /** + * Returns the const index of the ending object. + * @return The ending object's index. + */ + ConstPvlObjectIterator EndObject() const { return p_objects.end(); }; + + + /** + * Find the index of object with a specified name, between two indexes. + * @param name The name of the object to find. + * @param beg The lower index. + * @param end The higher index. + * @return The index of the object. + */ + PvlObjectIterator FindObject(const std::string &name, + PvlObjectIterator beg, + PvlObjectIterator end) { + PvlObject temp(name); + return find(beg,end,temp); + } + + + /** + * Find the index of object with a specified name, between two indexes. + * @param name The name of the object to find. + * @param beg The lower index. + * @param end The higher index. + * @return The index of the object. + */ + ConstPvlObjectIterator FindObject(const std::string &name, + ConstPvlObjectIterator beg, + ConstPvlObjectIterator end) const { + PvlObject temp(name); + return find(beg,end,temp); + } + + + PvlObject &FindObject(const std::string &name, + FindOptions opts = None); + + const PvlObject &FindObject(const std::string &name, + FindOptions opts = None) const; + + /** + * Add a PvlObject. + * @param object The PvlObject to add. + */ + void AddObject(const PvlObject &object) { + p_objects.push_back(object); + p_objects[p_objects.size()-1].SetFilename(Filename()); + } + + void DeleteObject(const std::string &name); + void DeleteObject(const int index); + + + /** + * Returns a boolean value based on whether the object exists in the current + * PvlObject or not. + * @param name The name of the object to search for. + * @return True if the current PvlObject has the specified object, false + * if it does not. + */ + bool HasObject(const std::string &name) const { + if (FindObject(name,BeginObject(),EndObject()) == EndObject()) return false; + return true; + } + + + /** + * Compares two PvlObjects. Returns a boolean value based on the + * StringEqual() method. + * @param object The PvlObject to compare. + * @return True if they are equal, false if not. + */ + bool operator==(const PvlObject &object) const { + return PvlKeyword::StringEqual(object.Name(),this->Name()); + } + + + //! Remove everything from the current PvlObject. + void Clear() { + Isis::PvlContainer::Clear(); p_objects.clear(); p_groups.clear(); + } + + const PvlObject & operator=(const PvlObject & other); + + private: + std::vector p_objects; /** p_groups;/** +#include + +#include "PvlObject.h" +#include "PvlTokenizer.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; +using namespace std; + +int main () { + Preference::Preferences(true); + + PvlObject o("Beasts"); + o += PvlKeyword("CAT","Meow"); + cout << o << endl; + cout << endl; + + PvlGroup g("Fish"); + g += PvlKeyword("Trout","Brown"); + g += PvlKeyword("Bass","Large mouth"); + o += g; + cout << o << endl; + cout << endl; + + PvlGroup g2("Birds"); + g2 += PvlKeyword("Sparrow","House"); + g2 += PvlKeyword("Crow"); + o += g2; + cout << o << endl; + cout << endl; + + PvlObject o2("Snake"); + o2.AddComment("Are slimey"); + o2 += PvlKeyword("Rattler","DiamondBack"); + o += o2; + cout << o << endl; + cout << endl; + + o.FindObject("Snake").AddGroup(g); + cout << o << endl; + cout << endl; + + o.FindObject("Snake") += o2; + cout << o << endl; + cout << endl; + + cout << "New for PvlObjectFindKeyword" << endl; + + cout << o.HasKeyword("Trout", PvlObject::Traverse) << endl; + cout << o.FindKeyword("Trout", PvlObject::Traverse) << endl; + cout << o.HasKeyword("Crow",PvlObject::Traverse) << endl; + cout << o.FindKeyword("Crow",PvlObject::Traverse) << endl; + cout << o.HasKeyword("Rattler",PvlObject::Traverse) << endl; + cout << o.FindKeyword("Rattler",PvlObject::Traverse) << endl; + cout << o.HasKeyword("Cat",PvlObject::Traverse) << endl; + cout << o.FindKeyword("Cat",PvlObject::Traverse) << endl; + + try { + cout << o.FindKeyword("Trout", PvlObject::None) << endl; + } + catch (iException &e) { + e.Report(false); + } + try { + cout << o.FindKeyword("Bus", PvlObject::Traverse) << endl; + } + catch (iException &e) { + e.Report(false); + } + cout << "Keyword Trout should not exist at top level " << o.HasKeyword("Trout", PvlObject::None) << endl; + cout << "Keyword Bus should dnot exit at top level " << o.HasKeyword("Bus", PvlObject::Traverse) << endl; + + cout << "End new for PvlObjectFindKeyword" << endl; + + cout << "------------" << endl; + o.FindObject("Snake").AddObject(o2); + o.FindObject("Snake").FindObject("Snake") += + PvlKeyword("Gopher","Constrictor"); + cout << o << endl; + cout << endl; + + + stringstream os; + os << o; + + cout << "------------" << endl; + + PvlObject o3; + os >> o3; + cout << o3 << endl; + + PvlObject o4; + stringstream os4; + + os4 << "Object = Hello\nKey=Value\nEndObject"; + os4 >> o4; + cout << o4 << endl << endl; + + cout << "Testing Object with no end tag" << endl; + try { + PvlObject o5; + stringstream os5; + + os5 << "Object = Hello\nKey=Value\n"; + os5 >> o5; + cout << o5; + } + catch(iException &e) { + cout.flush(); + e.Report(false); + } + + + cout << "Testing Object with wrong end tag" << endl; + try { + PvlObject o5; + stringstream os5; + + os5 << "Object = Hello\nKey=Value\nEndGroup\n"; + os5 >> o5; + cout << o5; + } + catch(iException &e) { + cout.flush(); + e.Report(false); + } +} diff --git a/isis/src/base/objs/PvlSequence/Makefile b/isis/src/base/objs/PvlSequence/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ea4f93f610f7bea212168f80dc60b56b0d08c2ac --- /dev/null +++ b/isis/src/base/objs/PvlSequence/Makefile @@ -0,0 +1,5 @@ +INCS = PvlSequence.h +SRCS = PvlSequence.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PvlSequence/PvlSequence.cpp b/isis/src/base/objs/PvlSequence/PvlSequence.cpp new file mode 100644 index 0000000000000000000000000000000000000000..df51497c774e7f4676f9db027cfa6783b31b7c45 --- /dev/null +++ b/isis/src/base/objs/PvlSequence/PvlSequence.cpp @@ -0,0 +1,109 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:23 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc/documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "PvlSequence.h" +#include "Pvl.h" + +namespace Isis { +/** + * Load a sequence using a Pvl keyword. Each value of the PvlKeyword will + * be treated as an array for a sequence. Typically, the values in the + * PvlKeyword should be enclosed in parens and comma separated. + * For example, (a,b,c). + * + * @param key keyword containing sequence + */ + PvlSequence &PvlSequence::operator=(PvlKeyword &key) { + for (int i=0; ioperator+=(key[i]); + } + return *this; + } + +/** + * Add a string array to the sequence. The values in the string + * must be enclosed in parens and comma separated. For example, + * (1,2,3). + * + * @param array A string representing an array. + */ + PvlSequence &PvlSequence::operator+=(const std::string &array) { + std::stringstream str; + str << "temp = " << array; + Pvl pvl; + str >> pvl; + PvlKeyword &key = pvl["temp"]; + std::vector temp; + for (int i=0; i &array) { + std::vector temp; + for (int i=0; i<(int)array.size(); i++) { + temp.push_back(iString(array[i])); + } + p_sequence.push_back(temp); + return *this; + } + +/** + * Add a vector of ints to the sequence. This adds another array to the + * sequence whose values are all integers. + * + * @param array vector of integers + */ + PvlSequence &PvlSequence::operator+=(std::vector &array) { + std::vector temp; + for (int i=0; i<(int)array.size(); i++) { + temp.push_back(iString(array[i])); + } + p_sequence.push_back(temp); + return *this; + } + +/** + * Add a vector of ints to the sequence. This adds another array to the + * sequence whose values are all doubles. + * + * @param array vector of doubles + */ + PvlSequence &PvlSequence::operator+=(std::vector &array) { + std::vector temp; + for (int i=0; i<(int)array.size(); i++) { + temp.push_back(iString(array[i])); + } + p_sequence.push_back(temp); + return *this; + } +} diff --git a/isis/src/base/objs/PvlSequence/PvlSequence.h b/isis/src/base/objs/PvlSequence/PvlSequence.h new file mode 100644 index 0000000000000000000000000000000000000000..03cd9e28df08fb89e0f9175831b1690c771a9eab --- /dev/null +++ b/isis/src/base/objs/PvlSequence/PvlSequence.h @@ -0,0 +1,97 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:23 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc/documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef PvlSequence_h +#define PvlSequence_h + +#include +#include "PvlKeyword.h" +#include "iString.h" + +namespace Isis { +/** + * @brief Parse and return elements of a Pvl sequence. + * + * A Pvl sequence is essentially an array of arrays. For example, + * @code + * Keyword = ((a,b,c), (d,e)) + * @endcode + * To extract the invidual arrays from a PvlKeyword you must use a + * PvlSequence. + * + * Here is an example of how to use PvlSequence + * @code + * PvlKeyword k; + * k += "(a,b,c)"; + * k += "(d,e)"; + * + * PvlSequence s = k; + * cout << s.Size() << endl; // should be 2 + * cout << s[0][0] << endl; // should be a + * cout << s[1][1] << endl; // should be e + * @endcode + * @ingroup Parsing + * + * @author 2005-02-16 Jeff Anderson + * + * @internal + * @todo Add PvlSequence(PvlKeyword) constructor + * so that we can code PvlSequence s = k; + * where k is a PvlKeyword. + */ + class PvlSequence { + public: + //! Construct an empty sequence + PvlSequence () {}; + + //! Destruct sequence + ~PvlSequence () {}; + + PvlSequence &operator=(PvlKeyword &key); + + PvlSequence &operator+=(const std::string &array); + + PvlSequence &operator+=(std::vector &array); + + PvlSequence &operator+=(std::vector &array); + + PvlSequence &operator+=(std::vector &array); + + //! Return the ith Array of the sequence + std::vector &operator[](int i) { return p_sequence[i]; }; + + //! Number of arrays in the sequence + inline int Size() const { return p_sequence.size(); }; + + //! Clear the sequence + inline void Clear() { p_sequence.clear(); }; + + private: + std::vector > p_sequence; /** +#include "PvlKeyword.h" +#include "PvlSequence.h" +#include "Preference.h" + +int main (void) { + Isis::Preference::Preferences(true); + + Isis::PvlKeyword key("Key"); + key += std::string("(xyzzy,plover)"); + key += std::string("(2,b,|,^,2,b)"); + + Isis::PvlSequence seq; + seq = key; + + seq += std::string("(a,b,c)"); + seq += std::string("(d,e)"); + seq += std::string("singleton"); + + std::vector slist; + slist.push_back("1"); + slist.push_back("2"); + seq += slist; + + std::vector ilist; + ilist.push_back(-1); + ilist.push_back(-2); + ilist.push_back(-3); + seq += ilist; + + std::vector dlist; + dlist.push_back(1.0); + dlist.push_back(0.0); + dlist.push_back(-1.0); + seq += dlist; + + std::cout << seq.Size() << std::endl; + for (int i=0; i= (int) value.size())) { + string message = Isis::Message::ArraySubscriptNotInRange(index); + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + return value[index]; + } + + /** + * Returns one element of the value-vector in uppercase. + * + * @param index Zero-based index of vector element to return. Defaults to 0 + * + * @return string + * + * @throws Isis::iException::Programmer + */ + string PvlToken::GetValueUpper (const int index) const { + if ((index < 0) || (index >= (int) value.size())) { + string message = Isis::Message::ArraySubscriptNotInRange(index); + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + string upper = value[index]; + for (int i=0; i<(int)upper.size(); i++) { + upper[i] = toupper (upper[i]); + } + return upper; + } +} // end namespace isis diff --git a/isis/src/base/objs/PvlToken/PvlToken.h b/isis/src/base/objs/PvlToken/PvlToken.h new file mode 100644 index 0000000000000000000000000000000000000000..e3c8af640c120ffda60666872efea6a7c0de6247 --- /dev/null +++ b/isis/src/base/objs/PvlToken/PvlToken.h @@ -0,0 +1,77 @@ +#ifndef PvlToken_h +#define PvlToken_h +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:09 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +namespace Isis { +/** + * @brief Container for Keyword-value pair + * + * This class is used for internalizing keyword-value(s) pairs. For example, + * SPACECRAFT=MARS_GLOBAL_SURVEYOR or FROM=file.cub. This is useful when parsing + * ASCII files such as PDS labels or command lines. + * + * @ingroup Parsing + * + * @author 2002-03-18 Jeff Anderson + * + * @internal + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2005-02-14 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * + * @todo 2005-02-14 Jeff Anderson - add coded and implemetation example to + * class documentation + */ + + class PvlToken { + private: + std::string key; //!< Storage for the keyword name + std::vector value; /** &ValueVector () const { return value; }; + }; +}; + +#endif diff --git a/isis/src/base/objs/PvlToken/PvlToken.truth b/isis/src/base/objs/PvlToken/PvlToken.truth new file mode 100644 index 0000000000000000000000000000000000000000..0c021d993d742e2a12b758f6861d2e20fcfc153e --- /dev/null +++ b/isis/src/base/objs/PvlToken/PvlToken.truth @@ -0,0 +1,18 @@ +Info on dog + key: Dog + upperkey: DOG + valuesize: 1 + value: drools + uppervalue: DROOLS + +Adding another value to dog + valuesize: 2 + value: wags tail + uppervalue: WAGS TAIL + +Clearing dog values + valuesize: 0 + +Testing Throws in dog +**PROGRAMMER ERROR** Array subscript [-1] is out of array bounds +**PROGRAMMER ERROR** Array subscript [1] is out of array bounds diff --git a/isis/src/base/objs/PvlToken/unitTest.cpp b/isis/src/base/objs/PvlToken/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79b1f730e37e3c3d2852c969f239386bffc924e8 --- /dev/null +++ b/isis/src/base/objs/PvlToken/unitTest.cpp @@ -0,0 +1,52 @@ +#include +#include "PvlToken.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + + Isis::PvlToken dog ("Dog"); + dog.AddValue ("drools"); + + cout << "Info on dog" << endl; + cout << " key: " << dog.GetKey () << endl; + cout << " upperkey: " << dog.GetKeyUpper () << endl; + cout << " valuesize: " << dog.ValueSize () << endl; + cout << " value: " << dog.GetValue () << endl; + cout << " uppervalue: " << dog.GetValueUpper () << endl; + cout << endl; + + cout << "Adding another value to dog" << endl; + dog.AddValue ("wags tail"); + cout << " valuesize: " << dog.ValueSize () << endl; + cout << " value: " << dog.GetValue (1) << endl; + cout << " uppervalue: " << dog.GetValueUpper (1) << endl; + cout << endl; + + cout << "Clearing dog values" << endl; + dog.ValueClear(); + cout << " valuesize: " << dog.ValueSize () << endl; + cout << endl; + + cout << "Testing Throws in dog" << endl; + + try { + dog.GetValue (-1); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + dog.GetValue (1); + } + catch (Isis::iException &e) { + e.Report (false); + } + + return 0; +} diff --git a/isis/src/base/objs/PvlTokenizer/Makefile b/isis/src/base/objs/PvlTokenizer/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..44f0cb7ec8fef4710dbd45c181034ce8d7e47ac7 --- /dev/null +++ b/isis/src/base/objs/PvlTokenizer/Makefile @@ -0,0 +1,5 @@ +INCS = PvlTokenizer.h +SRCS = PvlTokenizer.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PvlTokenizer/PvlTokenizer.cpp b/isis/src/base/objs/PvlTokenizer/PvlTokenizer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42607de5aa52c8d3f5090335114b0ce685c263b1 --- /dev/null +++ b/isis/src/base/objs/PvlTokenizer/PvlTokenizer.cpp @@ -0,0 +1,515 @@ +/** + * @file + * $Revision: 1.9 $ + * $Date: 2010/01/09 02:09:23 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include "PvlTokenizer.h" +#include "iException.h" +#include "Message.h" +#include "iString.h" + +using namespace std; +namespace Isis { + + //! Constructs a Tokenizer with an empty token list + PvlTokenizer::PvlTokenizer () { + Clear (); + } + + //! Destroys the Tokenizer object and token list + PvlTokenizer::~PvlTokenizer () { + Clear (); + } + + //! Empties the token list. + void PvlTokenizer::Clear () { + tokens.clear (); + } + + /** + * Loads the Token list from a stream. The loading will be terminated upon + * reaching either 1) end-of-stream, or + * 2) a programmer specified terminator string + * + * @param stream The input stream to tokenize + * + * @param terminator If the tokenizer see's this string as a token in the input + * stream it will cease tokenizing. Defaults to "END" + * + * @throws Isis::iException::Parse + */ + void PvlTokenizer::Load (std::istream &stream, const std::string &terminator) { + Isis::iString upTerminator(terminator); + upTerminator.UpCase(); + string s; + int c; + bool newlineFound = false; + + while(true) { + newlineFound = SkipWhiteSpace (stream); + c = stream.peek (); + ValidateCharacter (c); + if (c == EOF) return; + + if (c == '#') { + s = ReadComment (stream); + Isis::PvlToken t("_COMMENT_"); + t.AddValue (s); + + if(newlineFound || tokens.size() == 0 || tokens[tokens.size()-1].ValueSize() == 0) { + // applies to next pvl item + tokens.push_back (t); + } + else { + // applies to previous pvl item + tokens.push_back(tokens[tokens.size()-1]); + tokens[tokens.size()-2] = t; + } + + continue; + } + + if (c == '/') { + c = stream.get (); + c = stream.peek (); + stream.unget (); + ValidateCharacter (c); + if (c == '*') { + s = ReadComment (stream); + Isis::PvlToken t("_COMMENT_"); + t.AddValue (s); + + if(newlineFound || tokens.size() == 0 || tokens[tokens.size()-1].ValueSize() == 0) { + // applies to next pvl item + tokens.push_back (t); + } + else { + // applies to previous pvl item + tokens.push_back(tokens[tokens.size()-1]); + tokens[tokens.size()-2] = t; + } + + continue; + } + } + + s = ReadToken (stream); + Isis::PvlToken t(s); + + if (t.GetKeyUpper () == upTerminator) { + tokens.push_back (t); + return; + } + + SkipWhiteSpace (stream); + c = stream.peek (); + ValidateCharacter (c); + if (c == EOF) { + tokens.push_back (t); + return; + } + + if (c != '=') { + tokens.push_back (t); + if (t.GetKeyUpper () == upTerminator) return; + continue; + } + + stream.ignore (); + SkipWhiteSpace (stream); + + c = stream.peek (); + ValidateCharacter (c); + if (c == EOF) { + tokens.push_back(t); + return; + } + + if (c == '(') { + stream.ignore (); + try { + s = ReadToParen (stream); + ParseCommaList (t,s); + } + catch (Isis::iException &e) { + string message = Isis::Message::KeywordValueBad (t.GetKey()); + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } + tokens.push_back(t); + continue; + } + + if (c == '{') { + stream.ignore (); + try { + s = ReadToBrace (stream); + ParseCommaList (t,s); + } + catch (Isis::iException &e) { + string message = Isis::Message::KeywordValueBad (t.GetKey()); + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } + tokens.push_back(t); + continue; + } + + if (c == '"') { + stream.ignore (); + try { + s = ReadToDoubleQuote (stream); + } + catch (Isis::iException &e) { + string message = Isis::Message::KeywordValueBad (t.GetKey()); + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } + t.AddValue(s); + tokens.push_back(t); + continue; + } + + if (c == '\'') { + stream.ignore (); + try { + s = ReadToSingleQuote (stream); + } + catch (Isis::iException &e) { + string message = Isis::Message::KeywordValueBad (t.GetKey()); + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } + t.AddValue(s); + tokens.push_back(t); + continue; + } + + + s = ReadToken (stream); + t.AddValue(s); + tokens.push_back(t); + continue; + } + } + + /** + * Reads and returns a comment from the stream. + * + * @param stream Input stream to read from + * + * @return string + */ + string PvlTokenizer::ReadComment (std::istream &stream) { + string s; + int c; + + c = stream.get (); + while ((c != '\r') && (c != '\n') && (c != '\0')) { + s += (char) c; + c = stream.peek (); + ValidateCharacter (c); + if (c == EOF) return s; + c = stream.get (); + } + + stream.unget(); + + return s; + } + + /** + * Reads and returns a token from the stream. A token is delimited by either + * whitespace or an equal sign. In the case of whitespace the token will be + * considered valueless. That is, there will be no value in the value side of + * the token (e.g., KEYWORD=). + * + * @param stream Input stream to read from + * + * @return string + */ + string PvlTokenizer::ReadToken (std::istream &stream) { + string s; + int c; + + c = stream.get (); + while ((!isspace (c)) && (c != '\0') && (c != '=')) { + s += (char) c; + c = stream.peek (); + ValidateCharacter (c); + if (c == EOF) return s; + c = stream.get (); + } + + stream.unget(); + + return s; + } + + /** + * Skips over whitespace so long as it is not inside quotes. Whitespace is + * tabs, blanks, line feeds, carriage returns, and NULLs. + * + * @param stream Input stream to read from + */ + bool PvlTokenizer::SkipWhiteSpace (std::istream &stream) { + bool foundNewline = false; + int c; + + c = stream.peek (); + ValidateCharacter (c); + while ((isspace (c)) || (c == '\0')) { + if(c == '\n') { + foundNewline = true; + } + + c = stream.get (); + c = stream.peek (); + ValidateCharacter (c); + } + + return foundNewline; + } + + + string PvlTokenizer::ReadToDoubleQuote (std::istream &stream) { + string s; + int c; + + do { + c = stream.get (); + ValidateCharacter (c); + if (c == EOF) { + string message = Isis::Message::MissingDelimiter ('"',s); + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } + else if (c != '"') { + s += (char) c; + } + } while (c != '"'); + + std::string::size_type pos = s.find_first_of("\n\r"); + while (pos != std::string::npos) { + Isis::iString first = s.substr(0,pos); + bool addspace = false; + if (first[pos-1] == ' ') addspace = true; + first.TrimTail(" \t\n\r\f\0"); + Isis::iString second = s.substr(pos+1); + if (second[0] == ' ') addspace = true; + if (second[0] == '\r') addspace = true; + if (second[0] == '\n') addspace = true; + second.TrimHead(" \t\n\r\f\0"); + if (second[0] == ',') addspace = false; + s = first; + if (addspace) s += " "; + s += second; + pos = s.find_first_of("\n\r"); + } + return s; + } + + string PvlTokenizer::ReadToSingleQuote (std::istream &stream) { + string s; + int c; + + do { + c = stream.get (); + ValidateCharacter (c); + if (c == EOF) { + string message = Isis::Message::MissingDelimiter ('\'',s); + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } + else if (c != '\'') { + s += (char) c; + } + } while (c != '\''); + + std::string::size_type pos = s.find_first_of("\n\r"); + while (pos != std::string::npos) { + Isis::iString first = s.substr(0,pos); + bool addspace = false; + if (first[pos-1] == ' ') addspace = true; + first.TrimTail(" \t\n\r\f\0"); + Isis::iString second = s.substr(pos+1); + if (second[0] == ' ') addspace = true; + if (second[0] == '\r') addspace = true; + if (second[0] == '\n') addspace = true; + second.TrimHead(" \t\n\r\f\0"); + if (second[0] == ',') addspace = false; + s = first; + if (addspace) s += " "; + s += second; + pos = s.find_first_of("\n\r"); + } + + return s; + } + + string PvlTokenizer::ReadToParen (std::istream &stream) { + string s; + int c; + int leftParenCount = 1; + + do { + c = stream.get (); + ValidateCharacter (c); + if (c == EOF) { + string message = Isis::Message::MissingDelimiter (')',s); + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } + else if (c == '"') { + try { + s += "\"" + ReadToDoubleQuote(stream) + "\""; + } + catch (Isis::iException &e) { + e.Clear(); + string message = Isis::Message::MissingDelimiter ('"',s); + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } + } + else if (c == '\'') { + try { + s += "'" + ReadToSingleQuote(stream) + "'"; + } + catch (Isis::iException &e) { + e.Clear(); + string message = Isis::Message::MissingDelimiter ('\'',s); + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } + } + else if (c == ')') { + leftParenCount--; + if (leftParenCount > 0) s += (char) c; + } + else { + s += (char) c; + if (c == '(') leftParenCount++; + } + } while (leftParenCount > 0); + + return s; + } + + string PvlTokenizer::ReadToBrace (std::istream &stream) { + string s; + int c; + int leftBraceCount = 1; + + do { + c = stream.get (); + ValidateCharacter (c); + if (c == EOF) { + string message = Isis::Message::MissingDelimiter ('}',s); + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } + else if (c == '"') { + try { + s += "\"" + ReadToDoubleQuote(stream) + "\""; + } + catch (Isis::iException &e) { + e.Clear(); + string message = Isis::Message::MissingDelimiter ('"',s); + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } + } + else if (c == '\'') { + try { + s += "'" + ReadToSingleQuote(stream) + "'"; + } + catch (Isis::iException &e) { + e.Clear(); + string message = Isis::Message::MissingDelimiter ('\'',s); + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } + } + else if (c == '}') { + leftBraceCount--; + if (leftBraceCount > 0) s += (char) c; + } + else { + s += (char) c; + if (c == '{') leftBraceCount++; + } + } while (leftBraceCount > 0); + + return s; + } + + /** + * This routine parses a string containing a comma separated list. Each of the + * items in the list is stored as a value in the Token. + * + * @param t Token to load the comma separated list + * + * @param cl iString containing comma separated list + */ + void PvlTokenizer::ParseCommaList (Isis::PvlToken &t, const std::string &cl) { + stringstream stream(cl); + int c; + string s; + + do { + SkipWhiteSpace(stream); + c = stream.get (); + if (c == '"') { + s += ReadToDoubleQuote(stream); + } + else if (c == '\'') { + s += ReadToSingleQuote(stream); + } + else if (c == '(') { + s += "("; + s += ReadToParen(stream); + s += ")"; + } + else if (c == '{') { + s += "{"; + s += ReadToBrace(stream); + s += "}"; + } + else if (c == ',') { + t.AddValue (s); + s.erase(); + } + else if (c != EOF) { + s += (char) c; + } + } while (c != EOF); + + t.AddValue (s); + } + + + vector & PvlTokenizer::GetTokenList () { + return tokens; + } + + /** + * Make sure a character is valid printable (non-control) character + * + * @param c Character to be validated + */ + void PvlTokenizer::ValidateCharacter (int c) { + if (c == EOF) return; + if (isprint (c)) return; + if (isspace (c)) return; + if (c == '\0') return; + + string message = "ASCII data expected but found unprintable (binary) data"; + throw Isis::iException::Message(Isis::iException::Parse,message,_FILEINFO_); + } +} // end namespace isis diff --git a/isis/src/base/objs/PvlTokenizer/PvlTokenizer.h b/isis/src/base/objs/PvlTokenizer/PvlTokenizer.h new file mode 100644 index 0000000000000000000000000000000000000000..5043bd42e4c385e505c4e092a6e9dcddfbdff10b --- /dev/null +++ b/isis/src/base/objs/PvlTokenizer/PvlTokenizer.h @@ -0,0 +1,118 @@ +#ifndef PvlTokenizer_h +#define PvlTokenizer_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/01/09 02:09:23 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "PvlToken.h" + +namespace Isis { + /** + * @brief Construct Token list from a stream + * + * This class tokenizes a stream. That is, it will take a stream, from a file + * or a string, and break the contents of the stream into keyword-value pairs. + * Examples of such are PDS labels, the standard Isis command line, and VICAR + * labels. Note that this does not validate the stream to ensure it is of PDS- + * or VICAR-type. It simply creates a list of keyword-value pairs which can be + * parsed by another object. The ruleset for tokenizing is straightforward. + * Consider SPACECRAFT=MARS_GLOBAL_SURVEYOR. The keyword would be SPACECRAFT + * and the value would be MARS_GLOBAL_SURVEYOR. Other valid examples include: + * LINES=5, FOCAL_LENGTH=12.4, INSTRUMENT="CAMERA_A", LIST=(0,1,5), and + * DOGS=("LAB","PUG","BULL"). The later examples, are considered arrays and + * therefore, will have multiple values associated with the keyword. Comments + * are allowed in the stream and are indicated by either "#" or "/ *" as the + * first character on the line. + * + * @ingroup Parsing + * + * @author 2002-02-15 Jeff Anderson + * + * @internal + * @history 2003-02-25 Stuart Sides - Modified the way END is checked for. It + * was not working for embedded labels. + * + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * + * @history 2003-05-28 Stuart Sides - Modified so single quotes work the same + * as double quotes + * + * @history 2003-10-28 Jeff Anderson - Fixed bug in order to allow for + * whitespace inside of arrays of strings + * + * @history 2004-01-22 Jeff Anderson - Removed single quotes when the occur as + * delimeters inside of array keywords. + * + * @history 2005-02-16 Jeff Anderson - Modified parsing of comma separated + * lists to not remove parens or squiggly + * brackets. + * + * @history 2005-02-18 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * + * @history 2006-05-31 Elizabeth Miller - Fixed bug in Load method when a + * keyword is loaded without a value + * + * @todo 2005-02-14 Jeff Anderson - finish class documentation and add coded + * and implementation examples + * + * @history 2007-04-13 Stuart Sides - Fixed bug where quoted strings broken + * over more than two lines were not being + * read correctly. + * + * @history 2009-03-13 Steven Lambright - Inline comments now correctly + * correlate to the keywords before them on the same line. + * + * @history 2010-01-08 Eric Hyer - PvlTokenizer.cpp used EOF without including + * fstream, breaking this class on recent + * compilers (I added #include ). + */ + class PvlTokenizer { + + protected: + std::vector tokens; /** & GetTokenList (); + }; +}; + +#endif diff --git a/isis/src/base/objs/PvlTokenizer/PvlTokenizer.truth b/isis/src/base/objs/PvlTokenizer/PvlTokenizer.truth new file mode 100644 index 0000000000000000000000000000000000000000..2d5798e40523e835a419df0ac911223d609644ed --- /dev/null +++ b/isis/src/base/objs/PvlTokenizer/PvlTokenizer.truth @@ -0,0 +1,44 @@ +TESTING TOKENIZER +DOG is POODLE +CAT is TABBY +BIRD is PARROT +REPTILE is SNAKE LIZARD +-VEGGIE is +BOVINE is COW CAMEL +TREE is MAPLE ELM PINE +_COMMENT_ is # This is a comment +FLOWER is DAISY & TULIP +_COMMENT_ is /* This is another comment +BIG is NOT REALLY LARGE +SEQUENCE is (a,b,c) (d,e,f) +QUOTED_STRING is A QUOTED STRING +QuotedNewLine is abcdefgh ijk lmn +ApostNewLine is abcdefgh ijk lmn + +TESTING TOKENIZER CLEAR +0 + +TESTING TOKEN ERROR [PHRASE = "The quick brown fox jumped over the lazy dog] +**PARSE ERROR** Keyword [PHRASE] has bad value +**PARSE ERROR** Missing delimiter ["] at or near [The quick brown fox ...] + +TESTING TOKEN ERROR [PHRASE = {To Be or Not To Be That is the Question] +**PARSE ERROR** Keyword [PHRASE] has bad value +**PARSE ERROR** Missing delimiter [}] at or near [To Be or Not To Be T ...] + +TESTING TOKEN ERROR [PHRASE = (I came, I saw, I conquered] +**PARSE ERROR** Keyword [PHRASE] has bad value +**PARSE ERROR** Missing delimiter [)] at or near [I came, I saw, I con ...] + +TESTING TOKEN ERROR [FOOD = ("french","fries,"good") ] +**PARSE ERROR** Keyword [FOOD] has bad value +**PARSE ERROR** Missing delimiter ["] at or near ["french","fries,"goo ...] + +TESTING TOKEN ERROR [FOOD = ("burgers","hotdogs,"good")] +**PARSE ERROR** Keyword [FOOD] has bad value +**PARSE ERROR** Missing delimiter ["] at or near ["burgers","hotdogs," ...] + +TESTING TOKEN ERROR [FOOD = ("pickels,pizza")] + +TESTING TOKEN ERROR [FISH = ("trout","pizz"a)] + diff --git a/isis/src/base/objs/PvlTokenizer/unitTest.cpp b/isis/src/base/objs/PvlTokenizer/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8892a1a5d7f3c9f557572fdee8e7acc9532e70cb --- /dev/null +++ b/isis/src/base/objs/PvlTokenizer/unitTest.cpp @@ -0,0 +1,142 @@ +#include +#include "PvlToken.h" +#include "PvlTokenizer.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; +int main (void) { + Isis::Preference::Preferences(true); + +//***************************************************************************** +// Create Instances of the Tokenizer +//***************************************************************************** + + Isis::PvlTokenizer tizer; + +//***************************************************************************** +// Create a stream and load it +//***************************************************************************** + + stringstream os; + os << "DOG=POODLE " + << "CAT=\"TABBY\" " + << "BIRD=(PARROT) \0" + << "REPTILE={SNAKE,LIZARD} \t" + << "-VEGGIE \n" + << " " + << " BOVINE = ( COW , CAMEL ) \n " + << "TREE = { \"MAPLE\" ,\n \"ELM\" \n, \"PINE\" }" + << "FLOWER = \"DAISY & \nTULIP \"" + << "# This is a comment\n" + << "/* This is another comment\n" + << "BIG = (\" NOT \",\"REALLY LARGE\")\n" + << "SEQUENCE = ((a,b,c), (d,e,f))" + << "QUOTED_STRING=\"A QUOTED STRING\"" + << "QuotedNewLine=\"abcd\nefgh \nijk\n lmn\"" + << "ApostNewLine=\'abcd\nefgh \nijk\n lmn\'"; + + try { + tizer.Load (os); + } + catch (Isis::iException &e) { + e.Report (false); + } + + vector t = tizer.GetTokenList(); + + cout << "TESTING TOKENIZER" << endl; + int i,j; + for (i=0; i<(int)t.size(); i++) { + cout << t[i].GetKey() << " is "; + for (j=0; j t2 = tizer.GetTokenList(); + cout << t2.size() << endl << endl; + + stringstream os2; + os2 << "PHRASE = \"The quick brown fox jumped over the lazy dog"; + cout << "TESTING TOKEN ERROR [" << os2.str() << "]" << endl; + try { + tizer.Load (os2); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + stringstream os3; + os3 << "PHRASE = {To Be or Not To Be That is the Question"; + cout << "TESTING TOKEN ERROR [" << os3.str() << "]" << endl; + try { + tizer.Load (os3); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + stringstream os4; + os4 << "PHRASE = (I came, I saw, I conquered"; + cout << "TESTING TOKEN ERROR [" << os4.str() << "]" << endl; + try { + tizer.Load (os4); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + stringstream os5; + os5 << "FOOD = (\"french\",\"fries,\"good\") "; + cout << "TESTING TOKEN ERROR [" << os5.str() << "]" << endl; + try { + tizer.Load (os5); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + stringstream os6; + os6 << "FOOD = (\"burgers\",\"hotdogs,\"good\")"; + cout << "TESTING TOKEN ERROR [" << os6.str() << "]" << endl; + try { + tizer.Load (os6); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + stringstream os7; + os7 << "FOOD = (\"pickels,pizza\")"; + cout << "TESTING TOKEN ERROR [" << os7.str() << "]" << endl; + try { + tizer.Load (os7); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + stringstream os8; + os8 << "FISH = (\"trout\",\"pizz\"a)"; + cout << "TESTING TOKEN ERROR [" << os8.str() << "]" << endl; + try { + tizer.Load (os8); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + return 0; +} diff --git a/isis/src/base/objs/PvlTranslationManager/Makefile b/isis/src/base/objs/PvlTranslationManager/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d456f4da793604e4b63d8bb928518853d2790e55 --- /dev/null +++ b/isis/src/base/objs/PvlTranslationManager/Makefile @@ -0,0 +1,5 @@ +INCS = PvlTranslationManager.h +SRCS = PvlTranslationManager.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PvlTranslationManager/PvlTranslationManager.cpp b/isis/src/base/objs/PvlTranslationManager/PvlTranslationManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b084ad5b14287a720ce2fca42ff382f465f1c6c0 --- /dev/null +++ b/isis/src/base/objs/PvlTranslationManager/PvlTranslationManager.cpp @@ -0,0 +1,329 @@ +/** + * @file + * $Revision: 1.10 $ + * $Date: 2010/01/04 18:01:31 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "iString.h" +#include "Message.h" +#include "iException.h" +#include "PvlTranslationManager.h" + +using namespace std; +namespace Isis { + + PvlTranslationManager::PvlTranslationManager (const std::string &transFile) { + AddTable (transFile); + } + + /** + * Constructs and initializes a TranslationManager object + * + * @param inputLabel The Pvl holding the input label. + * + * @param transFile The translation file to be used to tranlate keywords in + * the input label. + */ + PvlTranslationManager::PvlTranslationManager (Isis::Pvl &inputLabel, + const std::string &transFile) { + p_fLabel = inputLabel; + + // Internalize the translation table + AddTable (transFile); + } + + /** + * Constructs and initializes a TranslationManager object + * + * @param inputLabel The Pvl holding the input label. + * + * @param transStrm A stream containing the tranlation table to be used to + * tranlate keywords in the input label. + */ + PvlTranslationManager::PvlTranslationManager (Isis::Pvl &inputLabel, + std::istream &transStrm) { + p_fLabel = inputLabel; + + // Internalize the translation table + AddTable (transStrm); + } + + /** + * Returns a translated value. The output name is used to find the input + * group, keyword, default and tranlations in the translation table. If the + * keyword does not exist in the input label, the input default if + * available will be used as the input value. This input value + * is then used to search all of the translations. If a match is + * found the translated value is returned. + * + * @param nName The output name used to identify the input keyword to be + * translated. + * + * @param findex The index into the input keyword array. Defaults to 0 + * + * @return string + */ + string PvlTranslationManager::Translate (const std::string nName, int findex) { + const Isis::PvlContainer *con; + int inst = 0; + PvlKeyword grp; + + while ((grp = InputGroup(nName, inst++)).Name() != "") { + if ((con = GetContainer(grp)) != NULL) { + if (con->HasKeyword(InputKeywordName(nName))) { + return PvlTranslationTable::Translate(nName, + (*con)[InputKeywordName(nName)][findex]); + } + } + } + + return Isis::PvlTranslationTable::Translate(nName); + } + + /** + * Translate the requested output name to output values using the input name + * and values or default value + * + * @param nName The output name used to identify the input keyword to be + * translated. + * + * @return Isis::PvlKeyword + */ + Isis::PvlKeyword PvlTranslationManager::DoTranslation( + const std::string nName) { + const Isis::PvlContainer *con = NULL; + Isis::PvlKeyword key; + + int inst = 0; + PvlKeyword grp; + + while ((grp = InputGroup(nName, inst++)).Name() != "") { + if ((con = GetContainer(grp)) != NULL) { + if (con->HasKeyword(InputKeywordName(nName))) { + key.SetName(OutputName(nName)); + + for (int v=0; v<(*con)[(InputKeywordName(nName))].Size(); v++) { + key.AddValue(Isis::PvlTranslationTable::Translate(nName, + (*con)[InputKeywordName(nName)][v]), + (*con)[InputKeywordName(nName)].Unit(v)); + } + + return key; + } + } + } + + return Isis::PvlKeyword (OutputName(nName), + PvlTranslationTable::Translate(nName, "")); + } + + + + // Automatically translate all the output names found in the translation table + // If a output name does not translate an error will be thrown by one + // of the support members + // Store the translated key, value pairs in the argument pvl + void PvlTranslationManager::Auto (Isis::Pvl &outputLabel) { + // Attempt to translate every group in the translation table + for (int i=0; iHasKeyword(InputKeywordName(nName))) { + return containingGroup->FindKeyword(InputKeywordName(nName)); + } + } + + instanceNumber ++; + inputGroupKeyword = InputGroup(nName, instanceNumber); + } + + if(anInputGroupFound) { + string msg = "Unable to find input keyword [" + InputKeywordName(nName) + + "] for output name [" + nName + "] in file [" + TranslationTable().Filename() +"]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + else { + string container = ""; + + for(int i = 0; i < InputGroup(nName).Size(); i++) { + if(i > 0) container += ","; + + container += InputGroup(nName)[i]; + } + + string msg = "Unable to find input group [" + container + + "] for output name [" + nName + "] in file [" + TranslationTable().Filename() +"]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + } + + + /** + * Indicates if the input keyword corresponding to the output name exists in + * the label + * + * @param nName The output name used to identify the input keyword. + */ + bool PvlTranslationManager::InputHasKeyword (const std::string nName) { + + // Set the current position in the input label pvl + // by finding the input group corresponding to the output group + const Isis::PvlContainer *con; + int inst = 0; + //while ((con = GetContainer(InputGroup(nName, inst++))) != NULL) { + //if ((con = GetContainer (InputGroup(nName))) != NULL) { + + PvlKeyword grp; + while ((grp = InputGroup(nName, inst++)).Name() != "") { + if ((con = GetContainer(grp)) != NULL) { + if (con->HasKeyword(InputKeywordName(nName))) return true; + } + } + + return false; + } + + /* + * Indicates if the input group corresponding to the output name exists in + * the label + * + * @param nName The output name used to identify the input keyword. + + bool PvlTranslationManager::InputHasGroup (const std::string nName) { + + if (GetContainer (InputGroup(nName)) != NULL) { + return true; + } + + return false; + } +*/ + + // Return a container from the input label according tund + const Isis::PvlContainer *PvlTranslationManager::GetContainer( + const PvlKeyword &inputGroup) const { + + + // Return the root container if "ROOT" is the ONLY thing in the list + if (inputGroup.Size() == 1 && + PvlKeyword::StringEqual(inputGroup[0], "ROOT")) { + return &p_fLabel; + } + + const Isis::PvlObject *currentObject = &p_fLabel; + + // Search for object containing our solution + int objectIndex; + for(objectIndex = 0; + objectIndex < inputGroup.Size() - 1; + objectIndex ++) { + if(currentObject->HasObject(inputGroup[objectIndex])) { + currentObject = ¤tObject->FindObject(inputGroup[objectIndex]); + } + else { + return NULL; + } + } + + // Our solution can be an object or a group + if(currentObject->HasObject(inputGroup[objectIndex])) { + return ¤tObject->FindObject(inputGroup[objectIndex]); + } + else if(currentObject->HasGroup(inputGroup[objectIndex])) { + return ¤tObject->FindGroup(inputGroup[objectIndex]); + } + else { + return NULL; + } + } + + + // Create the requsted container and any containers above it and + // return a reference to the container + // list is an Isis::PvlKeyword with an array of container types an their names + Isis::PvlContainer *PvlTranslationManager::CreateContainer(const std::string nName, + Isis::Pvl &pvl) { + + // Get the array of Objects/Groups from the OutputName keyword + Isis::PvlKeyword np = OutputPosition(nName); + + Isis::PvlObject *obj = &pvl; + + // Look at every pair in the output position + for (int c=0; cHasObject(np[c+1])) { + obj->AddObject (np[c+1]); + } + obj = &(obj->FindObject(np[c+1])); + } + // If this pair is a group + else if (np[c].UpCase() == "GROUP") { + // If the group doesn't exist create it + if (!obj->HasGroup (np[c+1])) { + obj->AddGroup (np[c+1]); + } + return (Isis::PvlContainer *) &(obj->FindGroup(np[c+1])); + + } + } + + return (Isis::PvlContainer *) obj; + } +} // end namespace isis diff --git a/isis/src/base/objs/PvlTranslationManager/PvlTranslationManager.h b/isis/src/base/objs/PvlTranslationManager/PvlTranslationManager.h new file mode 100644 index 0000000000000000000000000000000000000000..03c90af56ad2074538fc854c01a23cf505766bf7 --- /dev/null +++ b/isis/src/base/objs/PvlTranslationManager/PvlTranslationManager.h @@ -0,0 +1,114 @@ +#ifndef PvlTranslationManager_h +#define PvlTranslationManager_h +/** + * @file + * $Revision: 1.6 $ + * $Date: 2010/01/04 18:01:31 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "Filename.h" +#include "PvlTokenizer.h" +#include "PvlTranslationTable.h" + +namespace Isis { +/** + * @brief Allows applications to translate simple text files + * + * This class allows the translation of text files which can be parsed by the + * Pvl class. + * + * @ingroup Parsing + * + * @author 2003-05-29 Stuart Sides + * + * @internal + * @history 2003-09-03 Stuart Sides - Modified to work with new isis label + * format + * @history 2003-09-25 Stuart Sides - Added the Translate member + * @history 2005-02-15 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2006-08-09 Brendan George - Modified to support Optional keyword + * translation + * @history 2006-10-01 Stuart Sides - Fixed bug with Optional keyword. + * Non-optional keywords were being reported + * instantly. + * @history 2006-11-16 Brendan George - Changed instances of "Foreign" to "Input" + * and "Native" to "Output" + * @history 2007-06-22 Stuart Sides - Added ability to have more than one input location + * keyword for a translation. The first one found + * which contains the input keyword is used. + * @history 2008-05-09 Steven Lambright - Added ability to change input label without + * re-reading the translation file. + * @history 2008-07-10 Noah Hilt - Changed while loops to continue searching + * other groups if a group has been found, but the keyword does not + * exist in that group. + * @history 2008-07-10 Steven Lambright - Changed to use new accessors + * @history 2010-01-04 Steven Lambright - Added InputKeyword method and removed + * InputSize, InputUnits, InputValue. + * Renamed private Translate method to + * DoTranslation to remove ambiguity + * with a parent method, instead of + * using a dummy parameter. + * @todo 2005-02-15 Stuart Sides - add coded example and implementation example + * to class documentation, and finish + * documentation + */ + class PvlTranslationManager : public PvlTranslationTable { + public: + PvlTranslationManager (const std::string &transFile); + + PvlTranslationManager (Isis::Pvl &inputLabel, + const std::string &transFile); + + PvlTranslationManager (Isis::Pvl &inputLabel, + std::istream &transStrm); + + //! Destroys the TranslationManager object. + ~PvlTranslationManager () {}; + + // Attempt to translate the requested output name to output value + // using the input name and value/default value + std::string Translate (const std::string nName, int findex = 0); + + // Translate all translation table groups which contain "Auto" + void Auto (Isis::Pvl &outputLabel); + + // Return the ith input value associated with a output name + const PvlKeyword &InputKeyword (const std::string nName) const; + + // Return true if the input lable contains the translated group and key names + bool InputHasKeyword (const std::string nName); + + void SetLabel(Isis::Pvl &lab) { p_fLabel = lab; } + private: + + Isis::Pvl p_fLabel; //! +#include "PvlTranslationManager.h" +#include "Preference.h" +#include "iException.h" +#include "iString.h" +#include "Preference.h" + +using namespace std; +int main (void) { + Isis::Preference::Preferences(true); + + try { + + stringstream fStrm; + fStrm << "^IMAGE = (SomeFile.dat, 32)" << endl; + fStrm << "Object = Image" << endl; + fStrm << " Group = Size" << endl; + fStrm << " NL = 500" << endl; + fStrm << " NS = 400" << endl; + fStrm << " NB = (27,12,1)" << endl; + fStrm << " EndGroup" << endl; + fStrm << " Group = Pixel" << endl; + fStrm << " Bits = 16" << endl; + fStrm << " Signed = True" << endl; + fStrm << " Architecture = Sun" << endl; + fStrm << " Resolution = 100" << endl; + fStrm << " EndGroup" << endl; + fStrm << " Object = BandInfo" << endl; + fStrm << " Band = (r,g,b)" << endl; + fStrm << " Center = (2, 8, 1.9)" << endl; + fStrm << " EndObject" << endl; + fStrm << "EndObject" << endl; + + fStrm << "OBJECT = QUBE" << endl; + fStrm << " GROUP = IMAGE_MAP_PROJECTION" << endl; + fStrm << " MAP_PROJECTION_TYPE = SINUSOIDAL" << endl; + fStrm << " A_AXIS_RADIUS = 1737.4000000" << endl; + fStrm << " CENTER_LONGITUDE = 44.4975624" << endl; + fStrm << " END_GROUP = IMAGE_MAP_PROJECTION" << endl; + fStrm << "END_OBJECT = QUBE" << endl; + fStrm << "End" << endl; + Isis::Pvl fLabel; + fStrm >> fLabel; + + stringstream trnsStrm; + trnsStrm << "Group = DataFileName" << endl; + trnsStrm << " InputKey = ^IMAGE" << endl; + trnsStrm << " Translation = (*,*)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = ImageStartByte" << endl; + trnsStrm << " InputKey = ^IMAGE" << endl; + trnsStrm << " InputDefault = 1" << endl; + trnsStrm << " Translation = (*,*)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = NumberOfLines" << endl; + trnsStrm << " Auto" << endl; + trnsStrm << " OutputName = Lines" << endl; + trnsStrm << " OutputPosition = (\"Object\",\"IsisCube\","; + trnsStrm << "\"Group\",\"Dimensions\")" << endl; + trnsStrm << " InputPosition = (Image,Size)" << endl; + trnsStrm << " InputKey = NL" << endl; + trnsStrm << " Translation = (*,*)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = NumberOfBands" << endl; + trnsStrm << " Auto" << endl; + trnsStrm << " Optional" << endl; + trnsStrm << " OutputName = Bands" << endl; + trnsStrm << " OutputPosition = (\"Object\",\"IsisCube\","; + trnsStrm << "\"Group\",\"Dimensions\")" << endl; + trnsStrm << " InputPosition = (Image,Size)" << endl; + trnsStrm << " InputKey = Nb" << endl; + trnsStrm << " InputDefault = 1" << endl; + trnsStrm << " Translation = (*,*)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = Bonus" << endl; + trnsStrm << " Auto" << endl; + trnsStrm << " Optional" << endl; + trnsStrm << " InputPosition = (Image,Pixel)" << endl; + trnsStrm << " InputKey = Bonus" << endl; + trnsStrm << " Translation = (*,*)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = Extra" << endl; + trnsStrm << " Auto" << endl; + trnsStrm << " Optional" << endl; + trnsStrm << " InputPosition = (Image,Bogus)" << endl; + trnsStrm << " InputKey = Extra" << endl; + trnsStrm << " Translation = (*,*)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = BytesPerPixel" << endl; + trnsStrm << " Auto" << endl; + trnsStrm << " InputPosition = Size" << endl; + trnsStrm << " InputPosition = (Image,Size)" << endl; + trnsStrm << " InputPosition = (Image,Pixel)" << endl; + trnsStrm << " InputKey = Bits" << endl; + trnsStrm << " InputDefault = 8" << endl; + trnsStrm << " OutputName = PixelBytes" << endl; + trnsStrm << " OutputPosition = Root" << endl; + trnsStrm << " Translation = (1,8)" << endl; + trnsStrm << " Translation = (2,16)" << endl; + trnsStrm << " Translation = (4,32)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = PixelResolution" << endl; + trnsStrm << " InputPosition = (Image,Pixel)" << endl; + trnsStrm << " InputKey = Resolution" << endl; + trnsStrm << " InputDefault = 1" << endl; + trnsStrm << " Translation = (*,*)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = Sign" << endl; + trnsStrm << " InputPosition = (Image,Pixel)" << endl; + trnsStrm << " InputKey = Signed" << endl; + trnsStrm << " InputDefault = True" << endl; + trnsStrm << " Translation = (True,True)" << endl; + trnsStrm << " Translation = (False,False)" << endl; + trnsStrm << " Translation = (True,Yes)" << endl; + trnsStrm << " Translation = (False,No)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = BandName" << endl; + trnsStrm << " Auto" << endl; + trnsStrm << " OutputName = Band" << endl; + trnsStrm << " OutputPosition = (\"Object\",\"IsisCube\","; + trnsStrm << "\"Object\",\"BandBin\")" << endl; + trnsStrm << " InputPosition = (Image,BandInfo)" << endl; + trnsStrm << " InputKey = Band" << endl; + trnsStrm << " Translation = (Red,r)" << endl; + trnsStrm << " Translation = (Green,g)" << endl; + trnsStrm << " Translation = (Blue,b)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = BadGroup" << endl; + trnsStrm << " InputPosition = (Bad1,Bad2,Bad3)" << endl; + trnsStrm << " InputKey = BadKey" << endl; + trnsStrm << " InputDefault = 1" << endl; + trnsStrm << " Translation = (*,*)" << endl; + trnsStrm << "EndGroup" << endl; + trnsStrm << "Group = GoodGroupBadKey" << endl; + trnsStrm << " InputPosition = (Image,Pixel)" << endl; + trnsStrm << " InputKey = BadKey" << endl; + trnsStrm << " InputDefault = 1" << endl; + trnsStrm << " Translation = (*,*)" << endl; + trnsStrm << "EndGroup" << endl; + + trnsStrm << "Group = CenterLongitude" << endl; + trnsStrm << " Auto" << endl; + trnsStrm << " OutputPosition = (\"Group\",\"Mapping\")" << endl; + trnsStrm << " OutputName = CenterLongitude" << endl; + trnsStrm << " InputPosition = IMAGE_MAP_PROJECTION" << endl; + trnsStrm << " InputPosition = (QUBE,IMAGE_MAP_PROJECTION)" << endl; + trnsStrm << " InputPosition = (SPECTRAL_QUBE,IMAGE_MAP_PROJECTION)" << endl; + trnsStrm << " InputKey = CENTER_LONGITUDE" << endl; + trnsStrm << " Translation = (*,*)" << endl; + trnsStrm << "EndGroup" << endl; + + trnsStrm << "End" << endl; + + Isis::PvlTranslationManager transMgr (fLabel, trnsStrm); + + cout << "Testing Isis::PvlTranslationManager object" << endl; + + cout << " Testing InputValue member" << endl; + cout << " DataFileName = " << transMgr.InputKeyword("DataFileName")[0] << endl; + cout << " StartByte = " << transMgr.InputKeyword("ImageStartByte")[1] << endl; + cout << " NumberOfBands = " << transMgr.InputKeyword("NumberOfBands")[0] << endl; + cout << " PixelResolution = " << transMgr.InputKeyword("PixelResolution")[0] << endl; + cout << " Error messages:" << endl; + try { + transMgr.InputKeyword ("BadGroup"); + } + catch (Isis::iException &e) { + cerr << " "; + e.Report(false); + } + try { + transMgr.InputKeyword ("GoodGroupBadKey"); + } + catch (Isis::iException &e) { + cerr << " "; + e.Report(false); + } + cout << endl; + + cout << " Testing InputUnits member" << endl; + cout << " PixelResolution = " << transMgr.InputKeyword("PixelResolution").Unit() << endl; + cout << " NumberOfBands = " << transMgr.InputKeyword("NumberOfBands").Unit() << endl; + cout << " Error messages:" << endl; + try { + transMgr.InputKeyword ("BadGroup").Unit(); + } + catch (Isis::iException &e) { + cerr << " "; + e.Report(false); + } + try { + transMgr.InputKeyword ("GoodGroupBadKey").Unit(); + } + catch (Isis::iException &e) { + cerr << " "; + e.Report(false); + } + cout << endl; + + cout << " Testing InputSize member" << endl; + cout << " BandName = " << transMgr.InputKeyword("BandName").Size() << endl; + cout << " PixelResolution = " << transMgr.InputKeyword("PixelResolution").Size() << endl; + cout << " Error messages:" << endl; + try { + transMgr.InputKeyword("BadGroup").Size(); + } + catch (Isis::iException &e) { + cerr << " "; + e.Report(false); + } + try { + transMgr.InputKeyword("GoodGroupBadKey").Size(); + } + catch (Isis::iException &e) { + cerr << " "; + e.Report(false); + } + cout << endl; + + cout << " Testing InputHasKeyword member" << endl; + cout << " BandName = " << transMgr.InputHasKeyword ("BandName") << endl; + cout << " GoodGroupBadKey = " << transMgr.InputHasKeyword ("GoodGroupBadKey") << endl; + cout << endl; + +// cout << " Testing InputHasGroup member" << endl; +// cout << " BandName = " << transMgr.InputHasGroup ("BandName") << endl; +// cout << " BadGroup = " << transMgr.InputHasGroup ("BadGroup") << endl; +// cout << endl; + + cout << " Testing Translate member" << endl; + cout << " DataFilename = " << transMgr.Translate ("DataFilename") << endl; + cout << " ImageStartByte = " << transMgr.Translate ("ImageStartByte", 1) << endl; + cout << " Lines = " << transMgr.Translate ("NumberOfLines") << endl; + cout << endl; + + cout << " Testing Auto member" << endl; + Isis::Pvl pvl; + transMgr.Auto(pvl); + cout << pvl << endl; + + + } + catch (Isis::iException &e) { + e.Report(false); + } + + return 0; +} diff --git a/isis/src/base/objs/PvlTranslationTable/Makefile b/isis/src/base/objs/PvlTranslationTable/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2f68bfde83044022ee47e0d08f21b9d566b5615f --- /dev/null +++ b/isis/src/base/objs/PvlTranslationTable/Makefile @@ -0,0 +1,5 @@ +INCS = PvlTranslationTable.h +SRCS = PvlTranslationTable.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.cpp b/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50fdb1a103d61f766e5062729d3335781c192a0b --- /dev/null +++ b/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.cpp @@ -0,0 +1,437 @@ +/** + * @file + * $Revision: 1.12 $ + * $Date: 2010/01/04 17:58:51 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "iString.h" +#include "iException.h" +#include "iException.h" +#include "Message.h" +#include "Pvl.h" +#include "PvlTranslationTable.h" + +using namespace std; +namespace Isis { + + /** + * Constructs and initializes a PvlTranslationTable object + * + * @param transFile The translation file to be used + * + * @throws iException::Io + */ + PvlTranslationTable::PvlTranslationTable (Isis::Filename transFile) { + AddTable(transFile.Expanded()); + } + + /** + * Constructs and initializes a PvlTranslationTable object + * + * @param istr The translation stream to be used to translate values + */ + PvlTranslationTable::PvlTranslationTable (std::istream &istr) { + istr >> p_trnsTbl; + } + + //! Construct an empty PvlTranslationTable + PvlTranslationTable::PvlTranslationTable () { + } + + /** + * Adds the contents of a translation table to the searchable groups/keys + * + * @param transFile The name of the translation file to be added. + * + * @throws iException::Io + */ + void PvlTranslationTable::AddTable (const std::string &transFile) { + p_trnsTbl.Read(Filename(transFile).Expanded()); + } + + /** + * Adds the contents of a translation table to the searchable groups/keys + * Also performs a verification, to ensure that the translation table + * is valid + * + * @param transStm The stream to be added. + */ + void PvlTranslationTable::AddTable (std::istream &transStm) { + transStm >> p_trnsTbl; + + for (int i=0; i < p_trnsTbl.Groups(); i++) { + PvlGroup currGrp = p_trnsTbl.Group(i); + + if (!currGrp.HasKeyword("InputKey")) { + string message = "Unable to find InputKey for group [" + + currGrp.Name() + "] in file [" + + p_trnsTbl.Filename() + "]"; + throw iException::Message(iException::User, message, _FILEINFO_); + } + + // pair< name, size > of acceptable keywords. + // A size of -1 means non-zero size. + vector< pair > validKeywords; + + validKeywords.push_back( pair("Translation", 2) ); + validKeywords.push_back( pair("OutputName", 1) ); + validKeywords.push_back( pair("InputGroup", -1) ); + validKeywords.push_back( pair("InputPosition", -1) ); + validKeywords.push_back( pair("OutputPosition", -1) ); + validKeywords.push_back( pair("Auto", 0) ); + validKeywords.push_back( pair("Optional", 0) ); + validKeywords.push_back( pair("InputKey", 1) ); + validKeywords.push_back( pair("InputDefault", -1) ); + + for (int j=0; j 0 + if(validKeywords[key].second == -1) { + if(currKey.Size() > 0) { + validKeyword = true; + } + } + // otherwise should exact match + else if(currKey.Size() == validKeywords[key].second) { + validKeyword = true; + } + else { + keywordSizeMismatch = true; + } + } + + } + + // if we had an error report it + if(!validKeyword) { + if(!keywordSizeMismatch) { + string message = "Keyword [" + currKey.Name(); + message += "] is not a valid keyword."; + message += " Error in file [" + p_trnsTbl.Filename() +"]" ; + + throw iException::Message(iException::User, + message, + _FILEINFO_); + } + else { + string message = "Keyword [" + currKey.Name(); + message += "] does not have the correct number of elements."; + message += " Error in file [" + p_trnsTbl.Filename() +"]" ; + + throw iException::Message(iException::User, + message, + _FILEINFO_); + } + + } + } + } + } + + /** + * Translates the output name and input value. + * + * @param nName The output name to be used to search the translation table. + * + * @param fValue The input value to be translated + * + * @return string The translated string + * + * @throws iException::Programmer + */ + string PvlTranslationTable::Translate (const std::string nName, + const std::string fValue) const { + if (!p_trnsTbl.HasGroup(nName)) { + string msg = "Unable to find translation group [" + + nName + "] in file [" + p_trnsTbl.Filename() + "]"; + + throw iException::Message(iException::Programmer, + msg, + _FILEINFO_); + } + + const PvlGroup &tgrp = p_trnsTbl.FindGroup(nName); + + // If no input value was passed in search using the input default + string tmpFValue = fValue; + if (tmpFValue.empty()) { + if (tgrp.HasKeyword("InputDefault")) { + tmpFValue = (string) tgrp["InputDefault"]; + } + else { + string msg = "No value or default value to translate for "; + msg += "translation group ["; + msg += nName; + msg += "] in file [" + p_trnsTbl.Filename() + "]"; + throw iException::Message(iException::Programmer, + msg, + _FILEINFO_); + } + } + + // Search the Translation keywords for a match to the input value + Pvl::ConstPvlKeywordIterator it = tgrp.FindKeyword("Translation", + tgrp.Begin(), + tgrp.End()); + + while (it != tgrp.End()) { + const PvlKeyword &key = *it; + if ((string) key[1] == tmpFValue) { + return key[0]; + } + else if ((string) key[1] == "*") { + if ((string) key[0] == "*") { + return tmpFValue; + } + else { + return key[0]; + } + } + + it = tgrp.FindKeyword("Translation",it+1,tgrp.End()); + } + + string msg = "Unable to find a translation value for [" + + nName + ", " + Isis::iString(fValue) + "] in file [" + + p_trnsTbl.Filename() + "]"; + + throw iException::Message(iException::Programmer, + msg, + _FILEINFO_); + } + + /** + * Returns the input group name from the translation table corresponding to + * the output name argument. + * + * @param nName The output name to be used to search the translation table. + * @param inst The occurence number of the "InputGroup" keyword + * (first one is zero) + * + * @return string The input group name + * + * @throws iException::Programmer + */ + PvlKeyword PvlTranslationTable::InputGroup (const std::string nName, + const int inst) const { + + if (!p_trnsTbl.HasGroup(nName)) { + string msg = "Unable to find translation group [" + + nName + "] in file [" + p_trnsTbl.Filename() + "]"; + throw iException::Message(iException::Programmer, + msg, + _FILEINFO_); + } + + const PvlGroup &transGrp = p_trnsTbl.FindGroup(nName); + + //bool foundLegalInputGroup = false; + + Pvl::ConstPvlKeywordIterator it = transGrp.FindKeyword("InputPosition", + transGrp.Begin(), + transGrp.End()); + + int currentInstance = 0; + + // If no InputGroup keywords exist, the answer is root + if(inst == 0 && it == transGrp.End()) { + PvlKeyword root("InputPosition"); + root += "ROOT"; + return root; + } + + while (it != transGrp.End()) { + const PvlKeyword &result = *it; + + // This check is to prevent backtracking to the old "value,value" way of + // doing translation file input groups for the new keyword. Flag it + // immediately to give a good error message. + if(result.Size() == 1 && result[0].find(",") != string::npos) { + iString msg = "Keyword [InputPosition] cannot have a comma [,] in "; + msg += " the value ["; + msg += result[0]; + msg += "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + else { + //foundLegalInputGroup = true; + + if(currentInstance == inst) { + return result; + } + + currentInstance ++; + } + + it = transGrp.FindKeyword("InputPosition", it+1, transGrp.End()); + } + + /* Error if no containers were listed + if(!foundLegalInputGroup) { + iString msg = "No input position found for translation ["; + msg += nName; + msg += "] in translation file ["; + msg += p_trnsTbl.Filename(); + msg += "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + }*/ + + PvlKeyword empty; + return empty; + } + + /** + * Returns the input keyword name from the translation table corresponding to + * the output name argument. + * + * @param nName The output name to be used to search the translation table. + * + * @return string The input keyword name + * + * @throws iException::Programmer + */ + string PvlTranslationTable::InputKeywordName (const std::string nName) const { + + if (!p_trnsTbl.HasGroup(nName)) { + string msg = "Unable to find translation group [" + + nName + "] in file [" + p_trnsTbl.Filename() + "]"; + throw iException::Message(iException::Programmer, + msg, + _FILEINFO_); + } + + Isis::PvlGroup tgrp = p_trnsTbl.FindGroup(nName); + if (tgrp.HasKeyword("InputKey")) return tgrp["InputKey"]; + + return ""; + } + + /** + * Returns the input default value from the translation table corresponding + * to the output name argument. + * + * @param nName The output name to be used to search the translation table. + * + * @return string The input default value + * + * @throws iException::Programmer + */ + string PvlTranslationTable::InputDefault (const std::string nName) const { + + if (!p_trnsTbl.HasGroup(nName)) { + string msg = "Unable to find translation group [" + + nName + "] in file [" + p_trnsTbl.Filename() + "]"; + throw iException::Message(iException::Programmer, + msg, + _FILEINFO_); + } + + Isis::PvlGroup tgrp = p_trnsTbl.FindGroup(nName); + if (tgrp.HasKeyword("InputDefault")) return tgrp["InputDefault"]; + + return ""; + } + + bool PvlTranslationTable::IsAuto (const std::string nName) { + if (!p_trnsTbl.HasGroup(nName)) { + string msg = "Unable to find translation group [" + nName + + "] in file [" + p_trnsTbl.Filename() + "]"; + throw iException::Message(iException::Programmer, + msg, + _FILEINFO_); + } + + Isis::PvlGroup &tgrp = p_trnsTbl.FindGroup(nName); + if (tgrp.HasKeyword("Auto")) return true; + + return false; + } + + bool PvlTranslationTable::IsOptional (const std::string nName) { + if (!p_trnsTbl.HasGroup(nName)) { + string msg = "Unable to find translation group [" + nName + + "] in file [" + p_trnsTbl.Filename() + "]"; + throw iException::Message(iException::Programmer, + msg, + _FILEINFO_); + } + + Isis::PvlGroup &tgrp = p_trnsTbl.FindGroup(nName); + if (tgrp.HasKeyword("Optional")) return true; + + return false; + } + + Isis::PvlKeyword &PvlTranslationTable::OutputPosition ( + const std::string nName) { + if (!p_trnsTbl.HasGroup(nName)) { + string msg = "Unable to find translation group [" + + nName + "] in file [" + p_trnsTbl.Filename() + "]"; + throw iException::Message(iException::Programmer, + msg, + _FILEINFO_); + } + + Isis::PvlGroup &tgrp = p_trnsTbl.FindGroup(nName); + if (!tgrp.HasKeyword("OutputPosition")) { + string msg = "Unable to find translation keyword [OutputPostion] in [" + + nName + "] in file [" + p_trnsTbl.Filename() + "]"; + throw iException::Message(iException::Programmer, + msg, + _FILEINFO_); + + } + + return tgrp["OutputPosition"]; + } + + + string PvlTranslationTable::OutputName (const std::string nName) { + if (!p_trnsTbl.HasGroup(nName)) { + string msg = "Unable to find translation group [" + nName + + "] in file [" + p_trnsTbl.Filename() + "]"; + throw iException::Message(iException::Programmer, + msg, + _FILEINFO_); + } + + Isis::PvlGroup tgrp = p_trnsTbl.FindGroup(nName); + if (tgrp.HasKeyword("OutputName")) { + return tgrp["OutputName"]; + } + + return ""; + } +} // end namespace isis + diff --git a/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.h b/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.h new file mode 100644 index 0000000000000000000000000000000000000000..613b87caa7685a5f8b1dc3ca19da0ddb94469ffd --- /dev/null +++ b/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.h @@ -0,0 +1,166 @@ +#ifndef PvlTranslationTable_h +#define PvlTranslationTable_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/01/04 17:58:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "Filename.h" +#include "Pvl.h" + +namespace Isis { +/** + * @brief Internalizes a translation table + * + * This class internalizes an Isis translation table and provides group/key + * searches and value translations. The group names listed are the output names + * used by applications to get the input names and values. There is only one + * level of groups and groups are not allowed to be nested. The Group names can + * NOT be repeated. OutputGroup is a comma delimited list of objects and/or + * groups in the input label. Traversing this list within the input label + * will lead to the correct level to find the input keyword. OutputKey is the + * keyword within the group which holds the information. OutputDefault is the + * value used if there is no value for the keyword. Translation is the output + * and corresponding input values. Translation may be repeated as needed. + * An example piece of a tranlation file: + * @code + * Group = DataStart + * OutputKey = ^IMAGE + * OutputDefault = 1 + * Translation = (*,*) + * EndGroup + * Group = DataFileRecordBytes + * OutputKey = RECORD_BYTES + * Translation = (*,*) + * EndGroup + * Group = CoreSamples + * OutputGroup = IMAGE + * OutputKey = LINE_SAMPLES + * Translation = (*,*) + * EndGroup + * Group = CorePixelType + * OutputGroup = IMAGE + * OutputKey = SAMPLE_TYPE + * OutputDefault = LSB_INTEGER + * Translation = (Integer,LSB_INTEGER) + * Translation = (Integer,MSB_INTEGER) + * Translation = (Integer,PC_INTEGER) + * Translation = (Integer,MAC_INTEGER) + * Translation = (Integer,SUN_INTEGER) + * Translation = (Integer,VAX_INTEGER) + * Translation = (Natural,UNSIGNED_INTEGER) + * Translation = (Natural,LSB_UNSIGNED_INTEGER) + * Translation = (Natural,MSB_UNSIGNED_INTEGER) + * EndGroup + * Group = CoreOrganization + * OutputGroup = IMAGE + * OutputKey = BAND_STORAGE_TYPE + * OutputDefault = BAND_SEQUENTIAL + * Translation = (BSQ,BAND_SEQUENTIAL) + * Translation = (BIL,LINE_INTERLEAVED) + * Translation = (BIP,SAMPLE_INTERLEAVED) + * EndGroup + * End + * @endcode + * + * @ingroup Parsing + * + * @author 2003-05-01 Stuart Sides + * + * @internal + * @history 2003-09-03 Stuart Sides - Modified to work with new isis label + * format + * @history 2005-02-15 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-09-08 Stuart Sides - Modified Translate member to handle + * translating any input value i.e., "*" + * to a specific output value (Thanks Kris + * Beckeer) + * + * @history 2006-08-09 Brendan George - Added IsOptional function as part of + * support for Optional keyword translations + * @history 2006-11-16 Brendan George - Changed instances of "Foreign" to "Input" + * and "Native" to "Output" + * @history 2007-06-22 Stuart Sides - Added instance parameter to InputGroup member + * @history 2006-12-05 Brendan George - Changed OutputPosition keyword to be + * case insensitive, and added + * verification to the AddTable method so + * that Translation Tables are verified + * when read in + * @history 2008-07-10 Steven Lambright - Made trnsTbl member into a + * non-pointer + * @history 2010-01-04 Steven Lambright - Now using files instead of streams + * where possible to improve errors and + * added code that checks the + * integrity of translation files. Also + * now looking for "InputPosition" keyword + * instead of "InputGroup." The InputGroup + * method (which needs renamed later) now + * returns a PvlKeyword. + * @todo 2005-02-15 Stuart Sides - add coded and implementation example to + * class documentation and finish documentation + * for protected methods and variable + */ + class PvlTranslationTable { + + public: + // Constructors + PvlTranslationTable(Isis::Filename transFile); + PvlTranslationTable(std::istream &istr); + PvlTranslationTable(); + + //! Destroys the PvlTranslationTable object. + ~PvlTranslationTable () { }; + + // Return the associated input group from the trans table + PvlKeyword InputGroup (const std::string nName, const int inst=0) const; + + // Return the associated input keyword name from the trans table + std::string InputKeywordName (const std::string nName) const; + + // Return the associated input default value from the trans table + std::string InputDefault (const std::string nName) const; + + // Translate a single input value associated with a output name to a output value + std::string Translate (const std::string nName, const std::string fValue="") const; + + // Add more table entries to the translation table data + void AddTable (std::istream &transStm); + void AddTable (const std::string &transFile); + + protected: + Pvl &TranslationTable() { return p_trnsTbl; } + const Pvl &TranslationTable() const { return p_trnsTbl; } + + bool IsAuto (const std::string nName); + bool IsOptional (const std::string nName); + PvlKeyword &OutputPosition (const std::string nName); + std::string OutputName (const std::string nName); + + private: + Pvl p_trnsTbl; + }; +}; + +#endif diff --git a/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.truth b/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.truth new file mode 100644 index 0000000000000000000000000000000000000000..3e28525c6ffd73825270756cc92c8aabe1be04ec --- /dev/null +++ b/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.truth @@ -0,0 +1,43 @@ +Unit test for Isis::PvlTranslationTable + + Test InputGroup : + InputGroup ("DataFileName") = ROOT + InputGroup ("CoreLines") = IMAGE + **PROGRAMMER ERROR** Unable to find translation group [tttt1] in file [] + + Test InputKey : + InputKeywordName ("DataFileName") = ^IMAGE + InputKeywordName ("CoreLines") = LINES + **PROGRAMMER ERROR** Unable to find translation group [tttt2] in file [] + + Test InputDefault : + InputDefault ("DataFileName") = + InputDefault ("CoreBitsPerPixel") = 8 + **PROGRAMMER ERROR** Unable to find translation group [tttt3] in file [] + + Test Translate : + Translate ("DataFilename", "tttt4") = tttt4 + Translate ("CoreByteOrder","MSB_INTEGER") = BigEndian + Translate ("CorePixelType") = Integer + Translate ("CorePixelType") = Unknown + **PROGRAMMER ERROR** Unable to find translation group [tttt6] in file [] + **PROGRAMMER ERROR** No value or default value to translate for translation group [DataFileRecordBytes] in file [] + **PROGRAMMER ERROR** Unable to find a translation value for [CoreBitsPerPixel, 31] in file [] + + Test AddTable : + Translate ("CoreLinePrefixBytes", "128") = 128 + + Test IsAuto : + IsAuto ("DataFileName") = 0 + IsAuto ("CoreBitsPerPixel") = 1 + + Test IsOptional : + IsAuto ("DataFileName") = 0 + IsAuto ("CoreBitsPerPixel") = 1 + + Test OutputPosition : + OutputPosition ("CoreBitsPerPixel") yields : OutputPosition = (Object, IsisCube, Object, Core, Group, Pixels) + + Test OutputName : + OutputName ("CoreBitsPerPixel") = BitsPerPixel + diff --git a/isis/src/base/objs/PvlTranslationTable/unitTest.cpp b/isis/src/base/objs/PvlTranslationTable/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ded960efee09a0f7cfd264c75064f6ff5679039 --- /dev/null +++ b/isis/src/base/objs/PvlTranslationTable/unitTest.cpp @@ -0,0 +1,226 @@ +#include +#include "PvlTranslationTable.h" +#include "Preference.h" +#include "iException.h" +#include "iString.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main (void) { + Preference::Preferences(true); + + try { + stringstream in; + in << "Group = DataFileName" << endl; + in << " InputPosition = ROOT" << endl; + in << " InputKey = ^IMAGE" << endl; + in << " Translation = (*,*)" << endl; + in << "EndGroup" << endl; + in << "Group = DataFileRecordBytes" << endl; + in << " InputKey = RECORD_BYTES" << endl; + in << " Translation = (*,*)" << endl; + in << "EndGroup" << endl; + in << "Group = CoreLines" << endl; + in << " InputPosition = IMAGE" << endl; + in << " InputKey = LINES" << endl; + in << " Translation = (*,*)" << endl; + in << "EndGroup" << endl; + in << "Group = CoreBitsPerPixel" << endl; + in << " Auto" << endl; + in << " OutputName = BitsPerPixel" << endl; + in << " OutputPosition = (\"Object\",\"IsisCube\", \"Object\",\"Core\","; + in << "\"Group\",\"Pixels\")" << endl; + in << " InputPosition = IMAGE" << endl; + in << " InputKey = SAMPLE_BITS" << endl; + in << " InputDefault = 8" << endl; + in << " Translation = (8,8)" << endl; + in << " Translation = (16,16)" << endl; + in << " Translation = (32,32)" << endl; + in << "EndGroup" << endl; + in << "Group = CorePixelType" << endl; + in << " InputPosition = IMAGE" << endl; + in << " InputKey = SAMPLE_TYPE" << endl; + in << " InputDefault = LSB_INTEGER" << endl; + in << " Translation = (Integer,LSB_INTEGER)" << endl; + in << " Translation = (Integer,MSB_INTEGER)" << endl; + in << " Translation = (Integer,PC_INTEGER)" << endl; + in << " Translation = (Integer,MAC_INTEGER)" << endl; + in << " Translation = (Integer,SUN_INTEGER)" << endl; + in << " Translation = (Natural,UNSIGNED_INTEGER)" << endl; + in << " Translation = (Unknown,*)" << endl; + in << "EndGroup" << endl; + in << "Group = CoreByteOrder" << endl; + in << " InputPosition = IMAGE" << endl; + in << " InputKey = SAMPLE_TYPE" << endl; + in << " InputDefault = LSB_INTEGER" << endl; + in << " Translation = (LittleEndian,LSB_INTEGER)" << endl; + in << " Translation = (BigEndian,MSB_INTEGER)" << endl; + in << " Translation = (LittleEndian,PC_INTEGER)" << endl; + in << " Translation = (BigEndian,MAC_INTEGER)" << endl; + in << " Translation = (BigEndian,SUN_INTEGER)" << endl; + in << " Translation = (LittleEndian,UNSIGNED_INTEGER)" << endl; + in << "EndGroup" << endl; + in << "End" << endl; + + PvlTranslationTable table(in); + + string group,key; + + cout << "Unit test for Isis::PvlTranslationTable" << endl << endl; + + cout << " Test InputGroup :" << endl; + + cout << " InputGroup (\"DataFileName\") = " << + table.InputGroup("DataFileName")[0] << endl; + cout << " InputGroup (\"CoreLines\") = " << + table.InputGroup("CoreLines")[0] << endl; + try { + table.InputGroup ("tttt1"); + } + catch (iException &e) { + cerr << " "; + e.Report(false); + cerr << endl; + } + + cout << " Test InputKey :" << endl; + + cout << " InputKeywordName (\"DataFileName\") = " << + table.InputKeywordName ("DataFileName") << endl; + cout << " InputKeywordName (\"CoreLines\") = " << + table.InputKeywordName ("CoreLines") << endl; + try { + table.InputKeywordName ("tttt2"); + } + catch (iException &e) { + cerr << " "; + e.Report(false); + cerr << endl; + } + + cout << " Test InputDefault :" << endl; + + cout << " InputDefault (\"DataFileName\") = " << + table.InputDefault ("DataFileName") << endl; + cout << " InputDefault (\"CoreBitsPerPixel\") = " << + table.InputDefault ("CoreBitsPerPixel") << endl; + try { + table.InputDefault ("tttt3"); + } + catch (iException &e) { + cerr << " "; + e.Report(false); + cerr << endl; + } + + cout << " Test Translate :" << endl; + + cout << " Translate (\"DataFilename\", \"tttt4\") = " << + table.Translate ("DataFilename", "tttt4") << endl; + cout << " Translate (\"CoreByteOrder\",\"MSB_INTEGER\") = " << + table.Translate ("CoreByteOrder","MSB_INTEGER") << endl; + cout << " Translate (\"CorePixelType\") = " << + table.Translate ("CorePixelType") << endl; + cout << " Translate (\"CorePixelType\") = " << + table.Translate ("CorePixelType","baddata") << endl; + try { + table.Translate ("tttt6"); + } + catch (iException &e) { + cerr << " "; + e.Report(false); + } + + try { + table.Translate ("DataFileRecordBytes"); + } + catch (iException &e) { + cerr << " "; + e.Report(false); + } + + try { + table.Translate ("CoreBitsPerPixel", "31"); + } + catch (Isis::iException &e) { + cerr << " "; + e.Report(false); + cerr << endl; + } + + cout << " Test AddTable :" << endl; + + in.clear(); + in << "Group = CoreLineSuffixBytes" << endl; + in << " InputKey = LINE_SUFFIX_BYTES" << endl; + in << " Translation = (*,*)" << endl; + in << "EndGroup" << endl; + in << "Group = CoreLinePrefixBytes" << endl; + in << " InputKey = LINE_PREFIX_BYTES" << endl; + in << " Translation = (*,*)" << endl; + in << "EndGroup" << endl; + table.AddTable(in); + + cout << " Translate (\"CoreLinePrefixBytes\", \"128\") = " << + table.Translate ("CoreLinePrefixBytes", "128") << endl << endl; + + + class protectedTester : public Isis::PvlTranslationTable { + public: + void tester () { + stringstream in2; + in2 << "Group = DataFileName" << endl; + in2 << " InputKey = ^IMAGE" << endl; + in2 << " Translation = (*,*)" << endl; + in2 << "EndGroup" << endl; + in2 << "Group = CoreBitsPerPixel" << endl; + in2 << " Auto" << endl; + in2 << " Optional" << endl; + in2 << " OutputName = BitsPerPixel" << endl; + in2 << " OutputPosition = (\"Object\",\"IsisCube\", \"Object\",\"Core\","; + in2 << "\"Group\",\"Pixels\")" << endl; + in2 << " InputGroup = IMAGE" << endl; + in2 << " InputKey = SAMPLE_BITS" << endl; + in2 << " InputDefault = 8" << endl; + in2 << " Translation = (8,8)" << endl; + in2 << " Translation = (16,16)" << endl; + in2 << " Translation = (32,32)" << endl; + in2 << "EndGroup" << endl; + in2 << "End" << endl; + + AddTable(in2); + + cout << " Test IsAuto :" << endl; + cout << " IsAuto (\"DataFileName\") = " << + IsAuto("DataFileName") << endl; + cout << " IsAuto (\"CoreBitsPerPixel\") = " << + IsAuto("CoreBitsPerPixel") << endl << endl; + + cout << " Test IsOptional :" << endl; + cout << " IsAuto (\"DataFileName\") = " << + IsOptional("DataFileName") << endl; + cout << " IsAuto (\"CoreBitsPerPixel\") = " << + IsOptional("CoreBitsPerPixel") << endl << endl; + + cout << " Test OutputPosition :" << endl; + cout << " OutputPosition (\"CoreBitsPerPixel\") yields : " << + OutputPosition("CoreBitsPerPixel") << endl << endl; + + cout << " Test OutputName :" << endl; + cout << " OutputName (\"CoreBitsPerPixel\") = " << + OutputName("CoreBitsPerPixel") << endl << endl; + + }; + }; + protectedTester t; + t.tester(); + + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/Quaternion/Makefile b/isis/src/base/objs/Quaternion/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a11ddbffbdc29f8c32b362eec492d3e8a542e246 --- /dev/null +++ b/isis/src/base/objs/Quaternion/Makefile @@ -0,0 +1,5 @@ +INCS = Quaternion.h +SRCS = Quaternion.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Quaternion/Quaternion.cpp b/isis/src/base/objs/Quaternion/Quaternion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..93ddce2cc62700acd663fd8d7207689c4e4c8a71 --- /dev/null +++ b/isis/src/base/objs/Quaternion/Quaternion.cpp @@ -0,0 +1,284 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/12/28 21:09:46 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#include + +#include +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" +#include "Quaternion.h" +#include "iException.h" + +namespace Isis { + /** + * Constructs an empty quaternion + */ + Quaternion::Quaternion () { + p_quaternion.resize(4); + + for (int i = 0; i < 4; i++) { + p_quaternion[i] = 0.; + } + } + + /** + * Construct a Quaternion class from a matrix stored as a vector < + * double > with 9 elements or from a quaternion stored as a vector + * < double > with 4 elements + * + * @param rotation rotation defined as either a matrix or another quaternion + * loaded as a vector + */ + Quaternion::Quaternion ( const std::vector rotation ) { + p_quaternion.resize(4); + Set( rotation ); + + } + + //! Destroys the Quaternion object + Quaternion::~Quaternion() {} + + /** + * Sets the quaternion value + * + * @param rotation rotation defined as either a matrix or a set of 3 angles + */ + void Quaternion::Set ( std::vector rotation ) { + + if (rotation.size () == 9) { // Matrix initialization + m2q_c ( &rotation[0], &p_quaternion[0]); + } + else if (rotation.size() == 4) { //quaternion initialization + p_quaternion = rotation; + } + else { + std::string msg = "Input vector of unexpected size for matrix or quaternion"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + } + + + //! Converts quaternion to 3x3 rotational matrix + std::vector Quaternion::ToMatrix () { + std::vector matrix(9); + q2m_c ( &p_quaternion[0], (SpiceDouble (*)[3]) &matrix[0]); + return matrix; + } + + + /** + * Assign value of quaternion class to another quaternion. For + * example, + * @code + * Quaternion q1( matrix ); + * Quaternion q2(); + * ... + * q2 = q1; + * @endcode + * + * @param quat The Quaternion to copy + * + */ + Quaternion& Quaternion::operator=(const Quaternion &quat) { + p_quaternion = quat.p_quaternion; + return *this; + } + + + /** + * Multiply current Naif quaternion by another Naif quaternion, replacing the + * current quaternion. For example, + * @code + * Quaternion q1(),q(2); + * ... + * Quaternion q2() *= q1; + * @endcode + * More information on quaternions and the multiplication algorithm is + * available in the Naif routine qxq_c. + * + * @param[in] quat (const Quaternion &) quaternion to multiply on the right + * + * @return (Quaternion) product of quaternions + * + */ + Quaternion& Quaternion::operator*=(const Quaternion &quat ) { + std::vector qout(4); + + qxq_c( (SpiceDouble *) &(this->p_quaternion[0]), + (SpiceDouble *) &(quat.p_quaternion[0]), + (SpiceDouble *) &(qout[0]) ); + this->p_quaternion[0] = qout[0]; + this->p_quaternion[1] = qout[1]; + this->p_quaternion[2] = qout[2]; + this->p_quaternion[3] = qout[3]; + return *this; + } + + + /** + * Multiply two Naif quaternions to create a new quaternion. For example, + * @code + * Quaternion q1(),q(2); + * ... + * Quaternion q3() = q1*q2; + * @endcode + * More information is available on quaternions and the multiplication + * algorithm in the Naif routine qxq_c.c + * + * @param[in] quat (const Quaternion &) quaternion to multiply on the + * right + * + * @return (Quaternion) product of quaternions + * + */ + Quaternion Quaternion::operator*(const Quaternion &quat ) const { + Isis::Quaternion qout = *this; + qout *= quat; + + return qout; + } + + + + /** + * Multiply a quaternion by a scalar. Just multiply the rotation part and + * polish the resulting quaternion so it is still a unit quaternion with + * positive rotation. For example, + * @code + * Quaternion q1(),q(2); + * double scalar + * ... + * q2() = scalar*q2; + * @endcode + * + * @param[in] scalar (const double &) scalar value to be multiplied times + * the current quaternion + * @return (Quaternion) product of scalar and quaternion + * + */ + Quaternion Quaternion::operator*(const double &scalar) { + Isis::Quaternion qout = *this; + + double scalar2 = scalar*scalar; + double unitizer = 1 + qout.p_quaternion[0]*qout.p_quaternion[0]*(scalar2 - 1); + + if (unitizer > 0. ) { + unitizer = sqrt( unitizer ); + } + else { + std::string msg = "Unable to make quaternion a unit quaternion"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + qout.p_quaternion[0] = (qout.p_quaternion[0] * scalar)/unitizer; + + for (int i = 1; i < 4; i++) { + qout.p_quaternion[i] /= unitizer; + } + Polish (qout); + + return qout; + } + + //! Returns the conjugate of the quaternion + Quaternion Quaternion::Conjugate() { + Quaternion qout; + qout.p_quaternion[0] = p_quaternion[0]; + + for ( int i = 1; i < 4; i++) { + qout.p_quaternion[i] = -p_quaternion[i]; + } + return qout; + } + + + + /** + * Multiply a vector by a quaternion (rotate the vector) + * + * @param [in] vin (const std::vector(3)) Vector to be multiplied + * (rotated) + */ + std::vector Quaternion::Qxv ( const std::vector &vin ) { + if (vin.size() != 3) { + std::string msg = "Unexpected vector size -- 3 expected"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + Quaternion qvin; + qvin.p_quaternion[0] = 0.; + qvin.p_quaternion[1] = vin[0]; + qvin.p_quaternion[2] = vin[1]; + qvin.p_quaternion[3] = vin[2]; + + Quaternion qvout(p_quaternion); + Quaternion conj(p_quaternion); + qvout *= qvin; + qvout *= conj.Conjugate(); + std::vector vout(qvout.p_quaternion.begin()+1,qvout.p_quaternion.end()); + + return vout; + } + + + /** + * Polish the quaternion -- make the first component positive + * + */ + + void Quaternion::Polish ( Quaternion &quat ) { + + if ( quat.p_quaternion[0] < 0) { + quat.p_quaternion[0] = -quat.p_quaternion[0]; + quat.p_quaternion[1] = -quat.p_quaternion[1]; + quat.p_quaternion[2] = -quat.p_quaternion[2]; + quat.p_quaternion[3] = -quat.p_quaternion[3]; + } + + } + + + + /** + * Return the camera angles (right ascension, declination, and twist) for + * the quaternion + * + */ + std::vector Quaternion::ToAngles( int axis3, int axis2, int axis1 ) { + std::vector rotationMatrix = ToMatrix (); + SpiceDouble ang1, ang2, ang3; + m2eul_c( (SpiceDouble *) &rotationMatrix[0], axis3, axis2, axis1, + &ang3, &ang2, &ang1); + std::vector angles; + angles.push_back(ang1); + angles.push_back(ang2); + angles.push_back(ang3); + return angles; + } + +} + // end namespace isis diff --git a/isis/src/base/objs/Quaternion/Quaternion.h b/isis/src/base/objs/Quaternion/Quaternion.h new file mode 100644 index 0000000000000000000000000000000000000000..a4a014025c5bc0d5bd9624711913c8c0d150af8c --- /dev/null +++ b/isis/src/base/objs/Quaternion/Quaternion.h @@ -0,0 +1,109 @@ +#ifndef Quaternion_h +#define Quaternion_h + +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/12/28 19:16:01 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" + +namespace Isis { + /** + * @brief Provide operations for quaternion arithmetic + * + * This class provides a wrapper for existing Naif quaternion functions and + * also includes other operators and methods useful for working with + * quaternions. + * + * @ingroup Rotations + * + * @author 2005-12-07 Debbie A. Cook + * + * @internal + * @history Steven Lambright Fixed documentation + * + */ + + class Quaternion { + public: + // constructors + Quaternion (); + Quaternion ( const std::vector matrix ); + + // destructor + ~Quaternion(); + + //Methods + + std::vector ToMatrix (); + + std::vector ToAngles( int axis3, int axis2, int axis1 ); + + void Set ( std::vector ); + + //! Return the quaternion as a vector + std::vector GetQuaternion() const { return p_quaternion; } + ; + Quaternion& operator=(const Quaternion &quat); + + Quaternion& operator*=(const Quaternion &quat ); + + Quaternion operator*(const Quaternion &quat ) const; + + Quaternion operator*(const double &scalar); + + /** + * Return a member of a quaternion. For example, + * @code + * Quaternion q(); + * ... + * double angle = q[0]; + * @endcode + * + * @param[in] index (const int &) quaternion member to return + * + * @return (double&) value pointed to by iter + * + */ + double& operator[]( int index) {return p_quaternion.at(index); }; + + + + std::vector Qxv ( const std::vector &vin ); + + Quaternion Conjugate(); + + + + + private: + std::vector p_quaternion; //!< Quaternion + void Polish( Quaternion &quat ); + }; +}; + +#endif + diff --git a/isis/src/base/objs/Quaternion/Quaternion.truth b/isis/src/base/objs/Quaternion/Quaternion.truth new file mode 100644 index 0000000000000000000000000000000000000000..23e36d6305b8dd711c24513e79b4b873d09ad2be --- /dev/null +++ b/isis/src/base/objs/Quaternion/Quaternion.truth @@ -0,0 +1,24 @@ + Input matrix:0.221548 -0.185065 -0.957427 + -0.975149 -0.0420457 -0.217522 + 0 0.981826 -0.189781 +Output Matrix:0.221548 -0.185065 -0.957427 + -0.975149 -0.0420457 -0.217522 + 0 0.981826 -0.189781 + Naif quaternion from matrix: 0.497424 0.60278 -0.481193 -0.397088 + Class quaternion: 0.497424 0.60278 -0.481193 -0.397088 +Output angles: -100.94 77.2 0 + Input angles: -100.94 77.2 0. +Class constructed quaternion: 0.497424 0.60278 -0.481193 -0.397088 +Empty Quaternion: 0 0 0 0 +Filled Quaternion: 0.497424 0.60278 -0.481193 -0.397088 +Naif mult : 0.070948 0.766485 0.085975 -0.632516 +Quat mult*=: 0.070948 0.766485 0.085975 -0.632516 +Quat mult: * :0.070948 0.766485 0.085975 -0.632516 +Quat scalar mult: 0.753696 0.456666 -0.364551 -0.300834 +Conjugate of above is: 0.753696 -0.456666 0.364551 0.300834 +1 1 1 +qxv output = 0.0415326 1.43014 -0.976201 +mymat = 0.553202 -0.786431 0.274761 + 0.120518 0.401911 0.907713 + -0.824283 -0.469035 0.317117 +my qxv output = 0.0415326 1.43014 -0.976201 diff --git a/isis/src/base/objs/Quaternion/unitTest.cpp b/isis/src/base/objs/Quaternion/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd329fa6c4775c1c39354412b2095623695dbece --- /dev/null +++ b/isis/src/base/objs/Quaternion/unitTest.cpp @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include + +#include "Spice.h" +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" +#include "Quaternion.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + + // Test the matrix constructor + std::vector inMat(9); + std::vector outMat(9); + + //call eul2m to make a matrix and fill the vector + eul2m_c (0, 77.2*rpd_c(), -100.94*rpd_c(), 1, 3, 1, + (SpiceDouble (*)[3]) (&inMat[0]) ); + + Isis::Quaternion q1 ( inMat ); + + outMat = q1.ToMatrix(); + + // Take care of Solaris round-off. Find a better way later. + if (abs(outMat[6]) < .000000000000001) outMat[6] = 0.; + + // compare inMat and outMat + cout << " Input matrix:"< inquat(4); + m2q_c ( (SpiceDouble *) &inMat[0], (SpiceDouble *) &inquat[0]); + cout << " Naif quaternion from matrix: "<<" "< angles = q1.ToAngles( 1, 3, 1 ); + + // Take care of Solaris round-off. Find a better way later. + if (abs(angles[2])< .000000000000001) angles[2] = 0.; + + cout << "Output angles: "< multMat(9); + + multMat[0] = 0.; + multMat[1] = 1.; + multMat[2] = 0.; + multMat[3] = -1.; + multMat[4] = 0.; + multMat[5] = 0.; + multMat[6] = 0.; + multMat[7] = 0.; + multMat[8] = 1.; + + Isis::Quaternion multQ ( multMat ); + + mxm_c ( (SpiceDouble *) &inMat[0], (SpiceDouble *) &multMat[0], + (SpiceDouble (*) [3]) &outMat[0]); + + SpiceDouble naifQ[4]; + + m2q_c ( (SpiceDouble *) &outMat[0], naifQ); + q2 *= multQ; + cout << "Naif mult : " << naifQ[0] << " " << naifQ[1] << " " << naifQ[2] << + " " << naifQ[3] << endl; + cout << "Quat mult*=: " << q2[0] << " " << q2[1] << " " << q2[2] << " " + << q2[3] << endl; + + // Test the * operator with a quaternion + Isis::Quaternion q4; + + q4 = q3 * multQ; + + cout << "Quat mult: * :" << q4[0] << " " << q4[1] << " " << q4[2] << " " + << q4[3] << endl; + + // Test the * operator with a scalar + Isis::Quaternion q5; + + q5 = q1 * 2.; + cout << "Quat scalar mult: " << q5[0] << " " << q5[1] << " " << q5[2] << " " + << q5[3] << endl; + + + // Test the conjugate method + Isis::Quaternion q6 = q5.Conjugate(); + + cout << "Conjugate of above is: " << q6[0] << " " << q6[1] << " " << q6[2] + << " " << q6[3] << endl; + + // Test the qxv method + std::vector vecIn(3); + vecIn[0] = 1.; + vecIn[1] = 1.; + vecIn[2] = 1.; + + cout << vecIn[0] << " " << vecIn[1] << " " << vecIn[2] << endl; + + std::vector vecOut = q6.Qxv(vecIn); + + cout << "qxv output = " << vecOut[0] << " " << vecOut[1] << " " << vecOut[2] + << endl; + + std::vector mymat = q6.ToMatrix(); + + cout << "mymat = " << mymat[0] << " " << mymat[1] << " " << mymat[2] << endl + << " " << mymat[3] << " " << mymat[4] << " " << mymat[5] << endl + << " " << mymat[6] << " " << mymat[7] << " " << mymat[8] << endl; + + SpiceDouble myVecOut[3]; + mxv_c ( (SpiceDouble *) &mymat[0], (SpiceDouble *) &vecIn[0], myVecOut); + + cout << "my qxv output = " << myVecOut[0] << " " << myVecOut[1] << " " + << myVecOut[2] << endl; +} diff --git a/isis/src/base/objs/QuickFilter/Makefile b/isis/src/base/objs/QuickFilter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..992364db20968c8679e11b9ff7539de128143525 --- /dev/null +++ b/isis/src/base/objs/QuickFilter/Makefile @@ -0,0 +1,5 @@ +INCS = QuickFilter.h +SRCS = QuickFilter.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/QuickFilter/QuickFilter.cpp b/isis/src/base/objs/QuickFilter/QuickFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc36fe38c4aa8c74044daf9981e539e11efd99ca --- /dev/null +++ b/isis/src/base/objs/QuickFilter/QuickFilter.cpp @@ -0,0 +1,416 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:09 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "QuickFilter.h" +#include "iException.h" +#include + +using namespace std; +namespace Isis { + + /** + * Constructs a QuickFilter object with accumulators and counters set to zero. + * Because this is a line based filtering object, the number of samples and the + * boxcar size must be given to the constructor. + * + * @param ns Number of samples in the cube + * + * @param width Width of the boxcar (must be odd) + * + * @param height Height of the boxcar (must be odd) + * + * @throws Isis::iException::Programmer + */ + QuickFilter::QuickFilter (const int ns, const int width, + const int height) { + // Error checks + if (ns <= 0) { + string msg = "Invalid value for [ns] in QuickFilter constructor"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (width < 1) { + string m="[Width] must be must be greater than or equal to one in "; + m += "QuickFilter constructor"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + else if ((width % 2) == 0) { + string m="[Width] must be must be odd in "; + m += "QuickFilter constructor"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + if (height < 1) { + string m="[Height] must be must be greater than or equal to one in "; + m += "QuickFilter constructor"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + else if ((height % 2) == 0) { + string m="[Height] must be must be odd in "; + m += "QuickFilter constructor"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Create buffers + p_sums = new double[ns]; + p_sumsqrs = new double[ns]; + p_counts = new int[ns]; + p_ns = ns; + + // Set defaults for min/max and valid pixels + p_minimum = -DBL_MAX; + p_maximum = DBL_MAX; + p_minimumPixels = 0; + + // Set the boxcar size and compute half the size + p_width = width; + p_halfWidth = width / 2; + + p_height = height; + p_halfHeight = height / 2; + + Reset(); + } + + //! Reset all accumulators and counters to zero. + void QuickFilter::Reset() { + // Initialize buffers + for (int i=0; i= maximum) { + string m="Minimum must be less than maximum in [QuickFilter::SetMinMax]"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + p_minimum = minimum; + p_maximum = maximum; + p_lastIndex = -100; + } + + /** + * This method is used to set the minimum number of valid pixels in the boxcar. + * If the minimum requirement can not be satisfied then the Average and + * Variance methods will return Isis:NULL8. The default value is zero. + * + * @param pixels Number of minimum valid pixels for statistically + * computations to occur + * + * @throws Isis::iException::Programmer + */ + void QuickFilter::SetMinimumPixels (const int pixels) { + if (pixels < 0) { + string m="Pixels must be greater than or equal to zero in "; + m += "[QuickFilter::SetMinimumPixels]"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + p_minimumPixels = pixels; + if (p_minimumPixels > p_width * p_height) { + p_minimumPixels = p_width * p_height; + } + } + + /** + * Add an array of doubles to the accumulators and counters. This method must + * be invoked enough times to satisfy the height requirements of the boxcar. + * Note, however this is not strictly enforced. The method will check to make + * sure you have not added beyond the height of the boxcar. Therefore, you must + * remove a line before adding a new one. + * + * @param buf Array of doubles to add + * + * @throws Isis::iException::Programmer + */ + void QuickFilter::AddLine (const double *buf) { + // Check for adding too many lines + p_linesAdded++; + if (p_linesAdded > p_height) { + string m = "Number of lines added exceeds boxcar height ... "; + m+= "use RemoveLine before AddLine"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + for (int i=0; i p_maximum) continue; + p_sums[i] += buf[i]; + p_sumsqrs[i] += buf[i]*buf[i]; + p_counts[i]++; + p_lastIndex = -100; + } + } + } + + /** + * Remove an array of doubles from the accumulators and counters. + * + * @param buf Pointer to array of doubles to remove + */ + void QuickFilter::RemoveLine (const double *buf) { + for (int i=0; i p_maximum) continue; + p_sums[i] -= buf[i]; + p_sumsqrs[i] -= buf[i]*buf[i]; + p_counts[i]--; + p_lastIndex = -100; + } + } + p_linesAdded--; + } + + /** + * Computes and returns the boxcar average at pixel index (zero based). No + * error checks are done for out of array bounds conditions. If there are not + * enough valid pixels in the boxcar then Isis::NULL8 is returned. The routine + * works the fastest when sequentially accessing the averages + * (e.g., index = 0,1,2,...). + * + * @param index Zero based sample position + * + * @return double + */ + double QuickFilter::Average (const int index) { + // Move the boxcar if necessary + Compute (index); + + // Return NULL8 if we have invalid conditions + if (p_lastCount < p_minimumPixels) return Isis::NULL8; + if (p_lastCount <= 0) return Isis::NULL8; + + // Return the average + return p_lastSum / (double) p_lastCount; + } + + /** + * Computes and returns the boxcar variance at pixel index (zero based). No + * error checks are done for out of array bounds conditions. If there are not + * enough valid pixels in the boxcar then Isis::NULL8 is returned. The routine + * works the fastest when sequentially accessing the variances + * (e.g., index = 0,1,2,...). + * + * @param index Zero based sample position + * + * @return double + */ + double QuickFilter::Variance (const int index) { + // Move the boxcar if necessary + Compute(index); + + // Return NULL8 if we have invalid conditions + if (p_lastCount < p_minimumPixels) return Isis::NULL8; + if (p_lastCount <= 1) return Isis::NULL8; + + // Return the variance + double temp = p_lastCount * p_lastSumsqr - p_lastSum * p_lastSum; + if (temp < 0.0) temp = 0.0; // This shouldn't happen unless roundoff occurs + return temp / ((double) (p_lastCount - 1) * (double) p_lastCount); + } + + /** + * Computes and returns the number of valid pixels in the boxcar at pixel index + * (zero based). No error checks are done for out of array bounds conditions. + * The routine works the fastest when sequentially accessing the counts + * (e.g., index = 0,1,2,...). + * + * @param index Zero based sample position + * + * @return double + */ + int QuickFilter::Count(const int index) { + // Move the boxcar if necessary + Compute(index); + + // Return the valid count + return p_lastCount; + } + + /** + * Returns the width of the boxcar + * + * @return int + */ + int QuickFilter::Width() const { + return p_width; + } + + /** + * Returns the half the width of the boxcar rounded down because the boxcar + * size is odd. + * + * @return int + */ + int QuickFilter::HalfWidth() const { + return p_halfWidth; + } + + /** + * Returns the height of the boxcar + * + * @return int + */ + int QuickFilter::Height() const { + return p_height; + } + + /** + * Returns the half the height of the boxcar rounded down because the boxcar + * size is odd. + * + * @return int + */ + int QuickFilter::HalfHeight() const { + return p_halfHeight; + } + + /** + * Returns the number of samples in a line + * + * @return int + */ + int QuickFilter::Samples() const { + return p_ns; + } + + /** + * Returns the lowest pixel value included in filtering computations + * + * @return double + */ + double QuickFilter::Low() const { + return p_minimum; + } + + /** + * Returns the highest pixel value included in filtering computations + * + * @return double + */ + double QuickFilter::High() const { + return p_maximum; + } + + /** + * Returns the minimum number of pixels which need to be valid inside the + * boxcar. If there are not enough valid pixels then invoking Average and + * Variance methods will result in a NULL output. + * + * @return int + */ + int QuickFilter::MinimumPixels () const { + return p_minimumPixels; + } + + /** + * Computes the moving boxcar sums and counts for the Average, Variance, and + * count methods. No error checks are done for out of array bounds conditions. + * The routine works the fastest when sequentially accessing the averages + * (e.g., index = 0,1,2,...). + * + * @param index Zero based sample position + */ + void QuickFilter::Compute (const int index) { + // If the index hasn't changed just return + if (index == p_lastIndex) return; + + // Determine start and stop indeces + int start = index - p_halfWidth; + int stop = index + p_halfWidth; + + // See if the index has increased by one + if (index == p_lastIndex + 1) { + // Remove one column + start--; + if (start < 0) start = -1 * start; + p_lastSum -= p_sums[start]; + p_lastSumsqr -= p_sumsqrs[start]; + p_lastCount -= p_counts[start]; + + // Add another column + if (stop >= p_ns) stop = p_ns - (stop - p_ns + 2); + p_lastSum += p_sums[stop]; + p_lastSumsqr += p_sumsqrs[stop]; + p_lastCount += p_counts[stop]; + } + + // Recompute everything + else { + p_lastSum = 0.0; + p_lastCount = 0; + p_lastSumsqr = 0.0; + int j; + for (int i=start; i<=stop; i++) { + j = i; + if (i < 0) { + j = -1 * i; + } + else if (i >= p_ns) { + j = p_ns - (i - p_ns + 2); + } + + p_lastSum += p_sums[j]; + p_lastSumsqr += p_sumsqrs[j]; + p_lastCount += p_counts[j]; + } + } + + // Save the current index + p_lastIndex = index; + } +} // end namespace isis diff --git a/isis/src/base/objs/QuickFilter/QuickFilter.h b/isis/src/base/objs/QuickFilter/QuickFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..d1909e1cb26d21191371a858dd17ed4b3b62ba4b --- /dev/null +++ b/isis/src/base/objs/QuickFilter/QuickFilter.h @@ -0,0 +1,199 @@ +#ifndef QuickFilter_h +#define QuickFilter_h +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:09 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "SpecialPixel.h" + +namespace Isis { +/** + * @brief Container for boxcar statistics + * + * This class is used to compute statisics for NxM boxcars, where N and M are + * positive odd integers. In general, this object will be loaded by another + * derived class such as FilterLoader or FilterProcess. The programmer can then + * use the methods in this class to compute statistics such as the boxcar + * average, variance, and number of valid pixels in the boxcar. + * + * If you would like to see QuickFilter being used in implementation, + * see FilterLoader or FilterProcess + * + * @ingroup Statistics + * + * @author 2002-06-20 Jeff Anderson + * + * @internal + * @history 2002-07-10 Jeff Anderson - Added the Compute private method and + * made it unfold data at the edges as + * opposed to using NULL values. + * @history 2002-07-15 Jeff Anderson - Added Low and High methods + * @history 2002-08-01 Jeff Anderson - Added MinimumPixels method + * @history 2003-02-14 Jeff Anderson - Changed unfolding technique to use + * symmetry as opposed to mirroring + * (i.e., 32123 not 21123) + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-08-27 Jeff Anderson - Modified variance method to divide by + * (n-1)*n instead of n*n + * @history 2005-02-15 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * + * @todo 2005-02-15 Jeff Anderson - add coded example to class documentation + * @todo 2005-05-23 Jeff Anderson - Unlikely but we may have issues with 2GB+ + * cubes. It's unlikely because the boxcar size would + * have to have more than 2^32-1 pixels. + */ + + class QuickFilter { + private: + double *p_sums; /**< Sum accumulator for each column/sample. This array + is allocated to the size of p_ns. For each column + in the cube, this array will contain the sum of M + lines at the particular sample position. For + example, if M=3 and we had loaded lines 3,4,5 + using AddLine then + p_sum[0] = cube(1,3) + cube(1,4) + cube(1,5), + where cube(sample,line) is the value at the + position in the cube. The sums are used to + compute the average.*/ + double *p_sumsqrs; /**< This is identical to p_sums with the exception + that the pixel values are squared before summing + occurs. This of course is needed to compute the + variance.*/ + int *p_counts; /**< This is identical to p_sums with the exception + that it keeps count of the number of valid pixels + in p_sums and p_sumsqrs. A valid pixel is + considered to be not special (NULL, LIS, HIS, etc) + and within the range of p_minimum and p_maximum. + Therefore, p_counts[i] for any i is a number + between 0 and M (number of lines in the boxcar) + depending on the number of valid pixels.*/ + int p_ns; /**< This value is initialized in the constructor. It + is set using the value passed into the constructor. + It represents the number of samples across the + image. It will be used to allocate internal + buffers.*/ + + double p_minimum; /**< Minimum valid pixel value. It is set to DBL_MIN + in the constructor and can be changed using the + protected method SetMinMax. It is used to + evaluate input pixels to determine if they are + valid. A pixel will be accumulated in p_sums, + p_sumsqrs, and p_counts, if it is within the + range of p_minimum and p_maximum.*/ + double p_maximum; /**< Maximum valid pixel value. It is set to DBL_MAX + in the constructor and can be changed using the + protected method SetMinMax. It is used to + evaluate input pixels to determine if they are + valid. A pixel will be accumulated in p_sums, + p_sumsqrs, and p_counts, if it is within the + range of p_minimum and p_maximum.*/ + int p_minimumPixels; /**< The minimum number of pixels in the boxcar which + must be valid (not special and inside + p_minimum/p_maximum) in order for Average and + Variance to compute a value. If there are not + enough valid pixels then those methods will + return Isis::NULL8;*/ + int p_width; /**< This is the width of the boxcar. It is set in + the constructor using a parameter passed into + the constructor. It must be positive and odd and + is used in the Average, Variance, and Count + methods.*/ + int p_halfWidth; /**< This is half the width of the boxcar rounded + down to the next integer since the boxcar is + always odd. For example, p_width=5 implies + p_halfWidth=2 (5/2 = 2.5 = 2). It is used for + internal computations within Average, Variance, + and Count methods.*/ + int p_height; /**< This is the height of the boxcar. It is set in + the constructor using a parameter passed into + the constructor. It must be positive and odd and + is used in the Average, Variance, and Count + methods.*/ + int p_halfHeight; /**< This is half the height of the boxcar rounded + down to the next integer since the boxcar is + always odd. For example, p_height=5 implies + p_halfHeight=2 (5/2 = 2.5 = 2). It is used for + internal computations within Average, Variance, + and Count methods.*/ + + double p_lastSum; /**< The last sum of a full boxcar. That is using + the width of the boxcar (assume 3) + p_lastSum = p_sums[0] + p_sums[1] + p_sums[2] + at sample 2. At sample 3, + p_lastSum = p_sums[1] + p_sums[2] + p_sums[3]. + If the programmer makes ordered calls to the + Average, Variance, and/or Count methods we can + speed those routines. For example, + p_lastSum += p_sums[4] - p_sums[1] would be + correct for sample 4. This will make a + significant difference in speed if p_width is + large.*/ + double p_lastSumsqr; //!< See p_lastSum. + int p_lastCount; //!< See p_lastSum. + int p_lastIndex; /**< This is used to keep track of the last index + passed into the Average, Variance and/or count + method. If the index is the same as p_lastIndex + then computations are trival. If the index has + increased by one then the next accumulator will + be added and the first accumulator will be + removed from p_lastSum, p_lastSumsqr,and + p_latCount. This speed processing. Others the + entire boxcar needs to be recomputed. This + generally happens when a new line is added or + the programmer bounces around with the index.*/ + int p_linesAdded; /**< This is used to keep track of the number of + lines added. If the programmer adds more lines + than the height of the boxcar, an error will be + thrown.*/ + + void Compute (const int index); + + public: + QuickFilter (const int ns, const int width, const int height); + ~QuickFilter (); + + double Average (const int index); + double Variance (const int index); + int Count (const int index); + + int Width () const; + int HalfWidth () const; + int Height () const; + int HalfHeight () const; + int Samples() const; + + double Low() const; + double High() const; + int MinimumPixels () const; + + void AddLine (const double *buf); + void RemoveLine (const double *buf); + void Reset (); + + void SetMinMax (const double minimum, const double maximum); + void SetMinimumPixels (const int minimumValid); + + }; +}; + +#endif diff --git a/isis/src/base/objs/QuickFilter/QuickFilter.truth b/isis/src/base/objs/QuickFilter/QuickFilter.truth new file mode 100644 index 0000000000000000000000000000000000000000..55a171e0fabca6ad0b30a470a56b3aef260a78f3 --- /dev/null +++ b/isis/src/base/objs/QuickFilter/QuickFilter.truth @@ -0,0 +1,79 @@ +Unit Test for QuickFilter Object +-------------------------------- +Constructing f +Adding Line 1 +Adding Line 2 +Adding Line 3 +Adding Line 4 +Adding Line 5 + +Boxcar Width: 3 +Boxcar Height: 5 +Half Boxcar Width: 1 +Half Boxcar Height: 2 +Samples in Line: 4 + +Average[0]: 1.66667 +Average[1]: 2 +Average[2]: 2.5 +Average[3]: 3 +Variance[0]: 0.238095 +Variance[1]: 0.714286 +Variance[2]: 0.277778 +Variance[3]: 0 +Count[0]: 15 +Count[1]: 15 +Count[2]: 10 +Count[3]: 10 + +Changing Valid Count +Average[0]: 1.66667 +Average[1]: 2 +Average[2]: -1.79769e+308 +Average[3]: -1.79769e+308 +Variance[0]: 0.238095 +Variance[1]: 0.714286 +Variance[2]: -1.79769e+308 +Variance[3]: -1.79769e+308 +Count[0]: 15 +Count[1]: 15 +Count[2]: 10 +Count[3]: 10 + +Unloading data +Average[0]: -1.79769e+308 +Average[1]: -1.79769e+308 +Average[2]: -1.79769e+308 +Average[3]: -1.79769e+308 +Variance[0]: -1.79769e+308 +Variance[1]: -1.79769e+308 +Variance[2]: -1.79769e+308 +Variance[3]: -1.79769e+308 +Count[0]: 0 +Count[1]: 0 +Count[2]: 0 +Count[3]: 0 + +Changing Valid Range +Average[0]: 1.66667 +Average[1]: 1.5 +Average[2]: 2 +Average[3]: -1.79769e+308 +Variance[0]: 0.238095 +Variance[1]: 0.277778 +Variance[2]: 0 +Variance[3]: -1.79769e+308 +Count[0]: 15 +Count[1]: 10 +Count[2]: 5 +Count[3]: 0 + +Testing errors +**PROGRAMMER ERROR** Invalid value for [ns] in QuickFilter constructor +**PROGRAMMER ERROR** [Width] must be must be greater than or equal to one in QuickFilter constructor +**PROGRAMMER ERROR** [Height] must be must be greater than or equal to one in QuickFilter constructor +**PROGRAMMER ERROR** [Width] must be must be odd in QuickFilter constructor +**PROGRAMMER ERROR** [Height] must be must be odd in QuickFilter constructor +**PROGRAMMER ERROR** Minimum must be less than maximum in [QuickFilter::SetMinMax] +**PROGRAMMER ERROR** Minimum must be less than maximum in [QuickFilter::SetMinMax] +**PROGRAMMER ERROR** Number of lines added exceeds boxcar height ... use RemoveLine before AddLine diff --git a/isis/src/base/objs/QuickFilter/unitTest.cpp b/isis/src/base/objs/QuickFilter/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b999b9241c673482daf60d6b9d981c80f2e41f1 --- /dev/null +++ b/isis/src/base/objs/QuickFilter/unitTest.cpp @@ -0,0 +1,219 @@ +#include +#include "QuickFilter.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +class IsisFilterFEL : public Isis::QuickFilter { + public: + IsisFilterFEL (const int ns, const int width, const int height) : + Isis::QuickFilter (ns,width,height) { + } + + void AddLine (const double *buf) { + Isis::QuickFilter::AddLine(buf); + } + + void RemoveLine (const double *buf) { + Isis::QuickFilter::RemoveLine(buf); + } + + void SetMinMax (const double min, const double max) { + Isis::QuickFilter::SetMinMax(min,max); + } + + void SetMinimumPixels (const int min) { + Isis::QuickFilter::SetMinimumPixels(min); + } +}; + +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for QuickFilter Object" << endl; + cout << "--------------------------------" << endl; + + cout << "Constructing f" << endl; + IsisFilterFEL f(4,3,5); + + double a[4]; + a[0] = 1.0; + a[1] = 2.0; + a[2] = 3.0; + + cout << "Adding Line 1" << endl; + a[3] = Isis::NULL8; + f.AddLine(a); + + cout << "Adding Line 2" << endl; + a[3] = Isis::LOW_REPR_SAT8; + f.AddLine(a); + + cout << "Adding Line 3" << endl; + a[3] = Isis::HIGH_REPR_SAT8; + f.AddLine(a); + + cout << "Adding Line 4" << endl; + a[3] = Isis::LOW_INSTR_SAT8; + f.AddLine(a); + + cout << "Adding Line 5" << endl; + a[3] = Isis::HIGH_INSTR_SAT8; + f.AddLine(a); + cout << endl; + + cout << "Boxcar Width: " << f.Width() << endl; + cout << "Boxcar Height: " << f.Height() << endl; + cout << "Half Boxcar Width: " << f.HalfWidth() << endl; + cout << "Half Boxcar Height: " << f.HalfHeight() << endl; + cout << "Samples in Line: " << f.Samples() << endl; + cout << endl; + + cout << "Average[0]: " << f.Average(0) << endl; + cout << "Average[1]: " << f.Average(1) << endl; + cout << "Average[2]: " << f.Average(2) << endl; + cout << "Average[3]: " << f.Average(3) << endl; + cout << "Variance[0]: " << f.Variance(0) << endl; + cout << "Variance[1]: " << f.Variance(1) << endl; + cout << "Variance[2]: " << f.Variance(2) << endl; + cout << "Variance[3]: " << f.Variance(3) << endl; + cout << "Count[0]: " << f.Count(0) << endl; + cout << "Count[1]: " << f.Count(1) << endl; + cout << "Count[2]: " << f.Count(2) << endl; + cout << "Count[3]: " << f.Count(3) << endl; + cout << endl; + + cout << "Changing Valid Count" << endl; + f.SetMinimumPixels(11); + cout << "Average[0]: " << f.Average(0) << endl; + cout << "Average[1]: " << f.Average(1) << endl; + cout << "Average[2]: " << f.Average(2) << endl; + cout << "Average[3]: " << f.Average(3) << endl; + cout << "Variance[0]: " << f.Variance(0) << endl; + cout << "Variance[1]: " << f.Variance(1) << endl; + cout << "Variance[2]: " << f.Variance(2) << endl; + cout << "Variance[3]: " << f.Variance(3) << endl; + cout << "Count[0]: " << f.Count(0) << endl; + cout << "Count[1]: " << f.Count(1) << endl; + cout << "Count[2]: " << f.Count(2) << endl; + cout << "Count[3]: " << f.Count(3) << endl; + cout << endl; + + cout << "Unloading data" << endl; + f.RemoveLine(a); + f.RemoveLine(a); + f.RemoveLine(a); + f.RemoveLine(a); + f.RemoveLine(a); + cout << "Average[0]: " << f.Average(0) << endl; + cout << "Average[1]: " << f.Average(1) << endl; + cout << "Average[2]: " << f.Average(2) << endl; + cout << "Average[3]: " << f.Average(3) << endl; + cout << "Variance[0]: " << f.Variance(0) << endl; + cout << "Variance[1]: " << f.Variance(1) << endl; + cout << "Variance[2]: " << f.Variance(2) << endl; + cout << "Variance[3]: " << f.Variance(3) << endl; + cout << "Count[0]: " << f.Count(0) << endl; + cout << "Count[1]: " << f.Count(1) << endl; + cout << "Count[2]: " << f.Count(2) << endl; + cout << "Count[3]: " << f.Count(3) << endl; + cout << endl; + + cout << "Changing Valid Range" << endl; + f.SetMinMax (1.0,2.0); + f.SetMinimumPixels(1); + f.AddLine(a); + f.AddLine(a); + f.AddLine(a); + f.AddLine(a); + f.AddLine(a); + cout << "Average[0]: " << f.Average(0) << endl; + cout << "Average[1]: " << f.Average(1) << endl; + cout << "Average[2]: " << f.Average(2) << endl; + cout << "Average[3]: " << f.Average(3) << endl; + cout << "Variance[0]: " << f.Variance(0) << endl; + cout << "Variance[1]: " << f.Variance(1) << endl; + cout << "Variance[2]: " << f.Variance(2) << endl; + cout << "Variance[3]: " << f.Variance(3) << endl; + cout << "Count[0]: " << f.Count(0) << endl; + cout << "Count[1]: " << f.Count(1) << endl; + cout << "Count[2]: " << f.Count(2) << endl; + cout << "Count[3]: " << f.Count(3) << endl; + cout << endl; + + + cout << "Testing errors" << endl; + // Band number of samples in line + try { + Isis::QuickFilter f2(0,3,3); + } + catch (Isis::iException &e) { + e.Report (false); + } + + // Bad boxcar width + try { + Isis::QuickFilter f2(5,0,3); + } + catch (Isis::iException &e) { + e.Report (false); + } + + // Bad boxcar height + try { + Isis::QuickFilter f2(5,3,0); + } + catch (Isis::iException &e) { + e.Report (false); + } + + // Width not odd + try { + Isis::QuickFilter f2(5,2,3); + } + catch (Isis::iException &e) { + e.Report (false); + } + + // Height not odd + try { + Isis::QuickFilter f2(5,3,2); + } + catch (Isis::iException &e) { + e.Report (false); + } + + // Minimum = maximum + try { + f.SetMinMax(1.0,1.0); + } + catch (Isis::iException &e) { + e.Report (false); + } + + // Minimum > maximum + try { + f.SetMinMax(2.0,1.0); + } + catch (Isis::iException &e) { + e.Report (false); + } + + // Bad number of valid points + try { + f.SetMinimumPixels(0); + } + catch (Isis::iException &e) { + e.Report (false); + } + + // Add too much data + try { + f.AddLine(a); + } + catch (Isis::iException &e) { + e.Report (false); + } +} diff --git a/isis/src/base/objs/RadarCamera/Makefile b/isis/src/base/objs/RadarCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a02cd0d2b6d3167c5ddc2c2f70d51091f3f61381 --- /dev/null +++ b/isis/src/base/objs/RadarCamera/Makefile @@ -0,0 +1,5 @@ +INCS = RadarCamera.h +SRCS = RadarCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/RadarCamera/RadarCamera.cpp b/isis/src/base/objs/RadarCamera/RadarCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..02284f9719f65cdb43e9c822f99d2c0b942f2514 --- /dev/null +++ b/isis/src/base/objs/RadarCamera/RadarCamera.cpp @@ -0,0 +1,35 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/08/31 15:11:49 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "RadarCamera.h" + +namespace Isis { + /** + * Constructs the RadarCamera object + * + * @param lab Pvl label used to create the parent Camera object + */ + RadarCamera::RadarCamera (Isis::Pvl &lab) : Camera (lab) { + } +}; + diff --git a/isis/src/base/objs/RadarCamera/RadarCamera.h b/isis/src/base/objs/RadarCamera/RadarCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..85e57063a1f40b73cf863efab9397b3e50aa5ce8 --- /dev/null +++ b/isis/src/base/objs/RadarCamera/RadarCamera.h @@ -0,0 +1,55 @@ +#ifndef RadarCamera_h +#define RadarCamera_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/08/31 15:11:49 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Camera.h" + +namespace Isis { +/** + * @brief Generic class for Radar Cameras + * + * This class is used to abstract out radar camera functionality from children + * classes. + * + * @author 2009-08-26 Steven Lambright + * + * @internal + * @todo Implement more functionality in this class and abstract away from the children + */ + + class RadarCamera : public Camera { + public: + RadarCamera(Isis::Pvl &lab); + + virtual CameraType GetCameraType() const { return Radar; } + + private: + //! Copying cameras is not allowed + RadarCamera(const RadarCamera &); + //! Assigning cameras is not allowed + RadarCamera &operator=(const RadarCamera&); + }; +}; + +#endif diff --git a/isis/src/base/objs/RadarCamera/RadarCamera.truth b/isis/src/base/objs/RadarCamera/RadarCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..0170f43180265ca2e721755972a76c51e8179d4b --- /dev/null +++ b/isis/src/base/objs/RadarCamera/RadarCamera.truth @@ -0,0 +1,4 @@ +Camera = Framing? 0 +Camera = LineScan? 0 +Camera = PushFrame? 0 +Camera = Radar? 1 diff --git a/isis/src/base/objs/RadarCamera/unitTest.cpp b/isis/src/base/objs/RadarCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c45234d377ac4804710037f2244a690a3d435639 --- /dev/null +++ b/isis/src/base/objs/RadarCamera/unitTest.cpp @@ -0,0 +1,22 @@ +#include "RadarCamera.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +class MyCamera : public RadarCamera { + public: + MyCamera(Isis::Pvl& lab) : Isis::RadarCamera(lab) { } +}; + +int main() { + Isis::Preference::Preferences(true); + string inputFile = "$ISIS3DATA/mgs/testData/ab102401.lev2.cub"; + Pvl pvl(inputFile); + MyCamera cam(pvl); + + cout << "Camera = Framing? " << (cam.GetCameraType() == Camera::Framing) << std::endl; + cout << "Camera = LineScan? " << (cam.GetCameraType() == Camera::LineScan) << std::endl; + cout << "Camera = PushFrame? " << (cam.GetCameraType() == Camera::PushFrame) << std::endl; + cout << "Camera = Radar? " << (cam.GetCameraType() == Camera::Radar) << std::endl; +} diff --git a/isis/src/base/objs/RadarGroundMap/Makefile b/isis/src/base/objs/RadarGroundMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..42a37ec4c3982ef91635466fbeb57992306678f4 --- /dev/null +++ b/isis/src/base/objs/RadarGroundMap/Makefile @@ -0,0 +1,5 @@ +INCS = RadarGroundMap.h +SRCS = RadarGroundMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/RadarGroundMap/RadarGroundMap.cpp b/isis/src/base/objs/RadarGroundMap/RadarGroundMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2622acf2c07e31e7f539b4e149044d7f15752e5c --- /dev/null +++ b/isis/src/base/objs/RadarGroundMap/RadarGroundMap.cpp @@ -0,0 +1,489 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/03/27 06:54:43 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "RadarGroundMap.h" + +namespace Isis { + RadarGroundMap::RadarGroundMap(Camera *parent, Radar::LookDirection ldir, + double waveLength) : + CameraGroundMap(parent) { + p_camera = parent; + p_lookDirection = ldir; + p_waveLength = waveLength; + + // Angular tolerance based on radii and + // slant range (Focal length) + double radii[3]; + p_camera->Radii(radii); +// p_tolerance = p_camera->FocalLength() / radii[2]; +// p_tolerance *= 180.0 / Isis::PI; + p_tolerance = .00000001; + + // Compute a default time tolerance to a 1/20 of a pixel + double et1 = p_camera->Spice::CacheStartTime(); + double et2 = p_camera->Spice::CacheEndTime(); + p_timeTolerance = (et2 - et1) / p_camera->Lines() / 20.0; + } + + /** Compute ground position from slant range + * + * @param ux Slant range distance in meters scaled to focal plane + * @param uy Doppler shift (always 0.0) + * @param uz Not used + * + * @return conversion was successful + */ + bool RadarGroundMap::SetFocalPlane(const double ux, const double uy, + double uz) { + + SpiceRotation *bodyFrame = p_camera->BodyRotation(); + SpicePosition *spaceCraft = p_camera->InstrumentPosition(); + + // Get spacecraft position and velocity to create a state vector + std::vector Ssc(6); + // Load the state into Ssc + vequ_c ( (SpiceDouble *) &(spaceCraft->Coordinate()[0]), &Ssc[0]); + vequ_c ( (SpiceDouble *) &(spaceCraft->Velocity()[0]), &Ssc[3]); + + // Rotate state vector to body-fixed + std::vector bfSsc(6); + bfSsc = bodyFrame->ReferenceVector(Ssc); + + // Extract body-fixed position and velocity + std::vector Vsc(3); + std::vector Xsc(3); + vequ_c ( &bfSsc[0], (SpiceDouble *) &(Xsc[0]) ); + vequ_c ( &bfSsc[3], (SpiceDouble *) &(Vsc[0]) ); + + // Compute intrack, crosstrack, and radial coordinate + SpiceDouble i[3]; + vhat_c (&Vsc[0],i); + + SpiceDouble c[3]; + SpiceDouble dp; + dp = vdot_c(&Xsc[0],i); + SpiceDouble p[3],q[3]; + vscl_c(dp,i,p); + vsub_c(&Xsc[0],p,q); + vhat_c(q,c); + + SpiceDouble r[3]; + vcrss_c(i,c,r); + + // What is the initial guess for R + double radii[3]; + p_camera->Radii(radii); // km + SpiceDouble R = radii[0]; + SpiceDouble lastR = DBL_MAX; + SpiceDouble rlat; + SpiceDouble rlon; + + SpiceDouble lat = DBL_MAX; + SpiceDouble lon = DBL_MAX; + + double slantRangeSqr = (ux * p_rangeSigma ) / 1000.; // convert to meters, then km + slantRangeSqr = slantRangeSqr*slantRangeSqr; + SpiceDouble X[3]; + + int iter = 0; + do { + double normXsc = vnorm_c(&Xsc[0]); + double alpha = (R*R - slantRangeSqr - normXsc*normXsc) / + (2.0 * vdot_c(&Xsc[0],c)); + + double arg = slantRangeSqr - alpha*alpha; + if (arg < 0.0) return false; + + double beta = sqrt(arg); + if (p_lookDirection == Radar::Left) beta *= -1.0; + + SpiceDouble alphac[3],betar[3]; + vscl_c(alpha,c,alphac); + vscl_c(beta,r,betar); + + vadd_c(alphac,betar,alphac); + vadd_c(&Xsc[0],alphac,X); + + // Convert X to lat,lon + lastR = R; + reclat_c(X,&R,&lon,&lat); + + rlat = lat*180.0/Isis::PI; + rlon = lon*180.0/Isis::PI; + R = GetRadius(rlat,rlon); + iter++; + } + while (fabs(R-lastR) > p_tolerance && iter < 30); + + if (fabs(R-lastR) > p_tolerance) return false; + + lat = lat*180.0/Isis::PI; + lon = lon*180.0/Isis::PI; + while (lon < 0.0) lon += 360.0; + + // Compute body fixed look direction + std::vector lookB; + lookB.resize(3); + lookB[0] = X[0] - Xsc[0]; + lookB[1] = X[1] - Xsc[1]; + lookB[2] = X[2] - Xsc[2]; + + std::vector lookJ = bodyFrame->J2000Vector(lookB); + SpiceRotation *cameraFrame = p_camera->InstrumentRotation(); + std::vector lookC = cameraFrame->ReferenceVector(lookJ); + + SpiceDouble unitLookC[3]; + vhat_c(&lookC[0],unitLookC); + p_camera->SetLookDirection(unitLookC); + + return p_camera->Sensor::SetUniversalGround(lat,lon); + } + + /** Compute undistorted focal plane coordinate from ground position + * + * @param lat planetocentric latitude in degrees + * @param lon planetocentric longitude in degrees + * + * @return conversion was successful + */ + bool RadarGroundMap::SetGround(const double lat, const double lon) { + return SetGround(lat,lon,GetRadius(lat,lon)); + } + + /** Compute undistorted focal plane coordinate from ground position that includes a local radius + * + * @param lat planetocentric latitude in degrees + * @param lon planetocentric longitude in degrees + * @param radius local radius in meters + * + * @return conversion was successful + */ + bool RadarGroundMap::SetGround(const double lat, const double lon, const double radius) { + // Get the ground point in rectangular coordinates (X) + SpiceDouble X[3]; + SpiceDouble rlat = lat*Isis::PI/180.0; + SpiceDouble rlon = lon*Isis::PI/180.0; + latrec_c(radius,rlon,rlat,X); + + // Compute lower bound for Doppler shift + double et1 = p_camera->Spice::CacheStartTime(); + p_camera->Sensor::SetEphemerisTime(et1); + double xv1 = ComputeXv(X); + + // Compute upper bound for Doppler shift + double et2 = p_camera->Spice::CacheEndTime(); + p_camera->Sensor::SetEphemerisTime(et2); + double xv2 = ComputeXv(X); + + // Make sure we bound root (xv = 0.0) + if ((xv1 < 0.0) && (xv2 < 0.0)) return false; + if ((xv1 > 0.0) && (xv2 > 0.0)) return false; + + // Order the bounds + double fl,fh,xl,xh; + if (xv1 < xv2) { + fl = xv1; + fh = xv2; + xl = et1; + xh = et2; + } + else { + fl = xv2; + fh = xv1; + xl = et2; + xh = et1; + } + + // Iterate a max of 30 times + for (int j=0; j<30; j++) { + // Use the secant method to guess the next et + double etGuess = xl + (xh - xl) * fl / (fl - fh); + + // Compute the guessed Doppler shift. Hopefully + // this guess converges to zero at some point + p_camera->Sensor::SetEphemerisTime(etGuess); + double fGuess = ComputeXv(X); + + // Update the bounds + double delTime; + if (fGuess < 0.0) { + delTime = xl - etGuess; + xl = etGuess; + fl = fGuess; + } + else { + delTime = xh - etGuess; + xh = etGuess; + fh = fGuess; + } + + // See if we are done + if ((fabs(delTime) <= p_timeTolerance) || (fGuess == 0.0)) { + SpiceRotation *bodyFrame = p_camera->BodyRotation(); + SpicePosition *spaceCraft = p_camera->InstrumentPosition(); + + // Get body fixed spacecraft velocity and position + std::vector Ssc(6); + + // Load the state into Ssc and rotate to body-fixed + vequ_c ( (SpiceDouble *) &(spaceCraft->Coordinate()[0]), &Ssc[0]); + vequ_c ( (SpiceDouble *) &(spaceCraft->Velocity()[0]), &Ssc[3]); + std::vector bfSsc(6); + bfSsc = bodyFrame->ReferenceVector(Ssc); + + // Extract the body-fixed position and velocity from the state + std::vector Vsc(3); + std::vector Xsc(3); + vequ_c ( &bfSsc[0], (SpiceDouble *) &(Xsc[0]) ); + vequ_c ( &bfSsc[3], (SpiceDouble *) &(Vsc[0]) ); + + // Determine if focal plane coordinate falls on the correct side of the + // spacecraft. Radar has both left and right look directions. Make sure + // the coordinate is on the same side as the look direction. This is done + // by (X - S) . (V x S) where X=ground point vector, S=spacecraft position + // vector, and V=velocity vector. If the dot product is greater than 0, then + // the point is on the right side. If the dot product is less than 0, then + // the point is on the left side. If the dot product is 0, then the point is + // directly under the spacecraft (neither left or right) and is invalid. + SpiceDouble vout1[3]; + SpiceDouble vout2[3]; + SpiceDouble dp; + vsub_c(X,&Xsc[0],vout1); + vcrss_c(&Vsc[0],&Xsc[0],vout2); + dp = vdot_c(vout1,vout2); + if (dp > 0.0 && p_lookDirection == Radar::Left) return false; + 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); + lookB[0] = X[0] - Xsc[0]; + lookB[1] = X[1] - Xsc[1]; + lookB[2] = X[2] - Xsc[2]; + + std::vector lookJ = bodyFrame->J2000Vector(lookB); + SpiceRotation *cameraFrame = p_camera->InstrumentRotation(); + std::vector lookC = cameraFrame->ReferenceVector(lookJ); + + SpiceDouble unitLookC[3]; + vhat_c(&lookC[0],unitLookC); + p_camera->SetLookDirection(unitLookC); + + p_camera->SetFocalLength(p_slantRange*1000.0); // p_slantRange is km so focal length is in m + p_focalPlaneX = p_slantRange*1000.0 / p_rangeSigma; // km to meters and scaled to focal plane + p_focalPlaneY = 0.0; + return true; + } + } + + return false; + } + + + + /** Compute undistorted focal plane coordinate from ground position using current Spice from SetImage call + * + * This method will compute the undistorted focal plane coordinate for + * a ground position, using the current Spice settings (time and kernels) + * without resetting the current point values for lat/lon/radius/x/y and + * related radar parameter p_slantRange. + * + * @param lat planetocentric latitude in degrees + * @param lon planetocentric longitude in degrees + * @param radius local radius in m + * + * @return conversion was successful + */ + bool RadarGroundMap::GetXY(const double lat, const double lon, const double radius, + double *cudx, double *cudy) { + + // Get the ground point in rectangular body-fixed coordinates (X) + SpiceDouble X[3]; + SpiceDouble rlat = lat*Isis::PI/180.0; + SpiceDouble rlon = lon*Isis::PI/180.0; + latrec_c(radius/1000.,rlon,rlat,X); + + // Compute body-fixed look vector + SpiceRotation *bodyFrame = p_camera->BodyRotation(); + SpicePosition *spaceCraft = p_camera->InstrumentPosition(); + + std::vector sJ(6); // Spacecraft state vector (position and velocity) in J2000 frame + // Load the state into sJ + vequ_c ( (SpiceDouble *) &(spaceCraft->Coordinate()[0]), &sJ[0]); + vequ_c ( (SpiceDouble *) &(spaceCraft->Velocity()[0]), &sJ[3]); + + // Rotate the state to body-fixed + p_sB.resize(6); + p_sB = bodyFrame->ReferenceVector(sJ); + + // Extract the body-fixed position and velocity + SpiceDouble VsB[3]; + SpiceDouble PsB[3]; + vequ_c ( &p_sB[0], PsB); + vequ_c ( &p_sB[3], VsB); + + p_lookB.resize(3); + vsub_c(X, PsB, &p_lookB[0]); + + p_groundSlantRange = vnorm_c(&p_lookB[0]); // km + p_groundDopplerFreq = 2./p_waveLength/p_groundSlantRange*vdot_c(&p_lookB[0], &VsB[0]); + *cudx = p_groundSlantRange * 1000.0 / p_rangeSigma; // to meters, then to focal plane coord + *cudy = p_groundDopplerFreq / p_dopplerSigma; // htx to focal plane coord + + return true; + + } + + + + + double RadarGroundMap::ComputeXv(SpiceDouble X[3]) { + // Get the spacecraft position (Xsc) and velocity (Vsc) in body fixed + // coordinates + SpiceRotation *bodyFrame = p_camera->BodyRotation(); + SpicePosition *spaceCraft = p_camera->InstrumentPosition(); + + // Load the state into Ssc + std::vector Ssc(6); + vequ_c ( (SpiceDouble *) &(spaceCraft->Coordinate()[0]), &Ssc[0]); + vequ_c ( (SpiceDouble *) &(spaceCraft->Velocity()[0]), &Ssc[3]); + + // Rotate the state to body-fixed + std::vector bfSsc(6); + bfSsc = bodyFrame->ReferenceVector(Ssc); + + // Extract the body-fixed position and velocity + std::vector Vsc(3); + std::vector Xsc(3); + vequ_c ( &bfSsc[0], &Xsc[0] ); + vequ_c ( &bfSsc[3], &Vsc[0] ); + + // Compute the slant range + SpiceDouble lookB[3]; + vsub_c(&Xsc[0],X,lookB); + p_slantRange = vnorm_c(lookB); // units are km + + // Compute and return xv = -2 * (point - observer) dot (point velocity - observer velocity) / (slantRange*wavelength) + // In body-fixed coordinates, the point velocity = 0. so the equation becomes + // double xv = 2.0 * vdot_c(lookB,&Vsc[0]) / (vnorm_c(lookB) * WaveLength() ); + double xv = -2.0 * vdot_c(lookB,&Vsc[0]) / (vnorm_c(lookB) * WaveLength() ); // - is applied to lookB above + return xv; + } + + + double RadarGroundMap::GetRadius(double lat, double lon) { + if (p_camera->HasElevationModel()) { + return p_camera->DemRadius(lat,lon); + } + + double radii[3]; + p_camera->Radii(radii); + double a = radii[0]; + double b = radii[1]; + double c = radii[2]; + double xyradius = a * b / sqrt(pow(b*cos(lon),2) + pow(a*sin(lon),2) ); + return xyradius * c / sqrt(pow(c*cos(lat),2) + pow(xyradius*sin(lat),2) ); + } + + + + + /** Compute derivative w/r to position of focal plane coordinate from ground position using current Spice from SetImage call + * + * This method will compute the derivative of the undistorted focal plane coordinate for + * a ground position with respect to a spacecraft position coordinate, using the current + * Spice settings (time and kernels) without resetting the current point values for lat/lon/radius/x/y. + * + * @param varType enumerated partial type (definitions in SpicePosition) + * @param coefIndex coefficient index of fit polynomial + * @param *dx pointer to partial derivative of undistorted focal plane x + * @param *dy pointer to partial derivative of undistorted focal plane y + * + * @return conversion was successful + */ + // d_slantRange = (lookB dot d_lookB) / slantRange + // d_dopplerFrequency = -dopplerFrequency/slantRange*d_slantRange - + // 2./wavelength/slantRange*(d_lookB dot vlookB) - + // 2./wavelength/slantRange*(lookB dot d_vlookB) + + // Add the partial for the x coordinate of the position (differentiating + // point(x,y,z) - spacecraftPosition(x,y,z) in body-fixed and the velocity + // Load the derivative of the state into d_lookJ + bool RadarGroundMap::GetdXYdPosition(const SpicePosition::PartialType varType, int coefIndex, + double *dx, double *dy) { + SpicePosition *instPos = p_camera->InstrumentPosition(); + SpiceRotation *bodyRot = p_camera->BodyRotation(); + + std::vector d_lookJ(6); + vequ_c ( &(instPos->CoordinatePartial (varType, coefIndex))[0], &d_lookJ[0]); + vequ_c ( &(instPos->VelocityPartial (varType, coefIndex))[0], &d_lookJ[3]); + + std::vector d_lookB = bodyRot->ReferenceVector(d_lookJ); + + double d_slantRange = (-1.) * vdot_c (&p_lookB[0], &d_lookB[0])/p_groundSlantRange; + double d_dopplerFreq = (-1.)*p_groundDopplerFreq*d_slantRange/p_groundSlantRange - + 2./p_waveLength/p_groundSlantRange*vdot_c (&d_lookB[0], &p_sB[3]) + + 2./p_waveLength/p_groundSlantRange*vdot_c(&p_lookB[0], &d_lookB[3]); + + *dx = d_slantRange * 1000.0 / p_rangeSigma;// km to meters, then to focal plane coord + *dy = d_dopplerFreq / p_dopplerSigma; // htz scaled to focal plane + + return true; + } + + /** Compute derivative of focal plane coordinate w/r to ground point from ground position using current Spice from SetImage call + * + * This method will compute the derivative of the undistorted focal plane coordinate for + * a ground position with respect to lat, lon, or radius, using the current Spice settings (time and kernels) + * without resetting the current point values for lat/lon/radius/x/y. + * + * @param varType enumerated partial type (definitions in SpicePosition) + * @param coefIndex coefficient index of fit polynomial + * @param *dx pointer to partial derivative of undistorted focal plane x + * @param *dy pointer to partial derivative of undistorted focal plane y + * + * @return conversion was successful + */ + bool RadarGroundMap::GetdXYdPoint(double lat, double lon, double radius, PartialType wrt, + double *dx, double *dy) { + + // TODO add a check to make sure p_lookB has been set + + // Get the partial derivative of the surface point + std::vector d_lookB = PointPartial(lat, lon, radius, wrt); + + double d_slantRange = vdot_c(&p_lookB[0], &d_lookB[0]) / p_groundSlantRange; // km + // After switching to J2000, the last term will not be 0. as it is in body-fixed +// double d_dopplerFreq = p_groundDopplerFreq*d_slantRange/p_groundSlantRange // Ken +// + 2./p_waveLength/p_groundSlantRange*vdot_c(&d_lookB[0], &p_sB[3]); + double d_dopplerFreq = (-1.)*p_groundDopplerFreq*d_slantRange/p_groundSlantRange + + 2./p_waveLength/p_groundSlantRange*vdot_c(&d_lookB[0], &p_sB[3]); +// + 2./p_wavelength/slantRange*vdot_c(&p_lookB[0], 0); + + *dx = d_slantRange * 1000.0 / p_rangeSigma; + *dy = d_dopplerFreq / p_dopplerSigma; + + return true; + } + +} diff --git a/isis/src/base/objs/RadarGroundMap/RadarGroundMap.h b/isis/src/base/objs/RadarGroundMap/RadarGroundMap.h new file mode 100644 index 0000000000000000000000000000000000000000..e2d4fd4387ca13adec957a1cf78137bd56b01309 --- /dev/null +++ b/isis/src/base/objs/RadarGroundMap/RadarGroundMap.h @@ -0,0 +1,129 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/03/27 06:52:58 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef RadarGroundMap_h +#define RadarGroundMap_h + +#include "Camera.h" +#include "CameraGroundMap.h" + +namespace Isis { + +#ifndef RADAR_LOOK_DIR +namespace Radar { + enum LookDirection { Left, Right }; +} +#define RADAR_LOOK_DIR +#endif + + /** Convert between undistorted focal plane coordinate (slant range) + * and ground coordinates + * + * This class is used to convert between undistorted focal plane + * coordinate (the slant range) and ground coordinates lat/lon. This + * class handles the case of Radar instruments. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2008-06-16 Jeff Anderson + * Original version + * + * @history 2009-07-01 Janet Barrett - Fixed intrack, crosstrack, and radial + * coordinate calculations; changed boundary check to use + * radius instead of lat,lon; updated calculation of Doppler + * shift + * @history 2009-10-30 Debbie A. Cook - Fixed rotation of velocity vector in + * SetFocalPlane, SetGround, and ComputeXv + * @history 2009-11-10 Janet Barrett - Added iteration check to SetFocalPlane + * to take care of situation where DEM radius does not + * converge + * @history 2009-11-20 Janet Barrett - Added a check to the SetGround method + * to determine what side of the spacecraft the focal + * plane coordinate falls. This fixed the mirror image + * problem that occurred when projecting the image. + * @history 2009-12-14 Debbie A. Cook - Added ComputeXY method + * @history 2010-03-19 Debbe A. Cook - added class members p_wavelength, p_lookB, + * p_sB, p_slantRange, and p_dopplerFreq; and methods SlantRangeSigma, + * WaveLength, DopplerSigma, SetSlantRangeSigma, GetXY, + * GetXYdPosition, and GetXYdPoint. Removed method SetWeightFactors. + * + */ + class RadarGroundMap : public CameraGroundMap { + public: + RadarGroundMap(Camera *parent, Radar::LookDirection ldir, double waveLength); + + //! Destructor + virtual ~RadarGroundMap() {}; + + virtual bool SetFocalPlane(const double ux, const double uy, + const double uz); + + virtual bool SetGround(const double lat, const double lon); + virtual bool SetGround(const double lat, const double lon, const double radius); + virtual bool GetXY(const double lat, const double lon, const double radius, + double *cudx, double *cudy); + virtual bool GetdXYdPosition(const SpicePosition::PartialType varType, int coefIndex, + double *cudx, double *cudy); + virtual bool GetdXYdPoint(double lat, double lon, double radius, PartialType wrt, + double *dx, double *dy); + + //!Set the range sigma + void SetRangeSigma( double rangeSigma ) { p_rangeSigma = rangeSigma; }; + + //! Return the range sigma + double RangeSigma() { return p_rangeSigma; }; + + //! Set the doppler sigma + void SetDopplerSigma( double dopplerSigma ) { p_dopplerSigma = dopplerSigma; }; + + //! Return the doppler sigma + double YScale() { return p_dopplerSigma; }; + + //! Return the wavelength + double WaveLength() { return p_waveLength; }; + + private: + double ComputeXv(SpiceDouble X[3]); + double GetRadius(double lat, double lon); + + Radar::LookDirection p_lookDirection; + double p_tolerance; + double p_slantRange; //!< units are km + double p_dopplerFreq; //!< units are hertz + double p_timeTolerance; + double p_rangeSigma; //!< Scaling factor to convert meters to focal plane coord + double p_dopplerSigma; //!< Scaling factor to convert hertz to focal plane coord + double p_waveLength; // km/sec/hertz ?? + std::vector p_lookB; + std::vector p_sB; + double p_groundSlantRange; //!< units are km + double p_groundDopplerFreq; //!< units are hertz + + Camera *p_camera; + }; +}; +#endif diff --git a/isis/src/base/objs/RadarGroundMap/RadarGroundMap.truth b/isis/src/base/objs/RadarGroundMap/RadarGroundMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..a60b204df7c81bc10ccf10790ff9d9e25a0bf506 --- /dev/null +++ b/isis/src/base/objs/RadarGroundMap/RadarGroundMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Radar models. diff --git a/isis/src/base/objs/RadarGroundMap/unitTest.cpp b/isis/src/base/objs/RadarGroundMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37a94dcf30d5e810fa894cfe90e20a9581da5f26 --- /dev/null +++ b/isis/src/base/objs/RadarGroundMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Radar models." << endl; +} diff --git a/isis/src/base/objs/RadarGroundRangeMap/Makefile b/isis/src/base/objs/RadarGroundRangeMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d03098b8e78ac5a3c95d6852e9fa6c2e0119ffcb --- /dev/null +++ b/isis/src/base/objs/RadarGroundRangeMap/Makefile @@ -0,0 +1,5 @@ +INCS = RadarGroundRangeMap.h +SRCS = RadarGroundRangeMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/RadarGroundRangeMap/RadarGroundRangeMap.cpp b/isis/src/base/objs/RadarGroundRangeMap/RadarGroundRangeMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9961ca9c04e396e744f9846ac69e6b42cad14eb --- /dev/null +++ b/isis/src/base/objs/RadarGroundRangeMap/RadarGroundRangeMap.cpp @@ -0,0 +1,68 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/07/09 16:40:19 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "RadarGroundRangeMap.h" + +namespace Isis { + /** Construct mapping between detectors and focal plane x/y + * + * @param parent parent camera that will use this map + * @param naifIkCode code of the naif instrument for reading coefficients + * + */ + RadarGroundRangeMap::RadarGroundRangeMap(Camera *parent, const int naifIkCode) + : CameraFocalPlaneMap(parent,naifIkCode) { + } + + void RadarGroundRangeMap::setTransform(int naifIkCode, + double groundRangeResolution, + int samples, Radar::LookDirection ldir) { + // Setup map from radar(sample,time) to radar(groundRange,time) + double transx[3], transy[3]; + double transs[3], transl[3]; + + // There is no change for Left and Right look because the RangeCoefficientSet + // takes the look direction into account + transx[0] = -1.0 * groundRangeResolution; + transx[1] = groundRangeResolution; + transx[2] = 0.0; + + transs[0] = 1.0; + transs[1] = 1.0 / groundRangeResolution; + transs[2] = 0.0; + + transy[0] = 0.0; + transy[1] = 0.0; + transy[2] = 0.0; + + transl[0] = 0.0; + transl[1] = 0.0; + transl[2] = 0.0; + + std::string icode = "INS" + iString(naifIkCode); + pdpool_c((icode+"_TRANSX").c_str(), 3, transx); + pdpool_c((icode+"_TRANSY").c_str(), 3, transy); + pdpool_c((icode+"_ITRANSS").c_str(), 3, transs); + pdpool_c((icode+"_ITRANSL").c_str(), 3, transl); + } +} + diff --git a/isis/src/base/objs/RadarGroundRangeMap/RadarGroundRangeMap.h b/isis/src/base/objs/RadarGroundRangeMap/RadarGroundRangeMap.h new file mode 100644 index 0000000000000000000000000000000000000000..fb42fa9441d9d47d75062910c0da8259f597873b --- /dev/null +++ b/isis/src/base/objs/RadarGroundRangeMap/RadarGroundRangeMap.h @@ -0,0 +1,61 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/07/09 16:40:19 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef RadarGroundRangeMap_h +#define RadarGroundRangeMap_h + +#include "Camera.h" +#include "CameraFocalPlaneMap.h" + +namespace Isis { + +#ifndef RADAR_LOOK_DIR +namespace Radar { + enum LookDirection { Left, Right }; +} +#define RADAR_LOOK_DIR +#endif + + /** Construct a mapping between image sample and Radar ground range + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @author 2008-06-17 Jeff Anderson + * Original version + * + * @history 2009-07-01 Janet Barrett - Corrected the transformation + * calculations + * + */ + class RadarGroundRangeMap : public CameraFocalPlaneMap { + public: + RadarGroundRangeMap(Camera *parent, const int naifIkCode); + + static void setTransform(int naifIkCode, double groundRangeResolution, + int samples, Radar::LookDirection ldir); + }; +}; +#endif diff --git a/isis/src/base/objs/RadarGroundRangeMap/RadarGroundRangeMap.truth b/isis/src/base/objs/RadarGroundRangeMap/RadarGroundRangeMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..a60b204df7c81bc10ccf10790ff9d9e25a0bf506 --- /dev/null +++ b/isis/src/base/objs/RadarGroundRangeMap/RadarGroundRangeMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Radar models. diff --git a/isis/src/base/objs/RadarGroundRangeMap/unitTest.cpp b/isis/src/base/objs/RadarGroundRangeMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37a94dcf30d5e810fa894cfe90e20a9581da5f26 --- /dev/null +++ b/isis/src/base/objs/RadarGroundRangeMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Radar models." << endl; +} diff --git a/isis/src/base/objs/RadarPulseMap/Makefile b/isis/src/base/objs/RadarPulseMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c11543009463c3c5642f676b1b886862ece4fdfe --- /dev/null +++ b/isis/src/base/objs/RadarPulseMap/Makefile @@ -0,0 +1,5 @@ +INCS = RadarPulseMap.h +SRCS = RadarPulseMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/RadarPulseMap/RadarPulseMap.cpp b/isis/src/base/objs/RadarPulseMap/RadarPulseMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f596a7bdf41ba04823a32e3e4df0ff3a85c4ac0f --- /dev/null +++ b/isis/src/base/objs/RadarPulseMap/RadarPulseMap.cpp @@ -0,0 +1,69 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/07/09 16:40:59 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "RadarPulseMap.h" +#include "CameraFocalPlaneMap.h" + +namespace Isis { + /** Compute alpha position from a detector coordinate + * + * This method will compute a alpha sample given a detector + * coordinate. The alpha line will be computed using the the + * time in the parent camera + * + * @param sample Sample number in the detector + * @param line Line number in the detector (ignored) + * + * @return conversion successful + */ + bool RadarPulseMap::SetDetector(const double sample, + const double line) { + if (!CameraDetectorMap::SetDetector(sample,line)) return false; + double etDiff = p_camera->EphemerisTime() - p_etStart; + p_parentLine = etDiff / p_lineRate + 1.0; + return true; + } + + /** Compute radar (sample/time)from a alpha image coordinate + * + * This method will compute the radar position from the alpha + * line/sample coordinate. The alpha line will be used to set + * the appropriate time in the parent camera. + * + * @param sample Sample number in the alpha image + * @param line Line number in the alpha image + * + * @return conversion successful + */ + bool RadarPulseMap::SetParent(const double sample, + const double line) { + // Apply base class summing/first sample corrections + if (!CameraDetectorMap::SetParent(sample,line)) return false; + + // line is really a function of time so set detector line to zero + p_detectorLine = 0; + double etLine = p_etStart + p_lineRate * (line - 1.0); + p_camera->SetEphemerisTime(etLine); + return true; + } +} diff --git a/isis/src/base/objs/RadarPulseMap/RadarPulseMap.h b/isis/src/base/objs/RadarPulseMap/RadarPulseMap.h new file mode 100644 index 0000000000000000000000000000000000000000..d731acab71050c6f6689fa5b0dd18ddf4d14b74f --- /dev/null +++ b/isis/src/base/objs/RadarPulseMap/RadarPulseMap.h @@ -0,0 +1,116 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/07/09 16:40:59 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef RadarPulseMap_h +#define RadarPulseMap_h + +#include "RadarPulseMap.h" +#include "CameraDetectorMap.h" + +namespace Isis { + /** Convert between alpha image coordinates and radar sample, + * time coordinates + * + * This class is used to convert between alpha coordinates + * (sample/line) and radar pulse coordinates (sample,time) for a + * radar instrument. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2008-06-16 Jeff Anderson + * Original version + * + * @history 2009-07-01 Janet Barrett - Corrected the calculations + * used to convert from line to time and back + * + */ + class RadarPulseMap : public CameraDetectorMap { + public: + /** Construct a detector map for line scan cameras + * + * @param parent The parent camera model for the detector map + * @param etStart starting ephemeris time in seconds + * at the top of the first line + * @param lineRate the time in seconds between lines + * + */ + RadarPulseMap(Camera *parent, const double etStart, + const double lineRate) : + CameraDetectorMap(parent) { + p_etStart = etStart; + p_lineRate = lineRate; + p_yAxisTimeDependent = true; + } + + //! Destructor + virtual ~RadarPulseMap() {}; + + /** Reset the starting ephemeris time + * + * Use this method to reset the starting time of the top edge of + * the first line in the alpha image. That is the time, prior + * to cropping, scaling, or padding. Usually this will not need + * to be done unless the time changes between bands. + * + * @param etStart starting ephemeris time in seconds + * + */ + void SetStartTime (const double etStart) { p_etStart = etStart; }; + + /** Reset the line rate + * + * Use this method to reset the time between lines. Usually this + * will not need to be done unless the rate changes between bands. + * + * @param lineRate the time in seconds between lines + * + */ + void SetLineRate (const double lineRate) { p_lineRate = lineRate; }; + + //! Return the time in seconds between scan lines + double LineRate () const { return p_lineRate; }; + + virtual bool SetParent(const double sample, const double line); + + virtual bool SetDetector(const double sample, const double line); + + /** + * Set the time dependent axis, if never called y is the time dependent + * axis + */ + void SetXAxisTimeDependent(bool on) { + p_xAxisTimeDependent = on; + p_yAxisTimeDependent = !on; + }; + + private: + bool p_xAxisTimeDependent; + bool p_yAxisTimeDependent; + double p_etStart; //!< Starting time at the top of the 1st alpha line + double p_lineRate; //!< iTime between lines in parent cube + }; +}; +#endif diff --git a/isis/src/base/objs/RadarPulseMap/RadarPulseMap.truth b/isis/src/base/objs/RadarPulseMap/RadarPulseMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..a60b204df7c81bc10ccf10790ff9d9e25a0bf506 --- /dev/null +++ b/isis/src/base/objs/RadarPulseMap/RadarPulseMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Radar models. diff --git a/isis/src/base/objs/RadarPulseMap/unitTest.cpp b/isis/src/base/objs/RadarPulseMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37a94dcf30d5e810fa894cfe90e20a9581da5f26 --- /dev/null +++ b/isis/src/base/objs/RadarPulseMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Radar models." << endl; +} diff --git a/isis/src/base/objs/RadarSkyMap/Makefile b/isis/src/base/objs/RadarSkyMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b02be9afa4b4bdb9dec107951b0994cf55849a41 --- /dev/null +++ b/isis/src/base/objs/RadarSkyMap/Makefile @@ -0,0 +1,5 @@ +INCS = RadarSkyMap.h +SRCS = RadarSkyMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/RadarSkyMap/RadarSkyMap.cpp b/isis/src/base/objs/RadarSkyMap/RadarSkyMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0360a616c2320c2058f4c683e66801bc62b7f0d6 --- /dev/null +++ b/isis/src/base/objs/RadarSkyMap/RadarSkyMap.cpp @@ -0,0 +1,62 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/07/09 16:41:34 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "RadarSkyMap.h" + +namespace Isis { + /** Constructor a map between focal plane x/y and right acension/declination + * + * @param parent parent camera which will use this map + * + */ + RadarSkyMap::RadarSkyMap(Camera *parent) : CameraSkyMap(parent) { + } + + /** Compute ra/dec from slant range + * + * Radar can't paint a star will always return false + * + * @param ux distorted focal plane x in millimeters + * @param uy distorted focal plane y in millimeters + * @param uz distorted focal plane z in millimeters + * + * @return conversion was successful + */ + bool RadarSkyMap::SetFocalPlane(const double ux, const double uy, + double uz) { + return false; + } + + /** + * Compute slant range from ra/dec. + * + * Radar can't paint a star will always return false + * + * @param ra The right ascension angle + * @param dec The declination + * + */ + bool RadarSkyMap::SetSky(const double ra, const double dec) { + return false; + } +} diff --git a/isis/src/base/objs/RadarSkyMap/RadarSkyMap.h b/isis/src/base/objs/RadarSkyMap/RadarSkyMap.h new file mode 100644 index 0000000000000000000000000000000000000000..bb919a2eca0f71149da1487e3aafa3ef9ae98061 --- /dev/null +++ b/isis/src/base/objs/RadarSkyMap/RadarSkyMap.h @@ -0,0 +1,61 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/07/09 16:41:34 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef RadarSkyMap_h +#define RadarSkyMap_h + +#include "Camera.h" +#include "CameraSkyMap.h" + +namespace Isis { + /** Convert between slantrange/groundrange and ra/dec + * coordinates + * + * Radar can never paint a star so this routine alway returns + * false for a sky intersection + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2008-06-17 Jeff Anderson + * Original version + * + */ + class RadarSkyMap : public CameraSkyMap { + public: + RadarSkyMap(Camera *parent); + + //! Destructor + virtual ~RadarSkyMap() {}; + + virtual bool SetFocalPlane(const double ux, const double uy, + const double uz); + + virtual bool SetSky(const double ra, const double dec); + + }; +}; +#endif diff --git a/isis/src/base/objs/RadarSkyMap/RadarSkyMap.truth b/isis/src/base/objs/RadarSkyMap/RadarSkyMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..a60b204df7c81bc10ccf10790ff9d9e25a0bf506 --- /dev/null +++ b/isis/src/base/objs/RadarSkyMap/RadarSkyMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Radar models. diff --git a/isis/src/base/objs/RadarSkyMap/unitTest.cpp b/isis/src/base/objs/RadarSkyMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37a94dcf30d5e810fa894cfe90e20a9581da5f26 --- /dev/null +++ b/isis/src/base/objs/RadarSkyMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Radar models." << endl; +} diff --git a/isis/src/base/objs/RadarSlantRangeMap/Makefile b/isis/src/base/objs/RadarSlantRangeMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2079d171665ae37070a7df9ba0eeb704aca1cb52 --- /dev/null +++ b/isis/src/base/objs/RadarSlantRangeMap/Makefile @@ -0,0 +1,5 @@ +INCS = RadarSlantRangeMap.h +SRCS = RadarSlantRangeMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.cpp b/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ded12ea1c64da684d7c7bd4e331d71f5084bee1 --- /dev/null +++ b/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.cpp @@ -0,0 +1,247 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/03/27 06:56:17 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "iString.h" +#include "RadarSlantRangeMap.h" +#include "PvlSequence.h" + +namespace Isis { + /** Radar ground to slant range map constructor + * + * Create a map from ground range distance to slant range + * distance on a radar instrument + * + * @param parent the parent camera that will use this distortion map + * + */ + RadarSlantRangeMap::RadarSlantRangeMap(Camera *parent, double groundRangeResolution) : + CameraDistortionMap(parent,1.0) { + + p_camera = parent; + p_et = DBL_MAX; + p_a[0] = p_a[1] = p_a[2] = p_a[3] = 0.0; + + // Need to come up with an initial guess when solving for ground + // range given slantrange. We will compute the ground range at the + // near and far edges of the image by evaluating the sample-to- + // ground-range equation: r_gnd=(S-1)*groundRangeResolution + // at the edges of the image. We also need to add some padding to + // 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; + p_tolerance = 0.1; // Default tolerance is a tenth of a meter + p_maxIterations = 30; + } + + /** Set the ground range and compute a slant range + * + */ + bool RadarSlantRangeMap::SetFocalPlane(const double dx, const double dy) { + p_focalPlaneX = dx; // dx is a ground range distance in meters + p_focalPlaneY = dy; // dy is Doppler shift in htz and should always be 0 + + if (p_et != p_camera->EphemerisTime()) ComputeA(); + double slantRange = p_a[0] + p_a[1]*dx + p_a[2]*dx*dx + p_a[3]*dx*dx*dx; // meters + + p_camera->SetFocalLength(slantRange); + p_undistortedFocalPlaneX = slantRange / p_rangeSigma; + p_undistortedFocalPlaneY = 0; + + return true; + } + + /** Set the slant range and compute a ground range + * + */ + bool RadarSlantRangeMap::SetUndistortedFocalPlane(const double ux, + const double uy) { + p_undistortedFocalPlaneX = ux * p_rangeSigma; // ux converts to slant range in meters + p_undistortedFocalPlaneY = uy * p_dopplerSigma; // uy converts to Doppler shift in htz and should always be 0 + + if (p_et != p_camera->EphemerisTime()) ComputeA(); + + // Evaluate the ground range at the 2 extremes of the image + double slant = p_undistortedFocalPlaneX; + double minGroundRangeGuess = slant - (p_a[0] + p_initialMinGroundRangeGuess * + (p_a[1] + p_initialMinGroundRangeGuess * (p_a[2] + + p_initialMinGroundRangeGuess * p_a[3]))); + double maxGroundRangeGuess = slant - (p_a[0] + p_initialMaxGroundRangeGuess * + (p_a[1] + p_initialMaxGroundRangeGuess * (p_a[2] + + p_initialMaxGroundRangeGuess * p_a[3]))); + + // 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. + if ((minGroundRangeGuess == maxGroundRangeGuess) || + (minGroundRangeGuess < 0.0 && maxGroundRangeGuess < 0.0) || + (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] + + // groundRange * (p_a[2] + groundRange * p_a[3]))) + // The algorithm used is a combination of the bisection method with the + // secant method. + int iter = 0; + double eps = 3.E-8; + double ax = p_initialMinGroundRangeGuess; + double bx = p_initialMaxGroundRangeGuess; + double fax = minGroundRangeGuess; + double fbx = maxGroundRangeGuess; + double fcx = fbx; + double cx = 0.0; + double d = 0.0; + double e = 0.0; + double tol1; + double xm; + double p,q,r,s,t; + + do { + iter++; + if (fbx*fcx > 0.0) { + cx = ax; + fcx = fax; + d = bx - ax; + e = d; + } + if (fabs(fcx) < fabs(fbx)) { + ax = bx; + bx = cx; + cx = ax; + fax = fbx; + fbx = fcx; + fcx = fax; + } + tol1 = 2.0 * eps * fabs(bx) + 0.5 * p_tolerance; + xm = 0.5 * (cx - bx); + if (fabs(xm) <= tol1 || fbx == 0.0) { + p_focalPlaneX = bx; + p_focalPlaneY = 0.0; + return true; + } + if (fabs(e) >= tol1 && fabs(fax) > fabs(fbx)) { + s = fbx / fax; + if (ax == cx) { + p = 2.0 * xm * s; + q = 1.0 - s; + } else { + q = fax / fcx; + r = fbx / fcx; + p = s * (2.0 * xm * q * (q - r) - (bx - ax) * (r - 1.0)); + q = (q - 1.0) * (r - 1.0) * (s - 1.0); + } + if (p > 0.0) q = -q; + p = fabs(p); + t = 3.0 * xm * q - fabs(tol1 * q); + if (t > fabs(e*q)) t = fabs(e * q); + if (2.0*p < t) { + e = d; + d = p / q; + } else { + d = xm; + e = d; + } + } else { + d = xm; + e = d; + } + ax = bx; + fax = fbx; + if (fabs(d) > tol1) { + bx = bx + d; + } else { + if (xm >= 0.0) { + t = fabs(tol1); + } else { + t = -fabs(tol1); + } + bx = bx + t; + } + fbx = slant - (p_a[0] + bx * (p_a[1] + bx * (p_a[2] + bx * p_a[3]))); + } while (iter <= p_maxIterations); + + return false; + } + + /** Load the ground range/slant range coefficients from the + * RangeCoefficientSet keyword + * + */ + void RadarSlantRangeMap::SetCoefficients(PvlKeyword &keyword) { + PvlSequence seq; + seq = keyword; + for (int i=0; i array = seq[i]; + double et; + utc2et_c(array[0].c_str(),&et); + p_time.push_back(et); + p_a0.push_back(array[1].ToDouble()); + p_a1.push_back(array[2].ToDouble()); + p_a2.push_back(array[3].ToDouble()); + p_a3.push_back(array[4].ToDouble()); + // TODO: Test that times are ordered if not throw error + // Make the mrf2isis program sort them if necessary + } + } + + /** Set new A-coefficients based on the current ephemeris time. + * The A-coefficients used will be those with the closest + * ephemeris time to the current ephemeris time. + */ + void RadarSlantRangeMap::ComputeA() { + double currentEt = p_camera->EphemerisTime(); + + std::vector::iterator pos = lower_bound(p_time.begin(),p_time.end(),currentEt); + + int index; + if (pos == p_time.end()) { + index = p_time.size()-1; + } + else { + index = pos - p_time.begin(); + if ((currentEt - p_time[index]) > (p_time[index+1] - currentEt)) { + index++; + } + } + + int tsize = p_time.size(); + if (index >= tsize) { + index = p_time.size() - 1; + } + + p_a[0] = p_a0[index]; + p_a[1] = p_a1[index]; + p_a[2] = p_a2[index]; + p_a[3] = p_a3[index]; + } + + /** Set the weight factors for slant range and Doppler shift + * + */ + void RadarSlantRangeMap::SetWeightFactors(double range_sigma, double doppler_sigma) { + p_rangeSigma = range_sigma; // meters scaling factor + p_dopplerSigma = doppler_sigma; // htz scaling factor + } +} diff --git a/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.h b/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.h new file mode 100644 index 0000000000000000000000000000000000000000..e4c2d7031753efe5c008c301d2e473212d6ff24e --- /dev/null +++ b/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.h @@ -0,0 +1,90 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/03/27 06:56:17 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef RadarSlantRangeMap_h +#define RadarSlantRangeMap_h + +#include +#include "Camera.h" +#include "CameraDistortionMap.h" + +namespace Isis { + /** Convert between radar ground range and slant range + * + * Creates a map for converting radar ground range distance and + * slant range distance + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @author 2008-06-16 Jeff Anderson + * Original version + * + * @history 2009-07-01 Janet Barrett - Changed the bracketing method + * used to solve for the root of the function that + * determines ground range given slant range; + * fixed code that determines the range coefficients + * to used based on current ephemeris time + * @history 2010-03-19 Debbie A. Cook - Added comments about the units + * and corrected slant in SetUndistortedFocalPlane + * to be in meters instead of km + * + */ + class RadarSlantRangeMap : public CameraDistortionMap { + public: + RadarSlantRangeMap(Camera *parent, double groundRangeResolution); + + //! Destructor + virtual ~RadarSlantRangeMap() {}; + + virtual bool SetFocalPlane(const double dx, const double dy); + + virtual bool SetUndistortedFocalPlane(const double ux, const double uy); + + void SetCoefficients(PvlKeyword &keyword); + + void SetWeightFactors(double range_sigma, double doppler_sigma); + + private: + void ComputeA(); + double p_et; + double p_a[4]; + std::vector p_time; + std::vector p_a0; + std::vector p_a1; + std::vector p_a2; + std::vector p_a3; + + int p_maxIterations; + double p_tolerance; + double p_initialMinGroundRangeGuess; + double p_initialMaxGroundRangeGuess; + + double p_rangeSigma; + double p_dopplerSigma; + Camera *p_camera; + }; +}; +#endif diff --git a/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.truth b/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..a60b204df7c81bc10ccf10790ff9d9e25a0bf506 --- /dev/null +++ b/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Radar models. diff --git a/isis/src/base/objs/RadarSlantRangeMap/unitTest.cpp b/isis/src/base/objs/RadarSlantRangeMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37a94dcf30d5e810fa894cfe90e20a9581da5f26 --- /dev/null +++ b/isis/src/base/objs/RadarSlantRangeMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Radar models." << endl; +} diff --git a/isis/src/base/objs/RadialDistortionMap/Makefile b/isis/src/base/objs/RadialDistortionMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f10d1567100858aba65560bb904e0eb683030da9 --- /dev/null +++ b/isis/src/base/objs/RadialDistortionMap/Makefile @@ -0,0 +1,5 @@ +INCS = RadialDistortionMap.h +SRCS = RadialDistortionMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/RadialDistortionMap/RadialDistortionMap.cpp b/isis/src/base/objs/RadialDistortionMap/RadialDistortionMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dad48de09f91d7ebeae2d594ef3b2e4f6a65a3c3 --- /dev/null +++ b/isis/src/base/objs/RadialDistortionMap/RadialDistortionMap.cpp @@ -0,0 +1,85 @@ +#include "RadialDistortionMap.h" +#include "CameraFocalPlaneMap.h" + +using namespace std; + +namespace Isis { + RadialDistortionMap::RadialDistortionMap (Camera *parent, double k1, double zDirection) : CameraDistortionMap(parent, zDirection) { + p_k1 = k1; + } + + // Compute undistorted focal plane x/y. + bool RadialDistortionMap::SetFocalPlane (const double dx, const double dy) { + double offsetSqrd; + + p_focalPlaneX = dx; + p_focalPlaneY = dy; + + offsetSqrd = dx * dx + dy * dy; + + p_undistortedFocalPlaneX = dx * (1.0 + p_k1 * offsetSqrd); + p_undistortedFocalPlaneY = dy * (1.0 + p_k1 * offsetSqrd); + + return true; + } + + bool RadialDistortionMap::SetUndistortedFocalPlane (const double ux, const double uy) { + double offsetSqrd; + int numAttempts; + double delta; + bool done; + + p_undistortedFocalPlaneX = ux; + p_undistortedFocalPlaneY = uy; + + /**************************************************************************** + * Pre-loop intializations + ****************************************************************************/ + + numAttempts = 1; + delta = 0.00001; + + offsetSqrd = uy * uy + ux * ux; + double guess_dx, guess_dy; + double guess_ux, guess_uy; + + /**************************************************************************** + * Loop ... + ****************************************************************************/ + do { + /* Guess a distorted line/samp */ + guess_dx = ux / (1.0 + p_k1 * offsetSqrd); + guess_dy = uy / (1.0 + p_k1 * offsetSqrd); + + /* Use the guess to calculate a corrected line/samp */ + offsetSqrd = guess_dy * guess_dy + guess_dx * guess_dx; + + guess_ux = guess_dx * (1.0 + p_k1 * offsetSqrd); + guess_uy = guess_dy * (1.0 + p_k1 * offsetSqrd); + + /* If guessed corrected line/samp match the input line/samp we're done*/ + done = true; + if (abs(guess_uy - uy) > delta) { + done = false; + } + + if (abs(guess_ux - ux) > delta) { + done = false; + } + + /* Not converging so bomb */ + numAttempts++; + if (numAttempts > 20) { + return false; + } + } while (!done); + + /**************************************************************************** + * Sucess ... + ****************************************************************************/ + + p_focalPlaneX = guess_dx; + p_focalPlaneY = guess_dy; + return true; + } +} diff --git a/isis/src/base/objs/RadialDistortionMap/RadialDistortionMap.h b/isis/src/base/objs/RadialDistortionMap/RadialDistortionMap.h new file mode 100644 index 0000000000000000000000000000000000000000..0ce8439d515c760dd5ea94b4b554d2347fb6fa7c --- /dev/null +++ b/isis/src/base/objs/RadialDistortionMap/RadialDistortionMap.h @@ -0,0 +1,21 @@ +#ifndef NirDistortionMap_h +#define NirDistortionMap_h + +#include "CameraDistortionMap.h" +#include "Camera.h" + +namespace Isis { + class RadialDistortionMap : public CameraDistortionMap { + public: + RadialDistortionMap (Camera *parent, double k1, double zDirection = 1.0); + ~RadialDistortionMap () {}; + + bool SetFocalPlane (const double dx, const double dy); + bool SetUndistortedFocalPlane (const double ux, const double uy); + + private: + double p_k1; + //double p_cameraSpec; + }; +}; +#endif diff --git a/isis/src/base/objs/RadialDistortionMap/RadialDistortionMap.truth b/isis/src/base/objs/RadialDistortionMap/RadialDistortionMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..6347fe6d38f458077e14c2efcd5624b000c19da3 --- /dev/null +++ b/isis/src/base/objs/RadialDistortionMap/RadialDistortionMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Camera models. diff --git a/isis/src/base/objs/RadialDistortionMap/unitTest.cpp b/isis/src/base/objs/RadialDistortionMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39b61434074340b7a7618aa7af48e88aace99227 --- /dev/null +++ b/isis/src/base/objs/RadialDistortionMap/unitTest.cpp @@ -0,0 +1,9 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/ReseauDistortionMap/Makefile b/isis/src/base/objs/ReseauDistortionMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..83806879fb5b9b6e3c24f03b2f794aaf556b8ecd --- /dev/null +++ b/isis/src/base/objs/ReseauDistortionMap/Makefile @@ -0,0 +1,5 @@ +INCS = ReseauDistortionMap.h +SRCS = ReseauDistortionMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ReseauDistortionMap/ReseauDistortionMap.cpp b/isis/src/base/objs/ReseauDistortionMap/ReseauDistortionMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7faa3d3f4641500dfa825a1791a84d9273442b9 --- /dev/null +++ b/isis/src/base/objs/ReseauDistortionMap/ReseauDistortionMap.cpp @@ -0,0 +1,311 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:09 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "ReseauDistortionMap.h" +#include "LeastSquares.h" +#include "BasisFunction.h" +#include "CameraFocalPlaneMap.h" +#include "Pvl.h" +#include "Statistics.h" +#include + +using namespace std; +namespace Isis { + /** + * Creates a ReseauDistortionMap object + * + * @param parent The parent camera model + * @param labels The pvl labels to get the Reference Reseau location from + * @param fname The filename containing master reseau location for the + * particular camera + * + * @throws Isis::iException::User - There are not the same amount of master and + * refined reseaus + */ + ReseauDistortionMap::ReseauDistortionMap (Camera *parent, Pvl &labels, const std::string &fname) : + CameraDistortionMap (parent,1.0) { + // Set up distortion coefficients + Pvl mast(fname); + PvlGroup dim = mast.FindGroup("Dimensions"); + p_distortedLines = dim.FindKeyword("DistortedLines"); + p_distortedSamps = dim.FindKeyword("DistortedSamples"); + p_undistortedLines = dim.FindKeyword("UndistortedLines"); + p_undistortedSamps = dim.FindKeyword("UndistortedSamples"); + PvlGroup mastRes = mast.FindGroup("MasterReseaus"); + PvlKeyword mline = mastRes.FindKeyword("Line"); + PvlKeyword msamp = mastRes.FindKeyword("Sample"); + p_numRes = mline.Size(); + if (mline.Size() != msamp.Size()) { + string msg = "The number of lines and samples for the master reseaus are"; + msg += "not equal, the data file may be bad"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + for (int i=0; iPixelPitch(); + + PvlGroup refRes = labels.FindGroup("Reseaus",Pvl::Traverse); + PvlKeyword rline = refRes.FindKeyword("Line"); + PvlKeyword rsamp = refRes.FindKeyword("Sample"); + if (rline.Size() != rsamp.Size()) { + string msg = "The number of lines and samples for the refined reseaus are"; + msg += "not equal, the data file may be bad"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + for (int i=0; iFocalPlaneMap()->DetectorSampleOrigin(); + double focalLine = dy / p_pixelPitch + + p_camera->FocalPlaneMap()->DetectorLineOrigin(); + + // Find distance from input point to all nominal reseaus + double distances[p_numRes], wt[5]; + int closepts[5]; + double ldiffsq, sdiffsq; + for (int i=0; i 0.0) { + double scale = wt[0]; + double rfitlines[5], rfitsamps[5], mfitlines[5], mfitsamps[5]; + for (int ifpt = 0; ifpt < 5; ifpt++ ) { + int index = closepts[ifpt]; + rfitlines[ifpt] = p_rlines[index]; + rfitsamps[ifpt] = p_rsamps[index]; + mfitlines[ifpt] = p_mlines[index]; + mfitsamps[ifpt] = p_msamps[index]; + wt[ifpt] = scale/wt[ifpt]; + } + BasisFunction bsX("bilinearInterpX",3,3); + BasisFunction bsY("bilinearInterpY",3,3); + LeastSquares lsqX(bsX); + LeastSquares lsqY(bsY); + + vector known; + known.resize(3); + for (int i=0; i<5; i++) { + known[0] = 1.0; + known[1] = rfitsamps[i]; + known[2] = rfitlines[i]; + lsqX.AddKnown(known, mfitsamps[i], wt[i]); + lsqY.AddKnown(known, mfitlines[i], wt[i]); + } + lsqX.Solve(); + lsqY.Solve(); + + known[1] = focalSamp; + known[2] = focalLine; + + // Test to make sure the point is inside of the image + double undistortedFocalSamp = lsqX.Evaluate(known); + double undistortedFocalLine = lsqY.Evaluate(known); + if (undistortedFocalSamp < 0.5) return false; + if (undistortedFocalLine < 0.5) return false; + if (undistortedFocalSamp > p_undistortedSamps + 0.5) return false; + if (undistortedFocalLine > p_undistortedLines + 0.5) return false; + + // Convert undistorted sample, line position to an x,y position + p_undistortedFocalPlaneX = (undistortedFocalSamp - p_undistortedSamps + / 2.0) * p_pixelPitch; + p_undistortedFocalPlaneY = (undistortedFocalLine - p_undistortedLines + / 2.0) * p_pixelPitch; + } + else { // If the point passed in is a reseau... + int index = closepts[0]; + p_undistortedFocalPlaneX = (p_msamps[index] - p_undistortedSamps / 2.0) + * p_pixelPitch; + p_undistortedFocalPlaneY = (p_mlines[index] - p_undistortedLines / 2.0) + * p_pixelPitch; + } + return true; + } + + /** + * Finds the distorted x/y position of the given undistorted point + * + * @param ux The undistorted x position of the point + * @param uy The undistorted y position of the point + * + * @return bool Returns true if the distortion was completed successful, and + * false if it was not + */ + bool ReseauDistortionMap::SetUndistortedFocalPlane(const double ux, + const double uy) { + p_undistortedFocalPlaneX = ux; + p_undistortedFocalPlaneY = uy; + + // Convert undistorted values to sample, line positions + double undistortedFocalSamp = ux / p_pixelPitch + p_undistortedSamps / 2.0; + double undistortedFocalLine = uy / p_pixelPitch + p_undistortedLines / 2.0; + + // Find distance from input point to all nominal reseaus + double distances[p_numRes], wt[5]; + int closepts[5]; + double ldiffsq, sdiffsq; + for (int i=0; i 0.0) { + double scale = wt[0]; + double rfitlines[5], rfitsamps[5], mfitlines[5], mfitsamps[5]; + for (int ifpt = 0; ifpt < 5; ifpt++ ) { + int index = closepts[ifpt]; + mfitlines[ifpt] = p_mlines[index]; + mfitsamps[ifpt] = p_msamps[index]; + rfitlines[ifpt] = p_rlines[index]; + rfitsamps[ifpt] = p_rsamps[index]; + wt[ifpt] = scale/wt[ifpt]; + } + BasisFunction bsX("bilinearInterpX",3,3); + BasisFunction bsY("bilinearInterpY",3,3); + LeastSquares lsqX(bsX); + LeastSquares lsqY(bsY); + + vector known; + known.resize(3); + for (int i=0; i<5; i++) { + known[0] = 1.0; + known[1] = mfitsamps[i]; + known[2] = mfitlines[i]; + lsqX.AddKnown(known, rfitsamps[i], wt[i]); + lsqY.AddKnown(known, rfitlines[i], wt[i]); + } + lsqX.Solve(); + lsqY.Solve(); + + known[1] = undistortedFocalSamp; + known[2] = undistortedFocalLine; + + // Test points to make sure they are in the image + double distortedFocalSamp = lsqX.Evaluate(known); + double distortedFocalLine = lsqY.Evaluate(known); + if (distortedFocalSamp < 0.5) return false; + if (distortedFocalLine < 0.5) return false; + if (distortedFocalSamp > p_undistortedSamps + 0.5) return false; + if (distortedFocalLine > p_undistortedLines + 0.5) return false; + + // Convert distorted sample, line position back to an x,y position + p_focalPlaneX = (distortedFocalSamp - + p_camera->FocalPlaneMap()->DetectorSampleOrigin()) * p_pixelPitch; + p_focalPlaneY = (distortedFocalLine - + p_camera->FocalPlaneMap()->DetectorLineOrigin()) * p_pixelPitch; + } + + else { // If the point passed in is a reseau... + int index = closepts[0]; + p_focalPlaneX = (p_rsamps[index] - + p_camera->FocalPlaneMap()->DetectorSampleOrigin()) * p_pixelPitch; + p_focalPlaneY = (p_rlines[index] - + p_camera->FocalPlaneMap()->DetectorLineOrigin()) * p_pixelPitch; + } + return true; + } + +} // end namespace isis diff --git a/isis/src/base/objs/ReseauDistortionMap/ReseauDistortionMap.h b/isis/src/base/objs/ReseauDistortionMap/ReseauDistortionMap.h new file mode 100644 index 0000000000000000000000000000000000000000..bf76b295a434e6c94941c2b0dfcc90a8a1321e52 --- /dev/null +++ b/isis/src/base/objs/ReseauDistortionMap/ReseauDistortionMap.h @@ -0,0 +1,64 @@ +#ifndef ReseauDistortionMap_h +#define ReseauDistortionMap_h +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:09 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "CameraDistortionMap.h" + +namespace Isis { + /** + * Distort/undistort focal plane coordinates + * + * Creates a map for adding/removing optical distortions + * from the focal plane of the camera. + * + * @ingroup Camera + * + * @author 2005-06-08 Elizabeth Ribelin + * + * @internal + * @history 2005-12-07 Elizabeth Miller - Added check for colinearity in + * closest reseaus to fix a bug + */ + class ReseauDistortionMap : public CameraDistortionMap { + public: + ReseauDistortionMap(Camera *parent, Pvl &labels, const std::string &fname); + + virtual bool SetFocalPlane(const double dx, const double dy); + + virtual bool SetUndistortedFocalPlane(const double ux, const double uy); + + private: + std::vector p_rlines, p_rsamps; //! p_mlines, p_msamps; //! +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/SampleManager/Makefile b/isis/src/base/objs/SampleManager/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5a03da41e9b2cfe0f4d15724027b78f99fe44bc4 --- /dev/null +++ b/isis/src/base/objs/SampleManager/Makefile @@ -0,0 +1,5 @@ +INCS = SampleManager.h +SRCS = SampleManager.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/SampleManager/SampleManager.cpp b/isis/src/base/objs/SampleManager/SampleManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3187e3a16ed6af430f8fd52841208305725bd67 --- /dev/null +++ b/isis/src/base/objs/SampleManager/SampleManager.cpp @@ -0,0 +1,72 @@ + +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/18 18:32:45 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "SampleManager.h" + +using namespace std; +namespace Isis { + + /** + * Constructs a SampleManager object + * + * @param cube The cube this buffer manager will be associated with. + * + * @param reverse Modifies the order of progression + * SampleManager takes through the cube. By + * default, progresses samples first then bands. If + * reverse = true, then the buffer progresses bands + * first, then samples. + */ + + SampleManager::SampleManager(const Isis::Cube &cube, const bool reverse) : + Isis::BufferManager(cube.Samples(),cube.Lines(), + cube.Bands(),1,cube.Lines(),1, + cube.PixelType(), reverse ) { + } + + /** + * Positions the buffer at the requested line and returns a status indicator + * if the set was succesful or not + * + * @param sample The sample number within a band (1-based). + * @param band The band number within the cube (1-based). Defaults to 1 + * + * @return bool Status indicator of the set being successful or not + */ + + bool SampleManager::SetSample (const int sample, const int band) { + if (sample < 1) { + string message = "Invalid value for argument [sample]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + if (band < 1) { + string message = "Invalid value for argument [band]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + int map = (band - 1) * MaxSamples() + sample - 1; + return setpos(map); + } + +} // end namespace isis diff --git a/isis/src/base/objs/SampleManager/SampleManager.h b/isis/src/base/objs/SampleManager/SampleManager.h new file mode 100644 index 0000000000000000000000000000000000000000..27278f82d942359d7b16cfa5d18f47f3fed67182 --- /dev/null +++ b/isis/src/base/objs/SampleManager/SampleManager.h @@ -0,0 +1,64 @@ +#ifndef SampleManager_h +#define SampleManager_h + +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/18 18:32:45 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "BufferManager.h" +#include "Cube.h" + +namespace Isis { +/** + * @brief Buffer manager, for moving through a cube in samples + * + * This class is used as a manager for moving through a cube one + * sample buffer at a time. A sample buffer is defined as a one + * dimensional sub-area of a cube. That is, the number of + * lines by 1 sample by 1 band (1,nl,1). The manager moves this + * (1,nl,1) shape through the cube sequentially accessing all + * the sample buffer in the first band before proceeding to the + * second band. + * + * @ingroup LowLevelCubeIO + * + * @author 2007-12-06 Christopher Austin + * + * @internal + * @history 2007-12-06 Christopher Austin Original Version + * @history 2008-06-18 Steven Lambright Fixed documentation + * + */ + class SampleManager : public Isis::BufferManager { + + public: + // Constructors and Destructors + SampleManager(const Isis::Cube &cube, const bool reverse=false); + + //! Destroys the SampleManager object + ~SampleManager() {}; + + bool SetSample(const int sample, const int band=1 ); + }; +}; + +#endif + diff --git a/isis/src/base/objs/SampleManager/SampleManager.truth b/isis/src/base/objs/SampleManager/SampleManager.truth new file mode 100644 index 0000000000000000000000000000000000000000..f774d8240d8429959508a40531bf326ea2747f5f --- /dev/null +++ b/isis/src/base/objs/SampleManager/SampleManager.truth @@ -0,0 +1,520 @@ +Buffer Size: 1 126 1 + + Current sample, line, band is: 1 1 1 + Current sample, line, band is: 2 1 1 + Current sample, line, band is: 3 1 1 + Current sample, line, band is: 4 1 1 + Current sample, line, band is: 5 1 1 + Current sample, line, band is: 6 1 1 + Current sample, line, band is: 7 1 1 + Current sample, line, band is: 8 1 1 + Current sample, line, band is: 9 1 1 + Current sample, line, band is: 10 1 1 + Current sample, line, band is: 11 1 1 + Current sample, line, band is: 12 1 1 + Current sample, line, band is: 13 1 1 + Current sample, line, band is: 14 1 1 + Current sample, line, band is: 15 1 1 + Current sample, line, band is: 16 1 1 + Current sample, line, band is: 17 1 1 + Current sample, line, band is: 18 1 1 + Current sample, line, band is: 19 1 1 + Current sample, line, band is: 20 1 1 + Current sample, line, band is: 21 1 1 + Current sample, line, band is: 22 1 1 + Current sample, line, band is: 23 1 1 + Current sample, line, band is: 24 1 1 + Current sample, line, band is: 25 1 1 + Current sample, line, band is: 26 1 1 + Current sample, line, band is: 27 1 1 + Current sample, line, band is: 28 1 1 + Current sample, line, band is: 29 1 1 + Current sample, line, band is: 30 1 1 + Current sample, line, band is: 31 1 1 + Current sample, line, band is: 32 1 1 + Current sample, line, band is: 33 1 1 + Current sample, line, band is: 34 1 1 + Current sample, line, band is: 35 1 1 + Current sample, line, band is: 36 1 1 + Current sample, line, band is: 37 1 1 + Current sample, line, band is: 38 1 1 + Current sample, line, band is: 39 1 1 + Current sample, line, band is: 40 1 1 + Current sample, line, band is: 41 1 1 + Current sample, line, band is: 42 1 1 + Current sample, line, band is: 43 1 1 + Current sample, line, band is: 44 1 1 + Current sample, line, band is: 45 1 1 + Current sample, line, band is: 46 1 1 + Current sample, line, band is: 47 1 1 + Current sample, line, band is: 48 1 1 + Current sample, line, band is: 49 1 1 + Current sample, line, band is: 50 1 1 + Current sample, line, band is: 51 1 1 + Current sample, line, band is: 52 1 1 + Current sample, line, band is: 53 1 1 + Current sample, line, band is: 54 1 1 + Current sample, line, band is: 55 1 1 + Current sample, line, band is: 56 1 1 + Current sample, line, band is: 57 1 1 + Current sample, line, band is: 58 1 1 + Current sample, line, band is: 59 1 1 + Current sample, line, band is: 60 1 1 + Current sample, line, band is: 61 1 1 + Current sample, line, band is: 62 1 1 + Current sample, line, band is: 63 1 1 + Current sample, line, band is: 64 1 1 + Current sample, line, band is: 65 1 1 + Current sample, line, band is: 66 1 1 + Current sample, line, band is: 67 1 1 + Current sample, line, band is: 68 1 1 + Current sample, line, band is: 69 1 1 + Current sample, line, band is: 70 1 1 + Current sample, line, band is: 71 1 1 + Current sample, line, band is: 72 1 1 + Current sample, line, band is: 73 1 1 + Current sample, line, band is: 74 1 1 + Current sample, line, band is: 75 1 1 + Current sample, line, band is: 76 1 1 + Current sample, line, band is: 77 1 1 + Current sample, line, band is: 78 1 1 + Current sample, line, band is: 79 1 1 + Current sample, line, band is: 80 1 1 + Current sample, line, band is: 81 1 1 + Current sample, line, band is: 82 1 1 + Current sample, line, band is: 83 1 1 + Current sample, line, band is: 84 1 1 + Current sample, line, band is: 85 1 1 + Current sample, line, band is: 86 1 1 + Current sample, line, band is: 87 1 1 + Current sample, line, band is: 88 1 1 + Current sample, line, band is: 89 1 1 + Current sample, line, band is: 90 1 1 + Current sample, line, band is: 91 1 1 + Current sample, line, band is: 92 1 1 + Current sample, line, band is: 93 1 1 + Current sample, line, band is: 94 1 1 + Current sample, line, band is: 95 1 1 + Current sample, line, band is: 96 1 1 + Current sample, line, band is: 97 1 1 + Current sample, line, band is: 98 1 1 + Current sample, line, band is: 99 1 1 + Current sample, line, band is: 100 1 1 + Current sample, line, band is: 101 1 1 + Current sample, line, band is: 102 1 1 + Current sample, line, band is: 103 1 1 + Current sample, line, band is: 104 1 1 + Current sample, line, band is: 105 1 1 + Current sample, line, band is: 106 1 1 + Current sample, line, band is: 107 1 1 + Current sample, line, band is: 108 1 1 + Current sample, line, band is: 109 1 1 + Current sample, line, band is: 110 1 1 + Current sample, line, band is: 111 1 1 + Current sample, line, band is: 112 1 1 + Current sample, line, band is: 113 1 1 + Current sample, line, band is: 114 1 1 + Current sample, line, band is: 115 1 1 + Current sample, line, band is: 116 1 1 + Current sample, line, band is: 117 1 1 + Current sample, line, band is: 118 1 1 + Current sample, line, band is: 119 1 1 + Current sample, line, band is: 120 1 1 + Current sample, line, band is: 121 1 1 + Current sample, line, band is: 122 1 1 + Current sample, line, band is: 123 1 1 + Current sample, line, band is: 124 1 1 + Current sample, line, band is: 125 1 1 + Current sample, line, band is: 126 1 1 + Current sample, line, band is: 1 1 2 + Current sample, line, band is: 2 1 2 + Current sample, line, band is: 3 1 2 + Current sample, line, band is: 4 1 2 + Current sample, line, band is: 5 1 2 + Current sample, line, band is: 6 1 2 + Current sample, line, band is: 7 1 2 + Current sample, line, band is: 8 1 2 + Current sample, line, band is: 9 1 2 + Current sample, line, band is: 10 1 2 + Current sample, line, band is: 11 1 2 + Current sample, line, band is: 12 1 2 + Current sample, line, band is: 13 1 2 + Current sample, line, band is: 14 1 2 + Current sample, line, band is: 15 1 2 + Current sample, line, band is: 16 1 2 + Current sample, line, band is: 17 1 2 + Current sample, line, band is: 18 1 2 + Current sample, line, band is: 19 1 2 + Current sample, line, band is: 20 1 2 + Current sample, line, band is: 21 1 2 + Current sample, line, band is: 22 1 2 + Current sample, line, band is: 23 1 2 + Current sample, line, band is: 24 1 2 + Current sample, line, band is: 25 1 2 + Current sample, line, band is: 26 1 2 + Current sample, line, band is: 27 1 2 + Current sample, line, band is: 28 1 2 + Current sample, line, band is: 29 1 2 + Current sample, line, band is: 30 1 2 + Current sample, line, band is: 31 1 2 + Current sample, line, band is: 32 1 2 + Current sample, line, band is: 33 1 2 + Current sample, line, band is: 34 1 2 + Current sample, line, band is: 35 1 2 + Current sample, line, band is: 36 1 2 + Current sample, line, band is: 37 1 2 + Current sample, line, band is: 38 1 2 + Current sample, line, band is: 39 1 2 + Current sample, line, band is: 40 1 2 + Current sample, line, band is: 41 1 2 + Current sample, line, band is: 42 1 2 + Current sample, line, band is: 43 1 2 + Current sample, line, band is: 44 1 2 + Current sample, line, band is: 45 1 2 + Current sample, line, band is: 46 1 2 + Current sample, line, band is: 47 1 2 + Current sample, line, band is: 48 1 2 + Current sample, line, band is: 49 1 2 + Current sample, line, band is: 50 1 2 + Current sample, line, band is: 51 1 2 + Current sample, line, band is: 52 1 2 + Current sample, line, band is: 53 1 2 + Current sample, line, band is: 54 1 2 + Current sample, line, band is: 55 1 2 + Current sample, line, band is: 56 1 2 + Current sample, line, band is: 57 1 2 + Current sample, line, band is: 58 1 2 + Current sample, line, band is: 59 1 2 + Current sample, line, band is: 60 1 2 + Current sample, line, band is: 61 1 2 + Current sample, line, band is: 62 1 2 + Current sample, line, band is: 63 1 2 + Current sample, line, band is: 64 1 2 + Current sample, line, band is: 65 1 2 + Current sample, line, band is: 66 1 2 + Current sample, line, band is: 67 1 2 + Current sample, line, band is: 68 1 2 + Current sample, line, band is: 69 1 2 + Current sample, line, band is: 70 1 2 + Current sample, line, band is: 71 1 2 + Current sample, line, band is: 72 1 2 + Current sample, line, band is: 73 1 2 + Current sample, line, band is: 74 1 2 + Current sample, line, band is: 75 1 2 + Current sample, line, band is: 76 1 2 + Current sample, line, band is: 77 1 2 + Current sample, line, band is: 78 1 2 + Current sample, line, band is: 79 1 2 + Current sample, line, band is: 80 1 2 + Current sample, line, band is: 81 1 2 + Current sample, line, band is: 82 1 2 + Current sample, line, band is: 83 1 2 + Current sample, line, band is: 84 1 2 + Current sample, line, band is: 85 1 2 + Current sample, line, band is: 86 1 2 + Current sample, line, band is: 87 1 2 + Current sample, line, band is: 88 1 2 + Current sample, line, band is: 89 1 2 + Current sample, line, band is: 90 1 2 + Current sample, line, band is: 91 1 2 + Current sample, line, band is: 92 1 2 + Current sample, line, band is: 93 1 2 + Current sample, line, band is: 94 1 2 + Current sample, line, band is: 95 1 2 + Current sample, line, band is: 96 1 2 + Current sample, line, band is: 97 1 2 + Current sample, line, band is: 98 1 2 + Current sample, line, band is: 99 1 2 + Current sample, line, band is: 100 1 2 + Current sample, line, band is: 101 1 2 + Current sample, line, band is: 102 1 2 + Current sample, line, band is: 103 1 2 + Current sample, line, band is: 104 1 2 + Current sample, line, band is: 105 1 2 + Current sample, line, band is: 106 1 2 + Current sample, line, band is: 107 1 2 + Current sample, line, band is: 108 1 2 + Current sample, line, band is: 109 1 2 + Current sample, line, band is: 110 1 2 + Current sample, line, band is: 111 1 2 + Current sample, line, band is: 112 1 2 + Current sample, line, band is: 113 1 2 + Current sample, line, band is: 114 1 2 + Current sample, line, band is: 115 1 2 + Current sample, line, band is: 116 1 2 + Current sample, line, band is: 117 1 2 + Current sample, line, band is: 118 1 2 + Current sample, line, band is: 119 1 2 + Current sample, line, band is: 120 1 2 + Current sample, line, band is: 121 1 2 + Current sample, line, band is: 122 1 2 + Current sample, line, band is: 123 1 2 + Current sample, line, band is: 124 1 2 + Current sample, line, band is: 125 1 2 + Current sample, line, band is: 126 1 2 + +Buffer Size: 1 126 1 + + Current sample, line, band is: 1 1 1 + Current sample, line, band is: 1 1 2 + Current sample, line, band is: 2 1 1 + Current sample, line, band is: 2 1 2 + Current sample, line, band is: 3 1 1 + Current sample, line, band is: 3 1 2 + Current sample, line, band is: 4 1 1 + Current sample, line, band is: 4 1 2 + Current sample, line, band is: 5 1 1 + Current sample, line, band is: 5 1 2 + Current sample, line, band is: 6 1 1 + Current sample, line, band is: 6 1 2 + Current sample, line, band is: 7 1 1 + Current sample, line, band is: 7 1 2 + Current sample, line, band is: 8 1 1 + Current sample, line, band is: 8 1 2 + Current sample, line, band is: 9 1 1 + Current sample, line, band is: 9 1 2 + Current sample, line, band is: 10 1 1 + Current sample, line, band is: 10 1 2 + Current sample, line, band is: 11 1 1 + Current sample, line, band is: 11 1 2 + Current sample, line, band is: 12 1 1 + Current sample, line, band is: 12 1 2 + Current sample, line, band is: 13 1 1 + Current sample, line, band is: 13 1 2 + Current sample, line, band is: 14 1 1 + Current sample, line, band is: 14 1 2 + Current sample, line, band is: 15 1 1 + Current sample, line, band is: 15 1 2 + Current sample, line, band is: 16 1 1 + Current sample, line, band is: 16 1 2 + Current sample, line, band is: 17 1 1 + Current sample, line, band is: 17 1 2 + Current sample, line, band is: 18 1 1 + Current sample, line, band is: 18 1 2 + Current sample, line, band is: 19 1 1 + Current sample, line, band is: 19 1 2 + Current sample, line, band is: 20 1 1 + Current sample, line, band is: 20 1 2 + Current sample, line, band is: 21 1 1 + Current sample, line, band is: 21 1 2 + Current sample, line, band is: 22 1 1 + Current sample, line, band is: 22 1 2 + Current sample, line, band is: 23 1 1 + Current sample, line, band is: 23 1 2 + Current sample, line, band is: 24 1 1 + Current sample, line, band is: 24 1 2 + Current sample, line, band is: 25 1 1 + Current sample, line, band is: 25 1 2 + Current sample, line, band is: 26 1 1 + Current sample, line, band is: 26 1 2 + Current sample, line, band is: 27 1 1 + Current sample, line, band is: 27 1 2 + Current sample, line, band is: 28 1 1 + Current sample, line, band is: 28 1 2 + Current sample, line, band is: 29 1 1 + Current sample, line, band is: 29 1 2 + Current sample, line, band is: 30 1 1 + Current sample, line, band is: 30 1 2 + Current sample, line, band is: 31 1 1 + Current sample, line, band is: 31 1 2 + Current sample, line, band is: 32 1 1 + Current sample, line, band is: 32 1 2 + Current sample, line, band is: 33 1 1 + Current sample, line, band is: 33 1 2 + Current sample, line, band is: 34 1 1 + Current sample, line, band is: 34 1 2 + Current sample, line, band is: 35 1 1 + Current sample, line, band is: 35 1 2 + Current sample, line, band is: 36 1 1 + Current sample, line, band is: 36 1 2 + Current sample, line, band is: 37 1 1 + Current sample, line, band is: 37 1 2 + Current sample, line, band is: 38 1 1 + Current sample, line, band is: 38 1 2 + Current sample, line, band is: 39 1 1 + Current sample, line, band is: 39 1 2 + Current sample, line, band is: 40 1 1 + Current sample, line, band is: 40 1 2 + Current sample, line, band is: 41 1 1 + Current sample, line, band is: 41 1 2 + Current sample, line, band is: 42 1 1 + Current sample, line, band is: 42 1 2 + Current sample, line, band is: 43 1 1 + Current sample, line, band is: 43 1 2 + Current sample, line, band is: 44 1 1 + Current sample, line, band is: 44 1 2 + Current sample, line, band is: 45 1 1 + Current sample, line, band is: 45 1 2 + Current sample, line, band is: 46 1 1 + Current sample, line, band is: 46 1 2 + Current sample, line, band is: 47 1 1 + Current sample, line, band is: 47 1 2 + Current sample, line, band is: 48 1 1 + Current sample, line, band is: 48 1 2 + Current sample, line, band is: 49 1 1 + Current sample, line, band is: 49 1 2 + Current sample, line, band is: 50 1 1 + Current sample, line, band is: 50 1 2 + Current sample, line, band is: 51 1 1 + Current sample, line, band is: 51 1 2 + Current sample, line, band is: 52 1 1 + Current sample, line, band is: 52 1 2 + Current sample, line, band is: 53 1 1 + Current sample, line, band is: 53 1 2 + Current sample, line, band is: 54 1 1 + Current sample, line, band is: 54 1 2 + Current sample, line, band is: 55 1 1 + Current sample, line, band is: 55 1 2 + Current sample, line, band is: 56 1 1 + Current sample, line, band is: 56 1 2 + Current sample, line, band is: 57 1 1 + Current sample, line, band is: 57 1 2 + Current sample, line, band is: 58 1 1 + Current sample, line, band is: 58 1 2 + Current sample, line, band is: 59 1 1 + Current sample, line, band is: 59 1 2 + Current sample, line, band is: 60 1 1 + Current sample, line, band is: 60 1 2 + Current sample, line, band is: 61 1 1 + Current sample, line, band is: 61 1 2 + Current sample, line, band is: 62 1 1 + Current sample, line, band is: 62 1 2 + Current sample, line, band is: 63 1 1 + Current sample, line, band is: 63 1 2 + Current sample, line, band is: 64 1 1 + Current sample, line, band is: 64 1 2 + Current sample, line, band is: 65 1 1 + Current sample, line, band is: 65 1 2 + Current sample, line, band is: 66 1 1 + Current sample, line, band is: 66 1 2 + Current sample, line, band is: 67 1 1 + Current sample, line, band is: 67 1 2 + Current sample, line, band is: 68 1 1 + Current sample, line, band is: 68 1 2 + Current sample, line, band is: 69 1 1 + Current sample, line, band is: 69 1 2 + Current sample, line, band is: 70 1 1 + Current sample, line, band is: 70 1 2 + Current sample, line, band is: 71 1 1 + Current sample, line, band is: 71 1 2 + Current sample, line, band is: 72 1 1 + Current sample, line, band is: 72 1 2 + Current sample, line, band is: 73 1 1 + Current sample, line, band is: 73 1 2 + Current sample, line, band is: 74 1 1 + Current sample, line, band is: 74 1 2 + Current sample, line, band is: 75 1 1 + Current sample, line, band is: 75 1 2 + Current sample, line, band is: 76 1 1 + Current sample, line, band is: 76 1 2 + Current sample, line, band is: 77 1 1 + Current sample, line, band is: 77 1 2 + Current sample, line, band is: 78 1 1 + Current sample, line, band is: 78 1 2 + Current sample, line, band is: 79 1 1 + Current sample, line, band is: 79 1 2 + Current sample, line, band is: 80 1 1 + Current sample, line, band is: 80 1 2 + Current sample, line, band is: 81 1 1 + Current sample, line, band is: 81 1 2 + Current sample, line, band is: 82 1 1 + Current sample, line, band is: 82 1 2 + Current sample, line, band is: 83 1 1 + Current sample, line, band is: 83 1 2 + Current sample, line, band is: 84 1 1 + Current sample, line, band is: 84 1 2 + Current sample, line, band is: 85 1 1 + Current sample, line, band is: 85 1 2 + Current sample, line, band is: 86 1 1 + Current sample, line, band is: 86 1 2 + Current sample, line, band is: 87 1 1 + Current sample, line, band is: 87 1 2 + Current sample, line, band is: 88 1 1 + Current sample, line, band is: 88 1 2 + Current sample, line, band is: 89 1 1 + Current sample, line, band is: 89 1 2 + Current sample, line, band is: 90 1 1 + Current sample, line, band is: 90 1 2 + Current sample, line, band is: 91 1 1 + Current sample, line, band is: 91 1 2 + Current sample, line, band is: 92 1 1 + Current sample, line, band is: 92 1 2 + Current sample, line, band is: 93 1 1 + Current sample, line, band is: 93 1 2 + Current sample, line, band is: 94 1 1 + Current sample, line, band is: 94 1 2 + Current sample, line, band is: 95 1 1 + Current sample, line, band is: 95 1 2 + Current sample, line, band is: 96 1 1 + Current sample, line, band is: 96 1 2 + Current sample, line, band is: 97 1 1 + Current sample, line, band is: 97 1 2 + Current sample, line, band is: 98 1 1 + Current sample, line, band is: 98 1 2 + Current sample, line, band is: 99 1 1 + Current sample, line, band is: 99 1 2 + Current sample, line, band is: 100 1 1 + Current sample, line, band is: 100 1 2 + Current sample, line, band is: 101 1 1 + Current sample, line, band is: 101 1 2 + Current sample, line, band is: 102 1 1 + Current sample, line, band is: 102 1 2 + Current sample, line, band is: 103 1 1 + Current sample, line, band is: 103 1 2 + Current sample, line, band is: 104 1 1 + Current sample, line, band is: 104 1 2 + Current sample, line, band is: 105 1 1 + Current sample, line, band is: 105 1 2 + Current sample, line, band is: 106 1 1 + Current sample, line, band is: 106 1 2 + Current sample, line, band is: 107 1 1 + Current sample, line, band is: 107 1 2 + Current sample, line, band is: 108 1 1 + Current sample, line, band is: 108 1 2 + Current sample, line, band is: 109 1 1 + Current sample, line, band is: 109 1 2 + Current sample, line, band is: 110 1 1 + Current sample, line, band is: 110 1 2 + Current sample, line, band is: 111 1 1 + Current sample, line, band is: 111 1 2 + Current sample, line, band is: 112 1 1 + Current sample, line, band is: 112 1 2 + Current sample, line, band is: 113 1 1 + Current sample, line, band is: 113 1 2 + Current sample, line, band is: 114 1 1 + Current sample, line, band is: 114 1 2 + Current sample, line, band is: 115 1 1 + Current sample, line, band is: 115 1 2 + Current sample, line, band is: 116 1 1 + Current sample, line, band is: 116 1 2 + Current sample, line, band is: 117 1 1 + Current sample, line, band is: 117 1 2 + Current sample, line, band is: 118 1 1 + Current sample, line, band is: 118 1 2 + Current sample, line, band is: 119 1 1 + Current sample, line, band is: 119 1 2 + Current sample, line, band is: 120 1 1 + Current sample, line, band is: 120 1 2 + Current sample, line, band is: 121 1 1 + Current sample, line, band is: 121 1 2 + Current sample, line, band is: 122 1 1 + Current sample, line, band is: 122 1 2 + Current sample, line, band is: 123 1 1 + Current sample, line, band is: 123 1 2 + Current sample, line, band is: 124 1 1 + Current sample, line, band is: 124 1 2 + Current sample, line, band is: 125 1 1 + Current sample, line, band is: 125 1 2 + Current sample, line, band is: 126 1 1 + Current sample, line, band is: 126 1 2 + + Current sample, line, band is: 50 1 1 + + Current sample, line, band is: 25 1 2 + +Testing errors ... +**PROGRAMMER ERROR** Invalid value for argument [sample] + +Testing errors ... +**PROGRAMMER ERROR** Invalid value for argument [band] + diff --git a/isis/src/base/objs/SampleManager/unitTest.cpp b/isis/src/base/objs/SampleManager/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c26afcd08c96a6b57e3f745a10d21c97470f587f --- /dev/null +++ b/isis/src/base/objs/SampleManager/unitTest.cpp @@ -0,0 +1,82 @@ +#include +#include +#include + +#include "Preference.h" +#include "iException.h" +#include "Cube.h" +#include "SampleManager.h" + +using namespace std; +int main (int argc, char *argv[]) { + + Isis::Preference::Preferences(true); + + string fname = "$base/testData/isisTruth.cub"; + Isis::Cube cube; + cube.Open (fname); + + Isis::SampleManager sample(cube); + cout << "Buffer Size: " << + sample.SampleDimension() << " " << + sample.LineDimension() << " " << + sample.BandDimension() << endl; + cout << endl; + + for (sample.begin(); !sample.end(); sample++) { + cout << " Current sample, line, band is: " + << sample.Sample() << " " + << sample.Line() << " " + << sample.Band() << endl; + } + cout << endl; + + Isis::SampleManager sampleReverse(cube,true); + cout << "Buffer Size: " << + sampleReverse.SampleDimension() << " " << + sampleReverse.LineDimension() << " " << + sampleReverse.BandDimension() << endl; + cout << endl; + + for (sampleReverse.begin(); !sampleReverse.end(); sampleReverse++) { + cout << " Current sample, line, band is: " + << sampleReverse.Sample() << " " + << sampleReverse.Line() << " " + << sampleReverse.Band() << endl; + } + cout << endl; + + sample.SetSample(50); + cout << " Current sample, line, band is: " + << sample.Sample() << " " + << sample.Line() << " " + << sample.Band() << endl; + cout << endl; + + sampleReverse.SetSample(50); + cout << " Current sample, line, band is: " + << sampleReverse.Sample() << " " + << sampleReverse.Line() << " " + << sampleReverse.Band() << endl; + cout << endl; + + try { + cout << "Testing errors ... " << endl; + sample.SetSample(0,0); + } + catch (Isis::iException &e) { + e.Report(false); + cout << endl; + } + + try { + cout << "Testing errors ... " << endl; + sample.SetSample(1,0); + } + catch (Isis::iException &e) { + e.Report(false); + cout << endl; + } + + cube.Close (); +} diff --git a/isis/src/base/objs/Sensor/Makefile b/isis/src/base/objs/Sensor/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..eecadbc4c50f6d1829d6248339e4da65e4ac0688 --- /dev/null +++ b/isis/src/base/objs/Sensor/Makefile @@ -0,0 +1,5 @@ +INCS = Sensor.h +SRCS = Sensor.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Sensor/Sensor.cpp b/isis/src/base/objs/Sensor/Sensor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f02d1a37761adcae03c72595ecfec1b65ed9266e --- /dev/null +++ b/isis/src/base/objs/Sensor/Sensor.cpp @@ -0,0 +1,618 @@ +/** + * @file + * $Revision: 1.17 $ + * $Date: 2010/05/22 00:08:59 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Sensor.h" +#include "CubeManager.h" +#include "iString.h" +#include "iException.h" +#include "iException.h" +#include "Constants.h" +#include "SpecialPixel.h" +#include + +using namespace std; +namespace Isis { + + /** + * Constructs a Sensor object and loads SPICE kernels using information from + * the label object. The constructor expects an Instrument and Kernels group + * to be in the labels (see Spice documentation). + * + * @param lab Label containing Instrument and Kernels groups. + */ + Sensor::Sensor(Isis::Pvl &lab) : Isis::Spice(lab) { + // Assume no shape model + p_hasElevationModel = false; + p_demProj = NULL; + p_demCube = NULL; + p_interp = NULL; + p_portal = NULL; + string demCube = ""; + + // Do we have one + Isis::PvlGroup &kernels = lab.FindGroup("Kernels", Isis::Pvl::Traverse); + if(kernels.HasKeyword("ElevationModel") && + !kernels["ElevationModel"].IsNull() && + !IsSky()) { + demCube = (string) kernels["ElevationModel"]; + } + else if(kernels.HasKeyword("ShapeModel") && + !kernels["ShapeModel"].IsNull() && + !IsSky()) { + demCube = (string) kernels["ShapeModel"]; + } + + if(demCube != "") { + p_hasElevationModel = true; + p_demCube = CubeManager::Open(demCube); + p_demProj = Isis::ProjectionFactory::CreateFromCube(*(p_demCube->Label())); + + p_interp = new Isis::Interpolator(Interpolator::BiLinearType); + p_portal = new Isis::Portal(p_interp->Samples(), p_interp->Lines(), + p_demCube->PixelType(), + p_interp->HotSample(), p_interp->HotLine()); + } + + // No intersection with the target yet + p_hasIntersection = false; + } + + //! Destroys the Sensor + Sensor::~Sensor() { + if(p_demProj) { + delete p_demProj; + p_demProj = NULL; + } + + // we do not have ownership of p_demCube + p_demCube = NULL; + + if(p_interp) { + delete p_interp; + p_interp = NULL; + } + + if(p_portal) { + delete p_portal; + p_portal = NULL; + } + } + + /** + * This allows you to ignore the elevation model + * + * @param ignore True for no elevation model + */ + void Sensor::IgnoreElevationModel(bool ignore) { + // if we have an elevation model and are not ignoring it, + // set p_hasElevationModel to true + if(p_demProj && !ignore) { + p_hasElevationModel = true; + } + else { + p_hasElevationModel = false; + } + } + + /** + * By setting the ephemeris time you essential set the position of the + * spacecraft and body as indicated in the class Spice. However, after this + * is invoked there will be no intersection point until SetLookDirection or + * SetUniversalGround is invoked. + * + * @param time Ephemeris time (read NAIF documentation for a detailed + * description) + */ + void Sensor::SetEphemerisTime(const double time) { + Isis::Spice::SetEphemerisTime(time); + p_hasIntersection = false; + } + + /** + * Sets the look direction of the spacecraft. This routine will then attempt to + * intersect the look direction with the target. If successful you can utilize + * the methods which return the lat/lon, phase, incidence, etc. This routine + * returns false if the look direction does not intersect the target. + * + * @param v[] A look vector in camera coordinates. For example, (0,0,1) is + * usually the look direction out of the boresight of a camera. + * + * history 2009-09-23 Tracie Sucharski - Convert negative longitudes + * returned my reclat. + * @return bool + */ + bool Sensor::SetLookDirection(const double v[3]) { + // The look vector must be in the camera coordinate system + vector lookC(3); + lookC[0] = v[0]; + lookC[1] = v[1]; + lookC[2] = v[2]; + + // Convert it to body-fixed + vector lookJ = InstrumentRotation()->J2000Vector(lookC); + vector lookB = BodyRotation()->ReferenceVector(lookJ); + p_lookB[0] = lookB[0]; + p_lookB[1] = lookB[1]; + p_lookB[2] = lookB[2]; + p_newLookB = true; + + // Don't try to intersect the sky + if(IsSky()) { + p_hasIntersection = false; + return p_hasIntersection; + } + + // Prep for surfpt by obtaining the radii + SpiceDouble a, b, c; + a = p_radii[0]; + b = p_radii[1]; + c = p_radii[2]; + + // See if it intersects the planet + SpiceBoolean found; + std::vector sB = BodyRotation()->ReferenceVector(InstrumentPosition()->Coordinate()); + surfpt_c((SpiceDouble *) &sB[0], p_lookB, a, b, c, p_pB, &found); + if(!found) { + p_hasIntersection = false; + return p_hasIntersection; + } + + // If we have a dem kernel then we should iterate until + // the point converges + if(p_hasElevationModel) { + // Set hasIntersection flag to true so Resolution can be calculated + p_hasIntersection = true; + int maxit = 100; + int it = 1; + bool done = false; + SpiceDouble pB[3]; + while(!done) { + if(it > maxit) { + p_hasIntersection = false; + return p_hasIntersection; + } + // Set the tolerance for 1/100 of a pixel in meters + double tolerance = Resolution() / 100.0; + double lat, lon, radius; + reclat_c(p_pB, &radius, &lon, &lat); + lat *= 180.0 / Isis::PI; + lon *= 180.0 / Isis::PI; + if(lon < 0.0) lon += 360.0; + + if(it == 1) { + p_radius = DemRadius(lat, lon); + } + else { + double demRadius = DemRadius(lat, lon); + + if(!Isis::IsSpecial(demRadius)) { + p_radius = (p_radius + demRadius) / 2.0; + } + } + + if(Isis::IsSpecial(p_radius)) { + p_hasIntersection = false; + return p_hasIntersection; + } + + pB[0] = p_pB[0]; + pB[1] = p_pB[1]; + pB[2] = p_pB[2]; + surfpt_c((SpiceDouble *)&sB[0], p_lookB, p_radius, p_radius, p_radius, + p_pB, &found); + if(!found) { + p_hasIntersection = false; + return p_hasIntersection; + } + + double dist = sqrt((pB[0] - p_pB[0]) * (pB[0] - p_pB[0]) + + (pB[1] - p_pB[1]) * (pB[1] - p_pB[1]) + + (pB[2] - p_pB[2]) * (pB[2] - p_pB[2])) * 1000.; + if(dist < tolerance) { + // Now recompute tolerance at updated surface point and recheck + double tolerance = Resolution() / 100.0; + if(dist < tolerance) done = true; + } + + it++; + } + } + + // Convert x/y/z to lat/lon and radius + p_hasIntersection = true; + reclat_c(p_pB, &p_radius, &p_longitude, &p_latitude); + p_latitude *= 180.0 / Isis::PI; + p_longitude *= 180.0 / Isis::PI; + while(p_longitude < 0.0) p_longitude += 360.0; + while(p_longitude > 360.0) p_longitude -= 360.0; + return p_hasIntersection; + } + + /** + * Returns the x,y,z of the surface intersection in BodyFixed km. + * + * @param p[] The coordinate of the surface intersection + */ + void Sensor::Coordinate(double p[3]) const { + p[0] = p_pB[0]; + p[1] = p_pB[1]; + p[2] = p_pB[2]; + } + + /** + * Returns the phase angle in degrees. This does not use the surface model. + * + * @return double + */ + double Sensor::PhaseAngle() const { + SpiceDouble psB[3], upsB[3], dist; + std::vector sB = BodyRotation()->ReferenceVector(InstrumentPosition()->Coordinate()); + vsub_c((SpiceDouble *) &sB[0], p_pB, psB); + unorm_c(psB, upsB, &dist); + + SpiceDouble puB[3], upuB[3]; + vsub_c(p_uB, p_pB, puB); + unorm_c(puB, upuB, &dist); + + double angle = vdot_c(upsB, upuB); + if(angle > 1.0) return 0.0; + if(angle < -1.0) return 180.0; + return acos(angle) * 180.0 / Isis::PI; + } + + /** + * Returns the emission angle in degrees. This does not use the surface model. + * + * @return double + */ + double Sensor::EmissionAngle() const { + SpiceDouble psB[3], upsB[3], upB[3], dist; + std::vector sB = BodyRotation()->ReferenceVector(InstrumentPosition()->Coordinate()); + vsub_c((SpiceDouble *) &sB[0], p_pB, psB); + unorm_c(psB, upsB, &dist); + unorm_c(p_pB, upB, &dist); + + double angle = vdot_c(upB, upsB); + if(angle > 1.0) return 0.0; + if(angle < -1.0) return 180.0; + return acos(angle) * 180.0 / Isis::PI; + } + + /** + * Returns the incidence angle in degrees. This does not use the surface model. + * + * @return double + */ + double Sensor::IncidenceAngle() const { + SpiceDouble puB[3], upuB[3], upB[3], dist; + vsub_c(p_uB, p_pB, puB); + unorm_c(puB, upuB, &dist); + unorm_c(p_pB, upB, &dist); + + double angle = vdot_c(upB, upuB); + if(angle > 1.0) return 0.0; + if(angle < -1.0) return 180.0; + return acos(angle) * 180.0 / Isis::PI; + } + + /** + * This is the opposite routine for SetLookDirection. Instead of computing a + * point on the target, a point is set and the look direction is computed. + * Other methods such as lat/lon, phase, incidence, etc. can be used if this + * method returns a true. + * + * @param latitude Planetocentric latitude + * + * @param longitude Positive east longitude + * + * @param backCheck If true this method will check the lat/lon point to see if + * it falls on the backside of the target (or beyond the + * horizon). If false this test will not occur. + * Defaults to true + * + * @return bool + */ + bool Sensor::SetUniversalGround(const double latitude, + const double longitude, bool backCheck) { + // Can't intersect the sky + if(IsSky()) { + p_hasIntersection = false; + return p_hasIntersection; + } + + // Load the latitude/longitude + p_latitude = latitude; + p_longitude = longitude; + + double lon = p_longitude * Isis::PI / 180.0; + double lat = p_latitude * Isis::PI / 180.0; + + if(p_hasElevationModel) { + p_radius = DemRadius(p_latitude, p_longitude); + if(Isis::IsSpecial(p_radius)) { + p_hasIntersection = false; + return p_hasIntersection; + } + } + else { + // Otherwise compute the local radius on the ellipsoid + double a = p_radii[0]; + double b = p_radii[1]; + double c = p_radii[2]; + double xyradius = a * b / sqrt(pow(b * cos(lon), 2) + pow(a * sin(lon), 2)); + p_radius = xyradius * c / sqrt(pow(c * cos(lat), 2) + pow(xyradius * sin(lat), 2)); + } + + return SetGroundLocal(backCheck); + } + + /** + * This overloaded method has the opposite function as SetLookDirection. Instead + * of computing a point on the target, a point is set and the look direction is + * computed. Other methods such as lat/lon, phase, incidence, etc. can be used if + * this method returns a true. + * + * @param latitude Planetocentric latitude in degrees + * + * @param longitude Positive east longitude in degrees + * + * @param radius Radius in meters + * + * @param backCheck If true this method will check the lat/lon point to see if + * it falls on the backside of the target (or beyond the + * horizon). If false this test will not occur. + * Defaults to true + * + * @return bool + */ + bool Sensor::SetUniversalGround(const double latitude, + const double longitude, + const double radius, bool backCheck) { + // Can't intersect the sky + if(IsSky()) { + p_hasIntersection = false; + return p_hasIntersection; + } + + // Load the latitude/longitude/radius + p_latitude = latitude; + p_longitude = longitude; + p_radius = radius / 1000.; + + return SetGroundLocal(backCheck); + } + + /** + * This method handles the common functions for the overloaded SetUniversalGround methods. + * Instead of computing a point on the target, a point is set (lat,lon,radius) and the look + * direction is computed. + * + * @param backCheck If true this method will check the lat/lon point to see if + * it falls on the backside of the target (or beyond the + * horizon). If false this test will not occur. + * Defaults to true + * + * @return bool + * + */ + bool Sensor::SetGroundLocal(bool backCheck) { + // With the 3 spherical value compute the x/y/z coordinate + latrec_c(p_radius, (p_longitude * Isis::PI / 180.0), (p_latitude * Isis::PI / 180.0), p_pB); + + // Make sure the point isn't on the backside of the body + std::vector sB = BodyRotation()->ReferenceVector(InstrumentPosition()->Coordinate()); + p_lookB[0] = p_pB[0] - sB[0]; + p_lookB[1] = p_pB[1] - sB[1]; + p_lookB[2] = p_pB[2] - sB[2]; + p_newLookB = true; + + // Get emission angle for testing to see if surface point is viewable + double emission = EmissionAngle(); + + // See if the point is on the backside of the target + if(backCheck) { + if(fabs(emission) > 90.) { + p_hasIntersection = false; + return p_hasIntersection; + } + } + + // return with success + p_hasIntersection = true; + return p_hasIntersection; + + } + + + + /** + * Returns the look direction in the camera coordinate system + * + * @param v[] The look vector + */ + void Sensor::LookDirection(double v[3]) const { + vector lookB(3); + lookB[0] = p_lookB[0]; + lookB[1] = p_lookB[1]; + lookB[2] = p_lookB[2]; + vector lookJ = BodyRotation()->J2000Vector(lookB); + vector lookC = InstrumentRotation()->ReferenceVector(lookJ); + v[0] = lookC[0]; + v[1] = lookC[1]; + v[2] = lookC[2]; + } + + /** + * Returns the right ascension angle (sky longitude) + */ + double Sensor::RightAscension() { + if(p_newLookB) computeRaDec(); + return p_ra; + } + + /** + * Returns the declination angle (sky latitude) + */ + double Sensor::Declination() { + if(p_newLookB) computeRaDec(); + return p_dec; + } + + /** + * Protected method which computes the ra/dec of the current look direction + */ + void Sensor::computeRaDec() { + p_newLookB = false; + vector lookB(3); + lookB[0] = p_lookB[0]; + lookB[1] = p_lookB[1]; + lookB[2] = p_lookB[2]; + vector lookJ = BodyRotation()->J2000Vector(lookB);; + + SpiceDouble range; + recrad_c((SpiceDouble *)&lookJ[0], &range, &p_ra, &p_dec); + p_ra *= 180.0 / Isis::PI; + p_dec *= 180.0 / Isis::PI; + } + + /** + * Given the ra/dec compute the look direction + * + * @param ra right ascension in degrees (sky longitude) + * @param dec declination in degrees (sky latitude) + * + * @returns success or failure + */ + bool Sensor::SetRightAscensionDeclination(const double ra, const double dec) { + vector lookJ(3); + radrec_c(1.0, ra * Isis::PI / 180.0, dec * Isis::PI / 180.0, (SpiceDouble *)&lookJ[0]); + + vector lookC = InstrumentRotation()->ReferenceVector(lookJ); + return SetLookDirection((double *)&lookC[0]); + } + + + //! Return the distance between the spacecraft and surface point in km + double Sensor::SlantDistance() const { + SpiceDouble psB[3], upsB[3]; + SpiceDouble dist; + + std::vector sB = BodyRotation()->ReferenceVector(InstrumentPosition()->Coordinate()); + vsub_c(p_pB, (SpiceDouble *) &sB[0], psB); + unorm_c(psB, upsB, &dist); + return dist; + } + + //! Return the local solar time in hours + double Sensor::LocalSolarTime() { + double slat, slon; + SubSolarPoint(slat, slon); + + double lst = UniversalLongitude() - slon + 180.0; + lst = lst / 15.0; // 15 degress per hour + if(lst < 0.0) lst += 24.0; + if(lst > 24.0) lst -= 24.0; + return lst; + } + + //! Returns the distance between the sun and surface point in AU + double Sensor::SolarDistance() const { + // Get the sun coord + double sB[3]; + Isis::Spice::SunPosition(sB); + + // Calc the change + double xChange = sB[0] - p_pB[0]; + double yChange = sB[1] - p_pB[1]; + double zChange = sB[2] - p_pB[2]; + + // Calc the distance and convert to AU + double dist = sqrt(pow(xChange, 2) + pow(yChange, 2) + pow(zChange, 2)); + dist /= 149597870.691; + return dist; + } + + /** + * Returns the distance from the spacecraft to the subspacecraft point in km. + * It uses the ellipsoid, not the shape model + */ + double Sensor::SpacecraftAltitude() { + // Get the spacecraft coord + double spB[3]; + Isis::Spice::InstrumentPosition(spB); + + // Get subspacecraft point + double lat, lon; + SubSpacecraftPoint(lat, lon); + double rlat = lat * Isis::PI / 180.0; + double rlon = lon * Isis::PI / 180.0; + + // Compute radius + double rad; + if(p_hasElevationModel) { + rad = DemRadius(lat, lon); + } + else { + double a = p_radii[0]; + double b = p_radii[1]; + double c = p_radii[2]; + double xyradius = a * b / sqrt(pow(b * cos(rlon), 2) + pow(a * sin(rlon), 2)); + rad = xyradius * c / sqrt(pow(c * cos(rlat), 2) + pow(xyradius * sin(rlat), 2)); + } + + // Now with the 3 spherical value compute the x/y/z coordinate + double ssB[3]; + latrec_c(rad, rlon, rlat, ssB); + + // Calc the change + double xChange = spB[0] - ssB[0]; + double yChange = spB[1] - ssB[1]; + double zChange = spB[2] - ssB[2]; + + // Calc the distance + double dist = sqrt(pow(xChange, 2) + pow(yChange, 2) + pow(zChange, 2)); + return dist; + } + + /** Grab the radius from the dem if we have one + */ + double Sensor::DemRadius(double lat, double lon) { + if(!p_hasElevationModel) return Isis::Null; + + p_demProj->SetUniversalGround(lat, lon); + if(!p_demProj->IsGood()) { + return Isis::Null; + } + + p_portal->SetPosition(p_demProj->WorldX(), p_demProj->WorldY(), 1); + p_demCube->Read(*p_portal); + + double radius = p_interp->Interpolate(p_demProj->WorldX(), p_demProj->WorldY(), + p_portal->DoubleBuffer()); + if(Isis::IsSpecial(radius)) { + return Isis::Null; + } + + return radius / 1000.0; + } + +} diff --git a/isis/src/base/objs/Sensor/Sensor.h b/isis/src/base/objs/Sensor/Sensor.h new file mode 100644 index 0000000000000000000000000000000000000000..d59ff5966532d9b3d72916f4a2b6d84eb1791939 --- /dev/null +++ b/isis/src/base/objs/Sensor/Sensor.h @@ -0,0 +1,226 @@ +#ifndef Sensor_h +#define Sensor_h +/** + * @file + * $Revision: 1.14 $ + * $Date: 2010/05/22 00:08:59 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Spice.h" +#include "Cube.h" +#include "ProjectionFactory.h" +#include "Portal.h" +#include "Interpolator.h" + +namespace Isis { + /** + * @brief Class for computing sensor ground coordinates + * + * The sensor class allows for the computation of parameters related to orbiting + * instruments. In particular, a time and look direction can be set and from + * those the ground coordinate (latitude/longitude) along with phase, incidence, + * and emission angles can be computed. Likewise, a ground point can be set and + * look direction can be computed. This class is derived from the Spice class. + * + * An important capability of this class is + * the ability to use a surface model other than an ellipsoid when intersecting + * the look direction of the sensor with the planetary body. This allows for the + * generation of othrorectified products. The file containing the surface model + * is a cube and is obtained from the labels in the follow form: + * @code + * Group = Kernels + * ElevationModel = file.cub + * EndGroup + * @endcode + * + * @ingroup SpiceInstrumentsAndCameras + * + * @author 2003-04-11 Jeff Anderson + * + * @internal + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-05-30 Jeff Anderson - Updated unitTest and truth to account + * for precision due to optimization + * @history 2003-10-16 Jeff Anderson - Added LoadEulerMounting and + * LoadFrameMounting methods + * @history 2003-11-26 Jeff Anderson - Modified FrameMounting methods to allow + * for fixed frames or time dependent + * frames + * @history 2004-01-14 Jeff Anderson - Remove an unused constructor + * @history 2004-01-20 Jeff Anderson - Added an option to the + * SetUniversalGround method to eliminate + * checks for points on the backside of the + * target + * @history 2004-02-18 Jeff Anderson - Fixed a problem with the FrameMounting + * methods as the frame kernel is + * unloaded if a cache is created. + * @history 2004-02-23 Jeff Anderson - Fixed two bugs in the handling of DEMs. + * Used universal lat/lon when appropriate + * and the radius needed to be converted + * to km when read from the DEM file. + * @history 2005-02-15 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-02-24 Jeff Anderson - Added SlantDistance method and made + * the constructor ignore the + * ElevationModel keyword if it is null + * @history 2005-02-25 Jeff Anderson - Added LocalSolarTime method + * @history 2005-06-09 Elizabeth Ribelin - Added LoadEulerMounting method that + * accepts a matrix as a parameter + * @history 2005-08-24 Jeff Anderson - Make sure LocalSolarTime always return + * positive hours + * @history 2005-09-20 Jeff Anderson - Added tests for trying to intersect the + * sky + * @history 2006-03-31 Elizabeth Miller - Added SpacecraftAltitude & + * SolarDistance methods + * @history 2006-09-07 Debbie A. Cook - Changed back-of-planet test to use + * emission angle instead of length + * of vector to surface point + * @history 2006-10-11 Jeff Anderson - Modified reading radius + * from dem using bilinear + * interpolation + * @history 2006-10-12 Jeff Anderson - Modified the + * SetLookDirection method + * to use the DEM (if + * available) when + * computing a ground point + * @history 2007-05-18 Jeff Anderson - Modify SpacecraftAltitude method + * to use DEM + * @history 2007-06-11 Debbie A. Cook - Added alternative method that includes radius + * @history 2007-08-24 Debbie A. Cook - Replaced references to p_sB since it was removed from Spice + * @history 2007-11-27 Debbie A. Cook - Added overloaded method SetUniversalGround(lat, lon, radius) + * @history 2008-05-21 Steven Lambright - CubeManager is now used to speed up DEM Cube I/O + * @history 2008-06-18 Debbie A. Cook - Made DemRadius radius public instead of private and added + * method HasElevationModel + * @history 2008-08-06 Stuart Sides - Modified SetLookDirection to better + * handle oblique views. In the past it would oscillate and run out + * out iterations. + * @history 2009-02-06 Debbie A. Cook - Changed the tolerance from 1e-6 to 1e-12 for dist**2 (mm) + * @history 2009-02-06 Debbie A. Cook - Changed the tolerance back to 1e-6 (mm) + * @history 2009-02-15 Debbie A. Cook - Added virtual Resolution method + * @history 2009-06-30 Steven Lambright - Added IgnoreElevationModel and fixed + * DemRadius + * @history 2009-07-09 Debbie A. Cook - Corrected documentation on Resolution method + * @history 2009-09-23 Tracie Sucharski - Convert negative longitudes + * returned by reclat in SetLookDirection. + * + */ + class Sensor : public Isis::Spice { + public: + Sensor(Isis::Pvl &lab); + + virtual ~Sensor(); + + void SetEphemerisTime(const double time); + bool SetLookDirection(const double v[3]); + bool SetRightAscensionDeclination(const double ra, const double dec); + bool SetUniversalGround(const double latitude, const double longitude, + bool backCheck = true); + bool SetUniversalGround(const double latitude, const double longitude, + const double radius, bool backCheck = true); + + /** + * Returns if the last call to either SetLookDirection or + * SetUniversalGround had a valid intersection with the target. If so then + * other methods such as Coordinate, UniversalLatitude, UniversalLongitude, + * etc can be used with confidence. + */ + inline bool HasSurfaceIntersection() const { + return p_hasIntersection; + }; + + void Coordinate(double p[3]) const; + + /** + * Returns the planetocentric latitude. + */ + inline double UniversalLatitude() const { + return p_latitude; + }; + + /** + * Returns a positive east, 0-360 domain longitude. + */ + inline double UniversalLongitude() const { + return p_longitude; + }; + + /** + * Returns the local radius at the intersection point. This is either the + * radius on the ellipsoid, the radius from the surface model passed into + * the constructor, or the radius set with SetUniversalGround. + */ + inline double LocalRadius() const { + return p_radius * 1000.0; + }; + + double PhaseAngle() const; + double EmissionAngle() const; + double IncidenceAngle() const; + void LookDirection(double v[3]) const; + + double RightAscension(); + double Declination(); + + double SlantDistance() const; + double LocalSolarTime(); + double SolarDistance() const; + double SpacecraftAltitude(); + double DemRadius(double lat, double lon); //! +#include +#include "Sensor.h" +#include "iException.h" +#include "Filename.h" + +#include "Preference.h" + +using namespace std; +/** + * UnitTest for Spice class. + * + * @internal + * @history 2009-03-24 Tracie Sucharski - Replace obsolete keywords + * SpacecraftPosition and SpacecraftPointing with InstrumentPosition + * and InstrumentPointing. + */ +int main(int argc, char *argv[]) { + + Isis::Preference::Preferences(true); + + try { + + cout << setprecision(9); + cout << "Unit test for Isis::Sensor" << endl; + + Isis::Pvl lab; + Isis::PvlGroup inst("INSTRUMENT"); + inst += Isis::PvlKeyword("TargetName", "Mars"); + lab.AddGroup(inst); + + Isis::PvlGroup kern("Kernels"); + Isis::Filename f("$base/testData/kernels"); + string dir = f.Expanded() + "/"; + + kern += Isis::PvlKeyword("NaifFrameCode", -94031); + kern += Isis::PvlKeyword("LeapSecond", dir + "naif0007.tls"); + kern += Isis::PvlKeyword("SpacecraftClock", dir + "MGS_SCLKSCET.00045.tsc"); + kern += Isis::PvlKeyword("TargetPosition", dir + "de405.bsp"); + kern += Isis::PvlKeyword("TargetAttitudeShape", dir + "pck00006.tpc"); + kern += Isis::PvlKeyword("Instrument", dir + "mocSensorUnitTest.ti"); +// kern += Isis::PvlKeyword("InstrumentAddendum",dir+"mocAddendum.ti"); + kern += Isis::PvlKeyword("InstrumentAddendum", ""); + kern += Isis::PvlKeyword("InstrumentPosition", dir + "moc.bsp"); + kern += Isis::PvlKeyword("InstrumentPointing", dir + "moc.bc"); + kern += Isis::PvlKeyword("Frame", ""); + lab.AddGroup(kern); + + // Setup + double startTime = -69382819.0; + double endTime = -69382512.0; + double slope = (endTime - startTime) / (10 - 1); + Isis::Sensor spi(lab); + spi.InstrumentRotation()->SetTimeBias(-1.15); + + double v[3] = { 0.0, 0.0, 1.0 }; + double p[3]; + + // Testing Set Look Direction + cout << "Test SetLookDirection" << endl; + for(int i = 0; i < 10; i++) { + double t = startTime + (double) i * slope; + spi.SetEphemerisTime(t); + cout << "Has Intersection = " << spi.HasSurfaceIntersection() << endl; + + spi.SetLookDirection(v); + cout << "Has Intersection = " << spi.HasSurfaceIntersection() << endl; + cout << "Latitude = " << spi.UniversalLatitude() << endl; + cout << "Longitude = " << spi.UniversalLongitude() << endl; + spi.Coordinate(p); + cout << "Point = " << p[0] << " " << p[1] << " " << p[2] << endl; + cout << "Local Radius = " << spi.LocalRadius() << endl; + cout << "Phase = " << spi.PhaseAngle() << endl; + cout << "Emission = " << spi.EmissionAngle() << endl; + cout << "Incidence = " << spi.IncidenceAngle() << endl; + spi.LookDirection(p); + cout << "Look Direction = " << p[0] << " " << p[1] << " " << p[2] << endl; + cout << "Slant Distance = " << spi.SlantDistance() << endl; + cout << "Local Solar Time = " << spi.LocalSolarTime() << endl; + cout << "Spacecraft Altitude = " << spi.SpacecraftAltitude() << endl; + cout << "Solar Distance = " << spi.SolarDistance() << endl; + } + cout << endl; + + // Test bad look direction + cout << "Test bad look direction" << endl; + p[0] = 0.0; + p[1] = 0.0; + p[2] = -1.0; + spi.SetLookDirection(p); + cout << "Has Intersection = " << spi.HasSurfaceIntersection() << endl; + cout << endl; + + // Test SetUniversalGround + cout << "Test SetUniversalGround (lat/lon only)" << endl; + spi.SetUniversalGround(11.57143551329, 223.328646604); + cout << "Has Intersection = " << spi.HasSurfaceIntersection() << endl; + cout << "Latitude = " << spi.UniversalLatitude() << endl; + cout << "Longitude = " << spi.UniversalLongitude() << endl; + spi.Coordinate(p); + cout << "Point = " << p[0] << " " << p[1] << " " << p[2] << endl; + cout << "Local Radius = " << spi.LocalRadius() << endl; + cout << "Phase = " << spi.PhaseAngle() << endl; + cout << "Emission = " << spi.EmissionAngle() << endl; + cout << "Incidence = " << spi.IncidenceAngle() << endl; + spi.LookDirection(p); + cout << "Look Direction = " << p[0] << " " << p[1] << " " << p[2] << endl; + cout << "Slant Distance = " << spi.SlantDistance() << endl; + cout << "Local Solar Time = " << spi.LocalSolarTime() << endl; + cout << "Spacecraft Altitude = " << spi.SpacecraftAltitude() << endl; + cout << "Solar Distance = " << spi.SolarDistance() << endl; + cout << endl; + + // Test SetUniversalGround + cout << "Test SetUniversalGround (lat/lon/radius)" << endl; + spi.SetUniversalGround(11.57143551329, 223.328646604, 3400.); + cout << "Has Intersection = " << spi.HasSurfaceIntersection() << endl; + cout << "Latitude = " << spi.UniversalLatitude() << endl; + cout << "Longitude = " << spi.UniversalLongitude() << endl; + cout << "Radius = " << spi.LocalRadius() << endl; + spi.Coordinate(p); + cout << "Point = " << p[0] << " " << p[1] << " " << p[2] << endl; + cout << "Local Radius = " << spi.LocalRadius() << endl; + cout << "Phase = " << spi.PhaseAngle() << endl; + cout << "Emission = " << spi.EmissionAngle() << endl; + cout << "Incidence = " << spi.IncidenceAngle() << endl; + spi.LookDirection(p); + cout << "Look Direction = " << p[0] << " " << p[1] << " " << p[2] << endl; + cout << "Slant Distance = " << spi.SlantDistance() << endl; + cout << "Local Solar Time = " << spi.LocalSolarTime() << endl; + cout << "Spacecraft Altitude = " << spi.SpacecraftAltitude() << endl; + cout << "Solar Distance = " << spi.SolarDistance() << endl; + cout << endl; + + // Test bad ground point + cout << "Test Bad ground point" << endl; + spi.SetUniversalGround(11.57143551329, 43.328646604); + cout << "Has Intersection = " << spi.HasSurfaceIntersection() << endl; + + } + catch(Isis::iException &e) { + e.Report(); + } +} diff --git a/isis/src/base/objs/Sensor/unitTest.exclude b/isis/src/base/objs/Sensor/unitTest.exclude new file mode 100644 index 0000000000000000000000000000000000000000..4dbb4e4eba485ba22e4cd22ae3c1d91f32b7740a --- /dev/null +++ b/isis/src/base/objs/Sensor/unitTest.exclude @@ -0,0 +1 @@ +Look diff --git a/isis/src/base/objs/SerialNumber/Makefile b/isis/src/base/objs/SerialNumber/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2391f641b8c2d1d25620b725b1569693e290523a --- /dev/null +++ b/isis/src/base/objs/SerialNumber/Makefile @@ -0,0 +1,5 @@ +INCS = SerialNumber.h +SRCS = SerialNumber.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/SerialNumber/SerialNumber.cpp b/isis/src/base/objs/SerialNumber/SerialNumber.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc2b01fca043fadd1bedb7fd21574778584a1768 --- /dev/null +++ b/isis/src/base/objs/SerialNumber/SerialNumber.cpp @@ -0,0 +1,178 @@ +#include + +#include "SerialNumber.h" +#include "ObservationNumber.h" +#include "SerialNumberList.h" +#include "iException.h" +#include "Pvl.h" +#include "Cube.h" +#include "Process.h" +#include "PvlTranslationManager.h" +#include "Filename.h" + +namespace Isis { + /** + * Create an empty SerialNumber object. + */ + SerialNumber::SerialNumber () {} + + /** + * Destroy a SerialNumber object. + */ + SerialNumber::~SerialNumber () {} + + /** + * Compose a SerialNumber from a PVL. + * + * @param label A pvl formatted label to be used to generate the serial number + * @param def2filename If a serial number could not be found, try to return the filename + * + * @return Calculated SerialNumber or Filename + */ + std::string SerialNumber::Compose (Pvl &label, bool def2filename) { + + std::string sn; + try { + PvlGroup snGroup = FindSerialTranslation (label); + sn = CreateSerialNumber (snGroup,(int)snGroup["ObservationKeys"]); + } + catch (iException &e) { + e.Clear(); + if (def2filename) { + // Try to return the filename if it exists in the label, otherwise use + // "Unknown" as a last resort. + std::string snTemp = label.Filename(); + if (!snTemp.empty()) { + sn = Filename(snTemp).Name(); + } + else { + sn = "Unknown"; + } + } + else { + sn = "Unknown"; + } + } + + return sn; + } + + /** + * Compose a SerialNumber from a Cube. + * + * @param cube An opened Isis cub + * @param def2filename If a serial number could not be found, try to return the filename + * + * @return Calculated SerialNumber or Filename + */ + std::string SerialNumber::Compose (Cube &cube, bool def2filename) { + return Compose(*cube.Label(), def2filename); + } + + /** + * Compose a SerialNumber from a file. + * + * @param filename a filename to open + * @param def2filename If a serial number could not be found, try to return the + * filename + * + * @return Calculated SerialNumber or Filename + */ + std::string SerialNumber::Compose (const std::string &filename, bool def2filename) { + Pvl p(filename); + return Compose(p, def2filename); + } + + /** + * Get Groups by translating from correct Translation table + * + * @param label A pvl formatted label to be used to generate the serial number + * + */ + PvlGroup SerialNumber::FindSerialTranslation (Pvl &label) { + Pvl outLabel; + static PvlGroup dataDir (Preference::Preferences().FindGroup("DataDirectory")); + + // Get the mission name + static std::string missionTransFile = (std::string) dataDir["base"] + "/translations/MissionName2DataDir.trn"; + static PvlTranslationManager missionXlater (missionTransFile); + missionXlater.SetLabel(label); + std::string mission = missionXlater.Translate ("MissionName"); + + // Get the instrument name + static std::string instTransFile = (std::string) dataDir["base"] + "/translations/Instruments.trn"; + static PvlTranslationManager instrumentXlater (instTransFile); + instrumentXlater.SetLabel(label); + std::string instrument = instrumentXlater.Translate ("InstrumentName"); + + // We want to use this instrument's translation manager. It's much faster for + // SerialNumberList if we keep the translation manager in memory, so re-reading + // from the disk is not necessary every time. To do this, we'll use a map to store + // the translation managers with a string identifier to find them. This identifier + // needs to have the mission name and the instrument name. + + // Create the static map to keep the translation managers in memory + static std::map missionTranslators; + + // Determine the key for this translation manager - must have both mission and instrument + std::string key = mission + "_" + instrument; + + // Try to find an existing translation manager with the key + std::map::iterator translationIterator = missionTranslators.find(key); + + // If we don't succeed, create one + if(translationIterator == missionTranslators.end()) { + // Get the file + Filename snFile = (std::string) dataDir[mission] + "/translations/" + instrument + "SerialNumber????.trn"; + snFile.HighestVersion(); + + // use the translation file to generate keywords + missionTranslators.insert( + std::pair(key, PvlTranslationManager(snFile.Expanded())) + ); + + translationIterator = missionTranslators.find(key); + } + + translationIterator->second.SetLabel(label); + translationIterator->second.Auto(outLabel); + + PvlGroup snGroup = outLabel.FindGroup("SerialNumberKeywords"); + snGroup += PvlKeyword("ObservationKeys", snGroup.Keywords()); + + return snGroup; + } + + /** + * Create the SerialNumber string by concatenating the keywords in the label + * with '/' in between serialNumber groups and the number of observationKeys + * + * @param snGroup A PvlGroup containing the keywords to concatenate + * @param keys the number of strings to contatenate + */ + std::string SerialNumber::CreateSerialNumber (PvlGroup &snGroup, int keys ) { + std::string sn = snGroup["Keyword1"][0]; + for (int i=2; i<= keys; i++) { + iString keyword = "Keyword"+ (iString)i; + sn += "/" + snGroup[keyword][0]; + } + return sn; + } + + /** + * Creates the ObservationNumber from a string representing the + * SerialNumber and a SerialList. + * + * @param sn the string representing the SerialNumber + * + * @param list the SerialNumberList + * @param def2filename If a serial number could not be found, try to return the + * filename + * + * @return Calculated SerialNumber or Filename + */ + std::string SerialNumber::ComposeObservation (const std::string &sn, SerialNumberList &list, bool def2filename) { + std::string filename = list.Filename(sn); + return ObservationNumber::Compose(filename,def2filename); + } +} diff --git a/isis/src/base/objs/SerialNumber/SerialNumber.h b/isis/src/base/objs/SerialNumber/SerialNumber.h new file mode 100644 index 0000000000000000000000000000000000000000..27c595c3675a94303ebc7eda93c95079c130ed16 --- /dev/null +++ b/isis/src/base/objs/SerialNumber/SerialNumber.h @@ -0,0 +1,113 @@ +#ifndef SerialNumber_h +#define SerialNumber_h + +/** + * @file + * $Revision: 1.8 $ + * $Date: 2008/06/18 18:54:11 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#include "SerialNumberList.h" + +namespace Isis { + +/** + * @brief Serial Number composer + * + * A Serial Number is a unique identification for some object such as an + * Isis cube. A Serial Number for a specific object must be repeatable. This + * class is intended to be used to create all Serial Numbers for Isis. + * + * @ingroup ControlNetworks + * + * @author 2005-07-28 Stuart Sides + * + * @internal + * + * @todo This is only a temporary version. The code needs to be modified + * to use a PVL file to determine which keywords to use to create the + * Serial Number + * + * @history 2005-07-28 Stuart Sides Original version + * @history 2005-08-02 Jeff Anderson added new static methods for + * serial number composition from a cube or filename + * @history 2006-01-24 Jacob Danton Updated the SerialNumber Compose method + * to use .trn files specific to the mission + * @history 2006-06-15 Kris Becker Added the return of the filename as the + * fallback default condition. "Unknown" will + * still be returned if the input source is a + * label created in memory and does not have + * a valid serial number signature and it was + * not read in from a file. Add a test for + * this to the unitTest. + * @history 2006-12-08 Stuart Sides Added parameter the the Compose methods + * to allow or disallow defaulting to the + * filename. This parameter has a default of + * false. Which will cause "Unknown" to be + * returned for files where a SN could not be + * correctly produced. + * @history 2007-07-09 Steven Lambright Changed missions translation filename from Missions.trn to + * MissionName2DataDir.trn + * @history 2007-09-11 Steven Koechle Added three ComposeObservation methods + * and made code reusable by seperating + * existing code into two private methods. + * @history 2007-09-13 Steven Koechle Fixed boolean paramaters passed into + * FindSerialTranslation + * + * @history 2008-01-10 Christpher Austin Removed the use of the system default + * file in FindSerialTranslation() and detached ObservationNumber + * functionality into its own class + * @history 2008-05-09 Steven Lambright Optimized the FindSerialTranslation + * method + * @history 2008-05-18 Steven Lambright Fixed documentation + */ + + // Forward declarations + class Pvl; + class PvlGroup; + class Cube; + + class SerialNumber { + public: + SerialNumber (); + + virtual ~SerialNumber (); + + static std::string Compose (Pvl &label, bool def2filename=false); + + static std::string Compose (Cube &cube, bool def2filename=false); + + static std::string Compose (const std::string &filename, bool def2filename=false); + + static std::string ComposeObservation ( const std::string &sn, SerialNumberList &list, bool def2filename=false ); + + protected: + + static std::string CreateSerialNumber (PvlGroup &snGroup, int key); + + private: + + static PvlGroup FindSerialTranslation (Pvl &label); + + }; // End of Class +}; // End of namespace + +#endif diff --git a/isis/src/base/objs/SerialNumber/SerialNumber.truth b/isis/src/base/objs/SerialNumber/SerialNumber.truth new file mode 100644 index 0000000000000000000000000000000000000000..9ad27af45bc0f9c511ac2e214ed2b45429ef1a07 --- /dev/null +++ b/isis/src/base/objs/SerialNumber/SerialNumber.truth @@ -0,0 +1,7 @@ +Unknown +Unknown +isisTruth.cub +LO3/HRC/3133/1 + +Testing ObservationKeys +LO3/HRC/3133 diff --git a/isis/src/base/objs/SerialNumber/unitTest.cpp b/isis/src/base/objs/SerialNumber/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d7131ab2c5fc283a27b18d60efb64db7ef21e98 --- /dev/null +++ b/isis/src/base/objs/SerialNumber/unitTest.cpp @@ -0,0 +1,42 @@ +#include +#include "Filename.h" +#include "Pvl.h" +#include "SerialNumber.h" +#include "ObservationNumber.h" +#include "Cube.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + Isis::PvlGroup g("Instrument"); + g += Isis::PvlKeyword("SpacecraftName", "MySpacecraft"); + g += Isis::PvlKeyword("InstrumentId", "MyInstrumentId"); + g += Isis::PvlKeyword("SpacecraftClockCount", "987654321"); + + Isis::PvlObject o("IsisCube"); + o.AddGroup(g); + + Isis::Pvl p; + p.AddObject(o); + + std::cout << Isis::SerialNumber::Compose(p) << std::endl; + + p.FindGroup("Instrument",Isis::Pvl::Traverse).DeleteKeyword("InstrumentId"); + std::cout << Isis::SerialNumber::Compose(p) << std::endl; + + Isis::Cube cube; + cube.Open("$base/testData/isisTruth.cub"); + std::cout << Isis::SerialNumber::Compose(cube, true) << std::endl; + + Isis::Filename file("$lo/testData/3133_h1.cub"); + Isis::Pvl p1(file.Expanded()); + + std::cout << Isis::SerialNumber::Compose(p1) << std::endl; + + std::cout << std::endl << "Testing ObservationKeys" << std::endl; + + std::cout << Isis::ObservationNumber::Compose(p1) << std::endl; + return (0); +} diff --git a/isis/src/base/objs/SerialNumberList/Makefile b/isis/src/base/objs/SerialNumberList/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..40303a7f32b837ce6f73423a047ee21421c692e9 --- /dev/null +++ b/isis/src/base/objs/SerialNumberList/Makefile @@ -0,0 +1,5 @@ +INCS = SerialNumberList.h +SRCS = SerialNumberList.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/SerialNumberList/SerialNumberList.cpp b/isis/src/base/objs/SerialNumberList/SerialNumberList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1dc11838391c1f566f5e5a600570278391f49d85 --- /dev/null +++ b/isis/src/base/objs/SerialNumberList/SerialNumberList.cpp @@ -0,0 +1,314 @@ +#include "SerialNumberList.h" +#include "iException.h" +#include "FileList.h" +#include "Filename.h" +#include "SerialNumber.h" +#include "ObservationNumber.h" +#include "iString.h" +#include "Pvl.h" + +namespace Isis { + /** + * Creates an empty SerialNumberList + */ + SerialNumberList::SerialNumberList (bool checkTarget) { + p_checkTarget = checkTarget; + p_target.clear(); + } + + + /** + * Creates a SerialNumberList from a list of filenames + * + * @param listfile The list of files to be given serial numbers + * @param checkTarget Boolean value that specifies whether or not to check + * to make sure the target names match between files added + * to the serialnumber list + * @internal + * @history 2009-10-20 Jeannie Walldren - Added Progress flag + * @history 2009-11-05 Jeannie Walldren - Modified number + * of maximum steps for Progress flag + */ + SerialNumberList::SerialNumberList (const std::string &listfile, bool checkTarget, Progress *progress) { + p_checkTarget = checkTarget; + p_target.clear(); + try { + FileList flist(listfile); + if (progress != NULL) { + progress->SetText("Creating Isis 3 serial numbers from list file."); + progress->SetMaximumSteps((int) flist.size()+1); + progress->CheckStatus(); + } + for (int i=0; i<(int)flist.size(); i++) { + Add(flist[i]); + if (progress != NULL){ + progress->CheckStatus(); + } + } + } + catch (iException &e) { + std::string msg = "Can't open or invalid file list [" + listfile + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + /** + * Destructor + */ + SerialNumberList::~SerialNumberList () { + } + + + /** + * Adds a new filename / serial number pair to the + * SerialNumberList + * + * @param filename the filename to be added + * + * @internal + * @history 2007-06-04 Tracie Sucharski - Expand filename to include full + * path before adding to list. + */ + void SerialNumberList::Add (const std::string &filename) { + + Pvl p(Isis::Filename(filename).Expanded()); + try { + PvlGroup instrument = p.FindGroup("Instrument",Isis::Pvl::Traverse); + iString target = instrument["TargetName"][0]; + target.UpCase(); + + // Test the target name if desired + if (p_checkTarget && !p_target.empty()) { + if (p_target != target) { + std::string msg = "Target name of [" + target + "] from file ["; + msg += filename + "] does not match [" + p_target + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + else { + p_target = target; + } + + // Create the SN + std::string sn = SerialNumber::Compose(p); + std::string on = ObservationNumber::Compose(p); + if (sn == "Unknown") { + std::string msg = "Invalid serial number [Unknown] from file ["; + msg += filename + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + else if (HasSerialNumber(sn)) { + int index = SerialNumberIndex(sn); + std::string msg = "Duplicate, serial number [" + sn + "] from files ["; + msg += SerialNumberList::Filename(sn) + "] and [" + Filename(index) + "]."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + Pair nextpair; + nextpair.filename = Isis::Filename(filename).Expanded(); + nextpair.serialNumber = sn; + nextpair.observationNumber = on; + p_pairs.push_back(nextpair); + p_serialMap.insert(std::pair(sn,(int)(p_pairs.size()-1))); + p_fileMap.insert(std::pair(nextpair.filename,(int)(p_pairs.size()-1))); + } + catch (iException &e) { + std::string msg = "File [" + Isis::Filename(filename).Expanded() + + "] can not be added to "; + msg += "serial number list"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + + /** + * Determines whether or not the requested serial number exists + * in the list + * + * @param sn The serial number to be checked for + * + * @return bool + */ + bool SerialNumberList::HasSerialNumber (const std::string &sn) { + if (p_serialMap.find(sn) == p_serialMap.end()) return false; + return true; + } + + + /** + * How many serial number / filename combos are in the list + * + * @return int Returns number of serial numbers current in the list + */ + int SerialNumberList::Size () const { + return p_pairs.size(); + } + + + /** + * Return a filename given a serial number + * + * @param sn The serial number of the desired filename + * + * @return std::string The filename matching the input serial + * number + */ + std::string SerialNumberList::Filename (const std::string &sn) { + if (HasSerialNumber(sn)) { + int index = p_serialMap.find(sn)->second; + return p_pairs[index].filename; + } + else { + std::string msg = "Requested serial number [" + sn + "] "; + msg += "does not exist in the list"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + + /** + * return a serial number given a filename + * + * @param filename The filename to be matched + * + * @return std::string The serial number corresponding to the + * input filename + * + * @internal + * @history 2007-06-04 Tracie Sucharski - Expand filename to include full + * path before searching list. + */ + std::string SerialNumberList::SerialNumber(const std::string &filename){ + if (p_fileMap.find(Isis::Filename(filename).Expanded()) == p_fileMap.end()) { + std::string msg = "Requested filename [" + + Isis::Filename(filename).Expanded() + "]"; + msg += "does not exist in the list"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + int index = FilenameIndex(filename); + return p_pairs[index].serialNumber; + } + + /** + * Return a serial number given an index + * + * @param index The index of the desired serial number + * + * @return std::string The serial number returned + */ + std::string SerialNumberList::SerialNumber (int index){ + if (index >= 0 && index < (int) p_pairs.size()) { + return p_pairs[index].serialNumber; + } + else { + iString num = iString(index); + std::string msg = "Index [" + (std::string) num + "] is invalid"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + + /** + * Return a observation number given an index + * + * @param index The index of the desired observation number + * + * @return std::string The observation number returned + */ + std::string SerialNumberList::ObservationNumber (int index){ + if (index >= 0 && index < (int) p_pairs.size()) { + return p_pairs[index].observationNumber; + } + else { + iString num = iString(index); + std::string msg = "Index [" + (std::string) num + "] is invalid"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + + /** + * return a list index given a serial number + * + * @param sn The serial number searched for + * + * @return int The index of the serial number + */ + int SerialNumberList::SerialNumberIndex(const std::string &sn) { + if (HasSerialNumber(sn)) { + return p_serialMap.find(sn)->second; + } + else { + std::string msg = "Requested serial number [" + sn + "] "; + msg += "does not exist in the list"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + + /** + * Return a list index given a filename + * + * @param filename The filename to be searched for + * + * @return int The index of the input filename + * + * @internal @history 2007-06-04 Tracie Sucharski - Expand filename to include + * full path before searching list. + * @internal @history 2007-07-11 Stuart Sides - Fixed bug where + * the correct index was not returned. + */ + int SerialNumberList::FilenameIndex(const std::string &filename){ + + std::map::iterator pos; + if ((pos = p_fileMap.find(Isis::Filename(filename).Expanded())) == p_fileMap.end()) { + std::string msg = "Requested filename [" + + Isis::Filename(filename).Expanded() + "]"; + msg += "does not exist in the list"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + return pos->second; + } + + /** + * Return the filename at the given index + * + * @param index The index of the desired filename + * + * @return std::string The filename at the given index + */ + std::string SerialNumberList::Filename (int index) { + if (index >=0 && index < (int) p_pairs.size()) { + return p_pairs[index].filename; + } + else{ + iString num = iString(index); + std::string msg = "Index [" + (std::string) num + "] is invalid"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + + + /** + * Return possible serial numbers given an observation number + * + * @param on The observation number of the possible serial + * number + * + * @return vector The list of possible serial + * numbers matching the input observation number + */ + std::vector SerialNumberList::PossibleSerialNumbers (const std::string &on) { + std::vector numbers; + for( unsigned index=0; index 0 ) { + return numbers; + } + else { + std::string msg = "Requested observation number [" + on + "] "; + msg += "does not exist in the list"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + } + + +} diff --git a/isis/src/base/objs/SerialNumberList/SerialNumberList.h b/isis/src/base/objs/SerialNumberList/SerialNumberList.h new file mode 100644 index 0000000000000000000000000000000000000000..3cb4d3302e2eb5ece16f5cabdc6b53854eb2a0f6 --- /dev/null +++ b/isis/src/base/objs/SerialNumberList/SerialNumberList.h @@ -0,0 +1,116 @@ +#ifndef SerialNumberList_h +#define SerialNumberList_h +/** + * @file + * $Revision: 1.6 $ + * $Date: 2009/11/05 18:42:56 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc/documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "Progress.h" + +namespace Isis { +/** + * @brief Serial Number list generator + * + * Create a list of serial numbers from a list of files + * + * @ingroup ControlNetworks + * + * @author 2005-08-03 Jeff Anderson + * + * @internal + * + * @history 2005-08-03 Jeff Anderson Original Version + * @history 2006-02-10 Jacob Danton Added SerialNumber function + * @history 2006-02-13 Stuart Sides Added checks to make sure all the serial + * number items have the same target. + * + * @history 2006-05-31 Tracie Sucharski Added filename + * function that uses index instead of + * serial number. + * @history 2006-06-15 Jeff Anderson Added GetIndex method + * @history 2006-06-22 Brendan George Added functions to get + * index, modified/added functions to + * get filename and serial number, and + * modified so that index corresponds + * to order files are input. + * @history 2006-08-16 Brendan George Added/fixed error + * checking in FilenameIndex() and + * SerialNumber(string filename). + * @history 2006-08-18 Brendan George Modified to use Expanded + * Filename on input, allowing for + * filenames that use environment + * variables + * @history 2006-09-13 Steven Koechle Added method to get the + * ObservationNumber when you give it + * an index + * @history 2008-01-10 Christopher Austin - Adapted for the new + * ObservationNumber class. + * @history 2008-10-30 Steven Lambright - Fixed problem with definition + * of struct Pair, pointed out by "novus0x2a" (Support Board Member) + * @history 2009-10-20 Jeannie Walldren - Added Progress flag + * to Constructor + * @history 2009-11-05 Jeannie Walldren - Modified number + * of maximum steps for Progress flag + * in Constructor + */ + + class SerialNumberList { + public: + SerialNumberList (bool checkTarget=true); + SerialNumberList (const std::string &list, bool checkTarget=true, Progress *progress=NULL); + virtual ~SerialNumberList (); + + void Add (const std::string &filename); + bool HasSerialNumber (const std::string &sn); + + int Size () const; + std::string Filename (const std::string &sn); + std::string Filename (int index); + std::string SerialNumber(const std::string &filename); + std::string SerialNumber(int index); + std::string ObservationNumber (int index); + + int SerialNumberIndex(const std::string &sn); + int FilenameIndex(const std::string &filename); + + std::vector PossibleSerialNumbers (const std::string &on); + + protected: + struct Pair { + std::string filename; + std::string serialNumber; + std::string observationNumber; + }; + + std::vector p_pairs; + std::map p_serialMap; + std::map p_fileMap; + + bool p_checkTarget; + std::string p_target; + + }; +}; + +#endif diff --git a/isis/src/base/objs/SerialNumberList/SerialNumberList.truth b/isis/src/base/objs/SerialNumberList/SerialNumberList.truth new file mode 100644 index 0000000000000000000000000000000000000000..15f3efadd6fa3c4759f90bac5861e901d04f1363 --- /dev/null +++ b/isis/src/base/objs/SerialNumberList/SerialNumberList.truth @@ -0,0 +1,23 @@ +size = 3 +hasXYZ = 0 +/usgs/cpkgs/isis3/data/mgs/testData/ab102401.cub = MGS/561812335:32/MOC-WA/RED +/usgs/cpkgs/isis3/data/mgs/testData/m0402852.cub = MGS/619971158:28/MOC-NA/BROAD_BAND +/usgs/cpkgs/isis3/data/lo/testData/3133_h1.cub = LO3/HRC/3133/1 + +SN->File: /usgs/cpkgs/isis3/data/mgs/testData/ab102401.cub +File->SN:MGS/561812335:32/MOC-WA/RED +MGS/561812335:32/MOC-WA/RED = 0 +MGS/619971158:28/MOC-NA/BROAD_BAND = 1 +LO3/HRC/3133/1 = 2 + +SN->File (0): /usgs/cpkgs/isis3/data/mgs/testData/ab102401.cub + +SN->File (1): /usgs/cpkgs/isis3/data/mgs/testData/m0402852.cub + +SN->File (2): /usgs/cpkgs/isis3/data/mgs/testData/m0402852.cub + +Index->observationNumber (2): LO3/HRC/3133 + + +**USER ERROR** File [/usgs/cpkgs/isis3/data/base/testData/blobTruth.cub] can not be added to serial number list +**USER ERROR** Target name of [SKY] from file [$base/testData/blobTruth.cub] does not match [MARS] diff --git a/isis/src/base/objs/SerialNumberList/unitTest.cpp b/isis/src/base/objs/SerialNumberList/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d43a77de29e23be7965504ac82dc9e80fb1aa031 --- /dev/null +++ b/isis/src/base/objs/SerialNumberList/unitTest.cpp @@ -0,0 +1,54 @@ +#include +#include "SerialNumberList.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + try { + Isis::SerialNumberList snl(false); + + snl.Add("$mgs/testData/ab102401.cub"); + snl.Add("$mgs/testData/m0402852.cub"); + snl.Add("$lo/testData/3133_h1.cub"); + + cout << "size = " << snl.Size() << endl; + cout << "hasXYZ = " << snl.HasSerialNumber("XYZ") << endl; + + for (int i=0; iFile: " << snl.Filename("MGS/561812335:32/MOC-WA/RED") << endl + << "File->SN:" << snl.SerialNumber("$mgs/testData/ab102401.cub") << endl; + + for (int i=0; iFile (0): " << snl.Filename(0) << endl; + cout << endl << "SN->File (1): " << snl.Filename(1) << endl; + cout << endl << "SN->File (2): " << snl.Filename(1) << endl; + + cout<< endl << "Index->observationNumber (2): " << snl.ObservationNumber(2) << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } + + cout << endl << endl;; + + // Test to make sure all targets being the same works + try { + Isis::SerialNumberList snl; + snl.Add("$mgs/testData/ab102401.cub"); + snl.Add("$base/testData/blobTruth.cub"); + snl.Add("$lo/testData/3133_h1.cub"); + } + catch (Isis::iException &e) { + e.Report(false); + } + +} diff --git a/isis/src/base/objs/SessionLog/Makefile b/isis/src/base/objs/SessionLog/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46904f325e4b6654f380c2b9adc0a374c55ac44c --- /dev/null +++ b/isis/src/base/objs/SessionLog/Makefile @@ -0,0 +1,5 @@ +INCS = SessionLog.h +SRCS = SessionLog.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/SessionLog/SessionLog.cpp b/isis/src/base/objs/SessionLog/SessionLog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8f7999875e09f159d7e7fac800a207636910e59 --- /dev/null +++ b/isis/src/base/objs/SessionLog/SessionLog.cpp @@ -0,0 +1,129 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/07/08 22:16:43 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "SessionLog.h" +#include "Preference.h" +#include "iString.h" +#include "Application.h" + +using namespace std; +namespace Isis { + // Constructor + SessionLog::SessionLog () { + // Grab the user preferences for logging + Isis::PvlGroup &slog = Isis::Preference::Preferences().FindGroup("SessionLog"); + p_termOutput = Isis::iString((string)slog["TerminalOutput"]).UpCase() == "ON"; + p_fileOutput = Isis::iString((string)slog["FileOutput"]).UpCase() == "ON"; + p_outputFile = (string) slog["FileName"]; + p_access = Isis::iString((string) slog["FileAccess"]).UpCase(); + + // Add root + this->AddObject(Isis::iApp->History()); + p_errorAdded = false; + p_acctAdded = false; + p_root = &this->Object(0); + + atexit(Shutdown); + } + + // Destructor + SessionLog::~SessionLog () { + } + + // Singleton creator + SessionLog *SessionLog::p_log = NULL; + + SessionLog &SessionLog::TheLog(bool restart) { + if (restart && (p_log != NULL)) { + delete p_log; + p_log = NULL; + } + + if (p_log == NULL) { + // Create the singleton + p_log = new SessionLog (); + } + return *p_log; + } + + // Write info to the session log + void SessionLog::Write() { + AddAccounting(); + + // See if we should write to the print file + if (p_fileOutput) { + SetTerminator("\n"); + try { + if (p_access == "OVERWRITE") { + this->Isis::Pvl::Write(p_outputFile); + } + else { + this->Append(p_outputFile); + } + } + catch (...) { + std::cerr << "**WARNING** Unable to write session log [" << + p_outputFile << "] Disk may be full or directory permissions not writeable" + << std::endl; + exit(1); + } + SetTerminator("End"); + } + } + + void SessionLog::AddAccounting() { + // Update accounting if no errors + if (p_acctAdded) return; + if (!p_errorAdded) { + p_root->AddGroup(Isis::iApp->Accounting()); + } + p_acctAdded = true; + } + + // Add an error message + void SessionLog::AddError (Isis::Pvl &e) { + for (int i=0; iAddGroup(e.Group(i)); + p_errorAdded = true; + } + } + } + + // Add results from an application + void SessionLog::AddResults(Isis::PvlGroup &results) { + p_root->AddGroup(results); + } + + std::ostream& operator<<(std::ostream &os, Isis::SessionLog &log) { + log.AddAccounting(); + return operator<<(os,(Isis::Pvl &) log); + } + + void SessionLog::Shutdown() { + if(p_log) { + delete p_log; + p_log = NULL; + } + } +} // end namespace isis + diff --git a/isis/src/base/objs/SessionLog/SessionLog.h b/isis/src/base/objs/SessionLog/SessionLog.h new file mode 100644 index 0000000000000000000000000000000000000000..c23d8bfc4be095387b5ed252870c7e1da8d53cf9 --- /dev/null +++ b/isis/src/base/objs/SessionLog/SessionLog.h @@ -0,0 +1,78 @@ +#if !defined(SessionLog_h) +#define SessionLog_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/07/08 22:16:43 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "Pvl.h" +#include "iException.h" + +namespace Isis { +/** + * + * @internal + * @history 2005-12-28 Elizabeth Miller - Added try/catch block in Write() to + * catch an error that causes an abort + * @history 2008-01-09 Steven Lambright - Made Application a friend for + * destruction purposes + * @history 2008-07-08 Steven Lambright - Now uses atexit for destruction + * @todo 2005-02-15 Write class documentation + */ + class SessionLog : private Isis::Pvl { + public: + static SessionLog &TheLog(bool restart=false); + static bool HasLog() { return p_log != NULL; }; + + // Add the Results group + void AddResults(Isis::PvlGroup &results); + + // Write the log to the screen and/or file + void Write (); + + // Add an Error to the log + void AddError (Isis::Pvl &e); + + // Will we be logging to the terminal? + bool TerminalOutput() { return p_termOutput; }; + + private: + SessionLog(); + ~SessionLog(); + + PvlObject *p_root; + bool p_errorAdded; + + bool p_termOutput; + bool p_fileOutput; + std::string p_outputFile; + std::string p_access; + + static SessionLog *p_log; + + bool p_acctAdded; + void AddAccounting(); + friend std::ostream& operator<<(std::ostream &os, Isis::SessionLog &log); + static void Shutdown(); + }; +}; + +#endif diff --git a/isis/src/base/objs/SessionLog/SessionLog.truth b/isis/src/base/objs/SessionLog/SessionLog.truth new file mode 100644 index 0000000000000000000000000000000000000000..d6858fa6187cedb0436da00716644955f3a6131f --- /dev/null +++ b/isis/src/base/objs/SessionLog/SessionLog.truth @@ -0,0 +1,56 @@ +Object = ratio + IsisVersion = "3.1.13 | 2007-07-13" + ProgramVersion = 2003-07-29 + ExecutionDateTime = 2007-08-01T11:42:35 + HostName = blackflag + UserName = slambright + Description = "Divide two cubes" + + Group = UserParameters + NUMERATOR = a + DENOMINATOR = b + TO = bogus + End_Group + + // This is an example of the results group + Group = Results + // Average size of a rock + Average = 13.5 + End_Group + + Group = Accounting + ConnectTime = 00:00:00.0 + CpuTime = 00:00:00.0 + End_Group +End_Object +End +Object = ratio + IsisVersion = "3.1.13 | 2007-07-13" + ProgramVersion = 2003-07-29 + ExecutionDateTime = 2007-08-01T11:42:35 + HostName = blackflag + UserName = slambright + Description = "Divide two cubes" + + Group = UserParameters + NUMERATOR = a + DENOMINATOR = b + TO = bogus + End_Group + + // This is an example of the results group + Group = Results + // Average size of a rock + Average = 13.5 + End_Group + + Group = Error + Program = ratio + Class = "I/O ERROR" + Status = -1 + Message = "Unable to open file" + File = unitTest.cpp + Line = 501 + End_Group +End_Object +End diff --git a/isis/src/base/objs/SessionLog/unitTest.cpp b/isis/src/base/objs/SessionLog/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db45c959a24d8eb0baddf69cca5626ba8a685c1e --- /dev/null +++ b/isis/src/base/objs/SessionLog/unitTest.cpp @@ -0,0 +1,59 @@ +#include "SessionLog.h" +#include "Application.h" +#include "Preference.h" +#include "iException.h" +#include "Pvl.h" + +using namespace std; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + Isis::PvlGroup &g = Isis::Preference::Preferences().FindGroup("SessionLog"); + g["TerminalOutput"] = "On"; + + try { + Isis::PvlGroup results("Results");; + results.AddComment("// This is an example of the results group"); + results += Isis::PvlKeyword("Average",13.5,"Meters"); + results[0].AddComment("// Average size of a rock"); + + Isis::Pvl error; + Isis::PvlGroup temp("Error"); + temp += Isis::PvlKeyword("Program","ratio"); + temp += Isis::PvlKeyword("Class","I/O ERROR"); + temp += Isis::PvlKeyword("Status",-1); + temp += Isis::PvlKeyword("Message","Unable to open file"); + temp += Isis::PvlKeyword("File","unitTest.cpp"); + temp += Isis::PvlKeyword("Line",501); + error.AddGroup(temp); + + char *s_argv[] = {"unitTest","num=a", "den=b", "to=bogus"}; + int s_argc(4); + try { + Isis::Application app(s_argc,s_argv); + Isis::SessionLog &log = Isis::SessionLog::TheLog(true); + log.AddResults(results); + std::cout << log << std::endl; + } + catch (Isis::iException &e) { + e.Report(); + } + + try { + Isis::Application app(s_argc,s_argv); + Isis::SessionLog &log = Isis::SessionLog::TheLog(true); + log.AddResults(results); + log.AddError(error); + std::cout << log << std::endl; + } + catch (Isis::iException &e) { + e.Report(); + } + + } + catch (Isis::iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/SessionLog/unitTest.exclude b/isis/src/base/objs/SessionLog/unitTest.exclude new file mode 100644 index 0000000000000000000000000000000000000000..10bf08d787896a103810cd75161c7ac0290973f0 --- /dev/null +++ b/isis/src/base/objs/SessionLog/unitTest.exclude @@ -0,0 +1,8 @@ +ProgramPath +DateTime +User +HostName +IsisVersion +CpuTime +Connect + diff --git a/isis/src/base/objs/SessionLog/unitTest.xml b/isis/src/base/objs/SessionLog/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..6a337c65a339f6a99393b8174e67d488cdbfd08c --- /dev/null +++ b/isis/src/base/objs/SessionLog/unitTest.xml @@ -0,0 +1,143 @@ + + + + + Divide two cubes + + + + This program divides two cubes. It operates in one of two manners: 1) the + denominator cube must have the same number of bands as the numerator cube + or 2) the denominator cube must have exactly one band. In the former case, + corresponding bands are divided, for example, band one is divided by + band one, band two by band two, and so on. In the later case, all bands + in the numerator cube are divided by the single band in the denominator + cube. + Special pixels values are handled identically in both cases. Whenever a + special pixel occurs, in either the numerator or denominator, the output + pixel is set to NULL. Likewise, if the denominator is zero, the output + is set to NULL. + + + + Math and Statistics + + + + + Original version + + + Converted to Isis 3.0 + + + Added application test + + + Modified schema location from astogeology... to isis.astrogeology..." + + + Changed NUM, DEN and To from type filename to type cube + + + Modified filename parameters to be cube parameters where necessary + + + + + + ratio + cosi + + + + + + cube + input + + Numerator cube + + + The numerator cube. All pixels in this cube will be divided by + corresponding pixels in the denominator cube. + + + *.cub + + + + + cube + input + + Denominator cube + + + The denominator cube. The number of bands in this cube must + match the numerator cube or be exactly one. In the former case, + a band-by-band division occurs. In the later, each numerator + band is divided by the single denominator band. + + + *.cub + + + + + cube + Real + output + + Output cube + + + The output cube containing the results of the ratio. A NULL + pixel will be output when either of the numerator or denominator + pixels is special. Similarly, a NULL will be output if the + denominator pixel is zero. + + + *.cub + + + + + + + + Dividing one band by one band + + This example presents dividing one band in a cube by a single band. + In this case, we divide band 5 by band 4 in peaks.cub and + generate a single band + output cube. Note that the file (peaks.cub) does not have to be + the same name for NUMERATOR and DENOMINATOR so long as the + spatial size (samples and lines) match between the given files. + + + + numerator=peaks.cub:5 denominator=peaks.cub:4 to=ratio.cub + + + + + + + Dividing multiple bands by one band + + This example presents dividing all bands in a cube by an individual + band. In this case, the seven bands in peaks.cub are divided + by band 4 and the results output to ratio.cub. + + + + numerator=peaks.cub denominator=peaks.cub:4 to=ratio.cub + + + + + + + + diff --git a/isis/src/base/objs/Shade/Makefile b/isis/src/base/objs/Shade/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..29a33bda830efe5458f608d8821bd35186fabeac --- /dev/null +++ b/isis/src/base/objs/Shade/Makefile @@ -0,0 +1,5 @@ +INCS = Shade.h +SRCS = Shade.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Shade/NormModel.plugin b/isis/src/base/objs/Shade/NormModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..079b88583a01ff01b79c85e379d94dcd4128f835 --- /dev/null +++ b/isis/src/base/objs/Shade/NormModel.plugin @@ -0,0 +1,4 @@ +Group = Shade + Library = Shade + Routine = ShadePlugin +End_Group diff --git a/isis/src/base/objs/Shade/Shade.cpp b/isis/src/base/objs/Shade/Shade.cpp new file mode 100644 index 0000000000000000000000000000000000000000..12d76860c13077532040c54070e5d8eda71dc66b --- /dev/null +++ b/isis/src/base/objs/Shade/Shade.cpp @@ -0,0 +1,79 @@ +#include "Shade.h" +#include "iException.h" + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) + +namespace Isis { + Shade::Shade (Pvl &pvl, PhotoModel &pmodel) : NormModel(pvl,pmodel) { + PvlGroup &algorithm = pvl.FindObject("NormalizationModel").FindGroup("Algorithm",Pvl::Traverse); + + SetNormIncref(0.0); + SetNormAlbedo(1.0); + + if (algorithm.HasKeyword("Incref")) { + SetNormIncref(algorithm["Incref"]); + } + + if (algorithm.HasKeyword("Albedo")) { + SetNormAlbedo(algorithm["Albedo"]); + } + } + + void Shade::NormModelAlgorithm (double phase, double incidence, + double emission, double dn, double &albedo, double &mult, + double &base) + { + double rho; + double psurfref; + + // Calculate normalization at standard conditions + GetPhotoModel()->SetStandardConditions(true); + psurfref = GetPhotoModel()->CalcSurfAlbedo(p_normIncref, p_normIncref, 0.0); + GetPhotoModel()->SetStandardConditions(false); + + if (psurfref == 0.0) { + std::string msg = "Divide by zero error"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + + rho = p_normAlbedo / psurfref; + + albedo = rho * GetPhotoModel()->CalcSurfAlbedo(phase, incidence, emission); + } + + /** + * Set the normalization function parameter. This is the + * reference incidence angle to which the image photometry will + * be normalized. This parameter is limited to values that are + * >=0 and <90. + * + * @param incref Normalization function parameter, default + * is 0.0 + */ + void Shade::SetNormIncref (const double incref) { + if (incref < 0.0 || incref >= 90.0) { + std::string msg = "Invalid value of normalization incref [" + iString(incref) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_normIncref = incref; + } + + /** + * Set the normalization function parameter. + * This is the albedo (I/F value at incidence p_normIncref + * and zero phase) used to simulate a shaded relief image. To + * construct mosaics, the same value of albedo should be used + * for all images to achieve a uniform result. + * + * @param albedo Normalization function parameter + */ + void Shade::SetNormAlbedo (const double albedo) { + p_normAlbedo = albedo; + } +} + +extern "C" Isis::NormModel *ShadePlugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel) { + return new Isis::Shade(pvl,pmodel); +} diff --git a/isis/src/base/objs/Shade/Shade.h b/isis/src/base/objs/Shade/Shade.h new file mode 100644 index 0000000000000000000000000000000000000000..69aacd585b5a7592e30d6146e062e642a15e47cc --- /dev/null +++ b/isis/src/base/objs/Shade/Shade.h @@ -0,0 +1,62 @@ +#ifndef Shade_h +#define Shade_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/06/18 19:00:36 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "NormModel.h" + +namespace Isis { + class Pvl; + + /** + * @brief + * + * @author 2003-04-08 Randy Kirk + * + * @internal + * @history 2007-07-31 Steven Lambright - Refactored code + */ + class Shade : public NormModel { + public: + Shade (Pvl &pvl, PhotoModel &pmodel); + virtual ~Shade() {}; + + //! Set parameters needed for albedo normalization + void SetNormIncref(const double incref); + void SetNormAlbedo(const double albedo); + + protected: + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double dn, double &albedo, double &mult, double &base); + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double deminc, double demema, double dn, double &albedo, + double &mult, double &base) {}; + + private: + double p_normIncref; + double p_normAlbedo; + + }; +}; + +#endif diff --git a/isis/src/base/objs/Shade/Shade.truth b/isis/src/base/objs/Shade/Shade.truth new file mode 100644 index 0000000000000000000000000000000000000000..fc316b20ba4fc811ab8cf839a462b938e0c48dd0 --- /dev/null +++ b/isis/src/base/objs/Shade/Shade.truth @@ -0,0 +1,25 @@ +UNIT TEST for Shade normalization function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = NormalizationModel + Group = Algorithm + Name = Shade + Albedo = 0.0690507 + End_Group +End_Object +End + +Test phase=86.7226722, incidence=51.7002388, emission=38.9414439, dn=.0800618902 ... +Normalization value = 0.042796 + +Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0797334611 ... +Normalization value = 0.0427932 + +Test phase=86.7187773, incidence=51.7060221, emission=38.9331391, dn=.0794225037 ... +Normalization value = 0.0427905 + diff --git a/isis/src/base/objs/Shade/unitTest.cpp b/isis/src/base/objs/Shade/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..67cd0932402b8457f9729e7ccd8e8c720fa9f4ec --- /dev/null +++ b/isis/src/base/objs/Shade/unitTest.cpp @@ -0,0 +1,67 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "NormModel.h" +#include "NormModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + double result; + double mult; + double base; + + std::cout << "UNIT TEST for Shade normalization function" << std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup algn("Algorithm"); + algn += PvlKeyword("Name", "Shade"); + algn += PvlKeyword("Albedo", .0690507); + + PvlObject on("NormalizationModel"); + on.AddGroup(algn); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(on); + + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + NormModel *nm = NormModelFactory::Create(pvl,*pm); + + nm->CalcNrmAlbedo(86.7226722,51.7002388,38.9414439,.0800618902,result,mult,base); + + std::cout << "Test phase=86.7226722, incidence=51.7002388, emission=38.9414439, dn=.0800618902 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + + nm->CalcNrmAlbedo(86.7207248,51.7031305,38.9372914,.0797334611,result,mult,base); + + std::cout << "Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0797334611 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + + nm->CalcNrmAlbedo(86.7187773,51.7060221,38.9331391,.0794225037,result,mult,base); + + std::cout << "Test phase=86.7187773, incidence=51.7060221, emission=38.9331391, dn=.0794225037 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/ShadeAtm/Makefile b/isis/src/base/objs/ShadeAtm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9b9471f374f35306ee4c51e3b40961e4cb093f8f --- /dev/null +++ b/isis/src/base/objs/ShadeAtm/Makefile @@ -0,0 +1,5 @@ +INCS = ShadeAtm.h +SRCS = ShadeAtm.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/ShadeAtm/NormModel.plugin b/isis/src/base/objs/ShadeAtm/NormModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..40a8574114c549c8de8cf10984c0e33c94cdf769 --- /dev/null +++ b/isis/src/base/objs/ShadeAtm/NormModel.plugin @@ -0,0 +1,4 @@ +Group = ShadeAtm + Library = ShadeAtm + Routine = ShadeAtmPlugin +End_Group diff --git a/isis/src/base/objs/ShadeAtm/ShadeAtm.cpp b/isis/src/base/objs/ShadeAtm/ShadeAtm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a2cbd86508269923a4630e8daccf752bf4824b9 --- /dev/null +++ b/isis/src/base/objs/ShadeAtm/ShadeAtm.cpp @@ -0,0 +1,110 @@ +#include +#include "ShadeAtm.h" +#include "AtmosModel.h" +#include "NumericalApproximation.h" +#include "iException.h" + +namespace Isis { + ShadeAtm::ShadeAtm (Pvl &pvl, PhotoModel &pmodel, AtmosModel &amodel) : NormModel(pvl,pmodel,amodel) { + PvlGroup &algorithm = pvl.FindObject("NormalizationModel").FindGroup("Algorithm",Pvl::Traverse); + + SetNormIncref(0.0); + SetNormAlbedo(1.0); + + if (algorithm.HasKeyword("Incref")) { + SetNormIncref(algorithm["Incref"]); + } + + if (algorithm.HasKeyword("Albedo")) { + SetNormAlbedo(algorithm["Albedo"]); + } + } + + /* + * @param phase Phase angle + * @param incidence Incidence angle + * @param emission Emission angle + * @param dn + * @param albedo + * @param mult + * @param base + * + * @history 2008-11-05 Jeannie Walldren - Modified references + * to NumericalMethods class and replaced Isis::PI + * with PI since this is in Isis namespace. + * + */ + void ShadeAtm::NormModelAlgorithm (double phase, double incidence, + double emission, double dn, double &albedo, double &mult, double &base) + { + double rho; + double psurfref; + double psurf; + double ahInterp; + double munot; + double pstd; + double trans; + double trans0; + double sbar; + + // Calculate normalization at standard conditions + GetPhotoModel()->SetStandardConditions(true); + psurfref = GetPhotoModel()->CalcSurfAlbedo(p_normIncref, p_normIncref, 0.0); + GetPhotoModel()->SetStandardConditions(false); + + // Get reference hemispheric albedo (Hapke opposition effect doesn't influence it much) + GetAtmosModel()->GenerateAhTable(); + + if (psurfref == 0.0) { + std::string msg = "Divide by zero error"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + + rho = p_normAlbedo / psurfref; + + psurf = GetPhotoModel()->CalcSurfAlbedo(phase, incidence, emission); + + ahInterp = (GetAtmosModel()->AtmosAhSpline()).Evaluate(incidence,NumericalApproximation::Extrapolate); + + munot = cos(incidence*(PI/180.0)); + GetAtmosModel()->CalcAtmEffect(phase,incidence,emission,&pstd,&trans,&trans0,&sbar); + + albedo = pstd + rho * (ahInterp * munot * trans / + (1.0 - rho * GetAtmosModel()->AtmosAb() * sbar) + (psurf - ahInterp * munot) * trans0); + } + + /** + * Set the normalization function parameter. This is the + * reference incidence angle to which the image photometry will + * be normalized. This parameter is limited to values that are + * >=0 and <90. + * + * @param incref Normalization function parameter, default + * is 0.0 + */ + void ShadeAtm::SetNormIncref (const double incref) { + if (incref < 0.0 || incref >= 90.0) { + std::string msg = "Invalid value of normalization incref [" + + iString(incref) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_normIncref = incref; + } + + /** + * Set the normalization function parameter. This is the albedo (I/F + * value at incidence p_normIncref and zero phase) used to + * simulate a shaded relief image. To construct mosaics, the same value + * of albedo should be used for all images to achieve a uniform result. + * + * @param albedo Normalization function parameter + */ + void ShadeAtm::SetNormAlbedo (const double albedo) { + p_normAlbedo = albedo; + } +} + +extern "C" Isis::NormModel *ShadeAtmPlugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel, Isis::AtmosModel &amodel) { + return new Isis::ShadeAtm(pvl,pmodel,amodel); +} diff --git a/isis/src/base/objs/ShadeAtm/ShadeAtm.h b/isis/src/base/objs/ShadeAtm/ShadeAtm.h new file mode 100644 index 0000000000000000000000000000000000000000..76487507925665d4e63c730f8db8f8990bfce097 --- /dev/null +++ b/isis/src/base/objs/ShadeAtm/ShadeAtm.h @@ -0,0 +1,68 @@ +#ifndef ShadeAtm_h +#define ShadeAtm_h +/** + * @file + * $Revision: 1.6 $ + * $Date: 2009/05/11 21:56:13 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "NormModel.h" + +namespace Isis { + class Pvl; + + /** + * @brief + * + * @ingroup RadiometricAndPhotometricCorrection + * @author 1998-12-21 Randy Kirk + * + * @internal + * @history 2007-08-15 Steven Lambright - Refactored code + * @history 2008-11-05 Jeannie Walldren - Modified references + * to NumericalMethods class. + * @history 2009-05-11 Janet Barrett - Fixed so that the NormModelAlgorithm + * supporting DEM input is the empty function. DEM input is not yet + * supported. + + */ + class ShadeAtm : public NormModel { + public: + ShadeAtm (Pvl &pvl, PhotoModel &pmodel, AtmosModel &amodel); + virtual ~ShadeAtm() {}; + + protected: + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double dn, double &albedo, double &mult, double &base); + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double deminc, double demema, double dn, double &albedo, + double &mult, double &base) {}; + + private: + void SetNormIncref(const double incref); + void SetNormAlbedo(const double albedo); + + double p_normIncref; + double p_normAlbedo; + + }; +}; + +#endif diff --git a/isis/src/base/objs/ShadeAtm/ShadeAtm.truth b/isis/src/base/objs/ShadeAtm/ShadeAtm.truth new file mode 100644 index 0000000000000000000000000000000000000000..2153151129387a2cb1549563f9bed13cc87bb49d --- /dev/null +++ b/isis/src/base/objs/ShadeAtm/ShadeAtm.truth @@ -0,0 +1,32 @@ +UNIT TEST for ShadeAtm normalization function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = AtmosphericModel + Group = Algorithm + Name = Anisotropic1 + Bha = 0.85 + End_Group +End_Object + +Object = NormalizationModel + Group = Algorithm + Name = ShadeAtm + Albedo = 0.0690507 + End_Group +End_Object +End + +Test phase=86.7226722, incidence=51.7002388, emission=38.9414439, dn=.0800618902 ... +Normalization value = 0.131329 + +Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0797334611 ... +Normalization value = 0.131322 + +Test phase=86.7187773, incidence=51.7060221, emission=38.9331391, dn=.0794225037 ... +Normalization value = 0.131316 + diff --git a/isis/src/base/objs/ShadeAtm/unitTest.cpp b/isis/src/base/objs/ShadeAtm/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee289332c2777688d5bb6421aa0cd6688ad54bbf --- /dev/null +++ b/isis/src/base/objs/ShadeAtm/unitTest.cpp @@ -0,0 +1,81 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "AtmosModel.h" +#include "AtmosModelFactory.h" +#include "NormModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "ShadeAtm.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + double result; + double mult; + double base; + + std::cout << "UNIT TEST for ShadeAtm normalization function" << + std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup alga("Algorithm"); + alga += PvlKeyword("Name", "Anisotropic1"); + alga += PvlKeyword("Bha", 0.85); + + PvlObject oa("AtmosphericModel"); + oa.AddGroup(alga); + + PvlGroup algn("Algorithm"); + algn += PvlKeyword("Name", "ShadeAtm"); + algn += PvlKeyword("Albedo", 0.0690507); + + PvlObject on("NormalizationModel"); + on.AddGroup(algn); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(oa); + pvl.AddObject(on); + + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + AtmosModel *am = AtmosModelFactory::Create(pvl,*pm); + NormModel *nm = NormModelFactory::Create(pvl,*pm,*am); + + nm->CalcNrmAlbedo(86.7226722,51.7002388,38.9414439,.0800618902,result,mult,base); + + std::cout << "Test phase=86.7226722, incidence=51.7002388, emission=38.9414439, " << + "dn=.0800618902 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + + nm->CalcNrmAlbedo(86.7207248,51.7031305,38.9372914,.0797334611,result,mult,base); + + std::cout << "Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, " << + "dn=.0797334611 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + + nm->CalcNrmAlbedo(86.7187773,51.7060221,38.9331391,.0794225037,result,mult,base); + + std::cout << "Test phase=86.7187773, incidence=51.7060221, emission=38.9331391, " << + "dn=.0794225037 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/SimpleCylindrical/Makefile b/isis/src/base/objs/SimpleCylindrical/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..454b86dab2bdf893f95d37869387138942c05b0b --- /dev/null +++ b/isis/src/base/objs/SimpleCylindrical/Makefile @@ -0,0 +1,5 @@ +INCS = SimpleCylindrical.h +SRCS = SimpleCylindrical.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/SimpleCylindrical/Projection.plugin b/isis/src/base/objs/SimpleCylindrical/Projection.plugin new file mode 100644 index 0000000000000000000000000000000000000000..b256f87defb926d1bf4c4a7e96eccc6b5813fe32 --- /dev/null +++ b/isis/src/base/objs/SimpleCylindrical/Projection.plugin @@ -0,0 +1,6 @@ +Group = SimpleCylindrical + Library = SimpleCylindrical + Routine = SimpleCylindricalPlugin + Keyword = CenterLongitude +EndGroup + diff --git a/isis/src/base/objs/SimpleCylindrical/SimpleCylindrical.cpp b/isis/src/base/objs/SimpleCylindrical/SimpleCylindrical.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc0443a4d49489a25e901f90f9bc3a916bcbffb8 --- /dev/null +++ b/isis/src/base/objs/SimpleCylindrical/SimpleCylindrical.cpp @@ -0,0 +1,248 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/05/09 18:49:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "SimpleCylindrical.h" +#include "iException.h" +#include "Constants.h" + +using namespace std; +namespace Isis { + + /** + * Constructs a SimpleCylindrical object. + * + * @param label This argument must be a Label containing the proper mapping + * information as indicated in the Projection class. + * Additionally, the simple cylindrical projection requires the + * center longitude to be defined in the keyword CenterLongitude. + * + * @param allowDefaults If set to false the constructor requires that the + * keyword CenterLongitude exist in the label. Otherwise + * if it does not exist it will be computed and written + * to the label using the middle of the longitude range + * as specified in the labels. Defaults to false + * + * @throws Isis::iException::Io + */ + SimpleCylindrical::SimpleCylindrical(Isis::Pvl &label, bool allowDefaults) : + Isis::Projection::Projection (label) { + try { + // Try to read the mapping group + Isis::PvlGroup &mapGroup = label.FindGroup ("Mapping",Isis::Pvl::Traverse); + + // Compute the default value if allowed and needed + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLongitude"))) { + double lon = (p_minimumLongitude + p_maximumLongitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLongitude",lon); + } + + // Get the center longitude, convert to radians, adjust for longitude + // direction + p_centerLongitude = mapGroup["CenterLongitude"]; + p_centerLongitude *= Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) p_centerLongitude *= -1.0; + } + catch (Isis::iException &e) { + string message = "Invalid label group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + //! Destroys the SimpleCylindrical object + SimpleCylindrical::~SimpleCylindrical() { + } + + /** + * This method is used to set the latitude/longitude (assumed to be of the + * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. + * + * @param lat Latitude value to project + * + * @param lon Longitude value to project + * + * @return bool + */ + bool SimpleCylindrical::SetGround(const double lat,const double lon) { + // Convert to radians + p_latitude = lat; + p_longitude = lon; + double latRadians = lat * Isis::PI / 180.0; + double lonRadians = lon * Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) lonRadians *= -1.0; + + // Compute the coordinate + double deltaLon = (lonRadians - p_centerLongitude); + double x = p_equatorialRadius * deltaLon; + double y = p_equatorialRadius * latRadians; + SetComputedXY(x,y); + p_good = true; + return p_good; + } + + /** + * This method is used to set the projection x/y. The Set forces an attempted + * calculation of the corresponding latitude/longitude position. This may or + * may not be successful and a status is returned as such. + * + * @param x X coordinate of the projection in units that are the same as the + * radii in the label + * + * @param y Y coordinate of the projection in units that are the same as the + * radii in the label + * + * @return bool + */ + bool SimpleCylindrical::SetCoordinate(const double x, const double y) { + // Save the coordinate + SetXY(x,y); + + // Compute latitude and make sure it is not above 90 + p_latitude = GetY() / p_equatorialRadius; + if ((fabs(p_latitude) - Isis::HALFPI) > DBL_EPSILON) { + p_good = false; + return p_good; + } + + // Compute longitude + p_longitude = p_centerLongitude + GetX() / p_equatorialRadius; + + // Convert to degrees + p_latitude *= 180.0 / Isis::PI; + p_longitude *= 180.0 / Isis::PI; + + // Cleanup the longitude + if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; + // Do these if the projection is circular + // p_longitude = To360Domain (p_longitude); + // if (p_longitudeDomain == 180) p_longitude = To180Domain(p_longitude); + + p_good = true; + return p_good; + } + + /** + * This method is used to determine the x/y range which completely covers the + * area of interest specified by the lat/lon range. The latitude/longitude + * range may be obtained from the labels. The purpose of this method is to + * return the x/y range so it can be used to compute how large a map may need + * to be. For example, how big a piece of paper is needed or how large of an + * image needs to be created. The method may fail as indicated by its return + * value. + * + * @param minX Minimum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxX Maximum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param minY Minimum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxY Maximum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @return bool + */ + bool SimpleCylindrical::XYRange(double &minX, double &maxX, + double &minY, double&maxY) { + // Check the corners of the lat/lon range + XYRangeCheck (p_minimumLatitude,p_minimumLongitude); + XYRangeCheck (p_maximumLatitude,p_minimumLongitude); + XYRangeCheck (p_minimumLatitude,p_maximumLongitude); + XYRangeCheck (p_maximumLatitude,p_maximumLongitude); + + // Make sure everything is ordered + if (p_minimumX >= p_maximumX) return false; + if (p_minimumY >= p_maximumY) return false; + + // Return X/Y min/maxs + minX = p_minimumX; + maxX = p_maximumX; + minY = p_minimumY; + maxY = p_maximumY; + return true; + } + + + /** + * This function returns the keywords that this projection uses. + * + * @return PvlGroup The keywords that this projection uses + */ + PvlGroup SimpleCylindrical::Mapping() { + PvlGroup mapping = Projection::Mapping(); + + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * This function returns the latitude keywords that this projection uses + * + * @return PvlGroup The latitude keywords that this projection uses + */ + PvlGroup SimpleCylindrical::MappingLatitudes() { + PvlGroup mapping = Projection::MappingLatitudes(); + + return mapping; + } + + /** + * This function returns the longitude keywords that this projection uses + * + * @return PvlGroup The longitude keywords that this projection uses + */ + PvlGroup SimpleCylindrical::MappingLongitudes() { + PvlGroup mapping = Projection::MappingLongitudes(); + + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * Compares two Projection objects to see if they are equal + * + * @param proj Projection object to do comparison on + * + * @return bool Returns true if the Projection objects are equal, and false if + * they are not + */ + bool SimpleCylindrical::operator== (const Isis::Projection &proj) { + if (!Isis::Projection::operator==(proj)) return false; + // dont do the below it is a recusive plunge + // if (Isis::Projection::operator!=(proj)) return false; + SimpleCylindrical *simp = (SimpleCylindrical *) &proj; + if (simp->p_centerLongitude != this->p_centerLongitude) return false; + return true; + } +} // end namespace isis + +extern "C" Isis::Projection *SimpleCylindricalPlugin (Isis::Pvl &lab, + bool allowDefaults) { + return new Isis::SimpleCylindrical(lab,allowDefaults); +} diff --git a/isis/src/base/objs/SimpleCylindrical/SimpleCylindrical.h b/isis/src/base/objs/SimpleCylindrical/SimpleCylindrical.h new file mode 100644 index 0000000000000000000000000000000000000000..cab60ad87a66395a618fc462cef54c7eceb49f10 --- /dev/null +++ b/isis/src/base/objs/SimpleCylindrical/SimpleCylindrical.h @@ -0,0 +1,99 @@ +#ifndef SimpleCylindrical_h +#define SimpleCylindrical_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/05/09 18:49:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Projection.h" + +namespace Isis { +/** + * @brief Simple Cylindrical Map Projection + * + * This class provides methods for the forward and inverse equations of a Simple + * Cylindrical map projection (for a sphere). The code was converted to C++ from + * the Fortran version of the USGS General Cartographic Transformation Package + * (GCTP). In particular it was modified from the Equidistant Cylindrical code. + * This class inherits Projection and provides the two virtual methods SetGround + * (forward) and SetCoordinate (inverse) and a third virtual method, XYRange, + * for obtaining projection coordinate coverage for a latitude/longitude window. + * Please see the Projection class for a full accounting of all the methods + * available. + * + * @ingroup MapProjection + * + * @author 2003-01-29 Jeff Anderson + * + * @internal + * @history 2003-01-30 Jeff Anderson - Removed IsisWorldMapper argument from + * the constructor + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-06-05 Jeff Anderson - Changed SetCoordinate method so it did + * not adjust longitude into the longitude + * domain + * @history 2003-09-26 Jeff Anderson - Provided virtual methods for Name and + * operator== + * @history 2003-11-13 Jeff Anderson - Modified constructor to allow for + * computation for default value for + * CenterLongitude keyword. + * @history 2005-02-15 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2007-06-29 Steven Lambright - Added Mapping, MappingLatitudes and + * MappingLongitudes methods. + * @history 2008-05-09 Steven Lambright - Added Name, Version, IsEquatorialCylindrical methods + */ + class SimpleCylindrical : public Isis::Projection { + public: + SimpleCylindrical (Isis::Pvl &label, bool allowDefaults=false); + ~SimpleCylindrical (); + bool SetGround (const double lat, const double lon); + bool SetCoordinate (const double x, const double y); + bool XYRange (double &minX, double &maxX, double &minY, double &maxY); + PvlGroup Mapping(); + PvlGroup MappingLatitudes(); + PvlGroup MappingLongitudes(); + bool IsEquatorialCylindrical() { return true; } + + /** + * Returns the name of the map projection + * + * @return string Name of projection + */ + std::string Name() const { return "SimpleCylindrical"; } + + /** + * Returns the version of the map projection + * + * + * @return std::string Version number + */ + std::string Version () const { return "1.0"; } + + bool operator==(const Isis::Projection &proj); + + private: + double p_centerLongitude; //! +#include +#include "iException.h" +#include "SimpleCylindrical.h" +#include "ProjectionFactory.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "UNIT TEST FOR SimpleCylindrical" << endl << endl; + + Isis::Pvl lab; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGrp = lab.FindGroup("Mapping"); + mapGrp += Isis::PvlKeyword("EquatorialRadius",1.0); + mapGrp += Isis::PvlKeyword("PolarRadius",1.0); + mapGrp += Isis::PvlKeyword("LatitudeType","Planetocentric"); + mapGrp += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGrp += Isis::PvlKeyword("LongitudeDomain",180); + mapGrp += Isis::PvlKeyword("MinimumLatitude",-90.0); + mapGrp += Isis::PvlKeyword("MaximumLatitude",90.0); + mapGrp += Isis::PvlKeyword("MinimumLongitude",-180.0); + mapGrp += Isis::PvlKeyword("MaximumLongitude",180.0); + mapGrp += Isis::PvlKeyword("ProjectionName","SimpleCylindrical"); + + cout << "Test missing center longitude keyword ..." << endl; + try { + Isis::SimpleCylindrical p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + try { + mapGrp += Isis::PvlKeyword("CenterLongitude",-90.0); + Isis::Projection &p = *Isis::ProjectionFactory::Create(lab); + + cout << "Test SetGround method ... " << endl; + cout << std::setprecision(16); + cout << "Setting ground to (-50,-75)" << endl; + p.SetGround(-50.0,-75.0); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + + cout << "Test SetCoordinate method ... " << endl; + cout << "Setting coordinate to (0.2617993877991494,-0.8726646259971648)" << endl; + p.SetCoordinate(0.2617993877991494,-0.8726646259971648); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + cout << "Test XYRange method ... " << endl; + double minX,maxX,minY,maxY; + p.XYRange(minX,maxX,minY,maxY); + cout << "Minimum X: " << minX << endl; + cout << "Maximum X: " << maxX << endl; + cout << "Minimum Y: " << minY << endl; + cout << "Maximum Y: " << maxY << endl; + cout << endl; + + Isis::Projection *s = &p; + cout << "Test Name and comparision method ... " << endl; + cout << "Name: " << s->Name() << endl; + cout << "operator== " << (*s == *s) << endl; + cout << endl; + + cout << "Testing default option ... " << endl; + mapGrp.DeleteKeyword("CenterLongitude"); + Isis::SimpleCylindrical p2(lab,true); + cout << lab << endl; + cout << endl; + + cout << "Testing Mapping() methods ... " << endl; + + Isis::Pvl tmp1; + Isis::Pvl tmp2; + Isis::Pvl tmp3; + tmp1.AddGroup(p.Mapping()); + tmp2.AddGroup(p.MappingLatitudes()); + tmp3.AddGroup(p.MappingLongitudes()); + + cout << "Mapping() = " << endl; + cout << tmp1 << endl; + cout << "MappingLatitudes() = " << endl; + cout << tmp2 << endl; + cout << "MappingLongitudes() = " << endl; + cout << tmp3 << endl; + cout << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } +} + + + diff --git a/isis/src/base/objs/Sinusoidal/Makefile b/isis/src/base/objs/Sinusoidal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3c278ba48ca576f9c7efe619879ac67ed118ae9d --- /dev/null +++ b/isis/src/base/objs/Sinusoidal/Makefile @@ -0,0 +1,5 @@ +INCS = Sinusoidal.h +SRCS = Sinusoidal.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Sinusoidal/Projection.plugin b/isis/src/base/objs/Sinusoidal/Projection.plugin new file mode 100644 index 0000000000000000000000000000000000000000..201426e4a1ffc7c7ff9fa3924beb55703b67d0f2 --- /dev/null +++ b/isis/src/base/objs/Sinusoidal/Projection.plugin @@ -0,0 +1,7 @@ +Group = Sinusoidal + Library = Sinusoidal + Routine = SinusoidalPlugin + Keyword = CenterLongitude +EndGroup + + diff --git a/isis/src/base/objs/Sinusoidal/Sinusoidal.cpp b/isis/src/base/objs/Sinusoidal/Sinusoidal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e9aaeb603ef1dd94f5ef808730683502605d66e --- /dev/null +++ b/isis/src/base/objs/Sinusoidal/Sinusoidal.cpp @@ -0,0 +1,270 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/05/09 18:49:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Sinusoidal.h" +#include "iException.h" +#include "Constants.h" + +using namespace std; +namespace Isis { + + /** + * Constructs a Sinusoidal object. + * + * @param label This argument must be a Label containing the proper mapping + * information as indicated in the Projection class. Additionally, + * the sinusoidal projection requires the center longitude to be + * defined in the keyword CenterLongitude. + * + * @param allowDefaults If set to false the constructor expects that a keyword + * of CenterLongitude will be in the label. Otherwise it + * will attempt to compute the center longitude using the + * middle of the longitude range specified in the labels. + * Defaults to false + * + * @throws Isis::iException::Io + */ + Sinusoidal::Sinusoidal(Isis::Pvl &label, bool allowDefaults) : + Isis::Projection::Projection (label) { + try { + // Try to read the mapping group + Isis::PvlGroup &mapGroup = label.FindGroup ("Mapping",Isis::Pvl::Traverse); + + // Compute and write the default center longitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLongitude"))) { + double lon = (p_minimumLongitude + p_maximumLongitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLongitude",lon); + } + + // Get the center longitude + p_centerLongitude = mapGroup["CenterLongitude"]; + + // convert to radians, adjust for longitude direction + p_centerLongitude *= Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) p_centerLongitude *= -1.0; + } + catch (Isis::iException &e) { + string message = "Invalid label group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + //! Destroys the Sinusoidal object + Sinusoidal::~Sinusoidal() { + } + + /** + * This method is used to set the latitude/longitude (assumed to be of the + * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. + * + * @param lat Latitude value to project + * + * @param lon Longitude value to project + * + * @return bool + */ + bool Sinusoidal::SetGround(const double lat,const double lon) { + // Convert to radians + p_latitude = lat; + p_longitude = lon; + double latRadians = lat * Isis::PI / 180.0; + double lonRadians = lon * Isis::PI / 180.0; + if (p_longitudeDirection == PositiveWest) lonRadians *= -1.0; + + // Compute the coordinate + double deltaLon = (lonRadians - p_centerLongitude); + double x = p_equatorialRadius * deltaLon * cos(latRadians); + double y = p_equatorialRadius * latRadians; + SetComputedXY(x,y); + p_good = true; + return p_good; + } + + /** + * This method is used to set the projection x/y. The Set forces an attempted + * calculation of the corresponding latitude/longitude position. This may or + * may not be successful and a status is returned as such. + * + * @param x X coordinate of the projection in units that are the same as the + * radii in the label + * + * @param y Y coordinate of the projection in units that are the same as the + * radii in the label + * + * @return bool + */ + bool Sinusoidal::SetCoordinate(const double x, const double y) { + // Save the coordinate + SetXY(x,y); + + // Compute latitude and make sure it is not above 90 + p_latitude = GetY() / p_equatorialRadius; + if (fabs(p_latitude) > Isis::HALFPI) { + if (fabs(Isis::HALFPI - fabs(p_latitude)) > DBL_EPSILON) { + p_good = false; + return p_good; + } + else if (p_latitude < 0.0) { + p_latitude = -Isis::HALFPI; + } + else { + p_latitude = Isis::HALFPI; + } + } + + // Compute longitude + double coslat = cos(p_latitude); + if (coslat <= DBL_EPSILON) { + p_longitude = p_centerLongitude; + } + else { + p_longitude = p_centerLongitude + GetX() / (p_equatorialRadius * coslat); + } + + // Convert to degrees + p_latitude *= 180.0 / Isis::PI; + p_longitude *= 180.0 / Isis::PI; + + // Cleanup the longitude + if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; + // These need to be done for circular type projections + // p_longitude = To360Domain (p_longitude); + // if (p_longitudeDomain == 180) p_longitude = To180Domain(p_longitude); + + p_good = true; + return p_good; + } + + /** + * This method is used to determine the x/y range which completely covers the + * area of interest specified by the lat/lon range. The latitude/longitude + * range may be obtained from the labels. The purpose of this method is to + * return the x/y range so it can be used to compute how large a map may need + * to be. For example, how big a piece of paper is needed or how large of an + * image needs to be created. The method may fail as indicated by its return + * value. + * + * @param minX Minimum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxX Maximum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param minY Minimum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxY Maximum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @return bool + */ + bool Sinusoidal::XYRange(double &minX, double &maxX, + double &minY, double&maxY) { + // Check the corners of the lat/lon range + XYRangeCheck (p_minimumLatitude,p_minimumLongitude); + XYRangeCheck (p_maximumLatitude,p_minimumLongitude); + XYRangeCheck (p_minimumLatitude,p_maximumLongitude); + XYRangeCheck (p_maximumLatitude,p_maximumLongitude); + + // If the latitude crosses the equator check there + if ((p_minimumLatitude < 0.0) && (p_maximumLatitude > 0.0)) { + XYRangeCheck (0.0,p_minimumLongitude); + XYRangeCheck (0.0,p_maximumLongitude); + } + + // Make sure everything is ordered + if (p_minimumX >= p_maximumX) return false; + if (p_minimumY >= p_maximumY) return false; + + // Return X/Y min/maxs + minX = p_minimumX; + maxX = p_maximumX; + minY = p_minimumY; + maxY = p_maximumY; + return true; + } + + + /** + * This function returns the keywords that this projection uses. + * + * @return PvlGroup The keywords that this projection uses + */ + PvlGroup Sinusoidal::Mapping() { + PvlGroup mapping = Projection::Mapping(); + + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * This function returns the latitude keywords that this projection uses + * + * @return PvlGroup The latitude keywords that this projection uses + */ + PvlGroup Sinusoidal::MappingLatitudes() { + PvlGroup mapping = Projection::MappingLatitudes(); + + return mapping; + } + + /** + * This function returns the longitude keywords that this projection uses + * + * @return PvlGroup The longitude keywords that this projection uses + */ + PvlGroup Sinusoidal::MappingLongitudes() { + PvlGroup mapping = Projection::MappingLongitudes(); + + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * Compares two Projection objects to see if they are equal + * + * @param proj Projection object to do comparison on + * + * @return bool Returns true if the Projection objects are equal, and false if + * they are not + */ + bool Sinusoidal::operator== (const Isis::Projection &proj) { + if (!Isis::Projection::operator==(proj)) return false; + // dont do the below it is a recusive plunge + // if (Isis::Projection::operator!=(proj)) return false; + Sinusoidal *sinu = (Sinusoidal *) &proj; + if (sinu->p_centerLongitude != this->p_centerLongitude) return false; + return true; + } +} // end namespace isis + +extern "C" Isis::Projection *SinusoidalPlugin (Isis::Pvl &lab, + bool allowDefaults) { + return new Isis::Sinusoidal(lab,allowDefaults); +} diff --git a/isis/src/base/objs/Sinusoidal/Sinusoidal.h b/isis/src/base/objs/Sinusoidal/Sinusoidal.h new file mode 100644 index 0000000000000000000000000000000000000000..18824ff931b9202f9fac2482ca07fde8994092cd --- /dev/null +++ b/isis/src/base/objs/Sinusoidal/Sinusoidal.h @@ -0,0 +1,99 @@ +#ifndef Sinusoidal_h +#define Sinusoidal_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/05/09 18:49:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Projection.h" + +namespace Isis { +/** + * @brief Sinusoidal Map Projection + * + * This class provides methods for the forward and inverse equations of a + * Sinusoidal Equal-Area map projection (for a sphere). The code was converted + * to C++ from the Fortran version of the USGS General Cartographic + * Transformation Package (GCTP). This class inherits Projection and provides + * the two virtual methods SetGround (forward) and SetCoordinate (inverse) and + * a third virtual method, XYRange, for obtaining projection coordinate coverage + * for a latitude/longitude window. Please see the Projection class for a full + * accounting of all the methods available. + * + * @ingroup MapProjection + * + * @author 2003-01-29 Jeff Anderson + * + * @internal + * @history 2003-01-30 Jeff Anderson - Removed WorldMapper argument from the + * constructor + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-06-05 Jeff Anderson - Changed SetCoordinate method so it does + * not adjust the longitude into the + * longitude domain + * @history 2003-09-26 Jeff Anderson - Provided virtual methods for Name and + * operator== + * @history 2003-11-13 Jeff Anderson - Modified constructor to allow for + * computation of default center longitude + * using the longitude range. + * @history 2004-02-07 Jeff Anderson - Added plugin routine and file + * @history 2005-02-15 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2007-06-29 Steven Lambright - Added Mapping, MappingLatitudes and + * MappingLongitudes methods. + * @history 2008-05-09 Steven Lambright - Added Name, Version methods + */ + + class Sinusoidal : public Isis::Projection { + public: + Sinusoidal (Isis::Pvl &label, bool allowDefaults=false); + ~Sinusoidal (); + bool SetGround (const double lat, const double lon); + bool SetCoordinate (const double x, const double y); + bool XYRange (double &minX, double &maxX, double &minY, double &maxY); + PvlGroup Mapping(); + PvlGroup MappingLatitudes(); + PvlGroup MappingLongitudes(); + + /** + * Returns the name of the map projection + * + * @return string Name of projection + */ + std::string Name() const { return "Sinusoidal"; } + + /** + * Returns the version of the map projection + * + * + * @return std::string Version number + */ + std::string Version () const { return "1.0"; } + + bool operator== (const Isis::Projection &proj); + + private: + double p_centerLongitude; //! +#include +#include "iException.h" +#include "Sinusoidal.h" +#include "ProjectionFactory.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Unit Test For Sinusodial" << endl << endl; + + Isis::Pvl lab; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = lab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",1.0); + mapGroup += Isis::PvlKeyword("PolarRadius",1.0); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetocentric"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",180); + mapGroup += Isis::PvlKeyword("MinimumLatitude",-90.0); + mapGroup += Isis::PvlKeyword("MaximumLatitude",90.0); + mapGroup += Isis::PvlKeyword("MinimumLongitude",-180.0); + mapGroup += Isis::PvlKeyword("MaximumLongitude",180.0); + mapGroup += Isis::PvlKeyword("ProjectionName","Sinusoidal"); + + cout << "Test missing center longitude keyword ..." << endl; + try { + Isis::Sinusoidal p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("CenterLongitude",-90.0); + + try { + Isis::Projection &p = *Isis::ProjectionFactory::Create(lab); + // Isis::Sinusoidal p(lab); + + cout << "Test SetGround method ... " << endl; + cout << std::setprecision(16); + cout << "Setting ground to (-50,-75)" << endl; + p.SetGround(-50.0,-75.0); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + + cout << "Test SetCoordinate method ... " << endl; + cout << "Setting coordinate to (0.1682814027008146,-0.8726646259971648)" << endl; + p.SetCoordinate(0.1682814027008146,-0.8726646259971648); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + cout << "Test XYRange method ... " << endl; + double minX,maxX,minY,maxY; + p.XYRange(minX,maxX,minY,maxY); + cout << "Minimum X: " << minX << endl; + cout << "Maximum X: " << maxX << endl; + cout << "Minimum Y: " << minY << endl; + cout << "Maximum Y: " << maxY << endl; + cout << endl; + + Isis::Projection *s = &p; + cout << "Test Name and comparision method ... " << endl; + cout << "Name: " << s->Name() << endl; + cout << "operator== " << (*s == *s) << endl; + cout << endl; + + cout << "Test default computation ... " << endl; + mapGroup.DeleteKeyword("CenterLongitude"); + Isis::Sinusoidal p2(lab,true); + cout << lab << endl; + cout << endl; + + cout << "Testing Mapping() methods ... " << endl; + + Isis::Pvl tmp1; + Isis::Pvl tmp2; + Isis::Pvl tmp3; + tmp1.AddGroup(p.Mapping()); + tmp2.AddGroup(p.MappingLatitudes()); + tmp3.AddGroup(p.MappingLongitudes()); + + cout << "Mapping() = " << endl; + cout << tmp1 << endl; + cout << "MappingLatitudes() = " << endl; + cout << tmp2 << endl; + cout << "MappingLongitudes() = " << endl; + cout << tmp3 << endl; + cout << endl; + + cout << "Unit test was obtained from:" << endl << endl; + cout << " Map Projections - A Working Manual" << endl; + cout << " USGS Professional Paper 1395 by John P. Snyder" << endl; + cout << " Pages 365-366" << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } +} + + + diff --git a/isis/src/base/objs/SpecialPixel/Makefile b/isis/src/base/objs/SpecialPixel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..273e6bd194c1fb49b3ed060743dcd09e9ddbb05d --- /dev/null +++ b/isis/src/base/objs/SpecialPixel/Makefile @@ -0,0 +1,5 @@ +INCS = SpecialPixel.h +SRCS = +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/SpecialPixel/SpecialPixel.h b/isis/src/base/objs/SpecialPixel/SpecialPixel.h new file mode 100644 index 0000000000000000000000000000000000000000..3de0bab906cd59869be711b6d66eec97ca7e5b41 --- /dev/null +++ b/isis/src/base/objs/SpecialPixel/SpecialPixel.h @@ -0,0 +1,417 @@ +#if !defined(SpecialPixel_h) +#define SpecialPixel_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/01/17 19:25:27 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include "iString.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Manipulate special pixel values + * + * This is not technically a class but instead a set of constants and + * functions which operate on Isis special pixels. There are several types of + * special pixels defined under the namespace Isis which include: + * Isis::Null Pixel has no data available + * Isis::Lis Pixel was saturated on the instrument + * Isis::His Pixel was saturated on the instrument + * Isis::Lrs Pixel was saturated during a computation + * Isis::Hrs Pixel was saturated during a computation + * As indicated, saturated pixels are either generated by the instrument or + * generated by a computation. For example, on the instrument with a 8-bit + * Analog-to-Digital converter, a gain setting could cause the conversion of + * many pixels to exceed 255. Because their are only 8-bits the value 255 is + * likely a High Instrument Saturation (His) value. Likewise, 0 would be a Low + * Instrument Saturation (Lis) value. The Lrs and Hrs values indicate Low or + * High Representation Saturation respectively. When an application program + * operates on non-special pixels using standard arithmetic operators (and + * other functions) it is possible that the operation could generate an Lrs or + * Hrs. Application programmer should take care when processing pixels to + * ensure that special pixels are not used in computations. These tests can be + * performed with various functions provided in this include file. + * + * @ingroup Utility + * + * @author 2002-04-11 Kris Becker + * + * @internal + * @history 2003-02-11 Jeff Anderson - Wrote unitTest and documentation + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2005-02-15 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-05-18 Jeff Anderson - Changed long to int for 64-bit port + * @history 2008-01-09 Jeannie Walldren - Added new unitTests + * and new method, StringToPixel() + * @history 2008-01-10 Jeannie Walldren - Added new unitTests + * and modified StringToPixel() to allow + * the user to enter any legal and unique + * shortened version of special pixels. + * + * + * @todo 2005-02-15 Kris Becker - finish class documentation + * + */ + +/// @cond INTERNAL + // Set up special kludge for double precision initialization + typedef union { + int i[2]; + double d; + } DBL_UNION; + +#if ISIS_LITTLE_ENDIAN +# define DBL_INIT(a,b) {(b), (a)} +#else +# define DBL_INIT(a,b) {(a), (b)} +#endif +/// @endcond + + // Define 8-byte special pixel values for IEEE floating point + const DBL_UNION IVALID_MIN8 = { DBL_INIT(0xFFEFFFFF, 0xFFFFFFFA) }; + const double VALID_MIN8 = IVALID_MIN8.d; + const double ValidMinimum = IVALID_MIN8.d; /**= VALID_MIN8); + } + + /** + * Returns if the input pixel is null + * + * @param d Pixel value to test + * + * @return bool + */ + inline bool IsNullPixel(const double d) { + return (d == NULL8); + } + + /** + * Returns if the input pixel is one of the high saturation types + * + * @param d Pixel value to test + * + * @return bool + */ + inline bool IsHighPixel(const double d) { + return (d == HIGH_REPR_SAT8) || (d == HIGH_INSTR_SAT8); + } + + /** + * Returns if the input pixel is one of the low saturation types + * + * @param d Pixel value to test + * + * @return bool + */ + inline bool IsLowPixel(const double d) { + return (d == LOW_REPR_SAT8) || (d == LOW_INSTR_SAT8); + } + + /** + * Returns if the input pixel is high representation saturation + * + * @param d Pixel value to test + * + * @return bool + */ + inline bool IsHrsPixel(const double d) { + return (d == HIGH_REPR_SAT8); + } + + /** + * Returns if the input pixel is high instrument saturation + * + * @param d Pixel value to test + * + * @return bool + */ + inline bool IsHisPixel(const double d) { + return (d == HIGH_INSTR_SAT8); + } + + /** + * Returns if the input pixel is low instrument saturation + * + * @param d Pixel value to test + * + * @return bool + */ + inline bool IsLisPixel(const double d) { + return (d == LOW_INSTR_SAT8); + } + + /** + * Returns if the input pixel is low representation saturation + * + * @param d Pixel value to test + * + * @return bool + */ + inline bool IsLrsPixel(const double d) { + return (d == LOW_REPR_SAT8); + } + + /** + * Converts float pixels to double pixels with special pixel translations + * + * @param t Float pixel value to be converted to a double + * + * @return double The double pixel value + */ + inline double TestPixel(const float t) { + if (t < VALID_MIN4) { + if (t == NULL4) return (NULL8); + if (t == LOW_REPR_SAT4) return (LOW_REPR_SAT8); + if (t == LOW_INSTR_SAT4) return (LOW_INSTR_SAT8); + if (t == HIGH_REPR_SAT4) return (HIGH_REPR_SAT8); + if (t == HIGH_INSTR_SAT4) return (HIGH_INSTR_SAT8); + return (LOW_REPR_SAT8); + } + else if (t > VALID_MAX4) { + return (HIGH_REPR_SAT8); + } + else { + return ((double) t); + } + } + + /** + * Converts double to float with special pixel translations and + * care for overflows (underflows are assumed to cast to 0!) + * + * @param t Double pixel value to be converted to a float + * + * @return float The float pixel value + */ + inline float TestPixel(const double t) { + if (t < (double) VALID_MIN4) { + if (t == NULL8) return (NULL4); + if (t == LOW_REPR_SAT8) return (LOW_REPR_SAT4); + if (t == LOW_INSTR_SAT8) return (LOW_INSTR_SAT4); + if (t == HIGH_INSTR_SAT8) return (HIGH_INSTR_SAT4); + if (t == HIGH_REPR_SAT8) return (HIGH_REPR_SAT4); + return (LOW_REPR_SAT4); + } + else if (t > (double) VALID_MAX4) { + return (HIGH_REPR_SAT8); + } + else { + return ((float) t); + } + } + + /** + * Takes a double pixel value and returns the name of the pixel type as a + * string + * + * @param d Pixel value + * + * @return string The name of the pixel type + */ + inline std::string PixelToString(double d) { + if (Isis::IsSpecial(d)) { + if (Isis::IsNullPixel(d)) return std::string("Null"); + if (Isis::IsLrsPixel(d)) return std::string("Lrs"); + if (Isis::IsHrsPixel(d)) return std::string("Hrs"); + if (Isis::IsHisPixel(d)) return std::string("His"); + if (Isis::IsLisPixel(d)) return std::string("Lis"); + return std::string("Invalid"); + } + + QString result; + return result.setNum(d).toStdString(); + } + /** + * Takes the name of the pixel type as a string and returns a + * double pixel value. + * + * @param str The name of the pixel type + * + * @return double Pixel value + */ + inline double StringToPixel(const std::string & str) { + + iString s (str); + s.UpCase(); + + std::vector legal; + legal.push_back("NULL"); + legal.push_back("HRS"); + legal.push_back("LRS"); + legal.push_back("HIS"); + legal.push_back("LIS"); + int matches = 0; + for (int i = 0; i < (int) legal.size(); i++){ + if(legal[i].substr(0,s.size()) == s) { + matches++; + } + } + if (matches > 1) { + std::string msg = "Input [" + str + "] is not a unique abbreviation. Use " + s + "I or " + s + "R."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + if (matches == 0) { + try{ + return s.ToDouble(); + } + catch(iException &e) { + std::string msg = "Input [" + str + "] does not appear to be a legal special pixel abbreviation or double value."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + if (s[0] == 'N') return Null; + if (s.substr(0,2) == "HR") return Hrs; + if (s.substr(0,2) == "LR") return Lrs; + if (s.substr(0,2) == "HI") return His; + else return Lis;//(s.substr(0,2) == "LI") + + } +} + +#endif + diff --git a/isis/src/base/objs/SpecialPixel/SpecialPixel.truth b/isis/src/base/objs/SpecialPixel/SpecialPixel.truth new file mode 100644 index 0000000000000000000000000000000000000000..f78cf2d21807da12bc0c8164c2c19d8bd9749567 --- /dev/null +++ b/isis/src/base/objs/SpecialPixel/SpecialPixel.truth @@ -0,0 +1,144 @@ +Unit test for IsisSpecialPixel +Valid minimum (1 byte): 1 +Null (1 byte): 0 +Low Representation (1 byte): 0 +Low Instrument (1 byte): 0 +High Representation (1 byte): 255 +High Instrument (1 byte): 255 +Valid maximum (1 byte): 254 + +Valid minimum (2 byte): -32752 +Null (2 byte): -32768 +Low Representation (2 byte): -32767 +Low Instrument (2 byte): -32766 +High Representation (2 byte): -32764 +High Instrument (2 byte): -32765 +Valid maximum (2 byte): 32767 + +Valid minimum (4 byte): -3.40282e+38 +Null (4 byte): -3.40282e+38 +Low Representation (4 byte): -3.40282e+38 +Low Instrument (4 byte): -3.40282e+38 +High Representation (4 byte): -3.40282e+38 +High Instrument (4 byte): -3.40282e+38 +Valid maximum (4 byte): 3.40282e+38 + +Valid minimum (8 byte): -1.797693134862315e+308 +Null (8 byte): -1.797693134862315e+308 +Low Representation (8 byte): -1.797693134862315e+308 +Low Instrument (8 byte): -1.797693134862315e+308 +High Representation (8 byte): -1.797693134862316e+308 +High Instrument (8 byte): -1.797693134862316e+308 +Valid maximum (8 byte): 1.797693134862316e+308 + +Testing 0.0 ... +IsSpecial: 0 +IsValidPixel: 1 +IsNullPixel: 0 +IsLowPixel: 0 +IsHighPixel: 0 +IsHrsPixel: 0 +IsHisPixel: 0 +IsLrsPixel: 0 +IsLisPixel: 0 + +Testing Isis::Null ... +IsSpecial: 1 +IsValidPixel: 0 +IsNullPixel: 1 +IsLowPixel: 0 +IsHighPixel: 0 +IsHrsPixel: 0 +IsHisPixel: 0 +IsLrsPixel: 0 +IsLisPixel: 0 + +Testing Isis::Lis ... +IsSpecial: 1 +IsValidPixel: 0 +IsNullPixel: 0 +IsLowPixel: 1 +IsHighPixel: 0 +IsHrsPixel: 0 +IsHisPixel: 0 +IsLrsPixel: 0 +IsLisPixel: 1 + +Testing Isis::Lrs ... +IsSpecial: 1 +IsValidPixel: 0 +IsNullPixel: 0 +IsLowPixel: 1 +IsHighPixel: 0 +IsHrsPixel: 0 +IsHisPixel: 0 +IsLrsPixel: 1 +IsLisPixel: 0 + +Testing Isis::His ... +IsSpecial: 1 +IsValidPixel: 0 +IsNullPixel: 0 +IsLowPixel: 0 +IsHighPixel: 1 +IsHrsPixel: 0 +IsHisPixel: 1 +IsLrsPixel: 0 +IsLisPixel: 0 + +Testing Isis::Hrs ... +IsSpecial: 1 +IsValidPixel: 0 +IsNullPixel: 0 +IsLowPixel: 0 +IsHighPixel: 1 +IsHrsPixel: 1 +IsHisPixel: 0 +IsLrsPixel: 0 +IsLisPixel: 0 + +Testing PixelToString(double): +Isis::Null to String: Null +Isis::Lrs to String: Lrs +Isis::Hrs to String: Hrs +Isis::His to String: His +Isis::Lis to String: Lis +0.0 to String: 0 +1.5 to String: 1.5 +-6.0 to String: -6 + +Testing StringToPixel(string): +NuLl to Pixel: -1.797693134862315e+308 +lrs to Pixel: -1.797693134862315e+308 +Hrs to Pixel: -1.797693134862316e+308 +HIs to Pixel: -1.797693134862316e+308 +LIS to Pixel: -1.797693134862315e+308 +0.0 to Pixel: 0 +1.5 to Pixel: 1.5 +-6.0 to Pixel: -6 +-6 to Pixel: -6 + +Testing unique value shortcut for StringToPixel(string): +Nul to Pixel: -1.797693134862315e+308 +N to Pixel: -1.797693134862315e+308 +Lr to Pixel: -1.797693134862315e+308 +Hr to Pixel: -1.797693134862316e+308 +Hi to Pixel: -1.797693134862316e+308 +Li to Pixel: -1.797693134862315e+308 + +Testing illegal shortcuts/expressions for StringToPixel(string): +**USER ERROR** Input [Nl] does not appear to be a legal special pixel abbreviation or double value. +**PARSE ERROR** Cannot convert [NL] to a double +**USER ERROR** Input [Nulll] does not appear to be a legal special pixel abbreviation or double value. +**PARSE ERROR** Cannot convert [NULLL] to a double +**USER ERROR** Input [L] is not a unique abbreviation. Use LI or LR. +**USER ERROR** Input [Ls] does not appear to be a legal special pixel abbreviation or double value. +**PARSE ERROR** Cannot convert [LS] to a double +**USER ERROR** Input [H] is not a unique abbreviation. Use HI or HR. +**USER ERROR** Input [Hs] does not appear to be a legal special pixel abbreviation or double value. +**PARSE ERROR** Cannot convert [HS] to a double +**USER ERROR** Input [Hrsr] does not appear to be a legal special pixel abbreviation or double value. +**PARSE ERROR** Cannot convert [HRSR] to a double +**USER ERROR** Input [nonsense] does not appear to be a legal special pixel abbreviation or double value. +**PARSE ERROR** Cannot convert [NONSENSE] to a double + diff --git a/isis/src/base/objs/SpecialPixel/unitTest.cpp b/isis/src/base/objs/SpecialPixel/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..086ecaace98815d01b51477888d9baadf8cbca34 --- /dev/null +++ b/isis/src/base/objs/SpecialPixel/unitTest.cpp @@ -0,0 +1,278 @@ +#include +#include +#include "iException.h" +#include "SpecialPixel.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Unit test for IsisSpecialPixel" << endl; + + cout << "Valid minimum (1 byte): " << (int) Isis::VALID_MIN1 << endl; + cout << "Null (1 byte): " << (int) Isis::NULL1 << endl; + cout << "Low Representation (1 byte): " << (int) Isis::LOW_REPR_SAT1 << endl; + cout << "Low Instrument (1 byte): " << (int) Isis::LOW_INSTR_SAT1 << endl; + cout << "High Representation (1 byte): " << (int) Isis::HIGH_REPR_SAT1 << endl; + cout << "High Instrument (1 byte): " << (int) Isis::HIGH_INSTR_SAT1 << endl; + cout << "Valid maximum (1 byte): " << (int) Isis::VALID_MAX1 << endl; + cout << endl; + + cout << "Valid minimum (2 byte): " << Isis::VALID_MIN2 << endl; + cout << "Null (2 byte): " << Isis::NULL2 << endl; + cout << "Low Representation (2 byte): " << Isis::LOW_REPR_SAT2 << endl; + cout << "Low Instrument (2 byte): " << Isis::LOW_INSTR_SAT2 << endl; + cout << "High Representation (2 byte): " << Isis::HIGH_REPR_SAT2 << endl; + cout << "High Instrument (2 byte): " << Isis::HIGH_INSTR_SAT2 << endl; + cout << "Valid maximum (2 byte): " << Isis::VALID_MAX2 << endl; + cout << endl; + + cout << "Valid minimum (4 byte): " << Isis::VALID_MIN4 << endl; + cout << "Null (4 byte): " << Isis::NULL4 << endl; + cout << "Low Representation (4 byte): " << Isis::LOW_REPR_SAT4 << endl; + cout << "Low Instrument (4 byte): " << Isis::LOW_INSTR_SAT4 << endl; + cout << "High Representation (4 byte): " << Isis::HIGH_REPR_SAT4 << endl; + cout << "High Instrument (4 byte): " << Isis::HIGH_INSTR_SAT4 << endl; + cout << "Valid maximum (4 byte): " << Isis::VALID_MAX4 << endl; + cout << endl; + + cout << setprecision(16); + cout << "Valid minimum (8 byte): " << Isis::VALID_MIN8 << endl; + cout << "Null (8 byte): " << Isis::NULL8 << endl; + cout << "Low Representation (8 byte): " << Isis::LOW_REPR_SAT8 << endl; + cout << "Low Instrument (8 byte): " << Isis::LOW_INSTR_SAT8 << endl; + cout << "High Representation (8 byte): " << Isis::HIGH_REPR_SAT8 << endl; + cout << "High Instrument (8 byte): " << Isis::HIGH_INSTR_SAT8 << endl; + cout << "Valid maximum (8 byte): " << Isis::VALID_MAX8 << endl; + cout << endl; + + double d = 0.0; + cout << "Testing 0.0 ... " << endl; + cout << "IsSpecial: " << Isis::IsSpecial(d) << endl; + cout << "IsValidPixel: " << Isis::IsValidPixel(d) << endl; + cout << "IsNullPixel: " << Isis::IsNullPixel(d) << endl; + cout << "IsLowPixel: " << Isis::IsLowPixel(d) << endl; + cout << "IsHighPixel: " << Isis::IsHighPixel(d) << endl; + cout << "IsHrsPixel: " << Isis::IsHrsPixel(d) << endl; + cout << "IsHisPixel: " << Isis::IsHisPixel(d) << endl; + cout << "IsLrsPixel: " << Isis::IsLrsPixel(d) << endl; + cout << "IsLisPixel: " << Isis::IsLisPixel(d) << endl; + cout << endl; + + d = Isis::Null; + cout << "Testing Isis::Null ... " << endl; + cout << "IsSpecial: " << Isis::IsSpecial(d) << endl; + cout << "IsValidPixel: " << Isis::IsValidPixel(d) << endl; + cout << "IsNullPixel: " << Isis::IsNullPixel(d) << endl; + cout << "IsLowPixel: " << Isis::IsLowPixel(d) << endl; + cout << "IsHighPixel: " << Isis::IsHighPixel(d) << endl; + cout << "IsHrsPixel: " << Isis::IsHrsPixel(d) << endl; + cout << "IsHisPixel: " << Isis::IsHisPixel(d) << endl; + cout << "IsLrsPixel: " << Isis::IsLrsPixel(d) << endl; + cout << "IsLisPixel: " << Isis::IsLisPixel(d) << endl; + cout << endl; + + d = Isis::Lis; + cout << "Testing Isis::Lis ... " << endl; + cout << "IsSpecial: " << Isis::IsSpecial(d) << endl; + cout << "IsValidPixel: " << Isis::IsValidPixel(d) << endl; + cout << "IsNullPixel: " << Isis::IsNullPixel(d) << endl; + cout << "IsLowPixel: " << Isis::IsLowPixel(d) << endl; + cout << "IsHighPixel: " << Isis::IsHighPixel(d) << endl; + cout << "IsHrsPixel: " << Isis::IsHrsPixel(d) << endl; + cout << "IsHisPixel: " << Isis::IsHisPixel(d) << endl; + cout << "IsLrsPixel: " << Isis::IsLrsPixel(d) << endl; + cout << "IsLisPixel: " << Isis::IsLisPixel(d) << endl; + cout << endl; + + d = Isis::Lrs; + cout << "Testing Isis::Lrs ... " << endl; + cout << "IsSpecial: " << Isis::IsSpecial(d) << endl; + cout << "IsValidPixel: " << Isis::IsValidPixel(d) << endl; + cout << "IsNullPixel: " << Isis::IsNullPixel(d) << endl; + cout << "IsLowPixel: " << Isis::IsLowPixel(d) << endl; + cout << "IsHighPixel: " << Isis::IsHighPixel(d) << endl; + cout << "IsHrsPixel: " << Isis::IsHrsPixel(d) << endl; + cout << "IsHisPixel: " << Isis::IsHisPixel(d) << endl; + cout << "IsLrsPixel: " << Isis::IsLrsPixel(d) << endl; + cout << "IsLisPixel: " << Isis::IsLisPixel(d) << endl; + cout << endl; + + d = Isis::His; + cout << "Testing Isis::His ... " << endl; + cout << "IsSpecial: " << Isis::IsSpecial(d) << endl; + cout << "IsValidPixel: " << Isis::IsValidPixel(d) << endl; + cout << "IsNullPixel: " << Isis::IsNullPixel(d) << endl; + cout << "IsLowPixel: " << Isis::IsLowPixel(d) << endl; + cout << "IsHighPixel: " << Isis::IsHighPixel(d) << endl; + cout << "IsHrsPixel: " << Isis::IsHrsPixel(d) << endl; + cout << "IsHisPixel: " << Isis::IsHisPixel(d) << endl; + cout << "IsLrsPixel: " << Isis::IsLrsPixel(d) << endl; + cout << "IsLisPixel: " << Isis::IsLisPixel(d) << endl; + cout << endl; + + d = Isis::Hrs; + cout << "Testing Isis::Hrs ... " << endl; + cout << "IsSpecial: " << Isis::IsSpecial(d) << endl; + cout << "IsValidPixel: " << Isis::IsValidPixel(d) << endl; + cout << "IsNullPixel: " << Isis::IsNullPixel(d) << endl; + cout << "IsLowPixel: " << Isis::IsLowPixel(d) << endl; + cout << "IsHighPixel: " << Isis::IsHighPixel(d) << endl; + cout << "IsHrsPixel: " << Isis::IsHrsPixel(d) << endl; + cout << "IsHisPixel: " << Isis::IsHisPixel(d) << endl; + cout << "IsLrsPixel: " << Isis::IsLrsPixel(d) << endl; + cout << "IsLisPixel: " << Isis::IsLisPixel(d) << endl; + cout << endl; + +#if 0 + cout << Isis::IsEqual(Isis::NULL4,Isis::NULL4) << endl; + cout << Isis::IsEqual(Isis::NULL4,Isis::LOW_INSTR_SAT4) << endl; + cout << Isis::IsEqual(Isis::NULL4,Isis::LOW_REPR_SAT4) << endl; + cout << Isis::IsEqual(Isis::NULL4,Isis::HIGH_INSTR_SAT4) << endl; + cout << Isis::IsEqual(Isis::NULL4,Isis::HIGH_REPR_SAT4) << endl; + cout << endl; + + cout << Isis::IsEqual(Isis::LOW_INSTR_SAT4,Isis::NULL4) << endl; + cout << Isis::IsEqual(Isis::LOW_INSTR_SAT4,Isis::LOW_INSTR_SAT4) << endl; + cout << Isis::IsEqual(Isis::LOW_INSTR_SAT4,Isis::LOW_REPR_SAT4) << endl; + cout << Isis::IsEqual(Isis::LOW_INSTR_SAT4,Isis::HIGH_INSTR_SAT4) << endl; + cout << Isis::IsEqual(Isis::LOW_INSTR_SAT4,Isis::HIGH_REPR_SAT4) << endl; + cout << endl; + + cout << Isis::IsEqual(Isis::LOW_REPR_SAT4,Isis::NULL4) << endl; + cout << Isis::IsEqual(Isis::LOW_REPR_SAT4,Isis::LOW_INSTR_SAT4) << endl; + cout << Isis::IsEqual(Isis::LOW_REPR_SAT4,Isis::LOW_REPR_SAT4) << endl; + cout << Isis::IsEqual(Isis::LOW_REPR_SAT4,Isis::HIGH_INSTR_SAT4) << endl; + cout << Isis::IsEqual(Isis::LOW_REPR_SAT4,Isis::HIGH_REPR_SAT4) << endl; + cout << endl; + + cout << Isis::IsEqual(Isis::HIGH_INSTR_SAT4,Isis::NULL4) << endl; + cout << Isis::IsEqual(Isis::HIGH_INSTR_SAT4,Isis::LOW_INSTR_SAT4) << endl; + cout << Isis::IsEqual(Isis::HIGH_INSTR_SAT4,Isis::LOW_REPR_SAT4) << endl; + cout << Isis::IsEqual(Isis::HIGH_INSTR_SAT4,Isis::HIGH_INSTR_SAT4) << endl; + cout << Isis::IsEqual(Isis::HIGH_INSTR_SAT4,Isis::HIGH_REPR_SAT4) << endl; + cout << endl; + + cout << Isis::IsEqual(Isis::HIGH_REPR_SAT4,Isis::NULL4) << endl; + cout << Isis::IsEqual(Isis::HIGH_REPR_SAT4,Isis::LOW_INSTR_SAT4) << endl; + cout << Isis::IsEqual(Isis::HIGH_REPR_SAT4,Isis::LOW_REPR_SAT4) << endl; + cout << Isis::IsEqual(Isis::HIGH_REPR_SAT4,Isis::HIGH_INSTR_SAT4) << endl; + cout << Isis::IsEqual(Isis::HIGH_REPR_SAT4,Isis::HIGH_REPR_SAT4) << endl; + cout << endl; +#endif + + cout << "Testing PixelToString(double):" << endl; + d = Isis::Null; + cout << "Isis::Null to String:\t" << Isis::PixelToString(d) << endl; + d = Isis::Lrs; + cout << "Isis::Lrs to String:\t" << Isis::PixelToString(d) << endl; + d = Isis::Hrs; + cout << "Isis::Hrs to String:\t" << Isis::PixelToString(d) << endl; + d = Isis::His; + cout << "Isis::His to String:\t" << Isis::PixelToString(d) << endl; + d = Isis::Lis; + cout << "Isis::Lis to String:\t" << Isis::PixelToString(d) << endl; + d = 0.0; + cout << "0.0 to String:\t\t" << Isis::PixelToString(d) << endl; + d = 1.5; + cout << "1.5 to String:\t\t" << Isis::PixelToString(d) << endl; + d = -6.0; + cout << "-6.0 to String:\t\t" << Isis::PixelToString(d) << endl; + cout << endl; + + cout << "Testing StringToPixel(string):" << endl; + string s = "NuLl"; + cout << "NuLl to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + s = "lrs"; + cout << "lrs to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + s = "Hrs"; + cout << "Hrs to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + s = "HIs"; + cout << "HIs to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + s = "LIS"; + cout << "LIS to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + s = "0.0"; + cout << "0.0 to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + s = "1.5"; + cout << "1.5 to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + s = "-6.0"; + cout << "-6.0 to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + cout << Isis::PixelToString(d) << " to Pixel:\t" << Isis::StringToPixel(Isis::PixelToString(d)) << endl; + cout << endl; + + cout << "Testing unique value shortcut for StringToPixel(string):" << endl; + s = "Nul"; + cout << "Nul to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + s = "N"; + cout << "N to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + s = "Lr"; + cout << "Lr to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + s = "Hr"; + cout << "Hr to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + s = "Hi"; + cout << "Hi to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + s = "Li"; + cout << "Li to Pixel:\t\t" << Isis::StringToPixel(s) << endl; + cout << endl; + + cout << "Testing illegal shortcuts/expressions for StringToPixel(string):" << endl; + try{ + s = "Nl"; + Isis::StringToPixel(s); + } + catch(Isis::iException &e) { + e.Report(false); + } + try{ + s = "Nulll"; + Isis::StringToPixel(s); + } + catch (Isis::iException &e){ + e.Report(false); + } + try { + s = "L"; + Isis::StringToPixel(s); + } + catch (Isis::iException &e) { + e.Report(false); + } + try{ + s = "Ls"; + Isis::StringToPixel(s); + } + catch (Isis::iException &e){ + e.Report(false); + } + try{ + s = "H"; + Isis::StringToPixel(s); + } + catch (Isis::iException &e){ + e.Report(false); + } + try{ + s = "Hs"; + Isis::StringToPixel(s); + } + catch (Isis::iException &e){ + e.Report(false); + } + try{ + s = "Hrsr"; + Isis::StringToPixel(s); + } + catch (Isis::iException &e){ + e.Report(false); + } + try{ + s = "nonsense"; + Isis::StringToPixel(s); + } + catch (Isis::iException &e){ + e.Report(false); + } + cout << endl; +} + diff --git a/isis/src/base/objs/Spice/Makefile b/isis/src/base/objs/Spice/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..123b9a598c6e16b5762b2867fd116155323db127 --- /dev/null +++ b/isis/src/base/objs/Spice/Makefile @@ -0,0 +1,5 @@ +INCS = Spice.h +SRCS = Spice.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Spice/Spice.cpp b/isis/src/base/objs/Spice/Spice.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8998cd6fedb0e0203091fd85a068ffe69ef853e6 --- /dev/null +++ b/isis/src/base/objs/Spice/Spice.cpp @@ -0,0 +1,829 @@ +/** + * @file + * $Revision: 1.24 $ + * $Date: 2010/04/09 22:31:16 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "Spice.h" +#include "iString.h" +#include "iException.h" +#include "Filename.h" +#include "Constants.h" +#include "NaifStatus.h" + +using namespace std; +namespace Isis { + /** + * Constructs a Spice object and loads SPICE kernels using information from the + * label object. The constructor expects an Instrument and Kernels group to be + * in the labels. + * + * @param lab Label containing Instrument and Kernels groups. + * @internal + * @history 2005-10-07 Jim Torson - Modified the constructor so it can + * handle multiple SpacecraftPosition and + * multiple SpacecraftPointing kernel files + * @history 2005-11-29 Debbie A. Cook - Added loop to allow multiple frames + * kernels and code to initialize Naif + * codes when no platform is used (landers) + * @history 2006-01-03 Debbie A. Cook - Added loop to allow multiple spacecraft + * clock kernels (for Viking) + * @history 2006-02-21 Jeff Anderson/Debbie Cook - Refactor to use SpicePosition + * and SpiceRotation classes + * @history 2009-03-18 Tracie Sucharski - Remove code for old keywords. + */ + + // TODO: DOCUMENT EVERYTHING + Spice::Spice (Isis::Pvl &lab) { + Init (lab, false); + } + + Spice::Spice (Isis::Pvl &lab, bool notab) { + Init (lab, notab); + } + + void Spice::Init (Isis::Pvl &lab, bool notab) { + NaifStatus::CheckErrors(); + + // Initialization + p_startTime = 0.0; + p_endTime = 0.0; + p_cacheSize = 0; + p_et = -DBL_MAX; + p_allowDownsizing = false; + + // Get the kernel group and load main kernels + Isis::PvlGroup kernels = lab.FindGroup("Kernels",Isis::Pvl::Traverse); + + // Get the time padding first + if(kernels.HasKeyword("StartPadding")) { + p_startTimePadding = kernels["StartPadding"][0]; + } + else { + p_startTimePadding = 0.0; + } + + if(kernels.HasKeyword("EndPadding")) { + p_endTimePadding = kernels["EndPadding"][0]; + } + else { + p_endTimePadding = 0.0; + } + + +// Modified to load planetary ephemeris SPKs before s/c SPKs since some +// missions (e.g., MESSENGER) may augment the s/c SPK with new planet +// ephemerides. (2008-02-27 (KJB)) + Load(kernels["TargetPosition"], notab); + Load(kernels["InstrumentPosition"], notab); + Load(kernels["InstrumentPointing"], notab); + + if (kernels.HasKeyword("Frame")) { + Load(kernels["Frame"], notab); + } + + Load(kernels["TargetAttitudeShape"], notab); + Load(kernels["Instrument"], notab); + Load(kernels["InstrumentAddendum"], notab); // Always load after instrument + Load(kernels["LeapSecond"], notab); + Load(kernels["SpacecraftClock"], notab); + +// Modified to load extra kernels last to allow overriding default values +// (2010-04-07) (DAC) + if (kernels.HasKeyword("Extra")) { + Load(kernels["Extra"], notab); + } + + // Get NAIF ik, spk, sclk, and ck codes + // + // Use ikcode to get parameters from instrument kernel such as focal + // length, distortions, focal plane maps, etc + // + // Use spkcode to get spacecraft position from spk file + // + // Use sclkcode to transform times from et to tics + // + // Use ckcode to transform between frames + // + // Use bodycode to obtain radii and attitude (pole position/omega0) + // + // Use spkbodycode to read body position from spk + + string trykey = "NaifIkCode"; + if (kernels.HasKeyword("NaifFrameCode")) trykey = "NaifFrameCode"; + p_ikCode = (int) kernels[trykey]; + + p_spkCode = p_ikCode / 1000; + p_sclkCode = p_spkCode; + p_ckCode = p_ikCode; + + Isis::PvlGroup &inst = lab.FindGroup("Instrument",Isis::Pvl::Traverse); + p_target = (string) inst["TargetName"]; + + if (iString(p_target).UpCase() == "SKY") { + p_bodyCode = p_spkCode; + p_radii[0] = p_radii[1] = p_radii[2] = 1.0; + p_sky = true; + } + else { + p_bodyCode = NaifBodyCode(); + SpiceInt n; + bodvar_c(p_bodyCode,"RADII",&n,p_radii); + p_sky = false; + } + p_spkBodyCode = p_bodyCode; + + // Override them if they exist in the labels + if (kernels.HasKeyword("NaifSpkCode")) p_spkCode = (int) kernels["NaifSpkCode"]; + if (kernels.HasKeyword("NaifCkCode")) p_ckCode = (int) kernels["NaifCkCode"]; + if (kernels.HasKeyword("NaifSclkCode")) p_sclkCode = (int) kernels["NaifSclkCode"]; + if (kernels.HasKeyword("NaifBodyCode")) p_bodyCode = (int) kernels["NaifBodyCode"]; + if (!p_sky) { + if (kernels.HasKeyword("NaifSpkBodyCode")) p_spkBodyCode = (int) kernels["NaifSpkBodyCode"]; + } + + // Create our SpicePosition and SpiceRotation objects + p_bodyRotation = 0; + p_instrumentRotation = 0; + p_instrumentPosition = 0; + p_sunPosition = 0; + + if (p_sky) { + // Create the identity rotation for sky targets + // Everything in bodyfixed will really be J2000 + p_bodyRotation = new SpiceRotation(1); + } + else { + char frameName[32]; + SpiceInt frameCode; + SpiceBoolean found; + cidfrm_c (p_spkBodyCode, sizeof(frameName), &frameCode, frameName, &found); + + if (!found) { + string naifTarget = string("IAU_") + iString(p_target).UpCase(); + namfrm_c(naifTarget.c_str(),&frameCode); + if (frameCode == 0) { + string msg = "Can not find NAIF code for [" + naifTarget + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + p_bodyRotation = new SpiceRotation(frameCode); + } + p_instrumentRotation = new SpiceRotation(p_ckCode); + p_instrumentPosition = new SpicePosition(p_spkCode,p_spkBodyCode); + p_sunPosition = new SpicePosition(10,p_bodyCode); + + // Check to see if we have nadir pointing that needs to be computed & + // See if we have table blobs to load + if (iString((std::string)kernels["TargetPosition"]).UpCase() == "TABLE") { + Table t("SunPosition",lab.Filename()); + p_sunPosition->LoadCache(t); + + Table t2("BodyRotation",lab.Filename()); + p_bodyRotation->LoadCache(t2); + if (t2.Label().HasKeyword("SolarLongitude")) { + p_solarLongitude = t2.Label()["SolarLongitude"]; + } + else { + SolarLongitude(); + } + } + + // We can't assume InstrumentPointing & InstrumentPosition exist, old + // files may be around with the old keywords, SpacecraftPointing & + // SpacecraftPosition. The old keywords were in existance before the + // Table option, so we don't need to check for Table under the old + // keywords. + + if(kernels["InstrumentPointing"].Size() == 0) { + throw iException::Message(iException::Camera, + "No camera pointing available", + _FILEINFO_); + } + + // 2009-03-18 Tracie Sucharski - Removed test for old keywords, any files + // with the old keywords should be re-run through spiceinit. + if (iString((std::string)kernels["InstrumentPointing"]).UpCase() == "NADIR") { + delete p_instrumentRotation; + p_instrumentRotation = new SpiceRotation(p_ikCode,p_spkBodyCode); + } + else if (iString((std::string)kernels["InstrumentPointing"]).UpCase() == "TABLE") { + Table t("InstrumentPointing",lab.Filename()); + p_instrumentRotation->LoadCache(t); + } + + if(kernels["InstrumentPosition"].Size() == 0) { + throw iException::Message(iException::Camera, + "No instrument position available", + _FILEINFO_); + } + + if (iString((std::string)kernels["InstrumentPosition"]).UpCase() == "TABLE") { + Table t("InstrumentPosition",lab.Filename()); + p_instrumentPosition->LoadCache(t); + } + + NaifStatus::CheckErrors(); + } + + + //! Load/furnish NAIF kernel(s) + void Spice::Load(Isis::PvlKeyword &key, bool notab) { + NaifStatus::CheckErrors(); + + for (int i=0; i endTime) { + string msg = "Argument startTime must be less than or equal to endTime"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (p_cacheSize > 0) { + string msg = "A cache has already been created"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if(cacheSize == 1 && (p_startTimePadding != 0 || p_endTimePadding != 0)) { + string msg = "This instrument does not support time padding"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + double avgTime = (startTime + endTime) / 2.0; + ComputeSolarLongitude(avgTime); + + // Cache everything + if (!p_bodyRotation->IsCached()) { + int bodyRotationCacheSize = cacheSize; + if (cacheSize > 2) bodyRotationCacheSize = 2; + p_bodyRotation->LoadCache(startTime-p_startTimePadding, endTime+p_endTimePadding, bodyRotationCacheSize); + } + + if (p_instrumentRotation->GetSource() < SpiceRotation::Memcache) { + if (cacheSize > 3) p_instrumentRotation->MinimizeCache( SpiceRotation::Yes ); + p_instrumentRotation->LoadCache(startTime-p_startTimePadding, endTime+p_endTimePadding, cacheSize); + } + + if (!p_instrumentPosition->IsCached()) { + p_instrumentPosition->LoadCache(startTime-p_startTimePadding, endTime+p_endTimePadding, cacheSize); + if (cacheSize > 3) p_instrumentPosition->Memcache2HermiteCache(tol); + } + + if (!p_sunPosition->IsCached()) { + int sunPositionCacheSize = cacheSize; + if (cacheSize > 2) sunPositionCacheSize = 2; + p_sunPosition->LoadCache(startTime-p_startTimePadding, endTime+p_endTimePadding, sunPositionCacheSize); + } + + // Save the time and cache size + p_startTime = startTime; + p_endTime = endTime; + p_cacheSize = cacheSize; + p_et = -DBL_MAX; + + // Unload the kernels (TODO: Can this be done faster) + for (unsigned int i=0; iSetEphemerisTime(et); + p_instrumentRotation->SetEphemerisTime(et); + p_instrumentPosition->SetEphemerisTime(et); + p_sunPosition->SetEphemerisTime(et); + + std::vector uB = p_bodyRotation->ReferenceVector(p_sunPosition->Coordinate()); + p_uB[0] = uB[0]; + p_uB[1] = uB[1]; + p_uB[2] = uB[2]; + + ComputeSolarLongitude(p_et); + } + + /** + * Returns the spacecraft position in body-fixed frame km units. + * + * @param p[] Spacecraft position + */ + void Spice::InstrumentPosition (double p[3]) const { + if (p_et == -DBL_MAX) { + std::string msg = "You must call SetEphemerisTime first"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + std::vector sB = p_bodyRotation->ReferenceVector(p_instrumentPosition->Coordinate()); + p[0] = sB[0]; + p[1] = sB[1]; + p[2] = sB[2]; + } + + + /** + * Returns the spacecraft velocity in body-fixed frame km/sec units. + * + * @param p[] Spacecraft velocity + */ + void Spice::InstrumentVelocity (double v[3]) const { + if (p_et == -DBL_MAX) { + std::string msg = "You must call SetEphemerisTime first"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + std::vector vB = p_bodyRotation->ReferenceVector(p_instrumentPosition->Velocity()); + v[0] = vB[0]; + v[1] = vB[1]; + v[2] = vB[2]; + } + + /** + * Returns the sun position in either body-fixed or J2000 reference frame and + * km units. + * + * @param p[] Sun position + */ + void Spice::SunPosition (double p[3]) const { + if (p_et == -DBL_MAX) { + std::string msg = "You must call SetEphemerisTime first"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + p[0] = p_uB[0]; + p[1] = p_uB[1]; + p[2] = p_uB[2]; + } + + /** + * Calculates and returns the distance from the spacecraft to the target center + * + * @return double Distance to the center of the target from the spacecraft + */ + double Spice::TargetCenterDistance() const { + std::vector sB = p_bodyRotation->ReferenceVector(p_instrumentPosition->Coordinate()); + return sqrt(pow(sB[0],2) + pow(sB[1],2) + pow(sB[2],2)); + } + + /** + * Returns the radii of the body in km. The radii are obtained from the + * appropriate SPICE kernel for the body specified by TargetName in the + * Instrument group of the labels. + * + * @param r[] Radii of the target in kilometers + */ + void Spice::Radii (double r[3]) const { + r[0] = p_radii[0]; + r[1] = p_radii[1]; + r[2] = p_radii[2]; + } + + /** + * This returns the NAIF body code of the target indicated in the labels. + * + * @return SpiceInt + * + * @throws Isis::iException::Io + */ + SpiceInt Spice::NaifBodyCode() const { + SpiceInt code; + SpiceBoolean found; + bodn2c_c (p_target.c_str(), &code, &found); + if (!found) { + string msg = "Could not convert Target [" + p_target + + "] to NAIF code"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + return (int) code; + } + + /** + * This returns the NAIF SPK code to use when reading from SPK kernels. + * + * @return SpiceInt + */ + SpiceInt Spice::NaifSpkCode() const { + return p_spkCode; + } + + /** + * This returns the NAIF CK code to use when reading from CK kernels. + * + * @return SpiceInt + */ + SpiceInt Spice::NaifCkCode() const { + return p_ckCode; + } + + /** + * This returns the NAIF IK code to use when reading from instrument kernels. + * + * @return SpiceInt + */ + SpiceInt Spice::NaifIkCode() const { + return p_ikCode; + } + + // Return naif sclk code + SpiceInt Spice::NaifSclkCode() const { + return p_sclkCode; + } + /** + * This returns a value from the NAIF text pool. It is a static convience + * + * @param key Name of NAIF keyword to obtain from the pool + * + * @param index If the keyword is an array, the element to obtain. + * Defaults to 0 + * + * @return SpiceInt + * + * @throws Isis::iException::Io + */ + SpiceInt Spice::GetInteger(const std::string &key, int index) { + NaifStatus::CheckErrors(); + + SpiceBoolean found; + SpiceInt value; + SpiceInt n; + gipool_c (key.c_str(),(SpiceInt)index,1,&n,&value,&found); + if (!found) { + string msg = "Can not find [" + key + "] in instrument kernels"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + NaifStatus::CheckErrors(); + + return value; + } + + /** + * This returns a value from the NAIF text pool. It is a static convience method + * + * @param key Name of NAIF keyword to obtain from the pool + * + * @param index If the keyword is an array, the element to obtain. Defaults to 0 + * + * @return SpiceDouble + * + * @throws Isis::iException::Io + */ + SpiceDouble Spice::GetDouble(const std::string &key, int index) { + NaifStatus::CheckErrors(); + + SpiceBoolean found; + SpiceDouble value; + SpiceInt n; + gdpool_c (key.c_str(),(SpiceInt)index,1,&n,&value,&found); + if (!found) { + string msg = "Can not find [" + key + "] in instrument kernels"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + NaifStatus::CheckErrors(); + + return value; + } + + /** + * This returns a value from the NAIF text pool. It is a static convience + * method + * + * @param key Name of NAIF keyword to obtain from the pool + * + * @param index If the keyword is an array, the element to obtain. Defaults to 0 + * + * @return string + * + * @throws Isis::iException::Io + */ + string Spice::GetString(const std::string &key, int index) { + NaifStatus::CheckErrors(); + + SpiceBoolean found; + SpiceInt n; + char cstr[512]; + gcpool_c (key.c_str(),(SpiceInt)index,1,512,&n,cstr,&found); + if (!found) { + string msg = "Can not find [" + key + "] in instrument kernels"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + NaifStatus::CheckErrors(); + + return string(cstr); + } + + /** + * Returns the sub-spacecraft latitude/longitude in universal coordinates + * (0-360 positive east, ocentric) + * + * @param lat Sub-spacecraft latitude + * + * @param lon Sub-spacecraft longitude + */ + void Spice::SubSpacecraftPoint (double &lat, double &lon) { + NaifStatus::CheckErrors(); + + if (p_et == -DBL_MAX) { + std::string msg = "You must call SetEphemerisTime first"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + SpiceDouble usB[3],dist; + std::vector vsB = p_bodyRotation->ReferenceVector(p_instrumentPosition->Coordinate()); + SpiceDouble sB[3]; + sB[0] = vsB[0]; + sB[1] = vsB[1]; + sB[2] = vsB[2]; + unorm_c (sB,usB,&dist); + + SpiceDouble a = p_radii[0]; + SpiceDouble b = p_radii[1]; + SpiceDouble c = p_radii[2]; + + SpiceDouble originB[3]; + originB[0] = originB[1] = originB[2] = 0.0; + + SpiceBoolean found; + SpiceDouble subB[3]; + surfpt_c (originB,usB,a,b,c,subB,&found); + + SpiceDouble mylon,mylat; + reclat_c (subB,&a,&mylon,&mylat); + lat = mylat * 180.0 / Isis::PI; + lon = mylon * 180.0 / Isis::PI; + if (lon < 0.0) lon += 360.0; + + NaifStatus::CheckErrors(); + } + + /** + * Returns the sub-solar latitude/longitude in universal coordinates (0-360 + * positive east, ocentric) + * + * @param lat Sub-solar latitude + * + * @param lon Sub-solar longitude + */ + void Spice::SubSolarPoint (double &lat, double &lon) { + NaifStatus::CheckErrors(); + + if (p_et == -DBL_MAX) { + std::string msg = "You must call SetEphemerisTime first"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + SpiceDouble uuB[3],dist; + unorm_c (p_uB,uuB,&dist); + + SpiceDouble a = p_radii[0]; + SpiceDouble b = p_radii[1]; + SpiceDouble c = p_radii[2]; + + SpiceDouble originB[3]; + originB[0] = originB[1] = originB[2] = 0.0; + + SpiceBoolean found; + SpiceDouble subB[3]; + surfpt_c (originB,uuB,a,b,c,subB,&found); + + SpiceDouble mylon,mylat; + reclat_c (subB,&a,&mylon,&mylat); + lat = mylat * 180.0 / Isis::PI; + lon = mylon * 180.0 / Isis::PI; + if (lon < 0.0) lon += 360.0; + + NaifStatus::CheckErrors(); + } + + void Spice::ComputeSolarLongitude(double et) { + NaifStatus::CheckErrors(); + + if (iString(Target()).UpCase() == "SKY") { + p_solarLongitude = -999.0; + return; + } + + if (p_bodyRotation->IsCached()) return; + + double tipm[3][3], npole[3]; + char frameName[32]; + SpiceInt frameCode; + SpiceBoolean found; + + cidfrm_c (p_spkBodyCode, sizeof(frameName), &frameCode, frameName, &found); + + if ( found ) { + pxform_c("J2000",frameName,et,tipm); + } + else { + tipbod_c("J2000",p_spkBodyCode,et,tipm); + } + + for (int i=0; i<3; i++) { + npole[i] = tipm[2][i]; + } + + double state[6], lt; + spkez_c(p_spkBodyCode,et,"J2000","NONE",10,state,<); + + double uavel[3]; + ucrss_c(state,&state[3],uavel); + + double x[3], y[3], z[3]; + vequ_c(uavel,z); + ucrss_c(npole,z,x); + ucrss_c(z,x,y); + + double trans[3][3]; + for (int i=0; i<3; i++) { + trans[0][i] = x[i]; + trans[1][i] = y[i]; + trans[2][i] = z[i]; + } + + spkez_c(10,et,"J2000","LT+S",p_spkBodyCode,state,<); + + double pos[3]; + mxv_c(trans,state,pos); + + double radius, ls, lat; + reclat_c(pos,&radius,&ls,&lat); + ls *= 180.0 / Isis::PI; + if (ls < 0.0) ls += 360.0; + else if (ls > 360.0) ls -= 360.0; + p_solarLongitude = ls; + + NaifStatus::CheckErrors(); + } + + + /** + * Returns the solar longitude + * + * @return double - The Solar Longitude + */ + double Spice::SolarLongitude() { + ComputeSolarLongitude(p_et); + return p_solarLongitude; + } + + + /** + * Returns true if the kernel group has kernel files + * + * @param lab Label containing Instrument and Kernels groups. + * @return bool - status of kernel files in the kernel group + */ + bool Spice::HasKernels(Isis::Pvl &lab) { + + // Get the kernel group and check main kernels + Isis::PvlGroup kernels = lab.FindGroup("Kernels",Isis::Pvl::Traverse); + std::vector keywords; + keywords.push_back("TargetPosition"); + + if (kernels.HasKeyword("SpacecraftPosition")) { + keywords.push_back("SpacecraftPosition"); + } + else { + keywords.push_back("InstrumentPosition"); + } + + if (kernels.HasKeyword("SpacecraftPointing")) { + keywords.push_back("SpacecraftPointing"); + } + else { + keywords.push_back("InstrumentPointing"); + } + + if (kernels.HasKeyword("Frame")) { + keywords.push_back("Frame"); + } + + if (kernels.HasKeyword("Extra")) { + keywords.push_back("Extra"); + } + + Isis::PvlKeyword key; + for (int ikey = 0; ikey < (int) keywords.size(); ikey++) { + key = kernels[ikey]; + + for (int i=0; i +#include +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" +#include "Pvl.h" +#include "SpicePosition.h" +#include "SpiceRotation.h" + +namespace Isis { +/** + * @brief Obtain SPICE information for a spacecraft + * + * This class initializes standard NAIF SPICE kernels in order to allow queries + * of a spacecraft's position and attitude at a given time. It also allows for + * access to the position of the sun and transformation matrices from J2000 to a + * body-fixed reference frame for a given target (e.g., Mars). The constructor + * for this class expects a PVL object with the following minimum information: + * @code + * Group = Instrument + * TargetName = Mars + * EndGroup + * Group = Kernels + * NaifFrameCode = -94030 + * LeapSecond = naif0007.tls + * TargetAttitudeShape = pck00006.tpc + * TargetPosition = de405.bsp + * InstrumentPointing = (mgs_sc_ab1.bc, + * Instrument = moc13.ti + * SpacecraftClock = MGS_SCLKSCET.00045.tsc + * InstrumentPosition = mgs_ab1.bsp + * InstrumentAddendum = mocAddendum.ti + * EndGroup + * @endcode + * This group is typically found in the image labels after it has been run + * through the program "spiceinit" It is recommended you read NAIF documentation + * to obtain a better understanding about the various types of SPICE kernels. + * The NAIF toolkit accesses information from kernels on a + * last-in-first-out (LIFO) basis. This means that the creation of a second + * object can cause problems with the first object. To alleviate this problem we + * have supplied the CreateCache method which should be invoked immediately + * after the object is constructed. This caches information (spacecraft + * position, pointing, etc) internally in the object and unloads all NAIF + * kernels. + * + * @ingroup SpiceInstrumentsAndCameras + * + * @author 2003-03-13 Jeff Anderson + * + * @internal + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-10-15 Jeff Anderson - Added requirement for frame kernel in + * labels + * @history 2003-10-28 Jeff Anderson - Changed SpaceCraft to Spacecraft in + * labels and method names + * @history 2003-11-03 Jeff Anderson - Added SubSolarPoint and + * SubSpacecraftPoint methods + * @history 2003-11-12 Jeff Anderson - Added Target method + * @history 2004-01-14 Jeff Anderson - Changed how the SPK, CK, and Instrument + * codes where handled. The instrument code + * must be in the labels as NaifFrameCode + * and then the other two can be + * automatically computed. + * @history 2004-02-18 Jeff Anderson - Modified to ignore kernel labels which + * were blank + * @history 2004-03-25 Jeff Anderson - Modified NaifBodyCode method to convert + * Jupiter target code of 599 to 5 + * @history 2004-03-25 Jeff Anderson - Fixed bug in destructor and added + * GetString method. + * @history 2005-02-15 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-02-24 Jeff Anderson - Modified SubSolarPoint and + * SubSpacecraftPoint to return positive + * longitudes only + * @history 2005-09-12 Jeff Anderson - Check for case-insensitive values for + * TargetName of SKY + * @history 2005-09-20 Jeff Anderson - Added IsSky method + * @history 2006-01-05 Debbie A. Cook - Added units to comments + * @history 2006-03-28 Jeff Anderson - Refactored using SpiceRotation and + * SpicePosition classes. Added Tables + * and nadir kernel information. + * @history 2006-03-31 Elizabeth Miller - Added TargetCenterDistance method + * @history 2006-04-19 Elizabeth Miller - Added SolarLongitude method + * @history 2007-01-30 Tracie Sucharski - Throw error in the load method before + * calling furnish if the file does not exist. + * @history 2007-07-09 Steven Lambright - Frame kernel is now optional, added Extra kernel + * support. + * @history 2007-07-10 Debbie A. Cook - Modified method ComputeSolarLongitude to use + * pxform instead of tipbod to get body-fixed to + * J2000 rotation matrix so that the correct frame + * will be used. If the frame is different from the + * default IAU frame, the correct frame should be set + * in the iak file (see frames.req). Also modified + * setting of p_bodyRotation frameCode. The old code + * forced the IAU_ frame. The new code uses the Naif + * routine cidfrm to get the frame associated with the + * body id. These change will recognize any frame + * changes made in the iak file. + * @history 2007-08-10 Steven Lambright - Added support for Nadir keyword in InstrumentPointing group + * to not be the first element in the PvlKeyword. + * @history 2007-08-24 Debbie A. Cook - Removed p_sB so it is recalculated every time it is used + * insuring that any updates to the position or rotation are applied. + * Also removed p_BP since it is no longer used + * @history 2008-02-13 Steven Lambright - Added StartPadding and EndPadding caching capabilties + * @history 2008-02-13 Steven Lambright - Added Support Check for StartPadding and EndPadding caching capabilties; + * An clarified exception is thrown if a framing camera tries to use time padding + * @history 2008-02-27 Kris Becker - Modified so that planetary ephemeris SPKs + * are loaded before spacecraft SPKs so that + * missions that augment planet ephemerides + * will take precidence. + * @history 2008-06-23 Steven Lambright - Added NaifStatus error checking + * @history 2008-06-25 Debbie A. Cook - Added method InstrumentVelocity to support miniRF + * @history 2008-11-28 Debbie A. Cook - Added method HasKernels() + * @history 2009-03-18 Tracie Sucharski - Cleaned up some unnecessary,obsolete code. Make sure the + * table is used if the kernel names follow the "Table" keyword value, due to change + * made to spiceinit to retain kernel names if the spice is written to blob. + * @history 2009-06-18 Debbie A. Cook - Modified to downsize instrument rotation table when loading cache + * @history 2009-07-01 Debbie A. Cook - Modified to downsize body rotation, and sun position tables when loading cache + * @history 2009-08-03 Debbie A. Cook - Added tolerance argument to method + * CreateCache to allow downsizing of + * instrument position Spice table. + * @history 2009-08-21 Kris Becker - Moved the NAIF code methods to public + * scope. + * @history 2010-01-29 Debbie A. Cook - Redid Tracie's change to make sure the table is loaded instead of the + * kernels if the kernel keyword value lists "Table" before the kernel files. + * @history 2010-03-19 Debbie A. Cook - Added constructor and moved common constructor initialization into + * new method Init. Also added parameter notab to method Load. + * @history 2010-04-09 Debbie A. Cook - Moved the loading of the "extra" kernel(s) from the middle of + * the loads to the end. + * + * + */ + class Spice { + public: + // constructors + Spice (Isis::Pvl &lab); + Spice (Isis::Pvl &lab, bool notab); + + // destructor + ~Spice (); + + // Methods + void Init( Isis::Pvl &lab, bool notab); + void SetEphemerisTime (const double time); + void InstrumentPosition (double p[3]) const; + void SunPosition (double p[3]) const; + double TargetCenterDistance() const; + double SolarLongitude(); + void InstrumentVelocity( double v[3] ) const; + //! Sets flag to allow downsizing of kernels +// void AllowDownsizing( bool allow) const { p_allowDownsizing = allow; }; + + /** + * Returns the ephemeris time in seconds which was used to obtain the + * spacecraft and sun positions. + * + * @return double + */ + inline double EphemerisTime () const { return p_et; }; + + void Radii (double r[3]) const; + + void CreateCache (const double startTime, const double endTime, + const int size, double tol); + void CreateCache (const double time, double tol); + inline double CacheStartTime () const { return p_startTime; }; + inline double CacheEndTime () const { return p_endTime; }; + + void SubSpacecraftPoint (double &lat, double &lon); + void SubSolarPoint (double &lat, double &lon); + + /** + * Returns the string name of the target + * + * @return string + */ + std::string Target () const { return p_target; }; + + //! Return if our target is the sky + bool IsSky () const { return p_sky; }; + + static SpiceDouble GetDouble (const std::string &key, int index=0); + static SpiceInt GetInteger (const std::string &key, int index=0); + static std::string GetString (const std::string &key, int index=0); + + SpicePosition *SunPosition() const { return p_sunPosition; }; + SpicePosition *InstrumentPosition() const { return p_instrumentPosition; }; + SpiceRotation *BodyRotation() const { return p_bodyRotation; }; + SpiceRotation *InstrumentRotation() const { return p_instrumentRotation; }; + + bool HasKernels(Isis::Pvl &lab); + + SpiceInt NaifBodyCode () const; + SpiceInt NaifSpkCode () const; + SpiceInt NaifCkCode () const; + SpiceInt NaifIkCode () const; + SpiceInt NaifSclkCode () const; + + protected: + // Leave these protected so that inheriting classes don't + // have to convert between double and spicedouble + // None of the below data elements are usable (except + // p_radii) until SetEphemerisTime is invoked + SpiceDouble p_uB[3]; /** p_kernels; + std::string p_target; + + // cache stuff + SpiceDouble p_startTime; + SpiceDouble p_endTime; + SpiceDouble p_cacheSize; + + SpiceDouble p_startTimePadding; + SpiceDouble p_endTimePadding; + + SpicePosition *p_instrumentPosition; + SpiceRotation *p_instrumentRotation; + SpicePosition *p_sunPosition; + SpiceRotation *p_bodyRotation; + + bool p_keepKernelsLoaded; + bool p_allowDownsizing; + + // Constants + SpiceInt p_bodyCode; + SpiceInt p_spkCode; + SpiceInt p_ckCode; + SpiceInt p_ikCode; + SpiceInt p_sclkCode; + SpiceInt p_spkBodyCode; + + bool p_sky; + }; +}; + +#endif diff --git a/isis/src/base/objs/Spice/Spice.truth b/isis/src/base/objs/Spice/Spice.truth new file mode 100644 index 0000000000000000000000000000000000000000..f7ee6daaf479e6a677b6987a700eab5857db51eb --- /dev/null +++ b/isis/src/base/objs/Spice/Spice.truth @@ -0,0 +1,536 @@ +Unit test for Isis::Spice +Testing unknown target ... +**I/O ERROR** Could not convert Target [Mard] to NAIF code + +Creating Spice object ... +BodyCode = 499 +SpkCode = -94 +CkCode = -94031 +IkCode = -94031 + + +Testing unknown integer keyword ... +**I/O ERROR** Can not find [BadInteger] in instrument kernels + +Testing unknown double keyword ... +**I/O ERROR** Can not find [BadDouble] in instrument kernels + +Testing unknown string keyword ... +**I/O ERROR** Can not find [BadString] in instrument kernels + +Testing convience get methods ... +-94031 +3.5 +MGS_MOC + +Testing radius ... +Radii[0]: 3397 +Radii[1]: 3397 +Radii[2]: 3375 + +Testing without cache ... +Time = -69382819 +Spacecraft (B) = -2036.01629 -2120.808621 2008.687495 +Spacecraft Velocity (B) = -2.089191159 -1.697268689 -3.895161847 +Sun (B) = -176801920.6 113794008.3 -33706771.9 +BJ is +0.6561782269 +-0.4574472623 +-0.6001434301 +0.6085786288 +0.7910320527 +0.06245273504 +0.4461638568 +-0.4062145907 +0.7974506374 +BP is +-0.4423645664 +-0.692297865 +0.5701203878 +-0.3597558587 +0.7192938481 +0.594299657 +-0.8215164713 +0.05779296037 +-0.5672483241 +SubSpacecraft = 34.34257617 226.1685768 +SubSolar = -9.107720959 147.2336839 +Time = -69382784.89 +Spacecraft (B) = -2111.404257 -2172.427377 1874.729627 +Spacecraft Velocity (B) = -2.026180942 -1.622999314 -3.958312123 +Sun (B) = -176526606.5 114220422.9 -33707109.25 +BJ is +0.6576477714 +-0.4555333144 +-0.5999906735 +0.6069902978 +0.7921357874 +0.06390361984 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.4168543494 +-0.6905226544 +0.5911099011 +-0.3312854515 +0.7209911651 +0.6086227809 +-0.8464528345 +0.05788094286 +-0.5293084124 +SubSpacecraft = 31.75080906 225.8161224 +SubSolar = -9.107815409 147.0953692 +Time = -69382750.78 +Spacecraft (B) = -2184.722528 -2221.309928 1738.693913 +Spacecraft Velocity (B) = -1.960759914 -1.547430485 -4.016954876 +Sun (B) = -176250264 114646171.3 -33707446.59 +BJ is +0.6591134712 +-0.4536167035 +-0.5998344092 +0.6053984184 +0.7932348912 +0.06535413105 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.390339615 +-0.6887619255 +0.6109353444 +-0.3023537678 +0.7226720154 +0.621552377 +-0.8696074885 +0.05789791229 +-0.4903372795 +SubSpacecraft = 29.16383392 225.4757694 +SubSolar = -9.107909859 146.9570545 +Time = -69382716.67 +Spacecraft (B) = -2255.886692 -2267.422128 1600.737485 +Spacecraft Velocity (B) = -1.893192811 -1.470861242 -4.070898387 +Sun (B) = -175972894.7 115071251.1 -33707783.94 +BJ is +0.6605753178 +-0.4516974406 +-0.5996746382 +0.6038029997 +0.7943293576 +0.0668042602 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.3629817846 +-0.6870327422 +0.6294682162 +-0.273100895 +0.7243171208 +0.6330723574 +-0.8908760437 +0.05788540086 +-0.4505431779 +SubSpacecraft = 26.58655928 225.1461166 +SubSolar = -9.108004309 146.8187398 +Time = -69382682.56 +Spacecraft (B) = -2324.821503 -2310.740416 1461.023378 +Spacecraft Velocity (B) = -1.823756613 -1.393601682 -4.119988675 +Sun (B) = -175694500.2 115495660 -33708121.29 +BJ is +0.6620333026 +-0.4497755371 +-0.5995113615 +0.6022040511 +0.7954191804 +0.0682539988 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.3348119429 +-0.6853030661 +0.6467307557 +-0.2435256111 +0.725956728 +0.6431812387 +-0.9102726183 +0.05784925765 +-0.4099478306 +SubSpacecraft = 24.02376616 224.8259576 +SubSolar = -9.108098759 146.6804252 +Time = -69382648.44 +Spacecraft (B) = -2391.461346 -2351.252049 1319.719221 +Spacecraft Velocity (B) = -1.752742386 -1.3159638 -4.164109004 +Sun (B) = -175415082.2 115919395.2 -33708458.63 +BJ is +0.6634874171 +-0.4478510041 +-0.59934458 +0.600601582 +0.796504353 +0.06970333838 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.3060561627 +-0.68355981 +0.6626278076 +-0.2138609199 +0.7276038973 +0.6518098462 +-0.9276815899 +0.05778022785 +-0.3688743865 +SubSpacecraft = 21.48005645 224.5142511 +SubSolar = -9.108193209 146.5421105 +Time = -69382614.33 +Spacecraft (B) = -2455.750911 -2388.95502 1176.996136 +Spacecraft Velocity (B) = -1.68046736 -1.238257835 -4.203171537 +Sun (B) = -175134642.1 116342454.5 -33708795.98 +BJ is +0.6649376527 +-0.445923853 +-0.5991742946 +0.5989956017 +0.7975848692 +0.07115227047 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.2766952213 +-0.6818393104 +0.6771520577 +-0.1841172498 +0.7292245562 +0.6590389859 +-0.9431545965 +0.05767756345 +-0.3273113286 +SubSpacecraft = 18.95980983 224.2100903 +SubSolar = -9.108287659 146.4037958 +Time = -69382580.22 +Spacecraft (B) = -2517.646325 -2423.858162 1033.02746 +Spacecraft Velocity (B) = -1.607282465 -1.160802798 -4.237141488 +Sun (B) = -174853181.8 116764835.4 -33709133.32 +BJ is +0.6663840011 +-0.4439940949 +-0.5990005064 +0.5973861196 +0.7986607226 +0.0726007866 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.2471347253 +-0.6800459017 +0.6902622684 +-0.1543886702 +0.730893444 +0.6647999038 +-0.9566026166 +0.05772646791 +-0.2856205329 +SubSpacecraft = 16.46714253 223.9126751 +SubSolar = -9.108382109 146.2654811 +Time = -69382546.11 +Spacecraft (B) = -2577.115866 -2455.981253 887.9862654 +Spacecraft Velocity (B) = -1.533539138 -1.083910621 -4.266071131 +Sun (B) = -174570702.8 117186535.3 -33709470.66 +BJ is +0.6678264538 +-0.4420617412 +-0.5988232165 +0.5957731452 +0.799731907 +0.07404887829 +0.4461638568 +-0.4062145909 +0.7974506374 +BP is +-0.2172312486 +-0.6782515195 +0.7019867954 +-0.1248838113 +0.732561542 +0.6691469352 +-0.9680984548 +0.05769283776 +-0.2438378933 +SubSpacecraft = 14.00585821 223.6212937 +SubSolar = -9.108476558 146.1271665 +Time = -69382512 +Spacecraft (B) = -2634.139267 -2485.35422 742.042555 +Spacecraft Velocity (B) = -1.459550389 -1.007857765 -4.290081123 +Sun (B) = -174287206.7 117607551.9 -33709808.01 +BJ is +0.6692650023 +-0.4401268032 +-0.5986424257 +0.5941566878 +0.8007984161 +0.07549653709 +0.4461638568 +-0.4062145909 +0.7974506374 +BP is +-0.1871825234 +-0.6764943131 +0.7122626954 +-0.09564741512 +0.7341844699 +0.6721790953 +-0.9776575448 +0.05769409354 +-0.2021314341 +SubSpacecraft = 11.57940777 223.3353126 +SubSolar = -9.108571008 145.9888518 + +Testing with cache ... +Time = -69382819 +Spacecraft (B) = -2036.01629 -2120.808621 2008.687495 +Spacecraft Velocity (B) = -2.089191159 -1.697268689 -3.895161847 +Sun (B) = -176801920.6 113794008.3 -33706771.9 +BJ is +0.6561782269 +-0.4574472623 +-0.6001434301 +0.6085786288 +0.7910320527 +0.06245273504 +0.4461638568 +-0.4062145907 +0.7974506374 +BP is +-0.4423645664 +-0.692297865 +0.5701203878 +-0.3597558587 +0.7192938481 +0.594299657 +-0.8215164713 +0.05779296037 +-0.5672483241 +Time = -69382784.89 +Spacecraft (B) = -2111.404257 -2172.427377 1874.729627 +Spacecraft Velocity (B) = -2.026180942 -1.622999314 -3.958312123 +Sun (B) = -176526606.5 114220422.8 -33707109.24 +BJ is +0.6576477714 +-0.4555333144 +-0.5999906735 +0.6069902978 +0.7921357874 +0.06390361984 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.4168543494 +-0.6905226544 +0.5911099011 +-0.3312854515 +0.7209911651 +0.6086227809 +-0.8464528345 +0.05788094286 +-0.5293084124 +Time = -69382750.78 +Spacecraft (B) = -2184.722528 -2221.309928 1738.693913 +Spacecraft Velocity (B) = -1.960759914 -1.547430485 -4.016954876 +Sun (B) = -176250264 114646171.3 -33707446.59 +BJ is +0.6591134712 +-0.4536167035 +-0.5998344092 +0.6053984184 +0.7932348912 +0.06535413105 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.390339615 +-0.6887619255 +0.6109353444 +-0.3023537678 +0.7226720154 +0.621552377 +-0.8696074885 +0.05789791229 +-0.4903372795 +Time = -69382716.67 +Spacecraft (B) = -2255.886692 -2267.422128 1600.737485 +Spacecraft Velocity (B) = -1.893192811 -1.470861242 -4.070898387 +Sun (B) = -175972894.7 115071251.1 -33707783.94 +BJ is +0.6605753178 +-0.4516974406 +-0.5996746382 +0.6038029997 +0.7943293576 +0.0668042602 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.3629817846 +-0.6870327422 +0.6294682162 +-0.273100895 +0.7243171208 +0.6330723574 +-0.8908760437 +0.05788540086 +-0.4505431779 +Time = -69382682.56 +Spacecraft (B) = -2324.821503 -2310.740416 1461.023378 +Spacecraft Velocity (B) = -1.823756613 -1.393601682 -4.119988675 +Sun (B) = -175694500.2 115495659.9 -33708121.28 +BJ is +0.6620333026 +-0.4497755371 +-0.5995113615 +0.6022040511 +0.7954191804 +0.0682539988 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.3348119429 +-0.6853030661 +0.6467307557 +-0.2435256111 +0.725956728 +0.6431812387 +-0.9102726183 +0.05784925765 +-0.4099478306 +Time = -69382648.44 +Spacecraft (B) = -2391.461346 -2351.252049 1319.719221 +Spacecraft Velocity (B) = -1.752742386 -1.3159638 -4.164109004 +Sun (B) = -175415082.1 115919395.2 -33708458.63 +BJ is +0.6634874171 +-0.4478510041 +-0.59934458 +0.600601582 +0.796504353 +0.06970333838 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.3060561627 +-0.68355981 +0.6626278076 +-0.2138609199 +0.7276038973 +0.6518098462 +-0.9276815899 +0.05778022785 +-0.3688743865 +Time = -69382614.33 +Spacecraft (B) = -2455.750911 -2388.95502 1176.996136 +Spacecraft Velocity (B) = -1.68046736 -1.238257835 -4.203171537 +Sun (B) = -175134642.1 116342454.5 -33708795.97 +BJ is +0.6649376527 +-0.445923853 +-0.5991742946 +0.5989956017 +0.7975848692 +0.07115227047 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.2766952213 +-0.6818393104 +0.6771520577 +-0.1841172498 +0.7292245562 +0.6590389859 +-0.9431545965 +0.05767756345 +-0.3273113286 +Time = -69382580.22 +Spacecraft (B) = -2517.646325 -2423.858162 1033.02746 +Spacecraft Velocity (B) = -1.607282465 -1.160802798 -4.237141488 +Sun (B) = -174853181.8 116764835.4 -33709133.32 +BJ is +0.6663840011 +-0.4439940949 +-0.5990005064 +0.5973861196 +0.7986607226 +0.0726007866 +0.4461638568 +-0.4062145908 +0.7974506374 +BP is +-0.2471347253 +-0.6800459017 +0.6902622684 +-0.1543886702 +0.730893444 +0.6647999038 +-0.9566026166 +0.05772646791 +-0.2856205329 +Time = -69382546.11 +Spacecraft (B) = -2577.115866 -2455.981253 887.9862654 +Spacecraft Velocity (B) = -1.533539138 -1.083910621 -4.266071131 +Sun (B) = -174570702.8 117186535.3 -33709470.66 +BJ is +0.6678264538 +-0.4420617412 +-0.5988232165 +0.5957731452 +0.799731907 +0.07404887829 +0.4461638568 +-0.4062145909 +0.7974506374 +BP is +-0.2172312486 +-0.6782515195 +0.7019867954 +-0.1248838113 +0.732561542 +0.6691469352 +-0.9680984548 +0.05769283776 +-0.2438378933 +Time = -69382512 +Spacecraft (B) = -2634.139267 -2485.35422 742.042555 +Spacecraft Velocity (B) = -1.459550389 -1.007857765 -4.290081123 +Sun (B) = -174287206.7 117607551.9 -33709808.01 +BJ is +0.6692650023 +-0.4401268032 +-0.5986424257 +0.5941566878 +0.8007984161 +0.07549653709 +0.4461638568 +-0.4062145909 +0.7974506374 +BP is +-0.1871825234 +-0.6764943131 +0.7122626954 +-0.09564741512 +0.7341844699 +0.6721790953 +-0.9776575448 +0.05769409354 +-0.2021314341 + +Testing Utility methods +Target Name = Mars diff --git a/isis/src/base/objs/Spice/unitTest.cpp b/isis/src/base/objs/Spice/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..53b5f2e96c929ddca2da34a071a013e9ea050a7e --- /dev/null +++ b/isis/src/base/objs/Spice/unitTest.cpp @@ -0,0 +1,203 @@ +#include +#include +#include "iException.h" +#include "Spice.h" +#include "Filename.h" +#include "Preference.h" + + +using namespace std; +/** + * UnitTest for Spice class. + * + * @internal + * @history 2009-03-23 Tracie Sucharski - Removed old keywords + * SpacecraftPosition and SpacecraftPointing with the corrected + * InstrumentPosition and InstrumentPointing. + */ +class MySpice : public Isis::Spice { + public: + MySpice (Isis::Pvl &lab) : Isis::Spice (lab) { + cout << "BodyCode = " << NaifBodyCode() << endl; + cout << "SpkCode = " << NaifSpkCode() << endl; + cout << "CkCode = " << NaifCkCode() << endl; + cout << "IkCode = " << NaifIkCode() << endl; + cout << endl; + } + + int MyInteger (string key) { + return GetInteger(key,0); + } + + double MyDouble (string key) { + return GetDouble(key,0); + } + + string MyString (string key) { + return GetString(key,0); + } + + void MyOutput () { + cout << "BJ is " << endl; + vector BJ = BodyRotation()->Matrix(); + for (int i=0; i<(int)BJ.size(); i++) { + cout << BJ[i] << endl; + } + vector IJ = InstrumentRotation()->Matrix(); + vector BI = IJ; + mxmt_c((SpiceDouble (*)[3])&BJ[0],(SpiceDouble (*)[3])&IJ[0], + (SpiceDouble (*)[3])&BI[0]); + + cout << "BP is " << endl; + for (int i=0; i<(int)BI.size(); i++) { + cout << BI[i] << endl; + } + }; +}; + + + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + +cout << setprecision(10); +cout << "Unit test for Isis::Spice" << endl; + + Isis::PvlGroup inst("Instrument"); + inst += Isis::PvlKeyword("TargetName","Mard"); + + Isis::PvlGroup kern("Kernels"); + Isis::Filename f("$base/testData/kernels"); + string dir = f.Expanded() + "/"; + kern += Isis::PvlKeyword("NaifFrameCode",-94031); + kern += Isis::PvlKeyword("LeapSecond",dir+"naif0007.tls"); + kern += Isis::PvlKeyword("SpacecraftClock",dir+"MGS_SCLKSCET.00045.tsc"); + kern += Isis::PvlKeyword("TargetPosition",dir+"de405.bsp"); + kern += Isis::PvlKeyword("TargetAttitudeShape",dir+"pck00006.tpc"); + kern += Isis::PvlKeyword("Instrument",dir+"mocSpiceUnitTest.ti"); + kern += Isis::PvlKeyword("InstrumentAddendum",dir+"mocAddendum.ti"); + kern += Isis::PvlKeyword("InstrumentPosition",dir+"moc.bsp"); + kern += Isis::PvlKeyword("InstrumentPointing",dir+"moc.bc"); + kern += Isis::PvlKeyword("Frame",""); + + // Time Setup + double startTime = -69382819.0; + double endTime = -69382512.0; + double slope = (endTime - startTime) / (10 - 1); + + kern += Isis::PvlKeyword("StartPadding", slope); + kern += Isis::PvlKeyword("EndPadding", slope); + + Isis::Pvl lab; + lab.AddGroup(inst); + lab.AddGroup(kern); + + // Test bad target + try { + cout << "Testing unknown target ..." << endl; + MySpice spi(lab); + } + catch (Isis::iException &e) { + e.Report(false); + cout << endl; + } + + // Test bad getInteger + Isis::PvlGroup &temp = lab.FindGroup("Instrument"); + temp.AddKeyword(Isis::PvlKeyword("TargetName","Mars"),Isis::Pvl::Replace); + cout << "Creating Spice object ..." << endl; + MySpice spi(lab); + spi.InstrumentRotation()->SetTimeBias(-1.15); + cout << endl; + + try { + cout << "Testing unknown integer keyword ... " << endl; + spi.MyInteger("BadInteger"); + } + catch (Isis::iException &e) { + e.Report(false); + cout << endl; + } + + // Test bad getDouble + try { + cout << "Testing unknown double keyword ... " << endl; + spi.MyDouble("BadDouble"); + } + catch (Isis::iException &e) { + e.Report(false); + cout << endl; + } + + // Test bad getString + try { + cout << "Testing unknown string keyword ... " << endl; + spi.MyString("BadString"); + } + catch (Isis::iException &e) { + e.Report(false); + cout << endl; + } + + // Test good gets + cout << "Testing convience get methods ... " << endl; + cout << spi.MyInteger("FRAME_MGS_MOC") << endl; + cout << spi.MyDouble("INS-94030_NA_FOCAL_LENGTH") << endl; + cout << spi.MyString("FRAME_-94031_NAME") << endl; + cout << endl; + + // Testing radius + cout << "Testing radius ... " << endl; + double radii[3]; + spi.Radii(radii); + cout << "Radii[0]: " << radii[0] << endl; + cout << "Radii[1]: " << radii[1] << endl; + cout << "Radii[2]: " << radii[2] << endl; + cout << endl; + + // Normal testing (no cache) + cout << "Testing without cache ... " << endl; + for (int i=0; i<10; i++) { + double t = startTime + (double) i * slope; + spi.SetEphemerisTime(t); + cout << "Time = " << spi.EphemerisTime() << endl; + double p[3]; + spi.InstrumentPosition(p); + cout << "Spacecraft (B) = " << p[0] << " " << p[1] << " " << p[2] << endl; + double v[3]; + spi.InstrumentVelocity(v); + cout << "Spacecraft Velocity (B) = " << v[0] << " " << v[1] << " " << v[2] << endl; + spi.SunPosition(p); + cout << "Sun (B) = " << p[0] << " " << p[1] << " " << p[2] << endl; + spi.MyOutput(); + double lat,lon; + spi.SubSpacecraftPoint (lat,lon); + cout << "SubSpacecraft = " << lat << " " << lon << endl; + spi.SubSolarPoint (lat,lon); + cout << "SubSolar = " << lat << " " << lon << endl; + } + cout << endl; + + // Testing with cache + cout << "Testing with cache ... " << endl; + double tol=.0022; //estimate resolution pixelPitch*alt/fl*1000. + spi.CreateCache(startTime+slope,endTime-slope,10,tol); + for (int i=0; i<10; i++) { + double t = startTime + (double) i * slope; + spi.SetEphemerisTime(t); + cout << "Time = " << spi.EphemerisTime() << endl; + double p[3]; + spi.InstrumentPosition(p); + cout << "Spacecraft (B) = " << p[0] << " " << p[1] << " " << p[2] << endl; + double v[3]; + spi.InstrumentVelocity(v); + cout << "Spacecraft Velocity (B) = " << v[0] << " " << v[1] << " " << v[2] << endl; + spi.SunPosition(p); + cout << "Sun (B) = " << p[0] << " " << p[1] << " " << p[2] << endl; + spi.MyOutput(); + } + cout << endl; + + cout << "Testing Utility methods" << endl; + cout << "Target Name = " << spi.Target () << endl; +} diff --git a/isis/src/base/objs/SpicePosition/Makefile b/isis/src/base/objs/SpicePosition/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..85770e47560ec513244165fb70b577b7b74e1736 --- /dev/null +++ b/isis/src/base/objs/SpicePosition/Makefile @@ -0,0 +1,5 @@ +INCS = SpicePosition.h +SRCS = SpicePosition.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/SpicePosition/SpicePosition.cpp b/isis/src/base/objs/SpicePosition/SpicePosition.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc4aef3acd37a61092913d5b091c25dd2c31feba --- /dev/null +++ b/isis/src/base/objs/SpicePosition/SpicePosition.cpp @@ -0,0 +1,1113 @@ +#include +#include + +#include "SpicePosition.h" +#include "BasisFunction.h" +#include "LeastSquares.h" +#include "LineEquation.h" +#include "NaifStatus.h" +#include "NumericalApproximation.h" +#include "PolynomialUnivariate.h" +#include "iException.h" + +namespace Isis { + /** + * Construct an empty SpicePosition class using valid body codes. + * See required reading + * ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/ascii/individual_docs/naif_ids.req + * + * @param targetCode Valid naif body name. + * @param observerCode Valid naif body name. + */ + SpicePosition::SpicePosition(int targetCode, int observerCode) { + p_targetCode = targetCode; + p_observerCode = observerCode; + p_timeBias = 0.0; + p_aberrationCorrection = "LT+S"; + p_source = Spice; + p_coordinate.resize(3); + p_velocity.resize(3); + p_et = -DBL_MAX; + p_noOverride = true; + p_hasVelocity = false; + } + + /** Apply a time bias when invoking SetEphemerisTime method. + * + * The bias is used only when reading from NAIF kernels. It is added to the + * ephermeris time passed into SetEphemerisTime and then the body + * position is read from the NAIF kernels and returned. When the cache + * is loaded from a table the bias is ignored as it is assumed + * to have already been applied. If this method is never called + * the default bias is 0.0 seconds. + * + * @param timeBias time bias in seconds + */ + void SpicePosition::SetTimeBias (double timeBias) { + p_timeBias = timeBias; + } + + /** Set the aberration correction (light time). + * See NAIF required reading for more information on this correction at + * ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/ascii/individual_docs/spk.req + * + * @param correction This value must be one of the following: "NONE", "LT", + * "LT+S", where LT is a correction for planetary aberration (light time) and + * S a correction for stellar aberration. If never called the default is + * "LT+S". + */ + void SpicePosition::SetAberrationCorrection(const std::string &correction) { + if (correction == "NONE" || correction == "LT" || correction == "LT+S") { + p_aberrationCorrection = correction; + } + else { + std::string msg = "Invalid abberation correction [" + correction + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + + /** Return J2000 coordinate at given time. + * + * This method returns the J2000 coordinates (x,y,z) of the body at a given + * et in seconds. The coordinates are obtained from either a valid NAIF spk + * kernel, or alternatively from an internal cache loaded from an ISIS Table + * object. In the first case, the SPK kernel must contain positions for + * the body code specified in the constructor at the given time and it must + * be loaded using the SpiceKernel class. + * + * @param et ephemeris time in seconds + * @internal + * @history 2009-08-03 Jeannie Walldren - Moved code to + * individual methods for each Source type + * to make software more readable. + */ + const std::vector &SpicePosition::SetEphemerisTime(double et) { + NaifStatus::CheckErrors(); + + // Save the time + if (et == p_et) return p_coordinate; + p_et = et; + + // Read from the cache + if (p_source == Memcache) { + SetEphemerisTimeMemcache(); + } + else if(p_source == HermiteCache) { + SetEphemerisTimeHermiteCache(); + } + else { // Read from the kernel + SetEphemerisTimeSpice(); + } + // Return the coordinate + return p_coordinate; + NaifStatus::CheckErrors(); + } + + /** Cache J2000 position over a time range. + * + * This method will load an internal cache with coordinates over a time + * range. This prevents + * the NAIF kernels from being read over-and-over again and slowing a + * application down due to I/O performance. Once the + * cache has been loaded then the kernels can be unloaded from the NAIF + * system. + * + * @param startTime Starting ephemeris time in seconds for the cache + * @param endTime Ending ephemeris time in seconds for the cache + * @param size Number of coordinates/positions to keep in the cache + * + */ + void SpicePosition::LoadCache (double startTime, double endTime, int size) { + // Make sure cache isn't alread loaded + if (p_source == Memcache || p_source == HermiteCache) { + std::string msg = "A SpicePosition cache has already been created"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (startTime > endTime) { + std::string msg = "Argument startTime must be less than or equal to endTime"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if ((startTime != endTime) && (size == 1)) { + std::string msg = "Cache size must be more than 1 if startTime endTime differ"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + + // Loop and load the cache + double cacheSlope = 0.0; + if (size > 1) cacheSlope = (endTime - startTime) / (double) (size - 1); + + for (int i=0; i j2000Coord; + j2000Coord.push_back((double)rec[0]); + j2000Coord.push_back((double)rec[1]); + j2000Coord.push_back((double)rec[2]); + int inext = 3; + + p_cache.push_back(j2000Coord); + if (p_hasVelocity) { + std::vector j2000Velocity; + j2000Velocity.push_back((double)rec[3]); + j2000Velocity.push_back((double)rec[4]); + j2000Velocity.push_back((double)rec[5]); + inext = 6; + + p_cacheVelocity.push_back(j2000Velocity); + } + p_cacheTime.push_back((double)rec[inext]); + } + } + + /** Return a table with J2000 positions. + * + * Return a table containg the cached coordinates with the given name. The + * table will have four or seven columns, J2000 x,y,z (optionally vx,vy,vx) + * and the ephemeris time. + * + * @param tableName Name of the table to create and return + * @internal + * @history 2009-08-03 Jeannie Walldren - Added CacheType + * keyword to output table. This is based on + * p_source and will be read by LoadCache(Table). + */ + Table SpicePosition::Cache(const std::string &tableName) { + + // determine type of table to return + std::string tabletype = ""; + if (p_source == Memcache) { + tabletype = "Linear"; + } + else if (p_source == HermiteCache) { + tabletype = "HermiteSpline"; + } + else { + throw iException::Message(iException::Io, + "Cannot create Table, no Cache is loaded.", + _FILEINFO_); + } + + // reacord to be added to table + TableRecord record; + + // add x,y,z position labels to record + TableField x("J2000X",TableField::Double); + TableField y("J2000Y",TableField::Double); + TableField z("J2000Z",TableField::Double); + record += x; + record += y; + record += z; + + if ( p_hasVelocity ) { + // add x,y,z velocity labels to record + TableField vx("J2000XV",TableField::Double); + TableField vy("J2000YV",TableField::Double); + TableField vz("J2000ZV",TableField::Double); + record += vx; + record += vy; + record += vz; + } + // add time label to record + TableField t("ET",TableField::Double); + record += t; + + // create output table + Table table(tableName,record); + + int inext=0; + for (int i=0; i<(int)p_cache.size(); i++) { + record[inext++] = p_cache[i][0]; // record[0] + record[inext++] = p_cache[i][1]; // record[1] + record[inext++] = p_cache[i][2]; // record[2] + if (p_hasVelocity) { + record[inext++] = p_cacheVelocity[i][0]; // record[3] + record[inext++] = p_cacheVelocity[i][1]; // record[4] + record[inext++] = p_cacheVelocity[i][2]; // record[5] + } + record[inext] = p_cacheTime[i]; // record[6] + table += record; + + inext = 0; + } + + // set CacheType keyword in table's label + table.Label() += PvlKeyword("CacheType", tabletype); + + return table; + } + + + + /** Cache J2000 position over existing cached time range using + * polynomials + * + * This method will reload an internal cache with positions + * formed from coordinates fit to polynomials over a time + * range. + * + * @param function1 The first polynomial function used to + * find the position coordinates + * @param function2 The second polynomial function used to + * find the position coordinates + * @param function3 The third polynomial function used to + * find the position coordinates + */ + void SpicePosition::ReloadCache (Isis::PolynomialUnivariate &function1, + Isis::PolynomialUnivariate &function2, + Isis::PolynomialUnivariate &function3){ + // Make sure cache is already loaded + if ( p_source != Memcache && p_source != HermiteCache ) { + std::string msg = "A SpicePosition cache has not been created yet"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Clear existing coordinates from cache + p_cache.clear(); + p_cacheVelocity.clear(); + + + // Set velocity vector to true since it is calculated + p_hasVelocity = true; + +// std::cout <<"time cache size is " << p_cacheTime.size() << std::endl; + + // Calculate new postition coordinates from polynomials fit to coordinates & + // fill cache +// std::cout << "Before" << std::endl; +// double savetime = p_cacheTime.at(0); +// SetEphemerisTime(savetime); +// std::cout << " at time " << savetime << std::endl; +// for (int i=0; i<3; i++) { +// std::cout << p_coordinate[i] << std::endl; +// } + + // find the first and last time values + double firstTime = p_cacheTime[0]; + double lastTime = p_cacheTime[p_cacheTime.size()-1]; + + if (p_cacheTime.size() != 1 ) { + + // find time for the extremum of each polynomial + // since this is only a 2nd degree polynomial, + // finding these extrema is simple + double b1 = function1.Coefficient(1); + double c1 = function1.Coefficient(2); + double extremumXtime = -b1/(2.*c1) + p_baseTime; // extremum is time value for root of 1st derivative + // make sure we are in the domain + if (extremumXtime < firstTime) { + extremumXtime = firstTime; + } + if (extremumXtime > lastTime) { + extremumXtime = lastTime; + } + + double b2 = function2.Coefficient(1); + double c2 = function2.Coefficient(2); + double extremumYtime = -b2/(2.*c2) + p_baseTime; + // make sure we are in the domain + if (extremumYtime < firstTime) { + extremumYtime = firstTime; + } + if (extremumYtime > lastTime) { + extremumYtime = lastTime; + } + + double b3 = function3.Coefficient(1); + double c3 = function3.Coefficient(2); + double extremumZtime = -b3/(2.*c3) + p_baseTime; + // make sure we are in the domain + if (extremumZtime < firstTime) { + extremumZtime = firstTime; + } + if (extremumZtime > lastTime) { + extremumZtime = lastTime; + } + + // refill the time vector + p_cacheTime.clear(); + p_cacheTime.push_back(firstTime); + p_cacheTime.push_back(extremumXtime); + p_cacheTime.push_back(extremumYtime); + p_cacheTime.push_back(extremumZtime); + p_cacheTime.push_back(lastTime); + // we don't know order of extrema, so sort + sort(p_cacheTime.begin(),p_cacheTime.end()); + // in case an extremum is an endpoint + std::vector ::iterator it = unique(p_cacheTime.begin(),p_cacheTime.end()); + p_cacheTime.resize(it - p_cacheTime.begin()); + + if (p_cacheTime.size() == 2) { + p_cacheTime.clear(); + p_cacheTime.push_back(firstTime); + p_cacheTime.push_back((firstTime+lastTime)/2); + p_cacheTime.push_back(lastTime); + } + + // add positions and velocities for these times + for (int i = 0; i < (int) p_cacheTime.size(); i++) { + // x,y,z positions + std::vector time; + time.push_back(p_cacheTime[i] - p_baseTime); + p_coordinate[0] = function1.Evaluate(time); + p_coordinate[1] = function2.Evaluate(time); + p_coordinate[2] = function3.Evaluate(time); + p_cache.push_back(p_coordinate); + + // x,y,z velocities + p_velocity[0] = b1 + 2*c1*(p_cacheTime[i]-p_baseTime); + p_velocity[1] = b2 + 2*c2*(p_cacheTime[i]-p_baseTime); + p_velocity[2] = b3 + 2*c3*(p_cacheTime[i]-p_baseTime); + p_cacheVelocity.push_back(p_velocity); + } + } + else { + std::vector time; + time.push_back(p_cacheTime[0] - p_baseTime); + p_coordinate[0] = function1.Evaluate(time); + p_coordinate[1] = function2.Evaluate(time); + p_coordinate[2] = function3.Evaluate(time); + p_cache.push_back(p_coordinate); + p_velocity[0] = 0.; + p_velocity[1] = 0.; + p_velocity[2] = 0.; + p_cacheVelocity.push_back(p_velocity); + } + + double et = p_et; + p_et = -DBL_MAX; + SetEphemerisTime(et); + +/* std::cout << "After" << std::endl; + std::cout << " at time " << et << std::endl; + for (int i=0; i<3; i++) { + std::cout << p_coordinate[i] << std::endl; + }*/ + + return; + } + + + + /** Set the coefficients of a polynomial (parabola) fit to each + * of the components (X, Y, Z) of the position vector for the time period covered + * by the cache, component = a + bt + ct**2, where t = time - p_baseTime. + * + */ + void SpicePosition::SetPolynomial () { + int degree=2; + Isis::PolynomialUnivariate function1(degree); //!< Basis function fit to X + Isis::PolynomialUnivariate function2(degree); //!< Basis function fit to Y + Isis::PolynomialUnivariate function3(degree); //!< Basis function fit to Z + // + LeastSquares *fitX = new LeastSquares ( function1 ); + LeastSquares *fitY = new LeastSquares ( function2 ); + LeastSquares *fitZ = new LeastSquares ( function3 ); + + // Compute the base time + ComputeBaseTime (); + std::vector time; + std::vector XC,YC,ZC; + + if (p_cache.size() == 1) { + double t = p_cacheTime.at(0); + SetEphemerisTime( t ); + XC.push_back(p_coordinate[0]); + XC.push_back(0.0); + XC.push_back(0.0); + YC.push_back(p_coordinate[1]); + YC.push_back(0.0); + YC.push_back(0.0); + ZC.push_back(p_coordinate[2]); + ZC.push_back(0.0); + ZC.push_back(0.0); + } + else if (p_cache.size() == 2) { +// Load the times and get the corresponding coordinates + double t1 = p_cacheTime.at(0); + SetEphemerisTime( t1 ); + std::vector coord1 = p_coordinate; + t1 -= p_baseTime; + double t2 = p_cacheTime.at(1); + SetEphemerisTime( t2 ); + std::vector coord2 = p_coordinate; + t2 -= p_baseTime; + double slope[3]; + double intercept[3]; + +// Compute the linear equation for each coordinate and save them + for (int cIndex=0; cIndex < 3; cIndex++) { + Isis::LineEquation posline(t1, coord1[cIndex], t2, coord2[cIndex]); + slope[cIndex] = posline.Slope(); + intercept[cIndex] = posline.Intercept(); + } + XC.push_back(intercept[0]); + XC.push_back(slope[0]); + XC.push_back(0.0); + YC.push_back(intercept[1]); + YC.push_back(slope[1]); + YC.push_back(0.0); + ZC.push_back(intercept[2]); + ZC.push_back(slope[2]); + ZC.push_back(0.0); + } + else { + // Load the known values to compute the fit equation + + for (std::vector::size_type pos=0;pos < p_cacheTime.size();pos++) { + double t = p_cacheTime.at(pos); + time.push_back( t - p_baseTime ); + SetEphemerisTime( t ); + std::vector coord = p_coordinate; + + fitX->AddKnown ( time, coord[0] ); + fitY->AddKnown ( time, coord[1] ); + fitZ->AddKnown ( time, coord[2] ); + time.clear(); + } + //Solve the equations for the coefficients + fitX->Solve(); + fitY->Solve(); + fitZ->Solve(); + + // Delete the least squares objects now that we have all the coefficients + delete fitX; + delete fitY; + delete fitZ; + + // For now assume all three coordinates are fit to a parabola. Later they may + // each be fit to a unique basis function. + // Fill the coefficient vectors + + for ( int i = 0; i < function1.Coefficients(); i++) { + XC.push_back( function1.Coefficient( i ) ); + YC.push_back( function2.Coefficient( i ) ); + ZC.push_back( function3.Coefficient( i ) ); + } + + } + + // Now that the coefficients have been calculated set the polynomial with them + SetPolynomial ( XC, YC, ZC ); + return; + } + + + + /** Set the coefficients of a polynomial (parabola) fit to + * each of the three coordinates of the position vector for the + * time period covered by the cache, coord = a + bt + ct**2, + * where t = time - p_baseTime. + * + * @param [in] XC Coefficients of fit to X coordinate + * @param [in] YC Coefficients of fit to Y coordinate + * @param [in] ZC Coefficients of fit to Z coordinate + * + */ + void SpicePosition::SetPolynomial ( const std::vector& XC, + const std::vector& YC, + const std::vector& ZC ) { + Isis::PolynomialUnivariate function1( 2 ); + Isis::PolynomialUnivariate function2( 2 ); + Isis::PolynomialUnivariate function3( 2 ); + + // Load the functions with the coefficients + function1.SetCoefficients ( XC ); + function2.SetCoefficients ( YC ); + function3.SetCoefficients ( ZC ); + + // Compute the base time + ComputeBaseTime (); + + +// std::cout << "Basetime=" << p_baseTime << std::endl; + + // Reload the cache from the functions and the currently cached time + ReloadCache ( function1, function2, function3 ); + + // Save the current coefficients + p_coefficients[0] = XC; + +// std::cout << "Saved coef0="<& XC, + std::vector& YC, + std::vector& ZC ) { + XC = p_coefficients[0]; + YC = p_coefficients[1]; + ZC = p_coefficients[2]; + + return; + } + + + + //! Compute the base time using cached times + void SpicePosition::ComputeBaseTime () { + if (p_noOverride) { + p_baseTime = (p_cacheTime.at(0) + p_cacheTime.at(p_cacheTime.size()-1))/ 2.; + } + else { + p_baseTime = p_overrideBaseTime; + } + return; + } + + + /** + * Set an override base time to be used with observations on scanners to allow all + * images in an observation to use the save base time and polynomials for the positions. + * + * @param [in] baseTime The baseTime to use and override the computed base time + */ + void SpicePosition::SetOverrideBaseTime( double baseTime ) { + p_overrideBaseTime = baseTime; + p_noOverride = false; + return; + } + + + + /** Set the coefficients of a polynomial (parabola) fit to each of the + * three coordinates of the position vector for the time period covered by the cache, + * coordinate = A + B*t + C*t**2, where t = time - p_basetime. + * + * @param partialVar Variable output derivative vector is to be with respect to + * @return Derivative of j2000 vector calculated with polynomial + * with respect to partialVar + * + */ + std::vector SpicePosition::CoordinatePartial( SpicePosition::PartialType partialVar, int coeffIndex) { + // Start with a zero vector since the derivative of the other coordinates with + // respect to the partial var will be 0. + std::vector coordinate(3,0); + + // Get the index of the coordinate to update with the partial derivative + int coordIndex = partialVar; + + if (coeffIndex > 2) { + std::string msg = "SpicePosition only supports up to a 2nd order fit for the spacecraft position"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Reset the coordinate to its derivative + coordinate[coordIndex] = DPolynomial ( (Coefficient) coeffIndex ); + return coordinate; + } + + + + /** Compute the derivative of the velocity with respect to the specified variable. The + * velocity is the derivative of the coordinate with respect to time + * coordinate = A + B*t + C*t**2, where t = time - p_basetime. + * velocity = B + 2*C*t + * partial(velocity) with respect to A = 0. + * partial(velocity) with respect to B = 1. + * partial(velocity) with respect to C = 2*t. + * + * @param partialVar Variable output derivative vector is to be with respect to + * @return Derivative of j2000 velocity vector calculated with respect + * to partialVar + * + */ + std::vector SpicePosition::VelocityPartial( SpicePosition::PartialType partialVar, int coeffIndex ) { + // Start with a zero vector since the derivative of the other coordinates with + // respect to the partial var will be 0. + std::vector dvelocity(3,0); + + // Get the index of the coordinate to update with the partial derivative + int coordIndex = partialVar; + + double time = p_et - p_baseTime; + double derivative = 0.; + + // Reset the velocity coordinate to its derivative + switch (coeffIndex) { + case A: + break; + case B: + derivative = 1.; + case C: + derivative *= 2.*time; + break; + } + dvelocity[coordIndex] = derivative; + return dvelocity; + } + + + /** + * Evaluate the derivative of the fit polynomial (parabola) defined by the + * given coefficients with respect to the coefficient at the given index, at + * the current time. + * + * @param coeffIndex Index of coefficient to differentiate with respect + * to + * @return The derivative evaluated at the current time + * + */ + double SpicePosition::DPolynomial ( const Coefficient coeffIndex ) { + double derivative=1.; + double time = p_et - p_baseTime; + +// std::cout << "coeff index = " << coeffIndex << std::endl; + + switch (coeffIndex) { + case C: + derivative = time; + case B: + derivative *= time; + case A: + derivative *= 1.; + break; + } + return derivative; + } + + /** Return the velocity vector if available. + * + * @return The velocity vector evaluated at the current time + */ + const std::vector &SpicePosition::Velocity() { + if (p_hasVelocity) { + return p_velocity; + } + else { + std::string msg = "No velocity vector available"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + + + + /** + * This is a protected method that is called by + * SetEphemerisTime() when Source type is Memcache. It + * calculates J2000 coordinates (x,y,z) of the body that + * correspond to a given et in seconds. These coordinates are + * obtained from an internal cache loaded from an ISIS Table + * object. + * @see SetEphemerisTime() + * @internal + * @history 2009-08-03 Jeannie Walldren - Original version + * (moved code from SetEphemerisTime() to its own + * method) + */ + void SpicePosition::SetEphemerisTimeMemcache() { + // If the cache has only one position return it + if (p_cache.size() == 1) { + p_coordinate[0] = p_cache[0][0]; + p_coordinate[1] = p_cache[0][1]; + p_coordinate[2] = p_cache[0][2]; + + if (p_hasVelocity) { + p_velocity[0] = p_cacheVelocity[0][0]; + p_velocity[1] = p_cacheVelocity[0][1]; + p_velocity[2] = p_cacheVelocity[0][2]; + } + } + + else { + // Otherwise determine the interval to interpolate + std::vector::iterator pos; + pos = upper_bound(p_cacheTime.begin(),p_cacheTime.end(),p_et); + + int cacheIndex; + if (pos != p_cacheTime.end()) { + cacheIndex = distance(p_cacheTime.begin(),pos); + cacheIndex--; + } + else { + cacheIndex = p_cacheTime.size() - 2; + } + + if (cacheIndex < 0) cacheIndex = 0; + + // Interpolate the coordinate + double mult = (p_et - p_cacheTime[cacheIndex]) / + (p_cacheTime[cacheIndex+1] - p_cacheTime[cacheIndex]); + std::vector p2 = p_cache[cacheIndex+1]; + std::vector p1 = p_cache[cacheIndex]; + + p_coordinate[0] = (p2[0] - p1[0]) * mult + p1[0]; + p_coordinate[1] = (p2[1] - p1[1]) * mult + p1[1]; + p_coordinate[2] = (p2[2] - p1[2]) * mult + p1[2]; + + if (p_hasVelocity) { + p2 = p_cacheVelocity[cacheIndex+1]; + p1 = p_cacheVelocity[cacheIndex]; + p_velocity[0] = (p2[0] - p1[0]) * mult + p1[0]; + p_velocity[1] = (p2[1] - p1[1]) * mult + p1[1]; + p_velocity[2] = (p2[2] - p1[2]) * mult + p1[2]; + } + } + } + + + + /** + * This is a protected method that is called by + * SetEphemerisTime() when Source type is HermiteCache. It + * calculates J2000 coordinates (x,y,z) of the body that + * correspond to a given et in seconds. These coordinates are + * obtained by using a Hermite spline to interpolate values from + * an internal reduced cache loaded from an ISIS Table object. + * @see SetEphemerisTime() + * @internal + * @history 2009-08-03 Jeannie Walldren - Original version + */ + void SpicePosition::SetEphemerisTimeHermiteCache() { + + // what if framing camera??? + + ComputeBaseTime(); + + NumericalApproximation xhermite(NumericalApproximation::CubicHermite); + NumericalApproximation yhermite(NumericalApproximation::CubicHermite); + NumericalApproximation zhermite(NumericalApproximation::CubicHermite); + + for (unsigned int i = 0; i < p_cache.size(); i++) { + xhermite.AddData(p_cacheTime[i]-p_baseTime, p_cache[i][0]); // add time, x-position to x spline + yhermite.AddData(p_cacheTime[i]-p_baseTime, p_cache[i][1]); // add time, y-position to y spline + zhermite.AddData(p_cacheTime[i]-p_baseTime, p_cache[i][2]); // add time, z-position to z spline + + if (p_hasVelocity) { // Line scan camera + xhermite.AddCubicHermiteDeriv(p_cacheVelocity[i][0]); // add x-velocity to x spline + yhermite.AddCubicHermiteDeriv(p_cacheVelocity[i][1]); // add y-velocity to y spline + zhermite.AddCubicHermiteDeriv(p_cacheVelocity[i][2]); // add z-velocity to z spline + } + else { // Not line scan camera + throw iException::Message(iException::Io, "No velcities available.", _FILEINFO_); + // xhermite.AddCubicHermiteDeriv(0.0); // spacecraft didn't move => velocity = 0 + // yhermite.AddCubicHermiteDeriv(0.0); // spacecraft didn't move => velocity = 0 + // zhermite.AddCubicHermiteDeriv(0.0); // spacecraft didn't move => velocity = 0 + } + } + // Next line added 07/13/2009 to prevent Camera unit test from bombing because time is outside domain. DAC + // Also added etype to Evaluate calls + NumericalApproximation::ExtrapType etype=NumericalApproximation::Extrapolate; + p_coordinate[0] = xhermite.Evaluate(p_et-p_baseTime, etype); + p_coordinate[1] = yhermite.Evaluate(p_et-p_baseTime, etype); + p_coordinate[2] = zhermite.Evaluate(p_et-p_baseTime, etype); + + p_velocity[0] = xhermite.EvaluateCubicHermiteFirstDeriv(p_et-p_baseTime); + p_velocity[1] = yhermite.EvaluateCubicHermiteFirstDeriv(p_et-p_baseTime); + p_velocity[2] = zhermite.EvaluateCubicHermiteFirstDeriv(p_et-p_baseTime); + } + + /** + * This is a protected method that is called by + * SetEphemerisTime() when Source type is Spice. It + * calculates J2000 coordinates (x,y,z) of the body that + * correspond to a given et in seconds. The coordinates are + * obtained from a valid NAIF spk kernel. The SPK kernel must + * contain positions for the body code specified in the + * constructor at the given time and it must be loaded using the + * SpiceKernel class. + * @see SetEphemerisTime() + * @internal + * @history 2009-08-03 Jeannie Walldren - Original version + * (moved code from SetEphemerisTime() to its own + * method) + */ + void SpicePosition::SetEphemerisTimeSpice() { + // Read from the kernel + SpiceDouble j[6], lt; + // First try getting the entire state (including the velocity vector) + spkez_c ((SpiceInt)p_targetCode, + (SpiceDouble)(p_et + p_timeBias), + "J2000", + p_aberrationCorrection.c_str(), + (SpiceInt)p_observerCode, + j, + <); + // If Naif fails attempting to get the entire state, assume the velocity vector is + // not available and just get the position. First turn off Naif error reporting and + // return any error without printing them. + SpiceBoolean spfailure = failed_c(); + reset_c(); // Reset Naif error system to allow caller to recover + if ( !spfailure ) { + p_velocity[0] = j[3]; + p_velocity[1] = j[4]; + p_velocity[2] = j[5]; + p_hasVelocity = true; + } + else { + spkezp_c ((SpiceInt)p_targetCode, + (SpiceDouble)(p_et + p_timeBias), + "J2000", + p_aberrationCorrection.c_str(), + (SpiceInt)p_observerCode, + j, + <); + } + p_coordinate[0] = j[0]; + p_coordinate[1] = j[1]; + p_coordinate[2] = j[2]; + } + + + /** + * This method reduces the cache for position, time and velocity + * to the minimum number of values needed to interpolate the + * J2000 coordinates using a Hermite spline, given a tolerance + * of deviation from the NAIF values. + * + * @param tolerance Maximum error allowed between NAIF kernel + * coordinate values and values interpolated by + * the Hermite spline. + * @internal + * @history 2009-08-03 Jeannie Walldren - Original version. + */ + void SpicePosition::Memcache2HermiteCache(double tolerance){ + if (p_source == HermiteCache) { + return; + } + else if(p_source != Memcache) { + throw iException::Message(iException::Programmer, + "Source type is not Memcache, cannot convert.", + _FILEINFO_); + } + + // make sure base time is set before it is needed + ComputeBaseTime(); + + // find current size of cache + int n = p_cacheTime.size()-1; + + // create 3 starting values for the new table + vector inputIndices; + inputIndices.push_back(0); + inputIndices.push_back(n/2); + inputIndices.push_back(n); + + // find all indices needed to make a hermite table within the appropriate tolerance + vector indexList = HermiteIndices(tolerance,inputIndices); + + // remove all lines from cache vectors that are not in the index list???? + for (int i = n; i >= 0; i--) { + if (!binary_search(indexList.begin(),indexList.end(),i)) { + p_cache.erase(p_cache.begin()+i); + p_cacheTime.erase(p_cacheTime.begin()+i); + p_cacheVelocity.erase(p_cacheVelocity.begin()+i); + } + } + + p_source = HermiteCache; + } + + /** + * This method is called by Memcache2HermiteCache() to determine + * which indices from the orginal cache should be saved in the + * reduced cache. It is a recursive method that starts with an + * index list of 3 elements (first, center and last index + * values) and adds values to this list if the tolerance is not + * met. + * + * @param tolerance Maximum error allowed between NAIF kernel + * coordinate values and values interpolated by + * the Hermite spline. + * @param indexList Vector containing the list of indices to be + * kept in the cache. This list grows as the + * method is recursively called + * @return vector/ Vector containing final list + * of indices that will be kept for the Hermite cache. + * @internal + * @history 2009-08-03 Jeannie Walldren - Original version. + * @history 2009-08-14 Debbie A. Cook - Corrected indexing + * error in loop. + */ + vector SpicePosition::HermiteIndices(double tolerance, vector indexList){ + + unsigned int n = indexList.size(); + + NumericalApproximation xhermite(NumericalApproximation::CubicHermite); + NumericalApproximation yhermite(NumericalApproximation::CubicHermite); + NumericalApproximation zhermite(NumericalApproximation::CubicHermite); + for (unsigned int i = 0; i < indexList.size(); i++) { + xhermite.AddData(p_cacheTime[indexList[i]]-p_baseTime, p_cache[indexList[i]][0]); // add time, x-position to x spline + yhermite.AddData(p_cacheTime[indexList[i]]-p_baseTime, p_cache[indexList[i]][1]); // add time, y-position to y spline + zhermite.AddData(p_cacheTime[indexList[i]]-p_baseTime, p_cache[indexList[i]][2]); // add time, z-position to z spline + + if (p_hasVelocity) { // Line scan camera + xhermite.AddCubicHermiteDeriv(p_cacheVelocity[i][0]); // add x-velocity to x spline + yhermite.AddCubicHermiteDeriv(p_cacheVelocity[i][1]); // add y-velocity to y spline + zhermite.AddCubicHermiteDeriv(p_cacheVelocity[i][2]); // add z-velocity to z spline + } + else { // Not line scan camera + throw iException::Message(iException::Io, "No velcities available.", _FILEINFO_); + // xhermite.AddCubicHermiteDeriv(0.0); // spacecraft didn't move => velocity = 0 + // yhermite.AddCubicHermiteDeriv(0.0); // spacecraft didn't move => velocity = 0 + // zhermite.AddCubicHermiteDeriv(0.0); // spacecraft didn't move => velocity = 0 + } + } + + // loop through the saved indices from the end + for(unsigned int i = indexList.size()-1; i > 0; i--) { + double xerror = 0; + double yerror = 0; + double zerror = 0; + + // check every value of the original kernel values within interval + for (int line = indexList[i-1]+1; line < indexList[i]; line++) { + + // find the errors at each value + xerror = fabs(xhermite.Evaluate(p_cacheTime[line]-p_baseTime) - p_cache[line][0]); + yerror = fabs(yhermite.Evaluate(p_cacheTime[line]-p_baseTime) - p_cache[line][1]); + zerror = fabs(zhermite.Evaluate(p_cacheTime[line]-p_baseTime) - p_cache[line][2]); + + if (xerror > tolerance || yerror > tolerance || zerror > tolerance) { + // if any error is greater than tolerance, no need to continue looking, break + break; + } + } + + if (xerror < tolerance && yerror < tolerance && zerror < tolerance) { + // if errors are less than tolerance after looping interval, no new point is necessary + continue; + } + else { + // if any error is greater than tolerance, add midpoint of interval to indexList vector + indexList.push_back((indexList[i]+indexList[i-1])/2); + } + } + + if (indexList.size() > n) { + sort(indexList.begin(), indexList.end()); + indexList = HermiteIndices(tolerance,indexList); + } + return indexList; + } + + + /** Cache J2000 position over existing cached time range using + * table + * + * This method will reload an internal cache with positions + * formed from coordinates in a table + * + * @param table An ISIS table blob containing valid J2000 + * coordinate/time values. + * @internal + * @history 2009-08-03 Jeannie Walldren - Original version. + */ + void SpicePosition::ReloadCache(Table &table) { + p_source = Spice; + p_cacheTime.clear(); + p_cache.clear(); + p_cacheVelocity.clear(); + LoadCache(table); + } +} + + + + + + diff --git a/isis/src/base/objs/SpicePosition/SpicePosition.h b/isis/src/base/objs/SpicePosition/SpicePosition.h new file mode 100644 index 0000000000000000000000000000000000000000..2f469acd6b562164c330195d2c8ab338e54be454 --- /dev/null +++ b/isis/src/base/objs/SpicePosition/SpicePosition.h @@ -0,0 +1,206 @@ +#ifndef SpicePosition_h +#define SpicePosition_h +/** + * @file + * $Revision: 1.17 $ + * $Date: 2010/03/27 07:01:33 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Table.h" +#include "PolynomialUnivariate.h" +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" + +namespace Isis { + /** + * @brief Obtain SPICE position information for a body + * + * This class will obtain the J2000 body position between a target and + * observer body. For example, a spacecraft and Mars or the Sun and Mars. + * It is essentially a C++ wrapper to the NAIF spkez_c routine. Therefore, + * appropriate NAIF kernels are expected to be loaded prior to using this + * class. The position can be returned with or without one way light time + * corrections between the two bodies. See + * NAIF required reading for more information regarding this subject + * at + * ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/ascii/individual_docs/spk.req + *

    + * An important functionality of this class is the ability to cache the + * positions so they do not have to be constantly read from the NAIF kernels. + * Onced the data is cached the NAIF kernels can be unloaded too. + * + * @code + * + * @endcode + * + * @ingroup SpiceInstrumentsAndCameras + * + * @author 2005-12-01 Jeff Anderson + * + * @internal + * @history 2003-12-01 Jeff Anderson Original Version derived from Spice + * class + * @history 2006-03-23 Jeff Anderson Added check to SetEphemeris to return + * if the time did not change. Should speed up line + * scan cameras + * @history 2007-07-10 Debbie A. Cook Added else to method SetAberrationCorrection + * to separate error section from the rest of the code + * @history 2007-08-24 Debbie A. Cook Added members p_coefficients, enums PartialType and Coefficient, + * and methods ReloadCache, SetPolynomial, GetPolynomial, ComputeBaseTime, + * DPolynomial, and CoordinatePartial to support solving for instrument position + * in BundleAdjust + * @history 2008-01-10 Debbie A. Cook The function was changed from Parabola to Poly1D. New methods + * GetBaseTime and SetOverrideBaseTime were added + * @history 2008-02-07 Jeannie Walldren Poly1D was changed to + * PolynomialUnivariate + * @history 2008-02-10 Debbie A. Cook Removed the (-1.) in case A of DPolynomial since it was + * not actually part of the position derivation but how it was being applied + * in BundleAdjust. + * @history 2008-06-18 Steven Lambright Fixed documentation + * @history 2008-06-25 Debbie A. Cook Added members p_velocity, p_cacheVelocity, + * and p_hasVelocity; also added methods Velocity() and HasVelocity() + * to support miniRF. + * @history 2008-06-26 Debbie A. Cook Replaced Naif error handling calls with Isis NaifStatus + * @history 2009-08-03 Jeannie Walldren - Added methods + * ReloadCache( table ), HermiteIndices(), + * Memcache2HermiteCache() to allow for + * downsized instrument position tables in + * labels of Isis cubes and added methods + * SetEphemerisTimeSpice(), + * SetEphemerisTimeHermiteCache(), and + * SetEphemerisTimeMemcache() to make + * software more readable. + * @history 2009-08-14 Debbie A. Cook - Corrected loop counter in HermiteIndices + * @history 2009-08-27 Jeannie Walldren - Added documentation. + * @history 2009-10-20 Debbie A. Cook - Corrected calculation of extremum in ReloadCache + * @history 2009-11-06 Debbie A. Cook - Added velocity partial derivative method + * @history 2009-12-15 Debbie A. Cook - Changed enumerated partial types and argument list for + * CoordinatePartial and VelocityPartial + * @history 2010-03-19 Debbie A. Cook - Added argument coeffIndex to method Velocity Partial + */ + class SpicePosition { + public: + SpicePosition(int targetCode, int observerCode); + + //! Destructor + virtual ~SpicePosition() {} + + void SetTimeBias (double timeBias); + void SetAberrationCorrection(const std::string &correction); + const std::vector &SetEphemerisTime(double et); + + +// enum PartialType {WRT_X0,WRT_X1,WRT_X2, +// WRT_Y0,WRT_Y1,WRT_Y2, +// WRT_Z0,WRT_Z1,WRT_Z2}; + enum PartialType {WRT_X,WRT_Y,WRT_Z}; + + + enum Coefficient { A, B, C }; + + //! Return the current ephemeris time + double EphemerisTime() const { return p_et; }; + + //! Return the current J2000 position + const std::vector &Coordinate() { return p_coordinate; }; + + //! Return the current J2000 velocity + const std::vector &Velocity(); + + //! Return the flag indicating whether the velocity exists + bool HasVelocity() { return p_hasVelocity; }; + + void LoadCache (double startTime, double endTime, int size); + void LoadCache (double time); + void LoadCache(Table &table); + void ReloadCache( Isis::PolynomialUnivariate &function1,Isis::PolynomialUnivariate &function2, + Isis::PolynomialUnivariate &function3); + void ReloadCache(Table &table); + + Table Cache(const std::string &tableName); + + //! Is this position cached + bool IsCached() const { return (p_cache.size() > 0); }; + + void SetPolynomial (); + + void SetPolynomial ( const std::vector& XC, + const std::vector& YC, + const std::vector& ZC ); + + void GetPolynomial ( std::vector& XC, + std::vector& YC, + std::vector& ZC ); + + void ComputeBaseTime (); + + //! Return the base time for the position + double GetBaseTime (){ return p_baseTime; }; + + void SetOverrideBaseTime ( double baseTime ); + + double DPolynomial ( const Coefficient coeffIndex ); + + std::vector CoordinatePartial( SpicePosition::PartialType partialVar, int coeffIndex ); + + std::vector VelocityPartial( SpicePosition::PartialType partialVar, int coeffIndex ); + + + //??? jw + /** + * This enum defines indicates the status of the object + */ + enum Source { Spice, //!< Object is reading directly from the kernels + Memcache, //!< Object is reading from cached table + HermiteCache //!< Object is reading from splined table + }; + void Memcache2HermiteCache(double tolerance); + protected: + void SetEphemerisTimeMemcache(); + void SetEphemerisTimeHermiteCache(); + void SetEphemerisTimeSpice(); + std::vector HermiteIndices(double tol, std::vector indexList); + + private: + int p_targetCode; //!< target body code + int p_observerCode; //!< observer body code + + double p_timeBias; //!< iTime bias when reading kernels + std::string p_aberrationCorrection; //!< Light time correction to apply + + double p_et; //!< Current ephemeris time + std::vector p_coordinate; //!< J2000 position at time et + std::vector p_velocity; //!< J2000 velocity at time et + + Source p_source; //!< Enumerated value for the location of the SPK information used + std::vector p_cacheTime; //!< iTime for corresponding position + std::vector > p_cache; //!< Cached positions + std::vector > p_cacheVelocity; //!< Cached velocities + std::vector p_coefficients[3]; //!< Coefficients of polynomials + double p_baseTime; //!< Base time used in fit equations + bool p_noOverride; //!< Flag to compute base time; + double p_overrideBaseTime; //!< Value set by caller to override computed base time + bool p_hasVelocity; //!< Flag to indicate velocity is available + }; +}; + +#endif diff --git a/isis/src/base/objs/SpicePosition/SpicePosition.truth b/isis/src/base/objs/SpicePosition/SpicePosition.truth new file mode 100644 index 0000000000000000000000000000000000000000..e2f3dcc9dcc1803c2082140ac46b811e831754fb --- /dev/null +++ b/isis/src/base/objs/SpicePosition/SpicePosition.truth @@ -0,0 +1,97 @@ +Unit test for SpicePosition +Testing without cache ... +Time = -69382819 +Spacecraft (J) = -1730.464601 -1562.215688 2691.280624 +Velocity (J) = -4.141683634 1.195372416 -1.958384021 +Time = -69382784.89 +Spacecraft (J) = -1870.766044 -1520.58502 2623.001225 +Velocity (J) = -4.083714021 1.24528122 -2.044584389 +Time = -69382750.78 +Spacecraft (J) = -2009.015184 -1477.276745 2551.822536 +Velocity (J) = -4.021395321 1.293703278 -2.128322937 +Time = -69382716.67 +Spacecraft (J) = -2145.068141 -1432.34464 2477.833706 +Velocity (J) = -3.954994597 1.340460405 -2.209300597 +Time = -69382682.56 +Spacecraft (J) = -2278.790672 -1385.848421 2401.133655 +Velocity (J) = -3.88481023 1.385383116 -2.287243672 +Time = -69382648.44 +Spacecraft (J) = -2410.059194 -1337.853331 2321.830213 +Velocity (J) = -3.811167392 1.428318377 -2.361901801 +Time = -69382614.33 +Spacecraft (J) = -2538.76166 -1288.429473 2240.039565 +Velocity (J) = -3.734420243 1.469134372 -2.433033832 +Time = -69382580.22 +Spacecraft (J) = -2664.798937 -1237.651037 2155.885821 +Velocity (J) = -3.654974188 1.507725018 -2.500423366 +Time = -69382546.11 +Spacecraft (J) = -2788.086449 -1185.595221 2069.499369 +Velocity (J) = -3.573269593 1.544021413 -2.563924669 +Time = -69382512 +Spacecraft (J) = -2908.554485 -1132.340941 1981.014192 +Velocity (J) = -3.489730566 1.577989894 -2.623468911 + +Testing with cache ... +Time = -69382819 +Spacecraft (J) = -1730.464601 -1562.215688 2691.280624 +Velocity (J) = -4.141683634 1.195372416 -1.958384021 +Time = -69382784.89 +Spacecraft (J) = -1870.766044 -1520.58502 2623.001225 +Velocity (J) = -4.083714021 1.24528122 -2.044584389 +Time = -69382750.78 +Spacecraft (J) = -2009.015184 -1477.276745 2551.822536 +Velocity (J) = -4.021395321 1.293703278 -2.128322937 +Time = -69382716.67 +Spacecraft (J) = -2145.068141 -1432.34464 2477.833706 +Velocity (J) = -3.954994597 1.340460405 -2.209300597 +Time = -69382682.56 +Spacecraft (J) = -2278.790672 -1385.848421 2401.133655 +Velocity (J) = -3.88481023 1.385383116 -2.287243672 +Time = -69382648.44 +Spacecraft (J) = -2410.059194 -1337.853331 2321.830213 +Velocity (J) = -3.811167392 1.428318377 -2.361901801 +Time = -69382614.33 +Spacecraft (J) = -2538.76166 -1288.429473 2240.039565 +Velocity (J) = -3.734420243 1.469134372 -2.433033832 +Time = -69382580.22 +Spacecraft (J) = -2664.798937 -1237.651037 2155.885821 +Velocity (J) = -3.654974188 1.507725018 -2.500423366 +Time = -69382546.11 +Spacecraft (J) = -2788.086449 -1185.595221 2069.499369 +Velocity (J) = -3.573269593 1.544021413 -2.563924669 +Time = -69382512 +Spacecraft (J) = -2908.554485 -1132.340941 1981.014192 +Velocity (J) = -3.489730566 1.577989894 -2.623468911 + +Testing tables ... +Time = -69382819 +Spacecraft (J) = -1730.464601 -1562.215688 2691.280624 +Velocity (J) = -4.141683634 1.195372416 -1.958384021 +Time = -69382784.89 +Spacecraft (J) = -1870.766044 -1520.58502 2623.001225 +Velocity (J) = -4.083714021 1.24528122 -2.044584389 +Time = -69382750.78 +Spacecraft (J) = -2009.015184 -1477.276745 2551.822536 +Velocity (J) = -4.021395321 1.293703278 -2.128322937 +Time = -69382716.67 +Spacecraft (J) = -2145.068141 -1432.34464 2477.833706 +Velocity (J) = -3.954994597 1.340460405 -2.209300597 +Time = -69382682.56 +Spacecraft (J) = -2278.790672 -1385.848421 2401.133655 +Velocity (J) = -3.88481023 1.385383116 -2.287243672 +Time = -69382648.44 +Spacecraft (J) = -2410.059194 -1337.853331 2321.830213 +Velocity (J) = -3.811167392 1.428318377 -2.361901801 +Time = -69382614.33 +Spacecraft (J) = -2538.76166 -1288.429473 2240.039565 +Velocity (J) = -3.734420243 1.469134372 -2.433033832 +Time = -69382580.22 +Spacecraft (J) = -2664.798937 -1237.651037 2155.885821 +Velocity (J) = -3.654974188 1.507725018 -2.500423366 +Time = -69382546.11 +Spacecraft (J) = -2788.086449 -1185.595221 2069.499369 +Velocity (J) = -3.573269593 1.544021413 -2.563924669 +Time = -69382512 +Spacecraft (J) = -2908.554485 -1132.340941 1981.014192 +Velocity (J) = -3.489730566 1.577989894 -2.623468911 + diff --git a/isis/src/base/objs/SpicePosition/unitTest.cpp b/isis/src/base/objs/SpicePosition/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4f68c4f95dd76a2f407fe551f915549c80a3d58c --- /dev/null +++ b/isis/src/base/objs/SpicePosition/unitTest.cpp @@ -0,0 +1,72 @@ +#include +#include +#include "SpicePosition.h" +#include "Filename.h" +#include "Preference.h" +#include "Table.h" + +using namespace std; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << setprecision(10); + cout << "Unit test for SpicePosition" << endl; + + Isis::Filename f("$base/testData/kernels"); + string dir = f.Expanded() + "/"; + string moc(dir+"moc.bsp"); + string de(dir+"de405.bsp"); + string pck(dir+"pck00006.tpc"); + furnsh_c(moc.c_str()); + furnsh_c(de.c_str()); + furnsh_c(pck.c_str()); + + double startTime = -69382819.0; + double endTime = -69382512.0; + double slope = (endTime - startTime) / (10 - 1); + + Isis::SpicePosition pos(-94,499); + + // Normal testing (no cache) + cout << "Testing without cache ... " << endl; + for (int i=0; i<10; i++) { + double t = startTime + (double) i * slope; + vector p = pos.SetEphemerisTime(t); + vector v = pos.Velocity(); + cout << "Time = " << pos.EphemerisTime() << endl; + cout << "Spacecraft (J) = " << p[0] << " " << p[1] << " " << p[2] << endl; + cout << "Velocity (J) = " << v[0] << " " << v[1] << " " << v[2] << endl; + } + cout << endl; + + + // Testing with cache + cout << "Testing with cache ... " << endl; + pos.LoadCache(startTime,endTime,10); + for (int i=0; i<10; i++) { + double t = startTime + (double) i * slope; + vector p = pos.SetEphemerisTime(t); + vector v = pos.Velocity(); + cout << "Time = " << pos.EphemerisTime() << endl; + cout << "Spacecraft (J) = " << p[0] << " " << p[1] << " " << p[2] << endl; + cout << "Velocity (J) = " << v[0] << " " << v[1] << " " << v[2] << endl; + } + cout << endl; + + // Test table options + cout << "Testing tables ... " << endl; + Isis::Table tab = pos.Cache("Test"); + Isis::SpicePosition pos2(-94,499); + pos2.LoadCache(tab); + for (int i=0; i<10; i++) { + double t = startTime + (double) i * slope; + pos2.SetEphemerisTime(t); + vector p = pos2.Coordinate(); + vector v = pos2.Velocity(); + cout << "Time = " << pos2.EphemerisTime() << endl; + cout << "Spacecraft (J) = " << p[0] << " " << p[1] << " " << p[2] << endl; + cout << "Velocity (J) = " << v[0] << " " << v[1] << " " << v[2] << endl; + } + cout << endl; +} diff --git a/isis/src/base/objs/SpiceRotation/Makefile b/isis/src/base/objs/SpiceRotation/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..029735a92d2205c5f197ef136aae4c8b51ff96ac --- /dev/null +++ b/isis/src/base/objs/SpiceRotation/Makefile @@ -0,0 +1,5 @@ +INCS = SpiceRotation.h +SRCS = SpiceRotation.cpp ck3sdn.cpp qmini.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/SpiceRotation/SpiceRotation.cpp b/isis/src/base/objs/SpiceRotation/SpiceRotation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..686f30744d4fdc15db7a314d5933f797ae6d9b1c --- /dev/null +++ b/isis/src/base/objs/SpiceRotation/SpiceRotation.cpp @@ -0,0 +1,1817 @@ +#include +#include +#include +#include + +#include +#include + +#include "SpiceRotation.h" +#include "Quaternion.h" +#include "LineEquation.h" +#include "BasisFunction.h" +#include "LeastSquares.h" +#include "BasisFunction.h" +#include "PolynomialUnivariate.h" +#include "iString.h" +#include "iException.h" +#include "Table.h" +#include "NaifStatus.h" + +// Declarations for bindings for Naif Spicelib routines that do not have +// a wrapper +extern int refchg_(integer *frame1, integer *frame2, doublereal *et, + doublereal *rotate); +extern int frmchg_(integer *frame1, integer *frame2, doublereal *et, + doublereal *rotate); +extern int invstm_(doublereal *mat, doublereal *invmat); +// Temporary declarations for bindings for Naif supportlib routines +// These three declarations should be removed once supportlib is in Isis3 +extern int ck3sdn(double sdntol, bool avflag, int *nrec, + double *sclkdp, double *quats, double *avvs, + int nints, double *starts, double *dparr, + int *intarr); + +namespace Isis { + /** + * Construct an empty SpiceRotation class using a valid Naif frame code to + * set up for getting rotation from Spice kernels. See required reading + * ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/ascii/individual_docs/naif_ids.req + * + * @param frameCode Valid naif frame code. + */ + SpiceRotation::SpiceRotation( int frameCode ) { + p_constantFrames.push_back(frameCode); + p_timeBias = 0.0; + p_source = Spice; + p_CJ.resize(9); + p_matrixSet = false; + p_et = -DBL_MAX; + p_degree = 2; + p_degreeApplied = false; + p_noOverride = true; + p_axis1 = 3; + p_axis2 = 1; + p_axis3 = 3; + p_minimizeCache = No; + p_hasAngularVelocity = false; + p_av.resize(3); + p_fullCacheStartTime = 0; + p_fullCacheEndTime = 0; + p_fullCacheSize = 0; + } + + /** + * Construct an empty SpiceRotation class using valid Naif frame code and. + * body code to set up for computing nadir rotation. See required reading + * ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/ascii/individual_docs/naif_ids.req + * + * @param frameCode Valid naif frame code. + * @param targetCode Valid naif body code. + */ + SpiceRotation::SpiceRotation( int frameCode, int targetCode ) { + NaifStatus::CheckErrors(); + + p_constantFrames.push_back(frameCode); + p_targetCode = targetCode; + p_timeBias = 0.0; + p_source = Nadir; + p_CJ.resize(9); + p_matrixSet = false; + p_et = -DBL_MAX; + p_axisP = 3; + p_degree = 2; + p_degreeApplied = false; + p_noOverride = true; + p_axis1 = 3; + p_axis2 = 1; + p_axis3 = 3; + p_minimizeCache = No; + p_hasAngularVelocity = false; + p_av.resize(3); + p_fullCacheStartTime = 0; + p_fullCacheEndTime = 0; + p_fullCacheSize = 0; + + // Determine the axis for the velocity vector + std::string key = "INS" + Isis::iString(frameCode) + "_TRANSX"; + SpiceDouble transX[2]; + SpiceInt number; + SpiceBoolean found; + //Read starting at element 1 (skipping element 0) + gdpool_c ( key.c_str(), 1, 2, &number, transX, &found ); + + if (!found) { + std::string msg = "Cannot find [" + key + "] in text kernels"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + p_axisV = 2; + if (transX[0] < transX[1]) p_axisV = 1; + + NaifStatus::CheckErrors(); + } + + /** Apply a time bias when invoking SetEphemerisTime method. + * + * The bias is used only when reading from NAIF kernels. It is added to the + * ephermeris time passed into SetEphemerisTime and then the body + * position is read from the NAIF kernels and returned. When the cache + * is loaded from + * a table the bias is ignored as it is assumed to have already been + * applied. If this method is never called the default bias is 0.0 + * seconds. + * + * @param timeBias time bias in seconds + */ + void SpiceRotation::SetTimeBias (double timeBias) { + p_timeBias = timeBias; + } + + /** Return the J2000 to reference frame quaternion at given time. + * + * This method returns the J2000 to reference frame rotational matrix at a + * given et in seconds. The quaternion is obtained from either valid NAIF ck + * and/or fk, or alternatively from an internal cache loaded from an ISIS + * Table object. In the first case, the kernels must contain the rotation + * for the frame specified in the constructor at the given time (as well as + * all the intermediate frames going from the reference frame to J2000) and + * they must be loaded using the SpiceKernel class. + * + * @param et ephemeris time in seconds + */ + void SpiceRotation::SetEphemerisTime(double et) { + NaifStatus::CheckErrors(); + + // Save the time + if (p_et == et) return; + p_et = et; + + SpiceInt j2000 = J2000Code; + + // Read from the cache + if (p_source == Memcache) { + // If the cache has only one position set it + if (p_cache.size() == 1) { +/* p_quaternion = p_cache[0];*/ + p_CJ = p_cache[0]; +// p_CJ = p_quaternion.ToMatrix(); + if (p_hasAngularVelocity) { + p_av = p_cacheAv[0]; + } + } + + else { + // Otherwise determine the interval to interpolate + std::vector::iterator pos; + pos = upper_bound(p_cacheTime.begin(),p_cacheTime.end(),p_et); + + int cacheIndex; + if (pos != p_cacheTime.end()) { + cacheIndex = distance(p_cacheTime.begin(),pos); + cacheIndex--; + } else { + cacheIndex = p_cacheTime.size() - 2; + } + + if (cacheIndex < 0) cacheIndex = 0; + +// Interpolate the rotation + double mult = (p_et - p_cacheTime[cacheIndex]) / + (p_cacheTime[cacheIndex+1] - p_cacheTime[cacheIndex]); +/* Quaternion Q2 (p_cache[cacheIndex+1]); + Quaternion Q1 (p_cache[cacheIndex]);*/ + std::vector CJ2( p_cache[cacheIndex+1] ); + std::vector CJ1 (p_cache[cacheIndex] ); + SpiceDouble J2J1[3][3]; + mtxm_c ((SpiceDouble (*)[3]) &CJ2[0], (SpiceDouble (*)[3]) &CJ1[0], J2J1); + SpiceDouble axis[3]; + SpiceDouble angle; + raxisa_c (J2J1, axis, &angle); + SpiceDouble delta[3][3]; + axisar_c (axis, angle*(SpiceDouble)mult, delta); + mxmt_c ( (SpiceDouble *) &CJ1[0], delta, (SpiceDouble (*) [3]) &p_CJ[0] ); + if (p_hasAngularVelocity) { + double v1[3],v2[3]; // Vectors surrounding desired time + vequ_c((SpiceDouble *) &p_cacheAv[cacheIndex][0], v1); + vequ_c((SpiceDouble *) &p_cacheAv[cacheIndex+1][0], v2); + vscl_c((1. - mult), v1, v1); + vscl_c(mult, v2, v2); + vadd_c(v1, v2, (SpiceDouble *) &p_av[0]); + } + } + } + + // Apply coefficients defining a function for each of the three camera angles and angular velocity if available + else if (p_source == Function) { + Isis::PolynomialUnivariate function1( p_degree ); + Isis::PolynomialUnivariate function2( p_degree ); + Isis::PolynomialUnivariate function3( p_degree ); + + // Load the functions with the coefficients + function1.SetCoefficients ( p_coefficients[0] ); + function2.SetCoefficients ( p_coefficients[1] ); + function3.SetCoefficients ( p_coefficients[2] ); + + std::vector rtime; + rtime.push_back((et - p_baseTime) / p_timeScale); + double angle1 = function1.Evaluate (rtime); + double angle2 = function2.Evaluate (rtime); + double angle3 = function3.Evaluate (rtime); + + // Get the first angle back into the range Naif expects [180.,180.] + if (angle1 < -1*pi_c() ) { + angle1 += twopi_c(); + } + else if (angle1 > pi_c()) { + angle1 -= twopi_c(); + } + + eul2m_c ( (SpiceDouble) angle3, (SpiceDouble) angle2, (SpiceDouble) angle1, + p_axis3, p_axis2, p_axis1, + (SpiceDouble (*)[3]) &p_CJ[0]); + + if (p_hasAngularVelocity) { + ComputeAv(); + } + } + // Read from the kernel + else if (p_source == Spice) { + // Retrieve the J2000 (code=1) to reference rotation matrix + SpiceDouble time = p_et + p_timeBias; + + // Make sure the constant frame is loaded. This method also does the frame trace. + if (p_timeFrames.size() == 0) InitConstantRotation ( et ); + int toFrame = p_timeFrames[0]; + + // First try getting the entire state matrix (6x6), which includes CJ and the angular velocity + double stateCJ[6][6]; + frmchg_ ( (integer *) &j2000, (integer *) &toFrame, &time, (doublereal *) stateCJ ); + + // If Naif fails attempting to get the state matrix, assume the angular velocity vector is + // not available and just get the rotation matrix. First turn off Naif error reporting and + // return any error without printing them. + SpiceBoolean ckfailure = failed_c(); + reset_c(); // Reset Naif error system to allow caller to recover + + if ( !ckfailure ) { + xpose6_c ( stateCJ, stateCJ ); + xf2rav_c ( stateCJ, (SpiceDouble (*)[3]) &p_CJ[0], (SpiceDouble *) &p_av[0] ); + p_hasAngularVelocity = true; + } + else { + refchg_ ( (integer *) &j2000, (integer *) &toFrame, &time, (SpiceDouble *) &p_CJ[0] ); + + if ( failed_c() ) { + char naifstr[64]; + getmsg_c ("SHORT", sizeof(naifstr), naifstr); + reset_c(); // Reset Naif error system to allow caller to recover + + if ( eqstr_c( naifstr, "SPICE(UNKNOWNFRAME)" )) { + Isis::iString msg = Isis::iString( (int) p_constantFrames[0]) + " is an unrecognized " + + "reference frame code. Has the mission frames kernel been loaded?"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + else { + Isis::iString msg = "No pointing available at requested time [" + + Isis::iString(p_et+p_timeBias) + "] for frame code [" + + Isis::iString( (int) p_constantFrames[0]) + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + + // Transpose to obtain row-major order + xpose_c ( (SpiceDouble (*)[3]) &p_CJ[0], (SpiceDouble (*)[3]) &p_CJ[0]); + } + } + + // Compute from Nadir + else { + // TODO what about spk time bias and mission setting of light time corrections + // That information has only been passed to the SpicePosition class and + // is not available to this class, but probably should be applied to the + // spkez call. + + // Make sure the constant frame is loaded. This method also does the frame trace. + if (p_timeFrames.size() == 0) InitConstantRotation ( et ); + + SpiceDouble stateJ[6]; // Position and velocity vector in J2000 + SpiceDouble lt; + SpiceInt spkCode = p_constantFrames[0] / 1000; + spkez_c ( (SpiceInt) spkCode, p_et, "J2000", "LT+S", + (SpiceInt) p_targetCode, stateJ, < ); + // reverse the position to be relative to the spacecraft. This may be + // a mission dependent value and possibly the sense of the velocity as well. + SpiceDouble sJ[3],svJ[3]; + vpack_c ( -1*stateJ[0], -1*stateJ[1], -1*stateJ[2], sJ); + vpack_c ( stateJ[3], stateJ[4], stateJ[5], svJ); + twovec_c ( sJ, + p_axisP, + svJ, + p_axisV, + (SpiceDouble (*)[3]) &p_CJ[0]); + } + + + // Set the quaternion for this rotation + // p_quaternion.Set ( p_CJ ); + NaifStatus::CheckErrors(); + } + + /** Cache J2000 rotation quaternion over a time range. + * + * This method will load an internal cache with frames over a time + * range. This prevents the NAIF kernels from being read over-and-over + * again and slowing an application down due to I/O performance. Once the + * cache has been loaded then the kernels can be unloaded from the NAIF + * system. + * + * @param startTime Starting ephemeris time in seconds for the cache + * @param endTime Ending ephemeris time in seconds for the cache + * @param size Number of frames to keep in the cache + * + */ + void SpiceRotation::LoadCache (double startTime, double endTime, int size) { + + // Check for valid arguments + if (size <= 0) { + std::string msg = "Argument cacheSize must not be less or equal to zero"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (startTime > endTime) { + std::string msg = "Argument startTime must be less than or equal to endTime"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if ((startTime != endTime) && (size == 1)) { + std::string msg = "Cache size must be more than 1 if startTime endTime differ"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Make sure cache isn't already loaded + if (p_source == Memcache) { + std::string msg = "A SpiceRotation cache has already been created"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Save full cache parameters + p_fullCacheStartTime = startTime; + p_fullCacheEndTime = endTime; + p_fullCacheSize = size; + + // Make sure the constant frame is loaded. This method also does the frame trace. + if (p_timeFrames.size() == 0) InitConstantRotation ( startTime ); + + LoadTimeCache(); + int cacheSize = p_cacheTime.size(); + + // Loop and load the cache + for (int i=0; i 5) { + LoadTimeCache(); + } + } + + + /** Cache J2000 to frame rotation for a time. + * + * This method will load an internal cache with a rotation for a single + * time (e.g. useful for framing cameras). This prevents + * the NAIF kernels from being read over-and-over again and slowing a + * application down due to I/O performance. Once the + * cache has been loaded then the kernels can be unloaded from the NAIF + * system. This calls the LoadCache(stime,etime,size) method using the + * time as both the starting and ending time with a size of 1. + * + * @param time single ephemeris time in seconds to cache + * + */ + void SpiceRotation::LoadCache (double time) { + LoadCache(time,time,1); + } + + /** Cache J2000 rotations using a table file. + * + * This method will load either an internal cache with rotations (quaternions) + * or coefficients (for 3 polynomials defining the camera angles) from an + * ISIS table file. In the first case, the table must have 5 columns and + * at least one row. The 5 columns contain the following information, J2000 + * to reference quaternion (q0, q1, q2, q3) and the ephemeris time of that + * position. If there are multiple rows, it is assumed the quaternions between + * the rows can be interpolated. In the second case, the table must have + * three columns and at least two rows. The three columns contain the + * coefficients for each of the three camera angles. Row one of the + * table contains coefficient 0 (constant term) for angles 1, 2, and 3. + * If the degree of the fit equation is greater than 1, row 2 contains + * coefficient 1 (linear) for each of the three angles. Row n contains + * coefficient n-1 and the last row contains the time parameters, base time, + * and time scale, and the degree of the polynomial. + * + * @param table An ISIS table blob containing valid J2000 to reference + * quaternion/time values + */ + void SpiceRotation::LoadCache(Table &table) { + // Make sure cache isn't already loaded + if (p_source == Memcache || p_source == Function) { + std::string msg = "A SpiceRotation cache has already been created"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Load the constant and time-based frame traces and the constant rotation + if ( table.Label().HasKeyword("TimeDependentFrames") ) { + PvlKeyword labelTimeFrames = table.Label()["TimeDependentFrames"]; + for (int i=0; i j2000Quat; + j2000Quat.push_back((double)rec[0]); + j2000Quat.push_back((double)rec[1]); + j2000Quat.push_back((double)rec[2]); + j2000Quat.push_back((double)rec[3]); + + Quaternion q(j2000Quat); + std::vector CJ = q.ToMatrix(); + p_cache.push_back(CJ); + p_cacheTime.push_back((double)rec[4]); + } + p_source = Memcache; + } + + // list table of quaternion, angular velocity vector, and time + else if (recFields == 8) { + for (int r=0; r j2000Quat; + j2000Quat.push_back((double)rec[0]); + j2000Quat.push_back((double)rec[1]); + j2000Quat.push_back((double)rec[2]); + j2000Quat.push_back((double)rec[3]); + + + Quaternion q(j2000Quat); + std::vector CJ = q.ToMatrix(); + p_cache.push_back(CJ); + + std::vector av; + av.push_back ((double)rec[4]); + av.push_back ((double)rec[5]); + av.push_back ((double)rec[6]); + p_cacheAv.push_back(av); + + p_cacheTime.push_back((double)rec[7]); + p_hasAngularVelocity = true; + } + p_source = Memcache; + } + + // coefficient table for angle1, angle2, and angle3 + else if (recFields == 3) { + std::vector coeffAng1,coeffAng2,coeffAng3; + + for (int r=0; r::size_type pos=0;pos < p_cacheTime.size();pos++) { + p_et = p_cacheTime.at(pos); + SetEphemerisTime ( p_et ); + p_cache.push_back( p_CJ ); + p_cacheAv.push_back( p_av ); + } + + // Set source to cache and reset current et + p_source = Memcache; + p_et = -DBL_MAX; + SetEphemerisTime(et); + + NaifStatus::CheckErrors(); + } + + + + /** Return a table with J2000 to reference rotations. + * + * Return a table containing the cached pointing with the given + * name. The table will have eight columns, quaternio, angular + * velocity, and time of J2000 to reference frame rotation. + * + * @param tableName Name of the table to create and return + */ + Table SpiceRotation::LineCache(const std::string &tableName) { + + // Apply the function and fill the caches + if (p_source == Function) ReloadCache(); + + if (p_source != Memcache) { + std::string msg = "Only cached rotations can be returned as a line cache of quaternions and time"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + // Load the table and return it to caller + return Cache ( tableName ); + } + + + + /** Return a table with J2000 to reference rotations. + * + * Return a table containing the cached pointing with the given + * name. The table will have either five columns (for a list cache) + * of J2000 to reference quaternions and times, eight columns (if + * angular velocity is available), or three columns + * (for a coefficient cache), of J2000 to reference frame rotation + * angles defined by coefficients of a polynomial function (see + * SetPolynommial). In the coefficient cache the last row of + * the table is the base time, time scale, and polynomial degree. + * Note: In the case of the coefficient cache, the angular + * velocity is not written to the table since it can be calculated + * from the polynomials. + * + * @param tableName Name of the table to create and return + */ + Table SpiceRotation::Cache(const std::string &tableName) { + + // Load the list of rotations and their corresponding times + if (p_source == Memcache) { + TableField q0("J2000Q0",TableField::Double); + TableField q1("J2000Q1",TableField::Double); + TableField q2("J2000Q2",TableField::Double); + TableField q3("J2000Q3",TableField::Double); + TableField t("ET",TableField::Double); + + TableRecord record; + record += q0; + record += q1; + record += q2; + record += q3; + int timePos = 4; + + if (p_hasAngularVelocity) { + TableField av1("AV1",TableField::Double); + TableField av2("AV2",TableField::Double); + TableField av3("AV3",TableField::Double); + record += av1; + record += av2; + record += av3; + timePos = 7; + } + + record += t; + Table table(tableName,record); + + for (int i=0; i<(int)p_cache.size(); i++) { + Quaternion q(p_cache[i]); + std::vector v = q.GetQuaternion(); + record[0] = v[0]; + record[1] = v[1]; + record[2] = v[2]; + record[3] = v[3]; + + if (p_hasAngularVelocity) { + record[4] = p_cacheAv[i][0]; + record[5] = p_cacheAv[i][1]; + record[6] = p_cacheAv[i][2]; + } + + record[timePos] = p_cacheTime[i]; + table += record; + } + CacheLabel(table); + return table; + } + // Load the coefficients for the curves fit to the 3 camera angles + else if (p_source == Function) { + TableField angle1("J2000Ang1",TableField::Double); + TableField angle2("J2000Ang2",TableField::Double); + TableField angle3("J2000Ang3",TableField::Double); + + TableRecord record; + record += angle1; + record += angle2; + record += angle3; + + Table table(tableName,record); + + for (int cindex=0; cindex 1 ) { + table.Label() += PvlKeyword( "TimeDependentFrames"); + + for (int i=0; i<(int) p_timeFrames.size(); i++) { + table.Label()["TimeDependentFrames"].AddValue(p_timeFrames[i]); + } + } + + if ( p_constantFrames.size() > 1 ) { + table.Label() += PvlKeyword( "ConstantFrames"); + + for (int i=0; i<(int) p_constantFrames.size(); i++) { + table.Label()["ConstantFrames"].AddValue(p_constantFrames[i]); + } + + table.Label() += PvlKeyword("ConstantRotation"); + + for (int i=0; i<(int) p_TC.size(); i++) { + table.Label()["ConstantRotation"].AddValue(p_TC[i]); + } + } + + // Write original time coverage + if (p_fullCacheStartTime != 0) { + table.Label() += PvlKeyword( "CkTableStartTime"); + table.Label()["CkTableStartTime"].AddValue(p_fullCacheStartTime); + } + if (p_fullCacheEndTime != 0) { + table.Label() += PvlKeyword( "CkTableEndTime"); + table.Label()["CkTableEndTime"].AddValue(p_fullCacheEndTime); + } + if (p_fullCacheSize != 0) { + table.Label() += PvlKeyword( "CkTableOriginalSize"); + table.Label()["CkTableOriginalSize"].AddValue(p_fullCacheSize); + } + } + + + /** Return the camera angles (right ascension, declination, and twist) for + * + * the time-based matrix CJ + * + */ + std::vector SpiceRotation::Angles( int axis3, int axis2, int axis1 ) + { + NaifStatus::CheckErrors(); + + SpiceDouble ang1,ang2,ang3; + m2eul_c ((SpiceDouble *) &p_CJ[0],axis3, axis2, axis1, &ang3,&ang2, &ang1 ); + + std::vector angles; + angles.push_back(ang1); + angles.push_back(ang2); + angles.push_back(ang3); + + NaifStatus::CheckErrors(); + return angles; + } + + /** Given a direction vector in the reference frame, return a J2000 direction. + * + * @param [in] rVec A direction vector in the reference frame + * + * @return (vector) A direction vector in J2000 frame + */ + std::vector SpiceRotation::J2000Vector( const std::vector& rVec) { + NaifStatus::CheckErrors(); + + std::vector jVec; + + if (rVec.size() == 3) { + double TJ[3][3]; + mxm_c( (SpiceDouble *) &p_TC[0], (SpiceDouble *) &p_CJ[0], TJ); + jVec.resize(3); + mtxv_c( TJ, (SpiceDouble *) &rVec[0], (SpiceDouble *) &jVec[0]); + } + else if (rVec.size() == 6) { + // See Naif routine frmchg for the format of the state matrix. The constant rotation, TC, + // has a derivative with respect to time of I. + if (!p_hasAngularVelocity) { + // throw an error + } + std::vector stateTJ(36); + stateTJ = StateTJ(); + + // Now invert (inverse of a state matrix is NOT simply the transpose) + xpose6_c ( &stateTJ[0], (SpiceDouble (*) [6]) &stateTJ[0] ); + double stateJT[6][6]; + invstm_ ((doublereal *) &stateTJ[0], (doublereal *) stateJT); + xpose6_c ( stateJT, stateJT ); + jVec.resize(6); + + mxvg_c( stateJT, (SpiceDouble *) &rVec[0], 6, 6, (SpiceDouble *) &jVec[0]); + } + + NaifStatus::CheckErrors(); + return ( jVec ); + } + + + /** Given a direction vector in J2000, return a reference frame direction. + * + * @param [in] jVec A direction vector in J2000 + * + * @return (vector) A direction vector in reference + * frame + */ + std::vector + SpiceRotation::ReferenceVector( const std::vector& jVec ) { + NaifStatus::CheckErrors(); + + std::vector rVec(3); + + if (jVec.size() == 3) { + double TJ[3][3]; + mxm_c( (SpiceDouble *) &p_TC[0], (SpiceDouble *) &p_CJ[0], TJ); + rVec.resize(3); + mxv_c ( TJ, (SpiceDouble *) &jVec[0], (SpiceDouble *) &rVec[0] ); + } + else if (jVec.size() == 6) { + // See Naif routine frmchg for the format of the state matrix. The constant rotation, TC, + // has a derivative with respect to time of I. + if (!p_hasAngularVelocity) { + // throw an error + } + std::vector stateTJ(36); + stateTJ = StateTJ(); + rVec.resize(6); + mxvg_c( (SpiceDouble *) &stateTJ[0], (SpiceDouble *) &jVec[0], 6, 6, (SpiceDouble *) &rVec[0]); + } + + NaifStatus::CheckErrors(); + return ( rVec ); + } + + + /** Set the coefficients of a polynomial fit to each + * of the three camera angles for the time period covered by the + * cache, angle = a + bt + ct**2, where t = (time - p_baseTime)/ p_timeScale. + * + */ + void SpiceRotation::SetPolynomial () { + + // Rotation is already stored as a polynomial -- throw an error + if (p_source == Function) { + // Nothing to do + return; +// std::string msg = "Rotation already fit to a polynomial -- spiceint first to refit"; +// throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + Isis::PolynomialUnivariate function1(p_degree); //!< Basis function fit to 1st rotation angle + Isis::PolynomialUnivariate function2(p_degree); //!< Basis function fit to 2nd rotation angle + Isis::PolynomialUnivariate function3(p_degree); //!< Basis function fit to 3rd rotation angle + // + LeastSquares *fitAng1 = new LeastSquares ( function1 ); + LeastSquares *fitAng2 = new LeastSquares ( function2 ); + LeastSquares *fitAng3 = new LeastSquares ( function3 ); + + // Compute the base time + ComputeBaseTime (); + std::vector time; + std::vector coeffAng1,coeffAng2,coeffAng3; + + if (p_cache.size() == 1) { + p_degree = 0; + double t = p_cacheTime.at(0); + SetEphemerisTime( t ); + std::vector angles = Angles ( p_axis3, p_axis2, p_axis1); + coeffAng1.push_back(angles[0]); + coeffAng2.push_back(angles[1]); + coeffAng3.push_back(angles[2]); + } + else if (p_cache.size() == 2) { +// Load the times and get the corresponding rotation angles + p_degree = 1; + double t1 = p_cacheTime.at(0); + SetEphemerisTime( t1 ); + t1 -= p_baseTime; + t1 = t1/p_timeScale; + std::vector angles1 = Angles ( p_axis3, p_axis2, p_axis1); + double t2 = p_cacheTime.at(1); + SetEphemerisTime( t2 ); + t2 -= p_baseTime; + t2 = t2/p_timeScale; + std::vector angles2 = Angles ( p_axis3, p_axis2, p_axis1 ); + angles2[0] = WrapAngle ( angles1[0], angles2[0]); + angles2[2] = WrapAngle ( angles1[2], angles2[2]); + double slope[3]; + double intercept[3]; + +// Compute the linear equation for each angle and save them + for (int angleIndex=0; angleIndex < 3; angleIndex++) { + Isis::LineEquation angline(t1, angles1[angleIndex], t2, angles2[angleIndex]); + slope[angleIndex] = angline.Slope(); + intercept[angleIndex] = angline.Intercept(); + } + coeffAng1.push_back(intercept[0]); + coeffAng1.push_back(slope[0]); + coeffAng2.push_back(intercept[1]); + coeffAng2.push_back(slope[1]); + coeffAng3.push_back(intercept[2]); + coeffAng3.push_back(slope[2]); + } + else { + // Load the known values to compute the fit equation + double start1=0.; // value of 1st angle1 in cache + double start3=0.; // value of 1st angle1 in cache + + for (std::vector::size_type pos=0;pos < p_cacheTime.size();pos++) { + double t = p_cacheTime.at(pos); + time.push_back( (t - p_baseTime) / p_timeScale ); + SetEphemerisTime( t ); + std::vector angles = Angles ( p_axis3, p_axis2, p_axis1); + +// Fix 180/-180 crossovers on angles 1 and 3 before doing fit. + if (pos == 0) { + start1 = angles[0]; + start3 = angles[2]; + } + else { + angles[0] = WrapAngle ( start1, angles[0]); + angles[2] = WrapAngle ( start3, angles[2]); + } + + fitAng1->AddKnown ( time, angles[0] ); + fitAng2->AddKnown ( time, angles[1] ); + fitAng3->AddKnown ( time, angles[2] ); + time.clear(); + + } + //Solve the equations for the coefficients + fitAng1->Solve(); + fitAng2->Solve(); + fitAng3->Solve(); + + // Delete the least squares objects now that we have all the coefficients + delete fitAng1; + delete fitAng2; + delete fitAng3; + + // For now assume all three angles are fit to a polynomial. Later they may + // each be fit to a unique basis function. + // Fill the coefficient vectors + + for ( int i = 0; i < function1.Coefficients(); i++) { + coeffAng1.push_back( function1.Coefficient( i ) ); + coeffAng2.push_back( function2.Coefficient( i ) ); + coeffAng3.push_back( function3.Coefficient( i ) ); + } + + } + + // Now that the coefficients have been calculated set the polynomial with them + SetPolynomial ( coeffAng1, coeffAng2, coeffAng3 ); + + return; + } + + + + /** Set the coefficients of a polynomial fit to each of the + * three camera angles for the time period covered by the + * cache, angle = c0 + c1*t + c2*t**2 + ... + cn*t**n, + * where t = (time - p_baseTime) / p_timeScale, and n = p_degree. + * + * @param [in] coeffAng1 Coefficients of fit to Angle 1 + * @param [in] coeffAng2 Coefficients of fit to Angle 2 + * @param [in] coeffAng3 Coefficients of fit to Angle 3 + * + */ + void SpiceRotation::SetPolynomial ( const std::vector& coeffAng1, + const std::vector& coeffAng2, + const std::vector& coeffAng3 ) { + + Isis::PolynomialUnivariate function1( p_degree ); + Isis::PolynomialUnivariate function2( p_degree ); + Isis::PolynomialUnivariate function3( p_degree ); + + // Load the functions with the coefficients + function1.SetCoefficients ( coeffAng1 ); + function2.SetCoefficients ( coeffAng2 ); + function3.SetCoefficients ( coeffAng3 ); + + // Compute the base time + ComputeBaseTime (); + + // Save the current coefficients + p_coefficients[0] = coeffAng1; + p_coefficients[1] = coeffAng2; + p_coefficients[2] = coeffAng3; + + // Set the flag indicating p_degree has been applied to the camera angles, the + // coefficients of the polynomials have been saved, and the cache reloaded from + // the polynomials + p_degreeApplied = true; + p_source = Function; + + // Update the current rotation + double et = p_et; + p_et = -DBL_MAX; + SetEphemerisTime(et); + + return; + } + + + + /** + * Return the coefficients of a polynomial fit to each of the + * three camera angles for the time period covered by the cache, angle = + * c0 + c1*t + c2*t**2 + ... + cn*t**n, where t = (time - p_basetime) / p_timeScale + * and n = p_degree. + * + * @param [out] coeffAng1 Coefficients of fit to Angle 1 + * @param [out] coeffAng2 Coefficients of fit to Angle 2 + * @param [out] coeffAng3 Coefficients of fit to Angle 3 + * + */ + void SpiceRotation::GetPolynomial ( std::vector& coeffAng1, + std::vector& coeffAng2, + std::vector& coeffAng3 ) { + coeffAng1 = p_coefficients[0]; + coeffAng2 = p_coefficients[1]; + coeffAng3 = p_coefficients[2]; + + return; + } + + + + //! Compute the base time using cached times + void SpiceRotation::ComputeBaseTime () { + if (p_noOverride) { + p_baseTime = (p_cacheTime.at(0) + p_cacheTime.at(p_cacheTime.size()-1))/ 2.; + p_timeScale = p_baseTime - p_cacheTime.at(0); + // Take care of case where 1st and last times are the same + if (p_timeScale == 0) p_timeScale = 1.0; + } + else { + p_baseTime = p_overrideBaseTime; + p_timeScale = p_overrideTimeScale; + } + + return; + } + + + /** + * Set an override base time to be used with observations on scanners to allow all + * images in an observation to use the save base time and polynomials for the angles. + * + * @param [in] baseTime The baseTime to use and override the computed base time + */ + void SpiceRotation::SetOverrideBaseTime( double baseTime, double timeScale ) { + p_overrideBaseTime = baseTime; + p_overrideTimeScale = timeScale; + p_noOverride = false; + return; + } + + + + /** + * Evaluate the derivative of the fit polynomial defined by the + * given coefficients with respect to the coefficient at the given index, at + * the current time. + * + * @param coeffIndex The index of the coefficient to differentiate + * @return The derivative evaluated at the current time + * + */ + double SpiceRotation::DPolynomial ( const int coeffIndex ) { + double derivative; + double time = (p_et - p_baseTime) / p_timeScale; + + if (coeffIndex > 0 && coeffIndex <= p_degree) { + derivative = pow(time, coeffIndex); + } + else if (coeffIndex == 0) { + derivative = 1; + } + else { + Isis::iString msg = "Coeff index, " + Isis::iString(coeffIndex) + " exceeds degree of polynomial"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return derivative; + } + + + + /** Compute the derivative with respect to one of the coefficients in the + * angle polynomial fit equation of a vector rotated from J2000 to a + * reference frame. The polynomial equation is of the form + * angle = c0 + c1*t + c2*t**2 + ... cn*t**n, where t = (time - p_basetime) / p_timeScale + * and n = p_degree (the degree of the equation) + * + * @param [in] lookJ Look vector in J2000 frame + * @param [in] partialVar Variable derivative is to be with respect to + * @param [in] coeffIndex Coefficient index in the polynomial fit to the variable (angle) + * @return Vector rotated by derivative of J2000 to + * reference rotation + * + */ + std::vector + SpiceRotation::ToReferencePartial(std::vector& lookJ, + SpiceRotation::PartialType partialVar, int coeffIndex) { + NaifStatus::CheckErrors(); + //**TODO** To save time possibly save partial matrices + + // Get the rotation angles and form the derivative matrix for the partialVar + std::vector angles = Angles ( p_axis3, p_axis2, p_axis1 ); + int angleIndex = partialVar; + int axes[3]={p_axis1,p_axis2,p_axis3}; + double angle = angles.at(angleIndex); + + double dmatrix[3][3]; + drotat_ (&angle, (integer *) axes+angleIndex, (doublereal *) dmatrix); + // Transpose to obtain row-major order + xpose_c ( dmatrix, dmatrix); + + // Get the derivative of the polynomial with respect to partialVar + + double dpoly = DPolynomial ( coeffIndex ); + + // Multiply dpoly to complete dmatrix + for ( int row = 0; row < 3; row++ ) { + for ( int col = 0; col < 3; col++ ) { + dmatrix[row][col] *= dpoly; + } + } + // Apply the other 2 angles and chain them all together + double dCJ[3][3]; + switch (angleIndex) { + case 0: + rotmat_c (dmatrix, angles[1], axes[1], dCJ ); + rotmat_c (dCJ, angles[2], axes[2], dCJ ); + break; + case 1: + rotate_c (angles[0], axes[0], dCJ); + mxm_c ( dmatrix, dCJ, dCJ ); + rotmat_c (dCJ, angles[2], axes[2], dCJ ); + break; + case 2: + rotate_c (angles[0], axes[0], dCJ); + rotmat_c (dCJ, angles[1], axes[1], dCJ ); + mxm_c ( dmatrix, dCJ, dCJ ); + break; + } + + // Multiply the constant matrix to rotate to target frame + double dTJ[3][3]; + mxm_c( (SpiceDouble *) &p_TC[0], dCJ[0], dTJ); + + // Finally rotate the J2000 vector with the derivative matrix, dTJ + std::vector lookdT(3); + + mxv_c ( dTJ, (const SpiceDouble *) &lookJ[0], (SpiceDouble *) &lookdT[0] ); + + NaifStatus::CheckErrors(); + return lookdT; + } + + + /** Wrap the input angle to keep it within 2pi radians of the + * angle to compare. + * + * @param [in] compareAngle Look vector in J2000 frame + * @param [in] angle Angle to be wrapped if needed + * @return double Wrapped angle + * + */ + double SpiceRotation::WrapAngle(double compareAngle, double angle) { + NaifStatus::CheckErrors(); + double diff1 = compareAngle - angle; + + if ( diff1 < -1*pi_c() ){ + angle -= twopi_c(); + } + else if (diff1 > pi_c() ) { + angle += twopi_c(); + } + + NaifStatus::CheckErrors(); + return angle; + } + + /** Set the degree of the polynomials to be fit to the + * three camera angles for the time period covered by the + * cache, angle = c0 + c1*t + c2*t**2 + ... + cn*t**n, + * where t = (time - p_baseTime) / p_timeScale, and n = p_degree. + * + * @param [in] degree Degree of the polynomial to be fit + * + */ + void SpiceRotation::SetPolynomialDegree( int degree) { + + // If polynomials have not been applied yet then simply set the degree and return + if (!p_degreeApplied) { + p_degree = degree; + } + + // Otherwise the existing polynomials need to be either expanded ... + else if (p_degree < degree) { // (increase the number of terms) + std::vector coefAngle1(p_coefficients[0]), + coefAngle2(p_coefficients[1]), + coefAngle3(p_coefficients[2]); + + for (int icoef = p_degree+1; icoef <= degree; icoef++) { + coefAngle1.push_back(0.); + coefAngle2.push_back(0.); + coefAngle3.push_back(0.); + } + p_degree = degree; + SetPolynomial (coefAngle1, coefAngle2, coefAngle3); + } + // ... or reduced (decrease the number of terms) + else if (p_degree > degree) { + std::vector coefAngle1(degree + 1), + coefAngle2(degree + 1), + coefAngle3(degree + 1); + + for (int icoef = 0; icoef <=degree; icoef++) { + coefAngle1.push_back(p_coefficients[0][icoef]); + coefAngle2.push_back(p_coefficients[1][icoef]); + coefAngle3.push_back(p_coefficients[2][icoef]); + } + SetPolynomial (coefAngle1, coefAngle2, coefAngle3); + p_degree = degree; + } + } + + + /** Set the axes of rotation for decomposition of a rotation + * matrix into 3 angles. + * + * @param [in] axis1 Axes of rotation of first angle applied (right rotation) + * @param [in] axis2 Axes of rotation of second angle applied (center rotation) + * @param [in] axis3 Axes of rotation of third angle applied (left rotation) + * @return double Wrapped angle + * + */ + void SpiceRotation::SetAxes(int axis1, int axis2, int axis3) { + if (axis1 < 1 || axis2 < 1 || axis3 < 1 || axis1 > 3 || axis2 > 3 || axis3 > 3) { + std::string msg = "A rotation axis is outside the valid range of 1 to 3"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + p_axis1 = axis1; + p_axis2 = axis2; + p_axis3 = axis3; + } + + /** Load the time cache. This method should works with the LoadCache(startTime, endTime, size) method + * to load the time cache. + * + */ + void SpiceRotation::LoadTimeCache() { + int count=0; + + double observStart = p_fullCacheStartTime + p_timeBias; + double observEnd = p_fullCacheEndTime + p_timeBias; + double currentTime = observStart; // Added 12-03-2009 to allow observations to cross segment boundaries + bool timeLoaded = false; + + // Get number of ck loaded for this rotation. This method assumes only one SpiceRotation + // object is loaded. + NaifStatus::CheckErrors(); + ktotal_c ("ck", (SpiceInt *) &count); + + // Downsize the loaded cache + if (p_source == Memcache && p_minimizeCache == Yes) { + // Multiple ck case and type 5 ck case final step -- downsize loaded cache and reload + + if (p_fullCacheSize != (int) p_cache.size()) { + + Isis::iString msg = "Full cache size does NOT match cache size in LoadTimeCache -- should never happen"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + SpiceDouble timeSclkdp[p_fullCacheSize]; + SpiceDouble quats[p_fullCacheSize][4]; + SpiceInt spcode = p_constantFrames[0]/1000; + double avvs[p_fullCacheSize][3];// Angular velocity vector + + for (int r=0; r av; + av.resize(3); + + for (int r=0; r CJ(9); + q2m_c (quats[r], (SpiceDouble (*)[3]) &CJ[0]); + p_cache.push_back(CJ); + vequ_c ( avvs[r], (SpiceDouble *) &av[0] ); + p_cacheAv.push_back( av ); + } + + timeLoaded = true; + p_minimizeCache = Done; + } + else if (count == 1 && p_minimizeCache == Yes) { + // case of a single ck -- read instances and data straight from kernel for given time range + SpiceInt handle; + + // Define some Naif constants + int FILESIZ = 128; + int TYPESIZ = 32; + int SOURCESIZ = 128; +// double DIRSIZ = 100; + + SpiceChar file[FILESIZ]; + SpiceChar filtyp[TYPESIZ]; + SpiceChar source[SOURCESIZ]; + + SpiceBoolean found; + bool observationSpansToNextSegment = false; + + double segStartEt; + double segStopEt; + + kdata_c (0, "ck", FILESIZ, TYPESIZ, SOURCESIZ, file, filtyp, source, &handle, &found); + dafbfs_c ( handle ); + daffna_c ( &found ); + int spCode = ( (int) (p_constantFrames[0]/1000) ) * 1000; + + while ( found ) { + observationSpansToNextSegment = false; + double sum[10]; // daf segment summary + double dc[2]; // segment starting and ending times in tics + SpiceInt ic[6]; // segment summary values: + // instrument code for platform, + // reference frame code, + // data type, + // velocity flag, + // offset to quat 1, + // offset to end. + dafgs_c ( sum ); + dafus_c ( sum, (SpiceInt) 2, (SpiceInt) 6, dc, ic); + + // Don't read type 5 ck here + if (ic[2] == 5) break; + if (ic[2] != 3) { + std::string msg = "Time fetching method only works on type 3 and 5 ck"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + // Check times for type 3 ck segment if spacecraft matches + if (ic[0] == spCode) { + sct2e_c((int) spCode/1000, dc[0], &segStartEt); + sct2e_c((int) spCode/1000, dc[1], &segStopEt); + NaifStatus::CheckErrors(); + double et; + + // Get times for this segment + if (currentTime >= segStartEt && currentTime <= segStopEt) { + + // Check for a gap in the time coverage by making sure the time span of the observation does not + // cross a segment unless the next segment starts where the current one ends + if (observationSpansToNextSegment && currentTime > segStartEt) { + std::string msg = "Observation crosses segment boundary--unable to interpolate pointing"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + if (observEnd > segStopEt) { + observationSpansToNextSegment = true; + } + + // Extract necessary header parameters + int dovelocity = ic[3]; + int end = ic[5]; + double val[2]; + dafgda_c (handle, end-1, end, val); +// int nints = (int) val[0]; + int ninstances = (int) val[1]; + int numvel = dovelocity * 3; + int quatnoff = ic[4] + (4 + numvel) * ninstances - 1; +// int nrdir = (int) (( ninstances - 1 ) / DIRSIZ); /* sclkdp directory records */ + int sclkdp1off = quatnoff + 1; + int sclkdpnoff = sclkdp1off + ninstances - 1; +// int start1off = sclkdpnoff + nrdir + 1; +// int startnoff = start1off + nints - 1; + int sclkSpCode = spCode/1000; + + // Now get the times + std::vector sclkdp(ninstances); + dafgda_c ( handle, sclkdp1off, sclkdpnoff, (SpiceDouble *) &sclkdp[0]); + + int instance = 0; + sct2e_c( sclkSpCode, sclkdp[0], &et); + + while (instance < (ninstances-1) && et < currentTime) { + instance++; + sct2e_c( sclkSpCode, sclkdp[instance], &et); + } + + if (instance > 0) instance--; + sct2e_c(sclkSpCode, sclkdp[instance], &et); + + while (instance < (ninstances-1) && et < observEnd) { + p_cacheTime.push_back(et-p_timeBias); + instance++; + sct2e_c(sclkSpCode, sclkdp[instance], &et); + } + p_cacheTime.push_back(et-p_timeBias); + + if (!observationSpansToNextSegment) { + timeLoaded = true; + p_minimizeCache = Done; + break; + } + else { + currentTime = segStopEt; + } + } + } + dafcs_c ( handle ); // Continue search in daf last searched + daffna_c ( &found ); // Find next forward array in current daf + } + } + else if (count == 0 && p_source != Nadir && p_minimizeCache == Yes) { + std::string msg = "No camera kernels loaded...Unable to determine time cache to downsize"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Load times according to cache size (body rotations) -- handle first round of type 5 ck case and multiple ck case -- + // Load a time for every line scan line and downsize later + if (!timeLoaded) { + double cacheSlope = 0.0; + if (p_fullCacheSize > 1) + cacheSlope = (p_fullCacheEndTime - p_fullCacheStartTime) / (double) (p_fullCacheSize - 1); + for (int i=0; i SpiceRotation::GetFullCacheTime() { + + // No time cache was initialized -- throw an error + if (p_fullCacheSize < 1) { + std::string msg = "Time cache not available -- rerun spiceinit"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + std::vector fullCacheTime; + double cacheSlope = 0.0; + if (p_fullCacheSize > 1) cacheSlope = (p_fullCacheEndTime - p_fullCacheStartTime) / (double) (p_fullCacheSize - 1); + + for (int i=0; i frameCodes; + std::vector frameTypes; + frameCodes.push_back(p_constantFrames[0]); + + while (frameCodes[frameCodes.size()-1] != J2000Code) { + frmidx = frameCodes.size() - 1; + // First get the frame type (Note:: we may also need to save center if we use dynamic frames) + frinfo_c ( (SpiceInt) frameCodes[frmidx], (SpiceInt *) ¢er,(SpiceInt *) &type,(SpiceInt *) &typid, &found ); + + if (!found) { + + if (p_source == Nadir) { + frameTypes.push_back(0); + break; + } + + std::string msg = "The frame" + iString((int) frameCodes[frmidx]) + " is not supported by Naif"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + double matrix[3][3]; + + // To get the next link in the frame chain, use the frame type + if ( type == INERTL || type == PCK) { + nextFrame = J2000Code; + } + else if ( type == CK ) { + ckfrot_ ( (SpiceInt *) &typid, &et, (double *) matrix, &nextFrame, (logical *) &found ); + + if (!found) { + + if (p_source == Nadir) { + frameTypes.push_back(0); + break; + } + + std::string msg = "The ck rotation from frame " + iString(frameCodes[frmidx]) + " can not be found" + + " due to no pointing available at requested time or a problem with the frame"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + else if ( type == TK ) { + tkfram_ ( (SpiceInt *) &typid, (double *) matrix, &nextFrame, (logical *) &found ); + if (!found) { + std::string msg = "The tk rotation from frame " + iString(frameCodes[frmidx]) + " can not be found"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + else if ( type == DYN ) { + // + // Unlike the other frame classes, the dynamic frame evaluation + // routine ZZDYNROT requires the input frame ID rather than the + // dynamic frame class ID. ZZDYNROT also requires the center ID + // we found via the FRINFO call. + + zzdynrot_ ( (SpiceInt *) &typid, (SpiceInt *) ¢er, &et, (double *) matrix, &nextFrame ); + } + + else { + std::string msg = "The frame " + iString(frameCodes[frmidx]) + + " has a type "+ iString(type) + " not supported by your version of Naif Spicelib." + + "You need to update."; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + + } + frameCodes.push_back(nextFrame); + frameTypes.push_back(type); + } + + if ((int) frameCodes.size() == 1 && p_source != Nadir) { // Must be Sky + p_constantFrames.push_back(frameCodes[0]); + p_timeFrames.push_back(frameCodes[0]); + return; + } + + int nConstants = 0; + p_constantFrames.clear(); + while ( frameTypes[nConstants] == TK && nConstants<(int) frameTypes.size() ) nConstants++; + + + for (int i=0; i<=nConstants; i++) { + p_constantFrames.push_back(frameCodes[i]); + } + + if (p_source != Nadir) { + for (int i=nConstants; i<(int) frameCodes.size(); i++) { + p_timeFrames.push_back(frameCodes[i]); + } + } + else { + // Nadir rotation is from spacecraft to J2000 + p_timeFrames.push_back(frameCodes[nConstants]); + p_timeFrames.push_back(J2000Code); + } + } + + + /** Return the full rotation TJ as a matrix + */ + std::vector SpiceRotation::Matrix() { + std::vector TJ; + TJ.resize(9); + mxm_c( (SpiceDouble *) &p_TC[0], (SpiceDouble *) &p_CJ[0], (SpiceDouble (*) [3]) &TJ[0] ); + return TJ; + } + + /** Return constant rotation TC as a quaternion + */ + std::vector SpiceRotation::ConstantRotation() { + std::vector q; + q.resize(4); + q2m_c((SpiceDouble (*)[3]) &p_TC[0], (SpiceDouble (*)[3]) &q[0]); + return q; + } + + /** Return time-based rotation CJ as a quaternion + */ + std::vector SpiceRotation::TimeBasedRotation() { + std::vector q; + q.resize(4); + q2m_c((SpiceDouble (*)[3]) &p_CJ[0], (SpiceDouble (*)[3] ) &q[0]); + return q; + } + + + /** Initialize the constant rotation + */ + void SpiceRotation::InitConstantRotation( double et ) { + FrameTrace( et ); + // Get constant rotation which applies in all cases + int targetFrame = p_constantFrames[0]; + int fromFrame = p_timeFrames[0]; + p_TC.resize(9); + refchg_ ( (SpiceInt *) &fromFrame, (SpiceInt *) &targetFrame, &et, (doublereal *) &p_TC[0] ); + // Transpose to obtain row-major order + xpose_c ( (SpiceDouble (*)[3]) &p_TC[0], (SpiceDouble (*)[3]) &p_TC[0]); + } + + + + /** Compute the angular velocity from the time-based functions fit to the pointing angles + * This method computes omega = angular velocity matrix, and extracts the angular velocity. + * See comments in the Naif Spicelib routine xf2rav_c.c. + * + * _ _ + * | | + * | 0 -av[2] av[1] | + * | | + * omega = | av[2] 0 -av[0] | + * | | + * | -av[1] av[0] 0 | + * |_ _| + + * + * + * + */ + void SpiceRotation::ComputeAv() { + NaifStatus::CheckErrors(); + + // Make sure the angles have been fit to polynomials + if (p_source != Function) { + std::string msg = "The SpiceRotation pointing angles must be fit to polynomials in order to compute angular velocity"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + std::vector dCJdt; + dCJdt.resize(9); + DCJdt (dCJdt); + double omega[3][3]; + mtxm_c( (SpiceDouble (*)[3]) &dCJdt[0], (SpiceDouble (*)[3]) &p_CJ[0], omega); + p_av[0] = omega[2][1]; + p_av[1] = omega[0][2]; + p_av[2] = omega[1][0]; + } + + + /** Compute the derivative of the rotation p_CJ with respect to time. + * The derivative is computed based on p_CJ = [angle3] [angle2] [angle1] + * p_CJ = [angle3] [angle2] [angle1] + * axis3 axis2 axis1 + * + * @param [out] dCJ Derivative of p_CJ + * + */ + void SpiceRotation::DCJdt(std::vector &dCJ ) { + NaifStatus::CheckErrors(); + + // Get the rotation angles and axes + std::vector angles = Angles ( p_axis3, p_axis2, p_axis1 ); + int axes[3]={p_axis1,p_axis2,p_axis3}; + + double dmatrix[3][3]; + double dangle; + double wmatrix[3][3]; // work matrix + dCJ.assign(9, 0.); + + for (int angleIndex=0; angleIndex<3; angleIndex++) { + drotat_ (&(angles[angleIndex]), (integer *) axes+angleIndex, (doublereal *) dmatrix); + // Transpose to obtain row-major order + xpose_c ( dmatrix, dmatrix); + + // To get the derivative of the polynomial fit to the angle with respect to time + // first create the function object for this angle and load its coefficients + Isis::PolynomialUnivariate function( p_degree ); + function.SetCoefficients ( p_coefficients[angleIndex] ); + + // Evaluate the derivative of function at p_et + dangle = function.DerivativeVar ( (p_et - p_baseTime) / p_timeScale ); + + // Multiply dangle to complete dmatrix + for ( int row = 0; row < 3; row++ ) { + for ( int col = 0; col < 3; col++ ) { + dmatrix[row][col] *= dangle; + } + } + // Apply the other 2 angles and chain them all together + switch (angleIndex) { + case 0: + rotmat_c (dmatrix, angles[1], axes[1], dmatrix ); + rotmat_c (dmatrix, angles[2], axes[2], dmatrix ); + break; + case 1: + rotate_c (angles[0], axes[0], wmatrix); + mxm_c ( dmatrix, wmatrix, dmatrix ); + rotmat_c (dmatrix, angles[2], axes[2], dmatrix ); + break; + case 2: + rotate_c (angles[0], axes[0], wmatrix); + rotmat_c (wmatrix, angles[1], axes[1], wmatrix ); + mxm_c ( dmatrix, wmatrix, dmatrix ); + break; + } + int i,j; + for (int index=0; index<9; index++) { + i = index/3; + j = index%3; + dCJ[index] += dmatrix[i][j]; + } + } + + NaifStatus::CheckErrors(); + } + + + /** Compute and return the rotation matrix that rotates state vectors from J2000 to the target frame. + */ + std::vector SpiceRotation::StateTJ() { + std::vector stateTJ(36); + + // Build the state matrix for the time-based rotation from the matrix and angulary velocity + double stateCJ[6][6]; + rav2xf_c (&p_CJ[0], &p_av[0], stateCJ); +// (SpiceDouble (*) [3]) &p_CJ[0] + int irow=0; + int jcol=0; + int vpos=0; + + for (int row = 3; row < 6; row++) { + irow = row - 3; + vpos = irow * 3; + + for (int col = 0; col < 3; col++) { + jcol = col + 3; + // Fill the upper left corner + stateTJ[irow*6 + col] = p_TC[vpos]*stateCJ[0][col] + p_TC[vpos+1]*stateCJ[1][col] + p_TC[vpos+2]*stateCJ[2][col]; + // Fill the lower left corner + stateTJ[row*6 + col] = p_TC[vpos]*stateCJ[3][col] + p_TC[vpos+1]*stateCJ[4][col] + p_TC[vpos+2]*stateCJ[5][col]; + // Fill the upper right corner + stateTJ[irow*6 + jcol] = 0; + // Fill the lower right corner + stateTJ[row*6 +jcol] = stateTJ[irow*6 + col]; + } + } + return stateTJ; + } + + + +} diff --git a/isis/src/base/objs/SpiceRotation/SpiceRotation.h b/isis/src/base/objs/SpiceRotation/SpiceRotation.h new file mode 100644 index 0000000000000000000000000000000000000000..ed436bda4e07a23ffc45a1a560c611a60a8cd66f --- /dev/null +++ b/isis/src/base/objs/SpiceRotation/SpiceRotation.h @@ -0,0 +1,287 @@ +#ifndef SpiceRotation_h +#define SpiceRotation_h +/** + * @file + * $Revision: 1.20 $ + * $Date: 2010/03/27 07:04:26 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Table.h" +#include "Quaternion.h" +#include "PolynomialUnivariate.h" +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" + +#define J2000Code 1 + +namespace Isis { + /** + * @brief Obtain SPICE rotation information for a body + * + * This class will obtain the rotation from J2000 to a particular reference + * frame, for example the rotation from J2000 to MOC NA. + * + * It is essentially used to convert position vectors from one frame to + * another, making it is a C++ wrapper to the NAIF routines pxform_c and + * mxv or mtxv. Therefore, appropriate NAIF kernels are expected to be + * loaded prior to using this class. A position can be returned in either + * the J2000 frame or the selected reference frame. See NAIF required + * reading for more information regarding this subject at + * ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/ascii/individual_docs/spk.req + *

    + * An important functionality of this class is the ability to cache the + * rotations so they do not have to be constantly read from the NAIF kernels + * and they can be more conveniently updated. Once the data is cached, the + * NAIF kernels can be unloaded. If the rotation has a fixed part and a time- + * based part, the rotation is computed and stored in those two parts. + * + * @ingroup SpiceInstrumentsAndCameras + * + * @author 2005-12-01 Debbie A. Cook + * + * @internal + * @history 2005-12-01 Debbie A. Cook Original Version modified from + * SpicePosition class by Jeff Anderson + * @history 2006-03-23 Jeff Anderson modified SetEphemerisTime to return + * if the time did not change to improve speed. + * @history 2006-10-18 Debbie A. Cook Added method, WrapAngle, to wrap + * angles around 2 pi + * @history 2007-12-05 Debbie A. Cook added method SetPolynomialDegree to + * allow the degree of the polynomials fit to the + * camera angles to be changed. Also changed the + * polynomial from a fixed 2nd order polynomial to + * an nth degree polynomial with one independent + * variable. PartialType was revised and the calls to + * SetReferencePartial (has an added argument, coefficient index) + * and DPolynomial (argument type changed to int) were revised. + * The function was changed from Parabola + * to Polynomial1Variable, now called + * PolynomialUnivariate. New methods GetBaseTime + * and SetOverrideBaseTime were added + * @history 2008-02-15 Debbie A. Cook added a new error message to handle the + * case where the Naif reference frame code is not + * recognized. + * @history 2008-06-18 Fixed documentation, added NaifStatus calls + * @history 2008-11-26 Debbie A. Cook Added method to set axes of rotation. + * Default axes are still 3,1,3 so existing software will + * not be affected by the change. Also added timeScale to the + * the class and made some parameters protected instead of private + * so they are available to inheriting classes. + * @history 2008-12-12 Debbie A. Cook Added method to return frame code + * @history 2009-01-26 Debbie A. Cook Added wrap of 3rd camera angle when crossing +-180 + * @history 2009-04-21 Debbie A. Cook Added methods MinimizeCache and LoadTimeCache, variable p_minimizeCache, and + * enum constants DownsizeStatus + * @history 2009-06-29 Debbie A. Cook Fixed memory overwrite problem in LoadTimeCache when reading a type 3 ck + * @history 2009-07-24 Debbie A. Cook Removed downsizing for Nadir instrument pointing tables (LoadTimeCache) so that + * radar instruments will work. Current downsizing code requires sclk and radar has no sclk. + * @history 2009-10-01 Debbie A. Cook Divided the rotation into a constant (in time) part and a time-based part and + * added keywords listing the frame chains for both the constant part and the time-based part. + * @history 2009-10-09 Debbie A. Cook Added angular velocity when it is available + * @history 2009-10-30 Modified J2000Vector and ReferenceVector to work on either length 3 vectors (position only) + * or lenght 6 vectors (position and velocity) and added private method StateTJ() + * @history 2009-12-03 Debbie A. Cook Modified tests in LoadTimeCache to allow observation to cross segment boundary + * for LRO + * @history 2010-03-19 Debbie A. Cook Revised ReloadCache including removing obsolete arguments. Added + * initialization of members p_fullCacheStartTime, p_fullCacheEndTime, and p_fullCacheSize. Added these + * same values to the table label in method Cache and the reading of these values to the method + * LoadCache(table). Improved error message in FrameTrace. Also corrected a comment in StateTJ + * @todo Downsize using Hermite cubic spline and allow Nadir tables to be downsized again. + */ + class SpiceRotation { + public: + //! Constructors + SpiceRotation( int frameCode ); +/* SpiceRotation( int NaifCode ); +We would like to call refchg instead to avoid the strings. Currently Naif does +not have refchg_c, but only the f2c'd refchg.c.*/ + SpiceRotation( int frameCode, int targetCode ); + + //! Destructor + virtual ~SpiceRotation() { } + + //! Change the frame (has no effect if cached) + void SetFrame( int frameCode ) { p_constantFrames[0] = frameCode; }; + int Frame() { return p_constantFrames[0]; }; + + void SetTimeBias (double timeBias); + /** + * The rotation can come from one of 3 places for an Isis cube: Cache, + * Naif Spice kernels, or Nadir computations. + */ + enum Source { Spice, Nadir, Memcache, Function}; + + enum PartialType {WRT_RightAscension,WRT_Declination,WRT_Twist}; + + enum DownsizeStatus {Yes,Done,No}; + enum NaifFrameType { INERTL=1, PCK=INERTL+1, CK=PCK+1, TK=CK+1, DYN=TK+1}; + + void SetEphemerisTime(double et); + + //! Return the current ephemeris time + double EphemerisTime() const { return p_et; }; + + std::vector Matrix(); + std::vector AngularVelocity() { return p_av; }; + std::vector &ConstantMatrix() { return p_TC; }; + std::vector &TimeBasedMatrix() { return p_CJ; }; + + std::vector J2000Vector( const std::vector& rVec ); + + std::vector ReferenceVector( const std::vector& jVec ); + + //! Set the downsize status + void MinimizeCache ( DownsizeStatus status) { p_minimizeCache = status; }; + + void LoadCache (double startTime, double endTime, int size); + + void LoadCache (double time); + + void LoadCache(Table &table); + + Table LineCache( const std::string &tableName ); + + void ReloadCache(); + + Table Cache(const std::string &tableName); + void CacheLabel(Table &table ); + + void LoadTimeCache(); + + std::vector Angles( int axis3, int axis2, int axis1 ); + + //! Is this rotation cached + bool IsCached() const { return (p_cache.size() > 0); }; + + void SetPolynomial (); + + void SetPolynomial ( const std::vector& abcAng1, + const std::vector& abcAng2, + const std::vector& abcAng3 ); + + void GetPolynomial ( std::vector& abcAng1, + std::vector& abcAng2, + std::vector& abcAng3 ); + + //! Set the polynomial degree + void SetPolynomialDegree(int degree); + + //! Return the source of the rotation + Source GetSource () { return p_source; }; + + //! Resets the source of the rotation + void SetSource ( Source source ){ p_source = source; return; }; + + void ComputeBaseTime (); + + //! Return the base time for the rotation + double GetBaseTime (){ return p_baseTime; }; + + //! Return the time scale for the rotation + double GetTimeScale (){ return p_timeScale; }; + + void SetOverrideBaseTime ( double baseTime, double timeScale ); + + double DPolynomial ( const int coeffIndex ); + + std::vector ToReferencePartial(std::vector& lookJ, + PartialType partialVar, int coeffIndex); + double WrapAngle (double compareAngle, double angle); + void SetAxes ( int axis1, int axis2, int axis3); + std::vector GetFullCacheTime (); + void FrameTrace( double et ); + + //! Return the frame chain for the constant part of the rotation (ends in target) + std::vector ConstantFrameChain() { return p_constantFrames; }; + + //! Return the frame chain for the rotation (begins in J2000) + std::vector TimeFrameChain() { return p_timeFrames; }; + + void InitConstantRotation(double et); + std::vector ConstantRotation(); + std::vector TimeBasedRotation(); + void DCJdt (std::vector &dRJ ); + + //! Return whether or not the rotation has angular velocities + bool HasAngularVelocity() { return p_hasAngularVelocity; }; + + void ComputeAv(); + + protected: + std::vector p_cacheTime; //!< iTime for corresponding rotation + std::vector > p_cache; //!< Cached rotations + //!< Stored as rotation matrix from + // J2000 to reference frame or + // coefficients of polynomial + // fit to rotation angles + int p_degree; //!< Degree of fit polynomial for angles + int p_axis1; //!< Axis of rotation for angle 1 of rotation + int p_axis2; //!< Axis of rotation for angle 2 of rotation + int p_axis3; //!< Axis of rotation for angle 3 of rotation + + private: + std::vector p_constantFrames; //!< Chain of Naif frame codes in constant rotation TC + // The first entry will always be the target frame code + std::vector p_timeFrames; //!< Chain of Naif frame codes in time-based rotation CJ + // The last entry will always be 1 (J2000 code) + double p_timeBias; //!< iTime bias when reading kernels + + double p_et; //!< Current ephemeris time + Quaternion p_quaternion; //!< Quaternion for J2000 to reference + // rotation at et + + bool p_matrixSet; //!< Flag indicating p_TJ has been set + + Source p_source; //!< The source of the rotation data + int p_axisP; //!< The axis defined by the spacecraft + // vector for defining a nadir rotation + int p_axisV; //!< The axis defined by the velocity + // vector for defining a nadir rotation + int p_targetCode; //!< For computing Nadir rotation only + + double p_baseTime; //!< Base time used in fit equations + double p_timeScale; //!< Time scale used in fit equations + bool p_degreeApplied; //!< Flag indicating whether or not a polynomial + // of degree p_degree has been created and + // used to fill the cache + std::vector p_coefficients[3]; //!< Coefficients defining functions fit to 3 pointing angles + bool p_noOverride; //!< Flag to compute base time; + double p_overrideBaseTime; //!< Value set by caller to override computed base time + double p_overrideTimeScale; //!< Value set by caller to override computed time scale + DownsizeStatus p_minimizeCache; //!< Status of downsizing the cache (set to No to ignore) + double p_fullCacheStartTime; //!< Initial requested starting time of cache + double p_fullCacheEndTime; //!< Initial requested ending time of cache + int p_fullCacheSize; //!< Initial requested cache size + std::vector p_TC; //!< Rotation matrix from first constant rotation (after all + // time-based rotations in frame chain from J2000 to target) + // to the target frame + std::vector p_CJ; //!< Rotation matrix from J2000 to first constant rotation + // after all the time-based rotations in frame chain from + std::vector > p_cacheAv; + //!< Cached angular velocities for corresponding rotactions in p_cache + std::vector p_av; //!< Angular velocity for rotation at time p_et + bool p_hasAngularVelocity; //!< Flag indicating whether the rotation includes angular velocity + std::vector StateTJ(); //!< State matrix (6x6) for rotating state vectors from J2000 to target frame + }; +}; + +#endif + diff --git a/isis/src/base/objs/SpiceRotation/SpiceRotation.truth b/isis/src/base/objs/SpiceRotation/SpiceRotation.truth new file mode 100644 index 0000000000000000000000000000000000000000..ee74ec0d18dc7bd2811c45eca38dcb1cfc8825ca --- /dev/null +++ b/isis/src/base/objs/SpiceRotation/SpiceRotation.truth @@ -0,0 +1,325 @@ +Unit test for SpiceRotation +Naif code = -94031 +Testing without cache ... +CJ(0) = -0.87506927 0.25477955 -0.41151081 + 0.011442263 0.86088548 0.50867009 + 0.48386242 0.44041295 -0.75624969 +av(0) = -1.3817139e-05 -0.0011493844 -0.00067443921 +CJ(1) = -0.85216522 0.27457809 -0.44544506 + 0.011408438 0.86081401 0.5087918 + 0.52314843 0.42849284 -0.73668827 +av(1) = -1.2759664e-05 -0.0011485667 -0.00067607282 +CJ(2) = -0.82753684 0.29372914 -0.47844118 + 0.011307844 0.86075918 0.50888679 + 0.56129752 0.41571243 -0.71563138 +av(2) = -1.4155561e-05 -0.001147111 -0.00067413283 +CJ(3) = -0.80133591 0.31214822 -0.51031779 + 0.011159773 0.86071999 0.50895635 + 0.59811054 0.40214997 -0.69320934 +av(3) = -1.2104446e-05 -0.0011411423 -0.00066849871 +CJ(4) = -0.77359018 0.32985508 -0.54106734 + 0.010977931 0.86068895 0.50901279 + 0.63359113 0.38782749 -0.66944164 +av(4) = -1.4107831e-05 -0.0011349124 -0.0006662493 +CJ(5) = -0.74451309 0.34675249 -0.57049362 + 0.010796958 0.86067614 0.50903832 + 0.66752055 0.3728261 -0.64452852 +av(5) = -1.1968844e-05 -0.0011267333 -0.00066073722 +CJ(6) = -0.71415 0.36283075 -0.59861809 + 0.010597655 0.86068385 0.50902947 + 0.69991247 0.35717945 -0.61850252 +av(6) = -8.9185184e-06 -0.0011163624 -0.00065670687 +CJ(7) = -0.68276816 0.37813868 -0.625171 + 0.010490873 0.86063983 0.50910611 + 0.73055977 0.34104285 -0.59158448 +av(7) = -1.3255742e-05 -0.0011054424 -0.00064995353 +CJ(8) = -0.6504334 0.39252175 -0.65027923 + 0.010371283 0.86063225 0.50912136 + 0.75949248 0.32440531 -0.56385491 +av(8) = -1.1327819e-05 -0.0010915537 -0.00063894876 +CJ(9) = -0.61729588 0.4060182 -0.67386573 + 0.010223693 0.86060645 0.50916796 + 0.78666465 0.30741789 -0.53539982 +av(9) = -1.2932496e-05 -0.0010747293 -0.00063276804 + +Testing with cache ... +Time = -69382819 +CJ(0) = -0.87506927 0.25477955 -0.41151081 + 0.011442263 0.86088548 0.50867009 + 0.48386242 0.44041295 -0.75624969 +av(0) = -1.3817139e-05 -0.0011493844 -0.00067443921 +Time = -69382785 +CJ(1) = -0.85216522 0.27457809 -0.44544506 + 0.011408438 0.86081401 0.5087918 + 0.52314843 0.42849284 -0.73668827 +av(1) = -1.2759664e-05 -0.0011485667 -0.00067607282 +Time = -69382751 +CJ(2) = -0.82753684 0.29372914 -0.47844118 + 0.011307844 0.86075918 0.50888679 + 0.56129752 0.41571243 -0.71563138 +av(2) = -1.4155561e-05 -0.001147111 -0.00067413283 +Time = -69382717 +CJ(3) = -0.80133591 0.31214822 -0.51031779 + 0.011159773 0.86071999 0.50895635 + 0.59811054 0.40214997 -0.69320934 +av(3) = -1.2104446e-05 -0.0011411423 -0.00066849871 +Time = -69382683 +CJ(4) = -0.77359018 0.32985508 -0.54106734 + 0.010977931 0.86068895 0.50901279 + 0.63359113 0.38782749 -0.66944164 +av(4) = -1.4107831e-05 -0.0011349124 -0.0006662493 +Time = -69382648 +CJ(5) = -0.74451309 0.34675249 -0.57049362 + 0.010796958 0.86067614 0.50903832 + 0.66752055 0.3728261 -0.64452852 +av(5) = -1.1968844e-05 -0.0011267333 -0.00066073722 +Time = -69382614 +CJ(6) = -0.71415 0.36283075 -0.59861809 + 0.010597655 0.86068385 0.50902947 + 0.69991247 0.35717945 -0.61850252 +av(6) = -8.9185184e-06 -0.0011163624 -0.00065670687 +Time = -69382580 +CJ(7) = -0.68276816 0.37813868 -0.625171 + 0.010490873 0.86063983 0.50910611 + 0.73055977 0.34104285 -0.59158448 +av(7) = -1.3255742e-05 -0.0011054424 -0.00064995353 +Time = -69382546 +CJ(8) = -0.6504334 0.39252175 -0.65027923 + 0.010371283 0.86063225 0.50912136 + 0.75949248 0.32440531 -0.56385491 +av(8) = -1.1327819e-05 -0.0010915537 -0.00063894876 +Time = -69382512 +CJ(9) = -0.61729588 0.4060182 -0.67386573 + 0.010223693 0.86060645 0.50916796 + 0.78666465 0.30741789 -0.53539982 +av(9) = -1.2932496e-05 -0.0010747293 -0.00063276804 + +Testing with functions ... +Source = 3 +Time = -69382819 +CJ(0) = -0.87506744 0.25462094 -0.41161286 + 0.011738947 0.86135321 0.5078709 + 0.48385863 0.43958939 -0.75673113 +av(0) = 0.0060767721 -0.17762108 -0.10195853 +Time = -69382785 +CJ(1) = -0.85215758 0.27464212 -0.44542021 + 0.011286673 0.86064824 0.50907487 + 0.52316352 0.42878469 -0.73650771 +av(1) = 0.0019360782 -0.17696327 -0.10273742 +Time = -69382751 +CJ(2) = -0.82753094 0.29389355 -0.47835042 + 0.011001086 0.86036145 0.50956565 + 0.56131231 0.41641897 -0.71520887 +av(2) = -0.0011987164 -0.1760005 -0.10318454 +Time = -69382717 +CJ(3) = -0.80130119 0.31232593 -0.51026357 + 0.010876467 0.86037533 0.5095449 + 0.59816227 0.40274907 -0.69281678 +av(3) = -0.0033004854 -0.1748316 -0.10326287 +Time = -69382683 +CJ(4) = -0.77358897 0.32991801 -0.54103069 + 0.010878267 0.86056939 0.50921703 + 0.63359432 0.3880392 -0.66931593 +av(4) = -0.0043542414 -0.17354731 -0.10293423 +Time = -69382648 +CJ(5) = -0.7445192 0.34667611 -0.57053207 + 0.010943787 0.86082321 0.50878643 + 0.66751135 0.37255749 -0.64469335 +av(5) = -0.0043556308 -0.17222877 -0.10215942 +Time = -69382614 +CJ(6) = -0.71421902 0.36263313 -0.5986555 + 0.010983412 0.86101859 0.50845487 + 0.69983609 0.35657286 -0.6189388 +av(6) = -0.0033094482 -0.17094648 -0.10089834 +Time = -69382580 +CJ(7) = -0.68281661 0.37784723 -0.62529429 + 0.010882256 0.86104113 0.50841887 + 0.73050876 0.34035224 -0.59204502 +av(7) = -0.0012282184 -0.16975939 -0.099110118 +Time = -69382546 +CJ(8) = -0.65044065 0.39240013 -0.65034537 + 0.010502127 0.86078088 0.50886735 + 0.75948448 0.324158 -0.56400791 +av(8) = 0.001869117 -0.16871432 -0.096753305 +Time = -69382512 +CJ(9) = -0.61722064 0.40639527 -0.67370733 + 0.0096837405 0.86013226 0.50997914 + 0.78673052 0.30824564 -0.53482681 +av(9) = 0.0059583752 -0.16784557 -0.093786037 + +Testing ToReferencePartial method +For angles (ra,dec,twist) = 1.9429654 2.1356375 -0.92665897 + For lookJ = 0.78673052 0.30824564 -0.53482681 +Right ascension partial on A applied to lookJ =: -0.50997914 -0.67370733 0 +Right ascension partial on B applied to lookJ =: -0.50997914 -0.67370733 0 +Right ascension partial on C applied to lookJ =: -0.50997914 -0.67370733 0 +Declination partial on A applied to lookJ =: -0.7977269 0.60301797 0 + +Twist partial on A applied to lookJ =: 0.0011693703 -0.00020943951 0 + +Testing with setting functions ... +Source = 3 +Time = -69382819 +CJ(0) = -0.87506744 0.25462094 -0.41161286 + 0.011738947 0.86135321 0.5078709 + 0.48385863 0.43958939 -0.75673113 +av(0) = 0.0060767721 -0.17762108 -0.10195853 +Time = -69382785 +CJ(1) = -0.85215758 0.27464212 -0.44542021 + 0.011286673 0.86064824 0.50907487 + 0.52316352 0.42878469 -0.73650771 +av(1) = 0.0019360782 -0.17696327 -0.10273742 +Time = -69382751 +CJ(2) = -0.82753094 0.29389355 -0.47835042 + 0.011001086 0.86036145 0.50956565 + 0.56131231 0.41641897 -0.71520887 +av(2) = -0.0011987164 -0.1760005 -0.10318454 +Time = -69382717 +CJ(3) = -0.80130119 0.31232593 -0.51026357 + 0.010876467 0.86037533 0.5095449 + 0.59816227 0.40274907 -0.69281678 +av(3) = -0.0033004854 -0.1748316 -0.10326287 +Time = -69382683 +CJ(4) = -0.77358897 0.32991801 -0.54103069 + 0.010878267 0.86056939 0.50921703 + 0.63359432 0.3880392 -0.66931593 +av(4) = -0.0043542414 -0.17354731 -0.10293423 +Time = -69382648 +CJ(5) = -0.7445192 0.34667611 -0.57053207 + 0.010943787 0.86082321 0.50878643 + 0.66751135 0.37255749 -0.64469335 +av(5) = -0.0043556308 -0.17222877 -0.10215942 +Time = -69382614 +CJ(6) = -0.71421902 0.36263313 -0.5986555 + 0.010983412 0.86101859 0.50845487 + 0.69983609 0.35657286 -0.6189388 +av(6) = -0.0033094482 -0.17094648 -0.10089834 +Time = -69382580 +CJ(7) = -0.68281661 0.37784723 -0.62529429 + 0.010882256 0.86104113 0.50841887 + 0.73050876 0.34035224 -0.59204502 +av(7) = -0.0012282184 -0.16975939 -0.099110118 +Time = -69382546 +CJ(8) = -0.65044065 0.39240013 -0.65034537 + 0.010502127 0.86078088 0.50886735 + 0.75948448 0.324158 -0.56400791 +av(8) = 0.001869117 -0.16871432 -0.096753305 +Time = -69382512 +CJ(9) = -0.61722064 0.40639527 -0.67370733 + 0.0096837405 0.86013226 0.50997914 + 0.78673052 0.30824564 -0.53482681 +av(9) = 0.0059583752 -0.16784557 -0.093786037 + +Testing tables ... +Time = -69382819 +CJ(0) = -0.87506744 0.25462094 -0.41161286 + 0.011738947 0.86135321 0.5078709 + 0.48385863 0.43958939 -0.75673113 +av(0) = 0.0060767721 -0.17762108 -0.10195853 +Time = -69382785 +CJ(1) = -0.85215758 0.27464212 -0.44542021 + 0.011286673 0.86064824 0.50907487 + 0.52316352 0.42878469 -0.73650771 +av(1) = 0.0019360782 -0.17696327 -0.10273742 +Time = -69382751 +CJ(2) = -0.82753094 0.29389355 -0.47835042 + 0.011001086 0.86036145 0.50956565 + 0.56131231 0.41641897 -0.71520887 +av(2) = -0.0011987164 -0.1760005 -0.10318454 +Time = -69382717 +CJ(3) = -0.80130119 0.31232593 -0.51026357 + 0.010876467 0.86037533 0.5095449 + 0.59816227 0.40274907 -0.69281678 +av(3) = -0.0033004854 -0.1748316 -0.10326287 +Time = -69382683 +CJ(4) = -0.77358897 0.32991801 -0.54103069 + 0.010878267 0.86056939 0.50921703 + 0.63359432 0.3880392 -0.66931593 +av(4) = -0.0043542414 -0.17354731 -0.10293423 +Time = -69382648 +CJ(5) = -0.7445192 0.34667611 -0.57053207 + 0.010943787 0.86082321 0.50878643 + 0.66751135 0.37255749 -0.64469335 +av(5) = -0.0043556308 -0.17222877 -0.10215942 +Time = -69382614 +CJ(6) = -0.71421902 0.36263313 -0.5986555 + 0.010983412 0.86101859 0.50845487 + 0.69983609 0.35657286 -0.6189388 +av(6) = -0.0033094482 -0.17094648 -0.10089834 +Time = -69382580 +CJ(7) = -0.68281661 0.37784723 -0.62529429 + 0.010882256 0.86104113 0.50841887 + 0.73050876 0.34035224 -0.59204502 +av(7) = -0.0012282184 -0.16975939 -0.099110118 +Time = -69382546 +CJ(8) = -0.65044065 0.39240013 -0.65034537 + 0.010502127 0.86078088 0.50886735 + 0.75948448 0.324158 -0.56400791 +av(8) = 0.001869117 -0.16871432 -0.096753305 +Time = -69382512 +CJ(9) = -0.61722064 0.40639527 -0.67370733 + 0.0096837405 0.86013226 0.50997914 + 0.78673052 0.30824564 -0.53482681 +av(9) = 0.0059583752 -0.16784557 -0.093786037 + +Testing vector methods +v = 0 0 1 +v = 0 0 1 +Testing with linear function ... +Source = 3 +Time = -69382819 +CJ(0) = -0.87506927 0.25477955 -0.41151081 + 0.011442263 0.86088548 0.50867009 + 0.48386242 0.44041295 -0.75624969 +Time = -69382512 +CJ(1) = -0.61729588 0.4060182 -0.67386573 + 0.010223693 0.86060645 0.50916796 + 0.78666465 0.30741789 -0.53539982 + +Testing Nadir rotation ... +Time = -69382819 +CJ(0) = -0.87397636 0.25584047 -0.41317186 + 0.011529483 0.86087973 0.50867786 + 0.48583166 0.43980876 -0.75533824 +Time = -69382785 +CJ(1) = -0.8510575 0.27545415 -0.44701918 + 0.011395904 0.86083688 0.50875338 + 0.52494883 0.42788419 -0.73576073 +Time = -69382751 +CJ(2) = -0.82643964 0.29447099 -0.47987952 + 0.011259757 0.86079693 0.508824 + 0.56291272 0.415109 -0.71471238 +Time = -69382717 +CJ(3) = -0.80023437 0.31282061 -0.5116329 + 0.011120698 0.86076027 0.50888906 + 0.59958426 0.4015408 -0.69228874 +Time = -69382683 +CJ(4) = -0.77256675 0.3304389 -0.54217225 + 0.010977542 0.86072774 0.5089472 + 0.63483865 0.38724396 -0.66859704 +Time = -69382648 +CJ(5) = -0.74357294 0.34727037 -0.57140403 + 0.01082962 0.86070008 0.50899715 + 0.66856713 0.37228842 -0.64375409 +Time = -69382614 +CJ(6) = -0.71339766 0.36327069 -0.59924801 + 0.010678492 0.86067708 0.50903923 + 0.70067806 0.35674833 -0.6178842 +Time = -69382580 +CJ(7) = -0.6821915 0.37840638 -0.62563837 + 0.010527022 0.86065772 0.50907512 + 0.73109776 0.34070061 -0.59111687 +Time = -69382546 +CJ(8) = -0.65010809 0.39265255 -0.65052551 + 0.010377232 0.86064111 0.50910626 + 0.75977087 0.32422345 -0.5635844 +Time = -69382512 +CJ(9) = -0.61730133 0.40599204 -0.67387649 + 0.010229777 0.86062698 0.50913313 + 0.78666029 0.30739495 -0.53541939 + +Testing angle wrapping... + Using anchor angle of 30, 240 changes to -120 + Using anchor angle of 30, -10 changes to -10 + Using anchor angle of 30, -180 changes to 180 + Using anchor angle of 30, 90 changes to 90 diff --git a/isis/src/base/objs/SpiceRotation/ck3sdn.cpp b/isis/src/base/objs/SpiceRotation/ck3sdn.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6963d8be2937fb62899ad89db380a1b8314d4f4a --- /dev/null +++ b/isis/src/base/objs/SpiceRotation/ck3sdn.cpp @@ -0,0 +1,586 @@ +#include +#include +#include + +#include "Camera.h" + +using namespace std; +using namespace Isis; +//#include "f2c.h" + +/* Table of constant values */ + +static int c__4 = 4; + /* Builtin functions */ +// double sqrt(doublereal), asin(doublereal); +extern int moved_(doublereal *arrfrm, integer *ndim, doublereal *arrto); +extern int qmini(double *init, double *final, double frac, double *qintrp); + +/* $Procedure CK3SDN( Down sample type 3 CK data prepared for writing ) */ +/* Subroutine */ int ck3sdn(double sdntol, bool avflag, int *nrec, + double *sclkdp, double *quats, double *avvs, + int nints, double *starts, double *dparr, int *intarr) +{ + /* System generated locals */ + int i__1, i__2; + + /* Local variables */ + doublereal frac, dneg; + integer left; + doublereal dpos, dist2; + integer i__, j; + doublereal angle; + integer keepf; + integer keepl; + doublereal qlneg[4]; + logical fitok; + integer right; + doublereal dist2a, dist2b; + doublereal qkeepf[4]; + doublereal qkeepl[4]; + integer intcrf, ndropd, intcrl; + integer intnrf; + logical skipit; + doublereal qlinpt[4], qintrp[4]; + +/* $ Abstract */ + +/* Down sample type 3 CK data prepared for writing. */ + +/* $ Disclaimer */ + +/* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ +/* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ +/* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ +/* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ +/* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ +/* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ +/* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ +/* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ +/* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ +/* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ + +/* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ +/* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ +/* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ +/* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ +/* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ +/* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ + +/* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ +/* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ +/* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ +/* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ + +/* $ Required_Reading */ + +/* CK */ +/* DAF */ +/* ROTATIONS */ +/* SCLK */ + +/* $ Keywords */ + +/* POINTING */ +/* UTILITY */ + +/* $ Declarations */ +/* $ Brief_I/O */ + +/* Variable I/O Description */ +/* -------- --- -------------------------------------------------- */ +/* SDNTOL I Tolerance used for sampling down. */ +/* AVFLAG I True if angular velocity data is set. */ +/* NREC I/O Number of pointing records. */ +/* SCLKDP I/O Encoded SCLK times. */ +/* QUATS I/O Quaternions representing instrument pointing. */ +/* AVVS I/O Angular velocity vectors. */ +/* NINTS I Number of intervals. */ +/* STARTS I Encoded SCLK interval start times. */ +/* DPARR I Double precision work array. */ +/* INTARR I Integer work array. */ + +/* $ Detailed_Input */ + +/* SDNTOL is the angular tolerance, in radians, to be used to */ +/* down sample the input CK type 3 pointing data. */ +/* SDNTOL must be a non-negative number. */ + +/* AVFLAG is a logical flag indicating whether or not */ +/* the angular velocity data should be processed. */ + +/* NREC is the number of pointing instances in the input */ +/* buffer. */ + +/* SCLKDP are the encoded spacecraft clock times associated with */ +/* each pointing instance. These times must be strictly */ +/* increasing. */ + +/* QUATS is the quaternion buffer. */ + +/* AVVS is the angular velocity vector buffer. */ + +/* If AVFLAG is FALSE then this array is ignored by the */ +/* routine; however it still must be supplied as part of */ +/* the calling sequence. */ + +/* NINTS is the number of intervals that the pointing instances */ +/* are partitioned into. */ + +/* STARTS are the start times of each of the interpolation */ +/* intervals. These times must be strictly increasing */ +/* and must coincide with times for which the input */ +/* quaternion buffer contains pointing. */ + +/* DPARR is a double precision work array. */ + +/* INTARR is an integer work array. */ + +/* $ Detailed_Output */ + +/* NREC is the number of pointing instances in the buffer */ +/* after down sampling. */ + +/* SCLKDP is the encoded spacecraft clock time buffer after */ +/* down sampling. */ + +/* QUATS is the quaternion buffer after down sampling. */ + +/* AVVS is the angular velocity vector buffer after down */ +/* sampling. */ + +/* $ Parameters */ + +/* None. */ + +/* $ Exceptions */ + +/* 1) If the number of pointing records is not greater than zero, */ +/* the error SPICE(INVALIDNUMBEROFRECORDS) is signaled. */ + +/* 2) If the number of interval starts is not greater than zero, */ +/* the error SPICE(INVALIDNUMBEROFINTERVALS) is signaled. */ + +/* 3) If the number of interval starts is not is not less than */ +/* or equal to the number of records, the error */ +/* SPICE(BUFFERSIZESMISMATCH) is signaled. */ + +/* 4) If the first interval start time is not the same as the */ +/* first record time, the error SPICE(FIRSTRECORDMISMATCH) */ +/* is signaled. */ + +/* 5) If the down sampling tolerance is not a non-negative number, */ +/* the error SPICE(BADDOWNSAMPLINGTOL) is signaled. */ + +/* 6) If record times buffer does not contain any of the times */ +/* from interval start times buffers, the error */ +/* SPICE(INTERVALSTARTNOTFOUND) is signaled. */ + +/* $ Files */ + +/* None. */ + +/* $ Particulars */ + +/* This routine eliminates from the input quaternion and angular */ +/* rate buffers all data points for which type 3 CK interpolation */ +/* between bounding points that are not eliminated would produce */ +/* result that is within specified tolerance of the input attitude. */ +/* The elimination, refered to in these comments as "down sampling", */ +/* is done within each individual interpolation interval (as */ +/* specified in the input interval starts buffer), with intervals */ +/* boundaries unchanged. */ + +/* $ Examples */ + +/* Normally this routine would be called immediately before the */ +/* CKW03 is called and be supplied with the input time, quaternion, */ +/* angular rate, and interval start buffers that were fully and */ +/* properly prepared for the CKW03 input, like this: */ + +/* CALL CK3SDN ( SDNTOL, ARFLAG, */ +/* . NREC, SCLKDP, QUATS, AVVS, NINTS, STARTS, */ +/* . DPARR, INTARR ) */ + +/* CALL CKW03 ( HANDLE, SCLKDP(1), SCLKDP(NREC), */ +/* . INSTID, FRMNAM, ARFLAG, SEGID, */ +/* . NREC, SCLKDP, QUATS, AVVS, NINTS, STARTS ) */ + +/* $ Restrictions */ + +/* None. */ + +/* $ Literature_References */ + +/* None. */ + +/* $ Author_and_Institution */ + +/* N.J. Bachman (JPL) */ +/* B.V. Semenov (JPL) */ + +/* $ Version */ + +/* - Beta Version 1.1.0, 19-SEP-2005 (BVS)(FST) */ + +/* Incorporated Scott's shrinking window search algorithm to */ +/* speed up down sampling. */ + +/* - Beta Version 1.0.0, 29-JUL-2005 (BVS)(NJB) */ + +/* -& */ +/* $ Index_Entries */ + +/* sample down ck type_3 pointing data prepared for writing */ + +/* -& */ + +/* Local variables. */ + + +/* SPICELIB functions. */ + + +/* Standard SPICE error handling. */ + + if (return_c()) { + return 0; + } else { + chkin_c("CK3SDN"); + } + +/* Let's do some sanity checks that needed to make sure that future */ +/* loops and comparisons don't blow up. First, verify that the */ +/* number pointing records is greater that zero. */ + + if (*nrec <= 0) { + setmsg_c("The number of pointing records must be greater than zero. I" + "t was #."); + errint_c("#", *nrec); + sigerr_c("SPICE(INVALIDNUMBEROFRECORDS)"); + chkout_c("CK3SDN"); + return 0; + } + +/* Then, verify that the number intervals is greater that zero. */ + + if (nints <= 0) { + setmsg_c("The number of interval starts must be greater than zero. It" + " was #."); + errint_c("#", nints); + sigerr_c("SPICE(INVALIDNUMBEROFINTERVALS)"); + chkout_c("CK3SDN"); + return 0; + } + +/* Then, verify that the number intervals is less than or equal to */ +/* the number of records. */ + + if (nints > *nrec) { + setmsg_c("The number of interval starts, #, is not less than or equal" + " to the number of records, #."); + errint_c("#", nints); + errint_c("#", *nrec); + sigerr_c("SPICE(BUFFERSIZESMISMATCH)"); + chkout_c("CK3SDN"); + return 0; + } + +/* Then verify that the first time in the intervals array is the same */ +/* as the first time in the records array. */ + + if (sclkdp[0] != starts[0]) { + setmsg_c("The first interval start time, #, is not the same as the fi" + "rst record time, #."); + errdp_c("#", *sclkdp); + errdp_c("#", *starts); + sigerr_c("SPICE(FIRSTRECORDMISMATCH)"); + chkout_c("CK3SDN"); + return 0; + } + +/* Finally verify that input down sampling tolerance is not positive */ +/* number. */ + + if (sdntol < 0.) { + setmsg_c("The down sampling tolerance must be a non-negative number. " + "It was #."); + errdp_c("#", sdntol); + sigerr_c("SPICE(BADDOWNSAMPLINGTOL)"); + chkout_c("CK3SDN"); + return 0; + } + +/* This variable will hold to the index of the pointing record that */ +/* matches the start of the next interval. For the first interval */ +/* it is set to one. */ + + intnrf = 1; + +/* We will count the number of points that were dropped. */ + + ndropd = 0; + +/* Loop through interpolation intervals. */ + + i__1 = nints; + for (i__ = 1; i__ <= i__1; ++i__) { + +/* Assign the index of the pointing record that matches the */ +/* begin time of this interval. */ + + intcrf = intnrf; + +/* Find the index of the pointing record that ends this interval. */ +/* If this the last interval, it is the last pointing record in */ +/* pointing buffer. */ + + if (i__ == nints) { + intcrl = *nrec; + } else { + +/* This is not the last interval. To get its end time we need */ +/* to find the pointing record that matches the start of the */ +/* next interval and pick the record before it. */ + +/* First we find index of the pointing record that corresponds */ +/* to the start of the next interval. */ + + i__2 = *nrec - intcrf + 1; + intnrf = bsrchd_c(starts[i__], i__2, &sclkdp[intcrf - 1]); + if (intnrf != 0) { + +/* Found index must be adjusted to be relative to the */ +/* beginning of the buffer. Currently it is relative to the */ +/* start of the current interval. */ + + intnrf = intnrf + intcrf - 1; + +/* The index of the last record belonging to this interval */ +/* in the found index minus 1. */ + + intcrl = intnrf - 1; + } else { + +/* We did not find such record. The input buffer must have */ +/* been formed improperly for this to happen. Signal an */ +/* error. */ + + setmsg_c("Cannot find pointing record with time that matches " + "the start time # (encoded SCLK ticks) of the interpo" + "lation interval number #."); + errdp_c("#", starts[i__]); + i__2 = i__ + 1; + errint_c("#", i__2); + sigerr_c("SPICE(INTERVALSTARTNOTFOUND)"); + chkout_c("CK3SDN"); + return 0; + } + } + +/* Let's look at the indexes of the pointing records */ +/* corresponding to the begin and end of this interval. If they */ +/* are the same (meaning it's a singleton interval) or if they */ +/* are next to each other (meaning that the whole set of */ +/* interval's pointing data is comprised of only its begin */ +/* and end points) there is no down sampling to do. */ + + skipit = intcrf == intcrl || intcrf == intcrl - 1; + +/* Set initial values for a binary search. */ + + keepf = intcrf; + left = intcrf; + right = intcrl; + while(! skipit && keepf < intcrl) { + +/* Set the right endpoint of the interval by dividing the */ +/* binary search region in half. */ + + keepl = (left + right) / 2; + +/* Unitize bracketing quaternions as QMINI seems to be */ +/* very sensitive to that. :) */ + + vhatg_c(&quats[(keepf << 2) - 4], c__4, qkeepf); + vhatg_c(&quats[(keepl << 2) - 4], c__4, qkeepl); + +/* Pick the closer of the right quaternion or its negative to */ +/* QKEEPF for input into QMINI to ensure that QMINI does */ +/* interpolation in the "shortest arc" direction. */ + + vminug_c(qkeepl, c__4, qlneg); + dpos = vdistg_c(qkeepl, qkeepf, c__4); + dneg = vdistg_c(qlneg, qkeepf, c__4); + if (dneg < dpos) { + moved_(qlneg, (integer *) &c__4, qlinpt); + } else { + moved_(qkeepl, (integer *) &c__4, qlinpt); + } + +/* Check all records between the currently picked window ends */ +/* to see if interpolated pointing is within tolerance of the */ +/* actual pointing. */ + + fitok = TRUE; + j = keepf + 1; + while(j <= keepl - 1 && fitok) { + +/* Compute interpolation fraction for this pointing record. */ + + if (sclkdp[keepl - 1] - sclkdp[keepf - 1] != 0.) { + frac = (sclkdp[j - 1] - sclkdp[keepf - 1]) / (sclkdp[ + keepl - 1] - sclkdp[keepf - 1]); + } else { + sigerr_c("SPICE(CK3SDNBUG)"); + chkout_c("CK3SDN"); + return 0; + } + +/* Call Nat's fast quaternion interpolation routine to */ +/* compute interpolated rotation for this point. */ + + qmini(qkeepf, qlinpt, frac, qintrp); + +/* Find the squared distance between the interpolated */ +/* and input quaternions. */ + + dist2a = (quats[(j << 2) - 4] - qintrp[0]) * (quats[(j << 2) + - 4] - qintrp[0]) + (quats[(j << 2) - 3] - qintrp[1]) + * (quats[(j << 2) - 3] - qintrp[1]) + (quats[(j << 2) + - 2] - qintrp[2]) * (quats[(j << 2) - 2] - qintrp[2]) + + (quats[(j << 2) - 1] - qintrp[3]) * (quats[(j << 2) + - 1] - qintrp[3]); + dist2b = (quats[(j << 2) - 4] + qintrp[0]) * (quats[(j << 2) + - 4] + qintrp[0]) + (quats[(j << 2) - 3] + qintrp[1]) + * (quats[(j << 2) - 3] + qintrp[1]) + (quats[(j << 2) + - 2] + qintrp[2]) * (quats[(j << 2) - 2] + qintrp[2]) + + (quats[(j << 2) - 1] + qintrp[3]) * (quats[(j << 2) + - 1] + qintrp[3]); + dist2 = min(dist2a,dist2b); + +/* The rotation angle theta is related to the distance by */ +/* the formula */ + +/* || Q1 - Q2 || = 2 * | sin(theta/4) | */ + + angle = asin(sqrt(dist2) / 2.) * 4.; + +/* Compare the angle with specified threshold. */ + + fitok = fitok && abs(angle) <= sdntol; + +/* Increment index to move to the next record. */ + + ++j; + } + +/* Was the fit OK? */ + + if (fitok) { + +/* Fit was OK. Check if left and right are equal; if so we */ +/* found the point that were were looking for. */ + + if (left == right) { + +/* Mark all records between fist and last with DPMAX. */ + + i__2 = keepl - 1; + for (j = keepf + 1; j <= i__2; ++j) { + sclkdp[j - 1] = dpmax_c(); + ++ndropd; + } + +/* Set first point for the next search to be equal to */ +/* the to the found point. */ + + keepf = keepl; + +/* Reset window boundaries for binary search. */ + + left = keepl; + right = intcrl; + } else { + +/* Left and right sides haven't converged yet; shift */ +/* left side of the binary search window forward. */ + + left = keepl + 1; + } + } else { + +/* No fit; shift right side of the binary search window */ +/* backwards. */ + + right = keepl - 1; + +/* If right side when "over" the left side, set left side */ +/* to be equal to the right side. */ + + if (right < left) { + left = right; + } + } + } + } + +/* At this point all records that are to be removed, if any, have */ +/* been "tagged" with DPMAX in the times buffer. We need to re-sort */ +/* the buffers to push these records to the bottom and re-set the */ +/* number of records to indicate that only the top portion should be */ +/* used. */ + + if (ndropd != 0) { + +/* Since SCLKs were the ones "marked" by DPMAX, we will use them */ +/* to get the order vector. */ + + orderd_c(sclkdp, *nrec, (SpiceInt *) intarr); + +/* Now, with the order vector in hand, sort the SCLKs ... */ + + reordd_c(intarr, *nrec, sclkdp); + +/* ... then sort quaternions (element by element) ... */ + + for (i__ = 0; i__ <= 3; ++i__) { + i__1 = *nrec; + for (j = 1; j <= i__1; ++j) { + dparr[j - 1] = quats[i__ + (j << 2) - 4]; + } + reordd_c(intarr, *nrec, dparr); + i__1 = *nrec; + for (j = 1; j <= i__1; ++j) { + quats[i__ + (j << 2) - 4] = dparr[j - 1]; + } + } + +/* ... and, finally, if requested, sort AVs (also element by */ +/* element) ... */ + + if (avflag) { + for (i__ = 1; i__ <= 3; ++i__) { + i__1 = *nrec; + for (j = 1; j <= i__1; ++j) { + dparr[j - 1] = avvs[i__ + j * 3 - 4]; + } + reordd_c(intarr, *nrec, dparr); + i__1 = *nrec; + for (j = 1; j <= i__1; ++j) { + avvs[i__ + j * 3 - 4] = dparr[j - 1]; + } + } + } + +/* Reset the number of points. */ + + *nrec -= ndropd; + } + +/* All done. Check out. */ + + chkout_c("CK3SDN"); + return 0; +} /* ck3sdn_ */ + diff --git a/isis/src/base/objs/SpiceRotation/qmini.cpp b/isis/src/base/objs/SpiceRotation/qmini.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1bbb91a85691b59ae3b08e6191f236010883701b --- /dev/null +++ b/isis/src/base/objs/SpiceRotation/qmini.cpp @@ -0,0 +1,315 @@ +#include +#include +#include + +#include "Camera.h" + +using namespace std; +using namespace Isis; +/* qmini.f -- translated by f2c (version 19980913). + You must link the resulting object file with the libraries: + -lf2c -lm (in that order) +*/ + +//#include "f2c.h" + +/* Table of constant values */ + +static doublereal c_b2 = -1.; +static doublereal c_b3 = 1.; + +/* $Procedure QMINI ( Quaternion linear interpolation ) */ +/* Subroutine */ int qmini(doublereal *init, doublereal *final, doublereal frac, doublereal *qintrp) +{ + /* System generated locals */ + doublereal d__1; + + /* Local variables */ + doublereal vmag, axis[3]; + doublereal q[4], angle; + doublereal qscale[4]; + doublereal intang, instar[4]; + +/* $ Abstract */ + +/* Interpolate between two quaternions using a constant angular */ +/* rate. */ + +/* $ Disclaimer */ + +/* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ +/* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ +/* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ +/* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ +/* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ +/* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ +/* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ +/* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ +/* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ +/* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ + +/* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ +/* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ +/* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ +/* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ +/* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ +/* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ + +/* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ +/* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ +/* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ +/* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ + +/* $ Required_Reading */ + +/* ROTATIONS */ + +/* $ Keywords */ + +/* MATH */ +/* QUATERNION */ +/* ROTATION */ + +/* $ Declarations */ +/* $ Brief_I/O */ + +/* Variable I/O Description */ +/* -------- --- -------------------------------------------------- */ +/* INIT I Initial quaternion representing a rotation. */ +/* FINAL I Final quaternion representing a rotation. */ +/* FRAC I Fraction of rotation from INIT to FINAL by which */ +/* to interpolate. */ +/* QINTRP O Linearly interpolated quaternion. */ + +/* $ Detailed_Input */ + +/* INIT, */ +/* FINAL, */ +/* FRAC are, respectively, two unit quaternions between */ +/* which to interpolate, and an interpolation */ +/* fraction. See the Detailed_Output and Particulars */ +/* sections for details. */ + +/* $ Detailed_Output */ + +/* QINTRP is the quaternion resulting from linear */ +/* interpolation between INIT and FINAL by the */ +/* fraction FRAC. By "linear interpolation" we mean */ +/* the following: */ + +/* We view INIT and FINAL as quaternions */ +/* representing two values of a time-varying */ +/* rotation quaternion R(t) that rotates at a */ +/* constant angular velocity (that is, the row */ +/* vectors of R(t) rotate with constant angular */ +/* velocity). We can say that */ + +/* INIT represents R(t0) */ +/* FINAL represents R(t1) */ + +/* Equivalently, the SPICELIB routine Q2M maps */ +/* INIT and FINAL to rotation matrices */ +/* corresponding to R(t0) and R(t1) respectively. */ + +/* "Linear interpolation by the fraction FRAC" */ +/* means that we evaluate R(t) at time */ + +/* t0 + FRAC * (t1 - t0). */ + + +/* $ Parameters */ + +/* None. */ + +/* $ Exceptions */ + +/* 1) If either of INIT or FINAL is not a unit quaternion, the error */ +/* SPICE(NOTAROTATION) is signaled. */ + +/* 2) This routine assumes that the rotation that maps INIT to FINAL */ +/* has a rotation angle THETA radians, where */ + +/* 0 < THETA < pi. */ +/* _ */ + +/* This routine cannot distinguish between rotations of THETA */ +/* radians, where THETA is in the interval [0, pi), and */ +/* rotations of */ + +/* THETA + 2 * k * pi */ + +/* radians, where k is any integer. These "large" rotations will */ +/* yield invalid results when interpolated. You must ensure */ +/* that the inputs you provide to this routine will not be */ +/* subject to this sort of ambiguity. If in fact you are */ +/* interpolating a time-depedent rotation with constant angular */ +/* velocity AV between times t0 and t1, you must ensure that */ + +/* || AV || * |t1 - t0| < pi. */ + +/* Here we assume that the magnitude of AV is the angular rate */ +/* of the rotation in units of radians per second. */ + + +/* 3) When FRAC is outside of the interval [0, 1], the process */ +/* performed is "extrapolation", not interpolation. Such */ +/* values of FRAC are permitted. */ + +/* $ Files */ + +/* None. */ + +/* $ Particulars */ + +/* In the discussion below, we assume that the conditions specified */ +/* in item (2) of the Exceptions section have been satisfied. */ + +/* As we've said, we view INIT and FINAL as quaternions representing */ +/* two values of a time-varying rotation matrix R(t) that rotates at */ +/* a constant angular velocity; we define R(t), t0, and t1 so that */ + +/* INIT represents R(t0) */ +/* FINAL represents R(t1). */ + +/* The output quaternion QINTRP represents R(t) evaluated at the */ +/* time */ + +/* t0 + FRAC * (t1 - t0). */ + +/* How do we evaluate R at times between t0 and t1? Since the row */ +/* vectors of R are presumed to rotate with constant angular */ +/* velocity, we will first find the rotation axis of the quotient */ +/* rotation Q that maps the row vectors of R from their initial to */ +/* final position. Since the rows of R are the columns of the */ +/* transpose of R, we can write: */ + +/* T T */ +/* R(t1) = Q * R(t0), */ + +/* Since */ + +/* T T T */ +/* R(t1) = ( R(t1) * R(t0) ) * R(t0) */ + + +/* we can find Q, as well as a rotation axis A and an angle THETA */ +/* in the range [0, pi] such that Q rotates vectors by THETA */ +/* radians about axis A. */ + +/* We'll use the notation */ + +/* [ x ] */ +/* N */ + +/* to indicate a coordinate system rotation of x radians about the */ +/* vector N. Having found A and THETA, we can write (note that */ +/* the sign of the rotation angle is negated because we're using */ +/* a coordinate system rotation) */ + +/* T (t - t0) T */ +/* R(t) = [ - THETA * --------- ] * R(t0) */ +/* (t1 - t0) A */ + +/* Thus R(t) and QINTRP are determined. */ + +/* The input argument FRAC plays the role of the quotient */ + +/* t - t0 */ +/* ------- */ +/* t1 - t0 */ + +/* shown above. */ + + +/* $ Examples */ + +/* 1) Suppose we want to interpolate between quaternions */ +/* Q1 and Q2 that give the orientation of a spacecraft structure */ +/* at times t1 and t2. We wish to find an approximation of the */ +/* structure's orientation at the midpoint of the time interval */ +/* [t1, t2]. We assume that the angular velocity of the */ +/* structure equals the constant AV between times t1 and t2. We */ +/* also assume that */ + +/* || AV || * (t2 - t1) < pi. */ + +/* Then the code fragment */ + +/* CALL QMINI ( Q1, Q2, 0.5D0, QINTRP, SCLDAV ) */ + +/* produces the approximation we desire. */ + + + +/* $ Restrictions */ + +/* None. */ + +/* $ Literature_References */ + +/* None. */ + +/* $ Author_and_Institution */ + +/* N.J. Bachman (JPL) */ + +/* $ Version */ + +/* - SPICELIB Version 1.0.0, 19-JUL-2005 (NJB) */ + +/* -& */ +/* $ Index_Entries */ + +/* linear interpolation between quaternions */ + +/* -& */ + +/* SPICELIB functions */ + + +/* Local variables */ + + +/* Use discovery check-in. */ + + + +/* Find the conjugate INSTAR of the input quaternion INIT. */ + + instar[0] = init[0]; + vminus_c(&init[1], &instar[1]); + +/* Find the quotient quaternion Q that maps INIT to FINAL. */ + + qxq_c(final, instar, q); + +/* Extract the rotation angle from Q. Use arccosine for */ +/* speed, sacrificing some accuracy. */ + + angle = acos(brcktd_c(q[0], c_b2, c_b3)) * 2.; + +/* Create a quaternion QSCALE from the rotation axis of the quotient */ +/* and the scaled rotation angle. */ + + intang = frac * angle / 2.; + qscale[0] = cos(intang); + +/* Get the unit vector parallel to the vector part of Q. */ +/* UNORM does exactly what we want here, because if the vector */ +/* part of Q is zero, the returned "unit" vector will be the */ +/* zero vector. */ + + unorm_c(&q[1], axis, &vmag); + +/* Form the vector part of QSCALE. */ + + d__1 = sin(intang); + vscl_c(d__1, axis, &qscale[1]); + +/* Apply QSCALE to INIT to produce the interpolated quaternion we */ +/* seek. */ + + qxq_c(qscale, init, qintrp); + return 0; +} /* qmini_ */ + diff --git a/isis/src/base/objs/SpiceRotation/unitTest.cpp b/isis/src/base/objs/SpiceRotation/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e23506af04e0d2e31902fffe606ad8c4ad31c1c --- /dev/null +++ b/isis/src/base/objs/SpiceRotation/unitTest.cpp @@ -0,0 +1,271 @@ +#include +#include +#include +#include "SpiceRotation.h" +#include "Filename.h" +#include "Preference.h" +#include "Table.h" + + + +using namespace std; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << setprecision(8); + cout << "Unit test for SpiceRotation" << endl; + + Isis::Filename f("$base/testData/kernels"); + string dir = f.Expanded() + "/"; + string naif(dir+"naif0007.tls"); + string mgs(dir+"MGS_SCLKSCET.00045.tsc"); + string mocti(dir+"moc13.ti"); + string mocbc(dir+"moc.bc"); + string mocbsp(dir+"moc.bsp"); + string de(dir+"de405.bsp"); + string pck(dir+"pck00006.tpc"); + //string mocadd(dir+"mocAddendum.ti"); + string mocspice(dir+"mocSpiceRotationUnitTest.ti"); + furnsh_c(naif.c_str()); + furnsh_c(mgs.c_str()); + furnsh_c(mocti.c_str()); + furnsh_c(mocbc.c_str()); + furnsh_c(mocbsp.c_str()); + furnsh_c(de.c_str()); + furnsh_c(pck.c_str()); +// furnsh_c(mocadd.c_str()); + furnsh_c(mocspice.c_str()); + + double startTime = -69382819.0; + double endTime = -69382512.0; + double slope = (endTime - startTime) / (10 - 1); + + SpiceInt code; + namfrm_c ("MGS_MOC", &code); +// namfrm_c ("IAU_MARS", &code); + cout << "Naif code = " << code << endl; + + + Isis::SpiceRotation rot( -94031 ); + + // Normal testing (no cache) + cout << "Testing without cache ... " << endl; + for (int i=0; i<10; i++) { + double t = startTime + (double) i * slope; + rot.SetEphemerisTime(t); + std::vector CJ = rot.Matrix(); + + cout << "CJ(" << i << ") = " << CJ[0] << " " << CJ[1] << " " << CJ[2] << endl; + cout << " " << CJ[3] << " " << CJ[4] << " " << CJ[5] << endl; + cout << " " << CJ[6] << " " << CJ[7] << " " << CJ[8] << endl; + + if ( rot.HasAngularVelocity() ) { + std::vector av = rot.AngularVelocity(); + cout << "av(" << i << ") = " << av[0] << " " << av[1] << " " << av[2] << endl; + } + } + cout << endl; + + // Testing with cache + cout << "Testing with cache ... " << endl; + rot.LoadCache(startTime,endTime,10); + for (int i=0; i<10; i++) { + double t = startTime + (double) i * slope; +// vector p = pos.SetEphemerisTime(t); + rot.SetEphemerisTime(t); + vector CJ = rot.Matrix(); + cout << "Time = " << rot.EphemerisTime() << endl; + cout << "CJ(" << i << ") = " << CJ[0] << " " << CJ[1] << " " << CJ[2] << endl; + cout << " " << CJ[3] << " " << CJ[4] << " " << CJ[5] << endl; + cout << " " << CJ[6] << " " << CJ[7] << " " << CJ[8] << endl; + + if ( rot.HasAngularVelocity() ) { + std::vector av = rot.AngularVelocity(); + cout << "av(" << i << ") = " << av[0] << " " << av[1] << " " << av[2] << endl; + } + } + cout << endl; + + // Testing with Functions + cout << "Testing with functions ... " << endl; + std::vector abcAng1,abcAng2,abcAng3; + rot.SetPolynomial (); + rot.GetPolynomial ( abcAng1, abcAng2, abcAng3 ); + cout << "Source = " << rot.GetSource() << endl; + for (int i=0; i<10; i++) { + double t = startTime + (double) i * slope; + rot.SetEphemerisTime(t); + vector CJ = rot.Matrix(); + cout << "Time = " << rot.EphemerisTime() << endl; + cout << "CJ(" << i << ") = " << CJ[0] << " " << CJ[1] << " " << CJ[2] << endl; + cout << " " << CJ[3] << " " << CJ[4] << " " << CJ[5] << endl; + cout << " " << CJ[6] << " " << CJ[7] << " " << CJ[8] << endl; + + if ( rot.HasAngularVelocity() ) { + std::vector av = rot.AngularVelocity(); + cout << "av(" << i << ") = " << av[0] << " " << av[1] << " " << av[2] << endl; + } + } + cout << endl; + + // Testing ToReferencePartial method + cout << "Testing ToReferencePartial method" << endl; + std::vector angles = rot.Angles(3,1,3); + cout << "For angles (ra,dec,twist) = " << angles[0] << " " << angles[1] << " " << angles[2] + << endl; + std::vector lookC; + lookC.push_back(0.); + lookC.push_back(0.); + lookC.push_back(1.); + std::vector lookJ = rot.J2000Vector(lookC); + cout << " For lookJ = " << lookJ[0] << " " << lookJ[1] << " " << lookJ[2] << endl; + std::vector dAraLookC(3); + dAraLookC = rot.ToReferencePartial( lookJ, Isis::SpiceRotation::WRT_RightAscension, 0); + // Take care of round-off problem. Look for a better way + if (abs(dAraLookC[2]) < .00000000001) dAraLookC[2] = 0.; + cout << "Right ascension partial on A applied to lookJ =: " << dAraLookC[0] << " " + << dAraLookC[1] << " " << dAraLookC[2] << endl; + + std::vector dBraLookC(3); + dBraLookC = rot.ToReferencePartial( lookJ, Isis::SpiceRotation::WRT_RightAscension, 1); + if (abs(dBraLookC[2]) < .00000000001) dBraLookC[2] = 0.; + cout << "Right ascension partial on B applied to lookJ =: " << dBraLookC[0] << " " + << dBraLookC[1] << " " << dBraLookC[2] << endl; + + std::vector dCraLookC(3); + dCraLookC = rot.ToReferencePartial( lookJ, Isis::SpiceRotation::WRT_RightAscension, 2); + if (abs(dCraLookC[2]) < .00000000001) dCraLookC[2] = 0.; + cout << "Right ascension partial on C applied to lookJ =: " << dCraLookC[0] << " " + << dCraLookC[1] << " " << dCraLookC[2] << endl; + + std::vector dAdecLookC(3); + dAdecLookC = rot.ToReferencePartial( lookJ, Isis::SpiceRotation::WRT_Declination, 0); + if (abs(dAdecLookC[2]) < .00000000001) dAdecLookC[2] = 0.; + cout << "Declination partial on A applied to lookJ =: " << dAdecLookC[0] << " " + << dAdecLookC[1] << " " << dAdecLookC[2] << endl << endl; + std::vector dAtwLookC; + + dAtwLookC = rot.ToReferencePartial( lookJ, Isis::SpiceRotation::WRT_Twist, 0); + for (int i=0; i<3; i++) { + if (abs(dAtwLookC[i]) < .00000000000001) dAtwLookC[i] = 0.; + } + cout << "Twist partial on A applied to lookJ =: " << dAtwLookC[0] << " " + << dAtwLookC[1] << " " << dAtwLookC[2] << endl << endl; + + cout << "Testing with setting functions ... " << endl; + Isis::SpiceRotation rot3( -94031 ); + Isis::SpiceRotation::Source source=Isis::SpiceRotation::Spice; + rot3.SetSource ( source ); + rot3.LoadCache(startTime,endTime,10); + rot3.SetPolynomial ( abcAng1, abcAng2, abcAng3 ); + source = rot3.GetSource(); + cout << "Source = " << source << endl; + for (int i=0; i<10; i++) { + double t = startTime + (double) i * slope; + rot3.SetEphemerisTime(t); + vector CJ = rot3.Matrix(); + cout << "Time = " << rot3.EphemerisTime() << endl; + cout << "CJ(" << i << ") = " << CJ[0] << " " << CJ[1] << " " << CJ[2] << endl; + cout << " " << CJ[3] << " " << CJ[4] << " " << CJ[5] << endl; + cout << " " << CJ[6] << " " << CJ[7] << " " << CJ[8] << endl; + + if ( rot3.HasAngularVelocity() ) { + std::vector av = rot3.AngularVelocity(); + cout << "av(" << i << ") = " << av[0] << " " << av[1] << " " << av[2] << endl; + } + } + cout << endl; + + + // Test table options + cout << "Testing tables ... " << endl; + Isis::Table tab = rot.Cache("Test"); + Isis::SpiceRotation rot2( -94031 ); + rot2.LoadCache(tab); + for (int i=0; i<10; i++) { + double t = startTime + (double) i * slope; + rot2.SetEphemerisTime(t); + vector CJ = rot2.Matrix(); + cout << "Time = " << rot2.EphemerisTime() << endl; + cout << "CJ(" << i << ") = " << CJ[0] << " " << CJ[1] << " " << CJ[2] << endl; + cout << " " << CJ[3] << " " << CJ[4] << " " << CJ[5] << endl; + cout << " " << CJ[6] << " " << CJ[7] << " " << CJ[8] << endl; +// cout << "Spacecraft (J) = " << p[0] << " " << p[1] << " " << p[2] << endl; + + if ( rot2.HasAngularVelocity() ) { + std::vector av = rot2.AngularVelocity(); + cout << "av(" << i << ") = " << av[0] << " " << av[1] << " " << av[2] << endl; + } + } + cout << endl; + +// Test J2000 and Reference vector methods + cout << "Testing vector methods" << endl; + rot2.SetEphemerisTime(startTime); + std::vector v(3); + v[0] = 0.; v[1] = 0.; v[2] = 1.; + std::vector vout = rot2.J2000Vector( v ); + std::cout << "v = "< CJ = naRot.Matrix(); + + cout << "Time = " << naRot.EphemerisTime() << endl; + cout << "CJ(" << i << ") = " << CJ[0] << " " << CJ[1] << " " << CJ[2] << endl; + cout << " " << CJ[3] << " " << CJ[4] << " " << CJ[5] << endl; + cout << " " << CJ[6] << " " << CJ[7] << " " << CJ[8] << endl; + } + cout << endl; + + // Test angle wrap routine + double newangle = naRot.WrapAngle( 0.5235987756, 4.188790205); + cout << "Testing angle wrapping..." << endl; + cout << " Using anchor angle of 30, 240 changes to " << newangle*180./pi_c() << endl; + newangle = naRot.WrapAngle( 0.5235987756, -0.1745329252); + cout << " Using anchor angle of 30, -10 changes to " << newangle*180./pi_c() << endl; + newangle = naRot.WrapAngle( 0.5235987756, -3.141592654); + cout << " Using anchor angle of 30, -180 changes to " << newangle*180./pi_c() << endl; + newangle = naRot.WrapAngle( 0.5235987756, 1.570796327); + cout << " Using anchor angle of 30, 90 changes to " << newangle*180./pi_c() << endl; + + +} diff --git a/isis/src/base/objs/StandardDeviationOperator/InterestOperator.plugin b/isis/src/base/objs/StandardDeviationOperator/InterestOperator.plugin new file mode 100644 index 0000000000000000000000000000000000000000..263b550ef5447bbde60f54f84213f4d99a2ee53a --- /dev/null +++ b/isis/src/base/objs/StandardDeviationOperator/InterestOperator.plugin @@ -0,0 +1,4 @@ +Group = StandardDeviation + Library = StandardDeviationOperator + Routine = StandardDeviationOperatorPlugin +End_Group diff --git a/isis/src/base/objs/StandardDeviationOperator/Makefile b/isis/src/base/objs/StandardDeviationOperator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a834c757c0ac9fbd717e99abc8f95267a859cdce --- /dev/null +++ b/isis/src/base/objs/StandardDeviationOperator/Makefile @@ -0,0 +1,5 @@ +INCS = StandardDeviationOperator.h +SRCS = StandardDeviationOperator.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/StandardDeviationOperator/StandardDeviationOperator.cpp b/isis/src/base/objs/StandardDeviationOperator/StandardDeviationOperator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee6d1feb1967c369a85dae3c72e3e5812c352635 --- /dev/null +++ b/isis/src/base/objs/StandardDeviationOperator/StandardDeviationOperator.cpp @@ -0,0 +1,35 @@ +#include "StandardDeviationOperator.h" +#include "Chip.h" +#include "Statistics.h" + +namespace Isis { + /** + * This method returns the amount of interest for the given chip. + * + * @param chip + * + * @return the amount of interest for this chip + */ + double StandardDeviationOperator::Interest(Chip &chip) { + Statistics stats; + stats.SetValidRange(mdMinDN, mdMaxDN); + for(int i = 0; i < chip.Samples(); i++) { + double pixels[chip.Lines()]; + int n = 0; + for(int j = 0; j < chip.Lines(); j++) { + if(!IsSpecial(chip.GetValue(i + 1, j + 1))) { + pixels[n] = chip.GetValue(i + 1, j + 1); + n++; + } + } + stats.AddData(pixels, n); + } + + return stats.StandardDeviation(); + } +} + +extern "C" Isis::InterestOperator *StandardDeviationOperatorPlugin(Isis::Pvl &pPvl) { + return new Isis::StandardDeviationOperator(pPvl); +} + diff --git a/isis/src/base/objs/StandardDeviationOperator/StandardDeviationOperator.h b/isis/src/base/objs/StandardDeviationOperator/StandardDeviationOperator.h new file mode 100644 index 0000000000000000000000000000000000000000..82c5eda15deabe2318d020cad1ed1a500d3211e7 --- /dev/null +++ b/isis/src/base/objs/StandardDeviationOperator/StandardDeviationOperator.h @@ -0,0 +1,64 @@ +#if !defined(StandardDeviationOperator_h) +#define StandardDeviationOperator_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/06/10 23:46:37 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "InterestOperator.h" + +namespace Isis { + class Pvl; + class Chip; + + /** + * @brief Standard deviation interest operator + * + * This class is used to construct a standard deviation interest operator. + * For this class, the interest is always positive with the worst + * interest amount being 0. The higher the interest, the better. + * + * @see InterestOperator + * + * @author 2006-02-11 Jacob Danton + * + * @internal + * @history 2006-02-11 Jacob Danton - Original Version + * @history 2007-08-01 Steven Koechle - Fixed error where + * Interest was compairing the uninitialized value of + * pixels[n] to see if it was a special pixel. + * @history 2007-08-02 Steven Koechle - Removed + * CompareInterests virtual method. + * @history 2010-06-10 Sharmila Prasad - Changes to accomodate CnetValidMeasure base class + */ + class StandardDeviationOperator : public InterestOperator { + public: + StandardDeviationOperator(Pvl &pPvl) : InterestOperator(pPvl) { + p_worstInterest = 0.0; + }; + virtual ~StandardDeviationOperator() {}; + + protected: + virtual double Interest(Chip &chip); + }; +}; + +#endif diff --git a/isis/src/base/objs/StandardDeviationOperator/StandardDeviationOperator.truth b/isis/src/base/objs/StandardDeviationOperator/StandardDeviationOperator.truth new file mode 100644 index 0000000000000000000000000000000000000000..1150697fcf427f6f9c1ef1f244fa1cb96406a510 --- /dev/null +++ b/isis/src/base/objs/StandardDeviationOperator/StandardDeviationOperator.truth @@ -0,0 +1,16 @@ +Object = InterestOperator + Group = Operator + Name = StandardDeviation + DeltaLine = 100 + DeltaSamp = 100 + Samples = 15 + Lines = 15 + MinimumDN = 0.0 + MaximumDN = 1.0 + MinimumInterest = 0.01 + End_Group +End_Object +End +Sample: 90 +Line : 379 +Interest: 0.0166121 diff --git a/isis/src/base/objs/StandardDeviationOperator/unitTest.cpp b/isis/src/base/objs/StandardDeviationOperator/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..678d4c40413fa4a5c266dcf2af32bb118638f699 --- /dev/null +++ b/isis/src/base/objs/StandardDeviationOperator/unitTest.cpp @@ -0,0 +1,54 @@ +#include +#include +#include "InterestOperator.h" +#include "InterestOperatorFactory.h" +#include "StandardDeviationOperator.h" +#include "Chip.h" +#include "Cube.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "PvlObject.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + try { + PvlGroup op("Operator"); + op += PvlKeyword("Name","StandardDeviation"); + op += PvlKeyword("DeltaLine", 100); + op += PvlKeyword("DeltaSamp", 100); + op += PvlKeyword("Samples", 15); + op += PvlKeyword("Lines", 15); + op += PvlKeyword("MinimumDN", 0.0); + op += PvlKeyword("MaximumDN", 1.0); + op += PvlKeyword("MinimumInterest", 0.01); + + PvlObject o("InterestOperator"); + o.AddGroup(op); + + Pvl pvl; + pvl.AddObject(o); + std::cout << pvl << std::endl; + + InterestOperator *iop = InterestOperatorFactory::Create(pvl); + + Cube c; + c.Open("$mgs/testData/ab102401.cub"); + + //iop->Operate(c, 100, 350); + UniversalGroundMap univGrndMap(c); + iop->Operate(c, univGrndMap, 100, 350); + + std::cout << "Sample: " << iop->CubeSample() << std::endl + << "Line : " << iop->CubeLine() << std::endl + << "Interest: " << iop->InterestAmount() << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/Statistics/Makefile b/isis/src/base/objs/Statistics/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a54779e01df923af294fcaba82b0bd51db97ece3 --- /dev/null +++ b/isis/src/base/objs/Statistics/Makefile @@ -0,0 +1,5 @@ +INCS = Statistics.h +SRCS = Statistics.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Statistics/Statistics.cpp b/isis/src/base/objs/Statistics/Statistics.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0daec656698760f21f29cb3e29a8f64458e3855 --- /dev/null +++ b/isis/src/base/objs/Statistics/Statistics.cpp @@ -0,0 +1,435 @@ +/** + * @file + * $Date: 2010/03/19 20:34:55 $ + * $Revision: 1.6 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Statistics.h" +#include "iException.h" +#include "iString.h" + +using namespace std; +namespace Isis { + //! Constructs an IsisStats object with accumulators and counters set to zero. + Statistics::Statistics () { + SetValidRange(); + Reset (); + } + + //! Reset all accumulators and counters to zero. + void Statistics::Reset() { + p_sum = 0.0; + p_sumsum = 0.0; + p_minimum = DBL_MAX; + p_maximum = -DBL_MAX; + p_totalPixels = 0; + p_validPixels = 00; + p_nullPixels = 0; + p_lisPixels = 0; + p_lrsPixels = 0; + p_hrsPixels = 0; + p_hisPixels = 0; + p_overRangePixels = 0; + p_underRangePixels = 0; + p_removedData = false; + } + + //! Destroys the IsisStats object. + Statistics::~Statistics () {}; + + /** + * Add an array of doubles to the accumulators and counters. + * This method can be invoked multiple times (for example: once + * for each line in a cube) before obtaining statistics. + * + * @param data The data to be added to the data set used for statistical + * calculations. + * + * @param count The number of elements in the incoming data to be added. + */ + void Statistics::AddData (const double *data, const unsigned int count) { + for (unsigned int i=0; i= 100.0)) { + string m = "Invalid value for percent"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + if (p_validPixels < 1) return Isis::NULL8; + double k = sqrt (1.0 / (1.0 - percent / 100.0)); + return Average() - k * StandardDeviation(); + } + + /** + * This method returns a maximum such that + * X percent of the data will fall with K + * standard deviations of the average (Chebyshev's + * Theorem). It can be used to obtain a minimum that + * does not include statistical outliers. + * + * @param percent The probability that the maximum + * is within K standard deviations of the mean. + * Default value = 99.5. + * + * @return maximum value excluding statistical outliers + * + * @throws Isis::iException::Message + */ + double Statistics::ChebyshevMaximum (const double percent) const { + if ((percent <= 0.0) || (percent >= 100.0)) { + string m = "Invalid value for percent"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + if (p_validPixels < 1) return Isis::NULL8; + double k = sqrt (1.0 / (1.0 - percent / 100.0)); + return Average() + k * StandardDeviation(); + } + + /** + * This method returns the better of the absolute + * minimum or the Chebyshev minimum. The better + * value is considered the value closest to the mean. + * + * @param percent The probability that the minimum is within K + * standard deviations of the mean (Used to compute + * the Chebyshev minimum). Default value = 99.5. + * + * @return Best of absolute and Chebyshev minimums + * + * @see Statistics::Minimum + * Statistics::ChebyshevMinimum + */ + double Statistics::BestMinimum (const double percent) const { + if (p_validPixels < 1) return Isis::NULL8; + double min = ChebyshevMinimum (percent); + if (Minimum() > min) min = Minimum(); + return min; + } + + /** + * + * This method returns the better of the absolute + * maximum or the Chebyshev maximum. The better value + * is considered the value closest to the mean. + * + * @param percent The probability that the maximum is within K + * standard deviations of the mean (Used to compute + * the Chebyshev maximum). Default value = 99.5. + * + * @return Best of absolute and Chebyshev maximums + * + * @see Statistics::Maximum + * Statistics::ChebyshevMaximum + */ + double Statistics::BestMaximum (const double percent) const { + if (p_validPixels < 1) return Isis::NULL8; + double max = ChebyshevMaximum (percent); + if (Maximum() < max) max = Maximum(); + return max; + } + + /** + * + * This method returns the better of the z-score + * of the given value. The z-score is the number of + * standard deviations the value lies above or + * below the average. + * + * @param value The value to calculate the z-score of. + * + * @return z-score + * + */ + double Statistics::ZScore (const double value) const { + if (StandardDeviation()==0) { + if (value==Maximum()) return 0; + else { + string m = "Undefined Z-score. Standard deviation is zero and"; + m+=" the input value["+Isis::iString(value)+"] is out of range ["+Isis::iString(Maximum())+"]."; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + } + return (value-Average())/StandardDeviation(); + } + +} // end namespace isis diff --git a/isis/src/base/objs/Statistics/Statistics.h b/isis/src/base/objs/Statistics/Statistics.h new file mode 100644 index 0000000000000000000000000000000000000000..f90acc0203bf131acc9c5c7cf8ea4c9c87a064b6 --- /dev/null +++ b/isis/src/base/objs/Statistics/Statistics.h @@ -0,0 +1,188 @@ +#ifndef Statistics_h +#define Statistics_h +/** + * @file + * $Date: 2010/03/19 20:34:55 $ + * $Revision: 1.5 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +#include "SpecialPixel.h" +#include "Constants.h" + +namespace Isis { + /** + * @brief This class is used to accumulate statistics on double arrays. + * + * This class is used to accumulate statistics on double arrays. In + * particular, it is highly useful for obtaining statistics on cube data. + * Parameters which can be computed are 1) @b average, 2) @b standard + * @b deviation, 3) @b variance, 4) @b minimum, 5) @b maximum and 6) + * @b various @b counts of valid and/or special pixels. + * + * The following example shows a simple set up and usage of the Statistics + * class to calculate the average of a set of values: + * + * @code + * Statistics myStats ; + * double myData [] = { 1.0, 3.0, 2.4, 7.5 } ; + * + * myStats.AddData (myData, 4) ; + * double myAverage = myStats.Average () ; + * cout << "The average of the data is " << myAverage << endl ; + * @endcode + * + * For an example of how the Statistics object is used in %Isis, see the + * Histogram object (inherits from Statistics) and the stats application, + * stats.cpp (uses the Statistics child class Histogram). + * + * @ingroup Statistics + * + * @author Jeff Anderson - 2002-05-06 + * + * @internal + * @history 2002-05-08 Jeff Anderson - Added Chebyshev and Best + * minimum/maximum methods. + * @history 2004-05-11 Jeff Anderson - Moved Reset, AddData and RemoveData + * methods into public space. + * @history 2004-06-28 Jeff Anderson - Added Sum and SumSquare methods. + * @history 2005-02-17 Deborah Lee Soltesz - Modified file to support Doxygen + * documentation. + * @history 2005-05-23 Jeff Anderson - Changed to support 2GB+ files + * @history 2006-02-15 Jacob Danton - Added Valid Range options/methods + * @history 2006-03-10 Jacob Danton - Added Z-score method + * @history 2007-01-18 Robert Sucharski - Added AddData method + * for a single double value + * @history 2008-05-06 Steven Lambright - Added AboveRange, BelowRange methods + * @history 2010-03-18 Sharmila Prasad - Error message more meaningful for SetValidRange function + * + * @todo 2005-02-07 Deborah Lee Soltesz - add example using cube data to the + * class documentation + * + */ + class Statistics { + public: + Statistics (); + ~Statistics (); + + void Reset (); + void AddData (const double *data, const unsigned int count); + /** + * Add a double to the accumulators and counters. This method + * can be invoked multiple times (for example: once for each + * pixel in a cube) before obtaining statistics. + * + * @param data The data to be added to the data set used for statistical + * calculations. + * + */ + inline void AddData (const double data) { + p_totalPixels++; + if (Isis::IsValidPixel(data) && InRange(data)) { + p_sum += data; + p_sumsum += data * data; + if (data < p_minimum) p_minimum = data; + if (data > p_maximum) p_maximum = data; + p_validPixels++; + } else if (Isis::IsNullPixel(data)) { + p_nullPixels++; + } else if (Isis::IsHisPixel(data)) { + p_hisPixels++; + } else if (Isis::IsHrsPixel(data)) { + p_hrsPixels++; + } else if (Isis::IsLisPixel(data)) { + p_lisPixels++; + } else if (Isis::IsLrsPixel(data)) { + p_lrsPixels++; + } else if(AboveRange(data)) { + p_overRangePixels++; + } else { + p_underRangePixels++; + } + } + + void RemoveData (const double *data, const unsigned int count); + void RemoveData (const double data); + void SetValidRange(const double minimum=Isis::ValidMinimum, const double maximum=Isis::ValidMaximum); + + double ValidMinimum() const {return p_validMinimum;} + double ValidMaximum() const {return p_validMaximum;} + bool InRange(const double value) {return (value >= p_validMinimum && value <= p_validMaximum);} + bool AboveRange(const double value) {return (value > p_validMaximum);} + bool BelowRange(const double value) {return (value < p_validMinimum);} + + double Average () const; + double StandardDeviation () const; + double Variance () const; + + double Minimum () const; + double Maximum () const; + double ChebyshevMinimum (const double percent=99.5) const; + double ChebyshevMaximum (const double percent=99.5) const; + double BestMinimum (const double percent=99.5) const; + double BestMaximum (const double percent=99.5) const; + double ZScore (const double value) const; + + BigInt TotalPixels () const; + BigInt ValidPixels () const; + BigInt OverRangePixels () const; + BigInt UnderRangePixels () const; + BigInt NullPixels () const; + BigInt LisPixels () const; + BigInt LrsPixels () const; + BigInt HisPixels () const; + BigInt HrsPixels () const; + BigInt OutOfRangePixels () const; + + + /** + * Returns the sum of all the data + * + * @return The sum of the data + */ + double Sum() const { return p_sum; }; + + /** + * Returns the sum of all the squared data + * + * @return The sum of the squared data + */ + double SumSquare () const { return p_sumsum; }; + + private: + double p_sum; //!< Sum accumulator. + double p_sumsum; //!< Sum-squared accumulator. + double p_minimum; //!< Minimum double value encountered. + double p_maximum; //!< Maximum double value encountered. + double p_validMinimum; //!< Minimum valid pixel value + double p_validMaximum; //!< Maximum valid pixel value + BigInt p_totalPixels; //!< Count of total pixels processed. + BigInt p_validPixels; //!< Count of valid pixels (non-special) processed. + BigInt p_nullPixels; //!< Count of null pixels processed. + BigInt p_lrsPixels; //!< Count of low instrument saturation pixels processed. + BigInt p_lisPixels; //!< Count of low representation saturation pixels processed. + BigInt p_hrsPixels; //!< Count of high instrument saturation pixels processed. + BigInt p_hisPixels; //!< Count of high instrument representation pixels processed. + BigInt p_underRangePixels; //!< Count of pixels less than the valid range + BigInt p_overRangePixels; //!< Count of pixels greater than the valid range + bool p_removedData; /**< Indicates the RemoveData method was called which implies + p_minimum and p_maximum are invalid. */ + }; +} // end namespace isis + +#endif + diff --git a/isis/src/base/objs/Statistics/Statistics.truth b/isis/src/base/objs/Statistics/Statistics.truth new file mode 100644 index 0000000000000000000000000000000000000000..323e60dcabf8a836cd59fb21fc39bcdfa239a676 --- /dev/null +++ b/isis/src/base/objs/Statistics/Statistics.truth @@ -0,0 +1,74 @@ +Average: 5 +Average: 2 +Variance: 1 +Std Deviation: 1 +Minimum: 1 +Maximum: 3 +ChebyShev Min: -12.1421 +ChebyShev Max: 16.1421 +Best Minimum: 1 +Best Maximum: 3 +Total Pixels: 8 +Valid Pixels: 3 +Null Pixels: 1 +Lis Pixels: 1 +Lrs Pixels: 1 +His Pixels: 1 +Hrs Pixels: 1 +Sum: 6 +SumSquare: 14 + +Average: 3.5 +Variance: 3.5 +Std Deviation: 1.87083 +Minimum: 1 +Maximum: 6 +ChebyShev Min: -22.9575 +ChebyShev Max: 29.9575 +Best Minimum: 1 +Best Maximum: 6 +Total Pixels: 12 +Valid Pixels: 6 +Null Pixels: 2 +Lis Pixels: 1 +Lrs Pixels: 1 +His Pixels: 1 +Hrs Pixels: 1 +Sum: 21 +SumSquare: 91 + +Average: 5 +Variance: 1 +Std Deviation: 1 +ChebyShev Min: -9.14214 +ChebyShev Max: 19.1421 +Total Pixels: 9 +Valid Pixels: 3 +Null Pixels: 2 +Lis Pixels: 1 +Lrs Pixels: 1 +His Pixels: 1 +Hrs Pixels: 1 +Sum: 15 +SumSquare: 77 + +Average: -1.79769e+308 +Variance: -1.79769e+308 +Std Deviation: -1.79769e+308 +ChebyShev Min: -1.79769e+308 +ChebyShev Max: -1.79769e+308 +Total Pixels: 0 +Valid Pixels: 0 +Null Pixels: 0 +Lis Pixels: 0 +Lrs Pixels: 0 +His Pixels: 0 +Hrs Pixels: 0 +Sum: 0 +SumSquare: 0 + +**PROGRAMMER ERROR** You are removing non-existant data in [Statistics::RemoveData] +**PROGRAMMER ERROR** Minimum is invalid since you removed data +**PROGRAMMER ERROR** Maximum is invalid since you removed data +**PROGRAMMER ERROR** Invalid value for percent +**PROGRAMMER ERROR** Invalid value for percent diff --git a/isis/src/base/objs/Statistics/unitTest.cpp b/isis/src/base/objs/Statistics/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..14892dcc19626ad7499e4376c9e934971ee43572 --- /dev/null +++ b/isis/src/base/objs/Statistics/unitTest.cpp @@ -0,0 +1,148 @@ +#include +#include "Statistics.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + + Isis::Statistics s; + s.SetValidRange(1.0, 6.0); + + s.AddData(5.0); + s.AddData(5.0); + s.Average(); + cout << "Average: " << s.Average() << endl; + s.Reset(); + + double a[10]; + a[0] = 1.0; + a[1] = 2.0; + a[2] = 3.0; + a[3] = Isis::NULL8; + a[4] = Isis::HIGH_REPR_SAT8; + a[5] = Isis::LOW_REPR_SAT8; + a[6] = Isis::HIGH_INSTR_SAT8; + a[7] = Isis::LOW_INSTR_SAT8; + a[8] = 10.0; + a[9] = -1.0; + + s.AddData(a,8); + cout << "Average: " << s.Average() << endl; + cout << "Variance: " << s.Variance() << endl; + cout << "Std Deviation: " << s.StandardDeviation() << endl; + cout << "Minimum: " << s.Minimum() << endl; + cout << "Maximum: " << s.Maximum() << endl; + cout << "ChebyShev Min: " << s.ChebyshevMinimum() << endl; + cout << "ChebyShev Max: " << s.ChebyshevMaximum() << endl; + cout << "Best Minimum: " << s.BestMinimum() << endl; + cout << "Best Maximum: " << s.BestMaximum() << endl; + cout << "Total Pixels: " << s.TotalPixels() << endl; + cout << "Valid Pixels: " << s.ValidPixels() << endl; + cout << "Null Pixels: " << s.NullPixels() << endl; + cout << "Lis Pixels: " << s.LisPixels() << endl; + cout << "Lrs Pixels: " << s.LrsPixels() << endl; + cout << "His Pixels: " << s.HisPixels() << endl; + cout << "Hrs Pixels: " << s.HrsPixels() << endl; + cout << "Sum: " << s.Sum() << endl; + cout << "SumSquare: " << s.SumSquare() << endl; + cout << endl; + + double b[4]; + b[0] = 4.0; + b[1] = 5.0; + b[2] = 6.0; + b[3] = Isis::NULL8; + + s.AddData (b,4); + cout << "Average: " << s.Average() << endl; + cout << "Variance: " << s.Variance() << endl; + cout << "Std Deviation: " << s.StandardDeviation() << endl; + cout << "Minimum: " << s.Minimum() << endl; + cout << "Maximum: " << s.Maximum() << endl; + cout << "ChebyShev Min: " << s.ChebyshevMinimum() << endl; + cout << "ChebyShev Max: " << s.ChebyshevMaximum() << endl; + cout << "Best Minimum: " << s.BestMinimum() << endl; + cout << "Best Maximum: " << s.BestMaximum() << endl; + cout << "Total Pixels: " << s.TotalPixels() << endl; + cout << "Valid Pixels: " << s.ValidPixels() << endl; + cout << "Null Pixels: " << s.NullPixels() << endl; + cout << "Lis Pixels: " << s.LisPixels() << endl; + cout << "Lrs Pixels: " << s.LrsPixels() << endl; + cout << "His Pixels: " << s.HisPixels() << endl; + cout << "Hrs Pixels: " << s.HrsPixels() << endl; + cout << "Sum: " << s.Sum() << endl; + cout << "SumSquare: " << s.SumSquare() << endl; + cout << endl; + + s.RemoveData (a,3); + cout << "Average: " << s.Average() << endl; + cout << "Variance: " << s.Variance() << endl; + cout << "Std Deviation: " << s.StandardDeviation() << endl; + cout << "ChebyShev Min: " << s.ChebyshevMinimum() << endl; + cout << "ChebyShev Max: " << s.ChebyshevMaximum() << endl; + cout << "Total Pixels: " << s.TotalPixels() << endl; + cout << "Valid Pixels: " << s.ValidPixels() << endl; + cout << "Null Pixels: " << s.NullPixels() << endl; + cout << "Lis Pixels: " << s.LisPixels() << endl; + cout << "Lrs Pixels: " << s.LrsPixels() << endl; + cout << "His Pixels: " << s.HisPixels() << endl; + cout << "Hrs Pixels: " << s.HrsPixels() << endl; + cout << "Sum: " << s.Sum() << endl; + cout << "SumSquare: " << s.SumSquare() << endl; + cout << endl; + + s.Reset(); + cout << "Average: " << s.Average() << endl; + cout << "Variance: " << s.Variance() << endl; + cout << "Std Deviation: " << s.StandardDeviation() << endl; + cout << "ChebyShev Min: " << s.ChebyshevMinimum() << endl; + cout << "ChebyShev Max: " << s.ChebyshevMaximum() << endl; + cout << "Total Pixels: " << s.TotalPixels() << endl; + cout << "Valid Pixels: " << s.ValidPixels() << endl; + cout << "Null Pixels: " << s.NullPixels() << endl; + cout << "Lis Pixels: " << s.LisPixels() << endl; + cout << "Lrs Pixels: " << s.LrsPixels() << endl; + cout << "His Pixels: " << s.HisPixels() << endl; + cout << "Hrs Pixels: " << s.HrsPixels() << endl; + cout << "Sum: " << s.Sum() << endl; + cout << "SumSquare: " << s.SumSquare() << endl; + cout << endl; + + try { + s.RemoveData (a,8); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + s.Minimum (); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + s.Maximum (); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + s.ChebyshevMinimum (0.0); + } + catch (Isis::iException &e) { + e.Report (false); + } + + try { + s.ChebyshevMaximum (100.0); + } + catch (Isis::iException &e) { + e.Report (false); + } +} diff --git a/isis/src/base/objs/Stretch/Makefile b/isis/src/base/objs/Stretch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..42b3c5f229752f5b11e0b39aad91efcc08c1d0af --- /dev/null +++ b/isis/src/base/objs/Stretch/Makefile @@ -0,0 +1,5 @@ +INCS = Stretch.h +SRCS = Stretch.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Stretch/Stretch.cpp b/isis/src/base/objs/Stretch/Stretch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43d68c2cd22aff244d2a93c9449fe810533a2ca9 --- /dev/null +++ b/isis/src/base/objs/Stretch/Stretch.cpp @@ -0,0 +1,411 @@ +/** + * @file + * $Revision: 1.9 $ + * $Date: 2009/07/16 21:14:56 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "Stretch.h" +#include "Histogram.h" +#include "iString.h" +#include "SpecialPixel.h" +#include "iException.h" +#include "Pvl.h" + +using namespace std; +namespace Isis { + + /** + * Constructs a Stretch object with default mapping of special pixel values to + * themselves. + */ + Stretch::Stretch () { + p_null = Isis::NULL8; + p_lis = Isis::LOW_INSTR_SAT8; + p_lrs = Isis::LOW_REPR_SAT8; + p_his = Isis::HIGH_INSTR_SAT8; + p_hrs = Isis::HIGH_REPR_SAT8; + p_minimum = p_lrs; + p_maximum = p_hrs; + p_pairs = 0; + } + + /** + * Adds a stretch pair to the list of pairs. Note that all input pairs must be + * in ascending order. + * + * @param input Input value to map + * + * @param output Output value when the input is mapped + * + * @throws Isis::iException::Programmer - input pairs must be in ascending + * order + */ + void Stretch::AddPair (const double input, const double output) { + if (p_pairs > 0) { + if (input <= p_input[p_pairs-1]) { + string msg = "Input pairs must be in ascending order"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + + p_input.push_back(input); + p_output.push_back(output); + p_pairs++; + } + + /** + * Maps an input value to an output value based on the stretch pairs and/or + * special pixel mappings. + * + * @param value Value to map + * + * @return double The mapped output value is returned by this method + */ + double Stretch::Map (const double value) const { + // Check special pixels first + if (!Isis::IsValidPixel(value)) { + if (Isis::IsNullPixel(value)) return p_null; + if (Isis::IsHisPixel(value)) return p_his; + if (Isis::IsHrsPixel(value)) return p_hrs; + if (Isis::IsLisPixel(value)) return p_lis; + return p_lrs; + } + + // Check to see if we have any pairs + if (p_input.size() == 0) return value; + + // Check to see if outside the minimum and maximum next + if (value < p_input[0]) { + if (!Isis::IsValidPixel(p_minimum)) { + if (Isis::IsNullPixel(p_minimum)) return p_null; + if (Isis::IsHisPixel(p_minimum)) return p_his; + if (Isis::IsHrsPixel(p_minimum)) return p_hrs; + if (Isis::IsLisPixel(p_minimum)) return p_lis; + return p_lrs; + } + return p_minimum; + } + + if (value > p_input[p_pairs-1]) { + if (!Isis::IsValidPixel(p_maximum)) { + if (Isis::IsNullPixel(p_maximum)) return p_null; + if (Isis::IsHisPixel(p_maximum)) return p_his; + if (Isis::IsHrsPixel(p_maximum)) return p_hrs; + if (Isis::IsLisPixel(p_maximum)) return p_lis; + return p_lrs; + } + return p_maximum; + } + + // Check the end points + if (value == p_input[0]) return p_output[0]; + if (value == p_input[p_pairs-1]) return p_output[p_pairs-1]; + + // Ok find the surrounding pairs with a binary search + int start = 0; + int end = p_pairs-1; + while (start != end) { + int middle = (start + end) / 2; + + if(middle == start) { + end = middle; + } + else if(value < p_input[middle]) { + end = middle; + } + else { + start = middle; + } + } + + end = start+1; + + // Apply the stretch + double slope = (p_output[end] - p_output[start]) / (p_input[end] - p_input[start]); + return slope * (value - p_input[end]) + p_output[end]; + } + + /** + * Given a string containing stretch pairs for example "0:0 50:0 100:255 255:255" + * evaluate the first pair and return a pair of doubles where first is the first + * input and second is the first output + * @param pairs A string containing stretch pairs for example + * "0:0 50:0 100:255 255:255" + * + * @throws Isis::iException::User - invalid stretch pair + * + * @return std::pair of doubles where first is the first input and + * second is the first output + */ + std::pair Stretch::NextPair(Isis::iString &pairs) { + std::pair io; + + // do input side + Isis::iString temp = pairs.Token(":"); + temp.Trim(" \t\r\n\v\f"); + io.first = temp.ToDouble(); + + // do output side but first check for empty string + if (pairs.length() == 0) { + throw Isis::iException::Message(Isis::iException::User, "Invalid stretch pairs [" + + pairs + "]", _FILEINFO_); + } + pairs.TrimHead(" \t\r\n\v\f"); + temp = pairs.Token(" \t\r\n\v\f"); + io.second = temp.ToDouble(); + + // trim so p will return empty if it should + pairs.TrimHead(" \t\r\n\v\f"); + + return io; + } + + /** + * Parses a string of the form "i1:o1 i2:o2...iN:oN" where each i:o + * represents an input:output pair. Therefore, the user can enter a string in + * this form and this method will parse the string and load the stretch pairs + * into the object via AddPairs. + * + * @param pairs A string containing stretch pairs for example + * "0:0 50:0 100:255 255:255" + * + * @throws Isis::iException::User - invalid stretch pair + */ + void Stretch::Parse(const std::string &pairs) + { + // Zero out the stretch arrays + p_input.clear(); + p_output.clear(); + p_pairs = 0; + + Isis::iString p(pairs); + std::pair pear; + + p.TrimHead(" \t\r\n\v\f"); + try { + while (p.size() > 0) { + pear = Stretch::NextPair(p); + Stretch::AddPair(pear.first, pear.second); + } + } + + catch (Isis::iException &e) { + throw Isis::iException::Message(Isis::iException::User,"Invalid stretch pairs ["+pairs+"]",_FILEINFO_); + } + } + + /** + * Parses a string of the form "i1:o1 i2:o2...iN:oN" where each i:o + * represents an input:output pair where the input is a percentage. Using + * the Histogram an appropriate dn value will be calculated for each input + * percentage. Therefore, the user can enter a string in this form and this + * method will parse the string and load the stretch pairs into the object + * via AddPairs. + * + * @param pairs A string containing stretch pairs for example + * "0:0 50:0 100:255" + * + * @throws Isis::iException::User - invalid stretch pair + */ + void Stretch::Parse(const std::string &pairs, const Isis::Histogram *hist) + { + // Zero out the stretch arrays + p_input.clear(); + p_output.clear(); + p_pairs = 0; + + Isis::iString p(pairs); + std::pair pear; + + // need to save the input dn values in order to + // to detect collisions + std::vector converted; + + p.TrimHead(" \t\r\n\v\f"); + try { + while (p.size() > 0) { + pear = Stretch::NextPair(p); + pear.first = hist->Percent(pear.first); + + // test for collision! + // if collision occurs then ignore this pair and move on + // to next pair + bool collision = false; + unsigned int k = 0; + while (!collision && k < converted.size()) { + if (pear.first == converted[k]) { + collision = true; + } + else { + k++; + } + } + if (!collision) { + Stretch::AddPair(pear.first, pear.second); + converted.push_back(pear.first); + } + } + } + + catch (Isis::iException &e) { + throw Isis::iException::Message(Isis::iException::User,"Invalid stretch pairs [" + + pairs + "]", _FILEINFO_); + } + } + + + /** + * Converts stretch pair to a string + * + * @return string The stretch pair as a string + */ + string Stretch::Text() const { + + if (p_pairs < 0) return ""; + + Isis::iString p(""); + for (int i=0; i= p_pairs || index < 0) { + return -1; + } + return p_input[index]; + } + + /** + * Returns the value of the output side of the stretch pair at the specified + * index. If the index number is out of bounds, then the method returns -1. + * + * @param index The index number to retieve the output stretch pair value from + * + * @return double The output side of the stretch pair at the specified index + */ + double Stretch::Output (int index) const { + if (index >= p_pairs || index < 0) { + return -1; + } + return p_output[index]; + } + + /** + * Loads the stretch pairs from the pvl file into the Stretch + * object. The file should look similar to this: + * @code + * Group = Pairs + * Input = (0,100,255) + * Output = (255,100,0) + * EndGroup + * @endcode + * + * @param file - The input file containing the stretch pairs + * @param grpName - The group name to get the input and output + * keywords from + */ + void Stretch::Load(std::string &file, std::string &grpName) { + Pvl pvl(file); + Load(pvl,grpName); + } + + /** + * Loads the stretch pairs from the pvl file into the Stretch + * object. The pvl should look similar to this: + * @code + * Group = Pairs + * Input = (0,100,255) + * Output = (255,100,0) + * EndGroup + * @endcode + * + * @param pvl - The pvl containing the stretch pairs + * @param grpName - The group name to get the input and output + * keywords from + */ + void Stretch::Load(Isis::Pvl &pvl, std::string &grpName) { + PvlGroup grp = pvl.FindGroup(grpName,Isis::PvlObject::Traverse); + PvlKeyword inputs = grp.FindKeyword("Input"); + PvlKeyword outputs = grp.FindKeyword("Output"); + + if (inputs.Size() != outputs.Size()) { + std::string msg = "Invalid Pvl file: The number of Input values must equal the number of Output values"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + for (int i=0; iAddKeyword(inputs); + grp->AddKeyword(outputs); + pvl.AddGroup(*grp); + } + + /** + * Copies the stretch pairs from another Stretch object, but maintains special + * pixel values + * + * @param other - The Stretch to copy pairs from + */ + void Stretch::CopyPairs(const Stretch &other) { + this->p_pairs = other.p_pairs; + this->p_input = other.p_input; + this->p_output = other.p_output; + } + +} // end namespace isis + + diff --git a/isis/src/base/objs/Stretch/Stretch.h b/isis/src/base/objs/Stretch/Stretch.h new file mode 100644 index 0000000000000000000000000000000000000000..8a33174c036b80ad55a78577be5e448b7ad87465 --- /dev/null +++ b/isis/src/base/objs/Stretch/Stretch.h @@ -0,0 +1,180 @@ +#ifndef Stretch_h +#define Stretch_h +/** + * @file + * $Revision: 1.7 $ + * $Date: 2009/07/16 21:14:39 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Pvl.h" +#include "Histogram.h" + +namespace Isis { +/** + * @brief Pixel value mapper + * + * This class is used to stretch or remap pixel values. For example, it can be + * used to apply contrast stretches, color code stretches, or remap from a + * double range to 8-bit (0 to 255). The methodology used is straightforward. + * The program must set up a list of stretch pairs, input-to-output mappings, + * using the AddPair method. For example, (0,0) and (1,255) are two pairs which + * would cause an input of 0 to be mapped to 0, 0.5 would be mapped to 127.5 + * and 1 would be mapped to 255. More than two pairs can be used which + * generates piece-wise linear mappings. Special pixels are mapped to themselves + * unless overridden with methods such as SetNull. Input values outside the + * minimum and maximum input pair values are mapped to LRS and HRS respectively. + * + * If you would like to see Stretch being used in implementation, + * see stretch.cpp + * + * @ingroup Utility + * + * @author 2002-05-15 Jeff Anderson + * + * @internal + * @history 2002-09-17 Jeff Anderson - Added Parse method + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2005-02-16 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-03-11 Elizabeth Ribelin - Modified unitTest to test all + * methods in the class + * @history 2006-05-25 Jacob Danton - Fixed typo in documentation + * @history 2007-03-02 Elizabeth Miller - Added Load and Save + * methods + * @history 2008-11-12 Steven Lambright - Changed search algorithm into a + * binary search replacing a linear search. + * @history 2009-04-30 Eric Hyer - One line setters now implemented in header file instead of cpp + * - Modified parse method + * - added abstraction by letting NextPair handle low level details + * - created second Parse method for handling pairs where the input side + * is a perentage + * - created private NextPair method + * - Fixed Input and Output getters to check both sides of boundry condition + * for valid data + * @history 2009-07-16 Eric Hyer - Fixed bug introduced in AddPair by my last commit + * - Renamed variable pair to avoid potential conflict with std::pair + * + */ + class Stretch { + private: + std::vector p_input; //!< Array for input side of stretch pairs + std::vector p_output; //!< Array for output side of stretch pairs + int p_pairs; //!< Number of stretch pairs + + double p_null; /** NextPair(Isis::iString &pairs); + + public: + Stretch (); + + //! Destroys the Stretch object + ~Stretch () {}; + + void AddPair (const double input, const double output); + + /** + * Sets the mapping for NULL pixels. If not called the NULL pixels will be + * mapped to NULL. Otherwise you can map NULLs to any double value. + * For example, SetNull(0.0). + * + * @param value Value to map input NULLs + */ + void SetNull (const double value) { p_null = value; } + + /** + * Sets the mapping for LIS pixels. If not called the LIS pixels will be mapped + * to LIS. Otherwise you can map LIS to any double value. For example, + * SetLis(0.0). + * + * @param value Value to map input LIS + */ + void SetLis (const double value) { p_lis = value; } + + /** + * Sets the mapping for LRS pixels. If not called the LRS pixels will be mapped + * to LRS. Otherwise you can map LRS to any double value. For example, + * SetLrs(0.0). + * + * @param value Value to map input LRS + */ + void SetLrs (const double value) { p_lrs = value; } + + /** + * Sets the mapping for HIS pixels. If not called the HIS pixels will be mapped + * to HIS. Otherwise you can map HIS to any double value. For example, + * SetHis(255.0). + * + * @param value Value to map input HIS + */ + void SetHis (const double value) { p_his = value; } + + /** + * Sets the mapping for HRS pixels. If not called the HRS pixels will be mapped + * to HRS. Otherwise you can map HRS to any double value. For example, + * SetHrs(255.0). + * + * @param value Value to map input HRS + */ + void SetHrs (const double value) { p_hrs = value; } + + void SetMinimum (const double value) { p_minimum = value; } + void SetMaximum (const double value) { p_maximum = value; } + + void Load(Pvl &pvl, std::string &grpName); + void Save(Pvl &pvl, std::string &grpName); + void Load(std::string &file, std::string &grpName); + void Save(std::string &file, std::string &grpName); + + double Map (const double value) const; + + void Parse(const std::string &pairs); + void Parse(const std::string &pairs, const Isis::Histogram *hist); + + std::string Text () const; + + //! Returns the number of stretch pairs + int Pairs () const { return p_pairs; }; + + double Input (const int index) const; + double Output (const int index) const; + + //! Clears the stretch pairs + void ClearPairs() { p_pairs = 0; p_input.clear(); p_output.clear(); }; + + void CopyPairs(const Stretch &other); + }; +}; + +#endif + diff --git a/isis/src/base/objs/Stretch/Stretch.truth b/isis/src/base/objs/Stretch/Stretch.truth new file mode 100644 index 0000000000000000000000000000000000000000..d91bb6fc8145e5c19e6c50d2a77e5943a163f717 --- /dev/null +++ b/isis/src/base/objs/Stretch/Stretch.truth @@ -0,0 +1,64 @@ +Pairs as Text: 0.0:1.0 0.25:50.0 1.0:100.0 +Number of Pairs = 3 +First Input Value = 0 +First Output Value = 1 + +Stretch(0.0): 1 +Stretch(0.125): 25.5 +Stretch(0.25): 50 +Stretch(0.625): 75 +Stretch(1.0): 100 + +Stretch(-0.1): -1.79769e+308 +Stretch(1.1): -1.79769e+308 + +Stretch(Null): 1 +Stretch(Lis): 2 +Stretch(Lrs): 3 +Stretch(His): 4 +Stretch(Hrs): 5 + +Stretch(-0.1): 3 +Stretch(1.1): 5 + +Stretch(-0.1): 6 +Stretch(1.1): 7 + +Test ClearPairs method +ClearPairs() +Pairs = 0 + + +Testing Parse +127.5 + +**USER ERROR** Invalid stretch pairs [0:0 50:0 49:255 255:255] +**PROGRAMMER ERROR** Input pairs must be in ascending order +**USER ERROR** Invalid stretch pairs [-5xyzzy:0 50:0 100:255 255:255] +**PARSE ERROR** Cannot convert [-5xyzzy] to a double + +Testing new Parse that takes %'s for input side of pairs +75 + +**USER ERROR** Invalid stretch pairs [0:0 50:0 49:255 100:255] +**PROGRAMMER ERROR** Input pairs must be in ascending order +**USER ERROR** Invalid stretch pairs [-5:10] +**PROGRAMMER ERROR** Argument percent outside of the range 0 to 100 in [Histogram::Percent] +**USER ERROR** Invalid stretch pairs [121:215] +**PROGRAMMER ERROR** Argument percent outside of the range 0 to 100 in [Histogram::Percent] +**USER ERROR** Invalid stretch pairs [-5xyzzy:0 50:0 100:255] +**PARSE ERROR** Cannot convert [-5xyzzy] to a double +0, 255 +100, 100 +255, 0 +testing save +0, 255 +100, 100 +255, 0 +testing copy pairs +original stretch pairs +0, 0 +255, 255 +copy stretch pairs +0, 0 +255, 255 diff --git a/isis/src/base/objs/Stretch/test.pvl b/isis/src/base/objs/Stretch/test.pvl new file mode 100644 index 0000000000000000000000000000000000000000..720df1019ae704409cd69305f6ff8824a3d1ba7a --- /dev/null +++ b/isis/src/base/objs/Stretch/test.pvl @@ -0,0 +1,4 @@ +Group = Pairs + Input = (0,100,255) + Output = (255,100,0) +EndGroup diff --git a/isis/src/base/objs/Stretch/unitTest.cpp b/isis/src/base/objs/Stretch/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..72265d8414604eb41748ab3f9c13d176635544fd --- /dev/null +++ b/isis/src/base/objs/Stretch/unitTest.cpp @@ -0,0 +1,171 @@ +#include +#include "SpecialPixel.h" +#include "Stretch.h" +#include "iException.h" +#include "Preference.h" +#include "Histogram.h" + +using namespace std; +int main () { + Isis::Preference::Preferences(true); + + Isis::Stretch s; + + s.AddPair (0.0,1.0); + s.AddPair (0.25,50.0); + s.AddPair (1.0,100.0); + + cout << "Pairs as Text: " << s.Text() << endl; + cout << "Number of Pairs = " << s.Pairs() << endl; + cout << "First Input Value = " << s.Input(0) << endl; + cout << "First Output Value = " << s.Output(0) << endl << endl; + cout << "Stretch(0.0): " << s.Map(0.0) << endl; + cout << "Stretch(0.125): " << s.Map(0.125) << endl; + cout << "Stretch(0.25): " << s.Map(0.25) << endl; + cout << "Stretch(0.625): " << s.Map(0.625) << endl; + cout << "Stretch(1.0): " << s.Map(1.0) << endl << endl; + + cout << "Stretch(-0.1): " << s.Map(-0.1) << endl; + cout << "Stretch(1.1): " << s.Map(1.1) << endl << endl; + + s.SetNull(1.0); + s.SetLis(2.0); + s.SetLrs(3.0); + s.SetHis(4.0); + s.SetHrs(5.0); + + + cout << "Stretch(Null): " << s.Map(Isis::NULL8) << endl; + cout << "Stretch(Lis): " << s.Map(Isis::LOW_INSTR_SAT8) << endl; + cout << "Stretch(Lrs): " << s.Map(Isis::LOW_REPR_SAT8) << endl; + cout << "Stretch(His): " << s.Map(Isis::HIGH_INSTR_SAT8) << endl; + cout << "Stretch(Hrs): " << s.Map(Isis::HIGH_REPR_SAT8) << endl; + cout << endl; + + cout << "Stretch(-0.1): " << s.Map(-0.1) << endl; + cout << "Stretch(1.1): " << s.Map(1.1) << endl << endl; + + s.SetMinimum(6.0); + s.SetMaximum(7.0); + + cout << "Stretch(-0.1): " << s.Map(-0.1) << endl; + cout << "Stretch(1.1): " << s.Map(1.1) << endl << endl; + + + cout << "Test ClearPairs method" << endl; + cout << "ClearPairs()" << endl; + s.ClearPairs(); + cout << "Pairs = " << s.Pairs() << endl << endl; + + try { + s.AddPair(1.0,200.0); + } + catch (Isis::iException &e) { + e.Report(false); + } + + cout << endl << "Testing Parse" << endl; + s.Parse("0:0 50:0 100:255 255:255"); + cout << s.Map(75.0) << endl; + cout << endl; + + try { + s.Parse("0:0 50:0 49:255 255:255"); + } + catch (Isis::iException &e) { + e.Report(false); + } + + try { + s.Parse("-5xyzzy:0 50:0 100:255 255:255"); + } + catch (Isis::iException &e) { + e.Report(false); + } + + // test the Parse for when inputs are %'s + cout << endl << "Testing new Parse that takes %'s for input side of pairs" << endl; + + Isis::Histogram temp(0.0, 100.0, 101); + Isis::Histogram * h = &temp; + for (double i = 0.0; i <= 100.0; i++) { + h->AddData(&i, 1); + } + + s.Parse("0:0 25:0 50:50 100:100", h); + cout << s.Map(75.0) << endl; + cout << endl; + + try { + s.Parse("0:0 50:0 49:255 100:255", h); + } + catch (Isis::iException &e) { + e.Report(false); + } + + // test for % < 0 + try { + s.Parse("-5:10", h); + } + catch (Isis::iException &e) { + e.Report(false); + } + + // test for % > 100 + try { + s.Parse("121:215", h); + } + catch (Isis::iException &e) { + e.Report(false); + } + + // test for other bad data + try { + s.Parse("-5xyzzy:0 50:0 100:255", h); + } + catch (Isis::iException &e) { + e.Report(false); + } + + try { + s.ClearPairs(); + std::string fname = "unitTest.pvl"; + std::string grp = "Pairs"; + s.Load(fname,grp); + for (int i=0; i +#include + +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "PolygonTools.h" + +#include "StripPolygonSeeder.h" + +namespace Isis { + + /** + * @brief Construct a StripPolygonSeeder algorithm + * + * + * @param pvl A Pvl object that contains a valid polygon point + * seeding definition + */ + StripPolygonSeeder::StripPolygonSeeder (Pvl &pvl) : PolygonSeeder(pvl) { + Parse(pvl); + }; + + + /** + * @brief Seed a polygon with points + * + * Seed the supplied polygon with points in a staggered pattern. The spacing + * is determined by the PVL group "PolygonSeederAlgorithm" + * + * @param lonLatPoly The polygon to be seeded with + * points. + * + * @return A vector of points which have been + * seeded into the polygon. The caller assumes responsibility for deleteing + * these. + * + * @internal + * @history 2007-05-09 Tracie Sucharski Changed a single spacing value + * to a separate value for x and y. + * @history 2008-06-18 Steven Lambright Fixed documentation + * + */ + std::vector StripPolygonSeeder::Seed(const geos::geom::MultiPolygon *multiPoly) { + + // Storage for the points to be returned + std::vector points; + + // Create some things we will need shortly + const geos::geom::Envelope *polyBoundBox = multiPoly->getEnvelopeInternal(); + + // Call the parents standardTests member + std::string msg = StandardTests(multiPoly, polyBoundBox); + if (!msg.empty()) { + return points; + } + + // Do strip seeder specific tests to make sure this poly should be seeded + // (none for now) + + // Starting at the centroid of the xy polygon populate the polygon with + // staggered points with the requested spacing + geos::geom::Point *centroid = multiPoly->getCentroid(); + double centerX = centroid->getX(); + double centerY = centroid->getY(); + delete centroid; + + int xStepsToCentroid = (int)((centerX-polyBoundBox->getMinX())/p_Xspacing + 0.5); + int yStepsToCentroid = (int)((centerY-polyBoundBox->getMinY())/p_Yspacing + 0.5); + double dRealMinX = centerX - (xStepsToCentroid * p_Xspacing); + double dRealMinY = centerY - (yStepsToCentroid * p_Yspacing); + double dDeltaXToReal = p_Xspacing * 1.0/6.0; + double dDeltaYToReal = p_Yspacing * 1.0/6.0; + + for (double y=dRealMinY; y <= polyBoundBox->getMaxY(); y += p_Yspacing) { + //printf("Grid Line,%.10f,%.10f,Through,%.10f,%.10f\n",dRealMinX, y, xyBoundBox->getMaxX(), y); + for (double x=dRealMinX; x <= polyBoundBox->getMaxX(); x +=p_Xspacing) { + geos::geom::Coordinate c(x+dDeltaXToReal,y+dDeltaYToReal); + geos::geom::Point *p = Isis::globalFactory.createPoint(c); + if (p->within(multiPoly)) { + points.push_back(Isis::globalFactory.createPoint(c)); + } + + geos::geom::Coordinate c2(x-dDeltaXToReal,y-dDeltaYToReal); + p = Isis::globalFactory.createPoint(c2); + if (p->within(multiPoly)) { + points.push_back(Isis::globalFactory.createPoint(c2)); + } + } + } + + return points; + } + + /** + * @brief Parse the StripSeeder spicific parameters from the PVL + * + * @param pvl The PVL object containing the control parameters for this + * polygon seeder. + */ + void StripPolygonSeeder::Parse(Pvl &pvl) { + // Call the parents Parse method + PolygonSeeder::Parse(pvl); + + // Pull parameters specific to this algorithm out + try { + // Get info from Algorithm group + PvlGroup &algo = pvl.FindGroup("PolygonSeederAlgorithm",Pvl::Traverse); + PvlGroup & invalgo = invalidInput->FindGroup("PolygonSeederAlgorithm", + Pvl::Traverse); + + // Set the spacing + p_Xspacing = 0.0; + if (algo.HasKeyword("XSpacing")) { + p_Xspacing = (double) algo["XSpacing"]; + if (invalgo.HasKeyword("XSpacing")) { + invalgo.DeleteKeyword("XSpacing"); + } + } + else { + std::string msg = "PVL for StripSeeder must contain [XSpacing] in ["; + msg += pvl.Filename() + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + p_Yspacing = 0.0; + if (algo.HasKeyword("YSpacing")) { + p_Yspacing = (double) algo["YSpacing"]; + if (invalgo.HasKeyword("YSpacing")) { + invalgo.DeleteKeyword("YSpacing"); + } + } + else { + std::string msg = "PVL for StripSeeder must contain [YSpacing] in ["; + msg += pvl.Filename() + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + catch (iException &e) { + std::string msg = "Improper format for PolygonSeeder PVL ["+pvl.Filename()+"]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + if (p_Xspacing <= 0.0) { + iString msg = "X Spacing must be greater that 0.0 [(" + iString(p_Xspacing) + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + if (p_Yspacing <= 0.0) { + iString msg = "Y Spacing must be greater that 0.0 [(" + iString(p_Yspacing) + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + PvlGroup StripPolygonSeeder::PluginParameters(std::string grpName) { + PvlGroup pluginInfo(grpName); + + PvlKeyword name("Name", Algorithm()); + PvlKeyword minThickness("MinimumThickness", MinimumThickness()); + PvlKeyword minArea("MinimumArea", MinimumArea()); + PvlKeyword xSpac("XSpacing", p_Xspacing); + PvlKeyword ySpac("YSpacing", p_Yspacing); + + pluginInfo.AddKeyword(name); + pluginInfo.AddKeyword(minThickness); + pluginInfo.AddKeyword(minArea); + pluginInfo.AddKeyword(xSpac); + pluginInfo.AddKeyword(ySpac); + + return pluginInfo; + } + +}; // End of namespace Isis + + +/** + * @brief Create a StripSeeder object + * + * Used to create a StripSeeder object from a PolygonSeeder plugin PVL + * file. + * + * @param pvl The Pvl object that describes how the new object should be + * initialized. + * + * @return A pointer to the new object + */ +extern "C" Isis::PolygonSeeder *StripPolygonSeederPlugin (Isis::Pvl &pvl) { + return new Isis::StripPolygonSeeder(pvl); +} + diff --git a/isis/src/base/objs/StripPolygonSeeder/StripPolygonSeeder.h b/isis/src/base/objs/StripPolygonSeeder/StripPolygonSeeder.h new file mode 100644 index 0000000000000000000000000000000000000000..9a553f0153442e609fc6b20568876ad3be9342a9 --- /dev/null +++ b/isis/src/base/objs/StripPolygonSeeder/StripPolygonSeeder.h @@ -0,0 +1,87 @@ +#ifndef StripPolygonSeeder_h +#define StripPolygonSeeder_h +/** + * @file + * $Revision: 1.11 $ + * $Date: 2010/05/05 21:31:14 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "geos/geom/Point.h" +#include "geos/geom/MultiPolygon.h" +#include "PolygonSeeder.h" + +namespace Isis { + class Pvl; + + /** + * @brief Seed points using a grid with a staggered pattern + * + * This class seeds the polygon with Control Points by creating a grid, + * centered on the overlap polygon. In each grid square two points are checked + * to see if they are inside the overlap polygon. One of these points lies 1/6 + * of a grid square up and left from the grid's center point, while the other + * point lies 1/6 down and right. Each point found that is within the overlap + * polygon is returned as a point. + * + * @ingroup PatternMatching + * + * @author 2006-01-20 Stuart Sides + * + * @internal + * @history 2007-05-09 Tracie Sucharski, Changed a single spacing value + * to a separate value for x and y. + * @history 2008-02-29 Steven Lambright - Created SubGrid capabilities, + * cleaned up Seed methods + * @history 2008-04-17 Steven Lambright - Fixed naming conventions for seeders + * @history 2008-08-18 Christopher Austin - Upgraded to geos3.0.0 + * @history 2008-11-12 Steven Lambright - Fixed documentation + * @history 2008-11-25 Steven Lambright - Added error checking + * @history 2009-02-01 Steven Lambright - Fixed problem with calculating + * starting position in the top left corner of the polygon + * @history 2009-08-05 Travis Addair - Encapsulated group + * creation for seed definition group + * @history 2010-04-15 Eric Hyer - Now updates parent's invalidInput + * variable (see PolygonSeeder) + * @history 2010-04-20 Christopher Austin - adapted for generic/unitless + * seeding + * @history 2010-05-05 Christopher Austin - Fixed major bug where the strip + * was not a strip. + */ + class StripPolygonSeeder : public PolygonSeeder { + public: + StripPolygonSeeder (Pvl &pvl); + + //! Destructor + virtual ~StripPolygonSeeder() {}; + + std::vector Seed(const geos::geom::MultiPolygon *mp); + + virtual PvlGroup PluginParameters(std::string grpName); + + protected: + virtual void Parse(Pvl &pvl); + + private: + double p_Xspacing; //! +#include +#include +#include + +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/geom/Geometry.h" +#include "geos/geom/Polygon.h" + +#include "iException.h" +#include "PolygonTools.h" +#include "PolygonSeeder.h" +#include "PolygonSeederFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "ProjectionFactory.h" +#include "GridPolygonSeeder.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + try { + cout << "Test 1, create a seeder" << endl; + + PvlGroup alg("PolygonSeederAlgorithm"); + + if(!alg.HasKeyword("Name")) { + cout << "Test without subgrid" << endl; + alg += PvlKeyword("Name","Strip"); + alg += PvlKeyword("MinimumThickness", 0.3); + alg += PvlKeyword("MinimumArea", 10); + alg += PvlKeyword("XSpacing", 1500); + alg += PvlKeyword("YSpacing", 1500); + } + + PvlObject o("AutoSeed"); + o.AddGroup(alg); + + Pvl pvl; + pvl.AddObject(o); + cout << pvl << endl << endl; + + PolygonSeeder *ps = PolygonSeederFactory::Create(pvl); + + std::cout << "Test to make sure Parse did it's job" << std::endl; + std::cout << "MinimumThickness = " << ps->MinimumThickness() << std::endl; + std::cout << "MinimumArea = " << ps->MinimumArea() << std::endl; + + cout << "Test 2, test a square polygon" << endl; + try { + // Call the seed member with a polygon + geos::geom::CoordinateSequence *pts; + vector polys; + + // Create the A polygon + pts = new geos::geom::CoordinateArraySequence(); + pts->add (geos::geom::Coordinate (0, 0)); + pts->add (geos::geom::Coordinate (0, 1.5)); + pts->add (geos::geom::Coordinate (0.5, 1.5)); + pts->add (geos::geom::Coordinate (0.5, 0)); + pts->add (geos::geom::Coordinate (0, 0)); + + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing(pts),NULL)); + + geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon (polys); + + cout << "Lon/Lat polygon = " << mp->toString() << endl; + // Create the projection necessary for seeding + PvlGroup radii = Projection::TargetRadii("MARS"); + Isis::Pvl maplab; + maplab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = maplab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",(string)radii["EquatorialRadius"]); + mapGroup += Isis::PvlKeyword("PolarRadius",(string)radii["PolarRadius"]); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetocentric"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",360); + mapGroup += Isis::PvlKeyword("CenterLatitude",0); + mapGroup += Isis::PvlKeyword("CenterLongitude",0); + mapGroup += Isis::PvlKeyword("ProjectionName","Sinusoidal"); + + Projection *proj = Isis::ProjectionFactory::Create(maplab); + + /* + This test doesn't make sense because there is no ground range on this + projection. + + + double x1,x2,y1,y2; + proj->XYRange(x1,x2,y1,y2); + if(fabs(x1) < 0.00000001) x1 = 0.0; + if(fabs(x2) < 0.00000001) x2 = 0.0; + if(fabs(y1) < 0.00000001) y1 = 0.0; + if(fabs(y2) < 0.00000001) y2 = 0.0; + std::cout << "X: " << x1 << "-" << x2 << " Y: " << y1 << "-" << y2 << std::endl; + */ + + geos::geom::MultiPolygon *xymp = PolygonTools::LatLonToXY(*mp, proj); + vector seedValues = ps->Seed(xymp); + + vector points; + for( unsigned int pt = 0; pt < seedValues.size(); pt ++) { + if (proj->SetCoordinate(seedValues[pt]->getX(),seedValues[pt]->getY())) { + points.push_back(Isis::globalFactory.createPoint( + geos::geom::Coordinate(proj->UniversalLongitude(), + proj->UniversalLatitude()))); + } + else { + iString msg = "Unable to convert to a (lon,lat)"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + cout << setprecision(13); + for (unsigned int i=0; igetX() << " " << points[i]->getY() << ")" << endl; + } + } + catch (iException &e) { + e.Report(); + } + + cout << "Test 3, test for too thin" << endl; + try { + // Call the seed member with a polygon + geos::geom::CoordinateSequence *pts; + vector polys; + + // Create the A polygon + pts = new geos::geom::DefaultCoordinateSequence (); + pts->add (geos::geom::Coordinate (0, 0)); + pts->add (geos::geom::Coordinate (0, 0.5)); + pts->add (geos::geom::Coordinate (0.0125, 0.5)); + pts->add (geos::geom::Coordinate (0.0125, 0)); + pts->add (geos::geom::Coordinate (0, 0)); + + polys.push_back (Isis::globalFactory.createPolygon ( + Isis::globalFactory.createLinearRing(pts),NULL)); + + geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon (polys); + + cout << "Lon/Lat polygon = " << mp->toString() << endl; + + // Create the projection necessary for seeding + PvlGroup radii = Projection::TargetRadii("MARS"); + Isis::Pvl maplab; + maplab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = maplab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",(string)radii["EquatorialRadius"]); + mapGroup += Isis::PvlKeyword("PolarRadius",(string)radii["PolarRadius"]); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetocentric"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",360); + mapGroup += Isis::PvlKeyword("CenterLatitude",0); + mapGroup += Isis::PvlKeyword("CenterLongitude",0); + mapGroup += Isis::PvlKeyword("ProjectionName","Sinusoidal"); + Projection *proj = Isis::ProjectionFactory::Create(maplab); + + // NOTHING SHOULD BE PRINTED (the thickness test should not have been met) + geos::geom::MultiPolygon *xymp = PolygonTools::LatLonToXY(*mp, proj); + vector seedValues = ps->Seed(xymp); + + for (unsigned int i=0; i p_el) { + string msg = "Invalid start/end line range [sl,el] specified for subarea"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + if (p_ss > p_es) { + string msg = "Invalid start/end sample range [ss,es] specified for subarea"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + p_linc = linc; + if (p_linc <= 0.0) { + string msg = "Invalid line increment [linc] specified for subarea"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + p_sinc = sinc; + if (p_sinc <= 0.0) { + string msg = "Invalid sample increment [sinc] specified for subarea"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + + /** + * Modifies a label for a file containing a subarea. The AlphaCube, Mapping, + * and Instrument groups are all affected when a subarea is extracted from + * another file. If the linc is not equal to the sinc, then the Instrument + * and Mapping groups will be removed from the label because they will no + * longer be valid. If the linc is equal to the sinc and they are not equal + * to 1, then the map scale and resolution in the Mapping group needs to be + * updated. The latitude and longitude ranges become invalid when the subarea + * does not cover the entire sample and line range of the original cube. + * Update the upper left corner x,y values if the projection is still valid + * and the starting line and/or starting sample have been changed from their + * location in the original file. + * + * @param icube This is the input cube that will have the subarea + * extracted from it. The label of this cube will be used to + * create updated Mapping, Instrument, and AlphaCube groups + * for the label of the output cube containing the subarea. + * + * @param ocube This is the output cube file containing the subarea. The + * label of this cube will be modified by extracting the Mapping, + * Instrument, and AlphaCube groups from the input label and + * putting them in this label. + * + * @param results This is the Results group that will go into the application + * log file. This group must be created by the calling application. + * Information will be added to it if the Mapping or Instrument + * groups are deleted from the output image label. + * + */ + void SubArea::UpdateLabel(Cube *icube, Cube *ocube, PvlGroup &results) { + + Pvl inlabel = *icube->Label(); + + // If the linc and sinc are not equal, then the Instrument and + // Mapping groups are no longer valid. + if (p_linc != p_sinc) { + if (inlabel.FindObject("IsisCube").HasGroup("Instrument")) { + inlabel.FindObject("IsisCube").DeleteGroup("Instrument"); + results += PvlKeyword ("InstrumentGroupDeleted", "True"); + } + if (inlabel.FindObject("IsisCube").HasGroup("Mapping")) { + inlabel.FindObject("IsisCube").DeleteGroup("Mapping"); + results += PvlKeyword ("MappingGroupDeleted", "True"); + } + } + + if (inlabel.FindObject("IsisCube").HasGroup("Mapping")) { + // Update the upper left corner X,Y values if the starting line or + // starting sample are changed. + if (p_sl != 1 || p_ss != 1) { + Projection &proj = *icube->Projection(); + proj.SetWorld(p_ss-0.5,p_sl-0.5); + PvlGroup &mapgroup = inlabel.FindObject("IsisCube").FindGroup("Mapping", Pvl::Traverse); + mapgroup.AddKeyword(PvlKeyword("UpperLeftCornerX",proj.XCoord()), + Pvl::Replace); + mapgroup.AddKeyword(PvlKeyword("UpperLeftCornerY",proj.YCoord()), + Pvl::Replace); + } + + // If the linc and sinc are not equal to 1, then update the + // mapping scale and resolution. + if (p_linc == p_sinc && p_linc != 1.0) { + PvlGroup &mapgroup = inlabel.FindObject("IsisCube").FindGroup("Mapping", Pvl::Traverse); + double pixres = mapgroup["PixelResolution"]; + mapgroup["PixelResolution"] = pixres * p_linc; + double scale = mapgroup["Scale"]; + mapgroup["Scale"] = scale / p_linc; + } + + // If the outer bounds of the image are changed, then the + // latitude,longitude range is no longer valid. + if (p_sl != 1 || p_ss != 1 || p_el != p_nl || p_es != p_ns) { + PvlGroup &mapgroup = inlabel.FindObject("IsisCube").FindGroup("Mapping", Pvl::Traverse); + if (mapgroup.HasKeyword("MinimumLatitude")) { + mapgroup.DeleteKeyword("MinimumLatitude"); + } + if (mapgroup.HasKeyword("MaximumLatitude")) { + mapgroup.DeleteKeyword("MaximumLatitude"); + } + if (mapgroup.HasKeyword("MinimumLongitude")) { + mapgroup.DeleteKeyword("MinimumLongitude"); + } + if (mapgroup.HasKeyword("MaximumLongitude")) { + mapgroup.DeleteKeyword("MaximumLongitude"); + } + } + } + + // Make changes to the output cube label + if (ocube->HasGroup("Instrument")) { + ocube->DeleteGroup("Instrument"); + } + if (inlabel.FindObject("IsisCube").HasGroup("Instrument")) { + PvlGroup inst; + inst = inlabel.FindObject("IsisCube").FindGroup("Instrument"); + ocube->PutGroup(inst); + } + + if (ocube->HasGroup("Mapping")) { + ocube->DeleteGroup("Mapping"); + } + if (inlabel.FindObject("IsisCube").HasGroup("Mapping")) { + PvlGroup mapgrp; + mapgrp = inlabel.FindObject("IsisCube").FindGroup("Mapping"); + ocube->PutGroup(mapgrp); + } + + // Update the AlphaCube group - this group will only be updated if + // a Mapping group does not exist in the labels. + AlphaCube aCube(p_ns,p_nl,ocube->Samples(),ocube->Lines(), + p_ss-0.5,p_sl-0.5,p_es+0.5,p_el+0.5); + aCube.UpdateGroup(*ocube->Label()); + } +} diff --git a/isis/src/base/objs/SubArea/SubArea.h b/isis/src/base/objs/SubArea/SubArea.h new file mode 100644 index 0000000000000000000000000000000000000000..9c21b00e4c68b9f75d60b51e7ef8da0dd7567ad3 --- /dev/null +++ b/isis/src/base/objs/SubArea/SubArea.h @@ -0,0 +1,72 @@ +#ifndef SubArea_h +#define SubArea_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/10/15 22:21:19 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "Pvl.h" +#include "Cube.h" + +namespace Isis { +/** + * @brief Apply corrections to a cube label for subarea extraction + * + * This class is used to apply corrections to a cube label when a subarea + * has been extracted. It is a base class which will take the cube label from + * the original cube file along with subarea information and generate a + * corrected cube label for the output cube file. + * + * If you would like to see SubArea being used in implementation, see + * crop, reduce, enlarge, cropspecial, or pad. + * + * @ingroup HighLevelCubeIO + * + * @author 2009-10-02 Janet Barrett + * + */ + +class SubArea { + public: + SubArea () {}; + + ~SubArea () {}; + + // Define the subarea + void SetSubArea (const int orignl, const int origns, const int sl, + const int ss, const int el, const int es, + const double linc, const double sinc); + + // Create an updated label for a subarea file + void UpdateLabel(Cube *icube, Cube *ocube, PvlGroup &results); + + private: + int p_sl; //! + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 +End_Group + +Testing no change in image area for unprojected cube... + +Group = Results + InputLines = 768 + InputSamples = 640 + StartingLine = 1 + StartingSample = 1 + EndingLine = 768 + EndingSample = 640 + LineIncrement = 1.0 + SampleIncrement = 1.0 + OutputLines = 768 + OutputSamples = 640 +End_Group + +Output cube label: + +Group = Dimensions + Samples = 640 + Lines = 768 + Bands = 1 +End_Group + +Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 +End_Group + +Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 +End_Group + +Testing full image area with linc=2, sinc=2 for unprojected cube... + +Group = Results + InputLines = 768 + InputSamples = 640 + StartingLine = 1 + StartingSample = 1 + EndingLine = 768 + EndingSample = 640 + LineIncrement = 2.0 + SampleIncrement = 2.0 + OutputLines = 384 + OutputSamples = 320 +End_Group + +Output cube label: + +Group = Dimensions + Samples = 320 + Lines = 384 + Bands = 1 +End_Group + +Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 +End_Group + +Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 320 + BetaLines = 384 +End_Group + +Testing full image area with linc=2, sinc=3 for unprojected cube... + +Group = Results + InputLines = 768 + InputSamples = 640 + StartingLine = 1 + StartingSample = 1 + EndingLine = 768 + EndingSample = 640 + LineIncrement = 2.0 + SampleIncrement = 3.0 + OutputLines = 384 + OutputSamples = 214 + InstrumentGroupDeleted = True +End_Group + +Output cube label: + +Group = Dimensions + Samples = 214 + Lines = 384 + Bands = 1 +End_Group + +Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 214 + BetaLines = 384 +End_Group + +Testing sub image area with linc=.5, sinc=.5 for unprojected cube... + +Group = Results + InputLines = 768 + InputSamples = 640 + StartingLine = 25 + StartingSample = 10 + EndingLine = 735 + EndingSample = 622 + LineIncrement = 0.5 + SampleIncrement = 0.5 + OutputLines = 1422 + OutputSamples = 1226 +End_Group + +Output cube label: + +Group = Dimensions + Samples = 1226 + Lines = 1422 + Bands = 1 +End_Group + +Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 +End_Group + +Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 9.5 + AlphaStartingLine = 24.5 + AlphaEndingSample = 622.5 + AlphaEndingLine = 735.5 + BetaSamples = 1226 + BetaLines = 1422 +End_Group + +Testing sub image area with linc=1.0, sinc=2.5 for unprojected cube... + +Group = Results + InputLines = 768 + InputSamples = 640 + StartingLine = 25 + StartingSample = 10 + EndingLine = 735 + EndingSample = 622 + LineIncrement = 1.0 + SampleIncrement = 2.5 + OutputLines = 711 + OutputSamples = 246 + InstrumentGroupDeleted = True +End_Group + +Output cube label: + +Group = Dimensions + Samples = 246 + Lines = 711 + Bands = 1 +End_Group + +Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 9.5 + AlphaStartingLine = 24.5 + AlphaEndingSample = 622.5 + AlphaEndingLine = 735.5 + BetaSamples = 246 + BetaLines = 711 +End_Group + +Input projected cube label: + +Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 +End_Group + +Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 +End_Group + +Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679808356 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.766902750622 + MaximumLatitude = 34.44419678224 + MinimumLongitude = 219.7240455337 + MaximumLongitude = 236.18955063342 + UpperLeftCornerX = -480000.0 + UpperLeftCornerY = 2042000.0 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + LineProjectionOffset = -2041.5 + SampleProjectionOffset = -479.5 +End_Group + +Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 +End_Group + +Testing no change in image area for projected cube... + +Group = Results + InputLines = 1404 + InputSamples = 959 + StartingLine = 1 + StartingSample = 1 + EndingLine = 1404 + EndingSample = 959 + LineIncrement = 1.0 + SampleIncrement = 1.0 + OutputLines = 1404 + OutputSamples = 959 +End_Group + +Output cube label: + +Group = Dimensions + Samples = 959 + Lines = 1404 + Bands = 1 +End_Group + +Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 +End_Group + +Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679808356 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.766902750622 + MaximumLatitude = 34.44419678224 + MinimumLongitude = 219.7240455337 + MaximumLongitude = 236.18955063342 + UpperLeftCornerX = -480000.0 + UpperLeftCornerY = 2042000.0 + PixelResolution = 1000.0 + Scale = 59.274697523306 + TrueScaleLatitude = 0.0 + LineProjectionOffset = -2041.5 + SampleProjectionOffset = -479.5 +End_Group + +Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 +End_Group + +Testing full image area with linc=2, sinc=2 for projected cube... + +Group = Results + InputLines = 1404 + InputSamples = 959 + StartingLine = 1 + StartingSample = 1 + EndingLine = 1404 + EndingSample = 959 + LineIncrement = 2.0 + SampleIncrement = 2.0 + OutputLines = 702 + OutputSamples = 480 +End_Group + +Output cube label: + +Group = Dimensions + Samples = 480 + Lines = 702 + Bands = 1 +End_Group + +Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 +End_Group + +Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679808356 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + MinimumLatitude = 10.766902750622 + MaximumLatitude = 34.44419678224 + MinimumLongitude = 219.7240455337 + MaximumLongitude = 236.18955063342 + UpperLeftCornerX = -480000.0 + UpperLeftCornerY = 2042000.0 + PixelResolution = 2000.0 + Scale = 29.637348761653 + TrueScaleLatitude = 0.0 + LineProjectionOffset = -2041.5 + SampleProjectionOffset = -479.5 +End_Group + +Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 +End_Group + +Testing full image area with linc=2, sinc=3 for projected cube... + +Group = Results + InputLines = 1404 + InputSamples = 959 + StartingLine = 1 + StartingSample = 1 + EndingLine = 1404 + EndingSample = 959 + LineIncrement = 2.0 + SampleIncrement = 3.0 + OutputLines = 702 + OutputSamples = 320 + InstrumentGroupDeleted = True + MappingGroupDeleted = True +End_Group + +Output cube label: + +Group = Dimensions + Samples = 320 + Lines = 702 + Bands = 1 +End_Group + +Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 959.5 + AlphaEndingLine = 1404.5 + BetaSamples = 320 + BetaLines = 702 +End_Group + +Testing sub image area with linc=.5, sinc=.5 for projected cube... + +Group = Results + InputLines = 1404 + InputSamples = 959 + StartingLine = 25 + StartingSample = 10 + EndingLine = 1371 + EndingSample = 941 + LineIncrement = 0.5 + SampleIncrement = 0.5 + OutputLines = 2694 + OutputSamples = 1864 +End_Group + +Output cube label: + +Group = Dimensions + Samples = 1864 + Lines = 2694 + Bands = 1 +End_Group + +Group = Instrument + SpacecraftName = "MARS GLOBAL SURVEYOR" + InstrumentId = MOC-WA + TargetName = Mars + StartTime = 1997-10-20T10:58:37.46 + StopTime = 1997-10-20T11:03:44.66 + CrosstrackSumming = 4 + DowntrackSumming = 4 + FocalPlaneTemperature = 213.1 + GainModeId = 1A + LineExposureDuration = 100.000000 + MissionPhaseName = AB-1 + OffsetModeId = 5 + SpacecraftClockCount = 561812335:32 + RationaleDesc = "OLYMPUS MONS SPECIAL RED WIDE ANGLE" + FirstLineSample = 673 +End_Group + +Group = Mapping + ProjectionName = Sinusoidal + CenterLongitude = 227.95679808356 + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + UpperLeftCornerX = -471000.0 + UpperLeftCornerY = 2018000.0 + PixelResolution = 500.0 + Scale = 118.54939504661 + TrueScaleLatitude = 0.0 + LineProjectionOffset = -2041.5 + SampleProjectionOffset = -479.5 +End_Group + +Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 0.5 + AlphaStartingLine = 0.5 + AlphaEndingSample = 640.5 + AlphaEndingLine = 768.5 + BetaSamples = 640 + BetaLines = 768 +End_Group + +Testing sub image area with linc=1.0, sinc=2.5 for projected cube... + +Group = Results + InputLines = 1404 + InputSamples = 959 + StartingLine = 25 + StartingSample = 10 + EndingLine = 1371 + EndingSample = 941 + LineIncrement = 1.0 + SampleIncrement = 2.5 + OutputLines = 1347 + OutputSamples = 373 + InstrumentGroupDeleted = True + MappingGroupDeleted = True +End_Group + +Output cube label: + +Group = Dimensions + Samples = 373 + Lines = 1347 + Bands = 1 +End_Group + +Group = AlphaCube + AlphaSamples = 640 + AlphaLines = 768 + AlphaStartingSample = 9.5 + AlphaStartingLine = 24.5 + AlphaEndingSample = 941.5 + AlphaEndingLine = 1371.5 + BetaSamples = 373 + BetaLines = 1347 +End_Group + diff --git a/isis/src/base/objs/SubArea/unitTest.cpp b/isis/src/base/objs/SubArea/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca2cb84f6ef63080db905ece80ed7068e063d414 --- /dev/null +++ b/isis/src/base/objs/SubArea/unitTest.cpp @@ -0,0 +1,541 @@ +#include "Isis.h" +#include "Cube.h" +#include "ProcessByLine.h" +#include "Pvl.h" +#include "SubArea.h" + +#include +#include +#include + +using namespace std; +using namespace Isis; + +void IsisMain () { + Isis::Preference::Preferences(true); + UserInterface &ui = Application::GetUserInterface(); + ProcessByLine p1; + Pvl inlabel; + Cube cube; + + int sl,ss; + int el,es; + double linc,sinc; + int inl,ins; + int onl,ons; + + p1.SetInputCube("FROM1"); + string from1 = ui.GetFilename("FROM1"); + Cube inomapcube; + inomapcube.Open(from1); + inl = inomapcube.Lines(); + ins = inomapcube.Samples(); + sl = 1; + ss = 1; + el = inl; + es = ins; + linc = 1.0; + sinc = 1.0; + onl = (int)ceil ((double)(el - sl + 1) / linc); + ons = (int)ceil ((double)(es - ss + 1) / sinc); + Cube *onomapcube = p1.SetOutputCube("TO",ons,onl,1); + + PvlGroup results("Results"); + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("StartingLine", sl); + results += PvlKeyword ("StartingSample", ss); + results += PvlKeyword ("EndingLine", el); + results += PvlKeyword ("EndingSample", es); + results += PvlKeyword ("LineIncrement", linc); + results += PvlKeyword ("SampleIncrement", sinc); + results += PvlKeyword ("OutputLines", onl); + results += PvlKeyword ("OutputSamples", ons); + + SubArea s; + s.SetSubArea(inl,ins,sl,ss,el,es,linc,sinc); + s.UpdateLabel(&inomapcube,onomapcube,results); + + cout << "Input unprojected cube label: " << endl << endl; + inlabel = *inomapcube.Label(); + cout << inlabel.FindObject("IsisCube").FindObject("Core").FindGroup("Dimensions") << endl << endl; + if (inlabel.FindObject("IsisCube").HasGroup("Instrument")) { + cout << inlabel.FindObject("IsisCube").FindGroup("Instrument") << endl << endl; + } + if (inlabel.FindObject("IsisCube").HasGroup("Mapping")) { + cout << inlabel.FindObject("IsisCube").FindGroup("Mapping") << endl << endl; + } + if (inlabel.FindObject("IsisCube").HasGroup("AlphaCube")) { + cout << inlabel.FindObject("IsisCube").FindGroup("AlphaCube") << endl << endl; + } + + cout << "Testing no change in image area for unprojected cube..." << endl << endl; + Isis::Application::Log(results); + cout << endl; + p1.EndProcess(); + + cout << "Output cube label: " << endl << endl; + string file = ui.GetFilename("TO"); + Pvl label(file); + cout << label.FindObject("IsisCube").FindObject("Core").FindGroup("Dimensions") << endl << endl; + if (label.FindObject("IsisCube").HasGroup("Instrument")) { + cout << label.FindObject("IsisCube").FindGroup("Instrument") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("Mapping")) { + cout << label.FindObject("IsisCube").FindGroup("Mapping") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("AlphaCube")) { + cout << label.FindObject("IsisCube").FindGroup("AlphaCube") << endl << endl; + } + + cube.Open(file); + cube.Close(true); + + results.Clear(); + + ProcessByLine p2; + p2.SetInputCube("FROM1"); + linc = 2.0; + sinc = 2.0; + onl = (int)ceil ((double)(el - sl + 1) / linc); + ons = (int)ceil ((double)(es - ss + 1) / sinc); + onomapcube = p2.SetOutputCube("TO",ons,onl,1); + + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("StartingLine", sl); + results += PvlKeyword ("StartingSample", ss); + results += PvlKeyword ("EndingLine", el); + results += PvlKeyword ("EndingSample", es); + results += PvlKeyword ("LineIncrement", linc); + results += PvlKeyword ("SampleIncrement", sinc); + results += PvlKeyword ("OutputLines", onl); + results += PvlKeyword ("OutputSamples", ons); + + s.SetSubArea(inl,ins,sl,ss,el,es,linc,sinc); + s.UpdateLabel(&inomapcube,onomapcube,results); + + cout << "Testing full image area with linc=2, sinc=2 "; + cout << "for unprojected cube..." << endl; + + Isis::Application::Log(results); + cout << endl; + p2.EndProcess(); + + cout << "Output cube label: " << endl << endl; + cube.Open(file); + label = *cube.Label(); + cube.Close(true); + cout << label.FindObject("IsisCube").FindObject("Core").FindGroup("Dimensions") << endl << endl; + if (label.FindObject("IsisCube").HasGroup("Instrument")) { + cout << label.FindObject("IsisCube").FindGroup("Instrument") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("Mapping")) { + cout << label.FindObject("IsisCube").FindGroup("Mapping") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("AlphaCube")) { + cout << label.FindObject("IsisCube").FindGroup("AlphaCube") << endl << endl; + } + + results.Clear(); + + ProcessByLine p3; + p3.SetInputCube("FROM1"); + linc = 2.0; + sinc = 3.0; + onl = (int)ceil ((double)(el - sl + 1) / linc); + ons = (int)ceil ((double)(es - ss + 1) / sinc); + onomapcube = p3.SetOutputCube("TO",ons,onl,1); + + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("StartingLine", sl); + results += PvlKeyword ("StartingSample", ss); + results += PvlKeyword ("EndingLine", el); + results += PvlKeyword ("EndingSample", es); + results += PvlKeyword ("LineIncrement", linc); + results += PvlKeyword ("SampleIncrement", sinc); + results += PvlKeyword ("OutputLines", onl); + results += PvlKeyword ("OutputSamples", ons); + + s.SetSubArea(inl,ins,sl,ss,el,es,linc,sinc); + s.UpdateLabel(&inomapcube,onomapcube,results); + + cout << "Testing full image area with linc=2, sinc=3 "; + cout << "for unprojected cube..." << endl; + + Isis::Application::Log(results); + cout << endl; + p3.EndProcess(); + + cout << "Output cube label: " << endl << endl; + cube.Open(file); + label = *cube.Label(); + cube.Close(true); + cout << label.FindObject("IsisCube").FindObject("Core").FindGroup("Dimensions") << endl << endl; + if (label.FindObject("IsisCube").HasGroup("Instrument")) { + cout << label.FindObject("IsisCube").FindGroup("Instrument") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("Mapping")) { + cout << label.FindObject("IsisCube").FindGroup("Mapping") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("AlphaCube")) { + cout << label.FindObject("IsisCube").FindGroup("AlphaCube") << endl << endl; + } + + results.Clear(); + + ProcessByLine p4; + p4.SetInputCube("FROM1"); + sl = 25; + ss = 10; + el = inl - 33; + es = ins - 18; + linc = .5; + sinc = .5; + onl = (int)ceil ((double)(el - sl + 1) / linc); + ons = (int)ceil ((double)(es - ss + 1) / sinc); + onomapcube = p4.SetOutputCube("TO",ons,onl,1); + + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("StartingLine", sl); + results += PvlKeyword ("StartingSample", ss); + results += PvlKeyword ("EndingLine", el); + results += PvlKeyword ("EndingSample", es); + results += PvlKeyword ("LineIncrement", linc); + results += PvlKeyword ("SampleIncrement", sinc); + results += PvlKeyword ("OutputLines", onl); + results += PvlKeyword ("OutputSamples", ons); + + s.SetSubArea(inl,ins,sl,ss,el,es,linc,sinc); + s.UpdateLabel(&inomapcube,onomapcube,results); + + cout << "Testing sub image area with linc=.5, sinc=.5 "; + cout << "for unprojected cube..." << endl; + + Isis::Application::Log(results); + cout << endl; + p4.EndProcess(); + + cout << "Output cube label: " << endl << endl; + cube.Open(file); + label = *cube.Label(); + cube.Close(true); + cout << label.FindObject("IsisCube").FindObject("Core").FindGroup("Dimensions") << endl << endl; + if (label.FindObject("IsisCube").HasGroup("Instrument")) { + cout << label.FindObject("IsisCube").FindGroup("Instrument") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("Mapping")) { + cout << label.FindObject("IsisCube").FindGroup("Mapping") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("AlphaCube")) { + cout << label.FindObject("IsisCube").FindGroup("AlphaCube") << endl << endl; + } + + results.Clear(); + + ProcessByLine p5; + p5.SetInputCube("FROM1"); + linc = 1.0; + sinc = 2.5; + onl = (int)ceil ((double)(el - sl + 1) / linc); + ons = (int)ceil ((double)(es - ss + 1) / sinc); + onomapcube = p5.SetOutputCube("TO",ons,onl,1); + + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("StartingLine", sl); + results += PvlKeyword ("StartingSample", ss); + results += PvlKeyword ("EndingLine", el); + results += PvlKeyword ("EndingSample", es); + results += PvlKeyword ("LineIncrement", linc); + results += PvlKeyword ("SampleIncrement", sinc); + results += PvlKeyword ("OutputLines", onl); + results += PvlKeyword ("OutputSamples", ons); + + s.SetSubArea(inl,ins,sl,ss,el,es,linc,sinc); + s.UpdateLabel(&inomapcube,onomapcube,results); + + cout << "Testing sub image area with linc=1.0, sinc=2.5 "; + cout << "for unprojected cube..." << endl; + + Isis::Application::Log(results); + cout << endl; + p5.EndProcess(); + + cout << "Output cube label: " << endl << endl; + cube.Open(file); + label = *cube.Label(); + cube.Close(true); + cout << label.FindObject("IsisCube").FindObject("Core").FindGroup("Dimensions") << endl << endl; + if (label.FindObject("IsisCube").HasGroup("Instrument")) { + cout << label.FindObject("IsisCube").FindGroup("Instrument") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("Mapping")) { + cout << label.FindObject("IsisCube").FindGroup("Mapping") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("AlphaCube")) { + cout << label.FindObject("IsisCube").FindGroup("AlphaCube") << endl << endl; + } + + inomapcube.Close(); + + results.Clear(); + + ProcessByLine p6; + p6.SetInputCube("FROM2"); + string from2 = ui.GetFilename("FROM2"); + Cube imapcube; + imapcube.Open(from2); + inl = imapcube.Lines(); + ins = imapcube.Samples(); + sl = 1; + ss = 1; + el = inl; + es = ins; + linc = 1.0; + sinc = 1.0; + onl = (int)ceil ((double)(el - sl + 1) / linc); + ons = (int)ceil ((double)(es - ss + 1) / sinc); + Cube *omapcube = p6.SetOutputCube("TO",ons,onl,1); + + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("StartingLine", sl); + results += PvlKeyword ("StartingSample", ss); + results += PvlKeyword ("EndingLine", el); + results += PvlKeyword ("EndingSample", es); + results += PvlKeyword ("LineIncrement", linc); + results += PvlKeyword ("SampleIncrement", sinc); + results += PvlKeyword ("OutputLines", onl); + results += PvlKeyword ("OutputSamples", ons); + + s.SetSubArea(inl,ins,sl,ss,el,es,linc,sinc); + s.UpdateLabel(&imapcube,omapcube,results); + + cout << "Input projected cube label: " << endl << endl; + inlabel = *imapcube.Label(); + cout << inlabel.FindObject("IsisCube").FindObject("Core").FindGroup("Dimensions") << endl << endl; + if (inlabel.FindObject("IsisCube").HasGroup("Instrument")) { + cout << inlabel.FindObject("IsisCube").FindGroup("Instrument") << endl << endl; + } + if (inlabel.FindObject("IsisCube").HasGroup("Mapping")) { + cout << inlabel.FindObject("IsisCube").FindGroup("Mapping") << endl << endl; + } + if (inlabel.FindObject("IsisCube").HasGroup("AlphaCube")) { + cout << inlabel.FindObject("IsisCube").FindGroup("AlphaCube") << endl << endl; + } + + cout << "Testing no change in image area for projected cube..." << endl; + Isis::Application::Log(results); + cout << endl; + p6.EndProcess(); + + cout << "Output cube label: " << endl << endl; + cube.Open(file); + label = *cube.Label(); + cube.Close(true); + cout << label.FindObject("IsisCube").FindObject("Core").FindGroup("Dimensions") << endl << endl; + if (label.FindObject("IsisCube").HasGroup("Instrument")) { + cout << label.FindObject("IsisCube").FindGroup("Instrument") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("Mapping")) { + cout << label.FindObject("IsisCube").FindGroup("Mapping") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("AlphaCube")) { + cout << label.FindObject("IsisCube").FindGroup("AlphaCube") << endl << endl; + } + + results.Clear(); + + ProcessByLine p7; + p7.SetInputCube("FROM2"); + linc = 2.0; + sinc = 2.0; + onl = (int)ceil ((double)(el - sl + 1) / linc); + ons = (int)ceil ((double)(es - ss + 1) / sinc); + omapcube = p7.SetOutputCube("TO",ons,onl,1); + + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("StartingLine", sl); + results += PvlKeyword ("StartingSample", ss); + results += PvlKeyword ("EndingLine", el); + results += PvlKeyword ("EndingSample", es); + results += PvlKeyword ("LineIncrement", linc); + results += PvlKeyword ("SampleIncrement", sinc); + results += PvlKeyword ("OutputLines", onl); + results += PvlKeyword ("OutputSamples", ons); + + s.SetSubArea(inl,ins,sl,ss,el,es,linc,sinc); + s.UpdateLabel(&imapcube,omapcube,results); + + cout << "Testing full image area with linc=2, sinc=2 "; + cout << "for projected cube..." << endl; + + Isis::Application::Log(results); + cout << endl; + p7.EndProcess(); + + cout << "Output cube label: " << endl << endl; + cube.Open(file); + label = *cube.Label(); + cube.Close(true); + cout << label.FindObject("IsisCube").FindObject("Core").FindGroup("Dimensions") << endl << endl; + if (label.FindObject("IsisCube").HasGroup("Instrument")) { + cout << label.FindObject("IsisCube").FindGroup("Instrument") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("Mapping")) { + cout << label.FindObject("IsisCube").FindGroup("Mapping") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("AlphaCube")) { + cout << label.FindObject("IsisCube").FindGroup("AlphaCube") << endl << endl; + } + + results.Clear(); + + ProcessByLine p8; + p8.SetInputCube("FROM2"); + linc = 2.0; + sinc = 3.0; + onl = (int)ceil ((double)(el - sl + 1) / linc); + ons = (int)ceil ((double)(es - ss + 1) / sinc); + omapcube = p8.SetOutputCube("TO",ons,onl,1); + + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("StartingLine", sl); + results += PvlKeyword ("StartingSample", ss); + results += PvlKeyword ("EndingLine", el); + results += PvlKeyword ("EndingSample", es); + results += PvlKeyword ("LineIncrement", linc); + results += PvlKeyword ("SampleIncrement", sinc); + results += PvlKeyword ("OutputLines", onl); + results += PvlKeyword ("OutputSamples", ons); + + s.SetSubArea(inl,ins,sl,ss,el,es,linc,sinc); + s.UpdateLabel(&imapcube,omapcube,results); + + cout << "Testing full image area with linc=2, sinc=3 "; + cout << "for projected cube..." << endl; + + Isis::Application::Log(results); + cout << endl; + p8.EndProcess(); + + cout << "Output cube label: " << endl << endl; + cube.Open(file); + label = *cube.Label(); + cube.Close(true); + cout << label.FindObject("IsisCube").FindObject("Core").FindGroup("Dimensions") << endl << endl; + if (label.FindObject("IsisCube").HasGroup("Instrument")) { + cout << label.FindObject("IsisCube").FindGroup("Instrument") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("Mapping")) { + cout << label.FindObject("IsisCube").FindGroup("Mapping") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("AlphaCube")) { + cout << label.FindObject("IsisCube").FindGroup("AlphaCube") << endl << endl; + } + + results.Clear(); + + ProcessByLine p9; + p9.SetInputCube("FROM2"); + sl = 25; + ss = 10; + el = inl - 33; + es = ins - 18; + linc = .5; + sinc = .5; + onl = (int)ceil ((double)(el - sl + 1) / linc); + ons = (int)ceil ((double)(es - ss + 1) / sinc); + omapcube = p9.SetOutputCube("TO",ons,onl,1); + + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("StartingLine", sl); + results += PvlKeyword ("StartingSample", ss); + results += PvlKeyword ("EndingLine", el); + results += PvlKeyword ("EndingSample", es); + results += PvlKeyword ("LineIncrement", linc); + results += PvlKeyword ("SampleIncrement", sinc); + results += PvlKeyword ("OutputLines", onl); + results += PvlKeyword ("OutputSamples", ons); + + s.SetSubArea(inl,ins,sl,ss,el,es,linc,sinc); + s.UpdateLabel(&imapcube,omapcube,results); + + cout << "Testing sub image area with linc=.5, sinc=.5 "; + cout << "for projected cube..." << endl; + + Isis::Application::Log(results); + cout << endl; + p9.EndProcess(); + + cout << "Output cube label: " << endl << endl; + cube.Open(file); + label = *cube.Label(); + cube.Close(true); + cout << label.FindObject("IsisCube").FindObject("Core").FindGroup("Dimensions") << endl << endl; + if (label.FindObject("IsisCube").HasGroup("Instrument")) { + cout << label.FindObject("IsisCube").FindGroup("Instrument") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("Mapping")) { + cout << label.FindObject("IsisCube").FindGroup("Mapping") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("AlphaCube")) { + cout << label.FindObject("IsisCube").FindGroup("AlphaCube") << endl << endl; + } + + results.Clear(); + + ProcessByLine p10; + p10.SetInputCube("FROM2"); + linc = 1.0; + sinc = 2.5; + onl = (int)ceil ((double)(el - sl + 1) / linc); + ons = (int)ceil ((double)(es - ss + 1) / sinc); + omapcube = p10.SetOutputCube("TO",ons,onl,1); + + results += PvlKeyword ("InputLines", inl); + results += PvlKeyword ("InputSamples", ins); + results += PvlKeyword ("StartingLine", sl); + results += PvlKeyword ("StartingSample", ss); + results += PvlKeyword ("EndingLine", el); + results += PvlKeyword ("EndingSample", es); + results += PvlKeyword ("LineIncrement", linc); + results += PvlKeyword ("SampleIncrement", sinc); + results += PvlKeyword ("OutputLines", onl); + results += PvlKeyword ("OutputSamples", ons); + + s.SetSubArea(inl,ins,sl,ss,el,es,linc,sinc); + s.UpdateLabel(&imapcube,omapcube,results); + + cout << "Testing sub image area with linc=1.0, sinc=2.5 "; + cout << "for projected cube..." << endl; + + Isis::Application::Log(results); + cout << endl; + p10.EndProcess(); + + cout << "Output cube label: " << endl << endl; + cube.Open(file); + label = *cube.Label(); + cube.Close(true); + cout << label.FindObject("IsisCube").FindObject("Core").FindGroup("Dimensions") << endl << endl; + if (label.FindObject("IsisCube").HasGroup("Instrument")) { + cout << label.FindObject("IsisCube").FindGroup("Instrument") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("Mapping")) { + cout << label.FindObject("IsisCube").FindGroup("Mapping") << endl << endl; + } + if (label.FindObject("IsisCube").HasGroup("AlphaCube")) { + cout << label.FindObject("IsisCube").FindGroup("AlphaCube") << endl << endl; + } + + imapcube.Close(); + + results.Clear(); +} diff --git a/isis/src/base/objs/SubArea/unitTest.xml b/isis/src/base/objs/SubArea/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..0257b11f8f9836bff3d201589ac5df4d8c420e83 --- /dev/null +++ b/isis/src/base/objs/SubArea/unitTest.xml @@ -0,0 +1,67 @@ + + + + Unit test for SubArea class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + + + + + cube + input + + Test cube + + + Test cube + + + *.cub + + unitTest_nomap.cub + + + cube + input + + Test cube + + + Test cube + + + *.cub + + unitTest_map.cub + + + cube + output + + Test cube + + + Test cube + + + *.cub + + /tmp/isissubarea_01.cub + + + + diff --git a/isis/src/base/objs/SurfaceModel/Makefile b/isis/src/base/objs/SurfaceModel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7d93d7b3e24337734dc4c55836b26e2da1de03d6 --- /dev/null +++ b/isis/src/base/objs/SurfaceModel/Makefile @@ -0,0 +1,5 @@ +INCS = SurfaceModel.h +SRCS = SurfaceModel.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/SurfaceModel/SurfaceModel.cpp b/isis/src/base/objs/SurfaceModel/SurfaceModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..877b36565d6477144df368c4b4c08882060ccc43 --- /dev/null +++ b/isis/src/base/objs/SurfaceModel/SurfaceModel.cpp @@ -0,0 +1,93 @@ +#include "SurfaceModel.h" + +namespace Isis { + //! Constructor + SurfaceModel::SurfaceModel () { + p_poly2d = new PolynomialBivariate(2); + p_lsq = new LeastSquares(*p_poly2d); + } + + //! Destructor + SurfaceModel::~SurfaceModel() { + delete p_lsq; + delete p_poly2d; + } + + //! Add a single (x,y,z) triplet to the list of knowns. + //! After all knowns are added invoke the Solve method + void SurfaceModel::AddTriplet (const double x, const double y, const double z) { + std::vector vec; + vec.push_back(x); + vec.push_back(y); + p_lsq->AddKnown(vec,z); + } + + //! Add an array of (x,y,z) triplet to the list of knowns + //! After all knowns are added invoke the Solve method + void SurfaceModel::AddTriplets (const double *x, const double *y, + const double *z, const int n) { + for (int i=0; i &x, + const std::vector &y, + const std::vector &z) { + for (int i=0; i<(int)x.size(); i++) { + AddTriplet(x[i],y[i],z[i]); + } + } + + //! Fit a surface to the input triplets + void SurfaceModel::Solve() { + p_lsq->Solve(); + } + + //! Evaluate at x,y to compute z. This is available after the + //! Solve method is invoked + double SurfaceModel::Evaluate (const double x, const double y) { + std::vector vec; + vec.push_back(x); + vec.push_back(y); + return p_lsq->Evaluate(vec); + } + + /** After invoking Solve, a coordinate (x,y) at a local minimum (or + * maximum) of the surface model can be computed using this method. + * + * @return A zero if successful, otherwise, the surface is a plane + * and has no min/max + */ + int SurfaceModel::MinMax(double &x, double &y) { + /* For a PolynomialBivariate of 2nd degree, the partial derivatives are two lines: + * + * dz/dx = b + 2dx + ey + * dz/dy = c + ex + 2fy + * + * We will have a local min/max where dz/dx and dz/dy = 0. + * Solve using that condition using linear algebra yields: + * + * xlocal = (ce - 2bf) / (4df - ee) + * ylocal = (be - 2cd) / (4df - ee) + */ + + // Get coefficients + double b = p_poly2d->Coefficient(1); + double c = p_poly2d->Coefficient(2); + double d = p_poly2d->Coefficient(3); + double e = p_poly2d->Coefficient(4); + double f = p_poly2d->Coefficient(5); + + // Compute the determinant + double det = 4.0*d*f - e*e; + if (det == 0.0) return 1; + + // Compute local min/max + x = (c*e - 2.0*b*f) / det; + y = (b*e - 2.0*c*d) / det; + return 0; + } +} diff --git a/isis/src/base/objs/SurfaceModel/SurfaceModel.h b/isis/src/base/objs/SurfaceModel/SurfaceModel.h new file mode 100644 index 0000000000000000000000000000000000000000..2f92ad07f78efe31d105e812075cf559551cd4f2 --- /dev/null +++ b/isis/src/base/objs/SurfaceModel/SurfaceModel.h @@ -0,0 +1,73 @@ +#ifndef SurfaceModel_h +#define SurfaceModel_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/06/18 20:42:32 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "PolynomialBivariate.h" +#include "LeastSquares.h" + +namespace Isis { + /** + * @brief Model a 3-D surface + * + * Given a set of (x,y,z) triplets, this class will model the surface + * that best fits the points. The equation to be modelled is: + * + * @f[ + * z = a + b*x + c*y + d*x^2 + e*x*y + f*y^2 + * @f] + * + * @ingroup Math + * + * @author 2005-05-09 Jeff Anderson + * + * @internal + * @history 2008-06-18 Steven Lambright Fixed ifndef command + * + * @todo Add plot and/or visualize method + */ + class SurfaceModel { + public: + SurfaceModel (); + ~SurfaceModel(); + + void AddTriplet (const double x, const double y, const double z); + void AddTriplets (const double *x, const double *y, const double *z, + const int n); + void AddTriplets (const std::vector &x, + const std::vector &y, + const std::vector &z); + + void Solve(); + double Evaluate (const double x, const double y); + + int MinMax(double &x, double &y); + + private: + LeastSquares *p_lsq; + PolynomialBivariate *p_poly2d; + }; +}; + +#endif diff --git a/isis/src/base/objs/SurfaceModel/SurfaceModel.truth b/isis/src/base/objs/SurfaceModel/SurfaceModel.truth new file mode 100644 index 0000000000000000000000000000000000000000..bce2e8c58de724d6fcb8ff19c9d12208988c49ad --- /dev/null +++ b/isis/src/base/objs/SurfaceModel/SurfaceModel.truth @@ -0,0 +1,11 @@ +add 1 +add 2 +Solve +1 +6 +2 +2 +3 +2 +1.28571 -4.71429 +-0.285714 diff --git a/isis/src/base/objs/SurfaceModel/unitTest.cpp b/isis/src/base/objs/SurfaceModel/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bdc449cabb183a23895b47b6bdb476ac61551493 --- /dev/null +++ b/isis/src/base/objs/SurfaceModel/unitTest.cpp @@ -0,0 +1,50 @@ +#include +#include +#include "SurfaceModel.h" +#include "iException.h" +#include "Preference.h" + +int main () { + Isis::Preference::Preferences(true); + + try { + Isis::SurfaceModel s; + + double x[] = {0,1,1}; + double y[] = {0,1,-1}; + double z[] = {1,6,2}; + + std::vector x1,y1,z1; + x1.push_back(-1); + x1.push_back(-1); + x1.push_back(0); + y1.push_back(1); + y1.push_back(-1); + y1.push_back(1); + z1.push_back(2); + z1.push_back(3); + z1.push_back(2); + + std::cout << "add 1" << std::endl; + s.AddTriplets(x,y,z,3); + std::cout << "add 2" << std::endl; + s.AddTriplets(x1,y1,z1); + std::cout << "Solve" << std::endl; + s.Solve(); + std::cout << s.Evaluate(0,0) << std::endl; + std::cout << s.Evaluate(1,1) << std::endl; + std::cout << s.Evaluate(1,-1) << std::endl; + std::cout << s.Evaluate(-1,1) << std::endl; + std::cout << s.Evaluate(-1,-1) << std::endl; + std::cout << s.Evaluate(0,1) << std::endl; + + double mx,my; + s.MinMax(mx,my); + + std::cout << mx << " " << my << std::endl; + std::cout << s.Evaluate(mx,my) << std::endl; + } + catch (Isis::iException &e) { + e.Report(); + } +} diff --git a/isis/src/base/objs/System/Makefile b/isis/src/base/objs/System/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7007031c6d210bcb7ccfe838196e9416d568e0bb --- /dev/null +++ b/isis/src/base/objs/System/Makefile @@ -0,0 +1,5 @@ +INCS = System.h +SRCS = System.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/System/System.cpp b/isis/src/base/objs/System/System.cpp new file mode 100644 index 0000000000000000000000000000000000000000..41ae236ab1bbddf8e76cad1e7abafb18cf1e1695 --- /dev/null +++ b/isis/src/base/objs/System/System.cpp @@ -0,0 +1,302 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/07/09 17:59:17 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "System.h" +#include "Filename.h" +#include "iString.h" +#include "iException.h" +#include + +using namespace std; +namespace Isis { + + /** + * Runs the command contained in the argument + * + * @param command Command to be executed + * + * @throws Isis::iException::Programmer + */ + void System (string &command) { + int status = system (command.c_str()); + + if (status != 0) { + string msg = "Unable to execute [" + command + + "] return status [" + Isis::iString(status) + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,msg, _FILEINFO_); + } + + return; + } + + /** + * Runs various system specific uname commands and returns the results + * + * @return PvlGroup containing uname information + */ + PvlGroup GetUnameInfo () { + // Create a temporary file to store console output to + Isis::Filename temp; + temp.Temporary("/tmp/UnameConsoleInfo","txt"); + std::string tempFile = temp.Expanded(); + + // Uname commands output to temp file with each of the following + // values on its own line in this order: + // machine hardware name, processor, hardware platform name, + // operating system, kernel name, kernel version, kernel release, all + Isis::PvlGroup unameGroup("UNAME"); + std::ifstream readTemp; + + #if defined(__linux__) + // Write uname outputs to temp file + string uname1 = "uname -m > " + tempFile; + string uname2 = "uname -p >> " + tempFile; + string uname3 = "uname -i >> " + tempFile; + string uname4 = "uname -o >> " + tempFile; + string uname5 = "uname -s >> " + tempFile; + string uname6 = "uname -v >> " + tempFile; + string uname7 = "uname -r >> " + tempFile; + string uname8 = "uname -a >> " + tempFile; + System (uname1); + System (uname2); + System (uname3); + System (uname4); + System (uname5); + System (uname6); + System (uname7); + System (uname8); + // Read data from temp file + char value[256]; + readTemp.open(tempFile.c_str(), ifstream::in); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("MachineHardware", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("Processor", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("HardwarePlatform", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("OperatingSystem", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("KernelName", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("KernelVersion", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("KernelRelease", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("FullUnameString", value)); + + #elif defined(__APPLE__) + // Write uname outputs to temp file + string uname1 = "uname -m > " + tempFile; + string uname2 = "uname -p >> " + tempFile; + string uname3 = "uname -s >> " + tempFile; + string uname4 = "uname -v >> " + tempFile; + string uname5 = "uname -r >> " + tempFile; + string uname6 = "uname -a >> " + tempFile; + System (uname1); + System (uname2); + System (uname3); + System (uname4); + System (uname5); + System (uname6); + // Read data from temp file + char value[256]; + readTemp.open(tempFile.c_str(), ifstream::in); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("MachineHardware", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("Processor", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("OperatingSystem", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("OperatingSystemVersion", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("OperatingSystemRelease", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("FullUnameString", value)); + + #elif defined (__sun__) + // Write uname outputs to temp file + string uname1 = "uname -m > " + tempFile; + string uname2 = "uname -p >> " + tempFile; + string uname3 = "uname -i >> " + tempFile; + string uname4 = "uname -s >> " + tempFile; + string uname5 = "uname -v >> " + tempFile; + string uname6 = "uname -r >> " + tempFile; + string uname7 = "uname -a >> " + tempFile; + System (uname1); + System (uname2); + System (uname3); + System (uname4); + System (uname5); + System (uname6); + System (uname7); + // Read data from temp file + char value[256]; + readTemp.open(tempFile.c_str(), ifstream::in); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("MachineHardware", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("Processor", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("HardwarePlatform", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("OperatingSystem", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("OperatingSystemVersion", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("OperatingSystemRelease", value)); + readTemp.getline(value,256); + unameGroup.AddKeyword(Isis::PvlKeyword("FullUnameString", value)); + #endif + + // remove temp file and return + std::string cleanup = "rm -f " + tempFile; + System (cleanup); + return unameGroup; + } + + /** + * Runs some printenv commands that return Isis related Enviroment Variables. + * + * @return PvlGroup containing Enviroment information + * @todo Replace printenv commands with c library getenv + * @todo + */ + Isis::PvlGroup GetEnviromentInfo (){ + // Create a temporary file to store console output to + Isis::Filename temp; + temp.Temporary("/tmp/EnviromentInfo","txt"); + std::string tempFile = temp.Expanded(); + Isis::PvlGroup envGroup("EnviromentVariables"); + std::ifstream readTemp; + + string env1 = "printenv SHELL > " + tempFile; + string env2 = "printenv HOME >> " + tempFile; + string env3 = "printenv PWD >> " + tempFile; + string env4; + #if defined(__APPLE__) + env4 = "printenv DYLD_LIBRARY_PATH >> " + tempFile; + #else + env4 = "printenv LD_LIBRARY_PATH >> " + tempFile; + #endif + string env5 = "printenv ISISROOT >> " + tempFile; + string env6 = "printenv ISIS3DATA >> " + tempFile; + System (env1); + System (env2); + System (env3); + System (env4); + System (env5); + System (env6); + // Read data from temp file + char value[511]; + readTemp.open(tempFile.c_str(), ifstream::in); + readTemp.getline(value,255); + envGroup.AddKeyword(Isis::PvlKeyword("Shell", value)); + readTemp.getline(value,255); + envGroup.AddKeyword(Isis::PvlKeyword("Home", value)); + readTemp.getline(value,255); + envGroup.AddKeyword(Isis::PvlKeyword("Pwd", value)); + readTemp.getline(value,511); + #if defined(__APPLE__) + envGroup.AddKeyword(Isis::PvlKeyword("DYLDLibraryPath", value)); + #else + envGroup.AddKeyword(Isis::PvlKeyword("LDLibraryPath", value)); + #endif + readTemp.getline(value,255); + envGroup.AddKeyword(Isis::PvlKeyword("ISISROOT", value)); + readTemp.getline(value,255); + envGroup.AddKeyword(Isis::PvlKeyword("ISIS3DATA", value)); + + // remove temp file and return + std::string cleanup = "rm -f " + tempFile; + System (cleanup); + return envGroup; + } + + /** + * Runs df to see the disk space availability + * + * @return Isis::iString containing df results + */ + Isis::iString SystemDiskSpace (){ + Isis::Filename temp; + temp.Temporary("/tmp/SystemDiskSpace","txt"); + std::string tempFile = temp.Expanded(); + std::ifstream readTemp; + string diskspace = "df > " + tempFile; + System (diskspace); + readTemp.open(tempFile.c_str(), ifstream::in); + + iString results = ""; + char tmp[512]; + while(!readTemp.eof()){ + readTemp.getline(tmp,512); + results += tmp; + results += "\n"; + } + + // remove temp file and return + std::string cleanup = "rm -f " + tempFile; + System (cleanup); + return results; + } + + /** + * Runs ldd on linux and sun and otool on macs to get information about the applicaiton run + * + * @return Isis::iString containing application information + */ + Isis::iString GetLibraryDependencies (const std::string &file){ + Isis::Filename temp; + temp.Temporary("/tmp/LibraryDependencies","txt"); + std::string tempFile = temp.Expanded(); + std::ifstream readTemp; + string dependencies = ""; + #if defined(__linux__) + dependencies = "ldd -v " + file + " > " + tempFile; + #elif defined(__APPLE__) + dependencies = "otool -L " + file + " > " + tempFile; + #elif defined (__sun__) + dependencies = "ldd -v " + file + " > " + tempFile; + #endif + System (dependencies); + readTemp.open(tempFile.c_str(), ifstream::in); + + iString results = ""; + char tmp[512]; + while(!readTemp.eof()){ + readTemp.getline(tmp,512); + results += tmp; + results += "\n"; + } + + // remove temp file and return + std::string cleanup = "rm -f " + tempFile; + System (cleanup); + return results; + } +} // end namespace isis diff --git a/isis/src/base/objs/System/System.h b/isis/src/base/objs/System/System.h new file mode 100644 index 0000000000000000000000000000000000000000..552d7537aa8e055b88069b8fa5f708eee8532bdd --- /dev/null +++ b/isis/src/base/objs/System/System.h @@ -0,0 +1,59 @@ +#ifndef System_h +#define System_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/07/09 17:59:17 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "PvlGroup.h" + +namespace Isis { + /** + * @brief Execute a system command + * + * Allows system commands to be executed. These include but are not limited to + * running Isis programs. + * + * @ingroup Utility + * + * @author 2004-01-12 Stuart Sides + * + * @internal + * @history - 2005-02-16 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * + * @history - 2007-10-04 Steven Koechle - Added GetUnameInfo, + * GetEnviromentInfo, SystemDiskSpace, and + * GetLibraryDependencies. + * @history - 2008-07-09 SK - fixed problem with one of the printenv calls + * + * @todo 2005-02-16 Stuart Sides - add coded and implementation examples + */ + + void System (std::string &command); + Isis::PvlGroup GetUnameInfo (); + Isis::PvlGroup GetEnviromentInfo (); + Isis::iString SystemDiskSpace (); + Isis::iString GetLibraryDependencies (const std::string &file); +} + +#endif + diff --git a/isis/src/base/objs/System/System.truth b/isis/src/base/objs/System/System.truth new file mode 100644 index 0000000000000000000000000000000000000000..03583b81d35a61ead0502f4741b18ca9b507fa6e --- /dev/null +++ b/isis/src/base/objs/System/System.truth @@ -0,0 +1,4 @@ +Unit test for Isis::System +System.cpp +System.h +unitTest.cpp diff --git a/isis/src/base/objs/System/unitTest.cpp b/isis/src/base/objs/System/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..562ce367f42331206a9deb28dfcf3664c6829fab --- /dev/null +++ b/isis/src/base/objs/System/unitTest.cpp @@ -0,0 +1,22 @@ +#include +#include "iException.h" +#include "System.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Unit test for Isis::System" << endl; + + try { + string command = "ls -1 *.cpp *.h"; + Isis::System (command); + } + catch (Isis::iException &error) { + error.Report (false); + } +} + + + diff --git a/isis/src/base/objs/Table/Makefile b/isis/src/base/objs/Table/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..57bbed87cf9cf8a948900e24473819415ed4ebdf --- /dev/null +++ b/isis/src/base/objs/Table/Makefile @@ -0,0 +1,5 @@ +INCS = Table.h +SRCS = Table.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Table/Table.cpp b/isis/src/base/objs/Table/Table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa0644ffad4d73c926fe11e56b7ac094d63bf595 --- /dev/null +++ b/isis/src/base/objs/Table/Table.cpp @@ -0,0 +1,270 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/05/14 19:17:09 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Table.h" +#include "iException.h" +#include "Endian.h" + +using namespace std; +namespace Isis { + /** + * Constructor for creating a table + * + * @param tableName Name of the Table to be read + * + * @param rec Name of the TableRecord to be read into the Table + */ + Table::Table(const std::string &tableName, Isis::TableRecord &rec) : + Isis::Blob(tableName, "Table") { + p_assoc = Table::None; + p_blobPvl += Isis::PvlKeyword("Records", 0); + p_blobPvl += Isis::PvlKeyword("ByteOrder", "NULL"); + for(int f = 0; f < rec.Fields(); f++) p_blobPvl.AddGroup(rec[f].PvlGroup()); + p_record = rec; + } + + /** + * Constructor for reading a table + * + * @param tableName Name of the Table to be read + * + * @param file Name of the file to be read into the Table + */ + Table::Table(const std::string &tableName, const std::string &file) : + Isis::Blob(tableName, "Table") { + p_assoc = Table::None; + Read(file); + } + + /** + * Copy constructor for table + * + * @param other The table to copy from + */ + Table::Table(const Table &other) : Blob(other) { + p_record = other.p_record; + p_records = other.p_records; + p_assoc = other.p_assoc; + p_swap = other.p_swap; + + for(unsigned int i = 0; i < other.p_recbufs.size(); i++) { + char *data = new char[RecordSize()]; + + for(int j = 0; j < RecordSize(); j++) { + data[j] = other.p_recbufs[i][j]; + } + + p_recbufs.push_back(data); + } + }; + + Table &Table::operator=(const Isis::Table &other) { + *((Isis::Blob *)this) = *((Isis::Blob *)&other); + p_record = other.p_record; + p_records = other.p_records; + p_assoc = other.p_assoc; + p_swap = other.p_swap; + + for(unsigned int i = 0; i < other.p_recbufs.size(); i++) { + char *data = new char[RecordSize()]; + + for(int j = 0; j < RecordSize(); j++) { + data[j] = other.p_recbufs[i][j]; + } + + p_recbufs.push_back(data); + } + + return *this; + } + + /** + * Constructor for reading a table + * + * @param tableName Name of the Table to be read + */ + Table::Table(const std::string &tableName) : + Isis::Blob(tableName, "Table") { + p_assoc = Table::None; + } + + //! Destroys the Table object + Table::~Table() { + Clear(); + } + + /** + * Reads a TableRecord from the Table + * + * @param index Index where desired TableRecord is located + * + * @return Returns the TableRecord at specific index + */ + Isis::TableRecord &Table::operator[](const int index) { + p_record.Unpack(p_recbufs[index]); + return p_record; + } + + /** + * Adds a TableRecord to the Table + * + * @param rec The record to be added to the table + */ + void Table::operator+=(Isis::TableRecord &rec) { + char *newbuf = new char[RecordSize()]; + rec.Pack(newbuf); + p_recbufs.push_back(newbuf); + } + + /** + * Updates a TableRecord + * + * @param rec TableRecord to update old TableRecord with + * + * @param index Index of TableRecord to be updated + */ + void Table::Update(const Isis::TableRecord &rec, const int index) { + rec.Pack(p_recbufs[index]); + } + + /** + * Deletes a TableRecord from the Table + * + * @param index Index of TableRecord to be deleted + */ + void Table::Delete(const int index) { + vector::iterator it = p_recbufs.begin(); + for(int i = 0; i < index; i++, it++); + delete [] p_recbufs[index]; + p_recbufs.erase(it); + } + + //! Virtual function to validate PVL table information + void Table::ReadInit() { + p_records = p_blobPvl["Records"]; + + Isis::TableRecord rec; + for(int g = 0; g < p_blobPvl.Groups(); g++) { + if(p_blobPvl.Group(g).IsNamed("Field")) { + Isis::TableField f(p_blobPvl.Group(g)); + rec += f; + } + } + + p_record = rec; + + if(p_blobPvl.HasKeyword("Association")) { + Isis::iString temp = (string) p_blobPvl["Association"]; + temp.UpCase(); + if(temp == "SAMPLES") p_assoc = Table::Samples; + if(temp == "LINES") p_assoc = Table::Lines; + if(temp == "BANDS") p_assoc = Table::Bands; + } + + // Determine if we need to swap stuff when we read the data + Isis::ByteOrder bo = Isis::ByteOrderEnumeration(p_blobPvl["ByteOrder"]); + p_swap = false; + if(Isis::IsLsb() && (bo == Isis::Msb)) p_swap = true; + if(Isis::IsMsb() && (bo == Isis::Lsb)) p_swap = true; + + // Cleanup in case of a re-read + Clear(); + } + + /** + * Virtual function to Read the data + * + * @param stream InputStream to read data in from + * + * @throws Isis::iException::Io - Error reading or preparing to read a record + */ + void Table::ReadData(std::istream &stream) { + for(int rec = 0; rec < p_records; rec++) { + streampos sbyte = (streampos)(p_startByte - 1) + + (streampos)(rec * RecordSize()); + stream.seekg(sbyte, std::ios::beg); + if(!stream.good()) { + string msg = "Error preparing to read record [" + Isis::iString(rec + 1) + + "] from Table [" + p_blobName + "]"; + throw Isis::iException::Message(Isis::iException::Io, msg, _FILEINFO_); + } + + char *buf = new char[RecordSize()]; + stream.read(buf, RecordSize()); + if(!stream.good()) { + string msg = "Error reading record [" + Isis::iString(rec + 1) + + "] from Table [" + p_blobName + "]"; + throw Isis::iException::Message(Isis::iException::Io, msg, _FILEINFO_); + } + + if(p_swap) p_record.Swap(buf); + p_recbufs.push_back(buf); + } + } + + //! Virtual Function to prepare labels for writing + void Table::WriteInit() { + p_blobPvl["Records"] = Records(); + p_nbytes = Records() * RecordSize(); + + if(Isis::IsLsb()) { + p_blobPvl["ByteOrder"] = Isis::iString(Isis::ByteOrderName(Isis::Lsb)); + } + else { + p_blobPvl["ByteOrder"] = Isis::iString(Isis::ByteOrderName(Isis::Msb)); + } + + if(p_blobPvl.HasKeyword("Association")) { + p_blobPvl.DeleteKeyword("Association"); + } + if(p_assoc == Samples) { + p_blobPvl += Isis::PvlKeyword("Association", "Samples"); + } + else if(p_assoc == Lines) { + p_blobPvl += Isis::PvlKeyword("Association", "Lines"); + } + else if(p_assoc == Bands) { + p_blobPvl += Isis::PvlKeyword("Association", "Bands"); + } + } + + /** + * Virtual function to write the data + * + * @param os Outputstream to write the data to + */ + void Table::WriteData(std::fstream &os) { + for(int rec = 0; rec < Records(); rec++) { + os.write(p_recbufs[rec], RecordSize()); + } + } + + /** + * Clear the table of all records + */ + void Table::Clear() { + for(int i = 0; i < (int)p_recbufs.size(); i++) delete [] p_recbufs[i]; + p_recbufs.clear(); + } +} diff --git a/isis/src/base/objs/Table/Table.h b/isis/src/base/objs/Table/Table.h new file mode 100644 index 0000000000000000000000000000000000000000..71b944953b20791f1fbc737b59832a71027ad3cf --- /dev/null +++ b/isis/src/base/objs/Table/Table.h @@ -0,0 +1,157 @@ +#if !defined(Table_h) +#define Table_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/05/14 19:17:09 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Blob.h" +#include "TableRecord.h" + +namespace Isis { + /** + * @brief Read table blobs + * + * This class reads table blobs from the cubes (or detached + * tables). It is record based, N records in a table. Each + * record will have the same number of fields, F. The fields can + * be of different types including integer, string, and double. + * See the classes TableRecord and TableField for more + * information. The class uses PVL to store the structure of + * the table N, F, and Field types and binary to store the table + * data. + * + * If you would like to see Table being used in implementation, see histats.cpp + * + * @ingroup LowLevelCubeIO + * + * @author 2004-09-01 Jeff Anderson + * + * @internal + * @history 2005-03-18 Elizabeth Ribelin - Added documentation + * to class + * @history 2006-09-19 Jeff Anderson - Added clear method + * @history 2006-09-19 Jeff Anderson - Fixed bug in ReadInit + * method which needed to cleanup pointers to records + * if a re-read occurred. + * @history 2009-02-18 Steven Lambright - Added copy constructor and + * assignment operator. + */ + class Table : public Isis::Blob { + public: + // Constructors and Destructors + Table(const std::string &tableName); + Table(const std::string &tableName, Isis::TableRecord &rec); + Table(const std::string &tableName, const std::string &file); + Table(const Table &other); + + ~Table(); + + // Read a record + Isis::TableRecord &operator[](const int index); + + // Add a record + void operator+=(Isis::TableRecord &rec); + + Table &operator=(const Isis::Table &other); + + // Update a record + void Update(const Isis::TableRecord &rec, const int index); + + // Delete a record + void Delete(const int index); + + /** + * Returns the number of records + * + * @return Number of records + */ + inline int Records() const { + return p_recbufs.size(); + }; + + /** + * Returns the number of bytes per record + * + * @return Number of bytes per record + */ + inline int RecordSize() const { + return p_record.RecordSize(); + }; + + enum Association { None, Samples, Lines, Bands }; + + /** + * Sets the association to the input parameter + * + * @param assoc Association type + */ + void SetAssociation(const Table::Association assoc) { + p_assoc = assoc; + } + + /** + * Checks to see if association is Samples + * + * @return Returns true if association is Samples, and false if it is not + */ + bool IsSampleAssociated() { + return (p_assoc == Table::Samples); + }; + + /** + * Checks to see if association is Lines + * + * @return Returns true if association is Lines, and false if it is not + */ + bool IsLineAssociated() { + return (p_assoc == Table::Lines); + }; + + /** + * Checks to see if association is Bands + * + * @return Returns true if association is Bands, and false if it is not + */ + bool IsBandAssociated() { + return (p_assoc == Table::Bands); + }; + + void Clear(); + + protected: + void ReadInit(); + void ReadData(std::istream &stream); + void WriteInit(); + void WriteData(std::fstream &os); + + Isis::TableRecord p_record; //!< + std::vector p_recbufs; //!< + + int p_records; /** +#include "Table.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + try { + Isis::TableField f1("Column1", Isis::TableField::Integer); + Isis::TableField f2("Column2", Isis::TableField::Double); + Isis::TableField f3("Column3", Isis::TableField::Text, 10); + Isis::TableField f4("Column2", Isis::TableField::Double); + Isis::TableRecord rec; + rec += f1; + rec += f2; + rec += f3; + rec += f4; + Isis::Table t("UNITTEST", rec); + + rec[0] = 5; + rec[1] = 3.14; + rec[2] = "PI"; + rec[3] = 3.14159; + t += rec; + + rec[0] = -1; + rec[1] = 0.5; + rec[2] = "HI"; + rec[3] = -0.55; + t += rec; + + t.Write("tTest"); + + Isis::Table t2("UnitTest", "tTest"); + cout << (int) t2[0][0] << endl; + cout << (double) t2[0][1] << endl; + cout << (string) t2[0][2] << endl; + cout << (double) t2[0][3] << endl; + cout << (int) t2[1][0] << endl; + cout << (double) t2[1][1] << endl; + cout << (string) t2[1][2] << endl; + cout << (double) t2[1][3] << endl; + cout << endl << "Number of Records = " << t2.Records() << endl; + cout << "Record Size = " << t2.RecordSize() << endl; + + rec[0] = 19; + rec[1] = 2.2; + rec[2] = "Blob"; + rec[3] = 4.4; + t2.Update(rec, 0); + t2.SetAssociation(Isis::Table::Lines); + t2.Write("tTest"); + + cout << endl << "Testing Association Checks" << endl; + cout << "Sample Associated? " << t2.IsSampleAssociated() << endl; + cout << "Line Associated? " << t2.IsLineAssociated() << endl; + cout << "Band Associated? " << t2.IsBandAssociated() << endl; + cout << endl; + + Isis::Table t3("UnitTest", "tTest"); + cout << (int) t3[0][0] << endl; + cout << (double) t3[0][1] << endl; + cout << (string) t3[0][2] << endl; + cout << (double) t3[0][3] << endl; + cout << (int) t3[1][0] << endl; + cout << (double) t3[1][1] << endl; + cout << (string) t3[1][2] << endl; + cout << (double) t3[0][3] << endl << endl; + + cout << "Testing Record Delete method..." << endl; + cout << "Number of Records = " << t3.Records() << endl; + cout << "Deleted Record at Index 0" << endl; + t3.Delete(0); + cout << "Number of Records = " << t3.Records() << endl << endl; + + cout << "Testing Clear method..." << endl; + t3.Clear(); + cout << "Number of Records = " << t3.Records() << endl << endl; + remove("tTest"); + + string name1 = "InstrumentPointing"; + Isis::Table table1(name1, "truth.cub"); + for(int i = 0; i < table1.Records(); i++) { + for(int j = 0; j < table1[i].Fields(); j++) { + if(table1[i][j].IsText()) { + cout << (string)table1[i][j] << ","; + } + else if(table1[i][j].IsDouble()) { + cout << (double)table1[i][j] << ","; + } + } + cout << endl; + } + string name2 = "CameraStatistics"; + Isis::Table table2(name2, "truth.cub"); + for(int i = 0; i < table2.Records(); i++) { + for(int j = 0; j < table2[i].Fields(); j++) { + if(table2[i][j].IsText()) { + cout << (string)table2[i][j] << ","; + } + else if(table2[i][j].IsDouble()) { + cout << (double)table2[i][j] << ","; + } + } + cout << endl; + } + + } + catch(Isis::iException &e) { + e.Report(); + } +} + diff --git a/isis/src/base/objs/TableField/Makefile b/isis/src/base/objs/TableField/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..15357e8da40567220103e451188ccf4a1d24def8 --- /dev/null +++ b/isis/src/base/objs/TableField/Makefile @@ -0,0 +1,5 @@ +INCS = TableField.h +SRCS = TableField.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/TableField/TableField.cpp b/isis/src/base/objs/TableField/TableField.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2fa57cf4f6b428ab4a289ca979ed06c7e3c6b177 --- /dev/null +++ b/isis/src/base/objs/TableField/TableField.cpp @@ -0,0 +1,415 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/05/31 22:20:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "TableField.h" +#include "iException.h" + +using namespace std; +namespace Isis { + + /** + * Constructs a TableField object + * + * @param name The name of the field + * + * @param type The type of the field + * + * @param size The size of the field. Defaults to 0. + */ + TableField::TableField(const std::string &name, Isis::TableField::Type type, + int size) { + p_name = name; + p_type = type; + p_size = size; + if (p_type == TableField::Integer) { + p_bytes = 4 * p_size; + p_ivalues.resize(p_size); + } + else if (p_type == TableField::Double) { + p_bytes = 8 * p_size; + p_dvalues.resize(p_size); + } + else if (p_type == TableField::Text) { + p_bytes = 1 * p_size; + p_svalue.resize(p_size); + } + else if (p_type == TableField::Real) { + p_bytes = 4 * p_size; + p_rvalues.resize(p_size); + } + } + + /** + * Constructs a TableField object from a PvlGroup + * + * @param field PvlGroup containing Name, Size, and Type for new TableField + * object + * + * @throws Isis::iException::Programmer - Invalid field type + */ + TableField::TableField(Isis::PvlGroup &field) { + p_name = (string) field["Name"]; + p_size = (int) field["Size"]; + if ((string) field["Type"] == "Integer") { + p_type = TableField::Integer; + p_bytes = 4 * p_size; + p_ivalues.resize(p_size); + } + else if ((string) field["Type"] == "Double") { + p_type = TableField::Double; + p_bytes = 8 * p_size; + p_dvalues.resize(p_size); + } + else if ((string) field["Type"] == "Text"){ + p_type = TableField::Text; + p_bytes = 1 * p_size; + p_svalue.resize(p_size); + } + else if ((string) field["Type"] == "Real") { + p_type = TableField::Real; + p_bytes = 4 * p_size; + p_rvalues.resize(p_size); + } + else { + string msg = "Field [" + p_name + "] has invalid type"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + } + + //! Destroys the TableField object + TableField::~TableField() { + } + + /** + * + * + * @return + * + * @throws Isis::iException::Programmer - Field is not a Double + */ + TableField::operator double() const { + if (p_type != TableField::Double) { + string msg = "Field [" + p_name + "] is not a Double"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_dvalues[0]; + } + + /** + * + * + * @return + * + * @throws Isis::iException::Programmer - Field is not an Integer + */ + TableField::operator int() const { + if (p_type != TableField::Integer) { + string msg = "Field [" + p_name + "] is not Integer"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_ivalues[0]; + } + + /** + * + * + * @return + * + * @throws Isis::iException::Programmer - Field is not a Real + */ + TableField::operator float() const { + if (p_type != TableField::Real) { + string msg = "Field [" + p_name + "] is not Real"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_rvalues[0]; + } + + /** + * + * + * @return + * + * @throws Isis::iException::Programmer - Field is not a string + */ + TableField::operator std::string() const { + if (p_type != TableField::Text) { + string msg = "Field [" + p_name + "] is not Text"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_svalue; + } + + /** + * + * + * @return + * + * @throws Isis::iException::Programmer - Field is not a Double array + */ + TableField::operator std::vector() const { + if (p_type != TableField::Double) { + string msg = "Field [" + p_name + "] is not a Double array"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_dvalues; + } + + /** + * + * + * @return + * + * @throws Isis::iException::Programmer - Field is not an Integer array + */ + TableField::operator std::vector() const { + if (p_type != TableField::Integer) { + string msg = "Field [" + p_name + "] is not an Integer array"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_ivalues; + } + + /** + * + * + * @return + * + * @throws Isis::iException::Programmer - Field is not an Integer array + */ + TableField::operator std::vector() const { + if (p_type != TableField::Real) { + string msg = "Field [" + p_name + "] is not a Real array"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + return p_rvalues; + } + + /** + * Sets field value equal to input + * + * @param value Integer to be assigned to field value + * + * @throws Isis::iException::Programmer - Field is not an Integer + */ + void TableField::operator=(const int value) { + if (p_type != TableField::Integer) { + string msg = "Field [" + p_name + "] is not an Integer"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + p_ivalues[0] = value; + } + + /** + * Sets field value equal to input + * + * @param value Double to be assigned to field value + * + * @throws Isis::iException::Programmer - Field is not a Double + */ + void TableField::operator=(const double value) { + if (p_type != TableField::Double) { + string msg = "Field [" + p_name + "] is not a Double"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + p_dvalues[0] = value; + } + + /** + * Sets field value equal to input + * + * @param value string to be assigned to field value + * + * @throws Isis::iException::Programmer - Field is not a string + */ + void TableField::operator=(const std::string &value) { + if (p_type != TableField::Text) { + string msg = "Field [" + p_name + "] is not Text"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + p_svalue = value; + } + + /** + * Sets field value equal to input + * + * @param value float to be assigned to field value + * + * @throws Isis::iException::Programmer - Field is not a string + */ + void TableField::operator=(const float value) { + if (p_type != TableField::Real) { + string msg = "Field [" + p_name + "] is not Real"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + p_rvalues[0] = value; + } + + /** + * Sets field value equal to input + * + * @param values Integer vector of values to be assigned to field value + * + * @throws Isis::iException::Programmer - Field is not an Integer + * @throws Isis::iException::Programmer - Vector is not the correct size + */ + void TableField::operator=(const std::vector &values) { + if (p_type != TableField::Integer) { + string msg = "Field [" + p_name + "] is not an Integer"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + else if ((int) values.size() != p_size) { + string msg = "Field [" + p_name + "] values vector is not the correct size"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + p_ivalues = values; + } + + /** + * Sets field value equal to the input + * + * @param values Double vector of values to be assigned to field value + * + * @throws Isis::iException::Programmer - Field is not a Double + * @throws Isis::iException::Programmer - Vector is not the correct size + */ + void TableField::operator=(const std::vector &values) { + if (p_type != TableField::Double) { + string msg = "Field [" + p_name + "] is not a Double"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + else if ((int) values.size() != p_size) { + string msg = "Field [" + p_name + "] values vector is not the correct size"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + p_dvalues = values; + } + + /** + * Sets field value equal to the input + * + * @param values Float vector of values to be assigned to field + * value + * + * @throws Isis::iException::Programmer - Field is not a Real + * @throws Isis::iException::Programmer - Vector is not the correct size + */ + void TableField::operator=(const std::vector &values) { + if (p_type != TableField::Real) { + string msg = "Field [" + p_name + "] is not a Real"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + else if ((int) values.size() != p_size) { + string msg = "Field [" + p_name + "] values vector is not the correct size"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + p_rvalues = values; + } + + /** + * + * + * @param ibuf + * + * @throws Isis::iException::Programmer - Invalid field type + */ + void TableField::operator=(const void *ibuf) { + char *buf = (char *) ibuf; + if (p_type == TableField::Double) { + for (unsigned int i=0; i +#include "PvlGroup.h" + +namespace Isis { + /** + * @brief + * + * + * + * @ingroup LowLevelCubeIO + * + * @author 2004-09-01 Jeff Anderson + * + * @internal + * @history 2005-03-18 Elizabeth Ribelin - Added documentation to the class + * @history 2007-05-28 Steven Lambright - Added 4 byte + * floating point capabilities + * @todo Finish class documentation + */ + class TableField { + public: + enum Type { Integer, Double, Text, Real }; + + //Constructors and Destructor + TableField(const std::string &name, Isis::TableField::Type type, + int size=1); + TableField(Isis::PvlGroup &field); + ~TableField(); + + /** + * Returns the name of the TableField + * + * @return Name of TableField + */ + std::string Name() const { return p_name; }; + + /** + * Checks to see if field type is Integer + * + * @return Returns true if field type is Integer, and false if it is not + */ + bool IsInteger () const { return (p_type == TableField::Integer); }; + + /** + * Checks to see if field type is Double + * + * @return Returns true if field type is Double, and false if it is not + */ + bool IsDouble () const { return (p_type == TableField::Double); }; + + /** + * Checks to see if field type is Text + * + * @return Returns true if field type is Text, and false if it is not + */ + bool IsText () const { return (p_type == TableField::Text); }; + + /** + * Checks to see if field type is Text + * + * @return Returns true if field type is Text, and false if it is not + */ + bool IsReal () const { return (p_type == TableField::Real); }; + + /** + * Returns the number of bytes in the field + * + * @return The number of bytes in the TableField + */ + int Bytes() const { return p_bytes; }; + + /** + * Returns the size of the field + * + * @return The size of the TableField + */ + int Size() const { return p_size; }; + + operator double() const; + operator std::vector() const; + operator int() const; + operator std::vector() const; + operator std::string() const; + operator float() const; + operator std::vector() const; + + void operator=(const int value); + void operator=(const double value); + void operator=(const float value); + void operator=(const std::string &value); + void operator=(const std::vector &values); + void operator=(const std::vector &values); + void operator=(const std::vector &value); + void operator=(const char *buf); + void operator=(const void *buf); + + Isis::PvlGroup PvlGroup(); + + private: + std::string p_name; //! p_ivalues; //! p_dvalues; //! p_rvalues; //! +#include "TableField.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Testing integer singleton" << endl; + Isis::TableField f1("Test",Isis::TableField::Integer); + cout << "Name = " << f1.Name() << endl; + cout << "IsInteger = " << f1.IsInteger() << endl; + cout << "IsDouble = " << f1.IsDouble() << endl; + cout << "IsText = " << f1.IsText() << endl; + cout << "IsReal = " << f1.IsReal() << endl; + cout << "Size = " << f1.Size() << endl; + cout << "Bytes = " << f1.Bytes() << endl; + f1 = 15; + cout << "Value = " << (int)f1 << endl; + Isis::PvlGroup g = f1.PvlGroup(); + cout << g << endl; + cout << "----------------------------------------" << endl; + cout << "Testing double singleton" << endl; + Isis::TableField f2("Test",Isis::TableField::Double); + cout << "Name = " << f2.Name() << endl; + cout << "IsInteger = " << f2.IsInteger() << endl; + cout << "IsDouble = " << f2.IsDouble() << endl; + cout << "IsText = " << f2.IsText() << endl; + cout << "IsReal = " << f2.IsReal() << endl; + cout << "Size = " << f2.Size() << endl; + cout << "Bytes = " << f2.Bytes() << endl; + f2 = -3.14; + cout << "Value = " << (double)f2 << endl; + g = f2.PvlGroup(); + cout << g << endl; + cout << "----------------------------------------" << endl; + cout << "Testing text singleton" << endl; + Isis::TableField f3("Test",Isis::TableField::Text,20); + cout << "Name = " << f3.Name() << endl; + cout << "IsInteger = " << f3.IsInteger() << endl; + cout << "IsDouble = " << f3.IsDouble() << endl; + cout << "IsText = " << f3.IsText() << endl; + cout << "IsReal = " << f3.IsReal() << endl; + cout << "Size = " << f3.Size() << endl; + cout << "Bytes = " << f3.Bytes() << endl; + f3 = "Bah humbug"; + cout << "Value = " << (string)f3 << endl; + g = f3.PvlGroup(); + cout << g << endl; + cout << "----------------------------------------" << endl; + cout << "Testing real singleton" << endl; + Isis::TableField f4("Test",Isis::TableField::Real); + cout << "Name = " << f4.Name() << endl; + cout << "IsInteger = " << f4.IsInteger() << endl; + cout << "IsDouble = " << f4.IsDouble() << endl; + cout << "IsText = " << f4.IsText() << endl; + cout << "IsReal = " << f4.IsReal() << endl; + cout << "Size = " << f4.Size() << endl; + cout << "Bytes = " << f4.Bytes() << endl; + f4 = (float)15.542; + cout << "Value = " << (float)f4 << endl; + g = f4.PvlGroup(); + cout << g << endl; + cout << "----------------------------------------" << endl; + cout << "Testing integer array" << endl; + Isis::TableField f5("Test",Isis::TableField::Integer,3); + cout << "Name = " << f5.Name() << endl; + cout << "IsInteger = " << f5.IsInteger() << endl; + cout << "IsDouble = " << f5.IsDouble() << endl; + cout << "IsText = " << f5.IsText() << endl; + cout << "IsReal = " << f5.IsReal() << endl; + cout << "Size = " << f5.Size() << endl; + cout << "Bytes = " << f5.Bytes() << endl; + vector temp; temp.push_back(3); temp.push_back(2); temp.push_back(1); + f5 = temp; + temp.clear(); + temp = f5; + cout << "Value = " << temp[0] << " " << temp[1] << " " << temp[2] << endl; + g = f5.PvlGroup(); + cout << g << endl; + cout << "----------------------------------------" << endl; + cout << "Testing double array" << endl; + Isis::TableField f6("Test",Isis::TableField::Double,3); + cout << "Name = " << f6.Name() << endl; + cout << "IsInteger = " << f6.IsInteger() << endl; + cout << "IsDouble = " << f6.IsDouble() << endl; + cout << "IsText = " << f6.IsText() << endl; + cout << "IsReal = " << f6.IsReal() << endl; + cout << "Size = " << f6.Size() << endl; + cout << "Bytes = " << f6.Bytes() << endl; + vector tmp; tmp.push_back(1.3); tmp.push_back(2.4); tmp.push_back(-9.2); + f6 = tmp; + tmp.clear(); + tmp = f6; + cout << "Value = " << tmp[0] << " " << tmp[1] << " " << tmp[2] << endl; + g = f6.PvlGroup(); + cout << g << endl; + cout << "----------------------------------------" << endl; + cout << "Testing real array" << endl; + Isis::TableField f7("Test",Isis::TableField::Real,3); + cout << "Name = " << f7.Name() << endl; + cout << "IsInteger = " << f7.IsInteger() << endl; + cout << "IsDouble = " << f7.IsDouble() << endl; + cout << "IsText = " << f7.IsText() << endl; + cout << "IsReal = " << f7.IsReal() << endl; + cout << "Size = " << f7.Size() << endl; + cout << "Bytes = " << f7.Bytes() << endl; + vector tmp2; tmp2.push_back(1.3); tmp2.push_back(2.4); tmp2.push_back(-9.2); + f7 = tmp2; + tmp2.clear(); + tmp2 = f7; + cout << "Value = " << tmp2[0] << " " << tmp2[1] << " " << tmp2[2] << endl; + g = f7.PvlGroup(); + cout << g << endl; + cout << "----------------------------------------" << endl; + + cout<< "Testing integer constructor" << endl ; + Isis::PvlGroup group1("Field"); + + group1 += Isis::PvlKeyword ("name", "Test"); + group1 += Isis::PvlKeyword("type", "Integer"); + group1 += Isis::PvlKeyword("size", 20); + + Isis::TableField f8(group1); + g = f8.PvlGroup(); + cout << g << endl; + cout << "----------------------------------------" << endl; + + cout<< "Testing double constructor" << endl ; + Isis::PvlGroup group2("Field"); + + group2 += Isis::PvlKeyword ("name", "Test"); + group2 += Isis::PvlKeyword("type", "Double"); + group2 += Isis::PvlKeyword("size", 20); + + Isis::TableField f9(group2); + g = f9.PvlGroup(); + cout << g << endl; + cout << "----------------------------------------" << endl; + + cout<< "Testing text constructor" << endl ; + Isis::PvlGroup group3("Field"); + + group3 += Isis::PvlKeyword ("name", "Test"); + group3 += Isis::PvlKeyword("type", "Text"); + group3 += Isis::PvlKeyword("size", 20); + + Isis::TableField f10(group3); + g = f10.PvlGroup(); + cout << g << endl; + cout << "----------------------------------------" << endl; + + cout<< "Testing real constructor" << endl ; + Isis::PvlGroup group4("Field"); + + group4 += Isis::PvlKeyword ("name", "Test"); + group4 += Isis::PvlKeyword("type", "Real"); + group4 += Isis::PvlKeyword("size", 20); + + Isis::TableField f11(group4); + g = f11.PvlGroup(); + cout << g << endl; + cout << "----------------------------------------" << endl; + + cout<< "Testing erroneous type constructor" << endl ; + try{ + Isis::PvlGroup group5("Field"); + + group5 += Isis::PvlKeyword ("name", "Test"); + group5 += Isis::PvlKeyword("type", "BLAH"); + group5 += Isis::PvlKeyword("size", 20); + + Isis::TableField f12(group5); + g = f12.PvlGroup(); + cout << g << endl; + } + catch (Isis::iException &e){ + e.Report(false); + } + cout << "----------------------------------------" << endl; + + cout<< "Testing erroneous size constructor" << endl ; + try{ + Isis::PvlGroup group6("Field"); + + group6 += Isis::PvlKeyword ("name", "Test"); + group6 += Isis::PvlKeyword("type", "Integer"); + group6 += Isis::PvlKeyword("size", -7.3); + + Isis::TableField f13(group6); + g = f13.PvlGroup(); + cout << g << endl; + + } + catch (Isis::iException &e){ + e.Report(false); + } + cout << "----------------------------------------" << endl; + } diff --git a/isis/src/base/objs/TableRecord/Makefile b/isis/src/base/objs/TableRecord/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..02a450e08ff6b163dc062f8c46c63ba06077ba7b --- /dev/null +++ b/isis/src/base/objs/TableRecord/Makefile @@ -0,0 +1,5 @@ +INCS = TableRecord.h +SRCS = TableRecord.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/TableRecord/TableRecord.cpp b/isis/src/base/objs/TableRecord/TableRecord.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58c5902a80774ec4851f665e9932e3150ccf5355 --- /dev/null +++ b/isis/src/base/objs/TableRecord/TableRecord.cpp @@ -0,0 +1,184 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/06/25 18:13:35 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +#include "TableRecord.h" +#include "iString.h" +#include "iException.h" + +using namespace std; +namespace Isis { + + /** + * Returns the number of bytes per record + * + * @return Number of bytes per record + */ + int TableRecord::RecordSize() const { + int bytes = 0; + for (int i=0; i<(int)p_fields.size(); i++) bytes += p_fields[i].Bytes(); + return bytes; + } + + /** + * Returns the TableField in the record whose name corresponds to the + * input string + * + * @param field The name of desired TableField + * + * @return The specified TableField + * + * @throws Isis::iException::Programmer - The field does not exist in the + * record + */ + Isis::TableField &TableRecord::operator[](const std::string &field) { + Isis::iString upTemp = field; + upTemp.UpCase(); + for (int i=0; i<(int)p_fields.size(); i++) { + Isis::iString upField = p_fields[i].Name(); + upField.UpCase(); + if (upTemp == upField) return p_fields[i]; + } + + string msg = "Field [" + field + "] does not exist in record"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + + /** + * + * + * @param buf + * + * @throws Isis::iException::Programmer - Invalid field type + */ + void TableRecord::Pack(char *buf) const { + int sbyte = 0; + for (int f=0; f vals = field; + for (unsigned int i=0; i vals = field; + for (unsigned int i=0; i vals = field; + for (unsigned int i=0; i p_fields; /** +#include "TableRecord.h" +#include "iException.h" +#include "Buffer.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Testing Isis::TableRecord" << endl; + Isis::TableField f1("One",Isis::TableField::Integer); + Isis::TableField f2("Two",Isis::TableField::Double); + Isis::TableField f3("Three",Isis::TableField::Text,50); + Isis::TableField f4("Four",Isis::TableField::Real); + + Isis::TableRecord rec; + rec += f1; + rec += f2; + rec += f3; + rec += f4; + + + cout << "Fields = " << rec.Fields() << endl; + cout << "Record size = " << rec.RecordSize() << endl; + + cout << "-----" << endl; + cout <<"testing pack" << endl; + + char buf[66]; + cout << "Packing..." < + +using namespace std; +namespace Isis { + + //! Constructs an empty TextFile object + TextFile::TextFile() { + } + + /** + * Constructs a TextFile object and opens the specified file (including path). + * + * @param filename Filename (including path) to be opened by TextFile object. + * + * @param openmode Open Mode of file opened by TextFile object. InputOpens file + * for Input: Read Only, Fails if file does not exist + * OutputOpens file for Output: Read / Write - Creates file, + * Fails if file exists. OverwriteOpens file for Output: + * Read / Write - Creates file, Truncates if file exists. + * AppendOpens file for Append: Read / Write- Creates file, + * Appends if file exists. Defaults to "input" + * + * @param extension Extension to be added to filename (added only if not + * already on filename). Defaults to "" + */ + TextFile::TextFile(const std::string &filename, + const char *openmode, const char *extension) { + SetComment(); + SetNewLine(); + Open(filename, openmode, extension); + } + + /** + * Constructs a TextFile object and opens the specified file (including path), + * reads or writes file, leaves file open for further use of the rest of the + * methods + * + * @param filename Filename (including path) to be opened by TextFile object. + * + * @param openmode Open Mode of file opened by TextFile object. InputOpens file + * for Input: Read Only, Fails if file does not exist + * OutputOpens file for Output: Read / Write - Creates file, + * Fails if file exists. OverwriteOpens file for Output: + * Read / Write - Creates file, Truncates if file exists. + * AppendOpens file for Append: Read / Write - Creates file, + * Appends if file exists. Defaults to "input" + * + * @param lines iString Vector to fill if reading or put to file if writing + * + * @param maxLinesToReadWrite Limits the maximum lines read or written; 0=read + * entire file or write entire vectorDefaults to 0 + * + * @param skipComments Controls whether comments lines are filtered; + * true=filter, false=return any line read from + * fileDefaults to true + */ + TextFile::TextFile (const std::string &filename, const char *openmode, + std::vector &lines, const int &maxLinesToReadWrite, + const bool skipComments) { + SetComment(); + SetNewLine(); + Open(filename, openmode); + if (p_openmode == 1) { + GetFile(lines, maxLinesToReadWrite, skipComments); + } + else { + PutFile(lines, maxLinesToReadWrite); + } + } + /** + * Constructs a TextFile object and opens the specified file (including path), + * reads or writes file, leaves file open for further use of the rest of the + * methods + * + * @param filename Filename (including path) to be opened by TextFile object. + * + * @param openmode Open Mode of file opened by TextFile object. InputOpens file + * for Input: Read Only, Fails if file does not exist + * OutputOpens file for Output: Read / Write - Creates file, + * Fails if file exists. OverwriteOpens file for Output: + * Read / Write - Creates file, Truncates if file exists. + * AppendOpens file for Append: Read / Write - Creates file, + * Appends if file exists. Defaults to "input" + * + * @param lines + * + * @param maxLinesToReadWrite Limits the maximum lines read or written; 0=read + * entire file or write entire vectorDefaults to 0 + * + * @param skipComments Controls whether comments lines are filtered; + * true=filter, false=return any line read from + * fileDefaults to true + */ + TextFile::TextFile (const char *filename, const char *openmode, + std::vector &lines, const int &maxLinesToReadWrite, + const bool skipComments) { + string Filename = filename; + TextFile(Filename, openmode, lines, maxLinesToReadWrite, skipComments); + } + + /** + * Constructs a TextFile object and opens the specified file (including path), + * reads or writes file, leaves file open for further use of the rest of the + * methods + * + * @param filename Filename (including path) to be opened by TextFile object. + * + * @param openmode Open Mode of file opened by TextFile object. InputOpens file + * for Input: Read Only, Fails if file does not exist + * OutputOpens file for Output: Read / Write - Creates file, + * Fails if file exists. OverwriteOpens file for Output: + * Read / Write - Creates file, Truncates if file exists. + * AppendOpens file for Append: Read / Write - Creates file, + * Appends if file exists. Defaults to "input" + * + * @param lines + * + * + * @param maxLinesToReadWrite Limits the maximum lines read or written; 0=read + * entire file or write entire vectorDefaults to 0 + * + * @param skipComments Controls whether comments lines are filtered; + * true=filter, false=return any line read from + * fileDefaults to true + */ + TextFile::TextFile (const std::string &filename, const char *openmode, + std::string *lines, const int &maxLinesToReadWrite, + const bool skipComments) { + SetComment(); + SetNewLine(); + Open(filename, openmode); + if (p_openmode == 1) { + GetFile(lines, maxLinesToReadWrite, skipComments); + } + else { + PutFile(lines, maxLinesToReadWrite); + } + } + + /** + * Constructs a TextFile object and opens the specified file (including path), + * reads or writes file, leaves file open for further use of the rest of the + * methods + * + * @param filename Filename (including path) to be opened by TextFile object. + * + * @param openmode Open Mode of file opened by TextFile object. InputOpens file + * for Input: Read Only, Fails if file does not exist + * OutputOpens file for Output: Read / Write - Creates file, + * Fails if file exists. OverwriteOpens file for Output: + * Read / Write - Creates file, Truncates if file exists. + * AppendOpens file for Append: Read / Write - Creates file, + * Appends if file exists. Defaults to "input" + * + * @param lines + * + * @param maxLinesToReadWrite Limits the maximum lines read or written; 0=read + * entire file or write entire vectorDefaults to 0 + * + * @param skipComments Controls whether comments lines are filtered; + * true=filter, false=return any line read from + * fileDefaults to true + */ + TextFile::TextFile (const char *filename, const char *openmode, + std::string *lines, const int &maxLinesToReadWrite, + const bool skipComments) { + string Filename = filename; + TextFile(Filename, openmode, lines, maxLinesToReadWrite, skipComments); + } + + + //! Closes file (if still open). Destroys the TextFile object + TextFile::~TextFile () { + Close(); + } + + + // Methods + +/** + * Opens a text file. + * + * @param filename Filename (including path) to be opened. + * + * @param openmode Open Mode of file to be opened. There are + * four options, "input", "output", "overwrite", + * and "append". "input" opens with in fstream + * option, "output" opens with in, out, and + * trunc fstream options and verifies the file + * does not exist, "overwrite" opens with in, + * out, and trunc fstream options, and "append" + * opens with in, out, and ate(at end) fstream + * options, "append" will open with in and out + * options if the file does not exist. + * + * + * @param extension Extension to be added to filename (added only if not already + * on filename). Defaults to "" + * + * @throws Isis::iException::Programmer + * @throws Isis::iException::Io - output file already exists + * @throws Isis::iException::Io - unable to open file + */ + void TextFile::Open(const std::string &filename, const char *openmode, + const char *extension) { + // Open (filename [,openmode] [, with_extension ]) + // default openmode = 'input' + // default extension = 'txt'; extension = "" opens without default + + // note: in append mode, the input and output pointers move together + + + // Don't open if it already is + if (p_stream.is_open()) { + string message = "TextFile:Open:-> Already opened with this object: [" + + string (openmode) + "]:[" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Programmer, + message,_FILEINFO_); + } + + p_openmode = 0; + + // Save the filename for error messages + + Isis::Filename filenameTmp (filename); + filenameTmp.AddExtension(extension); + p_filename = filenameTmp.Expanded(); + + + // input, output, overwrite, append + + string chkOpenmode = Isis::iString(openmode).DownCase(); + if (chkOpenmode == "input") {p_openmode = 1;} + else if (chkOpenmode == "output") {p_openmode = 2;} + else if (chkOpenmode == "overwrite") {p_openmode = 3;} + else if (chkOpenmode == "append") {p_openmode = 4;} + else { + string message = "TextFile::-> Unknown openmode: (input, output, overwrite, append):[" + + string(openmode) + "]:[" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Programmer, + message,_FILEINFO_); + } + + // Input + if (p_openmode == 1) { + p_stream.open (p_filename.c_str(), fstream::in); + } + // Output + else if (p_openmode == 2) { + // first check if file already exists + if (filenameTmp.Exists()) { + string message = "TextFile:Open: -> Output file already exists [" + + string(openmode) + "]:[" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + + p_stream.open (p_filename.c_str(), fstream::in | fstream::out | fstream::trunc); + p_stream.clear(); + } + // Overwrite + else if (p_openmode == 3) { + p_stream.open (p_filename.c_str(), fstream::in | fstream::out | fstream::trunc); + } + // Append + else if (p_openmode == 4) { + // Open in append if it does exist, otherwise, open in overwrite mode + if (filenameTmp.Exists()) { + p_stream.open (p_filename.c_str(), fstream::in | fstream::out | fstream::ate); + } + else { + p_stream.open (p_filename.c_str(), fstream::in | fstream::out | fstream::trunc); + } + } + + if (!p_stream.is_open()) { + string message = "TextFile:Open:-> Unable to open: [" + + string(openmode) + "]:[" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + bool TextFile::OpenChk(bool bailIfNotOpen) { + if (p_stream.is_open()) { + return(true); + } + else { + if (bailIfNotOpen) { + string message = "TextFile::-> File not open: [" + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Programmer, + message,_FILEINFO_); + } + else { + return(false); + } + } + } + + //! Sets Read / Write pointer to begining of opened file + void TextFile::Rewind () { + OpenChk(true); + if (p_stream.eof()) {p_stream.clear();} + p_stream.seekg(0,ios_base::beg); + } + + //! Closes file. Called automatically by TextFile destructor. + void TextFile::Close() { + if (p_stream.is_open()) { + p_stream.flush(); + p_stream.close(); + } + } + + // vector array + void TextFile::GetFile(std::vector &lines, const int &maxLinesToRead, + const bool skipComments) + { + OpenChk(true); + string line; + int lineCount = 0; + while (GetLine(line, skipComments)) { + if (maxLinesToRead > 0) { + if (lineCount++ >= maxLinesToRead){break;}; + } + lines.push_back(line); + } + } + + // string array + void TextFile::GetFile(std::string *lines, const int &maxLinesToRead, + const bool skipComments) + { + OpenChk(true); + string line; + int lineCount = 0; + while (GetLine(line, skipComments)) { + if (maxLinesToRead > 0) { + if (lineCount > maxLinesToRead){break;}; + } + else if (lines[lineCount] == "\0") {break;} + lines[lineCount] = line; + lineCount++; + } + } + + // vector array + void TextFile::PutFile(std::vector &lines, const int &maxLinesToWrite) + { + OpenChk(true); + for(int lineCount=0; lineCount < (int) lines.size(); lineCount++) { + if (maxLinesToWrite > 0) { + if (lineCount > maxLinesToWrite){break;}; + } + PutLine(lines[lineCount]); + } + } + + // string array + void TextFile::PutFile(const std::string *lines, const int &maxLinesToWrite) + { + OpenChk(true); + int lineCount=0; + while (true) { + if (maxLinesToWrite > 0) { + if (lineCount > maxLinesToWrite){break;}; + } + else if (lines[lineCount] == "\0") {break;} + PutLine(lines[lineCount]); + lineCount++; + } + } + + /** + * Gets next line from file. Returns True if read a line, False if End Of File. + * + * @param line Line read from file, with newline removed. + * + * @param skipComments Controls whether comments lines are filtered; + * true=filter, false=return any line read from + * fileDefaults to true + * + * @return bool + */ + bool TextFile::GetLine(std::string &line, bool skipComments) { + return (p_GetLine(line, skipComments)); + } + + /** + * Gets next line from file. Returns True if read a line, False if End Of File. + * + * @param skipComments Controls whether comments lines are filtered; + * true=filter, false=return any line read from + * fileDefaults to true + * + * @return bool + */ + bool TextFile::GetLine(bool skipComments) { + string line; + return (p_GetLine(line, skipComments)); + } + + /** + * Gets next NON-COMMENT line from file. Returns True if read a line, False if + * End Of File. See SetComment method. + * + * @param line Line read from file, with newline removed. + * + * @return bool + */ + bool TextFile::GetLineNoFilter(std::string &line) { + return (p_GetLine(line, false)); + } + + /** + * Gets next NON-COMMENT line from file. Returns True if read a line, False if + * End Of File. See SetComment method. + * + * @return bool + */ + bool TextFile::GetLineNoFilter() { + string line; + return (p_GetLine(line, false)); + } + + /** + * Gets next line from file. Returns True if read a line, False if End Of File. + * + * @param line Line read from file, with newline removed. + * + * @param chkComment True=Skip Comment Lines, False=Return All Lines. + * + * @return bool + * + * @throws Isis::iException::Io - error reading text file + */ + bool TextFile::p_GetLine(std::string &line, bool chkComment) { + OpenChk(true); + + line = ""; + + // Try to read the next line + getline(p_stream, line); + + // Check for end of file + if (p_stream.eof()) { + return false; + } + + // See if an error occured + if (!p_stream.good()) { + line = ""; + string message = "TextFile:GetLine: -> Error reading text file: [" + + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + + // See if we have a comment and if we need to ignore + if (chkComment) { + if (p_commentString.length()) { + std::string::size_type locComment = line.find(p_commentString, 0); + if ( locComment != string::npos ) { + unsigned int afterWhiteSpace = line.find_first_not_of(" \t\v\b\a", 0); + if ((locComment == 0) || (locComment == afterWhiteSpace)) { + return p_GetLine(line, chkComment); + } + } + } + } + + // We have a good line + return true; + } + + /** + * Writes string to file and appends a 'newline' string. See SetNewLine method. + * + * @param line iString to be written to file. Defaults to "" + */ + void TextFile::PutLine(const std::string &line) { + PutLine(line.c_str()); + } + + /** + * Writes char string to file and appends a 'newline' string. + * See SetNewLine method. + * + * @param line Char string to be written to file.Defaults to "" + * + * @throws Isis::iException::Io - error writing text to file + * @throws Isis::iException::Programmer - input is read only text file, cannot + * write to file + */ + void TextFile::PutLine(const char *line) { + OpenChk(true); + + // Try to write the next line + p_stream << line << p_newLineString; + // See if an error occured + if (!p_stream.good()) { + if (p_openmode != 1) { + string message = "TextFile:PutLine: -> Error writing text file: [" + + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + else { + string message = + "TextFile:PutLine: -> Attempt to write to INPUT - Read Only text file: [" + + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Programmer,message, + _FILEINFO_); + } + } + } + + /** + * Writes string to file, prepends a 'comment' string and appends a 'newline' + * string. See SetComment method and SetNewLine method. + * + * @param line iString to be written to file.Defaults to "" + */ + void TextFile::PutLineComment(const std::string &line){ + PutLine(p_commentString + line); + } + + /** + * Writes char string to file, prepends a 'comment' string and appends a + * 'newline' string. See SetComment method and SetNewLine method. + * + * @param line Char string to be written to file.Defaults to "" + */ + void TextFile::PutLineComment(const char *line){ + PutLine(p_commentString + string(line)); + } + + + string TextFile::GetComment () { + return(p_commentString); + } + + + /** + * Sets the 'comment' string. Default = '#' See ReadFilter method. Skips lines + * that begin with this string. See PutLineComment method. Prepends 'comment' + * string to output line. + * + * @param commentString The string of characters to be used for 'comment' + * lines. Defaults to "#" + */ + void TextFile::SetComment (const char *commentString) { + p_commentString = commentString; + } + + + string TextFile::GetNewLine () { + return(p_newLineString); + } + + /** + * Sets the 'newline' string. Default = '\n'. See PutLine and PutLineComment + * methods. Appends 'newline' string to output line. + * + * @param newLineString The string of characters to be used for 'comment' + * lines. Defaults to "\n" + */ + void TextFile::SetNewLine (const char *newLineString) { + p_newLineString = newLineString; + } + + /** + * Counts number of lines in file. + * + * @param maxLinesToRead Limits lines counted - intended for large files. + * 0=count all lines. n=count up to and including n + * lines; if file longer than n lines, returns n+1. + * Defaults to 0 + * + * @return streamsize + */ + int TextFile::LineCount(const int &maxLinesToRead) { + OpenChk(true); + + // LineCount ( [maxLinesToRead] ) --- returns number of lines in open file + + bool eofStat = false; + if (p_stream.eof()) { // current state of stream is 'eof' + eofStat = true; + p_stream.clear(); + } + + streampos savePos = p_stream.tellg(); + p_stream.seekg(0,ios_base::beg); + + int lineCount = 0; + string tmpLine; + if (maxLinesToRead > 0) { + while ( (getline(p_stream, tmpLine)) && (lineCount <= maxLinesToRead)) { + lineCount++; + } + } + else { + while (getline(p_stream, tmpLine)) {lineCount++;} + } + + if (p_stream.eof()) {p_stream.clear();} + + p_stream.seekg(savePos,ios_base::beg); + + if (eofStat) { // restore current state of stream 'eof' + p_stream.seekg(0,ios_base::end); + p_stream.get(); + } + return lineCount; + } + + /** + * Counts number of bytes in file. + * + * @return streamsize + */ + streamsize TextFile::Size() { + OpenChk(true); + + // Size () --- returns file size in bytes + + bool eofStat = false; + if (p_stream.eof()) { // current state of stream is 'eof' + eofStat = true; + p_stream.clear(); + } + + streampos savePos = p_stream.tellg(); + p_stream.seekg(0,ios_base::end); + streamsize bytes = p_stream.tellg(); + p_stream.seekg(savePos,ios_base::beg); + + if (eofStat) { // restore current state of stream 'eof' + p_stream.seekg(0,ios_base::end); + p_stream.get(); + } + return bytes; + } +} // end namespace isis + + diff --git a/isis/src/base/objs/TextFile/TextFile.h b/isis/src/base/objs/TextFile/TextFile.h new file mode 100644 index 0000000000000000000000000000000000000000..65ab7f57711bbefb06cd641a163ad88e57012c85 --- /dev/null +++ b/isis/src/base/objs/TextFile/TextFile.h @@ -0,0 +1,130 @@ +#ifndef TextFile_h +#define TextFile_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/03/30 17:45:42 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +namespace Isis { +/** + * @brief Provides access to sequential ASCII stream I/O + * + * Provides access to sequential ASCII stream I/O. Checks for errors in opening, + * reading, and writing ASCII files. Can check for 'comment lines' while reading + * a text file. + * + * @ingroup Utility + * + * @author 2003-08-29 Glenn Bennett + * + * @internal + * @history 2005-02-16 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2010-03-30 Mackenzie Boyd - Modified open method append option to + * create the file if it doesn't exist, + * changed file existence check to use + * Filename class. + * + * @todo 2005-02-16 Glenn Bennett - add coded and implementation examples, and + * finish documentation + */ + class TextFile { + + protected: + std::fstream p_stream; //! &lines, + const int &maxLinesToReadWrite = 0, + const bool skipComments = true); + TextFile (const std::string &filename, + const char *openmode, std::vector &lines, + const int &maxLinesToReadWrite = 0, + const bool skipComments = true); + TextFile (const char *filename, + const char *openmode, std::string *lines, + const int &maxLinesToReadWrite, const bool skipComments = true); + TextFile (const std::string &filename, + const char *openmode, std::string *lines, + const int &maxLinesToReadWrite, const bool skipComments = true); + + ~TextFile (); + + void Open(const std::string &filename, const char *openmode="input", + const char *extension = ""); + void Open(const char *filename, const char *openmode="input", + const char *extension = ""); + + bool OpenChk(bool bailIfNotOpen = false); + + void Rewind(); + void Close(); + + void GetFile(std::vector &lines, const int &maxLinesToRead = 0, const bool skipComments = true); + void GetFile(std::string *lines, const int &maxLinesToRead, const bool skipComments = true); + + void PutFile(std::vector &lines, const int &maxLinesToWrite = 0); + void PutFile(const std::string *lines, const int &maxLinesToWrite); + + bool GetLine(std::string &line, const bool skipComments = true); + bool GetLineNoFilter(std::string &line); + + bool GetLine(const bool skipComments = true); + bool GetLineNoFilter(); + + void PutLine(const std::string &line); + void PutLine(const char *line = ""); + + void PutLineComment(const std::string &line); + void PutLineComment(const char *line = ""); + + std::string GetComment (); + std::string GetNewLine (); + + void SetComment (const char *commentString = "#"); + void SetNewLine (const char *newLineString = "\n"); + + int LineCount(const int &maxLinesToRead = 0); + std::streamsize Size(); + }; +}; + +#endif diff --git a/isis/src/base/objs/TextFile/TextFile.truth b/isis/src/base/objs/TextFile/TextFile.truth new file mode 100644 index 0000000000000000000000000000000000000000..f590f661e30e94672756b127d49b34a1eba85bb7 --- /dev/null +++ b/isis/src/base/objs/TextFile/TextFile.truth @@ -0,0 +1,43 @@ +Unit test for TextFile + +1) Create / Overwrite file /tmp/TextFile.tmp with prefilled vector + +2) Read file /tmp/TextFile.tmp into vector + +3) Create / Overwrite file /tmp/TextFile.tmp with prefilled string array + +4) Read file /tmp/TextFile.tmp into string array + +5) Overwrite file /tmp/TextFile.tmp + +6) Overwrite file and write 6 lines /tmp/TextFile.tmp + +7) Append 6 lines to file /tmp/TextFile.tmp + +8) Input (read) file /tmp/TextFile.tmp + +10) Trigger Error messages + a) Try to open non-existent file +**I/O ERROR** TextFile:Open:-> Unable to open: [Input]:[/tmp/NoSuchDir/TextFile.tmp] + + b) Try open as output to pre-existing file +**I/O ERROR** TextFile:Open: -> Output file already exists [Output]:[/tmp/TextFile.tmp] + + c) Open file with bad open mode +**PROGRAMMER ERROR** TextFile::-> Unknown openmode: (input, output, overwrite, append):[xxxInputxxx]:[/tmp/TextFile.tmp] + + d) Try to write to Input - Read Only file +**PROGRAMMER ERROR** TextFile:PutLine: -> Attempt to write to INPUT - Read Only text file: [/tmp/TextFile.tmp] + + e) Try to Write to a closed file +**PROGRAMMER ERROR** TextFile::-> File not open: [/tmp/TextFile.tmp] + + f) Try to Read from a closed file +**PROGRAMMER ERROR** TextFile::-> File not open: [/tmp/TextFile.tmp] + +testing GetLine for files that do not end in a newline: Passed + +this file has no newline chars in it! + +11) Remove temp file -> /tmp/TextFile.tmp <- + diff --git a/isis/src/base/objs/TextFile/unitTest.cpp b/isis/src/base/objs/TextFile/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0048f87f6543b2e719d56dbc33d92155cbbd9b8 --- /dev/null +++ b/isis/src/base/objs/TextFile/unitTest.cpp @@ -0,0 +1,526 @@ +#include "TextFile.h" +#include "iException.h" +#include "Preference.h" +#include +#include +#include + +using namespace std; +using namespace Isis; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Unit test for TextFile" << endl << endl; + + +// ---------------------------------------------------------------------------------- + + string testFile = "/tmp/TextFile.tmp"; + // setup test data + string testLines[21]; + + // setup line test data + testLines[0] = "# 0 zero line"; + testLines[1] = "# 1 first line"; + testLines[2] = "# 2 second line"; + testLines[3] = " #3 third line"; + testLines[4] = "/# 4 fourth line"; + testLines[5] = ""; + testLines[6] = "#"; + testLines[7] = "// 7 seventh line"; + testLines[8] = "// 8 eighth line"; + testLines[9] = "/* 9 ninth line"; + testLines[10] = "/* 10 tenth line"; + testLines[11] = "/* 11 eleventh line"; + testLines[12] = "/* 12 twelfth line"; + testLines[13] = " 1 replacement"; + testLines[14] = " 2 replacement"; + testLines[15] = " 3 replacement"; + testLines[16] = " even line replace"; + testLines[17] = ""; + testLines[18] = ""; + testLines[19] = ""; + testLines[20] = "\0"; + + + // calc cumulative byte counts for each line - to check TextFile.Size() + + streamsize testLineBytes[21]; + streamsize numBytes = 0; + streamsize numBytesFiltered = 0; + + vector testLinesVector; + + for (int i=0; i<=19; i++) { + numBytes += testLines[i].length() + strlen("\n"); + testLineBytes[i] = numBytes; + testLinesVector.push_back(testLines[i]); + int locComment = testLines[i].find("#", 0); + if ((locComment != (int) string::npos) && (locComment != 1)) { + numBytesFiltered += testLines[i].length() + strlen("\n"); + } + } + + numBytesFiltered = numBytes - numBytesFiltered; + + +// ---------------------------------------------------------------------------------- + + cout << "1) Create / Overwrite file " << testFile << " with prefilled vector"<< endl; + + try { + Isis::TextFile p(testFile, "overwrite", testLinesVector); // write file + + if (p.Size() != numBytes) { // test file size + cout << " *** Failed Size Test WRITE *** " << endl; + cout << "Calc bytes = " << numBytes << " methodSize = " + << p.Size() << endl; + } + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + +// ---------------------------------------------------------------------------------- + + cout << "2) Read file " << testFile << " into vector"<< endl; + + try { + vector linesIn; + + // read entire file, filter comments + Isis::TextFile g(testFile, "input", linesIn); + + int chkVectorSize = 0; // chk num bytes read + for (int i = 0; i< (int) linesIn.size(); i++) { + chkVectorSize += string(linesIn[i]).length() + strlen("\n"); + } + if (chkVectorSize != numBytesFiltered) { + cout << " *** Failed Size Test Filtered *** " << endl; + cout << "Calc bytes = " << numBytesFiltered << " Vector Size = " + << chkVectorSize << endl; + } + g.Close(); + + linesIn.erase(linesIn.begin(),linesIn.end()); + + // read entire file, do not filter comments + Isis::TextFile g2(testFile, "input", linesIn, 0, false); + + if (g2.Size() != numBytes) { // chk num bytes read + cout << " *** Failed Size Test READ *** " << endl; + cout << "Calc bytes = " << numBytes << " methodSize = " + << g2.Size() << endl; + } + + for (int i = 0; i<= 19; i++) { // compare data read to orig data + if (linesIn[i] != testLines[i]) { + cout << " *** Failed iString Comparison Test *** " << endl; + cout << i + << " Original iString =>" << testLines[i] + << "<= Vector read =>" << linesIn[i] + << "<=" << endl; + } + } + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + +// ---------------------------------------------------------------------------------- + + cout << "3) Create / Overwrite file " << testFile << " with prefilled string array"<< endl; + + try { + // write first four lines + Isis::TextFile p(testFile, "overwrite", testLines, 4); + + if (p.Size() != testLineBytes[4]) { // chk num bytes + cout << " *** Failed Size Test WRITE sense NULL in string array*** " << endl; + cout << "Calc bytes = " << testLineBytes[4] << " methodSize = " + << p.Size() << endl; + } + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + +// ---------------------------------------------------------------------------------- + + cout << "4) Read file " << testFile << " into string array"<< endl; + + try { + // prefill string array to nonnull, set last element to null + // the read file call below will not specify howmany lines to read + // so TextFile will stop filling string array when it encounters a null in output array + + string linesIn[4] = {" ", " ", " ", ""}; + + Isis::TextFile g(testFile, "input", linesIn, 0, false); // read entire file unfiltered + + for (int i=0; i<=2; i++) { // chk orig data against data read + if (linesIn[i] != testLines[i]) { + cout << " *** Failed Compare Test READ sense NULL in string array*** " << endl; + break; + } + } + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + +// ---------------------------------------------------------------------------------- + + cout << "5) Overwrite file " << testFile << endl; + + try { // open file, will truncate + Isis::TextFile f(testFile, "OverWrite"); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + +// ---------------------------------------------------------------------------------- + + cout << "6) Overwrite file and write 6 lines /tmp/TextFile.tmp" << endl; + + try { + Isis::TextFile f(testFile, "OverWrite"); // open overwrite + + f.SetNewLine(""); // turn off append new line + f.SetComment(""); // turn off comment character + + f.PutLine("# 0 zero line\n"); // char output + + f.SetNewLine(); // reset default append new line + f.SetComment(); // reset default comment string + + f.PutLineComment(" 1 first line"); // char output + f.PutLineComment(" 2 second line"); // char output + + f.PutLine(testLines[3]); + // line count + if (f.LineCount() != 4) { + cout << " *** Failed Line Count = 4 *** " << endl; + cout << " methodLineCount = " << f.LineCount() << endl; + } + // byte count + if (f.Size() != testLineBytes[3]) { + cout << " *** Failed Size Test After Line 4 *** " << endl; + cout << "Calc bytes = " << testLineBytes[3] << " methodSize = " + << f.Size() << endl; + } + + f.PutLine(testLines[4]); + + f.PutLine(); // output blank line + + if (f.LineCount() != 6) { // line count + cout << " *** Failed Line Count = 6 *** " << endl; + cout << " methodLineCount = " << f.LineCount() << endl; + } + + f.PutLineComment(); // output blank comment line + + if (f.Size() != testLineBytes[6]) { // byte count + cout << " *** Failed Size Test After Line 7 *** " << endl; + cout << "Calc bytes = " << testLineBytes[6] << " methodSize = " + << f.Size() << endl; + } + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + +// ---------------------------------------------------------------------------------- + + cout << "7) Append 6 lines to file /tmp/TextFile.tmp" << endl; + + try { + Isis::TextFile f(testFile, "Append"); + // append lines 7 & 8 + f.PutLine(testLines[7]); + f.PutLine(testLines[8]); + + if (f.LineCount() != 9) { // line count + cout << " *** Failed Line Count = 9 *** " << endl; + cout << " methodLineCount = " << f.LineCount() << endl; + } + + if (f.Size() != testLineBytes[8]) { // byte count + cout << " *** Failed Size Test After Line 9 *** " << endl; + cout << "Calc bytes = " << testLineBytes[8] << " methodSize = " + << f.Size() << endl; + } + + f.PutLine(testLines[9]); // append line 9 + + if (f.Size() != testLineBytes[9]) { // byte count + cout << " *** Failed Size Test After Line 9 *** " << endl; + cout << "Calc bytes = " << testLineBytes[9] << " methodSize = " + << f.Size() << endl; + } + + for (int i=10; i<=12; i++) { // append lines 10 -> 12 + f.PutLine(testLines[i]); + } + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + +// ---------------------------------------------------------------------------------- + + cout << "8) Input (read) file /tmp/TextFile.tmp" << endl; + + try { + Isis::TextFile f(testFile, "Input"); + + string line; + + for (int i=0; i<=12; i++) { // chk each file line against internal array + f.GetLineNoFilter(line); + if (line != testLines[i]) { + cout << " *** Failed Compare Input Array Line: " << i << " *** " << endl; + } + } + + f.Rewind(); // set input ptr back to beginning + f.SetComment(); // set comment chk, default is '#' + + f.GetLine(line); + // first 3 lines are commented + // so should return fourth line + if (line != testLines[4]) { + cout << " *** Failed Ignore comment lines *** " << endl; + cout << "should be: =>" << testLines[4] << "<=" << endl; + cout << "returned is: =>" << line << "<=" << endl; + } + if (f.LineCount() != 13) { // total line count should be 12 + cout << " *** Failed Line Count = 13 *** " << endl; + cout << " methodLineCount = " << f.LineCount() << endl; + } + + if (f.Size() != testLineBytes[12]) { // byte count + cout << " *** Failed Size Test with Lines = 12 *** " << endl; + cout << "Calc bytes = " << testLineBytes[12] << " methodSize = " + << f.Size() << endl; + } + + f.Rewind(); // set input ptr back to beginning + f.SetComment("/*"); // set comment to '/*' + + string lastLine; + + while (f.GetLine(line)) { // read file's 12 lines + lastLine = line; + } + if (lastLine != testLines[8]) { // line 8 was last non '/*' line read + cout << " *** Failed To see last 4 lines as comments *** " << endl; + } + + f.Rewind(); // set input ptr back to beginning + f.SetComment(); // set comment to default # + f.GetLineNoFilter(line); // should return line 1 + if (line != testLines[0]) { + cout << " *** Failed Read Do Not Skip Comment lines *** " << endl; + } + + f.Rewind(); // reset input ptr to beginning + while (f.GetLine(line)) { // read file's 12 lines + lastLine = line; + } + if (lastLine != testLines[12]) { // line 12 does not begin with '#' + cout << " *** Failed Read to end of file *** " << endl; + } + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + +#if 0 +// Jeff Anderson removed this test. It seems strange that you would want +// to open a file for append and then rewind it. This test used to pass +// but didn't when we went to a newer operating system. Again saying +// you want to open append and then rewind is lame. +// ---------------------------------------------------------------------------------- + + cout << "9) Replace Lines and Verify Replacement in /tmp/TextFile.tmp" << endl; + + + try { + Isis::TextFile f(testFile, "Append"); + + // although opened append, + f.Rewind(); // can set ptr to beginning + + for (int i=1; i<=3; i++) { + f.PutLine(testLines[i+12]); // replace lines 1 to 3 + } + + f.Rewind(); // set ptr back to begining + + string(line); + // re-read file to line 3 + for (int i=1; i<=3; i++) { // to chk replacement + f.GetLineNoFilter(line); + if (line != testLines[i+12]) { + cout << " *** Failed Read Replaced line: " << i << " *** " << endl; + } + } + + f.Rewind(); // set ptr back to begining + + // replace even lines + for (int i=1; i<=6; i++) { + f.GetLineNoFilter(); // moves ptr to next line + f.PutLine(testLines[16]); // replaces line + } + + f.Rewind(); // set ptr back to begining + + // re-read file to line 2 + for (int i=1; i<=2; i++) { + f.GetLineNoFilter(line); + } // chk line 2 was replaced + if (line != testLines[16]) { + cout << " *** Failed Read Replaced lines *** " << endl; + } + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + +// ---------------------------------------------------------------------------------- +#endif + + cout << "10) Trigger Error messages" << endl; + + cout << " a) Try to open non-existent file" << endl; + + testFile = "/tmp/NoSuchDir/TextFile.tmp"; + + try { + Isis::TextFile f(testFile, "Input"); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + + cout << " b) Try open as output to pre-existing file" << endl; + + testFile = "/tmp/TextFile.tmp"; + + try { + Isis::TextFile f(testFile, "Output"); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + + cout << " c) Open file with bad open mode" << endl; + + try { + Isis::TextFile fxText(testFile, "xxxInputxxx"); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + + cout << " d) Try to write to Input - Read Only file" << endl; + + try { + Isis::TextFile f(testFile, "Input"); + f.PutLine("Line 1"); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + + cout << " e) Try to Write to a closed file" << endl; + + try { + Isis::TextFile f(testFile, "append"); + f.Close(); + f.PutLine("Line 1"); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + + cout << " f) Try to Read from a closed file" << endl; + + try { + Isis::TextFile f(testFile, "input"); + f.Close(); + f.GetLine(); + } + catch (Isis::iException &e) { + e.Report (false); + } + cout << endl; + + + // create file that doesn't end in a newline and then test GetLine + FILE * fp; + fp = fopen(testFile.c_str(), "w"); + fprintf(fp, "this file has no newline chars in it!"); + fclose(fp); + TextFile tf; + tf.Open(testFile); + + string fileContents = ""; + string line = ""; + while (tf.GetLine(line, true)) { + fileContents += line; + line = ""; + } + + // this is the real test - line shouldn't be wiped even though tf.GetLine's + // call to getline returned false. + fileContents += line; + + string passed = "Failed"; + if (fileContents != "") + passed = "Passed"; + + cout << "testing GetLine for files that do not end in a newline: " << passed << "\n\n"; + cout << fileContents << "\n\n"; + + +// ---------------------------------------------------------------------------------- + + cout << "11) Remove temp file -> " << testFile << " <-\n" << endl; + + if (std::remove(testFile.c_str())) { // cleanup tmp file + cout << "*** Failed to remove tmp file: " << testFile << endl; + } +} diff --git a/isis/src/base/objs/TileManager/Makefile b/isis/src/base/objs/TileManager/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e1ec61df8d82ee3372979f104a77e3f75f4284f6 --- /dev/null +++ b/isis/src/base/objs/TileManager/Makefile @@ -0,0 +1,5 @@ +INCS = TileManager.h +SRCS = TileManager.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/TileManager/TileManager.cpp b/isis/src/base/objs/TileManager/TileManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6002b16001a4fda31e79485a4bfee823f492d890 --- /dev/null +++ b/isis/src/base/objs/TileManager/TileManager.cpp @@ -0,0 +1,80 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:10 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "TileManager.h" + +using namespace std; +namespace Isis { + + /** + * Constructs a TileManager object + * + * @param cube The cube this buffer will be assiciated with. + * + * @param bufNumSamples The number of samples in each tile buffer. + * Defaults to 128 + * + * @param bufNumLines The number of lines in each tile buffer. Defaults to 128 + * + */ + TileManager::TileManager(const Isis::Cube &cube, + const int &bufNumSamples, const int &bufNumLines) : + Isis::BufferManager(cube.Samples(),cube.Lines(),cube.Bands(), + bufNumSamples,bufNumLines,1, + cube.PixelType()) { + + p_numSampTiles = (cube.Samples() - 1) / bufNumSamples + 1; + p_numLineTiles = (cube.Lines() - 1) / bufNumLines + 1; + } + + /** + * Sets the current tile as requested + * + * @param tile The tile number within a band. This number starts with the + * upper left corner of the cube and proceedes across the samples + * then down the lines. The upper left tile of each band is always + * tile one (1) in band (n). + * + * @param band The band number within the cube. The first band in a cube is + * always one (1). + * + * @return bool + * + * @throws Isis::iException::Programmer - invalid argument value + */ + bool TileManager::SetTile (const int tile, const int band) { + if (tile < 1) { + string message = "Invalid value for argument [tile]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + if (band < 1) { + string message = "Invalid value for argument [band]"; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + } + + int map = (band - 1) * (p_numSampTiles * p_numLineTiles) + tile - 1; + + return setpos(map); + } +} // end namespace isis + diff --git a/isis/src/base/objs/TileManager/TileManager.h b/isis/src/base/objs/TileManager/TileManager.h new file mode 100644 index 0000000000000000000000000000000000000000..9abdfe70e3bf160781c04e92b844489967ce8f30 --- /dev/null +++ b/isis/src/base/objs/TileManager/TileManager.h @@ -0,0 +1,82 @@ +#if !defined(TileManager_h) +#define TileManager_h +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:10 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "BufferManager.h" +#include "Cube.h" + +namespace Isis { +/** + * @brief Buffer manager, for moving through a cube in tiles + * + * This class is used as a manager for moving through a cube one tile at a time. + * A tile is defined as a two dimensional (n samples by m lines) sub area of a + * cube. The band direction is always one deep. The sequence of tiles starts + * with the tile containing sample one, line one and band one. It then moves + * across the cube in the sample direction then to the next tile in the line + * direction and finally to the next tile in the band direction. + * + * If you would like to see TileManager being used in implementation, + * see the ProcessByTile class + * + * @ingroup LowLevelCubeIO + * + * @author 2002-10-10 Stuart Sides + * + * @internal + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2005-02-22 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * + * @todo 2005-05-23 Jeff Anderson - There could be problems with 2GB files if + * the tile size is very small, 1x1, 2x1, 1x2. Should we worry about this? + */ + class TileManager : public Isis::BufferManager { + + private: + int p_numSampTiles; //! +#include +#include +#include "iException.h" +#include "Cube.h" +#include "TileManager.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + string fname = "IsisTileUnitTest"; + const int ns = 254; + const int nl = 300; + const int nb = 2; + + // Allocate a cube + Isis::Cube *cube = new Isis::Cube; + try { + cube->SetDimensions(ns, nl, nb); + cube->Create (fname); + } + catch (Isis::iException &e) { + delete cube; + e.Report(false); + } + + // Create a tile buffer for the cube with default size (128,128) + Isis::TileManager tile(*cube); + cout << "tiles = " << tile.Tiles() << endl; + + // Get each tile and output the sample, line and band of the upper left corner + cout << "Coordinates of upper left pixel in each 128 x 128 tile" << endl; + int tileNum = 1; + for (tile.begin(); !tile.end(); tile++) { + cout << " Corner of tile " << tileNum++ << " is: (" + << tile.Sample(0) << ", " + << tile.Line(0) << ", " + << tile.Band() << ")" << endl; + } + + // Create a tile buffer for the cube with (91,113) + Isis::TileManager tile2(*cube, 91, 113); + + // Get each tile and output the sample, line and band of the upper left corner + cout << "Coordinates of upper left pixel in each 91 x 113 tile" << endl; + tileNum = 1; + for (tile2.begin(); !tile2.end(); tile2++) { + cout << " Corner of tile " << tileNum++ << " is: (" + << tile2.Sample() << ", " + << tile2.Line() << ", " + << tile2.Band() << ")" << endl; + } + + cout << "Coordinates of specific tiles in specific bands" << endl; + tile.SetTile (1,1); + cout << " Corner of tile 1 band 1 is: (" + << tile.Sample() << ", " + << tile.Line() << ", " + << tile.Band() << ")" << endl; + tile.SetTile (1,2); + cout << " Corner of tile 1 band 2 is: (" + << tile.Sample() << ", " + << tile.Line() << ", " + << tile.Band() << ")" << endl; + tile2.SetTile (6,1); + cout << " Corner of tile 6 band 1 is: (" + << tile2.Sample() << ", " + << tile2.Line() << ", " + << tile2.Band() << ")" << endl; + + cube->Close (true); +} diff --git a/isis/src/base/objs/Topo/Makefile b/isis/src/base/objs/Topo/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..070b576a7485efe1bcc045ac9e5dd0b02dcb955d --- /dev/null +++ b/isis/src/base/objs/Topo/Makefile @@ -0,0 +1,5 @@ +INCS = Topo.h +SRCS = Topo.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Topo/NormModel.plugin b/isis/src/base/objs/Topo/NormModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..60d240e03bcf60d98de60a6069c08d008a900ae6 --- /dev/null +++ b/isis/src/base/objs/Topo/NormModel.plugin @@ -0,0 +1,4 @@ +Group = Topo + Library = Topo + Routine = TopoPlugin +End_Group diff --git a/isis/src/base/objs/Topo/Topo.cpp b/isis/src/base/objs/Topo/Topo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..363c746f4eedd41c4e22d0fa318273841c8b8de6 --- /dev/null +++ b/isis/src/base/objs/Topo/Topo.cpp @@ -0,0 +1,121 @@ +#include "Topo.h" +#include "SpecialPixel.h" +#include "iException.h" + +using std::min; +using std::max; + +namespace Isis { + Topo::Topo (Pvl &pvl, PhotoModel &pmodel) : NormModel(pvl,pmodel) { + PvlGroup &algorithm = pvl.FindObject("NormalizationModel").FindGroup("Algorithm",Pvl::Traverse); + + SetNormIncref(0.0); + SetNormThresh(30.0); + SetNormAlbedo(1.0); + + if (algorithm.HasKeyword("Incref")) { + SetNormIncref(algorithm["Incref"]); + } + + if (algorithm.HasKeyword("Thresh")) { + SetNormThresh(algorithm["Thresh"]); + } + + if (algorithm.HasKeyword("Albedo")) { + SetNormAlbedo(algorithm["Albedo"]); + } + } + + void Topo::NormModelAlgorithm (double phase, double incidence, + double emission, double dn, double &albedo, double &mult, + double &base) + { + double rhobar; + double pprimeref; + double psurfref; + double emaref; + double phaseref; + double psurf; + double psurf0; + double pprime; + + GetPhotoModel()->SetStandardConditions(true); + psurf0 = GetPhotoModel()->CalcSurfAlbedo(0.0,0.0,0.0); + + if (psurf0 == 0.0) { + std::string msg = "Divide by zero error"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + else { + rhobar = p_normAlbedo / psurf0; + } + + emaref = 0.0; + phaseref = p_normIncref; + psurfref = GetPhotoModel()->CalcSurfAlbedo(phaseref,p_normIncref,emaref); + pprimeref = GetPhotoModel()->PhtTopder(phaseref,p_normIncref,emaref); + GetPhotoModel()->SetStandardConditions(false); + + // code for scaling each pixel + psurf = GetPhotoModel()->CalcSurfAlbedo(phase,incidence,emission); + pprime = GetPhotoModel()->PhtTopder(phase,incidence,emission); + + if (psurf*pprimeref > pprime*p_normThresh) { + albedo = NULL8; + } + else { + if (pprime == 0.0) { + std::string msg = "Divide by zero error"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + else { + albedo = dn * rhobar * (psurf * pprimeref) / pprime + + rhobar * psurfref - rhobar * (psurf * pprimeref) / pprime; + } + } + } + + /** + * Set the normalization function parameter. This is the + * reference incidence angle to which the image photometry will + * be normalized. This parameter is limited to values that are + * >=0 and <90. + * + * @param incref Normalization function parameter, default + * is 0.0 + */ + void Topo::SetNormIncref (const double incref) { + if (incref < 0.0 || incref >= 90.0) { + std::string msg = "Invalid value of normalization incref [" + + iString(incref) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_normIncref = incref; + } + + /** + * Set the normalization function parameter. This is + * the albedo that the image will be normalized to have. To + * construct mosaics, the same value of albedo should be used + * for all images to achieve a uniform result. + * + * @param albedo Normalization function parameter + */ + void Topo::SetNormAlbedo (const double albedo) { + p_normAlbedo = albedo; + } + + /** + * Set the normalization function parameter. + * + * @param thresh Normalization function parameter + */ + void Topo::SetNormThresh (const double thresh) { + p_normThresh = thresh; + } +} + +extern "C" Isis::NormModel *TopoPlugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel) { + return new Isis::Topo(pvl,pmodel); +} diff --git a/isis/src/base/objs/Topo/Topo.h b/isis/src/base/objs/Topo/Topo.h new file mode 100644 index 0000000000000000000000000000000000000000..a70cde6cf9379f0ee37bcecfab17ac6fbb431e45 --- /dev/null +++ b/isis/src/base/objs/Topo/Topo.h @@ -0,0 +1,66 @@ +#ifndef Topo_h +#define Topo_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/07/08 18:54:49 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "NormModel.h" + +namespace Isis { + class Pvl; + +/** + * @brief Topographic derivative of an arbitrary photometric function + * + * @author 1999-01-08 Randy Kirk + * + * @internal + * @history 2007-08-15 Steven Lambright Refactored and fixed unit test + * @history 2008-06-18 Steven Lambright Fixed ifndef, removed endlink doxygen + * command + */ + class Topo : public NormModel { + public: + Topo (Pvl &pvl, PhotoModel &pmodel); + virtual ~Topo() {}; + + protected: + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double dn, double &albedo, double &mult, double &base); + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double deminc, double demema, double dn, double &albedo, + double &mult, double &base) {}; + + private: + + void SetNormIncref(const double incref); + void SetNormThresh(const double thresh); + void SetNormAlbedo(const double albedo); + + double p_normIncref; + double p_normThresh; + double p_normAlbedo; + + }; +}; + +#endif diff --git a/isis/src/base/objs/Topo/Topo.truth b/isis/src/base/objs/Topo/Topo.truth new file mode 100644 index 0000000000000000000000000000000000000000..cacd294a27b2ac1469ea081d1e7451723b8c5c51 --- /dev/null +++ b/isis/src/base/objs/Topo/Topo.truth @@ -0,0 +1,26 @@ +UNIT TEST for Topo normalization function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = NormalizationModel + Group = Algorithm + Name = Topo + Albedo = 0.0690507 + Incref = 30.0 + End_Group +End_Object +End + +Test phase=86.7226722, incidence=51.7002388, emission=38.9414439, dn=.0800618902 ... +Normalization value = 0.0347164 + +Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0797334611 ... +Normalization value = 0.0347101 + +Test phase=86.7187773, incidence=51.7060221, emission=38.9331391, dn=.0794225037 ... +Normalization value = 0.0347042 + diff --git a/isis/src/base/objs/Topo/unitTest.cpp b/isis/src/base/objs/Topo/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6f7960a151ca6f456807e78cede96344f94b9ac --- /dev/null +++ b/isis/src/base/objs/Topo/unitTest.cpp @@ -0,0 +1,68 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "NormModel.h" +#include "NormModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + double result; + double mult; + double base; + + std::cout << "UNIT TEST for Topo normalization function" << + std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name","Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup algn("Algorithm"); + algn += PvlKeyword("Name", "Topo"); + algn += PvlKeyword("Albedo", 0.0690507); + algn += PvlKeyword("Incref", 30.0); + + PvlObject on("NormalizationModel"); + on.AddGroup(algn); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(on); + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + NormModel *nm = NormModelFactory::Create(pvl,*pm); + + nm->CalcNrmAlbedo(86.7226722,51.7002388,38.9414439,.0800618902,result,mult,base); + + std::cout << "Test phase=86.7226722, incidence=51.7002388, emission=38.9414439, dn=.0800618902 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + + nm->CalcNrmAlbedo(86.7207248,51.7031305,38.9372914,.0797334611,result,mult,base); + + std::cout << "Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0797334611 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + + nm->CalcNrmAlbedo(86.7187773,51.7060221,38.9331391,.0794225037,result,mult,base); + + std::cout << "Test phase=86.7187773, incidence=51.7060221, emission=38.9331391, dn=.0794225037 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/TopoAtm/Makefile b/isis/src/base/objs/TopoAtm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..827d11672d40ad692cee501d5a224d2f7dbc9c1f --- /dev/null +++ b/isis/src/base/objs/TopoAtm/Makefile @@ -0,0 +1,5 @@ +INCS = TopoAtm.h +SRCS = TopoAtm.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/TopoAtm/NormModel.plugin b/isis/src/base/objs/TopoAtm/NormModel.plugin new file mode 100644 index 0000000000000000000000000000000000000000..3dea458a11fcb5a01707eef7e9c3c24ccd9aa5bf --- /dev/null +++ b/isis/src/base/objs/TopoAtm/NormModel.plugin @@ -0,0 +1,4 @@ +Group = TopoAtm + Library = TopoAtm + Routine = TopoAtmPlugin +End_Group diff --git a/isis/src/base/objs/TopoAtm/TopoAtm.cpp b/isis/src/base/objs/TopoAtm/TopoAtm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9414200e2735874520f82e04d09ee20188b76b10 --- /dev/null +++ b/isis/src/base/objs/TopoAtm/TopoAtm.cpp @@ -0,0 +1,160 @@ +#include +#include "TopoAtm.h" +#include "NumericalApproximation.h" +#include "iException.h" + +namespace Isis { + /* + * @history 2008-11-05 Jeannie Walldren - Modified references to + * NumericalMethods class and replaced Isis::PI with PI + * since this is in Isis namespace. + */ + TopoAtm::TopoAtm (Pvl &pvl, PhotoModel &pmodel, AtmosModel &amodel) : NormModel(pvl,pmodel,amodel) { + double psurf0; + double emaref; + double phaseref; + double psurfref; + double pprimeref; + double ahref; + double munotref; + double pstdref; + double transref; + double trans0ref; + double sbar; + + PvlGroup &algorithm = pvl.FindObject("NormalizationModel").FindGroup("Algorithm",Pvl::Traverse); + + SetNormIncref(0.0); + SetNormAlbedo(1.0); + + if (algorithm.HasKeyword("Incref")) { + SetNormIncref(algorithm["Incref"]); + } + + if (algorithm.HasKeyword("Albedo")) { + SetNormAlbedo(algorithm["Albedo"]); + } + + // First-time setup: + // Calculate normalization at standard conditions + GetPhotoModel()->SetStandardConditions(true); + psurf0 = GetPhotoModel()->CalcSurfAlbedo(0.0,0.0,0.0); + + if (psurf0 == 0.0) { + std::string msg = "Divide by zero encountered"; + throw iException::Message(iException::Math,msg,_FILEINFO_); + } + else { + p_normRhobar = p_normAlbedo / psurf0; + } + + emaref = 0.0; + phaseref = p_normIncref; + psurfref = GetPhotoModel()->CalcSurfAlbedo(phaseref,p_normIncref,emaref); + pprimeref = GetPhotoModel()->PhtTopder(phaseref,p_normIncref,emaref); + GetPhotoModel()->SetStandardConditions(false); + + // Get reference hemispheric albedo (p_photoB0 doesn't influence it much) + GetAtmosModel()->GenerateAhTable(); + + ahref = (GetAtmosModel()->AtmosAhSpline()).Evaluate(p_normIncref,NumericalApproximation::Extrapolate); + + munotref = cos((PI/180.0)*p_normIncref); + + // Now calculate atmosphere at standard conditions + GetAtmosModel()->SetStandardConditions(true); + GetAtmosModel()->CalcAtmEffect(phaseref,p_normIncref,emaref,&pstdref,&transref,&trans0ref,&sbar); + GetAtmosModel()->SetStandardConditions(false); + + // Finally, calculate the additive and multiplicative parts of the + // output-normalized signal, from the point of view of fixed albedo + // and varying topography + p_normAout = p_normRhobar * pprimeref * trans0ref; + p_normBout = pstdref + p_normRhobar * (transref * ahref * munotref / + (1.0 - p_normRhobar * GetAtmosModel()->AtmosAb() * sbar) + trans0ref * + (psurfref - ahref * munotref)); + } + + /* + *@history 2008-11-05 Jeannie Walldren - Modified references to + * NumericalMethods class and replaced Isis::PI with PI + * since this is in Isis namespace. + */ + void TopoAtm::NormModelAlgorithm (double phase, double incidence, + double emission, double dn, double &albedo, double &mult, double &base) + { + double eps = 0.1; + double psurf; + double pprime; + double ahInterp; + double munot; + double pstd; + double trans; + double trans0; + double sbar; + double rhotlt; + double dpo; + double q; + double slope; + double pprimeeff; + double ptilt; + double dpm; + double pflat; + double rhoflat; + + psurf = GetPhotoModel()->CalcSurfAlbedo(phase,incidence,emission); + pprime = GetPhotoModel()->PhtTopder(phase,incidence,emission); + ahInterp = (GetAtmosModel()->AtmosAhSpline()).Evaluate(incidence,NumericalApproximation::Extrapolate); + + munot = cos(incidence*(PI/180.0)); + GetAtmosModel()->CalcAtmEffect(phase,incidence,emission,&pstd,&trans,&trans0,&sbar); + pflat = pstd + p_normRhobar * (trans * ahInterp * munot / + (1.0 - p_normRhobar * GetAtmosModel()->AtmosAb() * sbar) + trans0 * (psurf - + ahInterp * munot)); + ptilt = pflat + p_normRhobar * pprime * trans0 * eps; + dpo = ptilt - pstd; + dpm = (psurf - ahInterp * munot) * trans0; + q = ahInterp * munot * trans + GetAtmosModel()->AtmosAb() * sbar * dpo + dpm; + rhotlt = 2.0 * dpo / (q + sqrt(pow(q,2.0)-4.0*GetAtmosModel()->AtmosAb()*sbar*dpo*dpm)); + dpo = pflat - pstd; + q = ahInterp * munot * trans + GetAtmosModel()->AtmosAb() * sbar * dpo + dpm; + rhoflat = 2.0 * dpo / (q + sqrt(pow(q,2.0)-4.0*GetAtmosModel()->AtmosAb()*sbar*dpo*dpm)); + pprimeeff = (rhotlt - rhoflat) / (rhoflat * eps); + slope = (dn - 1.0) / pprimeeff; + albedo = p_normAout * slope + p_normBout; + } + + /** + * Set the normalization function parameter. This is the + * reference incidence angle to which the image photometry will + * be normalized. This parameter is limited to values that are + * >=0 and <90. + * + * @param incref Normalization function parameter, default + * is 0.0 + */ + void TopoAtm::SetNormIncref (const double incref) { + if (incref < 0.0 || incref >= 90.0) { + std::string msg = "Invalid value of normalization incref [" + iString(incref) + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + p_normIncref = incref; + } + + /** + * Set the normalization function parameter. To + * construct mosaics, the same value of albedo should be used + * for all images to achieve a uniform result. + * + * @param albedo Normalization function parameter, default + * is 0.0690507 + */ + void TopoAtm::SetNormAlbedo (const double albedo) { + p_normAlbedo = albedo; + } +} + +extern "C" Isis::NormModel *TopoAtmPlugin (Isis::Pvl &pvl, Isis::PhotoModel &pmodel, Isis::AtmosModel &amodel) { + return new Isis::TopoAtm(pvl,pmodel,amodel); +} diff --git a/isis/src/base/objs/TopoAtm/TopoAtm.h b/isis/src/base/objs/TopoAtm/TopoAtm.h new file mode 100644 index 0000000000000000000000000000000000000000..d1771bff088f86115f952c05a1e90bdd6ae4e7e3 --- /dev/null +++ b/isis/src/base/objs/TopoAtm/TopoAtm.h @@ -0,0 +1,109 @@ +#ifndef TopoAtm_h +#define TopoAtm_h +/** + * @file + * $Revision: 1.7 $ + * $Date: 2009/05/11 22:11:31 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "NormModel.h" + +namespace Isis { + class Pvl; + + /** + * @brief + * As in the case without an atmosphere, processing proceeds + * in three steps, a pass 1 PHOTOM followed by a divide filter to is- + * olate topography from albedo variations followed by a pass 2 PHOTOM. + * The first pass is intended to isolate relative albedo from overall + * photometric shading so that the filter will work as well as possible. + * The second pass cleans up whatever funny scaling the first pass did + * and scales the topographic modulation to desired standard conditions; + * as before these had best not be normal incidence, or the topography + * will vanish! + * + * Also as in the no-atmosphere case, the albedo mode (with atmosphere + * this time) is used for the first pass. The reference geometry for + * this pass is normal incidence with no atmosphere, i.e., + * INC=EMA=PHASE=TAU=0 + * The second pass is going to assume implicitly that these reference + * values were used the first time, freeing the TAE reference parameters + * to define the conditions of finite incidence and maybe finite optical + * depth to which the output will be normalized. + * + * Figuring out the scaling that got applied to the topographic modu- + * lation in pass 1 turns out to be tricky because of the nonlinearity + * of the equations and the fact that the original DN (which would be + * recoverable from the atmosphere model immediately after pass 1) is + * lost after the divide filter. As an approximation, I will require + * the user to input ALBEDO, which is the average DN in the image after + * pass 1, a measure of the average value of RHO and, given the norm- + * alization, the average of the normal albedo in the area. + * + * Rather than do the calculation analytically as I did in my hand- + * written notes, I evaluate the contrast of unit slope numerically + * at given albedo or RHO; the first-order dependence on RHO has been + * divided out so this is inaccurate to second order same as the other + * derivation but it is a whole lot easier to follow). If it turns + * out to be desirable, we can define two values of ALBEDO for this + * program, one describing the input (i.e., giving the albedo for this + * one image, at which slope normalization is calculated) and the other + * describing the output (the albedo to be used in simulating the out- + * put image). + * + * @ingroup RadiometricAndPhotometricCorrection + * @author 1998-12-21 Randy Kirk + * + * @internal + * @history 2007-08-15 Steven Lambright Refactored code + * @history 2008-06-18 Steven Lambright Fixed ifndef command + * @history 2008-11-05 Jeannie Walldren - Modified references + * to NumericalMethods class. + * @history 2009-05-11 Janet Barrett - Fixed so that the NormModelAlgorithm + * supporting DEM input is the empty function. DEM input is not yet + * supported. + + */ + class TopoAtm : public NormModel { + public: + TopoAtm (Pvl &pvl, PhotoModel &pmodel, AtmosModel &amodel); + virtual ~TopoAtm() {}; + + protected: + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double dn, double &albedo, double &mult, double &base); + virtual void NormModelAlgorithm (double pha, double inc, double ema, + double deminc, double demema, double dn, double &albedo, + double &mult, double &base) {}; + + private: + void SetNormIncref(const double incref); + void SetNormAlbedo(const double albedo); + + double p_normIncref; + double p_normAlbedo; + double p_normAout; + double p_normBout; + double p_normRhobar; + }; +}; + +#endif diff --git a/isis/src/base/objs/TopoAtm/TopoAtm.truth b/isis/src/base/objs/TopoAtm/TopoAtm.truth new file mode 100644 index 0000000000000000000000000000000000000000..b9e09a8d5b1829ab00596f6c650cfafd415d176a --- /dev/null +++ b/isis/src/base/objs/TopoAtm/TopoAtm.truth @@ -0,0 +1,33 @@ +UNIT TEST for TopoAtm normalization function + +Object = PhotometricModel + Group = Algorithm + Name = Lambert + End_Group +End_Object + +Object = AtmosphericModel + Group = Algorithm + Name = Anisotropic1 + Bha = 0.85 + End_Group +End_Object + +Object = NormalizationModel + Group = Algorithm + Name = TopoAtm + Albedo = 0.0690507 + Incref = 30.0 + End_Group +End_Object +End + +Test phase=86.7226722, incidence=51.7002388, emission=38.9414439, dn=.0800618902 ... +Normalization value = 0.0158958 + +Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, dn=.0797334611 ... +Normalization value = 0.0158845 + +Test phase=86.7187773, incidence=51.7060221, emission=38.9331391, dn=.0794225037 ... +Normalization value = 0.015874 + diff --git a/isis/src/base/objs/TopoAtm/unitTest.cpp b/isis/src/base/objs/TopoAtm/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6bba9045fc072145541b3d2edb93299d3c737b73 --- /dev/null +++ b/isis/src/base/objs/TopoAtm/unitTest.cpp @@ -0,0 +1,81 @@ +#include +#include +#include "PhotoModel.h" +#include "PhotoModelFactory.h" +#include "AtmosModel.h" +#include "AtmosModelFactory.h" +#include "TopoAtm.h" +#include "NormModelFactory.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iException.h" +#include "Preference.h" + +using namespace Isis; + +int main () { + Isis::Preference::Preferences(true); + + double result; + double mult; + double base; + + std::cout << "UNIT TEST for TopoAtm normalization function" << std::endl << std::endl; + + PvlGroup algp("Algorithm"); + algp += PvlKeyword("Name", "Lambert"); + + PvlObject op("PhotometricModel"); + op.AddGroup(algp); + + PvlGroup alga("Algorithm"); + alga += PvlKeyword("Name", "Anisotropic1"); + alga += PvlKeyword("Bha", 0.85); + + PvlObject oa("AtmosphericModel"); + oa.AddGroup(alga); + + PvlGroup algn("Algorithm"); + algn += PvlKeyword("Name", "TopoAtm"); + algn += PvlKeyword("Albedo", 0.0690507); + algn += PvlKeyword("Incref", 30.0); + + PvlObject on("NormalizationModel"); + on.AddGroup(algn); + + Pvl pvl; + pvl.AddObject(op); + pvl.AddObject(oa); + pvl.AddObject(on); + + std::cout << pvl << std::endl << std::endl; + + try { + PhotoModel *pm = PhotoModelFactory::Create(pvl); + AtmosModel *am = AtmosModelFactory::Create(pvl,*pm); + TopoAtm *nm = (TopoAtm*)NormModelFactory::Create(pvl,*pm,*am); + + nm->CalcNrmAlbedo(86.7226722,51.7002388,38.9414439,.0800618902,result,mult,base); + + std::cout << "Test phase=86.7226722, incidence=51.7002388, emission=38.9414439, " << + "dn=.0800618902 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + + nm->CalcNrmAlbedo(86.7207248,51.7031305,38.9372914,.0797334611,result,mult,base); + + std::cout << "Test phase=86.7207248, incidence=51.7031305, emission=38.9372914, " << + "dn=.0797334611 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + + nm->CalcNrmAlbedo(86.7187773,51.7060221,38.9331391,.0794225037,result,mult,base); + + std::cout << "Test phase=86.7187773, incidence=51.7060221, emission=38.9331391, " << + "dn=.0794225037 ..." << std::endl; + std::cout << "Normalization value = " << result << std::endl << std::endl; + } + catch (iException &e) { + e.Report(); + } + + return 0; +} diff --git a/isis/src/base/objs/Transform/Makefile b/isis/src/base/objs/Transform/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..554bd82ba8d1b60b6589611b400685ed6c27400f --- /dev/null +++ b/isis/src/base/objs/Transform/Makefile @@ -0,0 +1,5 @@ +INCS = Transform.h +SRCS = +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/Transform/Transform.h b/isis/src/base/objs/Transform/Transform.h new file mode 100644 index 0000000000000000000000000000000000000000..95f9419fd05c4d47e2c5073d4c18ea21a97913f1 --- /dev/null +++ b/isis/src/base/objs/Transform/Transform.h @@ -0,0 +1,144 @@ +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:10 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef Transform_h +#define Transform_h + +namespace Isis { +/** + * @brief Pixel transformation + * + * This class is used as a virtual base class for rubbersheeting (geometric + * warping) of image data. In Isis, rubbersheeting is performed by a transform + * from output space to input space, where a space could be a disk cube or an + * internalized memory cube. In particular, the transform must provide a method + * for converting output pixel locations (sample,line) to input pixel locations. + * A very simple example of a transform is a translation (shifting the cube + * left/right and up/down). More complex transforms can be created such as + * rotations, scaling, and converting to a map projection. The Transform class + * is "pure virtual" and should never be instantiated but instead used in an + * inheriting class. Using the translation example: + * @code + * class Translate : public Transform { + * public: Translate (IsisCube &cube, double sampOffset, double lineOffset) + * { + * p_lines = cube.Lines(); + * p_samples = cube.Samples(); + * p_lineOffset = lineOffset; + * p_sampOffset = sampOffset; + * } + * ~Translate () {}; + * int OutputSamples () { return p_samples; }; + * int OutputLines() { return p_lines; }; + * void Transform (double &insamp, double &inline, const double outsamp, + * const double outline) + * { + * insamp = outsamp + p_sampOffset; inline = outline + p_lineOffset; + * } + * private: + * double p_sampOffset; + * double p_lineOffset; + * int p_lines; + * int p_samples; + * }; + * @endcode + * If you are developing an application program whose intent is to geometrically + * manipulate the pixels in a cube, you should investigate the RubberSheet + * object which will deals nicely with a significant amount of the cube access + * and user input. Also, check out other applications which use the RubberSheet + * object such as "rotate" or "translate". + * + * If you would like to see Transform + * being used in implementation, see transform.cpp + * + * @ingroup Geometry + * + * @author 2002-10-14 Stuart Sides + * + * @internal + * @history 2002-11-14 Stuart Sides - Modified documentation after review + * by Jeff Anderson + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2004-06-22 Jeff Anderson - Modified Transform method so that it + * was not const + * @history 2005-02-22 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * + * @todo 2005-02-22 Stuart Sides - finish documentation + */ + class Transform { + private: + + protected: + + public: + + //! Constructs a Transform object + Transform () {}; + + //! Destroy the Transform object + virtual ~Transform () {}; + + // Pure virtual members + + /** + * Allows the retrieval of the calculated number of samples in the output + * image. + * + * @return int The number of samples in the output image. + */ + virtual int OutputSamples () const = 0; + + /** + * Allows the retrieval of the calculated number of lines in the output + * image. + * + * @return int The number of lines in the output image. + */ + virtual int OutputLines () const = 0; + + /** + * Transforms the given output line and sample to the corresponding output + * line and sample. + * + * @param inSample The calculated input sample where the output pixel came + * from. + * + * @param inLine The calculated input line where the output pixel came + * from. + * + * @param outSample The output sample for which an input line and sample is + * being sought + * + * @param outLine The output line for which an input line and sample is + * being sought + */ + virtual bool Xform (double &inSample, double &inLine, + const double outSample, + const double outLine) =0; + + }; +}; + +#endif + diff --git a/isis/src/base/objs/Transform/Transform.truth b/isis/src/base/objs/Transform/Transform.truth new file mode 100644 index 0000000000000000000000000000000000000000..8c101be5672feea8925aa5f8d114888e69647495 --- /dev/null +++ b/isis/src/base/objs/Transform/Transform.truth @@ -0,0 +1 @@ +This class currently contains only pure virtual functions,so this is a dummy unit test. diff --git a/isis/src/base/objs/Transform/unitTest.cpp b/isis/src/base/objs/Transform/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3cc6229318b3f0b32b7aaa74515952145862eed2 --- /dev/null +++ b/isis/src/base/objs/Transform/unitTest.cpp @@ -0,0 +1,11 @@ +#include +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + + cout << "This class currently contains only pure virtual functions," << + "so this is a dummy unit test." << endl; +} diff --git a/isis/src/base/objs/TransverseMercator/Makefile b/isis/src/base/objs/TransverseMercator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b383592f0b0329f1690e5759fe542126e895fc91 --- /dev/null +++ b/isis/src/base/objs/TransverseMercator/Makefile @@ -0,0 +1,5 @@ +INCS = TransverseMercator.h +SRCS = TransverseMercator.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/TransverseMercator/Projection.plugin b/isis/src/base/objs/TransverseMercator/Projection.plugin new file mode 100644 index 0000000000000000000000000000000000000000..b0c2dbf116b8bb814a383df0cc463df7f22f50d1 --- /dev/null +++ b/isis/src/base/objs/TransverseMercator/Projection.plugin @@ -0,0 +1,8 @@ +Group = TransverseMercator + Library = TransverseMercator + Routine = TransverseMercatorPlugin + Keyword = CenterLongitude + Keyword = CenterLatitude + Keyword = ScaleFactor +EndGroup + diff --git a/isis/src/base/objs/TransverseMercator/TransverseMercator.cpp b/isis/src/base/objs/TransverseMercator/TransverseMercator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8047a8ac35ed28dc89a70a1dc456e9b86591a1dd --- /dev/null +++ b/isis/src/base/objs/TransverseMercator/TransverseMercator.cpp @@ -0,0 +1,450 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/05/09 18:49:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "TransverseMercator.h" +#include "iException.h" +#include "Constants.h" +#include "Projection.h" + +using namespace std; +namespace Isis { + /** + * Constructs a TransverseMercator object + * + * @param label This argument must be a Label containing the proper mapping + * information as indicated in the Projection class. Additionally, + * the transversemercator projection requires the center longitude + * to be defined in the keyword CenterLongitude, and the scale + * factor to be defined in the keyword ScaleFactor. + * + * @param allowDefaults If set to false the constructor expects that a keyword + * of CenterLongitude and ScaleFactor will be in the label. + * Otherwise it will attempt to compute the center + * longitude using the middle of the longitude range + * specified in the label, and the scale factor will + * default to 1.0. Defaults to false. + * + * @throws Isis::iException::Io + */ + TransverseMercator::TransverseMercator(Isis::Pvl &label, bool allowDefaults) : + Isis::Projection::Projection (label) { + try { + // Try to read the mapping group + Isis::PvlGroup &mapGroup = label.FindGroup ("Mapping",Isis::Pvl::Traverse); + + // Compute and write the default center longitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLongitude"))) { + double lon = (p_minimumLongitude + p_maximumLongitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLongitude",lon); + } + + // Compute and write the default center latitude if allowed and + // necessary + if ((allowDefaults) && (!mapGroup.HasKeyword("CenterLatitude"))) { + double lat = (p_minimumLatitude + p_maximumLatitude) / 2.0; + mapGroup += Isis::PvlKeyword("CenterLatitude",lat); + } + + // Get the center longitude & latitude + p_centerLongitude = mapGroup["CenterLongitude"]; + p_centerLatitude = mapGroup["CenterLatitude"]; + + // make sure the center latitude value is valid + if (fabs(p_centerLatitude) >= 90.0) { + string msg = "Invalid Center Latitude Value. Must be between -90 and 90"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // make sure the center longitude value is valid + if (fabs(p_centerLongitude) > 360.0) { + string msg = "Invalid Center Longitude Value. Must be between -360 and 360"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // convert latitude to planetographic if it is planetocentric + if (this->IsPlanetocentric()) { + p_centerLatitude = this->ToPlanetographic(p_centerLatitude); + } + + // convert to radians and adjust for longitude direction + if (p_longitudeDirection == PositiveWest) p_centerLongitude *= -1.0; + p_centerLatitude *= Isis::PI / 180.0; + p_centerLongitude *= Isis::PI / 180.0; + + // Compute other necessary variables + p_eccsq = Eccentricity()*Eccentricity(); + p_esp = p_eccsq; + p_e0 = 1.0 - 0.25 * p_eccsq * (1.0 + p_eccsq / 16.0 * (3.0 + 1.25 *p_eccsq)); + p_e1 = 0.375 * p_eccsq * (1.0 + 0.25 * p_eccsq * ( 1.0 + 0.468750 * p_eccsq)); + p_e2 = 0.058593750 * p_eccsq * p_eccsq * (1.0 + 0.750 * p_eccsq); + p_e3 = p_eccsq * p_eccsq * p_eccsq * (35.0 / 3072.0); + p_ml0 = p_equatorialRadius * (p_e0 * p_centerLatitude - p_e1 * sin(2.0 * p_centerLatitude) + + p_e2 * sin(4.0 * p_centerLatitude) - p_e3 * sin(6.0 * p_centerLatitude)); + + // Set flag for sphere or ellipsiod + p_sph = true; // Sphere + if (Eccentricity() >= .00001) { + p_sph = false; // Ellipsoid + p_esp = p_eccsq / (1.0 - p_eccsq); + } + + // Get the scale factor + if ((allowDefaults) && (!mapGroup.HasKeyword("ScaleFactor"))) { + mapGroup += Isis::PvlKeyword("ScaleFactor",1.0); + } + p_scalefactor = mapGroup["ScaleFactor"]; + } + catch (Isis::iException &e) { + string message = "Invalid label group [Mapping]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + } + + //! Destroys the TransverseMercator object + TransverseMercator::~TransverseMercator() { + } + + /** + * This method is used to set the latitude/longitude (assumed to be of the + * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set + * forces an attempted calculation of the projection X/Y values. This may or + * may not be successful and a status is returned as such. + * + * @param lat Latitude value to project + * + * @param lon Longitude value to project + * + * @return bool + */ + bool TransverseMercator::SetGround(const double lat,const double lon) { + // Get longitude & fix direction + p_longitude = lon; + if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; + + double cLonDeg = p_centerLongitude * 180.0 / Isis::PI; + double deltaLon = p_longitude - cLonDeg; + while (deltaLon < -360.0) deltaLon += 360.0; + while (deltaLon > 360.0) deltaLon -= 360.0; + double deltaLonRads = deltaLon * Isis::PI / 180.0; + + // Now convert latitude to radians & clean up ... it must be planetographic + p_latitude = lat; + double latRadians = p_latitude * Isis::PI / 180.0; + if (IsPlanetocentric()) { + latRadians = ToPlanetographic(p_latitude) * Isis::PI / 180.0; + } + + double ml = p_equatorialRadius * (p_e0 * latRadians - p_e1 * sin(2.0 * latRadians) + + p_e2 * sin(4.0 * latRadians) - p_e3 * sin(6.0 * latRadians)); + + // Declare variables + const double epsilon = 1.0e-10; + + // Sphere Conversion + double x,y; + if (p_sph) { + double cosphi = cos(latRadians); + double b = cosphi * sin(deltaLonRads); + + // Point projects to infinity + if (fabs(fabs(b) - 1.0) <= epsilon) { + p_good = false; + return p_good; + } + x = 0.5 * p_equatorialRadius * p_scalefactor * log((1.0 + b) / (1.0 - b)); + + // If arcosine argument is too close to 1, con=0.0 because arcosine(1)=0 + double con = cosphi * cos(deltaLonRads) / sqrt(1.0 - b * b); + if (fabs(con) > 1.0) { + con = 0.0; + } + else { + con = acos(con); + } + if(p_latitude < 0.0) con = -con; + y = p_equatorialRadius * p_scalefactor * (con - p_centerLatitude); + } + + // Ellipsoid Conversion + else { + if(fabs(Isis::HALFPI - fabs(latRadians)) < epsilon) { + x = 0.0; + y = p_scalefactor * (ml - p_ml0); + } + else { + double sinphi = sin(latRadians); + double cosphi = cos(latRadians); + double al = cosphi * deltaLonRads; + double als = al * al; + double c = p_esp * cosphi * cosphi; + double tq = tan(latRadians); + double t = tq * tq; + double n = p_equatorialRadius / sqrt (1.0 - p_eccsq * sinphi * sinphi); + x = p_scalefactor * n * al * (1.0 + als / 6.0 * (1.0 - t + c + als + / 20.0 * (5.0 - 18.0 * t + t * t + 72.0 * c - 58.0 * p_esp))); + y = p_scalefactor *(ml - p_ml0 + n * tq * (als * (0.5 + als / 24.0 * + (5.0 - t + 9.0 * c + 4.0 * c * c + als / 30.0 * + (61.0 - 58.0 * t + t * t + 600.0 * c - 330.0 * p_esp))))); + } + } + + SetComputedXY(x,y); + p_good = true; + return p_good; + } + + /** + * This method is used to set the projection x/y. The Set forces an attempted + * calculation of the corresponding latitude/longitude position. This may or + * may not be successful and a status is returned as such. + * + * @param x X coordinate of the projection in units that are the same as the + * radii in the label + * + * @param y Y coordinate of the projection in units that are the same as the + * radii in the label + * + * @return bool + */ + bool TransverseMercator::SetCoordinate(const double x, const double y) { + // Save the coordinate + SetXY(x,y); + + // Declare & Initialize variables + double f,g,h,temp,con,phi,dphi,sinphi,cosphi,tanphi; + double c,cs,t,ts,n,rp,d,ds; + const double epsilon = 1.0e-10; + + // Sphere Conversion + if (p_sph) { + f = exp(GetX() / (p_equatorialRadius * p_scalefactor)); + g = 0.5 * (f - 1.0 / f); + temp = p_centerLatitude + GetY() / (p_equatorialRadius * p_scalefactor); + h = cos(temp); + con = sqrt((1.0 - h * h) / (1.0 + g * g)); + if (con > 1.0) con = 1.0; + if (con < -1.0) con = -1.0; + p_latitude = asin(con); + if (temp < 0.0 ) p_latitude = -p_latitude; + p_longitude = p_centerLongitude; + if (g != 0.0 || h != 0.0) { + p_longitude = atan2(g,h) + p_centerLongitude; + } + } + + // Ellipsoid Conversion + else if (!p_sph) { + con = (p_ml0 + GetY() / p_scalefactor) / p_equatorialRadius; + phi = con; + for (int i = 1; i < 7; i++) { + dphi = ((con + p_e1 * sin(2.0 * phi) - p_e2 * sin(4.0 * phi) + + p_e3 * sin(6.0 * phi)) / p_e0) - phi; + phi += dphi; + if (fabs(dphi) <= epsilon) break; + } + + // Didn't converge + if (fabs(dphi) > epsilon) { + p_good = false; + return p_good; + } + if (fabs(phi) >= Isis::HALFPI) { + if (GetY() >= 0.0) p_latitude = fabs(Isis::HALFPI); + if (GetY() < 0.0) p_latitude = - fabs(Isis::HALFPI); + p_longitude = p_centerLongitude; + } + else { + sinphi = sin(phi); + cosphi = cos(phi); + tanphi = tan(phi); + c = p_esp * cosphi * cosphi; + cs = c * c; + t = tanphi * tanphi; + ts = t * t; + con = 1.0 - p_eccsq * sinphi * sinphi; + n = p_equatorialRadius / sqrt(con); + rp = n * (1.0 - p_eccsq) / con; + d = GetX() / (n * p_scalefactor); + ds = d * d; + p_latitude = phi - (n * tanphi * ds / rp) * (0.5 - ds / + 24.0 * (5.0 + 3.0 * t + 10.0 * c - 4.0 * cs - 9.0 * + p_esp - ds / 30.0 * (61.0 + 90.0 * t + 298.0 * c + + 45.0 * ts - 252.0 * p_esp - 3.0 * cs))); + + + // Latitude cannot be greater than + or - halfpi radians (or 90 degrees) + if (fabs(p_latitude) > Isis::HALFPI) { + p_good = false; + return p_good; + } + p_longitude = p_centerLongitude + (d * (1.0 - ds / 6.0 * + (1.0 + 2.0 * t + c - ds / 20.0 * (5.0 - 2.0 * c + + 28.0 * t - 3.0 * cs + 8.0 * p_esp + 24.0 * ts))) / cosphi); + } + } + + // Convert to Degrees + p_latitude *= 180.0 / Isis::PI; + p_longitude *= 180.0 / Isis::PI; + + // Cleanup the longitude + if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; + // These need to be done for circular type projections + p_longitude = To360Domain (p_longitude); + if (p_longitudeDomain == 180) p_longitude = To180Domain(p_longitude); + + // Cleanup the latitude + if (IsPlanetocentric()) p_latitude = ToPlanetocentric(p_latitude); + + p_good = true; + return p_good; + } + + /** + * This method is used to determine the x/y range which completely covers the + * area of interest specified by the lat/lon range. The latitude/longitude + * range may be obtained from the labels. The purpose of this method is to + * return the x/y range so it can be used to compute how large a map may need + * to be. For example, how big a piece of paper is needed or how large of an + * image needs to be created. The method may fail as indicated by its return + * value. + * + * @param minX Minimum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxX Maximum x projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param minY Minimum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @param maxY Maximum y projection coordinate which covers the latitude + * longitude range specified in the labels. + * + * @return bool + */ + bool TransverseMercator::XYRange(double &minX, double &maxX, double &minY, double&maxY){ + // Check the corners of the lat/lon range + XYRangeCheck (p_minimumLatitude,p_minimumLongitude); + XYRangeCheck (p_maximumLatitude,p_minimumLongitude); + XYRangeCheck (p_minimumLatitude,p_maximumLongitude); + XYRangeCheck (p_maximumLatitude,p_maximumLongitude); + + // convert center latitude to degrees & test + double clat = p_centerLatitude * 180.0 / Isis::PI; + + if (clat > p_minimumLatitude && + clat < p_maximumLatitude) { + XYRangeCheck (clat, p_minimumLongitude); + XYRangeCheck (clat, p_maximumLongitude); + } + + // convert center longitude to degrees & test + double clon = p_centerLongitude * 180.0 / Isis::PI; + if (clon > p_minimumLongitude && + clon < p_maximumLongitude) { + XYRangeCheck (p_minimumLatitude, clon); + XYRangeCheck (p_maximumLatitude, clon); + } + + // Make sure everything is ordered + if (p_minimumX >= p_maximumX) return false; + if (p_minimumY >= p_maximumY) return false; + + // Return X/Y min/maxs + minX = p_minimumX; + maxX = p_maximumX; + minY = p_minimumY; + maxY = p_maximumY; + return true; + } + + + /** + * This function returns the keywords that this projection uses. + * + * @return PvlGroup The keywords that this projection uses + */ + PvlGroup TransverseMercator::Mapping() { + PvlGroup mapping = Projection::Mapping(); + + mapping += p_mappingGrp["CenterLatitude"]; + mapping += p_mappingGrp["CenterLongitude"]; + mapping += p_mappingGrp["ScaleFactor"]; + + return mapping; + } + + /** + * This function returns the latitude keywords that this projection uses + * + * @return PvlGroup The latitude keywords that this projection uses + */ + PvlGroup TransverseMercator::MappingLatitudes() { + PvlGroup mapping = Projection::MappingLatitudes(); + + mapping += p_mappingGrp["CenterLatitude"]; + + return mapping; + } + + /** + * This function returns the longitude keywords that this projection uses + * + * @return PvlGroup The longitude keywords that this projection uses + */ + PvlGroup TransverseMercator::MappingLongitudes() { + PvlGroup mapping = Projection::MappingLongitudes(); + + mapping += p_mappingGrp["CenterLongitude"]; + + return mapping; + } + + /** + * Compares two Projection objects to see if they are equal + * + * @param proj Projection object to do comparison on + * + * @return bool Returns true if the Projection objects are equal, and false if + * they are not + */ + bool TransverseMercator::operator== (const Isis::Projection &proj) { + if (!Isis::Projection::operator==(proj)) return false; + // dont do the below it is a recusive plunge + // if (Isis::Projection::operator!=(proj)) return false; + TransverseMercator *trans = (TransverseMercator *) &proj; + if ((trans->p_centerLongitude != this->p_centerLongitude) || + (trans->p_centerLatitude != this->p_centerLatitude)) return false; + return true; + } +} // end namespace isis + +extern "C" Isis::Projection *TransverseMercatorPlugin (Isis::Pvl &lab, + bool allowDefaults) { + return new Isis::TransverseMercator(lab,allowDefaults); +} + + diff --git a/isis/src/base/objs/TransverseMercator/TransverseMercator.h b/isis/src/base/objs/TransverseMercator/TransverseMercator.h new file mode 100644 index 0000000000000000000000000000000000000000..44f4436cdda5b80450500fa39a642043343e0931 --- /dev/null +++ b/isis/src/base/objs/TransverseMercator/TransverseMercator.h @@ -0,0 +1,97 @@ +#ifndef TransverseMercator_h +#define TransverseMercator_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/05/09 18:49:25 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Projection.h" +#include "Constants.h" + +namespace Isis { +/** + * @brief TransverseMercator Map Projection + * + * This class provides methods for the forward and inverse equations of a + * TransverseMercator map projection (for a sphere or ellipsoid). The code was + * converted to C++ from the C version of the USGS General Cartographic + * Transformation Package (GCTP). This class inherits Projection and provides + * the two virtual methods SetGround (forward) and SetCoordinate (inverse) and + * a third virtual method, XYRange, for obtaining projection coordinate coverage + * for a latitude/longitude window. Please see the Projection class for a full + * accounting of all the methods available. + * + * @ingroup MapProjection + * + * @author 2005-03-18 Elizabeth Ribelin + * + * @internal + * @history 2005-09-06 Elizabeth Ribelin - Fixed bug in radians/degrees + * conversions + * @history 2005-12-02 Elizabeth Miller - Fixed bug in ellipsiod lat/lon + * to x/y conversion + * @history 2007-06-29 Steven Lambright - Added Mapping, MappingLatitudes and + * MappingLongitudes methods. + * @history 2008-05-09 Steven Lambright - Added Name, Version methods + */ + class TransverseMercator : public Isis::Projection { + public: + TransverseMercator(Isis::Pvl &label, bool allowDefaults=false); + ~TransverseMercator(); + bool SetGround (const double lat, const double lon); + bool SetCoordinate (const double x, const double y); + PvlGroup Mapping(); + PvlGroup MappingLatitudes(); + PvlGroup MappingLongitudes(); + + bool XYRange (double &minX, double &maxX, double &minY, double &maxY); + + /** + * Returns the name of the map projection + * + * @return string Name of projection + */ + std::string Name() const { return "TransverseMercator"; } + + /** + * Returns the version of the map projection + * + * + * @return std::string Version number + */ + std::string Version () const { return "1.0"; } + + bool operator== (const Isis::Projection &proj); + + private: + double p_centerLongitude; //! +#include +#include "TransverseMercator.h" +#include "iException.h" +#include "ProjectionFactory.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "UNIT TEST FOR TransverseMercator" << endl << endl; + cout << "Part 1: Sphere..." << endl; + + Isis::Pvl lab; + lab.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup = lab.FindGroup("Mapping"); + mapGroup += Isis::PvlKeyword("EquatorialRadius",1.0); + mapGroup += Isis::PvlKeyword("PolarRadius",1.0); + mapGroup += Isis::PvlKeyword("LatitudeType","Planetographic"); + mapGroup += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup += Isis::PvlKeyword("LongitudeDomain",180); + mapGroup += Isis::PvlKeyword("MinimumLatitude",-70.0); + mapGroup += Isis::PvlKeyword("MaximumLatitude",70.0); + mapGroup += Isis::PvlKeyword("MinimumLongitude",-90.0); + mapGroup += Isis::PvlKeyword("MaximumLongitude",-60.0); + mapGroup += Isis::PvlKeyword("ProjectionName","TransverseMercator"); + + cout << "Test missing center longitude keyword ..." << endl; + try { + Isis::TransverseMercator p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("CenterLongitude",-75.0); + + cout << "Test missing center latitude keyword..." << endl; + try { + Isis::TransverseMercator p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("CenterLatitude", 0.0); + + cout << "Test missing scale factor keyword..." << endl; + try { + Isis::TransverseMercator p(lab); + } + catch (Isis::iException &e) { + e.Report(false); + } + cout << endl; + + mapGroup += Isis::PvlKeyword("ScaleFactor", 1.0); + + try { + Isis::Projection &p = *Isis::ProjectionFactory::Create(lab); + // Isis::TransMercator p(lab); + + cout << "Test SetGround method ... " << endl; + cout << std::setprecision(9); + cout << "Setting ground to (40.5,-73.5)" << endl; + p.SetGround(40.5,-73.5); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + + cout << "Test SetCoordinate method ... " << endl; + cout << "Setting coordinate to (0.0199077372, 0.707027609)" << endl; + p.SetCoordinate(0.0199077372, 0.707027609); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + cout << "Test XYRange method ... " << endl; + double minX,maxX,minY,maxY; + p.XYRange(minX,maxX,minY,maxY); + cout << "Minimum X: " << minX << endl; + cout << "Maximum X: " << maxX << endl; + cout << "Minimum Y: " << minY << endl; + cout << "Maximum Y: " << maxY << endl; + cout << endl; + + Isis::Projection *s = &p; + cout << "Test Name and comparision method ... " << endl; + cout << "Name: " << s->Name() << endl; + cout << "operator== " << (*s == *s) << endl; + cout << endl; + + cout << "Test default computation ... " << endl; + mapGroup.DeleteKeyword("CenterLongitude"); + mapGroup.DeleteKeyword("CenterLatitude"); + mapGroup.DeleteKeyword("ScaleFactor"); + Isis::TransverseMercator p2(lab,true); + cout << lab << endl; + cout << endl; + + cout << "Unit test was obtained from:" << endl << endl; + cout << " Map Projections - A Working Manual" << endl; + cout << " USGS Professional Paper 1395 by John P. Snyder" << endl; + cout << " Pages 268-269" << endl << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } + + cout << endl << "Part 2: Ellipsoid..." << endl; + + Isis::Pvl lab2; + lab2.AddGroup(Isis::PvlGroup("Mapping")); + Isis::PvlGroup &mapGroup2 = lab2.FindGroup("Mapping"); + mapGroup2 += Isis::PvlKeyword("EquatorialRadius",6378206.4); + mapGroup2 += Isis::PvlKeyword("PolarRadius",6356583.8); + mapGroup2 += Isis::PvlKeyword("LatitudeType","Planetographic"); + mapGroup2 += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); + mapGroup2 += Isis::PvlKeyword("LongitudeDomain",180); + mapGroup2 += Isis::PvlKeyword("MinimumLatitude",-70.0); + mapGroup2 += Isis::PvlKeyword("MaximumLatitude",70.0); + mapGroup2 += Isis::PvlKeyword("MinimumLongitude",-90.0); + mapGroup2 += Isis::PvlKeyword("MaximumLongitude",-60.0); + mapGroup2 += Isis::PvlKeyword("ProjectionName","TransverseMercator"); + mapGroup2 += Isis::PvlKeyword("CenterLongitude",-75.0); + mapGroup2 += Isis::PvlKeyword("CenterLatitude", 0.0); + mapGroup2 += Isis::PvlKeyword("ScaleFactor", 0.9996); + cout << endl; + + try { + Isis::Projection &p = *Isis::ProjectionFactory::Create(lab2); + // Isis::TransMercator p(lab); + + cout << "Test SetGround method ... " << endl; + cout << std::setprecision(9); + cout << "Setting ground to (40.5,-73.5)" << endl; + p.SetGround(40.5,-73.5); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + + cout << "Test SetCoordinate method ... " << endl; + cout << "Setting coordinate to (127106.467, 4484124.43)" << endl; + p.SetCoordinate(127106.467, 4484124.43); + cout << "Latitude: " << p.Latitude() << endl; + cout << "Longitude: " << p.Longitude() << endl; + cout << "XCoord: " << p.XCoord() << endl; + cout << "YCoord: " << p.YCoord() << endl; + cout << endl; + + cout << "Test XYRange method ... " << endl; + double minX,maxX,minY,maxY; + p.XYRange(minX,maxX,minY,maxY); + cout << "Minimum X: " << minX << endl; + cout << "Maximum X: " << maxX << endl; + cout << "Minimum Y: " << minY << endl; + cout << "Maximum Y: " << maxY << endl; + cout << endl; + + cout << "Testing Mapping() methods ... " << endl; + + Isis::Pvl tmp1; + Isis::Pvl tmp2; + Isis::Pvl tmp3; + tmp1.AddGroup(p.Mapping()); + tmp2.AddGroup(p.MappingLatitudes()); + tmp3.AddGroup(p.MappingLongitudes()); + + cout << "Mapping() = " << endl; + cout << tmp1 << endl; + cout << "MappingLatitudes() = " << endl; + cout << tmp2 << endl; + cout << "MappingLongitudes() = " << endl; + cout << tmp3 << endl; + cout << endl; + + cout << "Unit test was obtained from:" << endl << endl; + cout << " Map Projections - A Working Manual" << endl; + cout << " USGS Professional Paper 1395 by John P. Snyder" << endl; + cout << " Pages 269-270" << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } +} + diff --git a/isis/src/base/objs/UniversalGroundMap/Makefile b/isis/src/base/objs/UniversalGroundMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d82d69bbb70beab5e87943657bdbf3f68cf7326d --- /dev/null +++ b/isis/src/base/objs/UniversalGroundMap/Makefile @@ -0,0 +1,5 @@ +INCS = UniversalGroundMap.h +SRCS = UniversalGroundMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/UniversalGroundMap/UniversalGroundMap.cpp b/isis/src/base/objs/UniversalGroundMap/UniversalGroundMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06be64beab418a72e513d99e97fc155874fe47da --- /dev/null +++ b/isis/src/base/objs/UniversalGroundMap/UniversalGroundMap.cpp @@ -0,0 +1,184 @@ +#include "UniversalGroundMap.h" +#include "Projection.h" +#include "Camera.h" +#include "CameraFactory.h" +#include "ProjectionFactory.h" + +namespace Isis { + /** + * Constructs a UniversalGroundMap object from a pvl + * + * @param pvl The Pvl file to create the UniversalGroundMap from + */ + UniversalGroundMap::UniversalGroundMap(Pvl &pvl) { + Init(pvl); + } + + /** + * Constructs a UniversalGroundMap object from a cube + * + * @param cube The Cube to create the UniversalGroundMap from + */ + UniversalGroundMap::UniversalGroundMap(Cube &cube) { + Init(*(cube.Label())); + } + + /** + * Creates the UniversalGroundMap + * + * @param pvl The Pvl file to create the UniversalGroundMap from + * + * @throws Isis::iException::Camera - Could not create camera or projection + */ + void UniversalGroundMap::Init(Pvl &pvl) { + p_camera = NULL; + p_projection = NULL; + + try { + p_camera = CameraFactory::Create(pvl); + } + catch (iException &e) { + e.Clear(); + p_camera = NULL; + try { + p_projection = Isis::ProjectionFactory::CreateFromCube(pvl); + } + catch (iException &e) { + p_projection = NULL; + std::string msg = "Could not create camera or projection for [" + + pvl.Filename() + "]"; + throw iException::Message(iException::Camera, msg, _FILEINFO_); + } + } + } + + /** + * Set the image band number + * + * @param[in] band (int) Image band number + * + */ + void UniversalGroundMap::SetBand(const int band) { + if (p_camera != NULL) p_camera->SetBand(band); + } + + + + //! Destroys the UniversalGroundMap object + UniversalGroundMap::~UniversalGroundMap() { + if (p_camera != NULL) delete p_camera; + if (p_projection != NULL) delete p_projection; + } + + /** + * Returns whether the lat/lon position was set successfully in the camera + * model or projection + * + * @param lat The universal latitude + * @param lon The universal longitude + * + * @return Returns true if the lat/lon position was set successfully, and false + * if it was not + */ + bool UniversalGroundMap::SetUniversalGround (double lat, double lon) { + if (p_camera != NULL) { + if(p_camera->SetUniversalGround(lat,lon)){ + return p_camera->InCube(); + } else { + return false; + } + } + else { + return p_projection->SetUniversalGround(lat,lon); + } + } + + /** + * Returns the current line value of the camera model or projection + * + * @return Sample value + */ + double UniversalGroundMap::Sample () const { + if (p_camera != NULL) { + return p_camera->Sample(); + } + else { + return p_projection->WorldX(); + } + } + + /** + * Returns the current line value of the camera model or projection + * + * @return Line value + */ + double UniversalGroundMap::Line() const { + if (p_camera != NULL) { + return p_camera->Line(); + } + else { + return p_projection->WorldY(); + } + } + + /** + * Returns whether the sample/line postion was set successfully in the camera + * model or projection + * + * @param sample The sample position + * @param line The line position + * + * @return Returns true if the sample/line position was set successfully, and + * false if it was not + */ + bool UniversalGroundMap::SetImage (double sample, double line) { + if (p_camera != NULL) { + return p_camera->SetImage(sample,line); + } + else { + return p_projection->SetWorld(sample,line); + } + } + + /** + * Returns the universal latitude of the camera model or projection + * + * @return Universal Latitude + */ + double UniversalGroundMap::UniversalLatitude () const { + if (p_camera != NULL) { + return p_camera->UniversalLatitude(); + } + else { + return p_projection->UniversalLatitude(); + } + } + + /** + * Returns the universal longitude of the camera model or projection + * + * @return Universal Longitude + */ + double UniversalGroundMap::UniversalLongitude() const { + if (p_camera != NULL) { + return p_camera->UniversalLongitude(); + } + else { + return p_projection->UniversalLongitude(); + } + } + + /** + * Returns the resolution of the camera model or projection + * + * @return Resolution + */ + double UniversalGroundMap::Resolution() const { + if (p_camera != NULL) { + return p_camera->PixelResolution(); + } + else { + return p_projection->Resolution(); + } + } +} diff --git a/isis/src/base/objs/UniversalGroundMap/UniversalGroundMap.h b/isis/src/base/objs/UniversalGroundMap/UniversalGroundMap.h new file mode 100644 index 0000000000000000000000000000000000000000..047e76fe9d8d25d988015650e7840787d22474d1 --- /dev/null +++ b/isis/src/base/objs/UniversalGroundMap/UniversalGroundMap.h @@ -0,0 +1,98 @@ +#ifndef UniversalGroundMap_h +#define UniversalGroundMap_h +/** + * @file + * $Revision: 1.6 $ + * $Date: 2010/04/29 00:54:15 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { +/** + * @brief Universal Ground Map + * + * ??? + * + * @ingroup Geometry + * + * @author 2005-08-09 Jeff Anderson + * + * @internal + * @todo Jeff Anderson - Finish Class Documentation + * @history 2005-11-09 Tracie Sucharski Added HasProjection method. + * @history 2006-03-20 Elizabeth Miller Added camera, projection, and + * Resolution methods and documentation + * @history 2006-03-31 Elizabeth Miller Added unitTest + * @history 2006-05-17 Elizabeth Miller Depricated CameraManager to + * CameraFactory + * @history 2007-02-06 Tracie Sucharski Added SetBand method. + * @history 2007-02-06 Steven Lambright Fixed documentation + * @history 2009-04-24 Steven Koechle Added a check to SetUniversalGround that + * makes sure the result is on the cube before returning true. + * @history 2010-04-09 Sharmila Prasad Added an API to check for camera in an image + * @history 2010-04-28 Mackenzie Boyd Fixed dereferencing issue in constructor + * that takes a cube. + */ + class Camera; + class Projection; + class Pvl; + class Cube; + + class UniversalGroundMap { + public: + UniversalGroundMap(Pvl &pvl); + UniversalGroundMap(Cube &cube); + ~UniversalGroundMap(); + + void SetBand (const int band); + bool SetUniversalGround (double lat, double lon); + double Sample () const; + double Line() const; + + bool SetImage (double sample, double line); + double UniversalLatitude () const; + double UniversalLongitude() const; + double Resolution() const; + + /** + * Returns whether the ground map has a projection or not + * + * @return bool Returns true if the ground map has a projection, and false + * if it does not + */ + bool HasProjection () { return p_projection != 0; }; + + bool HasCamera() { return p_camera != 0; }; + + //! Return the projection associated with the ground map (NULL implies none) + Isis::Projection *Projection () const { return p_projection; }; + + //! Return the camera associated with the ground map (NULL implies none) + Isis::Camera *Camera () const { return p_camera; }; + + + private: + void Init(Pvl &pvl); + + Isis::Camera *p_camera; //! +#include +#include "iException.h" +#include "UniversalGroundMap.h" +#include "Camera.h" +#include "Pvl.h" +#include "Preference.h" + +using namespace std; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + try{ + cout << "UnitTest for Universal Ground Map" << endl; + + cout << " Testing Camera Model..." << endl; + Isis::Pvl p("$viking2/testData/f348b26.cub"); + Isis::UniversalGroundMap ugm(p);; + cout << setprecision(9); + + cout << "Is Projection? = " << ugm.HasProjection() << endl << endl; + + // Test all four corners to make sure the conversions are right + ugm.SetImage(1.0, 1.0); + cout << "For (1.0, 1.0) ..." << endl; + cout << "Universal Latitude = " << ugm.UniversalLatitude() << endl; + cout << "Universal Longitude = " << ugm.UniversalLongitude() << endl; + + ugm.SetUniversalGround(ugm.UniversalLatitude(), ugm.UniversalLongitude()); + cout << "Sample = " << ugm.Sample() << endl; + cout << "Line = " << ugm.Line() << endl << endl; + + ugm.SetImage(1204, 1.0); + cout << "For (1204, 1.0) ..." << endl; + cout << "Universal Latitude = " << ugm.UniversalLatitude() << endl; + cout << "Universal Longitude = " << ugm.UniversalLongitude() << endl; + + ugm.SetUniversalGround(ugm.UniversalLatitude(), ugm.UniversalLongitude()); + cout << "Sample = " << ugm.Sample() << endl; + cout << "Line = " << ugm.Line() << endl << endl; + + ugm.SetImage(1.0, 1056); + cout << "For (1.0, 1056) ..." << endl; + cout << "Universal Latitude = " << ugm.UniversalLatitude() << endl; + cout << "Universal Longitude = " << ugm.UniversalLongitude() << endl; + + ugm.SetUniversalGround(ugm.UniversalLatitude(), ugm.UniversalLongitude()); + cout << "Sample = " << ugm.Sample() << endl; + cout << "Line = " << ugm.Line() << endl << endl; + + ugm.SetImage(1204, 1056); + cout << "For (1204, 1056) ..." << endl; + cout << "Universal Latitude = " << ugm.UniversalLatitude() << endl; + cout << "Universal Longitude = " << ugm.UniversalLongitude() << endl; + + ugm.SetUniversalGround(ugm.UniversalLatitude(), ugm.UniversalLongitude()); + cout << "Sample = " << ugm.Sample() << endl; + cout << "Line = " << ugm.Line() << endl << endl; + + + + cout << " Testing Projection..." << endl; + Isis::Pvl p2("$base/dems/molaMarsPlanetaryRadius0001.cub"); + Isis::UniversalGroundMap ugm2(p2); + cout << "Is Projection? = " << ugm2.HasProjection() << endl << endl; + + // Test all four corners to make sure the conversions are right + ugm2.SetImage(1.0, 1.0); + cout << "For (1.0, 1.0) ..." << endl; + cout << "Universal Latitude = " << ugm2.UniversalLatitude() << endl; + cout << "Universal Longitude = " << ugm2.UniversalLongitude() << endl; + + ugm2.SetUniversalGround(ugm2.UniversalLatitude(), ugm2.UniversalLongitude()); + cout << "Sample = " << ugm2.Sample() << endl; + cout << "Line = " << ugm2.Line() << endl << endl; + + ugm2.SetImage(23040, 1.0); + cout << "For (23040, 1.0) ..." << endl; + cout << "Universal Latitude = " << ugm2.UniversalLatitude() << endl; + cout << "Universal Longitude = " << ugm2.UniversalLongitude() << endl; + + ugm2.SetUniversalGround(ugm2.UniversalLatitude(), ugm2.UniversalLongitude()); + cout << "Sample = " << ugm2.Sample() << endl; + cout << "Line = " << ugm2.Line() << endl << endl; + + ugm2.SetImage(1.0, 11520); + cout << "For (1.0, 11520) ..." << endl; + cout << "Universal Latitude = " << ugm2.UniversalLatitude() << endl; + cout << "Universal Longitude = " << ugm2.UniversalLongitude() << endl; + + ugm2.SetUniversalGround(ugm2.UniversalLatitude(), ugm2.UniversalLongitude()); + cout << "Sample = " << ugm2.Sample() << endl; + cout << "Line = " << ugm2.Line() << endl << endl; + + ugm2.SetImage(23040, 11520); + cout << "For (23040, 11520) ..." << endl; + cout << "Universal Latitude = " << ugm2.UniversalLatitude() << endl; + cout << "Universal Longitude = " << ugm2.UniversalLongitude() << endl; + + ugm2.SetUniversalGround(ugm2.UniversalLatitude(), ugm2.UniversalLongitude()); + cout << "Sample = " << ugm2.Sample() << endl; + cout << "Line = " << ugm2.Line() << endl << endl; + + cout << " Testing Camera Model and Projection..." << endl; + Isis::Pvl p3("$mgs/testData/m0402852.cub"); + Isis::UniversalGroundMap ugm3(p3); + cout << "Is Projection? = " << ugm3.HasProjection() << endl << endl; + + // Test all four corners to make sure the conversions are right + ugm3.SetImage(1.0, 1.0); + cout << "For (1.0, 1.0) ..." << endl; + cout << "Universal Latitude = " << ugm3.UniversalLatitude() << endl; + cout << "Universal Longitude = " << ugm3.UniversalLongitude() << endl; + + ugm3.SetUniversalGround(ugm3.UniversalLatitude(), ugm3.UniversalLongitude()); + cout << "Sample = " << ugm3.Sample() << endl; + cout << "Line = " << ugm3.Line() << endl << endl; + + ugm3.SetImage(1721, 1.0); + cout << "For (1721, 1.0) ..." << endl; + cout << "Universal Latitude = " << ugm3.UniversalLatitude() << endl; + cout << "Universal Longitude = " << ugm3.UniversalLongitude() << endl; + + ugm3.SetUniversalGround(ugm3.UniversalLatitude(), ugm3.UniversalLongitude()); + cout << "Sample = " << ugm3.Sample() << endl; + cout << "Line = " << ugm3.Line() << endl << endl; + + ugm3.SetImage(1.0, 667); + cout << "For (1.0, 667) ..." << endl; + cout << "Universal Latitude = " << ugm3.UniversalLatitude() << endl; + cout << "Universal Longitude = " << ugm3.UniversalLongitude() << endl; + + ugm3.SetUniversalGround(ugm3.UniversalLatitude(), ugm3.UniversalLongitude()); + cout << "Sample = " << ugm3.Sample() << endl; + cout << "Line = " << ugm3.Line() << endl << endl; + + ugm3.SetImage(1721, 667); + cout << "For (1721, 667) ..." << endl; + cout << "Universal Latitude = " << ugm3.UniversalLatitude() << endl; + cout << "Universal Longitude = " << ugm3.UniversalLongitude() << endl; + + ugm3.SetUniversalGround(ugm3.UniversalLatitude(), ugm3.UniversalLongitude()); + cout << "Sample = " << ugm3.Sample() << endl; + cout << "Line = " << ugm3.Line() << endl << endl; + + } + catch (Isis::iException &e) { + e.Report(); + } +} + + + + + + + diff --git a/isis/src/base/objs/UserInterface/Makefile b/isis/src/base/objs/UserInterface/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..362fbaa0199373aa75163e1f9c4e18768940d211 --- /dev/null +++ b/isis/src/base/objs/UserInterface/Makefile @@ -0,0 +1,5 @@ +INCS = UserInterface.h +SRCS = UserInterface.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/UserInterface/UserInterface.cpp b/isis/src/base/objs/UserInterface/UserInterface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1332955e396f2da49b2a4786004a3bb74f9069b --- /dev/null +++ b/isis/src/base/objs/UserInterface/UserInterface.cpp @@ -0,0 +1,945 @@ +/** + * @file + * $Revision: 1.17 $ + * $Date: 2010/05/28 17:55:36 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "UserInterface.h" +#include "iException.h" +#include "Filename.h" +#include "iString.h" +#include "System.h" +#include "Message.h" +#include "Gui.h" +#include "Preference.h" +#include "TextFile.h" + +using namespace std; +namespace Isis { + + /** + * Constructs an UserInterface object. + * + * @param xmlfile Name of the Isis application xml file to open. + * + * @param argc Number of arguments on the command line. Must be pass by + * reference!! + * + * @param argv[] Array of arguments + */ + UserInterface::UserInterface(const std::string &xmlfile, int &argc, char *argv[]) : + IsisAml::IsisAml(xmlfile) { + p_interactive = false; + p_info = false; + p_infoFileName = ""; + p_gui = NULL; + p_errList = ""; + p_saveFile = ""; + p_abortOnError = true; + p_parentId = 0; + + // Make sure the user has a .Isis and .Isis/history directory + try { + Isis::Filename setup("$HOME/.Isis"); + if(!setup.Exists()) { + setup.MakeDirectory(); + } + + setup = "$HOME/.Isis/history"; + if(!setup.Exists()) { + setup.MakeDirectory(); + } + } + catch(iException &e) { + e.Clear(); + } + + // Parse the user input + LoadCommandLine(argc, argv); + + // See if we need to create the gui + if(p_interactive) { + p_gui = Gui::Create(*this, argc, argv); + } + } + + //! Destroys the UserInterface object + UserInterface::~UserInterface() { + if(p_gui) { + delete p_gui; + p_gui = NULL; + } + } + + /** + * This is used to load the command line into p_cmdline and the Aml object + * using information contained in argc and argv. + * + * @param argc Number of arguments on the command line + * + * @param argv[] Array of arguments + * + * @throws Isis::iException::User - Invalid command line + * @throws Isis::iException::System - -GUI and -PID are incompatible arguments + * @throws Isis::iException::System - -BATCHLIST & -GUI are incompatible + * arguments + */ + void UserInterface::LoadCommandLine(int argc, char *argv[]) { + // The program will be interactive if it has no arguments or + // if it has the name unitTest + p_progName = argv[0]; + Isis::Filename file(p_progName); + if((argc == 1) && (file.Name() != "unitTest")) { + p_interactive = true; + } + + p_cmdline.clear(); + for(int i = 0; i < argc; i++) { + p_cmdline.push_back(argv[i]); + } + + // Check for special tokens (those beginning with a dash) + vector options; + options.push_back("-GUI"); + options.push_back("-NOGUI"); + options.push_back("-BATCHLIST"); + options.push_back("-LAST"); + options.push_back("-RESTORE"); + options.push_back("-WEBHELP"); + options.push_back("-HELP"); + options.push_back("-ERRLIST"); + options.push_back("-ONERROR"); + options.push_back("-SAVE"); + options.push_back("-INFO"); + options.push_back("-PREFERENCE"); + options.push_back("-LOG"); + options.push_back("-VERBOSE"); + options.push_back("-PID"); + + bool usedDashLast = false; + + for(unsigned int currArgument = 1; currArgument < (unsigned)argc; currArgument ++) { + string paramName; + vector paramValue; + + GetNextParameter(currArgument, paramName, paramValue); + + // we now have a name,value pair + if(paramName[0] == '-') { + paramName = ((iString)paramName).UpCase(); + + if(paramValue.size() > 1) { + string msg = "Invalid value for reserve parameter [" + + paramName + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + // We have an option (not a parameter)... + int matchOption = -1; + + for(int option = 0; option < (int)options.size(); option++) { + // If our option starts with the parameter name so far, this is it + if(options[option].find(paramName) == 0) { + if(matchOption >= 0) { + string msg = "Ambiguous Reserve Parameter [" + + paramName + "]. Please clarify."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + matchOption = option; + } + } + + if(matchOption < 0) { + string msg = "Invalid Reserve Parameter Option [" + + paramName + "]. Choices are "; + + iString msgOptions; + for(int option = 0; option < (int)options.size() - 1; option++) { + // Make sure not to show -PID as an option + if(options[option].compare("-PID") != 0) { + continue; + } + + if(!options.empty()) { + msgOptions += ","; + } + + msgOptions += options[option]; + } + + msg += " [" + msgOptions + "]"; + + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + paramName = options[matchOption]; + + if(paramName == "-LAST") { + usedDashLast = true; + } + + iString realValue = ""; + + if(paramValue.size()) realValue = paramValue[0]; + + EvaluateOption(paramName, realValue); + continue; + } + + try { + Clear(paramName); + PutAsString(paramName, paramValue); + } + catch(Isis::iException &e) { + throw Isis::iException::Message(Isis::iException::User, "Invalid command line", _FILEINFO_); + } + } + + // Can't use the batchlist with the gui, save, last or restore option + if(BatchListSize() != 0 && (p_interactive || usedDashLast + || p_saveFile != "")) { + string msg = "-BATCHLIST cannot be used with -GUI, -SAVE, -RESTORE, "; + msg += "or -LAST"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + + // Must use batchlist if using errorlist or onerror=continue + if((BatchListSize() == 0) && (!p_abortOnError || p_errList != "")) { + string msg = "-ERRLIST and -ONERROR=continue cannot be used without "; + msg += " the -BATCHLIST option"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + } + + + /** + * This gets the next parameter in the list of arguments. curPos will be changed + * to be the end of the current argument (still needs incremented to get the + * next argument). + * + * @param curPos End of previous argument + * @param name Resulting parameter name + * @param value Resulting array of parameter values (usually just 1 element) + */ + void UserInterface::GetNextParameter(unsigned int &curPos, std::string &name, + std::vector &value) { + iString paramName = p_cmdline[curPos]; + iString paramValue = ""; + + // we need to split name and value, they can either be in 1, 2 or 3 arguments, + // try to see if "=" is end of argument to distinguish. Some options have no + // "=" and they are value-less (-gui for example). + if(paramName.find("=") == string::npos) { + // This looks value-less, but lets make sure + // the next argument is not an equals sign by + // itself + if(curPos < p_cmdline.size() - 2) { + if(string(p_cmdline[curPos+1]).compare("=") == 0) { + paramValue = p_cmdline[curPos+2]; + + // increment extra to skip 2 elements next time around + curPos += 2; + } + } + } + // = is end of parameter, next item must be value + else if(paramName.find("=") == paramName.size() - 1) { + paramName = paramName.substr(0, paramName.size() - 1); + + if(curPos + 1 < p_cmdline.size()) { + paramValue = p_cmdline[curPos+1]; + } + + // increment extra to skip next element next time around + curPos ++; + } + // we found "=" in the middle + else if(paramName.find("=") != 0) { + string parameterLiteral = p_cmdline[curPos]; + paramName = parameterLiteral.substr(0, parameterLiteral.find("=")); + paramValue = parameterLiteral.substr(parameterLiteral.find("=") + 1); + } + // We found "=" at the beginning - did we find "appname param =value" ? + else { + // parameters can not start with "=" + string msg = "Unknown parameter [" + string(p_cmdline[curPos]) + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + name = paramName; + value.clear(); + + // read arrays out of paramValue + paramValue = paramValue.Trim(" "); + + if(paramValue.length() > 0 && paramValue[0] != '(') { + // We dont have an array... if they escaped + // an open paren, undo their escape + + // escape: \( result: ( + if(paramValue.length() > 1 && paramValue.substr(0, 2).compare("\\(") == 0) { + paramValue = paramValue.substr(1); + } + // escape: \\( result: \( + else if(paramValue.length() > 2 && paramValue.substr(0, 4).compare("\\\\(") == 0) { + paramValue = paramValue.substr(1); + } + + value.push_back(paramValue); + } + else if(paramValue.length()) { + // We have an array... + value = ReadArray(paramValue); + } + } + + + /** + * This interprets an array value from the command line. + * + * @param arrayString Parameter value containing an array of + * format (a,b,c) + * + * @return std::vector Values in the array string + */ + std::vector UserInterface::ReadArray(iString arrayString) { + std::vector values; + + bool inDoubleQuotes = false; + bool inSingleQuotes = false; + bool arrayClosed = false; + iString currElement = ""; + + for(unsigned int strPos = 0; strPos < arrayString.size(); strPos++) { + if(strPos == 0) { + if(arrayString[strPos] != '(') { + string msg = "Invalid array format [" + arrayString + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + continue; + } + + // take literally anything that is escaped and not quoted + if(arrayString[strPos] == '\\' && strPos + 1 < arrayString.size() && + !inDoubleQuotes && !inSingleQuotes) { + currElement += arrayString[strPos+1]; + strPos ++; + continue; + } + // ends in a backslash?? + else if(arrayString[strPos] == '\\' && !(inDoubleQuotes || inSingleQuotes)) { + string msg = "Invalid array format [" + arrayString + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + // not in quoted part of string + if(!inDoubleQuotes && !inSingleQuotes) { + if(arrayClosed) { + string msg = "Invalid array format [" + arrayString + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + if(arrayString[strPos] == '"') { + inDoubleQuotes = true; + } + else if(arrayString[strPos] == '\'') { + inSingleQuotes = true; + } + else if(arrayString[strPos] == ',') { + values.push_back(currElement); + currElement = ""; + } + else if(arrayString[strPos] == ')') { + values.push_back(currElement); + currElement = ""; + arrayClosed = true; + } + else { + currElement += arrayString[strPos]; + } + } + else if(inSingleQuotes) { + if(arrayString[strPos] == '\'') { + inSingleQuotes = false; + } + else { + currElement += arrayString[strPos]; + } + } + // in double quotes + else { + if(arrayString[strPos] == '"') { + inDoubleQuotes = false; + } + else { + currElement += arrayString[strPos]; + } + } + } + + if(!arrayClosed || currElement != "") { + string msg = "Invalid array format [" + arrayString + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + return values; + } + + + /** + * This interprets the "-" options for reserved parameters + * + * @param name "-OPTIONNAME" + * @param value Value of the option, if supplied (-name=value) + */ + void UserInterface::EvaluateOption(const std::string name, const std::string value) { + Preference &p = Preference::Preferences(); + + if(name == "-GUI") { + p_interactive = true; + } + else if(name == "-NOGUI") { + p_interactive = false; + } + else if(name == "-BATCHLIST") { + LoadBatchList(value); + } + else if(name == "-LAST") { + PvlGroup &grp = p.FindGroup("UserInterface", Isis::Pvl::Traverse); + iString histFile = grp["HistoryPath"][0] + "/" + Filename(p_progName).Name() + ".par"; + + LoadHistory(histFile); + } + else if(name == "-RESTORE") { + LoadHistory(value); + } + else if(name == "-WEBHELP") { + Isis::PvlGroup &pref = Isis::Preference::Preferences().FindGroup("UserInterface"); + string command = pref["GuiHelpBrowser"]; + command += " $ISISROOT/doc/Application/presentation/Tabbed/"; + command += Filename(p_progName).Name() + "/" + Filename(p_progName).Name() + ".html"; + Isis::System(command); + exit(0); + } + else if(name == "-INFO") { + p_info = true; + + // check for filename and set value + if(value.size() != 0) { + p_infoFileName = value; + } + } + else if(name == "-HELP") { + if(value.size() == 0) { + Pvl params; + params.SetTerminator(""); + for(int k = 0; k < NumGroups(); k++) { + for(int j = 0; j < NumParams(k); j++) { + if(ParamListSize(k, j) == 0) { + params += PvlKeyword(ParamName(k, j), ParamDefault(k, j)); + } + else { + PvlKeyword key(ParamName(k, j)); + string def = ParamDefault(k, j); + for(int l = 0; l < ParamListSize(k, j); l++) { + if(ParamListValue(k, j, l) == def) key.AddValue("*" + def); + else key.AddValue(ParamListValue(k, j, l)); + } + params += key; + } + } + } + cout << params; + } + else { + Pvl param; + param.SetTerminator(""); + string key = value; + for(int k = 0; k < NumGroups(); k++) { + for(int j = 0; j < NumParams(k); j++) { + if(ParamName(k, j) == key) { + param += PvlKeyword("ParameterName", key); + param += PvlKeyword("Brief", ParamBrief(k, j)); + param += PvlKeyword("Type", ParamType(k, j)); + if(PixelType(k, j) != "") { + param += PvlKeyword("PixelType", PixelType(k, j)); + } + if(ParamInternalDefault(k, j) != "") { + param += PvlKeyword("InternalDefault", + ParamInternalDefault(k, j)); + } + else param += PvlKeyword("Default", ParamDefault(k, j)); + if(ParamMinimum(k, j) != "") { + if(ParamMinimumInclusive(k, j) == "YES") { + param += PvlKeyword("GreaterThanOrEqual", ParamMinimum(k, j)); + } + else { + param += PvlKeyword("GreaterThan", ParamMinimum(k, j)); + } + } + if(ParamMaximum(k, j) != "") { + if(ParamMaximumInclusive(k, j) == "YES") { + param += PvlKeyword("LessThanOrEqual", ParamMaximum(k, j)); + } + else { + param += PvlKeyword("LessThan", ParamMaximum(k, j)); + } + } + if(ParamLessThanSize(k, j) > 0) { + PvlKeyword key("LessThan"); + for(int l = 0; l < ParamLessThanSize(k, j); l++) { + key.AddValue(ParamLessThan(k, j, l)); + } + param += key; + } + if(ParamLessThanOrEqualSize(k, j) > 0) { + PvlKeyword key("LessThanOrEqual"); + for(int l = 0; l < ParamLessThanOrEqualSize(k, j); l++) { + key.AddValue(ParamLessThanOrEqual(k, j, l)); + } + param += key; + } + if(ParamNotEqualSize(k, j) > 0) { + PvlKeyword key("NotEqual"); + for(int l = 0; l < ParamNotEqualSize(k, j); l++) { + key.AddValue(ParamNotEqual(k, j, l)); + } + param += key; + } + if(ParamGreaterThanSize(k, j) > 0) { + PvlKeyword key("GreaterThan"); + for(int l = 0; l < ParamGreaterThanSize(k, j); l++) { + key.AddValue(ParamGreaterThan(k, j, l)); + } + param += key; + } + if(ParamGreaterThanOrEqualSize(k, j) > 0) { + PvlKeyword key("GreaterThanOrEqual"); + for(int l = 0; l < ParamGreaterThanOrEqualSize(k, j); l++) { + key.AddValue(ParamGreaterThanOrEqual(k, j, l)); + } + param += key; + } + if(ParamIncludeSize(k, j) > 0) { + PvlKeyword key("Inclusions"); + for(int l = 0; l < ParamIncludeSize(k, j); l++) { + key.AddValue(ParamInclude(k, j, l)); + } + param += key; + } + if(ParamExcludeSize(k, j) > 0) { + PvlKeyword key("Exclusions"); + for(int l = 0; l < ParamExcludeSize(k, j); l++) { + key.AddValue(ParamExclude(k, j, l)); + } + param += key; + } + if(ParamOdd(k, j) != "") { + param += PvlKeyword("Odd", ParamOdd(k, j)); + } + if(ParamListSize(k, j) != 0) { + for(int l = 0; l < ParamListSize(k, j); l++) { + PvlGroup grp(ParamListValue(k, j, l)); + grp += PvlKeyword("Brief", ParamListBrief(k, j, l)); + if(ParamListIncludeSize(k, j, l) != 0) { + PvlKeyword include("Inclusions"); + for(int m = 0; m < ParamListIncludeSize(k, j, l); m++) { + include.AddValue(ParamListInclude(k, j, l, m)); + } + grp += include; + } + if(ParamListExcludeSize(k, j, l) != 0) { + PvlKeyword exclude("Exclusions"); + for(int m = 0; m < ParamListExcludeSize(k, j, l); m++) { + exclude.AddValue(ParamListExclude(k, j, l, m)); + } + grp += exclude; + } + param.AddGroup(grp); + } + } + cout << param; + } + } + } + } + exit(0); + } + else if(name == "-PID") { + p_parentId = iString(value).ToInteger(); + } + else if(name == "-ERRLIST") { + p_errList = value; + + if(value == "") { + string msg = "-ERRLIST expects a file name"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + if(Filename(p_errList).Exists()) { + remove(p_errList.c_str()); + } + } + else if(name == "-ONERROR") { + if(iString(value).UpCase() == "CONTINUE") { + p_abortOnError = false; + } + + else if(iString(value).UpCase() == "ABORT") { + p_abortOnError = true; + } + + else { + string msg = "[" + value + + "] is an invalid value for -ONERROR, options are ABORT or CONTINUE"; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + } + else if(name == "-SAVE") { + if(value.size() == 0) { + p_saveFile = ProgramName() + ".par"; + } + else { + p_saveFile = value; + } + } + else if(name == "-PREFERENCE") { + p.Load(value); + } + else if(name == "-LOG") { + if(value.empty()) { + p.FindGroup("SessionLog")["FileOutput"].SetValue("On"); + } + else { + p.FindGroup("SessionLog")["FileOutput"].SetValue("On"); + p.FindGroup("SessionLog")["FileName"].SetValue(value); + } + } + else if(name == "-VERBOSE") { + p.FindGroup("SessionLog")["TerminalOutput"].SetValue("On"); + } + + // Can't have a parent id and the gui + if(p_parentId > 0 && p_interactive) { + string msg = "-GUI and -PID are incompatible arguments"; + throw Isis::iException::Message(Isis::iException::System, msg, _FILEINFO_); + } + } + + + /** + * Loads the user entered batchlist file into a private variable for later use + * + * @param file The batchlist file to load + * + * @history 2010-03-26 Sharmila Prasad - Remove the restriction of the number of + * columns in the batchlist file to 10. + * @throws Isis::iException::User - The batchlist does not contain any data + */ + void UserInterface::LoadBatchList(const std::string file) { + // Read in the batch list + TextFile temp; + try { + temp.Open(file); + } + catch(iException &e) { + string msg = "The batchlist file [" + file + "] could not be opened"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + p_batchList.resize(temp.LineCount()); + + for(int i = 0; i < temp.LineCount(); i++) { + iString t; + temp.GetLine(t); + + // Convert tabs to spaces but leave tabs inside quotes alone + t.Replace("\t", " ", true); + + t.Compress(); + t.Trim(" "); + // Allow " ," " , " or ", " as a valid single seperator + t.Replace(" ," , "," , true); + t.Replace(", " , "," , true); + // Convert all spaces to "," the use "," as delimiter + t.Replace(" ", "," , true); + int j = 0; + iString token = t.Token(","); + + while(token != "") { + // removes quotes from tokens. NOTE: also removes escaped quotes. + token = token.Remove("\"'"); + p_batchList[i].push_back(token); + token = t.Token(","); + j++; + } + p_batchList[i].resize(j); + // Every row in the batchlist must have the same number of columns + if(i == 0) continue; + if(p_batchList[i-1].size() != p_batchList[i].size()) { + string msg = "The number of columns must be constant in batchlist"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + // The batchlist cannot be empty + if(p_batchList.size() < 1) { + string msg = "The list file [" + file + "] does not contain any data"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + + /** + * Loads the previous history for the program + * + * @param file Filename to get the history entry from + * + * @throws Isis::iException::User - The file does not contain any parameters + * to restore + * @throws Isis::iException::User - The file does not contain a valid parameter + * history file + * @throws Isis::iException::User - Parameter history file does not exist + */ + void UserInterface::LoadHistory(const std::string file) { + Isis::Filename hist(file); + if(hist.Exists()) { + try { + Isis::Pvl lab(hist.Expanded()); + + int g = lab.Groups() - 1; + if(g >= 0 && lab.Group(g).IsNamed("UserParameters")) { + Isis::PvlGroup &up = lab.Group(g); + for(int k = 0; k < up.Keywords(); k++) { + string keyword = up[k].Name(); + string value = up[k][0]; + PutAsString(keyword, value); + } + return; + } + + for(int o = lab.Objects() - 1; o >= 0; o--) { + if(lab.Object(o).IsNamed(ProgramName())) { + Isis::PvlObject &obj = lab.Object(o); + for(int g = obj.Groups() - 1; g >= 0; g--) { + Isis::PvlGroup &up = obj.Group(g); + if(up.IsNamed("UserParameters")) { + for(int k = 0; k < up.Keywords(); k++) { + string keyword = up[k].Name(); + string value = up[k][0]; + PutAsString(keyword, value); + } + } + return; + } + } + } + + string msg = "[" + hist.Expanded() + + "] does not contain any parameters to restore"; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + catch(...) { + string msg = "A corrupt parameter history file [" + file + + "] has been detected. Please fix or remove this file"; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + } + else { + string msg = "Parameter history file [" + file + + "] does not exist"; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + } + + /** + * Saves the user parameter information in the history of the program for later + * use + */ + void UserInterface::SaveHistory() { + + // If history recording is off, return + Preference &p = Preference::Preferences(); + PvlGroup &grp = p.FindGroup("UserInterface", Isis::Pvl::Traverse); + if(grp["HistoryRecording"][0] == "Off") return; + + // Get the current history file + Isis::Filename histFile(grp["HistoryPath"][0] + "/" + ProgramName() + ".par"); + + // If a save file is specified, override the default file path + if(p_saveFile != "") histFile = p_saveFile; + + // Get the current command line + Isis::Pvl cmdLine; + CommandLine(cmdLine); + + Isis::Pvl hist; + + // If the history file's Pvl is corrupted, then + // leave hist empty such that the history gets + // overwriten with the new entry. + try { + if(histFile.Exists()) { + hist.Read(histFile.Expanded()); + } + } + catch(iException e) { + e.Clear(); + } + + // Add it + hist.AddGroup(cmdLine.FindGroup("UserParameters")); + + // See if we have exceeded history length + while(hist.Groups() > (int)grp["HistoryLength"][0]) { + hist.DeleteGroup("UserParameters"); + } + + // Write it + try { + hist.Write(histFile.Expanded()); + } + catch(iException &e) { + e.Clear(); + } + + } + + /** + * Clears the gui parameters and sets the batch list information at line i as + * the new parameters + * + * @param i The line number to retrieve parameter information from + */ + void UserInterface::SetBatchList(int i) { + //Clear all parameters currently in the gui + for(int k = 0; k < NumGroups(); k++) { + for(int j = 0; j < NumParams(k); j++) { + Clear(ParamName(k, j)); + } + } + + //Load the new parameters into the gui + cout << p_progName << " "; + + for(unsigned int currArgument = 1; currArgument < p_cmdline.size(); currArgument++) { + string paramName; + vector paramValue; + + try { + GetNextParameter(currArgument, paramName, paramValue); + + if(paramName[0] == '-') continue; + + for(unsigned int value = 0; value < paramValue.size(); value ++) { + iString thisValue = paramValue[value]; + + string token = thisValue.Token("$"); + iString newValue; + + while(thisValue != "") { + newValue += token; + int j = iString(thisValue.substr(0, 1)).ToInteger() - 1; + newValue += p_batchList[i][j]; + thisValue.replace(0, 1, ""); + token = thisValue.Token("$"); + } + + if(token != "") newValue += token; + + paramValue[value] = newValue; + } + } + catch(Isis::iException &e) { + throw Isis::iException::Message(Isis::iException::User, "Invalid command line", _FILEINFO_); + } + + PutAsString(paramName, paramValue); + + cout << paramName; + + if(paramValue.size() == 1) { + cout << "=" << paramValue[0] << " "; + } + else if(paramValue.size() > 1) { + cout << "=("; + + for(unsigned int value = 0; value < paramValue.size(); value ++) { + if(value != 0) cout << ","; + + cout << paramValue[value] << endl; + } + + cout << ") "; + } + } + cout << endl; + + // Verify the command line + VerifyAll(); + } + + /** + * This method adds the line specified in the BatchList that the error occured + * on. The BatchList line is added exactly as it is seen, so the BatchList + * command can be run on the errorlist file created. + * + * @param i The line of the batchlist to write to the error file + */ + void UserInterface::SetErrorList(int i) { + if(p_errList != "") { + std::ofstream os; + string fileName(Filename(p_errList).Expanded()); + os.open(fileName.c_str(), std::ios::app); + + if(!os.good()) { + string msg = "Unable to create error list [" + p_errList + + "] Disk may be full or directory permissions not writeable"; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + + for(int j = 0; j < (int)p_batchList[i].size(); j++) { + os << p_batchList[i][j] << " "; + } + + os << endl; + os.close(); + } + } + + /** + * This method returns the flag state of info. This returns if + * its in debugging mode(the -info tag was specified). + */ + bool UserInterface::GetInfoFlag() { + return p_info; + } + + /** + * This method returns the filename where the debugging info is + * stored when the "-info" tag is used. + */ + std::string UserInterface::GetInfoFileName() { + return p_infoFileName; + } +} // end namespace isis diff --git a/isis/src/base/objs/UserInterface/UserInterface.h b/isis/src/base/objs/UserInterface/UserInterface.h new file mode 100644 index 0000000000000000000000000000000000000000..7c013189584ba7d3dddb4cc558bd75dc276765d7 --- /dev/null +++ b/isis/src/base/objs/UserInterface/UserInterface.h @@ -0,0 +1,198 @@ +#ifndef UserInterface_h +#define UserInterface_h +/** + * @file + * $Revision: 1.14 $ + * $Date: 2010/05/28 17:55:36 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "IsisAml.h" +#include "PvlTokenizer.h" +#include "Filename.h" +#include "Gui.h" + +class Gui; + +namespace Isis { + /** + * @brief Command Line and Xml loader, validation, and access + * + * This object is used to load and query user input via the command line. It + * requires as input to the constructor 1) an Isis Application Xml file and 2) + * the command line arguments (argc and argv). The Xml file will be used to + * validate the user input given on the command line (if any). To access user + * input see the Aml class which is inherited. + * + * @ingroup ApplicationInterface + * + * @author 2002-05-29 Jeff Anderson + * + * @internal + * @history 2002-10-25 Jeff Anderson - Command line mode was not fully + * verifying the AML object. Invoked the + * VerifyAll method after loading each of + * the command line tokens. + * @history 2003-02-07 Jeff Anderson - Modified constructor so that it will not + * start the GUI if the program name is + * unitTest. + * @history 2003-02-12 Jeff Anderson - Strip off leading directory in front of + * argv[0] so that unit tests run with + * pathnames do not start the Isis Gui. + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-12-16 Jeff Anderson - Added command line option -LAST and + * -RESTORE=file.par + * @history 2004-02-26 Jeff Anderson - Added command line option -HELP + * @history 2004-02-26 Jeff Anderson - Modified to allow a parameter to appear + * multiple times on the command line + * @history 2004-02-29 Jeff Anderson - Added the -PID command line switch which + * allows interprocess communication to + * occur with the parent so that the + * parents GUI can be properly updated. + * @history 2005-02-22 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-10-03 Elizabeth Miller - changed @ingroup tag + * @history 2005-12-21 Elizabeth Miller - Added command line options -BATCHLIST, + * -SAVE, -ERRLIST, -ONERROR, + * -PREFERENCE, and -PRINTFILE + * @history 2006-01-23 Elizabeth Miller - Renamed -HELP to -WEBHELP and made it + * accept abbreviations of reserve params + * @history 2007-07-12 Steven Koechle - Added -NOGUI flag + * @history 2007-10-04 Steven Koechle - Added -info flag. Debugging option to + * create a log of system info. + * @history 2008-02-22 Steven Koechle - Modified batchlist to take tab, + * command, and space characters as + * delimiters but also allow special cases + * like tab, as a single delimiter leaves + * quoted strings alone. + * @history 2008-04-16 Steven Lambright - Moved parameter verification call + * @history 2008-06-06 Steven Lambright - Changed corrupt history file message + * @history 2008-06-18 Steven Lambright - Fixed documentation + * @history 2008-09-23 Christopher Austin - Added a try/catch to SaveHistory(), + * where if the history file is corrupt, it + * simply overwrites it with the new single + * valid entry. + * @history 2008-01-07 Steven Lambright - Changed unit test and error on + * invalid parameter history files to conform with a Filename class + * change where Expanded(...) always returns a full path. + * @history 2009-08-17 Steven Lambright - Parameters are now more correctly + * interpretted from argv resulting in fewer escape characters and + * problems such as " " (2 spaces) being interpretted properly. Array + * parameter values support improved. + * @history 2009-11-19 Kris Becker - Made argc pass by reference since Qt's + * QApplication/QCoreApplication requires it + * @history 2010-03-26 Sharmila Prasad - Remove the restriction of the number of + * columns in the batchlist file to 10. + * @history 2010-05-28 Steven Lambright - History fails silently now + * @todo 2005-02-22 Jeff Anderson - add coded and implementation examples to + * class documentation + * + */ + + class UserInterface : public IsisAml { + public: + UserInterface(const std::string &xmlfile, int &argc, char *argv[]); + ~UserInterface(); + + /** + * Indicates if the Isis Graphical User Interface is operating. + * + * @return bool + */ + bool IsInteractive() { + return p_gui != NULL; + }; + + /** + * return the Gui + */ + Gui *TheGui() { + return p_gui; + }; + + + /** + * Returns the size of the batchlist. If there is no batchlist, it will + * return 0 + * + * @return int The size of the batchlist + */ + int BatchListSize() { + return p_batchList.size(); + }; + + /** + * Returns the parent id + * + * @return int The parent id + */ + int ParentId() { + return p_parentId; + }; + + /** + * Returns true if the program should abort on error, and false if it + * should continue + * + * @return bool True for abort, False for continue + */ + bool AbortOnError() { + return p_abortOnError; + }; + + void SaveHistory(); + void SetBatchList(int i); + void SetErrorList(int i); + + bool GetInfoFlag(); + std::string GetInfoFileName(); + + private: + std::vector p_cmdline; /** &value); + std::vector ReadArray(iString arrayString); + + //! Boolean value representing whether to abort or continue on error + bool p_abortOnError; + std::string p_saveFile; //! > p_batchList; + + bool p_interactive; /**> biscuit, + >> bread, + >> ,b,\,iscuit2,, + >> + +GUI: 0 + +Testing param = value Format +FROM: dog +TO: bread +GUI: 0 + +Testing Space in Argument Value +FROM: input file.cub +TO: output.cub +GUI: 0 + +Testing unitTest v. ./unitTest for GUI +GUI: 0 + +GUI: 0 + +Starting Batchlist Test +unitTest from=peaks.cub to=out1.txt +FROM: peaks.cub +TO: out1.txt +GUI: 0 + +unitTest from=peaks.cub to=out2.txt +FROM: peaks.cub +TO: out2.txt +GUI: 0 + +unitTest from=peaks.cub to=out3.txt +FROM: peaks.cub +TO: out3.txt +GUI: 0 + +unitTest from=peaks.cub to=out4.txt +FROM: peaks.cub +TO: out4.txt +GUI: 0 + +unitTest from=peaks.cub to= out 5.txt +FROM: peaks.cub +TO: out 5.txt +GUI: 0 + +unitTest from=peaks.cub to= out 6.txt +FROM: peaks.cub +TO: out 6.txt +GUI: 0 + +Finished Batchlist Test + +Testing =value +**USER ERROR** Unknown parameter [=input.cub] + +Testing param =value +**USER ERROR** Unknown parameter [=bread] + +Testing unterminated array-value quote +**USER ERROR** Invalid array format [("hello)] + +Testing array-value ending in backslash +**USER ERROR** Invalid array format [(hello)\] + +FROM: It +TO: Worked +GUI: 0 + +**USER ERROR** Invalid command line +**USER ERROR** Unknown parameter [bogus]. + +**USER ERROR** Parameter history file [junk.par] does not exist diff --git a/isis/src/base/objs/UserInterface/unitTest.cpp b/isis/src/base/objs/UserInterface/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a835cf8da2adc3409a2e395f8f385503723b6834 --- /dev/null +++ b/isis/src/base/objs/UserInterface/unitTest.cpp @@ -0,0 +1,273 @@ +#include +#include "UserInterface.h" +#include "iException.h" +#include "Preference.h" +#include "Filename.h" + +using namespace std; + +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Unit test for Isis::UserInterface ..." << endl; + + Isis::iString unitTestXml = Isis::Filename("unitTest.xml").Expanded(); + string highpass = Isis::Filename("$ISISROOT/src/base/apps/highpass/highpass.xml").Expanded(); + + try { + cout << "Basic FROM/TO Test" << endl; + { + const int myArgc = 3; + char *myArgv[myArgc] = {"unitTest", "from=input.cub", "to=output.cub"}; + + int myArgcQ = myArgc; + Isis::UserInterface ui(unitTestXml, myArgcQ, myArgv); + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: " << ui.GetAsString("TO") << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + + cout << "Testing param= value Format" << endl; + { + const int myArgc = 7; + char *myArgv[myArgc] = {"highpass", "from=dog", "to=biscuit", "line=", "3", "samp=", "3"}; + + int myArgcQ = myArgc; + Isis::UserInterface ui(highpass, myArgcQ, myArgv); + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: " << ui.GetAsString("TO") << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + + cout << "Testing No Arguments (Defaults)" << endl; + { + const int myArgc = 1; + char *myArgv[myArgc] = {"unitTest"}; + + int myArgcQ = myArgc; + Isis::UserInterface ui(unitTestXml, myArgcQ, myArgv); + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: " << ui.GetAsString("TO") << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + + cout << "Testing Basic Array Argument" << endl; + { + const int myArgc = 7; + char *myArgv[myArgc] = {"highpass", "from=dog", "to=(biscuit,bread)", "line=", "3", "samp=", "3"}; + + int myArgcQ = myArgc; + Isis::UserInterface ui(highpass, myArgcQ, myArgv); + vector vals; + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: "; + ui.GetAsString("TO", vals); + + for(unsigned int i = 0; i < vals.size(); i++) { + if(i != 0) cout << ","; + + cout << vals[i]; + } + + cout << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + + cout << "Testing Complicated Array Argument" << endl; + { + const int myArgc = 7; + char *myArgv[myArgc] = {"highpass", "from=dog", + "to=(biscuit\\,,'bread,',\",b,\\,iscuit2,\"\\,,)", + "line=", "3", "samp=", "3" + }; + + int myArgcQ = myArgc; + Isis::UserInterface ui(highpass, myArgcQ, myArgv); + vector vals; + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: " << endl; + ui.GetAsString("TO", vals); + + for(unsigned int i = 0; i < vals.size(); i++) { + cout << " >> " << vals[i] << endl; + } + + cout << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + + cout << "Testing param = value Format" << endl; + { + const int myArgc = 13; + char *myArgv[myArgc] = {"highpass", "from", "=", "dog", "to", "=", "bread", "line", "=", "3", "samp", "=", "3"}; + + int myArgcQ = myArgc; + Isis::UserInterface ui(highpass, myArgcQ, myArgv); + vector vals; + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: " << ui.GetAsString("TO") << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + + cout << "Testing Space in Argument Value" << endl; + { + const int myArgc = 3; + char *myArgv[myArgc] = {"unitTest", "from=input file.cub", "to=output.cub"}; + + int myArgcQ = myArgc; + Isis::UserInterface ui(unitTestXml, myArgcQ, myArgv); + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: " << ui.GetAsString("TO") << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + + cout << "Testing unitTest v. ./unitTest for GUI" << endl; + { + const int myArgc = 1; + char *myArgv[myArgc] = {"unitTest"}; + int myArgcQ = myArgc; + Isis::UserInterface ui(unitTestXml, myArgcQ, myArgv); + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + + { + const int myArgc = 1; + char *myArgv[myArgc] = {"./unitTest"}; + int myArgcQ = myArgc; + Isis::UserInterface ui(unitTestXml, myArgcQ, myArgv); + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + + { + cout << "Starting Batchlist Test" << endl; + const int myArgc = 4; + char *myArgv[myArgc] = {"unitTest", "from=$1", "to=$2", "-batchlist=unitTest.lis"}; + int myArgcQ = myArgc; + Isis::UserInterface ui(unitTestXml, myArgcQ, myArgv); + for(int i = 0; i < ui.BatchListSize(); i++) { + ui.SetBatchList(i); + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: " << ui.GetAsString("TO") << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + cout << "Finished Batchlist Test" << endl; + cout << endl; + } + + cout << "Testing =value" << endl; + try { + const int myArgc = 4; + char *myArgv[myArgc] = {"unitTest", "=input.cub", "to", "=output.cub"}; + + int myArgcQ = myArgc; + Isis::UserInterface ui(unitTestXml, myArgcQ, myArgv); + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: " << ui.GetAsString("TO") << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + catch(Isis::iException &e) { + e.Report(false); + cout << endl; + } + + cout << "Testing param =value" << endl; + try { + const int myArgc = 10; + char *myArgv[myArgc] = {"highpass", "from=dog", "to", "=bread", "line", "=", "3", "samp", "=", "3"}; + + int myArgcQ = myArgc; + Isis::UserInterface ui(highpass, myArgcQ, myArgv); + vector vals; + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: " << ui.GetAsString("TO") << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + catch(Isis::iException &e) { + e.Report(false); + cout << endl; + } + + cout << "Testing unterminated array-value quote" << endl; + try { + const int myArgc = 2; + char *myArgv[myArgc] = {"./unitTest", "from=(\"hello)"}; + int myArgcQ = myArgc; + Isis::UserInterface ui(unitTestXml, myArgcQ, myArgv); + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: " << ui.GetAsString("TO") << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + catch(Isis::iException &e) { + e.Report(false); + cout << endl; + } + + cout << "Testing array-value ending in backslash" << endl; + try { + const int myArgc = 2; + char *myArgv[myArgc] = {"./unitTest", "from=(hello)\\"}; + int myArgcQ = myArgc; + Isis::UserInterface ui(unitTestXml, myArgcQ, myArgv); + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: " << ui.GetAsString("TO") << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + catch(Isis::iException &e) { + e.Report(false); + cout << endl; + } + + try { + const int myArgc = 2; + char *myArgv[myArgc] = {"./unitTest", "-restore=unitTest.par"}; + int myArgcQ = myArgc; + Isis::UserInterface ui(unitTestXml, myArgcQ, myArgv); + cout << "FROM: " << ui.GetAsString("FROM") << endl; + cout << "TO: " << ui.GetAsString("TO") << endl; + cout << "GUI: " << ui.IsInteractive() << endl; + cout << endl; + } + catch(Isis::iException &e) { + e.Report(false); + cout << endl; + } + + try { + const int myArgc = 2; + char *myArgv[myArgc] = {"$ISISROOT/src/base/apps/highpass/highpass", "bogus=parameter"}; + int myArgcQ = myArgc; + Isis::UserInterface ui(highpass, myArgcQ, myArgv); + } + catch(Isis::iException &e) { + e.Report(false); + cout << endl; + } + + try { + const int myArgc = 2; + char *myArgv[myArgc] = {"$ISISROOT/src/base/apps/highpass/highpass", "-restore=junk.par"}; + int myArgcQ = myArgc; + Isis::UserInterface ui(highpass, myArgcQ, myArgv); + } + catch(Isis::iException &e) { + e.Report(false); + } + } + catch(Isis::iException &e) { + e.Report(false); + } +} diff --git a/isis/src/base/objs/UserInterface/unitTest.lis b/isis/src/base/objs/UserInterface/unitTest.lis new file mode 100644 index 0000000000000000000000000000000000000000..f111f75ecdf8cd6cdb9652764d4e99fa888641e7 --- /dev/null +++ b/isis/src/base/objs/UserInterface/unitTest.lis @@ -0,0 +1,6 @@ +peaks.cub out1.txt +peaks.cub, out2.txt +peaks.cub out3.txt +peaks.cub, out4.txt + peaks.cub , " out 5.txt" +peaks.cub , ' out 6.txt' diff --git a/isis/src/base/objs/UserInterface/unitTest.par b/isis/src/base/objs/UserInterface/unitTest.par new file mode 100644 index 0000000000000000000000000000000000000000..159cca1123887ed48f44339e513030fe16cfc4c0 --- /dev/null +++ b/isis/src/base/objs/UserInterface/unitTest.par @@ -0,0 +1,5 @@ +Group = UserParameters + From = It + To = Worked +EndGroup +End diff --git a/isis/src/base/objs/UserInterface/unitTest.xml b/isis/src/base/objs/UserInterface/unitTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..369d37e967de54576ba7725b22a38f47d456f2a2 --- /dev/null +++ b/isis/src/base/objs/UserInterface/unitTest.xml @@ -0,0 +1,54 @@ + + + + Unit test for IsisUserInterface class + + + + Just a test only a test + + + + Scripting + + + + + Original Version + + + Modified schema from astrogeology... isis.astrogeology... + + + + + + + filename + + Test cube + + + Test cube + + + *.cub + + /ISISROOT/testData/base/isisTruth.cub + + + filename + + Test cube + + + Test cube + + + *.cub + + /tmp/junk.dat + + + + diff --git a/isis/src/base/objs/VariableLineScanCameraDetectorMap/Makefile b/isis/src/base/objs/VariableLineScanCameraDetectorMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d20290dc7867f5687bd213d833c2c77364a01e06 --- /dev/null +++ b/isis/src/base/objs/VariableLineScanCameraDetectorMap/Makefile @@ -0,0 +1,5 @@ +INCS = VariableLineScanCameraDetectorMap.h +SRCS = VariableLineScanCameraDetectorMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/VariableLineScanCameraDetectorMap/VariableLineScanCameraDetectorMap.cpp b/isis/src/base/objs/VariableLineScanCameraDetectorMap/VariableLineScanCameraDetectorMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aeef57a312e96043fe6a6d217c13d0417db7cda7 --- /dev/null +++ b/isis/src/base/objs/VariableLineScanCameraDetectorMap/VariableLineScanCameraDetectorMap.cpp @@ -0,0 +1,119 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/08/08 22:02:36 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "VariableLineScanCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" + +namespace Isis { + VariableLineScanCameraDetectorMap::VariableLineScanCameraDetectorMap( + Camera *parent, std::vector< LineRateChange > &lineRates) : + LineScanCameraDetectorMap(parent, lineRates[0].GetStartEt(), lineRates[0].GetLineScanRate()), p_lineRates(lineRates) { + }; + + /** Compute parent position from a detector coordinate + * + * This method will compute a parent sample given a + * detector coordinate. The parent line will be computed using the + * the time in the parent camera + * + * @param sample Sample number in the detector + * @param line Line number in the detector + * + * @return conversion successful + */ + bool VariableLineScanCameraDetectorMap::SetDetector(const double sample, + const double line) { + // Use the parent SetDetector for the sample, which should work fine + if (!CameraDetectorMap::SetDetector(sample,line)) { + return false; + } + + // currEt is our known et time + double currEt = p_camera->EphemerisTime(); + int rateIndex = p_lineRates.size()-1; + + while(rateIndex >= 0 && currEt < p_lineRates[rateIndex].GetStartEt() - 0.5) { + rateIndex --; + } + + if(rateIndex < 0) { + return false; + } + + int rateStartLine = p_lineRates[rateIndex].GetStartLine(); + double rateStartEt = p_lineRates[rateIndex].GetStartEt(); + double rate = p_lineRates[rateIndex].GetLineScanRate(); + + double etDiff = currEt - rateStartEt; + p_parentLine = etDiff / rate + rateStartLine; + + //std::cout << "p_parentLine = " << p_parentLine << " = " << etDiff << "/" << rate << " + " << rateStartLine << std::endl; + + SetLineRate(rate); + + return true; + } + + /** Compute detector position from a parent image coordinate + * + * This method will compute the detector position from the parent + * line/sample coordinate. The parent line will be used to set the + * appropriate time in the parent camera. + * + * @param sample Sample number in the parent image + * @param line Line number in the parent image + * + * @return conversion successful + */ + bool VariableLineScanCameraDetectorMap::SetParent(const double sample, + const double line) { + if (!CameraDetectorMap::SetParent(sample,line)) { + return false; + } + + p_detectorLine = p_camera->FocalPlaneMap()->DetectorLineOffset(); + + int rateIndex = p_lineRates.size()-1; + + while(rateIndex >= 0 && line < p_lineRates[rateIndex].GetStartLine() - 0.5) { + rateIndex --; + } + + if(rateIndex < 0) { + return false; + } + + int rateStartLine = p_lineRates[rateIndex].GetStartLine(); + double rateStartEt = p_lineRates[rateIndex].GetStartEt(); + double rate = p_lineRates[rateIndex].GetLineScanRate(); + + double et = rateStartEt + (line - rateStartLine) * rate; + //printf("et = %.8f = %.8f + (%.3f - %i) * %.8f\n", et, rateStartEt, line, rateStartLine, rate); + + SetLineRate(rate); + + p_camera->SetEphemerisTime(et); + + return true; + } +} diff --git a/isis/src/base/objs/VariableLineScanCameraDetectorMap/VariableLineScanCameraDetectorMap.h b/isis/src/base/objs/VariableLineScanCameraDetectorMap/VariableLineScanCameraDetectorMap.h new file mode 100644 index 0000000000000000000000000000000000000000..562e36ec28bdce6d39d858a467d87668779b2432 --- /dev/null +++ b/isis/src/base/objs/VariableLineScanCameraDetectorMap/VariableLineScanCameraDetectorMap.h @@ -0,0 +1,90 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/03/07 18:02:33 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef VariableLineScanCameraDetectorMap_h +#define VariableLineScanCameraDetectorMap_h + +#include "LineScanCameraDetectorMap.h" + +namespace Isis { + class LineRateChange; + + /** Convert between parent image coordinates and detector coordinates + * + * This class is used to convert between parent dector coordinates + * (sample/line) and detector coordinates for a line scan camera. + * + * @author 2008-08-08 Steven Lambright + * + * @ingroup Camera + * @see Camera + * + * @internal + * @history 2008-08-08 Steven Lambright Original version + * @history 2009-03-07 Debbie A. Cook Removed reference to obsolute CameraDetectorMap methods + * + */ + class VariableLineScanCameraDetectorMap : public LineScanCameraDetectorMap { + public: + /** + * Constructs a VariableLineScanCameraDetectorMap. + * + * @param parent The camera + * @param p_lineRates This should be a vector with an entry for every + * scan rate change in it. The pair consists of the line number and + * ET of the changed time; the first entry should be line 1 and the last + * entry should be one line past the end of the image. See + * HrscCamera for an example. + */ + VariableLineScanCameraDetectorMap(Camera *parent, std::vector< LineRateChange > &lineRates); + + //! Destructor + virtual ~VariableLineScanCameraDetectorMap() {}; + + virtual bool SetParent(const double sample, const double line); + + virtual bool SetDetector(const double sample, const double line); + + private: + std::vector< LineRateChange > &p_lineRates; + }; + + class LineRateChange { + public: + LineRateChange(int line, double stime, double rate) { + p_line = line; + p_stime = stime; + p_rate = rate; + }; + + int GetStartLine() { return p_line; } + double GetStartEt() { return p_stime; } + double GetLineScanRate() { return p_rate; } + + private: + int p_line; + double p_stime; + double p_rate; + }; +}; +#endif diff --git a/isis/src/base/objs/VariableLineScanCameraDetectorMap/VariableLineScanCameraDetectorMap.truth b/isis/src/base/objs/VariableLineScanCameraDetectorMap/VariableLineScanCameraDetectorMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..6347fe6d38f458077e14c2efcd5624b000c19da3 --- /dev/null +++ b/isis/src/base/objs/VariableLineScanCameraDetectorMap/VariableLineScanCameraDetectorMap.truth @@ -0,0 +1 @@ +This class will be tested by the applications and the individual Camera models. diff --git a/isis/src/base/objs/VariableLineScanCameraDetectorMap/unitTest.cpp b/isis/src/base/objs/VariableLineScanCameraDetectorMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1e796681f5572ea434cc9d3b182886357352364 --- /dev/null +++ b/isis/src/base/objs/VariableLineScanCameraDetectorMap/unitTest.cpp @@ -0,0 +1,8 @@ +#include +#include "Preference.h" + +using namespace std; +int main() { + Isis::Preference::Preferences(true); + cout << "This class will be tested by the applications and the individual Camera models." << endl; +} diff --git a/isis/src/base/objs/VecFilter/Makefile b/isis/src/base/objs/VecFilter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5134aaffbe9ffd818168cb9462ce867fba6da1e9 --- /dev/null +++ b/isis/src/base/objs/VecFilter/Makefile @@ -0,0 +1,5 @@ +INCS = VecFilter.h +SRCS = VecFilter.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/VecFilter/VecFilter.cpp b/isis/src/base/objs/VecFilter/VecFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c8f00f4a26db3fb9b4ed1812f20e0d249d588d37 --- /dev/null +++ b/isis/src/base/objs/VecFilter/VecFilter.cpp @@ -0,0 +1,114 @@ +/** + * @file + * $Date: 2009/03/17 16:58:22 $ + * $Revision: 1.1 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "VecFilter.h" +#include "iException.h" +#include "iString.h" + +using namespace std; +namespace Isis { + //! Constructs a VecFilter object. + VecFilter::VecFilter () {} + + //! Destroys the VecFilter object. + VecFilter::~VecFilter () {}; + + /** + * Perform a lowpass filter on an input vector. + * + * @param invec The input vector on which the lowpass filter will be + * performed. + * + * @param boxsize The size of the one dimensional boxcar to use in + * doing the lowpass filter. The filter size must be odd and + * greater than 1. + * + */ + vector VecFilter::LowPass(vector invec, int boxsize) { + vector outvec; + + // Clear the output vector + //outvec.resize(0); + + // Boxcar size must be odd and greater than 1 + if ((boxsize % 2) == 0) { + string m="Boxcar size must be odd and greater than 1 in [VecFilter::LowPass]"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + // Perform lowpass filter + int halfwidth = boxsize / 2; + int vecsize = (int)invec.size() - 1; + for (int i=0; i<=vecsize; i++) { + int i1 = i - halfwidth; + if (i1 < 0) i1 = 0; + int i2 = i + halfwidth; + if (i2 > vecsize) i2 = vecsize; + int npts = 0; + double sum = 0.0; + for (int j=i1; j<=i2; j++) { + if (invec[j] != 0.0) { + sum = sum + invec[j]; + npts++; + } + } + if (npts > 0) { + outvec.push_back(sum/npts); + } else { + outvec.push_back(0.0); + } + } + return outvec; + } + + /** + * Perform a highpass filter by subtracting one vector (the lowpass + * filtered vector) from the original vector. + * + * @param invec1 The vector that contains the original data before + * the lowpass was applied. + * + * @param invec2 The vector which has gone through a lowpass filter. + * + */ + vector VecFilter::HighPass (vector invec1, vector invec2) { + vector outvec; + + // Both vectors must be the same size + if (invec1.size() != invec2.size()) { + string m="Both vectors must be the same size in [VecFilter::HighPass]"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + int vecsize = (int)invec1.size() - 1; + for (int i=0; i<=vecsize; i++) { + if (invec1[i] != 0.0 && invec2[i] != 0.0) { + outvec.push_back(invec1[i]-invec2[i]); + } else { + outvec.push_back(0.0); + } + } + return outvec; + } + +} // end namespace isis diff --git a/isis/src/base/objs/VecFilter/VecFilter.h b/isis/src/base/objs/VecFilter/VecFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..868516d6fd89dce86a940e3daae4f804d09959d4 --- /dev/null +++ b/isis/src/base/objs/VecFilter/VecFilter.h @@ -0,0 +1,54 @@ +#ifndef VecFilter_h +#define VecFilter_h +/** + * @file + * $Date: 2009/03/17 16:58:23 $ + * $Revision: 1.1 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +namespace Isis { + /** + * @brief This class is used to perform filter operations on vectors. + * + * This class performs boxcar filter operations on vectors. The boxcar + * will be a one dimensional Nx1 boxcar where N is a positive odd + * integer. + * + * For an example of how the VecFilter object is used in %Isis, see the + * hicubenorm.cpp application. + * + * @ingroup Statistics + * + * @author Janet Barrett - 2009-03-13 + * + */ + class VecFilter { + public: + VecFilter (); + ~VecFilter (); + + std::vector LowPass(std::vector invec, int boxsize); + std::vector HighPass(std::vector invec1, std::vector invec2); + + private: + }; +} // end namespace isis + +#endif + diff --git a/isis/src/base/objs/VecFilter/VecFilter.truth b/isis/src/base/objs/VecFilter/VecFilter.truth new file mode 100644 index 0000000000000000000000000000000000000000..04ecdfa06c70a4d630a22dfd8a449adb0805b77e --- /dev/null +++ b/isis/src/base/objs/VecFilter/VecFilter.truth @@ -0,0 +1,164 @@ +Size of original vector: 25 +Size of lowpass vector: 25 +Size of highpass vector: 25 +Filter size: 3 +Original vector values: +2602.6 +2533.23 +2547.07 +2532.98 +2543.84 +2548.51 +2557.58 +2541.52 +2553.88 +2554.78 +2563.41 +2546.53 +2554.91 +2556.8 +2563.03 +2546.29 +2554.3 +2553.09 +2564.72 +2545.95 +2556.63 +2556.48 +2565.31 +2546.2 +2556.72 +Lowpass filtered vector values: +2567.92 +2560.97 +2537.76 +2541.3 +2541.78 +2549.98 +2549.2 +2551 +2550.06 +2557.36 +2554.91 +2554.95 +2552.75 +2558.25 +2555.37 +2554.54 +2551.23 +2557.37 +2554.59 +2555.77 +2553.02 +2559.48 +2556 +2556.08 +2551.46 +Highpass filtered vector values: +34.6849 +-27.736 +9.30937 +-8.31667 +2.0653 +-1.47017 +8.37813 +-9.473 +3.8219 +-2.58003 +8.50453 +-8.41803 +2.1583 +-1.44043 +7.65327 +-8.2523 +3.0762 +-4.27933 +10.1334 +-9.81953 +3.61303 +-2.9952 +9.31403 +-9.8761 +5.2592 +Size of original vector: 25 +Size of lowpass vector: 25 +Size of highpass vector: 25 +Filter size: 5 +Original vector values: +2602.6 +2533.23 +2547.07 +2532.98 +2543.84 +2548.51 +2557.58 +2541.52 +2553.88 +2554.78 +2563.41 +2546.53 +2554.91 +2556.8 +2563.03 +2546.29 +2554.3 +2553.09 +2564.72 +2545.95 +2556.63 +2556.48 +2565.31 +2546.2 +2556.72 +Lowpass filtered vector values: +2560.97 +2553.97 +2551.95 +2541.13 +2546 +2544.89 +2549.07 +2551.25 +2554.24 +2552.02 +2554.7 +2555.29 +2556.94 +2553.51 +2555.07 +2554.7 +2556.29 +2552.87 +2554.94 +2555.38 +2557.82 +2554.12 +2556.27 +2556.18 +2556.08 +Highpass filtered vector values: +41.6337 +-20.7392 +-4.87476 +-8.1452 +-2.15456 +3.61976 +8.51474 +-9.73138 +-0.3524 +2.7518 +8.70932 +-8.75476 +-2.03014 +3.29416 +7.96024 +-8.41646 +-1.98182 +0.22296 +9.7808 +-9.4273 +-1.18538 +2.36488 +9.04248 +-9.9765 +0.6423 diff --git a/isis/src/base/objs/VecFilter/unitTest.cpp b/isis/src/base/objs/VecFilter/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..16bd5dac4fad4750c65990afdb4e18cd8727b93d --- /dev/null +++ b/isis/src/base/objs/VecFilter/unitTest.cpp @@ -0,0 +1,81 @@ +#include +#include "VecFilter.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + + Isis::VecFilter v; + vector filtorig; + vector filtlow; + vector filthigh; + int boxsize; + double indata[25] = {2602.6042,2533.2345,2547.0729,2532.9832,2543.8435, + 2548.5079,2557.5828,2541.5233,2553.8828,2554.7766,2563.4105,2546.5308, + 2554.9052,2556.8047,2563.0255,2546.2865,2554.3044,2553.0937,2564.721, + 2545.9481,2556.6338,2556.4804,2565.3126,2546.2027,2556.7211}; + + for (int i=0; i<25; i++) { + filtorig.push_back(indata[i]); + } + + boxsize = 3; + filtlow = v.LowPass(filtorig,boxsize); + filthigh = v.HighPass(filtorig,filtlow); + + cout << "Size of original vector: " << filtorig.size() << endl; + cout << "Size of lowpass vector: " << filtlow.size() << endl; + cout << "Size of highpass vector: " << filthigh.size() << endl; + cout << "Filter size: " << boxsize << endl; + + cout << "Original vector values: " << endl; + + for (int i=0; i<25; i++) { + cout << filtorig[i] << endl; + } + + cout << "Lowpass filtered vector values: " << endl; + + for (int i=0; i<25; i++) { + cout << filtlow[i] << endl; + } + + cout << "Highpass filtered vector values: " << endl; + + for (int i=0; i<25; i++) { + cout << filthigh[i] << endl; + } + + filtlow.clear(); + filthigh.clear(); + + boxsize = 5; + filtlow = v.LowPass(filtorig,boxsize); + filthigh = v.HighPass(filtorig,filtlow); + + cout << "Size of original vector: " << filtorig.size() << endl; + cout << "Size of lowpass vector: " << filtlow.size() << endl; + cout << "Size of highpass vector: " << filthigh.size() << endl; + cout << "Filter size: " << boxsize << endl; + + cout << "Original vector values: " << endl; + + for (int i=0; i<25; i++) { + cout << filtorig[i] << endl; + } + + cout << "Lowpass filtered vector values: " << endl; + + for (int i=0; i<25; i++) { + cout << filtlow[i] << endl; + } + + cout << "Highpass filtered vector values: " << endl; + + for (int i=0; i<25; i++) { + cout << filthigh[i] << endl; + } +} diff --git a/isis/src/base/objs/WorldMapper/Makefile b/isis/src/base/objs/WorldMapper/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cc6e8f52937935668e0454e99f85db0b2711b665 --- /dev/null +++ b/isis/src/base/objs/WorldMapper/Makefile @@ -0,0 +1,5 @@ +INCS = WorldMapper.h +SRCS = +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/WorldMapper/WorldMapper.h b/isis/src/base/objs/WorldMapper/WorldMapper.h new file mode 100644 index 0000000000000000000000000000000000000000..1e3e7c3e8ca818815e958658d61b981b011781d0 --- /dev/null +++ b/isis/src/base/objs/WorldMapper/WorldMapper.h @@ -0,0 +1,120 @@ +#ifndef WorldMapper_h +#define WorldMapper_h +/** + * @file + * $Revision: 1.1.1.1 $ + * $Date: 2006/10/31 23:18:10 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Isis { +/** + * @brief Create a mapping between a projection and other coordinate system + * + * This class can be used to create a mapping between a projection coordinate + * system and a different coordinate system. Simple examples of this would be a + * mapping between projection x/y's to cube line/samples or a mapping between + * projection x/y's and paper x/y's in inches. The class is pure virtual and + * therefore should never be directly instantiated. Remember the basic premise + * is to use this class to create a new class which converts coordinates from + * one system to another (inches to meters and back, meters to pixels and back, + * etc). + * + * If you would like to see WorldMapper being used in implementation, + * see the ProjectionFactory class + * + * @ingroup MapProjection + * + * @author 2003-01-28 Jeff Anderson + * + * @internal + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-09-25 Jeff Anderson - Added Resolution method + * @history 2005-02-22 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * + * @todo 2005-02-22 Jeff Anderson - add coded example to class documentation + */ + class WorldMapper { + public: + //! Constructs an empty WorldMapper object + WorldMapper () {}; + + //! Destroys the WorldMapper object + virtual ~WorldMapper () {}; + + /** + * This pure virtual method will return a projection X coordinate in meters + * given a world X coordinate. For example, the worldX value could be an X + * in millimeters on a piece of paper. The value returned would be an X in + * map projection coordinates. + * + * @param worldX An X value in world coordinates. + * + * @return double + */ + virtual double ProjectionX (const double worldX) const = 0; + + /** + * This pure virtual method will return a projection Y coordinate in meters + * given a world Y coordinate. For example, the worldY value could be an + * Y in millimeters on a piece of paper. The value returned would be an + * Y in map projection coordinates. + * + * @param worldY A Y value in world coordinates. + * + * @return double + */ + virtual double ProjectionY (const double worldY) const = 0; + + /** + * This pure virtual method will return a world X coordinate given a + * projection Y coordinate in meters. For example, the worldY value could + * be an Y in millimeters on a piece of paper. + * + * @param projectionX A X value in projection coordinates. + * + * @return double + */ + virtual double WorldX (const double projectionX) const = 0; + + /** + * This pure virtual method will return a world Y coordinate given a + * projection Y coordinate in meters. For example, the worldY value could + * be an Y in millimeters on a piece of paper. + * + * @param projectionY A Y value in projection coordinates. + * + * @return double + */ + virtual double WorldY (const double projectionY) const = 0; + + /** + * This virtual method will the resolution of the world system relative to + * one unit in the projection system. For example, one meter in the + * projection system could be .001 inches on a piece of paper. Unless this + * method is overridden it will return 1 + * + * @return double + */ + virtual double Resolution () const { return 1.0; }; + }; +}; + +#endif diff --git a/isis/src/base/objs/WorldMapper/WorldMapper.truth b/isis/src/base/objs/WorldMapper/WorldMapper.truth new file mode 100644 index 0000000000000000000000000000000000000000..e7724415f86ee9f2206af27ec0314796c38a8bd3 --- /dev/null +++ b/isis/src/base/objs/WorldMapper/WorldMapper.truth @@ -0,0 +1,6 @@ +Unit test for Isis::WorldMapper +WorldX to ProjectionX: 50 +ProjectionX to WorldX: 100 +WorldY to ProjectionY: 30 +ProjectionY to WorldY: 90 +Resolution: 1 diff --git a/isis/src/base/objs/WorldMapper/unitTest.cpp b/isis/src/base/objs/WorldMapper/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d19900ff17ff6f5744d873eea1d9d8e095fdf0c --- /dev/null +++ b/isis/src/base/objs/WorldMapper/unitTest.cpp @@ -0,0 +1,26 @@ +#include +#include "WorldMapper.h" +#include "Preference.h" + +using namespace std; +class IsisDoubleMapper : public Isis::WorldMapper { + public: + double ProjectionX(const double worldX) const { return worldX / 2.0; }; + double ProjectionY(const double worldY) const { return worldY / 3.0; }; + double WorldX(const double projectionX) const { return projectionX * 2.0; }; + double WorldY(const double projectionY) const { return projectionY * 3.0; }; +}; + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Unit test for Isis::WorldMapper" << endl; + + Isis::WorldMapper *map = new IsisDoubleMapper(); + + cout << "WorldX to ProjectionX: " << map->ProjectionX(100.0) << endl; + cout << "ProjectionX to WorldX: " << map->WorldX(50.0) << endl; + cout << "WorldY to ProjectionY: " << map->ProjectionY(90.0) << endl; + cout << "ProjectionY to WorldY: " << map->WorldY(30.0) << endl; + cout << "Resolution: " << map->Resolution() << endl; +} diff --git a/isis/src/base/objs/iException/Makefile b/isis/src/base/objs/iException/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..29d62e8d77396c26da482fdb0b846a197da9740e --- /dev/null +++ b/isis/src/base/objs/iException/Makefile @@ -0,0 +1,5 @@ +INCS = iException.h +SRCS = iException.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/iException/iException.cpp b/isis/src/base/objs/iException/iException.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e31520c0b47dcfe2882b13edc36db46469cae05 --- /dev/null +++ b/isis/src/base/objs/iException/iException.cpp @@ -0,0 +1,324 @@ +/** + * @file + * $Revision: 1.13 $ + * $Date: 2009/07/29 21:16:39 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "IsisDebug.h" + +#include + +#include "iException.h" +#include "iString.h" +#include "Pvl.h" +#include "Preference.h" +#include "Application.h" +#include "TextFile.h" + +using namespace std; +namespace Isis { + /** + * Constructs a blank iException. Checks if file and line number should be + * output, and whether the exception should be reported in PVL format. + */ + iException::iException () { + // See if we should output the file and line number + Isis::PvlGroup &ef = Isis::Preference::Preferences().FindGroup("ErrorFacility"); + Isis::iString fileline = (std::string) ef["FileLine"]; + p_reportFileLine = (fileline.UpCase() == "ON"); + + // Should we report in pvl format?? + p_pvlFormat = false; + Isis::iString pvlForm = (std::string) ef["Format"]; + p_pvlFormat = (pvlForm.UpCase() == "PVL"); + atexit(Shutdown); + } + + //! Exception object pointer (Default is NULL) + iException *iException::p_exception = NULL; + //! The list of exception information (From Info class) + QList iException::p_list; + + /** + * Adds a message to an existing iException object (or creates a new one if + * it doesn't exist) + * @param t An errType value of what type of exception is thrown. + * @param m The message to add + * @param f The filename + * @param l The line number + * @return The modified exception object. + */ + iException &iException::Message(iException::errType t, const std::string &m, + const char *f, int l) { + if (p_exception == NULL) { + p_exception = new iException(); + } + + PvlGroup &errPref = Preference::Preferences().FindGroup("ErrorFacility"); + bool printTrace = false; + + if (errPref.HasKeyword("StackTrace")) { + printTrace = (((iString)errPref["StackTrace"][0]).UpCase() == "ON"); + } + + if (printTrace && p_list.empty()) { + createStackTrace(); + } + + Info i; + i.type = t; + i.message = m; + i.filename = f; + i.lineNumber = l; + + p_list.push_back(i); + + p_exception->describe(); + + return *p_exception; + } + + //! Throws and destroys the iException object. + iException::~iException() throw () { + } + + /** + * Stores what happened in a member std::string. + */ + void iException::describe() { + if (p_list.size() > 0) { + std::string message; + for (int i=p_list.size()-1; i>=0; i--) { + message += "**" + enumString(p_list[i].type) + "** " + + p_list[i].message; + if (p_reportFileLine) { + message += " in " + p_list[i].filename + + " at " + Isis::iString(p_list[i].lineNumber); + } + if (i != 0) message += "\n"; + } + + p_what = message; + } + else { + p_what = ""; + } + } + + /** + * Returns what happened in output format. This pointer is valid as + * long as no new iException objects are created (iException::Message is not + * called again). + * + * @return The message stating what happened and where. + */ + const char *iException::what() const throw () { + if(p_what != "") { + return p_what.c_str(); + } + else { + return NULL; + } + } + + /** + * Returns the type of exception. + * @return The type of exception (None if no type). + */ + iException::errType iException::Type() const { + if (p_list.size() > 0) { + int i = p_list.size() - 1; + return p_list[i].type; + } + else { + return iException::None; + } + } + + /** + * Returns true or false based on whether the exception should output in PVL + * format. + * @return True if PVL format is enabled, false if not. + */ + bool iException::IsPvlFormat() { + return p_pvlFormat; + } + + void iException::Shutdown() { + if(p_exception) { + ASSERT_PTR(p_exception); + delete p_exception; + p_exception = NULL; + } + } + + /** + * Reports the exception to output. + * @param fileinfo Allows the caller to overide the users preference setting + * for file name and line number where the error was thrown + * @return The type of exception. + */ + int iException::Report (bool fileinfo) { + // Loop and present each message + bool saveFileLine = p_reportFileLine; + p_reportFileLine = fileinfo & p_reportFileLine; + + if (IsPvlFormat()) { + Isis::Pvl errors = PvlErrors(); + std::cerr << errors << std::endl; + } + else { + std::cerr << Errors() << std::endl; + } + + p_reportFileLine = saveFileLine; + int type = (int) Type(); // Must get type before clear!! + Clear(); + return type; + } + + /** + * Adds a new PvlGroup called "Error" and appends it to the file (if PVL + * format output is enabled) + */ + Pvl iException::PvlErrors() { + Isis::Pvl errors; + + for (int i=p_list.size()-1; i>=0; i--) { + PvlGroup errGroup("Error"); + + errGroup += Isis::PvlKeyword ("Program",Isis::Application::Name()); + errGroup += Isis::PvlKeyword ("Class",enumString(p_list[i].type)); + errGroup += Isis::PvlKeyword ("Code",(int)p_list[i].type); + errGroup += Isis::PvlKeyword ("Message",p_list[i].message); + errGroup += Isis::PvlKeyword ("File",p_list[i].filename); + errGroup += Isis::PvlKeyword ("Line",p_list[i].lineNumber); + + errors.AddGroup(errGroup); + } + + return errors; + } + + /** + * Returns the Exception message to be output (non-PVL) + */ + std::string iException::Errors() { + std::string message; + for (int i=p_list.size()-1; i>=0; i--) { + // Construct the line-based message + message += "**" + enumString(p_list[i].type) + "** " + + p_list[i].message; + if (p_reportFileLine) { + message += " in " + p_list[i].filename + + " at " + Isis::iString(p_list[i].lineNumber); + } + if (i != 0) message += "\n"; + } + return message; + } + + //! Clears the list of exceptions + void iException::Clear () { + p_list.clear(); + } + + /** + * Returns the type of exception in string format. + * @return "USER ERROR" if user error type, etc. + */ + std::string iException::enumString(iException::errType t) const { + switch (t) { + case User: + return "USER ERROR"; + + case Programmer: + return "PROGRAMMER ERROR"; + + case Pvl: + return "PVL ERROR"; + + case Io: + return "I/O ERROR"; + + case Camera: + return "CAMERA ERROR"; + + case Projection: + return "PROJECTION ERROR"; + + case Parse: + return "PARSE ERROR"; + + case Math: + return "MATH ERROR"; + + case Spice: + return "SPICE ERROR"; + + case Cancel: + return "CANCEL"; + + case System: + return "SYSTEM ERROR"; + + default: + return "UNKNOWN ERROR"; + } + } + + /** + * Given a string, returns the error type associated with it. + * @return If the string reads "USER ERROR", will return type User. + */ + iException::errType iException::enumString(const std::string &s) const { + if (s == "USER ERROR") return User; + if (s == "PROGRAMMER ERROR") return Programmer; + if (s == "PVL ERROR") return Pvl; + if (s == "I/O ERROR") return Io; + if (s == "CAMERA ERROR") return Camera; + if (s == "PROJECTION ERROR") return Projection; + if (s == "PARSE ERROR") return Parse; + if (s == "MATH ERROR") return Math; + if (s == "CANCEL") return Cancel; + if (s == "SYSTEM ERROR") return System; + return None; + } + + void iException::createStackTrace() { + Info stackTraceInfo; + stackTraceInfo.type = iException::Programmer; + stackTraceInfo.filename = "N/A"; + stackTraceInfo.lineNumber = 0; + + std::vector theStack; + StackTrace::GetStackTrace(&theStack); + stackTraceInfo.message = "\n"; + + for(unsigned int i = 1; i < theStack.size(); i++) { + stackTraceInfo.message += theStack[i] + "\n"; + } + + if(theStack.size() != 0) { + p_list.push_back(stackTraceInfo); + } + } +} + diff --git a/isis/src/base/objs/iException/iException.h b/isis/src/base/objs/iException/iException.h new file mode 100644 index 0000000000000000000000000000000000000000..c565f7494f56337440510a9fa8231b14152c9bb5 --- /dev/null +++ b/isis/src/base/objs/iException/iException.h @@ -0,0 +1,148 @@ +#ifndef iException_h +#define iException_h + +/** + * @file + * $Revision: 1.11 $ + * $Date: 2009/07/29 21:16:39 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include + +#define _FILEINFO_ __FILE__,__LINE__ + +namespace Isis { + class Pvl; + /** + * @brief Isis exception class + * + * The general Isis exception class. Contains an enumeration for what type of + * exception to throw. + * + * @author Jeff Anderson + * + * @internal + * @history 2005-05-10 Leah Dahmer - Added class documentation + * @history 2005-12-28 Elizabeth Miller - Fixed bug in Pvl error output + * @history 2006-06-12 Tracie Sucharski - Change clear method to static + * @history 2006-11-02 Jeff Anderson - Fixed bug in Report method for + * exit status + * @history 2007-12-31 Steven Lambright - Added stack trace + * @history 2008-05-23 Steven Lambright - Added stack trace + * @history 2008-06-18 Stuart Sides - Fixed doc error + * @history 2008-07-08 Steven Lambright - Changed memory cleanup; now uses + * atexit + * @history 2008-10-30 Steven Lambright - iException::Message now takes a + * const char* for the filename, instead of a chat*, issue pointed + * out by "novus0x2a" (Support Board Member) + * @history 2008-12-15 Steven Lambright - iException::what no longer returns + * deleted memory. + * @history 2009-07-29 Steven Lambright - Stack trace calculations moved to + * IsisDebug.h + */ + class iException : public std::exception { + public: + //! Contains a set of throwable exception types. + enum errType { + None = 0, + User = 1, + Programmer = 2, + Pvl = 3, + Io = 5, + Camera = 6, + Projection = 7, + Parse = 8, + Math = 9, + Spice = 10, + Cancel = 200, + System = 255 + }; + + static iException &Message(errType t, const std::string &m, const char *f, int l); + + const char *what() const throw(); + errType Type() const; + int Report (bool fileinfo = true); + Isis::Pvl PvlErrors (); + std::string Errors(); + bool IsPvlFormat(); + static void Clear (); + ~iException() throw (); + + private: + static iException *p_exception; + iException (); + + static void Shutdown(); + + /** + * @brief Exception information + * + * Contains information about an iException object. A helper class to + * iException. + * + * @author Unknown author, unknown date + * + * @internal + * @history 2005-05-10 Leah Dahmer - wrote class documentation + * @history 2008-07-08 Steven Lambright - Fixed destruction code + * @todo Find out author and date of class! + */ + class Info { + public: + errType type; + std::string message; + std::string filename; + int lineNumber; + }; + + //! List of iExceptions + static QList p_list; + + static void createStackTrace(); + std::string enumString(errType t) const; + errType enumString(const std::string &s) const; + + void describe(); + + /** + * True or false, depending on whether the filename and line number + * should be reported in the output. + */ + bool p_reportFileLine; + + /** + * True or false, depending on whether the exception should be output in + * PVL format. + */ + bool p_pvlFormat; + + /** + * This is the return value of what(). Calculate and keep track of it + * in order to prevent the caller from using deleted memory. + */ + std::string p_what; + }; +}; + +#endif diff --git a/isis/src/base/objs/iException/iException.truth b/isis/src/base/objs/iException/iException.truth new file mode 100644 index 0000000000000000000000000000000000000000..a32932ba1c41f60ab796008be2cfb371132b212d --- /dev/null +++ b/isis/src/base/objs/iException/iException.truth @@ -0,0 +1,15 @@ +TEST CASES FOR ERROR OBJECTS +---------------------------- +**MATH ERROR** Testing math errors +**SYSTEM ERROR** Testing system errors +**SPICE ERROR** Testing spice errors +**PARSE ERROR** Testing parse errors +**PROJECTION ERROR** Testing projection errors +**CAMERA ERROR** Testing camera errors +**I/O ERROR** Testing I/O errors +**PVL ERROR** Testing PVL errors +**PROGRAMMER ERROR** Testing programmer errors +**USER ERROR** Testing user errors +**UNKNOWN ERROR** Testing unknown (none) errors +Testing cancel option ... +**CANCEL** diff --git a/isis/src/base/objs/iException/unitTest.cpp b/isis/src/base/objs/iException/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3112e252a2a3cff981ab9bde8a1e48da13c7a166 --- /dev/null +++ b/isis/src/base/objs/iException/unitTest.cpp @@ -0,0 +1,50 @@ +#include +#include "Preference.h" + +#include "iException.h" + +using namespace std; +using namespace Isis; + +int main (void) { + Isis::Preference::Preferences(true); + +// Load up the error stack + + iException::Message(iException::None, + "Testing unknown (none) errors",_FILEINFO_); + iException::Message(iException::User, + "Testing user errors",_FILEINFO_); + iException::Message(iException::Programmer, + "Testing programmer errors",_FILEINFO_); + iException::Message(iException::Pvl, + "Testing PVL errors",_FILEINFO_); + iException::Message(iException::Io, + "Testing I/O errors",_FILEINFO_); + iException::Message(iException::Camera, + "Testing camera errors",_FILEINFO_); + iException::Message(iException::Projection, + "Testing projection errors",_FILEINFO_); + iException::Message(iException::Parse, + "Testing parse errors",_FILEINFO_); + iException::Message(iException::Spice, + "Testing spice errors",_FILEINFO_); + iException::Message(iException::System, + "Testing system errors",_FILEINFO_); + iException &e = iException::Message(iException::Math, + "Testing math errors",_FILEINFO_); + +// Only have to report one because we have generated a large stack +// of errors + + cout << "TEST CASES FOR ERROR OBJECTS" << endl; + cout << "----------------------------" << endl; + + e.Report (false); + + e = iException::Message(iException::Cancel,"",_FILEINFO_); + cout << "Testing cancel option ..." << endl; + e.Report (false); + + return 0; +} diff --git a/isis/src/base/objs/iString/Makefile b/isis/src/base/objs/iString/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b9c367474d75be7f2f7996855d0c50e2eff1b4b9 --- /dev/null +++ b/isis/src/base/objs/iString/Makefile @@ -0,0 +1,5 @@ +INCS = iString.h +SRCS = iString.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/iString/iString.cpp b/isis/src/base/objs/iString/iString.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83bb05bc8434b8c23a6cd7a687fec3446ea3a78f --- /dev/null +++ b/isis/src/base/objs/iString/iString.cpp @@ -0,0 +1,1004 @@ +/** + * @file + * $Revision: 1.15 $ + * $Date: 2010/03/19 20:38:01 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "iString.h" +#include "iException.h" +#include "SpecialPixel.h" + +using namespace std; +namespace Isis { + + /** + * Constructs an empty iString object + */ + iString::iString () : string() { + } + + /** + * Constructs a iString object with initial value set to the string + * argument. + * + * @param str The initial value of the iString + */ + iString::iString (const std::string &str) : string (str) { + } + + /** + * Constructs a iString with initial value set to the iString argument. + * + * @param str The initial value of the iString + */ + iString::iString (const iString &str) : string (str) { + } + + /** + * Constructs a iString with initial value set to the argument + * + * @param str The inital value of the iString + */ + iString::iString (const char *str) : string (str) { + } + + /** + * Constructs a iString object with its initial value set to the string + * representation of the int argument. + * + * @param num The initial value of the iString. The integer value is + * converted to a string representation and stored as the value. + */ + iString::iString (const int &num) : string () { + ostringstream str; + str << num; + assign (str.str()); + } + + /** + * Constructs a iString object with its initial value set to the string + * representation of the BigInt argument. + * + * @param num The initial value of the iString. The integer value is + * converted to a string representation and stored as the value. + */ + iString::iString (const BigInt &num) : string () { + ostringstream str; + str << num; + assign (str.str()); + } + + /** + * Constructs a iString object with its initial value set to the string + * representation of the double argument. + * + * @param num The initial value of the iString. The double value is converted to + * a string representation and stored as the value. The conversion + * is handled in the following manner: If (abs(num) < 0.1) it is + * presented in scientific notation If (abs(log10(num)) < 16) it is + * presented in normal notation if (abs(log10(num)) >= 16) it is + * presented in scientific notation Trailing zeros are removed such + * that 5.000 is presented as 5.0 + */ + iString::iString (const double &num, const int piPrecision) : string() { + SetDouble(num, piPrecision); + } + + + /** + * Performs the conversion necessary to represent a floating-point value as a + * string. See iString (const double &num) for details + * + * @param num The input value to be stored + */ + void iString::SetDouble(const double &num, const int piPrecision) { + // This is the original code and was replaced by the good stuff below + // ostringstream str; + // str << num; + // assign (str.str()); + + // If num is zero, then it is not valid to do a log10 on it. To avoid this, + // check for zero ahead of time and handle it. + if (num == 0.0) { + assign("0.0"); + return; + } + + if(num > DBL_MAX) { + SetDouble(DBL_MAX, piPrecision); + return; + } + + if(num < -DBL_MAX) { + SetDouble(-DBL_MAX, piPrecision); + return; + } + + if(isnan(num)) { + assign("nan"); + return; + } + + // First determine the number of digits preceding the decimal point + // Numbers of the form 0.ABCDEFG where A is non-zero are assumed to + // have a leading digit of zero. Numbers of the form 0.0ABCDEFG, + // 0.00ABCEFEG and so on are not considered to have a leading digit + // (pre = 0). + + //cout << "istring\n"; + //printf("%.15f\n",num); + + double temp = abs(num); + int pre = (int) (log10 (temp)) + 1; + + //printf("%.15f\n",temp); + //cout << "tempI " << iString(temp) << endl; + + // If preceding number of digits is too large then we will need to create a + // scientific notation string. We will need 14 spaces for numbers, 2 spaces + // for exponents, 2 spaces for signs, and 1 for the letter E, 1 for a decimal + // place, and 1 extra in case of a leading 0. A grand total + // of 21 spaces is required. Therefore our format can be %22e + + // If the preceding number of digits is zero then we likely have a + // really small number (e.g., 0.000331236236). So let's put those in + // scientific notation as well + + // Finally, remove any zeroes before the E and if the exponent is zero + // then strip it off as well. + + char dblstr[22]; + + if ((log10 (temp) > 13.0) || (log10 (temp) < -3.0)) { + char fmt[8], buff[8]; + sprintf (buff, "%de", piPrecision); + strcpy (fmt,"%21."); + strcat (fmt, buff); + sprintf (dblstr, fmt, num); + + char *e = strchr (dblstr,'e'); + char *sptr = e - 1; + + while (*sptr == '0') sptr--; + if (*sptr == '.') sptr++; + sptr++; + strcpy (sptr,e); + + e = strchr (dblstr,'e'); + int allzero = 1; + for (sptr=e + 2; *sptr; sptr++) if (*sptr != '0') allzero = 0; + + if (allzero) *e = 0; + } + + // Ok it can be presented as a normal floating point number. So we will need + // 14 spaces for numbers, 1 for the sign, 1 for the decimal, and 1 more + // for a possible leading 0. A grand total of 17 spaces. Therefore our + // format can be "%17.postf". Finally remove any trailing zeroes. + + else { + if (temp < 1.0) pre--; + int post = piPrecision - pre; + + char tempstr[3], fmt[8]; + strcpy (fmt,"%17."); + sprintf (tempstr,"%d",post); + strcat (fmt,tempstr); + strcat (fmt,"f"); + + sprintf (dblstr,fmt,num); + + if (post > 0) { + char *sptr = dblstr + strlen (dblstr) - 1; + while ((*sptr == '0') && (*(sptr-1) != '.')) *sptr-- = 0; + } + } + + while (dblstr[0] == ' ') { + for (unsigned int i=0; i> v_out; // read/get "type T" out of the stream + ios::iostate state = s.rdstate(); + if ((state & ios::failbit) || (state & ios::badbit) || + (!(state & ios::eofbit))) { // Make sure the stream is empty + throw (int)-1; + } + } catch (...) { + string message = "Cannot convert (" + str + ") to an integer"; + throw Isis::iException::Message(Isis::iException::Parse,message, _FILEINFO_); + } + return(v_out); + } + + /** + * Returns the BigInt representation of the object iString + * + * @return BigInt The Big Integer representation of the iString + */ + BigInt iString::ToBigInteger() const { + return ToBigInteger(*this); + } + + /** + * Returns the Big Integer representation of the input string + * + * @param str The string representing an integer value + * + * @return BigInt The string as a BigInt + */ + BigInt iString::ToBigInteger(const std::string &str) { + BigInt v_out; + try { + stringstream s; + s << str; // Put the string into a stream + s.seekg(0, ios::beg); // Move the input pointer to the beginning + s >> v_out; // read/get "type T" out of the stream + ios::iostate state = s.rdstate(); + if ((state & ios::failbit) || (state & ios::badbit) || + (!(state & ios::eofbit))) { // Make sure the stream is empty + throw (int)-1; + } + } catch (...) { + string message = "Cannot convert (" + str + ") to a big integer"; + throw Isis::iException::Message(Isis::iException::Parse,message, _FILEINFO_); + } + return(v_out); + } + + /** + * Returns the floating point value the iString represents + * + * @return double The iString as a double + */ + double iString::ToDouble() const { + return ToDouble(*this); + } + + /** + * Returns the floating-point value represented by the input string + * + * @param str The string representing the numeric value + * + * @return double The number the string represents + */ + double iString::ToDouble(const std::string &str) { + + double v_out; + + // Convert a hex value + if (str.substr(0,3) == "16#" && str.substr(str.length()-1,1) == "#") { + try { + stringstream s; + s << str.substr(3, str.find_last_of("#")-3); + s.seekg(0, ios::beg); + + union { + unsigned int i; + float f; + } u; + + s >> hex >> u.i; + + ios::iostate state = s.rdstate(); + if ((state & ios::failbit) || (state & ios::badbit)) { + throw (int)-1; + } + v_out = u.f; + } catch (...) { + string message = "Cannot convert HEX value [" + str + "] to a double"; + throw Isis::iException::Message(Isis::iException::Parse,message, _FILEINFO_); + } + } + // Convert a decimal value + else { + try { + stringstream s; + s << str; // Put the string into a stream + s.seekg(0, ios::beg); // Move the input pointer to the beginning + s >> v_out; // read/get "type T" out of the stream + ios::iostate state = s.rdstate(); + if ((state & ios::failbit) || (state & ios::badbit) || + (!(state & ios::eofbit))) { // Make sure the stream is empty + throw (int)-1; + } + } catch (...) { + string message = "Cannot convert [" + str + "] to a double"; + throw Isis::iException::Message(Isis::iException::Parse,message, _FILEINFO_); + } + } + + return(v_out); + } + + /** + * Retuns the object string as a QString + */ + QString iString::ToQt() const { + return QString::fromStdString(*this); + } + + /** + * Resturns the input string as a QString + * + * @param s [in] The standard string to be converted to a Qt string + */ + QString iString::ToQt(const std::string &s) { + return(QString::fromStdString(s)); + } + + /** + * Returns the first token in the iString. A token is defined as a string of + * characters from the beginning of the string to, but not including, the first + * character matching any character in the separator string. The token is + * removed from the original string along with the separator. + * + * @param separator The string of characters used to separate tokens. The order + * of the characters is not important. + * + * @return iString + */ + iString iString::Token (const iString &separator) { + iString retstr = "" ; + + for (unsigned int i = 0; i < size(); i++) { + for (unsigned int sep = 0; sep < separator.size(); sep++) { + if (separator[sep] == at(i)) { + retstr = substr(0,i); + replace(0,i+1,""); + return retstr; + } + } + } + + if (retstr == "") { + retstr = (*this); + replace(0,size(),""); + } + + return retstr; + } + + /** + * @brief Find separators between characters and split them into strings + * + * This method will break up the input string into tokens that are separated by + * one or more of the specified character. If allowEmptyEntries == true, then + * one or separator characters are deem a single separator and the string is + * split into two different sections. If allowEmptyEntries == false, then + * should more than one separator character occur in succession, this will + * result in the number of separator characters less one empty strings returned + * to the caller. + * + * @param separator A single character that separates each substring + * @param str The string to break into separate fields or tokens + * @param tokens A vector of strings that will receive the tokens as separated + * by the separator character. + * @param allowEmptyEntries If true, treat successive separator characters as a + * single separator. If false, successive separator + * characters result in empty strings/tokens. + * @return int The number of fields/tokens found in str + */ + int iString::Split(const char separator, const std::string &str, + std::vector &tokens, + bool allowEmptyEntries) { + string::size_type idx(0), idx2(0); + unsigned int ksize = str.size(); + tokens.clear(); + + if (ksize > 0) { + if (str[idx] == separator) idx++; + while ((idx2 = str.find(separator, idx)) != string::npos) { + if ((idx2 == idx)) { + if (allowEmptyEntries) tokens.push_back(""); + } else { + string::size_type len(idx2 - idx); + tokens.push_back(str.substr(idx, len)); + } + idx = idx2 + 1; + } + if (idx < ksize) tokens.push_back(str.substr(idx)); + } + return(tokens.size()); + } + + + /** + * Collapses multiple spaces into single spaces + * + * @param force Determines whether to compress inside quotes (single and + * double) + * + */ + iString iString::Compress (bool force) { + *this = Compress((string)*this, force); + return *this; + } + + /** + * Returns the input string with multiple spaces collapsed into single spaces + * + * @param str The string to be compressed + * + * @param force Determines whether to compress inside quotes + * + * @return string The compressed version of the input string + */ + std::string iString::Compress (const std::string &str, bool force) { + string result(str); + if (force == false) { + int spaces = 0; + int leftquote = result.find_first_of ("\"\'"); + while ((spaces = result.find(" ", spaces)) >= 0) { + int rightquote = result.find_first_of ("\"\'", leftquote+1); + if (spaces < leftquote) {//spaces are before quotation + result.erase (spaces, 1); + leftquote = result.find_first_of ("\"\'", spaces); + } else if ((spaces > leftquote) && (spaces < rightquote)) {//spaces are within quotation + spaces = rightquote + 1; + leftquote = result.find_first_of ("\"\'", rightquote+1); + } else if (leftquote == (int)npos) {//there are no quotations + result.erase (spaces, 1); + } else {//spaces are after quotation + leftquote = result.find_first_of ("\"\'", rightquote+1); + } + } + return result; + } else { + int spaces = 0; + while ((spaces = result.find(" ", spaces)) >= 0) { + result.erase (spaces,1); + } + return result; + } + } + + /** + * Replaces all instances of the first input string with the second input + * string + * + * For more information, see iString::Replace(const string, const string, + * const string, int) + * + * @param from Search string that when found in str, it is replaced with to + * @param to iString that will replace every occurance of from in str. + * @param maxReplaceCount Maximum number of replacements to allow per call + * + */ + iString iString::Replace ( const std::string &from, const std::string &to, + int maxReplaceCount) { + *this = iString(Replace((string)*this,from,to,maxReplaceCount)); + return *this; + } + + /** + * @brief Replace specified substring with replacement substring in a string + * + * This method accepts a string, a target substring and a replacement substring + * with the intent to find all occurances of the \b subTarg substring in \b s + * and replace them with the substring \b subRep. The \b maxReplaceCount + * parameter is so that a should the replacement substring contain the target + * substring, an infinite loop would occur. + * + * Note that the search for strings are implemented as a loop that always starts + * at the begining of \b s. So should the above scenario occur, it will be + * limited. + * + * I have found this useful for formulating database SQL queries in a loop. The + * following example illustrates this usage: + * @code + * string pntDist = "distance(giscpt,UPCPoint(%longitude,%latitude))"; + * string pntQuery = "SELECT pointid, latitude, longitude, radius, " + * " %distance AS Distance FROM " + pntTable + + * " WHERE (%distance <= " + iString(maxDist) + ")"; + * + * SqlQuery finder; // Uses whatever the default database is + * while (!theEndOfTime()) { + * iString longitude(source.getLongitude()); + * iString latitude(source.getLatitude()); + * + * string qDist = StringTools::replace(pntDist,"%longitude", longitude); + * qDist = StringTools::replace(qDist,"%latitude", latitude); + * string query = StringTools::replace(pntQuery, "%distance", qDist); + * finder.exec(query); + * ... // Do what you will with the results! + * } + * @endcode + * + * This routine \b is case sensitive and will only replace exact matches. + * + * To prevent infinite recursion, where the replace string contains the search + * string, use the \b maxReplaceCount to adjust appropriately. + * + * @param str Input string to search and replace substrings + * @param from Search string that when found in str, it is replaced with to + * @param to iString that will replace every occurance of from in str. + * @param maxReplaceCount Maximum number of replacements to allow per call + * + * @return std::string NEw string with from replaced with to + */ + std::string iString::Replace (const std::string &str, const std::string &from, + const std::string &to, int maxReplaceCount ) { + if (str.empty()) return(str); + if (from.empty()) return(str); + string sRet(str); + string::size_type pos; + int nReplaced = 0; + while ((nReplaced < maxReplaceCount) && + (pos = sRet.find(from)) != string::npos) { + sRet.replace(pos, from.size(), to); + nReplaced++; + } + return(sRet); + } + + + /** + * Replaces all instances of the first input string with the second input + * string. Honoring quotes if requested by the boolean + * + * @param from Search string that when found in str, it is + * replaced with to. + * @param to iString that will replace every occurance of + * from in str. + * @param honorquotes Set to true to honor quotes and not + * replace inside them + * + * @return iString New string with subTarg replaced with subRep + * + */ + iString iString::Replace (const std::string &from, const std::string &to, + bool honorquotes) { + *this = Replace ((string)*this, from, to, honorquotes); + return *this; + } + + /** + * Replace specified substring with replacement substring in a string honoring + * quotes if requested. This routine is case sensitive and will only replace + * exact matches. + * + * @param str Input string to search and replace substrings in + * @param from Search string that when found in str, it is + * replaced with to. + * @param to iString that will replace every occurance of + * from in str. + * @param honorquotes Set to true to honor quotes and not + * replace inside them + * + * @return iString New string with subTarg replaced with + * subRep + */ + iString iString::Replace (const std::string &str, const std::string &from, + const std::string &to ,bool honorquotes) { + + string result = str; + if (honorquotes == true) { + int instances = 0; + int quote = result.find_first_of ("\"\'"); + while ((instances = result.find(from, instances)) >= 0) { + + int nextquote = result.find_first_of ("\"\'", quote+1); + if (instances < quote) { + result.replace (instances, from.length(), to); + quote = result.find_first_of ("\"\'", instances); + } else if ((instances > quote) && (instances < nextquote)) { + instances = nextquote + 1; + quote = result.find_first_of ("\"\'", nextquote); + } else if (quote == (int)npos) { + result.replace (instances, from.length(), to); + } else { + quote = result.find_first_of ("\"\'", nextquote); + } + } + return (iString) result; + } else { + int instances = 0; + while ((instances = result.find(from, instances)) >= 0) { + result.replace (instances, from.length(), to); + } + return (iString) result; + } + } + + /** + * Returns the string with all occurrences of any character in the "from" + * argument converted to the "to" argument. The original string is modified. + * + * @param listofchars The string of characters to be replaced. The order of the + * characters is not important. + * + * @param to The single character used as the replacement. + * + * @return iString + */ + iString iString::Convert (const std::string &listofchars, const char &to) { + *this = Convert ((string) *this, listofchars, to); + return *this; + } + + /** + * Converts all occurences in the input string of any character in the "from" + * string to the "to" character + * + * @param str The input string + * + * @param listofchars The string of characters to be replaced. The order of the + * characters is unimportant + * + * @param to The single character used as replacement + * + * @return string The converted string (the input string is unmodified) + */ + string iString::Convert (const std::string &str, const std::string &listofchars, + const char &to ) { + std::string::size_type pos = 0; + string result = str; + string tmp; + tmp = to; + while ((pos = result.find_first_of(listofchars, pos)) != npos) { + result.replace (pos, 1, tmp); + pos++; + } + return result; + } + + /** + * Returns the string with all "new lines", "carriage returns", "tabs", "form + * feeds", "vertical tabs" and "back spaces" converted to single spaces. All + * quotes are ignored. The original string is modified. + * + * @return iString + */ + iString iString::ConvertWhiteSpace (){ + *this = ConvertWhiteSpace((string)*this); + return *this; + } + + /** + * Converts all forms of whitespace in the input string into single spaces + * + * @param str + * + * @return string + */ + std::string iString::ConvertWhiteSpace( const std::string &str) { + return Convert (str, "\n\r\t\f\v\b", ' '); + } + + /** + * Remove all instances of any character in the string from the iString + * + * @param del The characters to be removed from the iString. The character is + * unimportant + * + * @return iString + */ + iString iString::Remove (const std::string &del) { + std::string::size_type pos; + while ((pos=find_first_of(del)) != npos) this->erase(pos,1); + return *this; + } + + /** + * Remove all instances of any character in the "del" argument from the input + * string + * + * @param str The string from which characters are to be removed + * + * @param del The string of characters to be removed. Order is unimportant. + * + * @return string The string with the characters removed. The original string + * is unmodified + */ + std::string iString::Remove (const std::string &str, const std::string &del) { + string::size_type pos; + string result (str); + while ((pos=result.find_first_of(del)) != npos) result.erase(pos,1); + return result; + } + + /** + * Attempts to convert a 32 bit integer into its string representation + * + * @param value [in] The 32 bit integer to be converted to a string + * + * @return The Isis::iString representation of the int + */ + iString& iString::operator= (const int &value) { + ostringstream str; + str << value; + assign (str.str()); + return *this; + } + + /** + * Attempts to convert a 64 bit integer into its string representation + * + * @param value [in] The 64 bit integer to be converted to a string + * + * @return The Isis::iString representation of the BigInt + */ + iString& iString::operator= (const BigInt &value) { + ostringstream str; + str << value; + assign (str.str()); + return *this; + } + + /** + * Converts a Qt string into a std::string + * + * @param str [in] The Qt string to be converted to a std::string + * + * @return The std::string representation of the Qt string + */ + std::string iString::ToStd (const QString &str) { + return(str.toStdString()); + } + + /** + * Converts a vector of strings into a QStringList + * + * @param sl STL vector of strings + * + * @return QStringList + */ + QStringList iString::ToQt (const std::vector &sl) { + QStringList Qsl; + for (unsigned int i = 0 ; i < sl.size() ; i++) { + Qsl << ToQt(sl[i]); + } + return Qsl; + } + + /** + * Converts a QStringList into a vector of strings + * + * @param sl + * + * @return vector + */ + std::vector iString::ToStd (const QStringList &sl) { + std::vector Stdsl; + for (int i = 0 ; i < sl.size() ; i++) { + Stdsl.push_back(ToStd(sl.at(i))); + } + + return(Stdsl); + } +} diff --git a/isis/src/base/objs/iString/iString.h b/isis/src/base/objs/iString/iString.h new file mode 100644 index 0000000000000000000000000000000000000000..dce2bef8d934cc5418b13046400aedc08dcf8bf6 --- /dev/null +++ b/isis/src/base/objs/iString/iString.h @@ -0,0 +1,245 @@ +#ifndef iString_h +#define iString_h +/** + * @file + * $Revision: 1.14 $ + * $Date: 2010/03/19 20:38:01 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include "Constants.h" + +namespace Isis { + +/** + * @brief Adds specific functionality to C++ strings + * + * This class extends the standard C++ string class with specific functionality + * useable by ISIS programmers. + * + * @ingroup Parsing + * + * @author 2002-09-10 Stuart Sides + * + * @internal + * @history 2003-02-05 Jeff Anderson - Modified the constructor routine which + * accepts a type of double (i.e., + * conversion of a double to a string). The + * constructor now generates nice output as + * indicated in the documentation. + * @history 2003-05-16 Stuart Sides - Modified schema from astrogeology... + * isis.astrogeology... + * @history 2003-05-30 Jeff Anderson - Updated unitTest and truth file to + * account for optimzation changes + * @history 2003-05-30 Stuart Sides - Modified conversion of double to string + * constructor to output 14 place of + * accuracy + * @history 2003-06-24 Stuart Sides - Modified UpCase and DownCase to use the + * transform from the STL instead of looping + * and converting individual chars + * @history 2003-06-25 Stuart Sides - Added member function to remove all + * characters which are in the parameter + * from the object string (Remove) + * @history 2003-06-25 Stuart Sides - Added documentation for new member + * (Remove) + * @history 2003-07-17 Stuart Sides - Fixed bug in Convert. It sometimes would + * not convert any characters even though it + * should have. find_first_of should be + * "!=npos" instead of ">0". + * @history 2003-08-14 Stuart Sides - Fixed bug in Token. It would not parse + * "a","b" correctly. + * @history 2004-02-20 Stuart Sides - Added ability for ToDouble to convert PDS + * hex values to a double + * @history 2004-04-14 Jeff Anderson - Added (int) (double) and (string) cast + * conversions and operator= methods + * @history 2005-02-15 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2005-05-20 Jeff Anderson - Added BigInt methods + * + * @history 2006-01-23 Jacob Danton - Changed the scientific notation start value (from 0.1 to 0.0001) + * + * @history 2007-06-05 Brendan George - Merged with StringTools + * + * @history 2007-07-17 Steven Lambright - Fixed bug where -0.0 would result in SetDouble + * + * @history 2007-07-25 Steven Koechle - Fixed a bug where one of the TrimTail + * methods was calling erase incorrectly. + * + * @history 2008-02-08 Steven Koechle - Keeps Convert from infinite looping + * + * @history 2008-02-22 Steven Koechle - Added a Replace method that honors quotes + * + * @history 2008-06-12 Jeannie Walldren - Fixed a bug in + * Compress method so that it is able to deal with + * multiple quotations within the string + * + * @history 2008-06-18 Stuart Sides - Fixed doc error + * + * @history 2005-02-15 Stuart Sides - add coded and implementation examples to + * class documentation and document + * iString(const char *str), and private + * methods + * @history 2008-07-14 Steven Lambright - Made some members const + * @history 2008-07-16 Steven Lambright - Added support for double nans and + * inifinities + * + * @history 2009-11-02 Mackenzie Boyd - Modified Token method + * to ignore any quote + * groupings. Problems + * arose with current + * method and unclosed + * quotes. + * @history 2010-03-18 Sharmila Prasad - Ability to set the exact precision digits for double + * + * @todo The Token member should consider single and double + * quotes seperatly *as of 10/28/09* Token no longer + * considers quotes at all, so this todo is irrelevant? + */ + class iString : public std::string { + public: + iString(); + + iString (const std::string &str); + iString (const iString &str); + iString (const char *str); + iString (const int &num); + iString (const double &num, const int piPrecision=14); + iString (const BigInt &num); + iString (const QString &str); + + ~iString (); + + iString Trim (const std::string &chars); + static std::string Trim (const std::string &chars, const std::string &str); + + iString TrimHead (const std::string &chars); + static std::string TrimHead (const std::string &chars, const std::string &str); + + iString TrimTail (const std::string &chars); + static std::string TrimTail (const std::string &chars, const std::string &str); + + iString UpCase (); + static std::string UpCase (const std::string &str); + + iString DownCase (); + static std::string DownCase (const std::string &str); + + int ToInteger () const; + static int ToInteger (const std::string &str); + + BigInt ToBigInteger () const; + static BigInt ToBigInteger (const std::string &str); + + double ToDouble () const; + static double ToDouble (const std::string &str); + + QString ToQt () const; + static QString ToQt (const std::string &str); + + iString Token (const iString &separator); + static int Split (const char separator, const std::string &instr, + std::vector &tokens, + bool allowEmptyEntries = true); + + iString Compress (bool force=false); + static std::string Compress (const std::string &str, bool force=false); + + iString Replace (const std::string &from, const std::string &to, + int maxReplaceCount = 20); + static std::string Replace (const std::string &str, + const std::string &from, + const std::string &to, + int maxReplacementCount = 20); + + iString Replace (const std::string &from, const std::string &to ,bool honorquotes); + static iString Replace (const std::string &str, const std::string &from, + const std::string &to ,bool honorquotes); + + iString Convert (const std::string &listofchars, const char &to); + static std::string Convert (const std::string &str, + const std::string &listofchars, + const char &to); + + iString ConvertWhiteSpace (); + static std::string ConvertWhiteSpace (const std::string &str); + + iString Remove (const std::string &del); + static std::string Remove (const std::string &del, const std::string &str); + + /** + * Attempts to convert the stirng to a 32 bit integer and return that int + * + * @return int + */ + operator int() const { return ToInteger(); }; + + /** + * Attempts to convert the stirng to a 64 bit integer and return that + * int + * + * @return BigInt + */ + operator BigInt() const { return ToBigInteger(); }; + + /** + * Attempts to convert the stirng to a 64 bit double and return that double + * + * @return double + */ + operator double() const { return ToDouble(); }; + + /** + * Attempts to convert the stirng to a QStirng (Qt) and return that QString + * + * @return QString + */ + operator QString() const { return ToQt(); }; + + iString& operator= (const int &value); + + iString& operator= (const BigInt &value); + + /** + * Attempts to convert double into its string representation + * + * @param value [in] The double to be converted to a string + * + * @return The Isis::iString representation of the double + */ + iString& operator= (const double &value) { + SetDouble(value); + return *this; + } + + bool Equal(const std::string &str) const; + static bool Equal(const std::string &str1, const std::string &str2); + + static std::string ToStd(const QString &str); + + static QStringList ToQt(const std::vector &sl); + static std::vector ToStd(const QStringList &sl); + + private: + void SetDouble(const double &value, const int piPrecision=14); + }; +}; +#endif diff --git a/isis/src/base/objs/iString/iString.truth b/isis/src/base/objs/iString/iString.truth new file mode 100644 index 0000000000000000000000000000000000000000..4d59b6b28883b99e63a022118317457b8a020ac6 --- /dev/null +++ b/isis/src/base/objs/iString/iString.truth @@ -0,0 +1,133 @@ +No arg construtor : Test string +Constructor Isis::iString: Test string again +Constructor char : 65 +Constructor int : 999 +Constructor BigInt : 9999999999 +Constructor double :999.999 +Before Trim : ABCDefghijkBCAD +Return Trim : efghijk +After Trim : efghijk +Before TrimHead : ABCDefghijkBCAD +Return TrimHead : efghijkBCAD +After TrimHead : efghijkBCAD +Middle test : efghijkBCAD +Before TrimTail : ABCDefghijkBCAD +Return TrimTail : ABCDefghijk +After TrimTail : ABCDefghijk +Middle test : ABCDefghijk +Before TrimHead : ABCDefghijkBCAD +After TrimHead : efghijkBCAD +Middle test : efghijkBCAD +Before TrimTail : ABCDefghijkBCAD +After TrimTail : ABCDefghijk +Middle test : ABCDefghijk +Before Upcase : abcdefghijklmnopqrstuvwxyzABC!@#$%^&*() +After Upcase : ABCDEFGHIJKLMNOPQRSTUVWXYZABC!@#$%^&*() +Before DownCase : ABCDEFGHIJKLMNOPQRSTUVWXYZABC!@#$%^&*() +After DownCase : abcdefghijklmnopqrstuvwxyzabc!@#$%^&*() +Integer : 987654321 +Integer : 987654321 +**PARSE ERROR** Cannot convert (987trew) to an integer +BigInteger : 9876543210 +BigInteger : 9876543210 +**PARSE ERROR** Cannot convert (987trew) to a big integer +Double : 9876.54321 +Double : 9876.54321 +**PARSE ERROR** Cannot convert [123$987] to a double +Exponent : 123.0E45 +Exponent : 1.23e+47 +25:255 35:15 +25 +255 +35 +15 +key1=tok1 key2="t o k 2" key3=(1,2,3,4) +key1 +tok1 +key2 +"t +o +k +2" +key3 +(1,2,3,4) +"abcd","1234" +"abcd" +"1234" +",1234","ab,cd" +" +1234" +"ab +cd" +/this/is/a/long/filename.jnk,seperated/by/a/comma/ending/with/ +/this/is/a/long/filename.jnk +seperated/by/a/comma/ending/with/ +/this/is/another/long/filename.jnk seperated/by/3/spaces/file2.tmp +token# 1>> /this/is/another/long/filename.jnk +token# 2>> +token# 3>> +token# 4>> seperated/by/3/spaces/file2.tmp + +Before compress > " " < +After compress > " " < +Before compress >| " " ' ' |< +After compress >| " " ' ' |< +Before compress > AB CD < +After compress > AB CD < +Before force compress > " " < +After force compress > " " < +Before force compress > "AB CD" < +After force compress > "AB CD" < +Before force compress > < +After force compress > < +Before convert >ABCDEFG< +After convert >A-C-E--< +Before replace >Thirteen is bigger than fourteen< +After replace >Thirteen is smaller than fourteen< +After convert white space >a b c< +Before Upcase >xxxXXX0< +After Upcase >XXXXXX0< +Before DownCase >XXXXXX0< +After DownCase >xxxxxx0< +Testing QT conversion: 1 +255.0 +0.333 +-255.0 +1.235e-20 +1.23456789012346e+19 +5.0e-04 +Before Remove >a 1 b 2 c 3 d 4 e 5< +After Remove >a b c 3 d e < +100 +100000000000 +100.1 +Before Replace (honor quotes) >I is a test string: 'I is' is "is a string"< +After Replace (honor quotes) >I am a test string: 'I is' is "is a string"< +Before Replace (dont honor quotes) >I is a test string: 'I is' is "is a string"< +After Replace (dont honor quotes) >I am a test string: 'I am' am "am a string"< +Before split >This is a test string< +After split > +Element 0: This +Element 1: is +Element 2: a +Element 3: test +Element 4: string +< + +Qt QStringList values: +String1 +String2 +String3 +String4 + +Converted to std::vector... +String1 +String2 +String3 +String4 +Are they equivalent? +Counts? Yes +string(String1) == QString(String1)? Yes +string(String2) == QString(String2)? Yes +string(String3) == QString(String3)? Yes +string(String4) == QString(String4)? Yes diff --git a/isis/src/base/objs/iString/unitTest.cpp b/isis/src/base/objs/iString/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf925d785ad457a196a88d60e6ff33273a871e62 --- /dev/null +++ b/isis/src/base/objs/iString/unitTest.cpp @@ -0,0 +1,288 @@ +#include +#include +#include "iString.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +inline string yesOrNo(bool b) { + if (b) return (string("Yes")); + return (string("No")); +} + +int main (int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + cout.precision(14); + // Tests for non-static functions + try { + Isis::iString str0; + str0 = "Test string"; + cout << "No arg construtor : " << str0 << endl; + + Isis::iString str1 = str0 + " again"; + cout << "Constructor Isis::iString: " << str1 << endl; + + Isis::iString str1_5 = 'A'; + cout << "Constructor char : " << str1_5 << endl; + + Isis::iString str2 = 999; + cout << "Constructor int : " << str2 << endl; + + Isis::iString str2a = Isis::BigInt(9999999999LL); + cout << "Constructor BigInt : " << str2a << endl; + + Isis::iString str3 = 999.999; + cout << "Constructor double :" << str3 << endl; + + Isis::iString str4 = "ABCDefghijkBCAD"; + cout << "Before Trim : " << str4 << endl; + cout << "Return Trim : " << str4.Trim ("ABCD") << endl; + cout << "After Trim : " << str4 << endl; + + Isis::iString str5 = "ABCDefghijkBCAD"; + cout << "Before TrimHead : " << str5 << endl; + cout << "Return TrimHead : " << str5.TrimHead ("DBCA") << endl; + cout << "After TrimHead : " << str5 << endl; + cout << "Middle test : " << str5.TrimHead ("g") << endl; + + Isis::iString str6 = "ABCDefghijkBCAD"; + cout << "Before TrimTail : " << str6 << endl; + cout << "Return TrimTail : " << str6.TrimTail ("DBCA") << endl; + cout << "After TrimTail : " << str6 << endl; + cout << "Middle test : " << str6.TrimTail ("f") << endl; + + std::string str35 = "ABCDefghijkBCAD"; + cout << "Before TrimHead : " << str35 << endl; + str35 = Isis::iString::TrimHead("DBCA",str35); + cout << "After TrimHead : " << str35 << endl; + str35 = Isis::iString::TrimHead("g",str35); + cout << "Middle test : " << str35 << endl; + + std::string str36 = "ABCDefghijkBCAD"; + cout << "Before TrimTail : " << str36 << endl; + str36 = Isis::iString::TrimTail("DBCA",str36); + cout << "After TrimTail : " << str36 << endl; + str36 = Isis::iString::TrimTail("f",str36); + cout << "Middle test : " << str36 << endl; + + Isis::iString str7 = "abcdefghijklmnopqrstuvwxyzABC!@#$%^&*()"; + cout << "Before Upcase : " << str7 << endl; + cout << "After Upcase : " << str7.UpCase () << endl; + + cout << "Before DownCase : " << str7 << endl; + cout << "After DownCase : " << str7.DownCase () << endl; + + Isis::iString str8 = 987654321; + cout << "Integer : " << str8 << endl; + cout << "Integer : " << str8.ToInteger () << endl; + str8 = "987trew"; + try { + str8.ToInteger (); + } + catch (Isis::iException &error) { + error.Report (false); + } + + Isis::iString str8a = Isis::BigInt(9876543210LL); + cout << "BigInteger : " << str8a << endl; + cout << "BigInteger : " << str8a.ToBigInteger () << endl; + str8a = "987trew"; + try { + str8a.ToBigInteger (); + } + catch (Isis::iException &error) { + error.Report (false); + } + + Isis::iString str9 = 9876.54321; + cout << "Double : " << str9.c_str() << endl; + cout << "Double : " << str9.ToDouble () << endl; + str9 = "123$987"; + try { + str9.ToDouble (); + } + catch (Isis::iException &error) { + error.Report (false); + } + + Isis::iString str10 = "123.0E45"; + cout << "Exponent : " << str10 << endl; + cout << "Exponent : " << str10.ToDouble () << endl; + + Isis::iString str11 = "25:255 35:15"; + cout << str11 << endl; + while (str11.length() > 0) { + cout << str11.Token(": ") << endl; + } + + str11 = "key1=tok1 key2=\"t o k 2\" key3=(1,2,3,4)"; + cout << str11 << endl; + while (str11.length() > 0) { + cout << str11.Token("= ") << endl; + } + + str11 = "\"abcd\",\"1234\""; + cout << str11 << endl; + while (str11.length() > 0) { + cout << str11.Token(",") << endl; + } + + str11 = "\",1234\",\"ab,cd\""; + cout << str11 << endl; + while (str11.length() > 0) { + cout << str11.Token(",") << endl; + } + + str11 = "/this/is/a/long/filename.jnk,seperated/by/a/comma/ending/with/\r\n"; + cout << str11.Trim("\r\n") << endl; + while (str11.length() > 0) { + cout << str11.Token(",") << endl; + } + + str11 = "/this/is/another/long/filename.jnk seperated/by/3/spaces/file2.tmp"; + cout << str11.Trim("\r\n") << endl; + int m = 1; + while (str11.length() > 0) { + cout << "token# " << m++ << ">> " << str11.Token(" ") << endl; + } + + cout << endl; + + Isis::iString str12 = " \" \" "; + cout << "Before compress >" << str12 << "<" << endl; + str12.Compress (); + cout << "After compress >" << str12 << "<" << endl; + + Isis::iString str12b = "| \" \" \' \' |"; + cout << "Before compress >" << str12b << "<" << endl; + str12b.Compress (); + cout << "After compress >" << str12b << "<" << endl; + + Isis::iString str13 = " AB CD "; + cout << "Before compress >" << str13 << "<" << endl; + str13.Compress (); + cout << "After compress >" << str13 << "<" << endl; + + Isis::iString str14 = " \" \" "; + cout << "Before force compress >" << str14 << "<" << endl; + cout << "After force compress >" << str14.Compress (true) << "<" << endl; + + Isis::iString str15 = " \"AB CD\" "; + cout << "Before force compress >" << str15 << "<" << endl; + cout << "After force compress >" << str15.Compress (true) << "<" << endl; + + Isis::iString str16 = " "; + cout << "Before force compress >" << str16 << "<" << endl; + cout << "After force compress >" << str16.Compress (true) << "<" << endl; + + Isis::iString str17 = "ABCDEFG"; + cout << "Before convert >" << str17 << "<" << endl; + cout << "After convert >" << str17.Convert("BDFG", '-') << "<" << endl; + + Isis::iString str18 = "Thirteen is bigger than fourteen"; + cout << "Before replace >" << str18 << "<" << endl; + cout << "After replace >" << str18.Replace("bigger", "smaller") << "<" << endl; + + Isis::iString str19 = "a\tb\b\n\v\f\r c"; + // Don't cout the before string, it will cause all sorts of problems + // cout << "Before convert >" << str19 << "<" << endl; + cout << "After convert white space >" << str19.ConvertWhiteSpace () << "<" << endl; + + Isis::iString str20 = "xxxXXX0"; + cout << "Before Upcase >" << str20 << "<" << endl; + cout << "After Upcase >" << str20.UpCase () << "<" << endl; + + cout << "Before DownCase >" << str20 << "<" << endl; + cout << "After DownCase >" << str20.DownCase () << "<" << endl; + + Isis::iString str21 = "Test String"; + QString qstr1 = "Test String"; + cout << "Testing QT conversion: " << (str21.ToQt() == qstr1) << endl; + + Isis::iString str22(255.0); + Isis::iString str23(0.333); + Isis::iString str24(-255.0); + Isis::iString str25(1.235E-20); + Isis::iString str26(12345678901234567890.0); + Isis::iString str27(0.0005); + cout << str22 << endl; + cout << str23 << endl; + cout << str24 << endl; + cout << str25 << endl; + cout << str26 << endl; + cout << str27 << endl; + + Isis::iString str28("a 1 b 2 c 3 d 4 e 5"); + cout << "Before Remove >" << str28 << "<" << endl; + cout << "After Remove >" << str28.Remove("1245") << "<" << endl; + + Isis::iString str29("100"); + int i = str29; + cout << i << endl; + + Isis::iString str29a("100000000000"); + Isis::BigInt j = str29a; + cout << j << endl; + + Isis::iString str30("100.1"); + double d = str30; + cout << d << endl; + + Isis::iString str31("I is a test string: 'I is' is \"is a string\""); + Isis::iString str31a("I is a test string: 'I is' is \"is a string\""); + cout << "Before Replace (honor quotes) >" << str31 << "<" << endl; + str31.Replace("is","am",true); + cout << "After Replace (honor quotes) >" << str31 << "<" << endl; + cout << "Before Replace (dont honor quotes) >" << str31a << "<" << endl; + str31a.Replace("is","am",false); + cout << "After Replace (dont honor quotes) >" << str31a << "<" << endl; + + } + catch (Isis::iException &error) { + error.Report (false); + } + + //Tests for static functions untested above + try { + //Split test + string str1 = "This is a test string"; + vector strVec; + Isis::iString::Split(' ', str1, strVec); + cout << "Before split >" << str1 << "<" << endl; + cout << "After split >"; + for (unsigned int i=0 ; i < strVec.size() ; i++) { + cout << endl << "Element " << i << ": " << strVec[i]; + } + cout << endl << "<" << endl; + + QStringList qlist; + qlist << "String1" + << "String2" + << "String3" + << "String4"; + + cout << "\nQt QStringList values:\n"; + for (int i = 0 ; i < qlist.size() ; i++) { + cout << qlist.at(i).toLocal8Bit().constData() << endl; + } + + cout << "\nConverted to std::vector...\n"; + vector slist = Isis::iString::ToStd(qlist); + copy(slist.begin(), slist.end(), ostream_iterator(cout, "\n")); + + cout << "Are they equivalent?\n"; + cout << "Counts? " << yesOrNo((int) slist.size() == qlist.size()) << endl; + for (int j = 0 ; j < qlist.size() ; j++) { + QString qs = qlist.at(j); + string ss = slist.at(j); + cout << "string(" << ss << ") == QString(" + << qs.toLocal8Bit().constData() << ")? " + << yesOrNo(ss == qs.toStdString()) << endl; + } + + } catch (Isis::iException &error) { + error.Report (false); + } +} diff --git a/isis/src/base/objs/iTime/Makefile b/isis/src/base/objs/iTime/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..94c0dcb383874c370a011b4e555a606bd6cf7a88 --- /dev/null +++ b/isis/src/base/objs/iTime/Makefile @@ -0,0 +1,5 @@ +INCS = iTime.h +SRCS = iTime.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/base/objs/iTime/iTime.cpp b/isis/src/base/objs/iTime/iTime.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06e6caa8466f75570ba8debf65ba52cebb8b2ff0 --- /dev/null +++ b/isis/src/base/objs/iTime/iTime.cpp @@ -0,0 +1,496 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/01/15 01:37:59 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "Preference.h" + +#include "Filename.h" +#include "iString.h" +#include "iTime.h" + +using namespace std; +namespace Isis { + + // Static initializations + bool iTime::p_lpInitialized = false; + + //--------------------------------------------------------------------------- + // Constructors + //--------------------------------------------------------------------------- + + //! Constructs an empty iTime object. + iTime::iTime () { + p_original = ""; + } + + /** + * Constructs a iTime object and initializes it to the time from the argument. + * + * @param time A time string formatted in standard UTC or similar format. + * Example:"2000/12/31 23:59:01.6789" or "2000-12-31T23:59:01.6789" + */ + iTime::iTime (const std::string &time) { + LoadLeapSecondKernel (); + + // Convert the time string to a double ephemeris time + SpiceDouble et; + str2et_c (time.c_str(), &et); + + p_et = et; + p_original = time; + + Extract (); + UnloadLeapSecondKernel (); + } + + /** + * Constructs a iTime object and initializes it to the time from the argument. + * + * @param time An ephemeris time (ET). + */ + iTime::iTime (const double time) { + LoadLeapSecondKernel (); + p_et = time; + Extract (); + p_original = EtString(); + UnloadLeapSecondKernel (); + } + + //! Destroys the iTime object + iTime::~iTime () {} + + + //--------------------------------------------------------------------------- + // Public members + //--------------------------------------------------------------------------- + + /** + * Changes the value of the iTime object. + * + * @param time A time string formatted in standard UTC or similar format. + * Example:"2000/12/31 23:59:01.6789" or "2000-12-31T23:59:01.6789" + */ + void iTime::operator=(const std::string &time) { + + LoadLeapSecondKernel (); + + // Convert the time string to a double ephemeris time + SpiceDouble et; + str2et_c (time.c_str(), &et); + + p_et = et; + p_original = time; + + Extract (); + UnloadLeapSecondKernel (); + } + + // Overload of "=" with a c string + void iTime::operator=(const char *time) { + + LoadLeapSecondKernel (); + + // Convert the time string to a double ephemeris time + SpiceDouble et; + str2et_c (time, &et); + + p_et = et; + p_original = time; + + Extract (); + UnloadLeapSecondKernel (); + } + + + // Overload of "=" with a double + void iTime::operator=(const double time) { + LoadLeapSecondKernel (); + p_et = time; + Extract (); + p_original = EtString(); + UnloadLeapSecondKernel (); + } + + /** + * Compare two iTime objects for greater than or equal + * + * @param time The iTime object to be compared to "this" + * + * @return bool + */ + bool iTime::operator>=(const iTime &time) { + return (p_et >= time.p_et); + } + + /** + * Compare two iTime objects for less than or equal + * + * @param time The iTime object to be compared to "this" + * + * @return bool + */ + bool iTime::operator<=(const iTime &time) { + return (p_et <= time.p_et); + } + + /** + * Compare two iTime objects for greater than + * + * @param time The iTime object to be compared to "this" + * + * @return bool + */ + bool iTime::operator>(const iTime &time) { + return (p_et > time.p_et); + } + + + /** + * Compare two iTime objects for less than + * + * @param time The iTime object to be compared to "this" + * + * @return bool + */ + bool iTime::operator<(const iTime &time) { + return (p_et < time.p_et); + } + + /** + * Compare two iTime objects for inequality + * + * @param time The iTime object to be compared to "this" + * + * @return bool + */ + bool iTime::operator!=(const iTime &time) { + return (p_et != time.p_et); + } + + /** + * Compare two iTime objects for equality + * + * @param time The iTime object to be compared to "this" + * + * @return bool + */ + bool iTime::operator==(const iTime &time) { + return (p_et == time.p_et); + } + + /** + * Returns the year portion of the time as a string + * + * @return string + */ + string iTime::YearString () const { + Isis::iString sYear (p_year); + return sYear; + } + + /** + * Returns the year portion of the time as an int + * + * @return int + */ + int iTime::Year () const { + return p_year; + } + + /** + * Returns the month portion of the time as a string + * + * @return string + */ + string iTime::MonthString () const { + Isis::iString sMonth (p_month); + return sMonth; + } + + /** + * Returns the month portion of the time as an int + * + * @return int + */ + int iTime::Month () const { + return p_month; + } + + /** + * Returns the dat portion of the time as a string + * + * @return string + */ + string iTime::DayString () const { + Isis::iString sDay (p_day); + return sDay; + } + + /** + * Returns the day portion of the time as an int + * + * @return int + */ + int iTime::Day () const { + return p_day; + } + + /** + * Returns the hour portion of the time as a string + * + * @return string + */ + string iTime::HourString () const { + Isis::iString sHour (p_hour); + return sHour; + } + + /** + * Returns the hour portion of the time as an int + * + * @return int + */ + int iTime::Hour () const { + return p_hour; + } + + /** + * Returns the minute portion of the time as a string + * + * @return string + */ + string iTime::MinuteString () const { + Isis::iString sMinute (p_minute); + return sMinute; + } + + /** + * Returns the minute portion of the time as an int + * + * @return int + */ + int iTime::Minute () const { + return p_minute; + } + + /** + * Returns the second portion of the time as a string + * + * @return string + */ + string iTime::SecondString () const { + ostringstream osec; + osec.setf(ios::fixed); + osec << setprecision(8) << p_second; + iString sSeconds(osec.str()); + sSeconds.TrimTail("0"); + sSeconds.TrimTail("."); + if ( sSeconds.empty() ) sSeconds = "0"; + return (sSeconds); + } + + /** + * Returns the second portion of the time as a double + * + * @return double + */ + double iTime::Second () const { + return p_second; + } + + /** + * Returns the day of year portion of the time as a string + * + * @return string + */ + string iTime::DayOfYearString () const { + Isis::iString sDayOfYear (p_dayOfYear); + return sDayOfYear; + } + + /** + * Returns the day of year portion of the time as an int + * + * @return int + */ + int iTime::DayOfYear () const { + return p_dayOfYear; + } + + /** + * Returns the ephemeris time (TDB) representation of the time as a string. + * See the Naif documentation "time.req" for more information. + * + * @return string + */ + string iTime::EtString () const { + Isis::iString sEt (p_et); + return sEt; + } + + /** + * Returns the ephemeris time (TDB) representation of the time as a double. + * See the Naif documentation "time.req" for more information. + * + * @return double + */ + double iTime::Et () const { + return p_et; + } + + /** + * Returns the internally stored time, formatted as a UTC time + * + * @return string The internalized time, in UTC format + */ + string iTime::UTC () const { + string utc = YearString() + "-" ; + if (Month() < 10) utc += "0" + MonthString() + "-"; + else utc += MonthString() + "-"; + + if (Day() < 10) utc += "0" + DayString() + "T"; + else utc += DayString() + "T"; + + if (Hour() < 10) utc += "0" + HourString() + ":"; + else utc += HourString() + ":"; + + if (Minute() < 10) utc += "0" + MinuteString() + ":"; + else utc += MinuteString() + ":"; + + if (Second() < 10) utc += "0" + SecondString(); + else utc += SecondString(); + + return utc; + } + + //--------------------------------------------------- + // Private members + //--------------------------------------------------- + + /** + * Uses the Naif routines to convert a double ephemeris reresentation of a + * date/time to its individual components. + */ + void iTime::Extract () { + + SpiceChar out[256]; + Isis::iString tmp; + + // Populate the private year member + timout_c (p_et, "YYYY", 256, out); + tmp = out; + p_year = tmp.ToInteger(); + + // Populate the private month member + timout_c (p_et, "MM", 256, out); + tmp = out; + p_month = tmp.ToInteger(); + + // Populate the private day member + timout_c (p_et, "DD", 256, out); + tmp = out; + p_day = tmp.ToInteger(); + + // Populate the private hour member + timout_c (p_et, "HR", 256, out); + tmp = out; + p_hour = tmp.ToInteger(); + + // Populate the private minute member + timout_c (p_et, "MN", 256, out); + tmp = out; + p_minute = tmp.ToInteger(); + + // Populate the private second member + timout_c (p_et, "SC.#######::RND", 256, out); + tmp = out; + p_second = tmp.ToDouble(); + + // Populate the private doy member + timout_c (p_et, "DOY", 256, out); + tmp = out; + p_dayOfYear = tmp.ToInteger(); + + } + + + //! Uses the Naif routines to load the most current leap second kernel. + void iTime::LoadLeapSecondKernel () { + // Inorder to improve the speed of iTime comparisons, the leapsecond + // kernel is loaded only once and left open. + if (p_lpInitialized) return; + + // Get the leap second kernel file open + Isis::PvlGroup &dataDir = Isis::Preference::Preferences().FindGroup("DataDirectory"); + string baseDir = dataDir["Base"]; + baseDir += "/kernels/lsk/"; + p_leapSecond = baseDir + "naif????.tls"; + p_leapSecond.HighestVersion(); + + string leapSecondName(p_leapSecond.Expanded()); + furnsh_c (leapSecondName.c_str()); + + p_lpInitialized = true; + } + + //! Uses the Naif routines to unload the leap second kernel. + void iTime::UnloadLeapSecondKernel () { + // Inorder to improve the speed of iTime comparisons, the leapsecond + // kernel is loaded only once and left open. + + //string leapSecondName(p_leapSecond.Expanded()); + //unload_c (leapSecondName.c_str()); + } + + /** + * Returns the current Greenwich Mean iTime + * The time is based on the system time, so it is only as + * accurate as the local system clock. + * + * @return std::string The Current GMT + */ + std::string iTime::CurrentGMT() { + time_t startTime = time(NULL); + struct tm *tmbuf = gmtime(&startTime); + char timestr[80]; + strftime(timestr,80,"%Y-%m-%dT%H:%M:%S",tmbuf); + return (std::string) timestr; + } + + + /** + * Returns the current local time + * This time is taken directly from the system clock, so + * if the system clock is off, this will be, too. + * + * @return std::string The cutrrent local time + */ + std::string iTime::CurrentLocalTime() { + time_t startTime = time(NULL); + struct tm *tmbuf = localtime(&startTime); + char timestr[80]; + strftime(timestr,80,"%Y-%m-%dT%H:%M:%S",tmbuf); + return (std::string) timestr; + } +} // end namespace isis diff --git a/isis/src/base/objs/iTime/iTime.h b/isis/src/base/objs/iTime/iTime.h new file mode 100644 index 0000000000000000000000000000000000000000..ba3b92e0dca4cea165131db0f7b1ccd41a1da64c --- /dev/null +++ b/isis/src/base/objs/iTime/iTime.h @@ -0,0 +1,147 @@ +#ifndef Time_h +#define Time_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/12/28 19:27:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" + +#include "Filename.h" + +namespace Isis { +/** + * @brief Parse and return pieces of a time string + * + * This class parses a date/time string into individual components. The input + * time string can be in a variety of formats (see the NAIF routine str2et_c). + * The components and different representation can then be returned using the + * member functions. + * + * @ingroup Parsing + * + * @author 2003-10-24 Stuart Sides + * + * @internal + * @history 2003-11-05 Stuart Sides - Fixed error in documentation + * @history 2003-12-03 Stuart Sides - Added comparison operators for (>=, <=, + * >, <, ==, and !=) + * @history 2003-12-09 Stuart Sides - Modified so all iTime objects will share + * the same leap second kernel. This means + * the leapsecond kernel will be loaded once + * and never unloaded. Other objects which + * use the leapsecond kernel should not + * unload it either. + * @history 2005-02-22 Elizabeth Ribelin - Modified file to support Doxygen + * documentation + * @history 2006-03-31 Elizabeth Miller - added UTC method + * @history 2006-10-02 Brendan George - Added CurrentLocalTime and CurrentGMT + * methods + * @history 2007-12-07 Kris Becker - Modifed the SecondString() method to + * always return fixed notation for fractions of a second of no more + * than 8 digits after the decimal point. It was returning scientific + * notation causing parsing errors (in NAIF, PostgreSQL TIMESTAMP + * fields, etc...) + * + * @todo 2005-02-22 Stuart Sides - add coded and implementation examples to + * class documentation + */ + class iTime { + private: + Isis::Filename p_leapSecond; /**=(const iTime &time); + bool operator<=(const iTime &time); + bool operator>(const iTime &time); + bool operator<(const iTime &time); + bool operator!=(const iTime &time); + bool operator==(const iTime &time); + + // Return the year + std::string YearString () const; + int Year () const; + std::string MonthString () const; + int Month () const; + std::string DayString () const; + int Day () const; + std::string HourString () const; + int Hour () const; + std::string MinuteString () const; + int Minute () const; + std::string SecondString () const; + double Second () const; + std::string DayOfYearString () const; + int DayOfYear () const; + std::string EtString () const; + double Et () const; + std::string UTC () const; + static std::string CurrentGMT(); + static std::string CurrentLocalTime(); + }; +}; + +#endif + diff --git a/isis/src/base/objs/iTime/iTime.truth b/isis/src/base/objs/iTime/iTime.truth new file mode 100644 index 0000000000000000000000000000000000000000..4e78bd6e16da4e17bd4a0f6da45a8d2376c26653 --- /dev/null +++ b/isis/src/base/objs/iTime/iTime.truth @@ -0,0 +1,85 @@ +Unit test for Isis::iTime + Test of date = 2003/01/02 12:15:01.1234 + Year = 2003 + Year = 2003 + Month = 1 + Month = 1 + Day = 2 + Day = 2 + Hour = 12 + Hour = 12 + Minute = 15 + Minute = 15 + Second = 1.1234 + Second = 1.1234 + Day of Year = 2 + Day of Year = 2 + Et = 94781765.307363 + Et = 94781765.3 + UTC = 2003-01-02T12:15:01.1234 + + Test of date = 2000-12-31T23:59:01.6789 + Year = 2000 + Year = 2000 + Month = 12 + Month = 12 + Day = 31 + Day = 31 + Hour = 23 + Hour = 23 + Minute = 59 + Minute = 59 + Second = 1.6789 + Second = 1.6789 + Day of Year = 366 + Day of Year = 366 + Et = 31579205.862834 + Et = 31579205.9 + UTC = 2000-12-31T23:59:01.6789 + + Test of date = 31579205.862834 + Year = 2000 + Year = 2000 + Month = 12 + Month = 12 + Day = 31 + Day = 31 + Hour = 23 + Hour = 23 + Minute = 59 + Minute = 59 + Second = 1.6789 + Second = 1.6789 + Day of Year = 366 + Day of Year = 366 + Et = 31579205.862834 + Et = 31579205.9 + UTC = 2000-12-31T23:59:01.6789 + + Test of Isis::iTime operator>= member + 94781765.307363 >= 94781765.307363 = 1 + 94781765.307363 >= 94781765.307413 = 0 + 94781765.307363 >= 94781765.306963 = 1 + + Test of Isis::iTime operator<= member + 94781765.307363 <= 94781765.307363 = 1 + 94781765.307363 <= 94781765.307413 = 1 + 94781765.307363 <= 94781765.306963 = 0 + + Test of Isis::iTime operator> member + 94781765.307363 > 94781765.307363 = 0 + 94781765.307363 > 94781765.307413 = 0 + 94781765.307363 > 94781765.306963 = 1 + + Test of Isis::iTime operator< member + 94781765.307363 < 94781765.307363 = 0 + 94781765.307363 < 94781765.307413 = 1 + 94781765.307363 < 94781765.306963 = 0 + + Test of Isis::iTime operator!= member + 94781765.307363 != 94781765.307363 = 0 + 94781765.307363 != 94781765.307413 = 1 + + Test of Isis::iTime operator== member + 94781765.307363 == 94781765.307363 = 1 + 94781765.307363 == 94781765.307413 = 0 diff --git a/isis/src/base/objs/iTime/unitTest.cpp b/isis/src/base/objs/iTime/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e2fde22317e2cc20d340cd4120c7acaec6d516f4 --- /dev/null +++ b/isis/src/base/objs/iTime/unitTest.cpp @@ -0,0 +1,231 @@ +#include +#include +#include "iException.h" +#include "iTime.h" + +#include "Preference.h" + +using namespace std; +int main (int argc, char *argv[]) { + + Isis::Preference::Preferences(true); + + cout << "Unit test for Isis::iTime" << endl; + + try { + cout << setprecision(9); + string test = "2003/01/02 12:15:01.1234"; + Isis::iTime *time = new Isis::iTime (test); + cout << " Test of date = " << test << endl; + cout << " Year = " << time->YearString() << endl; + cout << " Year = " << time->Year() << endl; + cout << " Month = " << time->MonthString() << endl; + cout << " Month = " << time->Month() << endl; + cout << " Day = " << time->DayString() << endl; + cout << " Day = " << time->Day() << endl; + cout << " Hour = " << time->HourString() << endl; + cout << " Hour = " << time->Hour() << endl; + cout << " Minute = " << time->MinuteString() << endl; + cout << " Minute = " << time->Minute() << endl; + cout << " Second = " << time->SecondString() << endl; + cout << " Second = " << time->Second() << endl; + cout << " Day of Year = " << time->DayOfYearString() << endl; + cout << " Day of Year = " << time->DayOfYear() << endl; + cout << " Et = " << time->EtString() << endl; + cout << " Et = " << time->Et() << endl; + cout << " UTC = " << time->UTC() << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + + + double saveEt = 0.0; + try { + cout << endl; + cout << setprecision(9); + string test = "2000-12-31T23:59:01.6789"; + Isis::iTime time; + time = test; + cout << " Test of date = " << test << endl; + cout << " Year = " << time.YearString() << endl; + cout << " Year = " << time.Year() << endl; + cout << " Month = " << time.MonthString() << endl; + cout << " Month = " << time.Month() << endl; + cout << " Day = " << time.DayString() << endl; + cout << " Day = " << time.Day() << endl; + cout << " Hour = " << time.HourString() << endl; + cout << " Hour = " << time.Hour() << endl; + cout << " Minute = " << time.MinuteString() << endl; + cout << " Minute = " << time.Minute() << endl; + cout << " Second = " << time.SecondString() << endl; + cout << " Second = " << time.Second() << endl; + cout << " Day of Year = " << time.DayOfYearString() << endl; + cout << " Day of Year = " << time.DayOfYear() << endl; + cout << " Et = " << time.EtString() << endl; + cout << " Et = " << time.Et() << endl; + cout << " UTC = " << time.UTC() << endl; + saveEt = time.Et(); + } + catch (Isis::iException &error) { + error.Report (false); + } + + + try { + cout << endl; + cout << setprecision(9); + Isis::iTime time(saveEt); + cout << " Test of date = " << time.EtString() << endl; + cout << " Year = " << time.YearString() << endl; + cout << " Year = " << time.Year() << endl; + cout << " Month = " << time.MonthString() << endl; + cout << " Month = " << time.Month() << endl; + cout << " Day = " << time.DayString() << endl; + cout << " Day = " << time.Day() << endl; + cout << " Hour = " << time.HourString() << endl; + cout << " Hour = " << time.Hour() << endl; + cout << " Minute = " << time.MinuteString() << endl; + cout << " Minute = " << time.Minute() << endl; + cout << " Second = " << time.SecondString() << endl; + cout << " Second = " << time.Second() << endl; + cout << " Day of Year = " << time.DayOfYearString() << endl; + cout << " Day of Year = " << time.DayOfYear() << endl; + cout << " Et = " << time.EtString() << endl; + cout << " Et = " << time.Et() << endl; + cout << " UTC = " << time.UTC() << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + + + try { + cout << endl; + cout << setprecision(9); + cout << " Test of Isis::iTime operator>= member" << endl; + string test = "2003/01/02 12:15:01.1234"; + Isis::iTime *t1 = new Isis::iTime (test); + test = "2003/01/02 12:15:01.1234"; + Isis::iTime *t2 = new Isis::iTime (test); + cout << " " << t1->EtString() << " >= " << t2->EtString() << " = "; + cout << (*t1 >= *t2) << endl; + Isis::iTime *t3 = new Isis::iTime ("2003/01/02 12:15:01.12345"); + cout << " " << t1->EtString() << " >= " << t3->EtString() << " = "; + cout << (*t1 >= *t3) << endl; + Isis::iTime *t4 = new Isis::iTime ("2003/01/02 12:15:01.1230"); + cout << " " << t1->EtString() << " >= " << t4->EtString() << " = "; + cout << (*t1 >= *t4) << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + + try { + cout << endl; + cout << setprecision(9); + cout << " Test of Isis::iTime operator<= member" << endl; + string test = "2003/01/02 12:15:01.1234"; + Isis::iTime *t1 = new Isis::iTime (test); + test = "2003/01/02 12:15:01.1234"; + Isis::iTime *t2 = new Isis::iTime (test); + cout << " " << t1->EtString() << " <= " << t2->EtString() << " = "; + cout << (*t1 <= *t2) << endl; + Isis::iTime *t3 = new Isis::iTime ("2003/01/02 12:15:01.12345"); + cout << " " << t1->EtString() << " <= " << t3->EtString() << " = "; + cout << (*t1 <= *t3) << endl; + Isis::iTime *t4 = new Isis::iTime ("2003/01/02 12:15:01.1230"); + cout << " " << t1->EtString() << " <= " << t4->EtString() << " = "; + cout << (*t1 <= *t4) << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + + + try { + cout << endl; + cout << setprecision(9); + cout << " Test of Isis::iTime operator> member" << endl; + string test = "2003/01/02 12:15:01.1234"; + Isis::iTime *t1 = new Isis::iTime (test); + test = "2003/01/02 12:15:01.1234"; + Isis::iTime *t2 = new Isis::iTime (test); + cout << " " << t1->EtString() << " > " << t2->EtString() << " = "; + cout << (*t1 > *t2) << endl; + Isis::iTime *t3 = new Isis::iTime ("2003/01/02 12:15:01.12345"); + cout << " " << t1->EtString() << " > " << t3->EtString() << " = "; + cout << (*t1 > *t3) << endl; + Isis::iTime *t4 = new Isis::iTime ("2003/01/02 12:15:01.1230"); + cout << " " << t1->EtString() << " > " << t4->EtString() << " = "; + cout << (*t1 > *t4) << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + + try { + cout << endl; + cout << setprecision(9); + cout << " Test of Isis::iTime operator< member" << endl; + string test = "2003/01/02 12:15:01.1234"; + Isis::iTime *t1 = new Isis::iTime (test); + test = "2003/01/02 12:15:01.1234"; + Isis::iTime *t2 = new Isis::iTime (test); + cout << " " << t1->EtString() << " < " << t2->EtString() << " = "; + cout << (*t1 < *t2) << endl; + Isis::iTime *t3 = new Isis::iTime ("2003/01/02 12:15:01.12345"); + cout << " " << t1->EtString() << " < " << t3->EtString() << " = "; + cout << (*t1 < *t3) << endl; + Isis::iTime *t4 = new Isis::iTime ("2003/01/02 12:15:01.1230"); + cout << " " << t1->EtString() << " < " << t4->EtString() << " = "; + cout << (*t1 < *t4) << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + + try { + cout << endl; + cout << setprecision(9); + cout << " Test of Isis::iTime operator!= member" << endl; + string test = "2003/01/02 12:15:01.1234"; + Isis::iTime *t1 = new Isis::iTime (test); + test = "2003/01/02 12:15:01.1234"; + Isis::iTime *t2 = new Isis::iTime (test); + cout << " " << t1->EtString() << " != " << t2->EtString() << " = "; + cout << (*t1 != *t2) << endl; + Isis::iTime *t3 = new Isis::iTime ("2003/01/02 12:15:01.12345"); + cout << " " << t1->EtString() << " != " << t3->EtString() << " = "; + cout << (*t1 != *t3) << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + + try { + cout << endl; + cout << setprecision(9); + cout << " Test of Isis::iTime operator== member" << endl; + string test = "2003/01/02 12:15:01.1234"; + Isis::iTime *t1 = new Isis::iTime (test); + test = "2003/01/02 12:15:01.1234"; + Isis::iTime *t2 = new Isis::iTime (test); + cout << " " << t1->EtString() << " == " << t2->EtString() << " = "; + cout << (*t1 == *t2) << endl; + Isis::iTime *t3 = new Isis::iTime ("2003/01/02 12:15:01.12345"); + cout << " " << t1->EtString() << " == " << t3->EtString() << " = "; + cout << (*t1 == *t3) << endl; + } + catch (Isis::iException &error) { + error.Report (false); + } + + + + + +} + + + diff --git a/isis/src/base/tsts/CropCam2map/Makefile b/isis/src/base/tsts/CropCam2map/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d3586d0247164c88dc8b8980a6e5eabba63461e4 --- /dev/null +++ b/isis/src/base/tsts/CropCam2map/Makefile @@ -0,0 +1,16 @@ +APP1NAME = crop +APP2NAME = cam2map + +labels.txt.IGNORELINES = ByteOrder StartByte Bytes + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APP1NAME) from= $(INPUT)/lua0825f.cub \ + to= $(OUTPUT)/cropTruth.cub \ + sample=13 nsamples=100 \ + line=40 nlines=100 > /dev/null; + $(APP2NAME) from= $(OUTPUT)/cropTruth.cub \ + to= $(OUTPUT)/CropCam2mapTruth.cub \ + > /dev/null; + catlab from=$(OUTPUT)/CropCam2mapTruth.cub > $(OUTPUT)/labels.pvl; diff --git a/isis/src/base/tsts/CropEnlargeCam2map/Makefile b/isis/src/base/tsts/CropEnlargeCam2map/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ebdfb31fc78ec707eecc035b3d33b7bfafc35897 --- /dev/null +++ b/isis/src/base/tsts/CropEnlargeCam2map/Makefile @@ -0,0 +1,18 @@ +APP1NAME = crop +APP2NAME = enlarge +APP3NAME = cam2map + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APP1NAME) from= $(INPUT)/lua0825f.cub \ + to= $(OUTPUT)/cropTruth.cub \ + sample=15 nsamples=150 \ + line=50 nlines=150 > /dev/null; + $(APP2NAME) from= $(OUTPUT)/cropTruth.cub \ + to= $(OUTPUT)/CropEnlargeTruth.cub \ + interp=nearestneighbor sscale=2 lscale=2 > /dev/null; + $(APP3NAME) from= $(OUTPUT)/CropEnlargeTruth.cub \ + to= $(OUTPUT)/CropEnlargeCam2mapTruth.cub \ + > /dev/null; + catlab from=$(OUTPUT)/CropEnlargeCam2mapTruth.cub > $(OUTPUT)/labels.pvl; diff --git a/isis/src/base/tsts/CropReduceCam2map/Makefile b/isis/src/base/tsts/CropReduceCam2map/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..26d634158313882444c327e8bf32ebd085c1ce3b --- /dev/null +++ b/isis/src/base/tsts/CropReduceCam2map/Makefile @@ -0,0 +1,20 @@ +APP1NAME = crop +APP2NAME = reduce +APP3NAME = cam2map + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APP1NAME) from= $(INPUT)/lua0825f.cub \ + to= $(OUTPUT)/cropTruth.cub \ + sample=15 nsamples=200 \ + line=50 nlines=200 > /dev/null; + $(APP2NAME) from= $(OUTPUT)/cropTruth.cub \ + to= $(OUTPUT)/CropReduceTruth.cub \ + mode=total \ + ons=150 onl=150 > /dev/null; + $(APP3NAME) from= $(OUTPUT)/CropReduceTruth.cub \ + to= $(OUTPUT)/CropReduceCam2mapTruth.cub \ + > /dev/null; + catlab from=$(OUTPUT)/CropReduceCam2mapTruth.cub \ + > $(OUTPUT)/labels.pvl; diff --git a/isis/src/base/tsts/EnlargeCropCam2map/Makefile b/isis/src/base/tsts/EnlargeCropCam2map/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5f89b3619dbbd1350e9b4928c09d8ed4b8483e19 --- /dev/null +++ b/isis/src/base/tsts/EnlargeCropCam2map/Makefile @@ -0,0 +1,20 @@ +APP1NAME = enlarge +APP2NAME = crop +APP3NAME = cam2map + +labels.txt.IGNORELINES = ByteOrder StartByte Bytes + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APP1NAME) from= $(INPUT)/lua0825f.cub \ + to= $(OUTPUT)/enlargeTruth.cub \ + interp=nearestneighbor sscale=1.5 lscale=1.5 > /dev/null; + $(APP2NAME) from= $(OUTPUT)/enlargeTruth.cub \ + to= $(OUTPUT)/EnlargeCropTruth.cub \ + sample=50 nsamples=200 \ + line=100 nlines=200 > /dev/null; + $(APP3NAME) from= $(OUTPUT)/EnlargeCropTruth.cub \ + to= $(OUTPUT)/EnlargeCropCam2mapTruth.cub \ + > /dev/null; + catlab from=$(OUTPUT)/EnlargeCropCam2mapTruth.cub > $(OUTPUT)/labels.pvl; diff --git a/isis/src/base/tsts/Makefile b/isis/src/base/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..016388fc898d8c89f380cae1fd08942c29611582 --- /dev/null +++ b/isis/src/base/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-42s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/tsts/ReduceCropCam2map/Makefile b/isis/src/base/tsts/ReduceCropCam2map/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..04d52705ce8230edf71a5c77b879dc3fbeb57455 --- /dev/null +++ b/isis/src/base/tsts/ReduceCropCam2map/Makefile @@ -0,0 +1,18 @@ +APP1NAME = reduce +APP2NAME = crop +APP3NAME = cam2map + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APP1NAME) from= $(INPUT)/lua0825f.cub \ + to= $(OUTPUT)/reduceTruth.cub \ + mode=scale sscale=2.0 lscale=2.0 > /dev/null; + $(APP2NAME) from= $(OUTPUT)/reduceTruth.cub \ + to= $(OUTPUT)/ReduceCropTruth.cub \ + sample=10 nsamples=50 \ + line=10 nlines=50 > /dev/null; + $(APP3NAME) from= $(OUTPUT)/ReduceCropTruth.cub \ + to= $(OUTPUT)/ReduceCropCam2mapTruth.cub \ + > /dev/null; + catlab from=$(OUTPUT)/ReduceCropCam2mapTruth.cub > $(OUTPUT)/labels.pvl; diff --git a/isis/src/cassini/Makefile b/isis/src/cassini/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/cassini/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/cassini/apps/Makefile b/isis/src/cassini/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/cassini/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/cassini/apps/ciss2isis/Makefile b/isis/src/cassini/apps/ciss2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/cassini/apps/ciss2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/cassini/apps/ciss2isis/assets/N1472853667_1.LBL b/isis/src/cassini/apps/ciss2isis/assets/N1472853667_1.LBL new file mode 100644 index 0000000000000000000000000000000000000000..516437b8b24a586ec4b15107f440ebc4abc6ee6e --- /dev/null +++ b/isis/src/cassini/apps/ciss2isis/assets/N1472853667_1.LBL @@ -0,0 +1,120 @@ +PDS_VERSION_ID = PDS3 + +/* FILE CHARACTERISTICS */ + +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 1048 +FILE_RECORDS = 1028 + +/* POINTERS TO DATA OBJECTS */ + +^IMAGE_HEADER = ("N1472853667_1.IMG",1) +^TELEMETRY_TABLE = ("N1472853667_1.IMG",4) +^LINE_PREFIX_TABLE = ("N1472853667_1.IMG",5) +^IMAGE = ("N1472853667_1.IMG",5) + +/* IDENTIFICATION DATA ELEMENTS */ + +ANTIBLOOMING_STATE_FLAG = "ON" +BIAS_STRIP_MEAN = 17.250490 +CALIBRATION_LAMP_STATE_FLAG = "N/A" +COMMAND_FILE_NAME = "trigger_6510_6.ioi" +COMMAND_SEQUENCE_NUMBER = 6510 +DARK_STRIP_MEAN = 0.000000 +DATA_CONVERSION_TYPE = "TABLE" +DATA_SET_ID = "CO-S-ISSNA/ISSWA-2-EDR-V1.0" +DELAYED_READOUT_FLAG = "NO" +DESCRIPTION = "Incomplete product finalized due to truncated lines." +DETECTOR_TEMPERATURE = -89.243546 +EARTH_RECEIVED_START_TIME = 2004-247T09:54:37.232 +EARTH_RECEIVED_STOP_TIME = 2004-247T09:57:12.966 +ELECTRONICS_BIAS = 112 +EXPECTED_MAXIMUM = (0.756496,1.948700) +EXPECTED_PACKETS = 519 +EXPOSURE_DURATION = 220000.000000 +FILTER_NAME = ("CL1","CL2") +FILTER_TEMPERATURE = -0.468354 +FLIGHT_SOFTWARE_VERSION_ID = "1.3" +GAIN_MODE_ID = "12 ELECTRONS PER DN" +IMAGE_MID_TIME = 2004-246T21:34:26.410 +IMAGE_NUMBER = "1472853667" +IMAGE_OBSERVATION_TYPE = {"SCIENCE"} +IMAGE_TIME = 2004-246T21:36:16.410 +INSTRUMENT_DATA_RATE = 182.783997 +INSTRUMENT_HOST_NAME = "CASSINI ORBITER" +INSTRUMENT_ID = "ISSNA" +INSTRUMENT_MODE_ID = "FULL" +INSTRUMENT_NAME = "IMAGING SCIENCE SUBSYSTEM NARROW ANGLE" +INST_CMPRS_PARAM = ("N/A","N/A","N/A","N/A") +INST_CMPRS_RATE = (3.600000,4.333807) +INST_CMPRS_RATIO = 1.845952 +INST_CMPRS_TYPE = "LOSSLESS" +LIGHT_FLOOD_STATE_FLAG = "ON" +METHOD_DESC = "ISSPT2.5.3;Saturn-Ering;ISS_00ARI_DIFFUSRNG003_PRIME_4" +MISSING_LINES = 511 +MISSING_PACKET_FLAG = "NO" +MISSION_NAME = "CASSINI-HUYGENS" +MISSION_PHASE_NAME = "TOUR PRE-HUYGENS" +OBSERVATION_ID = "ISS_00ARI_DIFFUSRNG003_PRIME" +OPTICS_TEMPERATURE = (0.712693,1.905708) +ORDER_NUMBER = 2 +PARALLEL_CLOCK_VOLTAGE_INDEX = 9 +PREPARE_CYCLE_INDEX = 12 +PRODUCT_CREATION_TIME = 2004-247T10:39:14.000 +PRODUCT_ID = "1_N1472853667.118" +PRODUCT_VERSION_TYPE = "FINAL" +READOUT_CYCLE_INDEX = 10 +RECEIVED_PACKETS = 576 +SENSOR_HEAD_ELEC_TEMPERATURE = 1.633024 +SEQUENCE_ID = "S03" +SEQUENCE_NUMBER = 2 +SEQUENCE_TITLE = "ISS_00ARI_DIFFUSRNG003_PRIME" +SHUTTER_MODE_ID = "NACONLY" +SHUTTER_STATE_ID = "ENABLED" +SOFTWARE_VERSION_ID = "ISS 9.00 02-05-2004" +SPACECRAFT_CLOCK_CNT_PARTITION = 1 +SPACECRAFT_CLOCK_START_COUNT = "1472853447.118" +SPACECRAFT_CLOCK_STOP_COUNT = "1472853667.118" +START_TIME = 2004-246T21:32:36.410 +STOP_TIME = 2004-246T21:36:16.410 +TARGET_DESC = "Saturn-Ering" +TARGET_LIST = "N/A" +TARGET_NAME = "SATURN" +TELEMETRY_FORMAT_ID = "UNK" +VALID_MAXIMUM = (9896,4095) +OBJECT = IMAGE_HEADER + INTERCHANGE_FORMAT = ASCII + HEADER_TYPE = VICAR2 + BYTES = 3144 + RECORDS = 1 + ^DESCRIPTION = "VICAR2.TXT" +END_OBJECT = IMAGE_HEADER +OBJECT = TELEMETRY_TABLE + INTERCHANGE_FORMAT = BINARY + ROWS = 1 + COLUMNS = 2 + ROW_BYTES = 1048 + ^STRUCTURE = "TLMTAB.FMT" + OBJECT = COLUMN + NAME = NULL_PADDING + DATA_TYPE = MSB_UNSIGNED_INTEGER + START_BYTE = 61 + BYTES = 987 + END_OBJECT = COLUMN +END_OBJECT = TELEMETRY_TABLE +OBJECT = LINE_PREFIX_TABLE + INTERCHANGE_FORMAT = BINARY + ROWS = 1024 + COLUMNS = 7 + ROW_BYTES = 24 + ROW_SUFFIX_BYTES = 1024 + ^LINE_PREFIX_STRUCTURE = "PREFIX2.FMT" +END_OBJECT = LINE_PREFIX_TABLE +OBJECT = IMAGE + LINES = 1024 + LINE_SAMPLES = 1024 + SAMPLE_BITS = 8 + SAMPLE_TYPE = SUN_INTEGER + LINE_PREFIX_BYTES = 24 +END_OBJECT = IMAGE +END diff --git a/isis/src/cassini/apps/ciss2isis/assets/N1472853667_1.pvl b/isis/src/cassini/apps/ciss2isis/assets/N1472853667_1.pvl new file mode 100644 index 0000000000000000000000000000000000000000..50345ecd91274907fe0f11a504232dc1d6ffa827 --- /dev/null +++ b/isis/src/cassini/apps/ciss2isis/assets/N1472853667_1.pvl @@ -0,0 +1,97 @@ +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 1024 + Lines = 1024 + Bands = 1 + End_Group + + Group = Pixels + Type = SignedWord + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftName = Cassini-Huygens + InstrumentId = ISSNA + TargetName = Saturn + StartTime = 2004-246T21:32:36.410 + StopTime = 2004-246T21:36:16.410 + ExposureDuration = 220000.0 + AntibloomingStateFlag = On + BiasStripMean = 17.250490 + CompressionRatio = 1.845952 + CompressionType = Lossless + DataConversionType = Table + DelayedReadoutFlag = No + FlightSoftwareVersionId = 1.3 + GainModeId = 12 + GainState = 3 + ImageTime = 2004-246T21:36:16.410 + InstrumentDataRate = 182.783997 + OpticsTemperature = (0.712693, 1.905708 ) + ReadoutCycleIndex = 10 + ShutterModeId = NacOnly + SummingMode = 1 + InstrumentModeId = Full + SpacecraftClockCount = 1/1472853447.118 + ReadoutOrder = 0 + End_Group + + Group = Archive + DataSetId = CO-S-ISSNA/ISSWA-2-EDR-V1.0 + ProductId = 1_N1472853667.118 + ImageNumber = 1472853667 + End_Group + + Group = BandBin + FilterName = CL1/CL2 + OriginalBand = 1 + Center = 651.065 + Width = 340.923 + End_Group + + Group = Kernels + NaifFrameCode = -82360 + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = Table + Name = "ISS Prefix Pixels" + StartByte = 2163179 + Bytes = 24576 + Records = 1024 + ByteOrder = Lsb + Association = Lines + + Group = Field + Name = OverclockPixels + Type = Double + Size = 3 + End_Group +End_Object + +Object = History + Name = IsisCube + StartByte = 2162689 + Bytes = 490 +End_Object + +Object = OriginalLabel + Name = IsisCube + StartByte = 2187755 + Bytes = 9065 +End_Object +End diff --git a/isis/src/cassini/apps/ciss2isis/assets/images/N1472853667_1.jpg b/isis/src/cassini/apps/ciss2isis/assets/images/N1472853667_1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7cb4e6641e61c274377a4cde7500149b6c48bd7f Binary files /dev/null and b/isis/src/cassini/apps/ciss2isis/assets/images/N1472853667_1.jpg differ diff --git a/isis/src/cassini/apps/ciss2isis/assets/images/ciss2isisGUI.jpg b/isis/src/cassini/apps/ciss2isis/assets/images/ciss2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1d93bf2e7ebd94dc4feaedbd0fe5d82d1347cbc5 Binary files /dev/null and b/isis/src/cassini/apps/ciss2isis/assets/images/ciss2isisGUI.jpg differ diff --git a/isis/src/cassini/apps/ciss2isis/assets/thumbs/N1472853667_1.jpg b/isis/src/cassini/apps/ciss2isis/assets/thumbs/N1472853667_1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0e61a554132ee66953e9142c6b922553936271fc Binary files /dev/null and b/isis/src/cassini/apps/ciss2isis/assets/thumbs/N1472853667_1.jpg differ diff --git a/isis/src/cassini/apps/ciss2isis/assets/thumbs/ciss2isisGUI.jpg b/isis/src/cassini/apps/ciss2isis/assets/thumbs/ciss2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..71b8e71903ef441bac0cc7d166ea86e0cdfe49b9 Binary files /dev/null and b/isis/src/cassini/apps/ciss2isis/assets/thumbs/ciss2isisGUI.jpg differ diff --git a/isis/src/cassini/apps/ciss2isis/ciss2isis.cpp b/isis/src/cassini/apps/ciss2isis/ciss2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de852ea82672afb923c57d0e401c71c08b905c2c --- /dev/null +++ b/isis/src/cassini/apps/ciss2isis/ciss2isis.cpp @@ -0,0 +1,426 @@ +//Source: Cassini ISS Tour VICAR Image Data File and Detatched PDS Label SIS, Tour Version 1.1 December 1, 2004 + +#include "Isis.h" + +#include +#include + +#include "CisscalFile.h" +#include "Cube.h" +#include "Filename.h" +#include "Preference.h" +#include "ProcessImportPds.h" +#include "ProcessByLine.h" +#include "Pvl.h" +#include "SpecialPixel.h" +#include "Stretch.h" +#include "Table.h" +#include "UserInterface.h" +#include "TextFile.h" +#include "iException.h" +#include "iString.h" + + +using namespace std; +using namespace Isis; + +// Function prototypes +double ComputeOverclockAvg(vector pixel); +vector ConvertLinePrefixPixels (unsigned char *data); +Table CreateLinePrefixTable(vector prefixData); +void CreateStretchPairs(); +void FixDns (Buffer &buf); +void TranslateCassIssLabels (Filename &labelFile, Cube *ocube); +//Global variables +string compressionType; +string dataConversionType; +double flightSoftware; +Stretch stretch; +int sumMode; +int validMax; + +void IsisMain () +{ + //PROCESS 1: saves off label, header, and line prefix data ==========================================// + ProcessImportPds p; + Pvl label; + UserInterface &ui = Application::GetUserInterface(); + Filename in = ui.GetFilename("FROM"); + + p.SetPdsFile (in.Expanded(), "", label); + + //Checks if in file is rdr + if( label.HasObject("IMAGE_MAP_PROJECTION") ) { + string msg = "[" + in.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + // Set the output bit type to SignedWord + CubeAttributeOutput &outAtt = ui.GetOutputAttribute("TO"); + outAtt.PixelType (SignedWord); + outAtt.Minimum((double)VALID_MIN2); + outAtt.Maximum((double)VALID_MAX2); + Cube *ocube = p.SetOutputCube(ui.GetFilename("TO"), outAtt); + + TranslateCassIssLabels(in, ocube); + + //Save off header (includes vicar labels and binary telemetry header) + // No need to SetFileHeaderBytes() this is already done by ProcessImportPds automatically + int vicarLabelBytes = label.FindObject("IMAGE_HEADER").FindKeyword("BYTES"); + p.SaveFileHeader(); + + //Save off line prefix data, always 24 bytes of binary prefix per line,see SIS version 1.1 pg 103 + int linePrefixBytes = label.FindObject("IMAGE").FindKeyword("LINE_PREFIX_BYTES"); + p.SetDataPrefixBytes(linePrefixBytes); + p.SaveDataPrefix(); + + //SET PROGRESS TEXT, VALID MAXIMUM PIXEL VALUE, AND CREATE STRETCH IF NEEDED + if (dataConversionType != "Table") { //Conversion Type is 12Bit or 8LSB, only save off overclocked pixels + validMax = 255; + if (dataConversionType == "12Bit") { + p.Progress()->SetText("Image was 12 bit. No conversion needed. \nSaving line prefix data..."); + } + else { //if (dataConversionType == "8LSB") { + p.Progress()->SetText("Image was truncated to 8 least significant bits. No conversion needed. \nSaving line prefix data..."); + } + } + else { //if ConversionType == Table, Use LUT to create stretch pairs for conversion + validMax = 4095; + CreateStretchPairs(); + // Pvl outputLabels; + Pvl *outputLabel = ocube->Label(); + //Adjust Table-encoded values from 8 bit back to 12 bit. + PvlGroup &inst = outputLabel->FindGroup("Instrument",Pvl::Traverse); + double biasStripMean = inst.FindKeyword("BiasStripMean"); + inst.FindKeyword("BiasStripMean").SetValue(stretch.Map(biasStripMean)); + inst.FindKeyword("BiasStripMean").AddComment("BiasStripMean value converted back to 12 bit."); + p.Progress()->SetText("Image was converted using 12-to-8 bit table. \nConverting prefix pixels back to 12 bit and saving line prefix data..."); + } + + p.StartProcess (); + + // Write line prefix data to table in output cube + vector > dataPrefix = p.DataPrefix(); + vector prefixBand0 = dataPrefix.at(0); //There is only one band so the outside vector only contains + // one entry and the inside vector only contains nl entries + Table linePrefixTable = CreateLinePrefixTable(prefixBand0); + ocube->Write (linePrefixTable); + // Compute readout order (roo) and save to output cube's instrument group + unsigned char *header = (unsigned char *) p.FileHeader(); + int roo = *(header+50+vicarLabelBytes)/32 % 2;//**** THIS MAY NEED TO BE CHANGED, + // SEE BOTTOM OF THIS FILE FOR IN DEPTH COMMENTS ON READOUTORDER + PvlGroup &inst = ocube->Label()->FindGroup("Instrument",Pvl::Traverse); + inst.AddKeyword(PvlKeyword("ReadoutOrder",roo)); + p.EndProcess(); + + // PROCESS 2 : Do 8 bit to 12 bit conversion for image ==============================================// + ProcessByLine p2; + string ioFile = ui.GetFilename("TO"); + CubeAttributeInput att; + p2.SetInputCube(ioFile, att, ReadWrite); + //if ConversionType == 12Bit or 8LSB, only save off overclocked pixels + if (dataConversionType == "12Bit") { + p2.Progress()->SetText("Setting special pixels and saving as 16bit..."); + } + else if (dataConversionType == "8LSB") { + p2.Progress()->SetText("Setting special pixels and saving as 16bit..."); + } + //if ConversionType == Table, Use LUT to create stretch pairs for conversion + else { + p2.Progress()->SetText("Converting image pixels back to 12-bit and saving as 16bit..."); + } + p2.StartProcess(FixDns); + p2.EndProcess(); + return; +} + +//call this method after stretch is closed in IsisMain() +// write data into table to save in output cube +// author Jeannie Walldren 2008-08-21 +Table CreateLinePrefixTable(vector prefixData) { + TableField overclockPixels("OverclockPixels", TableField::Double, 3); + //3 columns, first two are overclocked pixels and the third is their average + TableRecord linePrefixRecord; + linePrefixRecord += overclockPixels; + Table linePrefixTable("ISS Prefix Pixels", linePrefixRecord); + linePrefixTable.SetAssociation(Table::Lines); + for (int l=0; l<(int)prefixData.size(); l++) { + unsigned char *linePrefix = (unsigned char *)(prefixData[l]); + linePrefixRecord[0] = ConvertLinePrefixPixels(linePrefix); + linePrefixTable += linePrefixRecord; + } + return linePrefixTable; +} + +//used by CreateLinePrefixTable() to convert prefix data +// author Jeannie Walldren 2008-08-21 +vector ConvertLinePrefixPixels (unsigned char *data) { + Buffer pixelBuf(1, 1, 1, SignedWord); + + vector calibrationPixels; + //Pixel data is MSB, see SIS version 1.1 page 17 + EndianSwapper swapper ("MSB"); + + vector pixel; + //12 is start byte for First Overclocked Pixel Sum in Binary Line Prefix, SIS version 1.1 page 94 + pixel.push_back(swapper.ShortInt(& (data[12]))); + //22 is start byte for Last Overclocked Pixel Sum in Binary Line Prefix, see SIS version 1.1 page 94 + pixel.push_back(swapper.ShortInt(& (data[22]))); + pixel.push_back(ComputeOverclockAvg(pixel)); + for (int i = 0; i < (int)pixel.size(); i++) { + pixelBuf[0] = pixel[i]; + // Do 8 bit to 12 bit conversion for prefix data + FixDns(pixelBuf); + double pix = pixelBuf[0]; + if (pix == NULL8) { + calibrationPixels.push_back(NULL2); + } + else if (pix == LOW_REPR_SAT8) { + calibrationPixels.push_back(LOW_REPR_SAT2); + } + else if (pix == LOW_INSTR_SAT8) { + calibrationPixels.push_back(LOW_INSTR_SAT2); + } + else if (pix == HIGH_INSTR_SAT8) { + calibrationPixels.push_back(HIGH_INSTR_SAT2); + } + else if (pix == HIGH_REPR_SAT8) { + calibrationPixels.push_back(HIGH_REPR_SAT2); + } + else { + calibrationPixels.push_back(pix); + } + } + return calibrationPixels; +} + +// Called in IsisMain() if DataConversionType == Table +// Creates stretch pairs for mapping in Fix Dns +// author Jeannie Walldren 2008-08-21 +void CreateStretchPairs() { + // Set up the strech for the 8 to 12 bit conversion from file + PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory"); + iString missionDir = (string) dataDir["Cassini"]; + Filename *lutFile = new Filename(missionDir + "/calibration/lut/lut.tab"); + CisscalFile *stretchPairs = new CisscalFile(lutFile->Expanded()); + // Create the stretch pairs + double temp1=0, temp2=0; + stretch.ClearPairs(); + for (int i=0; iLineCount(); i++) { + iString line; + stretchPairs->GetLine(line); //assigns value to line + line = line.TrimTail(", \t\n\r"); + while (line.size() > 0) { + line = line.TrimHead(", \t"); + temp2 = line.Token(", \t\n\r").ToDouble(); + stretch.AddPair(temp1,temp2); + temp1++; + } + } + stretchPairs->Close(); + return; +} + +// The input buffer has a raw 16 bit buffer but the values are still 0 to 255. +// We know that 255 (stretched to 4095 if Table converted) is saturated. +// Sky pixels could have valid DN of 0, but missing pixels are also saved as 0, +// so it is impossible to distinguish between them. +// This method is used by ConvertLinePrefixPixels() and IsisMain() for ProcessByLine p2. +// author Jeannie Walldren 2008-08-21 +void FixDns (Buffer &buf) { + for (int i=0; iLabel(); + labelXlater.Auto(*(outputLabel)); + + //Add needed keywords that are not in translation table to cube's instrument group + PvlGroup &inst = outputLabel->FindGroup("Instrument",Pvl::Traverse); + string scc = inputLabel.FindKeyword("SPACECRAFT_CLOCK_CNT_PARTITION"); + scc += "/" + (string) inputLabel.FindKeyword("SPACECRAFT_CLOCK_START_COUNT"); + inst.AddKeyword(PvlKeyword("SpacecraftClockCount",scc)); + + //Add units of measurement to keywords from translation table + double exposureDuration = inst.FindKeyword("ExposureDuration"); + inst.FindKeyword("ExposureDuration").SetValue(exposureDuration, "Milliseconds"); + + int gainModeId = inst.FindKeyword("GainModeId"); + inst.FindKeyword("GainModeId").SetValue(gainModeId, "ElectronsPerDN"); + + PvlKeyword opticsTemp = inst.FindKeyword("OpticsTemperature"); + inst.FindKeyword("OpticsTemperature").SetValue(opticsTemp[0]); + inst.FindKeyword("OpticsTemperature").AddValue(opticsTemp[1], "DegreesCelcius"); + + double instDataRate = inst.FindKeyword("InstrumentDataRate"); + inst.FindKeyword("InstrumentDataRate").SetValue(instDataRate, "KilobitsPerSecond"); + + // initialize global variables + dataConversionType = (string) inst.FindKeyword("DataConversionType"); + sumMode = inst.FindKeyword("SummingMode"); + compressionType = (string) inst.FindKeyword("CompressionType"); + iString fsw((string) inst.FindKeyword("FlightSoftwareVersionId")); + if (fsw == "Unknown") { + flightSoftware = 0.0; + } + else{ + flightSoftware = fsw.ToDouble(); + } + + // create BandBin group + iString filter = inputLabel.FindKeyword("FilterName")[0] + "/" + + inputLabel.FindKeyword("FilterName")[1]; + + string instrumentID = inst.FindKeyword("InstrumentId"); + string cameraAngleDefs; + if (instrumentID.at(3) == 'N') { + cameraAngleDefs = missionDir + "/translations/narrowAngle.def"; + } + else if (instrumentID.at(3) == 'W') { + cameraAngleDefs = missionDir + "/translations/wideAngle.def"; + } + + double center = 0; + double width = 0; + + TextFile cameraAngle(cameraAngleDefs); + int numLines = cameraAngle.LineCount(); + bool foundfilter = false; + for (int i=0; iPutGroup(bandBin); + + PvlGroup kerns("Kernels"); + + if (instrumentID == "ISSNA") { + kerns += PvlKeyword("NaifFrameCode",-82360); + } + else if (instrumentID == "ISSWA") { + kerns += PvlKeyword("NaifFrameCode",-82361); + } + else { + string msg = "CISS2ISIS only imports Cassini ISS narrow "; + msg += "angle or wide angle images"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + ocube->PutGroup(kerns); + + return; +} + + + +// This method is called in ConvertLinePrefixPixels() and is +// modelled after IDL CISSCAL's OverclockAvg() in cassimg_define.pro +// author Jeannie Walldren 2008-08-21 +double ComputeOverclockAvg(vector pixel){ + // overclocks array is corrupt for lossy images (see cassimg_readvic.pro) + + if (compressionType != "Lossy" && flightSoftware < 1.3) { //numberOfOverclocks == 1 + // if Bltype CASSINI-ISS or CAS-ISS2, i.e. flight software version < 1.3 + // then there is only one column of valid overclocks in prefix pixels table, + // the first column contains nulls, so use column 2 as average + return pixel[1]; + } + else{//numberOfOverclocks == 2 + // number of columns of valid overclocks in prefix pixels table is 2 + // for CAS-ISS3 or CAS-ISS4, i.e. flight software version 1.3 or 1.4 + // calculate appropriate average (as in cassimg_define.pro, CassImg::OverclockAvg()) + if (sumMode == 1){ + return ((((double) pixel[0])/2 + ((double) pixel[1])/6)/2); + } + if (sumMode == 2){ + return ((((double)pixel[0]) + ((double) pixel[1])/3)/2); + } + if (sumMode == 4){ + return ((((double) pixel[0]) + ((double) pixel[1]))/2); + } + else return 0; + } +} + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // File header and readout order comments... + // OUR FILE HEADER INCLUDES TWO SECTIONS: + // -The first is the VICAR label (SIS page 52). The number of bytes included here is calculated in the IsisMain() + // -The second is the Binary Label Header, or Binary Telemetry Header(SIS page 52). This contains 60 bytes (SIS page 84) of significant data. + // The READOUT ORDER of an image is the order in which the cameras were read. This is needed for radiometric calibration (CISSCAL). + // The possible values are : + // 0 : Narrow-angle camera was read out first + // 1 : Wide-angle camera was read out first + // IDL CISSCAL FILE CASSIMG_SUBTRACTDARK.PRO LINE 333: + // roo = bh[50]/32 MOD 2 ;Readout order is the 2nd bit of the 51st byte + // According to SIS page 92 (Field=Software, Valid Values), the readout order is index 2 (the THIRD bit) of the byte. + // Normally, we would assume that this was the third bit from the right, but there is some confusion on this matter. + // SIS page 17 says bits and bytes are both "big endian" for pixel data, but doesn't mention whether this includes the binary telemetry table data, + // Reading the first 3 bytes of the binary header and comparing with bit values described in SIS Table 7.3.2, + // if the bytes are read as most significant bit first (left-to-right), each value matches up except summation mode. + // In this case, SIS says they shoud be sum1:01, sum2:10, sum4:11. Actual values are sum1:00, sum2:01, sum4:10. + // The IDL code also appears to be written as though bits are read in this manner, accessing the third bit from the left (32 ~ 00100000). + // Since we haven't found a difinitive answer to this, we are mimicking the IDL code to determine the read out order. + // We have not found an image with roo = 1 as of yet to test this. + // If it is found to be the case that bits are read from left to right in this header, it may be more clear in the + // future to rewrite the line using a logical bitwise &-operator: roo = *(header+50+vicarLabelBytes) & (00100000); + // SOURCES : + // Cassini ISS Tour VICAR Image Data File and Detatched PDS Label SIS, Tour Version 1.1 December 1, 2004 + // IDL cisscal application files: cassimg_subtractdark.pro and linetime.pro + // -Jeannie Walldren 08/06/2008 + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/isis/src/cassini/apps/ciss2isis/ciss2isis.xml b/isis/src/cassini/apps/ciss2isis/ciss2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..b596ebd17af7ace46df91aaca276c4cb145b6b87 --- /dev/null +++ b/isis/src/cassini/apps/ciss2isis/ciss2isis.xml @@ -0,0 +1,194 @@ + + + + + + Import a PDS Cassini ISS image file into Isis + + + + This program will import a PDS Cassini ISS image file into an + Isis cube. Some Cassini files available from PDS contain VICAR labels + THIS PROGRAM ONLY ACCEPTS PDS LABELS. You must specify an + input file which contains PDS labels. Note: Scientists + indicate that zeros may be valid DN values for sky areas of CISS images, + but missing pixels are also assigned a value of zero and there is no known + way to distinguish them. Since the chance of a valid zero DN is so slight, + ciss2isis will replace all zeros with Isis::Null. + + + + + Original version + + + Removed Vicar Support. + Added PDS Cassini ISS support. + + + Added Example + Fixed certain label groups being written to Root + + + Removed unused variables, added StopTime to translation table + + + Checks if input file is rdr. + + Modified application to + save off binary file header and compute read out order, to save off line + prefix data of overclocked pixels with the appropriate overclock average + into a table, and to convert compressed 8bit images to 16bit using a + look-up table. Added keywords, with units where appropriate, to labels. + + Modified to + allow import of images with BandBin filter combinations not found or + commented out in the translation *.def files. Previously, this + circumstance stopped the program and threw an exception. Application now + outputs a warning to the log but still creates the cube. + + + Modified FixDns method and updated documentation. + + + Modified to convert BiasStripMean value back to 12-bit using look up table + for images with DataConversionType of Table. Updated documentation in + ciss2isis.cpp + + + Fixed the reading of Pvl labels twice. + + + + + Insert hyperlinks to section Related Objects and Documents, subsection + Documents. + + + Since zeros may be valid DNs and missing pixels are set to zero, + investigate whether there is a way to distinguish the two. If so, update + FixDns method in cisscal.cpp. + + + + + Cassini + + + + + + + Cassini ISS Software + Interface Specification (SIS) -- + https://cel.jpl.nasa.gov/cedr/home/mcdl.html + + + + + + + + + filename + input + + Input Detached PDS Cassini ISS image label file + + + Use this parameter to select the Cassini PDS Image Label. The file must + contain PDS labels for Cassini ISS data. This can be a detached label file with + pointer to the cube data. + + + *.lbl *.LBL + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + + + + + Using ciss2isis + + + The use of ciss2isis to ingest PDS images and output Isis3 cubes. + + + + from= N1472853667_1.LBL + to= N1472853667_1.cub + + + This example shows the use of ciss2isis create an Isis3 cube from a PDS image. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters + + + + + + + + + + Input PDS label file. + + + This is the detatched label from PDS + + FROM + + + + Output cube label + + + This is the label from the output cube showing th Instrument, BandBin, and + Kernels Keywords imported and the ISS Prefix Pixels Table added. + + TO + + + + + + + Final output image after the conversion + + + Converts from PDS format to a Isis3 cube. + + + TO + + + + + diff --git a/isis/src/cassini/apps/ciss2isis/tsts/Makefile b/isis/src/cassini/apps/ciss2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/cassini/apps/ciss2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/cassini/apps/ciss2isis/tsts/narrowAngle/Makefile b/isis/src/cassini/apps/ciss2isis/tsts/narrowAngle/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..90eff75a126833334678c7bc87b241fb4c4c0205 --- /dev/null +++ b/isis/src/cassini/apps/ciss2isis/tsts/narrowAngle/Makefile @@ -0,0 +1,10 @@ +APPNAME = ciss2isis + +labels.txt.IGNORELINES = Bytes StartByte + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/N1472853667_1.LBL \ + to=$(OUTPUT)/N1472853667_1.truth.cub > /dev/null; + catlab from=$(OUTPUT)/N1472853667_1.truth.cub >& $(OUTPUT)/labels.txt; diff --git a/isis/src/cassini/apps/ciss2isis/tsts/wideAngle/Makefile b/isis/src/cassini/apps/ciss2isis/tsts/wideAngle/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a71c6a58a95a08a4fc79d2bb73b9aa1886d4c276 --- /dev/null +++ b/isis/src/cassini/apps/ciss2isis/tsts/wideAngle/Makefile @@ -0,0 +1,10 @@ +APPNAME =ciss2isis + +labels.txt.IGNORELINES = Bytes StartByte ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/W1472855646_5.LBL \ + TO=$(OUTPUT)/W1472855646_5.truth.cub > /dev/null; + catlab from=$(OUTPUT)/W1472855646_5.truth.cub >& $(OUTPUT)/labels.txt; diff --git a/isis/src/cassini/apps/cisscal/DarkCurrent.cpp b/isis/src/cassini/apps/cisscal/DarkCurrent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8060e3cf26df70449ee4449e121c7b6bfb80f93 --- /dev/null +++ b/isis/src/cassini/apps/cisscal/DarkCurrent.cpp @@ -0,0 +1,1084 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/05/27 21:26:15 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include //use ceiling and floor functions +#include +#include "Application.h" +#include "Brick.h" +#include "CisscalFile.h" +#include "CissLabels.h" +#include "Cube.h" +#include "DarkCurrent.h" +#include "NumericalApproximation.h" +#include "Message.h" +#include "Preference.h" +#include "Progress.h" +#include "Pvl.h" +#include "SpecialPixel.h" +#include "iException.h" +#include "iString.h" + +using namespace std; +namespace Isis { + /** + * Constructs a DarkCurrent object. Sets class variables. + * + * @param cissLab CissLabels object from Cassini ISS cube + * @throws Isis::iException::Pvl If the input image has an + * invalid InstrumentDataRate or SummingMode. + * @internal + * @history 2008-11-05 Jeannie Walldren - Original Version + * @history 2009-05-27 Jeannie Walldren - Updated instrument + * data rate range for telemetry rate of 32. + */ + DarkCurrent::DarkCurrent(Isis::CissLabels &cissLab){ + p_compType = cissLab.CompressionType(); + p_dataConvType = cissLab.DataConversionType(); + p_expDur = cissLab.ExposureDuration(); + p_flightSoftware = cissLab.FlightSoftwareVersion(); + p_gainMode = cissLab.GainModeId(); + p_narrow = cissLab.NarrowAngle(); + p_sum = cissLab.SummingMode(); + + if (cissLab.ReadoutCycleIndex() == "Unknown") { + p_readoutIndex = -999; + } + else{ + p_readoutIndex = cissLab.ReadoutCycleIndex().ToInteger(); + } + + if (p_compType == "NotCompressed") { + p_compRatio = 1.0; + } + else { + p_compRatio = cissLab.CompressionRatio().ToDouble(); + } + + if (cissLab.DelayedReadoutFlag() == "No"){ + p_btsm = 0; + } + else if (cissLab.DelayedReadoutFlag() == "Yes"){ + p_btsm = 1; + } + else{ + p_btsm = -1; + } + + double instDataRate = cissLab.InstrumentDataRate(); + if (instDataRate >= 60.0 && instDataRate <= 61.0) p_telemetryRate = 8; + else if (instDataRate >= 121.0 && instDataRate <= 122.0) p_telemetryRate = 16; + else if (instDataRate >= 182.0 && instDataRate <= 183.0) p_telemetryRate = 24; + else if (instDataRate >= 203.0 && instDataRate <= 204.0) p_telemetryRate = 32; + else if (instDataRate >= 304.0 && instDataRate <= 305.0) p_telemetryRate = 40; + else if (instDataRate >= 365.0 && instDataRate <= 366.0) p_telemetryRate = 48; + else throw iException::Message(iException::Pvl, + "Input file contains invalid InstrumentDataRate. See Software Interface Specification (SIS), Version 1.1, page 31.", + _FILEINFO_); + + p_readoutOrder = cissLab.ReadoutOrder(); + + switch(p_sum.ToInteger()) { + case 1: p_lines = 1024;break; + case 2: p_lines = 512; break; + case 4: p_lines = 256; break; + default: throw iException::Message(iException::Pvl, + "Input file contains invalid SummingMode. See Software Interface Specification (SIS), Version 1.1, page 31.", + _FILEINFO_); + } + p_samples = p_lines; + p_startTime.resize(p_samples); + p_endTime.resize(p_samples); + p_duration.resize(p_samples); + for (int i = 0; i < p_samples; i++) { + p_startTime[i].resize(p_lines); + p_endTime[i].resize(p_lines); + p_duration[i].resize(p_lines); + } + }//end constructor + + + /** + * @brief Compute dark current values to subtract from image + * + * This method computes the dark current DN values to be + * subtracted from each pixel and returns those values in an + * array of the equal dimension to the image. + * + * @returns vector \ \> Final array of + * dark current DNs to be subtracted + * @throws Isis::iException::Pvl If the input image has an + * unknown ReadoutCycleIndex or DelayedReadoutFlag. + * @throws Isis::iException::Pvl If the input image has an + * invalid GainModeId. + * @throws Isis::iException::Math If MakeDarkArray() returns a + * vector of zeros. + * @see MakeDarkArray() + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original Version + * @history 2009-01-26 Jeannie Walldren - Changed declarations + * of 2 dimensional vectors + */ + vector > DarkCurrent::ComputeDarkDN(){//get dark_DN + if(p_readoutIndex == -999){ + throw iException::Message(iException::Pvl, + "Readout cycle index is unknown.", + _FILEINFO_); + } + if(p_btsm == -1) { + throw iException::Message(iException::Pvl, + "Delayed readout flag is unknown.", + _FILEINFO_); + } + vector > dark_e(p_samples), dark_DN(p_samples); + for(unsigned int i = 0; i < dark_e.size(); i++) { + dark_e[i].resize(p_lines); + dark_DN[i].resize(p_lines); + } + + // create new file + dark_e = DarkCurrent::MakeDarkArray(); + int notzero = 0; + for(unsigned int i = 0; i < dark_e.size(); i++){ + for(unsigned int j = 0; j < dark_e[0].size(); j++){ + if(dark_e[i][j] != 0.0){ + notzero++; + } + } + } + if( notzero != 0 ) { + // correct for gain: + double gain2, gainRatio; + if(p_narrow){ + gain2 = 30.27; + switch(p_gainMode){ // GainState()){ + case 215: //gs = 0: + gainRatio = 0.135386; + break; + case 95: //1: + gainRatio = 0.309569; + break; + case 29: //2: + gainRatio = 1.0; + break; + case 12: //3: + gainRatio = 2.357285; + break; + default: throw iException::Message(iException::Pvl, + "Input file contains invalid GainModeId. See Software Interface Specification (SIS), Version 1.1, page 29.", + _FILEINFO_); + } + } + else { + gain2 = 27.68; + switch(p_gainMode){ // GainState()){ + case 215://0: + gainRatio = 0.125446; + break; + case 95://1: + gainRatio = 0.290637; + break; + case 29://2: + gainRatio = 1.0; + break; + case 12://3: + gainRatio = 2.360374; + break; + default: throw iException::Message(iException::Pvl, + "Input file contains invalid GainModeId. See Software Interface Specification (SIS), Version 1.1, page 29.", + _FILEINFO_); + } + } + for(unsigned int i = 0; i < dark_e.size(); i++){ + for(unsigned int j = 0; j < dark_e[0].size(); j++){ + dark_DN[i][j] = (dark_e[i][j] /(gain2/gainRatio)); + } + } + return dark_DN; + } + else { + throw iException::Message(iException::Math, + "Error in dark simulation; dark array conatains all zeros.", + _FILEINFO_); + } + }//end ComputeDarkDN + + + /** + * @brief Compute time spent on CCD for given line + * + * Compute the line-time from light-flood erase to read out for a + * given image line. Returns the real seconds that the given + * line spends on the CCD. The parameter lline must be + * between 1 and 1024. + * + * @param lline Current line should range from 1 to 1024 + * @returns double Time in seconds spent on CCD for given + * line + * @throws Isis::iException::Programmer If the input parameter is + * out of valid range. + * @throws Isis::iException::Pvl If the input image contains an + * invalid number of lines. + * @throws Isis::iException::Pvl If the input image has an + * invalid ReadoutCycleIndex. + * @internal + * @history 2008-11-05 Jeannie Walldren - Original Version + * @history 2009-05-27 Jeannie Walldren - Updated with new idl + * cisscal version, 3.6, linetime code. + */ + double DarkCurrent::ComputeLineTime(int lline){ //returns the time for this line, takes the line number + // this method mimics linetime.pro from idl's cisscal program + double fsw; + if(p_flightSoftware == "Unknown") { + fsw = 0.0; + } + else fsw = p_flightSoftware.ToDouble(); + + double linetime; + double tlm = p_telemetryRate/8; + // updated idl code - change t0 initial value: + double t0 = p_expDur/1000 + 0.020; //time from erase to first line + t0 = t0 + 0.68*(p_lines - lline)/((double) p_lines); + //time due to 680ms erase + int line = lline-1; //lline is from 1 to 1024 => line is from 0 to 1023 + if (line < 0 || line > 1023){ + iString msg = "DarkCurrent: For ComputeLineTime(lline), lline must be between 1 and 1024."+iString(lline)+" out of range"; + throw iException::Message(iException::Programmer,msg.c_str() , _FILEINFO_); + } + + double r1 = 0; + if(p_compType == "Lossy" ) { + switch(p_lines) { + case 256: r1 = 89.754; break; + case 512: r1 = 110.131; break; + case 1024: r1 = 201.734; break; + default: throw iException::Message(iException::Pvl, + "Input file contains invalid number of lines. See Software Interface Specification (SIS), Version 1.1, page 50.", + _FILEINFO_); + } + double linetime = t0 + line/r1; + return linetime; + } + double data; + if (p_dataConvType == "12Bit"){ + data = 16.0; + } + else { + data = 8.0; + } + + double correction = 1.0; + // Telemetry rate factors (0,8,16,24,32,40,48 pps) + // The fastest science packet production rate is 48 packets per second. + // When the camera is creating less packets per second, it can have more + // time to service the CCD. This can lead to a faster readout. This + // effect is mostly seen in full or non compressed modes. + + double r0; + if (p_compType == "NotCompressed"){ + // Non-compressed modes + // The following non-compressed rates were measured in ITL tests at 48 + // packets per second. Rates are specified in lines per second. The + // values are for full, sum2 and sum4 modes. Flight software timing + // is accurate to 5ms, so rates are specified to 2 decimal places. + + // Ratio of rate for FSW 1.4 vs 1.3 (EGSE tests at 48 and 24pps) + + double rate_nc = 0; + double telem_nc = 0; + double telem_nc0 = 0; + if(p_dataConvType == "12Bit") { // not converted + switch(p_lines) { + case 1024: { // full, not converted + rate_nc = 67.49; + if(fsw >= 1.4) { + correction = 1.0027; + } + telem_nc0 = 1.0161; + switch(p_telemetryRate) { + case 8: telem_nc = 1.0128; break; + case 16: telem_nc = 1.0095; break; + case 24: telem_nc = 1.0082; break; + case 32: telem_nc = 1.0031; break; + case 40: telem_nc = 1.0033; break; + case 48: telem_nc = 1.0; break; + } + break; + } + case 512: { // sum2, not converted + rate_nc = 85.11; + if(fsw >= 1.4) { + correction = 1.0073; + } + telem_nc0 = 1.0297; + switch(p_telemetryRate) { + case 8: telem_nc = 1.0296; break; + case 16: telem_nc = 1.0252; break; + case 24: telem_nc = 1.0148; break; + case 32: telem_nc = 1.0114; break; + case 40: telem_nc = 1.0071; break; + case 48: telem_nc = 1.0; break; + } + break; + } + case 256: { // sum4, not converted + rate_nc = 142.54; + if(fsw >= 1.4) { + correction = 1.0087; + } + telem_nc0 = 1.0356; + switch(p_telemetryRate) { + case 8: telem_nc = 1.0320; break; + case 16: telem_nc = 1.0260; break; + case 24: telem_nc = 1.0201; break; + case 32: telem_nc = 1.0128; break; + case 40: telem_nc = 1.0057; break; + case 48: telem_nc = 1.0; break; + } + break; + } + } + } + else{ // converted + switch(p_lines){ + case 1024: { // full, converted + rate_nc = 71.96; + if(fsw >= 1.4){ + correction = 1.0016; + } + telem_nc0 = 1.0194; + switch(p_telemetryRate) { + case 8: telem_nc = 1.0148; break; + case 16: telem_nc = 1.0028; break; + case 24: telem_nc = 1.0011; break; + case 32: telem_nc = 1.0014; break; + case 40: telem_nc = 1.0009; break; + case 48: telem_nc = 1.0; break; + } + break; + } + case 512: { // sum2, converted + rate_nc = 88.99; + if(fsw >= 1.4){ + correction = 1.0042; + } + telem_nc0 = 1.0248; + switch(p_telemetryRate) { + case 8: telem_nc = 1.0219; break; + case 16: telem_nc = 1.0173; break; + case 24: telem_nc = 1.0151; break; + case 32: telem_nc = 1.0097; break; + case 40: telem_nc = 1.0057; break; + case 48: telem_nc = 1.0; break; + } + break; + } + case 256: { // sum4, converted + rate_nc = 152.12; + if(fsw >= 1.4){ + correction = 0.9946; + } + telem_nc0 = 1.0010; + switch(p_telemetryRate) { + case 8: telem_nc = 1.0000; break; + case 16: telem_nc = 0.9970; break; + case 24: telem_nc = 0.9910; break; + case 32: telem_nc = 0.9821; break; + case 40: telem_nc = 0.9763; break; + case 48: telem_nc = 1.0; break; + } + break; + } + } + } + r1 = rate_nc * telem_nc * correction; + r0 = rate_nc * telem_nc0 * correction; + } + else { // Lossy has already returned linetime, so (p_compType == "Lossless") + // Lossless linear model + // The following are least square fits for Lossless modes at 48pps. There is + // a fit for each summation mode and converted and not converted (12bit). + + // RMS of fit 0.255 0.076 0.496 not converted + // RMS of fit 0.172 0.162 0.429 converted + + // Ratio of rate for FSW 1.4 vs 1.3 (EGSE tests at 48 and 24pps) + + double rate0 = 0; + double slope = 0; + double telem_L = 0; + double telem_L0 = 0; + + if(p_dataConvType == "12Bit") { // not converted + switch(p_lines) { + case 1024: { // full, not converted + rate0 = 67.673; + slope = 1.6972; // +/- 0.0102 + + if(fsw >= 1.4) { + correction = 0.9999; + } + telem_L0 = 1.0276; + switch(p_telemetryRate) { + case 8: telem_L = 1.0284; break; + case 16: telem_L = 1.0182; break; + case 24: telem_L = 1.0122; break; + case 32: telem_L = 1.0048; break; + case 40: telem_L = 1.0016; break; + case 48: telem_L = 1.0; break; + } + break; + } + case 512: { // sum2, not converted + rate0 = 90.568; + slope = 0.3671; // +/- 0.0255 + + if(fsw >= 1.4) { + correction = 1.0034; + } + telem_L0 = 1.0030; + switch(p_telemetryRate) { + case 8: telem_L = 0.9979; break; + case 16: telem_L = 0.9933; break; + case 24: telem_L = 0.9854; break; + case 32: telem_L = 0.9884; break; + case 40: telem_L = 1.0023; break; + case 48: telem_L = 1.0; break; + } + break; + } + case 256: { // sum4, not converted + rate0 = 150.593; + slope = 0.4541; // +/-0.0450 + + if(fsw >= 1.4) { + correction = 1.0073; + } + telem_L0 = 1.0011; + switch(p_telemetryRate) { + case 8: telem_L = 0.9976; break; + case 16: telem_L = 0.9894; break; + case 24: telem_L = 0.9864; break; + case 32: telem_L = 1.0000; break; + case 40: telem_L = 1.0000; break; + case 48: telem_L = 1.0; break; + } + break; + } + } + } + else{ // converted + switch(p_lines){ + case 1024: { // full, converted + rate0 = 74.862; + slope = 0.4918; // +/- 0.0069 + if(fsw >= 1.4){ + correction = 1.0019; + } + telem_L0 = 1.0013; + switch(p_telemetryRate) { + case 8: telem_L = 1.0004; break; + case 16: telem_L = 0.9935; break; + case 24: telem_L = 0.9920; break; + case 32: telem_L = 1.0002; break; + case 40: telem_L = 0.9992; break; + case 48: telem_L = 1.0; break; + } + break; + } + case 512: { // sum2, converted + rate0 = 91.429; + slope = 0.4411; // +/- 0.0182 + if(fsw >= 1.4){ + correction = 1.0050; + } + telem_L0 = 1.0013; + switch(p_telemetryRate) { + case 8: telem_L = 0.9950; break; + case 16: telem_L = 1.0000; break; + case 24: telem_L = 1.0000; break; + case 32: telem_L = 1.0000; break; + case 40: telem_L = 1.0001; break; + case 48: telem_L = 1.0; break; + } + break; + } + case 256: { // sum4, converted + rate0 = 152.350; + slope = 0.5417; // +/- 0.0697 + if(fsw >= 1.4){ + correction = 1.0080; + } + telem_L0 = 0.9986; + switch(p_telemetryRate) { + case 8: telem_L = 0.9863; break; + case 16: telem_L = 1.0017; break; + case 24: telem_L = 1.0021; break; + case 32: telem_L = 1.0010; break; + case 40: telem_L = 1.0017; break; + case 48: telem_L = 1.0; break; + } + break; + } + } + } + double ro_ratefit = rate0 + slope*p_compRatio; + r1 = ro_ratefit * telem_L * correction; + r0 = ro_ratefit * telem_L0 * correction; + } + + // Calculation of BIU swap line which occurs upon completion of first packet + // If one or more complete lines can fit into the first packet of 440 words, + // they are moved from the Image Buffer allowing more to be read from the CCD + // before the BIU pause. + // Note: must also account for 4-word line header on each line + double tratio = p_compRatio; + if (p_compType == "Lossless" && tratio < 2.0) { + tratio = 2.0; + } + int fpacket = 440/(4+((int) (p_lines*data/16/tratio))); + int biu_line = fpacket + 1; + + // if camera is opposite of read_out_order (second) + // Calculate number of lines read in early pad of 0.262 seconds + // BIU swap occurs after these number of lines or when + // first science packet is complete (at biu_line) which + // ever is greater + bool second = false; + + if (p_narrow && p_readoutOrder == 1){ + second = true; + } + else if (!p_narrow && p_readoutOrder == 0){ + second = true; + } + + // First line after biu wait is at 0.289 seconds + double biutime = 0.289; + int early_lines = 1; + if (second && p_btsm == 0) { + early_lines = ((int) (0.262*r0)) + 1; + if (early_lines > biu_line) { + biu_line = early_lines; + } + // If there is 0.262 pad before readout window (i.e. second image) + // then biu swap occurs 2 rti later (0.25 sec) + biutime = 0.539; + } + + double rate; + if(p_lines < 1024 ) { + rate = r1; + if(p_btsm == 1) { + rate = r0; // No science packet rate + } + if(p_btsm == 0 && line >= biu_line && fsw < 1.4) { + linetime = t0 + biutime + (line-biu_line)/rate; + } + else{ + linetime = t0 + line/rate; + } + return linetime; + } + // Only FULL images can fill image buffer and cause r2 rate + double r2 = 3.5989*tlm; // ITL measured + if (p_dataConvType != "12Bit"){ + r2 = 7.1989*tlm; // ITL measured + } + // For Lossless, r2 depends on compression ratio: but not faster than r1. + + if (p_compType == "Lossless"){ + // r2 = cdsr * lines per packet + // lines per packet = data words per packet / data words per line + // data words per packet = (440 * 2% + 467 * 98%) - 4 (line header) = 462.46 + // data words per line = 4 (line header) + (1024 or 512)/tratio + r2 = p_telemetryRate * 462.46 / (4.0 + 1024.0 * data / 16.0 / tratio); + } + if (r1 < r2){ + r2 = r1; + } + // Due to bug, FSW < 1.4 did not use 4K words of image buffer + int buffer; + if (fsw < 1.4) { + buffer = 336; + } + else { + buffer = 340; + } + if (p_dataConvType != "12Bit") { + buffer = 2 * buffer; + } + // Stores 2 compressed lines into one + if (p_compType == "Lossless") { + buffer = 2*buffer; + } + // Due to bug, FSW < 1.4 declared image buffer full with one free line + if (fsw < 1.4) { + buffer = buffer - 1; + } + // Now treat more complicated 1x1 case. + int line_break; + if(p_btsm == 0) { + int inbuffer; + if (fsw >= 1.4){ + // Calculate line break + // Transmit starts at biutime after readout starts + // after early_lines initially read before biutime + // buffer has buffer-inbuffer left to fill + early_lines = ((int)(biutime*r0)) + 1; + if(early_lines > fpacket) { + inbuffer = early_lines - fpacket; + } + else inbuffer = 0; + if (r2 >= r1) { + line_break = 1024; + } + else { + line_break = early_lines + ((int) (r1*(buffer-inbuffer)/(r1-r2))) + 1; + } + linetime = t0 + line/r1; + if (line > line_break) { + linetime = t0 + line_break/r1 + (line-line_break)/r2; + } + } + else{ + // Calculate line break + // Transmit starts and readout resumes at biutime + // after biu_lines initially read before biutime + // fpacket lines in 1st packet, max(early_lines-fpacket,0) in buffer + if(early_lines > fpacket) { + inbuffer = early_lines - fpacket; + } + else { + inbuffer = 0; + } + + if (r2 >= r1) { + line_break = 1024; + } + else { + line_break = biu_line + ((int) (r1*(buffer-inbuffer)/(r1-r2))) + 1; + } + linetime = t0 + line/r1; + if(line >= biu_line && line <= line_break ) { + linetime = t0 + biutime + (line-biu_line)/r1; + } + if(line > line_break ){ + linetime = t0 + biutime + (line_break-biu_line)/r1 + (line-line_break)/r2; + } + } + } + else { // p_btsm == 1 + // t1 is amount of time botsim image waits for first image readout window + // t1 only depends on readout index and telem rate: + // t1 is first camera readout window plus pad plus biu swap + int readout; + switch((int) p_readoutIndex/4){ + case 0: readout = 50; break; + case 1: readout = 25; break; + case 2: readout = 14; break; + case 3: readout = 6; break; + default: throw iException::Message(iException::Pvl, + "Input file contains invalid ReadoutCycleIndex. See Software Interface Specification (SIS), Version 1.1, page 40.", + _FILEINFO_); + } + double t1; + if (readout*(6.0/((double) (tlm))) - ((int) readout*(6.0/((double) (tlm)))) < .5) { + t1 = floor(readout*(6.0/((double) (tlm)))) + 0.539; + } + else{ + t1 = ceil(readout*(6.0/((double) (tlm)))) + 0.539; + } + linetime = t0 + line/r0; + int line_break = buffer + fpacket + 1; // Full buffer + // NotCompressed 12Bit always stops and waits when buffer filled + if (p_dataConvType == "12Bit" && p_compType == "NotCompressed") { + if (line >= line_break){ + linetime = t0 + t1 + (line-line_break)/r2; + } + return linetime; + } + // Line at which transmission starts + // Reading stops during BIU swap (0.25 sec) for FSW < 1.4 + int trans_line; + double biu_swap; + if (fsw < 1.4) { + trans_line = ((int) ((t1-0.25)*r0)) + 1; + biu_swap = 0.25; + } + else { + trans_line = ((int) (t1*r0)) + 1; + biu_swap = 0.0; + } + // NOTCOMP TABLE/8LSB may start reading out before buffer is filled + // LOSSLESS 12BIT may start reading out before buffer is filled + // If buffer is filled first, rest is read out at r2 + // If t0+t1 occurs first then read continues at r1 until filled, then at r2 + if ( (p_dataConvType != "12Bit" && p_compType == "NotCompressed") + || (p_dataConvType == "12Bit" && p_compType == "Lossless") ) { + if (trans_line >= line_break) { + if (line >= line_break){ + linetime = t0 + t1 + (line-line_break)/r2; // waits + } + } + else { + if (r2 >= r1) { + line_break = 1024; + } + else{ + line_break = trans_line + ((int) ((line_break-trans_line)*r1/(r1-r2))) + 1; + } + if (line > trans_line){ + linetime = t0 + trans_line/r0 + (line-trans_line)/r1 + biu_swap; + } + if (line > line_break) { + linetime = t0 + trans_line/r0 + (line_break-trans_line)/r1 + (line-line_break)/r2 + biu_swap; + } + } + return linetime; + } + // LOSSLESS with 8LSB or TABLE fits in image memory + if (p_dataConvType != "12Bit" && p_compType == "LOSSLESS" && line > trans_line) { + linetime = t0 + trans_line/r0 + (line-trans_line)/r1 + biu_swap; + } + } + return linetime; + }// end ComputeLineTime + + + + /** + * @brief Find dark current files for this image. + * + * Determines which dark parameters file and bias distortion + * table, if any, should be used for this image and assigns these + * filenames to p_dparamfile and p_bdpath, respectively. These + * are dependent on the Instrument ID (ISSNA or ISSWA) and + * Instrument Mode ID (Full, Sum2, or Sum4). + * + * @see DarkParameterFile() + * @see BiasDistortionTable() + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original Version + */ + void DarkCurrent::FindDarkFiles(){ + // Get the directory where the CISS darkcurrent directory is + PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory"); + iString missionDir = (string) dataDir["Cassini"]; + iString darkDir(missionDir+"/calibration/darkcurrent/"); + + iString instrumentId (""); + + if(p_narrow){ + instrumentId += "nac"; + p_bdpath = darkDir + "nac_bias_distortion.tab"; + } + else { + instrumentId += "wac"; + } + iString instModeId(""); + if(p_sum.ToInteger() > 1 ){ + instModeId = instModeId + "sum" + p_sum; + } + else{ + instModeId += "full"; + } + p_dparamfile = darkDir + instrumentId + "_median_dark_parameters" + "?????" + "." + instModeId + ".cub"; + p_dparamfile.HighestVersion(); + return; + }//end FindDarkFiles + + + /** + * Computes begin time, end time, and duration for each pixel of + * the image. + * + * @see ComputeLineTime() + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original Version + */ + void DarkCurrent::ComputeTimeArrays(){ + // this method mimics get_line_times method of cassimg_subtractdark.pro from idl's cisscal program + int numberNegTime = 0; + vector timeToRead(p_lines); + for(int i = 0; i < p_lines; i++ ){ + timeToRead[i] = ComputeLineTime(i+1); + if (timeToRead[i] < 0){ + numberNegTime++; + } + } + if (numberNegTime > 0 ) return; + for(int i = 0;i < p_lines; i++){ + for(int j = 0; j <= i; j++){ + p_endTime[i][j] = timeToRead[i-j]; + } + for(int j = 0; j <= i; j++){ + if (j < i ){ + p_startTime[i][j] = p_endTime[i][j+1]; + } + else { + p_startTime[i][j] = 0.0; + } + p_duration[i][j] = p_endTime[i][j]-p_startTime[i][j]; + } + } + for (int i = 0; i < p_lines; i++) { + for(int j = 0; j < p_samples; j++) { + if (p_duration[i][j] <= 0) { + p_duration[i][j] = 0; + //I belive this is equivalent to the IDL code : + // p_duration(*,*) = p_duration(*,*) > 0.0 + } + } + } + for (int i = 0; i < p_lines; i++) { + for(int j = 0; j < p_samples; j++) { + p_endTime[i][j] = p_startTime[i][j] + p_duration[i][j]; + } + } + return; + }//end ComputeTimeArrays + + + /** + * @brief Creates dark array + * This method reads in the coefficients from the dark + * parameters file, calls MakeManyLineDark() to create dark_e, + * removes artifacts of this array be taking the median of every + * 5 values, and corrects for the average bias distortion at the + * beginning of each line. + * + * @returns vector \ \> Secondary dark + * array removed of artifacts and corrected for average + * bias distortion. + * @throws Isis::iException::Io If the dark parameter file or + * bias distortion table is not found. + * @throws Isis::iException::Io If p_startTime equals p_endTime + * for all pixels. + * @see FindDarkFiles() + * @see ComputeTimeArrays() + * @see MakeManyLineDark() + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original Version + * @history 2009-01-26 Jeannie Walldren - Changed declarations + * of 2 dimensional vectors + */ + vector > DarkCurrent::MakeDarkArray(){//return dark_e + // this method mimics makedarkarray method of cassimg_subtractdark.pro from idl's cisscal program + FindDarkFiles(); + if ( !p_dparamfile.Exists()) { + throw iException::Message(iException::Io, + "DarkParameterFile ***" + + p_dparamfile.Expanded() + "*** not found.", _FILEINFO_); + } + if (p_narrow && (!p_bdpath.Exists())) { + throw iException::Message(iException::Io, + "BiasDistortionFile ***" + + p_bdpath.Expanded() + "*** not found.", _FILEINFO_); + } + ComputeTimeArrays();//fill in values for p_startTime, p_endTime, p_duration + int good = 0; + for (int i = 0; i < p_lines; i++) { + for (int j = 0; j < p_samples; j++) { + if (p_startTime[i][j] != p_endTime[i][j]) { + good++; + } + } + } + if( good != 0 ) { + //read the coefficient cube into a Brick + Brick *darkCoefficients; + Cube dparamCube; + dparamCube.Open(p_dparamfile.Expanded()); + darkCoefficients = new Brick(p_samples,p_lines,8,dparamCube.PixelType()); + darkCoefficients->SetBasePosition(1,1,1); + dparamCube.Read(*darkCoefficients); + dparamCube.Close(); + // Assume WAC dark current is 0 for 0.005 ms. This is not the case for + // the NAC where there are negative values near the left edge of the frame: + if( !p_narrow ) { + for(int i = 0; i < p_lines; i++){ + for(int j = 0; j < p_samples; j++){ + (*darkCoefficients)[darkCoefficients->Index(i+1,j+1,1)] = 0.0; + } + } + } + // add functionality for summed images: + vector > dark_e(p_samples), di1(p_samples); + for(unsigned int i = 0; i < dark_e.size(); i++) { + dark_e[i].resize(p_lines); + di1[i].resize(p_lines); + } + + dark_e = MakeManyLineDark(*darkCoefficients); + + // Median-ed dark images have some spikes below the fitted curve. + // These are probably artifacts and the next section removes them. + vector neighborhood(5); + + //replace each value of di1 with the median of neighborhood of 5 values + for(int i = 0; i < p_lines; i++ ){ + for(int j = 0; j < p_samples; j++) { + if (j < 2 || j > (p_samples-3)) { + di1[i][j] = dark_e[i][j]; + } + else{ + for (int n = -2; n < 3; n++) { + neighborhood[n+2] = dark_e[i][j+n]; + } + //sort these five values + sort(neighborhood.begin(),neighborhood.end()); + for(int f = 0; f < 5; f++) { + } + //set equal to median + di1[i][j] = neighborhood[2]; + } + } + } + for (int i = 0; i < p_lines; i++) { + for (int j = 0; j < p_samples; j++) { + if (di1[i][j] - dark_e[i][j] > 10) { + dark_e[i][j] = di1[i][j]; + } + } + } + // correct for the average bias distortion at the beginning of each line: + if( p_narrow ) { + CisscalFile *biasDist = new CisscalFile(p_bdpath.Expanded()); + vector samp, bias_distortion; + for(int i = 0; i < biasDist->LineCount(); i++){ + iString line; + biasDist->GetLine(line); //assigns value to line + line = line.ConvertWhiteSpace(); + line = line.Compress(); + line = line.TrimHead(" "); + if (line == "") { + break; + } + samp.push_back(line.Token(" ").ToDouble()); + bias_distortion.push_back(line.Trim(" ").ToDouble()); + } + biasDist->Close(); + for(int i = 0; i < 21; i++ ){ + for(int j = 0; j < p_lines; j++ ){ + dark_e[i][j] = dark_e[i][j] - bias_distortion[i]; + } + } + } + return dark_e; + } + throw iException::Message(iException::Io, + "StartTime == EndTime for all pixels.", + _FILEINFO_); + }//end MakeDarkArray + + /** + * @brief Creates preliminary dark array from dark parameters + * file and line-time information + * + * Compute one line of a synthetic dark frame from timing tables + * and dark current parameters for each pixel using a spline + * interpretation method and evaluating at the start and end + * times for that pixel. + * + * @param darkBrick Containing the coefficients found in the dark + * parameters file for each pixel. + * + * @returns vector \ \> Preliminary dark + * array using the darkBrick values + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original Version + * @history 2009-01-26 Jeannie Walldren - Changed declarations + * of 2 dimensional vectors + */ + vector > DarkCurrent::MakeManyLineDark(Brick &darkBrick){//returns dark_e + // this method mimics make_manyline_dark method of cassimg_subtractdark.pro from idl's cisscal program + int num_params = 8; + vector > dark(p_samples), v1(num_params); + vector temp(p_samples),tgrid(num_params); + vector c(2), timespan(2); + + for(unsigned int i = 0; i < dark.size(); i++) { + dark[i].resize(p_lines); + } + for (int i = 0; i < num_params; i++) { + v1[i].resize(num_params); + switch(i){ + case 0:tgrid[i] = 0.0; break; + case 1:tgrid[i] = 10.0; break; + case 2:tgrid[i] = 32.0; break; + case 3:tgrid[i] = 100.0; break; + case 4:tgrid[i] = 220.0; break; + case 5:tgrid[i] = 320.0; break; + case 6:tgrid[i] = 460.0; break; + case 7:tgrid[i] = 1200.0; break; + default: tgrid[i] = Null; + } + } + for(int j = 0; j < num_params; j++){ + v1[j][j] = 1.0; + } + Progress progress; + progress.SetText("Computing dark current array..."); + progress.SetMaximumSteps(p_lines); + progress.CheckStatus(); + for (int jline = 0; jline < p_lines; jline++){ + for(int i = 0; i < p_samples; i++) { + temp[i] = darkBrick[darkBrick.Index(i+1,jline+1,1)]; // constant term + } + // sum the contribution from every pixel downstream of jline, including jline + for (int kline = 0; kline <=jline; kline++){ + // derive coefficients so that parameters can be multiplied and added + // rather than interpolated + timespan[0] = p_startTime[jline][kline]; + timespan[1] = p_endTime[jline][kline]; + // Interpolate by fitting a cubic spline to the + // 4 point neighborhood (x[i-1], x[i], x[i+1], x[i+2]) surrounding + // the interval, x[i] <= u < x[i+1]. + NumericalApproximation spline(NumericalApproximation::CubicNeighborhood); + for (int j = 0; j < num_params; j++){ + spline.AddData(tgrid,v1[j]); + //spline.Compute(); + c = spline.Evaluate(timespan); + spline.Reset(); + c[0] = c[1] - c[0]; + if (c[0] != 0.0){ + for(int i = 0; i < p_samples; i++) { + temp[i] = temp[i] + c[0]*darkBrick[darkBrick.Index(i+1,kline+1,j+1)]; + } + } + } + } + for(int i = 0; i < p_samples; i++) { + dark[i][jline] = temp[i]; + } + + progress.CheckStatus(); + } + return dark; + }//end MakeManyLineDark +}//end namespace Isis + diff --git a/isis/src/cassini/apps/cisscal/DarkCurrent.h b/isis/src/cassini/apps/cisscal/DarkCurrent.h new file mode 100644 index 0000000000000000000000000000000000000000..8234958ddac8b6126739b5f43c9440727298a086 --- /dev/null +++ b/isis/src/cassini/apps/cisscal/DarkCurrent.h @@ -0,0 +1,98 @@ +#ifndef DARKCURRENT_H +#define DARKCURRENT_H +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/05/27 21:26:15 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Filename.h" + +using namespace std; + +namespace Isis { + class CissLabels; +/** + * @brief Compute Cassini ISS dark current subtraction + * + * This class was created in order to perform necessary + * calculations for computing the two-dimensional dark current + * array to be subtracted from Cassini ISS images during + * calibration using the Isis cisscal application. + * + * @ingroup Cassini + * @author 2008-11-05 Jeannie Walldren + * @internal + * @history 2008-11-05 Jeannie Walldren - Original Version + * @history 2009-01-26 Jeannie Walldren - Changed declarations + * of 2 dimensional vectors + * @history 2009-05-27 Jeannie Walldren - Added + * p_flightSoftware variable. Updated + * ComputeLineTime() code with algorithm from the new + * version of linetime.pro in idl cisscal 3.6. Fixed + * instrument data rate value in the constructor. + */ + class DarkCurrent { + public: + // implied open file + DarkCurrent (CissLabels &cissLab); + ~DarkCurrent (){}; //!< Empty Destructor + + vector > ComputeDarkDN(); + Filename BiasDistortionTable(){return p_bdpath;}; //! > MakeDarkArray(); + vector > MakeManyLineDark(Brick &darkBrick); + + + int p_lines; //!< Number of lines in the image. + int p_samples; //!< Number of samples in the image. + Filename p_bdpath; //!< Bias distortion table for the image. Only exists for narrow camera images. + Filename p_dparamfile; //!< Dark parameters file for the image. + + //LABEL VARIABLES + int p_btsm; //!< Value dependent upon PvlKeyword DelayedReadoutFlag. Valid values are: "No"=0, "Yes"=1, "Unknown"=-1. Called "botsim" or "btsm" in IDL code. + double p_compRatio; //!< Value of PvlKeyword CompressionRatio from the labels of the image. Called "ratio" in IDL code. + string p_compType; //!< Value of PvlKeyword CompressionType from the labels of the image. Called "comp" in IDL code. + string p_dataConvType; //!< Value of PvlKeyword DataConversionType from the labels of the image. Called "conv" in IDL code. + double p_expDur; //!< Value of PvlKeyword ExposureDuration from the labels of the image. Called "exposure" or "time" in IDL code. + iString p_flightSoftware; //!< Value of PvlKeyword FlightSoftwareVersion from the labels of the image. Called "fsw" in IDL code. + int p_gainMode; //!< Value of PvlKeyword GainModeId from the labels of the image. + double p_instDataRate; //!< Value of PvlKeyword InstrumentDataRate from the labels of the image. + bool p_narrow; //!< Indicates whether the image is from a narrow-angle camera + int p_readoutIndex; //!< Value of PvlKeyword InstrumentDataRate from the labels of the image. Called "rdind" or "roindex" in IDL code. + int p_readoutOrder; //!< Value of PvlKeyword ReadoutOrder from the labels of the image. Valid values are: NAC first = 0, WAC first = 1. Called "roo" in IDL code. + iString p_sum; //!< Summing mode, as found in the labels of the image. This integer is created as an iString so that it may be added to a string. Called "sum" in IDL code. + int p_telemetryRate; //!< Telemetry rate of the image in packets per second. This is dependent on the range of the instrument data rate. Called "cdsr" in IDL code. + + vector > p_startTime; //!< Array of start times for each pixel of the image. + vector > p_endTime; //!< Array of end times for each pixel of the image. + vector > p_duration; //!< Array of durations for each pixel of the image. + }; +}; +#endif + diff --git a/isis/src/cassini/apps/cisscal/Makefile b/isis/src/cassini/apps/cisscal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/cassini/apps/cisscal/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/cassini/apps/cisscal/assets/dataFiles/cisscalStatsEx1.pvl b/isis/src/cassini/apps/cisscal/assets/dataFiles/cisscalStatsEx1.pvl new file mode 100644 index 0000000000000000000000000000000000000000..7e4653b7624633287c23cacea5e910b54decc5fb --- /dev/null +++ b/isis/src/cassini/apps/cisscal/assets/dataFiles/cisscalStatsEx1.pvl @@ -0,0 +1,22 @@ +Group = Results + From = ../OUT/outputCube.cub + Average = 282831015573.66 + StandardDeviation = 58186356748.861 + Variance = 3.38565211170568e+21 + Median = 291049818955.29 + Mode = 327543612837.65 + Skew = -0.42374899413832 + Minimum = -70238740480.0 + Maximum = 860353003520.0 + Sum = 2.96476763582042e+17 + TotalPixels = 1048576 + ValidPixels = 1048247 + OverValidMaximumPixels = 0 + UnderValidMinimumPixels = 0 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 329 +End_Group +End diff --git a/isis/src/cassini/apps/cisscal/assets/dataFiles/cisscalStatsEx2.pvl b/isis/src/cassini/apps/cisscal/assets/dataFiles/cisscalStatsEx2.pvl new file mode 100644 index 0000000000000000000000000000000000000000..ef08a9d4585e4407ebf2ed36488cdf1521fa0e8e --- /dev/null +++ b/isis/src/cassini/apps/cisscal/assets/dataFiles/cisscalStatsEx2.pvl @@ -0,0 +1,22 @@ +Group = Results + From = ../OUT/outputCube.cub + Average = 0.18601354175136 + StandardDeviation = 0.038268258097417 + Variance = 0.0014644595778105 + Median = 0.19141891353271 + Mode = 0.21542031145563 + Skew = -0.42374845760567 + Minimum = -0.046194925904274 + Maximum = 0.56584072113037 + Sum = 194988.13710024 + TotalPixels = 1048576 + ValidPixels = 1048247 + OverValidMaximumPixels = 0 + UnderValidMinimumPixels = 0 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 329 +End_Group +End diff --git a/isis/src/cassini/apps/cisscal/assets/dataFiles/idlcisscalStatsEx1.pvl b/isis/src/cassini/apps/cisscal/assets/dataFiles/idlcisscalStatsEx1.pvl new file mode 100644 index 0000000000000000000000000000000000000000..a50ca2248fcca478a1ac4fc41448875ec28a1b3e --- /dev/null +++ b/isis/src/cassini/apps/cisscal/assets/dataFiles/idlcisscalStatsEx1.pvl @@ -0,0 +1,22 @@ +Group = Results + From = /work1/jwalldren/cisscal/img5/idl.bw.deb.drk.lin.ff.dnfIU.cf.cub + Average = 282894995337.58 + StandardDeviation = 58381773969.834 + Variance = 3.40843153186474e+21 + Median = 290825716418.76 + Mode = 327434385656.97 + Skew = -0.40752724053633 + Minimum = -71193346048.0 + Maximum = 966052282368.0 + Sum = 2.96636902631098e+17 + TotalPixels = 1048576 + ValidPixels = 1048576 + OverValidMaximumPixels = 0 + UnderValidMinimumPixels = 0 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 +End_Group +End diff --git a/isis/src/cassini/apps/cisscal/assets/dataFiles/idlcisscalStatsEx2.pvl b/isis/src/cassini/apps/cisscal/assets/dataFiles/idlcisscalStatsEx2.pvl new file mode 100644 index 0000000000000000000000000000000000000000..fc8d546d52ac5dca3d01577a8e46a0e2088faee2 --- /dev/null +++ b/isis/src/cassini/apps/cisscal/assets/dataFiles/idlcisscalStatsEx2.pvl @@ -0,0 +1,22 @@ +Group = Results + From = /work1/jwalldren/cisscal/img5/idl.bw.deb.drk.lin.ff.dnfIF.cf.cub + Average = 0.18585505771637 + StandardDeviation = 0.038355390338653 + Variance = 0.0014711359680304 + Median = 0.19106536495919 + Mode = 0.21511636189386 + Skew = -0.40752868346466 + Minimum = -0.04677227139473 + Maximum = 0.63467264175415 + Sum = 194883.153 + TotalPixels = 1048576 + ValidPixels = 1048576 + OverValidMaximumPixels = 0 + UnderValidMinimumPixels = 0 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 +End_Group +End diff --git a/isis/src/cassini/apps/cisscal/assets/images/cisscalGuiEx1.jpg b/isis/src/cassini/apps/cisscal/assets/images/cisscalGuiEx1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..21748d8722909b66d5685222797f3f4c43a76e25 Binary files /dev/null and b/isis/src/cassini/apps/cisscal/assets/images/cisscalGuiEx1.jpg differ diff --git a/isis/src/cassini/apps/cisscal/assets/images/cisscalGuiEx2.jpg b/isis/src/cassini/apps/cisscal/assets/images/cisscalGuiEx2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b94a9175f99e50f755f1d894de9ab1477cecfe34 Binary files /dev/null and b/isis/src/cassini/apps/cisscal/assets/images/cisscalGuiEx2.jpg differ diff --git a/isis/src/cassini/apps/cisscal/assets/images/cisscalInput.jpg b/isis/src/cassini/apps/cisscal/assets/images/cisscalInput.jpg new file mode 100644 index 0000000000000000000000000000000000000000..758e3fcfd254d68a5615ea85731a77d388a75bb3 Binary files /dev/null and b/isis/src/cassini/apps/cisscal/assets/images/cisscalInput.jpg differ diff --git a/isis/src/cassini/apps/cisscal/assets/images/cisscalOutputEx1.jpg b/isis/src/cassini/apps/cisscal/assets/images/cisscalOutputEx1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0bef4ebba5974302bbe5c6329d9b361e8f0ddc29 Binary files /dev/null and b/isis/src/cassini/apps/cisscal/assets/images/cisscalOutputEx1.jpg differ diff --git a/isis/src/cassini/apps/cisscal/assets/images/cisscalOutputEx2.jpg b/isis/src/cassini/apps/cisscal/assets/images/cisscalOutputEx2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8432531a1a42bb46be5e14b0d9f230a3dad515b2 Binary files /dev/null and b/isis/src/cassini/apps/cisscal/assets/images/cisscalOutputEx2.jpg differ diff --git a/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalGuiThumbEx1.jpg b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalGuiThumbEx1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..47e27d5a9ee592756081a6a685568c2c817d6321 Binary files /dev/null and b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalGuiThumbEx1.jpg differ diff --git a/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalGuiThumbEx2.jpg b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalGuiThumbEx2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b9e12058a936cf5938eb178e86fff61c50e84eb8 Binary files /dev/null and b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalGuiThumbEx2.jpg differ diff --git a/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalInputThumb.jpg b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalInputThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..574259c8c9cf9842ca8f774b78b2e1abc0636b38 Binary files /dev/null and b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalInputThumb.jpg differ diff --git a/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalOutputThumbEx1.jpg b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalOutputThumbEx1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d5d3f9752eb6689717045a86f03de3992cee9cf0 Binary files /dev/null and b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalOutputThumbEx1.jpg differ diff --git a/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalOutputThumbEx2.jpg b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalOutputThumbEx2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..566b2302f90a0544e51a79b30c745afdc79df9a9 Binary files /dev/null and b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalOutputThumbEx2.jpg differ diff --git a/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalPvlThumbEx1.jpg b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalPvlThumbEx1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df75a720e55ce5764b817728af8b0f04f8964e78 Binary files /dev/null and b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalPvlThumbEx1.jpg differ diff --git a/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalPvlThumbEx2.jpg b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalPvlThumbEx2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e54c96d1293412e04401618019055f5591d45c7e Binary files /dev/null and b/isis/src/cassini/apps/cisscal/assets/thumbs/cisscalPvlThumbEx2.jpg differ diff --git a/isis/src/cassini/apps/cisscal/cisscal.cpp b/isis/src/cassini/apps/cisscal/cisscal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06ab49e9dc269264ee1de7d2ce2109ccd8fd3cbe --- /dev/null +++ b/isis/src/cassini/apps/cisscal/cisscal.cpp @@ -0,0 +1,1617 @@ +#include "Isis.h" +#include // sort, unique +#include +#include +#include //unique +#include // unique +#include +#include +#include +#include "Brick.h" +#include "Buffer.h" +#include "Camera.h" +#include "CisscalFile.h" +#include "CissLabels.h" +#include "Cube.h" +#include "DarkCurrent.h" +#include "Filename.h" +#include "LeastSquares.h" +#include "NumericalApproximation.h" +#include "PolynomialUnivariate.h" +#include "ProcessByLine.h" +#include "Preference.h" +#include "PvlGroup.h" +#include "SpecialPixel.h" +#include "Stretch.h" +#include "Table.h" +#include "UserInterface.h" +#include "iException.h" +#include "iString.h" + +using namespace Isis; +using namespace std; + +// Working functions and parameters +namespace gbl { + //global methods + void BitweightCorrect(Buffer &in); + void Calibrate(vector &in, vector &out); + void ComputeBias(); + void CopyInput(Buffer &in); + void CreateBitweightStretch(Filename bitweightTable); + Filename FindBitweightFile(); + vector OverclockFit(); + void Linearize(); + void FindDustRingParameters(); + Filename FindFlatFile(); + void FindCorrectionFactors(); + void DNtoElectrons(); + void FindShutterOffset(); + void DivideByAreaPixel(); + void FindEfficiencyFactor(string fluxunits); + iString GetCalibrationDirectory(string calibrationType); + + //global variables + CissLabels *cissLab; + Cube *incube; + PvlGroup calgrp; + Stretch stretch; + int numberOfOverclocks; + vector bias; + vector > bitweightCorrected; + //dark subtraction variables + vector > dark_DN; + // flatfield variables + Filename dustFile; + Filename mottleFile; + double strengthFactor; + bool dustCorrection, mottleCorrection, flatCorrection; + //DN to Flux variables + double trueGain; + bool divideByExposure; + Brick *offset; + double solidAngle; + double opticsArea; + double sumFactor; + double efficiencyFactor; + //correction factor variables + double polarizationFactor; + double correctionFactor; +} + +void IsisMain(){ + // Initialize Globals + UserInterface &ui = Application::GetUserInterface(); + gbl::cissLab = new CissLabels(ui.GetFilename("FROM")); + gbl::stretch.ClearPairs(); + gbl::numberOfOverclocks = 0; + gbl::bias.clear(); + gbl::dustFile = ""; + gbl::mottleFile = ""; + gbl::strengthFactor = 1.0; + gbl::dustCorrection = false; + gbl::mottleCorrection = false; + gbl::flatCorrection = false; + gbl::trueGain = 1.0; + gbl::divideByExposure = false; + gbl::offset = 0; // set pointer to null + gbl::solidAngle = 1.0; + gbl::opticsArea = 1.0; + gbl::sumFactor = 1.0; + gbl::efficiencyFactor = 1.0; + gbl::polarizationFactor = 1.0; + gbl::correctionFactor = 1.0; + + // Set up our ProcessByLine + ProcessByLine firstpass; + // initialize global input cube variable + gbl::incube = firstpass.SetInputCube("FROM"); + // resize 2dimensional vectors + gbl::bitweightCorrected.resize(gbl::incube->Samples()); + gbl::dark_DN.resize(gbl::incube->Samples()); + for(unsigned int i = 0; i < gbl::bitweightCorrected.size(); i++) { + gbl::bitweightCorrected[i].resize(gbl::incube->Lines()); + gbl::dark_DN[i].resize(gbl::incube->Lines()); + } + + // Add the radiometry group + gbl::calgrp.SetName("Radiometry"); + + // BITWEIGHT CORRECTION + gbl::calgrp += PvlKeyword("BitweightCorrectionPerformed","Yes"); + gbl::calgrp.FindKeyword("BitweightCorrectionPerformed").AddComment("Bitweight Correction Parameters"); + // Bitweight correction is not applied to Lossy-compressed or Table-converted images + if(gbl::cissLab->CompressionType() == "Lossy"){ + gbl::calgrp.FindKeyword("BitweightCorrectionPerformed").SetValue("No: Lossy compressed"); + gbl::calgrp += PvlKeyword("BitweightFile","Not applicable: No bitweight correction"); + firstpass.Progress()->SetText("Lossy compressed: skip bitweight correction as insignificant.\nCopying input image..."); + firstpass.StartProcess(gbl::CopyInput); + firstpass.EndProcess(); + } + else if(gbl::cissLab->DataConversionType() == "Table"){ + gbl::calgrp.FindKeyword("BitweightCorrectionPerformed").SetValue("No: Table converted"); + gbl::calgrp += PvlKeyword("BitweightFile","Not applicable: No bitweight correction"); + firstpass.Progress()->SetText("Table converted: skip bitweight correction as insignificant.\nCopying input image..."); + firstpass.StartProcess(gbl::CopyInput); + firstpass.EndProcess(); + } + // Skip bitweight correction for GainState==0, there is no data for this case, + // see ground calibration report 5.1.9 Uneven Bit Weighting + else if(gbl::cissLab->GainState() == 0) { + gbl::calgrp.FindKeyword("BitweightCorrectionPerformed").SetValue("No: No bitweight calibration file for GainState 0."); + gbl::calgrp += PvlKeyword("BitweightFile","Not applicable: No bitweight correction."); + firstpass.Progress()->SetText("No bitweight calibration file for GainState 0: skip bitweight correction.\nCopying input image..."); + firstpass.StartProcess(gbl::CopyInput); + firstpass.EndProcess(); + } + else { // Bitweight correction + Filename bitweightFile = gbl::FindBitweightFile(); + if(!bitweightFile.Exists()) { // bitweight file not found, stop calibration + throw iException::Message(iException::Io, + "Unable to calibrate image. BitweightFile ***" + + bitweightFile.Expanded() + "*** not found.", _FILEINFO_); + } + else{ + gbl::calgrp += PvlKeyword("BitweightFile", bitweightFile.Expanded()); + gbl::CreateBitweightStretch(bitweightFile); + firstpass.Progress()->SetText("Computing bitweight correction..."); + firstpass.StartProcess(gbl::BitweightCorrect); + firstpass.EndProcess(); + } + } + + // Reset the input cube for rest of calibration steps + ProcessByLine secondpass; + CubeAttributeInput att; + //set input cube to "FROM" due to requirements of processbyline that there be at least 1 input buffer + //we are actually using gbl::image as the input + gbl::incube = secondpass.SetInputCube("FROM"); + + //Subtract bias (debias) + gbl::ComputeBias(); + + //Dark current subtraction + try{ + DarkCurrent dark(*gbl::cissLab); + gbl::dark_DN = dark.ComputeDarkDN(); + gbl::calgrp += PvlKeyword("DarkSubtractionPerformed","Yes"); + gbl::calgrp.FindKeyword("DarkSubtractionPerformed").AddComment("Dark Current Subtraction Parameters"); + gbl::calgrp += PvlKeyword("DarkParameterFile",dark.DarkParameterFile().Expanded()); + if(gbl::cissLab->NarrowAngle()) { + gbl::calgrp += PvlKeyword("BiasDistortionTable",dark.BiasDistortionTable().Expanded()); + } + else{ + gbl::calgrp += PvlKeyword("BiasDistortionTable","ISSWA: No bias distortion table used"); + } + } + catch(iException e){ // cannot perform dark current, stop calibration + e.Report(); + throw iException::Message(iException::Pvl, + "Unable to calibrate image. Dark current calculations failed.", + _FILEINFO_); + } + + //Linearity Correction + gbl::Linearize(); + + //Dust Ring Correction + gbl::FindDustRingParameters(); + //Flat Field Correction + Filename flatFile = gbl::FindFlatFile(); + + //DN to Flux Correction + gbl::DNtoElectrons(); + gbl::FindShutterOffset(); + gbl::DivideByAreaPixel(); + gbl::FindEfficiencyFactor(ui.GetString("FLUXUNITS")); + + //Correction Factor + gbl::FindCorrectionFactors(); + if(gbl::flatCorrection) { + secondpass.SetInputCube(flatFile.Expanded(),att); + } + if(gbl::dustCorrection){ + secondpass.SetInputCube(gbl::dustFile.Expanded(),att); + } + if(gbl::mottleCorrection){ + secondpass.SetInputCube(gbl::mottleFile.Expanded(),att); + } + Cube *outcube = secondpass.SetOutputCube("TO"); + secondpass.Progress()->SetText("Calibrating image..."); + outcube->PutGroup(gbl::calgrp); + secondpass.StartProcess(gbl::Calibrate); + secondpass.EndProcess(); + gbl::calgrp.Clear(); + return; + +} //END MAIN + +/** + * This calibration method runs through all calibration steps. + * It takes a vector of input buffers that contains the + * input image and, if needed, the flat field image, the + * dustring correction image, and the mottle correction image. + * The vector of output buffers will only contain one element: + * the output image. + * + * @param in Vector of pointers to input buffers for the second + * process in IsisMain() + * @param out Vector of pointers to output buffer. + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + * @history 2009-05-27 Jeannie Walldren - Added polarization + * factor correction. Updated ConstOffset value per + * new idl cisscal version, 3.6. + */ +void gbl::Calibrate(vector &in, vector &out){ + Buffer *flat = 0; + Buffer *dustCorr = 0; + Buffer *mottleCorr = 0; + if(gbl::flatCorrection) { + flat = in[1]; + } + if(gbl::dustCorrection){ + dustCorr = in[2]; + if(gbl::mottleCorrection){ + mottleCorr = in[3]; + } + } + Buffer &outLine = *out[0]; + //get line index of output + int lineIndex = outLine.Line()-1; + for(unsigned int sampIndex = 0; sampIndex < gbl::bitweightCorrected.size(); sampIndex++){ + if(IsValidPixel(gbl::bitweightCorrected[sampIndex][lineIndex])){ + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + // STEP 1) set output to bitweight corrected values + outLine[sampIndex] = bitweightCorrected[sampIndex][lineIndex]; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + // STEP 2) remove bias (debias) + if(gbl::numberOfOverclocks){ + outLine[sampIndex] = outLine[sampIndex] - gbl::bias[lineIndex]; + } + else { + outLine[sampIndex] = outLine[sampIndex] - gbl::bias[0]; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + // idl cisscal step "REMOVE 2-HZ NOISE" skipped + // -- this is more of a filter than calibration + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + // STEP 3) remove dark current + outLine[sampIndex] = outLine[sampIndex] - gbl::dark_DN[sampIndex][lineIndex]; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + // idl cisscal step "ANTI-BLOOMING CORRECTION" skipped + // -- this is more of a filter than calibration + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + // STEP 4) linearity correction (linearize) + if(outLine[sampIndex] < 0){ + outLine[sampIndex] = (outLine[sampIndex])*(gbl::stretch.Map(0)); + } + else{ + outLine[sampIndex] = (outLine[sampIndex])*(gbl::stretch.Map((int) outLine[sampIndex])); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + // STEP 5) flatfield correction + // 5a1: dust ring correction + if(gbl::dustCorrection){ + outLine[sampIndex] = (outLine[sampIndex]) * ((*dustCorr)[sampIndex]); + // 5a2: mottle correction + if(gbl::mottleCorrection){ + outLine[sampIndex] = (outLine[sampIndex]) * (1 - ((gbl::strengthFactor) * ((*mottleCorr)[sampIndex])/1000.0)); + } + } + // 5b: divide by flats + if(gbl::flatCorrection){ + outLine[sampIndex] = outLine[sampIndex] / ((*flat)[sampIndex]); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + // STEP 6) convert DN to flux + // 6a DN to Electrons + outLine[sampIndex] = outLine[sampIndex] * gbl::trueGain; + // 6b Divide By Exposure Time + // JPL confirm that these values must be subtracted thus: + if(gbl::divideByExposure) { + double exposureTime = gbl::cissLab->ExposureDuration() - (*gbl::offset)[gbl::offset->Index(sampIndex+1,1,1)]; + // IDL documentation: + // Need to develop way to subtract constant offset discussed in + // section 4.3 of Ground Calibration Report. Right now just use 1 ms + // for all cases. + // CORRECTION: New analysis of Vega images points to a value more like + // 2.85 ms (correct to within about 0.05 ms for the NAC, less certain + // for the WAC. Use this until better data available. (12/1/2005 - BDK) + // UPDATE: Used azimuthal ring scans to pin down WAC to around 1.8 ms. + // (1/18/2006 - BDK) + double ConstOffset; + if (gbl::cissLab->InstrumentId() == "ISSNA"){ + ConstOffset = 2.85; + } + else { + ConstOffset = 1.8; + } + exposureTime = exposureTime - ConstOffset; + outLine[sampIndex] = outLine[sampIndex]*1000/exposureTime; // 1000 to scale ms to seconds + } + // 6c Divide By Area Pixel + outLine[sampIndex] = outLine[sampIndex] * gbl::sumFactor / ( gbl::solidAngle * gbl::opticsArea); + // 6d Divide By Efficiency + outLine[sampIndex] = outLine[sampIndex] / gbl::efficiencyFactor; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + // STEP 7) correction factors + outLine[sampIndex] = outLine[sampIndex] / (gbl::correctionFactor * gbl::polarizationFactor); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + } + else{ + outLine[sampIndex] = bitweightCorrected[sampIndex][lineIndex]; + } + } + return; +} + + +//=====4 Bitweight Methods=======================================================================// +// These methods are modelled after IDL CISSCAL's cassimg_bitweightcorrect.pro + +/** + * The purpose of this method is to copy the input to output if + * no bitweight correction occurs. + * + * @param in Input buffer for the first process in IsisMain() + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + * @history 2008-12-22 Jeannie Walldren - Fixed bug in calls + * to resize() method. + * @history 2009-01-26 Jeannie Walldren - Moved resizing of + * 2-dimensional vectors to main method + */ +void gbl::CopyInput(Buffer &in){ + // find line index + int lineIndex = in.Line()-1; + for(int sampIndex = 0; sampIndex < in.size(); sampIndex++){ + // assign input value to image vector + gbl::bitweightCorrected[sampIndex][lineIndex] = in[sampIndex]; + } + return; +} + +/** + * This method is modelled after IDL CISSCAL's + * cassimg_bitweightcorrect.pro. The purpose is to correct the + * image for uneven bit weights. This is done using one of + * several tables developed from the ground calibration + * exercises table depends on InstrumentId, GainModeId, and + * OpticsTemperature. + * + * @param in Input buffer for the first process in IsisMain() + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + * @history 2009-01-26 Jeannie Walldren - Moved resizing of + * 2-dimensional vectors to main method + */ +void gbl::BitweightCorrect(Buffer &in){ + // find line index + int lineIndex = in.Line()-1; + // loop through samples of this line + for(int sampIndex = 0; sampIndex < in.size(); sampIndex++){ + // map bitweight corrected image output values to buffer input values + if(IsValidPixel(in[sampIndex])){ + gbl::bitweightCorrected[sampIndex][lineIndex] = gbl::stretch.Map(in[sampIndex]); + } + //Handle special pixels + else { + gbl::bitweightCorrected[sampIndex][lineIndex] = in[sampIndex]; + } + } + return; +} + + +/** + * This method sets up the strech for the conversion from file. + * It is used by the BitweightCorrect() method to map LUT + * values. + * + * @param bitweightTable Name of the bitweight table for this + * image. + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + */ +void gbl::CreateBitweightStretch(Filename bitweightTable){ + CisscalFile *stretchPairs = new CisscalFile(bitweightTable.Expanded()); + // Create the stretch pairs + double stretch1 = 0, stretch2; + gbl::stretch.ClearPairs(); + for(int i = 0; i < stretchPairs->LineCount(); i++){ + iString line; + stretchPairs->GetLine(line); + line.ConvertWhiteSpace();//convert all \n, \r, \t to spaces + line.Compress();//compresses multiple spaces into single space + line = line.TrimTail(" ");//removes space from end of line + while(line.size() > 0){ + line = line.TrimHead(" ");//removes space before number, if there is one + stretch2 = line.Token(", ").ToDouble();//grabs number before comma or space + gbl::stretch.AddPair(stretch1,stretch2); + stretch1 = stretch1 + 1.0; + } + } + stretchPairs->Close(); + return; +} + +/** + * This method is modelled after IDL CISSCAL's + * cassimg_bitweightcorrect.pro. The purpose is to find the + * look up table file name for this image. + * + * The table to be used depends on: + * Camera NAC or WAC + * GainState 1, 2 or 3 <=> GainModeId 95, 29, or 12 + * Optics temp. -10, +5 or +25 + * + * @return Filename Name of the bitweight file + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + */ +Filename gbl::FindBitweightFile(){ + // Get the directory where the CISS bitweight directory is + iString bitweightName; + + if(gbl::cissLab->NarrowAngle()){ + bitweightName += "nac"; + } + else { + bitweightName += "wac"; + } + iString gainState(gbl::cissLab->GainState()); + bitweightName = bitweightName + "g" + gainState; + + if(gbl::cissLab->FrontOpticsTemp() < -5.0 ){ + bitweightName += "m10_bwt.tab"; + } + else if(gbl::cissLab->FrontOpticsTemp() < 25.0){ + bitweightName += "p5_bwt.tab"; + } + else { + bitweightName += "p25_bwt.tab"; + } + return gbl::GetCalibrationDirectory("bitweight") + bitweightName; +} +//=====End Bitweight Methods=====================================================================// + +//=====2 Debias Methods============================================================================// +//These methods are modelled after IDL CISSCAL's cassimg_debias.pro + +/** + * This method is modelled after IDL CISSCAL's + * cassimg_debias.pro. The purpose is to compute the bias + * (zero-exposure DN level of CCD chip) to be subtracted in the + * Calibrate() method. + * There are two ways to do this + * 1. (DEFAULT) using overclocked pixel array taken out of + * binary line prefix + * 2. subtract BiasMeanStrip value found in labels + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + * @history 2009-05-27 Jeannie Walldren - Commented out table + * if-statement as done idl cisscal version 3.6. + */ +void gbl::ComputeBias(){ + gbl::calgrp += PvlKeyword("BiasSubtractionPerformed","Yes"); + gbl::calgrp.FindKeyword("BiasSubtractionPerformed").AddComment("Bias Subtraction Parameters"); + + iString fsw(gbl::cissLab->FlightSoftwareVersion()); + double flightSoftwareVersion; + + if(fsw == "Unknown"){ + flightSoftwareVersion = 0.0;// cassimg_readlabels.pro sets this to 1.3, we treat this as 1.2??? + } + else{ + flightSoftwareVersion = fsw.ToDouble(); + } + // check overclocked pixels exist + if(gbl::cissLab->CompressionType() != "Lossy"){ + if(flightSoftwareVersion < 1.3){ // (1.2=CAS-ISS2 or Unknown=0.0=CAS-ISS) + gbl::numberOfOverclocks = 1; + } + else { //if(1.3=CAS-ISS3 or 1.4=CAS-ISS4) + gbl::numberOfOverclocks = 2; + } + gbl::calgrp += PvlKeyword("BiasSubtractionMethod","Overclock fit"); + } + // otherwise overclocked pixels are invalid and must use bias strip mean where possible + else { // overclocks array is corrupt for lossy images (see cassimg_readvic.pro) +#if 0 + // 2009-04-27 Jeannie Walldren + // following code comment out in new idl cisscal version, 3.6: + if(gbl::cissLab->DataConversionType() == "Table"){ // Lossy + Table = no debias + gbl::calgrp.FindKeyword("BiasSubtractionPerformed").SetValue("No: Table converted and Lossy compressed"); + gbl::calgrp += PvlKeyword("BiasSubtractionMethod","Not applicable: No bias subtraction"); + gbl::calgrp += PvlKeyword("NumberOfOverclocks", "Not applicable: No bias subtraction"); + gbl::bias.resize(1); + gbl::bias[0] = 0.0; + return; + } +#endif + + // according to SIS if 1.2 or 1.3 and Lossy, ignore bias strip mean - invalid data + if(flightSoftwareVersion <= 1.3){ // Lossy + 1.2 or 1.3 = no debias + gbl::calgrp.FindKeyword("BiasSubtractionPerformed").SetValue("No: Lossy compressed on CAS-ISS2 or CAS-ISS3"); + gbl::calgrp += PvlKeyword("BiasSubtractionMethod","Not applicable: No bias subtraction"); + gbl::calgrp += PvlKeyword("NumberOfOverclocks", "Not applicable: No bias subtraction"); + gbl::bias.resize(1); + gbl::bias[0] = 0.0; + return; + } + gbl::calgrp += PvlKeyword("BiasSubtractionMethod","Bias strip mean"); + gbl::numberOfOverclocks = 0;//overclocks array is corrupt for lossy images + } + //Choose bias subtraction method + if(gbl::numberOfOverclocks){ // use overclocked pixels as default + gbl::bias = gbl::OverclockFit(); + } + else { // use BiasStripMean in image label if can't use overclock + gbl::bias.resize(1); + gbl::bias[0] = gbl::cissLab->BiasStripMean(); + } + gbl::calgrp += PvlKeyword("NumberOfOverclocks",gbl::numberOfOverclocks); + return; +} + +/** + * This method is modelled after IDL CISSCAL's + * cassimg_define.pro method, CassImg::OverclockAvg(). This + * access function computes line-averaged overclocked pixel + * values and returns a linear fit of these values. + * + * @return vector Results of linear fit + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + */ +vector gbl::OverclockFit(){ + vector< vector > overclocks; + // Read overclocked info from table saved during ciss2isis + // table should have 3 columns: + // -col 3 is the "average" of the overclocked pixels + // -if there are 2 overclocks, columns 1 and 2 contain them + // -otherwise column 1 is all null and we use column 2 + Table overClkTable("ISS Prefix Pixels"); + gbl::incube->Read(overClkTable); + for(int i = 0; i < overClkTable.Records(); i++){ + overclocks.push_back(overClkTable[i]["OverclockPixels"]); + } + + vector overclockfit, eqn, avg; + PolynomialUnivariate poly(1); + LeastSquares lsq(poly); + //get overclocked averages + for(unsigned int i = 0; i < overclocks.size(); i++){ + avg.push_back(overclocks[i][2]); + } + if(avg[0] > 2*avg[1]){ + avg[0] = avg[1]; + } + + // initialize eqn + eqn.push_back(0.0); + for(unsigned int i = 0; i < avg.size(); i++){ + // if avg is a special pixel, we must change to integer values so we don't throw off the linear fit + if(avg[i] == Isis::NULL2){ + avg[i] = 0; + } + if(avg[i] == Isis::HIGH_REPR_SAT2){ + if(gbl::cissLab->DataConversionType() == "Table"){ + avg[i] = 4095; + } + else{ + avg[i] = 255; + } + } + eqn[0] = (double) (i+1); + // add to least squares variable + lsq.AddKnown(eqn,avg[i]); + } + // solve linear fit + lsq.Solve(LeastSquares::QRD); + for(unsigned int i = 0; i < overclocks.size(); i++){ + eqn[0] = (double) (i+1); + overclockfit.push_back(lsq.Evaluate(eqn)); + + } + //return a copy of the vector of linear fitted overclocks + // this will be used as the bias + return overclockfit; +} +//=====End Debias Methods========================================================================// + + +//=====Subtract Dark Methods=====================================================================// +// THESE ARE CONTAINED IN THE CLASS DARKCURRENT +//=====End Subtract Dark Methods=================================================================// + + +//=====1 Linearize Methods=========================================================================// +//This method is modelled after IDL CISSCAL's cassimg_linearise.pro + +/** + * This method is modelled after IDL CISSCAL's + * cassimg_linearise.pro. The purpose is to correct the image + * for non-linearity. + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + */ +void gbl::Linearize(){ +// These are the correction factor tables from the referenced documents +// For each gain state there are a list of DNs where measurements +// were performed and the corresponding correction factors C +// The correction is then performed as DN'=DN*Cdn +// Where Cdn is an interpolation for C from the tabulated values + + iString lut; + int gainState = gbl::cissLab->GainState(); + if(gbl::cissLab->NarrowAngle()){ + switch (gainState){ + case 0: lut = "NAC0.lut"; break; + case 1: lut = "NAC1.lut"; break; + case 2: lut = "NAC2.lut"; break; + case 3: lut = "NAC3.lut"; break; + default: throw iException::Message(iException::Pvl, + "Input file contains invalid GainState. See Software Interface Specification (SIS), Version 1.1, page 86.", + _FILEINFO_); + } + } + else{ + switch (gainState){ + case 0: lut = "WAC0.lut"; break; + case 1: lut = "WAC1.lut"; break; + case 2: lut = "WAC2.lut"; break; + case 3: lut = "WAC3.lut"; break; + default: throw iException::Message(iException::Pvl, + "Input file contains invalid GainState. See Software Interface Specification (SIS), Version 1.1, page 86.", + _FILEINFO_); + } + } + vector DN_VALS, C_VALS; + // Get the directory where the CISS linearize directory is. + Filename linearLUT(gbl::GetCalibrationDirectory("linearize") + lut); + if(!linearLUT.Exists()) { + throw iException::Message(iException::Io, + "Unable to calibrate image. LinearityCorrectionTable ***" + + linearLUT.Expanded() + "*** not found.", _FILEINFO_); + } + gbl::calgrp += PvlKeyword("LinearityCorrectionPerformed","Yes"); + gbl::calgrp.FindKeyword("LinearityCorrectionPerformed").AddComment("Linearity Correction Parameters"); + gbl::calgrp += PvlKeyword("LinearityCorrectionTable",linearLUT.Expanded()); + + TextFile *pairs = new TextFile(linearLUT.Expanded()); + for(int i = 0; i < pairs->LineCount(); i++){ + iString line; + pairs->GetLine(line,true); + line.ConvertWhiteSpace(); + line.Compress(); + DN_VALS.push_back(line.Token(" ").ToDouble()); + C_VALS.push_back(line.Trim(" ").ToDouble()); + } + pairs->Close(); + + // ASSUMPTION: C will not change significantly over fractional DN + // If this is not the case, then can perform simple second interpolation + // between DNs while mapping LUT onto the image + NumericalApproximation linearInterp(NumericalApproximation::Linear); + for(unsigned int i = 0; i < DN_VALS.size(); i++){ + linearInterp.AddData(DN_VALS[i], C_VALS[i]); + } + + // Create the stretch pairs + gbl::stretch.ClearPairs(); + for(unsigned int i = 0; i < 4096; i++){ + double j = linearInterp.Evaluate((double) i); + gbl::stretch.AddPair(i,j); + } + // Map LUT onto image, defending against out-of-range DN values + return; +} +//=====End Linearize Methods=====================================================================// + + +//=====2 Flatfield Methods=========================================================================// +// These methods are modelled after IDL CISSCAL's cassimg_dustringcorrect.pro and cassimg_dividebyflats.pro + +/** + * This method is modelled after IDL CISSCAL's + * cassimg_dustringcorrect.pro. The purpose is to find the + * files and value needed to perform dustring correction and + * mottle correction: dustFile, mottleFile, strengthFactor. + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + * @history 2009-05-27 Jeannie Walldren - Changed to read + * effective wavelength from 5th column of file + * (rather than 3rd) since effective wavelength file + * updated with new idl cisscal version, 3.6. Added + * effective wavelength to calibration group in + * labels. + */ +void gbl::FindDustRingParameters(){ + // No dustring or mottle correction for WAC + if( gbl::cissLab->WideAngle() ){ + gbl::dustCorrection = false; + gbl::mottleCorrection = false; + gbl::calgrp += PvlKeyword("DustRingCorrectionPerformed","No: ISSWA"); + gbl::calgrp.FindKeyword("DustRingCorrectionPerformed").AddComment("DustRing Correction Parameters"); + gbl::calgrp += PvlKeyword("DustRingFile","Not applicable: No dustring correction"); + gbl::calgrp += PvlKeyword("MottleCorrectionPerformed","No: dustring correction"); + gbl::calgrp += PvlKeyword("MottleFile","Not applicable: No dustring correction"); + gbl::calgrp += PvlKeyword("EffectiveWavelengthFile","Not applicable: No dustring correction"); + gbl::calgrp += PvlKeyword("StrengthFactor", "Not applicable: No dustring correction"); + return; + } + + // dustring correct for NAC + gbl::dustCorrection = true; + gbl::calgrp += PvlKeyword("DustRingCorrectionPerformed","Yes"); + gbl::calgrp.FindKeyword("DustRingCorrectionPerformed").AddComment("DustRing Correction Parameters"); + // get name of dust file + gbl::dustFile = (gbl::GetCalibrationDirectory("dustring") + "/nac_dustring_venus." + + gbl::cissLab->InstrumentModeId() + ".cub"); + if(!gbl::dustFile.Exists()) { // dustring file not found, stop calibration + throw iException::Message(iException::Io, + "Unable to calibrate image. DustRingFile ***" + + gbl::dustFile.Expanded() + "*** not found.", _FILEINFO_); + } + gbl::calgrp += PvlKeyword("DustRingFile",gbl::dustFile.Expanded()); + + // No mottle correct for summation mode other than 1 + if( gbl::cissLab->SummingMode() != 1 ){ + gbl::mottleCorrection = false; + gbl::calgrp += PvlKeyword("MottleCorrectionPerformed","No: Summing mode is " + iString(gbl::cissLab->SummingMode())); + gbl::calgrp += PvlKeyword("MottleFile","Not applicable: No mottle correction"); + gbl::calgrp += PvlKeyword("EffectiveWavelengthFile","Not applicable: No mottle correction"); + gbl::calgrp += PvlKeyword("StrengthFactor", "Not applicable: No mottle correction"); + return; + } + + // No Mottling correction for images before sclk=1444733393: (i.e., 2003-286T10:28:04) + if( gbl::cissLab->ImageNumber() < 1455892746){ + gbl::mottleFile = ""; + gbl::mottleCorrection = false; + gbl::calgrp += PvlKeyword("MottleCorrectionPerformed","No: Image before 2003-286T10:28:04"); + gbl::calgrp += PvlKeyword("MottleFile", "Not applicable: No mottle correction"); + gbl::calgrp += PvlKeyword("EffectiveWavelengthFile","Not applicable: No mottle correction"); + gbl::calgrp += PvlKeyword("StrengthFactor", "Not applicable: No mottle correction"); + return; + } + + // Mottling correction for full images after 2003-286T10:28:04 + gbl::mottleFile = (gbl::GetCalibrationDirectory("dustring") + "nac_mottle_1444733393.full.cub"); + if(!gbl::mottleFile.Exists()) { // mottle file not found, stop calibration + throw iException::Message(iException::Io, + "Unable to calibrate image. MottleFile ***" + + gbl::mottleFile.Expanded() + "*** not found.", _FILEINFO_); + } + gbl::mottleCorrection = true; + gbl::calgrp += PvlKeyword("MottleCorrectionPerformed","Yes"); + gbl::calgrp += PvlKeyword("MottleFile", gbl::mottleFile.Expanded()); + + // determine strength factor, need effective wavelength of filter + vector filterIndex (2); + filterIndex[0] = gbl::cissLab->FilterIndex()[0]; + filterIndex[1] = gbl::cissLab->FilterIndex()[1]; + if( filterIndex[0] == 17 && filterIndex[1] == 18 ){//filter combo CL1/CL2 + filterIndex[0] = -1; + } + if((filterIndex[0] < 17 && filterIndex[1] < 17 ) || (filterIndex[0] >= 17 && filterIndex[1] >= 17)){ + gbl::strengthFactor = 0.0; + // use effective wavelength to estimate strength factor: + Filename effectiveWavelength(gbl::GetCalibrationDirectory("efficiency") + "na_effwl.tab"); + if(!effectiveWavelength.Exists()) { // effectivewavelength file not found, stop calibration + throw iException::Message(iException::Io, + "Unable to calibrate image. EffectiveWavelengthFile ***" + + effectiveWavelength.Expanded() + "*** not found.", _FILEINFO_); + } + gbl::calgrp += PvlKeyword("EffectiveWavelengthFile",effectiveWavelength.Expanded()); + CisscalFile *effwlDB = new CisscalFile(effectiveWavelength.Expanded()); + iString col1,col2,col3, col4, col5; + double effwl; + for(int i = 0; i < effwlDB->LineCount(); i++){ + iString line; + effwlDB->GetLine(line); + line = line.ConvertWhiteSpace(); + line = line.Compress(); + col1 = line.Token(" "); + if(col1 == gbl::cissLab->FilterName()[0]){ + col2 = line.Token(" "); + if(col2 == gbl::cissLab->FilterName()[1]){ + col3 = line.Token(" "); // central wavelength of filter combo + col4 = line.Token(" "); // full-width at half-maximum (FWHM) of filter combo + col5 = line.Token(" "); // effective wavelength + if(col5 == ""){ + // Couldn't find a match in the database + gbl::calgrp.FindKeyword("MottleCorrectionPerformed").SetValue("Yes: EffectiveWavelengthFile contained no factor for filter combination, used strengthFactor of 1.0"); + gbl::strengthFactor = 1.0; + } + else{ + effwl = col5.ToDouble(); + gbl::calgrp += PvlKeyword("EffectiveWavelength", effwl); + gbl::strengthFactor = 1.30280 - 0.000717552 * effwl; + } + break; + } + else{ + continue; + } + } + else{ + continue; + } + } + effwlDB->Close(); + if(gbl::strengthFactor == 0.0) { + gbl::calgrp.FindKeyword("MottleCorrectionPerformed").SetValue("Yes: EffectiveWavelengthFile contained no factor for filter combination, used strengthFactor of 1.0"); + gbl::strengthFactor = 1.0; + } + } + else {//if(filterIndex[0] > 17 || filterIndex[1] > 17 ) + gbl::calgrp += PvlKeyword("EffectiveWavelengthFile","No effective wavelength file used"); + switch(filterIndex[0]){ + case 0: gbl::strengthFactor = 1.119; break; + case 1: gbl::strengthFactor = 1.186; break; + case 3: gbl::strengthFactor = 1.00; break; + case 6: gbl::strengthFactor = 0.843; break; + case 8: gbl::strengthFactor = 0.897; break; + case 10: gbl::strengthFactor = 0.780; break; + case -1: gbl::strengthFactor = 0.763; break; + default: + switch(filterIndex[1]){ + case 2: gbl::strengthFactor = 1.069; break; + case 4: gbl::strengthFactor = 0.833; break; + case 5: gbl::strengthFactor = 0.890; break; + case 7: gbl::strengthFactor = 0.997; break; + case 9: gbl::strengthFactor = 0.505; break; + case 11: gbl::strengthFactor = 0.764; break; + case 12: gbl::strengthFactor = 0.781; break; + case 13: gbl::strengthFactor = 0.608; break; + case 14: gbl::strengthFactor = 0.789; break; + case 15: gbl::strengthFactor = 0.722; break; + case 16: gbl::strengthFactor = 0.546; break; + default: throw iException::Message(iException::Pvl, + "Input file contains invalid FilterName. See Software Interface Specification (SIS) Appendix A, Table 8.2.", + _FILEINFO_); + } + } + } + gbl::calgrp += PvlKeyword("StrengthFactor", gbl::strengthFactor); + return; +} + +/** + * This method is modelled after IDL CISSCAL's + * cassimg_dividebyflats.pro. The purpose is to find the flat + * field file needed to correct the image for sensitivity + * variations across the field by dividing by flat field image. + * + * @return Filename Name of the flat file for this image. + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + */ +Filename gbl::FindFlatFile(){ + // There is a text database file in the slope files directory + // that maps filter combinations (and camera temperature) + // to the corresponding slope field files. + // according to slope_info.txt, slope_db_1 is original, slope_db_2 is the best and slope_db_3 is newest but has some issues + Filename flatFile; + Filename slopeDatabaseName(gbl::GetCalibrationDirectory("slope") + "slope_db_2.tab"); + if(!slopeDatabaseName.Exists()) { // slope database not found, stop calibration + throw iException::Message(iException::Io, + "Unable to calibrate image. SlopeDataBase ***" + + slopeDatabaseName.Expanded() + "*** not found.", _FILEINFO_); + } + gbl::calgrp += PvlKeyword("FlatfieldCorrectionPerformed","Yes"); + gbl::calgrp.FindKeyword("FlatfieldCorrectionPerformed").AddComment("Flatfield Correction Parameters"); + gbl::calgrp += PvlKeyword("SlopeDataBase",slopeDatabaseName.Expanded()); + gbl::flatCorrection = true; + + // Find the best-match flat file + // Choose a nominal optics temp name as per ISSCAL + iString frontOpticsTemp(""); + if( gbl::cissLab->FrontOpticsTemp() < -5.0 ){ + frontOpticsTemp += "m10"; + } + else if( gbl::cissLab->FrontOpticsTemp() < 25.0 ){ + frontOpticsTemp += "p5"; + } + else{ + frontOpticsTemp += "p25"; + } + // Require match for instrument, temperature range name, Filter1, filter2 + CisscalFile *slopeDB = new CisscalFile(slopeDatabaseName.Expanded()); + iString col1,col2,col3,col4,col5,col6,col7,col8; + for(int i = 0; i < slopeDB->LineCount(); i++){ + iString line; + slopeDB->GetLine(line); //assigns value to line + line = line.ConvertWhiteSpace(); + line = line.Compress(true); + col1 = line.Token(" "); col1.Trim("'"); + if(col1 == gbl::cissLab->InstrumentId()){ + col2 = line.Token(" "); col2.Trim("'"); + if((col2 == frontOpticsTemp) || (gbl::cissLab->WideAngle())){ + col3 = line.Token(" "); col3.Trim("'"); + if(col3 == gbl::cissLab->FilterName()[0]){ + col4 = line.Token(" "); col4.Trim("'"); + if(col4 == gbl::cissLab->FilterName()[1]){ + col5 = line.Token(" "); col5.Trim("'"); // col5 = gainstate (not used) + col6 = line.Token(" "); col6.Trim("'"); // col6 = antiblooming state (not used) + col7 = line.Token(" "); col7.Trim("'"); // col7 = file number (not used) + col8 = line.Trim(" "); // col8 = slope file name + break; + } + else { + continue; + } + } + else{ + continue; + } + } + else{ + continue; + } + } + else{ + continue; + } + } + slopeDB->Close(); + + if( col8 == "" ){ // error in slope database, stop calibration + // Couldn't find a match in the database + throw iException::Message(iException::Io, + "Unable to calibrate image. SlopeDataBase contained no factor for combination:" + + gbl::cissLab->InstrumentId() + ":" + frontOpticsTemp + ":" + + gbl::cissLab->FilterName()[0] + ":" + gbl::cissLab->FilterName()[1] + ".", + _FILEINFO_); + } + //Column 8 contains version of slopefile from which our flatfiles are derived + int j = col8.find("."); + //attatch version number to "flat" by skipping + // the first 5 characters("SLOPE") and skipping + // any thing after "." ("IMG") + col8 = "flat" + col8.substr(5,(j-5)+1); + flatFile = (gbl::GetCalibrationDirectory("slope/flat") + col8 + + gbl::cissLab->InstrumentModeId() + ".cub"); + gbl::calgrp += PvlKeyword("FlatFile",flatFile.Expanded()); + if(!flatFile.Exists()) { // flat file not found, stop calibration + throw iException::Message(iException::Io, + "Unable to calibrate image. FlatFile ***" + + flatFile.Expanded() + "*** not found.", _FILEINFO_); + } + return flatFile; +} +//=====End Flatfield Methods=====================================================================// + +//=====5 Convert DN to Flux Methods================================================================// +// These methods are modelled after IDL CISSCAL's cassimg_dntoelectrons.pro, cassimg_dividebyexpot.pro, +// cassimg_dividebyareapixel.pro, cassimg_dividebyefficiency.pro + +/** + * This method is modelled after IDL CISSCAL's + * cassimg_dntoelectrons.pro. The purpose is to find the true + * gain needed to multiply image by gain constant (convert DN to + * electrons). + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + * @history 2009-05-27 Jeannie Walldren - Removed return + * statement and added else statement so that the + * TrueGain keyword is added in any case. + */ +void gbl::DNtoElectrons(){ + gbl::calgrp += PvlKeyword("DNtoFluxPerformed","Yes"); + gbl::calgrp.FindKeyword("DNtoFluxPerformed").AddComment("DN to Flux Parameters"); + gbl::calgrp += PvlKeyword("DNtoElectrons","Yes"); + // Gain used for an image is documented by the GainModID attribute + // of the image. Nominal values are as follow: + // + // Attribute Gain Usual Nominal Gain + // Value state mode (e- per DN) + // "1400K" 0 SUM4 215 + // "400K" 1 SUM2 95 + // "100K" 2 FULL 29 + // "40K" 3 FULL 12 + if( gbl::cissLab->NarrowAngle() ) { + switch(gbl::cissLab->GainState()) { + case 0: gbl::trueGain = 30.27/0.135386;break; + case 1: gbl::trueGain = 30.27/0.309569;break; + case 2: gbl::trueGain = 30.27/1.0; break; + case 3: gbl::trueGain = 30.27/2.357285;break; + default: // invalid gainstate, unable to convert DN to electrons, stop calibration + throw iException::Message(iException::Pvl, + "Input file contains invalid GainState. See Software Interface Specification (SIS), Version 1.1, page 86.", + _FILEINFO_); + } + } + else{ + switch(gbl::cissLab->GainState()) { + case 0: gbl::trueGain = 27.68/0.125446;break; + case 1: gbl::trueGain = 27.68/0.290637;break; + case 2: gbl::trueGain = 27.68/1.0; break; + case 3: gbl::trueGain = 27.68/2.360374;break; + default: // invalid gainstate, unable to convert DN to electrons, stop calibration + throw iException::Message(iException::Pvl, + "Input file contains invalid GainState. See Software Interface Specification (SIS), Version 1.1, page 86.", + _FILEINFO_); + } + } + gbl::calgrp += PvlKeyword("TrueGain", gbl::trueGain); + return; +} + +/** + * This method is modelled after IDL CISSCAL's + * cassimg_dividebyexpot.pro. The purpose is to find the + * shutter offset needed to divide a Cassini image by corrected + * exposure time, correcting for shutter offset effects (sample + * dependency of actual exposure time). + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + */ +void gbl::FindShutterOffset(){ + // Don't do this for zero-exposure images! + if(gbl::cissLab->ExposureDuration() == 0.0){ // exposuretime = 0, stop calibration + throw iException::Message(iException::Pvl, + "Unable to calibrate image. Cannot divide by exposure time for zero exposure image.", + _FILEINFO_); + } + gbl::calgrp += PvlKeyword("DividedByExposureTime","Yes"); + gbl::divideByExposure = true; + // Define whereabouts of shutter offset files + iString offsetFileName(""); + if(gbl::cissLab->NarrowAngle()){ + offsetFileName += (gbl::GetCalibrationDirectory("offset") + "nacfm_so_"); + } + else{ + offsetFileName += (gbl::GetCalibrationDirectory("offset") + "wacfm_so_"); + } + if(gbl::cissLab->FrontOpticsTemp() < -5.0 ){ + offsetFileName += "m10."; + } + else if(gbl::cissLab->FrontOpticsTemp() < 25.0){ + offsetFileName += "p5."; + } + else { + offsetFileName += "p25."; + } + offsetFileName += (gbl::cissLab->InstrumentModeId() + ".cub"); + Filename shutterOffsetFile(offsetFileName); + if(!shutterOffsetFile.Exists()) { // shutter offset file not found, stop calibration + throw iException::Message(iException::Io, + "Unable to calibrate image. ShutterOffsetFile ***" + + shutterOffsetFile.Expanded() + "*** not found.", _FILEINFO_); + } + gbl::calgrp += PvlKeyword("ShutterOffsetFile",shutterOffsetFile.Expanded()); + Cube offsetCube; + offsetCube.Open(shutterOffsetFile.Expanded()); + gbl::offset = new Brick(gbl::incube->Samples(),1,1,offsetCube.PixelType()); + gbl::offset->SetBasePosition(1,1,1); + offsetCube.Read(*gbl::offset); + offsetCube.Close(); + return; + // Pixel value is now flux (electrons per second) +} + +/** + * This method is modelled after IDL CISSCAL's + * cassimg_dividebyareapixel.pro. The purpose is to find the + * values needed to normalise the image by dividing by area of + * optics and by solid angle subtended by a pixel. + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + */ +void gbl::DivideByAreaPixel(){ + // These values as per ISSCAL + // SolidAngle is (FOV of Optics) / (Number of Pixels) + // OpticsArea is (Diameter of Primary Mirror)^2 * Pi/4 + // We will adjust here for the effects of SUM modes + // (which effectively give pixels of 4 or 16 times normal size) + + gbl::calgrp += PvlKeyword("DividedByAreaPixel","Yes"); + if(gbl::cissLab->NarrowAngle()) { + gbl::solidAngle = 3.6*pow(10.0,-11.0); + gbl::opticsArea = 264.84; + } + else { + gbl::solidAngle = 3.6*pow(10.0,-9); + gbl::opticsArea = 29.32; + } + // Normalize summed images to real pixels + + // sumFactor is the inverse of the square of the summing mode, + // it was expressed in IDL as the following: + // [gbl::sumFactor = (gbl::incube->Samples()/1024.0)*(gbl::incube->Lines()/1024.0);] + gbl::sumFactor = 1/pow(gbl::cissLab->SummingMode(),2.0); + gbl::calgrp += PvlKeyword("SolidAngle",gbl::solidAngle); + gbl::calgrp += PvlKeyword("OpticsArea",gbl::opticsArea); + gbl::calgrp += PvlKeyword("SumFactor",gbl::sumFactor); + return; +} + +/** + * This method is modelled after IDL CISSCAL's + * cassimg_dividebyefficiency.pro. The purpose is to find the + * efficiency factor for the given flux units. This value is + * used to correct the image for filter and CCD efficiency. + * + * @b Note: For "I/F", The results diverge from the IDL results + * due to differences in the way they calculate solar distance. + * However, the DN results are still within 0.2% after we divide + * by efficiency factor. + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version of + * FindEfficiencyFactor_IoverF() and + * FindEfficiencyFactor_IntensityUnits() written. + * @history 2009-02-12 Jeannie Walldren - Modified + * FindEfficiencyFactor_IoverF() code to make a + * second attempt to find the planet if the + * Isis::Camera class fails to find it at the center + * point of the cube. Previously, if the target was + * not found, an exception was thrown. Now the + * SubSpacecraftPoint() method from Isis::Camera + * class is used to try to locate the target before + * throwing the exception. + * @history 2009-05-27 Jeannie Walldren - Joined + * FindEfficiencyFactor_IoverF() and + * FindEfficiencyFactor_IntensityUnits() into + * FindEfficiencyFactor() per new idl cisscal + * version, 3.6, updates. This version no longer uses + * the effic_db (now called omega0) to calculate the + * efficiency factor for intensity units. Now, the + * method is not far off from the I/F method. + */ + +void gbl::FindEfficiencyFactor(string fluxunits){ + + gbl::calgrp += PvlKeyword("DividedByEfficiency","Yes"); + gbl::calgrp += PvlKeyword("EfficiencyFactorMethod", fluxunits); + vector lambda; // lambda will contain all wavelength vectors used + + //--- 1) CREATE LINEAR APPROXIMATION FROM SYSTEM TRANSMISSION FILE ---------- + // find system transmission file (T0*T1*T2*QE) + + Filename transfile(gbl::GetCalibrationDirectory("efficiency/systrans") + + gbl::cissLab->InstrumentId().DownCase() + + gbl::cissLab->FilterName()[0].DownCase() + + gbl::cissLab->FilterName()[1].DownCase() + "_systrans.tab"); + if(!transfile.Exists()) { // transmission file not found, stop calibration + throw iException::Message(iException::Io, + "Unable to calibrate image. TransmissionFile ***" + + transfile.Expanded() + "*** not found.", _FILEINFO_); + } + // read in system transmission to find transmitted wavelength and flux + gbl::calgrp += PvlKeyword("TransmissionFile", transfile.Expanded()); + CisscalFile *trans = new CisscalFile(transfile.Expanded()); + vector wavelengthT, transmittedFlux; + double x, y; + for(int i = 0; i < trans->LineCount(); i++){ + iString line; + trans->GetLine(line); //assigns value to line + line = line.ConvertWhiteSpace(); + line = line.Compress(); + line = line.TrimHead(" "); + if (line == "") { + break; + } + x = line.Token(" ").ToDouble(); + y = line.Token(" ").ToDouble(); + wavelengthT.push_back(x); + transmittedFlux.push_back(y); + } + trans->Close(); + // wavelength and flux are in descending order, reverse to ascending order + if (wavelengthT[0] > wavelengthT.back()){ + reverse(wavelengthT.begin(), wavelengthT.end()); + reverse(transmittedFlux.begin(), transmittedFlux.end()); + } + lambda = wavelengthT; + // Create Linear approximation from the transmitted data + NumericalApproximation newtrans (NumericalApproximation::Linear); + for(unsigned int i = 0; i < transmittedFlux.size(); i++){ + newtrans.AddData(wavelengthT[i], transmittedFlux[i]); + } + + //--- 2) CREATE LINEAR APPROXIMATION FROM QUANTUM EFFICIENCY FILE ----------- + // find quantum efficiency file + Filename qecorrfile; + if( gbl::cissLab->NarrowAngle()) { + qecorrfile = gbl::GetCalibrationDirectory("correction") + "nac_qe_correction.tab"; + } + else { + qecorrfile = gbl::GetCalibrationDirectory("correction") + "wac_qe_correction.tab"; + } + if(!qecorrfile.Exists()) { // quantum efficiency file not found, stop calibration + throw iException::Message(iException::Io, + "Unable to calibrate image. QuantumEfficiencyFile ***" + + qecorrfile.Expanded() + "*** not found.", _FILEINFO_); + } + // read qe file to find qe wavelength and correction + gbl::calgrp += PvlKeyword("QuantumEfficiencyFile", qecorrfile.Expanded()); + CisscalFile *qeCorr = new CisscalFile(qecorrfile.Expanded()); + vector wavelengthQE, qecorrection; + for(int i = 0; i < qeCorr->LineCount(); i++){ + iString line; + qeCorr->GetLine(line); //assigns value to line + line = line.ConvertWhiteSpace(); + line = line.Compress(); + line = line.TrimHead(" "); + if (line == "") { + break; + } + x = line.Token(" ").ToDouble(); + y = line.Trim(" ").ToDouble(); + wavelengthQE.push_back(x); + qecorrection.push_back(y); + lambda.push_back(x); + } + qeCorr->Close(); + // wavelength and qecorr are in descending order, reverse to ascending order + if (wavelengthQE[0] > wavelengthQE.back()){ + reverse(wavelengthQE.begin(), wavelengthQE.end()); + reverse(qecorrection.begin(), qecorrection.end()); + } + // Create Linear approximation from the qe data + NumericalApproximation newqecorr(NumericalApproximation::Linear); + for(unsigned int i = 0; i < qecorrection.size(); i++){ + newqecorr.AddData(wavelengthQE[i], qecorrection[i]); + } + + + // these variables will be defined in the if-statement + iString units; + double minlam, maxlam; + vector fluxproduct1, fluxproduct2; + + if (fluxunits == "INTENSITY") { + gbl::calgrp += PvlKeyword("SpectralFile", "Not applicable: Intensity Units chosen"); + gbl::calgrp += PvlKeyword("SolarDistance", "Not applicable: Intensity Units chosen"); + //--- 3a) SORT AND MAKE LAMBDA UNIQUE, REMOVE OUTLIERS, ------------------- + //--- FIND FLUX PRODUCTS TO BE INTERPOLATED --------------------------- + units = "phot/cm^2/s/nm/ster"; + + // lambda domain min is the largest of the minimum wavelength values (rounded up) + minlam = ceil (max(wavelengthT.front(),wavelengthQE.front())); + // lambda domain max is the smallest of the maximum wavelength values (rounded down) + maxlam = floor(min(wavelengthT.back(),wavelengthQE.back())); + + // NumericalApproximation requires lambda to be sorted + sort(lambda.begin(), lambda.end()); + // NumericalApproximation requires lambda to be unique + vector::iterator it = unique(lambda.begin(),lambda.end()); + lambda.resize(it - lambda.begin()); + + // remove any values that fall below minlam + while(lambda[0] < minlam) { + lambda.erase(lambda.begin()); + } + + // remove any values that fall above maxlam + while(lambda[lambda.size()-1] > maxlam) { + lambda.erase(lambda.end()-1); + } + + for(unsigned int i = 0; i < lambda.size(); i++){ + double a = newtrans.Evaluate(lambda[i]); + double b = newqecorr.Evaluate(lambda[i]); + fluxproduct1.push_back(a*b); + } + fluxproduct2 = fluxproduct1; + } + else {// if(fluxunits == "I/F") { + //--- 3b) CALCULATE SOLAR DISTANCE, --------------------------------------- + // --- CREATE LINEAR APPROXIMATION FROM SPECTRAL FILE ------------------ + //--- SORT AND MAKE LAMBDA UNIQUE, REMOVE OUTLIERS, ------------------- + //--- FIND FLUX PRODUCTS TO BE INTERPOLATED --------------------------- + + units = "I/F"; + + // find spectral file + Filename specfile(gbl::GetCalibrationDirectory("efficiency") + "solarflux.tab"); + if(!specfile.Exists()) { // spectral file not found, stop calibration + throw iException::Message(iException::Io, + "Unable to calibrate image using I/F. SpectralFile ***" + + specfile.Expanded() + "*** not found.", _FILEINFO_); + } + gbl::calgrp += PvlKeyword("SpectralFile", specfile.Expanded()); + + // get distance from sun (AU): + double angstromsToNm = 10.0; + double distFromSun = 0; + try{ + Camera *cam = gbl::incube->Camera(); + bool camSuccess = cam->SetImage(gbl::incube->Samples()/2,gbl::incube->Lines()/2); + if(!camSuccess) {// the camera was unable to find the planet at the center of the image + double lat, lon; + // find values for lat/lon directly below spacecraft + cam->SubSpacecraftPoint(lat,lon); + // use these values to set the ground coordinates + cam->SetUniversalGround(lat,lon); + } + distFromSun = cam->SolarDistance(); + } + catch(iException &e){ // unable to get solar distance, can't divide by efficiency, stop calibration + throw e.Message(iException::Camera, + "Unable to calibrate image using I/F. Cannot calculate Solar Distance using Isis::Camera object.", + _FILEINFO_); + } + if(distFromSun <= 0){ // solar distance <= 0, can't divide by efficiency, stop calibration + throw iException::Message(iException::Camera, + "Unable to calibrate image using I/F. Solar Distance calculated is less than or equal to 0.", + _FILEINFO_); + } + gbl::calgrp += PvlKeyword("SolarDistance", distFromSun); + + // read spectral file to find wavelength and flux + CisscalFile *spectral = new CisscalFile(specfile.Expanded()); + vector wavelengthF, flux; + for(int i = 0; i < spectral->LineCount(); i++){ + iString line; + spectral->GetLine(line); //assigns value to line + line = line.ConvertWhiteSpace(); + line = line.Compress(); + line = line.TrimHead(" "); + if (line == "") { + break; + } + x = line.Token(" ").ToDouble() / angstromsToNm; + y = line.Trim(" ").ToDouble() * angstromsToNm; + wavelengthF.push_back(x); + flux.push_back(y); + lambda.push_back(x); + } + spectral->Close(); + // wavelength is in descending order, reverse to ascending order + if (wavelengthF[0] > wavelengthF.back()){ + reverse(wavelengthF.begin(), wavelengthF.end()); + reverse(flux.begin(), flux.end()); + } + // Create Linear Approximation + NumericalApproximation newflux(NumericalApproximation::Linear); + for(unsigned int i = 0; i < flux.size(); i++){ + newflux.AddData(wavelengthF[i], flux[i]); + } + + // lambda domain min is the largest of the minimum wavelength values (rounded up) + minlam = ceil (max(wavelengthF.front(),max(wavelengthT.front(),wavelengthQE.front()))); + // lambda domain max is the smallest of the maximum wavelength values (rounded down) + maxlam = floor(min(wavelengthF.back(),min(wavelengthT.back(),wavelengthQE.back()))); + + // NumericalApproximation requires lambda to be sorted + sort(lambda.begin(), lambda.end()); + // NumericalApproximation requires lambda to be unique + vector::iterator it = unique(lambda.begin(),lambda.end()); + lambda.resize(it - lambda.begin()); + + // remove any values that fall below minlam + while(lambda[0] < minlam) { + lambda.erase(lambda.begin()); + } + + // remove any values that fall above maxlam + while(lambda[lambda.size()-1] > maxlam) { + lambda.erase(lambda.end()-1); + } + + for(unsigned int i = 0; i < lambda.size(); i++){ + double a = newtrans.Evaluate(lambda[i]); + double b = newqecorr.Evaluate(lambda[i]); + double c = newflux.Evaluate(lambda[i])/(Isis::PI*pow(distFromSun,2.0)); + fluxproduct1.push_back(a*b*c); + fluxproduct2.push_back(a*b); + } + } + + //--- 4) CALCULATE EFFICIENCY FACTOR AND TOTAL EFFICIENCY ------------------- + //--- USING LAMBDA AND FLUX PRODUCTS ------------------------------------- + NumericalApproximation spline1(NumericalApproximation::CubicNatural); + NumericalApproximation spline2(NumericalApproximation::CubicNatural); + spline1.AddData(lambda, fluxproduct1); + spline2.AddData(lambda, fluxproduct2); + gbl::efficiencyFactor = spline1.BoolesRule(spline1.DomainMinimum(), spline1.DomainMaximum()); + double efficiency = spline2.BoolesRule(spline2.DomainMinimum(), spline2.DomainMaximum()); + gbl::calgrp += PvlKeyword("EfficiencyFactor", gbl::efficiencyFactor, units); + gbl::calgrp += PvlKeyword("TotalEfficiency", efficiency); + + // Cannot divide by 0.0 + if(gbl::efficiencyFactor == 0) { + throw iException::Message(iException::Math, + "Unable to calibrate image using I/F. Cannot divide by efficiency factor of 0.", + _FILEINFO_); + } + return; +} + + +//=====End DN to Flux Methods====================================================================// + + +//=====1 Correction Factors Methods================================================================// + +/** + * This method is modelled after IDL CISSCAL's + * cassimg_correctionfactors.pro. The purpose is to find the + * correction factor, i.e. the value used to correct the image + * for ad-hoc factors. + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + * @history 2009-05-27 Jeannie Walldren - Renamed from + * FindCorrectionFactor since code was added to find + * the polarization correction factor, when + * available. + */ +void gbl::FindCorrectionFactors(){ + string filter1 = gbl::cissLab->FilterName()[0]; + string filter2 = gbl::cissLab->FilterName()[1]; + // check if polarized filters + if(filter1 == "IRP0" || filter1 == "P120" || filter1 == "P60" || filter1 == "P0" + || filter2 == "IRP90" || filter2 == "IRP0" ) { + Filename polarizationFactorFile(gbl::GetCalibrationDirectory("correction") + "pol_correction.tab"); + if(!polarizationFactorFile.Exists()) { // correction factor file not found, stop calibration + throw iException::Message(iException::Io, + "Unable to calibrate image. PolarizationFactorFile ***" + + polarizationFactorFile.Expanded() + "*** not found.", _FILEINFO_); + } + gbl::calgrp += PvlKeyword("PolarizationFactorPerformed","Yes"); + gbl::calgrp.FindKeyword("PolarizationFactorPerformed").AddComment("Correction Factor Parameters"); + gbl::calgrp += PvlKeyword("PolarizationFactorFile",polarizationFactorFile.Expanded()); + CisscalFile *polFact = new CisscalFile(polarizationFactorFile.Expanded()); + gbl::polarizationFactor = 0.0; + iString col1, col2, col3, col4; + for(int i = 0; i < polFact->LineCount(); i++){ + iString line; + polFact->GetLine(line); //assigns value to line + line = line.ConvertWhiteSpace(); + line = line.Compress(); + col1 = line.Token(" "); + if( col1 == gbl::cissLab->InstrumentId()){ + col2 = line.Token(" "); + if( col2 == gbl::cissLab->FilterName()[0] ){ + col3 = line.Token(" "); + if( col3 == gbl::cissLab->FilterName()[1] ){ + col4 = line.Trim(" "); + if(col4 == ""){ + gbl::polarizationFactor = 1.0; + // dividing by polarization factor of 1.0 implies this correction is not performed + gbl::calgrp.FindKeyword("PolarizationFactorPerformed").SetValue("No: PolarizationFactorFile contained no factor for filter combination"); + } + else{ + gbl::polarizationFactor = col4.ToDouble(); + } + break; + } + else{ + continue; + } + } + else { + continue; + } + } + else { + continue; + } + } + polFact->Close(); + + // if no factor was found for instrument ID and filter combination + if(gbl::polarizationFactor == 0.0){ + gbl::polarizationFactor = 1.0; + // dividing by polarization factor of 1.0 implies this correction is not performed + gbl::calgrp.FindKeyword("PolarizationFactorPerformed").SetValue("No: PolarizationFactorFile contained no factor for filter combination"); + } + else{ + // polarization factor is defined such that they are applied with the correction factor for the related CLR/Filter pair + if(gbl::cissLab->InstrumentId() == "ISSNA") { + filter1 = "CL1"; + } + if(gbl::cissLab->InstrumentId() == "ISSWA") { + filter2 = "CL2"; + } + } + gbl::calgrp += PvlKeyword("PolarizationFactor",gbl::polarizationFactor); + + } + else{ + // no polarization correction - gbl::polarizationFactor already initialized to 1 in main() + gbl::calgrp += PvlKeyword("PolarizationFactorPerformed","No"); + gbl::calgrp.FindKeyword("PolarizationFactorPerformed").AddComment("Correction Factor Parameters"); + } + // Get the directory where the CISS calibration directories are. + Filename correctionFactorFile(gbl::GetCalibrationDirectory("correction") + "correctionfactors_qecorr.tab"); + if(!correctionFactorFile.Exists()) { // correction factor file not found, stop calibration + throw iException::Message(iException::Io, + "Unable to calibrate image. CorrectionFactorFile ***" + + correctionFactorFile.Expanded() + "*** not found.", _FILEINFO_); + } + gbl::calgrp += PvlKeyword("CorrectionFactorPerformed","Yes"); + gbl::calgrp += PvlKeyword("CorrectionFactorFile",correctionFactorFile.Expanded()); + CisscalFile *corrFact = new CisscalFile(correctionFactorFile.Expanded()); + gbl::correctionFactor = 0.0; + iString col1, col2, col3, col4; + for(int i = 0; i < corrFact->LineCount(); i++){ + iString line; + corrFact->GetLine(line); //assigns value to line + line = line.ConvertWhiteSpace(); + line = line.Compress(); + col1 = line.Token(" "); + if( col1 == gbl::cissLab->InstrumentId()){ + col2 = line.Token(" "); + if( col2 == filter1 ){ + col3 = line.Token(" "); + if( col3 == filter2 ){ + col4 = line.Trim(" "); + if(col4 == ""){ + gbl::correctionFactor = 1.0; + // dividing by correction factor of 1.0 implies this correction is not performed + gbl::calgrp.FindKeyword("CorrectionFactorPerformed").SetValue("No: CorrectionFactorFile contained no factor for filter combination"); + } + else{ + gbl::correctionFactor = col4.ToDouble(); + } + break; + } + else{ + continue; + } + } + else { + continue; + } + } + else { + continue; + } + } + corrFact->Close(); + + // if no factor was found for instrument ID and filter combination + if(gbl::correctionFactor == 0.0){ + gbl::correctionFactor = 1.0; + // dividing by correction factor of 1.0 implies this correction is not performed + gbl::calgrp.FindKeyword("CorrectionFactorPerformed").SetValue("No: CorrectionFactorFile contained no factor for filter combination"); + } + gbl::calgrp += PvlKeyword("CorrectionFactor",gbl::correctionFactor); + return; +} +//=====End Correction Factor Methods=============================================================// + +/** + * This method returns an iString containing the path of a + * Cassini calibration directory + * + * @param calibrationType + * @return iString Path of the calibration directory + * + * @internal + * @history 2008-11-05 Jeannie Walldren - Original version + */ +iString gbl::GetCalibrationDirectory(string calibrationType){ + // Get the directory where the CISS calibration directories are. + PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory"); + iString missionDir = (string) dataDir["Cassini"]; + return missionDir + "/calibration/" + calibrationType + "/"; +} + diff --git a/isis/src/cassini/apps/cisscal/cisscal.xml b/isis/src/cassini/apps/cisscal/cisscal.xml new file mode 100644 index 0000000000000000000000000000000000000000..efb7a8988debe4d65807d771c27f99d9c6762b65 --- /dev/null +++ b/isis/src/cassini/apps/cisscal/cisscal.xml @@ -0,0 +1,467 @@ + + + + + + Radiometric correction of Cassini ISS camera images. + + + +

    + This program performs radiometric corrections on images acquired by the + Cassisi Imaging Science Subsystem (ISS) camera. It performs bitweight + correction, bias subtraction, dark subtraction, non-linearity correction, + flat field correction, DN to flux conversion, and correction factor + division. The user may choose between intensity units and I/F for the DN + to flux conversion. This application is derived from the IDL CISSCAL + application developed by the Cassini Imaging Central Laboratory for + Operations (CICLPOS) using the following set of steps: +

    +

    + + Step 1: Correct Bitweight + + This step is performed on images that do not have a data conversion + type of "Table" or compression type of "Lossy" due to loss of + information in these processses. This step is also skipped if the image + has a zero gain state due to the lack of data for this case. Bitweight + correction requires no user defined parameters. It uses a bitweight file + found in the Cassini calibration bitweight directory. +

    +

    + + Step 2: Subtract Bias + + This step defaults to a method that uses a line dependent bias. That + method derives the bias by performing a linear fit to an array of + overclocked pixels taken out of the binary prefix data and saved off by + the ciss2isis application. This method cannot be + performed if the image has a compression type of "Lossy". In that case, + the BiasStripMean value found in the Instrument Group of the cube's labels + is subtracted from every pixel. This alternative method cannot be + implemented if the instrument used was CAS-ISS3 or earlier since, + according to the SIS, the BiasStripMean keyword contains invalid data for + these images. Bias subtraction requires no user defined parameters. +

    +

    + + Step 3: Subtract Dark + + This step uses a spline interpolation to construct a dark image by + calculating, for each pixel, a duration to be used with the coefficients + found in the dark parmeter file. Dark current removal requires no user + defined parameters and should be performed on all images. It uses a dark + parameter file and if a narrow angle camera was used, a bias distortion + table. These are found in the Cassini calibration darkcurrent directory. +

    +

    + + Step 4: Linearize + + This step corrects for non-linearity. It requires no user defined + parameters and should be performed on all images. It uses a linearity + correction table found in the Cassini calibration linearize directory. +

    +

    + + Step 5: Correct Flat field + + This step consists of two parts: dust ring removal and division by flat + field. Dust ring removal only applies to images from + narrow angle cameras. This process masks a dust ring found on images and, + if the image has SummingMode equal to 1 (i.e. it is a full, 1024x1024 + image) and is recent (after 286th day of 2003), divides out a mottle map. + Flat field correction is applied to all images. During + this process, each pixel is divided by the average of the center of the + image. For SummingMode 2 or 4, the results from this method diverge from + the IDL results due to differences in the bilinear method used to expand + the flat file image. Flat field correction requires no user defined + parameters. If narrow angle, it uses a dust ring file found in the Cassini + calibration dustring directory. If narrow and full, it also uses a mottle + file and an effective wavelength file found in dustring and efficiency + directories. And, for any image a slope database and a flat file are used, + found in slope and slope/slope2flat directories. +

    +

    + + Step 6: Convert DN to Flux + + This step consists of 4 processes and the user must enter a value of + "intensity" or "I/F" for the parameter "fluxunits". In the first process, + DNs are converted to electrons by multiplying by the true + gain. Second, the image is divided by the exposure time, + correcting for shutter offset effect. Third, the image is + divided by the optics area and, if intensity units are + chosen, divided by the solid angle. In the last process, + each pixel is divided by an efficiency factor. This value + is dependent on the flux units chosen by the user: intensity units + (photons/cm2/s/nm/ster) or I/F (irradiance over solar flux). + If "I/F" is chosen, the input cube must have been run through the Isis3 + application spiceinit to be able to calculate Solar + Distance. The results from this method diverge from the IDL results due + to differences in the way they calculate solar distance. However, the DN + results are still within 0.2% after we divide by the efficiency factor. DN + to Flux conversion should be performed on all images. Converting DN to + flux units requires a shutter offset file, a spectral file (if I/F is + chosen), a transmission file, and a quantum efficiency correction file + found in the Cassini calibration offset, efficiency, efficiency/systrans + and correction directories. +

    +

    + + Step 7: Divide by Correction Factor + + This step is implemented in order to force theory and observation to match. + It consists of 2 processes. First, if polarized, (i.e. a filter value of + IRP0, IRP90, P0, P60, or P120) the image is divided by a polarization + factor. Next, the image is divided by its correction factor. This step + requires no user defined parameters. It uses a polarization factor file + and a correction factor file found in the Cassini calibration correction + directory. +

    +

    + + Omitted IDL Steps: + + In the original IDL program, there were 2 steps that were omitted in this + application since they act as noise removal that can be filtered using + other applications after calibration is complete. + + The first omitted step is 2-Hz noise removal. This is meant to + remove horizontal banding patterns introduced during image readout of + Cassini ISS images and has two peaks in the power spectrum near 2Hz. There + are two methods to this correction. The first method invovles the + smoothing and filtering of the overclocked pixel array, thus removing high + frequency random noise, slow-varying, and DC-offset components. The second + method requires large regions of dark sky pixels present for all lines and + uses an image mean to construct a 2-Hz signal. + + The second omited step is A-B pixel pairs correction + (also referred to as anti-blooming correction or bright/dark pixel pair + removal). In the IDL program, this correction is only performed if the + labels of the image indicate that the AntiBloomingStateFlag is "On" and + the InstrumentModeId is "Full" (i.e., SummingMode is 1). In this + correction, bright/dark pixel pairs are identified and replaced with a + boxcar average of their horizontal neighbors. +

    + + + + + + Original version + + + Fixed documentation. + + + Fixed bug in bitweight correction. Updated documentation. + + + Updated user documentation "Related Objects and Documents" section + document web links. + + + Fixed documentation. + + + Fixed bug that caused errors on other compilers. + + + Modified the "I/F" option to make 2 attempts to locate the the target + before throwing an exception. First, the Isis::Camera class is used to + look for the target at the center point of the cube. If this fails, the + subspacecraft point is used to find the target. Only if both fail will + the application throw an error. + + + Modified cisscal and its DarkCurrent class to reflect updates to the new + idl cisscal program version, 3.6. Updated documentation and app test to + reflect these changes. + + + + + Cassini + + + + + + ciss2isis + + + spiceinit + + + + + + Cassini ISS Software Interface Specification (SIS) + + + edrsis.pdf + http://pds-imaging.jpl.nasa.gov/data/cassini/cassini_orbiter/coiss_0011_v2/document/ + + Charles Avis and Carolyn Porco + Cassini Electronic Library + + + + CISSCAL User Guide + + + cisscal_manual.pdf + http://pds-imaging.jpl.nasa.gov/data/cassini/cassini_orbiter/coiss_0011_v2/document/ + + Planetary Data System Rings Node + + + + Cassini ISS Image Calibration: Theoretical Basis + + + theoretical_basis.pdf + http://pds-imaging.jpl.nasa.gov/data/cassini/cassini_orbiter/coiss_0011_v2/document/ + + R. West + Planetary Data System Rings Node + + + + Cassini ISS Calibration Report + + + + http://pds-imaging.jpl.nasa.gov/data/cassini/cassini_orbiter/coiss_0011_v2/document/report/ + + Cassini ISS Development Team + Planetary Data System Rings Node + + + + Cassini ISS Calibration Report: 7.0 Radiometric Calibration Steps + + + + http://pds-imaging.jpl.nasa.gov/data/cassini/cassini_orbiter/coiss_0011_v2/document/report/iss/7.0/7.0.html + + Alfred McEwen and James Winburn + Planetary Data System Rings Node + + + + + + + + cube + input + + Input Isis cube + + + Use this parameter to choose an Isis cube to be calibrated. To ensure + that it contains all needed keywords in its label, input cube should + have been imported using ciss2isis and, if "I/F" is chosen, input cube + must have been run through spiceinit application. + + + *.cub + + + + + cube + output + real + + Output Isis cube + + + Use this parameter to select the output filename of the calibrated + Isis cube. + + + *.cub + + + + + + string + Options for converted flux units + + A list of the types of units to which user may choose to convert from + DNs. + + INTENSITY + + + + + + + + + + Cube calibrated using intensity units. + + This example shows how to calibrate a Cassini ISS cube, converting to + intensity units. + + + + from=../IN/inputCube.cub to=../OUT/outputCube.cub + + + Run the cisscal application to calibrate the cube. + + + + + + Example Gui + + Screenshot of GUI with parameters filled in to perform the cisscal + application. Input and output cubes are always required. The + radio button INTENSITY is chosen as default. + + + + + + + + + Stats on output cube + + + This pvl file contains the results of the stats application run on + the example 1 output cube. This may be compared with the pvl file + of the same application run on the example 2 output cube. + + + FLUXUNITS + + + + + + + Input image + + + This is a Titan narrow-angle image that was imported into Isis cube + format using ciss2isis. + + + + FROM + + + + + + + Output image + + + This is the Titan narrow-angle image calibrated and converted to + intensity units. + + + + TO + + + + + + Cube calibrated using I/F. + + This example shows how to calibrate a Cassini ISS cube, converting to + I/F. + + + + from=../IN/inputCube.cub to=../OUT/outputCube.cub fluxunits="I/F" + + + Run the cisscal application to calibrate the cube. + + + + + + Example Gui + + Screenshot of GUI with parameters filled in to perform the cisscal + application. Input and output cubes are always required. The + radio button I/F is chosen. + + + + + + + + + Stats on output cube + + + This pvl file contains the results of the stats application run on + the example 2 output cube. This may be compared with the pvl file + of the same application run on the example 1 output cube. + + + FLUXUNITS + + + + + + + Input image + + + This is a Titan narrow-angle image that was imported into Isis cube + format using ciss2isis and run through spiceinit. + + + + FROM + + + + + + + Output image + + + This is the Titan narrow-angle image calibrated and converted to + I/F. + + + + TO + + + + + + diff --git a/isis/src/cassini/apps/cisscal/tsts/Makefile b/isis/src/cassini/apps/cisscal/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/cassini/apps/cisscal/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/cassini/apps/cisscal/tsts/nacLosslsTblGain1BotsimSum4_IoF/Makefile b/isis/src/cassini/apps/cisscal/tsts/nacLosslsTblGain1BotsimSum4_IoF/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..26480f48e15e9cc554ef5dd61c3c303fee90dcde --- /dev/null +++ b/isis/src/cassini/apps/cisscal/tsts/nacLosslsTblGain1BotsimSum4_IoF/Makefile @@ -0,0 +1,13 @@ +APPNAME = cisscal + +N1536363784_1.truth.cub.TOLERANCE = 1.0e-5 + +include $(ISISROOT)/make/isismake.tsts + + +commands: + $(APPNAME) from=$(INPUT)/N1536363784_1.c2i.spice.cub \ + to=$(OUTPUT)/N1536363784_1.truth.cub \ + flux="I/F" \ + > /dev/null; + catlab from=$(OUTPUT)/N1536363784_1.truth.cub >& $(OUTPUT)/labels.truth.pvl; diff --git a/isis/src/cassini/apps/cisscal/tsts/nacLsyTblGain3NonlySum2/Makefile b/isis/src/cassini/apps/cisscal/tsts/nacLsyTblGain3NonlySum2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..72cd0c70ce9db104105fd5b84485d3122ec3b3ed --- /dev/null +++ b/isis/src/cassini/apps/cisscal/tsts/nacLsyTblGain3NonlySum2/Makefile @@ -0,0 +1,10 @@ +APPNAME = cisscal + +include $(ISISROOT)/make/isismake.tsts + + +commands: + $(APPNAME) from=$(INPUT)/N1355543510_1.c2i.nospice.cub \ + to=$(OUTPUT)/N1355543510_1.truth.cub \ + > /dev/null; + catlab from=$(OUTPUT)/N1355543510_1.truth.cub >& $(OUTPUT)/labels.truth.pvl; diff --git a/isis/src/cassini/apps/cisscal/tsts/wacNotcompr12bitG2WonlyFull/Makefile b/isis/src/cassini/apps/cisscal/tsts/wacNotcompr12bitG2WonlyFull/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e687f0078cf5b5247082c37272fed590ae9748ad --- /dev/null +++ b/isis/src/cassini/apps/cisscal/tsts/wacNotcompr12bitG2WonlyFull/Makefile @@ -0,0 +1,10 @@ +APPNAME = cisscal + +include $(ISISROOT)/make/isismake.tsts + + +commands: + $(APPNAME) from=$(INPUT)/W1294561261_1.c2i.nospice.cub \ + to=$(OUTPUT)/W1294561261_1.truth.cub \ + > /dev/null; + catlab from=$(OUTPUT)/W1294561261_1.truth.cub >& $(OUTPUT)/labels.truth.pvl; diff --git a/isis/src/cassini/apps/vims2isis/Makefile b/isis/src/cassini/apps/vims2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/cassini/apps/vims2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/cassini/apps/vims2isis/tsts/Makefile b/isis/src/cassini/apps/vims2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/cassini/apps/vims2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/cassini/apps/vims2isis/tsts/calibrated/Makefile b/isis/src/cassini/apps/vims2isis/tsts/calibrated/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..74881ef1c3858232cc8b17c605d333d27faff5c4 --- /dev/null +++ b/isis/src/cassini/apps/vims2isis/tsts/calibrated/Makefile @@ -0,0 +1,8 @@ +APPNAME = vims2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/CM_1514284191_1.cub \ + vis=$(OUTPUT)/vimsVisTruth.cub \ + ir=$(OUTPUT)/vimsIrTruth.cub > /dev/null; diff --git a/isis/src/cassini/apps/vims2isis/tsts/uncalibrated/Makefile b/isis/src/cassini/apps/vims2isis/tsts/uncalibrated/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5397ae1df5f784accf8e259c84c48eb032f0578b --- /dev/null +++ b/isis/src/cassini/apps/vims2isis/tsts/uncalibrated/Makefile @@ -0,0 +1,8 @@ +APPNAME = vims2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/v1545949478_1.qub \ + vis=$(OUTPUT)/vimsVisTruth.cub \ + ir=$(OUTPUT)/vimsIrTruth.cub > /dev/null; diff --git a/isis/src/cassini/apps/vims2isis/vims2isis.cpp b/isis/src/cassini/apps/vims2isis/vims2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4338c1ae38007a7c8f4997e10c1a7fb75174221b --- /dev/null +++ b/isis/src/cassini/apps/vims2isis/vims2isis.cpp @@ -0,0 +1,534 @@ +#include "Isis.h" +#include "EndianSwapper.h" +#include "ProcessImportPds.h" +#include "ProcessByLine.h" +#include "Filename.h" +#include "UserInterface.h" +#include "Filename.h" +#include "Pvl.h" +#include "iException.h" +#include "iString.h" +#include "Brick.h" +#include "Table.h" + +#include +#include + +using namespace std; +using namespace Isis; + +typedef struct { + int mi32OrigBandStart; + int mi32OrigBinEnd; + int mi32BandCenterStart; + int mi32BandCenterEnd; + int mi32NaifFrameCode; +}VIMS; + +enum VimsType { VIS, IR }; + +void ReadVimsBIL(std::string inFile, const PvlKeyword &suffixItems, std::string outFile); +void TranslateVimsLabels (Pvl &pdsLab, Cube *vimscube, VimsType vType); +void ProcessCube (Buffer &in, Buffer &out); +void ProcessBands(Pvl &pdsLab, Cube *vimscube, VimsType vtype); + +//*********************************************************************** +// IsisMain() +//*********************************************************************** +void IsisMain () +{ + UserInterface &ui = Application::GetUserInterface(); + Filename in = ui.GetFilename("FROM"); + Filename outIr = ui.GetFilename("IR"); + Filename outVis = ui.GetFilename("VIS"); + Pvl lab(in.Expanded()); + + //Checks if in file is rdr + if( lab.HasObject("IMAGE_MAP_PROJECTION") ) { + string msg = "[" + in.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + //Make sure it is a vims cube + try { + PvlObject qube(lab.FindObject("QUBE")); + iString id; + id = (string)qube["INSTRUMENT_ID"]; + id.ConvertWhiteSpace(); + id.Compress(); + id.Trim(" "); + if (id != "VIMS") { + string msg = "Invalid INSTRUMENT_ID [" + id + "]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + } + catch (iException &e) { + string msg = "Input file [" + in.Expanded() + + "] does not appear to be " + + "in VIMS EDR/RDR format"; + throw iException::Message(iException::Io,msg,_FILEINFO_); + } + + Filename tempname = in.Basename() + ".bsq.cub"; + Pvl pdsLab(in.Expanded()); + + // It's VIMS, let's figure out if it has the suffix data or not + if ((int)lab.FindObject("QUBE")["SUFFIX_ITEMS"][0] == 0) { + // No suffix data, we can use processimportpds + ProcessImportPds p; + + p.SetPdsFile (in.Expanded(), "", pdsLab); + // Set up the temporary output cube + //The temporary cube is set to Real pixeltype, regardless of input pixel type + Isis::CubeAttributeOutput outatt = CubeAttributeOutput("+Real"); + p.SetOutputCube(tempname.Name(),outatt); + p.StartProcess(); + p.EndProcess(); + } + else { + // We do it the hard way + ReadVimsBIL(in.Expanded(), lab.FindObject("QUBE")["SUFFIX_ITEMS"], tempname.Name()); + } + + //Now separate the cubes + ProcessByLine l; + + PvlGroup status("Results"); + + //VIS cube + const PvlObject &qube = lab.FindObject("Qube"); + if(qube["SAMPLING_MODE_ID"][1] != "N/A") { + CubeAttributeInput inattvis = CubeAttributeInput("+1-96"); + l.SetInputCube(tempname.Name(),inattvis); + Cube *oviscube = l.SetOutputCube("VIS"); + l.StartProcess(ProcessCube); + TranslateVimsLabels(pdsLab, oviscube, VIS); + l.EndProcess(); + + status += PvlKeyword("VisCreated", "true"); + } + else { + status += PvlKeyword("VisCreated", "false"); + } + + //IR cube + if(qube["SAMPLING_MODE_ID"][0] != "N/A") { + CubeAttributeInput inattir = CubeAttributeInput("+97-352"); + l.SetInputCube(tempname.Name(),inattir); + Cube *oircube = l.SetOutputCube("IR"); + l.StartProcess(ProcessCube); + TranslateVimsLabels(pdsLab, oircube, IR); + l.EndProcess(); + status += PvlKeyword("IrCreated", "true"); + } + else { + status += PvlKeyword("IrCreated", "false"); + } + + Application::Log(status); + + //Clean up + string tmp(tempname.Expanded()); + remove(tmp.c_str()); +} + +/** + * We created a method to manually skip the suffix and corner + * data for this image to avoid implementing it in + * ProcessImport and ProcessImportPds. To fully support this + * file format, we would have to re-implement the ISIS2 Cube + * IO plus add prefix data features to it. This is a shortcut; + * because we know these files have one sideplane and four + * backplanes, we know how much data to skip when. This should + * be fixed if we ever decide to fully support suffix and + * corner data, which would require extensive changes to + * ProcessImport/ProcessImportPds. Method written by Steven + * Lambright. + * + * @param inFilename Filename of the input file + * @param outFile Filename of the output file + */ +void ReadVimsBIL(std::string inFilename, const PvlKeyword &suffixItems, std::string outFile) { + Isis::PvlGroup &dataDir = Isis::Preference::Preferences().FindGroup("DataDirectory"); + string transDir = (string) dataDir["Base"]; + + Pvl pdsLabel(inFilename); + Isis::Filename transFile (transDir + "/" + "translations/pdsQube.trn"); + Isis::PvlTranslationManager pdsXlater (pdsLabel, transFile.Expanded()); + + + TableField sideplaneLine("Line", Isis::TableField::Integer); + TableField sideplaneBand("Band", Isis::TableField::Integer); + TableField sideplaneValue("Value", Isis::TableField::Integer); + + TableRecord record; + record += sideplaneLine; + record += sideplaneBand; + record += sideplaneValue; + Table sideplaneVisTable("SideplaneVis", record); + Table sideplaneIrTable("SideplaneIr", record); + + sideplaneVisTable.SetAssociation(Table::Lines); + sideplaneIrTable.SetAssociation(Table::Lines); + + Isis::iString str; + str = pdsXlater.Translate ("CoreBitsPerPixel"); + int bitsPerPixel = str.ToInteger(); + str = pdsXlater.Translate ("CorePixelType"); + PixelType pixelType = Isis::Real; + + if ((str == "Real") && (bitsPerPixel == 32)) { + pixelType = Isis::Real; + } + else if ((str == "Integer") && (bitsPerPixel == 8)) { + pixelType = Isis::UnsignedByte; + } + else if ((str == "Integer") && (bitsPerPixel == 16)) { + pixelType = Isis::SignedWord; + } + else if ((str == "Integer") && (bitsPerPixel == 32)) { + pixelType = Isis::SignedInteger; + } + else if ((str == "Natural") && (bitsPerPixel == 8)) { + pixelType = Isis::UnsignedByte; + } + else if ((str == "Natural") && (bitsPerPixel == 16)) { + pixelType = Isis::UnsignedWord; + } + else if ((str == "Natural") && (bitsPerPixel == 16)) { + pixelType = Isis::SignedWord; + } + else if ((str == "Natural") && (bitsPerPixel == 32)) { + pixelType = Isis::UnsignedInteger; + } + else { + string msg = "Invalid PixelType and BitsPerPixel combination [" + str + + ", " + Isis::iString(bitsPerPixel) + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + str = pdsXlater.Translate ("CoreByteOrder"); + Isis::ByteOrder byteOrder = Isis::ByteOrderEnumeration(str); + + str = pdsXlater.Translate ("CoreSamples", 0); + int ns = str.ToInteger(); + str = pdsXlater.Translate ("CoreLines", 2); + int nl = str.ToInteger(); + str = pdsXlater.Translate ("CoreBands", 1); + int nb = str.ToInteger(); + + std::vector baseList; + std::vector multList; + + str = pdsXlater.Translate ("CoreBase"); + baseList.clear(); + baseList.push_back(str.ToDouble()); + str = pdsXlater.Translate ("CoreMultiplier"); + multList.clear(); + multList.push_back(str.ToDouble()); + + Cube outCube; + outCube.SetPixelType(Isis::Real); + outCube.SetDimensions(ns,nl,nb); + outCube.Create(outFile); + + // Figure out the number of bytes to read for a single line + int readBytes = Isis::SizeOf (pixelType); + readBytes = readBytes * ns; + char *in = new char [readBytes]; + + // Set up an Isis::EndianSwapper object + Isis::iString tok(Isis::ByteOrderName(byteOrder)); + tok.UpCase(); + Isis::EndianSwapper swapper (tok); + + ifstream fin; + // Open input file + Isis::Filename inFile(inFilename); + fin.open (inFilename.c_str(), ios::in|ios::binary); + if (!fin.is_open()) { + string msg = "Cannot open input file [" + inFilename + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // Handle the file header + streampos pos = fin.tellg(); + int fileHeaderBytes = (int)(iString)pdsXlater.Translate("DataFileRecordBytes") * + ((int)(iString)pdsXlater.Translate ("DataStart", 0) - 1); + + fin.seekg (fileHeaderBytes, ios_base::beg); + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + inFilename + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(fileHeaderBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + // Construct a line buffer manager + Isis::Brick out(ns, 1, 1, Isis::Real); + + // Loop for each line + for (int line=0; line 1) { + base = baseList[band]; + mult = multList[band]; + } + else { + base = baseList[0]; + mult = multList[0]; + } + + // Get a line of data from the input file + pos = fin.tellg(); + fin.read (in, readBytes); + + if (!fin.good ()) { + string msg = "Cannot read file [" + inFilename + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(readBytes) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + // Swap the bytes if necessary and convert any out of bounds pixels + // to special pixels + for (int samp=0; samp= 4095) { + out[samp] = Isis::His; + } + } + } + else { + record[1] = (band+1) - 96; + sideplaneIrTable += record; + + // set HIS pixels appropriately + for(int samp = 0; samp < ns; samp++) { + if(out[samp] + suffixData >= 4095) { + out[samp] = Isis::His; + } + } + } + + delete [] sideplaneData; + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + inFilename + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(4) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + } + } // End band loop + + int backplaneSize = (int)suffixItems[1] * (4*(ns + (int)suffixItems[0])); + fin.seekg (backplaneSize, ios_base::cur); + + // Check the last io + if (!fin.good ()) { + string msg = "Cannot read file [" + inFilename + "]. Position [" + + Isis::iString((int)pos) + "]. Byte count [" + + Isis::iString(4 * (4*ns + 4)) + "]" ; + throw Isis::iException::Message(Isis::iException::Io,msg, _FILEINFO_); + } + + } // End line loop + + outCube.Write(sideplaneVisTable); + outCube.Write(sideplaneIrTable); + + // Close the file and clean up + fin.close (); + outCube.Close(); + delete [] in; +} + +//************************************************************ +// Name: ProcessCube +// +// Description: Function to copy cube from input to ouput +// +// Parameters: Buffer &in - Input Cube +// Buffer &out - Output Cube +// +// Return: None +//************************************************************ +void ProcessCube (Buffer &in, Buffer &out){ + for (int i=0;iBands(); + vims.mi32BandCenterStart = 0; + vims.mi32BandCenterEnd = 96; + vims.mi32NaifFrameCode = -82370; + } + else if (vtype==IR) { + vims.mi32OrigBandStart = 97; + vims.mi32OrigBinEnd = 352; + vims.mi32BandCenterStart = 96; + vims.mi32BandCenterEnd = 352; + vims.mi32NaifFrameCode = -82371; + } + PvlObject qube(pdsLab.FindObject("Qube")); + + //Create the BandBin Group + PvlGroup bandbin("BandBin"); + PvlKeyword originalBand("OriginalBand"); + for (int i=vims.mi32OrigBandStart; i <= vims.mi32OrigBinEnd; i++) { + originalBand.AddValue(i); + } + bandbin += originalBand; + PvlKeyword center("Center"); + PvlGroup bbin(qube.FindGroup("BandBin")); + for (int i=vims.mi32BandCenterStart; i < vims.mi32BandCenterEnd; i++) { + center += (string) bbin["BandBinCenter"][i]; + } + bandbin += center; + + vimsCube->PutGroup(bandbin); + + //Create the Kernels Group + PvlGroup kern("Kernels"); + kern += PvlKeyword("NaifFrameCode",vims.mi32NaifFrameCode); + vimsCube->PutGroup(kern); +} + +//************************************************************ +// Name: TranslateVimsLabels +// +// Description: Function to translate Vims label for both IR +// & VIS cubes +// +// Parameters: Pvl & pdsLab - Label +// Cube *vimsCube - output VIS/IR cubes +// VimsType vType - VIS / IR +// +// History: 2009-10-20 Tracie Sucharski, Corrected indices for +// SAMPLING_MODE_ID and GAIN_MODE_ID. +// +// Return: None +//************************************************************ +void TranslateVimsLabels (Pvl &pdsLab, Cube *vimscube, VimsType vType){ + + Isis::PvlGroup &dataDir = Isis::Preference::Preferences().FindGroup("DataDirectory"); + string transDir = (string) dataDir["Cassini"]; + + Isis::Filename transFile (transDir + "/" + "translations/vimsPds.trn"); + PvlObject qube(pdsLab.FindObject("Qube")); + Pvl pdsLabel(pdsLab); + Isis::PvlTranslationManager labelXlater (pdsLabel, transFile.Expanded()); + + Pvl outputLabel; + labelXlater.Auto(outputLabel); + + //Add needed keywords that are not in translation table to cube's instrument group + PvlGroup &inst = outputLabel.FindGroup("Instrument", Pvl::Traverse); + + //trim start and stop time + string strTime=inst.FindKeyword("StartTime")[0]; + inst.FindKeyword("StartTime").SetValue((string)((iString)strTime).Trim("Z")); + strTime = (string)qube["StopTime"]; + inst.FindKeyword("StopTime").SetValue((string)((iString)strTime).Trim("Z")); + + if (vType == IR) { + inst += PvlKeyword("SamplingMode", (string)qube["SamplingModeId"][0]); + } + else { + inst += PvlKeyword("SamplingMode", (string)qube["SamplingModeId"][1]); + } + if (vType == VIS) { + inst += PvlKeyword("Channel", "VIS"); + } + else{ + inst += PvlKeyword("Channel", "IR"); + } + + PvlKeyword expDuration("ExposureDuration"); + expDuration.AddValue(qube["ExposureDuration"][0],"IR"); + expDuration.AddValue(qube["ExposureDuration"][1],"VIS"); + inst += expDuration; + + if (vType == IR) { + inst += PvlKeyword("GainMode", (string)qube["GainModeId"][0]); + } + else { + inst += PvlKeyword("GainMode", (string)qube["GainModeId"][1]); + } + + vimscube->PutGroup(inst); + + //Get Archive + PvlGroup &archive = outputLabel.FindGroup("Archive", Pvl::Traverse); + vimscube->PutGroup(archive); + + ProcessBands(pdsLab, vimscube, vType); +} diff --git a/isis/src/cassini/apps/vims2isis/vims2isis.xml b/isis/src/cassini/apps/vims2isis/vims2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..57ce67ac18bcc88452e245045806bc4339a3e1cc --- /dev/null +++ b/isis/src/cassini/apps/vims2isis/vims2isis.xml @@ -0,0 +1,114 @@ + + + + + + Converts Vims images to Isis 3 format + + + + This program takes the BIL formatted vims cubes and translates them into Isis 3 + standard BSQ format. It also separates them into two cubes, one containing the + data from the Infrared camera, and one containing the data from the visual camera. + + + + + Original version + + + Fixed Start Time and Stop Time output + + + Added Spacecraft Clock Start and Stop Time keywords to label output + + + Fixed bug with exposure duration, was written out to labels as string + instead of numeric. + + + Fixed bug with exposure duration in Vis cube labels + + + Added appTests and enabled importing of uncalibrated data + + + Fixed importing of uncalibrated data + + + Checks if input file is rdr. + + + Removed references to CubeInfo + + + Added support for more raw data + + + If sideplane data is present it is now stored in the output cubes + for calibration. More keywords are now propagated. + + + Saturation values are now set when present and if IR or VIS + was turned off then files will not be imported for those channels. + + + Added the ability to translate Vims label for both IR and VIS + cubes + + + Corrected indexing for SAMPLING_MODE_ID and GAIN_MODE_ID values. + + + Changed DATA_SET_ID check to be INSTRUMENT_ID check instead, + DATA_SET_ID was too specific and wasn't allowing imports of + appropriate data. + + + + Cassini + + + + + + filename + input + + The input Vims image + + + This is the input image to be processed. It is 352 bands deep, the first 96 of + which are visual data, and the final 256 of which are IR data. + + *.qub *.cub + + + + cube + output + + Visual output cube + + + This is the destination for the cube containing the visual light data. It consists + of the first 96 bands of the original cube, reorganized into BSQ format + + *.cub + + + + cube + output + + IR output cube + + + This is the destination for the cube containing the IR data. It consists + of the final 256 bands of the original cube, reorganized into BSQ format + + *.cub + + + + diff --git a/isis/src/cassini/apps/vims2map/Makefile b/isis/src/cassini/apps/vims2map/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/cassini/apps/vims2map/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/cassini/apps/vims2map/tsts/Makefile b/isis/src/cassini/apps/vims2map/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/cassini/apps/vims2map/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/cassini/apps/vims2map/tsts/default/Makefile b/isis/src/cassini/apps/vims2map/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..04df129620da99992a0aab4738d57f510af963dd --- /dev/null +++ b/isis/src/cassini/apps/vims2map/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = vims2map + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/fileList.txt; + $(APPNAME) fromlist= $(OUTPUT)/fileList.txt \ + to=$(OUTPUT)/vims2mapTruth.cub > /dev/null; + $(RM) $(OUTPUT)/fileList.txt; diff --git a/isis/src/cassini/apps/vims2map/tsts/mpp/Makefile b/isis/src/cassini/apps/vims2map/tsts/mpp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e10c113400121e8a3377fa62296ee6a7036cf283 --- /dev/null +++ b/isis/src/cassini/apps/vims2map/tsts/mpp/Makefile @@ -0,0 +1,11 @@ +APPNAME = vims2map + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/fileList.txt; + $(APPNAME) fromlist= $(OUTPUT)/fileList.txt \ + to= $(OUTPUT)/vims2map-mpp-truth.cub \ + pixres=mpp resolution=100 \ + defaultrange=camera > /dev/null; + $(RM) $(OUTPUT)/fileList.txt; diff --git a/isis/src/cassini/apps/vims2map/vims2map.cpp b/isis/src/cassini/apps/vims2map/vims2map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58b213ee0dd73e4b004f7f6353b5c24241f25fa7 --- /dev/null +++ b/isis/src/cassini/apps/vims2map/vims2map.cpp @@ -0,0 +1,329 @@ +#define GUIHELPERS + +#include "Isis.h" +#include "Camera.h" +#include "ProcessByBrick.h" +#include "ProcessGroundPolygons.h" +#include "FileList.h" +#include "ProjectionFactory.h" +#include "ProcessRubberSheet.h" + +#include "iException.h" +#include "vims2map.h" + +using namespace std; +using namespace Isis; + +void PrintMap (); +void rasterizeVims(Isis::Buffer &in); +std::vector vimsValues; + +map GuiHelpers(){ + map helper; + helper ["PrintMap"] = (void*) PrintMap; + return helper; +} + +// Global variables +ProcessGroundPolygons g_pgp; +UniversalGroundMap *g_groundMap; +int g_bands; + +void IsisMain() { + + ProcessRubberSheet p; + Camera *incam = NULL; + Cube *icube; + + // Get the map projection file provided by the user + UserInterface &ui = Application::GetUserInterface(); + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + FileList list; + list.Read(ui.GetFilename("FROMLIST")); + if (list.size() < 1) { + string msg = "The list file [" + ui.GetFilename("FROMLIST") + + "does not contain any data"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + double newminlat, newmaxlat, newminlon, newmaxlon; + double minlat = 90; + double maxlat = -90; + double minlon = 360.0; + double maxlon = 0; + PvlGroup camGrp; + PvlGroup bandBinGrp; + string lastBandString; + + //Loop thru each file in the FROMLIST + for(unsigned int i = 0; iBands(); + incam = icube->Camera(); + + // Make sure it is not the sky + if (incam->IsSky()) { + string msg = "The image [" + list[i] + + "] is targeting the sky, use skymap instead."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Make sure all the bands for all the files match + if( i>1 && atts0.BandsStr() != lastBandString) { + string msg = "The Band numbers for all the files do not match."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } else { + lastBandString = atts0.BandsStr(); + } + + // Get the mapping group and the BandBin group + Pvl camMap; + incam->BasicMapping(camMap); + camGrp = camMap.FindGroup("Mapping"); + if(icube->HasGroup("BandBin")) { + bandBinGrp = icube->GetGroup("BandBin"); + + } + + incam->GroundRange(newminlat,newmaxlat,newminlon,newmaxlon,userMap); + //set min lat/lon + if(newminlat < minlat) { + minlat = newminlat; + } + if(newminlon < minlon) { + minlon = newminlon; + } + + //set max lat/lon + if(newmaxlat > maxlat) { + maxlat = newmaxlat; + } + if(newmaxlon > maxlon) { + maxlon = newmaxlon; + } + } //end for list.size + + camGrp.AddKeyword(PvlKeyword("MinimumLatitude",minlat),Pvl::Replace); + camGrp.AddKeyword(PvlKeyword("MaximumLatitude",maxlat),Pvl::Replace); + camGrp.AddKeyword(PvlKeyword("MinimumLongitude",minlon),Pvl::Replace); + camGrp.AddKeyword(PvlKeyword("MaximumLongitude",maxlon),Pvl::Replace); + + + // We want to delete the keywords we just added if the user wants the range + // out of the mapfile, otherwise they will replace any keywords not in the + // mapfile + if (ui.GetString("DEFAULTRANGE") == "MAP") { + camGrp.DeleteKeyword("MinimumLatitude"); + camGrp.DeleteKeyword("MaximumLatitude"); + camGrp.DeleteKeyword("MinimumLongitude"); + camGrp.DeleteKeyword("MaximumLongitude"); + } + // Otherwise, remove the keywords from the map file so the camera keywords + // will be propogated correctly + else { + while (userGrp.HasKeyword("MinimumLatitude")) { + userGrp.DeleteKeyword("MinimumLatitude"); + } + while (userGrp.HasKeyword("MinimumLongitude")) { + userGrp.DeleteKeyword("MinimumLongitude"); + } + while (userGrp.HasKeyword("MaximumLatitude")) { + userGrp.DeleteKeyword("MaximumLatitude"); + } + while (userGrp.HasKeyword("MaximumLongitude")) { + userGrp.DeleteKeyword("MaximumLongitude"); + } + } + + // If the user decided to enter a ground range then override + if (ui.WasEntered("MINLON")) { + userGrp.AddKeyword(PvlKeyword("MinimumLongitude", + ui.GetDouble("MINLON")),Pvl::Replace); + } + + if (ui.WasEntered("MAXLON")) { + userGrp.AddKeyword(PvlKeyword("MaximumLongitude", + ui.GetDouble("MAXLON")),Pvl::Replace); + } + + if (ui.WasEntered("MINLAT")) { + userGrp.AddKeyword(PvlKeyword("MinimumLatitude", + ui.GetDouble("MINLAT")),Pvl::Replace); + } + + if (ui.WasEntered("MAXLAT")) { + userGrp.AddKeyword(PvlKeyword("MaximumLatitude", + ui.GetDouble("MAXLAT")),Pvl::Replace); + } + + // If they want the res. from the mapfile, delete it from the camera so + // nothing gets overriden + if (ui.GetString("PIXRES") == "MAP") { + camGrp.DeleteKeyword("PixelResolution"); + } + // Otherwise, delete any resolution keywords from the mapfile so the camera + // info is propogated over + else if (ui.GetString("PIXRES") == "CAMERA") { + if (userGrp.HasKeyword("Scale")) { + userGrp.DeleteKeyword("Scale"); + } + if (userGrp.HasKeyword("PixelResolution")) { + userGrp.DeleteKeyword("PixelResolution"); + } + } + + // Copy any defaults that are not in the user map from the camera map file + for (int k=0; kIntersectsLongitudeDomain(userMap)) { + if (ui.GetString("LONSEAM") == "AUTO") { + if ((int) userGrp["LongitudeDomain"] == 360) { + userGrp.AddKeyword(PvlKeyword("LongitudeDomain",180), + Pvl::Replace); + if (incam->IntersectsLongitudeDomain(userMap)) { + // Its looks like a global image so switch back to the + // users preference + userGrp.AddKeyword(PvlKeyword("LongitudeDomain",360), + Pvl::Replace); + } + } + else { + userGrp.AddKeyword(PvlKeyword("LongitudeDomain",360), + Pvl::Replace); + if (incam->IntersectsLongitudeDomain(userMap)) { + // Its looks like a global image so switch back to the + // users preference + userGrp.AddKeyword(PvlKeyword("LongitudeDomain",180), + Pvl::Replace); + } + } + // Make the target info match the new longitude domain + double minlat,maxlat,minlon,maxlon; + incam->GroundRange(minlat,maxlat,minlon,maxlon,userMap); + userGrp.AddKeyword(PvlKeyword("MinimumLatitude",minlat),Pvl::Replace); + userGrp.AddKeyword(PvlKeyword("MaximumLatitude",maxlat),Pvl::Replace); + userGrp.AddKeyword(PvlKeyword("MinimumLongitude",minlon),Pvl::Replace); + userGrp.AddKeyword(PvlKeyword("MaximumLongitude",maxlon),Pvl::Replace); + } + + else if (ui.GetString("LONSEAM") == "ERROR") { + string msg = "The image [" + ui.GetFilename("FROM") + "] crosses the " + + "longitude seam"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + } + + + Pvl pvl; + pvl.AddGroup(userGrp); + pvl.AddGroup(bandBinGrp); + g_pgp.SetOutputCube("TO", pvl, g_bands); + + for (unsigned int f = 0; fSetText("Working on file: " + list[f]); + pbb.SetBrickSize(1,1,g_bands); + CubeAttributeInput atts0(list[f]); + pbb.SetInputCube(list[f], atts0, 0); + pbb.StartProcess(rasterizeVims); + pbb.EndProcess(); + } + g_pgp.EndProcess(); + + +} + +// Helper function to print out mapfile to session log +void PrintMap() { + UserInterface &ui = Application::GetUserInterface(); + + // Get mapping group from map file + Pvl userMap; + userMap.Read(ui.GetFilename("MAP")); + PvlGroup &userGrp = userMap.FindGroup("Mapping",Pvl::Traverse); + + //Write map file out to the log + Isis::Application::GuiLog(userGrp); +} + +void rasterizeVims (Isis::Buffer &in) { + + std::vectorlat, lon; + std::vectorvimsValues; + + for(int i = 0; i vimsSamps, vimsLines; + vimsSamps.push_back(s-0.5); + vimsSamps.push_back(s+0.5); + vimsSamps.push_back(s+0.5); + vimsSamps.push_back(s-0.5); + + vimsLines.push_back(l-0.5); + vimsLines.push_back(l-0.5); + vimsLines.push_back(l+0.5); + vimsLines.push_back(l+0.5); + + //Now need to convert all samps and lines to lat lon. + for (unsigned int j = 0; jSetImage(vimsSamps[j], vimsLines[j])) { + double latitude, longitude; + + latitude = g_groundMap->UniversalLatitude(); + longitude = g_groundMap->UniversalLongitude(); + lat.push_back(latitude); + lon.push_back(longitude); + } + + } + + if (lat.size() > 3) { + g_pgp.Rasterize(lat, lon, vimsValues); + } + + lat.clear(); + lon.clear(); + vimsSamps.clear(); + vimsLines.clear(); +} diff --git a/isis/src/cassini/apps/vims2map/vims2map.h b/isis/src/cassini/apps/vims2map/vims2map.h new file mode 100644 index 0000000000000000000000000000000000000000..8612530513afd1619db05b149fda35d1c5fda6b5 --- /dev/null +++ b/isis/src/cassini/apps/vims2map/vims2map.h @@ -0,0 +1,23 @@ +#ifndef vims2map_h +#define vims2map_h + +#include "Transform.h" + +class vims2map : public Isis::Transform { + private: + Isis::Camera *p_incam; + Isis::Projection *p_outmap; + + public: + // constructor + vims2map (const int inputSamples, const int inputLines, Isis::Camera *incam, + const int outputSamples, const int outputLines, Isis::Projection *outmap, + bool trim); + + // destructor + ~vims2map () {}; + + +}; + +#endif diff --git a/isis/src/cassini/apps/vims2map/vims2map.xml b/isis/src/cassini/apps/vims2map/vims2map.xml new file mode 100644 index 0000000000000000000000000000000000000000..1cbe1f274188fea9123a60fdc0c0bd440990f238 --- /dev/null +++ b/isis/src/cassini/apps/vims2map/vims2map.xml @@ -0,0 +1,410 @@ + + + + + Convert vims image to a map projection + + + + This program converts a cube in camera coordinates to a map projection. The input cube requires SPICE data and therefore + the program "spiceinit" should be run on it prior to "vims2map". The map + projection is defined using a PVL file specificied through the MAP + parameter. The system default is to use the Sinusoidal projection + ($ISIS3DATA/base/templates/maps/sinusoidal.map). + +

    If you need to generate your own map file you can use the "maptemplate" program or alternatively, hand create a file using your favorite editor. + The map file need only specify the ProjectionName as defaults will be computed for the remaining map file parameters. The following table + indicates how the defaults are established: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PARAMETERDEFAULT
    TargetNameRead from Instrument group in the input cube labels
    EquatorialRadius
    PolarRadius
    Read from SPICE pck file set during spiceinit. The pck file is defined in the Kernels group via the TargetAttitudeShape keyword
    LatitudeTypePlanetocentric
    LongitudeDirectionPositiveEast
    LongitudeDomainNormally, 360. However, if the cube crosses the longitude boundary the value will change to 180
    MinimumLatitude
    MaximumLatitude
    MinimumLongitude
    MaximumLongitude
    Computed from the input cube or read from the map file. However, any combination of the four values can then be overridden by the user
    PixelResolution
    Scale
    Computed from the input cube or read from the map file. The value can be overridden by the user.
    + +

    + If you only entered the input cube (FROM) and output cube (TO) and changed no other parameters the following is the default Mapping group: +

    +
    +  Group = Mapping
    +    TargetName             = Obtained from the Instrument group
    +    EquatorialRadius       = Obtained from TargetAttitudeShape kernel
    +    PolarRadius            = Obtained from TargetAttitudeShape kernel
    +
    +    LatitudeType           = Planetocentric
    +    LongitudeDirection     = PositiveEast
    +    LongitudeDomain        = 360 (Could be automatically adjusted to 180 by LONSEAM)
    +
    +    MinimumLatitude        = Computed from the input camera cube
    +    MaximumLatitude        = Computed from the input camera cube
    +    MinimumLongitude       = Computed from the input camera cube
    +    MaximumLongitude       = Computed from the input camera cube
    +
    +    ProjectionName         = Sinusodial
    +    CenterLongitude        = Average of MinimumLongitude and MaximumLongitude
    +    PixelResolution        = Computed from the input camera cube
    +  EndGroup
    +    
    + + Note that an important concept here is the map file can come from an existing map projected cube. + Because the cube has PVL labels and contains the Mapping group, you can essentially force + the input camera cube to have the same mapping parameters and/or selectively use some of the components of the cube's mapping group. + +

    If you are attempting to construct a mosaic, it is important that the PixelResolution, EquatorialRadius, PolarRadius, LatitudeType, + LongitudeDirection, LongitudeDomain, ProjectionName, and projection specific parameters (e.g., CenterLongitude, CenterLatitude) are the same for all cubes. That is, you should + create one map file and use it as input for all the cubes in your mosaic. + However, the ground range (MinimumLatitude, MaximumLatitude, MinimumLongitude, MaximumLongitude) should not be entered or you will create projected images + with large amounts of NULL pixels. The following Mapping group could be used for mosaicking: +

    +
    + Group = Mapping
    +   ProjectionName         = Sinusodial
    +   CenterLongitude        = 0
    +   PixelResolution        = 100 <meters>
    + EndGroup
    +   
    + +

    + Finally, depending on the projection, problems can occur with cubes that fall on the projection longitude seam. For example, if you are making a mosaic with LongitudeDomain = 360 and + your cube crosses 0/360 seam, this program would compute the default longitude range of the cube to MinimumLongitude = 0 and MaximumLongitude = 360. A very large output image + could be created depending on the pixel resolution. The LONSEAM parameter allows you to selectively handle this case. If you are making mosaics near the seam you will need to + understand and alter the default for this parameter. +

    +
    + + + Cassini + + + + + Original version + + + Removed references to CubeInfo + + + Fixed parameter names + + + + + lev1tolev2 + plansinu + planorth + + + + + + filename + input + + List of cubes to map + + + A list of map projected cubes to + + + *.txt *.lis *.lst + + + + + filename + input + + File containing mapping parameters + + $base/templates/maps + $base/templates/maps/sinusoidal.map + + A file containing the desired output mapping parameters in PVL form. This + file can be a simple hand produced label file. It can also be an existing cube label + which contains a Mapping group. You can produce map file using the "maptemplate" program. + + + + PrintMap + View MapFile + + This helper button will cat out the mapping group of the given mapfile to the session log + of the application + + $ISIS3DATA/base/icons/labels.png + + + + *.map *.cub + + + + + cube + output + real + + Newly mapped cube + + + This file will contain the map projected image. + + + *.cub + + + + + + + string + Defines how the pixel resolution in the output map file is obtained + CAMERA + + This parameter is used to specify how the pixel resolution is obtained for the output map + projected cube. + + + + + + + + + + + + + + double + Pixel resolution + + Specifies the resolution in either meters per pixel or pixels per degree + + 0.0 + + + + + + string + Defines how the default ground range is determined + MINIMIZE + + This parameter is used to specify how the default latitude/longitude ground range for the output map projected image + is obtained. The ground range can be obtained from the camera or map file. Note the user can overide the default using the MINLAT, MAXLAT, MINLON, MAXLON parameters. + The purpose of the ground range is to define the coverage of the map projected image. Essentially, the ground range and + pixel resolution are used to compute the size (samples and line) of the output image. + + + + + + + + + + + + + double + Starting latitude + Use default range + + The minimum latitude of the ground range. If this is entered by the user it will override the default camera or map value. By default, + planetocentric latitudes are assumed unless the MAP file specifies otherwise. + + + -90.0 + 90.0 + + + + double + Ending latitude + Use default range + + The maximum latitude of the ground range. If this is entered by the user it will override the default camera or map value. + By default, planetocentric latitudes are assumed unless the MAP file specifies otherwise. + + -90.0 + 90.0 + MINLAT + + + + double + Starting longitude + Use default range + + The minimum longitude of the ground range. If this is entered by the user it will override the default camera or map value. + By default, positive east longitudes in the range of 0 to 360 are assumed unless the MAP file specifies otherwise. + + + + + double + Ending longitude + Use default range + + The maximum longitude of the ground range. If this is entered by the user it will override the default camera or map value. + By default, positive east longitudes in the range of 0 to 360 are assumed unless the MAP file specifies otherwise. + + MINLON + + + + boolean + FALSE + + Trim pixels outside ground range + + + If this option is selected, pixels outside the latitude/longtiude + range will be trimmed or set to null. + This is useful for certain projections whose lines of latitude and + longitude are not parallel to image lines and sample columns. + + + + + + + string + AUTO + + How should images at the longitude seam be handled + + + With this option you can turn on/off the automatic longitude domain switching that occurs + when a file crosses the boundary of the longitude domain (0-360 or -180 to 180). If the switching is turn off then + you have the choice of making the program continue or exit when the cube does cross the bounday. + + + + + + + + + + + + + +
    diff --git a/isis/src/cassini/apps/vimscal/Makefile b/isis/src/cassini/apps/vimscal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/cassini/apps/vimscal/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/cassini/apps/vimscal/tsts/Makefile b/isis/src/cassini/apps/vimscal/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/cassini/apps/vimscal/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/cassini/apps/vimscal/tsts/default/Makefile b/isis/src/cassini/apps/vimscal/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3f24b5e93dc35fd7734b2f98c209b7cd96d761a0 --- /dev/null +++ b/isis/src/cassini/apps/vimscal/tsts/default/Makefile @@ -0,0 +1,13 @@ +APPNAME = vimscal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/v1570021638_1.ir.cub \ + TO=$(OUTPUT)/v1570021638_1.ir.iof.cal.cub > /dev/null; + $(APPNAME) FROM=$(INPUT)/v1570021638_1.vis.cub \ + TO=$(OUTPUT)/v1570021638_1.vis.iof.cal.cub > /dev/null; + $(APPNAME) FROM=$(INPUT)/v1570021638_1.ir.cub \ + TO=$(OUTPUT)/v1570021638_1.ir.spec.cal.cub units=specenergy > /dev/null; + $(APPNAME) FROM=$(INPUT)/v1570021638_1.vis.cub \ + TO=$(OUTPUT)/v1570021638_1.vis.spec.cal.cub units=specenergy > /dev/null; diff --git a/isis/src/cassini/apps/vimscal/tsts/irdark/Makefile b/isis/src/cassini/apps/vimscal/tsts/irdark/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..112f7b0a08f69a92740b651dc7337804bdc705ba --- /dev/null +++ b/isis/src/cassini/apps/vimscal/tsts/irdark/Makefile @@ -0,0 +1,14 @@ +APPNAME = vimscal + +V1483214528_1.ir.avgdark.cal.cub.TOLERANCE = 0.00000000004 +V1483214528_1.ir.origdark.cal.cub.TOLERANCE = 0.00000000004 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/V1483214528_1.ir.cub \ + TO=$(OUTPUT)/V1483214528_1.ir.avgdark.cal.cub \ + irorigdark=false > /dev/null; + $(APPNAME) FROM=$(INPUT)/V1483214528_1.ir.cub \ + TO=$(OUTPUT)/V1483214528_1.ir.origdark.cal.cub \ + irorigdark=true > /dev/null; diff --git a/isis/src/cassini/apps/vimscal/vimscal.cpp b/isis/src/cassini/apps/vimscal/vimscal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6dee2a106b20976a34e1a0a3c9603991493f7961 --- /dev/null +++ b/isis/src/cassini/apps/vimscal/vimscal.cpp @@ -0,0 +1,696 @@ +#include "Isis.h" + +#include +#include + +#include "EndianSwapper.h" +#include "UserInterface.h" +#include "iException.h" +#include "ProcessByLine.h" +#include "iString.h" +#include "LineManager.h" +#include "Table.h" +#include "Statistics.h" +#include "Camera.h" +#include "PolynomialUnivariate.h" +#include "LeastSquares.h" + +using namespace Isis; +using namespace std; + +//! map from to dark correction value +map< pair, double > sampleBasedDarkCorrections; + +//! map from to dark correction value +map< pair, double > lineBasedDarkCorrections; + +//! specific energy corrections for each band of the cube +vector specificEnergyCorrections; + +//! list of temp files that need deleted +vector tempFiles; + +//! solar remove coefficient +double solarRemoveCoefficient; + +//! Output in I/F units +bool iof; + +void calculateDarkCurrent(Cube *); +void calculateVisDarkCurrent(Cube *); +void calculateIrDarkCurrent(Cube *); + +void chooseFlatFile(Cube *, ProcessByLine *); + +void calculateSpecificEnergy(Cube *); +void calculateSolarRemove(Cube *, ProcessByLine *); + +void calibrate(vector &in, vector &out); + +iString createCroppedFile(Cube *icube, iString cubeFilename, bool flatFile = false); +void GetOffsets(const Pvl &lab, int &finalSampOffset, int &finalLineOffset); + +// This is the results group +PvlGroup calibInfo; + +void IsisMain(){ + UserInterface &ui = Application::GetUserInterface(); + + tempFiles.clear(); + specificEnergyCorrections.clear(); + sampleBasedDarkCorrections.clear(); + lineBasedDarkCorrections.clear(); + solarRemoveCoefficient = 1.0; + iof = (ui.GetString("UNITS") == "IOF"); + + calibInfo = PvlGroup("Results"); + + ProcessByLine p; + Cube *icube = p.SetInputCube("FROM"); + + bool isVims = true; + + try { + isVims = (icube->Label()->FindGroup("Instrument", Pvl::Traverse)["InstrumentId"][0] == "VIMS"); + } + catch (iException &e) { + e.Clear(); + isVims = false; + } + + if(!isVims) { + iString msg = "The input cube [" + iString(ui.GetAsString("FROM")) + "] is not a Cassini VIMS cube"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + if(icube->Label()->FindObject("IsisCube").HasGroup("AlphaCube")) { + iString msg = "The input cube [" + iString(ui.GetAsString("FROM")) + "] has had its dimensions modified and can not be calibrated"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + // done first since it's likely to cause an error if one exists + calculateSolarRemove(icube, &p); + + calculateDarkCurrent(icube); + chooseFlatFile(icube, &p); + calculateSpecificEnergy(icube); + + calibInfo += PvlKeyword("OutputUnits", ((iof)? "I/F" : "Specific Energy")); + + Application::Log(calibInfo); + + p.SetOutputCube("TO"); + p.StartProcess(calibrate); + p.EndProcess(); + + for(unsigned int i = 0; i < tempFiles.size(); i++) { + remove(tempFiles[i].c_str()); + } + + tempFiles.clear(); +} + +/** + * This applies the calculated calibration coefficients to the file. + * + * @param inBuffers + * @param outBuffers + */ +void calibrate(vector &inBuffers, vector &outBuffers) { + Buffer *inBuffer = inBuffers[0]; + Buffer *flatFieldBuffer = inBuffers[1]; + Buffer *solarRemoveBuffer = NULL; // this is optional + + if(inBuffers.size() > 2) { + inBuffer = inBuffers[0]; + solarRemoveBuffer = inBuffers[1]; + flatFieldBuffer = inBuffers[2]; + } + + Buffer *outBuffer = outBuffers[0]; + + for(int i = 0; i < inBuffer->size(); i++) { + (*outBuffer)[i] = (*inBuffer)[i]; + + if(IsSpecial((*outBuffer)[i])) continue; + + map< pair, double>::iterator darkCorrection = + sampleBasedDarkCorrections.find(pair(i+1, inBuffer->Band())); + + if(darkCorrection != sampleBasedDarkCorrections.end()) { + (*outBuffer)[i] -= darkCorrection->second; + } + + darkCorrection = lineBasedDarkCorrections.find(pair(inBuffer->Line(), inBuffer->Band())); + + if(darkCorrection != lineBasedDarkCorrections.end()) { + (*outBuffer)[i] -= darkCorrection->second; + } + + if(!IsSpecial((*flatFieldBuffer)[i])) { + (*outBuffer)[i] /= (*flatFieldBuffer)[i]; + } + + if(inBuffer->Band() <= (int)specificEnergyCorrections.size()) { + (*outBuffer)[i] *= specificEnergyCorrections[inBuffer->Band()-1]; + } + + if(iof && solarRemoveBuffer) { + (*outBuffer)[i] = (*outBuffer)[i] / ((*solarRemoveBuffer)[i] / solarRemoveCoefficient) * Isis::PI; + } + } +} + +/** + * This calculates the values necessary to convert from + * specific energy to I/F. A cube is used as part of the + * equation (which probably* just contains a vector of values) + * so p->SetInputCube(...) will be called with the appropriate + * filename. + * + * @param icube + * @param p + */ +void calculateSolarRemove(Cube *icube, ProcessByLine *p) { + UserInterface &ui = Application::GetUserInterface(); + if(ui.GetString("UNITS") != "IOF") return; + + Camera *cam = NULL; + + try { + cam = icube->Camera(); + } + catch(iException &e) { + iString msg = "Unable to create a camera from [" + + icube->Filename() + "]. Please run spiceinit on this file"; + throw iException::Message(iException::Camera, msg, _FILEINFO_); + } + + solarRemoveCoefficient = -1.0; + + // try center first + if(cam->SetImage(icube->Samples()/2, icube->Lines()/2)) { + solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); + } + + // try 4 corners + if(solarRemoveCoefficient < 0 && cam->SetImage(1.0, 1.0)) { + solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); + } + + if(solarRemoveCoefficient < 0 && cam->SetImage(icube->Samples(), 1.0)) { + solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); + } + + if(solarRemoveCoefficient < 0 && cam->SetImage(icube->Samples(), icube->Lines())) { + solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); + } + + if(solarRemoveCoefficient < 0 && cam->SetImage(1.0, icube->Lines())) { + solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); + } + + // try center of 4 edges + if(solarRemoveCoefficient < 0 && cam->SetImage(icube->Samples()/2, 1.0)) { + solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); + } + + if(solarRemoveCoefficient < 0 && cam->SetImage(icube->Samples(), icube->Lines()/2)) { + solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); + } + + if(solarRemoveCoefficient < 0 && cam->SetImage(icube->Samples()/2, icube->Lines())) { + solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); + } + + if(solarRemoveCoefficient < 0 && cam->SetImage(1.0, icube->Lines()/2)) { + solarRemoveCoefficient = cam->SolarDistance() * cam->SolarDistance(); + } + + if(solarRemoveCoefficient < 0) { + string msg = "Unable to project image at four corners, center of edges or "; + msg += "at center. The solar distance can not be calculated, try using"; + msg += " [UNITS=SPECENERGY] on ["; + msg += icube->Filename() + "]"; + throw iException::Message(iException::Camera, msg, _FILEINFO_); + } + + bool vis = (icube->Label()->FindGroup("Instrument", Pvl::Traverse)["Channel"][0] != "IR"); + + iString attributes; + + // vis is bands 1-96, ir is bands 97-352 in this calibration file + if(vis) { + attributes = "+1-96"; + } + else { + attributes = "+97-352"; + } + + CubeAttributeInput iatt(attributes); + + Filename solarFilename("$cassini/calibration/vims/solar_v????.cub"); + solarFilename.HighestVersion(); + + p->SetInputCube(createCroppedFile(icube, solarFilename.Expanded()), iatt); +} + + +/** + * This calculates the coefficients for specific energy corrections + */ +void calculateSpecificEnergy(Cube *icube) { + PvlGroup &inst = icube->Label()->FindGroup("Instrument", Pvl::Traverse); + bool vis = (inst["Channel"][0] != "IR"); + + double coefficient = 1.0; + + if(inst["GainMode"][0] == "HIGH") { + coefficient /= 2; + } + + if(vis && inst["SamplingMode"][0] == "HI-RES") { + coefficient *= 3; + } + + if(vis) { + coefficient /= (double)inst["ExposureDuration"][1] / 1000.0; + } + else { + coefficient /= ((double)inst["ExposureDuration"][0]) / 1000.0 - 0.004; + } + + iString specEnergyFile = "$cassini/calibration/vims/"; + + if(vis) { + specEnergyFile += "vis_perf_v????.cub"; + } + else { + specEnergyFile += "ir_perf_v????.cub"; + } + + iString waveCalFile = "$cassini/calibration/vims/wavecal_v????.cub"; + + Filename specEnergyFilename(specEnergyFile); + specEnergyFilename.HighestVersion(); + + Filename waveCalFilename(waveCalFile); + waveCalFilename.HighestVersion(); + + Cube specEnergyCube; + specEnergyCube.Open(specEnergyFilename.Expanded()); + + Cube waveCalCube; + waveCalCube.Open(waveCalFilename.Expanded()); + + LineManager specEnergyMgr(specEnergyCube); + LineManager waveCalMgr(waveCalCube); + + for(int i = 0; i < icube->Bands(); i++) { + Statistics specEnergyStats; + Statistics waveCalStats; + + if(vis) { + specEnergyMgr.SetLine(1, i+1); + waveCalMgr.SetLine(1, i+1); + } + else { + specEnergyMgr.SetLine(1, i+1); + // ir starts at band 97 + waveCalMgr.SetLine(1, i+96+1); + } + + specEnergyCube.Read(specEnergyMgr); + waveCalCube.Read(waveCalMgr); + + specEnergyStats.AddData(specEnergyMgr.DoubleBuffer(), specEnergyMgr.size()); + waveCalStats.AddData(waveCalMgr.DoubleBuffer(), waveCalMgr.size()); + + double bandCoefficient = coefficient * specEnergyStats.Average() * waveCalStats.Average(); + + specificEnergyCorrections.push_back(bandCoefficient); + } +} + +/** + * This decides if we have a VIS or IR dark current correction and calls the + * appropriate method. + * + * @param currCube + */ +void calculateDarkCurrent(Cube *icube) { + PvlGroup &inst = icube->Label()->FindGroup("Instrument", Pvl::Traverse); + bool vis = (inst["Channel"][0] != "IR"); + + calibInfo += PvlKeyword("Vis", ((vis)? "true" : "false")); + + if(vis) { + calculateVisDarkCurrent(icube); + } + else { + calculateIrDarkCurrent(icube); + } +} + +/** + * This populates darkCorrections with the result of the equation: + * dark = a + x * b + * for each line,band. a, b are from the "vis_*_dark_model.tab" files + * and x is the ExposureDuration. + * + * @param icube + */ +void calculateVisDarkCurrent(Cube *icube) { + PvlGroup &inst = icube->Label()->FindGroup("Instrument", Pvl::Traverse); + + // This is the dark current corrections for VIS + bool hires = ((inst["SamplingMode"][0] == "HIGH") || (inst["SamplingMode"][0] == "HI-RES")); + iString calFile = "$cassini/calibration/vims/vis_"; + + if(hires) { + calFile += "hires"; + } + else { + calFile += "lowres"; + } + + calFile += "_dark_model_v????.tab"; + + Filename calFilename(calFile); + calFilename.HighestVersion(); + + calibInfo += PvlKeyword("DarkCurrentFile", calFilename.OriginalPath() + "/" + calFilename.Name()); + + calFile = calFilename.Expanded(); + + EndianSwapper swapper("LSB"); + + FILE *calFilePtr = fopen(calFile.c_str(), "r"); + + double visExposure = inst["ExposureDuration"][1]; + + int sampleOffset, lineOffset; + GetOffsets(*icube->Label(), sampleOffset, lineOffset); + + /** + * Reading in one parameter at a time: + * parameter 1 = constant coefficient + * parameter 2 = exposure coefficient + * param1 + param2*exposure = dark correction + * + * Do byte swapping where necessary. + */ + for(int parameter = 1; parameter <= 2; parameter ++) { + for(int band = 1; band <= 96; band++) { + for(int sample = 1; sample <= 64; sample++) { + float calData; + + if(fread(&calData, sizeof(calData), 1, calFilePtr) != 1) { + // error! + string msg = "Error reading file [" + calFile + "]"; + throw iException::Message(iException::Io, msg, _FILEINFO_); + } + + int associatedSample = sample - sampleOffset + 1; + + calData = swapper.Float(&calData); + pair index = pair(associatedSample, band); + + map< pair, double>::iterator pos = sampleBasedDarkCorrections.find(index); + if(pos == sampleBasedDarkCorrections.end()) { + sampleBasedDarkCorrections.insert( pair< pair, double>(index, calData) ); + } + else { + (*pos).second = (*pos).second + visExposure * calData; + } + } + } + } + + fclose(calFilePtr); + + // If spectral summing is on, go in sets of 8 and set darks to the average + /* + PvlGroup &archive = icube->Label()->FindGroup("Archive", Pvl::Traverse); + if(archive["SpectralSummingFlag"][0] == "ON") { + for(int band = 1; band <= 96; band += 8) { + for(int sample = 1; sample <= 64; sample++) { + Statistics stats; + + // we're calculating an average of 8 of these values through the bands + for(int avgIndex = 0; avgIndex < 8; avgIndex ++) { + // this wont go out of bounds as long as we have 8 as the increment + pair index = pair(sample, band+avgIndex); + stats.AddData(sampleBasedDarkCorrections.find(index)->second); + } + + // now set the values to the average + for(int setIndex = 0; setIndex < 8; setIndex ++) { + pair index = pair(sample, band+setIndex); + if(!setIndex) printf("Changing %.4f to %.4f\n", sampleBasedDarkCorrections.find(index)->second, stats.Average()); + sampleBasedDarkCorrections.find(index)->second = stats.Average(); + } + } + } + }*/ +} + +/** + * This calculates the dark current corrections for IR. If + * IRDARKAVG is false, then it translates the sideplane data + * into the lineBasedDarkCorrections map directly and does nothing further + * with the data. Otherwise, this will apply a least squares linear + * fit (the original script did chi-squared, but this is okay) for + * each band and uses the points on the line instead of the sideplane + * data directly. + * + * @param icube + */ +void calculateIrDarkCurrent(Cube *icube) { + UserInterface &ui = Application::GetUserInterface(); + + bool found = false; + + // verify if IR we have sideplane data + for(int obj = 0; !found && obj < icube->Label()->Objects(); obj++) { + PvlObject &object = icube->Label()->Object(obj); + + if(object.Name() != "Table") continue; + + if(object.HasKeyword("Name") && object["Name"][0] == "SideplaneIr") found = true; + } + + if(!found) { + calibInfo += PvlKeyword("SideplaneCorrection", "None"); + return; + } + + Table sideplane("SideplaneIr", ui.GetFilename("FROM")); + + // If spectal summing is on OR compressor_id isnt N/A then + // just return. + PvlGroup &archive = icube->Label()->FindGroup("Archive", Pvl::Traverse); + + // If dark subtracted (compressorid is valid) and cant do linear + // correction (spectral editing flag on) then do not do dark + if(archive["CompressorId"][0] != "N/A" && + archive["SpectralEditingFlag"][0] == "ON") { + calibInfo += PvlKeyword("SideplaneCorrection", "None"); + return; + } + + // If subtracted (compressor id is valid) and dont do linear then return + if(archive["CompressorId"][0] != "N/A" && ui.GetBoolean("IRORIGDARK") == true) { + calibInfo += PvlKeyword("SideplaneCorrection", "None"); + return; + } + + if(archive["SpectralSummingFlag"][0] == "ON") return; + + // Insert the sideplane data into our lineBasedDarkCorrections map (line,band to correction) + for(int line = 1; line <= icube->Lines(); line++) { + for(int band = 1; band <= icube->Bands(); band++) { + pair index = pair(line,band); + int value = (int)sideplane[(line-1)*icube->Bands() + (band-1)][2]; + + lineBasedDarkCorrections.insert(pair< pair, double>(index,value)); + } + } + + if(ui.GetBoolean("IRORIGDARK") == true) { + calibInfo += PvlKeyword("SideplaneCorrection", "Sideplane"); + return; + } + + // do linear fits + for(int band = 1; band <= icube->Bands(); band++) { + PolynomialUnivariate basis(1); + LeastSquares lsq(basis); + + for(int line = 1; line <= icube->Lines(); line++) { + pair index = pair(line,band); + map< pair, double>::iterator val = lineBasedDarkCorrections.find(index); + + vector input; + input.push_back(line); + double expected = val->second; + + lsq.AddKnown(input, expected); + } + + lsq.Solve(); + + double coefficients[2] = { + basis.Coefficient(0), + basis.Coefficient(1) + }; + + for(int line = 1; line <= icube->Lines(); line++) { + pair index = pair(line,band); + + map< pair, double>::iterator val = lineBasedDarkCorrections.find(index); + double currentDark = val->second; + + double newDark = coefficients[0] + line * coefficients[1]; + + // initial dark applied by compressor + if(archive["CompressorId"][0] != "N/A") { + // input is in (dn-dark) units + // (dn-dark) - (fit-dark) = dn-fit + newDark -= currentDark; + } + + val->second = newDark; + } + } + + if(archive["CompressorId"][0] != "N/A") { + calibInfo += PvlKeyword("SideplaneCorrection", "Fit Delta"); + } + else { + calibInfo += PvlKeyword("SideplaneCorrection", "Fit"); + } +} + +/** + * This calls p->SetInputCube with the appropriate flat file needed for + * icube. + * + * @param icube + * @param p + */ +void chooseFlatFile(Cube *icube, ProcessByLine *p) { + PvlGroup &inst = icube->Label()->FindGroup("Instrument", Pvl::Traverse); + bool vis = (inst["Channel"][0] != "IR"); + bool hires = ((inst["SamplingMode"][0] == "HIGH") || (inst["SamplingMode"][0] == "HI-RES")); + + iString calFile = "$cassini/calibration/vims/flatfield/"; + + if(vis) { + calFile += "vis_"; + } + else { + calFile += "ir_"; + } + + if(hires) { + calFile += "hires_flatfield_v????.cub"; + } + else { + calFile += "flatfield_v????.cub"; + } + + Filename calibrationFilename(calFile); + calibrationFilename.HighestVersion(); + + calibInfo += PvlKeyword("FlatFile", calibrationFilename.OriginalPath() + "/" + calibrationFilename.Name()); + + CubeAttributeInput iatt; + p->SetInputCube(createCroppedFile(icube, calibrationFilename.Expanded(), true), iatt); +} + +/** + * This makes our calibration files match the input cube described + * by the swath keywords. + * + * @param icube + * @param cubeFilename + * + * @return iString + */ +iString createCroppedFile(Cube *icube, iString cubeFilename, bool flatFile) { + int sampOffset = 1; + int lineOffset = 1; + + if(flatFile) { + GetOffsets(*icube->Label(), sampOffset, lineOffset); + } + + + iString appArgs = "from=" + cubeFilename + " "; + appArgs += "sample=" + iString(sampOffset) + " "; + appArgs += "line=" + iString(lineOffset) + " "; + appArgs += "nsamples=" + iString(icube->Samples()) + " "; + appArgs += "nlines=" + iString(icube->Lines()) + " "; + + Filename tempFile("$TEMPORARY/tmp_" + Filename(cubeFilename).Basename() + "_" + Filename(icube->Filename()).Name()); + + appArgs += "to=" + tempFile.Expanded(); + + iApp->Exec("crop", appArgs); + tempFiles.push_back(tempFile.Expanded()); + return tempFile.Expanded(); +} + +void GetOffsets(const Pvl &lab, int &finalSampOffset, int &finalLineOffset) { + const PvlGroup &inst = lab.FindGroup("Instrument", Pvl::Traverse); + + // Get sample/line offsets + int sampOffset = inst ["XOffset"]; + int lineOffset = inst ["ZOffset"]; + + // Get swath width/length which will be image size unless occultation image + int swathWidth = inst ["SwathWidth"]; + int swathLength = inst ["SwathLength"]; + + bool vis = (inst["Channel"][0] != "IR"); + finalSampOffset = sampOffset; + finalLineOffset = lineOffset; + + string samplingMode = iString((string)inst ["SamplingMode"]).UpCase(); + if (vis) { + if (samplingMode == "NORMAL") { + finalSampOffset = sampOffset - 1; + finalLineOffset = lineOffset - 1; + } + else if (samplingMode == "HI-RES") { + finalSampOffset = (3 * ((sampOffset - 1) + swathWidth/2)) - swathWidth/2; + finalLineOffset = (3 * (lineOffset + swathLength/2)) - swathLength/2; + } + else { + string msg = "Unsupported sampling mode [" + samplingMode + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + else { + if (samplingMode == "NORMAL") { + finalSampOffset = sampOffset - 1; + finalLineOffset = lineOffset - 1; + } + else if (samplingMode == "HI-RES") { + finalSampOffset = 2* ((sampOffset-1) + ((swathWidth - 1)/4)); + finalLineOffset = lineOffset - 1; + } + else if (samplingMode == "NYQUIST") { + string msg = "Cannot process NYQUIST (undersampled) mode "; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + else { + string msg = "Unsupported sampling mode [" + samplingMode + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + + finalSampOffset ++; + finalLineOffset ++; +} diff --git a/isis/src/cassini/apps/vimscal/vimscal.xml b/isis/src/cassini/apps/vimscal/vimscal.xml new file mode 100644 index 0000000000000000000000000000000000000000..1ba1a17f9cb504c5db8fe4abd841e481977821f3 --- /dev/null +++ b/isis/src/cassini/apps/vimscal/vimscal.xml @@ -0,0 +1,137 @@ + + + + + + Radiometric correction of Cassini VIMS camera images. + + + + This program applies a dark current and a flat field correction to images, then converts the output units + to either specific energy or I/F. + +

    + Dark Current:
    + The dark current correction for VIS consists of reading a binary ".tab" file from $cassini/calibration/vims and subtracting + derived values from this file.
    + + The dark current correction for IR consists of reading the sideplane data (stored in a SideplaneIr table in the cube) and + subtracting this from the input cube. If "CompressorId" is available then the sideplane data was already subtracted from + the file, but the linear fit capabilities are still available to re-do the dark current with a linear fit instead of the + default subtraction. If spectral summing is on then no dark current can be applied. If spectral editing is on then the linear + fit on the dark current can not be applied. Sideplane keywords for IR are as follows: +
      +
    • None = No dark current subtraction (applied by the instrument)
    • +
    • Sideplane = Sideplane was subtracted only without fitting a line
    • +
    • Fit Delta = Sideplane was previously subtracted so the difference between the + sideplane and linear fit function subtracted
    • +
    • Fit = A linear fit was applied to the dark current values and the result was subtracted
    • +
    +

    + + Flat Field:
    + For both VIS and IR this determines the correct file from $cassini/calibration/vims/flatfield and divides the input data by the + flat field data.

    + + Subareas
    + The offset and swath keywords will be respected by running "crop" on the calibration files appropriately and using the cropped + calibration files. +
    + + + + Original version + + + The solar distance calculation is now much more likely to succeed + + + Better error handling - fewer temporary files left around + + + Sped up program by not searching a pvl much more than necessary, + improved error messages + + + Now closing calibration files when done with them + + + + + Cassini + + + + + + cube + input + + Input Isis cube + + + Use this parameter to choose an Isis cube to be calibrated. To ensure + that it contains all needed keywords in its label, input cube should + have been imported using vims2isis and, if "I/F" is chosen, input cube + must have been run through spiceinit application. + + + *.cub + + + + + cube + output + real + + Output Isis cube + + + Use this parameter to select the output filename of the calibrated + Isis cube. + + + *.cub + + + + + + + string + Output units + + + IOF + + + + + + + + boolean + Do not perform IR Dark Current Corrections + + By default Isis will fit a line to the dark current values, on each band, across the lines since + there is one dark value per line. The linear fit value will be applied correctly even if a dark + current was applied to this cube beforehand. This disables the line fitting for the dark current. + This parameter has no effect for VIS cubes. + + false + + + +
    diff --git a/isis/src/cassini/objs/CissLabels/CissLabels.cpp b/isis/src/cassini/objs/CissLabels/CissLabels.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ec7e549429d380a522afb53767691754e927c865 --- /dev/null +++ b/isis/src/cassini/objs/CissLabels/CissLabels.cpp @@ -0,0 +1,148 @@ +#include +#include "CissLabels.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "SpecialPixel.h" +#include "iException.h" +#include "iString.h" + +using namespace std; +namespace Isis { + /** + * Constructs a CissLabels object from an @b Isis::Pvl object. + * + * @param lab @b Pvl Labels of Cassini ISS file + */ + CissLabels::CissLabels(Pvl &lab) { + Init(lab); + } + + /** + * Constructs a CissLabels object from a file name. + * + * @param file Name of Cassini ISS file + */ + CissLabels::CissLabels(const string &file) { + Pvl lab(file); + Init(lab); + } + + /** + * General initializer. Reads labels of the file and computes + * values of image properties not already in the labels. + * + * @param lab @b Pvl Labels of Cassini ISS file + * @throws iException::Pvl Not valid Cassini ISS instrument + */ + void CissLabels::Init(Pvl &lab) { + try { + ReadLabels(lab); + ComputeImgProperties(); + } + catch (iException &e) { + e.Report(); + string msg = "Labels do not appear contain a valid Cassini ISS instrument"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + } + + /** + * @brief Reads the @b Pvl Labels + * + * This method reads the required keywords from the labels and + * sets the values of the private variables. + * + * @param lab @b Pvl Labels of Cassini ISS file + */ + void CissLabels::ReadLabels(Pvl &lab) { + // Get values out of the instrument group + PvlGroup &inst = lab.FindGroup("Instrument",Pvl::Traverse); + p_ABflag = (string) inst["AntiBloomingStateFlag"]; //valid values: On, Off, Unknown + p_biasStripMean = (double) inst["BiasStripMean"]; //valid values: real numbers + p_compressionRatio = (string) inst["CompressionRatio"]; //valid values: NotCompressed or real number + p_compressionType = (string) inst["CompressionType"]; //valid values: Lossy, Lossless, NotCompressed + p_dataConversionType = (string) inst["DataConversionType"]; //valid values: 12Bit, 8LSB, Table + p_delayedReadoutFlag = (string) inst["DelayedReadoutFlag"]; //valid values: Yes, No, Unknown + p_exposureDuration = (double) inst["ExposureDuration"]; //valid values: real numbers + p_flightSoftwareVersion = (string) inst["FlightSoftwareVersionId"]; //valid values: Unknown, 1.2, 1.3, 1.4 + p_gainModeId = (int) inst["GainModeId"]; //valid values: 12, 29, 95, 215 + p_gainState = (int) inst["GainState"]; //valid values: 0, 1, 2, 3 + p_instrumentDataRate = (double) inst["InstrumentDataRate"]; //valid values: 60.9, 121.9, 182.8, 243.7, 304.6, 365.6, -999.0 + p_instrumentModeId = (string) inst["InstrumentModeId"]; //valid values: Full, Sum2, Sum4 + p_instrumentId = (string) inst["InstrumentId"]; //valid values: ISSNA, ISSWA + p_readoutCycleIndex = (string) inst["ReadoutCycleIndex"]; //valid values: Unknown or integers 0-15 + p_readoutOrder = (int) inst["ReadoutOrder"]; //valid values: 0 or 1 + p_shutterModeId = (string) inst["ShutterModeId"]; //valid values: BothSim, NacOnly, WacOnly + p_summingMode = (int) inst["SummingMode"]; //valid values: 1, 2, 4 + p_frontOpticsTemp = inst["OpticsTemperature"][0].ToDouble(); //valid values: real numbers + // Get values out of the archive group + PvlGroup &arch = lab.FindGroup("Archive",Pvl::Traverse); + p_imageNumber = (double) arch["ImageNumber"]; + // Get values out of the bandbin group + PvlGroup &bandbin = lab.FindGroup("BandBin",Pvl::Traverse); + iString filter = (string) bandbin["FilterName"]; + p_filter.push_back(filter.Token("/")); + p_filter.push_back(filter); + } + + + /** + * @brief Computes values of non-keyword image properties. + * + * This method computes and sets the values of the image + * properties that are not keywords in the labels. + * + */ + void CissLabels::ComputeImgProperties() { + //set boolean p_antiblooming if antiblooming flag is on + if (p_ABflag == "On") p_antiblooming = true; + else p_antiblooming = false; + + //set boolean p_cissNA if camera type is narrow + if (p_instrumentId == "ISSNA") p_cissNA = true; + else p_cissNA = false; + + //set filter 1 and filter 2 indices + if (p_filter[0] == "UV1") p_filterIndex.push_back(0); + else if (p_filter[0] == "UV2") p_filterIndex.push_back(1); + else if (p_filter[0] == "BL1") p_filterIndex.push_back(3); + else if (p_filter[0] == "RED") p_filterIndex.push_back(6); + else if (p_filter[0] == "IR2") p_filterIndex.push_back(8); + else if (p_filter[0] == "IR4") p_filterIndex.push_back(10); + else if (p_filter[0] == "CL1") p_filterIndex.push_back(17); + else if (p_filter[0] == "HAL") p_filterIndex.push_back(19); + else if (p_filter[0] == "IRP0") p_filterIndex.push_back(20); + else if (p_filter[0] == "P0") p_filterIndex.push_back(21); + else if (p_filter[0] == "P60") p_filterIndex.push_back(22); + else if (p_filter[0] == "P120") p_filterIndex.push_back(23); + else if (p_filter[0] == "IR3") p_filterIndex.push_back(24); + else if (p_filter[0] == "IR5") p_filterIndex.push_back(25); + else if (p_filter[0] == "CB3") p_filterIndex.push_back(26); + else if (p_filter[0] == "MT3") p_filterIndex.push_back(27); + else if (p_filter[0] == "CB2") p_filterIndex.push_back(28); + else if (p_filter[0] == "MT2") p_filterIndex.push_back(29); + else throw iException::Message(iException::Pvl, "Labels have invalid filter 1 name. Cannot get filter 1 index.", _FILEINFO_); + + if (p_filter[1] == "UV3") p_filterIndex.push_back(2); + else if (p_filter[1] == "BL2") p_filterIndex.push_back(4); + else if (p_filter[1] == "GRN") p_filterIndex.push_back(5); + else if (p_filter[1] == "IR1") p_filterIndex.push_back(7); + else if (p_filter[1] == "IR3") p_filterIndex.push_back(9); + else if (p_filter[1] == "CB1") p_filterIndex.push_back(11); + else if (p_filter[1] == "CB2") p_filterIndex.push_back(12); + else if (p_filter[1] == "CB3") p_filterIndex.push_back(13); + else if (p_filter[1] == "MT1") p_filterIndex.push_back(14); + else if (p_filter[1] == "MT2") p_filterIndex.push_back(15); + else if (p_filter[1] == "MT3") p_filterIndex.push_back(16); + else if (p_filter[1] == "CL2") p_filterIndex.push_back(18); + else if (p_filter[1] == "RED") p_filterIndex.push_back(30); + else if (p_filter[1] == "BL1") p_filterIndex.push_back(31); + else if (p_filter[1] == "VIO") p_filterIndex.push_back(32); + else if (p_filter[1] == "HAL") p_filterIndex.push_back(33); + else if (p_filter[1] == "IRP90") p_filterIndex.push_back(34); + else if (p_filter[1] == "IRP0") p_filterIndex.push_back(35); + else throw iException::Message(iException::Pvl, "Labels have invalid filter 2 name. Cannot get filter 2 index.", _FILEINFO_); + return; + } +} + diff --git a/isis/src/cassini/objs/CissLabels/CissLabels.h b/isis/src/cassini/objs/CissLabels/CissLabels.h new file mode 100644 index 0000000000000000000000000000000000000000..c789d56ab505a38bd92f52f95b2e66a36199d17c --- /dev/null +++ b/isis/src/cassini/objs/CissLabels/CissLabels.h @@ -0,0 +1,427 @@ +#ifndef CISSLABELS_H +#define CISSLABELS_H +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/11/07 22:45:20 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "iString.h" +using namespace std; +namespace Isis { + class Pvl; + /** + * @brief Read values from Cassini ISS labels + * + * This class is designed to be used with images imported from + * Cassini ISS using @b ciss2isis. It contains accessor methods + * for the values of Keywords in the Instrument Group of the + * cube's labels. + * + * @ingroup Cassini + * @author 2008-11-05 Jeannie Walldren + * @internal + * @history 2008-11-05 Jeannie Walldren - Original Version + * @history 2008-11-07 Fixed documentation + */ + + class CissLabels { + public: + CissLabels (Pvl &lab); + CissLabels (const string &file); + //! Empty Destructor + ~CissLabels () {}; + + + /** + * @brief Returns whether InstrumentId from the Instrument + * group is "ISSNA". + * + * Indicates whether the camera used a narrow-angle lens + * ("ISSNA"). False implies it used a wide-angle lens + * ("ISSWA"). + * + * @returns @b bool True if instrument ISSNA + */ + inline bool NarrowAngle () const { return p_cissNA; }; + + + /** + * @brief Returns whether InstrumentId from the Instrument + * group is "ISSWA". + * + * Indicates whether the camera used a wide-angle lens + * ("ISSWA"). False implies it used a narrow-angle lens + * ("ISSNA"). + * + * @returns @b bool True if instrument ISSWA + */ + inline bool WideAngle () const { return !p_cissNA; }; + + + /** + * @brief Returns BiasStripMean from the Intstrument group. + * + * Finds the mean of the overclocked pixels. If the image has + * DataConversionType of "Lossy", the bias strip mean is not + * valid unless the Flight Software Version is 1.4. Valid + * values include all real numbers. + * + * @returns @b double BiasStripMean + */ + inline double BiasStripMean() const { return p_biasStripMean; }; + + + /** + * @brief Returns CompressionRatio from the Instrument group. + * + * Finds the ratio of the expected image size to the actual + * size. Valid values include any real number or + * "NotCompressed". This method returns an + * @b Isis::iString so that values other than + * "NotCompressed" may be converted to @b double. + * + * @returns @b iString CompressionRatio + */ + inline iString CompressionRatio() const { return p_compressionRatio; }; + + + /** + * @brief Returns CompressionType from the Instrument group. + * + * Finds the method of data compression used for the image. + * Valid values include "NotCompressed", + * "Lossless" (a.k.a Rice), or "Lossy" (a.k.a. Discrete Cosine + * Transform). + * + * @returns @b iString CompressionType + */ + inline iString CompressionType() const { return p_compressionType; }; + + + /** + * @brief Returns DataConversionType from the Instrument group. + * + * Finds the method used to convert the image from 12 to 8 + * bits. Valid values include "12Bit" (no conversion), + * "Table" (converted using look-up table), or "8LSB" (kept the + * 8 least significant bits only). + * + * @returns @b iString DataConversionType + */ + inline iString DataConversionType() const { return p_dataConversionType; }; + + + /** + * @brief Returns DelayedReadoutFlag from the Instrument group. + * + * Indicates whether the image waited while the ther camera was + * performing a readout. Valid values include "Yes", "No", or + * "Unknown". + * + * @returns @b iString DelayedReadoutFlag + */ + inline iString DelayedReadoutFlag() const { return p_delayedReadoutFlag; }; + + + /** + * @brief Returns ExposureDuration from the Instrument group. + * + * Finds the exposure duration in milliseconds for the image. + * There are 62 valid values between 0 and 1200000, or -999.0 + * (if data is unavailable). + * + * @returns @b double ExposureDuration + */ + inline double ExposureDuration() const { return p_exposureDuration; }; + + + /** + * @brief Returns a two-element array of the optical filters + * found in the BandBin group. + * + * Takes FilterName string from the BandBin group and splits + * the combination into a vector of filter names.\n + * Valid combinations include: + *
      + *
    • For narrow-angle cameras: + *
        + *
      • Filter 1: "CL1", "RED", "BL1", "UV2", "UV1", "IRP0", + * "P120", "P60", "P0", "HAL", "IR4", "IR2" + *
      • Filter 2: "CL2", "GRN", "UV3", "BL2", "MT2", "CB2", + * "MT3", "CB3", "MT1", "CB1", "IR3", "IR1" + *
      + *
    • For wide-angle cameras: + *
        + *
      • Filter 1: "CL1", "IR3", "IR4", "IR5", "CB3", "MT3", + * "CB2", "MT2", "IR2" + *
      • Filter 2: "CL2", "RED", "GRN", "BL1", "VIO", "HAL", + * "IRP90", "IRP0", "IR1" + *
      + *
    + * + * @returns @b vector @b \ The optical filter names. + */ + vector FilterName() const {return p_filter;}; + + + /** + * @brief Returns a two-element array of indices associated with + * optical filter names. + * + * Takes FilterName string from the BandBin group and assigns + * an index for each filter. Valid values are between 0 and 35. + * This method is not called for wide-angle cameras. + * + * @returns @b vector @b \ The filter indices. + */ + vector FilterIndex() const {return p_filterIndex;}; + + + /** + * @brief Returns FlightSoftwareVersion from the Instrument + * group. + * + * Retrieves the flight software version used for this image. + * Valid values include 1.2, 1.3, 1.4, or "Unknown". This + * method returns an @b Isis::iString so that any value other + * than "Unknown" may be converted to @b double. + * + * @returns @b iString FlightSoftwareVersion + */ + inline iString FlightSoftwareVersion() const { return p_flightSoftwareVersion; }; + + + /** + * @brief Returns the first element of OpticsTemperature from + * the Instrument group. + * + * Retrieves the first value of the two-element array + * containing front and rear optics temperatures. Valid values + * are greater than -999.0 degrees Celcius. + * + * @returns @b double OpticsTemperature[0] + */ + inline double FrontOpticsTemp() const { return p_frontOpticsTemp; }; + + + /** + * @brief Returns GainModeId from the Instrument group. + * + * Finds the electronics gain setting in electrons per DN. + * Valid values include 12, 29, 95, or 215. These values correspond + * to GainState 3, 2, 1, and 0, respectively. + * + * @returns @b int GainModeId + * @see GainState() + */ + inline int GainModeId() const { return p_gainModeId; }; + + + /** + * @brief Returns GainState from the Instrument group. + * + * Finds the gain state, which is dependent on the Gain Mode ID. + * Valid values include 0, 1, 2, or 3. These values correspond + * to GainModeId 215, 95, 29, and 12, respectively. + * + * @returns @b int GainState + * @see GainModeId() + */ + inline int GainState () const { return p_gainState;}; + + + /** + * @brief Returns ImageNumber from the Archive group. + * + * Finds the number of seconds on the clock at shutter close. + * Valid values include real numbers. + * + * @returns @b double ImageNumber + */ + inline double ImageNumber() const {return p_imageNumber;}; + + + /** + * @brief Returns InstrumentDataRate from the Instrument group. + * + * Finds the rate at which data was transferred out, in + * kilobits per second. Valid values include 60.9, 121.9, + * 182.8, 243.7, 304.6, 365.6, or -999.0 (if data is + * unavailable). + * + * @returns @b double InstrumentDataRate + */ + inline double InstrumentDataRate() const { return p_instrumentDataRate; }; + + + /** + * @brief Returns InstrumentId from the Instrument group. + * + * Finds the type of camera used. Valid values include "ISSNA" + * (also called "NAC" or "narrow-angle") or "ISSWA" (also + * called "WAC" or "wide-angle"). + * + * @returns @b iString InstrumentId + */ + inline iString InstrumentId() const { return p_instrumentId;}; + + + /** + * @brief Returns the lower case form of InstrumentModeId from + * the Instrument group. + * + * Finds the summation mode used for this image. All images + * have 1 band and an equal number of lines and samples. Valid + * values include "full" (1024x1024), "sum2" (512x512), or + * "sum4" (256x256). These values correspond to SummingMode 1, + * 2, and 4, respectively. + * + * @returns @b double lower-cased InstrumentModeId + * @see SummingMode() + */ + inline iString InstrumentModeId() { return p_instrumentModeId.DownCase(); }; + + + /** + * @brief Returns ReadoutCycleIndex from the Instrument group. + * + * Finds the index associated with the image in the Readout + * Cycle table. Valid values are "Unknown" or in the range + * 0-15. This method returns an @b Isis::iString so that any + * value not equal to "Unknown" may be converted to + * @b int. + * + * @returns @b iString ReadoutCycleIndex + */ + inline iString ReadoutCycleIndex() const { return p_readoutCycleIndex; }; + + + /** + * @brief Returns ReadoutOrder from the Instrument group. + * + * Finds the integer value representing the readout order of + * the image. Valid values are + *
      + *
    • 0 : indicates narrow-angle was read out first + *
    • 1 : indicates wide-angle was read out first + *
    + * + * @returns @b int ReadoutOrder + */ + inline int ReadoutOrder() const { return p_readoutOrder; }; + + + /** + * @brief Returns ShutterModeId from the Instrument group. + * + * Indicates whether the exposure was part of a joint + * observation with the other ISS camera. Valid values include + * "BothSim", "NacOnly", "WacOnly", + * or "Unknown". + * + * @returns @b iString ShutterModeId + */ + inline iString ShutterModeId() const { return p_shutterModeId; }; + + + /** + * @brief Returns SummingMode from the Instrument group. + * + * Finds the summation mode, which is dependent on the + * Instrument Mode ID. Valid values include 1, 2, or 4. These + * values correspond to InstrumentModeId "Full", "Sum2", and + * "Sum4", respectively. + * + * @returns @b int SummingMode + * @see InstrumentModeId() + */ + inline int SummingMode() const { return p_summingMode; }; + + + /** + * @brief Returns whether AntiBloomingFlag from the Instrument + * group is "On". + * + * Indicates whether anti-blooming was used for the image. + * False implies the anti-blooming flag is "Off" or "Unknown". + * + * @returns @b bool True if AntiBloomingStateFlag "On" + */ + inline bool AntibloomingOn() const { return p_antiblooming;}; + + + private: + void Init (Pvl &lab); + void ReadLabels (Pvl &lab); + void ComputeImgProperties(); + + + //! Value of the PDS keyword AntiBloomingFlag in the cube's labels + string p_ABflag; + //! Indicates whether anti-blooming state flag on + bool p_antiblooming; + //! Value of the PDS keyword BiasStripMean in the cube's labels + double p_biasStripMean; + //! Indicates whether camera is narrow-angle + bool p_cissNA; + //! Value of the PDS keyword CompressionRatio in the cube's labels + iString p_compressionRatio; + //! Value of the PDS keyword CompressionType in the cube's labels + iString p_compressionType; + //! Value of the PDS keyword DataConversionType in the cube's labels + iString p_dataConversionType; + //! Value of the PDS keyword DelayedReadoutFlag in the cube's labels + iString p_delayedReadoutFlag; + //! Value of the PDS keyword ExposureDuration in the cube's labels + double p_exposureDuration; + //! Two-element array of optical filters used for this image + vector p_filter; + //! Two-element array of filter indices corresponding to optical filters + vector p_filterIndex; + //! Value of the PDS keyword FlightSoftwareVersion in the cube's labels + iString p_flightSoftwareVersion; + //! Value of the PDS keyword OpticsTemperature[0] in the cube's labels + double p_frontOpticsTemp; + //! Value of the PDS keyword GainModeId in the cube's labels + int p_gainModeId; + //! Value of the PDS keyword GainState in the cube's labels + int p_gainState; + //! Value of the PDS keyword ImageNumber in the cube's labels + double p_imageNumber; + //! Value of the PDS keyword ImageTime in the cube's labels + double p_instrumentDataRate; + //! Value of the PDS keyword InstrumentId in the cube's labels + iString p_instrumentId; + //! Value of the PDS keyword InstrumentModeId in the cube's labels + iString p_instrumentModeId; + //! Value of the PDS keyword ReadoutCycleIndex in the cube's labels + iString p_readoutCycleIndex; + //! Value of the PDS keyword ReadoutOrder in the cube's labels + int p_readoutOrder; + //! Value of the PDS keyword ShutterModeId in the cube's labels + iString p_shutterModeId; + //! Value of the PDS keyword SummingMode in the cube's labels + int p_summingMode; + }; +}; + +#endif diff --git a/isis/src/cassini/objs/CissLabels/CissLabels.truth b/isis/src/cassini/objs/CissLabels/CissLabels.truth new file mode 100644 index 0000000000000000000000000000000000000000..f475e6349c411132d8a06afe64e5981d7bbb1f04 --- /dev/null +++ b/isis/src/cassini/objs/CissLabels/CissLabels.truth @@ -0,0 +1,96 @@ + +Unit test for CissLabels + + +ISSWA,NotCompressed,12Bit,CAS-ISS,WacOnly,Full test... +IsNarrowAngle? 0 +Bias Strip Mean = 69.72 +Compression Ratio = NotCompressed +Compression Type = NotCompressed +Data Conversion Type = 12Bit +Delayed Readout Flag = No +Exposure Duration = 120 +Filter 1 Name = IR4 +Filter 2 Name = CL2 +Filter 1 Index = 10 +Filter 2 Index = 18 +Flight Software Version(FSW) = Unknown +Front Optics Temp = 8.48 +Gain Mode ID = 29 +Gain State = 2 +Image Number = 1.29456e+09 +Instrument Data Rate = 365.6 +Instrument ID = ISSWA +Readout Cycle Index = 0 +Shutter Mode ID = WacOnly +Summing Mode = 1 + +ISSNA,Lossy,Table,CAS-ISS2,NacOnly,Sum2 test... +IsNarrowAngle? 1 +Bias Strip Mean = 120.75 +Compression Ratio = 18.437473 +Compression Type = Lossy +Data Conversion Type = Table +Delayed Readout Flag = No +Exposure Duration = 2000 +Filter 1 Name = IRP0 +Filter 2 Name = MT3 +Filter 1 Index = 20 +Filter 2 Index = 16 +Flight Software Version(FSW) = 1.2 +Front Optics Temp = 0.71269 +Gain Mode ID = 12 +Gain State = 3 +Image Number = 1.35554e+09 +Instrument Data Rate = 182.784 +Instrument ID = ISSNA +Readout Cycle Index = 15 +Shutter Mode ID = NacOnly +Summing Mode = 2 + +ISSNA,Lossless,Table,CAS-ISS4,BothSim,Sum4 test... +IsNarrowAngle? 1 +Bias Strip Mean = 30 +Compression Ratio = 3.721945 +Compression Type = Lossless +Data Conversion Type = Table +Delayed Readout Flag = No +Exposure Duration = 18000 +Filter 1 Name = CL1 +Filter 2 Name = CB3 +Filter 1 Index = 17 +Filter 2 Index = 13 +Flight Software Version(FSW) = 1.4 +Front Optics Temp = 0.712693 +Gain Mode ID = 95 +Gain State = 1 +Image Number = 1.53636e+09 +Instrument Data Rate = 182.784 +Instrument ID = ISSNA +Readout Cycle Index = 15 +Shutter Mode ID = BothSim +Summing Mode = 4 + +ISSNA,Lossless,8LSB,CAS-ISS,NacOnly,Full test... +IsNarrowAngle? 1 +Bias Strip Mean = 49.75 +Compression Ratio = 3.976 +Compression Type = Lossless +Data Conversion Type = 8LSB +Delayed Readout Flag = No +Exposure Duration = 10 +Filter 1 Name = CL1 +Filter 2 Name = CL2 +Filter 1 Index = 17 +Filter 2 Index = 18 +Flight Software Version(FSW) = Unknown +Front Optics Temp = 6.43 +Gain Mode ID = 12 +Gain State = 3 +Image Number = 1.31363e+09 +Instrument Data Rate = 182.8 +Instrument ID = ISSNA +Readout Cycle Index = 15 +Shutter Mode ID = NacOnly +Summing Mode = 1 + diff --git a/isis/src/cassini/objs/CissLabels/Makefile b/isis/src/cassini/objs/CissLabels/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..31bb1dbe113ea8b97e1ab16a209ae7dcd326ddcf --- /dev/null +++ b/isis/src/cassini/objs/CissLabels/Makefile @@ -0,0 +1,5 @@ +INCS = CissLabels.h +SRCS = CissLabels.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/cassini/objs/CissLabels/unitTest.cpp b/isis/src/cassini/objs/CissLabels/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0e490fd446d16b17c8ed86a54d377a0510072836 --- /dev/null +++ b/isis/src/cassini/objs/CissLabels/unitTest.cpp @@ -0,0 +1,122 @@ +#include +#include "CissLabels.h" +#include "iException.h" +#include "Pvl.h" + +using namespace std; +using namespace Isis; + +int main (int argc, char *argv[]) { +try { + cout << endl << "Unit test for CissLabels" << endl << endl; + + Pvl p1("$cassini/testData/W1294561261_1.c2i.nospice.cub"); + Pvl p2("$cassini/testData/N1355543510_1.c2i.nospice.cub"); + Pvl p3("$cassini/testData/N1536363784_1.c2i.spice.cub"); + Pvl p4("$cassini/testData/N1313633704_1.c2i.nospice.cub"); + CissLabels lab1(p1); + CissLabels lab2(p2); + CissLabels lab3(p3); + CissLabels lab4(p4); + + cout << endl << "ISSWA,NotCompressed,12Bit,CAS-ISS,WacOnly,Full test..." << endl; + cout << "IsNarrowAngle? " << lab1.NarrowAngle() << endl; + cout << "Bias Strip Mean = " << lab1.BiasStripMean() << endl; + cout << "Compression Ratio = " << lab1.CompressionRatio() << endl; + cout << "Compression Type = " << lab1.CompressionType() << endl; + cout << "Data Conversion Type = " << lab1.DataConversionType() << endl; + cout << "Delayed Readout Flag = " << lab1.DelayedReadoutFlag() << endl; + cout << "Exposure Duration = " << lab1.ExposureDuration() << endl; + cout << "Filter 1 Name = " << lab1.FilterName()[0] << endl; + cout << "Filter 2 Name = " << lab1.FilterName()[1] << endl; + cout << "Filter 1 Index = " << lab1.FilterIndex()[0] << endl; + cout << "Filter 2 Index = " << lab1.FilterIndex()[1] << endl; + cout << "Flight Software Version(FSW) = " << lab1.FlightSoftwareVersion() << endl; + cout << "Front Optics Temp = " << lab1.FrontOpticsTemp() << endl; + cout << "Gain Mode ID = " << lab1.GainModeId() << endl; + cout << "Gain State = " << lab1.GainState() << endl; + cout << "Image Number = " << lab1.ImageNumber() << endl; + cout << "Instrument Data Rate = " << lab1.InstrumentDataRate() << endl; + cout << "Instrument ID = " << lab1.InstrumentId() << endl; + cout << "Readout Cycle Index = " << lab1.ReadoutCycleIndex() << endl; + cout << "Shutter Mode ID = " << lab1.ShutterModeId() << endl; + cout << "Summing Mode = " << lab1.SummingMode() << endl; + + + cout << endl << "ISSNA,Lossy,Table,CAS-ISS2,NacOnly,Sum2 test..." << endl; + cout << "IsNarrowAngle? " << lab2.NarrowAngle() << endl; + cout << "Bias Strip Mean = " << lab2.BiasStripMean() << endl; + cout << "Compression Ratio = " << lab2.CompressionRatio() << endl; + cout << "Compression Type = " << lab2.CompressionType() << endl; + cout << "Data Conversion Type = " << lab2.DataConversionType() << endl; + cout << "Delayed Readout Flag = " << lab2.DelayedReadoutFlag() << endl; + cout << "Exposure Duration = " << lab2.ExposureDuration() << endl; + cout << "Filter 1 Name = " << lab2.FilterName()[0] << endl; + cout << "Filter 2 Name = " << lab2.FilterName()[1] << endl; + cout << "Filter 1 Index = " << lab2.FilterIndex()[0] << endl; + cout << "Filter 2 Index = " << lab2.FilterIndex()[1] << endl; + cout << "Flight Software Version(FSW) = " << lab2.FlightSoftwareVersion() << endl; + cout << "Front Optics Temp = " << lab2.FrontOpticsTemp() << endl; + cout << "Gain Mode ID = " << lab2.GainModeId() << endl; + cout << "Gain State = " << lab2.GainState() << endl; + cout << "Image Number = " << lab2.ImageNumber() << endl; + cout << "Instrument Data Rate = " << lab2.InstrumentDataRate() << endl; + cout << "Instrument ID = " << lab2.InstrumentId() << endl; + cout << "Readout Cycle Index = " << lab2.ReadoutCycleIndex() << endl; + cout << "Shutter Mode ID = " << lab2.ShutterModeId() << endl; + cout << "Summing Mode = " << lab2.SummingMode() << endl; + + + cout << endl << "ISSNA,Lossless,Table,CAS-ISS4,BothSim,Sum4 test..." << endl; + cout << "IsNarrowAngle? " << lab3.NarrowAngle() << endl; + cout << "Bias Strip Mean = " << lab3.BiasStripMean() << endl; + cout << "Compression Ratio = " << lab3.CompressionRatio() << endl; + cout << "Compression Type = " << lab3.CompressionType() << endl; + cout << "Data Conversion Type = " << lab3.DataConversionType() << endl; + cout << "Delayed Readout Flag = " << lab3.DelayedReadoutFlag() << endl; + cout << "Exposure Duration = " << lab3.ExposureDuration() << endl; + cout << "Filter 1 Name = " << lab3.FilterName()[0] << endl; + cout << "Filter 2 Name = " << lab3.FilterName()[1] << endl; + cout << "Filter 1 Index = " << lab3.FilterIndex()[0] << endl; + cout << "Filter 2 Index = " << lab3.FilterIndex()[1] << endl; + cout << "Flight Software Version(FSW) = " << lab3.FlightSoftwareVersion() << endl; + cout << "Front Optics Temp = " << lab3.FrontOpticsTemp() << endl; + cout << "Gain Mode ID = " << lab3.GainModeId() << endl; + cout << "Gain State = " << lab3.GainState() << endl; + cout << "Image Number = " << lab3.ImageNumber() << endl; + cout << "Instrument Data Rate = " << lab3.InstrumentDataRate() << endl; + cout << "Instrument ID = " << lab3.InstrumentId() << endl; + cout << "Readout Cycle Index = " << lab3.ReadoutCycleIndex() << endl; + cout << "Shutter Mode ID = " << lab3.ShutterModeId() << endl; + cout << "Summing Mode = " << lab3.SummingMode() << endl; + + // 8LSB + cout << endl << "ISSNA,Lossless,8LSB,CAS-ISS,NacOnly,Full test..." << endl; + cout << "IsNarrowAngle? " << lab4.NarrowAngle() << endl; + cout << "Bias Strip Mean = " << lab4.BiasStripMean() << endl; + cout << "Compression Ratio = " << lab4.CompressionRatio() << endl; + cout << "Compression Type = " << lab4.CompressionType() << endl; + cout << "Data Conversion Type = " << lab4.DataConversionType() << endl; + cout << "Delayed Readout Flag = " << lab4.DelayedReadoutFlag() << endl; + cout << "Exposure Duration = " << lab4.ExposureDuration() << endl; + cout << "Filter 1 Name = " << lab4.FilterName()[0] << endl; + cout << "Filter 2 Name = " << lab4.FilterName()[1] << endl; + cout << "Filter 1 Index = " << lab4.FilterIndex()[0] << endl; + cout << "Filter 2 Index = " << lab4.FilterIndex()[1] << endl; + cout << "Flight Software Version(FSW) = " << lab4.FlightSoftwareVersion() << endl; + cout << "Front Optics Temp = " << lab4.FrontOpticsTemp() << endl; + cout << "Gain Mode ID = " << lab4.GainModeId() << endl; + cout << "Gain State = " << lab4.GainState() << endl; + cout << "Image Number = " << lab4.ImageNumber() << endl; + cout << "Instrument Data Rate = " << lab4.InstrumentDataRate() << endl; + cout << "Instrument ID = " << lab4.InstrumentId() << endl; + cout << "Readout Cycle Index = " << lab4.ReadoutCycleIndex() << endl; + cout << "Shutter Mode ID = " << lab4.ShutterModeId() << endl; + cout << "Summing Mode = " << lab4.SummingMode() << endl; + cout << endl; + return 0; + } + catch (iException &e) { + e.Report(); + } +} diff --git a/isis/src/cassini/objs/CisscalFile/CisscalFile.cpp b/isis/src/cassini/objs/CisscalFile/CisscalFile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1dc542c85bcedd398e0f722328686017f3f2b547 --- /dev/null +++ b/isis/src/cassini/objs/CisscalFile/CisscalFile.cpp @@ -0,0 +1,126 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/08/25 21:58:30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "iException.h" +#include "Filename.h" +#include "Message.h" +#include "CisscalFile.h" +#include "TextFile.h" +#include "iString.h" + +using namespace std; +namespace Isis { + /** + * Constructs a CisscalFile object and opens the specified file + * (including path). + * + * @param filename Filename (including path) to be opened by TextFile object. + * + * @param openmode Open Mode of file opened by TextFile object. + *
      + *
    • "input" Opens file for + * Input: Read Only. Fails if file does + * not exist. + *
    • "output" Opens file + * for Output: Read/Write. Creates file, + * fails if file exists. + *
    • "overwrite" Opens file + * for Output: Read/Write. Creates file, + * truncates if file exists. + *
    • "append" Opens file + * for Append: Read/Write. Creates file, + * appends if file exists. + *
    + * Defaults to "input". + * + * @param extension Extension to be added to filename (added only if not + * already on filename). Defaults to "" + */ + CisscalFile::CisscalFile (const string &filename, const char *openmode, + const char *extension):TextFile(filename, openmode, extension){ + p_begindataFound = false; + } + + /** + * @brief Get next line of valid data, protected + * + * This method overwrites TextFile's protected method of + * the same name. It is called by the public overwritten method + * GetLine(), as in the parent class. + * + * @param line String to be rewritten with contents of the + * next line read from file + * @returns bool Indicates whether line was read + * @throws Isis::iException::Io "Error reading text file" + * @see GetLine() + */ + bool CisscalFile::p_GetLine(string &line) { + OpenChk(true); + // Try to read the next line + getline(p_stream, line); + // Check for end of file + if (p_stream.eof()) { + line = ""; + return false; + } + // See if an error occured + if (!p_stream.good()) { + line = ""; + string message = "TextFile:GetLine: -> Error reading text file: [" + + p_filename + "]"; + throw Isis::iException::Message(Isis::iException::Io,message,_FILEINFO_); + } + // Search for tag "\begindata" if it was not already found by recursively using this method + if (!p_begindataFound) { + if(line.find("\\begindata") == string::npos){ + return p_GetLine(line); + } + p_begindataFound = true; + return p_GetLine(line); + } + // We have a good line + return true; + } + + /** + * @brief Get next line of valid data + * + * This protected method overrides the base class method from + * TextFile of the same name. It finds the next line of + * valid data. If the "\begindata" tag has not been + * already found, it searches for that tag. Once found, every + * line beyond that is considered data and the method will + * retrieve the next line. Returns True if read a line, False if + * End Of File. + * + * @param line String to be rewritten with contents of the + * next line read from file + * @returns bool Indicates whether line was read + * @throws Isis::iException::Io "Error reading text file" + * @see p_GetLine() + */ + bool CisscalFile::GetLine(string &line) { + return p_GetLine(line); + } + +}//end CisscalFile.cpp diff --git a/isis/src/cassini/objs/CisscalFile/CisscalFile.h b/isis/src/cassini/objs/CisscalFile/CisscalFile.h new file mode 100644 index 0000000000000000000000000000000000000000..71e7e36cfe911b505363465b8031b9ad74f8b339 --- /dev/null +++ b/isis/src/cassini/objs/CisscalFile/CisscalFile.h @@ -0,0 +1,57 @@ +#ifndef CISSCALFILE_H +#define CISSCALFILE_H +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/08/25 21:58:30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "TextFile.h" +using namespace std; +namespace Isis { +/** + * @brief Extends TextFile to handle Cassini ISS + * calibration files. + * This class was created as an extension of TextFile to + * be able to read in Cassini ISS calibration files used + * by the Isis ciss2isis and cisscal + * applications. It is able to read PDS style text files + * and skip all header info that exists before the tag + * "\begindata". + * + * @ingroup Cassini + * @author 2008-03-27 Jeannie Walldren + * @history 2008-03-27 Jeannie Walldren - Original Version. + */ + class CisscalFile : public TextFile{ + public: + CisscalFile (const string &filename, const char *openmode="input", + const char *extension = ""); + ~CisscalFile (){TextFile::Close();}; //!> Destructor closes the text file. + bool GetLine(string &line); + protected: + bool p_begindataFound; //!> Flag variable indicates whether the tag "\begindata" has been found. + bool p_GetLine(string &line); + }; +}; +#endif + + diff --git a/isis/src/cassini/objs/CisscalFile/CisscalFile.truth b/isis/src/cassini/objs/CisscalFile/CisscalFile.truth new file mode 100644 index 0000000000000000000000000000000000000000..cd1446f5e05a160cb669528173ba73bff7596d19 --- /dev/null +++ b/isis/src/cassini/objs/CisscalFile/CisscalFile.truth @@ -0,0 +1,10 @@ + +Unit test for CisscalFile +-------------------------------------------- +1) Read valid data from /tmp/CisscalFile.tmp +data line 1 +data line 2 +data line 3: last line of data, next line (last in file) is empty + +-------------------------------------------- +2) Remove temp file -> /tmp/CisscalFile.tmp <- diff --git a/isis/src/cassini/objs/CisscalFile/Makefile b/isis/src/cassini/objs/CisscalFile/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d9e8a8f2c9eb18111d185bbc6a794e17f7174b19 --- /dev/null +++ b/isis/src/cassini/objs/CisscalFile/Makefile @@ -0,0 +1,5 @@ +INCS = CisscalFile.h +SRCS = CisscalFile.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/cassini/objs/CisscalFile/unitTest.cpp b/isis/src/cassini/objs/CisscalFile/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db73c3a6b136cc803b171619d19628a76d6ee18d --- /dev/null +++ b/isis/src/cassini/objs/CisscalFile/unitTest.cpp @@ -0,0 +1,128 @@ +#include +#include +#include +#include "CisscalFile.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main (int argc, char *argv[]) { + Preference::Preferences(true); + cout << endl << "Unit test for CisscalFile" << endl; + cout << "--------------------------------------------" << endl; + + +// ---------------------------------------------------------------------------------- + + string testFile = "/tmp/CisscalFile.tmp"; + // setup test data + string testLines[8]; + + // setup line test data + testLines[0] = "PDS_VERSION_ID = PDS3"; + testLines[1] = "RECORD_TYPE = STREAM"; + testLines[2] = " "; + testLines[3] = "\\begindata"; + testLines[4] = "data line 1"; + testLines[5] = "data line 2"; + testLines[6] = "data line 3: last line of data, next line (last in file) is empty"; + testLines[7] = ""; + + // calc cumulative byte counts for each line - to check CisscalFile.Size() + streamsize testLineBytes[8]; + streamsize numBytes = 0; + streamsize numBytesFiltered = 0; + vector testLinesVector; + + for (int i=0; i<=7; i++) { + numBytes += testLines[i].length() + strlen("\n"); + testLineBytes[i] = numBytes; + testLinesVector.push_back(testLines[i]); + } + + numBytesFiltered = numBytes - numBytesFiltered; + Isis::TextFile p(testFile, "overwrite", testLinesVector); + p.Close(); + +// ---------------------------------------------------------------------------------- + + cout << "1) Read valid data from " << testFile << endl; + try { + Isis::CisscalFile f(testFile); + bool lineFound = false; + string line; + // data line 1 + lineFound = f.GetLine(line); + if (!lineFound) { + cout << "First Line Not Found" << endl; + return 0; + } + if (line != testLines[4]) { + cout << " *** Failed to Find \"\\begindata\" Tag *** " << endl; + cout << " First line of data should be: -> " << testLines[4] << " <-" << endl; + cout << " returned is: -> " << line << " <-" << endl; + return 0; + } + cout << line << endl; + // data line 2 + lineFound = f.GetLine(line); + if(!lineFound) { + cout << "Second Line Not Found" << endl; + return 0; + } + if (line != testLines[5]) { + cout << " *** Failed to Match Second Line *** " << endl; + cout << " First line of data should be: -> " << testLines[5] << " <-" << endl; + cout << " returned is: -> " << line << " <-" << endl; + return 0; + } + cout << line << endl; + // data line 3 + lineFound = f.GetLine(line); + if(!lineFound) { + cout << "Third Line Not Found" << endl; + return 0; + } + if (line != testLines[6]) { + cout << " *** Failed to Match Third Line *** " << endl; + cout << " First line of data should be: -> " << testLines[6] << " <-" << endl; + cout << " returned is: -> " << line << " <-" << endl; + return 0; + } + cout << line << endl; + // last line, empty + lineFound = f.GetLine(line); + if(!lineFound) { + cout << "Last Line Not Found" << endl; + return 0; + } + if (line != testLines[7]) { + cout << " *** Failed to Match Last Line *** " << endl; + cout << " First line of data should be: -> " << testLines[7] << " <-" << endl; + cout << " returned is: -> " << line << " <-" << endl; + return 0; + } + cout << line << endl; + // grab line beyond end of file + lineFound = f.GetLine(line); + if (lineFound) { + cout << "Extra Line Found: -> " << line << " <-" << endl; + lineFound = f.GetLine(line); + cout << "Next Line True? -> " << lineFound << " <-" << endl; + return 0; + } + cout << "--------------------------------------------" << endl; + } + catch (Isis::iException &e) { + e.Report(false); + } +//----------------------------------------------------------------------------------- + cout << "2) Remove temp file -> " << testFile << " <-" << endl; + if (remove(testFile.c_str())) { + cout << "*** Failed to remove tmp file: " << testFile << endl; + } + return 0; +} + diff --git a/isis/src/cassini/objs/IssNACamera/Camera.plugin b/isis/src/cassini/objs/IssNACamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..874c8692c5d0c10f2c7930612cf2cd37a2b0a142 --- /dev/null +++ b/isis/src/cassini/objs/IssNACamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = Cassini-Huygens/ISSNA + Version = 1 + Library = IssNACamera + Routine = IssNACameraPlugin +EndGroup + diff --git a/isis/src/cassini/objs/IssNACamera/IssNACamera.cpp b/isis/src/cassini/objs/IssNACamera/IssNACamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d1dac82cf00f74eac774318665cbb68c85364a0 --- /dev/null +++ b/isis/src/cassini/objs/IssNACamera/IssNACamera.cpp @@ -0,0 +1,59 @@ +// $Id: IssNACamera.cpp,v 1.6 2009/08/31 15:12:29 slambright Exp $ +#include "IssNACamera.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "RadialDistortionMap.h" +#include "iString.h" + +using namespace std; +using namespace Isis; +namespace Cassini { + IssNACamera::IssNACamera (Pvl &lab) : FramingCamera(lab) { + PvlGroup bandBin = lab.FindGroup ("BandBin",Pvl::Traverse); + // Get the camera characteristics + iString key = string("INS"+(iString)(int)NaifIkCode()+"_")+ (string)bandBin["FilterName"] + "_FOCAL_LENGTH"; + key = key.Convert("/",'_'); + double focalLength = Spice::GetDouble(key); + + SetFocalLength (focalLength); + SetPixelPitch (); + InstrumentRotation()->SetFrame(Spice::GetInteger("INS_"+(iString)(int)NaifIkCode()+"_FRAME_ID")); + + // Get the start time in et + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + string stime = inst["StartTime"]; + double et; + str2et_c(stime.c_str(),&et); + double exposureDuration = (double)inst["ExposureDuration"] /1000.0; + et += exposureDuration / 2.0; + + // Setup detector map + int summingMode = inst["SummingMode"]; + CameraDetectorMap *detectorMap = new CameraDetectorMap(this); + detectorMap->SetDetectorLineSumming(summingMode); + detectorMap->SetDetectorSampleSumming(summingMode); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + + focalMap->SetDetectorOrigin (Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_SAMPLE"), + Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_LINE")); + + // Setup distortion map + double k1 = Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_K1"); + new RadialDistortionMap(this, k1); + + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(et); + LoadCache(); + } +} + +extern "C" Camera *IssNACameraPlugin(Pvl &lab) { + return new Cassini::IssNACamera(lab); +} diff --git a/isis/src/cassini/objs/IssNACamera/IssNACamera.h b/isis/src/cassini/objs/IssNACamera/IssNACamera.h new file mode 100644 index 0000000000000000000000000000000000000000..315ae4b5176d6c4dc1618ab3f034c83bf05b3437 --- /dev/null +++ b/isis/src/cassini/objs/IssNACamera/IssNACamera.h @@ -0,0 +1,38 @@ +// $Id: IssNACamera.h,v 1.7 2009/08/31 15:12:29 slambright Exp $ +#ifndef IssNACamera_h +#define IssNACamera_h + +#include "FramingCamera.h" + +namespace Cassini { + /** + * @brief Cassini ISS Narrow Angle Camera class + * + * This is the camera class for the IssNACamera + * + * @ingroup Cassini + * + * @author 2007-07-10 Steven Koechle + * + * @internal + * @history 2007-07-10 Steven Koechle - Original Version + * @history 2007-07-10 Steven Koechle - Removed hardcoding of + * NAIF Instrument number + * @history 2007-07-11 Steven Koechle - casted NaifIkCode to + * int before iString to fix problem on Linux 32bit + * @history 2008-08-08 Steven Lambright Now using the new LoadCache(...) + * method instead of CreateCache(...). + * @history 2009-01-22 Kris Becker Added new frame rotation to the CK + * frame hierarchy to convert to detector coordinates. This is + * essentially a 180 degree rotation. The frame definition is + * actually contained in the IAK. + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class IssNACamera : public Isis::FramingCamera { + public: + IssNACamera (Isis::Pvl &lab); + ~IssNACamera () {}; + }; +}; +#endif diff --git a/isis/src/cassini/objs/IssNACamera/IssNACamera.truth b/isis/src/cassini/objs/IssNACamera/IssNACamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..be099907d6b9169121ce2e5a11e8e380422e88c0 --- /dev/null +++ b/isis/src/cassini/objs/IssNACamera/IssNACamera.truth @@ -0,0 +1,28 @@ +Unit Test for IssNACamera... +Filename: N1525100863_2.cub +CK Frame: 14082360 + +For upper left corner ... +Line, Sample: 0.5000, 0.5000 +Lat, Long: 8.2462, 323.2153 +WestLon: 36.7847 + +For upper right corner ... +Line, Sample: 0.5000, 1024.5000 +Lat, Long: 23.3914, 331.5063 +WestLon: 28.4937 + +For lower left corner ... +Line, Sample: 1024.5000, 0.5000 +Lat, Long: -0.6730, 339.0561 +WestLon: 20.9439 + +For lower right corner ... +Line, Sample: 1024.5000, 1024.5000 +Lat, Long: 13.9600, 347.9185 +WestLon: 12.0815 + +For center pixel position ... +Line, Sample: 512.5000, 512.5000 +Lat, Long: 11.0856, 335.8600 +WestLon: 24.1400 diff --git a/isis/src/cassini/objs/IssNACamera/Makefile b/isis/src/cassini/objs/IssNACamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3e3e22def5bdcef9d4ee80822635f098a00013d2 --- /dev/null +++ b/isis/src/cassini/objs/IssNACamera/Makefile @@ -0,0 +1,5 @@ +INCS = IssNACamera.h +SRCS = IssNACamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/cassini/objs/IssNACamera/resources/IssNAAddendumXXX.ti b/isis/src/cassini/objs/IssNACamera/resources/IssNAAddendumXXX.ti new file mode 100644 index 0000000000000000000000000000000000000000..7d7590e8f8e683bd4ae708ec8338470e1140319f --- /dev/null +++ b/isis/src/cassini/objs/IssNACamera/resources/IssNAAddendumXXX.ti @@ -0,0 +1,105 @@ +$Id: IssNAAddendumXXX.ti,v 1.1 2009/01/22 22:04:56 kbecker Exp $ + +Data was gathered from the Isis2 file: iss_parameters.def.1 + +The Default focal length is not being used, but was left in +from isis2. + +The boresight of the instrument has been updated to the center +of the detector. Previous values were used along with specific +CK rotation angle frames that were propagated from ISIS2. These +values proved to be incorrect and have subsequently been corrected +so as to use the frames kernel directly as provided by NAIF. See +below for additional details pertaining to the SPICE frames +kernels as there is some special handling of this kernel. +(KJB, 2009-01-22) + +\begindata +INS-82360_BORESIGHT_LINE=512.5 +INS-82360_BORESIGHT_SAMPLE=512.5 + +INS-82360_DEFAULT_FOCAL_LENGTH=2003.44 +INS-82360_BL1_CL2_FOCAL_LENGTH=2002.79 +INS-82360_CL1_CL2_FOCAL_LENGTH=2002.88 +INS-82360_CL1_GRN_FOCAL_LENGTH=2002.75 +INS-82360_CL1_IR1_FOCAL_LENGTH=2002.74 +INS-82360_RED_CL2_FOCAL_LENGTH=2002.69 +INS-82360_CL1_IR3_FOCAL_LENGTH=2002.65 +INS-82360_CL1_BL2_FOCAL_LENGTH=2002.37 +INS-82360_CL1_CB1_FOCAL_LENGTH=2002.66 +INS-82360_CL1_CB2_FOCAL_LENGTH=2002.66 +INS-82360_CL1_CB3_FOCAL_LENGTH=2002.68 +INS-82360_CL1_MT1_FOCAL_LENGTH=2002.88 +INS-82360_CL1_MT2_FOCAL_LENGTH=2002.91 +INS-82360_CL1_MT3_FOCAL_LENGTH=2002.87 +INS-82360_CL1_UV3_FOCAL_LENGTH=2003.09 +INS-82360_HAL_CL2_FOCAL_LENGTH=2002.94 +INS-82360_IR2_CL2_FOCAL_LENGTH=2002.71 +INS-82360_IR2_IR1_FOCAL_LENGTH=2002.56 +INS-82360_IR2_IR3_FOCAL_LENGTH=2002.55 +INS-82360_IR4_CL2_FOCAL_LENGTH=2002.89 +INS-82360_IR4_IR3_FOCAL_LENGTH=2002.81 +INS-82360_IRP0_CB2_FOCAL_LENGTH=2002.48 +INS-82360_IRP0_CB3_FOCAL_LENGTH=2002.74 +INS-82360_IRP0_IR1_FOCAL_LENGTH=2002.60 +INS-82360_IRP0_IR3_FOCAL_LENGTH=2002.48 +INS-82360_IRP0_MT2_FOCAL_LENGTH=2002.72 +INS-82360_IRP0_MT3_FOCAL_LENGTH=2002.72 +INS-82360_P0_BL2_FOCAL_LENGTH=2002.19 +INS-82360_P0_CB1_FOCAL_LENGTH=2002.30 +INS-82360_P0_GRN_FOCAL_LENGTH=2002.38 +INS-82360_P0_IR1_FOCAL_LENGTH=2002.35 +INS-82360_P0_MT1_FOCAL_LENGTH=2002.40 +INS-82360_P0_UV3_FOCAL_LENGTH=2002.71 +INS-82360_P120_BL2_FOCAL_LENGTH=2002.11 +INS-82360_P120_CB1_FOCAL_LENGTH=2002.28 +INS-82360_P120_GRN_FOCAL_LENGTH=2002.38 +INS-82360_P120_IR1_FOCAL_LENGTH=2002.39 +INS-82360_P120_MT1_FOCAL_LENGTH=2002.54 +INS-82360_P120_UV3_FOCAL_LENGTH=2002.71 +INS-82360_P60_BL2_FOCAL_LENGTH=2002.13 +INS-82360_P60_CB1_FOCAL_LENGTH=2002.18 +INS-82360_P60_GRN_FOCAL_LENGTH=2002.28 +INS-82360_P60_IR1_FOCAL_LENGTH=2002.36 +INS-82360_P60_MT1_FOCAL_LENGTH=2002.34 +INS-82360_P60_UV3_FOCAL_LENGTH=2002.51 +INS-82360_RED_GRN_FOCAL_LENGTH=2002.61 +INS-82360_RED_IR1_FOCAL_LENGTH=2002.48 +INS-82360_UV1_CL2_FOCAL_LENGTH=2003.03 +INS-82360_UV2_CL2_FOCAL_LENGTH=2002.91 +INS-82360_UV2_UV3_FOCAL_LENGTH=2002.90 + +INS-82360_PIXEL_PITCH=.012 + +INS-82360_TRANSX=(0.0 0.012 0.0) +INS-82360_TRANSY=(0.0 0.0 0.012) + +INS-82360_ITRANSS=(0.0 83.333333333333333 0.0) +INS-82360_ITRANSL=(0.0 0.0 83.333333333333333) + +INS-82360_K1=.000008 +\begintext + +The Cassini ISS NAC frames kernel is missing one final rotation in its +CK frames hierarchy. A 180 degree rotation about the detector center +(Z-axis) is required to map into the proper detector orientation. This +is not included in the NAIF SPICE frames kernel (cas_v??.tf). The following +frames definition applies the rotation into camera coordinates and must +be the frame used in the ISIS camera model converting from the s/c frame to +the instrument. (KJB, 2009-01-22) + +\begindata + +INS_-82360_FRAME_ID = 14082360 +FRAME_CASSINI_ISS_NAC_USGS = 14082360 +FRAME_14082360_NAME = 'CASSINI_ISS_NAC_USGS' +FRAME_14082360_CLASS = 4 +FRAME_14082360_CLASS_ID = 14082360 +FRAME_14082360_CENTER = -82 +TKFRAME_14082360_SPEC = 'ANGLES' +TKFRAME_14082360_RELATIVE = 'CASSINI_ISS_NAC' +TKFRAME_14082360_ANGLES = (0.0, 0.0, 180.0) +TKFRAME_14082360_AXES = ( 1, 2, 3) +TKFRAME_14082360_UNITS = 'DEGREES' + +\begintext diff --git a/isis/src/cassini/objs/IssNACamera/unitTest.cpp b/isis/src/cassini/objs/IssNACamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f472208ce544fe071a89b14274205e0d3787c49a --- /dev/null +++ b/isis/src/cassini/objs/IssNACamera/unitTest.cpp @@ -0,0 +1,68 @@ +// $Id: unitTest.cpp,v 1.6 2009/01/22 22:04:55 kbecker Exp $ +using namespace std; + +#include +#include +#include "Camera.h" +#include "Filename.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for IssNACamera..." << endl; + /* + * Sample/Line TestLineSamp points changed for the IssNACamera + */ + try{ + +// Isis::Pvl p("N1477312678_2.cub"); + Isis::Pvl p("$cassini/testData/N1525100863_2.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << "Filename: " << Isis::Filename(p.Filename()).Name() << endl; + cout << "CK Frame: " << cam->InstrumentRotation()->Frame() << endl; + cout.setf(std::ios::fixed); + cout << setprecision(4); + + // Test all four corners to make sure the conversions are right + cout << "\nFor upper left corner ..." << endl; + TestLineSamp(cam, 0.5, 0.5); + + cout << "\nFor upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples()+0.5, 0.5); + + cout << "\nFor lower left corner ..." << endl; + TestLineSamp(cam, 0.5, cam->Lines()+0.5); + + cout << "\nFor lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples()+0.5, cam->Lines()+0.5); + + double samp = cam->Samples() / 2.0 + 0.5; + double line = cam->Lines() / 2.0 + 0.5; + cout << "\nFor center pixel position ..." << endl; + TestLineSamp(cam, samp, line); + + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + cout << "Line, Sample: " << line << ", " << samp << endl; + bool success = cam->SetImage(samp,line); + + if(success) { + cout << "Lat, Long: " << cam->UniversalLatitude() << ", " + << cam->UniversalLongitude() << endl; + double westlon = -cam->UniversalLongitude(); + while(westlon < 0.0) westlon += 360.0; + cout << "WestLon: " << westlon << endl; + } + +} diff --git a/isis/src/cassini/objs/IssWACamera/Camera.plugin b/isis/src/cassini/objs/IssWACamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..a7850039eb52e3ca4d7c1742a140de6151e20437 --- /dev/null +++ b/isis/src/cassini/objs/IssWACamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = Cassini-Huygens/ISSWA + Version = 1 + Library = IssWACamera + Routine = IssWACameraPlugin +EndGroup + diff --git a/isis/src/cassini/objs/IssWACamera/IssWACamera.cpp b/isis/src/cassini/objs/IssWACamera/IssWACamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f296a22d075e8f24a4a67d6b1f51ebcb1429e48b --- /dev/null +++ b/isis/src/cassini/objs/IssWACamera/IssWACamera.cpp @@ -0,0 +1,60 @@ +// $Id: IssWACamera.cpp,v 1.6 2009/08/31 15:12:29 slambright Exp $ +#include "IssWACamera.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "RadialDistortionMap.h" +#include "iString.h" + +using namespace std; +using namespace Isis; +namespace Cassini { + IssWACamera::IssWACamera (Pvl &lab) : FramingCamera(lab) { + PvlGroup bandBin = lab.FindGroup ("BandBin",Pvl::Traverse); + // Get the camera characteristics + iString key = string("INS"+(iString)(int)NaifIkCode()+"_")+ (string)bandBin["FilterName"] + "_FOCAL_LENGTH"; + key = key.Convert("/",'_'); + double focalLength = Spice::GetDouble(key); + + SetFocalLength (focalLength); + SetPixelPitch (); + InstrumentRotation()->SetFrame(Spice::GetInteger("INS_"+(iString)(int)NaifIkCode()+"_FRAME_ID")); + + + // Get the start time in et + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + string stime = inst["StartTime"]; + double et; + str2et_c(stime.c_str(),&et); + double exposureDuration = (double)inst["ExposureDuration"] /1000.0; + et += exposureDuration / 2.0; + + // Setup detector map + int summingMode = inst["SummingMode"]; + CameraDetectorMap *detectorMap = new CameraDetectorMap(this); + detectorMap->SetDetectorLineSumming(summingMode); + detectorMap->SetDetectorSampleSumming(summingMode); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + + focalMap->SetDetectorOrigin (Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_SAMPLE"), + Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_LINE")); + + // Setup distortion map + double k1 = Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_K1"); + new RadialDistortionMap(this, k1); + + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(et); + LoadCache(); + } +} + +extern "C" Camera *IssWACameraPlugin(Pvl &lab) { + return new Cassini::IssWACamera(lab); +} diff --git a/isis/src/cassini/objs/IssWACamera/IssWACamera.h b/isis/src/cassini/objs/IssWACamera/IssWACamera.h new file mode 100644 index 0000000000000000000000000000000000000000..5324845e7a67b238ec7239ff9de12d3b07fdd4e7 --- /dev/null +++ b/isis/src/cassini/objs/IssWACamera/IssWACamera.h @@ -0,0 +1,38 @@ +// $Id: IssWACamera.h,v 1.7 2009/08/31 15:12:29 slambright Exp $ +#ifndef IssWACamera_h +#define IssWACamera_h + +#include "FramingCamera.h" + +namespace Cassini { + /** + * @brief Cassini ISS Wide Angle Camera class + * + * This is the camera class for the IssWACamera + * + * @ingroup Cassini + * + * @author 2007-07-10 Steven Koechle + * + * @internal + * @history 2007-07-10 Steven Koechle - Original Version + * @history 2007-07-10 Steven Koechle - Removed hardcoding of + * NAIF Instrument number + * @history 2007-07-11 Steven Koechle - casted NaifIkCode to + * int before iString to fix problem on Linux 32bit + * @history 2008-08-08 Steven Lambright Now using the new LoadCache(...) + * method instead of CreateCache(...). + * @history 2009-01-22 Kris Becker Added new frame rotation to the CK frame + * hierarchy to convert to detector coordinates. This is + * essentially a 180 degree rotation. The frame definition is + * actually contained in the IAK. + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class IssWACamera : public Isis::FramingCamera { + public: + IssWACamera (Isis::Pvl &lab); + ~IssWACamera () {}; + }; +}; +#endif diff --git a/isis/src/cassini/objs/IssWACamera/IssWACamera.truth b/isis/src/cassini/objs/IssWACamera/IssWACamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..36900ed7ca502ecc5016af66e89ef1d51397f8a0 --- /dev/null +++ b/isis/src/cassini/objs/IssWACamera/IssWACamera.truth @@ -0,0 +1,26 @@ +Unit Test for IssWACamera... +Filename: W1525116136_1.cub +CK Frame: 14082361 + +For upper left corner ... +Line, Sample: 0.5000, 0.5000 +Lat, Long: 19.8765, 301.2891 +WestLon: 58.7109 + +For upper right corner ... +Line, Sample: 0.5000, 512.5000 +Point not on planet! + +For lower left corner ... +Line, Sample: 512.5000, 0.5000 +Lat, Long: -4.9743, 356.8556 +WestLon: 3.1444 + +For lower right corner ... +Line, Sample: 512.5000, 512.5000 +Point not on planet! + +For center pixel position ... +Line, Sample: 256.5000, 256.5000 +Lat, Long: 33.7641, 344.5575 +WestLon: 15.4425 diff --git a/isis/src/cassini/objs/IssWACamera/Makefile b/isis/src/cassini/objs/IssWACamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8e0e4e175436d6daf3e75ab40d709575a7cd7853 --- /dev/null +++ b/isis/src/cassini/objs/IssWACamera/Makefile @@ -0,0 +1,5 @@ +INCS = IssWACamera.h +SRCS = IssWACamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/cassini/objs/IssWACamera/resources/IssWAAddendumXXX.ti b/isis/src/cassini/objs/IssWACamera/resources/IssWAAddendumXXX.ti new file mode 100644 index 0000000000000000000000000000000000000000..e09cef4d953bb0a6d63084befe7fc61af6ea9fd6 --- /dev/null +++ b/isis/src/cassini/objs/IssWACamera/resources/IssWAAddendumXXX.ti @@ -0,0 +1,86 @@ +$Id: IssWAAddendumXXX.ti,v 1.1 2009/01/22 22:14:49 kbecker Exp $ + +Data was gathered from the Isis2 file: iss_parameters.def.1 + +The Default focal length is not being used, but was left in +from isis2. + +The boresight of the instrument has been updated to the center +of the detector. Previous values were used along with specific +CK rotation angle frames that were propagated from ISIS2. These +values proved to be incorrect and have subsequently been corrected +so as to use the frames kernel directly as provided by NAIF. See +below for additional details pertaining to the SPICE frames +kernels as there is some special handling of this kernel. +(KJB, 2009-01-22) + +\begindata +INS-82361_BORESIGHT_LINE=512.5 +INS-82361_BORESIGHT_SAMPLE=512.5 + +INS-82361_DEFAULT_FOCAL_LENGTH=200.77 +INS-82361_CB2_CL2_FOCAL_LENGTH=200.85 +INS-82361_CB2_IRP90_FOCAL_LENGTH=200.83 +INS-82361_CB2_IRP0_FOCAL_LENGTH=200.82 +INS-82361_CB3_CL2_FOCAL_LENGTH=201.22 +INS-82361_CB3_IRP90_FOCAL_LENGTH=201.12 +INS-82361_CB3_IRP0_FOCAL_LENGTH=201.11 +INS-82361_CL1_BL1_FOCAL_LENGTH=200.86 +INS-82361_CL1_CL2_FOCAL_LENGTH=200.77 +INS-82361_CL1_GRN_FOCAL_LENGTH=200.71 +INS-82361_CL1_HAL_FOCAL_LENGTH=200.74 +INS-82361_CL1_IR1_FOCAL_LENGTH=200.80 +INS-82361_CL1_RED_FOCAL_LENGTH=200.74 +INS-82361_CL1_VIO_FOCAL_LENGTH=201.09 +INS-82361_IR2_CL2_FOCAL_LENGTH=200.97 +INS-82361_IR2_IR_FOCAL_LENGTH=200.95 +INS-82361_IR2_IRP90_FOCAL_LENGTH=200.95 +INS-82361_IR3_CL2_FOCAL_LENGTH=201.04 +INS-82361_IR3_IRP90_FOCAL_LENGTH=201.03 +INS-82361_IR3_IRP0_FOCAL_LENGTH=201.04 +INS-82361_IR4_CL2_FOCAL_LENGTH=201.22 +INS-82361_IR4_IRP90_FOCAL_LENGTH=201.16 +INS-82361_IR4_IRP0_FOCAL_LENGTH=201.15 +INS-82361_MT2_CL2_FOCAL_LENGTH=200.82 +INS-82361_MT2_IRP0_FOCAL_LENGTH=200.81 +INS-82361_MT2_IRP90_FOCAL_LENGTH=200.82 +INS-82361_MT3_CL2_FOCAL_LENGTH=201.04 +INS-82361_MT3_IRP0_FOCAL_LENGTH=201.06 +INS-82361_MT3_IRP90_FOCAL_LENGTH=201.07 + +INS-82361_PIXEL_PITCH=.012 + +INS-82361_TRANSX=(0.0 0.012 0.0) +INS-82361_TRANSY=(0.0 0.0 0.012) + +INS-82361_ITRANSS=(0.0 83.333333333333333 0.0) +INS-82361_ITRANSL=(0.0 0.0 83.333333333333333) + +INS-82361_K1=.000062 + +\begintext + +The Cassini ISS WAC frames kernel is missing one final rotation in its +CK frames hierarchy. A 180 degree rotation about the detector center +(Z-axis) is required to map into the proper detector orientation. This +is not included in the NAIF SPICE frames kernel (cas_v??.tf). The following +frames definition applies the rotation into camera coordinates and must +be the frame used in the ISIS camera model converting from the s/c frame to +the instrument. (KJB, 2009-01-22) + +\begindata + +INS_-82361_FRAME_ID = 14082361 +FRAME_CASSINI_ISS_WAC_USGS = 14082361 +FRAME_14082361_NAME = 'CASSINI_ISS_WAC_USGS' +FRAME_14082361_CLASS = 4 +FRAME_14082361_CLASS_ID = 14082361 +FRAME_14082361_CENTER = -82 +TKFRAME_14082361_SPEC = 'ANGLES' +TKFRAME_14082361_RELATIVE = 'CASSINI_ISS_WAC' +TKFRAME_14082361_ANGLES = (0.0, 0.0, 180.0) +TKFRAME_14082361_AXES = ( 1, 2, 3) +TKFRAME_14082361_UNITS = 'DEGREES' + +\begintext + diff --git a/isis/src/cassini/objs/IssWACamera/unitTest.cpp b/isis/src/cassini/objs/IssWACamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1769640193c59118a869aca7b4bf6306cb27f35e --- /dev/null +++ b/isis/src/cassini/objs/IssWACamera/unitTest.cpp @@ -0,0 +1,70 @@ +// $Id: unitTest.cpp,v 1.6 2009/01/22 22:43:29 kbecker Exp $ +using namespace std; + +#include +#include +#include "Camera.h" +#include "Filename.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for IssWACamera..." << endl; + /* + * Sample/Line TestLineSamp points changed for the IssNACamera + */ + try{ + + Isis::Pvl p("$cassini/testData/W1525116136_1.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << "Filename: " << Isis::Filename(p.Filename()).Name() << endl; + cout << "CK Frame: " << cam->InstrumentRotation()->Frame() << endl; + cout.setf(std::ios::fixed); + cout << setprecision(4); + + // Test all four corners to make sure the conversions are right + cout << "\nFor upper left corner ..." << endl; + TestLineSamp(cam, 0.5, 0.5); + + cout << "\nFor upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples()+0.5, 0.5); + + cout << "\nFor lower left corner ..." << endl; + TestLineSamp(cam, 0.5, cam->Lines()+0.5); + + cout << "\nFor lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples()+0.5, cam->Lines()+0.5); + + double samp = cam->Samples() / 2.0 + 0.5; + double line = cam->Lines() / 2.0 + 0.5; + cout << "\nFor center pixel position ..." << endl; + TestLineSamp(cam, samp, line); + + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + cout << "Line, Sample: " << line << ", " << samp << endl; + bool success = cam->SetImage(samp,line); + + if(success) { + cout << "Lat, Long: " << cam->UniversalLatitude() << ", " + << cam->UniversalLongitude() << endl; + double westlon = -cam->UniversalLongitude(); + while(westlon < 0.0) westlon += 360.0; + cout << "WestLon: " << westlon << endl; + } + else { + cout << "Point not on planet!\n"; + } + +} diff --git a/isis/src/cassini/objs/Makefile b/isis/src/cassini/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/cassini/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/cassini/objs/VimsCamera/Camera.plugin b/isis/src/cassini/objs/VimsCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..93e8e0e53a4f551fb27333fb202300790cb5185a --- /dev/null +++ b/isis/src/cassini/objs/VimsCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = CASSINI-HUYGENS/VIMS + Version = 1 + Library = VimsCamera + Routine = VimsCameraPlugin +EndGroup + diff --git a/isis/src/cassini/objs/VimsCamera/Makefile b/isis/src/cassini/objs/VimsCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fd50864a3794d65851909a0578ad0d52ee64dca8 --- /dev/null +++ b/isis/src/cassini/objs/VimsCamera/Makefile @@ -0,0 +1,5 @@ +INCS = VimsCamera.h VimsGroundMap.h VimsSkyMap.h +SRCS = VimsCamera.cpp VimsGroundMap.cpp VimsSkyMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/cassini/objs/VimsCamera/VimsCamera.cpp b/isis/src/cassini/objs/VimsCamera/VimsCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d87a59423b92cd332f94004f90b02eec737505f --- /dev/null +++ b/isis/src/cassini/objs/VimsCamera/VimsCamera.cpp @@ -0,0 +1,121 @@ +#include "VimsCamera.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraDistortionMap.h" +#include "VimsGroundMap.h" +#include "VimsSkyMap.h" +#include "iString.h" +#include "iException.h" +#include "Filename.h" +#include "SpecialPixel.h" +#include "Constants.h" + +#include +#include +#include + +using namespace std; + +namespace Isis { + namespace Cassini { + + /** + * Constructor for the Cassini Vims Camera Model + * + * @param [in] lab (Pvl &) Label used to create camera model + * + * @history 2007-12-12 Tracie Sucharski, After creating spice cache with + * padding, reset et by calling SetImage(1,1) so that + * et is initialized properly at beginning of image + * without padding. + * + */ + VimsCamera::VimsCamera (Pvl &lab) : Camera(lab) { + + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + string channel = (string) inst ["Channel"]; + + // Set Frame mounting + + if (channel == "VIS") { + //LoadFrameMounting ("CASSINI_SC_COORD","CASSINI_VIMS_V"); + + SetFocalLength(143.0); + if (iString((string)inst["SamplingMode"]).UpCase() == "NORMAL") { + SetPixelPitch(3*.024); + } + else { + SetPixelPitch(.024); + } + } + else if (channel == "IR") { + //LoadFrameMounting ("CASSINI_SC_COORD","CASSINI_VIMS_IR"); + + SetFocalLength(426.0); + SetPixelPitch(.2); + } + + // Get the start time in et + iString stime = (string) inst ["NativeStartTime"]; + string intTime = stime.Token("."); + + double etStart; + scs2e_c(NaifSpkCode(),intTime.c_str(),&etStart); + // Add 2 seconds to either side of time range because the time are for IR + // channel, the VIS may actually start integrating before NATIVE_START_TIME. + // This insures the cache is large enough. + etStart += stime.ToDouble() / 15959.0 - 2.; + + // Get the end time in et + iString etime = (string) inst ["NativeStopTime"]; + intTime = etime.Token("."); + + double etStop; + scs2e_c(NaifSpkCode(),intTime.c_str(),&etStop); + // Add 2 seconds to either side of time range because the time are for IR + // channel, the VIS may actually start integrating before NATIVE_START_TIME. + // This insures the cache is large enough. + etStop += stime.ToDouble() / 15959.0 + 2.; + + // Setup detector map + new CameraDetectorMap(this); + + // Setup focal plane map + new CameraFocalPlaneMap(this,NaifIkCode()); + + // Setup distortion map + new CameraDistortionMap(this); + + // Setup the ground and sky map + new VimsGroundMap(this,lab); + new VimsSkyMap(this,lab); + + ((VimsGroundMap*)GroundMap())->Init(lab); + ((VimsSkyMap*)SkyMap())->Init(lab); + + double tol = PixelResolution(); + + if (tol < 0.) { + // Alternative calculation of .01*ground resolution of a pixel + tol = PixelPitch()*SpacecraftAltitude()/FocalLength()/1000./100.; + } + + if (channel == "VIS") CreateCache(etStart,etStop,64*64, tol); + if (channel == "IR") CreateCache(etStart,etStop,64*64, tol); + + // Call SetImage so that the et is reset to beginning of image w/o + // padding. + IgnoreProjection(true); + SetImage(1,1); + IgnoreProjection(false); + } + + + } +} + +// Plugin +extern "C" Isis::Camera *VimsCameraPlugin (Isis::Pvl &lab) { + return new Isis::Cassini::VimsCamera(lab); +} + diff --git a/isis/src/cassini/objs/VimsCamera/VimsCamera.h b/isis/src/cassini/objs/VimsCamera/VimsCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..b39b98a08f4375e79445eb12d0cde3dd72cbb809 --- /dev/null +++ b/isis/src/cassini/objs/VimsCamera/VimsCamera.h @@ -0,0 +1,53 @@ +#ifndef VimsCamera_h +#define VimsCamera_h + +#include "Camera.h" + +namespace Isis{ + namespace Cassini { + /** Cassini Vims camera model + * + * This is the camera model for the Cassini Vims instrument + * + * @ingroup SpiceInstrumentsAndCameras + * @ingroup Cassini-Huygens + * + * @see Camera + * + * @internal + * + * @history 2006-03-16 Tracie Sucharski Original version + * @history 2009-04-06 Steven Lambright Fixed problem that caused double + * deletion of sky map / ground map. + * @history 2009-08-03 Debbie A. Cook - Added new tolerance + * argument to CreateCache call to be compatible with + * update to Spice class + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + * + */ + class VimsCamera : public Camera { + public: + // constructors + VimsCamera (Pvl &lab); + + // destructor + ~VimsCamera () {}; + + /** + * The vims camera is the only point camera we have. + * + * + * @return CameraType Camera::Point + */ + virtual CameraType GetCameraType() const { + return Point; + } + +// void SetBand (const int physicalBand); +// bool IsBandIndependent () { return false; }; + + }; + }; +}; +#endif diff --git a/isis/src/cassini/objs/VimsCamera/VimsCamera.truth b/isis/src/cassini/objs/VimsCamera/VimsCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..ee11165d1eed4ae2f48d53428d5777e20faf9955 --- /dev/null +++ b/isis/src/cassini/objs/VimsCamera/VimsCamera.truth @@ -0,0 +1,106 @@ +Unit Test for VimsCamera... +Testing image $cassini/testData/CM_1515951157_1.ir.cub ... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK + +Testing image $cassini/testData/CM_1514390782_1.ir.cub ... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK + +Testing image $cassini/testData/CM_1514390782_1.vis.cub ... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK + +Testing image $cassini/testData/CM_1515945709_1.ir.cub ... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK + +Testing image $cassini/testData/CM_1515945709_1.vis.cub ... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK + diff --git a/isis/src/cassini/objs/VimsCamera/VimsGroundMap.cpp b/isis/src/cassini/objs/VimsCamera/VimsGroundMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd50ada1c8ffa5613464e6138b8bd92667ff16f1 --- /dev/null +++ b/isis/src/cassini/objs/VimsCamera/VimsGroundMap.cpp @@ -0,0 +1,463 @@ +/** + * @file + * $Revision: 1.13 $ + * $Date: 2009/08/07 22:08:29 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "Constants.h" +#include "Camera.h" +#include "VimsGroundMap.h" +#include "Filename.h" +#include "iString.h" +#include "SpecialPixel.h" +#include "LeastSquares.h" +#include "PolynomialBivariate.h" +#include "iException.h" +#include "Preference.h" + +#include +#include + +using namespace std; + +namespace Isis { + namespace Cassini { + VimsGroundMap::VimsGroundMap(Camera *parent, Pvl &lab) : + CameraGroundMap (parent) { + // Init(lab); + } + + /** + * Initialize vims camera model + * + * @param [in] lab (Pvl &) Cube Pvl label + * + * @history 2007-04-16 Tracie Sucharski - Look for unit vectors in + * the proper directory. + * @history 2007-04-18 Tracie Sucharski, The inaccuracy of the 15 Mhz clock + * (exposure , interline_delay) is already taken care of + * in the labels values, so remove the adjustment from the + * code (exp * 1.01725). + * *Reference: email from John Ivens 11/27/2006. + * @history 2007-04-19 Tracie Sucharski, Swap bytes on unit vectors. They + * are currently LSB binary files. + * ???Todo:??? Convert unit vectors to text files. + * @history 2008-02-05 Tracie Sucharski, Replaced unitVector files with + * Rick McCloskey's code to calculate look + * direction. + * @history 2009-08-06 Tracie Sucharski, Bug in unit vector change made + * on 2008-02-05, had the incorrect boresight for + * VIS Hires. + */ + void VimsGroundMap::Init(Pvl &lab) { + + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + + // Vis or IR + p_channel = (string) inst ["Channel"]; + // Get the start time in et + iString stime = (string) inst ["NativeStartTime"]; + string intTime = stime.Token("."); + + scs2e_c(-82,intTime.c_str(),&p_etStart); + p_etStart += stime.ToDouble() / 15959.0; + //---------------------------------------------------------------------- + // Because of inaccuracy with the 15 Mhz clock, the IR exposure and + // interline delay need to be adjusted. + //---------------------------------------------------------------------- + p_irExp = (double) inst ["ExposureDuration"] / 1000.; + p_visExp = (double) inst ["ExposureDuration"][1] / 1000.; + p_interlineDelay = + (double) inst ["InterlineDelayDuration"] / 1000.; + + // Get summation mode + string sampMode = iString((string)inst ["SamplingMode"]).UpCase(); + + // Get sample/line offsets + int sampOffset = inst ["XOffset"]; + int lineOffset = inst ["ZOffset"]; + + // Get swath width/length which will be image size unless occultation image + p_swathWidth = inst ["SwathWidth"]; + p_swathLength = inst ["SwathLength"]; + + if (p_channel == "VIS") { + if (sampMode == "NORMAL") { + p_xPixSize = p_yPixSize = 0.00051; + p_xBore = p_yBore = 31; + p_camSampOffset = sampOffset - 1; + p_camLineOffset = lineOffset - 1; + + } + else { + p_xPixSize = p_yPixSize = 0.00051/3.0; + p_xBore = p_yBore = 94; + //New as of 2009-08-04 per Dyer Lytle's email + // Old Values:p_camSampOffset = 3 * (sampOffset - 1) + p_swathWidth; + // p_camLineOffset = 3 * (lineOffset - 1) + p_swathLength; + p_camSampOffset = (3 * (sampOffset + p_swathWidth/2)) - p_swathWidth/2; + p_camLineOffset = (3 * (lineOffset + p_swathLength/2)) - p_swathLength/2; + } + } + else if (p_channel == "IR") { + if (sampMode == "NORMAL") { + p_xPixSize = p_yPixSize = 0.000495; + p_xBore = p_yBore = 31; + p_camSampOffset = sampOffset - 1; + p_camLineOffset = lineOffset - 1; + } + if (sampMode == "HI-RES") { + p_xPixSize = 0.000495 / 2.0; + p_yPixSize = 0.000495; + p_xBore = 62.5; + p_yBore = 31; + p_camSampOffset = 2* ((sampOffset-1) + ((p_swathWidth - 1)/4)); + p_camLineOffset = lineOffset - 1; + } + if (sampMode == "NYQUIST") { + string msg = "Cannot process NYQUIST(undersampled) mode "; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + + + // Calculate lat/lon maps + for (int line=0; lineParentLines(); line++) { + for (int samp=0; sampParentSamples(); samp++) { + p_latMap[line][samp] = Isis::NULL8; + p_lonMap[line][samp] = Isis::NULL8; + } + } + + //--------------------------------------------------------------------- + // Loop for each pixel in cube, get pointing information and calculate + // control point (line,sample,lat,lon) for later use in latlon_to_linesamp. + //--------------------------------------------------------------------- + p_minLat = 99999.; + p_minLon = 99999.; + p_maxLat = -99999.; + p_maxLon = -99999.; + + + p_camera->IgnoreProjection(true); + for (int line=0; lineParentLines(); line++) { + + // VIS exposure is for a single line. According to SIS, + // NATIVE_START_TIME is for the first pixel of the IR exposure. + // "The offset from IR start to VIS start is calculated by + // IrExposMsec - VisExposMsec)/2". + // This needs to be moved to forward routine + + if (p_channel == "VIS") { + double et = ((double)p_etStart + (((p_irExp * p_swathWidth) - p_visExp)/2.)) + + ((line + 0.5) * p_visExp); + p_camera->SetEphemerisTime(et); + } + + for (int samp=0; sampParentSamples(); samp++) { + if (p_channel == "IR") { + double et = (double)p_etStart + + (line * p_camera->ParentSamples() * p_irExp) + + (line * p_interlineDelay) + ((samp + 0.5) * p_irExp); + p_camera->SetEphemerisTime(et); + } + + if (p_camera->SetImage ((double) samp+1, (double)line+1)) { + double latitude = p_camera->UniversalLatitude(); + double longitude = p_camera->UniversalLongitude(); + // could do + // double lat = this->UniversalLatitude () + if (latitude < p_minLat) p_minLat = latitude; + if (latitude > p_maxLat) p_maxLat = latitude; + if (longitude < p_minLon) p_minLon = longitude; + if (longitude > p_maxLon) p_maxLon = longitude; + p_latMap[line][samp] = latitude; + p_lonMap[line][samp] = longitude; + } + else { + p_latMap[line][samp] = Isis::NULL8; + p_lonMap[line][samp] = Isis::NULL8; + } + } + } + p_camera->IgnoreProjection(false); + + } + + + /** Compute ground position from focal plane coordinate + * + * This method will compute the ground position given an + * undistorted focal plane coordinate. Note that the latitude/longitude + * value can be obtained from the camera class passed into the constructor. + * + * @param ux distorted focal plane x in millimeters + * @param uy distorted focal plane y in millimeters + * @param uz distorted focal plane z in millimeters + * + * @return conversion was successful + * + * @history 2008-01-02 Tracie Sucharski - Check incoming pixel for validity + * against edge of pixel not center. + * @history 2008-02-05 Tracie Sucharski, Replaced unitVector files with + * Rick McCloskey's code to calculate look + * direction + * @history 2008-02-14 Tracie Sucharski, Change imgSamp/imgLine to double + * so that fractional pixels are used in calculations. + */ + bool VimsGroundMap::SetFocalPlane(const double ux, const double uy, + const double uz) { + + p_ux = ux; + p_uy = uy; + p_uz = uz; + + double imgSamp = ux; + double imgLine = uy; + + if ((imgLine < 0.5) || (imgLine > p_camera->ParentLines() + 0.5) || + (imgSamp < 0.5) || (imgSamp > p_camera->ParentSamples() + 0.5)) { + return false; + } + imgLine--; + imgSamp--; + + // does interline_delay & exposure-duration account for summing modes? + // if not, won't use p_parentLine/p_parentSample + double et=0.; + if (p_channel == "VIS") { + et = (p_etStart + ((p_irExp * p_swathWidth) - p_visExp)/2.) + + ((imgLine + 0.5) * p_visExp); + } + else if (p_channel == "IR") { + et = (double)p_etStart + + (imgLine * p_camera->ParentSamples() * p_irExp) + + (imgLine * p_interlineDelay) + ((imgSamp + 0.5) * p_irExp); + } + p_camera->SetEphemerisTime(et); + + // get Look Direction + SpiceDouble lookC[3]; + LookDirection(lookC); + + SpiceDouble unitLookC[3]; + vhat_c(lookC,unitLookC); + return p_camera->SetLookDirection(unitLookC); + } + + /** Compute undistorted focal plane coordinate from ground position + * + * @param lat planetocentric latitude in degrees + * @param lon planetocentric longitude in degrees + * + * @return conversion was successful + * + * @history 2007-04-18 Tracie Sucharski - Added check for reasonable + * match when attempting to find closest + * lat/lon in map arrays. + * @history 2007-09-14 Tracie Sucharski - Added check for longitude + * outside min/max bounds. Don't know why + * this wasn't put in before (lat check was + * in), was it oversight, or did I take it out + * for some reason??? + * @history 2007-12-14 Tracie Sucharski - Remove resolution test, too + * image dependent and the resolution for vims is + * incorrect due to the instrument having + * rectangular pixels. + * @history 2008-01-02 Tracie Sucharski - Check validity of resulting + * sample and line against edge of starting + * ending pixels (0.5/Parent+0.5) instead of + * center of pixels. + * + */ + bool VimsGroundMap::SetGround(const double lat, const double lon) { + + if (lat < p_minLat || lat > p_maxLat) return false; + if (lon < p_minLon || lon > p_maxLon) return false; + + // Find closest points ??? what tolerance ??? + double minDist = 9999.; + int minSamp = -1; + int minLine = -1; + + for (int line=0; lineParentLines(); line++) { + + for (int samp=0; sampParentSamples(); samp++) { + double mapLat = p_latMap[line][samp]; + if (mapLat == Isis::NULL8) continue; + double mapLon = p_lonMap[line][samp]; + if (mapLon == Isis::NULL8) continue; + // If on boundary convert lons. If trying to find 360, convert + // lons on other side of meridian to values greater than 360. If + // trying to find 1.0, convert lons on other side to negative numbers. + if (abs(mapLon - lon) > 180) { + if ((lon - mapLon) > 0) { + mapLon = 360. + mapLon; + } + else if ((lon - mapLon) < 0) { + mapLon = mapLon - 360.; + } + } + double dist = ((lat - mapLat) * (lat - mapLat)) + + ((lon - mapLon) * (lon - mapLon)); + if (dist < minDist) { + minDist = dist; + minSamp = samp; + minLine = line; + } + } + } + + //----------------------------------------------------------------- + // If dist is less than some ??? tolerance ??? this is the + // closest point. Use this point and surrounding 8 pts as + // control pts. + //---------------------------------------------------------------- + if (minDist >= 9999.) return false; + + //----------------------------------------------------------------- + // Test for reasonable point using resolution. + //----------------------------------------------------------------- +#if 0 + p_camera->IgnoreProjection(true); + p_camera->SetImage(minSamp+1,minLine+1); + p_camera->IgnoreProjection(false); + + double radii[3]; + p_camera->Radii(radii); + double degPerSamp = + 1.0/((rpd_c() * radii[0]*1000.) / p_camera->SampleResolution()); + double degPerLine = + 1.0/((rpd_c() * radii[0]*1000.) / p_camera->LineResolution()); + + // Convert lon if needed + double mapLon = p_lonMap[minLine][minSamp]; + if (abs(mapLon - lon) > 180) { + if ((lon - mapLon) > 0) { + mapLon = 360. + mapLon; + } + else if ((lon - mapLon) < 0) { + mapLon = mapLon - 360.; + } + } + if (abs(p_latMap[minLine][minSamp] - lat) > (degPerLine * 5.) || + abs(mapLon - lon) > (degPerSamp * 5.) ) + return false; +#endif + //------------------------------------------------------------- + // Set-up for LU decomposition (least2 fit). + // Assume we will have 9 control points, this may not be true + // and will need to be adjusted before the final solution. + //------------------------------------------------------------- + Isis::PolynomialBivariate sampBasis(1); + Isis::PolynomialBivariate lineBasis(1); + Isis::LeastSquares sampLsq(sampBasis); + Isis::LeastSquares lineLsq(lineBasis); + std::vector known(2); + + for (int line=minLine-1; line p_camera->ParentLines()-1) continue; + for (int samp=minSamp-1; samp p_camera->ParentSamples()-1) continue; + + double mapLat = p_latMap[line][samp]; + double mapLon = p_lonMap[line][samp]; + if (( mapLat == Isis::NULL8) || (mapLon == Isis::NULL8) ) continue; + + // If on boundary convert lons. If trying to find 360, convert + // lons on other side of meridian to values greater than 360. If + // trying to find 1.0, convert lons on other side to negative numbers. + if (abs(mapLon - lon) > 180) { + if ((lon - mapLon) > 0) { + mapLon = 360. + mapLon; + } + else if ((lon - mapLon) < 0) { + mapLon = mapLon - 360.; + } + } + + known[0] = mapLat; + known[1] = mapLon; + sampLsq.AddKnown(known,samp+1); + lineLsq.AddKnown(known,line+1); + } + } + if (sampLsq.Knowns() < 3) return false; + + sampLsq.Solve(); + lineLsq.Solve(); + + // Solve for new sample position + known[0] = lat; + known[1] = lon; + double inSamp = sampLsq.Evaluate(known); + double inLine = lineLsq.Evaluate(known); + +// OLD CODE: Why < 0 and not < 1??? +// if (inSamp < 0 || inSamp > p_camera->ParentSamples() + 0.5 || +// inLine < 0 || inLine > p_camera->ParentLines() + 0.5) { + if (inSamp < 0.5 || inSamp > p_camera->ParentSamples() + 0.5 || + inLine < 0.5 || inLine > p_camera->ParentLines() + 0.5) { + return false; + } + + p_camera->IgnoreProjection(true); + p_camera->SetImage(inSamp,inLine); + p_camera->IgnoreProjection(false); + if (!p_camera->HasSurfaceIntersection()) return false; + + p_focalPlaneX = inSamp; + p_focalPlaneY = inLine; + + return true; + } + + + /** + * Returns the look direction in the camera coordinate system + * + * @param [out] v Look direction vector in camera coordinates + * + * This method will compute the look direction vector in the camera coordinate + * system. This code was converted from Rick McCloskey's point_tbl c + * code. + * + * @history 2008-01-031 Tracie Sucharski - Converted Rick's code rather than + * using the unitVector files from Rick. + */ + void VimsGroundMap::LookDirection(double v[3]) { + + double x = p_ux - 1. + p_camSampOffset; + double y = p_uy - 1. + p_camLineOffset; + + // Compute pointing angles based on pixel size separation + double theta = Isis::HALFPI - (y - p_yBore) * p_yPixSize; + double phi = (-1. * Isis::HALFPI) + (x - p_xBore) * p_xPixSize; + + v[0] = sin(theta) * cos(phi); + v[1] = cos(theta); + v[2] = sin(theta) * sin(phi) / -1.; + + + + } + + } +} diff --git a/isis/src/cassini/objs/VimsCamera/VimsGroundMap.h b/isis/src/cassini/objs/VimsCamera/VimsGroundMap.h new file mode 100644 index 0000000000000000000000000000000000000000..1ef33e0df4a63984f8ba1f9fddfa7fb94bee85be --- /dev/null +++ b/isis/src/cassini/objs/VimsCamera/VimsGroundMap.h @@ -0,0 +1,108 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2009/08/07 22:08:33 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef VimsGroundMap_h +#define VimsGroundMap_h + +#include "CameraGroundMap.h" + + +namespace Isis { + namespace Cassini { + /** Convert between undistorted focal plane and ground coordinates + * + * This base class is used to convert between undistorted focal plane + * coordinates (x/y) in millimeters and ground coordinates lat/lon. + * This class handles the case of framing cameras. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2006-03-16 Tracie Sucharski Original version + * @history 2008-02-05 Tracie Sucharski, Replaced unitVector files with + * Rick McCloskey's code to calculate look direction. + * @history 2008-06-18 Steven Lambright Fixed documentation + * @history 2009-04-06 Steven Lambright Fixed problem that caused double + * deletion of sky map / ground map. + * @history 2009-08-06 Tracie Sucharski, Bug in unit vector change made + * on 2008-02-05, had the incorrect boresight for + * VIS Hires. + * + */ + class VimsGroundMap : public CameraGroundMap { + public: + VimsGroundMap(Camera *parent, Pvl &lab); + + //! Destructor + virtual ~VimsGroundMap() { }; + + virtual bool SetFocalPlane(const double ux, const double uy, + const double uz); + + virtual bool SetGround(const double lat, const double lon); + + void Init(Pvl &lab); + + protected: + + private: + void LookDirection (double v[3]); + + SpiceDouble p_etStart; + + double p_exposureDuration; + double p_interlineDelay; + + double p_ux; + double p_uy; + double p_uz; + + double p_xPixSize; + double p_yPixSize; + double p_xBore; + double p_yBore; + + std::string p_channel; + double p_visExp; + double p_irExp; + int p_nsUv; + int p_nlUv; + int p_swathWidth; + int p_swathLength; + int p_camSampOffset; + int p_camLineOffset; + + double p_minLat; + double p_maxLat; + double p_minLon; + double p_maxLon; + double p_latMap[64][64]; + double p_lonMap[64][64]; + + }; + }; +}; +#endif diff --git a/isis/src/cassini/objs/VimsCamera/VimsSkyMap.cpp b/isis/src/cassini/objs/VimsCamera/VimsSkyMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f21315ce199065235dae5c5db6e28069e6eff398 --- /dev/null +++ b/isis/src/cassini/objs/VimsCamera/VimsSkyMap.cpp @@ -0,0 +1,420 @@ +/** + * @file + * $Revision: 1.7 $ + * $Date: 2009/04/06 15:23:27 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "Camera.h" +#include "VimsSkyMap.h" +#include "Filename.h" +#include "iString.h" +#include "SpecialPixel.h" +#include "LeastSquares.h" +#include "PolynomialBivariate.h" +#include "iException.h" +#include "Preference.h" + +#include +#include + +using namespace std; + +namespace Isis { + namespace Cassini { + VimsSkyMap::VimsSkyMap(Camera *parent, Pvl &lab) : + CameraSkyMap (parent) { + } + + + /** + * Initialize vims sky model + * + * @param [in] lab (Pvl &) Cube Pvl label + * + * @history 2007-04-16 Tracie Sucharski - Look for unit vectors in + * the proper directory. + * @history 2007-04-18 Tracie Sucharski, The inaccuracy of the 15 Mhz clock + * (exposure , interline_delay) is already taken care of + * in the labels values, so remove the adjustment from the + * code (exp * 1.01725). + * *Reference: email from John Ivens 11/27/2006. + */ + void VimsSkyMap::Init(Pvl &lab) { + + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + + // Vis or IR + p_channel = (string) inst ["Channel"]; + // Get the start time in et + iString stime = (string) inst ["NativeStartTime"]; + string intTime = stime.Token("."); + + // ??? How do I get to Naif code ??? + //scs2e_c(NaifSpkCode(),intTime.c_str(),&p_etStart); + scs2e_c(-82,intTime.c_str(),&p_etStart); + p_etStart += stime.ToDouble() / 15959.0; + + //---------------------------------------------------------------------- + // Because of inaccuracy with the 15 Mhz clock, the IR exposure and + // interline delay need to be adjusted. + //---------------------------------------------------------------------- + p_irExp = (double) inst ["ExposureDuration"] / 1000.; + p_visExp = (double) inst ["ExposureDuration"][1] / 1000.; + p_interlineDelay = + (double) inst ["InterlineDelayDuration"] / 1000.; + + // Get summation mode + string sampMode = iString((string)inst ["SamplingMode"]).UpCase(); + + // Get sample/line offsets + int sampOffset = inst ["XOffset"]; + int lineOffset = inst ["ZOffset"]; + + // Get swath width/length which will be image size unless occultation image + p_swathWidth = inst ["SwathWidth"]; + p_swathLength = inst ["SwathLength"]; + + //----------------------------------------------------------------------- + // Set up correct limits for unit vector file, calculate offsets and + // Read unit vectors. + //----------------------------------------------------------------------- + //int code = NaifIkCode(); + //string key = "INS" + iString(code) + "_UNIT_VECTORS"; + //Filename vectorFile(Spice::GetString(key,0)); + //tack on _HR or _NY for other summing modes. + // Get the directory for the unit vector files. + PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory"); + iString vecDir = (string) dataDir["Cassini"] + "/unitVectors/"; + + Filename vectorFile; + if (p_channel == "VIS") { + if (sampMode == "NORMAL") { + vectorFile = vecDir + "VIS_NORMAL_uv.bin"; + p_nsUv = 64; + p_nlUv = 64; + p_camSampOffset = sampOffset - 1; + p_camLineOffset = lineOffset - 1; + } + else { + vectorFile = vecDir + "VIS_HI-RES_uv.bin"; + p_nsUv = 192; + p_nlUv = 192; + + p_camSampOffset = 3 * (sampOffset - 1) + p_swathWidth; + p_camLineOffset = 3 * (lineOffset - 1) + p_swathLength; + /*p_camLineOffset = 3 * (lineOffset - 1) + swathLength - 6;*/ + /*p_camLineOffset = 93 - (3 * (lineOffset - 1)) - swathLength;*/ + /* This is in range of 450 (top) to -537 (boresight at 0). */ + /* The unit Vector file is in the range 94 to -98 (boresight at 0). */ + /* Change to 0 to 191 range for indexing into uv file. */ + /*p_camLineOffset = p_camLineOffset + 94;*/ + } + } + else if (p_channel == "IR") { + if (sampMode == "NORMAL") { + vectorFile = vecDir + "IR_NORMAL_uv.bin"; + p_nsUv = 64; + p_nlUv = 64; + p_camSampOffset = sampOffset - 1; + p_camLineOffset = lineOffset - 1; + } + if (sampMode == "HI-RES") { + vectorFile = vecDir + "IR_HI-RES_uv.bin"; + p_nsUv = 128; + p_nlUv = 64; + p_camSampOffset = 2* ((sampOffset-1) + ((p_swathWidth - 1)/4)); + p_camLineOffset = lineOffset - 1; + /* camSampOffset = 2 * (sampOffset - 1); SHIFT TOO FAR TO RIGHT */ + /*sampOffset = sampOffset * 2;*/ + } + if (sampMode == "NYQUIST") { + string msg = "Cannot process NYQUIST(undersampled) mode "; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + + ifstream fin; + string vectorFilename(vectorFile.Expanded()); + fin.open (vectorFilename.c_str(),ios::in|ios::binary); + if (!fin.is_open()){ + string msg = "Can't open unit vector file"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + // Read correct band + /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + / DONT FORGET TO TAKE THIS OUT WHEN WE HAVE UNIT VECTORS FOR ALL BANDS. + / This needs to be smartened up for different summing modes. */ + + int band = 0; + int startByte = (band * (p_nsUv*p_nlUv*3)) * 8; + fin.seekg (startByte, ios_base::beg); + + for (int line=0; lineParentLines(); line++) { + for (int samp=0; sampParentSamples(); samp++) { + p_raMap[line][samp] = Isis::NULL8; + p_decMap[line][samp] = Isis::NULL8; + } + } + + //--------------------------------------------------------------------- + // Loop for each pixel in cube, get pointing information and calculate + // control point (line,sample,lat,lon) for later use in latlon_to_linesamp. + //--------------------------------------------------------------------- + p_minRa = 99999.; + p_minDec = 99999.; + p_maxRa = -99999.; + p_maxDec = -99999.; + + p_camera->IgnoreProjection(true); + for (int line=0; lineParentLines(); line++){ + + // VIS exposure is for a single line. According to SIS, + // NATIVE_START_TIME is for the first pixel of the IR exposure. + // "The offset from IR start to VIS start is calculated by + // IrExposMsec - VisExposMsec)/2". + // This needs to be moved to forward routine + + if (p_channel == "VIS") { + double et = ((double)p_etStart + (((p_irExp * p_swathWidth) - p_visExp)/2.)) + + ((line + 0.5) * p_visExp); + p_camera->SetEphemerisTime(et); + } + + for (int samp=0; sampParentSamples(); samp++){ + if (p_channel == "IR") { + double et = (double)p_etStart + + (line * p_camera->ParentSamples() * p_irExp) + + (line * p_interlineDelay) + ((samp + 0.5) * p_irExp); + p_camera->SetEphemerisTime(et); + } + + p_camera->SetImage ((double) samp+1, (double)line+1); + double ra = p_camera->RightAscension(); + double dec = p_camera->Declination(); + if (ra < p_minRa) p_minRa = ra; + if (ra > p_maxRa) p_maxRa = ra; + if (dec < p_minDec) p_minDec = dec; + if (dec > p_maxDec) p_maxDec = dec; + p_raMap[line][samp] = ra; + p_decMap[line][samp] = dec; + } + } + p_camera->IgnoreProjection(false); + + } + + + /** Compute ground position from focal plane coordinate + * + * This method will compute the ground position given an + * undistorted focal plane coordinate. Note that the latitude/longitude + * value can be obtained from the camera class passed into the constructor. + * + * @param ux distorted focal plane x in millimeters + * @param uy distorted focal plane y in millimeters + * @param uz distorted focal plane z in millimeters + * + * @return conversion was successful + */ + bool VimsSkyMap::SetFocalPlane(const double ux, const double uy, + const double uz) { + + int imgSamp = (int) (ux + .5); + int imgLine = (int) (uy + .5); + + if ((imgLine < 1) || (imgLine > p_camera->ParentLines()) || + (imgSamp < 1) || (imgSamp > p_camera->ParentSamples())) { + return false; + } + imgLine--; + imgSamp--; + + // does interline_delay & exposure-duration account for summing modes? + // if not, won't use p_parentLine/p_parentSample + double et=0.; + if (p_channel == "VIS") { + et = (p_etStart + ((p_irExp * p_swathWidth) - p_visExp)/2.) + + ((imgLine + 0.5) * p_visExp); + } + else if (p_channel == "IR") { + et = (double)p_etStart + + (imgLine * p_camera->ParentSamples() * p_irExp) + + (imgLine * p_interlineDelay) + ((imgSamp + 0.5) * p_irExp); + } + p_camera->SetEphemerisTime(et); + + // Make sure line/samp fall within unitVector ,if not return false??? + int uvLine = imgLine + p_camLineOffset; + int uvSamp = imgSamp + p_camSampOffset; + if (uvSamp < 0 || uvSamp > p_nsUv || + uvLine < 0 || uvLine > p_nlUv) { + return false; + } + + SpiceDouble lookC[3]; + lookC[0] = p_unitVector[uvLine][uvSamp][0]; + lookC[1] = p_unitVector[uvLine][uvSamp][1]; + lookC[2] = p_unitVector[uvLine][uvSamp][2]; + + SpiceDouble unitLookC[3]; + vhat_c(lookC,unitLookC); + return p_camera->SetLookDirection(unitLookC); + } + + /** + * Sets the sky position to the given ra and dec + * + * @param ra the right ascension + * @param dec the declination + * + * @return set sky was successful + */ + bool VimsSkyMap::SetSky(const double ra, const double dec) { + if (ra < p_minRa || ra > p_maxRa || + dec < p_minDec || dec > p_maxDec) { + return false; + } + // Find closest points ??? what tolerance ??? + double minDist = 9999.; + int minSamp = -1; + int minLine = -1; + + for (int line=0; lineParentLines(); line++) { + + for (int samp=0; sampParentSamples(); samp++) { + double mapRa = p_raMap[line][samp]; + if (mapRa == Isis::NULL8) continue; + double mapDec = p_decMap[line][samp]; + if (mapDec == Isis::NULL8) continue; + // If on boundary convert lons. If trying to find 360, convert + // lons on other side of meridian to values greater than 360. If + // trying to find 1.0, convert lons on other side to negative numbers. + if (abs(mapRa - ra) > 180) { + if ((ra - mapRa) > 0) { + mapRa = 360. + mapRa; + } + else if ((ra - mapRa) < 0) { + mapRa = mapRa - 360.; + } + } + double dist = ((ra - mapRa) * (ra - mapRa)) + + ((dec - mapDec) * (dec - mapDec)); + if (dist < minDist) { + minDist = dist; + minSamp = samp; + minLine = line; + } + } + } + + //----------------------------------------------------------------- + // If dist is less than some ??? tolerance ??? this is the + // closest point. Use this point and surrounding 8 pts as + // control pts. + //---------------------------------------------------------------- + if (minDist >= 9999.) return false; + + //------------------------------------------------------------- + // Set-up for LU decomposition (least2 fit). + // Assume we will have 9 control points, this may not be true + // and will need to be adjusted before the final solution. + //------------------------------------------------------------- + Isis::PolynomialBivariate sampBasis(1); + Isis::PolynomialBivariate lineBasis(1); + Isis::LeastSquares sampLsq(sampBasis); + Isis::LeastSquares lineLsq(lineBasis); + std::vector known(2); + + for (int line=minLine-1; line p_camera->ParentLines()-1) continue; + for (int samp=minSamp-1; samp p_camera->ParentSamples()-1) continue; + + double mapRa = p_raMap[line][samp]; + double mapDec = p_decMap[line][samp]; + if (( mapRa == Isis::NULL8) || (mapDec == Isis::NULL8) ) continue; + + // If on boundary convert lons. If trying to find 360, convert + // lons on other side of meridian to values greater than 360. If + // trying to find 1.0, convert lons on other side to negative numbers. + if (abs(mapRa - ra) > 180) { + if ((ra - mapRa) > 0) { + mapRa = 360. + mapRa; + } + else if ((ra - mapRa) < 0) { + mapRa = mapRa - 360.; + } + } + + known[0] = mapDec; + known[1] = mapRa; + sampLsq.AddKnown(known,samp+1); + lineLsq.AddKnown(known,line+1); + } + } + if (sampLsq.Knowns() < 3) return false; + + sampLsq.Solve(); + lineLsq.Solve(); + + // Solve for new sample position + known[0] = dec; + known[1] = ra; + double inSamp = sampLsq.Evaluate(known); + double inLine = lineLsq.Evaluate(known); + + if (inSamp < 0 || inSamp > p_camera->ParentSamples() + 0.5 || + inLine < 0 || inLine > p_camera->ParentLines() + 0.5) { + return false; + } + + p_camera->IgnoreProjection(true); + p_camera->SetImage (inSamp,inLine); + p_camera->IgnoreProjection(false); + p_focalPlaneX = inSamp; + p_focalPlaneY = inLine; + + return true; + } + + } +} diff --git a/isis/src/cassini/objs/VimsCamera/VimsSkyMap.h b/isis/src/cassini/objs/VimsCamera/VimsSkyMap.h new file mode 100644 index 0000000000000000000000000000000000000000..56fdfb3d91c6c095084ea5a967ac595ed9b52d95 --- /dev/null +++ b/isis/src/cassini/objs/VimsCamera/VimsSkyMap.h @@ -0,0 +1,94 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2009/04/06 15:23:27 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef VimsSkyMap_h +#define VimsSkyMap_h + +#include "CameraSkyMap.h" + + +namespace Isis { + namespace Cassini { + /** Convert between undistorted focal plane and ground coordinates + * + * This base class is used to convert between undistorted focal plane + * coordinates (x/y) in millimeters and ground coordinates lat/lon. + * This class handles the case of framing cameras. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2006-04-05 Tracie Sucharski + * Original version + * @history 2009-04-06 Steven Lambright Fixed problem that caused double + * deletion of sky map / ground map. + * + */ + class VimsSkyMap : public CameraSkyMap { + public: + VimsSkyMap(Camera *parent, Pvl &lab); + + //! Destructor + virtual ~VimsSkyMap() {}; + + virtual bool SetFocalPlane(const double ux, const double uy, + const double uz); + + virtual bool SetSky(const double ra, const double dec); + + void Init(Pvl &lab); + + protected: + + private: + SpiceDouble p_etStart; + + double p_exposureDuration; + double p_interlineDelay; + + std::string p_channel; + double p_visExp; + double p_irExp; + int p_nsUv; + int p_nlUv; + int p_swathWidth; + int p_swathLength; + int p_camSampOffset; + int p_camLineOffset; + + double p_unitVector[192][192][3]; + + double p_minRa; + double p_maxRa; + double p_minDec; + double p_maxDec; + double p_raMap[64][64]; + double p_decMap[64][64]; + + }; + }; +}; +#endif diff --git a/isis/src/cassini/objs/VimsCamera/unitTest.cpp b/isis/src/cassini/objs/VimsCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a19544a2fc394374fcf7c0f14cabf9361dfeb52 --- /dev/null +++ b/isis/src/cassini/objs/VimsCamera/unitTest.cpp @@ -0,0 +1,157 @@ +using namespace std; + +#include +#include +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +/** + * @internal + * @history 2009-08-19 Tracie Sucharski, Added all new tests, including + * ir and vis, normal and hires modes with offsets. + */ +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for VimsCamera..." << endl; + /* + * Sample/Line TestLineSamp points changed for the VimsCamera, + * tolerance increased + */ + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + + // For vims, testing ir and vis, hires and normal with offsets and swath + // sizes that are not 1,1,64,64 (full field of view) + // Ir Normal full field of view: CM_1515951157_1.ir.cub + // Ir Normal partial field of view (17,17,48,48): CM_1514390782_1.ir.cub + // Vis Normal partial field of view (17,17,48,48): CM_1514390782_1.vis.cub + // Ir Hires partial field of view (17,26,48,36): CM_1515945709_1.ir.cub + // Vis Hires partial field of view (17,26,48,36): CM_1515945709_1.vis.cub + char files[5][1024] = { "$cassini/testData/CM_1515951157_1.ir.cub", + "$cassini/testData/CM_1514390782_1.ir.cub", + "$cassini/testData/CM_1514390782_1.vis.cub", + "$cassini/testData/CM_1515945709_1.ir.cub", + "$cassini/testData/CM_1515945709_1.vis.cub" }; + + double knownLat[5] = { 0.238187729668092, + -34.842880495045549, + -41.440694242217511, + -42.375769525935951, + -37.412633452415633 }; + double knownLon[5] = { 198.059202300647257, + 123.561260864268348, + 131.725836878894256, + 202.623084593112708, + 213.598346090590496 }; + + vector< pair > corners; + // CM_1515951157_1.ir.cub + corners.push_back(std::make_pair(25,30)); + corners.push_back(std::make_pair(40,30)); + corners.push_back(std::make_pair(25,45)); + corners.push_back(std::make_pair(40,45)); + // CM_1514390782_1.ir.cub + corners.push_back(std::make_pair(22,20)); + corners.push_back(std::make_pair(40,20)); + corners.push_back(std::make_pair(22,33)); + corners.push_back(std::make_pair(40,33)); + + // CM_1514390782_1.vis.cub + corners.push_back(std::make_pair(23,20)); + corners.push_back(std::make_pair(40,20)); + corners.push_back(std::make_pair(23,33)); + corners.push_back(std::make_pair(40,33)); + + // CM_1515945709_1.ir.cub + corners.push_back(std::make_pair(21,14)); + corners.push_back(std::make_pair(48,14)); + corners.push_back(std::make_pair(23,24)); + corners.push_back(std::make_pair(48,26)); + + // CM_1515945709_1.vis.cub + corners.push_back(std::make_pair(26,8)); + corners.push_back(std::make_pair(36,8)); + corners.push_back(std::make_pair(26,29)); + corners.push_back(std::make_pair(36,29)); + + for (unsigned int i = 0; i < sizeof(knownLat)/sizeof(double); i++) { + Isis::Pvl p(files[i]); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + cout << "Testing image " << files[i] << " ..." << endl; + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, corners[i*4].first, corners[i*4].second); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, corners[i*4+1].first, corners[i*4+1].second); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, corners[i*4+2].first, corners[i*4+2].second); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, corners[i*4+3].first, corners[i*4+3].second); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if (!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if (abs(cam->UniversalLatitude() - knownLat[i]) < 1E-8) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat[i] << endl; + } + + if (abs(cam->UniversalLongitude() - knownLon[i]) < 1E-8) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon[i] << endl; + } + + cout << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.196) deltaSamp = 0; + if (fabs(deltaLine) < 0.196) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/cassini/tsts/Makefile b/isis/src/cassini/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..016388fc898d8c89f380cae1fd08942c29611582 --- /dev/null +++ b/isis/src/cassini/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-42s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/cassini/tsts/vims/Makefile b/isis/src/cassini/tsts/vims/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..29d88dcc5a32ea5ab62b3d60593b0b1c29fe4a0e --- /dev/null +++ b/isis/src/cassini/tsts/vims/Makefile @@ -0,0 +1,42 @@ +APP1NAME = vims2isis +APP2NAME = spiceinit +APP3NAME = campt +APP4NAME = getsn + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APP1NAME) from= $(INPUT)/CM_1477461989_1.cub \ + VIS= $(OUTPUT)/CM_1477461989_1.cub--vims2isis-spiceinit-vis.cub \ + IR= $(OUTPUT)/CM_1477461989_1.cub--vims2isis-spiceinit-ir.cub > /dev/null + + $(APP2NAME) from= $(OUTPUT)/CM_1477461989_1.cub--vims2isis-spiceinit-vis.cub \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/CM_1477461989_1.cub--vims2isis-spiceinit-vis.cub \ + to= $(OUTPUT)/CM_1477461989_1.cub--finalOutput.pvl SAMPLE=32 LINE=7 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/CM_1477461989_1.cub--vims2isis-spiceinit-vis.cub \ + to= $(OUTPUT)/CM_1477461989_1.cub--finalOutput.pvl SAMPLE=55 LINE=33 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/CM_1477461989_1.cub--vims2isis-spiceinit-vis.cub \ + to= $(OUTPUT)/CM_1477461989_1.cub--finalOutput.pvl SAMPLE=32 LINE=58 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/CM_1477461989_1.cub--vims2isis-spiceinit-vis.cub \ + to= $(OUTPUT)/CM_1477461989_1.cub--finalOutput.pvl SAMPLE=4 LINE=33 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/CM_1477461989_1.cub--vims2isis-spiceinit-vis.cub \ + to= $(OUTPUT)/CM_1477461989_1.cub--finalOutput.pvl SAMPLE=32 LINE=33 ALLOWOUTSIDE=no \ + > /dev/null + + echo -e "\nOutput of getsn..." >> $(OUTPUT)/CM_1477461989_1.cub--getsnOutput.txt && \ + $(APP4NAME) from= $(OUTPUT)/CM_1477461989_1.cub--vims2isis-spiceinit-vis.cub \ + >> $(OUTPUT)/CM_1477461989_1.cub--getsnOutput.txt + + $(RM) $(OUTPUT)/CM_1477461989_1.cub--vims2isis-spiceinit-vis.cub > /dev/null + $(RM) $(OUTPUT)/CM_1477461989_1.cub--vims2isis-spiceinit-ir.cub > /dev/null + $(RM) $(OUTPUT)/../print.prt > /dev/null diff --git a/isis/src/clementine/Makefile b/isis/src/clementine/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/clementine/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/clementine/apps/Makefile b/isis/src/clementine/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/clementine/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/clementine/apps/clem2isis/Makefile b/isis/src/clementine/apps/clem2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/clementine/apps/clem2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/clementine/apps/clem2isis/assets/images/clem2isisGUI.jpg b/isis/src/clementine/apps/clem2isis/assets/images/clem2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5ce9d983c19166a5fdbaf81902bd1badaf9cc2ec Binary files /dev/null and b/isis/src/clementine/apps/clem2isis/assets/images/clem2isisGUI.jpg differ diff --git a/isis/src/clementine/apps/clem2isis/assets/images/lne4885r.jpg b/isis/src/clementine/apps/clem2isis/assets/images/lne4885r.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8ec7b292f1eda43c70bb6df52baddb37fcfbc5b3 Binary files /dev/null and b/isis/src/clementine/apps/clem2isis/assets/images/lne4885r.jpg differ diff --git a/isis/src/clementine/apps/clem2isis/assets/lne4885r.300 b/isis/src/clementine/apps/clem2isis/assets/lne4885r.300 new file mode 100644 index 0000000000000000000000000000000000000000..79375f2084707860ba4bdb5c9aa9cfd2f8b6488e Binary files /dev/null and b/isis/src/clementine/apps/clem2isis/assets/lne4885r.300 differ diff --git a/isis/src/clementine/apps/clem2isis/assets/thumbs/clem2isisGUI.jpg b/isis/src/clementine/apps/clem2isis/assets/thumbs/clem2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0b63704d06886508d4a8ad7b740c197455b1738a Binary files /dev/null and b/isis/src/clementine/apps/clem2isis/assets/thumbs/clem2isisGUI.jpg differ diff --git a/isis/src/clementine/apps/clem2isis/assets/thumbs/lne4885r.jpg b/isis/src/clementine/apps/clem2isis/assets/thumbs/lne4885r.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db62eb60952fcb8c5a94ece695b6aa3056240bba Binary files /dev/null and b/isis/src/clementine/apps/clem2isis/assets/thumbs/lne4885r.jpg differ diff --git a/isis/src/clementine/apps/clem2isis/bitstrm.cpp b/isis/src/clementine/apps/clem2isis/bitstrm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c18f710e4ada09b9c698963e6348d37fa7b6713f --- /dev/null +++ b/isis/src/clementine/apps/clem2isis/bitstrm.cpp @@ -0,0 +1,151 @@ +/* + * THIS ROUTINE IS PART OF THE CLEMENTINE PDS FILE READER PROGRAM. + * IT WAS WRITTEN BY ACT CORP. IN DIRECT SUPPORT TO THE + * CLEMENTINE (DSPSE) PROGRAM. + * + * IF YOU FIND A PROBLEM OR MAKE ANY CHANGES TO THIS CODE PLEASE CONTACT + * Dr. Erick Malaret at ACT Corp. + * tel: (703) 742-0294 + * (703) 683-7431 + * email: nrlvax.nrl.navy.mil + * + * + */ +#include +#include "jpeg_c.h" + +void *cBitStream( BitStream *bs, char *fn, Fmode fm ) +{ + cByteStream( &bs->bytestream, fn, fm ); + bs->BitBuffer = 0; + bs->bytesout = 0; + bs->outstring = NULL; + bs->BitBuffMask = (fm==OUTPUT) ? 0x80:0x00; + bs->bitmask[0] = 0x0000; bs->bitmask[1] = 0x0001; bs->bitmask[2] = 0x0002; + bs->bitmask[3] = 0x0004; bs->bitmask[4] = 0x0008; bs->bitmask[5] = 0x0010; + bs->bitmask[6] = 0x0020; bs->bitmask[7] = 0x0040; bs->bitmask[8] = 0x0080; + bs->bitmask[9] = 0x0100; bs->bitmask[10] = 0x0200; bs->bitmask[11] = 0x0400; + bs->bitmask[12] = 0x0800; bs->bitmask[13] = 0x1000; bs->bitmask[14] = 0x2000; + bs->bitmask[15] = 0x4000; bs->bitmask[16] = 0x8000; + return bs; +} + +void *dBitStream(BitStream *bs) +{ + if ( bs->bytestream.mode == OUTPUT ) { + if ( bs->BitBuffMask != 0x80 ) { + while (bs->BitBuffMask) { + bs->BitBuffer |= bs->BitBuffMask; + bs->BitBuffMask >>= 1; + } + if ( bs->mode ) + bs->outstring[bs->bytesout] = bs->BitBuffer; + else + ByteStream_write( &bs->bytestream, bs->BitBuffer ); + bs->bytesout++; + } + if ( bs->mode ) { + if ( fwrite(bs->outstring,sizeof(char),bs->bytesout,bs->bytestream.file) == 0 ) + printf("Error: writing output bitstream to file.\n"); + } + if ( fseek(bs->bytestream.file,8,0) ) + printf("Error: fseek in subroutine dBitStream().\n"); + else { + if ( fwrite(&(bs->bytesout),sizeof(long),1,bs->bytestream.file) == 0 ) + printf("Error: writing bytesout value to file.\n"); + } + } + dByteStream(&bs->bytestream); + return bs; +} + +short BitStream_write(BitStream *bs, short bits, short width) +{ + unsigned short BitMask = bs->bitmask[width]; + + while ( BitMask ) { + if ( bits & BitMask ) bs->BitBuffer |= (short)bs->BitBuffMask; + BitMask >>= 1; + bs->BitBuffMask >>= 1; + if ( !bs->BitBuffMask ) { + if ( bs->mode ) + bs->outstring[bs->bytesout] = bs->BitBuffer; + else + ByteStream_write( &bs->bytestream, bs->BitBuffer ); + bs->bytesout++; + bs->BitBuffer = 0; + bs->BitBuffMask = 0x80; + } + } + return bs->bytestream.stat; +} + +short BitStream_read( BitStream *bs, short w ) +{ + unsigned short RetVal = 0, BitMask = bs->bitmask[w]; + + while ( BitMask ) { + if ( !bs->BitBuffMask ) { + if ( bs->mode ) { + bs->BitBuffer = ((short)bs->outstring[bs->bytesout]) & 0x00ff; + } else + bs->BitBuffer = ByteStream_read(&bs->bytestream); + + bs->bytesout++; + bs->BitBuffMask = 0x80; + } + if ( bs->BitBuffer & bs->BitBuffMask ) RetVal |= BitMask; + bs->BitBuffMask >>= 1; + BitMask >>= 1; + } + return RetVal; +} + +void *cByteStream(ByteStream *Bs, char *FileName, Fmode FileMode) +{ + Bs->mode = FileMode; + if ( FileName != NULL ) { + Bs->file = fopen(FileName,(Bs->mode==INPUT) ? "rb":"wb"); + if ( Bs->file == NULL ) printf("ByteStream constructor error.\n"); + Bs->stat = 0; + } + return Bs; +} + +void *dByteStream(ByteStream *Bs) +{ + if ( Bs->file ) { + fclose(Bs->file); + Bs->file = NULL; + } + return Bs; +} + +short ByteStream_read(ByteStream *Bs) +{ + short c; + char cval; + int n; + + if ( Bs->mode == INPUT ) { + /* c = fgetc( Bs->file ); */ + n=fread(&cval,sizeof(char),1,Bs->file); + c = cval; + if ( n != 1 ) Bs->stat = EOF; + return c; + } + else + Bs->stat = EOF; + return EOF; +} + +short ByteStream_write(ByteStream *Bs, short c) +{ + if ( (Bs->mode != OUTPUT) || (fputc(c,Bs->file) == EOF) ) Bs->stat = EOF; + return Bs->stat; +} + +short ByteStream_status(ByteStream *Bs) +{ + return Bs->stat; +} diff --git a/isis/src/clementine/apps/clem2isis/clem2isis.cpp b/isis/src/clementine/apps/clem2isis/clem2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf199940d457fdbeec099e8b7c16b746f9f4b160 --- /dev/null +++ b/isis/src/clementine/apps/clem2isis/clem2isis.cpp @@ -0,0 +1,166 @@ +#include "Isis.h" + +#include +#include + +#include "pds.h" +#include "ProcessByLine.h" +#include "PvlTranslationManager.h" +#include "SpecialPixel.h" +#include "UserInterface.h" +#include "Filename.h" +#include "iException.h" +#include "iTime.h" +#include "Preference.h" +#include "iString.h" +#include "OriginalLabel.h" + +using namespace std; +using namespace Isis; + +void WriteLine (Buffer &b); +void TranslateLabels (Filename in, Cube *ocube); +PDSINFO *pdsi; + +void IsisMain () { + // Grab the file to import + UserInterface &ui = Application::GetUserInterface(); + Filename in = ui.GetFilename("FROM"); + Filename out = ui.GetFilename("TO"); + + // Make sure it is a Clementine EDR + bool projected; + try { + Pvl lab(in.Expanded()); + projected = lab.HasObject("IMAGE_MAP_PROJECTION"); + iString id; + id = (string)lab["DATA_SET_ID"]; + id.ConvertWhiteSpace(); + id.Compress(); + id.Trim(" "); + if (id.find("CLEM") == string::npos) { + string msg = "Invalid DATA_SET_ID [" + id + "]"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + } + catch (iException &e) { + string msg = "Input file [" + in.Expanded() + + "] does not appear to be " + + "in Clementine EDR format"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + //Checks if in file is rdr + if( projected ) { + string msg = "[" + in.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + //Decompress the file + long int lines = 0; + long int samps = 0; + iString filename = in.Expanded(); + pdsi = PDSR((char *)filename.c_str(),&lines,&samps); + + ProcessByLine p; + CubeAttributeOutput cubeAtt("+unsignedByte+1.0:254.0"); + Cube *ocube = p.SetOutputCube(ui.GetFilename("TO"), cubeAtt, pdsi->image_ncols, pdsi->image_nrows); + p.StartProcess (WriteLine); + TranslateLabels(in, ocube); + p.EndProcess (); +} + +//Function to move uncompressed data to a cube +void WriteLine (Buffer &b){ + for (int i=0; iimage_ncols; i++) { + double d = pdsi->image[((b.Line()-1)*pdsi->image_ncols) + i]; + if(d<=0.0){ + b[i] = Isis::Lis; + } + else if(d >= 255.0){ + b[i] = Isis::His; + } + else{ + b[i] = d; + } + } +} + +/** + * Function to propagate the labels. + * + * @internal + * @history 2009-02-17 Tracie Sucharski - Added BandBin keywords Center and + * Width to the translation table, Clementine.trn. Do not alter this + * keywords for filter F,simply translate. + * + */ + +void TranslateLabels (Filename in, Cube *ocube) { + // Get the directory where the Clementine translation tables are. + PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory"); + + // Transfer the instrument group to the output cube + iString transDir = (string) dataDir["clementine1"]; + Filename transFile (transDir + "/translations/clementine.trn"); + + Pvl pdsLab(in.Expanded()); + PvlTranslationManager labelXlater (pdsLab, transFile.Expanded()); + + // Pvl outputLabels; + Pvl *outputLabel = ocube->Label(); + labelXlater.Auto(*(outputLabel)); + + //Instrument group + PvlGroup inst = outputLabel->FindGroup ("Instrument",Pvl::Traverse); + + PvlKeyword &startTime = inst.FindKeyword("StartTime"); + startTime.SetValue( startTime[0].substr(0, startTime[0].size()-1)); + + // Old PDS labels used keyword INSTRUMENT_COMPRESSION_TYPE & PDS Labels now use ENCODING_TYPE + if(pdsLab.FindObject("Image").HasKeyword("InstrumentCompressionType")){ + inst += PvlKeyword("EncodingFormat",(string) pdsLab.FindObject("Image")["InstrumentCompressionType"]); + } + else { + inst += PvlKeyword("EncodingFormat",(string) pdsLab.FindObject("Image")["EncodingType"]); + } + + if (((string)inst["InstrumentId"]) == "HIRES") { + inst += PvlKeyword("MCPGainModeID", (string)pdsLab["MCP_Gain_Mode_ID"], ""); + } + + ocube->PutGroup(inst); + + PvlGroup bBin = outputLabel->FindGroup ("BandBin", Pvl::Traverse); + std::string filter = pdsLab["FilterName"]; + if (filter != "F") { + //Band Bin group + double center = pdsLab["CenterFilterWavelength"]; + center /= 1000.0; + bBin.FindKeyword("Center").SetValue(center,"micrometers"); + } + double width = pdsLab["Bandwidth"]; + width /= 1000.0; + bBin.FindKeyword("Width").SetValue(width,"micrometers"); + ocube->PutGroup(bBin); + + //Kernel group + PvlGroup kern("Kernels"); + if (((string)inst["InstrumentId"]) == "HIRES") { + kern += PvlKeyword("NaifFrameCode","-40001"); + } + if (((string)inst["InstrumentId"]) == "UVVIS") { + kern += PvlKeyword("NaifFrameCode","-40002"); + } + if (((string)inst["InstrumentId"]) == "NIR") { + kern += PvlKeyword("NaifFrameCode","-40003"); + } + if (((string)inst["InstrumentId"]) == "LWIR") { + kern += PvlKeyword("NaifFrameCode","-40004"); + } + ocube->PutGroup(kern); + + OriginalLabel org(pdsLab); + ocube->Write(org); +} diff --git a/isis/src/clementine/apps/clem2isis/clem2isis.xml b/isis/src/clementine/apps/clem2isis/clem2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..9568472f8c32c64593e837d7e68fb90c6ee45ee5 --- /dev/null +++ b/isis/src/clementine/apps/clem2isis/clem2isis.xml @@ -0,0 +1,166 @@ + + + + + Convert Clementine data to Isis cube + + + + This program takes a Clementine image and formats it into an Isis cube. The + images are decompressed from Clementine 8-bit into a pixel type selected by + the user. + + + + Clementine + + + + + Converted to Isis 3 + + + Fixed compiletime warnings + + + Made changes to make code more standard (replaced malloc.h with + stdlib.h). Also fixed bug in format for internal read of long formatted + for an int, which differs in size. + + + Fixed bug with non-permanent char* pointer + + + Removed "Z" from end of value for StartTime label. + Propagated Original Labels + Added PvlKeywords: + FocalPlaneTemperature + ExposureDuration + EncodingCompressionRatio + OffsetModeID + GainModeID + ProductID + MissionPhase. + Changed output cube from real to unsignedByte. + Added handeling for LIS and HIS values. + + + Added PvlKeywords and Added NIR Test Data + + + Added Example + + + Changed to translate labels through translation table. + Fixed Name keyword in BandBin group + + + Altered the output cube's BandBin group, changing the Keyword "Name" back + to "FilterName". + + + Checks if input file is rdr. + + + Removed references to CubeInfo + + + Added BandBin keywords Center and Width to clementine.trn and + alter the output values only if the filter is not the F filter. + + + Modified label transfer to include MCP_Gain_Mode_ID when images is from + HIRES camera. + + + + + + + filename + input + + Input file + + + This file is the input Clementine image to be processed into an Isis + cube. + + + + cube + output + + Output cube + + + This is the cube which will be output after the processing is + finished. + + *.cub + unsignedByte + + + + + + + Using clem2isis + + + The use of clem2isis to ingest PDS images and output Isis3 cubes + + + + from= lne4885r.300 + to=lne4885r.cub + + + This example shows the use of clem2isis create an Isis3 cube from a PDS + image. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters + + + + + + + + + + Input PDS image. + + + This is the image from PDS + + FROM + + + + + + + Final output image after the conversion + + + Converts from PDS format to a Isis3 cube. + + + TO + + + + + diff --git a/isis/src/clementine/apps/clem2isis/decomp.cpp b/isis/src/clementine/apps/clem2isis/decomp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bec1fb45a22b7e150ca5bf8249a2f7cdfe97135a --- /dev/null +++ b/isis/src/clementine/apps/clem2isis/decomp.cpp @@ -0,0 +1,804 @@ +/* + * THIS ROUTINE IS PART OF THE CLEMENTINE PDS FILE READER PROGRAM. + * IT WAS WRITTEN BY ACT CORP. IN DIRECT SUPPORT TO THE + * CLEMENTINE (DSPSE) PROGRAM. + * + * IF YOU FIND A PROBLEM OR MAKE ANY CHANGES TO THIS CODE PLEASE CONTACT + * Dr. Erick Malaret at ACT Corp. + * tel: (703) 742-0294 + * (703) 683-7431 + * email: nrlvax.nrl.navy.mil + * + * Dec 11 2006 KJB Changed malloc.h to stdlib.h for the Mac port again. + * malloc.h is deprecated. + * + */ +/* + Program to calculate the Discrete Cosine Transform of a 8x8 block of data +*/ + +#include +#ifdef __TURBOC__ +#include +#else +#include +#endif +#include +#include +#include "jpeg_c.h" + +#define TRUE 1 +#define FALSE 0 + +long *DCTHist[64]; +float *Rn[64]; +float Q[64]; +float q_table[64]; +float U[64]; +short ULS[64]; +int zzseq[] = {0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40, + 48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29, + 22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54, + 47,55,62,63}; + +void core(void); +void getDCTHist(BitStream *bs, long rows, long cols); +void getRn(void); + + +void decomp(BitStream *bs,CHARH *Image,long rows,long cols) +{ + short i,j,k,indexi,indexip8,indexj,indexjp8; + float temp; + long rowsleft, colsleft, icols; + short Done, Diff, Pred; + + /*********************** Image Decompression *********************/ + Done = FALSE; + rowsleft = rows; + colsleft = cols; + indexj = 0; + indexi = 0; + Pred = 0; + + while ( !Done ) { + /* Decode block data */ + decode(ULS,bs); + Diff = ULS[0] + Pred; + Pred = Diff; + ULS[0] = Diff; + + /* Calculate Inverse Discrete Cosine Transform */ + /*dequantize(U,ULS1,pt_q_table); 64 multiplications */ + for (i=0; i<64; i++) { + temp = Rn[i][ULS[i]]; + U[zzseq[i]] = temp * q_table[i]; + } + + core(); + + /*ilevelshift(U);*/ + for (i=0; i<64; i++) { + U[i] += 128.0; + U[i] = floor( U[i] + 0.5 ); + if ( U[i] > 255.0 ) U[i] = 255.0; + else if ( U[i] < 0.0 ) U[i] = 0.0; + else; + } + + indexip8 = indexi + 8; + indexjp8 = indexj + 8; + + if ( (rowsleft > 8) && (colsleft > 8) ) { + + for (i=indexi, k=0; i < indexip8; i++) + for (j=indexj, icols=i*cols; j < indexjp8; j++, k++) + Image[icols+j] = (char)U[k]; + + indexj += 8; + colsleft -= 8; + } + else if ( (rowsleft > 8) && (colsleft <= 8) ) { + + for (i=indexi, k=0; i < indexip8; i++) { + for (j=indexj, icols=i*cols; j < cols; j++, k++) + Image[icols+j] = (char)U[k]; + k += (8 - colsleft); + } + + indexj = 0; + indexi += 8; + rowsleft -= 8; + colsleft = cols; + } + else if ( (rowsleft <= 8) && (colsleft > 8) ) { + + for (i=indexi, k=0; i < rows; i++) + for (j=indexj, icols=i*cols; j < indexjp8; j++, k++) + Image[icols+j] = (char)U[k]; + + indexj += 8; + colsleft -= 8; + } + else { + + for (i=indexi, k=0; i < rows; i++) { + for (j=indexj, icols=i*cols; j < cols; j++, k++) + Image[icols+j] = (char)U[k]; + k += (8 - colsleft); + } + + Done = TRUE; + } + } +} + +void getDCTHist(BitStream *bs, long rows, long cols) +{ + short Pred, i; + long nblocks; + + nblocks = (rows * cols) / 64; + Pred = 0; + + while ( nblocks ) { + /* Decode block data */ + decode(ULS,bs); + ULS[0] += Pred; + Pred = ULS[0]; + + for (i=0; i<64; i++) DCTHist[i][ULS[i]]++; + + nblocks--; + } +} + +void getRn() +{ + short i, j; + float lb, ub, a, b, num, den, phi; + float m, pa, pap, pb, pbp, pm, pmp; + + for (i=0; i<64; i++) { + Rn[i][-256] = (float)-256; + Rn[i][256] = (float)256; + for (j=-255; j<256; j++) { + if ( DCTHist[i][j] > 0 ) { + lb = ((float)j - 0.5)*Q[i]; + ub = ((float)j + 0.5)*Q[i]; + + m = ((float)j)*Q[i]; + pm = DCTHist[i][j]; + pmp = m*pm; + + a = ceil(lb); + phi = a/Q[i] - (float)(j-1); + pa = phi*DCTHist[i][j] + (1.0-phi)*DCTHist[i][j-1]; + pap = ((float)j*pa - (1.0-phi)*DCTHist[i][j-1])*Q[i]; + + b = ceil(ub); + phi = b/Q[i] - (float)j; + pb = phi*DCTHist[i][j+1] + (1.0-phi)*DCTHist[i][j]; + pbp = ((float)j*pb + phi*DCTHist[i][j+1])*Q[i]; + + num = (m-a)*(pap+pmp)+(b-m)*(pbp+pmp); + den = (m-a)*(pa+pm)+(b-m)*(pb+pm); + Rn[i][j] = (num/den)/Q[i]; + } else { + Rn[i][j] = (float)j; + } + } + } +} + + +void core(void) +{ + float out[64], out1[64]; + float temp1,temp2,temp3,temp4,temp5,temp6,temp7,temp8; + float dummy1, dummy2, dummy3; + float buffer11,buffer12,buffer13,buffer14,buffer15,buffer16,buffer17,buffer18; + float buffer21,buffer22,buffer23,buffer24,buffer25,buffer26,buffer27,buffer28; + + /******** Preadditions ********/ + out[0] = U[0]; + out[1] = U[32]; + out[2] = U[16] - U[48]; + out[3] = U[16] + U[48]; + dummy1 = U[8] - U[56]; + dummy2 = U[24] - U[40]; + out[4] = dummy1 - dummy2; + out[5] = dummy1 + dummy2; + out[6] = -U[8] - U[56]; + out[7] = U[24] + U[40]; /* 8 additions */ + + out[8] = U[4]; + out[9] = U[36]; + out[10] = U[20] - U[52]; + out[11] = U[20] + U[52]; + dummy1 = U[12] - U[60]; + dummy2 = U[28] - U[44]; + out[12] = dummy1 - dummy2; + out[13] = dummy1 + dummy2; + out[14] = -U[12] - U[60]; + out[15] = U[28] + U[44]; /* 8 additions */ + + temp1 = U[2] - U[6]; + temp2 = U[34] - U[38]; + temp3 = U[18] - U[22]; + temp4 = U[50] - U[54]; + temp5 = U[10] - U[14]; + temp6 = U[26] - U[30]; + temp7 = U[58] - U[62]; + temp8 = U[42] - U[46]; + out[16] = temp1; + out[17] = temp2; + out[18] = temp3 - temp4; + out[19] = temp3 + temp4; + dummy1 = temp5 - temp7; + dummy2 = temp6 - temp8; + out[20] = dummy1 - dummy2; + out[21] = dummy1 + dummy2; + out[22] = -temp5 - temp7; + out[23] = temp6 + temp8; /* 16 additions */ + + temp1 = U[2] + U[6]; + temp2 = U[34] + U[38]; + temp3 = U[18] + U[22]; + temp4 = U[50] + U[54]; + temp5 = U[10] + U[14]; + temp6 = U[26] + U[30]; + temp7 = U[58] + U[62]; + temp8 = U[42] + U[46]; + out[24] = temp1; + out[25] = temp2; + out[26] = temp3 - temp4; + out[27] = temp3 + temp4; + dummy1 = temp5 - temp7; + dummy2 = temp6 - temp8; + out[28] = dummy1 - dummy2; + out[29] = dummy1 + dummy2; + out[30] = -temp5 - temp7; + out[31] = temp6 + temp8; /* 16 additions */ + + buffer11 = U[1] - U[7]; buffer21 = U[3] - U[5]; + buffer12 = U[33] - U[39]; buffer22 = U[35] - U[37]; + buffer13 = U[17] - U[23]; buffer23 = U[19] - U[21]; + buffer14 = U[49] - U[55]; buffer24 = U[51] - U[53]; + buffer15 = U[9] - U[15]; buffer25 = U[11] - U[13]; + buffer16 = U[25] - U[31]; buffer26 = U[27] - U[29]; + buffer17 = U[57] - U[63]; buffer27 = U[59] - U[61]; + buffer18 = U[41] - U[47]; buffer28 = U[43] - U[45]; + temp1 = buffer11 - buffer21; + temp2 = buffer12 - buffer22; + temp3 = buffer13 - buffer23; + temp4 = buffer14 - buffer24; + temp5 = buffer15 - buffer25; + temp6 = buffer16 - buffer26; + temp7 = buffer17 - buffer27; + temp8 = buffer18 - buffer28; + out[32] = temp1; + out[33] = temp2; + out[34] = temp3 - temp4; + out[35] = temp3 + temp4; + dummy1 = temp5 - temp7; + dummy2 = temp6 - temp8; + out[36] = dummy1 - dummy2; + out[37] = dummy1 + dummy2; + out[38] = -temp5 - temp7; + out[39] = temp6 + temp8; + temp1 = buffer11 + buffer21; + temp2 = buffer12 + buffer22; + temp3 = buffer13 + buffer23; + temp4 = buffer14 + buffer24; + temp5 = buffer15 + buffer25; + temp6 = buffer16 + buffer26; + temp7 = buffer17 + buffer27; + temp8 = buffer18 + buffer28; + out[40] = temp1; + out[41] = temp2; + out[42] = temp3 - temp4; + out[43] = temp3 + temp4; + dummy1 = temp5 - temp7; + dummy2 = temp6 - temp8; + out[44] = dummy1 - dummy2; + out[45] = dummy1 + dummy2; + out[46] = -temp5 - temp7; + out[47] = temp6 + temp8; /* 48 additions */ + + temp1 = -U[1] - U[7]; + temp2 = -U[33] - U[39]; + temp3 = -U[17] - U[23]; + temp4 = -U[49] - U[55]; + temp5 = -U[9] - U[15]; + temp6 = -U[25] - U[31]; + temp7 = -U[57] - U[63]; + temp8 = -U[41] - U[47]; + out[48] = temp1; + out[49] = temp2; + out[50] = temp3 - temp4; + out[51] = temp3 + temp4; + dummy1 = temp5 - temp7; + dummy2 = temp6 - temp8; + out[52] = dummy1 - dummy2; + out[53] = dummy1 + dummy2; + out[54] = -temp5 - temp7; + out[55] = temp6 + temp8; /* 16 additions */ + + temp1 = U[3] + U[5]; + temp2 = U[35] + U[37]; + temp3 = U[19] + U[21]; + temp4 = U[51] + U[53]; + temp5 = U[11] + U[13]; + temp6 = U[27] + U[29]; + temp7 = U[59] + U[61]; + temp8 = U[43] + U[45]; + out[56] = temp1; + out[57] = temp2; + out[58] = temp3 - temp4; + out[59] = temp3 + temp4; + dummy1 = temp5 - temp7; + dummy2 = temp6 - temp8; + out[60] = dummy1 - dummy2; + out[61] = dummy1 + dummy2; + out[62] = -temp5 - temp7; + out[63] = temp6 + temp8; /* 16 additions */ + /*for (i=0; i<64; i++) printf("out[%d] = %f\n",i,out[i]);*/ + + /********* Core Processing *********/ + out1[0] = out[0]; + out1[1] = out[1]; + out1[2] = out[2]; + out1[3] = 0.707106781 * out[3]; + out1[4] = out[4]; + out1[5] = 0.707106781 * out[5]; + dummy1 = 1.306562964 * out[6]; + dummy2 = 0.923879532 * (out[6] + out[7]); + dummy3 = -0.5411961 * out[7]; + out1[6] = dummy1 - dummy2; + out1[7] = dummy2 + dummy3; /* 5 multiplications, 3 additions */ + + out1[8] = out[8]; + out1[9] = out[9]; + out1[10] = out[10]; + out1[11] = 0.707106781 * out[11]; + out1[12] = out[12]; + out1[13] = 0.707106781 * out[13]; + dummy1 = 1.306562964 * out[14]; + dummy2 = 0.923879532 * (out[14] + out[15]); + dummy3 = -0.5411961 * out[15]; + out1[14] = dummy1 - dummy2; + out1[15] = dummy2 + dummy3; /* 5 multiplications, 3 additions */ + + out1[16] = out[16]; + out1[17] = out[17]; + out1[18] = out[18]; + out1[19] = 0.707106781 * out[19]; + out1[20] = out[20]; + out1[21] = 0.707106781 * out[21]; + dummy1 = 1.306562964 * out[22]; + dummy2 = 0.923879532 * (out[22] + out[23]); + dummy3 = -0.5411961 * out[23]; + out1[22] = dummy1 - dummy2; + out1[23] = dummy2 + dummy3; /* 5 multiplications, 3 additions */ + + out1[32] = out[32]; + out1[33] = out[33]; + out1[34] = out[34]; + out1[35] = 0.707106781 * out[35]; + out1[36] = out[36]; + out1[37] = 0.707106781 * out[37]; + dummy1 = 1.306562964 * out[38]; + dummy2 = 0.923879532 * (out[38] + out[39]); + dummy3 = -0.5411961 * out[39]; + out1[38] = dummy1 - dummy2; + out1[39] = dummy2 + dummy3; /* 5 multiplications, 3 additions */ + + out1[24] = 0.707106781 * out[24]; + out1[25] = 0.707106781 * out[25]; + out1[26] = 0.707106781 * out[26]; + out1[27] = 0.5 * out[27]; + out1[28] = 0.707106781 * out[28]; + out1[29] = 0.5 * out[29]; + dummy1 = 0.923879532 * out[30]; + dummy2 = 0.653281481 * (out[30] + out[31]); + dummy3 = -0.382683432 * out[31]; + out1[30] = dummy1 - dummy2; + out1[31] = dummy2 + dummy3; /* 9 multiplications, 3 additions */ + + out1[40] = 0.707106781 * out[40]; + out1[41] = 0.707106781 * out[41]; + out1[42] = 0.707106781 * out[42]; + out1[43] = 0.5 * out[43]; + out1[44] = 0.707106781 * out[44]; + out1[45] = 0.5 * out[45]; + dummy1 = 0.923879532 * out[46]; + dummy2 = 0.653281481 * (out[46] + out[47]); + dummy3 = -0.382683432 * out[47]; + out1[46] = dummy1 - dummy2; + out1[47] = dummy2 + dummy3; /* 9 multiplications, 3 additions */ + + dummy1 = 1.306562964 * out[48]; + dummy2 = 0.923879532 * (out[48] + out[56]); + dummy3 = -0.5411961 * out[56]; + out1[48] = dummy1 - dummy2; + out1[56] = dummy2 + dummy3; + dummy1 = 1.306562964 * out[49]; + dummy2 = 0.923879532 * (out[49] + out[57]); + dummy3 = -0.5411961 * out[57]; + out1[49] = dummy1 - dummy2; + out1[57] = dummy2 + dummy3; + dummy1 = 1.306562964 * out[50]; + dummy2 = 0.923879532 * (out[50] + out[58]); + dummy3 = -0.5411961 * out[58]; + out1[50] = dummy1 - dummy2; + out1[58] = dummy2 + dummy3; + dummy1 = 1.306562964 * out[52]; + dummy2 = 0.923879532 * (out[52] + out[60]); + dummy3 = -0.5411961 * out[60]; + out1[52] = dummy1 - dummy2; + out1[60] = dummy2 + dummy3; + dummy1 = 0.923879532 * out[51]; + dummy2 = 0.653281481 * (out[51] + out[59]); + dummy3 = -0.382683432 * out[59]; + out1[51] = dummy1 - dummy2; + out1[59] = dummy2 + dummy3; + dummy1 = 0.923879532 * out[53]; + dummy2 = 0.653281481 * (out[53] + out[61]); + dummy3 = -0.382683432 * out[61]; + out1[53] = dummy1 - dummy2; + out1[61] = dummy2 + dummy3; + temp1 = 0.5 * (out[54] + out[63]); + temp2 = 0.5 * (out[55] - out[62]); + temp3 = out[54] - out[63]; + temp4 = out[55] + out[62]; + temp5 = 0.35355339 * (temp3 - temp4); + temp6 = 0.35355339 * (temp3 + temp4); + out1[54] = temp1 - temp6; + out1[55] = temp2 + temp5; + out1[62] = temp5 - temp2; + out1[63] = temp1 + temp6; /* 22 multiplications 28 additions */ + /*for (i=0; i<64; i++) printf("out1[%d] = %f\n",i,out1[i]);*/ + + /********* Post Additions *********/ + temp1 = out1[0] + out1[8]; + temp2 = out1[1] + out1[9]; + temp3 = out1[2] + out1[10]; + temp4 = out1[3] + out1[11]; + temp5 = out1[4] + out1[12]; + temp6 = out1[5] + out1[13]; + temp7 = out1[6] + out1[14]; + temp8 = out1[7] + out1[15]; + out[0] = temp1 + temp2; + out[1] = temp1 - temp2; + out[2] = temp4; + out[3] = temp3 - temp4; + out[4] = temp7 - temp6; + out[5] = temp8; + out[6] = -temp5 - temp7; + out[7] = temp6 + temp8; + temp1 = out1[0] - out1[8]; + temp2 = out1[1] - out1[9]; + temp3 = out1[2] - out1[10]; + temp4 = out1[3] - out1[11]; + temp5 = out1[4] - out1[12]; + temp6 = out1[5] - out1[13]; + temp7 = out1[6] - out1[14]; + temp8 = out1[7] - out1[15]; + out[8] = temp1 + temp2; + out[9] = temp1 - temp2; + out[10] = temp4; + out[11] = temp3 - temp4; + out[12] = temp7 - temp6; + out[13] = temp8; + out[14] = -temp5 - temp7; + out[15] = temp6 + temp8; + out[16] = out1[24] + out1[25]; + out[17] = out1[24] - out1[25]; + out[18] = out1[27]; + out[19] = out1[26] - out1[27]; + out[20] = out1[30] - out1[29]; + out[21] = out1[31]; + out[22] = -out1[28] - out1[30]; + out[23] = out1[29] + out1[31]; + temp1 = out1[16] - out1[24]; + temp2 = out1[17] - out1[25]; + temp3 = out1[18] - out1[26]; + temp4 = out1[19] - out1[27]; + temp5 = out1[20] - out1[28]; + temp6 = out1[21] - out1[29]; + temp7 = out1[22] - out1[30]; + temp8 = out1[23] - out1[31]; + out[24] = temp1 + temp2; + out[25] = temp1 - temp2; + out[26] = temp4; + out[27] = temp3 - temp4; + out[28] = temp7 - temp6; + out[29] = temp8; + out[30] = -temp5 - temp7; + out[31] = temp6 + temp8; + temp1 = out1[48] - out1[40]; + temp2 = out1[49] - out1[41]; + temp3 = out1[50] - out1[42]; + temp4 = out1[51] - out1[43]; + temp5 = out1[52] - out1[44]; + temp6 = out1[53] - out1[45]; + temp7 = out1[54] - out1[46]; + temp8 = out1[55] - out1[47]; + out[32] = temp1 + temp2; + out[33] = temp1 - temp2; + out[34] = temp4; + out[35] = temp3 - temp4; + out[36] = temp7 - temp6; + out[37] = temp8; + out[38] = -temp5 - temp7; + out[39] = temp6 + temp8; + out[40] = out1[56] + out1[57]; + out[41] = out1[56] - out1[57]; + out[42] = out1[59]; + out[43] = out1[58] - out1[59]; + out[44] = out1[62] - out1[61]; + out[45] = out1[63]; + out[46] = -out1[60] - out1[62]; + out[47] = out1[63] + out1[61]; + temp1 = -out1[32] - out1[48]; + temp2 = -out1[33] - out1[49]; + temp3 = -out1[34] - out1[50]; + temp4 = -out1[35] - out1[51]; + temp5 = -out1[36] - out1[52]; + temp6 = -out1[37] - out1[53]; + temp7 = -out1[38] - out1[54]; + temp8 = -out1[39] - out1[55]; + out[48] = temp1 + temp2; + out[49] = temp1 - temp2; + out[50] = temp4; + out[51] = temp3 - temp4; + out[52] = temp7 - temp6; + out[53] = temp8; + out[54] = -temp5 - temp7; + out[55] = temp6 + temp8; + temp1 = out1[40] + out1[56]; + temp2 = out1[41] + out1[57]; + temp3 = out1[42] + out1[58]; + temp4 = out1[43] + out1[59]; + temp5 = out1[44] + out1[60]; + temp6 = out1[45] + out1[61]; + temp7 = out1[46] + out1[62]; + temp8 = out1[47] + out1[63]; + out[56] = temp1 + temp2; + out[57] = temp1 - temp2; + out[58] = temp4; + out[59] = temp3 - temp4; + out[60] = temp7 - temp6; + out[61] = temp8; + out[62] = -temp5 - temp7; + out[63] = temp6 + temp8; /* 96 additions */ + /*for (i=0; i<64; i++) printf("out[%d] = %f\n",i,out[i]);*/ + + temp1 = out[0] + out[16]; + temp2 = out[1] + out[17]; + temp3 = out[2] + out[18]; + temp4 = out[3] + out[19]; + temp5 = out[4] + out[20]; + temp6 = out[5] + out[21]; + temp7 = out[6] + out[22]; + temp8 = out[7] + out[23]; + out1[0] = temp1 + temp3; + out1[1] = temp2 + temp4; + out1[2] = temp2 - temp4; + out1[3] = temp1 - temp3; + out1[4] = temp5; + out1[5] = temp6; + out1[6] = temp7; + out1[7] = temp8; + temp1 = out[8] + out[24]; + temp2 = out[9] + out[25]; + temp3 = out[10] + out[26]; + temp4 = out[11] + out[27]; + temp5 = out[12] + out[28]; + temp6 = out[13] + out[29]; + temp7 = out[14] + out[30]; + temp8 = out[15] + out[31]; + out1[8] = temp1 + temp3; + out1[9] = temp2 + temp4; + out1[10] = temp2 - temp4; + out1[11] = temp1 - temp3; + out1[12] = temp5; + out1[13] = temp6; + out1[14] = temp7; + out1[15] = temp8; + temp1 = out[8] - out[24]; + temp2 = out[9] - out[25]; + temp3 = out[10] - out[26]; + temp4 = out[11] - out[27]; + temp5 = out[12] - out[28]; + temp6 = out[13] - out[29]; + temp7 = out[14] - out[30]; + temp8 = out[15] - out[31]; + out1[16] = temp1 + temp3; + out1[17] = temp2 + temp4; + out1[18] = temp2 - temp4; + out1[19] = temp1 - temp3; + out1[20] = temp5; + out1[21] = temp6; + out1[22] = temp7; + out1[23] = temp8; + temp1 = out[0] - out[16]; + temp2 = out[1] - out[17]; + temp3 = out[2] - out[18]; + temp4 = out[3] - out[19]; + temp5 = out[4] - out[20]; + temp6 = out[5] - out[21]; + temp7 = out[6] - out[22]; + temp8 = out[7] - out[23]; + out1[24] = temp1 + temp3; + out1[25] = temp2 + temp4; + out1[26] = temp2 - temp4; + out1[27] = temp1 - temp3; + out1[28] = temp5; + out1[29] = temp6; + out1[30] = temp7; + out1[31] = temp8; + out1[32] = out[32] + out[34]; + out1[33] = out[33] + out[35]; + out1[34] = out[33] - out[35]; + out1[35] = out[32] - out[34]; + out1[36] = out[36]; + out1[37] = out[37]; + out1[38] = out[38]; + out1[39] = out[39]; + out1[40] = out[40] + out[42]; + out1[41] = out[41] + out[43]; + out1[42] = out[41] - out[43]; + out1[43] = out[40] - out[42]; + out1[44] = out[44]; + out1[45] = out[45]; + out1[46] = out[46]; + out1[47] = out[47]; + out1[48] = out[48] + out[50]; + out1[49] = out[49] + out[51]; + out1[50] = out[49] - out[51]; + out1[51] = out[48] - out[50]; + out1[52] = out[52]; + out1[53] = out[53]; + out1[54] = out[54]; + out1[55] = out[55]; + out1[56] = out[56] + out[58]; + out1[57] = out[57] + out[59]; + out1[58] = out[57] - out[59]; + out1[59] = out[56] - out[58]; + out1[60] = out[60]; + out1[61] = out[61]; + out1[62] = out[62]; + out1[63] = out[63]; /* 64 additions */ + /*for (i=0; i<64; i++) printf("out1[%d] = %f\n",i,out1[i]);*/ + + temp1 = out1[0] + out1[32]; + temp2 = out1[1] + out1[33]; + temp3 = out1[2] + out1[34]; + temp4 = out1[3] + out1[35]; + temp5 = out1[4] + out1[36]; + temp6 = out1[5] + out1[37]; + temp7 = out1[6] + out1[38]; + temp8 = out1[7] + out1[39]; + U[0] = temp1 + temp5; + U[8] = temp2 + temp6; + U[16] = temp3 + temp7; + U[24] = temp4 + temp8; + U[32] = temp4 - temp8; + U[40] = temp3 - temp7; + U[48] = temp2 - temp6; + U[56] = temp1 - temp5; + temp1 = out1[8] + out1[40]; + temp2 = out1[9] + out1[41]; + temp3 = out1[10] + out1[42]; + temp4 = out1[11] + out1[43]; + temp5 = out1[12] + out1[44]; + temp6 = out1[13] + out1[45]; + temp7 = out1[14] + out1[46]; + temp8 = out1[15] + out1[47]; + U[1] = temp1 + temp5; + U[9] = temp2 + temp6; + U[17] = temp3 + temp7; + U[25] = temp4 + temp8; + U[33] = temp4 - temp8; + U[41] = temp3 - temp7; + U[49] = temp2 - temp6; + U[57] = temp1 - temp5; + temp1 = out1[16] + out1[48]; + temp2 = out1[17] + out1[49]; + temp3 = out1[18] + out1[50]; + temp4 = out1[19] + out1[51]; + temp5 = out1[20] + out1[52]; + temp6 = out1[21] + out1[53]; + temp7 = out1[22] + out1[54]; + temp8 = out1[23] + out1[55]; + U[2] = temp1 + temp5; + U[10] = temp2 + temp6; + U[18] = temp3 + temp7; + U[26] = temp4 + temp8; + U[34] = temp4 - temp8; + U[42] = temp3 - temp7; + U[50] = temp2 - temp6; + U[58] = temp1 - temp5; + temp1 = out1[24] + out1[56]; + temp2 = out1[25] + out1[57]; + temp3 = out1[26] + out1[58]; + temp4 = out1[27] + out1[59]; + temp5 = out1[28] + out1[60]; + temp6 = out1[29] + out1[61]; + temp7 = out1[30] + out1[62]; + temp8 = out1[31] + out1[63]; + U[3] = temp1 + temp5; + U[11] = temp2 + temp6; + U[19] = temp3 + temp7; + U[27] = temp4 + temp8; + U[35] = temp4 - temp8; + U[43] = temp3 - temp7; + U[51] = temp2 - temp6; + U[59] = temp1 - temp5; + temp1 = out1[24] - out1[56]; + temp2 = out1[25] - out1[57]; + temp3 = out1[26] - out1[58]; + temp4 = out1[27] - out1[59]; + temp5 = out1[28] - out1[60]; + temp6 = out1[29] - out1[61]; + temp7 = out1[30] - out1[62]; + temp8 = out1[31] - out1[63]; + U[4] = temp1 + temp5; + U[12] = temp2 + temp6; + U[20] = temp3 + temp7; + U[28] = temp4 + temp8; + U[36] = temp4 - temp8; + U[44] = temp3 - temp7; + U[52] = temp2 - temp6; + U[60] = temp1 - temp5; + temp1 = out1[16] - out1[48]; + temp2 = out1[17] - out1[49]; + temp3 = out1[18] - out1[50]; + temp4 = out1[19] - out1[51]; + temp5 = out1[20] - out1[52]; + temp6 = out1[21] - out1[53]; + temp7 = out1[22] - out1[54]; + temp8 = out1[23] - out1[55]; + U[5] = temp1 + temp5; + U[13] = temp2 + temp6; + U[21] = temp3 + temp7; + U[29] = temp4 + temp8; + U[37] = temp4 - temp8; + U[45] = temp3 - temp7; + U[53] = temp2 - temp6; + U[61] = temp1 - temp5; + temp1 = out1[8] - out1[40]; + temp2 = out1[9] - out1[41]; + temp3 = out1[10] - out1[42]; + temp4 = out1[11] - out1[43]; + temp5 = out1[12] - out1[44]; + temp6 = out1[13] - out1[45]; + temp7 = out1[14] - out1[46]; + temp8 = out1[15] - out1[47]; + U[6] = temp1 + temp5; + U[14] = temp2 + temp6; + U[22] = temp3 + temp7; + U[30] = temp4 + temp8; + U[38] = temp4 - temp8; + U[46] = temp3 - temp7; + U[54] = temp2 - temp6; + U[62] = temp1 - temp5; + temp1 = out1[0] - out1[32]; + temp2 = out1[1] - out1[33]; + temp3 = out1[2] - out1[34]; + temp4 = out1[3] - out1[35]; + temp5 = out1[4] - out1[36]; + temp6 = out1[5] - out1[37]; + temp7 = out1[6] - out1[38]; + temp8 = out1[7] - out1[39]; + U[7] = temp1 + temp5; + U[15] = temp2 + temp6; + U[23] = temp3 + temp7; + U[31] = temp4 + temp8; + U[39] = temp4 - temp8; + U[47] = temp3 - temp7; + U[55] = temp2 - temp6; + U[63] = temp1 - temp5; /* 128 additions */ +} diff --git a/isis/src/clementine/apps/clem2isis/huffman.cpp b/isis/src/clementine/apps/clem2isis/huffman.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d2b07f342684d9997dd60d4afe896001cd25080 --- /dev/null +++ b/isis/src/clementine/apps/clem2isis/huffman.cpp @@ -0,0 +1,197 @@ +/* + * THIS ROUTINE IS PART OF THE CLEMENTINE PDS FILE READER PROGRAM. + * IT WAS WRITTEN BY ACT CORP. IN DIRECT SUPPORT TO THE + * CLEMENTINE (DSPSE) PROGRAM. + * + * IF YOU FIND A PROBLEM OR MAKE ANY CHANGES TO THIS CODE PLEASE CONTACT + * Dr. Erick Malaret at ACT Corp. + * tel: (703) 742-0294 + * (703) 683-7431 + * email: nrlvax.nrl.navy.mil + * + * + */ +#include +#include "jpeg_c.h" +#include "pds.h" + +#define ZRL 240 +#define EOB 0 + +void inithuffcode(); +void genhuffsize(char *, short *, short *); +void genhuffcode(short *, char *); +void genehuf(short *, short *, short *, char *, char *, short); +void gendectbls(short *, short *, short *, short *, short *); + + +short dcbits[16], acbits[16]; +char dchuffval[12], achuffval[162]; + +short dcehufco[16]; +short dcehufsi[16]; +short dcmincode[16]; +short dcmaxcode[16]; +short dcvalptr[16]; + +short acehufco[256]; +short acehufsi[256]; +short acmincode[16]; +short acmaxcode[16]; +short acvalptr[16]; + +/******************* Initialization of Huffman tables ********************/ +void inithuffcode() +{ + char dchuffsize[13], achuffsize[163]; + short dchuffcode[12], achuffcode[162]; + short dclastk, aclastk; + + /* generate dc Huffman codes */ + genhuffsize(dchuffsize,dcbits,&dclastk); + genhuffcode(dchuffcode,dchuffsize); +// fprintf(qparm,"dc huffman tables:\n"); //removed qparm references BMG 2006-07-18 +// fprintf(qparm,"(symbol length code)\n"); //removed qparm references BMG 2006-07-18 + genehuf(dcehufco,dcehufsi,dchuffcode,dchuffsize,dchuffval,dclastk); + + /* generate ac Huffman codes */ + genhuffsize(achuffsize,acbits,&aclastk); + genhuffcode(achuffcode,achuffsize); +// fprintf(qparm,"ac huffman tables:\n"); //removed qparm references BMG 2006-07-18 +// fprintf(qparm,"(symbol length code)\n"); //removed qparm references BMG 2006-07-18 + genehuf(acehufco,acehufsi,achuffcode,achuffsize,achuffval,aclastk); + + /* generate decoding tables */ + gendectbls(dcmincode,dcmaxcode,dcvalptr,dchuffcode,dcbits); + gendectbls(acmincode,acmaxcode,acvalptr,achuffcode,acbits); +} + +void genhuffsize(char *huffsize, short *bits, short *lastk) +{ + short i = 0,j = 1,k = 0; + + while ( i < 16 ) + if ( j > bits[i] ) { + i++; + j = 1; + } else { + huffsize[k] = i+1; + k++; + j++; + } + huffsize[k] = 0; + *lastk = k; +} + +void genhuffcode(short *huffcode, char *huffsize) +{ + short code, k; + char si; + + k = code = 0; + si = huffsize[0]; + + while ( huffsize[k] ) { + if ( huffsize[k] == si ) { + huffcode[k] = code; + code++; k++; + } else { + code <<= 1; + si++; + } + } +} + +void genehuf(short *ehufco, short *ehufsi, short *huffcode, char *huffsize, + char *huffvalue, short lastk) +{ + short k; + short value; + + for (k=0; k < lastk; k++) { + value = ((short)huffvalue[k])&0x00ff; + ehufco[value] = huffcode[k]; + ehufsi[value] = huffsize[k]; +// fprintf(qparm,"%#.2x\t%d\t%#x\n", //removed qparm reference, BMG 2006-07-18 +// huffvalue[k]&0x00ff, +// ehufsi[value], +// ehufco[value] ); + } +} + +void gendectbls(short *mincode, short *maxcode, short *valptr, short *huffcode, short *bits) +{ + short k, l; + + l = k = 0; + + while ( l < 16 ) { + if ( bits[l] ) { + valptr[l] = k; + mincode[l] = huffcode[k]; + maxcode[l] = huffcode[k + bits[l] -1]; + k += bits[l]; + } else + maxcode[l] = -1; + l++; + } +} + + +/************************** Decoding Section *****************************/ + +unsigned short mask[] = {0x0000, +0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080, +0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000}; + +short code; + +void decode(short *u, BitStream *ibs) +{ + short symbol, coeff, i, run, cat, j, l; + + /* get dc coefficient */ + l = 0; + code = BitStream_read(ibs,1); + while ( code > dcmaxcode[l] ) { + code = (short)(code << 1) | BitStream_read(ibs,1); + l++; + } + symbol = (dchuffval[dcvalptr[l] + code - dcmincode[l]]) & 0x00ff; + if ( symbol ) { + coeff = BitStream_read(ibs,symbol); + if ( coeff & mask[symbol] ) + u[0] = coeff; + else + u[0] = ((0xffff << symbol) | coeff) + 1; + } else + u[0] = 0; + + /* get ac coefficients */ + i = 1; + while ( i < 64 ) { + l = 0; + code = BitStream_read(ibs,1); + while ( code > acmaxcode[l] ) { + code = (short)(code << 1) | BitStream_read(ibs,1); + l++; + } + symbol = (achuffval[acvalptr[l] + code - acmincode[l]]) & 0x00ff; + + if ( symbol == ZRL ) { + for (j=0; j < 16; j++) u[i++] = 0; + } else if ( symbol == EOB ) { + for (j=i; j < 64; j++) u[i++] = 0; + } else { + run = (symbol >> 4) & 0x000f; + cat = symbol&0x000f; + while ( run-- ) u[i++] = 0; + + coeff = BitStream_read(ibs,cat); + if ( coeff & mask[cat] ) + u[i++] = coeff; + else + u[i++] = ((0xffff << cat) | coeff) + 1; + } + } +} diff --git a/isis/src/clementine/apps/clem2isis/jpeg_c.h b/isis/src/clementine/apps/clem2isis/jpeg_c.h new file mode 100644 index 0000000000000000000000000000000000000000..e63fc97349ae6f092940df26e16b5f474b6d47a6 --- /dev/null +++ b/isis/src/clementine/apps/clem2isis/jpeg_c.h @@ -0,0 +1,61 @@ + +/* Structure Definitions */ +enum FmodeDef { INPUT, OUTPUT }; +typedef enum FmodeDef Fmode; + +struct ByteStreamDef +{ + Fmode mode; + short stat; + FILE *file; +}; +typedef struct ByteStreamDef ByteStream; + +extern void *cByteStream( ByteStream *, char *FileName, Fmode FileMode ); +extern void *dByteStream(ByteStream *); +extern short ByteStream_read(ByteStream *); +extern short ByteStream_write(ByteStream *, short c); +extern short ByteStream_status(ByteStream *); + +#define MEMORY 1 +#define DISK 0 +#if defined(__BORLANDC__) && !defined(__WIN32__) +#define MALLOC farmalloc +#define FREE farfree +#define CHARH unsigned char huge +#define FAR far +#else +#define MALLOC malloc +#define FREE free +#define CHARH unsigned char +#define FAR +#endif + +struct BitStreamDef +{ + ByteStream bytestream; + short BitBuffer; /* Bit I/O buffer */ + short BitBuffMask; /* Bit I/O buffer mask */ + CHARH *outstring; + char mode; + unsigned long bytesout; + unsigned short bitmask[17]; +}; +typedef struct BitStreamDef BitStream; + +extern void *cBitStream( BitStream *, char *fn, Fmode fm ); +extern void *dBitStream(BitStream *); +extern short BitStream_write(BitStream *, short bits, short width); +extern short BitStream_read(BitStream *, short bits); + +/* Global Tables */ +extern float q_table[64]; +extern int zzseq[64]; +extern short dcbits[16], acbits[16]; +extern char dchuffval[12], achuffval[162]; + +/* Function Declarations */ +extern void inithuffcode(); +extern void encode(short *, BitStream *); +extern void decode(short *, BitStream *); +extern void decomp(BitStream *bs,CHARH *Image,long rows,long cols); diff --git a/isis/src/clementine/apps/clem2isis/pds.cpp b/isis/src/clementine/apps/clem2isis/pds.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a373577914422c24d9524883cba9fc9e4ae5bad --- /dev/null +++ b/isis/src/clementine/apps/clem2isis/pds.cpp @@ -0,0 +1,511 @@ +/* + * THIS ROUTINE IS PART OF THE CLEMENTINE PDS FILE READER PROGRAM. + * IT WAS WRITTEN BY ACT CORP. IN DIRECT SUPPORT TO THE + * CLEMENTINE (DSPSE) PROGRAM. + * + * IF YOU FIND A PROBLEM OR MAKE ANY CHANGES TO THIS CODE PLEASE CONTACT + * Dr. Erick Malaret at ACT Corp. + * tel: (703) 742-0294 + * (703) 683-7431 + * email: nrlvax.nrl.navy.mil + * + * + * Oct 31, 1994 Tracie Sucharski, USGS, Flagstaff Change so that the + * carriage returns are not removed from the labels. + * Sep 29, 1995 Tracie Sucharski, Added a fix to init_qt as given + * by Luiz Perez from ACT. + * Feb 20 2004 Kris Becker - Changed to "isismalloc.h" + * Jun 17 2004 KJB - Added support for the Mac + * Jul 18 2006 Brendan George - removed qparm references to stop output + * of paramtrs.dat file. + * Dec 11 2006 KJB Changed malloc.h to stdlib.h for the Mac port again. + * malloc.h is deprecated. +*/ +#include +#include +#ifdef __TURBOC__ +#include +#else +#include +#endif +#include +#include "jpeg_c.h" +#include "pds.h" + +#define READ_PARAM "rb" +#define WRITE_PARAM "wb" + +#if ISIS_LITTLE_ENDIAN +#else +#define sun +#endif + +PDSINFO pds; +//FILE *qparm; //removed qparm references BMG 2006-07-18 +extern long *DCTHist[64]; +extern float *Rn[64]; +extern float Q[64]; + +void init_q_table(FILE *fptr); +void readhufftbls(FILE *fptr); +void pds_decomp(FILE *fptr,CHARH *p,long sizej,long sizei); +#ifdef sun +void PClong2SUNlongVector(unsigned long invec[],int npts) ; +void PCshort2SUNshortVector(unsigned short invec[],int npts) ; +#endif +extern void getDCTHist(BitStream *bs, long rows, long cols); +extern void getRn(void); + + +PDSINFO *PDSR(char *fname, long *rows, long *cols) +{ + FILE *fptr; + int n; + int j,i; + CHARH *c; + char nstring[84],sdummy[80],buffer[50],low; + long sizej; /* number of rows in the image */ + long sizei; /* number of columns in the image */ + int bitpix; /* bits per pixel */ + int record_bytes; + int hist_rec,brw_rec,image_rec,ns,brwsize; + char cval, *sptr, *ptr='\0'; + char record_type[20]; + int COMPRESSED=0; + long k,hdr_size; + + if( (fptr = fopen(fname,READ_PARAM)) == NULL){ /* open disk file */ + printf("Can't open %s.\n",fname); + return NULL; + } + + /* initialize some basic variables */ + bitpix =0; + sizej=sizei =0; + pds.browse_nrows =0; + pds.browse_ncols =0; + pds.image_nrows =0; + pds.image_ncols =0; + hist_rec = brw_rec = image_rec = -1; + + /* read header */ + do{ + /* read next line of text */ + for (n=0; (cval=fgetc(fptr)); n++) { + nstring[n]=cval; + if(cval=='\n') { + if( (cval=fgetc(fptr)) != '\r') ungetc(cval,fptr); + nstring[++n]='\0'; + break; + } + } + + /* find line's first non-space character */ + for (ns=0; nstring[ns]==' ';ns++); + sptr = &nstring[ns]; + + if (strncmp("^IMAGE_HISTOGRAM ",sptr,17)==0) { + /*printf("image histogram found \n"); */ + n=sscanf(nstring,"%s = %d", sdummy, &hist_rec); + /*printf("hist_rec = %d\n",hist_rec);*/ + } + + if (strncmp("^BROWSE_IMAGE ",sptr,14)==0) { + n=sscanf(nstring,"%s = %d", sdummy, &brw_rec); + /*printf("brw_rec = %d\n",brw_rec);*/ + } + + if (strncmp("^IMAGE ",sptr,7)==0) { + n=sscanf(nstring,"%s = %d", sdummy, &image_rec); + } + + if (strncmp("RECORD_TYPE",sptr,9)==0) { + n=sscanf(nstring,"%s = %s", sdummy, record_type); + } + + if (strncmp("RECORD_BYTES",sptr,12)==0) { + n=sscanf(nstring,"%s = %d", sdummy, &record_bytes); + } + + if (strncmp("ENCODING_TYPE",sptr,13)==0) { + n=sscanf(nstring,"%s = \"%[^\"]\"", sdummy, buffer); + if ( strstr(buffer,"N/A") ) + COMPRESSED = 0; + else if ( strstr(buffer,"DECOMPRESSED") ) + COMPRESSED = 0; + else + COMPRESSED = 1; + } + + if (strncmp("LINES ",sptr,6)==0) { + n=sscanf(nstring,"%s = %ld", sdummy, &sizej); + } + + if (strncmp("LINE_SAMPLES",sptr,12)==0) { + n=sscanf(nstring,"%s = %ld", sdummy, &sizei); + } + + if (strncmp("SAMPLE_BITS",sptr,11)==0) { + n=sscanf(nstring,"%s = %d", sdummy, &bitpix); + } + + if (strncmp("END",sptr,3)==0) { + if ( *(sptr+3)=='\n' || *(sptr+3)==' ' || *(sptr+3)=='\r' ) { + hdr_size = ftell(fptr); + break; + } + } + } while(1); + + /************** read histogram ***************/ + if ( hist_rec != -1 ) { + fseek(fptr,hist_rec-1,0); + pds.hist = (long *)malloc(256*sizeof(long)); + if(pds.hist == NULL) { + printf(" histogram memory not allocated \n"); + } + if ( pds.hist ) { + fread(pds.hist,sizeof(long),256,fptr); +#ifdef sun + PClong2SUNlongVector((unsigned long*)pds.hist,256); +#endif + /*printf("pds.hist = %x\n",pds.hist);*/ + } + } + + /************** read browse image **********/ + if ( brw_rec != -1 ) { + pds.browse_ncols = sizei/8; + pds.browse_nrows = sizej/8; + fseek(fptr,brw_rec-1,0); + brwsize = (sizej/8) * (sizei/8); + pds.brw_imag = (unsigned char *)malloc(brwsize); + if ( pds.brw_imag ) + fread(pds.brw_imag,sizeof(char),brwsize,fptr); + } + + /************* read image data ***************/ + if (strncmp(record_type,"UNDEFINED",9)==0) { + record_bytes=1; + fseek(fptr,(image_rec-1),0); + } else { + fseek(fptr,(image_rec-1)*record_bytes,0); + } + + switch (bitpix) { + case 8: + c = (CHARH *)MALLOC(sizej*sizei); + if ( c == NULL ) { + printf("Can't allocate memory for image array.\n"); + fclose(fptr); + return NULL; + } + + if ( COMPRESSED ) { + //qparm = fopen("paramtrs.dat","w"); //removed qparm references BMG 2006-07-18 + init_q_table(fptr); + readhufftbls(fptr); + pds_decomp(fptr,c,sizej,sizei); +// fclose(qparm); //removed qparm references BMG 2006-07-18 + } else { + + for (j=0, k=0; j 60000L ) { + blocks = nbytes / 32768; + rem = nbytes % 32768; + nb = 32768; + }; + ptr = ibs.outstring; + for (i=0; i < blocks; i++,ptr+=nb) { + if ( fread(ptr,sizeof(char),nb,fptr) != nb ) { + printf("Error reading data string.\n"); + FLAG = 1; + break; + } + } + if ( rem ) { + if ( (int)fread(ptr,sizeof(char),rem,fptr) != rem ) { + printf("Error reading data string.\n"); + FLAG = 1; + } + } + ibs.mode = MEMORY; + } else { + ibs.bytestream.file = fptr; + ibs.mode = DISK; + } + + if ( !FLAG ) { + npanels = sizej/32; + bytesperpanel = 32*sizei; + + /* Allocate memory for DCT coefficients histograms */ + for (i=0; i<64; i++) { + DCTHist[i] = (long FAR *)MALLOC(sizeof(long)*513); + memset((void *)DCTHist[i],0,sizeof(long)*513); + DCTHist[i] += 256; + } + /* Allocate memory for DCT coefficients table look-up */ + for (i=0; i<64; i++) { + Rn[i] = (float FAR *)MALLOC(sizeof(float)*513); + memset((void *)Rn[i],0,sizeof(float)*513); + Rn[i] += 256; + } + + for (i=0; i>8) + + ((ival&0xff000000)>>24); + invec[i]= oval; + } +} +void PCshort2SUNshortVector(unsigned short invec[],int npts){ + int i; + unsigned short ival,oval; + for(i=0;i>8)&0x00ff); + invec[i]= oval; + + } +} +#endif + diff --git a/isis/src/clementine/apps/clem2isis/pds.h b/isis/src/clementine/apps/clem2isis/pds.h new file mode 100644 index 0000000000000000000000000000000000000000..436e087ea9e11cfea8ec45f76d556840a0ff4847 --- /dev/null +++ b/isis/src/clementine/apps/clem2isis/pds.h @@ -0,0 +1,21 @@ + +#if defined(__BORLANDC__) && !defined(__WIN32__) +#define CHARH unsigned char huge +#else +#define CHARH unsigned char +#endif + +typedef struct { + char *text; /* pointer to text header */ + long *hist; /* pointer to histogram */ + unsigned char *brw_imag; /* pointer to browse image (if available) */ + int browse_nrows; /* number of rows in browse image */ + int browse_ncols; /* number of columns in browse image */ + CHARH *image; /* pointer to decompressed or uncompressed image */ + int image_nrows; /* number of rows in the image */ + int image_ncols; /* number of columns in the image */ +} PDSINFO; + +//extern FILE *qparm; //removed qparm references BMG 2006-07-18 + +extern PDSINFO *PDSR(char *fname, long *rows, long *cols); diff --git a/isis/src/clementine/apps/clem2isis/tsts/Makefile b/isis/src/clementine/apps/clem2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/clementine/apps/clem2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/clementine/apps/clem2isis/tsts/default/Makefile b/isis/src/clementine/apps/clem2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..91575f9a462507d71cba1588a5c4825a905484a4 --- /dev/null +++ b/isis/src/clementine/apps/clem2isis/tsts/default/Makefile @@ -0,0 +1,16 @@ +APPNAME = clem2isis + +nirLabels.txt.IGNORELINES = Bytes StartByte ByteOrder +uvvisLabels.txt.IGNORELINES = Bytes StartByte ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/lua1855j.310 \ + to=$(OUTPUT)/lua1855j.truth.cub > /dev/null; + $(RM) paramtrs.dat; + catlab from=$(OUTPUT)/lua1855j.truth.cub >& $(OUTPUT)/uvvisLabels.txt; + $(APPNAME) from=$(INPUT)/lna3056k.284 \ + to=$(OUTPUT)/lna3056k.truth.cub > /dev/null; + $(RM) paramtrs.dat; + catlab from=$(OUTPUT)/lna3056k.truth.cub >& $(OUTPUT)/nirLabels.txt; diff --git a/isis/src/clementine/apps/clem2isis/tsts/incMCPgain/Makefile b/isis/src/clementine/apps/clem2isis/tsts/incMCPgain/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..db609ce7fe6b18c103e585915cdfaf37a3935879 --- /dev/null +++ b/isis/src/clementine/apps/clem2isis/tsts/incMCPgain/Makefile @@ -0,0 +1,7 @@ +APPNAME = clem2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/lhd4904o.335 \ + to=$(OUTPUT)/MCPgainIn.cub > /dev/null; diff --git a/isis/src/clementine/apps/clemhirescal/Makefile b/isis/src/clementine/apps/clemhirescal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/clementine/apps/clemhirescal/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/clementine/apps/clemhirescal/assets/data/lhd_flat.jpg b/isis/src/clementine/apps/clemhirescal/assets/data/lhd_flat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..005fd0f132d5b3f637d17427d1fb09d04dd66de9 Binary files /dev/null and b/isis/src/clementine/apps/clemhirescal/assets/data/lhd_flat.jpg differ diff --git a/isis/src/clementine/apps/clemhirescal/assets/images/clem2.jpg b/isis/src/clementine/apps/clemhirescal/assets/images/clem2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6d64f6aaed7e277db735fa0388e43e59bd54d025 Binary files /dev/null and b/isis/src/clementine/apps/clemhirescal/assets/images/clem2.jpg differ diff --git a/isis/src/clementine/apps/clemhirescal/assets/images/clem2CAL.jpg b/isis/src/clementine/apps/clemhirescal/assets/images/clem2CAL.jpg new file mode 100644 index 0000000000000000000000000000000000000000..38f21a2523152edb779051bd6cb2d9f4caedd94d Binary files /dev/null and b/isis/src/clementine/apps/clemhirescal/assets/images/clem2CAL.jpg differ diff --git a/isis/src/clementine/apps/clemhirescal/assets/images/clemGUI.jpg b/isis/src/clementine/apps/clemhirescal/assets/images/clemGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..907076beb0ff5df995cbc929ee741cbd0133a820 Binary files /dev/null and b/isis/src/clementine/apps/clemhirescal/assets/images/clemGUI.jpg differ diff --git a/isis/src/clementine/apps/clemhirescal/assets/thumbs/clem2.jpg b/isis/src/clementine/apps/clemhirescal/assets/thumbs/clem2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..146d8a21afc11d7f31b73d66f4bcc013ae51ac98 Binary files /dev/null and b/isis/src/clementine/apps/clemhirescal/assets/thumbs/clem2.jpg differ diff --git a/isis/src/clementine/apps/clemhirescal/assets/thumbs/clem2CAL.jpg b/isis/src/clementine/apps/clemhirescal/assets/thumbs/clem2CAL.jpg new file mode 100644 index 0000000000000000000000000000000000000000..05c04585a0d8a7234842e4444b24a5ee5796e3ea Binary files /dev/null and b/isis/src/clementine/apps/clemhirescal/assets/thumbs/clem2CAL.jpg differ diff --git a/isis/src/clementine/apps/clemhirescal/assets/thumbs/clemGUI.jpg b/isis/src/clementine/apps/clemhirescal/assets/thumbs/clemGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..82ef3d197d53b5898130c72064d26bfa42c1e1c8 Binary files /dev/null and b/isis/src/clementine/apps/clemhirescal/assets/thumbs/clemGUI.jpg differ diff --git a/isis/src/clementine/apps/clemhirescal/clemhirescal.cpp b/isis/src/clementine/apps/clemhirescal/clemhirescal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..153b786cc25354d529fde98ff4be27c629e94371 --- /dev/null +++ b/isis/src/clementine/apps/clemhirescal/clemhirescal.cpp @@ -0,0 +1,128 @@ +#include "Isis.h" + +#include "Cube.h" +#include "CubeAttribute.h" +#include "iException.h" +#include "iString.h" +#include "ProcessByLine.h" +#include "Pvl.h" +#include "SpecialPixel.h" + +#include + +using namespace std; +using namespace Isis; + +void clemhirescal(vector &in, vector &out); + +double offset; +double abscoef; + +void IsisMain() { + // Open the input cube + ProcessByLine p; + Cube *input = p.SetInputCube("FROM"); + + // Check for filter type of A-D + Pvl *label = input->Label(); + iString wave = (string)label->FindGroup("BandBin", Pvl::Traverse)["FilterName"]; + if ((wave != "A") && (wave != "B") && (wave != "C") && (wave != "D")) { + string message = "Invalid FilterName [" + wave + "], can only handle A-D filters"; + throw iException::Message(Isis::iException::None, message, _FILEINFO_); + } + // Determine and load calibration flat field file + wave.DownCase(); + iString flatFile("$Clementine1/calibration/hires/lh" + + wave + "_flat.cub"); + CubeAttributeInput cubeAtt; + p.SetInputCube(flatFile, cubeAtt); + + // Check the offset mode for validity + int index = label->FindGroup("Instrument", Pvl::Traverse)["OffsetModeID"]; + if (index < 0 || index > 5) { + string message = "Invalid OffsetModeID, can only handle offests 0-5"; + throw iException::Message(Isis::iException::None, message, _FILEINFO_); + } + + // Set the offset (b0) value based on mode + double dataOffset[] = {-49.172, -41.0799, -32.8988, -24.718, -16.98, -8.0}; + offset = dataOffset[index]; + + // Computer the K value to convert to I/F. The K value per MCP and wavelength + // were obtained from JGR publication Vol 108, A radiometric calibration for the + // Clementine HIRES camera: Robinson, Malart, White, page 17 + UserInterface &ui = Application::GetUserInterface(); + if (ui.GetString("KFROM").compare("COMPUTED") == 0) { + wave.UpCase(); + int MCP = label->FindGroup("Instrument", Pvl::Traverse)["MCPGainModeID"]; + // Two possible MCP gains for filter A + if (wave == "A") { + if (MCP == 156) { + abscoef = 0.00105; + } + else if (MCP == 159) { + abscoef = 0.00089; + } + else { + string message = "Image is not one of supported MCP Gain Mode IDs, enter your own K value"; + throw Isis::iException::Message(Isis::iException::User, message, _FILEINFO_); + } + } + // Three possiblities for filter D + else if (wave == "D") { + if (MCP == 151) { + abscoef = 0.001655; + } + else if (MCP == 154) { + abscoef = 0.001375; + } + else if (MCP == 158) { + abscoef = 0.00097; + } + else { + string message = "Image is not one of supported MCP Gain Mode IDs, enter your own K value"; + throw Isis::iException::Message(Isis::iException::User, message, _FILEINFO_); + } + } + // Other filters not supported for preset K value + else { + string message = "Image is of filter [" + wave + "], not supported type A or D, enter your own K value"; + throw Isis::iException::Message(Isis::iException::User, message, _FILEINFO_); + } + } + + // Otherwise get K value from user + else { + abscoef = ui.GetDouble("KVALUE"); + } + + // K, Offset, and flat file are defined. Create output cube and process + // each line + p.SetOutputCube("TO"); + p.StartProcess(clemhirescal); + p.EndProcess(); +} + + +void clemhirescal (vector &in, vector &out) { + Buffer &num = *in[0]; // Input line + Buffer &den = *in[1]; // Denominator line + Buffer &rat = *out[0]; // Output line + + for (int i = 0 ; i < num.size() ; i ++) { + // If it is special, write it out and continue + if (IsSpecial(num[i])) { + rat[i] = num[i]; + } + else { + //Check denominator for both unusable conditions + if (IsSpecial(den[i]) || den[i] == 0.0) { + rat[i] = Isis::Null; + } + else { + //Do ratio and multiply by k constant. + rat[i] = ((num[i] + offset) / den[i]) * abscoef; + } + } + } +} diff --git a/isis/src/clementine/apps/clemhirescal/clemhirescal.xml b/isis/src/clementine/apps/clemhirescal/clemhirescal.xml new file mode 100644 index 0000000000000000000000000000000000000000..501c8b5a86193bf06eba414ffd01365287e82f9b --- /dev/null +++ b/isis/src/clementine/apps/clemhirescal/clemhirescal.xml @@ -0,0 +1,202 @@ + + + + + Calibrate Clementine Hires images + + + This program serves to calibrate most images from the Clementine Hires + camera. It does so through the use of some constants based on offset and + flat images based on filter type. There are six possible offsets, with the + resultant change being anywhere between eight and fifty to the DN. There + are four flat images, one for each of the four possible filters. + Information for this program came from JGR Vol 108, A radiometric + calibration for the Clementine Hires camera: Robinson, Malaret, White. + + + + Original version + + + + + Clementine + + + + + + cube + input + + Input cube to be calibrated + + + Use this parameter to select the filename + + + *.cub + + + + + cube + real + output + + Output of calibrated cube + + + This file will contain the results of the calibration + + + *.cub + + + + + + + string + + K value selection + + + COMPUTED + + + + + + + This parameter is used to choose either a user entered K value or a + previously set, calculated K value. + + + + + double + + 0.00125 + + 0.0 + 0.05 + + An averaged K value + + + The K value is the absolute coefficient per wavelength and MCP gain + state. This is an average of several possible K values, the default + should not be used when possible as it is an average. + + + + + + + + + Usage of the Clementine Hires calibration + + + This shows the usage of the clementine high resolution image calibration + program. In this case a K value can be computed for the image. + + + + from= clem2.cub to=clem2CAL.cub + + + This shows the terminal interface for using clemhirescal from the command + line. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to calibrate a hires + image using a perviously set K value. + + + + + + + + + + Input image before calibration + + + This is the image as it was taken originally, complete with hotspot + and chickenwire pattern. + + + FROM + + + + + + + Output image after calibration + + + The image should now appear more even, without hotspot or + chickenwire pattern, and radiometrically calibrated. + + + TO + + + + + + + Flat file denominator + + + This is one of the four avaliable flat files. It is the one used on + the image you see, it is specifically for the D filter type. + + + Flat file for D filter + + + + + + + diff --git a/isis/src/clementine/apps/clemhirescal/tsts/Makefile b/isis/src/clementine/apps/clemhirescal/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/clementine/apps/clemhirescal/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/clementine/apps/clemhirescal/tsts/default/Makefile b/isis/src/clementine/apps/clemhirescal/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..65a9d2e226fc83f37b7e514689ae18dae1a4c2f5 --- /dev/null +++ b/isis/src/clementine/apps/clemhirescal/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = clemhirescal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/lhd4904o.335.cub \ + to=$(OUTPUT)/calTruth.cub > /dev/null; diff --git a/isis/src/clementine/apps/clemnircal/Makefile b/isis/src/clementine/apps/clemnircal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/clementine/apps/clemnircal/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/clementine/apps/clemnircal/assets/images/after.jpg b/isis/src/clementine/apps/clemnircal/assets/images/after.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9388562e7e90d1c6de41767ab6b26b6bffb841f0 Binary files /dev/null and b/isis/src/clementine/apps/clemnircal/assets/images/after.jpg differ diff --git a/isis/src/clementine/apps/clemnircal/assets/images/before.jpg b/isis/src/clementine/apps/clemnircal/assets/images/before.jpg new file mode 100644 index 0000000000000000000000000000000000000000..52c91340e58102be7aaae2f48c83213ea6069102 Binary files /dev/null and b/isis/src/clementine/apps/clemnircal/assets/images/before.jpg differ diff --git a/isis/src/clementine/apps/clemnircal/assets/images/clemnircal.jpg b/isis/src/clementine/apps/clemnircal/assets/images/clemnircal.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1d445fc33b327984d01386657bca8b934450b8e4 Binary files /dev/null and b/isis/src/clementine/apps/clemnircal/assets/images/clemnircal.jpg differ diff --git a/isis/src/clementine/apps/clemnircal/assets/thumbs/after.jpg b/isis/src/clementine/apps/clemnircal/assets/thumbs/after.jpg new file mode 100644 index 0000000000000000000000000000000000000000..11c6047855fa0f813b388fbf0dc0255ce8f34462 Binary files /dev/null and b/isis/src/clementine/apps/clemnircal/assets/thumbs/after.jpg differ diff --git a/isis/src/clementine/apps/clemnircal/assets/thumbs/before.jpg b/isis/src/clementine/apps/clemnircal/assets/thumbs/before.jpg new file mode 100644 index 0000000000000000000000000000000000000000..840442e4f128ad93bb8bd81585687561d4b8a1a7 Binary files /dev/null and b/isis/src/clementine/apps/clemnircal/assets/thumbs/before.jpg differ diff --git a/isis/src/clementine/apps/clemnircal/assets/thumbs/clemnircal.jpg b/isis/src/clementine/apps/clemnircal/assets/thumbs/clemnircal.jpg new file mode 100644 index 0000000000000000000000000000000000000000..22bfcfb4890736f222ce91ba173e06be482d8fbb Binary files /dev/null and b/isis/src/clementine/apps/clemnircal/assets/thumbs/clemnircal.jpg differ diff --git a/isis/src/clementine/apps/clemnircal/clemnircal.cpp b/isis/src/clementine/apps/clemnircal/clemnircal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a02fa02c7d96b2022d02703cab233126767c19ff --- /dev/null +++ b/isis/src/clementine/apps/clemnircal/clemnircal.cpp @@ -0,0 +1,322 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "Pixel.h" +#include "iException.h" +#include "TextFile.h" +#include "Table.h" +#include + +using namespace std; +using namespace Isis; + +const double digitalOffset = 8.30690; +const double globalBias = 2.15547; +const double globalDarkCoefficient = 0.730; +const double vConstant = -0.954194; + +double gainFactor; +double absoluteCoefficient; +double saturationThreshold = 255.0; +double cryonorm = 10000.0; // This will almost always be 10,000 +double cryocoolerDuration; +double optimalExposureDuration; + +int numCoefficients = -1; // This will almost always be 1 or 2 +int offsetModeID = 0; + +bool convertToNull = false; +bool doThermalCorrection = false; + +std::vector thermBgCoefficients; + +void NirCal(std::vector< Isis::Buffer* > &in, std::vector< Isis::Buffer* > &out); + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + UserInterface &ui = Application::GetUserInterface(); + + // Basic settings + convertToNull = ui.GetBoolean("BPFLAG"); + doThermalCorrection = ui.GetBoolean("THCOR"); + absoluteCoefficient = ui.GetDouble("ABSCOEF"); + saturationThreshold = ui.GetDouble("HISAT"); + + // Do files (filter + product ID matters) + Cube *icube = p.SetInputCube("FROM"); + Cube *ocube =p.SetOutputCube("TO"); + Cube *ffcube, *ofcube, *afcube, *dccube, *biascube, *bpcube; + + iString filter = (string)(icube->GetGroup("BandBin"))["FilterName"]; + filter = filter.DownCase(); + iString productID = (string)(icube->GetGroup("Archive"))["ProductID"]; + iString orbit = productID.substr(productID.find('.')+1, productID.length()-1); + + // If hemisphere code greater than 'I' set to 'n' else set to 's' + char hemisphereCode = (productID[productID.find('.')-1] > 'I') ? 'n' : 's'; + iString compressionType = (string)(icube->GetGroup("Instrument"))["EncodingFormat"]; + offsetModeID = (icube->GetGroup("Instrument"))["OffsetModeID"]; + int gainModeID = (icube->GetGroup("Instrument"))["GainModeID"]; + iString gainModeIDStr = gainModeID; + double exposureDuration = (double)(icube->GetGroup("Instrument"))["ExposureDuration"]; + optimalExposureDuration = (exposureDuration * 0.984675) + 0.233398; + cryocoolerDuration = (icube->GetGroup("Instrument"))["CryocoolerDuration"]; + + if (ui.WasEntered("FFFILE")) { + ffcube = p.SetInputCube("FFFILE"); + } else { + string fffileLoc = "$clementine1/calibration/nir/"; + fffileLoc += "newnir_flat_" + filter + ".cub"; + CubeAttributeInput cubeAtt; + ffcube = p.SetInputCube(fffileLoc, cubeAtt); + } + + if (ui.WasEntered("OFFILE")) { + ofcube = p.SetInputCube("OFFILE"); + } else { + string fffileLoc = "$clementine1/calibration/nir/nirorbitflats/"; + fffileLoc += "nir_orbflat_" + orbit + "_" + filter + ".cub"; + CubeAttributeInput cubeAtt; + ofcube = p.SetInputCube(fffileLoc, cubeAtt); + } + + string afFileTableLoc = ""; + if (ui.WasEntered("AFFILE")) { + afcube = p.SetInputCube("AFFILE"); + } else { + string affileLoc; + afFileTableLoc = "$clementine1/calibration/nir/nir.addflats.dat"; + + TextFile aFFileTable(afFileTableLoc); + int numLines = aFFileTable.LineCount(); + for (int i=0; iFilename()); + calgrp += PvlKeyword("OrbitFlatFieldFile",ofcube->Filename()); + calgrp += PvlKeyword("AdditiveFile",afcube->Filename()); + calgrp += PvlKeyword("DarkCurrentFile",dccube->Filename()); + calgrp += PvlKeyword("BiasFile",biascube->Filename()); + calgrp += PvlKeyword("BadPixelFile",bpcube->Filename()); + + //Table files + calgrp += PvlKeyword("ThermalCorrectionTable",thermTbl); + calgrp += PvlKeyword("AdditiveFileTable",afFileTableLoc); + + calgrp += PvlKeyword("DigitalOffset",digitalOffset); + calgrp += PvlKeyword("GlobalBias",globalBias); + calgrp += PvlKeyword("GlobalDarkCoefficient",globalDarkCoefficient); + calgrp += PvlKeyword("V",vConstant); + //Calculated in processing routine + calgrp += PvlKeyword("GainFactor",gainFactor); + calgrp += PvlKeyword("AbsoluteCoefficient",absoluteCoefficient); + calgrp += PvlKeyword("CryoNorm",cryonorm); + calgrp += PvlKeyword("OptimalExposureDuration",optimalExposureDuration); + + ocube->PutGroup(calgrp); + p.EndProcess(); +} + +void NirCal(std::vector< Isis::Buffer* > &in, std::vector< Isis::Buffer* > &out) { + Isis::Buffer &incube = *in[0]; + Isis::Buffer &ffcube = *in[1]; + Isis::Buffer &ofcube = *in[2]; + Isis::Buffer &afcube = *in[3]; + Isis::Buffer &dccube = *in[4]; + Isis::Buffer &biascube = *in[5]; + Isis::Buffer &badpixelcube = *in[6]; + Isis::Buffer &outcube = *out[0]; + + //Compute the thermal background correction + double backgroundCorr = 0.0; + + for(int iCoefficient = 0; iCoefficient <= numCoefficients; iCoefficient ++) { + backgroundCorr += thermBgCoefficients[iCoefficient] * pow(cryocoolerDuration / cryonorm, iCoefficient); + } + + //No correction for thermal shape is required + double thermalShapeCorrection = 0.0; + + for(int iSample = 0; iSample < incube.SampleDimension(); iSample ++) { + // If the bad pixel cube has 0.0 as a value, then this is a known bad pixel + if((badpixelcube[iSample] == 0.0)) { + outcube[iSample] = Isis::Null; + continue; + } + else if(Pixel::IsSpecial(incube[iSample])) { + outcube[iSample] = incube[iSample]; + continue; + } + else if(incube[iSample] >= saturationThreshold) { + outcube[iSample] = Isis::Hrs; + continue; + } + else if(Pixel::IsSpecial(ffcube[iSample]) || ffcube[iSample] == 0.0) { + // In ISIS2 code the flat field cube was not being checked for + // high saturations, and math was still performed on the + // files. So, either the result was near zero (because it's + // a dividend) or there are no high saturations in this cube + // ever. + outcube[iSample] = Isis::Null; + continue; + } + // Can't do math on special pixels... + else if(Pixel::IsSpecial(dccube[iSample]) || + Pixel::IsSpecial(afcube[iSample]) || + Pixel::IsSpecial(ofcube[iSample]) || + Pixel::IsSpecial(biascube[iSample]) || + Pixel::IsSpecial(badpixelcube[iSample])) { + outcube[iSample] = Isis::Null; + continue; + } + + // Gain factor already checked for zero values + double term1 = (incube[iSample] - digitalOffset) / gainFactor; + + double term2 = term1 - globalBias - biascube[iSample] - (offsetModeID * vConstant); + + double term3 = term2 / optimalExposureDuration; + + double term4 = term3 - globalDarkCoefficient - dccube[iSample]; + + double term5 = term4 - backgroundCorr - thermalShapeCorrection; + + double term6 = term5 / ffcube[iSample]; + + double term7 = term6 / ofcube[iSample]; + + double term8 = term7 - afcube[iSample]; + + + outcube[iSample] = term8 * absoluteCoefficient; + } +} diff --git a/isis/src/clementine/apps/clemnircal/clemnircal.xml b/isis/src/clementine/apps/clemnircal/clemnircal.xml new file mode 100644 index 0000000000000000000000000000000000000000..461094463ab2aa5b8f119bf659b547125dfbcaf5 --- /dev/null +++ b/isis/src/clementine/apps/clemnircal/clemnircal.xml @@ -0,0 +1,467 @@ + + + + + Performs radiometric corrections on Clementine NIR images + + + +INTRODUCTION +
    +
    + + +This program performs radiometric corrections to images acquired by the +Clementine spacecraft Near Infrared camera and writes the +output image values in units of radiance. +
    +
    + + +EQUATIONS +
    +
    + +Term1 = ( DR(x,y) - digital_offset ) / Gfact(gm) +
    + +Term2 = Term1 - bias_global - BIAS(x,y) - (om * V) +
    + +Term3 = Term2 / t +
    + +Term4 = Term3 - DC(x,y) - 0.730 +
    + +Term5 = Term4 - therm - thermShape +
    + +Term6 = Term5 / FF(x,y) +
    + +Term7 = Term6 / OF(x,y) +
    + +Term8 = Term7 - AF(x,y) +
    + +R(x,y) = Term8 * abscoef +
    +
    + +General equations applied to data for radiometric correction are +indicated below: +
    +
    + +Let: x,y = line and sample position of pixel in an image +
    + R(x,y) = Result of correction in absolute radiance. +
    + DO(x,y) = Result of correction. The output can either + be absolute radiance values or they can be converted to + reflectance(I/F values +
    + DR(x,y) = Raw input density number +
    + FF(x,y) = Flat-field as a function of filter and line, sample +
    + position. This will be read from an ISIS cube file. +
    + OF(x,y) = Orbit dependent flat file correction. +
    + DC(x,y) = Dark current as a function of compression type, +
    + line, sample position. + AF(x,y) = Empirical additive flat-field coefficients at line, sample position. +
    + BIAS(x,y) = Bias correction as a function of compression type, + line, sample position. +
    + digital_offset = 9.0 +
    + bias_global = 2.0 +
    + V = -.91 +
    + abscoef = 1.0 +
    + g(GainModeID) = Gain factor as a function of insturment GainModeID +
    + g(0) = 2.0235 +
    + g(1) = 8.2755 +
    + g(2) = 4.9144 +
    + g(5) = 0.9443 +
    + g(8) = 4.1835 +
    + g(9) = 1.3530 +
    + g(11) = 15.9844 +
    + g(13) = 7.77177 +
    + g(16) = 28.1618 +
    + g(17) = 24.8658 +
    + g(18) = 21.9100 +
    + g(19) = 18.6140 +
    + g(22) = 6.83130 +
    + g(23) = 3.48425 +
    + g(24) = 20.3218 +
    + g(25) = 17.9433 +
    + g(26) = 15.8104 +
    + g(27) = 13.4320 +
    + g(28) = 9.32361 +
    + g(29) = 6.95951 +
    + g(30) = 4.75472 +
    + g(31) = 2.43896 +
    + g(33) = 13.9238 +
    + g(34) = 12.2687 +
    + g(36) = 7.23501 +
    + g(41) = 7.04438 +
    + g(42) = 6.16495 +
    + g(44) = 3.57405 +
    + g(45) = 2.73995 +
    + g(46) = 1.88595 +
    + g(48) = 11.9078 +
    + g(50) = 9.26433 +
    + g(52) = 5.39513 +
    + g(53) = 4.08125 +
    + g(61) = 1.40899 +
    + g(62) = 0.964975 +
    + + gm = Gain_mode of instrument(gm = 1,2,4) +
    + om = Offset_mode of instrument(om = 1,2,3,4,...,31) +
    + t = Optimal integration duration of observation in seconds + (function of ExposureDuration on labels in + milliseconds.) +
    + therm = Thermal background correction value +
    + thermShape = Thermal shape correction value (always 0.0) +
    + + + Clementine + + + + + clemnirnoise + clemnirclean + clemuvviscal + + + + + + Original Version (nircal.F) + + + Converted to Isis 3.0 + + + Removed unused Thermal Shape Correction Parameter. + Fixed table lookup problem, and Radiometry group + + + Fixed bugs in XML file, added an example, added more data to Radiometry group. + + Altered the output + cube's BandBin group, changing the Keyword "Name" back to "FilterName". + + + Removed references to CubeInfo + + + + + + + cube + input + + Input file name + + + Specify the input file to be corrected. + + + *.cub + + + + + cube + output + real + + Output file name + + + Specify the output file. The result will be the + radiometrically corrected image. + + + *.cub + + + + + cube + input + Automatic + + Array of flat-field coefficients + + + This parameter allows the user to use an alternate + flat-field file. In most cases, the default should be used + for this parameter to indicate the derived flat-field file + is to be used. + + + *.cub + + + + + cube + input + Automatic + + Array of orbit dependent flat-field coefficients + + + The parameter allows the user to use an alternate orbit + dependent flat-field file. In most cases, the default should + be used for this paramter. + + + *.cub + + + + + cube + input + Automatic + + Array of empirical additive flat-field coefficients + + + The parameter allows the user to use an alternate emperical + additive flat-field file. In most cases, the default + should be used for this parameter. + + + *.cub + + + + + cube + input + Automatic + + Dark current file + + + This parameter allows the user to use an alternate + dark current file. In most cases, the default should be + used for this parameter to indicate the derived dark file + is to be used. The name of the derived dark current file + is "$ISIS3DATA/clementine1/calibration/nir/dark_nir.cub" + When InstrumentCompressionType = "CLEM-JPEG-0" the name + of the derived dark current file is + "$ISIS3DATA/clementine1/calibration/nir/dark_nir_cmp0.cub" + + + *.cub + + + + + cube + input + Automatic + + Bias correction file + + + This parameter allows the user to use an alternate + bias file. In most cases, the default should be + used for this parameter to indicate the derived bias file + is to be used. The name of the derived bias file + is "$ISIS3DATA/clementine1/calibration/nir/bias_nir.cub" + When InstrumentCompressionType = "CLEM-JPEG-0" the name + of the derived bias file is + "$ISIS3DATA/clementine1/calibration/nir/bias_nir_cmp0.cub" + + + *.cub + + + + + cube + input + Automatic + + Bad pixel file + + + This parameter allows the user to use an alternate + bad pixel file. In most cases, the default should be + used for this parameter to indicate the derived + bad pixel file is to be used. The name of the derived + bad pixel file is "$ISIS3DATA/clementine1/calibration/nir/badpix_nir.v3.cub" + When InstrumentCompressionType = "CLEM-JPEG-0" the name + of the derived bad pixel file is + "$ISIS3DATA/clementine1/calibration/nir/badpix_nir_cmp0.v3.cub" + + + *.cub + + + + + + + boolean + + true + + + Convert bad pixels to null + + + This option allows the user to decide whether to keep or remove known bad pixels. + When enabled, DN values of 0.0 in the bad pixel cube are known bad pixels that will be set to NULL in the output. + + + + + boolean + + true + + + Apply thermal background correction + + + Apply thermal background correction + + + + + double + + 1.0 + + + Absolute coefficient + + + Absolute coefficient + + + + + double + + 240.0 + + + High saturation value + + + DN values greater than this value in the input cube will be set to HRS. + + + + + + + + + Calibrating a cube to radiance values using nircal + + + Calibrating a cube to radiance values using nircal + + + + + nircal FROM=lna3056k.cub TO=lna3056k.cal.cub + + + In this example nircal will calibrate lna3056k.cub. + + + + + + + Calibrate lna3056k.cub + In this example clemnircal will calibrate lna3056k.cub using the defaults. + + + + + + + + Image before correction + This is the input image lna3056k.cub before being corrected with clemnircal. + + FROM + + + + + + Image after correction + This is the input image lna3056k.cub after being corrected with clemnircal. There are scattered NULL pixels because BPFLAG was true, so all known bad pixels were automatically set to NULL. + + TO + + + + + +
    diff --git a/isis/src/clementine/apps/clemnircal/tsts/Makefile b/isis/src/clementine/apps/clemnircal/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/clementine/apps/clemnircal/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/clementine/apps/clemnircal/tsts/default/Makefile b/isis/src/clementine/apps/clemnircal/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b46498cff34855960586cdd640e2dc4bc3c416d3 --- /dev/null +++ b/isis/src/clementine/apps/clemnircal/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = clemnircal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/lna3056k.cub \ + to=$(OUTPUT)/clemnircalTruth.cub > /dev/null; diff --git a/isis/src/clementine/apps/clemnirclean/Makefile b/isis/src/clementine/apps/clemnirclean/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/clementine/apps/clemnirclean/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/clementine/apps/clemnirclean/assets/images/clemnircleanGUI.jpg b/isis/src/clementine/apps/clemnirclean/assets/images/clemnircleanGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5db2691f7905d0af51cc38673d7f5a9bdf8effe3 Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/images/clemnircleanGUI.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.box1.jpg b/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.box1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..80cf358d85d70ea88a51acbc770e299236c7d70b Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.box1.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.box2.jpg b/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.box2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b41b04f08ef6ef49e51a1e3b3d44cf0dadc3746c Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.box2.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.box3.jpg b/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.box3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6c798f6cfaf7922fd131d579d043fa1e7b40169b Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.box3.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.box4.jpg b/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.box4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0bd1f159c39feadfcbfe74892879dade4557364e Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.box4.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.cal.jpg b/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.cal.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d2216c54f6c52e9066ca0b0b4f9a683d05efaa73 Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.cal.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.jpg b/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.jpg new file mode 100644 index 0000000000000000000000000000000000000000..74ebd3e4847627b9a9bfcb90b7233de14a6970c4 Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/images/lne4885r.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/thumbs/clemnircleanGUI.jpg b/isis/src/clementine/apps/clemnirclean/assets/thumbs/clemnircleanGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6eb73b485ef13f004cf0ef4b4eda93525570615a Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/thumbs/clemnircleanGUI.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.box1.jpg b/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.box1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c7a481461f4f12ea01e43c67d951f23e46c323a6 Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.box1.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.box2.jpg b/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.box2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8aa7c0e920acbc505417a6cf1db492a5074c7693 Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.box2.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.box3.jpg b/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.box3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b69039443c207a6cbad466e797eb60b2ffc3745d Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.box3.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.box4.jpg b/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.box4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9d222237999b7ec3fb70ee144390b5eaaf1bc515 Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.box4.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.cal.jpg b/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.cal.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c3059d56affa1f38df77bb8f41fe9876f093a6b3 Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.cal.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.jpg b/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.jpg new file mode 100644 index 0000000000000000000000000000000000000000..795d591e2a325c5b722a5eda3153c2afd742436d Binary files /dev/null and b/isis/src/clementine/apps/clemnirclean/assets/thumbs/lne4885r.jpg differ diff --git a/isis/src/clementine/apps/clemnirclean/clemnirclean.cpp b/isis/src/clementine/apps/clemnirclean/clemnirclean.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6e543fe42ff8d926bc44545f3393251176c31af6 --- /dev/null +++ b/isis/src/clementine/apps/clemnirclean/clemnirclean.cpp @@ -0,0 +1,65 @@ +#include "Isis.h" +#include "Application.h" +#include "Filename.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + + // Open the input cube and get filename of output cube + UserInterface &ui = Application::GetUserInterface(); + Filename infname = ui.GetFilename("FROM"); + string name = infname.Basename(); + Filename outfname = ui.GetFilename("TO"); + string outpath = outfname.Path() + "/"; + string outname = infname.Basename(); + bool rmv = ui.GetBoolean("REMOVE"); + + // Run noisefilter on the cube and replace with nulls, 3x3 boxcar + string inFile = ui.GetFilename("FROM"); + Filename temp1; + temp1.Temporary(outname+".box1_","cub"); + string outFile = outpath+temp1.Name(); + string parameters = "FROM=" + inFile + " TO=" + outFile + + " toldef=stddev tolmax=1.25 tolmin=1.25 samples=3 lines=3 replace=null"; + Isis::iApp ->Exec("noisefilter",parameters); + + // Run lowpass on the cube using outside filter, 3x3 boxcar + inFile = outFile; + Filename temp2; + temp2.Temporary(outname+".box2_","cub"); + outFile = outpath+temp2.Name(); + parameters = "FROM=" + inFile + " TO=" + outFile + + " samples=3 lines=3 filter=outside"; + Isis::iApp ->Exec("lowpass", parameters); + if (rmv) remove(inFile.c_str()); + + // Run lowpass on the cube using outside filter, 3x3 boxcar + inFile = outFile; + Filename temp3; + temp3.Temporary(outname+".box3_","cub"); + outFile = outpath+temp3.Name(); + + parameters = "FROM=" + inFile + " TO=" + outFile + + " samples=3 lines=3 filter=outside"; + Isis::iApp ->Exec("lowpass",parameters); + if (rmv) remove(inFile.c_str()); + + // Run noisefilter on the cube and replace with avg, 3x3 boxcar + inFile = outFile; + Filename temp4; + temp4.Temporary(outname+".box4_","cub"); + outFile = outpath+temp4.Name(); + parameters = "FROM=" + inFile + " TO=" + outFile + + " toldef=stddev tolmax=1.5 tolmin=1.5 samples=3 lines=3 nullisnoise=yes"; + Isis::iApp -> Exec("noisefilter",parameters); + if (rmv) remove(inFile.c_str()); + + // Run lowpass on the cube using outside filter, 5x5 boxcar + inFile = outFile; + parameters = "FROM=" + inFile + " TO=" + outfname.Expanded() + + " samples=5 lines=5 filter=outside"; + Isis::iApp ->Exec("lowpass",parameters); + if (rmv) remove(inFile.c_str()); +} diff --git a/isis/src/clementine/apps/clemnirclean/clemnirclean.xml b/isis/src/clementine/apps/clemnirclean/clemnirclean.xml new file mode 100644 index 0000000000000000000000000000000000000000..f07eccc28f8a2cc0f1f7ab831fd3102619e17e84 --- /dev/null +++ b/isis/src/clementine/apps/clemnirclean/clemnirclean.xml @@ -0,0 +1,192 @@ + + + + + Clean-up of Clementine NIR Images + + + + This program will take a Clementime calibrated cube and clean up null pixels and noise. + + + + Clementine + + + + + noisefilter + lowpass + + + + + + Original version Isis2: perl script nir2db.pl + + + Converted to Isis3 from Isis2 + + + + + + + cube + input + + Input cube to be cleaned + + + The cube to be cleaned. The cube will be ran through a series of filters to + remove noise. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the cleaned data. + + + *.cub + + + + + + boolean + + Remove intermediate files + + + Option to remove or leave intermediate cube files made by the application + + + TRUE + + + + + + + + Using clemnirclean + + + The use of clemnircal creates a clean NIR image. It creates 4 images in intermediate steps. + + + + from= lne4885r.cub + to=lne4885r.cal.cub + remove=no + + + This example shows the use of clemnircal to clean up NIR images + + + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to leave temporary images + + + + + + + + + + + + Input image before the filter. + + + This is the image after it was run through clemnircal. + + + FROM + + + + + + + + + Output image after the first boxcar filter was applied + + + Does a 3x3 noisefilter with null replace. + + + + + + + Output image after the second boxcar filter was applied + + + Does a 3x3 lowpass with outside filter. + + + + + + + Output image after the third boxcar filter was applied + + + Does a 3x3 lowpass with outside filter. + + + + + + + Output image after the fourth boxcar filter was applied + + + Does a 3x3 noisefilter with average replace. + + + + + + + Final output image after the all boxcar filters were applied + + + Does a 5x5 lowpass with outside filter. + + + TO + + + + + + diff --git a/isis/src/clementine/apps/clemnirclean/tsts/Makefile b/isis/src/clementine/apps/clemnirclean/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/clementine/apps/clemnirclean/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/clementine/apps/clemnirclean/tsts/default/Makefile b/isis/src/clementine/apps/clemnirclean/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c5752067079aacaf2fdc04df03278490e85ae925 --- /dev/null +++ b/isis/src/clementine/apps/clemnirclean/tsts/default/Makefile @@ -0,0 +1,14 @@ +APPNAME = clemnirclean + +lne4885r.cal.box1_100000.cub.TOLERANCE = 0.0000001 +lne4885r.cal.box2_100000.cub.TOLERANCE = 0.0000001 +lne4885r.cal.box3_100000.cub.TOLERANCE = 0.0000001 +lne4885r.cal.box4_100000.cub.TOLERANCE = 0.0000001 +lne4885r.truth.cub.TOLERANCE = 0.0000001 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/lne4885r.cal.cub \ + TO=$(OUTPUT)/lne4885r.truth.cub remove=no\ + > /dev/null; diff --git a/isis/src/clementine/apps/clemnirnoise/Makefile b/isis/src/clementine/apps/clemnirnoise/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/clementine/apps/clemnirnoise/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/clementine/apps/clemnirnoise/assets/images/clemnirnoiseGUI.jpg b/isis/src/clementine/apps/clemnirnoise/assets/images/clemnirnoiseGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..50ecc695fe31f0a44c40247ea0e1b8f1f32ff318 Binary files /dev/null and b/isis/src/clementine/apps/clemnirnoise/assets/images/clemnirnoiseGUI.jpg differ diff --git a/isis/src/clementine/apps/clemnirnoise/assets/images/lne4885r.jpg b/isis/src/clementine/apps/clemnirnoise/assets/images/lne4885r.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3e496d402435a0309960538b2fd9eab0d5a764d3 Binary files /dev/null and b/isis/src/clementine/apps/clemnirnoise/assets/images/lne4885r.jpg differ diff --git a/isis/src/clementine/apps/clemnirnoise/assets/images/lne4885r.noise.jpg b/isis/src/clementine/apps/clemnirnoise/assets/images/lne4885r.noise.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9cf2c6f773133895b6c5552a13819b9dcf00be68 Binary files /dev/null and b/isis/src/clementine/apps/clemnirnoise/assets/images/lne4885r.noise.jpg differ diff --git a/isis/src/clementine/apps/clemnirnoise/assets/thumbs/clemnirnoiseGUI.jpg b/isis/src/clementine/apps/clemnirnoise/assets/thumbs/clemnirnoiseGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..49b7bf0d777335502d454393e33f0cf3700db4a1 Binary files /dev/null and b/isis/src/clementine/apps/clemnirnoise/assets/thumbs/clemnirnoiseGUI.jpg differ diff --git a/isis/src/clementine/apps/clemnirnoise/assets/thumbs/lne4885r.jpg b/isis/src/clementine/apps/clemnirnoise/assets/thumbs/lne4885r.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5a9152dfc4c03555013dfa2f4ba87915c30f6a74 Binary files /dev/null and b/isis/src/clementine/apps/clemnirnoise/assets/thumbs/lne4885r.jpg differ diff --git a/isis/src/clementine/apps/clemnirnoise/assets/thumbs/lne4885r.noise.jpg b/isis/src/clementine/apps/clemnirnoise/assets/thumbs/lne4885r.noise.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a9e37b45c7544696033fe36f7f82472841f0c5ae Binary files /dev/null and b/isis/src/clementine/apps/clemnirnoise/assets/thumbs/lne4885r.noise.jpg differ diff --git a/isis/src/clementine/apps/clemnirnoise/clemnirnoise.cpp b/isis/src/clementine/apps/clemnirnoise/clemnirnoise.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c0195ee0cc6b48ec31d8b175e11297cb9b57c7e0 --- /dev/null +++ b/isis/src/clementine/apps/clemnirnoise/clemnirnoise.cpp @@ -0,0 +1,96 @@ +#include "Isis.h" + +#include + +#include "ProcessByBrick.h" +#include "Pixel.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void NoiseFilter(Buffer &in, Buffer &out); + +void IsisMain() { + // We will be processing by brick + ProcessByBrick p; + // UserInterface &ui = Application::GetUserInterface(); + + // Setup the input and output cubes + Cube *icube = p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + + // Start the processing + p.SetBrickSize(icube->Samples(), icube->Lines(), 1); + p.StartProcess(NoiseFilter); + p.EndProcess(); +} + +void NoiseFilter(Buffer &in, Buffer &out) { + double TOL1 = 9.0; + double TOL2 = 3.0; + int NPOS = 100; + double diff; + double diffSum; + double diffAvg; + int dCount; + int LCOUNT = 0; + + for(int il = 0; il < in.LineDimension();il++){ + for(int is = 0; is < in.SampleDimension();is++){ + int index = in.SampleDimension() * il + is; + out[index] = in[index]; + } + // Determine if a noise pattern exists samples 2,6,10,14,... + diffSum = 0.0; + dCount = 0; + for(int is = 1; is < in.SampleDimension()-4;is+=4){ + int index = in.SampleDimension() * il + is; + if(!Pixel::IsSpecial(in[index]) && + !Pixel::IsSpecial(in[index]) && + !Pixel::IsSpecial(in[index])){ + diff = abs((in[index]-in[index-1]) + (in[index]-in[index+1])); + diffSum += diff; + dCount += 2; + } + } + diffAvg = 0.0; + if (dCount > 1) { + diffAvg = diffSum / dCount; + } + if (diffAvg > TOL1){ + LCOUNT++; + for(int is = 1; is < in.SampleDimension()-4;is+=4){ + int index = in.SampleDimension() * il + is; + out[index] = Isis::Null; + } + } + + // Determine if a noise pattern exists samples 4,8,12,16,... + diffSum = 0.0; + dCount = 0; + for(int is = 4; is < in.SampleDimension()-4;is+=4){ + int index = in.SampleDimension() * il + is; + if(!Pixel::IsSpecial(in[index]) && + !Pixel::IsSpecial(in[index]) && + !Pixel::IsSpecial(in[index])){ + diff = (in[index]-in[index-1]) + (in[index]-in[index+1]); + if(diff < 0.0){ + diffSum += diff; + dCount += 2; + } + } + } + diffAvg = 0.0; + if (dCount > 1) { + diffAvg = diffSum / dCount; + } + if (diffAvg > TOL2 && dCount > NPOS){ + LCOUNT++; + for(int is = 4; is < in.SampleDimension()-4;is+=4){ + int index = in.SampleDimension() * il + is; + out[index] = Isis::Null; + } + } + } +} diff --git a/isis/src/clementine/apps/clemnirnoise/clemnirnoise.xml b/isis/src/clementine/apps/clemnirnoise/clemnirnoise.xml new file mode 100644 index 0000000000000000000000000000000000000000..9c7e20162a1a6c38e77e59792b2c1bd0b01e7b18 --- /dev/null +++ b/isis/src/clementine/apps/clemnirnoise/clemnirnoise.xml @@ -0,0 +1,146 @@ + + + + + identifiy and remove NIR noise pattern + + + + + +
    +

    + + WARNING + +

    +

    + For the clementine mosaic in Isis2, this program was run before calibration. There is concern this + application's systematic noise removal eliminates a substantial amount of valid data. +

    +
    +

    + The program removes a bothersome noise pattern periodically + found in Clementine NIR camera imaging. The noise pattern + is found in samples 2,6,10,14,18.... found on some or all lines + in a NIR image. The program will recognize that the + noise pattern exists and then will simply set these sample + positions to "null" if the pattern is found. +

    +
    + + + + + Clementine + + + + + Original Version: clemnirns.F + + + Converted to Isis 3 + + + Removed references to CubeInfo + + + + + + + + + cube + input + + Input cube + + + Input cube file name + + *.cub + + + cube + output + + Output cube + + + Output cube file name + + *.cub + + + + + + + Using clemnirnoise + + + The use of clemnirnoise detects certain patterns of noise and replaces the noise with nulls. + + + + from= lne4885r.cub + to=lne4885r.noise.cub + + + This example shows the use of clemnirnoise to detect and remove systematic noise. + + + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to leave temporary images + + + + + + + + + + + + Input image before the filter. + + + This is the image after ingestion from clem2isis + + + FROM + + + + + + + + + Final output image after the all boxcar filters were applied + + + Looks for noise in specific patterns on lines and removes it if detected. + + + TO + + + + +
    diff --git a/isis/src/clementine/apps/clemnirnoise/tsts/Makefile b/isis/src/clementine/apps/clemnirnoise/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/clementine/apps/clemnirnoise/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/clementine/apps/clemnirnoise/tsts/default/Makefile b/isis/src/clementine/apps/clemnirnoise/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..90ba27db24f586745f2917f70cea885a4268f260 --- /dev/null +++ b/isis/src/clementine/apps/clemnirnoise/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = clemnirnoise + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/lne4885r.cub \ + TO=$(OUTPUT)/lne4885r.truth.cub \ + > /dev/null; + diff --git a/isis/src/clementine/apps/clemuvviscal/Makefile b/isis/src/clementine/apps/clemuvviscal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/clementine/apps/clemuvviscal/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/clementine/apps/clemuvviscal/assets/images/TempCorrection.jpg b/isis/src/clementine/apps/clemuvviscal/assets/images/TempCorrection.jpg new file mode 100644 index 0000000000000000000000000000000000000000..061bbdc325c2f3bc30032e24091beb06539dc605 Binary files /dev/null and b/isis/src/clementine/apps/clemuvviscal/assets/images/TempCorrection.jpg differ diff --git a/isis/src/clementine/apps/clemuvviscal/assets/images/after.jpg b/isis/src/clementine/apps/clemuvviscal/assets/images/after.jpg new file mode 100644 index 0000000000000000000000000000000000000000..357f76741ceb222665fcaf9c88759c295446460b Binary files /dev/null and b/isis/src/clementine/apps/clemuvviscal/assets/images/after.jpg differ diff --git a/isis/src/clementine/apps/clemuvviscal/assets/images/before.jpg b/isis/src/clementine/apps/clemuvviscal/assets/images/before.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eafba16a5427a04a8d0ddddbf0436f07521aaf33 Binary files /dev/null and b/isis/src/clementine/apps/clemuvviscal/assets/images/before.jpg differ diff --git a/isis/src/clementine/apps/clemuvviscal/assets/thumbs/TempCorrection.jpg b/isis/src/clementine/apps/clemuvviscal/assets/thumbs/TempCorrection.jpg new file mode 100644 index 0000000000000000000000000000000000000000..57fe266586a29e7859661d24da3813a1032401d7 Binary files /dev/null and b/isis/src/clementine/apps/clemuvviscal/assets/thumbs/TempCorrection.jpg differ diff --git a/isis/src/clementine/apps/clemuvviscal/assets/thumbs/after.jpg b/isis/src/clementine/apps/clemuvviscal/assets/thumbs/after.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4b4733fab5de1b01b044329d2f2d9cda79448d5a Binary files /dev/null and b/isis/src/clementine/apps/clemuvviscal/assets/thumbs/after.jpg differ diff --git a/isis/src/clementine/apps/clemuvviscal/assets/thumbs/before.jpg b/isis/src/clementine/apps/clemuvviscal/assets/thumbs/before.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6e3c0e9a2e5a05ce7f928155b771bac3b0300b77 Binary files /dev/null and b/isis/src/clementine/apps/clemuvviscal/assets/thumbs/before.jpg differ diff --git a/isis/src/clementine/apps/clemuvviscal/clemuvviscal.cpp b/isis/src/clementine/apps/clemuvviscal/clemuvviscal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa9ec2df555f9de550ee620faefc19367c23bd3f --- /dev/null +++ b/isis/src/clementine/apps/clemuvviscal/clemuvviscal.cpp @@ -0,0 +1,327 @@ +#include "Isis.h" + +#include + +#include "ProcessByLine.h" +#include "Pixel.h" +#include "Camera.h" +#include "iException.h" +#include "Table.h" + +using namespace std; +using namespace Isis; + +bool conv; +double dcconst; +bool useDcconst; +double focalPlaneTemp; +double exposureDuration; +int offsetModeID; +double gain; +double avgFF; +double cr; +double dist; +double C2; +double correctedExposureDuration; + +const double ACO = 1.062; +const double BCO = -0.1153E-02; +const double CCO = 0.6245E-05; +const double DCO = -0.1216E-07; +const double C3 = 7.13; +const double C4 = -8.177; // Post-readout offset +const double C5 = 15.56; +const double DT = .00068; + +void UvVisCal(std::vector< Isis::Buffer* > &in, std::vector< Isis::Buffer* > &out); +void FixTemp(int); + +void IsisMain() { + // We will be processing by line + ProcessByBrick p; + UserInterface &ui = Application::GetUserInterface(); + + // Use the def file for filter constants + Pvl uvvisDef("$clementine1/calibration/uvvis/uvvis.def"); + + // Setup the input and output cubes + Cube *icube = p.SetInputCube("FROM"); + + Cube *dccube; + if (ui.WasEntered("DCFILE")) { + dccube = p.SetInputCube("DCFILE"); + } else { + string dcfileloc = "$clementine1/calibration/uvvis/"; + dcfileloc += "dark_5_15_96.cub"; + CubeAttributeInput cubeAtt; + dccube = p.SetInputCube(dcfileloc, cubeAtt); + } + + iString filter = (string)(icube->GetGroup("BandBin"))["FilterName"]; + filter = filter.DownCase(); + + Cube *ffcube; + if (ui.WasEntered("FFFILE")) { + ffcube = p.SetInputCube("FFFILE"); + } else { + // compute default fffile + double compressRatio = (icube->GetGroup("Instrument"))["EncodingCompressionRatio"]; + + // check to see if cube is compressed or uncompressed + if (compressRatio == 1.0) { + string fffileLoc = "$clementine1/calibration/uvvis/"; + fffileLoc += "lu" + filter + "_uncomp_flat_long.cub"; + CubeAttributeInput cubeAtt; + ffcube = p.SetInputCube(fffileLoc, cubeAtt); + } else { + string fffileLoc = "$clementine1/calibration/uvvis/"; + fffileLoc += "lu" + filter + "_comp_flat_long.cub"; + CubeAttributeInput cubeAtt; + ffcube = p.SetInputCube(fffileLoc, cubeAtt); + } + } + + Cube *ocube = p.SetOutputCube("TO"); + + avgFF = uvvisDef.FindGroup("Filter"+filter.UpCase())["AVGFF"]; + cr = uvvisDef.FindGroup("Filter"+filter.UpCase())["CO"]; + gain = uvvisDef.FindGroup(iString("GainModeID")+iString(icube->GetGroup("Instrument")["GainModeID"][0]))["GAIN"]; + + useDcconst = ui.WasEntered("DCCONST"); + if (useDcconst) { + dcconst = ui.GetDouble("DCCONST"); + } else { + dcconst = 0.0; + } + + conv = ui.GetBoolean("CONV"); + exposureDuration = icube->GetGroup("Instrument")["ExposureDuration"]; + offsetModeID = icube->GetGroup("Instrument")["OffsetModeID"]; + + if (((string)icube->GetGroup("Instrument")["FocalPlaneTemperature"]).compare("UNK") == 0) { + //if FocalPlaneTemp is unknown set it to zero + focalPlaneTemp = 0.0; + } else { + focalPlaneTemp = icube->GetGroup("Instrument")["FocalPlaneTemperature"]; + } + + Camera *cam = icube->Camera(); + bool camSuccess = cam->SetImage(icube->Samples()/2,icube->Lines()/2); + + if(!camSuccess) { + throw iException::Message(iException::Camera, "Unable to calculate the Solar Distance for this cube.", _FILEINFO_); + } + + dist = cam->SolarDistance(); + + // If temp. correction set to true, or focal plane temp is zero then use temperature correction + if (ui.GetBoolean("TCOR") || abs(focalPlaneTemp) <= DBL_EPSILON) { + // Temperature correction requires the use of the mission phase + // (PRELAUNCH, EARTH, LUNAR) and the product ID. + string productID = (string)(icube->GetGroup("Archive")["ProductID"]); + char missionPhase = ((string)((icube->GetGroup("Archive"))["MissionPhase"])).at(0); + string n1substring(productID.substr(productID.find('.')+1, productID.length()-1)); + string n2substring(productID.substr(4, productID.find('.')-1)); + int n1 = atoi( n1substring.c_str() ); + int n2 = atoi( n2substring.c_str() ); + int phase = 0; + + if (missionPhase == 'L') { + phase = 0; + } else if (missionPhase == 'E') { + phase = 1; + } else if (missionPhase == 'P') { + phase = 2; + } else { + throw iException::Message(iException::Pvl, "Invalid Mission Phase", _FILEINFO_); + } + + // This formula makes the primary search critera the original product ID's extension, + // the secondary search criteria the mission phase and finally the numerical part of the + // original product ID. + int imageID = (100000 * n1) + (10000 * phase) + n2; + FixTemp(imageID); + } + + if (focalPlaneTemp <= 0.0) { + focalPlaneTemp = 272.5; + } + + // Start the processing + p.SetBrickSize(icube->Samples(), icube->Lines(), 1); + p.StartProcess(UvVisCal); + + // Add the radiometry group + PvlGroup calgrp("Radiometry"); + calgrp += PvlKeyword("FlatFieldFile", ffcube->Filename()); + + if(ui.GetString("DARKCURRENT").compare("DCFILE") == 0) { + calgrp += PvlKeyword("DarkCurrentFile", dccube->Filename()); + } + else { + calgrp += PvlKeyword("DarkCurrentConstant", dcconst); + } + + calgrp += PvlKeyword("CorrectedFocalPlaneTemp", focalPlaneTemp); + calgrp += PvlKeyword("C1", avgFF); + calgrp += PvlKeyword("C2", C2); + calgrp += PvlKeyword("C3", C3); + calgrp += PvlKeyword("C4", C4); + calgrp += PvlKeyword("C5", C5); + calgrp += PvlKeyword("CR", cr); + calgrp += PvlKeyword("FrameTransferTimePerRow", cr); + calgrp += PvlKeyword("Gain", gain); + calgrp += PvlKeyword("CorrectedExposureDuration", correctedExposureDuration); + calgrp += PvlKeyword("ConvertToRadiance", conv); + + calgrp += PvlKeyword("ACO", ACO); + calgrp += PvlKeyword("BCO", BCO); + calgrp += PvlKeyword("CCO", CCO); + calgrp += PvlKeyword("DCO", DCO); + + ocube->PutGroup(calgrp); + p.EndProcess(); +} + +void UvVisCal(std::vector< Isis::Buffer* > &in, std::vector< Isis::Buffer* > &out) { +#define INPUT_CUBE (*in[0]) +#define DC_CUBE (*in[1]) +#define FF_CUBE (*in[2]) +#define OUTPUT_CUBE (*out[0]) + + C2 = 0.003737 * exp(0.0908 * (focalPlaneTemp - 273.15)); + correctedExposureDuration = exposureDuration + 0.0494; + + double dc = 0.0; + bool valid = false; + double *sum, *ro; + + sum = new double[INPUT_CUBE.SampleDimension()]; + ro = new double[INPUT_CUBE.SampleDimension()]; + + for (int iSample = 0; iSample < INPUT_CUBE.SampleDimension(); iSample++) { + ro[iSample] = 0.0; + sum[iSample] = 0.0; + + for (int iLine = 0; iLine < INPUT_CUBE.LineDimension(); iLine ++) { + valid = false; + int index = INPUT_CUBE.SampleDimension() * iLine + iSample; + + if (Pixel::IsSpecial(INPUT_CUBE[index])) { + OUTPUT_CUBE[index] = INPUT_CUBE[index]; + + if (Pixel::IsHigh(INPUT_CUBE[index])) { + sum[iSample] += 255; + } + } else { + if (Pixel::IsSpecial(FF_CUBE[index])) { //check DCFILE + OUTPUT_CUBE[index] = Isis::Null; + sum[iSample] += INPUT_CUBE[index]; + } else { + valid = true; + if (!useDcconst) { + dc = DC_CUBE[index]; + } else { + dc = dcconst; + } + } + } + + if (valid) { + //Global Offset Corrections + double step1_dn = INPUT_CUBE[index] - (C4 * offsetModeID) - C5; + //Gain Correction + double step2_dn = step1_dn / gain; + //Pixel dependent dark current correction + double step3_dn = step2_dn - (dc + C3); + //Non-linearity correction + double xmul = ACO + (BCO * step3_dn) + (CCO * pow(step3_dn, 2)) + (DCO*pow(step3_dn, 3)); + double corstep3_dn = step3_dn * xmul; + //Tempurature-dependent offset correction + double rotim = 60.05 + 0.05 * iLine; + double u = correctedExposureDuration + rotim; + double step4_dn = corstep3_dn - (C2 * u); + OUTPUT_CUBE[index] = step4_dn; + sum[iSample] += step4_dn; + } + } + + ro[iSample] = sum[iSample] * DT / (correctedExposureDuration + (288.0 * DT)); + } + + for (int iLine = 0; iLine < INPUT_CUBE.LineDimension(); iLine ++) { + for (int iSample = 0; iSample < INPUT_CUBE.SampleDimension(); iSample++) { + valid = false; + int index = INPUT_CUBE.SampleDimension() * iLine + iSample; + if (!Pixel::IsSpecial(INPUT_CUBE[index])) { + if (Pixel::IsSpecial(FF_CUBE[index])) { //check FFFILE + OUTPUT_CUBE[index] = Isis::Null; + } else { + valid = true; + } + + if (valid) { + // Frame transfer correction + double step5_dn = OUTPUT_CUBE[index] - ro[iSample]; + // Flat-field and exposure time normalization (Units=counts/ms) + double step6_dn = step5_dn / (FF_CUBE[index] * correctedExposureDuration); + // Normalize to sun-moon distance of 1AU + double step7_dn = step6_dn * pow(dist, 2); + // Conversion to radience (L=mW/sr-cm*cm) + double L = step7_dn / avgFF; + // Conversion to reflectance + if (conv) { + OUTPUT_CUBE[index] = step7_dn * cr; + } else { + OUTPUT_CUBE[index] = L; + } + } + } + } + } + + delete sum; + delete ro; +} + +/* + * In the ISIS2 Fortran we noticed FIXTEMP uses a REAL*4 to store the RIMGID. + * This results in the last digit being lost precision. The table that + * it looks in for data is also store as a REAL*4 again resulting + * in a loss in precision. We believe this makes the lookup table inaccurate. + */ +void FixTemp(int imgID){ + string table = "$clementine1/calibration/uvvis/uvvisTemperature.tbl"; + Table t("FocalPlaneTemperatures", table); + float currID = t[0]["ImageID"]; + int currIndex = 0; + + do { + currID = t[currIndex]["ImageID"]; + currIndex ++; + } while ((imgID > currID) && (currIndex < t.Records())); + currIndex --; // Fixes an out-of-bounds segmentation fault + + // Make sure currIndex makes sense + if (currIndex < 0 || currIndex >= t.Records()) { + focalPlaneTemp = 0; + return; + } + + // Value too small - look up in the table and see if we're closer + if (currID < imgID) { + double diff = imgID - currID; + if ((currIndex + 1 < t.Records()) && abs((float)t[currIndex + 1]["ImageID"] - imgID) < diff) { + currIndex ++; + } + } + // Value too big - look down in the table and see if we're closer + else if (currID > imgID) { + double diff = currID - imgID; + if (currIndex - 1 >=0 && abs((float)t[currIndex - 1]["ImageID"] - imgID) < diff) { + currIndex --; + } + } + + focalPlaneTemp = (float)t[currIndex]["Temp"]; +} diff --git a/isis/src/clementine/apps/clemuvviscal/clemuvviscal.xml b/isis/src/clementine/apps/clemuvviscal/clemuvviscal.xml new file mode 100644 index 0000000000000000000000000000000000000000..7e8b7d8fc8d3793b93deaf85549b75c7b6397f96 --- /dev/null +++ b/isis/src/clementine/apps/clemuvviscal/clemuvviscal.xml @@ -0,0 +1,444 @@ + + + + + Radiometric correction of Clementine UV/VIS camera images + + + +This program performs radiometric corrections to images acquired by the +Clementine spacecraft UVVIS camera. It performs dark subtraction, +readout correction, non-linearity and flat field corrections and +gives the user the option of writing the output image values as radiance +values or as reflectance(I/F) values. +
    + +

    PLEASE NOTE: In the ISIS2 Fortran code the method FIXTEMP uses a REAL*4 (6 digits of accuracy) to + store the RIMGID (8 digits) which results in the last digits being lost. In the table that references RIMGID + the value is a REAL*4 again resulting in the same loss of precision; this makes the lookup table for temperature corrections inaccurate.

    +
    +
    + +ALGORITHM +
    +
    +
    + + +General algorithm applied to data for radiometric correction is +described below: +
    +
    + + +Step 1. Global Offset Correction +
    +
    + + Step1_DN = raw_DN - C4*OffsetModeID - C5 +
    + C4 = -8.177 +
    + C5 = 15.56 +
    +
    + +Step 2. Divide by gain +
    +
    + + Step2_DN = Step1_DN / g(GainModeID) +
    + g(GainModeID) +
    + g(1) = 1.0 +
    + g(2) = 2.907 +
    + g(4) = 6.906 +
    +
    + +Step 3. Dark current correction +
    +
    + + Step3_DN = Step2_DN - (DC + C3) +
    + C3 = 7.13 +
    +
    + + Non-linearity correction +
    +
    + + XMUL = ACO + BCO*Step3_DN + CCO*(Step3_DN**2) + DCO*(Step3_DN**3) +
    + + CorrectedStep3_DN = Step3_DN * XMUL +
    + + ACO = 1.062 +
    + BCO = -.1153E-02 +
    + CCO = .6245E-05 +
    + DCO = -.1216E-07 +
    +
    + +Step 4. Temperature-Dependent Offset Correction +
    +
    + + Step4_DN = CorrectedStep3_DN - C2 * u +
    + C2 = .003737 * exp(.0908*(T-273.15)) +
    + T = Corrected FocalPlaneTemperature (The value in the labels is + not correct. The value used is taken from an interpolated + set of values from ACT) +
    + u = t + readout time +
    + t = ExposureDuration + .0494 +
    + readout time = 60.05 + .05*(line # - 1) +
    +
    + +Step 5. Frame Transfer Correction +
    +
    + + Step5_DN = Step4_DN - ro +
    + ro = column_sum*dt/(t+288*dt) +
    + column_sum = sum of all 288 Step4_DN values +
    + dt = frame transfer time per row = .00068 +
    + t = ExposureDuration + .0494 +
    +
    + +Step 6. Flat-Field and Exposure Time Normalization +
    +
    + + Step6_DN = Step5_DN / (FF*t) +
    + FF = Filter-dependent flat-field +
    + t = ExposureDuration + .0494 +
    +
    + + The units of Step6_DN are now in counts/ms. +
    +
    + +Step 7. Normalize to Sun-Moon distance of 1 AU +
    +
    + + Step7_DN = Step6_DN * (SolarDistance in AU)**2 +
    +
    + +Step 8a. Conversion to 1 AU Relative Radiance +
    +
    + + L = Step7_DN / C1 ( L = Radiance in mW/sr-cm**2 ) +
    +
    + + CenterFilterWavelength C1 +
    + 415 nm 1.39 +
    + 750 nm 2.57 +
    + 900 nm 4.35 +
    + 950 nm 4.76 +
    + 1000 nm 2.77 +
    +
    + +Step 8b. Conversion to Reflectance +
    +
    + + R = Step7_DN * CR +
    +
    + + The following CR values were derived by Eric Eliason on 6/20/96. These + are slight improvements over Carle Pieter's values because Eric used + the most current flat files and Alfred McEwen's non-linearity + correction. For more information, see Eric's memo from 6/20/96. +
    +
    + + + CenterFilterWavelength CR +
    + 415 nm .021406 +
    + 750 nm .012266 +
    + 900 nm .010674 +
    + 950 nm .010831 +
    + 1000 nm .024271 +
    +
    + Note: if the cub has a compression ratio of 1.0 (the cube is uncompressed) + it will use difference flat field file. +
    + + + Clementine + + + + + clemnircal + + + + + + Original Version (uvviscal.F) + + + Converted to Isis 3.0 + + + Beautified and forcing output pixel type to real. + + + Cleaned up XML, added an example and added Radiometry group to labels of output cube. + + + Fixed problem with solar distance calculation + + + Changed TCOR paramter's default to TRUE + + + Altered the output cube's BandBin group, changing the Keyword "Name" back + to "FilterName". + + + Removed references to CubeInfo + + + Fixed a segmentation fault. + + + + + + + cube + input + + Input file name + + + Specify the input file to be corrected. + + + *.cub + + + + + cube + output + + Output file name + + + Specify the output file. The result will be the + radiometrically corrected image. The output values can + either be output as absolute radiance or converted to + reflectance (I/F) values. + + + *.cub + + real + + + + + + boolean + + Convert to I/F reflectance + + + This option allows the output values to be written as + absolute radiance or converted to reflectance values (I/F). + + + true + + + + + boolean + + Use temperature correction + + + This option defines whether or not to use temperature correction. + If disabled, the focal plane temperature read from the labels is used (if it is not equal to zero, otherwise temperature correction is used anyways). + When TCOR is enabled, the temperature read from the labels is disregarded and a table is searched based on the orbit number and mission phasederived from + the ProductID stored in the labels. + + + true + + + + + string + Dark current data source + + This option allows the user to input a constant value for the dark current, or alternatively a cube file with dark current values (default). + + DCFILE + + + + + + + + double + + Dark current constant + + + This constant will replace the array of dark current + coefficients in the derived dark current file. In most + cases, the default should be used for this parameter to + indicate the derived dark current file is to be used. + + + + + cube + input + Automatic + Dark current file + + This parameter allows the user to use an alternate dark + current file. In most cases, the default should be used for + this parameter to indicate the derived dark current file is + to be used. The name of the derived dark current file is + $ISIS3DATA/clementine1/calibration/uvvis/dark_5_15_96.cub. + + + *.cub + + + + + + cube + input + Automatic + + Array of flat-field coefficients + + + This parameter allows the user to use an alternate + flat-field file. In most cases, the default should be used + for this parameter to indicate the derived flat-field file + is to be used. There is a different version of the flat + file for compressed and uncompressed images. The name of the + derived flat-field file is + $ISIS3DATA/clementine1/calibration/uvvis/lu[filter]_[un]comp_flat_long.cub. + An example for a compressed B filter image is + $ISIS3DATA/clementine1/calibration/uvvis/lub_comp_flat_long.cub. + + + *.cub + + + + + + + + + Calibrating a cube to I/F values using temperature correction + + + Calibrating a cube to I/F values using temperature correction + + + + + clemuvviscal FROM=lua1841h.cub TO=lua1841h.cal.cub TCOR=TRUE + + + In this example clemuvviscal will calibrate lua1841h.cub using temperature correction. + + + + + + + Calibrate lua1841h.cub using temperature correction + In this example clemuvviscal will calibrate lua1841h.cub using temperature correction. + + + + + + + + Image before correction + This is the input image lua1841h.cub before being corrected with clemuvviscal. + + FROM + + + + + + Image after correction + This is the input image lua1841h.cub after being corrected with clemuvviscal. The values in this cube are all I/F because CONV was set to true by default. + + TO + + + + + +
    diff --git a/isis/src/clementine/apps/clemuvviscal/tsts/Makefile b/isis/src/clementine/apps/clemuvviscal/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/clementine/apps/clemuvviscal/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/clementine/apps/clemuvviscal/tsts/filters/Makefile b/isis/src/clementine/apps/clemuvviscal/tsts/filters/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0d84d3a2b743d44dee36deca2f0dd35877ba4dfc --- /dev/null +++ b/isis/src/clementine/apps/clemuvviscal/tsts/filters/Makefile @@ -0,0 +1,21 @@ +APPNAME = clemuvviscal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/lua1841h.cub \ + TO=$(OUTPUT)/lua1841h.truth.cub TCOR=true\ + > /dev/null; + $(APPNAME) FROM=$(INPUT)/lub0008e.cub \ + TO=$(OUTPUT)/lub0008e.truth.cub TCOR=true\ + > /dev/null; + $(APPNAME) FROM=$(INPUT)/luc0890d.cub \ + TO=$(OUTPUT)/luc0890d.truth.cub TCOR=true\ + > /dev/null; + $(APPNAME) FROM=$(INPUT)/lud0917d.cub \ + TO=$(OUTPUT)/lud0917d.truth.cub TCOR=true\ + > /dev/null; + $(APPNAME) FROM=$(INPUT)/lue1007d.cub \ + TO=$(OUTPUT)/lue1007d.truth.cub TCOR=true\ + > /dev/null; + diff --git a/isis/src/clementine/apps/clemuvviscal/tsts/noTemp/Makefile b/isis/src/clementine/apps/clemuvviscal/tsts/noTemp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..740419ef778a5bae987552a795190496d6ef791f --- /dev/null +++ b/isis/src/clementine/apps/clemuvviscal/tsts/noTemp/Makefile @@ -0,0 +1,8 @@ +APPNAME = clemuvviscal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/lua1841h.cub \ + TO=$(OUTPUT)/lua1841h.truth.cub TCOR=false \ + > /dev/null; diff --git a/isis/src/clementine/apps/clemuvviscal/tsts/uncompressed/Makefile b/isis/src/clementine/apps/clemuvviscal/tsts/uncompressed/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..561c26037e5c1a49b0810b917570531a3b4c378f --- /dev/null +++ b/isis/src/clementine/apps/clemuvviscal/tsts/uncompressed/Makefile @@ -0,0 +1,8 @@ +APPNAME = clemuvviscal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/lue0972q.cub \ + TO=$(OUTPUT)/lue0972q.truth.cub TCOR=true \ + > /dev/null; diff --git a/isis/src/clementine/objs/HiresCamera/Camera.plugin b/isis/src/clementine/objs/HiresCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..72d810b34b5e1cfe1869b706e3cf09ac5fc593d3 --- /dev/null +++ b/isis/src/clementine/objs/HiresCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = Clementine_1/Hires + Version = 1 + Library = HiresCamera + Routine = HiresCameraPlugin +EndGroup + diff --git a/isis/src/clementine/objs/HiresCamera/HiresCamera.cpp b/isis/src/clementine/objs/HiresCamera/HiresCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c8fac5bb747489e9bf4bbaf0e6e1deb7e4e4a3e --- /dev/null +++ b/isis/src/clementine/objs/HiresCamera/HiresCamera.cpp @@ -0,0 +1,61 @@ +#include "HiresCamera.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraDistortionMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "iString.h" + +using namespace std; +using namespace Isis; +namespace Clementine { + HiresCamera::HiresCamera (Pvl &lab) : FramingCamera(lab) { + + // Get the camera characteristics + iString filter = (string)(lab.FindGroup("BandBin", Pvl::Traverse))["FilterName"]; + filter = filter.UpCase(); + + SetFocalLength (); + SetPixelPitch (); + + // Get the start time in et + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + string stime = inst["StartTime"]; + + double time; + str2et_c(stime.c_str(),&time); + + + + // Do not correct time for center of the exposure duration. This is because + // the kernels were built to accept the start times of the images. + // time += ((double)inst["ExposureDuration"] / 1000.0) / 2.0; // Add half + // exposure duration in milliseconds + + // Setup detector map + new CameraDetectorMap(this); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + + focalMap->SetDetectorOrigin ( + Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + + "_BORESIGHT_SAMPLE"), + Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + + "_BORESIGHT_LINE")); + + // Setup distortion map + new CameraDistortionMap(this); + + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(time); + LoadCache(); + } +} + +extern "C" Camera *HiresCameraPlugin(Pvl &lab) { + return new Clementine::HiresCamera(lab); +} diff --git a/isis/src/clementine/objs/HiresCamera/HiresCamera.h b/isis/src/clementine/objs/HiresCamera/HiresCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..66e23cf332ed32cae639b0eb726bb7b5fd211e17 --- /dev/null +++ b/isis/src/clementine/objs/HiresCamera/HiresCamera.h @@ -0,0 +1,26 @@ +#ifndef HiresCamera_h +#define HiresCamera_h + +#include "FramingCamera.h" + +namespace Clementine { + /** + * @brief Camera class + * + * This is the camera class for the HiresCamera + * + * @ingroup Clementine + * + * @author 2009-01-16 Tracie Sucharski + * + * @internal + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class HiresCamera : public Isis::FramingCamera { + public: + HiresCamera (Isis::Pvl &lab); + ~HiresCamera () {}; + }; +}; +#endif diff --git a/isis/src/clementine/objs/HiresCamera/HiresCamera.truth b/isis/src/clementine/objs/HiresCamera/HiresCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..79b9adf91b50b7b061f4b15ff82a86ae9dc2712a --- /dev/null +++ b/isis/src/clementine/objs/HiresCamera/HiresCamera.truth @@ -0,0 +1,20 @@ +Unit Test for HiresCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/clementine/objs/HiresCamera/Makefile b/isis/src/clementine/objs/HiresCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..621e17d78c4e73dbc8341b78da14b613b990d316 --- /dev/null +++ b/isis/src/clementine/objs/HiresCamera/Makefile @@ -0,0 +1,5 @@ +INCS = HiresCamera.h +SRCS = HiresCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/clementine/objs/HiresCamera/unitTest.cpp b/isis/src/clementine/objs/HiresCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6cf3a90eb3cbfb18f6ea1ad2082f20a531462b17 --- /dev/null +++ b/isis/src/clementine/objs/HiresCamera/unitTest.cpp @@ -0,0 +1,89 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for HiresCamera..." << endl; + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownLat = -75.78743503621011; + double knownLon = 270.6408545511526; + + Isis::Pvl p("$clementine1/testData/lhd0147b.200.lev1.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.001) deltaSamp = 0; + if (fabs(deltaLine) < 0.001) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/clementine/objs/LwirCamera/Camera.plugin b/isis/src/clementine/objs/LwirCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..6f25b03c07510244869520742f0176f7926089d3 --- /dev/null +++ b/isis/src/clementine/objs/LwirCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = Clementine_1/Lwir + Version = 1 + Library = LwirCamera + Routine = LwirCameraPlugin +EndGroup + diff --git a/isis/src/clementine/objs/LwirCamera/LwirCamera.cpp b/isis/src/clementine/objs/LwirCamera/LwirCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6e6023685fc3b2469fbca2e5ea1f7bfbcf1bb49f --- /dev/null +++ b/isis/src/clementine/objs/LwirCamera/LwirCamera.cpp @@ -0,0 +1,64 @@ +#include "LwirCamera.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "RadialDistortionMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "iString.h" + +using namespace std; +using namespace Isis; +namespace Clementine { + /** + * Constructor + * @internal + * @history 2009-01-16 Jeannie Walldren - Original Version + */ + LwirCamera::LwirCamera (Pvl &lab) : FramingCamera(lab) { + + // Get the camera characteristics + iString filter = (string)(lab.FindGroup("BandBin", Pvl::Traverse))["FilterName"]; + filter = filter.UpCase(); + + SetFocalLength (); + SetPixelPitch (); + + // Get the start time in et + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + string stime = inst["StartTime"]; + + double time; + str2et_c(stime.c_str(),&time); + + // Do not correct time for center of the exposure duration. This is because the kernels were built to accept the + // start times of the images. + //time += ((double)inst["ExposureDuration"] / 1000.0) / 2.0; // Add half exposure duration in milliseconds + + // Setup detector map + new CameraDetectorMap(this); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + + focalMap->SetDetectorOrigin (Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_SAMPLE"), + Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_LINE")); + + // Setup distortion map + new RadialDistortionMap(this, 0.0); + + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(time); + LoadCache(); + } +} + +/** + * @internal + * @history 2009-01-16 Jeannie Walldren - Original Version + */ +extern "C" Camera *LwirCameraPlugin(Pvl &lab) { + return new Clementine::LwirCamera(lab); +} diff --git a/isis/src/clementine/objs/LwirCamera/LwirCamera.h b/isis/src/clementine/objs/LwirCamera/LwirCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..e9bc55f8534d259c929cbcb6e33f00e148a7a50c --- /dev/null +++ b/isis/src/clementine/objs/LwirCamera/LwirCamera.h @@ -0,0 +1,28 @@ +#ifndef LwirCamera_h +#define LwirCamera_h + +#include "FramingCamera.h" + +namespace Clementine { + /** + * @brief LWIR Camera class + * + * This is the camera class for Clementine's long wavelength + * infared camera. + * + * @ingroup Clementine + * + * @author 2009-01-16 Jeannie Walldren + * + * @internal + * @history 2009-01-16 Jeannie Walldren - Original Version + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class LwirCamera : public Isis::FramingCamera { + public: + LwirCamera (Isis::Pvl &lab); + ~LwirCamera () {}; + }; +}; +#endif diff --git a/isis/src/clementine/objs/LwirCamera/LwirCamera.truth b/isis/src/clementine/objs/LwirCamera/LwirCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..11e7642f045d8d9d714cbbeb1f53d265c41d9e52 --- /dev/null +++ b/isis/src/clementine/objs/LwirCamera/LwirCamera.truth @@ -0,0 +1,20 @@ +Unit Test for LwirCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/clementine/objs/LwirCamera/Makefile b/isis/src/clementine/objs/LwirCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..51d53a533e889bd336254ca39fecbc114658fbc9 --- /dev/null +++ b/isis/src/clementine/objs/LwirCamera/Makefile @@ -0,0 +1,5 @@ +INCS = LwirCamera.h +SRCS = LwirCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/clementine/objs/LwirCamera/unitTest.cpp b/isis/src/clementine/objs/LwirCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2128ad99447bdf08d5e8a14b7eec13f8fe92bb80 --- /dev/null +++ b/isis/src/clementine/objs/LwirCamera/unitTest.cpp @@ -0,0 +1,89 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for LwirCamera..." << endl; + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownCtrLat = 20.089177228428; + double knownCtrLon = 40.539951455237; + + Isis::Pvl p("$clementine1/testData/lla4263l.153.lev1.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownCtrLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownCtrLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownCtrLon) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownCtrLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.001) deltaSamp = 0; + if (fabs(deltaLine) < 0.001) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/clementine/objs/Makefile b/isis/src/clementine/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/clementine/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/clementine/objs/NirCamera/Camera.plugin b/isis/src/clementine/objs/NirCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..3567d4e49099dad4047929f48e42518fe4a073be --- /dev/null +++ b/isis/src/clementine/objs/NirCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = Clementine_1/Nir + Version = 1 + Library = NirCamera + Routine = NirCameraPlugin +EndGroup + diff --git a/isis/src/clementine/objs/NirCamera/Makefile b/isis/src/clementine/objs/NirCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..17f8308bf0865187c9e1b9c3343f2e4ff71eaa86 --- /dev/null +++ b/isis/src/clementine/objs/NirCamera/Makefile @@ -0,0 +1,5 @@ +INCS = NirCamera.h +SRCS = NirCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/clementine/objs/NirCamera/NirCamera.cpp b/isis/src/clementine/objs/NirCamera/NirCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..68a4c8111f8bcee9df77388e882c86d75ba4f95a --- /dev/null +++ b/isis/src/clementine/objs/NirCamera/NirCamera.cpp @@ -0,0 +1,73 @@ +#include "NirCamera.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "RadialDistortionMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "iString.h" + +using namespace std; +using namespace Isis; +namespace Clementine { + NirCamera::NirCamera (Pvl &lab) : FramingCamera(lab) { + + // Get the camera characteristics + iString filter = (string)(lab.FindGroup("BandBin", Pvl::Traverse))["FilterName"]; + filter = filter.UpCase(); + + if(filter.compare("A") == 0) { + SetFocalLength (2548.2642*0.038); + } + else if(filter.compare("B") == 0) { + SetFocalLength (2530.8958*0.038); + } + else if(filter.compare("C") == 0) { + SetFocalLength (2512.6589*0.038); + } + else if(filter.compare("D") == 0) { + SetFocalLength (2509.0536*0.038); + } + else if(filter.compare("E") == 0) { + SetFocalLength (2490.7378*0.038); + } + else if(filter.compare("F") == 0) { + SetFocalLength (2487.8694*0.038); + } + + SetPixelPitch (); + + // Get the start time in et + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + string stime = inst["StartTime"]; + + double time; + str2et_c(stime.c_str(),&time); + + // Do not correct time for center of the exposure duration. This is because the kernels were built to accept the + // start times of the images. + //time += ((double)inst["ExposureDuration"] / 1000.0) / 2.0; // Add half exposure duration in milliseconds + + // Setup detector map + new CameraDetectorMap(this); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + + focalMap->SetDetectorOrigin (Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_SAMPLE"), + Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_LINE")); + + // Setup distortion map + new RadialDistortionMap(this, -0.0006364); + + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(time); + LoadCache(); + } +} + +extern "C" Camera *NirCameraPlugin(Pvl &lab) { + return new Clementine::NirCamera(lab); +} diff --git a/isis/src/clementine/objs/NirCamera/NirCamera.h b/isis/src/clementine/objs/NirCamera/NirCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..d5296863ce830e1e8a6515216f45f3f21a2052a2 --- /dev/null +++ b/isis/src/clementine/objs/NirCamera/NirCamera.h @@ -0,0 +1,32 @@ +#ifndef NirCamera_h +#define NirCamera_h + +#include "FramingCamera.h" + +namespace Clementine { + /** + * @brief Camera class + * + * This is the camera class for the NirCamera + * + * @ingroup Clementine + * + * @author 2007-07-10 Steven Lambright + * + * @internal + * @history 2007-07-10 Steven Lambright - Original Version + * @history 2007-07-11 Steven Koechle - casted NaifIkCode to int before + * istring to fix Linux 32bit build error + * @history 2008-08-08 Steven Lambright Made the unit test work with a Sensor + * change. Also, now using the new LoadCache(...) method instead of + * CreateCache(...). + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class NirCamera : public Isis::FramingCamera { + public: + NirCamera (Isis::Pvl &lab); + ~NirCamera () {}; + }; +}; +#endif diff --git a/isis/src/clementine/objs/NirCamera/NirCamera.truth b/isis/src/clementine/objs/NirCamera/NirCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..b2daf14ea21a2bd8d1899fd92b5c842b2302687f --- /dev/null +++ b/isis/src/clementine/objs/NirCamera/NirCamera.truth @@ -0,0 +1,20 @@ +Unit Test for NirCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/clementine/objs/NirCamera/unitTest.cpp b/isis/src/clementine/objs/NirCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f77abbc1ebb9c948a67e9f121ad3468e3ec363d2 --- /dev/null +++ b/isis/src/clementine/objs/NirCamera/unitTest.cpp @@ -0,0 +1,89 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for NirCamera..." << endl; + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownLat = -19.72242246137051; + double knownLon = 60.6696196154468; + + Isis::Pvl p("$clementine1/testData/lna1391h.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.001) deltaSamp = 0; + if (fabs(deltaLine) < 0.001) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/clementine/objs/UvvisCamera/Camera.plugin b/isis/src/clementine/objs/UvvisCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..2dfe4cd5219343ecb9bf2c78975feea5809efe04 --- /dev/null +++ b/isis/src/clementine/objs/UvvisCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = Clementine_1/Uvvis + Version = 1 + Library = UvvisCamera + Routine = UvvisCameraPlugin +EndGroup + diff --git a/isis/src/clementine/objs/UvvisCamera/Makefile b/isis/src/clementine/objs/UvvisCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..afe050368234508f2fa80550eb8eb0b6f127a874 --- /dev/null +++ b/isis/src/clementine/objs/UvvisCamera/Makefile @@ -0,0 +1,5 @@ +INCS = UvvisCamera.h +SRCS = UvvisCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/clementine/objs/UvvisCamera/UvvisCamera.cpp b/isis/src/clementine/objs/UvvisCamera/UvvisCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5c2e6f8134a23c3ef2bdf6c99616fd812819762e --- /dev/null +++ b/isis/src/clementine/objs/UvvisCamera/UvvisCamera.cpp @@ -0,0 +1,48 @@ +#include "UvvisCamera.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraDistortionMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "iString.h" + +using namespace std; +using namespace Isis; +namespace Clementine { + UvvisCamera::UvvisCamera (Pvl &lab) : FramingCamera(lab) { + // Get the camera characteristics + SetFocalLength (); + SetPixelPitch (); + + // Get the start time in et + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + string stime = inst["StartTime"]; + + double time; + str2et_c(stime.c_str(),&time); + time += ((double)inst["ExposureDuration"] / 1000.0) / 2.0; // Add half exposure duration in milliseconds + + // Setup detector map + new CameraDetectorMap(this); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + + focalMap->SetDetectorOrigin (Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_SAMPLE"), + Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_LINE")); + + // Setup distortion map + new CameraDistortionMap(this); + + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(time); + LoadCache(); + } +} + +extern "C" Camera *UvvisCameraPlugin(Pvl &lab) { + return new Clementine::UvvisCamera(lab); +} diff --git a/isis/src/clementine/objs/UvvisCamera/UvvisCamera.h b/isis/src/clementine/objs/UvvisCamera/UvvisCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..e10731eca7d8b42956052f2c8d06b40bd6a1c641 --- /dev/null +++ b/isis/src/clementine/objs/UvvisCamera/UvvisCamera.h @@ -0,0 +1,32 @@ +#ifndef UvvisCamera_h +#define UvvisCamera_h + +#include "FramingCamera.h" + +namespace Clementine { + /** + * @brief Camera class + * + * This is the camera class for the UvvisCamera + * + * @ingroup Clementine + * + * @author 2007-07-10 Tracie Sucharski + * + * @internal + * @history 2007-07-10 Steven Lambright - Imported to Isis 3 + * @history 2007-07-11 Steven Koechle - casted NaifIkCode to int before + * istring to fix Linux 32bit build error + * @history 2008-08-08 Steven Lambright Made the unit test work with a Sensor + * change. Also, now using the new LoadCache(...) method instead of + * CreateCache(...). + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class UvvisCamera : public Isis::FramingCamera { + public: + UvvisCamera (Isis::Pvl &lab); + ~UvvisCamera () {}; + }; +}; +#endif diff --git a/isis/src/clementine/objs/UvvisCamera/UvvisCamera.truth b/isis/src/clementine/objs/UvvisCamera/UvvisCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..319bbbcc209e65b9ff7183ac52ac73dfdbdc1cc1 --- /dev/null +++ b/isis/src/clementine/objs/UvvisCamera/UvvisCamera.truth @@ -0,0 +1,20 @@ +Unit Test for UvvisCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/clementine/objs/UvvisCamera/unitTest.cpp b/isis/src/clementine/objs/UvvisCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36be1ec7ba1ede7566a5a3117a4919dedeb24f3a --- /dev/null +++ b/isis/src/clementine/objs/UvvisCamera/unitTest.cpp @@ -0,0 +1,94 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for UvvisCamera..." << endl; + /** + * Increased line/samp->lat/lon->line/samp tolerances + */ + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + // double knownLat = -78.56557059110476; + // double knownLon = 126.7899573707551; + double knownLat = -78.56562123061852; + double knownLon = 126.7899420749119; + + //Isis::Pvl p("$mgs/testData/lub0428b.cub"); + Isis::Pvl p("$clementine1/testData/lub0428b.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.0043) deltaSamp = 0; + if (fabs(deltaLine) < 0.0043) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} diff --git a/isis/src/clementine/tsts/Makefile b/isis/src/clementine/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..016388fc898d8c89f380cae1fd08942c29611582 --- /dev/null +++ b/isis/src/clementine/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-42s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/clementine/tsts/clementine/Makefile b/isis/src/clementine/tsts/clementine/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5c09c0b7f5a09c94adcf614d2b26117f30d8f8c1 --- /dev/null +++ b/isis/src/clementine/tsts/clementine/Makefile @@ -0,0 +1,40 @@ +APP1NAME = clem2isis +APP2NAME = spiceinit +APP3NAME = campt +APP4NAME = getsn + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APP1NAME) from= $(INPUT)/lna3819k.045 \ + to= $(OUTPUT)/lna3819k.045--clem2isis-spiceinit.cub > /dev/null + + $(APP2NAME) from= $(OUTPUT)/lna3819k.045--clem2isis-spiceinit.cub \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/lna3819k.045--clem2isis-spiceinit.cub \ + to= $(OUTPUT)/lna3819k.045--finalOutput.pvl SAMPLE=2 LINE=2 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/lna3819k.045--clem2isis-spiceinit.cub \ + to= $(OUTPUT)/lna3819k.045--finalOutput.pvl SAMPLE=254 LINE=2 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/lna3819k.045--clem2isis-spiceinit.cub \ + to= $(OUTPUT)/lna3819k.045--finalOutput.pvl SAMPLE=254 LINE=254 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/lna3819k.045--clem2isis-spiceinit.cub \ + to= $(OUTPUT)/lna3819k.045--finalOutput.pvl SAMPLE=2 LINE=254 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/lna3819k.045--clem2isis-spiceinit.cub \ + to= $(OUTPUT)/lna3819k.045--finalOutput.pvl SAMPLE=128 LINE=128 ALLOWOUTSIDE=no \ + > /dev/null + + echo -e "\nOutput of getsn..." > $(OUTPUT)/lna3819k.045--getsnOutput.txt && \ + $(APP4NAME) from= $(OUTPUT)/lna3819k.045--clem2isis-spiceinit.cub \ + >> $(OUTPUT)/lna3819k.045--getsnOutput.txt + + $(RM) $(OUTPUT)/lna3819k.045--clem2isis-spiceinit.cub > /dev/null + $(RM) $(OUTPUT)/../print.prt > /dev/null diff --git a/isis/src/database/Makefile b/isis/src/database/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/database/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/database/apps/Makefile b/isis/src/database/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/database/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/database/objs/Database/Database.cpp b/isis/src/database/objs/Database/Database.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eb53c34178576dbd9b0af9f647dda127145c0945 --- /dev/null +++ b/isis/src/database/objs/Database/Database.cpp @@ -0,0 +1,570 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/06/26 01:19:21 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include "DbProfile.h" +#include "Database.h" +#include "DatabaseFactory.h" +#include "iString.h" + +#include +#include + +using namespace std; + +namespace Isis { + +std::string Database::_actualConnectionName = ""; + +/** + * @brief Default database constructor + * + * This constructor does not interact at all with the DatabaseFactory class but + * uses the default condition for the Qt QSqlDatabase state. + * + */ +Database::Database() : QSqlDatabase(), _name("") { } + +/** + * @brief Construction of the unamed database with optional connection + * + * This Database constructor essentially will attempt to invoke the default + * profile as provided by the DatabaseFactory class. That profile is read when + * the factory is created using the IsisPreferences class. If there is a + * Database object there and it contains a specification of an AccessConfig + * profile, the contents of the profile mentioned there govern the action of + * this constructor. + * + * If the caller provides true to this class, it will immediately attempt a + * connection. Otherwise it will not attempt a connection to the database. + * + * Use the isOpen Qt method to check for the status of the connection. + * + * @param dbConn If Connect, an immediate connection is attempted, otherwise + * connection is deferred. + */ +Database::Database(Database::Access dbConn) : QSqlDatabase(init()), _name("") { + _name = _actualConnectionName; + if ((dbConn == Connect) && isValid()) { + if (!open()) { + string mess = "Failed to open database default database [" + _name; + tossDbError(mess,_FILEINFO_); + } + } +// Name cannot be set, so set to determined name +} + +/** + * @brief Create a named database object + * + * This construction scheme assumes the named database either already exists as + * a persistant database connection or exists as a user specified profile in the + * DatabaseFactory environment. + * + * @param name Name of the desired database connection to establish + * @param dbConn If Connect, an immediate connection is attempted, otherwise + * connection is deferred. + */ +Database::Database(const std::string &name, Database::Access dbConn) : + QSqlDatabase(init(name)),_name(name) { + _name = _actualConnectionName; + if ((dbConn == Connect) && isValid()) { + if (!open()) { + string mess = "Failed to open database specified as " + _name; + tossDbError(mess,_FILEINFO_); + } + } +} + +/** + * @brief Create database connection specified by name and driver type + * + * This constructor is useful for creating a named database with a specific + * driver type. The following example creates a PostgreSQL database named + * "sparky". + * @code + * Database db("sparky", "postgresql"); + * @endcode + * + * If you do not provide a driver (driverType = ""), then it will attempt to + * find an existing database connection named "sparky" and use it or it will + * attempt to resolve the request by searching for a DbProfile named "sparky". + * + * @param connName Name of connect to create or return + * @param driverType Type of database to created. This is typically MySQL, + * PostgreSQL or SQLite. + */ +Database::Database(const std::string &connName, const std::string &driverType) : + QSqlDatabase(init(connName, driverType)), _name(connName) { + _name = _actualConnectionName; +} + +/** + * @brief Create database connection using the supplied DbProfile + * + * This constructor accepts a DbProfile that contains sufficient information to + * create a complete database connection. The caller can optional request that + * the connection be established meaning that the profile contain enough + * information to do so. If connect = false, then upon return, the caller can + * further add or modify connection parameters as needed. + * + * @param profile DbProfile containing a single database connection profile or + * one that provides enough information to determine appropriate + * access information. + * @param dbConn If Connect, an immediate connection is attempted, otherwise + * connection is deferred. + */ +Database::Database(const DbProfile &profile, Database::Access dbConn) : + QSqlDatabase(init(profile, DoNotConnect)), + _name(profile.Name()) { + _name = _actualConnectionName; + if ((dbConn == Connect) && isValid()) { + if (!open()) { + string mess = "Failed to open database with profile " + _name; + tossDbError(mess,_FILEINFO_); + } + } +} + +/** + * @brief Constructor creates a clone/copy from an existing one + * + * This constructor creates a clone or copy of an existing one. You can be sure + * that you can send it a Database object as well as a Qt QSqlDatabase since the + * Database class inherits the QT QSqlDatabase class. + * + * @param other Database to clone from this one + * @param newName New name of the cloned database (it can't be the same name) + */ +Database::Database(const QSqlDatabase &other, const std::string &newName) : + QSqlDatabase(QSqlDatabase::cloneDatabase(other, iString::ToQt(newName))), + _name(newName) { } + + +/** + * @brief Database destructor + * + * This will close the Database connection if it is still open, and, if it is + * not marked as persistant, it is removed from the named Database pool. It + * is not completely removed (from the Qt QSqlDatabase pool), however. Use + * the remove() method to ensure it is completely destroyed/removed from the + * pool. + */ +Database::~Database() { + DatabaseFactory *factory = DatabaseFactory::getInstance(); + if (!factory->isPersistant(_name)) { + if (isOpen()) { close(); } + factory->remove(_name); + } +} + +/** + * @brief Makes this instance persistant + * + * Database persistancy in this context means the database remains in whatever + * state the user leaves it in, such as open, and ensures that the configuration + * remains available for other uses of the same connection. + * + * This feature is useful if you have a long running application that will make + * prepeated attempts to access the database using the same configuration + * parameters. It saves overhead and provides a guaranteed state of access. It + * can and perhaps should be closed when not used in between long accesses. + * This will prevent timeouts from the database. + * + * The intended usefulness of the persistant database state is so that at + * anytime in the life or processing point in the program, the database + * connection is available. + * + * Note that this uses the DatabaseFactory class to retain its persistancy. + * + * @see DatabaseFactory + */ +void Database::makePersistant() { + DatabaseFactory *factory = DatabaseFactory::getInstance(); + if (!factory->isPersistant(_name)) { + factory->add(*this, _name); + } + return; +} + +/** + * @brief Checks persistancy state of a database instantiation + * + * This method tests to determine if this database connection is persistant so + * that future access can be utilized in this state. + * + * @return bool True if persistant, otherwise false + */ +bool Database::isPersistant() const { + DatabaseFactory *factory = DatabaseFactory::getInstance(); + return (factory->isPersistant(_name)); +} + +/** + * @brief Sets this database connection/profile as the default + * + * Calling this method sets this database instance/connection as the default + * connection. It is added to the list of persistant connections and can be + * retreived at will at any point in an application. This will be true even if + * this instance is released. + * + * It uses the DatabaseFactory class to register it as the default. Note that + * there is only one default ever and it is designated by name. By definition + * it is also marked as a persistant connection. + * + * @see DatabaseFactory + */ +void Database::setAsDefault() { + DatabaseFactory *factory = DatabaseFactory::getInstance(); + if (!factory->isPersistant(_name)) { + factory->add(*this, _name); + } + factory->setDefault(_name); + return; +} + +/** + * @brief Removes the named database from pool + * + * This static method is required in order to remove a previous used + * Database from the database pool. Database configurations hang around + * after they are used. To completely remove them from application + * space, you must call this method. + + * NOTE: The Database destructor only ensure the connection is closed. + * It does not complete remove them. Persistant databases have their + * connect state preserved from one Database construction/instantiation + * to the next. This method is the only way to completely remove a + * database from global application space connectivity. + * + * WARNING: Do not attempt to remove an active Database! This will cause + * a spurious warning from Qt and render the database inoperative! + * + * @param name Name of database to remove (and destroy) + */ +void Database::remove(const std::string &name) { + DatabaseFactory *factory = DatabaseFactory::getInstance(); + factory->destroy(name); + return; +} + +/** + * @brief Adds a user specifed access configuration file to system + * + * This method accepts a file name that contains a Database access configuration + * file and adds it to the database access profile system. This is actually + * performed by the DatabaseFactory class. + * + * @see DatabaseFactory::addAccessProfile() + * + * @param confFile Name of file to add. This can have any valid Isis or + * environment variable as part of the file specfication. + * + * @return bool True if successful, false if the file could not be opened or an + * error was found in the file. + */ +bool Database::addAccessConfig(const std::string &confFile) { + DatabaseFactory *factory = DatabaseFactory::getInstance(); + return (factory->addAccessProfile(confFile)); +} + +/** + * @brief Retrieves the named database access profile + * + * This method is provided to the calling environment to retrieve any named + * profile. If an empty string is provided, it returns the default as + * determined by the DatabaseFactory class rules. + * + * This can be used to determine the default and potentially augment its + * contents prior to creating a database connection. + * + * For example, here is a small code segment that retrieves the default access + * profile and tests for its validity. If it is not valid, chances are there is + * no default established. + * + * @code + * DbProfile default = Database::getProfile(); + * if (!default.isValid()) { + * cerr << "No default access profile established!" << endl; + * } + * + * // Open the database (after optional modification) + * Database mydb(default); + * @endcode + * + * @see DatabaseFactory::getProfile() + * + * @param name Name of profile to retrieve. An empty string will return the + * default profile. + * + * @return DbProfile Requested profile. Test its validity using the + * DbProfile::isValid() method. + */ +DbProfile Database::getProfile(const std::string &name) { + DatabaseFactory *factory = DatabaseFactory::getInstance(); + return (factory->getProfile(name)); +} + +/** + * @brief Initializes a database by connection name and driver type + * + * This method accepts (optional) connection name and driver type to establish a + * database connection. If both passed string parameters are empty, then either + * the default will be returned or a new database connection is returned using + * the default profile - if one is established. If neither of these conditions + * are met, this routine will throw an error. + * + * If only a connection name is given but no driver, then either a persistant + * connection or a default profile must exist. + * + * If both a name and driver is provided, then a clean database object is + * returned without any connection parameters set and the application programmer + * must set them. + * + * NOTE: This method is implemented in such a way that it assumes it is part of + * the QSqlDatabase initialization phase upon object construction. You will see + * some implementation decisions based upon this expeectation. + * + * @param connName Name of the connection to create + * @param driverType Type of driver/database to create. This is typically + * MySQL, PostgreSQL or SQLite. + * + * @return QSqlDatabase The created database + */ +QSqlDatabase Database::init(const std::string &connName, + const std::string &driverType) { + + _actualConnectionName = connName; + DatabaseFactory *factory = DatabaseFactory::getInstance(); + + // First test for condition where both name and type are not provided. + // This tests for the default profile and returns it if it exists, + // otherwise it returns a default database. + if (connName.empty() && driverType.empty()) { + if (factory->isAvailable(factory->getDefault())) { + _actualConnectionName = factory->getDefault(); + return (factory->create(_actualConnectionName)); + } + + // No default is established so retreive the default profile + DbProfile profile = factory->getProfile(); + if (profile.isValid()) { + return (init(profile, DoNotConnect)); + } + } + + // If only the name and no driver is provided, get an existing connection + if ((!connName.empty()) && (driverType.empty())) { + if (factory->isAvailable(connName)) { + _actualConnectionName = connName; + return (factory->create(connName)); + } + else { + // See if the database exists by profile + DbProfile profile = factory->getProfile(connName); + return (init(profile, DoNotConnect)); + } + } + + // Finally, a driver and optional name is provided. This condition sets up + // a named database for subsequent definition later + return (factory->create(driverType, connName)); +} + + +/** + * @brief Create and initialize a new database connection from a DbProfile + * + * This init method accepts a DbProfile database access profile that is assumed + * to contain sufficient information to establish a connection and open it. + * Note that the connection is opened only if the connect = true. Otherwise, + * the parameters from teh profile is set but the database is returned without + * initiating a connection to the database - this so the caller can adjust or + * provide additional parameters. + * + * NOTE: This method is implemented in such a way that it assumes it is part of + * the QSqlDatabase initialization phase upon object construction. You will see + * some implementation decisions based upon this expeectation. + * + * @param profile A valid database profile specifying access parameters. + * @param dbConn If Connect, an immediate connection is attempted, otherwise + * connection is deferred. + * @return QSqlDatabase A Qt database object with access parameters set + */ +QSqlDatabase Database::init(const DbProfile &profile, Database::Access dbConn) { + if (!profile.isValid()) { + ostringstream mess; + mess << "Database/profile [" << profile.Name() << "] is not valid!" << ends; + throw iException::Message(Isis::iException::Programmer, mess.str(), + _FILEINFO_); + } + + _actualConnectionName = profile.Name(); + DatabaseFactory *factory = DatabaseFactory::getInstance(); + + // initialize the database + try { + + // If we reach here, it is a valid profile. Create the database and + // return it as initialized from the profile contents + QSqlDatabase db = factory->create(profile("Type"), profile("Name")); + _actualConnectionName = profile("Name"); + configureAccess(db, profile); + + // Go ahead and connect if requested + if (dbConn == Connect) { + if (!db.open()) { + string mess = "Failed to connect to database using profile " + + profile("Name"); + tossDbError(mess, _FILEINFO_); + } + } + return (db); + } + catch (iException &ie) { + string mess = "Unable to create database from " + profile.Name(); + ie.Message(Isis::iException::User, mess, _FILEINFO_); + throw ie; + } + catch (...) { + string mess = "Unknown exception while creating database from profile " + + profile.Name(); + throw iException::Message(Isis::iException::User, mess, _FILEINFO_); + } +} + +/** + * @brief Set access parameters from a database DbProfile access specification + * + * This method takes a database and a database access configuration setup and + * applies the parameters to it setting up access. This method does not intiate + * the connection, only sets known, common parameters. These parameters are + * Host, DbName, User, password, Port and Options. They follow the + * specifications of the Qt SQL QSqlDatabase class methods. + * + * @param db The Qt database object to set access parameters for. + * @param profile The database access parameter source. + */ +void Database::configureAccess(QSqlDatabase &db, const DbProfile &profile) { + if (profile.exists("Host")) { + db.setHostName(iString::ToQt(profile("Host"))); + } + + if (profile.exists("DbName")) { + db.setDatabaseName(iString::ToQt(profile("DbName"))); + } + + if (profile.exists("User")) { + db.setUserName(iString::ToQt(profile("User"))); + } + + if (profile.exists("Password")) { + db.setPassword(iString::ToQt(profile("Password"))); + } + + if (profile.exists("Port")) { + bool ok; + db.setPort(iString::ToQt(profile("Port")).toInt(&ok)); + if (!ok) { + ostringstream mess; + mess << "Invalid port number [" << profile("Port") << "] in profile " + << profile("Name") << ends; + throw iException::Message(Isis::iException::User, mess.str(), _FILEINFO_); + } + } + + if (profile.exists("Options")) { + db.setConnectOptions(iString::ToQt(profile("Options"))); + } + return; +} + +/** + * @brief Clones this database into another giving it another name + * + * This database object is cloned into another one and names it the provided + * name. All access parameters are retained as initiallyt set up. + * + * @param name Name to give the cloned database. + * + * @return The cloned Database + */ +Database Database::clone(const std::string &name) const { + return (Database(*this, name)); +} + +/** + * @brief Returns a vector string containing all the tables in the database + * + * This method returns a complete list of accessable tables within the database. + * It is assumed the database connections is established and open. + * + * @return std::vector List of tables in the database + */ +std::vector Database::getTables() const { + return (iString::ToStd(tables(QSql::Tables))); +} + +/** + * @brief Returns a vector string containing all views within the database + * + * This method returns a vector of strings with all views accessable to the user + * in each element in the vector. + * + * @return std::vector List of all accessable views in the + * database + */ +std::vector Database::getViews() const { + return (iString::ToStd(tables(QSql::Views))); +} + +/** + * @brief Returns vector strings of all available system tables in the database + * + * This method returns a vector of strings containing a list of all system + * tables accessable to the user within the database. + * + * @return std::vector List of system tables with the database + */ +std::vector Database::getSystemTables() const { + return (iString::ToStd(tables(QSql::SystemTables))); +} + +/** + * @brief Generic exception tosser + * + * This method is used from within this class to construct and deploy an + * exception when an error occurs in some of the methods in this class. + * + * @param message Text of message to include in exception + * @param f Name of method initiating the exception + * @param l Line number the error occured + */ +void Database::tossDbError(const std::string &message, const char *f, int l) const + throw (iException &) { + string errmess = message + " - DatabaseError = " + + iString::ToStd(lastError().text()); + throw iException::Message(Isis::iException::Programmer, errmess, f, l); +} + +} diff --git a/isis/src/database/objs/Database/Database.h b/isis/src/database/objs/Database/Database.h new file mode 100644 index 0000000000000000000000000000000000000000..743fd9e2471cb51d3487a8d49c17c23ee68e4563 --- /dev/null +++ b/isis/src/database/objs/Database/Database.h @@ -0,0 +1,137 @@ +#if !defined(Database_h) +#define Database_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/10/30 16:38:23 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "DbProfile.h" +#include "iException.h" +#include + +namespace Isis { + +/** + * @brief Isis database class providing generalized access to a variety of + * databases + * + * This class provides database connections within the Isis application + * programming interface (API) environment. It is based upon the + * DatabaseFactory class and utilizes its features to let users control access + * to databases. See the documentation for that class to get a full description + * of generalized access methods as defined by users. + * + * This class also provides programmer derived access using either database + * profiles (DbProfile) containing access (DbAccess) specifications. + * @code + * // Use the UPC profile + * Database upc("upc") + * @endcode + * + * Connections can be made to specific databases using named drivers also + * provided from the DatabaseFactory class. + * @code + * // Set up one for UPC directly + * Database upc1("upcDirect", "PostgreSQL"); // "QPSQL" also works + * upc1.setHostName("upcdb0.wr.usgs.gov"); + * upc1.setDatabaseName("upc"); + * upc1.setUserName("upcread"); + * upc1.setPort(3309); + * upc1.open(); + * @endcode + * + * Since this class is derived from the Qt QSqlDatabase class, it can and is + * intended to be used in the Qt environment directly. IMPORTANT NOTE: The + * init() function returns a QSqlDatabase instance in all constructors which + * means that the class has not yet completed constructing. The implications of + * this are that the Database class elements, namely data constructs, are + * generally off limits until after the return from init(). This is primarily + * the reason for some of the implimentation decisions made in this class. + * + * See also SqlQuery and SqlRecord. + * + * @ingroup Database + * @author 2006-08-18 Kris Becker + * + * @internal + * @history 2007-06-05 Brendan George - Modified to work with + * iString/StringTools merge + * @history 2008-10-30 Steven Lambright - tossDbError now accepts a const + * char* for a filename, issue pointed out by "novus0x2a" (Support + * Board Member) + */ + class Database : public QSqlDatabase { + public: + /** Access status for database creation */ + typedef enum { + Connect, //!< Connect to database immediately + DoNotConnect //!< Do not connect to database + } Access; + + Database(); + Database(Access dbConn); + Database(const std::string &connName, const std::string &driverType); + Database(const std::string &name, Access dbConn = Connect); + Database(const DbProfile &profile, Access dbConn = Connect); + virtual ~Database(); + + /** + * @brief Return the name of this database as specifed upon creation + * + * @return std::string The name of this database + */ + std::string Name() const { return (_name); } + + void makePersistant(); + bool isPersistant() const; + void setAsDefault(); + Database clone(const std::string &name) const; + std::vector getTables() const; + std::vector getViews() const; + std::vector getSystemTables() const; + + static void remove(const std::string &name); + + static bool addAccessConfig(const std::string &confFile); + static DbProfile getProfile(const std::string &name); + + protected: + Database(const QSqlDatabase &other, const std::string &name); + QSqlDatabase init(const DbProfile &profile, Access dbConn = Connect); + QSqlDatabase init(const std::string &name = "", + const std::string &driverType = ""); + void configureAccess(QSqlDatabase &db, const DbProfile &profile); + + private: + static std::string _actualConnectionName; /** Needed due to peculiar + * issues with Database + * construction techniques */ + std::string _name; //!< Name of the connection + + void tossDbError(const std::string &message, const char *f, int l) const + throw (iException &); + }; + +} +#endif diff --git a/isis/src/database/objs/Database/Database.truth b/isis/src/database/objs/Database/Database.truth new file mode 100644 index 0000000000000000000000000000000000000000..dd0a8ff16da5e13df898e1c8916f205b26f0a805 --- /dev/null +++ b/isis/src/database/objs/Database/Database.truth @@ -0,0 +1,12 @@ +Field 0: v1 +Field 1: v2 +Field 2: v3 +Database Name: unittestdb +Persistant: 0 +Calling makePersistant()... +Persistant: 1 +Clone name: unittestdb clone +Tables: [ testTable ] +Views: [] +SystemTables: [ sqlite_master ] +Removing clone... Done. diff --git a/isis/src/database/objs/Database/Makefile b/isis/src/database/objs/Database/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..81aecde17e3908db33133f3794c60472a2b189ba --- /dev/null +++ b/isis/src/database/objs/Database/Makefile @@ -0,0 +1,6 @@ +INCS = Database.h +SRCS = Database.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/database/objs/Database/unitTest.cpp b/isis/src/database/objs/Database/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f34876c38d1d77ac2c414d2aab49ac9d73e8090b --- /dev/null +++ b/isis/src/database/objs/Database/unitTest.cpp @@ -0,0 +1,84 @@ +#include +#include +#include "Database.h" +#include "SqlQuery.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +void print(vector in); + +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + // SQLite database is in memory + std::string dbname(":memory:"); + + Database testdb("unittestdb", "SQLite"); + testdb.setDatabaseName(dbname.c_str()); + if(!testdb.open()) { + iException::Message(iException::User, "Connection failed", _FILEINFO_); + } + + // Construct queries + string table = "CREATE TABLE testTable (" + " v1 TEXT," + " v2 INTEGER," + " v3 REAL );"; + string insert = "INSERT INTO testTable (v1, v2, v3) " + " VALUES ('test text', 7, 123.4);"; + string query = "SELECT * FROM testTable;"; + + SqlQuery create(testdb); + create.setThrowOnFailure(); + + try { + create.exec(table); + create.exec(insert); + create.exec(query); + vector fields = create.fieldNameList(); + for(int i = 0; i < (int)fields.size(); i++) { + cout << "Field " << i << ": " << fields[i] << endl; + } + } + catch(iException &e) { + e.Report(false); + } + + cout << "Database Name: " << testdb.Name() << endl; + cout << "Persistant: " << testdb.isPersistant() << endl; + cout << "Calling makePersistant()..." << endl; + testdb.makePersistant(); + cout << "Persistant: " << testdb.isPersistant() << endl; + + Database c = testdb.clone("unittestdb clone"); + cout << "Clone name: " << c.Name() << endl; + + cout << "Tables: "; + print(testdb.getTables()); + + cout << "Views: "; + print(testdb.getViews()); + + cout << "SystemTables: "; + print(testdb.getSystemTables()); + + cout << "Removing clone... "; + Database::remove("c"); + cout << "Done." << endl; + + // Closing and removing persistant DB + testdb.close(); + Database::remove(dbname); + return 0; +} + +// Print contents of a vector to console +void print(vector in) { + cout << "["; + for(int i = 0; i < (int)in.size(); i++) { + cout << " " << in[i] << " "; + } + cout << "]" << endl; +} diff --git a/isis/src/database/objs/DatabaseFactory/DatabaseFactory.cpp b/isis/src/database/objs/DatabaseFactory/DatabaseFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05b1101e6d37de63029e1ca5b72a8944ce7b1af4 --- /dev/null +++ b/isis/src/database/objs/DatabaseFactory/DatabaseFactory.cpp @@ -0,0 +1,578 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/11/27 23:09:58 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include + +using namespace std; + + +#include +#include +#include + +#include "DatabaseFactory.h" +#include "DbAccess.h" +#include "Preference.h" +#include "Filename.h" +#include "iString.h" + +namespace Isis { + + +DatabaseFactory *DatabaseFactory::_factory = 0; + +/** + * @brief Constructor establishing the startup state of this singleton + * + * This constructor sets up the initial state of the DatabaseFactory object. + * This object is implementated as a singleton and must take measures to ensure + * that at program termination, all database connections are closed. This is + * acheived through setting up a Qt termination function that is executed when + * the Qt environment is exiting. + * + * Note that it is an error to schedule this process outside of Qt (using the + * atexit() function) because it uses Qt classes that must be properly + * deallocated. This cannot be done once the Qt environment exits. + * + * Upon invocation of this object, a database access scheme is read. This is + * explained in the class documentation and will not be repeated here. + * + * As a safety measure, this constructor determines if a Qt application class, + * Gui or non-Gui is initialized. If it is not, a non-Gui QCoreApplication is + * instantiated to properly initialize the Qt environment. This is required in + * order to have any Qt-based database plugins loaded and available for + * subsequent use. It is highly recommended that this activity occur + * explicitily at a much higher level as it allows for greater programmer + * application control. + */ +DatabaseFactory::DatabaseFactory() : _defProfName(""), _profiles(), + _defDatabase(""), _dbList() { + +// Checks the existance of the Qt application core. This is required in order +// ensure database driver plugins are loaded - if they exist. + QCoreApplication *cApp = QCoreApplication::instance(); + if (cApp == 0) { + static char *argv = { "DatabaseFactory" }; + static int argc = 1; + new QCoreApplication(argc, &argv); + } + + // Initializes + init(); + + // This ensures this singleton is shut down when the application exists, + // so existing database connections are terminated. + qAddPostRoutine(DieAtExit); +} + +/** + * @brief Destructor implements self-destruction of this object + */ +DatabaseFactory::~DatabaseFactory() { + selfDestruct(); +} + +/** + * @brief Exit termination routine + * + * This (static) method ensure this object is destroyed when Qt exits. This is + * required so that persistant database connections can be terminated and + * cleaned up. + * + * Note that it is error to add this to the system _atexit() routine because + * this object utilizes Qt classes. At the time the atexit call stack is + * executed, Qt is long gone resulting in Very Bad Things. Fortunately, Qt has + * an exit stack function as well. This method is added to the Qt exit call + * stack. See the DatabaseFactory() constructor. + */ +void DatabaseFactory::DieAtExit() { + delete _factory; + _factory = 0; + return; +} + +/** + * @brief Returns and instance of this DatabaseFactory singleton + * + * This method is the sole source of access to the DatabaseFactory class. Upon + * the first call to this method, the DatabaseFactory is created. Subsequent + * calls simply return a pointer reference to object which can be used to + * reference existing databases and database drivers. + * + * @return DatabaseFactory* Returns a pointer reference to a DatabaseFactory + * singleton object + */ +DatabaseFactory *DatabaseFactory::getInstance() { + if (DatabaseFactory::_factory == 0) { + DatabaseFactory::_factory = new DatabaseFactory(); + } + return (DatabaseFactory::_factory); +} + +/** + * @brief Establishes an access profile for subsequent database connections + * + * This method takes the name of a database access profile file and adds all its + * profiles to the internally maintained list. Users of this class can then use + * any one of profiles in the list as the access scheme for all database + * creation and connection requests. + * + * If a profile of the same name happens to already exist, it is replaced by any + * new one contained in the access profiles file. + * + * \b NOTE that if a default profile is specified in the added acsess scheme it + * supercedes all other defaults - which includes one loaded at startup from + * IsisPreferences and one set by the programmer explicitly. To retain current + * settings require the user to get the named default prior to adding these + * profiles and resetting it upon return. + * + * @param profileFile Name of profile file to add + * + * @return bool True if the new profile is successfully added, false otherwise. + */ +bool DatabaseFactory::addAccessProfile(const std::string &profileFile) { + try { + Filename dbconf(profileFile); + if (dbconf.Exists()) { + DbAccess acp(profileFile); + + // Add the top level one - may be replaced + const DbProfile &topProf = acp.getProfile(); + _profiles.add(topProf.Name(),topProf); + + // Now add each individual one + for (int i = 0 ; i < acp.profileCount() ; i++) { + const DbProfile &newProf = acp.getProfile(i); + _profiles.add(newProf.Name(), newProf); + } + + // See if a default exists + if (acp.exists("DefaultProfile")) { + _defProfName = acp.value("DefaultProfile"); + } + return (true); + } + } catch (...) { + // upon any failure, we were unsuccessful + return (false); + } + + // File did not exist + return (false); +} +/** + * @brief Adds a database access profile to the list of profiles + * + * This method will add a new access profile to the list of existing profiles + * and make it available for subsequent access requests. + * + * \b NOTE that if an profile exists with the same name, it is \b replaced with + * this one. The one is no longer accessable. + * + * @param profile New access profile to add to internal list + */ +void DatabaseFactory::addProfile(const DbProfile &profile) { + _profiles.add(profile.Name(), profile); + return; +} + +/** + * @brief Return list of names of currently available profiles + * + * This method will return a list of the names of all currently available + * database access profiles as a vector of strings. + * + * @return std::vector List of available profile names + */ +std::vector DatabaseFactory::getProfileList() const { + std::vector plist; + for (int i = 0 ; i < _profiles.size() ; i++) { + plist.push_back(_profiles.key(i)); + } + return (plist); +} + +/** + * @brief Get the specified database access profile + * + * This method provides access profiles from the "system-wide" database access + * profile. The primary source of availability of these profiles is established + * upon the first instance returned from the DatabaseFactory through the + * preferences. See the DatabaseFactory documentation for how this is + * established. + * + * If the named profile dones not exist, a black one is returned and can be + * checked via the DbProfile.isValid() method. + * + * @param name Name of the profile to return. If not provided by the + * caller, then the default will be provided (which is defined + * in the Pvl input Access Profile or is unspecified which + * will result in an invalid profile (typically)). + * + * @return DbProfile An database access profile resulting from the request. + * @see initPreferences(). + */ +DbProfile DatabaseFactory::getProfile(const std::string &name) const { + string profName(name); + if (profName.empty()) profName = _defProfName; + + // Refer to user access if provided + if (!_profiles.exists(profName)) { + return(DbProfile(profName)); + } + else { + return (_profiles.get(profName)); + } +} + +/** + * @brief Determine what database drivers are available + * + * This method returns a vector of strings that contains the names of all + * available database drivers. + * + * In this list will be Qt named drivers, such as QMYSQL, formal names for + * drivers such as MySQL and PostgreSQL, and named database connections such as + * UPC. The list includes all currently availble database resources. + * + * @return std::vector List of database drivers + */ +std::vector DatabaseFactory::available() const { + Drivers drivers = getResourceList(true,true); + std::vector dblist; + for (int i = 0 ; i < drivers.size() ; i++) { + dblist.push_back(drivers.key(i)); + } + return (dblist); +} + +/** + * @brief Check for the existance of a specific database driver + * + * dbname can be a Qt database driver or a formal name of a database, such as + * MySQL. The name is case insensitve. + * + * @param dbname Name of the database driver to check availability + * + * @return bool True if the specifed driver exists, otherwise false + */ +bool DatabaseFactory::isDriverAvailable(const std::string &dbname) const { + Drivers drivers = getResourceList(true,false); + if (!drivers.exists(dbname)) { return (false); } + return (QSqlDatabase::isDriverAvailable(iString::ToQt(drivers.get(dbname)))); +} + +/** + * @brief Check for availablity of a database connection resource + * + * This method checks for the existance of a driver for the specified named + * database resource. + * + * @param dbname Name of the database resource to check availability + * + * @return bool True if the connection exists, otherwise false + */ +bool DatabaseFactory::isAvailable(const std::string &dbname) const { + Drivers dbdrivers = getResourceList(false,true); + string name(dbname); + if (name.empty()) { name = _defDatabase; } + return (dbdrivers.exists(name)); +} + +/** + * @brief Determines if the database resource is connected + * + * Checks the named database for existance in the database connection pool. + * + * @param dbname Case insensitive name of database connection + * + * @return bool True if it exists in the pool, otherwise false + */ +bool DatabaseFactory::isConnected(const std::string &dbname) const { + string name(dbname); + if (name.empty()) { name = _defDatabase; } + return (QSqlDatabase::contains(iString::ToQt(name))); +} + +/** + * @brief Checks if the database resource is persistant + * + * This method tests the database to determine if the connection is persistant. + * Persistance means that the connection to the database remains open. A + * databases persistant state is maintained in this object by holding a + * reference to it. + * + * @param dbname Name of the database to check persistance status + * + * @return bool True if the database is persistant, otherwise false + */ +bool DatabaseFactory::isPersistant(const std::string &dbname) const { + return (_dbList.exists(dbname)); +} + + +/** + * @brief Create a database using the named driver + * + * This method creats a database connection using the specified driver. The + * driver should be one of the available drivers as identified by the + * isDriverAvailable() method. + * + * The caller provides a name of the database created by this method. This name + * is arbitrary and can be anything meaningful to the caller of this method. IT + * is intended (and required) for use of named connections that are retained for + * future use in this object. + * + * @param driver Name of database driver to instantiate for the connection + * @param dbname Name of the database connect provided by the caller + * + * @return QSqlDatabase A named Qt database object created with the specifed + * driver + */ +QSqlDatabase DatabaseFactory::create(const std::string &driver, + const std::string &dbname) { + // Check driver availability + if (!isDriverAvailable(driver)) { + string mess = "Driver [" + driver + "] for database [" + dbname + + "] does not exist"; + throw iException::Message(Isis::iException::Programmer, mess, _FILEINFO_); + } + + // Create the database with the specified driver and name + Drivers drivers = getResourceList(true,false); + return (QSqlDatabase::addDatabase(iString::ToQt(drivers.get(driver)), + iString::ToQt(dbname))); +} + +/** + * @brief Create a database connection from a named resource + * + * This method is used to create a database from an existing resource. This + * typically will be a database source that has been added using the add() + * method. It provides persistant connections from this object. + * + * @param dbname Name of database resource + * + * @return QSqlDatabase A Database object + */ +QSqlDatabase DatabaseFactory::create(const std::string &dbname) { + + // Return an existing connection + if (_dbList.exists(dbname)) { + return (_dbList.get(dbname)); + } + + // One doesn't exist, throw an error + string mess = "Database [" + dbname + "] does not exist"; + throw iException::Message(Isis::iException::Programmer, mess, _FILEINFO_); +} + +/** + * @brief Adds the database to the connection pool making it persistant + * + * This method can be called after the create() method, handing back the created + * database object. In effect, this creates a copy of the database in its + * current state and makes it available to subsquent create(name) calls. + * + * If one calls create() and does not add the database using this method, then + * the database is destroyed/deallocated when it goes out of scope or no longer + * has a reference to it. + * + * Adding a database to the connection pool using this method essentially makes + * it persistant and available for subsquent use. + * + * @param db Database object to add to pool + * @param name Name to associate with the object + * @param setAsDefault True if this is to become the default connection + */ +void DatabaseFactory::add(const QSqlDatabase &db, const std::string &name, + bool setAsDefault) { + _dbList.add(name, db); + if (setAsDefault) { _defDatabase = name; } + return; +} + +/** + * @brief Removes the database from the connection pool and destroys it + * + * This method should be invoked only after add() has been called with the named + * database. It is removed from the connection pool and destroyed terminating + * any persistant connection it may have had. + * + * Other references to this database are invalidated. + * + * @param name Name of the database to remove + */ +void DatabaseFactory::destroy(const std::string &name) { + remove(name); + QSqlDatabase::removeDatabase(iString::ToQt(name)); + return; +} + +/** + * @brief Removes the database from the connection pool + * + * This method removes the named database from the connection pool making it a + * non-persistant database connection. References to the database are still + * valid until they are destroyed in the callers environment. + * + * @param name Name of database to remove from the connection pool + */ +void DatabaseFactory::remove(const std::string &name) { + _dbList.remove(name); +#if 0 + if (iString::Equal(name,_defDatabase)) { + _defDatabase = ""; + } +#endif + return; +} + +/** + * @brief Initializes this object upon instantiation + * + * This method is called to initialize the database pool. This includes loading + * any explicit database drivers and loading database access profiles. + * + */ +void DatabaseFactory::init() { + // Add the PostgreSQL database driver explicitly if it doesn't exist + loadDrivers(); + + // Use the users Preferences to determine if a default exists + initPreferences(); + return; +} + +/** + * @brief Initializes user database preferences + * + * This method is typically called once at object instantiation. It references + * Isis user preferences and loads database access specific profiles. The + * access profiles and their associated database configuration parameters + * establish named databases with access paramters. + * + * See the main DatabaseFactory documentation for details. + */ +void DatabaseFactory::initPreferences() { + Preference &userPref = Preference::Preferences(); + if (userPref.HasGroup("Database")) { + PvlGroup &dbgroup = userPref.FindGroup("Database"); + if (dbgroup.HasKeyword("AccessConfig")) { + addAccessProfile(dbgroup["AccessConfig"]); + } + // Get default profile name for later use + if (dbgroup.HasKeyword("DefaultProfile")) + _defProfName = (string) dbgroup["DefaultProfile"]; + } + return; +} + +/** + * @brief Get a list of available database drivers and connections + * + * This method can be called at any time to return a list of available database + * drivers and current connections. These data may change over the lifetime of + * an application. It returns a snapshot of whats available. + * + * One thing this method does in adds formal database names for known Qt drivers + * that access them. This provides a generic interface to users needing + * connections to specific databases. + * + * @param drivers If true, return a list of database drivers + * @param connections If true, return a list of existing connections + * + * @return DatabaseFactory::Drivers Returns a list of the requested resources + */ +DatabaseFactory::Drivers DatabaseFactory::getResourceList(bool drivers, + bool connections) + const { + QStringList dblist; + if (drivers) dblist += QSqlDatabase::drivers(); + if (connections) dblist += QSqlDatabase::connectionNames(); + Drivers dbDrivers; + for (int i = 0 ; i < dblist.size() ; i++) { + string dbname(iString::ToStd(dblist.at(i))); + dbDrivers.add(dbname,dbname); + } + + + // Now create pseudonyms for well known databases + // PostgreSQL and UPC + if (dbDrivers.exists("QPSQL")) { + dbDrivers.add("PostgreSQL", "QPSQL"); + } + + // MySQL and HiCAT + if (dbDrivers.exists("QMYSQL")) { + dbDrivers.add("MySQL", "QMYSQL"); + } + + // Oracle + if (dbDrivers.exists("QOCI")) { + dbDrivers.add("Oracle", "QOCI"); + } + + // SQLite + if (dbDrivers.exists("QSQLITE")) { + dbDrivers.add("SQLite", "QSQLITE"); + } + + // That's it + return (dbDrivers); +} + +/** + * @brief Load any drivers explicity + * + * This method is intended to be invoked at object instantiation to load + * database drivers explicitly. + * + * At this time, we are relying on Qt database driver plugins to provide this + * resource. + */ +void DatabaseFactory::loadDrivers() { + // Currently relying on Qt plugins - but that could change + return; +} + +/** + * @brief Destroy all elements associated with this object + * + * This method deletes the singleton reference of this object and removes all + * persistant existing database connections. It is typically executed when the + * application is terminated but can be invoked safely under other conditions. + */ +void DatabaseFactory::selfDestruct() { + while (_dbList.size() > 0) { + _dbList.remove(_dbList.key(0)); + } + QStringList dblist = QSqlDatabase::connectionNames(); + for (int i = 0 ; i < dblist.size() ; i++) { + QSqlDatabase::removeDatabase(dblist[i]); + } + return; +} + +} diff --git a/isis/src/database/objs/DatabaseFactory/DatabaseFactory.h b/isis/src/database/objs/DatabaseFactory/DatabaseFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..1c419d472ac70ca18170d96fd1fb34b1c80c3be2 --- /dev/null +++ b/isis/src/database/objs/DatabaseFactory/DatabaseFactory.h @@ -0,0 +1,360 @@ +#if !defined(DatabaseFactory_h) +#define DatabaseFactory_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/11/27 23:09:58 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include + +#include "CollectorMap.h" +#include "iException.h" + +namespace Isis { + +class DbAccess; +class DbProfile; + +/** + * @brief Create database interfaces using access profiles or generic drivers + * + * This class provides two major components for database programming: database + * drivers and access profiles. This class is implemented as a Singleton (see + * GoF Design Patterns). As such, it serves as a single access point for + * drivers and profiles. It should become clear why database access profiles + * are also provided in this class after reading the subsequent documentation. + * + * This class creates Qt QSqlDatabase objects and subsequent use of the + * resulting objects from this class are dependant on a valid Qt environment. + * At the time this class was developed, Qt provides database drivers as + * plugins and this class assumes they are already available within the Qt + * environment. See the Qt documentation for details on options to provide + * database drivers in the Qt environment. Note, however, that the existance of + * Qt database drivers in not required to build this class or supporting + * classes. Proper use of instantiated classes does require database drivers to + * exist in the Qt environment. + * + * The names of the Qt drivers is an issue. Qt names their drivers obscurely so + * that it is not readily obvious what, for example, is the MySQL driver name. + * This class uses access profiles, described below, that name the type of + * database you expect to access. This implies the user must know if the + * database is Oracle, PostgreSQL or MySQL and specify the proper name in the + * access profile. The Qt PostgreSQL driver is called \a QPSQL. This class tests + * for the specifc Qt named drivers and adds formal names to the driver list. + * For example, if the \a QPSQL exists, a driver named \a PostgreSQL is also + * added/available. If the MySQL Qt driver, \a QMYSQL, exists, \a MySQL is also + * added to the available drivers. For this reason, it is recommededd that + * access profiles use the formal names instead of the Qt driver names...just + * in case we decided to discontinue use of Qt as the database framework and + * replace it with another. + * + * This factory generates database driver instances whereby access is defined by + * database access profiles. The primary profile is specified in the + * IsisPreferences file in the Database group. Access profiels are established + * by user preferences as read from the $HOME/.Isis/IsisPreferences. In the + * \b Database group, the \b AccessConfig keyword contains a full path to a + * database profile. This file contains a Database object with a AccessConfig + * keyword that specifies the full path to a file that contains database access + * information and optionally a DefaultProfile that indicates the default + * profile to use when creating an unnamed database. Note that the database + * profile file may also indicate a default, but the value of DefaultProfile + * overrides this default so certain applications and uses can govern behavior + * if needed. + * + * The intended strategy behind this design is to allow the profile file to + * specify the read only access configuration to the database. An unnamed + * request to create a database will use the named default and create a driver + * to the requesting application when accessing a database. If an application + * is designed to update the contents of the database, the user can specify the + * access to the database and specify the name of the profile in the profile + * file that provides write access to the database. The DefaultProfile keyword + * in the database group is used to specify the name of the profile. + * + * Below is an example of a Database group contained within your personal + * IsisPreferences file describing the location of the Database access profile + * file is and a commented example of how to specify the default profile to use + * when an unnamed database instantiation is requested: + * + * @code + * ######################################################## + * # Customize the database configuration upon startup + * # of any database type application + * ######################################################## + * Group = Database + * AccessConfig = $HOME/.Isis/database/upc.conf + * # DefaultProfile = upc + * EndGroup + * @endcode + * + * The specification of AccessConfig indicates the file that this object reads + * when it is instantiated. The file, in this case, upc.conf, should contain + * a Database object and one or more Profile Groups. Although DefaultProfile is + * commented, it is also reflected in the profile file as illustrated below. If + * the user wants write or update access, he could simple set the value of + * \b DefaultProfile to \b UpcWrite, uncomment it and the \b UpcWrite profile + * then becomes the default database connection. + * + * Below is an example of the contents of a database access configuration + * profile file: + * @code + * Object = Database + * Name = UPC + * Dbname = upc + * Type = PostgreSQL + * Host = "upcdb0.wr.usgs.gov" + * Port = 3309 + * Description = "UPC provides GIS-capable image searches" + * AlternateHosts = "upcdb1.wr.usgs.gov" + * DefaultProfile = Upc + * + * Group = Profile + * Name = Upc + * User = "upcread" + * Access = ReadOnly + * Password = "public" + * EndGroup + * + * Group = Profile + * Name = UpcWrite + * User = "upcwrite" + * Access = Update + * EndGroup + * + * Group = Profile + * Name = UpcAdmin + * User = "upcmgr" + * Access = Admin + * EndGroup + * EndObject + * @endcode + * + * Not all the keywords are critical/required but some are needed in order to + * sucessfully acquire access to a specified database. The \b Dbname keyword is + * needed to specify the name of the database to access. Options include + * \b User which specifies the name of the database user that provides access to + * the database; \b Password is an optional password if the user account + * requires one - note that under most conditions, it is unwise to reveal a + * password in this fashion. It is only advisable if the database user has read + * only access specified in its access conditions or if file permissions are set + * such that no other user can see the contents, which is still not advised. + * Users can utilize other access methods, such as environment variables, or + * whatever the database access system provides. FOr example, PostgreSQL uses + * the + *
    libpq + * library and it has some additional access provisions. You could set + * + * environment variables or use the + * + * password file to create a more secure access scheme. Check your database + * documentations for additional access options; \b Host is used to provide the + * name of the dababase host computer. And \b Port specifies a specific port + * number to use to connect. See the Qt QSqlDatabase documentation for access + * specifics. This access scheme is used directly in this class. + * + * When selecting a specific Profile from within the Database object, all + * keywords in the Database object are first copied to a new Profile. Then the + * requested Profile is merged with new profile and given the name of the group + * profile. Under this scenario, it is intended to provide a cascading hierarchy + * of access parameters, whereby the Profile keywords take precendence. For any + * keywords that exist in both the Database object section and the specfied + * profile, the keywords in the Profile group replace those in the Database + * section. In the above example, the keyword \b Name exists in both the + * Database section and each Profile group. When the default profile \b Upc is + * selected, the \b Name keyword in the Profile group eith the value \b Upc + * replaces the one in the Database section that has the value \b UPC. + * + * For example the code to select the \b Upc profile is: + * + * @code + * DatabaseFactory *factory = DatabaseFactory::instance(); + * DbProfile upc = factory->getProfile("upc"); + * @endcode + * + * Using the above example configuration scheme, the resulting \b Upc profile + * looks like this: + * + * @code + * Group = Profile + * Name = Upc + * Dbname = upc + * Type = PostgreSQL + * Host = "upcdb0.wr.usgs.gov" + * Port = 3309 + * Description = "UPC provides GIS-capable image searches" + * AlternateHosts = "upcdb1.wr.usgs.gov" + * DefaultProfile = Upc + * User = "upcread" + * Access = ReadOnly + * Password = "public" + * EndGroup + * @endcode + * + * This allows each Profile group to change any or all access parameters, even + * the type of database (PostgreSQL to MySQL, for example) it needs. + * + * When the DatabaseFactory is invoked for the first time, the users preference + * file is loaded and the default Database AccessConfig file is read. It + * governs all further access unless the programmer specifically codes its own + * access parameters, which is still possible through this class. + * + * This is an example using this class to craft explicit access to a database + * named \b upc: + * @code + * DatabaseFactory *factory = DatabaseFactory::getInstance(); + * QSqlDatabase upc = factory->create("Postgresql", "upctest"); + * upc.setHostName("upcdb0"); + * upc.setUserName("upcread"); + * upc.setPassword("public"); + * upc.setDatabaseName("upc"); + * if (upc.open()) { + * QSqlQuery query("SELECT * FROM pg_tables where schemaname = 'public'", + * upc); + * } + * @endcode + * In the above example, a database driver for PostgreSQL is created with the + * name "upctest". Access parameters are set explicitly and a query is issued + * if access is successful. Note that access schemes supported by targeted + * databases apply. For example, PostgreSQL will utilize environment variables + * to supply some access parameters. MySQL and PostgreSQL also utilize a + * configuration file whereby access can be acheived through variables set + * there. These combinations should supply adequate options to provide flexible + * options for accessing databases within the Isis system. + * + * See the Database class for an example of using a specific profile to provide + * access to a database. + * + * @ingroup Database + * @author 2006-08-18 Kris Becker + * + * @history 2007-06-05 Brendan George - Modified to work with + * iString/StringTools merge + * @history 2009-11-27 Kris Becker - Made argc parameter for QCoreApplication so + * persistence of the parameter is preserve as required for Qt. + */ + class DatabaseFactory { + public: + static DatabaseFactory *getInstance(); + + /** + * @brief Sets the default name of the database + * + * This method defines the name of the database to use when none is + * specifed in subsequent calls to the create methods. This is typically + * a named profile, but could be a database driver as well as they are + * used in the same context. + * + * @param name Name of the default database + */ + void setDefault(const std::string &name) {_defDatabase = name; } + + /** + * @brief Returns the name of the default database + * + * This method returns the name of the current default database. If a + * call to the create method is attempted without a name, this is the one + * used to return an instance of database. + * + * @return std::string Name of default database + */ + std::string getDefault() const { return (_defDatabase); } + + bool addAccessProfile(const std::string &profileFile); + void addProfile(const DbProfile &profile); + std::vector getProfileList() const; + DbProfile getProfile(const std::string &name = "") const; + + /** + * @brief Returns the name of the default profile + * + * If a default profile name has been established this will return the + * name of the default profile. If none are loaded, an empty string is + * returned. + * + * @return std::string Name of default profile, empty if undetermined + */ + std::string getDefaultProfileName() const { return (_defProfName); } + + /** + * @brief Sets the default profile to the name provided + * + * This allows the calling environment to establish the default database + * access profile by name. It returns true if the named profile exists + * within the current list of profiles, false if it doesn't; + * + * @param name Name of the new default database access profile + * + * @return bool True if it named profile exists, false otherwise + */ + bool setDefaultProfileName(const std::string &name) { + _defProfName = name; + return (_profiles.exists(name)); + } + + std::vector available() const; + bool isDriverAvailable(const std::string &driver) const; + bool isAvailable(const std::string &dbname = "") const; + bool isConnected(const std::string &dbname) const; + bool isPersistant(const std::string &name) const; + + QSqlDatabase create(const std::string &driver, const std::string &dbname); + QSqlDatabase create(const std::string &name); + void add(const QSqlDatabase &db, const std::string &name, + bool setAsDefault = false); + void remove(const std::string &dbname); + void destroy(const std::string &dbname); + + private: + // Gain access through Singleton interface + DatabaseFactory(); + ~DatabaseFactory (); + + static void DieAtExit(); + + static DatabaseFactory *_factory; //!< Pointer to self (singleton) + + /** Define list of drivers and/or databases */ + typedef CollectorMap Drivers; + /** Define list of Profiles */ + typedef CollectorMap Profiles; + /** Define active database maintainer */ + typedef CollectorMap Databases; + + std::string _defProfName; //!< Default profile name + Profiles _profiles; //!< Maintain list of profiles + std::string _defDatabase; //!< Name of default database + Databases _dbList; //!< Maintains active databases + + void init(); + void initPreferences(); + void loadDrivers(); + Drivers getResourceList(bool drivers, bool connections) const; + void selfDestruct(); + + }; +} +#endif + + + diff --git a/isis/src/database/objs/DatabaseFactory/DatabaseFactory.truth b/isis/src/database/objs/DatabaseFactory/DatabaseFactory.truth new file mode 100644 index 0000000000000000000000000000000000000000..0943cb65ccd45bddfb388b6a273e6550b444cd60 --- /dev/null +++ b/isis/src/database/objs/DatabaseFactory/DatabaseFactory.truth @@ -0,0 +1,22 @@ +Default name: default profile +Add access profile: 0 +Adding a couple profiles... +Default profile name: +Setting a default name... 0 +Default profile name: default name +Driver available [doesntexist]: 0 +Driver available [mysql]: 1 +Driver available [postgresql]: 1 +Driver available [sqlite]: 1 +Is Available: 0 +Is connected: 0 +Is persistant: 0 +Attempting to create a database connection +**PROGRAMMER ERROR** Database [doesntexist] does not exist +Adding a database... Done. +Attempting to create a database connection... Done. +Is Available: 0 +Is connected: 0 +Is persistant: 1 +Removing database... Done. +Destroying database... Done. diff --git a/isis/src/database/objs/DatabaseFactory/Makefile b/isis/src/database/objs/DatabaseFactory/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0bca8f36d5125516f9b0212bee22187eaaf86e0f --- /dev/null +++ b/isis/src/database/objs/DatabaseFactory/Makefile @@ -0,0 +1,6 @@ +INCS = DatabaseFactory.h +SRCS = DatabaseFactory.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/database/objs/DatabaseFactory/unitTest.cpp b/isis/src/database/objs/DatabaseFactory/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f96ddf2b6f68699e8d0b143946f286f74381e649 --- /dev/null +++ b/isis/src/database/objs/DatabaseFactory/unitTest.cpp @@ -0,0 +1,80 @@ +#include "DbProfile.h" +#include "Database.h" +#include "DatabaseFactory.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + DatabaseFactory *df = DatabaseFactory::getInstance(); + DbProfile p0("default profile"); + DbProfile p1("test profile 1"); + DbProfile p2("test profile 2"); + df->setDefault("default profile"); + cout << "Default name: " << df->getDefault() << endl; + cout << "Add access profile: " << df->addAccessProfile("profile") << endl; + cout << "Adding a couple profiles..." << endl; + df->addProfile(p1); + df->addProfile(p2); + vector strings = df->getProfileList(); +/* Removed to keep from having to change truth data every install. + * Added specific checks below for databases we care about. + for(int i = 0; i < (int)strings.size(); i++) { + cout << "Profile list: " << strings[i] << endl; + }*/ + + DbProfile dup = df->getProfile("test profile 1"); + + cout << "Default profile name: " << df->getDefaultProfileName() << endl; + cout << "Setting a default name... "; + cout << df->setDefaultProfileName("default name") << endl; + cout << "Default profile name: " << df->getDefaultProfileName() << endl; + + vector available = df->available(); + cout << "Driver available [doesntexist]: " << df->isDriverAvailable("doesntexist") << endl; + cout << "Driver available [mysql]: " << df->isDriverAvailable("mysql") << endl; + cout << "Driver available [postgresql]: " << df->isDriverAvailable("postgresql") << endl; + cout << "Driver available [sqlite]: " << df->isDriverAvailable("sqlite") << endl; + cout << "Is Available: " << df->isAvailable("doesntexist") << endl; + cout << "Is connected: " << df->isConnected("doesntexist") << endl; + cout << "Is persistant: " << df->isPersistant("doesntexist") << endl; + + try { + cout << "Attempting to create a database connection" << endl; + df->create("doesntexist"); + } + catch(iException &e) { + e.Report(false); + } + + Database d; + cout << "Adding a database... "; + df->add(d, "test db", true); + cout << "Done." << endl; + + try { + cout << "Attempting to create a database connection... "; + df->create("test db"); + cout << "Done." << endl; + } + catch(iException &e) { + e.Report(false); + } + + cout << "Is Available: " << df->isAvailable("test db") << endl; + cout << "Is connected: " << df->isConnected("test db") << endl; + cout << "Is persistant: " << df->isPersistant("test db") << endl; + + cout << "Removing database... "; + df->remove("test db"); + cout << "Done." << endl; + cout << "Destroying database... "; + df->destroy("test db"); + cout << "Done." << endl; + + + return 0; +} diff --git a/isis/src/database/objs/DbAccess/DbAccess.cpp b/isis/src/database/objs/DbAccess/DbAccess.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e3b98b01132b101c266fa3bad84f496a6e81a5a --- /dev/null +++ b/isis/src/database/objs/DbAccess/DbAccess.cpp @@ -0,0 +1,216 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/06/06 00:35:33 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include + +using std::string; +using std::ostringstream; + +#include "DbAccess.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "PvlObject.h" +#include "iString.h" + +namespace Isis { + +/** + * @brief Construct with a given database access configuration file + * + * This constructor accepts the name of a Pvl formatted file that must contain a + * object named \b Database. It loads keywords in the order they occur in the + * object. Keywords should be unique - if not, previous keywords are silently + * replaced by subsequent occuring keywords. + * + * Then all groups named \b Profile are loaded and established as additional, + * distinct access profiles. They all should have unique names. Subsequent + * profiles with the same name are replaced. + * + * The caller may additionally provide the name of the default profile to use + * when none is given. If one is not provided, then should a keyword called + * \b DefaultProfile is searched for and the value of this keyword serves as the + * default profile. See the getProfile() method for details on how this + * situation is resolved. + * + * @param dbaccFile Name of a Pvl formatted file containing the access + * specifications for a database + * @param defProfileName Optional name of the default access profile + */ +DbAccess::DbAccess(const std::string &dbaccFile, + const std::string &defProfileName) : DbProfile("Database"), + _defProfileName(defProfileName), _profiles() { + load(dbaccFile); +} + + +/** + * @brief Constructor that accepts a Database Pvl Object + * + * The functionality of this constructor is exactly the same as file constructor + * except with a PvObject named "Database" as an argument. + * + * @param pvl A Database PvlObject containing access information + * @param defProfileName Optional name of the default profile + */ +DbAccess::DbAccess(PvlObject &pvl, const std::string &defProfileName) : + DbProfile("Database"), _defProfileName(defProfileName), + _profiles() { + load(pvl); +} + +/** + * @brief Retrieves the specified access profile + * + * This method retrieves the named profile. If no name is provided, the default + * profile is returned. + * + * There are two ways to specify the default. The first source of a named + * default comes from within the configuration file. A keyword specified in the + * Database object section named \b DefaultProfile can specify a named profile, + * the value of the Name keyword in a \b Profile group. The second source comes + * from the application programmer. In the constructor call to this object, the + * application programmer can provide a named profile as the default, which + * could ultimately come from the user (interface). + * + * If no default is specified, then only the keywords contained in the Database + * object section of the configuration file is returned when requesting an + * unnamed profile. + * + * @param name Optional name of the profile to return + * + * @return const DbProfile The specified profile. One should test the + * validatity of the profile returned as this is the only indication of + * success. + */ +const DbProfile DbAccess::getProfile(const std::string &name) const + throw (iException &) { + string defName(name); + if (defName.empty()) { + defName = getDefaultProfileName(); + } + else { + if (!_profiles.exists(defName)) { + return (DbProfile(defName)); + } + } + +// We have identified the proper profile + if (_profiles.exists(defName)) { + // Return the composite of this access scheme + return(DbProfile(*this, _profiles.get(defName),defName)); + } + else { + // Return only the high level database access keys and hope it is enough + return (DbProfile(*this, DbProfile(),defName)); + } +} + +/** + * @brief Returns the nth specified DbProfile in the list + * + * This method allows user to iterate through the list of DbProfiles in this + * access scheme. If the caller provides an index that exceeds the number + * contained, an exception is thrown. Use profileCount() to determine the + * number of profiles. + * + * @param nth Zero-based index of profile to return + * + * @return const DbProfile The requested nth profile + */ +const DbProfile DbAccess::getProfile(int nth) const throw (iException &) { + const DbProfile &p = _profiles.getNth(nth); + return(DbProfile(*this, p, p.Name())); +} + +/** + * @brief Loads a Database access configuration file + * + * Given the name of a file, it will open the file using Isis Pvl classes. See + * the load(pvl) class for additonal information what takes place in this + * method. + * + * Note the file may use environment variables. + * + * @param filename Name of Pvl file to open. + */ +void DbAccess::load(const std::string &filename) { + Pvl pvl(filename); + PvlObject db = pvl.FindObject("Database"); + load(db); +} + +/** + * @brief Load a database access profile configuration from a PvlObject + * + * This method loads all keywords found in the Object section of the PvlObject + * and then searches for each Group named Profile. Profile groups contain + * augmentations to the object keywords to add to or replace object level access + * specifications. Each profile group must contain a \b Name keyword to + * uniquely identify the (group) access parameters. + * + * Profiles are loaded and stored in this object for subsequent access. + * + * @param pvl A PvlObject that contains keywords and option Profile groups. + */ +void DbAccess::load(PvlObject &pvl) { + + // Load database keywords + loadkeys(pvl); + + // Get all database user access profiles + PvlObject::PvlGroupIterator group = pvl.FindGroup("Profile", + pvl.BeginGroup(), + pvl.EndGroup()); + while (group != pvl.EndGroup()) { + DbProfile dbgroup(*group); + _profiles.add(dbgroup.Name(), dbgroup); + group = pvl.FindGroup("Profile", ++group, pvl.EndGroup()); + } + return; +} + +/** + * @brief Determine the name of the default profile + * + * This method is called to determine the real name of the default profile as + * predetermined at load time. This determination is made either through the + * default specified in the configuration Database object, the \b DefaultProfile + * keyword, or provided by the application progirammer in the constructor. + * + * @return std::string Name of default profile it it can be determined + * otherwise an empty string is returned. + */ +std::string DbAccess::getDefaultProfileName() const { + if (!_defProfileName.empty()) { + return (_defProfileName); + } + else if (exists("DefaultProfile")) { + return (value("DefaultProfile")); + } + return (string("")); +} + + +} diff --git a/isis/src/database/objs/DbAccess/DbAccess.h b/isis/src/database/objs/DbAccess/DbAccess.h new file mode 100644 index 0000000000000000000000000000000000000000..c54e49ae2f01c5629a3e1d3e10ea607d4607f0f8 --- /dev/null +++ b/isis/src/database/objs/DbAccess/DbAccess.h @@ -0,0 +1,188 @@ +#if !defined(DbAccess_h) +#define DbAccess_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/06/06 00:35:33 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "CollectorMap.h" +#include "DbProfile.h" +#include "iException.h" + +namespace Isis { + + +class PvlObject; + + /** + * @brief DbAccess manages programatic access to a database through profiles + * + * This class reads a Pvl formatted file and constructs access profiles on the + * fly from the contents. It is intended to specify any and all information + * sufficient to establish a database connection in software applications. + * + * The input file to this class is typically created with an editor. It can + * contain any keyword = value combination. It must contain a \b Database + * object and may optionally contain \b Profile groups. The \b Database object + * can contain kewords such as \a User, \a Host, \a DbName, and so forth. Here + * is an example of what the file, named upc.conf, of this type would look + * like: + * + * @code + * Object = Database + * Name = UPC + * Dbname = upc + * Type = PostgreSQL + * Host = "upcdb0.wr.usgs.gov" + * Port = 3309 + * Description = "UPC provides GIS-capable image searches" + * AlternateHosts = "upcdb1.wr.usgs.gov" + * EndObject + * @endcode + * + * The code used to load and access this profile is: + * + * @code + * DbAccess upc("upc.conf"); + * DbProfile default = upc.getProfile(); + * @endcode + * + * Additionally, you can add specific profiles that alter some or all of the + * parameters contained in the Object section of the file. Simply add one or + * more \a Profile groups that grant or specify different access profiles for + * the given database. For example the example below names the Profile + * "upcread" and adds an additional user and password to the profile. + * + * @code + * Object = Database + * Name = UPC + * Dbname = upc + * Type = PostgreSQL + * Host = "upcdb0.wr.usgs.gov" + * Port = 3309 + * Description = "UPC provides GIS-capable image searches" + * AlternateHosts = "upcdb1.wr.usgs.gov" + * DefaultProfile = "upcread" + * + * Group = Profile + * Name = "upcread" + * User = "upcread" + * Password = "public" + * EndGroup + * EndObject + * @endcode + * + * To access this profile, use: + * + * @code + * DbProfile upcread = upc.getProfile("upcread"); + * @endcode + * + * It will look for the \a Name keyword as the specifed named profile. What + * actually happens when the above code is invoked is all the keywords + * contained in the Database object, such as \a Dbname, \a Type, as well as + * \a Name are copied to a new \e dynamic profile named "upcread". Then any + * keywords found in the actual Profile group with Name = "upcread" are copied + * to the newly created dynamic one replacing any existing keywords with the + * ones found in the requested Profile. This ensures precedence is given to + * requested profiles and common parameters in the Database object are + * retained. + * + * @ingroup Utility + * @author 2006-07-01 Kris Becker + * + * @history 2007-06-05 Brendan George - Modified to work with + * iString/StringTool merge + */ + class DbAccess : public DbProfile { + private: + /** Define the container for the DbAccess key word list */ + typedef CollectorMap + ProfileList; + + public: + // Constructors and Destructor + DbAccess() : DbProfile("Database"), _defProfileName(""), _profiles() { } + DbAccess(const std::string &dbaccFile, + const std::string &defProfileName = ""); + DbAccess(PvlObject &pvl, const std::string &defProfileName = ""); + + /** Destructor ensures everything is cleaned up properly */ + virtual ~DbAccess () { } + + /** + * Reports the number of user profiles to access this database + * + * @return int Number access profiles + */ + int profileCount() const { return (_profiles.size()); } + + /** + * Checks existance of a database user profile + * + * @param profile Name of profile to check for existance + * + * @return bool True if the profile exists, false otherwise + */ + bool profileExists(const std::string &profile) const { + return (_profiles.exists(profile)); + } + + const DbProfile getProfile(const std::string &name = "") const + throw (iException &); + const DbProfile getProfile(int nth) const throw (iException &); + + + /** + * Adds a profile to the database profile + * + * Inheritors may add profiles to the user profile list. Note that + * duplicate profiles are not allowed, therefore existing profiles with + * the same name is replaced. + * + * @param profile Profile to add + */ + void addProfile(const DbProfile &profile) { + _profiles.add(profile.Name(),profile); + } + + void load(const std::string &filename); + void load(PvlObject &pvl); + + std::string getDefaultProfileName() const; + + private: + std::string _defProfileName; //!< Name of default profile + ProfileList _profiles; //!< List of profiles + }; + + + + + +} +#endif + + diff --git a/isis/src/database/objs/DbAccess/DbAccess.truth b/isis/src/database/objs/DbAccess/DbAccess.truth new file mode 100644 index 0000000000000000000000000000000000000000..7fbf712e9cca53ce03167287eb89f3588e2047b4 --- /dev/null +++ b/isis/src/database/objs/DbAccess/DbAccess.truth @@ -0,0 +1,20 @@ +Profile count: 0 +Adding a profile... +Profile exist: 1 +Profile count: 1 +Default profile name: +Duplicate profile name: test profile +DbProfile valid: 0 +Size: 0 +Setting name: new name +Adding a key test_key... +Exists (before): 0 +Exists (after): 1 +Size: 1 +Count: 1 +Key: test_key +Value: test value +() operator: test value +**PROGRAMMER ERROR** Requested index (99) out of range + +**I/O ERROR** Unable to open [/tmp/not_a_file] diff --git a/isis/src/database/objs/DbAccess/Makefile b/isis/src/database/objs/DbAccess/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..efc040bf727719558dc50d9cf561f3611ecdcd32 --- /dev/null +++ b/isis/src/database/objs/DbAccess/Makefile @@ -0,0 +1,6 @@ +INCS = DbAccess.h +SRCS = DbAccess.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/database/objs/DbAccess/unitTest.cpp b/isis/src/database/objs/DbAccess/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e62281e0bb9fc12399b514d67fe4cde09c5e5ac6 --- /dev/null +++ b/isis/src/database/objs/DbAccess/unitTest.cpp @@ -0,0 +1,52 @@ +#include "DbAccess.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + DbAccess d; + DbProfile p("test profile"); + + cout << "Profile count: " << d.profileCount() << endl; + cout << "Adding a profile..." << endl; + d.addProfile(p); + cout << "Profile exist: " << d.profileExists("test profile") << endl; + cout << "Profile count: " << d.profileCount() << endl; + cout << "Default profile name: " << d.getDefaultProfileName() << endl; + DbProfile dup = d.getProfile(0); + cout << "Duplicate profile name: " << dup.Name() << endl; + + cout << "DbProfile valid: " << p.isValid() << endl; + cout << "Size: " << d.size() << endl; + cout << "Setting name: "; + d.setName("new name"); + cout << d.Name() << endl; + cout << "Adding a key test_key..." << endl; + cout << "Exists (before): " << d.exists("test_key") << endl; + d.add("test_key", "test value"); + cout << "Exists (after): " << d.exists("test_key") << endl; + cout << "Size: " << d.size() << endl; + cout << "Count: " << d.count("test_key") << endl; + cout << "Key: " << d.key(0) << endl; + cout << "Value: " << d.value("test_key") << endl; + cout << "() operator: " << d("test_key") << endl; + + try { + d.getProfile(99); + } + catch(iException &e) { + e.Report(false); + } + + try { + d.load("/tmp/not_a_file"); + } + catch(iException &e) { + e.Report(false); + } + + return 0; +} diff --git a/isis/src/database/objs/DbProfile/DbProfile.cpp b/isis/src/database/objs/DbProfile/DbProfile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9c1da2d174df9ae324e86a6abd3d1cc555f48ce --- /dev/null +++ b/isis/src/database/objs/DbProfile/DbProfile.cpp @@ -0,0 +1,228 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/09/06 06:47:48 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include + +using std::string; +using std::ostringstream; + +#include "DbProfile.h" +#include "PvlGroup.h" + +namespace Isis { + +/** + * @brief Creates a DbProfile from a Pvl entity + * + * This constructor will create a DbProfile by reading keywords from a Pvl + * container. Pvl Containers can be an Object or a Group, or simply a list of + * keywords. This PvlContainer is expected to point to the appropriate keywords + * that the caller has pre-established by normal Isis Pvl methods. + * + * @param pvl Pvl container of keywords to make a DbProfile from + */ +DbProfile::DbProfile(PvlContainer &pvl) : _name("Profile"), _keys() { + loadkeys(pvl); + if (_keys.exists("Name")) { + _name = value("Name"); + } +} + + +/** + * @brief Creates a profile from the merging of two a DbProfiles + * + * This constructor will create a new DbProfile from two existing DbProfiles. + * Its intended use is for the merging of keys in an ordered fashion. It is + * useful when a higher level class inherits this class and a specific + * implementations calls for the keys to come from both the parent and the child + * DbProfile. + * + * It should be noted that this is a convenient way to merge high level + * database access parameters with individual profile access where the last keys + * take precedence over the first. Thus, in the case where the same keys exist + * in both the first and second profiles, keys in the second profile take + * precedence. This is great for defining general database parameters in the + * top level database configure section and having individual profiles redefine + * certain access parameters. + * + * @param name Name of new profile + * @param prof1 First profile to merge + * @param prof2 Second profile to merge + */ +DbProfile::DbProfile(const DbProfile &prof1, const DbProfile &prof2, + const std::string &name) : _name(prof1.Name()), + _keys(prof1._keys) { + for (int nk = 0 ; nk < prof2._keys.size() ; nk++) { + _keys.add(prof2._keys.key(nk),prof2._keys.getNth(nk)); + } + + if (!name.empty()) { _name = name; } +} + + +/** + * Adds a keyword and value pair to the profile + * + * This method adds a keyword and value pair to the profile if it doesn't exist. + * If the keyword already exists,it appends the value to the existing keyword. + * + * @param key Keyword to add or ammend + * @param value Value to add to the keyword + */ +void DbProfile::add(const std::string &key, const std::string &value) { + if (_keys.exists(key)) { + _keys.get(key).AddValue(value); + } + else { + _keys.add(key, PvlKeyword(key,value)); + } +} + +/** + * Adds a keyword and value pair to the profile + * + * This method adds a keyword and value pair to the profile if + * it doesn't exist. + * + * If the keyword already exists, it is deleted and replaced + * with this new keyword and value. + * + * @param key Keyword to replace + * @param value Value to add to the keyword + */ +void DbProfile::replace(const std::string &key, const std::string &value) { + _keys.add(key, PvlKeyword(key,value)); +} + + +/** + * Removes a keyword from the profile + * + * @param key Keyword to remove + */ +void DbProfile::remove(const std::string &key) { + _keys.remove(key); +} + +/** + * Report number of values in keyword + * + * This method will return the number of values in the specified keyword. If + * the keyword does not exist, 0 is returned. + * + * @param key Name of key to get value count for + * + * @return int Number values in key, or 0 if the key does not exist + */ +int DbProfile::count(const std::string &key) const { + if (_keys.exists(key)) { + return (_keys.get(key).Size()); + } + return (0); +} + +/** + * Returns the specified value for the given keyword + * + * This method returns a value from the specified keyword. If the keyword or + * the specified value does not exist, an exception is thrown. + * + * @param key Name of keyword to return value for. + * + * @param nth Specifies the nth value in the keyword + * + * @return std::string The requested value in the keyword + */ +std::string DbProfile::value(const std::string &key, int nth) const { + try { + return (_keys.get(key)[nth]); + } catch ( iException &ie ) { + ostringstream mess; + mess << "Error fetching value from key " << key; + if ( nth != 0 ) { + mess << " (index=" << nth << ")"; + } + ie.Message(iException::Programmer, mess.str(), _FILEINFO_); + throw; + } +} + +/** + * Returns the specified value for the given keyword + * + * This method returns a value from the specified keyword. If the keyword or + * the specified value does not exist, an exception is thrown. + * + * @param key Name of keyword to return value for. + * + * @param nth Specifies the nth value in the keyword + * + * @return std::string The requested value in the keyword + */ +std::string DbProfile::operator()(const std::string &key, int nth) const { + return (value(key,nth)); +} + +/** + * @brief Loads DbProfile keys from the given Pvl construct + * + * This method iterates through all keywords in the Pvl container and loads them + * into this property. + * + * @param pvl Container of keywords that will be loaded + */ +void DbProfile::loadkeys(PvlContainer &pvl) { + PvlContainer::PvlKeywordIterator key; + for (key = pvl.Begin() ; key != pvl.End() ; ++key) { + _keys.add(key->Name(), *key); + } +} + +#if 0 +void DbProfile::printOn(std::ostream &o) const { + + // Create the ordered list of keywords + typedef CollectorMap OrderedKeys; + OrderedKeys okeys; + DbProfileKeyList::CollectorConstIter keys; + for (keys = begin() ; keys != end() ; ++keys) { + const DbProfileKey &pk = keys->second; + okeys.add(pk._index, &pk.key); + } + + // Now write the keys in order + PvlGroup propGroup(_group); + OrderedKeys::CollectorConstIter okItr; + for (okItr = okeys.begin() ; okItr != okeys.end() ; ++okItr) { + propGroup.AddKeyword(*(okItr->second)); + } + + o << propGroup << std::endl; +} +#endif + + +} diff --git a/isis/src/database/objs/DbProfile/DbProfile.h b/isis/src/database/objs/DbProfile/DbProfile.h new file mode 100644 index 0000000000000000000000000000000000000000..c1bb8958cada39a8578befa7ce10b1395d488279 --- /dev/null +++ b/isis/src/database/objs/DbProfile/DbProfile.h @@ -0,0 +1,172 @@ +#if !defined(DbProfile_h) +#define DbProfile_h +/** + * @file + * $Revision: 1.7 $ + * $Date: 2008/09/06 06:47:48 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "PvlKeyword.h" +#include "PvlContainer.h" +#include "CollectorMap.h" +#include "iException.h" + +namespace Isis { + +/** + * @brief A DbProfile is a container for access parameters to a database + * + * This class provides a utility for (keyword) parameter management to access a + * database system. Profiles can be used to specify all parameters necessary + * to apply to programatic interfaces to database software such as Qt's SQL + * Module class, QSqlDatabase. + * + * Using QSqlDatabase as an example, keywords such as \a User, \a Host, \a Port, + * and \a Dbname can be stored in this object and retrieved easily. + * + * It can be easily adapted to any database software API by externally managing + * the contents of a configuration file. See DbAccess for additional details on + * how this scheme can be utilized. + * + * @ingroup Utility + * @author 2006-11-09 Kris Becker + * + * @internal + * @history 2007-02-15 Kris Becker - Added key() method so one can iterate + * through all keys in the profile + * @history 2007-12-19 Kris Becker - Added getKeyList method for additional + * flexibility to class developers + * @history 2008-03-11 Kris Becker - Added more information to exception + * caught when attempting to get values from non-existant keys + * @history 2008-09-05 Kris Becker - Added the replace and remove methods to + * the class. + */ + class DbProfile { + + protected: + /* Container for multi-valued keywords in profiles */ + typedef CollectorMap KeyList; + + public: + // Constructors and Destructor + DbProfile() : _name("Profile"), _keys() { } + DbProfile(const std::string &name) : _name(name), _keys() { } + DbProfile(const DbProfile &prof1,const DbProfile &prof2, + const std::string &name= ""); + DbProfile(PvlContainer &pvl); + + + /** Destructor ensures everything is cleaned up properly */ + virtual ~DbProfile () { } + + /** + * @brief Reports if this is a valid profile + * + * A valid profile is simply defined to contain keys. If there are no + * keys defined for the profile, it is deemed invalid. + * + * @return bool True if the profile is valid, therefore containing keys + */ + bool isValid() const { return (size() > 0); } + + /** + * Reports the number of keywords in this user profile + * + * @return int Number keywords found in profile + */ + int size() const { return (_keys.size()); } + + /** + * Set the name of this profile + * + * @param name iString used to set the name of this profile + */ + void setName(const std::string &name) { _name = name; } + + /** + * @brief Returns the name of this property + * + * @return std::string Name of this property + */ + std::string Name() const { return (_name); } + + /** + * Checks for the existance of a keyword + * + * @param key Name of keyword to check + * + * @return bool True if it exists, false if it doesn't + */ + bool exists(const std::string &key) const { return (_keys.exists(key)); } + + // Convenience methods for adding keys + void add(const std::string &key, const std::string &value = ""); + void replace(const std::string &key, const std::string &value = ""); + void remove(const std::string &key); + int count(const std::string &key) const; + + /** + * Returns the nth key in the profile + * + * This method returns the name of the nth keyword in the profile so one + * can iterate through all existing keys. Note that database passwords + * could be vulnerable to exposure via this method. + * + * Keywords in the profile are sorted in alphabetical order and not in the + * order in which they are read. + * + * @param nth Specifies the nth key in the profile + * + * @return std::string Name of nth keyword in the profile. + * + * @throws Out-of-range exception if the nth keyword does not exist + */ + std::string key(int nth) const { return (_keys.key(nth)); } + std::string value(const std::string &key, int nth = 0) const; + std::string operator()(const std::string &key, int nth = 0) const; + + protected: + void loadkeys(PvlContainer &pvl); + + /** + * @brief Returns a reference to the key list + * + * Direct access to the keyword container allows class developers some + * additional flexibility whilst maintaining integrity through the + * public interface. + * + * @return const KeyList& Reference to keyword list + */ + const KeyList &getKeyList() const { return (_keys); } + + private: + std::string _name; //!< Name of this profile + KeyList _keys; //!< List of keys in profile + }; +} + + +#endif + + diff --git a/isis/src/database/objs/DbProfile/DbProfile.truth b/isis/src/database/objs/DbProfile/DbProfile.truth new file mode 100644 index 0000000000000000000000000000000000000000..7a40770373b35d40480b74ed9b78c1a4c2b3ca58 --- /dev/null +++ b/isis/src/database/objs/DbProfile/DbProfile.truth @@ -0,0 +1,15 @@ +Valid: 0 +Size: 0 +Name: test profile +Adding a key... +Valid: 1 +Size: 1 +Count: 1 +Exists: 0 +Exists: 1 +() operator: bar +Value: bar +Test getting non-existing key BadKey +**PROGRAMMER ERROR** Error fetching value from key BadKey +**PROGRAMMER ERROR** Requested value does not exist! +BadKey = \ No newline at end of file diff --git a/isis/src/database/objs/DbProfile/Makefile b/isis/src/database/objs/DbProfile/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d8b2512d6d23a433d1696adefd602410ff2672aa --- /dev/null +++ b/isis/src/database/objs/DbProfile/Makefile @@ -0,0 +1,6 @@ +INCS = DbProfile.h +SRCS = DbProfile.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/database/objs/DbProfile/unitTest.cpp b/isis/src/database/objs/DbProfile/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..73aab005aa1e213066e4fef3ef606bde3c3871b4 --- /dev/null +++ b/isis/src/database/objs/DbProfile/unitTest.cpp @@ -0,0 +1,36 @@ +#include "DbProfile.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + DbProfile p("test profile"); + + cout << "Valid: " << p.isValid() << endl; + cout << "Size: " << p.size() << endl; + p.setName("test profile"); + cout << "Name: " << p.Name() << endl; + cout << "Adding a key..." << endl; + p.add("foo", "bar"); + cout << "Valid: " << p.isValid() << endl; + cout << "Size: " << p.size() << endl; + cout << "Count: " << p.count("foo") << endl; + cout << "Exists: " << p.exists("boo") << endl; + cout << "Exists: " << p.exists("foo") << endl; + cout << "() operator: " << p("foo") << endl; + cout << "Value: " << p.value("foo", 0) << endl; + + cout << "Test getting non-existing key BadKey\n"; + cout.flush(); + try { + cout << "BadKey ="; + cout << p("BadKey") << endl; + } catch ( iException &ie ) { + ie.Report(); + } + + return 0; +} diff --git a/isis/src/database/objs/Makefile b/isis/src/database/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/database/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/database/objs/SqlQuery/Makefile b/isis/src/database/objs/SqlQuery/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f2382f559221e512011990b82adf4896192568fb --- /dev/null +++ b/isis/src/database/objs/SqlQuery/Makefile @@ -0,0 +1,6 @@ +INCS = SqlQuery.h +SRCS = SqlQuery.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/database/objs/SqlQuery/SqlQuery.cpp b/isis/src/database/objs/SqlQuery/SqlQuery.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a259ef513c8c7d8a69f6b843175fcdc92d99f99 --- /dev/null +++ b/isis/src/database/objs/SqlQuery/SqlQuery.cpp @@ -0,0 +1,298 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2008/10/30 16:40:50 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include "DbProfile.h" +#include "Database.h" +#include "iString.h" +#include "SqlQuery.h" +#include "SqlRecord.h" +#include + +using namespace std; + +namespace Isis { + +/** + * @brief Default constructor + * + * This constructor prepares a query using the default database as established + * through the Database class. It will also ensure that on any error, an + * exception is thrown, in line with the Isis way of doing things. + */ +SqlQuery::SqlQuery() : QSqlQuery(Database()), _throwIfFailed(true) { } + +/** + * @brief Construtor using a specified database + * + * This constructor should be used for preparing for queries using a specified + * database. This would be used when using a database other than the default. + * + * Turns exception throwing on. + * + * @param db Database to use for subsequent database queries + */ +SqlQuery::SqlQuery(Database &db) : QSqlQuery(db), _throwIfFailed(true) { } + + +/** + * @brief Construct a query object and execute the provided query string + * + * This constructor will take a query string and an optional database + * specification and execute the query all after the initial construction. If + * the caller does not provide a Database, the default one is used and a + * connection is automatically attempted. + * + * It can be used to execute an initial query and is perhaps the most powerful + * example of the Isis database design. It could be used as the starting point + * for any database access and an initial query in one line of code. For + * example, below is a line of code that executes a line of code showing all the + * tables in a PostgreSQL database using the default database: + * @code + * SqlQuery pgtables("select tblname from pg_tables"); + * @endcode + * + * This will use the Database() default constructor since one is not explicitly + * provide. That constructor attempts a connection using the default database + * access profile as read from your IsisPreferences file. Its default behaviour + * is to initiate the connection to the database. If that suceeds, the query is + * issued. The resulting \a pgtables SqlQuery object can now be contiually used + * for other queries until it goes out of scope. + * + * + * @param query iString containing a valid SQL query to execute + * @param db An optional database object to issue the query to. This + * database now becomes the one used in all subsequent queries + * using this SqlQuery object. + */ +SqlQuery::SqlQuery(const std::string &query, Database db) : QSqlQuery(db), + _throwIfFailed(true) { +// Execute with error detector + exec(query); +} + +/** + * @brief Constructor using an existing SqlQuery object + * + * This constructor creates a new SqlQuery object from an existing one, + * inheriting all its characteristics - including a Database if one is + * associated to the object. + * + * @param other A SqlQuery object used to create this one from + */ +SqlQuery::SqlQuery(const SqlQuery &other) : QSqlQuery(other), + _throwIfFailed(other._throwIfFailed) { } + + +/** + * @brief Execute an SQL query provided in the query string + * + * This method executes the given query in the string. This method assumes this + * query object has a valid and open Database connection associated with it. It + * will also check the result for valid completion and toss an iException if the + * caller has established this course of action when it fails. + * + * Results are ready for processing on completion. + * + * @see SqlRecord. + * + * @param query An SQL query string to issue to a database + * + * @return bool True if successful, false if it fails. This will only return + * valse if setNoThrowOnFailure() has been issued, otherwise an + * iException is thrown if it fails. + */ +bool SqlQuery::exec(const std::string &query) { + bool ok = this->QSqlQuery::exec(iString::ToQt(query)); + if ((!ok) && isThrowing()) { + string mess = "Query \'" + query + "\' failed to execute"; + tossQueryError(mess, _FILEINFO_); + } + return (ok); +} + +/** + * @brief Returns the executed query string + * + * This method returns the last executed query string as it was issued to the + * database. Note that some database systems do not support this option + * directly. This routine will attempt to return the last executed query first + * from the Qt QSqlQuery class. If this is empty/undefined, then the last + * current query will be returned. + * + * @return std::string The last executed query string. If undetermined or + * undefined, an empty string is returned. + */ +std::string SqlQuery::getQuery() const { + std::string lastq = iString::ToStd(lastQuery()); + if (lastq.empty()) lastq = iString::ToStd(executedQuery()); + return (lastq); +} + +/** + * @brief Returns the number of fields (columns) from query + * + * The method returns the number of fields or columns returned by the last + * issued query string. Note that if the query has not been issued, it will + * return 0 or an undefined value (-1?). + * + * \b NOTE this is not valid until \a after the first next() is issued. + * + * @return int Number of fields/columns in last query issued + */ +int SqlQuery::nFields() const { + return (record().count()); +} + +/** + * @brief Returns the column name of the resulting query at the given index + * + * This method returns the name of the column heading as a result of the query + * at the given index. + * + * \b NOTE this is not valid until \a after the first next() is issued. + * + * @param index Zero-based starting index of column name ot retreive + * + * @return std::string Name of column at given index + */ +std::string SqlQuery::fieldName(int index) const { + return (iString::ToStd(record().fieldName(index))); +} + +/** + * @brief Returns index of column for given name + * + * This method returns the index of the given column name. + * + * \b NOTE this is not valid until \a after the first next() is issued. + * + * @param name Name of column to get index for + * + * @return int Zero-based index of named column + */ +int SqlQuery::fieldIndex(const std::string &name) const { + return(record().indexOf(iString::ToQt(name))); +} + +/** + * @brief Returns the names of all fields in the resulting query + * + * After a query has been issued, this method will return the names of all + * fields/columns in the resulting query. + * + * \b NOTE this is not valid until \a after the first next() is issued. + * + * @see SqlRecord::getFieldName(). + * + * @return std::vector Vector of strings of all fields/columns in + * a query. + */ +std::vector SqlQuery::fieldNameList() const { + std::vector fields; + QSqlRecord rec = record(); + for (int i = 0 ; i < rec.count() ; i++) { + fields.push_back(iString::ToStd(rec.fieldName(i))); + } + return (fields); +} + +/** + * @brief Returns the types of each field/column in a resutling query + * + * After a query has been issued, this method will return the types of all + * fields/columns. These types are defined by the SqlRecord::getType() method. + * + * @return std::vector iString vector of all field types. + */ +std::vector SqlQuery::fieldTypeList() const { + std::vector types; + SqlRecord rec = getRecord(); + for (int i = 0 ; i < rec.count() ; i++) { + types.push_back(rec.getType(i)); + } + return (types); +} + +/** + * @brief Returns the count of rows resulting from the query + * + * This returns the number of rows returned/accessable as a result of the issued + * query. Its value is governed by the Qt + * + * QsqlQuery::size() method. Namely, a -1 can be returned under many + * different conditions of the queray and the database (driver) support. Check + * the documentation for details. + * + * @return int Number of rows returned by the query. -1 is typically returned + * under conditions where the value is not available or undefined. + */ +int SqlQuery::nRows() const { + return (size()); +} + +/** + * @brief Returns a SqlRecord for the current query row + * + * While traversing through the resulting query row set, this method returns a + * lower level interface to individual rows. The returned object is provided by + * the SqlRecord class. + * + * \b NOTE this is not valid until \a after the first next() is issued. + * @see SqlRecord. + * + * @return SqlRecord A single resulting row of a query after an next() is + * issued. + */ +SqlRecord SqlQuery::getRecord() const { + return (SqlRecord(*this)); +} + +/** + * @brief Issues an iException from various sources of error states in this + * class. + * + * This method is provided to issue a consistant error message format from this + * class. The user of this class can decide at runtime to issue + * Isis::iException exceptions when error condition or query failures are + * detected or handle the errors themselves. All exceptions go through this + * method for deployment to simplify the process. + * + * Note callers of this method within this class provide the context of the + * error, such as name and line of code, to preserve accuracy of the error + * context. + * + * @see setThrowOnFailure(), setNoThrowOnFailure(). + * + * @param message Context of the error to report + * @param f Routine name issuing the error + * @param l Line number of the offending error + */ +void SqlQuery::tossQueryError(const std::string &message, const char *f, int l) const + throw (iException &) { + string errmess = message + " - QueryError = " + + iString::ToStd(lastError().text()); + throw iException::Message(Isis::iException::User, errmess, f, l); +} + +} diff --git a/isis/src/database/objs/SqlQuery/SqlQuery.h b/isis/src/database/objs/SqlQuery/SqlQuery.h new file mode 100644 index 0000000000000000000000000000000000000000..7a3ecdec06d52b3d27928c59c023a02e01423722 --- /dev/null +++ b/isis/src/database/objs/SqlQuery/SqlQuery.h @@ -0,0 +1,198 @@ +#if !defined(SqlQuery_h) +#define SqlQuery_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/10/30 16:40:50 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "iException.h" +#include "Database.h" +#include +#include + +namespace Isis { + +class SqlRecord; + +/** + * @brief Construct and execute a query on a database and manage result + * + * This class is derived from the + * Qt QSqlQuery class. + * It is designed to be used in conjunction with the functionality of that + * class. + * + * The major features are to to make it easier to specify what happens when + * errors occurs (setThrowOnFailure()) and return and accept query strings and + * results using the standard C++ library and classes (vector, string). It + * exists mainly as a convenience class interface to the Qt QSqlQuery class, + * providing standard C++ elements as opposed to Qt elements. + * + * \b NOTE all constructors initially set exception throwing as the default. + * + * Some examples follow: + * + * This example uses some of Qt's features, which you can use at will throughout + * this and other classes. This one uses the named/positional binding features" + * @code + * Database mptdb("matchpoints"); + * + * // We now have a match point table. Populate it with the data read in. + * SqlQuery inserter(mptdb); + * inserter.setThrowOnFailure(); + * inserter.prepare("INSERT INTO " + * "matchpt (pointid, fsc, line, samp, class, diameter) " + * "VALUES (:pointid, :fsc, :line, :samp, :class,:diameter)"); + * mptdb.transaction(); + * for (int row = 0 ; row < mpt.rows() ; row++) { + * CSVReader::CSVAxis matchpt = mpt.getRow(row); + * for (int i = 0 ; i < 6 ; i++) {* + * inserter.bindValue(i, QVariant(matchpt[i].c_str())); + * } + * cout << "Inserting row " << row << ", status..." << inserter.exec() + * << endl; + * + * } + * mptdb.commit(); + * mptdb.close(); + *} + * @endcode + * + * Thats all well and good but Qt's binding is restricted to using it in the + * INSERT/VALUES constructs. They have no support for binding used outside this + * SQL operation. Below is an example with a more general approach provided + * with this API, although a bit less robust. + * + * @code + * auto_ptr db = auto_ptr (new Database(dbProf, + * Database::Connect)); + * + * SqlQuery finder(*db); + * finder.setThrowOnFailure(); + * string pntDist = "distance(giscpt,UPCPoint(%longitude,%latitude))"; + * string pntQuery = "SELECT pointid, latitude, longitude, radius FROM " + * + pntTable + " WHERE (%distance <= " + iString(maxDist) + + * ")"; + * + * Progress progress; + * progress.SetText("lodbnet"); + * progress.SetMaximumSteps(pnts.rows()); + * for (int row = 0 ; row < pnts.rows() ; row++) { + * CSVReader::CSVAxis pntR = pnts.getRow(row); + * + * // Convert longitude to proper system if requested + * double longitude = iString(pntR[1]).ToDouble(); + * if ((make360) && (longitude < 0.0)) { longitude += 360.0; } + * double latitude = iString(pntR[0]).ToDouble(); + * double radius = iString(pntR[2]).ToDouble(); + * + * // Prepare the query, converting the longitude + * string dcheck(iString::Replace(pntDist, "%longitude", + * iString(longitude))); dcheck = iString::Replace(dcheck, "%latitude", + * iString(latitude)); string query = iString::Replace(pntQuery, "%distance", + * dcheck); + * + * finder.exec(query); + * if (finder.size() > 0) { + * Statistics stats; + * vector pointList; + * while (finder.next()) { + * SqlRecord record = finder.getRecord(); + * OutPoint point; + * point.latitude = iString(record.getValue("latitude")).ToDouble(), + * point.longitude = iString(record.getValue("longitude")).ToDouble(), + * point.radius = iString(record.getValue("radius")).ToDouble(), + * point.pointid = iString(record.getValue("pointid")), + * stats.AddData(&point.radius, 1); + * pointList.push_back(point); + * } + * } + * progress.CheckStatus(); + * } + * + * @endcode + * + * @see iString + * + * @ingroup Database + * + * @author 2006-11-09 Kris Becker + * + * @internal + * @history 2007-04-19 Kris Becker - Reordered return of getQuery() result + * to first try lastQuery(), then + * executedQuery(). + * @history 2007-06-05 Brendan George - Modified to work with + * iString/StringTools merge + * @history 2008-10-30 Steven Lambright - tossQueryError now accepts a const + * char* for a filename, issue pointed out by "novus0x2a" (Support + * Board Member) + */ + class SqlQuery : public QSqlQuery { + public: + SqlQuery(); + SqlQuery(Database &db); + SqlQuery(const std::string &query, + Database db = Database(Database::Connect)); + SqlQuery(const SqlQuery &other); + virtual ~SqlQuery() { } + + /** + * @brief Report error status when executing queries + * + * @return bool True if iExceptions are thrown upon errors, otherwise + * returns false. + */ + bool isThrowing() const { return (_throwIfFailed); } + + /** + * @brief Sets throwing of exceptions on errors to true + */ + void setThrowOnFailure() { _throwIfFailed = true; } + /** + * @brief Turns throwing of iExceptions off on errors + */ + void setNoThrowOnFailure() { _throwIfFailed = false; } + + bool exec(const std::string &query); + bool exec() { return(QSqlQuery::exec()); } + std::string getQuery() const; + + int nFields() const; + std::string fieldName(int index) const; + int fieldIndex(const std::string &name) const; + std::vector fieldNameList() const; + std::vector fieldTypeList() const; + + int nRows() const; + SqlRecord getRecord() const; + + private: + bool _throwIfFailed; //!< User can select action on query results + + void tossQueryError(const std::string &message, const char *f, int l) const + throw (iException &); + }; +} +#endif diff --git a/isis/src/database/objs/SqlQuery/SqlQuery.truth b/isis/src/database/objs/SqlQuery/SqlQuery.truth new file mode 100644 index 0000000000000000000000000000000000000000..afdbba5d5cbc00c3c5b0c92ba129b5d6a129e408 --- /dev/null +++ b/isis/src/database/objs/SqlQuery/SqlQuery.truth @@ -0,0 +1,16 @@ +Is throwing: 1 +Executing CREATE TABLE command: 1 +Query: CREATE TABLE testTable ( v1 TEXT, v2 INTEGER, v3 REAL ); +Executing INSERT command: 1 +Query: INSERT INTO testTable (v1, v2, v3) VALUES ('test txt', 7, 123.4); +Executing SELECT command: 1 +Query: SELECT * FROM testTable; +The mac systems report the double fields as string fields. Until the problematic 3rd party software is fixed, the mac systems will need OS truth data. +0) Name: v1, Type: string +1) Name: v2, Type: int +2) Name: v3, Type: string +Field index (v2): 1 +nFields: 3 +nRows: -1 +Field name[0]: v1 +SqlRecord size: 3 diff --git a/isis/src/database/objs/SqlQuery/unitTest.cpp b/isis/src/database/objs/SqlQuery/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..49f5ef86c83a0422ff5391832ba90ee025036c6e --- /dev/null +++ b/isis/src/database/objs/SqlQuery/unitTest.cpp @@ -0,0 +1,63 @@ +#include "SqlQuery.h" +#include "SqlRecord.h" +#include "Filename.h" +#include "Database.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + Database testdb("testdb", "SQLite"); + testdb.setDatabaseName(":memory:"); + string table = "CREATE TABLE testTable (" + " v1 TEXT," + " v2 INTEGER," + " v3 REAL );"; + string insert = "INSERT INTO testTable (v1, v2, v3) " + " VALUES ('test txt', 7, 123.4);"; + string query = "SELECT * FROM testTable;"; + + if(!testdb.open()) { + iException::Message(iException::User, "Connection failed", _FILEINFO_); + } + + SqlQuery q(testdb); + q.setThrowOnFailure(); + cout << "Is throwing: " << q.isThrowing() << endl; + + try { + cout << "Executing CREATE TABLE command: " << q.exec(table) << endl; + cout << "Query: " << q.getQuery() << endl; + cout << "Executing INSERT command: " << q.exec(insert) << endl; + cout << "Query: " << q.getQuery() << endl; + cout << "Executing SELECT command: " << q.exec(query) << endl; + cout << "Query: " << q.getQuery() << endl; + + } + catch(iException &e) { + e.Report(false); + } + + cout << "The mac systems report the double fields as string fields. " << + "Until the problematic 3rd party software is fixed, " << + "the mac systems will need OS truth data." << endl; + + vector nameList = q.fieldNameList(); + vector typeList = q.fieldTypeList(); + for(int i = 0; i < (int)nameList.size(); i++) { + cout << i << ") Name: " << nameList[i] << ", Type: " << typeList[i] << endl; + } + + cout << "Field index (v2): " << q.fieldIndex("v2") << endl; + cout << "nFields: " << q.nFields() << endl; + cout << "nRows: " << q.nRows() << endl; + cout << "Field name[0]: " << q.fieldName(0) << endl; + SqlRecord record = q.getRecord(); + cout << "SqlRecord size: " << record.size() << endl; + + return 0; +} diff --git a/isis/src/database/objs/SqlRecord/Makefile b/isis/src/database/objs/SqlRecord/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f96051925ce66105b605cfb220880a68bdbd98b6 --- /dev/null +++ b/isis/src/database/objs/SqlRecord/Makefile @@ -0,0 +1,6 @@ +INCS = SqlRecord.h +SRCS = SqlRecord.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/database/objs/SqlRecord/SqlRecord.cpp b/isis/src/database/objs/SqlRecord/SqlRecord.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4c80246d64e68b4aa75c00dc220fd3f4770422c9 --- /dev/null +++ b/isis/src/database/objs/SqlRecord/SqlRecord.cpp @@ -0,0 +1,211 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2007/06/06 00:46:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include + +#include "SqlRecord.h" +#include "SqlQuery.h" +#include "iString.h" + +#include +#include + +using namespace std; + +namespace Isis { + +/** + * @brief Default Constructor + * + * Construct a SqlRecord object with no content. Not very useful, really. + */ +SqlRecord::SqlRecord() : QSqlRecord() { } + +/** + * @brief Construct a SqlRecord from a SqlQuery + * + * This constructor takes a SqlQuery object and constructs an object from the + * current active row. This is only valid after an initial call to the next() + * method in the (derived) SqlQuery class. + * + * @param query A valid SqlQuery with an active row that will be accessable upon + * successful completion of this constructor. + */ +SqlRecord::SqlRecord(const SqlQuery &query) : QSqlRecord(query.record()) { } + +/** + * @brief Indicates the existance/non-existance of a field in the row + * + * This method can be used to determine if a field/column name exists within the + * row. + * + * @param name Name of field/column to test for. This is case insensitive. + * + * @return bool True if the field/column exists, false otherwise. + */ +bool SqlRecord::hasField(const std::string &name) const { + return (contains(iString::ToQt(name))); +} + +/** + * @brief Returns the name of a field/column at a particular index + * + * For valid indexes, the name of the field/colunm is returned. See the Qt + * documentation on precise behavior. + * + * @param index Index of the desired column name to return. + * + * @return std::string Name of the column at the requested index + */ +std::string SqlRecord::getFieldName(int index) const { + return (iString::ToStd(fieldName(index))); +} + +/** + * @brief Return the index of a named field/column + * This method will determine the index of the named field after a query has + * been successfully issued and results have been returned. + * + * @param name Name of field/column to return an index for + * + * @return int Index of the named column + */ +int SqlRecord::getFieldIndex(const std::string &name) const { + return(indexOf(iString::ToQt(name))); +} + +/** + * @brief Returns the type of a named field/column + * + * This method returns the type of a named column. Types are derived from the + * Qt type as defined + * here in + * the QVariant type description. + * + * What is returned is a type as named in the \a Description column of that + * table without the \a Q and the resulting characters returned as a lower case + * string. For example the QVariant::Type of \b QChar is return as \b char. + * The \b double type is returned as is, \b double. + * + * @see QtTypeField(). + * @see getType(int index). + * + * @param name Field/column name to determine type for + * + * @return std::string Type of the field/column + */ +std::string SqlRecord::getType(const std::string &name) const { + QVariant ftype(field(iString::ToQt(name)).type()); + return (QtTypeField(ftype.typeName())); +} + +/** + * @brief Returns the type of a field/column at the specified index + * + * This method returns the type of a columnat the specfied index. Types are + * derived from the Qt type as defined + * here in + * the QVariant type description. + * + * What is returned is a type as named in the \a Description column of that + * table without the \a Q and the resulting characters returned as a lower case + * string. For example the QVariant::Type of \b QChar is return as \b char. + * The \b double type is returned as is, \b double. + * + * @see QtTypeField(). + * @see getType(const std::string &name). + * + * @param index Index of the desired field/column to return type for. + * + * @return std::string Type of the field/column at given index. + */ +std::string SqlRecord::getType(int index) const { + QVariant ftype(field(index).type()); + return (QtTypeField(ftype.typeName())); +} + +/** + * @brief Determines if the value of the field/column is NULL + * + * @param name Name of field/column to check for NULL + * + * @return bool True if NULL, otherwise false. + */ +bool SqlRecord::isNull(const std::string &name) const { + return (field(iString::ToQt(name)).isNull()); +} + +/** + * @brief Returns the value of the field/column at specified index + * + * This method will return the value of the field/column at the index. It is + * returned as a string and conversion handling is left to the caller. + * + * @param index Index of field/column get value from. + * + * @return iString Value of the field/column index. + */ +iString SqlRecord::getValue(int index) const { + return (iString(iString::ToStd(field(index).value().toString()))); +} + +/** + * @brief Returns the value of the named field/column + * + * This method will return the value of the named field/column as a string. It + * is left to the caller to handle ant conversion of the returned type. + * + * @param name Name of the field/column to get value for. + * + * @return iString Value of the named field/column. + */ +iString SqlRecord::getValue(const std::string &name) const { + return (iString(iString::ToStd(field(iString::ToQt(name)).value().toString()))); +} + +/** + * @brief Returns a generic field type given a Qt QVariant type + * + * This routine converts the Qt QVariant + * type to + * a more generic type. It is pretty simplistic in nature at this point. It + * will strip \a Q if it is the first character in the \a Description of the + * type and convert the result to lower case. + * + * @param ctype A Qt QVariant::Type description + * + * @return std::string A generic type for the Qt type. + */ +std::string SqlRecord::QtTypeField(const char *ctype) const { + string retType(""); + if (ctype == 0) { + return (retType); + } + else { + retType = iString::DownCase((tolower(ctype[0]) == 'q') ? &ctype[1] : ctype); + } + return(retType); +} + +} diff --git a/isis/src/database/objs/SqlRecord/SqlRecord.h b/isis/src/database/objs/SqlRecord/SqlRecord.h new file mode 100644 index 0000000000000000000000000000000000000000..9a2f320214d5cc6da4b9608acfbcf8404fdd3f28 --- /dev/null +++ b/isis/src/database/objs/SqlRecord/SqlRecord.h @@ -0,0 +1,92 @@ +#if !defined(SqlRecord_h) +#define SqlRecord_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2007/06/06 00:46:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "iException.h" +#include + +namespace Isis { + +class SqlQuery; +class iString; + +/** + * @brief Provide simplified access to resulting SQL query row + * + * This class is derived from + * Qt's QSqlRecord + * class and is provided for convenience and simplifed use in a standard C++ + * environment. Mainly, it provides strings and values as Standard std::strings + * and other more common C++ constructs as well as taking advantage of some + * unique Isis provisions (e.g., iString). One can still use Qt's rich features + * interchangeably with this class. + * + * SqlRecord is intended to be used by the SqlQuery class provided in this + * interface. + * + * @see SqlQuery. + * + * @ingroup Database + * + * @author 2006-08-18 Kris Becker + * + * @history 2007-06-05 Brendan George - Modified to work with + * iString/StringTools merge + */ + class SqlRecord : public QSqlRecord { + public: + SqlRecord(); + SqlRecord(const SqlQuery &query); + virtual ~SqlRecord() { } + + /** + * @brief Returns the number of fields/columns in query + * + * This result is the number of fields/columns returned in the query as a + * result of the SQL statement issued to generate the resultant row set. + * + * @return int Number of fields/columns in row + */ + int size() const { return (count()); } + + bool hasField(const std::string &name) const; + int getFieldIndex(const std::string &name) const; + std::string getFieldName(int index) const; + + std::string getType(int index) const; + std::string getType(const std::string &name) const; + + bool isNull(const std::string &name) const; + iString getValue(int index) const; + iString getValue(const std::string &name) const; + + private: + std::string QtTypeField(const char *ctype) const; + + }; +} +#endif diff --git a/isis/src/database/objs/SqlRecord/SqlRecord.truth b/isis/src/database/objs/SqlRecord/SqlRecord.truth new file mode 100644 index 0000000000000000000000000000000000000000..7e072c6b2f8a6ae11288dbac71e81f7a92f932cf --- /dev/null +++ b/isis/src/database/objs/SqlRecord/SqlRecord.truth @@ -0,0 +1,12 @@ +v1: test text +v2: 7 +v3: 123.4 +Is null (v1): 0 +Is null (blank): 1 +Size: 3 +Has field(v2): 1 +Field index(v3): 2 +The mac systems report the double fields as string fields. Until the problematic 3rd party software is fixed, the mac systems will need OS truth data. +Col 0) Name: v1, Type: string +Col 1) Name: v2, Type: int +Col 2) Name: v3, Type: string diff --git a/isis/src/database/objs/SqlRecord/unitTest.cpp b/isis/src/database/objs/SqlRecord/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d45dc1533b2addaeda0f75d48d568e8688175b1b --- /dev/null +++ b/isis/src/database/objs/SqlRecord/unitTest.cpp @@ -0,0 +1,69 @@ +#include "Database.h" +#include "Filename.h" +#include "SqlQuery.h" +#include "SqlRecord.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main(int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + // SQLite + Filename dbfile("/tmp/test.db"); + Database testdb("testdb", "SQLite"); + string dbfileName(dbfile.Expanded()); + testdb.setDatabaseName(dbfileName.c_str()); + if(!testdb.open()) { + iException::Message(iException::User, "Connection failed", _FILEINFO_); + } + + string table = "CREATE TABLE testTable (" + " v1 TEXT," + " v2 INTEGER," + " v3 REAL );"; + string insert = "INSERT INTO testTable (v1, v2, v3) " + " VALUES ('test text', 7, 123.4);"; + string query = "SELECT * FROM testTable;"; + SqlQuery create(testdb); + create.setThrowOnFailure(); + + try { + create.exec(table); + create.exec(insert); + create.exec(query); + + while(create.next()) { + SqlRecord r = create.getRecord(); + cout << "v1: " << iString(r.getValue(0)) << endl; + cout << "v2: " << iString(r.getValue(1)) << endl; + cout << "v3: " << iString(r.getValue(2)) << endl; + cout << "Is null (v1): " << r.isNull("v1") << endl; + cout << "Is null (blank): " << r.isNull("") << endl; + } + } + catch(iException &e) { + e.Report(false); + } + + + SqlRecord record(create); + cout << "Size: " << record.size() << endl; + cout << "Has field(v2): " << record.hasField("v2") << endl; + cout << "Field index(v3): " << record.getFieldIndex("v3") << endl; + + cout << "The mac systems report the double fields as string fields. " << + "Until the problematic 3rd party software is fixed, " << + "the mac systems will need OS truth data." << endl; + + for(int i = 0; i < record.size(); i++) { + iString value = record.getValue(i); + cout << "Col " << i << ") " << "Name: " << record.getFieldName(i) << + ", Type: " << record.getType(i) << endl; + + } + + remove("/tmp/test.db"); + return 0; +} diff --git a/isis/src/dawn/Makefile b/isis/src/dawn/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/dawn/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/dawn/apps/Makefile b/isis/src/dawn/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/dawn/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/dawn/apps/dawnfc2isis/Makefile b/isis/src/dawn/apps/dawnfc2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/dawn/apps/dawnfc2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/dawn/apps/dawnfc2isis/dawnfc2isis.cpp b/isis/src/dawn/apps/dawnfc2isis/dawnfc2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..94c8ae5a513ce888b8462a210e87bb226448cef4 --- /dev/null +++ b/isis/src/dawn/apps/dawnfc2isis/dawnfc2isis.cpp @@ -0,0 +1,191 @@ +#include "Isis.h" + +#include +#include + +#include "ProcessImportPds.h" +#include "ProcessBySample.h" +#include "UserInterface.h" +#include "Filename.h" + +using namespace std; +using namespace Isis; + +void flipbyline (Buffer &in, Buffer &out); + +void IsisMain () +{ + ProcessImportPds p; + Pvl pdsLabel; + UserInterface &ui = Application::GetUserInterface(); + + Filename inFile = ui.GetFilename("FROM"); + iString instid; + iString missid; + + try { + Pvl lab(inFile.Expanded()); + instid = (string) lab.FindKeyword ("INSTRUMENT_ID"); + missid = (string) lab.FindKeyword ("MISSION_ID"); + } + catch (iException &e) { + string msg = "Unable to read [INSTRUMENT_ID] or [MISSION_ID] from input file [" + + inFile.Expanded() + "]"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + instid.ConvertWhiteSpace(); + instid.Compress(); + instid.Trim(" "); + missid.ConvertWhiteSpace(); + missid.Compress(); + missid.Trim(" "); + if (missid != "DAWN" && instid != "FC1" && instid != "FC2") { + string msg = "Input file [" + inFile.Expanded() + "] does not appear to be " + + "a DAWN Framing Camera (FC) EDR or RDR file."; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + p.SetPdsFile (inFile.Expanded(),"",pdsLabel); + p.SetOrganization(Isis::ProcessImport::BSQ); + string tmpName = "$TEMPORARY/" + inFile.Basename() + ".tmp.cub"; + Filename tmpFile(tmpName); + CubeAttributeOutput outatt = CubeAttributeOutput("+Real"); + p.SetOutputCube (tmpFile.Expanded(),outatt); + p.SaveFileHeader(); + + Pvl labelPvl (inFile.Expanded()); + + p.StartProcess (); + p.EndProcess (); + + ProcessBySample p2; + CubeAttributeInput inatt; + p2.SetInputCube (tmpFile.Expanded(), inatt); + Cube *outcube = p2.SetOutputCube ("TO"); + + // Get the directory where the DAWN translation tables are. + PvlGroup dataDir (Preference::Preferences().FindGroup("DataDirectory")); + iString transDir = (string) dataDir["Dawn"] + "/translations/"; + + // Create a PVL to store the translated labels in + Pvl outLabel; + + // Translate the BandBin group + Filename transFile (transDir + "dawnfcBandBin.trn"); + PvlTranslationManager bandBinXlater (labelPvl, transFile.Expanded()); + bandBinXlater.Auto(outLabel); + + // Translate the Archive group + transFile = transDir + "dawnfcArchive.trn"; + PvlTranslationManager archiveXlater (labelPvl, transFile.Expanded()); + archiveXlater.Auto(outLabel); + + // Translate the Instrument group + transFile = transDir + "dawnfcInstrument.trn"; + PvlTranslationManager instrumentXlater (labelPvl, transFile.Expanded()); + instrumentXlater.Auto(outLabel); + + // Write the BandBin, Archive, and Instrument groups + // to the output cube label + outcube->PutGroup(outLabel.FindGroup("BandBin",Pvl::Traverse)); + outcube->PutGroup(outLabel.FindGroup("Archive",Pvl::Traverse)); + outcube->PutGroup(outLabel.FindGroup("Instrument",Pvl::Traverse)); + + // Make sure the HorizontalPixelScale and VerticalPixelScale are the same + PvlGroup &instGrp(outLabel.FindGroup("Instrument", Pvl::Traverse)); + iString sheight = (string) instGrp["VerticalPixelScale"]; + iString swidth = (string) instGrp["HorizontalPixelScale"]; + if ((sheight == "N/A" && swidth != "N/A") || (sheight != "N/A" && + swidth == "N/A")) { + string msg = "Input file [" + inFile.Expanded() + "] does not have valid " + + "HorizontalPixelScale and VerticalPixelScale values. These values " + + "must be equivalent or the image is considered to be invalid."; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + if (sheight != "N/A" && swidth != "N/A") { + double pheight = sheight.ToDouble(); + double pwidth = swidth.ToDouble(); + if (pheight != pwidth) { + string msg = "Input file [" + inFile.Expanded() + "] does not have valid " + + "HorizontalPixelScale and VerticalPixelScale values. These values " + + "must be equivalent or the image is considered to be invalid."; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + } + + // Set the BandBin filter name, center, and width values based on the + // FilterNumber. + PvlGroup &bbGrp(outLabel.FindGroup("BandBin", Pvl::Traverse)); + int filtno = bbGrp["FilterNumber"]; + int center; + int width; + string filtname; + if (filtno == 1) { + center = 700; + width = 700; + filtname = "Clear_F1"; + } else if (filtno == 2) { + center = 555; + width = 43; + filtname = "Green_F2"; + } else if (filtno == 3) { + center = 749; + width = 44; + filtname = "Red_F3"; + } else if (filtno == 4) { + center = 917; + width = 45; + filtname = "NIR_F4"; + } else if (filtno == 5) { + center = 965; + width = 85; + filtname = "NIR_F5"; + } else if (filtno == 6) { + center = 829; + width = 33; + filtname = "NIR_F6"; + } else if (filtno == 7) { + center = 653; + width = 42; + filtname = "Red_F7"; + } else if (filtno == 8) { + center = 438; + width = 40; + filtname = "Blue_F8"; + } else { + string msg = "Input file [" + inFile.Expanded() + "] has an invalid " + + "FilterNumber. The FilterNumber must fall in the range 1 to 8."; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + bbGrp.AddKeyword(PvlKeyword("Center",center)); + bbGrp.AddKeyword(PvlKeyword("Width",width)); + bbGrp.AddKeyword(PvlKeyword("FilterName",filtname)); + outcube->PutGroup(bbGrp); + + PvlGroup kerns("Kernels"); + if (instid == "FC1") { + kerns += PvlKeyword("NaifFrameCode",-203110); + } else if (instid == "FC2") { + kerns += PvlKeyword("NaifFrameCode",-203120); + } else { + string msg = "Input file [" + inFile.Expanded() + "] has an invalid " + + "InstrumentId."; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + outcube->PutGroup(kerns); + + p2.StartProcess (flipbyline); + p2.EndProcess (); + + string tmp(tmpFile.Expanded()); + remove(tmp.c_str()); +} + +// Flip image by line +void flipbyline (Buffer &in, Buffer &out) { + int index = in.size() - 1; + for (int i=0; i + + + + Import PDS formatted DAWN FC EDR or RDR image cube into Isis format cube + + + This program will import a PDS formatted DAWN Framing Camera (FC) level 1 (EDR) or + level 2 (RDR) image into an Isis cube. A DAWN RDR file contains a single image + object and will be written to the file specified by the TO parameter. The DAWN + EDR file can contain multiple image objects. Until we have further information + about the frame image objects in the EDR, this program is going to ignore them and + only process the main image object. The main EDR image object will be written to + the file specified by the TO parameter. + + + + + Original version + + + The program now automatically flips the image in the line direction. + + + + + Import and Export + + + + + + filename + input + + Input PDS formatted DAWN EDR or RDR file + + + Use this parameter to select the DAWN EDR or RDR + filename. This file must contain the PDS labels. + + + *.img *.IMG + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + + diff --git a/isis/src/dawn/apps/dawnfc2isis/tsts/Makefile b/isis/src/dawn/apps/dawnfc2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/dawn/apps/dawnfc2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/dawn/apps/dawnfc2isis/tsts/case01/Makefile b/isis/src/dawn/apps/dawnfc2isis/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a4eaec9a512ba4d0fbe4defbeeed457f75e299c9 --- /dev/null +++ b/isis/src/dawn/apps/dawnfc2isis/tsts/case01/Makefile @@ -0,0 +1,10 @@ +APPNAME = dawnfc2isis + +labels.txt.IGNORELINES = Bytes StartByte ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/FC21B0001010_09049002212F5D.IMG \ + to=$(OUTPUT)/FC21B0001010_09049002212F5D.cub > /dev/null; + catlab from=$(OUTPUT)/FC21B0001010_09049002212F5D.cub >& $(OUTPUT)/labels.txt; diff --git a/isis/src/dawn/objs/DawnFcCamera/Camera.plugin b/isis/src/dawn/objs/DawnFcCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..1dfc92f9f8f29a6d7175e03bdfc5e4879c012b9e --- /dev/null +++ b/isis/src/dawn/objs/DawnFcCamera/Camera.plugin @@ -0,0 +1,10 @@ +Group = DAWN/FC1 + Version = 1 + Library = DawnFcCamera + Routine = DawnFcCameraPlugin +EndGroup +Group = DAWN/FC2 + Version = 1 + Library = DawnFcCamera + Routine = DawnFcCameraPlugin +EndGroup diff --git a/isis/src/dawn/objs/DawnFcCamera/DawnFcCamera.cpp b/isis/src/dawn/objs/DawnFcCamera/DawnFcCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..431271b19c3f40a4d805678c3253b849dca85d57 --- /dev/null +++ b/isis/src/dawn/objs/DawnFcCamera/DawnFcCamera.cpp @@ -0,0 +1,58 @@ +#include "DawnFcCamera.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraDistortionMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "RadialDistortionMap.h" +#include "iString.h" +#include "iTime.h" + +using namespace std; +using namespace Isis; +namespace Dawn { + DawnFcCamera::DawnFcCamera (Pvl &lab) : FramingCamera(lab) { + PvlGroup bandBin = lab.FindGroup("BandBin",Pvl::Traverse); + + // Get the camera characteristics + iString key = string("INS"+(iString)(int)NaifIkCode()+"_F") + + (string)bandBin["FilterNumber"] + "_FOCAL_LENGTH"; + key = key.Convert("/",'_'); + double focalLength = Spice::GetDouble(key); + SetFocalLength(focalLength); + SetPixelPitch(); + + // Get the start time in et + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + string stime = inst["StartTime"]; + double et; + str2et_c(stime.c_str(),&et); + double exposureDuration = (double)inst["ExposureDuration"] /1000.0; + et += exposureDuration / 2.0; + + // Setup detector map + CameraDetectorMap *detectorMap = new CameraDetectorMap(this); + detectorMap->SetDetectorLineSumming(1); + detectorMap->SetDetectorSampleSumming(1); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + + focalMap->SetDetectorOrigin (Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_SAMPLE"), + Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_LINE")); + + // Setup distortion map + new CameraDistortionMap(this); + + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(et); + LoadCache(); + } +} + +extern "C" Camera *DawnFcCameraPlugin(Pvl &lab) { + return new Dawn::DawnFcCamera(lab); +} diff --git a/isis/src/dawn/objs/DawnFcCamera/DawnFcCamera.h b/isis/src/dawn/objs/DawnFcCamera/DawnFcCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..39b7946080f74d5e0902da9cfb56fdf889428f5b --- /dev/null +++ b/isis/src/dawn/objs/DawnFcCamera/DawnFcCamera.h @@ -0,0 +1,25 @@ +#ifndef DawnFcCamera_h +#define DawnFcCamera_h + +#include "FramingCamera.h" + +namespace Dawn { + /** + * @ingroup SpiceInstrumentsAndCameras + * + * @brief Camera class + * + * This is the camera class for the FC camera + * + * @ingroup Dawn + * + * @author Janet Barrett + * + */ + class DawnFcCamera : public Isis::FramingCamera { + public: + DawnFcCamera (Isis::Pvl &lab); + ~DawnFcCamera () {}; + }; +}; +#endif diff --git a/isis/src/dawn/objs/DawnFcCamera/DawnFcCamera.truth b/isis/src/dawn/objs/DawnFcCamera/DawnFcCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..318ea97316e74500084a47dc98e52964007fb070 --- /dev/null +++ b/isis/src/dawn/objs/DawnFcCamera/DawnFcCamera.truth @@ -0,0 +1,20 @@ +Unit Test for DawnFcCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/dawn/objs/DawnFcCamera/Makefile b/isis/src/dawn/objs/DawnFcCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1b8b35d8cf4e2a94a818b10bc2154b494d188ec3 --- /dev/null +++ b/isis/src/dawn/objs/DawnFcCamera/Makefile @@ -0,0 +1,5 @@ +INCS = DawnFcCamera.h +SRCS = DawnFcCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/dawn/objs/DawnFcCamera/unitTest.cpp b/isis/src/dawn/objs/DawnFcCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..26e7f94cd40997f54d8a0ad373dbbcf063689aba --- /dev/null +++ b/isis/src/dawn/objs/DawnFcCamera/unitTest.cpp @@ -0,0 +1,89 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for DawnFcCamera..." << endl; + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownLat = 48.35423755148862; + double knownLon = 277.8684962230142; + + Isis::Pvl p("$dawn/testData/FC21B0001010_09049002212F5D.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) == 0) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) == 0) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.001) deltaSamp = 0; + if (fabs(deltaLine) < 0.001) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/dawn/objs/Makefile b/isis/src/dawn/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/dawn/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/docsys/Application/Makefile b/isis/src/docsys/Application/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..59cab21c5728e1532b895253680e27e9c9eb0646 --- /dev/null +++ b/isis/src/docsys/Application/Makefile @@ -0,0 +1,106 @@ +include $(ISISROOT)/make/isismake.macros + +# ISIS DOCS MAKEFILE +# Create tables of contents for the Application +# documentation and kicks off lower makefiles +# dls - deborah lee soltesz - 4/25/2002 + + +TOCDIR = $(ISISROOT)/doc/Application + + +help: + echo "Isis Application Documentation Make System Commands" + echo "------------------------ " + echo "make docs : Build Isis Application Documentation" + echo " " + echo "make wwwdocsrc : Sync Source to Public Web Server" + echo "make devdocsrc : Sync Source to Development Web Server" + echo "make wwwdoc : Sync Documentation to Public Web Server" + echo "make devdoc : Sync Documentation to Development Web Server" + echo " " + echo "make clean : Clean up Source Area (docsys/Application)" + + + +#--------------- +# DOCS: generate documentation + +docs: documentation toccat tocoldvnew tocalph categories + + +# APPLICATION LIST +# build the TOC XML for all the applications + +documentation: + echo " Creating Documentation" + mkdir -p $(ISISROOT)/doc/Application + cd data ; make docs ; cd .. ; + + +#--------------- +# TABLES OF CONTENTS +# build tables of contents to doc directory + +tocalph: $(TOCDIR)/alpha.html +$(TOCDIR)/alpha.html: build/toc.xml build/TOCindex_alpha.xsl + echo " Creating Alphabetical Applications List" + $(XALAN) -p menuPath "'../'" -o $(TOCDIR)/alpha.html build/toc.xml build/TOCindex_alpha.xsl + +toccat: $(TOCDIR)/index.html +$(TOCDIR)/index.html: build/toc.xml build/TOCindex_category.xsl + echo " Creating Categorical Applications List" + $(XALAN) -p menuPath "'../'" -o $(TOCDIR)/index.html build/toc.xml build/TOCindex_category.xsl + +tocoldvnew: $(TOCDIR)/oldvnew.html +$(TOCDIR)/oldvnew.html: build/toc.xml build/TOCindex_oldvnew.xsl + echo " Creating Old vs. New Applications List" + $(XALAN) -p menuPath "'../'" -o $(TOCDIR)/oldvnew.html build/toc.xml build/TOCindex_oldvnew.xsl + +categories: ../Schemas/Application/application.xsd build/IsisApplicationCategoriesbuild.xsl + echo " Generating list of categories from the AML Schema" + mkdir -p $(ISISROOT)/bin/xml/ + $(XALAN) -o $(ISISROOT)/bin/xml/applicationCategories.xml ../Schemas/Application/application.xsd build/IsisApplicationCategoriesbuild.xsl + + + +#--------------- +# CLEAN: clean up extraneous files + +clean: + rm -f build/toc.xml + cd data ; make clean ; cd .. ; + + +#TODO +# the following are temprary macros for updating the websites with the latest document build. +# these need to be removed and replaced with a more reasonable update script + +# public docsrc upload +wwwdocsrc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docsys to public server" + rsync -vlHptr --delete --progress --rsh=ssh $(ISISROOT)/src/docsys/* webmaster@wwwflag:/www/httpd/Astrogeology/Extranet/htdocs/Projects/IsisXML/docsrc/ + +# dev docsrc upload +devdocsrc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docsys to dev server" + rsync -vlHptr --delete --progress --rsh=ssh $(ISISROOT)/src/docsys/* dsoltesz@wwwdev:/www/httpd/Astrogeology/Extranet/htdocs/Projects/IsisXML/docsrc/ + +# public doc upload +wwwdoc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docs to public server" + rsync -vlHptr --delete --progress --rsh=ssh $(ISISROOT)/doc/* webmaster@wwwflag:/www/httpd/Astrogeology/Extranet/htdocs/Projects/IsisXML/doc/ + +# dev doc upload +devdoc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docs to dev server" + rsync -vlHptr --delete --progress --rsh=ssh $(ISISROOT)/doc/* dsoltesz@wwwdev:/www/httpd/Astrogeology/Extranet/htdocs/Projects/IsisXML/doc/ + diff --git a/isis/src/docsys/Application/build/IsisApplicationCategoriesbuild.xsl b/isis/src/docsys/Application/build/IsisApplicationCategoriesbuild.xsl new file mode 100644 index 0000000000000000000000000000000000000000..f49c1da826effaba6deff5bbd4c3cb73608d8cb6 --- /dev/null +++ b/isis/src/docsys/Application/build/IsisApplicationCategoriesbuild.xsl @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/isis/src/docsys/Application/build/IsisApplicationTOCbuild.xsl b/isis/src/docsys/Application/build/IsisApplicationTOCbuild.xsl new file mode 100755 index 0000000000000000000000000000000000000000..b2ed9623d7da5c623354f4af0e29e26a8a8e94fe --- /dev/null +++ b/isis/src/docsys/Application/build/IsisApplicationTOCbuild.xsl @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/isis/src/docsys/Application/build/TOCindex.xsl b/isis/src/docsys/Application/build/TOCindex.xsl new file mode 100755 index 0000000000000000000000000000000000000000..9942ed8cf4611ebd2b117dbe512b77258962d290 --- /dev/null +++ b/isis/src/docsys/Application/build/TOCindex.xsl @@ -0,0 +1,278 @@ + + + + + + + + + + + + + + + + + + + + + + + + + USGS: ISIS Application Table of Contents + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis 3 Application Documentation

    + +
    + + + + + + + +
    +

    + Table of Contents +

    +
    + Home +
    + + +

    Categories

    +

    Core Programs

    + + +

    Mission Specific Programs

    + + + + + + +
    +

    Core Programs

    + + +
    +

    + + + +

    + + + + + + + + + + + +
    + + + + +
    +
    +
    + + +
    +

    Mission Specific Programs

    + + +
    +

    + + + +

    + + + + + + + + + + + +
    + + + + +
    +
    +
    + + + +
    +

    Alphabetical Listing

    + + + + + + + + + +
    + + + + + +
    +
    +
    + + + + +
    +

    Old Names vs. New Names

    + + + + + + + + + + + + + + + +
    + Old Name + + New Name(s) +
    + + +
      + + +
    • + + + +
    • +
      +
      +
    +
    + + + + + + + + + + + + + + +
    + + + + + + +
    + +
    + diff --git a/isis/src/docsys/Application/build/TOCindex_alpha.xsl b/isis/src/docsys/Application/build/TOCindex_alpha.xsl new file mode 100755 index 0000000000000000000000000000000000000000..fd61c94ba56d34a219a127499f2375a4957582e5 --- /dev/null +++ b/isis/src/docsys/Application/build/TOCindex_alpha.xsl @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + USGS: ISIS Application Table of Contents (Alphabetical Listing) + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis 3 Application Documentation

    + +
    + + + + + + + + + +
    + Categorical | + Old vs. New | + Home +
    +

    + Alphabetical Listing of Applications +

    +
    + + + + + + + + + + + + + + +
    + + + + + +
    +
    +
    + + + + + + + + + +
    + + + + + +
    + +
    + diff --git a/isis/src/docsys/Application/build/TOCindex_category.xsl b/isis/src/docsys/Application/build/TOCindex_category.xsl new file mode 100755 index 0000000000000000000000000000000000000000..1f45b79a08827b15f34aafca86bb211d250cc28c --- /dev/null +++ b/isis/src/docsys/Application/build/TOCindex_category.xsl @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + USGS: ISIS Application Table of Contents (Categorical) + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis 3 Application Documentation

    + +
    + + + + + + + + + +
    + + Alphabetical Listing | + Old vs. New | + Home +
    +

    + Applications by Category +

    +
    + + + + +

    Categories

    +

    Core Programs

    +
      + + +
    • + + +
    • +
      +
    + +

    Mission Specific Programs

    +
      + + +
    • + + +
    • +
      +
    + + + + +

    Core Programs

    + + +

    + + + +

    + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + + + +

    Mission Specific Programs

    + + +

    + + + +

    + + + + + + + + + + + +
    + + + + +
    +
    + +
    +
    +
    + + + + +
    + + + + + +
    + +
    + diff --git a/isis/src/docsys/Application/build/TOCindex_oldvnew.xsl b/isis/src/docsys/Application/build/TOCindex_oldvnew.xsl new file mode 100755 index 0000000000000000000000000000000000000000..db5526eb243c0b8acf87a2c06c98cdc62a5f7893 --- /dev/null +++ b/isis/src/docsys/Application/build/TOCindex_oldvnew.xsl @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + USGS: ISIS Application Table of Contents (Old vs. New Application Names) + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis 3 Application Documentation

    +
    + + + + + + + + + +
    + Categorical | + Alphabetical | + Home +
    +

    + Old vs. New Application Names +

    +
    + + +

    +Several applications have been renamed or evolved into multiple +applications in the newest version of Isis. The following table cross-references the current application names in Isis 3 to the names of applications in previous versions of Isis. +

    + + + + + + + + + + + + + + + + + + + + +
    + Previous Versions + + Isis 3 +
    + + +
      + + +
    • + + + +
    • +
      +
      +
    +
    + + + + + + + + + + + + + + +
    + + + + +
    + +
    + diff --git a/isis/src/docsys/Application/build/toc_footer.xml b/isis/src/docsys/Application/build/toc_footer.xml new file mode 100755 index 0000000000000000000000000000000000000000..3d8c267325c509716393f71fef37d0a600bbf57d --- /dev/null +++ b/isis/src/docsys/Application/build/toc_footer.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/isis/src/docsys/Application/build/toc_header.xml b/isis/src/docsys/Application/build/toc_header.xml new file mode 100755 index 0000000000000000000000000000000000000000..355fbd1ec32aa1eb822dfa3c1ee7c9da28e08c39 --- /dev/null +++ b/isis/src/docsys/Application/build/toc_header.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/isis/src/docsys/Application/data/Makefile b/isis/src/docsys/Application/data/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..de18f4e651cb8332807062c79c4e332665570a13 --- /dev/null +++ b/isis/src/docsys/Application/data/Makefile @@ -0,0 +1,82 @@ +include $(ISISROOT)/make/isismake.macros + +# ISIS APPLICATION DOCS MAKEFILE +# Process the XML files deposited by application +# makefiles +# dls - deborah lee soltesz - 4/25/2002 + + +DEST_PRES_DIR = $(ISISROOT)/doc/Application/presentation + +PFSTYLEDIR = ../presentation/PrinterFriendly/styles +PFDIR = $(DEST_PRES_DIR)/PrinterFriendly +TABSTYLEDIR = ../presentation/Tabbed/styles +TABDIR = $(DEST_PRES_DIR)/Tabbed + +APPLICATIONS = $(filter-out CVS $(wildcard *.*) $(wildcard Makefile*) , $(wildcard *)) + +help: + echo "Do not run make in this directory!" + echo "Run make from $ISISROOT/src/docsys/Application to remake Application documentation." + + +APPSDIR = $(ISISROOT)/doc/Application + +#------ +# DOCS: generate documentation + +docs: printer tabbed toc + + +#------ +# PRINTER FRIENDLY +# run style sheet for Printer Friendly presentation +printer: + + echo " Printer Friendly Version" + + for dirname in $(APPLICATIONS); do \ + cd $$dirname ; make -f ../Makefile-application printer ; cd .. ; \ + done + mkdir -p $(PFDIR)/styles ; \ + rsync -lHptr --delete --rsh=ssh $(PFSTYLEDIR)/*.css $(PFDIR)/styles/ ; \ + +#------ +# TABBED +# run style sheet for Tabbed presentation +tabbed: + + echo " Tabbed Interface Version" + + for dirname in $(APPLICATIONS); do \ + cd $$dirname ; make -f ../Makefile-application tabbed ; cd .. ; \ + done + mkdir -p $(TABDIR)/styles ; \ + rsync -lHptr --delete --rsh=ssh $(TABSTYLEDIR)/*.css $(TABDIR)/styles/ ; \ + + +#------ +# TOC +# run style sheet for Table of Contents XML +toc: ../build/toc.xml +../build/toc.xml: $(APPSDIR) ../build/IsisApplicationTOCbuild.xsl + + echo " Table of Contents XML" + cat ../build/toc_header.xml > ../build/toc.xml + for dirname in $(APPLICATIONS); do \ + echo " Adding [$$dirname]" ; \ + $(XALAN) $$dirname/$$dirname.xml ../build/IsisApplicationTOCbuild.xsl >> ../build/toc.xml ; \ + done + cat ../build/toc_footer.xml >> ../build/toc.xml + mkdir -p $(ISISROOT)/bin/xml/ + cp ../build/toc.xml $(ISISROOT)/bin/xml/applicationTOC.xml + +#------ +# CLEAN: clean up files + +clean: + rm -rf $(APPLICATIONS) + + + + diff --git a/isis/src/docsys/Application/data/Makefile-application b/isis/src/docsys/Application/data/Makefile-application new file mode 100755 index 0000000000000000000000000000000000000000..275f7a4f9cc7b6616489d6c5be51d0aed50b931b --- /dev/null +++ b/isis/src/docsys/Application/data/Makefile-application @@ -0,0 +1,66 @@ +include $(ISISROOT)/make/isismake.macros + +# ISIS APPLICATION DOC MAKEFILE +# Process the XML files deposited by application +# makefiles +# dls - deborah lee soltesz - 3/3/2003 + +APPSDIR = $(ISISROOT)/doc/Application +DEST_PRES_DIR = $(APPSDIR)/presentation + +PFSTYLEDIR = ../../presentation/PrinterFriendly/styles +PFDIR = $(DEST_PRES_DIR)/PrinterFriendly +TABSTYLEDIR = ../../presentation/Tabbed/styles +TABDIR = $(DEST_PRES_DIR)/Tabbed + +APP = $(shell basename `pwd`) + + + + +help: + echo "Do not run make in this directory!" + echo "Run make from $ISISROOT/src/docsys/Application to remake Application documentation." + +#------ +# DOCS: generate documentation + +docs: printer tabbed + + +printer: $(PFDIR)/$(APP)/$(APP).html + +$(PFDIR)/$(APP)/$(APP).html: $(APP).xml $(PFSTYLEDIR)/IsisApplicationDocStyle.xsl + + # PRINTER FRIENDLY + # run style sheet for Printer Friendly presentation + + echo " [$(APP)]" ; \ + mkdir -p $(PFDIR)/$(APP) ; \ + if test -d assets;\ + then \ + rsync -lHptr --delete --rsh=ssh assets $(PFDIR)/$(APP) ; \ + fi + $(XALAN) -p menuPath "'../../../../'" -o $(PFDIR)/$(APP)/$(APP).html $(APP).xml $(PFSTYLEDIR)/IsisApplicationDocStyle.xsl ; \ + touch $(APPSDIR) + + + + + +tabbed: $(TABDIR)/$(APP)/$(APP).html + +$(TABDIR)/$(APP)/$(APP).html: $(APP).xml $(TABSTYLEDIR)/IsisApplicationDocStyle.xsl + + # TABBED + # run style sheet for Tabbed presentation + + echo " [$(APP)]" + mkdir -p $(TABDIR)/$(APP) + if test -d assets;\ + then \ + rsync -lHptr --delete --rsh=ssh assets $(TABDIR)/$(APP) ; \ + fi + $(XALAN) -p menuPath "'../../../../'" -o $(TABDIR)/$(APP)/$(APP).html $(APP).xml $(TABSTYLEDIR)/IsisApplicationDocStyle.xsl + touch $(APPSDIR) + diff --git a/isis/src/docsys/Application/presentation/PrinterFriendly/styles/IsisApplicationDocStyle.css b/isis/src/docsys/Application/presentation/PrinterFriendly/styles/IsisApplicationDocStyle.css new file mode 100755 index 0000000000000000000000000000000000000000..24ce5e07f6de5901b3ea628a611c6e6e6b5e8aba --- /dev/null +++ b/isis/src/docsys/Application/presentation/PrinterFriendly/styles/IsisApplicationDocStyle.css @@ -0,0 +1,236 @@ + /* ISIS APPLICATION PROGRAMMING DOC STYLE SHEET + * FILENAME: IsisApplicationDocStyle.css + * + * Purpose: formatting style sheet for Isis Application + * Programmer documentation presentation + * + * Author: Deborah Lee Soltesz, USGS, 04/03/2002 + */ + + + /* ---------------------------------------------------------------- + * HEADINGS */ + + h1 { + color: #336699 ; + } + + h2 { + background-color: #88AACC ; + } + + h3 { + color: #336699 ; + } + + + hr { + color: #000099 ; + } + + + /* ---------------------------------------------------------------- + * TABLE CELL FORMATTING: table styles for figures; use with CAPTIONS */ + + + + /* LEVEL 1: outside level of table cells*/ + + .tableCellLevel1 + { + border: 1px ; + border-color: #88AACC ; + border-style: solid ; + } + + .tableCellLevel1_th + { + border: 3px ; + border-color: #88AACC ; + border-style: solid ; + background-color: #BBDDEE ; + } + + + .tableCellLevel1_type + { + border: 1px ; + border-color: #88AACC ; + border-style: solid ; + font-style: italic ; + } + + .tableCellLevel1_name + { + border: 1px ; + border-color: #88AACC ; + border-style: solid ; + font-weight: bold ; + } + + .tableCellLevel1_description + { + border: 1px ; + border-color: #88AACC ; + border-style: solid ; + } + + + /* LEVEL 2: level of table cells nested inside an outer table */ + + .tableCellLevel2 + { + border: 1px ; + border-color: #CCCCCC ; + border-style: solid ; + font-size: 80% ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + } + + .tableCellLevel2_type + { + border: 1px ; + border-color: #CCCCCC ; + border-style: solid ; + font-style: italic ; + font-size: 80% ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + } + + .tableCellLevel2_name + { + border: 1px ; + border-color: #CCCCCC ; + border-style: solid ; + font-weight: bold ; + font-size: 80% ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + } + + .tableCellLevel2_description + { + border: 1px ; + border-color: #CCCCCC ; + border-style: solid ; + font-size: 80% ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + } + + + + + /* ---------------------------------------------------------------- + * TABS: tab styles */ + + .tabOn + { + border: 1px ; + border-bottom: 0px ; + border-color: #333399 ; + border-style: solid ; + background-color: #6666AA; + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-weight: bold ; + padding: 5px ; + color: #FFFFFF ; + margin: 0px; + } + + .tabOff + { + border: 1px ; + border-bottom: 0px ; + border-color: #6666AA; + border-style: solid ; + background-color: #DDCCCC ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-weight: normal ; + font-style: italic ; + padding: 5px ; + color: #666666 ; + margin: 0px; + } + + .tabHighlight + { + border: 1px ; + border-bottom: 0px ; + border-color: #6666AA; + border-style: solid ; + background-color: #DDDDEE ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-style: italic ; + padding: 5px ; + color: #666666 ; + margin: 0px; + } + + + + /* ---------------------------------------------------------------- + * PAGE VIEW: page view styles */ + + .pageView { + border: 3px; + border-style:solid; + border-color:#6666AA; + } + + .functionView { + background-color: #DDDDEE; + border-top: 3px; + border-left: 3px; + border-right: 10px; + border-bottom: 10px; + border-style: solid; + border-color: #666666; + + position: absolute; + padding: 10px; + top: 10px; + left: 20px; + + visibility: hidden; + } + + + /* ------------------------------------------------------------- + * TOC Table: color override style for application documentation */ + + table.tableFormattedInformation caption + { + border-color: #369 ; + background-color: #ACE ; + } + + table.tableFormattedInformation th + { + border-color: #68A ; + background-color: #9BD ; + } + + + /* ------------- + * History Table */ + + .tableCellHistory_date + { + font-style: italic ; + vertical-align: top ; + padding: 3px ; + } + + .tableCellHistory_name + { + font-weight: bold ; + vertical-align: top ; + padding: 3px ; + } + + .tableCellHistory_description + { + vertical-align: top ; + padding: 3px ; + } + + diff --git a/isis/src/docsys/Application/presentation/PrinterFriendly/styles/IsisApplicationDocStyle.xsl b/isis/src/docsys/Application/presentation/PrinterFriendly/styles/IsisApplicationDocStyle.xsl new file mode 100755 index 0000000000000000000000000000000000000000..a7d90852239739b49de83f797e104fdeae954945 --- /dev/null +++ b/isis/src/docsys/Application/presentation/PrinterFriendly/styles/IsisApplicationDocStyle.xsl @@ -0,0 +1,951 @@ + + + + + + + + + + + + + + + + + + + + USGS: ISIS <xsl:value-of select="@name"/> Application Documentation + + + + + + + + Isis, image processing, + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis 3 Application Documentation

    + +
    + + + + + + +
    +

    + +

    +
    + Standard View | + TOC | + Home +
    + +

    + +

    + + +

    + + + Description
    + + + + Categories
    +
    + + + + Groups
    +
    + + + + Examples
    +
    + + + + History
    +
    + + + + Things To Do
    +
    + +

    + + + + +
    +

    + Description +

    + +
    + +
    + + + +
    +

    + Categories +

    + + + + + +
    +

    + Related Applications in Previous Versions of Isis +

    + + This application replaces the following + + + applications existing in previous versions of Isis, which have been deprecated + + + application existing in previous versions of Isis, which has been deprecated + + + from the current version of Isis: + +
      + +
    • +
      +
    +
    + + + + + + +
    +

    + + Related Objects and Documents +

    + + + + + +

    Applications

    +
      + + +
    • +
    • +
      +
      +
    +
    + + +

    Documents

    +
      + + + + + +
    • +
    • +
      + + +
    • +
    • +
      + + +
    • + + + + , + + + + , + + + + ; + + + + ; + +
    • +
      + +
      +
      +
      +
    +
    + +
    +
    +
    + + + + + + + +
    +

    + Parameter Groups +

    + + + + +

    + + + + + + + + + + + +
    + Name + + Description +
    + + + + +
    +
    +
    + + + + + + + + +
    +

    + + + : + +

    +
    + + +

    + Description +

    +

    + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Type + + +
    + File Mode + + +
    + Pixel Type + + +
    + Default Path + + +
    + Count + + +
    + Default + + +
    + Internal Default + + +
    + Option List: + + + + + + + + + + + + + + +
    + Option + Brief + Description
    + + + + + + + +

    Exclusions

    +
      + +
    • +
      +
    +
    + +

    Inclusions

    +
      + +
    • +
      +
    +
    + +
    +
    + Minimum + + + + + (inclusive) + + + (inclusive) + + + (exclusive) + + +
    + Maximum + + + + + (inclusive) + + + (inclusive) + + + (exclusive) + + +
    + Greater Than + +
      + +
    • + +
    • +
      +
    +
    + Greater Than or Equal + +
      + +
    • + +
    • +
      +
    +
    + Less Than + +
      + +
    • +
      +
    +
    + Less Than or Equal + +
      + +
    • +
      +
    +
    + Not Equal + +
      + +
    • +
      +
    +
    + Odd + + This value must be an odd number +
    + Exclusions + +
      + +
    • +
      +
    +
    + Inclusions + +
      + +
    • +
      +
    +
    + Filter + + +
    +
    + +
    + +
    +
    + + + +
    + + + + + +
    +

    + Examples +

    + + + +
    +

    + Example +

    +

    + +

    + +

    + Description +

    + +
    + +
    + + + + +

    + Command Line +

    + +
    + + + + + + +
    +
    + +
    +
    +
    + +
    + + + + + +

    + GUI Screenshot +

    + +
    + + + + +
    +
    + +
    + + + + +

    + + + Input Images + + + Input Image + + +

    + +
    + + + + +
    +
    + +
    + + + + +

    + + + Data Files + + + Data File + + +

    + +
    + + + + + + + +
    + + + +
    +
    + +
    + + + + + +

    + + + Output Images + + + Output Image + + +

    + +
    + + + + +
    +
    + +
    + + + +
    +
    + +
    + + + + + +
    +

    + History +

    + + + + + + + + + + + +
    + + + + + +
    +
    + + + + +
    +

    + Things To Do +

    + +
      + +
    • +
      +
    +
    + + + + + + +
    + + + + +
    + + + + + + + + + + + + + +
    + +
    + + + +

    + +

    + + +

    + + Parameter Name: + + +
    + +

    +
    + +

    + +

    + + + + +
    + + + + + + + + + + + + + + +
    + diff --git a/isis/src/docsys/Application/presentation/ProgTester/IsisApplicationDocStyle.xsl b/isis/src/docsys/Application/presentation/ProgTester/IsisApplicationDocStyle.xsl new file mode 100755 index 0000000000000000000000000000000000000000..da30ed88ca64a46d82d1ba4831132d3f7ec0444d --- /dev/null +++ b/isis/src/docsys/Application/presentation/ProgTester/IsisApplicationDocStyle.xsl @@ -0,0 +1,1336 @@ + + + + + + + + + + + + + + + + + USGS: ISIS <xsl:value-of select="@name"/> Application Documentation + + + + + Isis, image processing, + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + USGS
    + + +

    + Isis 3 Application Documentation

    + +
    + +

    + +

    + +

    + +

    + + +

    + + + Description
    + + + + Categories
    +
    + + + + + Groups
    +
    + + + + Examples
    +
    + + + + History
    +
    + + + + Things To Do
    +
    + + +

    + + + + +
    +

    + Description +

    + +
    + +
    + + + + +
    +

    + Categories +

    + +
      + +
    • +
      + +
    • + +
    • +
      +
    + + + + +
    +

    + Related Applications in Previous Versions of Isis +

    + + This application replaces the following + + + applications existing in previous versions of Isis, which have been deprecated + + + application existing in previous versions of Isis, which has been deprecated + + + from the current version of Isis: + +
      + +
    • +
      +
    +
    + + + + + +
    +

    + + Related Objects and Documents +

    + + + + + +

    Applications

    +
      + + +
    • +
    • +
      +
      +
    +
    + + +

    Documents

    +
      + + + + + +
    • +
    • +
      + + +
    • +
    • +
      + + +
    • + + + + , + + + + , + + + + ; + + + + ; + +
    • +
      + +
      +
      +
      +
    +
    + +
    +
    +
    + + + + + + + +
    +

    + Parameter Groups +

    + + + + +

    + + + + + + + + + + + +
    + Name + + Description +
    + + + + +
    +
    +
    + + + + + + + + +
    +

    + + + : + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Type + + +
    + File Mode + + +
    + Pixel Type + + +
    + Default Path + + +
    + Count + + +
    + Default + + +
    + Internal Default + + +
    + Option List: + + + + + + + + + + + + + + + + + + +
    + Option + Brief + Description + Exclusions + Inclusions
    + + + + + + + + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + Minimum + + + + + (inclusive) + + + (inclusive) + + + (exclusive) + + +
    + Maximum + + + + + (inclusive) + + + (inclusive) + + + (exclusive) + + +
    + Greater Than + +
      + +
    • + +
    • +
      +
    +
    + Greater Than or Equal + +
      + +
    • + +
    • +
      +
    +
    + Less Than + +
      + +
    • +
      +
    +
    + Less Than or Equal + +
      + +
    • +
      +
    +
    + Not Equal + +
      + +
    • +
      +
    +
    + Odd + + This value must be an odd number +
    + Exclusions + +
      + +
    • +
      +
    +
    + Inclusions + +
      + +
    • +
      +
    +
    + Filter + + +
    + + +

    + Description +

    + +
    + +
    + +
    +
    + + + +
    + + + + + +
    +

    + Examples +

    + + + +
    +

    + Example +

    +

    + +

    + +

    + Description +

    + +
    + +
    + + +

    + Command Line +

    + +
    + + + + + + +
    +
    + +
    +
    +
    + +
    + + + + +

    + GUI Screenshot +

    + +
    + + + + +
    +
    + +
    + + + + +

    + + + Input Images + + + Input Image + + +

    + +
    + + + + +
    +
    + +
    + + + + +

    + + + Data Files + + + Data File + + +

    + +
    + + + + + + + +
    + + + +
    +
    + +
    + + + + +

    + + + Output Images + + + Output Image + + +

    + +
    + + + + +
    +
    + + +
    + +
    +
    + +
    + + + + + +
    +

    + History +

    + +

    + All history entries are shown, including those marked hidden +

    + + + + + + + + + + + +
    + + + + + +
    +
    + + + + +
    +

    + Things To Do +

    + +
      + +
    • +
      +
    +
    + + + + + + +
    + footer will appear here + + + +
    + + + + + + + + + + + + +
    + +
    + + + +

    + +

    + + +

    + + Parameter Name: + + +
    + +

    +
    + +
    + +
    + + + + +
    + + + + + + + + + + + + + +
    + diff --git a/isis/src/docsys/Application/presentation/Tabbed/styles/IsisApplicationDocStyle.css b/isis/src/docsys/Application/presentation/Tabbed/styles/IsisApplicationDocStyle.css new file mode 100755 index 0000000000000000000000000000000000000000..8c04c8eb66ea44f81e540d10788b3b692965316f --- /dev/null +++ b/isis/src/docsys/Application/presentation/Tabbed/styles/IsisApplicationDocStyle.css @@ -0,0 +1,242 @@ + /* ISIS APPLICATION PROGRAMMING DOC STYLE SHEET + * FILENAME: IsisApplicationDocStyle.css + * + * Purpose: formatting style sheet for Isis Application + * Programmer documentation presentation + * + * Author: Deborah Lee Soltesz, USGS, 04/03/2002 + */ + + + /* ---------------------------------------------------------------- + * HEADINGS */ + + h1 { + color: #336699 ; + } + + h2 { + background-color: #88AACC ; + } + + h3 { + color: #336699 ; + } + + hr { + color: #000099 ; + } + + + + + /* ---------------------------------------------------------------- + * TABLE CELL FORMATTING: table styles for figures; use with CAPTIONS */ + + + + + /* LEVEL 1: outside level of table cells*/ + + .tableCellLevel1 + { + border: 1px ; + border-color: #88AACC ; + border-style: solid ; + } + + .tableCellLevel1_th + { + border: 3px ; + border-color: #88AACC ; + border-style: solid ; + background-color: #BBDDEE ; + } + + + .tableCellLevel1_type + { + border: 1px ; + border-color: #88AACC ; + border-style: solid ; + font-style: italic ; + } + + .tableCellLevel1_name + { + border: 1px ; + border-color: #88AACC ; + border-style: solid ; + font-weight: bold ; + } + + .tableCellLevel1_description + { + border: 1px ; + border-color: #88AACC ; + border-style: solid ; + } + + + /* LEVEL 2: level of table cells nested inside an outer table */ + + .tableCellLevel2 + { + border: 1px ; + border-color: #CCCCCC ; + border-style: solid ; + font-size: 80%; + font-family: Arial, Helvetica, Geneva, sans-serif ; + } + + .tableCellLevel2_type + { + border: 1px ; + border-color: #CCCCCC ; + border-style: solid ; + font-style: italic ; + font-size: 80% ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + } + + .tableCellLevel2_name + { + border: 1px ; + border-color: #CCCCCC ; + border-style: solid ; + font-weight: bold ; + font-size: 80% ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + } + + .tableCellLevel2_description + { + border: 1px ; + border-color: #CCCCCC ; + border-style: solid ; + font-size: 80% ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + } + + + + + /* ---------------------------------------------------------------- + * TABS: tab styles */ + + .tabOn + { + border: 1px ; + border-bottom: 0px ; + border-color: #88AACC ; + border-style: solid ; + background-color: #88AACC ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-weight: bold ; + padding: 5px ; + color: #FFFFFF ; + margin: 0px; + } + + .tabOff + { + border: 1px ; + border-bottom: 0px ; + border-color: #6699AA; + border-style: solid ; + background-color: #BBCCDD ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-weight: normal ; + font-style: italic ; + padding: 5px ; + color: #666666 ; + margin: 0px; + } + + .tabHighlight + { + border: 1px ; + border-bottom: 0px ; + border-color: #3366AA; + border-style: solid ; + background-color: #CCDDEE ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-style: italic ; + padding: 5px ; + color: #666666 ; + margin: 0px; + } + + + + /* ---------------------------------------------------------------- + * PAGE VIEW: page view styles */ + + .pageView { + border: 3px; + border-style:solid; + border-color:#88AACC ; + } + + .functionView { + background-color: #e3e9eF; + border-top: 3px; + border-left: 3px; + border-right: 10px; + border-bottom: 10px; + border-style: solid; + border-color: #666666; + + position: absolute; + padding: 10px; + top: 10px; + left: 20px; + width: 70%; + + visibility: hidden; + } + + + + + + /* ------------------------------------------------------------- + * TOC Table: color override style for application documentation */ + + table.tableFormattedInformation caption + { + border-color: #369 ; + background-color: #ACE ; + } + + table.tableFormattedInformation th + { + border-color: #68A ; + background-color: #9BD ; + } + + /* ------------- + * History Table */ + + .tableCellHistory_date + { + font-style: italic ; + vertical-align: top ; + padding: 3px ; + } + + .tableCellHistory_name + { + font-weight: bold ; + vertical-align: top ; + padding: 3px ; + } + + .tableCellHistory_description + { + vertical-align: top ; + padding: 3px ; + } + + + diff --git a/isis/src/docsys/Application/presentation/Tabbed/styles/IsisApplicationDocStyle.xsl b/isis/src/docsys/Application/presentation/Tabbed/styles/IsisApplicationDocStyle.xsl new file mode 100755 index 0000000000000000000000000000000000000000..bcf6151a5d39a7b3b7a51587904f52514869f367 --- /dev/null +++ b/isis/src/docsys/Application/presentation/Tabbed/styles/IsisApplicationDocStyle.xsl @@ -0,0 +1,1117 @@ + + + + + + + + + + + + + + + + + + + + + + USGS: ISIS <xsl:value-of select="@name"/> Application Documentation + + + + + + + + Isis, image processing, + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis 3 Application Documentation

    + +
    + + + + + + +
    +

    + +

    +
    + Printer Friendly View | + TOC | + Home +
    + +

    + +

    + + + + + + + + + + + + + + + + + + + + + +
    + Overview + + Parameters + + Example +
    + + + + +
    +
    + + + + +
    +

    + Description +

    + +
    + +
    + + + + +
    +

    + Categories +

    + + + + + + +
    +

    + Related Applications in Previous Versions of Isis +

    + + This application replaces the following + + + applications existing in previous versions of Isis, which have been deprecated + + + application existing in previous versions of Isis, which has been deprecated + + + from the current version of Isis: + +
      + +
    • +
      +
    +
    + + + + + +
    +

    + + Related Objects and Documents +

    + + + + + +

    Applications

    +
      + + +
    • +
    • +
      +
      +
    +
    + + +

    Documents

    +
      + + + + + +
    • +
    • +
      + + +
    • +
    • +
      + + +
    • + + + + , + + + + , + + + + ; + + + + ; + +
    • +
      + +
      +
      +
      +
    +
    + +
    +
    +
    + + + + + + +
    +

    + History +

    + + + + + + + + + + + +
    + + + + + +
    +
    + + + + +
    +

    + Things To Do +

    + +
      + +
    • +
      +
    +
    + + +
    + + + + +
    + + + + + + + + + + +
    +
    + + + +
    +

    + Parameter Groups +

    + + + + +

    + + + + + + + + + + + +
    + Name + + Description +
    + + + + +
    +
    +
    + +
    + + + +
    + + + + + + + + + + + +
    + + +
    + + X + +
    + + +

    + + + : + +

    + +
    + + +

    + Description +

    +

    + +

    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Type + + +
    + File Mode + + +
    + Pixel Type + + +
    + Default Path + + +
    + Count + + +
    + Default + + +
    + Internal Default + + +
    + Option List: + + + + + + + + + + + + + + + +
    + Option + Brief + Description
    + + + + + + + +

    Exclusions

    +
      + +
    • +
      +
    +
    + +

    Inclusions

    +
      + +
    • +
      +
    +
    + +
    +
    + Minimum + + + + + (inclusive) + + + (inclusive) + + + (exclusive) + + +
    + Maximum + + + + + (inclusive) + + + (inclusive) + + + (exclusive) + + +
    + Greater Than + + +
    +
    +
    + Greater Than or Equal + + +
    +
    +
    + Less Than + + +
    +
    +
    + Less Than or Equal + + +
    +
    +
    + Not Equal + + +
    +
    +
    + Odd + + This value must be an odd number +
    + Exclusions + +
      + +
    • +
      +
    +
    + Inclusions + +
      + +
    • +
      +
    +
    + Filter + + +
    +
    + + + + + + +
    + + +
    + +
    +
    +
    + + + + + + + + +
    +
    + +
    +

    + Example +

    +

    + +

    + +

    + Description +

    + +
    + +
    + + +

    + Command Line +

    + +
    + + + + + + +
    +
    + +
    +
    +
    + +
    + + + + +

    + GUI Screenshot +

    + +
    + + + + +
    +
    + +
    + + + + +

    + + + Input Images + + + Input Image + + +

    + +
    + + + + +
    +
    + +
    + + + + +

    + + + Data Files + + + Data File + + +

    + + Links open in a new window. + + +
    + + + + + + + +
    + + + +
    +
    + +
    + + + + +

    + + + Output Images + + + Output Image + + +

    + +
    + + + + +
    +
    + +
    +
    + + + + + +
    +
    +
    + +
    + + + +
    + + + +
    + + + + + + + + + + + +
    + +
    + + + +

    + +

    + + +

    + + Parameter Name: + + +
    + +

    +
    + +

    + +

    + + + + +
    + + + + + + + + + + + + + + + +
    + diff --git a/isis/src/docsys/Makefile b/isis/src/docsys/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..d99f72944abec6dfcb311586175055de0b9432a2 --- /dev/null +++ b/isis/src/docsys/Makefile @@ -0,0 +1,183 @@ +include $(ISISROOT)/make/isismake.macros + +# ISIS DOCS MAKEFILE +# Move assets and static documents to doc root +# and kick off lower makefiles +# dls - deborah lee soltesz - 4/25/2002 + + + +#APPLICATIONS = $(filter-out Makefile CVS $(wildcard *.*) , data/$(wildcard *)) +#DOCUMENTS = $(filter-out Makefile $(wildcard *.*) , documents/$(wildcard *)) +DOCDIR = $(ISISROOT)/doc +USER = webman +USERDEV = isis3mgr + +help: + echo "Isis Documentation Make System Commands" + echo "------------------------ " + echo "make docs : Build Isis Web Documentation" + echo " " + echo "make schemas : Update Isis XML Schemas" + echo "make assetsdir : Update assets" + echo " " + echo "make wwwdoc : Sync Documentation to Public Web Server" + echo "make devdoc : Sync Documentation to Development Web Server" + echo "make wwwschema : Sync Schemas to Public Web Server" + echo "make syncall : Sync Everything to All Web Servers" + echo "make syncdev : Sync Everything to Development" + echo " " + echo "make clean : Clean up Source Area (docsys)" + +docs: upperlevel + +upperlevel: + + echo " " + echo " Building Upper Level Documentation" + echo " Updating Directories" + + echo " [assets]" + rsync -lHptr --delete --rsh=ssh --cvs-exclude assets $(DOCDIR) + + echo " [P3P]" + rsync -lHptr --delete --rsh=ssh --cvs-exclude w3c $(DOCDIR) + + echo " [UserDocs]" + mkdir -p UserDocs + rsync -lHptr --delete --rsh=ssh --cvs-exclude UserDocs $(DOCDIR) + + echo " [AboutIsis]" + mkdir -p AboutIsis + rsync -lHptr --delete --rsh=ssh --cvs-exclude AboutIsis $(DOCDIR) + + echo " [General]" + mkdir -p General + rsync -lHptr --delete --rsh=ssh --cvs-exclude General $(DOCDIR) + + echo " [Guides]" + mkdir -p Guides + rsync -lHptr --delete --rsh=ssh --cvs-exclude Guides $(DOCDIR) + + echo " [Installation]" + mkdir -p Installation + rsync -lHptr --delete --rsh=ssh --cvs-exclude Installation $(DOCDIR) + + echo " [TechnicalInfo]" + mkdir -p TechnicalInfo + rsync -lHptr --delete --rsh=ssh --cvs-exclude TechnicalInfo $(DOCDIR) + + echo " [Schemas]" + mkdir -p Schemas + rsync -lHptr --delete --rsh=ssh --cvs-exclude Schemas $(DOCDIR) + + echo " [home page]" + #rsync -lHptr --delete --rsh=ssh --cvs-exclude *.html $(DOCDIR)/ + $(XALAN) -v -p menuPath "'./'" -o $(DOCDIR)/index.html build/homepage.xml build/main.xsl + + echo " Finished Updating Directories" + + echo " " + echo " Building Documents" + mkdir -p $(DOCDIR)/documents + cd documents ; make docs ; cd .. ; + echo " Finished Building Documents" + + echo " Finished Building Upper Level Documentation" + echo " " + + + echo " Building Application Documentation" + cd Application ; make docs ; cd .. ; + echo " Finished Building Application Documentation" + echo " " + + echo " Building Object Documentation" + cd Object ; make docs ; cd .. ; + echo " Finished Building Object Documentation" + echo " " + + chmod -R ugo+r $(DOCDIR) + + + +assetsdir: + echo " " + echo " Updating assets" + rsync -lHptr --delete --rsh=ssh --cvs-exclude assets $(DOCDIR) + echo " Finished Updating assets" + echo " " + +schemas: + echo " " + echo " Updating Isis XML Schemas" + rsync -lHptr --delete --rsh=ssh --cvs-exclude Schemas $(DOCDIR)/ + echo " Finished Updating Isis XML Schemas" + echo " " + + +clean: + rm -rf UserDocs + rm -rf AboutIsis + rm -rf General + rm -rf Guides + rm -rf Installation + rm -rf TechnicalInfo + rm -rf cgi-bin + + cd Schemas && rm -f *.html ; cd .. ; + cd build && rm -f doctoc.xml ; cd .. ; + + cd Application ; make clean ; cd .. ; + cd Object ; make clean ; cd .. ; + cd documents ; make clean ; cd .. ; + +cleandocs: + rm -r $(DOCDIR)/* + +#TODO +# the following are temprary macros for updating the websites with the latest document build. +# these need to be removed and replaced with a more reasonable update script + + +# public doc upload +wwwdoc: wwwschema + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docs to public server" + rsync -vlHtr --delete --progress --rsh=ssh --exclude 'Schemas/*' --cvs-exclude $(ISISROOT)/doc/ $(USER)@astroweb:/www/sites/Isis/htdocs/ + +devdoc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docs to development server" + rsync -vlHtr --delete --progress --rsh=ssh --cvs-exclude $(ISISROOT)/doc/ $(USERDEV)@astrodev:/www/sites/Isis/htdocs/ + +# copy Schemas to public www + +wwwschema: schemas + echo " " + echo "_______________________________________________________________________________" + echo "SYNC: schemas to public server" + rsync -vlHtr --progress --rsh=ssh --cvs-exclude $(ISISROOT)/doc/Schemas/ $(USER)@astroweb:/www/sites/Isis/htdocs/Schemas/ + rsync -vlHptr --delete --progress --rsh=ssh --cvs-exclude $(ISISROOT)/doc/assets $(USER)@astroweb:/www/sites/Isis/htdocs/ + + + +syncall: + echo " " + echo " " + echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + echo "~ SYNC ALL ~" + echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + make wwwdoc + make devdoc + +syncdev: + echo " " + echo " " + echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + echo "~ SYNC DEV ~" + echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + make devdoc + diff --git a/isis/src/docsys/Object/Makefile b/isis/src/docsys/Object/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..083fdbfebedc2046274f7c94348c5d64c04121eb --- /dev/null +++ b/isis/src/docsys/Object/Makefile @@ -0,0 +1,228 @@ +include $(ISISROOT)/make/isismake.macros + +# ISIS DOCS MAKEFILE +# Create tables of contents for the Object +# documentation and kicks off lower makefiles +# dls - deborah lee soltesz - 4/25/2002 +# history +# dls 3/4/2005 - modified to use doxygen instead +# of IsisOML system + + +TOCDIR = $(ISISROOT)doc/Object +OBJECTASSETS = $(wildcard $(ISISROOT)/src/*/objs/*/assets/) + +help: + echo "Isis Object Documentation Make System Commands" + echo "------------------------ " + echo "make docs : Build Isis Object Documentation" + echo " " + echo "make wwwdocsrc : Sync Source to Public Web Server" + echo "make devdocsrc : Sync Source to Development Web Server" + echo "make wwwdoc : Sync Documentation to Public Web Server" + echo "make devdoc : Sync Documentation to Development Web Server" + echo " " + echo "make clean : Clean up Source Area (docsys/Object)" + + +docs: documentation assetsDir conf render + +documentation: + echo " Creating Object Documentation" + mkdir -p $(ISISROOT)/doc/Object + mkdir -p $(ISISROOT)/doc/Object/apps + mkdir -p $(ISISROOT)/doc/Object/Developer + mkdir -p $(ISISROOT)/doc/Object/Programmer +#dls 2006-10-04 -- took out -d on rsync that i'd added to make Sun happy +# (Sun = hipeaks)... Linux (orkin) was complaining + rsync -qlHptr --delete --rsh=ssh *.html $(ISISROOT)/doc/Object/ + rsync -qlHptr --delete --rsh=ssh build/isisDoxyDefs.doxydef $(ISISROOT)/doc/documents/DocStyle/assets/ + + +assetsDir: + echo " ...copying assets" + rsync -qlHptr --delete --rsh=ssh assets $(ISISROOT)/doc/Object/ + +conf: + echo " ...building apps configuration" + mkdir -p build/apps + cat build/apps_tag.conf > build/apps_tag_temp.conf + echo "OUTPUT_DIRECTORY = $(ISISROOT)/doc/Object/" >> build/apps_tag_temp.conf + echo "STRIP_FROM_PATH = $(ISISROOT)/" >> build/apps_tag_temp.conf + echo "INPUT = $(ISISROOT)/src/ \\" >> build/apps_tag_temp.conf + echo " build/isisAppsDoxyDefs.doxydef" >> build/apps_tag_temp.conf + echo "HTML_HEADER = build/IsisObjectHeaderApps.html" >> build/apps_tag_temp.conf + echo "HTML_FOOTER = build/IsisObjectFooter.html" >> build/apps_tag_temp.conf + echo "HTML_OUTPUT = apps" >> build/apps_tag_temp.conf + echo "HTML_STYLESHEET = build/doxygen_apps.css" >> build/apps_tag_temp.conf + + echo " ...building Programmer configuration" + cat build/Programmer.conf > build/Programmer_temp.conf + echo "OUTPUT_DIRECTORY = $(ISISROOT)/doc/Object/" >> build/Programmer_temp.conf + echo "FILE_PATTERNS = *objs*.h \ " >> build/Programmer_temp.conf + echo " *objs*.cpp \ " >> build/Programmer_temp.conf + echo " *build/isisDoxyDefs.doxydef" >> build/Programmer_temp.conf + echo "STRIP_FROM_PATH = $(ISISROOT)/" >> build/Programmer_temp.conf + echo "INPUT = build/isisDoxyDefs.doxydef $(ISISROOT)/src/ " >> build/Programmer_temp.conf + echo "HTML_HEADER = build/IsisObjectHeaderProgrammers.html" >> build/Programmer_temp.conf + echo "HTML_FOOTER = build/IsisObjectFooter.html" >> build/Programmer_temp.conf + echo "HTML_OUTPUT = Programmer" >> build/Programmer_temp.conf + echo "TAGFILES = build/apps/apps_fix.tag" >> build/Programmer_temp.conf + echo "HTML_STYLESHEET = build/doxygen_prog.css" >> build/Programmer_temp.conf + echo "IMAGE_PATH = " >> build/Programmer_temp.conf + + if [ "$(findstring LOUD,$(MODE))" = "LOUD" ]; \ + then \ + echo "QUIET = NO" >> build/Programmer_temp.conf; \ + echo "WARNINGS = YES" >> build/Programmer_temp.conf; \ + echo "WARN_IF_UNDOCUMENTED = YES" >> build/Programmer_temp.conf; \ + echo "WARN_IF_DOC_ERROR = YES" >> build/Programmer_temp.conf; \ + echo "WARN_NO_PARAMDOC = YES" >> build/Programmer_temp.conf; \ + else \ + echo "QUIET = YES" >> build/Programmer_temp.conf; \ + echo "WARNINGS = YES" >> build/Programmer_temp.conf; \ + echo "WARN_IF_UNDOCUMENTED = YES" >> build/Programmer_temp.conf; \ + echo "WARN_IF_DOC_ERROR = YES" >> build/Programmer_temp.conf; \ + echo "WARN_NO_PARAMDOC = YES" >> build/Programmer_temp.conf; \ + fi + + for dirname in "$(OBJECTASSETS)"; do \ + echo "$$dirname \\" >> build/Programmer_temp.conf ; \ + done + + echo " ...building Developer configuration" + cat build/Developer.conf > build/Developer_temp.conf + echo "OUTPUT_DIRECTORY = $(ISISROOT)/doc/Object/" >> build/Developer_temp.conf + echo "STRIP_FROM_PATH = $(ISISROOT)/" >> build/Developer_temp.conf + echo "INPUT = $(ISISROOT)/src/ \\" >> build/Developer_temp.conf + echo " build/isisDoxyDefs.doxydef" >> build/Developer_temp.conf + echo "HTML_HEADER = build/IsisObjectHeader.html" >> build/Developer_temp.conf + echo "HTML_FOOTER = build/IsisObjectFooter.html" >> build/Developer_temp.conf + echo "HTML_OUTPUT = Developer" >> build/Developer_temp.conf + echo "TAGFILES = build/apps/apps_fix.tag" >> build/Developer_temp.conf + echo "HTML_STYLESHEET = build/doxygen.css" >> build/Developer_temp.conf + echo "IMAGE_PATH = " >> build/Developer_temp.conf + if [ "$(findstring LOUD,$(MODE))" = "LOUD" ]; \ + then \ + echo "QUIET = NO" >> build/Developer_temp.conf; \ + echo "WARNINGS = YES" >> build/Developer_temp.conf; \ + echo "WARN_IF_UNDOCUMENTED = YES" >> build/Developer_temp.conf; \ + echo "WARN_IF_DOC_ERROR = YES" >> build/Developer_temp.conf; \ + echo "WARN_NO_PARAMDOC = YES" >> build/Developer_temp.conf; \ + else \ + echo "QUIET = YES" >> build/Developer_temp.conf; \ + echo "WARNINGS = NO" >> build/Developer_temp.conf; \ + echo "WARN_IF_UNDOCUMENTED = NO" >> build/Developer_temp.conf; \ + echo "WARN_IF_DOC_ERROR = NO" >> build/Developer_temp.conf; \ + echo "WARN_NO_PARAMDOC = NO" >> build/Developer_temp.conf; \ + fi + + for dirname in "$(OBJECTASSETS)" ; do \ + echo "$$dirname \\" >> build/Developer_temp.conf ; \ + done + + +render: doApps doProg doDev +doApps: + echo " ...building apps documentation" + doxygen build/apps_tag_temp.conf +# cp build/apps/apps.tag $(ISISROOT)/doc/Object/apps/ + $(XALAN) -o build/apps/apps_fix.tag build/apps/apps.tag build/IsisApplicationTagFix.xsl + cp build/apps/apps_fix.tag $(ISISROOT)/doc/Object/apps/ + +doProg: + echo " ...building Programmer documentation" + doxygen build/Programmer_temp.conf + cd $(ISISROOT)/doc/Object/Programmer ; perl installdox -l apps_fix.tag@../apps/ -q ; cd $(ISISROOT)/src/docsys/Object/ + +doDev: + echo " ...building Developer documentation" + doxygen build/Developer_temp.conf + cd $(ISISROOT)/doc/Object/Developer ; perl installdox -l apps_fix.tag@../apps/ -q ; cd $(ISISROOT)/src/docsys/Object/ + +doProgTest: + echo "Building ProgTester configuration" + mkdir -p docbuild + cat $(ISISROOT)/src/docsys/Object/build//Programmer.conf > docbuild/ProgTester_temp.conf + echo "FILE_PATTERNS = *.h \ " >> docbuild/ProgTester_temp.conf + echo " *.cpp \ " >> docbuild/ProgTester_temp.conf + echo " *build/isisDoxyDefs.doxydef" >> docbuild/ProgTester_temp.conf + echo "OUTPUT_DIRECTORY = $(CURDIR)/" >> docbuild/ProgTester_temp.conf + echo "STRIP_FROM_PATH = $(CURDIR)/" >> docbuild/ProgTester_temp.conf + echo "INPUT = $(CURDIR)/ \\" >> docbuild/ProgTester_temp.conf + echo " $(ISISROOT)/src/docsys/Object/build/isisDoxyDefs.doxydef" >> docbuild/ProgTester_temp.conf + echo "HTML_HEADER = $(ISISROOT)/src/docsys/Object/build/IsisObjectHeaderProgTester.html" >> docbuild/ProgTester_temp.conf + echo "HTML_FOOTER = $(ISISROOT)/src/docsys/Object/build/IsisObjectFooterProgTester.html" >> docbuild/ProgTester_temp.conf + echo "HTML_OUTPUT = html" >> docbuild/ProgTester_temp.conf + echo "TAGFILES = " >> docbuild/ProgTester_temp.conf + echo "HTML_STYLESHEET = $(ISISROOT)/src/docsys/Object/build/doxygen.css" >> docbuild/ProgTester_temp.conf + if [ "$(findstring LOUD,$(MODE))" = "LOUD" ]; \ + then \ + echo "QUIET = NO" >> build/ProgTester_temp.conf; \ + echo "WARNINGS = YES" >> build/ProgTester_temp.conf; \ + echo "WARN_IF_UNDOCUMENTED = YES" >> build/ProgTester_temp.conf; \ + echo "WARN_IF_DOC_ERROR = YES" >> build/ProgTester_temp.conf; \ + echo "WARN_NO_PARAMDOC = YES" >> build/ProgTester_temp.conf; \ + else \ + echo "QUIET = YES" >> build/ProgTester_temp.conf; \ + echo "WARNINGS = NO" >> build/ProgTester_temp.conf; \ + echo "WARN_IF_UNDOCUMENTED = NO" >> build/ProgTester_temp.conf; \ + echo "WARN_IF_DOC_ERROR = NO" >> build/ProgTester_temp.conf; \ + echo "WARN_NO_PARAMDOC = NO" >> build/ProgTester_temp.conf; \ + fi + doxygen docbuild/ProgTester_temp.conf + echo "View your documentation by opening the file html/index.html in a browser" +#do the following on a clean, as well as whacking the html directory created in this dir by doxy + rm -r docbuild + + + +#---- +# CLEAN +clean: + rm -f build/apps_tag_temp.conf + rm -f build/Programmer_temp.conf + rm -f build/Developer_temp.conf + rm -rf build/apps + rm -f ../documents/DocStyle/assets/isisDoxyDefs.doxydef + +cleandoc: + rm -r $(ISISROOT)/doc/Object + + + + + + +#TODO +# the following are temprary macros for updating the websites with the latest document build. +# these need to be removed and replaced with a more reasonable update script + +# public docsrc upload +wwwdocsrc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docsys to public server" + rsync -vlHptr --delete --progress --rsh=ssh $(ISISROOT)/src/docsys/* webmaster@wwwflag:/www/httpd/Astrogeology/Extranet/htdocs/Projects/IsisXML/docsrc/ + +# dev docsrc upload +devdocsrc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docsys to dev server" + rsync -vlHptr --delete --progress --rsh=ssh $(ISISROOT)/src/docsys/* dsoltesz@wwwdev:/www/httpd/Astrogeology/Extranet/htdocs/Projects/IsisXML/docsrc/ + +# public doc upload +wwwdoc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docs to public server" + rsync -vlHptr --delete --progress --rsh=ssh $(ISISROOT)/doc/* webmaster@wwwflag:/www/httpd/Astrogeology/Extranet/htdocs/Projects/IsisXML/doc/ + +# dev doc upload +devdoc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docs to dev server" + rsync -vlHptr --delete --progress --rsh=ssh $(ISISROOT)/doc/* dsoltesz@wwwdev:/www/httpd/Astrogeology/Extranet/htdocs/Projects/IsisXML/doc/ + diff --git a/isis/src/docsys/Object/alpha.html b/isis/src/docsys/Object/alpha.html new file mode 100644 index 0000000000000000000000000000000000000000..a7db0cdec2aeb5b97368b4d4cf3417ad4e33689d --- /dev/null +++ b/isis/src/docsys/Object/alpha.html @@ -0,0 +1,50 @@ + + + + + USGS: Isis Object Table of Contents (Alphabetized) + + + + + + + + + + + + + + + + + +USGS +
    +

    + Isis 3.0 Object Documentation

    +
    +

    + +Oops! You have reached a deprecated page! +The Isis Object Developers' Reference (the Isis API) +has moved. If your browser does not redirect to the new location momentarily, +follow this link to the Developers' Reference. + +

    + + + diff --git a/isis/src/docsys/Object/alpha_prog.html b/isis/src/docsys/Object/alpha_prog.html new file mode 100644 index 0000000000000000000000000000000000000000..d755f982ae0cf3b27d1c8fadb7f716f8c91c30bb --- /dev/null +++ b/isis/src/docsys/Object/alpha_prog.html @@ -0,0 +1,51 @@ + + + + + USGS: Isis Object Table of Contents (Alphabetized) + + + + + + + + + + + + + + + + + +USGS +
    +

    + Isis 3.0 Object Documentation

    +
    + +

    + +Oops! You have reached a deprecated page! +The Isis Object Programmers' Reference +has moved. If your browser does not redirect to the new location momentarily, +follow this link to the Programmers' Reference. + +

    + + + diff --git a/isis/src/docsys/Object/assets/styles/IsisObjectAPIDocStyle.css b/isis/src/docsys/Object/assets/styles/IsisObjectAPIDocStyle.css new file mode 100644 index 0000000000000000000000000000000000000000..a433d74cfd99255a30af3c4d0847112dd5fd007f --- /dev/null +++ b/isis/src/docsys/Object/assets/styles/IsisObjectAPIDocStyle.css @@ -0,0 +1,261 @@ + /* ISIS OBJECT PROGRAMMING DOC STYLE SHEET + * FILENAME: IsisObjectAPIDocStyle.css + * + * Purpose: formatting style sheet for Isis Object + * API documentation presentation + * + * Author: Deborah Lee Soltesz, USGS, 03/15/2002 + * Modified: Deborah Lee Soltesz, USGS, 12/02/2004 + * for use with new doxygen generated documentation + */ + + + /* ---------------------------------------------------------------- + * HEADINGS */ + + H1 { + color: #663333 ; + } + + H2 { + background-color: #CCAA99 ; + } + + H3 { + color: #663333 ; + } + + + HR { + color: #990000 ; + } + + + body { + background-repeat: repeat ; + background-attachment: fixed ; + background-image: URL('../../../assets/banners/isis_bg.jpg'); + } + + small { + font-size: 60%; + } + + + /* ----------------------------------------------------- + * DOXYGEN FORMATTING: styles taken from doxygen */ + +DIV.qindex { + width: 100%; + background-color: #775544; + color: #AA9988 ; + border: 1px solid #664433 ; + text-align: center; + margin: 2px; + padding: 4px; + line-height: 120%; +} + +A.qindexHL, A.qindex {color: #FFFFEE;} +A.qindexHL:visited, A.qindex:visited {color: #FFFFEE ;} +A.qindexHL:hover, A.qindexHL:active, A.qindex:hover, A.qindex:active {color: gold ;} + +.el { + font-family: Arial, Helvetica, SANS-SERIF ; + font-variant: normal ; + } + +A.el {} +A.elRef {} +A.code {} +A.codeRef {} +A:hover {} + +DL.el { margin-left: -1cm } +PRE.fragment { + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +DIV.fragment { + border: 1px solid #DDCCBB; + background-color: #fff9f3; + padding: 6px; + margin-bottom: 12px ; +} + +DIV.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px +} + +TD.md { + background-color: #FFEEDD; + font-weight: bold; +} +TD.mdname1 { + background-color: #FFEEDD; + font-weight: bold; + color: #602020; +} +TD.mdname { + background-color: #FFEEDD; + font-weight: bold; + color: #602020; + width: 600px; +} + +DIV.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; + font-family: Geneva, Arial, Helvetica, sans-serif; +} + +DIV.groupText { margin-left: 16px; font-style: italic; font-size: 14px } +BODY { + color: black; + margin-right: 20px; + margin-left: 20px; +} +TD.indexkey { + background-color: #EEDDCC; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #DDCCCC; +} +TD.indexvalue { + background-color: #FFEEDD; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #DDCCCC; +} +TR.memlist { + background-color: #f6f3f0; +} +P.formulaDsp { text-align: center; } +IMG.formulaDsp { } +IMG.formulaInl { vertical-align: middle; } + +img { + background-color: white ; + border: 2px solid black ; + padding: 5px; + margin: 5px; +} +img.noborder { + background-color: transparent ; + border: 0px none transparent ; + padding: 0px; +} + +SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #c06000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 } +.mdTable { + border: 1px solid #887766; + background-color: #FFEEDD; +} +.mdRow { + padding: 8px 10px; +} +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 14px; + font-style: italic; + background-color: #FFFFF0; + border-top: 1px none #E3E1E0; + border-right: 1px none #E3E1E0; + border-bottom: 1px none #E3E1E0; + border-left: 1px none #E3E1E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 14px; + font-style: italic; + background-color: #FFFFF0; + border-top: 1px none #E3E1E0; + border-right: 1px none #E3E1E0; + border-bottom: 1px none #E3E1E0; + border-left: 1px none #E3E1E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-style: solid; + border-top-color: #E3E1E0; + border-right-color: #E3E1E0; + border-bottom-color: #E3E1E0; + border-left-color: #E3E1E0; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FFFFF0; + font-family: Geneva, Arial, Helvetica, sans-serif; + font-size: 12px; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-style: solid; + border-top-color: #E3E1E0; + border-right-color: #E3E1E0; + border-bottom-color: #E3E1E0; + border-left-color: #E3E1E0; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FFFFF0; + font-family: Geneva, Arial, Helvetica, sans-serif; + font-size: 13px; +} +.search { color: #003399; + font-weight: bold; +} +FORM.search { + margin-bottom: 0px; + margin-top: 0px; +} +INPUT.search { font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #ffeeee; +} +TD.tiny { font-size: 75%;} diff --git a/isis/src/docsys/Object/assets/styles/tab_b.gif b/isis/src/docsys/Object/assets/styles/tab_b.gif new file mode 100644 index 0000000000000000000000000000000000000000..0d623483ffdf5f9f96900108042a7ab0643fe2a3 Binary files /dev/null and b/isis/src/docsys/Object/assets/styles/tab_b.gif differ diff --git a/isis/src/docsys/Object/assets/styles/tab_l.gif b/isis/src/docsys/Object/assets/styles/tab_l.gif new file mode 100644 index 0000000000000000000000000000000000000000..9b1e6337c9299a700401a2a78a2c6ffced475216 Binary files /dev/null and b/isis/src/docsys/Object/assets/styles/tab_l.gif differ diff --git a/isis/src/docsys/Object/assets/styles/tab_r.gif b/isis/src/docsys/Object/assets/styles/tab_r.gif new file mode 100644 index 0000000000000000000000000000000000000000..ce9dd9f533cb5486d6941844f442b59d4a9e9175 Binary files /dev/null and b/isis/src/docsys/Object/assets/styles/tab_r.gif differ diff --git a/isis/src/docsys/Object/assets/styles/tabs.css b/isis/src/docsys/Object/assets/styles/tabs.css new file mode 100644 index 0000000000000000000000000000000000000000..8c9c76c320c48cc8a3515f4ad7a783dfeda15a1c --- /dev/null +++ b/isis/src/docsys/Object/assets/styles/tabs.css @@ -0,0 +1,102 @@ +/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */ + +DIV.tabs +{ + float : left; + width : 100%; + background : url("tab_b.gif") repeat-x bottom; + margin-bottom : 4px; +} + +DIV.tabs UL +{ + margin : 0px; + padding-left : 10px; + list-style : none; +} + +DIV.tabs LI, DIV.tabs FORM +{ + display : inline; + margin : 0px; + padding : 0px; +} + +DIV.tabs FORM +{ + float : right; +} + +DIV.tabs A +{ + float : left; + background : url("tab_r.gif") no-repeat right top; + border-bottom : 1px solid #84B0C7; + font-size : x-small; + font-weight : bold; + text-decoration : none; +} + +DIV.tabs A:hover +{ + background-position: 100% -150px; +} + +DIV.tabs A:link, DIV.tabs A:visited, +DIV.tabs A:active, DIV.tabs A:hover +{ + color: #1A419D; +} + +DIV.tabs SPAN +{ + float : left; + display : block; + background : url("tab_l.gif") no-repeat left top; + padding : 5px 9px; + white-space : nowrap; +} + +DIV.tabs INPUT +{ + float : right; + display : inline; + font-size : 1em; +} + +DIV.tabs TD +{ + font-size : x-small; + font-weight : bold; + text-decoration : none; +} + + + +/* Commented Backslash Hack hides rule from IE5-Mac \*/ +DIV.tabs SPAN {float : none;} +/* End IE5-Mac hack */ + +DIV.tabs A:hover SPAN +{ + background-position: 0% -150px; +} + +DIV.tabs LI#current A +{ + background-position: 100% -150px; + border-width : 0px; +} + +DIV.tabs LI#current SPAN +{ + background-position: 0% -150px; + padding-bottom : 6px; +} + +DIV.nav +{ + background-color : none ; + border : none ; + border-bottom : 1px solid #84B0C7; +} diff --git a/isis/src/docsys/Object/build/Developer.conf b/isis/src/docsys/Object/build/Developer.conf new file mode 100644 index 0000000000000000000000000000000000000000..5fd6a63f5d3438fd957d7a476e15cb42b1af9723 --- /dev/null +++ b/isis/src/docsys/Object/build/Developer.conf @@ -0,0 +1,226 @@ +# Doxyfile 1.4.1 +# +# March 2005 +# developed by deborah lee soltesz & Leah Dahmer for generating +# the API version of Isis Object documentation for application developers + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = "Isis 3.0" +PROJECT_NUMBER = +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = YES +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = YES +FULL_PATH_NAMES = YES +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = YES +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +ALIASES = "history=\xrefitem history \"History\" \"History\"" +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = YES +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = NO +GENERATE_TESTLIST = NO +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +FILE_PATTERNS = *objs*.cpp \ + *objs*.h \ + *build/isisDoxyDefs.doxydef +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = *unitTest.cpp +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 3 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = Developer +HTML_FILE_EXTENSION = .html +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = Developer/latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = YES +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +# +# 2006-05-15 dls removed graphs - set CLASS_DIAGRAMS and HAVE_DOT to NO +# need to create an alternative API presentation with graphs +# +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = NO +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = NO +UML_LOOK = YES +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = NO +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = NO +DOT_IMAGE_FORMAT = png +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 600 +MAX_DOT_GRAPH_HEIGHT = 800 +MAX_DOT_GRAPH_DEPTH = 2 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = YES +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/isis/src/docsys/Object/build/IsisApplicationTagFix.xsl b/isis/src/docsys/Object/build/IsisApplicationTagFix.xsl new file mode 100644 index 0000000000000000000000000000000000000000..5a52c588e3cb47c0ed24b8a808522fc7699154fd --- /dev/null +++ b/isis/src/docsys/Object/build/IsisApplicationTagFix.xsl @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/isis/src/docsys/Object/build/IsisObjectFooter.html b/isis/src/docsys/Object/build/IsisObjectFooter.html new file mode 100644 index 0000000000000000000000000000000000000000..87e875abea0062706dcc04e166d57ed63d01a2ff --- /dev/null +++ b/isis/src/docsys/Object/build/IsisObjectFooter.html @@ -0,0 +1,5 @@ + + + + + diff --git a/isis/src/docsys/Object/build/IsisObjectFooterProgTester.html b/isis/src/docsys/Object/build/IsisObjectFooterProgTester.html new file mode 100644 index 0000000000000000000000000000000000000000..1c36e000ad2a6f2f4c3bb24bb517ab7024c485e0 --- /dev/null +++ b/isis/src/docsys/Object/build/IsisObjectFooterProgTester.html @@ -0,0 +1,6 @@ + +
    +[Footer: contact info, page info, notices, and links] + + + diff --git a/isis/src/docsys/Object/build/IsisObjectHeader.html b/isis/src/docsys/Object/build/IsisObjectHeader.html new file mode 100644 index 0000000000000000000000000000000000000000..83a6d0ecc1b466ac8e20e74c13b28da3c478694c --- /dev/null +++ b/isis/src/docsys/Object/build/IsisObjectHeader.html @@ -0,0 +1,69 @@ + + + + +USGS Astrogeology Isis API + + + + + + + + + + + + + + + + + +USGS +
    + + + + + + +
    +

    +Isis 3.0 Developer's Reference (API)

    +
    + + Home
    + +
    + diff --git a/isis/src/docsys/Object/build/IsisObjectHeaderApps.html b/isis/src/docsys/Object/build/IsisObjectHeaderApps.html new file mode 100644 index 0000000000000000000000000000000000000000..955ce0d3f2be59f768a05f03ec3067f45924faa1 --- /dev/null +++ b/isis/src/docsys/Object/build/IsisObjectHeaderApps.html @@ -0,0 +1,189 @@ + + + + +USGS Astrogeology Isis API + + + + + + + + + + + + + + + + + + + + +USGS +
    + + + + + + +
    +

    +Isis 3.0 Application Source Code Reference

    +
    + + Home
    + +
    + diff --git a/isis/src/docsys/Object/build/IsisObjectHeaderProgTester.html b/isis/src/docsys/Object/build/IsisObjectHeaderProgTester.html new file mode 100644 index 0000000000000000000000000000000000000000..05f7daa6018abbe6d14b0ce44cdf89ca5adaa9cd --- /dev/null +++ b/isis/src/docsys/Object/build/IsisObjectHeaderProgTester.html @@ -0,0 +1,285 @@ + + + + +USGS Astrogeology Isis API + + + + + + + + + + + + + + + + + +[USGS] +
    + + + + + + +
    +

    +Isis 3.0 Programmers Test Documentation

    +
    Home
    + +
    + diff --git a/isis/src/docsys/Object/build/IsisObjectHeaderProgrammers.html b/isis/src/docsys/Object/build/IsisObjectHeaderProgrammers.html new file mode 100644 index 0000000000000000000000000000000000000000..6c35eca0fbc3bcde8e1dbabe2335866cfdcc55e9 --- /dev/null +++ b/isis/src/docsys/Object/build/IsisObjectHeaderProgrammers.html @@ -0,0 +1,191 @@ + + + + +USGS Astrogeology Isis API + + + + + + + + + + + + + + + + + + + + + + + +USGS +
    + + + + + + +
    +

    +Isis 3.0 Object Programmers' Reference

    +
    + + Home
    + +
    + diff --git a/isis/src/docsys/Object/build/Programmer.conf b/isis/src/docsys/Object/build/Programmer.conf new file mode 100644 index 0000000000000000000000000000000000000000..5cbcb10c058f630620ec41597306d52dde9de06f --- /dev/null +++ b/isis/src/docsys/Object/build/Programmer.conf @@ -0,0 +1,225 @@ +# Doxyfile 1.4.1 +# +# March 2005 +# developed by deborah lee soltesz for generating +# application documentation and tag file for linking +# to Isis app docs from Isis Object documentation +# (for pointing to apps as examples of usage) + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = "Isis 3.0 Programmer Reference" +PROJECT_NUMBER = +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = YES +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = YES +FULL_PATH_NAMES = YES +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = YES +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +ALIASES = "history=\xrefitem history \"History\" \"History\"" +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = YES +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = INTERNAL +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +# file patterns for Programmer docs are set in the Object Makefile +#FILE_PATTERNS = *objs*.h \ +# *objs*.cpp \ +# *build/isisDoxyDefs.doxydef +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = *unitTest.cpp *moc_* +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 3 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = Programmer +HTML_FILE_EXTENSION = .html +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = Programmer/latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = YES +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = NO +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = NO +UML_LOOK = YES +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = NO +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = NO +DOT_IMAGE_FORMAT = png +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 600 +MAX_DOT_GRAPH_HEIGHT = 800 +MAX_DOT_GRAPH_DEPTH = 2 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = YES +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/isis/src/docsys/Object/build/apps_tag.conf b/isis/src/docsys/Object/build/apps_tag.conf new file mode 100644 index 0000000000000000000000000000000000000000..d3b309eaba4a29e06018b81f63a28aac7ca355aa --- /dev/null +++ b/isis/src/docsys/Object/build/apps_tag.conf @@ -0,0 +1,232 @@ +# Doxyfile 1.4.1 +# +# March 2005 +# developed by deborah lee soltesz for generating +# application documentation and tag file for linking +# to Isis app docs from Isis Object documentation +# (for pointing to apps as examples of usage) + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = "Isis 3.0 Applications" +PROJECT_NUMBER = +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = YES +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = YES +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +ALIASES = "history=\xrefitem history \"History\" \"History\"" \ + "whatsnew=\xrefitem whatsnew \"What's New\" \"What's New\"" +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = YES +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = NO +GENERATE_TESTLIST = NO +GENERATE_BUGLIST = NO +GENERATE_DEPRECATEDLIST= NO +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = NO +WARN_IF_UNDOCUMENTED = NO +WARN_IF_DOC_ERROR = NO +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +FILE_PATTERNS = *apps*.h \ + *apps*.cpp \ + *build/isisAppsDoxyDefs.doxydef +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = *unitTest.cpp +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = NO +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +VERBATIM_HEADERS = NO +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 3 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = apps +HTML_FILE_EXTENSION = .html +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = NO +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = build/apps/apps.tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = NO +HAVE_DOT = YES +CLASS_GRAPH = NO +COLLABORATION_GRAPH = NO +GROUP_GRAPHS = NO +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = NO +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = NO +DIRECTORY_GRAPH = NO +DOT_IMAGE_FORMAT = png +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 600 +MAX_DOT_GRAPH_HEIGHT = 800 +MAX_DOT_GRAPH_DEPTH = 2 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = YES +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/isis/src/docsys/Object/build/doxygen.css b/isis/src/docsys/Object/build/doxygen.css new file mode 100644 index 0000000000000000000000000000000000000000..f3283fd8a60f8495ae6ee0abf560b5065fe18138 --- /dev/null +++ b/isis/src/docsys/Object/build/doxygen.css @@ -0,0 +1,358 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Geneva, Arial, Helvetica, sans-serif; +} +BODY,TD { + font-size: 90%; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} +CAPTION { font-weight: bold } +DIV.qindex { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.nav { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.navtab { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +TD.navtab { + font-size: 70%; +} +A.qindex { + text-decoration: none; + font-weight: bold; + color: #1A419D; +} +A.qindex:visited { + text-decoration: none; + font-weight: bold; + color: #1A419D +} +A.qindex:hover { + text-decoration: none; + background-color: #ddddff; +} +A.qindexHL { + text-decoration: none; + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} +A.qindexHL:hover { + text-decoration: none; + background-color: #6666cc; + color: #ffffff; +} +A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } +A.el { text-decoration: none; font-weight: bold } +A.elRef { font-weight: bold } +A.code:link { text-decoration: none; font-weight: normal; color: #0000FF} +A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} +A.codeRef:link { font-weight: normal; color: #0000FF} +A.codeRef:visited { font-weight: normal; color: #0000FF} +A:hover { text-decoration: none; background-color: #f2f2ff } +DL.el { margin-left: -1cm } +.fragment { + font-family: monospace, fixed; + font-size: 95%; +} +PRE.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } + +DIV.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} +DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% } +BODY { + background: #DDCCBB ; + color: black; + margin-right: 20px; + margin-left: 20px; +} +TD.indexkey { + background-color: #e8eef2; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TD.indexvalue { + background-color: #e8eef2; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TR.memlist { + background-color: #f0f0f0; +} +P.formulaDsp { text-align: center; } +IMG.formulaDsp { } +IMG.formulaInl { vertical-align: middle; } +SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #e08000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 } +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplParams { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + color: #606060; + background-color: #FAFAFA; + font-size: 80%; +} +.search { color: #003399; + font-weight: bold; +} +FORM.search { + margin-bottom: 0px; + margin-top: 0px; +} +INPUT.search { font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +TD.tiny { font-size: 75%; +} +a { + color: #1A41A8; +} +a:visited { + color: #2A3798; +} +.dirtab { padding: 4px; + border-collapse: collapse; + border: 1px solid #84b0c7; +} +TH.dirtab { background: #e8eef2; + font-weight: bold; +} +HR { height: 1px; + border: none; + border-top: 1px solid black; +} + +/* Style for detailed member documentation */ +.memtemplate { + font-size: 80%; + color: #606060; + font-weight: normal; +} +.memnav { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +.memitem { + padding: 4px; + background-color: #eef3f5; + border-width: 1px; + border-style: solid; + border-color: #dedeee; + -moz-border-radius: 8px 8px 8px 8px; +} +.memname { + white-space: nowrap; + font-weight: bold; +} +.memdoc{ + padding-left: 10px; +} +.memproto { + background-color: #d5e1e8; + width: 100%; + border-width: 1px; + border-style: solid; + border-color: #84b0c7; + font-weight: bold; + -moz-border-radius: 8px 8px 8px 8px; +} +.paramkey { + text-align: right; +} +.paramtype { + white-space: nowrap; +} +.paramname { + color: #602020; + font-style: italic; +} +/* End Styling for detailed member documentation */ + +/* for the tree view */ +.ftvtree { + font-family: sans-serif; + margin:0.5em; +} +.directory { font-size: 9pt; font-weight: bold; } +.directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } +.directory > h3 { margin-top: 0; } +.directory p { margin: 0px; white-space: nowrap; } +.directory div { display: none; margin: 0px; } +.directory img { vertical-align: -30%; } + diff --git a/isis/src/docsys/Object/build/doxygen_apps.css b/isis/src/docsys/Object/build/doxygen_apps.css new file mode 100644 index 0000000000000000000000000000000000000000..04af5d0da62c0a53ee0402d8ad77439ba1ba300f --- /dev/null +++ b/isis/src/docsys/Object/build/doxygen_apps.css @@ -0,0 +1,358 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Geneva, Arial, Helvetica, sans-serif; +} +BODY,TD { + font-size: 90%; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} +CAPTION { font-weight: bold } +DIV.qindex { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.nav { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.navtab { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +TD.navtab { + font-size: 70%; +} +A.qindex { + text-decoration: none; + font-weight: bold; + color: #1A419D; +} +A.qindex:visited { + text-decoration: none; + font-weight: bold; + color: #1A419D +} +A.qindex:hover { + text-decoration: none; + background-color: #ddddff; +} +A.qindexHL { + text-decoration: none; + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} +A.qindexHL:hover { + text-decoration: none; + background-color: #6666cc; + color: #ffffff; +} +A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } +A.el { text-decoration: none; font-weight: bold } +A.elRef { font-weight: bold } +A.code:link { text-decoration: none; font-weight: normal; color: #0000FF} +A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} +A.codeRef:link { font-weight: normal; color: #0000FF} +A.codeRef:visited { font-weight: normal; color: #0000FF} +A:hover { text-decoration: none; background-color: #f2f2ff } +DL.el { margin-left: -1cm } +.fragment { + font-family: monospace, fixed; + font-size: 95%; +} +PRE.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } + +DIV.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} +DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% } +BODY { + background: #99DDDD ; + color: black; + margin-right: 20px; + margin-left: 20px; +} +TD.indexkey { + background-color: #e8eef2; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TD.indexvalue { + background-color: #e8eef2; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TR.memlist { + background-color: #f0f0f0; +} +P.formulaDsp { text-align: center; } +IMG.formulaDsp { } +IMG.formulaInl { vertical-align: middle; } +SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #e08000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 } +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplParams { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + color: #606060; + background-color: #FAFAFA; + font-size: 80%; +} +.search { color: #003399; + font-weight: bold; +} +FORM.search { + margin-bottom: 0px; + margin-top: 0px; +} +INPUT.search { font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +TD.tiny { font-size: 75%; +} +a { + color: #1A41A8; +} +a:visited { + color: #2A3798; +} +.dirtab { padding: 4px; + border-collapse: collapse; + border: 1px solid #84b0c7; +} +TH.dirtab { background: #e8eef2; + font-weight: bold; +} +HR { height: 1px; + border: none; + border-top: 1px solid black; +} + +/* Style for detailed member documentation */ +.memtemplate { + font-size: 80%; + color: #606060; + font-weight: normal; +} +.memnav { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +.memitem { + padding: 4px; + background-color: #eef3f5; + border-width: 1px; + border-style: solid; + border-color: #dedeee; + -moz-border-radius: 8px 8px 8px 8px; +} +.memname { + white-space: nowrap; + font-weight: bold; +} +.memdoc{ + padding-left: 10px; +} +.memproto { + background-color: #d5e1e8; + width: 100%; + border-width: 1px; + border-style: solid; + border-color: #84b0c7; + font-weight: bold; + -moz-border-radius: 8px 8px 8px 8px; +} +.paramkey { + text-align: right; +} +.paramtype { + white-space: nowrap; +} +.paramname { + color: #602020; + font-style: italic; +} +/* End Styling for detailed member documentation */ + +/* for the tree view */ +.ftvtree { + font-family: sans-serif; + margin:0.5em; +} +.directory { font-size: 9pt; font-weight: bold; } +.directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } +.directory > h3 { margin-top: 0; } +.directory p { margin: 0px; white-space: nowrap; } +.directory div { display: none; margin: 0px; } +.directory img { vertical-align: -30%; } + diff --git a/isis/src/docsys/Object/build/doxygen_prog.css b/isis/src/docsys/Object/build/doxygen_prog.css new file mode 100644 index 0000000000000000000000000000000000000000..04af5d0da62c0a53ee0402d8ad77439ba1ba300f --- /dev/null +++ b/isis/src/docsys/Object/build/doxygen_prog.css @@ -0,0 +1,358 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Geneva, Arial, Helvetica, sans-serif; +} +BODY,TD { + font-size: 90%; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} +CAPTION { font-weight: bold } +DIV.qindex { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.nav { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.navtab { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +TD.navtab { + font-size: 70%; +} +A.qindex { + text-decoration: none; + font-weight: bold; + color: #1A419D; +} +A.qindex:visited { + text-decoration: none; + font-weight: bold; + color: #1A419D +} +A.qindex:hover { + text-decoration: none; + background-color: #ddddff; +} +A.qindexHL { + text-decoration: none; + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} +A.qindexHL:hover { + text-decoration: none; + background-color: #6666cc; + color: #ffffff; +} +A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } +A.el { text-decoration: none; font-weight: bold } +A.elRef { font-weight: bold } +A.code:link { text-decoration: none; font-weight: normal; color: #0000FF} +A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} +A.codeRef:link { font-weight: normal; color: #0000FF} +A.codeRef:visited { font-weight: normal; color: #0000FF} +A:hover { text-decoration: none; background-color: #f2f2ff } +DL.el { margin-left: -1cm } +.fragment { + font-family: monospace, fixed; + font-size: 95%; +} +PRE.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } + +DIV.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} +DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% } +BODY { + background: #99DDDD ; + color: black; + margin-right: 20px; + margin-left: 20px; +} +TD.indexkey { + background-color: #e8eef2; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TD.indexvalue { + background-color: #e8eef2; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TR.memlist { + background-color: #f0f0f0; +} +P.formulaDsp { text-align: center; } +IMG.formulaDsp { } +IMG.formulaInl { vertical-align: middle; } +SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #e08000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 } +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplParams { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + color: #606060; + background-color: #FAFAFA; + font-size: 80%; +} +.search { color: #003399; + font-weight: bold; +} +FORM.search { + margin-bottom: 0px; + margin-top: 0px; +} +INPUT.search { font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +TD.tiny { font-size: 75%; +} +a { + color: #1A41A8; +} +a:visited { + color: #2A3798; +} +.dirtab { padding: 4px; + border-collapse: collapse; + border: 1px solid #84b0c7; +} +TH.dirtab { background: #e8eef2; + font-weight: bold; +} +HR { height: 1px; + border: none; + border-top: 1px solid black; +} + +/* Style for detailed member documentation */ +.memtemplate { + font-size: 80%; + color: #606060; + font-weight: normal; +} +.memnav { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +.memitem { + padding: 4px; + background-color: #eef3f5; + border-width: 1px; + border-style: solid; + border-color: #dedeee; + -moz-border-radius: 8px 8px 8px 8px; +} +.memname { + white-space: nowrap; + font-weight: bold; +} +.memdoc{ + padding-left: 10px; +} +.memproto { + background-color: #d5e1e8; + width: 100%; + border-width: 1px; + border-style: solid; + border-color: #84b0c7; + font-weight: bold; + -moz-border-radius: 8px 8px 8px 8px; +} +.paramkey { + text-align: right; +} +.paramtype { + white-space: nowrap; +} +.paramname { + color: #602020; + font-style: italic; +} +/* End Styling for detailed member documentation */ + +/* for the tree view */ +.ftvtree { + font-family: sans-serif; + margin:0.5em; +} +.directory { font-size: 9pt; font-weight: bold; } +.directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } +.directory > h3 { margin-top: 0; } +.directory p { margin: 0px; white-space: nowrap; } +.directory div { display: none; margin: 0px; } +.directory img { vertical-align: -30%; } + diff --git a/isis/src/docsys/Object/build/isisAppsDoxyDefs.doxydef b/isis/src/docsys/Object/build/isisAppsDoxyDefs.doxydef new file mode 100644 index 0000000000000000000000000000000000000000..7fb1c85fd86cf41abc44ac35c990a36fbd1ce22d --- /dev/null +++ b/isis/src/docsys/Object/build/isisAppsDoxyDefs.doxydef @@ -0,0 +1,39 @@ +// this file should not be shown in doxygen output if possible + +/** + * @file + * This file contains internal configuration settings + * for the %Isis API and Programmer documentation. + */ + +/** @internal + * isisAppsDoxyDefs.doxydef + * + * This file contains doxygen commands for setting up + * global documentation options shared by all %Isis + * apps + * + * @author deborah lee soltesz 2004-11-03 + * @history 2005-03-10 deborah lee soltesz modified for + * apps from objects conf + */ + + +// MAIN PAGE - content of the table-of-contents page for the %Isis 3.0 Object Documentation +// TODO: look at using doxy conditional processing to have different main page for +// API vs. Programmer Docs + + /** + * \mainpage Isis 3.0 Application Documentation + * + * This documentation is generated merely to provide copies of application + * source code for the %Isis 3.0 Developers' Reference (API) + * and Programmers' References. Actual + * Isis application documentation (usage, examples, etc.) are provided + * in the Isis Software Manual. + * + */ + + + + diff --git a/isis/src/docsys/Object/build/isisDoxyDefs.doxydef b/isis/src/docsys/Object/build/isisDoxyDefs.doxydef new file mode 100644 index 0000000000000000000000000000000000000000..8d9139c8f1250fab2c6c745cf7c029f60a6e7ca8 --- /dev/null +++ b/isis/src/docsys/Object/build/isisDoxyDefs.doxydef @@ -0,0 +1,579 @@ +// this file should not be shown in doxygen output if possible + +/** + * \file + * This file contains internal configuration settings + * for the %Isis API and Programmer documentation. + */ + + +/** + * \namespace Isis + * + * Namespace for all %Isis base objects + * + */ +/** + * \namespace Isis::Message + * + * Namespace containing standardized %Isis error messages + * + * IsisMessage is not a class. It only contains a namespace which consists of + * all the standardized Isis error messages. These messages should be used + * when applicable instead of constructing the message string inside the + * object or application. + * + */ +/** + * \namespace Galileo + * + * Namespace for all %Isis Galileo mission objects + * + */ +/** + * \namespace Isis::Mgs + * + * Namespace for all %Isis Mars Global Surveyor mission objects + * + */ +/** + * \namespace Isis::Mro + * + * Namespace for all %Isis Mars Reconnaissance Orbiter mission objects + * + */ +/** + * \namespace Isis::Odyssey + * + * Namespace for all %Isis Mars Odyssey mission objects + * + */ + +/** + * \namespace Isis::Lo + * + * Namespace for all %Isis Lunar Orbiter mission objects + * + */ +/** + * \namespace Isis::Lro + * + * Namespace for all %Isis Lunar Reconnaissance Orbiter mission objects + * + */ + + +/** + * \namespace Qisis + * + * Namespace for the %Isis visualazation objects + * + */ +/** + * \namespace std + * + * Namespace for the standard library + * + */ + + +/** \internal + * isisDoxyDefs.doxydef + * + * This file contains doxygen commands for setting up + * global documentation options shared by all %Isis + * Objects, such as module/category definitions, main + * page content, etc. + * + * @author deborah lee soltesz 2004-11-03 + * @history 2005-03-07 deborah lee soltesz - Completed main page content. + * @history 2005-03-07 deborah lee soltesz - Completed and refine module descriptions. + * @history 2006-08-10 deborah lee soltesz - Added "Radiometric and Photometric Corrections" and alphabetized mission-specific categories + * @history 2008-05-19 steven lambright - Fixed Mission End Group Tag + * @history 2008-05-19 steven lambright - Fixed Bad Namespace Documentation + * + * @todo Develop two different pages for API vs. Programmer + * documentation. 2004-11-03 + * @todo Make "std" namespace invisible... probably not gonna happen + */ + +// BASE + + // GEOMETRY + /** + * \defgroup Geometry Geometry + * + * The Objects in this module are used in the performance of + * geometric transformations of a cube. + */ + + // HIGH LEVEL CUBE IO + /** + * \defgroup HighLevelCubeIO High Level Cube I/O + * + * The Objects in this module are used to read and write cube data. + * + */ + + // LOW LEVEL CUBE IO + /** + * \defgroup LowLevelCubeIO Low Level Cube I/O + * + * The Objects in this module are used to read and write cube data. + * + */ + + // MAP PROJECTION + /** + * \defgroup MapProjection Map Projection + * + * The Objects in this module are used to set, manipulate, and get + * projection information for a cube. + * + */ + + // PARSING + /** + * \defgroup Parsing Parsing + * + * The Objects in this module provide a variety of text parsing functionality + * for reading, manipulating, and internalizing file lists, dates, PVL format, + * and other textual information. + * + */ + + // SPICE + /** + * \defgroup SpiceInstrumentsAndCameras Spice, Instruments, and Cameras + * + * The Objects in this module are used to read and manipulate Spice data. + * + */ + + // STATS + /** + * \defgroup Statistics Statistics + * + * The Objects in this module are used to generate a variety of statistics + * from cube data. + * + */ + + // APPLICATION INTERFACE + /** + * \defgroup ApplicationInterface Application Interface + * + * Objects for managing and displaying the graphical and command line user + * interfaces of non-interactive Isis Applications. + * + */ + + // VISUALIZATION TOOLS + /** + * \defgroup VisualizationTools Visualization Tools + * + * Objects for building graphical user interfaces and other aspects of + * interactive Isis Visualization Applications. + * + */ + + // UI + /** + * \defgroup UserInterface User Interface + * + * Objects for managing and displaying the graphical and command line user + * interfaces. + * + * @deprecated Objects in this category should be moved to the ApplicationInteface + * group + * + */ + + // UTILITY + /** + * \defgroup Utility Utility + * + * Objects providing general functionality. + * + */ + + // SYSTEM + /** + * \defgroup System System + * + * The Objects in this module manage, manipulate, or otherwise + * deal with the %Isis build/run environment. + * + */ + + // MATH + /** + * \defgroup Math Math + * + * The Objects in this module perform math on cube data. + * + */ + + // RADIOMETRIC AND PHOTOMETRIC CORRECTION + /** + * \defgroup RadiometricAndPhotometricCorrection Radiometric And Photometric Correction + * + * The Objects in this module perform radiometric correction, photometric modelling, and photmetric correction. + * + */ + + + // PATTERN MATCHING + /** + * \defgroup PatternMatching Pattern Matching + * + * The Objects in this module can be used to auto-correlate areas + * between images. + */ + + // CONTROL NETWORKS + /** + * \defgroup ControlNetworks Control Networks + * + * The Objects in this module are used to define, record, and edit match points + * and control points between images. + */ + +// MISSIONS + + /** + * \defgroup Mission Mission Specific Objects + * + * These modules contain Objects specific to various mission data. + * + * @{ + */ + + // CASSINI + /** + * \defgroup Cassini Cassini + * + * These objects provide functionality for manipulating data from the + * Cassini-Huygens Mission to Saturn and its moons. Four NASA spacecraft + * have been sent to explore Saturn. Pioneer 11 was first to fly past + * Saturn in 1979. Voyager 1 flew past a year later, followed by its twin, + * Voyager 2, in 1981. The Cassini spacecraft is the first to explore the + * Saturn system of rings and moons from orbit. The European Space Agency's + * Huygens Probe dove into Titan's thick atmosphere in January 2005. The + * sophisticated instruments on both spacecraft are providing scientists with + * vital data and the best views ever of this mysterious, vast region of our + * solar system. + * + * Mission site: http://saturn.jpl.nasa.gov/ + * + * USGS Astrogeology: http://astrogeology.usgs.gov/Missions/Cassini/ + * + */ + + // CLEMENTINE + /** + * \defgroup Clementine Clementine + * + * These objects provide functionality for manipulating data from the + * Clemtine mission to the Earth's Moon. Clementine was a joint project + * between the Strategic Defense Initiative Organization and NASA. The + * objective of the mission was to test sensors and spacecraft components + * under extended exposure to the space environment and to make scientific + * observations of the Moon and the near-Earth asteroid 1620 Geographos. + * The observations included imaging at various wavelengths including + * ultraviolet and infrared, laser ranging altimetry, and charged particle + * measurements. These observations were originally for the purposes of + * assessing the surface mineralogy of the Moon and Geographos, obtaining + * lunar altimetry from 60N to 60S latitude, and determining the size, shape, + * rotational characteristics, surface properties, and cratering statistics of + * Geographos. + * + * Mission site: http://nssdc.gsfc.nasa.gov/planetary/clementine.html + * + * USGS Astrogeology: http://astrogeology.usgs.gov/Missions/Clementine/ + */ + + // GALILEO + /** + * \defgroup Galileo Galileo + * + * These objects provide functionality for manipulating data from the + * %Galileo mission to Jupiter. Launched in 1989, he %Galileo mission consisted of two spacecraft: + * an orbiter and an atmospheric probe. During the flybys of Venus and the Earth in transit to Jupiter, + * %Galileo scientists took the opportunity to study these two planets as well as + * the Moon, making some unprecedented observations as a result. In addition, + * following each Earth flyby, %Galileo made excursions as far out in the solar + * system as the asteroid belt, enabling scientists to make the first close-up + * studies of two asteroids, Gaspra and Ida. %Galileo scientists were fortunate to + * be the only ones with a direct view of the Comet Shoemaker-Levy 9 fragment impacts + * on Jupiter. The primary mission involved sending an atmospheric probe into Jupiter's + * atmosphere and studying Jupiter, its satellites, and its magnetosphere with the orbiter. + * In 2003, the orbiter was deliberately destroyed by plunging it into Jupiter's atmophere. + * + * Mission site: http://voyager.jpl.nasa.gov/ + * + * USGS Astrogeology: http://astrogeology.usgs.gov/Missions/Galileo/ + */ + + // MARINER + /** + * \defgroup Mariner Mariner + * + * These objects provide functionality for manipulating data from the + * Mariner missions. From 1962 to 1973, ten planetary spacecraft were + * launched under the name Mariner, targeting our neighbors, the inner + * planets Mercury, Venus, and Mars. There were six missions, most missions + * launching a pair of Mariner spacecrafts a few months apart. Of the ten + * launched Magellan spacecrafts, seven were successful in their missions, + * and three were lost due to launch vehicle failures. + * + * USGS Astrogeology: http://astrogeology.usgs.gov/Missions/Mariner/ + * + */ + + // MARS EXPLORATION ROVERS + /** + * \defgroup MarsExplorationRover Mars Exploration Rover + * + * These objects provide functionality for manipulating data from the + * 2003 Mars Exploration Rover mission. The Mars Exploration Rover + * mission launched in the summer of 2003. Rover Spirit landed 3 January + * 2004, and Rover Opportunity landed 24 January 2004. Both rovers have + * been very successful and are have had their missions extended beyond + * the initial three month mission plan. + * + * MER Athena science package site: http://athena.cornell.edu/ + * + * USGS Astrogeology: http://astrogeology.usgs.gov/Missions/Rovers/ + * + */ + + // MGS + /** + * \defgroup MarsGlobalSurveyor Mars Global Surveyor + * + * These objects provide functionality for manipulating data from the + * Mars Global Surveyor mission. + * + * Mission site: http://mars.jpl.nasa.gov/mgs/ + * + * USGS Astrogeology: http://astrogeology.usgs.gov/Missions/MarsGlobalSurveyor/ + * + */ + + // MARS ODYSSEY + /** + * \defgroup MarsOdyssey Mars Odyssey + * + * These objects provide functionality for manipulating data from the + * 2001 Mars Odyssey mission. Mars Odyssey is part of NASA's Mars Exploration + * Program, a long-term effort of robotic exploration of the red planet. + * Odyssey's primary science mission took place February 2002 through August 2004, + * and the orbiter began its extended mission on August 24, 2004. For the first time, + * the mission mapped the amount and distribution of chemical elements and minerals + * that make up the martian surface. The spacecraft globally mapped many elements, + * and the maps of hydrogen distribution led scientists to discover vast amounts of + * water ice in the polar regions burried just beneath the surface. Odyssey recorded + * the radiation environment in low Mars orbit to determine the radiation-related risk + * to any future human explorers who may one day go to Mars. All of these objectives + * support the four science goals of the Mars Exploration Program. + * + * Mission site: http://mars.jpl.nasa.gov/odyssey/ + * + * USGS Astrogeology: http://astrogeology.usgs.gov/Missions/More/#Odyssey + * + */ + + + // MRO + /** + * \defgroup MarsReconnaissanceOrbiter Mars Reconnaissance Orbiter + * + * These objects provide functionality for manipulating data from the + * Mars Reconnaissance Orbiter mission.Mars Reconnaissance Orbiter, + * scheduled for launch in 2005, is on a search for evidence that water + * persisted on the surface of Mars for a long period of time. While other + * Mars missions have shown that water flowed across the surface in Mars' + * history, it remains a mystery whether water was ever around long enough + * to provide a habitat for life. + * + * Mission site: http://mars3.jpl.nasa.gov/mro/ + * + */ + + // MESSENGER + /** + * \defgroup MESSENGER Mercury MESSENGER + * + * These objects provide functionality for manipulating data from the + * MESSENGER Mission to Mercury. MESSENGER launched from Cape Canaveral + * Air Force Station, Fla., on August 3, 2004. It will fly past Venus + * twice, in October 2006 and June 2007. + * Three Mercury flybys, each followed about two months later by a course + * correction maneuver, put MESSENGER in position to enter Mercury orbit + * in March 2011. During the flybys MESSENGER will map nearly the entire + * planet in color, image most of the areas unseen by Mariner 10, and + * measure the composition of the surface, atmosphere and magnetosphere. + * It will be the first new data from Mercury in more than 30 years. + * + * Mission site: http://messenger.jhuapl.edu/ + * + */ + + // VIKING + /** + * \defgroup Viking Viking + * + * These objects provide functionality for manipulating data from the Mars + * Viking orbiters. Viking Mission to Mars was composed of two + * spacecraft, Viking 1 and Viking 2, each consisting of an orbiter and + * a lander. The primary mission objectives were to obtain high resolution + * images of the Martian surface, characterize the structure and composition + * of the atmosphere and surface, and search for evidence of life. + * + * Mission site: http://voyager.jpl.nasa.gov/ + * + * USGS Astrogeology: http://astrogeology.usgs.gov/Missions/Viking/ + */ + + // VOYAGER + /** + * \defgroup Voyager Voyager + * + * These objects provide functionality for manipulating data from the + * Voyager mission to the outer planets. The primary mission was the exploration of Jupiter + * and Saturn. After making a string of discoveries there -- such as active + * volcanoes on Jupiter's moon Io and intricacies of Saturn's rings -- the + * mission was extended. Voyager 2 went on to explore Uranus and Neptune, and + * is still the only spacecraft to have visited those outer planets. The + * current mission, the Voyager Interstellar Mission (VIM) is exploring the outermost + * edge of the solar system and beyond. + * + * Mission site: http://voyager.jpl.nasa.gov/ + * + * USGS Astrogeology: http://astrogeology.usgs.gov/Missions/Voyager/ + * + */ + + + + // LUNAR ORBITER + /** + * \defgroup LunarOrbiter Lunar Orbiter + * + * These objects provide functionality for manipulating data from the + * Lunar Orbiter missions of the 1960's. + * + * Mission summary: http://www.lpi.usra.edu/expmoon/orbiter/orbiter.html + * + * USGS Astrogeology: http://astrogeology.usgs.gov/Missions/LunarOrbiter/ + * + */ + + // LUNAR RECONNAISSANCE ORBITER + /** + * \defgroup LunarReconnaissance Orbiter Lunar Reconnaissance Orbiter + * + * These objects provide functionality for manipulating data from the + * Lunar Reconnaissance Orbiter (2008). + * + * Mission site: http://lunar.gsfc.nasa.gov/ + * + */ + + + + + /* @} end of Missions group */ + + +// MAIN PAGE - content of the table-of-contents page for the %Isis 3.0 Object Documentation +// TODO: look at using doxy conditional processing to have different main page for +// API vs. Programmer Docs + + /** + * \mainpage Isis 3.0 Object Documentation + * + * The %Isis 3.0 Developers' (API) and Programmers' References are provided on this + * site for developers to access information about the %Isis Objects that are the + * building blocks of the %Isis software package. %Isis 3.0 is written in the C++ + * programming language. %Isis 3.0 Objects are in $ISISROOT/src/[module]/objs, + * where [module] is a subdirectory containing related Objects. + * + * The Developers' Reference, also called the Application Program Interface (API), + * is designed for %Isis application developers. Only information of use and interest + * to an application developer is provided, such as public and protected class members, + * deprecated items, known bugs, etc. + * + * The Programmers' Reference is designed primarily for our in-house %Isis programming team who + * develop and maintain %Isis Objects. Information provided in the Programmers' Reference includes + * internal documentation, to-do lists, private members, etc. + * + * Currently, Object documentation is under development as we move to a new documentation system + * and old documentation is converted to the new system, content is reviewed and updated, and + * new documentation is completed. The References will be updated frequently on the + * %Isis 3.0 website - access them via the + * %Isis 3.0 Technical Docs link on the home page. + * + * \section section1 Objects + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    + *

    General

    + *

    Modules: Classes by Category

    + *

    Alphabetical List of Classes

    + *

    What's New

    + *
    + *

    File I/O

    + *

    High Level Cube I/O

    + *

    Low Level Cube I/O

    + *

    Parsing

    + *
    + *

    Math

    + *

    Math

    + *

    Statistics

    + *

    Geometry

    + *
    + *

    Cartography

    + *

    Map Projection

    + *

    Spice, Instruments, and Cameras

    + *

    Control Networks

    + *
    + *

    Missions

    + *

    + * Mars Reconnaissance Orbiter + *

    + *

    + * Mars Exploration Rover + *

    + *

    + * Cassini-Huygens + *

    + *

    + * All Mission Specific Objects + *

    + *
    + *

    Miscellaneous

    + *

    Radiometric And Photometric Correction

    + *

    Pattern Matching

    + *

    Visualization Tools

    + *

    Application Interface

    + *

    Utility

    + *

    System

    + *
    + */ + + + + diff --git a/isis/src/docsys/Object/index.html b/isis/src/docsys/Object/index.html new file mode 100644 index 0000000000000000000000000000000000000000..418458380dcf56b230014d4600bd17a67feb62ee --- /dev/null +++ b/isis/src/docsys/Object/index.html @@ -0,0 +1,52 @@ + + + + + USGS: Isis Object Table of Contents (Categorical) + + + + + + + + + + + + + + + + + +USGS +
    +

    + Isis 3.0 Object Documentation

    +
    + +

    + +Oops! You have reached a deprecated page! +The Isis Object Developers' Reference (the Isis API) +has moved. If your browser does not redirect to the new location momentarily, +follow this link to the Developers' Reference. + +

    + + + + diff --git a/isis/src/docsys/Object/index_prog.html b/isis/src/docsys/Object/index_prog.html new file mode 100644 index 0000000000000000000000000000000000000000..9b813f40a7edda65c486a7a6c94fccf4cb12c742 --- /dev/null +++ b/isis/src/docsys/Object/index_prog.html @@ -0,0 +1,51 @@ + + + + + USGS: Isis Object Table of Contents (Categorical) + + + + + + + + + + + + + + + + + +USGS +
    +

    + Isis 3.0 Object Documentation

    +
    + +

    + +Oops! You have reached a deprecated page! +The Isis Object Programmers' Reference +has moved. If your browser does not redirect to the new location momentarily, +follow this link to the Programmers' Reference. + +

    + + + diff --git a/isis/src/docsys/Schemas/Application/application.xsd b/isis/src/docsys/Schemas/Application/application.xsd new file mode 100755 index 0000000000000000000000000000000000000000..1984b9ecb8bd142a31e7260e321cafc240373ba5 --- /dev/null +++ b/isis/src/docsys/Schemas/Application/application.xsd @@ -0,0 +1,694 @@ + + + + + + e + + + XML schema for Isis application documentation (Application Markup Language, or AML) + + + 2006-03-12 Designed by Jeff Anderson, janderson@usgs.gov, and Deborah Lee Soltesz, dsoltesz@usgs.gov, USGS Astrogeology Research Program, Flagstaff, AZ + + + 2006-03-23 Added helpers element based on work by Elizabeth Riblin and Jeff Anderson + + + 2007-07-26 Added missionItem_type enummerations for LO and LRO - Steven Koechle + + + 2010-03-25 Added missionItem_type enummeration for Dawn - Janet Barrett + + + + XML file describing an Isis application + + + + + + + + + + + + + + + + + + + element enclosing a very brief description + + + + + multiline description that may contain HTML + + + + + + + + + + A list of categories this application falls under + + + + + + Enumerated type describing a single basic category this application falls in + + + + + Enumerated type describing a single mission-specific category this application falls in + + + + + + + + An item in a list + + + + + A container of parameters for an application. + + + + + + + + + + + A container describing a single parameter to an application. + + + + + + + enumeration describing a parameter of type filename: whether the file's an input, output, etc. + + + + + default directory path to a location on the system + + + + + + + + + + + The minimum allowed value the user may enter for this parameter. + + + + + + + + + + + + The maximum allowed value the user may enter for this parameter. + + + + + + + + + + + + A list of parameters the value for this parameter must be greater than. + + + + + + + + + + A list of parameters the value for this parameter must be greater than or equal to. + + + + + + + + + + A list of parameters the value for this parameter must be less than. + + + + + + + + + + A list of parameters the value for this parameter must be less than or equal to. + + + + + + + + + + A list of parameters the value for this parameter must not be equal to. + + + + + + + + + + Is the parameter value an odd integer? This is an empty element. If it exists, the parameter must be an odd integer. + + + + + Regular Expression to filter a file list if this parameter is a file choice. (e.g. *.cub for input cube file parameter) + + + + + + + What numerical type are the pixels in the cube? (real, unsigned byte, etc.) + + + + + + + + + + The number of items in the list or array if this parameter takes a list or array + + + + + + + + The default value or array/list of values + + + + + + + + + + Description of a calculated default (depended on input files or other variables) + + + + + List of parameters to exclude if this parameter is used + + + + + + + + + + list of possible values + + + + + + + + + + A single example of using this application. + + + + + + + + + + + + + + + + A container describing an image. Attributes: width and height are the number of pixels horizontally and vertically; src is the relative path to the thumbenail. + + + + + A container describing a single GUI screenshot for this example. A screenshot is a raster image depicting an application window. + + + + + + + + + + A container desribing the command line for executing this example. + + + + + + The full command line that will execute this example and render the result. + + + + + + + + + The name of the application parameter associated with this image + + + + + Container describing an input or output file other than an image used in the example. + + + + + + + + + + + + + an enumeration describing the type of a value. + + + + + things-to-do list. Each 'item' contains a single lien in the list. + + + + + + + + + + A container describing the history of this application. + + + + + + A single 'change' in the history of this class. Attribute 'name' is the author's full name; attribute 'date' is the change date in YYYY-MM-DD format. The element contains a free text description of the changes made. + + + + + + + + + + + + + + + + + + + + + + reusable type for describing an image + + + + + + + A description of the thumbnail for this image. Attributes: width and height are the number of pixels horizontally and vertically; caption is a brief description of the image; src is the relative path to the thumbenail. + + + + + + + + + + + reusable type for describing a thumbnail image + + + + + + + + + enumeration for basic Application categorizations + + + + + + + + + + + + + + + + + + + + + + + + enumeration for mission specific Application categorizations + + + + + + + + + + + + + + + + + + + + + + + + enumeration for inclusion types - boolean values + + + + + + + + + + + enumerations for types of parameters + + + + + + + + + + + + + enumeration describing if a file (parameter) is input, output, etc. + + + + + + + + + enumeration describing a cube's pixel digital number type + + + + + + + + + + A container for holding the groups of parameters for the application. + + + + + + + + + + A container of examples for using the application. + + + + + + + + + + A container of Graphical User Interface (GUI) screenshots for this example. + + + + + + + + + + A container of dataFiles for this example. + + + + + + + + + + A container of images that are inputs to the application. + + + + + + + + + + A container of images that are outputs from the application. + + + + + + + + + + Describes an option in a list. Brief child element will be used as the text next to the radio button for the optiion. + + + + + + + + + + + + + + list of related applications and documents + + + + + + A list of related documents. Each item should contain the directory name for a particular document stored in the 'documents' directory. + + + + + + + + + + A list of related applications. Each item should contain the proper Isis application name. + + + + + + + + + + + + + List of parameters that must be used if this one is used. + + + + + + + + + + title of an application, document, or resource + + + + + full path or URL to a resource including the filename + + + + + + + + + + + Filename of a resource with no path specified + + + + + Relative path or URL path to a file without a filename specified. If this element is not specified, stylesheets may assume a default location other than the current working directory. + + + + + list of application names this application was named in previous versions + + + + + + + + + + container describing a document + + + + + + + + author (or authors) of the document + + + + + publisher information (name, city, etc.) + + + + + pages in document refered to by this reference + + + + + publication date + + + + + + + + defines a set of 'helper' functions that provide advanced options or other assistance + + + + + + defines a 'helper' function that provides advanced options or other assistance + + + + + + name of function to call that implements the helper + + + + + + + icon file to display for this helper + + + + + + name of the helper + + + + + + + + diff --git a/isis/src/docsys/Schemas/Application/documentation/index.html b/isis/src/docsys/Schemas/Application/documentation/index.html new file mode 100755 index 0000000000000000000000000000000000000000..d96a4f32419f62617fcca6438167da307185cba1 --- /dev/null +++ b/isis/src/docsys/Schemas/Application/documentation/index.html @@ -0,0 +1,3429 @@ + + + + + + + + + + + + + + + + + + + Schema + application.xsd +
    +
    +
    + + + + + + + + + + + + + + + + +
    schema location: C:\dev\isis\application.xsd
    attribute form default: unqualified
    element form default: qualified
      +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Elements Complex types Simple types 
    application dimension2Dthumbnail_type categoryItem_type 
    brief dimensions2Dimage_type filemode_type 
    category  + inclusion_type 
    count  + missionItem_type 
    dataFile  + paramType_type 
    dataFiles  + pixelType_type 
    default  + +
    description  + +
    document  + +
    example  + +
    examples  + +
    exclusions  + +
    filename  + +
    group  + +
    groups  + +
    guiInterface  + +
    guiInterfaces  + +
    helpers  + +
    history  + +
    image  + +
    inclusions  + +
    inputImages  + +
    internalDefault  + +
    item  + +
    liens  + +
    list  + +
    oldName  + +
    option  + +
    outputImages  + +
    parameter  + +
    parameterName  + +
    path  + +
    seeAlso  + +
    source  + +
    terminalInterface  + +
    title  + +
    type  + +
    +
    +
    + + element + application + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenbrief description category seeAlso oldName history liens groups examples
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    annotation
    documentation
    XML file describing an Isis application
    source<xs:element name="application">
    <xs:annotation>
    +   
    <xs:documentation>XML file describing an Isis application</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="brief"/>
    +     
    <xs:element ref="description"/>
    +     
    <xs:element ref="category"/>
    +     
    <xs:element ref="seeAlso" minOccurs="0"/>
    +     
    <xs:element ref="oldName" minOccurs="0"/>
    +     
    <xs:element ref="history"/>
    +     
    <xs:element ref="liens" minOccurs="0"/>
    +     
    <xs:element ref="groups" minOccurs="0"/>
    +     
    <xs:element ref="examples" minOccurs="0"/>
    +   
    </xs:all>
    +   
    <xs:attribute name="name" type="xs:string" use="required"/>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + attribute + application/@name + + + + + + + + + + + + + +
    typexs:string
    properties
    isRef 0
    use required
    source<xs:attribute name="name" type="xs:string" use="required"/>
    +
    +
    + element + brief + + + + + + + + + + + + + + + + + +
    diagramobject
    used by
    elements application dataFile example helpers/helper option parameter
    complexType dimensions2Dimage_type
    annotation
    documentation
    element enclosing a very brief description
    source<xs:element name="brief">
    <xs:annotation>
    +   
    <xs:documentation>element enclosing a very brief description</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + category + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrencategoryItem missionItem
    used by
    element application
    annotation
    documentation
    A list of categories this application falls under
    source<xs:element name="category">
    <xs:annotation>
    +   
    <xs:documentation>A list of categories this application falls under</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:choice maxOccurs="unbounded">
    +     
    <xs:element name="categoryItem" type="categoryItem_type">
    +       
    <xs:annotation>
    +         
    <xs:documentation>Enumerated type describing a single basic category this application falls in</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element name="missionItem" type="missionItem_type">
    +       
    <xs:annotation>
    +         
    <xs:documentation>Enumerated type describing a single mission-specific category this application falls in</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +   
    </xs:choice>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + category/categoryItem + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    typecategoryItem_type
    properties
    isRef 0
    content simple
    facets
    enumeration Cameras
    enumeration Control Networks
    enumeration Display
    enumeration Fourier Domain
    enumeration Filters
    enumeration Geometry
    enumeration Import and Export
    enumeration Map Projection
    enumeration Math and Statistics
    enumeration Radiometric and Photometric Correction
    enumeration Registration and Pattern Matching
    enumeration Scripting
    enumeration System
    enumeration Topography
    enumeration Trim and Mask
    enumeration Utility
    annotation
    documentation
    Enumerated type describing a single basic category this application falls in
    source<xs:element name="categoryItem" type="categoryItem_type">
    <xs:annotation>
    +   
    <xs:documentation>Enumerated type describing a single basic category this application falls in</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + category/missionItem + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    typemissionItem_type
    properties
    isRef 0
    content simple
    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
    annotation
    documentation
    Enumerated type describing a single mission-specific category this application falls in
    source<xs:element name="missionItem" type="missionItem_type">
    <xs:annotation>
    +   
    <xs:documentation>Enumerated type describing a single mission-specific category this application falls in</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + count + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    used by
    element parameter
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    sizexs:integerrequired      
    annotation
    documentation
    The number of items in the list or array if this parameter takes a list or array
    source<xs:element name="count">
    <xs:annotation>
    +   
    <xs:documentation>The number of items in the list or array if this parameter takes a list or array</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:attribute name="size" type="xs:integer" use="required"/>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + attribute + count/@size + + + + + + + + + + + + + +
    typexs:integer
    properties
    isRef 0
    use required
    source<xs:attribute name="size" type="xs:integer" use="required"/>
    +
    +
    + element + dataFile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenbrief description parameterName
    used by
    element dataFiles
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    pathxs:anyURIrequired      
    annotation
    documentation
    Container describing an input or output file other than an image used in the example.
    source<xs:element name="dataFile">
    <xs:annotation>
    +   
    <xs:documentation>Container describing an input or output file other than an image used in the example.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="brief"/>
    +     
    <xs:element ref="description"/>
    +     
    <xs:element ref="parameterName" minOccurs="0"/>
    +   
    </xs:all>
    +   
    <xs:attribute name="path" type="xs:anyURI" use="required"/>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + attribute + dataFile/@path + + + + + + + + + + + + + +
    typexs:anyURI
    properties
    isRef 0
    use required
    source<xs:attribute name="path" type="xs:anyURI" use="required"/>
    +
    +
    + element + dataFiles + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrendataFile
    used by
    element example
    annotation
    documentation
    A container of dataFiles for this example.
    source<xs:element name="dataFiles">
    <xs:annotation>
    +   
    <xs:documentation>A container of dataFiles for this example.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="dataFile" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + default + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenitem
    used by
    element parameter
    annotation
    documentation
    The default value or array/list of values
    source<xs:element name="default">
    <xs:annotation>
    +   
    <xs:documentation>The default value or array/list of values</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + description + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    mixed true
    used by
    elements application dataFile example helpers/helper option parameter terminalInterface
    complexType dimensions2Dimage_type
    annotation
    documentation
    multiline description that may contain HTML
    source<xs:element name="description">
    <xs:annotation>
    +   
    <xs:documentation>multiline description that may contain HTML</xs:documentation>
    </xs:annotation>
    <xs:complexType mixed="true">
    +   
    <xs:sequence>
    +     
    <xs:any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + document + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrentitle source author publisher pages date
    used by
    element seeAlso/documents
    annotation
    documentation
    container describing a document
    source<xs:element name="document">
    <xs:annotation>
    +   
    <xs:documentation>container describing a document</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="title"/>
    +     
    <xs:element ref="source" minOccurs="0"/>
    +     
    <xs:element name="author" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>author (or authors) of the document</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element name="publisher" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>publisher information (name, city, etc.)</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element name="pages" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>pages in document refered to by this reference</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element name="date" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>publication date</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +   
    </xs:all>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + document/author + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    annotation
    documentation
    author (or authors) of the document
    source<xs:element name="author" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>author (or authors) of the document</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + document/publisher + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    annotation
    documentation
    publisher information (name, city, etc.)
    source<xs:element name="publisher" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>publisher information (name, city, etc.)</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + document/pages + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    annotation
    documentation
    pages in document refered to by this reference
    source<xs:element name="pages" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>pages in document refered to by this reference</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + document/date + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    annotation
    documentation
    publication date
    source<xs:element name="date" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>publication date</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + example + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenbrief description terminalInterface guiInterfaces dataFiles inputImages outputImages
    used by
    element examples
    annotation
    documentation
    A single example of using this application.
    source<xs:element name="example">
    <xs:annotation>
    +   
    <xs:documentation>A single example of using this application.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="brief"/>
    +     
    <xs:element ref="description"/>
    +     
    <xs:element ref="terminalInterface" minOccurs="0"/>
    +     
    <xs:element ref="guiInterfaces" minOccurs="0"/>
    +     
    <xs:element ref="dataFiles" minOccurs="0"/>
    +     
    <xs:element ref="inputImages" minOccurs="0"/>
    +     
    <xs:element ref="outputImages" minOccurs="0"/>
    +   
    </xs:all>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + examples + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenexample
    used by
    element application
    annotation
    documentation
    A container of examples for using the application.
    source<xs:element name="examples">
    <xs:annotation>
    +   
    <xs:documentation>A container of examples for using the application.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="example" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + exclusions + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenitem
    used by
    elements option parameter
    annotation
    documentation
    List of parameters to exclude if this parameter is used
    source<xs:element name="exclusions">
    <xs:annotation>
    +   
    <xs:documentation>List of parameters to exclude if this parameter is used</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + filename + + + + + + + + + + + + + + + + + +
    diagramobject
    used by
    element source
    annotation
    documentation
    Filename of a resource with no path specified
    source<xs:element name="filename">
    <xs:annotation>
    +   
    <xs:documentation>Filename of a resource with no path specified</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + group + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenparameter
    used by
    element groups
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    annotation
    documentation
    A container of parameters for an application.
    source<xs:element name="group">
    <xs:annotation>
    +   
    <xs:documentation>A container of parameters for an application.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="parameter" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    +   
    <xs:attribute name="name" type="xs:string" use="required"/>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + attribute + group/@name + + + + + + + + + + + + + +
    typexs:string
    properties
    isRef 0
    use required
    source<xs:attribute name="name" type="xs:string" use="required"/>
    +
    +
    + element + groups + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrengroup
    used by
    element application
    annotation
    documentation
    A container for holding the groups of parameters for the application.
    source<xs:element name="groups">
    <xs:annotation>
    +   
    <xs:documentation>A container for holding the groups of parameters for the application.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="group" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + guiInterface + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenimage
    used by
    element guiInterfaces
    annotation
    documentation
    A container describing a single GUI screenshot for this example. A screenshot is a raster image depicting an application window.
    source<xs:element name="guiInterface">
    <xs:annotation>
    +   
    <xs:documentation>A container describing a single GUI screenshot for this example. A screenshot is a raster image depicting an application window.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="image"/>
    +   
    </xs:all>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + guiInterfaces + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenguiInterface
    used by
    element example
    annotation
    documentation
    A container of Graphical User Interface (GUI) screenshots for this example.
    source<xs:element name="guiInterfaces">
    <xs:annotation>
    +   
    <xs:documentation>A container of Graphical User Interface (GUI) screenshots for this example.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="guiInterface" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + helpers + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenhelper
    used by
    element parameter
    annotation
    documentation
    defines a set of 'helper' functions that provide advanced options or other assistance
    source<xs:element name="helpers">
    <xs:annotation>
    +   
    <xs:documentation>defines a set of 'helper' functions that provide advanced options or other assistance</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element name="helper" maxOccurs="unbounded">
    +       
    <xs:annotation>
    +         
    <xs:documentation>defines a 'helper' function that provides advanced options or other assistance</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:all>
    +           
    <xs:element name="function">
    +             
    <xs:annotation>
    +               
    <xs:documentation>name of function to call that implements the helper</xs:documentation>
    +             
    </xs:annotation>
    +           
    </xs:element>
    +           
    <xs:element ref="brief"/>
    +           
    <xs:element ref="description"/>
    +           
    <xs:element name="icon" minOccurs="0">
    +             
    <xs:annotation>
    +               
    <xs:documentation>icon file to display for this helper</xs:documentation>
    +             
    </xs:annotation>
    +           
    </xs:element>
    +         
    </xs:all>
    +         
    <xs:attribute name="name" type="xs:string" use="required">
    +           
    <xs:annotation>
    +             
    <xs:documentation>name of the helper</xs:documentation>
    +           
    </xs:annotation>
    +         
    </xs:attribute>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + helpers/helper + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 1
    maxOcc unbounded
    content complex
    childrenfunction brief description icon
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    documentation
    name of the helper
    annotation
    documentation
    defines a 'helper' function that provides advanced options or other assistance
    source<xs:element name="helper" maxOccurs="unbounded">
    <xs:annotation>
    +   
    <xs:documentation>defines a 'helper' function that provides advanced options or other assistance</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element name="function">
    +       
    <xs:annotation>
    +         
    <xs:documentation>name of function to call that implements the helper</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element ref="brief"/>
    +     
    <xs:element ref="description"/>
    +     
    <xs:element name="icon" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>icon file to display for this helper</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +   
    </xs:all>
    +   
    <xs:attribute name="name" type="xs:string" use="required">
    +     
    <xs:annotation>
    +       
    <xs:documentation>name of the helper</xs:documentation>
    +     
    </xs:annotation>
    +   
    </xs:attribute>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + attribute + helpers/helper/@name + + + + + + + + + + + + + + + + + +
    typexs:string
    properties
    isRef 0
    use required
    annotation
    documentation
    name of the helper
    source<xs:attribute name="name" type="xs:string" use="required">
    <xs:annotation>
    +   
    <xs:documentation>name of the helper</xs:documentation>
    </xs:annotation>
    +
    </xs:attribute>
    +
    +
    + element + helpers/helper/function + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    annotation
    documentation
    name of function to call that implements the helper
    source<xs:element name="function">
    <xs:annotation>
    +   
    <xs:documentation>name of function to call that implements the helper</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + helpers/helper/icon + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    annotation
    documentation
    icon file to display for this helper
    source<xs:element name="icon" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>icon file to display for this helper</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + history + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenchange
    used by
    element application
    annotation
    documentation
    A container describing the history of this application.
    source<xs:element name="history">
    <xs:annotation>
    +   
    <xs:documentation>A container describing the history of this application.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element name="change" maxOccurs="unbounded">
    +       
    <xs:annotation>
    +         
    <xs:documentation>A single 'change' in the history of this class. Attribute 'name' is the author's full name; attribute 'date' is the change date in YYYY-MM-DD format. The element contains a free text description of the changes made.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType mixed="true">
    +         
    <xs:attribute name="name" type="xs:string" use="required"/>
    +         
    <xs:attribute name="date" type="xs:date" use="required"/>
    +         
    <xs:attribute name="hidden" use="optional" default="false">
    +           
    <xs:simpleType>
    +             
    <xs:restriction base="xs:string">
    +               
    <xs:enumeration value="yes"/>
    +               
    <xs:enumeration value="no"/>
    +               
    <xs:enumeration value="true"/>
    +               
    <xs:enumeration value="false"/>
    +             
    </xs:restriction>
    +           
    </xs:simpleType>
    +         
    </xs:attribute>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + history/change + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 1
    maxOcc unbounded
    content complex
    mixed true
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    datexs:daterequired      
    hiddenderived by: xs:stringoptional  false    
    annotation
    documentation
    A single 'change' in the history of this class. Attribute 'name' is the author's full name; attribute 'date' is the change date in YYYY-MM-DD format. The element contains a free text description of the changes made.
    source<xs:element name="change" maxOccurs="unbounded">
    <xs:annotation>
    +   
    <xs:documentation>A single 'change' in the history of this class. Attribute 'name' is the author's full name; attribute 'date' is the change date in YYYY-MM-DD format. The element contains a free text description of the changes made.</xs:documentation>
    </xs:annotation>
    <xs:complexType mixed="true">
    +   
    <xs:attribute name="name" type="xs:string" use="required"/>
    +   
    <xs:attribute name="date" type="xs:date" use="required"/>
    +   
    <xs:attribute name="hidden" use="optional" default="false">
    +     
    <xs:simpleType>
    +       
    <xs:restriction base="xs:string">
    +         
    <xs:enumeration value="yes"/>
    +         
    <xs:enumeration value="no"/>
    +         
    <xs:enumeration value="true"/>
    +         
    <xs:enumeration value="false"/>
    +       
    </xs:restriction>
    +     
    </xs:simpleType>
    +   
    </xs:attribute>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + attribute + history/change/@name + + + + + + + + + + + + + +
    typexs:string
    properties
    isRef 0
    use required
    source<xs:attribute name="name" type="xs:string" use="required"/>
    +
    +
    + attribute + history/change/@date + + + + + + + + + + + + + +
    typexs:date
    properties
    isRef 0
    use required
    source<xs:attribute name="date" type="xs:date" use="required"/>
    +
    +
    + attribute + history/change/@hidden + + + + + + + + + + + + + + + + + +
    typerestriction of xs:string
    properties
    isRef 0
    default false
    use optional
    facets
    enumeration yes
    enumeration no
    enumeration true
    enumeration false
    source<xs:attribute name="hidden" use="optional" default="false">
    <xs:simpleType>
    +   
    <xs:restriction base="xs:string">
    +     
    <xs:enumeration value="yes"/>
    +     
    <xs:enumeration value="no"/>
    +     
    <xs:enumeration value="true"/>
    +     
    <xs:enumeration value="false"/>
    +   
    </xs:restriction>
    </xs:simpleType>
    +
    </xs:attribute>
    +
    +
    + element + image + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    typedimensions2Dimage_type
    properties
    content complex
    childrenbrief description thumbnail parameterName
    used by
    elements guiInterface inputImages outputImages
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    widthxs:integerrequired      
    heightxs:integerrequired      
    srcxs:anyURIrequired      
    annotation
    documentation
    A container describing an image. Attributes: width and height are the number of pixels horizontally and vertically;  src is the relative path to the thumbenail.
    source<xs:element name="image" type="dimensions2Dimage_type">
    <xs:annotation>
    +   
    <xs:documentation>A container describing an image. Attributes: width and height are the number of pixels horizontally and vertically;  src is the relative path to the thumbenail.</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + inclusions + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenitem
    used by
    elements option parameter
    annotation
    documentation
    List of parameters that must be used if this one is used.
    source<xs:element name="inclusions">
    <xs:annotation>
    +   
    <xs:documentation>List of parameters that must be used if this one is used.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + inputImages + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenimage
    used by
    element example
    annotation
    documentation
    A container of images that are inputs to the application.
    source<xs:element name="inputImages">
    <xs:annotation>
    +   
    <xs:documentation>A container of images that are inputs to the application.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence maxOccurs="unbounded">
    +     
    <xs:element ref="image"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + internalDefault + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    typexs:string
    properties
    content simple
    used by
    element parameter
    annotation
    documentation
    Description of a calculated default (depended on input files or other variables)
    source<xs:element name="internalDefault" type="xs:string">
    <xs:annotation>
    +   
    <xs:documentation>Description of a calculated default (depended on input files or other variables)</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + item + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    typexs:string
    properties
    content simple
    used by
    elements seeAlso/applications default exclusions parameter/greaterThan parameter/greaterThanOrEqual inclusions parameter/lessThan parameter/lessThanOrEqual liens parameter/notEqual oldName
    annotation
    documentation
    An item in a list
    source<xs:element name="item" type="xs:string">
    <xs:annotation>
    +   
    <xs:documentation>An item in a list</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + liens + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenitem
    used by
    element application
    annotation
    documentation
    things-to-do list. Each 'item' contains a single lien in the list.
    source<xs:element name="liens">
    <xs:annotation>
    +   
    <xs:documentation>things-to-do list. Each 'item' contains a single lien in the list.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + list + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenoption
    used by
    element parameter
    annotation
    documentation
    list of possible values
    source<xs:element name="list">
    <xs:annotation>
    +   
    <xs:documentation>list of possible values</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="option" minOccurs="2" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + oldName + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenitem
    used by
    element application
    annotation
    documentation
    list of application names this application was named in previous versions
    source<xs:element name="oldName">
    <xs:annotation>
    +   
    <xs:documentation>list of application names this application was named in previous versions</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + option + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenbrief description exclusions inclusions
    used by
    element list
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    valuexs:stringrequired      
    annotation
    documentation
    Describes an option in a list. Brief child element will be used as the text next to the radio button for the optiion.
    source<xs:element name="option">
    <xs:annotation>
    +   
    <xs:documentation>Describes an option in a list. Brief child element will be used as the text next to the radio button for the optiion.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="brief"/>
    +     
    <xs:element ref="description"/>
    +     
    <xs:element ref="exclusions" minOccurs="0"/>
    +     
    <xs:element ref="inclusions" minOccurs="0"/>
    +   
    </xs:all>
    +   
    <xs:attribute name="value" type="xs:string" use="required"/>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + attribute + option/@value + + + + + + + + + + + + + +
    typexs:string
    properties
    isRef 0
    use required
    source<xs:attribute name="value" type="xs:string" use="required"/>
    +
    +
    + element + outputImages + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenimage
    used by
    element example
    annotation
    documentation
    A container of images that are outputs from the application.
    source<xs:element name="outputImages">
    <xs:annotation>
    +   
    <xs:documentation>A container of images that are outputs from the application.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence maxOccurs="unbounded">
    +     
    <xs:element ref="image"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + parameter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrentype fileMode defaultPath brief description count default internalDefault list minimum maximum greaterThan greaterThanOrEqual lessThan lessThanOrEqual notEqual odd filter exclusions inclusions pixelType helpers
    used by
    element group
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    annotation
    documentation
    A container describing a single parameter to an application.
    source<xs:element name="parameter">
    <xs:annotation>
    +   
    <xs:documentation>A container describing a single parameter to an application.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="type"/>
    +     
    <xs:element name="fileMode" type="filemode_type" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>enumeration describing a parameter of type filename: whether the file's an input, output, etc.</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element name="defaultPath" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>default directory path to a location on the system</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element ref="brief"/>
    +     
    <xs:element ref="description"/>
    +     
    <xs:element ref="count" minOccurs="0"/>
    +     
    <xs:element ref="default" minOccurs="0"/>
    +     
    <xs:element ref="internalDefault" minOccurs="0"/>
    +     
    <xs:element ref="list" minOccurs="0"/>
    +     
    <xs:element name="minimum" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>The minimum allowed value the user may enter for this parameter.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:simpleContent>
    +           
    <xs:extension base="xs:string">
    +             
    <xs:attribute name="inclusive" type="inclusion_type" use="required"/>
    +           
    </xs:extension>
    +         
    </xs:simpleContent>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="maximum" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>The maximum allowed value the user may enter for this parameter.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:simpleContent>
    +           
    <xs:extension base="xs:string">
    +             
    <xs:attribute name="inclusive" type="inclusion_type" use="required"/>
    +           
    </xs:extension>
    +         
    </xs:simpleContent>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="greaterThan" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>A list of parameters the value for this parameter must be greater than.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:sequence>
    +           
    <xs:element ref="item" maxOccurs="unbounded"/>
    +         
    </xs:sequence>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="greaterThanOrEqual" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>A list of parameters the value for this parameter must be greater than or equal to.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:sequence>
    +           
    <xs:element ref="item" maxOccurs="unbounded"/>
    +         
    </xs:sequence>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="lessThan" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>A list of parameters the value for this parameter must be less than.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:sequence>
    +           
    <xs:element ref="item" maxOccurs="unbounded"/>
    +         
    </xs:sequence>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="lessThanOrEqual" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>A list of parameters the value for this parameter must be less than or equal to.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:sequence>
    +           
    <xs:element ref="item" maxOccurs="unbounded"/>
    +         
    </xs:sequence>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="notEqual" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>A list of parameters the value for this parameter must not be equal to.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:sequence>
    +           
    <xs:element ref="item" maxOccurs="unbounded"/>
    +         
    </xs:sequence>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="odd" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>Is the parameter value an odd integer? This is an empty element. If it exists, the parameter must be an odd integer.</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element name="filter" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>Regular Expression to filter a file list if this parameter is a file choice. (e.g. *.cub for input cube file parameter)</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element ref="exclusions" minOccurs="0"/>
    +     
    <xs:element ref="inclusions" minOccurs="0"/>
    +     
    <xs:element name="pixelType" type="pixelType_type" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>What numerical type are the pixels in the cube? (real, unsigned byte, etc.)</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element ref="helpers" minOccurs="0"/>
    +   
    </xs:all>
    +   
    <xs:attribute name="name" type="xs:string" use="required"/>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + attribute + parameter/@name + + + + + + + + + + + + + +
    typexs:string
    properties
    isRef 0
    use required
    source<xs:attribute name="name" type="xs:string" use="required"/>
    +
    +
    + element + parameter/fileMode + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    typefilemode_type
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content simple
    facets
    enumeration input
    enumeration output
    annotation
    documentation
    enumeration describing a parameter of type filename: whether the file's an input, output, etc.
    source<xs:element name="fileMode" type="filemode_type" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>enumeration describing a parameter of type filename: whether the file's an input, output, etc.</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + parameter/defaultPath + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    annotation
    documentation
    default directory path to a location on the system
    source<xs:element name="defaultPath" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>default directory path to a location on the system</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + parameter/minimum + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    typeextension of xs:string
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    inclusiveinclusion_typerequired      
    annotation
    documentation
    The minimum allowed value the user may enter for this parameter.
    source<xs:element name="minimum" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>The minimum allowed value the user may enter for this parameter.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:simpleContent>
    +     
    <xs:extension base="xs:string">
    +       
    <xs:attribute name="inclusive" type="inclusion_type" use="required"/>
    +     
    </xs:extension>
    +   
    </xs:simpleContent>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + attribute + parameter/minimum/@inclusive + + + + + + + + + + + + + + + + + +
    typeinclusion_type
    properties
    isRef 0
    use required
    facets
    enumeration yes
    enumeration no
    enumeration true
    enumeration false
    source<xs:attribute name="inclusive" type="inclusion_type" use="required"/>
    +
    +
    + element + parameter/maximum + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    typeextension of xs:string
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    inclusiveinclusion_typerequired      
    annotation
    documentation
    The maximum allowed value the user may enter for this parameter.
    source<xs:element name="maximum" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>The maximum allowed value the user may enter for this parameter.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:simpleContent>
    +     
    <xs:extension base="xs:string">
    +       
    <xs:attribute name="inclusive" type="inclusion_type" use="required"/>
    +     
    </xs:extension>
    +   
    </xs:simpleContent>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + attribute + parameter/maximum/@inclusive + + + + + + + + + + + + + + + + + +
    typeinclusion_type
    properties
    isRef 0
    use required
    facets
    enumeration yes
    enumeration no
    enumeration true
    enumeration false
    source<xs:attribute name="inclusive" type="inclusion_type" use="required"/>
    +
    +
    + element + parameter/greaterThan + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    childrenitem
    annotation
    documentation
    A list of parameters the value for this parameter must be greater than.
    source<xs:element name="greaterThan" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>A list of parameters the value for this parameter must be greater than.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + parameter/greaterThanOrEqual + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    childrenitem
    annotation
    documentation
    A list of parameters the value for this parameter must be greater than or equal to.
    source<xs:element name="greaterThanOrEqual" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>A list of parameters the value for this parameter must be greater than or equal to.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + parameter/lessThan + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    childrenitem
    annotation
    documentation
    A list of parameters the value for this parameter must be less than.
    source<xs:element name="lessThan" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>A list of parameters the value for this parameter must be less than.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + parameter/lessThanOrEqual + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    childrenitem
    annotation
    documentation
    A list of parameters the value for this parameter must be less than or equal to.
    source<xs:element name="lessThanOrEqual" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>A list of parameters the value for this parameter must be less than or equal to.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + parameter/notEqual + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    childrenitem
    annotation
    documentation
    A list of parameters the value for this parameter must not be equal to.
    source<xs:element name="notEqual" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>A list of parameters the value for this parameter must not be equal to.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + parameter/odd + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    annotation
    documentation
    Is the parameter value an odd integer? This is an empty element. If it exists, the parameter must be an odd integer.
    source<xs:element name="odd" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>Is the parameter value an odd integer? This is an empty element. If it exists, the parameter must be an odd integer.</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + parameter/filter + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    annotation
    documentation
    Regular Expression to filter a file list if this parameter is a file choice. (e.g. *.cub for input cube file parameter)
    source<xs:element name="filter" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>Regular Expression to filter a file list if this parameter is a file choice. (e.g. *.cub for input cube file parameter)</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + parameter/pixelType + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    typepixelType_type
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content simple
    facets
    enumeration real
    enumeration unsignedByte
    enumeration signedWord
    annotation
    documentation
    What numerical type are the pixels in the cube? (real, unsigned byte, etc.)
    source<xs:element name="pixelType" type="pixelType_type" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>What numerical type are the pixels in the cube? (real, unsigned byte, etc.)</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + parameterName + + + + + + + + + + + + + + + + + +
    diagramobject
    used by
    element dataFile
    complexType dimensions2Dimage_type
    annotation
    documentation
    The name of the application parameter associated with this image
    source<xs:element name="parameterName">
    <xs:annotation>
    +   
    <xs:documentation>The name of the application parameter associated with this image</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + path + + + + + + + + + + + + + + + + + +
    diagramobject
    used by
    element source
    annotation
    documentation
    Relative path or URL path to a file without a filename specified. If this element is not specified, stylesheets may assume a default location other than the current working directory.
    source<xs:element name="path">
    <xs:annotation>
    +   
    <xs:documentation>Relative path or URL path to a file without a filename specified. If this element is not specified, stylesheets may assume a default location other than the current working directory.</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + seeAlso + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrendocuments applications
    used by
    element application
    annotation
    documentation
    list of related applications and documents
    source<xs:element name="seeAlso">
    <xs:annotation>
    +   
    <xs:documentation>list of related applications and documents</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element name="documents" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>A list of related documents. Each item should contain the directory name for a particular document stored in the 'documents' directory.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:sequence>
    +           
    <xs:element ref="document" maxOccurs="unbounded"/>
    +         
    </xs:sequence>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="applications" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>A list of related applications. Each item should contain the proper Isis application name.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:sequence>
    +           
    <xs:element ref="item" maxOccurs="unbounded"/>
    +         
    </xs:sequence>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:all>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + seeAlso/documents + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    childrendocument
    annotation
    documentation
    A list of related documents. Each item should contain the directory name for a particular document stored in the 'documents' directory.
    source<xs:element name="documents" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>A list of related documents. Each item should contain the directory name for a particular document stored in the 'documents' directory.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="document" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + seeAlso/applications + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    childrenitem
    annotation
    documentation
    A list of related applications. Each item should contain the proper Isis application name.
    source<xs:element name="applications" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>A list of related applications. Each item should contain the proper Isis application name.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + source + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrenfilename path
    used by
    element document
    annotation
    documentation
    full path or URL to a resource including the filename
    source<xs:element name="source">
    <xs:annotation>
    +   
    <xs:documentation>full path or URL to a resource including the filename</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="filename"/>
    +     
    <xs:element ref="path" minOccurs="0"/>
    +   
    </xs:all>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + terminalInterface + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    properties
    content complex
    childrencommandLine description
    used by
    element example
    annotation
    documentation
    A container desribing the command line for executing this example.
    source<xs:element name="terminalInterface">
    <xs:annotation>
    +   
    <xs:documentation>A container desribing the command line for executing this example.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element name="commandLine" type="xs:string">
    +       
    <xs:annotation>
    +         
    <xs:documentation>The full command line that will execute this example and render the result.</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element ref="description"/>
    +   
    </xs:all>
    </xs:complexType>
    +
    </xs:element>
    +
    +
    + element + terminalInterface/commandLine + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    typexs:string
    properties
    isRef 0
    content simple
    annotation
    documentation
    The full command line that will execute this example and render the result.
    source<xs:element name="commandLine" type="xs:string">
    <xs:annotation>
    +   
    <xs:documentation>The full command line that will execute this example and render the result.</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + title + + + + + + + + + + + + + + + + + +
    diagramobject
    used by
    element document
    annotation
    documentation
    title of an application, document, or resource
    source<xs:element name="title">
    <xs:annotation>
    +   
    <xs:documentation>title of an application, document, or resource</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + element + type + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    typeparamType_type
    properties
    content simple
    used by
    element parameter
    facets
    enumeration filename
    enumeration integer
    enumeration double
    enumeration string
    enumeration boolean
    enumeration cube
    annotation
    documentation
    an enumeration describing the type of a value.
    source<xs:element name="type" type="paramType_type">
    <xs:annotation>
    +   
    <xs:documentation>an enumeration describing the type of a value. </xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + complexType + dimension2Dthumbnail_type + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    used by
    element dimensions2Dimage_type/thumbnail
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    widthxs:integerrequired      
    heightxs:integerrequired      
    captionxs:stringrequired      
    srcxs:stringrequired      
    annotation
    documentation
    reusable type for describing a thumbnail image
    source<xs:complexType name="dimension2Dthumbnail_type">
    <xs:annotation>
    +   
    <xs:documentation>reusable type for describing a thumbnail image</xs:documentation>
    </xs:annotation>
    <xs:attribute name="width" type="xs:integer" use="required"/>
    <xs:attribute name="height" type="xs:integer" use="required"/>
    <xs:attribute name="caption" type="xs:string" use="required"/>
    <xs:attribute name="src" type="xs:string" use="required"/>
    +
    </xs:complexType>
    +
    +
    + attribute + dimension2Dthumbnail_type/@width + + + + + + + + + + + + + +
    typexs:integer
    properties
    isRef 0
    use required
    source<xs:attribute name="width" type="xs:integer" use="required"/>
    +
    +
    + attribute + dimension2Dthumbnail_type/@height + + + + + + + + + + + + + +
    typexs:integer
    properties
    isRef 0
    use required
    source<xs:attribute name="height" type="xs:integer" use="required"/>
    +
    +
    + attribute + dimension2Dthumbnail_type/@caption + + + + + + + + + + + + + +
    typexs:string
    properties
    isRef 0
    use required
    source<xs:attribute name="caption" type="xs:string" use="required"/>
    +
    +
    + attribute + dimension2Dthumbnail_type/@src + + + + + + + + + + + + + +
    typexs:string
    properties
    isRef 0
    use required
    source<xs:attribute name="src" type="xs:string" use="required"/>
    +
    +
    + complexType + dimensions2Dimage_type + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    childrenbrief description thumbnail parameterName
    used by
    element image
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    widthxs:integerrequired      
    heightxs:integerrequired      
    srcxs:anyURIrequired      
    annotation
    documentation
    reusable type for describing an image
    source<xs:complexType name="dimensions2Dimage_type">
    <xs:annotation>
    +   
    <xs:documentation>reusable type for describing an image</xs:documentation>
    </xs:annotation>
    <xs:all>
    +   
    <xs:element ref="brief"/>
    +   
    <xs:element ref="description"/>
    +   
    <xs:element name="thumbnail" type="dimension2Dthumbnail_type">
    +     
    <xs:annotation>
    +       
    <xs:documentation>A description of the thumbnail for this image. Attributes: width and height are the number of pixels horizontally and vertically; caption is a brief description of the image; src is the relative path to the thumbenail.</xs:documentation>
    +     
    </xs:annotation>
    +   
    </xs:element>
    +   
    <xs:element ref="parameterName" minOccurs="0"/>
    </xs:all>
    <xs:attribute name="width" type="xs:integer" use="required"/>
    <xs:attribute name="height" type="xs:integer" use="required"/>
    <xs:attribute name="src" type="xs:anyURI" use="required"/>
    +
    </xs:complexType>
    +
    +
    + attribute + dimensions2Dimage_type/@width + + + + + + + + + + + + + +
    typexs:integer
    properties
    isRef 0
    use required
    source<xs:attribute name="width" type="xs:integer" use="required"/>
    +
    +
    + attribute + dimensions2Dimage_type/@height + + + + + + + + + + + + + +
    typexs:integer
    properties
    isRef 0
    use required
    source<xs:attribute name="height" type="xs:integer" use="required"/>
    +
    +
    + attribute + dimensions2Dimage_type/@src + + + + + + + + + + + + + +
    typexs:anyURI
    properties
    isRef 0
    use required
    source<xs:attribute name="src" type="xs:anyURI" use="required"/>
    +
    +
    + element + dimensions2Dimage_type/thumbnail + + + + + + + + + + + + + + + + + + + + + + + + + +
    diagramobject
    typedimension2Dthumbnail_type
    properties
    isRef 0
    content complex
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    widthxs:integerrequired      
    heightxs:integerrequired      
    captionxs:stringrequired      
    srcxs:stringrequired      
    annotation
    documentation
    A description of the thumbnail for this image. Attributes: width and height are the number of pixels horizontally and vertically; caption is a brief description of the image; src is the relative path to the thumbenail.
    source<xs:element name="thumbnail" type="dimension2Dthumbnail_type">
    <xs:annotation>
    +   
    <xs:documentation>A description of the thumbnail for this image. Attributes: width and height are the number of pixels horizontally and vertically; caption is a brief description of the image; src is the relative path to the thumbenail.</xs:documentation>
    </xs:annotation>
    +
    </xs:element>
    +
    +
    + simpleType + categoryItem_type + + + + + + + + + + + + + + + + + + + + + + + + + +
    typerestriction of xs:string
    properties
    final restriction
    used by
    element category/categoryItem
    facets
    enumeration Cameras
    enumeration Control Networks
    enumeration Display
    enumeration Fourier Domain
    enumeration Filters
    enumeration Geometry
    enumeration Import and Export
    enumeration Map Projection
    enumeration Math and Statistics
    enumeration Radiometric and Photometric Correction
    enumeration Registration and Pattern Matching
    enumeration Scripting
    enumeration System
    enumeration Topography
    enumeration Trim and Mask
    enumeration Utility
    annotation
    documentation
    enumeration for basic Application categorizations
    source<xs:simpleType name="categoryItem_type" final="restriction">
    <xs:annotation>
    +   
    <xs:documentation>enumeration for basic Application categorizations</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
    +   
    <xs:enumeration value="Cameras"/>
    +   
    <xs:enumeration value="Control Networks"/>
    +   
    <xs:enumeration value="Display"/>
    +   
    <xs:enumeration value="Fourier Domain"/>
    +   
    <xs:enumeration value="Filters"/>
    +   
    <xs:enumeration value="Geometry"/>
    +   
    <xs:enumeration value="Import and Export"/>
    +   
    <xs:enumeration value="Map Projection"/>
    +   
    <xs:enumeration value="Math and Statistics"/>
    +   
    <xs:enumeration value="Radiometric and Photometric Correction"/>
    +   
    <xs:enumeration value="Registration and Pattern Matching"/>
    +   
    <xs:enumeration value="Scripting"/>
    +   
    <xs:enumeration value="System"/>
    +   
    <xs:enumeration value="Topography"/>
    +   
    <xs:enumeration value="Trim and Mask"/>
    +   
    <xs:enumeration value="Utility"/>
    </xs:restriction>
    +
    </xs:simpleType>
    +
    +
    + simpleType + filemode_type + + + + + + + + + + + + + + + + + + + + + + + + + +
    typerestriction of xs:string
    properties
    final restriction
    used by
    element parameter/fileMode
    facets
    enumeration input
    enumeration output
    annotation
    documentation
    enumeration describing if a file (parameter) is input, output, etc.
    source<xs:simpleType name="filemode_type" final="restriction">
    <xs:annotation>
    +   
    <xs:documentation>enumeration describing if a file (parameter) is input, output, etc.</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
    +   
    <xs:enumeration value="input"/>
    +   
    <xs:enumeration value="output"/>
    </xs:restriction>
    +
    </xs:simpleType>
    +
    +
    + simpleType + inclusion_type + + + + + + + + + + + + + + + + + + + + + + + + + +
    typerestriction of xs:string
    properties
    final restriction
    used by
    attributes parameter/minimum/@inclusive parameter/maximum/@inclusive
    facets
    enumeration yes
    enumeration no
    enumeration true
    enumeration false
    annotation
    documentation
    enumeration for inclusion types - boolean values
    source<xs:simpleType name="inclusion_type" final="restriction">
    <xs:annotation>
    +   
    <xs:documentation>enumeration for inclusion types - boolean values</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
    +   
    <xs:enumeration value="yes"/>
    +   
    <xs:enumeration value="no"/>
    +   
    <xs:enumeration value="true"/>
    +   
    <xs:enumeration value="false"/>
    </xs:restriction>
    +
    </xs:simpleType>
    +
    +
    + simpleType + missionItem_type + + + + + + + + + + + + + + + + + + + + + + + + + +
    typerestriction of xs:string
    properties
    final restriction
    used by
    element category/missionItem
    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
    annotation
    documentation
    enumeration for mission specific Application categorizations
    source<xs:simpleType name="missionItem_type" final="restriction">
    <xs:annotation>
    +   
    <xs:documentation>enumeration for mission specific Application categorizations</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
    +   
    <xs:enumeration value="Cassini"/>
    +   
    <xs:enumeration value="Clementine"/>
    +   
    <xs:enumeration value="Mariner"/>
    +   
    <xs:enumeration value="Galileo"/>
    +   
    <xs:enumeration value="Lunar Orbiter"/>
    +   
    <xs:enumeration value="Lunar Reconnaissance Orbiter"/>
    +   
    <xs:enumeration value="Mars Reconnaissance Orbiter"/>
    +   
    <xs:enumeration value="Mars Global Surveyor"/>
    +   
    <xs:enumeration value="Mars Odyssey"/>
    +   
    <xs:enumeration value="Mars Exploration Rover"/>
    +   
    <xs:enumeration value="Messenger"/>
    +   
    <xs:enumeration value="Small Missions for Advanced Research and Technology 1"/>
    +   
    <xs:enumeration value="Voyager"/>
    +   
    <xs:enumeration value="Viking"/>
    </xs:restriction>
    +
    </xs:simpleType>
    +
    +
    + simpleType + paramType_type + + + + + + + + + + + + + + + + + + + + + + + + + +
    typerestriction of xs:string
    properties
    final restriction
    used by
    element type
    facets
    enumeration filename
    enumeration integer
    enumeration double
    enumeration string
    enumeration boolean
    enumeration cube
    annotation
    documentation
    enumerations for types of parameters
    source<xs:simpleType name="paramType_type" final="restriction">
    <xs:annotation>
    +   
    <xs:documentation>enumerations for types of parameters</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
    +   
    <xs:enumeration value="filename"/>
    +   
    <xs:enumeration value="integer"/>
    +   
    <xs:enumeration value="double"/>
    +   
    <xs:enumeration value="string"/>
    +   
    <xs:enumeration value="boolean"/>
    +   
    <xs:enumeration value="cube"/>
    </xs:restriction>
    +
    </xs:simpleType>
    +
    +
    + simpleType + pixelType_type + + + + + + + + + + + + + + + + + + + + + + + + + +
    typerestriction of xs:string
    properties
    final restriction
    used by
    element parameter/pixelType
    facets
    enumeration real
    enumeration unsignedByte
    enumeration signedWord
    annotation
    documentation
    enumeration describing a cube's pixel digital number type
    source<xs:simpleType name="pixelType_type" final="restriction">
    <xs:annotation>
    +   
    <xs:documentation>enumeration describing a cube's pixel digital number type</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
    +   
    <xs:enumeration value="real"/>
    +   
    <xs:enumeration value="unsignedByte"/>
    +   
    <xs:enumeration value="signedWord"/>
    </xs:restriction>
    +
    </xs:simpleType>
    +
    +
    + XML Schema documentation generated by +
    + XMLSpy + + Schema Editor + + http://www.altova.com/xmlspy + + + diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p1.png b/isis/src/docsys/Schemas/Application/documentation/index_p1.png new file mode 100755 index 0000000000000000000000000000000000000000..cfeb7ba799d3daf77564dfa4dbf2f3c6571aeb77 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p1.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p10.png b/isis/src/docsys/Schemas/Application/documentation/index_p10.png new file mode 100755 index 0000000000000000000000000000000000000000..f039420a0b3b7bdb638891d0ee2d6fc15abc570f Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p10.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p11.png b/isis/src/docsys/Schemas/Application/documentation/index_p11.png new file mode 100755 index 0000000000000000000000000000000000000000..fab365360d971d70e02fd4211da4bfdd4a56a711 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p11.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p12.png b/isis/src/docsys/Schemas/Application/documentation/index_p12.png new file mode 100755 index 0000000000000000000000000000000000000000..1accba112748a6528deb2506ca40162d3cb0081c Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p12.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p13.png b/isis/src/docsys/Schemas/Application/documentation/index_p13.png new file mode 100755 index 0000000000000000000000000000000000000000..f25722207a1ad1d960a216ad04233dca078139f4 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p13.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p14.png b/isis/src/docsys/Schemas/Application/documentation/index_p14.png new file mode 100755 index 0000000000000000000000000000000000000000..7a0c052d5f5f30ba81623f4ac4da975acbbc2087 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p14.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p15.png b/isis/src/docsys/Schemas/Application/documentation/index_p15.png new file mode 100755 index 0000000000000000000000000000000000000000..77fc7ad05b70d044eb663e88e788ade205ae3e42 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p15.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p16.png b/isis/src/docsys/Schemas/Application/documentation/index_p16.png new file mode 100755 index 0000000000000000000000000000000000000000..625504cee5007761f11d79bf122d0393569b473a Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p16.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p17.png b/isis/src/docsys/Schemas/Application/documentation/index_p17.png new file mode 100755 index 0000000000000000000000000000000000000000..debc85aa142a66467ad10ab8e1176b8a8b1bedbc Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p17.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p18.png b/isis/src/docsys/Schemas/Application/documentation/index_p18.png new file mode 100755 index 0000000000000000000000000000000000000000..81ac73d946f8993d4378b57cea1536b33f274c9b Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p18.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p19.png b/isis/src/docsys/Schemas/Application/documentation/index_p19.png new file mode 100755 index 0000000000000000000000000000000000000000..1eb0d64bfe7bb0b9cf05eacd5c3047037daad986 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p19.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p2.png b/isis/src/docsys/Schemas/Application/documentation/index_p2.png new file mode 100755 index 0000000000000000000000000000000000000000..2bb666860b9c85033c01a6275570918de15a2b1a Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p2.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p20.png b/isis/src/docsys/Schemas/Application/documentation/index_p20.png new file mode 100755 index 0000000000000000000000000000000000000000..1c7531b80d6cbd26052596fc13116603536330e0 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p20.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p21.png b/isis/src/docsys/Schemas/Application/documentation/index_p21.png new file mode 100755 index 0000000000000000000000000000000000000000..90dd104172723b02a2642083e1a3de2d322e2a25 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p21.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p22.png b/isis/src/docsys/Schemas/Application/documentation/index_p22.png new file mode 100755 index 0000000000000000000000000000000000000000..6dc49dfd9f1f70c366c0dcc5b02e516bcb9a3673 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p22.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p23.png b/isis/src/docsys/Schemas/Application/documentation/index_p23.png new file mode 100755 index 0000000000000000000000000000000000000000..1fecf86df922c44347fecf6ca5fec64f9f4f4f59 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p23.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p24.png b/isis/src/docsys/Schemas/Application/documentation/index_p24.png new file mode 100755 index 0000000000000000000000000000000000000000..9c2af14d02ae6a782cc5288d21ee1443921b2dc3 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p24.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p25.png b/isis/src/docsys/Schemas/Application/documentation/index_p25.png new file mode 100755 index 0000000000000000000000000000000000000000..f4ef6f24ff093286ec784f24b155cae7a137a2b0 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p25.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p26.png b/isis/src/docsys/Schemas/Application/documentation/index_p26.png new file mode 100755 index 0000000000000000000000000000000000000000..63d6775977e975c2b5896f023ed822601663805a Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p26.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p27.png b/isis/src/docsys/Schemas/Application/documentation/index_p27.png new file mode 100755 index 0000000000000000000000000000000000000000..cb5c89ee44b98725d64a9c335e2a6380edb0d4c3 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p27.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p28.png b/isis/src/docsys/Schemas/Application/documentation/index_p28.png new file mode 100755 index 0000000000000000000000000000000000000000..a0e7d2305da1fd201309c145070c6de5fcc0267c Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p28.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p29.png b/isis/src/docsys/Schemas/Application/documentation/index_p29.png new file mode 100755 index 0000000000000000000000000000000000000000..2439c866e8e8b70d6dc716ed89e4fdc66071f20d Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p29.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p3.png b/isis/src/docsys/Schemas/Application/documentation/index_p3.png new file mode 100755 index 0000000000000000000000000000000000000000..5e148eec1713bc786ae9fdaf3c3c42b35cceff92 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p3.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p30.png b/isis/src/docsys/Schemas/Application/documentation/index_p30.png new file mode 100755 index 0000000000000000000000000000000000000000..bf390226a6626e08504ba6598c90b6eab57ca164 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p30.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p31.png b/isis/src/docsys/Schemas/Application/documentation/index_p31.png new file mode 100755 index 0000000000000000000000000000000000000000..170de56677ae5f86e24a35c95979bb0b1b24870d Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p31.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p32.png b/isis/src/docsys/Schemas/Application/documentation/index_p32.png new file mode 100755 index 0000000000000000000000000000000000000000..841e4514cf9734bd762eeb1c41da4c4a2c89a670 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p32.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p33.png b/isis/src/docsys/Schemas/Application/documentation/index_p33.png new file mode 100755 index 0000000000000000000000000000000000000000..b6d179e5578db95d982937ad8395ddf2a54645ac Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p33.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p34.png b/isis/src/docsys/Schemas/Application/documentation/index_p34.png new file mode 100755 index 0000000000000000000000000000000000000000..41b9ddd78238fce55db3f60647d855d48d9756ca Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p34.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p35.png b/isis/src/docsys/Schemas/Application/documentation/index_p35.png new file mode 100755 index 0000000000000000000000000000000000000000..ae53cb6da58e048e113be72d55af2db864fc15f0 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p35.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p36.png b/isis/src/docsys/Schemas/Application/documentation/index_p36.png new file mode 100755 index 0000000000000000000000000000000000000000..2dc6a5b2cfe2c518fe6251dd0d3ba0e6e0ba9c81 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p36.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p37.png b/isis/src/docsys/Schemas/Application/documentation/index_p37.png new file mode 100755 index 0000000000000000000000000000000000000000..b8760caa7485f618ba249f6848a85373c99a3ec2 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p37.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p38.png b/isis/src/docsys/Schemas/Application/documentation/index_p38.png new file mode 100755 index 0000000000000000000000000000000000000000..7d419b3b8496d9560cefd73128ecce2fde723969 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p38.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p39.png b/isis/src/docsys/Schemas/Application/documentation/index_p39.png new file mode 100755 index 0000000000000000000000000000000000000000..1d3940c06fe68329331514cf45796164c63b85cc Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p39.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p4.png b/isis/src/docsys/Schemas/Application/documentation/index_p4.png new file mode 100755 index 0000000000000000000000000000000000000000..c681d6832340e51bac43edd8ec43cc8884308366 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p4.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p40.png b/isis/src/docsys/Schemas/Application/documentation/index_p40.png new file mode 100755 index 0000000000000000000000000000000000000000..905c18858827526acd9922979308bc430e26c3ef Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p40.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p41.png b/isis/src/docsys/Schemas/Application/documentation/index_p41.png new file mode 100755 index 0000000000000000000000000000000000000000..ae756334c55580c133d92cc55c980553ada4fa8f Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p41.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p42.png b/isis/src/docsys/Schemas/Application/documentation/index_p42.png new file mode 100755 index 0000000000000000000000000000000000000000..3aadfc65687265604fb19ed7bfc8bca91cfa371f Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p42.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p43.png b/isis/src/docsys/Schemas/Application/documentation/index_p43.png new file mode 100755 index 0000000000000000000000000000000000000000..c6d9460fd9226e2bc8ef0c38aed356f91c3a55fd Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p43.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p44.png b/isis/src/docsys/Schemas/Application/documentation/index_p44.png new file mode 100755 index 0000000000000000000000000000000000000000..5c6d5345fcd002cacd1fbc3be9d14642b6f04710 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p44.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p45.png b/isis/src/docsys/Schemas/Application/documentation/index_p45.png new file mode 100755 index 0000000000000000000000000000000000000000..05c8150eb0f434800d78876d1fc3486cb42030bc Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p45.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p46.png b/isis/src/docsys/Schemas/Application/documentation/index_p46.png new file mode 100755 index 0000000000000000000000000000000000000000..cd42d8c19f2489ca027307c0fc25b268b7610084 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p46.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p47.png b/isis/src/docsys/Schemas/Application/documentation/index_p47.png new file mode 100755 index 0000000000000000000000000000000000000000..5816519bf6a1cb79970230704db9e1fe24496225 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p47.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p48.png b/isis/src/docsys/Schemas/Application/documentation/index_p48.png new file mode 100755 index 0000000000000000000000000000000000000000..e44bb74af719685dcb4aeda18a9d5dd0e131fdd5 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p48.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p49.png b/isis/src/docsys/Schemas/Application/documentation/index_p49.png new file mode 100755 index 0000000000000000000000000000000000000000..1a5c35676aa06790bb4e08db9c5f102f14fecf09 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p49.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p5.png b/isis/src/docsys/Schemas/Application/documentation/index_p5.png new file mode 100755 index 0000000000000000000000000000000000000000..c7446948521dd01d224bbb907f09032c7fc6ed05 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p5.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p50.png b/isis/src/docsys/Schemas/Application/documentation/index_p50.png new file mode 100755 index 0000000000000000000000000000000000000000..540d33b476e5749430060b785efbdf99c9a8cf15 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p50.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p51.png b/isis/src/docsys/Schemas/Application/documentation/index_p51.png new file mode 100755 index 0000000000000000000000000000000000000000..a4413fa10d78d5d9dcaa089f65b8d09186ecdaac Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p51.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p52.png b/isis/src/docsys/Schemas/Application/documentation/index_p52.png new file mode 100755 index 0000000000000000000000000000000000000000..22550afb80d86596f6dac37b25dc8a61857c6e77 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p52.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p53.png b/isis/src/docsys/Schemas/Application/documentation/index_p53.png new file mode 100755 index 0000000000000000000000000000000000000000..b257f99918ddcb0317d4ecb9a8b02d2fe621a49a Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p53.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p54.png b/isis/src/docsys/Schemas/Application/documentation/index_p54.png new file mode 100755 index 0000000000000000000000000000000000000000..758c1fa9ed4ec049b995624d44d4de61653643c3 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p54.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p55.png b/isis/src/docsys/Schemas/Application/documentation/index_p55.png new file mode 100755 index 0000000000000000000000000000000000000000..d04d58e5716cb49e36b3c6579f409f59ef332f98 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p55.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p56.png b/isis/src/docsys/Schemas/Application/documentation/index_p56.png new file mode 100755 index 0000000000000000000000000000000000000000..2de41894de3ab7836c05ee5962b2856aff36d1b4 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p56.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p57.png b/isis/src/docsys/Schemas/Application/documentation/index_p57.png new file mode 100755 index 0000000000000000000000000000000000000000..8bc11eac6605efc3d84467142c9fdc4df1551ac3 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p57.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p58.png b/isis/src/docsys/Schemas/Application/documentation/index_p58.png new file mode 100755 index 0000000000000000000000000000000000000000..de64333b33d3a33a273c6775a957abf020473d3f Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p58.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p59.png b/isis/src/docsys/Schemas/Application/documentation/index_p59.png new file mode 100755 index 0000000000000000000000000000000000000000..e71249b300c6c322a3a860f6f72bf16d11f5beea Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p59.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p6.png b/isis/src/docsys/Schemas/Application/documentation/index_p6.png new file mode 100755 index 0000000000000000000000000000000000000000..c84a78e264cb1d370723fe4607c6221e3541359d Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p6.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p60.png b/isis/src/docsys/Schemas/Application/documentation/index_p60.png new file mode 100644 index 0000000000000000000000000000000000000000..c09f38c5dcc1c2624e0b7d20e0edc0d492fc4c43 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p60.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p61.png b/isis/src/docsys/Schemas/Application/documentation/index_p61.png new file mode 100644 index 0000000000000000000000000000000000000000..5ec9debacecde58f6b6e0d666dfbc2af6c645df4 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p61.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p62.png b/isis/src/docsys/Schemas/Application/documentation/index_p62.png new file mode 100644 index 0000000000000000000000000000000000000000..7ad2bb799211d62504a9afff9a97bb5458dde449 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p62.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p63.png b/isis/src/docsys/Schemas/Application/documentation/index_p63.png new file mode 100644 index 0000000000000000000000000000000000000000..90e9ee717a024a74cdea0b85626b4e80efc874e8 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p63.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p64.png b/isis/src/docsys/Schemas/Application/documentation/index_p64.png new file mode 100644 index 0000000000000000000000000000000000000000..9bf7188d7eebd7976d80fefb52dab851da9a619a Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p64.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p65.png b/isis/src/docsys/Schemas/Application/documentation/index_p65.png new file mode 100644 index 0000000000000000000000000000000000000000..974b7974545bc846de0d57eb16069d93311c4023 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p65.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p7.png b/isis/src/docsys/Schemas/Application/documentation/index_p7.png new file mode 100755 index 0000000000000000000000000000000000000000..e2ac8571a1b20d6bee484f8c554297cd553c8b85 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p7.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p8.png b/isis/src/docsys/Schemas/Application/documentation/index_p8.png new file mode 100755 index 0000000000000000000000000000000000000000..876759f1a4963380b786ce3373ce7ea908edb4d2 Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p8.png differ diff --git a/isis/src/docsys/Schemas/Application/documentation/index_p9.png b/isis/src/docsys/Schemas/Application/documentation/index_p9.png new file mode 100755 index 0000000000000000000000000000000000000000..121f37b68a162679f3b3cdde0eff113de5a8683c Binary files /dev/null and b/isis/src/docsys/Schemas/Application/documentation/index_p9.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation.xsd b/isis/src/docsys/Schemas/Documentation/documentation.xsd new file mode 100755 index 0000000000000000000000000000000000000000..b71cb203f7041349dfac06eb5bbcabe43f61dfd9 --- /dev/null +++ b/isis/src/docsys/Schemas/Documentation/documentation.xsd @@ -0,0 +1,329 @@ + + + + + Isis Documentation Schema + + + XML schema for describing the documentation available on the Isis web site + + + Designed by Deborah Lee Soltesz, dsoltesz@usgs.gov, 10/11/2002, USGS Astrogeology Research Program, Flagstaff, AZ + + + + container describing a single electronic document. "hidden" attribute should prevent this document from being linked in an autogenerated TOC. + + + + + + + + + + + + + + + enumeration for categories the document should be filed under + + + + + marks the document as "hidden", thus should not be linked to or otherwise referenced publicly + + + + + a document that gives general information about the software system and developers - history, policies, contact information, etc. + + + + + a document that serves as a guide (how-to or tutorial) for using the software or API, modifying the software, etc. + + + + + a document that serves as a tutorial on some subject regarding using, programming, maintaining, etc. Isis + + + + + a document that provides information about the installation of the software + + + + + document that gives information about maintaining the software installation + + + + + a document that contains highly technical information about the software + + + + + document related to support of the software by the software developers (i.e. USGS Isis Programming Team) + + + + + a document that serves simply to provide information + + + + + a document that serves as a reference (as opposed to a guide/how-to/tutorial) + + + + + a document outlining a policy + + + + + a document about the Isis XML languages + + + + + a document about the Isis API + + + + + a document about the previous version of Isis, Isis 2.1 + + + + + + + enumeration for target audience types + + + + + A basic user, generally one who does not install, maintain, or program for the software system, but simply uses the software + + + + + + An advanced user + + + + + A person who installs and maintains the software package (generally a systems administrator) + + + + + A programmer who uses the API to develop applications + + + + + A programmer who modifies the software system (Isis), i.e. develops Objects + + + + + all audiences + + + + + + + list of files that represent this document - for example, if the document is avaible in Word, PDF, and HTML, there would be three files listed here, one for each format + + + + + + + + + + list of categories this document should be linked under + + + + + + a single category in the list (enumerated type) + + + + + + + + list of target audience types + + + + + + + + + + bibliographic information about the document + + + + + + + + + + + + + + + list of history of changes to the document + + + + + + + + + + container of link (and potentially content) information for files representing the document. "hidden" attribute should prevent this file/subdocument from being linked. "primary" attribute should make this the favored file out of a selection of multiple files. + + + + + + + + + + + + + + + + name of the format or other descriptor for this file + + + + + size of the file if applicable (ie. not HTML or text) + + + + + electronic source information + + + + + + + + + + + full URL to a document at another location + + + + + + filename of document in this document structure (including desired name for HTML output of this document) + + + + + subtitle (useful for multipage documents) + + + + + inline document content- this file will be generated as an HTML document. Body must contain either a URI to an external XML file (with root element BODY) or the HTML formatted content + + + + + + XML-legal HTML formatted document text + + + + + + + + + filename for external XML source of content. External file must have a root element BODY that contains HTML formatted content + + + + + a single target audience type: user, advanced, administrator, developer, programmer + + + + + title of the document + + + + + brief description of this document + + + + + long description of this document + + + + + author's name + + + + + publisher's information + + + + + date of publication + + + + + single history entry + + + + + + + + + + + + + + + + + diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index.html b/isis/src/docsys/Schemas/Documentation/documentation/index.html new file mode 100755 index 0000000000000000000000000000000000000000..9fffa4e8d76d3ac0ab50c75eac11299c5479d379 --- /dev/null +++ b/isis/src/docsys/Schemas/Documentation/documentation/index.html @@ -0,0 +1,3141 @@ + + + + + + + + + + + + + + + + + +USGS +
    +

    +Isis Documentation +

    +
    +
    + Home +
    + +Schema + + +documentation.xsd + +
    +
    +
    + + + + + + + + +
    + + schema location:  + + + + documentation.xsd + +
    + +   + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + Elements  + + + + Simple types  + +
    + + audience + + + +   + + + + audienceType + + + +   + +
    + + author + + + +   + + + + categoryType + + + +   + +
    + + bibliography + + + +   + + +
    + + body + + + +   + + +
    + + brief + + + +   + + +
    + + category + + + +   + + +
    + + change + + + +   + + +
    + + date + + + +   + + +
    + + description + + + +   + + +
    + + documentation + + + +   + + +
    + + file + + + +   + + +
    + + filename + + + +   + + +
    + + files + + + +   + + +
    + + history + + + +   + + +
    + + publisher + + + +   + + +
    + + size + + + +   + + +
    + + source + + + +   + + +
    + + src + + + +   + + +
    + + subtitle + + + +   + + +
    + + target + + + +   + + +
    + + title + + + +   + + +
    + + type + + + +   + + +
    + + URL + + + +   + + +
    +
    +
    + + +element + + +audience + + + + + + + + + + + + + + + + + + +
    + + diagram + + + + [Schema element diagram] + + [Schema element diagram]
    + + children + + + + target + +
    + + used by + + + + + + + +
    + + element  + + + + documentation + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    list of target audience types
    +
    +
    +
    +
    + +element + + +author + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + used by + + + + + + + +
    + + element  + + + + bibliography + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    author's name
    +
    +
    +
    +
    + +element + + +bibliography + + + + + + + + + + + + + + + + + + +
    + + diagram + + + + [Schema element diagram] + [Schema element diagram] + [Schema element diagram] + [Schema element diagram] + [Schema element diagram] + [Schema element diagram] + + [Schema element diagram]
    + + children + + + + title + + + + + + + brief + + + + + + + description + + + + + + + author + + + + + + + publisher + + + + + + + date + +
    + + used by + + + + + + + +
    + + element  + + + + documentation + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    bibliographic information about the document
    +
    +
    +
    +
    + +element + + +body + + + + + + + + + + + + + + + + + + +
    + + diagram + + + + [Schema element diagram] + + [Schema element diagram]
    + + children + + + + src + +
    + + used by + + + + + + + +
    + + element  + + + + file + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    inline document content- this file will be
    +            generated as an HTML document. Body must contain either a URI to an external XML
    +            file (with root element BODY) or the HTML formatted content
    +
    +
    +
    +
    + +element + + +brief + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + used by + + + + + + + +
    + + element  + + + + bibliography + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    brief description of this document
    +
    +
    +
    +
    + +element + + +category + + + + + + + + + + + + + + + + + + +
    + + diagram + + + + [Schema element diagram] + + [Schema element diagram]
    + + children + + + + categoryItem + +
    + + used by + + + + + + + +
    + + element  + + + + documentation + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    list of categories this document should be
    +            linked under
    +
    +
    +
    +
    + +element + + +category/categoryItem + + + + + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + type + + + + categoryType + +
    + + facets + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + enumeration  + + + + hidden + +
    + + enumeration  + + + + about + +
    + + enumeration  + + + + guide + +
    + + enumeration  + + + + tutorial + +
    + + enumeration  + + + + installation + +
    + + enumeration  + + + + administration + +
    + + enumeration  + + + + technicaldoc + +
    + + enumeration  + + + + support + +
    + + enumeration  + + + + information + +
    + + enumeration  + + + + reference + +
    + + enumeration  + + + + policy + +
    + + enumeration  + + + + xml + +
    + + enumeration  + + + + api + +
    + + enumeration  + + + + isis2 + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    a single category in the list (enumerated type)
    +
    +
    +
    +
    + +element + + +change + + + + + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + used by + + + + + + + +
    + + element  + + + + history + +
    +
    + + attributes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + Name   + + + + Type   + + + + Use   + + + + Default   + + + + Fixed   + + + + Annotation + +
    + + name   + + + + xs:string   + + + + required   + + + +    + + + +    + + + + +
    + + date   + + + + xs:date   + + + + required   + + + +    + + + +    + + + + +
    + + hidden   + + + + xs:string   + + + + optional   + + + + false   + + + +    + + + + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    single history entry
    +
    +
    +
    +
    + +element + + +date + + + + + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + type + + + + xs:date + +
    + + used by + + + + + + + +
    + + element  + + + + bibliography + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    date of publication
    +
    +
    +
    +
    + +element + + +description + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + used by + + + + + + + +
    + + element  + + + + bibliography + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    long description of this document
    +
    +
    +
    +
    + +element + + +documentation + + + + + + + + + + + + + + + + + + +
    + + diagram + + + + [Schema element diagram] + [Schema element diagram] + [Schema element diagram] + [Schema element diagram] + [Schema element diagram] + + [Schema element diagram]
    + + children + + + + files + + + + + + + category + + + + + + + audience + + + + + + + bibliography + + + + + + + history + +
    + + attributes + + + + + + + + + + + + + + + + + + + +
    + + Name   + + + + Type   + + + + Use   + + + + Default   + + + + Fixed   + + + + Annotation + +
    + + hidden   + + + + xs:boolean   + + + + optional   + + + + false   + + + +    + + + + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    container describing a single electronic
    +            document. "hidden" attribute should prevent this document from being linked in
    +            an autogenerated TOC.
    +
    +
    +
    +
    + +element + + +file + + + + + + + + + + + + + + + + + + + + + + +
    + + diagram + + + + [Schema element diagram] + [Schema element diagram] + [Schema element diagram] + [Schema element diagram] + [Schema element diagram] + + [Schema element diagram]
    + + children + + + + type + + + + + + + size + + + + + + + source + + + + + + + subtitle + + + + + + + body + +
    + + used by + + + + + + + +
    + + element  + + + + files + +
    +
    + + attributes + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + Name   + + + + Type   + + + + Use   + + + + Default   + + + + Fixed   + + + + Annotation + +
    + + hidden   + + + + xs:boolean   + + + + optional   + + + + false   + + + +    + + + + +
    + + primary   + + + + xs:boolean   + + + + optional   + + + + false   + + + +    + + + + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    container of link (and potentially content)
    +            information for files representing the document. "hidden" attribute should
    +            prevent this file/subdocument from being linked. "primary" attribute should make
    +            this the favored file out of a selection of multiple files. 
    +
    +
    +
    +
    + +element + + +filename + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + used by + + + + + + + +
    + + element  + + + + source + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    filename of document in this document structure
    +            (including desired name for HTML output of this document)
    +
    +
    +
    +
    + +element + + +files + + + + + + + + + + + + + + + + + + +
    + + diagram + + + + [Schema element diagram] + + [Schema element diagram]
    + + children + + + + file + +
    + + used by + + + + + + + +
    + + element  + + + + documentation + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    list of files that represent this document -
    +            for example, if the document is avaible in Word, PDF, and HTML, there would be
    +            three files listed here, one for each format
    +
    +
    +
    +
    + +element + + +history + + + + + + + + + + + + + + + + + + +
    + + diagram + + + + [Schema element diagram] + + [Schema element diagram]
    + + children + + + + change + +
    + + used by + + + + + + + +
    + + element  + + + + documentation + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    list of history of changes to the document
    +
    +
    +
    +
    + +element + + +publisher + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + used by + + + + + + + +
    + + element  + + + + bibliography + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    publisher's information
    +
    +
    +
    +
    + +element + + +size + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + used by + + + + + + + +
    + + element  + + + + file + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    size of the file if applicable (ie. not HTML or
    +            text)
    +
    +
    +
    +
    + +element + + +source + + + + + + + + + + + + + + + + + + +
    + + diagram + + + + [Schema element diagram] + [Schema element diagram] + + [Schema element diagram]
    + + children + + + + URL + + + + + + + filename + +
    + + used by + + + + + + + +
    + + element  + + + + file + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    electronic source information
    +
    +
    +
    +
    + +element + + +src + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + used by + + + + + + + +
    + + element  + + + + body + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    filename for external XML source of content.
    +            External file must have a root element BODY that contains HTML formatted content
    +
    +
    +
    +
    + +element + + +subtitle + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + used by + + + + + + + +
    + + element  + + + + file + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    subtitle (useful for multipage documents)
    +
    +
    +
    +
    + +element + + +target + + + + + + + + + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + type + + + + audienceType + +
    + + used by + + + + + + + +
    + + element  + + + + audience + +
    +
    + + facets + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + enumeration  + + + + user + +
    + + enumeration  + + + + intermediate + +
    + + enumeration  + + + + advanced + +
    + + enumeration  + + + + administrator + +
    + + enumeration  + + + + developer + +
    + + enumeration  + + + + programmer + +
    + + enumeration  + + + + all + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    a single target audience type: user, advanced,
    +            administrator, developer, programmer
    +
    +
    +
    +
    + +element + + +title + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + used by + + + + + + + +
    + + element  + + + + bibliography + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    title of the document
    +
    +
    +
    +
    + +element + + +type + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + used by + + + + + + + +
    + + element  + + + + file + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    name of the format or other descriptor for this
    +            file
    +
    +
    +
    +
    + +element + + +URL + + + + + + + + + + + + + + +
    + + diagram + + [Schema element diagram]
    + + used by + + + + + + + +
    + + element  + + + + source + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    full URL to a document at another location
    +
    +
    +
    +
    + +simpleType + + +audienceType + + + + + + + + + + + + + + + + + + +
    + + type + + + + restriction of + + + xs:string + +
    + + used by + + + + + + + +
    + + element  + + + + target + +
    +
    + + facets + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + enumeration  + + + + user + +
    + + enumeration  + + + + intermediate + +
    + + enumeration  + + + + advanced + +
    + + enumeration  + + + + administrator + +
    + + enumeration  + + + + developer + +
    + + enumeration  + + + + programmer + +
    + + enumeration  + + + + all + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    enumeration for target audience types
    +
    +
    +
    +
    + +simpleType + + +categoryType + + + + + + + + + + + + + + + + + + +
    + + type + + + + restriction of + + + xs:string + +
    + + used by + + + + + + + +
    + + element  + + + + category/categoryItem + +
    +
    + + facets + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + enumeration  + + + + hidden + +
    + + enumeration  + + + + about + +
    + + enumeration  + + + + guide + +
    + + enumeration  + + + + tutorial + +
    + + enumeration  + + + + installation + +
    + + enumeration  + + + + administration + +
    + + enumeration  + + + + technicaldoc + +
    + + enumeration  + + + + support + +
    + + enumeration  + + + + information + +
    + + enumeration  + + + + reference + +
    + + enumeration  + + + + policy + +
    + + enumeration  + + + + xml + +
    + + enumeration  + + + + api + +
    + + enumeration  + + + + isis2 + +
    +
    + + annotation + + + + + + + +
    + + documentation  + + +
    enumeration for categories the document should
    +            be filed under
    +
    +
    + + \ No newline at end of file diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p1.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p1.png new file mode 100755 index 0000000000000000000000000000000000000000..dd2fdffa5a2cabf94a6e1f1e6eb22fb288e7465c Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p1.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p10.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p10.png new file mode 100755 index 0000000000000000000000000000000000000000..a5db7b0459de7f0bafb6fd443c04cc2f7308edc3 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p10.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p11.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p11.png new file mode 100755 index 0000000000000000000000000000000000000000..5b0ecf0e84b02978f5cc0f2448b866b2ff0b5d77 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p11.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p12.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p12.png new file mode 100755 index 0000000000000000000000000000000000000000..956e6a36e5b957d572bf2f96347c7b1506dd3833 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p12.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p13.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p13.png new file mode 100755 index 0000000000000000000000000000000000000000..622e408f3f00220148e27f6993d3e4480d0a9841 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p13.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p14.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p14.png new file mode 100755 index 0000000000000000000000000000000000000000..853c2106454120408cca60979b573feb69b45e57 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p14.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p15.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p15.png new file mode 100755 index 0000000000000000000000000000000000000000..c3948371c986376d9444de393772b2f30e5ad3ea Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p15.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p16.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p16.png new file mode 100755 index 0000000000000000000000000000000000000000..d0f34121307b56ec4ddaec0e9ceb59b3d0022431 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p16.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p17.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p17.png new file mode 100755 index 0000000000000000000000000000000000000000..1c6de88bc4c56f6bf330ef1a51301ce8a03cad1f Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p17.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p18.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p18.png new file mode 100755 index 0000000000000000000000000000000000000000..a5e3a00f93c219719eac9f6ef90e8f4a07ed31e4 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p18.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p19.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p19.png new file mode 100755 index 0000000000000000000000000000000000000000..9cd5670ba6883b20e0dc9131d0bf810ce6f7665a Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p19.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p2.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p2.png new file mode 100755 index 0000000000000000000000000000000000000000..c227b258b22efb29e41541e2c0bde7011ab638a3 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p2.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p20.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p20.png new file mode 100755 index 0000000000000000000000000000000000000000..e1c607637a06e270a5829f1c26b3c04de345fe64 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p20.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p21.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p21.png new file mode 100755 index 0000000000000000000000000000000000000000..d85bcd8d10cfb4a8eddcebffc27e7eafb943588c Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p21.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p22.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p22.png new file mode 100755 index 0000000000000000000000000000000000000000..a3779598d04d9c22aef9566201102a00bd03a958 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p22.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p23.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p23.png new file mode 100755 index 0000000000000000000000000000000000000000..080e6d684e23fcc6b786cf43661be8dd8eed5154 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p23.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p24.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p24.png new file mode 100755 index 0000000000000000000000000000000000000000..1ea307756c350ea373fe7e9e1dc56383fbc573ee Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p24.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p3.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p3.png new file mode 100755 index 0000000000000000000000000000000000000000..53ea6c4244b5149ac8743534168f80df35e6db4a Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p3.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p4.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p4.png new file mode 100755 index 0000000000000000000000000000000000000000..769027fa8c5f56cd2092cb4af941f6a07de7bc55 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p4.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p5.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p5.png new file mode 100755 index 0000000000000000000000000000000000000000..09ad191a5cf8454168c99a07a4371ef495de3ade Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p5.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p6.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p6.png new file mode 100755 index 0000000000000000000000000000000000000000..8970b54fa029101af21f11d15a1403d2abbee37a Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p6.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p7.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p7.png new file mode 100755 index 0000000000000000000000000000000000000000..8bc6a8bb93b80c6d6a3a4fcead174c843771477b Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p7.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p8.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p8.png new file mode 100755 index 0000000000000000000000000000000000000000..ca82df389d40d4a1438e1679b4997f52fb6c111a Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p8.png differ diff --git a/isis/src/docsys/Schemas/Documentation/documentation/index_p9.png b/isis/src/docsys/Schemas/Documentation/documentation/index_p9.png new file mode 100755 index 0000000000000000000000000000000000000000..3ff9a7c6a3085332b80ec106c46da98d95f54a33 Binary files /dev/null and b/isis/src/docsys/Schemas/Documentation/documentation/index_p9.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index.html b/isis/src/docsys/Schemas/Object/documentation/index.html new file mode 100755 index 0000000000000000000000000000000000000000..89d6d62e4275b9ed6c3d07f84bab6f046c56e603 --- /dev/null +++ b/isis/src/docsys/Schemas/Object/documentation/index.html @@ -0,0 +1,1000 @@ + Schema object.xsd


    schema location:  U:\usgsshareall\skoechle\object.xsd
    attribute form default:  unqualified
    element form default:  qualified
     
    Elements  Complex types  Simple types 
    audience  memberAccessType  audienceType 
    brief  valueDescriptionType  categoryItem_type 
    category  functionType 
    class  missionItem_type 
    code 
    description 
    example 
    externalClass 
    filename 
    global 
    history 
    includes 
    inherits 
    internalClass 
    item 
    liens 
    path 
    private 
    protected 
    public 
    seeAlso 
    source 
    target 
    text 
    title 
    type 


    element audience
    diagram shape
    properties
    content complex
    children target
    used by
    element class
    annotation
    documentation
    list of target audience types
    source <xs:element name="audience">
    <xs:annotation>
    +   
    <xs:documentation>list of target audience types</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="target" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>

    element brief
    diagram shape
    used by
    elements class memberAccessType/userDefinedTypes/enumeration memberAccessType/userDefinedTypes/enumeration/definition/expression memberAccessType/function memberAccessType/userDefinedTypes/struct memberAccessType/userDefinedTypes/typedef memberAccessType/userDefinedTypes/struct/variables/variable
    annotation
    documentation
    short description
    source <xs:element name="brief">
    <xs:annotation>
    +   
    <xs:documentation>short description</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element category
    diagram shape
    properties
    content complex
    children categoryItem missionItem
    used by
    element class
    annotation
    documentation
    A list of categories this object falls under.
    source <xs:element name="category">
    <xs:annotation>
    +   
    <xs:documentation>A list of categories this object falls under.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:choice maxOccurs="unbounded">
    +     
    <xs:element name="categoryItem" type="categoryItem_type">
    +       
    <xs:annotation>
    +         
    <xs:documentation>Enumerated type describing a single basic category this object falls in</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element name="missionItem" type="missionItem_type">
    +       
    <xs:annotation>
    +         
    <xs:documentation>Enumerated type describing a single mission specific category this object falls in</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +   
    </xs:choice>
    </xs:complexType>
    +
    </xs:element>

    element category/categoryItem
    diagram shape
    type categoryItem_type
    properties
    isRef 0
    content simple
    facets
    enumeration Footprint
    enumeration Geometry
    enumeration High Level Cube I/O
    enumeration Low Level Cube I/O
    enumeration Map Projection
    enumeration Mosaicking
    enumeration Parsing
    enumeration Spice, Instruments, and Cameras
    enumeration Statistics
    enumeration User Interface
    enumeration Utility
    enumeration Math
    annotation
    documentation
    Enumerated type describing a single basic category this object falls in
    source <xs:element name="categoryItem" type="categoryItem_type">
    <xs:annotation>
    +   
    <xs:documentation>Enumerated type describing a single basic category this object falls in</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element category/missionItem
    diagram shape
    type missionItem_type
    properties
    isRef 0
    content simple
    facets
    enumeration Cassini
    enumeration Chandrayaan
    enumeration Clementine
    enumeration Mariner
    enumeration Galileo
    enumeration Lunar Orbiter
    enumeration Lunar Reconnaissance Orbiter
    enumeration Mars Express
    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
    annotation
    documentation
    Enumerated type describing a single mission specific category this object falls in
    source <xs:element name="missionItem" type="missionItem_type">
    <xs:annotation>
    +   
    <xs:documentation>Enumerated type describing a single mission specific category this object falls in</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element class
    diagram shape
    properties
    content complex
    children brief description history category audience seeAlso inherits includes liens private protected public global
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    annotation
    documentation
    root element for XML describing an ISIS object
    source <xs:element name="class">
    <xs:annotation>
    +   
    <xs:documentation>root element for XML describing an ISIS object</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="brief" minOccurs="0"/>
    +     
    <xs:element ref="description"/>
    +     
    <xs:element ref="history"/>
    +     
    <xs:element ref="category"/>
    +     
    <xs:element ref="audience" minOccurs="0"/>
    +     
    <xs:element ref="seeAlso" minOccurs="0"/>
    +     
    <xs:element ref="inherits" minOccurs="0"/>
    +     
    <xs:element ref="includes" minOccurs="0"/>
    +     
    <xs:element ref="liens" minOccurs="0"/>
    +     
    <xs:element ref="private" minOccurs="0"/>
    +     
    <xs:element ref="protected" minOccurs="0"/>
    +     
    <xs:element ref="public"/>
    +     
    <xs:element ref="global" minOccurs="0"/>
    +   
    </xs:all>
    +   
    <xs:attribute name="name" type="xs:string" use="required"/>
    </xs:complexType>
    +
    </xs:element>

    attribute class/@name
    type xs:string
    properties
    isRef 0
    use required
    source <xs:attribute name="name" type="xs:string" use="required"/>

    element code
    diagram shape
    used by
    element example
    annotation
    documentation
    source code
    source <xs:element name="code">
    <xs:annotation>
    +   
    <xs:documentation>source code</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element description
    diagram shape
    properties
    content complex
    mixed true
    used by
    elements class memberAccessType/userDefinedTypes/enumeration memberAccessType/function memberAccessType/userDefinedTypes/struct memberAccessType/userDefinedTypes/typedef
    complexType valueDescriptionType
    annotation
    documentation
    multiparagraph description
    source <xs:element name="description">
    <xs:annotation>
    +   
    <xs:documentation>multiparagraph description</xs:documentation>
    </xs:annotation>
    <xs:complexType mixed="true">
    +   
    <xs:sequence>
    +     
    <xs:any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>

    element example
    diagram shape
    properties
    content complex
    children text code
    used by
    element memberAccessType/function
    annotation
    documentation
    text example that may include source code
    source <xs:element name="example">
    <xs:annotation>
    +   
    <xs:documentation>text example that may include source code</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:choice maxOccurs="unbounded">
    +     
    <xs:element ref="text"/>
    +     
    <xs:element ref="code"/>
    +   
    </xs:choice>
    </xs:complexType>
    +
    </xs:element>

    element externalClass
    diagram shape
    used by
    element inherits
    annotation
    documentation
    name and description of the third party class
    source <xs:element name="externalClass">
    <xs:annotation>
    +   
    <xs:documentation>name and description of the third party class</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element filename
    diagram shape
    used by
    element source
    annotation
    documentation
    Filename of a resource with no path specified
    source <xs:element name="filename">
    <xs:annotation>
    +   
    <xs:documentation>Filename of a resource with no path specified</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element global
    diagram shape
    type memberAccessType
    properties
    content complex
    children data function userDefinedTypes
    used by
    element class
    source <xs:element name="global" type="memberAccessType"/>

    element history
    diagram shape
    properties
    content complex
    children change
    used by
    element class
    annotation
    documentation
    programming history beginning with creation
    source <xs:element name="history">
    <xs:annotation>
    +   
    <xs:documentation>programming history beginning with creation</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element name="change" maxOccurs="unbounded">
    +       
    <xs:annotation>
    +         
    <xs:documentation>A single 'change' in the history of this class. Attribute 'name' is the author's full name; attribute 'date' is the change date in YYYY-MM-DD format. The element contains a free text dexcription of the changes made.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType mixed="true">
    +         
    <xs:attribute name="name" type="xs:string" use="required"/>
    +         
    <xs:attribute name="date" type="xs:date" use="required"/>
    +         
    <xs:attribute name="hidden" use="optional" default="false">
    +           
    <xs:simpleType>
    +             
    <xs:restriction base="xs:string">
    +               
    <xs:enumeration value="yes"/>
    +               
    <xs:enumeration value="no"/>
    +               
    <xs:enumeration value="true"/>
    +               
    <xs:enumeration value="false"/>
    +             
    </xs:restriction>
    +           
    </xs:simpleType>
    +         
    </xs:attribute>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>

    element history/change
    diagram shape
    properties
    isRef 0
    minOcc 1
    maxOcc unbounded
    content complex
    mixed true
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    datexs:daterequired      
    hiddenderived by: xs:stringoptional  false    
    annotation
    documentation
    A single 'change' in the history of this class. Attribute 'name' is the author's full name; attribute 'date' is the change date in YYYY-MM-DD format. The element contains a free text dexcription of the changes made.
    source <xs:element name="change" maxOccurs="unbounded">
    <xs:annotation>
    +   
    <xs:documentation>A single 'change' in the history of this class. Attribute 'name' is the author's full name; attribute 'date' is the change date in YYYY-MM-DD format. The element contains a free text dexcription of the changes made.</xs:documentation>
    </xs:annotation>
    <xs:complexType mixed="true">
    +   
    <xs:attribute name="name" type="xs:string" use="required"/>
    +   
    <xs:attribute name="date" type="xs:date" use="required"/>
    +   
    <xs:attribute name="hidden" use="optional" default="false">
    +     
    <xs:simpleType>
    +       
    <xs:restriction base="xs:string">
    +         
    <xs:enumeration value="yes"/>
    +         
    <xs:enumeration value="no"/>
    +         
    <xs:enumeration value="true"/>
    +         
    <xs:enumeration value="false"/>
    +       
    </xs:restriction>
    +     
    </xs:simpleType>
    +   
    </xs:attribute>
    </xs:complexType>
    +
    </xs:element>

    attribute history/change/@name
    type xs:string
    properties
    isRef 0
    use required
    source <xs:attribute name="name" type="xs:string" use="required"/>

    attribute history/change/@date
    type xs:date
    properties
    isRef 0
    use required
    source <xs:attribute name="date" type="xs:date" use="required"/>

    attribute history/change/@hidden
    type restriction of xs:string
    properties
    isRef 0
    default false
    use optional
    facets
    enumeration yes
    enumeration no
    enumeration true
    enumeration false
    source <xs:attribute name="hidden" use="optional" default="false">
    <xs:simpleType>
    +   
    <xs:restriction base="xs:string">
    +     
    <xs:enumeration value="yes"/>
    +     
    <xs:enumeration value="no"/>
    +     
    <xs:enumeration value="true"/>
    +     
    <xs:enumeration value="false"/>
    +   
    </xs:restriction>
    </xs:simpleType>
    +
    </xs:attribute>

    element includes
    diagram shape
    properties
    content complex
    children item
    used by
    element class
    annotation
    documentation
    list of files to include to use this object. Each 'item' contains a single included filename.
    source <xs:element name="includes">
    <xs:annotation>
    +   
    <xs:documentation>list of files to include to use this object. Each 'item' contains a single included filename.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence maxOccurs="unbounded">
    +     
    <xs:element ref="item"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>

    element inherits
    diagram shape
    properties
    content complex
    children internalClass externalClass
    used by
    element class
    annotation
    documentation
    list of parent classes this object inherits from
    source <xs:element name="inherits">
    <xs:annotation>
    +   
    <xs:documentation>list of parent classes this object inherits from</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:choice maxOccurs="unbounded">
    +     
    <xs:element ref="internalClass"/>
    +     
    <xs:element ref="externalClass"/>
    +   
    </xs:choice>
    </xs:complexType>
    +
    </xs:element>

    element internalClass
    diagram shape
    used by
    element inherits
    annotation
    documentation
    name of the class in this project
    source <xs:element name="internalClass">
    <xs:annotation>
    +   
    <xs:documentation>name of the class in this project</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element item
    diagram shape
    used by
    elements seeAlso/classes includes liens
    annotation
    documentation
    list item
    source <xs:element name="item">
    <xs:annotation>
    +   
    <xs:documentation>list item</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element liens
    diagram shape
    properties
    content complex
    children item
    used by
    element class
    annotation
    documentation
    things-to-do list. Each 'item' contains a single lien in the list.
    source <xs:element name="liens">
    <xs:annotation>
    +   
    <xs:documentation>things-to-do list. Each 'item' contains a single lien in the list.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>

    element path
    diagram shape
    used by
    element source
    annotation
    documentation
    Relative path or URL path to a file without a filename specified. If this element is not specified, stylesheets may assume a default location other than the current working director.
    source <xs:element name="path">
    <xs:annotation>
    +   
    <xs:documentation>Relative path or URL path to a file without a filename specified. If this element is not specified, stylesheets may assume a default location other than the current working director.</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element private
    diagram shape
    type memberAccessType
    properties
    content complex
    children data function userDefinedTypes
    used by
    element class
    annotation
    documentation
    container for private member variables and functions
    source <xs:element name="private" type="memberAccessType">
    <xs:annotation>
    +   
    <xs:documentation>container for private member variables and functions</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element protected
    diagram shape
    type memberAccessType
    properties
    content complex
    children data function userDefinedTypes
    used by
    element class
    annotation
    documentation
    container for protected member variables and functions
    source <xs:element name="protected" type="memberAccessType">
    <xs:annotation>
    +   
    <xs:documentation>container for protected member variables and functions</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element public
    diagram shape
    type memberAccessType
    properties
    content complex
    children data function userDefinedTypes
    used by
    element class
    annotation
    documentation
    container for public member variables and functions
    source <xs:element name="public" type="memberAccessType">
    <xs:annotation>
    +   
    <xs:documentation>container for public member variables and functions</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element seeAlso
    diagram shape
    properties
    content complex
    children documents classes
    used by
    element class
    annotation
    documentation
    list of related objects and documents
    source <xs:element name="seeAlso">
    <xs:annotation>
    +   
    <xs:documentation>list of related objects and documents</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element name="documents" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>A list of related documents. Each item should contain the directory nane for a particular document stored in the 'documents' directory.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:sequence>
    +           
    <xs:element name="document" maxOccurs="unbounded">
    +             
    <xs:annotation>
    +               
    <xs:documentation>container describing a document</xs:documentation>
    +             
    </xs:annotation>
    +             
    <xs:complexType>
    +               
    <xs:all>
    +                 
    <xs:element ref="title"/>
    +                 
    <xs:element ref="source" minOccurs="0"/>
    +                 
    <xs:element name="author" minOccurs="0">
    +                   
    <xs:annotation>
    +                     
    <xs:documentation>author (or authors) of this document</xs:documentation>
    +                   
    </xs:annotation>
    +                 
    </xs:element>
    +                 
    <xs:element name="publisher" minOccurs="0">
    +                   
    <xs:annotation>
    +                     
    <xs:documentation>publisher information (name, city, etc.)</xs:documentation>
    +                   
    </xs:annotation>
    +                 
    </xs:element>
    +                 
    <xs:element name="pages" minOccurs="0">
    +                   
    <xs:annotation>
    +                     
    <xs:documentation>pages in document refered to by this reference</xs:documentation>
    +                   
    </xs:annotation>
    +                 
    </xs:element>
    +                 
    <xs:element name="date" type="xs:date" minOccurs="0">
    +                   
    <xs:annotation>
    +                     
    <xs:documentation>publication date</xs:documentation>
    +                   
    </xs:annotation>
    +                 
    </xs:element>
    +               
    </xs:all>
    +             
    </xs:complexType>
    +           
    </xs:element>
    +         
    </xs:sequence>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="classes" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>A list of related classes. Each item should contain the proper Isis class name.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:sequence>
    +           
    <xs:element ref="item" maxOccurs="unbounded"/>
    +         
    </xs:sequence>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:all>
    </xs:complexType>
    +
    </xs:element>

    element seeAlso/documents
    diagram shape
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    children document
    annotation
    documentation
    A list of related documents. Each item should contain the directory nane for a particular document stored in the 'documents' directory.
    source <xs:element name="documents" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>A list of related documents. Each item should contain the directory nane for a particular document stored in the 'documents' directory.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element name="document" maxOccurs="unbounded">
    +       
    <xs:annotation>
    +         
    <xs:documentation>container describing a document</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:all>
    +           
    <xs:element ref="title"/>
    +           
    <xs:element ref="source" minOccurs="0"/>
    +           
    <xs:element name="author" minOccurs="0">
    +             
    <xs:annotation>
    +               
    <xs:documentation>author (or authors) of this document</xs:documentation>
    +             
    </xs:annotation>
    +           
    </xs:element>
    +           
    <xs:element name="publisher" minOccurs="0">
    +             
    <xs:annotation>
    +               
    <xs:documentation>publisher information (name, city, etc.)</xs:documentation>
    +             
    </xs:annotation>
    +           
    </xs:element>
    +           
    <xs:element name="pages" minOccurs="0">
    +             
    <xs:annotation>
    +               
    <xs:documentation>pages in document refered to by this reference</xs:documentation>
    +             
    </xs:annotation>
    +           
    </xs:element>
    +           
    <xs:element name="date" type="xs:date" minOccurs="0">
    +             
    <xs:annotation>
    +               
    <xs:documentation>publication date</xs:documentation>
    +             
    </xs:annotation>
    +           
    </xs:element>
    +         
    </xs:all>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>

    element seeAlso/documents/document
    diagram shape
    properties
    isRef 0
    minOcc 1
    maxOcc unbounded
    content complex
    children title source author publisher pages date
    annotation
    documentation
    container describing a document
    source <xs:element name="document" maxOccurs="unbounded">
    <xs:annotation>
    +   
    <xs:documentation>container describing a document</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="title"/>
    +     
    <xs:element ref="source" minOccurs="0"/>
    +     
    <xs:element name="author" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>author (or authors) of this document</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element name="publisher" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>publisher information (name, city, etc.)</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element name="pages" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>pages in document refered to by this reference</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element name="date" type="xs:date" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>publication date</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +   
    </xs:all>
    </xs:complexType>
    +
    </xs:element>

    element seeAlso/documents/document/author
    diagram shape
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    annotation
    documentation
    author (or authors) of this document
    source <xs:element name="author" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>author (or authors) of this document</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element seeAlso/documents/document/publisher
    diagram shape
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    annotation
    documentation
    publisher information (name, city, etc.)
    source <xs:element name="publisher" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>publisher information (name, city, etc.)</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element seeAlso/documents/document/pages
    diagram shape
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    annotation
    documentation
    pages in document refered to by this reference
    source <xs:element name="pages" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>pages in document refered to by this reference</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element seeAlso/documents/document/date
    diagram shape
    type xs:date
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content simple
    annotation
    documentation
    publication date
    source <xs:element name="date" type="xs:date" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>publication date</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element seeAlso/classes
    diagram shape
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    children item
    annotation
    documentation
    A list of related classes. Each item should contain the proper Isis class name.
    source <xs:element name="classes" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>A list of related classes. Each item should contain the proper Isis class name.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element ref="item" maxOccurs="unbounded"/>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>

    element source
    diagram shape
    properties
    content complex
    children filename path
    used by
    element seeAlso/documents/document
    annotation
    documentation
    for an electronic document, full path or URL to a resource including the filename
    source <xs:element name="source">
    <xs:annotation>
    +   
    <xs:documentation>for an electronic document, full path or URL to a resource including the filename</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="filename"/>
    +     
    <xs:element ref="path" minOccurs="0"/>
    +   
    </xs:all>
    </xs:complexType>
    +
    </xs:element>

    element target
    diagram shape
    type audienceType
    properties
    content simple
    used by
    element audience
    facets
    enumeration developer
    enumeration programmer
    enumeration all
    annotation
    documentation
    a single target audience type who is expected to use this object
    source <xs:element name="target" type="audienceType">
    <xs:annotation>
    +   
    <xs:documentation>a single target audience type who is expected to use this object</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element text
    diagram shape
    used by
    element example
    annotation
    documentation
    free text
    source <xs:element name="text">
    <xs:annotation>
    +   
    <xs:documentation>free text</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element title
    diagram shape
    used by
    element seeAlso/documents/document
    annotation
    documentation
    title of an application, document, or resource
    source <xs:element name="title">
    <xs:annotation>
    +   
    <xs:documentation>title of an application, document, or resource</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element type
    diagram shape
    used by
    complexType valueDescriptionType
    annotation
    documentation
    class or native type of a parameter, variable, return value, etc.
    source <xs:element name="type">
    <xs:annotation>
    +   
    <xs:documentation>class or native type of a parameter, variable, return value, etc.</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    complexType memberAccessType
    diagram shape
    children data function userDefinedTypes
    used by
    elements global private protected public
    annotation
    documentation
    type defining everything that belongs in the private, protected, and public sections of a class
    source <xs:complexType name="memberAccessType">
    <xs:annotation>
    +   
    <xs:documentation>type defining everything that belongs in the private, protected, and public sections of a class</xs:documentation>
    </xs:annotation>
    <xs:choice maxOccurs="unbounded">
    +   
    <xs:element name="data" maxOccurs="unbounded">
    +     
    <xs:annotation>
    +       
    <xs:documentation>a container describing a member variable of a class</xs:documentation>
    +     
    </xs:annotation>
    +     
    <xs:complexType>
    +       
    <xs:complexContent>
    +         
    <xs:extension base="valueDescriptionType">
    +           
    <xs:attribute name="name" type="xs:string" use="required"/>
    +         
    </xs:extension>
    +       
    </xs:complexContent>
    +     
    </xs:complexType>
    +   
    </xs:element>
    +   
    <xs:element name="function" maxOccurs="unbounded">
    +     
    <xs:annotation>
    +       
    <xs:documentation>a container for describing a member fucntion of a class. The attribute 'name' is the function name; the attribute 'type' is an enumeration for the basic function type (method, constructor, etc.)</xs:documentation>
    +     
    </xs:annotation>
    +     
    <xs:complexType>
    +       
    <xs:all>
    +         
    <xs:element ref="description"/>
    +         
    <xs:element ref="brief" minOccurs="0"/>
    +         
    <xs:element name="returns" type="valueDescriptionType" minOccurs="0">
    +           
    <xs:annotation>
    +             
    <xs:documentation>a container for describing what is returned by the function. If not present, either the function is a constructor or destructor, or is assumed to return void</xs:documentation>
    +           
    </xs:annotation>
    +         
    </xs:element>
    +         
    <xs:element name="argumentList" minOccurs="0">
    +           
    <xs:annotation>
    +             
    <xs:documentation>The list of arguments to the function. Arguments should be listed in the order they are taken by the function.</xs:documentation>
    +           
    </xs:annotation>
    +           
    <xs:complexType>
    +             
    <xs:sequence>
    +               
    <xs:element name="argument" maxOccurs="unbounded">
    +                 
    <xs:annotation>
    +                   
    <xs:documentation>A container for describing a single argument.</xs:documentation>
    +                 
    </xs:annotation>
    +                 
    <xs:complexType>
    +                   
    <xs:complexContent>
    +                     
    <xs:extension base="valueDescriptionType">
    +                       
    <xs:attribute name="name" type="xs:string" use="required"/>
    +                     
    </xs:extension>
    +                   
    </xs:complexContent>
    +                 
    </xs:complexType>
    +               
    </xs:element>
    +             
    </xs:sequence>
    +           
    </xs:complexType>
    +         
    </xs:element>
    +         
    <xs:element name="throws" minOccurs="0">
    +           
    <xs:annotation>
    +             
    <xs:documentation>container for information about what exceptions the function throws</xs:documentation>
    +           
    </xs:annotation>
    +           
    <xs:complexType>
    +             
    <xs:sequence>
    +               
    <xs:element name="reason" maxOccurs="unbounded">
    +                 
    <xs:annotation>
    +                   
    <xs:documentation>the reason (free text) an exception is thrown, with attribute 'type' for what the exception type is </xs:documentation>
    +                 
    </xs:annotation>
    +                 
    <xs:complexType mixed="true">
    +                   
    <xs:attribute name="type" type="xs:string" use="required"/>
    +                 
    </xs:complexType>
    +               
    </xs:element>
    +             
    </xs:sequence>
    +           
    </xs:complexType>
    +         
    </xs:element>
    +         
    <xs:element name="prefix" type="xs:string" minOccurs="0">
    +           
    <xs:annotation>
    +             
    <xs:documentation>information that is appended to the beginning of a function prototype; e.g. virtual</xs:documentation>
    +           
    </xs:annotation>
    +         
    </xs:element>
    +         
    <xs:element name="suffix" type="xs:string" minOccurs="0">
    +           
    <xs:annotation>
    +             
    <xs:documentation>information that is appended to the end of a function prototype; e.g. const, = 0, or static</xs:documentation>
    +           
    </xs:annotation>
    +         
    </xs:element>
    +         
    <xs:element ref="example" minOccurs="0"/>
    +       
    </xs:all>
    +       
    <xs:attribute name="name" type="xs:string" use="required"/>
    +       
    <xs:attribute name="type" type="functionType" use="required"/>
    +     
    </xs:complexType>
    +   
    </xs:element>
    +   
    <xs:element name="userDefinedTypes" minOccurs="0">
    +     
    <xs:complexType>
    +       
    <xs:choice maxOccurs="unbounded">
    +         
    <xs:element name="enumeration">
    +           
    <xs:annotation>
    +             
    <xs:documentation>description of a defined enumerated type</xs:documentation>
    +           
    </xs:annotation>
    +           
    <xs:complexType>
    +             
    <xs:all>
    +               
    <xs:element ref="brief" minOccurs="0"/>
    +               
    <xs:element ref="description"/>
    +               
    <xs:element name="definition">
    +                 
    <xs:annotation>
    +                   
    <xs:documentation>list of name/values that define this type</xs:documentation>
    +                 
    </xs:annotation>
    +                 
    <xs:complexType>
    +                   
    <xs:sequence>
    +                     
    <xs:element name="expression" maxOccurs="unbounded">
    +                       
    <xs:annotation>
    +                         
    <xs:documentation>a name/value pair in an enumerated type</xs:documentation>
    +                       
    </xs:annotation>
    +                       
    <xs:complexType>
    +                         
    <xs:all>
    +                           
    <xs:element ref="brief" minOccurs="0"/>
    +                         
    </xs:all>
    +                         
    <xs:attribute name="name" type="xs:string" use="required"/>
    +                         
    <xs:attribute name="value" type="xs:int" use="optional"/>
    +                       
    </xs:complexType>
    +                     
    </xs:element>
    +                   
    </xs:sequence>
    +                 
    </xs:complexType>
    +               
    </xs:element>
    +             
    </xs:all>
    +             
    <xs:attribute name="name" type="xs:string" use="required"/>
    +           
    </xs:complexType>
    +         
    </xs:element>
    +         
    <xs:element name="struct">
    +           
    <xs:annotation>
    +             
    <xs:documentation>description of a defined struct</xs:documentation>
    +           
    </xs:annotation>
    +           
    <xs:complexType>
    +             
    <xs:all>
    +               
    <xs:element ref="brief" minOccurs="0"/>
    +               
    <xs:element ref="description"/>
    +               
    <xs:element name="variables">
    +                 
    <xs:annotation>
    +                   
    <xs:documentation>list of variables in the struct</xs:documentation>
    +                 
    </xs:annotation>
    +                 
    <xs:complexType>
    +                   
    <xs:all>
    +                     
    <xs:element name="variable">
    +                       
    <xs:annotation>
    +                         
    <xs:documentation>a variable in the struct</xs:documentation>
    +                       
    </xs:annotation>
    +                       
    <xs:complexType>
    +                         
    <xs:all>
    +                           
    <xs:element ref="brief" minOccurs="0"/>
    +                         
    </xs:all>
    +                         
    <xs:attribute name="type" type="xs:string" use="required"/>
    +                         
    <xs:attribute name="name" type="xs:string" use="required"/>
    +                       
    </xs:complexType>
    +                     
    </xs:element>
    +                   
    </xs:all>
    +                 
    </xs:complexType>
    +               
    </xs:element>
    +             
    </xs:all>
    +             
    <xs:attribute name="name" type="xs:string" use="required"/>
    +           
    </xs:complexType>
    +         
    </xs:element>
    +         
    <xs:element name="typedef">
    +           
    <xs:annotation>
    +             
    <xs:documentation>description of a defined typdef</xs:documentation>
    +           
    </xs:annotation>
    +           
    <xs:complexType>
    +             
    <xs:all>
    +               
    <xs:element ref="brief" minOccurs="0"/>
    +               
    <xs:element ref="description"/>
    +               
    <xs:element name="oldName" type="xs:string">
    +                 
    <xs:annotation>
    +                   
    <xs:documentation>the name of the type being redefined</xs:documentation>
    +                 
    </xs:annotation>
    +               
    </xs:element>
    +             
    </xs:all>
    +             
    <xs:attribute name="name" type="xs:string" use="required"/>
    +           
    </xs:complexType>
    +         
    </xs:element>
    +       
    </xs:choice>
    +     
    </xs:complexType>
    +   
    </xs:element>
    </xs:choice>
    +
    </xs:complexType>

    element memberAccessType/data
    diagram shape
    type extension of valueDescriptionType
    properties
    isRef 0
    minOcc 1
    maxOcc unbounded
    content complex
    children type description default
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    annotation
    documentation
    a container describing a member variable of a class
    source <xs:element name="data" maxOccurs="unbounded">
    <xs:annotation>
    +   
    <xs:documentation>a container describing a member variable of a class</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:complexContent>
    +     
    <xs:extension base="valueDescriptionType">
    +       
    <xs:attribute name="name" type="xs:string" use="required"/>
    +     
    </xs:extension>
    +   
    </xs:complexContent>
    </xs:complexType>
    +
    </xs:element>

    attribute memberAccessType/data/@name
    type xs:string
    properties
    isRef 0
    use required
    source <xs:attribute name="name" type="xs:string" use="required"/>

    element memberAccessType/function
    diagram shape
    properties
    isRef 0
    minOcc 1
    maxOcc unbounded
    content complex
    children description brief returns argumentList throws prefix suffix example
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    typefunctionTyperequired      
    annotation
    documentation
    a container for describing a member fucntion of a class. The attribute 'name' is the function name; the attribute 'type' is an enumeration for the basic function type (method, constructor, etc.)
    source <xs:element name="function" maxOccurs="unbounded">
    <xs:annotation>
    +   
    <xs:documentation>a container for describing a member fucntion of a class. The attribute 'name' is the function name; the attribute 'type' is an enumeration for the basic function type (method, constructor, etc.)</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="description"/>
    +     
    <xs:element ref="brief" minOccurs="0"/>
    +     
    <xs:element name="returns" type="valueDescriptionType" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>a container for describing what is returned by the function. If not present, either the function is a constructor or destructor, or is assumed to return void</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element name="argumentList" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>The list of arguments to the function. Arguments should be listed in the order they are taken by the function.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:sequence>
    +           
    <xs:element name="argument" maxOccurs="unbounded">
    +             
    <xs:annotation>
    +               
    <xs:documentation>A container for describing a single argument.</xs:documentation>
    +             
    </xs:annotation>
    +             
    <xs:complexType>
    +               
    <xs:complexContent>
    +                 
    <xs:extension base="valueDescriptionType">
    +                   
    <xs:attribute name="name" type="xs:string" use="required"/>
    +                 
    </xs:extension>
    +               
    </xs:complexContent>
    +             
    </xs:complexType>
    +           
    </xs:element>
    +         
    </xs:sequence>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="throws" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>container for information about what exceptions the function throws</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:sequence>
    +           
    <xs:element name="reason" maxOccurs="unbounded">
    +             
    <xs:annotation>
    +               
    <xs:documentation>the reason (free text) an exception is thrown, with attribute 'type' for what the exception type is </xs:documentation>
    +             
    </xs:annotation>
    +             
    <xs:complexType mixed="true">
    +               
    <xs:attribute name="type" type="xs:string" use="required"/>
    +             
    </xs:complexType>
    +           
    </xs:element>
    +         
    </xs:sequence>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="prefix" type="xs:string" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>information that is appended to the beginning of a function prototype; e.g. virtual</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element name="suffix" type="xs:string" minOccurs="0">
    +       
    <xs:annotation>
    +         
    <xs:documentation>information that is appended to the end of a function prototype; e.g. const, = 0, or static</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +     
    <xs:element ref="example" minOccurs="0"/>
    +   
    </xs:all>
    +   
    <xs:attribute name="name" type="xs:string" use="required"/>
    +   
    <xs:attribute name="type" type="functionType" use="required"/>
    </xs:complexType>
    +
    </xs:element>

    attribute memberAccessType/function/@name
    type xs:string
    properties
    isRef 0
    use required
    source <xs:attribute name="name" type="xs:string" use="required"/>

    attribute memberAccessType/function/@type
    type functionType
    properties
    isRef 0
    use required
    facets
    enumeration constructor
    enumeration destructor
    enumeration method
    source <xs:attribute name="type" type="functionType" use="required"/>

    element memberAccessType/function/returns
    diagram shape
    type valueDescriptionType
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    children type description default
    annotation
    documentation
    a container for describing what is returned by the function. If not present, either the function is a constructor or destructor, or is assumed to return void
    source <xs:element name="returns" type="valueDescriptionType" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>a container for describing what is returned by the function. If not present, either the function is a constructor or destructor, or is assumed to return void</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element memberAccessType/function/argumentList
    diagram shape
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    children argument
    annotation
    documentation
    The list of arguments to the function. Arguments should be listed in the order they are taken by the function.
    source <xs:element name="argumentList" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>The list of arguments to the function. Arguments should be listed in the order they are taken by the function.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element name="argument" maxOccurs="unbounded">
    +       
    <xs:annotation>
    +         
    <xs:documentation>A container for describing a single argument.</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:complexContent>
    +           
    <xs:extension base="valueDescriptionType">
    +             
    <xs:attribute name="name" type="xs:string" use="required"/>
    +           
    </xs:extension>
    +         
    </xs:complexContent>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>

    element memberAccessType/function/argumentList/argument
    diagram shape
    type extension of valueDescriptionType
    properties
    isRef 0
    minOcc 1
    maxOcc unbounded
    content complex
    children type description default
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    annotation
    documentation
    A container for describing a single argument.
    source <xs:element name="argument" maxOccurs="unbounded">
    <xs:annotation>
    +   
    <xs:documentation>A container for describing a single argument.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:complexContent>
    +     
    <xs:extension base="valueDescriptionType">
    +       
    <xs:attribute name="name" type="xs:string" use="required"/>
    +     
    </xs:extension>
    +   
    </xs:complexContent>
    </xs:complexType>
    +
    </xs:element>

    attribute memberAccessType/function/argumentList/argument/@name
    type xs:string
    properties
    isRef 0
    use required
    source <xs:attribute name="name" type="xs:string" use="required"/>

    element memberAccessType/function/throws
    diagram shape
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    children reason
    annotation
    documentation
    container for information about what exceptions the function throws
    source <xs:element name="throws" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>container for information about what exceptions the function throws</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element name="reason" maxOccurs="unbounded">
    +       
    <xs:annotation>
    +         
    <xs:documentation>the reason (free text) an exception is thrown, with attribute 'type' for what the exception type is </xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType mixed="true">
    +         
    <xs:attribute name="type" type="xs:string" use="required"/>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>

    element memberAccessType/function/throws/reason
    diagram shape
    properties
    isRef 0
    minOcc 1
    maxOcc unbounded
    content complex
    mixed true
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    typexs:stringrequired      
    annotation
    documentation
    the reason (free text) an exception is thrown, with attribute 'type' for what the exception type is
    source <xs:element name="reason" maxOccurs="unbounded">
    <xs:annotation>
    +   
    <xs:documentation>the reason (free text) an exception is thrown, with attribute 'type' for what the exception type is </xs:documentation>
    </xs:annotation>
    <xs:complexType mixed="true">
    +   
    <xs:attribute name="type" type="xs:string" use="required"/>
    </xs:complexType>
    +
    </xs:element>

    attribute memberAccessType/function/throws/reason/@type
    type xs:string
    properties
    isRef 0
    use required
    source <xs:attribute name="type" type="xs:string" use="required"/>

    element memberAccessType/function/prefix
    diagram shape
    type xs:string
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content simple
    annotation
    documentation
    information that is appended to the beginning of a function prototype; e.g. virtual
    source <xs:element name="prefix" type="xs:string" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>information that is appended to the beginning of a function prototype; e.g. virtual</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element memberAccessType/function/suffix
    diagram shape
    type xs:string
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content simple
    annotation
    documentation
    information that is appended to the end of a function prototype; e.g. const, = 0, or static
    source <xs:element name="suffix" type="xs:string" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>information that is appended to the end of a function prototype; e.g. const, = 0, or static</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    element memberAccessType/userDefinedTypes
    diagram shape
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    content complex
    children enumeration struct typedef
    source <xs:element name="userDefinedTypes" minOccurs="0">
    <xs:complexType>
    +   
    <xs:choice maxOccurs="unbounded">
    +     
    <xs:element name="enumeration">
    +       
    <xs:annotation>
    +         
    <xs:documentation>description of a defined enumerated type</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:all>
    +           
    <xs:element ref="brief" minOccurs="0"/>
    +           
    <xs:element ref="description"/>
    +           
    <xs:element name="definition">
    +             
    <xs:annotation>
    +               
    <xs:documentation>list of name/values that define this type</xs:documentation>
    +             
    </xs:annotation>
    +             
    <xs:complexType>
    +               
    <xs:sequence>
    +                 
    <xs:element name="expression" maxOccurs="unbounded">
    +                   
    <xs:annotation>
    +                     
    <xs:documentation>a name/value pair in an enumerated type</xs:documentation>
    +                   
    </xs:annotation>
    +                   
    <xs:complexType>
    +                     
    <xs:all>
    +                       
    <xs:element ref="brief" minOccurs="0"/>
    +                     
    </xs:all>
    +                     
    <xs:attribute name="name" type="xs:string" use="required"/>
    +                     
    <xs:attribute name="value" type="xs:int" use="optional"/>
    +                   
    </xs:complexType>
    +                 
    </xs:element>
    +               
    </xs:sequence>
    +             
    </xs:complexType>
    +           
    </xs:element>
    +         
    </xs:all>
    +         
    <xs:attribute name="name" type="xs:string" use="required"/>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="struct">
    +       
    <xs:annotation>
    +         
    <xs:documentation>description of a defined struct</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:all>
    +           
    <xs:element ref="brief" minOccurs="0"/>
    +           
    <xs:element ref="description"/>
    +           
    <xs:element name="variables">
    +             
    <xs:annotation>
    +               
    <xs:documentation>list of variables in the struct</xs:documentation>
    +             
    </xs:annotation>
    +             
    <xs:complexType>
    +               
    <xs:all>
    +                 
    <xs:element name="variable">
    +                   
    <xs:annotation>
    +                     
    <xs:documentation>a variable in the struct</xs:documentation>
    +                   
    </xs:annotation>
    +                   
    <xs:complexType>
    +                     
    <xs:all>
    +                       
    <xs:element ref="brief" minOccurs="0"/>
    +                     
    </xs:all>
    +                     
    <xs:attribute name="type" type="xs:string" use="required"/>
    +                     
    <xs:attribute name="name" type="xs:string" use="required"/>
    +                   
    </xs:complexType>
    +                 
    </xs:element>
    +               
    </xs:all>
    +             
    </xs:complexType>
    +           
    </xs:element>
    +         
    </xs:all>
    +         
    <xs:attribute name="name" type="xs:string" use="required"/>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +     
    <xs:element name="typedef">
    +       
    <xs:annotation>
    +         
    <xs:documentation>description of a defined typdef</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:all>
    +           
    <xs:element ref="brief" minOccurs="0"/>
    +           
    <xs:element ref="description"/>
    +           
    <xs:element name="oldName" type="xs:string">
    +             
    <xs:annotation>
    +               
    <xs:documentation>the name of the type being redefined</xs:documentation>
    +             
    </xs:annotation>
    +           
    </xs:element>
    +         
    </xs:all>
    +         
    <xs:attribute name="name" type="xs:string" use="required"/>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:choice>
    </xs:complexType>
    +
    </xs:element>

    element memberAccessType/userDefinedTypes/enumeration
    diagram shape
    properties
    isRef 0
    content complex
    children brief description definition
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    annotation
    documentation
    description of a defined enumerated type
    source <xs:element name="enumeration">
    <xs:annotation>
    +   
    <xs:documentation>description of a defined enumerated type</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="brief" minOccurs="0"/>
    +     
    <xs:element ref="description"/>
    +     
    <xs:element name="definition">
    +       
    <xs:annotation>
    +         
    <xs:documentation>list of name/values that define this type</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:sequence>
    +           
    <xs:element name="expression" maxOccurs="unbounded">
    +             
    <xs:annotation>
    +               
    <xs:documentation>a name/value pair in an enumerated type</xs:documentation>
    +             
    </xs:annotation>
    +             
    <xs:complexType>
    +               
    <xs:all>
    +                 
    <xs:element ref="brief" minOccurs="0"/>
    +               
    </xs:all>
    +               
    <xs:attribute name="name" type="xs:string" use="required"/>
    +               
    <xs:attribute name="value" type="xs:int" use="optional"/>
    +             
    </xs:complexType>
    +           
    </xs:element>
    +         
    </xs:sequence>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:all>
    +   
    <xs:attribute name="name" type="xs:string" use="required"/>
    </xs:complexType>
    +
    </xs:element>

    attribute memberAccessType/userDefinedTypes/enumeration/@name
    type xs:string
    properties
    isRef 0
    use required
    source <xs:attribute name="name" type="xs:string" use="required"/>

    element memberAccessType/userDefinedTypes/enumeration/definition
    diagram shape
    properties
    isRef 0
    content complex
    children expression
    annotation
    documentation
    list of name/values that define this type
    source <xs:element name="definition">
    <xs:annotation>
    +   
    <xs:documentation>list of name/values that define this type</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:sequence>
    +     
    <xs:element name="expression" maxOccurs="unbounded">
    +       
    <xs:annotation>
    +         
    <xs:documentation>a name/value pair in an enumerated type</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:all>
    +           
    <xs:element ref="brief" minOccurs="0"/>
    +         
    </xs:all>
    +         
    <xs:attribute name="name" type="xs:string" use="required"/>
    +         
    <xs:attribute name="value" type="xs:int" use="optional"/>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:sequence>
    </xs:complexType>
    +
    </xs:element>

    element memberAccessType/userDefinedTypes/enumeration/definition/expression
    diagram shape
    properties
    isRef 0
    minOcc 1
    maxOcc unbounded
    content complex
    children brief
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    valuexs:intoptional      
    annotation
    documentation
    a name/value pair in an enumerated type
    source <xs:element name="expression" maxOccurs="unbounded">
    <xs:annotation>
    +   
    <xs:documentation>a name/value pair in an enumerated type</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="brief" minOccurs="0"/>
    +   
    </xs:all>
    +   
    <xs:attribute name="name" type="xs:string" use="required"/>
    +   
    <xs:attribute name="value" type="xs:int" use="optional"/>
    </xs:complexType>
    +
    </xs:element>

    attribute memberAccessType/userDefinedTypes/enumeration/definition/expression/@name
    type xs:string
    properties
    isRef 0
    use required
    source <xs:attribute name="name" type="xs:string" use="required"/>

    attribute memberAccessType/userDefinedTypes/enumeration/definition/expression/@value
    type xs:int
    properties
    isRef 0
    use optional
    source <xs:attribute name="value" type="xs:int" use="optional"/>

    element memberAccessType/userDefinedTypes/struct
    diagram shape
    properties
    isRef 0
    content complex
    children brief description variables
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    annotation
    documentation
    description of a defined struct
    source <xs:element name="struct">
    <xs:annotation>
    +   
    <xs:documentation>description of a defined struct</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="brief" minOccurs="0"/>
    +     
    <xs:element ref="description"/>
    +     
    <xs:element name="variables">
    +       
    <xs:annotation>
    +         
    <xs:documentation>list of variables in the struct</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:all>
    +           
    <xs:element name="variable">
    +             
    <xs:annotation>
    +               
    <xs:documentation>a variable in the struct</xs:documentation>
    +             
    </xs:annotation>
    +             
    <xs:complexType>
    +               
    <xs:all>
    +                 
    <xs:element ref="brief" minOccurs="0"/>
    +               
    </xs:all>
    +               
    <xs:attribute name="type" type="xs:string" use="required"/>
    +               
    <xs:attribute name="name" type="xs:string" use="required"/>
    +             
    </xs:complexType>
    +           
    </xs:element>
    +         
    </xs:all>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:all>
    +   
    <xs:attribute name="name" type="xs:string" use="required"/>
    </xs:complexType>
    +
    </xs:element>

    attribute memberAccessType/userDefinedTypes/struct/@name
    type xs:string
    properties
    isRef 0
    use required
    source <xs:attribute name="name" type="xs:string" use="required"/>

    element memberAccessType/userDefinedTypes/struct/variables
    diagram shape
    properties
    isRef 0
    content complex
    children variable
    annotation
    documentation
    list of variables in the struct
    source <xs:element name="variables">
    <xs:annotation>
    +   
    <xs:documentation>list of variables in the struct</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element name="variable">
    +       
    <xs:annotation>
    +         
    <xs:documentation>a variable in the struct</xs:documentation>
    +       
    </xs:annotation>
    +       
    <xs:complexType>
    +         
    <xs:all>
    +           
    <xs:element ref="brief" minOccurs="0"/>
    +         
    </xs:all>
    +         
    <xs:attribute name="type" type="xs:string" use="required"/>
    +         
    <xs:attribute name="name" type="xs:string" use="required"/>
    +       
    </xs:complexType>
    +     
    </xs:element>
    +   
    </xs:all>
    </xs:complexType>
    +
    </xs:element>

    element memberAccessType/userDefinedTypes/struct/variables/variable
    diagram shape
    properties
    isRef 0
    content complex
    children brief
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    typexs:stringrequired      
    namexs:stringrequired      
    annotation
    documentation
    a variable in the struct
    source <xs:element name="variable">
    <xs:annotation>
    +   
    <xs:documentation>a variable in the struct</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="brief" minOccurs="0"/>
    +   
    </xs:all>
    +   
    <xs:attribute name="type" type="xs:string" use="required"/>
    +   
    <xs:attribute name="name" type="xs:string" use="required"/>
    </xs:complexType>
    +
    </xs:element>

    attribute memberAccessType/userDefinedTypes/struct/variables/variable/@type
    type xs:string
    properties
    isRef 0
    use required
    source <xs:attribute name="type" type="xs:string" use="required"/>

    attribute memberAccessType/userDefinedTypes/struct/variables/variable/@name
    type xs:string
    properties
    isRef 0
    use required
    source <xs:attribute name="name" type="xs:string" use="required"/>

    element memberAccessType/userDefinedTypes/typedef
    diagram shape
    properties
    isRef 0
    content complex
    children brief description oldName
    attributes
    Name  Type  Use  Default  Fixed  Annotation
    namexs:stringrequired      
    annotation
    documentation
    description of a defined typdef
    source <xs:element name="typedef">
    <xs:annotation>
    +   
    <xs:documentation>description of a defined typdef</xs:documentation>
    </xs:annotation>
    <xs:complexType>
    +   
    <xs:all>
    +     
    <xs:element ref="brief" minOccurs="0"/>
    +     
    <xs:element ref="description"/>
    +     
    <xs:element name="oldName" type="xs:string">
    +       
    <xs:annotation>
    +         
    <xs:documentation>the name of the type being redefined</xs:documentation>
    +       
    </xs:annotation>
    +     
    </xs:element>
    +   
    </xs:all>
    +   
    <xs:attribute name="name" type="xs:string" use="required"/>
    </xs:complexType>
    +
    </xs:element>

    attribute memberAccessType/userDefinedTypes/typedef/@name
    type xs:string
    properties
    isRef 0
    use required
    source <xs:attribute name="name" type="xs:string" use="required"/>

    element memberAccessType/userDefinedTypes/typedef/oldName
    diagram shape
    type xs:string
    properties
    isRef 0
    content simple
    annotation
    documentation
    the name of the type being redefined
    source <xs:element name="oldName" type="xs:string">
    <xs:annotation>
    +   
    <xs:documentation>the name of the type being redefined</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    complexType valueDescriptionType
    diagram shape
    children type description default
    used by
    elements memberAccessType/function/argumentList/argument memberAccessType/data memberAccessType/function/returns
    annotation
    documentation
    type defining a container which describes a value, such as an argument, parameter, or variable
    source <xs:complexType name="valueDescriptionType">
    <xs:annotation>
    +   
    <xs:documentation>type defining a container which describes a value, such as an argument, parameter, or variable</xs:documentation>
    </xs:annotation>
    <xs:all>
    +   
    <xs:element ref="type"/>
    +   
    <xs:element ref="description" minOccurs="0"/>
    +   
    <xs:element name="default" minOccurs="0">
    +     
    <xs:annotation>
    +       
    <xs:documentation>the default value of a member variable, argument, or funtion return.</xs:documentation>
    +     
    </xs:annotation>
    +   
    </xs:element>
    </xs:all>
    +
    </xs:complexType>

    element valueDescriptionType/default
    diagram shape
    properties
    isRef 0
    minOcc 0
    maxOcc 1
    annotation
    documentation
    the default value of a member variable, argument, or funtion return.
    source <xs:element name="default" minOccurs="0">
    <xs:annotation>
    +   
    <xs:documentation>the default value of a member variable, argument, or funtion return.</xs:documentation>
    </xs:annotation>
    +
    </xs:element>

    simpleType audienceType
    type restriction of xs:string
    properties
    final restriction
    used by
    element target
    facets
    enumeration developer
    enumeration programmer
    enumeration all
    annotation
    documentation
    enumeration for target audience types
    source <xs:simpleType name="audienceType" final="restriction">
    <xs:annotation>
    +   
    <xs:documentation>enumeration for target audience types</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
    +   
    <xs:enumeration value="developer"/>
    +   
    <xs:enumeration value="programmer"/>
    +   
    <xs:enumeration value="all"/>
    </xs:restriction>
    +
    </xs:simpleType>

    simpleType categoryItem_type
    type restriction of xs:string
    properties
    final restriction
    used by
    element category/categoryItem
    facets
    enumeration Footprint
    enumeration Geometry
    enumeration High Level Cube I/O
    enumeration Low Level Cube I/O
    enumeration Map Projection
    enumeration Mosaicking
    enumeration Parsing
    enumeration Spice, Instruments, and Cameras
    enumeration Statistics
    enumeration User Interface
    enumeration Utility
    enumeration Math
    source <xs:simpleType name="categoryItem_type" final="restriction">
    <xs:restriction base="xs:string">
    +   
    <xs:enumeration value="Footprint"/>
    +   
    <xs:enumeration value="Geometry"/>
    +   
    <xs:enumeration value="High Level Cube I/O"/>
    +   
    <xs:enumeration value="Low Level Cube I/O"/>
    +   
    <xs:enumeration value="Map Projection"/>
    +   
    <xs:enumeration value="Mosaicking"/>
    +   
    <xs:enumeration value="Parsing"/>
    +   
    <xs:enumeration value="Spice, Instruments, and Cameras"/>
    +   
    <xs:enumeration value="Statistics"/>
    +   
    <xs:enumeration value="User Interface"/>
    +   
    <xs:enumeration value="Utility"/>
    +   
    <xs:enumeration value="Math"/>
    </xs:restriction>
    +
    </xs:simpleType>

    simpleType functionType
    type restriction of xs:string
    properties
    final restriction
    used by
    attribute memberAccessType/function/@type
    facets
    enumeration constructor
    enumeration destructor
    enumeration method
    annotation
    documentation
    enumerated function type (constructor | destructor | method)
    source <xs:simpleType name="functionType" final="restriction">
    <xs:annotation>
    +   
    <xs:documentation>enumerated function type (constructor | destructor | method)</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
    +   
    <xs:enumeration value="constructor"/>
    +   
    <xs:enumeration value="destructor"/>
    +   
    <xs:enumeration value="method"/>
    </xs:restriction>
    +
    </xs:simpleType>

    simpleType missionItem_type
    type restriction of xs:string
    properties
    final restriction
    used by
    element category/missionItem
    facets
    enumeration Cassini
    enumeration Chandrayaan
    enumeration Clementine
    enumeration Mariner
    enumeration Galileo
    enumeration Lunar Orbiter
    enumeration Lunar Reconnaissance Orbiter
    enumeration Mars Express
    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
    annotation
    documentation
    enumeration for mission specific Application categorizations
    source <xs:simpleType name="missionItem_type" final="restriction">
    <xs:annotation>
    +   
    <xs:documentation>enumeration for mission specific Application categorizations</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
    +   
    <xs:enumeration value="Cassini"/>
    +   
    <xs:enumeration value="Chandrayaan"/>
    +   
    <xs:enumeration value="Clementine"/>
    +   
    <xs:enumeration value="Mariner"/>
    +   
    <xs:enumeration value="Galileo"/>
    +   
    <xs:enumeration value="Lunar Orbiter"/>
    +   
    <xs:enumeration value="Lunar Reconnaissance Orbiter"/>
    +   
    <xs:enumeration value="Mars Express"/>
    +   
    <xs:enumeration value="Mars Reconnaissance Orbiter"/>
    +   
    <xs:enumeration value="Mars Global Surveyor"/>
    +   
    <xs:enumeration value="Mars Odyssey"/>
    +   
    <xs:enumeration value="Mars Exploration Rover"/>
    +   
    <xs:enumeration value="Messenger"/>
    +   
    <xs:enumeration value="Small Missions for Advanced Research and Technology 1"/>
    +   
    <xs:enumeration value="Voyager"/>
    +   
    <xs:enumeration value="Viking"/>
    </xs:restriction>
    +
    </xs:simpleType>


    XML Schema documentation generated by
    XMLSpy Schema Editor http://www.altova.com/xmlspy diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p1.png b/isis/src/docsys/Schemas/Object/documentation/index_p1.png new file mode 100755 index 0000000000000000000000000000000000000000..0dc8edcd8eaf1c0dfa6802bc95c64c892077d27a Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p1.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p10.png b/isis/src/docsys/Schemas/Object/documentation/index_p10.png new file mode 100755 index 0000000000000000000000000000000000000000..477cac65cfb6897dfcdf9613a845aa310e1e516e Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p10.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p11.png b/isis/src/docsys/Schemas/Object/documentation/index_p11.png new file mode 100755 index 0000000000000000000000000000000000000000..1eb0d64bfe7bb0b9cf05eacd5c3047037daad986 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p11.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p12.png b/isis/src/docsys/Schemas/Object/documentation/index_p12.png new file mode 100755 index 0000000000000000000000000000000000000000..fcc896fbd3ea9aedbd78fc60e23fb4593e29859d Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p12.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p13.png b/isis/src/docsys/Schemas/Object/documentation/index_p13.png new file mode 100755 index 0000000000000000000000000000000000000000..222bbca3f5ca994c721733f671fc84dd35e08b06 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p13.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p14.png b/isis/src/docsys/Schemas/Object/documentation/index_p14.png new file mode 100755 index 0000000000000000000000000000000000000000..34b581f974329ed4d039d0df7c868933718bba5b Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p14.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p15.png b/isis/src/docsys/Schemas/Object/documentation/index_p15.png new file mode 100755 index 0000000000000000000000000000000000000000..6189094a15691b1e48eb189c6574fb306655c698 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p15.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p16.png b/isis/src/docsys/Schemas/Object/documentation/index_p16.png new file mode 100755 index 0000000000000000000000000000000000000000..c5b9e755bd8b404a75d3c3bcdb7eec9114487475 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p16.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p17.png b/isis/src/docsys/Schemas/Object/documentation/index_p17.png new file mode 100755 index 0000000000000000000000000000000000000000..dca1a4ee5149a54bf07914053dab7c24189998d3 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p17.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p18.png b/isis/src/docsys/Schemas/Object/documentation/index_p18.png new file mode 100755 index 0000000000000000000000000000000000000000..c532e1ca35023b25f396605155bf41b13a6390b2 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p18.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p19.png b/isis/src/docsys/Schemas/Object/documentation/index_p19.png new file mode 100755 index 0000000000000000000000000000000000000000..998d6cdbb0d45221017a56b02f47734a68f1c162 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p19.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p2.png b/isis/src/docsys/Schemas/Object/documentation/index_p2.png new file mode 100755 index 0000000000000000000000000000000000000000..609e237344732c7a7c0c4002f7fd22ca29540ba8 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p2.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p20.png b/isis/src/docsys/Schemas/Object/documentation/index_p20.png new file mode 100755 index 0000000000000000000000000000000000000000..0924aec37282d9f194b598f822b6c25b83a2ca86 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p20.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p21.png b/isis/src/docsys/Schemas/Object/documentation/index_p21.png new file mode 100755 index 0000000000000000000000000000000000000000..475a56f79cb05f0323b22defc8143ec9dfbeaa6e Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p21.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p22.png b/isis/src/docsys/Schemas/Object/documentation/index_p22.png new file mode 100755 index 0000000000000000000000000000000000000000..7192a5d3ac70183a31cd17f7747b6eacc601aeb3 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p22.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p23.png b/isis/src/docsys/Schemas/Object/documentation/index_p23.png new file mode 100755 index 0000000000000000000000000000000000000000..c3c08526d432b67c8e9bed3e6130fe245fe2bfed Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p23.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p24.png b/isis/src/docsys/Schemas/Object/documentation/index_p24.png new file mode 100755 index 0000000000000000000000000000000000000000..130072ed35f61fd6f174e2b4c34a645af70d22af Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p24.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p25.png b/isis/src/docsys/Schemas/Object/documentation/index_p25.png new file mode 100755 index 0000000000000000000000000000000000000000..0370c85ee36a276ab9a7429dc419a14e281ff079 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p25.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p26.png b/isis/src/docsys/Schemas/Object/documentation/index_p26.png new file mode 100755 index 0000000000000000000000000000000000000000..9e853c08ff8394540011c0073822cc05651cb267 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p26.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p27.png b/isis/src/docsys/Schemas/Object/documentation/index_p27.png new file mode 100755 index 0000000000000000000000000000000000000000..88a04d2d380842939067c3c74e0b9537593931d7 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p27.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p28.png b/isis/src/docsys/Schemas/Object/documentation/index_p28.png new file mode 100755 index 0000000000000000000000000000000000000000..f25722207a1ad1d960a216ad04233dca078139f4 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p28.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p29.png b/isis/src/docsys/Schemas/Object/documentation/index_p29.png new file mode 100755 index 0000000000000000000000000000000000000000..7a0c052d5f5f30ba81623f4ac4da975acbbc2087 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p29.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p3.png b/isis/src/docsys/Schemas/Object/documentation/index_p3.png new file mode 100755 index 0000000000000000000000000000000000000000..da7afd79b2c4dcfa560792f0ff686e80a87d80a4 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p3.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p30.png b/isis/src/docsys/Schemas/Object/documentation/index_p30.png new file mode 100755 index 0000000000000000000000000000000000000000..77fc7ad05b70d044eb663e88e788ade205ae3e42 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p30.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p31.png b/isis/src/docsys/Schemas/Object/documentation/index_p31.png new file mode 100755 index 0000000000000000000000000000000000000000..9a3cded7881ec5a301c3a488f776967fd6985c57 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p31.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p32.png b/isis/src/docsys/Schemas/Object/documentation/index_p32.png new file mode 100755 index 0000000000000000000000000000000000000000..5ac9c51c4fdfcc4e7035c6e23199744df196d8f6 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p32.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p33.png b/isis/src/docsys/Schemas/Object/documentation/index_p33.png new file mode 100755 index 0000000000000000000000000000000000000000..a64a7f52995c844b7c40243ee074cda8050cd1c8 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p33.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p34.png b/isis/src/docsys/Schemas/Object/documentation/index_p34.png new file mode 100755 index 0000000000000000000000000000000000000000..9ca94be3ed9a89f6e4550904559b4fa64cf4c2a9 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p34.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p35.png b/isis/src/docsys/Schemas/Object/documentation/index_p35.png new file mode 100755 index 0000000000000000000000000000000000000000..5ec9debacecde58f6b6e0d666dfbc2af6c645df4 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p35.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p36.png b/isis/src/docsys/Schemas/Object/documentation/index_p36.png new file mode 100755 index 0000000000000000000000000000000000000000..ba499cbec719d6759d0b9bb5e16a1e0f369cdc77 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p36.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p37.png b/isis/src/docsys/Schemas/Object/documentation/index_p37.png new file mode 100755 index 0000000000000000000000000000000000000000..bac9223cda1907490fa74b7a7ca1a3d787ad58cd Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p37.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p38.png b/isis/src/docsys/Schemas/Object/documentation/index_p38.png new file mode 100755 index 0000000000000000000000000000000000000000..304aa66218b69102ca4b1f3e5e3e0281f00bb4e0 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p38.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p39.png b/isis/src/docsys/Schemas/Object/documentation/index_p39.png new file mode 100755 index 0000000000000000000000000000000000000000..ea5c31e70c23bcdd9684c6a5343139c4eb3aac42 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p39.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p4.png b/isis/src/docsys/Schemas/Object/documentation/index_p4.png new file mode 100755 index 0000000000000000000000000000000000000000..6dc79c495b750fd3c7849e5f68fe0df9ebea373a Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p4.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p40.png b/isis/src/docsys/Schemas/Object/documentation/index_p40.png new file mode 100755 index 0000000000000000000000000000000000000000..75e8a00c1d09dfd1d46d92092ef82a041dcb71ff Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p40.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p41.png b/isis/src/docsys/Schemas/Object/documentation/index_p41.png new file mode 100755 index 0000000000000000000000000000000000000000..0353a7875a8eb6e666997bef198b3bea51ee136b Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p41.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p42.png b/isis/src/docsys/Schemas/Object/documentation/index_p42.png new file mode 100755 index 0000000000000000000000000000000000000000..6d57f26cdebbbe231290930df012a970cbb517a8 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p42.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p43.png b/isis/src/docsys/Schemas/Object/documentation/index_p43.png new file mode 100755 index 0000000000000000000000000000000000000000..1946941364a509a1bd3344a482628f09166c375a Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p43.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p44.png b/isis/src/docsys/Schemas/Object/documentation/index_p44.png new file mode 100755 index 0000000000000000000000000000000000000000..3701ec3f1fc149910d467ca7e26f7abdf119f6a7 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p44.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p45.png b/isis/src/docsys/Schemas/Object/documentation/index_p45.png new file mode 100644 index 0000000000000000000000000000000000000000..c11b515de04512a1cb147eaac36d8d646c6e9655 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p45.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p46.png b/isis/src/docsys/Schemas/Object/documentation/index_p46.png new file mode 100644 index 0000000000000000000000000000000000000000..03fcf451b0eb0ce4c1a68d3035ba5075ecefaca9 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p46.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p47.png b/isis/src/docsys/Schemas/Object/documentation/index_p47.png new file mode 100644 index 0000000000000000000000000000000000000000..f42b32daba458879ee868087dc36e5469c132e9a Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p47.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p48.png b/isis/src/docsys/Schemas/Object/documentation/index_p48.png new file mode 100644 index 0000000000000000000000000000000000000000..90d37855033e9ac404d83d09acaee55b3b63cdfc Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p48.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p49.png b/isis/src/docsys/Schemas/Object/documentation/index_p49.png new file mode 100644 index 0000000000000000000000000000000000000000..401eb351c502703d7db2965d29ec5b897b12956f Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p49.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p5.png b/isis/src/docsys/Schemas/Object/documentation/index_p5.png new file mode 100755 index 0000000000000000000000000000000000000000..5036e962842f335e0664c001ec504aa1e4638eab Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p5.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p50.png b/isis/src/docsys/Schemas/Object/documentation/index_p50.png new file mode 100644 index 0000000000000000000000000000000000000000..73fe41017c06c0f481ec11c94618eb3789a04d50 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p50.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p51.png b/isis/src/docsys/Schemas/Object/documentation/index_p51.png new file mode 100644 index 0000000000000000000000000000000000000000..c27f29b9c59235c40c0b4c72484c6035adb9692a Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p51.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p52.png b/isis/src/docsys/Schemas/Object/documentation/index_p52.png new file mode 100644 index 0000000000000000000000000000000000000000..f964511e81313bf38b122cf6d6eefa3177554e27 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p52.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p53.png b/isis/src/docsys/Schemas/Object/documentation/index_p53.png new file mode 100644 index 0000000000000000000000000000000000000000..58dc553219f645371ee3f727db20fc7cea288acb Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p53.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p54.png b/isis/src/docsys/Schemas/Object/documentation/index_p54.png new file mode 100644 index 0000000000000000000000000000000000000000..66d1f4c868448224cb23675cca456fa035316bfc Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p54.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p55.png b/isis/src/docsys/Schemas/Object/documentation/index_p55.png new file mode 100644 index 0000000000000000000000000000000000000000..0ae7d9b659ac2d7e14d7baee7a3d1206e682753a Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p55.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p56.png b/isis/src/docsys/Schemas/Object/documentation/index_p56.png new file mode 100644 index 0000000000000000000000000000000000000000..9c8ceed3399d16bf632910bb45db846b2c3418ce Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p56.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p57.png b/isis/src/docsys/Schemas/Object/documentation/index_p57.png new file mode 100644 index 0000000000000000000000000000000000000000..b70631f30b7e343a92074b351f7e1857b9733411 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p57.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p6.png b/isis/src/docsys/Schemas/Object/documentation/index_p6.png new file mode 100755 index 0000000000000000000000000000000000000000..237499d7ce3b5ff4d71a2fb670ed6f395faa0388 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p6.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p7.png b/isis/src/docsys/Schemas/Object/documentation/index_p7.png new file mode 100755 index 0000000000000000000000000000000000000000..375988064b7dd5ae721e73db93e334eca3a13d40 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p7.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p8.png b/isis/src/docsys/Schemas/Object/documentation/index_p8.png new file mode 100755 index 0000000000000000000000000000000000000000..37d2186e2002043eb74b811289e9aabd18e69a8c Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p8.png differ diff --git a/isis/src/docsys/Schemas/Object/documentation/index_p9.png b/isis/src/docsys/Schemas/Object/documentation/index_p9.png new file mode 100755 index 0000000000000000000000000000000000000000..163ae9fa04cdc00c9eb3d0d086caae3b672743c7 Binary files /dev/null and b/isis/src/docsys/Schemas/Object/documentation/index_p9.png differ diff --git a/isis/src/docsys/Schemas/Object/object.xsd b/isis/src/docsys/Schemas/Object/object.xsd new file mode 100755 index 0000000000000000000000000000000000000000..367aa088886cc26272480751694431b27cdc3fe6 --- /dev/null +++ b/isis/src/docsys/Schemas/Object/object.xsd @@ -0,0 +1,537 @@ + + + + + ISIS Object Schema + + + XML Schema for ISIS object documentation + + + Designed by Stuart Sides, ssides@usgs.gov, and Deborah Lee Soltesz, dsoltesz@usgs.gov, 3/14/2002, USGS Astrogeology Research Program, Flagstaff, AZ + + + + root element for XML describing an ISIS object + + + + + + + + + + + + + + + + + + + + + + + short description + + + + + multiparagraph description + + + + + + + + + + list of files to include to use this object. Each 'item' contains a single included filename. + + + + + + + + + + list of parent classes this object inherits from + + + + + + + + + + + programming history beginning with creation + + + + + + A single 'change' in the history of this class. Attribute 'name' is the author's full name; attribute 'date' is the change date in YYYY-MM-DD format. The element contains a free text dexcription of the changes made. + + + + + + + + + + + + + + + + + + + + + + things-to-do list. Each 'item' contains a single lien in the list. + + + + + + + + + + list of related objects and documents + + + + + + A list of related documents. Each item should contain the directory nane for a particular document stored in the 'documents' directory. + + + + + + container describing a document + + + + + + + + author (or authors) of this document + + + + + publisher information (name, city, etc.) + + + + + pages in document refered to by this reference + + + + + publication date + + + + + + + + + + + A list of related classes. Each item should contain the proper Isis class name. + + + + + + + + + + + + + container for private member variables and functions + + + + + container for protected member variables and functions + + + + + container for public member variables and functions + + + + + class or native type of a parameter, variable, return value, etc. + + + + + list item + + + + + type defining everything that belongs in the private, protected, and public sections of a class + + + + + a container describing a member variable of a class + + + + + + + + + + + + a container for describing a member fucntion of a class. The attribute 'name' is the function name; the attribute 'type' is an enumeration for the basic function type (method, constructor, etc.) + + + + + + + + a container for describing what is returned by the function. If not present, either the function is a constructor or destructor, or is assumed to return void + + + + + The list of arguments to the function. Arguments should be listed in the order they are taken by the function. + + + + + + A container for describing a single argument. + + + + + + + + + + + + + + + container for information about what exceptions the function throws + + + + + + the reason (free text) an exception is thrown, with attribute 'type' for what the exception type is + + + + + + + + + + + information that is appended to the beginning of a function prototype; e.g. virtual + + + + + information that is appended to the end of a function prototype; e.g. const, = 0, or static + + + + + + + + + + + + + + description of a defined enumerated type + + + + + + + + list of name/values that define this type + + + + + + a name/value pair in an enumerated type + + + + + + + + + + + + + + + + + + + description of a defined struct + + + + + + + + list of variables in the struct + + + + + + a variable in the struct + + + + + + + + + + + + + + + + + + + description of a defined typdef + + + + + + + + the name of the type being redefined + + + + + + + + + + + + + + type defining a container which describes a value, such as an argument, parameter, or variable + + + + + + + the default value of a member variable, argument, or funtion return. + + + + + + + enumerated function type (constructor | destructor | method) + + + + + + + + + + text example that may include source code + + + + + + + + + + + source code + + + + + free text + + + + + A list of categories this object falls under. + + + + + + Enumerated type describing a single basic category this object falls in + + + + + Enumerated type describing a single mission specific category this object falls in + + + + + + + + title of an application, document, or resource + + + + + for an electronic document, full path or URL to a resource including the filename + + + + + + + + + + + Relative path or URL path to a file without a filename specified. If this element is not specified, stylesheets may assume a default location other than the current working director. + + + + + Filename of a resource with no path specified + + + + + name of the class in this project + + + + + name and description of the third party class + + + + + enumeration for target audience types + + + + + + + + + + + + + + + + + + + + + + + + + + enumeration for mission specific Application categorizations + + + + + + + + + + + + + + + + + + + + + + + + + + a single target audience type who is expected to use this object + + + + + list of target audience types + + + + + + + + + diff --git a/isis/src/docsys/assets/banners/banner.jpg b/isis/src/docsys/assets/banners/banner.jpg new file mode 100755 index 0000000000000000000000000000000000000000..ef19adc7d1b1e36e21e967214ff3b540e2a08924 Binary files /dev/null and b/isis/src/docsys/assets/banners/banner.jpg differ diff --git a/isis/src/docsys/assets/banners/isis_bg.jpg b/isis/src/docsys/assets/banners/isis_bg.jpg new file mode 100755 index 0000000000000000000000000000000000000000..0844e5c8f88c872a9e6e06f24e60465f07e06db3 Binary files /dev/null and b/isis/src/docsys/assets/banners/isis_bg.jpg differ diff --git a/isis/src/docsys/assets/banners/isis_main.jpg b/isis/src/docsys/assets/banners/isis_main.jpg new file mode 100755 index 0000000000000000000000000000000000000000..71652dfa452c290e2a7257532e50b2b429b3e404 Binary files /dev/null and b/isis/src/docsys/assets/banners/isis_main.jpg differ diff --git a/isis/src/docsys/assets/banners/isis_menu.jpg b/isis/src/docsys/assets/banners/isis_menu.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8738204a7cb098b720e1d97745694b3bc42847a0 Binary files /dev/null and b/isis/src/docsys/assets/banners/isis_menu.jpg differ diff --git a/isis/src/docsys/assets/banners/isis_wallpaper.jpg b/isis/src/docsys/assets/banners/isis_wallpaper.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ec4990b7f4fe7a444efabf309ee3899e6a798759 Binary files /dev/null and b/isis/src/docsys/assets/banners/isis_wallpaper.jpg differ diff --git a/isis/src/docsys/assets/icons/firstgov.gif b/isis/src/docsys/assets/icons/firstgov.gif new file mode 100755 index 0000000000000000000000000000000000000000..eafecca2273b9d736bc2a8337cace72258b42220 Binary files /dev/null and b/isis/src/docsys/assets/icons/firstgov.gif differ diff --git a/isis/src/docsys/assets/icons/firstgov_trans.gif b/isis/src/docsys/assets/icons/firstgov_trans.gif new file mode 100755 index 0000000000000000000000000000000000000000..ba5ed0af61192d754dc4cacd7235563b1da26a7f Binary files /dev/null and b/isis/src/docsys/assets/icons/firstgov_trans.gif differ diff --git a/isis/src/docsys/assets/icons/littleVIS.gif b/isis/src/docsys/assets/icons/littleVIS.gif new file mode 100755 index 0000000000000000000000000000000000000000..d5b03d321efa2901c14319907a90f76f4b433c6c Binary files /dev/null and b/isis/src/docsys/assets/icons/littleVIS.gif differ diff --git a/isis/src/docsys/assets/navigation/buttons/arrowdown.gif b/isis/src/docsys/assets/navigation/buttons/arrowdown.gif new file mode 100755 index 0000000000000000000000000000000000000000..0296a7f0e257d21dd5a5b4ebe63ad34515eff8ad Binary files /dev/null and b/isis/src/docsys/assets/navigation/buttons/arrowdown.gif differ diff --git a/isis/src/docsys/assets/navigation/buttons/arrowleft.gif b/isis/src/docsys/assets/navigation/buttons/arrowleft.gif new file mode 100755 index 0000000000000000000000000000000000000000..94a5f79061c14d565524a9dd6de595aaa32c584a Binary files /dev/null and b/isis/src/docsys/assets/navigation/buttons/arrowleft.gif differ diff --git a/isis/src/docsys/assets/navigation/buttons/arrowright.gif b/isis/src/docsys/assets/navigation/buttons/arrowright.gif new file mode 100755 index 0000000000000000000000000000000000000000..b1dd9748dbf46bb77bd00a76ed8328ae11e55516 Binary files /dev/null and b/isis/src/docsys/assets/navigation/buttons/arrowright.gif differ diff --git a/isis/src/docsys/assets/navigation/buttons/arrowup.gif b/isis/src/docsys/assets/navigation/buttons/arrowup.gif new file mode 100755 index 0000000000000000000000000000000000000000..eda8bcb99acb117158869a22f1ff5433fbf3b4e0 Binary files /dev/null and b/isis/src/docsys/assets/navigation/buttons/arrowup.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/about_menu_bar.gif b/isis/src/docsys/assets/navigation/menubar/about_menu_bar.gif new file mode 100755 index 0000000000000000000000000000000000000000..7d641f9ddb32b390c73e3b4e54d681426a13b873 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/about_menu_bar.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/about_menu_button.gif b/isis/src/docsys/assets/navigation/menubar/about_menu_button.gif new file mode 100755 index 0000000000000000000000000000000000000000..7931555a8b5ab96dd1f2b9cb27cfabec61645282 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/about_menu_button.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/about_menu_button_hot.gif b/isis/src/docsys/assets/navigation/menubar/about_menu_button_hot.gif new file mode 100755 index 0000000000000000000000000000000000000000..91f78a04b922736d9a838db4f5084e44b1e209c8 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/about_menu_button_hot.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/blank_menu_bar.gif b/isis/src/docsys/assets/navigation/menubar/blank_menu_bar.gif new file mode 100755 index 0000000000000000000000000000000000000000..a11e74770f8b4133db7f4febd7291f483a5175ed Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/blank_menu_bar.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/datainfo_menu_bar.gif b/isis/src/docsys/assets/navigation/menubar/datainfo_menu_bar.gif new file mode 100755 index 0000000000000000000000000000000000000000..52dd358e6ffe83cb8b7db8088854b2142c437222 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/datainfo_menu_bar.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/datainfo_menu_button.gif b/isis/src/docsys/assets/navigation/menubar/datainfo_menu_button.gif new file mode 100755 index 0000000000000000000000000000000000000000..e6f3ea102f8406971320072dc02353d8ef8da5e2 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/datainfo_menu_button.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/datainfo_menu_button_hot.gif b/isis/src/docsys/assets/navigation/menubar/datainfo_menu_button_hot.gif new file mode 100755 index 0000000000000000000000000000000000000000..22b166cf1df8da7d60c3d2ece9bf7ed71994c6c1 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/datainfo_menu_button_hot.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/gallery_menu_bar.gif b/isis/src/docsys/assets/navigation/menubar/gallery_menu_bar.gif new file mode 100755 index 0000000000000000000000000000000000000000..0ce398a698654b363b9ef86694202f87bccc1851 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/gallery_menu_bar.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/gallery_menu_button.gif b/isis/src/docsys/assets/navigation/menubar/gallery_menu_button.gif new file mode 100755 index 0000000000000000000000000000000000000000..7d7c6c0fd98e471d42af6aa8f7cd9fa88a712c5b Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/gallery_menu_button.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/gallery_menu_button_hot.gif b/isis/src/docsys/assets/navigation/menubar/gallery_menu_button_hot.gif new file mode 100755 index 0000000000000000000000000000000000000000..c7bec3b4c019b2e185ac9bc29f9dfed04713f298 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/gallery_menu_button_hot.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/hottopics_menu_button.gif b/isis/src/docsys/assets/navigation/menubar/hottopics_menu_button.gif new file mode 100755 index 0000000000000000000000000000000000000000..b9863d7287f1207d97e8317fe75795e1a4cb6124 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/hottopics_menu_button.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/hottopics_menu_button_hot.gif b/isis/src/docsys/assets/navigation/menubar/hottopics_menu_button_hot.gif new file mode 100755 index 0000000000000000000000000000000000000000..7e555bf37330dc27ece210568abcc72c14a29bdd Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/hottopics_menu_button_hot.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/kidszone_menu_button.gif b/isis/src/docsys/assets/navigation/menubar/kidszone_menu_button.gif new file mode 100755 index 0000000000000000000000000000000000000000..97fc3bc095d1c0af503933e605e774e5afb7e4f0 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/kidszone_menu_button.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/kidszone_menu_button_dead.gif b/isis/src/docsys/assets/navigation/menubar/kidszone_menu_button_dead.gif new file mode 100755 index 0000000000000000000000000000000000000000..d96bcf4a81a8720fe6641d52bde2a509fdbfb2cb Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/kidszone_menu_button_dead.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/kidszone_menu_button_hot.gif b/isis/src/docsys/assets/navigation/menubar/kidszone_menu_button_hot.gif new file mode 100755 index 0000000000000000000000000000000000000000..10344659d1c77ba44deff779393e3412bad89e6b Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/kidszone_menu_button_hot.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/missions_menu_bar.gif b/isis/src/docsys/assets/navigation/menubar/missions_menu_bar.gif new file mode 100755 index 0000000000000000000000000000000000000000..7ab8c5619adfbbed4b567741359906ad8a26117e Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/missions_menu_bar.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/missions_menu_button.gif b/isis/src/docsys/assets/navigation/menubar/missions_menu_button.gif new file mode 100755 index 0000000000000000000000000000000000000000..5d1ab12837c7df77db7345812abd275947f89713 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/missions_menu_button.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/missions_menu_button_hot.gif b/isis/src/docsys/assets/navigation/menubar/missions_menu_button_hot.gif new file mode 100755 index 0000000000000000000000000000000000000000..6f57f250810e4004d191bc2ed1e007a1004cd871 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/missions_menu_button_hot.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/research_menu_bar.gif b/isis/src/docsys/assets/navigation/menubar/research_menu_bar.gif new file mode 100755 index 0000000000000000000000000000000000000000..fca986639d237c7fa1c205bb0441eaaea0a820a7 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/research_menu_bar.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/research_menu_button.gif b/isis/src/docsys/assets/navigation/menubar/research_menu_button.gif new file mode 100755 index 0000000000000000000000000000000000000000..c31f5bea4a5312e25b0e56f7b25b671158f05d30 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/research_menu_button.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/research_menu_button_hot.gif b/isis/src/docsys/assets/navigation/menubar/research_menu_button_hot.gif new file mode 100755 index 0000000000000000000000000000000000000000..5b0912c47f43bac7ed14879c87889fb2a7836aa6 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/research_menu_button_hot.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/search_menu_button.gif b/isis/src/docsys/assets/navigation/menubar/search_menu_button.gif new file mode 100755 index 0000000000000000000000000000000000000000..cff53245f1759402c21b1c5b0633be96080d8488 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/search_menu_button.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/search_menu_button_hot.gif b/isis/src/docsys/assets/navigation/menubar/search_menu_button_hot.gif new file mode 100755 index 0000000000000000000000000000000000000000..92320e9b3c06dd62f2c38afaf3b3a9aba01112e9 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/search_menu_button_hot.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/solarsystem_menu_bar.gif b/isis/src/docsys/assets/navigation/menubar/solarsystem_menu_bar.gif new file mode 100755 index 0000000000000000000000000000000000000000..01cf2e2ae616d2eac28dea0753f1a6ce11c456e9 Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/solarsystem_menu_bar.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/solarsystem_menu_button.gif b/isis/src/docsys/assets/navigation/menubar/solarsystem_menu_button.gif new file mode 100755 index 0000000000000000000000000000000000000000..5f98fa9ddfbac3dcdd8a793301d95d71bde084fa Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/solarsystem_menu_button.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/solarsystem_menu_button_hot.gif b/isis/src/docsys/assets/navigation/menubar/solarsystem_menu_button_hot.gif new file mode 100755 index 0000000000000000000000000000000000000000..ea001a87893c67179397193b00b228b2ecffbc8d Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/solarsystem_menu_button_hot.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/starfield_menu_bar.gif b/isis/src/docsys/assets/navigation/menubar/starfield_menu_bar.gif new file mode 100755 index 0000000000000000000000000000000000000000..de00a774958a59a16c892aa9139037a0cf84551d Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/starfield_menu_bar.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/technology_menu_bar.gif b/isis/src/docsys/assets/navigation/menubar/technology_menu_bar.gif new file mode 100755 index 0000000000000000000000000000000000000000..0a62071de71df47f5293bbf93098c76510611b4c Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/technology_menu_bar.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/technology_menu_button.gif b/isis/src/docsys/assets/navigation/menubar/technology_menu_button.gif new file mode 100755 index 0000000000000000000000000000000000000000..f76c9dcc4120617cf1acb6ce7442756e5e9d0f7f Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/technology_menu_button.gif differ diff --git a/isis/src/docsys/assets/navigation/menubar/technology_menu_button_hot.gif b/isis/src/docsys/assets/navigation/menubar/technology_menu_button_hot.gif new file mode 100755 index 0000000000000000000000000000000000000000..d98f502e3cb4b488e4004379609a609063126f8e Binary files /dev/null and b/isis/src/docsys/assets/navigation/menubar/technology_menu_button_hot.gif differ diff --git a/isis/src/docsys/assets/scripts/feed2js/build.php b/isis/src/docsys/assets/scripts/feed2js/build.php new file mode 100644 index 0000000000000000000000000000000000000000..c559556428b3ce247fa06a2340dc8f3872d31570 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/build.php @@ -0,0 +1,213 @@ +')) { + $src = preg_replace("/(\)/si", "SCRIPT DELETED", "$src"); + die("Warning! Attempt to inject javascript detected. Aborted and tracking log updated."); +} + + +// check for status of submit buttons + $generate = (isset($_GET['generate'])) ? $_GET['generate'] : ''; + if (isset($generate)) $generate = $_GET['generate']; + +// update to full descriptions for html turned on + if ($html=='a') $desc = 0; + +// build parameter string for the feed2js url + $options = ''; + if ($chan != 'n') $options .= "&chan=$chan"; + if ($num != 0) $options .= "&num=$num"; + if ($desc != 0) $options .= "&desc=$desc"; + if ($date != 'n') $options .= "&date=$date"; + if ($tz != 'feed') $options .= "&tz=$tz"; + if ($targ != 'n') $options .= "&targ=$targ"; + if ($html != 'n') $html_options = "&html=$html"; + if ($utf == 'y') $options .= '&utf=y'; + if ($rss_box_id != '') $options .= "&css=$rss_box_id"; + if ($pc == 'y') $options .= '&pc=y'; + + + +if ($generate) { + // URLs for a preview or a generated feed link + + $my_dir = 'http://' . $_SERVER['SERVER_NAME'] . dirname($_SERVER['PHP_SELF']); + + $rss_str = "$my_dir/feed2js.php?src=" . urlencode($src) . htmlentities($options . $html_options); + + $noscript_rss_str = "$my_dir/feed2js.php?src=" . urlencode($src) . htmlentities($options . '&html=y'); + +} + +?> + + + + + Cut n' Paste JavaScript RSS Feed + + + + + + + +
    +

    Feed2JS Build JavaScript and Preview

    +

    The tool below will help you format a feed's display with the information you want to use on your web site. All you need to enter is the URL for the RSS source, and select the desired options below.

    + +

    First, be sure to preview the feed to verify the content and format. Once the content is displayed how you like, just use the generate javascript button to get your code. Once the content looks okay, move on to our style tool to make it pretty.

    + + + + +

    Get Your Code Here

    +

    Below is the code you need to copy and paste to your own web page to include this RSS feed. The NOSCRIPT tag provides a link to a HTML display of the feed for users who may not have JavaScript enabled.

    +
    +cut and paste javascript:
    +
    + + + + +
    + +

    URL Enter the web address of the RSS Feed (must be in http:// format, not feed://)
    + +
    +Note: Please verify the URL of your feed (make sure it presents raw RSS) and check that it is valid before using this form. +

    + +
    +

    Show n' Tell!

    +
    +
    + +
    +
    + + +

    Show channel? (yes/no/title) Display information about the publisher of the feed (yes=show the title and description; title= display title only, no=do not display anything)
    + /> yes /> title /> no

    + +

    Number of items to display. Enter the number of items to be displayed (enter 0 to show all available)
    +

    + +

    Show/Hide item descriptions? How much? (0=no descriptions; 1=show full description text; n>1 = display first n characters of description; n=-1 do not link item title, just display item contents)
    +

    + +

    Use HTML in item display? ("yes" = use HTML from feed and the full item descriptions will be used, ignoring any character limit set above; "no" = output is text-only formatted by CSS; "preserve paragraphs" = no HTML but convert all RETURN/linefeeds to <br> to preserve paragraph breaks)
    +/> yes /> no /> preserve paragraphs only

    + +

    Show item posting date? (yes/no) Display the time and date for each item.
    +/> yes /> no

    + +

    Time Zone Offset (+n/-n/'feed') Date and timer are converted to GMT time; to have display in local time, you must enter an offset from your current local time to (GMT). If your local time is 5 hours before GMT, enter -5. If your local time is 8 hours past GMT, enter +8. Fractional offsets such as +10:30 must be entered as decimal +10.5. If you prefer to just display the date is recorded in the RSS, use a value = feed
    +

    + +

    Target links in the new window? (n="no, links open the same page", y="yes, open links in a new window", "xxxx" = open links in a frame named 'xxxx', 'popup' = use a JavaScript function popupfeed() to open in new window)
    +

    + +

    UTF-8 Character Encoding
    Required for many non-western language web pages and also may help if you see strange characters replacing quotes in your output (see help pages for more information).
    + /> use UTF-8 character encoding +

    + +

    Podcast enclosures
    For RSS 2.0 feeds with enclosures, display link to media files
    + /> yes + /> no +

    + +

    Custom CSS Class (advanced users)
    Use to create different styles for multiple feeds per page. Specify class for content as rss-box-XXXX where XXXX is the value entered below. Style sheets must be created in accordance with Feed2JS guidelines.
    +

    + +
    +
    + + + + + diff --git a/isis/src/docsys/assets/scripts/feed2js/feed2js.php b/isis/src/docsys/assets/scripts/feed2js/feed2js.php new file mode 100644 index 0000000000000000000000000000000000000000..93b099a0a0395370ffd29915fd6b1f8a8bf6a126 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/feed2js.php @@ -0,0 +1,316 @@ +')) { + $src = preg_replace("/(\)/si", "SCRIPT DELETED", "$src"); + die("Warning! Attempt to inject javascript detected. Aborted and tracking log updated."); +} + + +// MAGPIE SETUP ---------------------------------------------------- +// access configuration settings +require_once('feed2js_config.php'); + +// check for utf encoding type +$utf = (isset($_GET['utf'])) ? $_GET['utf'] : 'n'; + +if ($utf == 'y') { + define('MAGPIE_CACHE_DIR', MAGPIE_DIR . 'cache_utf8/'); + // chacrater encoding + define('MAGPIE_OUTPUT_ENCODING', 'UTF-8'); + +} else { + define('MAGPIE_CACHE_DIR', MAGPIE_DIR . 'cache/'); +} + +// GET VARIABLES --------------------------------------------- +// retrieve values from posted variables + +// flag to show channel info +$chan = (isset($_GET['chan'])) ? $_GET['chan'] : 'n'; + +// variable to limit number of displayed items; default = 0 (show all, 100 is a safe bet to list a big list of feeds) + +$num = (isset($_GET['num'])) ? $_GET['num'] : 0; +if ($num==0) $num = 100; + +// indicator to show item description, 0 = no; 1=all; n>1 = characters to display +// values of -1 indicate to displa item without the title as a link +// (default=0) +$desc = (isset($_GET['desc'])) ? $_GET['desc'] : 0; + +// flag to show date of posts, values: no/yes (default=no) +$date = (isset($_GET['date'])) ? $_GET['date'] : 'n'; + +// time zone offset for making local time, +// e.g. +7, =-10.5; 'feed' = print the time string in the RSS w/o conversion +$tz = (isset($_GET['tz'])) ? $_GET['tz'] : 'feed'; + + +// flag to open target window in new window; n = same window, y = new window, +// other = targeted window, 'popup' = call JavaScript function popupfeed() to display +// in new window (default is n) + +$targ = (isset($_GET['targ'])) ? $_GET['targ'] : 'n'; +if ($targ == 'n') { + $target_window = ' target="_self"'; +} elseif ($targ == 'y' ) { + $target_window = ' target="_blank"'; +} elseif ($targ == 'popup') { + $target_window = ' onClick="popupfeed(this.href);return false"'; +} else { + $target_window = ' target="' . $targ . '"'; +} + +// flag to show feed as full html output rather than JavaScript, used for alternative +// views for JavaScript-less users. +// y = display html only for non js browsers (NO LONGER USED) +// n = default (JavaScript view) +// a = display javascript output but allow HTML +// p = display text only items but convert linefeeds to BR tags + +// default setting for no conversion of linebreaks +$html = (isset($_GET['html'])) ? $_GET['html'] : 'n'; + +$br = ' '; +if ($html == 'a') { + $desc = 1; +} elseif ($html == 'p') { + $br = '
    '; +} + +// optional parameter to use different class for the CSS container +$rss_box_id = (isset($_GET['css'])) ? '-' . $_GET['css'] : ''; + +// optional parameter to use different class for the CSS container +$play_podcast = (isset($_GET['pc'])) ? $_GET['pc'] : 'n'; + + +// PARSE FEED and GENERATE OUTPUT ------------------------------- +// This is where it all happens! + +$rss = @fetch_rss( $src ); + +// begin javascript output string for channel info +$str= "document.write('
    ');\n"; + + +// no feed found by magpie, return error statement +if (!$rss) { + $str.= "document.write('

    $script_msgError: Feed failed! Causes may be (1) No data found for RSS feed $src; (2) There are no items are available for this feed; (3) The RSS feed does not validate.

    Please verify that the URL $src works first in your browser and that the feed passes a validator test.

    ');\n"; + + +} else { + + + // Create CONNECTION CONFIRM + // create output string for local javascript variable to let + // browser know that the server has been contacted + $feedcheck_str = "feed2js_ck = true;\n\n"; + + // we have a feed, so let's process + if ($chan == 'y') { + + // output channel title and description + $str.= "document.write('

    channel['link']) . '"' . $target_window . ">" . addslashes(strip_returns($rss->channel['title'])) . "
    " . addslashes(strip_returns(strip_tags($rss->channel['description']))) . "

    ');\n"; + + } elseif ($chan == 'title') { + // output title only + $str.= "document.write('

    channel['link']) . '"' . $target_window . ">" . addslashes(strip_returns($rss->channel['title'])) . "

    ');\n"; + + } + + // begin item listing + $str.= "document.write('
      ');\n"; + + // Walk the items and process each one + $all_items = array_slice($rss->items, 0, $num); + + foreach ( $all_items as $item ) { + + // set defaults thanks RPFK + if (!isset($item['summary'])) $item['summary'] = ''; + $more_link = ''; + + if ($item['link']) { + // link url + $my_url = addslashes($item['link']); + } elseif ($item['guid']) { + // feeds lacking item -> link + $my_url = ($item['guid']); + } + + + if ($desc < 0) { + $str.= "document.write('
    • ');\n"; + + } elseif ($item['title']) { + // format item title + $my_title = addslashes(strip_returns($item['title'])); + + // create a title attribute. thanks Seb! + $title_str = substr(addslashes(strip_returns(strip_tags((htmlspecialchars($item['summary']))))), 0, 255) . '...'; + + // write the title strng + $str.= "document.write('
    • ' . $my_title . "
      ');\n"; + + } else { + // if no title, build a link to tag on the description + $str.= "document.write('
    • ');\n"; + $more_link = " «details»"; + } + + // print out date if option indicated + + if ($date == 'y') { + + if ($tz == 'feed') { + // echo the date/time stamp reported in the feed + + if ($item['pubdate'] != '') { + // RSS 2.0 is alreayd formatted, so just use it + $pretty_date = $item['pubdate']; + } elseif ($item['published'] != "") { + // ATOM 1.0 format, remove the "T" and "Z" and the time zone offset + $pretty_date = str_replace("T", " ", $item['published']); + $pretty_date= str_replace("Z", " ", $pretty_date); + + } elseif ($item['issued'] != "") { + // ATOM 0.3 format, remove the "T" and "Z" and the time zone offset + $pretty_date = str_replace("T", " ", $item['issued']); + $pretty_date= str_replace("Z", " ", $pretty_date); + } elseif ( $item['dc']['date'] != "") { + // RSS 1.0, remove the "T" and the time zone offset + $pretty_date = str_replace("T", " ", $item['dc']['date']); + $pretty_date = substr($pretty_date, 0,-6); + } else { + + // no time/date stamp, + $pretty_date = 'n/a'; + } + + } else { + // convert to local time via conversion to GMT + offset + + // adjust local server time to GMT and then adjust time according to user + // entered offset. + + $pretty_date = date($date_format, $item['date_timestamp'] - $tz_offset + $tz * 3600); + + } + + $str.= "document.write('$pretty_date
      ');\n"; + } + + // link to podcast media if availavle + + if ($play_podcast == 'y' and is_array($item['enclosure'])) { + $str.= "document.write('
      ');\n"; + for ($i = 0; $i < count($item['enclosure']); $i++) { + + // display only if enclosure is a valid URL + //if (strpos($item['enclosure'][$i]['url'], 'http://')!=0) { + $str.= "document.write('Play " . substr(trim($item['enclosure'][$i]['url']), -3) . " ');\n"; + //} + + } + + $str.= "document.write('
      ');\n"; + + } + + + // output description of item if desired + if ($desc) { + + // Atom/encocded content support (thanks David Carter-Tod) + + if ($item['content']['encoded']) { + $my_blurb = html_entity_decode ( $item['content']['encoded'], ENT_NOQUOTES); + + + } else { + $my_blurb = $item['summary']; + } + + // strip html + if ($html != 'a') $my_blurb = strip_tags($my_blurb); + + // trim descriptions + if ($desc > 1) { + + // display specified substring numbers of chars; + // html is stripped to prevent cut off tags + $my_blurb = substr($my_blurb, 0, $desc) . '...'; + } + + + $str.= "document.write('" . addslashes(strip_returns($my_blurb, $br)) . "');\n"; + + } + + $str.= "document.write('$more_link
    • ');\n"; + } + + + $str .= "document.write('
    ');\n"; + +} + +// Render as JavaScript +// START OUTPUT +// headers to tell browser this is a JS file +if ($rss) header("Content-type: application/x-javascript"); + +// Spit out the results as the series of JS statements +echo $feedcheck_str . $str; + + +?> diff --git a/isis/src/docsys/assets/scripts/feed2js/feed2js_config.php b/isis/src/docsys/assets/scripts/feed2js/feed2js_config.php new file mode 100644 index 0000000000000000000000000000000000000000..6e2f4115569a6f324f39541703cfd5c8b219f675 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/feed2js_config.php @@ -0,0 +1,66 @@ + \ No newline at end of file diff --git a/isis/src/docsys/assets/scripts/feed2js/feed2php.inc b/isis/src/docsys/assets/scripts/feed2js/feed2php.inc new file mode 100644 index 0000000000000000000000000000000000000000..0b9ae69f3036eee380de44a42f3c667869f4fc34 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/feed2php.inc @@ -0,0 +1,300 @@ +1 = characters to display +// values of -1 indicate to display item without the title as a link +// (default=0) +if (!isset($desc)) $desc = 0; + +// flag to show date of posts, values: no/yes (default=no) +$date = (isset($date)) ? $date : 'n'; + +// time zone offset for making local time, +// e.g. +7, =-10.5; 'feed' = print the time string in the RSS w/o conversion +$tz = (isset($tz)) ? $tz : 'feed'; + +// flag to open target window in new window; n = same window, y = new window, +// other = targeted window, 'popup' = call JavaScript function popupfeed to display +// in new window +// (default is n) + +if (!isset($targ)) $targ = 'n'; + +if ($targ == 'n') { + $target_window = ' target="_self"'; +} elseif ($targ == 'y' ) { + $target_window = ' target="_blank"'; +} elseif ($targ == 'popup') { + $target_window = ' onClick="popupfeed(this.href);return false"'; +} else { + $target_window = ' target="' . $targ . '"'; +} + +// flag to show feed as full html output rather than JavaScript, used for alternative +// views for JavaScript-less users. +// y = display html only for non js browsers +// n = default (JavaScript view) +// a = display javascript output but allow HTML +// p = display text only items but convert linefeeds to BR tags + +// default setting for no conversion of linebreaks +if (!isset($html)) $html = 'n'; + +$br = ' '; +if ($html == 'a') { + $desc = 1; +} elseif ($html == 'p') { + $br = '
    '; +} + +// optional parameter to use different class for the CSS container +if (isset($css)) { + $rss_box_id = '-' . $css; +} else { + $rss_box_id = ''; +} + +if (isset($pc)) { + $play_podcast = $pc; +} else { + $play_podcast = 'n'; +} + + +// PARSE FEED and GENERATE OUTPUT ------------------------------- +// This is where it all happens! + +// Fetch the data, thanks Magpie +$rss = @fetch_rss( $src ); + +// begin javascript output string for channel info +$str = "
    \n"; + +// no feed found by magpie, return error statement +if (!$rss) { + // error, nothing grabbed + $str.= "

    Error: Feed failed! Causes may be (1) No data found for RSS feed $src; (2) There are no items are available for this feed; (3) The RSS feed does not validate.

    Please verify that the URL $src works first in your browser and that the feed passes a validator test.

    \n"; +} else { + + if ($chan == 'y') { + + // output channel title and description + $str.= "

    channel['link']) . "\" target=\"" . $target_window . "\">" . strip_returns($rss->channel['title']) . "
    " . strip_returns($rss->channel['description']) . "

    \n"; + + } elseif ($chan == 'title') { + // output title only + $str.= "

    channel['link']) . "\" target=\"" . $target_window . "\">" . strip_returns($rss->channel['title']) . "

    \n"; + + } + + // begin item listing + $str.= "
      \n"; + + + // Walk the items and process each one + $all_items = array_slice($rss->items, 0, $num); + + foreach ( $all_items as $item ) { + + if ($item['link']) { + // link url + $my_url = $item['link']; + } elseif ($item['guid']) { + // feeds lacking item -> link + $my_url = ($item['guid']); + } + + + if ($desc < 0) { + $str.= "
    • \n"; + + } elseif ($item['title']) { + // format item title + $my_title = strip_returns($item['title']); + + // create a title attribute. thanks Seb! + $title_str = substr(strip_returns(strip_tags($item['summary'])), 0, 255) . '...'; + + // write the item + $str.= "
    • " . $my_title . "
      \n"; + + } else { + // if no title, build a link to tag on the description + $str.= "
    • \n"; + $more_link = " «details»"; + } + + + // print out date if option indicated and feed returns a value. + // Use the new date_timestamp function in Magpie 0.71 + if ($date == 'y') { + if ($tz == 'feed') { + // echo the date/time stamp reported in the feed + + if ($item['pubdate'] != '') { + // RSS 2.0 is already formatted, so just use it + $pretty_date = 'published on ' . $item['pubdate']; + } elseif ($item['published'] != "") { + // ATOM 1.0 format, remove the "T" and "Z" and the time zone offset + $pretty_date = str_replace("T", " ", $item['published']); + $pretty_date= 'published on ' . str_replace("Z", " ", $pretty_date); + + } elseif ($item['issued'] != "") { + // ATOM 0.3 format, remove the "T" and "Z" and the time zone offset + $pretty_date = str_replace("T", " ", $item['issued']); + $pretty_date= 'published on ' . str_replace("Z", " ", $pretty_date); + } elseif ( $item['dc']['date'] != "") { + // RSS 1.0, remove the "T" and the time zone offset + $pretty_date = str_replace("T", " ", $item['dc']['date']); + $pretty_date = 'published on ' . substr($pretty_date, 0,-6); + } else { + + // no time/date stamp, just use the server time + $pretty_date = 'published date n/a'; + } + + } else { + // convert to local time via conversion to GMT + offset + + // adjust local server time to GMT and then adjust time according to user + // entered offset. + + $pretty_date = 'published on ' . date($date_format, $item['date_timestamp'] - $tz_offset + $tz * 3600); + + } + + + + $str.= "$pretty_date
      \n"; + } + + // link to podcast media if available + + if ($play_podcast == 'y' and is_array($item['enclosure'])) { + $str.= "
      Media: "; + + for ($i = 0; $i < count($item['enclosure']); $i++) { + + // display only if enclosure is a valid URL + //if (strpos($item['enclosure'][$i]['url'], 'http://')!=0) { + $str.= "Play " . substr(trim($item['enclosure'][$i]['url']), -3) . " "; + //} + + } + $str.= "
      "; + + } + + + + + // output description of item if desired + if ($desc) { + + // Atom/encoded content support (thanks David Carter-Tod) + + if ($item['content']['encoded']) { + $my_blurb = html_entity_decode ( $item['content']['encoded'], ENT_NOQUOTES); + + } else { + $my_blurb = $item['summary']; + } + + + + // strip html + if ($html != 'a') $my_blurb = strip_tags($my_blurb); + + // trim descriptions + if ($desc > 1) { + + // display specified substring numbers of chars; + // html is stripped to prevent cut off tags + $my_blurb = substr($my_blurb, 0, $desc) . '...'; + } + + $str.= strip_returns($my_blurb, $br) . "\n"; + } + + $str.= "$more_link
    • \n"; + } +} + +$str .= "
    \n"; +echo $str; + +?> diff --git a/isis/src/docsys/assets/scripts/feed2js/footer b/isis/src/docsys/assets/scripts/feed2js/footer new file mode 100644 index 0000000000000000000000000000000000000000..8d6f68bcc7d2cd9d1c65b8eaa12cd5e5db35cedb --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/footer @@ -0,0 +1,9 @@ + diff --git a/isis/src/docsys/assets/scripts/feed2js/magpie/extlib/Snoopy.class.inc b/isis/src/docsys/assets/scripts/feed2js/magpie/extlib/Snoopy.class.inc new file mode 100755 index 0000000000000000000000000000000000000000..531161059d7630be85f43119224fc7b58cc48c73 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/magpie/extlib/Snoopy.class.inc @@ -0,0 +1,1250 @@ + +Copyright (c): 1999-2008 New Digital Group, all rights reserved +Version: 1.2.4 + + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +You may contact the author of Snoopy by e-mail at: +monte@ohrt.com + +The latest version of Snoopy can be obtained from: +http://snoopy.sourceforge.net/ + +*************************************************/ + +class Snoopy +{ + /**** Public variables ****/ + + /* user definable vars */ + + var $host = "www.php.net"; // host name we are connecting to + var $port = 80; // port we are connecting to + var $proxy_host = ""; // proxy host to use + var $proxy_port = ""; // proxy port to use + var $proxy_user = ""; // proxy user to use + var $proxy_pass = ""; // proxy password to use + + var $agent = "Snoopy v1.2.4"; // agent we masquerade as + var $referer = ""; // referer info to pass + var $cookies = array(); // array of cookies to pass + // $cookies["username"]="joe"; + var $rawheaders = array(); // array of raw headers to send + // $rawheaders["Content-type"]="text/html"; + + var $maxredirs = 5; // http redirection depth maximum. 0 = disallow + var $lastredirectaddr = ""; // contains address of last redirected address + var $offsiteok = true; // allows redirection off-site + var $maxframes = 0; // frame content depth maximum. 0 = disallow + var $expandlinks = true; // expand links to fully qualified URLs. + // this only applies to fetchlinks() + // submitlinks(), and submittext() + var $passcookies = true; // pass set cookies back through redirects + // NOTE: this currently does not respect + // dates, domains or paths. + + var $user = ""; // user for http authentication + var $pass = ""; // password for http authentication + + // http accept types + var $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; + + var $results = ""; // where the content is put + + var $error = ""; // error messages sent here + var $response_code = ""; // response code returned from server + var $headers = array(); // headers returned from server sent here + var $maxlength = 500000; // max return data length (body) + var $read_timeout = 0; // timeout on read operations, in seconds + // supported only since PHP 4 Beta 4 + // set to 0 to disallow timeouts + var $timed_out = false; // if a read operation timed out + var $status = 0; // http request status + + var $temp_dir = "/tmp"; // temporary directory that the webserver + // has permission to write to. + // under Windows, this should be C:\temp + + var $curl_path = "/usr/local/bin/curl"; + // Snoopy will use cURL for fetching + // SSL content if a full system path to + // the cURL binary is supplied here. + // set to false if you do not have + // cURL installed. See http://curl.haxx.se + // for details on installing cURL. + // Snoopy does *not* use the cURL + // library functions built into php, + // as these functions are not stable + // as of this Snoopy release. + + /**** Private variables ****/ + + var $_maxlinelen = 4096; // max line length (headers) + + var $_httpmethod = "GET"; // default http request method + var $_httpversion = "HTTP/1.0"; // default http request version + var $_submit_method = "POST"; // default submit method + var $_submit_type = "application/x-www-form-urlencoded"; // default submit type + var $_mime_boundary = ""; // MIME boundary for multipart/form-data submit type + var $_redirectaddr = false; // will be set if page fetched is a redirect + var $_redirectdepth = 0; // increments on an http redirect + var $_frameurls = array(); // frame src urls + var $_framedepth = 0; // increments on frame depth + + var $_isproxy = false; // set if using a proxy server + var $_fp_timeout = 30; // timeout for socket connection + +/*======================================================================*\ + Function: fetch + Purpose: fetch the contents of a web page + (and possibly other protocols in the + future like ftp, nntp, gopher, etc.) + Input: $URI the location of the page to fetch + Output: $this->results the output text from the fetch +\*======================================================================*/ + + function fetch($URI) + { + + //preg_match("|^([^:]+)://([^:/]+)(:[\d]+)*(.*)|",$URI,$URI_PARTS); + $URI_PARTS = parse_url($URI); + if (!empty($URI_PARTS["user"])) + $this->user = $URI_PARTS["user"]; + if (!empty($URI_PARTS["pass"])) + $this->pass = $URI_PARTS["pass"]; + if (empty($URI_PARTS["query"])) + $URI_PARTS["query"] = ''; + if (empty($URI_PARTS["path"])) + $URI_PARTS["path"] = ''; + + switch(strtolower($URI_PARTS["scheme"])) + { + case "http": + $this->host = $URI_PARTS["host"]; + if(!empty($URI_PARTS["port"])) + $this->port = $URI_PARTS["port"]; + if($this->_connect($fp)) + { + if($this->_isproxy) + { + // using proxy, send entire URI + $this->_httprequest($URI,$fp,$URI,$this->_httpmethod); + } + else + { + $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); + // no proxy, send only the path + $this->_httprequest($path, $fp, $URI, $this->_httpmethod); + } + + $this->_disconnect($fp); + + if($this->_redirectaddr) + { + /* url was redirected, check if we've hit the max depth */ + if($this->maxredirs > $this->_redirectdepth) + { + // only follow redirect if it's on this site, or offsiteok is true + if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) + { + /* follow the redirect */ + $this->_redirectdepth++; + $this->lastredirectaddr=$this->_redirectaddr; + $this->fetch($this->_redirectaddr); + } + } + } + + if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) + { + $frameurls = $this->_frameurls; + $this->_frameurls = array(); + + while(list(,$frameurl) = each($frameurls)) + { + if($this->_framedepth < $this->maxframes) + { + $this->fetch($frameurl); + $this->_framedepth++; + } + else + break; + } + } + } + else + { + return false; + } + return true; + break; + case "https": + if(!$this->curl_path) + return false; + if(function_exists("is_executable")) + if (!is_executable($this->curl_path)) + return false; + $this->host = $URI_PARTS["host"]; + if(!empty($URI_PARTS["port"])) + $this->port = $URI_PARTS["port"]; + if($this->_isproxy) + { + // using proxy, send entire URI + $this->_httpsrequest($URI,$URI,$this->_httpmethod); + } + else + { + $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); + // no proxy, send only the path + $this->_httpsrequest($path, $URI, $this->_httpmethod); + } + + if($this->_redirectaddr) + { + /* url was redirected, check if we've hit the max depth */ + if($this->maxredirs > $this->_redirectdepth) + { + // only follow redirect if it's on this site, or offsiteok is true + if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) + { + /* follow the redirect */ + $this->_redirectdepth++; + $this->lastredirectaddr=$this->_redirectaddr; + $this->fetch($this->_redirectaddr); + } + } + } + + if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) + { + $frameurls = $this->_frameurls; + $this->_frameurls = array(); + + while(list(,$frameurl) = each($frameurls)) + { + if($this->_framedepth < $this->maxframes) + { + $this->fetch($frameurl); + $this->_framedepth++; + } + else + break; + } + } + return true; + break; + default: + // not a valid protocol + $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n'; + return false; + break; + } + return true; + } + +/*======================================================================*\ + Function: submit + Purpose: submit an http form + Input: $URI the location to post the data + $formvars the formvars to use. + format: $formvars["var"] = "val"; + $formfiles an array of files to submit + format: $formfiles["var"] = "/dir/filename.ext"; + Output: $this->results the text output from the post +\*======================================================================*/ + + function submit($URI, $formvars="", $formfiles="") + { + unset($postdata); + + $postdata = $this->_prepare_post_body($formvars, $formfiles); + + $URI_PARTS = parse_url($URI); + if (!empty($URI_PARTS["user"])) + $this->user = $URI_PARTS["user"]; + if (!empty($URI_PARTS["pass"])) + $this->pass = $URI_PARTS["pass"]; + if (empty($URI_PARTS["query"])) + $URI_PARTS["query"] = ''; + if (empty($URI_PARTS["path"])) + $URI_PARTS["path"] = ''; + + switch(strtolower($URI_PARTS["scheme"])) + { + case "http": + $this->host = $URI_PARTS["host"]; + if(!empty($URI_PARTS["port"])) + $this->port = $URI_PARTS["port"]; + if($this->_connect($fp)) + { + if($this->_isproxy) + { + // using proxy, send entire URI + $this->_httprequest($URI,$fp,$URI,$this->_submit_method,$this->_submit_type,$postdata); + } + else + { + $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); + // no proxy, send only the path + $this->_httprequest($path, $fp, $URI, $this->_submit_method, $this->_submit_type, $postdata); + } + + $this->_disconnect($fp); + + if($this->_redirectaddr) + { + /* url was redirected, check if we've hit the max depth */ + if($this->maxredirs > $this->_redirectdepth) + { + if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr)) + $this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]); + + // only follow redirect if it's on this site, or offsiteok is true + if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) + { + /* follow the redirect */ + $this->_redirectdepth++; + $this->lastredirectaddr=$this->_redirectaddr; + if( strpos( $this->_redirectaddr, "?" ) > 0 ) + $this->fetch($this->_redirectaddr); // the redirect has changed the request method from post to get + else + $this->submit($this->_redirectaddr,$formvars, $formfiles); + } + } + } + + if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) + { + $frameurls = $this->_frameurls; + $this->_frameurls = array(); + + while(list(,$frameurl) = each($frameurls)) + { + if($this->_framedepth < $this->maxframes) + { + $this->fetch($frameurl); + $this->_framedepth++; + } + else + break; + } + } + + } + else + { + return false; + } + return true; + break; + case "https": + if(!$this->curl_path) + return false; + if(function_exists("is_executable")) + if (!is_executable($this->curl_path)) + return false; + $this->host = $URI_PARTS["host"]; + if(!empty($URI_PARTS["port"])) + $this->port = $URI_PARTS["port"]; + if($this->_isproxy) + { + // using proxy, send entire URI + $this->_httpsrequest($URI, $URI, $this->_submit_method, $this->_submit_type, $postdata); + } + else + { + $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); + // no proxy, send only the path + $this->_httpsrequest($path, $URI, $this->_submit_method, $this->_submit_type, $postdata); + } + + if($this->_redirectaddr) + { + /* url was redirected, check if we've hit the max depth */ + if($this->maxredirs > $this->_redirectdepth) + { + if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr)) + $this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]); + + // only follow redirect if it's on this site, or offsiteok is true + if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) + { + /* follow the redirect */ + $this->_redirectdepth++; + $this->lastredirectaddr=$this->_redirectaddr; + if( strpos( $this->_redirectaddr, "?" ) > 0 ) + $this->fetch($this->_redirectaddr); // the redirect has changed the request method from post to get + else + $this->submit($this->_redirectaddr,$formvars, $formfiles); + } + } + } + + if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) + { + $frameurls = $this->_frameurls; + $this->_frameurls = array(); + + while(list(,$frameurl) = each($frameurls)) + { + if($this->_framedepth < $this->maxframes) + { + $this->fetch($frameurl); + $this->_framedepth++; + } + else + break; + } + } + return true; + break; + + default: + // not a valid protocol + $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n'; + return false; + break; + } + return true; + } + +/*======================================================================*\ + Function: fetchlinks + Purpose: fetch the links from a web page + Input: $URI where you are fetching from + Output: $this->results an array of the URLs +\*======================================================================*/ + + function fetchlinks($URI) + { + if ($this->fetch($URI)) + { + if($this->lastredirectaddr) + $URI = $this->lastredirectaddr; + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + $this->results[$x] = $this->_striplinks($this->results[$x]); + } + else + $this->results = $this->_striplinks($this->results); + + if($this->expandlinks) + $this->results = $this->_expandlinks($this->results, $URI); + return true; + } + else + return false; + } + +/*======================================================================*\ + Function: fetchform + Purpose: fetch the form elements from a web page + Input: $URI where you are fetching from + Output: $this->results the resulting html form +\*======================================================================*/ + + function fetchform($URI) + { + + if ($this->fetch($URI)) + { + + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + $this->results[$x] = $this->_stripform($this->results[$x]); + } + else + $this->results = $this->_stripform($this->results); + + return true; + } + else + return false; + } + + +/*======================================================================*\ + Function: fetchtext + Purpose: fetch the text from a web page, stripping the links + Input: $URI where you are fetching from + Output: $this->results the text from the web page +\*======================================================================*/ + + function fetchtext($URI) + { + if($this->fetch($URI)) + { + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + $this->results[$x] = $this->_striptext($this->results[$x]); + } + else + $this->results = $this->_striptext($this->results); + return true; + } + else + return false; + } + +/*======================================================================*\ + Function: submitlinks + Purpose: grab links from a form submission + Input: $URI where you are submitting from + Output: $this->results an array of the links from the post +\*======================================================================*/ + + function submitlinks($URI, $formvars="", $formfiles="") + { + if($this->submit($URI,$formvars, $formfiles)) + { + if($this->lastredirectaddr) + $URI = $this->lastredirectaddr; + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + { + $this->results[$x] = $this->_striplinks($this->results[$x]); + if($this->expandlinks) + $this->results[$x] = $this->_expandlinks($this->results[$x],$URI); + } + } + else + { + $this->results = $this->_striplinks($this->results); + if($this->expandlinks) + $this->results = $this->_expandlinks($this->results,$URI); + } + return true; + } + else + return false; + } + +/*======================================================================*\ + Function: submittext + Purpose: grab text from a form submission + Input: $URI where you are submitting from + Output: $this->results the text from the web page +\*======================================================================*/ + + function submittext($URI, $formvars = "", $formfiles = "") + { + if($this->submit($URI,$formvars, $formfiles)) + { + if($this->lastredirectaddr) + $URI = $this->lastredirectaddr; + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + { + $this->results[$x] = $this->_striptext($this->results[$x]); + if($this->expandlinks) + $this->results[$x] = $this->_expandlinks($this->results[$x],$URI); + } + } + else + { + $this->results = $this->_striptext($this->results); + if($this->expandlinks) + $this->results = $this->_expandlinks($this->results,$URI); + } + return true; + } + else + return false; + } + + + +/*======================================================================*\ + Function: set_submit_multipart + Purpose: Set the form submission content type to + multipart/form-data +\*======================================================================*/ + function set_submit_multipart() + { + $this->_submit_type = "multipart/form-data"; + } + + +/*======================================================================*\ + Function: set_submit_normal + Purpose: Set the form submission content type to + application/x-www-form-urlencoded +\*======================================================================*/ + function set_submit_normal() + { + $this->_submit_type = "application/x-www-form-urlencoded"; + } + + + + +/*======================================================================*\ + Private functions +\*======================================================================*/ + + +/*======================================================================*\ + Function: _striplinks + Purpose: strip the hyperlinks from an html document + Input: $document document to strip. + Output: $match an array of the links +\*======================================================================*/ + + function _striplinks($document) + { + preg_match_all("'<\s*a\s.*?href\s*=\s* # find ]+)) # if quote found, match up to next matching + # quote, otherwise match up to next space + 'isx",$document,$links); + + + // catenate the non-empty matches from the conditional subpattern + + while(list($key,$val) = each($links[2])) + { + if(!empty($val)) + $match[] = $val; + } + + while(list($key,$val) = each($links[3])) + { + if(!empty($val)) + $match[] = $val; + } + + // return the links + return $match; + } + +/*======================================================================*\ + Function: _stripform + Purpose: strip the form elements from an html document + Input: $document document to strip. + Output: $match an array of the links +\*======================================================================*/ + + function _stripform($document) + { + preg_match_all("'<\/?(FORM|INPUT|SELECT|TEXTAREA|(OPTION))[^<>]*>(?(2)(.*(?=<\/?(option|select)[^<>]*>[\r\n]*)|(?=[\r\n]*))|(?=[\r\n]*))'Usi",$document,$elements); + + // catenate the matches + $match = implode("\r\n",$elements[0]); + + // return the links + return $match; + } + + + +/*======================================================================*\ + Function: _striptext + Purpose: strip the text from an html document + Input: $document document to strip. + Output: $text the resulting text +\*======================================================================*/ + + function _striptext($document) + { + + // I didn't use preg eval (//e) since that is only available in PHP 4.0. + // so, list your entities one by one here. I included some of the + // more common ones. + + $search = array("']*?>.*?'si", // strip out javascript + "'<[\/\!]*?[^<>]*?>'si", // strip out html tags + "'([\r\n])[\s]+'", // strip out white space + "'&(quot|#34|#034|#x22);'i", // replace html entities + "'&(amp|#38|#038|#x26);'i", // added hexadecimal values + "'&(lt|#60|#060|#x3c);'i", + "'&(gt|#62|#062|#x3e);'i", + "'&(nbsp|#160|#xa0);'i", + "'&(iexcl|#161);'i", + "'&(cent|#162);'i", + "'&(pound|#163);'i", + "'&(copy|#169);'i", + "'&(reg|#174);'i", + "'&(deg|#176);'i", + "'&(#39|#039|#x27);'", + "'&(euro|#8364);'i", // europe + "'&a(uml|UML);'", // german + "'&o(uml|UML);'", + "'&u(uml|UML);'", + "'&A(uml|UML);'", + "'&O(uml|UML);'", + "'&U(uml|UML);'", + "'ß'i", + ); + $replace = array( "", + "", + "\\1", + "\"", + "&", + "<", + ">", + " ", + chr(161), + chr(162), + chr(163), + chr(169), + chr(174), + chr(176), + chr(39), + chr(128), + "ä", + "ö", + "ü", + "Ä", + "Ö", + "Ü", + "ß", + ); + + $text = preg_replace($search,$replace,$document); + + return $text; + } + +/*======================================================================*\ + Function: _expandlinks + Purpose: expand each link into a fully qualified URL + Input: $links the links to qualify + $URI the full URI to get the base from + Output: $expandedLinks the expanded links +\*======================================================================*/ + + function _expandlinks($links,$URI) + { + + preg_match("/^[^\?]+/",$URI,$match); + + $match = preg_replace("|/[^\/\.]+\.[^\/\.]+$|","",$match[0]); + $match = preg_replace("|/$|","",$match); + $match_part = parse_url($match); + $match_root = + $match_part["scheme"]."://".$match_part["host"]; + + $search = array( "|^http://".preg_quote($this->host)."|i", + "|^(\/)|i", + "|^(?!http://)(?!mailto:)|i", + "|/\./|", + "|/[^\/]+/\.\./|" + ); + + $replace = array( "", + $match_root."/", + $match."/", + "/", + "/" + ); + + $expandedLinks = preg_replace($search,$replace,$links); + + return $expandedLinks; + } + +/*======================================================================*\ + Function: _httprequest + Purpose: go get the http data from the server + Input: $url the url to fetch + $fp the current open file pointer + $URI the full URI + $body body contents to send if any (POST) + Output: +\*======================================================================*/ + + function _httprequest($url,$fp,$URI,$http_method,$content_type="",$body="") + { + $cookie_headers = ''; + if($this->passcookies && $this->_redirectaddr) + $this->setcookies(); + + $URI_PARTS = parse_url($URI); + if(empty($url)) + $url = "/"; + $headers = $http_method." ".$url." ".$this->_httpversion."\r\n"; + if(!empty($this->agent)) + $headers .= "User-Agent: ".$this->agent."\r\n"; + if(!empty($this->host) && !isset($this->rawheaders['Host'])) { + $headers .= "Host: ".$this->host; + if(!empty($this->port)) + $headers .= ":".$this->port; + $headers .= "\r\n"; + } + if(!empty($this->accept)) + $headers .= "Accept: ".$this->accept."\r\n"; + if(!empty($this->referer)) + $headers .= "Referer: ".$this->referer."\r\n"; + if(!empty($this->cookies)) + { + if(!is_array($this->cookies)) + $this->cookies = (array)$this->cookies; + + reset($this->cookies); + if ( count($this->cookies) > 0 ) { + $cookie_headers .= 'Cookie: '; + foreach ( $this->cookies as $cookieKey => $cookieVal ) { + $cookie_headers .= $cookieKey."=".urlencode($cookieVal)."; "; + } + $headers .= substr($cookie_headers,0,-2) . "\r\n"; + } + } + if(!empty($this->rawheaders)) + { + if(!is_array($this->rawheaders)) + $this->rawheaders = (array)$this->rawheaders; + while(list($headerKey,$headerVal) = each($this->rawheaders)) + $headers .= $headerKey.": ".$headerVal."\r\n"; + } + if(!empty($content_type)) { + $headers .= "Content-type: $content_type"; + if ($content_type == "multipart/form-data") + $headers .= "; boundary=".$this->_mime_boundary; + $headers .= "\r\n"; + } + if(!empty($body)) + $headers .= "Content-length: ".strlen($body)."\r\n"; + if(!empty($this->user) || !empty($this->pass)) + $headers .= "Authorization: Basic ".base64_encode($this->user.":".$this->pass)."\r\n"; + + //add proxy auth headers + if(!empty($this->proxy_user)) + $headers .= 'Proxy-Authorization: ' . 'Basic ' . base64_encode($this->proxy_user . ':' . $this->proxy_pass)."\r\n"; + + + $headers .= "\r\n"; + + // set the read timeout if needed + if ($this->read_timeout > 0) + socket_set_timeout($fp, $this->read_timeout); + $this->timed_out = false; + + fwrite($fp,$headers.$body,strlen($headers.$body)); + + $this->_redirectaddr = false; + unset($this->headers); + + while($currentHeader = fgets($fp,$this->_maxlinelen)) + { + if ($this->read_timeout > 0 && $this->_check_timeout($fp)) + { + $this->status=-100; + return false; + } + + if($currentHeader == "\r\n") + break; + + // if a header begins with Location: or URI:, set the redirect + if(preg_match("/^(Location:|URI:)/i",$currentHeader)) + { + // get URL portion of the redirect + preg_match("/^(Location:|URI:)[ ]+(.*)/i",chop($currentHeader),$matches); + // look for :// in the Location header to see if hostname is included + if(!preg_match("|\:\/\/|",$matches[2])) + { + // no host in the path, so prepend + $this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port; + // eliminate double slash + if(!preg_match("|^/|",$matches[2])) + $this->_redirectaddr .= "/".$matches[2]; + else + $this->_redirectaddr .= $matches[2]; + } + else + $this->_redirectaddr = $matches[2]; + } + + if(preg_match("|^HTTP/|",$currentHeader)) + { + if(preg_match("|^HTTP/[^\s]*\s(.*?)\s|",$currentHeader, $status)) + { + $this->status= $status[1]; + } + $this->response_code = $currentHeader; + } + + $this->headers[] = $currentHeader; + } + + $results = ''; + do { + $_data = fread($fp, $this->maxlength); + if (strlen($_data) == 0) { + break; + } + $results .= $_data; + } while(true); + + if ($this->read_timeout > 0 && $this->_check_timeout($fp)) + { + $this->status=-100; + return false; + } + + // check if there is a a redirect meta tag + + if(preg_match("']*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match)) + + { + $this->_redirectaddr = $this->_expandlinks($match[1],$URI); + } + + // have we hit our frame depth and is there frame src to fetch? + if(($this->_framedepth < $this->maxframes) && preg_match_all("']+)'i",$results,$match)) + { + $this->results[] = $results; + for($x=0; $x_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host); + } + // have we already fetched framed content? + elseif(is_array($this->results)) + $this->results[] = $results; + // no framed content + else + $this->results = $results; + + return true; + } + +/*======================================================================*\ + Function: _httpsrequest + Purpose: go get the https data from the server using curl + Input: $url the url to fetch + $URI the full URI + $body body contents to send if any (POST) + Output: +\*======================================================================*/ + + function _httpsrequest($url,$URI,$http_method,$content_type="",$body="") + { + if($this->passcookies && $this->_redirectaddr) + $this->setcookies(); + + $headers = array(); + + $URI_PARTS = parse_url($URI); + if(empty($url)) + $url = "/"; + // GET ... header not needed for curl + //$headers[] = $http_method." ".$url." ".$this->_httpversion; + if(!empty($this->agent)) + $headers[] = "User-Agent: ".$this->agent; + if(!empty($this->host)) + if(!empty($this->port)) + $headers[] = "Host: ".$this->host.":".$this->port; + else + $headers[] = "Host: ".$this->host; + if(!empty($this->accept)) + $headers[] = "Accept: ".$this->accept; + if(!empty($this->referer)) + $headers[] = "Referer: ".$this->referer; + if(!empty($this->cookies)) + { + if(!is_array($this->cookies)) + $this->cookies = (array)$this->cookies; + + reset($this->cookies); + if ( count($this->cookies) > 0 ) { + $cookie_str = 'Cookie: '; + foreach ( $this->cookies as $cookieKey => $cookieVal ) { + $cookie_str .= $cookieKey."=".urlencode($cookieVal)."; "; + } + $headers[] = substr($cookie_str,0,-2); + } + } + if(!empty($this->rawheaders)) + { + if(!is_array($this->rawheaders)) + $this->rawheaders = (array)$this->rawheaders; + while(list($headerKey,$headerVal) = each($this->rawheaders)) + $headers[] = $headerKey.": ".$headerVal; + } + if(!empty($content_type)) { + if ($content_type == "multipart/form-data") + $headers[] = "Content-type: $content_type; boundary=".$this->_mime_boundary; + else + $headers[] = "Content-type: $content_type"; + } + if(!empty($body)) + $headers[] = "Content-length: ".strlen($body); + if(!empty($this->user) || !empty($this->pass)) + $headers[] = "Authorization: BASIC ".base64_encode($this->user.":".$this->pass); + + for($curr_header = 0; $curr_header < count($headers); $curr_header++) { + $safer_header = strtr( $headers[$curr_header], "\"", " " ); + $cmdline_params .= " -H \"".$safer_header."\""; + } + + if(!empty($body)) + $cmdline_params .= " -d \"$body\""; + + if($this->read_timeout > 0) + $cmdline_params .= " -m ".$this->read_timeout; + + $headerfile = tempnam($temp_dir, "sno"); + + exec($this->curl_path." -k -D \"$headerfile\"".$cmdline_params." \"".escapeshellcmd($URI)."\"",$results,$return); + + if($return) + { + $this->error = "Error: cURL could not retrieve the document, error $return."; + return false; + } + + + $results = implode("\r\n",$results); + + $result_headers = file("$headerfile"); + + $this->_redirectaddr = false; + unset($this->headers); + + for($currentHeader = 0; $currentHeader < count($result_headers); $currentHeader++) + { + + // if a header begins with Location: or URI:, set the redirect + if(preg_match("/^(Location: |URI: )/i",$result_headers[$currentHeader])) + { + // get URL portion of the redirect + preg_match("/^(Location: |URI:)\s+(.*)/",chop($result_headers[$currentHeader]),$matches); + // look for :// in the Location header to see if hostname is included + if(!preg_match("|\:\/\/|",$matches[2])) + { + // no host in the path, so prepend + $this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port; + // eliminate double slash + if(!preg_match("|^/|",$matches[2])) + $this->_redirectaddr .= "/".$matches[2]; + else + $this->_redirectaddr .= $matches[2]; + } + else + $this->_redirectaddr = $matches[2]; + } + + if(preg_match("|^HTTP/|",$result_headers[$currentHeader])) + $this->response_code = $result_headers[$currentHeader]; + + $this->headers[] = $result_headers[$currentHeader]; + } + + // check if there is a a redirect meta tag + + if(preg_match("']*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match)) + { + $this->_redirectaddr = $this->_expandlinks($match[1],$URI); + } + + // have we hit our frame depth and is there frame src to fetch? + if(($this->_framedepth < $this->maxframes) && preg_match_all("']+)'i",$results,$match)) + { + $this->results[] = $results; + for($x=0; $x_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host); + } + // have we already fetched framed content? + elseif(is_array($this->results)) + $this->results[] = $results; + // no framed content + else + $this->results = $results; + + unlink("$headerfile"); + + return true; + } + +/*======================================================================*\ + Function: setcookies() + Purpose: set cookies for a redirection +\*======================================================================*/ + + function setcookies() + { + for($x=0; $xheaders); $x++) + { + if(preg_match('/^set-cookie:[\s]+([^=]+)=([^;]+)/i', $this->headers[$x],$match)) + $this->cookies[$match[1]] = urldecode($match[2]); + } + } + + +/*======================================================================*\ + Function: _check_timeout + Purpose: checks whether timeout has occurred + Input: $fp file pointer +\*======================================================================*/ + + function _check_timeout($fp) + { + if ($this->read_timeout > 0) { + $fp_status = socket_get_status($fp); + if ($fp_status["timed_out"]) { + $this->timed_out = true; + return true; + } + } + return false; + } + +/*======================================================================*\ + Function: _connect + Purpose: make a socket connection + Input: $fp file pointer +\*======================================================================*/ + + function _connect(&$fp) + { + if(!empty($this->proxy_host) && !empty($this->proxy_port)) + { + $this->_isproxy = true; + + $host = $this->proxy_host; + $port = $this->proxy_port; + } + else + { + $host = $this->host; + $port = $this->port; + } + + $this->status = 0; + + if($fp = fsockopen( + $host, + $port, + $errno, + $errstr, + $this->_fp_timeout + )) + { + // socket connection succeeded + + return true; + } + else + { + // socket connection failed + $this->status = $errno; + switch($errno) + { + case -3: + $this->error="socket creation failed (-3)"; + case -4: + $this->error="dns lookup failure (-4)"; + case -5: + $this->error="connection refused or timed out (-5)"; + default: + $this->error="connection failed (".$errno.")"; + } + return false; + } + } +/*======================================================================*\ + Function: _disconnect + Purpose: disconnect a socket connection + Input: $fp file pointer +\*======================================================================*/ + + function _disconnect($fp) + { + return(fclose($fp)); + } + + +/*======================================================================*\ + Function: _prepare_post_body + Purpose: Prepare post body according to encoding type + Input: $formvars - form variables + $formfiles - form upload files + Output: post body +\*======================================================================*/ + + function _prepare_post_body($formvars, $formfiles) + { + settype($formvars, "array"); + settype($formfiles, "array"); + $postdata = ''; + + if (count($formvars) == 0 && count($formfiles) == 0) + return; + + switch ($this->_submit_type) { + case "application/x-www-form-urlencoded": + reset($formvars); + while(list($key,$val) = each($formvars)) { + if (is_array($val) || is_object($val)) { + while (list($cur_key, $cur_val) = each($val)) { + $postdata .= urlencode($key)."[]=".urlencode($cur_val)."&"; + } + } else + $postdata .= urlencode($key)."=".urlencode($val)."&"; + } + break; + + case "multipart/form-data": + $this->_mime_boundary = "Snoopy".md5(uniqid(microtime())); + + reset($formvars); + while(list($key,$val) = each($formvars)) { + if (is_array($val) || is_object($val)) { + while (list($cur_key, $cur_val) = each($val)) { + $postdata .= "--".$this->_mime_boundary."\r\n"; + $postdata .= "Content-Disposition: form-data; name=\"$key\[\]\"\r\n\r\n"; + $postdata .= "$cur_val\r\n"; + } + } else { + $postdata .= "--".$this->_mime_boundary."\r\n"; + $postdata .= "Content-Disposition: form-data; name=\"$key\"\r\n\r\n"; + $postdata .= "$val\r\n"; + } + } + + reset($formfiles); + while (list($field_name, $file_names) = each($formfiles)) { + settype($file_names, "array"); + while (list(, $file_name) = each($file_names)) { + if (!is_readable($file_name)) continue; + + $fp = fopen($file_name, "r"); + $file_content = fread($fp, filesize($file_name)); + fclose($fp); + $base_name = basename($file_name); + + $postdata .= "--".$this->_mime_boundary."\r\n"; + $postdata .= "Content-Disposition: form-data; name=\"$field_name\"; filename=\"$base_name\"\r\n\r\n"; + $postdata .= "$file_content\r\n"; + } + } + $postdata .= "--".$this->_mime_boundary."--\r\n"; + break; + } + + return $postdata; + } +} + +?> diff --git a/isis/src/docsys/assets/scripts/feed2js/magpie/rss_cache.inc b/isis/src/docsys/assets/scripts/feed2js/magpie/rss_cache.inc new file mode 100755 index 0000000000000000000000000000000000000000..f54ec3ed25eec6123fad99aad70e84ca92d66000 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/magpie/rss_cache.inc @@ -0,0 +1,200 @@ + + * Version: 0.51 + * License: GPL + * + * The latest version of MagpieRSS can be obtained from: + * http://magpierss.sourceforge.net + * + * For questions, help, comments, discussion, etc., please join the + * Magpie mailing list: + * http://lists.sourceforge.net/lists/listinfo/magpierss-general + * + */ + +class RSSCache { + var $BASE_CACHE = './cache'; // where the cache files are stored + var $MAX_AGE = 3600; // when are files stale, default one hour + var $ERROR = ""; // accumulate error messages + + function RSSCache ($base='', $age='') { + if ( $base ) { + $this->BASE_CACHE = $base; + } + if ( $age ) { + $this->MAX_AGE = $age; + } + + // attempt to make the cache directory + if ( ! file_exists( $this->BASE_CACHE ) ) { + $status = @mkdir( $this->BASE_CACHE, 0755 ); + + // if make failed + if ( ! $status ) { + $this->error( + "Cache couldn't make dir '" . $this->BASE_CACHE . "'." + ); + } + } + } + +/*=======================================================================*\ + Function: set + Purpose: add an item to the cache, keyed on url + Input: url from which the rss file was fetched + Output: true on sucess +\*=======================================================================*/ + function set ($url, $rss) { + $this->ERROR = ""; + $cache_file = $this->file_name( $url ); + $fp = @fopen( $cache_file, 'w' ); + + if ( ! $fp ) { + $this->error( + "Cache unable to open file for writing: $cache_file" + ); + return 0; + } + + + $data = $this->serialize( $rss ); + fwrite( $fp, $data ); + fclose( $fp ); + + return $cache_file; + } + +/*=======================================================================*\ + Function: get + Purpose: fetch an item from the cache + Input: url from which the rss file was fetched + Output: cached object on HIT, false on MISS +\*=======================================================================*/ + function get ($url) { + $this->ERROR = ""; + $cache_file = $this->file_name( $url ); + + if ( ! file_exists( $cache_file ) ) { + $this->debug( + "Cache doesn't contain: $url (cache file: $cache_file)" + ); + return 0; + } + + $fp = @fopen($cache_file, 'r'); + if ( ! $fp ) { + $this->error( + "Failed to open cache file for reading: $cache_file" + ); + return 0; + } + + if ($filesize = filesize($cache_file) ) { + $data = fread( $fp, filesize($cache_file) ); + $rss = $this->unserialize( $data ); + + return $rss; + } + + return 0; + } + +/*=======================================================================*\ + Function: check_cache + Purpose: check a url for membership in the cache + and whether the object is older then MAX_AGE (ie. STALE) + Input: url from which the rss file was fetched + Output: cached object on HIT, false on MISS +\*=======================================================================*/ + function check_cache ( $url ) { + $this->ERROR = ""; + $filename = $this->file_name( $url ); + + if ( file_exists( $filename ) ) { + // find how long ago the file was added to the cache + // and whether that is longer then MAX_AGE + $mtime = filemtime( $filename ); + $age = time() - $mtime; + if ( $this->MAX_AGE > $age ) { + // object exists and is current + return 'HIT'; + } + else { + // object exists but is old + return 'STALE'; + } + } + else { + // object does not exist + return 'MISS'; + } + } + + function cache_age( $cache_key ) { + $filename = $this->file_name( $url ); + if ( file_exists( $filename ) ) { + $mtime = filemtime( $filename ); + $age = time() - $mtime; + return $age; + } + else { + return -1; + } + } + +/*=======================================================================*\ + Function: serialize +\*=======================================================================*/ + function serialize ( $rss ) { + return serialize( $rss ); + } + +/*=======================================================================*\ + Function: unserialize +\*=======================================================================*/ + function unserialize ( $data ) { + return unserialize( $data ); + } + +/*=======================================================================*\ + Function: file_name + Purpose: map url to location in cache + Input: url from which the rss file was fetched + Output: a file name +\*=======================================================================*/ + function file_name ($url) { + $filename = md5( $url ); + return join( DIRECTORY_SEPARATOR, array( $this->BASE_CACHE, $filename ) ); + } + +/*=======================================================================*\ + Function: error + Purpose: register error +\*=======================================================================*/ + function error ($errormsg, $lvl=E_USER_WARNING) { + // append PHP's error message if track_errors enabled + if ( isset($php_errormsg) ) { + $errormsg .= " ($php_errormsg)"; + } + $this->ERROR = $errormsg; + if ( MAGPIE_DEBUG ) { + trigger_error( $errormsg, $lvl); + } + else { + error_log( $errormsg, 0); + } + } + + function debug ($debugmsg, $lvl=E_USER_NOTICE) { + if ( MAGPIE_DEBUG ) { + $this->error("MagpieRSS [debug] $debugmsg", $lvl); + } + } + +} + +?> diff --git a/isis/src/docsys/assets/scripts/feed2js/magpie/rss_fetch.inc b/isis/src/docsys/assets/scripts/feed2js/magpie/rss_fetch.inc new file mode 100755 index 0000000000000000000000000000000000000000..68e2ba4eaa238c83d29c8385030b1ddaf79ba62d --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/magpie/rss_fetch.inc @@ -0,0 +1,458 @@ + + * License: GPL + * + * The latest version of MagpieRSS can be obtained from: + * http://magpierss.sourceforge.net + * + * For questions, help, comments, discussion, etc., please join the + * Magpie mailing list: + * magpierss-general@lists.sourceforge.net + * + */ + +// Setup MAGPIE_DIR for use on hosts that don't include +// the current path in include_path. +// with thanks to rajiv and smarty +if (!defined('DIR_SEP')) { + define('DIR_SEP', DIRECTORY_SEPARATOR); +} + +if (!defined('MAGPIE_DIR')) { + define('MAGPIE_DIR', dirname(__FILE__) . DIR_SEP); +} + +require_once( MAGPIE_DIR . 'rss_parse.inc' ); +require_once( MAGPIE_DIR . 'rss_cache.inc' ); + +// for including 3rd party libraries +define('MAGPIE_EXTLIB', MAGPIE_DIR . 'extlib' . DIR_SEP); +require_once( MAGPIE_EXTLIB . 'Snoopy.class.inc'); + + +/* + * CONSTANTS - redefine these in your script to change the + * behaviour of fetch_rss() currently, most options effect the cache + * + * MAGPIE_CACHE_ON - Should Magpie cache parsed RSS objects? + * For me a built in cache was essential to creating a "PHP-like" + * feel to Magpie, see rss_cache.inc for rationale + * + * + * MAGPIE_CACHE_DIR - Where should Magpie cache parsed RSS objects? + * This should be a location that the webserver can write to. If this + * directory does not already exist Magpie will try to be smart and create + * it. This will often fail for permissions reasons. + * + * + * MAGPIE_CACHE_AGE - How long to store cached RSS objects? In seconds. + * + * + * MAGPIE_CACHE_FRESH_ONLY - If remote fetch fails, throw error + * instead of returning stale object? + * + * MAGPIE_DEBUG - Display debugging notices? + * +*/ + + +/*=======================================================================*\ + Function: fetch_rss: + Purpose: return RSS object for the give url + maintain the cache + Input: url of RSS file + Output: parsed RSS object (see rss_parse.inc) + + NOTES ON CACHEING: + If caching is on (MAGPIE_CACHE_ON) fetch_rss will first check the cache. + + NOTES ON RETRIEVING REMOTE FILES: + If conditional gets are on (MAGPIE_CONDITIONAL_GET_ON) fetch_rss will + return a cached object, and touch the cache object upon receiving a + 304. + + NOTES ON FAILED REQUESTS: + If there is an HTTP error while fetching an RSS object, the cached + version will be return, if it exists (and if MAGPIE_CACHE_FRESH_ONLY is off) +\*=======================================================================*/ + +define('MAGPIE_VERSION', '0.72'); + +$MAGPIE_ERROR = ""; + +function fetch_rss ($url) { + // initialize constants + init(); + + if ( !isset($url) ) { + error("fetch_rss called without a url"); + return false; + } + + // if cache is disabled + if ( !MAGPIE_CACHE_ON ) { + // fetch file, and parse it + $resp = _fetch_remote_file( $url ); + if ( is_success( $resp->status ) ) { + return _response_to_rss( $resp ); + } + else { + error("Failed to fetch $url and cache is off"); + return false; + } + } + // else cache is ON + else { + // Flow + // 1. check cache + // 2. if there is a hit, make sure its fresh + // 3. if cached obj fails freshness check, fetch remote + // 4. if remote fails, return stale object, or error + + $cache = new RSSCache( MAGPIE_CACHE_DIR, MAGPIE_CACHE_AGE ); + + if (MAGPIE_DEBUG and $cache->ERROR) { + debug($cache->ERROR, E_USER_WARNING); + } + + + $cache_status = 0; // response of check_cache + $request_headers = array(); // HTTP headers to send with fetch + $rss = 0; // parsed RSS object + $errormsg = 0; // errors, if any + + // store parsed XML by desired output encoding + // as character munging happens at parse time + $cache_key = $url . MAGPIE_OUTPUT_ENCODING; + + if (!$cache->ERROR) { + // return cache HIT, MISS, or STALE + $cache_status = $cache->check_cache( $cache_key); + } + + // if object cached, and cache is fresh, return cached obj + if ( $cache_status == 'HIT' ) { + $rss = $cache->get( $cache_key ); + if ( isset($rss) and $rss ) { + // should be cache age + $rss->from_cache = 1; + if ( MAGPIE_DEBUG > 1) { + debug("MagpieRSS: Cache HIT", E_USER_NOTICE); + } + return $rss; + } + } + + // else attempt a conditional get + + // setup headers + if ( $cache_status == 'STALE' ) { + $rss = $cache->get( $cache_key ); + if ( $rss and $rss->etag and $rss->last_modified ) { + $request_headers['If-None-Match'] = $rss->etag; + $request_headers['If-Last-Modified'] = $rss->last_modified; + } + } + + $resp = _fetch_remote_file( $url, $request_headers ); + + if (isset($resp) and $resp) { + if ($resp->status == '304' ) { + // we have the most current copy + if ( MAGPIE_DEBUG > 1) { + debug("Got 304 for $url"); + } + // reset cache on 304 (at minutillo insistent prodding) + $cache->set($cache_key, $rss); + return $rss; + } + elseif ( is_success( $resp->status ) ) { + $rss = _response_to_rss( $resp ); + if ( $rss ) { + if (MAGPIE_DEBUG > 1) { + debug("Fetch successful"); + } + // add object to cache + $cache->set( $cache_key, $rss ); + return $rss; + } + } + else { + $errormsg = "Failed to fetch $url "; + if ( $resp->status == '-100' ) { + $errormsg .= "(Request timed out after " . MAGPIE_FETCH_TIME_OUT . " seconds)"; + } + elseif ( $resp->error ) { + # compensate for Snoopy's annoying habbit to tacking + # on '\n' + $http_error = substr($resp->error, 0, -2); + $errormsg .= "(HTTP Error: $http_error)"; + } + else { + $errormsg .= "(HTTP Response: " . $resp->response_code .')'; + } + } + } + else { + $errormsg = "Unable to retrieve RSS file for unknown reasons."; + } + + // else fetch failed + + // attempt to return cached object + if ($rss) { + if ( MAGPIE_DEBUG ) { + debug("Returning STALE object for $url"); + } + return $rss; + } + + // else we totally failed + error( $errormsg ); + + return false; + + } // end if ( !MAGPIE_CACHE_ON ) { +} // end fetch_rss() + +/*=======================================================================*\ + Function: error + Purpose: set MAGPIE_ERROR, and trigger error +\*=======================================================================*/ + +function error ($errormsg, $lvl=E_USER_WARNING) { + global $MAGPIE_ERROR; + + // append PHP's error message if track_errors enabled + if ( isset($php_errormsg) ) { + $errormsg .= " ($php_errormsg)"; + } + if ( $errormsg ) { + $errormsg = "MagpieRSS: $errormsg"; + $MAGPIE_ERROR = $errormsg; + trigger_error( $errormsg, $lvl); + } +} + +function debug ($debugmsg, $lvl=E_USER_NOTICE) { + trigger_error("MagpieRSS [debug] $debugmsg", $lvl); +} + +/*=======================================================================*\ + Function: magpie_error + Purpose: accessor for the magpie error variable +\*=======================================================================*/ +function magpie_error ($errormsg="") { + global $MAGPIE_ERROR; + + if ( isset($errormsg) and $errormsg ) { + $MAGPIE_ERROR = $errormsg; + } + + return $MAGPIE_ERROR; +} + +/*=======================================================================*\ + Function: _fetch_remote_file + Purpose: retrieve an arbitrary remote file + Input: url of the remote file + headers to send along with the request (optional) + Output: an HTTP response object (see Snoopy.class.inc) +\*=======================================================================*/ +function _fetch_remote_file ($url, $headers = "" ) { + // Snoopy is an HTTP client in PHP + $client = new Snoopy(); + $client->agent = MAGPIE_USER_AGENT; + $client->read_timeout = MAGPIE_FETCH_TIME_OUT; + $client->use_gzip = MAGPIE_USE_GZIP; + if (is_array($headers) ) { + $client->rawheaders = $headers; + } + + @$client->fetch($url); + return $client; + +} + +/*=======================================================================*\ + Function: _response_to_rss + Purpose: parse an HTTP response object into an RSS object + Input: an HTTP response object (see Snoopy) + Output: parsed RSS object (see rss_parse) +\*=======================================================================*/ +function _response_to_rss ($resp) { + $rss = new MagpieRSS( $resp->results, MAGPIE_OUTPUT_ENCODING, MAGPIE_INPUT_ENCODING, MAGPIE_DETECT_ENCODING ); + + // if RSS parsed successfully + if ( $rss and !$rss->ERROR) { + + // find Etag, and Last-Modified + foreach($resp->headers as $h) { + // 2003-03-02 - Nicola Asuni (www.tecnick.com) - fixed bug "Undefined offset: 1" + if (strpos($h, ": ")) { + list($field, $val) = explode(": ", $h, 2); + } + else { + $field = $h; + $val = ""; + } + + if ( $field == 'ETag' ) { + $rss->etag = $val; + } + + if ( $field == 'Last-Modified' ) { + $rss->last_modified = $val; + } + } + + return $rss; + } // else construct error message + else { + $errormsg = "Failed to parse RSS file."; + + if ($rss) { + $errormsg .= " (" . $rss->ERROR . ")"; + } + error($errormsg); + + return false; + } // end if ($rss and !$rss->error) +} + +/*=======================================================================*\ + Function: init + Purpose: setup constants with default values + check for user overrides +\*=======================================================================*/ +function init () { + if ( defined('MAGPIE_INITALIZED') ) { + return; + } + else { + define('MAGPIE_INITALIZED', true); + } + + if ( !defined('MAGPIE_CACHE_ON') ) { + define('MAGPIE_CACHE_ON', true); + } + + if ( !defined('MAGPIE_CACHE_DIR') ) { + define('MAGPIE_CACHE_DIR', './cache'); + } + + if ( !defined('MAGPIE_CACHE_AGE') ) { + define('MAGPIE_CACHE_AGE', 60*60); // one hour + } + + if ( !defined('MAGPIE_CACHE_FRESH_ONLY') ) { + define('MAGPIE_CACHE_FRESH_ONLY', false); + } + + if ( !defined('MAGPIE_OUTPUT_ENCODING') ) { + define('MAGPIE_OUTPUT_ENCODING', 'ISO-8859-1'); + } + + if ( !defined('MAGPIE_INPUT_ENCODING') ) { + define('MAGPIE_INPUT_ENCODING', null); + } + + if ( !defined('MAGPIE_DETECT_ENCODING') ) { + define('MAGPIE_DETECT_ENCODING', true); + } + + if ( !defined('MAGPIE_DEBUG') ) { + define('MAGPIE_DEBUG', 0); + } + + if ( !defined('MAGPIE_USER_AGENT') ) { + $ua = 'MagpieRSS/'. MAGPIE_VERSION . ' (+http://magpierss.sf.net'; + + if ( MAGPIE_CACHE_ON ) { + $ua = $ua . ')'; + } + else { + $ua = $ua . '; No cache)'; + } + + define('MAGPIE_USER_AGENT', $ua); + } + + if ( !defined('MAGPIE_FETCH_TIME_OUT') ) { + define('MAGPIE_FETCH_TIME_OUT', 5); // 5 second timeout + } + + // use gzip encoding to fetch rss files if supported? + if ( !defined('MAGPIE_USE_GZIP') ) { + define('MAGPIE_USE_GZIP', true); + } +} + +// NOTE: the following code should really be in Snoopy, or at least +// somewhere other then rss_fetch! + +/*=======================================================================*\ + HTTP STATUS CODE PREDICATES + These functions attempt to classify an HTTP status code + based on RFC 2616 and RFC 2518. + + All of them take an HTTP status code as input, and return true or false + + All this code is adapted from LWP's HTTP::Status. +\*=======================================================================*/ + + +/*=======================================================================*\ + Function: is_info + Purpose: return true if Informational status code +\*=======================================================================*/ +function is_info ($sc) { + return $sc >= 100 && $sc < 200; +} + +/*=======================================================================*\ + Function: is_success + Purpose: return true if Successful status code +\*=======================================================================*/ +function is_success ($sc) { + return $sc >= 200 && $sc < 300; +} + +/*=======================================================================*\ + Function: is_redirect + Purpose: return true if Redirection status code +\*=======================================================================*/ +function is_redirect ($sc) { + return $sc >= 300 && $sc < 400; +} + +/*=======================================================================*\ + Function: is_error + Purpose: return true if Error status code +\*=======================================================================*/ +function is_error ($sc) { + return $sc >= 400 && $sc < 600; +} + +/*=======================================================================*\ + Function: is_client_error + Purpose: return true if Error status code, and its a client error +\*=======================================================================*/ +function is_client_error ($sc) { + return $sc >= 400 && $sc < 500; +} + +/*=======================================================================*\ + Function: is_client_error + Purpose: return true if Error status code, and its a server error +\*=======================================================================*/ +function is_server_error ($sc) { + return $sc >= 500 && $sc < 600; +} + +?> diff --git a/isis/src/docsys/assets/scripts/feed2js/magpie/rss_parse.inc b/isis/src/docsys/assets/scripts/feed2js/magpie/rss_parse.inc new file mode 100755 index 0000000000000000000000000000000000000000..4deb848c11903a72f03399fc3c9d8ad48b5bfe21 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/magpie/rss_parse.inc @@ -0,0 +1,613 @@ + +* @version 0.7a (with patch for RSS enclosures at line 209) +* @license GPL +* +*/ + +define('RSS', 'RSS'); +define('ATOM', 'Atom'); + +require_once (MAGPIE_DIR . 'rss_utils.inc'); + +/** +* Hybrid parser, and object, takes RSS as a string and returns a simple object. +* +* see: rss_fetch.inc for a simpler interface with integrated caching support +* +*/ +class MagpieRSS { + var $parser; + + var $current_item = array(); // item currently being parsed + var $items = array(); // collection of parsed items + var $channel = array(); // hash of channel fields + var $textinput = array(); + var $image = array(); + var $feed_type; + var $feed_version; + var $encoding = ''; // output encoding of parsed rss + + var $_source_encoding = ''; // only set if we have to parse xml prolog + + var $ERROR = ""; + var $WARNING = ""; + + // define some constants + + var $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright'); + var $_KNOWN_ENCODINGS = array('UTF-8', 'US-ASCII', 'ISO-8859-1'); + + // parser variables, useless if you're not a parser, treat as private + var $stack = array(); // parser stack + var $inchannel = false; + var $initem = false; + var $incontent = false; // if in Atom field + var $intextinput = false; + var $inimage = false; + var $current_namespace = false; + + + /** + * Set up XML parser, parse source, and return populated RSS object.. + * + * @param string $source string containing the RSS to be parsed + * + * NOTE: Probably a good idea to leave the encoding options alone unless + * you know what you're doing as PHP's character set support is + * a little weird. + * + * NOTE: A lot of this is unnecessary but harmless with PHP5 + * + * + * @param string $output_encoding output the parsed RSS in this character + * set defaults to ISO-8859-1 as this is PHP's + * default. + * + * NOTE: might be changed to UTF-8 in future + * versions. + * + * @param string $input_encoding the character set of the incoming RSS source. + * Leave blank and Magpie will try to figure it + * out. + * + * + * @param bool $detect_encoding if false Magpie won't attempt to detect + * source encoding. (caveat emptor) + * + */ + function MagpieRSS ($source, $output_encoding='ISO-8859-1', + $input_encoding=null, $detect_encoding=true) + { + # if PHP xml isn't compiled in, die + # + if (!function_exists('xml_parser_create')) { + $this->error( "Failed to load PHP's XML Extension. " . + "http://www.php.net/manual/en/ref.xml.php", + E_USER_ERROR ); + } + + list($parser, $source) = $this->create_parser($source, + $output_encoding, $input_encoding, $detect_encoding); + + + if (!is_resource($parser)) { + $this->error( "Failed to create an instance of PHP's XML parser. " . + "http://www.php.net/manual/en/ref.xml.php", + E_USER_ERROR ); + } + + + $this->parser = $parser; + + # pass in parser, and a reference to this object + # setup handlers + # + xml_set_object( $this->parser, $this ); + xml_set_element_handler($this->parser, + 'feed_start_element', 'feed_end_element' ); + + xml_set_character_data_handler( $this->parser, 'feed_cdata' ); + + $status = xml_parse( $this->parser, $source ); + + if (! $status ) { + $errorcode = xml_get_error_code( $this->parser ); + if ( $errorcode != XML_ERROR_NONE ) { + $xml_error = xml_error_string( $errorcode ); + $error_line = xml_get_current_line_number($this->parser); + $error_col = xml_get_current_column_number($this->parser); + $errormsg = "$xml_error at line $error_line, column $error_col"; + + $this->error( $errormsg ); + } + } + + xml_parser_free( $this->parser ); + + $this->normalize(); + } + + function feed_start_element($p, $element, &$attrs) { + $el = $element = strtolower($element); + $attrs = array_change_key_case($attrs, CASE_LOWER); + + // check for a namespace, and split if found + $ns = false; + if ( strpos( $element, ':' ) ) { + list($ns, $el) = split( ':', $element, 2); + } + if ( $ns and $ns != 'rdf' ) { + $this->current_namespace = $ns; + } + + # if feed type isn't set, then this is first element of feed + # identify feed from root element + # + if (!isset($this->feed_type) ) { + if ( $el == 'rdf' ) { + $this->feed_type = RSS; + $this->feed_version = '1.0'; + } + elseif ( $el == 'rss' ) { + $this->feed_type = RSS; + $this->feed_version = $attrs['version']; + } + elseif ( $el == 'feed' ) { + $this->feed_type = ATOM; + $this->feed_version = $attrs['version']; + $this->inchannel = true; + } + return; + } + + if ( $el == 'channel' ) + { + $this->inchannel = true; + } + elseif ($el == 'item' or $el == 'entry' ) + { + $this->initem = true; + if ( isset($attrs['rdf:about']) ) { + $this->current_item['about'] = $attrs['rdf:about']; + } + } + + // if we're in the default namespace of an RSS feed, + // record textinput or image fields + elseif ( + $this->feed_type == RSS and + $this->current_namespace == '' and + $el == 'textinput' ) + { + $this->intextinput = true; + } + + elseif ( + $this->feed_type == RSS and + $this->current_namespace == '' and + $el == 'image' ) + { + $this->inimage = true; + } + + elseif ( + $this->feed_type == RSS and + $el == 'enclosure' ) + { + $this->current_item[$el][] = $attrs; + $this->incontent = $el; + } + + # handle atom content constructs + elseif ( $this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) ) + { + // avoid clashing w/ RSS mod_content + if ($el == 'content' ) { + $el = 'atom_content'; + } + + $this->incontent = $el; + + + } + + // if inside an Atom content construct (e.g. content or summary) field treat tags as text + elseif ($this->feed_type == ATOM and $this->incontent ) + { + // if tags are inlined, then flatten + $attrs_str = join(' ', + array_map('map_attrs', + array_keys($attrs), + array_values($attrs) ) ); + + $this->append_content( "<$element $attrs_str>" ); + + array_unshift( $this->stack, $el ); + } + + // Atom support many links per containging element. + // Magpie treats link elements of type rel='alternate' + // as being equivalent to RSS's simple link element. + // + elseif ($this->feed_type == ATOM and $el == 'link' ) + { + if ( isset($attrs['rel']) and $attrs['rel'] == 'alternate' ) + { + $link_el = 'link'; + } + else { + $link_el = 'link_' . $attrs['rel']; + } + + $this->append($link_el, $attrs['href']); + } + // set stack[0] to current element + else { + array_unshift($this->stack, $el); + } + } + + + + function feed_cdata ($p, $text) { + if ($this->feed_type == ATOM and $this->incontent) + { + $this->append_content( $text ); + } + else { + $current_el = join('_', array_reverse($this->stack)); + $this->append($current_el, $text); + } + } + + function feed_end_element ($p, $el) { + $el = strtolower($el); + + if ( $el == 'item' or $el == 'entry' ) + { + $this->items[] = $this->current_item; + $this->current_item = array(); + $this->initem = false; + } + elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' ) + { + $this->intextinput = false; + } + elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'image' ) + { + $this->inimage = false; + } + elseif ($this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) ) + { + $this->incontent = false; + } + elseif ($el == 'channel' or $el == 'feed' ) + { + $this->inchannel = false; + } + elseif ($this->feed_type == ATOM and $this->incontent ) { + // balance tags properly + // note: i don't think this is actually neccessary + if ( $this->stack[0] == $el ) + { + $this->append_content(""); + } + else { + $this->append_content("<$el />"); + } + + array_shift( $this->stack ); + } + else { + array_shift( $this->stack ); + } + + $this->current_namespace = false; + } + + function concat (&$str1, $str2="") { + if (!isset($str1) ) { + $str1=""; + } + $str1 .= $str2; + } + + + + function append_content($text) { + if ( $this->initem ) { + $this->concat( $this->current_item[ $this->incontent ], $text ); + } + elseif ( $this->inchannel ) { + $this->concat( $this->channel[ $this->incontent ], $text ); + } + } + + // smart append - field and namespace aware + function append($el, $text) { + if (!$el) { + return; + } + if ( $this->current_namespace ) + { + if ( $this->initem ) { + $this->concat( + $this->current_item[ $this->current_namespace ][ $el ], $text); + } + elseif ($this->inchannel) { + $this->concat( + $this->channel[ $this->current_namespace][ $el ], $text ); + } + elseif ($this->intextinput) { + $this->concat( + $this->textinput[ $this->current_namespace][ $el ], $text ); + } + elseif ($this->inimage) { + $this->concat( + $this->image[ $this->current_namespace ][ $el ], $text ); + } + } + else { + if ( $this->initem ) { + $this->concat( + $this->current_item[ $el ], $text); + } + elseif ($this->intextinput) { + $this->concat( + $this->textinput[ $el ], $text ); + } + elseif ($this->inimage) { + $this->concat( + $this->image[ $el ], $text ); + } + elseif ($this->inchannel) { + $this->concat( + $this->channel[ $el ], $text ); + } + + } + } + + function normalize () { + // if atom populate rss fields + if ( $this->is_atom() ) { + $this->channel['description'] = $this->channel['tagline']; + for ( $i = 0; $i < count($this->items); $i++) { + $item = $this->items[$i]; + if ( isset($item['summary']) ) + $item['description'] = $item['summary']; + if ( isset($item['atom_content'])) + $item['content']['encoded'] = $item['atom_content']; + + $atom_date = (isset($item['issued']) ) ? $item['issued'] : $item['modified']; + if ( $atom_date ) { + $epoch = @parse_w3cdtf($atom_date); + if ($epoch and $epoch > 0) { + $item['date_timestamp'] = $epoch; + } + } + + $this->items[$i] = $item; + } + } + elseif ( $this->is_rss() ) { + $this->channel['tagline'] = $this->channel['description']; + for ( $i = 0; $i < count($this->items); $i++) { + $item = $this->items[$i]; + if ( isset($item['description'])) + $item['summary'] = $item['description']; + if ( isset($item['content']['encoded'] ) ) + $item['atom_content'] = $item['content']['encoded']; + + if ( $this->is_rss() == '1.0' and isset($item['dc']['date']) ) { + $epoch = @parse_w3cdtf($item['dc']['date']); + if ($epoch and $epoch > 0) { + $item['date_timestamp'] = $epoch; + } + } + elseif ( isset($item['pubdate']) ) { + $epoch = @strtotime($item['pubdate']); + if ($epoch > 0) { + $item['date_timestamp'] = $epoch; + } + } + + $this->items[$i] = $item; + } + } + } + + + function is_rss () { + if ( $this->feed_type == RSS ) { + return $this->feed_version; + } + else { + return false; + } + } + + function is_atom() { + if ( $this->feed_type == ATOM ) { + return $this->feed_version; + } + else { + return false; + } + } + + /** + * return XML parser, and possibly re-encoded source + * + */ + function create_parser($source, $out_enc, $in_enc, $detect) { + if ( substr(phpversion(),0,1) == 5) { + $parser = $this->php5_create_parser($in_enc, $detect); + } + else { + list($parser, $source) = $this->php4_create_parser($source, $in_enc, $detect); + } + if ($out_enc) { + $this->encoding = $out_enc; + xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $out_enc); + } + + return array($parser, $source); + } + + /** + * Instantiate an XML parser under PHP5 + * + * PHP5 will do a fine job of detecting input encoding + * if passed an empty string as the encoding. + * + * All hail libxml2! + * + */ + function php5_create_parser($in_enc, $detect) { + // by default php5 does a fine job of detecting input encodings + if(!$detect && $in_enc) { + return xml_parser_create($in_enc); + } + else { + return xml_parser_create(''); + } + } + + /** + * Instaniate an XML parser under PHP4 + * + * Unfortunately PHP4's support for character encodings + * and especially XML and character encodings sucks. As + * long as the documents you parse only contain characters + * from the ISO-8859-1 character set (a superset of ASCII, + * and a subset of UTF-8) you're fine. However once you + * step out of that comfy little world things get mad, bad, + * and dangerous to know. + * + * The following code is based on SJM's work with FoF + * @see http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss + * + */ + function php4_create_parser($source, $in_enc, $detect) { + if ( !$detect ) { + return array(xml_parser_create($in_enc), $source); + } + + if (!$in_enc) { + if (preg_match('//m', $source, $m)) { + $in_enc = strtoupper($m[1]); + $this->source_encoding = $in_enc; + } + else { + $in_enc = 'UTF-8'; + } + } + + if ($this->known_encoding($in_enc)) { + return array(xml_parser_create($in_enc), $source); + } + + // the dectected encoding is not one of the simple encodings PHP knows + + // attempt to use the iconv extension to + // cast the XML to a known encoding + // @see http://php.net/iconv + + if (function_exists('iconv')) { + $encoded_source = iconv($in_enc,'UTF-8', $source); + if ($encoded_source) { + return array(xml_parser_create('UTF-8'), $encoded_source); + } + } + + // iconv didn't work, try mb_convert_encoding + // @see http://php.net/mbstring + if(function_exists('mb_convert_encoding')) { + $encoded_source = mb_convert_encoding($source, 'UTF-8', $in_enc ); + if ($encoded_source) { + return array(xml_parser_create('UTF-8'), $encoded_source); + } + } + + // else + $this->error("Feed is in an unsupported character encoding. ($in_enc) " . + "You may see strange artifacts, and mangled characters.", + E_USER_NOTICE); + + return array(xml_parser_create(), $source); + } + + function known_encoding($enc) { + $enc = strtoupper($enc); + if ( in_array($enc, $this->_KNOWN_ENCODINGS) ) { + return $enc; + } + else { + return false; + } + } + + function error ($errormsg, $lvl=E_USER_WARNING) { + // append PHP's error message if track_errors enabled + if ( isset($php_errormsg) ) { + $errormsg .= " ($php_errormsg)"; + } + if ( MAGPIE_DEBUG ) { + trigger_error( $errormsg, $lvl); + } + else { + error_log( $errormsg, 0); + } + + $notices = E_USER_NOTICE|E_NOTICE; + if ( $lvl&$notices ) { + $this->WARNING = $errormsg; + } else { + $this->ERROR = $errormsg; + } + } + + +} // end class RSS + +function map_attrs($k, $v) { + return "$k=\"$v\""; +} + +// patch to support medieval versions of PHP4.1.x, +// courtesy, Ryan Currie, ryan@digibliss.com + +if (!function_exists('array_change_key_case')) { + define("CASE_UPPER",1); + define("CASE_LOWER",0); + + + function array_change_key_case($array,$case=CASE_LOWER) { + if ($case=CASE_LOWER) $cmd=strtolower; + elseif ($case=CASE_UPPER) $cmd=strtoupper; + foreach($array as $key=>$value) { + $output[$cmd($key)]=$value; + } + return $output; + } + +} + +?> diff --git a/isis/src/docsys/assets/scripts/feed2js/magpie/rss_utils.inc b/isis/src/docsys/assets/scripts/feed2js/magpie/rss_utils.inc new file mode 100755 index 0000000000000000000000000000000000000000..2a29e72a9696598bd8f1eca21aa4f955ebf4b243 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/magpie/rss_utils.inc @@ -0,0 +1,67 @@ + + * Version: 0.51 + * License: GPL + * + * The lastest version of MagpieRSS can be obtained from: + * http://magpierss.sourceforge.net + * + * For questions, help, comments, discussion, etc., please join the + * Magpie mailing list: + * magpierss-general@lists.sourceforge.net + */ + + +/*======================================================================*\ + Function: parse_w3cdtf + Purpose: parse a W3CDTF date into unix epoch + + NOTE: http://www.w3.org/TR/NOTE-datetime +\*======================================================================*/ + +function parse_w3cdtf ( $date_str ) { + + # regex to match wc3dtf + $pat = "/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/"; + + if ( preg_match( $pat, $date_str, $match ) ) { + list( $year, $month, $day, $hours, $minutes, $seconds) = + array( $match[1], $match[2], $match[3], $match[4], $match[5], $match[6]); + + # calc epoch for current date assuming GMT + $epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year); + + $offset = 0; + if ( $match[10] == 'Z' ) { + # zulu time, aka GMT + } + else { + list( $tz_mod, $tz_hour, $tz_min ) = + array( $match[8], $match[9], $match[10]); + + # zero out the variables + if ( ! $tz_hour ) { $tz_hour = 0; } + if ( ! $tz_min ) { $tz_min = 0; } + + $offset_secs = (($tz_hour*60)+$tz_min)*60; + + # is timezone ahead of GMT? then subtract offset + # + if ( $tz_mod == '+' ) { + $offset_secs = $offset_secs * -1; + } + + $offset = $offset_secs; + } + $epoch = $epoch + $offset; + return $epoch; + } + else { + return -1; + } +} + +?> diff --git a/isis/src/docsys/assets/scripts/feed2js/magpie_debug.php b/isis/src/docsys/assets/scripts/feed2js/magpie_debug.php new file mode 100755 index 0000000000000000000000000000000000000000..3e8e0e010e775794eb0ec4fbaac20cecd023671e --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/magpie_debug.php @@ -0,0 +1,87 @@ +Example Output"; + echo "Channel: " . $rss->channel['title'] . "

    "; + echo "

    "; +} +else { + echo "Error: " . magpie_error(); +} +?> + +
    + RSS URL:
    + +
    + +

    Parsed Results (var_dump'ed)

    +
    +
    +
    + +Error:
    PHP compiled without XML support (--with-xml), Magpie won't work without PHP support for XML.
    \n"; + exit; + } + else { + echo "OK: Found an XML parser.
    \n"; + } + + if ( ! function_exists('gzinflate') ) { + echo "Warning: PHP compiled without Zlib support (--with-zlib). No support for GZIP encoding.
    \n"; + } + else { + echo "OK: Support for GZIP encoding.
    \n"; + } + + if ( ! (function_exists('iconv') and function_exists('mb_convert_encoding') ) ) { + echo "Warning: No support for iconv (--with-iconv) or multi-byte strings (--enable-mbstring)." . + "No support character set munging.
    \n"; + } + else { + echo "OK: Support for character munging.
    \n"; + } +} + +?> diff --git a/isis/src/docsys/assets/scripts/feed2js/magpie_simple.php b/isis/src/docsys/assets/scripts/feed2js/magpie_simple.php new file mode 100755 index 0000000000000000000000000000000000000000..ae84b5e174a046c75746368e389e2fd5aa8f9880 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/magpie_simple.php @@ -0,0 +1,28 @@ +channel['title'] . "

    "; + echo "

      "; + foreach ($rss->items as $item) { + $href = $item['link']; + $title = $item['title']; + echo "
    • $title
    • "; + } + echo "
    "; +} +?> + +
    + RSS URL:
    + +
    + +

    +

    Security Note:

    +This is a simple example script. If this was a real script we probably wouldn't allow strangers to submit random URLs, and we certainly wouldn't simply echo anything passed in the URL. Additionally its a bad idea to leave this example script lying around. +

    \ No newline at end of file diff --git a/isis/src/docsys/assets/scripts/feed2js/nosource.php b/isis/src/docsys/assets/scripts/feed2js/nosource.php new file mode 100755 index 0000000000000000000000000000000000000000..0e70486ecf6c08a9d708d5f314c75032bf819a2a --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/nosource.php @@ -0,0 +1,41 @@ + + + + + + No XML Source + + + +
    +

    XML error

    +

    There is an error in the requested URL as no xml source was provided. A correct request should look like:

    + + +

    +<script type="text/javascript" language="Javascript"
    src="feed2js.php?src=http://www.somesite.com/myfeed.xml"> +</script> +

    + +

    You should check your source code!

    + +
    + + diff --git a/isis/src/docsys/assets/scripts/feed2js/popup.js b/isis/src/docsys/assets/scripts/feed2js/popup.js new file mode 100644 index 0000000000000000000000000000000000000000..dd20b0c4b14bfcf4c586f59ab059ceb2038f9c51 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/popup.js @@ -0,0 +1,17 @@ +function popupfeed(url) { +/* + Use this function to generate a pop up window for item links generated + by the Feed2JS service. The name of this function must exactly be + popupfeed + + and you can use the code below to specify specific window features + See http://jade.mcli.dist.maricopa.edu/feed/index.php?s=mod +*/ + + // string to specify window features + + var myfeatures = "toolbar=no,location=no,directories=no,menubar=no,scrollbars=yes,status=yes,resizable=no,width=800,height=400"; + + thefeed = window.open( url, 'feed2jspop', myfeatures); + if (window.focus) {thefeed.focus()} +} diff --git a/isis/src/docsys/assets/scripts/feed2js/preview.php b/isis/src/docsys/assets/scripts/feed2js/preview.php new file mode 100644 index 0000000000000000000000000000000000000000..c97123b71f2d7d9bde67bd9612ecdca094da4357 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/preview.php @@ -0,0 +1,92 @@ +')) { + $src = preg_replace("/(\)/si", "SCRIPT DELETED", "$src"); + die("Warning! Attempt to inject javascript detected. Aborted and tracking log updated."); +} + +// update to full descriptions for html turned on +if ($html=='a') $desc = 0; + +// build parameter string for the feed2js url +$options = ''; +if ($chan != 'n') $options .= "&chan=$chan"; +if ($num != 0) $options .= "&num=$num"; +if ($desc != 0) $options .= "&desc=$desc"; +if ($date != 'n') $options .= "&date=$date"; +if ($tz != 'feed') $options .= "&tz=$tz"; +if ($targ != 'n') $options .= "&targ=$targ"; +if ($html != 'n') $html_options = "&html=$html"; +if ($utf == 'y') $options .= '&utf=y'; +if ($rss_box_id != '') $options .= "&css=$rss_box_id"; +if ($pc == 'y') $options .= '&pc=y'; + + +$rss_str = "feed2js.php?src=" . urlencode($src) . $options . $html_options; + +$noscript_rss_str = "feed2js.php?src=" . urlencode($src) . $options . '&html=y'; +?> + + + + + '; + } else { + echo ''; + } + ?> + Feed Sneak Preview + + + + + + + + + +
    +

    Look At Your Feed

    +

    Below is a preview of your feed using a basic style (learn how to customize this via the Feed2JS style pages). If this looks like the correct content and display, close this window and use the Generate JavaScript button to create your own web page code.

    + + + + +
    +
    + + +
    +
    + +
    + + + diff --git a/isis/src/docsys/assets/scripts/feed2js/readme.pdf b/isis/src/docsys/assets/scripts/feed2js/readme.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a1a28d31cbcb86d69511a1208c3aec1725a94070 Binary files /dev/null and b/isis/src/docsys/assets/scripts/feed2js/readme.pdf differ diff --git a/isis/src/docsys/assets/scripts/feed2js/style.php b/isis/src/docsys/assets/scripts/feed2js/style.php new file mode 100644 index 0000000000000000000000000000000000000000..3ca4e228df0cea94f6ddb33b889d810fd315aba2 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style.php @@ -0,0 +1,165 @@ + + + + + + Stylize Your JavaScript RSS Feed + + + + +
    + +

    Feed2JS: Style a Feed

    +

    Once you have built the code for your Feed2JS, you can see how the output of RSS content generated by Feed2JS can be customized by applying different style sheets. Each part of the feed has an identifier, allowing you to add styles to the box containing the feeds, the title, the item display, and the date posting text. A few sample styles are provided here; for more see the Feed2JS Style Center. +

    + +
    +

    Try on a Style Sheet

    +

    URL Enter the web address for the RSS Feed to "stylize"; if you do not have one handy, you can use the one below from CogDogBlog.
    +

    + +

    Style Selector
    +These are but a few style varieties to sample- you are invited to modify or create your own. If you have a snazzy, prettier version, please send it our way. For a blank slate, select the "none/template" style.
    + + +

    + +
    + +

    Using a Style Sheet

    +

    You will need to incorporate the CSS code or linkage in your own HTML files; there are two ways you can do this:

    + +
      +
    1. Insert the CSS directly into the HTML for the page that will display the feed. This methods is best for sites that only are displaying the feed on one or a few pages. Use the form below to find the style you desire, copy the CSS, and paste it somewhere into the <HEAD>...</HEAD> of your HTML file that contains the Feed2JS code, surrounded by the <style>...</style> tags shown below. +
      <style type="text/css"  media="all">
      +
      +<!--  this is where you paste the CSS provided by the form below -->
      +
      +</style>
    2. + +
    3. Link to an external style sheet. This method is best if you will be using the feeds on multiple pages, as the CSS is stored externally, and thus allows you to change the output display of many pages by editing a single file. Just copy the CSS provided by the form below, and paste it into a new text file. Save it as something called "myfeed.css". Think smart about where you decided to store this file, as other HTML pages that call it need to define a correct path to the file. Many web sites just create a top level directory named style and store all style sheet files in this directory.

      +Regardless, to connect the HTML file that contains the Feed2JS code to an external style sheet, insert this line into the <HEAD>...</HEAD> of your HTML. +
      +<link rel="stylesheet" href="style/myfeed.css" media="all">
      +
      +Remember again that the value of href= must be a correct relative path (or a full valid URL such as http://www.blah.com/style/myfeed.css) from the HTML file to the CSS file.
    4. +
    + +

    CSS classes

    + +

    This sketch represents the CSS classes created by Feed2JS.

    +
      +
    • rss-box defines the bounding div for the entire display- use to define borders, fill, etc.
    • +
    • rss-title the title of the feed and link style if displayed. Use with variants of rss-title a:link, rss-title a:hover, etc for rollowver styles
    • +
    • rss-items defines the unordered list <ul>...</ul> for the feed items- use to define the padding/margins for items.
    • +
    • rss-item display of each feed item description and title, <li>...</li> as well as the channel description, if displayed.
    • +
    • rss-item a: variant for the item title and link style
    • +
    • rss-date defines the display of item posting dates
    • +
    + +

    For any RSS 2.0 feeds with podcast enclosures, Feed2JS will provide a Play XXX link, where "XXX" is the extension of the media file, e.g. "mp3", "m4a", etc. The styles applied are modeled after Well Styled's Inline Buttons method. +

    +<div class="pod-play-box">
    +<a class="pod-play" href="podcastURL"><em>Play</em><span> File</span></a>
    +</div>
    +
    + + + +

    Custom colors may be achieved by editing appropriate foreground and background colors from the base styles (emphasized below):

    +
    +.pod-play {
    +   _width:12em;
    +   margin: 0 0.2em; padding: 0.1em 0; _padding:0;
    +   
    +   white-space:nowrap;
    +   text-decoration: none;
    +   vertical-align:middle;
    +   background: #fb6;
    +   color: black;
    +   }
    +.pod-play em {
    +   _width:1em; _cursor:hand;
    +   font-style: normal;
    +   margin:0; padding: 0.1em 0.5em;
    +   background: white;
    +   color: #222;  
    +   }
    +.pod-play span {
    +   _width:1em; _cursor:hand;
    +   margin:0; padding: 0.1em 0.5em 0.1em 0.3em;
    +   }
    +.pod-play:hover {
    +   background: #666;
    +   color: white;  
    +   }
    +.pod-play:hover em {
    +   background: black;
    +   color: white  
    +   }
    +
    + + +
    + +

    Advanced: Two Styles in One Page

    +

    If you have more than one feed displayed per page, you can assign different styles to each display. You will need a solid understanding of CSS and inheritance to get this to work!.

    + +

    By supplying a value for CSS Custom Class in the build form you can now create different top level classes. The value passed will create a CSS class named rss-box-XXXX where XXXX is this value. This implies that you may have to define more specific classes for the other classes listed above, or use the top level rss-box-XXXX classes to say define a different background color.

    + +

    See two examples:

    +
      +
    • Two Completely Different Styles. The second style has a value of css=spirit, so all CSS elements are defined to be a descendant of this class.
    • + +
    • Two Similar Styles. In this case, the only difference is the background color, which can be specified in the rss_box_w and rss_box_g classes.
    • +
    + + +
    + + + + + diff --git a/isis/src/docsys/assets/scripts/feed2js/style/.css b/isis/src/docsys/assets/scripts/feed2js/style/.css new file mode 100644 index 0000000000000000000000000000000000000000..78d6e436fd407bf4975c5c3160c08dc1b1ec8492 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/.css @@ -0,0 +1,103 @@ +/* begin styles for RSS Feed */ + + + +.rss_box { + + margin: 1em; + + width: 300px; + + background-color: #99CCFF; + + border: 1px solid ##5F74CC; + + + +} + +.rss_items { + + margin-top:0px; + + padding:0.5em; 0.5em; + + margin-left:0px; + + color:##0099ff; + +} + +p.rss_title {padding:0.5em;} + +.rss_title { + + text-decoration: none; + + font-family: verdana, sans-serif; + + font-size: 85%; + + background-color:#330066; + + color:#ffffff; + + font-weight:bold; + + margin: 0px; + + padding:0em; + + text-align: left; + +} + + + +.rss_item { + + font-family: verdana, arial, sans-serif; + + font-size: 0.75em; + + font-weight : normal; + + list-style:none; + + padding-bottom:1em; + +} + + + +.rss_item a { + + color:blue; + + font-size: 105%; + + font-weight:bold; + + font-family:arial, sans-serif; + + } + + + +.rss_item a:visited { + + color:#330066; + +} + + + +.rss_date { + + font-size: 85%; + + font-weight : normal; + + color: #F60; + + } \ No newline at end of file diff --git a/isis/src/docsys/assets/scripts/feed2js/style/basic1.css b/isis/src/docsys/assets/scripts/feed2js/style/basic1.css new file mode 100755 index 0000000000000000000000000000000000000000..8765b8c4831e2182221eef66f2a4acc65bec8547 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/basic1.css @@ -0,0 +1,80 @@ +/* begin styles for RSS Feed */ + +.rss-box { + margin: 10px 5%; + padding: 4px 8px; + + background-color: #ededed; + border: 2px dashed #7485CA; +} + +.rss-title, rss-title a { + font-family: "American Typewriter", "Trebuchet MS", Trebuchet, Lucida, sans-serif; + font-size: 18px; + font-weight:bold; + margin: 5px 0; + padding: 0; + letter-spacing: 1px; +} + +.rss-items { + +} + +.rss-item { + font-family: verdana, arial, sans-serif; + font-size: 13px; + font-weight : bold; + margin: 8px 0; +} + +.rss-item a:link, .rss-item a:visited, .rss-item a:active { + text-decoration : none; + border-bottom: 1px solid #ededed; + color: #88b; + } + +.rss-item a:hover { + text-decoration : none; + color: #e0861e; + border-bottom: 1px dotted #e0861e; + } + +.rss-date { + font-size: 11px; + font-weight : normal; + color: #F60; + } + +/* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ + +.pod-play { + _width:12em; + margin: 0 0.2em; padding: 0.1em 0; _padding:0; + + white-space:nowrap; + text-decoration: none; + vertical-align:middle; + background: #fb6; + color: black; + } +.pod-play em { + _width:1em; _cursor:hand; + font-style: normal; + margin:0; padding: 0.1em 0.5em; + background: white; + color: #222; + } +.pod-play span { + _width:1em; _cursor:hand; + margin:0; padding: 0.1em 0.5em 0.1em 0.3em; + } +.pod-play:hover { + background: #666; + color: white; + } +.pod-play:hover em { + background: black; + color: white + } + diff --git a/isis/src/docsys/assets/scripts/feed2js/style/bbc_style.css b/isis/src/docsys/assets/scripts/feed2js/style/bbc_style.css new file mode 100644 index 0000000000000000000000000000000000000000..9a55b6f31354b4a081daf1d36889aa9c4b8d9d6b --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/bbc_style.css @@ -0,0 +1 @@ +/* begin styles for RSS Feed */ .rss-box { margin: 0.5em; width: 200px; background-color: #FFFFCC; border: 7px solid #990000; } .rss-items { margin-top:0px; padding:0.5em; 0.5em; margin-left:0px; color: #FFFFFF; } p.rss-title {padding:0.5em;} .rss-title { text-decoration: none; font-family: small tahoma, "Bitstream Vera Sans", "Trebuchet MS", "Lucida Grande", lucida, helvetica, sans-serif; font-size: 15px; background-color:#990000; color:white; font-weight:bold; margin: 0px; padding:0em; text-align: left; } .rss-item { font-family: small tahoma, "Bitstream Vera Sans", "Trebuchet MS", "Lucida Grande", lucida, helvetica, sans-serif; font-size: 10px; font-weight : normal; list-style:none; padding-bottom:1em; } .rss-item a { text-decoration : none; color: #330066; font-size: 12px; font-weight:light; font-family:small tahoma, "Bitstream Vera Sans", "Trebuchet MS", "Lucida Grande", lucida, helvetica, sans-serif; } .rss-item a:visited { color:white; } .rss-date { font-size: 85%; font-weight : normal; color: #fff; } /* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ .pod-play { _width:12em; margin: 0 0.2em; padding: 0.1em 0; _padding:0; white-space:nowrap; text-decoration: none; vertical-align:middle; background: #fb6; color: black; } .pod-play em { _width:1em; _cursor:hand; font-style: normal; margin:0; padding: 0.1em 0.5em; background: white; color: #222; } .pod-play span { _width:1em; _cursor:hand; margin:0; padding: 0.1em 0.5em 0.1em 0.3em; } .pod-play:hover { background: #666; color: white; } .pod-play:hover em { background: black; color: white } \ No newline at end of file diff --git a/isis/src/docsys/assets/scripts/feed2js/style/blackbox.css b/isis/src/docsys/assets/scripts/feed2js/style/blackbox.css new file mode 100644 index 0000000000000000000000000000000000000000..dc56eea9fe63709813f11d0f04c40853e0bc86ec --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/blackbox.css @@ -0,0 +1 @@ +/* begin styles for RSS Feed */ .rss-box { margin: 1em; width: 200px; background-color: #000000; border: 1px dashed #240; } .rss-items { margin-top:0px; padding:0.5em; 0.5em; margin-left:0px; color:#FFFFFF; } p.rss-title {padding:0.5em;} .rss-title { text-decoration: none; font-family: small tahoma, "Bitstream Vera Sans", "Trebuchet MS", "Lucida Grande", lucida, helvetica, sans-serif; font-size: 12px; background-color:#000; color:#fff; font-weight:bold; margin: 0px; padding:0em; text-align: left; } .rss-item { font-family: small tahoma, "Bitstream Vera Sans", "Trebuchet MS", "Lucida Grande", lucida, helvetica, sans-serif; font-size: 12px; font-weight : normal; list-style:none; padding-bottom:1em; } .rss-item a { text-decoration : none; color: white; font-size: 12px; font-weight:light; font-family:small tahoma, "Bitstream Vera Sans", "Trebuchet MS", "Lucida Grande", lucida, helvetica, sans-serif; } .rss-item a:visited { color:white; } .rss-date { font-size: 85%; font-weight : normal; color: #fff; } /* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ .pod-play { _width:12em; margin: 0 0.2em; padding: 0.1em 0; _padding:0; white-space:nowrap; text-decoration: none; vertical-align:middle; background: #fb6; color: black; } .pod-play em { _width:1em; _cursor:hand; font-style: normal; margin:0; padding: 0.1em 0.5em; background: white; color: #222; } .pod-play span { _width:1em; _cursor:hand; margin:0; padding: 0.1em 0.5em 0.1em 0.3em; } .pod-play:hover { background: #666; color: white; } .pod-play:hover em { background: black; color: white } \ No newline at end of file diff --git a/isis/src/docsys/assets/scripts/feed2js/style/css_classes.gif b/isis/src/docsys/assets/scripts/feed2js/style/css_classes.gif new file mode 100644 index 0000000000000000000000000000000000000000..02298dd1ec136702ec732d5ef5a1df7add8075d5 Binary files /dev/null and b/isis/src/docsys/assets/scripts/feed2js/style/css_classes.gif differ diff --git a/isis/src/docsys/assets/scripts/feed2js/style/dog.css b/isis/src/docsys/assets/scripts/feed2js/style/dog.css new file mode 100644 index 0000000000000000000000000000000000000000..de7ac552da6af9d4200e7eb8efa31d0728d49855 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/dog.css @@ -0,0 +1,86 @@ +/* begin styles for RSS Feed */ + +.rss-box { + width: 500px; + background:#fff url(dog.jpg) bottom left no-repeat; + padding: 5px 10px 5px 120px; + border-left: 8px solid #111; + border-top: 8px solid #111; +} + +.rss-title, .rss-title a:link +{ + font-family: Georgia, "Times New Roman", Times, serif; + font-size: 44px; + font-weight: bold; + text-decoration:none; + margin: 5px 0; + padding: 0; + text-align:right; + +} + +.rss-title a:visited, .rss-title a:active { + color: #922; +} + +rss-title a:hover { +text-decoration:underline; +} + +.rss-items { + +} + +.rss-item { + font-family: Arial, Verdana, sans-serif; + font-size: 14px; + margin-bottom: 1em +} + +.rss-item a:link, .rss-item a:visited, .rss-item a:active { + text-decoration : none; + color: #26590D; + } + +.rss-item a:hover { + text-decoration : underline; + color: #F66025; + } + +.rss-date { + font-size: 11px; + font-weight : normal; + color: #338; + } +/* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ + +.pod-play { + _width:12em; + margin: 0 0.2em; padding: 0.1em 0; _padding:0; + + white-space:nowrap; + text-decoration: none; + vertical-align:middle; + background: #fb6; + color: black; + } +.pod-play em { + _width:1em; _cursor:hand; + font-style: normal; + margin:0; padding: 0.1em 0.5em; + background: white; + color: #222; + } +.pod-play span { + _width:1em; _cursor:hand; + margin:0; padding: 0.1em 0.5em 0.1em 0.3em; + } +.pod-play:hover { + background: #666; + color: white; + } +.pod-play:hover em { + background: black; + color: white + } diff --git a/isis/src/docsys/assets/scripts/feed2js/style/dog.jpg b/isis/src/docsys/assets/scripts/feed2js/style/dog.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e0c5ccbc85d520eef9545799abe69fbeca1c0ed4 Binary files /dev/null and b/isis/src/docsys/assets/scripts/feed2js/style/dog.jpg differ diff --git a/isis/src/docsys/assets/scripts/feed2js/style/essc.css b/isis/src/docsys/assets/scripts/feed2js/style/essc.css new file mode 100644 index 0000000000000000000000000000000000000000..2983906fb37558496900e7c23c56646402c800b4 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/essc.css @@ -0,0 +1 @@ +/* begin styles for RSS Feed */ .rss-box { margin: 1em; width: 250px; background-color: #CCCCFF; border: 1px solid #9B72CF; } .rss-items { margin-top:0px; padding:0.5em; 0.5em; margin-left:0px; color:#000000; } p.rss-title {padding:0.5em;} .rss-title { text-decoration: none; font-family: verdana, sans-serif; font-size: 85%; background-color:#A4A4FF; color:#ffffff; font-weight:bold; margin: 0px; padding:0em; text-align: left; } .rss-item { font-family: verdana, arial, sans-serif; font-size: 0.75em; font-weight : normal; list-style:none; padding-bottom:1em; } .rss-item a { text-decoration : underline; color:blue; font-size: 105%; font-weight:bold; font-family:arial, sans-serif; } .rss-item a:visited { color:purple; } .rss-date { font-size: 85%; font-weight : normal; color: #F60; } /* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ .pod-play { _width:12em; margin: 0 0.2em; padding: 0.1em 0; _padding:0; white-space:nowrap; text-decoration: none; vertical-align:middle; background: #fb6; color: black; } .pod-play em { _width:1em; _cursor:hand; font-style: normal; margin:0; padding: 0.1em 0.5em; background: white; color: #222; } .pod-play span { _width:1em; _cursor:hand; margin:0; padding: 0.1em 0.5em 0.1em 0.3em; } .pod-play:hover { background: #666; color: white; } .pod-play:hover em { background: black; color: white } \ No newline at end of file diff --git a/isis/src/docsys/assets/scripts/feed2js/style/feed2js.jpg b/isis/src/docsys/assets/scripts/feed2js/style/feed2js.jpg new file mode 100644 index 0000000000000000000000000000000000000000..094f15cfe3a786ac0c8776f74cd5e32156df42ad Binary files /dev/null and b/isis/src/docsys/assets/scripts/feed2js/style/feed2js.jpg differ diff --git a/isis/src/docsys/assets/scripts/feed2js/style/greenbars.css b/isis/src/docsys/assets/scripts/feed2js/style/greenbars.css new file mode 100644 index 0000000000000000000000000000000000000000..d761e428646643f93bf777dfeda3ac4de48ac57c --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/greenbars.css @@ -0,0 +1,84 @@ +/* begin styles for RSS Feed */ + +.rss-box { + width: 240px; + padding: 4px 8px; + background-color: #CF9; + border-left: 60px solid #238912; + border-top: 1px dotted #238912; + border-right: 1px dotted #238912; + border-bottom: 1px dotted #238912; +} + +.rss-title, .rss-title a:link +{ + font-family: Arial, Verdana, sans-serif; + font-size: 30px; + font-weight: bold; + margin: 5px 0; + padding: 0; + text-align:center; + +} + +.rss-title a:visited, .rss-title a:active, .rss-title a:hover { + color: #692; +} + +.rss-items { + list-style:none; + +} + +.rss-item { + font-family: Arial, Verdana, sans-serif; + font-size: 11px; + margin-bottom: 1em +} + +.rss-item a:link, .rss-item a:visited, .rss-item a:active { + text-decoration : none; + color: #26590D; + } + +.rss-item a:hover { + text-decoration : underline; + color: #F66025; + } + +.rss-date { + font-size: 10px; + font-weight : normal; + color: #333; + } +/* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ + +.pod-play { + _width:12em; + margin: 0 0.2em; padding: 0.1em 0; _padding:0; + + white-space:nowrap; + text-decoration: none; + vertical-align:middle; + background: #fb6; + color: black; + } +.pod-play em { + _width:1em; _cursor:hand; + font-style: normal; + margin:0; padding: 0.1em 0.5em; + background: white; + color: #222; + } +.pod-play span { + _width:1em; _cursor:hand; + margin:0; padding: 0.1em 0.5em 0.1em 0.3em; + } +.pod-play:hover { + background: #666; + color: white; + } +.pod-play:hover em { + background: black; + color: white + } diff --git a/isis/src/docsys/assets/scripts/feed2js/style/kp.css b/isis/src/docsys/assets/scripts/feed2js/style/kp.css new file mode 100644 index 0000000000000000000000000000000000000000..8666524069edc8f9c41f5fdee4abb5da21a08c9e --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/kp.css @@ -0,0 +1 @@ +/* begin styles for RSS Feed */ .rss-box { margin: 5px 5%; padding: 4px 8px; width: 219px; background-color: #ffffff; } .rss-title, rss-title a { font-family: verdana, arial, sans-serif; font-size: 11; font-weight:normal; margin: 0px 0; padding: 0; letter-spacing: 1px; } .rss-items { } .rss-item { font-family: verdana, arial, sans-serif; font-size: 11px; font-weight : normal; margin: 0px 0; } .rss-item a:link, .rss-item a:visited, .rss-item a:active { text-decoration : none; border-bottom: 1px solid #336699; color: #336699; } .rss-item a:hover { text-decoration : none; color: #336699; border-bottom: 1px dotted #336699; } .rss-date { font-size: 11px; font-weight : normal; color: #336699; } /* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ .pod-play { _width:12em; margin: 0 0.2em; padding: 0.1em 0; _padding:0; white-space:nowrap; text-decoration: none; vertical-align:middle; background: #fb6; color: black; } .pod-play em { _width:1em; _cursor:hand; font-style: normal; margin:0; padding: 0.1em 0.5em; background: white; color: #222; } .pod-play span { _width:1em; _cursor:hand; margin:0; padding: 0.1em 0.5em 0.1em 0.3em; } .pod-play:hover { background: #666; color: white; } .pod-play:hover em { background: black; color: white } \ No newline at end of file diff --git a/isis/src/docsys/assets/scripts/feed2js/style/main.css b/isis/src/docsys/assets/scripts/feed2js/style/main.css new file mode 100644 index 0000000000000000000000000000000000000000..98839bf7e6e09e7a991eb68d7f5061415d1a4455 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/main.css @@ -0,0 +1,75 @@ +body { + background:#ededed; + font-family: "Trebuchet MS", verdana, arial, helvetica, sans-sarif; + font-size: small; + margin:0; + padding:0; +} + +#content { + background:#fff; + margin: 20px 5%; + padding: 4px 20px; + border: 1px dotted #777; +} + +p { + + margin: 0 0 1em; + } + +.first { margin-top:0;} + +h1, h2, h3, h4 { margin-bottom:0;} + +.spread, .nospread { + margin-top:0; + margin-left:20px; + } + +.spread li { + margin-bottom:0.5em; +} + +pre { + border: #777777 1px solid; + padding: 0.5em; + margin-left: 1em; + margin-right: 2em; + white-space: pre; + background-color: #e6e6e6; + color: black; +} + +#badge { + float:right; + padding: 4px; + background: #ededed; + border: 1px solid #777; + font-size: 10px; + margin: 4px 0 4px 1em; + text-align:center; +} + +.badge-header { + background-color: #f60; + color: #fff; + font-size: 12px; + margin: 0 4px 0 0; + padding:0; +} + +#content .caption { + font-size: 11px; + color: #555; + text-align:center; + margin: 2em 0; +} + +#footer { + margin: 60px 20% 10px; +} + +#footer p.smallprint { + font-family: "American Typewriter", "Courier New", Courier, monospaced; font-size: 11px; color: #222; padding: 0.5em 1em; background-color:#ccf;} + diff --git a/isis/src/docsys/assets/scripts/feed2js/style/marooned2.css b/isis/src/docsys/assets/scripts/feed2js/style/marooned2.css new file mode 100644 index 0000000000000000000000000000000000000000..70719bd219e5f10b683131e4106bf6e7a22f3368 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/marooned2.css @@ -0,0 +1 @@ +/* begin styles for RSS Feed */ h2 { color: maroon; font-size: 170%; text-decoration: none font-weight: bold; ffont-family: FontName, Tahoma } h3 { color: maroon; font-size: 140%; text-decoration: none font-weight: bold; text-indent: 5em; ffont-family: FontName, Tahoma } .rss-box { background-color: white; margin: 10px 15%; padding: 4px 8px; border: solid 5px maroon } .rss-title, rss-title a { font-size: 120%; font-family: FontName, Tahoma; font-weight: bold; letter-spacing: 1px; margin: 5px 0; padding: 0 } .rss-items { list-style-type: none; list-style-image: url("http://142.27.144.70/gerry/pointer.jpg") } .rss-item { color: black; font-size: 75%; font-family: Tahoma; font-weight: bold; margin: 8px 0 } .rss-item a:link, .rss-item a:visited { color: maroon; font-size: 120%; text-decoration: none } .rss-item a:hover { color: gray; text-decoration: underline } .rss-date { color: gray; font-size: 80%; font-weight: normal } /* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ .pod-play { _width:12em; margin: 0 0.2em; padding: 0.1em 0; _padding:0; white-space:nowrap; text-decoration: none; vertical-align:middle; background: #fb6; color: black; } .pod-play em { _width:1em; _cursor:hand; font-style: normal; margin:0; padding: 0.1em 0.5em; background: white; color: #222; } .pod-play span { _width:1em; _cursor:hand; margin:0; padding: 0.1em 0.5em 0.1em 0.3em; } .pod-play:hover { background: #666; color: white; } .pod-play:hover em { background: black; color: white } \ No newline at end of file diff --git a/isis/src/docsys/assets/scripts/feed2js/style/nobullets.css b/isis/src/docsys/assets/scripts/feed2js/style/nobullets.css new file mode 100644 index 0000000000000000000000000000000000000000..1bf7eaa126f9f73491184a185fc861bf97b186a5 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/nobullets.css @@ -0,0 +1 @@ +/* begin styles for RSS Feed This is the most basic style to use for a list with no bullets */ .rss-box { width: 300px; background-color: #ffffff; } .rss-title, rss-title a { margin: 0px 0; padding: 0; } .rss-items { list-style:none; margin:0; padding:0; } .rss-item { font-size: x-small; margin-bottom: 1em;; } .rss-item a:link, .rss-item a:visited, .rss-item a:active { } .rss-item a:hover { } .rss-date { font-size: xx-small; } /* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ .pod-play { _width:12em; margin: 0 0.2em; padding: 0.1em 0; _padding:0; white-space:nowrap; text-decoration: none; vertical-align:middle; background: #fb6; color: black; } .pod-play em { _width:1em; _cursor:hand; font-style: normal; margin:0; padding: 0.1em 0.5em; background: white; color: #222; } .pod-play span { _width:1em; _cursor:hand; margin:0; padding: 0.1em 0.5em 0.1em 0.3em; } .pod-play:hover { background: #666; color: white; } .pod-play:hover em { background: black; color: white } \ No newline at end of file diff --git a/isis/src/docsys/assets/scripts/feed2js/style/none.css b/isis/src/docsys/assets/scripts/feed2js/style/none.css new file mode 100644 index 0000000000000000000000000000000000000000..8733a52b5eb608c87971c8a49160f5b98d56a004 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/none.css @@ -0,0 +1,61 @@ +/* no css just to show an unstyled feed + and to provide a template for creating new styles */ + + .rss-box { + + } + + .rss-title, rss-title a { + + } + + .rss-items { + +} + + +.rss-item a:link, .rss-item a:visited, .rss-item a:active { + +} + +.rss-item a:hover { + +} + +.rss-date { + +} + + + +/* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ + +.pod-play { + _width:12em; + margin: 0 0.2em; padding: 0.1em 0; _padding:0; + + white-space:nowrap; + text-decoration: none; + vertical-align:middle; + background: #fb6; + color: black; + } +.pod-play em { + _width:1em; _cursor:hand; + font-style: normal; + margin:0; padding: 0.1em 0.5em; + background: white; + color: #222; + } +.pod-play span { + _width:1em; _cursor:hand; + margin:0; padding: 0.1em 0.5em 0.1em 0.3em; + } +.pod-play:hover { + background: #666; + color: white; + } +.pod-play:hover em { + background: black; + color: white + } diff --git a/isis/src/docsys/assets/scripts/feed2js/style/outlive.css b/isis/src/docsys/assets/scripts/feed2js/style/outlive.css new file mode 100644 index 0000000000000000000000000000000000000000..ea68e6449ea0a66fd001efadac791daecf29281a --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/outlive.css @@ -0,0 +1,76 @@ +/* begin styles for RSS Feed */ + +.rss-box { + margin: 1em; + width: 98%; + background-color: #EEE; + border: 1px solid silver; + +} +.rss-items { + margin-top:0px; + padding:0.5em; 0.5em; + margin-left:0px; + color:#000000; +} +p.rss-title {padding:0.5em;} +.rss-title { + font-size: 8pt; + background-color: silver; + color: gray; + font-weight:bold; + text-align: left; +} + +.rss-item { + font-size: 7pt; + list-style:none; + padding-bottom:1em; +} + +.rss-item a { + color:navy; + font-size: 9pt; + font-weight:bold; + } + +.rss-item a:visited { + color: black; +} + +.rss-date { + font-size: 7pt; + color: red; + } + +/* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ + +.pod-play { + _width:12em; + margin: 0 0.2em; padding: 0.1em 0; _padding:0; + + white-space:nowrap; + text-decoration: none; + vertical-align:middle; + background: #fb6; + color: black; + } +.pod-play em { + _width:1em; _cursor:hand; + font-style: normal; + margin:0; padding: 0.1em 0.5em; + background: white; + color: #222; + } +.pod-play span { + _width:1em; _cursor:hand; + margin:0; padding: 0.1em 0.5em 0.1em 0.3em; + } +.pod-play:hover { + background: #666; + color: white; + } +.pod-play:hover em { + background: black; + color: white + } diff --git a/isis/src/docsys/assets/scripts/feed2js/style/play-button.jpg b/isis/src/docsys/assets/scripts/feed2js/style/play-button.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1768671a41992b3cfb9f2199776940e7655e06d7 Binary files /dev/null and b/isis/src/docsys/assets/scripts/feed2js/style/play-button.jpg differ diff --git a/isis/src/docsys/assets/scripts/feed2js/style/plum.css b/isis/src/docsys/assets/scripts/feed2js/style/plum.css new file mode 100644 index 0000000000000000000000000000000000000000..3dc43875d6f84aad2174a7a1cdd3e17a072f6edb --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/plum.css @@ -0,0 +1 @@ +/* begin styles for RSS Feed */ .rss-box { margin: 1em; width: 250px; background-color: #99CCFF; border: 1px solid ##5F74CC; } .rss-items { margin-top:0px; padding:0.5em; 0.5em; margin-left:0px; color:##0099ff; } p.rss-title {padding:0.5em;} .rss-title { text-decoration: none; font-family: verdana, sans-serif; font-size: 85%; background-color:#330066; color:#ffffff; font-weight:bold; margin: 0px; padding:0em; text-align: left; } .rss-item { font-family: verdana, arial, sans-serif; font-size: 0.75em; font-weight : normal; list-style:none; padding-bottom:1em; } .rss-item a { color:blue; font-size: 105%; font-weight:bold; font-family:arial, sans-serif; } .rss-item a:visited { color:#330066; } .rss-date { font-size: 85%; font-weight : normal; color: #F60; } /* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ .pod-play { _width:12em; margin: 0 0.2em; padding: 0.1em 0; _padding:0; white-space:nowrap; text-decoration: none; vertical-align:middle; background: #fb6; color: black; } .pod-play em { _width:1em; _cursor:hand; font-style: normal; margin:0; padding: 0.1em 0.5em; background: white; color: #222; } .pod-play span { _width:1em; _cursor:hand; margin:0; padding: 0.1em 0.5em 0.1em 0.3em; } .pod-play:hover { background: #666; color: white; } .pod-play:hover em { background: black; color: white } \ No newline at end of file diff --git a/isis/src/docsys/assets/scripts/feed2js/style/rss.css b/isis/src/docsys/assets/scripts/feed2js/style/rss.css new file mode 100644 index 0000000000000000000000000000000000000000..e8dc2c7c1960b7619eb657ac7ff8141a8aa73c62 --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/rss.css @@ -0,0 +1 @@ +/* begin styles for RSS Feed */ .rss-box { margin: 10px o%; padding: 4px 8px; width: 250px; background-color: #ededed; border: 2px dashed #7485CA; } .rss-title, rss-title a { font-family: "American Typewriter", "Trebuchet MS", Trebuchet, Lucida, sans-serif; font-size: 13px; font-weight:bold; margin: 5px 0; padding: 0; letter-spacing: 1px; } .rss-items { } .rss-item { font-family: verdana, arial, sans-serif; font-size: 8px; font-weight : bold; margin: 8px 0; } .rss-item a:link, .rss-item a:visited, .rss-item a:active { text-decoration : none; border-bottom: 1px solid #ededed; color: #88b; } .rss-item a:hover { text-decoration : none; color: #e0861e; border-bottom: 1px dotted #e0861e; } .rss-date { font-size: 11px; font-weight : normal; color: #F60; } /* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ .pod-play { _width:12em; margin: 0 0.2em; padding: 0.1em 0; _padding:0; white-space:nowrap; text-decoration: none; vertical-align:middle; background: #fb6; color: black; } .pod-play em { _width:1em; _cursor:hand; font-style: normal; margin:0; padding: 0.1em 0.5em; background: white; color: #222; } .pod-play span { _width:1em; _cursor:hand; margin:0; padding: 0.1em 0.5em 0.1em 0.3em; } .pod-play:hover { background: #666; color: white; } .pod-play:hover em { background: black; color: white } \ No newline at end of file diff --git a/isis/src/docsys/assets/scripts/feed2js/style/sekodeng.css b/isis/src/docsys/assets/scripts/feed2js/style/sekodeng.css new file mode 100644 index 0000000000000000000000000000000000000000..928416e33ca15523f7ea5e4cc9218c43aa99857b --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/sekodeng.css @@ -0,0 +1 @@ +/* begin styles for RSS Feed */ .rss-box { margin: 1em; width: 160px; background-color: #333333; border: 1px solid #000000; } .rss-items { margin-top:0px; padding:0.5em; 0.5em; margin-left:0px; color:#000000; } p.rss-title {padding:0.5em;} .rss-title { font-size: 8pt; background-color: #000000; color: #f76b08; font-weight:bold; text-align: center; } .rss-item { color:#DFDFDF; font-size: 7pt; list-style:none; padding-bottom:1em; } .rss-item a { color:#f67b08; font-size: 8pt; font-weight:bold; } .rss-item a:visited { color: #f67b08; } .rss-item a:hover { color: #00FFFF; } .rss-date { font-size: 7pt; color: #f76b08; } /* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ .pod-play { _width:12em; margin: 0 0.2em; padding: 0.1em 0; _padding:0; white-space:nowrap; text-decoration: none; vertical-align:middle; background: #fb6; color: black; } .pod-play em { _width:1em; _cursor:hand; font-style: normal; margin:0; padding: 0.1em 0.5em; background: white; color: #222; } .pod-play span { _width:1em; _cursor:hand; margin:0; padding: 0.1em 0.5em 0.1em 0.3em; } .pod-play:hover { background: #666; color: white; } .pod-play:hover em { background: black; color: white } \ No newline at end of file diff --git a/isis/src/docsys/assets/scripts/feed2js/style/style_pile.php b/isis/src/docsys/assets/scripts/feed2js/style/style_pile.php new file mode 100644 index 0000000000000000000000000000000000000000..831179c8982b4fa8555e1f01bb19ea15e8a1224c --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/style_pile.php @@ -0,0 +1,20 @@ + title +$mystyles = array( + 'basic1'=> 'Basic Blue', + 'bbc_style' => 'BBC', + 'blackbox' => 'Blackbox', + 'dog' => 'Dog\'s Eye View', + 'essc' => 'ESSC', + 'greenbars' => 'Green Bars', + 'kp' => 'KP', + 'marooned2' => 'Marooned', + 'none' => 'No Style / Blank Template', + 'nobullets' => 'No Bullets', + 'outlive' => 'OutlivE', + 'plum' => 'Plum', + 'princessthing' => 'Princess', + 'sekodeng' => 'Sekodeng', + 'zanestate' => 'Zanestate Yahoo', + ); +?> diff --git a/isis/src/docsys/assets/scripts/feed2js/style/zanestate.css b/isis/src/docsys/assets/scripts/feed2js/style/zanestate.css new file mode 100644 index 0000000000000000000000000000000000000000..90c71bf2f18144aa0ecbf744792a739b7b390f7a --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style/zanestate.css @@ -0,0 +1,85 @@ +/* begin styles for RSS Feed */ + +.rss-box { + margin: 1em; + width: 250px; + background-color: #F1F1FD; + border: 1px solid #9B72CF; + +} +.rss-items { + margin-top:0px; + padding:0.5em; 0.5em; + margin-left:0px; + color:#000000; +} +p.rss-title {padding:0.5em;} +.rss-title { + text-decoration: none; + font-family: verdana, sans-serif; + font-size: 85%; + background-color:#9B72CF; + color:#ffffff; + font-weight:bold; + margin: 0px; + padding:0em; + text-align: left; +} + +.rss-item { + font-family: verdana, arial, sans-serif; + font-size: 0.75em; + font-weight : normal; + list-style:none; + padding-bottom:1em; +} + +.rss-item a { + text-decoration : underline; + color:blue; + font-size: 105%; + font-weight:bold; + font-family:arial, sans-serif; + } + +.rss-item a:visited { + color:purple; +} + +.rss-date { + font-size: 85%; + font-weight : normal; + color: #F60; + } + +/* buttons modeled from http://www.wellstyled.com/css-inline-buttons.html */ + +.pod-play { + _width:12em; + margin: 0 0.2em; padding: 0.1em 0; _padding:0; + + white-space:nowrap; + text-decoration: none; + vertical-align:middle; + background: #fb6; + color: black; + } +.pod-play em { + _width:1em; _cursor:hand; + font-style: normal; + margin:0; padding: 0.1em 0.5em; + background: white; + color: #222; + } +.pod-play span { + _width:1em; _cursor:hand; + margin:0; padding: 0.1em 0.5em 0.1em 0.3em; + } +.pod-play:hover { + background: #666; + color: white; + } +.pod-play:hover em { + background: black; + color: white + } diff --git a/isis/src/docsys/assets/scripts/feed2js/style_preview.php b/isis/src/docsys/assets/scripts/feed2js/style_preview.php new file mode 100644 index 0000000000000000000000000000000000000000..30e3f35828dfaf59c0ed864da13ce8ff0235ab9a --- /dev/null +++ b/isis/src/docsys/assets/scripts/feed2js/style_preview.php @@ -0,0 +1,98 @@ + + + + + + + Styled Feed + + + \n" . stripslashes($new_css) . "\n\n"; + } else { + echo ''; + } + ?> + + + + + + + +
    +

    Style Preview!

    + +

    Here is a preview of the style sheet applied to the RSS Feed . The URL to generate this view is: +

    + +
    + + + + +

    CSS Applied

    +

    Below is the CSS applied here, yours for copy and pasting pleasure. See below for a description of the classes provided and refer to the Feed2JS style selection site for more details on where to use this code.

    + +

    You may also use the form below to modify the CSS to experiment with your own variants.

    + +
    + + + +

    Make changes and +or

    + +
    + +

    CSS classes

    + +

    This sketch represents the CSS classes created by Feed2JS.

    +
      +
    • rss-box defines the bounding div for the entire display- use to define borders, fill, etc.
    • +
    • rss-title the title of the feed and link style if displayed. Use with variants of rss-title a:link, rss-title a:hover, etc for rollover styles
    • +
    • rss-items defines the unordered list <ul>...</ul> for the feed items- use to define the padding/margins for items.
    • +
    • rss-item display of each feed item description and title, <li>...</li> as well as the channel description, if displayed.
    • +
    • rss-item a: variant for the item title and link style
    • +
    • rss-date defines the display of item posting dates
    • +
    + +
    + +
    + + diff --git a/isis/src/docsys/assets/scripts/footer.js b/isis/src/docsys/assets/scripts/footer.js new file mode 100755 index 0000000000000000000000000000000000000000..7863f25b2d750e11f8f93dd8fcbf51dccd523f12 --- /dev/null +++ b/isis/src/docsys/assets/scripts/footer.js @@ -0,0 +1,44 @@ + // FOOTER + // FILENAME: footer.js + // + // Purpose: write standard footer + // + // Author: Deborah Lee Soltesz, USGS, 10/2001 + + + document.write("
    "); + document.write(" "); + document.write(" "); + document.write(" "); + document.write("
    "); + document.write(" "); + document.write(" "); + document.write(" U.S. Department of the Interior | "); + document.write(" "); + document.write(" "); + document.write(" U.S. Geological Survey "); + document.write(" "); + document.write("
    "); + document.write(" "); + document.write(" "); + document.write(" "); + document.write(" Isis | "); + document.write(" "); + document.write(" Privacy & Disclaimers | "); + document.write(" "); + document.write(" Astrogeology Research Program "); + document.write(" "); + document.write(" "); + document.write("
    "); + document.write(" "); + document.write(" To contact us, please post comments and questions on the "); + document.write(" "); + document.write(" Isis Support Center
    "); + document.write(" "); + document.write("
    "); + document.write(" "); + document.write(" "); + document.write("
    "); + diff --git a/isis/src/docsys/assets/scripts/homepage.js b/isis/src/docsys/assets/scripts/homepage.js new file mode 100644 index 0000000000000000000000000000000000000000..311835f3ec4bb790b7c047f02104a29221b1e174 --- /dev/null +++ b/isis/src/docsys/assets/scripts/homepage.js @@ -0,0 +1,55 @@ +/*********************************** + * Script: homepage.js + * Purpose: write little HTML snippets on Isis homepage, + * avoiding XML/XSLT weirdness + * Author: Deborah Lee Soltesz + * Date: 2006-11-13 + * + ***********************************/ + +function writeAnnouncements() { + isWeb = (document.URL.lastIndexOf("isis.astrogeology.usgs.gov") > 0) || + (document.URL.lastIndexOf("isis-dev.wr.usgs.gov") > 0) || + (document.URL.lastIndexOf("blackflag") > 0) ; + if (isWeb) { + document.write ( + "
    " ); + } else { + document.write ( "Visit the Isis Support Center for the latest news and announcements") ; + } + if (isWeb) { + document.write ( + "

    " + + " " + + " More..." + + "

    " ) ; + } +} + +function writeWhatsUpAtTheSupportCenter () { + isWeb = (document.URL.lastIndexOf("isis.astrogeology.usgs.gov") > 0) || + (document.URL.lastIndexOf("isis-dev.wr.usgs.gov") > 0) || + (document.URL.lastIndexOf("blackflag") > 0) ; + if (isWeb) { + document.write ( + " " + + "

    What's Up at the Isis Support Center?

    " + + "
    " + + "
    " + ); + } + if (isWeb) { + document.write ( + "" ); + } + if (isWeb) { + document.write ( + "

    " + + " " + + " More... " + + "

    " + + "
    " + + "
    " + ); + } +} diff --git a/isis/src/docsys/assets/scripts/navigationBar.js b/isis/src/docsys/assets/scripts/navigationBar.js new file mode 100755 index 0000000000000000000000000000000000000000..ecfe384fd177b6ad5cd768d66cf9aeb1f3a2a5e4 --- /dev/null +++ b/isis/src/docsys/assets/scripts/navigationBar.js @@ -0,0 +1,272 @@ + + // SCRIPT: Navigation Bar + // Filename: navigationBar.js + // Purpose: behavior for the horizontal navigation bar + // Author: Deborah Lee Soltesz, USGS, 10/2001 + // History: 12/2005 dls implemented writing of navbar in this script + // to allow changing the menu in one place for + // the entire site + + + + navWidth = 600 ; + navHeight = 19 ; + navSubImgName = "bsubtopics" ; + + site = "http://astrogeology.usgs.gov" ; + + // array indices + navFilenameCool = 0 ; + navFilenameHot = 1 ; + navImgName = 2 ; + navSubFilename = 3 ; + navMap = 4 ; + + imageNumChoice = 0 ; // current image highlighted + + defaultBar = 0 ; // the bar to be displayed when none is highlighted + + // customize: edit path + navBaseURL = "/assets/navigation/menubar/" ; + + // customize: name of blank submenu bars + navSubBlank = "blank_menu_bar.gif" ; + navSubBase = "starfield_menu_bar.gif" ; + + Timeout = 5000 ; + TimeoutID = 0 ; + + // customize: list images to be used in the script + navArr = new Array ( + new Array ("", "", ""), // no 0 + new Array ("solarsystem_menu_button.gif", "solarsystem_menu_button_hot.gif", "bsolarsystem", "solarsystem_menu_bar.gif" , "SolarSystemMap"), + new Array ("missions_menu_button.gif", "missions_menu_button_hot.gif", "bmissions" , "missions_menu_bar.gif" , "MissionsMap" ), + new Array ("technology_menu_button.gif", "technology_menu_button_hot.gif", "btechnology" , "technology_menu_bar.gif" , "TechnologyMap" ), + new Array ("datainfo_menu_button.gif", "datainfo_menu_button_hot.gif", "bdatainfo" , "datainfo_menu_bar.gif" , "DataAndInformationMap"), + new Array ("research_menu_button.gif", "research_menu_button_hot.gif", "bresearch" , "research_menu_bar.gif" , ""), + new Array ("hottopics_menu_button.gif", "hottopics_menu_button_hot.gif", "bhottopics" , navSubBlank , ""), + new Array ("gallery_menu_button.gif", "gallery_menu_button_hot.gif", "bgallery" , "gallery_menu_bar.gif" , ""), + new Array ("about_menu_button.gif", "about_menu_button_hot.gif", "babout" , "about_menu_bar.gif" , ""), + new Array ("search_menu_button.gif", "search_menu_button_hot.gif", "bsearch" , navSubBlank , ""), + new Array ("kidszone_menu_button.gif", "kidszone_menu_button_hot.gif", "bkids" , navSubBlank , "") + ) ; + numNavImages = navArr.length ; + + // preloading images needs to be looked into -- it seems to clear up + // some problems in Netscape4.7, but there's still a lag on changing + // images on mouseover the first time in all browsers, suggesting the + // preload may not be working? + preloadImage = new Array (numNavImages) ; + preloadImageSub = new Array (numNavImages) ; + for (loop = 1 ; loop < numNavImages ; loop++) { + preloadImage[loop] = new Image () ; + preloadImageSub[loop] = new Image () ; + preloadImage[loop].src = site + navBaseURL + navArr [loop][navFilenameHot] ; + preloadImageSub[loop].src = site + navBaseURL + navArr [loop][navSubFilename] ; + } + + // customize: list links for altering submenu image map + // Up to 12 links, array corresponds to same order above + // First element is path to subtopics + navLinkArr = new Array ( + new Array ("", "/", "/", "/", "/", "/", "/", "/", "/", "/", "/", "/", "/"), // no 0 + new Array ("/SolarSystem/", "Sun/", "Mercury/", "Venus/", "Earth/", "Mars/", "Jupiter/", "Saturn/", "Uranus/", "Neptune/", "Pluto/", "OtherObjects/", "Beyond/"), + new Array ("/Missions/", "Cassini/", "Clementine/", "Galileo/", "LunarOrbiter/", "LunarOrbiter/", "Magellan/", "Mariner/", "MarsPathfinder/", "MarsGlobalSurveyor/", "Viking/", "Voyager/", "More/"), + new Array ("/Technology/", "Software/", "Software/", "ImageProcessing/", "ImageProcessing/", "LabsAndFacilities/", "LabsAndFacilities/", "OtherTechnology/", "OtherTechnology/", "TechnicalInformationLinks/", "TechnicalInformationLinks/", "TechnicalInformationLinks/", "TechnicalInformationLinks/"), + new Array ("/DataAndInformation/", "Databases/", "Databases/", "Databases/", "Databases/", "Databases/", "Databases/", "ImagesAndMaps/", "ImagesAndMaps/", "ImagesAndMaps/", "ImagesAndMaps/", "ImagesAndMaps/", "ImagesAndMaps/"), + new Array ("/Research/", "Geology/", "Monitoring/", "Monitoring/", "RemoteSensing/", "RemoteSensing/", "IceAndPolar/", "IceAndPolar/", "InTheLab/", "OtherResearch/", "OtherResearch/", "Organizations/", "Organizations/"), + new Array ("/HotTopics/", "", "", "", "", "", "", "", "", "", "", "", ""), + new Array ("/Gallery/", "ImageGallery/", "ImageGallery/", "DesktopWallpaper/", "DesktopWallpaper/", "DesktopWallpaper/", "MoviesAndAnimations/", "MoviesAndAnimations/", "MoviesAndAnimations/", "Posters/", "Posters/", "ScreenSavers/", "ScreenSavers/"), + new Array ("/About/", "AstroHistory/", "AstroToday/", "AstroFuture/", "People/", "Teams/", "Contact/", "Contact/", "Visitors/", "Visitors/", "Careers/", "Crediting/", "Crediting/"), + new Array ("/Search/", "", "", "", "", "", "", "", "", "", "", "", ""), + new Array ("/Kids/", "", "", "", "", "", "", "", "", "", "", "", "") + ) ; + numLinks = navLinkArr.length ; + + // customize: list corresponding alt/title tags for submenu image map + navLinkAltArr = new Array ( + new Array ("", "", "", "", "", "", "", "", "", "", "", "", ""), // no 0 + new Array ("", "Sun", "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto", "Other Objects", "Beyond the Solar System"), + new Array ("", "Cassini", "Clementine", "Galileo", "Lunar Orbiter", "Lunar Orbiter", "Magellan", "Mariner", "Mars Pathfinder", "Mars Global Surveyor", "Viking", "Voyager", "More Missions"), + new Array ("", "Software", "Software", "Image Processing", "Image Processing", "Labs and Facilities", "Labs and Facilities", "Other Technology", "Other Technology", "Technical Information Links", "Technical Information Links", "Technical Information Links", "TechnicalInformationLinks"), + new Array ("", "", "", "", "", "Databases", "Databases", "ImagesAndMaps", "ImagesAndMaps", "", "", "", ""), + new Array ("", "Geology", "Monitoring", "Monitoring", "Remote Sensing", "Remote Sensing", "Ice and Polar", "Ice and Polar", "In the Lab", "Other Research", "Other Research", "Organizations", "Organizations"), + new Array ("", "", "", "", "", "", "", "", "", "", "", "", ""), + new Array ("", "Image Gallery", "Image Gallery", "Desktop Wallpaper", "Desktop Wallpaper", "Desktop Wallpaper", "Movies and Animations", "Movies and Animations", "Movies and Animations", "Posters", "Posters", "Screen Savers", "Screen Savers"), + new Array ("", "History", "Now", "Future", "People", "Teams", "Contact Us", "Contact Us", "Visitor Information", "Visitors Information", "Careers", "Using Our Images", "Using Our Images"), + new Array ("", "", "", "", "", "", "", "", "", "", "", "", ""), + new Array ("", "", "", "", "", "", "", "", "", "", "", "", "") + ) ; + + // 'enumed' types for referring to each topic corresponding to arrays + noBar = 0 ; + solarBar = 1 ; + missionBar = 2 ; + techBar = 3 ; + datainfoBar = 4 ; + researchBar = 5 ; + hottopicsBar = 6 ; + galleryBar = 7 ; + aboutBar = 8 ; + searchBar = 9 ; + kidsBar = 10 ; + + gonnaReheat = 0 ; // lets cool function know it's been called from the heat function + + // writes the image width + function writeNavWidth () { + document.write(navWidth) ; + } + + // writes the image height + function writeNavHeight () { + document.write(navHeight) ; + } + + // write out the path and filename to the chosen image + function writeNavPathAndFilename (imageNum) { + document.write(site + navBaseURL + navArr[imageNum][navFilename]) ; + } + + // change specified image tag named 'imgName' to chosen image + function heatNavButton (imageNum) { + gonnaReheat = 1 ; + coolAllNavButtons () ; + window.clearTimeout(TimeoutID) ; + gonnaReheat = 0 ; + setImageNum (imageNum) ; + document.images[navArr[imageNum][navImgName]].src = site + navBaseURL + navArr[imageNum][navFilenameHot] ; + document.images[navSubImgName].src = site + navBaseURL + navArr[imageNum][navSubFilename] ; + TimeoutID = window.setTimeout("coolAllNavButtons()", Timeout); + } + + + // functions for changing the image map area hrefs and titles + function setImageNum (imageNum) { + imageNumChoice = imageNum ; + } + + // set which is the default bar to highlight for the page + function setDefaultBarTo (imgNum) { + defaultBar = imgNum ; + } + + function getMapAreaHref (i) { + return site + navLinkArr[imageNumChoice][0] + navLinkArr[imageNumChoice][i] ; + } + + function getMapAreaAlt (i) { + return navLinkAltArr[imageNumChoice][i] ; + } + + + + // change specified image tag named 'imgName' to cool state + function coolNavButton (imageNum) { + document.images[navArr[imageNum][navImgName]].src = site + navBaseURL + navArr[imageNum][navFilenameCool] ; + document.images[navSubImgName].src = site + navBaseURL + navSubBase ; + } + + // change all buttons to cool state + function coolAllNavButtons () { + document.images[navSubImgName].src = site + navBaseURL + navSubBase ; + for (i = 1 ; i < numNavImages ; i++) { + document.images[navArr[i][navImgName]].src = site + navBaseURL + navArr[i][navFilenameCool] ; + } + + if (gonnaReheat != 1) { + imageNumChoice = defaultBar ; + if (imageNumChoice) { + heatNavButton (imageNumChoice) ; + } + } + } + + + function writeNavigationBar () { + document.write(" ") ; + document.write(" ") ; + + document.write(" ") ; + document.write(" ") ; + + document.write(" ") ; + document.write(" ") ; + + document.write(" ") ; + document.write(" ") ; + + document.write(" ") ; + document.write(" ") ; + + document.write(" ") ; + document.write(" ") ; + + document.write(" ") ; + document.write(" ") ; + + document.write(" ") ; + document.write(" ") ; + + document.write(" ") ; + document.write(" ") ; + + document.write(" ") ; + document.write(" ") ; + + document.write(" ") ; + document.write(" ") ; + document.write(" ") ; + + document.write(" ") ; + document.write(" ") ; + document.write(" ") ; + + document.write("
    ") ; + document.write(" ") ; + document.write(" \"[Solar") ; + + document.write(" ") ; + document.write(" \"[Missions]\"") ; + document.write(" ") ; + document.write(" \"[Technology]\"") ; + + document.write(" ") ; + document.write(" \"[Data") ; + document.write(" ") ; + document.write(" \"[Research]\"") ; + + document.write(" ") ; + document.write(" \"[Hot") ; + document.write(" ") ; + document.write(" \"[Gallery]\"") ; + + document.write(" ") ; + document.write(" \"[About") ; + document.write(" ") ; + document.write(" \"[Search]\"") ; + + document.write(" ") ; + document.write(" \"[Kids'
    ") ; + document.write(" \"
    ") ; + + document.write(" ") ; + + document.write(" \"\"") ; + document.write(" \"\"") ; + document.write(" \"\"") ; + document.write(" \"\"") ; + document.write(" \"\"") ; + document.write(" \"\"") ; + document.write(" \"\"") ; + document.write(" \"\"") ; + document.write(" \"\"") ; + + document.write(" \"\"") ; + document.write(" \"\"") ; + document.write(" \"\"") ; + document.write(" \"\"") ; + document.write(" ") ; + document.write(" ") ; + } + diff --git a/isis/src/docsys/assets/scripts/utility.js b/isis/src/docsys/assets/scripts/utility.js new file mode 100755 index 0000000000000000000000000000000000000000..4b6635b07cce815adb88f6252f75c4c94ec223be --- /dev/null +++ b/isis/src/docsys/assets/scripts/utility.js @@ -0,0 +1,68 @@ + + // SCRIPT: Utility Functions + // Filename: utility.js + // Purpose: miscellaneous little handy JavaScript fuctions + // + // Author: Deborah Lee Soltesz, USGS, 11/2001 + + // History: added popUpNewWindow - dls 2/5/2003 + + + // browser checks + ns4 = (document.layers) ? true:false ; + ns6 = (document.getElementById) ? true:false ; + isNav = (navigator.appName.indexOf("Netscape") != -1) + isMSIE = (navigator.appName.indexOf("Microsoft") != -1) + + + // ***************************************************************** + + // POP UP WINDOW + // Open an image (or other file) in new window sized to width-height. + // If window exists, close and open with new size attributes. + // NO decor (toolbars, menus, scrollbars, etc.) and NOT resizable. + + function popUpWindow (url, width, height) { + if (window["POP"] && window["POP"].closed == false) { + POP = window["POP"] ; + if (ns4) { + POP.close() ; + } + else { + POP.resizeTo (width + 30, height + 50) ; + } + } + POP = open(url,"POP","toolbar=0,location=0,status=0,menubar=0,scrollbars=0,resizable=1,width=" + (width + 20) + ",height=" + (height + 20)); + POP.focus() ; + } + + function popUpWindowScrolling (url, width, height) { + if (window["POPs"] && window["POPs"].closed == false) { + POPs = window["POPs"] ; + if (ns4) { + POP.close() ; + } + else { + POPs.resizeTo (width + 30, height + 50) ; + } + } + POPs = open(url,"POPs","toolbar=0,location=0,status=0,menubar=0,scrollbars=1,resizable=1,width=" + (width + 20) + ",height=" + (height + 20)); + POPs.focus() ; + } + + function popUpNewWindow (url, width, height) { + //create random window name + now = new Date() ; + winname = "POP" + now.getHours() + now.getMinutes() + now.getSeconds() + (String)(Math.round(Math.random() * 1000)) ; + open(url,winname,"toolbar=0,location=0,status=0,menubar=0,scrollbars=0,resizable=1,width=" + (width + 20) + ",height=" + (height + 20)); + } + + // CLEAN UP POP UP WINDOW + function cleanUpPopUpWindow () { + if (window["POP"] && window["POP"].closed == false) { + POP = window["POP"] ; + POP.close() ; + } + } + + diff --git a/isis/src/docsys/assets/styles/IsisStyleCommon.css b/isis/src/docsys/assets/styles/IsisStyleCommon.css new file mode 100755 index 0000000000000000000000000000000000000000..e80de5ff1377c0f0de629b900b404eab41fc9364 --- /dev/null +++ b/isis/src/docsys/assets/styles/IsisStyleCommon.css @@ -0,0 +1,523 @@ + /* ISIS STYLE SHEET + * FILENAME: IsisStyleCommon.css + * + * Purpose: formatting style sheet for all pages + * + * Author: Deborah Lee Soltesz, USGS, 04/03/2002 + */ + + + body { + background-color: #FAF0D4 ; + background-image: URL(../banners/isis_wallpaper.jpg) ; + background-repeat: repeat-y ; + background-attachment: fixed ; + font-family: Arial, Helvetica, Geneva, sans-serif ; + } + + /* ---------------------------------------------------------------- + * HEADINGS */ + + h1 { + font-family: Arial Black, Arial, Geneva, sans-serif ; + font-size: 150% ; + font-weight: bold ; + font-variant: small-caps ; + text-decoration: none ; + margin-top: 2px; + margin-bottom: 3px; + } + + h1.subtitle + { + font-family: Arial, Geneva, sans-serif ; + font-variant: normal ; + font-size: 100% ; + font-style: italic ; + font-weight: normal ; + text-decoration: none ; + color: black ; + margin-top: 0px; + margin-bottom: 3px; + } + + h2 { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 110% ; + font-weight: bold ; + font-variant: small-caps ; + text-decoration: none ; + margin-top:2px; + margin-bottom:3px; + padding: 3px ; + } + + h3 { + font-family: serif ; + font-size: 110% ; + font-weight: bold ; + font-variant: small-caps ; + text-decoration: none ; + margin-top:10px; + margin-bottom:5px; + } + + + h4 { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 100% ; + font-weight: bold ; + text-decoration: underline ; + font-style: italic; + margin-top:10px; + margin-bottom:5px; + + } + + h5 { + font-family: serif ; + font-size: 90% ; + font-weight: bold ; + text-decoration: none ; + margin-top:10px; + margin-bottom:5px; + } + + h6 { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + font-weight: bold ; + font-variant: small-caps ; + text-decoration: underline ; + margin-top:10px; + margin-bottom:5px; + } + + hr { + height: 1px ; + } + + + p { + margin: 0px; + padding-bottom: 5px; + padding-top: 5px; + } + + a { + font-weight: bold; + } + + li { + padding-bottom: 5px; + } + + tt { + font-size: 110% ; + font-weight: bolder ; + } + + + div { + font-weight: normal ; + } + + + + /* ------------------------------------------------------------- + * TOC Table: style for upper level pages' tables of contents */ + + .tableTOC + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 90% ; + border: 3px solid brown ; + } + + table.tableTOC + { + width: 100% ; + } + + table.tableTOC th + { + padding: 3px; + } + + table.tableTOC td + { + padding: 3px; + } + + + + /* ------------------------------------------------------------- + * Poll Table: style for upper level pages' tables of contents */ + + table.tablePoll + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + width: 15em ; + border: 3px solid brown ; + } + + table.tablePoll th + { + background-color: #DDCCAA ; + } + + table.tablePoll td + { + + } + + + /* ------------------------------------------------------------- + * TOC Table: style for upper level pages' tables of contents */ + + table.tableTOCmulticol + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 90% ; + width: 100% ; + } + + table.tableTOCmulticol th + { + padding: 3px; + } + + table.tableTOCmulticol td + { + border: 3px solid brown ; + padding: 3px; + } + + + + /* ------------------------------------------------------------------------------------------------ + * General Information Table: plain style for tables of general information - no colors, borders, etc. */ + + .tableGeneralInformation + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 90% ; + } + + table.tableGeneralInformation + { + width: 80% ; + } + + table.tableGeneralInformation th + { + padding: 3px; + padding-right: 7px; + } + + table.tableGeneralInformation td + { + padding: 3px; + padding-right: 7px; + } + + + /* ------------------------------------------------------------- + * TOC Table: style for upper level pages' tables of contents */ + + .tableFormattedInformation + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 90% ; + } + + table.tableFormattedInformation + { + width: 80% ; + } + + table.tableFormattedInformation caption + { + border-top: 2px solid #999966 ; + background-color: #EEEECC ; + } + + table.tableFormattedInformation th + { + padding: 3px; + border: 2px solid #999966 ; + background-color: #CCCCAA ; + text-align: center ; + } + + table.tableFormattedInformation td + { + padding: 3px; + border: 1px solid gray ; + } + + table.tableFormattedInformation col.number + { + text-align: right ; + } + + table.tableFormattedInformation col.center + { + text-align: center ; + } + + table.tableFormattedInformation col.text + { + text-align: left ; + } + + /* ------------------------------------------------------------- + * Image Table: style for images with caption displayed in basic table */ + + .imageTable + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + } + + table.imageTable + { + } + + table.imageTable tr + { + vertical-align: top ; + } + + table.imageTable caption + { + border-top: 2px solid #999966 ; + background-color: #EEEECC ; + } + + table.imageTable th + { + padding: 3px; + border: 2px solid #999966 ; + background-color: #CCCCAA ; + text-align: center ; + } + + table.imageTable td + { + padding: 3px; + border: 2px solid #999966 ; + background-color: #CCCCAA ; + text-align: center ; + } + + table.imageTable img + { + border: 2px solid black ; + } + + + /* ------------------------------------------------------------- + * Image Table 2: style for image with caption in separate cell + * (intended for image and caption side-by-side */ + + .imageTable2 + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + } + + table.imageTable2 + { + padding: 3px; + border: 2px solid #999966 ; + background-color: #CCCCAA ; + } + + table.imageTable2 th + { + text-align: center ; + } + + table.imageTable2 td + { + text-align: center ; + } + + table.imageTable2 img + { + border: 2px solid black ; + } + + + + /* ---------------------------------------------------------------- + * TABLE CELL FORMATTING: table styles for figures; use with CAPTIONS */ + + + /* History table */ + + + .tableCellHistory_date + { + font-style: italic ; + } + + .tableCellHistory_name + { + font-weight: bold ; + } + + .tableCellHistory_description + { + } + + + + /* ------------------------------------------------------------- + * Highlight Section: style for image with caption in separate cell + * (intended for image and caption side-by-side */ + + + div.highlightSection + { + padding: 3px; + border: 2px solid #999966 ; + background-color: #DDDDBB ; + margin-left: 30px; + margin-right: 30px; + } + + div.highlightSection h2 + { + background-color: #AAAA77 ; + } + + + + /* ---------------------------------------------------------------- + * CAPTION: caption text styles */ + + .caption /* defines style for a text caption using page's default color */ + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + } + + .captionBold /* defines style for a text caption using page's default color */ + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + font-weight:bold; + } + + + /* ---------------------------------------------------------------- + * TABLE OF CONTENTS: table of contents text styles */ + .TOCanchors /* defines style for top-of-page table-of-contents anchor links */ + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + margin-bottom:5px ; + margin-top:5px ; + } + + .TOCtoplink /* defines style for link to top of page */ + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 70% ; + font-variant: small-caps ; + font-weight: bold ; + margin-bottom:10px ; + margin-top:10px ; + } + + + /* ---------------------------------------------------------------- + * IMAGE FORMATTING: special formatting for linked images */ + + .blackBorderedImage /* */ + { + border: 2px solid black ; + } + + + div.code { + margin: 5px; + margin-left: 30px; + + padding: 5px; + padding-left: 30px; + + font-family: monospace; + + background-color: #EEE; + border: 1px solid #999; + } + + + div {clear: left ;} + + .pageMenu { + width: 200px; + + float: right ; + + font-family: Arial, Helvetica, SANS SERIF ; + font-weight: bold ; + font-size: 80% ; + + background-color: #FFC; + border: 1px solid #C96; + } + + .pageMenu td { + padding: 5px; + } + + + table.cheatSheet { + width: 600px ; + margin-left: auto ; + margin-right: auto ; + } + + table.cheatSheet td, table.cheatSheet th { + border-color: silver; + border-width: 2px; + border-style: solid; + padding: 5px; + vertical-align: top ; + text-align: left ; + } + + table.cheatSheet th { + background-color: #999999 ; + color: white ; + } + + + div.isisMenu { + width: 155px ; + overflow: hidden ; + position: absolute ; + top: 5px ; + left: 5px ; + } + + div.isisContent { + padding-left: 10px; + padding-right: 20px; + position: absolute ; + left: 170px; + top: 5px ; + width: 80% ; + } + + /** Added by Ryan Raub, for use in the documentation (Warning Messages)*/ + span.warning { + color: #ff0000; + font-weight: bold; + } + diff --git a/isis/src/docsys/assets/styles/main.css b/isis/src/docsys/assets/styles/main.css new file mode 100755 index 0000000000000000000000000000000000000000..4660fb0772209d3135d96012776c47203e0d522b --- /dev/null +++ b/isis/src/docsys/assets/styles/main.css @@ -0,0 +1,82 @@ + /* ISIS STYLE SHEET + * FILENAME: main.css + * + * Purpose: formatting style sheet for upper level + * Isis pages + * + * Author: Deborah Lee Soltesz, USGS, 04/03/2002 + */ + + + + h1 { + color: #993333 ; + } + + h1.subtitle + { + color: #663333 ; + } + + h2 { + background-color: #CCAA88 ; + } + + h3 { + color: #993333 ; + } + + + h4 { + color: #993333 ; + + } + + h5 { + color: #993333 ; + } + + h6 { + color: #993333 ; + } + + HR { + color: #990000 ; + } + + .isisNavigationBar { + margin-left: auto ; + margin-right: auto ; + background-color: white ; + padding: 5px; + text-align: center ; + } + div.isisNavigationBar { + background-color: #600 ; + } + + div.isisNavigationBar table { + width: 600px ; + margin-left: auto ; + margin-right: auto ; + border: 0px solid transparent ; + border-collapse: collapse ; + padding: 0px; + background-color: white ; + } + + div.isisNavigationBar table td { + padding: 0px ; + margin: 0px ; + } + + div.isisNavigationBar img { + padding: 0px ; + margin: 0px ; + } + + + + + + diff --git a/isis/src/docsys/assets/styles/menu.css b/isis/src/docsys/assets/styles/menu.css new file mode 100755 index 0000000000000000000000000000000000000000..eebbe6828f0da82991dabb660bfb247efa7b6ca9 --- /dev/null +++ b/isis/src/docsys/assets/styles/menu.css @@ -0,0 +1,175 @@ + /* MAIN STYLE SHEET + * FILENAME: menu.css + * + * Purpose: style sheet for Isis website menu + * + * Author: Deborah Lee Soltesz, USGS, 11/2002 + */ + + + /* ---------------------------------------------------------------- + * HEADINGS */ + + + + .isisMenu h1, + .isisMenu h2, + .isisMenu h3, + .isisMenu h4, + .isisMenu h5, + .isisMenu h6 + { + font-family: Verdana, Helvetica, Geneva, Arial, sans-serif ; + font-size: 80% ; + font-weight: bold ; + text-align: left ; + } + + .isisMenu h1 { + font-variant: small-caps ; + font-size: 120% ; + + margin-top:10px; + margin-bottom:2px; + padding: 2px; + + background-color: #667733 ; + color: white ; + } + + + .isisMenu h2 { + font-variant: small-caps ; + text-decoration: none ; + + margin-top:2px; + margin-bottom:2px; + padding: 2px ; + background-color: #CCAA88 ; + opacity: .60; + filter: alpha(opacity=60); + -moz-opacity: 0.6 ; + } + + + .isisMenu h3 { + font-style: italic ; + text-decoration: none ; + margin-top:10px; + margin-bottom:5px; + } + + + .isisMenu h4 { + text-decoration: underline ; + margin-top:10px; + margin-bottom:5px; + + } + + .isisMenu h5 { + text-decoration: underline ; + margin-top:10px; + margin-bottom:5px; + } + + .isisMenu h6 { + font-variant: small-caps ; + text-decoration: underline ; + margin-top:10px; + margin-bottom:5px; + } + + .isisMenu hr { + color: #C98 ; + background-color: #C98 ; + height: 1px ; + border: 0px ; + margin-bottom: 1px ; + margin-top: 20px ; + } + + + + .isisMenu div { + text-align: left ; + margin-bottom:3px ; + margin-top:3px ; + } + + .isisMenu a { + width: 95%; + font-variant: small-caps ; + font-weight: bold ; + text-decoration: none ; + padding: 2px ; + color: #CC0000 ; + } + + .isisMenu a:visited + { + color: #663333 ; + font-weight: bold ; + text-decoration: none; + } + + .isisMenu a:hover { + padding: 1px; + background-color: #EEEEAA ; + border: 1px solid silver ; + } + + .isisMenu a:active + { + color: #AA9933 ; + font-weight: bold ; + text-decoration: none; + padding: 1px; + background-color: #EEEEDD ; + border: 1px solid #CCCCAA ; + } + +/* Search styles */ + + .isisMenu table.AstroIsisSearch + { + width: 150px ; + /*border: 2px solid #6655AA ;*/ + } + + .isisMenu .AstroIsisSearch a + { + width: AUTO ; + font-variant: normal ; + font-weight: bold ; + text-decoration: none ; + padding: 2px ; + color: #CC0000 ; + font-size: 80%; + } + + .isisMenu .AstroIsisSearch a:visited + { + color: #663333 ; + font-weight: bold ; + text-decoration: none; + } + + .isisMenu .AstroIsisSearch a:hover { + padding: 1px; + background-color: #EEEEAA ; + border: 1px solid silver ; + } + + .isisMenu .AstroIsisSearch a:active + { + color: #AA9933 ; + font-weight: bold ; + text-decoration: none; + padding: 1px; + background-color: #EEEEDD ; + border: 1px solid #CCCCAA ; + } + + + diff --git a/isis/src/docsys/assets/styles/print.css b/isis/src/docsys/assets/styles/print.css new file mode 100644 index 0000000000000000000000000000000000000000..d28bdd140cd9c1142476920a61a4348c8e196822 --- /dev/null +++ b/isis/src/docsys/assets/styles/print.css @@ -0,0 +1,491 @@ + /* ISIS STYLE SHEET + * FILENAME: IsisStyleCommon.css + * + * Purpose: formatting style sheet for all pages + * + * Author: Deborah Lee Soltesz, USGS, 04/03/2002 + */ + + + BODY { + background-color: white ; + } + + /* ---------------------------------------------------------------- + * HEADINGS */ + + h1 { + font-family: Arial Black, Arial, Geneva, sans-serif ; + font-size: 150% ; + font-weight: bold ; + font-variant: small-caps ; + text-decoration: none ; + margin-top: 2px; + margin-bottom: 3px; + } + + h1.subtitle + { + font-family: Arial, Geneva, sans-serif ; + font-variant: normal ; + font-size: 100% ; + font-style: italic ; + font-weight: normal ; + text-decoration: none ; + color: black ; + margin-top: 0px; + margin-bottom: 3px; + } + + h2 { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 110% ; + font-weight: bold ; + font-variant: small-caps ; + text-decoration: none ; + margin-top:2px; + margin-bottom:3px; + padding: 3px ; + } + + h3 { + font-family: serif ; + font-size: 110% ; + font-weight: bold ; + font-variant: small-caps ; + text-decoration: none ; + margin-top:10px; + margin-bottom:5px; + } + + + h4 { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 100% ; + font-weight: bold ; + text-decoration: underline ; + font-style: italic; + margin-top:10px; + margin-bottom:5px; + + } + + h5 { + font-family: serif ; + font-size: 90% ; + font-weight: bold ; + text-decoration: none ; + margin-top:10px; + margin-bottom:5px; + } + + h6 { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + font-weight: bold ; + font-variant: small-caps ; + text-decoration: underline ; + margin-top:10px; + margin-bottom:5px; + } + + hR { + height: 1px ; + } + + + p { + margin: 0px; + padding-bottom: 5px; + padding-top: 5px; + } + + a { + font-weight: bold; + } + + li { + padding-bottom: 5px; + } + + tt { + font-size: 110% ; + font-weight: bolder ; + } + + + + + + /* ------------------------------------------------------------- + * TOC Table: style for upper level pages' tables of contents */ + + .tableTOC + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 90% ; + border: 3px solid brown ; + } + + table.tableTOC + { + width: 100% ; + } + + table.tableTOC th + { + padding: 3px; + } + + table.tableTOC td + { + padding: 3px; + } + + + + /* ------------------------------------------------------------- + * Poll Table: style for upper level pages' tables of contents */ + + table.tablePoll + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + width: 15em ; + border: 3px solid brown ; + } + + table.tablePoll th + { + background-color: #DDCCAA ; + } + + table.tablePoll td + { + + } + + + /* ------------------------------------------------------------- + * TOC Table: style for upper level pages' tables of contents */ + + table.tableTOCmulticol + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 90% ; + width: 100% ; + } + + table.tableTOCmulticol th + { + padding: 3px; + } + + table.tableTOCmulticol td + { + border: 3px solid brown ; + padding: 3px; + } + + + + /* ------------------------------------------------------------------------------------------------ + * General Information Table: plain style for tables of general information - no colors, borders, etc. */ + + .tableGeneralInformation + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 90% ; + } + + table.tableGeneralInformation + { + width: 80% ; + } + + table.tableGeneralInformation th + { + padding: 3px; + padding-right: 7px; + } + + table.tableGeneralInformation td + { + padding: 3px; + padding-right: 7px; + } + + + /* ------------------------------------------------------------- + * TOC Table: style for upper level pages' tables of contents */ + + .tableFormattedInformation + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 90% ; + } + + table.tableFormattedInformation + { + width: 80% ; + } + + table.tableFormattedInformation caption + { + border-top: 2px solid #999966 ; + background-color: #EEEECC ; + } + + table.tableFormattedInformation th + { + padding: 3px; + border: 2px solid #999966 ; + background-color: #CCCCAA ; + } + + table.tableFormattedInformation td + { + padding: 3px; + border: 1px solid gray ; + } + + + /* ------------------------------------------------------------- + * Image Table: style for images with caption displayed in basic table */ + + .imageTable + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + } + + table.imageTable + { + } + + table.imageTable tr + { + vertical-align: top ; + } + + table.imageTable caption + { + border-top: 2px solid #999966 ; + background-color: #EEEECC ; + } + + table.imageTable th + { + padding: 3px; + border: 2px solid #999966 ; + background-color: #CCCCAA ; + text-align: center ; + } + + table.imageTable td + { + padding: 3px; + border: 2px solid #999966 ; + background-color: #CCCCAA ; + text-align: center ; + } + + table.imageTable img + { + border: 2px solid black ; + } + + + /* ------------------------------------------------------------- + * Image Table 2: style for image with caption in separate cell + * (intended for image and caption side-by-side */ + + .imageTable2 + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + } + + table.imageTable2 + { + padding: 3px; + border: 2px solid #999966 ; + background-color: #CCCCAA ; + } + + table.imageTable2 th + { + text-align: center ; + } + + table.imageTable2 td + { + text-align: center ; + } + + table.imageTable2 img + { + border: 2px solid black ; + } + + + + /* ---------------------------------------------------------------- + * TABLE CELL FORMATTING: table styles for figures; use with CAPTIONS */ + + + /* History table */ + + + .tableCellHistory_date + { + font-style: italic ; + } + + .tableCellHistory_name + { + font-weight: bold ; + } + + .tableCellHistory_description + { + } + + + + /* ------------------------------------------------------------- + * Highlight Section: style for image with caption in separate cell + * (intended for image and caption side-by-side */ + + + div.highlightSection + { + padding: 3px; + border: 2px solid #999966 ; + background-color: #DDDDBB ; + margin-left: 30px; + margin-right: 30px; + } + + div.highlightSection h2 + { + background-color: #AAAA77 ; + } + + + + /* ---------------------------------------------------------------- + * CAPTION: caption text styles */ + + .caption /* defines style for a text caption using page's default color */ + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + } + + .captionBold /* defines style for a text caption using page's default color */ + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + font-weight:bold; + } + + + /* ---------------------------------------------------------------- + * TABLE OF CONTENTS: table of contents text styles */ + .TOCanchors /* defines style for top-of-page table-of-contents anchor links */ + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 80% ; + margin-bottom:5px ; + margin-top:5px ; + } + + .TOCtoplink /* defines style for link to top of page */ + { + font-family: Arial, Helvetica, Geneva, sans-serif ; + font-size: 70% ; + font-variant: small-caps ; + font-weight: bold ; + margin-bottom:10px ; + margin-top:10px ; + } + + + /* ---------------------------------------------------------------- + * IMAGE FORMATTING: special formatting for linked images */ + + .blackBorderedImage /* */ + { + border: 2px solid black ; + } + + + div.code { + margin: 5px; + margin-left: 30px; + + padding: 5px; + padding-left: 30px; + + font-family: monospace; + + background-color: #EEE; + border: 1px solid #999; + } + + + div {clear: left ;} + + .pageMenu { + width: 200px; + + float: right ; + + font-family: Arial, Helvetica, SANS SERIF ; + font-weight: bold ; + font-size: 80% ; + + background-color: #FFC; + border: 1px solid #C96; + } + + .pageMenu td { + padding: 5px; + } + + + table.cheatSheet { + width: 600px ; + margin-left: auto ; + margin-right: auto ; + } + + table.cheatSheet td, table.cheatSheet th { + border-color: silver; + border-width: 2px; + border-style: solid; + padding: 5px; + vertical-align: top ; + text-align: left ; + } + + table.cheatSheet th { + background-color: #999999 ; + color: white ; + } + + + div.isisMenu { + visibility: hidden ; + } + + div.isisContent { + position: relative ; + left: 0px; + top: 5px ; + width: 97% ; + } + + + diff --git a/isis/src/docsys/build/AboutIsis.xsl b/isis/src/docsys/build/AboutIsis.xsl new file mode 100755 index 0000000000000000000000000000000000000000..6626a370c1b5223220efe12c6ee6a83a698b149d --- /dev/null +++ b/isis/src/docsys/build/AboutIsis.xsl @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + USGS Isis: About Isis + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis Documentation

    + +
    + + + + + + + +
    +

    + About Isis +

    +
    + Home +
    + + + + + + + + + +
    + + + + + +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + (, ) + +
    + + +
    + + + + + + + + + + + + + + + + + + + (, ) + + +
    + + + + + + + + + + + + + + + + + + + | + + + + + +
    +
    +
    + +
    + +
    + + + + + + + + + + + + +

    + + + +
    + +
    + + (, ) + +

    +
    + + + + + + + + +

    + + + + + + + + (, )
    +
    + +
    + + + + + + + + + + + + + + + + + + + | + + +

    + +
    +
    +
    + +
    + +
    + + +
    + diff --git a/isis/src/docsys/build/General.xsl b/isis/src/docsys/build/General.xsl new file mode 100755 index 0000000000000000000000000000000000000000..f5bec07ad6f9d21098117114499ef196fe68d83a --- /dev/null +++ b/isis/src/docsys/build/General.xsl @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + USGS Isis: General Information + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis 3 Documentation

    + +
    + + + + + + + +
    +

    + General Information +

    +
    + Home +
    + + + + + + + + + +
    + + + + + +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + (, ) + +
    + + +
    + + + + + + + + + + + + + + + + + + + (, ) + + +
    + + + + + + + + + + + + + + + + + + + | + + + + + +
    +
    +
    + +
    + +
    + + + + + + + + + + + + +

    + + + +
    + +
    + + (, ) + +

    +
    + + + + + + + + +

    + + + + + + + + (, )
    +
    + +
    + + + + + + + + + + + + + + + + + + + | + + +

    + +
    +
    +
    + +
    + +
    + +
    + diff --git a/isis/src/docsys/build/Guides.xsl b/isis/src/docsys/build/Guides.xsl new file mode 100755 index 0000000000000000000000000000000000000000..bb2585db5ba1bf586d0c195571e0c744207c74c3 --- /dev/null +++ b/isis/src/docsys/build/Guides.xsl @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + USGS Isis: Guides and Tutorials + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis 3 Documentation

    + +
    + + + + + + + +
    +

    + Tutorials +

    +
    + Home +
    + + + +
    +

    Tutorials

    + +

    + +Coming Soon! Isis Workshop! +This section has been temporarily removed. +We will soon be unveiling the new Isis Workshop +which will feature tutorials on using Isis 3 +for everyone from beginners to advanced users! +

    + +

    +--Deborah Lee Soltesz, Web Developer +

    + + + + + + + +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + (, ) + +
    + + +
    + + + + + + + + + + + + + + + + + + + (, ) + + +
    + + + + + + + + + + + + + + + + + + + | + + + + + +
    +
    +
    + +
    + +
    + + + + + + + + + + + + +

    + + + +
    + +
    + + (, ) + +

    +
    + + + + + + + + +

    + + + + + + + + (, )
    +
    + +
    + + + + + + + + + + + + + + + + + + + | + + +

    + +
    +
    +
    + +
    + +
    + + +
    + diff --git a/isis/src/docsys/build/Installation.xsl b/isis/src/docsys/build/Installation.xsl new file mode 100755 index 0000000000000000000000000000000000000000..e625687a29b718fed47d97aa95c56c82608c6410 --- /dev/null +++ b/isis/src/docsys/build/Installation.xsl @@ -0,0 +1,280 @@ + + + + + + + + + + + + + + + + + + + + + + USGS Isis: Download and Installation + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis Documentation

    + +
    + + + + + + + +
    +

    + Download and Installation +

    +
    + Home +
    + + +

    + Isis 3 beta was released March 2004 for Linux. + See the Isis 3.0b Installation Guide + for instructions on downloading and installing Isis 3. +

    + +

    + Refer to the Isis 2 Installation Guide + for instructions on downloading and installing Isis 2. +

    + + + + + + +
    + + + + + + +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + (, ) + +
    + + +
    + + + + + + + + + + + + + + + + + + + (, ) + + +
    + + + + + + + + + + + + + + + + + + + | + + + + + +
    +
    +
    + +
    + +
    + + + + + + + + + + + + +

    + + + +
    + +
    + + (, ) + +

    +
    + + + + + + + + +

    + + + + + + + + (, )
    +
    + +
    + + + + + + + + + + + + + + + + + + + | + + +

    + +
    +
    +
    + +
    + +
    +
    + diff --git a/isis/src/docsys/build/IsisDocumentTOCbuild.xsl b/isis/src/docsys/build/IsisDocumentTOCbuild.xsl new file mode 100755 index 0000000000000000000000000000000000000000..02bce7e8490f8a86ae9e2314ae052f5dcebfe4c3 --- /dev/null +++ b/isis/src/docsys/build/IsisDocumentTOCbuild.xsl @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + <xsl:value-of select="bibliography/title"/> + + + + + + + + + + + + + + + + + + + + + + diff --git a/isis/src/docsys/build/IsisInlineDocumentBuild.xsl b/isis/src/docsys/build/IsisInlineDocumentBuild.xsl new file mode 100755 index 0000000000000000000000000000000000000000..ef83588fcbab4be95b7c9aeb491c03d849cf32ca --- /dev/null +++ b/isis/src/docsys/build/IsisInlineDocumentBuild.xsl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + +include $(ISISROOT)/make/isismake.macros +docs: + echo " Constructing []" + + $(XALAN) -p menuPath "'../../'" -p filenameParam "''" -o .xml ../../build/IsisPrimaryPageBuild.xsl + $(XALAN) -p menuPath "'../../'" -p filenameParam "''" -o .xml ../../build/IsisSubPageBuild.xsl + + + + + + + + diff --git a/isis/src/docsys/build/IsisPrimaryPageBuild.xsl b/isis/src/docsys/build/IsisPrimaryPageBuild.xsl new file mode 100755 index 0000000000000000000000000000000000000000..96d179368080c1f92a622478866a63d719c1c804 --- /dev/null +++ b/isis/src/docsys/build/IsisPrimaryPageBuild.xsl @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + USGS Isis: <xsl:value-of select="bibliography/title"/> + <xsl:if test="files/file/subtitle and normalize-space(files/file) = normalize-space($filenameParam)"> + - <xsl:value-of select="files/file/subtitle"/> + </xsl:if> + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS +

    + + + Isis 2 Documentation + + + Isis 3 Documentation + + +

    + +

    +
    +
    + + + + + + + +
    +

    +

    + +

    +
    + + + + Home +
    + + + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + | + + + + +
    + + + + + + (, ) + + + () + + + + + + + + + + + + + + + + + + | +
    +

    +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    + Document History +

    + + + + + + + + + + + +
    + + + + + +
    +
    + + + +
    + + + + + +
    + + + + + + + + + + + + + +
    + diff --git a/isis/src/docsys/build/IsisSubPageBuild.xsl b/isis/src/docsys/build/IsisSubPageBuild.xsl new file mode 100755 index 0000000000000000000000000000000000000000..98d2f70c663ae24e17d2a7f6a6522bdab9ca5ec5 --- /dev/null +++ b/isis/src/docsys/build/IsisSubPageBuild.xsl @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + USGS Isis: <xsl:value-of select="bibliography/title"/> + <xsl:if test="files/file/subtitle and normalize-space(files/file) = normalize-space($filenameParam)"> + - <xsl:value-of select="files/file/subtitle"/> + </xsl:if> + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS +

    + + + Isis 2 Documentation + + + Isis 3 Documentation + + +

    + +

    +
    +
    + + + + + + + +
    +

    +

    + +

    +
    + + + + + Home +
    + + + + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + | + + + + +
    + + + + + + (, ) + + + () + + + + + + + + + + + + + + + + + + | +
    +

    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    + Document History +

    + + + + + + + + + + + +
    + + + + + +
    +
    + + + + +
    + + + + + + +
    + + + + + + + + + + + + + +
    + diff --git a/isis/src/docsys/build/News-makefile.xsl b/isis/src/docsys/build/News-makefile.xsl new file mode 100755 index 0000000000000000000000000000000000000000..a860e64635ebc0a426270f2c49a2ae7c414fd066 --- /dev/null +++ b/isis/src/docsys/build/News-makefile.xsl @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + +include $(ISISROOT)/make/isismake.macros +all: Isis3-_.html Isis2-_.html + + + + + +Isis3-_.html: ../build/News.xsl isisnews.xml + echo " Constructing News [Isis3-_]" + $(XALAN) -p filenameParam "'Isis3-_'" -o Isis3-_.html isisnews.xml ../build/News.xsl + + + + + +Isis2-_.html: ../build/News.xsl isisnews.xml + echo " Constructing News [Isis2-_]" + $(XALAN) -p filenameParam "'Isis2-_'" -o Isis2-_.html isisnews.xml ../build/News.xsl + + + + + + + + + + + + + + + + + + + + diff --git a/isis/src/docsys/build/News.xsl b/isis/src/docsys/build/News.xsl new file mode 100755 index 0000000000000000000000000000000000000000..f30c2802f456f6a9bc5960a8ce5c88f708f2fba1 --- /dev/null +++ b/isis/src/docsys/build/News.xsl @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + USGS Isis: User Documentation + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis News

    + +
    + + + + + + + +
    +

    + +

    +
    + + Home +
    + +
    + +

    + + + + + + +
    +

    Read More!

    +
      + +
    • + : + +
    • +
      +
    +
    + + +

    Related Links

    +
      + +
    • + : + +
    • +
      +
    +
    + + + +
    + + + + +
    + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + diff --git a/isis/src/docsys/build/NewsMore.xsl b/isis/src/docsys/build/NewsMore.xsl new file mode 100755 index 0000000000000000000000000000000000000000..1292ae1117e161071d742d6329ac7092a54ba383 --- /dev/null +++ b/isis/src/docsys/build/NewsMore.xsl @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + USGS Isis: Isis News + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis News

    + +
    + + + + + + + +
    +

    + Headlines: Isis + + 3 + 2.1 + + +

    +
    + + Home +
    + +
    + + + + + + +

    + +

    + + + +
    + +
    +

    +
    +
    + + + + + + + +
    + + + + + +
    +
    + + + + + + + + + + + + + + + diff --git a/isis/src/docsys/build/TechnicalInfo.xsl b/isis/src/docsys/build/TechnicalInfo.xsl new file mode 100755 index 0000000000000000000000000000000000000000..12c3434656f95dd9c79179fd237233e89e7584ef --- /dev/null +++ b/isis/src/docsys/build/TechnicalInfo.xsl @@ -0,0 +1,373 @@ + + + + + + + + + + + + + + + + + + + + + + + USGS Isis: Technical Documents + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis 3 Documentation

    + +
    + + + + + + + +
    +

    + Technical Documents +

    +
    + Home +
    + + + +
    +

    For Application Developers

    + + + + + + + + + +
    + +

    API

    + + +

    + + Isis Developers Reference
    + A handy reference guide to the Isis API and documentation for all Isis libraries and objects + for developers of new Isis applications +

    + + + + + + + + +
    + +

    XML

    + + +

    + + Isis Application XML Reference
    + Reference guide for the Isis Application XML language +

    + + +

    + + Isis Documentation XML Reference
    + Reference guide for the Isis Documentation XML language +

    + + + + + + + +
    + + + +
    +

    For System Administrators

    + + + + + + + +
    + + + + + + +
    +

    For Low-Level Programmers

    + + + + + + +
    + + +

    API

    + + +

    + + Isis Programmers Reference
    + An indepth reference guide for programmers who modify the Isis software package +

    + + + + + + +
    + + + + + + +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + (, ) + +
    + + +
    + + + + + + + + + + + + + + + + + + + (, ) + + +
    + + + + + + + + + + + + + + + + + + | + + + + +
    +
    +
    + +
    + +
    + + + + + + + + + + + + +

    + + + +
    + +
    + + (, ) + +

    +
    + + + + + + + + +

    + + + + + + + + (, )
    +
    + +
    + + + + + + + + + + + + + + + + + + + | + + +

    + +
    +
    +
    + +
    + +
    + +
    + diff --git a/isis/src/docsys/build/UserDocs.xsl b/isis/src/docsys/build/UserDocs.xsl new file mode 100755 index 0000000000000000000000000000000000000000..bfad78f532777c1783acbe0cc5c0dbe3703a5ea3 --- /dev/null +++ b/isis/src/docsys/build/UserDocs.xsl @@ -0,0 +1,393 @@ + + + + + + + + + + + + + + + + + + + + + + + + + USGS Isis: User Documentation + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + USGS
    + + +

    + Isis 3 Documentation

    + +
    + + + + + + + +
    +

    + User Documentation +

    +
    + Home +
    + + + + +
    +

    Getting Started

    + + + + + + + + + + + + + + + + + + + + + + +
    + + Software Manual + + Handy reference guide to all Isis applications +
    + + Isis Workshop + + Interactive and hands on tutorials designed to guide users through the basics of using Isis to advanced processing techniques for creating mosaics from mission data, + correcting and enhancing problem data, and other techniques. +
    + + + + +
    +

    Guides

    + +

    Intermediate

    + + + + + +
    + + + +

    Advanced

    + + + + + +
    +
    + + + + +
    +

    References

    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + Software Manual + + Handy reference guide to all Isis applications +
    + + Old vs. New Program Names + + A useful table cross-referencing the current application names in Isis 3 to the names of applications in previous versions of Isis. + +
    + + + + + + + + +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + (, ) + +
    + + +
    + + + + + + + + + + + + + + + + + + + (, ) + + +
    + + + + + + + + + + + + + + + + + + + | + + + + + +
    +
    +
    + +
    + +
    + + + + + + + + + + + + +

    + + + +
    + +
    + + (, ) + +

    +
    + + + + + + + + +

    + + + + + + + + (, )
    +
    + +
    + + + + + + + + + + + + + + + + + + + | + + +

    + +
    +
    +
    + +
    + +
    + + +
    + diff --git a/isis/src/docsys/build/doctoc_footer.xml b/isis/src/docsys/build/doctoc_footer.xml new file mode 100755 index 0000000000000000000000000000000000000000..3d8c267325c509716393f71fef37d0a600bbf57d --- /dev/null +++ b/isis/src/docsys/build/doctoc_footer.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/isis/src/docsys/build/doctoc_header.xml b/isis/src/docsys/build/doctoc_header.xml new file mode 100755 index 0000000000000000000000000000000000000000..355fbd1ec32aa1eb822dfa3c1ee7c9da28e08c39 --- /dev/null +++ b/isis/src/docsys/build/doctoc_header.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/isis/src/docsys/build/homepage.xml b/isis/src/docsys/build/homepage.xml new file mode 100644 index 0000000000000000000000000000000000000000..696c358b925d230913f31423c85ad68906a2eea2 --- /dev/null +++ b/isis/src/docsys/build/homepage.xml @@ -0,0 +1,73 @@ + + +
    + + + + + + + +
    [USGS Banner] + + Visit the USGS Home Page + Go to the Astrogeology Research Program Home Page + USGS + +
    + +
    +
    + + +

    Isis

    +

    Integrated Software for Imagers and Spectrometers

    +
    + + + + +
    +

    Welcome

    +

    + This is the home page for Isis, an image processing software package. The focus + of the software is to manipulate imagery collected by current and past NASA + planetary missions sent to Mars, Jupiter, Saturn, and other solar system bodies. +

    +

    Announcements

    +
    +
    + +
    +
    +

    Popular Destinations

    + + + + + + + +
    + + +
    diff --git a/isis/src/docsys/build/main.xsl b/isis/src/docsys/build/main.xsl new file mode 100755 index 0000000000000000000000000000000000000000..abe72ae8a377f87298bf1ecb37661f3570f09671 --- /dev/null +++ b/isis/src/docsys/build/main.xsl @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + USGS Isis: Planetary Image Processing Software + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + +
    + + + + + +
    + + + + + + + + + + + + + +
    + diff --git a/isis/src/docsys/build/menu.xsl b/isis/src/docsys/build/menu.xsl new file mode 100644 index 0000000000000000000000000000000000000000..e54d7560bb73d89fbe8ae6a88fe2dabc0d6bb3dd --- /dev/null +++ b/isis/src/docsys/build/menu.xsl @@ -0,0 +1,125 @@ + + + + + + + +
    + + Home +
    + + + + + + + +
    +

    + Isis 3 +

    + + + + + + + + + +
    +

    + Isis 2 +

    + + + + + + + + +
    +

    Search

    + + +
    + + + + +
    + + + + +
    + + + + + + + + + + + + + + +
    +
    + Advanced | + Help +
    +
    +
    +
    + +
    + +
    + diff --git a/isis/src/docsys/build/searchpage.xml b/isis/src/docsys/build/searchpage.xml new file mode 100644 index 0000000000000000000000000000000000000000..7ee99e5355a9bdc83420aba030d4b0328ff3502f --- /dev/null +++ b/isis/src/docsys/build/searchpage.xml @@ -0,0 +1,235 @@ + + + USGS + + +

    Isis Advanced Search

    +
    +
    + Help | + Home +
    + + +
    + + + + +
    +
    + + + + +
    + Search + + + + + + + + + + + + + + +
    + + Entire site + + Isis 3.0: Guides & References
    + + Isis 3.0: Software Manual + + Isis 3.0: Developers Reference
    + + Isis 3.0: Programmers Reference + + Isis 2.1: All Documentation
    + + +
    for documents that +
    + + + +
    + +
    +
    and +
    + + + +
    + +
    + +
    dated + + + + + + + + + + + + + + + + + + + + +
    + + Anytime
    + + + +
    + + + on or after + + + + + +
    + and before + + + + + +
    + +
    and show +
    + + + +

    + + + + + + + + + + + + + + + + +
    +
    +
    +
    + + + + +
    \ No newline at end of file diff --git a/isis/src/docsys/documents/CommandLine/CommandLine.xml b/isis/src/docsys/documents/CommandLine/CommandLine.xml new file mode 100755 index 0000000000000000000000000000000000000000..a0855fc3e930c7ceed687b7a7a61128900653f1b --- /dev/null +++ b/isis/src/docsys/documents/CommandLine/CommandLine.xml @@ -0,0 +1,711 @@ + + + + + + +

    Introduction

    +

    + This section describes how to run Isis programs on the command line, instead of the GUI. This is particularly useful if 1) you desire to setup shell scripts or other batch job mechanisms to run a sequence of programs on cubes or 2) you are a power user who prefers keyboarding over mousing. +

    + +

    Invoking a Program

    +

    + To start an ISIS program, simply type it’s name, for example, "ratio". This starts the program under the GUI, however, if you provide anything after the program name it will be assumed the program is running under the command line. For example, +

    + + +
    +lowpass from=moon.cub to=moon.lpf.cub lines=5 samples=5 minimum=1
    +stats from=moon.lpf.cub
    +
    + +

    + The programs will immediately attempt to run and if parameters are missing or wrong, an error will be output. For example, +

    + +
    +lowpass from=moon.cub lines=4 samples=5 minimum=1
    +**USER ERROR** Parameter [TO] must be entered.
    +
    +lowpass from=moon.cub to=moon.lpf.cub lines=4 samples=5 minimum=1
    +**USER ERROR** Value for [LINES] must be odd.
    +
    + +

    Parameter-Value Pairs

    +

    + For consistency, all Isis command lines take the form of: +

    + +
    +program parameter1=value parameter2=value …parameterN=value
    +
    + +

    + The parameters can occur in any order, can be abbreviated so long as they are unique, are case insensitive, and can be omitted if they have a default value. The values can be integers, doubles, strings, or booleans [Future Option] The values can also be homogenous arrays of these types. Using the GUI for lowpass in the below figure as a guide, we can present several examples: +

    + +
    +lowpass f=moon.cub t=moon.lpf.cub s=5 l=5 minimum=1
    +lowpass f=moon.cub t=moon.lpf.cub s=5 li=5
    +lowpass f=moon.cub t=moon.lpf.cub s=5 lin=5
    +
    + + + + + + +
    + + [lowpass GUI Screenshot] +

    + Parameter-Value Pairs Example +

    +

    + 420x627, 22KB +

    +
    + + +

    + The first example would fail with a uniqueness error as "l" could mean parameter line, lis, lrs, or low. +

    + +
    +lowpass f=moon.cub t=moon.lpf.cub s=5 l=5 minimum=1
    +**USER ERROR** Invalid command line
    +**USER ERROR** Parameter [l] is not unique.
    +
    +

    + The second example would fail with a uniqueness error as "li" could mean parameter lines or lis. +

    + +
    +lowpass f=moon.cub t=moon.lpf.cub s=5 li=5 minimum=1
    +**USER ERROR** Invalid command line
    +**USER ERROR** Parameter [li] is not unique.
    +
    + +

    + The third example would succeed; note the minimum parameter is not required as it has a default of one, the parameters are case insensitive, and their order has changed. +

    + +
    +lowpass S=5 LIN=5 F=moon.cub T=moon.lpf.cub
    +Working
    +100% Processed
    +
    +

    Integer and Double Parameters

    +

    + The application documentation indicates the type of each parameter. Integer and Double parameters are trivial taking the form of: +

    + +
    +samples=5
    +minimum=0.679
    +
    + +

    + Often there will be error check conditions performed by the application to ensure they have a valid range. For example, +

    + +
    +lowpass f=moon.cub t=moon.lpf.cub s=0 lin=5
    +**USER ERROR** Parameter [SAMPLES] must be greater than or equal to [1]
    +
    + +

    + Similarly, two parameters may be required to be ordered +

    + +
    +lowpass f=moon.cub t=moon.lpf.cub s=5 lin=5 low=5 hi=3
    + **USER ERROR** Parameter [LOW] must be less than parameter [HIGH]
    +
    + +

    String Parameters

    +

    + String parameters can be slightly more complicated because of operating system intricacies. The difference is in one word strings versus multiple word strings. The following example would cause problems: +

    + +
    +foobar comment=Hello world
    +**USER ERROR** Invalid command line
    +**USER ERROR** Unknown parameter [world].
    +
    +

    + Therefore multiple word strings must be quoted. We would expect the following to work, but receive the same error: +

    + +
    +foobar comment="Hello World"
    +**USER ERROR** Invalid command line
    +**USER ERROR** Unknown parameter [world].
    +
    +

    + Unfortunately, the Unix shell pre-parses command lines and removes the quotes. To alleviate this problem use the following: +

    + +
    +Foobar comment=\"Hello World\"
    +
    +

    Lists of String Parameters

    +

    + Some applications will restrict the values of string parameters to a pre-defined list. We will use the below "raw2isis" GUI as an example. In this particular case, both BITTYPE and BYTEORDER are strings restricted to certain values. Those values are given in parenthesis to the right of the radio buttons. Two examples of valid command lines are: +

    + +
    +raw2isis byteorder=lsb bittype=real from=file.raw to=file.cub nl=500 ns=500
    +raw2isis byteorder=lsb bittype=R from=file.raw to=file.cub nl=500 ns=500
    +
    +

    + When radio buttons appear the GUI, the value can be abbreviated to uniqueness and is case insensitive as well. The second example, bittype=R implies bittype=real. The following example would fail because of uniqueness issues matching both UnsignedByte and UnsignedWord: +

    + +
    +raw2isis bittype=unsigned from=file.raw to=file.cub nl=500 ns=500
    +**PROGRAMMER ERROR** Value of [BITTYPE] does not match a list option uniquely
    +
    + + + + + + +
    + + [raw2isis GUI Screenshot] +

    + Lists of String Parameters Example +

    +

    + 503x627, 24KB +

    +
    + +

    Boolean Parameters

    +

    + These parameters are represented by check boxes in the GUI. Command line examples of the use of a boolean parameter are: +

    + +
    +foobar option=yes
    +foobar option=no
    +foobar option=true
    +foobar option=false
    +foobar option=t
    +foobar option=f
    +
    + +

    + The values are case insensitive. That is, Yes, YES, True, T, etc work as well. +

    + +

    Inclusive and Exclusive Parameters

    +

    + The GUI has the ability to include or exclude parameters via stipling (graying out parameters). The application programs will complain if you get it wrong in command line mode. Using our "raw2isis" example, +

    + +
    +raw2isis fr=my.raw to=my.cub li=500 sa=500 min=0 max=255
    +**USER ERROR** Parameter [CREATESPECIAL] must be used
    +  if parameter [MINIMUM] is used.
    +
    +raw2isis fr=my.raw to=my.cub li=500 sa=500 createspecial=yes
    +**USER ERROR** Parameter [MINIMUM] must be used
    +  if parameter [CREATESPECIAL] equates to true.
    +
    + +

    Cube Attributes

    +

    + When a parameter is an input or output cube the GUI presents two extra buttons […] and [att]. The […] button which gives a file selection dialog is not implemented on the command line. However, the [att] button is fully implemented in order to select the attributes for the input and output cube. +

    + +

    Output Cube Attributes

    +

    + The user can specify properties of the output cube. They include: +

    + +
      +
    • Pixel Type
    • +
    • Output Pixel Range
    • +
    • Label Format
    • +
    • Pixel Storage Order
    • +
    • Storage Format
    • +
    + +

    + On the command line, the user supplements the output parameter with the attributes. Some examples are: +

    + +
    +highpass to=temp.hpf.cub+detached+bsq
    +highpass to=temp.hpf.cub+16bit
    +highpass to=temp.hpf.cub+8bit+-5.0:5.0
    +
    + +

    Pixel Type

    +

    + This defines the output pixel type. There are three types of output pixels: UnsignedByte, SignedWord, and Real. Valid values and synonyms are given below: +

    + +
      +
    • +UnsignedByte
    • +
    • +8bit
    • +
    • +8-bit
    • +
    + +
      +
    • +SignedWord
    • +
    • +16bit
    • +
    • +16-bit
    • +
    + +
      +
    • +Real
    • +
    • +32-bit
    • +
    + +

    + The default value depends upon the type of program. Most geometry-like programs such as crop, rotate, cam2map, pad, etc will simply propagate the input pixel type. Programs which fiddle with the pixel values such as derive, highpass, grad, etc will generally output real pixels. +

    + +

    Output Pixel Range

    +

    + When choosing an output pixel type other than Real/32-bit the user must define the expected range of output pixels. The form is +minimum:maximum. For example, +

    + +
    +moccal to=cal.cub+0.0:0.3
    +
    + +

    + It is important to select a good minimum and maximum. If the window is too tight, pixels in the output file will be saturated (many LRS or HRS special pixels). If the window is wide then quantization can occur. That is, all the pixels are mapped to one value in the output cube. It can be a difficult problem that can be alleviated by outputting real images, understanding that the sacrifice is utilizing more disk space. +

    + +

    Label Format

    +

    + The option exists to create attached or detached labels. This is facilitated through: +

    + +
    +crop from=input.cub to=output.cub+detached
    +crop from=input.cub to=output.cub+attached
    +
    + +

    + Detached labels will be put in a separate file with an .lbl extension. The default option is read from the system-wide/user IsisPreference file. +

    + +

    Pixel Storage Order

    +

    + The output order of 16-bit and 32-bit pixels can be selected in the following manner: +

    + +
    +crop from=input.cub to=output.cub+lsb
    +crop from=input.cub to=output.cub+msb
    +
    + +

    + The two formats, lsb and msb are for least and most significant byte orders respectively. The default is to use the format native to the machines architecture. +

    + +

    Storage Format Format

    +

    + The storage format of the file can be tiled or band sequential. The default format is tiled which is preferable for most geometric processing programs. To select the format use: +

    + +
    +lowpass from=input.cub to=output.cub+tiled
    +lowpass from=input.cub to=output.cub+bsq
    +lowpass from=input.cub to=output.cub+bandSequential
    +
    +

    + Combining +

    + +
    +lowpass from=input.cub to=output.cub+bandSequential+detached
    +
    + +

    + gives a raw file that can be easily imported into other image processing packages. +

    + +

    Input Cube Attributes

    +

    + Input cube attributes are significantly less complicated than those of output. They allow the user to select the bands on which to operate. The below example divides all bands by band 5: +

    + +
    +ratio num=input.cub den=input.cub+5 to=dividebyband5.cub
    +
    + +

    + There are several forms of band selection: +

    + +
      +
    • +singleBand
    • +
    • +startBand-endBand
    • +
    • [Future Option] +filtername
    • +
    + +

    + The selections can be combined by comma separation. Below are several examples, +

    + +
    ++9
    ++3-5
    ++3,8,10-12
    ++3-1
    ++8,4,2
    +
    + +

    Reserved Parameters

    +

    + All Isis applications have a suite of reserved parameters. These parameters are +

    + +
      +
    • -webhelp, -help or -help=parameterName
    • +
    • -last
    • +
    • -restore=file
    • +
    • -gui
    • +
    • -nogui
    • +
    • -batchlist=file
    • +
    • -errlist=file
    • +
    • -onerror=abort | continue
    • +
    • -preference=file
    • +
    • -log or -log=file
    • +
    • -info or -info=file
    • +
    • -save or -save=file
    • +
    • -verbose
    • +
    + +

    + These parameters may be typed out in full or until the command is distinct. For instance: + +

    +equalizer -pref=myPreferences -s=ttt –g
    +equalizer -l
    +
    + The first command line is acceptable because each parameter is distinct. However, the second command + line would cause an error. The -l could have been intended to be the -last or -log parameter. In this case, the + -l must be extended to -lo for log or -la for last. If you choose to use the shortened version of the parameters, + be sure to watch for conflicts of this sort. +

    + +

    -webhelp and -help Parameters

    +

    + This parameter is used to obtain help on the program. Typing the -webhelp parameter will launch a + browser containing the documentation for the application. Typing the -help parameter will give a list of the + programs parameters with their default value. For list parameters, all the possible options will be output, and there + will be a * denoting the default option. Typing -help=parameterName will give a brief description of + the parameter, its default value, inclusion/exclusion information, and any other information given in the xml. The + three possible options and the resulting output are seen below: +

    + +
    +equalizer –webhelp
    +
    +

    + This command will cause a web browser to be launched with the documentation for the "equalizer" program. +

    +
    +equalizer -help
    +
    +

    + The above command will cause the following terminal output to appear on the screen. +

    +
    +FROMLIST = Null
    +TO       = Null
    +HOLDLIST = Null
    +APPLY    = TRUE
    +ADJUST   = (*BOTH, CONTRAST, BRIGHTNESS)
    +CMODE    = (*PCA, SD)
    +MINCOUNT = 1000
    +WEIGHT   = FALSE
    +
    +

    + To gain more information on the CMODE parameter, the following command can be used. +

    +
    +equalizer -help=cmode
    +
    +

    + This command will cause the following terminal output to appear on the screen. +

    +
    +ParameterName = CMODE
    +Brief         = "The constrast mode to use for the equalization"
    +Type          = string
    +Default       = PCA
    +
    +Group = PCA
    +  Brief = "Principal Component Analysis Fit Mode"
    +End_Group
    +
    +Group = SD
    +  Brief = "Standard Deviation Fit Mode"
    +End_Group
    +
    + +

    -last Parameter

    +

    + This parameter will run the program using the parameters from the last time a program was run in the GUI. For example, +

    + +
    +highpass –last
    +
    + +

    + Additionally, parameters can be modified in the following manner: +

    + +
    +highpass –last from=next.cub to=next.hpf.cub
    +
    + +

    -restore Parameter

    +

    + This parameter allows the user to run the programs with the parameters from a file. In particular, a file saved using the GUI save mode or a session log. For example, +

    + +
    +highpass –restore=guiSave.par
    +highpass –restore=print.prt
    +
    + +

    + Either will look for the last occurrence of Group=UserParameters in Object=highpass in the specified file. Parameters will be loaded from that group. +

    + +

    -gui Parameter

    + +

    + This parameter forces the GUI to run. It can be used in combination with parameters and reserved parameters. For example, +

    + +
    +highpass from=input.cub to=output.cub lines=5 –gui
    +highpass –last –gui
    +highpass –restore=print.prt –gui
    +
    + + +

    + All examples cause the GUI to be shown with the values filled into the appropriate fields. +

    + +

    -nogui Parameter

    + +

    + This parameter forces the GUI not to run. Its main intention is to be used on a program with no parameters For example, +

    + +
    +csspck2spk –nogui
    +
    +

    + All examples cause the GUI to be shown with the values filled into the appropriate fields. +

    + +

    -batchlist Parameter

    + +

    + This parameter allows the user to run a program multiple times on a list of input parameters. It can be used in + combination with all parameters. It cannot be used with the -last, -restore, or -gui reserved parameters. The + batchlist file must be a text file containing one or more columns of data. The columns can be used in the other + parameters by using a '\$' followed by the column number. An example of what the batchList.txt file might look like + can be seen below. +

    +
    +/work2/eribelin/viking/   f387a06.cub
    +/work2/eribelin/viking/   f348b26.cub
    +/work2/eribelin/viking/   f319b19.cub
    +
    +

    + An example commandline would look similar to the following: +

    + +
    +highpass -batchlist=batchList.txt from=\$1\$2 to=\$1/hpf/\$2 lines=5 samples=5
    +
    + +

    + The commandlines that would be run from the above command would be: +

    + +
    +highpass from=/work2/eribelin/viking/f387a06.cub to=/work2/eribelin/viking/hpf/f387a06.cub  lines=5 samples=5
    +highpass from=/work2/eribelin/viking/f348b26.cub to=/work2/eribelin/viking/hpf/f348b26.cub  lines=5 samples=5
    +highpass from=/work2/eribelin/viking/f319b19.cub to=/work2/eribelin/viking/hpf/f319b19.cub  lines=5 samples=5
    +
    + +

    -errlist Parameter

    + +

    + This parameter will save the lines from the batchlist that an error occurs on in an error file in addition to writing + the errors out to the screen. It can be used in combination with all parameters and the -batchlist and -onerror + reserved parameters. All lines that were not run successfully will be propagated to the errorfile. +

    + +
    +highpass -batchlist=batchList.txt from=\$1\$2 to=\$1/hpf/\$2 lines=5 samples=5 -errlist=errList.txt
    +
    +

    + This errorlist can be read back in as the batchlist once the errors are corrected. +

    + +

    -onerror Parameter

    + +

    + This parameter can be used with all parameters, and the -batchlist and -errlist reserved parameters. If the + continue option is selected, it allows the user to run the program on several different files, without stopping + if an error occurs on one of the commandlines. If the abort option is selected or it is ran without being set + (the default is abort), the program will halt when the first error occurs. +

    + +
    +highpass -batchlist=batchList.txt from=\$1\$2 to=\$1/hpf/\$2 lines=5 samples=5 -onerror=continue
    +
    +

    + In this example, any errors that occur will be printed out to the screen and the program will continue to the next + command. +

    + +

    -preference Parameter

    + +

    + This parameter can be used with all parameters, and reserved parameters. It overrides the current preference file + with the file input by the user. For example, +

    + +
    +highpass from=input.cub to=output.cub lines=5 samples=5 -preference=myHighpassPrefs
    +
    +

    + In this example, anything currently in the preference file will be overridden with the preferences in the file + myHighpassPrefs. +

    + +

    -log Parameter

    + +

    + This parameter can be used with all parameters, and reserved parameters. It overrides the current log file + in the preferences with the file input by the user. If the -preference option is also used, the log file entered + will override the session log loaded in the preference file. When -log is used without specifying a filename, + the session log will be save to the print.prt file. If the session log output is turned off in the preferences, using + the -log option will override it for the command line being run. Examples of each use follow. +

    + +
    +highpass from=input.cub to=output.cub lines=5 samples=5 -log
    +highpass from=input.cub to=output.cub lines=5 samples=5 -log=temp.prt
    +
    +

    + In the first example, the session log will be saved in the print.prt file in the current directory (even if the + session log output is turned off in the preferences). In the second example, the current session log file in the + preference file will be overridden with temp.prt, and the session log information will be saved there. +

    + +

    -info Parameter

    + +

    + This parameter can be used with all parameters, and reserved parameters. It gathers debugging information necessary + to help the Isis developers understand user problems. When -info is used without specifying a filename, + the debugging information will be displayed to the console through standard output. PLEASE NOTE: The + user should remove any data from this file that they consider to be personal and do not want publicly available before posting + the file on the Isis Support Forums Examples of each use follow. +

    + +
    +highpass from=input.cub to=output.cub lines=5 samples=5 -info
    +highpass from=input.cub to=output.cub lines=5 samples=5 -info=debug.log
    +
    +

    + In the first example, the debugging information will be output to standard out. In the second example, the debugging information + will be written to debug.log. +

    + +

    -save Parameter

    + +

    + This parameter can be used with all parameters, and reserved parameters except the -batchlist and -errlist + options. It saves the command line parameters to a file in Pvl format. The output file can be read back in to the + program using the -restore option. The default save file name is programName.par. If the -save + option is not used, the history file will be saved by default in the location specified in the preference file under + HistoryPath. If only -save is used, the file will be saved in the current directory, and if the -save option is used + with a specific filename, it will be saved in that location. +

    + +
    +highpass from=input.cub to=output.cub lines=5 samples=5 -save=hpf/saveFile.par
    +highpass from=input.cub to=output.cub lines=5 samples=5 -save
    +
    +

    + In the first example, the program will save the parameters information in the saveFile.par file in the hpf directory. + The second example would save the same parameters in the highpass.par file in the current directory. +

    + +

    -verbose Parameter

    + +

    + This parameter can be used with all parameters, and reserved parameters. If the terminal output preference is + turned off in the preferences, the -verbose option will override it, and print the terminal output to the screen for the + current command only. For example, +

    + +
    +highpass from=input.cub to=output.cub lines=5 samples=5 -verbose
    +
    +

    + The terminal output would be written out to the screen as the program was executed. +

    + +

    Error Status

    + +

    + Command lines programs exit with a status indicating success or failure. + Further information regarding the status can be found in the + Isis Error Handling Facility. +

    + + + HTML + + + CommandLine.html + +
    +
    + + + guide + + + + intermediate + + + + Command Line Usage + + + Invoking Isis programs from the Unix command line + + + How to run Isis on the Unix Command Line. + Required reading before using the software in any scripting language + + Jeff Anderson + 2004-02-27 + +
    + diff --git a/isis/src/docsys/documents/CommandLine/assets/image001.png b/isis/src/docsys/documents/CommandLine/assets/image001.png new file mode 100644 index 0000000000000000000000000000000000000000..04b3f71a0291f2b2f413e82ae0e348ec6df934bc Binary files /dev/null and b/isis/src/docsys/documents/CommandLine/assets/image001.png differ diff --git a/isis/src/docsys/documents/CommandLine/assets/image003.png b/isis/src/docsys/documents/CommandLine/assets/image003.png new file mode 100644 index 0000000000000000000000000000000000000000..5d60afe37a6d5300d5e741323f2d8d8240026018 Binary files /dev/null and b/isis/src/docsys/documents/CommandLine/assets/image003.png differ diff --git a/isis/src/docsys/documents/CommandLine/assets/thumbs/image001.png b/isis/src/docsys/documents/CommandLine/assets/thumbs/image001.png new file mode 100644 index 0000000000000000000000000000000000000000..40676ce17372f6395cc2990f8dcea085979559b7 Binary files /dev/null and b/isis/src/docsys/documents/CommandLine/assets/thumbs/image001.png differ diff --git a/isis/src/docsys/documents/CommandLine/assets/thumbs/image003.png b/isis/src/docsys/documents/CommandLine/assets/thumbs/image003.png new file mode 100644 index 0000000000000000000000000000000000000000..b703fddad4e955291a28c7737d9e033527b4108c Binary files /dev/null and b/isis/src/docsys/documents/CommandLine/assets/thumbs/image003.png differ diff --git a/isis/src/docsys/documents/Conversion/Conversion.xml b/isis/src/docsys/documents/Conversion/Conversion.xml new file mode 100644 index 0000000000000000000000000000000000000000..788a070321183cef1a7a67f7dffe35aee3708f4f --- /dev/null +++ b/isis/src/docsys/documents/Conversion/Conversion.xml @@ -0,0 +1,398 @@ + + + + + +

    + Driving Force of the Conversion +

    +

    + The major reason for embarking on the conversion of Isis was to modernize a nearly 15-year old software package. + Isis was prototyped in the mid-to-late 1980's. Mainstream use began when it was ported to Unix around 1990. + At that time, the technologies used in the development included TAE (a text-based user interface) and Fortran and C. + Later IDL and X-Windows were used to add display functionality to the system. In the mid-1990's, the Perl scripting + language was used to replace TAE PDF procedures. A modernization needed to be undertaken, one that would benefit users, + software developers, and Isis system management. +

    + +

    + User Design Considerations +

    + +

    + Two major elements were considered, the first was replacing the TAE text-based user interface and the second was + easing the users learning curve. Currently, Isis employs a graphic user interface derived from the Qt API. + A significant reason the Qt API was selected is it is available on Unix, Windows, and Macintosh platforms. +

    + + + + + +
    + + [lowpass GUI Screenshot] +

    + Example of the GUI +

    +

    + 500x666, 64KB +

    +
    + + +

    + In addition to replacing the user interface, several other problem areas were identified and addressed in order + to make learning and using Isis easier. They include +

    + +
      +
    • Overly feature rich programs such that only the programmer or designer can fully utilize the application
    • +
    • Programs names with unclear meanings
    • +
    • Two or more programs with the same functionality
    • +
    • Function of the program is unclear
    • +
    + +
    + +

    + Some examples and solutions of each if these problems are: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Problem + + Solution +
    + Overly Feature Rich +
      +
    • boxfilter
    • +
    • photomet
    • +
    • mosaic
    • +
    +
    + Multiple Programs +
      +
    • highpass, lowpass, etc
    • +
    • hapke, minneart, etc
    • +
    • handmos, mapmos, pad
    • +
    +
    + Unclear Names +
      +
    • dsk2dsk
    • +
    • random
    • +
    +
    + Standard Meanings +
      +
    • crop
    • +
    • rotate
    • +
    +
    + Multiple Programs +
      +
    • plansinu
    • +
    • planorth
    • +
    • lev1tolev2
    • +
    +
    + Single Programs +
      +
    • cam2map
    • +
    +
    + Unclear Program Function +
      +
    • Documentation restricted to text-only
    • +
    +
    + Clearer Program Function +
      +
    • Documentation with text
    • +
    • Documentation with visual examples
    • +
    +
    + + + + + +
    + + [Documentation screenshot] +

    + Example of the Documentation +

    +

    + 579x600, 114KB +

    +
    + + +

    + Programmer Design Considerations +

    + +

    +There were many major design considerations relating to software development. They included: +

    + +
      +
    • Increase code reuse
    • +
    • Increase programmer productivity
    • +
    • Utilize more third party APIs
    • +
    • Utilize more developer tools
    • +
    + +

    Increase code reuse

    +

    + The Isis API consisted of many hundreds of C and Fortran subroutines. The documentation for the routines + was located in the source code, forcing application programmers to manually find and locate the desired + function. Coupled with fact there was no table of contents or other front-end navigation ability meant + developers often relied on word-of-mouth to determine existing capabilities. In the worst case, capabilities + were sometimes re-coded because of lack of information. +

    +

    + The conversion process allowed for more planning in regards to the Isis Application Programmer API. The API + reference presents a full developer documentation set in a consistent, web-based interface. The following is + an example of the documentation for a C++ class, +

    + + +

    Increase programmer productivity

    +

    + Another aspect of the design was to increase programmer productivity. In particular, the goal was to have + the developer redirect focus from error checking, user input, and cube I/O to the algorithm. The following + example of the “mirror†program clarifies the position: +

    + + + + + + + + + + +
    + Isis 2.1 + + Isis 3.0 +
    +
      +
    • Total 261 lines
    • +
    • Documentation – 97 lines
    • +
    • Algorithm – 3 lines
    • +
    • User interface – 8 lines
    • +
    • Error checking – 48 lines
    • +
    • I/O handling – 65 lines
    • +
    +
    +
      +
    • Total 29 lines
    • +
    • Documentation – 10 lines
    • +
    • Algorithm – 3 lines
    • +
    • User interface – 2 lines
    • +
    • Error checking – 0 lines
    • +
    • I/O handling – 0 lines
    • +
    +
    + +

    + The redirection of focus can be attributed to the C++ expansion of the “DOIO†concept. This concept + developed in the late 1970's, significantly reduced the amount of programming overhead (errors, I/O, + user interface). +

    + +

    Utilize more third party APIs

    +

    + To further increase code reuse there was a desire to utilize third party APIs. Many of the newer APIs + are restricted to C++ or Java and not available in Fortran or C. Currently the Isis system utilizes + the following APIs: +

    + +
      +
    • Imagemagick (image file format library)
    • +
    • Qt (multi-platform window system)
    • +
    • Xerces (Xml parsing)
    • +
    • TNT/JAMA (matrix and linear algebra)
    • +
    • NAIF/SPICE Toolkit
    • +
    + +

    Utilize more developer tools

    +

    + Many of the current development tools are geared toward object-oriented languages or other new + technologies (e.g., Xml, MySql, etc). Developers can use various language sensitive editors, debuggers, + code profilers, code analyzers, and other tools not readily available or fine-tuned for Fortran/C. +

    + +

    + Isis System Management Design Considerations +

    +

    + The administration of Isis is especially critical as it is being used more and more by the external USGS + planetary community. In particular the following areas were addressed: +

    + +
      +
    • Source maintenance
    • +
    • Software verification
    • +
    • Distribution
    • +
    • User Support
    • +
    + +

    Source Maintenance

    +

    + Isis source code maintenance is now handled through Concurrent Versions System. CVS allows for programmers + to check out, modify, and commit changes to the Isis source repository. It monitors conflicts between + simultaneous access to the source code by developers, as well as providing methods for retrieving all + previous versions of the source. +

    + +

    Software Verification

    +

    + A major need for system management was the ability to verify Isis functions properly when porting to + a new operating system, upgrading operating systems, changing compilers, or modifying compiler switches. + Isis now relies on a suite of “unit tests†to verify the entire API is functioning properly. In addition, + a suite of “application tests†is used to verify individual programs are operating the same. +

    + +

    Distribution

    +

    + The distribution of Isis on CD/DVDs to external customers became problematic due to the growing size of + support files (SPICE and calibration) for current missions. To facilitate timely distribution and quick + installation, a self-syncing system was constructed. The system utilizes the “rsync†software package + to distribute Isis over the Internet in time period of 2 to 10 hours. +

    + +

    User Support

    +

    Previously, Isis user support was handled through an email-based mechanism. It was not centralized + and therefore questions could fall through the cracks. Additionally, no uniform methods existed for + collecting user information (e.g., platform, O/S level, Isis version, etc). Currently, we utilize a + web-based ticket tracking system. It can be found at http://isis-support.wr.usgs.gov/ +

    + +

    + Other Significant Design Changes +

    +

    + Obviously there have been significant changes already discussed including the GUI, programming, + and system management. There are other changes or additions made, some subtle, worth minor discussion + and some major. The following sections discuss other these changes. +

    + +

    User Preferences

    +

    + In the past, user preferences were handled via system environment variables. For example, “setenv + ISIS_SESSION_LOG myprint.prt†was the c-shell command for changing user preferences for error logging. + Currently, all user preferences will be specified in a system-wide, personal-user, and/or project-specific + preference file. The preference file is in Parameter Value Language (PVL) format. +

    + +

    Session Log File

    +

    + In the previous version of Isis, the session log files were partially PVL and then free-format as the + programmer output results of the program. The current version requires all output to the session log + be in PVL format. Results of the program will be stored in a RESULTS group. Additional information + needed to be free-format can be written to a user specified output file. For example, the histogram + program now writes either a postscript histogram or a classic histogram to a file. It is no longer + output in the session log. Additionally, the programmer has some control over free-format in the + session log by utilizing the PVL comment construct. +

    + +

    Cube Format and Compatibility

    +

    + The cube format for Isis has been upgraded. In particular, Isis outputs a new tiled format discussed + at a later point in this document. The tiled format is better suited for large spatial products and + still allows for rapid access in the hyper-spectral modes. However, all programs in Isis 3 will + continue to read the band sequential format produced in Isis 2 for backward compatibility. Support + is also continued for 8-bit unsigned, 16-bit signed, and 32-bit real pixel types, along with the + various special pixel values. Finally, the Isis software will be endian-neutral. That is, programs + will automatically handle LSB or MSB pixel storage order, regardless of machine architecture. +

    + +

    Suffix Data

    + +

    + [Future Option] Much effort went into the design and development of suffix data such as backplanes, + sideplanes, and bottomplanes. Conceptually, the idea of suffix data was appealing in the original Isis design. Realistically, most + of the Isis 2 application programs never dealt with them because of the complexity. In Isis 3 we plan to continue with the ability to + support suffix data, albeit in a different form and name. Suffix data will be handled through BLOBs (Binary Large OBjects). The + advantage is the BLOB is a contingous + chunk of data unlike suffixes which were intermixed amongst the pixel data. A BLOB will be able to represent a sideplane, bottomplane, + or any other non-image data (e.g., vectors defining regions of interest, lookup tables). +

    +
    + +

    SFROM, ORANGE and OTYPE Parameters

    +

    + In Isis 2.1, the SFROM, ORANGE, and OTYPE parameters were essentially qualifiers for input and output + cubes, respectively. The functionality of these three parameters still exists; however, it is handled + via attributes to cube files as opposed to sets of parameters. For example, TO2, ORANGE2, OTYPE2 or + FROM2, SFROM2 are replaced by a file specification with attributes TO=output.cub+16bit +

    + +

    Display Software

    +

    + Image display was handled via “qview†for cartographic (large spatial) and “cv†for hyper-spectral cubes. + They were coded using X-Windows and IDL, respectively. Display capabilities for Isis 3 are coded in + the Qt API. The design for these capabilities will follow the PICS TVDO concept. That is, an image + display base class is provided. This class allows for standard display functions such as zoom, roam, + stretch, blink, cursor interrogation, and measurement tools. Individual display programs that perform + specialized functions will be derived off the base class. Such programs include control point selection, + limb-fitting, and editing. +

    + + + HTML + + Conversion.html + +
    +
    + + reference + + + intermediate + + + Conversion from Isis 2 to Isis 3 + The reasons, considerations, and major design changes related to the upgrade from Isis 2 to Isis 3 + The reasons, considerations, and major design changes related to the upgrade from Isis 2 to Isis 3 + Jeff Anderson + 2003-06-30 + + + + +
    diff --git a/isis/src/docsys/documents/Conversion/assets/docshot.jpg b/isis/src/docsys/documents/Conversion/assets/docshot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ea5efb6f599e1a8a51071872f683381eee670d3a Binary files /dev/null and b/isis/src/docsys/documents/Conversion/assets/docshot.jpg differ diff --git a/isis/src/docsys/documents/Conversion/assets/lowpass.jpg b/isis/src/docsys/documents/Conversion/assets/lowpass.jpg new file mode 100644 index 0000000000000000000000000000000000000000..77c824a72c6be78fde7b6ce97d21fe69c434c6eb Binary files /dev/null and b/isis/src/docsys/documents/Conversion/assets/lowpass.jpg differ diff --git a/isis/src/docsys/documents/Conversion/assets/thumbs/docshot.jpg b/isis/src/docsys/documents/Conversion/assets/thumbs/docshot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aac101d205646b5e7c5727f7c5f9f0b38e3da887 Binary files /dev/null and b/isis/src/docsys/documents/Conversion/assets/thumbs/docshot.jpg differ diff --git a/isis/src/docsys/documents/Conversion/assets/thumbs/lowpass.jpg b/isis/src/docsys/documents/Conversion/assets/thumbs/lowpass.jpg new file mode 100644 index 0000000000000000000000000000000000000000..71cdc6d8c9318ceb8f5a98e99d1dc3c9af0cd7c5 Binary files /dev/null and b/isis/src/docsys/documents/Conversion/assets/thumbs/lowpass.jpg differ diff --git a/isis/src/docsys/documents/Credits/Credits.xml b/isis/src/docsys/documents/Credits/Credits.xml new file mode 100755 index 0000000000000000000000000000000000000000..ab11f9d1cfd8555bce6b9eea1fb59830cbe6371c --- /dev/null +++ b/isis/src/docsys/documents/Credits/Credits.xml @@ -0,0 +1,196 @@ + + + + + +

    Recent Astrogeology Contributors

    +

    + As indicated in the + history, + Isis has been in existence in one form or another for over 30 years and + any aged software package will have had many contributors. Dozens of + people within the USGS and other institutions have been involved in + the Isis design and development at some point in its evolution. + These include scientists, programmers, users, and students. Here is + a current list of Astrogeology Team members involved in the + development of Isis: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Travis AddairJeff AndersonBrent ArchinalChristopher Austin
    Jeannie Waldren BackerJanet BarrettKris BeckerTammy Becker
    MacKenzie BoydDebbie CookKenneth EdmundsonLisa Gaddis
    Trent HareKen HerkenhoffAnnie Howington-KrausEric Hyer
    Chris IsbellJeff JohnsonRandy KirkSteven Lambright
    Ella LeeSharmila PrasadJac ShinamanStuart Sides
    Larry SoderblomTracie Sucharski
    +
    + +

    Past USGS Contributors

    +

    + Additionally, there are many past Astrogeology or USGS employees + who have contributed to the image processing software. They include: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Alex AcostaStacey AlleyJames AndersonJoni Bauers
    Glenn BennettPat ChavezWay ChristensenJim Crawforth
    Norm CushingJacob DantonPhil DavisKay Edwards
    Eric EliasonPatrica EliasonBrendon GeorgeVerna Gregg
    Rae HarveyNoah HiltTom KelleherHugh Kieffer
    Steven KoechleJim MathewsJason MawhinneyAlfred McEwen
    Dennis McMackenElizabeth MillerWendy ParkerMark Robinson
    Bill ScottDeborah Lee SolteszJim StapletonTeal Thompson
    Jim TorsonAaron Young
    +
    + +

    Outside Contributors

    +

    + Finally, contributions have been made to Isis by many people outside + of the USGS. Their involvement came at various times during the + evolution of Isis and is sincerely appreciated: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Don Anderson, ASUBob Dean, JPL
    Roger Clark, USGSPierre Drossary, Observatoire de Paris
    Paul Jensen, University of ColoradoMike Jones, University of Colorado
    Lucas Kamp, Oxford UniversityJohn Lindelow, University of Hawaii
    Ralph Lewis, University of HawaiiJulianna Lo, University of Hawaii
    Bob Mehlman, UCLABill Smythe, JPL
    +
    + +

    Don't Be Forgotten

    +

    + There are undoubtedly individuals that were overlooked in their + contributions to this image processing system. Their exclusion is + not intentional or deliberate. Our apologies for any oversight and + please feel free to send us an email to be included in the credits. +

    + + + + HTML + + + Credits.html + +
    +
    + + + about + + + + all + + + + Credits + Contributors to the Isis software package + + A summary of USGS and non-USGS contributors to the Isis + software package + + Jeff Anderson + 2003-03-25 + +
    diff --git a/isis/src/docsys/documents/Disclaimers/Disclaimers.xml b/isis/src/docsys/documents/Disclaimers/Disclaimers.xml new file mode 100755 index 0000000000000000000000000000000000000000..4d9da9011d19b6def9c576910415845e3dd55b54 --- /dev/null +++ b/isis/src/docsys/documents/Disclaimers/Disclaimers.xml @@ -0,0 +1,124 @@ + + + + + +

    Trademarks and Tradenames

    +

    + Any use of trade, product, or firm names in Isis web pages, + documents, or publications is for descriptive purposes only and + does not imply endorsement by the U.S. Government. +

    + +

    Warranty

    +

    + Although Isis has been used by the USGS, no warranty, expressed + or implied, is made by the USGS as to the accuracy and functioning + of such software and related material nor shall the fact of + distribution constitute any such warranty, and no responsibility + is assumed by the USGS in connection therewith. +

    + +

    Preliminary Content

    +

    + Please note that some information + accessed through these pages may be preliminary in nature. This + information is provided with the understanding that it is not + guaranteed to be complete, and conclusions drawn from such + information are the responsibility of the user. +

    + +

    Privacy Notice

    +

    Isis Web Site

    +

    + Visits to this site are logged by domain - personal + identifying information, such as e-mail addresses, are + not logged. Information, web traffic logs, e-mails, + and other correspondence related to this web server and + its content are archived. This information is used only by + the USGS Astrogeology Web team members and others in the + USGS hierarchy, and will not be released to any other + program, organization, business, or individual. +

    + +

    Isis Support Center

    +

    + In addition to the general privacy policy for the Isis Web Site, mentioned above, + the + Isis Support Center + does collect information that has the potential to identify a particular user. + Some of the information users put in their profiles can be accessed by other users of this + system, such as IM user names, location, website, occupation, and interests. +

    + +

    + Required Information: + The only obligatory information required to use the Isis Support Center are Username, E-mail Address, and Password. + E-mail address must be a valid e-mail address. Users concerned about privacy + should use a username and e-mail account that does not identify them personally and should turn off the + "Always show my e-mail address" in their profiles (this option is turned off by default). +

    + +

    + E-mail Communcations Between Users: + A user cannot e-mail a second user unless the second users has chosen "Always show my e-mail address" in his profile. + If he chooses to turn this option on, users will be able to send mail to him through the Support Center, + but they will not be able to see his e-mail address on the Support Center web pages. However, when a + user e-mails another user through the Center, the e-mail address of the sender will be revealed to the recipient + in the e-mail. If the sender requests a copy, the recipient's address will not be revealed in the copy. Site + administrators do have access to user e-mail addresses. +

    + +

    + Visibility of Topics, Instant Messages, and Other Communications + Messages posted to the forum are publicly viewable. Other forms of correspondence (private messages, e-mail, postings + to the old Isis Support Center/Support Wizard) may be published on the forum, but all identifying information will be + removed or permission will be requested from the user to include the message on the board. +

    + +

    + Cookies + The Isis Support Center uses temporary cookies to store your session ID and a small amount of user data needed to + determine your log-in status as you move around the web site. These temporary cookies are automatically deleted + when you close your browser. Persistent cookies are used to automatically log + you onto the site when you come back later if you choose this option when you log-in, and will remain + available to your browser between visits to our site. To disable automatic log-in, log out of the Isis Support + Center, and make sure to the "Log me in automatically" box is not checked the next time you log in. Cookies are + only used to keep you logged in to the Isis Support Center, and never used to track the frequency of + visits, pages you visit, or any other purpose. +

    + +

    + If you have questions or concerns, or need assistance protecting your privacy while using the Isis Support Center, + please e-mail the Isis Support Center Administration. +

    + + + HTML + + + Disclaimers.html + +
    +
    + + + about + + + + all + + + + Disclaimers + Standard legalese regarding usage, trademarks, and privacy + + This section contain standard USGS comments regarding software + accuracy, use of trademarks and tradenames and other general + disclaimers. + + Jeff Anderson + 2003-03-25 + +
    diff --git a/isis/src/docsys/documents/DocStyle/DocStyle.xml b/isis/src/docsys/documents/DocStyle/DocStyle.xml new file mode 100644 index 0000000000000000000000000000000000000000..e28024b9b89f246340b4177e909b992858a651ca --- /dev/null +++ b/isis/src/docsys/documents/DocStyle/DocStyle.xml @@ -0,0 +1,2838 @@ + + + + + api + guide + technicaldoc + + + + programmer + + + + Style Guide + + Object source code styles and conventions + + + This document describes Object naming conventions, + documenting source code for automatic documentation generation, + and formatting documentation. + + Deborah Lee Soltesz and Leah Dahmer + 2005-02-17 + + + + + Fixed format instructions for @history (date and author were inverted) + + + Updated @image use instructions and conventions + + + Update CVS tags described in the guide so that CVS + wouldn't automatically replace the tag with actual + information when this document is checked in. (Replaced + $ signs with ISO8859-1 entity, treating the $s as special + characters). + + + + + + + +

    + +Introduction: Conventions and Definitions of this Guide +

    + + + + + + + + + + +

    Purpose

    +

    +This guide has been generated for Isis programming team as a style reference for +writing in-code documentation to meet team requirements for consistency, +content, and information dissemination. Serving as a reference for proper +documentation structure for automatic generation of documentation in various formats, +primarily HTML, is the primary focus of this guide. Isis Applications have their own +code and documentation style. Information for the documentation system maintainers +will be provided in a separate document covering system level tags (such as +@mainpage and @defgroup), directory structure, naming conventions, etc. +

    + +

    Conventions

    +

    +In the tag lists (later in this guide), arguments will be surrounded with either +< >s, [ ]s, ( )s, or { }s. These brackets should not be included in +the tags when used--they are only used as a visual reference in this document. +

    +
      +
    • Parentheses () will be used to mark titles and independent names for items,
    • +
    • square brackets [] will be used to mark optional one word arguments,
    • +
    • angle brackets <> will be used to mark keywords used by doxygen to identify members, and
    • +
    • curly braces {} will be used to denote multi-worded descriptions.
    • +
    + + +

    Definitions

    +

    +Mandatory is a pretty strong word... we will define here to mean +use it if it applies. Many documentation components will always be included, +such as CVS revision for files and category for classes. Other tags +may not always be applicable, such as documenting return value and parameters for functions. +Use your discretion, and have your documentation reviewed by a peer. +

    + + + + + + +
    +

    +Understanding Our Audience: API verses Programmer Reference

    + +

    +There are two major audiences for our source code documenation. +Two sets of documentation are maintained, one for each audience. +

    + +
      +
    • + Application Developers: + These folks only want to know how to use Isis objects. They use + the API, which gives information about public and protected + entities, new features, and descriptions and examples of usage. + This audience will be encouraged to use the web pages for reading + the API. +
    • +
    • + Object Programmers: + These folks are mainly the ones who maintain and develop Isis. + This audience needs to know details about the inner workings of + the code in order to maintain it. They use the Programmers' Reference, + which provides all the verbose nitty gritty information, such as documentation + for private entities, history, things to do, and other internal documentation. + While this group will have verbose web-based documentation, they often read the + documentation in the source code instead of going to the website. +
    • +
    + + + + + + + +
    +

    Naming Conventions

    + +

    File Extensions:

    +
      +
    • Header files have a .h extension.
    • +
    • Implementation files have a .cpp extension.
    • +
    • Plugin files have a .plugin extension.
    • +
    • Truth files have a .truth extension.
    • +
    • Primary make files are named Makefile. Secondary make files + (called from the primary) should begin with the string Makefile.
    • +
    + +

    Files and Directories

    +

    +We will be using a UpperCamelCase syntax, where every new word begins with +a capital letter, for all file names and most directory names. +

    + +

    +Object Directories: All of an Object's files go into a directory named identically +to the Object. In the case where the Object has several classes, one primary +class (the parent, base, API) should be identified and used for naming the directory. +

    + +

    +Subdirectories are not allowed for Object source code. +

    + +

    +Files: Header and Implementation files are to name identically to the class they define. +In the case where the file contains several classes, one primary +class (the parent, base, API) should be identified and used for naming the file. +

    + +

    Naming user defined types and method names:

    + +

    +We will be using a UpperCamelCase syntax, where every new word begins with +a capital letter, for all user defined types (classes, structs, typedefs, etc.), +and method names, such as: ProcessByLine (class) and +ProcessByLine() (constructor). +

    + +

    Naming variables:

    + +

    +All variables will use lowerCamelCase syntax, where the first letter +is lower case and the beginning of other words are capitalized, +such as: allRequirements. +

    + + + + + + + +
    +

    +Documentation Basics

    + +

    + +Source Code Documentation Structure +

    + +

    +Currently, the Isis programming team is using the +Doxygen +documentation extraction software. Doxygen has extended the tag set of the +javadoc documentation style, +a systematic in-code documentation style that allows pertinent documentation +to be extracted easily. Doxygen is just one of many software packages that +are able to extract and use javadoc documentation for a variety of purposes, +allowing us to take advantage of a wealth of documentation extractors, IDEs, +and other tools on the market that make our lives simpler and more productive. +

    + +

    +In order to be able to generate automatic documentation correctly and follow a +systematic and consistent approach , each programmer must: +

    + +
      +
    • + Write documentation for each entity (class, method, struct, variable, etc.) + in the source code where the primary or most commonly used definition + of that entity resides. Generally, this means the following files contain + documentation for the listed entities: +
        +
      • + Header (.h): classes, inline functions, enums, typedefs, unions, structs, and variables declared in the header file +
      • +
      • + Implementation (.cpp): member function implementations and any entities declared or defined in the implementation file +
      • +
      + +
    • + +
    • + Use specialized commenting styles before or after each entity, called documentation lines + or documentation blocks, for example: +
        +
      • + Single line of documentation (documentation line) +
          +
        • start documentation with string //! before or //!< after the code
        • + +
        • Before the entity +
          + //! my integer
          + int myInteger ; +
          +
        • + +
        • After the entity +
          + int myInteger ; //!< my integer
          +
          +
        • +
        +
      • + +
      • + Multi-lined documentation (documentation block) +
          +
        • wrap documentation with /** */ before or /**< */ after the code
        • + +
        • Before the entity +
          +
          +/**
          + * my method
          + */
          +int myMethod () {
          +  return myInteger ;
          +}
          +            
          +
          +
        • + +
        • After the entity +
          +
          +int myMethod () {
          +  return myInteger ;
          +}
          +/**<
          + * my method
          + */
          +            
          +
          +
        • +
        +
      • +
      +
    • +
    + + + +

    + +Date Format +

    + +

    +Dates should always follow the + +ISO date format standard. Generally, you'll want to note the current date - use +YYYY-MM-DD. See the + +complete ISO 8601 standard [190KB PDF] for the complete information. +Use of this standard allows us to avoid internationalization issues and have dates +that can be easily extracted by computer software. +

    + + + +

    + +Using HTML +

    + +

    +HTML can be used anywhere in your documentation. +Keep it simple. Doxygen will "interpret" your HTML, so you may not get the +desired effect. Best advice, avoid attempting special effects by just using the basic HTML +formatting tags - bold, underline, pre, code, table (caption, tr, td, th), etc. and only +when really necessary. Better yet, consider using the formatting tags in the Other Useful +Tags section instead of HTML. Your plain old text will be pretty nicely rendered into paragraphs +with automatically linked items and other bells and whistles. Keep your source readable: +minimize formatting. +

    + + + + + +

    + +Autolinking +

    + +

    +Class, method, variable, and other entity names will be automatically linked +in the documentation. To prevent this for a specific occurence of a name, +use a percent sign (%) in front of the name. For example, if you have a +class name "Histogram" and you want to prevent the linking of the word +"Histogram" in your description because it is not referring to the class but +to an actual histogram, use "%Histogram" to prevent the word from being linked. +

    + +

    +E-mail addresses and web addresses are also automatically linked. If a web +address is particularly long, put it on its own line. +

    + + + +
    + + + HTML + + Introduction + + intro.html + +
    + + + + + + + + + + + +

    +Mandatory is a strong word we will define here to mean +use it if it applies. Many tags will always be used, +such as $Revision$ for files and @ingroup for classes. Other tags +may not always be applicable, such as @return and @param for functions. +

    + +

    +Descriptions do not require a special tag. Simply write text and make +sure for blocks there's a blank line before and after the description: +

    + +
    +
    +/**
    + * @brief Get my integer
    + *
    + * myMethod is a simple function for returning
    + * my integer stored in this data structure.
    + *
    + * @return (int) The current value of my integer.
    + */
    +int myMethod () {
    +  return myInteger ;
    +}
    +
    + + + +

    +Syntax notes: Within the list of the following commands, arguments will be outlined in < +>s, []s, {}s, and ()s. Below is a list of their +meanings: +

    + +
      +
    • + <argument>: Signifies a one-worded argument. Any comments after the + initial word will be either ignored or used as comments, depending on the + command. +
    • +
    • + [argument]: Indicates an optional one-worded argument. +
    • +
    • + (argument): Indicates a multi-worded argument that is not a description + or comment block +
    • +
    • + {argument}: Indicates a description or comment stream. +
    • +
    + +

    +Do not use any of these indicators within your doxygen comment blocks. +They are merely for organization of this document only. +

    + + + + + + + +
    +

    Files:

    + +

    + +@file: Required to start a file documentation block. +

    + + +

    + +Disclaimer: Use the following disclaimer in the @file block of every file: +

    +
    +

    + Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + individual third-party library and package descriptions for intellectual property information, + user agreements, and related information. +

    + +

    + Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + USGS as to the accuracy and functioning of such software and related material nor shall the + fact of distribution constitute any such warranty, and no responsibility is assumed by the + USGS in connection therewith. +

    + +

    + For additional information, launch $ISISROOT/doc/documents/Disclaimers/Disclaimers.html + in a browser or see the Privacy & Disclaimers page on the Isis website, + http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + http://www.usgs.gov/privacy.html. +

    +
    + +

    + +$Revision$: Enters the CVS version of this file into the documentation. CVS will replace this string with the full version string when the file is checked in. For example, the CVS version of this document is $Revision: 1.1.1.1 $. +

    + +

    + +$Date$: Enters the CVS last modification date of this file into the +documentation. CVS will replace this string with the full last modification date when the file is checked in. For example, the CVS last modification date of this document is $Date: 2006/10/31 23:18:12 $. +

    + +

    +Notes

    + +

    +Additional documentation: A brief and/or long description, history, or +other information is left to the discretion of the programmer. +

    + +

    +Other CVS tags: $Id$ and other CVS tags may be used at the taste +and discretion of the programmer. +

    + + + + + + +
    +

    Classes:

    + +

    +Give an overall description of the class. Does it +represent a particular data structure (e.g. binary tree) +or emulate the behavior and attributes of a real world +object (e.g. camera) or concept (e.g. vector)? +

    + +

    + +Writing Inline Examples with @code and @endcode: + +Examples should always be provided to illustrate the setup and intended use +of a class. Include one or more brief examples in your documentation, using +the @code to start the example and @endcode to end the example. Do not +escape special characters like <, >, and & inside a @code/@endcoe block - +your code snippet will be parsed and special characters properly rendered for you. +

    + +

    + +Linking to Examples in Other Isis Objects or Applications: + +Whenever possible, point out working Isis sourcecode where your object is in heavy and thorough use, such +as a class or application containing your object or a a class inheriting your object. +In the web page output, names of files and classes in your descriptions are automatically linked +to the appropriate documentation. Simply write a sentence that contains the class or file names +you wish to link to with a bit of explanation, such as in the following snippet from the +Statistics class documentation: +

    + +
    +* For an example of how the Statistics object is used in %Isis, see the
    +* Histogram object (inherits from Statistics) and the stats application,
    +* stats.cpp (uses the Statistics child class Histogram).
    +
    + +

    +In the resulting web page output, Statistics, Histogram, and stats.cpp will all be linked +to pages about those classes and file. The percent sign (%) in '%Isis' prevents the word Isis from being +linked to the Isis namespace documentation. +

    + +

    + +@author { Author }: Always use original author(s), with modifiers noted in +@history. +

    + +

    + +@bug { bug description }: Use for noting bugs. Remove the +bug documentation when the bug is fixed, and make a note in a +@history entry. +

    + +

    + +@deprecated: Indicates a deprecated entity in a documentation block. +

    + +

    + +@ingroup(<groupname>[<groupname> <groupname>]): +Categorize this class as belonging to a particular group of Objects. +The class documentation will be linked in the group's page (identified by <groupname>). +Groups are listed in the Modules section of the Isis documentation, and defined by the +isisDoxyDefs.doxydef +file. +

    + +

    + +@whatsnew { date } { paragraph describing new features }: +Description of a new feature of this class that users of your object will +find interesting. Keep it exciting, simple, and brief. +

    + + +

    Internal Class Documentation

    + +

    + +@internal: to start a section of internal documentation +put @internal on its own line in your documentation block. +Everything between the @internal tag and the end of the block +will be marked as "not for public consumption." Internal +documentation will not appear in the API, only in the Programmers' +Reference. +

    + +

    +@todo and @history should always be placed in the internal +section of the documentation. +

    + +

    + +@todo { paragraph describing what is to be done }: +Notes a lien, or item needing to be done. When it's done, the +entry should be removed and a @history entry should be added. +

    + +

    + +@history YYYY-MM-DD <author> { description of change } : +Make a note of the who, when, and what of a modification to the class. +

    + + + + + + + +
    +

    +For Methods:

    + +

    +Methods are documented where they are implemented. Inline +methods will be documented in the header, others in the +implementation file. +

    + +

    +Write a wonderful description explaining the use of the method. +Information describing its implementation, such as algorithms, +design decisions, etc. can be placed in an @internal section +at the end of the documentation block. Parameters, return value, +and exceptions thrown are documented in their own section in +the method's documentation block. +

    + +

    +Use the following tags as needed to complete your desription. +

    + + +

    + +@author { Author }: This is only needed if the method author is not the author of + the method's scope (e.g. Bob added a member function to Ted's class). + Always use original author(s), with modifiers noted in +@history. +

    + +

    + +@bug { bug description }: Use for noting bugs. Remove the +bug documentation when the bug is fixed, and make a note in a +@history entry. +

    + +

    + +@deprecated: Indicate a deprecated function. +

    + +

    + +@param<[in|out|in,out]> <parameter-name> {(type) parameter description}: +Describe a parameter for the function with name <parameter-name>, +followed by the parameter type, then a description. The @param command +also has a mandatory attribute specifying direction of the attribute, [in] or [out], or [in,out] for both. +

    + +

    + +@return (type) {description}: Describe the return value of a method. +

    + +

    + +@throws <exception-object> { description }: Desribe the exception +of type exception-object thrown by this method. +

    + +

    + +@relates <name>: +Indicate this function is related to the entity indicated by name. +Useful for documenting non-friend functions that are +nevertheless strongly coupled to a certain class. This tag will cause this +method's documentation to be included in the documentation indicated by +name. +

    + +

    +Example: +

    +
    +/*!
    +* A String class.
    +*/
    +class String {
    +  friend int strcmp(const String &,const String &);
    +};
    +
    +/*!
    +* Compares two strings.
    +*/
    +int strcmp(const String &s1,const String &s2) {...}
    +
    +/*! @relates String
    +* A string debug function.
    +*/
    +void stringDebug() {...}
    +  
    + + +

    + +@see { references }: List cross-references to +classes, functions, methods, variable, files, or URL may be specified. Two +names joined by either :: or # are understood as referring to a class and one of +its members. One of several overloaded methods or constructors may be selected +by including a parenthesized list of argument types after the method name. +

    + + + + +

    +Internal Documentation

    + +

    + +@internal: Start a section of internal documentation +by putting @internal on its own line in your documentation block. +Everything between the @internal tag and the end of the block +will be marked as "not for public consumption." Internal +documentation will not appear in the API, only in the Programmers' +Reference. +

    + +

    +@todo and @history should always be placed in the internal +section of the documentation. +

    + +

    + +@todo { paragraph describing what is to be done }: +Note any liens, or items needing to be done. When it's done, the +entry should be removed and a @history entry should be added. +

    + +

    + +@history YYYY-MM-DD <author> { description of change } : +Make a note of the who, when, and what of a modification to the class. +

    + + + + + + + +
    +

    +Variables:

    +

    +For most variables, a short one-lined description will suffice. For longer +descriptions, use a description block (described in the Basics +section of this document). Variable declarations are often one of the places where programmers prefer to +place their documentation on the same line after the declaration. In the following example, note the +use of the left angle bracket to start documentation that +follows the value, and this notation can be used for both single and +block documentation. +

    + +
    +
    +int    counter ;   //!<  An iterator that tracks how often this instance has been touched
    +float  value   ;   //!<  The value stored by this data structure
    +String title   ;   /**!< The title, or name, of the value.
    +                    *    The title follows the standards outlined
    +                    *    in the design document available on the
    +                    *    mission website.
    +                    */
    +  
    +
    + +

    +Use @internal, @history, @whatsnew, @author, @todo, and other tags if needed. +

    + + + + + + +
    +

    +For Other User Defined Types:

    +

    +Aside from classes, most user defined type declarations need only a short one-lined description +For longer descriptions, use a description block (described in the Basics +section of this document). +

    + +

    +In all cases, use @internal, @history, @whatsnew, @author, @todo, @deprecated, and other tags if needed. +

    + +

    + +Enumerations: +A general description is required for all enum declarations, and enumeration value +descriptions should be used as necessary. In the following example, +note the use of the left angle bracket to start documentation that +follows the value, and this notation can be used for both single and +block documentation. +

    + +
    +
    +/**
    + * This enum is a set of red, blue, and green values of a specified pixel.
    + */
    +enum Colors {
    +    Red,    //!<  The "red" value of the pixel.
    +    Blue,   //!<  The "blue" value of the pixel.
    +    Green   /**!< The "green" value of the pixel.
    +             *    Green is a very special portion of
    +             *    the visible EM spectrum, so more
    +             *    documentation is being provided.
    +             */
    +};
    +  
    +
    + +

    + +Structures: +A general description is required for all stuct declarations and the +variables they contain. In the following example, +note the use of the left angle bracket to start documentation that +follows the value, and this notation can be used for both single and +block documentation. +

    + + +
    +
    +/**
    + * This structure holds a name-value pair
    + */
    +struct NamedFloat {
    +  float  value   ;   //!<  The value stored by this data structure
    +  String name    ;   /**!< The of the value.
    +                      *    The name follows the standards outlined
    +                      *    in the design document available on the
    +                      *    mission's website.
    +                      */
    +};
    +  
    +
    + + + + +

    + +Type Definitions: +A general description is required for all type definition declarations. Note in the +example below the use of the @internal tag to add a little extra information for other +programmer's to understand why the types were defined (i.e. explains the design decision). +

    + +
    +
    +/**
    + * A set of data types to represent various monetary units.
    + *
    + * @internal This typedef was created for the purpose of increasing code readability.
    + */
    + typedef int Pounds, Shillings, Pennies, Dollars, Cents;
    +  
    +
    + +

    + +@internal: Use this in any documenation block where you wish to add internal documentation, +such as comments regarding design, @history, @todo, and so forth. +All documentation after the @internal tag and before the end of the documenation block will appear +in a section of the Programmer's Documentation titled "For internal use only." +

    +
    + + + HTML + + Mandatory Commands + + + mandatoryCommands.html + +
    + + + + + + + + + +

    +The following list are additional tags that may be useful in +documenting your code. Tags not appearing in this list or the +list of mandatory tags are generally forbidden either because of +the documentation rules (such as documentation must appear directly +before or after the entity being documented) or because the usage +is restricted to the documentation system managers (such as creating +new categorization groups). Forbidden tags include: mainpage, defgroup, +class, fn, enum, struct, and other tags that are unecessary if documentation +is positioned next to the entity it documents. +

    + +
    +

    +Formatting:

    + +

    + +@a <argument>: Format argument in a special font. +

    + + +

    + +@b <word>: Display the argument word in bold. +Equivilant to HTML <b>word</b> +

    + +

    + +@c <word>: Display the argument word in typewriter font. +<tt>word</tt> +

    + +

    + +@code: Start a block of code. A code block is treated differently +than regular text. It is interpreted as C/C++ code. The names of classes and +members are hyperlinked to their documentation. +

    + +

    + +@endcode: End a code block after starting it with the +@code command. +

    + +

    + +@e <word>: Display "word" in italics. +<em>word</em> or <i>word</i> +

    + +

    + +@f$: Mark the beginning or end of an in-text formula. All formulas +should be in between @f$ commands. For example: +

    + +
    + The distance between @f$(x_1,y_1)@f$ and + @f$(x_2,y_2)@f$ is @f$ @sqrt{(x_2-x_1)^2+(y_2-y_1)^2}@f$ +
    + +

    + This example results in the display of the distance equation. +

    + +

    + + @f[: Mark the start of a long formula that is displayed centered on + a separate line. +

    + +

    + + @f]: Mark the end of a long formula that is displayed on a separate + line. +

    + +

    + + @n: Force a new line. +

    + +

    + + \$, \@, \\, \&, \<, \>, \#, + \%: These commands write the character after the first '\' symbol + to the output. These characters need to be escaped because they have special + meanings in HTML, XML, and/or Doxygen. +

    + + + + + + +
    +

    + + Messages:

    + +

    + + @attention { attention text }: Start a paragraph where a message + that needs attention may be entered. Ends when a blank line is encountered or + some other sectioning device. +

    + +

    + + @note { text }: Start a paragraph where a note can be entered. The + paragraph will be indented. +

    + +

    + + @par [( paragraph title )] { paragraph }: Start a paragraph with a + user defined heading. The heading extends until the end of a line. The paragraph + following the command will be indented. +

    + +

    + + @remarks { remarks text }>: Start a paragraph where one or more + remarks may be entered. +

    + +

    + + @warning { warning message }: Start a paragraph where one or more + warnings may be entered. +

    + + + + + + + +
    +

    + + Code Documentation:

    + +

    + + @brief { description }: Start a paragraph where a brief description + may be entered. NOTE: If you do not use the @brief command, your + first sentence (ending with a .) will be used as the brief description. When + appearing in output documentation with your long description, the brief description + (marked by @brief or the first line of your long description) will appear on its + own line above the long description and will not be repeated. +

    + +

    + + @date <$Date$ | YYYY-MM-DD> { Optional comment }: Start a paragraph where one or + more dates may be entered. You may use the CVS date command to insert the last file modification + date from CVS or enter your own date using the + ISO 8601 date format. +

    + +

    + + @dir [<path fragment>]: Directory documentation. The "path fragment" + argument should the directory name and enough of the path to be unique with respect to + the other directories in the project. +

    + +

    + + @hideinitializer: By default, the value of a define and the + initializer of a variable are displayed unless they are longer than 30 lines. By + putting this command in a comment block of a define or variable, the initializer + is always hidden. +

    + +

    + + @name ( header ): This command turns a document block into a header + definition of a member group. The comment block should be followed by a //@{...//@} + block containing the members of the group. +

    + +

    +If a compound (e.g. a class or file) has many members, it is often desired to group them together. Doxygen +already automatically groups things together on type and protection level, but maybe you feel that this is +not enough or that that default grouping is wrong. For instance, because you feel that members of different +(syntactic) types belong to the same (semantic) group. +A member group is defined by a +

    + +
    +  //@{
    +  ...
    +  //@}
    +  
    + +

    + block or a +

    + +
    +  /*@{*/
    +  ...
    +  /*@}*/
    +  
    + +

    + block if you prefer C style comments. Note that the members of the group should be physcially inside the + member group's body. +

    + +

    + Before the opening marker of a block a separate documentation block may be placed. This block should contain + the @name command and is used to specify the title of the group. Optionally, the documentation + block may also contain more detailed information about the group. +

    + +

    + Nesting of member groups is not allowed. +

    + +

    + If all members of a member group inside a class have the same type and protection level (for instance all + are static public members), then the whole member group is displayed as a subgroup of the type/protection + level group (the group is displayed as a subsection of the "Static Public Members" section for instance). + If two or more members have different types, then the group is put at the same level as the automatically + generated groups. If you want to force all member-groups of a class to be at the top level, you should put a + @nosubgrouping command inside the documentation of the class. +

    + + +

    + + @nosubgrouping: This command can be put in the documentation of a + class. It can be used in combination with member grouping to avoid that doxygen + put a member group as a subgroup of a Public/Protected/Private... section. +

    + +

    + + @overload [( function declaration )]: This command can be used to + generate the following standard text for an overloaded member function: 'This is + an overloaded member function, provided for convenience. It differs from the + above function only in what argument(s) it accepts.' The overload command does + not work inside a one-line comment. +

    + +

    + + @post { description of the post-condition }: Starts a paragraph where + the post-condition of an entity can be described. The paragraph will be indented. +

    + +

    + + @pre { description of the pre-condition }: Starts a paragraph where + the pre-condition of an entity can be described. The paragraph will be indented. +

    + +

    + + @showinitializer: By default, the value of a define and the + initializer of a variable are only displayed if they are less than 30 lines long. + By putting this command in a comment block of a define or variable, the + initializer is shown unconditionally. +

    + +

    + + @since YYYY.MM.DD: This tag can be used to specify since when an + entity has been avaliable. +

    + +

    + + @test { paragraph describing a test case }: Starts a paragraph where + a test can be described. The description will also add the test case to a + separate test list. The two instances of the description will be cross-referenced. +

    + + + + + + + + +
    +

    + + Including & Linking Files:

    + +

    + + @file <file-name>: Indicates that a comment block contains + documentation for a source or header file with name <name>.The + documentation of global functions, variables, typedefs, and enums will only be + included in the output if the file they are in is documented as well. +

    + +

    + + @htmlinclude <file-name>: This command includes the file as is + in the HTML documentation. +

    + +

    + + @image <format> <file> ["Caption"][<size-indication>=<size>] +

    + +

    + Syntax +

      +
    • format: html
    • +
    • file: image filename, no path
    • +
    • caption: brief description of the image, required, quoted
    • +
    • size indication: width | height
    • +
    • size: integer number of pixels
    • +
    • size indication: width | height
    • +
    +

    + +

    + Conventions +

      +
    • image file names: Object name + _ + filename (e.g., Statistics_graph.png)
    • +
    • image file locations: assets directory beneath the Object source code directory (e.g., $ISISROOT/src/base/obj/Statistics/assets/)
    • +
    +

    + +

    + Inserts an image into the documentation. Image files must be in the assets directory beneath + the Isis Object source code($ISISROOT/src/*/obj/*). If the image is found, it will be copied + to the correct output directory. +

    + +

    + This command is output format-specific, + so if you want to insert an image into generated documentation for more than one format, you'll have to + enter the command for each format. The format values supported are html and + latex, however Isis documentation is not generated in latex format, + so html should be the only format specified. + You can also use a URL to specify image + location, but doxygen will not check for existance or copy it into a directory + for you. The last argument is used to specify width and height of the image. The + image format for HTML is limited to what your browser supports. Doxygen does not + check if the image is in the correct format. +

    + +

    + + @include <file-name> and @includelineno <file-name>: + This command can be used to include a source file as a block of code. The + command takes the name of the include file or the line number as an argument. + Source files or directories can be specified by using the EXAMPLE_PATH tag in + the doxygen configuration file. +

    + +

    + + @dontinclude <file-name>: This command can be used to parse a + source file without actually verbatim including it (as @include does). + This is useful if you want to divide the source file into smaller pieces and add + documentation between the pieces. +

    + +

    + + @link <link-object>: The links that are automatically generated + in doxygen always have the name of the object they point to as link-text. The + link command can be used to create a link to an object with a user-specified + link-text. This command has a matching @endlink command. +

    + +

    + + @endlink: Ends a link that was started with the @link command. +

    + +

    + + @skip ( pattern ): This command searches line-by-line through the + example that was last included using @include or @dontinclude + until it finds a line that contains the specified pattern. +

    + +

    + + @line ( pattern ): This command searches line by line through the + example that was last included using @include and @dontinclude + until it finds a non-blank line. If that line contains the specified pattern, it + is written to the output. +

    + +

    + + @skipline ( pattern ): This command searches line-by-line through the + example that was last included using @include or @dontinclude + until it finds a line that contains the specified pattern. It then writes the + line to the output. The @skipline command is equivalent to @skip + followed by a @line. +

    + +

    + + @if <section-label>: Starts a conditional documentation section. + This section ends with a matching @endif command. + Conditional documentation is disabled by default. To enable it, you must put the + section label after the ENABLED_SECTIONS tag in the doxygen configuration file. +

    + +

    + + @elseif: Starts a conditional documentation section if the previous + section was not enabled. A conditional section is disabled by default. To enable + it, you must put the section-label after the ENABLED_SECTIONS tag in the + configuration file. Conditional blocks can be nested with proper ending commands. + (@endif, @ifnot, @else, @elseif). +

    + +

    + + @else: Starts a conditional section if the previous section was not + enabled. The previous should have started with an @if, @ifnot, or @elseif + command. +

    + +

    + + @endif: Ends a conditional documentation statement after beginning it + with the @if or @elseif commands. +

    + +

    + + @ifnot <section-label>: Starts a conditional documentation + section. This section ends with a matching @endif + command. This conditional statement is enabled by default. To disable it, you + must put the section label after the ENABLED_SECTIONS tag in the doxygen + configuration file. +

    + +

    + + @until ( pattern ): This command writes all lines of the example that + was last included using @include or @dontinclude to the output, + until it finds a line containing the specified pattern. The line containing the + pattern will be written as well. +

    + + +
    + + + HTML + + Useful Commands + + + usefulCommands.html + +
    + + + + + + + + + + +

    +Below is an example of a well documented header file, using our standard +commenting style. Note that in a collection of multiple tags, an +empty line must exist between different commands. Also notice the position of +documentation for the class and its members as the placement of these document blocks is +important. Remember, member functions are documented where they're implemented. +

    + +
    +
    +#ifndef Statistics_h
    +#define Statistics_h
    +/**
    + * @file
    + * $Date$
    + * $Revision$
    + *
    + *  Unless noted otherwise, the portions of Isis written by the USGS are public domain. See
    + *  individual third-party library and package descriptions for intellectual property information,
    + *  user agreements, and related information.
    + *
    + *  Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the
    + *  USGS as to the accuracy and functioning of such software and related material nor shall the
    + *  fact of distribution constitute any such warranty, and no responsibility is assumed by the
    + *  USGS in connection therewith.
    + *
    + *  For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html
    + *  in a browser or see the Privacy & Disclaimers page on the Isis website,
    + *  http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
    + *  http://www.usgs.gov/privacy.html.
    + */
    +
    +
    +#include "SpecialPixel.h"
    +
    +namespace Isis {
    +    /**
    +    * @brief This class is used to accumulate statistics on double arrays.
    +    *
    +    * This class is used to accumulate statistics on double arrays. In
    +    * particular, it is highly useful for obtaining statistics on cube data.
    +    * Parameters which can be computed are 1) @b average, 2) @b standard
    +    * @b deviation, 3) @b variance, 4) @b minimum, 5) @b maximum and 6)
    +    * @b various @b counts of valid and/or special pixels.
    +    *
    +    * The following example shows a simple set up and usage of the Statistics
    +    * class to calculate the average of a set of values:
    +    *
    +    * @code
    +    *   Statistics myStats ;
    +    *   double myData [] = { 1.0, 3.0, 2.4, 7.5 } ;
    +    *
    +    *   myStats.AddData (myData, 4) ;
    +    *   double myAverage = myStats.Average () ;
    +    *   cout << "The average of the data is " << myAverage << endl ;
    +    * @endcode
    +    *
    +    * For an example of how the Statistics object is used in %Isis, see the
    +    * Histogram object (inherits from Statistics) and the stats application,
    +    * stats.cpp (uses the Statistics child class Histogram).
    +    *
    +    * @ingroup Statistics
    +    *
    +    * @author Jeff Anderson - 2002-05-06
    +    *
    +    * @whatsnew 2002-05-06 The current sum and squared sum of the data can be retrieved
    +    *                      with the Sum and SumSquare methods.
    +    *
    +    * @internal
    +    * @history 2002-05-08 Jeff Anderson - Added Chebyshev and Best
    +    *                                     minimum/maximum methods.
    +    * @history 2004-05-11 Jeff Anderson - Moved Reset, AddData and
    +    *                                     RemoveData methods into
    +    *                                     public space.
    +    * @history 2004-06-28 Jeff Anderson - Added Sum and SumSquare
    +    *                                     methods.
    +    *
    +    * @todo 2005-02-07 Deborah Lee Soltesz - add example using cube
    +    *                                        data to the class documentation
    +    *
    +    */
    +  class Statistics {
    +    private:
    +      double p_sum;           //!< Sum accumulator.
    +      double p_sumsum;        //!< Sum-squared accumulator.
    +      double p_minimum;       //!< Minimum double value encountered.
    +      double p_maximum;       //!< Maximum double value encountered.
    +      double p_totalPixels;   //!< Count of total pixels processed.
    +      double p_validPixels;   //!< Count of valid pixels (non-special) processed.
    +      double p_nullPixels;    //!< Count of null pixels processed.
    +      double p_lrsPixels;     //!< Count of low instrument saturation pixels processed.
    +      double p_lisPixels;     //!< Count of low representation saturation pixels processed.
    +      double p_hrsPixels;     //!< Count of high instrument saturation pixels processed.
    +      double p_hisPixels;     //!< Count of high instrument representation pixels processed.
    +      bool   p_removedData;   /**< Indicates the RemoveData method was called which implies
    +                                   p_minimum and p_maximum are invalid. */
    +
    +    public:
    +      Statistics ();
    +      ~Statistics ();
    +
    +      void Reset ();
    +      void AddData (const double *data, const unsigned int count);
    +      void RemoveData (const double *data, const unsigned int count);
    +
    +      double Average () const;
    +      double StandardDeviation () const;
    +      double Variance () const;
    +
    +      double Minimum () const;
    +      double Maximum () const;
    +      double ChebyshevMinimum (const double percent=99.5) const;
    +      double ChebyshevMaximum (const double percent=99.5) const;
    +      double BestMinimum (const double percent=99.5) const;
    +      double BestMaximum (const double percent=99.5) const;
    +
    +      double TotalPixels () const;
    +      double ValidPixels () const;
    +      double NullPixels () const;
    +      double LisPixels () const;
    +      double LrsPixels () const;
    +      double HisPixels () const;
    +      double HrsPixels () const;
    +
    +
    +      /**
    +       * Returns the sum of all the data
    +       *
    +       * @return (double) Sum of the data
    +       */
    +      double Sum() const { return p_sum; };
    +
    +      /**
    +       * Returns the sum of all the squared data
    +       *
    +       * @return (double) Sum of the squared data
    +       */
    +      double SumSquare () const { return p_sumsum; };
    +  };
    +} // end namespace isis
    +  
    +
    + +

    +Download the Statistics header code example +

    + +

    + + View the corresponding HTML documentation that is generated by doxygen +

    + + +
    + + + HTML + + Example Header + + + exampleHeader.html + +
    + + + + + + + +

    +Below is an example of a perfectly commented implementation file, using our standard +documentation style. Note that in a collection of multiple tags, an +empty line must exist between different commands. Also notice the position of +documentation for each method as the placement of these document blocks is +important. +

    + +
    +
    +/**
    + * @file
    + * $Date$
    + * $Revision$
    + *
    + *  Unless noted otherwise, the portions of Isis written by the USGS are public domain. See
    + *  individual third-party library and package descriptions for intellectual property information,
    + *  user agreements, and related information.
    + *
    + *  Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the
    + *  USGS as to the accuracy and functioning of such software and related material nor shall the
    + *  fact of distribution constitute any such warranty, and no responsibility is assumed by the
    + *  USGS in connection therewith.
    + *
    + *  For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html
    + *  in a browser or see the Privacy & Disclaimers page on the Isis website,
    + *  http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
    + *  http://www.usgs.gov/privacy.html.
    + */
    +
    +#include <float.h>
    +#include <string>
    +#include "Statistics.h"
    +#include "iException.h"
    +
    +using namespace std;
    +namespace Isis {
    +  //! Constructs an IsisStats object with accumulators and counters set to zero.
    +  Statistics::Statistics () {
    +    Reset ();
    +  }
    +
    +  //! Reset all accumulators and counters to zero.
    +  void Statistics::Reset() {
    +    p_sum = 0.0;
    +    p_sumsum = 0.0;
    +    p_minimum = DBL_MAX;
    +    p_maximum = -DBL_MAX;
    +    p_totalPixels = 0.0;
    +    p_validPixels = 0.0;
    +    p_nullPixels = 0.0;
    +    p_lisPixels = 0.0;
    +    p_lrsPixels = 0.0;
    +    p_hrsPixels = 0.0;
    +    p_hisPixels = 0.0;
    +    p_removedData = false;
    +}
    +
    +  //! Destroys the IsisStats object.
    +  Statistics::~Statistics () {};
    +
    +  /**
    +   * Add an array of doubles to the accumulators and counters.
    +   * This method can be invoked multiple times (for example: once
    +   * for each line in a cube) before obtaining statistics.
    +   *
    +   * @param[in] data  (const double*)      data to be added to the data
    +   *                                       set used for statistical calculations
    +   *
    +   * @param[in] count (const unsigned int) number of elements in the incoming
    +   *                                       data to be added
    +   */
    +  void Statistics::AddData (const double *data, const unsigned int count) {
    +    for (unsigned int i=0; i<count; i++) {
    +      p_totalPixels++;
    +
    +      if (Isis::IsValidPixel(data[i])) {
    +        p_sum += data[i];
    +        p_sumsum += data[i] * data[i];
    +        if (data[i] < p_minimum) p_minimum = data[i];
    +        if (data[i] > p_maximum) p_maximum = data[i];
    +        p_validPixels++;
    +      } else if (Isis::IsNullPixel(data[i])) {
    +        p_nullPixels++;
    +      } else if (Isis::IsHisPixel(data[i])) {
    +        p_hisPixels++;
    +      } else if (Isis::IsHrsPixel(data[i])) {
    +        p_hrsPixels++;
    +      } else if (Isis::IsLisPixel(data[i])) {
    +        p_lisPixels++;
    +      } else {
    +        p_lrsPixels++;
    +      }
    +    }
    +  }
    +
    +  /**
    +   * Remove an array of doubles from the accumulators and counters.
    +   * Note that is invalidates the absolute minimum and maximum. They
    +   * will no longer be usable.
    +   *
    +   * @param[in]  data  (const double*)      data to be removed from data
    +   *                                       set used for statistical calculations
    +   *
    +   * @param[in]  count (const unsigned int) number of elements in the data to be removed
    +   *
    +   * @throws Isis::iException::Message
    +   */
    +  void Statistics::RemoveData (const double *data, const unsigned int count) {
    +    p_removedData = true;
    +
    +    for (unsigned int i=0; i<count; i++) {
    +      p_totalPixels--;
    +
    +      if (Isis::IsValidPixel(data[i])) {
    +        p_sum -= data[i];
    +        p_sumsum -= data[i] * data[i];
    +        p_validPixels--;
    +      } else if (Isis::IsNullPixel(data[i])) {
    +        p_nullPixels--;
    +      } else if (Isis::IsHisPixel(data[i])) {
    +        p_hisPixels--;
    +      } else if (Isis::IsHrsPixel(data[i])) {
    +        p_hrsPixels--;
    +      } else if (Isis::IsLisPixel(data[i])) {
    +        p_lisPixels--;
    +      } else {
    +        p_lrsPixels--;
    +      }
    +    }
    +
    +    if (p_totalPixels < 0) {
    +      string m="You are removing non-existant data in [Statistics::RemoveData]";
    +      throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_);
    +    }
    +  }
    +
    +  /**
    +   * Computes and returns the average.
    +   * If there are no valid pixels, then NULL8 is returned.
    +   *
    +   * @return (double) average
    +   */
    +  double Statistics::Average () const {
    +    if (p_validPixels < 1.0) return Isis::NULL8;
    +    return p_sum / p_validPixels;
    +  }
    +
    +  /**
    +   * Computes and returns the standard deviation.
    +   * If there are no valid pixels, then NULL8 is returned.
    +   *
    +   * @return (double) standard deviation
    +   */
    +  double Statistics::StandardDeviation () const {
    +    if (p_validPixels <= 1.0) return Isis::NULL8;
    +    return sqrt(Variance());
    +  }
    +
    +  /**
    +   * Computes and returns the variance.
    +   * If there are no valid pixels, then NULL8 is returned.
    +   *
    +   * @return (double) variance
    +   *
    +   * @internal
    +   * @history 2003-08-27 Jeff Anderson - Modified Variance method to compute
    +   *                                     using n*(n-1) instead of n*n.
    +   */
    +  double Statistics::Variance () const {
    +    if (p_validPixels <= 1.0) return Isis::NULL8;
    +    double temp = p_validPixels * p_sumsum - p_sum * p_sum;
    +    if (temp < 0.0) temp = 0.0; // This should happen unless roundoff occurs
    +    return temp / ((p_validPixels - 1.0) * p_validPixels);
    +  }
    +
    +  /**
    +   * Returns the absolute minimum double found in all data passed through the
    +   * AddData method. If there are no valid pixels, then NULL8 is returned.
    +   *
    +   * @return (double) current minimum value in data set
    +   *
    +   * @throws Isis::iException::Message
    +   */
    +  double Statistics::Minimum () const {
    +    if (p_removedData) {
    +      string m = "Minimum is invalid since you removed data";
    +      throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_);
    +    }
    +
    +    if (p_validPixels < 1.0) return Isis::NULL8;
    +    return p_minimum;
    +  }
    +
    +  /**
    +   * Returns the absolute maximum double found in all
    +   * data passed through the AddData method. If there
    +   * are no valid pixels, then NULL8 is returned.
    +   *
    +   * @return (double) current maximum value in data set
    +   *
    +   * @throws Isis::iException::Message
    +   */
    +  double Statistics::Maximum () const {
    +    if (p_removedData) {
    +      string m = "Maximum is invalid since you removed data";
    +      throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_);
    +    }
    +
    +    if (p_validPixels < 1.0) return Isis::NULL8;
    +    return p_maximum;
    +  }
    +
    +  /**
    +   * Returns the total number of pixels processed
    +   * (valid and invalid).
    +   *
    +   * @return (double) number of pixels (data) processed
    +   */
    +  double Statistics::TotalPixels () const {
    +    return p_totalPixels;
    +  }
    +
    +  /**
    +   * Returns the total number of valid pixels processed.
    +   * Only valid pixels are utilized when computing the
    +   * average, standard deviation, variance, minimum and
    +   * maximum.
    +   *
    +   * @return (double) number of valid pixels (data) processed
    +   */
    +  double Statistics::ValidPixels () const {
    +    return p_validPixels;
    +  }
    +
    +  /**
    +   * Returns the total number of NULL pixels encountered.
    +   *
    +   * @return (double) number of NULL pixels (data) processed
    +   */
    +  double Statistics::NullPixels () const {
    +    return p_nullPixels;
    +  }
    +
    +  /**
    +   * Returns the total number of low instrument
    +   * saturation (LIS) pixels encountered.
    +   *
    +   * @return (double) number of LIS pixels (data) processed
    +   */
    +  double Statistics::LisPixels () const {
    +    return p_lisPixels;
    +  }
    +
    +  /**
    +   * Returns the total number of low representation
    +   * saturation (LRS) pixels encountered.
    +   *
    +   * @return (double) number of LRS pixels (data) processed
    +   */
    +  double Statistics::LrsPixels () const {
    +    return p_lrsPixels;
    +  }
    +
    +  /**
    +   * Returns the total number of high instrument
    +   * saturation (HIS) pixels encountered.
    +   *
    +   * @return (double) number of HIS pixels (data) processed
    +   */
    +  double Statistics::HisPixels () const {
    +    return p_hisPixels;
    +  }
    +
    +  /**
    +   * Returns the total number of high representation
    +   * saturation (HRS) pixels encountered.
    +   *
    +   * @return (double) number of HRS pixels (data) processed
    +   */
    +  double Statistics::HrsPixels () const {
    +    return p_hrsPixels;
    +  }
    +
    +  /**
    +   * This method returns a minimum such that X percent
    +   * of the data will fall with K standard deviations
    +   * of the average (Chebyshev's Theorem). It can be
    +   * used to obtain a minimum that does not include
    +   * statistical outliers.
    +   *
    +   * @param[in]  percent (double) The probability that the minimum
    +   *                is within K standard deviations of the mean.
    +   *                Default value = 99.5.
    +   *
    +   * @return minimum value excluding statistical outliers
    +   *
    +   * @throws Isis::iException::Message
    +   */
    +  double Statistics::ChebyshevMinimum (const double percent) const {
    +    if ((percent <= 0.0) || (percent >= 100.0)) {
    +      string m = "Invalid value for percent";
    +      throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_);
    +    }
    +
    +    if (p_validPixels < 1.0) return Isis::NULL8;
    +    double k = sqrt (1.0 / (1.0 - percent / 100.0));
    +    return Average() - k * StandardDeviation();
    +  }
    +
    +  /**
    +   * This method returns a maximum such that
    +   * X percent of the data will fall with K
    +   * standard deviations of the average (Chebyshev's
    +   * Theorem). It can be used to obtain a minimum that
    +   * does not include statistical outliers.
    +   *
    +   * @param[in]  percent (double) The probability that the maximum
    +   *                is within K standard deviations of the mean.
    +   *                Default value = 99.5.
    +   *
    +   * @return maximum value excluding statistical outliers
    +   *
    +   * @throws Isis::iException::Message
    +   */
    +  double Statistics::ChebyshevMaximum (const double percent) const {
    +    if ((percent <= 0.0) || (percent >= 100.0)) {
    +      string m = "Invalid value for percent";
    +      throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_);
    +    }
    +
    +    if (p_validPixels < 1.0) return Isis::NULL8;
    +    double k = sqrt (1.0 / (1.0 - percent / 100.0));
    +    return Average() + k * StandardDeviation();
    +  }
    +
    +  /**
    +   * This method returns the better of the absolute
    +   * minimum or the Chebyshev minimum. The better
    +   * value is considered the value closest to the mean.
    +   *
    +   * @param[in]  percent (double) The probability that the minimum is within K
    +   *                standard deviations of the mean (Used to compute
    +   *                the Chebyshev minimum). Default value = 99.5.
    +   *
    +   * @return (double) Best of absolute and Chebyshev minimums
    +   *
    +   * @see Statistics::Minimum
    +   *      Statistics::ChebyshevMinimum
    +   */
    +  double Statistics::BestMinimum (const double percent) const {
    +    if (p_validPixels < 1.0) return Isis::NULL8;
    +    double min = ChebyshevMinimum (percent);
    +    if (Minimum() > min) min = Minimum();
    +    return min;
    +  }
    +
    +  /**
    +   *
    +   * This method returns the better of the absolute
    +   * maximum or the Chebyshev maximum. The better value
    +   * is considered the value closest to the mean.
    +   *
    +   * @param[in]  percent (double) The probability that the maximum is within K
    +   *                standard deviations of the mean (Used to compute
    +   *                the Chebyshev maximum). Default value = 99.5.
    +   *
    +   * @return (double) Best of absolute and Chebyshev maximums
    +   *
    +   * @see Statistics::Maximum
    +   *      Statistics::ChebyshevMaximum
    +   */
    +  double Statistics::BestMaximum (const double percent) const {
    +    if (p_validPixels < 1.0) return Isis::NULL8;
    +    double max = ChebyshevMaximum (percent);
    +    if (Maximum() < max) max = Maximum();
    +    return max;
    +  }
    +
    +} // end namespace isis
    +  
    +
    + +

    +Download the Statistics implementation code example +

    + +

    + + View the corresponding HTML documentation that is generated by doxygen +

    + + +
    + + + HTML + + Example Implementation + + + exampleImplementation.html + +
    + + + +

    Rules of Thumb

    + +
      +
    • All tags must have an ending tag, even if it is not normally required. + Eg. Text in a bullet, <li>, + must end with an ending bullet tag, </li> +
    • +
    • Empty tags (meaning tags that do not contain text and normally do not + have an ending tag) such as img + must have a slash before the ending angle bracket of the tag. Eg. + <img src="bob.gif" width="150" height="75" alt="Bob"/> +
    • +
    • Attribute (name-value pairs inside an HTML tag) values must be quoted. Eg. + <table width="600"> +
    • +
    • Only use body level tags (tags allowed + in the body of an HTML document). +
    • +
    • Do not use document structure elements, such as headings + (h1, h2, etc.) + and hr. Such elements are intended to structure the + document, not serve as pretty formatting. Your documentation is transformed into HTML + which already contains document structure elements. +
    • +
    • Use lower case for tag tag and attribute names. + <img src="bob.gif" width="150" height="75" alt="Bob"/> + not + <IMG SRC="bob.gif" WIDTH="150" HEIGHT="75" ALT="Bob"/> +
    • +
    • Avoid elements deprecated in HTML 4.01 and higher. Favorites include + U, CENTER, + and FONT. +
    • +
    + +

    + These rules are not a matter of taste, style, or preference... they're a matter of + conformance to standards. +

    + + +

    Reference

    + +

    HTML Tags

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + b + + Bold. + Renders current font as boldface. + + <b>This is bolded</b> appears as + This is bolded +
    + i + + Italic. Renders current font in italics. + + <i>This is italicized</i> appears as + This is italicized +
    + em + + Phrase element meaning "emphasis". Generally rendered by browsers in italics. + + <em>This is emphasized</em> appears as + This is emphasized +
    + strong + + Phrase element meaning "strong emphasis". Generally rendered by browsers in boldface. + + <strong>This is strongly emphasized</strong> appears as + This is strongly emphasized +
    + sup + + Superscript + + Bob<sup>1</sup> appears as + Bob1 +
    + sub + + Subscript + + Bob<sub>1</sub> appears as + Bob1 +
    + tt + + Teletype font. + Rendered in browser's default fixed-width font. + + <tt>This is teletype</tt> appears as + This is teletype +
    + pre + + Preformatted text. + Generally rendered in browser's default fixed-width font, with whitespace intact, and automatic word wrap disabled. + Generally browsers render all whitespace within this tag, and add padding before and after the tagged text. + This is not a quick and dirty alternative to tables! Use if for code snippets, data file snippets, etc. + +
    +            <pre>
    +              This is preformatted text.
    +              53.6    82.1    536.3
    +               8.53  137.6     66.3
    +            </pre>
    +            
    + + appears as + +
    +              This is preformatted text.
    +              53.6    82.1    536.3
    +               8.53  137.6     66.3
    +            
    + +

    + Whereas without the PRE tag, you'd get this: +

    + +

    + This is preformatted text. + 53.6 82.1 536.3 + 8.53 137.6 66.3 +

    +
    + table + + Table start/end + + +

    + Contains "tr" and "caption" tags. See more table tags below. + Eg. +

    + +
    +            <table>
    +              <caption>My table caption</caption>
    +              <tr>
    +                <th>
    +                Row 1, Column 1 Header
    +                </th>
    +                <th>
    +                Row 1, Column 2 Header
    +                </th>
    +                <th>
    +                Row 1, Column 3 Header
    +                </th>
    +              </tr>
    +
    +              <tr>
    +                <td>
    +                Row 2, Column 1
    +                </td>
    +                <td>
    +                Row 2, Column 2
    +                </td>
    +                <td>
    +                Row 2, Column 3
    +                </td>
    +              </tr>
    +
    +              <tr>
    +                <td>
    +                Row 3, Column 1
    +                </td>
    +                <td>
    +                Row 3, Column 2
    +                </td>
    +                <td>
    +                Row 4, Column 3
    +                </td>
    +              </tr>
    +            </table>
    +            
    + +

    + Looks like: +

    + + + + + + + + + + + + + + + + + + + + +
    My table caption
    + Row 1, Column 1 Header + + Row 1, Column 2 Header + + Row 1, Column 3 Header +
    + Row 2, Column 1 + + Row 2, Column 2 + + Row 2, Column 3 +
    + Row 3, Column 1 + + Row 3, Column 2 + + Row 4, Column 3 +
    + + +
    + caption + + Adds a caption to this table + + +
    + tr + + Table row start/end + + Contains TH and TD tags +
    + th + + Table row or column header cell + + Usually rendered with highlighting, bolding, or other special formatting to make the cell stand out. + Some accessibility readers will audibly repeat the contents of the TH before each cell in the column/row. +
    + td + + Table cell + + Stardard table cell in a row +
    +
    + +

    Special Characters

    + +

    + Some keyboard characters are reserved for special use. + Some characters you may wish to use are not accessible from + the keyboard. Use the special character sequences below. +

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + & + + &amp; + + Ampersand +
    + < + + &lt; + + Less than +
    + ≤ + + &le; + + Less than or equal +
    + > + + &gt; + + Greater than +
    + ≥ + + &ge; + + Greater than or equal +
    + ° + + &deg; + + Degree +
    + ± + + &plusmn; + + Plus or minus +
    + ÷ + + &divide; + + Division symbol +
    + × + + &times; + + Multiplication symbol +
    +
    +
    + + + HTML + + HTML Quick Reference + + HTMLQuickRef.html + +
    + +
    + +
    + diff --git a/isis/src/docsys/documents/DocStyle/assets/Statistics.cpp b/isis/src/docsys/documents/DocStyle/assets/Statistics.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c58e22e71b1360095b51fe6ac4e5f78c032c7f73 --- /dev/null +++ b/isis/src/docsys/documents/DocStyle/assets/Statistics.cpp @@ -0,0 +1,370 @@ +/** + * @file + * $Date: 2006/10/31 23:18:12 $ + * $Revision: 1.1.1.1 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Statistics.h" +#include "iException.h" + +using namespace std; +namespace Isis { + //! Constructs an IsisStats object with accumulators and counters set to zero. + Statistics::Statistics () { + Reset (); + } + + //! Reset all accumulators and counters to zero. + void Statistics::Reset() { + p_sum = 0.0; + p_sumsum = 0.0; + p_minimum = DBL_MAX; + p_maximum = -DBL_MAX; + p_totalPixels = 0.0; + p_validPixels = 0.0; + p_nullPixels = 0.0; + p_lisPixels = 0.0; + p_lrsPixels = 0.0; + p_hrsPixels = 0.0; + p_hisPixels = 0.0; + p_removedData = false; + } + + //! Destroys the IsisStats object. + Statistics::~Statistics () {}; + + /** + * Add an array of doubles to the accumulators and counters. + * This method can be invoked multiple times (for example: once + * for each line in a cube) before obtaining statistics. + * + * @param[in] data (const double*) data to be added to the data + * set used for statistical calculations + * + * @param[in] count (const unsigned int) number of elements in the incoming + * data to be added + */ + void Statistics::AddData (const double *data, const unsigned int count) { + for (unsigned int i=0; i p_maximum) p_maximum = data[i]; + p_validPixels++; + } else if (Isis::IsNullPixel(data[i])) { + p_nullPixels++; + } else if (Isis::IsHisPixel(data[i])) { + p_hisPixels++; + } else if (Isis::IsHrsPixel(data[i])) { + p_hrsPixels++; + } else if (Isis::IsLisPixel(data[i])) { + p_lisPixels++; + } else { + p_lrsPixels++; + } + } + } + + /** + * Remove an array of doubles from the accumulators and counters. + * Note that is invalidates the absolute minimum and maximum. They + * will no longer be usable. + * + * @param[in] data (const double*) data to be removed from data + * set used for statistical calculations + * + * @param[in] count (const unsigned int) number of elements in the data to be removed + * + * @throws Isis::iException::Message + */ + void Statistics::RemoveData (const double *data, const unsigned int count) { + p_removedData = true; + + for (unsigned int i=0; i= 100.0)) { + string m = "Invalid value for percent"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + if (p_validPixels < 1.0) return Isis::NULL8; + double k = sqrt (1.0 / (1.0 - percent / 100.0)); + return Average() - k * StandardDeviation(); + } + + /** + * This method returns a maximum such that + * X percent of the data will fall with K + * standard deviations of the average (Chebyshev's + * Theorem). It can be used to obtain a minimum that + * does not include statistical outliers. + * + * @param[in] percent (double) The probability that the maximum + * is within K standard deviations of the mean. + * Default value = 99.5. + * + * @return maximum value excluding statistical outliers + * + * @throws Isis::iException::Message + */ + double Statistics::ChebyshevMaximum (const double percent) const { + if ((percent <= 0.0) || (percent >= 100.0)) { + string m = "Invalid value for percent"; + throw Isis::iException::Message(Isis::iException::Programmer,m,_FILEINFO_); + } + + if (p_validPixels < 1.0) return Isis::NULL8; + double k = sqrt (1.0 / (1.0 - percent / 100.0)); + return Average() + k * StandardDeviation(); + } + + /** + * This method returns the better of the absolute + * minimum or the Chebyshev minimum. The better + * value is considered the value closest to the mean. + * + * @param[in] percent (double) The probability that the minimum is within K + * standard deviations of the mean (Used to compute + * the Chebyshev minimum). Default value = 99.5. + * + * @return (double) Best of absolute and Chebyshev minimums + * + * @see Statistics::Minimum + * Statistics::ChebyshevMinimum + */ + double Statistics::BestMinimum (const double percent) const { + if (p_validPixels < 1.0) return Isis::NULL8; + double min = ChebyshevMinimum (percent); + if (Minimum() > min) min = Minimum(); + return min; + } + + /** + * + * This method returns the better of the absolute + * maximum or the Chebyshev maximum. The better value + * is considered the value closest to the mean. + * + * @param[in] percent (double) The probability that the maximum is within K + * standard deviations of the mean (Used to compute + * the Chebyshev maximum). Default value = 99.5. + * + * @return (double) Best of absolute and Chebyshev maximums + * + * @see Statistics::Maximum + * Statistics::ChebyshevMaximum + */ + double Statistics::BestMaximum (const double percent) const { + if (p_validPixels < 1.0) return Isis::NULL8; + double max = ChebyshevMaximum (percent); + if (Maximum() < max) max = Maximum(); + return max; + } + +} // end namespace isis diff --git a/isis/src/docsys/documents/DocStyle/assets/Statistics.h b/isis/src/docsys/documents/DocStyle/assets/Statistics.h new file mode 100644 index 0000000000000000000000000000000000000000..2b25af3a77eb408b017e4c82895b18eefd2ae10d --- /dev/null +++ b/isis/src/docsys/documents/DocStyle/assets/Statistics.h @@ -0,0 +1,128 @@ +#ifndef Statistics_h +#define Statistics_h +/** + * @file + * $Date: 2006/10/31 23:18:12 $ + * $Revision: 1.1.1.1 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +#include "SpecialPixel.h" + +namespace Isis { + /** + * @brief This class is used to accumulate statistics on double arrays. + * + * This class is used to accumulate statistics on double arrays. In + * particular, it is highly useful for obtaining statistics on cube data. + * Parameters which can be computed are 1) @b average, 2) @b standard + * @b deviation, 3) @b variance, 4) @b minimum, 5) @b maximum and 6) + * @b various @b counts of valid and/or special pixels. + * + * The following example shows a simple set up and usage of the Statistics + * class to calculate the average of a set of values: + * + * @code + * Statistics myStats ; + * double myData [] = { 1.0, 3.0, 2.4, 7.5 } ; + * + * myStats.AddData (myData, 4) ; + * double myAverage = myStats.Average () ; + * cout << "The average of the data is " << myAverage << endl ; + * @endcode + * + * For an example of how the Statistics object is used in %Isis, see the + * Histogram object (inherits from Statistics) and the stats application, + * stats.cpp (uses the Statistics child class Histogram). + * + * @ingroup Statistics + * + * @author Jeff Anderson - 2002-05-06 + * + * @whatsnew 2002-05-06 The current sum and squared sum of the data can be retrieved + * with the Sum and SumSquare methods. + * + * @internal + * @history 2002-05-08 Jeff Anderson - Added Chebyshev and Best minimum/maximum methods. + * @history 2004-05-11 Jeff Anderson - Moved Reset, AddData and RemoveData methods into public space. + * @history 2004-06-28 Jeff Anderson - Added Sum and SumSquare methods. + * + * @todo 2005-02-07 Deborah Lee Soltesz - add example using cube data to the class documentation + * + */ + class Statistics { + private: + double p_sum; //!< Sum accumulator. + double p_sumsum; //!< Sum-squared accumulator. + double p_minimum; //!< Minimum double value encountered. + double p_maximum; //!< Maximum double value encountered. + double p_totalPixels; //!< Count of total pixels processed. + double p_validPixels; //!< Count of valid pixels (non-special) processed. + double p_nullPixels; //!< Count of null pixels processed. + double p_lrsPixels; //!< Count of low instrument saturation pixels processed. + double p_lisPixels; //!< Count of low representation saturation pixels processed. + double p_hrsPixels; //!< Count of high instrument saturation pixels processed. + double p_hisPixels; //!< Count of high instrument representation pixels processed. + bool p_removedData; /**< Indicates the RemoveData method was called which implies + p_minimum and p_maximum are invalid. */ + + public: + Statistics (); + ~Statistics (); + + void Reset (); + void AddData (const double *data, const unsigned int count); + void RemoveData (const double *data, const unsigned int count); + + double Average () const; + double StandardDeviation () const; + double Variance () const; + + double Minimum () const; + double Maximum () const; + double ChebyshevMinimum (const double percent=99.5) const; + double ChebyshevMaximum (const double percent=99.5) const; + double BestMinimum (const double percent=99.5) const; + double BestMaximum (const double percent=99.5) const; + + double TotalPixels () const; + double ValidPixels () const; + double NullPixels () const; + double LisPixels () const; + double LrsPixels () const; + double HisPixels () const; + double HrsPixels () const; + + + /** + * Returns the sum of all the data + * + * @return (double) Sum of the data + */ + double Sum() const { return p_sum; }; + + /** + * Returns the sum of all the squared data + * + * @return (double) Sum of the squared data + */ + double SumSquare () const { return p_sumsum; }; + }; +} // end namespace isis + + + diff --git a/isis/src/docsys/documents/EnvironmentAndPreferencesSetup/EnvironmentAndPreferencesSetup.xml b/isis/src/docsys/documents/EnvironmentAndPreferencesSetup/EnvironmentAndPreferencesSetup.xml new file mode 100644 index 0000000000000000000000000000000000000000..0594651180dd130d490c4646034c934e6d55ff46 --- /dev/null +++ b/isis/src/docsys/documents/EnvironmentAndPreferencesSetup/EnvironmentAndPreferencesSetup.xml @@ -0,0 +1,160 @@ + + + + + + + +

    Introduction

    +

    + This document describes how to setup your Unix environment in order to run Isis. + It also discusses the Isis Preference files, which gives the user the ability to + customize the operation of Isis. +

    + +

    Unix Setup

    + +

    + Assuming Isis 3 has been successful installed on your computer (see + Isis Download and Installation Guide), + you will need to add a few commands to your startup file. For the + C-shell, add the following commands to the $HOME/.login file or the equivalent system-wide + startup file: + +

    +setenv ISISROOT directory
    +setenv PATH ${PATH}:${ISISROOT}/bin
    +setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:${ISISROOT}/lib
    +        
    + + where directory is the location of the Isis tree. +

    + +

    + If you are using the Bourne shell or a derivative (e.g., bash), add the following commands + to your .profile file or the equivalent system-wide startup file: + +

    +set ISISROOT directory
    +PATH=${PATH}:${ISISROOT}/bin
    +LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${ISISROOT}/lib
    +          
    +

    + +

    + Before you add these commands to your startup script you may want to check with your local system + administrator to see if they have already done this step. You can use the following command to see + if Isis is already setup: + +

    +echo $ISISROOT
    +        
    +

    + +

    + It will output either the directory of the Isis system or + + "ISISROOT: Undefined variable", which implies the Isis is not setup and/or not installed. +

    + + +

    System Preference File

    +

    + Your local Isis administrator manages a system-wide preference file. The file $ISISROOT/IsisPreferences, + is in Parameter Value Language (PVL) format, and contains specifications for how Isis should operate. + For example, +

    + +
    +Group = UserInterface
    +  ProgressBarPercent = 10
    +EndGroup
    +        
    + +

    + Implies the application progress bar (GUI thermometer) for all users will change by + 10% for every Isis user by default. To find out specifics about various user preferences + see the Isis Preference Dictionary. +

    + +

    User Preference File

    + +

    + The user can override elements of the system wide preference file by creating a personal preference + file. The file must reside in the hidden directory $HOME/.Isis and must be named IsisPreferences. +

    + +

    + An example usage is, +

    + +
    +Group = UserInterface
    +  ProgressBarPercent = 1
    +EndGroup
    +        
    + + +

    Project Preference File

    + + +

    + [Future Option] Finally the highest priority preference file is a project file. It is specified on the command line when + executing Isis applications. For example, +

    + +
    +highpass -pref=/bigProject/Preferences
    +
    + +

    + This allows for large batch/scripted projects to ensure all users involved in the project + have the same preferences. +

    +
    + +
    +

    Tips For Programmers

    +

    + Every Isis application program should instantiate an IsisProcess object or one of its + derivatives; if you don’t your doing a lot of unnecessary work! The instantiation allows + for access, in the rare case that an application needs it, to a user preference. For example, + + +

    +IsisProcessByLine p;
    +
    +IsisPreference *pref = p.GetPreferences();
    +pref->UseGroup(“DataAreasâ€);
    +string directory = pref->GetString("Voyager");
    +
    +

    + +

    + See the Isis Developers Reference. +

    +
    + + + HTML + + EnvironmentAndPreferencesSetup.html + +
    +
    + + administration + guide + + + intermediate + administrator + + + Environment & Preference Setup + Setting up the Unix environment and customizing Isis preferences + Setting up the Unix environment to run Isis and customizing the operation of Isis + Jeff Anderson + 2003-06-25 + +
    diff --git a/isis/src/docsys/documents/ErrorDictionary/ErrorDictionary.xml b/isis/src/docsys/documents/ErrorDictionary/ErrorDictionary.xml new file mode 100644 index 0000000000000000000000000000000000000000..62d942d8a0bcc51569e958ef31417fad5ec6a26d --- /dev/null +++ b/isis/src/docsys/documents/ErrorDictionary/ErrorDictionary.xml @@ -0,0 +1,194 @@ + + + + + + +

    + Introduction +

    +

    + This dictionary contains information regarding the various classes of errors that can occur in Isis programs. Below is a table of the classes of errors with accompanying error codes. The code is sent to the operating system when a program exits due to an error. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Class + + Code +
    + User Error + + 1 +
    + Programmer Error + + 2 +
    + PVL Error + + 3 +
    + I/O Error + + 5 +
    + Camera Error + + 6 +
    + Projection Error + + 7 +
    + Parse Error + + 8 +
    + System Error + + 255 +
    + + +

    + User Error +

    +

    + This error occurs when the user chooses values for input parameters that are invalid. + Examples include entering 1) a negative integer when the parameter only allows positive integers, + 2) parameters that do not exist in a program (usually a typo), and 3) entering a value not in a required + list (8bit, 16bit, 32bit). The error is almost always related to the user input provided in either the + Isis GUI or on the command line. +

    + +

    + Programmer Error +

    +

    + This should be a rare error. It occurs when the programmer supplied invalid information to a C++ + class and/or method. Generally, these errors are caught by the programmer during the development + stage of the software. They can occur under unusual circumstances such as array out-of-bounds or + memory leaks. Users should report these errors to the + Isis Support Site. +

    + +

    + PVL Error +

    +

    + Isis makes heavy use of Parameter Value Language (PVL). The most common error that can occur with + PVL is requesting parameter-values (Objects, Groups, or Keywords) that do not exist. Generally, the + PVL error message is the most specific information in a stack of error messages. For example, +

    + +
    +** PVL ERROR** Could not find requested keyword [SpacecraftName]
    +** LABEL ERROR** Error in label file [moon.cub]
    +** CAMERA ERROR ** Unable to initialize camera model
    +          
    + +

    + I/O Error +

    +

    Errors of this nature are directly related to file I/O. This includes opening, closing, reading, or + writing files. These errors could include 1) non-existent file on open/allocate, generally caused by a + misspelling or wrong directory paths, 2) read and/or write permission violations based on user or group + ownership, and 3) insufficient disk space for allocation of an output file. +

    + +

    + Camera Error +

    +

    Generally, a handful of conditions can cause a camera error. One of the most common is the cube does + not have Instrument and Kernels group and therefore is not a raw camera cube. Programs such as cam2map, + camtrim, or others beginning with “cam†require such groups in the cube labels. If the cube has an Instrument + group but not a Kernel group you should run the “caminit†program on your cube. Other sources of problems may + include missing keywords in the Instrument group, invalid pointers to SPICE files in the kernel group, or + unsupported instruments. +

    + +

    + Projection Error +

    +

    Projection errors occur when reading labels of a cube or a map file. In most cases, a require keyword + is missing or there may be some type of syntax error with the map projection group. Another possibility + is that the map projection is not supported by the Isis system. +

    + +

    + Parse Error +

    +

    This error occurs when parsing command lines or PVL files. Generally, the syntax of a file or command + line is not correct and can include problems such as missing quotes, parenthesis, equal signs, etc. +

    + +

    + System Error +

    +

    This error relates to operating system or instruction set errors. Example may include insufficient + dynamic memory, out of bounds array errors, or division by zero. Often these errors are due to insufficient + checks made by the programmer. Such error should be submitted to the Isis support web site. +

    + + + + HTML + + ErrorDictionary.html + +
    +
    + + reference + + + intermediate + + + Error Dictionary + Reference of error messages, their meanings, and resolving errors + Reference of error messages, their meanings, and resolving errors + Jeff Anderson + 2003-06-30 + + + + +
    diff --git a/isis/src/docsys/documents/ErrorHandlingFacility/ErrorHandlingFacility.xml b/isis/src/docsys/documents/ErrorHandlingFacility/ErrorHandlingFacility.xml new file mode 100644 index 0000000000000000000000000000000000000000..eb4aee21e5a7cdd831cd3454dbe34df80f633d06 --- /dev/null +++ b/isis/src/docsys/documents/ErrorHandlingFacility/ErrorHandlingFacility.xml @@ -0,0 +1,262 @@ + + + + + + + +

    Introduction

    +

    +Errors will occur when running Isis applications. For example, the user may have entered invalid parameters +or I/O to a file may have failed due to insufficient disk space. This document discusses the various aspects +of the Isis Error Handling Facility. +

    + +

    +When an error occurs several elements can be reported. They include: +

    + +
      +
    • Program name
    • +
    • Class of error
    • +
    • Error code
    • +
    • Specific message
    • +
    • Source code file
    • +
    • Line number in the source code file
    • +
    + + +

    +How these elements are presented and where they are written is user selectable as described in the +Isis Preference Dictionary. +

    + +

    Standard Form

    + +

    +The standard form of an error message is + +

    +**CLASS** MESSAGE in FILE at LINE
    +
    + +Two examples are given below, + +
    +**USER ERROR** Parameter [TO] must be entered in IsisAml.cpp at 1613
    +**I/O ERROR** Unable to open cube [moon.cub] in IsisCube.cpp at 203
    +
    +

    + +

    +The CLASS +is a general identifier that can help the user narrow down the scope of the problem. Other +CLASSES include +SYSTEM ERROR, +PROJECTION ERROR, and +CAMERA ERROR. +Because there are a variety of error +CLASSES we have developed the +Isis Error Dictionary. This dictionary gives +users additional context regarding the error, which may direct them to a solution. +

    + +

    +The MESSAGE +gives more specific information regarding the error. It is standard practice to place the offending +problem in square brackets. This will help the user narrow the scope of the problem even further. +

    + +

    +The FILE at +LINE is an element +of the message more useful for programmers. This allows the programmer to track down problems more easily. +Some users may desire to turn this feature off and can do so by modifying their personal +Isis Preference file. + +

    +Group = ErrorFacility
    +  FileLine = On | Off
    +EndGroup
    +
    +

    + +

    PVL Form

    +

    +The standard form can be overridden by modifying the Preference file. + +

    +Group = ErrorFacility
    +  Format = Standard | PVL
    +EndGroup
    +
    + +This forces the output of errors messages to be in Parameter Value Language format. Our previous standard form example, + +
    +**I/O Error** Unable to open cube [moon.cub] in IsisCube.cpp at 203
    +
    + +would be presented in the following format, + +
    +Group = Error
    +  Program = highpass
    +  Class   = "I/O ERROR"
    +  Code    = -3
    +  Message = "Unable to open cube [moon.cub]"
    +  Source  = IsisCube.cpp
    +  Line    = 203
    +EndGroup
    +
    +

    + +

    Errors and the GUI

    + + + + + +
    + + [GUI error screen shot] +

    + Screen shot of illustrating a GUI error message. +

    +

    + 600x500, 15KB +

    +
    + +

    +When an error occurs in the GUI +it is written to the error dialog box. Because the GUI is interactive, +the user has a chance to correct the problem and continue program execution. +

    +

    +[Future Option] Any of the message text appearing +inside of brackets will be show in red, further highlighting the offending problem. + +

    + +
    + +

    Errors and the Command Line

    + +

    +When an error occurs under the command line or batch-processing mode. The error report is written to the +STDERR stream. +Unlike the GUI, the program immediately terminates with a status code. +Output to "standard error" allows redirection of erros to files using standard Unix commands. For example, + +

    +highpass from=bad.cub >& error.txt
    +
    +

    + +

    Program Exit Status

    +

    +Under the command line, programs that run successfully will exit with a zero status. If an error is generated +then the program will exit with a non-zero status. The status has a 1-to-1 correlation with the +CLASS of +error (e.g., User, +I/O ERROR). +To find out the various CLASS +versus CODE relationships you should examine +the Isis Error Dictionary. +

    + +

    +Under the GUI, the program always exits successfully as the +user has the opportunity to correct errors. +

    + +

    Errors and the Session Log

    +

    +When an error occurs it will be written in the standard or PVL form to the +Session Log. +That is, it may be written to the log file and/or the terminal screen depending upon the log settings +in the user preference file. +

    + +
    +

    Tips For Programmers

    +

    +Dealing with errors in Isis is generally quite simple. Application programs will automatically trap +errors using C++ expections. For example, the following program has no required error checking. +It will automatically report invalid user input or I/O errors such as opening or allocating cubes. + + +

    
    +using namespace std;
    +#include "Isis.h"
    +#include "IsisProcessByLine.h"
    +#include "IsisSpecialPixel.h"
    +
    +void mirror (IsisBuffer &in, IsisBuffer &out);
    +
    +void IsisMain() {
    +  // We will be processing by line
    +  IsisProcessByLine p;
    +                               
    +  // Setup the input and output cubes
    +  p.SetInputCube("FROM");
    +  p.SetOutputCube ("TO");
    +
    +  // Start the processing
    +  p.StartProcess(mirror);
    +  p.EndProcess();
    +}
    +
    +// Line processing routine
    +void mirror (IsisBuffer &in, IsisBuffer &out) {
    +  // Loop and flip pixels in the line.
    +  int index = in.size() - 1;
    +  for (int i=0; i<in.size(); i++) {
    +    out[i] = in[index - i];
    +  }
    +}
    +
    +

    + +

    +On occasions the programmer may be required report an error. This can be facilitated in the following manner: + +

    
    +IsisCubePacket *from = p.SetInputCube("FROM");
    +
    +if (from->Lines() / 2 == 0) {
    +  string msg = "Input cube [" + from->Filename() +
    +                "must have an odd number of lines" ;
    +  throw IsisErrorUser (msg,_FILEINFO_);
    +}
    +
    +

    + +

    + See the Isis Developers Reference. +

    + +
    + + + HTML + + ErrorHandlingFacility.html + +
    +
    + + guide + + + intermediate + + + Error Handling Facility + Guide to the various aspects of the Error Handling Facility + General overview of the Error Handling Facility, what form error messages take, how error messages differ between the command line and GUI, and Tips For Programmers. + Jeff Anderson + 2003-06-25 + +
    diff --git a/isis/src/docsys/documents/ErrorHandlingFacility/assets/screenshot_guierror.gif b/isis/src/docsys/documents/ErrorHandlingFacility/assets/screenshot_guierror.gif new file mode 100644 index 0000000000000000000000000000000000000000..9cbe9bf7fdd1df98bea9ddcb03d35087aca63d0f Binary files /dev/null and b/isis/src/docsys/documents/ErrorHandlingFacility/assets/screenshot_guierror.gif differ diff --git a/isis/src/docsys/documents/ErrorHandlingFacility/assets/screenshot_guierror.psd b/isis/src/docsys/documents/ErrorHandlingFacility/assets/screenshot_guierror.psd new file mode 100644 index 0000000000000000000000000000000000000000..2399ad4267b75b03a740ad549dfc0fd661d64bd0 Binary files /dev/null and b/isis/src/docsys/documents/ErrorHandlingFacility/assets/screenshot_guierror.psd differ diff --git a/isis/src/docsys/documents/ErrorHandlingFacility/assets/thumbs/screenshot_guierror.gif b/isis/src/docsys/documents/ErrorHandlingFacility/assets/thumbs/screenshot_guierror.gif new file mode 100644 index 0000000000000000000000000000000000000000..12ae4eae60580bcfc253796a54e8cc5f198bbb80 Binary files /dev/null and b/isis/src/docsys/documents/ErrorHandlingFacility/assets/thumbs/screenshot_guierror.gif differ diff --git a/isis/src/docsys/documents/HowToApplicationCategoryTest/HowToApplicationCategoryTest.xml b/isis/src/docsys/documents/HowToApplicationCategoryTest/HowToApplicationCategoryTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..6069ad8a8f95784797b8d0992c085c8fc92e3e9a --- /dev/null +++ b/isis/src/docsys/documents/HowToApplicationCategoryTest/HowToApplicationCategoryTest.xml @@ -0,0 +1,658 @@ + + + + + xml + technicaldoc + guide + + + + developer + + + + Isis Application and Category Test How-to + Guide to writing an application and category tests + Guide to writing application and category tests using make. This guide describes + step by step the process of writing a test for an application or category. The guide + also gives general guidance on errors and common mistakes in writing a test. + + Robert Wallace + 2006-08-08 + + + + + + HTML + + index.html + + + +

    Overview

    +

    + Isis Application Test files are used to ensure that an application is working correctly. Isis Category Test files are + used to ensure that a category is working correctly. These tests are especially important when porting to a new + operating system, or changing compilers. They are also important when changes are made to the entire + system (such as refactoring) or to other files that directly affect the application. If something is changed that affects + the outcome of the application, the test will fail, making the programmer aware that something has changed and + needs to be examined. This guide focuses on the specific + task of adding tests to an existing application or category. +

    + + +

    Questions & Answers

    + +

    What do I need to know?

    +

    + You need to be familiar with what the application or category does in order to test it properly. Also a basic knowledge of make + would be helpful but not required. +

    + +

    What is make?

    +

    + Make is a programming tool used to automate the build process. Make is used used to build C/C++ projects. +

    + + +

    Make Basics

    + +

    Targets

    +

    + Make is a text file that is broken down into what is known as targets. Targets represent a series of actions as a + single word. Targets are distinguished by the colon ( : ) after the target name +

    +                        
    +                            clean:
    +                            	
    +                            actions
    +                        
    +                    
    + An action is a single command that is terminated by a semicolon ( ; ). If a command must be on multiple lines, each line + must end with a backslash ( \ ). +
    +                        
    +                            clean:
    +                            	ratio num=isisTruth.cub+1 \
    +                            	den=isisTruth.cub+2 \
    +                            	to=temp.cub;
    +                        
    +                    
    + + If there is any character, after the backslash (even a space), the command will end + at that line. Make will not show an error but the command will not run as intended. +

    + Each line in a target must be preceded with a tab character. Make will show an error if there is not a tab at the + front of each line in a target. +

    +

    + +

    Variables

    +

    + Make allows for variables to be used to store values. These variables can be set at the command line by using + the syntax VARIABLE=value. For example, setting the variable clean would be CLEAN=yes. Variables are usually in + all capital letters. Variables are accessed using the $( ) syntax. For example, using the clean variable would be + $(CLEAN). +

    + + +

    Writing a Test for an application

    + +

    Test Structure

    +

    + A test is composed of input, output, truth and make files. All of the files the test needs as input are placed in the + input directory. Everything the test generates goes into the output directory. When the test is working correctly the + output files representing the base truth files of the test are placed in the truth directory. The make file contains the + commands to run the test. +

    + +

    Test Results

    +

    + Tests are to ensure that the programs are running correctly. This is done by comparing the output files generated + by the test with the files designated as the truth for the test. If the files have the same contents the test shows an + OK status. If the files are different in some way the test shows a FAILED status. +

    + +

    Setup Tests

    +
      +
    1. Go to the directory where the application directory is located
    2. +
    3. Type + make testdir +
    4. +
        +
      1. This creates a directory call tsts
      2. +
      3. Places a Makefile for creating tests in the tsts directory
      4. +
      +
    + +

    Setup Individual Test

    +
      +
    1. Within the tsts directory type + make newtest TEST=testname +
    2. +
        +
      1. Where testname is the name of the test. Testname should decribe what the test is testing for.
      2. +
      3. e.g. if the program has a variable mode that can be ALL or NONE, the test for mode all would be + named all and the test for mode none would be none.
      4. +
      5. The command would be + make newtest TEST=all +
      6. +
      7. This creates a directory called testname and places a template makefile, and an input directory in that directory
      8. +
      +
    3. Type + cd testname + to chage directories to the test
    4. +
    + + The template makefile should look like this. +
    +                    
    +                        APPNAME =
    +
    +                        include $(ISISROOT)/make/isismake.tsts
    +
    +                        commands:
    +                        > /dev/null;
    +                    
    +                
    +
      +
    1. APPNAME - name of the application being tested
    2. +
    3. include - includes all targets from the isismake.tsts file
    4. +
    5. commands - defines the commands target needed to run the test
    6. +
    7. /dev/null - all actions are placed before or on this line
    8. +
    +

    Write Test

    +
      +
    1. APPNAME - type in the application name after the equals. Capitalization and spelling count here.
    2. +
        +
      1. The excetable for the test resides two directories above the test. APPNAME is adjusted + during the run of the test to take care of this. APPNAME should just be the name of the program. + Each time the test is run, the current version of the executable is used. Running the test will not + remake the executable.
      2. +
      +
    3. Write in commands before the > /dev/null.
    4. +
        +
      1. Remember
      2. +
          +
        1. if multiple commands are needed than each needs > /dev/null; + at the end of the commands
        2. +
        3. beginning of each line needs a tab character
        4. +
        5. if a command goes onto multiple lines, end of each line needs a \ with + nothing after it
        6. +
        +
      +
    5. Type $(APPNAME) where the need of the current application is being used. Other program names + should just be the name of the program.
    6. +
    7. Copy any input files to the input directory
    8. +
    9. Set all paths in the test so that the input files have $(INPUT) before the filename
    10. +
    11. Set all paths in the test so that the output files have $(OUTPUT) before the filename
    12. +
        +
      1. Files that are to be compared for the test must be in the output directory
      2. +
      +
    13. If the test is testing standardout, the output must be redirected to a text file. Change the /dev/null to + the name of a text file for comparison. See cathist for an example of this.
    14. +
    15. To generate the output files for the test type + make output +
    16. +
    17. Add variables as needed to the test. Variables are defined in the next section
    18. +
    19. When the output file looks good type + make truthdata +
    20. +
        +
      1. if the test is operating system dependent test than do + make ostruthdata +
      2. +
      +
    21. To run the test, type + make test + . At this point the test shoud pass. If not, revise the test till it does.
    22. +
    + +

    Test Variables

    +

    + Tests deal with files. Variables for the tests are strings attached to the end of file names. For example + if the file is test.txt then the variable IGNORELINES would be test.txt.IGNORELINES. The file portion must match spelling and + capitalization of the file it is assoiciated with. The variable portion (.IGNORELINES) needs to be in all capital letters. + For each file in the test if the variable is not set than a default value is used. + +
    +
    + Possible variables for file types are: +

      +
    1. Cub files (.cub)
    2. +
        +
      1. .TOLERANCE
      2. +
          +
        1. Defines the difference in dn values allowed between the cubes generated by the test and the truth cubes, + to allow the test to pass
        2. +
        3. Value - number, usually a small decimal value
        4. +
        5. Defaults - 0, meaning that the two dn values have to match exactly
        6. +
        7. For an example, see the mpp test in the cam2map application
        8. +
        +
      3. .IGNORESPECIAL
      4. +
          +
        1. Designates whether or not to ignore special pixels in comparing two cubes
        2. +
        3. Value - yes or no value
        4. +
        5. Defaults - no, special pixels will be used in the comparison of two cube files
        6. +
        +
      +
    3. Text Files (.txt)
    4. +
        +
      1. .SKIPLINES
      2. +
          +
        1. Defines the number of lines to skip at the beginning of a text file
        2. +
        3. Value - number, integer
        4. +
        5. Defaults - 0, meaning that the whole file it to be used
        6. +
        7. For an example, see the cnet test in the coreg application
        8. +
        +
      3. .IGNORELINES
      4. +
          +
        1. Defines the lines of text to omit from the output file
        2. +
        3. Value - list of word at the beginning of the lines to omit
        4. +
        5. Defaults - empty list, use the whole file
        6. +
        7. For an example, see the circle test in the isisui application
        8. +
        +
      5. Note: SKIPLINES occurs before IGNORELINES
      6. +
      +
    5. Binary Files (.jpg .tif .bin ...)
    6. +
        +
      1. .BINSKIP
      2. +
          +
        1. Defines the number of bytes to skip at the start of an input file
        2. +
        3. Value - number, integer
        4. +
        5. Defaults - 0, meaning that the whole file is to be used
        6. +
        +
      3. .BINCOUNT
      4. +
          +
        1. Defines the number of bytes to copy to the output file
        2. +
        3. Value - number, integer
        4. +
        5. Defaults - 0, meaning that the whole file is to be used
        6. +
        +
      +
    7. Pvl Files (.pvl)
    8. +
        +
      1. .SKIPLINES, .IGNORELINES
      2. +
          +
        1. Because a pvl file is essentially a formatted text file, test variables that work on text files will work the same way on pvl files
        2. +
        +
      3. .DIFF
      4. +
          +
        1. See Pvl Files for setting variables when comparing pvl files.
        2. +
        +
      +
    +

    + +

    Pvl Files

    +

    + In order to assure the most accurate testing possible, pvl (parameter value language) files are compared by parsing through the groups, objects and keywords in the file. + Any file with a .pvl extension is considered a pvl file. Because pvl files contain text, the text file test variables will work on the pvl files; it is not recommended to use + these test variables, however, and the result must still be a valid pvl file. The order of the keywords, objects and groups matter and may not be different in any case. + In order to set tolerances and ignore keywords, a pvl tolerance file with .DIFF attached to the end will be used. For example, if if file is test.pvl then the tolerance file must be named + test.pvl.DIFF. These files must only exist in the input data + directory. Inside the pvl tolerance file you can specify + numerical tolerances and keywords to ignore. Inside the pvl + tolerance file, there should be one or two groups, Tolerances + and IgnoreKeys, in the root of the file. So, a basic pvl + tolerance file looks like this: +

    +                   
    +Group = Tolerances
    +End_Group
    +
    +Group = IgnoreKeys
    +End_Group
    +
    +End
    +                   
    +                 
    + To set a tolerance on a number, inside the Tolerances group there must be a keyword in this format: +
    +                   
    +KeywordName = MaximumDifference
    +                   
    +                 
    + If the output and truth data values exceed the maximum difference (tolerance), then the files are not considered the same. In order to ignore a non-numerical value, such as a + file name, inside the IgnoreKeys group there must be a keyword in this format: +
    +                   
    +KeywordName = true
    +                   
    +                 
    + Note: The value of this keyword does not matter.
    + With these formats in mind, to give a tolerance for the keyword + StandardDeviation of 0.0000000001 and ignore the keyword + FileName the pvl tolerance file would look like this: +
    +                   
    +Group = Tolerances
    +  StandardDeviation = 0.0000000001
    +End_Group
    +
    +Group = IgnoreKeys
    +  FileName = true
    +End_Group
    +
    +End
    +                   
    +                 
    + To debug these files, or see why two pvl files compare as different, you can use pvldiff. The FROM parameter will be the output file + (which will be created with the command make output), the FROM2 parameter will be the truth file and the DIFF parameter will be + the DIFF file inside of the input folder (the same as the FROM2 parameter with .DIFF added on to the end). When pvldiff is run, it will output + the first difference it finds that exceeds the tolerances.
    + For an example of the pvl test, say we have the pvl file cubelabels.pvl that looks like this: +
    +                   
    +Object = IsisCube
    +  Object = Core
    +    StartByte   = 65537
    +    Format      = Tile
    +    TileSamples = 128
    +    TileLines   = 128
    +
    +    Group = Dimensions
    +      Samples = 1024
    +      Lines   = 1024
    +      Bands   = 7
    +    End_Group
    +
    +    Group = Pixels
    +      Type       = Real
    +      ByteOrder  = LSB
    +      Base       = 0.0
    +      Multiplier = 1.0
    +    End_Group
    +  End_Object
    +End_Object
    +
    +Object = SomeObject
    +  SomeCalculaion = 5536.4363463414
    +End_Object
    +
    +End
    +                   
    +                 
    + The SomeCalculation keyword may vary by 0.000000001 and the ByteOrder could be MSB or LSB. To compensate for this, you would add a file named cubelabels.pvl.DIFF in + the input folder with the following: +
    +                   
    +Group = Tolerances
    +  SomeCalculation = 0.000000001
    +End_Group
    +
    +Group = IgnoreKeys
    +  ByteOrder = true
    +End_Group
    +
    +End
    +                   
    +                 
    + This would ignore the value of ByteOrder always and SomeCalculation if it were within the tolerance. +

    + Finally, you can create unique tolerances and ignore + keys for each element of an array contained within a + keyword, like so: +

    +
    +                  
    +Group = Tolerances
    + SomeArray = (0.000000001, 0.0, 0.025)
    + AnotherArray = 0.000000001
    +End_Group
    +
    +Group = IgnoreKeys
    + SomeArray =(false, true, false)
    +End_Group
    +
    +End
    +                  
    +                
    + In the above case, the keyword SomeArray would have a tolerance + of 0.000000001 applied to the first element, a tolerance of + 0.025 applied to the third element, and the second element would + be ignored entirely. +

    + Just make sure when working with arrays that you have + exactly the same number of tolerances/ignore keys for the + keyword as there are elements in the array. Alternatively, + you can list only one tolerance or ignore key for the + keyword, and it will be applied to every element in the + array. In the above case, the keyword AnotherArray could + have 50 elements, but each element would have a tolerance of + 0.000000001 applied to it. Having multiple tolerances and + ignore keys without matching the number of array elements, + however, will result in an error. +

    +

    + +

    Test Data

    +

    + In order to perserve the data that is used by the test, type + make checkin + . This copies the contents of the input and truth directories to the testdata area. Since the output files can be generated + by using the output command, these files do not need to be saved. Once the files are stored in the + testdata area you can do + make release + to remove all of the files exept the makefile. Then the makefile can be checked into cvs. To restore these files back into the test, type + make checkout + . This copies the files into the proper directories. Once the files for the test are in the test data area, the test + will still run even if the test files are not in the same directory as the test. +

    + +

    Writing a Test for a category

    +

    + Category tests work the same way as application tests do. The difference is that category tests don't test a + single program but a sequence of programs. Therefore the APPNAME isn't needed for a category test and + can be deleted safely. All of the variables for testing an application also work for the category test. +

    + + +

    Modifying an Existing Application Test

    +
      +
    1. Checkout the application from the cvs repository.
    2. +
    3. Follow the steps above to setup the tests.
    4. +
    5. Copy the commands from the xml file for the application test below the word + commands and above the /dev/null;. +

      + If the application test looks like this: +

      +                                
      +<test>
      +  <commandLine>
      +    num=\$base/testData/isisTruth.cub+1
      +    den=\$base/testData/isisTruth.cub+2
      +    to=<temp>temp1.cub</temp>
      +  </commandLine>
      +
      +  <cubes>
      +    <compareCube>
      +      <truth>ratioTruth1.cub</truth>
      +      <against>temp1.cub</against>
      +    </compareCube>
      +  </cubes>
      +</test>
      +                            
      + Then the test would look like: +
      +                                
      +APPNAME =
      +
      +include $(ISISROOT)/make/isismake.tsts
      +
      +commands:
      +	num=\$base/testData/isisTruth.cub+1
      +    den=\$base/testData/isisTruth.cub+2
      +    to=<temp>temp1.cub</temp> > /dev/null;
      +                            
      +

      +
    6. +
    7. Add a \ to the end of each line except the last one that has the ; at the end. +

      + The test now looks like: +

      +                                
      +APPNAME =
      +
      +include $(ISISROOT)/make/isismake.tsts
      +
      +commands:
      +	num=\$base/testData/isisTruth.cub+1 \
      +    den=\$base/testData/isisTruth.cub+2 \
      +    to=<temp>temp1.cub</temp> > /dev/null; 
      +                            
      +

      +
    8. +
    9. Delete all spaces at the front of each line, add a tab to the front of each line. +

      + The test now looks like: +

      +                                
      +APPNAME =
      +
      +include $(ISISROOT)/make/isismake.tsts
      +
      +commands:
      +	num=\$base/testData/isisTruth.cub+1 \
      +	den=\$base/testData/isisTruth.cub+2 \
      +	to=<temp>temp1.cub</temp> > /dev/null; 
      +                            
      +

      +
    10. +
    11. Set APPNAME to the name of the application being tested. Add $(APPNAME) to the front of the first line + of each command that is using the application that is being tested. Programs that are being used by the test + but are not being tested just need the name of the program. +

      + The test now looks like: +

      +                                
      +APPNAME = ratio
      +
      +include $(ISISROOT)/make/isismake.tsts
      +
      +commands:
      +	$(APPNAME) num=\$base/testData/isisTruth.cub+1 \
      +	den=\$base/testData/isisTruth.cub+2 \
      +	to=<temp>temp1.cub</temp> > /dev/null; 
      +                            
      +

      +
    12. +
    13. Replace the path of input file names to be $(INPUT). +

      + The test now looks like: +

      +                                
      +APPNAME = ratio
      +
      +include $(ISISROOT)/make/isismake.tsts
      +
      +commands:
      +	$(APPNAME) num=$(INPUT)/isisTruth.cub+1 \
      +	den=$(INPUT)/isisTruth.cub+2 \
      +	to=<temp>temp1.cub</temp> > /dev/null; 
      +                            
      +

      +
    14. +
    15. Replace <temp></temp> files with name in the truth tag for the application test +

      + The test now looks like: +

      +                                
      +APPNAME = ratio
      +
      +include $(ISISROOT)/make/isismake.tsts
      +
      +commands:
      +	$(APPNAME) num=$(INPUT)/isisTruth.cub+1 \
      +	den=$(INPUT)/isisTruth.cub+2 \
      +	to=ratioTruth1.cub > /dev/null; 
      +                            
      +

      +
    16. +
    17. Replace the path of output file names to be $(OUTPUT) +

      + The test now looks like: +

      +                                
      +APPNAME = ratio
      +
      +include $(ISISROOT)/make/isismake.tsts
      +
      +commands:
      +	$(APPNAME) num=$(INPUT)/isisTruth.cub+1 \
      +	den=$(INPUT)/isisTruth.cub+2 \
      +	to=$(OUTPUT)/ratioTruth1.cub > /dev/null; 
      +                            
      +

      +
    18. +
    19. Add variables as needed
    20. +
        +
      1. e.g. add a tolerance to the output cube would be + ratioTruth1.cub.TOLERANCE = someValue
      2. +
      +
    21. Copy input files into the input directory
    22. +
        +
      1. In the example above copy isisTruth.cub into the input directory + from the $ISIS3DATA/base/testData area.
      2. +
      +
    23. Copy the truth file from the application test to the truth directory
    24. +
        +
      1. In the example above copy ratioTruth1.cub into the truth directory + from the appTest directory of the ratio application
      2. +
      +
    25. Type + make test +
    26. +
    27. The test should have the same results as the application test did.
    28. +
    29. Type + make checkin + to copy the data to the test data area
    30. +
    31. Type + make release + to clean up the test directory
    32. +
    33. Checkin the Makefile into the cvs repository
    34. +
    + + +

    Modifying a Test

    +
      +
    1. Checkout the Makefile from the cvs repository
    2. +
    3. Type + make checkout + to get the data for the test
    4. +
    5. Modify the test as needed
    6. +
    7. Type + make test + to see the current results of the test
    8. +
    9. If the truth files need to be remade type + make truthdata + or + make ostruthdata + as described above
    10. +
    11. When done, type + make checkin + to copy the data back to the testdata area
    12. +
    13. Type + make release + to remove the files
    14. +
    15. Check in the Makefile back into the cvs repository
    16. +
    + +
    +
    + + Created + + Updated with recent changes to testing system and added examples + +
    + diff --git a/isis/src/docsys/documents/HowToApplicationExamples/HowToApplicationExamples.xml b/isis/src/docsys/documents/HowToApplicationExamples/HowToApplicationExamples.xml new file mode 100644 index 0000000000000000000000000000000000000000..036a6e04cc506125c54d3bfd4f9812fbc085975a --- /dev/null +++ b/isis/src/docsys/documents/HowToApplicationExamples/HowToApplicationExamples.xml @@ -0,0 +1,558 @@ + + + + + xml + technicaldoc + guide + + + + developer + + + + Isis Application Examples How-to + Guide to writing the examples section of Isis Application XML + Guide to writing application examples in the Isis Application XML. All examples added to the official Isis + application documentation will be automatically added to the application documentation pages. This guide + describes the examples section of the Isis Application XML, provides instructions on how to add sample + files to an example, and gives general guidance for writing examples for Isis. + Deborah Lee Soltesz + 2003-04-22 + + + + + HTML + + index.html + + + +

    Overview

    +

    + Isis Application XML files are used for a variety of purposes: a guide for users, documentation for programmers, context-sensitive help, + and generating the application window when a user runs the program in graphical mode to name a few. This guide focuses on the + specific task of adding examples to an application's XML file, which become part of the users' Software Manual. +

    + +

    + All sample code below is from the crop application unless + noted otherwise. +

    + + + +

    Questions & Answers

    + +

    What do I need to know?

    +

    + You should have a general understanding of what XML is - this document explains how to add to an XML file in order + to add an example to the software documentation. You may want to be able to write basic HTML in order to enhance the formatting + of certain sections. You should know some basic image processing, such as how to create a JPEG, how to resize an image and sharpen + it, and so forth -- the image processing tasks required can be performed in Isis, Adobe Photoshop, or a number of other popular image + processing software packages. + It also helps if you are familiar with the Isis web site and how it is organized from a visitor's standpoint. There are many good tutorials on the web + for learning XML and HTML, such as W3Schools.com. +

    + +

    What is an Application?

    +

    + In a nutshell: it's a computer program, or software. For example, in Isis algebra, sharpen, and compare are all applications. +

    + +

    What is Application XML?

    +

    + Each application has a file describing it - what parameters it takes, what values are valid for those parameters, who wrote the software, + descriptions of what the software does, etc. The file is used to generate web page documentation and provide information to the application when + it runs. The file is written in the Application XML language, which specifies how the information about an application is stored in the file. +

    + +

    Where do I find the Application XML specification?

    +

    + A + + handy reference to the Application XML language is available as part of the Isis documentation. +

    + +

    What does "mandatory by policy" mean?

    +

    + An element that is "mandatory by policy" means it must be used in certain situations according to the policies + of the Isis Programming Team, USGS, DOI, Section 508, or common sense. For instance, specifying file size + for non-text files is a USGS policy and is standard practice in web development - when a link to a non-text file + is created on the Isis website, the link will include the file size information so visitors will know how big the file + they're getting ready to download is. Not only does the USGS say we have to give this information, but it's also a + very polite practice, and visitors love polite web developers. +

    + +

    Where do the Application XML files go in the Isis structure?

    +

    + Base Application XML files and source code all live in $ISISROOT/src/base/apps/. Mission-specific Application XML files + and source code live in $ISISROOT/src/{mission}/apps/. Each application has its own directory with the same name as the + application where the application's XML and source code are kept. Documentation subcomponents (such as example images) reside in a + directory named assets under the application directory. + An Application XML file is named the same as the application name with a .xml extension. For example, ratio: +

    + +
      +
    • resides in $ISISROOT/src/base/ratio/
    • +
    • its XML file is $ISISROOT/src/base/ratio/ratio.xml
    • +
    • all the images in its examples are under the $ISISROOT/src/base/apps/ratio/assets/ directory
    • +
    + + +

    What happens to the examples I write?

    + + + [Screenshot - Crop Application Web Page] + +

    + When the Isis system is built, the Isis Software Manual is generated from the Application XML files. + Each application has its own web page in the manual, and the examples are part of the page for their respective applications. +

    +

    + The image to the left + illustrates how the example for the crop + application was transformed into a web page. Click the image to open a larger version of the screen shot in a new window (445x800, 115 KB). +

    + +
    +
    + +

    How do I preview the examples as a web page?

    + +

    + Each application has a make target to automatically generate a web page from the application's XML file. Run + the following command, filling in the application name for application: make application.html and + open the application.html in your favorite web browser using the File - Open menu. For example, to + preview the web page for crop, run make crop.html and open crop.html in your browser. +

    + +

    What is XML-Compliant HTML?

    +

    + It's HTML code that is written to follow XML's rules. + For example, all tags have a beginning and ending tag, empty tags (such as img and br) + must have a slash before the ending angle bracket, all attributes must be in quotes, etc. See + W3C XHTML 1.0, Section 4: Differences with HTML 4 for more about writing XML-Compliant HTML. +

    + +

    + Remember, if you use HTML, you'll be formatting only a small part of the document, the headers, page title, body tags, and so forth are all ready handled for you. + Avoid using structural elements, such as headings, horizontal rules, etc. Keep it simple - bold, italics, lists, code, pre, tt, and tables + should be all most folks need. You may use span with the style attribute defined in place of text formatting (such as bold and italics) if you + are comfortable with using CSS style language. +

    + + + +

    Adding Examples to the Application XML metadata file

    + + +

    Anatomy of Application XML

    +

    + Each document must start with the XML document prolog: +

      <?xml version="1.0" encoding="UTF-8"?>
    + + followed by the start root element: +
      <application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    +   xsi:noNamespaceSchemaLocation="http://isis.astrogeology.usgs.gov/Schemas/Application/application.xsd">
    + + The rest of the document is made up of the content, and ended with the closing tag of the root element: +
      </application>
    +

    + +

    + The following chart illustrates the basic layout of the Application XML language used to write the application file. + The examples section is highlighted in the chart. Other sections of the Application XML file are discussed in separate documents. +

    + +
    + [Application XML Diagram] +
    + +
    + +

    + Each application XML file has one examples section, which may contain any number of example sections - one per example. + The maximum recommended number of examples is three. Your examples should present a wide range of capabilities of the application. +

    + +

    + The following chart (below, left) illustrates the basic structure of the examples section of the Application XML language. + Click the thumbnail image to the right of the chart to view a comprehensive diagram of the examples section. +

    + + + +
    + + + + + +
    + [Examples XML Diagram (collapsed)] + + + [Examples XML Diagram (fully expanded)] + +

    + Above: Fully expanded diagram of examples section of the Isis Application XML. Click to view image in a new window. (1300x1600, 45 KB) +

    +

    + Left: Collapsed diagram of the Examples section of Isis Application XML. +

    +
    +
    + +

    + Unless noted otherwise, + all elements are mandatory by policy! + If an element can be used and is applicable, it must be present. + The examples section language and its usage will be described in detail in the sections that follow. +

    + + + + +
    +

    Image

    + +

    + The image element is described here first because it is a special element used throughout the examples section of the + Application XML language. The image element is used to describe an image you wish to use to illustrate your example. + It is part of the guiInterface, inputImages, and outputImages elements described later in this document. +

    + +
    + [Image Element - Application Examples XML Diagram] +
    + +

    + image contains the following elements and attributes. +

    + +

    Attributes

    +

    + All attributes are mandatory. +

    + +
      +
    • width: the width in pixels of the image (integer)
    • +
    • height: the height in pixels of the image (integer)
    • +
    • src: the path and file name of the image (path/filename)
    • +
    + +

    Elements

    +

    + All attributes are mandatory except for parameterName. +

    + +
      +
    • brief: a short (one sentence) description of the image
    • +
    • description: a long description or explanation, which may contain HTML
    • +
    • parameterName: the application parameter name associated with the image. parameterName is + mandatory by policy when image is used in inputImages or outputImages. + Do not use parameterName in guiInterfaces. + For example, if this image is the result of running the crop application, the parameter name is TO. +
    • +
    • thumbnail: A description of the thumbnail image associated with this image. thumbnail has the following attributes: +
        +
      • width: the width in pixels of the thumbnail (integer)
      • +
      • height: the height in pixels of the thumbnail (integer)
      • +
      • src: the path and file name of the thumbnail (path/filename)
      • +
      • caption: a short caption describing the thumbnail (text)
      • +
      +
    • +
    + +

    Images: Tips and Hints

    + +
    Where should I put my images?
    +

    + In the directory where your XML file resides, create an assets directory. In the assets directory, create + an images and a thumbs directory. Store your images in the assets/images directory, and your + thumbnails in the assets/thumbs directory. +

    + +
    What sizes should my images be?
    + +

    + Images should fit comfortably on a monitor set to 800x600 resolution. Thumbnails are used as clickable icons + that represent the larger image. Thumbnails should be small enough + to load on a web page quickly and take up minimal space on a web page, yet be large enough to give your + audience a sense of what they will see if they choose to view the full sized image. +

    + +
      +
    • Images: no larger than 750 pixels wide and 550 pixels tall
    • +
    • Thumbnails: no larger than 200 pixels wide or high, and no more than 32 KB file size
    • +
    + +
    What format should my images be?
    +

    + JPEG, PNG, or GIF. JPEG may be the easiest because Isis has a file exporter (isis2std). +

    + +
      +
    • JPEG: 16 million colors, compress to reduce file size. Acceptable for all images. +
        +
      • Isis: Quality 80 for regular images, Quality 50 for thumbnails and screen shots.
      • +
      • Photoshop: Quality 10 for regular images, Quality 8 for thumbnails and screen shots.
      • +
      +
    • +
    • PNG: 256 to 16 million colors. Acceptable for all images.
    • +
    • GIF: 256 colors. Acceptable for screen shots and greyscale images.
    • +
    + +
    How do I create a screen shot of an application?
    +
      +
    • Windows: Click on the application window and hit Alt and PrtScn keys on the keyboard to copy the + screen shot to your past buffer. Go to your favorite image processing software, create a new image and paste + the screen shot into it.
    • +
    • Linux: Start the application and gimp. + In gimp, open the File - Acquire - Screen Shot menu, set the delay to a few seconds, click on the + application window to bring it to the front. When the mouse cursor turns to a plus sign (+), click the application window again. + gimp will display the screen shot. Right-click on the screen shot and go the the File - Save menu to save the image.
    • +
    + +

    Sample Code

    +
      <image src="assets/images/peaks.1.jpg" width="500" height="500">
    +    <brief>Input image for crop</brief>
    +    <description>
    +      This is the input image for the 200x300 example of crop.
    +      The area to be "cropped" is shown in red.
    +    </description>
    +    <thumbnail caption=" Input image" src="assets/thumbs/peaks.1.jpg" width="200" height="200"/>
    +    <parameterName>FROM</parameterName>
    +  </image>
    + + + + +
    +

    Brief

    + +
    + [Brief Element - Application Examples XML Diagram] +
    + +

    + The brief element should contain a very brief (one sentence) synopsis or description of the example. This element may contain only text. +

    + +

    Sample Code

    +
      <brief>
    +    200x300 sub-area
    +  </brief>
    + + +
    +

    Description

    + +
    + [Description Element - Application Examples XML Diagram] +
    + +

    + The description element should contain a long description of the example, including any tips or instructions the user should be aware of. This element + may contain XML-compliant HTML formatting. +

    + +

    Sample Code

    +
      <description>
    +    Extracting a 200x300 sub-area
    +  </description>
    + + +
    +

    Terminal Interface

    + +
    + [Terminal Interface Element - Application Examples XML Diagram] +
    + +

    + The purpose of the terminalInterface element is to show the user the command used on the terminal interface command line to execute the example. + The terminalInterface element contains two elements: +

    + +
      +
    • commandLine: The actual command to recreate the example
    • +
    • description: a long description or explanation of the command line, which may contain HTML
    • +
    + +

    Sample Code

    +
      <terminalInterface>
    +    <commandLine>
    +      crop f=peaks.cub t=crop.cub samp=100 line=200 band=1 nsamp=200 nline=300 nbands=1
    +    </commandLine>
    +    <description>
    +      In this example crop will extract a 200x300 sub-area that starts at sample 100 and line 200
    +    </description>
    +  </terminalInterface>
    + + + +
    +

    GUI Interfaces

    + +
    + [GUI Interfaces Element - Application Examples XML Diagram] +
    + +

    + The purpose of the guiInterfaces element is to provide one or more screen shots of the application windows. + guiInterfaces may contain one or more guiInterface elements. Each guiInterface + element contains one image element. +

    + +

    + The image element is a special element that may be used in several places. See the + + image element description for more information. +

    + +

    Sample Code

    +
      <guiInterfaces>
    +    <guiInterface>
    +      <image width="472" height="388" src="assets/images/cropgui.jpg">
    +        <brief>Example Gui</brief>
    +        <description>
    +          Screen shot of GUI with parameters filled in to
    +          perform a 200 pixel by 300 pixel crop of the input image.
    +        </description>
    +        <thumbnail width="200" height="165" caption="Crop Gui" src="assets/thumbs/cropgui.jpg" />
    +      </image>
    +    </guiInterface>
    +  </guiInterfaces>
    + + +
    +

    Data Files

    + +
    + [Data Files Element - Application Examples XML Diagram] +
    + +

    + The purpose of the dataFiles element is to show the non-image sample files generated by or input to the application. + dataFiles may contain one or more dataFile elements, one per file. dataFile has the following elements and attributes: +

    + +

    Attribute

    +
      +
    • path: path and filename of the data file
    • +
    + +

    Elements

    +
      +
    • brief: a short (one sentence) description of the data file
    • +
    • description: a long description or explanation, which may contain HTML
    • +
    • parameterName: the application parameter name associated with the data file. + For example, if this data file is the result of running the percent application, the parameter name is TO. +
    • +
    + +

    Sample Code (percent)

    +
      <dataFiles>
    +    <dataFile path="assets/percent.txt">
    +      <brief>Output file for percent</brief>
    +      <description>
    +        Output text file shown in editor giving results of the percent application.
    +      </description>
    +      <parameterName>TO</parameterName>
    +    </dataFile>
    +  </dataFiles>
    + + + +
    +

    Input Images

    + +
    + [Input Images Element - Application Examples XML Diagram] +
    + +

    + The purpose of the inputImages element is to show the sample images used as input to the application for this example. + inputImages may contain one or more image elements. + The image element is a special element that may be used in several places. See the + image element description for more information. +

    + +

    Sample Code

    +
      <inputImages>
    +    <image src="assets/images/peaks.1.jpg" width="500" height="500">
    +      <brief>Input image for crop</brief>
    +      <description>
    +        This is the input image for the 200x300 example of crop.
    +        The area to be "cropped" is shown in red.
    +      </description>
    +      <thumbnail caption=" Input image" src="assets/thumbs/peaks.1.jpg" width="200" height="200"/>
    +      <parameterName>FROM</parameterName>
    +    </image>
    +  </inputImages>
    + + +
    +

    Output Images

    + +
    + [Output Images Element - Application Examples XML Diagram] +
    + +

    + The purpose of the outputImages element is to show the sample images that are generated by the application when it is run. + outputImages may contain one or more image elements. + The image element is a special element that may be used in several places. See the + image element description for more information. +

    + +

    Sample Code

    +
      <outputImages>
    +    <image src="assets/images/peaks.crop.jpg" width="200" height="300">
    +      <brief>Output image for crop</brief>
    +      <description> This is the output image for the 200x300 example of crop
    +      </description>
    +      <thumbnail
    +        caption="Output image showing results of the crop application with 200 by 300 input."
    +        src="assets/thumbs/peaks.crop.jpg" width="133" height="200"/>
    +      <parameterName>TO</parameterName>
    +    </image>
    +  </outputImages>
    + + +
    +

    Examples

    + + + + +
    +

    Final Note

    + +

    + Don't forget to add an entry in the history section of the Application XML file! +

    + + + +
    +
    + + Created + +
    diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/application_collapsed.png b/isis/src/docsys/documents/HowToApplicationExamples/assets/application_collapsed.png new file mode 100644 index 0000000000000000000000000000000000000000..b44c980625d77d5ed0eb9feb57ac11b62abb96a0 Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/application_collapsed.png differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/brief.png b/isis/src/docsys/documents/HowToApplicationExamples/assets/brief.png new file mode 100644 index 0000000000000000000000000000000000000000..9e55c8309e2a4b36441f7bf8d49764543ed6f5fb Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/brief.png differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/datafiles.png b/isis/src/docsys/documents/HowToApplicationExamples/assets/datafiles.png new file mode 100644 index 0000000000000000000000000000000000000000..602062369e30f1fba6c11e2cac29caddfec60434 Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/datafiles.png differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/description.png b/isis/src/docsys/documents/HowToApplicationExamples/assets/description.png new file mode 100644 index 0000000000000000000000000000000000000000..af170d7d4ccdb06f1c0df03a694773958aac465a Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/description.png differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/examples.png b/isis/src/docsys/documents/HowToApplicationExamples/assets/examples.png new file mode 100644 index 0000000000000000000000000000000000000000..39a9b4b158a63ccdb3af74c91c85e0f18488262c Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/examples.png differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/examples/crop.xml b/isis/src/docsys/documents/HowToApplicationExamples/assets/examples/crop.xml new file mode 100644 index 0000000000000000000000000000000000000000..9ab65d78dddd210a383b13c3a55b0ec10481bb85 --- /dev/null +++ b/isis/src/docsys/documents/HowToApplicationExamples/assets/examples/crop.xml @@ -0,0 +1,207 @@ + + + + + Crops a cube + + + + This program can be used to crop or select a sub-area from a cube. The user + can select to crop in any or all dimensions: sample, line, and band. The + crop parameter selection requires that the area of interest be contiguous. + That is, the program will not allow non-continuous cropping such as lines + 1-5, 10-30, and 80-100. + + + + Trim and Mask + + + + + Original version + + + Converted to Isis 3.0 + + + Added examples + + + Removed crop from the Utility category + + + Make images smaller + + + Added red rectangle to input image of example to illustrate crop area. + + + Moved images to /assets/image directory and thumbnails to /assets/thumb directory. + + + Fixed problem with isiscvs not checking in the thumb and image directories. + + + + + + dsk2dsk + + + + + + filename + input + + Input cube + + + The cube which will be cropped. + + + *.cub + + + + + filename + output + + Output cropped cube + + + The smaller output cube containing the results of the crop. + + + *.cub + + + + + + + integer + Starting Sample + + + The starting sample to extract. It must be inside + the cube. + + + 1 + + + + integer + Starting Line + + + The starting line to extract. It must be inside + the cube. + + + 1 + + + + integer + Starting Band + + + The starting band to extract. It must be inside + the cube. + + + 1 + + + + + + + integer + Number of Samples + + + The number of samples to extract. It must stay + inside the input cube. + + + 1 + + + + integer + Number of Lines + + + The number of lines to extract. It must stay + inside the input cube. + + + 1 + + + + integer + Number of Bands + + + The number of bands to extract. It must stay + inside the input cube. + + + 1 + + + + + + + + 200x300 sub-area + + Extracting a 200x300 sub-area + + + f=peaks.cub t=crop.cub samp=100 line=200 band=1 nsamp=200 nline=300 nbands=1 + + + In this example crop will extract a 200x300 sub-area that starts at sample 100 and line 200 + + + + + + Input image for crop + This is the input image for the 200x300 example of crop. The area to be "cropped" is shown in red. + + + FROM + + + + + + Output image for crop + This is the output image for the 200x300 example of crop + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a 200 pixel by 300 pixel crop of the input image. + + + + + + + diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/examples/crop_example.xml b/isis/src/docsys/documents/HowToApplicationExamples/assets/examples/crop_example.xml new file mode 100644 index 0000000000000000000000000000000000000000..2ae36d6c3177359383caa9106fde1669bf42bc99 --- /dev/null +++ b/isis/src/docsys/documents/HowToApplicationExamples/assets/examples/crop_example.xml @@ -0,0 +1,50 @@ + + + + + + + 200x300 sub-area + + Extracting a 200x300 sub-area + + + f=peaks.cub t=crop.cub samp=100 line=200 band=1 nsamp=200 nline=300 nbands=1 + + + In this example crop will extract a 200x300 sub-area that starts at sample 100 and line 200 + + + + + + Input image for crop + This is the input image for the 200x300 example of crop. The area to be "cropped" is shown in red. + + + FROM + + + + + + Output image for crop + This is the output image for the 200x300 example of crop + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a 200 pixel by 300 pixel crop of the input image. + + + + + + + diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/examples_collapsed.png b/isis/src/docsys/documents/HowToApplicationExamples/assets/examples_collapsed.png new file mode 100644 index 0000000000000000000000000000000000000000..b10228427d0fb877114f347e9343f73b1580976c Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/examples_collapsed.png differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/examples_thumb.png b/isis/src/docsys/documents/HowToApplicationExamples/assets/examples_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..597c9b0bdeaf3ea7125c373814f5705dabd63353 Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/examples_thumb.png differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/guiInterfaces.png b/isis/src/docsys/documents/HowToApplicationExamples/assets/guiInterfaces.png new file mode 100644 index 0000000000000000000000000000000000000000..19b3a6f3e20c08d772ad9bb4b7e72a4fa81426fc Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/guiInterfaces.png differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/image.png b/isis/src/docsys/documents/HowToApplicationExamples/assets/image.png new file mode 100644 index 0000000000000000000000000000000000000000..05765ec294f605db7c706ab48ee63daa8582e29a Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/image.png differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/inputimages.png b/isis/src/docsys/documents/HowToApplicationExamples/assets/inputimages.png new file mode 100644 index 0000000000000000000000000000000000000000..52a54b5ff8802c2c2fba0258a642e2b4980afa43 Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/inputimages.png differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/outputimages.png b/isis/src/docsys/documents/HowToApplicationExamples/assets/outputimages.png new file mode 100644 index 0000000000000000000000000000000000000000..026b725fa076f32ed2bf5b532e5cb361166241f0 Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/outputimages.png differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/screenshot.jpg b/isis/src/docsys/documents/HowToApplicationExamples/assets/screenshot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3f082111490c12252b413693acf47bdc290dd8cc Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/screenshot.jpg differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/screenshot_small.jpg b/isis/src/docsys/documents/HowToApplicationExamples/assets/screenshot_small.jpg new file mode 100644 index 0000000000000000000000000000000000000000..366718b21e76b5f46903476847676a151062324f Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/screenshot_small.jpg differ diff --git a/isis/src/docsys/documents/HowToApplicationExamples/assets/terminalInterface.png b/isis/src/docsys/documents/HowToApplicationExamples/assets/terminalInterface.png new file mode 100644 index 0000000000000000000000000000000000000000..ee5c9ae8debcd3f28c29c11ac3ddb919ecf442b9 Binary files /dev/null and b/isis/src/docsys/documents/HowToApplicationExamples/assets/terminalInterface.png differ diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/HowToGeneralDocumentation.xml b/isis/src/docsys/documents/HowToGeneralDocumentation/HowToGeneralDocumentation.xml new file mode 100755 index 0000000000000000000000000000000000000000..542905f430399a10f2b3d41c77822a24c47fad92 --- /dev/null +++ b/isis/src/docsys/documents/HowToGeneralDocumentation/HowToGeneralDocumentation.xml @@ -0,0 +1,391 @@ + + + + + + xml + technicaldoc + guide + + + + + developer + + + + + Isis Documents How-to + Guide to writing documents using Isis Documentation XML + Guide to adding documents to the Isis documentation tree. All documents added to the official Isis + documentation will be automatically linked on the Isis web pages and distributed with Isis. This guide + describes the formats documents may be in, what types of documents may be added, and how to + write the Isis Documentation XML metadata file that is used automatically add a document to the Isis + system. + Deborah Lee Soltesz + 2003-01-29 + + + + + + HTML + + + index.html + + + + +

    Overview

    +

    + Isis has three kinds of documentation: Application, Object, and General Documents. Application and Object documentation + are part of the programming and development structure and are discussed in those portions of the Isis documentation. + General Documents are not associated directly with Applications or Objects. Such documents include user guides, + procedural instructions, administration references, and this very document you are reading now. This guide describes + the formats Documents may be in, what types of Documents may be added, and how to write the Isis Documentation XML + metadata file that is used to automatically add a Document to the Isis system. +

    +

    + Isis documentation is part of the source code distribution, resides in an organized structure, and in part is automatically + generated from text files written in the Isis XML languages. When Isis is installed on a system, a complete copy of the + documentation is installed with the software. Additionally, a copy of the documentation is published to the Isis web site, therefore + the Isis web site and the Isis documentation are identical. In this document, the term "web site" will refer to the complete Isis + documentation. +

    + + +

    Questions & Answers

    +

    What do I need to know?

    +

    + You should have a general understanding of what XML is - this document explains how to write an XML file for + adding a Document to Isis. If you plan to add a web page to Isis, you should be able to write basic HTML. It also helps if + you are familiar with the Isis web site and how it is organized from a visitor's standpoint. There are many good tutorials on the web + for learning XML and HTML, such as W3Schools.com. +

    + +

    What is a Document?

    +

    + A Document is a file, or a set of files, that supply information related to Isis. Documents that are most common are guides and + reference manuals. Documents are automatically linked into the upper levels of the Isis website based on the audience and + category supplied in the metadata file. Documents may be written by the Isis team members and housed in the documentation + or may be external resources on other web sites. +

    + +

    What is the Document metadata file?

    +

    + The Document metadata file is an XML file that describes a Document, and may even contain the HTML formatted content of the Document itself. + In the latter case, the Document metadata will be automatically transformed to an HTML file during the building of the Isis documentation. + The metadata file also contains bibliographic information, history tracking, file information, and the target audience and category the + Document will be linked under on the Isis web site. +

    + +

    Where do I find the Document XML specification?

    +

    + A + + handy reference to the Document XML language is available as part of the Isis documentation. +

    + +

    What does "mandatory by policy" mean?

    +

    + An element that is "mandatory by policy" means it must be used in certain situations according to the policies + of the Isis Programming Team, USGS, DOI, Section 508, or common sense. For instance, specifying file size + for non-text files is a USGS policy and is standard practice in web development - when a link to a non-text file + is created on the Isis website, the link will include the file size information so visitors will know how big the file + they're getting ready to download is. Not only does the USGS say we have to give this information, but it's also a + very polite practice, and visitors love polite web developers. +

    + +

    Where do Documents go in the Isis structure?

    +

    + Documents live in $ISISROOT/src/docsys/documents/. Each Document (its metadata and files) should be in its + own directory, and subcomponents should reside in a directory named assets. The XML metadata file should + be named the same as the directory with a .xml extension. For example, this Document: +

    + +
      +
    • resides in $ISISROOT/src/docsys/documents/HowToGeneralDocumentation/
    • +
    • its metadata file is HowToGeneralDocumentation.xml
    • +
    • all the images on this page are in the $ISISROOT/src/docsys/documents/HowToGeneralDocumentation/assets/ directory
    • +
    + + +

    Writing the Document XML metadata file

    + + +

    Anatomy

    +

    + Each document must start with the XML document prolog: +

      <?xml version="1.0" encoding="UTF-8"?>
    + + followed by the start root element: +
      <documentation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://isis.astrogeology.usgs.gov/Schemas/Documentation/documentation.xsd">
    + + The rest of the document is made up of the metadata content, and ended with the closing tag of the root element: +
      </documentation>
    +

    + +

    + The following chart illustrates the layout of the Document XML language used to write the metadata file. + Click the image to view the full sized chart (opens in a new window). +

    + +
    + + [Document XML Diagram] +
    + +

    + The language and its usage will be described in the sections that follow, in order of increasing complexity. +

    + + +
    +

    History

    + +
    + [History Element - Document XML Diagram] +
    + +

    + The purpose of the history element is to record changes to a Document. This element is not mandatory because + a Document may be a resource on another website and not maintained by the Isis team. However, if you are creating a new + Document or editing an existing Document, this element is mandatory by policy! +

    + +

    + The history element contains one or more change elements. The change element has + two attributes, name and date and should contain a free text comment describing the change to + the document. +

    + +

    Example

    +
      <change name="Deborah Lee Soltesz" date="2003-01-29">Created</change>
    + +
      +
    • name: your name
    • +
    • date: the date of the change in YYYY-MM-DD format. If the month or year is less than 10, pad the number with a 0 (see example above)
    • +
    + + +
    +

    Bibliography

    + +
    + [Bibliography Element - Document XML Diagram] +
    + +

    + The purpose of the bibliography element is to document bibliographic information about the document: author, publisher, etc. + The bibliography element contains the following elements: +

    + +
      +
    • title: The title of the Document
    • +
    • brief: A short (one sentence) description
    • +
    • description: A long (paragraph) description
    • +
    • author: The name(s) of the author(s)
    • +
    • publisher: The publisher information - name, address, etc.
    • +
    • date: the publication date in YYYY-MM-DD format
    • +
    + +

    + All elements are mandatory except for publisher (which should be used when the publisher is not the Astrogeology Research Program). + All elements may contain free text except the date and may appear in any order. The bibliography information is used to + create links in the Isis web pages and generate title and header information if the Document metadata is to be transformed to an HTML file. +

    + +

    Example

    +
      <bibliography>
    +    <title>Isis Documents How-to</title>
    +    <brief>Guide to writing documents using Isis Documentation XML</brief>
    +    <description>Guide to adding documents to the Isis
    +    documentation tree. All documents added to the official Isis
    +    documentation will be automatically linked on the Isis web
    +    pages and distributed with Isis. This guide describes the formats
    +    documents may be in, what types of documents may be added, and
    +    how to write the Isis Documentation XML metadata file that is
    +    used automatically add a document to the Isis system.</description>
    +    <author>Deborah Lee Soltesz</author>
    +    <date>2003-01-29</date>
    +  </bibliography>
    + + +
    +

    Category

    + +
    + [Category Element - Document XML Diagram] +
    + +

    + The purpose of the category element is to specify how the Document will be categorized on the web site. + The category element contains one or more categoryItem elements. The categoryItem element + can be one of several preset categories: +

    + +
      +
    • hidden: A special category that will prevent this document from being linked on the Isis website
    • +
    • about: The document falls under the About Isis section of the site. E.g. The History of the Isis Software Package
    • +
    • guide: The document serves as a guide to some element of using, developing, or administrating Isis. E.g. this document
    • +
    • tutorial: The document serves as a step-by-step tutorial or lesson. E.g. Destriping Noisy Data
    • +
    • installation: The document is related to installing Isis
    • +
    • administration: The document is related to maintaining the installation of Isis
    • +
    • technicaldoc: This is a technical document about developing, programming, or the adminstration of Isis. This document falls under the Technical Documents section of the site.
    • +
    • support: The document is related to Isis technical support
    • +
    • information: General information about Isis
    • +
    • reference: This document is a reference (such as a listing of commands without the detailed examples and explanations a guide might include)
    • +
    • policy: This document outlines a policy. E.g. Privacy Policy and Disclaimers
    • +
    • xml: This document is about one of the XML languages. E.g. this document
    • +
    + +

    + + Refer to the Documentation XML specification for an up-to-date list of categories. +

    + +

    Example

    +
      <category>
    +    <categoryItem>xml</categoryItem>
    +    <categoryItem>technicalinfo</categoryItem>
    +    <categoryItem>guide</categoryItem>
    +  </category>
    + + +
    +

    Audience

    + +
    + [Audience Element - Document XML Diagram] +
    + +

    + The purpose of the audience element is to specify (in combination with category) how the Document will be categorized on the web site. + The audience element contains one or more target elements. The target element + can be one of several preset audiences: +

    + +
      +
    • user: A person who is new to Isis, or uses Isis and has basic skill at using the software
    • +
    • intermediate: An intermediate user. A person who has mastered basic skills and is performing intermediate level functions
    • +
    • advanced: An advanced user. A person who has advanced skills or is performing advanced functions
    • +
    • administrator: A person who maintains the software on the computer, usually a systems administrator
    • +
    • developer: A person who uses the Isis API to develop applications. This group may include image processors and scientists
    • +
    • programmer: A person who writes Isis base software libraries. This is generally a member of the Astrogeology Programming Team
    • +
    • all: Everybody
    • +
    + +

    + + Refer to the Documentation XML specification for an up-to-date list of audiences. +

    + +

    Example

    +
      <audience>
    +    <target>developer</target>
    +  </audience>
    + + +
    +

    Files

    + +
    + [History Element - Document XML Diagram] +
    + +

    + The purpose of the files element is to specify the information about the file or files in this Document. + This information is used to create links in the Isis web pages and even transform the metadata file into new HTML documents. +

    +

    + The files element contains one or more file elements. There is one file element for each + file in the Document. Another application of this is that you want to present one document in multiple file formats + (e.g. PDF, Excel, and Access) - each format would be documented in its own file element. + The file element has the following attributes: +

    + +
      +
    • hidden true or false. Hides this file in the Document so it is not linked. If you want to hide the entire Document, + use the hidden attribute in category/categoryItem. Use is optional and defaults to false.
    • +
    • primary true or false. Sets this file as the top page of a multipage Document. Use is optional and defaults to false.
    • +
    + +

    + The file element contains the following elements: +

    + +
      +
    • type: A mandatory, free text description of the file type - shorter is better! E.g. PDF, HTML, JPEG, Quicktime
    • +
    • size: The file size in bytes. This is not mandatory except by policy: use size for non-text (text, HTML, XML) + content such as PDF files, images, movies, etc. E.g. 1.3 MB, 225 KB
    • +
    • subtitle: Specify the subtitle of this page in the document. This is not mandatory, but is useful for multipage Documents and will be used in creating the text for links to the pages.
    • +
    • source: Contains the filename or URL (web, ftp, or other electronic address) of the file. This element is mandatory and may contain one + of the following elements:
    • +
        +
      1. URL: web, ftp, or other electronic address e.g. http://astrogeology.usgs.gov
      2. +
      3. source: file name of a Document that resides in $ISISROOT/src/docsys/documents/. If this Document is a web page + that will be generated from the metadata file, this is the target file name for the web page.
      4. +
      + +
    • body: If your Document is an autogenerated web page, this is where the content of your webpage goes. All web page Documents + should be created this way, not as a separate HTML file. When Isis is built, the web page will be generated with consistent formatting + and layout, summary information (ie. HTML title and meta tags), and page headers and footers. The body + element contains one of the following:
    • + +
        +
      1. HTML: inline (i.e. in the metadata file), XML-compliant, HTML formatted content (see + W3C XHTML: Differences with HTML 4 + for tips on writing XML compliant HTML)
      2. +
      3. src: filename for an external XML file containing the content of the web page. The external file must have a root element of + body and contain XML compliant, body-level HTML
      4. +
      + +
    + +

    Examples

    +

    + The following examples are Document XML metadata files. +

    + +
      +
    • External Document: + this example shows a metadata file for an external, non-HTML document, + diagram.png (35 KB)
    • +
    • Simple Web Page, Inline Content: + an example of a metadata file that contains the HTML formatted content in the + body element. This example would generate a single web page.
    • +
    • Single Web Page, External Content: + an example of a metadata file that contains a src reference in the file to an external + file (example2_body.xml) + containing the HTML formatted content. This example would generate a single web page.
    • +
    • Multiple Pages, Inline Content: + a example of a metadata file that contains the HTML formatted content in body elements of + several file elements. This example would generate several web pages, one for each file element.
    • +
    + +

    Coming Soon

    +
      +
    • Templates you can use to get started on a document
    • +
    • Tools to build a preview of your document
    • +
    + + +
    +
    + + + Created + Revisions based on review by Stuart Sides + Added explanations for new items category:tutorial and audience:intermediate + + +
    diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/audience.png b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/audience.png new file mode 100755 index 0000000000000000000000000000000000000000..65e72d6304f6fa6989d2f0cc810fe4c983e6ab3e Binary files /dev/null and b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/audience.png differ diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/bibliography.png b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/bibliography.png new file mode 100755 index 0000000000000000000000000000000000000000..b75725c687f90c517cd1899e1c6a47b44d155b57 Binary files /dev/null and b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/bibliography.png differ diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/category.png b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/category.png new file mode 100755 index 0000000000000000000000000000000000000000..2780f6ed7c13da0964ab39ac4c15ccb6de416688 Binary files /dev/null and b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/category.png differ diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/diagram.png b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/diagram.png new file mode 100755 index 0000000000000000000000000000000000000000..c66d3172709ea551d38dc322f65833d0425d124c Binary files /dev/null and b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/diagram.png differ diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/diagram_collapsed.png b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/diagram_collapsed.png new file mode 100755 index 0000000000000000000000000000000000000000..5b0ecf0e84b02978f5cc0f2448b866b2ff0b5d77 Binary files /dev/null and b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/diagram_collapsed.png differ diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/diagram_small.png b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/diagram_small.png new file mode 100755 index 0000000000000000000000000000000000000000..0dee4197c3786e488ecb2603b273ad27d625fbab Binary files /dev/null and b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/diagram_small.png differ diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example1/example1.xml b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example1/example1.xml new file mode 100755 index 0000000000000000000000000000000000000000..655cdad781fd8556fb4c935b9c1e35093ae8ab68 --- /dev/null +++ b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example1/example1.xml @@ -0,0 +1,60 @@ + + + + + +

    This is the content of the main page of the example multipage document

    + + HTML + Page 1 + + example1_page1.html + +
    + + +

    This is the content of page 2 of the example multipage document

    + + HTML + Page 2 + + example1_page2.html + +
    + + +

    This is the content of page 3 of the example multipage document

    + + HTML + Page 3 + + example1_page3.html + +
    + + +

    This is the content of page 4 of the example multipage document

    + + HTML + Page 4 + + example1_page4.html + +
    +
    + + about + + + all + + + Multipage Document Example + An example of a multipage Document + An example demonstrating how a multipage Document with inline content is created. + The XML contains several file elements under the files element and during the Isis build + will be converted into a set HTML formatted web pages. + Deborah Lee Soltesz + 2002-12-12 + +
    diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example2/example2.xml b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example2/example2.xml new file mode 100755 index 0000000000000000000000000000000000000000..de11939ad41768dedf50c2630b37bb84039d779c --- /dev/null +++ b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example2/example2.xml @@ -0,0 +1,27 @@ + + + + + + example2_body.xml + + HTML + + example2.html + + + + + about + + + all + + + HTML with External Content Document Example + Example of a Document with an external source of body content + Example of a Document XML metadata file with the body stored in an external file that will be converted to an HTML file + Deborah Lee Soltesz + 2002-12-05 + + diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example2/example2_body.xml b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example2/example2_body.xml new file mode 100755 index 0000000000000000000000000000000000000000..77935b00e8cce16a68e75c4ac5fbed97897e75ac --- /dev/null +++ b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example2/example2_body.xml @@ -0,0 +1,25 @@ + + +

    + This file is the external source of content for a Document that will be converted to an HTML file. +

    + + +

    What's the deal?

    + + +

    The Document XML Metadata File

    +

    + The metadata file example2.xml contains all the bibliographic, history, and basic file information for the Document. + The metadata file specifies that the Document content is HTML that is to be created from the contents of the metadata file. + The files/file/body/src element references this file as its source of content. +

    + +

    What will happen to this file?

    +

    + When Isis is built, the metadata file will be converted into a web page. The bibliographic information will be output as summary + information in the HTML file, preset page headers and footers will be used, with the title (and subtitle) from the metadata used in the + page header. The file specified by files/file/body/src will be inserted into the body of the HTML file between the page header and footer. +

    + + diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example3/example3.xml b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example3/example3.xml new file mode 100755 index 0000000000000000000000000000000000000000..f6ae69a01b53f81010abc28f6cd975a8394f3006 --- /dev/null +++ b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example3/example3.xml @@ -0,0 +1,28 @@ + + + + + +

    This is the content of this example document. This will become the content of the HTML page generated during the Isis build.

    + + HTML + + example3.html + +
    +
    + + administration + guide + + + administrator + + + Example of an Inline Content Single Page Document + Example of a Document metadata file that generates a single web page + Example of a Document metadata file that will generate a single page document from HTML formatted content included in the file + Deborah Lee Soltesz + 2002-12-09 + +
    diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example4/diagram.png b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example4/diagram.png new file mode 100755 index 0000000000000000000000000000000000000000..c66d3172709ea551d38dc322f65833d0425d124c Binary files /dev/null and b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example4/diagram.png differ diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example4/example4.xml b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example4/example4.xml new file mode 100755 index 0000000000000000000000000000000000000000..8926c3fad90cf3e4f8ca3433c1b80218545ad639 --- /dev/null +++ b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/examples/example4/example4.xml @@ -0,0 +1,29 @@ + + + + + PNG + + diagram.png + + 30 KB + + + + guide + + + programmer + developer + + + Example of an external Document + Example of a Document that is a stand-alone external file + Example of a Document that is a stand-alone external file. In this case, the file is an image + (actually, the Isis Documentation XML Language Diagram), + but could be a PDF file, a spreadsheet, or just about anything. + + Deborah Lee Soltesz + 2003-01-30 + + diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/files.png b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/files.png new file mode 100755 index 0000000000000000000000000000000000000000..bef6134c6322df6be0ee3c041da1456c02349f25 Binary files /dev/null and b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/files.png differ diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/assets/history.png b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/history.png new file mode 100755 index 0000000000000000000000000000000000000000..e8b4fce801c3e6fa73904d168cce4faf8d838fae Binary files /dev/null and b/isis/src/docsys/documents/HowToGeneralDocumentation/assets/history.png differ diff --git a/isis/src/docsys/documents/HowToGeneralDocumentation/work/diagram.psd b/isis/src/docsys/documents/HowToGeneralDocumentation/work/diagram.psd new file mode 100755 index 0000000000000000000000000000000000000000..a85d53c50c09126d13e1db96d7aa2c5c2089bab7 Binary files /dev/null and b/isis/src/docsys/documents/HowToGeneralDocumentation/work/diagram.psd differ diff --git a/isis/src/docsys/documents/InstallGuide/InstallGuide.xml b/isis/src/docsys/documents/InstallGuide/InstallGuide.xml new file mode 100755 index 0000000000000000000000000000000000000000..338baad804aa2846acce97f0b333d8b7fc308af2 --- /dev/null +++ b/isis/src/docsys/documents/InstallGuide/InstallGuide.xml @@ -0,0 +1,368 @@ + + + + + + + + + + + +

    Platforms

    +

    + Isis 3 applications are compiled and linked on our local systems. We + provide copies of some of the necessary third party libraries, but we + can not provide them for all operating system, hardware and + distribution combinations. Other libraries are assumed to be + available from your installation. As we upgrade to new software and + hardware we may introduce incompatibilities with older platforms. In + some cases we will not have the resources to resolve all problems, + but we will attempt to remain compatible within reason and our + resource limits. +

    + +

    1) Find Disk Space

    +

    + The current distribution of Isis 3 contains over 200 applications. + It includes the complete source, binaries, documentation, and + libraries necessary to run the applications. + Note: This does not include 3rd party binaries and header files + necessary for developing Isis applications. The data area is + available as a seperate download. Be aware, the full data area is + very large (many 10s of GBs). This includes SPICE kernels for + CASSINI, Clementine1, Mars Global Surveyor, Mars Odyssey, Mars + Reconnaissance Orbiter, Viking, and others. Other missions are + included as they become available in Isis. +

    +

    + We suggest you install Isis3 in a work area, away from any existing + Isis2.x installations. Change your current working directory to + where you want isis3 installed and create a directory named isis3. + The rsync commands in step 2 will place all of Isis and the SPICE + kernels under this + directory. + + If you are looking for Isis 2, please + refer to the Isis 2 Installation + Guide for instructions on downloading and installing Isis 2. +

    + +

    + Example: +

    +
    +        $ cd /work1
    +        $ mkdir isis3
    +        $ cd isis3
    +
    + +

    2) Download Isis3

    +

    + We are distributing Isis3 using an rsync server. If the "rsync" + command is is not available on your system please see your system + administrator. To download Isis3 follow the example for your hardware + and operating system combintion. + Make sure to include the "." at the end of the "rsync" + commands - if you don't, you will only get a list of available + downloads from the rsync server. +

    + +

    + Warning: + You must be in the correct directory as shown above, and you + must type the follwing commands correctly. If you do not you could + remove files not associated with ISIS. + +

    + +

    + Example for Suse 10.1 Linux x86 64-bit Intel compatible systems: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::x86-64_linux_SUSE/isis .
    +
    +

    + Example for Suse 10.1 Linux x86 32-bit Intel compatible systems: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::x86_linux_SUSE/isis .
    +
    + +

    + Example for Red Hat 5.4 Linux x86 64-bit Intel compatible systems: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::x86-64_linux_RHEL/isis .
    +
    +

    + Example for Red Hat 5.4 Linux x86 32-bit Intel compatible systems: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::x86_linux_RHEL/isis .
    +
    + +

    + Example for MacOSX 10.5 32-bit Intel compatible systems: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::x86_darwin_OSX/isis .
    +
    + + Note: We are no longer building Isis 3 for Linux SuSE + 9.X, RedHat Enterprise 3, 4 or equivalent systems or Mac OSX + with the Power PC processor. + + + +

    3) Get the Isis3 data files

    +

    + The data area is separate from the source code. This data area is + crucial to Isis3 and must be downloaded too. +

    +

    + Perform this step from the same directory you ran the previous rsync + command from. In the example it was "/work1/isis3". +

    +

    + To download all Isis3 data files use the following command. +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data .
    +
    +

    + Note: The isis3 data area is very large (over 70GB). You may want to + consider downloading only the missions you require. To download + specific Isis3 mission data files use the following commands. + Please note: Reguardless of the mission the base data is required. +

    +

    + + Required Download + +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/base data/
    +
    +

    + Cassini Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/cassini data/
    +        
    +

    + Clementine Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/clementine1 data/
    +        
    +

    + Galileo Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/galileo data/
    +        
    +

    + Ideal Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/ideal data/
    +        
    +

    + Lunar Orbiter Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/lo data/
    +        
    +

    + Lunar Reconnaissance Orbiter Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/lro data/
    +        
    +

    + Mars Exploration Rover Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/mer data/
    +        
    +

    + Messenger Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/messenger data/
    +        
    +

    + Mars Express Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/mex data/
    +        
    +

    + Mars Global Surveyor Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/mgs data/
    +        
    +

    + Mars Reconnaissance Orbiter Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/mro data/
    +        
    +

    + Odyssey Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/odyssey data/
    +        
    +

    + Smart1 Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/smart1 data/
    +        
    +

    + Viking Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/viking1 data/
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/viking2 data/
    +        
    +

    + Voyager Mission: +

    +
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/voyager1 data/
    +        rsync -azv --delete isisdist.wr.usgs.gov::isis3data/data/voyager2 data/
    +        
    + +

    4) Set up your environment

    +

    + Isis3 needs to know where all its pieces are located. We use an + environment variable called "ISISROOT" to do this. For the above + example set ISISROOT to as follows: +

    + +

    + for C shells: +

    +
    +        setenv ISISROOT /work1/isis3/isis
    +
    + +

    + for Bourne shells: +

    +
    +        ISISROOT=/work1/isis3/isis
    +        export ISISROOT
    +
    + +

    + Run the startup script for Isis. This script assumes you installed + the Isis 3 data area in the same directory you installed the Isis 3 + package. If you did not do this, you will need to modify the script to + meet your needs. +

    + +

    + for C shells: +

    +
    +        source $ISISROOT/scripts/isis3Startup.csh
    +
    + +

    + for Bourne shells: +

    +
    +        . $ISISROOT/scripts/isis3Startup.sh
    +
    + + + +

    + If you encounter any problems we will be monitoring our discussion + board daily and will respond to any questions as best we can. +

    +

    + Isis Support Center +

    + +

    Information and Warnings

    + +

    + Isis 3 and Isis 2 will have collisions of executable names (e.g., + pds2isis exists in both systems). It is best to remove initializations + of Isis 2 from your startup file otherwise you may get unpredictable + results. +

    + +

    + The shell script used to set your environment to run Isis3 modifies the + PATH environment variable. +

    + +

    + The installation for Isis 3 does not allow the installer to choose what + data sets to install or where to put them. The only control is through + the destination directory in the rsync command. If you choose to + move the data area you will need to modify the isis3Startup.xxx script. +

    + + + + HTML + + + index.html + +
    +
    + + + technicaldoc + + + + administrator + + + + Added missing flags to rsync command + Updated for isis 3.0.8 + Updated for isis 3.0.18 + Remove references to beta version + Updated for isis 3.1.5 - Mac OS X + Added rsync options for data + Updated for 3.1.17 + Updated for release 3.2.0 + Updated for release 3.2.1 + + + + Installing Isis + Downloading and installing Isis 3 + + This document describes how to download and install a + binary version of Isis. + + Stuart Sides + 2004-03-10 + +
    diff --git a/isis/src/docsys/documents/Isis2TechnicalDocs/Isis2TechnicalDocs.xml b/isis/src/docsys/documents/Isis2TechnicalDocs/Isis2TechnicalDocs.xml new file mode 100755 index 0000000000000000000000000000000000000000..0d26122ffcdb362a4f238f9e4824c74eee2666da --- /dev/null +++ b/isis/src/docsys/documents/Isis2TechnicalDocs/Isis2TechnicalDocs.xml @@ -0,0 +1,60 @@ + + + + + + hidden + technicaldoc + isis2 + + + + + developer + + + + + Isis 2 Technical Documentation + Links to Isis 2 Technical Documents + List of links to Isis 2 documents covering technical topics, such as administration, release notes, and installation. + Deborah Lee Soltesz + 2003-04-03 + + + + + + HTML + + + index.html + + + + + + + + + + + + + Created + + + diff --git a/isis/src/docsys/documents/Isis2Tutorials/Isis2Tutorials.xml b/isis/src/docsys/documents/Isis2Tutorials/Isis2Tutorials.xml new file mode 100755 index 0000000000000000000000000000000000000000..8544699bfdd5cff9cdc04d0b5ba40de785c88a0e --- /dev/null +++ b/isis/src/docsys/documents/Isis2Tutorials/Isis2Tutorials.xml @@ -0,0 +1,78 @@ + + + + + + hidden + technicaldoc + isis2 + + + + + developer + + + + + Isis 2 Tutorials + Links to Isis 2 tutorials, procedures, and how-to's + List of links to Isis 2 tutorials, procedures, and how-to's. + Deborah Lee Soltesz + 2003-04-03 + + + + + + HTML + + + index.html + + + + +

    General

    + + + +

    Digital Image Processing Procedures

    + + + +
    +
    + + + Created + + +
    diff --git a/isis/src/docsys/documents/Isis2UserDocs/Isis2UserDocs.xml b/isis/src/docsys/documents/Isis2UserDocs/Isis2UserDocs.xml new file mode 100755 index 0000000000000000000000000000000000000000..d41d4ed8ceae8169308f887a4cce283e7b26d76b --- /dev/null +++ b/isis/src/docsys/documents/Isis2UserDocs/Isis2UserDocs.xml @@ -0,0 +1,90 @@ + + + + + + hidden + technicaldoc + isis2 + + + + + developer + + + + + Isis 2 User Documentation + Links to Isis 2 User Documents + List of links to documents covering general topics for users of Isis 2.1 + Deborah Lee Soltesz + 2003-04-03 + + + + + + HTML + + + index.html + + + + +

    General Documentation

    + + +

    Isis User Documentation

    + + + + +
    +
    + + + Created + + +
    diff --git a/isis/src/docsys/documents/IsisHistory/IsisHistory.xml b/isis/src/docsys/documents/IsisHistory/IsisHistory.xml new file mode 100755 index 0000000000000000000000000000000000000000..096b192a09930b08bd330d4d8a945cc9b5b2b465 --- /dev/null +++ b/isis/src/docsys/documents/IsisHistory/IsisHistory.xml @@ -0,0 +1,367 @@ + + + + + +

    Introduction

    + +

    + The cartographic and scientific processing of planetary image + data has a long history within the USGS Astrogeology Program. + The software used has evolved numerous times to keep up with + the steady advances made in computing technology. The + following outlines the progression of the software over + nearly thirty years: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DatesComputerCartographic Software
    1971-1980PDP-11/DOS-BATCHUnnamed
    1978-1987PDP-11/RSX-11MFlagstaff Image Processing System (FIPS)
    1985-1994VAX/VMSPlanetary Image Cartography System (PICS)
    1992-PresentUNIXIntegrated Software for Imagers and Spectrometers
    + +
    + +

    The Early Years

    + + + + + + + + +
    + + [Computer Room] +

    + Computer Room +

    +

    + 600x370, 135KB +

    +
    + + [Ella] +

    + Ella Lee using a DeAnza system to display her work +

    +

    + 456x500, 115KB +

    +
    + + +

    + In 1971, when the Astrogeology's involvement in the Apollo program ended, + many computer personnel transferred to Eros Data Center, transferred to + other federal agencies, or took jobs in the private sector. + Jim Crawforth and Alex Acosta remained and established a computer group to + serve the Flagstaff Field Center. Development began of the unnamed image + processing package on a Digital Equipment Corporation (DEC) PDP-11/20 + with 8K bytes of memory, two 2.5 + megabyte removable disks, an 800BPI tape drive, a card reader, and a + teletype terminal. It ran the DOS/Batch, a single user operating + system, and image display was handled on a $80,000 filmwriter from + Optronics International Inc. +

    + +

    + During the following years, the software migrated to a DEC PDP-11/45 + with 256KB of memory and larger 40MB disks the size of washing machines. + The operating system of choice was RSX-11M, a multi-user system + accessed through VT52 black and white video terminals. Programmers + were restricted to developing applications which utilized a maximum + of 32KB of memory. Image display was upgraded from film to a DeAnza + 512x512 Frame Buffer. This configuration became known as the Flagstaff + Image Processing System (FIPS) +

    +
    + + +

    The Planetary Image Cartography System

    + +

    + In the early 1980's, DEC announced their new VAX/VMS computers which + allowed for virtual addressing. Developers no longer had restrictions + on the size of their programs. With this major change in computing + environment, the Astrogeology Team selected Eric Eliason to lead + the conversion of FIPS to the Planetary Image Cartography System + (PICS). The Transportable Application Executive (TAE) was chosen + as the user interface and programs were gradually migrated to VAX/VMS. + PICS was a popular tool in the planetary community with its ability + to process Viking, Voyager, Magellan, Landsat and various other + spacecraft imagery. +

    + + + + + + + +
    + + [Grinnell Workstation] +

    + Grinnell Workstation +

    +

    + 615x500, 190KB +

    +
    + + [Grinnell System] +

    + Grinnell System +

    +

    + 333x500, 95KB +

    +
    + + [VAX 4000] +

    + VAX 4000 +

    +

    + 325x500, 95KB +

    +
    + +
    + +

    A Star is Born

    +

    + In the late 1980's, several major events occurred which significantly + changed the future of Astrogeology imaging processing software. The + first was our involvement in the Galileo NIMS mission. PICS could + handle multi-spectral instruments with two to seven bands, but the + burden was on the user to manage each band as a separate file. The + hyper-spectral NIMS instrument would have 200-300 bands making + management under PICS an impossibility. At this + time, a completely new software system was invented. The + Integrated System for Imaging Spectrometers (ISIS) came into + existence under the guidance of designer Jim Torson and developer + Kris Becker. The prototype software was released as Isis 2.0. +

    + + + + + +
    + + [Janet using TAE] +

    + Janet Richie uses TAE for her processing work +

    +

    + 500x401, 150KB +

    +
    + +

    + A second major event occurred in the early 1990's, the Clementine + mission. Literally hundreds of thousands of images would be + collected. Unfortunately, PICS operated on VAX/VMS, an aging + and expensive computer system. The planetary community often + lamented over the $50,000 for a single machine including a + display device. At this time, Unix began to make a push + into the computing world. Astrogeology made the decision to + merge the VAX/VMS versions ISIS and PICS under Unix. The integration + of PICS into ISIS was lead by Kay Edwards. The primary Unix platforms + supported were SunOS and DEC OSF1. This version is referred to as Isis 2.1. +

    + +

    + During the late 1990's, ISIS continued to grow in + both number of applications + and the supported operating systems. Software to process data from + Galileo SSI, Mars Pathfinder, Mars Global Surveyor MOC, Mars Odyssey + Themis, and other instruments was added. The software was ported + to the + Linux operating system as the demand for cheaper computers with + "Open Software" increased. TAE was still the user interface but + display software ran under X-windows making visual image analysis + available directly on the user's desktop. ISIS made huge gains in + usage by non-USGS customers, especially with increased focus on + cartographic processing. So much so that the Astrogeolgy Team + changed the meaning of the acronym to Integrated System for Imagers + and Spectrometers. +

    + +

    Current Events

    + + +

    + In 2001, Astrogeology recognized the software was approaching an + end-of-life cycle. Users constantly asked for TAE to be replaced + by a standard Graphical User Interface (GUI). The ISIS development staff + were unable to use many powerful debugging tools because they + did not function at all on Fortran and had other issues with combined + Fortran/C programs. Many of the Open Source APIs were only available + in C++ or Java and thus not available for usage. Aging cube file + formats would not efficiently support missions with line scan cameras. + These and many other reasons led to the decision to modernize ISIS. + Led by Jeff Anderson, work began in December 2001 on the conversion + of Isis to C++. +

    + + + + + + + + +
    Screenshots of Isis Application GUIs: + In addition to GUIs replacing the outdated TAE interface to Isis, programs + will have more meaningful names and there will be more task-specific programs + to make using Isis easier and faster
    + + [Crop screenshot] +

    + Crop +

    +

    + All programs will have dialog boxes for selecting files to process, as shown in this screenshot. + Crop was called dsk2dsk in earlier versions of Isis, one of many programs that have been given + more meaningful names in Isis 3.0. +

    +

    + 549x500, 65KB +

    +
    + + [Low Pass screenshot] +

    + Lowpass +

    +

    + Lowpass is one of several task-specific programs that were once the boxfilter program. +

    +

    + 463x522, 75KB +

    +
    + + [Sharpen screenshot] +

    + Sharpen +

    +

    + Sharpen is another processing task that was once acheived through the boxfilter program. + With large programs like filter broken into several smaller programs, there are few parameters to provide, and + the names are more meaningful, making Isis easier to learn and use. +

    +

    + 480x430, 65KB +

    +
    + +
    + +

    Isis Pedigree

    + + + + + + + + + + + + + + + + + + + + + + +
    Summary of Major Versions of Isis
    + Version + + Description +
    + 1.0 + + Prototype software +
    + 2.0 + + First official release on VAX/VMS +
    + 2.1 + + Ported to Unix +
    + 3.0 + + Rewritten in the C++ programming language for Linux +
    + + + + + HTML + + + IsisHistory.html + +
    +
    + + + about + + + + all + + + + History + A 30 year history of USGS Astrogeology image processing software + + This is a history of the evolution of image procesisng software + within the Astrogeology Team over a 30+ year period from 1971 to 2003. + + Jeff Anderson + 2003-03-25 + + + + Original document + Photographs of computer systems, scans of historical photographs + Dressed up formatting, embedded images + +
    diff --git a/isis/src/docsys/documents/IsisHistory/images/computer_room.jpg b/isis/src/docsys/documents/IsisHistory/images/computer_room.jpg new file mode 100755 index 0000000000000000000000000000000000000000..9182ec93e2a14f2191bce4b3c53ebf4e26e7a901 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/computer_room.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/ella.jpg b/isis/src/docsys/documents/IsisHistory/images/ella.jpg new file mode 100755 index 0000000000000000000000000000000000000000..d7f54bf7fef89116473489d9dfa6e59f0029df92 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/ella.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/grinnell.jpg b/isis/src/docsys/documents/IsisHistory/images/grinnell.jpg new file mode 100755 index 0000000000000000000000000000000000000000..65f0489c3099ad5af459750681016be80720c085 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/grinnell.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/grinnell_station.jpg b/isis/src/docsys/documents/IsisHistory/images/grinnell_station.jpg new file mode 100755 index 0000000000000000000000000000000000000000..16da2257294a47b6130a21f4ee3ffc9d237a1f8e Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/grinnell_station.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/screenshot_crop.jpg b/isis/src/docsys/documents/IsisHistory/images/screenshot_crop.jpg new file mode 100755 index 0000000000000000000000000000000000000000..f7b22fa36c90ce626f45b6cb34a3addef46974e6 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/screenshot_crop.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/screenshot_lowpass.jpg b/isis/src/docsys/documents/IsisHistory/images/screenshot_lowpass.jpg new file mode 100755 index 0000000000000000000000000000000000000000..b553e433b902b88cdc5e16ad2673a7d59b3ea89c Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/screenshot_lowpass.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/screenshot_sharpen.jpg b/isis/src/docsys/documents/IsisHistory/images/screenshot_sharpen.jpg new file mode 100755 index 0000000000000000000000000000000000000000..d07cc42a5c88b01817467a1f51815546e897301e Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/screenshot_sharpen.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/tae.jpg b/isis/src/docsys/documents/IsisHistory/images/tae.jpg new file mode 100755 index 0000000000000000000000000000000000000000..e15de2ad5e8e8f34284647b765b6011b9f2f6096 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/tae.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/thumbs/computer_room.jpg b/isis/src/docsys/documents/IsisHistory/images/thumbs/computer_room.jpg new file mode 100755 index 0000000000000000000000000000000000000000..543ae1774b9a7e20fb4667f562af0d50e968cdb9 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/thumbs/computer_room.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/thumbs/ella.jpg b/isis/src/docsys/documents/IsisHistory/images/thumbs/ella.jpg new file mode 100755 index 0000000000000000000000000000000000000000..4a5b53f1851a27c03eb04225431a6b0ac8adc0e8 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/thumbs/ella.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/thumbs/grinnell.jpg b/isis/src/docsys/documents/IsisHistory/images/thumbs/grinnell.jpg new file mode 100755 index 0000000000000000000000000000000000000000..a014c5cd7caac33daae6c71664b5a5f9187a3bc7 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/thumbs/grinnell.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/thumbs/grinnell_station.jpg b/isis/src/docsys/documents/IsisHistory/images/thumbs/grinnell_station.jpg new file mode 100755 index 0000000000000000000000000000000000000000..1379ec251b58caa5273bdbaf0da441c1018d74d3 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/thumbs/grinnell_station.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/thumbs/screenshot_crop.jpg b/isis/src/docsys/documents/IsisHistory/images/thumbs/screenshot_crop.jpg new file mode 100755 index 0000000000000000000000000000000000000000..d119dcff5fb559892bb1f2574575956cfe36fc5b Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/thumbs/screenshot_crop.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/thumbs/screenshot_lowpass.jpg b/isis/src/docsys/documents/IsisHistory/images/thumbs/screenshot_lowpass.jpg new file mode 100755 index 0000000000000000000000000000000000000000..676d3dde20cd4979d721f035c64d348d9b4e08b6 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/thumbs/screenshot_lowpass.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/thumbs/screenshot_sharpen.jpg b/isis/src/docsys/documents/IsisHistory/images/thumbs/screenshot_sharpen.jpg new file mode 100755 index 0000000000000000000000000000000000000000..583d5445bbdbbd419c1aa9345e00651675855f35 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/thumbs/screenshot_sharpen.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/thumbs/tae.jpg b/isis/src/docsys/documents/IsisHistory/images/thumbs/tae.jpg new file mode 100755 index 0000000000000000000000000000000000000000..eeadf8fa696dfbc64c639aeb7b8c2177e0e8b807 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/thumbs/tae.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/thumbs/vax4000.jpg b/isis/src/docsys/documents/IsisHistory/images/thumbs/vax4000.jpg new file mode 100755 index 0000000000000000000000000000000000000000..971282016d5387aead24bf0d842ccbec380eb8e1 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/thumbs/vax4000.jpg differ diff --git a/isis/src/docsys/documents/IsisHistory/images/vax4000.jpg b/isis/src/docsys/documents/IsisHistory/images/vax4000.jpg new file mode 100755 index 0000000000000000000000000000000000000000..54aed115011eb22b91af02c6b20492797203b0a6 Binary files /dev/null and b/isis/src/docsys/documents/IsisHistory/images/vax4000.jpg differ diff --git a/isis/src/docsys/documents/LabelDictionary/LabelDictionary.xml b/isis/src/docsys/documents/LabelDictionary/LabelDictionary.xml new file mode 100644 index 0000000000000000000000000000000000000000..7bcf14ff186494c10b2057213a3935c17f2ecf8f --- /dev/null +++ b/isis/src/docsys/documents/LabelDictionary/LabelDictionary.xml @@ -0,0 +1,488 @@ + + + + + + +

    Introduction

    + +

    + This document is a reference to the various objects and groups, which can be found in Isis labels. + The definition of each object/group, the parameter meanings, and an example will be given. +

    + +

    + IsisCube Object +

    + +

    + The IsisCube Object is simply a container. It is used to house the various elements (groups and objects) that make up an Isis cube. The IsisCube object is comprised of the Core object, which defines the cube size and pixel attributes and many optional groups that are described elsewhere in this document including Archive, BandBin, Instrument, Kernels, and Mapping Groups. While we present a whole IsisCube object we will save of the individual elements in their own sections. +

    + +
    +Object = IsisCube
    +  Object = Core
    +    ^Core       = filename.dat
    +    StartByte   = 65537
    +    Format      = Tile
    +    TileSamples = 128
    +    TileLines   = 128
    +
    +    Group = Dimensions
    +      Samples = 320
    +      Lines   = 5392
    +      Bands   = 1
    +    EndGroup
    +
    +    Group = Pixels
    +      Type       = Real
    +      ByteOrder  = Lsb
    +      Base       = 0.0
    +      Multiplier = 1.0
    +    EndGroup
    +  EndObject
    +
    +  Group = BandBin
    +    OriginalBand = 10
    +    Center       = 14.88 <microns>
    +    Width        = 0.87 <microns>
    +    FilterNumber = 10
    +  EndGroup
    +EndObject
    +
    + + + +

    Core Object

    +

    + The core object is used to house the groups (Dimensions and Pixels) that describe the size and pixel attributes of the cube, as well as the storage type of the data. +

    + +
    +Object = Core
    +  ^Core       = filename.dat
    +  StartByte   = 65537
    +  Format      = Tile
    +  TileSamples = 128
    +  TileLines   = 128
    +
    +  Group = Dimensions
    +    Samples = 320
    +    Lines   = 5392
    +    Bands   = 1
    +  EndGroup
    +
    +  Group = Pixels
    +    Type       = Real
    +    ByteOrder  = Lsb
    +    Base       = 0.0
    +    Multiplier = 1.0
    +  EndGroup
    +EndObject
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    KeywordTypeDescription
    ^CoreStringThis optional keyword is used to point to an extra binary file containing the cube data. The cube is designated detached (labels and cube data in separate files) if this keyword exists. If the keyword does not exist it indicates the labels and cube data are attached (in the same file).
    StartByteIntegerThis keyword points to the starting byte (one-based) of the cube data. For detached cubes this value is often equal to one. For attached cubes it often 65537 as there is typically 64k bytes reserved for label space. On occasions it may be larger if the labels have grown beyond this boundary.
    FormatString (Tile or BandSequential)This keyword indicates how the cube data is arranged. BandSequential indicates the pixels are stored first by sample, then by line, and finally by band. Tile indicates the pixels are stored in tiles which is the preferred storage mechanism in Isis 3 as it facilities the fastest “universal accessâ€. The tiles are stored in row major format. That is, all the tiles for band 1 ordered from left-to-right, then top-to-bottom, followed by all the tiles for band 2, etc.
    TileSamples, TileLinesIntegerOptional keywords which must exist when Format=Tile in a cube. These define the size of the tiles in the cube and do not have to be the same. They are typically 128 x 128 in size.
    + +

    Dimensions Group

    +

    + This group contains keywords which define the physical dimensions of the cube. The group is always found inside the Core object. +

    + +
    +Group = Dimensions
    +  Samples = 320
    +  Lines   = 5392
    +  Bands   = 1
    +EndGroup
    +
    + + + + + + + + + + +
    KeywordTypeDescription
    Samples, Lines, BandsIntegerThese three keywords are in the Dimensions group and define the size of the cube.
    +

    Pixel Group

    +

    + This group describes information about the pixels in a cube. The group is always found inside the Core object. +

    + +
    +Group = Pixels
    +  Type       = Real
    +  ByteOrder  = Lsb
    +  Base       = 0.0
    +  Multiplier = 1.0
    +EndGroup
    +
    + + + + + + + + + + + + + + + + + + +
    KeywordTypeDescription
    TypeString (UnsignedByte, SignedWord, Real)Currently there are three type of pixels in Isis which represent unsigned 8-bit vaues (0 to 255), signed 16-bit values (-32768 to 32767) and 32-bit IEEE floating point pixel values. [Future option] Support alternative pixel types.
    ByteOrderString (Lsb, Msb)This defines the byte order or endianess of the pixels. The order must either be least significant byte (Lsb) or most significant byte (Msb).
    Base, MultiplierDoubleThese values are used to scale UnsignedByte and SignedWord pixels so they appear to be Real (32-bit floating) pixels. That is, realDn = diskDN * Multiplier + Base. These values are always 0.0 and 1.0 when Type=Real.
    + +

    AlphaCube Group

    +

    + This group is used to map pixel locations in a child cube (beta) back to its parent cube (alpha). It is necessary in order to determine which detector a pixel represents in Isis camera models. The group is created by Isis ingestion programs (e.g., thm2isis, moc2isis, ciss2isis, etc) and automatically updated by programs such as crop, pad, reduce, or enlarge. The keywords found in this group can occur in one of two places. Either inside of the AlphaCube group or inside of the Instrument group and therefore they can occur twice. Once if a crop occurred in Instrument (level 1) space and again if a crop occurred in Mapping (level 2) space. +

    + +
    +Group = AlphaCube
    +    AlphaSamples          = 320
    +    AlphaLines            = 5392
    +    AlphaStartingSample   = 0.5
    +    AlphaStartingLine     = 0.5
    +    AlphaEndingSample     = 320.5
    +    AlphaEndingLine       = 5392.5
    +    BetaSamples           = 320
    +    BetaLines             = 5392
    +EndGroup
    +
    + + + + + + + + + + + + + + + + + + +
    KeywordTypeDescription
    AlphaSamples, AlphaLines Integer The number of lines and samples in the original parent/alpha cube.
    AlphaStartingSample, AlphaStartingLine Double The starting sample and line in the alpha cube which maps to (0.5,0.5) in the beta cube.
    AlphaEndingSample, AlphaEndingLine Double The ending sample and line in the alpha cube which maps to (BetaSamples+0.5,BetaLines+0.5) in the beta cube.
    +

    Archive Group

    +

    + This group is used to store keywords that identify archival information. That is, information which uniquely identifies the data. There is not a “required†set of keywords for this group. Generally, the keywords found in this group represent PDS specific information as indicated in the example given below. +

    + +
    +Group = Archive
    +  ImageNumber         = "7102002401"
    +  ProductId           = “AB-1-024/01â€
    +  DataSetId           = "MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0"
    +  ProducerId          = "MGS_MOC_TEAM"
    +  ProductCreationTime = "1999-01-15T20:40:59.000Z"
    +  UploadId            = "moc_p024_v1.sasf"
    +  ImageKeyId          = "5618102401"
    +  RationalDescription = “OLYMPUS MONS SPECIAL RED WA"
    +EndGroup
    +
    + +

    BandBin Group

    +

    + This group is used to stored information regarding each band in the cube. This implies that every keyword in the group be an array with a dimension equal to the number of bands in the cube. This group is not required nor if it exists are any particular keywords required. That is, the names of keywords are irrelevant although some instrument- specific programs may expect certain keywords to be available (e.g., OriginalBand). The keywords in this group will be automatically pruned if any program uses the input cube attribute option (e.g., from=input.cub+1,3-4). +

    + +
    +Group = BandBin
    +  OriginalBand = (1, 2, 3, 4, 5)
    +  Center       = (6.78, 6.78, 7.93, 8.56, 9.35) <microns>
    +  Width        = (1.01, 1.01, 1.09, 1.16, 1.20) <microns>
    +  FilterNumber = (1, 2, 3, 4, 5)
    +EndGroup
    +
    + + + + + + + + + + + + + + +
    KeywordTypeDescription
    OriginalBand Integer This keyword indicates the original band number at the current band location. Hence, extracting bands 2 and 5 from a cube via the input cube attribute option would yield OriginalBand = (2,5)
    Center, Width Double Often these keywords are used to describe the center wavelength and width of each band.
    + +

    ImportLabel Object

    + This object contains the original labels that were read during the import process, if possible. For example, vicar2isis and pds2isis often have many more labels than are required by Isis programs. However, there may be information in those labels that the user would like to examine or preserve. Note that Isis program should never use any keywords values in these labels. + +
    +Object = ImportLabel
    +  Lblsize  = 536
    +  Format   = HALF
    +  Type     = IMAGE
    +  Bufsiz   = 24576
    +  Dim      = 3
    +  Eol      = 1
    +  Recsize  = 536
    +  Org      = BSQ
    +  Nl       = 256
    +  Ns       = 256
    +  Nb       = 1
    +  N1       = 256
    +  N2       = 256
    +  N3       = 1
    +  N4       = 0
    +  Nbb      = 24
    +  Nlb      = 1
    +  Host     = SUN-SOLR
    +  Intfmt   = HIGH
    +EndObject
    +
    + +

    Instrument Group

    +

    + This group stores specific information regarding the mission and instrument. This information is typically used to perform radiometric calibration as well as in camera models in order to accurately compute ground positions in a raw camera cube. Obviously, the keywords in the group will vary from instrument to instrument. However, there are three required keywords (Name, SpaceCraft, and Target). Definitions for Instrument specific keywords can be found in the appropriate documentation for that instrument. +

    + +
    +Group = Instrument
    +  SpacecraftName  = "Galileo Orbiter"
    +  InstrumentId    = "Solid State Imaging System"
    +  TargetName      = Io
    +  StartTime       = "1996-06-25T17:36:56.858"
    +  FrameModeId     = Full
    +EndGroup
    +
    + + + + + + + + + + + + + + + + + + +
    KeywordTypeDescription
    SpacecraftName String Name of the mission/spacecraft
    InstrumentId String The name of the instrument
    TargetName String The name of target/body which the instrument is viewing
    + +

    Kernels Group

    +

    + The Kernels group is created when the program “spiceinit†is run on a raw camera cube (e.g., Moc or Themis raw geometry). The program determines which NAIF SPICE kernels are needed for proper operation of the camera model. These kernels are written to this group. +

    + +
    +Group = Kernels
    +  LeapSecond          = mk98264a.tls
    +  SpaceCraftClock     = mk00062b.tsc
    +  TargetPosition      = s980326b.bsp
    +  TargetAttitudeShape = pck00005.tpc
    +  Instrument          = ""
    +  InstrumentAddendum  = ssiAddendum.ti
    +  SpaceCraftPosition  = s980326b.bsp
    +  SpaceCraftPointing  = galssi_io_010806.baa.bck
    +  Frame               = ""
    +  ElevationModel      = iodem.cub
    +EndGroup
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeywordTypeDescription
    LeapSecond Filename The name of the NAIF leapsecond kernel. See NAIF required reading document time.req for more information.
    SpaceCraftClock Filename The name of the NAIF spacecraft clock kernel. See NAIF required reading document sclk.req for more information.
    TargetPosition Filename The name of the NAIF planetary ephemeris kernel. Note that this may be the same as the spacecraft position kernel. See NAIF required reading document spk.req for more information.
    TargetAttitudeShape Filename The name of the NAIF planetary constants kernel. It contains the target radii and definitions for prime merdian and the pole. See NAIF required reading document pck.req for more information.
    Instrument Filename The name of the NAIF instrument kernel for the particular mission/instrument. It contains specifics regarding the instruement (e.g., focal length, boresight, etc).
    InstrumentAddendum Filename The name of the Isis addendum to the instrument kernel for the particular mission/instrument. This often contains information that is lacking from the NAIF instrument kernel in order to have a properly functioning sensor model.
    SpacecraftPosition Filename The name of the NAIF spacecraft ephemeris (position) kernel. Note that this may be the same as the target position kernel. See NAIF required reading document spk.req for more information.
    SpacecraftPointing Filename The name of the NAIF spacecraft pointing (c-matrix) kernel. See NAIF required reading document ck.req for more information.
    Frame Filename The name of the NAIF frame kernel. See NAIF required reading document frames.req for more information.
    ElevationModel Filename The name of an Isis cube containing the local (or global) radii covering the cube’s latitude/longitude ground range. The elevation model will utilized by the camera model to remove topographic effects. If one is not available the local radii is computed from the ellipsoid defined in the TargetAttitudeShape kernel.
    + +

    Mapping Group

    +

    + The Mapping Group is used to define map projections. Recommending reading includes the Isis Map Projection Guide and Map Projections – A Working Manual, Snyder, J.P., U.S. Geological Survey, Bulletin 1532. +

    + +
    +Group = Mapping
    +  ProjectionName         = Sinusoidal
    +  TargetName             = MARS
    +  EquatorialRadius       = 3396190.0 <meters>
    +  PolarRadius            = 3376200.0 <meters>
    +  LatitudeType           = Planetocentric
    +  LongitudeDirection     = PositiveEast
    +  LongitudeDomain        = 360
    +  MinimumLatitude        = -5.5707102
    +  MaximumLatitude        = 13.8285999
    +  MinimumLongitude       = 351.4547729
    +  MaximumLongitude       = 355.6184082
    +  PixelResolution        = 100.0 <meters/pixel>
    +  Scale                  = 592.74697523306 <pixels/degree>
    +  TrueScaleLatitude      = 0.0
    +  CenterLongitude        = 354.0
    +  LineProjectionOffset   = -8196.5
    +  SampleProjectionOffset = -1508.5
    +  UpperLeftCornerX       = -150900.0 <meters>
    +  UpperLeftCornerY       = 819700.0 <meters>
    +EndGroup
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeywordTypeDescription
    ProjectionName String This indicates the name of the map projection (Sinusoidal, SimpleCylindrical, PolarStereographic, etc)
    EquatorialRadius, PolarRadius Double The distance in meters from the center of the body to any point on the equator or to either pole, respectively.
    LongitudeDirection String The direction of positive longitude, PositiveEast or PostiveWest. The term PositiveEast implies that longitudes increase to the right on a map.
    LatitudeType String Indicates the coordinate type for the latitude values, Planetocentric or Planetographic
    LongitudeDomain String Indicates the preferred representation, 180 or 360 domain, of longitudes when reporting values or constructing new map. The value 360 implies 0 to 360 while 180 implies -180 to 180.
    MinimumLatitude, MaximumLatitude, MinimumLongitude, MaximumLongitude Double The values indicate the ground range of the projection (in coordinates of LatitudeType and LongitudeDirection). Because cubes/images are discrete by nature (integral number of pixels), the latitude and longitude boundaries will rarely if every match perfectly. Therefore these values are used only when a map-projected cube is constructed and should only be used as reference from that point forward. For example, do not use these values to import data into another image processing package; instead use UpperLeftCornerX and UpperLeftCornerY.
    PixelResolution Double This indicates size of each pixel in meters relative to the map projection. Beware that this does not imply each pixel has true scale. That is completely dependent upon the type of map projection utilized (Sinusoidal, Mercator, etc). The resolution often only holds at the latitude of true scale.
    Scale Double This indicates the number of pixels per degree relative to the map projection. Beware that this does not imply each pixel has true scale. That is completely dependent upon the type of map projection utilized (Sinusoidal, Mercator, etc). The scale often only holds at the latitude of true scale.
    TrueScaleLatitude Double This indicates the latitude at which the Scale or PixelResolution holds true.
    UpperLeftCornerX, UpperLeftCornerY Double These values indicate the projection X/Y in meters at sample 0.5, line 0.5. This base X/Y along with the PixelResolution can be used to compute the projection X/Y at any pixel location in the cube. For example, X = (Sample – 0.5) * PixelResolution + UpperLeftCornerX and Y = UpperLeftCornerY – (Line – 0.5) * PixelResolution. With the proper equations for the projection the computed X/Y could be converted to a latitude/longitude.
    LineProjectionOffset,SampleProjectionOffset Double These values are listed solely for compatibility with PDS labels and are equivalent to the UpperLeftCorner values in pixel units.
    + + + + HTML + + + LabelDictionary.html + +
    +
    + + + reference + + + + intermediate + + + + Label Dictionary + Reference to the objects and groups in Isis cube labels + + This document is a reference to the various objects and groups, which can be found in Isis labels. + The definition of each object/group, the parameter meanings, and an example will be given. + + Jeff Anderson + 2003-06-11 + + + + Original + Converted Jeff Anderson's documentation to HTML and added to this file + Total rewrite + +
    diff --git a/isis/src/docsys/documents/LogicalCubeFormatGuide/LogicalCubeFormatGuide.xml b/isis/src/docsys/documents/LogicalCubeFormatGuide/LogicalCubeFormatGuide.xml new file mode 100644 index 0000000000000000000000000000000000000000..88054cbed84e476b4cb9ad7319ea5f4c7fa783c8 --- /dev/null +++ b/isis/src/docsys/documents/LogicalCubeFormatGuide/LogicalCubeFormatGuide.xml @@ -0,0 +1,170 @@ + + + + + + +

    Introduction

    + +

    + This basic guide focuses on core Isis labels and a conceptual file structure for a cube. The intent is not to describe the complex nature of the physical file format or the meaning of every element of an Isis label. There are other programmer-related documents that delve into this detailed information. They include, Isis Physical Cube Format Guide and Isis Label Reference. While this document is basic in nature, it is not intended to be an introduction to image processing. We assume the reader has a general understanding of common terminology such as pixels, lines, samples, bit-type, etc. +

    +

    + From our past experiences we know that a digital image is a two-dimensional array of pixels. The Isis cube format expands an image into the third dimension. +

    + +
    +
    + [Line Diagram of the Isis Cube image format]
    +

    + This diagram illustrates that the Isis Cube image format can be visualized as a rectangular prism, + with the origin in the closest upper left corner , the lines running in the height direction, the + samples running in the width direction, and the bands running in the depth direction. +

    +
    +
    + + +

    + The word "cube" may be somewhat misleading as it implies equal length along each dimension. The volume of course is a rectangular prism + but for convenience sake we will continue to use cube. The origin of the cube is referred as coordinate (1,1,1) in order of + (sample,line,band). Samples increase from left-to-right, lines from top-to-bottom, and bands from front-to-back. We refer to the sample-line axes as spatial planes. + The sample-band and line-band axes are denoted as spectral planes. +

    + +

    Pixels and Special Pixels

    + +

    + As usual, each individual pixel contains a number representing some physical property (e.g., radiance, reflectance, elevation). As a user, these numbers should always be thought of as a floating-point number. That is, 15.397 or –1E15. The conversion from 8-bit or 16-bit pixels is handled behind the scene, thus presenting users (and application programmers) with real world values. +

    +

    + Isis has the ability to deal with unique conditions within a cube. That is, there are reserved values that have special meaning and hence the name "special pixels". + The following is a table of pixel value you may encounter when running programs or visually examining cubes: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Null + + A null pixel indicates no data was collected at the particular location +
    + Lis + + A low instrument saturation pixel occurred meaning the instrument readout was at its lowest possible value +
    + His + + A high instrument saturation pixel occurred meaning the instrument readout was at its highest possible value +
    + Lrs + + A low representation saturation pixel occurred meaning a program computed a new pixel value at this + location that was lower than native bit-type for the file (e.g., less than zero for an 8-bit file). +
    + Hrs + + A high representation saturation pixel occurred meaning a program computed a new pixel value at this + location that was greater than native bit-type for the file (e.g., greater than 255 for an 8-bit file). +
    + +

    File Specifications

    + +

    + An Isis cube consists of two parts, the labels and the pixel data. These can be stored together in one file (attached) or + in two separate files (detached). As Isis programs automatically enforce an extension of .cub on the output file you can expect + to find the pixels in a file with an extension of .cub; if you decide detach your labels you will also have a file with an extension of .lbl. + The following is an example of the minimum labels for a cube: + +

    +  Object = IsisCube
    +    Object = Core
    +      StartByte   = 65537
    +      Format      = Tile
    +      TileSamples = 128
    +      TileLines   = 128
    +
    +      Group = Dimensions
    +        Samples = 2468
    +        Lines   = 11499
    +        Bands   = 1
    +      EndGroup
    +
    +      Group = Pixels
    +        Type       = Real
    +        ByteOrder  = Lsb
    +        Base       = 0.0
    +        Multiplier = 1.0
    +      EndGroup
    +    EndObject
    +  EndObject
    +End
    +
    +          
    +

    + +

    Other Groups

    + +

    + There are many other groups that you will find in the labels of a cube. For example, + Instrument, Kernels, Archive, and Mapping, to name a few. + Definitions of these groups and their keywords, as well as the IsisCube object presented above, can be found in the + Isis Label Dictionary. +

    + + + + HTML + + + LogicalCubeFormatGuide.html + +
    +
    + + + guide + + + + intermediate + + + + Logical Cube Format Guide + Guide to core Isis labels and a conceptual file structure for a cube + + This basic guide focuses on core Isis labels and a conceptual file structure for a cube + + Jeff Anderson + 2003-03-26 + + + + Original + Converted Jeff Anderson's documentation to HTML and added to this file + +
    diff --git a/isis/src/docsys/documents/LogicalCubeFormatGuide/assets/cubediagram.png b/isis/src/docsys/documents/LogicalCubeFormatGuide/assets/cubediagram.png new file mode 100644 index 0000000000000000000000000000000000000000..48819a7b90ee827effa551944333f1220f378e48 Binary files /dev/null and b/isis/src/docsys/documents/LogicalCubeFormatGuide/assets/cubediagram.png differ diff --git a/isis/src/docsys/documents/LogicalCubeFormatGuide/assets/cubediagram.psd b/isis/src/docsys/documents/LogicalCubeFormatGuide/assets/cubediagram.psd new file mode 100644 index 0000000000000000000000000000000000000000..b8ec030789ec5422337f1eecb4db72a076a199ec Binary files /dev/null and b/isis/src/docsys/documents/LogicalCubeFormatGuide/assets/cubediagram.psd differ diff --git a/isis/src/docsys/documents/Makefile b/isis/src/docsys/documents/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..99494a68ec1548897d6bf66eeea4c415d0872f8d --- /dev/null +++ b/isis/src/docsys/documents/Makefile @@ -0,0 +1,112 @@ +include $(ISISROOT)/make/isismake.macros + +# ISIS DOCS MAKEFILE +# Create XML table of contents for the documents +# and generate upper level navigation pages +# dls - deborah lee soltesz - 12/04/2002 + + +DOCUMENTS = $(filter-out CVS $(wildcard Makefile*) $(wildcard *.*) , $(wildcard *)) +DOCDIR = $(ISISROOT)/doc/documents + + + + +docs: documents tocXML aboutisis general guides installation technicalinfo userdocs + + + +# DOCUMENT LIST +# build individual documents as needed + +documents: + echo " Building Individual Documents" + for dirname in $(DOCUMENTS); do \ + cd $$dirname ; \ + make -f ../Makefile-documents docbuild ; \ + cd .. ; \ + done + echo " Finished Building Individual Documents" + + + +# TABLE OF CONTENTS XML +# build tables of contents XML file for doc directories + +tocXML: ../build/doctoc.xml ../build/IsisDocumentTOCbuild.xsl +../build/doctoc.xml: $(DOCDIR) + + echo " Building Table of Contents XML" + cat ../build/doctoc_header.xml > ../build/doctoc.xml + for dirname in $(DOCUMENTS); do \ + echo " Adding [$$dirname]" ; \ + $(XALAN) -p dirParam "'$$dirname'" $$dirname/$$dirname.xml ../build/IsisDocumentTOCbuild.xsl >> ../build/doctoc.xml ; \ + done + cat ../build/doctoc_footer.xml >> ../build/doctoc.xml + echo " Finished Building Table of Contents XML" + + + +# TABLE OF CONTENTS PAGES +# build various upper level pages that link documents + +# ABOUT ISIS TOC +aboutisis: $(ISISROOT)/doc/AboutIsis/index.html +$(ISISROOT)/doc/AboutIsis/index.html: ../build/doctoc.xml ../build/AboutIsis.xsl + + echo " Constructing [About Isis]" + $(XALAN) -p menuPath "'../'" -o $(ISISROOT)/doc/AboutIsis/index.html ../build/doctoc.xml ../build/AboutIsis.xsl + + +# GENERAL TOC +general: $(ISISROOT)/doc/General/index.html +$(ISISROOT)/doc/General/index.html: ../build/doctoc.xml ../build/General.xsl + + echo " Constructing [General]" + $(XALAN) -p menuPath "'../'" -o $(ISISROOT)/doc/General/index.html ../build/doctoc.xml ../build/General.xsl + +# GUIDES TOC +guides: $(ISISROOT)/doc/Guides/index.html +$(ISISROOT)/doc/Guides/index.html: ../build/doctoc.xml ../build/Guides.xsl + + echo " Constructing [Guides]" + $(XALAN) -p menuPath "'../'" -o $(ISISROOT)/doc/Guides/index.html ../build/doctoc.xml ../build/Guides.xsl + +# INSTALLATION TOC +installation: $(ISISROOT)/doc/Installation/index.html +$(ISISROOT)/doc/Installation/index.html: ../build/doctoc.xml ../build/Installation.xsl + + echo " Constructing [Installation]" + $(XALAN) -p menuPath "'../'" -o $(ISISROOT)/doc/Installation/index.html ../build/doctoc.xml ../build/Installation.xsl + +# TECHNICAL INFO TOC +technicalinfo: $(ISISROOT)/doc/TechnicalInfo/index.html +$(ISISROOT)/doc/TechnicalInfo/index.html: ../build/doctoc.xml ../build/TechnicalInfo.xsl + + echo " Constructing [TechnicalInfo]" + $(XALAN) -p menuPath "'../'" -o $(ISISROOT)/doc/TechnicalInfo/index.html ../build/doctoc.xml ../build/TechnicalInfo.xsl + +# USER DOCS TOC +userdocs: $(ISISROOT)/doc/UserDocs/index.html +$(ISISROOT)/doc/UserDocs/index.html: ../build/doctoc.xml ../build/UserDocs.xsl + + echo " Constructing [UserDocs]" + $(XALAN) -p menuPath "'../'" -o $(ISISROOT)/doc/UserDocs/index.html ../build/doctoc.xml ../build/UserDocs.xsl + + + + + + +# CLEAN +clean: + for dirname in $(DOCUMENTS); do \ + cd $$dirname ; \ + rm -f *.html ; \ + rm -f Makefile-temp ; \ + cd .. ; \ + done + + + + diff --git a/isis/src/docsys/documents/Makefile-documents b/isis/src/docsys/documents/Makefile-documents new file mode 100755 index 0000000000000000000000000000000000000000..91bf92ec6a3373110120a204e014723023a4150c --- /dev/null +++ b/isis/src/docsys/documents/Makefile-documents @@ -0,0 +1,66 @@ +include $(ISISROOT)/make/isismake.macros + +# ISIS DOCS MAKEFILE +# Create XML table of contents for the documents +# and generate upper level navigation pages +# dls - deborah lee soltesz - 12/04/2002 + + +DOCUMENTS = $(filter-out CVS $(wildcard Makefile*) $(wildcard *.*) , $(wildcard *)) +DOCDIR = $(ISISROOT)/doc/documents + + +DOC = $(shell basename `pwd`) + + +# DOCUMENT LIST +# build the TOC XML for all the documents and generate makefiles that +# build individual documents as needed + +docbuild: $(DOCDIR)/$(DOC) +$(DOCDIR)/$(DOC): $(DOC).xml ../../build/IsisInlineDocumentBuild.xsl ../../build/IsisSubPageBuild.xsl ../../build/IsisPrimaryPageBuild.xsl + + + mkdir -p $(DOCDIR)/$(DOC) + touch $(DOCDIR)/$(DOC) + touch $(DOCDIR) + $(XALAN) -p menuPath "'../../'" -p dirParam "'$(DOC)'" -o Makefile-temp $(DOC).xml ../../build/IsisInlineDocumentBuild.xsl + make -f Makefile-temp docs + rsync -lHptr --delete --rsh=ssh * $(DOCDIR)/$(DOC)/ + + + + + +#TODO +# the following are temprary macros for updating the websites with the latest document build. +# these need to be removed and replaced with a more reasonable update script + +# public docsrc upload +wwwdocsrc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docsys to public server" + rsync -vlHptr --delete --progress --rsh=ssh $(ISISROOT)/src/docsys/* webmaster@wwwflag:/www/httpd/Astrogeology/Extranet/htdocs/Projects/IsisXML/docsrc/ + +# dev docsrc upload +devdocsrc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docsys to dev server" + rsync -vlHptr --delete --progress --rsh=ssh $(ISISROOT)/src/docsys/* dsoltesz@wwwdev:/www/httpd/Astrogeology/Extranet/htdocs/Projects/IsisXML/docsrc/ + +# public doc upload +wwwdoc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docs to public server" + rsync -vlHptr --delete --progress --rsh=ssh $(ISISROOT)/doc/* webmaster@wwwflag:/www/httpd/Astrogeology/Extranet/htdocs/Projects/IsisXML/doc/ + +# dev doc upload +devdoc: + echo " " + echo "_______________________________________________________________________________" + echo "BEGIN SYNC: docs to dev server" + rsync -vlHptr --delete --progress --rsh=ssh $(ISISROOT)/doc/* dsoltesz@wwwdev:/www/httpd/Astrogeology/Extranet/htdocs/Projects/IsisXML/doc/ + diff --git a/isis/src/docsys/documents/Overview/Overview.xml b/isis/src/docsys/documents/Overview/Overview.xml new file mode 100755 index 0000000000000000000000000000000000000000..8f73960db5f3f89bb04a4739bc9d3907ecd519b8 --- /dev/null +++ b/isis/src/docsys/documents/Overview/Overview.xml @@ -0,0 +1,71 @@ + + + + + + +

    What is Isis

    +

    + The Integrated System for Imagers and Spectrometers (Isis) is + a specialized image processing package. It has many standard + image processing operations such as contrast stretch, image + algebra, filters, and statistical analysis. Isis operates on both + classical two-dimensional images as well as three-dimensional + cubes collected from imaging spectrometers. The real power of + Isis, however, is its unique + capabilities for processing data from NASA spacecraft missions + such as Voyager, Viking, Galileo, Mars Global Surveyor, + and Mars Odyssey. +

    + +

    Mission Specific Capabilities

    +

    + There are three major functions which must exist in order to + process EDR images (Experimental Data Records) for a particular + mission. The first is the ability to ingest or convert the EDR + into an Isis image. The second is to calibrate + the raw DNs (e.g. number from 0 to 255) by converting them to + radiance or some other planetophysical property. Finally, + a camera/sensor model must be developed in order to convert + the images in raw camera geometry to a usable map projection. +

    + +

    Cartographic Capabilities

    +

    + Once the software for ingestion, calibration, and camera models + are in place, a large suite of cartography programs can be + utilized. These programs allow for digital mosaicking of + adjacent EDRs, photometric modeling and normalization, + removal of systematic noise patterns, overlaying graticules, + and numerous other cartographic and scientific analysis functions. +

    + + + + HTML + + + Overview.html + +
    +
    + + + about + + + + all + + + + Overview + A quick summary of Isis + + This document summarizes the purpose, functions, and supported + missions in the Isis software package. + + Jeff Anderson + 2003-06-25 + +
    diff --git a/isis/src/docsys/documents/PreferenceDictionary/PreferenceDictionary.xml b/isis/src/docsys/documents/PreferenceDictionary/PreferenceDictionary.xml new file mode 100644 index 0000000000000000000000000000000000000000..add71bef29e8e9dd56858dc2df6fcf9443a59d43 --- /dev/null +++ b/isis/src/docsys/documents/PreferenceDictionary/PreferenceDictionary.xml @@ -0,0 +1,133 @@ + + + + + +

    Introduction

    +

    +This reference document describes the elements of the Isis User Preference file. See Environment and Preference Setup for detailed information. +

    + +

    User Interface

    +

    +The user interface group in the preference file allows you to customize the way your applications run, and how they look +in graphical form. The user interface in either graphical or command line mode supplies a progress indicator to the user. +The increment of the progress bar can be customized to increase the bar by 10%, 5%, 2%, or 1%. Additionally, in the +command line mode, the user can turn off the progress bar if desired. The GUI will always update the progress bar. The +style of the GUI can be customized to have a windows, cde, kde, etc. look to it. The browser fired up from the GUI can +also be specified, along with the size of the GUI, and its font type and size. By default, all history files are stored in the +users home directory under .Isis/history. This can be customized to save the history files in the users current directory +(using '.') or any other directory. The history recording can also be turned off if the user does not wish to record any +history on the programs being run. + +

    +Group=UserInterface
    +  ProgressBarPercent = 10 | 5 | 2 | 1
    +  ProgressBar        = On | Off
    +  GuiStyle           = windows | motif | cde | motifplus | platinum | sgi | kde | aqua
    +  GuiHelpBrowser     = firefox { your preferred browser, may need path }
    +  GuiFontName        = helvitica | times | charter | any legal font
    +  GuiFontSize        = 10 | 12 | 14 | any font point size
    +  GuiWidth           = 460 { your preferred gui width }
    +  GuiHeight          = 600 { your preferred gui height }
    +  HistoryPath        = $HOME/.Isis/history { your preferred location for the application .par files }
    +  HistoryRecording   = On | Off
    +  HistoryLength      = your preferred count of history entries to remember
    +EndGroup
    +
    +

    + +

    Error Facility

    +

    +Errors can be written in either standard (single line) or PVL format. +Additionally, the source file and line number identifying where the error +occurred can be suppressed. Stack traces can also be displayed when running Isis +in debug mode. + +

    +Group = ErrorFacility
    +  Format   = Standard | Pvl
    +  FileLine = On | Off
    +  StackTrace = On | Off
    +EndGroup
    +
    +

    + +

    Session Log

    +

    +These parameters control the session log. Logging can be completely turned off, directed to a terminal, to a file, or both. The name of the log file is customizable and content can be either overwritten or appended. + +

    +Group = SessionLog
    +  TerminalOutput = On | Off
    +  FileOutput     = On | Off
    +  FileName       = print.prt
    +  FileAccess     = Append | Overwrite
    +EndGroup
    +
    +

    + +

    Cube Customization

    +

    +The user can control how specific attributes of cube I/O are performed. In particular, they can specify whether programs will 1) automatically overwrite an existing cube or issue and error message, 2) generate a single attached file containing labels, history, and cube data or detached cube with three files (label, history, data), 3) automatically gather statistics as the data is written to disk and record the computations in the labels, and 4) record a history entry of the program in the cube file. + +

    +Group = CubeCustomization
    +  Overwrite  = Allow | Error
    +  Format     = Attached | Detached
    +  Statistics = On | Off
    +  History    = On | Off
    +EndGroup
    +
    +

    + +

    Data Directories

    +

    +Isis supports many missions that require various data such as SPICE kernels or calibration files. Because these files can be quite large it may be required to move the data into a different directories from the normal distribution. This customization supports that requirement. The Isis system manager would generally modify this group in the system-wide preference file. + +

    +Group = DataDirectory
    +  Base      = $ISIS3DATA/base
    +  Viking1   = $ISIS3DATA/viking1
    +  Viking2   = $ISIS3DATA/viking2
    +  Voyager   = $ISIS3DATA/voyager
    +  Mgs       = $ISIS3DATA/mgs
    +  Galileo   = $ISIS3DATA/galileo
    +  Cassini   = $ISIS3DATA/cassini
    +  Odyssey   = $ISIS3DATA/odyssey
    +  Mro       = $ISIS3DATA/mro
    +  Messenger = $ISIS3DATA/messenger
    +  Temporary = .
    +EndGroup
    +
    +

    + + + HTML + + + PreferenceDictionary.html + +
    +
    + + + reference + + + + intermediate + + + + Preference Dictionary + + Complete reference to all user preference settings + + + Complete reference to all user preference settings + + Jeff Anderson + 2003-03-27 + +
    diff --git a/isis/src/docsys/documents/ProgrammerGuide/ProgrammerGuide.xml b/isis/src/docsys/documents/ProgrammerGuide/ProgrammerGuide.xml new file mode 100755 index 0000000000000000000000000000000000000000..9c5868b15e13acc6b4441b3655f1877b4fd8fcb2 --- /dev/null +++ b/isis/src/docsys/documents/ProgrammerGuide/ProgrammerGuide.xml @@ -0,0 +1,29 @@ + + + + + +

    This is a dummy file for the a Programmers Guide.

    + + HTML + + ProgrammerGuide.html + +
    +
    + + technicaldoc + guide + api + + + programmer + + + Programmer Guide + Guide to Programming the Isis software package + Guide to the Isis software for Isis Programmers, using libraries, writing libraries and applications, working in the team development area, writing XML files, and winning lottery numbers. + Deborah Lee Soltesz + 2002-12-09 + +
    diff --git a/isis/src/docsys/documents/References/References.xml b/isis/src/docsys/documents/References/References.xml new file mode 100755 index 0000000000000000000000000000000000000000..36d6528adf70b4e96b556e38dc26a038635a8f0d --- /dev/null +++ b/isis/src/docsys/documents/References/References.xml @@ -0,0 +1,64 @@ + + + + + + +

    + We appreciate the acknowledgement of the authors and the USGS in publications that result from the use of the + Isis software package or in products that include this software in whole or in part. Samples of the correct way + to acknowledge and reference the appropriate parties follows. +

    + +

    Acknowledgement

    +

    + The correct acknowledgement for the ISIS software package is as follows: +

    +
    +        This research has made use of the USGS Integrated Software for Imagers and Spectometers (ISIS). 
    +        
    + +

    References

    +

    + If you need to make references to ISIS in a paper, here are some starting points: +

    +
    +Torson, J.M., and Becker, K.J., (1997) ISIS - A Software Architecture for Processing Planetary Images (abs.), 
    +      LPSC XXVIII, pp. 1443-1444. 
    +
    +Gaddis, L.R., et al., (1997) An Overview of the Integrated Software for Imaging Spectrometers (abs.), 
    +      LPSC XXVIII, pp. 387-388 
    +
    +Anderson, J.A., et al., (2004) Modernization of the Integrated Software for Imagers and Spectrometers (abs. 2039),
    +      LPSC XXXV 
    +        
    + + + + HTML + + + References.html + +
    +
    + + + about + + + + all + + + + References + Acknowledgements, Citations, and References for the Isis software package + + A summary of acknowledgements, citations, and references for the Isis + software package + + Elizabeth Miller + 2006-01-09 + +
    diff --git a/isis/src/docsys/documents/SessionLogs/SessionLogs.xml b/isis/src/docsys/documents/SessionLogs/SessionLogs.xml new file mode 100644 index 0000000000000000000000000000000000000000..d29a16211e45f7f02ec2295ed652bb48053a2d83 --- /dev/null +++ b/isis/src/docsys/documents/SessionLogs/SessionLogs.xml @@ -0,0 +1,168 @@ + + + + + + + +

    Introduction

    +

    +Session logs are a mechanism for users to keep track of work they have done. It is a record of the execution of an Isis program or sequence of Isis programs. Information written to the log includes: +

    + +
      +
    • Isis version number
    • +
    • Program version date
    • +
    • Date and time the program was run
    • +
    • Computer name on which the program was run
    • +
    • User who ran the program
    • +
    • Brief description of the program
    • +
    • Input parameters
    • +
    • Program results
    • +
    • Error messages
    • +
    • Accounting information
    • +
    + +

    +Control of session logs can be handled via user preferences. For specific information on these preferences see the +Isis Preference Dictionary. + +

    Group = SessionLog
    +  TerminalOutput = On | Off
    +  FileOutput = On | Off
    +  FileName = print.prt
    +  FileAccess = Append | Overwrite
    +EndGroup
    +
    +

    + +

    Format

    +

    +The output format for session logs is the Parameter Value Language. An example log file for a program would be as follows: + +

    +Object = Highpass
    +  IsisVersion        = 3.0
    +  ProgramVersionDate = 2003-05-16
    +  ExecutionDateTime  = 2003-06-25T12:18:45
    +  ComputerName       = char
    +  UserName           = janderso
    +  ProgramDescription = "Apply a high pass filter to a cube"
    +
    +  Group = UserParameters
    +    From      = input.cub
    +    To        = output.cub
    +    Samples   = 5
    +    Lines     = 5
    +    Low       = "Use all pixels" 
    +    High      = "Use all pixels"
    +    Minimum   = 0
    +    Propagate = True
    +  EndGroup
    +
    +  Group = Results
    +    PixelsChanged  = 1024000
    +    PercentChanged = 100.0
    +  EndGroup
    +
    +  Group = Accounting
    +    ConnectTime  = 0:00:05.2
    +    CpuTime      = 0:00:04.1
    +    DirectIO     = 0
    +    PageFaults   = 2673
    +    ProcessSwaps = 0
    +  EndGroup
    +EndObject
    +
    +

    + +

    +If an error occurred during the processing the file may look like, + +

    +Object = Highpass
    +  IsisVersion        = 3.0
    +  ProgramVersionDate = 2003-05-16
    +  ExecutionDateTime  = 2003-06-25T12:18:45
    +  ComputerName       = char
    +  UserName           = janderso
    +  ProgramDescription = "Apply a high pass filter to a cube"
    +
    +  Group = UserParameters
    +    From      = moon.cub
    +    To        = output.cub
    +    Samples   = 5
    +    Lines     = 5
    +    Low       = "Use all pixels" 
    +    High      = "Use all pixels"
    +    Minimum   = 0
    +    Propagate = True
    +  EndGroup
    +
    +  Group = Error
    +    Program = Highpass
    +    Class   = "I/O ERROR"
    +    Code    = -3
    +    Message = "Unable to open cube [moon.cub]"
    +    Source  = IsisCube.cpp
    +    Line    = 203
    +  EndGroup
    +EndObject
    +
    +

    + +

    Controlling Terminal Output

    +

    +One method of session logging is writing the information to STDOUT , that is, the terminal. This can be turned on or off with user preferences: + +

    +Group = SessionLog
    +  TerminalOutput = On | Off
    +EndGroup
    +
    +

    + +

    +The user can utilize standard Unix constructs to redirect the output if desired. For example, + +

    +stats from=moon.cub > stats.log
    +
    + +

    + + +

    Controlling File Output

    +

    +Another method of session logging is writing information to a file. Again control of this mechanism is through the user preferences: + +

    +Group = SessionLog
    +  FileOutput = On | Off
    +  FileName = print.prt
    +  FileAccess = Append | Overwrite
    +EndGroup
    +
    +

    + + + HTML + + SessionLogs.html + +
    +
    + + guide + + + intermediate + + + Session Logs + Guide to understanding, controlling, and reading Session Logs + Guide to understanding, controlling, and reading Session Logs, a mechanism for users to keep track of work that they have done + Jeff Anderson + 2003-06-25 + +
    diff --git a/isis/src/docsys/documents/SystemArchitecture/SystemArchitecture.xml b/isis/src/docsys/documents/SystemArchitecture/SystemArchitecture.xml new file mode 100644 index 0000000000000000000000000000000000000000..8f7e3baaed84c4d5ff353b8947f2fc63e70be06d --- /dev/null +++ b/isis/src/docsys/documents/SystemArchitecture/SystemArchitecture.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + HTML + + SystemArchitecture.html + + + + + guide + + + user + + + System Architecture + An indepth "get started" tour of Isis, including history, mechanics, and basic use. + Take an indepth "get started" tour of Isis, from the software's history to an overview of the newest features. Learn the basics of working in the Isis software environment. + Jeff Anderson + 2003-06-25 + + diff --git a/isis/src/docsys/documents/UserRights/UserRights.xml b/isis/src/docsys/documents/UserRights/UserRights.xml new file mode 100644 index 0000000000000000000000000000000000000000..4d347daddf08350ab87fa064045e5116a0d6c091 --- /dev/null +++ b/isis/src/docsys/documents/UserRights/UserRights.xml @@ -0,0 +1,97 @@ + + + + + +

    + Software and related material (data and (or) documentation), + contained in or furnished in connection with a software + distribution, are made available by the U.S. Geological + Survey (USGS) to be used in the public interest and in the + advancement of science. You may, without any fee or cost, use, + copy, modify, or distribute this software, and any derivative + works thereof, and its supporting documentation, subject + to the following restrictions and understandings. +

    + +

    + If you distribute copies or modifications of the + software and related material, make sure the recipients + receive a copy of this notice and receive or can get a copy + of the original distribution. If the software and (or) related + material are modified and distributed, it must be made clear + that the recipients do not have the original and they must be + informed of the extent of the modifications. For example, + modified files must include a prominent notice stating + the modifications made, the author of the modifications, + and the date the modifications were made. This restriction + is necessary to guard against problems introduced in the + software by others, reflecting negatively on the reputation + of the USGS. +

    + +

    + The software is public property and you therefore have the + right to the source code, if desired. You may charge fees + for distribution, warranties, and services provided in + connection with the software or derivative works thereof. The + name USGS can be used in any advertising or publicity to + endorse or promote any products or commercial entity + using this software if specific written permission is + obtained from the USGS. +

    + +

    + The user agrees to appropriately acknowledge the authors + and the USGS in publications that result from the use of + this software or in products that include this software in + whole or in part. +

    + +

    + Because the software and related material are free + (other than nominal materials and handling fees) and + provided "as is," the authors, the USGS, and the + United States Government have made no warranty, express or + implied, as to accuracy or completeness and are not + obligated to provide the user with any support, consulting, + training or assistance of any kind with regard to the use, + operation, and performance of this software nor to + provide the user with any updates, revisions, new versions + or "bug fixes." +

    + +

    + The user assumes all risk for any damages whatsoever + resulting from loss of use, data, or profits arising in + connection with the access, use, quality, or performance + of this software. +

    + + + HTML + + + UserRights.html + +
    +
    + + + about + + + + all + + + + User Rights Notice + Licensing, copyright, distribution, and warranty information + + User Rights Notice + + Jeff Anderson + 2003-04-03 + +
    diff --git a/isis/src/docsys/originals/assets/banners/banner.psd b/isis/src/docsys/originals/assets/banners/banner.psd new file mode 100755 index 0000000000000000000000000000000000000000..c7e407fb2e1f80287e056fee072e3c026c38c99d Binary files /dev/null and b/isis/src/docsys/originals/assets/banners/banner.psd differ diff --git a/isis/src/docsys/originals/assets/banners/banner2.psd b/isis/src/docsys/originals/assets/banners/banner2.psd new file mode 100755 index 0000000000000000000000000000000000000000..80ea1d90b4062eac345e93d905b76415852d6ecd Binary files /dev/null and b/isis/src/docsys/originals/assets/banners/banner2.psd differ diff --git a/isis/src/docsys/originals/assets/banners/banner3.psd b/isis/src/docsys/originals/assets/banners/banner3.psd new file mode 100755 index 0000000000000000000000000000000000000000..2e7e8f555ec74bcf41319451a1b544cfd6d071ba Binary files /dev/null and b/isis/src/docsys/originals/assets/banners/banner3.psd differ diff --git a/isis/src/docsys/originals/assets/banners/banner4.psd b/isis/src/docsys/originals/assets/banners/banner4.psd new file mode 100755 index 0000000000000000000000000000000000000000..085f37444da0b8cafb8f803fe2625fd8457334fa Binary files /dev/null and b/isis/src/docsys/originals/assets/banners/banner4.psd differ diff --git a/isis/src/docsys/originals/assets/banners/isis_bg_texture.jpg b/isis/src/docsys/originals/assets/banners/isis_bg_texture.jpg new file mode 100755 index 0000000000000000000000000000000000000000..0844e5c8f88c872a9e6e06f24e60465f07e06db3 Binary files /dev/null and b/isis/src/docsys/originals/assets/banners/isis_bg_texture.jpg differ diff --git a/isis/src/docsys/originals/assets/banners/isis_wallpaper.psd b/isis/src/docsys/originals/assets/banners/isis_wallpaper.psd new file mode 100755 index 0000000000000000000000000000000000000000..aa2f66d889b390f650569e4b2585c013fda774e6 Binary files /dev/null and b/isis/src/docsys/originals/assets/banners/isis_wallpaper.psd differ diff --git a/isis/src/docsys/w3c/p3p.xml b/isis/src/docsys/w3c/p3p.xml new file mode 100644 index 0000000000000000000000000000000000000000..618d18be8f35f3421247baa860d379d3e1b11cb3 --- /dev/null +++ b/isis/src/docsys/w3c/p3p.xml @@ -0,0 +1,13 @@ + + + + /IsisSupport + + + + /* + /IsisSupport + + + + diff --git a/isis/src/galileo/Makefile b/isis/src/galileo/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/galileo/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/galileo/apps/Makefile b/isis/src/galileo/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/galileo/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/galileo/apps/gllssi2isis/Makefile b/isis/src/galileo/apps/gllssi2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/galileo/apps/gllssi2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/galileo/apps/gllssi2isis/assets/images/gllssi2isisGuiAuto.jpg b/isis/src/galileo/apps/gllssi2isis/assets/images/gllssi2isisGuiAuto.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2eaac4a382c79d6e8fbc7a0eb364709b85761ba Binary files /dev/null and b/isis/src/galileo/apps/gllssi2isis/assets/images/gllssi2isisGuiAuto.jpg differ diff --git a/isis/src/galileo/apps/gllssi2isis/assets/images/gllssi2isisOutputAuto.jpg b/isis/src/galileo/apps/gllssi2isis/assets/images/gllssi2isisOutputAuto.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7fd6f0f4bc30d0470571ff47f3fc6b05e797555a Binary files /dev/null and b/isis/src/galileo/apps/gllssi2isis/assets/images/gllssi2isisOutputAuto.jpg differ diff --git a/isis/src/galileo/apps/gllssi2isis/assets/inputLabelEx1.txt b/isis/src/galileo/apps/gllssi2isis/assets/inputLabelEx1.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad42af9c0a42fd4e97ef162e25dd880433ca6e86 --- /dev/null +++ b/isis/src/galileo/apps/gllssi2isis/assets/inputLabelEx1.txt @@ -0,0 +1,169 @@ +CCSD3ZF0000100000001NJPL3IF0PDS200000001 = SFDU_LABEL + +/* File Format and Length */ +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 1000 +FILE_RECORDS = 813 + +/* Pointers to Data Objects */ +^IMAGE_HEADER = ("0826R.IMG",1) +^TELEMETRY_TABLE = ("0826R.IMG",3) +^BAD_DATA_VALUES_HEADER = ("0826R.IMG",5) +^IMAGE = ("0826R.IMG",14) +^LINE_PREFIX_TABLE = ("0826R.IMG",14) + +/* Description/Catalog Keywords */ +DATA_SET_ID = "GO-J/JSA-SSI-2-REDR-V1.0" +SPACECRAFT_NAME = "GALILEO ORBITER" +INSTRUMENT_NAME = "SOLID STATE IMAGING SYSTEM" + +/* Time tags and observation descriptors */ +SPACECRAFT_CLOCK_CNT_PARTITION = 1 +SPACECRAFT_CLOCK_START_COUNT = "03836008.26" +IMAGE_TIME = 1997-02-19T21:07:27.314Z +IMAGE_ID = E6I0032 +ORBIT_NUMBER = 6 +OBSERVATION_ID = "E6ISSRFMON01" +TARGET_NAME = "IO" +NTV_TIME_FROM_CLOSEST_APPROACH = "-000T23:47:33Z" +NTV_SAT_TIME_FROM_CLOSEST_APRH = "-000T14:56:32Z" +NOTE = "NOT APPLICABLE" + +/* Camera and spacecraft state parameters */ +FILTER_NAME = "VIOLET" +FILTER_NUMBER = 3 +EXPOSURE_DURATION = 195.83 +GAIN_MODE_ID = "100K" +FRAME_DURATION = 8.667 +LIGHT_FLOOD_STATE_FLAG = "ON" +EXPOSURE_TYPE = "NORMAL" +BLEMISH_PROTECTION_FLAG = "OFF" +INVERTED_CLOCK_STATE_FLAG = "NOT INVERTED" +ON_CHIP_MOSAIC_FLAG = "Y" +COMPRESSION_TYPE = "INTEGER COSINE TRANSFORM" +ENTROPY = 2.879 +TELEMETRY_FORMAT_ID = "IM8" +OBSTRUCTION_ID = "NOT POSSIBLE" +INSTRUMENT_MODE_ID = "N/A" + +/* Viewing Geometry */ +/* Note: These viewing geometry parameters are best estimates */ +/* at the time this picture label was generated. */ +POSITIVE_LONGITUDE_DIRECTION = WEST + +/* Spacecraft Geometry */ +TARGET_CENTER_DISTANCE = 1.073668e+06 +CENTRAL_BODY_DISTANCE = 1.181189e+06 +SUB_SPACECRAFT_LATITUDE = -0.352 +SUB_SPACECRAFT_LONGITUDE = 94.985 +SUB_SPACECRAFT_LINE = 208.036 +SUB_SPACECRAFT_LINE_SAMPLE = 618.951 +SUB_SPACECRAFT_AZIMUTH = 138.758 + +/* Camera and Lighting Geometry */ +/* Resolution of HORIZONTAL_PIXEL_SCALE, */ +/* VERTICAL_PIXEL_SCALE, and SLANT_DISTANCE */ +/* is calculated from the light source values in */ +/* INTERCEPT_POINT_LATITUDE, INTERCEPT_POINT_LONGITUDE,*/ +/* INTERCEPT_POINT_LINE and INTERCEPT_POINT_LINE_SAMPLE keywords */ +/* If the target is a Ring keyword RING_RADIUS */ +/* is substituted for INTERCEPT_POINT_LATITUDE */ +/* If the TARGET_NAME = J RINGS, viewing geometry was */ +/* calculated using Jupiter as the target. */ +TWIST_ANGLE = 91.629 +CONE_ANGLE = 143.115 +RIGHT_ASCENSION = 271.728 +DECLINATION = -25.015 +NORTH_AZIMUTH = 89.938 +SMEAR_AZIMUTH = "UNK" +SMEAR_MAGNITUDE = "UNK" +HORIZONTAL_PIXEL_SCALE = 1.088200e+04 +VERTICAL_PIXEL_SCALE = 1.088240e+04 +SLANT_DISTANCE = 1.071840e+06 +SOLAR_DISTANCE = 7.660860e+08 +SUB_SOLAR_LATITUDE = -0.830 +SUB_SOLAR_LONGITUDE = 64.399 +SUB_SOLAR_AZIMUTH = 180.964 +INCIDENCE_ANGLE = 30.588 +EMISSION_ANGLE = 0.006 +PHASE_ANGLE = 30.588 +LOCAL_HOUR_ANGLE = 149.414 +INTERCEPT_POINT_LATITUDE = -0.352 +INTERCEPT_POINT_LONGITUDE = 94.985 +INTERCEPT_POINT_LINE = 208.0 +INTERCEPT_POINT_LINE_SAMPLE = 619.0 + +/* Target radii */ +A_AXIS_RADIUS = 1.830000e+03 +B_AXIS_RADIUS = 1.818700e+03 +C_AXIS_RADIUS = 1.815300e+03 + +/* Processing parameters */ +MEAN_RADIANCE = "N/A" +MEAN_REFLECTANCE = "N/A" +REFLECTANCE_SCALING_FACTOR = "N/A" +RADIANCE_SCALING_FACTOR = "N/A" +UNEVEN_BIT_WEIGHT_CORR_FLAG = "N/A" +DARK_CURRENT_FILE_NAME = "N/A" +SLOPE_FILE_NAME = "N/A" +BLEMISH_FILE_NAME = "N/A" +SHUTTER_OFFSET_FILE_NAME = "N/A" +DATA_TYPE = LSB_UNSIGNED_INTEGER +SOURCE_PRODUCT_ID = {"S980127A.BSP","S980127A.BSP","N/A","CKE06APE.PLT","NULL" +} +PROCESSING_HISTORY_TEXT = "VICAR programs run: SSIMERGE,UNMOSAIC,CATLABEL,BADL +ABELS." +PRODUCT_TYPE = "REDR" + + +/* ICT or Lossless compression */ +ENCODING_COMPRESSION_RATIO = 8.870 +ENCODING_MIN_COMPRESSION_RATIO = 5.748 +ENCODING_MAX_COMPRESSION_RATIO = 72.831 +HUFFMAN_TABLE_TYPE = "SKEWED" +ICT_DESPIKE_THRESHOLD = 30 +CUT_OUT_WINDOW = {1,389,400,410} +TRUTH_WINDOW = {801,801,96,96} +PRODUCT_VERSION_ID = 0 +ICT_QUANTIZATION_STEP_SIZE = 5 +ICT_ZIGZAG_PATTERN = "ZIGZAG" +CMPRS_QUANTZ_TBL_ID = "UNIFORM" + +/* VICAR IMAGE HEADER Object */ +OBJECT = IMAGE_HEADER +INTERCHANGE_FORMAT = BINARY +HEADER_TYPE = VICAR2 +BYTES = 2000 +RECORDS = 2 +^DESCRIPTION = "VICAR2.TXT" +END_OBJECT + +/* Table Object (for telemetry table) */ +OBJECT = TELEMETRY_TABLE +INTERCHANGE_FORMAT = BINARY +ROWS = 1 +COLUMNS = 86 +ROW_BYTES = 1800 +^STRUCTURE = "RTLMTAB.FMT" +END_OBJECT + +/* Bad Data Value Header Object */ +OBJECT = BAD_DATA_VALUES_HEADER +HEADER_TYPE = BDV +INTERCHANGE_FORMAT = BINARY +BYTES = 9000 +RECORDS = 9 +^DESCRIPTION = "BADDATA.TXT" +END_OBJECT + +/* Image Object */ +OBJECT = IMAGE +LINES = 800 +LINE_SAMPLES = 800 +SAMPLE_BITS = 8 +SAMPLE_TYPE = UNSIGNED_INTEGER +INVALID_CONSTANT = "N/A" +LINE_PREFIX_BYTES = 200 +^LINE_PREFIX_STRUCTURE = "RLINEPRX.FMT" +END_OBJECT +END diff --git a/isis/src/galileo/apps/gllssi2isis/assets/thumbs/gllssi2isisGuiAutoThumb.jpg b/isis/src/galileo/apps/gllssi2isis/assets/thumbs/gllssi2isisGuiAutoThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9a82fd8af19218fd88783ca6c47a1609be4c7ff7 Binary files /dev/null and b/isis/src/galileo/apps/gllssi2isis/assets/thumbs/gllssi2isisGuiAutoThumb.jpg differ diff --git a/isis/src/galileo/apps/gllssi2isis/assets/thumbs/gllssi2isisOutputAutoThumb.jpg b/isis/src/galileo/apps/gllssi2isis/assets/thumbs/gllssi2isisOutputAutoThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b88367a9ba0694c549c19646136108901f5072e4 Binary files /dev/null and b/isis/src/galileo/apps/gllssi2isis/assets/thumbs/gllssi2isisOutputAutoThumb.jpg differ diff --git a/isis/src/galileo/apps/gllssi2isis/gllssi2isis.cpp b/isis/src/galileo/apps/gllssi2isis/gllssi2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d123126ffb8ff7016a132c1ec6c5a6d0fee7159 --- /dev/null +++ b/isis/src/galileo/apps/gllssi2isis/gllssi2isis.cpp @@ -0,0 +1,210 @@ +#include "Isis.h" + +#include +#include + +#include "ProcessImportPds.h" + +#include "UserInterface.h" +#include "CubeAttribute.h" +#include "Filename.h" +#include "iException.h" +#include "iTime.h" + +using namespace std; +using namespace Isis; +bool summed; + +Cube *summedOutput; + +void TranslateData(Buffer &inData); +void TranslateLabels (Pvl &pdsLabel, Cube *ocube); + +void IsisMain (){ + + //initialize globals + summed = false; + summedOutput = NULL; + // Grab the file to import + ProcessImportPds p; + UserInterface &ui = Application::GetUserInterface(); + Filename inFile = ui.GetFilename("FROM"); + Filename out = ui.GetFilename("TO"); + + // Make sure it is a Galileo SSI image + Pvl lab(inFile.Expanded()); + + //Checks if in file is rdr + if( lab.HasObject("IMAGE_MAP_PROJECTION") ) { + string msg = "[" + inFile.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + // data set id value must contain "SSI-2-REDR-V1.0"(valid SSI image) + // or "SSI-4-REDR-V1.0"(reconstructed from garbled SSI image) + string dataSetId; + dataSetId = (string)lab["DATA_SET_ID"]; + try { + if (dataSetId.find("SSI-2-REDR-V1.0") == string::npos + && dataSetId.find("SSI-4-REDR-V1.0") == string::npos) { + string msg = "Invalid DATA_SET_ID [" + dataSetId + "]"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + } + catch (iException &e) { + string msg = "Unable to read [DATA_SET_ID] from input file [" + + inFile.Expanded() + "]"; + throw iException::Message(iException::Io,msg,_FILEINFO_); + } + + // set summing mode + if(ui.GetString("FRAMEMODE") == "AUTO") { + double frameDuration = lab["FRAME_DURATION"]; + // reconstructed images are 800x800 (i.e. not summed) + // even though they have frame duration of 2.333 + // (which ordinarily indicates a summed image) + if (dataSetId.find("SSI-4-REDR-V1.0") != string::npos) { + summed = false; + } + else if (frameDuration > 2.0 && frameDuration < 3.0) { + summed = true; + } + // seti documentation implies valid frame duration values are 2.333, 8.667, 30.333, 60.667 + // however some images have value 15.166 (see example 3700R.LBL) + else if (frameDuration > 15.0 && frameDuration < 16.0) { + summed = true; + } + } + else if(ui.GetString("FRAMEMODE") == "SUMMED") { + summed = true; + } + else { + summed = false; + } + + Progress prog; + Pvl pdsLabel; + p.SetPdsFile(inFile.Expanded(),"",pdsLabel); + + //Set up the output file + Cube *ocube; + + if(!summed) { + ocube = p.SetOutputCube("TO"); + p.StartProcess(); + } + else { + summedOutput = new Cube(); + summedOutput->SetDimensions(p.Samples()/2, p.Lines()/2, p.Bands()); + summedOutput->SetPixelType(p.PixelType()); + summedOutput->Create(ui.GetFilename("TO")); + p.StartProcess(TranslateData); + ocube = summedOutput; + } + + TranslateLabels(pdsLabel, ocube); + p.EndProcess (); + + if(summed) { + summedOutput->Close(); + delete summedOutput; + } + + return; +} + +void TranslateData(Buffer &inData) { + summedOutput->Write(inData); +} + +void TranslateLabels(Pvl &pdsLabel, Cube *ocube) { + // Get the directory where the MOC translation tables are. + PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory"); + + // Transfer the instrument group to the output cube + iString transDir = (string) dataDir["Galileo"]; + Filename transFile (transDir + "/translations/galileoSsi.trn"); + + // Get the translation manager ready + PvlTranslationManager labelXlater (pdsLabel, transFile.Expanded()); + // Pvl outputLabels; + Pvl *outputLabel = ocube->Label(); + labelXlater.Auto(*(outputLabel)); + + //Add to the Archive Group + PvlGroup &arch = outputLabel->FindGroup("Archive",Pvl::Traverse); + PvlGroup &inst = outputLabel->FindGroup("Instrument",Pvl::Traverse); + arch.AddKeyword(PvlKeyword("DataType","RADIANCE")); + string CTC = (string) arch.FindKeyword("ObservationId"); + string CTCout = CTC.substr(0,2); + arch.AddKeyword(PvlKeyword("CalTargetCode",CTCout)); + + // Add to the Instrument Group + iString itest =(string) inst.FindKeyword("StartTime"); + itest.Remove("Z"); + inst.FindKeyword("StartTime").SetValue(itest); + //change exposure duration to seconds + double expDur = inst.FindKeyword("exposureDuration"); + double expDurOut = expDur / 1000.0; + inst.FindKeyword("exposureDuration").SetValue(expDurOut,"seconds"); + inst.AddKeyword(PvlKeyword("FrameDuration", + (string) pdsLabel["frameDuration"],"seconds")); + + //Calculate the Frame_Rate_Id keyword + string frameModeId = "FULL"; + int summingMode = 1; + + if(summed) { + frameModeId = "SUMMATION"; + summingMode = 2; + } + + inst.AddKeyword(PvlKeyword("Summing",summingMode)); + inst.AddKeyword(PvlKeyword("FrameModeId",frameModeId)); + + // Create the Band bin Group + PvlGroup &bandBin = outputLabel->FindGroup("BandBin",Pvl::Traverse); + string filterName = pdsLabel["FILTER_NAME"]; + string waveLength = ""; + string width = ""; + if (filterName == "CLEAR") { + waveLength = "0.611"; + width = ".44"; + } + if (filterName == "VIOLET") { + waveLength = "0.404"; + width = ".05"; + } + if (filterName == "GREEN") { + waveLength = "0.559"; + width = ".06"; + } + if (filterName == "RED") { + waveLength = "0.671"; + width = ".06"; + } + if (filterName == "IR-7270") { + waveLength = "0.734"; + width = ".01"; + } + if (filterName == "IR-7560") { + waveLength = "0.756"; + width = ".018"; + } + if (filterName == "IR-8890") { + waveLength = "0.887"; + width = ".116"; + } + if (filterName == "INFRARED") { + waveLength = "0.986"; + width = ".04"; + } + bandBin.AddKeyword(PvlKeyword("Center",waveLength, "micrometers")); + bandBin.AddKeyword(PvlKeyword("Width",width,"micrometers")); + + //create the kernel group + PvlGroup kern("Kernels"); + kern += PvlKeyword("NaifFrameCode",-77001); + ocube->PutGroup(kern); +} diff --git a/isis/src/galileo/apps/gllssi2isis/gllssi2isis.xml b/isis/src/galileo/apps/gllssi2isis/gllssi2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..20f2f368f8792c7f47db136f54bafa9755876abe --- /dev/null +++ b/isis/src/galileo/apps/gllssi2isis/gllssi2isis.xml @@ -0,0 +1,215 @@ + + + + + + Import a Galileo solid state imager (SSI) image EDR into Isis cube format + + + + Converts a PDS formatted Galileo solid state imager (SSI) image EDR + into an Isis Cube. The required instrument labels will be propagated + into the instrument group. The user must choose an input image label, + output cube name, and frame mode, or summing mode. Galileo SSI images have + a summing mode of FULL (800 x 800 pixels) or SUMMED (400 x 400 pixels). +

    + Note: For the I24 encounter (found in volume go_0022), + many Galileo SSI images of Io were originally "garbled". These images + were reconstructed and released with the filename ####s where ####r is the + name of the original garbled file and #### is the last four digits of the + SPACECRAFT_CLOCK_START_COUNT. These images will have Most of the original + images were 400 x 400 (i.e. SUMMED). However, the reconstructed files are + 800 x 800 and must be imported as FULL to get the entire image. If the + user imports a reconstructed image with FRAMEMODE = AUTO, it will be + treated as a FULL image, even if the original was SUMMED. +

    +
    + + + + Original version + + + Converted to Isis 3.0 + + + Added Summing Keyword. Moved most hardcoded translations into a + translation table. Modified tests to check the lables. Removed ImageID + keyword. + + + Removed the hard coded Instrument Mode ID keyword translation. + + + Added summing options. Output summed images will now only be a quarter of + the size for calibration (the upper-left data in the input is preserved). + + + Checks if input file is rdr. + + + Removed references to CubeInfo. + + + Added valid DATA_SET_ID value for reconstructed images (i.e. value + contains "SSI-4-REDR-V1.0"). Modified code to set as FULL summing + mode if FRAMEMODE=AUTO and the image is reconstructed. + + + + + Galileo + + + + + + + Planetary Science Data Dictionary Document + + + + PSDDmain_1r71.pdf + + + http://pds.jpl.nasa.gov/documents/psdd/ + + + + Jet Propulsion Laboratory + + + California Institute of Technology + + + + + + + + + filename + input + + Input PDS Galileo SSI file + + + Use this parameter to select the PDS filename. This file must + contain the PDS labels, however the image data can be detached + and will be automatically obtained from the PDS image pointer keyword. + + + *.lbl *.LBL + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + + + string + Summing mode of the input image + Summing mode of the input image. The user + may specify the summing mode or choose to allow the program to + determine this. + + AUTO + + + + + + + + + + + + Cube imported with defaults + + This example shows how to import Galileo SSI image to ISIS 3. + + + + from=../IN/input.lbl to=../OUT/output.cub + + + Run the gllssi2isis application with defaults + + + + + + + Example GUI + + + Screenshot of GUI with parameters filled in to perform the + gllssi2isis application. Input label and output cubes are always + required. The FRAMEMODE radio button AUTO is chosen as default. + + + + + + + + + Input label + + + Copy of the labels of the input image + + + FROM + + + + + + + Output image + + + Output image after gllssi2isis has imported it to ISIS3. + + + + TO + + + + + +
    diff --git a/isis/src/galileo/apps/gllssi2isis/tsts/Makefile b/isis/src/galileo/apps/gllssi2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/galileo/apps/gllssi2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/galileo/apps/gllssi2isis/tsts/case01/Makefile b/isis/src/galileo/apps/gllssi2isis/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..311830453093f03803d593c11e02f2dc89f54d56 --- /dev/null +++ b/isis/src/galileo/apps/gllssi2isis/tsts/case01/Makefile @@ -0,0 +1,10 @@ +APPNAME = gllssi2isis + +labels.txt.IGNORELINES = Bytes StartByte ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/0826r.lbl \ + to=$(OUTPUT)/gllssi2isisTruth1.cub > /dev/null; + catlab from=$(OUTPUT)/gllssi2isisTruth1.cub >& $(OUTPUT)/labels.txt; diff --git a/isis/src/galileo/apps/gllssi2isis/tsts/case02/Makefile b/isis/src/galileo/apps/gllssi2isis/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..32470f45cdf27a78186eaade2d1e5e1b7641b30d --- /dev/null +++ b/isis/src/galileo/apps/gllssi2isis/tsts/case02/Makefile @@ -0,0 +1,10 @@ +APPNAME = gllssi2isis + +labels.txt.IGNORELINES = Bytes StartByte ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/1213r.lbl \ + to=$(OUTPUT)/gllssi2isisTruth2.cub > /dev/null; + catlab from=$(OUTPUT)/gllssi2isisTruth2.cub >& $(OUTPUT)/labels.txt; diff --git a/isis/src/galileo/apps/gllssi2isis/tsts/case03/Makefile b/isis/src/galileo/apps/gllssi2isis/tsts/case03/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..031845e9f937a30af9f0340dd94158601b695510 --- /dev/null +++ b/isis/src/galileo/apps/gllssi2isis/tsts/case03/Makefile @@ -0,0 +1,10 @@ +APPNAME = gllssi2isis + +labels.txt.IGNORELINES = Bytes StartByte ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/3700R.LBL \ + TO=$(OUTPUT)/3700R.cub > /dev/null; + catlab FROM=$(OUTPUT)/3700R.cub > $(OUTPUT)/3700R.txt; diff --git a/isis/src/galileo/apps/gllssi2isis/tsts/case04/Makefile b/isis/src/galileo/apps/gllssi2isis/tsts/case04/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..350a28eaf353d81263beafa681dc5f339a494e49 --- /dev/null +++ b/isis/src/galileo/apps/gllssi2isis/tsts/case04/Makefile @@ -0,0 +1,10 @@ +APPNAME = gllssi2isis + +7500r.txt.IGNORELINES = Bytes StartByte ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/7500r.lbl \ + TO=$(OUTPUT)/7500r.cub > /dev/null; + catlab FROM=$(OUTPUT)/7500r.cub > $(OUTPUT)/7500r.txt; diff --git a/isis/src/galileo/apps/gllssi2isis/tsts/go_0022_I24_IO_repairedImage/Makefile b/isis/src/galileo/apps/gllssi2isis/tsts/go_0022_I24_IO_repairedImage/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..866591a1e4d6c7975b3b0e72134c848d6e3f46f1 --- /dev/null +++ b/isis/src/galileo/apps/gllssi2isis/tsts/go_0022_I24_IO_repairedImage/Makefile @@ -0,0 +1,10 @@ +APPNAME = gllssi2isis + +labels.txt.IGNORELINES = Bytes StartByte ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/8500s.lbl \ + to=$(OUTPUT)/8500s.cub > /dev/null; + catlab from=$(OUTPUT)/8500s.cub >& $(OUTPUT)/labels.txt; diff --git a/isis/src/galileo/apps/gllssical/Makefile b/isis/src/galileo/apps/gllssical/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/galileo/apps/gllssical/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/galileo/apps/gllssical/gllssical.cpp b/isis/src/galileo/apps/gllssical/gllssical.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f45d25ee870e86132c478a1067dd6c15315336a --- /dev/null +++ b/isis/src/galileo/apps/gllssical/gllssical.cpp @@ -0,0 +1,428 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "Buffer.h" +#include "SpecialPixel.h" +#include "TextFile.h" +#include "Camera.h" + +using namespace Isis; +using namespace std; + +/** + * Shutter file: + * The shutter on the galileo SSI camera took from + * about 1ms at the top of the camera to about 1.5ms + * at the bottom due to friction. The shutter offset file in + * isis 2 is rotated 90 degrees. + * + * Some of the values and equations in the program were verified + * using the book "In Orbit at Jupiter, Contributions of the Galileo + * Science Team," Section H Part I. + */ + +vector weight; +double scaleFactor0; +double a2; +double dcScaleFactor; +double exposureDuration; +double picScale; + +void Calibrate1(vector &in, vector &out); +void Calibrate2(vector &in, vector &out); +Filename FindDarkFile(Cube *icube); +Filename FindGainFile(Cube *icube); +Filename FindShutterFile(Cube *icube); +Filename ReadWeightTable(Cube *icube); +Filename GetScaleFactorFile(); +int getGainModeID(Cube *icube); +void calculateScaleFactor(Cube *icube, Cube *gaincube); + +void IsisMain() { + // Initialize Globals + UserInterface &ui = Application::GetUserInterface(); + weight.clear(); + scaleFactor0 = 0.0; + dcScaleFactor = 0.0; + exposureDuration = 0.0; + a2 = 0.0; + picScale = 0.0; + + // Set up our ProcessByLine + ProcessByLine p; + Cube *icube = p.SetInputCube("FROM"); + std::cout << "Dark File: " << FindDarkFile(icube).Expanded() << std::endl; + std::cout << "Gain File: " << FindGainFile(icube).Expanded() << std::endl; + std::cout << "Shutter File: " << FindShutterFile(icube).Expanded() << std::endl; + + Isis::CubeAttributeInput inAtt1; + Filename darkFilename = FindDarkFile(icube); + Cube *darkcube = p.SetInputCube(darkFilename.Expanded(), inAtt1); + picScale = darkcube->GetGroup("Instrument")["PicScale"][0]; + + Isis::CubeAttributeInput inAtt2; + Filename gainFilename = FindGainFile(icube); + Cube *gaincube = p.SetInputCube(gainFilename.Expanded(), inAtt2); + + Isis::CubeAttributeInput inAtt3; + p.SetInputCube(FindShutterFile(icube).Expanded(), inAtt3, Isis::AllMatchOrOne); + + Cube *ocube = p.SetOutputCube("TO"); + + if(ui.GetBoolean("BITWEIGHTING")) { + ReadWeightTable(icube); + } + else { + for(int i = 0; i < 256; i++) { + weight.push_back(i); + } + } + + calculateScaleFactor(icube, gaincube); + + exposureDuration = ((double)icube->GetGroup("Instrument")["ExposureDuration"][0]) * 1000; + + if(darkcube->PixelType() == Isis::UnsignedByte) { + p.StartProcess(Calibrate1); + } + else { + p.StartProcess(Calibrate2); + } + + PvlGroup calibrationLog("RadiometricCalibration"); + calibrationLog.AddKeyword(PvlKeyword("From", (std::string)ui.GetFilename("FROM"))); + + Filename shutterFilename = FindShutterFile(icube); + calibrationLog.AddKeyword(PvlKeyword("DarkCurrentFile", darkFilename.OriginalPath() + "/" + darkFilename.Name())); + calibrationLog.AddKeyword(PvlKeyword("GainFile", gainFilename.OriginalPath() + "/" + gainFilename.Name())); + calibrationLog.AddKeyword(PvlKeyword("ShutterFile", shutterFilename.OriginalPath() + "/" + shutterFilename.Name())); + + ocube->PutGroup(calibrationLog); + Application::Log(calibrationLog); + p.EndProcess(); +} + +void Calibrate1(vector &in, vector &out) { + Buffer &inputFile = *in[0]; + Buffer &darkFile = *in[1]; + Buffer &gainFile = *in[2]; + Buffer &shutterFile = *in[3]; + Buffer &outputFile = *out[0]; + + double scaleFactor = scaleFactor0 / (exposureDuration - shutterFile[0]); + + for (int samp = 0; samp < inputFile.size(); samp++) { + if(IsSpecial(inputFile[samp])) { + outputFile[samp] = inputFile[samp]; + continue; + } + + if(IsSpecial(darkFile[samp]) || IsSpecial(gainFile[samp]) || IsSpecial(shutterFile[samp])) { + outputFile[samp] = Isis::Null; + continue; + } + + double xdn = weight[(unsigned long)(inputFile[samp])]; + double xdc = weight[(unsigned long)(darkFile[samp])]; + double xdo = scaleFactor * gainFile[samp] * (xdn - xdc); + + if(xdo >= 0) { + outputFile[samp] = xdo; + } + else { + outputFile[samp] = Isis::Lrs; + } + } +} + +void Calibrate2(vector &in, vector &out) { + Buffer &inputFile = *in[0]; + Buffer &darkFile = *in[1]; + Buffer &gainFile = *in[2]; + Buffer &shutterFile = *in[3]; + Buffer &outputFile = *out[0]; + + double scaleFactor = scaleFactor0 / (exposureDuration - shutterFile[0]); + + for (int samp = 0; samp < inputFile.size(); samp++) { + if(IsSpecial(inputFile[samp])) { + outputFile[samp] = inputFile[samp]; + continue; + } + + if(IsSpecial(darkFile[samp]) || IsSpecial(gainFile[samp]) || IsSpecial(shutterFile[samp])) { + outputFile[samp] = Isis::Null; + continue; + } + + double xdn = weight[(unsigned long)(inputFile[samp])]; + double xdo = scaleFactor * gainFile[samp] * (xdn - (1.0/picScale)*darkFile[samp]); // weight of dark file DN??? See decal1 + + if(xdo >= 0) { + outputFile[samp] = xdo; + } + else { + outputFile[samp] = Isis::Lrs; + } + } +} + +Filename FindDarkFile(Cube *icube) { + string file = "$galileo/calibration/gll_dc.sav"; + + TextFile darkFile(file); + darkFile.SetComment("C"); + iString data; + + /** + * The dark current table requires the following information to match: + * Mission,Frame Mode ID,Gain State ID,Frame Rate ID,Extended Exposure,Readout Mode,Image Number + * So let's grab the information we need from the image labels first + */ + int gainModeId = getGainModeID(icube); + + int frameRateId = 0; + /** + * Frame rate code + * 1 = 2 1/3 (sec) + * 2 = 8 2/3 + * 3 = 30 1/3 + * 4 = 60 2/3 + * 5 = 15 1/6 + */ + if ((int)(double)icube->GetGroup("Instrument")["FrameDuration"][0] == 2) frameRateId = 1; + if ((int)(double)icube->GetGroup("Instrument")["FrameDuration"][0] == 8) frameRateId = 2; + if ((int)(double)icube->GetGroup("Instrument")["FrameDuration"][0] == 30) frameRateId = 3; + if ((int)(double)icube->GetGroup("Instrument")["FrameDuration"][0] == 60) frameRateId = 4; + if ((int)(double)icube->GetGroup("Instrument")["FrameDuration"][0] == 15) frameRateId = 5; + + int exposureTypeId = (icube->GetGroup("Instrument")["ExposureType"][0] == "NORMAL")? 0 : 1; + + // We have what we need from the image label, now go through the text file that is our table line by line + // looking for a match. + while (darkFile.GetLine(data)) { + data = data.Compress(); + + iString mission = data.Token(" "); + if (mission != "GALILEO") { + continue; + } + + iString frameMode = data.Token(" "); + if (frameMode.at(0) != icube->GetGroup("Instrument")["FrameModeId"][0].at(0)) { + continue; + } + + iString gainState = data.Token(" "); + if ((int)gainState != gainModeId) { + continue; + } + + iString frameRate = data.Token(" "); + if (frameRateId != (int)frameRate) { + continue; + } + + iString tableExposureTypeId = data.Token(" "); + if ((int)tableExposureTypeId != exposureTypeId) { + continue; + } + + iString readout = data.Token(" "); + if (readout.at(0) != icube->GetGroup("Instrument")["ReadoutMode"][0].at(0)) { + continue; + } + + int minImageNum = data.Token(" "); + int maxImageNum = data.Token(" "); + + int imageNumber = (int)((double)icube->GetGroup("Instrument")["SpacecraftClockStartCount"] * 100 + 0.5); + iString telemetry = icube->GetGroup("Instrument")["TelemetryFormat"][0]; + if (imageNumber > 99757701 && imageNumber < 159999999) { + if ((telemetry == "AI8" && (gainState == "1" || gainState == "2")) || + (telemetry == "IM4" && (gainState == "3" || gainState == "4"))) { + imageNumber = 160000001; + } + else { + imageNumber = 1; + } + } + + if (imageNumber < minImageNum || imageNumber > maxImageNum) { + continue; + } + + // By process of elimination, we found the dark current file successfully. Return it. + return Filename(string("$galileo/calibration/darkcurrent/") + data.Token(" ") + string(".cub")); + } + + throw iException::Message(iException::Pvl, "Dark current file could not be determined.", _FILEINFO_); +} + +Filename FindGainFile(Cube *icube) { + string file = "$galileo/calibration/gll_gain.sav"; + + TextFile gainFile(file); + gainFile.SetComment("C"); + iString data; + + int imageNumber = (int)((double)icube->GetGroup("Instrument")["SpacecraftClockStartCount"] * 100 + 0.5); + + while (gainFile.GetLine(data)) { + data = data.Compress(); + + iString mission = data.Token(" "); + if (mission != "GALILEO") { + continue; + } + + /** + * Filter codes + * 0=clear,1=green,2=red,3=violet,4=7560,5=9680,6=7270,7=8890 + */ + iString filter = icube->GetGroup("BandBin")["FilterNumber"][0]; + if (filter != data.Token(" ")) { + continue; + } + + iString frameMode = data.Token(" "); + if (frameMode.at(0) != icube->GetGroup("Instrument")["FrameModeId"][0].at(0)) { + continue; + } + + int minImageNum = data.Token(" "); + int maxImageNum = data.Token(" "); + if (imageNumber < minImageNum || imageNumber > maxImageNum) { + continue; + } + + return Filename(string("$galileo/calibration/gain/") + data.Token(" ") + string(".cub")); + } + + throw iException::Message(iException::Pvl, "Gain file could not be determined.", _FILEINFO_); +} + +Filename ReadWeightTable(Cube *icube) { + string file = "$galileo/calibration/weightTables_v???.sav"; + + Filename weightFile(file); + weightFile.HighestVersion(); + Pvl weightTables(weightFile.Expanded()); + iString group = iString("FrameMode") + (char)icube->GetGroup("Instrument")["FrameModeId"][0].at(0); + PvlGroup &frameGrp = weightTables.FindGroup(group); + iString keyword = iString("GainState") + ((getGainModeID(icube) < 3)? iString("12") : iString("34")); + + for (int i = 0; i < frameGrp[keyword].Size(); i++) { + weight.push_back(frameGrp[keyword][i]); + } + + return weightFile; +} + +int getGainModeID(Cube *icube) { + int gainModeId = 0; + /** + * Gain mode ID code + * 1 = 400,000 + * 2 = 100,000 + * 3 = 40,000 + * 4 = 10,000 + */ + if ((int)(double)icube->GetGroup("Instrument")["GainModeId"][0] == 4E5) { + gainModeId = 1; + } + else if ((int)(double)icube->GetGroup("Instrument")["GainModeId"][0] == 1E5) { + gainModeId = 2; + } + else if ((int)(double)icube->GetGroup("Instrument")["GainModeId"][0] == 4E4) { + gainModeId = 3; + } + else if ((int)(double)icube->GetGroup("Instrument")["GainModeId"][0] == 1E4) { + gainModeId = 4; + } + else { + throw iException::Message(iException::Pvl, + "Invalid value for Gain Mode ID [" + + icube->GetGroup("Instrument")["GainModeId"][0] + + "].", _FILEINFO_); + } + + return gainModeId; +} + +void calculateScaleFactor(Cube *icube, Cube *gaincube) { + Pvl conversionFactors(GetScaleFactorFile().Expanded()); + PvlKeyword fltToRef, fltToRad; + + for(int grp = 0; grp < conversionFactors.Groups(); grp++) { + PvlGroup currGrp = conversionFactors.Group(grp); + + // Match target name + if(currGrp.HasKeyword("TargetName")) { + if(icube->GetGroup("Instrument")["TargetName"][0].find(currGrp["TargetName"][0]) != 0) { + continue; + } + } + + // Match MinimumEncounter + if(currGrp.HasKeyword("MinimumTargetName")) { + try { + if((int)currGrp["MinimumTargetName"] > + (int)(iString)icube->GetGroup("Instrument")["TargetName"][0].substr(0,2)) { + continue; + } + } + catch(iException e) { + e.Clear(); + continue; + } + } + + fltToRef = currGrp["FloatToRef"]; + fltToRad = currGrp["FloatToRad"]; + } + + int filterNumber = (int)icube->GetGroup("BandBin")["FilterNumber"][0]; + + if(fltToRef.Size() == 0) { + throw iException::Message(iException::Pvl, + "Unable to find matching reflectance and radiance values for target [" + + icube->GetGroup("Instrument")["TargetName"][0] + "] in [" + + GetScaleFactorFile().Expanded() + "]", + _FILEINFO_); + } + + double s1 = fltToRef[filterNumber]; + double s2 = fltToRad[filterNumber]; + + Camera *cam = icube->Camera(); + bool camSuccess = cam->SetImage(icube->Samples()/2,icube->Lines()/2); + + if(!camSuccess) { + throw iException::Message(iException::Camera, + "Unable to calculate the Solar Distance on [" + + icube->Filename() + "]", _FILEINFO_); + } + + double rsun = cam->SolarDistance() / 5.2; + + a2 = (s2 / s1) / pow(rsun, 2); + + scaleFactor0 = s1 * ( + (double)conversionFactors["GainRatios"][getGainModeID(icube)] / + (double)conversionFactors["GainRatios"][getGainModeID(gaincube)]) * pow(rsun, 2); +} + +Filename GetScaleFactorFile() { + string file = "$galileo/calibration/conversionFactors_v???.sav"; + Filename scaleFactor(file); + scaleFactor.HighestVersion(); + return scaleFactor; +} + +Filename FindShutterFile(Cube *icube) { + string file = "$galileo/calibration/shutter/calibration.so02"; + file += icube->GetGroup("Instrument")["FrameModeId"][0].at(0); + file += ".cub"; + Filename shutterFile(file); + return shutterFile; +} diff --git a/isis/src/galileo/apps/gllssical/gllssical.xml b/isis/src/galileo/apps/gllssical/gllssical.xml new file mode 100644 index 0000000000000000000000000000000000000000..4a640d6941d110c521ea1be5cd9cbc8d7da2813a --- /dev/null +++ b/isis/src/galileo/apps/gllssical/gllssical.xml @@ -0,0 +1,127 @@ + + + + + Perform Radiometric correction on GALILEO-SSI Imaging + + + + Galileo + + + + This program is used to radiometrically correct flight images using a linear + model of the light-transfer function. This program is specific to the + Galileo SSI camera. + + References: + + 1) D-4264 MIPL Software Structural Design for the Instrument Calibration + of GLL SSI Science Processing. + + 2) K. Klaasen, "Reduction in Number of Unique SSI Calibration Files", + 29 May 1987. + + 3) 625-210,"Galileo SSI Calibration Report Part 1", K. Klaasen, H. + Breneman, November 1, 1988. + + + This program will radiometrically correct the input image, converting the + input DN values to some specified radiometric unit. The program + requires a radiometric file generated from calibration data acquired at + the same filter position as the input image, and a dark-current file + acquired at the same camera gain-state, frame-rate, PNI, and BPM + settings. Also, extended exposure mode frames require an + extended-exposure mode dark-current file. + + This program extracts the filter position, exposure time, and frame-rate + from the label of the input file to determine the required gain file + to use. The file $ISIS3DATA/galileo/calibration/gll_gain.sav defines the + gain file to use for the given filter, gain state, and frame mode. The file + $ISIS3DATA/galileo/calibration/gll_dc.sav defines the DC file to use for the given, gain + state, frame mode, frame rate, blemish protection mode, clock mode, and + extended exposure mode. + + This program performs the following processing steps on each pixel: + + 1. The radiometric correction is applied: + e = z(d - dc) + where z is retrieved from the Radiometric File and dc is retrieved + from the Dark-Current File. + + 2. The output pixel is scaled to radiometric units R. + + S1 K + r = e * -------- * --- (D/5.2)**2 + A1(t-to) Ko + where + + S1 = filter-dependent conversion factor from ft-Lamberts to + I/F units for a reference distance of 5.2 AU from the Sun. + t = commanded exposure time of the input image (msec). + to = line-dependent shutter offset. + K = system gain constant for the gain-state of the image. + Ko = system gain constant for the calibration file gain-state. + D = target distance from the Sun (in AU). + + 5. The output DN is usually in the range of + 0.0 to 1.0. + + If the uneven bit weighting correction is enabled, the input DN values (d) + will be corrected for uneven-bit-weighting due to the ADC. If the input + dark-current file is in byte format (i.e. an individual dark-current frame), + then the correction will be applied to the dark-current as well. The current + correction table was supplied by Herb Breneman, 2 Mar 89, and is based on + 1975 calibration data. + + + + + Original version + + + Removed references to CubeInfo + + + + + + + cube + input + Input file + + Input cube file + + + *.cub + + + + + cube + output + real + Output file + + Output cube file + + + *.cub + + + + + + + boolean + + Correct for uneven bit weighting + + false + Correct for uneven bit weighting + + + + + diff --git a/isis/src/galileo/apps/gllssical/tsts/Makefile b/isis/src/galileo/apps/gllssical/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/galileo/apps/gllssical/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/galileo/apps/gllssical/tsts/default/Makefile b/isis/src/galileo/apps/gllssical/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b97755e7c8ed762797993d3366cc060ff68c5ae8 --- /dev/null +++ b/isis/src/galileo/apps/gllssical/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = gllssical + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/3439R.cub TO=$(OUTPUT)/3439R.cal.cub > /dev/null; + $(APPNAME) FROM=$(INPUT)/1213r.cub TO=$(OUTPUT)/1213r.cal.cub > /dev/null; diff --git a/isis/src/galileo/objs/Makefile b/isis/src/galileo/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/galileo/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/galileo/objs/SsiCamera/Camera.plugin b/isis/src/galileo/objs/SsiCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..d89fc1c7c8e665b801b9cc54aa11b271294edc90 --- /dev/null +++ b/isis/src/galileo/objs/SsiCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = GalileoOrbiter/SolidStateImagingSystem + Version = 1 + Library = SsiCamera + Routine = SsiCameraPlugin +EndGroup + diff --git a/isis/src/galileo/objs/SsiCamera/Makefile b/isis/src/galileo/objs/SsiCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8ad74fd5c5ca015d01b8c566090f608d249ed936 --- /dev/null +++ b/isis/src/galileo/objs/SsiCamera/Makefile @@ -0,0 +1,5 @@ +INCS = SsiCamera.h +SRCS = SsiCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/galileo/objs/SsiCamera/SsiCamera.cpp b/isis/src/galileo/objs/SsiCamera/SsiCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f5ac6e075211f4fb471c0577f3de6b08f6a716c4 --- /dev/null +++ b/isis/src/galileo/objs/SsiCamera/SsiCamera.cpp @@ -0,0 +1,71 @@ +#include "SsiCamera.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraDistortionMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "RadialDistortionMap.h" +#include "iString.h" +#include "iTime.h" + +using namespace std; +using namespace Isis; +namespace Galileo { + SsiCamera::SsiCamera (Pvl &lab) : FramingCamera(lab) { + // Get the camera characteristics + double k1; + + iTime removeCoverDate("1994/04/01 00:00:00"); + iTime imageDate(lab.FindKeyword("StartTime",Isis::PvlObject::Traverse)[0]); + /* + * Change the Focal Length and K1 constant based on whether or not the protective cover is on + * See "The Direction of the North Pole and the Control Network of Asteroid 951 Gaspra" Icarus 107, 18-22 (1994) + */ + if(imageDate < removeCoverDate) { + int code = NaifIkCode(); + string key = "INS" + Isis::iString(code) + "_FOCAL_LENGTH_COVER"; + SetFocalLength(Isis::Spice::GetDouble(key)); + k1 = Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_K1_COVER"); + } + else { + SetFocalLength (); + k1 = Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_K1"); + } + + SetPixelPitch (); + + // Get the start time in et + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + string stime = inst["StartTime"]; + double et; + str2et_c(stime.c_str(),&et); + + // Get summation mode + double sumMode = inst["Summing"]; + + // Setup detector map + CameraDetectorMap *detectorMap = new CameraDetectorMap(this); + detectorMap->SetDetectorSampleSumming(sumMode); + detectorMap->SetDetectorLineSumming(sumMode); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + + focalMap->SetDetectorOrigin (Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_SAMPLE"), + Spice::GetDouble("INS" + (iString)(int)NaifIkCode() + "_BORESIGHT_LINE")); + + // Setup distortion map + new RadialDistortionMap(this, k1); + + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(et); + LoadCache(); + } +} + +extern "C" Camera *SsiCameraPlugin(Pvl &lab) { + return new Galileo::SsiCamera(lab); +} diff --git a/isis/src/galileo/objs/SsiCamera/SsiCamera.h b/isis/src/galileo/objs/SsiCamera/SsiCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..abc23fbc752ca653ad749ba33a8930bafd0b1169 --- /dev/null +++ b/isis/src/galileo/objs/SsiCamera/SsiCamera.h @@ -0,0 +1,34 @@ +#ifndef SsiCamera_h +#define SsiCamera_h + +#include "FramingCamera.h" + +namespace Galileo { + /** + * @ingroup SpiceInstrumentsAndCameras + * + * @brief Camera class + * + * This is the camera class for the IssNACamera + * + * @ingroup Galileo + * + * @author Jeff Anderson + * + * @internal + * @history 2007-10-25 Steven Koechle - Fixed so that it works + * in Isis3 + * @history 2008-08-08 Steven Lambright Now using the new LoadCache(...) + * method instead of CreateCache(...). + * @history 2009-05-04 Steven Koechle - Fixed to grab appropriate FocalLength + * based on image time. + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class SsiCamera : public Isis::FramingCamera { + public: + SsiCamera (Isis::Pvl &lab); + ~SsiCamera () {}; + }; +}; +#endif diff --git a/isis/src/galileo/objs/SsiCamera/SsiCamera.truth b/isis/src/galileo/objs/SsiCamera/SsiCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..f51f79165adebb0ac7327f192d47073fb10ceaca --- /dev/null +++ b/isis/src/galileo/objs/SsiCamera/SsiCamera.truth @@ -0,0 +1,20 @@ +Unit Test for SsiCamera... +For upper left corner ... +DeltaSample = ERROR +DeltaLine = ERROR + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/galileo/objs/SsiCamera/unitTest.cpp b/isis/src/galileo/objs/SsiCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e22ff473666a83dcae0846e3db1bef213637cd41 --- /dev/null +++ b/isis/src/galileo/objs/SsiCamera/unitTest.cpp @@ -0,0 +1,89 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for SsiCamera..." << endl; + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownLat = 39.04149631568807; + double knownLon = 175.6356026237572; + + Isis::Pvl p("$galileo/testData/1213r.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.001) deltaSamp = 0; + if (fabs(deltaLine) < 0.001) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/lo/Makefile b/isis/src/lo/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/lo/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/lo/apps/Makefile b/isis/src/lo/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/lo/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/lo/apps/lo2isis/Makefile b/isis/src/lo/apps/lo2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/lo/apps/lo2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/lo/apps/lo2isis/assets/images/lo2isisGUI.jpg b/isis/src/lo/apps/lo2isis/assets/images/lo2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d01ccb4bcc63e73395fa5a5f4109950c677ec511 Binary files /dev/null and b/isis/src/lo/apps/lo2isis/assets/images/lo2isisGUI.jpg differ diff --git a/isis/src/lo/apps/lo2isis/assets/thumbs/lo2isisGUI.jpg b/isis/src/lo/apps/lo2isis/assets/thumbs/lo2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..245a74ae386e738b6091b059c216ed6b8fe97062 Binary files /dev/null and b/isis/src/lo/apps/lo2isis/assets/thumbs/lo2isisGUI.jpg differ diff --git a/isis/src/lo/apps/lo2isis/lo2isis.cpp b/isis/src/lo/apps/lo2isis/lo2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4540fb00c918f28af18460b2b459e5d58eba3382 --- /dev/null +++ b/isis/src/lo/apps/lo2isis/lo2isis.cpp @@ -0,0 +1,169 @@ +#include "Isis.h" +#include "ProcessImportPds.h" +#include "UserInterface.h" +#include "Filename.h" +#include "Pvl.h" +#include "iException.h" +#include "TextFile.h" +#include + +using namespace std; +using namespace Isis; + +void TranslateLunarLabels (Filename &labelFile, Cube *ocube); + +void IsisMain () +{ + ProcessImportPds p; + Pvl label; + UserInterface &ui = Application::GetUserInterface(); + Filename in = ui.GetFilename("FROM"); + + //Checks if in file is rdr + label = in.Expanded(); + if( label.HasObject("IMAGE_MAP_PROJECTION") ) { + string msg = "[" + in.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + p.SetPdsFile (in.Expanded(), "", label); + Cube *ocube = p.SetOutputCube("TO"); + p.StartProcess (); + TranslateLunarLabels(in, ocube); + p.EndProcess (); + + return; +} + +void TranslateLunarLabels (Filename &labelFile, Cube *ocube) { + + // Get the directory where the Lunar translation tables are. + PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory"); + + // Transfer the instrument group to the output cube + iString transDir = (string) dataDir["Lo"] + "/translations/"; + Pvl inputLabel (labelFile.Expanded()); + Filename transFile; + Filename bandBinTransFile; + + bool hasFiducial = false; + // Check to see if file is PDS + if (inputLabel.HasKeyword("PDS_VERSION_ID", Pvl::None)) { + if (inputLabel.FindKeyword("PDS_VERSION_ID", Pvl::None)[0] == "PDS3") { + if (inputLabel.HasKeyword("LO:FIDUCIAL_ID", Pvl::Traverse)) { + hasFiducial = true; + bandBinTransFile = transDir + "LoPdsFiducialImport.trn"; + } + else if (inputLabel.HasKeyword("LO:BORESIGHT_SAMPLE", Pvl::Traverse)) { + bandBinTransFile = transDir + "LoPdsBoresightImport.trn"; + } + else { + string msg = "[" + labelFile.Name() + "] does not contain boresight or fiducial information."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + else { + string msg = "[" + labelFile.Name() + "] contains unknown PDS version type ["+version+"]."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + // Else the input is an Isis2 cube + else { + if(inputLabel.HasKeyword("FIDUCIAL_ID", Pvl::Traverse)) { + hasFiducial = true; + bandBinTransFile = transDir + "LoIsis2FiducialImport.trn"; + } + else if (inputLabel.HasKeyword("BORESIGHT_SAMPLE", Pvl::Traverse)) { + bandBinTransFile = transDir + "LoIsis2BoresightImport.trn"; + } + else { + string msg = "[" + labelFile.Name() + "] does not contain boresight or fiducial information."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + + transFile = transDir + "LoGeneralImport.trn"; + // Get the translation manager ready + PvlTranslationManager commonlabelXlater (inputLabel, transFile.Expanded()); + // Pvl outputLabels; + Pvl *outputLabel = ocube->Label(); + commonlabelXlater.Auto(*(outputLabel)); + + PvlTranslationManager labelXlater (inputLabel, bandBinTransFile.Expanded()); + labelXlater.Auto(*(outputLabel)); + + PvlGroup &inst = outputLabel->FindGroup("Instrument",Pvl::Traverse); + + //Creates FiducialCoordinateMicron with the proper units + if (!inputLabel.HasKeyword("LO:BORESIGHT_SAMPLE", Pvl::Traverse)) { + iString fcm = (string) inst.FindKeyword("FiducialCoordinateMicron"); + iString fcmUnits = fcm; + fcmUnits = iString::TrimHead("0123456789.",fcmUnits); + fcm = iString::TrimTail("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",fcm); + inst.FindKeyword("FiducialCoordinateMicron").SetValue((int)fcm, fcmUnits); + } + + // High Resolution & Fiducial Medium Case + if (hasFiducial) { + //Add units to some keywords + PvlKeyword fxc = inst.FindKeyword("FiducialXCoordinates"); + inst.FindKeyword("FiducialXCoordinates").Clear(); + for (int i = 0; i < fxc.Size();i++) { + inst.FindKeyword("FiducialXCoordinates").AddValue(fxc[i],"mm"); + } + + PvlKeyword fyc = inst.FindKeyword("FiducialYCoordinates"); + inst.FindKeyword("FiducialYCoordinates").Clear(); + for (int i = 0; i < fyc.Size();i++) { + inst.FindKeyword("FiducialYCoordinates").AddValue(fyc[i],"mm"); + } + + PvlKeyword fl = inst.FindKeyword("FiducialLines"); + inst.FindKeyword("FiducialLines").Clear(); + for (int i = 0; i < fl.Size();i++) { + inst.FindKeyword("FiducialLines").AddValue(fl[i],"pixels"); + } + + PvlKeyword fs = inst.FindKeyword("FiducialSamples"); + inst.FindKeyword("FiducialSamples").Clear(); + for (int i = 0; i < fs.Size();i++) { + inst.FindKeyword("FiducialSamples").AddValue(fs[i],"pixels"); + } + } else if(!hasFiducial){ + //What needs to be done if it contains Boresight info + } + + string instrumentID = inst.FindKeyword("InstrumentId"); + string spacecraftName = inst.FindKeyword("SpacecraftName"); + + //Determines the NaifFrameCode + PvlGroup kerns("Kernels"); + iString frameCode; + if (spacecraftName.compare("Lunar Orbiter 3")==0) { + frameCode = "-533"; + } else if (spacecraftName.compare("Lunar Orbiter 4")==0) { + frameCode = "-534"; + } else if (spacecraftName.compare("Lunar Orbiter 5")==0) { + frameCode = "-535"; + } + + if (instrumentID == "High Resolution Camera") { + frameCode += "001"; + } else if (instrumentID == "Medium Resolution Camera") { + frameCode += "002"; + } + + //Create subframe and frame keywords + iString imgNumber = (string) inst.FindKeyword("ImageNumber"); + int subFrame = ((iString)imgNumber.substr(5)).ToInteger(); + + inst.AddKeyword(PvlKeyword("SubFrame",subFrame)); + //ImageNumber is auto translated, and no longer needed + inst.DeleteKeyword("ImageNumber"); + + kerns += PvlKeyword("NaifFrameCode",frameCode); + outputLabel->FindObject("IsisCube").AddGroup(kerns); + + return; +} diff --git a/isis/src/lo/apps/lo2isis/lo2isis.xml b/isis/src/lo/apps/lo2isis/lo2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..c804969450c8dec67c73d32ad2b98bdfe640a924 --- /dev/null +++ b/isis/src/lo/apps/lo2isis/lo2isis.xml @@ -0,0 +1,111 @@ + + + + + + Import an Isis 2 Lunar Orbiter image file into Isis 3. + + + + This program will import a Lunar Orbiter PDS or Isis 2 Cube image file into + an Isis cube. + + + + + Original Version + + + Corrected documentation error + + + Added full frame support + + + Added medium resolution support + + + Moved lunar directories to lo + + + Checks if input file is rdr. + + + Changed to accept PDS files. + + + Added support for PDS files generated by lopdsgen. + + + + + Lunar Orbiter + + + + + + cube + input + + Input Lunar Orbiter PDS or Isis2 cube + + + Use this parameter to select the Lunar Orbiter PDS or Isis 2 Cube. + + + *.img *.cub *.CUB + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + + + + + Using lo2isis + + + The use of lo2isis to ingest Isis2 cubes and output Isis3 cubes with the correct labels. + + + + from= 3133_h1_raw.cub + to= 3133_h1.cub + + + This example shows the use of lo2isis to create an Isis3 cube from an Isis2 cube. + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters + + + + + + + + diff --git a/isis/src/lo/apps/lo2isis/tsts/Makefile b/isis/src/lo/apps/lo2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/lo/apps/lo2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/lo/apps/lo2isis/tsts/case01/Makefile b/isis/src/lo/apps/lo2isis/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..67725f15d1b2142649fbf50f0241dff86f5b272e --- /dev/null +++ b/isis/src/lo/apps/lo2isis/tsts/case01/Makefile @@ -0,0 +1,8 @@ +APPNAME = lo2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/3133_h1.cub \ + to=$(OUTPUT)/3133_h1.truth.cub > /dev/null; + catlab from=$(OUTPUT)/3133_h1.truth.cub >& $(OUTPUT)/labels.pvl; diff --git a/isis/src/lo/apps/lo2isis/tsts/case02/Makefile b/isis/src/lo/apps/lo2isis/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..aa2f0101f8e918b9350b410d2a6a958001329a3b --- /dev/null +++ b/isis/src/lo/apps/lo2isis/tsts/case02/Makefile @@ -0,0 +1,8 @@ +APPNAME = lo2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/4164H_Full_mirror.cub \ + to=$(OUTPUT)/4164H_Full_mirror.truth.cub > /dev/null; + catlab from=$(OUTPUT)/4164H_Full_mirror.truth.cub >& $(OUTPUT)/labels.pvl; diff --git a/isis/src/lo/apps/lo2isis/tsts/case03/Makefile b/isis/src/lo/apps/lo2isis/tsts/case03/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2a6b077e4b5f5acb035d19f07c06a92472ea68c0 --- /dev/null +++ b/isis/src/lo/apps/lo2isis/tsts/case03/Makefile @@ -0,0 +1,8 @@ +APPNAME = lo2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/3083_med_tohi_isis2.cub \ + to=$(OUTPUT)/3083_med_tohi.truth.cub > /dev/null; + catlab from=$(OUTPUT)/3083_med_tohi.truth.cub >& $(OUTPUT)/labels.pvl; diff --git a/isis/src/lo/apps/lo2isis/tsts/case04/Makefile b/isis/src/lo/apps/lo2isis/tsts/case04/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8f5d61552d45af3a70b8556342c47942e5bf7968 --- /dev/null +++ b/isis/src/lo/apps/lo2isis/tsts/case04/Makefile @@ -0,0 +1,8 @@ +APPNAME = lo2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/3083_med_isis2.cub \ + to=$(OUTPUT)/3083_med.truth.cub > /dev/null; + catlab from=$(OUTPUT)/3083_med.truth.cub > $(OUTPUT)/labels.pvl; diff --git a/isis/src/lo/apps/lo2isis/tsts/reimport/Makefile b/isis/src/lo/apps/lo2isis/tsts/reimport/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e09133c757826b8335604807891cd8d8145c3867 --- /dev/null +++ b/isis/src/lo/apps/lo2isis/tsts/reimport/Makefile @@ -0,0 +1,8 @@ +APPNAME = lo2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/3133_h1.pds.img \ + to=$(OUTPUT)/3133_h1.truth.cub > /dev/null; + catlab from=$(OUTPUT)/3133_h1.truth.cub >& $(OUTPUT)/labels.pvl; diff --git a/isis/src/lo/apps/lopdsgen/Makefile b/isis/src/lo/apps/lopdsgen/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/lo/apps/lopdsgen/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/lo/apps/lopdsgen/assets/images/baseGui.jpg b/isis/src/lo/apps/lopdsgen/assets/images/baseGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ee962d6740d10b8feedda5aedc9279f19868a7f1 Binary files /dev/null and b/isis/src/lo/apps/lopdsgen/assets/images/baseGui.jpg differ diff --git a/isis/src/lo/apps/lopdsgen/assets/images/input_level1.jpg b/isis/src/lo/apps/lopdsgen/assets/images/input_level1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b44338249ae75b045d2c38abd7fc314f733eedae Binary files /dev/null and b/isis/src/lo/apps/lopdsgen/assets/images/input_level1.jpg differ diff --git a/isis/src/lo/apps/lopdsgen/assets/images/output_level1.jpg b/isis/src/lo/apps/lopdsgen/assets/images/output_level1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..413df913079b4911a6ce14d2d70c20cfa2ef68d2 Binary files /dev/null and b/isis/src/lo/apps/lopdsgen/assets/images/output_level1.jpg differ diff --git a/isis/src/lo/apps/lopdsgen/assets/input_labels.pvl b/isis/src/lo/apps/lopdsgen/assets/input_labels.pvl new file mode 100644 index 0000000000000000000000000000000000000000..87eed9fb40df415bc11fced701fade660ad05707 --- /dev/null +++ b/isis/src/lo/apps/lopdsgen/assets/input_labels.pvl @@ -0,0 +1,112 @@ +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 8263 + Lines = 7840 + Bands = 1 + End_Group + + Group = Pixels + Type = UnsignedByte + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + TargetName = Moon + SpacecraftName = "Lunar Orbiter 3" + StartTime = 1967-02-22T05:24:28.800 + InstrumentId = "High Resolution Camera" + FrameNumber = 3200 + FiducialCoordinateMicron = 50 + FiducialID = (1a, 2a, 46b, 93b, 94b, 26b, 70b, 27b, 47b, + 69b, 98b, 145b, 146b, 189b, 190b, 120b, 166b, + 123b, 165b, 99b, 192b, 193b, 245b, 246b, 285b, + 286b, 220b, 264b, 269b, 219b) + FiducialSamples = (32093.000, 32096.000, 27242.000, 21970.000, + 21976.000, 29433.000, 24604.000, 29209.000, + 27018.000, 24604.000, 21537.000, 16271.000, + 16276.000, 11451.000, 11451.000, 19122.000, + 14082.000, 18681.000, 14078.000, 21312.000, + 11230.000, 11015.000, 5313.000, 5309.000, + 929.000, 927.000, 8160.000, 3338.000, 2679.000, + 8163.000) + FiducialLines = (8497.000, 579.000, 571.000, 8481.000, 565.000, + 579.000, 571.000, 8488.000, 8487.000, 8486.000, + 565.000, 8476.000, 560.000, 8475.000, 555.000, + 566.000, 558.000, 8476.000, 8476.000, 8482.000, + 557.000, 8474.000, 8471.000, 564.000, 8476.000, + 561.000, 557.000, 560.000, 8472.000, + 8474.000) + FiducialXCoordinates = (-108.396, -108.339, -74.548, -38.026, -37.964, + -89.786, -56.272, -88.373, -73.101, -56.319, + -34.929, 1.610, 1.642, 35.174, 35.198, -18.178, + 16.913, -15.149, 16.863, -33.441, 36.710, + 38.211, 77.875, 77.889, 108.365, 108.352, + 58.079, 91.579, 96.167, 58.045) + FiducialYCoordinates = (27.470, -27.488, -27.493, 27.496, -27.490, + -27.490, -27.489, 27.488, 27.498, 27.493, + -27.490, 27.500, -27.492, 27.492, -27.486, + -27.499, -27.483, 27.490, 27.499, 27.499, + -27.493, 27.488, 27.484, -27.490, 27.480, + -27.481, -27.487, -27.490, 27.480, 27.492) + SubFrame = 780 + End_Group + + Group = Archive + ProductId = 3200H + ScanCreationDate = 2003-06-18T10:11:57 + ScanResolution = 25um + OutputMicron = 50um + ScanDensityRange = 0.5_TO_3.0 + RecordBytes = 512 + FileRecords = 201733 + LabelRecords = 28 + End_Group + + Group = BandBin + FilterName = none + Center = 1.000 + OriginalBand = 1 + End_Group + + Group = Kernels + NaifFrameCode = -533001 + CameraVersion = 1 + End_Group + + Group = AlphaCube + AlphaSamples = 11800 + AlphaLines = 8750 + AlphaStartingSample = 3050.5 + AlphaStartingLine = 600.5 + AlphaEndingSample = 11313.5 + AlphaEndingLine = 8440.5 + BetaSamples = 8263 + BetaLines = 7840 + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = History + Name = IsisCube + StartByte = 66110190 + Bytes = 1593 +End_Object + +Object = OriginalLabel + Name = IsisCube + StartByte = 66093057 + Bytes = 17133 +End_Object +End diff --git a/isis/src/lo/apps/lopdsgen/assets/output_labels.pvl b/isis/src/lo/apps/lopdsgen/assets/output_labels.pvl new file mode 100644 index 0000000000000000000000000000000000000000..fe198d9f2e8309d795acc2019af7053927615252 --- /dev/null +++ b/isis/src/lo/apps/lopdsgen/assets/output_labels.pvl @@ -0,0 +1,87 @@ +PDS_VERSION_ID = PDS3 + +/* FILE FORMAT AND LENGTH */ +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 33052 +FILE_RECORDS = 7841 +LABEL_RECORDS = 1 +INTERCHANGE_FORMAT = BINARY + +/* POINTERS TO START RECORDS OF OBJECTS IN FILE */ +^IMAGE = 2 + +/* IMAGE DESCRIPTION */ +DATA_SET_ID = LO-L-LO1/2/3-4-CDR-V1.0 +PRODUCT_ID = level1 +ORIGINAL_PRODUCT_ID = 3200H +PRODUCT_TYPE = CDR +MISSION_NAME = "LUNAR ORBITER" +SPACECRAFT_NAME = LUNAR_ORBITER_3 +INSTRUMENT_NAME = 24_INCH_FOCAL_LENGTH_CAMERA +INSTRUMENT_ID = 24INCH_FLC +TARGET_NAME = MOON +START_TIME = 1967-02-22T05:24:28.800 +IMAGE_NUMBER = (320010780, 320010790, 320010800, 320010810, + 320010820, 320010830, 320010850, 320010860, + 320010870, 320010880, 320010890, 320010900, + 320010910, 320010920, 320010940, 320010950, + 320010960, 320010970, 320010980, 320010990, + 320011000, 320011010, 320011020, 320011040, + 320011050, 320011060, 320011070, 320011080, + 320011090) +FRAME_NUMBER = 3200 +SCAN_CREATION_DATE = 2003-06-18T10:11:57 +SCAN_PARAMETER = (25, 50um, 0.5, 3.0) +SCAN_PARAMETER_DESCRIPTION = (SCAN_RESOLUTION, OUTPUT_MICRON, + SCAN_DENSITY_RANGE1, SCAN_DENSITY_RANGE2) +FIDUCIAL_ID = (1a, 2a, 46b, 93b, 94b, 26b, 70b, 27b, 47b, 69b, + 98b, 145b, 146b, 189b, 190b, 120b, 166b, 123b, + 165b, 99b, 192b, 193b, 245b, 246b, 285b, 286b, + 220b, 264b, 269b, 219b) +FIDUCIAL_SAMPLES = (32093.000, 32096.000, 27242.000, 21970.000, + 21976.000, 29433.000, 24604.000, 29209.000, + 27018.000, 24604.000, 21537.000, 16271.000, + 16276.000, 11451.000, 11451.000, 19122.000, + 14082.000, 18681.000, 14078.000, 21312.000, + 11230.000, 11015.000, 5313.000, 5309.000, + 929.000, 927.000, 8160.000, 3338.000, 2679.000, + 8163.000) +FIDUCIAL_LINES = (8497.000, 579.000, 571.000, 8481.000, 565.000, + 579.000, 571.000, 8488.000, 8487.000, 8486.000, + 565.000, 8476.000, 560.000, 8475.000, 555.000, + 566.000, 558.000, 8476.000, 8476.000, 8482.000, + 557.000, 8474.000, 8471.000, 564.000, 8476.000, + 561.000, 557.000, 560.000, 8472.000, + 8474.000) +FIDUCIAL_COORD_MICRON = 50 +FIDUCIAL_X_COORDINATES = (-108.396, -108.339, -74.548, -38.026, -37.964, + -89.786, -56.272, -88.373, -73.101, -56.319, + -34.929, 1.610, 1.642, 35.174, 35.198, -18.178, + 16.913, -15.149, 16.863, -33.441, 36.710, 38.211, + 77.875, 77.889, 108.365, 108.352, 58.079, 91.579, + 96.167, 58.045) +FIDUCIAL_Y_COORDINATES = (27.470, -27.488, -27.493, 27.496, -27.490, + -27.490, -27.489, 27.488, 27.498, 27.493, + -27.490, 27.500, -27.492, 27.492, -27.486, + -27.499, -27.483, 27.490, 27.499, 27.499, + -27.493, 27.488, 27.484, -27.490, 27.480, + -27.481, -27.487, -27.490, 27.480, 27.492) +PRODUCER_INSTITUTION_NAME = "U.S. GEOLOGICAL SURVEY" +PRODUCT_CREATION_TIME = 2009-12-18T17:44:45 + +/* DESCRIPTION OF OBJECTS CONTAINED IN FILE */ +Object = IMAGE + LINES = 7840 + LINE_SAMPLES = 8263 + SAMPLE_TYPE = PC_REAL + SAMPLE_BITS = 32 + SAMPLE_BIT_MASK = 2#11111111111111111111111111111111# + MINIMUM = 1.0 + MAXIMUM = 248.0 + CORE_NULL = 16#FF7FFFFB# + CORE_LOW_REPR_SATURATION = 16#FF7FFFFC# + CORE_LOW_INSTR_SATURATION = 16#FF7FFFFD# + CORE_HIGH_REPR_SATURATION = 16#FF7FFFFF# + CORE_HIGH_INSTR_SATURATION = 16#FF7FFFFE# +End_Object +End diff --git a/isis/src/lo/apps/lopdsgen/assets/thumbs/baseGui.jpg b/isis/src/lo/apps/lopdsgen/assets/thumbs/baseGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f0d6dfa020ebd68cfcb75be984eceac5253ec69f Binary files /dev/null and b/isis/src/lo/apps/lopdsgen/assets/thumbs/baseGui.jpg differ diff --git a/isis/src/lo/apps/lopdsgen/assets/thumbs/input_level1.jpg b/isis/src/lo/apps/lopdsgen/assets/thumbs/input_level1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..83928be65aa2d6f1292a6244348546f7147d6082 Binary files /dev/null and b/isis/src/lo/apps/lopdsgen/assets/thumbs/input_level1.jpg differ diff --git a/isis/src/lo/apps/lopdsgen/assets/thumbs/output_level1.jpg b/isis/src/lo/apps/lopdsgen/assets/thumbs/output_level1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ffd18ee2efd731916b9704a8383cf71506eb0c57 Binary files /dev/null and b/isis/src/lo/apps/lopdsgen/assets/thumbs/output_level1.jpg differ diff --git a/isis/src/lo/apps/lopdsgen/lopdsgen.cpp b/isis/src/lo/apps/lopdsgen/lopdsgen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe97bf04d4afae716253eae998b6da61bbc23474 --- /dev/null +++ b/isis/src/lo/apps/lopdsgen/lopdsgen.cpp @@ -0,0 +1,299 @@ +#include "Isis.h" + +#include "iTime.h" +#include "ProcessExportPds.h" +#include "PvlTranslationManager.h" +#include "PvlFormatPds.h" +#include "OriginalLabel.h" + +using namespace std; +using namespace Isis; + +enum Pixtype { NONE, NEG, BOTH }; + +void setRangeAndPixels( UserInterface &ui, ProcessExportPds &p, + double &min, double &max, Pixtype ptype ); +void IsisMain() { + // Set the processing object + ProcessExportPds p; + + // Setup the input cube + Cube *iCube = p.SetInputCube("FROM"); + + UserInterface &ui = Application::GetUserInterface(); + + double min = -DBL_MAX; + double max = DBL_MAX; + + if (ui.GetString("BITTYPE") == "8BIT") { + p.SetOutputType(Isis::UnsignedByte); + min = 0.0; + max = 255.0; + setRangeAndPixels( ui, p, min, max, BOTH ); + } + else if (ui.GetString("BITTYPE") == "S16BIT") { + p.SetOutputType(Isis::SignedWord); + min = -32768.0; + max = 32767.0; + setRangeAndPixels( ui, p, min, max, NEG ); + } + else if (ui.GetString("BITTYPE") == "U16BIT") { + p.SetOutputType(Isis::UnsignedWord); + min = 0.0; + max = 65535.0; + setRangeAndPixels( ui, p, min, max, BOTH ); + } + else { + p.SetOutputType(Isis::Real); + p.SetOutputNull(Isis::NULL4); + p.SetOutputLrs(Isis::LOW_REPR_SAT4); + p.SetOutputLis(Isis::LOW_INSTR_SAT4); + p.SetOutputHrs(Isis::HIGH_REPR_SAT4); + p.SetOutputHis(Isis::HIGH_INSTR_SAT4); + setRangeAndPixels( ui, p, min, max, NONE ); + } + + if (ui.GetString("ENDIAN") == "MSB") + p.SetOutputEndian(Isis::Msb); + else if (ui.GetString("ENDIAN") == "LSB") + p.SetOutputEndian(Isis::Lsb); + + p.SetExportType( ProcessExportPds::Fixed ); + + // Get the PDS label from the process, omitting keywords unnecessary for LO + p.ForceBands(false); + p.ForceBandName(false); + p.ForceCenterFilterWavelength(false); + p.ForceBandStorageType(false); + p.ForceOffset(false); + p.ForceScalingFactor(false); + Pvl &pdsLabel = p.StandardPdsLabel(ProcessExportPds::Image); + + // Add PRODUCT_ID keyword, the first part of the output filename + Filename outFileNoExt(ui.GetFilename("TO")); + outFileNoExt.RemoveExtension(); + iString productID (outFileNoExt.Basename()); + PvlKeyword productId ("PRODUCT_ID", productID.UpCase()); + pdsLabel.AddKeyword(productId); + + // Translate the keywords from the original labels that go in this label + OriginalLabel origBlob; + iCube->Read(origBlob); + Pvl origLabel; + PvlObject origLabelObj = origBlob.ReturnLabels(); + origLabelObj.SetName("OriginalLabelObject"); + origLabel.AddObject(origLabelObj); + + // Get the directory where the Lunar translation tables are. + PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory"); + + // Transfer the instrument group to the output cube + iString transDir = (string) dataDir["Lo"] + "/translations/"; + + // Isis 3 cubes being exported for the first time + if (!origLabel.HasKeyword("PRODUCT_TYPE", Pvl::Traverse)) { + + PvlTranslationManager orig (origLabel, transDir + "LoOriginalExport.trn"); + orig.Auto(pdsLabel); + + // Add elements of SCAN_PARAMETER keyword to label + PvlObject &qube = origLabelObj.FindObject("QUBE"); + PvlGroup &ingestion = qube.FindGroup("ISIS_INGESTION"); + + // Strips and level1 products use the following two keywords in different ways + PvlKeyword &scanResolution = ingestion.FindKeyword("SCAN_RESOLUTION"); + PvlKeyword &scanDensityRange = ingestion.FindKeyword("SCAN_DENSITY_RANGE"); + + // Change the units of SCAN_RESOLUTION from "um" to "" + string scanResolutionStr = scanResolution[0]; + unsigned umPos = scanResolutionStr.find("um"); + string resolution = scanResolutionStr.substr(0, umPos); + scanResolution[0] = resolution; + scanResolution.SetUnits("micron"); + scanResolution.SetName("LO:FILMSTRIP_SCAN_RESOLUTION"); + + // Break keyword SCAN_DENSITY_RANGE into two different parts + string scanDensityRangeStr = scanDensityRange[0]; + unsigned toPos = scanDensityRangeStr.find("_TO_"); + string range1 = scanDensityRangeStr.substr(0, toPos); + string range2 = scanDensityRangeStr.substr(toPos + 4); + + // Label translation for strips + if (qube.FindGroup("ISIS_INSTRUMENT").HasKeyword("STRIP_NUMBER")) { + PvlTranslationManager orig(origLabel, transDir + "LoStripExport.trn"); + orig.Auto(pdsLabel); + + pdsLabel.AddKeyword(scanResolution, PvlContainer::Replace); + + /* + PvlKeyword newScanDensityRange ("SCAN_DENSITY_RANGE"); + newScanDensityRange += range1; + newScanDensityRange += range2; + pdsLabel.AddKeyword(newScanDensityRange, PvlContainer::Replace); + */ + } + // Translation for level1 products + else if (qube.FindGroup("ISIS_INSTRUMENT").HasKeyword("START_TIME")) { + PvlTranslationManager orig(origLabel, transDir + "LoLevel1Export.trn"); + orig.Auto(pdsLabel); + + pdsLabel.AddKeyword(scanResolution, PvlContainer::Replace); + + // Keyword SCAN_PARAMETER will contain four elements, defined + // by SCAN_PARAMETER_DESCRIPTION + /* + PvlKeyword scanParameter ("SCAN_PARAMETER"); + scanParameter += scanResolution[0]; + scanParameter += qube.FindKeyword("OUTPUT_MICRON")[0]; + scanParameter += range1; + scanParameter += range2; + */ + + PvlKeyword &outputMicron = qube.FindKeyword("OUTPUT_MICRON"); + + // Change the units of OUTPUT_MICRON from "um" to "" + string outputMicronStr = outputMicron[0]; + umPos = outputMicronStr.find("um"); + resolution = outputMicronStr.substr(0, umPos); + outputMicron[0] = resolution; + outputMicron.SetUnits("micron"); + outputMicron.SetName("LO:FILMSTRIP_SCAN_PROCESSING_RESOLUTION"); + + pdsLabel.AddKeyword(outputMicron, PvlContainer::Replace); + + //pdsLabel.AddKeyword(scanParameter, PvlContainer::Replace); + + // Calculate statistics on the cube to be processed and place + // its MINIMUM and MAXIMUM into the output label + p.CalculateStatistics(); + pdsLabel.FindObject("IMAGE").AddKeyword(PvlKeyword("MINIMUM", p.CubeStatistics(0)->Minimum()), Pvl::Replace); + pdsLabel.FindObject("IMAGE").AddKeyword(PvlKeyword("MAXIMUM", p.CubeStatistics(0)->Maximum()), Pvl::Replace); + } + else { + Filename inputFile (ui.GetFilename("FROM")); + string msg = "[" + inputFile.Expanded() + "] does not appear to be an LO file. "; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + // Reexporting a product created by this program and reingested into Isis + else { + + PvlTranslationManager orig (origLabel, transDir + "LoReimportExport.trn"); + orig.Auto(pdsLabel); + + // Reexporting strips + if (origLabel.HasKeyword("STRIP_NUMBER", Pvl::Traverse)) { + PvlTranslationManager strip (origLabel, transDir + "LoStripExport.trn"); + strip.Auto(pdsLabel); + } + // Reexporting level 1 products + else { + PvlTranslationManager lvl1 (origLabel, transDir + "LoLevel1Export.trn"); + lvl1.Auto(pdsLabel); + } + } + + // Add to labels boresight or fiducial data + string bandBinTransFile; + if (iCube->Label()->HasKeyword("FiducialId", Pvl::Traverse)) { + bandBinTransFile = transDir + "LoFiducialExport.trn"; + PvlTranslationManager bandLab(*(iCube->Label()), bandBinTransFile); + bandLab.Auto(pdsLabel); + } + else if (iCube->Label()->HasKeyword("BoresightSample", Pvl::Traverse)) { + bandBinTransFile = transDir + "LoBoresightExport.trn"; + PvlTranslationManager bandLab(*(iCube->Label()), bandBinTransFile); + bandLab.Auto(pdsLabel); + } + else { + Filename inputFile (ui.GetFilename("FROM")); + string msg = "[" + inputFile.Expanded() + "] does not contain boresight or fiducial information. "; + msg += "Try ingesting your data with lo2isis first."; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Add PRODUCT_CREATION_TIME + time_t startTime = time(NULL); + struct tm *tmbuf = gmtime(&startTime); + char timestr[80]; + strftime(timestr,80,"%Y-%m-%dT%H:%M:%S",tmbuf); + string dateTime = (string) timestr; + iTime tmpDateTime(dateTime); + pdsLabel += PvlKeyword("PRODUCT_CREATION_TIME", tmpDateTime.UTC()); + + if(ui.WasEntered("NOTE")) { + pdsLabel.AddKeyword(PvlKeyword("NOTE", ui.GetString("NOTE")), Pvl::Replace); + } + + // Add a keyword type (i.e., string, bool, int...) file to the PDS label Pvl + PvlFormat *formatter = pdsLabel.GetFormat(); + formatter->SetCharLimit(128); + formatter->Add("$lo/translations/LoExportFormatter.typ"); + + // Add an output format template (group, object, & keyword output order) to + // the PDS PVL + pdsLabel.SetFormatTemplate ("$lo/templates/labels/LoExportTemplate.pft"); + + // Write labels to output file + Filename outFile(ui.GetFilename("TO", "img")); + string outFilename(outFile.Expanded()); + ofstream oCube(outFilename.c_str()); + p.OutputLabel(oCube); + p.StartProcess(oCube); + oCube.close(); + p.EndProcess(); + + /* + //Records what it did to the print.prt file + PvlGroup results( "DNs Used" ); + results += PvlKeyword( "Null", p.OutputNull() ); + results += PvlKeyword( "LRS", p.OutputLrs() ); + results += PvlKeyword( "LIS", p.OutputLis() ); + results += PvlKeyword( "HIS", p.OutputHis() ); + results += PvlKeyword( "HRS", p.OutputHrs() ); + results += PvlKeyword( "ValidMin", min ); + results += PvlKeyword( "ValidMax", max ); + Application::Log( results ); + */ + + return; +} + +//Sets up special pixels and valid pixel ranges +void setRangeAndPixels( UserInterface &ui, ProcessExportPds &p, double &min, double &max, Pixtype ptype ) { + if( ptype == NEG ) { + if ( ui.GetBoolean("NULL") ) { + p.SetOutputNull(min++); + } + if ( ui.GetBoolean("LRS") ) { + p.SetOutputLrs(min++); + } + if ( ui.GetBoolean("LIS") ) { + p.SetOutputLis(min++); + } + if ( ui.GetBoolean("HIS") ) { + p.SetOutputHis(min++); + } + if ( ui.GetBoolean("HRS") ) { + p.SetOutputHrs(min++); + } + } + else if( ptype == BOTH ) { + if ( ui.GetBoolean("NULL") ) { + p.SetOutputNull(min++); + } + if ( ui.GetBoolean("LRS") ) { + p.SetOutputLrs(min++); + } + if ( ui.GetBoolean("LIS") ) { + p.SetOutputLis(min++); + } + if ( ui.GetBoolean("HRS") ) { + p.SetOutputHrs(max--); + } + if ( ui.GetBoolean("HIS") ) { + p.SetOutputHis(max--); + } + } + p.SetOutputRange(min,max); +} diff --git a/isis/src/lo/apps/lopdsgen/lopdsgen.xml b/isis/src/lo/apps/lopdsgen/lopdsgen.xml new file mode 100644 index 0000000000000000000000000000000000000000..b1f40e0cd6dad43222ec65b3b2b434ec8894185c --- /dev/null +++ b/isis/src/lo/apps/lopdsgen/lopdsgen.xml @@ -0,0 +1,406 @@ + + + + + + Convert from Isis 3 Lunar Orbiter cubes to the PDS format + + + + Program to convert Isis 3 cubes for Lunar Orbiter strips and level 1 products + to PDS image files. + + + + Lunar Orbiter + + + + + + Original version + + + Updated test and example for changes to PVL. + + + Added support for reexporting the cubes generated from PDS files produced + by this application. + + + + + + + cube + input + + Input cube to be converted + + + The LO strip or level 1 Isis 3 cube to be converted to PDS format. + + + *.cub + + + + + filename + output + + Output PDS image + + + The resulting PDS file. + + + *.img + + + + + + + string + + 32BIT + + Bit type of output file + + Bit type of output: + 8 bit (0=black, 255=white) + 16 bit unsigned (0=black, 65535=white) + 16 bit signed (-32767=black, 32768=white) + 32 bit (1.17549435e-38=black, 3.40282347e+38=white) + + + + + + + + + + boolean + true + Dedicates the minimum DN value for null pixels. + + If set to true, the minimum value of the raw output data will be + reserved for null pixels. The actual value used for null pixels will + be denoted in the print.prt file as well as displayed onscreen. + + + + boolean + false + Dedicates a DN value for LRS pixels. + + If set to true, then an output DN value is set aside for the LRS input pixels. + The actual DN value used for LRS pixels will be denoted in the print.prt + file as well as displayed onscreen. + + + + boolean + false + Dedicates a DN value for LIS pixels. + + If set to true, then an output DN value is set aside for the LIS input pixels. + The actual DN value used for LIS pixels will be denoted in the print.prt + file as well as displayed onscreen. + + + + boolean + false + Dedicates a DN value for HIS pixels. + + If set to true, then an output DN value is set aside for the HIS input pixels. + The actual DN value used for HIS pixels will be denoted in the print.prt + file as well as displayed onscreen. + + + + boolean + false + Dedicates a DN value for HRS pixels. + + If set to true, then an output DN value is set aside for the HRS input pixels. + The actual DN value used for HRS pixels will be denoted in the print.prt + file as well as displayed onscreen. + + + + + + + string + + NONE + + Type of stretch + + This parameter is used to select one of three ways to stretch + (or map) the input pixels. They are NONE, LINEAR, or MANUAL. + + + + + + + + + + + double + Minimum pixel value + + The minimum input pixel value which will be mapped to black. + + + MAXIMUM + + + + + double + Maximum pixel value + + The maximum input pixel value which will be mapped to white. + + + MINIMUM + + + + + double + Minimum Percent + + The percentage of data in the histogram used to compute the minimum + pixel value in the stretch. + + 0.5 + + MAXPERCENT + + + + + double + Maximum Percent + + The percentage of data in the histogram used to compute the maximum + pixel value in the stretch. + + 99.5 + + MINPERCENT + + + + + + + string + + LSB + + Endianness of the output bytes + + This parameter is used to select one whether the output will be + streamed starting with the most significant byte (MSB) or starting + with the least significant bytes (LSB). The choice should be made by + the user depending upon the format read by the system architecture + from which they plan to read the raw data. + + + + + + + + + + + string + None + + Value for the output PDS keyword NOTE + + + This parameter allows the user to specify the value of the standard + PDS keyword NOTE within the output PDS label. This keyword + will be located in the Root of the PDS PVL label. + + + + + + + + + Export Level 1 cube to 32-bit PDS + + + This example shows a typical conversion of an Isis 3 Lunar + Orbiter cube to a PDS format image. The default settings + produce 32-bit data with least significant byte first order. + + + + from=lev1.cub to=lev1.pds.img + + + In this example, lopdsgen will convert a cube to a pds + format image with all settings left at their defaults. + + + + + + + + Example GUI + + + Screenshot of GUI with parameters set to export a level1 LO + cube to a PDS image. + + + + + + + + + + Input cube for lopdsgen + + + This is an Isis 3 cube, specifically a level 1 LO product, that + will be exported to a standard PDS format image. + + + FROM + + + + + + Click here for the labels of the input image + + This PVL contains the labels of the Isis 3, level 1 LO input + image that will be exported to a PDS. + + + + Click here for the labels of the output image + + This PVL contains the labels of the PDS format image that has + been generated from an Isis 3, level 1 LO cube. + + + + + + + + Output pds image from lopdsgen + + + This is a PDS format image that has been produced by exporting the + input Isis 3, level 1 LO cube with default settings. + + + TO + + + + + diff --git a/isis/src/lo/apps/lopdsgen/tsts/Makefile b/isis/src/lo/apps/lopdsgen/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/lo/apps/lopdsgen/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/lo/apps/lopdsgen/tsts/default/Makefile b/isis/src/lo/apps/lopdsgen/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..03e9ab7b7423e539ead659a53160c5910e728394 --- /dev/null +++ b/isis/src/lo/apps/lopdsgen/tsts/default/Makefile @@ -0,0 +1,12 @@ +APPNAME = lopdsgen + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/3133_h1_isis3.cub \ + to=$(OUTPUT)/3133_h1.pds.img \ + > /dev/null; + catlab from=$(OUTPUT)/3133_h1.pds.img \ + to=$(OUTPUT)/3133_h1.pvl \ + > /dev/null; + rm $(OUTPUT)/3133_h1.pds.img; diff --git a/isis/src/lo/apps/lopdsgen/tsts/reexport/Makefile b/isis/src/lo/apps/lopdsgen/tsts/reexport/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..eb605aba1f57ab9bd78cf73c5b7202d55b3fcf15 --- /dev/null +++ b/isis/src/lo/apps/lopdsgen/tsts/reexport/Makefile @@ -0,0 +1,20 @@ +APPNAME = lopdsgen + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/3133_h1.cub \ + to=$(OUTPUT)/3133_h1.pds.img \ + > /dev/null; + catlab from=$(OUTPUT)/3133_h1.pds.img \ + to=$(OUTPUT)/3133_h1_1.pvl \ + > /dev/null; + lo2isis from=$(OUTPUT)/3133_h1.pds.img \ + to=$(OUTPUT)/3133_h1_1.cub \ + > /dev/null; + cubediff from=$(INPUT)/3133_h1.cub \ + from2=$(OUTPUT)/3133_h1_1.cub \ + to=$(OUTPUT)/cube_difference.txt \ + > /dev/null; + rm $(OUTPUT)/3133_h1.pds.img; + rm $(OUTPUT)/3133_h1_1.cub; diff --git a/isis/src/lo/objs/LoCameraFiducialMap/LoCameraFiducialMap.cpp b/isis/src/lo/objs/LoCameraFiducialMap/LoCameraFiducialMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13f7868af066909eb0da0cdc85e3d8a1041f51db --- /dev/null +++ b/isis/src/lo/objs/LoCameraFiducialMap/LoCameraFiducialMap.cpp @@ -0,0 +1,113 @@ +#include "LoCameraFiducialMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "iString.h" +#include "Affine.h" + +using namespace std; +namespace Isis { + namespace Lo { + /** Construct mapping between Lunar Orbiter detectors and focal plane x/y + * + * @param naifIkCode Naif code of the Lunar Orbiter instrument for reading coefficients + * + */ + LoCameraFiducialMap::LoCameraFiducialMap(PvlGroup &inst, const int naifIkCode) { + // Get the Instrument label information needed to define the fiducial map for this frame + p_naifIkCode = naifIkCode; + ReadFiducials(inst); + + // Set the x-axis direction. The medium camera is reversed. + int xdir; + if (naifIkCode%2 == 0) { + xdir = -1; + } + else { + xdir = 1; + } + CreateTrans( xdir ); + } + + + void LoCameraFiducialMap::ReadFiducials(PvlGroup &inst) { + + // Try to read the fiducials from the labels + try { + // Fiducial mapping to define the Focal Plane map + PvlKeyword &fSamps = inst["FiducialSamples"]; + PvlKeyword &fLines = inst["FiducialLines"]; + PvlKeyword &fXs = inst["FiducialXCoordinates"]; + PvlKeyword &fYs = inst["FiducialYCoordinates"]; + + for (int i=0; iSolve ( &p_fidSamples[0], (double *) &p_fidLines[0], + (double *) &p_fidXCoords[0], (double *) &p_fidYCoords[0], + p_fidSamples.size()); + + } catch ( iException &e ) { + std::string msg = "Unable to create fiducial map"; + throw Isis::iException::Message(iException::User,msg,_FILEINFO_); + } + + // Get the coefficients + vector transx; + vector transy; + transx = fptrans->Coefficients(1); + transy = fptrans->Coefficients(2); + + // Medium camera has a reversed x-axis + for (int icoef=0; icoef<3; icoef++) {transx[icoef] *= xdir;}; + + // Correct the Affine order - move the constant to the front + transx.insert(transx.begin(), transx[2]); + transx.pop_back(); + transy.insert(transy.begin(), transy[2]); + transy.pop_back(); + + string icode = "INS" + iString(p_naifIkCode); + string icodex = icode + "_TRANSX"; + string icodey = icode + "_TRANSY"; + pdpool_c(icodex.c_str(), 3, (double (*)) &transx[0]); + pdpool_c(icodey.c_str(), 3, (double (*)) &transy[0]); + + vector transs; + vector transl; + transs = fptrans->InverseCoefficients(1); + transl = fptrans->InverseCoefficients(2); + + // Correct the Affine order - move the constant to the front + transs.insert(transs.begin(), transs[2]); + transs.pop_back(); + transl.insert(transl.begin(), transl[2]); + transl.pop_back(); + + // Medium camera has a reversed x-axis + transs[1] *= xdir; + transl[1] *= xdir; + + string icodes = icode + "_ITRANSS"; + string icodel = icode + "_ITRANSL"; + pdpool_c(icodes.c_str(), 3, (double (*)) &transs[0]); + pdpool_c(icodel.c_str(), 3, (double (*)) &transl[0]); + } + } +} + diff --git a/isis/src/lo/objs/LoCameraFiducialMap/LoCameraFiducialMap.h b/isis/src/lo/objs/LoCameraFiducialMap/LoCameraFiducialMap.h new file mode 100644 index 0000000000000000000000000000000000000000..0d60498506b28011f7ccfcc638290c11857cf6aa --- /dev/null +++ b/isis/src/lo/objs/LoCameraFiducialMap/LoCameraFiducialMap.h @@ -0,0 +1,74 @@ +/** + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef LoCameraFiducialMap_h +#define LoCameraFiducialMap_h + +#include "PvlGroup.h" + +using namespace std; + +namespace Isis { + namespace Lo { + /** + * @brief Computes map from image coordinates to focal plane based on fiducials + * + * The LoCameraFiducialMap class allows for the computation of a transformation + * from image coordinates (sample,line) to focal plane coordinates (x,y) for + * either the Lunar Orbiter High Resolution Camera or the Lunar Orbiter Medium + * resolution camera for any of the last three Lunar Orbiter missions. The + * transformation map is an affine transformation defined by values written in + * the Isis 3 Instrument group labels. + * + * This class will load the fiducial sample/line and x/y values from the labels, + * compute the coefficients of the affine transformation, and place the + * coefficients in to the data pool. Typically these values are read from an + * iak, but for Lunar Orbiter they are frame dependent. + * + * @ingroup SpiceInstrumentsAndCameras + * @ingroup LunarOrbiter + * + * @author 2007-07-17 Debbie A. Cook + * + * @internal + * @history 2007-07-17 Debbie A. Cook - Original Version + * @history 2007-11-01 Debbie A. Cook - Revised to handle medium resolution camera + * @history 2008-06-18 Steven Lambright - Fixed documentation + */ + class LoCameraFiducialMap { + public: + //! Constructor + LoCameraFiducialMap ( PvlGroup &inst, const int naifIkCode ); + + //! Destructor + ~LoCameraFiducialMap (){}; + + private: + void ReadFiducials( PvlGroup &inst ); + void CreateTrans( int xdir ); + vector p_fidSamples; //!< Image sample positions of fiducial map + vector p_fidLines; //!< Image line positions of fiducial map + vector p_fidXCoords; //!< Focal plane X positions of fiducial map + vector p_fidYCoords; //!< Focal plane Y positions of fiducial map + int p_naifIkCode; //!< Naif instrument code + + }; + }; +}; +#endif diff --git a/isis/src/lo/objs/LoCameraFiducialMap/LoCameraFiducialMap.truth b/isis/src/lo/objs/LoCameraFiducialMap/LoCameraFiducialMap.truth new file mode 100644 index 0000000000000000000000000000000000000000..b8dd4fc99977163fdc75f764c7ba95eb6355b3d5 --- /dev/null +++ b/isis/src/lo/objs/LoCameraFiducialMap/LoCameraFiducialMap.truth @@ -0,0 +1,12 @@ +Unit Test for LoCameraFiducialMap... +Testing medium fiducial fit on a 100 x 100 cropped frame +Upper left corner OK +Upper right corner OK +Lower left corner OK +Lower right corner OK +Testing high fiducial fit on a full 34530 x 8750 frame +Upper left corner OK +Upper right corner OK +Lower left corner OK +Lower right corner OK +Center corner OK diff --git a/isis/src/lo/objs/LoCameraFiducialMap/Makefile b/isis/src/lo/objs/LoCameraFiducialMap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..181f35afbb48d956279a05db5bafad63b9301895 --- /dev/null +++ b/isis/src/lo/objs/LoCameraFiducialMap/Makefile @@ -0,0 +1,5 @@ +INCS = LoCameraFiducialMap.h +SRCS = LoCameraFiducialMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/lo/objs/LoCameraFiducialMap/unitTest.cpp b/isis/src/lo/objs/LoCameraFiducialMap/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bb6655b981553099568dc149beb4f4237fea3ba6 --- /dev/null +++ b/isis/src/lo/objs/LoCameraFiducialMap/unitTest.cpp @@ -0,0 +1,218 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "CameraFocalPlaneMap.h" +#include "iException.h" +#include "Preference.h" + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for LoCameraFiducialMap..." << endl; + + try{ + + std::cout << "Testing medium fiducial fit on a 100 x 100 cropped frame" << std::endl; + Isis::Pvl pm("$lo/testData/3083_med_raw.cub"); + Isis::Camera *camm = Isis::CameraFactory::Create(pm); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are correct + // Upper left pixel + double samp = 1.0; + double line = 1.0; + double knownUpperLeftX = 37.38041454316298; + double knownUpperLeftY = -31.62938549926507; + + // Now Convert from detector to distorted focal plane + if (camm->FocalPlaneMap()->SetDetector(samp,line)) { + double focalPlaneX = camm->FocalPlaneMap()->FocalPlaneX(); + double focalPlaneY = camm->FocalPlaneMap()->FocalPlaneY(); + if(fabs(focalPlaneX - knownUpperLeftX) < 1E-9 && + fabs(focalPlaneY - knownUpperLeftY) < 1E-9 ){ + cout << "Upper left corner OK" << endl; + } + else { + cout << setprecision(16) << "Upper left X off by: " << focalPlaneX - knownUpperLeftX << endl; + cout << setprecision(16) << "Upper left Y off by: " << focalPlaneY - knownUpperLeftY << endl; + } + } + + // Upper right pixel + samp = camm->Samples(); + double knownUpperRightX = 36.6926459512808; + double knownUpperRightY = -31.62980917422247; + + // Now Convert from detector to distorted focal plane + if (camm->FocalPlaneMap()->SetDetector(samp,line)) { + double focalPlaneX = camm->FocalPlaneMap()->FocalPlaneX(); + double focalPlaneY = camm->FocalPlaneMap()->FocalPlaneY(); + + if(fabs(focalPlaneX - knownUpperRightX) < 1E-9 && + fabs(focalPlaneY - knownUpperRightY) < 1E-9 ){ + cout << "Upper right corner OK" << endl; + } + else { + cout << setprecision(16) << "Upper right X off by: " << focalPlaneX - knownUpperRightX << endl; + cout << setprecision(16) << "Upper right Y off by: " << focalPlaneY - knownUpperRightY << endl; + } + } + + // Lower left pixel + samp = 1.0; + line = camm->Lines(); + double knownLowerLeftX = 37.37931706369603; + double knownLowerLeftY = -30.94212343336155; + + // Now Convert from detector to distorted focal plane + if (camm->FocalPlaneMap()->SetDetector(samp,line)) { + double focalPlaneX = camm->FocalPlaneMap()->FocalPlaneX(); + double focalPlaneY = camm->FocalPlaneMap()->FocalPlaneY(); + if(fabs(focalPlaneX - knownLowerLeftX) < 1E-9 && + fabs(focalPlaneY - knownLowerLeftY) < 1E-9 ){ + cout << "Lower left corner OK" << endl; + } + else { + cout << setprecision(16) << "Lower left X off by: " << focalPlaneX - knownLowerLeftX << endl; + cout << setprecision(16) << "Lower left Y off by: " << focalPlaneY - knownLowerLeftY << endl; + } + } + + // Lower right pixel + samp = camm->Samples(); + line = camm->Lines(); + double knownLowerRightX = 36.69154847181385; + double knownLowerRightY = -30.94254710831895; + + // Now Convert from detector to distorted focal plane + if (camm->FocalPlaneMap()->SetDetector(samp,line)) { + double focalPlaneX = camm->FocalPlaneMap()->FocalPlaneX(); + double focalPlaneY = camm->FocalPlaneMap()->FocalPlaneY(); + if(fabs(focalPlaneX - knownLowerRightX) < 1E-9 && + fabs(focalPlaneY - knownLowerRightY) < 1E-9 ){ + cout << "Lower right corner OK" << endl; + } + else { + cout << setprecision(16) << "Lower right X off by: " << focalPlaneX - knownLowerRightX << endl; + cout << setprecision(16) << "Lower right Y off by: " << focalPlaneY - knownLowerRightY << endl; + } + } + + std::cout << "Testing high fiducial fit on a full 34530 x 8750 frame" << std::endl; + Isis::Pvl ph("$lo/testData/4164H_Full_mirror.cub"); + Isis::Camera *camh = Isis::CameraFactory::Create(ph); + cout << setprecision(9); + + // Test all four corners and center pixel to make sure the conversions are correct + // Upper left pixel + samp = 1.0; + line = 1.0; + knownUpperLeftX = 125.8894771096694; + knownUpperLeftY = -31.23569821243375; + + // Now Convert from detector to distorted focal plane + if (camh->FocalPlaneMap()->SetDetector(samp,line)) { + double focalPlaneX = camh->FocalPlaneMap()->FocalPlaneX(); + double focalPlaneY = camh->FocalPlaneMap()->FocalPlaneY(); + if(fabs(focalPlaneX - knownUpperLeftX) < 1E-9 && + fabs(focalPlaneY - knownUpperLeftY) < 1E-9 ){ + cout << "Upper left corner OK" << endl; + } + else { + cout << setprecision(16) << "Upper left X off by: " << focalPlaneX - knownUpperLeftX << endl; + cout << setprecision(16) << "Upper left Y off by: " << focalPlaneY - knownUpperLeftY << endl; + } + } + + // Upper right pixel + samp = camh->Samples(); + knownUpperRightX = -114.13710918057000754; + knownUpperRightY = -31.21483142132193; + + // Now Convert from detector to distorted focal plane + if (camh->FocalPlaneMap()->SetDetector(samp,line)) { + double focalPlaneX = camh->FocalPlaneMap()->FocalPlaneX(); + double focalPlaneY = camh->FocalPlaneMap()->FocalPlaneY(); + + if(fabs(focalPlaneX - knownUpperRightX) < 1E-9 && + fabs(focalPlaneY - knownUpperRightY) < 1E-9 ){ + cout << "Upper right corner OK" << endl; + } + else { + cout << setprecision(18) << "Upper right X off by: " << focalPlaneX - knownUpperRightX << endl; + cout << setprecision(18) << "Upper right Y off by: " << focalPlaneY - knownUpperRightY << endl; + } + } + + // Lower left pixel + samp = 1.0; + line = camh->Lines(); + knownLowerLeftX = 125.9405233275204; + knownLowerLeftY = 29.52307388869981; + + // Now Convert from detector to distorted focal plane + if (camh->FocalPlaneMap()->SetDetector(samp,line)) { + double focalPlaneX = camh->FocalPlaneMap()->FocalPlaneX(); + double focalPlaneY = camh->FocalPlaneMap()->FocalPlaneY(); + if(fabs(focalPlaneX - knownLowerLeftX) < 1E-9 && + fabs(focalPlaneY - knownLowerLeftY) < 1E-9 ){ + cout << "Lower left corner OK" << endl; + } + else { + cout << setprecision(16) << "Lower left X off by: " << focalPlaneX - knownLowerLeftX << endl; + cout << setprecision(16) << "Lower left Y off by: " << focalPlaneY - knownLowerLeftY << endl; + } + } + + // Lower right pixel + samp = camh->Samples(); + line = camh->Lines(); + knownLowerRightX = -114.0860629627191; + knownLowerRightY = 29.54394067981162; + + // Now Convert from detector to distorted focal plane + if (camh->FocalPlaneMap()->SetDetector(samp,line)) { + double focalPlaneX = camh->FocalPlaneMap()->FocalPlaneX(); + double focalPlaneY = camh->FocalPlaneMap()->FocalPlaneY(); + if(fabs(focalPlaneX - knownLowerRightX) < 1E-9 && + fabs(focalPlaneY - knownLowerRightY) < 1E-9 ){ + cout << "Lower right corner OK" << endl; + } + else { + cout << setprecision(16) << "Lower right X off by: " << focalPlaneX - knownLowerRightX << endl; + cout << setprecision(16) << "Lower right Y off by: " << focalPlaneY - knownLowerRightY << endl; + } + } + + // Center pixel + samp = camh->Samples()/2; + line = camh->Lines()/2; + double knownCenterX = 5.90517988076963;//119.9912428434887; + double knownCenterY = -0.8493513951460194;//-30.39329207495764; + + // Now Convert from detector to distorted focal plane + if (camh->FocalPlaneMap()->SetDetector(samp,line)) { + double focalPlaneX = camh->FocalPlaneMap()->FocalPlaneX(); + double focalPlaneY = camh->FocalPlaneMap()->FocalPlaneY(); + if(fabs(focalPlaneX - knownCenterX) < 1E-9 && + fabs(focalPlaneY - knownCenterY) < 1E-9 ){ + cout << "Center corner OK" << endl; + } + else { + cout << setprecision(16) << "Center X off by: " << focalPlaneX - knownCenterX << endl; + cout << setprecision(16) << "Center Y off by: " << focalPlaneY - knownCenterY << endl; + } + } + + delete camh; + } + + catch (Isis::iException &e) { + e.Report(); + } +} + diff --git a/isis/src/lo/objs/LoHighCamera/Camera.plugin b/isis/src/lo/objs/LoHighCamera/Camera.plugin new file mode 100755 index 0000000000000000000000000000000000000000..10122d36ef608a80adf6e134f3a52b376475c531 --- /dev/null +++ b/isis/src/lo/objs/LoHighCamera/Camera.plugin @@ -0,0 +1,15 @@ +Group = LunarOrbiter3/HighResolutionCamera + Version = 1 + Library = LoHighCamera + Routine = LoHighCameraPlugin +EndGroup +Group = LunarOrbiter4/HighResolutionCamera + Version = 1 + Library = LoHighCamera + Routine = LoHighCameraPlugin +EndGroup +Group = LunarOrbiter5/HighResolutionCamera + Version = 1 + Library = LoHighCamera + Routine = LoHighCameraPlugin +EndGroup diff --git a/isis/src/lo/objs/LoHighCamera/LoHighCamera.cpp b/isis/src/lo/objs/LoHighCamera/LoHighCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a940639e9d57f8db6b5b5ed938b6053b3a5a8516 --- /dev/null +++ b/isis/src/lo/objs/LoHighCamera/LoHighCamera.cpp @@ -0,0 +1,60 @@ +#include "LoHighCamera.h" +#include "LoCameraFiducialMap.h" +#include "LoHighDistortionMap.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "iString.h" +#include "Affine.h" + +using namespace std; +namespace Isis { + namespace Lo { + // constructors + LoHighCamera::LoHighCamera (Pvl &lab) : FramingCamera(lab) { + // Get the Instrument label information needed to define the camera for this frame + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + iString spacecraft = (string)inst["SpacecraftName"]; + iString instId = (string)inst["InstrumentId"]; + + // Turn off the aberration corrections for the instrument position object + InstrumentPosition()->SetAberrationCorrection("NONE"); + + // Get the camera characteristics + SetFocalLength (); + SetPixelPitch (); + + // Get the start time in et + string stime = inst["StartTime"]; + double time; + str2et_c(stime.c_str(),&time); + + // Setup focal plane map + + LoCameraFiducialMap fid( inst, NaifIkCode()); + + // Setup detector map + new CameraDetectorMap(this); + + // Setup focalplane map + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + // Try (0.,0.) + focalMap->SetDetectorOrigin(0.0,0.0); + + // Setup distortion map + LoHighDistortionMap *distortionMap = new LoHighDistortionMap(this); + distortionMap->SetDistortion(NaifIkCode()); + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(time); + LoadCache(); + } + } +} + +extern "C" Isis::Camera *LoHighCameraPlugin(Isis::Pvl &lab) { + return new Isis::Lo::LoHighCamera(lab); +} diff --git a/isis/src/lo/objs/LoHighCamera/LoHighCamera.h b/isis/src/lo/objs/LoHighCamera/LoHighCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..84b69ccbd85ea28cde66b5ff1cc28579714d98fa --- /dev/null +++ b/isis/src/lo/objs/LoHighCamera/LoHighCamera.h @@ -0,0 +1,56 @@ +/** + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef LoHighCamera_h +#define LoHighCamera_h + +#include "FramingCamera.h" + +using namespace std; + +namespace Isis { + namespace Lo { + /** + * @brief Defines the Lunar Orbiter High Resolution camera class + * + * The LoHighCamera class defines the High Resolution camera for the last three + * Lunar Orbiter missions (3, 4, and 5). + * + * @ingroup SpiceInstrumentsAndCameras + * @ingroup LunarOrbiter + * + * @author 2007-07-17 Debbie A. Cook + * + * @internal + * @history 2007-07-17 Debbie A. Cook - Original Version + * @history 2008-08-08 Steven Lambright Made the unit test work with a Sensor + * change. Also, now using the new LoadCache(...) method instead of + * CreateCache(...). + * @history 2009-03-07 Debbie A. Cook Removed reference to obsolute CameraDetectorMap methods + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class LoHighCamera : public Isis::FramingCamera { + public: + LoHighCamera (Isis::Pvl &lab); + ~LoHighCamera () {}; + }; + }; +}; +#endif diff --git a/isis/src/lo/objs/LoHighCamera/LoHighCamera.truth b/isis/src/lo/objs/LoHighCamera/LoHighCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..05f2ff51f22f507de815f5992dc632fe2dce26da --- /dev/null +++ b/isis/src/lo/objs/LoHighCamera/LoHighCamera.truth @@ -0,0 +1,20 @@ +Unit Test for LoHighCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/lo/objs/LoHighCamera/LoHighDistortionMap.cpp b/isis/src/lo/objs/LoHighCamera/LoHighDistortionMap.cpp new file mode 100755 index 0000000000000000000000000000000000000000..5ea5c7737009db6d1c18daa0c646ffb1dd4a0a8b --- /dev/null +++ b/isis/src/lo/objs/LoHighCamera/LoHighDistortionMap.cpp @@ -0,0 +1,193 @@ +#include "LoHighDistortionMap.h" + +using namespace std; + +namespace Isis { + namespace Lo { + /** Constructor for LunarOrbiterHighDistortionMap class + * + * Define the distortion model coefficients for a Lunar Orbiter + * High Resolution camera. + * + * @param parent A pointer to the parent camera object + * + * @internal + * + * @history 2007-06-29 Debbie A. Cook Original version + * + */ + LoHighDistortionMap::LoHighDistortionMap (Camera *parent) : + CameraDistortionMap (parent,-1) { + } + + + /** Load LO High Resolution Camera perspective & distortion coefficients + * + * This method loads the perspective correction factors, distortion centers, + * and coefficients from the instrument kernel. The perspective correction + * factors in the NAIF instrument kernel are expected to be in the form of: + * + * @code + * INSxxxxxxx_PERSPECTIVE_FACTORS = ( xpers, ypers) + * + * where xxxxxxx is the instrument code (always a negative number) and + * xpers and ypers are the X and Y perspective correction factors. + * @endcode + * + * These factors will be used to convert from focal plane x,y to + * perspective-corrected x,y as follows. + * + * pcx = FocalPlaneX * ( 1. + xpers*FocalPlaneX + ypers*FocalPlaneY); + * pcy = FocalPlaneY * ( 1. + xpers*FocalPlaneX + ypers*FocalPlaneY); + * + * The distortion center coordinates (in mm) are expected to be in the form + * of: + * + * @code + * INSxxxxxxx_DISTORTION_CENTER = ( xcenter, ycenter) + * + * where xxxxxxx as is described above for the perspective factors. + * @endcode + * + * The center will be used to calculate the radius of distortion in the + * equations below. + * + * distX = PersCorrectedX - x0 + * distY = PersCorrectedY - y0 + * + * The distortion coefficients in the NAIF instrument + * kernel are expected to be in the form of: + * + * @code + * INSxxxxxxx_OD_K = ( coef1, coef2, ..., coefN) + * + * where xxxxxxx is as is described about for the perspective factors. + * @endcode + * + * These coefficient will be used to convert from focal plane x,y to + * to undistorted x,y as follows (add equation here) + * + * r^2 = DistX^2 + DistY^2 + * dr/r = k0 + k1*r^2 + * ux = PersCorrectedX - DistX*dr/r, similarly for uy + * + * @param naifIkCode Code to search for in instrument kernel + * */ + + void LoHighDistortionMap::SetDistortion(const int naifIkCode) { + // Get the perspective correction factors for x and y and the distortion + // center (point of symmetry of distortion) + std::string perskey = "INS" + Isis::iString(naifIkCode) + "_PERSPECTIVE_FACTORS"; + std::string centkey = "INS" + Isis::iString(naifIkCode) + "_POINT_OF_SYMMETRY"; + p_xPerspective = p_camera->Spice::GetDouble(perskey, 0); + p_yPerspective = p_camera->Spice::GetDouble(perskey, 1); + p_x0 = p_camera->Spice::GetDouble(centkey, 0); + p_y0 = p_camera->Spice::GetDouble(centkey, 1); + + // Get the distortion coefficients + CameraDistortionMap::SetDistortion (naifIkCode); + } + + + /** Compute undistorted focal plane x/y for Lo High Resolution Camera + * + * Compute undistorted focal plane x/y given a distorted focal plane x/y + * for the Lunar Orbiter High Resolution Camera. The polynomial used is + * described in the SetDistortion documentation. After calling this method, + * the undistorted x/y can be obtained via the UndistortedFocalPlaneX and + * UndistortedFocalPlaneY methods of the parent class. + * + * @param dx distorted focal plane x in millimeters + * @param dy distorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + */ + bool LoHighDistortionMap::SetFocalPlane(const double dx, + const double dy) { + p_focalPlaneX = dx; + p_focalPlaneY = dy; + + // Apply perspective correction factors to get perspective corrected x/y + double perspectiveFactor = 1. + (p_xPerspective * dx) + (p_yPerspective * dy); + double pcx = dx * perspectiveFactor; + double pcy = dy * perspectiveFactor; + + // Translate the perspective-corrected x/y coordinate to be relative to the + // distortion point of symmetry + double distx = pcx - p_x0; + double disty = pcy - p_y0; + + // Get the distance from the focal plane center and if we are close + // skip the distortion + double r2 = distx * distx + disty * disty; + if (r2 <= 1.0E-6) { + p_undistortedFocalPlaneX = pcx; + p_undistortedFocalPlaneY = pcy; + return true; + } + + // Otherwise remove distortion + double drOverR = p_odk[0] + p_odk[1]*r2; + p_undistortedFocalPlaneX = pcx - (drOverR * distx); + p_undistortedFocalPlaneY = pcy - (drOverR * disty); + return true; + } + + + /** Compute distorted focal plane x/y for Lo High Resolution Camera + * + * Compute distorted focal plane x/y given an undistorted focal plane x/y for + * the Lunar Orbiter High Resolution Camera. This method applies both a + * perspective error and a distortion error based on a polynomial defined + * in the SetDistortion method. After calling this method the distorted x/y + * can be obtained via the FocalPlaneX and FocalPlaneY methods. + * + * @param ux undistorted focal plane x in millimeters + * @param uy undistorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + */ + bool LoHighDistortionMap::SetUndistortedFocalPlane(const double ux, + const double uy) { + // Adjust for Z direction + double signFactor = fabs(p_zDirection)/p_zDirection; + + p_undistortedFocalPlaneX = ux*signFactor; + p_undistortedFocalPlaneY = uy*signFactor; + + // Translate the distorted x/y coordinate to be relative to the + // distortion point of symmetry + double distux = p_undistortedFocalPlaneX - p_x0; + double distuy = p_undistortedFocalPlaneY - p_y0; + + // Compute the distance from the focal plane center and if we are + // close to the center then no distortion is required + double rp2 = distux * distux + distuy * distuy; + + double pcx,pcy; + + if (rp2 > 1.0E-6) { + + // Add distortion. First compute fractional distortion at rp (r-prime) + double drOverR = p_odk[0] + rp2 * p_odk[1]; + + // Compute the perspective corrected x/y + pcx = p_undistortedFocalPlaneX + (distux * drOverR); + pcy = p_undistortedFocalPlaneY + (distuy * drOverR); + } + else { + pcx = p_undistortedFocalPlaneX; + pcy = p_undistortedFocalPlaneY; + } + + // Add the perspective error + double perspectiveCorrection = 1. - (p_xPerspective * pcx) - (p_yPerspective * pcy); + p_focalPlaneX = pcx * perspectiveCorrection; + p_focalPlaneY = pcy * perspectiveCorrection; + return true; + } + } + +} diff --git a/isis/src/lo/objs/LoHighCamera/LoHighDistortionMap.h b/isis/src/lo/objs/LoHighCamera/LoHighDistortionMap.h new file mode 100755 index 0000000000000000000000000000000000000000..c6897c22a85a7d1ca6300c6a6f2f8c35278be839 --- /dev/null +++ b/isis/src/lo/objs/LoHighCamera/LoHighDistortionMap.h @@ -0,0 +1,69 @@ +#ifndef LoHighDistortionMap_h +#define LoHighDistortionMap_h + +/** + * @file + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "CameraDistortionMap.h" + +namespace Isis { + namespace Lo { + /** Distort/undistort focal plane coordinates + * + * Creates a map for adding/removing optical distortions + * from the focal plane of the Lunar Orbiter high resolution camera. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2007-06-29 Debbie A. Cook - Original version + * @history 2008-02-04 Jeff Anderson - Made change to allow for + * variable focal length in THEMIS IR + * @history 2008-07-25 Steven Lambright - Fixed constructor; CameraDistortionMap + * is responsible both for setting the p_camera protected member and + * calling Camera::SetDistortionMap. When the parent called + * Camera::SetDistortionMap the Camera took ownership of the instance + * of this object. By calling this twice, and with Camera only + * supporting having one distortion map, this object was deleted before + * the constructor was finished. + */ + class LoHighDistortionMap : public CameraDistortionMap { + public: + LoHighDistortionMap(Camera *parent); + + void SetDistortion(const int naifIkCode); + virtual bool SetFocalPlane(const double dx, const double dy); + + virtual bool SetUndistortedFocalPlane(const double ux, const double uy); + + private: + double p_xPerspective; /* Perspective correction factor in x */ + double p_yPerspective; /* Perspective correction factor in y */ + double p_x0; /* Center of distortion on x axis */ + double p_y0; /* Center of distortion on y axis */ + std::vector p_coefs; + std::vector p_icoefs; + }; + }; +}; +#endif diff --git a/isis/src/lo/objs/LoHighCamera/Makefile b/isis/src/lo/objs/LoHighCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..267f97f599689d0149c2105fbfa9fda48b55cf75 --- /dev/null +++ b/isis/src/lo/objs/LoHighCamera/Makefile @@ -0,0 +1,5 @@ +INCS = LoHighCamera.h LoHighDistortionMap.h +SRCS = LoHighCamera.cpp LoHighDistortionMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/lo/objs/LoHighCamera/unitTest.cpp b/isis/src/lo/objs/LoHighCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70b830e8d786df75f59a15708052a91702d4b265 --- /dev/null +++ b/isis/src/lo/objs/LoHighCamera/unitTest.cpp @@ -0,0 +1,91 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for LoHighCamera..." << endl; + /** + * LO: DeltaSample/Line tolerance increased for this mission. + */ + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownLat = 69.15786682597842; + double knownLon = 317.6381881472366; + + Isis::Pvl p("$lo/testData/4164H_Full_mirror.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.1) deltaSamp = 0; + if (fabs(deltaLine) < 0.1) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} diff --git a/isis/src/lo/objs/LoMediumCamera/Camera.plugin b/isis/src/lo/objs/LoMediumCamera/Camera.plugin new file mode 100755 index 0000000000000000000000000000000000000000..f380ebb7628578e965d4b51d6b18e9c5591d59a6 --- /dev/null +++ b/isis/src/lo/objs/LoMediumCamera/Camera.plugin @@ -0,0 +1,15 @@ +Group = LunarOrbiter3/MediumResolutionCamera + Version = 1 + Library = LoMediumCamera + Routine = LoMediumCameraPlugin +EndGroup +Group = LunarOrbiter4/MediumResolutionCamera + Version = 1 + Library = LoMediumCamera + Routine = LoMediumCameraPlugin +EndGroup +Group = LunarOrbiter5/MediumResolutionCamera + Version = 1 + Library = LoMediumCamera + Routine = LoMediumCameraPlugin +EndGroup diff --git a/isis/src/lo/objs/LoMediumCamera/LoMediumCamera.cpp b/isis/src/lo/objs/LoMediumCamera/LoMediumCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f749f3e57d27a92daa8556c388181e1210ed5812 --- /dev/null +++ b/isis/src/lo/objs/LoMediumCamera/LoMediumCamera.cpp @@ -0,0 +1,81 @@ +#include "LoMediumCamera.h" +#include "LoCameraFiducialMap.h" +#include "LoMediumDistortionMap.h" +#include "CameraDistortionMap.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "iString.h" +#include "Affine.h" + +using namespace std; +namespace Isis { + namespace Lo { + // constructors + LoMediumCamera::LoMediumCamera (Pvl &lab) : FramingCamera(lab) { + // Get the Instrument label information needed to define the camera for this frame + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + iString spacecraft = (string)inst["SpacecraftName"]; + iString instId = (string)inst["InstrumentId"]; + + LoMediumCamera::FocalPlaneMapType type; + if (inst.HasKeyword("FiducialSamples")) { + type = Fiducial; + } + else if (inst.HasKeyword("BoresightSample")) { + type = Boresight; + } + else { + std::string msg = "Unknown focal plane map type: "; + msg += "Labels must include fiducials or boresight"; + throw Isis::iException::Message(iException::User,msg,_FILEINFO_); + } + + // Turn off the aberration corrections for the instrument position object + InstrumentPosition()->SetAberrationCorrection("NONE"); + + // Get the camera characteristics + SetFocalLength (); + SetPixelPitch (); + + // Get the start time in et + string stime = inst["StartTime"]; + double time; + str2et_c(stime.c_str(),&time); + + // Setup focal plane map + if (type == Fiducial) { + LoCameraFiducialMap fid( inst, NaifIkCode()); + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + // Try (0.,0.) + focalMap->SetDetectorOrigin(0.0,0.0); + + } + else { + // Read boresight + double boresightSample = inst["BoresightSample"]; + double boresightLine = inst["BoresightLine"]; + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + focalMap->SetDetectorOrigin(boresightSample,boresightLine); + } + + // Setup detector map + new CameraDetectorMap(this); + + // Setup distortion map + LoMediumDistortionMap *distortionMap = new LoMediumDistortionMap(this); + distortionMap->SetDistortion(NaifIkCode()); + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(time); + LoadCache(); + } + } +} + +extern "C" Isis::Camera *LoMediumCameraPlugin(Isis::Pvl &lab) { + return new Isis::Lo::LoMediumCamera(lab); +} diff --git a/isis/src/lo/objs/LoMediumCamera/LoMediumCamera.h b/isis/src/lo/objs/LoMediumCamera/LoMediumCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..cbbc7607b8378c7965972c785844522d78f9887c --- /dev/null +++ b/isis/src/lo/objs/LoMediumCamera/LoMediumCamera.h @@ -0,0 +1,58 @@ +/** + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#ifndef LoMediumCamera_h +#define LoMediumCamera_h + +#include "FramingCamera.h" + +using namespace std; + +namespace Isis { + namespace Lo { + /** + * @brief Defines the Lunar Orbiter Medium Resolution camera class + * + * The LoHighCamera class defines the High Resolution camera for the last three + * Lunar Orbiter missions (3, 4, and 5). + * + * @ingroup SpiceInstrumentsAndCameras + * @ingroup LunarOrbiter + * + * @author 2007-07-17 Debbie A. Cook + * + * @internal + * @history 2007-07-17 Debbie A. Cook - Original Version + * @history 2008-04-07 Debbie A. Cook - Set x/y axis directions for jigsaw + * @history 2008-08-08 Steven Lambright Made the unit test work with a Sensor + * change. Also, now using the new LoadCache(...) method instead of + * CreateCache(...). + * @history 2009-03-07 Debbie A. Cook Removed reference to obsolute CameraDetectorMap methods + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class LoMediumCamera : public Isis::FramingCamera { + public: + LoMediumCamera (Isis::Pvl &lab); + ~LoMediumCamera () {}; + enum FocalPlaneMapType {Fiducial,Boresight,None}; + }; + }; +}; +#endif diff --git a/isis/src/lo/objs/LoMediumCamera/LoMediumCamera.truth b/isis/src/lo/objs/LoMediumCamera/LoMediumCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..6acacb915a0e1ae7063de918702f784d07155489 --- /dev/null +++ b/isis/src/lo/objs/LoMediumCamera/LoMediumCamera.truth @@ -0,0 +1,20 @@ +Unit Test for LoMediumCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/lo/objs/LoMediumCamera/LoMediumDistortionMap.cpp b/isis/src/lo/objs/LoMediumCamera/LoMediumDistortionMap.cpp new file mode 100755 index 0000000000000000000000000000000000000000..c9791a3196df0618b3e3279dc0a24617c6e01b51 --- /dev/null +++ b/isis/src/lo/objs/LoMediumCamera/LoMediumDistortionMap.cpp @@ -0,0 +1,230 @@ +#include +#include + +#include "LoMediumDistortionMap.h" +#include "CameraFocalPlaneMap.h" + +using namespace std; + +namespace Isis { + namespace Lo { + /** Constructor for LunarOrbiterMediumDistortionMap class + * + * Define the distortion model coefficients for a Lunar Orbiter + * Medium Resolution camera. + * + * @param parent A pointer to the parent camera object + * + * @internal + * + * @history 2007-07-31 Debbie A. Cook Original version + * + */ + LoMediumDistortionMap::LoMediumDistortionMap (Camera *parent) : + CameraDistortionMap (parent,-1) { + } + + + /** Load LO Medium Resolution Camera perspective & distortion coefficients + * + * This method loads the distortion centers, and coefficients from the + * instrument kernel. * The distortion center coordinates (in mm) are + * expected to be in the form of: + * + * @code + * INSxxxxxxx_DISTORTION_CENTER = ( xcenter, ycenter) + * + * where xxxxxxx is the instrument code (always a negative number). + * @endcode + * + * The center, (x0,y0), will be used to calculate the radius of distortion, + * r, in the equations below. + * + * distX = x - x0 + * distY = y - y0, where (x,y) are the distorted focal plane coordinates. + * r^2 = (DistX^2 + DistY^2)/sref^2 + * + * The distortion coefficients in the NAIF instrument + * kernel are expected to be in the form of: + * + * @code + * INSxxxxxxx_OD_K = ( coef1, coef2, ..., coefN) + * + * where xxxxxxx is as is described above for the distortion center. + * @endcode + * + * These coefficient will be used to convert from focal plane x,y to + * to undistorted x,y as follows: + * + * dr/r = (k0 + k1*r^2 + k2*r^4)/sref + * ux = x - DistX*dr/r, similarly for uy + * + * @param naifIkCode Code to search for in instrument kernel + * */ + + void LoMediumDistortionMap::SetDistortion(const int naifIkCode) { + // Get the distortion center (point of symmetry of distortion) + p_camera->FocalPlaneMap()->SetFocalPlane(0., 0.); + double boreS = p_camera->FocalPlaneMap()->DetectorSample(); + double boreL = p_camera->FocalPlaneMap()->DetectorLine(); + std::string centkey = "INS" + Isis::iString(naifIkCode) + "_POINT_OF_SYMMETRY"; + p_sample0 = boreS - p_camera->Spice::GetDouble(centkey, 0); + p_line0 = boreL + p_camera->Spice::GetDouble(centkey, 1); + + // Get the distortion coefficients + CameraDistortionMap::SetDistortion (naifIkCode); + } + + + /** Compute undistorted focal plane x/y for Lo Medium Resolution Camera + * + * Compute undistorted focal plane x/y given a distorted focal plane x/y + * for the Lunar Orbiter Medium Resolution Camera. The polynomial used is + * described in the SetDistortion documentation. After calling this method, + * the undistorted x/y can be obtained via the UndistortedFocalPlaneX and + * UndistortedFocalPlaneY methods of the parent class. + * + * @param dx distorted focal plane x in millimeters + * @param dy distorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + */ + bool LoMediumDistortionMap::SetFocalPlane(const double dx, + const double dy) { + + // Set sRef needed for lo medium distortion algorithm + double sRef = 5000.; + + // lo medium distortion algorithm is applied in the image plane so convert back to sample/line + p_focalPlaneX = dx; + p_focalPlaneY = dy; + + // Test for extraneous data. Maximum x is about 38.045 and maximum y is about 31.899. + // First tried adding 10% and it was sufficient to trim off extraneous data, but + // also prevented lat/lons from being calculated to the images edges. Increased x to + // 20.361224% to pick up image edges. 3171 was the test image. + // 17.5% to pick up image edges. 3171 was the test image. + if (fabs(dx) > 45.79142767 || fabs(dy) > 35.09) return false; + + p_camera->FocalPlaneMap()->SetFocalPlane(dx, dy); + double ds = p_camera->FocalPlaneMap()->DetectorSample(); + double dl = p_camera->FocalPlaneMap()->DetectorLine(); + + // Translate the focal plane x/y coordinate to be relative to the + // distortion point of symmetry + double dists = ds - p_sample0; + double distl = dl - p_line0; + + // Get the distance from the focal plane center and if we are close + // skip the distortion + double origr2 = dists * dists + distl * distl; + double sp = sqrt(origr2); // pixels + if (sp <= .000001) { + p_undistortedFocalPlaneX = dx; + p_undistortedFocalPlaneY = dy; + return true; + } + + // Otherwise remove distortion + // Use the distorted radial coordinate, rp (r prime), to estimate the ideal radial coordinate + double nS = sp/sRef; + double dS = p_odk[0]*nS + p_odk[1]*pow(nS,3) + p_odk[2]*pow(nS,5); + double prevdS = 2*dS; + double pixtol = .000001; + int numit=0; + double s; + + // Now use the estimate to compute the radial coordinate and get an improved estimate + while (fabs(dS-prevdS) > pixtol) { + + if (numit > 14 || fabs(dS) > 1E9) { + dS = 0.; + // if (numit > 14) std::cout<<"Too many iterations"< 1E9) std::cout<<"Diverging"<FocalPlaneMap()->SetDetector(undistortedSample, undistortedLine); + p_undistortedFocalPlaneX = p_camera->FocalPlaneMap()->FocalPlaneX(); + p_undistortedFocalPlaneY = p_camera->FocalPlaneMap()->FocalPlaneY(); + return true; + } + + + /** Compute distorted focal plane x/y for Lo Medium Resolution Camera + * + * Compute distorted focal plane x/y given an undistorted focal plane x/y for + * the Lunar Orbiter Medium Resolution Camera. This method applies a + * distortion error based on a polynomial defined in the SetDistortion + * method. After calling this method the distorted x/y can be obtained via + * the FocalPlaneX and FocalPlaneY methods. + * + * @param ux undistorted focal plane x in millimeters + * @param uy undistorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + */ + bool LoMediumDistortionMap::SetUndistortedFocalPlane(const double ux, + const double uy) { + // Adjust for Z direction + double signFactor = fabs(p_zDirection)/p_zDirection; + + p_undistortedFocalPlaneX = ux*signFactor; + p_undistortedFocalPlaneY = uy*signFactor; + + // Test for data outside of image (image bounds plus 10% for y and 20.361224% for x) + if (fabs(ux) > 45.79142767 || fabs(uy) > 35.09) return false; + if (fabs(ux) > 41.85 || fabs(uy) > 35.09) return false; + + // Set sRef needed for lo medium distortion algorithm + double sRef = 5000.; + + // The algorithm is applied in the image plane so convert back to sample/line + p_camera->FocalPlaneMap()->SetFocalPlane(p_undistortedFocalPlaneX, p_undistortedFocalPlaneY); + double us = p_camera->FocalPlaneMap()->DetectorSample(); + double ul = p_camera->FocalPlaneMap()->DetectorLine(); + + // Translate the distorted x/y coordinate to be relative to the + // distortion point of symmetry + double distus = us - p_sample0; + double distul = ul - p_line0; + + // Compute the distance from the focal plane center and if we are + // close to the center then no distortion is required + double rp2 = (distus * distus + distul * distul); // pixels squared + + if (rp2 < 1.0E-6) { + p_focalPlaneX = p_undistortedFocalPlaneX; + p_focalPlaneY = p_undistortedFocalPlaneY; + return true; + } + + // Add distortion. First compute fractional distortion at rp (r-prime) + rp2 = rp2/sRef/sRef; + double drOverR = (p_odk[0] + rp2*p_odk[1] + rp2*rp2*p_odk[2])/sRef; + + // Compute the focal plane distorted s/l + double ds = p_sample0 + (distus * (1. + drOverR) ); + double dl = p_line0 + (distul * (1. + drOverR) ); + + p_camera->FocalPlaneMap()->SetDetector(ds, dl); + p_focalPlaneX = p_camera->FocalPlaneMap()->FocalPlaneX(); + p_focalPlaneY = p_camera->FocalPlaneMap()->FocalPlaneY(); + return true; + } + } + +} diff --git a/isis/src/lo/objs/LoMediumCamera/LoMediumDistortionMap.h b/isis/src/lo/objs/LoMediumCamera/LoMediumDistortionMap.h new file mode 100755 index 0000000000000000000000000000000000000000..24744d76347097a74d6f6fd22cab16af1b8c8fdc --- /dev/null +++ b/isis/src/lo/objs/LoMediumCamera/LoMediumDistortionMap.h @@ -0,0 +1,57 @@ +#ifndef LoMediumDistortionMap_h +#define LoMediumDistortionMap_h + +#include +#include "CameraDistortionMap.h" + +namespace Isis { + namespace Lo { + /** Distort/undistort focal plane coordinates + * + * Creates a map for adding/removing optical distortions + * from the focal plane of the Lunar Orbiter medium resolution camera. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2007-07-31 Debbie A. Cook - Original version + * @history 2008-02-04 Jeff Anderson - Made change to support variable + * focal length in THEMIS IR camera + * @history 2008-07-25 Steven Lambright - Fixed constructor; CameraDistortionMap + * is responsible both for setting the p_camera protected member and + * calling Camera::SetDistortionMap. When the parent called + * Camera::SetDistortionMap the Camera took ownership of the instance + * of this object. By calling this twice, and with Camera only + * supporting having one distortion map, this object was deleted before + * the constructor was finished. + * @history 2009-05-22 Debbie A. Cook - Cleaned up code and added iteration loop. Previous + * version only iterated twice, but results indicated more iterations were + * needed for better accuracy. + * @history 2009-08-21 Debbie A. Cook - Added test for data outside focal plane limits + * plus 10% to avoid getting erroneous data projected on oblique images + * @history 2010-01-25 Debbie A. Cook - Increased out-of-bounds test to 17.5% of fiducial max + * to make sure lat/lons were defined to the image edges + * + */ + class LoMediumDistortionMap : public CameraDistortionMap { + public: + LoMediumDistortionMap(Camera *parent); + + void SetDistortion(const int naifIkCode); + virtual bool SetFocalPlane(const double dx, const double dy); + + virtual bool SetUndistortedFocalPlane(const double ux, const double uy); + + private: + double p_sample0; /* Center of distortion on sample axis */ + double p_line0; /* Center of distortion on line axis */ + std::vector p_coefs; + std::vector p_icoefs; + }; + }; +}; + +#endif diff --git a/isis/src/lo/objs/LoMediumCamera/Makefile b/isis/src/lo/objs/LoMediumCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c0188ef656fe9c0c007bc03e6b3a586241bba4a5 --- /dev/null +++ b/isis/src/lo/objs/LoMediumCamera/Makefile @@ -0,0 +1,5 @@ +INCS = LoMediumCamera.h LoMediumDistortionMap.h +SRCS = LoMediumCamera.cpp LoMediumDistortionMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/lo/objs/LoMediumCamera/unitTest.cpp b/isis/src/lo/objs/LoMediumCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..89e1baa386bec3cae72bffcc0ec16476cc6c1441 --- /dev/null +++ b/isis/src/lo/objs/LoMediumCamera/unitTest.cpp @@ -0,0 +1,93 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for LoMediumCamera..." << endl; + /** + * LO: DeltaSample/Line tolerance increased for this mission. + */ + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + // double knownLat = -2.432877580154799; + // double knownLon = 13.554396715197; + double knownLat = -2.432887257324968; + double knownLon = 13.55438058072546; + + Isis::Pvl p("$lo/testData/3083_med_tohi.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.25) deltaSamp = 0; + if (fabs(deltaLine) < 0.25) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} diff --git a/isis/src/lo/objs/Makefile b/isis/src/lo/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/lo/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/local/Makefile b/isis/src/local/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/local/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/local/apps/Makefile b/isis/src/local/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/local/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/local/apps/basemapmos/Makefile b/isis/src/local/apps/basemapmos/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/local/apps/basemapmos/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/local/apps/basemapmos/assets/cubes.lis b/isis/src/local/apps/basemapmos/assets/cubes.lis new file mode 100644 index 0000000000000000000000000000000000000000..29a2c43943159ba6b611382680bc23c3b9d8413b --- /dev/null +++ b/isis/src/local/apps/basemapmos/assets/cubes.lis @@ -0,0 +1,3 @@ +cube1.cub +cube2.cub +cube3.cub diff --git a/isis/src/local/apps/basemapmos/assets/images/basemapresult.jpg b/isis/src/local/apps/basemapmos/assets/images/basemapresult.jpg new file mode 100644 index 0000000000000000000000000000000000000000..60852b5a7be3a2f0d0833feb4fc3fe80875bb9c6 Binary files /dev/null and b/isis/src/local/apps/basemapmos/assets/images/basemapresult.jpg differ diff --git a/isis/src/local/apps/basemapmos/assets/images/cube1.jpg b/isis/src/local/apps/basemapmos/assets/images/cube1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e58ee74562b3091503529e9c6eaea99d4f8c492a Binary files /dev/null and b/isis/src/local/apps/basemapmos/assets/images/cube1.jpg differ diff --git a/isis/src/local/apps/basemapmos/assets/images/cube2.jpg b/isis/src/local/apps/basemapmos/assets/images/cube2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..be87b7148e3c858df9e5276e15c8f66eac84338e Binary files /dev/null and b/isis/src/local/apps/basemapmos/assets/images/cube2.jpg differ diff --git a/isis/src/local/apps/basemapmos/assets/images/cube3.jpg b/isis/src/local/apps/basemapmos/assets/images/cube3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..37e71a4195bc2e76b4faf7a6892a4e6f58ca5782 Binary files /dev/null and b/isis/src/local/apps/basemapmos/assets/images/cube3.jpg differ diff --git a/isis/src/local/apps/basemapmos/assets/thumbs/basemapresultthumb.jpg b/isis/src/local/apps/basemapmos/assets/thumbs/basemapresultthumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8ecd741953cdead23e7b6a6343f9688531e54b9b Binary files /dev/null and b/isis/src/local/apps/basemapmos/assets/thumbs/basemapresultthumb.jpg differ diff --git a/isis/src/local/apps/basemapmos/basemapmos.cpp b/isis/src/local/apps/basemapmos/basemapmos.cpp new file mode 100644 index 0000000000000000000000000000000000000000..45e87221d7b79e136d68bc86e8fe15efe432feb7 --- /dev/null +++ b/isis/src/local/apps/basemapmos/basemapmos.cpp @@ -0,0 +1,154 @@ +#include "Isis.h" +#include "Application.h" +#include "FileList.h" +#include "Cube.h" + +#include +#include + +using namespace std; +using namespace Isis; + +void IsisMain() { + + //Get user parameters + UserInterface &ui = Application::GetUserInterface(); + FileList cubes; + cubes.Read(ui.GetFilename("FROMLIST")); + string PRIORITY = ui.GetString("PRIORITY"); + string HNS1 = ui.GetAsString("HNS1"); + string HNL1 = ui.GetAsString("HNL1"); + string HNS2 = ui.GetAsString("HNS2"); + string HNL2 = ui.GetAsString("HNL2"); + string LNS = ui.GetAsString("LNS"); + string LNL = ui.GetAsString("LNL"); + string GRANGE = ui.GetString("GRANGE"); + string MINLAT, MAXLAT, MINLON, MAXLON; + if( GRANGE == "USER" ) { + MINLAT = ui.GetAsString("MINLAT"); + MAXLAT = ui.GetAsString("MAXLAT"); + MINLON = ui.GetAsString("MINLON"); + MAXLON = ui.GetAsString("MAXLON"); + } + string MATCHBANDBIN = ui.GetAsString("MATCHBANDBIN"); + + // Sets up the pathName to be used for most application calls + string pathName = Filename("$TEMPORARY/").Path() + "/"; + string cubeListBaseName = pathName + Filename(ui.GetFilename("FROMLIST")).Basename(); + + //Creates the first highpass cubes + std::ofstream firstHighPassList; + string firstHighPass(cubeListBaseName + "_FirstHighPassList.lis"); + firstHighPassList.open(firstHighPass.c_str() ); + for ( unsigned i=0; iExec("lowpass",parameters); + + //Finally combines the first highpass and lowpass mosaics + parameters = "FROM1=" + cubeListBaseName + "_newmosFirst.cub" + + " FROM2=" + cubeListBaseName + "_lpfmos.cub" + + " TO= " + cubeListBaseName + "_untrimmedmoc.cub" + + " OPERATOR= add"; + Isis::iApp ->Exec("algebra",parameters); + + //Concludes with a maptrim of the final product + parameters = "FROM=" + cubeListBaseName + "_untrimmedmoc.cub" + + " TO=" + ui.GetAsString("TO"); + if( GRANGE == "USER" ) { + parameters += " MINLAT= " + MINLAT + + " MINLON= " + MINLON + + " MAXLAT= " + MAXLAT + + " MAXLON= " + MAXLON; + } + Isis::iApp ->Exec("maptrim",parameters); + + + //Will remove all of the temp files by default + if ( ui.GetBoolean("REMOVETEMP") ) { + string newmosFirst(cubeListBaseName + "_newmosFirst.cub"); + string newmosSecond(cubeListBaseName + "_newmosSecond.cub"); + string lpfmos(cubeListBaseName + "_lpfmos.cub"); + string untrimmedmoc(cubeListBaseName + "_untrimmedmoc.cub"); + remove(firstHighPass.c_str() ); + remove(secondHighPass.c_str() ); + remove(newmosFirst.c_str() ); + remove(newmosSecond.c_str() ); + remove(lpfmos.c_str() ); + remove(untrimmedmoc.c_str() ); + for ( unsigned i=0; i + + + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://isis.astrogeology.usgs.gov/Schemas/Application/application.xsd"> + + Creates a flattened mosaic using a list of map projected cubes + + + This program uses a text-based list of cubes, all in the same map projection + and equivalent projection parameters (PixelResolution, CenterLongitude, + LatitudeSystem, etc), to generate a flattened mosaic. The size of the + mosaic will be determined automatically unless specified by the user. In + addition, this final mosaic will be trimmed as a final step. This trim will + be determined automatically unless specified by the user. + + + + Mosaicking + + + + + Original version + + + Added a maptrim execution to the final product. + + + Added the Priority parameter. + + + Fixed handling of temporary files + + + + + + + + filename + input + + List of cubes to mosaic + + + A list of map projected cubes to mosaic and flatten. The Mapping + groups must match in order to mosaic the cubes. Also, this list + should be in the same directory as the input cubes listed by the list. + + + *.txt *.lis *.lst + + + + cube + output + + Mosaic output cube + + + The trimmed flattened mosaic cube which is created from the cubes + listed by the input list. + + + *.cub + + + + + string + + ONTOP + + The priority of pixel placement + + This parameter is used to select one of two ways to mosaic the + pixels in areas of overlap. + + + + + + + + + + + + integer + 101 + + Number of samples in the first high frequency data boxcar + + This is the total number of samples in the first high frequency data + boxcar. It must be odd and can not exceed twice the number of samples + in the input cubes. In general, the size of the boxcar should be specified and does not cause + the program to operate significantly slower. + + + 1 + + + integer + 101 + + Number of lines in the first high frequency data boxcar + + This is the total number of lines in the second high + frequency data boxcar. It must be odd and can not exceed twice the + number of lines in the input cubes. In general, the size of the + boxcar should be specified and does not cause the program to operate + significantly slower. + + + 1should be specified and + + + integer + 501 + Number of samples in the second high frequency data boxcar + + This is the total number of samples in the second high + frequency data boxcar. It must be odd and can not exceed twice the + number of samples in the input cubes. In general, the size of the + boxcar should be specified and does not cause the program to operate significantly slower. + + + 1 + + + integer + 501 + + Number of lines in the second high frequency data boxcar + + This is the total number of lines in the second high + frequency data boxcar. It must be odd and can not exceed twice the + number of lines in the input cubes. In general, the size of the + boxcar should be specified and does not cause the program to operate significantly slower. + + + 1 + + + integer + 101 + + Number of samples in low frequency data boxcar + + + This is the total number of samples in the low frequency data boxcar. + It must be odd and can not exceed twice the number of samples in the + output mosaic. In general, the size of the boxcar should be specified + and does not cause the program to operate significantly slower. + + + 1 + + + integer + 101 + + Number of lines in low frequency data boxcar + + + This is the total number of lines in the low frequency data boxcar. It + must be odd and can not exceed twice the number of lines in the output + mosaic. In general, the size of the boxcar should be specified and + does not cause the program to operate significantly slower. + + + 1 + + + + + + string + AUTO + Ground Range Options + + The ground range can either be calculated automatically or entered by the user. + If the USER option is selected, values must be entered for the MINLAT, MAXLAT, + MINLON, and MAXLON parameters. AUTO is the default for this parameter. + + + + + + + + double + Minimum Latitude + + The minimum latitude value to use in the mosaic. + + + + double + Maximum Latitude + + The maximum latitude value to use in the mosaic. + + + + double + Minimum Longitude + + The minimum longitude value to use in the mosaic. + + + + double + Maximum Longitude + + The maximum longitude value to use in the mosaic. + + + + + + + boolean + TRUE + Enforce BandBin Group Match + + This option causes the application to fail if the input bandbin group does not + match the mosaic bandbin group.

    NOTE: In the case of failure, + intermediate data may not be removed. + + + + + + + boolean + + TRUE + + + Destroy intermediate data + + + Multiple cube images as well as lists are created durring the + production of the final flattened mosaic. If this parameter is + changed to false, those temporary cubes and lists will not be removed. + REMOVETEMP should only be set to false when your current directory + contains the input list as well as all of the input cubes. Otherwise, + all intermediate lists will be created in the current directory, and + all of the intermediate cubes will be created in the same directory as + the input cubes. + + + + + + + + + + Basemapmos Result + + This example shows how basemapmos works upon a small mosaic. + + + + FROMLIST=cubes.lis + TO=final.cub HNS1=73 HNL1=73 HNS2=103 HNL2=103 LNS=83 + LNL=83 + + Runs basemapmos with the first highpass filter being 73x73, + the second highpass filter being 103x103, and a 83x83 + lowpass filter. + + + + + + cubes.lis + + This is a simple file that lists all of the cubes to mosaic. + This list as well as the cubes to be mosaiced should + be within the current directory when noseam is executed. + + FROMLIST + + + + + + First listed cube + + This is the first cube listed in cubes.lis + + + + + Second listed cube + + This is the second cube listed in cubes.lis + + + + + Third listed cube + + This is the third cube listed in cubes.lis + + + + + + + + The resulting mosaic + + This is the resulting mosaic final.cub. + + + TO + + + + + + + + diff --git a/isis/src/local/apps/basemapmos/tsts/Makefile b/isis/src/local/apps/basemapmos/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/local/apps/basemapmos/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/local/apps/basemapmos/tsts/default/Makefile b/isis/src/local/apps/basemapmos/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0e098352663ba74adbedf70585e47cf871e4bb5c --- /dev/null +++ b/isis/src/local/apps/basemapmos/tsts/default/Makefile @@ -0,0 +1,14 @@ +APPNAME = basemapmos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/* > $(OUTPUT)/cubes.lis; + $(APPNAME) FROMLIST=$(OUTPUT)/cubes.lis \ + TO=$(OUTPUT)/result.cub \ + HNS1=73 HNL1=73 HNS2=103 HNL2=103 LNS=83 LNL=83 > /dev/null; + $(APPNAME) FROMLIST=$(OUTPUT)/cubes.lis \ + TO=$(OUTPUT)/userrangeresult.cub \ + GRANGE=USER MINLAT=18 MAXLAT=37 MINLON=12 MAXLON=28 \ + HNS1=73 HNL1=73 HNS2=103 HNL2=103 LNS=83 LNL=83 > /dev/null; + $(RM) $(OUTPUT)/cubes.lis; diff --git a/isis/src/local/apps/camcoeffs/Makefile b/isis/src/local/apps/camcoeffs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/local/apps/camcoeffs/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/local/apps/camcoeffs/assets/output.txt b/isis/src/local/apps/camcoeffs/assets/output.txt new file mode 100644 index 0000000000000000000000000000000000000000..8904b421f6590928e017395ee0c46dfe4dbbbe63 --- /dev/null +++ b/isis/src/local/apps/camcoeffs/assets/output.txt @@ -0,0 +1,6 @@ +Results + INS-41219_TRANSX = (0.2589180702, -0.0069999992, 3.3598e-06) + INS-41219_TRANSY = (-59.9867757282, 3.3598e-06, -0.0069999992) + INS-41219_TRANSS = (32.875172540392, -142.85719209406, -0.068567378407362) + INS-41219_TRANSL = (-8569.5245899736, -0.068567378407362, -142.85719209406) +End_Group diff --git a/isis/src/local/apps/camcoeffs/camcoeffs.cpp b/isis/src/local/apps/camcoeffs/camcoeffs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1516d55ce44b410e027424beff2ecb1972f756e --- /dev/null +++ b/isis/src/local/apps/camcoeffs/camcoeffs.cpp @@ -0,0 +1,185 @@ +#include "Isis.h" + +#include +#include + +#include "iException.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + + double eq1[] = { + ui.GetDouble("XCONSTCOEF"), + ui.GetDouble("XSAMPLECOEF"), + ui.GetDouble("XLINECOEF"), + }; + double eq2[] = { + ui.GetDouble("YCONSTCOEF"), + ui.GetDouble("YSAMPLECOEF"), + ui.GetDouble("YLINECOEF"), + }; + + double res1[3] = {0.0,0.0,0.0}; + double res2[3] = {0.0,0.0,0.0}; + + bool solutionFound = false; + + /** + * Do this loop in order to shorten the number of solutions we have + * to program in. This halves the number of cases by saying "What if equation 1 + * is really equation 2, and equation 2 is really equation 1?" The solution + * will also be flipped, which is handled if order becomes 1. + * + * order = 0 means the equations are in their original form, order = 1 means + * they were swapped. + */ + for(int order = 0; !solutionFound && order < 2; order++) { + double A = eq1[0]; + double B = eq1[1]; + double C = eq1[2]; + double D = eq2[0]; + double E = eq2[1]; + double F = eq2[2]; + + if(order == 1) { + A = eq2[0]; + B = eq2[1]; + C = eq2[2]; + D = eq1[0]; + E = eq1[1]; + F = eq1[2]; + } + + solutionFound = true; + + // These are used to test solution dependencies, they become zero if the + // equations are parallel and thus unsolvable + double denomX = (F==0)? 0.0 : B - (E * C / F); + double denomY = (E==0)? 0.0 : C - (F * B / E); + if(B != 0 && E != 0 && F != 0 && denomX != 0 && denomY != 0) { + /** + * Input Equations: + * X = A + BS + CL + * Y = D + ES + FL + * + * Dependencies: + * B != 0, E != 0, F != 0, (B-EC/F) != 0, (C-FB/E) != 0 + * + * Inverses: + * S = ((DC/F-A)/(B-EC/F)) + (1/(B-EC/F))X + ((-C/F)/(B-EC/F))Y + * L = (DB/E-A)/(C-FB/E) + (1/(C-FB/E))X + ((-B/E)/(C-FB/E))Y + */ + res1[0] = (D * C / F - A) / denomX; + res1[1] = 1.0 / denomX; + res1[2] = -(C / F) / denomX; + res2[0] = (D * B/ E - A) / denomY; + res2[1] = 1.0 / denomY; + res2[2] = (-B / E) / denomY; + } + else if(C != 0 && E != 0 && B == 0) { + /** + * Input Equations: + * X = A + CL + * Y = D + ES + FL + * + * Dependencies: + * C != 0, E != 0, B == 0 + * + * Inverses: + * S = ((FA)/(CE) - D/E) + (-F/(CE))X + (1/E)Y + * L = (-A/C) + (1/C)X + 0.0Y + */ + res1[0] = (F * A)/(C * E) - D / E; + res1[1] = -F / (C * E); + res1[2] = 1.0 / E; + res2[0] = -A / C; + res2[1] = 1.0 / C; + res2[2] = 0.0; + } + else { + solutionFound = false; + } + + // If we found a swapped sol'n, the x coefficient is really + // the y coefficient at this point. The constants are correct. + if(order == 1 && solutionFound) { + double tmp = res1[1]; + res1[1] = res1[2]; + res1[2] = tmp; + + tmp = res2[1]; + res2[1] = res2[2]; + res2[2] = tmp; + } + } + + if(!solutionFound) { + throw iException::Message(iException::Math, "Not enough information", _FILEINFO_); + } + + iString inEquationX = "X = " + iString(eq1[0]); + inEquationX += " + " + iString(eq1[1]) + "S"; + inEquationX += " + " + iString(eq1[2]) + "L"; + iString inEquationY = "Y = " + iString(eq2[0]); + inEquationY += " + " + iString(eq2[1]) + "S"; + inEquationY += " + " + iString(eq2[2]) + "L"; + iString outEquationS = "S = " + iString(res1[0]); + outEquationS += " + " + iString(res1[1]) + "X"; + outEquationS += " + " + iString(res1[2]) + "Y"; + iString outEquationL = "L = " + iString(res2[0]); + outEquationL += " + " + iString(res2[1]) + "X"; + outEquationL += " + " + iString(res2[2]) + "Y"; + + // check.... + /* + double rndS = 12; + double rndL = 534; + + double x = eq1[0] + rndS*eq1[1] + rndL*eq1[2]; + double y = eq2[0] + rndS*eq2[1] + rndL*eq2[2]; + double s = res1[0] + x*res1[1] + y*res1[2]; + double l = res2[0] + x*res2[1] + y*res2[2]; + + if(fabs(rndS - s) > 1E-12 || fabs(rndL - l) > 1E-12) { + std::cerr << "Equation Fails!" << std::endl; + std::cerr << "Differences: " << fabs(rndS - s) << "," << fabs(rndL - l) << std::endl; + } + */ + + PvlGroup res("Results"); + + if(ui.WasEntered("IAKCODE")) { + PvlKeyword naifFormatX("INS" + ui.GetString("IAKCODE") + "_TRANSX"); + naifFormatX += eq1[0]; + naifFormatX += eq1[1]; + naifFormatX += eq1[2]; + PvlKeyword naifFormatY("INS" + ui.GetString("IAKCODE") + "_TRANSY"); + naifFormatY += eq2[0]; + naifFormatY += eq2[1]; + naifFormatY += eq2[2]; + PvlKeyword naifFormatS("INS" + ui.GetString("IAKCODE") + "_ITRANSS"); + naifFormatS += res1[0]; + naifFormatS += res1[1]; + naifFormatS += res1[2]; + PvlKeyword naifFormatL("INS" + ui.GetString("IAKCODE") + "_ITRANSL"); + naifFormatL += res2[0]; + naifFormatL += res2[1]; + naifFormatL += res2[2]; + + res += naifFormatX; + res += naifFormatY; + res += naifFormatS; + res += naifFormatL; + } + else { + res += PvlKeyword("EquationX", inEquationX); + res += PvlKeyword("EquationY", inEquationY); + res += PvlKeyword("EquationS", outEquationS); + res += PvlKeyword("EquationL", outEquationL); + } + + Application::Log(res); +} diff --git a/isis/src/local/apps/camcoeffs/camcoeffs.xml b/isis/src/local/apps/camcoeffs/camcoeffs.xml new file mode 100644 index 0000000000000000000000000000000000000000..a7152c0d77f9e4591f4143cf782619c28d08f3de --- /dev/null +++ b/isis/src/local/apps/camcoeffs/camcoeffs.xml @@ -0,0 +1,126 @@ + + + + + This program calculates TRANSX,TRANSY from TRANSS, TRANSL for iak kernels + + + + This program outputs the exact IAK Kernel keywords that should be added to the kernel. The + TRANSX,TRANSY keywords are the result of the input (no processing done, this should be known information). + These values were provides as parameters to this program. The TRANSS,TRANSL keywords are calculated based on + the TRANSX,TRANSY keywords and are the result of this program. The keywords can be copied directly into the + pertinent IAK kernel. + + + + System + + + + + Original Version + + + + + + + string + Output Equations + + The IAK code of the TRANS values + + + This IAK code of the TRANS values, a negative number (such as -41210) is expected. + + + + + + double + + Focal Plane X Constant Coefficient + + + This is the first value in the TRANSY keyword, which represents the focal plane X constant coefficient. + + + + double + + Focal Plane X Sample Coefficient + + + This is the second value in the TRANSY keyword, which represents the focal plane X sample coefficient. + + + + double + + Focal Plane X Line Coefficient + + + This is the third value in the TRANSY keyword, which represents the focal plane X line coefficient. + + + + double + + Focal Plane Y Constant Coefficient + + + This is the first value in the TRANSY keyword, which represents the focal plane Y constant coefficient. + + + + double + + Focal Plane Y Sample Coefficient + + + This is the second value in the TRANSY keyword, which represents the focal plane Y sample coefficient. + + + + double + + Focal Plane Y Line Coefficient + + + This is the third value in the TRANSY keyword, which represents the focal plane Y line coefficient. + + + + + + + + Getting the TRANSX,TRANSY keywords for an IAK Kernel + + This example shows how to get the TRANSX,TRANSY keywords for an IAK + Kernel when given the TRANSS, TRANSL keywords + + + + iakcode=-41219 xc=0.2589180702 xs=-0.0069999992 xl=0.0000033598 yc=-59.9867757282 ys=0.0000033598 yl=-0.0069999992 + + + This is a typical run + + + + + The Output + + This program outputs the exact IAK Kernel keywords that should be added to the kernel. The + TRANSX,TRANSY keywords are the result of the input (no processing done, this should be known information). + These values were provides as parameters to this program. The TRANSS,TRANSL keywords are calculated based on + the TRANSX,TRANSY keywords and are the result of this program. The keywords can be copied directly into the + pertinent IAK kernel. + + + + + + diff --git a/isis/src/local/apps/camcoeffs/tsts/Makefile b/isis/src/local/apps/camcoeffs/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/local/apps/camcoeffs/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/local/apps/camcoeffs/tsts/default/Makefile b/isis/src/local/apps/camcoeffs/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7912c159e560cdaee037e6fe19f444e613a8f20b --- /dev/null +++ b/isis/src/local/apps/camcoeffs/tsts/default/Makefile @@ -0,0 +1,15 @@ +APPNAME = camcoeffs + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) XCONSTCOEF=0 XSAMPLECOEF=4 XLINECOEF=0 \ + YCONSTCOEF=0 YSAMPLECOEF=0 YLINECOEF=2 > $(OUTPUT)/simple.txt; + $(APPNAME) XCONSTCOEF=0 XSAMPLECOEF=0 XLINECOEF=4 \ + YCONSTCOEF=0 YSAMPLECOEF=2 YLINECOEF=0 > $(OUTPUT)/simple2.txt; + $(APPNAME) XCONSTCOEF=10 XSAMPLECOEF=1 XLINECOEF=4 \ + YCONSTCOEF=5 YSAMPLECOEF=2 YLINECOEF=0 > $(OUTPUT)/missingLineCoef.txt; + $(APPNAME) XCONSTCOEF=10 XSAMPLECOEF=1 XLINECOEF=0 \ + YCONSTCOEF=5 YSAMPLECOEF=2 YLINECOEF=4 > $(OUTPUT)/missingLineCoef2.txt; + $(APPNAME) XCONSTCOEF=10 XSAMPLECOEF=1 XLINECOEF=6 \ + YCONSTCOEF=5 YSAMPLECOEF=2 YLINECOEF=4 > $(OUTPUT)/complicated.txt; diff --git a/isis/src/local/apps/camcoeffs/tsts/naifFormat/Makefile b/isis/src/local/apps/camcoeffs/tsts/naifFormat/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..04f15f656caa918408954c4c323eee8d5b72fc1c --- /dev/null +++ b/isis/src/local/apps/camcoeffs/tsts/naifFormat/Makefile @@ -0,0 +1,9 @@ +APPNAME = camcoeffs + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) IAKCODE=-41219 XCONSTCOEF=0.2589180702 \ + XSAMPLECOEF=-0.0069999992 XLINECOEF=0.0000033598 \ + YCONSTCOEF=-59.9867757282 YSAMPLECOEF=0.0000033598 \ + YLINECOEF=-0.0069999992 > $(OUTPUT)/naif.txt; diff --git a/isis/src/local/apps/camtest/Makefile b/isis/src/local/apps/camtest/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/local/apps/camtest/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/local/apps/camtest/camtest.cpp b/isis/src/local/apps/camtest/camtest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1573f2729d61f842dad0ae459f74ea403bb9840c --- /dev/null +++ b/isis/src/local/apps/camtest/camtest.cpp @@ -0,0 +1,93 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "Camera.h" +#include "SpecialPixel.h" + +using namespace std; +using namespace Isis; + +// Globals and prototypes +Camera *cam; + +void doIt (Buffer &in, Buffer &out); + +enum OutputType { + Lat, + Lon, + Err, + Samp, + Line +} OutputFormat; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + + ProcessByLine p; + + // Open the input cube + Cube *icube = p.SetInputCube("FROM"); + cam = icube->Camera(); + p.SetOutputCube("TO"); + + iString format = ui.GetString("FORMAT"); + + if(format == "LAT") { + OutputFormat = Lat; + } + else if(format == "LON") { + OutputFormat = Lon; + } + else if(format == "ERR") { + OutputFormat = Err; + } + else if(format == "SAMP") { + OutputFormat = Samp; + } + else if(format == "LINE") { + OutputFormat = Line; + } + + p.StartProcess(doIt); + p.EndProcess(); +} + +// Line processing routine +void doIt (Buffer &in, Buffer &out) { + if(in.Line() == 1) { + cam->SetBand(in.Band()); + } + + for(int samp = 0; samp < in.SampleDimension(); samp++) { + if(!cam->SetImage((double)(samp), (double)(in.Line()))) { + out[samp] = Null; + continue; + } + + if(OutputFormat == Lat) { + out[samp] = cam->UniversalLatitude(); + } + else if(OutputFormat == Lon) { + out[samp] = cam->UniversalLongitude(); + } + else { + if(!cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude())) { + out[samp] = Null; + continue; + } + + + if(OutputFormat == Samp) { + out[samp] = cam->Sample(); + } + else if(OutputFormat == Line) { + out[samp] = cam->Line(); + } + else { + double deltaS = cam->Sample() - samp; + double deltaL = cam->Line() - in.Line(); + out[samp] = pow( deltaS*deltaS + deltaL*deltaL, 0.5); + } + + } + } +} diff --git a/isis/src/local/apps/camtest/camtest.xml b/isis/src/local/apps/camtest/camtest.xml new file mode 100644 index 0000000000000000000000000000000000000000..242c282017e9e1aa2a69a0dc5cfac4cc300090de --- /dev/null +++ b/isis/src/local/apps/camtest/camtest.xml @@ -0,0 +1,100 @@ + + + + Perform basic camera accuracy tests + + This program will do basic tests for new camera models + + + System + + + + + Original Version + + + Now tests the center of each pixel instead + of edges - this upset pushframe tests a lot and + produced inaccurate results. + + + + + + + cube + input + + Input cube + + + The cube which needs to be tested + + + *.cub + + + + + cube + real + output + + Output cube + + + + + *.cub + + + + + + + string + Units of the output cube + + + + ERR + + + + + + + + + + + + diff --git a/isis/src/local/apps/camtest/tsts/Makefile b/isis/src/local/apps/camtest/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/local/apps/camtest/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/local/apps/camtest/tsts/dummy/Makefile b/isis/src/local/apps/camtest/tsts/dummy/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c9005c3a648d5d24233509a857d7f11687e07cd0 --- /dev/null +++ b/isis/src/local/apps/camtest/tsts/dummy/Makefile @@ -0,0 +1,8 @@ +APPNAME = camtest + +include $(ISISROOT)/make/isismake.tsts + +commands: + echo "This program has a dummy test to prevent " \ + "errors on camera model changes, and because" \ + "this program is only for internal testing." > $(OUTPUT)/truth.txt; diff --git a/isis/src/local/apps/cissua2isis/Makefile b/isis/src/local/apps/cissua2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/local/apps/cissua2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/local/apps/cissua2isis/cissua2isis.cpp b/isis/src/local/apps/cissua2isis/cissua2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aea86173a0784d14e5906a889ef0576d50ed167f --- /dev/null +++ b/isis/src/local/apps/cissua2isis/cissua2isis.cpp @@ -0,0 +1,217 @@ +#include "Isis.h" + +#include + +#include "ProcessImportPds.h" +#include "Pvl.h" +#include "UserInterface.h" +#include "TextFile.h" +#include "Stretch.h" +#include "Table.h" +#include "TableRecord.h" + +using namespace std; +using namespace Isis; + +void TranslateUoACassiniLabels (Pvl &labelPvl, Cube *ocube ); +vector ConvertLinePrefixPixels (Isis::PixelType pixelType, + unsigned char *data); +void FixDns8 (Buffer &buf); +Stretch stretch; +void CreateStretchPairs(); + +void IsisMain(){ + + ProcessImportPds p; + UserInterface &ui = Application::GetUserInterface(); + + // Get the input + Filename inFile = ui.GetFilename("FROM"); + Pvl pdsLabel; + p.SetPdsFile (inFile.Expanded(), "", pdsLabel); + + CubeAttributeOutput &outAtt = ui.GetOutputAttribute("TO"); + Cube *ocube = p.SetOutputCube(ui.GetFilename("TO"), outAtt); + + // Process + p.StartProcess (); + TranslateUoACassiniLabels (pdsLabel, ocube); + + // Fix the StartTime and StopTime keywords from having the 'Z' value at the end + Pvl *outLabel = ocube->Label(); + PvlGroup &inst = outLabel->FindGroup( "Instrument", Isis::PvlObject::Traverse ); + PvlKeyword &start = inst.FindKeyword( "StartTime" ); + PvlKeyword &stop = inst.FindKeyword( "StopTime" ); + iString startValue = start[0]; + iString stopValue = stop[0]; + start[0] = startValue.TrimTail( "Z" ); + stop[0] = stopValue.TrimTail( "Z" ); + + // All finished with the ImportPds object + p.EndProcess (); + +} + +vector ConvertLinePrefixPixels (Isis::PixelType pixelType, + unsigned char *data) { + Isis::Buffer pixelBuf(1, 1, 1, Isis::SignedWord); + + vector calibrationPixels; + //***CHECK LABEL FOR ACTUAL ENDIAN VALUE RATHER THAN ASSUMING MSB***??? + EndianSwapper swapper ("MSB"); + + vector pixel; + //12 is start byte for First Overclocked Pixel Sum in Binary Line Prefix, see SIS pg 83 + pixel.push_back(swapper.ShortInt(& (data[12]))); + //22 is start byte for Last Overclocked Pixel Sum in Binary Line Prefix, see SIS pg 83 + pixel.push_back(swapper.ShortInt(& (data[22]))); + for (int i = 0; i < (int)pixel.size(); i++) { + pixelBuf[0] = pixel[i]; + FixDns8(pixelBuf); + double pix = pixelBuf[0]; + if (pix == NULL8) calibrationPixels.push_back(NULL2); + else if (pix == LOW_REPR_SAT8) calibrationPixels.push_back(LOW_REPR_SAT2); + else if (pix == LOW_INSTR_SAT8) calibrationPixels.push_back(LOW_INSTR_SAT2); + else if (pix == HIGH_INSTR_SAT8) calibrationPixels.push_back(HIGH_INSTR_SAT2); + else if (pix == HIGH_REPR_SAT8) calibrationPixels.push_back(HIGH_REPR_SAT2); + else calibrationPixels.push_back((int)(pix+0.5)); + } + + return calibrationPixels; +} + +void FixDns8 (Buffer &buf) { + for (int i=0; iHighestVersion(); + TextFile *stretchPairs = new TextFile(temp->Expanded()); + + // Create the stretch pairs + stretch.ClearPairs(); + for (int i=0; iLineCount(); i++) { + iString line; + stretchPairs->GetLine(line,true); //assigns value to line + int temp1 = line.Token(" "); + int temp2 = line.Trim(" "); + stretch.AddPair(temp1,temp2); + } + stretchPairs->Close(); + + // Clean up + delete temp; + delete stretchPairs; + +} + + +void TranslateUoACassiniLabels (Pvl &labelPvl, Cube *ocube) { + + //Create a PVL to store the translated labels + Pvl *outLabel = ocube->Label(); + + // Get the directory where the CISS translation tables are. + PvlGroup dataDir( Preference::Preferences().FindGroup("DataDirectory") ); + iString transDir = (string) dataDir["Cassini"] + "/translations/"; + + // Translate + Filename transFile (transDir + "cissua2isis.trn"); + PvlTranslationManager instrumentXlater (labelPvl, transFile.Expanded()); + instrumentXlater.Auto ((*outLabel)); + + PvlGroup &inst = outLabel->FindGroup( "Instrument", Isis::PvlObject::Traverse ); + + // Create the correct SpacecraftClockCount value + PvlGroup &inInst = labelPvl.FindGroup("ISIS_INSTRUMENT",Pvl::Traverse); + string scc = inInst.FindKeyword("SPACECRAFT_CLOCK_CNT_PARTITION"); + scc += "/" + (string) inInst.FindKeyword("ORIGINAL_SPACECRAFT_CLOCK_START_COUN"); + inst.AddKeyword(PvlKeyword("SpacecraftClockCount",scc)); + + // dataConv is used later + string dataConv = inInst.FindKeyword("DATA_CONVERSION_TYPE"); + inst.AddKeyword(PvlKeyword("DataConversionType", dataConv)); + + //to add an array of values + PvlKeyword opticsTemp(inInst.FindKeyword("OPTICS_TEMPERATURE")); + opticsTemp.SetName("OpticsTemperature"); + inst.AddKeyword(opticsTemp); + + //two possible label names for same keyword + if (labelPvl.HasKeyword("ENCODING_TYPE")) { + string encodingType = labelPvl.FindKeyword("ENCODING_TYPE",Pvl::Traverse); + inst.AddKeyword(PvlKeyword("CompressionType",encodingType)); + } + else { + string instCmprsType = labelPvl.FindKeyword("INST_CMPRS_TYPE",Pvl::Traverse); + inst.AddKeyword(PvlKeyword("CompressionType",instCmprsType)); + } + + string flightSoftware = labelPvl.FindKeyword("FLIGHT_SOFTWARE_VERSION_ID",Pvl::Traverse); + inst.AddKeyword(PvlKeyword("FlightSoftwareVersionId",flightSoftware)); + + // Sets the needed Kernel FrameCode + string instrumentID = inst.FindKeyword("InstrumentId"); + PvlGroup kerns("Kernels"); + if (instrumentID == "ISSNA") { + kerns += PvlKeyword("NaifFrameCode",-82360); + } + else if (instrumentID == "ISSWA") { + kerns += PvlKeyword("NaifFrameCode",-82361); + } + else { + string msg = "CISS2ISIS only imports Cassini ISS narrow "; + msg += "angle or wide angle images"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + outLabel->FindObject("IsisCube").AddGroup(kerns); + + // Create BandBin group + iString filter = labelPvl.FindKeyword("BAND_BIN_FILTER_NAME",Isis::PvlObject::Traverse)[0]; + filter = filter.substr( 0, 3 ) + "/" + filter.substr( 4 ); + string cameraAngleDefs; + if(instrumentID.at(3) == 'N'){ + cameraAngleDefs = transDir + "narrowAngle.def"; + }else if (instrumentID.at(3) == 'W') { + cameraAngleDefs = transDir + "wideAngle.def"; + } + double center = 0; + double width = 0; + TextFile cameraAngle(cameraAngleDefs); + int numLines = cameraAngle.LineCount(); + bool foundfilter = false; + for (int i=0; iFindObject("IsisCube").AddGroup(bandBin); + +} diff --git a/isis/src/local/apps/cissua2isis/cissua2isis.xml b/isis/src/local/apps/cissua2isis/cissua2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..ea2dc2786d24d6628908565ef4548214ce5d11b4 --- /dev/null +++ b/isis/src/local/apps/cissua2isis/cissua2isis.xml @@ -0,0 +1,59 @@ + + + + + + Imports a U of A cassini Isis2 cube to an Isis3 cube. + + + + Imports a University of Arizona's Isis2 cube to an Isis3 cube. + + + + + Original version, heavily based off of ciss2isis + + + Fixed name for history and removed prefix data. + + + + + Cassini + + + + + + cube + input + + Input UA cube + + + A University of Arizona Isis2 cube to be imported to an Isis3 cube. + + + *.cub + + + + + cube + real + output + + Output Isis3 cube + + + The output Isis3 cube file for the imported Isis2 cube. + + + *.cub + + + + + + diff --git a/isis/src/local/apps/cissua2isis/tsts/Makefile b/isis/src/local/apps/cissua2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/local/apps/cissua2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/local/apps/cissua2isis/tsts/default/Makefile b/isis/src/local/apps/cissua2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c94d2e02e5102c8a873cb06c0251d64d76edc0f4 --- /dev/null +++ b/isis/src/local/apps/cissua2isis/tsts/default/Makefile @@ -0,0 +1,13 @@ +APPNAME = cissua2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/N1509133834_1.IMG.cal.lev1.cub \ + to=$(OUTPUT)/N1509133834_1.IMG.cal.lev1.cub > /dev/null; + catlab from=$(OUTPUT)/N1509133834_1.IMG.cal.lev1.cub \ + to=$(OUTPUT)/N1509133834_1.IMG.cal.lev1.pvl > /dev/null; + $(APPNAME) from=$(INPUT)/N1509135639_1.IMG.cal.lev1.cub \ + to=$(OUTPUT)/N1509135639_1.IMG.cal.lev1.cub > /dev/null; + catlab from=$(OUTPUT)/N1509135639_1.IMG.cal.lev1.cub \ + to=$(OUTPUT)/N1509135639_1.IMG.cal.lev1.pvl > /dev/null; diff --git a/isis/src/local/apps/demwrap/Makefile b/isis/src/local/apps/demwrap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/local/apps/demwrap/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/local/apps/demwrap/demwrap.cpp b/isis/src/local/apps/demwrap/demwrap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22d6cb9ea7f4799bc174e083290a41858843dd76 --- /dev/null +++ b/isis/src/local/apps/demwrap/demwrap.cpp @@ -0,0 +1,130 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "Projection.h" +#include "SpecialPixel.h" +#include "LineManager.h" +#include "OriginalLabel.h" +#include "History.h" +#include "Table.h" + +using namespace std; +using namespace Isis; + +void DoWrap (Buffer &in); + +Cube *ocube; + +int leftPad; +int rightPad; +int topPad; +int bottomPad; + +void IsisMain() { + // We will be use a mosaic technique so get the size of the input file + ProcessByLine p; + Cube *icube = p.SetInputCube ("FROM"); + int ins = icube->Samples(); + int inl = icube->Lines(); + int inb = icube->Bands(); + + // Retrieve the padding parameters + UserInterface &ui = Application::GetUserInterface(); + leftPad = ui.GetInteger("LEFT"); + rightPad = ui.GetInteger("RIGHT"); + topPad = ui.GetInteger("TOP"); + bottomPad = ui.GetInteger("BOTTOM"); + + // Compute the output size + int ns = ins + leftPad + rightPad; + int nl = inl + topPad + bottomPad; + int nb = inb; + + if(leftPad > ins || rightPad > ins || topPad > inl || bottomPad > inl) { + iString message = "The padding must be less than or equal to the image dimensions"; + throw iException::Message(iException::User, message, _FILEINFO_); + } + + Projection *proj = icube->Projection(); + if(proj == NULL) { + iString message = "The input cube must be a DEM file, which means it has a projection"; + throw iException::Message(iException::User, message, _FILEINFO_); + } + + if(!proj->IsEquatorialCylindrical()) { + iString message = "The input cube must have an equatorial cylindrical projection"; + throw iException::Message(iException::User, message, _FILEINFO_); + } + + PvlGroup mapgrp = icube->Label()->FindGroup("Mapping", Pvl::Traverse); + + double upperLeftCorner = mapgrp["UpperLeftCornerX"]; + upperLeftCorner -= leftPad * proj->Resolution(); + mapgrp.AddKeyword(PvlKeyword("UpperLeftCornerX", upperLeftCorner, "meters"), + Pvl::Replace); + + upperLeftCorner = mapgrp["UpperLeftCornerY"]; + upperLeftCorner += topPad * proj->Resolution(); + mapgrp.AddKeyword(PvlKeyword("UpperLeftCornerY", upperLeftCorner, "meters"), + Pvl::Replace); + + + p.SetOutputCube ("TO", ns, nl, nb); + // Make sure everything is propagated and closed + p.EndProcess(); + + // Now we'll really be processing our input cube + p.SetInputCube("FROM"); + + // We need to create the output file + ocube = new Cube(); + ocube->Open(Filename(ui.GetFilename("TO")).Expanded(), "rw"); + + p.StartProcess(DoWrap); + + // update mapping grp + ocube->PutGroup(mapgrp); + + p.EndProcess(); + ocube->Close(); + delete ocube; +} + +void DoWrap (Buffer &in) { + LineManager outMan(*ocube); + + outMan.SetLine(in.Line() + topPad); + int inputSize = in.size(); + int outputSize = outMan.size(); + + for(int outputIndex = 0; outputIndex < outputSize; outputIndex++) { + int inputIndex = outputIndex - leftPad; + if(inputIndex < 0) { + outMan[outputIndex] = in[inputIndex + inputSize]; + } + else if(inputIndex < inputSize) { + outMan[outputIndex] = in[inputIndex]; + } + else { + outMan[outputIndex] = in[inputIndex - inputSize]; + } + } + + ocube->Write(outMan); + + // first line goes the top n lines + if(in.Line() == 1) { + for(int outLine = 1; outLine <= topPad; outLine++) { + outMan.SetLine(outLine); + ocube->Write(outMan); + } + } + + // last line goes the bottom n lines + int inl = ocube->Lines() - topPad - bottomPad; + if(in.Line() == inl) { + for(int outLine = 1; outLine <= bottomPad; outLine++) { + outMan.SetLine(outLine + topPad + inl); + ocube->Write(outMan); + } + } +} diff --git a/isis/src/local/apps/demwrap/demwrap.xml b/isis/src/local/apps/demwrap/demwrap.xml new file mode 100644 index 0000000000000000000000000000000000000000..713024740e02bf4589b061287c72c72b94f356b7 --- /dev/null +++ b/isis/src/local/apps/demwrap/demwrap.xml @@ -0,0 +1,97 @@ + + + + + This program pads DEMs with a specified number of pixels. It is not valid to run this program on anything but a DEM. + + + + This program pads DEMs with a specified number of pixels. It is not valid to run this program on anything but a DEM. + + + + + Original version + + + Added additional checks for valid projections and fixed the implementation of the north and south poles. + + + + + System + + + + + + cube + input + + Input DEM cube + + + The DEM cube which will be padded + + + *.cub + + + + + cube + output + + Output padded DEM cube + + + + + *.cub + + + + + + + integer + Number of pixels to pad on the left side + 0 + 0 + + This is the number of pixels to pad on the left side of the cube + + + + + integer + Number of pixels to pad on the right side + 0 + 0 + + This is the number of pixels to pad on the right side of the cube + + + + + integer + Number of pixels to pad on the top edge + 0 + 0 + + This is the number of pixels to pad on the top edge of the cube + + + + + integer + Number of pixels to pad on the bottom edge + 0 + 0 + + This is the number of pixels to pad on the bottom edge of the cube + + + + + diff --git a/isis/src/local/apps/demwrap/tsts/Makefile b/isis/src/local/apps/demwrap/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/local/apps/demwrap/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/local/apps/demwrap/tsts/default/Makefile b/isis/src/local/apps/demwrap/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..df9f3df7b41b338c4e48042a960a431e3a5bdf44 --- /dev/null +++ b/isis/src/local/apps/demwrap/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = demwrap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=\$$base/dems/ulcn2005_lpo.cub \ + top=2 bottom=1 left=3 right=4 TO=$(OUTPUT)/ulcn2005_lpo.cub \ + > /dev/null; + catlab FROM=$(OUTPUT)/ulcn2005_lpo.cub > $(OUTPUT)/ulcn2005_lpo.pvl diff --git a/isis/src/local/apps/polytool/Makefile b/isis/src/local/apps/polytool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/local/apps/polytool/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/local/apps/polytool/polytool.cpp b/isis/src/local/apps/polytool/polytool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f804f621f4b1a52796127c2cf56614e5fc99245a --- /dev/null +++ b/isis/src/local/apps/polytool/polytool.cpp @@ -0,0 +1,103 @@ +#include "Isis.h" + +#include "PvlGroup.h" +#include "PvlKeyword.h" + +#include +#include + +#include "geos/io/WKTReader.h" + +#include "PolygonTools.h" + +using namespace std; +using namespace Isis; + +geos::geom::Geometry * GetPolygon( std::string name ); + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + + std::string result; + if( ui.GetString("PROCESS").compare("DESPIKE") == 0 ) { + geos::geom::MultiPolygon * polygon1 = PolygonTools::MakeMultiPolygon( GetPolygon( ui.GetFilename("FROM1") ) ); + + geos::geom::MultiPolygon * outpoly = PolygonTools::Despike( polygon1 ); + + result = outpoly->toString(); + } + else if( ui.GetString("PROCESS").compare("DIFFERENCE") == 0 ) { + geos::geom::Geometry * polygon1 = GetPolygon( ui.GetFilename("FROM1") ); + geos::geom::Geometry * polygon2 = GetPolygon( ui.GetFilename("FROM2") ); + + geos::geom::Geometry *outgeom = PolygonTools::Difference( polygon1, polygon2 ); + + result = outgeom->toString(); + } + else if( ui.GetString("PROCESS").compare("EQUAL") == 0 ) { + geos::geom::Geometry * geom1 = GetPolygon( ui.GetFilename("FROM1") ); + geos::geom::MultiPolygon * polygon1 = PolygonTools::MakeMultiPolygon(geom1); + + geos::geom::Geometry * geom2 = GetPolygon( ui.GetFilename("FROM2") ); + geos::geom::MultiPolygon * polygon2 = PolygonTools::MakeMultiPolygon(geom2); + + PvlGroup grp( "Results" ); + if (PolygonTools::Equal( polygon1, polygon2 )) { + grp += PvlKeyword( "Equal", "true" ); + } + else { + grp += PvlKeyword( "Equal", "false" ); + } + + delete geom1; + delete geom2; + delete polygon1; + delete polygon2; + + Application::Log( grp ); + } + else if( ui.GetString("PROCESS").compare("INTERSECT") == 0 ) { + geos::geom::Geometry * polygon1 = GetPolygon( ui.GetFilename("FROM1") ); + geos::geom::Geometry * polygon2 = GetPolygon( ui.GetFilename("FROM2") ); + + geos::geom::Geometry *outgeom = PolygonTools::Intersect( polygon1, polygon2 ); + + result = outgeom->toString(); + } + + if ( !result.empty() ) { + // Output the resultant polygon + std::string outname = ui.GetFilename("TO"); + std::ofstream outfile; + outfile.open( outname.c_str() ); + outfile << result; + outfile.close(); + if( outfile.fail() ) { + iString msg = "Unable to write the polygon to [" + outname + "]"; + throw iException::Message(iException::Io, msg, _FILEINFO_); + } + } +} + + +/** + * Grabs the first line of a file and attempts to create a Multipolygon to from + * it. + * + * @param name The filename containing the multipolygon in its first line + * + * @return geos::geom::MultiPolygon* + */ +geos::geom::Geometry * GetPolygon( std::string name ) { + ifstream is; + is.open( name.c_str() ); + + std::string fileData = ""; + while( is.good() ) { + fileData += is.get(); + } + const std::string fileContents = fileData; + + geos::io::WKTReader geosReader; + return geosReader.read( fileContents ); +} diff --git a/isis/src/local/apps/polytool/polytool.xml b/isis/src/local/apps/polytool/polytool.xml new file mode 100644 index 0000000000000000000000000000000000000000..2f4d51384233fb9149c9617a61847e487efa8fc9 --- /dev/null +++ b/isis/src/local/apps/polytool/polytool.xml @@ -0,0 +1,113 @@ + + + + + A tool for looking at polygon processing + + This is a debugging tool made for the purpose of being able to see one or + more polygons processed by various ISIS 3 processes. + + + + Geometry + + + + + Original version + + + Added the EQUAL option + + + Removed memory leaks in this program in order to do + memory leak checking for PolygonTools + + + + + + + + + filename + input + Input 1 + + This input should be a file containing a single multipolygon. + + + + + filename + input + Input 2 + + This input should be a file containing a single multipolygon. + + + + + + + + + string + DESPIKE + Which process to execute + + Used to determine which process should be ran on the input + multipolygon(s) + + + + + + + + + + + + + + + filename + output + Output multipolygon + + The resultant polygon from the process ran. + + + + + + + + diff --git a/isis/src/local/apps/polytool/tsts/Makefile b/isis/src/local/apps/polytool/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/local/apps/polytool/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/local/apps/polytool/tsts/default/Makefile b/isis/src/local/apps/polytool/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..df2f163bb325d8b112ab2cebbc999f8c2136bcc8 --- /dev/null +++ b/isis/src/local/apps/polytool/tsts/default/Makefile @@ -0,0 +1,13 @@ +APPNAME = polytool + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from1=$(INPUT)/multipolygon1.txt \ + to=$(OUTPUT)/despiked.txt > /dev/null; + $(APPNAME) from1=$(INPUT)/multipolygon1.txt \ + from2=$(INPUT)/multipolygon2.txt process=difference \ + to=$(OUTPUT)/differenced.txt > /dev/null; + $(APPNAME) from1=$(INPUT)/multipolygon1.txt \ + from2=$(INPUT)/multipolygon2.txt process=intersect \ + to=$(OUTPUT)/intersected.txt > /dev/null; diff --git a/isis/src/local/apps/qmos/Makefile b/isis/src/local/apps/qmos/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/local/apps/qmos/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/local/apps/qmos/qmos.cpp b/isis/src/local/apps/qmos/qmos.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4cf3a533916062b546063855af035ed26624d223 --- /dev/null +++ b/isis/src/local/apps/qmos/qmos.cpp @@ -0,0 +1,116 @@ +#include "IsisDebug.h" + +#include + +#include "iException.h" +#include "ProjectionFactory.h" +#include "Filename.h" +#include "MosaicWidget.h" +#include "MosaicMainWindow.h" +#include "Preference.h" +#include "PvlGroup.h" + +void startMonitoringMemory(); +void stopMonitoringMemory(); + +int main (int argc, char *argv[]) { + #ifdef CWDEBUG + startMonitoringMemory(); + #endif + + try { + QApplication *app = new QApplication(argc,argv); + QApplication::setApplicationName("qmos"); + + // check for forcing of gui style + Isis::PvlGroup & uiPref = Isis::Preference::Preferences().FindGroup( + "UserInterface"); + if (uiPref.HasKeyword("GuiStyle")) + { + std::string style = uiPref["GuiStyle"]; + QApplication::setStyle((Isis::iString) style); + } + + // Add the Qt plugin directory to the library path + Isis::Filename qtpluginpath ("$ISISROOT/3rdParty/plugins"); + QCoreApplication::addLibraryPath(qtpluginpath.Expanded().c_str()); + + + Qisis::MosaicMainWindow *mainWindow = new Qisis::MosaicMainWindow("qmos"); + + Isis::PvlGroup mapping("Mapping"); + { + mapping += Isis::PvlKeyword("ProjectionName", "PolarStereographic"); + mapping += Isis::PvlKeyword("CenterLatitude", "45.0"); + mapping += Isis::PvlKeyword("CenterLongitude", "0.0"); + mapping += Isis::PvlKeyword("TargetName", "Mars"); + mapping += Isis::PvlKeyword("LatitudeType","Planetocentric"); + mapping += Isis::PvlKeyword("LongitudeDirection", "PositiveEast"); + mapping += Isis::PvlKeyword("LongitudeDomain", "360"); + } + + Isis::Pvl pvl; + pvl.AddGroup(mapping); + Isis::Projection *proj = Isis::ProjectionFactory::Create(pvl); + + Qisis::MosaicWidget *mos = new Qisis::MosaicWidget(mainWindow); + mos->setProjection(proj); + mos->setLabelText("Polar Stereographic"); + mainWindow->setCentralWidget(mos); + mainWindow->show(); + + int status = app->exec(); + delete mos; + delete mainWindow; + delete app; + + return status; + } + catch (Isis::iException &e) { + e.Report(); + } + +} + + +void startMonitoringMemory() { +#ifdef CWDEBUG +#ifndef NOMEMCHECK + MyMutex *mutex = new MyMutex(); + std::fstream *alloc_output = new std::fstream("/dev/null"); + Debug( make_all_allocations_invisible_except(NULL) ); + ForAllDebugChannels( if (debugChannel.is_on()) debugChannel.off() ); + Debug( dc::malloc.on() ); + Debug( libcw_do.on() ); + Debug( libcw_do.set_ostream(alloc_output) ); + Debug( libcw_do.set_ostream(alloc_output, mutex) ); + atexit(stopMonitoringMemory); +#endif +#endif +} + + +void stopMonitoringMemory() { +#ifdef CWDEBUG +#ifndef NOMEMCHECK + Debug( + alloc_filter_ct alloc_filter; + std::vector objmasks; + objmasks.push_back("libc.so*"); + objmasks.push_back("libstdc++*"); + std::vector srcmasks; + srcmasks.push_back("*new_allocator.h*"); + srcmasks.push_back("*set_ostream.inl*"); + alloc_filter.hide_objectfiles_matching(objmasks); + alloc_filter.hide_sourcefiles_matching(srcmasks); + alloc_filter.hide_unknown_locations(); + delete libcw_do.get_ostream(); + libcw_do.set_ostream(&std::cout); + list_allocations_on(libcw_do, alloc_filter); + dc::malloc.off(); + libcw_do.off() + ); +#endif +#endif +} + diff --git a/isis/src/local/apps/qmos/qmos.xml b/isis/src/local/apps/qmos/qmos.xml new file mode 100644 index 0000000000000000000000000000000000000000..17e20cb0b79c7e42cf41a5f5ddeecce15553b156 --- /dev/null +++ b/isis/src/local/apps/qmos/qmos.xml @@ -0,0 +1,27 @@ + + + + + + Display and analyze cube footprints + + + + This program will display cube footprints and allow for interactive + analysis. It is a prototype version and is still in progress. More + documentation will be forthcoming. + + + + Display + + + + + Original version + + + Discontinued forcing of gui style to windows + + + diff --git a/isis/src/local/apps/qmos/tsts/Makefile b/isis/src/local/apps/qmos/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/local/apps/qmos/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/local/apps/qmos/tsts/default/Makefile b/isis/src/local/apps/qmos/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ae5a2608188cc2d40ddf9892257ac2ed03f7a889 --- /dev/null +++ b/isis/src/local/apps/qmos/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = qmos + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/qmosTruth.txt $(OUTPUT)/qmosTruth.txt; diff --git a/isis/src/local/objs/Makefile b/isis/src/local/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/local/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/lro/Makefile b/isis/src/lro/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/lro/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/lro/apps/Makefile b/isis/src/lro/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/lro/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/lro/apps/lronac2isis/Makefile b/isis/src/lro/apps/lronac2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/lro/apps/lronac2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/lro/apps/lronac2isis/lronac2isis.cpp b/isis/src/lro/apps/lronac2isis/lronac2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1bc8c56e0e89e417976758094589acda5d91e9b2 --- /dev/null +++ b/isis/src/lro/apps/lronac2isis/lronac2isis.cpp @@ -0,0 +1,237 @@ +#include "Isis.h" +#include "ProcessImportPds.h" +#include "UserInterface.h" +#include "Filename.h" +#include "iException.h" +#include "iString.h" +#include "Pvl.h" +#include "OriginalLabel.h" +#include "History.h" +#include "LineManager.h" +#include + +#define MAX_INPUT_VALUE 4095 + +using namespace std; +using namespace Isis; + +void ResetGlobals(); +void Import ( Buffer &buf ); +void TranslateLrocNacLabels ( Filename &labelFile, Cube *ocube ); + +// Global variables for processing functions +Cube *g_ocube; +std::vector< double> g_xterm, g_bterm, g_mterm; +bool g_flip = false; + +void IsisMain () { + // Initialize variables + ResetGlobals(); + + //Check that the file comes from the right camera + UserInterface &ui = Application::GetUserInterface(); + Filename inFile = ui.GetFilename("FROM"); + iString id; + int sumMode; + try { + Pvl lab(inFile.Expanded()); + + if (lab.HasKeyword("DATA_SET_ID")) + id = (string) lab.FindKeyword("DATA_SET_ID"); + else { + string msg = "Unable to read [DATA_SET_ID] from input file [" + inFile.Expanded() + "]"; + throw iException::Message(iException::Io, msg, _FILEINFO_); + } + + //Checks if in file is rdr + bool projected = lab.HasObject("IMAGE_MAP_PROJECTION"); + if (projected) { + string msg = "[" + inFile.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + sumMode = (int) lab.FindKeyword("CROSSTRACK_SUMMING"); + + // Store the decompanding information + PvlKeyword xtermKeyword = lab.FindKeyword("LRO:XTERM"), + mtermKeyword = lab.FindKeyword("LRO:MTERM"), + btermKeyword = lab.FindKeyword("LRO:BTERM"); + + if (mtermKeyword.Size() != xtermKeyword.Size() || btermKeyword.Size() != xtermKeyword.Size()) { + string msg = "The decompanding terms do not have the same dimensions"; + throw iException::Message(iException::Io, msg, _FILEINFO_); + } + + for (int i = 0; i < xtermKeyword.Size(); i++) { + g_xterm.push_back(xtermKeyword[i]); + g_mterm.push_back(mtermKeyword[i]); + g_bterm.push_back(btermKeyword[i]); + } + + double versionId = (double)(lab.FindKeyword("PRODUCT_VERSION_ID")[0]).Trim("v"); + + if (lab.FindKeyword("FRAME_ID")[0] == "RIGHT" && versionId < 1.30) + g_flip = true; + else + g_flip = false; + } + catch (iException &e) { + string msg = "The PDS header is missing important keyword(s)."; + throw iException::Message(iException::Io, msg, _FILEINFO_); + } + + id.ConvertWhiteSpace(); + id.Compress(); + id.Trim(" "); + if (id.substr(13,3) != "EDR") { + string msg = "Input file [" + inFile.Expanded() + "] does not appear to be " + + "in LROC-NAC EDR format. DATA_SET_ID is [" + id + "]"; + throw iException::Message(iException::Io, msg, _FILEINFO_); + } + + //Process the file + Pvl pdsLab; + ProcessImportPds p; + p.SetPdsFile(inFile.Expanded(), "", pdsLab); + + // Set the output bit type to Real + CubeAttributeOutput &outAtt = ui.GetOutputAttribute("TO"); + + g_ocube = new Cube(); + g_ocube->SetByteOrder(outAtt.ByteOrder()); + g_ocube->SetCubeFormat(outAtt.FileFormat()); + g_ocube->SetMinMax((double) VALID_MIN2, (double) VALID_MAX2); + if (outAtt.DetachedLabel()) g_ocube->SetDetached(); + if (outAtt.AttachedLabel()) g_ocube->SetAttached(); + g_ocube->SetDimensions(p.Samples(), p.Lines(), p.Bands()); + g_ocube->SetPixelType(Isis::Real); + g_ocube->Create(ui.GetFilename("TO")); + + // Do 8 bit to 12 bit conversion + // And if NAC-R, flip the frame + p.StartProcess(Import); + + // Then translate the labels + TranslateLrocNacLabels(inFile, g_ocube); + p.EndProcess(); + + // Add History + History history("IsisCube"); + history.AddEntry(); + g_ocube->Write(history); + + // Add original label + OriginalLabel origLabel(pdsLab); + g_ocube->Write(origLabel); + + g_ocube->Close(); + delete g_ocube; +} + +// The input buffer has a raw 16 bit buffer but the values are still 0 to 255 +// See "Appendix B - NAC and WAC Companding Schemes" of the LROC_SOC_SPEC document for reference +void Import ( Buffer &in ) { + LineManager outLines(*g_ocube); + outLines.SetLine(in.Line(), in.Band()); + Buffer buf(in.SampleDimension(), in.LineDimension(), in.BandDimension(), g_ocube->PixelType()); + + // Do the decompanding + for (int pixin = 0; pixin < in.size(); pixin++) { + // if pixin < xtermo0, then it is in "segment 0" + if (in[pixin] < g_xterm[0]) + buf[pixin] = (int) in[pixin]; + + // otherwise, it is in segments 1 to 5 + else { + unsigned int segment = 1; + while (segment < g_xterm.size() && (in[pixin]- g_bterm[segment - 1])/g_mterm[segment - 1] >= g_xterm[segment]) + segment++; + + // Compute the upper and lower bin values + double upper = (in[pixin] + 1 - g_bterm[segment - 1])/g_mterm[segment - 1] - 1; + double lower = (in[pixin]- g_bterm[segment - 1])/g_mterm[segment - 1]; + + // Check if the bin is on the upper boundary of the last segment + if (upper > MAX_INPUT_VALUE) + upper = MAX_INPUT_VALUE; + else if (segment < g_xterm.size() && upper >= g_xterm[segment]) + upper = g_xterm[segment]-1; + + // Check if it is on the lower boundary of a segment + if (lower < g_xterm[segment-1]) + lower = g_xterm[segment-1]; + + // Output the middle bin value + buf[pixin] = (upper + lower)/2.0; + } + } + + // flip the NAC-R frame + if (g_flip) { + Buffer tmpbuf(buf); + for (int i = 0; i < buf.size(); i++) + buf[i] = tmpbuf[buf.size() - i - 1]; + } + outLines.Copy(buf); + g_ocube->Write(outLines); +} + +//Function to translate the labels +void TranslateLrocNacLabels ( Filename &labelFile, Cube *ocube ) { + + //Pvl to store the labels + Pvl outLabel; + //Set up the directory where the translations are + PvlGroup dataDir(Preference::Preferences().FindGroup("DataDirectory")); + iString transDir = (string) dataDir["Lro"] + "/translations/"; + Pvl labelPvl(labelFile.Expanded()); + + //Translate the Instrument group + Filename transFile(transDir + "lronacInstrument.trn"); + PvlTranslationManager instrumentXlator(labelPvl, transFile.Expanded()); + instrumentXlator.Auto(outLabel); + + //Translate the Archive group + transFile = transDir + "lronacArchive.trn"; + PvlTranslationManager archiveXlater(labelPvl, transFile.Expanded()); + archiveXlater.Auto(outLabel); + + //Translate the BandBin group + transFile = transDir + "lronacBandBin.trn"; + PvlTranslationManager bandBinXlater(labelPvl, transFile.Expanded()); + bandBinXlater.Auto(outLabel); + + Pvl lab(labelFile.Expanded()); + + //Set up the Kernels group + PvlGroup kern("Kernels"); + if (lab.FindKeyword("FRAME_ID")[0] == "LEFT") + kern += PvlKeyword("NaifFrameCode", -85600); + else + kern += PvlKeyword("NaifFrameCode", -85610); + + PvlGroup inst = outLabel.FindGroup("Instrument", Pvl::Traverse); + if (lab.FindKeyword("FRAME_ID")[0] == "LEFT") { + inst.FindKeyword("InstrumentId") = "NACL"; + inst.FindKeyword("InstrumentName") = "LUNAR RECONNAISSANCE ORBITER NARROW ANGLE CAMERA LEFT"; + } + else { + inst.FindKeyword("InstrumentId") = "NACR"; + inst.FindKeyword("InstrumentName") = "LUNAR RECONNAISSANCE ORBITER NARROW ANGLE CAMERA RIGHT"; + } + + //Add all groups to the output cube + ocube->PutGroup(inst); + ocube->PutGroup(outLabel.FindGroup("Archive", Pvl::Traverse)); + ocube->PutGroup(outLabel.FindGroup("BandBin", Pvl::Traverse)); + ocube->PutGroup(kern); +} + +void ResetGlobals() { + g_ocube = NULL; + g_xterm.clear(); + g_mterm.clear(); + g_bterm.clear(); + g_flip = false; +} diff --git a/isis/src/lro/apps/lronac2isis/lronac2isis.xml b/isis/src/lro/apps/lronac2isis/lronac2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..76d2baae2cbc26ee771515d03ccda3bf97b0821c --- /dev/null +++ b/isis/src/lro/apps/lronac2isis/lronac2isis.xml @@ -0,0 +1,55 @@ + + + + + + Import an LROC NAC image as an Isis cube + + + + This program takes an image from the Lunar Reconnaissance Orbiter Narrow Angle Camera + and produces an Isis cube containing the image data. + + + + + Original Version + + + + + Lunar Reconnaissance Orbiter + + + + + + filename + input + + Input file + + + The image to be processed + + + *.img + + + + + cube + output + + Output cube + + + This is the resultant cube, containing the image and label data. + + + *.cub + + + + + diff --git a/isis/src/lro/apps/lronac2isis/tsts/Makefile b/isis/src/lro/apps/lronac2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/lro/apps/lronac2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/lro/apps/lronac2isis/tsts/default/Makefile b/isis/src/lro/apps/lronac2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..382067625d8821a23a5f254d627701035cab11a0 --- /dev/null +++ b/isis/src/lro/apps/lronac2isis/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = lronac2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/M111607830RE.IMG \ + to=$(OUTPUT)/M111607830RE.cub > /dev/null; \ No newline at end of file diff --git a/isis/src/lro/apps/lronac2pds/Makefile b/isis/src/lro/apps/lronac2pds/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/lro/apps/lronac2pds/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/lro/apps/lronac2pds/lronac2pds.cpp b/isis/src/lro/apps/lronac2pds/lronac2pds.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be9f6c46739b373f4c376f111d46554107398f54 --- /dev/null +++ b/isis/src/lro/apps/lronac2pds/lronac2pds.cpp @@ -0,0 +1,246 @@ +#include "Isis.h" +#include "ProcessExport.h" +#include "ProcessByLine.h" +#include "Pvl.h" +#include "PvlTranslationManager.h" +#include "PvlFormatPds.h" +#include "OriginalLabel.h" +#include "iTime.h" +#include "md5.h" +#include "md5wrapper.h" +#include + +#define SCALING_FACTOR 32767 + +using namespace std; +using namespace Isis; + +void ResetGlobals (); +void ProcessImage ( Buffer &in, Buffer &out ); +string MD5Checksum ( string filename ); +void OutputLabel ( std::ofstream &fout, Cube* cube ); +void CopyData ( std::ifstream &fin, std::ofstream &fout ); + +string g_md5Checksum; + +bool g_isIof; + +iString g_productVersionId = "N/A"; + +void IsisMain () { + ResetGlobals(); + UserInterface &ui = Application::GetUserInterface(); + + g_productVersionId = ui.GetString("VERSIONIDSTRING"); + + // Set the processing object + + ProcessByLine p; + Cube *inCube = p.SetInputCube("FROM"); + + g_isIof = inCube->Label()->FindGroup("Radiometry", Pvl::Traverse).FindKeyword("RadiometricType")[0].Equal("IOF"); + + Filename scaledCube = ui.GetFilename("FROM"); + scaledCube.Temporary(ui.GetFilename("FROM"), "cub"); + p.SetOutputCube(scaledCube.Expanded(), CubeAttributeOutput(), inCube->Samples(), inCube->Lines(), inCube->Bands()); + // Scale image and calculate max and min values + p.StartProcess(ProcessImage); + p.EndProcess(); + + ProcessExport pe; + + // Setup the input cube + inCube = pe.SetInputCube(scaledCube.Expanded(), CubeAttributeInput()); + + if (g_isIof) { + pe.SetOutputType(Isis::SignedWord); + pe.SetOutputEndian(Isis::Lsb); + + pe.SetOutputRange(Isis::VALID_MIN2, Isis::VALID_MAX2); + + pe.SetOutputNull(Isis::NULL2); + pe.SetOutputLrs(Isis::LOW_REPR_SAT2); + pe.SetOutputLis(Isis::LOW_INSTR_SAT2); + pe.SetOutputHis(Isis::HIGH_INSTR_SAT2); + pe.SetOutputHrs(Isis::HIGH_REPR_SAT2); + } + else { + pe.SetOutputType(Isis::Real); + pe.SetOutputEndian(Isis::Lsb); + + pe.SetOutputRange(Isis::VALID_MIN4, Isis::VALID_MAX4); + + pe.SetOutputNull(Isis::NULL4); + pe.SetOutputLrs(Isis::LOW_REPR_SAT4); + pe.SetOutputLis(Isis::LOW_INSTR_SAT4); + pe.SetOutputHis(Isis::HIGH_INSTR_SAT4); + pe.SetOutputHrs(Isis::HIGH_REPR_SAT4); + } + + Filename tempFile(ui.GetFilename("TO")); + tempFile.Temporary(ui.GetFilename("TO"), "temp"); + string tempFilename(tempFile.Expanded()); + ofstream temporaryFile(tempFilename.c_str()); + + pe.StartProcess(temporaryFile); + temporaryFile.close(); + + // Calculate MD5 Checksum + g_md5Checksum = MD5Checksum(tempFilename); + + Filename outFile(ui.GetFilename("TO")); + string outFilename(outFile.Expanded()); + ifstream inFile(tempFilename.c_str()); + ofstream pdsFile(outFilename.c_str()); + + // Output the label + OutputLabel(pdsFile, inCube); + + // Then copy the image data + CopyData(inFile, pdsFile); + + pdsFile.close(); + + pe.EndProcess(); + + remove((scaledCube.Expanded()).c_str()); + remove(tempFilename.c_str()); + return; +} + +void ResetGlobals () { + g_md5Checksum = ""; + g_isIof = false; +} + +void ProcessImage ( Buffer &in, Buffer &out ) { + for (int i = 0; i < in.size(); i++) { + if (IsSpecial(in[i])) + out[i] = in[i]; + else if (g_isIof) + out[i] = SCALING_FACTOR * in[i]; + else + out[i] = in[i]; + } +} + +string MD5Checksum ( string filename ) { + md5wrapper md5; + std::string checkSum = md5.getHashFromFile(filename.c_str()); + return checkSum; +} + +void OutputLabel ( std::ofstream &fout, Cube* cube ) { + OriginalLabel origLab(cube->Filename()); + Pvl labelPvl = origLab.ReturnLabels(); + + //Pvl to store the labels + Pvl outLabel; + PvlFormatPds *p_formatter = new PvlFormatPds("$lro/translations/pdsExportRootGen.typ"); + labelPvl.SetFormat(p_formatter); + labelPvl.SetTerminator("END"); + //Set up the directory where the translations are + PvlGroup dataDir(Preference::Preferences().FindGroup("DataDirectory")); + iString transDir = (string) dataDir["Lro"] + "/translations/"; + + stringstream stream; + iString pdsLabel = ""; + + //Translate the Original Pds Label + Filename transFile(transDir + "lronacPdsLabelExport.trn"); + PvlTranslationManager labelXlator(labelPvl, transFile.Expanded()); + labelXlator.Auto(outLabel); + + // Copy any Translation changes over + for (int i = 0; i < outLabel.Keywords(); i++) { + bool hasUnit = false; + string unit = ""; + if (labelPvl[outLabel[i].Name()].Unit() != "") { + hasUnit = true; + unit = labelPvl[outLabel[i].Name()].Unit(); + } + bool hasComment = false; + string comment = ""; + if (labelPvl[outLabel[i].Name()].Comments() > 0) { + hasComment = true; + comment = labelPvl[outLabel[i].Name()].Comment(0); + } + labelPvl[outLabel[i].Name()] = outLabel[i]; + + if (hasUnit) + labelPvl[outLabel[i].Name()].SetUnits(unit); + if (hasComment) + labelPvl[outLabel[i].Name()].AddComment(comment); + } + + //Update the product ID + labelPvl["PRODUCT_ID"][0].replace(11, 1, "C"); + + // Update the product creation time + labelPvl["PRODUCT_CREATION_TIME"].SetValue(iTime::CurrentGMT()); + + labelPvl["PRODUCT_VERSION_ID"].SetValue(g_productVersionId); + + // Update the "IMAGE" Object + PvlObject &imageObject = labelPvl.FindObject("IMAGE"); + imageObject.Clear(); + imageObject += PvlKeyword("LINES", cube->Lines()); + imageObject += PvlKeyword("LINE_SAMPLES", cube->Samples()); + if (g_isIof) { + imageObject += PvlKeyword("SAMPLE_BITS", 16); + imageObject += PvlKeyword("SAMPLE_TYPE", "LSB_INTEGER"); + imageObject += PvlKeyword("SCALING_FACTOR", 1.0 / SCALING_FACTOR); + imageObject += PvlKeyword("VALID_MINIMUM", Isis::VALID_MIN2); + imageObject += PvlKeyword("NULL", Isis::NULL2); + imageObject += PvlKeyword("LOW_REPR_SATURATION", Isis::LOW_REPR_SAT2); + imageObject += PvlKeyword("LOW_INSTR_SATURATION", Isis::LOW_INSTR_SAT2); + imageObject += PvlKeyword("HIGH_INSTR_SATURATION", Isis::HIGH_INSTR_SAT2); + imageObject += PvlKeyword("HIGH_REPR_SATURATION", Isis::HIGH_REPR_SAT2); + imageObject += PvlKeyword("UNIT", "Scaled I/F"); + } + else { + imageObject += PvlKeyword("SAMPLE_BITS", 32); + imageObject += PvlKeyword("SAMPLE_TYPE", "PC_REAL"); + imageObject += PvlKeyword("VALID_MINIMUM", "16#FF7FFFFA#"); + imageObject += PvlKeyword("NULL", "16#FF7FFFFB#"); + imageObject += PvlKeyword("LOW_REPR_SATURATION", "16#FF7FFFFC#"); + imageObject += PvlKeyword("LOW_INSTR_SATURATION", "16#FF7FFFFD#"); + imageObject += PvlKeyword("HIGH_INSTR_SATURATION", "16#FF7FFFFE#"); + imageObject += PvlKeyword("HIGH_REPR_SATURATION", "16#FF7FFFFF#"); + imageObject += PvlKeyword("UNIT", "W / (m**2 micrometer sr)"); + } + imageObject += PvlKeyword("MD5_CHECKSUM", (iString) g_md5Checksum); + + stream << labelPvl; + + int recordBytes = cube->Samples(); + int labelRecords = (int) ((stream.str().length()) / recordBytes) + 1; + + labelPvl["RECORD_BYTES"] = recordBytes; + if (g_isIof) + labelPvl["FILE_RECORDS"] = (int) (cube->Lines() * 2 + labelRecords); + else + labelPvl["FILE_RECORDS"] = (int) (cube->Lines() * 4 + labelRecords); + labelPvl["LABEL_RECORDS"] = labelRecords; + labelPvl["^IMAGE"] = (int) (labelRecords + 1); + + stream.str(std::string()); + + stream << labelPvl; + pdsLabel += stream.str(); + + while (pdsLabel.length() < (unsigned int) (labelRecords * recordBytes)) { + pdsLabel += '\n'; + } + + fout << pdsLabel; + return; +} + +void CopyData ( std::ifstream &fin, std::ofstream &fout ) { + char line[2532]; + while (!fin.eof()) { + fin.read(line, 2532); + fout.write(line, fin.gcount()); + } +} diff --git a/isis/src/lro/apps/lronac2pds/lronac2pds.xml b/isis/src/lro/apps/lronac2pds/lronac2pds.xml new file mode 100644 index 0000000000000000000000000000000000000000..cb552ad23f65b3615093182b3c49f9418ffb2a4c --- /dev/null +++ b/isis/src/lro/apps/lronac2pds/lronac2pds.xml @@ -0,0 +1,66 @@ + + + + + Convert from cube to pds format + + + + Program to convert cubes to pds image files. + + + + Import and Export + + + + + + Original version + + + + + + + cube + input + + Input cube to be converted + + + The cube to be converted to pds format. + + + *.cub + + + + + filename + output + + Output pds image + + + The resulting pds file. + + + *.img + + + + + + + string + Group to modify + + The user input ID string + + "N/A" + + + + + diff --git a/isis/src/lro/apps/lronac2pds/md5.cpp b/isis/src/lro/apps/lronac2pds/md5.cpp new file mode 100644 index 0000000000000000000000000000000000000000..56ab483ab2ce6515180bec4b1e0b2214c416afb9 --- /dev/null +++ b/isis/src/lro/apps/lronac2pds/md5.cpp @@ -0,0 +1,327 @@ +/* + * This is the C++ implementation of the MD5 Message-Digest + * Algorithm desrcipted in RFC 1321. + * I translated the C code from this RFC to C++. + * There is no warranty. + * + * Feb. 12. 2005 + * Benjamin Grüdelbach + */ + +/* + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD5 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD5 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +//md5 class include +#include "md5.h" + +// Constants for MD5Transform routine. +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) +//#define ROTATE_LEFT(x, n) (((x) << (n)) | (( (UINT32) x) >> (32-(n)))) + +/* +FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. +*/ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (unsigned long int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (unsigned long int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (unsigned long int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (unsigned long int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. */ +void MD5::MD5Init (MD5_CTX *context) +{ + context->count[0] = context->count[1] = 0; + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* + MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. +*/ +void MD5::MD5Update (MD5_CTX *context, unsigned char *input, unsigned int inputLen) +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ( (context->count[0] += ((unsigned long int)inputLen << 3)) + < ((unsigned long int)inputLen << 3)) + context->count[1]++; + + context->count[1] += ((unsigned long int)inputLen >> 29); + partLen = 64 - index; + + /* + * Transform as many times as possible. + */ + if (inputLen >= partLen) + { + MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy ((POINTER)&context->buffer[index], + (POINTER)&input[i], + inputLen-i); +} + +/* + * MD5 finalization. Ends an MD5 message-digest operation, writing the + * the message digest and zeroizing the context. + */ +void MD5::MD5Final (unsigned char digest[16], MD5_CTX *context) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* + * Pad out to 56 mod 64. + */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* + * Zeroize sensitive information. + */ + MD5_memset ((POINTER)context, 0, sizeof (*context)); +} + +/* + * MD5 basic transformation. Transforms state based on block. + */ +void MD5::MD5Transform (unsigned long int state[4], unsigned char block[64]) +{ + unsigned long int a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* + * Zeroize sensitive information. + */ + MD5_memset ((POINTER)x, 0, sizeof (x)); +} + +/* + * Encodes input (unsigned long int) into output (unsigned char). Assumes len is + * a multiple of 4. + */ +void MD5::Encode (unsigned char *output, unsigned long int *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* + * Decodes input (unsigned char) into output (unsigned long int). Assumes len is + * a multiple of 4. + */ +void MD5::Decode (unsigned long int *output, unsigned char *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((unsigned long int)input[j]) | + (((unsigned long int)input[j+1]) << 8) | + (((unsigned long int)input[j+2]) << 16) | + (((unsigned long int)input[j+3]) << 24); +} + +/* + * Note: Replace "for loop" with standard memcpy if possible. + */ +void MD5::MD5_memcpy (POINTER output, POINTER input, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; +} + +/* + * Note: Replace "for loop" with standard memset if possible. + */ +void MD5::MD5_memset (POINTER output,int value,unsigned int len) +{ + unsigned int i; + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; +} + +/* + * EOF + */ diff --git a/isis/src/lro/apps/lronac2pds/md5.h b/isis/src/lro/apps/lronac2pds/md5.h new file mode 100644 index 0000000000000000000000000000000000000000..0d16c05a73b9202a70ec21b63e20b0df67a58ff7 --- /dev/null +++ b/isis/src/lro/apps/lronac2pds/md5.h @@ -0,0 +1,86 @@ +/* + * This is the C++ implementation of the MD5 Message-Digest + * Algorithm desrcipted in RFC 1321. + * I translated the C code from this RFC to C++. + * There is no warranty. + * + * Feb. 12. 2005 + * Benjamin Grüdelbach + */ + +/* + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD5 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD5 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +//---------------------------------------------------------------------- +//include protection +#ifndef MD5_H +#define MD5_H + +//---------------------------------------------------------------------- +//STL includes +#include + +//---------------------------------------------------------------------- +//typedefs +typedef unsigned char *POINTER; + +/* + * MD5 context. + */ +typedef struct +{ + unsigned long int state[4]; /* state (ABCD) */ + unsigned long int count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +/* + * MD5 class + */ +class MD5 +{ + + private: + + void MD5Transform (unsigned long int state[4], unsigned char block[64]); + void Encode (unsigned char*, unsigned long int*, unsigned int); + void Decode (unsigned long int*, unsigned char*, unsigned int); + void MD5_memcpy (POINTER, POINTER, unsigned int); + void MD5_memset (POINTER, int, unsigned int); + + public: + + void MD5Init (MD5_CTX*); + void MD5Update (MD5_CTX*, unsigned char*, unsigned int); + void MD5Final (unsigned char [16], MD5_CTX*); + + MD5(){}; +}; + +//---------------------------------------------------------------------- +//End of include protection +#endif + +/* + * EOF + */ diff --git a/isis/src/lro/apps/lronac2pds/md5wrapper.cpp b/isis/src/lro/apps/lronac2pds/md5wrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..04a378dfe95cb3ee7f4fad09752e961caac197d8 --- /dev/null +++ b/isis/src/lro/apps/lronac2pds/md5wrapper.cpp @@ -0,0 +1,134 @@ +/* + * This is part of my wrapper-class to create + * a MD5 Hash from a string and a file. + * + * This code is completly free, you + * can copy it, modify it, or do + * what ever you want with it. + * + * Feb. 2005 + * Benjamin Grüdelbach + */ + +//---------------------------------------------------------------------- +//basic includes +#include +#include + +//my includes +#include "md5wrapper.h" +#include "md5.h" + +//---------privates-------------------------- + +/* + * internal hash function, calling + * the basic methods from md5.h + */ +std::string md5wrapper::hashit(std::string text) +{ + MD5_CTX ctx; + + //init md5 + md5->MD5Init(&ctx); + //update with our string + md5->MD5Update(&ctx, + (unsigned char*)text.c_str(), + text.length()); + + //create the hash + unsigned char buff[16] = ""; + md5->MD5Final((unsigned char*)buff,&ctx); + + //converte the hash to a string and return it + return convToString(buff); +} + +/* + * converts the numeric hash to + * a valid std::string. + * (based on Jim Howard's code; + * http://www.codeproject.com/cpp/cmd5.asp) + */ +std::string md5wrapper::convToString(unsigned char *bytes) +{ + char asciihash[33]; + + int p = 0; + for(int i=0; i<16; i++) + { + ::sprintf(&asciihash[p],"%02x",bytes[i]); + p += 2; + } + asciihash[32] = '\0'; + return std::string(asciihash); +} + +//---------publics-------------------------- + +//constructor +md5wrapper::md5wrapper() +{ + md5 = new MD5(); +} + + +//destructor +md5wrapper::~md5wrapper() +{ + delete md5; +} + +/* + * creates a MD5 hash from + * "text" and returns it as + * string + */ +std::string md5wrapper::getHashFromString(std::string text) +{ + return this->hashit(text); +} + + +/* + * creates a MD5 hash from + * a file specified in "filename" and + * returns it as string + * (based on Ronald L. Rivest's code + * from RFC1321 "The MD5 Message-Digest Algorithm") + */ +std::string md5wrapper::getHashFromFile(std::string filename) +{ + FILE *file; + MD5_CTX context; + + int len; + unsigned char buffer[1024], digest[16]; + + //open file + if ((file = fopen (filename.c_str(), "rb")) == NULL) + { + return "-1"; + } + + //init md5 + md5->MD5Init (&context); + + //read the filecontent + while ( (len = fread (buffer, 1, 1024, file)) ) + { + md5->MD5Update (&context, buffer, len); + } + + /* + generate hash, close the file and return the + hash as std::string + */ + md5->MD5Final (digest, &context); + fclose (file); + return convToString(digest); + } + +/* + * EOF + */ diff --git a/isis/src/lro/apps/lronac2pds/md5wrapper.h b/isis/src/lro/apps/lronac2pds/md5wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..477969bfe0d43adbdbc6ae8e9672270ba8592bcc --- /dev/null +++ b/isis/src/lro/apps/lronac2pds/md5wrapper.h @@ -0,0 +1,67 @@ +/* + * This is my wrapper-class to create + * a MD5 Hash from a string and a file. + * + * This code is completly free, you + * can copy it, modify it, or do + * what ever you want with it. + * + * Feb. 2005 + * Benjamin Grüdelbach + */ + +//include protection +#ifndef MD5WRAPPER_H +#define MD5WRAPPER_H + +//basic includes +#include + +//forwards +class MD5; + +class md5wrapper +{ + private: + MD5 *md5; + + /* + * internal hash function, calling + * the basic methods from md5.h + */ + std::string hashit(std::string text); + + /* + * converts the numeric giets to + * a valid std::string + */ + std::string convToString(unsigned char *bytes); + public: + //constructor + md5wrapper(); + + //destructor + ~md5wrapper(); + + /* + * creates a MD5 hash from + * "text" and returns it as + * string + */ + std::string getHashFromString(std::string text); + + /* + * creates a MD5 hash from + * a file specified in "filename" and + * returns it as string + */ + std::string getHashFromFile(std::string filename); +}; + + +//include protection +#endif + +/* + * EOF + */ diff --git a/isis/src/lro/apps/lronac2pds/tsts/Makefile b/isis/src/lro/apps/lronac2pds/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/lro/apps/lronac2pds/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/lro/apps/lronaccal/Makefile b/isis/src/lro/apps/lronaccal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/lro/apps/lronaccal/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/lro/apps/lronaccal/lronaccal.cpp b/isis/src/lro/apps/lronaccal/lronaccal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..02269e751cdef17b3a7f76ef311437e54b856f49 --- /dev/null +++ b/isis/src/lro/apps/lronaccal/lronaccal.cpp @@ -0,0 +1,481 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "Camera.h" +#include "iTime.h" +#include "iException.h" +#include "TextFile.h" +#include "LineManager.h" +#include "Brick.h" +#include "Table.h" +#include "Statistics.h" +#include +#include + +using namespace std; +using namespace Isis; + +// Working functions and parameters +void ResetGlobals (); +void CopyCubeIntoArray ( string &fileString, vector &data ); +void ReadTextDataFile ( string &fileString, vector &data ); +void ReadTextDataFile ( string &fileString, vector > &data ); +void Calibrate ( Buffer &in, Buffer &out ); +void RemoveMaskedOffset ( Buffer &line ); +void CorrectDark ( Buffer &in ); +void CorrectNonlinearity ( Buffer &in ); +void CorrectFlatfield ( Buffer &in ); +void RadiometricCalibration ( Buffer &in ); + +#define LINE_SIZE 5064 +#define MAXNONLIN 600 +#define SOLAR_RADIUS 695500 +#define KM_PER_AU 149597871 + +vector g_oddMaskedPixels, g_evenMaskedPixels, g_summedMaskedPixels; + +double g_radianceLeft, g_radianceRight, g_iofLeft, g_iofRight; + +double g_exposure; // Exposure duration +double g_solarDistance; // average distance in [AU] + +bool g_summed, g_masked, g_maskedLeft, g_dark, g_nonlinear, g_flatfield, g_radiometric, g_iof, g_isLeftNac; + +vector g_averageDarkLine, g_linearOffsetLine, g_flatfieldLine; + +vector > g_linearityCoefficients; + +// Main moccal routine +void IsisMain () { + ResetGlobals(); + // We will be processing by line + ProcessByLine p; + + // Setup the input and make sure it is a ctx file + UserInterface &ui = Application::GetUserInterface(); + + g_masked = ui.GetBoolean("MASKED"); + g_dark = ui.GetBoolean("DARK"); + g_nonlinear = ui.GetBoolean("NONLINEARITY"); + g_flatfield = ui.GetBoolean("FLATFIELD"); + g_radiometric = ui.GetBoolean("RADIOMETRIC"); + g_iof = (ui.GetString("RADIOMETRICTYPE") == "IOF"); + + Isis::Pvl lab(ui.GetFilename("FROM")); + Isis::PvlGroup &inst = lab.FindGroup("Instrument", Pvl::Traverse); + + // Check if it is a NAC image + std::string instId = inst["InstrumentId"]; + if (instId != "NACL" && instId != "NACR") { + string msg = "This is not a NAC image. lrocnaccal requires a NAC image."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + // And check if it has already run through calibration + if (lab.FindObject("IsisCube").HasGroup("Radiometry")) { + string msg = "This image has already been calibrated"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + if (instId == "NACL") + g_isLeftNac = true; + else + g_isLeftNac = false; + + if ((int) inst["SpatialSumming"] == 1) + g_summed = false; + else + g_summed = true; + + g_exposure = inst["LineExposureDuration"]; + + p.SetInputCube("FROM", OneBand); + + iString darkFile, flatFile, offsetFile, coefficientFile; + + if (g_masked) { + iString maskedFile = ui.GetAsString("MASKEDFILE"); + + if (maskedFile.Equal("Default") || maskedFile.length() == 0) + maskedFile = "$lro/calibration/" + instId + "_MaskedPixels.0001.pvl"; + + Filename maskedFilename(maskedFile); + if ((maskedFilename.Expanded()).find("?") != string::npos) + maskedFilename.HighestVersion(); + if (!maskedFilename.Exists()) { + string msg = maskedFile + " does not exist."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + Pvl maskedPvl(maskedFilename.Expanded()); + + if (g_summed) { + PvlKeyword summedPixels = maskedPvl["Summed"]; + for (int i = 0; i < summedPixels.Size(); i++) + g_summedMaskedPixels.push_back(summedPixels[i]); + } + else { + PvlKeyword evenPixels = maskedPvl["Even"]; + for (int i = 0; i < evenPixels.Size(); i++) + g_evenMaskedPixels.push_back(evenPixels[i]); + PvlKeyword oddPixels = maskedPvl["Odd"]; + for (int i = 0; i < oddPixels.Size(); i++) + g_oddMaskedPixels.push_back(oddPixels[i]); + } + } + + if (g_dark) { + darkFile = ui.GetAsString("DARKFILE"); + + if (darkFile.Equal("Default") || darkFile.length() == 0) { + darkFile = "$lro/calibration/" + instId + "_AverageDarks"; + if (g_summed) + darkFile += "_Summed"; + darkFile += ".????.cub"; + } + CopyCubeIntoArray(darkFile, g_averageDarkLine); + } + + if (g_nonlinear) { + offsetFile = ui.GetAsString("OFFSETFILE"); + + if (offsetFile.Equal("Default") || offsetFile.length() == 0) { + offsetFile = "$lro/calibration/" + instId + "_LinearizationOffsets"; + if (g_summed) + offsetFile += "_Summed"; + offsetFile += ".????.cub"; + } + CopyCubeIntoArray(offsetFile, g_linearOffsetLine); + + coefficientFile = ui.GetAsString("NONLINEARITYFILE"); + if (coefficientFile.Equal("Default") || coefficientFile.length() == 0) { + coefficientFile = "$lro/calibration/" + instId + "_LinearizationCoefficients.????.txt"; + } + ReadTextDataFile(coefficientFile, g_linearityCoefficients); + } + + if (g_flatfield) { + flatFile = ui.GetAsString("FLATFIELDFILE"); + + if (flatFile.Equal("Default") || flatFile.length() == 0) { + flatFile = "$lro/calibration/" + instId + "_Flatfield"; + ; + if (g_summed) + flatFile += "_Summed"; + flatFile += ".????.cub"; + } + CopyCubeIntoArray(flatFile, g_flatfieldLine); + } + + if (g_radiometric) { + iString radFile = ui.GetAsString("RADIOMETRICFILE"); + + if (radFile.Equal("Default") || radFile.length() == 0) + radFile = "$lro/calibration/NAC_RadiometricResponsivity.????.pvl"; + + Filename radFilename(radFile); + if ((radFilename.Expanded()).find("?") != string::npos) + radFilename.HighestVersion(); + if (!radFilename.Exists()) { + string msg = radFile + " does not exist."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + Pvl radPvl(radFilename.Expanded()); + + if (g_iof) { + try { + iTime startTime((string) inst["StartTime"]); + double etStart = startTime.Et(); + // Get the distance between the Moon and the Sun at the given time in + // Astronomical Units (AU) + string bspKernel1 = p.MissionData("lro", "/kernels/tspk/moon_pa_de421_1900-2050.bpc", false); + string bspKernel2 = p.MissionData("lro", "/kernels/tspk/de421.bsp", false); + furnsh_c(bspKernel1.c_str()); + furnsh_c(bspKernel2.c_str()); + string pckKernel1 = p.MissionData("base", "/kernels/pck/pck?????.tpc", true); + string pckKernel2 = p.MissionData("lro", "/kernels/pck/moon_080317.tf", false); + string pckKernel3 = p.MissionData("lro", "/kernels/pck/moon_assoc_me.tf", false); + furnsh_c(pckKernel1.c_str()); + furnsh_c(pckKernel2.c_str()); + furnsh_c(pckKernel3.c_str()); + double sunpos[6], lt; + spkezr_c("sun", etStart, "MOON_ME", "LT+S", "MOON", sunpos, <); + g_solarDistance = vnorm_c(sunpos) / KM_PER_AU; + unload_c(bspKernel1.c_str()); + unload_c(bspKernel2.c_str()); + unload_c(pckKernel1.c_str()); + unload_c(pckKernel2.c_str()); + unload_c(pckKernel3.c_str()); + } + catch (iException &e) { + string msg = "Unable to find the necessary SPICE kernels for converting to IOF"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + g_iofLeft = radPvl["IOF_LEFT"]; + g_iofRight = radPvl["IOF_RIGHT"]; + } + else { + g_radianceLeft = radPvl["Radiance_LEFT"]; + g_radianceRight = radPvl["Radiance_RIGHT"]; + } + } + + // Setup the output cube + Cube *ocube = p.SetOutputCube("TO"); + + // Start the line-by-line calibration sequence + p.StartProcess(Calibrate); + + PvlGroup calgrp("Radiometry"); + if (g_masked) { + if (g_summed) { + PvlKeyword darkColumns("DarkColumns"); + for (unsigned int i = 0; i < g_summedMaskedPixels.size(); i++) + darkColumns += g_summedMaskedPixels[i]; + calgrp += darkColumns; + } + // Even and Odd seperately + else { + PvlKeyword evenDarkColumns("EvenDarkColumns"); + PvlKeyword oddDarkColumns("OddDarkColumns"); + + for (unsigned int i = 0; i < g_evenMaskedPixels.size(); i++) + evenDarkColumns += g_evenMaskedPixels[i]; + for (unsigned int i = 0; i < g_oddMaskedPixels.size(); i++) + oddDarkColumns += g_oddMaskedPixels[i]; + + calgrp += evenDarkColumns; + calgrp += oddDarkColumns; + } + } + if (g_dark) + calgrp += PvlKeyword("DarkFile", darkFile); + if (g_nonlinear) { + calgrp += PvlKeyword("NonlinearOffset", offsetFile); + calgrp += PvlKeyword("LinearizationCoefficients", coefficientFile); + } + if (g_flatfield) + calgrp += PvlKeyword("FlatFile", flatFile); + if (g_radiometric) { + if (g_iof) { + calgrp += PvlKeyword("RadiometricType", "IOF"); + if (g_isLeftNac) + calgrp += PvlKeyword("ResponsivityValue", g_iofLeft); + else + calgrp += PvlKeyword("ResponsivityValue", g_iofRight); + } + else { + calgrp += PvlKeyword("RadiometricType", "AbsoluteRadiance"); + if (g_isLeftNac) + calgrp += PvlKeyword("ResponsivityValue", g_radianceLeft); + else + calgrp += PvlKeyword("ResponsivityValue", g_radianceRight); + } + calgrp += PvlKeyword("SolarDistance", g_solarDistance); + } + ocube->PutGroup(calgrp); + p.EndProcess(); +} + +void ResetGlobals () { + g_exposure = 1.0; // Exposure duration + g_solarDistance = 1.01; // average distance in [AU] + + g_oddMaskedPixels.clear(); + g_evenMaskedPixels.clear(); + g_summedMaskedPixels.clear(); + + g_radianceLeft = 1.0; + g_radianceRight = 1.0; + g_iofLeft = 1.0; + g_iofRight = 1.0; + + g_summed = true; + g_masked = true; + g_dark = true; + g_nonlinear = true; + g_flatfield = true; + g_radiometric = true; + g_iof = true; + g_isLeftNac = true; + g_averageDarkLine.clear(); + g_linearOffsetLine.clear(); + g_flatfieldLine.clear(); + g_linearityCoefficients.clear(); +} + +// Line processing routine +void Calibrate ( Buffer &in, Buffer &out ) { + for (int i = 0; i < in.size(); i++) + out[i] = in[i]; + + if (g_masked) + RemoveMaskedOffset(out); + + if (g_dark) + CorrectDark(out); + + if (g_nonlinear) + CorrectNonlinearity(out); + + if (g_flatfield) + CorrectFlatfield(out); + + if (g_radiometric) + RadiometricCalibration(out); +} + +void CopyCubeIntoArray ( string &fileString, vector &data ) { + Cube cube; + Filename filename(fileString); + if ((filename.Expanded()).find("?") != string::npos) + filename.HighestVersion(); + if (!filename.Exists()) { + string msg = fileString + " does not exist."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + cube.Open(filename.Expanded()); + Brick brick(cube.Samples(), cube.Lines(), cube.Bands(), cube.PixelType()); + brick.SetBasePosition(1, 1, 1); + cube.Read(brick); + data.clear(); + for (int i = 0; i < cube.Samples(); i++) + data.push_back(brick[i]); + + fileString = filename.Expanded(); +} + +void ReadTextDataFile ( string &fileString, vector &data ) { + Filename filename(fileString); + if ((filename.Expanded()).find("?") != string::npos) + filename.HighestVersion(); + if (!filename.Exists()) { + string msg = fileString + " does not exist."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + TextFile file(filename.Expanded()); + iString lineString; + unsigned int line = 0; + while (file.GetLine(lineString)) { + data.push_back((lineString.Token(" ,;")).ToDouble()); + line++; + } + fileString = filename.Expanded(); +} + +void ReadTextDataFile ( string &fileString, vector > &data ) { + Filename filename(fileString); + if ((filename.Expanded()).find("?") != string::npos) + filename.HighestVersion(); + if (!filename.Exists()) { + string msg = fileString + " does not exist."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + TextFile file(filename.Expanded()); + iString lineString; + while (file.GetLine(lineString)) { + vector line; + lineString.ConvertWhiteSpace(); + lineString.Compress(); + lineString.TrimHead(" ,"); + while (lineString.size() > 0) { + line.push_back((lineString.Token(" ,")).ToDouble()); + } + + data.push_back(line); + } + + fileString = filename.Expanded(); +} + +void RemoveMaskedOffset ( Buffer &in ) { + if (g_summed) { + Statistics stats; + for (unsigned int i = 0; i < g_summedMaskedPixels.size(); i++) + stats.AddData(&in[g_summedMaskedPixels[i]], 1); + + double mean = stats.Average(); + + for (int i = 0; i < in.size(); i++) + in[i] -= mean; + } + // Even and Odd seperately + else { + + Statistics evenStats, oddStats; + + for (unsigned int i = 0; i < g_evenMaskedPixels.size(); i++) + evenStats.AddData(&in[g_evenMaskedPixels[i]], 1); + for (unsigned int i = 0; i < g_oddMaskedPixels.size(); i++) + oddStats.AddData(&in[g_oddMaskedPixels[i]], 1); + + double evenMean = evenStats.Average(); + double oddMean = oddStats.Average(); + + for (int i = 0; i < in.size(); i += 2) { + in[i] -= evenMean; + in[i + 1] -= oddMean; + } + } +} + +void CorrectDark ( Buffer &in ) { + for (int i = 0; i < in.size(); i++) { + if (!IsSpecial(in[i])) + in[i] -= g_averageDarkLine[i]; + else + in[i] = Isis::Null; + } +} + +void CorrectNonlinearity ( Buffer &in ) { + for (int i = 0; i < in.size(); i++) { + if (!IsSpecial(in[i])) { + in[i] += g_linearOffsetLine[i]; + + if (in[i] < MAXNONLIN) { + if (g_summed) + in[i] -= (1.0 / (g_linearityCoefficients[2* i ][0] * pow(g_linearityCoefficients[2* i ][1], in[i]) + + g_linearityCoefficients[2* i ][2]) + 1.0 / (g_linearityCoefficients[2* i + 1][0] * pow( + g_linearityCoefficients[2* i + 1][1], in[i]) + g_linearityCoefficients[2* i + 1][2])) / 2; + else + in[i] -= 1.0 / (g_linearityCoefficients[i][0] * pow(g_linearityCoefficients[i][1], in[i]) + + g_linearityCoefficients[i][2]); + } + } + else + in[i] = Isis::Null; + } +} + +void CorrectFlatfield ( Buffer &in ) { + for (int i = 0; i < in.size(); i++) { + if (!IsSpecial(in[i]) && g_flatfieldLine[i] > 0) + in[i] /= g_flatfieldLine[i]; + else + in[i] = Isis::Null; + } +} + +void RadiometricCalibration ( Buffer &in ) { + for (int i = 0; i < in.size(); i++) { + if (!IsSpecial(in[i])) { + in[i] /= g_exposure; + if (g_iof) { + if (g_isLeftNac) + in[i] = in[i] * pow(g_solarDistance, 2) / g_iofLeft; + else + in[i] = in[i] * pow(g_solarDistance, 2) / g_iofRight; + } + else { + if (g_isLeftNac) + in[i] = in[i] / g_radianceLeft; + else + in[i] = in[i] / g_radianceRight; + } + } + else + in[i] = Isis::Null; + } +} diff --git a/isis/src/lro/apps/lronaccal/lronaccal.xml b/isis/src/lro/apps/lronaccal/lronaccal.xml new file mode 100644 index 0000000000000000000000000000000000000000..fb96f8e3f563476de470ef5dabb2f32d855612b2 --- /dev/null +++ b/isis/src/lro/apps/lronaccal/lronaccal.xml @@ -0,0 +1,242 @@ + + + + + + Radiometrically calibrates a LROC NAC image + + + +

    + lronaccal performs radiometric corrections to images acquired by the Narrow Angle + Camera aboard the Lunar Reconnaissance Orbiter spacecraft. The LROC NAC camera + will make observations simulteously with the HiRise camera. +

    + +

    + The LRO NAC detector has a total of 5064 pixels, divided among an A + channel and a B channel. The pixels alternate between the two channels: + ABABABAB, etc. Images from LROC NAC may or may not include all pixels in the + acquired image. There are special summing modes that are utilized + on-board the spacecraft to average detector pixels to combine them into a + single output pixel value. The value of the ISIS label keyord, + SpatialSumming, indicates the number of samples that were summed and + averaged to result in the pixel values stored in the file. Note that this + will reduce the number of samples in the output image by a factor of at + most the SpatialSumming mode value. +

    +

    + The LROC NAC camera has the ability to acquire images of differing sizes in + both line and sample. The starting hardware detector pixel for the + acquired image is specified by the ISIS label keyword, SampleFirstPixel. + The first pixel in the detector is indicated by a value of 0. +

    + +

    + Dark current pixels are taken for each line from the masked pixels + that lie along each edge of the image. +

    + +

    + If SpatialSumming is 1 the dark current pixels are averaged together then + this average is subtracted from all image pixels. If SpatialSumming is 2, + the dark current pixels for the A and B channel are averaged separately, + then the A channel dark average is subtracted from the A channel image + pixels and the B channel dark average is subtracted from the B channel + image pixels. +

    + +
    + + + + Original version + + + + + Lunar Reconnaissance Orbiter + + + + + lronac2isis + + + + + + + cube + input + + Level 0 LROC NAC image + + + An uncalibrated LROC NAC image. + + + *.cub + + + + + cube + output + real + + Level 1 LROC NAC image + + + The resultant radiometrically calibrated cube + + + + + + + boolean + True + + Calibrate using the masked pixels. + + + + MaskedFile + + + filename + Default + + + + + + + + + + boolean + True + + Calibrate using the average dark pixels. + + + + DarkFile + + + + filename + Default + + Calibrate using the average dark pixels. + + + + + + + + + boolean + True + + Calibrate using nonlinearity. + + + + OffsetFile + NonlinearityFile + + + + filename + Default + + The Nonlinearity offset values. + + + + + + + filename + Default + + Calibrate using the average dark pixels. + + + + + + + + + boolean + True + + Calibrate using the flatfield. + + + + FlatfieldFile + + + + filename + Default + + Calibrate using the average dark pixels. + + + + + + + + + boolean + True + + Calibrate using radiometric calibration. + + + + RadiometricType + RadiometricFile + + + + string + + Which radiance correction? + + + + IOF + + + + + + + + filename + Default + + + + + + + +
    diff --git a/isis/src/lro/apps/lronaccal/tsts/Makefile b/isis/src/lro/apps/lronaccal/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/lro/apps/lronaccal/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/lro/apps/lronaccal/tsts/default/Makefile b/isis/src/lro/apps/lronaccal/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8dc50ab45f7f94e654a5a1af835b356a55987225 --- /dev/null +++ b/isis/src/lro/apps/lronaccal/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = lronaccal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/M111607830RE_crop.cub \ + to=$(OUTPUT)/M111607830RE_crop_cal.cub > /dev/null; diff --git a/isis/src/lro/apps/lrowac2isis/Makefile b/isis/src/lro/apps/lrowac2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/lro/apps/lrowac2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/lro/apps/lrowac2isis/lrowac2isis.cpp b/isis/src/lro/apps/lrowac2isis/lrowac2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..413cec76aab06a76dcc8ca49178eb49c632c3102 --- /dev/null +++ b/isis/src/lro/apps/lrowac2isis/lrowac2isis.cpp @@ -0,0 +1,834 @@ +#include "Isis.h" + +#include +#include + +#include + +#include "ProcessImportPds.h" +#include "LineManager.h" +#include "OriginalLabel.h" +#include "Brick.h" +#include "History.h" +#include "Stretch.h" + +using namespace std; +using namespace Isis; + +vector outputCubes; +vector frameletLines; +void separateFramelets(Buffer &in); +void writeNullsToFile(); +void TranslateLabels (Pvl &pdsLab, Pvl &isis3VisEven, Pvl &isis3VisOdd, + Pvl &isis3UvEven, Pvl &isis3UvOdd); +void ValidateInputLabels(Pvl &pdsLab); + +std::vector padding; +int colorOffset = 0; +int inputCubeLines = 0; + +// Output UV Files +Cube *uveven = NULL; +Cube *uvodd = NULL; + +// Output VIS Files +Cube *viseven = NULL; +Cube *visodd = NULL; + +Stretch lookupTable; + +bool flip = false; + +void IsisMain () { + colorOffset = 0; + frameletLines.clear(); + outputCubes.clear(); + + uveven = NULL; + uvodd = NULL; + viseven = NULL; + visodd = NULL; + + ProcessImportPds p; + Pvl pdsLab; + + UserInterface &ui = Application::GetUserInterface(); + string fromFile = ui.GetFilename("FROM"); + + flip = false;//ui.GetBoolean("FLIP"); + + p.SetPdsFile (fromFile, "", pdsLab); + ValidateInputLabels(pdsLab); + inputCubeLines = p.Lines(); + + lookupTable = Stretch(); + + // read the lut if the option is on + if( ui.GetBoolean("UNLUT") && pdsLab["LRO:LOOKUP_TABLE_TYPE"][0] == "STORED" ) { + PvlKeyword lutKeyword = pdsLab["LRO:LOOKUP_CONVERSION_TABLE"]; + + for( int i = 0; i < lutKeyword.Size(); i ++ ) { + iString lutPair = lutKeyword[i]; + lutPair.ConvertWhiteSpace(); + lutPair.Remove("() "); + iString outValueMin = lutPair.Token(" ,"); + iString outValueMax = lutPair.Token(" ,"); + lookupTable.AddPair(i, ((double)outValueMin + (double)outValueMax) / 2.0); + } + } + + string instModeId = pdsLab["INSTRUMENT_MODE_ID"]; + + // this will be used to convert num input lines to num output lines, + // only changed for when both uv and vis exist (varying summing) + double visOutputLineRatio = 1.0; + double uvOutputLineRatio = 1.0; + + int numFilters = 0; + if( ui.GetBoolean("COLOROFFSET") ) { + colorOffset = ui.GetInteger("COLOROFFSETSIZE"); + } + + // Determine our band information based on + // INSTRUMENT_MODE_ID - FILTER_NUMBER is + // only going to be used for BW images + if( instModeId == "COLOR" ) { + numFilters = 7; + frameletLines.push_back(4); + frameletLines.push_back(4); + frameletLines.push_back(14); + frameletLines.push_back(14); + frameletLines.push_back(14); + frameletLines.push_back(14); + frameletLines.push_back(14); + + uveven = new Cube(); + uvodd = new Cube(); + viseven = new Cube(); + visodd = new Cube(); + + // 14 output lines (1 framelet) from 5vis/2uv lines + visOutputLineRatio = 14.0 / (14.0 * 5.0 + 4.0 * 2.0); + + // 4 output lines (1 framelet) from 5vis/2uv lines + uvOutputLineRatio = 4.0 / (14.0 * 5.0 + 4.0 * 2.0); + } + else if( instModeId == "VIS" ) { + numFilters = 5; + + frameletLines.push_back(14); + frameletLines.push_back(14); + frameletLines.push_back(14); + frameletLines.push_back(14); + frameletLines.push_back(14); + + viseven = new Cube(); + visodd = new Cube(); + + // 14 output lines (1 framelet) from 5vis/2uv lines + visOutputLineRatio = 14.0 / (14.0 * 5.0); + } + else if( instModeId == "UV" ) { + numFilters = 2; + + frameletLines.push_back(4); + frameletLines.push_back(4); + + uveven = new Cube(); + uvodd = new Cube(); + + // 4 output lines (1 framelet) from 2uv lines + uvOutputLineRatio = 4.0 / (4.0 * 2.0); + } + else if( instModeId == "BW" ) { + numFilters = 1; + + frameletLines.push_back(14); + + viseven = new Cube(); + visodd = new Cube(); + } + + padding.resize(numFilters); + + + for( int filter = 0; filter < numFilters; filter++ ) { + padding[filter] = (colorOffset * frameletLines[filter]) * filter; + + // dont count UV for VIS offsetting + if( instModeId == "COLOR" && filter > 1 ) { + padding[filter] -= 2 * colorOffset * frameletLines[filter]; + } + } + + Filename baseFilename(ui.GetFilename("TO")); + + if( uveven && uvodd ) { + // padding[1] is max padding for UV + int numSamples = ((viseven) ? p.Samples() / 4 : p.Samples()); + numSamples = 128; // UV is alway sum 4 so it is 128 samples + int numLines = (int) (uvOutputLineRatio * inputCubeLines + 0.5) + padding[1]; + int numBands = 2; + + uveven->SetDimensions(numSamples, numLines, numBands); + uveven->SetPixelType(Isis::Real); + + string filename = baseFilename.Path() + "/" + baseFilename.Basename() + ".uv.even.cub"; + uveven->Create(filename); + + uvodd->SetDimensions(numSamples, numLines, numBands); + uvodd->SetPixelType(Isis::Real); + + filename = baseFilename.Path() + "/" + baseFilename.Basename() + ".uv.odd.cub"; + uvodd->Create(filename); + } + + if( viseven && visodd ) { + // padding[size-1] is max padding for vis (padding[0] or padding[4] or padding[6]) + int numSamples = p.Samples(); + int numLines = (int)(visOutputLineRatio * inputCubeLines + 0.5) + padding[padding.size()-1]; + int numBands = ((uveven)? padding.size() - 2 : padding.size()); + + viseven->SetDimensions(numSamples, numLines, numBands); + viseven->SetPixelType(Isis::Real); + + string filename = baseFilename.Path() + "/" + baseFilename.Basename() + ".vis.even.cub"; + viseven->Create(filename); + + visodd->SetDimensions(numSamples, numLines, numBands); + visodd->SetPixelType(Isis::Real); + + filename = baseFilename.Path() + "/" + baseFilename.Basename() + ".vis.odd.cub"; + visodd->Create(filename); + } + + Pvl isis3VisEvenLab, isis3VisOddLab, isis3UvEvenLab, isis3UvOddLab; + TranslateLabels(pdsLab, isis3VisEvenLab, isis3VisOddLab, isis3UvEvenLab, isis3UvOddLab); + + writeNullsToFile(); + p.StartProcess(separateFramelets); + p.EndProcess(); + + // Add original labels + OriginalLabel origLabel(pdsLab); + + int numFramelets = padding.size(); + PvlKeyword numFrameletsKeyword("NumFramelets", numFramelets); + + if( uveven ) { + for( int grp = 0; grp < isis3UvEvenLab.Groups(); grp++ ) { + uveven->PutGroup(isis3UvEvenLab.Group(grp)); + } + + History history("IsisCube"); + history.AddEntry(); + uveven->Write(history); + uveven->Write(origLabel); + + uveven->Close(); + delete uveven; + uveven = NULL; + } + + if( uvodd ) { + for( int grp = 0; grp < isis3UvOddLab.Groups(); grp++ ) { + uvodd->PutGroup(isis3UvOddLab.Group(grp)); + } + + History history("IsisCube"); + history.AddEntry(); + uvodd->Write(history); + uvodd->Write(origLabel); + + uvodd->Close(); + delete uvodd; + uvodd = NULL; + } + + if( viseven ) { + for( int grp = 0; grp < isis3VisEvenLab.Groups(); grp++ ) { + viseven->PutGroup(isis3VisEvenLab.Group(grp)); + } + + History history("IsisCube"); + history.AddEntry(); + viseven->Write(history); + viseven->Write(origLabel); + + viseven->Close(); + delete viseven; + viseven = NULL; + } + + if( visodd ) { + for( int grp = 0; grp < isis3VisOddLab.Groups(); grp++ ) { + visodd->PutGroup(isis3VisOddLab.Group(grp)); + } + + History history("IsisCube"); + history.AddEntry(); + visodd->Write(history); + visodd->Write(origLabel); + + visodd->Close(); + delete visodd; + visodd = NULL; + } +} + +/** + * Get the framelet number line is in. + * + * @param line input line number (starting at 1) + * @param even Set to true if even framelet, otherwise false + * + * @return int framelet this line belongs to + */ +int getFrameletNumber ( int line, int &frameletSetNumber, int &frameletSetOffset, + int &frameletLineOffset, bool &even ) { + int frameletNumber = -1; + + int frameletSetSize = 0; + + // framelet set = one capture of vis/uv data (1 to 7 framelets) + for( unsigned int i = 0; i < frameletLines.size(); i++ ) { + frameletSetSize += frameletLines[i]; + } + + frameletSetNumber = (line - 1) / frameletSetSize; + + // frameletSetNumber is 0-based, but even is 1-based, so logic reversed from + // what would be intuitive. An odd frameletSetNumber means even framelet. + even = ((frameletSetNumber % 2) == 1); + + // offset into set + frameletSetOffset = line - (frameletSetSize * frameletSetNumber) - 1; + + int offset = frameletSetOffset; + for( unsigned int framelet = 0; frameletNumber < 0; framelet++ ) { + offset -= frameletLines.at(framelet); + + if( offset < 0 ) { + frameletNumber = framelet; + frameletLineOffset = offset + frameletLines.at(framelet); + } + } + + return frameletNumber; +} + +//! Separates each of the individual WAC framelets into the right place +void separateFramelets ( Buffer &in ) { + // this is true if uv is summed and mixed with unsummed vis + bool extractMiddleSamples = false; + // This is the framelet set the line belongs to + int frameletSet = 0; + // this is the offset into the set + int frameletSetOffset = 0; + // this is true if framelet belongs in an even cube + bool even = false; + // line # in current framelet + int frameletLineOffset = 0; + // this is the framelet number the current line belongs in + int framelet = getFrameletNumber(in.Line(), frameletSet, frameletSetOffset, frameletLineOffset, even); + // this is the output file the current line belongs in + Cube *outfile = NULL; + + // uv and vis outputs + if( viseven && uveven ) { + if( framelet < 2 && even ) { + outfile = uveven; + extractMiddleSamples = true; + } + else if( framelet < 2 ) { + outfile = uvodd; + extractMiddleSamples = true; + } + else if( even ) { + outfile = viseven; + } + else { + outfile = visodd; + } + } + // vis output + else if( viseven ) { + if( even ) { + outfile = viseven; + } + else { + outfile = visodd; + } + } + // uv output + else { + extractMiddleSamples = true; + + if( even ) { + outfile = uveven; + } + else { + outfile = uvodd; + } + } + + // We know our output file now, so get a linemanager for writing + LineManager mgr(*outfile); + + // line is framelet * frameletLineOffset + frameletSetOffset + int outLine = 1; + int outBand = framelet + 1; + + // if both vis & uv on, outLine is a calculation based on the current line + // being uv or vis and the general calculation (above) does not work + if( viseven && uveven ) { + // uv file + if( framelet < 2 ) { + outLine = frameletSet * 4 + 1 + padding[framelet]; + } + // vis file + else { + outLine = frameletSet * 14 + 1 + padding[framelet]; + outBand -= 2; // uv is not in vis file + } + } + // only vis on + else if( viseven ) { + outLine = frameletSet * 14 + 1 + padding[framelet]; + } + // only uv on + else { + outLine = frameletSet * 4 + 1 + padding[framelet]; + } + + if( flip ) { + outLine = outfile->Lines() - (outLine - 1); + } + + outLine += frameletLineOffset; + + mgr.SetLine(outLine, outBand); + + if( !extractMiddleSamples ) { + for( int i = 0; i < in.size(); i++ ) { + if( i >= mgr.size() ) { + string msg = "The input file has an unexpected number of samples"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + mgr[i] = lookupTable.Map(in[i]); + } + } + else { + // read middle of input... + int startSamp = (in.size() / 2) - mgr.size() / 2; + int endSamp = (in.size() / 2) + mgr.size() / 2; + + if( mgr.size() > in.size() ) { + string msg = "Output number of samples calculated is invalid"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + for( int inputSamp = startSamp; inputSamp < endSamp; inputSamp++ ) { + mgr[inputSamp - startSamp] = lookupTable.Map(in[inputSamp]); + } + } + + outfile->Write(mgr); +} + +/** + * This calculates the output labels for each file, which are only valid if the + * output cubes have been created (uses ns/nl from each file if + * available). Otherwise the label calculated for that particular file is + * incomplete and invalid. + * + * One input file goes to 2 or 4 output file, so let's calculate everything we + * can here. + * + * @param pdsLab Input File Label + * @param isis3VisEven Even vis file output label + * @param isis3VisOdd Odd vis file output label + * @param isis3UvEven Even UV file output label + * @param isis3UvOdd Odd UV file output label + */ +void TranslateLabels ( Pvl &pdsLab, Pvl &isis3VisEven, Pvl &isis3VisOdd, + Pvl &isis3UvEven, Pvl &isis3UvOdd ) { + // Let's start by running through the generic translations. + + // Get the directory where the translation tables are. + PvlGroup dataDir(Preference::Preferences().FindGroup("DataDirectory")); + iString transDir = (string) dataDir["Lro"] + "/translations/"; + + // Translate the in + Filename transFile(transDir + "lrowacInstrument.trn"); + PvlTranslationManager instrumentXlater(pdsLab, transFile.Expanded()); + instrumentXlater.Auto(isis3VisEven); + instrumentXlater.Auto(isis3VisOdd); + instrumentXlater.Auto(isis3UvEven); + instrumentXlater.Auto(isis3UvOdd); + + // Translate the Archive group + transFile = transDir + "lrowacArchive.trn"; + PvlTranslationManager archiveXlater(pdsLab, transFile.Expanded()); + + archiveXlater.Auto(isis3VisEven); + archiveXlater.Auto(isis3VisOdd); + archiveXlater.Auto(isis3UvEven); + archiveXlater.Auto(isis3UvOdd); + + // Get a couple of user parameters into the instrument groups + UserInterface &ui = Application::GetUserInterface(); + + vector genericInstrument; + genericInstrument.push_back(PvlKeyword("DataFlipped", "No"));//(ui.GetBoolean("FLIP")? "Yes" : "No"))); + + // color offset doesn't apply to BW mode (single band cubes) + if( colorOffset && viseven && viseven->Bands() == 1 ) { + genericInstrument.push_back(PvlKeyword("ColorOffset", 0)); + } + else { + genericInstrument.push_back(PvlKeyword("ColorOffset", colorOffset)); + } + + genericInstrument.push_back(PvlKeyword("Decompanded", (ui.GetBoolean("UNLUT") ? "Yes" : "No"))); + + // We'll need the instrument groups a lot, get a reference right to them + PvlGroup &visEvenInst = isis3VisEven.FindGroup("Instrument", Pvl::Traverse); + PvlGroup &visOddInst = isis3VisOdd.FindGroup("Instrument", Pvl::Traverse); + PvlGroup &uvEvenInst = isis3UvEven.FindGroup("Instrument", Pvl::Traverse); + PvlGroup &uvOddInst = isis3UvOdd.FindGroup("Instrument", Pvl::Traverse); + + // Add user parameters to the instrument group + for( unsigned int key = 0; key < genericInstrument.size(); key++ ) { + visEvenInst.AddKeyword(genericInstrument[key]); + visOddInst.AddKeyword(genericInstrument[key]); + uvEvenInst.AddKeyword(genericInstrument[key]); + uvOddInst.AddKeyword(genericInstrument[key]); + } + + // add labels unique to particular files + if( viseven ) { + visEvenInst.AddKeyword(PvlKeyword("Framelets", "Even")); + visEvenInst.AddKeyword(PvlKeyword("NumFramelets", viseven->Lines() / 14)); + visEvenInst.AddKeyword(PvlKeyword("InstrumentId", "WAC-VIS"), Pvl::Replace); + visEvenInst.AddKeyword(PvlKeyword("InstrumentModeId", (std::string) pdsLab["INSTRUMENT_MODE_ID"])); + } + + if( visodd ) { + visOddInst.AddKeyword(PvlKeyword("Framelets", "Odd")); + visOddInst.AddKeyword(PvlKeyword("NumFramelets", visodd->Lines() / 14)); + visOddInst.AddKeyword(PvlKeyword("InstrumentId", "WAC-VIS"), Pvl::Replace); + visOddInst.AddKeyword(PvlKeyword("InstrumentModeId", (std::string) pdsLab["INSTRUMENT_MODE_ID"])); + } + + // **TEMPORARY. This should be done by a translation table. + // Translate the BandBin group + PvlGroup visBandBin("BandBin"); + PvlKeyword visWavelength("Center"); + PvlKeyword visFilterNum("FilterNumber"); + PvlKeyword visBandwidth("Width"); + + if( viseven && viseven->Bands() == 1 ) { + visWavelength = pdsLab["CENTER_FILTER_WAVELENGTH"][0]; + visFilterNum = pdsLab["FILTER_NUMBER"][0]; + + if( pdsLab.HasKeyword("BANDWIDTH") ) { + visBandwidth = pdsLab["BANDWIDTH"][0]; + } + } + else { + for( int i = 0; i < pdsLab["FILTER_NUMBER"].Size(); i++ ) { + if( (int) pdsLab["FILTER_NUMBER"][i] > 2 ) { + visWavelength += pdsLab["CENTER_FILTER_WAVELENGTH"][i]; + visFilterNum += pdsLab["FILTER_NUMBER"][i]; + + if( pdsLab.HasKeyword("BANDWIDTH") ) { + visBandwidth += pdsLab["BANDWIDTH"][i]; + } + } + } + } + + visBandBin += visFilterNum; + visBandBin += visWavelength; + + if( visBandwidth.Size() != 0 ) { + visBandBin += visBandwidth; + } + + isis3VisEven += visBandBin; + isis3VisOdd += visBandBin; + + PvlGroup visKerns("Kernels"); + visKerns += PvlKeyword("NaifIkCode", "-85621"); + isis3VisEven += visKerns; + isis3VisOdd += visKerns; + + if( uveven ) { + uvEvenInst.AddKeyword(PvlKeyword("Framelets", "Even")); + uvEvenInst.AddKeyword(PvlKeyword("NumFramelets", uveven->Lines() / 4)); + uvEvenInst.AddKeyword(PvlKeyword("InstrumentId", "WAC-UV"), Pvl::Replace); + uvEvenInst.AddKeyword(PvlKeyword("InstrumentModeId", (std::string) pdsLab["INSTRUMENT_MODE_ID"])); + } + + if( uvodd ) { + uvOddInst.AddKeyword(PvlKeyword("Framelets", "Odd")); + uvOddInst.AddKeyword(PvlKeyword("NumFramelets", uvodd->Lines() / 4)); + uvOddInst.AddKeyword(PvlKeyword("InstrumentId", "WAC-UV"), Pvl::Replace); + uvOddInst.AddKeyword(PvlKeyword("InstrumentModeId", (std::string) pdsLab["INSTRUMENT_MODE_ID"])); + } + + // Translate the BandBin group + PvlGroup uvBandBin("BandBin"); + PvlKeyword uvWavelength("Center"); + PvlKeyword uvFilterNum("FilterNumber"); + PvlKeyword uvBandwidth("Width"); + + for( int i = 0; i < pdsLab["FILTER_NUMBER"].Size(); i++ ) { + if( (int) pdsLab["FILTER_NUMBER"][i] <= 2 ) { + uvWavelength += pdsLab["CENTER_FILTER_WAVELENGTH"][i]; + uvFilterNum += pdsLab["FILTER_NUMBER"][i]; + + if( pdsLab.HasKeyword("BANDWIDTH") ) { + uvBandwidth += pdsLab["BANDWIDTH"][i]; + } + } + } + + uvBandBin += uvFilterNum; + uvBandBin += uvWavelength; + + if( uvBandwidth.Size() != 0 ) { + uvBandBin += uvBandwidth; + } + + isis3UvEven += uvBandBin; + isis3UvOdd += uvBandBin; + + PvlGroup uvKerns("Kernels"); + uvKerns += PvlKeyword("NaifIkCode", "-85626"); + + isis3UvEven += uvKerns; + isis3UvOdd += uvKerns; +} + +/** + * This initializes all of the files will NULL DN's. + * + */ +void writeNullsToFile () { + // have output vis files? initialize files with nulls + if( viseven && visodd ) { + LineManager evenLineMgr(*viseven); + LineManager oddLineMgr(*visodd); + evenLineMgr.SetLine(1, 1); + oddLineMgr.SetLine(1, 1); + + for( int i = 0; i < evenLineMgr.size(); i++ ) { + evenLineMgr[i] = Isis::Null; + oddLineMgr[i] = Isis::Null; + } + + while( !evenLineMgr.end() ) { + viseven->Write(evenLineMgr); + visodd->Write(oddLineMgr); + evenLineMgr++; + oddLineMgr++; + } + } + + // have output uv files? initialize files with nulls + if( uveven && uvodd ) { + LineManager evenLineMgr(*uveven); + LineManager oddLineMgr(*uvodd); + evenLineMgr.SetLine(1, 1); + oddLineMgr.SetLine(1, 1); + + for( int i = 0; i < evenLineMgr.size(); i++ ) { + evenLineMgr[i] = Isis::Null; + oddLineMgr[i] = Isis::Null; + } + + while( !evenLineMgr.end() ) { + uveven->Write(evenLineMgr); + uvodd->Write(oddLineMgr); + evenLineMgr++; + oddLineMgr++; + } + } +} + +/** + * This method ensures the integrety of the input labels and that the file is + * exactly as expected. + * + * @param pdsLab PDS Cube Labels + */ +void ValidateInputLabels ( Pvl &pdsLab ) { + try { + // Check known values first to verify they match + PvlKeyword &lut = pdsLab["LRO:LOOKUP_CONVERSION_TABLE"]; + + if( lut.Size() != 256 ) { + iString msg = "Keyword [LRO:LOOKUP_CONVERSION_TABLE] has the wrong number of values"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + PvlKeyword &missionName = pdsLab["MISSION_NAME"]; + + if( missionName.Size() != 1 || missionName[0] != "LUNAR RECONNAISSANCE ORBITER" ) { + iString msg = "Keyword [MISSION_NAME] does not have a value of [LUNAR RECONNAISSANCER ORBITER]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + PvlKeyword &instrumentId = pdsLab["INSTRUMENT_ID"]; + + if( instrumentId.Size() != 1 || instrumentId[0] != "LROC" ) { + iString msg = "Keyword [INSTRUMENT_ID] does not have a value of [LROC]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + // Make sure CENTER_FILTER_WAVELENGTH/FILTER_NUMBER makes sense + if( pdsLab["FILTER_NUMBER"].Size() != pdsLab["CENTER_FILTER_WAVELENGTH"].Size() ) { + iString msg = "Keywords [FILTER_NUMBER,CENTER_FILTER_WAVELENGTH] must have the same number of values"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + if( pdsLab["INSTRUMENT_MODE_ID"][0] == "BW" && pdsLab["FILTER_NUMBER"].Size() != 1 ) { + iString msg = "Keyword [FILTER_NUMBER] must have size 1 if [INSTRUMENT_MODE_ID] is [BW]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + else if( pdsLab["INSTRUMENT_MODE_ID"][0] == "COLOR" && (pdsLab["FILTER_NUMBER"].Size() < 5 + || pdsLab["FILTER_NUMBER"].Size() > 7 || pdsLab["FILTER_NUMBER"].Size() == 6) ) { + iString msg = "Keyword [FILTER_NUMBER] must have size 5 or 7 if [INSTRUMENT_MODE_ID] is [COLOR]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + else if( pdsLab["INSTRUMENT_MODE_ID"][0] == "UV" && pdsLab["FILTER_NUMBER"].Size() != 2 ) { + iString msg = "Keyword [FILTER_NUMBER] must have size 2 if [INSTRUMENT_MODE_ID] is [UV]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + else if( pdsLab["INSTRUMENT_MODE_ID"][0] == "VIS" && pdsLab["FILTER_NUMBER"].Size() != 5 ) { + iString msg = "Keyword [FILTER_NUMBER] must have size 5 if [INSTRUMENT_MODE_ID] is [VIS]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + else if( pdsLab["INSTRUMENT_MODE_ID"][0] != "BW" && pdsLab["INSTRUMENT_MODE_ID"][0] != "COLOR" && + pdsLab["INSTRUMENT_MODE_ID"][0] != "UV" && pdsLab["INSTRUMENT_MODE_ID"][0] != "VIS" ) { + iString msg = "The value of keyword [INSTRUMENT_MODE_ID] is not recognized"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + // number/bandwidth matches for filters + vector< pair > filters; + filters.push_back( pair(1, "321") ); + filters.push_back( pair(2, "360") ); + filters.push_back( pair(3, "415") ); + filters.push_back( pair(4, "566") ); + filters.push_back( pair(5, "604") ); + filters.push_back( pair(6, "643") ); + filters.push_back( pair(7, "689") ); + + for( int i = 0; i < pdsLab["FILTER_NUMBER"].Size(); i++ ) { + bool found = false; + bool match = false; + for( int j = 0; !found && j < (int) filters.size(); j++ ) { + if( (int) pdsLab["FILTER_NUMBER"][i] == filters[j].first ) { + found = true; + + match = (pdsLab["CENTER_FILTER_WAVELENGTH"][i] == filters[j].second); + } + } + + if( found && !match ) { + iString msg = "The [FILTER_NUMBER] and [CENTER_FILTER_WAVELENGTH] keywords do not correspond properly"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + if( !found ) { + iString msg = "The value of the keyword [FILTER_NUMBER] is invalid"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + } + + // Now make sure keywords that shouldn't exist dont + iString invalidKeywords[] = { + "SPACECRAFT_CLOCK_CNT_PARTITION" + }; + + for( unsigned int i = 0; i < sizeof(iString) / sizeof(invalidKeywords); i++ ) { + if( pdsLab.HasKeyword(invalidKeywords[i]) ) { + iString msg = "Keyword ["; + msg += invalidKeywords[i]; + msg += "] must not exist"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + } + + // Now check for keywords that must be integers + PvlKeyword &orbitNumber = pdsLab["ORBIT_NUMBER"]; + QRegExp integerRegex("[0-9]+"); + + if( orbitNumber.Size() != 1 || !integerRegex.exactMatch(orbitNumber[0]) ) { + iString msg = "The value of keyword [ORBIT_NUMBER] is not valid"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + // Check for keywords that must be doubles or integers + QRegExp numberRegex("[-+]{0,1}([0-9]*\\.[0-9]+)|([0-9]+\\.[0-9]*)|([0-9]+)"); + iString numericKeywords[] = { + "LRO:BEGIN_TEMPERATURE_SCS", + "LRO:MIDDLE_TEMPERATURE_SCS", + "LRO:END_TEMPERATURE_SCS", + "LRO:BEGIN_TEMPERATURE_FPA", + "LRO:MIDDLE_TEMPERATURE_FPA", + "LRO:END_TEMPERATURE_FPA", + "INTERFRAME_DELAY", + "EXPOSURE_DURATION" + }; + + for( unsigned int i = 0; i < sizeof(numericKeywords) / sizeof(iString); i++ ) { + if( pdsLab[numericKeywords[i]].Size() != 1 || !numberRegex.exactMatch(pdsLab[numericKeywords[i]][0]) ) { + iString msg = "The value of keyword ["; + msg += numericKeywords[i]; + msg += "] is not valid"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + } + + // Now check for keywords that must be dateTtime + QRegExp timeRegex("[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]*"); + iString timeKeywords[] = { + "START_TIME", + "STOP_TIME" + }; + + for( unsigned int i = 0; i < sizeof(timeKeywords) / sizeof(iString); i++ ) { + if( pdsLab[timeKeywords[i]].Size() != 1 || !timeRegex.exactMatch(pdsLab[timeKeywords[i]][0]) ) { + iString msg = "The value of keyword ["; + msg += timeKeywords[i]; + msg += "] is not valid"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + } + + // Now check keywords that must be clock counts + QRegExp clockRegex("[0-9]+/[0-9]+:[0-9]+\\.{0,1}[0-9]*"); + iString clockKeywords[] = { + "SPACECRAFT_CLOCK_START_COUNT", + "SPACECRAFT_CLOCK_STOP_COUNT" + }; + + for( unsigned int i = 0; i < sizeof(clockKeywords) / sizeof(iString); i++ ) { + if( pdsLab[clockKeywords[i]].Size() != 1 || !clockRegex.exactMatch(pdsLab[clockKeywords[i]][0]) ) { + iString msg = "The value of keyword ["; + msg += clockKeywords[i]; + msg += "] is not valid"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + } + } + catch( iException &e ) { + iString msg = "The input product is out of date and has invalid labels. Please get an up to date version from the ASU LROC Team"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } +} diff --git a/isis/src/lro/apps/lrowac2isis/lrowac2isis.xml b/isis/src/lro/apps/lrowac2isis/lrowac2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..f12dc877f03e466f1b51ea113514e51bd068ceee --- /dev/null +++ b/isis/src/lro/apps/lrowac2isis/lrowac2isis.xml @@ -0,0 +1,118 @@ + + + + + + Import LRO WAC EDR images into Isis cube format + + + + + + + + Original version + + + Updated to work with multiple summing modes in one + image and added LUT capabilities. + + + Keywords are now being placed properly, moved all keyword + calculations back to the TranslateLabels method. + + + Updated wavelengths + + + Color offsets for BW mode images are now always zero. + Color offset does not make sense for single band cubes. + + + Removed flip, changed default of coloroffset to off. + + + Now propogating new keyword from labels v1.1 bandwidth + + + + + Lunar Reconnaissance Orbiter + + + + + + filename + input + + Input PDS formatted LRO WAC EDR image file. + + + Use this parameter to select the LRO WAC EDR image filename. + + + *.img *.IMG + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the base output filename. + + + *.cub + + + + + + + boolean + Add padding to align bands + + The result of how MARCI takes pictures leaves a filter height offset in adjacent filters. This will correct that offset + by adding padding to the top of the image file, aligning color images correctly. + + false + COLOROFFSETSIZE + + + + integer + Amount of filter heights to pad with for COLOROFFSET + + The filters are offset by a certain number of filters, which is a multiple of their height. It appears + the filters are all offset by twice their height, or two filter heights. One filter height can be explained by + the method of taking pictures: the first filter on the first framelet is one higher than the second filter on + the first framelet. + + 2 + 0 + + + + + + boolean + Use the lookup table in the labels + + If this is set to true, and the input cube is lutted, a lookup table + will be used to convert the raw DN values to their original + values. This must be set to true for calibration. + + true + + + + diff --git a/isis/src/lro/apps/lrowac2isis/tsts/Makefile b/isis/src/lro/apps/lrowac2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/lro/apps/lrowac2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/lro/apps/lrowac2isis/tsts/default/Makefile b/isis/src/lro/apps/lrowac2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..deec022dc7f8b8477448bc8084c0453e1dfaaf57 --- /dev/null +++ b/isis/src/lro/apps/lrowac2isis/tsts/default/Makefile @@ -0,0 +1,17 @@ +APPNAME = lrowac2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/wac0000a1c4.img \ + TO=$(OUTPUT)/out.cub > /dev/null; + catlab FROM=$(OUTPUT)/out.vis.even.cub \ + > $(OUTPUT)/out.vis.even.pvl > /dev/null; + crop FROM=$(OUTPUT)/out.vis.even.cub \ + to=$(OUTPUT)/small.even.cub > /dev/null; + $(RM) $(OUTPUT)/out.vis.even.cub > /dev/null; + crop FROM=$(OUTPUT)/out.vis.odd.cub \ + to=$(OUTPUT)/small.odd.cub > /dev/null; + catlab FROM=$(OUTPUT)/out.vis.odd.cub \ + > $(OUTPUT)/out.vis.odd.pvl > /dev/null; + $(RM) $(OUTPUT)/out.vis.odd.cub > /dev/null; diff --git a/isis/src/lro/apps/lrowac2pds/Makefile b/isis/src/lro/apps/lrowac2pds/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/lro/apps/lrowac2pds/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/lro/apps/lrowac2pds/lrowac2pds.cpp b/isis/src/lro/apps/lrowac2pds/lrowac2pds.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1a6a2ba817d51931eadf2b36ed0fa05f804f6c9 --- /dev/null +++ b/isis/src/lro/apps/lrowac2pds/lrowac2pds.cpp @@ -0,0 +1,461 @@ +#include "Isis.h" +#include +#include +#include +#include "FileList.h" +#include "Brick.h" +#include "OriginalLabel.h" +#include "Brick.h" +#include "History.h" +#include "Stretch.h" +#include "iTime.h" +#include "ProcessExport.h" +#include "PvlTranslationManager.h" +#include "PvlFormatPds.h" +#include "md5.h" +#include "md5wrapper.h" +#include "OriginalLabel.h" +#include + +#define COLOR_SAMPLES 704 +#define VIS_SAMPLES 704 +#define UV_SAMPLES 128 +#define BW_SAMPLES 1024 +#define VIS_LINES 14 +#define UV_LINES 4 + +using namespace std; +using namespace Isis; + +vector frameletLines; + +void ResetGlobals (); +void mergeFramelets (); +string MD5Checksum ( string filename ); +void OutputLabel ( std::ofstream &fout, Cube* cube, Pvl &pdsLab ); +void CopyData ( std::ifstream &fin, std::ofstream &fout ); + +std::vector padding; +int colorOffset = 0; +int inputCubeLines = 0; + +// Output UV Files +Cube *uveven = NULL; +Cube *uvodd = NULL; + +// Output VIS Files +Cube *viseven = NULL; +Cube *visodd = NULL; + +Cube* out = NULL; + +iString instrumentModeId = ""; +iString productId = ""; +iString g_productVersionId = "N/A"; + +string g_md5Checksum; + +int numFramelets = 0; +int numSamples = 0; +int numLines = 0; +int numUVFilters = 0; +int numVisFilters = 0; + +bool g_isIoF; + +void IsisMain () { + Pvl pdsLab; + + FileList list; + UserInterface &ui = Application::GetUserInterface(); + list.Read(ui.GetFilename("FROMLIST")); + + if (list.size() < 1) { + string msg = "The list file [" + ui.GetFilename("FROMLIST") + "does not contain any data"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + g_productVersionId = ui.GetString("VERSIONIDSTRING"); + + for (unsigned int i = 0; i < list.size(); i++) { + + Pvl tempPvl; + tempPvl.Read(list[i]); + + OriginalLabel origLab(list[i]); + pdsLab = origLab.ReturnLabels(); + + iString prodId = pdsLab["PRODUCT_ID"][0]; + if (productId == "") + productId = prodId; + + if (productId != prodId) { + string msg = "This program is intended for use on a single LROC WAC images only."; + msg += "The ProductIds do not match."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + Isis::PvlGroup &inst = tempPvl.FindGroup("Instrument", Pvl::Traverse); + iString instId = (string) inst["InstrumentId"]; + iString framelets = (string) inst["Framelets"]; + iString numFrames = (int) inst["NumFramelets"]; + + if (instId != "WAC-VIS" && instId != "WAC-UV") { + string msg = "This program is intended for use on LROC WAC images only. ["; + msg += list[i] + "] does not appear to be a WAC image."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + iString instModeId = (string) inst["InstrumentModeId"]; + if (instrumentModeId == "") + instrumentModeId = instModeId; + if (numFramelets == 0) + numFramelets = numFrames; + g_isIoF = tempPvl.FindGroup("Radiometry", Pvl::Traverse).FindKeyword("RadiometricType")[0].Equal("IOF"); + + if (instId == "WAC-VIS" && framelets == "Even") { + viseven = new Cube(); + viseven->Open(list[i]); + } + else if (instId == "WAC-VIS" && framelets == "Odd") { + visodd = new Cube(); + visodd->Open(list[i]); + } + if (instId == "WAC-UV" && framelets == "Even") { + uveven = new Cube(); + uveven->Open(list[i]); + } + else if (instId == "WAC-UV" && framelets == "Odd") { + uvodd = new Cube(); + uvodd->Open(list[i]); + } + } + + // Determine our band information based on + // INSTRUMENT_MODE_ID - FILTER_NUMBER is + // only going to be used for BW images + if (instrumentModeId == "COLOR") { + numUVFilters = 2; + numVisFilters = 5; + + numSamples = COLOR_SAMPLES; + } + else if (instrumentModeId == "VIS") { + numUVFilters = 0; + numVisFilters = 5; + + numSamples = VIS_SAMPLES; + } + else if (instrumentModeId == "UV") { + numUVFilters = 2; + numVisFilters = 0; + + numSamples = UV_SAMPLES; + } + else if (instrumentModeId == "BW") { + numUVFilters = 0; + numVisFilters = 1; + + numSamples = BW_SAMPLES; + } + + numLines = numFramelets * (UV_LINES * numUVFilters + VIS_LINES * numVisFilters); + + out = new Cube(); + out->SetDimensions(numSamples, numLines, 1); + out->SetPixelType(Isis::Real); + + Filename mergedCube = ui.GetFilename("TO"); + mergedCube.Temporary(ui.GetFilename("TO"), "cub"); + + out->Create(mergedCube.Expanded().c_str()); + + mergeFramelets(); + + /* + + Filename outFile(ui.GetFilename("TO", "img")); + string outFilename(outFile.Expanded()); + ofstream oCube(outFilename.c_str()); + p.OutputLabel(oCube); + p.StartProcess(oCube); + oCube.close(); + p.EndProcess(); + + */ + + out->Close(); + delete out; + out = NULL; + + if (uveven) { + uveven->Close(); + delete uveven; + uveven = NULL; + } + + if (uvodd) { + uvodd->Close(); + delete uvodd; + uvodd = NULL; + } + + if (viseven) { + viseven->Close(); + delete viseven; + viseven = NULL; + } + + if (visodd) { + visodd->Close(); + delete visodd; + visodd = NULL; + } + + // Export data + + ProcessExport pe; + + // Setup the input cube + Cube *inCube = pe.SetInputCube(mergedCube.Expanded(), CubeAttributeInput()); + + pe.SetOutputType(Isis::Real); + pe.SetOutputEndian(Isis::Lsb); + + pe.SetOutputRange(Isis::VALID_MIN4, Isis::VALID_MAX4); + + pe.SetOutputNull(Isis::NULL4); + pe.SetOutputLrs(Isis::LOW_REPR_SAT4); + pe.SetOutputLis(Isis::LOW_INSTR_SAT4); + pe.SetOutputHis(Isis::HIGH_INSTR_SAT4); + pe.SetOutputHrs(Isis::HIGH_REPR_SAT4); + + Filename tempFile(ui.GetFilename("TO")); + tempFile.Temporary(ui.GetFilename("TO"), "temp"); + string tempFilename(tempFile.Expanded()); + ofstream temporaryFile(tempFilename.c_str()); + + pe.StartProcess(temporaryFile); + temporaryFile.close(); + + // Calculate MD5 Checksum + g_md5Checksum = MD5Checksum(tempFilename); + + Filename outFile(ui.GetFilename("TO")); + string outFilename(outFile.Expanded()); + ifstream inFile(tempFilename.c_str()); + ofstream pdsFile(outFilename.c_str()); + + // Output the label + OutputLabel(pdsFile, inCube, pdsLab); + + // Then copy the image data + CopyData(inFile, pdsFile); + + pdsFile.close(); + + pe.EndProcess(); + + remove((mergedCube.Expanded()).c_str()); + remove(tempFilename.c_str()); + return; +} + +void ResetGlobals () { + colorOffset = 0; + frameletLines.clear(); + + uveven = NULL; + uvodd = NULL; + viseven = NULL; + visodd = NULL; + + out = NULL; + + instrumentModeId = ""; + productId = ""; + g_md5Checksum = ""; + + numFramelets = 0; + numSamples = 0; + numLines = 0; + numUVFilters = 0; + numVisFilters = 0; + + g_isIoF = false; +} + +//! Merges each of the individual WAC framelets into the right place +void mergeFramelets () { + Brick *uvevenManager = NULL, *uvoddManager = NULL, *visevenManager = NULL, *visoddManager = NULL; + + if (numUVFilters > 0) { + uvevenManager = new Brick(*uveven, UV_SAMPLES, UV_LINES, numUVFilters); + uvoddManager = new Brick(*uvodd, UV_SAMPLES, UV_LINES, numUVFilters); + + uvevenManager->begin(); + uvoddManager->begin(); + } + if (numVisFilters > 0) { + visevenManager = new Brick(*viseven, numSamples, VIS_LINES, numVisFilters); + visoddManager = new Brick(*visodd, numSamples, VIS_LINES, numVisFilters); + + visevenManager->begin(); + visoddManager->begin(); + } + + Brick outManager(*out, numSamples, UV_LINES * numUVFilters + VIS_LINES * numVisFilters, 1); + outManager.begin(); + + // For each frame + for (int f = 0; f < numFramelets; f++) { + // write out the UV first + if (numUVFilters > 0) { + uveven->Read(*uvevenManager); + uvodd->Read(*uvoddManager); + + int pad = (numSamples - UV_SAMPLES) / 2; + for (int line = 0; line < numUVFilters * UV_LINES; line++) { + int offset = numSamples * line; + // left padding + for (int i = 0; i < pad; i++) + outManager[offset + i] = Isis::Null; + for (int i = 0; i < UV_SAMPLES; i++) { + int index = line * UV_SAMPLES + i; + if (f % 2 == 0) + outManager[i + offset + pad] = uvoddManager->at(index); + else + outManager[i + offset + pad] = uvevenManager->at(index); + } + // right padding + for (int i = 0; i < pad; i++) + outManager[i + offset + pad + UV_SAMPLES] = Isis::Null; + } + uvevenManager->next(); + uvoddManager->next(); + } + // then the vis + if (numVisFilters > 0) { + viseven->Read(*visevenManager); + visodd->Read(*visoddManager); + + int offset = numUVFilters * UV_LINES * numSamples; + for (int i = 0; i < numVisFilters * VIS_LINES * numSamples; i++) { + if (f % 2 == 0) + outManager[i + offset] = visoddManager->at(i); + else + outManager[i + offset] = visevenManager->at(i); + } + + visevenManager->next(); + visoddManager->next(); + } + + out->Write(outManager); + outManager.next(); + } +} + +string MD5Checksum ( string filename ) { + md5wrapper md5; + std::string checkSum = md5.getHashFromFile(filename.c_str()); + return checkSum; +} + +void OutputLabel ( std::ofstream &fout, Cube* cube, Pvl &labelPvl ) { + //Pvl to store the labels + Pvl outLabel; + PvlFormatPds *p_formatter = new PvlFormatPds("$lro/translations/pdsExportRootGen.typ"); + labelPvl.SetFormat(p_formatter); + labelPvl.SetTerminator("END"); + //Set up the directory where the translations are + PvlGroup dataDir(Preference::Preferences().FindGroup("DataDirectory")); + iString transDir = (string) dataDir["Lro"] + "/translations/"; + + stringstream stream; + iString pdsLabel = ""; + + //Translate the Original Pds Label + Filename transFile(transDir + "lrowacPdsLabelExport.trn"); + PvlTranslationManager labelXlator(labelPvl, transFile.Expanded()); + labelXlator.Auto(outLabel); + + // Copy any Translation changes over + for (int i = 0; i < outLabel.Keywords(); i++) { + bool hasUnit = false; + string unit = ""; + if (labelPvl[outLabel[i].Name()].Unit() != "") { + hasUnit = true; + unit = labelPvl[outLabel[i].Name()].Unit(); + } + bool hasComment = false; + string comment = ""; + if (labelPvl[outLabel[i].Name()].Comments() > 0) { + hasComment = true; + comment = labelPvl[outLabel[i].Name()].Comment(0); + } + labelPvl[outLabel[i].Name()] = outLabel[i]; + + if (hasUnit) + labelPvl[outLabel[i].Name()].SetUnits(unit); + if (hasComment) + labelPvl[outLabel[i].Name()].AddComment(comment); + } + + //Update the product ID + labelPvl["PRODUCT_ID"][0].replace(11, 1, "C"); + + // Update the product creation time + labelPvl["PRODUCT_CREATION_TIME"].SetValue(iTime::CurrentGMT()); + + labelPvl["PRODUCT_VERSION_ID"].SetValue(g_productVersionId); + + // Update the "IMAGE" Object + PvlObject &imageObject = labelPvl.FindObject("IMAGE"); + imageObject.Clear(); + imageObject += PvlKeyword("LINES", cube->Lines()); + imageObject += PvlKeyword("LINE_SAMPLES", cube->Samples()); + imageObject += PvlKeyword("SAMPLE_BITS", 32); + imageObject += PvlKeyword("SAMPLE_TYPE", "PC_REAL"); + imageObject += PvlKeyword("VALID_MINIMUM", "16#FF7FFFFA#"); + imageObject += PvlKeyword("NULL", "16#FF7FFFFB#"); + imageObject += PvlKeyword("LOW_REPR_SATURATION", "16#FF7FFFFC#"); + imageObject += PvlKeyword("LOW_INSTR_SATURATION", "16#FF7FFFFD#"); + imageObject += PvlKeyword("HIGH_INSTR_SATURATION", "16#FF7FFFFE#"); + imageObject += PvlKeyword("HIGH_REPR_SATURATION", "16#FF7FFFFF#"); + if (g_isIoF == true) + imageObject += PvlKeyword("UNIT", "\"I/F\""); + else + imageObject += PvlKeyword("UNIT", "W / (m**2 micrometer sr)"); + imageObject += PvlKeyword("MD5_CHECKSUM", (iString) g_md5Checksum); + + stream << labelPvl; + + int recordBytes = cube->Samples(); + int labelRecords = (int) ((stream.str().length()) / recordBytes) + 1; + + labelPvl["RECORD_BYTES"] = recordBytes; + labelPvl["FILE_RECORDS"] = (int) (cube->Lines() * 4 + labelRecords); + labelPvl["LABEL_RECORDS"] = labelRecords; + labelPvl["^IMAGE"] = (int) (labelRecords + 1); + + stream.str(std::string()); + + stream << labelPvl; + pdsLabel += stream.str(); + + while (pdsLabel.length() < (unsigned int) (labelRecords * recordBytes)) { + pdsLabel += '\n'; + } + + fout << pdsLabel; + return; +} + +void CopyData ( std::ifstream &fin, std::ofstream &fout ) { + char line[704]; + while (!fin.eof()) { + fin.read(line, 704); + fout.write(line, fin.gcount()); + } +} diff --git a/isis/src/lro/apps/lrowac2pds/lrowac2pds.xml b/isis/src/lro/apps/lrowac2pds/lrowac2pds.xml new file mode 100644 index 0000000000000000000000000000000000000000..7880c48c0b9e95cc2e5d36570e1dfdcaceff87a5 --- /dev/null +++ b/isis/src/lro/apps/lrowac2pds/lrowac2pds.xml @@ -0,0 +1,64 @@ + + + + + Import LRO WAC EDR images into Isis cube format + + + + + + + + Original version + + + + + Lunar Reconnaissance Orbiter + + + + + + filename + input + + Input PDS formatted LRO WAC EDR image file. + + + Use this parameter to select the LRO WAC EDR image filename. + + + *.img *.IMG + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the base output filename. + + + *.cub + + + + + + + string + Group to modify + + The user input ID string + + "N/A" + + + + + diff --git a/isis/src/lro/apps/lrowac2pds/md5.cpp b/isis/src/lro/apps/lrowac2pds/md5.cpp new file mode 100644 index 0000000000000000000000000000000000000000..56ab483ab2ce6515180bec4b1e0b2214c416afb9 --- /dev/null +++ b/isis/src/lro/apps/lrowac2pds/md5.cpp @@ -0,0 +1,327 @@ +/* + * This is the C++ implementation of the MD5 Message-Digest + * Algorithm desrcipted in RFC 1321. + * I translated the C code from this RFC to C++. + * There is no warranty. + * + * Feb. 12. 2005 + * Benjamin Grüdelbach + */ + +/* + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD5 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD5 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +//md5 class include +#include "md5.h" + +// Constants for MD5Transform routine. +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) +//#define ROTATE_LEFT(x, n) (((x) << (n)) | (( (UINT32) x) >> (32-(n)))) + +/* +FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. +*/ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (unsigned long int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (unsigned long int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (unsigned long int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (unsigned long int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. */ +void MD5::MD5Init (MD5_CTX *context) +{ + context->count[0] = context->count[1] = 0; + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* + MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. +*/ +void MD5::MD5Update (MD5_CTX *context, unsigned char *input, unsigned int inputLen) +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ( (context->count[0] += ((unsigned long int)inputLen << 3)) + < ((unsigned long int)inputLen << 3)) + context->count[1]++; + + context->count[1] += ((unsigned long int)inputLen >> 29); + partLen = 64 - index; + + /* + * Transform as many times as possible. + */ + if (inputLen >= partLen) + { + MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy ((POINTER)&context->buffer[index], + (POINTER)&input[i], + inputLen-i); +} + +/* + * MD5 finalization. Ends an MD5 message-digest operation, writing the + * the message digest and zeroizing the context. + */ +void MD5::MD5Final (unsigned char digest[16], MD5_CTX *context) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* + * Pad out to 56 mod 64. + */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* + * Zeroize sensitive information. + */ + MD5_memset ((POINTER)context, 0, sizeof (*context)); +} + +/* + * MD5 basic transformation. Transforms state based on block. + */ +void MD5::MD5Transform (unsigned long int state[4], unsigned char block[64]) +{ + unsigned long int a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* + * Zeroize sensitive information. + */ + MD5_memset ((POINTER)x, 0, sizeof (x)); +} + +/* + * Encodes input (unsigned long int) into output (unsigned char). Assumes len is + * a multiple of 4. + */ +void MD5::Encode (unsigned char *output, unsigned long int *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* + * Decodes input (unsigned char) into output (unsigned long int). Assumes len is + * a multiple of 4. + */ +void MD5::Decode (unsigned long int *output, unsigned char *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((unsigned long int)input[j]) | + (((unsigned long int)input[j+1]) << 8) | + (((unsigned long int)input[j+2]) << 16) | + (((unsigned long int)input[j+3]) << 24); +} + +/* + * Note: Replace "for loop" with standard memcpy if possible. + */ +void MD5::MD5_memcpy (POINTER output, POINTER input, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; +} + +/* + * Note: Replace "for loop" with standard memset if possible. + */ +void MD5::MD5_memset (POINTER output,int value,unsigned int len) +{ + unsigned int i; + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; +} + +/* + * EOF + */ diff --git a/isis/src/lro/apps/lrowac2pds/md5.h b/isis/src/lro/apps/lrowac2pds/md5.h new file mode 100644 index 0000000000000000000000000000000000000000..0d16c05a73b9202a70ec21b63e20b0df67a58ff7 --- /dev/null +++ b/isis/src/lro/apps/lrowac2pds/md5.h @@ -0,0 +1,86 @@ +/* + * This is the C++ implementation of the MD5 Message-Digest + * Algorithm desrcipted in RFC 1321. + * I translated the C code from this RFC to C++. + * There is no warranty. + * + * Feb. 12. 2005 + * Benjamin Grüdelbach + */ + +/* + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD5 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD5 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +//---------------------------------------------------------------------- +//include protection +#ifndef MD5_H +#define MD5_H + +//---------------------------------------------------------------------- +//STL includes +#include + +//---------------------------------------------------------------------- +//typedefs +typedef unsigned char *POINTER; + +/* + * MD5 context. + */ +typedef struct +{ + unsigned long int state[4]; /* state (ABCD) */ + unsigned long int count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +/* + * MD5 class + */ +class MD5 +{ + + private: + + void MD5Transform (unsigned long int state[4], unsigned char block[64]); + void Encode (unsigned char*, unsigned long int*, unsigned int); + void Decode (unsigned long int*, unsigned char*, unsigned int); + void MD5_memcpy (POINTER, POINTER, unsigned int); + void MD5_memset (POINTER, int, unsigned int); + + public: + + void MD5Init (MD5_CTX*); + void MD5Update (MD5_CTX*, unsigned char*, unsigned int); + void MD5Final (unsigned char [16], MD5_CTX*); + + MD5(){}; +}; + +//---------------------------------------------------------------------- +//End of include protection +#endif + +/* + * EOF + */ diff --git a/isis/src/lro/apps/lrowac2pds/md5wrapper.cpp b/isis/src/lro/apps/lrowac2pds/md5wrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..04a378dfe95cb3ee7f4fad09752e961caac197d8 --- /dev/null +++ b/isis/src/lro/apps/lrowac2pds/md5wrapper.cpp @@ -0,0 +1,134 @@ +/* + * This is part of my wrapper-class to create + * a MD5 Hash from a string and a file. + * + * This code is completly free, you + * can copy it, modify it, or do + * what ever you want with it. + * + * Feb. 2005 + * Benjamin Grüdelbach + */ + +//---------------------------------------------------------------------- +//basic includes +#include +#include + +//my includes +#include "md5wrapper.h" +#include "md5.h" + +//---------privates-------------------------- + +/* + * internal hash function, calling + * the basic methods from md5.h + */ +std::string md5wrapper::hashit(std::string text) +{ + MD5_CTX ctx; + + //init md5 + md5->MD5Init(&ctx); + //update with our string + md5->MD5Update(&ctx, + (unsigned char*)text.c_str(), + text.length()); + + //create the hash + unsigned char buff[16] = ""; + md5->MD5Final((unsigned char*)buff,&ctx); + + //converte the hash to a string and return it + return convToString(buff); +} + +/* + * converts the numeric hash to + * a valid std::string. + * (based on Jim Howard's code; + * http://www.codeproject.com/cpp/cmd5.asp) + */ +std::string md5wrapper::convToString(unsigned char *bytes) +{ + char asciihash[33]; + + int p = 0; + for(int i=0; i<16; i++) + { + ::sprintf(&asciihash[p],"%02x",bytes[i]); + p += 2; + } + asciihash[32] = '\0'; + return std::string(asciihash); +} + +//---------publics-------------------------- + +//constructor +md5wrapper::md5wrapper() +{ + md5 = new MD5(); +} + + +//destructor +md5wrapper::~md5wrapper() +{ + delete md5; +} + +/* + * creates a MD5 hash from + * "text" and returns it as + * string + */ +std::string md5wrapper::getHashFromString(std::string text) +{ + return this->hashit(text); +} + + +/* + * creates a MD5 hash from + * a file specified in "filename" and + * returns it as string + * (based on Ronald L. Rivest's code + * from RFC1321 "The MD5 Message-Digest Algorithm") + */ +std::string md5wrapper::getHashFromFile(std::string filename) +{ + FILE *file; + MD5_CTX context; + + int len; + unsigned char buffer[1024], digest[16]; + + //open file + if ((file = fopen (filename.c_str(), "rb")) == NULL) + { + return "-1"; + } + + //init md5 + md5->MD5Init (&context); + + //read the filecontent + while ( (len = fread (buffer, 1, 1024, file)) ) + { + md5->MD5Update (&context, buffer, len); + } + + /* + generate hash, close the file and return the + hash as std::string + */ + md5->MD5Final (digest, &context); + fclose (file); + return convToString(digest); + } + +/* + * EOF + */ diff --git a/isis/src/lro/apps/lrowac2pds/md5wrapper.h b/isis/src/lro/apps/lrowac2pds/md5wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..477969bfe0d43adbdbc6ae8e9672270ba8592bcc --- /dev/null +++ b/isis/src/lro/apps/lrowac2pds/md5wrapper.h @@ -0,0 +1,67 @@ +/* + * This is my wrapper-class to create + * a MD5 Hash from a string and a file. + * + * This code is completly free, you + * can copy it, modify it, or do + * what ever you want with it. + * + * Feb. 2005 + * Benjamin Grüdelbach + */ + +//include protection +#ifndef MD5WRAPPER_H +#define MD5WRAPPER_H + +//basic includes +#include + +//forwards +class MD5; + +class md5wrapper +{ + private: + MD5 *md5; + + /* + * internal hash function, calling + * the basic methods from md5.h + */ + std::string hashit(std::string text); + + /* + * converts the numeric giets to + * a valid std::string + */ + std::string convToString(unsigned char *bytes); + public: + //constructor + md5wrapper(); + + //destructor + ~md5wrapper(); + + /* + * creates a MD5 hash from + * "text" and returns it as + * string + */ + std::string getHashFromString(std::string text); + + /* + * creates a MD5 hash from + * a file specified in "filename" and + * returns it as string + */ + std::string getHashFromFile(std::string filename); +}; + + +//include protection +#endif + +/* + * EOF + */ diff --git a/isis/src/lro/apps/lrowac2pds/tsts/Makefile b/isis/src/lro/apps/lrowac2pds/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/lro/apps/lrowac2pds/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/lro/apps/lrowaccal/Makefile b/isis/src/lro/apps/lrowaccal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/lro/apps/lrowaccal/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/lro/apps/lrowaccal/lrowaccal.cpp b/isis/src/lro/apps/lrowaccal/lrowaccal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1e7b43974b15fe55bd59aa962536ea8a798dbcd --- /dev/null +++ b/isis/src/lro/apps/lrowaccal/lrowaccal.cpp @@ -0,0 +1,330 @@ +#include "Isis.h" +#include "SpecialPixel.h" +#include "CubeAttribute.h" +#include "Cube.h" +#include "Camera.h" +#include "Constants.h" +#include "Statistics.h" +#include "ProcessByBrick.h" +#include "Brick.h" +#include "iTime.h" +#include + +using namespace Isis; +using namespace std; + +#define POLAR_MODE_SAMPLES 1024 +#define NO_POLAR_MODE_SAMPLES 704 +#define BW_BANDS 1 +#define VIS_LINES 14 +#define COLOR_BANDS 5 +#define UV_SAMPLES 128 +#define UV_LINES 4 +#define UV_BANDS 2 +#define KM_PER_AU 149597871 + +void ResetGlobals (); +void Calibrate ( Buffer &in, Buffer &out ); +void CopyCubeIntoArray ( string &fileString, vector &data ); +double min ( double a, double b ); + +vector g_iofResponsivity; +vector g_radianceResponsivity; + +bool g_dark = true, g_flatfield = true, g_radiometric = true, g_iof = true, g_specpix = true; + +double g_exposure; // Exposure duration +double g_solarDistance = 1.01; // average distance in [AU] + +vector g_bands; + +vector darkCube, flatCube, specpixCube; + +void IsisMain () { + UserInterface &ui = Application::GetUserInterface(); + + ProcessByBrick p; + Cube *icube = p.SetInputCube("FROM"); + + // Make sure it is a WAC cube + Isis::PvlGroup &inst = icube->Label()->FindGroup("Instrument", Pvl::Traverse); + iString instId = (string) inst["InstrumentId"]; + instId.UpCase(); + if (instId != "WAC-VIS" && instId != "WAC-UV") { + string msg = "This program is intended for use on LROC WAC images only. ["; + msg += icube->Filename() + "] does not appear to be a WAC image."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + // And check if it has already run through calibration + if (icube->Label()->FindObject("IsisCube").HasGroup("Radiometry")) { + string msg = "This image has already been calibrated"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + if (icube->Label()->FindObject("IsisCube").HasGroup("AlphaCube")) { + string msg = "This application can not be run on any image that has been geometrically transformed (i.e. scaled, rotated, sheared, or reflected) or cropped."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + g_dark = ui.GetBoolean("DARK"); + g_flatfield = ui.GetBoolean("FLATFIELD"); + g_radiometric = ui.GetBoolean("RADIOMETRIC"); + g_iof = (ui.GetString("RADIOMETRICTYPE") == "IOF"); + g_specpix = ui.GetBoolean("SPECIALPIXELS"); + + // Determine the dark/flat files to use + iString offset = (string) inst["BackgroundOffset"]; + iString mode = (string) inst["Mode"]; + iString instModeId = (string) inst["InstrumentModeId"]; + instModeId.UpCase(); + + if (instModeId == "COLOR" && (string) inst["InstrumentId"] == "WAC-UV") + instModeId = "UV"; + else if (instModeId == "VIS") + instModeId = "COLOR"; + + iString darkFile = ui.GetAsString("DARKFILE"); + iString flatFile = ui.GetAsString("FLATFIELDFILE"); + iString radFile = ui.GetAsString("RADIOMETRICFILE"); + iString specpixFile = ui.GetAsString("SPECIALPIXELSFILE"); + + // Figure out which bands are input + for (int i = 1; i <= icube->Bands(); i++) { + g_bands.push_back(icube->PhysicalBand(i)); + } + + Isis::PvlGroup &bandBin = icube->Label()->FindGroup("BandBin", Pvl::Traverse); + iString filter = (string) bandBin["Center"][0]; + + if (g_dark) { + if (darkFile.Equal("Default") || darkFile.length() == 0) { + darkFile = "$lro/calibration/WAC_" + instModeId; + if (instModeId == "BW") + darkFile += "_" + filter + "_Mode" + mode; + darkFile += "_Offset" + offset + "_Dark.????.cub"; + } + CopyCubeIntoArray(darkFile, darkCube); + } + + if (g_flatfield) { + if (flatFile.Equal("Default") || flatFile.length() == 0) { + flatFile = "$lro/calibration/WAC_" + instModeId; + if (instModeId == "BW") + flatFile += "_" + filter + "_Mode" + mode; + flatFile += "_Flatfield.????.cub"; + } + CopyCubeIntoArray(flatFile, flatCube); + } + + PvlKeyword responsivity; + + if (g_radiometric) { + if (radFile.Equal("Default") || radFile.length() == 0) + radFile = "$lro/calibration/WAC_RadiometricResponsivity.????.pvl"; + + Filename radFilename(radFile); + if ((radFilename.Expanded()).find("?") != string::npos) + radFilename.HighestVersion(); + if (!radFilename.Exists()) { + string msg = radFile + " does not exist."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + Pvl radPvl(radFilename.Expanded()); + + if (g_iof) { + responsivity = radPvl["IOF_" + instModeId]; + for (int i = 0; i < responsivity.Size(); i++) + g_iofResponsivity.push_back(responsivity[i]); + + try { + iTime startTime((string) inst["StartTime"]); + double etStart = startTime.Et(); + // Get the distance between the Moon and the Sun at the given time in + // Astronomical Units (AU) + string bspKernel1 = p.MissionData("lro", "/kernels/tspk/moon_pa_de421_1900-2050.bpc", false); + string bspKernel2 = p.MissionData("lro", "/kernels/tspk/de421.bsp", false); + furnsh_c(bspKernel1.c_str()); + furnsh_c(bspKernel2.c_str()); + string pckKernel1 = p.MissionData("base", "/kernels/pck/pck?????.tpc", true); + string pckKernel2 = p.MissionData("lro", "/kernels/pck/moon_080317.tf", false); + string pckKernel3 = p.MissionData("lro", "/kernels/pck/moon_assoc_me.tf", false); + furnsh_c(pckKernel1.c_str()); + furnsh_c(pckKernel2.c_str()); + furnsh_c(pckKernel3.c_str()); + double sunpos[6], lt; + spkezr_c("sun", etStart, "MOON_ME", "LT+S", "MOON", sunpos, <); + g_solarDistance = vnorm_c(sunpos) / KM_PER_AU; + unload_c(bspKernel1.c_str()); + unload_c(bspKernel2.c_str()); + unload_c(pckKernel1.c_str()); + unload_c(pckKernel2.c_str()); + unload_c(pckKernel3.c_str()); + } + catch (iException &e) { + string msg = "Can not find necessary SPICE kernels for converting to IOF"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + else { + responsivity = radPvl["Radiance_" + instModeId]; + for (int i = 0; i < responsivity.Size(); i++) + g_radianceResponsivity.push_back(responsivity[i]); + } + } + + if (g_specpix) { + if (specpixFile.Equal("Default") || specpixFile.length() == 0) { + specpixFile = "$lro/calibration/WAC_" + instModeId; + if (instModeId == "BW") + specpixFile += "_" + filter + "_Mode" + mode; + specpixFile += "_SpecialPixels.????.cub"; + } + CopyCubeIntoArray(specpixFile, specpixCube); + } + + if (instModeId == "BW") { + if (mode == "1" || mode == "0") + p.SetBrickSize(NO_POLAR_MODE_SAMPLES, VIS_LINES, (int)min(BW_BANDS, g_bands.size())); + else + p.SetBrickSize(POLAR_MODE_SAMPLES, VIS_LINES, (int)min(BW_BANDS, g_bands.size())); + } + else if (instModeId == "COLOR") { + p.SetBrickSize(NO_POLAR_MODE_SAMPLES, VIS_LINES, (int)min(COLOR_BANDS, g_bands.size())); + } + else if (instModeId == "UV") { + p.SetBrickSize(UV_SAMPLES, UV_LINES, (int)min(UV_BANDS, g_bands.size())); + } + + g_exposure = inst["ExposureDuration"]; + + Cube *ocube = p.SetOutputCube("TO"); + p.StartProcess(Calibrate); + + // Add an output group with the appropriate information + PvlGroup calgrp("Radiometry"); + if (g_dark) + calgrp += PvlKeyword("DarkFile", darkFile); + if (g_flatfield) + calgrp += PvlKeyword("FlatFile", flatFile); + if (g_radiometric) { + if (g_iof) + calgrp += PvlKeyword("RadiometricType", "IOF"); + else + calgrp += PvlKeyword("RadiometricType", "AbsoluteRadiance"); + + responsivity.SetName("ResponsivityValues"); + calgrp += responsivity; + calgrp += PvlKeyword("SolarDistance", g_solarDistance); + } + ocube->PutGroup(calgrp); + + p.EndProcess(); +} + +void ResetGlobals () { + g_iofResponsivity.clear(); + g_radianceResponsivity.clear(); + + g_dark = true; + g_flatfield = true; + g_radiometric = true; + g_iof = true; + g_specpix = true; + + g_bands.clear(); + + g_exposure = 1.0; // Exposure duration + g_solarDistance = 1.01; // average distance in [AU] + + darkCube.clear(); + flatCube.clear(); + specpixCube.clear(); +} + +// Calibrate each framelet +void Calibrate ( Buffer &inCube, Buffer &outCube ) { + + int frame = inCube.Line() / inCube.LineDimension(); + + for (int i = 0; i < outCube.size(); i++) + outCube[i] = inCube[i]; + + if (g_dark) { + for (int i = 0; i < outCube.size(); i++) { + int offset = inCube.size() * (int) min(frame, (darkCube.size()-1) / inCube.size()); + + if (IsSpecial(darkCube[offset + i])) + outCube[i] = Isis::Null; + else + outCube[i] -= darkCube[offset + i]; + } + } + + if (g_flatfield) { + int offset = inCube.size() * (int) min(frame, (flatCube.size()-1) / inCube.size()); + + for (int i = 0; i < outCube.size(); i++) + if (flatCube[i] <= 0 || IsSpecial(flatCube[offset + i])) + outCube[i] = Isis::Null; + else + outCube[i] /= flatCube[offset + i]; + } + + if (g_radiometric) { + for (int i = 0; i < outCube.size(); i++) { + if (IsSpecial(outCube[i])) + outCube[i] = Isis::Null; + else { + outCube[i] /= g_exposure; + if (g_iof) + outCube[i] *= pow(g_solarDistance, 2) / g_iofResponsivity[outCube.Band() - 1]; + else + outCube[i] /= g_radianceResponsivity[outCube.Band() - 1]; + } + } + } + + if (g_specpix) { + for (int i = 0; i < outCube.size(); i++) { + int offset = inCube.size() * (int) min(frame, (specpixCube.size()-1) / inCube.size()); + + if (IsSpecial(specpixCube[offset + i])) + outCube[i] = specpixCube[offset + i]; + } + } + +} + +void CopyCubeIntoArray ( string &fileString, vector & data ) { + Cube cube; + Filename filename(fileString); + if ((filename.Expanded()).find("?") != string::npos) + filename.HighestVersion(); + if (!filename.Exists()) { + string msg = fileString + " does not exist."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + cube.Open(filename.Expanded()); + Brick brick(cube.Samples(), cube.Lines(), cube.Bands(), cube.PixelType()); + brick.SetBasePosition(1, 1, 1); + cube.Read(brick); + + data.clear(); + + for (unsigned int b = 0; b < g_bands.size(); b++) { + for (int l = 1; l <= brick.LineDimension(); l++) + for (int s = 1; s <= brick.SampleDimension(); s++) { + data.push_back(brick.at(brick.Index(s, l, g_bands[b]))); + } + } + + fileString = filename.Expanded(); +} + +double min ( double a, double b ) { + if (a < b) + return a; + return b; +} diff --git a/isis/src/lro/apps/lrowaccal/lrowaccal.xml b/isis/src/lro/apps/lrowaccal/lrowaccal.xml new file mode 100644 index 0000000000000000000000000000000000000000..2d3bf56b2d519288becaf1e84ccdfd5032ff4bb9 --- /dev/null +++ b/isis/src/lro/apps/lrowaccal/lrowaccal.xml @@ -0,0 +1,170 @@ + + + + + + This program calibrates WAC images + + + + This program applies a dark and flat-field correction for each framelet based on the + band's filter number. In order to output in I/F units, the cube must have spice + data. + + + + Lunar Reconnaissance Orbiter + + + + + Original version + + + + + + + cube + input + + Input Image + + + This is the non-calibrated, unprojected WAC cube + + + *.cub + + + + + cube + output + real + + Output Image + + + This is the calibrated WAC cube + + + *.cub + + + + + + + boolean + True + + Calibrate using the average dark pixels. + + + + DarkFile + + + + filename + Default + + Calibrate using the average dark pixels. + + + + + + + + + boolean + True + + Calibrate using the flatfield. + + + + FlatfieldFile + + + + filename + Default + + Calibrate using the average dark pixels. + + + + + + + + + boolean + True + + Calibrate using radiometric calibration. + + + + RadiometricType + RadiometricFile + + + + string + + Which radiance correction? + + + + IOF + + + + + + + + filename + Default + + + + + + + + + + boolean + True + + + + + SpecialPixelsFile + + + + filename + Default + + + + + + + + + diff --git a/isis/src/lro/apps/lrowaccal/tsts/Makefile b/isis/src/lro/apps/lrowaccal/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/lro/apps/lrowaccal/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/lro/apps/lrowaccal/tsts/wac-mono-even/Makefile b/isis/src/lro/apps/lrowaccal/tsts/wac-mono-even/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5be81c63b6fc96410e6b11432053a7c7c4c4fdf3 --- /dev/null +++ b/isis/src/lro/apps/lrowaccal/tsts/wac-mono-even/Makefile @@ -0,0 +1,7 @@ +APPNAME = lrowaccal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/wac0003330c.vis.even.cub \ + to=$(OUTPUT)/wac0003330c.vis.even.cal.cub > /dev/null; diff --git a/isis/src/lro/apps/lrowaccal/tsts/wac-mono-odd/Makefile b/isis/src/lro/apps/lrowaccal/tsts/wac-mono-odd/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..828a42fa573aa900d7b8a6d915fa02533320c80e --- /dev/null +++ b/isis/src/lro/apps/lrowaccal/tsts/wac-mono-odd/Makefile @@ -0,0 +1,7 @@ +APPNAME = lrowaccal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/wac0003330c.vis.odd.cub \ + to=$(OUTPUT)/wac0003330c.vis.odd.cal.cub > /dev/null; diff --git a/isis/src/lro/apps/lrowaccal/tsts/wac-uv-even/Makefile b/isis/src/lro/apps/lrowaccal/tsts/wac-uv-even/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8776efd91863d035c312b179ad92cff179357118 --- /dev/null +++ b/isis/src/lro/apps/lrowaccal/tsts/wac-uv-even/Makefile @@ -0,0 +1,7 @@ +APPNAME = lrowaccal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/wac0002dd70.uv.even.cub \ + to=$(OUTPUT)/wac0002dd70.uv.even.cal.cub > /dev/null; diff --git a/isis/src/lro/apps/lrowaccal/tsts/wac-uv-odd/Makefile b/isis/src/lro/apps/lrowaccal/tsts/wac-uv-odd/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..06666721b90566ed2eb6c2cff2a1079d0ca3a544 --- /dev/null +++ b/isis/src/lro/apps/lrowaccal/tsts/wac-uv-odd/Makefile @@ -0,0 +1,7 @@ +APPNAME = lrowaccal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/wac0002dd70.uv.odd.cub \ + to=$(OUTPUT)/wac0002dd70.uv.odd.cal.cub > /dev/null; diff --git a/isis/src/lro/apps/lrowaccal/tsts/wac-vis-even/Makefile b/isis/src/lro/apps/lrowaccal/tsts/wac-vis-even/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..892cc139f91944caf55d612407a7fcfd588165d9 --- /dev/null +++ b/isis/src/lro/apps/lrowaccal/tsts/wac-vis-even/Makefile @@ -0,0 +1,7 @@ +APPNAME = lrowaccal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/wac0002dd70.vis.even.cub+1,3,5 \ + to=$(OUTPUT)/wac0002dd70.vis.even.cal135.cub > /dev/null; diff --git a/isis/src/lro/apps/lrowaccal/tsts/wac-vis-odd/Makefile b/isis/src/lro/apps/lrowaccal/tsts/wac-vis-odd/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..15fd3a4dcf7b1b25f4297e24df539797d87fac5b --- /dev/null +++ b/isis/src/lro/apps/lrowaccal/tsts/wac-vis-odd/Makefile @@ -0,0 +1,7 @@ +APPNAME = lrowaccal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/wac0002dd70.vis.odd.cub+2,4 \ + to=$(OUTPUT)/wac0002dd70.vis.odd.cal24.cub > /dev/null; diff --git a/isis/src/lro/apps/lrowacpho/Exponential.cpp b/isis/src/lro/apps/lrowacpho/Exponential.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8c6f323575693f03c2b0a1108ee4a13bebcdc96b --- /dev/null +++ b/isis/src/lro/apps/lrowacpho/Exponential.cpp @@ -0,0 +1,306 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2010/05/18 06:38:05 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include +#include + +#include "Camera.h" +#include "Exponential.h" +#include "DbProfile.h" +#include "PvlObject.h" +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" + +using namespace std; + +namespace Isis { + + /** + * @brief Method to get photometric property given angles + * + * This routine computes the photometric property at the given + * cube location after ensuring a proper parameter container is + * found for the specified band. + * + * @author Kris Becker - 2/21/2010 + * + * @param i Incidence angle at cube location + * @param e Emission angle at cube location + * @param g Phase angle at cube location + * @param band Band number in cube (actually is band index) for + * lookup purposes + * + * @return double Returns photometric correction using + * parameters + */ + double Exponential::photometry ( double i, double e, double g, int band ) const { + // Test for valid band + if ((band <= 0) || (band > (int) _bandpho.size())) { + std::string mess = "Provided band " + iString(band) + " out of range."; + throw iException::Message(iException::Programmer, mess, _FILEINFO_); + } + double ph = photometry(_bandpho[band - 1], i, e, g); + return (_bandpho[band - 1].phoStd / ph); + } + + /** + * @brief Performs actual photometric correction calculations + * + * This routine computes photometric correction using parameters + * for the Exponential-Buratti-Hill equation. + * + * @author Kris Becker - 2/21/2010 + * + * @param parms Container of band-specific Exponential parameters + * @param i Incidence angle in degrees + * @param e Emission angle in degrees + * @param g Phase angle in degrees + * + * @return double Photometric correction parameter + */ + double Exponential::photometry ( const Parameters &parms, double i, double e, double g ) const { + + // Ensure problematic values are adjusted + if (i == 0.0) + i = 10.E-12; + if (e == 0.0) + e = 10.E-12; + + // Convert to radians + i *= rpd_c(); + e *= rpd_c(); + g *= parms.phaUnit; // Apply unit normalizer + + // Compute Lommel-Seeliger components + double mu = cos(e); + double mu0 = cos(i); + + double alpha = g; + + // Simple Exponential photometric polynomial equation with exponential opposition + // surge term. + double rcal = 0.0; + for (unsigned int i = 0; i < parms.aTerms.size(); i++) { + rcal += parms.aTerms[i] * exp(parms.bTerms[i] * alpha); + } + + return ((mu0 / (mu + mu0)) * rcal); + } + + /** + * @brief Return parameters used for all bands + * + * Method creates keyword vectors of band specific parameters + * used in the photometric correction. + * + * @author Kris Becker - 2/22/2010 + * + * @param pvl Output PVL container write keywords + */ + void Exponential::Report ( PvlContainer &pvl ) { + pvl += PvlKeyword("Algorithm", "Exponential"); + pvl += PvlKeyword("IncRef", _iRef, "degrees"); + pvl += PvlKeyword("EmaRef", _eRef, "degrees"); + pvl += PvlKeyword("PhaRef", _gRef, "degrees"); + PvlKeyword units("ExponentialUnits"); + PvlKeyword phostd("PhotometricStandard"); + PvlKeyword bbc("BandBinCenter"); + PvlKeyword bbct("BandBinCenterTolerance"); + PvlKeyword bbn("BandNumber"); + + std::vector aTermKeywords; + std::vector bTermKeywords; + for (unsigned int i = 0; i < _bandpho[0].aTerms.size(); i++) + aTermKeywords.push_back(PvlKeyword("A" + iString((int) i))); + for (unsigned int i = 0; i < _bandpho[0].bTerms.size(); i++) + bTermKeywords.push_back(PvlKeyword("B" + iString((int) i))); + + for (unsigned int i = 0; i < _bandpho.size(); i++) { + Parameters &p = _bandpho[i]; + units.AddValue(p.units); + phostd.AddValue(p.phoStd); + bbc.AddValue(p.wavelength); + bbct.AddValue(p.tolerance); + bbn.AddValue(p.band); + for (unsigned int j = 0; j < aTermKeywords.size(); j++) + aTermKeywords[j].AddValue(p.aTerms[j]); + for (unsigned int j = 0; j < bTermKeywords.size(); j++) + bTermKeywords[j].AddValue(p.bTerms[j]); + } + pvl += units; + pvl += phostd; + pvl += bbc; + pvl += bbct; + pvl += bbn; + for (unsigned int i = 0; i < aTermKeywords.size(); i++) + pvl += aTermKeywords[i]; + + for (unsigned int i = 0; i < bTermKeywords.size(); i++) + pvl += bTermKeywords[i]; + + return; + } + + /** + * @brief Determine Exponential parameters given a wavelength + * + * This method determines the set of Exponential parameters to use + * for a given wavelength. It iterates through all band + * profiles as read from the PVL file and computes the + * difference between the "wavelength" parameter and the + * BandBinCenter keyword. The absolute value of this value is + * checked against the BandBinCenterTolerance paramter and if it + * is less than or equal to it, a Parameter container is + * returned. + * + * @author Kris Becker - 2/22/2010 + * + * @param wavelength Wavelength used to find parameter set + * + * @return Exponential::Parameters Container of valid values. If + * not found, a value of iProfile = -1 is returned. + */ + Exponential::Parameters Exponential::findParameters ( const double wavelength ) const { + for (unsigned int i = 0; i < _profiles.size(); i++) { + const DbProfile &p = _profiles[i]; + if (p.exists("BandBinCenter")) { + double p_center = ConfKey(p, "BandBinCenter", Null); + double tolerance = ConfKey(p, "BandBinCenterTolerance", 1.0E-6); + if (fabs(wavelength - p_center) <= fabs(tolerance)) { + Parameters pars = extract(p); + pars.iProfile = i; + pars.wavelength = wavelength; + pars.tolerance = tolerance; + return (pars); + } + } + } + + // Not found if we reach here + return (Parameters()); + } + + /** + * @brief Extracts necessary Exponential parameters from profile + * + * Given a profile read from the input PVL file, this method + * extracts needed parameters (from Keywords) in the PVL profile + * and creates a container of the converted values. + * + * @author Kris Becker - 2/22/2010 + * + * @param p Profile to extract/convert + * + * @return Exponential::Parameters Container of extracted values + */ + Exponential::Parameters Exponential::extract ( const DbProfile &p ) const { + Parameters pars; + + for (int i = 0;i < p.size(); i++) { + if (p.exists("A" + iString(i)) || p.exists("B" + iString(i))) { + pars.aTerms.push_back(ConfKey(p, "A" + iString(i), 1.0)); + pars.bTerms.push_back(ConfKey(p, "B" + iString(i), 0.0)); + } + } + + pars.wavelength = ConfKey(p, "BandBinCenter", Null); + pars.tolerance = ConfKey(p, "BandBinCenterTolerance", Null); + // Determine equation units - defaults to Radians + pars.units = ConfKey(p, "ExponentialUnits", iString("Radians")); + pars.phaUnit = (iString::Equal(pars.units, "Degrees")) ? 1.0 : rpd_c(); + return (pars); + } + + /** + * @brief Initialize class from input PVL and Cube files + * + * This method is typically called at class instantiation time, + * but is reentrant. It reads the parameter PVL file and + * extracts Photometric model and Normalization models from it. + * The cube is needed to match all potential profiles for each + * band. + * + * @author Kris Becker - 2/22/2010 + * + * @param pvl Input PVL parameter files + * @param cube Input cube file to correct + */ + void Exponential::init ( PvlObject &pvl, Cube &cube ) { + + // Make it reentrant + _profiles.clear(); + _bandpho.clear(); + + // Interate over all Photometric groups + _normProf = DbProfile(pvl.FindObject("NormalizationModel").FindGroup("Algorithm", Pvl::Traverse)); + _iRef = ConfKey(_normProf, "IncRef", 30.0); + _eRef = ConfKey(_normProf, "EmaRef", 0.0); + _gRef = ConfKey(_normProf, "PhaRef", _iRef); + + PvlObject &phoObj = pvl.FindObject("PhotometricModel"); + DbProfile phoProf = DbProfile(phoObj); + PvlObject::PvlGroupIterator algo = phoObj.BeginGroup(); + while (algo != phoObj.EndGroup()) { + if (iString::Equal(algo->Name(), "Algorithm")) { + _profiles.push_back(DbProfile(phoProf, DbProfile(*algo))); + } + ++algo; + } + + Pvl *label = cube.Label(); + PvlKeyword center = label->FindGroup("BandBin", Pvl::Traverse)["Center"]; + string errs(""); + for (int i = 0; i < cube.Bands(); i++) { + Parameters parms = findParameters(center[i]); + if (parms.IsValid()) { + parms.band = i + 1; + _camera->SetBand(i + 1); + parms.phoStd = photometry(parms, _iRef, _eRef, _gRef); + _bandpho.push_back(parms); + } + else { // Appropriate photometric parameters not found + ostringstream mess; + mess << "Band " << i + 1 << " with wavelength Center = " << center[i] + << " does not have PhotometricModel Algorithm group/profile"; + iException &e = iException::Message(iException::User, mess.str(), _FILEINFO_); + errs += e.Errors() + "\n"; + e.Clear(); + } + } + + // Check for errors and throw them all at the same time + if (!errs.empty()) { + errs += " --> Errors in the input PVL file \"" + pvl.Filename() + "\""; + throw iException::Message(iException::User, errs, _FILEINFO_); + } + + return; + } + +} // namespace Isis + + diff --git a/isis/src/lro/apps/lrowacpho/Exponential.h b/isis/src/lro/apps/lrowacpho/Exponential.h new file mode 100644 index 0000000000000000000000000000000000000000..e83c84d41cec64eb3bf7de00e09c6bb51e10aa0e --- /dev/null +++ b/isis/src/lro/apps/lrowacpho/Exponential.h @@ -0,0 +1,109 @@ +#if !defined(Exponential_h) +#define Exponential_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2010/05/18 06:38:05 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include + +#include "PhotometricFunction.h" +#include "iString.h" +#include "Camera.h" +#include "DbProfile.h" +#include "SpecialPixel.h" + +namespace Isis { + + class PvlObject; + class Camera; + + /** + * @brief An implementation of the Exponential photometric function + * + * This class implements the Exponential-Buratti-Hill photometric + * equation as outline in thier paper "Multispectral Photometry + * of the Moon and Absolute Calibration of the Clementine UV/VIS + * Camera", published in Icaris v141, pg. 205-255 (1999). + * + * @author 2010-02-15 Kris Becker + * + */ + class Exponential : public PhotometricFunction { + public: + /** + * @brief Create Hilier photometric object + * + */ + Exponential (PvlObject &pvl, Cube &cube) : PhotometricFunction(pvl, cube) {init(pvl, cube);} + + //! Destructor + virtual ~Exponential () {} + + double photometry ( double i, double e, double g, int band = 1 ) const; + void Report ( PvlContainer &pvl ); + + private: + /** + * @brief Container for band photometric correction parameters + * + * @author Kris Becker - 2/21/2010 + */ + struct Parameters { + Parameters () : + aTerms(), bTerms(), wavelength(0.0), tolerance(0.0), units("Degrees"), phaUnit(1.0), band(0), phoStd( + 0.0), iProfile(-1) { + } + ~Parameters () { + } + bool IsValid () const { + return (iProfile != -1); + } + std::vector aTerms; // bTerms; // _profiles; + std::vector _bandpho; + + void init(PvlObject &pvl, Cube &cube); + + double photometry ( const Parameters &parms, double i, double e, double g ) const; + + Parameters findParameters ( const double wavelength ) const; + Parameters extract ( const DbProfile &profile ) const; + }; + +} +; + +#endif + diff --git a/isis/src/lro/apps/lrowacpho/Hillier.cpp b/isis/src/lro/apps/lrowacpho/Hillier.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d88fb527341524cd2f0917bba3e5f4aff6004317 --- /dev/null +++ b/isis/src/lro/apps/lrowacpho/Hillier.cpp @@ -0,0 +1,304 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2010/05/18 06:38:05 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include +#include + +#include "Camera.h" +#include "Hillier.h" +#include "DbProfile.h" +#include "PvlObject.h" +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" + +using namespace std; + +namespace Isis { + /** + * @brief Method to get photometric property given angles + * + * This routine computes the photometric property at the given + * cube location after ensuring a proper parameter container is + * found for the specified band. + * + * @author Kris Becker - 2/21/2010 + * + * @param i Incidence angle at cube location + * @param e Emission angle at cube location + * @param g Phase angle at cube location + * @param band Band number in cube (actually is band index) for + * lookup purposes + * + * @return double Returns photometric correction using + * parameters + */ + double Hillier::photometry ( double i, double e, double g, int band ) const { + // Test for valid band + if ((band <= 0) || (band > (int) _bandpho.size())) { + std::string mess = "Provided band " + iString(band) + " out of range."; + throw iException::Message(iException::Programmer, mess, _FILEINFO_); + } + double ph = photometry(_bandpho[band - 1], i, e, g); + return (_bandpho[band - 1].phoStd / ph); + } + + /** + * @brief Performs actual photometric correction calculations + * + * This routine computes photometric correction using parameters + * for the Hillier-Buratti-Hill equation. + * + * @author Kris Becker - 2/21/2010 + * + * @param parms Container of band-specific Hillier parameters + * @param i Incidence angle in degrees + * @param e Emission angle in degrees + * @param g Phase angle in degrees + * + * @return double Photometric correction parameter + */ + double Hillier::photometry ( const Parameters &parms, double i, double e, double g ) const { + + // Ensure problematic values are adjusted + if (i == 0.0) + i = 10.E-12; + if (e == 0.0) + e = 10.E-12; + + // Convert to radians + i *= rpd_c(); + e *= rpd_c(); + g *= parms.phaUnit; // Apply unit normalizer + + // Compute Lommel-Seeliger components + double mu = cos(e); + double mu0 = cos(i); + + double alpha = g; + double alpha2 = g * g; + + // Simple Hillier photometric polynomial equation with exponential opposition + // surge term. + double rcal = (mu0 / (mu + mu0)) * (parms.b0 * exp(-parms.b1 * alpha) + parms.a0 + (parms.a1 * alpha) + (parms.a2 * alpha2) + (parms.a3 * alpha * alpha2) + (parms.a4 * alpha2 * alpha2)); + + return (rcal); + } + + /** + * @brief Return parameters used for all bands + * + * Method creates keyword vectors of band specific parameters + * used in the photometric correction. + * + * @author Kris Becker - 2/22/2010 + * + * @param pvl Output PVL container write keywords + */ + void Hillier::Report ( PvlContainer &pvl ) { + pvl += PvlKeyword("Algorithm", "Hillier"); + pvl += PvlKeyword("IncRef", _iRef, "degrees"); + pvl += PvlKeyword("EmaRef", _eRef, "degrees"); + pvl += PvlKeyword("PhaRef", _gRef, "degrees"); + PvlKeyword units("HillierUnits"); + PvlKeyword phostd("PhotometricStandard"); + PvlKeyword bbc("BandBinCenter"); + PvlKeyword bbct("BandBinCenterTolerance"); + PvlKeyword bbn("BandNumber"); + PvlKeyword b0("B0"); + PvlKeyword b1("B1"); + PvlKeyword a0("A0"); + PvlKeyword a1("A1"); + PvlKeyword a2("A2"); + PvlKeyword a3("A3"); + PvlKeyword a4("A4"); + for (unsigned int i = 0; i < _bandpho.size(); i++) { + Parameters &p = _bandpho[i]; + units.AddValue(p.units); + phostd.AddValue(p.phoStd); + bbc.AddValue(p.wavelength); + bbct.AddValue(p.tolerance); + bbn.AddValue(p.band); + b0.AddValue(p.b0); + b1.AddValue(p.b1); + a0.AddValue(p.a0); + a1.AddValue(p.a1); + a2.AddValue(p.a2); + a3.AddValue(p.a3); + a4.AddValue(p.a4); + } + pvl += units; + pvl += phostd; + pvl += bbc; + pvl += bbct; + pvl += bbn; + pvl += b0; + pvl += b1; + pvl += a0; + pvl += a1; + pvl += a2; + pvl += a3; + pvl += a4; + return; + } + + /** + * @brief Determine Hillier parameters given a wavelength + * + * This method determines the set of Hillier parameters to use + * for a given wavelength. It iterates through all band + * profiles as read from the PVL file and computes the + * difference between the "wavelength" parameter and the + * BandBinCenter keyword. The absolute value of this value is + * checked against the BandBinCenterTolerance paramter and if it + * is less than or equal to it, a Parameter container is + * returned. + * + * @author Kris Becker - 2/22/2010 + * + * @param wavelength Wavelength used to find parameter set + * + * @return Hillier::Parameters Container of valid values. If + * not found, a value of iProfile = -1 is returned. + */ + Hillier::Parameters Hillier::findParameters ( const double wavelength ) const { + for (unsigned int i = 0; i < _profiles.size(); i++) { + const DbProfile &p = _profiles[i]; + if (p.exists("BandBinCenter")) { + double p_center = ConfKey(p, "BandBinCenter", Null); + double tolerance = ConfKey(p, "BandBinCenterTolerance", 1.0E-6); + if (fabs(wavelength - p_center) <= fabs(tolerance)) { + Parameters pars = extract(p); + pars.iProfile = i; + pars.wavelength = wavelength; + pars.tolerance = tolerance; + return (pars); + } + } + } + + // Not found if we reach here + return (Parameters()); + } + + /** + * @brief Extracts necessary Hillier parameters from profile + * + * Given a profile read from the input PVL file, this method + * extracts needed parameters (from Keywords) in the PVL profile + * and creates a container of the converted values. + * + * @author Kris Becker - 2/22/2010 + * + * @param p Profile to extract/convert + * + * @return Hillier::Parameters Container of extracted values + */ + Hillier::Parameters Hillier::extract ( const DbProfile &p ) const { + Parameters pars; + pars.b0 = ConfKey(p, "B0", 0.0); + pars.b1 = ConfKey(p, "B1", 0.0); + pars.a0 = ConfKey(p, "A0", 0.0); + pars.a1 = ConfKey(p, "A1", 0.0); + pars.a2 = ConfKey(p, "A2", 0.0); + pars.a3 = ConfKey(p, "A3", 0.0); + pars.a4 = ConfKey(p, "A4", 0.0); + pars.wavelength = ConfKey(p, "BandBinCenter", Null); + pars.tolerance = ConfKey(p, "BandBinCenterTolerance", Null); + // Determine equation units - defaults to Radians + pars.units = ConfKey(p, "HillierUnits", iString("Radians")); + pars.phaUnit = (iString::Equal(pars.units, "Degrees")) ? 1.0 : rpd_c(); + return (pars); + } + + /** + * @brief Initialize class from input PVL and Cube files + * + * This method is typically called at class instantiation time, + * but is reentrant. It reads the parameter PVL file and + * extracts Photometric model and Normalization models from it. + * The cube is needed to match all potential profiles for each + * band. + * + * @author Kris Becker - 2/22/2010 + * + * @param pvl Input PVL parameter files + * @param cube Input cube file to correct + */ + void Hillier::init ( PvlObject &pvl, Cube &cube ) { + // Make it reentrant + _profiles.clear(); + _bandpho.clear(); + + // Interate over all Photometric groups + _normProf = DbProfile(pvl.FindObject("NormalizationModel").FindGroup("Algorithm", Pvl::Traverse)); + _iRef = ConfKey(_normProf, "IncRef", 30.0); + _eRef = ConfKey(_normProf, "EmaRef", 0.0); + _gRef = ConfKey(_normProf, "PhaRef", _iRef); + + PvlObject &phoObj = pvl.FindObject("PhotometricModel"); + DbProfile phoProf = DbProfile(phoObj); + PvlObject::PvlGroupIterator algo = phoObj.BeginGroup(); + while (algo != phoObj.EndGroup()) { + if (iString::Equal(algo->Name(), "Algorithm")) { + _profiles.push_back(DbProfile(phoProf, DbProfile(*algo))); + } + ++algo; + } + + Pvl *label = cube.Label(); + PvlKeyword center = label->FindGroup("BandBin", Pvl::Traverse)["Center"]; + string errs(""); + for (int i = 0; i < cube.Bands(); i++) { + Parameters parms = findParameters(center[i]); + if (parms.IsValid()) { + parms.band = i + 1; + _camera->SetBand(i + 1); + parms.phoStd = photometry(parms, _iRef, _eRef, _gRef); + _bandpho.push_back(parms); + } + else { // Appropriate photometric parameters not found + ostringstream mess; + mess << "Band " << i + 1 << " with wavelength Center = " << center[i] + << " does not have PhotometricModel Algorithm group/profile"; + iException &e = iException::Message(iException::User, mess.str(), _FILEINFO_); + errs += e.Errors() + "\n"; + e.Clear(); + } + } + + // Check for errors and throw them all at the same time + if (!errs.empty()) { + errs += " --> Errors in the input PVL file \"" + pvl.Filename() + "\""; + throw iException::Message(iException::User, errs, _FILEINFO_); + } + + return; + } + +} // namespace Isis + + diff --git a/isis/src/lro/apps/lrowacpho/Hillier.h b/isis/src/lro/apps/lrowacpho/Hillier.h new file mode 100644 index 0000000000000000000000000000000000000000..ebf1cffc4e730ed1de0c2d795a74d3121308d6a7 --- /dev/null +++ b/isis/src/lro/apps/lrowacpho/Hillier.h @@ -0,0 +1,103 @@ +#if !defined(Hillier_h) +#define Hillier_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2010/05/18 06:38:05 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "PhotometricFunction.h" +#include "iString.h" +#include "Camera.h" +#include "DbProfile.h" +#include "SpecialPixel.h" + +namespace Isis { + + class PvlObject; + class Camera; + + /** + * @brief An implementation of the Hillier photometric function + * + * This class implements the Hillier-Buratti-Hill photometric + * equation as outline in thier paper "Multispectral Photometry + * of the Moon and Absolute Calibration of the Clementine UV/VIS + * Camera", published in Icaris v141, pg. 205-255 (1999). + * + * @author 2010-02-15 Kris Becker + * + */ + class Hillier : public PhotometricFunction{ + public: + /** + * @brief Create Hilier photometric object + * + */ + Hillier (PvlObject &pvl, Cube &cube) : PhotometricFunction(pvl, cube) {init(pvl, cube);}; + + //! Destructor + virtual ~Hillier() {}; + + double photometry(double i, double e, double g, int band = 1) const; + void Report(PvlContainer &pvl); + + private: + /** + * @brief Container for band photometric correction parameters + * + * @author Kris Becker - 2/21/2010 + */ + struct Parameters { + Parameters() : b0(0.0), b1(0.0), a0(0.0), a1(0.0), a2(0.0), a3(0.0), + a4(0.0), wavelength(0.0), tolerance(0.0), + units("Degrees"), phaUnit(1.0), band(0), phoStd(0.0), + iProfile(-1) { } + ~Parameters() { } + bool IsValid() const { return (iProfile != -1); } + double b0, b1, a0, a1, a2, a3, a4; // _profiles; + std::vector _bandpho; + + void init(PvlObject &pvl, Cube &cube); + + virtual double photometry(const Parameters &parms, double i, double e,double g) const; + + Parameters findParameters(const double wavelength) const; + Parameters extract(const DbProfile &profile) const; + }; + +}; + +#endif + diff --git a/isis/src/lro/apps/lrowacpho/Makefile b/isis/src/lro/apps/lrowacpho/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/lro/apps/lrowacpho/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/lro/apps/lrowacpho/PhotometricFunction.cpp b/isis/src/lro/apps/lrowacpho/PhotometricFunction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d3033d82f014d437c4f19ece7a56a35c38b0d07 --- /dev/null +++ b/isis/src/lro/apps/lrowacpho/PhotometricFunction.cpp @@ -0,0 +1,93 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2010/05/18 06:38:05 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include +#include + +#include "Camera.h" +#include "PhotometricFunction.h" +#include "DbProfile.h" +#include "PvlObject.h" +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" + +using namespace std; + +namespace Isis { + + /** + * @brief Construct from PVL and Cube file + * + * @author Kris Becker - 2/21/2010 + * + * @param pvl Photometric parameter files + * @param cube Input cube file + */ + PhotometricFunction::PhotometricFunction ( PvlObject &pvl, Cube &cube ) { + _camera = cube.Camera(); + } + /** + * @brief Compute photometric DN at given line/sample/band + * + * This routine applies the photometric angles to the equation + * and returns the calibration coefficient at the given cube + * location. + * + * The return parameter is the photometric standard/photometric + * correction coefficient at the given pixel location. + * + * @author Kris Becker - 2/21/2010 + * + * @param line Line of cube image to compute photometry + * @param sample Sample of cube image to compute photometry + * @param band Band of cube image to compute photometry + * + * @return double Photometric correction at cube loation + */ + double PhotometricFunction::Compute ( const double &line, const double &sample, int band ) { + // Update band if necessary + if (_camera->Band() != band) { + _camera->SetBand(band); + } + if (!_camera->SetImage(sample, line)) + return (Null); + + double i = _camera->IncidenceAngle(); + double e = _camera->EmissionAngle(); + double g = _camera->PhaseAngle(); + + if (i < MinimumIncidenceAngle() || i > MaximumIncidenceAngle() || e < MinimumEmissionAngle() || e + > MaximumEmissionAngle() || g < MinimumPhaseAngle() || g > MaximumPhaseAngle()) + return (Null); + + + return photometry(i, e, g, band); + } + +} // namespace Isis + + diff --git a/isis/src/lro/apps/lrowacpho/PhotometricFunction.h b/isis/src/lro/apps/lrowacpho/PhotometricFunction.h new file mode 100644 index 0000000000000000000000000000000000000000..fe191600b455994f588981520d969f3311d200eb --- /dev/null +++ b/isis/src/lro/apps/lrowacpho/PhotometricFunction.h @@ -0,0 +1,184 @@ +#if !defined(PhotometricFunction_h) +#define PhotometricFunction_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2010/05/18 06:38:06 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "iString.h" +#include "Camera.h" +#include "DbProfile.h" +#include "SpecialPixel.h" + +#include +#include +#include + +namespace Isis { + + /** Implement templatized MIN fumnction */ + template inline T MIN ( const T &A, const T &B ) { + if (A < B) { + return (A); + } + else { + return (B); + } + } + + /** Implement templatized MAX function */ + template inline T MAX ( const T &A, const T &B ) { + if (A > B) { + return (A); + } + else { + return (B); + } + } + + class PvlObject; + class Camera; + + /** + * @brief An implementation of the PhotometricFunction photometric function + * + * This class implements the PhotometricFunction-Buratti-Hill photometric + * equation as outline in thier paper "Multispectral Photometry + * of the Moon and Absolute Calibration of the Clementine UV/VIS + * Camera", published in Icaris v141, pg. 205-255 (1999). + * + * @author 2010-02-15 Kris Becker + * + */ + class PhotometricFunction { + public: + /** + * @brief Create Hilier photometric object + * + */ + PhotometricFunction ( PvlObject &pvl, Cube &cube ); + + //! Destructor + virtual ~PhotometricFunction () { + } + ; + + void setCamera ( Camera *cam ) { + _camera = cam; + } + + static iString AlgorithmName ( const PvlObject &pvl ) { + return pvl.FindObject("PhotometricModel").FindGroup("Algorithm", Pvl::Traverse).FindKeyword("Name")[0]; + } + + virtual double Compute ( const double &line, const double &sample, int band = 1 ); + virtual double photometry ( double i, double e, double g, int band = 1 ) const = 0; + virtual void Report ( PvlContainer &pvl ) = 0; + + void SetMinimumIncidenceAngle (double angle) { + p_minimumIncidenceAngle = angle; + } + void SetMaximumIncidenceAngle (double angle) { + p_maximumIncidenceAngle = angle; + } + void SetMinimumEmissionAngle (double angle) { + p_minimumEmissionAngle = angle; + } + void SetMaximumEmissionAngle (double angle) { + p_maximumEmissionAngle = angle; + } + void SetMinimumPhaseAngle (double angle) { + p_minimumPhaseAngle = angle; + } + void SetMaximumPhaseAngle (double angle) { + p_maximumPhaseAngle = angle; + } + + double MinimumIncidenceAngle () { + return p_minimumIncidenceAngle; + } + double MaximumIncidenceAngle () { + return p_maximumIncidenceAngle; + } + double MinimumEmissionAngle () { + return p_minimumEmissionAngle; + } + double MaximumEmissionAngle () { + return p_maximumEmissionAngle; + } + double MinimumPhaseAngle () { + return p_minimumPhaseAngle; + } + double MaximumPhaseAngle () { + return p_maximumPhaseAngle; + } + + protected: + + Camera *_camera; + double _iRef; //!< Incidence refernce angle + double _eRef; // Emission reference angle + double _gRef; // Phase reference angle + + double p_minimumIncidenceAngle; + double p_maximumIncidenceAngle; + double p_minimumEmissionAngle; + double p_maximumEmissionAngle; + double p_minimumPhaseAngle; + double p_maximumPhaseAngle; + + DbProfile _normProf; + + /** + * @brief Helper method to initialize parameters + * + * This method will check the existance of a keyword and extract the value + * if it exists to the passed parameter (type). If it doesn't exist, the + * default values is returned. + * + * @param T Templated variable type + * @param conf Parameter profile container + * @param keyname Name of keyword to get a value from + * @param defval Default value it keyword/value doesn't exist + * @param index Optional index of the value for keyword arrays + * + * @return T Return type + */ + template + T ConfKey ( const DbProfile &conf, const std::string &keyname, const T &defval, int index = 0 ) const { + if (!conf.exists(keyname)) { + return (defval); + } + if (conf.count(keyname) < index) { + return (defval); + } + iString iValue(conf.value(keyname, index)); + T value = iValue; // This makes it work with a string? + return (value); + } + + }; + +} +; + +#endif + diff --git a/isis/src/lro/apps/lrowacpho/lrowacpho.cpp b/isis/src/lro/apps/lrowacpho/lrowacpho.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fef5319b3bfea3dadb9c0b467b8ad173c83f9e0d --- /dev/null +++ b/isis/src/lro/apps/lrowacpho/lrowacpho.cpp @@ -0,0 +1,97 @@ +// $Id: lrowacpho.cpp,v 1.1 2010/05/18 06:38:06 kbecker Exp $ +#include "Isis.h" + +#include +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "Hillier.h" +#include "PhotometricFunction.h" +#include "Exponential.h" +#include "Pvl.h" +#include "Cube.h" + +#include "PvlGroup.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +// Global variables +PhotometricFunction *pho; + +void phoCal ( Buffer &in, Buffer &out ); + +void IsisMain () { + // We will be processing by line + ProcessByLine p; + + // Set up the input cube and get camera information + Cube *icube = p.SetInputCube("FROM"); + + // Create the output cube + Cube *ocube = p.SetOutputCube("TO"); + + // Set up the user interface + UserInterface &ui = Application::GetUserInterface(); + // Get the name of the parameter file + Pvl par(ui.GetFilename("PHOPAR")); + + iString algoName = PhotometricFunction::AlgorithmName(par); + algoName.UpCase(); + + if (algoName == "HILLIER") { + pho = new Hillier(par, *icube); + } + else if (algoName == "EXPONENTIAL") { + pho = new Exponential(par, *icube); + } + else { + string msg = " Algorithm Name [" + algoName + "] not recognized."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + pho->SetMinimumPhaseAngle(ui.GetDouble ("MINPHASE")); + pho->SetMaximumPhaseAngle(ui.GetDouble ("MAXPHASE")); + pho->SetMinimumEmissionAngle(ui.GetDouble ("MINEMISSION")); + pho->SetMaximumEmissionAngle(ui.GetDouble ("MAXEMISSION")); + pho->SetMinimumIncidenceAngle(ui.GetDouble ("MININCIDENCE")); + pho->SetMaximumIncidenceAngle(ui.GetDouble ("MAXINCIDENCE")); + + // Start the processing + p.StartProcess(phoCal); + + PvlGroup photo("Photometry"); + pho->Report(photo); + ocube->PutGroup(photo); + Application::Log(photo); + p.EndProcess(); +} + +/** + * @brief Apply Hillier photometric correction + * + * Short function dispatched for each line to apply the Hillier photometrc + * correction function. + * + * @author kbecker (2/20/2010) + * + * @param in Buffer containing input data + * @param out Buffer of photometrically corrected data + */ +void phoCal ( Buffer &in, Buffer &out ) { + + for (int i = 0; i < in.size(); i++) { + // Don't correct special pixels + if (IsSpecial(in[i])) { + out[i] = in[i]; + } + else { + // Get correction and test for validity + double ph = pho->Compute(in.Line(i), in.Sample(i), in.Band(i)); + out[i] = (IsSpecial(ph) ? Null : in[i] * ph); + } + } + + return; +} + diff --git a/isis/src/lro/apps/lrowacpho/lrowacpho.xml b/isis/src/lro/apps/lrowacpho/lrowacpho.xml new file mode 100644 index 0000000000000000000000000000000000000000..56f0ed45a6338af952018be06cc97666f57fd82c --- /dev/null +++ b/isis/src/lro/apps/lrowacpho/lrowacpho.xml @@ -0,0 +1,323 @@ + + + + + + Apply Hillier or Exponential photometric correction to multiband cubes + + + +

    + phohillier implements a photometric correction based upon a paper + titled "Multispectral Photometry of the Moon and Absolute Calibration of + Clementine UV/Vis Camera" by Hillier, Burratti and Hill, published in Icarus + 141, 205-225 (1999). The equation for I/F photometric correction from + this source is: +

    +
    +      I/F = (mu0/(mu+mu0)*F(phase)
    +
    +              where:
    +                  mu0 = cos(incidence)
    +                  mu   = cos(emission)
    +                  F(phase) = b0*e(-b1*phase) + a0 + a1*phase + a2*phase^2 + 
    +                                      a3*phase^3 + a4*phase^4
    +    
    +

    + The equation described there utilizes the Lommel-Seeliger function to + account for scattering dependance on incidence and emission angles. Lunar + Reflectance approximately follows this function and this is the dependence + expected for signly scattered light. Thus is should be a good + approximation for dark objects such as the Moon where singly scattered + light dominates reflectance. The phase function is a fourth order + polynomial with an exponential term to better account for opposition + surge. +

    +

    + This application provides features that allow multiband cubes to be + photometrically corrected with a properly formatted PVL input file much + like that of ISIS program photomet. This application restricts + much of the options available to the more sophiscated photomet + application. Below is an example input parameter file for this + application: +

    +
    +Object = NormalizationModel 
    +  Group = Algorithm 
    +    Name = Albedo 
    +    PhotoModel = Hillier
    +    Incref=30.0
    +    Emaref=0.0
    +    Pharef=30.0
    +  EndGroup 
    +EndObject 
    +
    +Object = PhotometricModel 
    +  HillierUnits = Degrees
    +  Group = Algorithm
    +    Name = Hillier
    +    FilterName = "Filter1"
    +    BandBinCenter = 100.1
    +    B0 = 0.0432753
    +    B1 = 0.0644091
    +    A0 = -0.0207532
    +    A1 = 0.00165219
    +    A2 = -3.94007e-05
    +    A3  = 4.19325e-07
    +    A4 = -1.69163e-09
    +  EndGroup
    +
    +  Group = Algorithm
    +    Name = Hillier
    +    FilterName = "Filter2"
    +    BandBinCenter = 112.5
    +    B0 = 0.0332283
    +    B1 = 0.00667452
    +    A0 = -0.0258405
    +    A1 = -9.04379e-05
    +    A2 = 7.59709e-06
    +    A3 = -1.06395e-07
    +    A4 = 5.18268e-10
    +  EndGroup
    +
    +  Group = Algorithm
    +    Name = Hillier
    +    FilterName = "Filter8"
    +    BandBinCenter = 545.3
    +    BandBinCenterTolerance = 1.0E-2
    +    B0 = 0.0347020
    +    B1 = 0.0211712
    +    A0 = -0.0244440
    +    A1 = 0.000388924
    +    A2 = 4.72860e-07
    +    A3 = -5.00731e-08
    +    A4 = 3.07309e-10
    +  EndGroup
    +EndObject
    +  
    +

    + The NormalizationModel object will (currently) always apply an Albedo + normalization. The value of the Name parameter is ignored here. Also + ignored is the value if PhotoModel as it is always "Hillier". The Incref, + Emaref and Pharef are the incidence, emission and phase angles to be used + as the photometric standard. It will be used to normalize the photometric + correction parameter to these angles. The equation used to create the + photometrically corrected I/F dn is: +

    +
    +          odn = idn * (phostd  / ph)
    +         
    +              where phostd is the Hillier photometry at the given Incref, 
    +                                     Emaref and Pharef angles
    +                         ph        is the photometric correction for the 
    +                                     incidence, emission and phase at each pixel
    +      
    +

    + In the above example, parameters B0-B1 and A0-A4 are the parameters for + the Hillier equation. Additional parameters area needed in order to apply + a specific set of parameters in an Algorithm group to selected bands. The + set of parameters, B0-B1, A0-A4, within an Algorithm group are applied to + a band if (ABS(Center-BandBinCenter) <= ABS(BandBinCenterTolerance)). + The "Center" parameter in the above equality comes from the Center keyword + in the BandBin group of the input cube file specified in the FROM + parameter. This keyword must exist in the input cube or an error is + generated and the program aborts. BandBinCenter and + BandBinCenterTolerance are contained in each Algorithm group. Only + BandBinCenter is required. If BandBinCenterTolerance is not present in an + Algorithm group a value of 1.0E-6 is used. All input bands in the FROM + file must be matched to at least one of the Algorithm parameters otherwise + an error is generated and the application is aborted. +

    +

    + The parameter HillierUnits is provided to specify if the phase angle is in + units of degrees or radians. It does not have to exist in any group or + even in the top Object section. If it does not exist, "Radians" is the + default. +

    +

    + An additional feature of the PVL structure is that any keyword that exists + in the Object section of the PhotometricModel Object is propagated to each + Algorithm group when it is read in unless the keyword already exists in + the Algorithm group. If a keyword exists in both the PhotometricModel + object and an Algorithm group, the keyword in the Algorithm group has + precedence. +

    +

    + Below is an example of a small PVL file that will process all bands that + have a center wavelength of 100.0 to 900.0 (units do not matter as long as + the PVL ALgorithm groups contain the same units as the BandBin Center + keyword in the input cube file). The units of phase is provided in + Radians for this particular example and is overridden from the keyword in + the PhotometricModel object: +

    +
    +Object = NormalizationModel 
    +  Group = Algorithm 
    +    Name = Albedo 
    +    PhotoModel = Hillier
    +    Incref=30.0
    +    Emaref=0.0
    +    Pharef=30.0
    +  EndGroup 
    +EndObject 
    +      
    +Object = PhotometricModel 
    +  HillierUnits = Degrees
    +  Group = Algorithm
    +    Name = Hillier
    +    FilterName = "AllFilters"
    +    BandBinCenter = 500.0
    +    BandBinCenterTolerance = 400.0
    +    HillierUnits = Radians
    +    B0 = 0.0347020
    +    B1 = 0.0211712
    +    A0 = -0.0244440
    +    A1 = 0.000388924
    +    A2 = 4.72860e-07
    +    A3 = -5.00731e-08
    +    A4 = 3.07309e-10
    +  EndGroup
    +EndObject      
    +    
    +

    + Additional consequences of the photometric correction processing is any + incidence angle greater than i90 degrees is set to the ISIS special Null + pixel value. And, of course, any ISIS special pixel encountered on input + is propagated to the output TO file without modification. +

    +
    + + + + Original version. + + + + + Radiometric and Photometric Correction + Cameras + + + + + + cube + input + + Input cube + + + Use this parameter to select the input filename. + + + *.cub + + + + + cube + real + output + + Output cube + + + This file will contain the photometrically corrected image data after + being corrected by with Hillier algorithm. + + + + + filename + input + + Pvl file + + + This file will contain the parameters B0-B1, A0-A4 to use when + applying the Hellier photometric correction. See the main program + documentation for a full description. + + *.pvl + + + + + + double + 0.0 + Minimum phase angle to trim + + Pixels which have a phase angle less than this value will be + trimmed. + + 0.0 + 180.0 + MAXPHASE + + + double + 180.0 + Maximum phase angle to trim + + Pixels which have a phase angle greater than this value will be + trimmed. + + 0.0 + 180.0 + MINPHASE + + + + double + 0.0 + Minimum emission angle to trim + + Pixels which have an emission angle less than this value will be + trimmed. + + 0.0 + 90.0 + MAXEMISSION + + + 90.0 + double + Maximum emission angle to trim + + Pixels which have a emission angle greater than this value will be + trimmed. + + 0.0 + 90.0 + MINEMISSION + + + + double + 0.0 + Minimum incidence angle to trim + + Pixels which have an incidence angle less than this value will be + trimmed. + + 0.0 + 180.0 + MAXINCIDENCE + + + double + 90.0 + Maximum incidence angle to trim + + Pixels which have a incidence angle greater than this value will be + trimmed. + + 0.0 + 180.0 + MININCIDENCE + + + + +
    diff --git a/isis/src/lro/apps/lrowacpho/tsts/Makefile b/isis/src/lro/apps/lrowacpho/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/lro/apps/lrowacpho/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/lro/apps/mrf2isis/Makefile b/isis/src/lro/apps/mrf2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/lro/apps/mrf2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/lro/apps/mrf2isis/mrf2isis.cpp b/isis/src/lro/apps/mrf2isis/mrf2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dbb1cedb63933294c153453c22325c8564f5a73e --- /dev/null +++ b/isis/src/lro/apps/mrf2isis/mrf2isis.cpp @@ -0,0 +1,159 @@ +#include "Isis.h" + +#include +#include + +#include "ProcessImportPds.h" + +#include "UserInterface.h" +#include "Filename.h" + +using namespace std; +using namespace Isis; + +void IsisMain () +{ + ProcessImportPds p; + Pvl label; + UserInterface &ui = Application::GetUserInterface(); + + string labelFile = ui.GetFilename("FROM"); + Filename inFile = ui.GetFilename("FROM"); + iString id; + Pvl lab(inFile.Expanded()); + + try { + id = (string) lab.FindKeyword ("DATA_SET_ID"); + } + catch (iException &e) { + string msg = "Unable to read [DATA_SET_ID] from input file [" + + inFile.Expanded() + "]"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + id.ConvertWhiteSpace(); + id.Compress(); + id.Trim(" "); + if (id != "CHAN1-L-MRFFR-5-CDR-MAP-V1.0" && id != "CHAN1-L-MRFFR-4-CDR-V1.0" && + id != "CH1-ORB-L-MRFFR-4-CDR-V1.0" && id != "CH1-ORB-L-MRFFR-5-CDR-MAP-V1.0" && + id != "CH1-ORB-L-MRFFR-5-CDR-MOSAIC-V1.0" && + id != "LRO-L-MRFLRO-3-CDR-V1.0" && id != "LRO-L-MRFLRO-5-CDR-MAP-V1.0" && + id != "LRO-L-MRFLRO-4-CDR-V1.0" && id != "LRO-L-MRFLRO-5-CDR-MOSAIC-V1.0") { + string msg = "Input file [" + inFile.Expanded() + "] does not appear to be " + + "in CHANDRAYAAN-1 MINI-RF FORERUNNER level 1 or level 2 format " + + "or in LUNAR RECONNAISSANCE ORBITER MINI-RF LRO level 1 or " + + "level 2 format. " + + "DATA_SET_ID is [" + id + "]"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + p.SetPdsFile (labelFile, "", label); + Cube *outcube = p.SetOutputCube ("TO"); + + iString bandorder; + bandorder = (string) lab.FindObject("IMAGE").FindKeyword("BAND_STORAGE_TYPE"); + bandorder.UpCase(); + if (bandorder == "BAND_SEQUENTIAL") { + p.SetOrganization(Isis::ProcessImport::BSQ); + } else if (bandorder == "SAMPLE_INTERLEAVED") { + p.SetOrganization(Isis::ProcessImport::BIP); + } else if (bandorder == "LINE_INTERLEAVED") { + p.SetOrganization(Isis::ProcessImport::BIL); + } else { + string msg = "Input file [" + inFile.Expanded() + "] has an invalid " + + "band storage type. BAND_STORAGE_TYPE is [" + bandorder + "]"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + p.StartProcess (); + + // Get the mapping labels + Pvl otherLabels; + p.TranslatePdsProjection(otherLabels); + + // Get the directory where the MiniRF level 2 translation tables are. + PvlGroup dataDir (Preference::Preferences().FindGroup("DataDirectory")); + iString transDir = (string) dataDir["Lro"] + "/translations/"; + + if (id == "CHAN1-L-MRFFR-5-CDR-MAP-V1.0" || id == "LRO-L-MRFLRO-5-CDR-MAP-V1.0") { + // Translate the BandBin group + Filename transFile (transDir + "mrflev2BandBin.trn"); + PvlTranslationManager bandBinXlater (label, transFile.Expanded()); + bandBinXlater.Auto(otherLabels); + + // Translate the Archive group + transFile = transDir + "mrflev2Archive.trn"; + PvlTranslationManager archiveXlater (label, transFile.Expanded()); + archiveXlater.Auto(otherLabels); + + // Write the BandBin, Archive, and Mapping groups to the output cube label + outcube->PutGroup(otherLabels.FindGroup("BandBin")); + outcube->PutGroup(otherLabels.FindGroup("Mapping")); + outcube->PutGroup(otherLabels.FindGroup("Archive")); + } else { + // Translate the BandBin group + Filename transFile (transDir + "mrflev1BandBin.trn"); + PvlTranslationManager bandBinXlater (label, transFile.Expanded()); + bandBinXlater.Auto(otherLabels); + + // Translate the Archive group + transFile = transDir + "mrflev1Archive.trn"; + PvlTranslationManager archiveXlater (label, transFile.Expanded()); + archiveXlater.Auto(otherLabels); + + // Translate the Instrument group + transFile = transDir + "mrflev1Instrument.trn"; + PvlTranslationManager instrumentXlater (label, transFile.Expanded()); + instrumentXlater.Auto(otherLabels); + + // Translate the Image group + transFile = transDir + "mrflev1Image.trn"; + PvlTranslationManager imageXlater (label, transFile.Expanded()); + imageXlater.Auto(otherLabels); + + // Write the BandBin, Archive, Instrument, and ImageInfo groups + // to the output cube label + outcube->PutGroup(otherLabels.FindGroup("BandBin")); + outcube->PutGroup(otherLabels.FindGroup("Archive")); + outcube->PutGroup(otherLabels.FindGroup("Instrument")); + outcube->PutGroup(otherLabels.FindGroup("ImageInfo")); + + // Make sure the ScaledPixelHeight and ScaledPixelWidth are the same + PvlGroup &instGrp(otherLabels.FindGroup("Instrument", Pvl::Traverse)); + if (instGrp.HasKeyword("ScaledPixelHeight") && + instGrp.HasKeyword("ScaledPixelWidth")) { + double pheight = instGrp["ScaledPixelHeight"]; + double pwidth = instGrp["ScaledPixelWidth"]; + if (pheight != pwidth) { + string msg = "Input file [" + inFile.Expanded() + "] does not have valid " + + "ScaledPixelHeight and ScaledPixelWidth values. These values " + + "must be equivalent or the image is considered to be invalid."; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + } + + // Set the frequency based on the InstrumentModeId. This has to + // be done manually, because the frequency information was not + // put in the PDS labels. + if (!(instGrp.HasKeyword("Frequency"))) { + string instmodeid = instGrp["InstrumentModeId"]; + double frequency; + if (instmodeid.compare(0,10,"BASELINE_S") == 0 || + instmodeid.compare(0,6,"ZOOM_S") == 0) { + frequency = 2379305000.0; + } else { // BASELINE_X or ZOOM_X + frequency = 7140000000.0; + } + instGrp.AddKeyword(PvlKeyword("Frequency",frequency)); + outcube->PutGroup(instGrp); + } + PvlGroup kerns("Kernels"); + if (id.compare(0,5,"CHAN1") == 0 || id.compare(0,3,"CH1") == 0) { + kerns += PvlKeyword("NaifFrameCode",-86001); + } else { // LRO + kerns += PvlKeyword("NaifFrameCode",-85700); + } + outcube->PutGroup(kerns); + } + + p.EndProcess (); +} diff --git a/isis/src/lro/apps/mrf2isis/mrf2isis.xml b/isis/src/lro/apps/mrf2isis/mrf2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..a35b459da1a81e4ec78fedce6c2d307dc14ecef1 --- /dev/null +++ b/isis/src/lro/apps/mrf2isis/mrf2isis.xml @@ -0,0 +1,76 @@ + + + + + Import PDS formatted MiniRF level 1 or level 2 image cube into Isis format cube + + + This program will import a PDS formatted Chandrayaan-1 Mini-RF Forerunner level 1 or + level 2 image into an Isis cube. It will also import a PDS formatted Lunar Reconnaissance + Orbiter Mini-RF LRO level 1 or level 2 image into an Isis cube. + + + + + Original version + + + Removed references to CubeInfo + + + Added a check to make sure the ScaledPixelHeight and + ScaledPixelWidth are equal; hard code the frequency + value in the labels based on the instrument mode id - + this is done because the PDS labels are lacking in + this information; add Kernels group to the labels + + + Added a check to see if the Frequency keyword exists + in the labels. If it doesn't exist, then mrf2isis + will put a Frequency keyword in the labels. + + + Made changes so that program would run on files that + were created by the mrf2pds program. + + + + + Import and Export + + + + + + filename + input + + Input PDS formatted MiniRF level 1 or level 2 file + + + Use this parameter to select the MiniRF (Chandrayaan-1 + or LRO) level 1 or level 2 filename. This file must + contain the PDS labels. + + + *.lbl *.LBL + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + + diff --git a/isis/src/lro/apps/mrf2isis/tsts/Makefile b/isis/src/lro/apps/mrf2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/lro/apps/mrf2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/lro/apps/mrf2isis/tsts/level1/Makefile b/isis/src/lro/apps/mrf2isis/tsts/level1/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0b56386f1b5e4a5f6c723e54117176f4e6c3f960 --- /dev/null +++ b/isis/src/lro/apps/mrf2isis/tsts/level1/Makefile @@ -0,0 +1,9 @@ +APPNAME = mrf2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/FSL_CDR_LV1_00200_1Q.LBL \ + to=$(OUTPUT)/FSL_CDR_LV1_00200_1Q.cub > /dev/null; + $(APPNAME) from=$(INPUT)/LSL_CDR_LV1_00300_1Q.LBL \ + to=$(OUTPUT)/LSL_CDR_LV1_00300_1Q.cub > /dev/null; diff --git a/isis/src/lro/apps/mrf2isis/tsts/level2/Makefile b/isis/src/lro/apps/mrf2isis/tsts/level2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2e2d9e1718f2a0dde3fab56004870c83e3837477 --- /dev/null +++ b/isis/src/lro/apps/mrf2isis/tsts/level2/Makefile @@ -0,0 +1,9 @@ +APPNAME = mrf2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/FSL_CDR_LV2_00200_1Q.LBL \ + to=$(OUTPUT)/FSL_CDR_LV2_00200_1Q.cub > /dev/null; + $(APPNAME) from=$(INPUT)/LSL_CDR_LV2_00300_1Q.LBL \ + to=$(OUTPUT)/LSL_CDR_LV2_00300_1Q.cub > /dev/null; diff --git a/isis/src/lro/apps/mrf2pds/Makefile b/isis/src/lro/apps/mrf2pds/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/lro/apps/mrf2pds/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/lro/apps/mrf2pds/ProcessExportMiniRFLroPds.cpp b/isis/src/lro/apps/mrf2pds/ProcessExportMiniRFLroPds.cpp new file mode 100644 index 0000000000000000000000000000000000000000..729ee6c1f5634a10f516e2350b6fc7b8db9d85d0 --- /dev/null +++ b/isis/src/lro/apps/mrf2pds/ProcessExportMiniRFLroPds.cpp @@ -0,0 +1,87 @@ +/** + * Unless noted otherwise, the portions of Isis written by the + * USGS are public domain. See individual third-party library + * and package descriptions for intellectual property + * information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "Pvl.h" +#include "PvlFormat.h" +#include "iException.h" +#include "iString.h" +#include "Filename.h" +#include "PvlFormatPds.h" +#include "ProcessExportMiniRFLroPds.h" + +using namespace std; + +namespace Isis { + + /** + * Create a standard PDS label for type IMAGE using the mrf + * formatting + * + * @author sprasad (2/1/2010) + */ + Pvl &ProcessExportMiniRFLroPds::StandardPdsLabel(const ProcessExportPds::PdsFileType type) { + p_label = new Pvl; + + p_formatter = new PvlFormatPds("$lro/translations/mrfExportRoot.typ"); + p_label->SetFormat(p_formatter); + p_label->SetTerminator("END"); + + if(type == ProcessExportPds::Image) { + CreateImageLabel(); + } + else { + string msg = "Unsupported PDS output type"; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + return *p_label; + } + + + /** + * Create Image label with mrf formatting + * + * @author sprasad (2/1/2010) + */ + void ProcessExportMiniRFLroPds::CreateImageLabel(void) { + + Pvl &mainPvl = *p_label; + + if(p_exportType == ProcessExportPds::Stream) { + StreamImageRoot(mainPvl); + } + else if(p_exportType == ProcessExportPds::Fixed) { + FixedImageRoot(mainPvl); + } + else { + string msg = "Invalid PDS export type"; + throw Isis::iException::Message(Isis::iException::Programmer, msg, _FILEINFO_); + } + + StandardImageImage(mainPvl); + + // The IMAGE_MAP_PROJECTION group is located in the ROOT for PDS IMAGEs. The + // standard routines will add the IMAGE_MAP_PROJECTION correctly + StandardAllMapping(mainPvl); + mainPvl.GetFormat()->Add("$lro/translations/mrfExportAllMapping.typ"); + } + +} diff --git a/isis/src/lro/apps/mrf2pds/ProcessExportMiniRFLroPds.h b/isis/src/lro/apps/mrf2pds/ProcessExportMiniRFLroPds.h new file mode 100644 index 0000000000000000000000000000000000000000..6e330c0529d230dabc26fe503df4799404a79100 --- /dev/null +++ b/isis/src/lro/apps/mrf2pds/ProcessExportMiniRFLroPds.h @@ -0,0 +1,45 @@ +/** + * Unless noted otherwise, the portions of Isis written by the + * USGS are public domain. See individual third-party library + * and package descriptions for intellectual property + * information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "ProcessExportPds.h" + +namespace Isis { + class PvlFormatPds; + + /** + * @brief Process class for LRO specific PDS image + * + * This class extends the ProcessExportPds class to add Mini RF + * LRO specific PVL. + * + * @history 2009-11-04 Sharmila Prasad - Original version + * @history 2010-03-09 Sharmila Prasad - Changed class name to + * ProcessExportMiniRFLroPds to avoid conflicts with + * functionality of LRO objects + */ + + class ProcessExportMiniRFLroPds : public Isis::ProcessExportPds { + public: + ProcessExportMiniRFLroPds() {}; + ~ProcessExportMiniRFLroPds() {}; + + virtual Pvl &StandardPdsLabel(const ProcessExportPds::PdsFileType type = ProcessExportPds::Image); + virtual void CreateImageLabel(void); + }; +} diff --git a/isis/src/lro/apps/mrf2pds/mrf2pds.cpp b/isis/src/lro/apps/mrf2pds/mrf2pds.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d54a77f86efe5325e86abb05f3c09ff204390f7f --- /dev/null +++ b/isis/src/lro/apps/mrf2pds/mrf2pds.cpp @@ -0,0 +1,460 @@ +#include "Isis.h" +#include "UserInterface.h" +#include "Filename.h" +#include "iException.h" +#include "iString.h" +#include "Pvl.h" +#include "ProcessExportMiniRFLroPds.h" +#include "PvlTranslationManager.h" +#include "OriginalLabel.h" +#include "SerialNumberList.h" +#include "Constants.h" +#include "Statistics.h" +#include "NaifStatus.h" +#include "Spice.h" +#include +#include +#include + +using namespace std; +using namespace Isis; + +void FixLabel(Pvl &pcPdsLbl, bool &pbLevel2); +void GetSourceProductID(std::string psSrcListFile, std::string psSrcType, Pvl &pcPdsLabel); +void GetUserLabel(std::string psUserLbl, Pvl &pdsLabel, bool pbLevel2); + +static unsigned int iCheckSum = 0; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + Filename inFile = ui.GetFilename("FROM"); + + // Set the processing object + ProcessExportMiniRFLroPds cProcess; + + // Setup the input cube + Cube *cInCube = cProcess.SetInputCube("FROM"); + Pvl *cInLabel = cInCube->Label(); + + // Get the output label file + Filename outFile(ui.GetFilename("TO", "lbl")); + string outFilename(outFile.Expanded()); + + cProcess.SetDetached(true, outFilename); + + cProcess.SetExportType(ProcessExportPds::Fixed); + + //Set the resolution to Kilometers + cProcess.SetPdsResolution(ProcessExportPds::Kilometer); + + // 32bit + cProcess.SetOutputType(Isis::Real); + cProcess.SetOutputNull(Isis::NULL4); + cProcess.SetOutputLrs(Isis::LOW_REPR_SAT4); + cProcess.SetOutputLis(Isis::LOW_INSTR_SAT4); + cProcess.SetOutputHrs(Isis::HIGH_REPR_SAT4); + cProcess.SetOutputHis(Isis::HIGH_INSTR_SAT4); + cProcess.SetOutputRange(-DBL_MAX, DBL_MAX); + + cProcess.SetOutputEndian(Isis::Msb); + + // Turn off Keywords + cProcess.ForceScalingFactor(false); + cProcess.ForceSampleBitMask(false); + cProcess.ForceCoreNull(false); + cProcess.ForceCoreLrs(false); + cProcess.ForceCoreLis(false); + cProcess.ForceCoreHrs(false); + cProcess.ForceCoreHis(false); + + // Standard label Translation + Pvl &pdsLabel = cProcess.StandardPdsLabel(ProcessExportPds::Image); + + // bLevel => Level 2 = True, Level 3 = False + bool bLevel2 = cInCube->HasGroup("Instrument"); + + // Translate the keywords from the original EDR PDS label that go in + // this RDR PDS label for Level2 images only + if(bLevel2) { + OriginalLabel cOriginalBlob; + cInCube->Read(cOriginalBlob); + Pvl cOrigLabel; + PvlObject cOrigLabelObj = cOriginalBlob.ReturnLabels(); + cOrigLabelObj.SetName("OriginalLabelObject"); + cOrigLabel.AddObject(cOrigLabelObj); + + // Translates the ISIS labels along with the original EDR labels + cOrigLabel.AddObject(*(cInCube->Label())); + PvlTranslationManager cCubeLabel2(cOrigLabel, "$lro/translations/mrfExportOrigLabel.trn"); + cCubeLabel2.Auto(pdsLabel); + + + if(cInLabel->FindObject("IsisCube").FindGroup("Instrument").HasKeyword("MissionName")) { + PvlKeyword &cKeyMissionName = cInLabel->FindObject("IsisCube").FindGroup("Instrument").FindKeyword("MissionName"); + size_t sFound = cKeyMissionName[0].find("CHANDRAYAAN"); + if(sFound != string::npos) { + cCubeLabel2 = PvlTranslationManager(cOrigLabel, "$lro/translations/mrfExportOrigLabelCH1.trn"); + cCubeLabel2.Auto(pdsLabel); + } + else { + cCubeLabel2 = PvlTranslationManager(cOrigLabel, "$lro/translations/mrfExportOrigLabelLRO.trn"); + cCubeLabel2.Auto(pdsLabel); + } + } + } + else { //Level3 - add Band_Name keyword + PvlGroup &cBandBinGrp = cInCube->GetGroup("BandBin"); + PvlKeyword cKeyBandBin = PvlKeyword("BAND_NAME"); + PvlKeyword cKeyInBandBin; + if(cBandBinGrp.HasKeyword("OriginalBand")) { + cKeyInBandBin = cBandBinGrp.FindKeyword("OriginalBand"); + } + else if(cBandBinGrp.HasKeyword("FilterName")) { + cKeyInBandBin = cBandBinGrp.FindKeyword("FilterName"); + } + for(int i = 0; i < cKeyInBandBin.Size(); i++) { + cKeyBandBin += cKeyInBandBin[i]; + } + PvlObject &cImageObject(pdsLabel.FindObject("IMAGE")); + cImageObject += cKeyBandBin; + } + + // Get the Sources Product ID if entered for Level2 only as per example + if(ui.WasEntered("SRC") && bLevel2) { + std::string sSrcFile = ui.GetFilename("SRC"); + std::string sSrcType = ui.GetString("TYPE"); + GetSourceProductID(sSrcFile, sSrcType, pdsLabel); + } + + // Get the User defined Labels + if(ui.WasEntered("USERLBL")) { + std::string sUserLbl = ui.GetFilename("USERLBL"); + GetUserLabel(sUserLbl, pdsLabel, bLevel2); + } + + // Calculate CheckSum + Statistics *cStats = cInCube->Statistics(); + iCheckSum = (unsigned int)cStats->Sum(); + + FixLabel(pdsLabel, bLevel2); + + // Add an output format template to the PDS PVL + // Distinguish betweeen Level 2 and 3 images by calling the camera() + // function as only non mosaic images(Level2) have a camera + if(bLevel2) { + pdsLabel.SetFormatTemplate("$lro/translations/mrfPdsLevel2.pft"); + } + else { + pdsLabel.SetFormatTemplate("$lro/translations/mrfPdsLevel3.pft"); + } + + size_t iFound = outFilename.find(".lbl"); + outFilename.replace(iFound, 4, ".img"); + ofstream oCube(outFilename.c_str()); + cProcess.OutputDetatchedLabel(); + //cProcess.OutputLabel(oCube); + cProcess.StartProcess(oCube); + oCube.close(); + cProcess.EndProcess(); +} + +/** + * Reads the file with User input in PVL format and substitutes + * non empty keyvalues with the existing values in the output + * PVL. + * + * @author sprasad (11/10/2009) + * + * @param psUserLbl - User Label File + * @param pcPdsLbl - Output Pds PVL + */ +void GetUserLabel(std::string psUserLbl, Pvl &pcPdsLbl, bool pbLevel2) { + Pvl cUsrPvl(psUserLbl); + + /*if (pbLevel2 && + (cUsrPvl.HasKeyword("SPACECRAFT_CLOCK_START_COUNT") || + cUsrPvl.HasKeyword("SPACECRAFT_CLOCK_STOP_COUNT") || + cUsrPvl.HasKeyword("START_TIME") || + cUsrPvl.HasKeyword("STOP_TIME"))) { + + std::string msg = "Unsupported User defined keywords for Level2"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + }*/ + + // Add all the keywords in the root + for(int j = 0; j < cUsrPvl.Keywords(); j++) { + if(pcPdsLbl.HasKeyword(cUsrPvl[j].Name())) { + PvlKeyword &cKey = pcPdsLbl.FindKeyword(cUsrPvl[j].Name()); + cKey.Clear(); + cKey.SetValue(cUsrPvl[j][0]); + } + else + pcPdsLbl.AddKeyword(cUsrPvl[j]); + } + + // Add keywords in the objects + for(int j = 0; j < cUsrPvl.Objects(); j++) { + PvlObject cUsrObject = cUsrPvl.Object(j); + if(pcPdsLbl.HasObject(cUsrObject.Name())) { + PvlObject &cObject = pcPdsLbl.FindObject(cUsrObject.Name()); + for(int k = 0; k < cUsrObject.Keywords(); k++) { + PvlKeyword cUsrKeyword = cUsrObject[k]; + if(cObject.HasKeyword(cUsrKeyword.Name())) { + PvlKeyword &cKey = cObject.FindKeyword(cUsrKeyword.Name()); + cKey.Clear(); + cKey.SetValue(cUsrKeyword[0]); + } + else { + cObject.AddKeyword(cUsrKeyword); + } + } + } + } +} + +/** + * Read the input file containing source id's for a mosaic and + * write into the output PVL with SOURCE_PRODUCT_ID keyname + * + * @author sprasad (11/10/2009) + * + * @param psSrcListFile - File containing source id's + * @param pcPdsLbl - Output PVL + */ +void GetSourceProductID(std::string psSrcListFile, std::string psSrcType, Pvl &pcPdsLbl) { + PvlKeyword cKeySrcPrdId; + + if(pcPdsLbl.HasKeyword("SOURCE_PRODUCT_ID")) { + pcPdsLbl.DeleteKeyword("SOURCE_PRODUCT_ID"); + } + + cKeySrcPrdId.SetName("SOURCE_PRODUCT_ID"); + + // List File name + if(psSrcType == "LIST") { + SerialNumberList cSnl = psSrcListFile; + for(int i = 0; i < cSnl.Size(); i++) { + cKeySrcPrdId += cSnl.SerialNumber(i); + } + } + // ID's - add directly to the PvlKeyword + else { + ifstream inIdFile; + inIdFile.open(psSrcListFile.c_str(), std::ios::in); + char buff[501]; + inIdFile.getline(buff, 500); + while(!inIdFile.eof()) { + if(buff[0] != '\n' && buff[0] != '\0') { + cKeySrcPrdId += buff; + } + inIdFile.getline(buff, 500); + } + inIdFile.close(); + } + pcPdsLbl += cKeySrcPrdId; +} + +/** + * Update, Add , Delete the labels in the output PVL to + * match the required Mini RF PDS Label + * + * @author sprasad (11/10/2009) + * + * @param pcPdsLbl - Output PVL + */ +void FixLabel(Pvl &pcPdsLbl, bool &pbLevel2) { + // Level 3 + if(!pbLevel2) { + if(pcPdsLbl.HasKeyword("LINE_EXPOSURE_DURATION")) { + pcPdsLbl.DeleteKeyword("LINE_EXPOSURE_DURATION"); + } + if(pcPdsLbl.HasKeyword("ORBIT_NUMBER")) { + pcPdsLbl.DeleteKeyword("ORBIT_NUMBER"); + } + if(pcPdsLbl.HasKeyword("INCIDENCE_ANGLE")) { + pcPdsLbl.DeleteKeyword("INCIDENCE_ANGLE"); + } + if(pcPdsLbl.HasKeyword("INSTRUMENT_MODE_ID")) { + pcPdsLbl.DeleteKeyword("INSTRUMENT_MODE_ID"); + } + if(pcPdsLbl.HasKeyword("INSTRUMENT_MODE_DESC")) { + pcPdsLbl.DeleteKeyword("INSTRUMENT_MODE_DESC"); + } + if(pcPdsLbl.HasKeyword("LOOK_DIRECTION")) { + pcPdsLbl.DeleteKeyword("LOOK_DIRECTION"); + } + } + + // Additional keywords and update existing keywords + if(pcPdsLbl.HasKeyword("LABEL_RECORDS")) { + pcPdsLbl.DeleteKeyword("LABEL_RECORDS"); + } + + if(!pcPdsLbl.HasKeyword("PRODUCER_FULL_NAME")) { + PvlKeyword cKeyPrdFullName = PvlKeyword("PRODUCER_FULL_NAME", "USGS AstroGeology Flagstaff"); + pcPdsLbl += cKeyPrdFullName; + } + + if(!pcPdsLbl.HasKeyword("PRODUCER_INSTITUTION_NAME")) { + PvlKeyword cKeyPrdInstName = PvlKeyword("PRODUCER_INSTITUTION_NAME", "USGS AstroGeology"); + pcPdsLbl += cKeyPrdInstName; + } + + if(!pcPdsLbl.HasKeyword("MISSION_NAME")) { + PvlKeyword cKeyMissionName = PvlKeyword("MISSION_NAME", "LUNAR RECONNAISSANCE ORBITER"); + pcPdsLbl += cKeyMissionName; + } + + if(!pcPdsLbl.HasKeyword("PRODUCER_ID")) { + PvlKeyword cKeyPrdID = PvlKeyword("PRODUCER_ID", "USGS"); + pcPdsLbl += cKeyPrdID; + } + + time_t startTime = time(NULL); + struct tm *tmbuf = gmtime(&startTime); + char timestr[80]; + strftime(timestr, 80, "%Y-%m-%dT%H:%M:%S", tmbuf); + PvlKeyword cKeyPrdCreationTime("PRODUCT_CREATION_TIME", timestr); + pcPdsLbl += cKeyPrdCreationTime; + + PvlKeyword cKeySoftware("SOFTWARE_NAME", "ISIS3"); + pcPdsLbl += cKeySoftware; + + PvlKeyword cKeySoftwareVersion("SOFTWARE_VERSION_ID", version); + pcPdsLbl += cKeySoftwareVersion; + + // Specific to IMAGE Object + PvlObject &cImageObject(pcPdsLbl.FindObject("IMAGE")); + if(cImageObject.HasKeyword("OFFSET")) { + cImageObject.DeleteKeyword("OFFSET"); + } + + // Update SAMPLE_TYPE from "IEEE_" to "PC_" + if(cImageObject.HasKeyword("SAMPLE_TYPE")) { + PvlKeyword &cSampleType = cImageObject.FindKeyword("SAMPLE_TYPE"); + string sVal = cSampleType[0]; + int iFound = sVal.find('_'); + if(iFound >= 0) { + sVal.replace(0, iFound, "PC"); + cSampleType.SetValue(sVal); + } + } + + if(pbLevel2) { + char buff[62]; + sprintf(buff, "%d", iCheckSum); + PvlKeyword cKeyChkSum("CHECKSUM", buff); + cImageObject += cKeyChkSum; + } + + // Projection object + PvlObject &cProjectionObject(pcPdsLbl.FindObject("IMAGE_MAP_PROJECTION")); + if(cProjectionObject.HasKeyword("PROJECTION_LATITUDE_TYPE")) { + cProjectionObject.DeleteKeyword("PROJECTION_LATITUDE_TYPE"); + } + + if(!cProjectionObject.HasKeyword("COORDINATE_SYSTEM_TYPE")) { + PvlKeyword cKeyCordSysType = PvlKeyword("COORDINATE_SYSTEM_TYPE", " "); + cProjectionObject += cKeyCordSysType; + } + + if(cProjectionObject.HasKeyword("MAP_PROJECTION_TYPE")) { + PvlKeyword cKeyPrjType = cProjectionObject.FindKeyword("MAP_PROJECTION_TYPE"); + if(cKeyPrjType[0] == "OBLIQUE CYLINDRICAL") { + PvlKeyword &cKeyCenLon = cProjectionObject.FindKeyword("CENTER_LONGITUDE"); + cKeyCenLon.SetValue("0.0 "); + PvlKeyword &cKeyCenLat = cProjectionObject.FindKeyword("CENTER_LATITUDE"); + cKeyCenLat.SetValue("0.0 "); + + if(pbLevel2) { + // Get the X,Y,Z values from Proj X Axis Vector + PvlKeyword cKeyObXProj = cProjectionObject.FindKeyword("OBLIQUE_PROJ_X_AXIS_VECTOR"); + double x, y, z; + x = iString(cKeyObXProj[0]).ToDouble(); + y = iString(cKeyObXProj[1]).ToDouble(); + z = iString(cKeyObXProj[2]).ToDouble(); + + // Calculate Reference Latitude and Longitude + // angle in degrees = angle in radians * 180 / Pi + /*double dRad,dLon,dLat; + reclat_c(xAxis,&dRad,&dLon,&dLat); + dLat = dLat * 180.0 / Isis::PI; + dLon = dLon * 180.0 / Isis::PI; + */ + + double dLon, dLat; + dLon = atan(y / x) * (180 / Isis::PI); + dLat = atan(z / (sqrt(pow(x, 2) + pow(y, 2)))) * (180 / Isis::PI); + + PvlKeyword cKeyRefLon("REFERENCE_LONGITUDE"); + iString iStr(dLon, 6); + iStr += " "; + cKeyRefLon.SetValue((std::string)iStr); + cProjectionObject.AddKeyword(cKeyRefLon); + + PvlKeyword cKeyRefLat("REFERENCE_LATITUDE"); + iStr = iString(dLat, 6); + iStr += " "; + cKeyRefLat.SetValue(iStr); + cProjectionObject.AddKeyword(cKeyRefLat); + } + else { // Level3 Projection object + if(cProjectionObject.HasKeyword("OBLIQUE_PROJ_POLE_LATITUDE")) { + cProjectionObject.DeleteKeyword("OBLIQUE_PROJ_POLE_LATITUDE"); + } + if(cProjectionObject.HasKeyword("OBLIQUE_PROJ_POLE_LONGITUDE")) { + cProjectionObject.DeleteKeyword("OBLIQUE_PROJ_POLE_LONGITUDE"); + } + if(cProjectionObject.HasKeyword("OBLIQUE_PROJ_POLE_ROTATION")) { + cProjectionObject.DeleteKeyword("OBLIQUE_PROJ_POLE_ROTATION"); + } + if(cProjectionObject.HasKeyword("OBLIQUE_PROJ_X_AXIS_VECTOR")) { + cProjectionObject.DeleteKeyword("OBLIQUE_PROJ_X_AXIS_VECTOR"); + } + if(cProjectionObject.HasKeyword("OBLIQUE_PROJ_Y_AXIS_VECTOR")) { + cProjectionObject.DeleteKeyword("OBLIQUE_PROJ_Y_AXIS_VECTOR"); + } + if(cProjectionObject.HasKeyword("OBLIQUE_PROJ_Z_AXIS_VECTOR")) { + cProjectionObject.DeleteKeyword("OBLIQUE_PROJ_Z_AXIS_VECTOR"); + } + } + } + } + + PvlKeyword cKeyDataSetMapProj("^DATA_SET_MAP_PROJECTION", "DSMAP.CAT"); + cProjectionObject += cKeyDataSetMapProj; + + if(cProjectionObject.HasKeyword("LINE_PROJECTION_OFFSET")) { + PvlKeyword &cLineProjOffset = cProjectionObject.FindKeyword("LINE_PROJECTION_OFFSET"); + string sVal = cLineProjOffset[0]; + int iFound = sVal.find('<'); + if(iFound >= 0) { + string::iterator it; + it = sVal.begin() + iFound; + sVal.erase(it); + cLineProjOffset.SetValue(sVal); + } + } + + if(cProjectionObject.HasKeyword("SAMPLE_PROJECTION_OFFSET")) { + PvlKeyword &cSampleProjOffset = cProjectionObject.FindKeyword("SAMPLE_PROJECTION_OFFSET"); + string sVal = cSampleProjOffset[0]; + int iFound = sVal.find('<'); + if(iFound >= 0) { + string::iterator it; + it = sVal.begin() + iFound; + sVal.erase(it); + cSampleProjOffset.SetValue(sVal); + } + } + + if(cProjectionObject.HasKeyword("MAP_SCALE")) { + PvlKeyword &cMapScale = cProjectionObject.FindKeyword("MAP_SCALE"); + string sVal = cMapScale[0]; + int iFound = sVal.find("EL"); + if(iFound >= 0) { + sVal.erase(iFound, 2); + cMapScale.SetValue(sVal); + } + } +} diff --git a/isis/src/lro/apps/mrf2pds/mrf2pds.xml b/isis/src/lro/apps/mrf2pds/mrf2pds.xml new file mode 100644 index 0000000000000000000000000000000000000000..37c7244c1d824eaeca9f1d067f97e54b9b28814e --- /dev/null +++ b/isis/src/lro/apps/mrf2pds/mrf2pds.xml @@ -0,0 +1,141 @@ + + + + + Export a Mini-RF isis cube to a pds image + + + This program takes an isis cube of the Mini-RF of levels 2 and 3 and + produces a pds image. Level 2: Caliberated projected Mini-RF isis cube + Level 3: Mosaic isis cube containing 1 or more Level 2 Mini-RF isis + cubes + + + + Original Version + Added Level3 conversion capability + Use class + ProcessExportMiniRFLroPds instead of ProcessExportLroPds with + class name change + + + + Lunar Reconnaissance Orbiter + + + + + + cube + input + Input file + The Mini-RF isis cube to be converted to PDS format + *.cub + + + filename + output + Output cube + Output Mini-RF pds image + *.lbl + + + + + + filename + input + Default + Specify the values for user defined keywords in pvl format + Specify the values for user defined keywords in pvl format + + + +

    +
    + + + + + + + + + + + + + + + + + + +
    Format for Level2 User defined Keywords
    LABEL_REVISION_NOTE=
    DATA_SET_NAME=
    PRODUCER_ID=
    PRODUCER_FULL_NAME=
    PRODUCER_INSTITUTION_NAME=
    MISSION_NAME=
    PRODUCT_ID=
    PRODUCT_VERSION_ID=
    RELEASE_ID=
    START_TIME=
    STOP_TIME=
    SPACECRAFT_CLOCK_START_COUNT=
    SPACECRAFT_CLOCK_STOP_COUNT=
    DESCRIPTION=
    OBJECT=IMAGE
    DESCRIPTION=
    END_OBJECT
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    Format for Level3 User defined Keywords
    LABEL_REVISION_NOTE=
    DATA_SET_ID=
    DATA_SET_NAME=
    PRODUCER_ID=
    PRODUCER_FULL_NAME=
    PRODUCER_INSTITUTION_NAME=
    MISSION_NAME=
    PRODUCT_ID=
    PRODUCT_VERSION_ID=
    RELEASE_ID=
    START_TIME=
    STOP_TIME=
    SPACECRAFT_CLOCK_START_COUNT=
    SPACECRAFT_CLOCK_STOP_COUNT=
    DESCRIPTION=
    OBJECT=IMAGE
    NAME=
    DESCRIPTION=
    END_OBJECT
    OBJECT=IMAGE_MAP_PROJECTION
    COORDINATE_SYSTEM_TYPE =
    END_OBJECT
    +

    +
    + +
    + *.pvl +
    +
    + + + string + + ID + + File with source product Ids or Filenames + + This parameter is used to select whether the source file + has Id's or Filenames + + + + + + + + filename + input + None + File with all the Source Product ID or Filenames + File with all the Source Product IDs or Filenames + *.lis + + +
    +
    + diff --git a/isis/src/lro/apps/mrf2pds/tsts/CH_Lev2/Makefile b/isis/src/lro/apps/mrf2pds/tsts/CH_Lev2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c21dd10c36af9583fc3477c02f7d0d735efa960b --- /dev/null +++ b/isis/src/lro/apps/mrf2pds/tsts/CH_Lev2/Makefile @@ -0,0 +1,21 @@ +APPNAME = mrf2pds +PDS2ISIS= pds2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/FSR_CDR_LV2_01921_0R_Lev2.cub \ + to=$(OUTPUT)/FSR_CDR_LV2_01921_0R_Lev2_OUT \ + userlbl=$(INPUT)/UserLabels.pvl \ + type=list src=$(INPUT)/Src.lis > /dev/null; + + $(PDS2ISIS) from=$(OUTPUT)/FSR_CDR_LV2_01921_0R_Lev2_OUT.lbl \ + image=$(OUTPUT)/FSR_CDR_LV2_01921_0R_Lev2_OUT.img \ + to=$(OUTPUT)/FSR_CDR_LV2_01921_0R_Lev2_OUT.cub > /dev/null; + + $(MV) $(OUTPUT)/FSR_CDR_LV2_01921_0R_Lev2_OUT.lbl $(OUTPUT)/FSR_CDR_LV2_01921_0R_Lev2_OUT.pvl > /dev/null; + + $(RM) $(OUTPUT)/FSR_CDR_LV2_01921_0R_Lev2_OUT.img > /dev/null; + + + diff --git a/isis/src/lro/apps/mrf2pds/tsts/CH_Lev3/Makefile b/isis/src/lro/apps/mrf2pds/tsts/CH_Lev3/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5b17c8490bb4fe9a3471bba59c8e9c4fa77c6132 --- /dev/null +++ b/isis/src/lro/apps/mrf2pds/tsts/CH_Lev3/Makefile @@ -0,0 +1,11 @@ +APPNAME = mrf2pds + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/Level3.cub \ + to=$(OUTPUT)/Level3_OUT \ + userlbl=$(INPUT)/UserLabels.pvl > /dev/null; + + $(MV) $(OUTPUT)/Level3_OUT.lbl $(OUTPUT)/Level3_OUT.pvl > /dev/null; + diff --git a/isis/src/lro/apps/mrf2pds/tsts/Makefile b/isis/src/lro/apps/mrf2pds/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/lro/apps/mrf2pds/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/lro/objs/LroNarrowAngleCamera/Camera.plugin b/isis/src/lro/objs/LroNarrowAngleCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..f7bb8ef445ab7f79f3119e00bb4e5db3550fc924 --- /dev/null +++ b/isis/src/lro/objs/LroNarrowAngleCamera/Camera.plugin @@ -0,0 +1,12 @@ +Group = LUNAR_RECONNAISSANCE_ORBITER/NACL + Version = 1 + Library = LroNarrowAngleCamera + Routine = LroNarrowAngleCameraPlugin +EndGroup + +Group = LUNAR_RECONNAISSANCE_ORBITER/NACR + Version = 1 + Library = LroNarrowAngleCamera + Routine = LroNarrowAngleCameraPlugin +EndGroup + diff --git a/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleCamera.cpp b/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cfd51db7ad29d9a274c32d7b90e57a2a5c44effd --- /dev/null +++ b/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleCamera.cpp @@ -0,0 +1,94 @@ +#include "LroNarrowAngleCamera.h" +#include "iString.h" +#include "iException.h" +#include "LineScanCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "LroNarrowAngleDistortionMap.h" +#include "LineScanCameraGroundMap.h" +#include "LineScanCameraSkyMap.h" + +using namespace std; +namespace Isis { + namespace Lro { + // constructors + LroNarrowAngleCamera::LroNarrowAngleCamera (Isis::Pvl &lab) : Isis::LineScanCamera(lab) { + // Set up the camera info from ik/iak kernels + SetFocalLength(); + SetPixelPitch(); + + double constantTimeOffset = 0.0, + additionalPreroll = 0.0, + additiveLineTimeError = 0.0, + multiplicativeLineTimeError = 0.0; + + iString ikernKey = "INS" + iString((int)NaifIkCode()) + "_CONSTANT_TIME_OFFSET"; + constantTimeOffset = GetDouble(ikernKey); + + ikernKey = "INS" + iString((int)NaifIkCode()) + "_ADDITIONAL_PREROLL"; + additionalPreroll = GetDouble(ikernKey); + + ikernKey = "INS" + iString((int)NaifIkCode()) + "_ADDITIVE_LINE_ERROR"; + additiveLineTimeError = GetDouble(ikernKey); + + ikernKey = "INS" + iString((int)NaifIkCode()) + "_MULTIPLI_LINE_ERROR"; + multiplicativeLineTimeError = GetDouble(ikernKey); + + // Get the start time from labels + Isis::PvlGroup &inst = lab.FindGroup ("Instrument",Isis::Pvl::Traverse); + iString stime = (string)inst["SpacecraftClockPrerollCount"]; + SpiceDouble etStart; + if( stime != "NULL" ) { + scs2e_c (NaifSclkCode(),stime.c_str(),&etStart); + } + else { + stime = (string)inst["PrerollTime"]; + str2et_c(stime.c_str(), &etStart); + } + + // Get other info from labels + double csum = inst["SpatialSumming"]; + double lineRate = (double) inst["LineExposureDuration"] / 1000.0; + double ss = inst["SampleFirstPixel"]; + ss += 1.0; + + lineRate *= 1.0 + multiplicativeLineTimeError; + lineRate += additiveLineTimeError; + etStart += additionalPreroll*lineRate; + etStart += constantTimeOffset; + + SetEphemerisTime(etStart); + + // Setup detector map + LineScanCameraDetectorMap *detectorMap = new LineScanCameraDetectorMap(this,etStart,lineRate); + detectorMap->SetDetectorSampleSumming(csum); + detectorMap->SetStartingDetectorSample(ss); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap =new CameraFocalPlaneMap(this,NaifIkCode()); + + // Retrieve boresight location from instrument kernel (IK) (addendum?) + ikernKey = "INS" + iString((int)NaifIkCode()) + "_BORESIGHT_SAMPLE"; + double sampleBoreSight = GetDouble(ikernKey); + + ikernKey = "INS" + iString((int)NaifIkCode()) + "_BORESIGHT_LINE"; + double lineBoreSight = GetDouble(ikernKey); + + focalMap->SetDetectorOrigin(sampleBoreSight, lineBoreSight); + focalMap->SetDetectorOffset(0.0,0.0); + + // Setup distortion map + LroNarrowAngleDistortionMap *distMap = new LroNarrowAngleDistortionMap(this); + distMap->SetDistortion( NaifIkCode()); + + // Setup the ground and sky map + new LineScanCameraGroundMap(this); + new LineScanCameraSkyMap(this); + + LoadCache(); + } + } +} + +extern "C" Isis::Camera *LroNarrowAngleCameraPlugin (Isis::Pvl &lab) { + return new Isis::Lro::LroNarrowAngleCamera(lab); +} diff --git a/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleCamera.h b/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..70645b5d1a9094f109960862c9820e61463eb385 --- /dev/null +++ b/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleCamera.h @@ -0,0 +1,23 @@ +#ifndef LroNarrowAngleCamera_h +#define LroNarrowAngleCamera_h + +#include "LineScanCamera.h" + +namespace Isis { + namespace Lro { + /** + * @internal + * @history 2009-02-20 Jacob Danton, Original Object + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class LroNarrowAngleCamera : public LineScanCamera { + public: + LroNarrowAngleCamera (Isis::Pvl &lab); + + ~LroNarrowAngleCamera () {}; + }; + }; +}; + +#endif diff --git a/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleCamera.truth b/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..5995e8816d3f1fff0fefd2be728dbe3332823547 --- /dev/null +++ b/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleCamera.truth @@ -0,0 +1,19 @@ +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleDistortionMap.cpp b/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleDistortionMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e2d2a8941fc23c8eb75d22a73fe727f520bdf6bc --- /dev/null +++ b/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleDistortionMap.cpp @@ -0,0 +1,117 @@ +#include + +#include "iString.h" +#include "LroNarrowAngleDistortionMap.h" + +namespace Isis { + namespace Lro { + + /** Camera distortion map constructor + * + * Create a camera distortion map. This class maps between distorted + * and undistorted focal plane x/y's. The default mapping is the + * identity, that is, the focal plane x/y and undistorted focal plane + * x/y will be identical. + * + * @param parent the parent camera that will use this distortion map + * @param zDirection the direction of the focal plane Z-axis + * (either 1 or -1) + * + */ + LroNarrowAngleDistortionMap::LroNarrowAngleDistortionMap(Camera *parent) : CameraDistortionMap(parent, 1) { + } + + void LroNarrowAngleDistortionMap::SetDistortion(const int naifIkCode) { + std::string odkkey = "INS" + Isis::iString(naifIkCode) + "_OD_K"; + p_odk.clear(); + p_odk.push_back(p_camera->GetDouble(odkkey, 0)); + } + + /** Compute undistorted focal plane x/y + * + * Compute undistorted focal plane x/y given a distorted focal plane x/y. + * + * @param dx distorted focal plane x in millimeters + * @param dy distorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + * @todo Generalize polynomial equation + */ + bool LroNarrowAngleDistortionMap::SetFocalPlane(const double dx, const double dy) { + p_focalPlaneX = dx; + p_focalPlaneY = dy; + + double dk1 = -p_odk[0]; + + double den = 1+dk1*dy*dy; // r = dy*dy = distance from the focal plane center + if( den == 0.0 ) + return false; + + p_undistortedFocalPlaneX = dx; + p_undistortedFocalPlaneY = dy/den; + + return true; + } + + /** Compute distorted focal plane x/y + * + * Compute distorted focal plane x/y given an undistorted focal plane x/y. + * + * @param ux undistorted focal plane x in millimeters + * @param uy undistorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + */ + bool LroNarrowAngleDistortionMap::SetUndistortedFocalPlane(const double ux, const double uy) { + // image coordinates prior to introducing distortion + p_undistortedFocalPlaneX = ux; + p_undistortedFocalPlaneY = uy; + + double yt = uy; + + double rr,dr; + double ydistorted; + double yprevious = 1000000.0; + double tolerance = 1.0e-10; + + bool bConverged = false; + + double dk1 = -p_odk[0]; + + // iterating to introduce distortion (in sample only)... + // we stop when the difference between distorted coordinate + // in successive iterations is at or below the given tolerance + for( int i = 0; i < 50; i++ ) { + rr = yt*yt; + + // dr is the radial distortion contribution + dr = 1.0 + dk1*rr; + + // distortion at the current sample location + yt = uy * dr; + + // distorted sample + ydistorted = yt; + + // check for convergence + if( fabs(yt - yprevious) <= tolerance ) { + bConverged = true; + break; + } + + yprevious = yt; + } + + if( bConverged ) { + p_focalPlaneX = p_undistortedFocalPlaneX; + p_focalPlaneY = ydistorted; + } + + return bConverged; + } + } +} + + diff --git a/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleDistortionMap.h b/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleDistortionMap.h new file mode 100644 index 0000000000000000000000000000000000000000..f7a6c64d652c209c01caffea6c4406f6f4e0722f --- /dev/null +++ b/isis/src/lro/objs/LroNarrowAngleCamera/LroNarrowAngleDistortionMap.h @@ -0,0 +1,41 @@ +#ifndef LroNarrowAngleDistortionMap_h +#define LroNarrowAngleDistortionMap_h + +#include +#include "CameraDistortionMap.h" + +namespace Isis { + namespace Lro { + + /** Distort/undistort focal plane coordinates + * + * Creates a map for adding/removing optical distortions + * from the focal plane of a camera. + * + * @ingroup Camera + * + * @see Camera + * + * @author 2009-07-03 Jacob Danton + * @history 2010-05-10 Ken Edmundson - Corrected computation of distorted + * and undistorted locations + * + * @internal + */ + class LroNarrowAngleDistortionMap : public CameraDistortionMap { + public: + LroNarrowAngleDistortionMap(Camera *parent); + + //! Destructor + virtual ~LroNarrowAngleDistortionMap() {}; + + void SetDistortion(const int naifIkCode); + + virtual bool SetFocalPlane(const double dx, const double dy); + + virtual bool SetUndistortedFocalPlane(const double ux, const double uy); + + }; + }; +}; +#endif diff --git a/isis/src/lro/objs/LroNarrowAngleCamera/Makefile b/isis/src/lro/objs/LroNarrowAngleCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3f5e8b9db51611c872a25a1aa23f3d0fa9471ce0 --- /dev/null +++ b/isis/src/lro/objs/LroNarrowAngleCamera/Makefile @@ -0,0 +1,5 @@ +INCS = LroNarrowAngleCamera.h LroNarrowAngleDistortionMap.h +SRCS = LroNarrowAngleCamera.cpp LroNarrowAngleDistortionMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/lro/objs/LroNarrowAngleCamera/unitTest.cpp b/isis/src/lro/objs/LroNarrowAngleCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..509593166eb57dd81c727ac60e661a44a4ca7f37 --- /dev/null +++ b/isis/src/lro/objs/LroNarrowAngleCamera/unitTest.cpp @@ -0,0 +1,94 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + + /** LRO NAC: The line,samp to lat,lon to line,samp tolerance was increased for this + * camera model test. + * + */ + + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownLat = -83.229473272165; + double knownLon = 353.93153626711; + + Isis::Pvl p("$lro/testData/M111607830RE_crop.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.01) deltaSamp = 0; + if (fabs(deltaLine) < 0.01) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/lro/objs/LroWideAngleCamera/Camera.plugin b/isis/src/lro/objs/LroWideAngleCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..8ff9b0c188831ad4e36c6da0c1fd35ff3a55a349 --- /dev/null +++ b/isis/src/lro/objs/LroWideAngleCamera/Camera.plugin @@ -0,0 +1,11 @@ +Group = LUNAR_RECONNAISSANCE_ORBITER/WAC-VIS + Library = LroWideAngleCamera + Routine = LroWideAngleCameraPlugin + Version = 1 +EndGroup + +Group = LUNAR_RECONNAISSANCE_ORBITER/WAC-UV + Library = LroWideAngleCamera + Routine = LroWideAngleCameraPlugin + Version = 1 +EndGroup diff --git a/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCamera.cpp b/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b993709f56f63e4d4d59924e3678dd568364f907 --- /dev/null +++ b/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCamera.cpp @@ -0,0 +1,318 @@ +#include +#include + +#include "LroWideAngleCamera.h" +#include "PushFrameCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "PushFrameCameraGroundMap.h" +#include "CameraSkyMap.h" +#include "LroWideAngleCameraDistortionMap.h" + +using namespace std; + +namespace Isis { + namespace Lro { + /** + * Constructor for the LRO WAC Camera Model + * + * @param lab Pvl Label to create the camera model from + * + * @throws Isis::iException::User - The image does not appear to be a Lunar + * Reconaissance Orbiter Wide Angle Camera image + */ + LroWideAngleCamera::LroWideAngleCamera ( Isis::Pvl &lab ) : + Isis::PushFrameCamera(lab) { + // Set up the camera characteristics + InstrumentRotation()->SetFrame(-85620); + SetFocalLength(); + SetPixelPitch(); + + // Get the ephemeris time from the labels + double et; + Isis::PvlGroup &inst = lab.FindGroup("Instrument", Isis::Pvl::Traverse); + string stime = inst["SpacecraftClockStartCount"]; + scs2e_c(NaifSclkCode(), stime.c_str(), &et); + + p_exposureDur = inst["ExposureDuration"]; + // TODO: Changed et - exposure to et + exposure. + // Think about if this is correct + p_etStart = et + ((p_exposureDur / 1000.0) / 2.0); + + // Compute the framelet size and number of framelets + iString instId = iString((string) inst["InstrumentId"]).UpCase(); + + int frameletSize = 14; + int sumMode = 1; + + if( instId == "WAC-UV" ) { + sumMode = 4; + frameletSize = 16; + } + else if( instId == "WAC-VIS" ) { + sumMode = 1; + frameletSize = 14; + } + else { + string msg = "Invalid value [" + instId + + "] for keyword [InstrumentId]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + p_nframelets = ParentLines() / (frameletSize / sumMode); + + // Setup the line detector offset map for each filter + int nbands = (int) lab.FindKeyword("Bands", PvlObject::Traverse); + const PvlGroup &bandBin = lab.FindGroup("BandBin", Isis::Pvl::Traverse); + const PvlKeyword &filtNames = bandBin["Center"]; + // Sanity check + if( nbands != filtNames.Size() ) { + ostringstream mess; + mess << "Number bands in (file) label (" << nbands + << ") do not match number of values in BandBin/Center keyword (" + << filtNames.Size() << ") - required for band-dependant geoemtry"; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + // Now create detector offsets + std::map filterToDetectorOffset; + + filterToDetectorOffset.insert(std::pair(315, 244)); + filterToDetectorOffset.insert(std::pair(321, 244)); + + filterToDetectorOffset.insert(std::pair(360, 302)); + + filterToDetectorOffset.insert(std::pair(415, 702)); + + filterToDetectorOffset.insert(std::pair(565, 727)); + filterToDetectorOffset.insert(std::pair(566, 727)); + + filterToDetectorOffset.insert(std::pair(600, 753)); + filterToDetectorOffset.insert(std::pair(604, 753)); + + filterToDetectorOffset.insert(std::pair(640, 780)); + filterToDetectorOffset.insert(std::pair(643, 780)); + + filterToDetectorOffset.insert(std::pair(680, 805)); + filterToDetectorOffset.insert(std::pair(689, 805)); + + int frameletOffsetFactor = inst["ColorOffset"]; + + if( inst["DataFlipped"][0].UpCase() == "YES" ) + frameletOffsetFactor *= -1; + + std::map filterToFrameletOffset; + // the UV order is based on position in the cube + filterToFrameletOffset.insert( + std::pair(321, 0 * frameletOffsetFactor ) + ); + filterToFrameletOffset.insert( + std::pair(315, 0 * frameletOffsetFactor ) + ); + + filterToFrameletOffset.insert( + std::pair(360, 1 * frameletOffsetFactor ) + ); + + filterToFrameletOffset.insert( + std::pair(415, 0 * frameletOffsetFactor )); + + filterToFrameletOffset.insert( + std::pair(566, 1 * frameletOffsetFactor ) + ); + filterToFrameletOffset.insert( + std::pair(565, 1 * frameletOffsetFactor ) + ); + + filterToFrameletOffset.insert( + std::pair(604, 2 * frameletOffsetFactor ) + ); + filterToFrameletOffset.insert( + std::pair(600, 2 * frameletOffsetFactor ) + ); + + filterToFrameletOffset.insert( + std::pair(643, 3 * frameletOffsetFactor ) + ); + filterToFrameletOffset.insert( + std::pair(640, 3 * frameletOffsetFactor ) + ); + + filterToFrameletOffset.insert( + std::pair(689, 4 * frameletOffsetFactor ) + ); + filterToFrameletOffset.insert( + std::pair(680, 4 * frameletOffsetFactor ) + ); + + for( int i = 0; i < filtNames.Size(); i++ ) { + if( filterToDetectorOffset.find((int) filtNames[i]) == + filterToDetectorOffset.end() ) { + string msg = "Unrecognized filter name [" + filtNames[i] + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + p_detectorStartLines.push_back( + filterToDetectorOffset.find(filtNames[i])->second + ); + p_frameletOffsets.push_back( + filterToFrameletOffset.find(filtNames[i])->second + ); + } + + // Setup detector map + double frameletRate = (double) inst["InterframeDelay"] / 1000.0; + PushFrameCameraDetectorMap *dmap = new PushFrameCameraDetectorMap(this, + p_etStart, frameletRate, frameletSize); + dmap->SetDetectorSampleSumming(sumMode); + dmap->SetDetectorLineSumming(sumMode); + + bool flippedFramelets = false; + + // flipping disabled + if( iString((string) inst["DataFlipped"]).UpCase() == "YES" ) + flippedFramelets = true; + + dmap->SetFlippedFramelets(flippedFramelets, p_nframelets); + + // Setup focal plane map + new CameraFocalPlaneMap(this, NaifIkCode()); + + // The line detector origin varies based on instrument mode + double detectorOriginLine; + double detectorOriginSamp; + + dmap->SetGeometricallyFlippedFramelets(false); + + iString ikernKey; + ikernKey = "INS" + iString((int) NaifIkCode()) + "_BORESIGHT_SAMPLE"; + double sampleBoreSight = GetDouble(ikernKey); + + ikernKey = "INS" + iString((int) NaifIkCode()) + "_BORESIGHT_LINE"; + double lineBoreSight = GetDouble(ikernKey); + + if( instId == "WAC-UV" ) { + /** + * The detector origin sample is from + * LRO Wide Angle Geometric Calibration + * document by Peter Thomas and accounts + * for the 8 pixels off the left side of + * the detector and the 256 other ignored + * pixels off the left side of the detector + * which are not in the image. + */ + detectorOriginSamp = sampleBoreSight - 8 - 256; + detectorOriginLine = lineBoreSight; + } + else { + iString instModeId; + instModeId = ((iString) (string) inst["InstrumentModeId"]).UpCase(); + + if( instModeId == "COLOR" || instModeId == "VIS" ) { + /** + * The detector origin sample is from + * LRO Wide Angle Geometric Calibration + * document by Peter Thomas and accounts + * for the 8 pixels off the left side of + * the detector and the 160 other ignored + * pixels off the left side of the detector + * which are not in the image. + */ + detectorOriginSamp = sampleBoreSight - 8 - 160; + detectorOriginLine = lineBoreSight; + } + else if( instModeId == "BW" ) { + + iString mode = ((iString) (string) inst["Mode"]).UpCase(); + + /** + * The detector origin sample is from + * LRO Wide Angle Geometric Calibration + * document by Peter Thomas and accounts + * for the 8 pixels off the left side of + * the detector. + */ + + // Mode 0 and 1 are not Polar (i.e. they are only 704 pixels wide) + if( mode == "0" || mode == "1" ) { + // The 160 other ignored pixels off the left side of the detector + // which are not in the image. These numbers added to compensate + // for the non-polar mode. + detectorOriginSamp = sampleBoreSight - 8 - 160; + detectorOriginLine = lineBoreSight; + } + // Mode 2 and 3 are Polar (i.e. they are 1024 pixels wide) + else if( mode == "2" || mode == "3" ) { + detectorOriginSamp = sampleBoreSight - 8; + detectorOriginLine = lineBoreSight; + } + else { + string msg = "Invalid value [" + mode + "] for keyword [Mode]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + // There are no offsets for BW mode.. there can only be 1 filter + // and there must be 1 filter. + p_frameletOffsets[0] = 0; + } + else { + string msg = "Invalid value [" + instModeId + + "] for keyword [InstrumentModeId]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + FocalPlaneMap()->SetDetectorOrigin(detectorOriginSamp, + detectorOriginLine); + + // Setup distortion map + new LroWideAngleCameraDistortionMap(this, NaifIkCode()); + + // Setup the ground and sky map + bool evenFramelets = (iString((string) inst["Framelets"][0]).UpCase() + == "EVEN"); + + new PushFrameCameraGroundMap(this, evenFramelets); + + new CameraSkyMap(this); + LoadCache(); + + if( instId == "WAC-UV" ) { + // geometric tiling is not worth trying for 4-line framelets + SetGeometricTilingHint(2, 2); + } + else { + SetGeometricTilingHint(8, 4); + } + } + + /** + * Sets the band in the camera model + * + * @param vband The band number to set + */ + void LroWideAngleCamera::SetBand ( const int vband ) { + + // Sanity check on requested band + int maxbands = min(p_detectorStartLines.size(), p_frameletOffsets.size()); + if( (vband <= 0) || (vband > maxbands) ) { + ostringstream mess; + mess << "Requested virtual band (" << vband + << ") outside valid (BandBin/Center) limits (1 - " << maxbands + << ")"; + throw iException::Message(iException::Programmer, mess.str(), _FILEINFO_); + } + + // Set up valid band access + Camera::SetBand(vband); + PushFrameCameraDetectorMap *dmap = NULL; + dmap = (PushFrameCameraDetectorMap *) DetectorMap(); + dmap->SetBandFirstDetectorLine(p_detectorStartLines[vband - 1]); + dmap->SetFrameletOffset(p_frameletOffsets[vband - 1]); + } + } +} + +// Plugin +extern "C" Isis::Camera *LroWideAngleCameraPlugin ( Isis::Pvl &lab ) { + return new Isis::Lro::LroWideAngleCamera(lab); +} diff --git a/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCamera.h b/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..b27264631dd87554ad616ac39ad6ded0f33181b5 --- /dev/null +++ b/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCamera.h @@ -0,0 +1,64 @@ +#ifndef LroWideAngleCamera_h +#define LroWideAngleCamera_h + +#include "PushFrameCamera.h" + +namespace Isis { + namespace Lro { + /** + * @brief LRO Narrow Angle Camera Model + * + * @ingroup SpiceInstrumentsAndCameras + * @ingroup LunarReconnaissanceOrbiter + * + * @author 2009-07-08 Jeff Anderson + * + * @internal + * @history 2009-07-15 Steven Lambright - Added support for COLOROFFSET + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + * @history 2009-09-09 Steven Lambright - Updated wavelengths + * @history 2009-11-06 Steven Lambright - FilterName keyword is now Center + * @history 2010-03-15 Steven Lambright - Tiling hint now set to a safe + * value regardless of output projection resolution. Also + * incorporated ASU's changes for new modes. + * @history 2010-05-12 Kris Becker - Added checks for number of bands to + * match number of values in BandBin/Center keyword and insure a + * valid band is selected in SetBand() method; Rewrote the + * camera distortion model that also requires negative + * coefficients in IK kernel. + */ + class LroWideAngleCamera : public Isis::PushFrameCamera { + public: + // constructor + LroWideAngleCamera (Isis::Pvl &lab); + + //! Destroys the Themis Vis Camera object + ~LroWideAngleCamera () {}; + + // Sets the band to the band number given + void SetBand (const int band); + + /** + * The camera model is band dependent, so this method returns false + * + * @return bool False + */ + bool IsBandIndependent () { + return false; + }; + + private: + double p_etStart; //! p_detectorStartLines; + std::vector p_frameletOffsets; + }; + }; +}; + +#endif + diff --git a/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCamera.truth b/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..abbeced5f98c316faa85e5213fa50b24a4278ca8 --- /dev/null +++ b/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCamera.truth @@ -0,0 +1,20 @@ +Unit Test for LroWideAngleCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCameraDistortionMap.cpp b/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCameraDistortionMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1594dbf47fdef0326c2f8440ffee9301f8bb86d7 --- /dev/null +++ b/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCameraDistortionMap.cpp @@ -0,0 +1,154 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/05/12 23:28:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include + +#include "iString.h" +#include "LroWideAngleCameraDistortionMap.h" + +namespace Isis { + namespace Lro { + /** Camera distortion map constructor + * + * Create a camera distortion map. This class maps between distorted + * and undistorted focal plane x/y's. The default mapping is the + * identity, that is, the focal plane x/y and undistorted focal plane + * x/y will be identical. + * + * @param parent the parent camera that will use this distortion map + * @param zDirection the direction of the focal plane Z-axis + * (either 1 or -1) + * + */ + LroWideAngleCameraDistortionMap::LroWideAngleCameraDistortionMap(Camera *parent, int naifIkCode) : CameraDistortionMap(parent) { + std::string odkkey = "INS" + Isis::iString(naifIkCode) + "_OD_K"; + for( int i = 0; i < 2; i++ ) { + p_odk.push_back(p_camera->GetDouble(odkkey, i)); + } + } + + /** Compute undistorted focal plane x/y + * + * Compute undistorted focal plane x/y given a distorted focal plane x/y. + * + * @param dx distorted focal plane x in millimeters + * @param dy distorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + * @todo Generalize polynomial equation + */ + + bool LroWideAngleCameraDistortionMap::SetFocalPlane(const double dx, const double dy) { + p_focalPlaneX = dx; + p_focalPlaneY = dy; + + double dk1 = p_odk[0]; + double dk2 = p_odk[1]; + + double rr = dx*dx + dy*dy; + double r = sqrt(rr); + + double dr = 1.0 + dk1*rr + dk2*r*rr; + if( dr == 0.0 ) + return false; + + // Compute the undistorted positions + p_undistortedFocalPlaneX = dx/dr; + p_undistortedFocalPlaneY = dy/dr; + + return true; + } + + /** Compute distorted focal plane x/y + * + * Compute distorted focal plane x/y given an undistorted focal plane x/y. + * + * @param ux undistorted focal plane x in millimeters + * @param uy undistorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + * @todo Generalize polynomial equation + * @todo Figure out a better solution for divergence condition + */ + + bool LroWideAngleCameraDistortionMap::SetUndistortedFocalPlane(const double ux, const double uy) { + // image coordinates prior to introducing distortion + p_undistortedFocalPlaneX = ux; + p_undistortedFocalPlaneY = uy; + + double xt = ux; + double yt = uy; + + double r,rr,dr; + double xdistorted,ydistorted; + double xprevious,yprevious; + + xprevious = 1000000.0; + yprevious = 1000000.0; + double tolerance = 1.0e-10; + + bool bConverged = false; + + double dk1 = p_odk[0]; + double dk2 = p_odk[1]; + + // iterating to introduce distortion... + // we stop when the difference between distorted coordinates + // in successive iterations is at or below the given tolerance + for( int i = 0; i < 50; i++ ) { + rr = xt*xt + yt*yt; + r = sqrt(rr); + + // dr is the radial distortion contribution + dr = 1.0 + dk1*rr + dk2*r*rr; + + // introducing distortion + xt = ux * dr; + yt = uy * dr; + + // distorted point + xdistorted = xt; + ydistorted = yt; + + // check for convergence + if( (fabs(xt - xprevious) <= tolerance) && (fabs(yt - yprevious) <= tolerance) ) { + bConverged = true; + break; + } + + xprevious = xt; + yprevious = yt; + } + + if( bConverged ) { + p_focalPlaneX = xdistorted; + p_focalPlaneY = ydistorted; + } + + return bConverged; + } + + } +} + diff --git a/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCameraDistortionMap.h b/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCameraDistortionMap.h new file mode 100644 index 0000000000000000000000000000000000000000..4973c691ad4cb2186dcd43cc95295c77f010750a --- /dev/null +++ b/isis/src/lro/objs/LroWideAngleCamera/LroWideAngleCameraDistortionMap.h @@ -0,0 +1,73 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/05/12 23:28:12 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef LroWideAngleCameraDistortionMap_h +#define LroWideAngleCameraDistortionMap_h + +#include "CameraDistortionMap.h" + +namespace Isis { + namespace Lro { + /** Distort/undistort focal plane coordinates + * + * Creates a map for adding/removing optical distortions + * from the focal plane of a camera. + * + * @ingroup Camera + * + * @see Camera + * + * @author 2008-08-22 Steven Lambright + * + * @internal + * @history 2009-11-19 Kris Becker - Changed the convergence tolerance + * from 1/10,000 of a pixel to 1/100 of a pixel + * @history 2010-05-05 Ken Edmundson - Corrected distorted and undistorted + * computations; Fix requires coefficients in the + * lro_instruments_v??.ti to be negative (essentially matches + * what is reported in the calibration document); removed the + * GuessDx method as it was not used; updated the UV boresight in + * the IK based upon analysis of the VIS and UV. + */ + class LroWideAngleCameraDistortionMap : public CameraDistortionMap { + public: + LroWideAngleCameraDistortionMap(Camera *parent, int naifIkCode); + + //! Destructor + virtual ~LroWideAngleCameraDistortionMap() {}; + + virtual bool SetFocalPlane(const double dx, const double dy); + + virtual bool SetUndistortedFocalPlane(const double ux, const double uy); + + void SetFilter(int filter) { + p_filter = filter; + } + + private: + int p_filter; + double p_k1; + double p_k2; + }; + }; +}; +#endif diff --git a/isis/src/lro/objs/LroWideAngleCamera/Makefile b/isis/src/lro/objs/LroWideAngleCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ff2ec835efe2fe0d25341412eb73bff4d95b4ecd --- /dev/null +++ b/isis/src/lro/objs/LroWideAngleCamera/Makefile @@ -0,0 +1,5 @@ +INCS = LroWideAngleCamera.h LroWideAngleCameraDistortionMap.h +SRCS = LroWideAngleCamera.cpp LroWideAngleCameraDistortionMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/lro/objs/LroWideAngleCamera/unitTest.cpp b/isis/src/lro/objs/LroWideAngleCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87e5e437ea0905c4db6e1b69f2261914146a5d51 --- /dev/null +++ b/isis/src/lro/objs/LroWideAngleCamera/unitTest.cpp @@ -0,0 +1,96 @@ +#include +#include + +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) { + Isis::Preference::Preferences(true); + + cout << "Unit Test for LroWideAngleCamera..." << endl; + + try { + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownLat = -70.69638475050628; + double knownLon = 244.3314992195277; + + + Isis::Pvl p("$lro/testData/wacCameraTest.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 15.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 15.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, 56); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 56); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if( !cam->SetImage(samp,line) ) { + std::cout << "ERROR" << std::endl; + return 0; + } + +#if 0 + cout << "Latitude = " << setprecision(16) << cam->UniversalLatitude() << endl; + cout << "Longitude = " << setprecision(16) << cam->UniversalLongitude() << endl; +#endif + + if( abs(cam->UniversalLatitude() - knownLat) < 1E-10 ) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if( abs(cam->UniversalLongitude() - knownLon) < 1E-10 ) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch( Isis::iException &e ) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if( success ) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if( success ) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if( fabs(deltaSamp) < 0.01 ) deltaSamp = 0; + if( fabs(deltaLine) < 0.01 ) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/lro/objs/Makefile b/isis/src/lro/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/lro/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/lro/objs/MiniRF/Camera.plugin b/isis/src/lro/objs/MiniRF/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..3fb21599d0aacfd8f47c455e3e72c901337905a0 --- /dev/null +++ b/isis/src/lro/objs/MiniRF/Camera.plugin @@ -0,0 +1,10 @@ +Group = CHANDRAYAAN1_ORBITER/MRFFR + Version = 1 + Library = MiniRF + Routine = MiniRFPlugin +EndGroup +Group = LUNARRECONNAISSANCEORBITER/MRFLRO + Version = 1 + Library = MiniRF + Routine = MiniRFPlugin +EndGroup diff --git a/isis/src/lro/objs/MiniRF/Makefile b/isis/src/lro/objs/MiniRF/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..30bf815c87675010ab6adb363723606b64a1f7f2 --- /dev/null +++ b/isis/src/lro/objs/MiniRF/Makefile @@ -0,0 +1,5 @@ +INCS = MiniRF.h +SRCS = MiniRF.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/lro/objs/MiniRF/MiniRF.cpp b/isis/src/lro/objs/MiniRF/MiniRF.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6ad0d142b5608460f0913e3ca577f9e2d228c88 --- /dev/null +++ b/isis/src/lro/objs/MiniRF/MiniRF.cpp @@ -0,0 +1,173 @@ +/** + * @file + * $Revision: 1.7 $ + * $Date: 2010/03/27 06:46:58 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "MiniRF.h" +#include "iString.h" +#include "iException.h" +#include "RadarPulseMap.h" +#include "RadarGroundRangeMap.h" +#include "RadarSlantRangeMap.h" +#include "RadarGroundMap.h" +#include "RadarSkyMap.h" + +using namespace std; + +namespace Isis { + namespace Lro { + /** + * @brief Initialize the Mini-RF SAR radar model for LRO and Chandrayaan 1 + * + * This constructor reads the image labels of a Mini-RF SAR file to acquire + * its default parameters. + * + * @param lab The label provided to initialize the radar model. + * @internal + * @history 2009-07-31 Jeannie Walldren - Added tolerance + * parameter value of -1 to call to + * Spice::CreateCache() method. + * @history 2009-07-31 Debbie Cook - Calculated actual tolerance + * value to pass into Spice::CreateCache() method. + */ + MiniRF::MiniRF (Isis::Pvl &lab) : Isis::RadarCamera(lab) { + + // Get the ground range resolution (ScaledPixelHeight and ScaledPixelWidth + // are expected to be equal - mrf2isis checks for this) + Isis::PvlGroup &inst = lab.FindGroup ("Instrument",Isis::Pvl::Traverse); + double groundRangeResolution = inst["ScaledPixelHeight"]; // meters + + // Synthesize the pixel pitch to the ground range resolution + SetPixelPitch(groundRangeResolution); // meters/pix + + // Focal length should always be slant range to the current ground + // point. This will be set each time the slant range is calculated. + // For now, set the focal length to 1.0. + SetFocalLength(1.0); + + // Get the start time from labels (the SpacecraftClockStartCount is set to + // is set to UNK in the PDS labels, so StartTime is used instead) + string stime = inst["StartTime"]; + SpiceDouble etStart; + str2et_c(stime.c_str(),&etStart); + + // The line rate is in units of seconds in the PDS label. The exposure + // is the sum of the burst and the delay for the return. The movement of the + // spacecraft is negligible compared to the speed of light, so we are assuming + // the spacecraft hasn't moved between the burst and the return. + double lineRate = (double) inst["LineExposureDuration"]; + + // Get the incidence angle at the center of the image + double incidenceAngle = (double) inst["IncidenceAngle"]; + incidenceAngle = incidenceAngle * Isis::PI / 180.0; + + // Get the azimuth resolution at the center of the image + double azimuthResolution = (double) inst["AzimuthResolution"]; // label units are meters + azimuthResolution = azimuthResolution / 1000.0; // change to km + + // Get the range resolution at the center of the image + double rangeResolution = (double) inst["RangeResolution"]; // label units are meters + + // Get the wavelength or frequency of the instrument. This does not + // exist in the PDS labels, so it will need to be hardcoded until the + // PDS labels are updated. Right now, the mrf2isis program is putting + // a frequency value in the labels based on the instrument mode id. + double frequency = (double) inst["Frequency"]; // units are htz + double waveLength = clight_c() / frequency; // units are km/sec/htz + + // Setup map from image(sample,line) to radar(sample,time) + new RadarPulseMap(this,etStart,lineRate); + + // Setup map from radar(sample,time) to radar(groundrange,time) + Radar::LookDirection ldir = Radar::Right; + if ((std::string)inst["LookDirection"] == "LEFT") { + ldir = Radar::Left; + } + RadarGroundRangeMap::setTransform(NaifIkCode(),groundRangeResolution, + this->Samples(),ldir); + new RadarGroundRangeMap(this,NaifIkCode()); + + // Calculate weighting for focal plane coordinates. This is done + // because the focal plane coordinates (slant range and Doppler + // shift) do not have the same units of measurement and cannot + // be used by jigsaw as is. The weighting factors convert the + // focal plane coordinates into comparitive values. The weighting + // factor for the Doppler shift requires spacecraft pointing and + // velocity at the center of the image, so it is calculated + // after Spice gets loaded. + double range_sigma = rangeResolution * sin(incidenceAngle) * 100; // scaled meters + double etMid = etStart + 0.5 * (this->ParentLines() + 1) * lineRate; + + // Setup the map from Radar(groundRange,t) to Radar(slantRange,t) + RadarSlantRangeMap *slantRangeMap = new RadarSlantRangeMap(this, + groundRangeResolution); + slantRangeMap->SetCoefficients(inst["RangeCoefficientSet"]); + + // Setup the ground and sky map + RadarGroundMap *groundMap = new RadarGroundMap(this,ldir,waveLength); + groundMap->SetRangeSigma ( range_sigma ); + new RadarSkyMap(this); + + // Set the time range to cover the cube + // Must be done last as the naif kernels will be unloaded + double etEnd = etStart + this->ParentLines() * lineRate + lineRate; + etStart = etStart - lineRate; + double tol=PixelResolution()/100.; + + if (tol < 0.) { + // Alternative calculation of .01*ground resolution of a pixel + SetEphemerisTime(etMid); + tol = PixelPitch()*SpacecraftAltitude()/FocalLength()/100.; + } + Spice::CreateCache(etStart,etEnd,this->ParentLines()+1, tol); + SetEphemerisTime(etMid); + SpiceRotation *bodyFrame = this->BodyRotation(); + SpicePosition *spaceCraft = this->InstrumentPosition(); + + SpiceDouble Ssc[6]; + // Load the state into Ssc + vequ_c ( (SpiceDouble *) &(spaceCraft->Coordinate()[0]), Ssc); + vequ_c ( (SpiceDouble *) &(spaceCraft->Velocity()[0]), Ssc+3); + // Create the J2000 to body-fixed state transformation matrix BJ + SpiceDouble BJ[6][6]; + rav2xf_c ( &(bodyFrame->Matrix()[0]), (SpiceDouble *) &(bodyFrame->AngularVelocity()[0]), BJ); + // Rotate the spacecraft state from J2000 to body-fixed + mxvg_c ( BJ, Ssc, 6, 6, Ssc ); + // Extract the body-fixed position and velocity + double Vsc[3]; + double Xsc[3]; + vequ_c ( Ssc, Xsc ); + vequ_c ( Ssc+3, Vsc ); + + double radii[3]; + this->Radii(radii); + double R = radii[0]; + double height = sqrt(Xsc[0]*Xsc[0] + Xsc[1]*Xsc[1] + Xsc[2]*Xsc[2]) - R; + double speed = vnorm_c( Vsc ); + double dopplerSigma = 2.0 * speed * azimuthResolution / (waveLength * + height / cos(incidenceAngle)) * 100.; + groundMap->SetDopplerSigma ( dopplerSigma ); + slantRangeMap->SetWeightFactors( range_sigma, dopplerSigma); + } + } +} + +extern "C" Isis::Camera *MiniRFPlugin (Isis::Pvl &lab) { + return new Isis::Lro::MiniRF(lab); +} diff --git a/isis/src/lro/objs/MiniRF/MiniRF.h b/isis/src/lro/objs/MiniRF/MiniRF.h new file mode 100644 index 0000000000000000000000000000000000000000..806e06103881c0684689b2408a71c12d27ef1094 --- /dev/null +++ b/isis/src/lro/objs/MiniRF/MiniRF.h @@ -0,0 +1,63 @@ +#ifndef MiniRF_h +#define MiniRF_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/03/27 06:46:58 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "RadarCamera.h" + +namespace Isis { + namespace Lro { + /** + * @brief LRO Mini-RF SAR and Chandrayaan 1 Mini-RF SAR + * + * This is the camera model for both LRO Mini-RF SAR and + * Chandrayaan 1 Mini-RF SAR radar systems. + * + * @ingroup SpiceInstrumentsAndCameras + * @ingroup LRO + * + * @author 2008-07-01 Jeff Anderson + * + * @internal + * @history 2009-07-01 Janet Barrett - Updated with code to handle + * weighting of slant range and Doppler shift; fixed so that + * the frequency and wavelength of the instrument are made + * available to Radar classes. + * @history 2009-07-31 Debbie A. Cook and Jeannie Walldren - Added + * new tolerance argument to LoadCache call to be compatible + * with update to Spice class + * @history 2009-08-05 Debbie A. Cook - corrected altitude in tolerance + * calculation + * @history 2009-10-16 Debbie A. Cook - fixed the rotation of the velocity vector + * @history 2009-11-03 Debbie A. Cook - added RadarGroundMap method calls to set radar parameters + * @history 2010-03-19 Debbie A. Cook - removed unit change of rangeResolution so range_sigma works + * on meters instead of km + */ + class MiniRF : public RadarCamera { + public: + MiniRF (Isis::Pvl &lab); + + ~MiniRF () {}; + }; + }; +}; + +#endif diff --git a/isis/src/lro/objs/MiniRF/MiniRF.truth b/isis/src/lro/objs/MiniRF/MiniRF.truth new file mode 100644 index 0000000000000000000000000000000000000000..373c42800f8d04cdd14e5eff1b6b7d2c384f6f8b --- /dev/null +++ b/isis/src/lro/objs/MiniRF/MiniRF.truth @@ -0,0 +1,20 @@ +Unit Test for MiniRFCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/lro/objs/MiniRF/unitTest.cpp b/isis/src/lro/objs/MiniRF/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7af37eb08e6646e025544d2c8e9b3abdb0ff8737 --- /dev/null +++ b/isis/src/lro/objs/MiniRF/unitTest.cpp @@ -0,0 +1,90 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "Pvl.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for MiniRFCamera..." << endl; + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownLat = 85.59669503708331; + double knownLon = 264.741957434605; + + Isis::Pvl p("$chan1/testData/FSR_CDR_LV1_01801_0R.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 2E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.001) deltaSamp = 0; + if (fabs(deltaLine) < 0.001) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/lro/tsts/Makefile b/isis/src/lro/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..016388fc898d8c89f380cae1fd08942c29611582 --- /dev/null +++ b/isis/src/lro/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-42s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/lro/tsts/lroc/Makefile b/isis/src/lro/tsts/lroc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..35e3d05180eb3752f2a6e698f641694c21c979d4 --- /dev/null +++ b/isis/src/lro/tsts/lroc/Makefile @@ -0,0 +1,80 @@ +IMPORT = lrowac2isis +SPICEINIT = spiceinit +CROP = crop +PROJECT = cam2map +MOSAIC = automos +INPUTFILE = wac0000a1c4 + +# These cubes, if there is a problem, will be +# very significantly different +$(INPUTFILE).uv.lev2.cub.TOLERANCE = 0.0002 +$(INPUTFILE).vis.lev2.cub.TOLERANCE = 0.0004 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(IMPORT) from=$(INPUT)/$(INPUTFILE).img \ + to=$(OUTPUT)/$(INPUTFILE).cub \ + > /dev/null; + $(SPICEINIT) ck='$$lro/kernels/ck/moc42_2009258_2009259_v01.bc' \ + sclk='$$lro/kernels/sclk/lro_clkcor_2010158_v00.tsc' \ + from=$(OUTPUT)/$(INPUTFILE).vis.even.cub > /dev/null; + $(SPICEINIT) ck='$$lro/kernels/ck/moc42_2009258_2009259_v01.bc' \ + sclk='$$lro/kernels/sclk/lro_clkcor_2010158_v00.tsc' \ + from=$(OUTPUT)/$(INPUTFILE).vis.odd.cub > /dev/null; + $(SPICEINIT) ck='$$lro/kernels/ck/moc42_2009258_2009259_v01.bc' \ + sclk='$$lro/kernels/sclk/lro_clkcor_2010158_v00.tsc' \ + from=$(OUTPUT)/$(INPUTFILE).uv.even.cub > /dev/null; + $(SPICEINIT) ck='$$lro/kernels/ck/moc42_2009258_2009259_v01.bc' \ + sclk='$$lro/kernels/sclk/lro_clkcor_2010158_v00.tsc' \ + from=$(OUTPUT)/$(INPUTFILE).uv.odd.cub > /dev/null; + catlab from=$(OUTPUT)/$(INPUTFILE).vis.even.cub > $(OUTPUT)/vislabel.pvl; + catlab from=$(OUTPUT)/$(INPUTFILE).uv.odd.cub > $(OUTPUT)/uvlabel.pvl; + $(CROP) from=$(OUTPUT)/$(INPUTFILE).vis.even.cub line=3000 nlines=200 \ + sample=100 nsamples=200 \ + TO=$(OUTPUT)/$(INPUTFILE).vis.even.crop.cub > /dev/null; + $(MV) $(OUTPUT)/$(INPUTFILE).vis.even.crop.cub \ + $(OUTPUT)/$(INPUTFILE).vis.even.cub; + $(CROP) from=$(OUTPUT)/$(INPUTFILE).vis.odd.cub line=3000 nlines=200 \ + sample=100 nsamples=200 \ + TO=$(OUTPUT)/$(INPUTFILE).vis.odd.crop.cub > /dev/null; + $(MV) $(OUTPUT)/$(INPUTFILE).vis.odd.crop.cub \ + $(OUTPUT)/$(INPUTFILE).vis.odd.cub; + $(CROP) from=$(OUTPUT)/$(INPUTFILE).uv.even.cub line=900 nlines=100 \ + TO=$(OUTPUT)/$(INPUTFILE).uv.even.crop.cub > /dev/null; + $(MV) $(OUTPUT)/$(INPUTFILE).uv.even.crop.cub \ + $(OUTPUT)/$(INPUTFILE).uv.even.cub; + $(CROP) from=$(OUTPUT)/$(INPUTFILE).uv.odd.cub line=900 nlines=100 \ + TO=$(OUTPUT)/$(INPUTFILE).uv.odd.crop.cub > /dev/null; + $(MV) $(OUTPUT)/$(INPUTFILE).uv.odd.crop.cub \ + $(OUTPUT)/$(INPUTFILE).uv.odd.cub; + $(PROJECT) FROM=$(OUTPUT)/$(INPUTFILE).vis.even.cub \ + TO=$(OUTPUT)/$(INPUTFILE).vis.even.lev2.cub \ + > /dev/null; + $(PROJECT) FROM=$(OUTPUT)/$(INPUTFILE).vis.odd.cub \ + TO=$(OUTPUT)/$(INPUTFILE).vis.odd.lev2.cub \ + MAP=$(OUTPUT)/$(INPUTFILE).vis.even.lev2.cub MATCHMAP=TRUE \ + > /dev/null; + $(PROJECT) FROM=$(OUTPUT)/$(INPUTFILE).uv.even.cub \ + TO=$(OUTPUT)/$(INPUTFILE).uv.even.lev2.cub \ + > /dev/null; + $(PROJECT) FROM=$(OUTPUT)/$(INPUTFILE).uv.odd.cub \ + TO=$(OUTPUT)/$(INPUTFILE).uv.odd.lev2.cub \ + MAP=$(OUTPUT)/$(INPUTFILE).uv.even.lev2.cub MATCHMAP=TRUE \ + > /dev/null; + $(LS) $(OUTPUT)/$(INPUTFILE).vis.even.lev2.cub \ + $(OUTPUT)/$(INPUTFILE).vis.odd.lev2.cub > $(OUTPUT)/vis.lis; + $(MOSAIC) FROMLIST=$(OUTPUT)/vis.lis \ + MOSAIC=$(OUTPUT)/$(INPUTFILE).vis.lev2.cub > /dev/null; + $(LS) $(OUTPUT)/$(INPUTFILE).uv.even.lev2.cub \ + $(OUTPUT)/$(INPUTFILE).uv.odd.lev2.cub > $(OUTPUT)/uv.lis; + $(MOSAIC) FROMLIST=$(OUTPUT)/uv.lis \ + MOSAIC=$(OUTPUT)/$(INPUTFILE).uv.lev2.cub > /dev/null; + $(RM) $(OUTPUT)/vis.lis; + $(RM) $(OUTPUT)/uv.lis; + $(RM) $(OUTPUT)/$(INPUTFILE).vis.even.lev2.cub; + $(RM) $(OUTPUT)/$(INPUTFILE).vis.odd.lev2.cub; + $(RM) $(OUTPUT)/$(INPUTFILE).uv.even.lev2.cub; + $(RM) $(OUTPUT)/$(INPUTFILE).uv.odd.lev2.cub; + $(RM) $(OUTPUT)/$(INPUTFILE).vis.odd.cub; + $(RM) $(OUTPUT)/$(INPUTFILE).uv.odd.cub; diff --git a/isis/src/mariner/Makefile b/isis/src/mariner/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/mariner/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/mariner/apps/Makefile b/isis/src/mariner/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/mariner/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/mariner/apps/mar102isis/Makefile b/isis/src/mariner/apps/mar102isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mariner/apps/mar102isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mariner/apps/mar102isis/assets/MVE_002.117 b/isis/src/mariner/apps/mar102isis/assets/MVE_002.117 new file mode 100644 index 0000000000000000000000000000000000000000..a8aa4ddd8c6a5d7b0650109b98d88895b87790e6 Binary files /dev/null and b/isis/src/mariner/apps/mar102isis/assets/MVE_002.117 differ diff --git a/isis/src/mariner/apps/mar102isis/assets/images/gui.jpg b/isis/src/mariner/apps/mar102isis/assets/images/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..500a0fcb6adfe3619c32f13a44f2dc9eb027e7e0 Binary files /dev/null and b/isis/src/mariner/apps/mar102isis/assets/images/gui.jpg differ diff --git a/isis/src/mariner/apps/mar102isis/assets/images/imported.jpg b/isis/src/mariner/apps/mar102isis/assets/images/imported.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b9c022ac1cecd076337f8a589e4ec8e2a1f3e811 Binary files /dev/null and b/isis/src/mariner/apps/mar102isis/assets/images/imported.jpg differ diff --git a/isis/src/mariner/apps/mar102isis/assets/thumbs/gui.jpg b/isis/src/mariner/apps/mar102isis/assets/thumbs/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1fc79655b13117f1a3df1c4352e9a2607d987543 Binary files /dev/null and b/isis/src/mariner/apps/mar102isis/assets/thumbs/gui.jpg differ diff --git a/isis/src/mariner/apps/mar102isis/assets/thumbs/imported.jpg b/isis/src/mariner/apps/mar102isis/assets/thumbs/imported.jpg new file mode 100644 index 0000000000000000000000000000000000000000..60d96bcc484ce8a7e533a1c9f4ba1076adae8378 Binary files /dev/null and b/isis/src/mariner/apps/mar102isis/assets/thumbs/imported.jpg differ diff --git a/isis/src/mariner/apps/mar102isis/mar102isis.cpp b/isis/src/mariner/apps/mar102isis/mar102isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..14b2d9fa32d44d58c363c6535746690cf8737e38 --- /dev/null +++ b/isis/src/mariner/apps/mar102isis/mar102isis.cpp @@ -0,0 +1,481 @@ +#include "Isis.h" + +#include "Cube.h" +#include "Filename.h" +#include "iString.h" +#include "iTime.h" +#include "PixelType.h" +#include "ProcessImport.h" +#include "ProcessImportPds.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "PvlKeyword.h" +#include "PvlFormat.h" +#include "PvlFormatPds.h" + +#include +#include + +using namespace std; +using namespace Isis; + +void UpdateLabels (Cube *cube, const string &labels); +void TranslateIsis2Labels (Filename &labelFile, Cube *oCube); +string EbcdicToAscii (unsigned char *header); +string DaysToDate (int days); + +void IsisMain () { + UserInterface &ui = Application::GetUserInterface(); + + // Determine whether input is a raw Mariner 10 image or an Isis 2 cube + bool isRaw = false; + Filename inputFile = ui.GetFilename("FROM"); + Pvl label (inputFile.Expanded()); + + // If the PVL created from the input labels is empty, then input is raw + if (label.Groups() + label.Objects() + label.Keywords() == 0) { + isRaw = true; + } + + // Import for RAW files + if (isRaw) { + ProcessImport p; + + // All mariner images from both cameras share this size + p.SetDimensions(832,700,1); + p.SetFileHeaderBytes(968); + p.SaveFileHeader(); + p.SetPixelType(UnsignedByte); + p.SetByteOrder(Lsb); + p.SetDataSuffixBytes(136); + + p.SetInputFile (ui.GetFilename("FROM")); + Cube *oCube = p.SetOutputCube("TO"); + + p.StartProcess (); + unsigned char *header = (unsigned char *) p.FileHeader(); + string labels = EbcdicToAscii(header); + UpdateLabels(oCube, labels); + p.EndProcess (); + } + // Import for Isis 2 cubes + else { + ProcessImportPds p; + + // All mariner images from both cameras share this size + p.SetDimensions(832,700,1); + p.SetPixelType(UnsignedByte); + p.SetByteOrder(Lsb); + p.SetDataSuffixBytes(136); + + p.SetPdsFile (inputFile.Expanded(), "", label); + Cube *oCube = p.SetOutputCube("TO"); + + TranslateIsis2Labels(inputFile, oCube); + p.StartProcess (); + p.EndProcess (); + } +} + +// Converts labels into standard pvl format and adds necessary +// information not included in original labels +void UpdateLabels (Cube *cube, const string &labels) { + // First, we parse out as much valid information as possible from the + // original labels + string key; + int keyPosition; + int consumeChars; + + // Image number + key = "FDS="; + keyPosition = labels.find(key); + consumeChars = labels.find("IM-1") - keyPosition - key.length(); + iString fds (labels.substr(keyPosition + key.length(), consumeChars)); + fds.Trim(" "); + + // Year the image was taken + key = "YR="; + keyPosition = labels.find(key); + consumeChars = labels.find("DAY") - keyPosition - key.length(); + iString yr (labels.substr(keyPosition + key.length(), consumeChars)); + yr.Trim(" "); + + // Day the image was taken + key = "DAY="; + keyPosition = labels.find(key); + consumeChars = labels.find("GMT") - keyPosition - key.length(); + iString day (labels.substr(keyPosition + key.length(), consumeChars)); + day.Trim(" "); + + // Greenwich Mean Time + key = "GMT="; + keyPosition = labels.find(key); + consumeChars = labels.find("CCAMERA") - keyPosition - key.length(); + iString gmt (labels.substr(keyPosition + key.length(), consumeChars)); + gmt.Trim(" "); + + // Which of the two cameras took the image + key = "CCAMERA="; + keyPosition = labels.find(key); + consumeChars = labels.find("FILTER") - keyPosition - key.length(); + iString ccamera (labels.substr(keyPosition + key.length(), consumeChars)); + ccamera.Trim(" "); + + // Filter number + key = "FILTER="; + keyPosition = labels.find(key); + consumeChars = labels.find("(") - keyPosition - key.length(); + iString filterNum (labels.substr(keyPosition + key.length(), consumeChars)); + filterNum.Trim(" "); + + // Filter name + consumeChars = labels.find(")") - keyPosition - key.length() - consumeChars; + iString filterName (labels.substr(labels.find("(") + 1, consumeChars)); + filterName.Trim(" "); + + // Center wavelength + int fnum = filterNum.ToInteger(); + double filterCenter = 0.; + switch (fnum) { + case 0: + filterCenter = .575; + break; + case 2: + filterCenter = .475; + break; + case 3: + filterCenter = .360; + break; + case 4: + filterCenter = .511; + break; + case 5: + filterCenter = .487; + break; + case 6: + filterCenter = .355; + break; + default: + break; + } + + // Exposure duration + key = "EXPOSURE="; + keyPosition = labels.find(key); + consumeChars = labels.find("MSEC") - keyPosition - key.length(); + iString exposure (labels.substr(keyPosition + key.length(), consumeChars)); + exposure.Trim(" "); + + // Create the instrument group + PvlGroup inst("Instrument"); + inst += PvlKeyword("SpacecraftName","Mariner_10"); + inst += PvlKeyword("InstrumentId","M10_VIDICON_" + ccamera); + + // Get the date + int days = day.ToInteger(); + iString date = DaysToDate(days); + + // Get the time + iString time = gmt; + time = time.Replace("/",":"); + + // Construct the Start Time in yyyy-mm-ddThh:mm:ss format + string fullTime = date + "T" + time + ".000"; + iTime startTime(fullTime); + + // Create the archive group + PvlGroup archive ("Archive"); + + int year = yr.ToInteger(); + year += 1900; + string fullGMT = iString(year) + ":" + day + ":" + time; + archive += PvlKeyword ("GMT", fullGMT); + archive += PvlKeyword ("ImageNumber", fds); + + // Create the band bin group + PvlGroup bandBin("BandBin"); + iString filter = filterName; + filter = filter.Replace(")",""); + bandBin += PvlKeyword("FilterName", filter); + iString number = filterNum; + bandBin += PvlKeyword("FilterNumber", number); + bandBin += PvlKeyword("OriginalBand", "1"); + iString center = filterCenter; + bandBin += PvlKeyword("Center", center); + bandBin.FindKeyword("Center").SetUnits("micrometers"); + + // Dates taken from ASU Mariner website - http://ser.ses.asu.edu/M10/TXT/encounters.html and + // from Nasa website - http://www.jpl.nasa.gov/missions/missiondetails.cfm?mission_Mariner10 + // under fast facts. Mariner encountered the Moon, Venus, and Mercury three times. + // Date used for all is two days before date of first encounter on website. Information + // is important for nominal reseaus used and for Keyword encounter + string target = ""; + if (startTime < iTime("1974-2-3T12:00:00")) { + target = "$mariner10/reseaus/mar10MoonNominal.pvl"; + inst += PvlKeyword("TargetName", "Moon"); + archive += PvlKeyword ("Encounter", "Moon"); + } + //Disagreement on the below date between ASU website and NASA website, used earlier of the two - ASU + else if (startTime < iTime("1974-3-22T12:00:00")) { + target = "$mariner10/reseaus/mar10VenusNominal.pvl"; + inst += PvlKeyword("TargetName", "Venus"); + archive += PvlKeyword ("Encounter", "Venus"); + } + else if (startTime < iTime("1974-9-19T12:00:00")) { + target = "$mariner10/reseaus/mar10Merc1Nominal.pvl"; + inst += PvlKeyword("TargetName", "Mercury"); + archive += PvlKeyword ("Encounter", "Mercury_1"); + } + // No specific date on ASU website, used NASA date + else if (startTime < iTime("1975-3-14T12:00:00")) { + target = "$mariner10/reseaus/mar10Merc2Nominal.pvl"; + inst += PvlKeyword("TargetName", "Mercury"); + archive += PvlKeyword ("Encounter", "Mercury_2"); + } + else { + target = "$mariner10/reseaus/mar10Merc3Nominal.pvl"; + inst += PvlKeyword("TargetName", "Mercury"); + archive += PvlKeyword ("Encounter", "Mercury_3"); + } + + // Place start time and exposure duration in intrument group + inst += PvlKeyword("StartTime", fullTime); + inst += PvlKeyword("ExposureDuration", exposure, "milliseconds"); + + // Open nominal positions pvl named by string encounter + Pvl nomRx (target); + + // Allocate all keywords within reseaus groups well as the group its self + PvlGroup rx("Reseaus"); + PvlKeyword line("Line"); + PvlKeyword sample("Sample"); + PvlKeyword type("Type"); + PvlKeyword valid("Valid"); + PvlKeyword templ("Template"); + PvlKeyword status("Status"); + + // All cubes will stay this way until findrx is run on them + status = "Nominal"; + + // Kernels group + PvlGroup kernels("Kernels"); + PvlKeyword naif("NaifFrameCode"); + + // Camera dependent information + string camera = ""; + if (iString("M10_VIDICON_A") == inst["InstrumentId"][0]) { + templ = "$mariner10/reseaus/mar10a.template.cub"; + naif += "-76110"; + camera = "M10_VIDICON_A_RESEAUS"; + } + else { + templ = "$mariner10/reseaus/mar10b.template.cub"; + naif += "-76120"; + camera = "M10_VIDICON_B_RESEAUS"; + } + + // Add naif frame code + kernels += naif; + + // Find the correct PvlKeyword corresponding to the camera for nominal positions + PvlKeyword resnom = nomRx[camera]; + + // This loop goes through the PvlKeyword resnom which contains data + // in the format: line, sample, type, on each line. There are 111 reseaus for + // both cameras. To put data away correctly, it must go through a total 333 items, + // all in one PvlKeyword. + int i = 0; + while (i < 333) { + line += resnom[i]; + i++; + sample += resnom[i]; + i++; + type += resnom[i]; + i++; + valid += 0; + } + + // Add all the PvlKeywords to the PvlGroup Reseaus + rx += line; + rx += sample; + rx += type; + rx += valid; + rx += templ; + rx += status; + + // Get the labels and add the updated labels to them + Pvl *cubeLabels = cube->Label(); + cubeLabels->FindObject("IsisCube").AddGroup(inst); + cubeLabels->FindObject("IsisCube").AddGroup(archive); + cubeLabels->FindObject("IsisCube").AddGroup(bandBin); + cubeLabels->FindObject("IsisCube").AddGroup(kernels); + cubeLabels->FindObject("IsisCube").AddGroup(rx); + + PvlObject original ("OriginalLabel"); + original += PvlKeyword ("Label", labels); + cubeLabels->AddObject(original); +} + +// Translate Isis 2 labels into Isis 3 labels. +void TranslateIsis2Labels (Filename &labelFile, Cube *oCube) { + // Get the directory where the Mariner translation tables are. + PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory"); + + // Transfer the instrument group to the output cube + iString transDir = (string) dataDir["Mariner10"] + "/translations/"; + Pvl inputLabel (labelFile.Expanded()); + Filename transFile; + + transFile = transDir + "mariner10isis2.trn"; + + // Get the translation manager ready + PvlTranslationManager translation (inputLabel, transFile.Expanded()); + Pvl *outputLabel = oCube->Label(); + translation.Auto(*(outputLabel)); + + //Instrument group + PvlGroup &inst = outputLabel->FindGroup("Instrument", Pvl::Traverse); + + PvlKeyword &instrumentId = inst.FindKeyword("InstrumentId"); + instrumentId.SetValue("M10_VIDICON_" + instrumentId[0]); + + PvlKeyword &targetName = inst.FindKeyword("TargetName"); + iString targetTail (targetName[0].substr(1)); + targetTail = targetTail.DownCase(); + targetName.SetValue( targetName[0].at(0) + targetTail ); + + PvlKeyword &startTime = inst.FindKeyword("StartTime"); + startTime.SetValue( startTime[0].substr(0, startTime[0].size()-1)); + + PvlGroup &archive = outputLabel->FindGroup("Archive", Pvl::Traverse); + PvlKeyword &imgNo = archive.FindKeyword("ImageNumber"); + iString ino = imgNo[0]; + ino.Trim(" "); + imgNo.SetValue(ino); + + iTime time (startTime[0]); + if (time < iTime("1974-2-3T12:00:00")) { + archive += PvlKeyword ("Encounter", "Moon"); + } + else if (time < iTime("1974-3-22T12:00:00")) { + archive += PvlKeyword ("Encounter", "Venus"); + } + else if (time < iTime("1974-9-19T12:00:00")) { + archive += PvlKeyword ("Encounter", "Mercury_1"); + } + else if (time < iTime("1975-3-14T12:00:00")) { + archive += PvlKeyword ("Encounter", "Mercury_2"); + } + else { + archive += PvlKeyword ("Encounter", "Mercury_3"); + } + + inst.FindKeyword("ExposureDuration").SetUnits("milliseconds"); + + PvlGroup &bBin = outputLabel->FindGroup ("BandBin", Pvl::Traverse); + std::string filter = inputLabel.FindObject("QUBE")["FILTER_NAME"]; + if (filter != "F") { + //Band Bin group + bBin.FindKeyword("Center").SetUnits("micrometers"); + } + + // Kernels group + PvlGroup &kernels = outputLabel->FindGroup ("Kernels", Pvl::Traverse); + PvlGroup &reseaus = outputLabel->FindGroup ("Reseaus", Pvl::Traverse); + PvlKeyword &templ = reseaus.FindKeyword("Template"); + PvlKeyword &valid = reseaus.FindKeyword("Valid"); + + for (int i = 0; i < valid.Size(); i++) { + valid[i] = valid[i].substr(0, 1); + } + + // Camera dependent information + string camera = ""; + if (iString("M10_VIDICON_A") == inst["InstrumentId"][0]) { + templ = "$mariner10/reseaus/mar10a.template.cub"; + kernels.FindKeyword("NaifFrameCode").SetValue("-76110"); + camera = "M10_VIDICON_A_RESEAUS"; + } + else { + templ = "$mariner10/reseaus/mar10b.template.cub"; + kernels.FindKeyword("NaifFrameCode").SetValue("-76120"); + camera = "M10_VIDICON_B_RESEAUS"; + } +} + +// FYI, mariner10 original labels are stored in ebcdic, a competitor with ascii, +// a conversion table is necessary then to get the characters over to ascii. For +// more info: http://en.wikipedia.org/wiki/Extended_Binary_Coded_Decimal_Interchange_Code +//! Converts ebsidic Mariner10 labels to ascii +string EbcdicToAscii (unsigned char *header) { + // Table to convert ebcdic to ascii + unsigned char xlate[] = { + 0x00,0x01,0x02,0x03,0x9C,0x09,0x86,0x7F,0x97,0x8D,0x8E,0x0B,0x0C,0x0D,0x0E,0x0F, + 0x10,0x11,0x12,0x13,0x9D,0x85,0x08,0x87,0x18,0x19,0x92,0x8F,0x1C,0x1D,0x1E,0x1F, + 0x80,0x81,0x82,0x83,0x84,0x0A,0x17,0x1B,0x88,0x89,0x8A,0x8B,0x8C,0x05,0x06,0x07, + 0x90,0x91,0x16,0x93,0x94,0x95,0x96,0x04,0x98,0x99,0x9A,0x9B,0x14,0x15,0x9E,0x1A, + 0x20,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xD5,0x2E,0x3C,0x28,0x2B,0x7C, + 0x26,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0x21,0x24,0x2A,0x29,0x3B,0x5E, + 0x2D,0x2F,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xE5,0x2C,0x25,0x5F,0x3E,0x3F, + 0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0x60,0x3A,0x23,0x40,0x27,0x3D,0x22, + 0xC3,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9, + 0xCA,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0, + 0xD1,0x7E,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0xD2,0xD3,0xD4,0x5B,0xD6,0xD7, + 0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0x5D,0xE6,0xE7, + 0x7B,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0xE8,0xE9,0xEA,0xEB,0xEC,0xED, + 0x7D,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3, + 0x5C,0x9F,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF + }; + + // Mariner 10 has 360 bytes of header information + for (int i=0; i<360; i++) { + header[i] = xlate[header[i]]; + } + + // Put in a end of string mark and return + header[215] = 0; + printf("Header: %s\n", header); + return string((const char *)header); +} + +// Mariner 10 labels provide the number of days since the beginning of the year +// 1974 in the GMT keyword, but not always a start time. In order to derive an +// estimated start time, with an actual date attached, a conversion must be +// performed. +string DaysToDate (int days) { + int currentMonth = 12; + int currentDay = 31; + int currentYear = 1973; + while (days > 0) { + // The Mariner 10 mission took place in the years 1973 through 1975, + // none of which were Leap Years, thus February always had 28 days + if (currentDay == 28 && currentMonth == 2) { + currentMonth = 3; + currentDay = 1; + } + else if (currentDay == 30 && + (currentMonth == 4 || currentMonth == 6 || + currentMonth == 9 || currentMonth == 11)) { + currentMonth++; + currentDay = 1; + } + else if (currentDay == 31 && currentMonth == 12) { + currentMonth = 1; + currentDay = 1; + currentYear++; + } + else if (currentDay == 31) { + currentMonth++; + currentDay = 1; + } + else { + currentDay++; + } + days--; + } + iString year = currentYear; + iString month = (currentMonth < 10) ? "0" + iString(currentMonth) : iString(currentMonth); + iString day = (currentDay < 10) ? "0" + iString(currentDay) : iString(currentDay); + return year + "-" + month + "-" + day; +} diff --git a/isis/src/mariner/apps/mar102isis/mar102isis.xml b/isis/src/mariner/apps/mar102isis/mar102isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..46871f21641141bb343db3e3f2ff9df44fa7db82 --- /dev/null +++ b/isis/src/mariner/apps/mar102isis/mar102isis.xml @@ -0,0 +1,130 @@ + + + + + + Convert Mariner10 images to Isis cubes. + + + + Converts raw mariner10 images to Isis cubes. This includes converting labels + and adding the group reseaus, and which encounter the image is specific to. + + + + Mariner + + + + + raw2isis + + + + + + Original version + + + Made several additions to labels including reseaus, and NaifFrameCode, + added to repository. + + + Added compatibility for importing Isis 2 cubes. + + + Fixed consistency errors between RAW and Isis2 imports. + + + Changed SpacecraftName from Mariner10 to Mariner_10. + + + + + + + filename + input + + Input file to be converted to an Isis cube + + + The raw Mariner10 image to be converted to an Isis cube with complete + labels. + + + + + cube + output + + Output cube + + + The resultant cube containing the Mariner10 image. + + + *.cub + + + + + + + + + Mariner10 image imported + + + This example shows the simple process of importing a Mariner10 image. + + + + from=MVE_002.117 to=imported.cub + + + The command line argument needed to execut an import of a Mariner10 + image. + + + + + + + A raw Mariner10 image + + + This is a raw Mariner10 image to be imported. + + FROM + + + + + + + The imported ouput + + + This is the Mariner10 image, now imported and in cube format. + + + TO + + + + + + + Example Gui + + Screenshot of GUI with parameters filled in to with a mariner10 raw image as input and a cube as output. + + + + + + + + + diff --git a/isis/src/mariner/apps/mar102isis/tsts/Makefile b/isis/src/mariner/apps/mar102isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mariner/apps/mar102isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mariner/apps/mar102isis/tsts/default/Makefile b/isis/src/mariner/apps/mar102isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7c9c1a89f7dfbfe5d86fa76a50c7f2e772b54653 --- /dev/null +++ b/isis/src/mariner/apps/mar102isis/tsts/default/Makefile @@ -0,0 +1,10 @@ +APPNAME = mar102isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/MVE_002.117 to=$(OUTPUT)/MVE_002.117.cub \ + > /dev/null; + catlab from=$(OUTPUT)/MVE_002.117.cub to=$(OUTPUT)/MVE_002.117.pvl \ + > /dev/null; + rm $(OUTPUT)/MVE_002.117.cub; diff --git a/isis/src/mariner/apps/mar102isis/tsts/isis2/Makefile b/isis/src/mariner/apps/mar102isis/tsts/isis2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0ea90194b13771794237fce62344b6d6ac3a7186 --- /dev/null +++ b/isis/src/mariner/apps/mar102isis/tsts/isis2/Makefile @@ -0,0 +1,10 @@ +APPNAME = mar102isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/0027438.cub to=$(OUTPUT)/0027438_isis3.cub \ + > /dev/null; + catlab from=$(OUTPUT)/0027438_isis3.cub to=$(OUTPUT)/0027438_isis3.pvl \ + > /dev/null; + rm $(OUTPUT)/0027438_isis3.cub; diff --git a/isis/src/mariner/apps/mar10clean/Makefile b/isis/src/mariner/apps/mar10clean/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mariner/apps/mar10clean/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mariner/apps/mar10clean/assets/images/clean.jpg b/isis/src/mariner/apps/mar10clean/assets/images/clean.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7b67908fe813f3203ebfe6568dc7097a1b718566 Binary files /dev/null and b/isis/src/mariner/apps/mar10clean/assets/images/clean.jpg differ diff --git a/isis/src/mariner/apps/mar10clean/assets/images/cleanGUI.jpg b/isis/src/mariner/apps/mar10clean/assets/images/cleanGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4fd3708842b1c070741e9059b81bc5df1b845820 Binary files /dev/null and b/isis/src/mariner/apps/mar10clean/assets/images/cleanGUI.jpg differ diff --git a/isis/src/mariner/apps/mar10clean/assets/images/input.jpg b/isis/src/mariner/apps/mar10clean/assets/images/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e43cf8768586d79a3b2b9cc604448ddafcc0231f Binary files /dev/null and b/isis/src/mariner/apps/mar10clean/assets/images/input.jpg differ diff --git a/isis/src/mariner/apps/mar10clean/assets/thumbs/clean.jpg b/isis/src/mariner/apps/mar10clean/assets/thumbs/clean.jpg new file mode 100644 index 0000000000000000000000000000000000000000..492cdf8718a46721c2b37db588b564bfdfb1aa41 Binary files /dev/null and b/isis/src/mariner/apps/mar10clean/assets/thumbs/clean.jpg differ diff --git a/isis/src/mariner/apps/mar10clean/assets/thumbs/cleanGUI.jpg b/isis/src/mariner/apps/mar10clean/assets/thumbs/cleanGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..83f5111b8f5d84c6be02c062709a22cde4dc9375 Binary files /dev/null and b/isis/src/mariner/apps/mar10clean/assets/thumbs/cleanGUI.jpg differ diff --git a/isis/src/mariner/apps/mar10clean/assets/thumbs/input.jpg b/isis/src/mariner/apps/mar10clean/assets/thumbs/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..54b7fc86769b4c21b4dfe490687ea2e709127c8f Binary files /dev/null and b/isis/src/mariner/apps/mar10clean/assets/thumbs/input.jpg differ diff --git a/isis/src/mariner/apps/mar10clean/mar10clean.cpp b/isis/src/mariner/apps/mar10clean/mar10clean.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1121b33a4e9024647521990afe2b26d4cbfa34f2 --- /dev/null +++ b/isis/src/mariner/apps/mar10clean/mar10clean.cpp @@ -0,0 +1,61 @@ +#include "Isis.h" + +#include "Pipeline.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + + // Open the input cube + UserInterface &ui = Application::GetUserInterface(); + Pipeline p("mar10clean"); + p.SetInputFile("FROM"); + p.SetOutputFile("TO"); + p.KeepTemporaryFiles(!ui.GetBoolean("REMOVE")); + + // Run mar10nonoise to remove noise + p.AddToPipeline("mar10nonoise"); + p.Application("mar10nonoise").SetInputParameter("FROM", true); + p.Application("mar10nonoise").SetOutputParameter("TO", "mar10nonoise"); + + // Run findrx on the cube to find the actual position of the reseaus + p.AddToPipeline("findrx"); + p.Application("findrx").SetInputParameter("FROM", true); + + // Run remrx on the cube to remove the reseaus + p.AddToPipeline("remrx"); + p.Application("remrx").SetInputParameter("FROM", true); + p.Application("remrx").SetOutputParameter("TO", "remrx"); + p.Application("remrx").AddParameter("SDIM", "SDIM"); + p.Application("remrx").AddParameter("LDIM", "LDIM"); + + // Run a low pass filter on the null data in the cube + p.AddToPipeline("lowpass", "pass1"); + p.Application("pass1").SetInputParameter("FROM", true); + p.Application("pass1").SetOutputParameter("TO", "lowpass1"); + p.Application("pass1").AddConstParameter("SAMP", "3"); + p.Application("pass1").AddConstParameter("LINE", "3"); + p.Application("pass1").AddConstParameter("MINIMUM", "4"); + p.Application("pass1").AddConstParameter("FILTER", "outside"); + + // Run a low pass filter on the null data in the cube + p.AddToPipeline("lowpass", "pass2"); + p.Application("pass2").SetInputParameter("FROM", true); + p.Application("pass2").SetOutputParameter("TO", "lowpass2"); + p.Application("pass2").AddConstParameter("SAMP", "3"); + p.Application("pass2").AddConstParameter("LINE", "3"); + p.Application("pass2").AddConstParameter("MINIMUM", "4"); + p.Application("pass2").AddConstParameter("FILTER", "outside"); + + // Run trim to remove data outside of visual frame + p.AddToPipeline("trim"); + p.Application("trim").SetInputParameter("FROM", true); + p.Application("trim").SetOutputParameter("TO", "trim"); + p.Application("trim").AddConstParameter("TOP", "5"); + p.Application("trim").AddConstParameter("LEFT", "11"); + p.Application("trim").AddConstParameter("RIGHT", "8"); + + p.Run(); +} + diff --git a/isis/src/mariner/apps/mar10clean/mar10clean.xml b/isis/src/mariner/apps/mar10clean/mar10clean.xml new file mode 100644 index 0000000000000000000000000000000000000000..0db970db31ea648660bb9123d00376aeb4de6fec --- /dev/null +++ b/isis/src/mariner/apps/mar10clean/mar10clean.xml @@ -0,0 +1,176 @@ + + + + + Clean-up of Mariner10 images + + + + This program performs the clean up of Mariner10 images. This includes salt + and pepper noise, removing reseaus, and trimming edges of invalid data. + + + + Mariner + + + + + findrx + remrx + trim + mar10nonoise + + + + + + Original version + + + Added example, test + + + Modified order of runs to remove noise before finding and removing + reseaus. + + + + + + + cube + input + + Input file to be cleaned + + + The cube to be cleaned. The cube will be run through a series of + filters to remove salt and pepper noise and reseaus. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the clean data. + + + *.cub + + + + + + + boolean + + Remove intermediate files + + + Option to remove or leave intermediate cube files made by the + application. + + TRUE + + + + integer + + Number of Samples to Remove around each Reseau + + + This number will be used in the remrx step of the clean up. It is + the number of samples to remove around each reseau. + + 9 + + + + integer + + Number of Lines to Remove around each Reseau + + + This number will be used in the remrx step of the clean up. It is + the number of lines to remove around each reseau. + + 9 + + + + + + + + + Input Mariner10 Image to be cleaned + + + This example shows the application in action. It removes all salt and + pepper noise as well as reseaus. + + + + from=MVE_030.227.cub to=clean.cub + + + Input a Mariner10 unclead image to from and output a cleaned image to + to. + + + + + + + Mariner10 Image to Clean + + + This is the input Mariner10 image prior to cleaning. + + + FROM + + + + + + + Cleaned Mariner10 Image + + + This is the Mariner10 image after the cleaning sequence has taken + place. + + + TO + + + + + + + + Example Gui + + + Screenshot of GUI with parameters filled in to with a Mariner10 + uncleaned cube as input and a clean cube as output. + + + + + + + + + + + diff --git a/isis/src/mariner/apps/mar10clean/tsts/Makefile b/isis/src/mariner/apps/mar10clean/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mariner/apps/mar10clean/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mariner/apps/mar10clean/tsts/default/Makefile b/isis/src/mariner/apps/mar10clean/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3140dceed5704ff25edee6e7026011d4bac21e7c --- /dev/null +++ b/isis/src/mariner/apps/mar10clean/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = mar10clean + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/MVE_030.227.cub to=$(OUTPUT)/cleanTruth.cub \ + > /dev/null; diff --git a/isis/src/mariner/apps/mar10nonoise/Makefile b/isis/src/mariner/apps/mar10nonoise/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mariner/apps/mar10nonoise/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mariner/apps/mar10nonoise/assets/images/input.jpg b/isis/src/mariner/apps/mar10nonoise/assets/images/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e43cf8768586d79a3b2b9cc604448ddafcc0231f Binary files /dev/null and b/isis/src/mariner/apps/mar10nonoise/assets/images/input.jpg differ diff --git a/isis/src/mariner/apps/mar10nonoise/assets/images/nonoise.png b/isis/src/mariner/apps/mar10nonoise/assets/images/nonoise.png new file mode 100644 index 0000000000000000000000000000000000000000..381568b4ad25acde6f662eac7e8d736a0a16de9d Binary files /dev/null and b/isis/src/mariner/apps/mar10nonoise/assets/images/nonoise.png differ diff --git a/isis/src/mariner/apps/mar10nonoise/assets/images/nonoiseGUI.jpg b/isis/src/mariner/apps/mar10nonoise/assets/images/nonoiseGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..69282b0651802ea48463993e67206affa666a3b5 Binary files /dev/null and b/isis/src/mariner/apps/mar10nonoise/assets/images/nonoiseGUI.jpg differ diff --git a/isis/src/mariner/apps/mar10nonoise/assets/thumbs/input.jpg b/isis/src/mariner/apps/mar10nonoise/assets/thumbs/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..54b7fc86769b4c21b4dfe490687ea2e709127c8f Binary files /dev/null and b/isis/src/mariner/apps/mar10nonoise/assets/thumbs/input.jpg differ diff --git a/isis/src/mariner/apps/mar10nonoise/assets/thumbs/nonoise.png b/isis/src/mariner/apps/mar10nonoise/assets/thumbs/nonoise.png new file mode 100644 index 0000000000000000000000000000000000000000..313145bf607123f41fbde6ea98d7dddf11451b95 Binary files /dev/null and b/isis/src/mariner/apps/mar10nonoise/assets/thumbs/nonoise.png differ diff --git a/isis/src/mariner/apps/mar10nonoise/assets/thumbs/nonoiseGUI.jpg b/isis/src/mariner/apps/mar10nonoise/assets/thumbs/nonoiseGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4ce162483a5e97c2df76ac05a633c0c84b366efc Binary files /dev/null and b/isis/src/mariner/apps/mar10nonoise/assets/thumbs/nonoiseGUI.jpg differ diff --git a/isis/src/mariner/apps/mar10nonoise/mar10nonoise.cpp b/isis/src/mariner/apps/mar10nonoise/mar10nonoise.cpp new file mode 100644 index 0000000000000000000000000000000000000000..860ec1a199eb08421a15b3915a646ea419bea778 --- /dev/null +++ b/isis/src/mariner/apps/mar10nonoise/mar10nonoise.cpp @@ -0,0 +1,94 @@ + +#include "Isis.h" + +#include "Pipeline.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + + // Open the input cube + UserInterface &ui = Application::GetUserInterface(); + Pipeline p("mar10nonoise"); + p.SetInputFile("FROM"); + p.SetOutputFile("TO"); + p.KeepTemporaryFiles(!ui.GetBoolean("REMOVE")); + + // Salt filter 1 + p.AddToPipeline("noisefilter", "saltRemoval1"); + p.Application("saltRemoval1").SetInputParameter("FROM", true); + p.Application("saltRemoval1").SetOutputParameter("TO", "1salt1"); + p.Application("saltRemoval1").AddConstParameter("SAMP", "3"); + p.Application("saltRemoval1").AddConstParameter("LINE", "3"); + p.Application("saltRemoval1").AddConstParameter("MINIMUM", "4"); + p.Application("saltRemoval1").AddConstParameter("TOLMIN", "300"); + p.Application("saltRemoval1").AddConstParameter("TOLMAX", "35"); + p.Application("saltRemoval1").AddConstParameter("REPLACE", "null"); + + // Pepper filter 1 + p.AddToPipeline("noisefilter", "pepperRemoval1"); + p.Application("pepperRemoval1").SetInputParameter("FROM", true); + p.Application("pepperRemoval1").SetOutputParameter("TO", "2pepp1"); + p.Application("pepperRemoval1").AddConstParameter("SAMP", "3"); + p.Application("pepperRemoval1").AddConstParameter("LINE", "3"); + p.Application("pepperRemoval1").AddConstParameter("MINIMUM", "4"); + p.Application("pepperRemoval1").AddConstParameter("TOLMIN", "30"); + p.Application("pepperRemoval1").AddConstParameter("TOLMAX", "300"); + p.Application("pepperRemoval1").AddConstParameter("REPLACE", "null"); + + // Salt filter 2 + p.AddToPipeline("noisefilter", "saltRemoval2"); + p.Application("saltRemoval2").SetInputParameter("FROM", true); + p.Application("saltRemoval2").SetOutputParameter("TO", "3salt2"); + p.Application("saltRemoval2").AddConstParameter("SAMP", "3"); + p.Application("saltRemoval2").AddConstParameter("LINE", "3"); + p.Application("saltRemoval2").AddConstParameter("TOLDEF", "stddev"); + p.Application("saltRemoval2").AddConstParameter("FLATTOL", "15"); + p.Application("saltRemoval2").AddConstParameter("MINIMUM", "4"); + p.Application("saltRemoval2").AddConstParameter("TOLMIN", "300"); + p.Application("saltRemoval2").AddConstParameter("TOLMAX", "2"); + p.Application("saltRemoval2").AddConstParameter("REPLACE", "null"); + + // Pepper filter 2 + p.AddToPipeline("noisefilter", "pepperRemoval2"); + p.Application("pepperRemoval2").SetInputParameter("FROM", true); + p.Application("pepperRemoval2").SetOutputParameter("TO", "4pepp2"); + p.Application("pepperRemoval2").AddConstParameter("SAMP", "3"); + p.Application("pepperRemoval2").AddConstParameter("LINE", "3"); + p.Application("pepperRemoval2").AddConstParameter("TOLDEF", "stddev"); + p.Application("pepperRemoval2").AddConstParameter("FLATTOL", "15"); + p.Application("pepperRemoval2").AddConstParameter("MINIMUM", "4"); + p.Application("pepperRemoval2").AddConstParameter("TOLMIN", "2"); + p.Application("pepperRemoval2").AddConstParameter("TOLMAX", "300"); + p.Application("pepperRemoval2").AddConstParameter("REPLACE", "null"); + + // Salt filter 3 + p.AddToPipeline("noisefilter", "saltRemoval3"); + p.Application("saltRemoval3").SetInputParameter("FROM", true); + p.Application("saltRemoval3").SetOutputParameter("TO", "5salt3"); + p.Application("saltRemoval3").AddConstParameter("SAMP", "5"); + p.Application("saltRemoval3").AddConstParameter("LINE", "5"); + p.Application("saltRemoval3").AddConstParameter("TOLDEF", "stddev"); + p.Application("saltRemoval3").AddConstParameter("FLATTOL", "12"); + p.Application("saltRemoval3").AddConstParameter("MINIMUM", "15"); + p.Application("saltRemoval3").AddConstParameter("TOLMIN", "300"); + p.Application("saltRemoval3").AddConstParameter("TOLMAX", "1.9"); + p.Application("saltRemoval3").AddConstParameter("REPLACE", "null"); + + // Pepper filter 3 + p.AddToPipeline("noisefilter", "pepperRemoval3"); + p.Application("pepperRemoval3").SetInputParameter("FROM", true); + p.Application("pepperRemoval3").SetOutputParameter("TO", "6pepp3"); + p.Application("pepperRemoval3").AddConstParameter("SAMP", "5"); + p.Application("pepperRemoval3").AddConstParameter("LINE", "5"); + p.Application("pepperRemoval3").AddConstParameter("TOLDEF", "stddev"); + p.Application("pepperRemoval3").AddConstParameter("FLATTOL", "12"); + p.Application("pepperRemoval3").AddConstParameter("MINIMUM", "15"); + p.Application("pepperRemoval3").AddConstParameter("TOLMIN", "1.9"); + p.Application("pepperRemoval3").AddConstParameter("TOLMAX", "300"); + p.Application("pepperRemoval3").AddConstParameter("REPLACE", "null"); + + p.Run(); +} + diff --git a/isis/src/mariner/apps/mar10nonoise/mar10nonoise.xml b/isis/src/mariner/apps/mar10nonoise/mar10nonoise.xml new file mode 100644 index 0000000000000000000000000000000000000000..9a3210876fe887b771baff9f073b9bb43d68bd82 --- /dev/null +++ b/isis/src/mariner/apps/mar10nonoise/mar10nonoise.xml @@ -0,0 +1,141 @@ + + + + + Noise removal from Mariner10 images + + + + This program will remove noise from Mariner10 images. + + + + Mariner + + + + + mar10clean + noisefilter + + + + + + Original version + + + + + + + cube + input + + Input file to be cleaned + + + The cube to be cleaned. The cube will be ran through a series of filters to + remove pepper noise. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the cleaned data. + + + *.cub + + + + + + boolean + + Remove intermediate files + + + Option to remove or leave intermediate cube files made by the + application + + TRUE + + + + + + + + Input Mariner10 Image to have noise removed + + + This example shows the application in action. It removes most noise. + Noise is replaced with Isis::Null. + + + + from=MVE_030.227.cub to=nonoise.cub + + + An example of an uncleaned Mariner10 image for input and a noise + removed output cube. + + + + + + + + Example Gui + + + Screenshot of GUI with parameters filled in to with a Mariner10 + cube with noise as input and a noise removed cube as output. + + + + + + + + + + Mariner10 image to remove noise from + + + This is the input Mariner10 image prior to the removal of noise. + + + FROM + + + + + + + Output Image + + + This is the Mariner10 image after the application has been run. + The red represents null pixels which could be removed using a + lowpass or left as is. + + + TO + + + + + + + + diff --git a/isis/src/mariner/apps/mar10nonoise/tsts/Makefile b/isis/src/mariner/apps/mar10nonoise/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mariner/apps/mar10nonoise/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mariner/apps/mar10nonoise/tsts/default/Makefile b/isis/src/mariner/apps/mar10nonoise/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..15763ff5a2d7bc62c791c316a3fc3ec46cec5bd6 --- /dev/null +++ b/isis/src/mariner/apps/mar10nonoise/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = mar10nonoise + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/MVE_030.227.cub to=$(OUTPUT)/nonoiseTruth.cub \ + > /dev/null; diff --git a/isis/src/mariner/apps/mar10restore/Makefile b/isis/src/mariner/apps/mar10restore/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mariner/apps/mar10restore/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mariner/apps/mar10restore/assets/images/postRestore.jpg b/isis/src/mariner/apps/mar10restore/assets/images/postRestore.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f76116113d9e6c79ff868be5dc6a775110028acb Binary files /dev/null and b/isis/src/mariner/apps/mar10restore/assets/images/postRestore.jpg differ diff --git a/isis/src/mariner/apps/mar10restore/assets/images/preRestore.jpg b/isis/src/mariner/apps/mar10restore/assets/images/preRestore.jpg new file mode 100644 index 0000000000000000000000000000000000000000..26095bbf94f262a71dcaa94b98c2a587e3e00dc4 Binary files /dev/null and b/isis/src/mariner/apps/mar10restore/assets/images/preRestore.jpg differ diff --git a/isis/src/mariner/apps/mar10restore/assets/images/restoreGUI.jpg b/isis/src/mariner/apps/mar10restore/assets/images/restoreGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..01fa0c665fa617e8deaaff7c0fc4a45083b7f1f8 Binary files /dev/null and b/isis/src/mariner/apps/mar10restore/assets/images/restoreGUI.jpg differ diff --git a/isis/src/mariner/apps/mar10restore/assets/thumbs/postRestore.jpg b/isis/src/mariner/apps/mar10restore/assets/thumbs/postRestore.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9fd773425f85a8dbcbbeb1e1fcdc34d6a8109122 Binary files /dev/null and b/isis/src/mariner/apps/mar10restore/assets/thumbs/postRestore.jpg differ diff --git a/isis/src/mariner/apps/mar10restore/assets/thumbs/preRestore.jpg b/isis/src/mariner/apps/mar10restore/assets/thumbs/preRestore.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0beb48082779cd5085e4e96bece4db6740e3242e Binary files /dev/null and b/isis/src/mariner/apps/mar10restore/assets/thumbs/preRestore.jpg differ diff --git a/isis/src/mariner/apps/mar10restore/assets/thumbs/restoreGUI.jpg b/isis/src/mariner/apps/mar10restore/assets/thumbs/restoreGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9e07a1a6bd59a814d28920ac38c6ed6365db4dbe Binary files /dev/null and b/isis/src/mariner/apps/mar10restore/assets/thumbs/restoreGUI.jpg differ diff --git a/isis/src/mariner/apps/mar10restore/mar10restore.cpp b/isis/src/mariner/apps/mar10restore/mar10restore.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd4a01ac7d5714f3b9f822f0d1ceb156124a38e9 --- /dev/null +++ b/isis/src/mariner/apps/mar10restore/mar10restore.cpp @@ -0,0 +1,125 @@ +#include "Isis.h" +#include "Chip.h" +#include "Cube.h" +#include "iException.h" +#include "iString.h" +#include "Pipeline.h" +#include "Statistics.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + + UserInterface &ui = Application::GetUserInterface(); + Cube cube; + cube.Open(ui.GetFilename("FROM")); + + // Check that the cube actually needs reconstruction + Chip cp(5,5); + cp.TackCube(25,25); + cp.Load(cube); + Statistics *stats = cp.Statistics(); + if (stats->ValidPixels() > 8) { + string msg = "The cube [" + ui.GetFilename("FROM") + "] does not need reconstruction"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + delete stats; + stats = NULL; + + // Open the input cube + Pipeline p("mar10restore"); + p.SetInputFile("FROM"); + p.SetOutputFile("TO"); + p.KeepTemporaryFiles(!ui.GetBoolean("REMOVE")); + + // Run a standard deviation filter on the cube + p.AddToPipeline("noisefilter", "noise1"); + p.Application("noise1").SetInputParameter("FROM", true); + p.Application("noise1").SetOutputParameter("TO", "noise1"); + p.Application("noise1").AddConstParameter("TOLDEF", "stddev"); + p.Application("noise1").AddConstParameter("FLATTOL", "10"); + p.Application("noise1").AddConstParameter("SAMP", "5"); + p.Application("noise1").AddConstParameter("LINE", "5"); + p.Application("noise1").AddConstParameter("MINIMUM", "4"); + p.Application("noise1").AddConstParameter("TOLMIN", "2.0"); + p.Application("noise1").AddConstParameter("TOLMAX", "1.5"); + p.Application("noise1").AddConstParameter("REPLACE", "null"); + + // run a standard deviation filter on the cube + p.AddToPipeline("noisefilter", "noise2"); + p.Application("noise2").SetInputParameter("FROM", true); + p.Application("noise2").SetOutputParameter("TO", "noise2"); + p.Application("noise2").AddConstParameter("TOLDEF", "stddev"); + p.Application("noise2").AddConstParameter("FLATTOL", "10"); + p.Application("noise2").AddConstParameter("SAMP", "11"); + p.Application("noise2").AddConstParameter("LINE", "11"); + p.Application("noise2").AddConstParameter("MINIMUM", "9"); + p.Application("noise2").AddConstParameter("TOLMIN", "100"); + p.Application("noise2").AddConstParameter("TOLMAX", "2.0"); + p.Application("noise2").AddConstParameter("REPLACE", "null"); + + // Run a standard deviation filter on the cube + p.AddToPipeline("noisefilter", "noise3"); + p.Application("noise3").SetInputParameter("FROM", true); + p.Application("noise3").SetOutputParameter("TO", "noise3"); + p.Application("noise3").AddConstParameter("TOLDEF", "stddev"); + p.Application("noise3").AddConstParameter("FLATTOL", "10"); + p.Application("noise3").AddConstParameter("SAMP", "7"); + p.Application("noise3").AddConstParameter("LINE", "7"); + p.Application("noise3").AddConstParameter("MINIMUM", "4"); + p.Application("noise3").AddConstParameter("TOLMIN", "100"); + p.Application("noise3").AddConstParameter("TOLMAX", "1.5"); + p.Application("noise3").AddConstParameter("REPLACE", "null"); + + // Run a low pass filter on the invalid data in the cube + p.AddToPipeline("lowpass", "lowpass1"); + p.Application("lowpass1").SetInputParameter("FROM", true); + p.Application("lowpass1").SetOutputParameter("TO", "lp1"); + p.Application("lowpass1").AddConstParameter("SAMP", "3"); + p.Application("lowpass1").AddConstParameter("LINE", "3"); + p.Application("lowpass1").AddConstParameter("MINIMUM", "2"); + p.Application("lowpass1").AddConstParameter("FILTER", "outside"); + p.Application("lowpass1").AddConstParameter("NULL", "true"); + p.Application("lowpass1").AddConstParameter("LIS", "true"); + p.Application("lowpass1").AddConstParameter("HIS", "true"); + p.Application("lowpass1").AddConstParameter("LRS", "true"); + + // Run a low pass filter on the invalid data in the cube + p.AddToPipeline("lowpass", "lowpass2"); + p.Application("lowpass2").SetInputParameter("FROM", true); + p.Application("lowpass2").SetOutputParameter("TO", "lp2"); + p.Application("lowpass2").AddConstParameter("SAMP", "3"); + p.Application("lowpass2").AddConstParameter("LINE", "3"); + p.Application("lowpass2").AddConstParameter("MINIMUM", "2"); + p.Application("lowpass2").AddConstParameter("FILTER", "outside"); + p.Application("lowpass2").AddConstParameter("NULL", "true"); + p.Application("lowpass2").AddConstParameter("LIS", "true"); + p.Application("lowpass2").AddConstParameter("HIS", "true"); + p.Application("lowpass2").AddConstParameter("LRS", "true"); + + // Run a low pass filter on the invalid data in the cube + p.AddToPipeline("lowpass", "lowpass3"); + p.Application("lowpass3").SetInputParameter("FROM", true); + p.Application("lowpass3").SetOutputParameter("TO", "lp3"); + p.Application("lowpass3").AddConstParameter("SAMP", "3"); + p.Application("lowpass3").AddConstParameter("LINE", "3"); + p.Application("lowpass3").AddConstParameter("MINIMUM", "2"); + p.Application("lowpass3").AddConstParameter("FILTER", "outside"); + p.Application("lowpass3").AddConstParameter("NULL", "true"); + p.Application("lowpass3").AddConstParameter("LIS", "true"); + p.Application("lowpass3").AddConstParameter("HIS", "true"); + p.Application("lowpass3").AddConstParameter("LRS", "true"); + + p.AddToPipeline("trim"); + p.Application("trim").SetInputParameter("FROM", true); + p.Application("trim").SetOutputParameter("TO", "trim"); + p.Application("trim").AddConstParameter("LEFT", 15); + p.Application("trim").AddConstParameter("RIGHT", 5); + p.Application("trim").AddConstParameter("BOTTOM", 0); + p.Application("trim").AddConstParameter("TOP", 5); + + p.Run(); +} + + diff --git a/isis/src/mariner/apps/mar10restore/mar10restore.xml b/isis/src/mariner/apps/mar10restore/mar10restore.xml new file mode 100644 index 0000000000000000000000000000000000000000..5c8e2b2ee77128a89c97885364517c7c8ede7fe1 --- /dev/null +++ b/isis/src/mariner/apps/mar10restore/mar10restore.xml @@ -0,0 +1,146 @@ + + + + + Restoration of Mariner10 compress images + + + + This application makes full images out of previously compressed images. The + compressed images don't appear compressed when imported, they appear dark + because there are 3/4 nulls. By removing noise and then averaging these + cubes a decent image can be produced. + + + + Mariner + + + + + noisefilter + lowpass + + + + + + Original version + + + Added trim to pipeline, updated documentation, added example, added test + + + + + + + cube + input + + Input file to be restored + + + An input file which needs reconstruction. + + + *.cub + + + + + cube + output + + Output cube + + + Reconstructed cube without null data. + + + *.cub + + + + + + + boolean + + Remove intermediate files + + + Option to remove or leave intermediate cube files made by the + application + + TRUE + + + + + + + + Input Mariner10 image to be restored + + + This image was originally transmitted compressed and now needs to be + restored. Restoration is imperfect as only a quarter of the original + data is present. + + + from=MVE_010.102.cub to=restored.cub + + + Arguments to input a Mariner10 image needing restoration + + + + + + + + Example Gui + + + Screenshot of GUI with parameters filled in to with a Mariner10 + cube needing restoration. + + + + + + + + + + Mariner10 image to be restored + + + This image will have noise removed and will have the significant + amount of null data filled in from the original data. + + + FROM + + + + + + + Restored Mariner10 image + + + A restored image after noise removal and averaging to fill in null + data. + + + TO + + + + + + + + diff --git a/isis/src/mariner/apps/mar10restore/tsts/Makefile b/isis/src/mariner/apps/mar10restore/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mariner/apps/mar10restore/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mariner/apps/mar10restore/tsts/default/Makefile b/isis/src/mariner/apps/mar10restore/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..47fff6dcdcedeef73874200093d61c58421eecee --- /dev/null +++ b/isis/src/mariner/apps/mar10restore/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = mar10restore + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/MVE_010.102.cub to=$(OUTPUT)/restoreTruth.cub \ + > /dev/null; diff --git a/isis/src/mariner/apps/mar10restore/tsts/error/Makefile b/isis/src/mariner/apps/mar10restore/tsts/error/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59a4ecb30471d824de7eab156520953dd71f891d --- /dev/null +++ b/isis/src/mariner/apps/mar10restore/tsts/error/Makefile @@ -0,0 +1,13 @@ +APPNAME = mar10restore + +include $(ISISROOT)/make/isismake.tsts + +commands: + if [ `$(APPNAME) from=$(INPUT)/isisTruth.cub to=$(OUTPUT)/fail.cub \ + >& $(OUTPUT)/output.txt` ]; \ + then \ + true; \ + fi; + $(CAT) $(OUTPUT)/output.txt | $(SED) s_\\[.\*\]_\[input/isisTruth.cub\]_ \ + | $(SED) 's_ in .*__' > $(OUTPUT)/error.txt; + rm -f $(OUTPUT)/output.txt > /dev/null; diff --git a/isis/src/mariner/objs/Makefile b/isis/src/mariner/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/mariner/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/mariner/objs/Mariner10Camera/Camera.plugin b/isis/src/mariner/objs/Mariner10Camera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..edcf18d4e00fa463feabcf2b013eba5893f94675 --- /dev/null +++ b/isis/src/mariner/objs/Mariner10Camera/Camera.plugin @@ -0,0 +1,11 @@ +Group = MARINER_10/M10_VIDICON_A + Version = 1 + Library = Mariner10Camera + Routine = Mariner10CameraPlugin +EndGroup +Group = MARINER_10/M10_VIDICON_B + Version = 1 + Library = Mariner10Camera + Routine = Mariner10CameraPlugin +EndGroup + diff --git a/isis/src/mariner/objs/Mariner10Camera/Makefile b/isis/src/mariner/objs/Mariner10Camera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b1b730c35b88af885e8cc5cb0dcf27188af0ffa --- /dev/null +++ b/isis/src/mariner/objs/Mariner10Camera/Makefile @@ -0,0 +1,5 @@ +INCS = Mariner10Camera.h +SRCS = Mariner10Camera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera.cpp b/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a809b232d5715375a1eb25069e2b8191121b163 --- /dev/null +++ b/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera.cpp @@ -0,0 +1,128 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2010/06/29 18:16:39 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Mariner10Camera.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "ReseauDistortionMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "iString.h" +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" +#include "Filename.h" + +#include +#include + + +using namespace std; +namespace Isis { + /** + * Creates a Mariner10 Camera Model + * + * @param lab Pvl Label from the image + * + * @throws Isis::iException::User - The file does not appear to be a mariner10 + * image + */ + Mariner10Camera::Mariner10Camera(Pvl &lab) : FramingCamera(lab) { + + // Turn off the aberration corrections for instrument position object + InstrumentPosition()->SetAberrationCorrection("NONE"); + InstrumentRotation()->SetFrame(-76000); + + // Set camera parameters + SetFocalLength(); + SetPixelPitch(); + + PvlGroup inst = lab.FindGroup("Instrument", Pvl::Traverse); + // Get utc start time + string stime = inst["StartTime"]; + double et; + utc2et_c(stime.c_str(), &et); + //std::cout<SetDetectorOrigin(sampleBoresight, lineBoresight); + + // Setup distortion map which is dependent on encounter, use start time + // MOON: 1973-11-08T03:16:26.350 + iString spacecraft = (string)inst["SpacecraftName"]; + iString instId = (string)inst["InstrumentId"]; + string cam; + if(instId == "M10_VIDICON_A") { + cam = "a"; + } + else if(instId == "M10_VIDICON_B") { + cam = "b"; + } + else { + string msg = "File does not appear to be a Mariner10 image"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + const string fname = Filename("$mariner10/reseaus/mar10" + cam + + "MasterReseaus.pvl").Expanded(); + + try { + new ReseauDistortionMap(this, lab, fname); + } + catch(iException &e) { + std::string msg = "Unable to create distortion map."; + throw Isis::iException::Message(Isis::iException::Programmer, msg, _FILEINFO_); + } + + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(et); + LoadCache(); + } +} // end namespace isis + +extern "C" Isis::Camera *Mariner10CameraPlugin(Isis::Pvl &lab) { + return new Isis::Mariner10Camera(lab); +} diff --git a/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera.h b/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera.h new file mode 100644 index 0000000000000000000000000000000000000000..b0db33be63f2adeeab5da39f346898c546c56ce6 --- /dev/null +++ b/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera.h @@ -0,0 +1,56 @@ +#ifndef Mariner10Camera_h +#define Mariner10Camera_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2010/06/29 18:16:39 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "FramingCamera.h" + +namespace Isis { + /** + * @brief Mariner10 Camera Model + * + * This is the camera model for both mariner10, both cameras A (wide angle) + * and B (narrow angle). + * + * @ingroup SpiceInstrumentsAndCameras + * @ingroup Mariner10 + * + * @author 2009-04-13 Tracie Sucharski + * + * @internal + * @history 2009-12-18 Tracie Sucharski - Changed inheritance from Camera to + * FramingCamera. + * @history 2010-02-22 Tracie Sucharski - Preface naif includes with /naif. + * @history 2010-03-04 Tracie Sucharski - Removed couts. + * @history 2010-03-04 Tracie Sucharski - Added throw when creation of + * ReseauDistortion fails. + */ + class Mariner10Camera : public Isis::FramingCamera { + public: + Mariner10Camera(Isis::Pvl &lab); + + //! Destroys the Mariner10Camera Object + ~Mariner10Camera() {}; + }; +}; +#endif + diff --git a/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera.truth b/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera.truth new file mode 100644 index 0000000000000000000000000000000000000000..5da57eebe62b3f6303037747c2e35329e6b42ab7 --- /dev/null +++ b/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera.truth @@ -0,0 +1,41 @@ +Unit Test for Mariner10Camera... +Testing image $mariner10/testData/27265.cub ... +For upper left corner ... +DeltaSample = -0.0250238898 +DeltaLine = 0.0117888667 + +For upper right corner ... +DeltaSample = 0.0113466804 +DeltaLine = -0.00137409172 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0.0128398463 + +For lower right corner ... +DeltaSample = -0.0124746887 +DeltaLine = 0.0516041294 + +For center pixel position ... +Latitude OK +Longitude OK +Testing image $mariner10/testData/166474.cub ... +For upper left corner ... +DeltaSample = 0.0275677459 +DeltaLine = -0.0452389126 + +For upper right corner ... +DeltaSample = 0.0248980849 +DeltaLine = 0.00357873038 + +For lower left corner ... +DeltaSample = -0.0662917843 +DeltaLine = 0.0440512044 + +For lower right corner ... +DeltaSample = 0.00496599101 +DeltaLine = 0.0112288006 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera_Darwin_i386_10_5.truth b/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera_Darwin_i386_10_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..b30ae0b1de940bb4bff98e1d3f0a0c8e8a174efa --- /dev/null +++ b/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera_Darwin_i386_10_5.truth @@ -0,0 +1,41 @@ +Unit Test for Mariner10Camera... +Testing image $mariner10/testData/27265.cub ... +For upper left corner ... +DeltaSample = -0.0250238898 +DeltaLine = 0.0117888667 + +For upper right corner ... +DeltaSample = 0.0113466804 +DeltaLine = -0.0013740917 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0.0128398463 + +For lower right corner ... +DeltaSample = -0.0124746887 +DeltaLine = 0.0516041295 + +For center pixel position ... +Latitude OK +Longitude OK +Testing image $mariner10/testData/166474.cub ... +For upper left corner ... +DeltaSample = 0.0275677459 +DeltaLine = -0.0452389126 + +For upper right corner ... +DeltaSample = 0.0248980849 +DeltaLine = 0.0035787304 + +For lower left corner ... +DeltaSample = -0.0662917843 +DeltaLine = 0.0440512044 + +For lower right corner ... +DeltaSample = 0.00496599101 +DeltaLine = 0.0112288006 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera_Linux_i686_RedHat5_5.truth b/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera_Linux_i686_RedHat5_5.truth new file mode 100644 index 0000000000000000000000000000000000000000..b9e5de3ab0abb5720ff968900c7409047f167bc5 --- /dev/null +++ b/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera_Linux_i686_RedHat5_5.truth @@ -0,0 +1,41 @@ +Unit Test for Mariner10Camera... +Testing image $mariner10/testData/27265.cub ... +For upper left corner ... +DeltaSample = -0.0250238898 +DeltaLine = 0.0117888667 + +For upper right corner ... +DeltaSample = 0.0113466805 +DeltaLine = -0.00137409171 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0.0128398463 + +For lower right corner ... +DeltaSample = -0.0124746887 +DeltaLine = 0.0516041294 + +For center pixel position ... +Latitude OK +Longitude OK +Testing image $mariner10/testData/166474.cub ... +For upper left corner ... +DeltaSample = 0.0275677459 +DeltaLine = -0.0452389126 + +For upper right corner ... +DeltaSample = 0.0248980849 +DeltaLine = 0.0035787304 + +For lower left corner ... +DeltaSample = -0.0662917844 +DeltaLine = 0.0440512044 + +For lower right corner ... +DeltaSample = 0.00496599099 +DeltaLine = 0.0112288006 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera_Linux_i686_SUSE10_1.truth b/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera_Linux_i686_SUSE10_1.truth new file mode 100644 index 0000000000000000000000000000000000000000..dd96f1251823ef2614ece13785bfb5afd25f5841 --- /dev/null +++ b/isis/src/mariner/objs/Mariner10Camera/Mariner10Camera_Linux_i686_SUSE10_1.truth @@ -0,0 +1,41 @@ +Unit Test for Mariner10Camera... +Testing image $mariner10/testData/27265.cub ... +For upper left corner ... +DeltaSample = -0.0250238898 +DeltaLine = 0.0117888666 + +For upper right corner ... +DeltaSample = 0.0113466804 +DeltaLine = -0.00137409171 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0.0128398463 + +For lower right corner ... +DeltaSample = -0.0124746887 +DeltaLine = 0.0516041294 + +For center pixel position ... +Latitude OK +Longitude OK +Testing image $mariner10/testData/166474.cub ... +For upper left corner ... +DeltaSample = 0.0275677459 +DeltaLine = -0.0452389126 + +For upper right corner ... +DeltaSample = 0.0248980849 +DeltaLine = 0.0035787304 + +For lower left corner ... +DeltaSample = -0.0662917844 +DeltaLine = 0.0440512044 + +For lower right corner ... +DeltaSample = 0.00496599099 +DeltaLine = 0.0112288006 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/mariner/objs/Mariner10Camera/unitTest.cpp b/isis/src/mariner/objs/Mariner10Camera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38b2611e312c40673bdcaa83acbe4a5b5c4f13fe --- /dev/null +++ b/isis/src/mariner/objs/Mariner10Camera/unitTest.cpp @@ -0,0 +1,114 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main(void) { + Isis::Preference::Preferences(true); + + cout << "Unit Test for Mariner10Camera..." << endl; + try { + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + char files[2][1024] = { "$mariner10/testData/27265.cub", + "$mariner10/testData/166474.cub" + }; + + double knownLat[2] = { -27.5746680495404, + -22.58558961173848 + }; + double knownLon[2] = { 312.1934068790935, + 292.0697686733246 + }; + + vector< pair > corners; + + // 27265.cub Mariner A + corners.push_back(std::make_pair(14, 1)); + corners.push_back(std::make_pair(831, 1)); + corners.push_back(std::make_pair(9, 700)); + corners.push_back(std::make_pair(829, 700)); + // 166474.cub Mariner B + corners.push_back(std::make_pair(36, 1)); + corners.push_back(std::make_pair(829, 1)); + corners.push_back(std::make_pair(55, 700)); + corners.push_back(std::make_pair(830, 700)); + + + for(unsigned int i = 0; i < sizeof(knownLat) / sizeof(double); i++) { + // Isis::Pvl p("$mariner10/testData/27265.cub"); + Isis::Pvl p(files[i]); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + cout << "Testing image " << files[i] << " ..." << endl; + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, corners[i*4].first, corners[i*4].second); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, corners[i*4+1].first, corners[i*4+1].second); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, corners[i*4+2].first, corners[i*4+2].second); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, corners[i*4+3].first, corners[i*4+3].second); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp, line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat[i]) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat[i] << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon[i]) < 2E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon[i] << endl; + } + } + } + catch(Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp, line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if(fabs(deltaSamp) < 0.001) deltaSamp = 0; + if(fabs(deltaLine) < 0.001) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/mer/Makefile b/isis/src/mer/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/mer/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/mer/apps/Makefile b/isis/src/mer/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/mer/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/mer/apps/mer2isis/Makefile b/isis/src/mer/apps/mer2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mer/apps/mer2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mer/apps/mer2isis/mer2isis.cpp b/isis/src/mer/apps/mer2isis/mer2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..51c6424067a600ac1ef23bed88a3e66134d8e8e1 --- /dev/null +++ b/isis/src/mer/apps/mer2isis/mer2isis.cpp @@ -0,0 +1,119 @@ +#include "Isis.h" + +#include "ProcessImportPds.h" + + +/** + * @author 2006-01-23 Brian Lipkowitz + * @author 2006-01-23 Robert Wallace + */ + +using namespace std; +using namespace Isis; + +void IsisMain() { + void TranslateMerEdrLabels (Filename &labelFile, Cube *ocube); + + UserInterface &ui = Application::GetUserInterface(); + + Filename input = Filename (ui.GetFilename ("FROM")); + + //Checks if in file is rdr + Pvl lab(input.Expanded()); + if( lab.HasObject("IMAGE_MAP_PROJECTION") ) { + string msg = "[" + input.Name() + "] has already been projected."; + msg += " Use pds2isis."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + iString output; + if ( ui.WasEntered("TO")) { + output = ui.GetFilename("TO"); + } + else { + output = input.Path() + input.Basename() + ".cub"; + } + + Pvl inputFile; + + iString paramaters = "FROM=" + input.Expanded(); + paramaters += " TO=" + output; + + ProcessImportPds p; + p.SetPdsFile(input.Expanded(),"",inputFile); + + Cube *ocube = p.SetOutputCube("TO"); + p.StartProcess (); + TranslateMerEdrLabels(input,ocube); + p.EndProcess(); +} + +void TranslateMerEdrLabels (Filename &labelFile, Cube *ocube) { + //Create a PVL to store the translated labels + Pvl outLabel; + + // Get the directory where the MER translation tables are. + PvlGroup dataDir (Preference::Preferences().FindGroup("DataDirectory")); + iString transDir = (string) dataDir["Mer"]; + transDir = transDir + "/" + "translations/"; + + // Get a filename for the MESSENGER EDR label + Pvl labelPvl (labelFile.Expanded()); + Filename transFile; + + // Translate the Archive group + transFile = transDir + "merStructure.trn"; + PvlTranslationManager structXlater (labelPvl, transFile.Expanded()); + structXlater.Auto (outLabel); + ocube->PutGroup (outLabel.FindGroup("ARCHIVE", Pvl::Traverse)); + + // Translate the Instrument group + transFile = transDir + "merInstrument.trn"; + PvlTranslationManager instrumentXlater (labelPvl, transFile.Expanded()); + instrumentXlater.Auto (outLabel); + ocube->PutGroup (outLabel.FindGroup("INSTRUMENT", Pvl::Traverse)); + + // Pull out MiCCD and MiElectronic from the TemperatureName in the instrument group + void MiFixLab(PvlGroup & instGroup); + PvlGroup instGroup = ocube->GetGroup("INSTRUMENT"); + MiFixLab(instGroup); + ocube->PutGroup(instGroup); + + // Translate the Image_Request group + transFile = transDir + "merImageRequest.trn"; + PvlTranslationManager imageReqXlater (labelPvl, transFile.Expanded()); + imageReqXlater.Auto (outLabel); + ocube->PutGroup (outLabel.FindGroup("MER_IMAGE_REQUEST_PARMS", Pvl::Traverse)); + + // Translate the Subframe group + transFile = transDir + "merSubframe.trn"; + PvlTranslationManager subframeXlater (labelPvl, transFile.Expanded()); + subframeXlater.Auto (outLabel); + ocube->PutGroup (outLabel.FindGroup("MER_SUBFRAME_REQUEST_PARMS", Pvl::Traverse)); +} + +void MiFixLab( PvlGroup & instGroup ) { + // code to get instrment and electronics temperatures. + PvlKeyword temp = instGroup.FindKeyword("InstrumentTemperature"); + PvlKeyword tempName = instGroup.FindKeyword("InstrumentTemperatureName"); + + PvlKeyword miCCD; + miCCD.SetName( "TemperatureMiCCD"); + miCCD.SetValue(temp[6]); + instGroup.AddKeyword(miCCD); + + PvlKeyword miElectornic; + miElectornic.SetName( "TemperatureMiElectronics"); + miElectornic.SetValue(temp[7]); + instGroup.AddKeyword(miElectornic); + + //Code to remove "Z" from the StartTime and StopTime keywords + //StartTime code + iString Newstarttime = (string)instGroup.FindKeyword("StartTime"); + Newstarttime.Remove("Z"); + instGroup.FindKeyword("StartTime").SetValue(Newstarttime); + //StopTime code + iString Newstoptime = (string)instGroup.FindKeyword("StopTime"); + Newstoptime.Remove("Z"); + instGroup.FindKeyword("StopTime").SetValue(Newstoptime); +} diff --git a/isis/src/mer/apps/mer2isis/mer2isis.xml b/isis/src/mer/apps/mer2isis/mer2isis.xml new file mode 100755 index 0000000000000000000000000000000000000000..70a3686aeb0c1981a7371b737771373d7c8037ec --- /dev/null +++ b/isis/src/mer/apps/mer2isis/mer2isis.xml @@ -0,0 +1,69 @@ + + + + Import a Mer PDS image to Isis cube format + + + + This program will import Mars Exploration Rover images to Isis cube formatted images. + + + + + Original version + + + Removed call to OriginalLabel, ProcessImportPds now handles this. + + + Documentation fixes + + + Added ShutterEffectCorrectionFlag keyword to the merInstrument.trn file. + + + Checks if input file is rdr. + + + Removed references to CubeInfo + + + Added code to remove "Z" from StartTime and Stop Time keyword + + + + + Mars Exploration Rover + + + + + + filename + input + + Input Mer PDS image + + + Input Mer PDS Image for importing into Isis cube format + + + *.img *.IMG + + + + cube + output + + Output cube + + + The Isis cube containing the imported Mer image data + + + *.cub + + + + + diff --git a/isis/src/mer/apps/mer2isis/tsts/Makefile b/isis/src/mer/apps/mer2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mer/apps/mer2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mer/apps/mer2isis/tsts/case01/Makefile b/isis/src/mer/apps/mer2isis/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6a0bde7c0aabc92809b93f7d35c29131d82f083b --- /dev/null +++ b/isis/src/mer/apps/mer2isis/tsts/case01/Makefile @@ -0,0 +1,8 @@ +APPNAME = mer2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/1M189529263EFF64KCP2977M2F1.IMG \ + to=$(OUTPUT)/mer2isisTruth1.cub > /dev/null; + catlab from=$(OUTPUT)/mer2isisTruth1.cub > $(OUTPUT)/labels1.pvl; diff --git a/isis/src/mer/apps/mer2isis/tsts/case02/Makefile b/isis/src/mer/apps/mer2isis/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4addeccd5cf46685924c8d4a3d1eb493723fd9a2 --- /dev/null +++ b/isis/src/mer/apps/mer2isis/tsts/case02/Makefile @@ -0,0 +1,8 @@ +APPNAME = mer2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/2M189392700EFFAL00P2977M2F1.IMG \ + to=$(OUTPUT)/mer2isisTruth2.cub > /dev/null; + catlab from=$(OUTPUT)/mer2isisTruth2.cub > $(OUTPUT)/labels2.pvl; diff --git a/isis/src/mer/apps/mical/Makefile b/isis/src/mer/apps/mical/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mer/apps/mical/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mer/apps/mical/MiCalibration.cpp b/isis/src/mer/apps/mical/MiCalibration.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e268c041a580ffcb589464433e3618efeb6f8608 --- /dev/null +++ b/isis/src/mer/apps/mical/MiCalibration.cpp @@ -0,0 +1,139 @@ +#include + +#include "MiCalibration.h" + +using namespace std; +namespace Isis{ + namespace Mer { + + //Construct with cube and calkernel(filename) + MiCalibration::MiCalibration(Cube &image, Pvl &kernel) { + ReadLabels(image); + ReadKernel(kernel); + SetCCDTemperature(p_CCDTemperature); + SetPCBTemperature(p_PCBTemperature); + SetOmegaNaught(); + SetReferencePixelModel(); + SetZeroExposureValue(); + SetActiveAreaValue(); + } + + /** + * Get keyword values for the label of the input cube that are + * needed for the calibration equations. + */ + + void MiCalibration::ReadLabels(Cube &image){ + PvlGroup labelgrp = image.Label()->FindGroup("Instrument",Pvl::Traverse); + p_exposureDuration = labelgrp["ExposureDuration"]; + p_instrumentSerialNumber = labelgrp["InstrumentSerialNumber"]; + p_CCDTemperature = labelgrp["InstrumentTemperature"][6]; + p_PCBTemperature = labelgrp["InstrumentTemperature"][7]; + p_OffsetModeId = labelgrp["OffsetModeID"]; + p_shuttereffectcorrectionflag = (string)labelgrp["ShutterEffectCorrectionFlag"]; + p_filterName = (string)labelgrp["FilterName"]; + p_startTime = (string)labelgrp["StartTime"]; + } + /** + * Get values from the calibration kernel + * use the instrumentSerialnumber to determain what rover + * the image is from that get the values for that rover. + * + * @param kernel - the kernal from the data area or user + * entered. + */ + void MiCalibration::ReadKernel(Pvl &kernel){ + string rover = "MI_" + Isis::iString(p_instrumentSerialNumber); + PvlGroup kernelgrp = kernel.FindGroup(rover,Pvl::Traverse); + p_DELCCDTa = kernelgrp["DELCCDTa"]; + p_DELCCDTb = kernelgrp["DELCCDTb"]; + p_RPVOFFa = kernelgrp["RPVOFFa"]; + p_RPVOFFb = kernelgrp["RPVOFFb"]; + p_RPPCBTa = kernelgrp["RPPCBTa"]; + p_RPPCBTb = kernelgrp["RPPCBTb"]; + p_RPPCBTc = kernelgrp["RPPCBTc"]; + p_RPCCDTa = kernelgrp["RPCCDTa"]; + p_RPCCDTb = kernelgrp["RPCCDTb"]; + p_RPCCDTc = kernelgrp["RPCCDTc"]; + p_ZEROEXPa = kernelgrp["ZEROEXPa"]; + p_ZEROEXPb = kernelgrp["ZEROEXPb"]; + p_ACTAREAa = kernelgrp["ACTAREAa"]; + p_ACTAREAb = kernelgrp["ACTAREAb"]; + p_temperatureOffset = kernelgrp["TemperatureOffset"]; + p_transfertime = kernelgrp["TransferTime"]; + p_ReferencePixelImage = (string)kernelgrp["ReferencePixelImage"]; + p_ZeroExposureImage = (string)kernelgrp["ZeroExposureImage"]; + p_ActiveAreaImage = (string)kernelgrp["ActiveAreaImage"]; + p_FlatImageOpen = (string)kernelgrp["FlatImageOpen"]; + p_FlatImageClosed = (string)kernelgrp["FlatImageClosed"]; + } + /** + * Get the CCD temperature and output a corrected + * CCDtemperatrue. Values used in the calculation come from the + * calibration kernel + */ + void MiCalibration::SetCCDTemperature(double temperature){ + p_CCDTemperature = temperature; + p_CCDTemperatureCorrect = (p_CCDTemperature + p_temperatureOffset) + + p_DELCCDTa * + (1 - exp(p_exposureDuration / p_DELCCDTb)); + } + + /** + * Returns the PCB temperature + * @param temperature + */ + void MiCalibration::SetPCBTemperature(double temperature){ + p_PCBTemperature = temperature; + } + + /** + * Calculates the Omega Naught. Is dependent on which rover the + * data is from. + */ + void MiCalibration::SetOmegaNaught(){ + if (p_instrumentSerialNumber == 105) { + p_OmegaNaught = 8.53e+05 - 2.50e+03 * p_CCDTemperatureCorrect; + } + else if (p_instrumentSerialNumber == 110) { + p_OmegaNaught = 8.21e+05 - 2.99e03 * p_CCDTemperatureCorrect; + } + } + + /** + * Calculates the Reference Pixel Model value. The inputs to + * the algarithem come for the image labels and calibration + * kernel. + */ + void MiCalibration::SetReferencePixelModel(){ + p_ReferencePixelModel = (p_RPVOFFa - p_OffsetModeId) * p_RPVOFFb + + (p_RPPCBTa + p_RPPCBTb * p_exposureDuration) * + exp(p_RPPCBTc * p_PCBTemperature) + + (p_RPCCDTa + p_RPCCDTb *p_exposureDuration) * + exp(p_RPCCDTc * p_CCDTemperatureCorrect); + + } + + /** + * Calculates the zero exposure value. The inputs come from the + * image label and calibration kernel. + */ + void MiCalibration::SetZeroExposureValue(){ + p_ZeroExposureValue = + p_ZEROEXPa * exp(p_ZEROEXPb * p_CCDTemperatureCorrect); + } + + /** + * Caluculate the active aere value. the inputs come from the + * image label and calibration kernel. + */ + void MiCalibration::SetActiveAreaValue(){ + p_ActiveAreaValue = p_exposureDuration * p_ACTAREAa * + exp(p_ACTAREAb * p_CCDTemperatureCorrect); + } + + + } +} + + diff --git a/isis/src/mer/apps/mical/MiCalibration.h b/isis/src/mer/apps/mical/MiCalibration.h new file mode 100644 index 0000000000000000000000000000000000000000..50ab4246ce969348b067231f200a8cb9a88a191f --- /dev/null +++ b/isis/src/mer/apps/mical/MiCalibration.h @@ -0,0 +1,95 @@ +#ifndef MiCalibration_h +#define MiCalibration_h + +#include "Cube.h" +#include "Pvl.h" +#include "Statistics.h" + +namespace Isis{ + namespace Mer{ + class MiCalibration { + public: + MiCalibration(Cube &image, Pvl &kernel); + ~MiCalibration(){}; + + inline double ExposureDuration() const {return p_exposureDuration;}; + int InstrumentSerialNumber() const {return p_instrumentSerialNumber;}; + inline std::string ShutterEffectCorrectionFlag() + const {return p_shuttereffectcorrectionflag;}; + inline std::string ReferencePixelImage() const {return p_ReferencePixelImage;}; + inline std::string ZeroExposureImage() const {return p_ZeroExposureImage;}; + inline std::string ActiveAreaImage() const {return p_ActiveAreaImage;}; + inline std::string FlatImageOpen() const {return p_FlatImageOpen;}; + inline std::string FlatImageClosed() const {return p_FlatImageClosed;}; + inline std::string FilterName() const {return p_filterName;}; + inline std::string StartTime() const {return p_startTime;}; + inline double TransferTime() const {return p_transfertime;}; + inline double OffsetModeID() const {return p_OffsetModeId;}; + inline double OmegaNaught() const {return p_OmegaNaught;}; + inline double CCDTemperatureCorrect() const {return p_CCDTemperatureCorrect;}; + inline double PCBTemperature() const {return p_PCBTemperature;}; + inline double ReferencePixelModel() const {return p_ReferencePixelModel;}; + inline double ZeroExposureValue() const {return p_ZeroExposureValue;}; + inline double ActiveAreaValue() const {return p_ActiveAreaValue;}; + + void SetReferencePixelModel(); + void SetZeroExposureValue(); + void SetActiveAreaValue(); + void SetCCDTemperature (double temperature); + void SetPCBTemperature (double temperature); + void SetOmegaNaught (); + + private: + double p_exposureDuration; //expousr duration in mill sec. + int p_instrumentSerialNumber; + double p_CCDTemperature; + double p_PCBTemperature; + double p_CCDTemperatureCorrect; + double p_OffsetModeId; + std::string p_shuttereffectcorrectionflag; + std::string p_filterName; + std::string p_startTime; + + double p_ReferencePixelModel; + double p_ZeroExposureValue; + double p_ActiveAreaValue; + + double p_DELCCDTa; + double p_DELCCDTb; + double p_RPVOFFa; + double p_RPVOFFb; + double p_RPPCBTa; + double p_RPPCBTb; + double p_RPPCBTc; + double p_RPCCDTa; + double p_RPCCDTb; + double p_RPCCDTc; + double p_ZEROEXPa; + double p_ZEROEXPb; + double p_ACTAREAa; + double p_ACTAREAb; + double p_temperatureOffset; + double p_transfertime; + std::string p_ReferencePixelImage; + std::string p_ZeroExposureImage; + std::string p_ActiveAreaImage; + std::string p_FlatImageOpen; + std::string p_FlatImageClosed; + double p_RPswitch; + double p_ZEswitch; + double p_AAswitch; + double p_OmegaNaught; + + double p_calPixel; + double p_DesmearPixel; + double p_outputPixel; + + void ReadLabels (Cube &image); + void ReadKernel (Pvl &kernel); + + + }; + }; +}; +#endif + diff --git a/isis/src/mer/apps/mical/mical.cpp b/isis/src/mer/apps/mical/mical.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4228011a109e113583b1f1c12f5c6d84449384d6 --- /dev/null +++ b/isis/src/mer/apps/mical/mical.cpp @@ -0,0 +1,321 @@ +#define GUIHELPERS + +#include "Isis.h" +#include "ProcessByLine.h" +#include "Pvl.h" +#include "UserInterface.h" +#include "iException.h" +#include "MiCalibration.h" +#include "iTime.h" +#include "Brick.h" +#include "Histogram.h" + +#include +#include + +using namespace std; +using namespace Isis; + +//helper button functions in the code +void helperButtonLogCalKernel(); + +map GuiHelpers(){ + map helper; + helper ["helperButtonLogCalKernel"] = (void*) helperButtonLogCalKernel; + return helper; +} + +namespace gbl { + void Calibrate (vector&in, vector&out); + + Mer::MiCalibration *mi; + double sunAU; + + double ReferencePixelValue; + + int useReferenceValue; + int useZeroExposureValue; + int useActiveAreaValue; +} + +PvlGroup calgrp; +string stagestop; + +void IsisMain(){ + //We will be processing by line + ProcessByLine p; + + + UserInterface &ui = Application::GetUserInterface(); + stagestop = ui.GetAsString("CALSTAGE"); + + Cube *pack = p.SetInputCube("FROM"); + PvlGroup calgrp("Radiometry"); + + //check if the image is calibrated + if (pack->HasGroup("Radiometry")) { + string msg = "The MI image ["+ pack->Filename() +"] has already been "; + msg += "radiometrically calibrated"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + //Open the calibration kernel that contains constrnts for each camera + string calKernelFile; + if (ui.WasEntered("CALKERNEL")) { + calKernelFile = ui.GetFilename("CALKERNEL"); + cout << "use the user kernel" << endl; + } + else { + calKernelFile = p.MissionData("mer","/calibration/mical.ker.???",true); + cout << "use the system kernel" << endl; + } + Pvl calKernel(calKernelFile); +// gbl::mi = new Mer::MiCalibration(*(pack->GetCube()), calKernel); + gbl::mi = new Mer::MiCalibration(*(pack), calKernel); + calgrp += PvlKeyword("CalibrationKernel",calKernelFile); + + + // See if User entered a temperature and call setTemperature functions + if (ui.WasEntered("CCDtemp")) { + gbl::mi->SetCCDTemperature(ui.GetDouble("CCDtemp")); + } + if (ui.WasEntered("PCBtemp")) { + gbl::mi->SetPCBTemperature(ui.GetDouble("PCBtemp")); + } + + iTime startTime = gbl::mi->StartTime(); + double ETstartTime = startTime.Et(); + //Get the distance between Mars and the Sun at the given time in + // Astronomical Units (AU) + string bspKernel = p.MissionData("base","/kernels/spk/de???.bsp",true); + furnsh_c(bspKernel.c_str()); + string pckKernel = p.MissionData("base","/kernels/pck/pck?????.tpc",true); + furnsh_c(pckKernel.c_str()); + double sunpos[6],lt; + spkezr_c("sun",ETstartTime,"iau_mars","LT+S","mars",sunpos,<); + double dist = vnorm_c(sunpos); + double kmperAU = 1.4959787066E8; + gbl::sunAU = dist / kmperAU; + unload_c (bspKernel.c_str()); + unload_c (pckKernel.c_str()); + + + //See what calibtation values the user wants to apply + //run SetReferencePixelModel if RPCORRECTION for gui is false no correction is done + gbl::useReferenceValue = 1; + gbl::useZeroExposureValue = 1; + gbl::useActiveAreaValue = 1; + // if user wants NO reference value correction or if shutter effect + // correction is true set the user value to zero and set label output values + // to reflect no correction. + if (!ui.GetBoolean("RPCORRECTION") || gbl::mi->ShutterEffectCorrectionFlag() == "TRUE") { + gbl::useReferenceValue = 0; + calgrp += PvlKeyword("ReferencePixelValueSource","N/A"); + calgrp += PvlKeyword("ReferencePixelValue", 0); + calgrp += PvlKeyword("ReferencePixelImage", "NoCorrection"); + } + // find out if user entered a ERP file. If yes then get the AVG for the + // Reference Pixel value. If no file is entered then use the model to + // get the reference value. + else if (ui.WasEntered("REFPIXIMAGE")) { + Brick *b; + Cube ERPfile; + ERPfile.Open(ui.GetFilename("REFPIXIMAGE")); + b = new Brick(11,201,1,ERPfile.PixelType()); + b->SetBasePosition(4,412,1); + ERPfile.Read(*b); + + Statistics stat; + b->SetBaseLine(5); + + stat.AddData(b->DoubleBuffer(), b->size()); + gbl::ReferencePixelValue = stat.Average(); + + calgrp += PvlKeyword("ReferencePixelValueSource","ERPImage"); + calgrp += PvlKeyword("ReferencePixelValueImage", ui.GetFilename("REFPIXIMAGE")); + calgrp += PvlKeyword("ReferencePixelValue", gbl::ReferencePixelValue); + } + else { + gbl::ReferencePixelValue = gbl::mi->ReferencePixelModel(); + calgrp += PvlKeyword("ReferencePixelValueSource","ERPModel"); + calgrp += PvlKeyword("ReferenceModel",gbl::ReferencePixelValue); + } + // if user wants NO zero exposure or if shutter effect correction is true + // set the user value to zero and set label output to reflect no correction + if (!ui.GetBoolean("ZECORRECTION") || gbl::mi->ShutterEffectCorrectionFlag() == "TRUE") { + gbl::useZeroExposureValue = 0; + calgrp += PvlKeyword("ZeroExposureValue", 0); + calgrp += PvlKeyword("ZeroExposureImage", "NoCorrection"); + } + else { + calgrp += PvlKeyword("ZeroExposureValue",gbl::mi->ZeroExposureValue()); + calgrp += PvlKeyword("ZeroExposureImage",gbl::mi->ZeroExposureImage()); + } + // If user wants NO active area set user value to zero and set the label + // output values to reflect no correction. + if (!ui.GetBoolean("AACORRECTION")) { + gbl::useActiveAreaValue = 0; + calgrp += PvlKeyword("ActiveAreaValue", 0); + calgrp += PvlKeyword("ActiveAreaImage", "NoCorrection"); + } + else { + calgrp += PvlKeyword("ActiveAreaValue",gbl::mi->ActiveAreaValue()); + calgrp += PvlKeyword("ActiveAreaImage", gbl::mi->ActiveAreaImage()); + } + + + // get the Ref, Zero, and Act images in to buffers + CubeAttributeInput att; + p.SetInputCube(gbl::mi->ReferencePixelImage(), att); + p.SetInputCube(gbl::mi->ZeroExposureImage(), att); + p.SetInputCube(gbl::mi->ActiveAreaImage(), att); + // The flatfield image used is dependent on if + // the dust cover is open or closed. + // + + if (ui.WasEntered("FLATFIELD")) { + p.SetInputCube(ui.GetFilename("FLATFIELD"), att); + if (stagestop == "FLAT" || stagestop == "IOF" ) { + calgrp += PvlKeyword("FlatFieldImage", gbl::mi->FlatImageOpen()); + } + } + else { +cout << "TEST of cover " << gbl::mi->FilterName() << endl; + if (gbl::mi->FilterName() == "MI_OPEN") { + p.SetInputCube(gbl::mi->FlatImageOpen(), att); + if (stagestop == "FLAT" || stagestop == "IOF" ) { + calgrp += PvlKeyword("FlatFieldImage", gbl::mi->FlatImageOpen()); + } + } + else if (gbl::mi->FilterName() == "MI_CLOSED") { + p.SetInputCube(gbl::mi->FlatImageClosed(), att); + if (stagestop == "FLAT" || stagestop == "IOF" ) { + calgrp += PvlKeyword("FlatFieldImage", gbl::mi->FlatImageClosed()); + } + } + } + + + //calculate full model value and output to the labels. + double fullModel = gbl::mi->ReferencePixelModel() + + gbl::mi->ZeroExposureValue() + + gbl::mi->ActiveAreaValue(); + calgrp += PvlKeyword("DarkCurrentFullModel",fullModel); + + //Add temperature values to the radiometry group + calgrp += PvlKeyword("CCDTemperture", gbl::mi->CCDTemperatureCorrect()); + calgrp += PvlKeyword("PCBTemperature", gbl::mi->PCBTemperature()); + if (stagestop == "IOF") { + calgrp += PvlKeyword("OmegaNaught", gbl::mi->OmegaNaught()); + calgrp += PvlKeyword("SunAU", gbl::sunAU); + } + +//write Radiometry group to the output cube. + Cube *opack =p.SetOutputCube("TO"); + opack->PutGroup(calgrp); + + p.StartProcess(gbl::Calibrate); + p.EndProcess(); +} + +//Line processing routine + +void gbl::Calibrate(vector&in, vector&out) { + Buffer &ibuf = *in[0]; + Buffer &rbuf = *in[1]; + Buffer &zbuf = *in[2]; + Buffer &abuf = *in[3]; + Buffer &fbuf = *in[4]; + Buffer &obuf = *out[0]; + +// Do the dark current correction (Note that if shutter effect correction +// flag is true then the userReferenceValue and useZeroExposureValue +// are set to zero so there is no correction. + for (int samp=0; sampZeroExposureValue() * zbuf[samp]) * useZeroExposureValue) + + ((gbl::mi->ActiveAreaValue() * abuf[samp]) * useActiveAreaValue)); + } + if (stagestop == "DARK") return; + + //-------------------------------------------------------------------- + // Add Desmear correction + + if (mi->ShutterEffectCorrectionFlag() == "FALSE" && + mi->ExposureDuration() < 1000 || mi->ExposureDuration() > 0 && ibuf.size() != 1024) { + + double smearScale = mi->TransferTime() / mi->ExposureDuration() / obuf.size(); + static vector smear; + if (obuf.Line() == 1) { + smear.resize(obuf.size()); + for (int i=0; iExposureDuration() / 1000.0; + + for (int i = 0; i < obuf.size(); i++) { + if (gbl::mi->FilterName() == "MI_OPEN") { + obuf[i] = obuf[i] * (pow(gbl::sunAU,2) / (exposureSeconds * gbl::mi->OmegaNaught())); + } + else if (gbl::mi->FilterName() == "MI_CLOSED") { + obuf[i] = obuf[i] * (pow(gbl::sunAU,2) / + (exposureSeconds * gbl::mi->OmegaNaught()) / .53); + } + } +} + +//Helper Button Function to display cal Kernel in the log area +void helperButtonLogCalKernel() { + UserInterface &ui = Application::GetUserInterface(); + string calKernelFile; + if (ui.WasEntered("CALKERNEL")) { + calKernelFile = ui.GetFilename("CALKERNEL"); + } + else { + // calKernelFile = p.MissionData("mer","/calibration/mical.ker.???",true); + cout << "use the system kernel" << endl; + } + + Pvl p; + p.Read(calKernelFile); + string Ostring = "********** Output of [" + calKernelFile + "] *********"; + Application::GuiLog(Ostring); + Application::GuiLog(p); +} + + diff --git a/isis/src/mer/apps/mical/mical.xml b/isis/src/mer/apps/mical/mical.xml new file mode 100644 index 0000000000000000000000000000000000000000..307ac6e6bf6551f08f450f82a0d06f8f2b8c5a16 --- /dev/null +++ b/isis/src/mer/apps/mical/mical.xml @@ -0,0 +1,313 @@ + + + + + + Radiometrically calibrates a Mars Exploration Rover (MER) + Microscopic Imager(MI) image + + + +

    + mical performs radiometric corrections to images acquired by the MER + MI camera. MI images taken during science operations have 1024 samples + and 1024 lines and are single bands. The pre calibration images are signed + word or 16 bit images. Subareas can be aquired but this was rarely done during + the mission.
    + + mical has a number of parameters required to process MER MI image + data. Most of these parameters are read from an ISIS parameter defaults + file located in the mer directory specified in the IsisPreference file. + This file has the form: +

        
    +      $mer/calibration/mical.ker.xxx
    +    
    +      where "xxx" is a positive number.
    +     
    + mical will search for the parameter file with the highest number and + load all its defaults needed to process MI images. Note that the + caller may explicity provide an alternative ISIS parameter defaults + file name in the "CALKERNEL" input parameter if they have their own + set of defaults that applies to MI data. See an existing calibration + file for details on how to configure this file. +

    +

    + The level of calibration output can be selected. by choosing one of the + output options, the user can choose to dark current correct, dark current and + flat field, or dark current, flat field and output in I/F values. +

    + +

    + The dark current correction equation mical implements is as follows: +

    +      r = dn - (rpi + rpv) + (zei * zev) + (aai * aav)
    +    
    + + Where: + r is the aver signal being generated at the focal plane + dn is the input pixel value + rpi is the referance pixel dn + rpv is the referance pixel correction value + zei is the zero exposure pixel dn + zev is the zero exposure correction value + aai is the active area pixel dn + aav is the active area correction value + + The user can choose to not correct for the reference pixel, zero exposure + or active area by selecting or deselecting the RPCORRECTION, ZECORECTION, + or AACORRECTION checkbox. The program will also determain if these + corrections should be applied. If the ShutteEffectCorrectionFlag is set to "TRUE" + in the image labels, the reference pixel, and zero exposure will not be applied.
    + + If a flat fielded output is chosen: +
    +       r = dn / f
    +     
    + + where: + r is the corrected output value + dn is the input pixel that has been dark current corrected + f is a flat field pixel
    + + if the "ShutteEffectCorrectionFlag is false and the exposure duration is greater + them zero and less them 1000 and the image is mot equal to 1024 samples, a + image smear correction is applied. +

    + + + + +
    + + + + Original version + + + + + Mars Exploration Rover + + + + + mer2isis + + + + + + + cube + input + + Level 0 MER MI image + + + An uncalibrated MER MI image. + + + *.cub *.CUB + + + + + cube + output + real + + Level 1 MER MI image + + + The resultant radiometrically calibrated cube + + + *.cub *.CUB + + + + + filename + input + + PVL kernel containing calibration prameters + + Internal Default + + If you do not enter a file, mical will search for a file with the form: +
    +            $mer/calibration/mical.kernel.xxx
    +
    +            where "xxx" is a positive number.
    +          
    + the kernel with the highest version (xxx) will be used. + See an existing calibration + file for details on how to configure this file. +
    + + + helperButtonLogCalKernel + View Calibration Kernel in the log area + + This button will display the callibration kernel in the log area. + If no file is entered in the CALKERNEL parameter then the system + file will be displayed. + + $ISIS3DATA/base/icons/view_text.png + + +
    + + + cube + input + + Referance Pixel image (ERP) + + + At times, a referance pixel image was aquired when image data was + taken. If a referance pixel image was acquired, it can be used in the + calibration. A referance pixel image uses the designation "ERP" rather + then "EFF" in the file name. + + + *.cub *.CUB + + Use Model Value + + + cube + input + + The flat field image used in correction + + + User can enter a flat field image that will be used in the correction. + If no value is entered, then the file listed in the calibration kernel + will be used. + + + *.cub *.CUB + + Use value in kernel + +
    + + + string + + The calibration stage to process + + + This parameter allows the user to control what calibration step will + be applied to the input image. if "DARK" is selected, then only a + dark current correction is preformed. If "FLAT" is selected, the + image is corrected for dark current and a flat field correction is + applied. if "IOF" is chosen then the final outut will in refiectance + values. + + + IOF + + + + + + + + + + + + double + + CCD temperature + + + A user defined CCD temperature that will be used in calculations that use + the CCD temperature. If entered, this value will be used rather then the + temperature in the image labels. + + Temperature from Labels + + + + double + + PCB temperature + + + A user defined PCB temperature that will be used in calculations that use + the PCB temperature. If entered, this value will be used rather then the + temperature in the image labels. + + Temperature from labels + + + + boolean + + Correct for Referance Pixel + + + If this option is selected, the reference pixel correction will be applied. + if the ShutteEffectCorrectionFlag is set to TRUE then the reference pixel + correction is not applied, even if this parameter is set to true. The + default is true which will apply the correction. + + TRUE + + + + boolean + + Correct for Zero Exposure + + + If this option is selected, the zero exposure correction will be applied. + if the ShutteEffectCorrectionFlag is set to TRUE then the zero exposure + correction is not applied, even if this parameter is set to true. The + default is true which will apply the correction. + + TRUE + + + + boolean + + Correct for Active Area + + + If this option is selected, the active area. correction will be applied. + The default is true which will apply the correction. + + TRUE + + +
    +
    + diff --git a/isis/src/mer/apps/mical/tsts/Makefile b/isis/src/mer/apps/mical/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mer/apps/mical/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mer/apps/mical/tsts/case01/Makefile b/isis/src/mer/apps/mical/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..658ac2bc756c0be146f27acbf7e5680169a4d104 --- /dev/null +++ b/isis/src/mer/apps/mical/tsts/case01/Makefile @@ -0,0 +1,8 @@ +APPNAME = mical + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/2M189392700EFFAL00P2977M2F1.cub \ + to=$(OUTPUT)/micalTruth1.cub > /dev/null; + catlab from=$(OUTPUT)/micalTruth1.cub > $(OUTPUT)/labels1.pvl; diff --git a/isis/src/mer/apps/mical/tsts/case02/Makefile b/isis/src/mer/apps/mical/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..17633fda3feba88c38837befccfa8b73abe5de3f --- /dev/null +++ b/isis/src/mer/apps/mical/tsts/case02/Makefile @@ -0,0 +1,8 @@ +APPNAME = mical + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/1M189529263EFF64KCP2977M2F1.cub \ + to=$(OUTPUT)/micalTruth2.cub > /dev/null; + catlab from=$(OUTPUT)/micalTruth2.cub > $(OUTPUT)/labels2.pvl; diff --git a/isis/src/mer/objs/Makefile b/isis/src/mer/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/mer/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/messenger/Makefile b/isis/src/messenger/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/messenger/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/messenger/apps/Makefile b/isis/src/messenger/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/messenger/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/messenger/apps/mdis2isis/Makefile b/isis/src/messenger/apps/mdis2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/messenger/apps/mdis2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/messenger/apps/mdis2isis/mdis2isis.cpp b/isis/src/messenger/apps/mdis2isis/mdis2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..281dbc70872e9242980e173aa507fc8f4a86fb27 --- /dev/null +++ b/isis/src/messenger/apps/mdis2isis/mdis2isis.cpp @@ -0,0 +1,402 @@ +// $Id: mdis2isis.cpp,v 1.18 2009/12/29 21:45:54 slambright Exp $ +#include "Isis.h" + +#include +#include +#include + +#include "ProcessImportPds.h" +#include "ProcessByLine.h" + +#include "UserInterface.h" +#include "Filename.h" +#include "iException.h" +#include "iTime.h" +#include "Buffer.h" +#include "TextFile.h" +#include "CSVReader.h" +#include "PvlGroup.h" +#include "PvlKeyword.h" +#include "PvlSequence.h" +#include "LineManager.h" +#include "OriginalLabel.h" +#include "SpecialPixel.h" +#include "tnt_array1d.h" +#include "tnt_array1d_utils.h" + +using namespace std; +using namespace Isis; + +typedef TNT::Array1D LutTable; + +// Establish MDIS DN maximums +static const double WACValidMaximum = 3600.0; +static const double NACValidMaximum = 3400.0; + +LutTable lut; +Pvl TranslateMdisEdrLabels (Filename &labelFile, const std::string &target = ""); +int CreateFilterSpecs(const std::string &instId, int filter_code, + PvlGroup &bandbin, std::string &naifId); +void UnlutData(Buffer &data); +LutTable LoadLut(Pvl &label, std::string &tableused, std::string &lutid); +Cube *outCube = NULL; +double validMaxDn = WACValidMaximum; // Assumes the WAC + + +/** + * @brief Helper function to convert values to doubles + * + * @param T Type of value to convert + * @param value Value to convert + * + * @return double Converted value + */ +template double ToDouble(const T &value) { + return (iString(value).Trim(" \r\t\n").ToDouble()); +} + +template int ToInteger(const T &value) { + return (iString(value).Trim(" \r\t\n").ToInteger()); +} + + +void IsisMain () +{ + ProcessImportPds p; + Pvl pdsLabel; + UserInterface &ui = Application::GetUserInterface(); + bool needsUnlut = false; + + // Get the input filename and make sure it is a MESSENGER/MDIS EDR + Filename inFile = ui.GetFilename("FROM"); + iString id; + bool projected; + Pvl lab(inFile.Expanded()); + + try { + needsUnlut = (int) lab.FindKeyword("MESS:COMP12_8"); + // Check for NAC imager + if ((int) lab.FindKeyword("MESS:IMAGER") == 1) validMaxDn = NACValidMaximum; + id = (string) lab.FindKeyword ("MISSION_NAME"); + projected = lab.HasObject("IMAGE_MAP_PROJECTION"); + } + catch (iException &e) { + string msg = "Unable to read [MISSION] from input file [" + + inFile.Expanded() + "]"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + //Checks if in file is rdr + if( projected ) { + string msg = "[" + inFile.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + id.ConvertWhiteSpace(); + id.Compress(); + id.Trim(" "); + if (id != "MESSENGER") { + string msg = "Input file [" + inFile.Expanded() + "] does not appear to be " + + "in MESSENGER EDR format. MISSION_NAME is [" + id + "]"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + std::string target; + if (ui.WasEntered("TARGET")) { + target = ui.GetString("TARGET"); + } + + p.SetPdsFile (inFile.Expanded(), "", pdsLabel); + Pvl outLabel = TranslateMdisEdrLabels (inFile, target); + PvlKeyword sourceId("SourceProductId", '"'+inFile.Basename()+'"'); + + if(ui.GetBoolean("UNLUT") == false || !needsUnlut) { + // We're not going to unlut the data, so just set output cube + // and let ProcessImportPds do the writing for us. + CubeAttributeOutput &outAtt = ui.GetOutputAttribute("TO"); + outCube = p.SetOutputCube(ui.GetFilename("TO"), outAtt); + + // Write the Instrument, BandBin, Archive, and Kernels groups to the output + // cube label + PvlGroup &group = outLabel.FindGroup("Instrument", Pvl::Traverse); + group.AddKeyword(PvlKeyword("Unlutted", !needsUnlut)); + outCube->PutGroup (group); + outCube->PutGroup (outLabel.FindGroup("BandBin", Pvl::Traverse)); + + group = outLabel.FindGroup("Archive", Pvl::Traverse); + group.AddKeyword(sourceId, Pvl::Replace); + outCube->PutGroup (group); + + outCube->PutGroup (outLabel.FindGroup("Kernels", Pvl::Traverse)); + + outCube = NULL; + + // Set valid ranges + p.SetNull(DBL_MIN, 0.0); + p.SetHIS(validMaxDn, DBL_MAX); + + p.StartProcess (); + } + else { + // Unlut is indicated, so we need to handle the conversion and the cube + // writing. Also will enforce DN limits. + std::string lutfile, lutid; + lut = LoadLut(lab, lutfile, lutid); + + outCube = new Cube(); + outCube->SetDimensions(p.Samples(), p.Lines(), p.Bands()); + outCube->Create(ui.GetFilename("TO")); + + PvlGroup &group = outLabel.FindGroup("Instrument", Pvl::Traverse); + group.AddKeyword(PvlKeyword("Unlutted", true)); + group.AddKeyword(PvlKeyword("LutInversionTable", lutfile)); + outCube->Label()->FindObject("IsisCube").AddGroup(group); + + group = outLabel.FindGroup("Archive", Pvl::Traverse); + sourceId.AddValue('"'+lutid+'"'); + group.AddKeyword(sourceId); + outCube->Label()->FindObject("IsisCube").AddGroup(group); + + outCube->Label()->FindObject("IsisCube").AddGroup(outLabel.FindGroup("BandBin", Pvl::Traverse)); + outCube->Label()->FindObject("IsisCube").AddGroup(outLabel.FindGroup("Kernels", Pvl::Traverse)); + + p.StartProcess (UnlutData); + + OriginalLabel ol(Pvl(inFile.Expanded())); + outCube->Write(ol); + outCube->Close(); + delete outCube; + } + + // All finished with the ImportPds object + p.EndProcess (); +} + +Pvl TranslateMdisEdrLabels (Filename &labelFile, const std::string &target) { + //Create a PVL to store the translated labels + Pvl outLabel; + + // Get the directory where the MRO HiRISE translation tables are. + PvlGroup dataDir (Preference::Preferences().FindGroup("DataDirectory")); + iString transDir = (string) dataDir["Messenger"] + "/translations/"; + + // Get a filename for the MESSENGER EDR label + Pvl labelPvl (labelFile.Expanded()); + + // Translate the Instrument group + Filename transFile (transDir + "mdisInstrument.trn"); + PvlTranslationManager instrumentXlater (labelPvl, transFile.Expanded()); + instrumentXlater.Auto (outLabel); + + // Translate the BandBin group + transFile = transDir + "mdisBandBin.trn"; + PvlTranslationManager bandBinXlater (labelPvl, transFile.Expanded()); + bandBinXlater.Auto (outLabel); + + // Translate the Archive group + transFile = transDir + "mdisArchive.trn"; + PvlTranslationManager archiveXlater (labelPvl, transFile.Expanded()); + archiveXlater.Auto (outLabel); + + // Create the Kernel Group + PvlGroup kerns("Kernels"); + PvlGroup &bandbin(outLabel.FindGroup("BandBin", Pvl::Traverse)); + PvlGroup &instGrp(outLabel.FindGroup("Instrument", Pvl::Traverse)); + std::string instId = instGrp["InstrumentId"]; + std::string naifCode; + + // Establish Filter specific keywords + CreateFilterSpecs(instId, (int) instGrp["FilterWheelPosition"], bandbin, + naifCode); + kerns += PvlKeyword("NaifIkCode", naifCode); + outLabel.AddGroup(kerns); + +// If the user specifed the target explicitly or it doesn't exist, create +// something so the camera will always work + if (instGrp.FindKeyword("TargetName").IsNull() || (!target.empty())) { + if (!target.empty()) { + instGrp["TargetName"] = iString(target); + } + else { + instGrp["TargetName"] = iString("Sky"); + } + } + +// Compute the gimble pivot angle and write to the label + double pivotCounter = (double) instGrp["PivotPosition"]; + double pivotAngle = pivotCounter / ((double) (2 << 15)) * 180.0; + instGrp += PvlKeyword("PivotAngle", pivotAngle, "Degrees"); + + return outLabel; +} + +/** + * @brief Determine filter code from filter wheel position code + * + * This routine will determine the true filter wheel from the + * MESS:FW_POS in and image EDR keyword. This routine will + * open the file + * $Messenger/calibration/mdisCalibration????.trn" + * + * @param filter_code The value of the MESS:FW_POS keyword in + * the EDR label. + * @return int Valid filter number between 1 and 12, otherwise + * returns 0. + */ +int CreateFilterSpecs(const std::string &instId, int filter_code, + PvlGroup &bandbin, string &naifCode) { + + // WAC Filter table + struct { int filter; + const char *code; + const char *name; + const char *center; + const char *width; + } WACfilters[] = { + { 1, "A", "700 BW 5", "698.8", "5.3" }, + { 2, "B", "700 BW 600", "700.0", "600.0" }, + { 3, "C", "480 BW 10", "479.9", "10.1" }, + { 4, "D", "560 BW 5", "558.9", "5.8" }, + { 5, "E", "630 BW 5", "628.8", "5.5" }, + { 6, "F", "430 BW 40", "433.2", "18.1" }, + { 7, "G", "750 BW 5", "748.7", "5.1" }, + { 8, "H", "950 BW 7", "947.0", "6.2" }, + { 9, "I", "1000 BW 15", "996.2", "14.3" }, + { 10, "J", "900 BW 5", "898.8", "5.1" }, + { 11, "K", "1020 BW 40", "1012.6", "33.3" }, + { 12, "L", "830 BW 5", "828.4", "5.2" } + }; + + + + naifCode = "NULL"; + int filter(0); + string name, center, width; + + if (instId == "MDIS-NAC") { + naifCode = "-236820"; + filter = 2; + name = "748 BP 53"; + center = "747.7"; + width = "52.6"; + } + else if (instId == "MDIS-WAC") { + // Set up WAC calibration file + Filename calibFile("$messenger/calibration/mdisCalibration????.trn"); + calibFile.HighestVersion(); + Pvl config(calibFile.Expanded()); + + PvlGroup &confgrp = config.FindGroup("FilterWheel"); + int tolerance = confgrp["EncoderTolerance"]; + + naifCode = "-236800"; + for(int filterTry = 1; filterTry <= 12 ; filterTry++) { + int idealPosition = confgrp[iString("EncoderPosition") + iString(filterTry)]; + if ((filter_code <= (idealPosition + tolerance)) && + (filter_code >= (idealPosition - tolerance))) { + int fno = filterTry - 1; + filter = WACfilters[fno].filter; + name = WACfilters[fno].name; + center = WACfilters[fno].center; + width = WACfilters[fno].width; + break; + } + } + } + else { + // Not the expected instrument + string msg = "Unknown InstrumentId [" + instId + "], image does not " + + "appear to be from the MESSENGER/MDIS Camera"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + if (!name.empty()) { + bandbin.AddKeyword(PvlKeyword("Number", filter), PvlContainer::Replace); + bandbin.AddKeyword(PvlKeyword("Name", name),PvlContainer::Replace); + bandbin.AddKeyword(PvlKeyword("Center", center,"NM"),PvlContainer::Replace); + bandbin.AddKeyword(PvlKeyword("Width", width, "NM"),PvlContainer::Replace); + } + else { + // If we reach here, we cannot validate the number - set it to unknown + bandbin.AddKeyword(PvlKeyword("Number", "Unknown"), PvlContainer::Replace); + } + + return (0); +} + +void UnlutData(Buffer &data) { + LineManager out(*outCube); + out.SetLine(data.Line(), data.Band()); + + for(int i = 0; i < data.size(); i++) { + int dnvalue = (int)(data[i] + 0.5); + if(dnvalue < 0 || dnvalue > 255) { + throw iException::Message(iException::User, + "In the input file a value of [" + + iString(data[i]) + + "] was found. Unlutted images should only contain values 0 to 255.", + _FILEINFO_); + } + + out[i] = lut[dnvalue]; + } + + outCube->Write(out); +} + +LutTable LoadLut(Pvl &label, std::string &tableused, std::string &froot) { + int tableToUse = label.FindKeyword("MESS:COMP_ALG"); + + Filename tableFile("$messenger/calibration/LUT_INVERT/MDISLUTINV_?.TAB"); + tableFile.HighestVersion(); + tableused = tableFile.OriginalPath() + "/" + tableFile.Name(); + froot = tableFile.Basename(); + + CSVReader csv(tableFile.Expanded()); + + int nRows = csv.rows(); + if (nRows != 256) { + std::ostringstream mess; + mess << "MDIS LUT Inversion table, " << tableFile.Expanded() + << ", should contain 256 rows but has " << nRows; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + int nCols = csv.columns(); + if (nCols != 9) { + std::ostringstream mess; + mess << "MDIS LUT Inversion table, " << tableFile.Expanded() + << ", should contain 9 columns but has " << nCols; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + LutTable mlut(nRows, Null); // 8 bit => 12 bit, 2^8 = 256 conversion values + + // reset the lookup values to a known bad value + int tableRow = tableToUse + 1; + for(int i = 0; i < nRows; i++) { + CSVReader::CSVAxis row = csv.getRow(i); + int dn8 = ToInteger(row[0]); + + // Gut check! + if ((dn8 < 0) || (dn8 >= nRows)) { + std::ostringstream mess; + mess << "Index (" << dn8 << ") at line " << i+1 + << " is invalid inMDIS LUT Inversion table " + << tableFile.Expanded() << " - valid range is 0 <= index < 256!"; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + double dn16 = ToDouble(row[tableRow]); + if (dn16 > validMaxDn) dn16 = His; + mlut[dn8] = dn16; + } + + // Ensure the 0th pixel is NULL + mlut[0] = Null; + + // cout << "Lut Table " << mlut << endl; + return (mlut); +} + diff --git a/isis/src/messenger/apps/mdis2isis/mdis2isis.xml b/isis/src/messenger/apps/mdis2isis/mdis2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..4ab486456bd50aaaba581a8283691b35b7bc6bb6 --- /dev/null +++ b/isis/src/messenger/apps/mdis2isis/mdis2isis.xml @@ -0,0 +1,148 @@ + + + + + + Import MESSENGER/MIDS EDR/RDR products into ISIS cubes + + + +

    + mdis2isis converts PDS labelled MESSENGER/MDIS EDRs to ISIS labels. + MDIS has a narrow angle camera (MDIS-NAC) and a wide angel camera (MDIS-WAC) + with twelve filters. This application will convert all these observations to ISIS format. + The resulting ISIS cubes are ready for SPICE initialization and projection. +

    +

    + Some of the images are compressed onboard the spacecraft. When this is + detected, they are unlutted and each DN is converted to its precompressed + 12-bit DN value. All output files are created in floating point DN + format. +

    +

    + There are DN limits that are imposed on the output pixel. For the NAC + instrument, the valid range is 0 < DN < 3400. The limit for the WAC + is 0 < DN < 3600. For both instruments, 0 values are mapped to the + NULL special pixel value. And values that exceed the maximum are set to + the HIS (high instrument saturation) special pixel value. +

    +
    + + + Messenger + + + + + Original version + + + Added appTest + + + Added lookup table capabilities + + + Fixed problem where labels went outside the IsisCube object + + + Added validation of filter number here. The number in the label is + unreliable and requires validation as filter identification is critical + in calibration and camera model (at a minimum). If it cannot be + determined, the number is set to "Unknown" which renders the file + unusable for calibration and geometric operations. + + + Checks if input file is rdr. + + + Removed references to CubeInfo + + + Reworked the lut inversion implementation to use a different dn table + source. This altered the resulting DNs a bit. Also instituted DN limits + for low (0) and high saturation levels for WAC (3600) and NAC (3400). DN + values that exceed these maximums are set to NULL and HIS (High + Instrument Saturation), respectively. Started the SOURCE_PRODUCT_ID + pedigree chain. + + + Now looking for mdisCalibration????.trn in $messenger/calibration instead of + $messenger/translations + + + + + + + cube + input + + Input cube file name + + + The input MDIS EDR/RDR file + + + *.IMG *.IMA + + + + + cube + real + output + + Output cube + + + Output file converted from PDS EDR format to ISIS. This ISIS file will have all the + information transferred from the PDS EDR file that is necessary to + initialize for geometric processing (see spiceinit, cam2map, etc...). + + + *.cub + + + + + + + string + Provide observation target if not in EDR + + This parameter may be necessary as some EDR labels do not adequately defined + the TARGET_NAME keyword in the labels. Messenger takes a very long trip to + finally arrive at Mercury orbit in 2011. During cruise, many flybys occur. The + proper specification of the TARGET_NAME is critical to valid instantiation of + ISIS camera models. + + At the time of the original writing of this application, NULL was a frequently + occuring value of the TARGET_NAME keyword even for flyby encounters. + This keyword allows one to specify the observed body explicitiy for these cases. + + The default is to honor the value in the EDR label as it is anticipated this will be + corrected in subsequent EDR generation. + + Label Value + + + boolean + + Convert 8-bit values to 12-bit values + + + If this is set to true, and the input cube is lutted, a lookup table + will be used to convert the original DN values to their original + 12-bit values. This must be set to true for calibration. + + + + true + + + + + + +
    diff --git a/isis/src/messenger/apps/mdis2isis/tsts/Makefile b/isis/src/messenger/apps/mdis2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/messenger/apps/mdis2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/messenger/apps/mdis2isis/tsts/default/Makefile b/isis/src/messenger/apps/mdis2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08d6e415e4f887bcd94d4d95f2ca8ad4765a689a --- /dev/null +++ b/isis/src/messenger/apps/mdis2isis/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME = mdis2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/EN0001426030M.IMG \ + to=$(OUTPUT)/mdis2isisTruth.cub > /dev/null + $(APPNAME) from=$(INPUT)/EN0089569526M.IMG \ + to=$(OUTPUT)/mdis2isisLutTruth.cub > /dev/null + $(APPNAME) from=$(INPUT)/EN0131771763M.IMG \ + to=$(OUTPUT)/mdis2isisStrangeLabelTruth.cub > /dev/null diff --git a/isis/src/messenger/apps/mdis2pds/Makefile b/isis/src/messenger/apps/mdis2pds/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/messenger/apps/mdis2pds/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/messenger/apps/mdis2pds/mdis2pds.cpp b/isis/src/messenger/apps/mdis2pds/mdis2pds.cpp new file mode 100644 index 0000000000000000000000000000000000000000..24ec57eebe1013300529f0b4abd01665189a507d --- /dev/null +++ b/isis/src/messenger/apps/mdis2pds/mdis2pds.cpp @@ -0,0 +1,355 @@ +#include "Isis.h" + +#include +#include +#include +#include + +#include "UserInterface.h" +#include "Progress.h" +#include "Filename.h" +#include "iException.h" +#include "ProcessExportPds.h" +#include "Cube.h" +#include "Histogram.h" +#include "LineManager.h" +#include "OriginalLabel.h" +#include "PvlTranslationManager.h" +#include "BufferManager.h" +#include "LineManager.h" + +using namespace std; +using namespace Isis; + +inline std::string Quote(const std::string &value, const char qChar = '"') { + if (value.empty()) return (value); + if (value[0] == qChar) return (value); + return (std::string(qChar+value+qChar)); + } + +inline double SetRound(double value, const int precision) { + double scale = pow(10.0, precision); + value = rint(value * scale) / scale; + return (value); +} + +inline void ValidateUnit(PvlKeyword &key, const std::string &kunit) { + PvlKeyword temp = key; + key.Clear(); + for (int i = 0 ; i < temp.Size() ; i++) { + try { + // If this works, check unit, otherwise an exception is thrown + (void) temp[i].ToDouble(); + string unit = temp.Unit(i); + if (unit.empty()) unit = kunit; + key.AddValue(temp[i],unit); + } + catch (...) { + key.AddValue(temp[i]); + } + } + return; + } + +inline void FixUnit(PvlObject &obj, const string &key, const string &unit) { + if (obj.HasKeyword(key, PvlObject::Traverse)) { + ValidateUnit(obj.FindKeyword(key, PvlObject::Traverse), unit); + } + return; +} + +inline void FixQuotes(PvlContainer &kcont, const string &value = "N/A") { + PvlContainer::PvlKeywordIterator kiter; + for (kiter = kcont.Begin() ; kiter != kcont.End() ; ++kiter) { + for (int nv = 0 ; nv < kiter->Size() ; nv++) { + if ((*kiter)[nv] == value) (*kiter)[nv] = Quote((*kiter)[nv]); + } + } +} + +inline void FixLabels(PvlObject &obj) { + // Current object-owned keywords + FixQuotes(obj); + + // Fix all nested objects + PvlObject::PvlObjectIterator o; + for (o = obj.BeginObject() ; o != obj.EndObject() ; ++o) { + FixLabels(*o); + } + + // Fix local groups + PvlObject::PvlGroupIterator g; + for (g = obj.BeginGroup() ; g != obj.EndGroup() ; ++g) { + FixQuotes(*g); + } + return; +} + + +void IsisMain () { + const std::string mdis2pds_program = "mdis2pds"; + const std::string mdis2pds_version = "1.0"; + const std::string mdis2pds_revision = "$Revision: 1.10 $"; + const std::string mdis2pds_runtime = Application::DateTime(); + + UserInterface &ui = Application::GetUserInterface(); + Filename input(ui.GetFilename ("FROM")); + Filename output = ui.GetFilename("TO"); + output.AddExtension("IMG"); + + // Set up the export + ProcessExportPds processPds; + Cube *incube = processPds.SetInputCube( "FROM" ); + + Histogram *hist = incube->Histogram(0); + double minmin = 0.0; + double maxmax = 0.0; + if ( ui.GetString("TYPE").compare("AUTOMATIC") == 0 ) { + minmin = (ui.GetDouble("MINPER") <= 0.000001) ? + hist->Minimum() : + hist->Percent(ui.GetDouble("MINPER")); + + maxmax = (ui.GetDouble("MAXPER") >= 99.999999) ? + hist->Maximum() : + hist->Percent(ui.GetDouble("MAXPER")); + } else { + minmin = ui.GetDouble("MIN"); + maxmax = ui.GetDouble("MAX"); + } + + processPds.SetOutputEndian(Isis::Msb); + processPds.SetExportType( ProcessExportPds::Fixed ); + processPds.SetInputRange(minmin, maxmax); + + // Set the output pixel type and the special pixel values + string dataSetID = "MESS-E/V/H-MDIS-"; + int nbits = ui.GetInteger("BITS"); + if (nbits == 8) { + processPds.SetOutputType(UnsignedByte); + processPds.SetOutputRange(VALID_MIN1, VALID_MAX1); + processPds.SetOutputNull(NULL1); + processPds.SetOutputLis(LOW_INSTR_SAT1); + processPds.SetOutputLrs(LOW_REPR_SAT1); + processPds.SetOutputHis(HIGH_INSTR_SAT1); + processPds.SetOutputHrs(HIGH_REPR_SAT1); + dataSetID += "1"; + } + else if (nbits == 16) { + processPds.SetOutputType(UnsignedWord); + processPds.SetOutputRange(VALID_MINU2, VALID_MAXU2); + processPds.SetOutputNull(NULLU2); + processPds.SetOutputLis(LOW_INSTR_SATU2); + processPds.SetOutputLrs(LOW_REPR_SATU2); + processPds.SetOutputHis(HIGH_INSTR_SATU2); + processPds.SetOutputHrs(HIGH_REPR_SATU2); + dataSetID += "2"; + } + else if (nbits == 32 ) { + processPds.SetOutputType(Real); + processPds.SetOutputRange(minmin, maxmax); + processPds.SetOutputNull(NULL4); + processPds.SetOutputLrs(LOW_REPR_SAT4); + processPds.SetOutputLis(LOW_INSTR_SAT4); + processPds.SetOutputHrs(HIGH_REPR_SAT4); + processPds.SetOutputHis(HIGH_INSTR_SAT4); + dataSetID += "4"; + } + else if ( nbits > 8 && nbits < 16 ) { + processPds.SetOutputType(UnsignedWord); + processPds.SetOutputRange(3.0, pow(2.0, (double)(nbits))-3.0); + processPds.SetOutputNull(0); + processPds.SetOutputLrs(1); + processPds.SetOutputLis(2); + processPds.SetOutputHis(pow(2.0, (double)(nbits))-2.0); + processPds.SetOutputHrs(pow(2.0, (double)(nbits))-1.0); + dataSetID += "0"; + } + else { + string msg = "[" + iString(nbits) + "] is not a supported bit length."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + dataSetID += "-CDR-CALDATA-V1.0"; + + Progress p; + p.SetText("Modifying Keywords"); + p.SetMaximumSteps(7); + p.CheckStatus(); + + // Get the PDS label from the process + Pvl &pdsLabel = processPds.StandardPdsLabel(ProcessExportPds::Image); + + // Translate the keywords from the original EDR PDS label that go in + // this RDR PDS label + OriginalLabel origBlob; + incube->Read(origBlob); + Pvl origLabel; + PvlObject origLabelObj = origBlob.ReturnLabels(); + origLabelObj.SetName("OriginalLabelObject"); + origLabel.AddObject(origLabelObj); + + p.CheckStatus(); + + // Translates the ISIS labels along with the original EDR labels + origLabel.AddObject( *(incube->Label()) ); + PvlTranslationManager labels( origLabel, + "$messenger/translations/mdisCdrLabel.trn"); + labels.Auto(pdsLabel); + + p.CheckStatus(); + + // Add keyword comments + PvlKeyword &recordType( pdsLabel.FindKeyword("RECORD_TYPE") ); + recordType.AddComment("/*** FILE FORMAT ***/"); + + PvlKeyword &image( pdsLabel.FindKeyword("^IMAGE") ); + image.AddComment("/*** POINTERS TO START BYTE OFFSET OF OBJECTS IN IMAGE FILE ***/"); + + PvlKeyword &missionName( pdsLabel.FindKeyword("MISSION_NAME") ); + missionName.AddComment("/*** GENERAL DATA DESCRIPTION PARAMETERS ***/"); + + PvlKeyword &startTime( pdsLabel.FindKeyword("START_TIME") ); + startTime.AddComment("/*** TIME PARAMETERS ***/"); + + PvlKeyword &instrumentName( pdsLabel.FindKeyword("INSTRUMENT_NAME") ); + instrumentName.AddComment("/*** INSTRUMENT ENGINEERING PARAMETERS ***/"); + + PvlKeyword &messMetExp( pdsLabel.FindKeyword("MESS:MET_EXP") ); + messMetExp.AddComment("/*** INSTRUMENT RAW PARAMETERS ***/"); + + PvlKeyword &geometry( pdsLabel.FindKeyword("RIGHT_ASCENSION") ); + geometry.AddComment("/*** GEOMETRY INFORMATION ***/"); + + PvlKeyword &target( pdsLabel.FindKeyword("SC_TARGET_POSITION_VECTOR") ); + target.AddComment("/*** TARGET PARAMETERS ***/"); + + PvlKeyword &sensor( pdsLabel.FindKeyword("SLANT_DISTANCE") ); + sensor.AddComment("/*** TARGET WITHIN SENSOR FOV ***/"); + + PvlKeyword &spacecraftPosition( pdsLabel.FindKeyword("SUB_SPACECRAFT_LATITUDE") ); + spacecraftPosition.AddComment("/*** SPACECRAFT POSITION WITH RESPECT TO CENTRAL BODY ***/"); + + PvlKeyword &spacecraftLocation( pdsLabel.FindKeyword("SPACECRAFT_SOLAR_DISTANCE") ); + spacecraftLocation.AddComment("/*** SPACECRAFT LOCATION ***/"); + + PvlKeyword &solarDistance( pdsLabel.FindKeyword("SOLAR_DISTANCE") ); + solarDistance.AddComment("/*** VIEWING AND LIGHTING GEOMETRY (SUN ON TARGET) ***/"); + + PvlGroup &subframe( pdsLabel.FindGroup("SUBFRAME1_PARAMETERS") ); + subframe.AddComment("/*** GEOMETRY FOR EACH SUBFRAME ***/"); + + p.CheckStatus(); + + // Creates keywords from the input's hist above + PvlKeyword minDn( "MINIMUM", SetRound(hist->Minimum(),16) ); + PvlKeyword maxDn( "MAXIMUM", SetRound(hist->Maximum(),16) ); + PvlKeyword meanDn( "MEAN", SetRound(hist->Average(),16) ); + PvlKeyword stddev( "STANDARD_DEVIATION", SetRound(hist->StandardDeviation(),16) ); + + PvlKeyword saturated( "SATURATED_PIXEL_COUNT", hist->HisPixels() ); + + PvlObject &imageObj = pdsLabel.FindObject("IMAGE"); + + minDn.AddComment("/*** IMAGE STATISTICS ***/"); + imageObj.AddKeyword( minDn ); + imageObj.AddKeyword( maxDn ); + imageObj.AddKeyword( meanDn ); + imageObj.AddKeyword( stddev ); + saturated.AddComment("/*** PIXEL COUNTS ***/"); + imageObj.AddKeyword( saturated ); + if (imageObj.HasKeyword("DARK_STRIP_MEAN") ) { + PvlKeyword &darkStripMean = imageObj.FindKeyword("DARK_STRIP_MEAN"); + if (darkStripMean.Size() > 0) { + darkStripMean[0] = iString(SetRound(darkStripMean[0],16)); + } + } + + p.CheckStatus(); + + // Fixes bad keywords + PvlKeyword &data_set_id = pdsLabel.FindKeyword( "DATA_SET_ID", Pvl::Traverse ); + data_set_id.SetValue( dataSetID ); + PvlKeyword &product_id = pdsLabel.FindKeyword( "PRODUCT_ID", Pvl::Traverse ); + if ((product_id.Size() == 0) || ((product_id.Size() > 0) && (product_id[0] == "N/A"))) { + product_id.SetValue( output.Basename() ); + } + PvlKeyword &product_creation_time = pdsLabel.FindKeyword( "PRODUCT_CREATION_TIME", Pvl::Traverse ); + product_creation_time.SetValue( mdis2pds_runtime ); + + PvlKeyword &software_name = pdsLabel.FindKeyword( "SOFTWARE_NAME", Pvl::Traverse ); + if ( (software_name.Size() > 0) && (software_name[0] == "N/A")) { + software_name.SetValue( mdis2pds_program ); + } + + PvlKeyword &software_version_id = pdsLabel.FindKeyword( "SOFTWARE_VERSION_ID", Pvl::Traverse ); + if ( software_version_id.Size() > 0 ) { + if ( software_version_id[0] == "N/A") { + software_version_id.SetValue( Quote(mdis2pds_version) ); + } + else { + software_version_id.SetValue( software_version_id[0] ); + } + } + + PvlKeyword &filter_number = pdsLabel.FindKeyword( "FILTER_NUMBER",Pvl::Traverse ); + if ( (filter_number.Size() > 0) ) { + filter_number.SetValue( Quote(filter_number[0]) ); + } + + + // Add quotes + PvlKeyword &data_quality_id = pdsLabel.FindKeyword( "DATA_QUALITY_ID", Pvl::Traverse ); + data_quality_id.SetValue(Quote(data_quality_id)); + PvlKeyword &sequence_name = pdsLabel.FindKeyword( "SEQUENCE_NAME", Pvl::Traverse ); + sequence_name.SetValue(Quote(sequence_name)); + PvlKeyword &start_count = pdsLabel.FindKeyword( "SPACECRAFT_CLOCK_START_COUNT", Pvl::Traverse ); + start_count.SetValue(Quote(start_count)); + PvlKeyword &stop_count = pdsLabel.FindKeyword( "SPACECRAFT_CLOCK_STOP_COUNT", Pvl::Traverse ); + stop_count.SetValue(Quote(stop_count)); + PvlKeyword &source_product_id = pdsLabel.FindKeyword( "SOURCE_PRODUCT_ID", Pvl::Traverse ); + for ( int i = 0; i < source_product_id.Size(); i++ ) { + source_product_id[i] = Quote(source_product_id[i]); + } + + // Enforce parentheses for scalars + if (source_product_id.Size() == 1) + source_product_id.SetValue('('+source_product_id[0]+')'); + + // Removes keywords + PvlObject &imageObject( pdsLabel.FindObject("IMAGE") ); + imageObject.DeleteKeyword("FILTER_NAME"); + imageObject.DeleteKeyword("CENTER_FILTER_WAVELENGTH"); + imageObject.DeleteKeyword("BANDWIDTH"); + + p.CheckStatus(); + + // Fix all the hosed units upon ingest. They are illformed. + FixUnit(pdsLabel, "RETICLE_POINT_RA", "DEG"); + FixUnit(pdsLabel, "RETICLE_POINT_DECLINATION", "DEG"); + FixUnit(pdsLabel, "RETICLE_POINT_LATITUDE", "DEG"); + FixUnit(pdsLabel, "RETICLE_POINT_LONGITUDE", "DEG"); + + // Now address nested keywords in SUBFRAME groups + for (int i = 1 ; i <= 5 ; i++) { + iString n(i); + string group = "SUBFRAME" + n + "_PARAMETERS"; + if (pdsLabel.HasGroup(group)) { + PvlGroup &grp = pdsLabel.FindGroup(group); + ValidateUnit(grp.FindKeyword("RETICLE_POINT_LATITUDE"), "DEG"); + ValidateUnit(grp.FindKeyword("RETICLE_POINT_LONGITUDE"), "DEG"); + } + } + + p.CheckStatus(); + +// Finally, fix keywords by Quoting missing N/A values + FixLabels(pdsLabel); + p.CheckStatus(); + + // All done...write result. + ofstream outstream( output.Expanded().c_str() ); + processPds.OutputLabel(outstream); + + processPds.StartProcess(outstream); + outstream.close(); + processPds.EndProcess(); +} diff --git a/isis/src/messenger/apps/mdis2pds/mdis2pds.xml b/isis/src/messenger/apps/mdis2pds/mdis2pds.xml new file mode 100644 index 0000000000000000000000000000000000000000..b9fa178f7a777fe5a63203cce5bdb32838506661 --- /dev/null +++ b/isis/src/messenger/apps/mdis2pds/mdis2pds.xml @@ -0,0 +1,208 @@ + + + + + + Exports a Messenger cube back into PDS format + + + + mdis2pds will process a Messenger MDIS cube and export it to PDS/CDR + format. The resulting file will have a PDS compliant label and data object + according to the SIS document. mdis2pds assumes the input file has + at least been run through mdis2isis and mdiscal. This will ensure that + proper values of the PRODUCT_ID and SOURCE_PRODUCT_ID are included in the + output CDR label. + + + + + Original version + + + Shortened and optimized the code handling the histograms. Removed the + 32 bit strech. + + + Fixed for correct source. Previously was using incorrect comparison data. + + + Modified sources of some of the keywords for the translation. Honors + existing software name and versions if they exist; only include the High + Instrument Saturation count in the SATURATED_PIXEL_COUNT label keyword + where before it included all special pixels. + + + Corrected the determination of minimum/maximum data ranges when using the + histogram. The issue involves specifying MAXPER=100.0 and it not + producing the entire valid range of data. This may result in HRS pixels. + It has been changed to use the full valid data range in as computed from + the Histogram. + + + Fixed N/A quoting, misplaced units and data values that exceeded 20 + characters. Also quoted the SOFTWARE_VERSION_ID and FILTER_NUMBER + keyword values. Added units to RETICLE_POINT_* keywords where missing. + + + + + Messenger + + + + + + + + cube + input + Input Messenger cube + + Input filename of a messenger cube file to be exported into a cdr image. + + *.cub + + + + filename + output + + Final output filename. + + + Output filename, by default the filename will be generated from the + input filename. + + + + + + + + + string + AUTOMATIC + + Select the type of stretch + + + This parameter is used to select one of two ways to stretch output + pixels. The are AUTOMATIC or MANUAL. + + + + + + + + + double + + Lower bound of the stretch + + + Lower bound for the manually specified stretch. + + + + double + + Upper bound of the stretch + + + Upper bound for the manually specified stretch. + + + + + double + 0.0 + + Minimum DN valid percentage + + + The cumulative percentage value to be mapped to the minimum + valid pixel for the specified number of bits. For example: With BITS=10 + and MINPER=1.0, the DN which corresponds to the cummulative + percent of 1.0 will be mapped to 3, where 0 represents NULL, 1 + represents LRS and 2 represents LIS. + + 0.0 + 100.0 + + + MAXPER + + + + + double + 100.0 + + Mazimum DN valid percentage + + + The cumulative percentage value to be mapped to the maximum + valid pixel for the specified number of bits. For example: With BITS=10 + and MINPER=99.0, the DN which corresponds to the cummulative + percent of 99.0 will be mapped to 1021, 1021=(2**bits)-1-2. + Where 1023 represents HIS and 1022 represents HRS. + + 0.0 + 100.0 + + + MINPER + + + + + + + + + + integer + 32 + + Number of bits for the output DN + + + The number of bits to compress the input data to. The valid data as + well as the five special pixel values (NULL, LIS, LRS, HIS, HRS) will be + compressed into this number of bits. The output data type will be + automaticity choosen using this value. A value of 8 will create + unsigned byte output files. Values from 9 to 16 will create unsigned + word output files. Unused bits in the unsigned word output file will be + set to zero. + + 8 + 32 + + + + + + + diff --git a/isis/src/messenger/apps/mdis2pds/tsts/Makefile b/isis/src/messenger/apps/mdis2pds/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/messenger/apps/mdis2pds/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/messenger/apps/mdis2pds/tsts/default/Makefile b/isis/src/messenger/apps/mdis2pds/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c5f339d6060dc28534daba1f04768c25dd1cc78e --- /dev/null +++ b/isis/src/messenger/apps/mdis2pds/tsts/default/Makefile @@ -0,0 +1,15 @@ +APPNAME = mdis2pds + +output.cub.TOLERANCE = 0.0000000002 +output.pvl.IGNORELINES = PRODUCT_CREATION_TIME + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/EN0108840044M.cal.cub \ + to=$(OUTPUT)/output > /dev/null; + catlab from=$(OUTPUT)/output.IMG \ + to=$(OUTPUT)/output.pvl > /dev/null; + pds2isis from=$(OUTPUT)/output.IMG \ + to=$(OUTPUT)/output > /dev/null; + $(RM) $(OUTPUT)/output.IMG; diff --git a/isis/src/messenger/apps/mdis2pds/tsts/manual/Makefile b/isis/src/messenger/apps/mdis2pds/tsts/manual/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3676233f19a486f7eddd61d8c05fc7d2cf78b065 --- /dev/null +++ b/isis/src/messenger/apps/mdis2pds/tsts/manual/Makefile @@ -0,0 +1,16 @@ +APPNAME = mdis2pds + +output.cub.TOLERANCE = 0.0000000002 +output.pvl.IGNORELINES = PRODUCT_CREATION_TIME + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/EN0108840044M.cal.cub \ + to=$(OUTPUT)/output type=manual \ + min=-1.0 max=1.0 > /dev/null; + catlab from=$(OUTPUT)/output.IMG \ + to=$(OUTPUT)/output.pvl > /dev/null; + pds2isis from=$(OUTPUT)/output.IMG \ + to=$(OUTPUT)/output > /dev/null; + $(RM) $(OUTPUT)/output.IMG; diff --git a/isis/src/messenger/apps/mdiscal/DarkModelPixel.h b/isis/src/messenger/apps/mdiscal/DarkModelPixel.h new file mode 100644 index 0000000000000000000000000000000000000000..eb95e72d5a2d924eea3cce4c95d6ff159ebc8f17 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/DarkModelPixel.h @@ -0,0 +1,149 @@ +#if !defined(DarkModelPixel_h) +#define DarkModelPixel_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/09/04 18:48:13 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include + +#include "MdisCalUtils.h" +#include "Filename.h" +#include "CSVReader.h" +#include "tnt_array1d.h" +#include "tnt_array1d_utils.h" + +namespace Isis { + + +class DarkModelPixel { + public: + DarkModelPixel() : _scale(1),_ccdTemp(0.0),_expTime(0.0),_coefs(8, 0.0), + _filename() { } + DarkModelPixel(int pixelBinning) : _scale(1),_ccdTemp(0.0),_expTime(0.0), + _coefs(8, 0.0), _filename() { + setPixelBinning(pixelBinning); + } + + DarkModelPixel(int pixelBinning, double ccdTemp, double expTime) : + _scale(1), _ccdTemp(ccdTemp),_expTime(expTime), + _coefs(8, 0.0) { + setPixelBinning(pixelBinning); + setCCDTemperature(ccdTemp); + setExposureTime(expTime); + } + + ~DarkModelPixel() { } + + void setPixelBinning(int pxlBin) { + if ( pxlBin > 0 ) { _scale = (int) std::pow(2.0, pxlBin); } + else { _scale = 1; } + return; + } + void setCCDTemperature(double ccdTemp) { + _ccdTemp = ccdTemp; + return; + } + + /** + * @brief Set exposure time + * @param expTime Exposure time of image in seconds + */ + void setExposureTime(const double &expTime) { + _expTime = expTime * 1000.0; + } + + + std::string loadCoefficients(bool isNac, bool isFpuBinned) { + std::string filename = "$messenger/calibration/DARK_MODEL/MDIS"; + // Filename consists of binned/notbinned, camera, and filter + filename += (isNac)? "NAC" : "WAC"; + filename += (isFpuBinned)? "_BINNED_" : "_NOTBIN_"; + filename += "DARKMODEL_?.TAB"; + + Filename finalName(filename); + finalName.HighestVersion(); + filename = finalName.OriginalPath() + "/" + finalName.Name(); + _filename = filename; + + // Open the CSV file + CSVReader csv(finalName.Expanded()); + DVector coefs(8); + double ccdTempSqrd = _ccdTemp * _ccdTemp; + double ccdTempCubed = ccdTempSqrd * _ccdTemp; + for ( int i = 0 ; i < 8 ; i++ ) { + CSVReader::CSVAxis row = csv.getRow(i); + DVector values(4); + for(int v = 0 ; v < 4 ; v++) { + values[v] = ToDouble(row[v]); + } + + // temps are in order in the file + coefs[i] = values[0] + + values[1] * _ccdTemp + + values[2] * ccdTempSqrd + + values[3] * ccdTempCubed; + } + + // All done, save off coefficients and return filename + _coefs = coefs; + return (filename); + } + + std::string getFilename() const { return (_filename); } + + double getDarkPixel(int sample, int line) const { + double sum(0.0); + double npixels(0.0); + int line0 = line * _scale; + for ( int l = 0 ; l < _scale ; l++, line0++ ) { + int samp0 = sample * _scale; + for ( int s = 0 ; s < _scale ; s++, samp0++ ) { + // ctemp + dtemp*exposure + double acoef = _coefs[0] + _coefs[1] * _expTime; + double bcoef = _coefs[2] + _coefs[3] * _expTime; + double mcoef = _coefs[4] + _coefs[5] * _expTime; + double ncoef = _coefs[6] + _coefs[7] * _expTime; + + double alphacoef = acoef + bcoef * line0; + double betacoef = mcoef + ncoef * line0; + + sum += (alphacoef + betacoef * samp0); + npixels += 1.0; + } + } + + // Return the average + return (sum/npixels); + } + + private: + typedef TNT::Array1D DVector; //!< 1-D Buffer + int _scale; + double _ccdTemp; + double _expTime; + DVector _coefs; + std::string _filename; +}; + +}; +#endif + diff --git a/isis/src/messenger/apps/mdiscal/Makefile b/isis/src/messenger/apps/mdiscal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/messenger/apps/mdiscal/MdisCalUtils.h b/isis/src/messenger/apps/mdiscal/MdisCalUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..c4889714df765c40c26161aae48d6054904feceb --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/MdisCalUtils.h @@ -0,0 +1,256 @@ +#if !defined(MdisCalUtils_h) +#define MdisCalUtils_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/11/19 22:35:13 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "iString.h" +#include "Filename.h" +#include "CSVReader.h" + +namespace Isis { +/** + * @brief Helper function to convert values to doubles + * + * @param T Type of value to convert + * @param value Value to convert + * + * @return double Converted value + */ +template double ToDouble(const T &value) { + return (iString(value).Trim(" \r\t\n").ToDouble()); +} + +template int ToInteger(const T &value) { + return (iString(value).Trim(" \r\t\n").ToInteger()); +} + +template inline T MIN(const T &A, const T &B) { + return ( ((A) < (B)) ? (A) : (B)); + } + + template inline T MAX(const T &A, const T &B) { + return ( ((A) > (B)) ? (A) : (B)); + } + + inline std::string Quote(const std::string &value) { + if (value.empty()) return (value); + if(value[0] == '"') return (value); + return (std::string('"'+value+'"')); + } + +/** + * @brief Load required NAIF kernels required for timing needs + * + * This method maintains the loading of kernels for MESSENGER timing and + * planetary body ephemerides to support time and relative positions of planet + * bodies. + */ +static void loadNaifTiming( ) { + static bool _naifLoaded(false); + if (!_naifLoaded) { +// Load the NAIF kernels to determine timing data + Isis::Filename leapseconds("$base/kernels/lsk/naif????.tls"); + leapseconds.HighestVersion(); + + Isis::Filename sclk("$messenger/kernels/sclk/messenger_???.tsc"); + sclk.HighestVersion(); + + Isis::Filename pck("$base/kernels/spk/de???.bsp"); + pck.HighestVersion(); + +// Load the kernels + std::string leapsecondsName(leapseconds.Expanded()); + std::string sclkName(sclk.Expanded()); + std::string pckName(pck.Expanded()); + furnsh_c(leapsecondsName.c_str()); + furnsh_c(sclkName.c_str()); + furnsh_c(pckName.c_str()); + +// Ensure it is loaded only once + _naifLoaded = true; + } + return; +} + + /** + * @brief Computes the distance from the Sun to the observed body + * + * This method requires the appropriate NAIK kernels to be loaded that + * provides instrument time support, leap seconds and planet body ephemeris. + * + * @return double Distance in AU between Sun and observed body + */ +static bool sunDistanceAU(const std::string &scStartTime, + const std::string &target, + double &sunDist) { + + // Ensure NAIF kernels are loaded + loadNaifTiming(); + sunDist = 1.0; + + // Determine if the target is a valid NAIF target + SpiceInt tcode; + SpiceBoolean found; + (void) bodn2c_c(target.c_str(), &tcode, &found); + if (!found) return (false); + + // Convert starttime to et + double obsStartTime; + scs2e_c (-236,scStartTime.c_str(),&obsStartTime); + + // Get the vector from target to sun and determine its length + double sunv[3]; + double lt; + (void) spkpos_c(target.c_str(), obsStartTime, "J2000", "LT+S", "sun", + sunv, <); + double sunkm = vnorm_c(sunv); + + // Return in AU units + sunDist = sunkm/1.49597870691E8; + return (true); +} + +std::vector loadWACCSV(const std::string &fname, int filter, + int nvalues, bool header = true, int skip = 0) { + // Open the CSV file + Filename csvfile(fname); + CSVReader csv(csvfile.Expanded(), header, skip); + for (int i = 0 ; i < csv.rows() ; i++) { + CSVReader::CSVAxis row = csv.getRow(i); + if (ToInteger(row[0]) == filter) { + if ((row.dim1()-1) < nvalues) { + std::string mess = "Number values (" + iString(row.dim1()-1) + + ") in file " + fname + + " less than number requested (" + + iString(nvalues) + ")!"; + throw iException::Message(iException::User, mess.c_str(), _FILEINFO_); + } + std::vector rsp; + for(int i = 0 ; i < nvalues ; i++) { + rsp.push_back(ToDouble(row[1+i])); + } + return (rsp); + } + } + + // If it reaches here, the filter was not found + std::ostringstream mess; + mess << "CSV Vector MDIS filter " << filter << ", not found in file " + << fname << "!"; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); +} + + + std::vector loadNACCSV(const std::string &fname, int nvalues, + bool header = true, int skip = 0) { + // Open the CSV file + Filename csvfile(fname); + CSVReader csv(csvfile.Expanded(), header, skip); + CSVReader::CSVAxis row = csv.getRow(0); + if (row.dim1() < nvalues) { + std::string mess = "Number values (" + iString(row.dim1()) + + ") in file " + fname + " less than number requested (" + + iString(nvalues) + ")!"; + throw iException::Message(iException::User, mess.c_str(), _FILEINFO_); + + } + std::vector rsp; + for(int i = 0 ; i < nvalues ; i++) { + rsp.push_back(ToDouble(row[i])); + } + return (rsp); +} + + +std::vector loadResponsivity(bool isNAC, bool binned, int filter, + std::string &fname) { + + Filename resfile(fname); + if(fname.empty()) { + std::string camstr = (isNAC) ? "NAC" : "WAC"; + std::string binstr = (binned) ? "_BINNED" : "_NOTBIN"; + std::string base = "$messenger/calibration/RESPONSIVITY/"; + resfile = base + "MDIS" + camstr + binstr + "_RESP_?.TAB"; + resfile.HighestVersion(); + fname = resfile.OriginalPath() + "/" + resfile.Name(); + } + + // Unfortunately NAC has a slightly different format so must do it + // explicitly + if (isNAC) { + return (loadNACCSV(fname, 4, false, 0)); + } + else { + // Load the WAC parameters + return (loadWACCSV(fname, filter, 4, false, 0)); + } +} + + +std::vector loadSolarIrr(bool isNAC, bool binned, int filter, + std::string &fname) { + + Filename solfile(fname); + if(fname.empty()) { + std::string camstr = (isNAC) ? "NAC" : "WAC"; + std::string base = "$messenger/calibration/SOLAR/"; + solfile = base + "MDIS" + camstr + "_SOLAR_?.TAB"; + solfile.HighestVersion(); + fname = solfile.OriginalPath() + "/" + solfile.Name(); + } + + if (isNAC) { + return (loadNACCSV(fname, 3, false, 0)); + } + else { + return (loadWACCSV(fname, filter, 3, false, 0)); + } +} + +double loadSmearComponent(bool isNAC, int filter, std::string &fname) { + + Filename smearfile(fname); + if(fname.empty()) { + std::string camstr = (isNAC) ? "NAC" : "WAC"; + std::string base = "$messenger/calibration/smear/"; + smearfile = base + "MDIS" + camstr + "_FRAME_TRANSFER_??.TAB"; + smearfile.HighestVersion(); + fname = smearfile.OriginalPath() + "/" + smearfile.Name(); + } + + std::vector smear; + if (isNAC) { + smear = loadNACCSV(fname, 1, false, 0); + } + else { + smear = loadWACCSV(fname, filter, 1, false, 0); + } + return (smear[0]); +} + + +}; +#endif diff --git a/isis/src/messenger/apps/mdiscal/assets/images/EW0089565626A.jpg b/isis/src/messenger/apps/mdiscal/assets/images/EW0089565626A.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5e1fdf41b69b4cdb142faf3358d333586ef36193 Binary files /dev/null and b/isis/src/messenger/apps/mdiscal/assets/images/EW0089565626A.jpg differ diff --git a/isis/src/messenger/apps/mdiscal/assets/images/EW0089565626A.model.jpg b/isis/src/messenger/apps/mdiscal/assets/images/EW0089565626A.model.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a1da521d50ea1eb507165db9a38157386ebb70fe Binary files /dev/null and b/isis/src/messenger/apps/mdiscal/assets/images/EW0089565626A.model.jpg differ diff --git a/isis/src/messenger/apps/mdiscal/assets/images/mdiscal.jpg b/isis/src/messenger/apps/mdiscal/assets/images/mdiscal.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4b90f26810e18c3979d3934c54a22ca643e40816 Binary files /dev/null and b/isis/src/messenger/apps/mdiscal/assets/images/mdiscal.jpg differ diff --git a/isis/src/messenger/apps/mdiscal/assets/thumbs/EW0089565626A.jpg b/isis/src/messenger/apps/mdiscal/assets/thumbs/EW0089565626A.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3c8f84725cf40c84b2d8e04b9a37d7baccf851d1 Binary files /dev/null and b/isis/src/messenger/apps/mdiscal/assets/thumbs/EW0089565626A.jpg differ diff --git a/isis/src/messenger/apps/mdiscal/assets/thumbs/EW0089565626A.model.jpg b/isis/src/messenger/apps/mdiscal/assets/thumbs/EW0089565626A.model.jpg new file mode 100644 index 0000000000000000000000000000000000000000..60e976af48da0b8576fe25f5c69631848c3df736 Binary files /dev/null and b/isis/src/messenger/apps/mdiscal/assets/thumbs/EW0089565626A.model.jpg differ diff --git a/isis/src/messenger/apps/mdiscal/assets/thumbs/mdiscal.jpg b/isis/src/messenger/apps/mdiscal/assets/thumbs/mdiscal.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6c17145834ded7135adae82a701a3cb215935e95 Binary files /dev/null and b/isis/src/messenger/apps/mdiscal/assets/thumbs/mdiscal.jpg differ diff --git a/isis/src/messenger/apps/mdiscal/mdiscal.cpp b/isis/src/messenger/apps/mdiscal/mdiscal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae81f3bae227a19bdb0642f75e8c8e5742f8f9b2 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/mdiscal.cpp @@ -0,0 +1,563 @@ +// $Id: mdiscal.cpp,v 1.22 2009/09/04 17:59:05 mboyd Exp $ +#include "Isis.h" + +#include +#include +#include +#include +#include +#include + +#include "ProcessByLine.h" +#include "Statistics.h" +#include "MultivariateStatistics.h" +#include "TextFile.h" +#include "Spice.h" +#include "MdisCalUtils.h" +#include "DarkModelPixel.h" + +using namespace Isis; +using namespace std; + +bool convertDarkToNull; +enum MdisDarkCurrentMode { + DarkCurrentNone, + DarkCurrentStandard, + DarkCurrentLinear, + DarkCurrentModel +}; + + +MdisDarkCurrentMode darkCurrentMode; +vector calibrationValues; +bool isNarrowAngleCamera; +bool isBinnedData; +double exposureDuration; +double ccdTemperature; +int filterNumber; +static int nDarkColumns(0); +static int nValidDark(0); +Statistics darkStrip; +vector prevLineData; +vector smearData; +double smearComponent(3.4); +Pvl configFile; + +// Absolute coefficents +static double abs_coef(1.0); + +// I/F variables +static double solarDist(1.0); +static double F_f(1.0); +static double iof(1.0); // I/F value for observation +static DarkModelPixel *model(0); + +// Local functions +Filename DetermineFlatFieldFile(); +void GatherDarkStatistics(Buffer &in); +void Calibrate(vector&in, vector&out); + +void IsisMain() { + + const string mdiscal_program = "mdiscal"; + const string mdiscal_version = "1.2"; + const string mdiscal_revision = "$Revision: 1.22 $"; + string mdiscal_runtime = Application::DateTime(); + + // Specify the version of the CDR generated + const int cdr_version = 3; + + // We will be processing by column in case of a linear dark current fit. This will make the + // calibration a one pass system in this case, rather than two. + ProcessByLine p; + Filename calibFile("$messenger/calibration/mdisCalibration????.trn"); + calibFile.HighestVersion(); + configFile.Read(calibFile.Expanded()); + + // Initialize variables + calibrationValues.clear(); + prevLineData.clear(); + convertDarkToNull = true; + isNarrowAngleCamera = true; + isBinnedData = true; + darkCurrentMode = (MdisDarkCurrentMode)-1; + exposureDuration = 0.0; + ccdTemperature = 0.0; // This needs figured out! + filterNumber = 1; // Sufficent for the NAC! + model = 0; + + Cube *icube = p.SetInputCube("FROM"); + PvlGroup &inst = icube->GetGroup("Instrument"); + isNarrowAngleCamera = ((string)inst["InstrumentId"] == "MDIS-NAC"); + exposureDuration = inst["ExposureDuration"]; + exposureDuration /= 1000.0; // Convert ms to sec + + // Determine dark columns + int fpuBin = inst["FpuBinningMode"]; + int pxlBin = inst["PixelBinningMode"]; + nDarkColumns = 4 / (fpuBin+1) / (pxlBin+1); + nValidDark = MIN(nDarkColumns, 3); + if(nValidDark < 3) { + if ((fpuBin+pxlBin) > 1) nValidDark = 0; + else nValidDark = MIN(nValidDark, 1); + } + darkStrip.Reset(); + + + ccdTemperature = icube->GetGroup("Archive")["CCDTemperature"]; + + // Binned data only applies to FPUBIN mode. Pixel binning must be dealt + // with specially in other calibration support components + isBinnedData = (fpuBin == 1); + + // Get the trusted filter number + if( !isNarrowAngleCamera ) { + filterNumber = ((int) (icube->GetGroup("BandBin")["Number"])) - 1; + } + else { + filterNumber = 1; // For the NAC + } + + UserInterface &ui = Application::GetUserInterface(); + convertDarkToNull = !ui.GetBoolean("KEEPDARK"); + + iString darkCurr = ui.GetString("DARKCURRENT"); + + if(icube->Bands() != 1) { + throw iException::Message(iException::User, + "MDIS images may only contain one band", _FILEINFO_); + } + + if(icube->Samples() < 3) { + throw iException::Message(iException::User, + "Unable to obtain dark current data. Expected a sample dimension of at least 3", _FILEINFO_); + } + + if((int)icube->GetGroup("Instrument")["Unlutted"] == false) { + throw iException::Message(iException::User, + "Calibration may not be performed on unlutted data.", _FILEINFO_); + } + + + // Check for cases where certain models cannot be computed. + // These would be for cases where more than two factors of compression + // occur. For this case, only the model can be used and only if the + // exposure time < 2 secs. + if ((darkCurr != "NONE") && (nValidDark <= 0)) { + // Both cases require dark pixels, model does not + if ((darkCurr == "STANDARD") || (darkCurr == "LINEAR")) { + darkCurr = "MODEL"; + string mess = "There are no valid dark current pixels which are required" + " for " + darkCurr + " calibration... must use MODEL"; + iException &ie= iException::Message(iException::User, mess, _FILEINFO_); + ie.Report(); + ie.Clear(); + } + + // Model cannot be used for exposure times > 1.0 + if ((darkCurr == "MODEL") && (exposureDuration > 1.0)) { + darkCurr = "NONE"; + string mess = "There are no valid dark current pixels and the dark model" + " correction can not be used when the exposure duration" + " exceeds 1000...image cannot be calibrated"; + iException &ie= iException::Message(iException::User, mess, _FILEINFO_); + ie.Report(); + ie.Clear(); + } + } + + auto_ptr darkModel; + if(darkCurr == "NONE") { + darkCurrentMode = DarkCurrentNone; + } + else if(darkCurr == "STANDARD") { + darkCurrentMode = DarkCurrentStandard; + calibrationValues.resize(icube->Lines()); + } + else if(darkCurr == "LINEAR") { + darkCurrentMode = DarkCurrentLinear; + calibrationValues.resize(icube->Lines()); + } + else if(darkCurr == "MODEL") { + if(exposureDuration > 1.0) { + string mess = "Dark model correction can not be used when the " + "exposure duration exceeds 1000...using LINEAR instead."; + iException &ie= iException::Message(iException::User, mess, _FILEINFO_); + ie.Report(); + ie.Clear(); + + // set processing to standard + darkCurrentMode = DarkCurrentLinear; + calibrationValues.resize(icube->Lines()); + darkCurr = "STANDARD"; + } + else { + darkCurrentMode = DarkCurrentModel; + } + } + else { + // should never happen + throw iException::Message(iException::Programmer, + "Invalid dark current mode [" + + darkCurr + "]", _FILEINFO_); + } + + string darkCurrentFile(""); + if(darkCurrentMode != DarkCurrentNone) { + if(darkCurrentMode != DarkCurrentModel) { + p.Progress()->SetText("Gathering Dark Current Statistics"); + p.StartProcess(GatherDarkStatistics); + } + else { + // read in dark current table variables and report the filename used + darkModel = auto_ptr (new DarkModelPixel(pxlBin,ccdTemperature, exposureDuration)); + darkCurrentFile = darkModel->loadCoefficients(isNarrowAngleCamera, isBinnedData); + model = darkModel.get(); + } + } + + // We need to figure out our flat-field file + if(darkCurrentMode == DarkCurrentLinear) { + // We need to perform a linear regression with our data, + // convert statistics to a line. + double *xdata = new double[calibrationValues.size()]; + double *ydata = new double[calibrationValues.size()]; + + for(unsigned int x = 0; x < calibrationValues.size(); x++) { + xdata[x] = x; + ydata[x] = calibrationValues[x]; + } + + // Perform a regression + MultivariateStatistics stats; + stats.AddData(xdata, ydata, calibrationValues.size()); + + // y = A + Bx + double a, b; + stats.LinearRegression(a,b); + delete [] xdata; + delete [] ydata; + + // Store a,b in calibration data instead of our line + calibrationValues.resize(2); + calibrationValues[0] = a; + calibrationValues[1] = b; + } + + // Compute the (new) absolute calibration + string respfile(""); + vector rsp = loadResponsivity(isNarrowAngleCamera, isBinnedData, + filterNumber+1, respfile); + // abs_coef = 1.0 / (rsp[0] * ((rsp[2] * ccdTemperature) + rsp[1])); + double T = 1.0; + double Rt = rsp[0]; + double Resp = 0; + for (unsigned int i = 1 ; i < rsp.size() ; i++) { + Resp += Rt * (rsp[i] * T); + T *= ccdTemperature; + } + abs_coef = 1.0 / Resp; + + // Retrieve filter dependant SMEAR component + string smearfile(""); + smearComponent = loadSmearComponent(isNarrowAngleCamera, filterNumber+1, + smearfile); + + // Compute I/F if requested by user + iof = 1.0; + bool do_iof = ui.GetBoolean("IOF"); + bool iof_is_good = false; + string solirrfile(""); + if(ui.GetBoolean("IOF")) { + PvlGroup &inst = icube->GetGroup("Instrument"); + string target = inst["TargetName"]; + string startTime = inst["SpacecraftClockCount"]; + if (sunDistanceAU(startTime, target, solarDist)) { + vector sol = loadSolarIrr(isNarrowAngleCamera, isBinnedData, + filterNumber+1, solirrfile); + F_f = sol[2]; + iof = pi_c() * (solarDist * solarDist) / F_f; + iof_is_good = true; + } + else { + iof = 1.0; + iof_is_good = false; + } + } + + // Determine if we need to subsample the flat field should pixel binning + // occurred + string reducedFlat(""); + Filename flatfield = DetermineFlatFieldFile(); + if (pxlBin > 0) { + iString scale(pow(2.0, pxlBin)); + Filename newflat; + newflat.Temporary(flatfield.Basename()+"_reduced", "cub"); + string parameters = "FROM=" + flatfield.Expanded() + + " TO=" + newflat.Expanded() + + " REDUCTION_TYPE=SCALE" + + " LSCALE=" + scale + + " SSCALE=" + scale; + cout << "Running: reduce " << parameters << endl; + iApp->Exec("reduce",parameters); + reducedFlat = newflat.Expanded(); + CubeAttributeInput att; + p.SetInputCube(reducedFlat,att); + } + else { + CubeAttributeInput att; + p.SetInputCube(flatfield.Expanded(),att); + } + + // Set output file for processing + Cube *ocube = p.SetOutputCube("TO"); + + try { + p.Progress()->SetText("Calibrating MDIS Cube"); + p.StartProcess(Calibrate); + } catch (...) { + if (!reducedFlat.empty()) remove(reducedFlat.c_str()); + throw; + } + + // Remove the temporary reduced input file if generated + if (!reducedFlat.empty()) remove(reducedFlat.c_str()); + + // Log calibration activity + PvlGroup calibrationLog("RadiometricCalibration"); + calibrationLog.AddKeyword(PvlKeyword("SoftwareName", mdiscal_program)); + calibrationLog.AddKeyword(PvlKeyword("SoftwareVersion", mdiscal_version)); + calibrationLog.AddKeyword(PvlKeyword("ProcessDate", mdiscal_runtime)); + calibrationLog.AddKeyword(PvlKeyword("From", (string)ui.GetFilename("FROM"))); + calibrationLog.AddKeyword(PvlKeyword("DarkCurrentModel", darkCurr)); + + if(darkCurrentMode == DarkCurrentLinear) { + iString equation = "Y = " + iString(calibrationValues[0]) + iString(" + ") + iString(calibrationValues[1]) + iString("x"); + calibrationLog.AddKeyword(PvlKeyword("DarkCurrentEquation", (string)equation)); + } + else if(darkCurrentMode == DarkCurrentModel) { + calibrationLog.AddKeyword(PvlKeyword("DarkCurrentFile", darkCurrentFile)); + } + + calibrationLog.AddKeyword(PvlKeyword("BinnedImage", isBinnedData)); + calibrationLog.AddKeyword(PvlKeyword("FilterNumber", filterNumber+1)); + calibrationLog.AddKeyword(PvlKeyword("FlatFieldFile", flatfield.OriginalPath() + "/" + flatfield.Name())); + calibrationLog.AddKeyword(PvlKeyword("CalibrationFile", calibFile.OriginalPath() + "/" + calibFile.Name())); + calibrationLog.AddKeyword(PvlKeyword("ResponsivityFile", respfile)); + calibrationLog.AddKeyword(PvlKeyword("SmearCompFile", smearfile)); + PvlKeyword rspKey("Response", rsp[0]); + for (unsigned int i = 1 ; i < rsp.size() ; i++) { + rspKey.AddValue(rsp[i]); + } + calibrationLog.AddKeyword(rspKey); + calibrationLog.AddKeyword(PvlKeyword("SmearComponent", smearComponent)); + + string calibType; + if ( do_iof && iof_is_good ) { + calibrationLog.AddKeyword(PvlKeyword("Units", "I over F")); + calibrationLog.AddKeyword(PvlKeyword("SolarDistance", solarDist, "AU")); + calibrationLog.AddKeyword(PvlKeyword("SolarIrrFile", solirrfile)); + calibrationLog.AddKeyword(PvlKeyword("FilterIrradianceFactor", F_f)); + calibrationLog.AddKeyword(PvlKeyword("IOFFactor", iof)); + calibType = "IF"; + } + else { + calibrationLog.AddKeyword(PvlKeyword("Units", "W / (m**2 micrometer sr )")); + calibType = "RA"; + } + + calibrationLog.AddKeyword(PvlKeyword("DarkStripColumns",nDarkColumns), + Pvl::Replace); + if (darkStrip.TotalPixels() > 0) { + calibrationLog.AddKeyword(PvlKeyword("DarkStripMean",darkStrip.Average()), + Pvl::Replace); + } + + // Handle updates of ProductId and SourceProduct Id keywords + PvlGroup &archive = ocube->GetGroup("Archive"); + PvlKeyword key = archive["ProductId"]; + iString orgProdId = key[0]; + iString newProdId = orgProdId + "_" + calibType + "_" + iString(cdr_version); + newProdId[0] = 'C'; + key.SetValue(Quote(newProdId)); + archive.AddKeyword(key, Pvl::Replace); + + // Now SourceProductId + if(archive.HasKeyword("SourceProductId")) { + key = archive["SourceProductId"]; + for(int i = 0 ; i < key.Size() ; i++) { + key[i] = Quote(key[i]); + } + } + else { + key = PvlKeyword("SourceProductId", Quote(orgProdId)); + } + + if(!darkCurrentFile.empty()) { + key.AddValue(Quote(Filename(darkCurrentFile).Basename())); + } + key.AddValue(Quote(flatfield.Basename())); + key.AddValue(Quote(Filename(respfile).Basename())); + // key.AddValue(Quote(Filename(smearfile).Basename())); + if (iof_is_good) { + key.AddValue(Quote(Filename(solirrfile).Basename())); + } + archive.AddKeyword(key, Pvl::Replace); + + // Write Calibration group to file and log + ocube->PutGroup(calibrationLog); + Application::Log(calibrationLog); + configFile.Clear(); +} + +Filename DetermineFlatFieldFile() { + string filename = "$messenger/calibration/FLAT/"; + + // Filename consists of binned/notbinned, camera, and filter + filename += "MDIS"; + filename += ((isNarrowAngleCamera)? "NAC" : "WAC"); + filename += ((isBinnedData)? "_BINNED_" : "_NOTBIN_"); + filename += "FLAT"; + if (isNarrowAngleCamera) { + // NAC spec is simpler + filename += "_?.cub"; + } + else { + // add a zero if the filter is 1-digit + filename += "_FIL"; + if (filterNumber < 9) filename += "0"; + filename += iString(filterNumber+1); + filename += "_?.cub"; + } + + Filename final(filename); + final.HighestVersion(); + return final; +} + + +void GatherDarkStatistics(Buffer &in) { + + // Some situations cannot use these processes for calibration + calibrationValues[in.Line()-1] = Isis::Null; + + if(nDarkColumns > 0) { + if(darkCurrentMode == DarkCurrentStandard) { + // Figure out the median (Isis::Statistics wont do this for us) + // because we have repeated numbers, put them into a sorted array size + // of no more than 3 and take the middle + vector calibValues; + int nDark = nValidDark; + for(int i = 0 ; i < nDark ; i++) { + calibValues.push_back(in[i]); + } + sort(calibValues.begin(), calibValues.end()); + + // grab the middle element in the array for the median + calibrationValues[in.Line()-1] = calibValues[nDark/2]; + } + else if(darkCurrentMode == DarkCurrentLinear) { + // Presently the linear regression only uses the first sample in the + // dark current data + calibrationValues[in.Line()-1] = in[0]; + } + } +} + +void Calibrate(vector&in, vector&out) { + Buffer &imageIn = *in[0]; + Buffer &flatField = *in[1]; + Buffer &imageOut = *out[0]; + + if(imageIn.Line() == 1) { + prevLineData.resize(imageIn.SampleDimension()); + smearData.resize(imageIn.SampleDimension()); + + for(unsigned int i = 0; i < prevLineData.size(); i++) { + prevLineData[i] = 0.0; + smearData[i] = 0.0; + } + } + + for(int i = 0; i < imageIn.size(); i++) { + + // Check for special pixel in input image and pass through + if(Isis::IsSpecial(imageIn[i])) { + imageOut[i] = imageIn[i]; + continue; + } + + // If the flat field pixel is special, can't calibrate so set to NULL + // and pass through (unlikely). + if(Isis::IsSpecial(flatField[i])) { + imageOut[i] = Isis::Null; + continue; + } +//462 +// if(i == 25 && imageIn.Line() == 25) std::cout << "In: " << imageIn[i] << std::endl; + + // Step 1: Perform dark current corrections + if(darkCurrentMode == DarkCurrentNone) { + imageOut[i] = imageIn[i]; + } + else if(darkCurrentMode == DarkCurrentStandard) { + imageOut[i] = imageIn[i] - calibrationValues[imageIn.Line()-1]; + } + else if(darkCurrentMode == DarkCurrentLinear) { + // Linear: out = in - bestfitline = in - (A + Bx) + imageOut[i] = imageIn[i] - (calibrationValues[0] + calibrationValues[1] * + (imageIn.Line()-1)); + } + else if(darkCurrentMode == DarkCurrentModel) { + imageOut[i] = imageIn[i] - model->getDarkPixel(i, imageIn.Line()-1); + } + + // Step 2: Perform linearity correction + if(isNarrowAngleCamera == true) { + if(imageOut[i] <= 0.0) { + imageOut[i] /= 0.912031; + } + else { + imageOut[i] /= 0.011844 * log10(imageOut[i]) + 0.912031; + } + } + else { + // Wide angle camera + if(imageOut[i] <= 0.0) { + imageOut[i] /= 0.936321; + } + else { + imageOut[i] /= 0.008760 * log10(imageOut[i]) + 0.936321; + } + } + + // Step 3: Readout Smear Correction (ms -> seconds) + double t2 = smearComponent / imageIn.SampleDimension() / 1000.0; + + if(exposureDuration > 0.0 && imageIn.Line() > 1) { + smearData[i] += t2 / exposureDuration * prevLineData[i]; + imageOut[i] -= smearData[i]; + } + + prevLineData[i] = imageOut[i]; + + // Step 4: Uniformity (flat field) + imageOut[i] /= flatField[i]; // divide by flat field + + // Step 5: Absolute coefficient + if(exposureDuration > 0.0) { + imageOut[i] = imageOut[i] / exposureDuration * abs_coef; + } + + // Step 6: Convert to I/F units + imageOut[i] *= iof; + } + + // Compute dark current statistics and NULL'em if requested + for(int j = 0 ; j < nDarkColumns; j++) { + darkStrip.AddData(imageOut[j]); + if(convertDarkToNull) imageOut[j] = Isis::Null; + } + +} + diff --git a/isis/src/messenger/apps/mdiscal/mdiscal.xml b/isis/src/messenger/apps/mdiscal/mdiscal.xml new file mode 100644 index 0000000000000000000000000000000000000000..5c719e16eed90da9c7a8df2c42edd22c3a7aa9c9 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/mdiscal.xml @@ -0,0 +1,606 @@ + + + + + + Calibrates MESSENGER/MIDS EDR/RDR products + + + + Messenger images are corrected for the following, in order, during + calibration:
    +
      +
    • + Dark Current +
    • +
    • + Linearity +
    • +
    • + Smear +
    • +
    • + Uniformity (flat field) +
    • +
    • + Absolute coefficient +
    • +
    +
    + Dark current correction: +
      +
    • + None +
    • + No dark current correction is performed. +
    • + Standard +
    • + Messenger images have a strip of dark current data on the left-hand side. + This will take a median of the first three sample colums (for unbinned + data) and use that for the dark current on a line by line basis. +
    • + Linear +
    • + This will fit a line across the first column of data, which is dark + current data, and use the line to determine the dark current correction. +
    • + Model +
    • + There are independent dark models, developed on-ground. This will use the + most recent of these models to correct the dark current. +
    + Linearity Correction:
    + Linearity is the measure of how variable is each camera's DN level per unit + exposure time and radiance, as a function of variation in exposure time or + radiance. Using dark-corrected, desmeared DN values (DCDSI) taken from the + center quarter of the images, response linearity was measured with both the + NAC and WAC binned and not-binned.

    + + Smear Correction:
    + Frame transfer smear corrections for MDIS follow the technique described for + NEAR MSI image by Murchie et al. (1999). In brief, an image is exposed for a + nominal integration time and is then transferred in 3.84 ms to a memory zone + on the CCD, from which the analog signal is digitized line-by-line. + Accumulation of signal continues during the finite duration of frame + transfer, inducing a streak or frame-transfer smear in the wake of an + illuminated object in the field of view, parallel to the direction of frame + transfer.

    + Uniformity Correction:
    + Response uniformity, or flat field, is a measure of pixel-to-pixel + variations in responsivity. Measurements of response uniformity of the WAC + and NAC were conducted in the OCF, at room temperature and while cold, by + imaging the integrating sphere with the two 45W bulbs illuminating the + interior.

    + Absolute Coefficient Correction:
    + This converts the DN values from responsivity to radiance values. +

    + The MODEL dark current option cannot be used if the exposure time + exceeds 1 second. In this case, the LINEAR model is selected and a + message is issued to the user. +

    +

    + Note that there are some extreme cases where an image could not be + radiometrically calibrated. When there is more than two factors of + binning, FPU or PIXEL, then there are no valid dark pixel colums. For + this case, calibrations using STANDARD or LINEAR cannot be used, however, + the MODEL can. But, the MODEL cannot be used if the exposure time is + exceeds 1 seconds. And in this case, the image cannot be calibrated. + When these conditions are detected, a message is issued, but calibration + continues using either the MODEL or NONE as the calibration mode. +

    +

    + The following is an excerpt from the MESSENGER MDIS calibration document + on this process +

    +
    +Raw units are of DN converted to the physical units
    +of radiance or I/F, following the calibration equation:
    +
    +L(x,y,f,T,t,b) = Lin[DN(x,y,f,T,t,b,MET) - Dk(x,y,T,t,b,MET) -
    +Sm(x,y,t,b)] / [Flat(x,y,f,b) * t * Resp(f,b,T)]
    +
    +where:
    +
    +L(x,y,f,T,t,b) is radiance in units of W / (m**-2 microns**-1 sr**-1),
    +measured by the pixel in column x, row y, through filter f, at CCD
    +temperature T and exposure time t, for binning mode b,
    +
    +DN(x,y,f,T,t,b,MET) is the raw DN measured by the pixel in column x, row
    +y, through filter f, at CCD temperature T and exposure time t, for binning
    +mode b, and Mission Elapsed Time (MET),
    +
    +Dk(x,y,T,t,b,MET) is the dark level in a given pixel, derived from
    +a model based on exposure time and CCD temperature,
    +
    +Sm(x,y,t,b) is the scene-dependent frame transfer smear for the pixel,
    +
    +Lin is a function that corrects small nonlinearity of detector response,
    +
    +Flat(x,y,f,b) is the non-uniformity or 'flat-field' correction,
    +
    +Resp(f,b,T) is the responsivity, relating dark-, flat-, and
    +smear-corrected DN per unit exposure time to radiance,
    +
    +and
    +
    +t is the exposure time in milliseconds.
    +
    +The above equation assumes that data are in the native 12-bit format in
    +which they were read off the CCD, and that onboard application of 12-to-8
    +bit lookup tables (LUTs) has been inverted.
    +
    +This correction is done step-wise using the calibration tables and
    +images in this directory as follows:
    +
    +(1) Inversion of 12 to 8 bit Compression
    +========================================
    +
    +8-to-12 bit inversion of DN values is required when the value of
    +MESS:COMP12_8 is 1 (when the data are 8-bit). There are 8 inverse lookup
    +tables (LUTs). The table to use is indicated by the value of MESS:COMP_ALG
    +from 0 through 7. An 8-bit value (in a row of the table) is inverted by
    +replacing it with the 12-bit value in the column corresponding to a
    +particular LUT.
    +
    +The inversion tables are given in the product MDISLUTINV_0.
    +
    +
    +(2) Subtraction of modeled dark level
    +=====================================
    +
    +There are four separate models of dark level (dark current plus
    +electronics bias), for the MDIS-WAC and MDIS-NAC (as indicated by the
    +keyword INSTRUMENT_ID), and for each camera, without pixel binning turned
    +on (MESS:FPU_BIN = 0) or with pixel binning turned on (MESS:FPU_BIN = 1).
    +The models estimates the dark level Dk(x,y,t,T) as a function of column
    +position x, row position y, exposure time t (as indicated by the keyword
    +MESS:EXPOSURE or EXPOSURE_DURATION), and CCD temperature T (as indicated
    +by the keyword MESS:CCD_TEMP):
    +
    +Dk(x,y,t,T) = C(T) + D(T) + [E(T) + F(T) * t] * y + {O(T) + P(T) * t +
    + [Q(T) + S(T) * t] * y} * x
    +
    +Variables C(T), D(T), E(T), F(T), O(T), P(T), Q(T), and S(T) are all
    +third-order functions of CCD temperature, for example:
    +
    +C(T) = H0 + H1 * T + H2 * T**2 + H3 * T**3
    +
    +In all cases x or y is in the range 0-1023 for a not-binned image (as
    +indicated by the keyword MESS:FPU_BIN = 0) or 0-511 for a binned image (as
    +indicated by the keyword MESS:FPU_BIN = 1). t is in units of milliseconds,
    +and T is in UNCALIBRATED raw counts of CCD temperature.
    +
    +For each pixel in column x and row y of an image, application of the
    +correction is:
    +
    +DN_dark(x,y,t,T) = DN(x,y,t,T) - Dk(x,y,t,T)
    +
    +where
    +
    +DN(x,y,t,T) is DN in 12-bit format,
    +
    +Dk(x,y,t,T) is the predicted DN level from the dark modeldark model, and
    +
    +DN_dark(x,y,t,T) is dark-corrected DN.
    +
    +The eight sets of coefficients for the WAC not-binned, WAC binned, NAC
    +not-binned, and NAC binned dark models are given in the products
    +MDISWAC_NOTBIN_DARKMODEL_0, MDISWAC_BINNED_DARKMODEL_0,
    +MDISNAC_NOTBIN_DARKMODEL_0, and MDISNAC_BINNED_DARKMODEL_0 respectively.
    +
    +
    +(3) Frame Transfer Smear Correction
    +===================================
    +
    +Accumulation of signal continues during the finite duration
    +of frame transfer induces a streak or frame-transfer smear in the wake
    +of an illuminated object in the field of view, parallel to the direction
    +of frame transfer. This smear is approximated as:
    +
    +Sm(x,y,t,b,f) = SUMM(1,y-1) { t2/t * [DN_dark(x,y,t,b) -
    +Sm(x,y,t,b,f)] / Flat(x,y,b,f)}
    +
    +where
    +
    +Sm(x,y,t,b,f) is the smear in column x and row y at exposure time t
    +in binning mode b and filter f,
    +
    +Dk_dark (x,y,t,b) is dark-corrected DN in column x and row y at
    +exposure time t and temperature T in binning mode b,
    +
    +Flat(x,y,b,f) is the flat-field correction in column x and row y in
    +binning mode b and filter f,
    +
    +t is exposure time in ms, and
    +
    +t2 is the time for frame transfer (about 3.4 ms) divided by the number of
    +lines in the image in the direction of frame transfer, 1024 for
    +full-frame images (when MESS:FPU_BIN = 0) or 512 for binned images (when
    +MESS:FPU_BIN = 1).
    +
    +For each pixel in column x and row y of an image, application of the
    +correction is :
    +
    +DN_dark_smear(x,y,t,b,f) = DN_dark(x,y,t,b,f) - Sm(x,y,t,b,f)
    +
    +where
    +
    +DN_dark_smear(x,y,t,b,f) is dark- and smear- corrected DN,
    +
    +DN_dark(x,y,t,b,f) is dark-corrected DN, and
    +
    +Sm(x,y,t,b,f) is the smear calculated as shown above.
    +
    +
    +(4) Correction for CCD non-linearity
    +====================================
    +
    +To remove effects of nonlinearity in WAC image data, the following
    +corrections should be applied after correction of dark current, bias,
    +and smear.
    +
    +For DN_dark_smear > 1 
    + DN_lin = DN_dark_smear/[0.008760 * Ln(DN_dark_smear) + 0.936321]
    +
    +For DN_dark_smear <= 1 
    + DN_lin = DN_dark_smear/0.936321
    +
    +To remove effects of nonlinearity in NAC image data, the following
    +procedure should be applied after correction of dark current, bias,
    +and smear.
    +
    +For DN_dark_smear > 1 
    + DN_lin = DN_dark_smear/[0.011844 * Ln(DN_dark_smear) +
    +0.912031]
    +
    +For DN_dark_smear <= 1
    + DN_lin = DN_dark_smear/0.912031
    +
    +where
    +
    +DN_dark_smear is the input dark- and smear-corrected DN, and
    +
    +DN_lin is linearized dark- and smear-corrected DN.
    +
    +
    +(5) Flat-field correction
    +=========================
    +
    +The flat field correction removes pixel to pixel differences in detector
    +responsivity, so that the responsivity coefficients can be expressed as
    +scalars for each filter. There is a separate flat-field image for MDIS-WAC
    +and MDIS-NAC (as indicated by the keyword INSTRUMENT_ID), without pixel
    +binning turned on (MESS:FPU_BIN = 0) or with pixel binning turned on
    +(MESS:FPU_BIN = 1), for each separate filter (as indicated by the keyword
    +FILTER_NUMBER). All of the files are in the 'FLAT' directory.
    +
    +For each pixel in column x and row y of an image, application of the
    +correction is
    +
    +DN_flat(x,y,f,b) = DN_lin(x,y,f,b) / Flat(x,y,f,b)
    +
    +where
    +
    +DN_flat(x,y,f,b) is flat-fielded, linearized, dark- and smear-corrected
    +DN,
    +
    +DN_lin(x,y,f,b) is linearized dark- and smear-corrected DN, and
    +
    +Flat(x,y,f,b) is the value in the appropriate flat-field image.
    +
    +
    +(6) Conversion from DNs to radiance 
    + ===================================
    +The value that relates corrected DN's measured per unit time to radianceis the
    +responsivity. Responsivity is modeled as a function of which camera is being
    +used (MDIS-WAC or MDIS-NAC as indicated by the keyword INSTRUMENT_ID), its
    +binning state (as indicated by the keyword MESS:FPU_BIN), and in the case of the
    +WAC the filter number (as indicated by the keyword FILTER_NUMBER). The
    +coefficients used to calculate the responsivity are in the 'RESPONSIVITY'
    +directory. For a camera, binning state, and filter, the responsivity is
    +calculated from uncalibrated CCD temperature (as indicated by the keyword
    +MESS:CCD_TEMP) as follows:
    + 
    +Resp(T,b) = R(t=-30.3C,b) * [correction_offset(b) + T(CCD) * correction_coef1(b)
    ++ T(CCD)^2 * correction_coef2(b)]
    +
    +where
    +
    +Resp(T,b) is responsivity at CCD temperature T in binning state b,
    +
    +T(CCD) is raw CCD temperature in units of DNs,
    +
    +R(t=-30.3C,b) is responsivity in binning state b at CCD temperature of 1060 DN
    +(-30.3C),
    +
    +correction_offset(b) is the camera-dependent temperature correction offset for
    +binning state b,
    +
    +correction_coef1(b) is the camera-dependent temperature correction first-order
    +coefficient for binning state b.
    +
    +correction_coef2(b) is the camera-dependent temperature correction second-order
    +coefficient for binning state b.
    +
    +The temperature correction defaults to unity at CCD temperature of 1060 DN
    +(-30.3C).
    +
    +To apply responsivity to obtain radiance L, the expression is
    +
    +L = DN_flat / (t * Resp(T,b))
    +
    +where
    +
    +L is radiance in units of W / (m**2 microns**1 sr**1),
    +
    +DN_flat is dark-, smear-, linearity-, and flat field-corrected DN,
    +
    +t is the exposure time in milliseconds, and
    +
    +Resp(f,T,b) is the responsivity in filter f at CCD temperature T and
    +binning state b.
    +
    +
    +(7) Conversion from radiance to I/F
    +===================================
    +
    +To convert from radiance to I/F (also known as radiance factor, the ratio
    +of measured radiance to that which would be measured from a white
    +perfectly Lambertian surface), the following expression should be applied:
    +
    +I_over_F(f) = L(f) * pi * (SOLAR_DISTANCE/149597870.691)**2 / F(f)
    +
    +where
    +
    +L(f) is calibrated radiance calculated as described above for some filter
    +f,
    +
    +SOLAR_DISTANCE is that value for distance of the target object from the
    +center of the sun in kilometers (as indicated by the keyword
    +SOLAR_DISTANCE)
    +
    +149597870.691 is the number of kilometers in 1 AU
    +
    +F(f) is effective average solar irradiance sampled under the filter
    +bandpass.
    +
    +The effective average solar radiance for each camera and bandpass is given
    +in the SOLAR directory.
    +    
    +
    + + + Messenger + + + + + mdis2isis + + + + + + Original version + + + Added computation of I/F reflectance for valid NAIF target bodies. + + + Corrected a bug that prevented the I/F correction from ever being + applied. The exposure time must be expressed throughout as seconds and + not milliseconds (engineering units) with the exception being the dark + current model, which requires them to be in engineering units. There + were incorrect values for the nominal filter wheel encoder values in the + file $messenger/calibration/mdisCalibration.trn that incorrectly + identified the filter. This has been corrected, but it was also + determined that the validation of the proper filter wheel should take + place in mdis2isis. Added loading of external file values as comma + separated values (CSV) files. This includes the absolute response and + solar irradiance constants. + + + Added filter dependant smear component support. These values are + externally maintained in calibration/responsivity directory. + + + Removed references to CubeInfo + + + The dark current model does not support exposure times greater than 2 + seconds. In these cases, apply the STANDARD dark current processing and + report this to the user as an error but complete processing. Users can + always select a different model. + + + Corrected determination of dark column count; corrected computation of + dark current correction based upon valid/good columns; added computation + of dark strip mean after calibration as a sanity check on the process; + updated ProductID and SourceProductId in the Archive group; Corrected + units of resulting calibration; made filter characteristics of name, + wavelength and width compliant with CDR SIS specifications; added program + name and versions to RadiometricCalibration group; reworked how the dark + model and flatfield are applied to support pixel binning. + + + Added additional tests for extreme observing conditions that do not allow + the image to be calibrated. + + + Very minor change of watts unit expressed as W instead of w. + + + Changed the exposure threshold for the dark current model from 2 seconds + to 1 second and it now uses the LINEAR model instead of the STANDARD + model in this case; Implemented new quadratic responsivity equation for + both WAC and NAC instruments that adds an additional term to the + responsivity files; updated documentation. + + + Corrected inclusion of dark current model file to SourceProductId when + applicable; bumped the version number to 3. + + + Added parameter to the usage of reduce to accomidate changes to reduce. + + + + + + + cube + input + + Input cube + + + This is the Isis Cube to be calibrated. + + + *.cub + + + + cube + output + + Output cube + + + This is the output file. The output cube will be a calibrated version + of the input cube. + + + *.cub + + + + + + + string + Dark current calibration method + + MODEL + + + + + + + + + boolean + Do not set dark current data to null + + If this is checked, the dark current data (assumed to be the first + three columns) are not removed from the image and also undergo the + calibration process. + + false + + + boolean + True + + Convert to I/F units + + +

    + This option when set wil convert the output to I/F from radiance values. + To convert from radiance to I/F (also known as radiance factor, the ratio + of measured radiance to that which would be measured from a white + perfectly Lambertian surface), the following expression should is applied: +

    +I_over_F(f) = L(f) * PI * (SOLAR_DISTANCE/149597870.691)**2 / F(f)                
    +            
    + where L(f) is calibrated radiance calculated for some filter f, + SOLAR_DISTANCE is that value for distance of the target object from + the center of the sun in kilometers (as indicated by the keyword + SOLAR_DISTANCE), 149597870.691 is the number of kilometers in 1 AU + and F(f) is effective average solar irradiance sampled under the + filter bandpass. +

    +

    + If the observed target is not of a valid body as recognized by + NAIF, the output is left in radiance. +

    +
    +
    +
    +
    + + + + + Calibrating an MDIS image + + + This example will show the calibration process of a MDIS image + + + FROM=EW0089565626A.cub + TO=EW0089565626A.calib.cub DARKCURRENT=MODEL + Calibration process of a MDIS image, using the MODEL dark + current option + + + + + Calibrate an MDIS image + + The is the GUI for mdiscal when converting the uncalibrated cube + EW0089565626A.cub to the calibrated cube EW0089565626A.calib.cub. + + + + + + + + Input Cube + + The is EW0089565626A.jpg before calibration + + + + + + + Output With Dark Model + + The is the output generated by the default options + + + + + + +
    diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/DARK_MODEL/MDISNAC_BINNED_DARKMODEL_0.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/DARK_MODEL/MDISNAC_BINNED_DARKMODEL_0.TAB new file mode 100644 index 0000000000000000000000000000000000000000..c95e43037240e8f4568f6930f9a2c54538bae3ec --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/DARK_MODEL/MDISNAC_BINNED_DARKMODEL_0.TAB @@ -0,0 +1,8 @@ +-5.8097988281E+03, 1.7283071518E+01, -1.6385525465E-02, 5.1732235988E-06, C +-1.8777013779E+01, 5.3521092981E-02, -5.0854214351E-05, 1.6108440803E-08, D +-5.2125591278E+01, 1.4842796326E-01, -1.4089376782E-04, 4.4586382586E-08, E +-4.2577763088E-03, 1.2289244296E-05, -1.1821382095E-08, 3.7898404033E-12, F + 6.7693686485E-01, -1.9095379394E-03, 1.7939668169E-06, -5.6198729004E-10, O + 1.8011084758E-03, -5.1680335673E-06, 4.9400128432E-09, -1.5730491996E-12, P +-6.8822302856E-03, 1.9457356757E-05, -1.8341884456E-08, 5.7656765647E-12, Q + 9.0018211267E-06, -2.5762753708E-08, 2.4592881551E-11, -7.8309830747E-15, S diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/DARK_MODEL/MDISNAC_NOTBIN_DARKMODEL_0.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/DARK_MODEL/MDISNAC_NOTBIN_DARKMODEL_0.TAB new file mode 100644 index 0000000000000000000000000000000000000000..8bd94fb049da75df0ee5b4eadbfad88e815636a0 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/DARK_MODEL/MDISNAC_NOTBIN_DARKMODEL_0.TAB @@ -0,0 +1,8 @@ + 4.2023032227E+03, -1.0731396675E+01, 9.7427340224E-03, -2.9430198083E-06, C +-6.4488357544E+01, 1.7918111384E-01, -1.6589123697E-04, 5.1176485272E-08, D +-2.5825297832E+00, 7.5459880754E-03, -7.3521878221E-06, 2.3887327671E-09, E +-4.6477396972E-04, 1.3100850538E-06, -1.2340704014E-09, 3.8851509358E-13, F + 1.4337165281E-02, -4.2157098505E-05, 4.1253350958E-08, -1.3463695436E-11, O +-6.8638852099E-05, 1.8093267329E-07, -1.5740860004E-10, 4.5092483350E-14, P +-1.6973295715E-04, 4.9278952474E-07, -4.7705933648E-10, 1.5399279887E-13, Q + 1.3579968083E-07, -4.3391262805E-10, 4.5662052698E-13, -1.5864258740E-16, S diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/DARK_MODEL/MDISWAC_BINNED_DARKMODEL_0.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/DARK_MODEL/MDISWAC_BINNED_DARKMODEL_0.TAB new file mode 100644 index 0000000000000000000000000000000000000000..a8cf091dc7898e1c72e1b186bb8371233982f037 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/DARK_MODEL/MDISWAC_BINNED_DARKMODEL_0.TAB @@ -0,0 +1,8 @@ +-4.8456835938E+02, 2.1177132130E+00, -2.0681277383E-03, 6.7554736916E-07, C +-1.0241144180E+01, 2.9923267663E-02, -2.9156690289E-05, 9.4747587553E-09, D +-2.7916862488E+01, 8.1357844174E-02, -7.9065292084E-05, 2.5624844469E-08, E + 6.4676237525E-04, -1.9150979824E-06, 1.8912227340E-09, -6.2288374328E-13, F +-5.5056393147E-01, 1.5255932231E-03, -1.4063004983E-06, 4.3035455755E-10, O +-2.0105857402E-03, 5.9298422457E-06, -5.8322826568E-09, 1.9130825396E-12, P + 1.2794663198E-02, -3.6932731746E-05, 3.5541496857E-08, -1.1403694829E-11, Q +-1.5473751773E-06, 4.2902912334E-09, -3.9528887975E-12, 1.2098870388E-15, S diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/DARK_MODEL/MDISWAC_NOTBIN_DARKMODEL_0.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/DARK_MODEL/MDISWAC_NOTBIN_DARKMODEL_0.TAB new file mode 100644 index 0000000000000000000000000000000000000000..005ba19ea4f1456a0a50d5993be4340a112a74da --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/DARK_MODEL/MDISWAC_NOTBIN_DARKMODEL_0.TAB @@ -0,0 +1,8 @@ + 1.2382397461E+03, -2.7684268951E+00, 2.5647317525E-03, -7.8695262573E-07, C +-3.4833836555E+00, 1.0116644204E-02, -9.7957554317E-06, 3.1624916019E-09, D +-2.4299888611E+00, 7.1440534666E-03, -7.0058499659E-06, 2.2918509313E-09, E +-5.3432234563E-04, 1.4995789570E-06, -1.4002544679E-09, 4.3498413422E-13, F + 2.0633848384E-02, -6.2951665313E-05, 6.3933789818E-08, -2.1631758884E-11, O +-3.3310454455E-04, 9.7098586593E-07, -9.4381846782E-10, 3.0594274401E-13, P + 5.1751307910E-04, -1.5100623614E-06, 1.4695749062E-09, -4.7704423961E-13, Q + 1.1701602176E-07, -3.3471744820E-10, 3.1903074475E-13, -1.0133021399E-16, S diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/LUT_INVERT/MDISLUTINV_0.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/LUT_INVERT/MDISLUTINV_0.TAB new file mode 100644 index 0000000000000000000000000000000000000000..da6db799829c8ecd81bdc4691861ed0eabb95338 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/LUT_INVERT/MDISLUTINV_0.TAB @@ -0,0 +1,256 @@ + 0, 0, 0, 0, 0, 0, 0, 0, 0 + 1, 221, 221, 224, 181, 181, 184, 1, 16 + 2, 223, 222, 229, 183, 182, 189, 3, 32 + 3, 225, 223, 233, 185, 183, 193, 5, 48 + 4, 227, 224, 238, 187, 184, 198, 7, 64 + 5, 228, 225, 242, 188, 185, 202, 9, 80 + 6, 230, 226, 247, 190, 186, 207, 11, 96 + 7, 232, 227, 252, 193, 187, 212, 13, 112 + 8, 235, 229, 256, 195, 189, 216, 15, 128 + 9, 237, 230, 261, 197, 190, 221, 17, 144 + 10, 239, 231, 266, 199, 191, 226, 20, 160 + 11, 242, 232, 270, 202, 192, 230, 22, 176 + 12, 244, 234, 275, 204, 194, 235, 25, 192 + 13, 246, 235, 280, 207, 195, 240, 27, 208 + 14, 249, 236, 285, 209, 196, 245, 30, 224 + 15, 252, 238, 290, 212, 198, 250, 33, 241 + 16, 255, 239, 294, 215, 199, 254, 36, 257 + 17, 257, 240, 299, 218, 200, 259, 39, 273 + 18, 260, 242, 304, 221, 202, 264, 42, 289 + 19, 263, 243, 309, 224, 203, 269, 45, 305 + 20, 266, 245, 314, 227, 205, 274, 48, 321 + 21, 269, 246, 319, 230, 206, 279, 51, 337 + 22, 273, 248, 324, 233, 208, 284, 55, 353 + 23, 276, 249, 329, 236, 209, 289, 58, 369 + 24, 279, 251, 334, 240, 211, 294, 62, 385 + 25, 283, 253, 339, 243, 213, 299, 65, 401 + 26, 286, 254, 345, 247, 214, 305, 69, 417 + 27, 290, 256, 350, 251, 216, 310, 73, 433 + 28, 294, 258, 355, 254, 218, 315, 77, 449 + 29, 298, 260, 360, 258, 220, 320, 81, 465 + 30, 302, 261, 365, 262, 221, 325, 85, 481 + 31, 306, 263, 371, 266, 223, 331, 90, 498 + 32, 310, 265, 376, 271, 225, 336, 94, 514 + 33, 314, 267, 381, 275, 227, 341, 99, 530 + 34, 319, 269, 387, 280, 229, 347, 103, 546 + 35, 323, 271, 392, 284, 231, 352, 108, 562 + 36, 328, 273, 398, 289, 233, 358, 113, 578 + 37, 333, 275, 403, 294, 235, 363, 118, 594 + 38, 338, 277, 409, 299, 237, 369, 123, 610 + 39, 343, 279, 414, 304, 239, 374, 128, 626 + 40, 348, 282, 420, 309, 242, 380, 133, 642 + 41, 353, 284, 425, 314, 244, 385, 138, 658 + 42, 358, 286, 431, 319, 246, 391, 144, 674 + 43, 363, 289, 437, 324, 249, 397, 149, 690 + 44, 368, 291, 442, 330, 251, 402, 155, 706 + 45, 374, 293, 448, 335, 253, 408, 161, 722 + 46, 379, 296, 454, 341, 256, 414, 167, 739 + 47, 385, 298, 460, 347, 258, 420, 173, 755 + 48, 391, 301, 466, 352, 261, 426, 179, 771 + 49, 397, 303, 472, 358, 263, 432, 185, 787 + 50, 403, 306, 477, 365, 266, 438, 192, 803 + 51, 409, 309, 483, 371, 269, 443, 199, 819 + 52, 416, 311, 489, 377, 271, 449, 205, 835 + 53, 422, 314, 496, 384, 274, 456, 212, 851 + 54, 429, 317, 502, 391, 277, 462, 219, 867 + 55, 435, 319, 508, 397, 279, 468, 226, 883 + 56, 442, 322, 514, 404, 282, 474, 233, 899 + 57, 449, 325, 520, 411, 285, 480, 240, 915 + 58, 456, 328, 526, 418, 288, 486, 247, 931 + 59, 463, 331, 533, 425, 291, 493, 255, 947 + 60, 470, 334, 539, 432, 294, 499, 262, 963 + 61, 477, 337, 545, 440, 297, 505, 270, 980 + 62, 485, 340, 552, 447, 300, 512, 278, 996 + 63, 492, 343, 558, 455, 303, 518, 286,1012 + 64, 500, 346, 565, 462, 306, 525, 294,1028 + 65, 507, 350, 571, 470, 310, 531, 302,1044 + 66, 515, 353, 578, 478, 313, 538, 310,1060 + 67, 523, 356, 585, 486, 316, 545, 319,1076 + 68, 531, 360, 591, 494, 320, 551, 327,1092 + 69, 540, 363, 598, 503, 323, 558, 336,1108 + 70, 548, 366, 605, 511, 326, 565, 345,1124 + 71, 556, 370, 611, 520, 330, 571, 354,1140 + 72, 565, 373, 618, 528, 333, 578, 363,1156 + 73, 574, 377, 625, 537, 337, 585, 372,1172 + 74, 583, 381, 632, 546, 341, 592, 381,1188 + 75, 592, 384, 639, 555, 344, 599, 391,1204 + 76, 601, 388, 646, 564, 348, 606, 400,1220 + 77, 610, 392, 653, 573, 352, 613, 410,1237 + 78, 619, 395, 660, 582, 355, 620, 419,1253 + 79, 628, 399, 667, 592, 359, 627, 429,1269 + 80, 637, 403, 674, 601, 363, 634, 439,1285 + 81, 647, 407, 681, 611, 367, 641, 449,1301 + 82, 657, 411, 689, 621, 371, 649, 460,1317 + 83, 666, 415, 696, 631, 375, 656, 470,1333 + 84, 676, 420, 703, 641, 380, 663, 481,1349 + 85, 686, 424, 711, 651, 384, 671, 491,1365 + 86, 696, 428, 718, 661, 388, 678, 502,1381 + 87, 707, 432, 725, 672, 392, 685, 513,1397 + 88, 717, 437, 733, 682, 397, 693, 524,1413 + 89, 728, 441, 740, 693, 401, 700, 535,1429 + 90, 738, 446, 748, 704, 406, 708, 546,1445 + 91, 749, 450, 756, 714, 410, 716, 557,1461 + 92, 760, 455, 763, 725, 415, 723, 569,1478 + 93, 771, 459, 771, 736, 419, 731, 580,1494 + 94, 782, 464, 779, 748, 424, 739, 592,1510 + 95, 793, 469, 787, 759, 429, 747, 604,1526 + 96, 805, 474, 795, 770, 434, 755, 616,1542 + 97, 816, 479, 803, 782, 439, 763, 628,1558 + 98, 827, 483, 811, 793, 443, 771, 640,1574 + 99, 839, 488, 819, 805, 448, 779, 652,1590 + 100, 851, 493, 827, 817, 453, 787, 665,1606 + 101, 863, 499, 835, 829, 458, 795, 678,1622 + 102, 875, 504, 843, 841, 464, 804, 690,1638 + 103, 887, 509, 852, 853, 469, 812, 703,1654 + 104, 899, 514, 860, 866, 474, 820, 716,1670 + 105, 912, 519, 869, 878, 479, 829, 729,1686 + 106, 924, 525, 877, 891, 485, 837, 742,1702 + 107, 937, 530, 886, 904, 490, 846, 756,1719 + 108, 949, 535, 894, 917, 495, 854, 769,1735 + 109, 962, 541, 903, 930, 501, 863, 782,1751 + 110, 975, 547, 912, 943, 506, 872, 796,1767 + 111, 988, 552, 921, 956, 512, 881, 810,1783 + 112,1002, 558, 929, 969, 518, 890, 824,1799 + 113,1015, 564, 938, 983, 524, 898, 838,1815 + 114,1028, 569, 947, 996, 529, 907, 852,1831 + 115,1042, 575, 956,1010, 535, 916, 866,1847 + 116,1055, 581, 965,1023, 541, 925, 881,1863 + 117,1069, 587, 974,1037, 547, 935, 895,1879 + 118,1083, 594, 984,1051, 554, 944, 910,1895 + 119,1097, 600, 993,1065, 560, 953, 925,1911 + 120,1111, 606,1002,1080, 566, 962, 940,1927 + 121,1125, 612,1011,1094, 572, 972, 955,1943 + 122,1140, 619,1021,1109, 579, 981, 970,1959 + 123,1154, 625,1030,1123, 585, 991, 985,1976 + 124,1169, 632,1040,1138, 592,1000,1001,1992 + 125,1183, 639,1050,1153, 598,1010,1016,2008 + 126,1198, 645,1059,1168, 605,1020,1032,2024 + 127,1213, 652,1069,1183, 612,1029,1048,2040 + 128,1228, 659,1079,1198, 619,1039,1063,2056 + 129,1243, 666,1089,1214, 626,1049,1079,2072 + 130,1259, 673,1099,1229, 633,1059,1096,2088 + 131,1274, 680,1109,1245, 640,1069,1112,2104 + 132,1289, 687,1119,1260, 647,1079,1129,2120 + 133,1305, 694,1130,1276, 654,1090,1145,2136 + 134,1321, 701,1140,1292, 661,1100,1162,2152 + 135,1337, 709,1150,1308, 668,1111,1179,2168 + 136,1353, 716,1161,1324, 676,1121,1196,2184 + 137,1369, 723,1171,1340, 683,1132,1213,2200 + 138,1385, 731,1182,1357, 691,1142,1230,2217 + 139,1401, 738,1193,1373, 698,1153,1247,2233 + 140,1418, 746,1204,1390, 706,1164,1264,2249 + 141,1435, 754,1215,1407, 714,1175,1282,2265 + 142,1451, 762,1226,1424, 722,1186,1299,2281 + 143,1468, 770,1237,1441, 730,1197,1317,2297 + 144,1485, 778,1248,1458, 738,1208,1335,2313 + 145,1502, 786,1259,1475, 746,1219,1353,2329 + 146,1519, 794,1270,1492, 754,1231,1371,2345 + 147,1536, 803,1282,1510, 763,1242,1390,2361 + 148,1554, 811,1293,1527, 771,1253,1408,2377 + 149,1571, 820,1305,1545, 779,1265,1427,2393 + 150,1589, 828,1316,1563, 788,1277,1445,2409 + 151,1607, 837,1328,1581, 797,1288,1464,2425 + 152,1624, 846,1340,1599, 806,1300,1483,2441 + 153,1642, 855,1352,1617, 815,1312,1502,2458 + 154,1661, 864,1364,1635, 824,1324,1521,2474 + 155,1679, 873,1376,1654, 833,1337,1540,2490 + 156,1697, 882,1388,1672, 842,1349,1560,2506 + 157,1716, 891,1401,1691, 851,1361,1579,2522 + 158,1734, 900,1413,1710, 860,1374,1599,2538 + 159,1753, 910,1426,1729, 870,1386,1618,2554 + 160,1772, 919,1439,1748, 879,1399,1638,2570 + 161,1791, 929,1452,1767, 889,1412,1658,2586 + 162,1810, 939,1465,1786, 898,1425,1678,2602 + 163,1829, 948,1478,1805, 908,1438,1699,2618 + 164,1848, 958,1491,1825, 918,1451,1719,2634 + 165,1868, 968,1504,1844, 928,1464,1740,2650 + 166,1887, 979,1517,1864, 938,1478,1760,2666 + 167,1907, 989,1531,1884, 949,1491,1781,2682 + 168,1926,1000,1544,1904, 959,1505,1802,2698 + 169,1946,1010,1558,1924, 970,1518,1823,2715 + 170,1966,1021,1572,1944, 980,1532,1844,2731 + 171,1986,1032,1585,1964, 991,1546,1866,2747 + 172,2007,1043,1600,1985,1002,1560,1887,2763 + 173,2027,1054,1614,2005,1013,1575,1908,2779 + 174,2047,1065,1628,2026,1024,1589,1930,2795 + 175,2068,1076,1643,2047,1036,1604,1952,2811 + 176,2089,1087,1658,2068,1047,1619,1973,2827 + 177,2110,1099,1673,2089,1058,1633,1995,2843 + 178,2131,1110,1688,2110,1070,1648,2018,2859 + 179,2152,1122,1703,2131,1082,1663,2040,2875 + 180,2173,1134,1718,2153,1093,1679,2062,2891 + 181,2194,1146,1733,2174,1106,1694,2085,2907 + 182,2215,1158,1749,2196,1118,1709,2108,2923 + 183,2237,1171,1764,2217,1130,1725,2130,2939 + 184,2258,1183,1780,2239,1143,1741,2153,2956 + 185,2280,1196,1796,2261,1155,1757,2176,2972 + 186,2302,1209,1812,2283,1168,1773,2199,2988 + 187,2324,1222,1829,2305,1181,1790,2223,3004 + 188,2346,1235,1845,2328,1194,1806,2246,3020 + 189,2368,1248,1862,2350,1208,1823,2269,3036 + 190,2391,1262,1879,2373,1221,1840,2293,3052 + 191,2413,1275,1896,2396,1234,1857,2317,3068 + 192,2436,1289,1913,2419,1248,1875,2340,3084 + 193,2459,1303,1931,2442,1262,1892,2364,3100 + 194,2481,1317,1948,2465,1276,1910,2388,3116 + 195,2504,1331,1966,2488,1291,1927,2413,3132 + 196,2527,1346,1984,2511,1305,1946,2437,3148 + 197,2551,1361,2003,2534,1320,1964,2462,3164 + 198,2574,1376,2021,2558,1335,1983,2486,3180 + 199,2597,1391,2040,2581,1350,2002,2511,3197 + 200,2621,1406,2059,2605,1365,2021,2536,3213 + 201,2644,1422,2078,2629,1381,2040,2561,3229 + 202,2668,1437,2097,2653,1396,2059,2586,3245 + 203,2692,1453,2117,2677,1412,2079,2611,3261 + 204,2716,1469,2137,2701,1428,2099,2637,3277 + 205,2740,1486,2157,2726,1445,2119,2662,3293 + 206,2764,1503,2178,2750,1462,2140,2688,3309 + 207,2788,1520,2199,2775,1479,2161,2713,3325 + 208,2813,1537,2220,2800,1496,2182,2739,3341 + 209,2838,1554,2241,2825,1513,2203,2765,3357 + 210,2862,1572,2262,2850,1531,2225,2791,3373 + 211,2887,1590,2284,2875,1549,2247,2818,3389 + 212,2912,1608,2307,2900,1567,2269,2844,3405 + 213,2937,1627,2329,2925,1586,2292,2871,3421 + 214,2962,1646,2352,2950,1605,2315,2897,3437 + 215,2988,1665,2376,2976,1624,2338,2924,3454 + 216,3013,1684,2399,3001,1643,2362,2951,3470 + 217,3038,1704,2423,3027,1663,2386,2978,3486 + 218,3064,1725,2448,3053,1683,2411,3005,3502 + 219,3090,1745,2473,3079,1704,2436,3032,3518 + 220,3115,1766,2498,3105,1725,2461,3059,3534 + 221,3141,1787,2523,3132,1746,2487,3087,3550 + 222,3168,1809,2550,3158,1767,2513,3114,3566 + 223,3194,1831,2577,3185,1789,2540,3142,3582 + 224,3220,1854,2604,3211,1812,2567,3170,3598 + 225,3247,1877,2631,3238,1835,2595,3198,3614 + 226,3273,1901,2660,3265,1858,2624,3226,3630 + 227,3300,1925,2689,3292,1882,2653,3254,3646 + 228,3327,1950,2718,3319,1907,2682,3283,3662 + 229,3354,1975,2748,3346,1932,2712,3311,3678 + 230,3381,2000,2779,3373,1958,2743,3340,3695 + 231,3408,2027,2810,3401,1984,2775,3369,3711 + 232,3435,2054,2842,3428,2011,2808,3398,3727 + 233,3463,2082,2875,3456,2038,2841,3427,3743 + 234,3490,2110,2909,3484,2067,2875,3456,3759 + 235,3518,2139,2944,3512,2096,2910,3485,3775 + 236,3545,2170,2980,3540,2126,2946,3514,3791 + 237,3573,2201,3017,3568,2157,2983,3544,3807 + 238,3601,2233,3054,3596,2189,3021,3573,3823 + 239,3629,2266,3093,3625,2222,3060,3603,3839 + 240,3658,2300,3134,3653,2255,3101,3632,3855 + 241,3686,2335,3175,3682,2290,3144,3662,3871 + 242,3715,2372,3218,3711,2327,3187,3693,3887 + 243,3743,2410,3263,3740,2365,3233,3723,3903 + 244,3772,2450,3310,3769,2404,3280,3753,3919 + 245,3801,2492,3359,3798,2445,3330,3784,3935 + 246,3830,2536,3411,3827,2489,3382,3814,3952 + 247,3859,2582,3465,3856,2534,3437,3845,3968 + 248,3888,2630,3522,3886,2582,3495,3876,3984 + 249,3917,2682,3583,3915,2634,3557,3907,4000 + 250,3947,2738,3648,3945,2688,3624,3938,4016 + 251,3976,2799,3718,3975,2747,3697,3969,4032 + 252,4006,2865,3796,4005,2812,3776,4001,4048 + 253,4035,2939,3882,4035,2884,3866,4032,4064 + 254,4065,3024,3980,4065,2965,3971,4064,4080 + 255,4095,4095,4095,4095,4095,4095,4095,4095 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_0.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_0.TAB new file mode 100644 index 0000000000000000000000000000000000000000..5e9f459a8438d297b818fd7e35c4f6714ec4028e --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_0.TAB @@ -0,0 +1 @@ + 1.3574E+05, 1.1326E+00, -1.2592E-04 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_1.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_1.TAB new file mode 100644 index 0000000000000000000000000000000000000000..19026806f8491940e8493c4f1ba888192f162a6f --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_1.TAB @@ -0,0 +1 @@ + 7.1337E+02, 1.2488E+00, -2.3460E-04 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_2.LBL b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_2.LBL new file mode 100644 index 0000000000000000000000000000000000000000..2f489c0adda31614bfd181421be1cc68ee7f0af1 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_2.LBL @@ -0,0 +1,159 @@ +PDS_VERSION_ID = PDS3 + +/*** FILE FORMAT ***/ +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 53 +FILE_RECORDS = 12 + +/*** GENERAL DATA DESCRIPTION PARAMETERS ***/ +MISSION_NAME = "MESSENGER" +SPACECRAFT_NAME = "MESSENGER" +INSTRUMENT_HOST_NAME = "MERCURY SURFACE, SPACE ENVIRONMENT, + GEOCHEMISTRY AND RANGING" +DATA_SET_ID = "MESS-E/V/H-MDIS-2-EDR-RAWDATA-V1.0" +PRODUCT_ID = "MDISNAC_BINNED_RESP_2" + /*( MDIScam_bining_RESP_v )*/ + /*( cam = camera, NAC or WAC )*/ + /*( bining = binning, NOTBIN or BINNED )*/ + /*( v = version number, 0-9,a-z )*/ +PRODUCER_INSTITUTION_NAME = "APPLIED PHYSICS LABORATORY" + +/*** TIME PARAMETERS ***/ +PRODUCT_CREATION_TIME = 2008-11-07T20:00:00 + +/*** INSTRUMENT ENGINEERING PARAMETERS ***/ +INSTRUMENT_NAME = "MERCURY DUAL IMAGING SYSTEM NARROW ANGLE CAMERA" +INSTRUMENT_ID = "MDIS-NAC" +MESS:FPU_BIN = 1 +MESS:COMP12_8 = 0 + + +OBJECT = FILE + ^TABLE = "MDISNAC_BINNED_RESP_2.TAB" + RECORD_TYPE = FIXED_LENGTH + FILE_RECORDS = 1 + RECORD_BYTES = 53 + + OBJECT = TABLE + NAME = "MDIS NAC BINNED RESPONSIVITY MODEL, + VERSION 2" + INTERCHANGE_FORMAT = "ASCII" + ROWS = 1 + COLUMNS = 4 + ROW_BYTES = 53 + DESCRIPTION = "This is the model of responsivity for + the MDIS narrow-angle camera, with pixel + binning turned on (MESS:FPU_BIN = 1). It + is used to correct raw DN to units of + radiance, after correction for dark level, + frame transfer smear, linearity, and flat + field. The responsivity is in units of DN + per unit time per unit radiance. It is + dependent on CCD temperature T + (MESS:CCD_TEMP), and binning state b + (MESS:FPU_BIN). + + Exposure time t is in raw units of ms + (MESS:EXPOSURE or EXPOSURE_DURATION) and + radiance in units of + W / (m**2 microns**1 sr**1). + + Responsivity is calculated + using a second-order polynomial as + Resp(T,b) = R(t=-30.3C,b) * + [correction_offset(b) + T(CCD) * + correction_coef1(b) + T(CCD)^2 * + correction_coef2(b)] + + where + + Resp(T,b) is responsivity + at CCD temperature T in binning state b, + + T(CCD) is raw CCD temperature in units + of DNs, + + R(t=-30.3C,b) is responsivity in + binning state b at CCD temperature + of 1060 DN (-30.3C), + + correction_offset(b) is the camera- + dependent temperature correction + offset for binning state b, + + correction_coef1(b) is the camera- + dependent temperature correction + first-order coefficient for + binning state b. + + correction_coef2(b) is the camera- + dependent temperature correction + second-order coefficient for + binning state b. + + The temperature correction defaults to + unity at CCD temperature of 1060 DN + (-30.3C). + + To apply responsivity to obtain radiance + L, the expression is + L = DN_dk_sm_lin_fl / (t * Resp(T,b)) + + where + + DN_dk_sm_lin_fl is dark-, smear-, + linearity-, and flat field-corrected DN, + + t is the exposure time in milliseconds, + + Resp(T,b) is the responsivity." + + OBJECT = COLUMN + COLUMN_NUMBER = 1 + NAME = REFERENCE_RESPONSIVITY + DATA_TYPE = ASCII_REAL + START_BYTE = 1 + BYTES = 11 + DESCRIPTION = "Responsivity at the reference + temperature MESS:CCD_TEMP=1060 + (-30.3C)." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 2 + NAME = CORRECTION_OFFSET + DATA_TYPE = ASCII_REAL + START_BYTE = 13 + BYTES = 12 + DESCRIPTION = "Offset term in the CCD temperature + correction to responsivity." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 3 + NAME = CORRECTION_COEF1 + DATA_TYPE = ASCII_REAL + START_BYTE = 26 + BYTES = 12 + DESCRIPTION = "Coefficient to the first order term + in the CCD temperature correction + to responsivity." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 3 + NAME = CORRECTION_COEF2 + DATA_TYPE = ASCII_REAL + START_BYTE = 39 + BYTES = 15 + DESCRIPTION = "Coefficient to the second order term + in the CCD temperature correction + to responsivity." + END_OBJECT = COLUMN + + END_OBJECT = TABLE + +END_OBJECT = FILE + +END + diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_2.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_2.TAB new file mode 100644 index 0000000000000000000000000000000000000000..a0248e6aba44806e9d0633ef59e2d0840f97b6cd --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_2.TAB @@ -0,0 +1 @@ + 7.1337E+02, 1.2488E+00, -2.3460E-04, 0.0000000E+00 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_3.LBL b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_3.LBL new file mode 100644 index 0000000000000000000000000000000000000000..0af2ac2a61c9fadb50e699b8632b25fb2aca990c --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_3.LBL @@ -0,0 +1,159 @@ +PDS_VERSION_ID = PDS3 + +/*** FILE FORMAT ***/ +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 53 +FILE_RECORDS = 1 + +/*** GENERAL DATA DESCRIPTION PARAMETERS ***/ +MISSION_NAME = "MESSENGER" +SPACECRAFT_NAME = "MESSENGER" +INSTRUMENT_HOST_NAME = "MERCURY SURFACE, SPACE ENVIRONMENT, + GEOCHEMISTRY AND RANGING" +DATA_SET_ID = "MESS-E/V/H-MDIS-2-EDR-RAWDATA-V1.0" +PRODUCT_ID = "MDISNAC_BINNED_RESP_3" + /*( MDIScam_bining_RESP_v )*/ + /*( cam = camera, NAC or WAC )*/ + /*( bining = binning, NOTBIN or BINNED )*/ + /*( v = version number, 0-9,a-z )*/ +PRODUCER_INSTITUTION_NAME = "APPLIED PHYSICS LABORATORY" + +/*** TIME PARAMETERS ***/ +PRODUCT_CREATION_TIME = 2008-12-22T20:00:00 + +/*** INSTRUMENT ENGINEERING PARAMETERS ***/ +INSTRUMENT_NAME = "MERCURY DUAL IMAGING SYSTEM NARROW ANGLE CAMERA" +INSTRUMENT_ID = "MDIS-NAC" +MESS:FPU_BIN = 1 +MESS:COMP12_8 = 0 + + +OBJECT = FILE + ^TABLE = "MDISNAC_BINNED_RESP_3.TAB" + RECORD_TYPE = FIXED_LENGTH + FILE_RECORDS = 1 + RECORD_BYTES = 53 + + OBJECT = TABLE + NAME = "MDIS NAC BINNED RESPONSIVITY MODEL, + VERSION 3" + INTERCHANGE_FORMAT = "ASCII" + ROWS = 1 + COLUMNS = 4 + ROW_BYTES = 53 + DESCRIPTION = "This is the model of responsivity for + the MDIS narrow-angle camera, with pixel + binning turned on (MESS:FPU_BIN = 1). It + is used to correct raw DN to units of + radiance, after correction for dark level, + frame transfer smear, linearity, and flat + field. The responsivity is in units of DN + per unit time per unit radiance. It is + dependent on CCD temperature T + (MESS:CCD_TEMP), and binning state b + (MESS:FPU_BIN). + + Exposure time t is in raw units of ms + (MESS:EXPOSURE or EXPOSURE_DURATION) and + radiance in units of + W / (m**2 microns**1 sr**1). + + Responsivity is calculated + using a second-order polynomial as + Resp(T,b) = R(t=-30.3C,b) * + [correction_offset(b) + T(CCD) * + correction_coef1(b) + T(CCD)^2 * + correction_coef2(b)] + + where + + Resp(T,b) is responsivity + at CCD temperature T in binning state b, + + T(CCD) is raw CCD temperature in units + of DNs, + + R(t=-30.3C,b) is responsivity in + binning state b at CCD temperature + of 1060 DN (-30.3C), + + correction_offset(b) is the camera- + dependent temperature correction + offset for binning state b, + + correction_coef1(b) is the camera- + dependent temperature correction + first-order coefficient for + binning state b. + + correction_coef2(b) is the camera- + dependent temperature correction + second-order coefficient for + binning state b. + + The temperature correction defaults to + unity at CCD temperature of 1060 DN + (-30.3C). + + To apply responsivity to obtain radiance + L, the expression is + L = DN_dk_sm_lin_fl / (t * Resp(T,b)) + + where + + DN_dk_sm_lin_fl is dark-, smear-, + linearity-, and flat field-corrected DN, + + t is the exposure time in milliseconds, + + Resp(T,b) is the responsivity." + + OBJECT = COLUMN + COLUMN_NUMBER = 1 + NAME = REFERENCE_RESPONSIVITY + DATA_TYPE = ASCII_REAL + START_BYTE = 1 + BYTES = 11 + DESCRIPTION = "Responsivity at the reference + temperature MESS:CCD_TEMP=1060 + (-30.3C)." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 2 + NAME = CORRECTION_OFFSET + DATA_TYPE = ASCII_REAL + START_BYTE = 13 + BYTES = 12 + DESCRIPTION = "Offset term in the CCD temperature + correction to responsivity." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 3 + NAME = CORRECTION_COEF1 + DATA_TYPE = ASCII_REAL + START_BYTE = 26 + BYTES = 12 + DESCRIPTION = "Coefficient to the first order term + in the CCD temperature correction + to responsivity." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 3 + NAME = CORRECTION_COEF2 + DATA_TYPE = ASCII_REAL + START_BYTE = 39 + BYTES = 15 + DESCRIPTION = "Coefficient to the second order term + in the CCD temperature correction + to responsivity." + END_OBJECT = COLUMN + + END_OBJECT = TABLE + +END_OBJECT = FILE + +END + diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_3.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_3.TAB new file mode 100644 index 0000000000000000000000000000000000000000..ecc976a3e15feb32cf3ec9c215a5a3552729441b --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_BINNED_RESP_3.TAB @@ -0,0 +1 @@ + 5.9060E+02, 1.2488E+00, -2.3460E-04, 0.0000000E+00 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_0.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_0.TAB new file mode 100644 index 0000000000000000000000000000000000000000..05950952830a6c8ac428bf830f91d03dbb4cefe4 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_0.TAB @@ -0,0 +1 @@ + 3.5504E+04, 1.3191E+00, -3.0184E-04 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_1.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_1.TAB new file mode 100644 index 0000000000000000000000000000000000000000..4fd77c3ea39d7e29b7e8f3083fac15b699c72cf7 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_1.TAB @@ -0,0 +1 @@ + 1.8659E+02, 1.2488E+00, -2.3460E-04 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_2.LBL b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_2.LBL new file mode 100644 index 0000000000000000000000000000000000000000..70aea0342c5bed10e1a95653686eee2b8bcfc5a5 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_2.LBL @@ -0,0 +1,159 @@ +PDS_VERSION_ID = PDS3 + +/*** FILE FORMAT ***/ +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 53 +FILE_RECORDS = 12 + +/*** GENERAL DATA DESCRIPTION PARAMETERS ***/ +MISSION_NAME = "MESSENGER" +SPACECRAFT_NAME = "MESSENGER" +INSTRUMENT_HOST_NAME = "MERCURY SURFACE, SPACE ENVIRONMENT, + GEOCHEMISTRY AND RANGING" +DATA_SET_ID = "MESS-E/V/H-MDIS-2-EDR-RAWDATA-V1.0" +PRODUCT_ID = "MDISNAC_NOTBIN_RESP_2" + /*( MDIScam_bining_RESP_v )*/ + /*( cam = camera, NAC or WAC )*/ + /*( bining = binning, NOTBIN or BINNED )*/ + /*( v = version number, 0-9,a-z )*/ +PRODUCER_INSTITUTION_NAME = "APPLIED PHYSICS LABORATORY" + +/*** TIME PARAMETERS ***/ +PRODUCT_CREATION_TIME = 2008-11-07T20:00:00 + +/*** INSTRUMENT ENGINEERING PARAMETERS ***/ +INSTRUMENT_NAME = "MERCURY DUAL IMAGING SYSTEM NARROW ANGLE CAMERA" +INSTRUMENT_ID = "MDIS-NAC" +MESS:FPU_BIN = 0 +MESS:COMP12_8 = 0 + + +OBJECT = FILE + ^TABLE = "MDISNAC_NOTBIN_RESP_2.TAB" + RECORD_TYPE = FIXED_LENGTH + FILE_RECORDS = 1 + RECORD_BYTES = 53 + + OBJECT = TABLE + NAME = "MDIS NAC NOT-BINNED RESPONSIVITY MODEL, + VERSION 2" + INTERCHANGE_FORMAT = "ASCII" + ROWS = 1 + COLUMNS = 4 + ROW_BYTES = 53 + DESCRIPTION = "This is the model of responsivity for + the MDIS narrow-angle camera, with pixel + binning turned off (MESS:FPU_BIN = 0). It + is used to correct raw DN to units of + radiance, after correction for dark level, + frame transfer smear, linearity, and flat + field. The responsivity is in units of DN + per unit time per unit radiance. It is + dependent on CCD temperature T + (MESS:CCD_TEMP), and binning state b + (MESS:FPU_BIN). + + Exposure time t is in raw units of ms + (MESS:EXPOSURE or EXPOSURE_DURATION) and + radiance in units of + W / (m**2 microns**1 sr**1). + + Responsivity is calculated + using a second-order polynomial as + Resp(T,b) = R(t=-30.3C,b) * + [correction_offset(b) + T(CCD) * + correction_coef1(b) + T(CCD)^2 * + correction_coef2(b)] + + where + + Resp(T,b) is responsivity + at CCD temperature T in binning state b, + + T(CCD) is raw CCD temperature in units + of DNs, + + R(t=-30.3C,b) is responsivity in + binning state b at CCD temperature + of 1060 DN (-30.3C), + + correction_offset(b) is the camera- + dependent temperature correction + offset for binning state b, + + correction_coef1(b) is the camera- + dependent temperature correction + first-order coefficient for + binning state b. + + correction_coef2(b) is the camera- + dependent temperature correction + second-order coefficient for + binning state b. + + The temperature correction defaults to + unity at CCD temperature of 1060 DN + (-30.3C). + + To apply responsivity to obtain radiance + L, the expression is + L = DN_dk_sm_lin_fl / (t * Resp(T,b)) + + where + + DN_dk_sm_lin_fl is dark-, smear-, + linearity-, and flat field-corrected DN, + + t is the exposure time in milliseconds, + + Resp(T,b) is the responsivity." + + OBJECT = COLUMN + COLUMN_NUMBER = 1 + NAME = REFERENCE_RESPONSIVITY + DATA_TYPE = ASCII_REAL + START_BYTE = 1 + BYTES = 11 + DESCRIPTION = "Responsivity at the reference + temperature MESS:CCD_TEMP=1060 + (-30.3C)." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 2 + NAME = CORRECTION_OFFSET + DATA_TYPE = ASCII_REAL + START_BYTE = 13 + BYTES = 12 + DESCRIPTION = "Offset term in the CCD temperature + correction to responsivity." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 3 + NAME = CORRECTION_COEF1 + DATA_TYPE = ASCII_REAL + START_BYTE = 26 + BYTES = 12 + DESCRIPTION = "Coefficient to the first order term + in the CCD temperature correction + to responsivity." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 3 + NAME = CORRECTION_COEF2 + DATA_TYPE = ASCII_REAL + START_BYTE = 39 + BYTES = 15 + DESCRIPTION = "Coefficient to the second order term + in the CCD temperature correction + to responsivity." + END_OBJECT = COLUMN + + END_OBJECT = TABLE + +END_OBJECT = FILE + +END + diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_2.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_2.TAB new file mode 100644 index 0000000000000000000000000000000000000000..af96e3c05fbde8e2ad8420cb7747fd5de1a05fb4 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_2.TAB @@ -0,0 +1 @@ + 1.8659E+02, 1.2488E+00, -2.3460E-04, 0.0000000E+00 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_3.LBL b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_3.LBL new file mode 100644 index 0000000000000000000000000000000000000000..854526c690879407c793e6b32344872574fe87c9 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_3.LBL @@ -0,0 +1,159 @@ +PDS_VERSION_ID = PDS3 + +/*** FILE FORMAT ***/ +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 53 +FILE_RECORDS = 1 + +/*** GENERAL DATA DESCRIPTION PARAMETERS ***/ +MISSION_NAME = "MESSENGER" +SPACECRAFT_NAME = "MESSENGER" +INSTRUMENT_HOST_NAME = "MERCURY SURFACE, SPACE ENVIRONMENT, + GEOCHEMISTRY AND RANGING" +DATA_SET_ID = "MESS-E/V/H-MDIS-2-EDR-RAWDATA-V1.0" +PRODUCT_ID = "MDISNAC_NOTBIN_RESP_3" + /*( MDIScam_bining_RESP_v )*/ + /*( cam = camera, NAC or WAC )*/ + /*( bining = binning, NOTBIN or BINNED )*/ + /*( v = version number, 0-9,a-z )*/ +PRODUCER_INSTITUTION_NAME = "APPLIED PHYSICS LABORATORY" + +/*** TIME PARAMETERS ***/ +PRODUCT_CREATION_TIME = 2008-12-22T20:00:00 + +/*** INSTRUMENT ENGINEERING PARAMETERS ***/ +INSTRUMENT_NAME = "MERCURY DUAL IMAGING SYSTEM NARROW ANGLE CAMERA" +INSTRUMENT_ID = "MDIS-NAC" +MESS:FPU_BIN = 0 +MESS:COMP12_8 = 0 + + +OBJECT = FILE + ^TABLE = "MDISNAC_NOTBIN_RESP_3.TAB" + RECORD_TYPE = FIXED_LENGTH + FILE_RECORDS = 1 + RECORD_BYTES = 53 + + OBJECT = TABLE + NAME = "MDIS NAC NOT-BINNED RESPONSIVITY MODEL, + VERSION 3" + INTERCHANGE_FORMAT = "ASCII" + ROWS = 1 + COLUMNS = 4 + ROW_BYTES = 53 + DESCRIPTION = "This is the model of responsivity for + the MDIS narrow-angle camera, with pixel + binning turned off (MESS:FPU_BIN = 0). It + is used to correct raw DN to units of + radiance, after correction for dark level, + frame transfer smear, linearity, and flat + field. The responsivity is in units of DN + per unit time per unit radiance. It is + dependent on CCD temperature T + (MESS:CCD_TEMP), and binning state b + (MESS:FPU_BIN). + + Exposure time t is in raw units of ms + (MESS:EXPOSURE or EXPOSURE_DURATION) and + radiance in units of + W / (m**2 microns**1 sr**1). + + Responsivity is calculated + using a second-order polynomial as + Resp(T,b) = R(t=-30.3C,b) * + [correction_offset(b) + T(CCD) * + correction_coef1(b) + T(CCD)^2 * + correction_coef2(b)] + + where + + Resp(T,b) is responsivity + at CCD temperature T in binning state b, + + T(CCD) is raw CCD temperature in units + of DNs, + + R(t=-30.3C,b) is responsivity in + binning state b at CCD temperature + of 1060 DN (-30.3C), + + correction_offset(b) is the camera- + dependent temperature correction + offset for binning state b, + + correction_coef1(b) is the camera- + dependent temperature correction + first-order coefficient for + binning state b. + + correction_coef2(b) is the camera- + dependent temperature correction + second-order coefficient for + binning state b. + + The temperature correction defaults to + unity at CCD temperature of 1060 DN + (-30.3C). + + To apply responsivity to obtain radiance + L, the expression is + L = DN_dk_sm_lin_fl / (t * Resp(T,b)) + + where + + DN_dk_sm_lin_fl is dark-, smear-, + linearity-, and flat field-corrected DN, + + t is the exposure time in milliseconds, + + Resp(T,b) is the responsivity." + + OBJECT = COLUMN + COLUMN_NUMBER = 1 + NAME = REFERENCE_RESPONSIVITY + DATA_TYPE = ASCII_REAL + START_BYTE = 1 + BYTES = 11 + DESCRIPTION = "Responsivity at the reference + temperature MESS:CCD_TEMP=1060 + (-30.3C)." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 2 + NAME = CORRECTION_OFFSET + DATA_TYPE = ASCII_REAL + START_BYTE = 13 + BYTES = 12 + DESCRIPTION = "Offset term in the CCD temperature + correction to responsivity." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 3 + NAME = CORRECTION_COEF1 + DATA_TYPE = ASCII_REAL + START_BYTE = 26 + BYTES = 12 + DESCRIPTION = "Coefficient to the first order term + in the CCD temperature correction + to responsivity." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 3 + NAME = CORRECTION_COEF2 + DATA_TYPE = ASCII_REAL + START_BYTE = 39 + BYTES = 15 + DESCRIPTION = "Coefficient to the second order term + in the CCD temperature correction + to responsivity." + END_OBJECT = COLUMN + + END_OBJECT = TABLE + +END_OBJECT = FILE + +END + diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_3.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_3.TAB new file mode 100644 index 0000000000000000000000000000000000000000..50c55e1447e5425ac5b5dce2dc8bb61699a17306 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISNAC_NOTBIN_RESP_3.TAB @@ -0,0 +1 @@ + 1.5448E+02, 1.2488E+00, -2.3460E-04, 0.0000000E+00 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_0.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_0.TAB new file mode 100644 index 0000000000000000000000000000000000000000..ef9899c878ee047089d6e8ff8ce84d076143fd78 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_0.TAB @@ -0,0 +1,12 @@ + 1, 7.7437E+05, 1.2488E+00, -2.3460E-04 + 2, 3.9266E+05, 9.5557E-01, 4.1897E-05 + 3, 2.2576E+05, 1.8314E+00, -7.8410E-04 + 4, 5.4572E+05, 1.5695E+00, -5.3712E-04 + 5, 6.9952E+05, 1.5327E+00, -5.0237E-04 + 6, 4.3152E+04, 2.3026E+00, -1.2284E-03 + 7, 7.1210E+05, 1.0912E+00, -8.6054E-05 + 8, 3.5521E+05, -3.5311E-01, 1.2761E-03 + 9, 1.6219E+05, -1.2844E+00, 2.1543E-03 +10, 5.0648E+05, 2.3988E-01, 7.1685E-04 +11, 1.6909E+05, -1.8549E+00, 2.6924E-03 +12, 6.6792E+05, 7.4585E-01, 2.3968E-04 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_1.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_1.TAB new file mode 100644 index 0000000000000000000000000000000000000000..76e7c2ae1392c3627effaaec26707d582c5f8c49 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_1.TAB @@ -0,0 +1,12 @@ + 1, 6.4287E+05, 1.2488E+00, -2.3460E-04 + 2, 3.9266E+05, 9.5557E-01, 4.1897E-05 + 3, 1.9776E+05, 1.8314E+00, -7.8410E-04 + 4, 4.3133E+05, 1.5695E+00, -5.3712E-04 + 5, 5.5759E+05, 1.5327E+00, -5.0237E-04 + 6, 3.2459E+04, 2.3026E+00, -1.2284E-03 + 7, 6.2956E+05, 1.0912E+00, -8.6054E-05 + 8, 2.8301E+05, -3.5311E-01, 1.2761E-03 + 9, 1.3610E+05, -1.2844E+00, 2.1543E-03 +10, 4.2871E+05, 2.3988E-01, 7.1685E-04 +11, 1.0168E+05, -1.8549E+00, 2.6924E-03 +12, 5.2562E+05, 7.4585E-01, 2.3968E-04 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_2.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_2.TAB new file mode 100644 index 0000000000000000000000000000000000000000..f807a6b5ec9875064d72337f337e77462815ec29 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_2.TAB @@ -0,0 +1,12 @@ + 1, 3.4072E+02, 1.2488E+00, -2.3460E-04 + 2, 7.8532E+03, 9.5557E-01, 4.1897E-05 + 3, 2.0093E+02, 1.8314E+00, -7.8410E-04 + 4, 2.5103E+02, 1.5695E+00, -5.3712E-04 + 5, 3.0779E+02, 1.5327E+00, -5.0237E-04 + 6, 7.7674E+01, 2.3026E+00, -1.2284E-03 + 7, 3.2045E+02, 1.0912E+00, -8.6054E-05 + 8, 1.7405E+02, -3.5311E-01, 1.2761E-03 + 9, 1.9463E+02, -1.2844E+00, 2.1543E-03 +10, 2.1779E+02, 2.3988E-01, 7.1685E-04 +11, 3.3818E+02, -1.8549E+00, 2.6924E-03 +12, 2.7385E+02, 7.4585E-01, 2.3968E-04 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_3.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_3.TAB new file mode 100644 index 0000000000000000000000000000000000000000..ad6b69a1cb3c09a196ec081c79360d2fa313fc7c --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_3.TAB @@ -0,0 +1,12 @@ + 1, 3.4072E+02, 1.2488E+00, -2.3460E-04 + 2, 7.8532E+03, 9.5557E-01, 4.1897E-05 + 3, 1.8779E+02, 1.8314E+00, -7.8410E-04 + 4, 2.5103E+02, 1.5695E+00, -5.3712E-04 + 5, 3.0779E+02, 1.5327E+00, -5.0237E-04 + 6, 8.3520E+01, 2.3026E+00, -1.2284E-03 + 7, 3.2045E+02, 1.0912E+00, -8.6054E-05 + 8, 1.7405E+02, -3.5311E-01, 1.2761E-03 + 9, 1.9463E+02, -1.2844E+00, 2.1543E-03 +10, 2.1779E+02, 2.3988E-01, 7.1685E-04 +11, 3.3818E+02, -1.8549E+00, 2.6924E-03 +12, 2.7385E+02, 7.4585E-01, 2.3968E-04 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_4.LBL b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_4.LBL new file mode 100644 index 0000000000000000000000000000000000000000..05a316062339a5a46688e0390c2d5b302a52a56e --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_4.LBL @@ -0,0 +1,170 @@ +PDS_VERSION_ID = PDS3 + +/*** FILE FORMAT ***/ +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 56 +FILE_RECORDS = 12 + +/*** GENERAL DATA DESCRIPTION PARAMETERS ***/ +MISSION_NAME = "MESSENGER" +SPACECRAFT_NAME = "MESSENGER" +INSTRUMENT_HOST_NAME = "MERCURY SURFACE, SPACE ENVIRONMENT, + GEOCHEMISTRY AND RANGING" +DATA_SET_ID = "MESS-E/V/H-MDIS-2-EDR-RAWDATA-V1.0" +PRODUCT_ID = "MDISWAC_BINNED_RESP_4" + /*( MDIScam_bining_RESP_v )*/ + /*( cam = camera, NAC or WAC )*/ + /*( bining = binning, NOTBIN or BINNED )*/ + /*( v = version number, 0-9,a-z )*/ +PRODUCER_INSTITUTION_NAME = "APPLIED PHYSICS LABORATORY" + +/*** TIME PARAMETERS ***/ +PRODUCT_CREATION_TIME = 2008-11-05T20:00:00 + +/*** INSTRUMENT ENGINEERING PARAMETERS ***/ +INSTRUMENT_NAME = "MERCURY DUAL IMAGING SYSTEM WIDE ANGLE CAMERA" +INSTRUMENT_ID = "MDIS-WAC" +MESS:FPU_BIN = 1 +MESS:COMP12_8 = 0 + + +OBJECT = FILE + ^TABLE = "MDISWAC_BINNED_RESP_4.TAB" + RECORD_TYPE = FIXED_LENGTH + FILE_RECORDS = 12 + RECORD_BYTES = 56 + + OBJECT = TABLE + NAME = "MDIS WAC BINNED RESPONSIVITY MODEL, + VERSION 4" + INTERCHANGE_FORMAT = "ASCII" + ROWS = 12 + COLUMNS = 5 + ROW_BYTES = 56 + DESCRIPTION = "This is the model of responsivity for + the MDIS wide-angle camera, with pixel + binning turned on (MESS:FPU_BIN = 1). It + is used to correct raw DN to units of + radiance, after correction for dark level, + frame transfer smear, linearity, and flat + field. The responsivity is in units of DN + per unit time per unit radiance. It is + dependent on filter position f + (FILTER_NUMBER), CCD temperature T + (MESS:CCD_TEMP), and binning state b + (MESS:FPU_BIN). + + Exposure time t is in raw units of ms + (MESS:EXPOSURE or EXPOSURE_DURATION) and + radiance in units of + W / (m**2 microns**1 sr**1). + + Responsivity is calculated as + using a second-order polynomial as + Resp(f,T,b) = R(f,t=-30.3C,b) * + [correction_offset(f,b) + T(CCD) * + correction_coef1(f,b) + T(CCD)^2 * + correction_coef2(f,b)] + + where + + Resp(f,T,b) is responsivity in filter f + at CCD temperature T in binning state b, + + T(CCD) is raw CCD temperature in units + of DNs, + + R(f,t=-30.3C,b) is responsivity in filter + f in binning state b at CCD temperature + of 1060 DN (-30.3C), + + correction_offset(f,b) is camera- and + filter-dependent temperature correction + offset for filter f and binning state b, + + correction_coef1(f,b) is the camera- and + filter-dependent temperature correction + first-order coefficient for filter f and + binning state b. + + correction_coef2(f,b) is the camera- and + filter-dependent temperature correction + second-order coefficient for filter f and + binning state b. + + The temperature correction defaults to + unity at CCD temperature of 1060 DN + (-30.3C). + + To apply responsivity to obtain radiance + L, the expression is + L = DN_dk_sm_lin_fl / (t * Resp(f,T,b)) + + where + + DN_dk_sm_lin_fl is dark-, smear-, + linearity-, and flat field-corrected DN, + + t is the exposure time in milliseconds, + + Resp(f,T,b) is the responsivity." + + OBJECT = COLUMN + COLUMN_NUMBER = 1 + NAME = FILTER_NUMBER + DATA_TYPE = ASCII_INTEGER + START_BYTE = 1 + BYTES = 2 + DESCRIPTION = "WAC filter position as given in + FILTER_NUMBER." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 2 + NAME = REFERENCE_RESPONSIVITY + DATA_TYPE = ASCII_REAL + START_BYTE = 4 + BYTES = 11 + DESCRIPTION = "Responsivity at the reference + temperature MESS:CCD_TEMP=1060 + (-30.3C)." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 3 + NAME = CORRECTION_OFFSET + DATA_TYPE = ASCII_REAL + START_BYTE = 16 + BYTES = 12 + DESCRIPTION = "Offset term in the CCD temperature + correction to responsivity." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 4 + NAME = CORRECTION_COEF1 + DATA_TYPE = ASCII_REAL + START_BYTE = 29 + BYTES = 12 + DESCRIPTION = "Coefficient to the first order term + in the CCD temperature correction + to responsivity." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 5 + NAME = CORRECTION_COEF2 + DATA_TYPE = ASCII_REAL + START_BYTE = 42 + BYTES = 15 + DESCRIPTION = "Coefficient to the second order term + in the CCD temperature correction + to responsivity." + END_OBJECT = COLUMN + + END_OBJECT = TABLE + +END_OBJECT = FILE + +END + diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_4.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_4.TAB new file mode 100644 index 0000000000000000000000000000000000000000..464cba824eaa294b8b28decb6f744a6498819fba --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_BINNED_RESP_4.TAB @@ -0,0 +1,12 @@ + 1, 3.4072E+02, 8.0631E-01, 4.9021E-04, -2.9630290E-07 + 2, 7.8532E+03, 9.5557E-01, 4.1897E-05, 0.0000000E+00 + 3, 1.8779E+02, -1.0325E+00, 4.1604E-03, -2.1182256E-06 + 4, 2.5103E+02, -1.0288E+00, 3.9466E-03, -1.9200537E-06 + 5, 3.0779E+02, -2.4806E-01, 2.5649E-03, -1.3114699E-06 + 6, 8.3520E+01, 4.0058E+00, -4.2228E-03, 1.3026514E-06 + 7, 3.2045E+02, 1.2296E-01, 1.5675E-03, -7.0187040E-07 + 8, 1.7405E+02, 1.9273E+00, -2.6913E-03, 1.7104290E-06 + 9, 1.9463E+02, 2.7795E+00, -4.9030E-03, 3.0380316E-06 +10, 2.1779E+02, 7.3872E-01, -1.6836E-04, 3.8775680E-07 +11, 3.3818E+02, 1.7110E+00, -3.4829E-03, 2.6519439E-06 +12, 2.7385E+02, 9.7077E-01, -1.8015E-04, 1.9122500E-07 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_0.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_0.TAB new file mode 100644 index 0000000000000000000000000000000000000000..2a60487faf3009ac464a29ba5ad6dda042e81cb2 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_0.TAB @@ -0,0 +1,12 @@ + 1, 1.9359E+05, 1.2488E+00, -2.3460E-04 + 2, 9.8165E+04, 9.5557E-01, 4.1897E-05 + 3, 5.6441E+04, 1.8314E+00, -7.8410E-04 + 4, 1.3643E+05, 1.5695E+00, -5.3712E-04 + 5, 1.7488E+05, 1.5327E+00, -5.0237E-04 + 6, 1.0788E+04, 2.3026E+00, -1.2284E-03 + 7, 1.7803E+05, 1.0912E+00, -8.6054E-05 + 8, 8.8803E+04, -3.5311E-01, 1.2761E-03 + 9, 4.0546E+04, -1.2844E+00, 2.1543E-03 +10, 1.2662E+05, 2.3988E-01, 7.1685E-04 +11, 4.2273E+04, -1.8549E+00, 2.6924E-03 +12, 1.6698E+05, 7.4585E-01, 2.3968E-04 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_1.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_1.TAB new file mode 100644 index 0000000000000000000000000000000000000000..27f2ffed5ef5e40f39e3ec743a50d8a744fae882 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_1.TAB @@ -0,0 +1,12 @@ + 1, 1.6072E+05, 1.2488E+00, -2.3460E-04 + 2, 9.8165E+04, 9.5557E-01, 4.1897E-05 + 3, 4.9441E+04, 1.8314E+00, -7.8410E-04 + 4, 1.0783E+05, 1.5695E+00, -5.3712E-04 + 5, 1.3940E+05, 1.5327E+00, -5.0237E-04 + 6, 8.1147E+03, 2.3026E+00, -1.2284E-03 + 7, 1.5739E+05, 1.0912E+00, -8.6054E-05 + 8, 7.0754E+04, -3.5311E-01, 1.2761E-03 + 9, 3.4025E+04, -1.2844E+00, 2.1543E-03 +10, 1.0718E+05, 2.3988E-01, 7.1685E-04 +11, 2.5420E+04, -1.8549E+00, 2.6924E-03 +12, 1.3140E+05, 7.4585E-01, 2.3968E-04 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_2.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_2.TAB new file mode 100644 index 0000000000000000000000000000000000000000..1fd0f3c3efe184b94514add3416e995a6cfbf77a --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_2.TAB @@ -0,0 +1,12 @@ + 1, 8.5180E+01, 1.2488E+00, -2.3460E-04 + 2, 1.9633E+03, 9.5557E-01, 4.1897E-05 + 3, 5.0232E+01, 1.8314E+00, -7.8410E-04 + 4, 6.2758E+01, 1.5695E+00, -5.3712E-04 + 5, 7.6947E+01, 1.5327E+00, -5.0237E-04 + 6, 1.9418E+01, 2.3026E+00, -1.2284E-03 + 7, 8.0114E+01, 1.0912E+00, -8.6054E-05 + 8, 4.3513E+01, -3.5311E-01, 1.2761E-03 + 9, 4.8655E+01, -1.2844E+00, 2.1543E-03 +10, 5.4447E+01, 2.3988E-01, 7.1685E-04 +11, 8.4546E+01, -1.8549E+00, 2.6924E-03 +12, 6.8462E+01, 7.4585E-01, 2.3968E-04 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_3.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_3.TAB new file mode 100644 index 0000000000000000000000000000000000000000..eec362c37155c0729296aae87aace37018219e9c --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_3.TAB @@ -0,0 +1,12 @@ + 1, 8.5180E+01, 1.2488E+00, -2.3460E-04 + 2, 1.9633E+03, 9.5557E-01, 4.1897E-05 + 3, 4.6946E+01, 1.8314E+00, -7.8410E-04 + 4, 6.2758E+01, 1.5695E+00, -5.3712E-04 + 5, 7.6947E+01, 1.5327E+00, -5.0237E-04 + 6, 2.0880E+01, 2.3026E+00, -1.2284E-03 + 7, 8.0114E+01, 1.0912E+00, -8.6054E-05 + 8, 4.3513E+01, -3.5311E-01, 1.2761E-03 + 9, 4.8655E+01, -1.2844E+00, 2.1543E-03 +10, 5.4447E+01, 2.3988E-01, 7.1685E-04 +11, 8.4546E+01, -1.8549E+00, 2.6924E-03 +12, 6.8462E+01, 7.4585E-01, 2.3968E-04 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_4.LBL b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_4.LBL new file mode 100644 index 0000000000000000000000000000000000000000..2a0ea95493771f2e4de78cb2501da015312aaaf8 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_4.LBL @@ -0,0 +1,170 @@ +PDS_VERSION_ID = PDS3 + +/*** FILE FORMAT ***/ +RECORD_TYPE = FIXED_LENGTH +RECORD_BYTES = 56 +FILE_RECORDS = 12 + +/*** GENERAL DATA DESCRIPTION PARAMETERS ***/ +MISSION_NAME = "MESSENGER" +SPACECRAFT_NAME = "MESSENGER" +INSTRUMENT_HOST_NAME = "MERCURY SURFACE, SPACE ENVIRONMENT, + GEOCHEMISTRY AND RANGING" +DATA_SET_ID = "MESS-E/V/H-MDIS-2-EDR-RAWDATA-V1.0" +PRODUCT_ID = "MDISWAC_NOTBIN_RESP_4" + /*( MDIScam_bining_RESP_v )*/ + /*( cam = camera, NAC or WAC )*/ + /*( bining = binning, NOTBIN or BINNED )*/ + /*( v = version number, 0-9,a-z )*/ +PRODUCER_INSTITUTION_NAME = "APPLIED PHYSICS LABORATORY" + +/*** TIME PARAMETERS ***/ +PRODUCT_CREATION_TIME = 2008-11-05T20:00:00 + +/*** INSTRUMENT ENGINEERING PARAMETERS ***/ +INSTRUMENT_NAME = "MERCURY DUAL IMAGING SYSTEM WIDE ANGLE CAMERA" +INSTRUMENT_ID = "MDIS-WAC" +MESS:FPU_BIN = 0 +MESS:COMP12_8 = 0 + + +OBJECT = FILE + ^TABLE = "MDISWAC_NOTBIN_RESP_4.TAB" + RECORD_TYPE = FIXED_LENGTH + FILE_RECORDS = 12 + RECORD_BYTES = 56 + + OBJECT = TABLE + NAME = "MDIS WAC NOT-BINNED RESPONSIVITY MODEL, + VERSION 4" + INTERCHANGE_FORMAT = "ASCII" + ROWS = 12 + COLUMNS = 5 + ROW_BYTES = 56 + DESCRIPTION = "This is the model of responsivity for + the MDIS wide-angle camera, without pixel + binning turned on (MESS:FPU_BIN = 0). It + is used to correct raw DN to units of + radiance, after correction for dark level, + frame transfer smear, linearity, and flat + field. The responsivity is in units of DN + per unit time per unit radiance. It is + dependent on filter position f + (FILTER_NUMBER), CCD temperature T + (MESS:CCD_TEMP), and binning state b + (MESS:FPU_BIN). + + Exposure time t is in raw units of ms + (MESS:EXPOSURE or EXPOSURE_DURATION) and + radiance in units of + W / (m**2 microns**1 sr**1). + + Responsivity is calculated as + using a second-order polynomial as + Resp(f,T,b) = R(f,t=-30.3C,b) * + [correction_offset(f,b) + T(CCD) * + correction_coef1(f,b) + T(CCD)^2 * + correction_coef2(f,b)] + + where + + Resp(f,T,b) is responsivity in filter f + at CCD temperature T in binning state b, + + T(CCD) is raw CCD temperature in units + of DNs, + + R(f,t=-30.3C,b) is responsivity in filter + f in binning state b at CCD temperature + of 1060 DN (-30.3C), + + correction_offset(f,b) is camera- and + filter-dependent temperature correction + offset for filter f and binning state b, + + correction_coef1(f,b) is the camera- and + filter-dependent temperature correction + first-order coefficient for filter f and + binning state b. + + correction_coef2(f,b) is the camera- and + filter-dependent temperature correction + second-order coefficient for filter f and + binning state b. + + The temperature correction defaults to + unity at CCD temperature of 1060 DN + (-30.3C). + + To apply responsivity to obtain radiance + L, the expression is + L = DN_dk_sm_lin_fl / (t * Resp(f,T,b)) + + where + + DN_dk_sm_lin_fl is dark-, smear-, + linearity-, and flat field-corrected DN, + + t is the exposure time in milliseconds, + + Resp(f,T,b) is the responsivity." + + OBJECT = COLUMN + COLUMN_NUMBER = 1 + NAME = FILTER_NUMBER + DATA_TYPE = ASCII_INTEGER + START_BYTE = 1 + BYTES = 2 + DESCRIPTION = "WAC filter position as given in + FILTER_NUMBER." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 2 + NAME = REFERENCE_RESPONSIVITY + DATA_TYPE = ASCII_REAL + START_BYTE = 4 + BYTES = 11 + DESCRIPTION = "Responsivity at the reference + temperature MESS:CCD_TEMP=1060 + (-30.3C)." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 3 + NAME = CORRECTION_OFFSET + DATA_TYPE = ASCII_REAL + START_BYTE = 16 + BYTES = 12 + DESCRIPTION = "Offset term in the CCD temperature + correction to responsivity." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 4 + NAME = CORRECTION_COEF1 + DATA_TYPE = ASCII_REAL + START_BYTE = 29 + BYTES = 12 + DESCRIPTION = "Coefficient to the first order term + in the CCD temperature correction + to responsivity." + END_OBJECT = COLUMN + + OBJECT = COLUMN + COLUMN_NUMBER = 5 + NAME = CORRECTION_COEF2 + DATA_TYPE = ASCII_REAL + START_BYTE = 42 + BYTES = 15 + DESCRIPTION = "Coefficient to the second order term + in the CCD temperature correction + to responsivity." + END_OBJECT = COLUMN + + END_OBJECT = TABLE + +END_OBJECT = FILE + +END + diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_4.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_4.TAB new file mode 100644 index 0000000000000000000000000000000000000000..806d7ac962d07a107669a5dbdcdaf1d30468fae4 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/RESPONSIVITY/MDISWAC_NOTBIN_RESP_4.TAB @@ -0,0 +1,12 @@ + 1, 8.5180E+01, 8.0631E-01, 4.9021E-04, -2.9630290E-07 + 2, 1.9633E+03, 9.5557E-01, 4.1897E-05, 0.0000000E+00 + 3, 4.6946E+01, -1.0325E+00, 4.1604E-03, -2.1182256E-06 + 4, 6.2758E+01, -1.0288E+00, 3.9466E-03, -1.9200537E-06 + 5, 7.6947E+01, -2.4806E-01, 2.5649E-03, -1.3114699E-06 + 6, 2.0880E+01, 4.0058E+00, -4.2228E-03, 1.3026514E-06 + 7, 8.0114E+01, 1.2296E-01, 1.5675E-03, -7.0187040E-07 + 8, 4.3513E+01, 1.9273E+00, -2.6913E-03, 1.7104290E-06 + 9, 4.8655E+01, 2.7795E+00, -4.9030E-03, 3.0380316E-06 +10, 5.4447E+01, 7.3872E-01, -1.6836E-04, 3.8775680E-07 +11, 8.4546E+01, 1.7110E+00, -3.4829E-03, 2.6519439E-06 +12, 6.8462E+01, 9.7077E-01, -1.8015E-04, 1.9122500E-07 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/SOLAR/MDISNAC_SOLAR_0.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/SOLAR/MDISNAC_SOLAR_0.TAB new file mode 100644 index 0000000000000000000000000000000000000000..2577ae121527acb90a9db313764f52694c22f742 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/SOLAR/MDISNAC_SOLAR_0.TAB @@ -0,0 +1 @@ + 747.70, 52.55, 1278.85 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/SOLAR/MDISWAC_SOLAR_0.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/SOLAR/MDISWAC_SOLAR_0.TAB new file mode 100644 index 0000000000000000000000000000000000000000..8f0e7b930e7911a26396fefb5aa5858af0c63630 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/SOLAR/MDISWAC_SOLAR_0.TAB @@ -0,0 +1,12 @@ + 1, 698.76, 5.30, 1429.10 + 2, 701.27, 196.51, 1432.13 + 3, 479.87, 10.14, 2091.95 + 4, 558.91, 5.82, 1833.26 + 5, 628.81, 5.52, 1669.08 + 6, 433.21, 18.11, 1733.07 + 7, 748.73, 5.09, 1293.93 + 8, 947.03, 6.15, 813.27 + 9, 996.23, 14.30, 741.46 + 10, 898.80, 5.08, 900.80 + 11, 1012.56, 33.33, 714.15 + 12, 828.39, 5.20, 1062.92 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/mdisCalibration0001.trn b/isis/src/messenger/apps/mdiscal/resources/calibration/mdisCalibration0001.trn new file mode 100644 index 0000000000000000000000000000000000000000..cfdd6047b9c1a63ba6b00eb3fbb4784d95bd6025 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/mdisCalibration0001.trn @@ -0,0 +1,57 @@ +Group = NarrowAngleResponsivity + NotBinned = 3.5504E+04 + Binned = 3.5504E+04 +EndGroup + +Group = NarrowAngleOffset + NotBinned = 1.3191E+00 + Binned = 1.3191E+00 +EndGroup + +Group = NarrowAngleSlope + NotBinned = -3.0184E-04 + Binned = -3.0184E-04 +EndGroup + +Group = WideAngleResponsivity + NotBinned = (1.9359E+05, 9.8165E+04, 5.6441E+04, + 1.3643E+05, 1.7488E+05, 1.0788E+04, + 1.7803E+05, 8.8803E+04, 4.0546E+04, + 1.2662E+05, 4.2273E+04, 1.6698E+05) + Binned = (1.9359E+05, 9.8165E+04, 5.6441E+04, + 1.3643E+05, 1.7488E+05, 1.0788E+04, + 1.7803E+05, 8.8803E+04, 4.0546E+04, + 1.2662E+05, 4.2273E+04, 1.6698E+05) +EndGroup + +Group = WideAngleOffset + FilterValues = (1.2488E+00, 9.5557E-01, 1.8314E+00, + 1.5695E+00, 1.5327E+00, 2.3026E+00, + 1.0912E+00, -3.5311E-01, -1.2844E+00, + 2.3988E-01, -1.8549E+00, 7.4585E-01) +EndGroup + +Group = WideAngleSlope + FilterValues = (-2.3460E-04, 4.1897E-05, -7.8410E-04, + -5.3712E-04, -5.0237E-04, -1.2284E-03, + -8.6054E-05, 1.2761E-03, 2.1543E-03, + 7.1685E-04, 2.6924E-03, 2.3968E-04) +EndGroup + +Group = FilterWheel + EncoderPosition1 = 17376 # Wave(nm) 700 FWHM(nm) 5 + EncoderPosition2 = 11976 # Wave(nm) 700 FWHM(nm) 600 + EncoderPosition3 = 6492 # Wave(nm) 480 FWHM(nm) 10 + EncoderPosition4 = 1108 # Wave(nm) 560 FWHM(nm) 5 + EncoderPosition5 = 61104 # Wave(nm) 630 FWHM(nm) 5 + EncoderPosition6 = 55684 # Wave(nm) 415 FWHM(nm) 40 + EncoderPosition7 = 50148 # Wave(nm) 750 FWHM(nm) 5 + EncoderPosition8 = 44760 # Wave(nm) 950 FWHM(nm) 7 + EncoderPosition9 = 39256 # Wave(nm) 1000 FWHM(nm) 15 + EncoderPosition10 = 39256 # Wave(nm) 900 FWHM(nm) 5 + EncoderPosition11 = 33796 # Wave(nm) 1020 FWHM(nm) 40 + EncoderPosition12 = 28252 # Wave(nm) 830 FWHM(nm) 5 + EncoderTolerance = 240 +EndGroup + +End diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/mdisCalibration0002.trn b/isis/src/messenger/apps/mdiscal/resources/calibration/mdisCalibration0002.trn new file mode 100644 index 0000000000000000000000000000000000000000..2bd76816b34e145bd2d09f777ff68ad77ac615e3 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/mdisCalibration0002.trn @@ -0,0 +1,59 @@ +# Filter encoder positions for filters 10, 11 and 12 were incorrect and +# are updated in this version (KJB, 2008-01-19). +Group = NarrowAngleResponsivity + NotBinned = 3.5504E+04 + Binned = 3.5504E+04 +EndGroup + +Group = NarrowAngleOffset + NotBinned = 1.3191E+00 + Binned = 1.3191E+00 +EndGroup + +Group = NarrowAngleSlope + NotBinned = -3.0184E-04 + Binned = -3.0184E-04 +EndGroup + +Group = WideAngleResponsivity + NotBinned = (1.9359E+05, 9.8165E+04, 5.6441E+04, + 1.3643E+05, 1.7488E+05, 1.0788E+04, + 1.7803E+05, 8.8803E+04, 4.0546E+04, + 1.2662E+05, 4.2273E+04, 1.6698E+05) + Binned = (1.9359E+05, 9.8165E+04, 5.6441E+04, + 1.3643E+05, 1.7488E+05, 1.0788E+04, + 1.7803E+05, 8.8803E+04, 4.0546E+04, + 1.2662E+05, 4.2273E+04, 1.6698E+05) +EndGroup + +Group = WideAngleOffset + FilterValues = (1.2488E+00, 9.5557E-01, 1.8314E+00, + 1.5695E+00, 1.5327E+00, 2.3026E+00, + 1.0912E+00, -3.5311E-01, -1.2844E+00, + 2.3988E-01, -1.8549E+00, 7.4585E-01) +EndGroup + +Group = WideAngleSlope + FilterValues = (-2.3460E-04, 4.1897E-05, -7.8410E-04, + -5.3712E-04, -5.0237E-04, -1.2284E-03, + -8.6054E-05, 1.2761E-03, 2.1543E-03, + 7.1685E-04, 2.6924E-03, 2.3968E-04) +EndGroup + +Group = FilterWheel + EncoderPosition1 = 17376 # Wave(nm) 700 FWHM(nm) 5 + EncoderPosition2 = 11976 # Wave(nm) 700 FWHM(nm) 600 + EncoderPosition3 = 6492 # Wave(nm) 480 FWHM(nm) 10 + EncoderPosition4 = 1108 # Wave(nm) 560 FWHM(nm) 5 + EncoderPosition5 = 61104 # Wave(nm) 630 FWHM(nm) 5 + EncoderPosition6 = 55684 # Wave(nm) 415 FWHM(nm) 40 + EncoderPosition7 = 50148 # Wave(nm) 750 FWHM(nm) 5 + EncoderPosition8 = 44760 # Wave(nm) 950 FWHM(nm) 7 + EncoderPosition9 = 39256 # Wave(nm) 1000 FWHM(nm) 15 + EncoderPosition10 = 33796 # Wave(nm) 900 FWHM(nm) 5 + EncoderPosition11 = 28252 # Wave(nm) 1020 FWHM(nm) 40 + EncoderPosition12 = 22852 # Wave(nm) 830 FWHM(nm) 5 + EncoderTolerance = 240 +EndGroup + +End diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/smear/MDISNAC_FRAME_TRANSFER_01.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/smear/MDISNAC_FRAME_TRANSFER_01.TAB new file mode 100644 index 0000000000000000000000000000000000000000..3235bceacd9e448a471ae9db476a0389f0f13970 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/smear/MDISNAC_FRAME_TRANSFER_01.TAB @@ -0,0 +1 @@ + 3.4 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/smear/MDISWAC_FRAME_TRANSFER_01.TAB b/isis/src/messenger/apps/mdiscal/resources/calibration/smear/MDISWAC_FRAME_TRANSFER_01.TAB new file mode 100644 index 0000000000000000000000000000000000000000..dd5f08b5ee3998e40f9c1b17aeb262be5212ac23 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/smear/MDISWAC_FRAME_TRANSFER_01.TAB @@ -0,0 +1,12 @@ + 1, 3.4 + 2, 3.4 + 3, 3.7 + 4, 3.5 + 5, 3.4 + 6, 4.2 + 7, 3.4 + 8, 3.4 + 9, 3.4 + 10, 3.4 + 11, 3.4 + 12, 3.4 diff --git a/isis/src/messenger/apps/mdiscal/resources/calibration/smear/mdis_readout.pro b/isis/src/messenger/apps/mdiscal/resources/calibration/smear/mdis_readout.pro new file mode 100644 index 0000000000000000000000000000000000000000..6e165dc3772c2cdb080a074a307ad9965b180766 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/resources/calibration/smear/mdis_readout.pro @@ -0,0 +1,79 @@ +pro mdis_readout,image_dark,exp_1,im_type,filter1,image_readout +!ORDER=1 +;MSR +;UPDATED May 1, 2003 +;UPDATED August 2005 +;UPDATED February 24 2008 (rconstant per wavelength) + +; Function to undo linear smearing blur that occurs during +; pixel read-out time in MDIS Imager +; Algorithm form Pat Murphy, APL originally for NEAR MSI + +; t2 = .9 msec / nlines frame transfer per line +; T1 = exposure time + +;if im_type eq 1 then begin +;print,'*************************************************************' +;print,'Warning: need confirmation that t constant is half for binned ' +;print,'*************************************************************' +;endif + +;FOR MESSENGER MDIS 3.84 msecs initially + +; t2 = 3.84/1024. ORIGINAL VALUE FROM HUGO +; readout_constant=3.4/1000. ;converting into seconds to match exposure + rconstant=fltarr(12) + rindex=filter1-1 + rconstant[0]=3.4/1000. ;1 A 700nm narrow . + rconstant[1]=3.4/1000. ;2 B 700nm clear + rconstant[2]=3.7/1000. ;3 C 480nm + rconstant[3]=3.5/1000. ;4 D 560nm + rconstant[4]=3.4/1000. ;5 E 630nm + rconstant[5]=4.2/1000. ;6 F 430nm + rconstant[6]=3.4/1000. ;7 G 750nm + rconstant[7]=3.4/1000. ;8 H 950nm* + rconstant[8]=3.4/1000. ;9 I 1000nmS* + rconstant[9]=3.4/1000. ;10 J 900nm* + rconstant[10]=3.4/1000. ;11 K 1020nm* + rconstant[11]=3.4/1000. ;12 L 830nm* + + t2 = rconstant[rindex]/1024. + + if im_type eq 1 then t2=rconstant[rindex]/512. + +print,'Using readout constant: ',rconstant[rindex],' Updated Feb 2008' +print,'Using readout time of: ',t2, ' msecs' + + T1 = exp_1 + + s=size(image_dark) + + image_readout = image_dark + + NX = s(1) + NY = s(2) + + added = fltarr(NX) + +if T1 gt 0.0000 then begin + for j = 1, NY-1 do begin + added = added + t2/T1*image_readout(*,j-1) + image_readout(*,j) = image_dark(*,j) - added + endfor +endif + +if T1 eq 0.0000 then print, '*** INFO: Found 0 exposure, skip readout smear' + +print,' MDIS: readout smear removed' + +return +end + + + + + + + + + diff --git a/isis/src/messenger/apps/mdiscal/resources/doc/CALINFO.TXT b/isis/src/messenger/apps/mdiscal/resources/doc/CALINFO.TXT new file mode 100755 index 0000000000000000000000000000000000000000..fd07e71a4198ac5ac15bfecfe4e884237abb2141 Binary files /dev/null and b/isis/src/messenger/apps/mdiscal/resources/doc/CALINFO.TXT differ diff --git a/isis/src/messenger/apps/mdiscal/resources/doc/MDIS_CDR_DS.CAT b/isis/src/messenger/apps/mdiscal/resources/doc/MDIS_CDR_DS.CAT new file mode 100755 index 0000000000000000000000000000000000000000..c9ff4234776c47219bc6af7e8832134edee1aaa9 Binary files /dev/null and b/isis/src/messenger/apps/mdiscal/resources/doc/MDIS_CDR_DS.CAT differ diff --git a/isis/src/messenger/apps/mdiscal/tsts/Makefile b/isis/src/messenger/apps/mdiscal/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/messenger/apps/mdiscal/tsts/default/Makefile b/isis/src/messenger/apps/mdiscal/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6895066a9e9c1bd4d8461f657691db61bef50eb4 --- /dev/null +++ b/isis/src/messenger/apps/mdiscal/tsts/default/Makefile @@ -0,0 +1,18 @@ +APPNAME = mdiscal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/EW0089565626A.cub to=$(OUTPUT)/default.cub iof=no > /dev/null; + catlab FROM=$(OUTPUT)/default.cub > $(OUTPUT)/default_label.pvl; + $(APPNAME) FROM=$(INPUT)/EW0089565626A.cub to=$(OUTPUT)/nodark.cub DARKCURRENT=none iof=no > /dev/null; + catlab FROM=$(OUTPUT)/nodark.cub > $(OUTPUT)/nodark_label.pvl; + $(APPNAME) FROM=$(INPUT)/EW0089565626A.cub to=$(OUTPUT)/lineardark.cub DARKCURRENT=linear iof=no > /dev/null; + catlab FROM=$(OUTPUT)/lineardark.cub > $(OUTPUT)/lineardark_label.pvl; + $(APPNAME) FROM=$(INPUT)/EW0089565626A.cub to=$(OUTPUT)/standarddark.cub DARKCURRENT=standard iof=no > /dev/null; + catlab FROM=$(OUTPUT)/standarddark.cub > $(OUTPUT)/standarddark_label.pvl; + $(APPNAME) FROM=$(INPUT)/EW0089565626A.cub KEEPDARK=true to=$(OUTPUT)/keepdark.cub iof=no > /dev/null; + catlab FROM=$(OUTPUT)/keepdark.cub > $(OUTPUT)/keepdark_label.pvl; + $(APPNAME) FROM=$(INPUT)/EW0089565626A.cub to=$(OUTPUT)/iof.cub > /dev/null; + catlab FROM=$(OUTPUT)/iof.cub > $(OUTPUT)/iof_label.pvl; + diff --git a/isis/src/messenger/apps/mdisddr/Kernels.cpp b/isis/src/messenger/apps/mdisddr/Kernels.cpp new file mode 100644 index 0000000000000000000000000000000000000000..24101cdbcedbaa63fb8d31d03c9e241c9a5f4697 --- /dev/null +++ b/isis/src/messenger/apps/mdisddr/Kernels.cpp @@ -0,0 +1,269 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2009/12/29 23:03:50 $ + * $Id: Kernels.cpp,v 1.2 2009/12/29 23:03:50 ehyer Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include +#include + +#include "Kernels.h" +#include "Filename.h" +#include "PvlKeyword.h" +#include "Pvl.h" +#include "iException.h" +#include "naif/SpiceUsr.h" + +using namespace std; + +namespace Isis { + + /** + * @brief Construct using an ISIS file name + * + * @param filename Name of ISIS cube file + */ + Kernels::Kernels(const std::string &filename) { + Pvl pvl(filename); + Load(pvl); + } + + /** + * @brief Construct using an ISIS Cube object + * + * @param cube Cube object of ISIS file + */ + Kernels::Kernels(Cube &cube) { + Load(*cube.Label()); + } + + /** + * @brief Construct from an ISIS label + * + * @param pvl ISIS label to get kernel information from + */ + Kernels::Kernels(Pvl &pvl) { + Load(pvl); + } + + + /** + * @brief Perform the hunt for Spice kernels in an ISIS label + * + * This method must traverse the ISIS label hierarchy to find all the + * pertinent kernel files. Many of them are found in the Kernel Group, but + * others exist in Table objects that are SPICE blobs. The actual names are + * found in the Kernels keyword in the named Table object. + * + * @param pvl ISIS label + */ + void Kernels::Load(Pvl &pvl) { + _kernels.clear(); + addKernels(findKernels("InstrumentPosition", KernelSet::Spk, pvl, "InstrumentPosition")); + addKernels(findKernels("Frame", KernelSet::Fk, pvl)); + addKernels(findKernels("InstrumentPointing", KernelSet::Ck, pvl, "InstrumentPointing")); + addKernels(findKernels("TargetPosition", KernelSet::Pck, pvl, "SunPosition")); + addKernels(findKernels("TargetAttitudeShape", KernelSet::Pck, pvl, "BodyRotation")); + addKernels(findKernels("Instrument", KernelSet::Ik, pvl)); + addKernels(findKernels("InstrumentAddendum", KernelSet::Spk, pvl)); + addKernels(findKernels("LeapSecond", KernelSet::Lsk, pvl)); + addKernels(findKernels("SpacecraftClock", KernelSet::Sclk, pvl)); + addKernels(findKernels("ShapeModel", KernelSet::Dem, pvl)); + addKernels(findKernels("Extras", KernelSet::Extras, pvl)); + return; + } + + void Kernels::addKernels(const KernelSet &kset) { + KernelSet kerns = kset; + if (size() > 0) { + kerns.setDependancy(_kernels[size()-1].type()); + } + _kernels.push_back(kerns); + return; + } + + /** + * @brief Provide a list of all the kernels found + * + * This method will return all the kernel file references as found in the ISIS + * label. It will optionally remove the file paths and return only the kernel + * file name if requested. If removePath is false, it returns the complete + * path to the SPICE kernels. + * + * @param removePath Do we remove the file paths and return only the file + * names? + * + * @return std::vector A vector of filenames of SPICE kernels + */ + Kernels::KernelFiles Kernels::getList(bool removePath) const { + KernelFiles flist; + for (unsigned int i = 0 ; i < _kernels.size() ; i++) { + KernelFiles kfiles = _kernels[i].getNames(); + for (unsigned int k = 0 ; k < kfiles.size() ; k++) { + if (removePath) { + Filename kfile(kfiles[k]); + flist.push_back(kfile.Name()); + } + else { + flist.push_back(kfiles[k]); + } + } + } + return (flist); + } + + /** + * @brief Unloads all kernels if they were loaded when found + */ + void Kernels::Unload() { + if (_furnish) { + for (unsigned int i = 0 ; i < _kernels.size() ; i++) { + KernelFiles kfiles = _kernels[i].getNames(); + for (unsigned int k = 0 ; k < kfiles.size() ; k++) { + Filename f(kfiles[k]); + string kernName(f.Expanded()); + unload_c(kernName.c_str()); + } + } + } + return; + } + + KernelSet Kernels::findKernels(const std::string &kname, + KernelSet::KernelType ktype, Pvl &pvl, + const std::string &blobname) const { + // Get the kernel group and load main kernels + PvlGroup &kernels = pvl.FindGroup("Kernels",Pvl::Traverse); + KernelSet kkey(PvlKeyword(kname), ktype); + + // Check for the keyword + if (kernels.HasKeyword(kname)) { + kkey = KernelSet(kernels[kname], ktype); + // Check for keyword design < 3.1.19 and update it to current state + if (kkey.inTable() && (kkey.size() == 0)) { + string bname(blobname); + if (bname.empty()) bname = kname; + const PvlObject &blob = findTable(bname, pvl); + if (blob.HasKeyword("Kernels")) { + PvlKeyword bkey = blob["Kernels"]; + PvlKeyword newkey = kernels[kname]; + // Found the Kernels keyword in BLOB. Get the filenames + for (int i = 0 ; i < bkey.Size() ; i++) { + newkey.AddValue(bkey[i]); + } + kkey = KernelSet(newkey, ktype); + } + else { + kkey.Missing("Image has been jigsawed and/or kernels are gone"); + } + } + } + + return (kkey); + } + + const PvlObject &Kernels::findTable(const std::string &name, PvlObject &pvl) + const { + PvlObject::ConstPvlObjectIterator tobj = pvl.FindObject("Table", + pvl.BeginObject(), + pvl.EndObject()); + while (tobj != pvl.EndObject()) { + if (iString::Equal(tobj->Name(), "Table")) { + if (tobj->HasKeyword("Name")) { + if (iString::Equal((*tobj)["Name"], name)) { + return (*tobj); + } + } + } + ++tobj; + } + + // If it reaches here, it is a fatal error + string mess = "Failed to find Table object named " + name; + throw iException::Message(iException::Programmer, mess, _FILEINFO_); + } + /** + * @brief Loops through PvlKeyword containing Kernel file names + * + * This method interogates a PvlKeyword that is determined to + * contain SPICE kernel names. It will optionally load the + * kernels if initially requested and then adds the name to the + * internally managed list. + * + * Some keywords may contain special keywords. These are ignored in this + * method and can be handled explicitly in other methods. + * + * @param key PvlKeyword containing SPICE kernels + * @see loadKernelFromTable() + */ + void Kernels::loadKernel(PvlKeyword &key) { + for (int i=0; iName()) == "TABLE") { + if (objIter->HasKeyword("Name")) { + if (iString::Equal(objIter->FindKeyword("Name")[0], tblname)) { + loadKernel(objIter->FindKeyword("Kernels")); + return; + } + } + } + } + } + return; + } +} // namespace Isis + + diff --git a/isis/src/messenger/apps/mdisddr/Kernels.h b/isis/src/messenger/apps/mdisddr/Kernels.h new file mode 100644 index 0000000000000000000000000000000000000000..7f31ea5976084d60ac29b69bb66994763890e667 --- /dev/null +++ b/isis/src/messenger/apps/mdisddr/Kernels.h @@ -0,0 +1,174 @@ +#if !defined(Kernels_h) +#define Kernels_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/06/26 23:39:21 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "Pvl.h" +#include "Cube.h" +#include "Camera.h" +#include "iException.h" + +namespace Isis { + +class KernelSet { + public: + typedef enum { None, Lsk, Pck, Ik, Fk, Sclk, Ck, Spk, Iak, Dem, Extras } KernelType; + typedef std::vector KernelFiles; + KernelSet() : _kernkey(PvlKeyword("Kernels")), _ktype(None), + _dependancy(None),_missing("") {} + KernelSet(const PvlKeyword &key, KernelType &ktype, + const KernelType &depends = None) : _kernkey(key), _ktype(ktype), + _dependancy(depends), + _missing("") { } + ~KernelSet() {} + + /** + * @brief Determines if the kernel keyword is valid + * @return bool True if the keyword is non-NULL + */ + bool isValid() const { return (!_kernkey.IsNull()); } + /** + * @brief Get number of kernels files in list excluding special Tabel/Nadir + * @return int Number of real kernel files + */ + int size() const { + if (!isValid()) return (0); + return (_kernkey.Size() - ((inTable()) ? 1 : 0)); + } + + KernelType type() const { return (_ktype); } + bool inTable() const { + if ((_kernkey.Size() > 0) && (isTableBound(_kernkey[0]))) return (true); + return (false); + } + + KernelType dependant() const { return (_dependancy); } + void setDependancy(const KernelType &depends) { _dependancy = depends; } + + KernelFiles getNames() const { + KernelFiles k; + if (isValid()) { + for (int i = 0 ; i < _kernkey.Size() ; i++) { + if (!isTableBound(_kernkey[i])) k.push_back(_kernkey[i]); + } + } + return (k); + } + + void Missing(const std::string &mess = "Kernel names not found") { + _missing = mess; + } + + bool isMissing() const { return (_missing.size() > 0); } + const std::string getMissing() const { return (_missing); } + + private: + PvlKeyword _kernkey; + KernelType _ktype; + KernelType _dependancy; + std::string _missing; + + bool isTableBound(const std::string &kfile) const { + if (iString::Equal(kfile, "Table")) return (true); + if (iString::Equal(kfile, "Nadir")) return (true); + return (false); + } + +}; + + + /** + * @brief Determine SPICE kernels defined in an ISIS file + * + * This class determines all SPICE kernels associated to an ISIS cube file and + * optionally loads them using the NAIF toolkit. This creates the kernel pool + * as it was when spiceinit determined all the kernels and it initialized the + * file for geometric operations. + * + * Note that ISIS caches of some of the voluminous NAIF kernels, extracting + * only what is required from the SPK and CK (generally) kernels for a given + * observation. After this occurs, these kernels are no longer loaded by the + * ISIS Spice class hierarchy. This class provides that environment so that + * further NAIF operations can occur, such as velocity vectors. + * + * @ingroup Utility + * @author 2007-08-19 Kris Becker + */ +class Kernels { + public: + typedef KernelSet::KernelFiles KernelFiles; + /** Default Constructor */ + Kernels() : _kernels(), _furnish(false) { } + Kernels(const std::string &filename); + Kernels(Cube &cube); + Kernels(Pvl &pvl); + /** Destructor always unloads the kernels from the pool */ + virtual ~Kernels() { Unload(); } + + /** + * @brief Returns the number of kernel keywords found + * @return int Number keywords + */ + int nKeys() const { return (_kernels.size()); } + + /** Returns the number of kernels found and/or loaded */ + int size() const { + int nk(0); + ConstKernelListIter k; + for (k = _kernels.begin() ; k != _kernels.end() ; ++k) { + nk += k->size(); + } + return (nk); + } + + void Load(Pvl &pvl); + KernelFiles getList(bool removePath = false) const; + void Unload(); + + private: + typedef std::vector KernelList; + typedef KernelList::iterator KernelListIter; + typedef KernelList::const_iterator ConstKernelListIter; + typedef KernelSet::KernelType KernelType; + KernelList _kernels; + bool _furnish; //!< Load the kernels found? + + KernelSet findKernels(const std::string &kname, + KernelSet::KernelType ktype, Pvl &Pvl, + const std::string &blobname = "") const; + const PvlObject &findTable(const std::string &name, PvlObject &pvl) const; + void addKernels(const KernelSet &kset); + void loadKernel(PvlKeyword &key); + void loadKernelFromTable(PvlKeyword &key, const std::string &tblname, + Pvl &pvl); + +}; + +} // namespace Isis +#endif + + diff --git a/isis/src/messenger/apps/mdisddr/Makefile b/isis/src/messenger/apps/mdisddr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/messenger/apps/mdisddr/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/messenger/apps/mdisddr/mdisddr.cpp b/isis/src/messenger/apps/mdisddr/mdisddr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3d32f3098707c6d2d5711efc89d7a8cb59cea9a5 --- /dev/null +++ b/isis/src/messenger/apps/mdisddr/mdisddr.cpp @@ -0,0 +1,355 @@ +#include "Isis.h" + +#include +#include +#include +#include + +#include "UserInterface.h" +#include "Progress.h" +#include "Filename.h" +#include "iException.h" +#include "ProcessExportPds.h" +#include "Cube.h" +#include "Histogram.h" +#include "LineManager.h" +#include "OriginalLabel.h" +#include "PvlTranslationManager.h" +#include "BufferManager.h" +#include "LineManager.h" +#include "CollectorMap.h" +#include "Kernels.h" + +using namespace std; +using namespace Isis; + + +typedef CollectorMap BandMap; + +inline std::string Quote(const std::string &value, const char qChar = '"') { + if (value.empty()) return (value); + if (value[0] == qChar) return (value); + return (std::string(qChar+value+qChar)); + } + +inline double SetRound(double value, const int precision) { + double scale = pow(10.0, precision); + value = rint(value * scale) / scale; + return (value); +} + +inline void ValidateUnit(PvlKeyword &key, const std::string &kunit) { + PvlKeyword temp = key; + key.Clear(); + for (int i = 0 ; i < temp.Size() ; i++) { + try { + // If this works, check unit, otherwise an exception is thrown + (void) temp[i].ToDouble(); + string unit = temp.Unit(i); + if (unit.empty()) unit = kunit; + key.AddValue(temp[i],unit); + } + catch (...) { + key.AddValue(temp[i]); + } + } + return; + } + +inline void FixUnit(PvlObject &obj, const string &key, const string &unit) { + if (obj.HasKeyword(key, PvlObject::Traverse)) { + ValidateUnit(obj.FindKeyword(key, PvlObject::Traverse), unit); + } + return; +} + +inline void FixQuotes(PvlContainer &kcont, const string &value = "N/A") { + PvlContainer::PvlKeywordIterator kiter; + for (kiter = kcont.Begin() ; kiter != kcont.End() ; ++kiter) { + for (int nv = 0 ; nv < kiter->Size() ; nv++) { + if ((*kiter)[nv] == value) (*kiter)[nv] = Quote((*kiter)[nv]); + } + } +} + +inline void FixLabels(PvlObject &obj) { + // Current object-owned keywords + FixQuotes(obj); + + // Fix all nested objects + PvlObject::PvlObjectIterator o; + for (o = obj.BeginObject() ; o != obj.EndObject() ; ++o) { + FixLabels(*o); + } + + // Fix local groups + PvlObject::PvlGroupIterator g; + for (g = obj.BeginGroup() ; g != obj.EndGroup() ; ++g) { + FixQuotes(*g); + } + return; +} + +inline void WriteBand(ProcessExportPds &process, ofstream &out, + const std::string &fname, int band ) { + process.ClearInputCubes(); + (void) process.SetInputCube(fname,CubeAttributeInput("+"+iString(band))); + process.StartProcess(out); + return; +} + + +void IsisMain () { + const std::string mdisddr_program = "mdisddr"; + const std::string mdisddr_version = "1.0"; + const std::string mdisddr_revision = "$Revision: 1.1 $"; + const std::string mdisddr_runtime = Application::DateTime(); + const std::string dataSetID = "MESS-E/V/H-MDIS-6-DDR-GEOMDATA-V1.0"; + + UserInterface &ui = Application::GetUserInterface(); + Filename input(ui.GetFilename ("FROM")); + string to(""); + bool toEntered = ui.WasEntered("TO"); + if (toEntered) { + to = ui.GetAsString("TO"); + } + + string opath("."); // Set default to local directory + if (ui.WasEntered("OPATH")) { + opath = ui.GetString("OPATH"); + } + else { + ui.PutAsString("OPATH", opath); + } + + // Generate the image cube that phocube produces for the DDR data + Filename phoFile(input.Basename()+"_phocube", "cub"); + string pfile = phoFile.Expanded(); + string parameters = "FROM="+input.Expanded() + " TO="+pfile + + " LATITUDE=TRUE LONGITUDE=TRUE PHASE=TRUE EMISSION=TRUE INCIDENCE=TRUE"; + Isis::iApp->Exec("phocube", parameters); + + // Wrap a try clause so that if anything goes wrong below, we can remove + // the phocube file. + try { + Pvl phoLabel(pfile); + BandMap bandmap; + PvlKeyword bn = phoLabel.FindGroup("BandBin",Pvl::Traverse)["Name"]; + for (int i = 0 ; i < bn.Size() ; i++) { + bandmap.add(bn[i], i+1); + } + + // Set up the export. Note that the attributes selects 5 bands from the + // output of the phocube run. It doesn't matter at this time which 5 + // bands it is, just so that we have this established so the right labels + // and file size is created. + ProcessExportPds processPds; + (void) processPds.SetInputCube(pfile, CubeAttributeInput("+1-5") ); + + // Due to the nature of the phocube file, we cannot compute a histogram + // of the data (it includes lots of data we don't need). So we will + // fix the range to the expected well defined angle ranges. + double minmin = 0.0; + double maxmax = 0.0; + if ( ui.GetString("TYPE").compare("AUTOMATIC") == 0 ) { + minmin = -360.0; + maxmax = 360.0; + } else { + minmin = ui.GetDouble("MIN"); + maxmax = ui.GetDouble("MAX"); + } + + processPds.SetOutputEndian(Isis::Msb); + processPds.SetExportType( ProcessExportPds::Fixed ); + processPds.SetInputRange(minmin, maxmax); + + // Set the output pixel type and the special pixel values + processPds.SetOutputType(Real); + processPds.SetOutputRange(minmin, maxmax); + processPds.SetOutputNull(NULL4); + processPds.SetOutputLrs(LOW_REPR_SAT4); + processPds.SetOutputLis(LOW_INSTR_SAT4); + processPds.SetOutputHrs(HIGH_REPR_SAT4); + processPds.SetOutputHis(HIGH_INSTR_SAT4); + + Progress p; + p.SetText("Modifying Keywords"); + p.SetMaximumSteps(6); + p.CheckStatus(); + + // Get the PDS label from the process + Pvl &pdsLabel = processPds.StandardPdsLabel(ProcessExportPds::Image); + + // Translate the keywords from the original EDR PDS label that go in + // this DDR PDS label. Note that we have to open the original (FROM) + // cube as the phocube output goes into the specification of the + // output PDS file (required for 5 band IMAGE object). + Cube from; + from.Open(input.Expanded()); + OriginalLabel origBlob; + from.Read(origBlob); + Pvl origLabel; + PvlObject origLabelObj = origBlob.ReturnLabels(); + origLabelObj.SetName("OriginalLabelObject"); + origLabel.AddObject(origLabelObj); + p.CheckStatus(); + + // Translates the ISIS labels along with the original EDR labels + origLabel.AddObject(*from.Label()); + PvlTranslationManager labels( origLabel, + "$messenger/translations/mdisDDRLabel.trn"); + labels.Auto(pdsLabel); + p.CheckStatus(); + + // Add any new keywords + string lnote = "2007-12-20, S. Murchie (JHU/APL); " + "2008-01-02, S. Murchie (JHU/APL); " + "2008-01-11, J. Ward (GEO)"; + pdsLabel += PvlKeyword("LABEL_REVISION_NOTE", lnote); + pdsLabel += PvlKeyword("SPACECRAFT_NAME", Quote("MESSENGER")); + + // Fixes bad keywords + PvlKeyword &data_set_id = pdsLabel.FindKeyword( "DATA_SET_ID", Pvl::Traverse ); + data_set_id.SetValue( dataSetID ); + string prodid(input.Basename()); + PvlKeyword &product_id = pdsLabel.FindKeyword( "PRODUCT_ID", Pvl::Traverse ); + if ((product_id.Size() == 0) || ((product_id.Size() > 0) && (product_id[0] == "N/A"))) { + product_id.SetValue( prodid ); + } + else { + string pid = product_id[0]; + pid[0] = 'D'; + string::size_type pos = pid.find_first_of("_"); + if (pos != string::npos) { + pid.erase(pos); + } + pid.append("_DE_0"); + product_id.SetValue(pid); + prodid = pid; + } + + // Now we have enough to establish output file name + if (!toEntered) to = opath + "/" + prodid; + Filename output(to); + output.AddExtension("IMG"); + if (!toEntered) ui.PutFilename("TO", output.Expanded()); + + PvlKeyword &product_creation_time = pdsLabel.FindKeyword( "PRODUCT_CREATION_TIME", Pvl::Traverse ); + product_creation_time.SetValue( mdisddr_runtime ); + + PvlKeyword &software_name = pdsLabel.FindKeyword( "SOFTWARE_NAME", Pvl::Traverse ); + software_name.SetValue( mdisddr_program ); + + PvlKeyword &software_version_id = pdsLabel.FindKeyword( "SOFTWARE_VERSION_ID", Pvl::Traverse ); + software_version_id.SetValue( Quote(mdisddr_version) ); + + PvlKeyword &filter_number = pdsLabel.FindKeyword( "FILTER_NUMBER",Pvl::Traverse ); + if ( (filter_number.Size() > 0) ) { + filter_number.SetValue( Quote(filter_number[0]) ); + } + + + // Add quotes + PvlKeyword &data_quality_id = pdsLabel.FindKeyword( "DATA_QUALITY_ID", Pvl::Traverse ); + data_quality_id.SetValue(Quote(data_quality_id)); + PvlKeyword &sequence_name = pdsLabel.FindKeyword( "SEQUENCE_NAME", Pvl::Traverse ); + sequence_name.SetValue(Quote(sequence_name)); + PvlKeyword &start_count = pdsLabel.FindKeyword( "SPACECRAFT_CLOCK_START_COUNT", Pvl::Traverse ); + start_count.SetValue(Quote(start_count)); + PvlKeyword &stop_count = pdsLabel.FindKeyword( "SPACECRAFT_CLOCK_STOP_COUNT", Pvl::Traverse ); + stop_count.SetValue(Quote(stop_count)); + + // For DDRs, the SOURCE_PRODUCT_ID is made up of SPICE kernels. I need to + // go get em. + Kernels kernels(from); + Kernels::KernelFiles kfiles = kernels.getList(true); + PvlKeyword &source_product_id = pdsLabel.FindKeyword( "SOURCE_PRODUCT_ID", Pvl::Traverse ); + source_product_id.Clear(); + for ( unsigned int i = 0; i < kfiles.size(); i++ ) { + source_product_id.AddValue(Quote(kfiles[i])); + } + + // Enforce parentheses for scalars + if (source_product_id.Size() == 1) + source_product_id.SetValue('('+source_product_id[0]+')'); + + // Removes keywords + PvlObject imageObject( pdsLabel.FindObject("IMAGE") ); + if (imageObject.HasKeyword("CENTER_FILTER_WAVELENGTH")) imageObject.DeleteKeyword("CENTER_FILTER_WAVELENGTH"); + if (imageObject.HasKeyword("BANDWIDTH")) imageObject.DeleteKeyword("BANDWIDTH"); + if (imageObject.HasKeyword("UNIT")) imageObject.DeleteKeyword("UNIT"); + if (imageObject.HasKeyword("DARK_STRIP_MEAN")) imageObject.DeleteKeyword("DARK_STRIP_MEAN"); + if (imageObject.HasKeyword("OFFSET")) imageObject.DeleteKeyword("OFFSET"); + if (imageObject.HasKeyword("SCALING_FACTOR")) imageObject.DeleteKeyword("SCALING_FACTOR"); + if (imageObject.HasKeyword("SAMPLE_BIT_MASK")) imageObject.DeleteKeyword("SAMPLE_BIT_MASK"); + + // Add band names to image object + PvlKeyword &bandNames = imageObject.FindKeyword("FILTER_NAME"); + bandNames.SetName("BAND_NAME"); + bandNames.Clear(); + bandNames.AddValue("Latitude, planetocentric, deg N"); + bandNames.AddValue("Longitude, planetocentric, deg E"); + bandNames.AddValue("Incidence angle at equipotential surface, deg"); + bandNames.AddValue("Emission angle at equipotential surface, deg"); + bandNames.AddValue("Phase angle at equipotential surface, deg"); + pdsLabel.DeleteObject("IMAGE"); + pdsLabel.AddObject(imageObject); + + p.CheckStatus(); + + // Fix all the hosed units upon ingest. They are illformed. + FixUnit(pdsLabel, "RETICLE_POINT_RA", "DEG"); + FixUnit(pdsLabel, "RETICLE_POINT_DECLINATION", "DEG"); + FixUnit(pdsLabel, "RETICLE_POINT_LATITUDE", "DEG"); + FixUnit(pdsLabel, "RETICLE_POINT_LONGITUDE", "DEG"); + + // Now address nested keywords in SUBFRAME groups + for (int i = 1 ; i <= 5 ; i++) { + iString n(i); + string group = "SUBFRAME" + n + "_PARAMETERS"; + if (pdsLabel.HasGroup(group)) { + PvlGroup &grp = pdsLabel.FindGroup(group); + ValidateUnit(grp.FindKeyword("RETICLE_POINT_LATITUDE"), "DEG"); + ValidateUnit(grp.FindKeyword("RETICLE_POINT_LONGITUDE"), "DEG"); + } + } + p.CheckStatus(); + + + // Finally, fix keywords by Quoting missing N/A values + FixLabels(pdsLabel); + p.CheckStatus(); + + // All done...write result. + pdsLabel.SetFormatTemplate ("$messenger/templates/labels/mdisPdsDDR.pft"); + string ofile(output.Expanded()); + ofstream outstream( ofile.c_str() ); + processPds.OutputLabel(outstream); + + // Writing out the 5 bands is a bit tricky for this product. The bands + // must be ordered in a specific order, but phocube orders them in a + // different order. To make this approach work, determine the proper band + // as ordered in the phocube output and select the desired bands one at a + // time setting the input cube to the desired band and writing it out by + // stream. + + // Write latitude, longitude, incidence, emission, phase bands + WriteBand(processPds, outstream, pfile, bandmap.get("Latitude")); + WriteBand(processPds, outstream, pfile, bandmap.get("Longitude")); + WriteBand(processPds, outstream, pfile, bandmap.get("Incidence Angle")); + WriteBand(processPds, outstream, pfile, bandmap.get("Emission Angle")); + WriteBand(processPds, outstream, pfile, bandmap.get("Phase Angle")); + outstream.close(); + processPds.EndProcess(); + remove(pfile.c_str()); + } catch (iException &ie) { + remove(pfile.c_str()); + throw; + } + catch (...) { + remove(pfile.c_str()); + throw iException::Message(iException::None, "Unexpected exception caught!", + _FILEINFO_); + } + +} diff --git a/isis/src/messenger/apps/mdisddr/mdisddr.xml b/isis/src/messenger/apps/mdisddr/mdisddr.xml new file mode 100644 index 0000000000000000000000000000000000000000..0c19022520014fbf8b5e99cb10285652de94173f --- /dev/null +++ b/isis/src/messenger/apps/mdisddr/mdisddr.xml @@ -0,0 +1,192 @@ + + + + + + Creates a MESSENGER DDR PDS product from an MDIS image + + +

    + mdisddr will process a Messenger MDIS NAC or WAC image cube and + export it to PDS/DDR format. The resulting file will have a PDS + compliant label and data object according to the description in SIS + document, mdis_crd_rdrsis.pdf. This file can be found in the PDS data + archive CDROM under the document directory. + mdisddr assumes the input file has been run through at a minimum + mdis2isis and spiceinit. This will ensure that proper values of the + PRODUCT_ID and SOURCE_PRODUCT_ID are included in the output DDR + label. +

    +

    + The Derived Data Record (DDR) data set consists of files that parallel + CDRs in their directory structure. Each DDR has 5 layers of data + containing geometric information (latitude, longitude, incidence angle, + emission angle, phase angle) as 32-bit PC_REAL or IEEE_REAL. This + information is derived from pixel spatial coordinates and associated SPICE + files. A DDR label is attached and points to a single multiband image in + the DDR. x, y dimensions = 1024/(MESS:FPU_BIN * MESS:PIXELBIN) +

    +

    + The sequence of processing that creates a DDR is as follows. Gimbal + positions are extracted from the gimbal C kernel. Using that and other + SPICE kernels, the equipotential surface intercept is calculated for + each spatial pixel. The angles of this pixel relative to the + equatorial plane and reference longitude constitute the latitude and + longitude of the pixel. For that latitude and longitude, solar + incidence, emission, and phase angles are determined. This is the + order in which the bands are written to the output PDS image file. +

    +
    + + + + Original Version + + + Added additional documentation. + + + + + Messenger + + + + + + + cube + input + Input MESSENGER cube + + Input filename of a MESSENGER cube file to be exported into a PDS DDR + image. The minimum requirement is that it must be initalized with + SPICE (using the spiceinit application). + + *.cub + + + + filename + output + Derived + Name of output file + +

    + Output filename, by default the filename will be generated from the + input file contents using the PRODUCT_ID. The user can specify the + name if desired here, but to ensure consistancy with SIS + specifications, the name of the file will be derived by the program. + See the OPATH parameter for additional options of where the output + file will be written. +

    +

    + The format of the derived filename will be of the form + DN0131770878M_DE_0.IMG where 'D' indicates it is a derived data + product, the second letter will be 'N' for MDIS/NAC or 'W' for + MDIS/WAC instrument; the next ten characters will be numbers + indicating the mission elasped time (MET) of the image; the + following character is the filter - 'M' for monochrome or the + NAC, letters 'A' -'L' for WAC filters; the two characters after + the first underscore is always 'DE' indicating it is a derived + data type; and the last number after the second underscore is + the version number. The customary IMG extension is standard for + most all PDS image data products. +

    +
    +
    + + + string + Current + Path to write output DDR file to when TO is not given + + This parameter is provided to be used instead of the TO parameter if + the filename convention is to be followed. If TO is not given, then + output filename is derived internally according to the description in + the SIS and the output file is placed in the OPATH directory. The + default is to write it to the current directory. + + + +
    + + + + + string + AUTOMATIC + + Select the type of stretch + + + This parameter is used to select one of two ways to stretch output + pixels. The are AUTOMATIC or MANUAL. + + + + + + + + + double + + Lower bound of the stretch + + + Lower bound for the manually specified stretch. + + + + double + + Upper bound of the stretch + + + Upper bound for the manually specified stretch. + + + + + + + + integer + 32 + + Number of bits for the output DN + + + The number of bits to compress the input data to. The valid data as + well as the five special pixel values (NULL, LIS, LRS, HIS, HRS) will be + compressed into this number of bits. The output data type will be + automaticity choosen using this value. A value of 8 will create + unsigned byte output files. Values from 9 to 16 will create unsigned + word output files. Unused bits in the unsigned word output file will be + set to zero. + + 8 + 32 + + +
    +
    + diff --git a/isis/src/messenger/apps/mdisddr/resources/data/templates/labels/mdisPdsDDR.pft b/isis/src/messenger/apps/mdisddr/resources/data/templates/labels/mdisPdsDDR.pft new file mode 100644 index 0000000000000000000000000000000000000000..2f1e247d99078e460d4e5b667bf739783cd12455 --- /dev/null +++ b/isis/src/messenger/apps/mdisddr/resources/data/templates/labels/mdisPdsDDR.pft @@ -0,0 +1,216 @@ +PDS_VERSION_ID = PDS3 + +/*** FILE FORMAT ***/ +RECORD_TYPE +RECORD_BYTES +FILE_RECORDS +LABEL_RECORDS +LABEL_REVISION_NOTE = "2007-12-20, S. Murchie (JHU/APL); + 2008-01-02, S. Murchie (JHU/APL); + 2008-01-11, J. Ward (GEO)" + +/*** POINTERS TO START BYTE OFFSET OF OBJECTS IN IMAGE FILE ***/ +^IMAGE + +/*** GENERAL DATA DESCRIPTION PARAMETERS ***/ +MISSION_NAME +SPACECRAFT_NAME +INSTRUMENT_HOST_NAME +DATA_SET_ID +DATA_QUALITY_ID +/* pcnnnnnnnnnnf_tt_v */ +/* p = product type (C calibrated */ +/* or D derived) */ +/* c = camera (W WAC or N NAC) */ +/* nnnnnnnnnn = Mission Elapsed Time */ +/* f = filter */ +/* tt = data type (RA radiance, IF I/F, */ +/* or DE derived products) */ +/* v = version number */ +PRODUCT_ID +SOURCE_PRODUCT_ID +PRODUCER_INSTITUTION_NAME +SOFTWARE_NAME +SOFTWARE_VERSION_ID +MISSION_PHASE_NAME +TARGET_NAME +SEQUENCE_NAME + +/*** TIME PARAMETERS ***/ +START_TIME +STOP_TIME +SPACECRAFT_CLOCK_START_COUNT +SPACECRAFT_CLOCK_STOP_COUNT +PRODUCT_CREATION_TIME + +/*** INSTRUMENT ENGINEERING PARAMETERS ***/ +INSTRUMENT_NAME +INSTRUMENT_ID +FILTER_NAME +FILTER_NUMBER +CENTER_FILTER_WAVELENGTH +BANDWIDTH +EXPOSURE_DURATION +EXPOSURE_TYPE +DETECTOR_TEMPERATURE +FOCAL_PLANE_TEMPERATURE +FILTER_TEMPERATURE +OPTICS_TEMPERATURE + +/*** INSTRUMENT RAW PARAMETERS ***/ +MESS:MET_EXP +MESS:ATT_CLOCK_COUNT +MESS:ATT_Q1 +MESS:ATT_Q2 +MESS:ATT_Q3 +MESS:ATT_Q4 +MESS:ATT_FLAG +MESS:PIV_GOAL +MESS:PIV_POS +MESS:PIV_READ +MESS:PIV_CAL +MESS:FW_GOAL +MESS:FW_POS +MESS:FW_READ +MESS:CCD_TEMP +MESS:CAM_T1 +MESS:CAM_T2 +MESS:EXPOSURE +MESS:DPU_ID +MESS:IMAGER +MESS:SOURCE +MESS:FPU_BIN +MESS:COMP12_8 +MESS:COMP_ALG +MESS:COMP_FST +MESS:TIME_PLS +MESS:LATCH_UP +MESS:EXP_MODE +MESS:PIV_STAT +MESS:PIV_MPEN +MESS:PIV_PV +MESS:PIV_RV +MESS:FW_PV +MESS:FW_RV +MESS:AEX_STAT +MESS:AEX_STHR +MESS:AEX_TGTB +MESS:AEX_BACB +MESS:AEX_MAXE +MESS:AEX_MINE +MESS:DLNKPRIO +MESS:WVLRATIO +MESS:PIXELBIN +MESS:SUBFRAME +MESS:SUBF_X1 +MESS:SUBF_Y1 +MESS:SUBF_DX1 +MESS:SUBF_DY1 +MESS:SUBF_X2 +MESS:SUBF_Y2 +MESS:SUBF_DX2 +MESS:SUBF_DY2 +MESS:SUBF_X3 +MESS:SUBF_Y3 +MESS:SUBF_DX3 +MESS:SUBF_DY3 +MESS:SUBF_X4 +MESS:SUBF_Y4 +MESS:SUBF_DX4 +MESS:SUBF_DY4 +MESS:SUBF_X5 +MESS:SUBF_Y5 +MESS:SUBF_DX5 +MESS:SUBF_DY5 +MESS:CRITOPNV +MESS:JAILBARS +MESS:JB_X0 +MESS:JB_X1 +MESS:JB_SPACE + +/*** GEOMETRY INFORMATION ***/ +RIGHT_ASCENSION +DECLINATION +TWIST_ANGLE +RA_DEC_REF_PIXEL +RETICLE_POINT_RA +RETICLE_POINT_DECLINATION + +/*** TARGET PARAMETERS ***/ +SC_TARGET_POSITION_VECTOR +TARGET_CENTER_DISTANCE + +/*** TARGET WITHIN SENSOR FOV ***/ +SLANT_DISTANCE +CENTER_LATITUDE +CENTER_LONGITUDE +HORIZONTAL_PIXEL_SCALE +VERTICAL_PIXEL_SCALE +SMEAR_MAGNITUDE +SMEAR_AZIMUTH +NORTH_AZIMUTH +RETICLE_POINT_LATITUDE +RETICLE_POINT_LONGITUDE + +/*** SPACECRAFT POSITION WITH RESPECT TO CENTRAL BODY ***/ +SUB_SPACECRAFT_LATITUDE +SUB_SPACECRAFT_LONGITUDE +SPACECRAFT_ALTITUDE +SUB_SPACECRAFT_AZIMUTH + +/*** SPACECRAFT LOCATION ***/ +SPACECRAFT_SOLAR_DISTANCE +SC_SUN_POSITION_VECTOR +SC_SUN_VELOCITY_VECTOR + +/*** VIEWING AND LIGHTING GEOMETRY (SUN ON TARGET) ***/ +SOLAR_DISTANCE +SUB_SOLAR_AZIMUTH +SUB_SOLAR_LATITUDE +SUB_SOLAR_LONGITUDE +INCIDENCE_ANGLE +PHASE_ANGLE +EMISSION_ANGLE +LOCAL_HOUR_ANGLE + +/*** GEOMETRY FOR EACH SUBFRAME ***/ +GROUP = SUBFRAME1_PARAMETERS + RETICLE_POINT_LATITUDE + RETICLE_POINT_LONGITUDE +END_GROUP = SUBFRAME1_PARAMETERS + +GROUP = SUBFRAME2_PARAMETERS + RETICLE_POINT_LATITUDE + RETICLE_POINT_LONGITUDE +END_GROUP = SUBFRAME2_PARAMETERS + +GROUP = SUBFRAME3_PARAMETERS + RETICLE_POINT_LATITUDE + RETICLE_POINT_LONGITUDE +END_GROUP = SUBFRAME3_PARAMETERS + +GROUP = SUBFRAME4_PARAMETERS + RETICLE_POINT_LATITUDE + RETICLE_POINT_LONGITUDE +END_GROUP = SUBFRAME4_PARAMETERS + +GROUP = SUBFRAME5_PARAMETERS + RETICLE_POINT_LATITUDE + RETICLE_POINT_LONGITUDE +END_GROUP = SUBFRAME5_PARAMETERS + +OBJECT = IMAGE + LINES + LINE_SAMPLES + SAMPLE_TYPE + SAMPLE_BITS + BANDS + BAND_STORAGE_TYPE + BAND_NAME + CORE_NULL + CORE_LOW_REPR_SATURATION + CORE_LOW_INSTR_SATURATION + CORE_HIGH_REPR_SATURATION + CORE_HIGH_INSTR_SATURATION +END_OBJECT = IMAGE +END diff --git a/isis/src/messenger/apps/mdisddr/resources/data/translations/mdisDDRLabel.trn b/isis/src/messenger/apps/mdisddr/resources/data/translations/mdisDDRLabel.trn new file mode 100644 index 0000000000000000000000000000000000000000..f2cf17d079ed3ba1e796ffcd4154d78f972c115b --- /dev/null +++ b/isis/src/messenger/apps/mdisddr/resources/data/translations/mdisDDRLabel.trn @@ -0,0 +1,1308 @@ +#Base + +Group = SpacecraftName + Auto + OutputName = MISSION_NAME + OutputPosition = (Root) + InputGroup = Root,IsisCube,Instrument + InputKey = SpacecraftName + Translation = ('"MESSENGER"',"Messenger") + Translation = (*,*) +EndGroup + +Group = INSTRUMENT_HOST_NAME + Auto + OutputName = INSTRUMENT_HOST_NAME + OutputPosition = ("ROOT") + InputKey = INSTRUMENT_HOST_NAME + InputGroup = OriginalLabelObject + Translation = ('"MESSENGER"',"MESSENGER") + Translation = (*,*) +EndGroup + +Group = DataSetId + Auto + OutputName = DATA_SET_ID + OutputPosition = (Root) + InputGroup = Root,IsisCube,Archive + InputKey = DataSetId + Translation = (*,*) +EndGroup + +Group = DataQualityId + Auto + OutputName = DATA_QUALITY_ID + OutputPosition = (Root) + InputGroup = Root,IsisCube,Archive + InputKey = DataQualityId + Translation = (*,*) +EndGroup + +Group = ProductId + Auto + OutputName = PRODUCT_ID + OutputPosition = (Root) + InputGroup = Root,IsisCube,Archive + InputKey = ProductId + Translation = (*,*) + InputDefault = "N/A" +EndGroup + +Group = SOURCE_PRODUCT_ID + Auto + OutputName = SOURCE_PRODUCT_ID + OutputPosition = (Root) + InputKey = SOURCE_PRODUCT_ID + InputGroup = Root,IsisCube,Archive + Translation = (*,*) + InputDefault = N/A +EndGroup + +Group = ProducerId + Auto + OutputName = PRODUCER_INSTITUTION_NAME + OutputPosition = (Root) + InputGroup = Root,IsisCube,Archive + InputKey = ProducerId + Translation = (*,*) +EndGroup + +Group = SOFTWARE_NAME + Auto + OutputName = SOFTWARE_NAME + OutputPosition = (Root) + InputGroup = Root,IsisCube,RadiometricCalibration + InputKey = SoftwareName + Translation = (*,*) + InputDefault = N/A +EndGroup + +Group = SOFTWARE_VERSION_ID + Auto + OutputName = SOFTWARE_VERSION_ID + OutputPosition = (Root) + InputGroup = Root,IsisCube,RadiometricCalibration + InputKey = SOFTWARE_VERSION_ID + Translation = (*,*) + InputDefault = "N/A" +EndGroup + +Group = MissionPhaseName + Auto + OutputName = MISSION_PHASE_NAME + OutputPosition = (Root) + InputGroup = Root,IsisCube,Instrument + InputKey = MissionPhaseName + Translation = (*,*) +EndGroup + +Group = TARGET_NAME + Auto + OutputName = TARGET_NAME + OutputPosition = (Root) + InputGroup = OriginalLabelObject + InputKey = TARGET_NAME + Translation = (*,*) +EndGroup + +Group = SEQUENCE_NAME + Auto + OutputName = SEQUENCE_NAME + OutputPosition = ("ROOT") + InputKey = SEQUENCE_NAME + InputGroup = OriginalLabelObject + Translation = (*,*) + InputDefault = N/A +EndGroup + +# Times + +Group = StartTime + Auto + OutputName = START_TIME + OutputPosition = (Root) + InputGroup = Root,IsisCube,Instrument + InputKey = StartTime + Translation = (*,*) +EndGroup + +Group = StopTime + Auto + OutputName = STOP_TIME + OutputPosition = (Root) + InputGroup = Root,IsisCube,Instrument + InputKey = StopTime + Translation = (*,*) +EndGroup + +Group = SpacecraftClockStartCount + Auto + OutputName = SPACECRAFT_CLOCK_START_COUNT + OutputPosition = (Root) + InputGroup = Root,IsisCube,Archive + InputKey = SpacecraftClockStartCount + Translation = (*,*) +EndGroup + +Group = SpacecraftClockStopCount + Auto + OutputName = SPACECRAFT_CLOCK_STOP_COUNT + OutputPosition = (Root) + InputGroup = Root,IsisCube,Archive + InputKey = SpacecraftClockStopCount + Translation = (*,*) +EndGroup + +Group = EdrProductCreationTime + Auto + OutputName = PRODUCT_CREATION_TIME + OutputPosition = (Root) + InputGroup = Root,IsisCube,Archive + InputKey = EdrProductCreationTime + Translation = (*,*) +EndGroup + +# Instrument + +Group = InstrumentName + Auto + OutputName = INSTRUMENT_NAME + OutputPosition = (Root) + InputGroup = Root,IsisCube,Instrument + InputKey = InstrumentName + Translation = (*,*) +EndGroup + +Group = InstrumentId + Auto + OutputName = INSTRUMENT_ID + OutputPosition = (Root) + InputGroup = Root,IsisCube,Instrument + InputKey = InstrumentId + Translation = (*,*) +EndGroup + +Group = FILTER_NAME + Auto + OutputName = FILTER_NAME + OutputPosition = (Root) + InputGroup = Root,IsisCube,BandBin + InputKey = Name + Translation = (*,*) +EndGroup + +Group = FILTER_NUMBER + Auto + OutputName = FILTER_NUMBER + OutputPosition = (Root) + InputGroup = OriginalLabelObject + InputKey = FILTER_NUMBER +# Translation = (N/A, 0) + Translation = (*,*) +# InputDefault = N/A +EndGroup + +Group = CENTER_FILTER_WAVELENGTH + Auto + OutputName = CENTER_FILTER_WAVELENGTH + OutputPosition = (Root) + InputGroup = Root,IsisCube,BandBin + InputKey = Center + Translation = (*,*) +EndGroup + +Group = FilterWidth + Auto + OutputName = BANDWIDTH + OutputPosition = (Root) + InputGroup = Root,IsisCube,BandBin + InputKey = Width +# Translation = (N/A, 50) + Translation = (*,*) +EndGroup + +Group = ExposureDuration + Auto + OutputName = EXPOSURE_DURATION + OutputPosition = (Root) + InputGroup = Root,IsisCube,Instrument + InputKey = ExposureDuration + Translation = (*,*) + InputDefault = N/A +EndGroup + +Group = ExposureType + Auto + OutputName = EXPOSURE_TYPE + OutputPosition = (Root) + InputKey = ExposureType + InputGroup = Root,IsisCube,Instrument + Translation = ("MANUAL", "Manual") + Translation = ("AUTOMATIC", "Automatic") + Translation = (*,*) + InputDefault = UNKNOWN +EndGroup + +Group = Units + Auto + OutputName = UNIT + OutputPosition = ("Object","IMAGE") + InputGroup = Root,IsisCube,RadiometricCalibration + InputKey = Units + Translation = (*,*) + InputDefault = N/A +EndGroup + +Group = DarkStripMean + Auto + OutputName = DARK_STRIP_MEAN + OutputPosition = ("Object","IMAGE") + InputGroup = Root,IsisCube,RadiometricCalibration + InputKey = DarkStripMean + Translation = (*,*) + InputDefault = "N/A" +EndGroup + +Group = DETECTOR_TEMPERATURE + Auto + OutputName = DETECTOR_TEMPERATURE + OutputPosition = ("ROOT") + InputKey = DETECTOR_TEMPERATURE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = FOCAL_PLANE_TEMPERATURE + Auto + OutputName = FOCAL_PLANE_TEMPERATURE + OutputPosition = ("ROOT") + InputKey = FOCAL_PLANE_TEMPERATURE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = FILTER_TEMPERATURE + Auto + OutputName = FILTER_TEMPERATURE + OutputPosition = ("ROOT") + InputKey = FILTER_TEMPERATURE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = OPTICS_TEMPERATURE + Auto + OutputName = OPTICS_TEMPERATURE + OutputPosition = ("ROOT") + InputKey = OPTICS_TEMPERATURE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:MET_EXP + Auto + OutputName = MESS:MET_EXP + OutputPosition = ("ROOT") + InputKey = MESS:MET_EXP + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:ATT_CLOCK_COUNT + Auto + OutputName = MESS:ATT_CLOCK_COUNT + OutputPosition = ("ROOT") + InputKey = MESS:ATT_CLOCK_COUNT + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:ATT_Q1 + Auto + OutputName = MESS:ATT_Q1 + OutputPosition = ("ROOT") + InputKey = MESS:ATT_Q1 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:ATT_Q2 + Auto + OutputName = MESS:ATT_Q2 + OutputPosition = ("ROOT") + InputKey = MESS:ATT_Q2 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:ATT_Q3 + Auto + OutputName = MESS:ATT_Q3 + OutputPosition = ("ROOT") + InputKey = MESS:ATT_Q3 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:ATT_Q4 + Auto + OutputName = MESS:ATT_Q4 + OutputPosition = ("ROOT") + InputKey = MESS:ATT_Q4 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:ATT_FLAG + Auto + OutputName = MESS:ATT_FLAG + OutputPosition = ("ROOT") + InputKey = MESS:ATT_FLAG + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:PIV_GOAL + Auto + OutputName = MESS:PIV_GOAL + OutputPosition = ("ROOT") + InputKey = MESS:PIV_GOAL + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:PIV_POS + Auto + OutputName = MESS:PIV_POS + OutputPosition = ("ROOT") + InputKey = MESS:PIV_POS + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:PIV_READ + Auto + OutputName = MESS:PIV_READ + OutputPosition = ("ROOT") + InputKey = MESS:PIV_READ + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:PIV_CAL + Auto + OutputName = MESS:PIV_CAL + OutputPosition = ("ROOT") + InputKey = MESS:PIV_CAL + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:FW_GOAL + Auto + OutputName = MESS:FW_GOAL + OutputPosition = ("ROOT") + InputKey = MESS:FW_GOAL + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:FW_POS + Auto + OutputName = MESS:FW_POS + OutputPosition = ("ROOT") + InputKey = MESS:FW_POS + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:FW_READ + Auto + OutputName = MESS:FW_READ + OutputPosition = ("ROOT") + InputKey = MESS:FW_READ + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:CCD_TEMP + Auto + OutputName = MESS:CCD_TEMP + OutputPosition = ("ROOT") + InputKey = MESS:CCD_TEMP + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:CAM_T1 + Auto + OutputName = MESS:CAM_T1 + OutputPosition = ("ROOT") + InputKey = MESS:CAM_T1 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:CAM_T2 + Auto + OutputName = MESS:CAM_T2 + OutputPosition = ("ROOT") + InputKey = MESS:CAM_T2 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:EXPOSURE + Auto + OutputName = MESS:EXPOSURE + OutputPosition = ("ROOT") + InputKey = MESS:EXPOSURE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:DPU_ID + Auto + OutputName = MESS:DPU_ID + OutputPosition = ("ROOT") + InputKey = MESS:DPU_ID + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:IMAGER + Auto + OutputName = MESS:IMAGER + OutputPosition = ("ROOT") + InputKey = MESS:IMAGER + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SOURCE + Auto + OutputName = MESS:SOURCE + OutputPosition = ("ROOT") + InputKey = MESS:SOURCE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:FPU_BIN + Auto + OutputName = MESS:FPU_BIN + OutputPosition = ("ROOT") + InputKey = MESS:FPU_BIN + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:COMP12_8 + Auto + OutputName = MESS:COMP12_8 + OutputPosition = ("ROOT") + InputKey = MESS:COMP12_8 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:COMP_ALG + Auto + OutputName = MESS:COMP_ALG + OutputPosition = ("ROOT") + InputKey = MESS:COMP_ALG + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:COMP_FST + Auto + OutputName = MESS:COMP_FST + OutputPosition = ("ROOT") + InputKey = MESS:COMP_FST + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:TIME_PLS + Auto + OutputName = MESS:TIME_PLS + OutputPosition = ("ROOT") + InputKey = MESS:TIME_PLS + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:LATCH_UP + Auto + OutputName = MESS:LATCH_UP + OutputPosition = ("ROOT") + InputKey = MESS:LATCH_UP + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:EXP_MODE + Auto + OutputName = MESS:EXP_MODE + OutputPosition = ("ROOT") + InputKey = MESS:EXP_MODE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:PIV_STAT + Auto + OutputName = MESS:PIV_STAT + OutputPosition = ("ROOT") + InputKey = MESS:PIV_STAT + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:PIV_MPEN + Auto + OutputName = MESS:PIV_MPEN + OutputPosition = ("ROOT") + InputKey = MESS:PIV_MPEN + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:PIV_PV + Auto + OutputName = MESS:PIV_PV + OutputPosition = ("ROOT") + InputKey = MESS:PIV_PV + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:PIV_RV + Auto + OutputName = MESS:PIV_RV + OutputPosition = ("ROOT") + InputKey = MESS:PIV_RV + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:FW_PV + Auto + OutputName = MESS:FW_PV + OutputPosition = ("ROOT") + InputKey = MESS:FW_PV + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:FW_RV + Auto + OutputName = MESS:FW_RV + OutputPosition = ("ROOT") + InputKey = MESS:FW_RV + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:AEX_STAT + Auto + OutputName = MESS:AEX_STAT + OutputPosition = ("ROOT") + InputKey = MESS:AEX_STAT + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:AEX_STHR + Auto + OutputName = MESS:AEX_STHR + OutputPosition = ("ROOT") + InputKey = MESS:AEX_STHR + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:AEX_TGTB + Auto + OutputName = MESS:AEX_TGTB + OutputPosition = ("ROOT") + InputKey = MESS:AEX_TGTB + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:AEX_BACB + Auto + OutputName = MESS:AEX_BACB + OutputPosition = ("ROOT") + InputKey = MESS:AEX_BACB + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:AEX_MAXE + Auto + OutputName = MESS:AEX_MAXE + OutputPosition = ("ROOT") + InputKey = MESS:AEX_MAXE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:AEX_MINE + Auto + OutputName = MESS:AEX_MINE + OutputPosition = ("ROOT") + InputKey = MESS:AEX_MINE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:DLNKPRIO + Auto + OutputName = MESS:DLNKPRIO + OutputPosition = ("ROOT") + InputKey = MESS:DLNKPRIO + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:WVLRATIO + Auto + OutputName = MESS:WVLRATIO + OutputPosition = ("ROOT") + InputKey = MESS:WVLRATIO + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:PIXELBIN + Auto + OutputName = MESS:PIXELBIN + OutputPosition = ("ROOT") + InputKey = MESS:PIXELBIN + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBFRAME + Auto + OutputName = MESS:SUBFRAME + OutputPosition = ("ROOT") + InputKey = MESS:SUBFRAME + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_X1 + Auto + OutputName = MESS:SUBF_X1 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_X1 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_Y1 + Auto + OutputName = MESS:SUBF_Y1 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_Y1 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_DX1 + Auto + OutputName = MESS:SUBF_DX1 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_DX1 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_DY1 + Auto + OutputName = MESS:SUBF_DY1 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_DY1 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_X2 + Auto + OutputName = MESS:SUBF_X2 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_X2 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_Y2 + Auto + OutputName = MESS:SUBF_Y2 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_Y2 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_DX2 + Auto + OutputName = MESS:SUBF_DX2 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_DX2 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_DY2 + Auto + OutputName = MESS:SUBF_DY2 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_DY2 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_X3 + Auto + OutputName = MESS:SUBF_X3 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_X3 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_Y3 + Auto + OutputName = MESS:SUBF_Y3 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_Y3 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_DX3 + Auto + OutputName = MESS:SUBF_DX3 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_DX3 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_DY3 + Auto + OutputName = MESS:SUBF_DY3 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_DY3 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_X4 + Auto + OutputName = MESS:SUBF_X4 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_X4 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_Y4 + Auto + OutputName = MESS:SUBF_Y4 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_Y4 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_DX4 + Auto + OutputName = MESS:SUBF_DX4 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_DX4 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_DY4 + Auto + OutputName = MESS:SUBF_DY4 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_DY4 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_X5 + Auto + OutputName = MESS:SUBF_X5 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_X5 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_Y5 + Auto + OutputName = MESS:SUBF_Y5 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_Y5 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_DX5 + Auto + OutputName = MESS:SUBF_DX5 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_DX5 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:SUBF_DY5 + Auto + OutputName = MESS:SUBF_DY5 + OutputPosition = ("ROOT") + InputKey = MESS:SUBF_DY5 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:CRITOPNV + Auto + OutputName = MESS:CRITOPNV + OutputPosition = ("ROOT") + InputKey = MESS:CRITOPNV + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:JAILBARS + Auto + OutputName = MESS:JAILBARS + OutputPosition = ("ROOT") + InputKey = MESS:JAILBARS + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:JB_X0 + Auto + OutputName = MESS:JB_X0 + OutputPosition = ("ROOT") + InputKey = MESS:JB_X0 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:JB_X1 + Auto + OutputName = MESS:JB_X1 + OutputPosition = ("ROOT") + InputKey = MESS:JB_X1 + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = MESS:JB_SPACE + Auto + OutputName = MESS:JB_SPACE + OutputPosition = ("ROOT") + InputKey = MESS:JB_SPACE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = RIGHT_ASCENSION + Auto + OutputName = RIGHT_ASCENSION + OutputPosition = ("ROOT") + InputKey = RIGHT_ASCENSION + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = DECLINATION + Auto + OutputName = DECLINATION + OutputPosition = ("ROOT") + InputKey = DECLINATION + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = TWIST_ANGLE + Auto + OutputName = TWIST_ANGLE + OutputPosition = ("ROOT") + InputKey = TWIST_ANGLE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = RA_DEC_REF_PIXEL + Auto + OutputName = RA_DEC_REF_PIXEL + OutputPosition = ("ROOT") + InputKey = RA_DEC_REF_PIXEL + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = RETICLE_POINT_RA + Auto + OutputName = RETICLE_POINT_RA + OutputPosition = ("ROOT") + InputKey = RETICLE_POINT_RA + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = RETICLE_POINT_DECLINATION + Auto + OutputName = RETICLE_POINT_DECLINATION + OutputPosition = ("ROOT") + InputKey = RETICLE_POINT_DECLINATION + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SC_TARGET_POSITION_VECTOR + Auto + OutputName = SC_TARGET_POSITION_VECTOR + OutputPosition = ("ROOT") + InputKey = SC_TARGET_POSITION_VECTOR + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = TARGET_CENTER_DISTANCE + Auto + OutputName = TARGET_CENTER_DISTANCE + OutputPosition = ("ROOT") + InputKey = TARGET_CENTER_DISTANCE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SLANT_DISTANCE + Auto + OutputName = SLANT_DISTANCE + OutputPosition = ("ROOT") + InputKey = SLANT_DISTANCE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = CENTER_LATITUDE + Auto + OutputName = CENTER_LATITUDE + OutputPosition = ("ROOT") + InputKey = CENTER_LATITUDE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = CENTER_LONGITUDE + Auto + OutputName = CENTER_LONGITUDE + OutputPosition = ("ROOT") + InputKey = CENTER_LONGITUDE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = HORIZONTAL_PIXEL_SCALE + Auto + OutputName = HORIZONTAL_PIXEL_SCALE + OutputPosition = ("ROOT") + InputKey = HORIZONTAL_PIXEL_SCALE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = VERTICAL_PIXEL_SCALE + Auto + OutputName = VERTICAL_PIXEL_SCALE + OutputPosition = ("ROOT") + InputKey = VERTICAL_PIXEL_SCALE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SMEAR_MAGNITUDE + Auto + OutputName = SMEAR_MAGNITUDE + OutputPosition = ("ROOT") + InputKey = SMEAR_MAGNITUDE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SMEAR_AZIMUTH + Auto + OutputName = SMEAR_AZIMUTH + OutputPosition = ("ROOT") + InputKey = SMEAR_AZIMUTH + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = NORTH_AZIMUTH + Auto + OutputName = NORTH_AZIMUTH + OutputPosition = ("ROOT") + InputKey = NORTH_AZIMUTH + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = RETICLE_POINT_LATITUDE + Auto + OutputName = RETICLE_POINT_LATITUDE + OutputPosition = ("ROOT") + InputKey = RETICLE_POINT_LATITUDE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = RETICLE_POINT_LONGITUDE + Auto + OutputName = RETICLE_POINT_LONGITUDE + OutputPosition = ("ROOT") + InputKey = RETICLE_POINT_LONGITUDE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SUB_SPACECRAFT_LATITUDE + Auto + OutputName = SUB_SPACECRAFT_LATITUDE + OutputPosition = ("ROOT") + InputKey = SUB_SPACECRAFT_LATITUDE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SUB_SPACECRAFT_LONGITUDE + Auto + OutputName = SUB_SPACECRAFT_LONGITUDE + OutputPosition = ("ROOT") + InputKey = SUB_SPACECRAFT_LONGITUDE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SPACECRAFT_ALTITUDE + Auto + OutputName = SPACECRAFT_ALTITUDE + OutputPosition = ("ROOT") + InputKey = SPACECRAFT_ALTITUDE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SUB_SPACECRAFT_AZIMUTH + Auto + OutputName = SUB_SPACECRAFT_AZIMUTH + OutputPosition = ("ROOT") + InputKey = SUB_SPACECRAFT_AZIMUTH + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SPACECRAFT_SOLAR_DISTANCE + Auto + OutputName = SPACECRAFT_SOLAR_DISTANCE + OutputPosition = ("ROOT") + InputKey = SPACECRAFT_SOLAR_DISTANCE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SC_SUN_POSITION_VECTOR + Auto + OutputName = SC_SUN_POSITION_VECTOR + OutputPosition = ("ROOT") + InputKey = SC_SUN_POSITION_VECTOR + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SC_SUN_VELOCITY_VECTOR + Auto + OutputName = SC_SUN_VELOCITY_VECTOR + OutputPosition = ("ROOT") + InputKey = SC_SUN_VELOCITY_VECTOR + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SOLAR_DISTANCE + Auto + OutputName = SOLAR_DISTANCE + OutputPosition = ("ROOT") + InputKey = SOLAR_DISTANCE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SUB_SOLAR_AZIMUTH + Auto + OutputName = SUB_SOLAR_AZIMUTH + OutputPosition = ("ROOT") + InputKey = SUB_SOLAR_AZIMUTH + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SUB_SOLAR_LATITUDE + Auto + OutputName = SUB_SOLAR_LATITUDE + OutputPosition = ("ROOT") + InputKey = SUB_SOLAR_LATITUDE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SUB_SOLAR_LONGITUDE + Auto + OutputName = SUB_SOLAR_LONGITUDE + OutputPosition = ("ROOT") + InputKey = SUB_SOLAR_LONGITUDE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = INCIDENCE_ANGLE + Auto + OutputName = INCIDENCE_ANGLE + OutputPosition = ("ROOT") + InputKey = INCIDENCE_ANGLE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = PHASE_ANGLE + Auto + OutputName = PHASE_ANGLE + OutputPosition = ("ROOT") + InputKey = PHASE_ANGLE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = EMISSION_ANGLE + Auto + OutputName = EMISSION_ANGLE + OutputPosition = ("ROOT") + InputKey = EMISSION_ANGLE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = LOCAL_HOUR_ANGLE + Auto + OutputName = LOCAL_HOUR_ANGLE + OutputPosition = ("ROOT") + InputKey = LOCAL_HOUR_ANGLE + InputGroup = OriginalLabelObject + Translation = (*,*) +EndGroup + +Group = SUBFRAME1_PARAMETERS + Auto + OutputName = RETICLE_POINT_LATITUDE + OutputPosition = ("Group","SUBFRAME1_PARAMETERS") + InputKey = RETICLE_POINT_LATITUDE + InputGroup = OriginalLabelObject,SUBFRAME1_PARAMETERS + Translation = (*,*) +EndGroup + +Group = SUBFRAME1_PARAMETERS2 + Auto + OutputName = RETICLE_POINT_LONGITUDE + OutputPosition = ("Group","SUBFRAME1_PARAMETERS") + InputKey = RETICLE_POINT_LONGITUDE + InputGroup = OriginalLabelObject,SUBFRAME1_PARAMETERS + Translation = (*,*) +EndGroup + +Group = SUBFRAME2_PARAMETERS + Auto + OutputName = RETICLE_POINT_LATITUDE + OutputPosition = ("Group","SUBFRAME2_PARAMETERS") + InputKey = RETICLE_POINT_LATITUDE + InputGroup = OriginalLabelObject,SUBFRAME2_PARAMETERS + Translation = (*,*) +EndGroup + +Group = SUBFRAME2_PARAMETERS2 + Auto + OutputName = RETICLE_POINT_LONGITUDE + OutputPosition = ("Group","SUBFRAME2_PARAMETERS") + InputKey = RETICLE_POINT_LONGITUDE + InputGroup = OriginalLabelObject,SUBFRAME2_PARAMETERS + Translation = (*,*) +EndGroup + +Group = SUBFRAME3_PARAMETERS + Auto + OutputName = RETICLE_POINT_LATITUDE + OutputPosition = ("Group","SUBFRAME3_PARAMETERS") + InputKey = RETICLE_POINT_LATITUDE + InputGroup = OriginalLabelObject,SUBFRAME3_PARAMETERS + Translation = (*,*) +EndGroup + +Group = SUBFRAME3_PARAMETERS2 + Auto + OutputName = RETICLE_POINT_LONGITUDE + OutputPosition = ("Group","SUBFRAME3_PARAMETERS") + InputKey = RETICLE_POINT_LONGITUDE + InputGroup = OriginalLabelObject,SUBFRAME3_PARAMETERS + Translation = (*,*) +EndGroup + +Group = SUBFRAME4_PARAMETERS + Auto + OutputName = RETICLE_POINT_LATITUDE + OutputPosition = ("Group","SUBFRAME4_PARAMETERS") + InputKey = RETICLE_POINT_LATITUDE + InputGroup = OriginalLabelObject,SUBFRAME4_PARAMETERS + Translation = (*,*) +EndGroup + +Group = SUBFRAME4_PARAMETERS2 + Auto + OutputName = RETICLE_POINT_LONGITUDE + OutputPosition = ("Group","SUBFRAME4_PARAMETERS") + InputKey = RETICLE_POINT_LONGITUDE + InputGroup = OriginalLabelObject,SUBFRAME4_PARAMETERS + Translation = (*,*) +EndGroup + +Group = SUBFRAME5_PARAMETERS + Auto + OutputName = RETICLE_POINT_LATITUDE + OutputPosition = ("Group","SUBFRAME5_PARAMETERS") + InputKey = RETICLE_POINT_LATITUDE + InputGroup = OriginalLabelObject,SUBFRAME5_PARAMETERS + Translation = (*,*) +EndGroup + +Group = SUBFRAME5_PARAMETERS2 + Auto + OutputName = RETICLE_POINT_LONGITUDE + OutputPosition = ("Group","SUBFRAME5_PARAMETERS") + InputKey = RETICLE_POINT_LONGITUDE + InputGroup = OriginalLabelObject,SUBFRAME5_PARAMETERS + Translation = (*,*) +EndGroup diff --git a/isis/src/messenger/apps/mdisddr/tsts/Makefile b/isis/src/messenger/apps/mdisddr/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/messenger/apps/mdisddr/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/messenger/apps/mdisddr/tsts/NAC/Makefile b/isis/src/messenger/apps/mdisddr/tsts/NAC/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9e5f6f2fa8f5614f23482380601838604513bcb8 --- /dev/null +++ b/isis/src/messenger/apps/mdisddr/tsts/NAC/Makefile @@ -0,0 +1,15 @@ +APPNAME = mdisddr + +output.cub.TOLERANCE = 0.0000002 +output.pvl.IGNORELINES = PRODUCT_CREATION_TIME + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/EN0131770878M.cal.cub \ + to=$(OUTPUT)/output > /dev/null; + catlab from=$(OUTPUT)/output.IMG \ + to=$(OUTPUT)/output.pvl > /dev/null; + pds2isis from=$(OUTPUT)/output.IMG \ + to=$(OUTPUT)/output > /dev/null; + $(RM) $(OUTPUT)/output.IMG; diff --git a/isis/src/messenger/apps/mdisddr/tsts/WAC/Makefile b/isis/src/messenger/apps/mdisddr/tsts/WAC/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a7255f2f10d3e9d71463c7ef35180027d581f56e --- /dev/null +++ b/isis/src/messenger/apps/mdisddr/tsts/WAC/Makefile @@ -0,0 +1,15 @@ +APPNAME = mdisddr + +output.cub.TOLERANCE = 0.00000002 +output.pvl.IGNORELINES = PRODUCT_CREATION_TIME + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/EW0131773041G.cal.cub \ + to=$(OUTPUT)/output > /dev/null; + catlab from=$(OUTPUT)/output.IMG \ + to=$(OUTPUT)/output.pvl > /dev/null; + pds2isis from=$(OUTPUT)/output.IMG \ + to=$(OUTPUT)/output > /dev/null; + $(RM) $(OUTPUT)/output.IMG; diff --git a/isis/src/messenger/apps/mdisedrinfo/Makefile b/isis/src/messenger/apps/mdisedrinfo/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/messenger/apps/mdisedrinfo/MdisEdrKeys.h b/isis/src/messenger/apps/mdisedrinfo/MdisEdrKeys.h new file mode 100644 index 0000000000000000000000000000000000000000..8c81c1135dcbaf623738563ed3fbc9921a98d9f1 --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/MdisEdrKeys.h @@ -0,0 +1,346 @@ +#if !defined(MdisEdrKeys_h) +#define MdisEdrKeys_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/09/22 20:46:27 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include + +#include "Pvl.h" +#include "CollectorMap.h" +#include "MdisGeometry.h" +#include "OriginalLabel.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief MDIS EDR keyword container class + * + * This class ingests a PDS EDR label and stages all keywords found in a + * table. Keywords can be added through the Pvl class or updated explicitly + * by adding a PvlKeyword. + * + * Any add or update operation will replace existing completely so no more + * than on keyword will exist in the table at a time. + * + * Keyword names are not case sensitive. Also, any Object or Group hierarchy + * is not honored in this class. Meaning that if a keyword of the same name + * exists in more than one Object or Group, only the last occurring one is + * retained. + * + * @ingroup Utility + * @author 2007-08-14 Kris Becker + * @history 2008-09-22 Kris Becker - corrected formatting of units that were + * missing in some cases where the first value units is not defined. + */ +class MdisEdrKeys { + public: + /** Benign constuctor */ + MdisEdrKeys() { } + /** Constuctor adds a Pvl label to the table */ + MdisEdrKeys(Pvl &edrlab) : _edrLabel(edrlab), _keys() { + LoadKeys(edrlab, _keys); + } + + /** + * @brief Add a Pvl file (label) to the table + * + * This constuctor will ingest a Pvl labelled file to the table. It can + * be any Pvl file that is supported by the Pvl class, including most all + * PDS formatted labels. This particular interface assumes a MDIS PDS EDR + * label as its parameter. + * + * @param edrfile File containing the PDS EDR label + */ + MdisEdrKeys(const std::string &edrfile) { + _edrLabel = Pvl(edrfile); + LoadKeys(_edrLabel, _keys); + } + + /** + * @brief Construct from an Isis Cube file + * + * This constructor will ingest an ISIS cube file label. Note that there + * is no regard for the Object/Group structure so all keywords are + * included and keywords that repeat in other Objects or Groups replace + * any existing definition. + * + * @param cube A valid ISIS Cube object with a label + */ + MdisEdrKeys(Cube &cube) { + _edrLabel = OriginalLabel(cube.Filename()).ReturnLabels(); + LoadKeys(_edrLabel, _keys); + } + + /** Destroys the object */ + virtual ~MdisEdrKeys() { } + + /** + * @brief Returns the number of keywords in the container + * + * @return int Number of keys in container + */ + inline int size() const { return _keys.size(); } + + /** + * @brief Adds a keyword to the container directly + * + * This method is provided for adding keywords directly to the contained + * that may not be contained within a Pvl object. + * + * @param key PvlKeyword to add to the container + * @param name Optional name other than what the keyword is named + */ + void add(const PvlKeyword &key, const std::string &name = "") { + if (name.empty()) { + _keys.add(key.Name(), key); + } + else { + _keys.add(name, key); + } + return; + } + + /** + * @brief Returns the nth keyword in the container + * + * This method allows one to retrieve the nth keyword in the container as + * a means to iterate through the complete contents for direct + * interogation/use. + * + * If the keyword at specified index does not exist, an exception is + * thrown. + * + * @param index Index of the keyword ranging from 0 to size()-1 + * + * @return const PvlKeyword& Returns a reference to the keyword at index + */ + const PvlKeyword &operator[](const int index) const throw (iException &) { + return (_keys.getNth(index)); + } + + /** + * @brief Return the specified keyword by name + * + * Retrieves a keyword by name without regard for case. An exception is + * thrown if it does not exist. + * + * @param name Name of keyword to retrieve + * + * @return PvlKeyword& Reference to named keyword + */ + PvlKeyword &get(const std::string &name) throw (iException &) { + return (_keys.get(name)); + } + + /** + * @brief Returns the specified keyword by name + * + * Retrieves a keyword by name without regard for case. An exception is + * thrown if it does not exist. + * + * @param name Name of keyword to retrieve + * + * @return const PvlKeyword& Returns a const reference to the named + * keyword + */ + const PvlKeyword &get(const std::string &name) const throw (iException &) { + return (_keys.get(name)); + } + + /** + * @brief Replaces or adds keywords in a Pvl class + * + * This method will add all the keywords found in the Pvl keys object to + * the container. Any keywords that already exist in the container are + * replaced with the new one. + * + * @param keys Pvl class containing the keywords to add + */ + void updateKeys(Pvl &keys) { + LoadKeys(keys, _keys); + } + + /** + * @brief Return a formatted list of keyword values + * + * This method takes in a list of named keywords and formats them + * according to PDS standards in a comma delineated string. This is the + * defined format of the team for its population of PDS EDR label + * keywords. + * + * If any one of the keywords is not found, an exception is thrown. + * + * @param keylist List of keywords to extract + * @param NAstr String used to specify no value (used mainly so a unit + * qualifer is not added to the value) + * @return std::string Returns a comma delineated string of keyword values + */ + std::string extract(const std::vector &keylist, + const std::string &NAstr, PvlGroup *group = 0) { + std::ostringstream out; + + std::string loopSep(""); + int nbad(0); + for (unsigned int i = 0 ; i < keylist.size() ; i++) { + iString keyname(keylist[i]); + keyname.Trim(" \n\t"); + try { + PvlKeyword &key = _keys.get(keyname); + if (group) group->AddKeyword(key); + if ((key.Size() == 0) || (key.IsNull())) { + out << loopSep << "NULL"; + } + else if (key.Size() == 1) { + out << loopSep << key[0] << formatUnit(key.Unit(0)); + } + else { + out << loopSep << "("; + std::string vsep(""); + for (int iv = 0 ; iv < key.Size() ; iv++) { + out << vsep << key[iv]; + if (key[iv] != NAstr) { + out << formatUnit(key.Unit(iv)); + } + vsep = ","; + } + out << ")"; + } + loopSep = ";"; + } catch (iException &ie) { + nbad++; + std::string mess = "Keyword \"" + keyname + "\" does not exist!"; + iException::Message(iException::User, mess.c_str(), _FILEINFO_); + } + } + + // Check to see if all keywords are found + if (nbad > 0) { + std::string mess = "One or more keywords in list do not exist!"; + throw iException::Message(iException::User, mess.c_str(), _FILEINFO_); + } + + return (out.str()); + } + + private: +//!< Define the keyword container for systematic processing + typedef CollectorMap KeyList; + Pvl _edrLabel; //!< Label used to populate the container + KeyList _keys; //!< The container + + /** + * @brief Parse the contents of a (generic) container + * + * This method iterates through all keywords in the PvlContainer and adds + * them KeyList. + * + * @param p Pvl container of keywords + * @param keys Container to receive the keywords + */ + void MapKeys(PvlContainer &p, KeyList &keys, + const std::string prefix= "") { + std::string prekey(prefix); + if (!prefix.empty()) prekey += "/"; + PvlContainer::PvlKeywordIterator keyIter = p.Begin(); + for ( ; keyIter != p.End() ; ++keyIter) { + std::string keyname = prefix + keyIter->Name(); + PvlKeyword key = *keyIter; + key.SetName(keyname); + keys.add(keyname, key); + } + return; + } + + /** + * @brief Adds keywords in groups within an object + * + * This metod iterates through all the keywords in the given group and + * addes them to the keys container. + * + * @param obj Object containing Groups to add to container + * @param keys Container to add the group keywords to + */ + void LoadGroups(PvlObject &obj, KeyList &keys) { + PvlObject::PvlGroupIterator current = obj.BeginGroup(); + for ( ; current != obj.EndGroup() ; ++current) { + MapKeys(*current, keys); + } + return; + } + + /** + * @brief Add object keywords and all keywords in the Object hierachy + * + * This method adds all keywords found in the Object and then any Groups + * that exist in the object. + * + * @param Object to extract keywords from and add to container + * @param keys The container to add keywords to + */ + void LoadKeys(PvlObject &obj, KeyList &keys, + const std::string prefix = "") { + MapKeys(obj, keys, prefix); // Load object level keywords + LoadGroups(obj, keys); // Load all groups in this object + + // Now load all the rest of the object keywords ingnoring + // all SUBFRAME[12345]_PARAMETERS since they are unsupported. + PvlObject::PvlObjectIterator objIter = obj.BeginObject(); + for ( ; objIter != obj.EndObject() ; ++objIter) { + iString objname(objIter->Name()); + objname.UpCase(); + std::string::size_type gotSubframe = objname.find("SUBFRAME"); + if (gotSubframe != std::string::npos) { + LoadKeys(*objIter, keys, objIter->Name()); + } + else { + LoadKeys(*objIter, keys); + } + } + return; + } + + /** + * @brief Returns a properly formated unit + * + * + * @param unit value of unit. If empty returns empty string otherwise + * places "<" and ">" on the ends. + * + * @return std::string The formatted unit + */ + std::string formatUnit(const std::string &unit) const { + if (!unit.empty()) { + return (" <"+unit+">"); + } + return (unit); + } +}; + +} // namespace Isis +#endif + diff --git a/isis/src/messenger/apps/mdisedrinfo/MdisGeometry.cpp b/isis/src/messenger/apps/mdisedrinfo/MdisGeometry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c57b0ae681ddf4d21b645983956021b4c93ad9a5 --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/MdisGeometry.cpp @@ -0,0 +1,1160 @@ +/** + * @file + * $Revision: 1.9 $ + * $Date: 2009/12/29 23:03:50 $ + * $Id: MdisGeometry.cpp,v 1.9 2009/12/29 23:03:50 ehyer Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "MdisGeometry.h" +#include "CameraFactory.h" +#include "SpiceManager.h" +#include "Pvl.h" +#include "OriginalLabel.h" +#include "SpecialPixel.h" +#include "iString.h" +#include "iException.h" +#include "naif/SpiceUsr.h" + +using namespace std; + +namespace Isis { + + /** + * @brief Constructor using an ISIS cube file name + * @param filename Name of ISIS cube file + */ + MdisGeometry::MdisGeometry(const std::string &filename) { + Cube cube; + cube.Open(filename); + init(cube); + } + + /** + * @brief Construct using an ISIS Cube class + * @param cube ISIS cube class + */ + MdisGeometry::MdisGeometry(Cube &cube) { + init(cube); + } + + /** + * @brief Initialize class with an ISIS file + * + * This method is reentrant in that it can be used repeatedly in computing + * MDIS geometry. If a file has already been processed, it will be cleared to + * make way for the specified file. + * + * @param filename Name of ISIS cube file + */ + void MdisGeometry::setCube(const std::string &filename) { + Cube cube; + cube.Open(filename); + delete _camera; + init(cube); + return; + } + + + /** + * @brief Checks for the TargetName keyword for validity + * + * This static method will check the value of the Targetname keyword for a + * valid NAIF target code. If it is not valid, ISIS cannot spiceinit the + * image and we will not be able to get any geometric data. + * + * The value of the TargetName keyword is extracted and is checked for a NAIF + * body code, indicating it is a valid target. This result is returned to the + * caller. + * + * If the target is not a recognized NAIF code and the makeValid parameter is + * true, the TargetName keyword values is changed to "Sky". This will allow + * for the basic values to be computed. + * + * @param label Label to validate target + * @param makeValid True if the caller wants a valid Sky target if NAIF knows + * nothing about it + * + * @return bool True if the target is a recognized target, false if not. + */ + bool MdisGeometry::validateTarget(Pvl &label, bool makeValid) { + // Add the planetary constants kernel + SpiceManager naif; + naif.add("$base/kernels/pck/pck?????.tpc"); + + // Get the target and check for validity + PvlKeyword &target = label.FindKeyword("TargetName", PvlObject::Traverse); + SpiceInt tcode; + SpiceBoolean found; + (void) bodn2c_c(target[0].c_str(), &tcode, &found); + if (found) return (true); + + if (makeValid) { target.SetValue("Sky"); } + return (false); + } + + /** + * @brief Returns the center line and sample coordinate of the image + * + * This method returns the reference line and sample coordinate at the center + * of the image. + * + * @param sample Sample coordinate at the center + * @param line Line coordinate at the center + */ + void MdisGeometry::refCenterCoord(double &sample, double &line) const { + // Ensure there is a camera model instantiated! + if (!_camera) { + string mess = "No image (camera model) established for reference pixel!"; + throw iException::Message(iException::Programmer, mess.c_str(), + _FILEINFO_); + } + + // Compute point at center + sample = _camera->Samples()/2.0; + line = _camera->Lines()/2.0; + return; + } + + /** + * @brief Returns the upper left line and sample coordinate of the image + * + * This method returns the reference line and sample coordinate at the upper + * left corner of the image. + * + * @param sample Sample coordinate at the upper left + * @param line Line coordinate at the upper left + */ + void MdisGeometry::refUpperLeftCoord(double &sample, double &line) const { + // Upper left point is a constant + sample = 1.0; + line = 1.0; + return; + } + + /** + * @brief Returns the upper right line and sample coordinate of the image + * + * This method returns the reference line and sample coordinate at the upper + * right corner of the image. + * + * @param sample Sample coordinate at the upper right + * @param line Line coordinate at the upper right + */ + void MdisGeometry::refUpperRightCoord(double &sample, double &line) const { + // Ensure there is a camera model instantiated! + if (!_camera) { + string mess = "No image (camera model) established for reference pixel!"; + throw iException::Message(iException::Programmer, mess.c_str(), + _FILEINFO_); + } + + // Upper right corner point + sample = _camera->Samples(); + line = 1.0; + return; + } + + /** + * @brief Returns the lower left line and sample coordinate of the image + * + * This method returns the reference line and sample coordinate at the lower + * left corner of the image. + * + * @param sample Sample coordinate at the lower left + * @param line Line coordinate at the lower left + */ + void MdisGeometry::refLowerLeftCoord(double &sample, double &line) const { + // Ensure there is a camera model instantiated! + if (!_camera) { + string mess = "No image (camera model) established for reference pixel!"; + throw iException::Message(iException::Programmer, mess.c_str(), + _FILEINFO_); + } + + // Lower left corner point + sample = 1.0; + line = _camera->Lines(); + return; + } + + /** + * @brief Returns the lower right line and sample coordinate of the image + * + * This method returns the reference line and sample coordinate at the lower + * right corner of the image. + * + * @param sample Sample coordinate at the lower right + * @param line Line coordinate at the lower right + */ + void MdisGeometry::refLowerRightCoord(double &sample, double &line) const { + // Ensure there is a camera model instantiated! + if (!_camera) { + string mess = "No image (camera model) established for reference pixel!"; + throw iException::Message(iException::Programmer, mess.c_str(), + _FILEINFO_); + } + + // Lower right corner point + sample = _camera->Samples(); + line = _camera->Lines(); + return; + } + + /** + * @brief Compute and retrieve geometric parameters for given file + * + * This routine invokes a series of methods that compute geometric parameters + * for MESSENGER MDIS camera observations. These parameters are expressly for + * population of PDS keyword values in the original EDRs. + * + * A camera model is required when computing these values and is provided + * through several constructor options and a method. + * + * The filename argument is only for recording in the FILENAME keyword as the + * source of the actual ISIS file is likely from a PDS EDR file. This + * satisifies a need to associate the data with the original EDR. The camera + * model is invoked from the ISIS verision of the cube. + * + * @param filename File to record as orginal source of data + * + * @return Pvl Contains PvlKeywords of all computed parameters + */ + Pvl MdisGeometry::getGeometry(const std::string &filename) { + Pvl geom; + + // Set initial keywords + geom += PvlKeyword("FILENAME", filename); + geom += format("SOURCE_PRODUCT_ID", _spice.getList(true)); + + // Invoke routines to compute associated keys + GeometryKeys(geom); + TargetKeys(geom); + SpacecraftKeys(geom); + ViewingAndLightingKeys(geom); + return (geom); + } + + /** + * @brief Initialize the class parameter with the ISIS cube source + * + * This method is the main initialization routine. If is mostly reentrant but + * the caller must, at a minimum, decide to free any existing camera model. + * + * It is intended to be used in the various constructors, but can also be used + * to intialize a new cube as needed in this object. It does reset everything + * to defaults. + * + * It is assumed that the incoming ISIS cube has been initialize with SPICE + * kernels (typically via spiceinit) or this initialization will fail. + * + * @param cube ISIS Cube to initialize + */ + void MdisGeometry::init(Cube &cube) { + _label = *cube.Label(); + _orglabel = OriginalLabel(cube.Filename()).ReturnLabels(); + _nSubframes = (int) _orglabel.FindKeyword("MESS:SUBFRAME", + PvlObject::Traverse); + _camera = CameraFactory::Create(_label); + _digitsPrecision = _defaultDigits; + _NullDefault = "\"N/A\""; + _doUpdate = true; + _spice.Load(_label); + return; + } + + + /** + * @brief Compute values related to camera attitude + * + * This method determines keywords that provides camera FOV data. It computes + * RA and DEC coordinates of the boresight and its 4 corners. It generates + * the follwing keywords: RA_DEC_REF_PIXEL, RIGHT_ASCENSION, DECLINATION, + * TWIST_ANGLE, RETICLE_POINT_RA and RETICLE_POINT_DECLINATION. + * + * @param geom Pvl container for generated keyword/value data + */ + void MdisGeometry::GeometryKeys(Pvl &geom) { + // Ensure there is a camera model instantiated! + if (!_camera) { + string mess = "No image (camera model) established for Geometry keys!"; + throw iException::Message(iException::Programmer, mess.c_str(), + _FILEINFO_); + } + + // Get the center ra/dec + double refSamp, refLine; + refCenterCoord(refSamp, refLine); + + std::vector refPixel; + refPixel.push_back(refSamp); + refPixel.push_back(refLine); + geom += format("RA_DEC_REF_PIXEL", refPixel); + + _camera->SetImage(refSamp, refLine); + double centerRa = _camera->RightAscension(); + double centerDec = _camera->Declination(); + geom += format("RIGHT_ASCENSION", centerRa, "DEG"); + geom += format("DECLINATION", centerDec, "DEG"); + + // Compute the celestial north clocking angle for TWIST_ANGLE + double res = _camera->RaDecResolution(); + _camera->SetRightAscensionDeclination(centerRa,centerDec+2.0*res); + double x = _camera->Sample() - refSamp; + double y = _camera->Line() - refLine; + double rot = atan2(-y,x) * 180.0 / Isis::PI; + rot = 90.0 - rot; + if (rot < 0.0) rot += 360.0; + // Above completes celestial north, below is twist angle + double twist_angle = (180.0 - rot); + twist_angle = fmod(twist_angle, 360.0); + geom += format("TWIST_ANGLE", twist_angle, "DEG"); + +// Now compute the RA/DEC reticle points + std::vector retRa, retDec; + + refUpperLeftCoord(refSamp, refLine); + _camera->SetImage(refSamp, refLine); + retRa.push_back(_camera->RightAscension()); + retDec.push_back(_camera->Declination()); + + refUpperRightCoord(refSamp, refLine); + _camera->SetImage(refSamp, refLine); + retRa.push_back(_camera->RightAscension()); + retDec.push_back(_camera->Declination()); + + refLowerLeftCoord(refSamp, refLine); + _camera->SetImage(refSamp, refLine); + retRa.push_back(_camera->RightAscension()); + retDec.push_back(_camera->Declination()); + + refLowerRightCoord(refSamp, refLine); + _camera->SetImage(refSamp, refLine); + retRa.push_back(_camera->RightAscension()); + retDec.push_back(_camera->Declination()); + + geom += format("RETICLE_POINT_RA", retRa, "DEG"); + geom += format("RETICLE_POINT_DECLINATION", retDec, "DEG"); + + return; + } + + /** + * @brief Computes geometric values related to a target + * + * This method computes geometric values related to an observed target, such + * as Earth, Moon, Mercury, etc... + * + * Not all data will be of a planetary body. Some are taken of deep space (we + * call it Sky) or other undefined bodies. These types of observations are + * not defined for the values computed herein. The criteria used here is the + * center reference pixel must intersect the target body. It is undefined for + * Sky images and will result in a null string ("N/A", probably) for all + * keyword values. + * + * If the center reference pixel does intersect the target body, the values + * should be complete for most cases. One exception is the + * RETICLE_POINT_LATITUDE and RETICLE_POINT_LONGITUDE values, which are taken + * at the 4 corners of the image. It is not uncommon for flyby images to have + * the target body centered in the camera FOV and not all corner pixels + * intersect it. For these cases, the values will be the null string. The + * opposite may also be true in that the center pixel does not intersect the + * target body but one or more of the reticle points do. This method will + * resolve as many of these parameters as are defined. + * + * The following keyword values are computed in this method: + * SC_TARGET_POSITION_VECTOR, TARGET_CENTER_DISTANCE, SLANT_DISTANCE, + * CENTER_LATITUDE, CENTER_LONGITUDE, HORIZONTAL_PIXEL_SCALE, + * VERTICAL_PIXEL_SCALE, SMEAR_MAGNITUDE, SMEAR_AZIMUTH, NORTH_AZIMUTH, + * RETICLE_POINT_LATITUDE and RETICLE_POINT_LONGITUDE. + * + * @param geom Pvl container for generated keyword/value data + */ + void MdisGeometry::TargetKeys(Pvl &geom) { + // Ensure there is a camera model instantiated! + if (!_camera) { + string mess = "No image (camera model) established for Target keys!"; + throw iException::Message(iException::Programmer, mess.c_str(), + _FILEINFO_); + } + + // Get sc_target_position_vector and target_center_distance for all targets + // except Sky + if ( !_camera->IsSky() ) { + SpicePosition *scpos = _camera->InstrumentPosition(); + std::vector jVec; + jVec = scpos->Coordinate(); + geom += format("SC_TARGET_POSITION_VECTOR", jVec, "KM"); + + // Compute distances + geom += format("TARGET_CENTER_DISTANCE", _camera->TargetCenterDistance(), + "KM"); + } + else if (_doUpdate) { + geom += format("SC_TARGET_POSITION_VECTOR", Null); + geom += format("TARGET_CENTER_DISTANCE", Null); + } + + // Get reference pixel coordinate + double refSamp, refLine; + refCenterCoord(refSamp, refLine); + + // Set point at center + _camera->SetImage(refSamp,refLine); + if (_camera->HasSurfaceIntersection()) { + + geom += format("SLANT_DISTANCE", _camera->SlantDistance(), "KM"); + + // Geometric coordinages + geom += format("CENTER_LATITUDE", _camera->UniversalLatitude(), "DEG"); + geom += format("CENTER_LONGITUDE", _camera->UniversalLongitude(), "DEG"); + + // Resolution + geom += format("HORIZONTAL_PIXEL_SCALE", _camera->SampleResolution(), "M"); + geom += format("VERTICAL_PIXEL_SCALE", _camera->LineResolution(), "M"); + +// COMPUTE SMEAR MAGNITUDE AND AZIMUTH + + double smear_magnitude, smear_azimuth; + if (SmearComponents(smear_magnitude, smear_azimuth)) { + geom += format("SMEAR_MAGNITUDE", smear_magnitude, "PIXELS"); + geom += format("SMEAR_AZIMUTH", smear_azimuth, "DEG"); + } + else if (_doUpdate) { + geom += format("SMEAR_MAGNITUDE", Null); + geom += format("SMEAR_AZIMUTH", Null); + } + + // Other angles + geom += format("NORTH_AZIMUTH", _camera->NorthAzimuth(), "DEG"); + } + else if (_doUpdate) { + geom += format("SLANT_DISTANCE", Null); + geom += format("CENTER_LATITUDE", Null); + geom += format("CENTER_LONGITUDE", Null); + geom += format("HORIZONTAL_PIXEL_SCALE", Null); + geom += format("VERTICAL_PIXEL_SCALE", Null); + geom += format("SMEAR_MAGNITUDE", Null); + geom += format("SMEAR_AZIMUTH", Null); + geom += format("NORTH_AZIMUTH", Null); + } + + // Now compute the reticle points + std::vector retLat, retLon; + int nGood(0); + + refUpperLeftCoord(refSamp, refLine); + _camera->SetImage(refSamp, refLine); + if (_camera->HasSurfaceIntersection()) { + retLat.push_back(_camera->UniversalLatitude()); + retLon.push_back(_camera->UniversalLongitude()); + nGood++; + } + else { + retLat.push_back(Null); + retLon.push_back(Null); + } + + refUpperRightCoord(refSamp, refLine); + _camera->SetImage(refSamp, refLine); + if (_camera->HasSurfaceIntersection()) { + retLat.push_back(_camera->UniversalLatitude()); + retLon.push_back(_camera->UniversalLongitude()); + nGood++; + } + else { + retLat.push_back(Null); + retLon.push_back(Null); + } + + refLowerLeftCoord(refSamp, refLine); + _camera->SetImage(refSamp, refLine); + if (_camera->HasSurfaceIntersection()) { + retLat.push_back(_camera->UniversalLatitude()); + retLon.push_back(_camera->UniversalLongitude()); + nGood++; + } + else { + retLat.push_back(Null); + retLon.push_back(Null); + } + + refLowerRightCoord(refSamp, refLine); + _camera->SetImage(refSamp, refLine); + if (_camera->HasSurfaceIntersection()) { + retLat.push_back(_camera->UniversalLatitude()); + retLon.push_back(_camera->UniversalLongitude()); + nGood++; + } + else { + retLat.push_back(Null); + retLon.push_back(Null); + } + + if (nGood > 0) { + geom += format("RETICLE_POINT_LATITUDE", retLat, "DEG"); + geom += format("RETICLE_POINT_LONGITUDE", retLon, "DEG"); + } + else if (_doUpdate) { + geom += format("RETICLE_POINT_LATITUDE", retLat); + geom += format("RETICLE_POINT_LONGITUDE", retLon); + } + + // Do subframe targets + SubframeTargetKeys(geom); + + return; + } + + /** + * @brief Computes geometric values related to a target for subframe images + * + * This method computes geometric values related to an observed target, such + * as Earth, Moon, Mercury, etc..., for subframe images. This + * + * @param geom Pvl container for generated keyword/value data + */ + void MdisGeometry::SubframeTargetKeys(Pvl &geom) { + // Ensure there is a camera model instantiated! + if (!_camera) { + string mess = "No image (camera model) established for Target keys!"; + throw iException::Message(iException::Programmer, mess.c_str(), + _FILEINFO_); + } + + // Now compute the reticle points of all subframes if they exist + for (int i = 1 ; i <= 5 ; i++) { + iString n(i); + string object = "SUBFRAME" + n + "_PARAMETERS/"; + + double sample, line, width, height; + if (!getSubframeCoordinates(i,sample,line,width,height)) { + // Subframe does not exist + std::vector retLat(4,Null), retLon(4,Null); + geom += format(object+"RETICLE_POINT_LATITUDE", retLat); + geom += format(object+"RETICLE_POINT_LONGITUDE", retLon); + } + else { + // Subframe exists in this frame + std::vector retLat, retLon; + int nGood(0); + + double refSamp(sample), refLine(line); + _camera->SetImage(refSamp, refLine); + if (_camera->HasSurfaceIntersection()) { + retLat.push_back(_camera->UniversalLatitude()); + retLon.push_back(_camera->UniversalLongitude()); + nGood++; + } + else { + retLat.push_back(Null); + retLon.push_back(Null); + } + + refSamp = sample + width - 1.0; + refLine = line; + _camera->SetImage(refSamp, refLine); + if (_camera->HasSurfaceIntersection()) { + retLat.push_back(_camera->UniversalLatitude()); + retLon.push_back(_camera->UniversalLongitude()); + nGood++; + } + else { + retLat.push_back(Null); + retLon.push_back(Null); + } + + refSamp = sample; + refLine = line + height - 1.0; + _camera->SetImage(refSamp, refLine); + if (_camera->HasSurfaceIntersection()) { + retLat.push_back(_camera->UniversalLatitude()); + retLon.push_back(_camera->UniversalLongitude()); + nGood++; + } + else { + retLat.push_back(Null); + retLon.push_back(Null); + } + + refSamp = sample + width - 1.0; + refLine = line + height - 1.0; + _camera->SetImage(refSamp, refLine); + if (_camera->HasSurfaceIntersection()) { + retLat.push_back(_camera->UniversalLatitude()); + retLon.push_back(_camera->UniversalLongitude()); + nGood++; + } + else { + retLat.push_back(Null); + retLon.push_back(Null); + } + + if (nGood > 0) { + geom += format(object+"RETICLE_POINT_LATITUDE", retLat, "DEG"); + geom += format(object+"RETICLE_POINT_LONGITUDE", retLon, "DEG"); + } + else if (_doUpdate) { + geom += format(object+"RETICLE_POINT_LATITUDE", retLat); + geom += format(object+"RETICLE_POINT_LONGITUDE", retLon); + } + } + } + return; + } + + /** + * @brief Determine if the specified subframe exists and return its data + * + * This method looks at the contents of the orginal PDS EDR label to determine + * if the requested subframe exists within the full frame. If it does, the + * starting sample and line, as well as the width and height are return. The + * method returns a true condition when a subframe exists, otherwise it + * returns false (with zeros for coordinates). + * + * @param frameno Specified frame number (valid range: 1-5) + * @param sample Returns the starting sample coordinate of the subframe + * @param line Returns the starting line coordinate of the subframe + * @param width Returns the width in pixels of the subframe + * @param height Returns the heigth in pixels of the subframe + * + * @return bool Returns true if the subframe exists in this image, false + * otherwise. + */ + bool MdisGeometry::getSubframeCoordinates(int frameno, + double &sample, double &line, + double &width, double &height) { + + // Does the subframe exist? + if ((frameno < 1) || (frameno > _nSubframes)) { + // No + sample = line = width = height = 0.0; + return (false); + } + else { + // It does exist, extract coordinates from original image label + iString n(frameno); + sample = (double) _orglabel.FindKeyword("MESS:SUBF_X" + n, + PvlObject::Traverse); + line = (double) _orglabel.FindKeyword("MESS:SUBF_Y" + n, + PvlObject::Traverse); + width = (double) _orglabel.FindKeyword("MESS:SUBF_DX" + n, + PvlObject::Traverse); + height = (double) _orglabel.FindKeyword("MESS:SUBF_DY" + n, + PvlObject::Traverse); + + } + return (true); + } + + + /** + * @brief Compute smear components of the reference pixel + * + * This method computes the SMEAR_MAGNITUDE and SMEAR_AZIMUTH keyword values + * if possible. There are cases where the values cannot be computed, such as + * the boresight is on the limb and the magnitude becomes infinity. + * + * IMPORTANT: It is assumed that the pixel location to compute these values + * for are already set in the _camera object and that this pixel intersections + * the target surface. All computations will be derived from this intersection + * point. + * + * Note that at the time of this development, ISIS did not provide all the + * necessary NAIF SPICE components though the API (namely, velecity vectors). + * Because of this, all the SPICE kernels must be loaded as the values cannnot + * come from what is internally cached in the Spice class. This is an + * unfortunate consquence as efficiency is severely compromised by this issue. + * This object provides this requirement via the SpiceManager class. + * + * @param smear_magnitude Returns the smear magnitude compoment in pixel + * units. + * @param smear_azimuth Returns the smear velocity vector in km/s units. + * + * @return bool True if the components can be computed, false if it fails. + */ + bool MdisGeometry::SmearComponents(double &smear_magnitude, + double &smear_azimuth) { + smear_magnitude = Null; + smear_azimuth = Null; + + // Ensure there is a camera model instantiated! + if (!_camera) { + string mess = "No image/camera model established for smear components!"; + throw iException::Message(iException::Programmer, mess.c_str(), + _FILEINFO_); + } + + // Get NAIF body codes + SpiceInt scCode(-236), targCode(0); + SpiceBoolean found; + string target(_camera->Target()); + (void) bodn2c_c("MESSENGER", &scCode, &found); + (void) bodn2c_c(target.c_str(), &targCode, &found); + if (!found) { + return (false); + } + + // Get the target state (starg) + SpiceRotation *rotate = _camera->InstrumentRotation(); + SpiceDouble starg[6]; // Position and velocity vector in J2000 + SpiceDouble lt; + spkez_c (targCode, rotate->EphemerisTime(), "J2000", "LT+S", scCode, + starg, < ); + + // Get surfarce intersection vector in body-fixed coordinates (surfx) + double surfx[3]; + _camera->Coordinate(surfx); + + // Get camera transform (ticam) + std::vector ticam = rotate->Matrix(); + + // Get angular velocity vector of camera (av) + SpiceDouble sclkdp; + (void) sce2c_c(scCode, rotate->EphemerisTime(), &sclkdp); + + // Determine instrument ID (inst) + PvlKeyword &key = _label.FindKeyword("NaifIkCode", PvlObject::Traverse); + SpiceInt inst = (int) key; + iString iCode((int) inst); + key = _label.FindKeyword("Number", PvlObject::Traverse); + inst -= (int) key; + + // Get CK time tolerance (tol) + SpiceDouble tol = Spice::GetDouble("INS" + iCode + "_CK_TIME_TOLERANCE"); + + // Finally get av + SpiceDouble cmat[3][3], av[3], clkout; + (void) ckgpav_c((scCode*1000), sclkdp, tol, "J2000", cmat, av, &clkout, + &found); + if (!found) { +#if defined(DEBUG) + cout << "Cannot get angular camera velocity for time " + << setprecision(12) << sclkdp << "!\n"; +#endif + return (false); + } + + // Get the state transformation matrix (tsipm) + SpiceChar frname[40]; + SpiceInt frcode; + (void) cidfrm_c(targCode, sizeof(frname), &frcode, frname, &found); + if (!found) { + return (false); + } + + SpiceDouble tsipm[6][6]; + (void) sxform_c("J2000", frname, rotate->EphemerisTime(), tsipm); + + // Get focal length + double foclen = _camera->FocalLength(); + + // Get pixel scale (pix/mm) from camera pixel pitch (mm/pix) + double pxlscl = 1.0/_camera->PixelPitch(); + +//-- Now implement the SMEAR routine (smrimg) + SpiceDouble tipm[3][3], dtipm[3][3]; + for (int i = 0 ; i < 3 ; i++) { + for (int j = 0 ; j < 3 ; j++ ) { + tipm[i][j] = tsipm[i][j]; + dtipm[i][j] = tsipm[i][j+3]; + } + } + + // rav2dr stuff here + SpiceDouble omega[3][3]; + omega[0][0] = 0.0; + omega[1][1] = 0.0; + omega[2][2] = 0.0; + + omega[0][1] = -av[2]; + omega[0][2] = av[1]; + omega[1][2] = -av[0]; + + omega[1][0] = av[2]; + omega[2][0] = -av[1]; + omega[2][1] = av[0]; + + SpiceDouble dticam[3][3]; + mxmt_c(&ticam[0], omega, dticam); + + //-- Done with rav2dr + + // Complete the rest of smrimg + SpiceDouble surfxi[3], vi[3]; + mtxv_c(tipm, surfx, surfxi); + vadd_c(starg, surfxi, vi); + + SpiceDouble dvb[3], dvi[3]; + mtxv_c(dtipm, surfx, dvb); + vadd_c(&starg[3], dvb, dvi); + + SpiceDouble vc[3], dvc1[3], dvc2[3], dvc[3]; + mxv_c(&ticam[0], vi, vc); + + mxv_c(&ticam[0], dvi, dvc1); + mxv_c(dticam, vi, dvc2); + vadd_c(dvc1, dvc2, dvc); + + // Make sure we Vf can be computed + if (vc[2] == 0.0) { + return (false); + } + + // Compute derivative of Vf which is dvf + SpiceDouble dvf[2]; + vlcomg_c(2, -foclen*dvc[2] / (vc[2]*vc[2]), vc, + foclen / vc[2], dvc, dvf); + + // dvf has units for mm/sec. Scale by pixel pitch and multiply + // by exposure length to obtain smear + key = _label.FindKeyword("ExposureDuration", PvlObject::Traverse); + double explen = (double) key; // in milliseconds + + SpiceDouble smear[2]; + vsclg_c(pxlscl*(explen/1000.0), dvf, 2, smear); //convert explen to seconds + + // Compute the norm and azimuth angle + smear_magnitude = vnormg_c(smear, 2); + if (smear_magnitude == 0.0) { + smear_azimuth = 0.0; + } + else { + smear_azimuth = atan2(smear[1], smear[0]) * dpr_c(); + if (smear_azimuth < 0.0) smear_azimuth += 360.0; + } + + return (true); + } + + + /** + * @brief Computes spacecraft attitude geomtric values + * + * This method computes geometric values related to spacecraft location and + * attitude. These will typically always be defined as long as SPICE is valid + * at the image epoch. + * + * The following keyword values are computed: SUB_SPACECRAFT_LATITUDE, + * SUB_SPACECRAFT_LONGITUDE, SPACECRAFT_ALTITUDE, SUB_SPACECRAFT_AZIMUTH, + * SPACECRAFT_SOLAR_DISTANCE, SC_SUN_POSITION_VECTOR and + * SC_SUN_VELOCITY_VECTOR. + * + * The SUB_SPACECRAFT_LATITUDE, SUB_SPACECRAFT_LONGITUDE, SPACECRAFT_ALTITUDE, + * and SUB_SPACECRAFT_AZIMUTH are subject to center reference pixel + * intersection with the target body and are also not relevent to Sky images. + * + * @param geom Pvl container for generated keyword/value data + */ + void MdisGeometry::SpacecraftKeys(Pvl &geom) { + // Ensure there is a camera model instantiated! + if (!_camera) { + string mess = "No image (camera model) established for Spacecraft keys!"; + throw iException::Message(iException::Programmer, mess.c_str(), + _FILEINFO_); + } + + // Get reference pixel coordinate + double refSamp, refLine; + refCenterCoord(refSamp, refLine); + + // Get the center ra/dec + _camera->SetImage(refSamp, refLine); + if (!_camera->IsSky()) { + double lat, lon; + _camera->SubSpacecraftPoint(lat, lon); + geom += format("SUB_SPACECRAFT_LATITUDE", lat, "DEG"); + geom += format("SUB_SPACECRAFT_LONGITUDE", lon, "DEG"); + geom += format("SPACECRAFT_ALTITUDE", _camera->SpacecraftAltitude(), "KM"); + + if (_camera->HasSurfaceIntersection()) { + geom += format("SUB_SPACECRAFT_AZIMUTH", _camera->SpacecraftAzimuth(), + "DEG"); + } + else if (_doUpdate) { + geom += format("SUB_SPACECRAFT_AZIMUTH", Null); + } + } + else if (_doUpdate) { + geom += format("SUB_SPACECRAFT_LATITUDE", Null); + geom += format("SUB_SPACECRAFT_LONGITUDE", Null); + geom += format("SPACECRAFT_ALTITUDE", Null); + geom += format("SUB_SPACECRAFT_AZIMUTH", Null); + } + + // Compute distance and position from spacecraft to sun + // This is the J2000 target to sun reference + SpicePosition *sunpos = _camera->SunPosition(); + std::vector jVec = sunpos->Coordinate(); + + // J2000 spacecraft to sun reference + SpicePosition *campos = _camera->InstrumentPosition(); + std::vector sVec = campos->Coordinate(); + + // Subtract target-sun vector from sc-sun vector and normalize to get + // distance from observer to sun + double scPos[3]; + vsub_c(&sVec[0], &jVec[0], scPos); + double sc_sun_dist = vnorm_c(scPos); + geom += format("SPACECRAFT_SOLAR_DISTANCE", sc_sun_dist, "KM"); + + // Record position vector + std::vector scVec; + scVec.push_back(scPos[0]); + scVec.push_back(scPos[1]); + scVec.push_back(scPos[2]); + geom += format("SC_SUN_POSITION_VECTOR", scVec, "KM"); + + geom += format("SC_SUN_VELOCITY_VECTOR", ScVelocityVector(), "KM/S"); + return; + } + + /** + * @brief Computes the sun velocity vector relative to observer (spacecraft) + * + * This method computes the x, y, z component of the velocity vector of sun + * relative to the observer, expressed in J2000 coordinates, and corrected for + * light time, evaluated at epoch at which image was taken. Units are + * kilometers per second. This routine provides the SC_SUN_VELOCITY_VECTOR + * keyword. + * + * @return std::vector x, y, z velocity components in km/s units + */ + std::vector MdisGeometry::ScVelocityVector() { + // Ensure there is a camera model instantiated! + if (!_camera) { + string mess = "No image/camera model established for Spacecraft Velocity keys!"; + throw iException::Message(iException::Programmer, mess.c_str(), + _FILEINFO_); + } + + // Get NAIF body codes + SpiceInt sc(-236), sun(10); + SpiceBoolean found; + (void) bodn2c_c("MESSENGER", &sc, &found); + (void) bodn2c_c("SUN", &sun, &found); + + // Get the Sun to Messenger state matrix + SpiceRotation *rotate = _camera->BodyRotation(); + SpiceDouble stateJ[6]; // Position and velocity vector in J2000 + SpiceDouble lt; + spkez_c (sc , rotate->EphemerisTime(), "J2000", "LT+S", sun, stateJ, < ); + + // Stage result and negate as it needs to be relative to Messenger + vector scvel; + scvel.push_back(stateJ[3]); + scvel.push_back(stateJ[4]); + scvel.push_back(stateJ[5]); + vminus_c(&scvel[0], &scvel[0]); + + return (scvel); + } + + /** + * @brief Compute viewing and lighting geometric components + * + * This method computes the viewing and lighting angles and distance values in + * relation to the target and the sun. If the center reference pixel + * coordinate does not intersect the surface these values are undefined and + * will result in null strings for each keyword. + * + * The following keywords are computed: SOLAR_DISTANCE, SUB_SOLAR_AZIMUTH, + * SUB_SOLAR_LATITUDE, SUB_SOLAR_LONGITUDE, INCIDENCE_ANGLE, EMISSION_ANGLE, + * and PHASE_ANGLE. + * + * @param geom Pvl container for generated keyword/value data + */ + void MdisGeometry::ViewingAndLightingKeys(Pvl &geom) { + // Ensure there is a camera model instantiated! + if (!_camera) { + string mess = "No image (camera model) established for Viewing & Lighting keys!"; + throw iException::Message(iException::Programmer, mess.c_str(), + _FILEINFO_); + } + +// Get reference pixel coordinate + double refSamp, refLine; + refCenterCoord(refSamp, refLine); + +// Get the center ra/dec + _camera->SetImage(refSamp, refLine); + + // These parameters only require a target other than the Sky + if (!_camera->IsSky()) { + double sslat, sslon; + _camera->SubSolarPoint(sslat,sslon); + geom += format("SUB_SOLAR_LATITUDE", sslat, "DEG"); + geom += format("SUB_SOLAR_LONGITUDE", sslon, "DEG"); + + SpicePosition *sunpos = _camera->SunPosition(); + std::vector jVec = sunpos->Coordinate(); + double solar_dist = vnorm_c(&jVec[0]); + + geom += format("SOLAR_DISTANCE", solar_dist, "KM"); + + } + else if (_doUpdate) { + geom += format("SUB_SOLAR_LATITUDE", Null); + geom += format("SUB_SOLAR_LONGITUDE", Null); + geom += format("SOLAR_DISTANCE", Null); + } + + // These require surface intersections + if (_camera->HasSurfaceIntersection()) { +// Solar information + geom += format("SUB_SOLAR_AZIMUTH", _camera->SunAzimuth(), "DEG"); + geom += format("INCIDENCE_ANGLE", _camera->IncidenceAngle(), "DEG"); + geom += format("PHASE_ANGLE", _camera->PhaseAngle(), "DEG"); + geom += format("EMISSION_ANGLE", _camera->EmissionAngle(), "DEG"); + geom += format("LOCAL_HOUR_ANGLE", _camera->LocalSolarTime()*15.0, "DEG"); + } + else if (_doUpdate) { + geom += format("SUB_SOLAR_AZIMUTH", Null); + geom += format("INCIDENCE_ANGLE", Null); + geom += format("PHASE_ANGLE", Null); + geom += format("EMISSION_ANGLE", Null); + geom += format("LOCAL_HOUR_ANGLE", Null); + } + return; + + } + + /** + * @brief Format a single double value according to specifications + * + * This method formats the actual double value according to specifications of + * the PDS and mission definitions. If the passed values is a an ISIS special + * pixel (namely a Null value), the special null string is subsitituted. + * + * The double precision value is subject to formatted digits of precision of a + * predetermined magnitude. It is manageable at the caller level. + * + * @param name Name of the keyword to create + * @param value Double precision value to format. If its a special pixel, + * the null string will be substituted. + * @param unit Optional unit for the value. Pass an empty string to exclude + * unit from format. + * + * @return PvlKeyword Returns the formatted PVL keyword + */ + PvlKeyword MdisGeometry::format(const std::string &name, const double &value, + const std::string &unit) const { + if (IsSpecial(value)) { + return (PvlKeyword(name, _NullDefault)); + } + else { + return (PvlKeyword(name, DoubleToString(value), unit)); + } + } + + /** + * @brief Format a vector of double precision values + * + * This method formats double valued according to specifications of the PDS + * and mission definitions. If the passed values is a an ISIS special pixel + * (namely a Null value), the special null string is subsitituted. + * + * The double precision value is subject to formatted digits of precision of a + * predetermined magnitude. It is manageable at the caller level. + * + * @param name Name of the keyword to create + * @param values Vector of double precision values to format. If its a + * special pixel, the null string will be substituted. + * @param unit Optional unit for the value. Pass an empty string to exclude + * unit from format. + * + * @return PvlKeyword Returns the formatted PVL keyword + */ + PvlKeyword MdisGeometry::format(const std::string &name, + const std::vector &values, + const std::string &unit) const { + PvlKeyword key(name); + for (unsigned int i = 0 ; i < values.size() ; i++) { + if (IsSpecial(values[i])) { + key.AddValue(_NullDefault); + } + else { + key.AddValue(DoubleToString(values[i]), unit); + } + } + return (key); + } + + /** + * @brief Create a PvlKeyword from a vector of string values + * + * This method formats a vector of string values according to specifications + * of the PDS and mission definitions. If any one of the passed string values + * is a an empty string, the special null string is subsitituted. + * + * @param name Name of the keyword to create + * @param values Vector of string values to format. Empty strings are + * substituted by the null string value. + * @param unit Optional unit for the value. Pass an empty string to exclude + * unit from format. + * + * @return PvlKeyword Returns the formatted PVL keyword + */ + PvlKeyword MdisGeometry::format(const std::string &name, + const std::vector &values, + const std::string &unit) const { + PvlKeyword key(name); + for (unsigned int i = 0 ; i < values.size() ; i++) { + if (values[i].empty()) { + key.AddValue(_NullDefault); + } + else { + key.AddValue(values[i], unit); + } + } + return (key); + } + + /** + * @brief Convert a double value to a string subject to precision specs + * + * This method converts a double value to a string that has a prefined digitis + * of precision. Fixed float form is used with the specified number of digits + * of precision. + * + * @param value Double value to convert to string + * + * @return iString Returns the converted string + */ + iString MdisGeometry::DoubleToString(const double &value) const { + if (IsSpecial(value)) { + return (iString(_NullDefault)); + } + + // Format the string to specs + ostringstream strcnv; + strcnv.setf(std::ios::fixed); + strcnv << setprecision(_digitsPrecision) << value; + return (iString(strcnv.str())); + } +} // namespace Isis + + diff --git a/isis/src/messenger/apps/mdisedrinfo/MdisGeometry.h b/isis/src/messenger/apps/mdisedrinfo/MdisGeometry.h new file mode 100644 index 0000000000000000000000000000000000000000..9b7c9dcf250919fe22b8f019583a79bc84fc10a8 --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/MdisGeometry.h @@ -0,0 +1,179 @@ +#if !defined(MdisGeometry_h) +#define MdisGeometry_h +/** + * @file + * $Revision: 1.7 $ + * $Date: 2009/09/19 00:12:10 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "Pvl.h" +#include "Cube.h" +#include "Camera.h" +#include "SpiceManager.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Computes all MDIS Geometric keywords + * + * This class computes a set of MESSENGER/MIDS geometric parameters from an + * ISIS cube file. The cube file must have been initialized with SPICE + * kernels (typically by spiceinit). + * + * Many of the parameters are provided by the ISIS Spice/Cameraclass + * hierarchy, but there are a few that utilize NAIF toolkit + * functionality/features that require loading of the kernels that otherwise + * would not be necessary. These are parameters that require velecity vectors + * and pixel smear components (currently not provided directly via the ISIS + * API). + * + * Some of the keywords may not be computable for several reasons. There may + * not be appropriate kernel data coverage for the specified image acquisition + * time, the boresight pixel does not intersect the surface, or the corner + * pixels are off planet. In these cases, the null string is replaced if the + * actions is set appropriately. + * + * @ingroup Utility + * @author 2007-08-14 Kris Becker + * @internal + * @history 2008-04-14 Kris Becker - Removed the isTargetValid() method as it + * was not implemented; Corrected computation of + * SC_TARGET_POSITION_VECTOR and TARGET_CENTER_DISTANCE when target + * is anything but Sky (it was previously only computed when the + * center reference pixel intersected the target). + * @history 2009-09-18 Debbie A. Cook - corrected pxlscl and explen in MdisGeometry + */ +class MdisGeometry { + public: + + /** Default constructor */ + MdisGeometry() : _label(), _orglabel(), _nSubframes(0), _camera(0), + _digitsPrecision(_defaultDigits), + _NullDefault("\"N/A\""), _doUpdate(true), _spice() { } + MdisGeometry(const std::string &filename); + MdisGeometry(Cube &cube); + virtual ~MdisGeometry() { delete _camera; } + + void setCube(const std::string &filename); + static bool validateTarget(Pvl &label, bool makeValid = true); + virtual void refCenterCoord(double &sample, double &line) const; + virtual void refUpperLeftCoord(double &sample, double &line) const; + virtual void refUpperRightCoord(double &sample, double &line) const; + virtual void refLowerLeftCoord(double &sample, double &line) const; + virtual void refLowerRightCoord(double &sample, double &line) const; + Pvl getGeometry(const std::string &filename); + + + /** + * @brief Sets digits of precision for floating point keywords + * + * This method can be used to set the number of digits that follow the + * decimal point when formatting floating point keyword values. PDS will + * typically specify 5 digits of precision (which is the defined by + * _defaultDigits). + * + */ + void setPrecision(int ndigits) { + _digitsPrecision = ndigits; + } + + /** + * @brief Sets the string to be used for uncomputable values + * + * Use this method to set the string that will be used when values cannot + * be computed. PDS recommends the value of "N/A" for these cases. + * + * @param nullstring Value of the string to use + */ + void setNull(const std::string &nullstring) { + _NullDefault = nullstring; + } + + /** + * @brief Value in use for uncomputable values + * + * @return std::string Uncomputed value string + */ + std::string getNull() const { + return (_NullDefault); + } + + /** + * @brief Select action when values cannot be computed + * + * When keyword values cannot be computed, the caller can set the action + * taken for the keyword. If action is true, the keyword value is set to + * the null string. If false, no action is taken and the keyword is not + * generated. + * + * @param action True sets uncomputable keywords to null string, + * false is a noop. + */ + void updateNullKeys(bool action = true) { + _doUpdate = action; + } + + protected: + /** Return const reference to Camera model */ + const Camera &getCamera() const { return (*_camera); } + /** Return reference to Camera model */ + Camera &getCamera() { return (*_camera); } + + private: + enum { _defaultDigits = 5 }; //!< (PDS) Default digits of precision + Pvl _label; //!< Label used to initialize camera model + Pvl _orglabel; //!< Original label of PDS product + int _nSubframes; //!< Number subframes in image + Camera *_camera; //!< Camera model initiated from cube label + int _digitsPrecision; //!< Current digits of precision + std::string _NullDefault; //!< Current null string + bool _doUpdate; //!< Action when vlue is uncomputable + SpiceManager _spice; //!< SPICE kernel manager + + void init(Cube &cube); + + void GeometryKeys(Pvl &geom); + void TargetKeys(Pvl &geom); + void SubframeTargetKeys(Pvl &geom); + bool getSubframeCoordinates(int frameno, double &sample, double &line, + double &width, double &height); + void SpacecraftKeys(Pvl &geom); + void ViewingAndLightingKeys(Pvl &geom); + bool SmearComponents(double &smear_magnitude, double &smear_azimuth); + std::vector ScVelocityVector(); + + PvlKeyword format(const std::string &name, const double &value, + const std::string &unit = "") const; + PvlKeyword format(const std::string &name, const std::vector &values, + const std::string &unit = "") const; + PvlKeyword format(const std::string &name, + const std::vector &values, + const std::string &unit = "") const; + iString DoubleToString(const double &value) const; +}; + +} // namespace Isis +#endif + diff --git a/isis/src/messenger/apps/mdisedrinfo/SpiceManager.cpp b/isis/src/messenger/apps/mdisedrinfo/SpiceManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f1f8ea2c842c1bb2b624aa45fa4cd70fd4634c2 --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/SpiceManager.cpp @@ -0,0 +1,285 @@ +/** + * @file + * $Revision: 1.9 $ + * $Date: 2009/12/29 23:03:50 $ + * $Id: SpiceManager.cpp,v 1.9 2009/12/29 23:03:50 ehyer Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include +#include + +#include "SpiceManager.h" +#include "Filename.h" +#include "PvlKeyword.h" +#include "Pvl.h" +#include "iException.h" +#include "naif/SpiceUsr.h" + +using namespace std; + +namespace Isis { + + /** + * @brief Construct using an ISIS file name + * + * @param filename Name of ISIS cube file + * @param furnish Do we load the kernels we find? + */ + SpiceManager::SpiceManager(const std::string &filename, bool furnish) { + Pvl pvl(filename); + Load(pvl, furnish); + } + + /** + * @brief Construct using an ISIS Cube object + * + * @param cube Cube object of ISIS file + * @param furnish Do we load the kernels we find? + */ + SpiceManager::SpiceManager(Cube &cube, bool furnish) { + Load(*cube.Label(), furnish); + } + + /** + * @brief Construct from an ISIS label + * + * @param pvl ISIS label to get kernel information from + * @param furnish Do we load the kernels we find? + */ + SpiceManager::SpiceManager(Pvl &pvl, bool furnish) { + Load(pvl, furnish); + } + + + /** + * @brief Perform the hunt for Spice kernels in an ISIS label + * + * This method must traverse the ISIS label hierarchy to find all the + * pertinent kernel files. Many of them are found in the Kernel Group, but + * others exist in Table objects that are SPICE blobs. The actual names are + * found in the Kernels keyword in the named Table object. + * + * @param pvl ISIS label + * @param furnish Do we actually load the kernel files as we find them? + */ + void SpiceManager::Load(Pvl &pvl, bool furnish) { + Unload(); + _furnish = furnish; + + std::string kernlist; + // Get the kernel group and load main kernels + PvlGroup kernels = pvl.FindGroup("Kernels",Pvl::Traverse); + // Changed 2008-02-27 to load planetary ephemeris before spacecraft + // since MESSENGER team may update planet data in the s/c SPK. + loadKernelFromTable(kernels["TargetPosition"], "SunPosition", pvl); + + // Now do s/c ephemeris + if (kernels.HasKeyword("SpacecraftPosition")) { + loadKernel(kernels["SpacecraftPosition"]); + } + else { + loadKernelFromTable(kernels["InstrumentPosition"], "InstrumentPosition", + pvl); + } + + if (kernels.HasKeyword("SpacecraftPointing")) { + loadKernel(kernels["SpacecraftPointing"]); + } + else { + loadKernelFromTable(kernels["InstrumentPointing"], "InstrumentPointing", + pvl); + } + + if (kernels.HasKeyword("Frame")) { + loadKernel(kernels["Frame"]); + } + + if (kernels.HasKeyword("Extra")) { + loadKernel(kernels["Extra"]); + } + + + loadKernel(kernels["TargetAttitudeShape"]); + loadKernel(kernels["Instrument"]); + loadKernel(kernels["InstrumentAddendum"]); // Always load after instrument + loadKernel(kernels["LeapSecond"]); + loadKernel(kernels["SpacecraftClock"]); + return; + } + + /** + * @brief Add a specified kernel file to the pool + * + * This method adds a specified kernel file to the NAIF pool. The caller can + * provide a file pattern with "?" in the filename as this method will + * determine the highest occuring version. + * + * @param kernel Name of kernel file (or pattern) to add + */ + void SpiceManager::add(const std::string &kernfile) { + + string kfile(kernfile); + + // Check for versionized file naming + string::size_type start = kfile.find_first_of("?"); + if (start != string::npos) { + Filename efile(kfile); + efile.HighestVersion(); + kfile = efile.Expanded(); + } + + // Add a specific kernel to the list + PvlKeyword kernel("Kernels", kfile); + loadKernel(kernel); + return; + } + + /** + * @brief Provide a list of all the kernels found + * + * This method will return all the kernel file references as found in the ISIS + * label. It will optionally remove the file paths and return only the kernel + * file name if requested. If removePath is false, it returns the complete + * path to the SPICE kernels. + * + * @param removePath Do we remove the file paths and return only the file + * names? + * + * @return std::vector A vector of filenames of SPICE kernels + */ + std::vector SpiceManager::getList(bool removePath) const { + std::vector flist; + for (unsigned int i = 0 ; i < _kernlist.size() ; i++) { + if (removePath) { + Filename kfile(_kernlist[i]); + flist.push_back(kfile.Name()); + } + else { + flist.push_back(_kernlist[i]); + } + } + return (flist); + } + + /** + * @brief Unloads all kernels if they were loaded when found + */ + void SpiceManager::Unload() { + if (_furnish) { + for (unsigned int i = 0 ; i < _kernlist.size() ; i++) { + /** + * Changed to work with hipeaks crappy compiler. + * string kernName(Filename(_kernlist[i]).Expanded()); + * unload_c(kernName.c_str()); + */ + Filename f(_kernlist[i]); + string kernName(f.Expanded()); + unload_c(kernName.c_str()); + } + } + _kernlist.clear(); + return; + } + + /** + * @brief Loops through PvlKeyword containing Kernel file names + * + * This method interogates a PvlKeyword that is determined to + * contain SPICE kernel names. It will optionally load the + * kernels if initially requested and then adds the name to the + * internally managed list. + * + * Some keywords may contain special keywords. These are ignored in this + * method and can be handled explicitly in other methods. + * + * @param key PvlKeyword containing SPICE kernels + * @see loadKernelFromTable() + */ + void SpiceManager::loadKernel(PvlKeyword &key) { + for (int i=0; iName()) == "TABLE") { + if (objIter->HasKeyword("Name")) { + if (iString::Equal(objIter->FindKeyword("Name")[0], tblname)) { + loadKernel(objIter->FindKeyword("Kernels")); + return; + } + } + } + } + } + return; + } + /** + * @brief Adds the named kernel file to the internal list + * + * This method will add the name of the kernel file to the list. It will + * first determine if it already exists. If it does, it will not be added a + * second time. + * + * @param kname Name of SPICE kernel file to add + */ + void SpiceManager::addKernelName(const std::string &kname) { + for (unsigned int i = 0 ; i < _kernlist.size() ; i++) { + if (_kernlist[i] == kname) return; + } + _kernlist.push_back(kname); + return; + } + +} // namespace Isis + + diff --git a/isis/src/messenger/apps/mdisedrinfo/SpiceManager.h b/isis/src/messenger/apps/mdisedrinfo/SpiceManager.h new file mode 100644 index 0000000000000000000000000000000000000000..501e342f24844bcfde702e47ef5300280d05a5af --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/SpiceManager.h @@ -0,0 +1,87 @@ +#if !defined(SpiceManager_h) +#define SpiceManager_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2007/08/23 07:15:44 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "Pvl.h" +#include "Cube.h" +#include "Camera.h" +#include "iException.h" + +namespace Isis { + + + /** + * @brief Load/Unload SPICE kernels defined in an ISIS file + * + * This class determines all SPICE kernels associated to an ISIS cube file and + * optionally loads them using the NAIF toolkit. This creates the kernel pool + * as it was when spiceinit determined all the kernels and it initialized the + * file for geometric operations. + * + * Note that ISIS caches of some of the voluminous NAIF kernels, extracting + * only what is required from the SPK and CK (generally) kernels for a given + * observation. After this occurs, these kernels are no longer loaded by the + * ISIS Spice class hierarchy. This class provides that environment so that + * further NAIF operations can occur, such as velocity vectors. + * + * @ingroup Utility + * @author 2007-08-19 Kris Becker + */ +class SpiceManager { + public: + /** Default Constructor */ + SpiceManager() : _kernlist(), _furnish(true) { } + SpiceManager(const std::string &filename, bool furnish = true); + SpiceManager(Cube &cube, bool furnish = true); + SpiceManager(Pvl &pvl, bool furnish = true); + /** Destructor always unloads the kernels from the pool */ + virtual ~SpiceManager() { Unload(); } + + /** Returns the number of kernels found and/or loaded */ + int size() const { return (_kernlist.size()); } + + void Load(Pvl &pvl, bool furnish = true); + void add(const std::string &kernel); + std::vector getList(bool removePath = false) const; + void Unload(); + + + private: + std::vector _kernlist; //!< The list of kernels + bool _furnish; //!< Load the kernels found? + + void loadKernel(PvlKeyword &key); + void loadKernelFromTable(PvlKeyword &key, const std::string &tblname, + Pvl &pvl); + void addKernelName(const std::string &kname); + +}; + +} // namespace Isis +#endif + diff --git a/isis/src/messenger/apps/mdisedrinfo/assets/mdispdskeys.lis b/isis/src/messenger/apps/mdisedrinfo/assets/mdispdskeys.lis new file mode 100644 index 0000000000000000000000000000000000000000..e16c823831f35a62cf9db188a189f02fce5a86c8 --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/assets/mdispdskeys.lis @@ -0,0 +1 @@ +FILENAME;TARGET_NAME;SOURCE_PRODUCT_ID;RA_DEC_REF_PIXEL;RIGHT_ASCENSION;DECLINATION;TWIST_ANGLE;RETICLE_POINT_RA;RETICLE_POINT_DECLINATION;SC_TARGET_POSITION_VECTOR;TARGET_CENTER_DISTANCE;SLANT_DISTANCE;CENTER_LATITUDE;CENTER_LONGITUDE;HORIZONTAL_PIXEL_SCALE;VERTICAL_PIXEL_SCALE;SMEAR_MAGNITUDE;SMEAR_AZIMUTH;NORTH_AZIMUTH;RETICLE_POINT_LATITUDE;RETICLE_POINT_LONGITUDE;SUB_SPACECRAFT_LATITUDE;SUB_SPACECRAFT_LONGITUDE;SPACECRAFT_ALTITUDE;SUB_SPACECRAFT_AZIMUTH;SPACECRAFT_SOLAR_DISTANCE;SC_SUN_POSITION_VECTOR;SC_SUN_VELOCITY_VECTOR;SOLAR_DISTANCE;SUB_SOLAR_AZIMUTH;SUB_SOLAR_LATITUDE;SUB_SOLAR_LONGITUDE;INCIDENCE_ANGLE;PHASE_ANGLE;EMISSION_ANGLE;LOCAL_HOUR_ANGLE diff --git a/isis/src/messenger/apps/mdisedrinfo/assets/smear0.msg b/isis/src/messenger/apps/mdisedrinfo/assets/smear0.msg new file mode 100644 index 0000000000000000000000000000000000000000..e11c32c79bddf70b54ffb3eb1dfe296a1b19eb75 --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/assets/smear0.msg @@ -0,0 +1,1753 @@ +Debbie A Cook/GD/USGS/DOI +08/20/2007 06:28 PM To +Kris J Becker/GD/USGS/DOI@USGS +cc + +bcc + +Subject +Fw: Image smear magnitude and azimuth + + + + ----- Forwarded by Debbie A Cook/GD/USGS/DOI on 08/20/2007 06:22 PM ----- + Nat Bachman +08/18/2007 06:59 PM +Please respond to +Nathaniel.Bachman@jpl.nasa.gov + +To +Debbie A Cook +cc +Charles Acton , Boris Semenov +, Edward Wright , Nat Bachman + +Subject +Image smear magnitude and azimuth + + + + +Kris, + +I'm sorry to pass on this bad news, but it looks like these parameters need to be +revisited. I was in late today, but I will try to catch you Tuesday to discuss this some +more. + + Debbie + +Hi Debbie, + +You probably won't be excited to hear this, but---I think you +need to take a hard look at that PICGEO smear routine SMRIMG before +using it. +If you do use it, you may need to modify the outputs to get the correct +azimuth origin and sign. + +The computation that SMRIMG performs was based on my idea of what a +reasonable +smear definition was---this predated the SIS that you cited. The Clementine +EDR SIS in fact uses a significantly different definition. + +Here are the basic technical points I think need to be considered: + +1) SMRIMG works with an input "camera" reference frame whose +Z axis + is assumed to point to a surface point on the target body. Smear + azimuth is computed as a clockwise rotation about the +Z axis, + measured from the +X axis. + + Depending on instrument characteristics, the +X and +Y axes of + this frame may happen to coincide with, respectively, the +sample + and -line directions in a photo, or they may not. This relationship + simply must be checked, and azimuth must be adjusted accordingly. + My guess is that you usually *will* need to adjust the azimuth + direction. + +2) SMRIMG computes the smear of the projection of a fixed surface point + on the X-Y plane of the frame defined by TICAM. The "direction" of + the smear points in the direction of the velocity of the point's image + on the camera's X-Y plane. Imagine a point light source fixed on + the target body's surface; the smear direction points from the + image of the light source at shutter open to the image of the + source at shutter close. + + The EDR SIS, on the other hand, considers the smear direction to + be the direction of the projection onto the camera's X-Y plane + of the velocity of the boresight intercept. Imagine the boresight + spray-painting the target as it travels along the target + surface; the velocity vector points from the surface point + at the start of the paint trail to that at the end. So the EDR + SIS definition calls for a smear direction that points in the + opposite direction of that found by SMRIMG, all other factors + being equal. + +3) SMRIMG was intended, as the header says, to be used in the + context of a specific program, namely PICGEO. SMRIMG does + basically no error checking. So your software needs to make + sure that SMRIMG is fed reasonable inputs. + +4) You need to decide whether camera angular velocity should be + used or zeroed out. Boris has observed that angular velocity + data from CKs can be garbage---it depends on the situation. + As you can imagine, smear is very sensitive to camera angular + velocity, so bad angular velocity data can invalidate the + results. + +I personally feel that my own smear definition is superior to +that of the EDR SIS, because 1) it doesn't depend on any +model of the target body's surface (in particular, it applies +without modification to plate models and DEMs) and 2) it's computationally +simpler than what's prescribed by the EDR SIS, even if the target is +assumed to be an ellipsoid. This is not to say that you should use the +SMRIMG code: it's probably not useful to you have a routine +that I prefer but that doesn't implement the specifications +you're using. :) In any case, a SPICE-quality smear routine +would rely on frame kernels to define both the camera frame and the +photo frame, so the correct smear sign and offset could be automatically +determined by the routine. It would also have robust error checking. + +Now, about software implementing the EDR SIS smear definition: NAIF +did create a routine called SMEARV_M, originally intended for use by +Mars Observer, +I think, that does part of this computation: it finds a boresight intercept +and the velocity of that intercept on the target surface. This routine +predates SRFXPT by many years; it doesn't do accurate aberration corrections +for a surface point, and it presumes that TISBOD can be used to find +the inertial-to-bodyfixed reference frame transformation for the target, +which means it can't be used with body-fixed frames other than the +IAU_* defaults. However, if you like, you could modify this routine to +make it do what you want. The pure math routine it calls, SURFPV_M, I +think is carefully written; it may be useful even if you prefer to ignore +SMEARV_M. + +I'm attaching the source code of the *_M routines to this e-mail. SMRIMG +is included for reference. + + -Nat + + + + + + + + + + + + + + + + + +C$Procedure SMEARV_M ( Smear velocity ) + + SUBROUTINE SMEARV_M ( TARGET, + . OBSRVR, + . ET, + . U, + . DU, + . REFIN, + . ABCORR, + . SP, + . DSP, + . FOUND ) + +C$ Abstract +C +C Determine the instantaneous velocity of a surface intercept +C vector with respect to the surface of the target body at the +C intercept point. Also find the coordinates of the intercept point. +C +C$ Disclaimer +C +C THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE +C CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. +C GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE +C ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE +C PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" +C TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY +C WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A +C PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC +C SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE +C SOFTWARE AND RELATED MATERIALS, HOWEVER USED. +C +C IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA +C BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT +C LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, +C INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, +C REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE +C REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. +C +C RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF +C THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY +C CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE +C ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. +C +C$ Required_Reading +C +C None. +C +C$ Keywords +C +C GEOMETRY +C +C$ Declarations + + INTEGER TARGET + INTEGER OBSRVR + DOUBLE PRECISION ET + DOUBLE PRECISION U ( 3 ) + DOUBLE PRECISION DU ( 3 ) + CHARACTER*(*) REFIN + CHARACTER*(*) ABCORR + DOUBLE PRECISION SP ( 3 ) + DOUBLE PRECISION DSP ( 3 ) + LOGICAL FOUND + +C$ Brief_I/O +C +C Variable I/O Description +C -------- --- -------------------------------------------------- +C TARGET I NAIF integer code of target body. +C OBSRVR I NAIF integer code of observing body. +C ET I Epoch at which the velocity is to be computed. +C U I An inertially referenced vector. +C DU I Velocity of U. +C REFIN I Reference frame of U and DU. +C ABCORR I Aberration correction. +C SP O Location on the target body towards which U points. +C DSP O Velocity of SP. +C FOUND O True if SP exists and DSP can be computed. +C +C$ Detailed_Input +C +C TARGET is the NAIF integer code of a target body. +C This routine assumes that this body is modelled +C by a tri-axial ellipsoid, and that a PCK file +C containing its radii and rotation model constants +C has been loaded into the kernel pool. +C +C OBSRVR is the NAIF integer code of the observing body +C which is normally a spacecraft. +C +C ET is the time, measured in ephemeris seconds past +C J2000, at which the surface intercept point and its +C velocity are to be computed. +C +C Note that SPK ephemeris data covering the epoch ET +C for the TARGET and OBSRVR must be loaded via SPKLEF +C before calling SMEARV_M. +C +C U is the inertially referenced pointing or line-of- +C sight vector of an instrument on the observing body +C at ET. U is time-varying, but the length of U is +C constant. Normally, the ray emanating from the +C observing body in the direction of U intersects +C the target body. +C +C DU is the inertially referenced velocity of the pointing +C vector U at ET. Note that if AV is the angular +C velocity vector, then DU is the cross product of AV +C and U: +C +C DU = AV X U +C +C The angular velocity vector is the vector whose +C direction gives the axis about which an instrument- +C fixed reference frame is rotating, and whose +C magnitude is equal to the magnitude of the rotation +C velocity in radians per second. (In the SPICE system, +C angular velocity vectors are stored in CK files.) +C +C REFIN is the name of the inertial frame to which U and DU +C are referenced. This must be a frame supported +C by the SPICELIB subroutine CHGIRF, such as 'J2000'. +C +C ABCORR indicates the aberration corrections to be applied +C in order to determine the state of the target body. +C ABCORR may be any of the following; case and spacing +C are not significant. +C +C 'NONE' Apply no correction. Return the true +C state of the target body relative to +C the observer. +C +C 'LT' Correct for planetary (light time) +C aberration. +C +C 'LT+S' Correct for planetary and stellar +C aberrations. +C +C$ Detailed_Output +C +C SP, +C DSP are, respectively, the body-fixed coordinates of the +C surface intercept point, and its instantaneous +C velocity vector at time ET. +C +C That is, if the ray with direction vector U, +C emanating from the position of the observer, +C intersects the target, AND if the velocity of +C the intercept point is small enough to be computed, +C then SP will be the body-fixed coordinates of the +C intercept point, and DSP will be the instantaneous +C velocity of that point on the surface of the target +C body. This velocity vector lies in the plane that +C is tangent to the target body at SP. +C +C If the ray in the direction of U misses the target, +C or if the velocity of the intercept point is too large +C to be computed, as when the intercept point is on the +C limb where its velocity is infinite, SP and DSP are +C undefined. +C +C In the body-fixed coordinate system, the center of +C the ellipsoid model of the target body is at the +C origin, and the semi-axes of the ellipsoid are +C aligned with the x, y, and z-axes. SP and DSP +C are referenced to this body-fixed frame. +C +C FOUND is a logical flag that is set to .TRUE. if both SP +C exists and DSP can be computed, and otherwise, .FALSE. +C +C$ Parameters +C +C None. +C +C$ Exceptions +C +C 1) If OBSRVR is equal to TARGET, the error +C SPICE(BODIESNOTDISTINCT) is signalled. +C +C 2) If the pointing vector U is the zero vector, then +C a subroutine that SMEARV_M calls will diagnose and +C signal an error. +C +C 3) If the reference frame REFIN is not supported by the +C current version of CHGIRF, an error is diagnosed and +C signalled by a routine that SMEARV_M calls. +C +C 4) If the value of ABCORR is not recognized, an error is +C diagnosed and signalled by a routine that SMEARV_M calls. +C +C 5) If no SPK ephemeris file has been loaded prior to calling +C SMEARV_M, or if the SPK data has insufficient coverage, an +C error will be diagnosed and signalled by a routine that +C SMEARV_M calls. +C +C 6) If a PCK file containing the radii and rotation model constants +C of the target body has not been loaded prior to calling +C SMEARV_M, an error will be diagnosed and signalled by a +C routine that SMEARV_M calls. +C +C 7) If SP is on or too close to the limb, FOUND will be returned +C with the value .FALSE. and both SP and DSP will be unchanged. +C +C$ Files +C +C No files are input to this routine, however, SMEARV_M expects +C that the appropriate SPK and PCK files have been loaded using +C SPKLEF and LDPOOL, respectively. +C +C$ Particulars +C +C SMEARV_M determines the state of the observing body with respect +C to the target body at the requested time. It computes the +C intercept point of a ray emanating from the position of the +C observing body in the direction of the pointing vector, U, +C with the target body. +C +C SMEARV_M also returns the velocity vector of that intercept point +C which is tangent to the target body's surface at the intercept +C point. This velocity includes the effects of the velocity of the +C observer, the velocity of the pointing vector, the rotation of +C the target body, and the light-time between the observing and +C the target bodies. +C +C$ Examples +C +C The following code example computes the coordinates and +C velocity of the point on Mars where the boresight ray of the +C Mars Observer camera intersects the surface at a given +C spacecraft clock time. +C +C The following data files are needed: +C +C 1) A Mars Observer C-kernel file. +C 2) An SPK file containing ephemeris data for MO and Mars. +C 3) An MOC I-kernel file. +C 4) A Mars Observer SCLK file. +C 5) A planetary constants kernel file. +C +C Light time correction will be used when computing the state of +C Mars relative to Mars Observer. +C +C INTEGER FILEN +C PARAMETER ( FILEN = 128 ) +C +C INTEGER TIMLEN +C PARAMETER ( TIMLEN = 40 ) +C +C INTEGER MO +C PARAMETER ( MO = -94 ) +C +C INTEGER MOC +C PARAMETER ( MOC = -94030 ) +C +C INTEGER MARS +C PARAMETER ( MARS = 499 ) +C +C CHARACTER*(*) ABCORR +C PARAMETER ( ABCORR = 'LT' ) +C +C CHARACTER*(*) REF +C PARAMETER ( REF = 'J2000' ) +C +C CHARACTER*(FILEN) BSPFIL +C CHARACTER*(FILEN) BCFIL +C CHARACTER*(FILEN) TSCFIL +C CHARACTER*(FILEN) TPCFIL +C CHARACTER*(FILEN) TIFIL +C CHARACTER*(TIMLEN) SCLKCH +C CHARACTER*(TIMLEN) TOLCH +C +C INTEGER BCHAN +C INTEGER BSPHAN +C +C DOUBLE PRECISION AV ( 3 ) +C DOUBLE PRECISION CLKOUT +C DOUBLE PRECISION DSP ( 3 ) +C DOUBLE PRECISION DU ( 3 ) +C DOUBLE PRECISION ET +C DOUBLE PRECISION SP ( 3 ) +C DOUBLE PRECISION U ( 3 ) +C +C LOGICAL FOUND +C C +C C SPICELIB functions +C C +C DOUBLE PRECISION VNORM +C +C C +C C Get all the data files and load them. +C C +C WRITE (*,*) 'Enter name of MO SPK file' +C READ (*,FMT='(A)') BSPFIL +C +C WRITE (*,*) 'Enter name of MO CK file' +C READ (*,FMT='(A)') BCFIL +C +C WRITE (*,*) 'Enter name of MO SCLK file' +C READ (*,FMT='(A)') TSCFIL +C +C WRITE (*,*) 'Enter name of MOC I-kernel file' +C READ (*,FMT='(A)') TIFIL +C +C WRITE (*,*) 'Enter name of planetary constants kernel file' +C READ (*,FMT='(A)') TPCFIL +C +C CALL SPKLEF ( BSPFIL, BSPHAN ) +C CALL CKLPF ( BCFIL, BCHAN ) +C CALL LDPOOL ( TSCFIL ) +C CALL LDPOOL ( TIFIL ) +C CALL LDPOOL ( TPCFIL ) +C +C C +C C At what time and tolerance do we need the pointing? +C C +C WRITE (*,*) 'Enter the SCLK time for which you wish ' // +C 'to find the velocity of the point where' +C WRITE (*,*) 'the MOC''s boresight intersects the surface' +C READ (*,FMT='(A)') SCLKCH +C +C WRITE (*,*) 'Enter C-kernel tolerance' +C READ (*,FMT='(A)') TOLCH +C +C C +C C Get the MOC's boresight vector and its angular velocity +C C vector; the MOSPICE routine INSVAV_M returns this given +C C an instrument ID, SCLK time and tolerance, and an inertial +C C reference frame. The inertial reference frame, REF, in this +C C case, is 'J2000'. +C C +C CALL INSVAV_M ( MOC, +C . SCLKCH, +C . TOLCH, +C . REF, +C . U, +C . AV, +C . CLKOUT, +C . FOUND ) +C +C CALL SCT2E ( MO, CLKOUT, ET ) +C +C C +C C Compute the velocity of U, the boresight vector. +C C +C CALL VCRSS ( AV, U, DU ) +C +C C +C C Now we have all of the inputs. Compute the smear velocity. +C C +C CALL SMEARV_M ( MARS, +C . MO, +C . ET, +C . U, +C . DU, +C . REF, +C . ABCORR, +C . SP, +C . DSP, +C . FOUND ) +C +C C +C C Write the results. +C C +C WRITE (*,*) 'Mars body fixed coordinates where the ' // +C . 'MOC''s boresight vector intersects the' +C WRITE (*,*) 'surface:' +C WRITE (*,*) +C WRITE (*,*) ' x = ', SP (1) +C WRITE (*,*) ' y = ', SP (2) +C WRITE (*,*) ' z = ', SP (3) +C +C WRITE (*,*) 'Velocity of the boresight-surface ' // +C . 'intercept point:' +C WRITE (*,*) +C WRITE (*,*) ' dx/dt = ', DSP (1) +C WRITE (*,*) ' dy/dt = ', DSP (2) +C WRITE (*,*) ' dz/dt = ', DSP (3) +C WRITE (*,*) 'magnitude = ', VNORM ( DSP) +C +C END +C +C$ Restrictions +C +C None. +C +C$ Literature_References +C +C None. +C +C$ Author_and_Institution +C +C J.E. McLean (JPL) +C M.J. Spencer (JPL) +C +C$ Version +C +C- MOSPICE Version 1.0.1, 10-MAR-1992 (WLT) +C +C Comment section for permuted index source lines was added +C following the header. +C +C- MOSPICE Version 1.0.0, 05-SEP-1990 (MJS) +C +C This subroutine is an MO version of the GLLSPICE subroutine +C SMEARV_G, version 1.0.0, dated 06-NOV-1990, by JEM. The +C following changes were performed: +C +C 1) The name of the module was changed from SMEARV_G to +C SMEARV_M; +C 2) A new argument was added to the calling sequence: +C ABCORR, the aberration correction that is to be applied +C when computing the state of the target body. Previously, +C the type of aberration correction applied was hard- +C coded; 'LT', light time, was used. If this argument +C equals 'NONE', the epoch passed to TISBOD is ET; +C otherwise, ET-LT. Since this argument must be checked +C locally, ABCORR is compressed and placed in the local +C variable CORR; CORR, then, is converted to upper case. +C 3) The names of all the GLLSPICE routines mentioned in this +C module were changed to their MOSPICE equivalents +C (SURFPV_G was changed to SURFPV_M); +C 4) The examples section was re-done -- instead of +C computing the smear velocity vector on Earth in an SSI +C picture, the coordinates and the velocity of the point +C on Mars where the MOC boresight vector intersects the +C surface is computed. +C +C-& + +C$ Index_Entries +C +C smear velocity +C +C-& + + +C +C SPICELIB functions +C + LOGICAL RETURN + +C +C Local Parameters +C +C A state is a 6 dimensional array. The first three components +C represent a position, the second three represent the time +C derivative of that position. POS and VEL are indices into +C a state array. +C + INTEGER POS + PARAMETER ( POS = 1 ) + + INTEGER STDIM + PARAMETER ( STDIM = 6 ) + + INTEGER VEL + PARAMETER ( VEL = 4 ) + +C +C Local variables +C + CHARACTER*(5) CORR + + DOUBLE PRECISION LT + DOUBLE PRECISION RADII ( 3 ) + DOUBLE PRECISION STIBF ( STDIM ) + DOUBLE PRECISION STOBF ( STDIM ) + DOUBLE PRECISION STOI ( STDIM ) + DOUBLE PRECISION STUBF ( STDIM ) + DOUBLE PRECISION STUI ( STDIM ) + DOUBLE PRECISION STTI ( STDIM ) + DOUBLE PRECISION TSIBF ( STDIM, STDIM ) + + INTEGER NRADII + +C +C Standard SPICE error handling. +C + IF ( RETURN () ) THEN + RETURN + ELSE + CALL CHKIN ( 'SMEARV_M' ) + END IF + +C +C Initialization +C + FOUND = .FALSE. + +C +C Remove all spaces from ABCORR and place the resulting string +C in CORR; then, convert CORR to upper case. +C + CALL CMPRSS ( ' ', 0, ABCORR, CORR ) + CALL UCASE ( CORR, CORR ) + +C +C Check the input body codes. If they are equal, signal +C an error. +C + IF ( OBSRVR .EQ. TARGET ) THEN + + CALL SETMSG ( 'In computing smear velocity, the observing ' // + . 'and the target body are the same.' ) + CALL SIGERR ( 'SPICE(BODIESNOTDISTINCT)' ) + CALL CHKOUT ( 'SMEARV_M' ) + RETURN + + END IF + +C +C Get the state of the target body, using the requested aberration +C correction, as seen from the observing body at ET in the same +C inertial frame as the pointing vectors. +C + CALL SPKEZ ( TARGET, ET, REFIN, CORR, OBSRVR, STTI, LT ) + +C +C Negate STTI so that it is the inertially referenced state of +C the observer as seen by the target. +C + CALL VMINUG ( STTI, STDIM, STOI ) + +C +C Now we need the state of the observer in target body-fixed +C coordinates, STOBF: +C +C Let POI and VOI be the position and velocity vectors of the +C observer in inertial coordinates. That is STOI = ( POI, VOI ). +C Let TIBF be the 3x3 transformation matrix that rotates vectors +C from inertial to body-fixed coordinates. Then the position of +C the observer in body-fixed coordinates is the product of TIBF and +C POI: +C +C POBF = TIBF * POI +C +C The velocity of the observer in body-fixed coordinates is the +C derivative of POBF, +C +C d POBF d (TIBF * POI) +C VOBF = ------ = -------------- = DTIBF * POI + TIBF * VOI +C dt dt +C +C where DTIBF is the derivative of the transformation matrix TIBF. +C Thus the following 6x6 matrix, TSIBF, when multiplied by STOI, +C transforms the entire state to body-fixed coordinates. +C +C +- -+ +- -+ +- -+ +C | TIBF 0 | | POI | | POBF | +C TSIBF * STOI = | | * | | = | | = STOBF +C | DTIBF TIBF | | VOI | | VOBF | +C +- -+ +- -+ +- -+ +C +C +C TISBOD generates this 6x6 matrix, TSIBF, to transform an inertial +C state to body-fixed coordinates at a particular epoch. If we are +C taking into account light time corrections, our epoch must be +C ET-LT. +C + IF ( CORR .EQ. 'NONE' ) THEN + + CALL TISBOD ( REFIN, TARGET, ET, TSIBF ) + + ELSE + + CALL TISBOD ( REFIN, TARGET, ET-LT, TSIBF ) + + ENDIF + + CALL MXVG ( TSIBF, STOI, STDIM, STDIM, STOBF ) + +C +C We also need U and DU in body-fixed coordinates. Pack +C U and DU into a state, STUI, and multiply by TSIBF. +C + CALL VEQU ( U, STUI ( POS ) ) + CALL VEQU ( DU, STUI ( VEL ) ) + + CALL MXVG ( TSIBF, STUI, STDIM, STDIM, STUBF ) + +C +C Now we get the radii of the ellipsoid model of the target +C body. +C + CALL BODVAR ( TARGET, 'RADII', NRADII, RADII ) + +C +C Finally, we call the geometry routine SURFPV_M, which +C takes the body-fixed states of the observer and +C pointing vector and the ellipsoid model, and +C computes the intercept point and the velocity of +C that point on the surface of the ellipsoid. +C + CALL SURFPV_M ( STOBF, STUBF, + . RADII(1), RADII(2), RADII(3), + . STIBF, FOUND ) + + IF ( .NOT. FOUND ) THEN + CALL CHKOUT ( 'SMEARV_M' ) + RETURN + END IF + +C +C STIBF, is the body-fixed state of the intercept point. +C + CALL VEQU ( STIBF ( POS ), SP ) + CALL VEQU ( STIBF ( VEL ), DSP ) + + CALL CHKOUT ( 'SMEARV_M' ) + RETURN + END +C$Procedure SURFPV_M ( Surface point and velocity ) + + SUBROUTINE SURFPV_M ( STO, STU, A, B, C, STI, FOUND ) + +C$ Abstract +C +C Determine the intersection of a line-of-sight vector with the +C surface of an ellipsoid and the velocity of the intercept +C point on the surface. +C +C$ Disclaimer +C +C THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE +C CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. +C GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE +C ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE +C PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" +C TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY +C WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A +C PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC +C SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE +C SOFTWARE AND RELATED MATERIALS, HOWEVER USED. +C +C IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA +C BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT +C LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, +C INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, +C REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE +C REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. +C +C RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF +C THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY +C CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE +C ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. +C +C$ Required_Reading +C +C None. +C +C$ Keywords +C +C ELLIPSOID +C GEOMETRY +C +C$ Declarations + + DOUBLE PRECISION STO ( 6 ) + DOUBLE PRECISION STU ( 6 ) + DOUBLE PRECISION A + DOUBLE PRECISION B + DOUBLE PRECISION C + DOUBLE PRECISION STI ( 6 ) + LOGICAL FOUND + +C$ Brief_I/O +C +C Variable I/O Description +C -------- --- -------------------------------------------------- +C STO I State of the observer in body-fixed coordinates +C STU I State of a line-of-sight vector: U and dU/dt. +C A I Length of the ellipsoid semi-axis along the x-axis +C B I Length of the ellipsoid semi-axis along the y-axis +C C I Length of the ellipsoid semi-axis along the z-axis +C STI O State of the intercept point on the ellipsoid. +C FOUND O Can the state of the intercept point be determined? +C +C$ Detailed_Input +C +C STO is a 6-vector giving the body-fixed state of an +C observer. The first three elements are the body-fixed +C coordinates of the position of the observer; the last +C three elements are the components of the observer's +C velocity in the body-fixed frame. In the body-fixed +C frame, the center of the ellipsoid is at the origin, +C and the semi-axes of the ellipsoid are aligned with +C the x, y, and z-axes. +C +C STU is a 6-vector giving the body-fixed state of a +C line-of-sight vector. The first three elements are +C a vector, U, that presumably points in the direction +C of the ellipsoid; the length of this vector is +C constant. The last three elements are the velocity of +C the vector, U; we'll call it DU. So, STU = ( U, DU ). +C +C Note that if AV is the angular velocity vector, +C then DU is the cross product of AV and U: +C +C DU = AV X U +C +C The angular velocity vector is the vector whose +C direction gives the axis about which an instrument- +C fixed reference frame is rotating, and whose +C magnitude is equal to the magnitude of the rotation +C velocity in radians per second. (In the SPICE system, +C angular velocity vectors are stored in CK files.) +C +C A is the length of the semi-axis of the ellipsoid +C that is parallel to the x-axis of the body-fixed +C coordinate system. +C +C B is the length of the semi-axis of the ellipsoid +C that is parallel to the y-axis of the body-fixed +C coordinate system. +C +C C is the length of the semi-axis of the ellipsoid +C that is parallel to the z-axis of the body-fixed +C coordinate system. +C +C$ Detailed_Output +C +C STI is the body-fixed state of the surface intercept point, +C if it exists. +C +C That is, if the ray with direction vector U, +C emanating from the position of the observer, +C intersects the ellipsoid, AND if the velocity of +C the intercept point is small enough to be computed, +C then the first three elements of STI will be the +C body-fixed coordinates of the first intercept +C point, and the last three elements of STI will be the +C instantaneous velocity of that point on the surface +C of the ellipsoid. This velocity vector lies in +C the plane that is tangent to the ellipsoid at the +C intercept point. +C +C If there is no intersection, or if the velocity is +C too large to be computed, as when the intercept point +C is on the limb where its velocity is infinite, STI +C is undefined. +C +C FOUND is a logical flag indicating whether or not the +C state of the intercept point exists and can be +C computed. If STI is defined, FOUND will be +C returned as .TRUE. otherwise it will be false. +C +C$ Parameters +C +C None. +C +C$ Exceptions +C +C 1) If the input line-of-sight vector is the zero vector, that +C is, if the first three elements of STU are all zero, then +C a subroutine that SURFPV_M calls will diagnose and signal +C an error. +C +C 2) If any of the body's axes, A, B, or C, is nonpositive, +C a subroutine that SURFPV_M calls will diagnose and signal +C an error. +C +C$ Files +C +C None. +C +C$ Particulars +C +C The position and velocity of the observer as well as the +C line-of-sight vector and its velocity vary with time. The +C inputs to SURFPV_M may be considered the values of these +C vector functions at a particular time, say t0. Thus +C +C State of observer: STO = ( P(t0), P'(t0) ) +C +C State of pointing vector: STU = ( U(t0), U'(t0) ) +C +C To determine the intercept point, I(t0), we simply compute the +C geometrical intersection of the ray originating at P(t0) +C in the direction of U(t0) with the ellipsoid +C +C 2 2 2 +C x y z +C --- + --- + --- = 1 +C 2 2 2 +C A B C +C +C I(t) is the path of the intercept point along the surface of +C the ellipsoid. To determine the velocity of the intercept point, +C we need to take the time derivative of I(t), and evaluate it at +C t0. Unfortunately I(t) is a complicated expression, and its +C derivative is even more complicated. +C +C However, we know that the derivative of I(t) at t0, I'(t0), +C is tangent to I(t) at t0. Thus I'(t0) lies in the plane that +C is tangent to the ellipsoid at t0. Let J(t) be the curve in the +C in the tangent plane that represents the intersection of the +C ray emanating from P(t0) with direction U(t0) with that tangent +C plane. +C +C J'(t0) = I'(t0). +C +C The expression for J'(t) is much simpler than that of I'(t); +C SURFPV_M evaluates J'(t) at t0. +C +C +C Derivation of J(t) and J'(t) +C ---------------------------------------------------------------- +C +C I(t0) is the intercept point. Let N be a surface normal at I(t0). +C Then the tangent plane at I(t0) is the set of points X such that +C +C < X - I(t0), N > = 0. +C +C J(t) can be expressed as the vector sum of the position of the +C observer and some scalar multiple of the line-of-sight vector, +C +C J(t) = P(t) + s(t) * U(t), +C +C where s(t) is a scalar function of time. The derivative of +C J(t) is given by +C +C J'(t) = P'(t) + s(t) * U'(t) + s'(t) * U(t). +C +C We have P(t0), P'(t0), U(t0), U'(t0), I(t0), and N, but to +C evaluate J'(t0), we need s(t0) and s'(t0). We derive an +C expression for s(t) as follows. +C +C Because J(t) is in the tangent plane, it must satisfy +C +C < J(t) - I(t0), N > = 0. +C +C Substituting the expression for J(t) into the equation above +C gives +C +C < P(t) + s(t) * U(t) - I(t0), N > = 0. +C +C Thus +C +C < P(t) - I(t0), N > + s(t) * < U(t), N > = 0, +C +C and +C - < P(t) - I(t0), N > +C s(t) = -------------------- +C < U(t), N > +C +C The derivative of s(t) is given by +C +C s'(t) = +C +C - ( < U(t),N > * < P'(t),N > - < P(t)-I(t0),N > * < U'(t),N > ) +C ----------------------------------------------------------------- +C 2 +C < U(t), N > +C +C +C$ Examples +C +C This code example shows how the routine SMEARV_M uses SPKEZ to +C get a state vector and then transforms it to body-fixed +C coordinates for input to SURFPV_M. The output from SURFPV_M +C and SMEARV_M are the same. SMEARV_M is really a high level +C interface to the geometry routine SURFPV_M. +C +C In this example, we assume U and DU are the direction and +C velocity of the line-of-sight vector and are referenced to +C the inertial frame, REFIN. Also, we assume that the +C appropriate SPK and PCK files have been loaded. +C +C C +C C Get the state of the target body as seen from the +C C observing body at time ET in the same inertial frame as the +C C pointing vectors. The argument ABCORR indicates the +C C aberration corrections to be applied in order to determine +C C this state. ABCORR is passed as an argument to SMEARV_M; it +C C may be any of the following. +C C +C C 'NONE' Apply no correction. Return the true +C C state of the target body relative to +C C the observer. +C C +C C 'LT' Correct for planetary (light time) +C C aberration. +C C +C C 'LT+S' Correct for planetary and stellar +C C aberrations. +C C +C CALL SPKEZ ( TARGET, ET, REFIN, ABCORR, OBSRVR, STTI, LT ) +C +C C +C C Negate STTI so that it is the inertially referenced state +C C of the observer as seen by the target. +C C +C CALL VMINUG ( STTI, 6, STOI ) +C +C C +C C Now we need the state of the observer in target body-fixed +C C coordinates, STOBF. TISBOD generates the 6x6 matrix TSIBF +C C that transforms an inertial state to body-fixed coordinates +C C at a particular epoch. If we are taking into account light +C C time corrections, our epoch must be ET-LT. +C C +C IF ( ABCORR .EQ. 'NONE' ) THEN +C +C CALL TISBOD ( REFIN, TARGET, ET, TSIBF ) +C +C ELSE +C +C CALL TISBOD ( REFIN, TARGET, ET-LT, TSIBF ) +C +C ENDIF +C +C CALL MXVG ( TSIBF, STOI, 6, 6, STOBF ) +C +C C +C C We also need U and DU in body-fixed coordinates. Pack +C C U and DU into a state, STUI, and multiply by TSIBF. +C C +C CALL VEQU ( U, STUI ( 1 ) ) +C CALL VEQU ( DU, STUI ( 4 ) ) +C +C CALL MXVG ( TSIBF, STUI, 6, 6, STUBF ) +C +C C +C C Now we get the radii of the ellipsoid model of the target +C C body from the kernel pool. +C C +C CALL BODVAR ( TARGET, 'RADII', NRADII, RADII ) +C +C C +C C Finally, we call the geometry routine SURFPV_M, which +C C takes the body-fixed states of the observer and +C C pointing vector and the ellipsoid model, and +C C computes the intercept point and the velocity of +C C that point on the surface of the ellipsoid. +C C +C CALL SURFPV_M ( STOBF, STUBF, +C . RADII(1), RADII(2), RADII(3), +C . STIBF, FOUND ) +C +C C +C C STIBF, is the body-fixed state of the intercept point. +C C +C IF ( FOUND ) THEN +C +C WRITE (*,*) 'Intercept point:' +C WRITE (*,*) ' x = ', STIBF ( 1 ) +C WRITE (*,*) ' y = ', STIBF ( 2 ) +C WRITE (*,*) ' z = ', STIBF ( 3 ) +C WRITE (*,*) ' dx/dt = ', STIBF ( 4 ) +C WRITE (*,*) ' dy/dt = ', STIBF ( 5 ) +C WRITE (*,*) ' dz/dt = ', STIBF ( 6 ) +C +C END IF +C +C$ Restrictions +C +C None. +C +C$ Literature_References +C +C None. +C +C$ Author_and_Institution +C +C J.E. McLean (JPL) +C +C$ Version +C +C- MOSPICE Version 1.0.1, 10-MAR-1992 (WLT) +C +C Comment section for permuted index source lines was added +C following the header. +C +C- MOSPICE Version 1.0.0, 05-SEP-1991 (MJS) +C +C This subroutine is an MO version of the GLLSPICE subroutine +C SURFPV_G, version 1.0.0, dated 19-OCT-1990, by JEM. The name +C of the routine was changed from SURFPV_G to SURFPV_M, and the +C names of all the GLLSPICE routines mentioned in this module +C were changed to their MOSPICE equivalents (SMEARV_G was +C changed to SMEARV_M). It was also noted in the example section +C that the routine SMEARV_M accepts, as an argument, the +C aberration correction that is to be applied in order to +C compute the state of the target body; this was not mentioned +C previously because the routine SMEARV_G did not accept an +C aberration correction argument, rather, it assumed light time +C correction. +C +C-& + +C$ Index_Entries +C +C surface point and velocity +C +C-& + + +C +C SPICELIB functions +C + LOGICAL RETURN + + DOUBLE PRECISION DPMAX + DOUBLE PRECISION VDOT + DOUBLE PRECISION VNORM + + +C +C Local variables +C + DOUBLE PRECISION DP ( 3 ) + DOUBLE PRECISION DU ( 3 ) + DOUBLE PRECISION I ( 3 ) + DOUBLE PRECISION M + DOUBLE PRECISION N ( 3 ) + DOUBLE PRECISION P ( 3 ) + DOUBLE PRECISION PMI ( 3 ) + DOUBLE PRECISION S + DOUBLE PRECISION SECOND ( 3 ) + DOUBLE PRECISION STUHAT ( 6 ) + DOUBLE PRECISION THIRD ( 3 ) + DOUBLE PRECISION U ( 3 ) + + + +C +C Standard SPICE error handling. +C + IF ( RETURN () ) THEN + RETURN + ELSE + CALL CHKIN ( 'SURFPV_M' ) + END IF + + +C +C Determine the ellipsoid surface intercept point of the +C ray emanating from the observer in the direction of U. +C We'll call it I and it will go in the first three +C elements of STI once we determine the velocity. If there +C is no intersection, we check out. +C +C SURFPT takes care of some error checking too. It signals +C an error if U is the zero vector or if A, B, or C are bad +C axis lengths. +C + CALL SURFPT ( STO, STU, A, B, C, I, FOUND) + + IF ( .NOT. FOUND ) THEN + CALL CHKOUT ( 'SURFPV_M' ) + RETURN + END IF + +C +C U is useful for its direction only. Normalize U and divide +C DU by the same scalar. We know that the norm of U is not zero +C because SURFPT checked it. +C + CALL VSCLG ( 1.0D0 / VNORM( STU ), STU, 6, STUHAT ) + + +C +C The velocity vector of the intercept point goes in the last three +C elements of STI. Let +C +C I = I(t0) DI = I'(t0) +C P = P(t0) DP = P'(t0) +C U = U(t0) / | U(t0) | DU = U'(t0) / | U(t0) | +C +C and N be the unit normal to the ellipsoid surface at I. +C Then, from the derivation in $ Particulars above, +C +C DI = +C +C +C < P-I,N > < U,N > < DP,N > - < P-I,N > < DU,N > +C DP - --------- DU - ------------------------------------- U +C < U,N > 2 +C < U,N > +C +C + +C +C Compute the unit normal at the intercept point, and unpack +C the input states into P, U, DP, and DU. Let P-I = PMI +C + CALL SURFNM ( A, B, C, I, N ) + + CALL VEQU ( STO, P ) + CALL VEQU ( STUHAT, U ) + + CALL VEQU ( STO(4), DP ) + CALL VEQU ( STUHAT(4), DU ) + + CALL VSUB ( P, I, PMI ) + +C +C As the intercept point nears the limb, it's velocity goes to +C infinity. We must check the value of < U,N > before dividing +C by it. If the intercept point is on the limb < U,N > = 0. +C If it is near the limb, < U,N > may be so small that dividing +C by would result in a number that is greater than the maximum +C double precision number for the computer. +C + + IF ( VDOT ( U,N ) .EQ. 0.D0 ) THEN +C +C The intercept point is on the the limb, so its velocity +C is infinite. This means we can't "find" the state +C of the intercept point. +C + FOUND = .FALSE. + CALL CHKOUT ( 'SURFPV_M' ) + RETURN + END IF + +C +C Evaluate the second term of the equation for DI, but don't +C divide by < U,N > just yet. +C + CALL VSCL ( VDOT ( PMI,N ), DU, SECOND ) +C +C 2 +C Evaluate the third term, but don't divide by < U,N > just yet. +C + S = VDOT ( U,N ) * VDOT ( DP,N ) - VDOT ( PMI,N ) * VDOT ( DU,N ) + + CALL VSCL ( S, U, THIRD ) + +C +C We'll use the following test. +C +C Let +C + M = MAX ( VNORM (SECOND), VNORM (THIRD), 1.0D0 ) + +C +C +C If +C +C M DPMAX +C ------- > ----- +C 2 +C < U,N > 10 +C +C +C That is, if +C 2 +C M > DPMAX * < U,N > / 10 +C +C +C where DPMAX is the largest double precision number, +C then, the velocity is probably too large to compute. +C We know that we can perform the multiplication above +C because U and N are both unit vectors, so the dot +C product of U and N is less than or equal to one. +C + + IF ( M .GT. ( DPMAX() / 10.0D0 ) * VDOT ( U,N ) ** 2 ) THEN + FOUND = .FALSE. + CALL CHKOUT ( 'SURFPV_M' ) + RETURN + END IF + + +C +C If < U,N > passed the tests above, we can solve for the velocity. +C +C 2 +C DI = DP - SECOND / < U,N > - THIRD / < U,N > +C +C + S = 1.0D0 / VDOT ( U, N ) + + CALL VLCOM3 ( 1.0D0, DP, -S, SECOND, -(S**2), THIRD, STI(4) ) + +C +C Since we could compute the velocity, we can assign the +C intercept point, and set the found flag to .TRUE. +C + CALL VEQU ( I, STI(1) ) + + FOUND = .TRUE. + + CALL CHKOUT ( 'SURFPV_M' ) + RETURN + END + +C$Procedure SMRIMG ( Smear image ) +C + SUBROUTINE SMRIMG ( STARG, + . SURFX, + . TICAM, + . AV, + . TSIPM, + . FOCLEN, + . PXLSCL, + . EXPLEN, + . SMRLEN, + . SMRAZ, + . FOUND ) + + IMPLICIT NONE + +C +C$ Abstract +C +C Determine the smear in an image due to observer and target +C motion. +C +C$ Required_Reading +C +C None. +C +C$ Keywords +C +C GEOMETRY +C +C$ Declarations +C + DOUBLE PRECISION STARG ( 6 ) + DOUBLE PRECISION SURFX ( 3 ) + DOUBLE PRECISION TICAM ( 3, 3 ) + DOUBLE PRECISION AV ( 3 ) + DOUBLE PRECISION TSIPM ( 6, 6 ) + DOUBLE PRECISION FOCLEN + DOUBLE PRECISION PXLSCL + DOUBLE PRECISION EXPLEN + DOUBLE PRECISION SMRLEN + DOUBLE PRECISION SMRAZ + LOGICAL FOUND +C +C$ Brief_I/O +C +C Variable I/O Description +C -------- --- -------------------------------------------------- +C STARG I Inertial target state. +C SURFX I Surface intercept of camera boresight. +C TICAM I Inertial-to-camera transformation matrix. +C AV I Angular velocity of camera (radians/second). +C TSIPM I Inertial-to-bodyfixed state transformation matrix. +C FOCLEN I Camera focal length. +C PXLSCL I Camera pixel scale, (pixels/mm). +C EXPLEN I Exposure length (seconds). +C SMRLEN O Length of smear (pixels). +C SMRAZ O Azimuth of smear (degrees). +C FOUND O Found flag. +C +C$ Detailed_Input +C +C STARG is the aberration-corrected state of the target as +C seen from observer's position. +C +C The state is given in inertial coordinates. +C +C The epoch of the state should be the midpoint of +C the interval during which the camera's shutter was +C open. +C +C SURFX is the surface intercept point of the camera's +C boresight ray with the surface of the target body. +C The position of the target should be aberration- +C corrected, and the orientation of the target should +C be corrected for light time. SURFX is given in +C body-fixed coordinates. +C +C TICAM is a 3x3 matrix that transforms vectors from +C inertial to camera coordinates. +C +C AV is the camera's angular velocity in inertial +C coordinates. The reference frame must be the +C same as that used for BORE. The epoch at which AV +C should be obtained is the epoch of the image. +C +C TSIPM is the 6x6 matrix that transforms states from +C inertial to camera coordinates. TSIPM is used to +C find the state of the camera's boresight vector +C in body-fixed coordinates. +C +C The epoch at which this transformation matrix +C should be evaluated is the epoch of the image minus +C the one-way light time from the target to the +C observer. +C +C FOCLEN is the focal length of the camera in millimeters. +C +C PXLSCL is the pixel scale in units of pixels/millimeter. +C It is assumed that the camera has square pixels. +C +C EXPLEN is the duration of the exposure for which the +C smear is to be computed. Units are seconds. +C +C$ Detailed_Output +C +C SMRLEN is an estimate of the length of the smear at the +C center of the image defined by the input geometry +C and camera attributes. The units are pixels. +C SMRLEN defined only if FOUND is TRUE. +C +C SMRAZ is the azimuth angle of the smear at the center of +C the image defined by the input geometry. The units +C are degrees. +C SMRAZ defined only if FOUND is TRUE. +C +C FOUND is a logical flag that is set to .TRUE. if the +C smear could be computed, and otherwise, .FALSE. +C With valid inputs, the smear should be +C computable. This flag is used in lieu of error +C checking on the inputs. +C +C$ Parameters +C +C None. +C +C$ Exceptions +C +C 1) In the interest of speed, this routine performs no error +C checking. +C +C 2) If the boresight intercept point defined by the inputs is on +C or too close to the target body's limb, FOUND will be +C returned with the value .FALSE. and both SMRLEN and SMRAZ will +C be unchanged. +C +C$ Files +C +C None. +C +C$ Particulars +C +C The definition of `smear' used by this routine is intended to +C provide an estimate magnitude and direction of the smear in an +C image taken by a camera. The smear in question is that of +C features of an extended target body; this routine does not +C compute a smear estimate applicable to star images. +C +C The amount of smear in an image is not generally exactly uniform +C throughout the image; for simplicity, this routine estimates smear +C at the image center. The smear estimate takes into account the +C following motions: +C +C -- Center-of-mass motion of the observer. +C -- Rotation of the camera with respect to inertial space. +C -- Center-of-mass motion of the target. +C -- Rotation of the target with respect to inertial space. +C +C This routine computes an estimate of the length of the smear of +C the image of a surface feature that appears in the center of the +C image at the midpoint of the exposure; this normally should be a +C good estimate of the length of the smear of any surface feature. +C Additionally, the direction in which surface features appear to be +C smeared in the image is estimated by the direction of the smear of +C the image of this surface point. +C +C$ Examples +C +C Maybe later. +C +C$ Restrictions +C +C None. +C +C$ Literature_References +C +C None. +C +C$ Author_and_Institution +C +C N.J. Bachman (JPL) +C +C$ Version +C +C- Beta Version 1.0.0, 18-JAN-1994 (NJB) +C +C-& + +C +C SPICELIB functions +C + +C +C Local Parameters +C + DOUBLE PRECISION DPR + DOUBLE PRECISION VNORMG + +C +C Local variables +C + DOUBLE PRECISION DTICAM ( 3, 3 ) + DOUBLE PRECISION DTIPM ( 3, 3 ) + DOUBLE PRECISION DVB ( 3 ) + DOUBLE PRECISION DVC ( 3 ) + DOUBLE PRECISION DVC1 ( 3 ) + DOUBLE PRECISION DVC2 ( 3 ) + DOUBLE PRECISION DVF ( 2 ) + DOUBLE PRECISION DVI ( 3 ) + DOUBLE PRECISION SMEAR ( 2 ) + DOUBLE PRECISION SURFXI ( 3 ) + DOUBLE PRECISION TIPM ( 3, 3 ) + DOUBLE PRECISION VC ( 3 ) + DOUBLE PRECISION VI ( 3 ) + + INTEGER I + INTEGER J + +C +C No error handling. +C + +C +C Initialization +C + FOUND = .FALSE. + +C +C We're going to compute the time derivative of the image of +C the feature that appears at the image center at the input +C epoch. +C +C We'll use the following variables in the derivation: +C +C V Body-fixed location of feature. +C B +C +C V Inertial vector from observer to feature. +C I +C +C V V expressed in camera frame. +C C I +C +C V Image of V in focal plane. +C F C +C +C TRGPOS Inertial vector from observer to target center. +C +C TICAM Transformation from inertial to camera +C coordinates. +C +C TIPM Transformation from inertial to body-fixed +C ("body equator and prime meridian") +C coordinates. +C +C ET Epoch of observation. +C +C LT One-way light time from target to observer. +C +C F Camera focal length. +C +C +C The following relationships hold: +C +C t +C V (ET) = TRGPOS(ET) + TIPM (ET-LT) * V +C I B +C +C +C V (ET) = TIMCAM(ET) * V (ET) +C C I +C +C f +C V = ----- * ( V (1), V (2) ) +C F V (3) C C +C C +C +C +C Differentiating these expressions, we obtain: +C +C +C d [ V ] | d TRGPOS | +C I | = -------- | +C ---------- | dt |ET +C dt | ET +C t +C d [TIPM ] | +C + ---------- | * ( 1 - d(LT)/dt) * V +C dt |ET-LT B +C +C +C which, assuming that light time varies slowly, yields the +C approximate equality +C +C +C d [ V ] | t +C I | d TRGPOS | d [TIPM ] | +C ---------- | = -------- | + ---------- | * V +C dt | ET dt |ET dt |ET-LT B +C +C +C We also have +C +C +C d [ V ] | +C C | d [TICAM]| +C ---------- | = -------- | * V (ET) +C dt | ET dt |ET I +C +C +C d [ V ]| +C I | +C + TICAM(ET) * --------| +C dt |ET +C +C and finally +C +C d [ V ] | d [ V (3)]| +C F | -F C | +C ---------- | = ------- * -------- | +C dt | ET 2 dt |ET +C V (3) +C C +C +C * ( V (1), V (2) ) +C C C +C +C +C d [ ( V (1), V (2) ) ] +C F C C +C + ------- * -------------------------- +C V (3) dt +C C +C +C +C +C We proceed to compute these derivatives. First we'll need TIPM +C and the time derivatives of TIPM and TICAM: +C + DO I = 1, 3 + + DO J = 1, 3 + TIPM (J,I) = TSIPM(J, I) + DTIPM(J,I) = TSIPM(3+J,I) + END DO + + END DO + + + CALL RAV2DR ( TICAM, AV, DTICAM ) + +C +C Now for the main event. Compute: +C +C 1) V and the derivative of V , which we'll call DVI: +C I I +C + CALL MTXV ( TIPM, SURFX, SURFXI ) + CALL VADD ( STARG, SURFXI, VI ) + + CALL MXV ( DTIPM, SURFX, DVB ) + CALL VADD ( STARG(4), DVB, DVI ) + +C +C 2) V and the derivative of V , which we'll call DVC: +C C C +C + CALL MXV ( TICAM, VI, VC ) + + CALL MXV ( TICAM, DVI, DVC1 ) + CALL MXV ( DTICAM, VI, DVC2 ) + CALL VADD ( DVC1, DVC2, DVC ) + +C +C Make sure that V can be computed: +C F + + IF ( VC(3) .EQ. 0.D0 ) THEN + RETURN + END IF + +C +C 3) Compute the derivative of V , which we'll call DVF: +C F +C + CALL VLCOMG ( 2, -FOCLEN * DVC(3) / VC(3)**2, VC, + . FOCLEN / VC(3), DVC, DVF ) + + +C +C DVF has units of mm/sec. Scale by pixels/mm and multiply by +C the exposure length to obtain the smear vector. +C + CALL VSCLG ( PXLSCL * EXPLEN, DVF, 2, SMEAR ) + +C +C Compute the norm and azimuth angle of this smear vector. +C + SMRLEN = VNORMG ( SMEAR, 2 ) + + IF ( SMRLEN .EQ. 0.D0 ) THEN + + SMRAZ = 0.D0 + + ELSE + + SMRAZ = -DATAN2 ( SMEAR(2), SMEAR(1) ) * DPR() + + IF ( SMRAZ .LT. 0.D0 ) THEN + SMRAZ = SMRAZ + 360.D0 + END IF + + END IF + + + FOUND = .TRUE. + + RETURN + END + + diff --git a/isis/src/messenger/apps/mdisedrinfo/assets/smear1.msg b/isis/src/messenger/apps/mdisedrinfo/assets/smear1.msg new file mode 100644 index 0000000000000000000000000000000000000000..06628a21cacfcd13678a23ca7a1892edfd303545 --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/assets/smear1.msg @@ -0,0 +1,528 @@ +Debbie A Cook/GD/USGS/DOI +08/21/2007 05:36 PM To +Kris J Becker/GD/USGS/DOI@USGS +cc + +bcc + +Subject +Fw: Bug fix for SMRIMG + + + History: +This message has been replied to. + + +----- Forwarded by Debbie A Cook/GD/USGS/DOI on 08/21/2007 05:36 PM ----- +Nat Bachman +08/21/2007 12:50 AM +Please respond to +Nathaniel.Bachman@jpl.nasa.gov + +To +Debbie A Cook , Charles Acton , Boris +Semenov , Edward Wright , Nat +Bachman +cc + +Subject +Bug fix for SMRIMG + + + + + + +Hi Debbie, + +It turned out that there was a bug in SMRIMG: the effect of +the target body rotation on the smear velocity was not +handled properly due to a coding error (the derivation +in the comments was correct, but the code didn't match +the comments). The effect is small enough so that the +original version of the routine produces "reasonable" +results when the target body is the Moon. Cranking up +the target body rotation rate by a few orders of +magnitude makes the presence of the bug obvious. + +Anyway, I've attached a fixed version of the routine. + + -Nat + +C$Procedure SMRIMG ( Smear image ) + + SUBROUTINE SMRIMG ( STARG, + . SURFX, + . TICAM, + . AV, + . TSIPM, + . FOCLEN, + . PXLSCL, + . EXPLEN, + . SMRLEN, + . SMRAZ, + . FOUND ) + + IMPLICIT NONE + +C$ Abstract +C +C Determine the smear in an image due to observer and target +C motion. +C +C$ Disclaimer +C +C THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE +C CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. +C GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE +C ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE +C PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" +C TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY +C WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A +C PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC +C SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE +C SOFTWARE AND RELATED MATERIALS, HOWEVER USED. +C +C IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA +C BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT +C LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, +C INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, +C REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE +C REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. +C +C RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF +C THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY +C CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE +C ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. +C +C$ Required_Reading +C +C None. +C +C$ Keywords +C +C GEOMETRY +C +C$ Declarations +C + DOUBLE PRECISION STARG ( 6 ) + DOUBLE PRECISION SURFX ( 3 ) + DOUBLE PRECISION TICAM ( 3, 3 ) + DOUBLE PRECISION AV ( 3 ) + DOUBLE PRECISION TSIPM ( 6, 6 ) + DOUBLE PRECISION FOCLEN + DOUBLE PRECISION PXLSCL + DOUBLE PRECISION EXPLEN + DOUBLE PRECISION SMRLEN + DOUBLE PRECISION SMRAZ + LOGICAL FOUND +C +C$ Brief_I/O +C +C Variable I/O Description +C -------- --- -------------------------------------------------- +C STARG I Inertial target state. +C SURFX I Surface intercept of camera boresight. +C TICAM I Inertial-to-camera transformation matrix. +C AV I Angular velocity of camera (radians/second). +C TSIPM I Inertial-to-bodyfixed state transformation matrix. +C FOCLEN I Camera focal length. +C PXLSCL I Camera pixel scale, (pixels/mm). +C EXPLEN I Exposure length (seconds). +C SMRLEN O Length of smear (pixels). +C SMRAZ O Azimuth of smear (degrees). +C FOUND O Found flag. +C +C$ Detailed_Input +C +C STARG is the aberration-corrected state of the target as +C seen from observer's position. +C +C The state is given in inertial coordinates. +C +C The epoch of the state should be the midpoint of +C the interval during which the camera's shutter was +C open. +C +C SURFX is the surface intercept point of the camera's +C boresight ray with the surface of the target body. +C The position of the target should be aberration- +C corrected, and the orientation of the target should +C be corrected for light time. SURFX is given in +C body-fixed coordinates. +C +C TICAM is a 3x3 matrix that transforms vectors from +C inertial to camera coordinates. +C +C AV is the camera's angular velocity in inertial +C coordinates. The reference frame must be the +C same as that used for BORE. The epoch at which AV +C should be obtained is the epoch of the image. +C +C TSIPM is the 6x6 matrix that transforms states from +C inertial to camera coordinates. TSIPM is used to +C find the state of the camera's boresight vector +C in body-fixed coordinates. +C +C The epoch at which this transformation matrix +C should be evaluated is the epoch of the image minus +C the one-way light time from the target to the +C observer. +C +C FOCLEN is the focal length of the camera in millimeters. +C +C PXLSCL is the pixel scale in units of pixels/millimeter. +C It is assumed that the camera has square pixels. +C +C EXPLEN is the duration of the exposure for which the +C smear is to be computed. Units are seconds. +C +C$ Detailed_Output +C +C SMRLEN is an estimate of the length of the smear at the +C center of the image defined by the input geometry +C and camera attributes. The units are pixels. +C SMRLEN defined only if FOUND is TRUE. +C +C SMRAZ is the azimuth angle of the smear at the center of +C the image defined by the input geometry. The units +C are degrees. SMRAZ defined only if FOUND is TRUE. +C +C FOUND is a logical flag that is set to .TRUE. if the +C smear could be computed, and otherwise, .FALSE. +C With valid inputs, the smear should be +C computable. This flag is used in lieu of error +C checking on the inputs. +C +C$ Parameters +C +C None. +C +C$ Exceptions +C +C 1) In the interest of speed, this routine performs no error +C checking. +C +C 2) If the boresight intercept point defined by the inputs is on +C or too close to the target body's limb, FOUND will be +C returned with the value .FALSE. and both SMRLEN and SMRAZ will +C be unchanged. +C +C$ Files +C +C None. +C +C$ Particulars +C +C The definition of `smear' used by this routine is intended to +C provide an estimate magnitude and direction of the smear in an +C image taken by a camera. The smear in question is that of +C features of an extended target body; this routine does not +C compute a smear estimate applicable to star images. +C +C The amount of smear in an image is not generally exactly uniform +C throughout the image; for simplicity, this routine estimates smear +C at the image center. The smear estimate takes into account the +C following motions: +C +C -- Center-of-mass motion of the observer. +C -- Rotation of the camera with respect to inertial space. +C -- Center-of-mass motion of the target. +C -- Rotation of the target with respect to inertial space. +C +C This routine computes an estimate of the length of the smear of +C the image of a surface feature that appears in the center of the +C image at the midpoint of the exposure; this normally should be a +C good estimate of the length of the smear of any surface feature. +C Additionally, the direction in which surface features appear to be +C smeared in the image is estimated by the direction of the smear of +C the image of this surface point. +C +C$ Examples +C +C Maybe later. +C +C$ Restrictions +C +C None. +C +C$ Literature_References +C +C None. +C +C$ Author_and_Institution +C +C N.J. Bachman (JPL) +C +C$ Version +C +C- Beta Version 1.1.0, 21-AUG-2007 (NJB) +C +C Bug fix: body-fixed velocity of surface point is +C now correctly converted to the inertial frame +C defined by TSIPM. +C +C- Beta Version 1.0.0, 18-JAN-1994 (NJB) +C +C-& + + +C$ Index_Entries +C +C smear magnitude and direction +C +C-& + +C$ Revisions +C +C- Beta Version 1.1.0, 21-AUG-2007 (NJB) +C +C Bug fix: body-fixed velocity of surface point is +C now correctly converted to the inertial frame +C defined by TSIPM. +C +C In the computation of DVI, the code did not match +C the derivation in the comments. The erroneous line +C in step 1 +C +C CALL MXV ( DTIPM, SURFX, DVB ) +C +C was changed to +C +C CALL MTXV ( DTIPM, SURFX, DVB ) +C +C-& + +C +C SPICELIB functions +C + +C +C Local Parameters +C + DOUBLE PRECISION DPR + DOUBLE PRECISION VNORMG + +C +C Local variables +C + DOUBLE PRECISION DTICAM ( 3, 3 ) + DOUBLE PRECISION DTIPM ( 3, 3 ) + DOUBLE PRECISION DVB ( 3 ) + DOUBLE PRECISION DVC ( 3 ) + DOUBLE PRECISION DVC1 ( 3 ) + DOUBLE PRECISION DVC2 ( 3 ) + DOUBLE PRECISION DVF ( 2 ) + DOUBLE PRECISION DVI ( 3 ) + DOUBLE PRECISION SMEAR ( 2 ) + DOUBLE PRECISION SURFXI ( 3 ) + DOUBLE PRECISION TIPM ( 3, 3 ) + DOUBLE PRECISION VC ( 3 ) + DOUBLE PRECISION VI ( 3 ) + + INTEGER I + INTEGER J + +C +C No error handling. +C + +C +C Initialization +C + FOUND = .FALSE. + +C +C We're going to compute the time derivative of the image of +C the feature that appears at the image center at the input +C epoch. +C +C We'll use the following variables in the derivation: +C +C V Body-fixed location of feature. +C B +C +C V Inertial vector from observer to feature. +C I +C +C V V expressed in camera frame. +C C I +C +C V Image of V in focal plane. +C F C +C +C TRGPOS Inertial vector from observer to target center. +C +C TICAM Transformation from inertial to camera +C coordinates. +C +C TIPM Transformation from inertial to body-fixed +C ("body equator and prime meridian") +C coordinates. +C +C ET Epoch of observation. +C +C LT One-way light time from target to observer. +C +C F Camera focal length. +C +C +C The following relationships hold: +C +C t +C V (ET) = TRGPOS(ET) + TIPM (ET-LT) * V +C I B +C +C +C V (ET) = TIMCAM(ET) * V (ET) +C C I +C +C f +C V = ----- * ( V (1), V (2) ) +C F V (3) C C +C C +C +C +C Differentiating these expressions, we obtain: +C +C +C d [ V ] | d TRGPOS | +C I | = -------- | +C ---------- | dt |ET +C dt | ET +C t +C d [TIPM ] | +C + ---------- | * ( 1 - d(LT)/dt) * V +C dt |ET-LT B +C +C +C which, assuming that light time varies slowly, yields the +C approximate equality +C +C +C d [ V ] | t +C I | d TRGPOS | d [TIPM ] | +C ---------- | = -------- | + ---------- | * V +C dt | ET dt |ET dt |ET-LT B +C +C +C We also have +C +C +C d [ V ] | +C C | d [TICAM]| +C ---------- | = -------- | * V (ET) +C dt | ET dt |ET I +C +C +C d [ V ]| +C I | +C + TICAM(ET) * --------| +C dt |ET +C +C and finally +C +C d [ V ] | d [ V (3)]| +C F | -F C | +C ---------- | = ------- * -------- | +C dt | ET 2 dt |ET +C V (3) +C C +C +C * ( V (1), V (2) ) +C C C +C +C +C d [ ( V (1), V (2) ) ] +C F C C +C + ------- * -------------------------- +C V (3) dt +C C +C +C +C +C We proceed to compute these derivatives. First we'll need TIPM +C and the time derivatives of TIPM and TICAM: +C + DO I = 1, 3 + + DO J = 1, 3 + TIPM (J,I) = TSIPM(J, I) + DTIPM(J,I) = TSIPM(3+J,I) + END DO + + END DO + + + CALL RAV2DR ( TICAM, AV, DTICAM ) + +C +C Now for the main event. Compute: +C +C 1) V and the derivative of V , which we'll call DVI: +C I I +C + CALL MTXV ( TIPM, SURFX, SURFXI ) + CALL VADD ( STARG, SURFXI, VI ) + + CALL MTXV ( DTIPM, SURFX, DVB ) + CALL VADD ( STARG(4), DVB, DVI ) + +C +C 2) V and the derivative of V , which we'll call DVC: +C C C +C + CALL MXV ( TICAM, VI, VC ) + + CALL MXV ( TICAM, DVI, DVC1 ) + CALL MXV ( DTICAM, VI, DVC2 ) + CALL VADD ( DVC1, DVC2, DVC ) + +C +C Make sure that V can be computed: +C F + + IF ( VC(3) .EQ. 0.D0 ) THEN + RETURN + END IF + +C +C 3) Compute the derivative of V , which we'll call DVF: +C F +C + CALL VLCOMG ( 2, -FOCLEN * DVC(3) / VC(3)**2, VC, + . FOCLEN / VC(3), DVC, DVF ) + + +C +C DVF has units of mm/sec. Scale by pixels/mm and multiply by +C the exposure length to obtain the smear vector. +C + CALL VSCLG ( PXLSCL * EXPLEN, DVF, 2, SMEAR ) + +C +C Compute the norm and azimuth angle of this smear vector. +C + SMRLEN = VNORMG ( SMEAR, 2 ) + + IF ( SMRLEN .EQ. 0.D0 ) THEN + + SMRAZ = 0.D0 + + ELSE + + SMRAZ = -DATAN2 ( SMEAR(2), SMEAR(1) ) * DPR() + + IF ( SMRAZ .LT. 0.D0 ) THEN + SMRAZ = SMRAZ + 360.D0 + END IF + + END IF + + + FOUND = .TRUE. + + RETURN + END + + diff --git a/isis/src/messenger/apps/mdisedrinfo/mdisedrinfo.cpp b/isis/src/messenger/apps/mdisedrinfo/mdisedrinfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a90d478f9f5f4208522eba2c11ade5ca420196c --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/mdisedrinfo.cpp @@ -0,0 +1,175 @@ +// $Id: mdisedrinfo.cpp,v 1.8 2008/07/11 22:38:41 nhilt Exp $ +#include "Isis.h" + +#include +#include +#include +#include +#include +#include + +#include "Filename.h" +#include "UserInterface.h" +#include "Cube.h" +#include "OriginalLabel.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iString.h" + +#include "MdisGeometry.h" +#include "MdisEdrKeys.h" + +using namespace Isis; +using namespace std; + + +void IsisMain(){ + +// Input parameters + UserInterface &ui = Application::GetUserInterface(); + string sourceFile = ui.GetAsString("FROM"); // Save off source filename + Filename from(sourceFile); + + string to; + if (ui.WasEntered("TO")) to = ui.GetAsString("TO"); + bool delete_from(false); + +// Is there a separate file containing keywords to report? + string keylist; + if (ui.WasEntered("KEYLIST")) keylist = ui.GetAsString("KEYLIST"); + else keylist = to; + +// Get PVL parameter + string pvl; + if (ui.WasEntered("PVL")) pvl = ui.GetAsString("PVL"); + +// Run mdis2isis if necessary. If this step must be done, we must also +// run spiceinit to initialize it with spice. + if (iString::UpCase(from.Extension()) != "CUB") { + Filename temp; + temp.Temporary(from.Basename(), "cub"); + string params = "from=" + from.Expanded() + " to=" + temp.Expanded(); + + try { + iApp->Exec("mdis2isis", params); + +// Ensure a proper target before initialization + Cube cube; + cube.Open(temp.Expanded(), "rw"); + Pvl *label = cube.Label(); + MdisGeometry::validateTarget(*label, true); + cube.Close(); + + // Run spiceinit on it + iApp->Exec("spiceinit", "from="+temp.Expanded()); + } catch (iException &ie ) { + string tempName(temp.Expanded()); + remove (tempName.c_str()); + ie.Message(iException::User,"Failed to execute mdis2isis/spiceinit", + _FILEINFO_); + throw; + } + + // FROM file is now the ISIS cube. Stage cube file for deletion as well. + from = temp; + delete_from = true; + } + +// Now process the label and instantiate the camera model(s) + try { + +// Get the orginal PDS EDR labels and initialize the keyword map + Pvl edrlab = OriginalLabel(from.Expanded()).ReturnLabels(); + MdisEdrKeys edrkeys(edrlab); + +// Compute the Geometry + MdisGeometry geom(from.Expanded()); + Pvl geomkeys = geom.getGeometry(sourceFile); + edrkeys.updateKeys(geomkeys); + + PvlGroup mdiskeys("MdisPdsKeys"); + +// Only process the PDS EDR keyword mapping if KEYMAP (or TO) is entered. + if (!keylist.empty()) { + Filename kmap(keylist); + if (!kmap.Exists()) { + string mess = "EDR keyword map source file, " + kmap.Expanded() + + ", does not exist!"; + throw iException::Message(iException::User, mess.c_str(), _FILEINFO_); + } + + // Get the keylist source line + string kmapName(kmap.Expanded()); + ifstream ifile(kmapName.c_str(), ios::in); + if (!ifile) { + string mess = "Unable to open key map source file " + kmap.Expanded(); + throw iException::Message(iException::User, mess, _FILEINFO_); + } + + string keystring; + if (!getline(ifile, keystring)) { + string mess = "I/O error reading key map line from " + kmap.Expanded(); + throw iException::Message(iException::User, mess, _FILEINFO_); + } + + ifile.close(); + + // Split the line using semi-colons as the delimiter + vector keys; + iString::Split(';', keystring, keys); + std::string keyvalues = edrkeys.extract(keys, geom.getNull(), &mdiskeys); + + if (!to.empty()) { + // Now open the output file and write the result + Filename tomap(to); + string tomapName(tomap.Expanded()); + bool toExists = tomap.Exists(); + ofstream ofile; + if (toExists) { + ofile.open(tomapName.c_str(), std::ios::out|std::ios::app); + } + else { + ofile.open(tomapName.c_str(), std::ios::out); + } + + if (!ofile) { + string mess = "Could not open or create output TO file " + + tomapName; + throw iException::Message(iException::User, mess, _FILEINFO_); + } + + // Write the header if requested by the user + if (!toExists) ofile << keystring << endl; + ofile << keyvalues << endl; + ofile.close(); + } + } + else { + PvlContainer::PvlKeywordIterator keyIter = geomkeys.Begin(); + for ( ; keyIter != geomkeys.End() ; ++keyIter) { + mdiskeys.AddKeyword(*keyIter); + } + } + +// See if the user wants to write out the PVL keywords + if (!pvl.empty()) { + Pvl pout; + pout.AddGroup(mdiskeys); + pout.Write(pvl); + } + +// Log the results to the log/terminal/gui + Application::Log(mdiskeys); + } + catch (iException &ie) { + + string fromName(from.Expanded()); + if (delete_from) remove (fromName.c_str()); + throw; + } + +// Delete the from file if it was temporarily created from an EDR + string fromName(from.Expanded()); + if (delete_from) remove (fromName.c_str()); +} + diff --git a/isis/src/messenger/apps/mdisedrinfo/mdisedrinfo.xml b/isis/src/messenger/apps/mdisedrinfo/mdisedrinfo.xml new file mode 100644 index 0000000000000000000000000000000000000000..17c0c5f012fa09bee33196f3d6245749c19a1fd9 --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/mdisedrinfo.xml @@ -0,0 +1,680 @@ + + + + + + + Computes MESSENGER/MDIS EDR geometric keyword values + + + +

    + mdisedrinfo computes geometric properties that satisfy PDS EDR archive + specifications. + + The input file can be either a MDIS EDR or an ISIS cube. It will work + on either one. The file type is distinguished by the file extension. + If the extension is not .cub, then the file is deemed a PDS EDR. It is converted + to an ISIS cube (using mdis2isis) and initialized with SPICE + kernels (using spiceinit). The resulting ISIS cube file is then used to + compute the values. If the FROM file extension is .cub, then it is + assumed to be an ISIS cube that has been initialized with the proper + SPICE kernel information. +

    +

    + The ISIS cube file stores the original MDIS PDS EDR labels. All PDS EDR + keywords are loaded with their intial values. The keyword/values generated + by mdisedrinfo replace the original ones and are made available + through a semi-colon delineated list provided in either the KEYLIST or + TO parameter. All original PDS EDR keywords and their values are available + as well. The RETICLE_POINT_LATITUDE and + RETICLE_POINT_LONGITUDE keywords in each of the + SUBFRAME[12345]_PARAMETERS objects are also + computed by mdisedrinfo. These parameters are referenced + using the name of the object from whence they came. For example, + the RETICLE_POINT_LATITUDE in object + SUBFRAME2_PARAMETERS is referenced as + SUBFRAME2_PARAMETERS/RETICLE_POINT_LATITUDE. + In general, this special class of reticle point keywords are prepended + with the name of the object followed by the keyword name and separated + by a forward slash. See the parameter descriptions for + further details. +

    +

    + Also, the KEYLIST parameter is expected to contain the single line of + semi-colon delineated keywords selected for update. It is optional in + that the TO file can also provide this item, if the TO file exists. + The idea is to provide a single file that has the keyword list and + have each image data appended to it on succesive runs. On the first + run, if TO does not exist and KEYLIST is given, the keyword list is + read from KEYLIST, TO is created and the single keyword list line from + KEYLIST is written to it followed by the computed/selected keywords. + Any keyword in the list provided that does not exist will cause the + application to abort. +

    +

    + There are three additional keywords generated by this application that are + not in the PDS EDR label at the time this application was developed. + The filename specified in the FROM parameter + is provided through the FILENAME keyword. It is added as an + additional reference to support subsequent processing of the results. + The SOURCE_PRODUCT_ID keyword is added that identifies every + SPICE kernel used to compute the geometric parameters. And the + RA_DEC_REF_PIXEL records the center pixel coordinate of the + image that was used to compute all the target geometric properties. These + keywords may be used in future PDS EDRs released by the team. +

    +

    + Images that do not have a target name recognized by NAIF + (such as STAR, etc...) will generally fail if left unchanged. When + processing raw PDS EDR images, a check is performed by + mdisedrinfo after importing into ISIS with + mdis2isis of the TargetName (TARGET_NAME in the + PDS EDR header) keyword for a valid NAIF target. If it is invalid, the + TargetName ISIS keyword is changed to Sky so + spiceinit executes properly. This check is not performed if the + input FROM file is an ISIS cube. It is the responsibility of the user to + ensure proper target names are in ISIS cube files. +

    +

    + Images that were acquired in subframe mode are not supported and will + abort the application when they are detected. +

    +

    + The follow table lists the keywords that are computed by mdisedrinfo + along with a description for each one: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MESSENGER/MDIS PDS EDR Keywords
    + Keyword + + Description and Definitions +
    +FILENAME + +The name of the input file specified in the FROM parameter. +
    +SOURCE_PRODUCT_ID + +This keyword records all the SPICE kernels in use to compute the geometric parameters. +Only the filenames are recorded - the paths to them are ISIS specific and are removed. +
    +RA_DEC_REF_PIXEL + + The RA_DEC_REF_PIXEL element (x,y) specifies the reference pixel to + which the right_ascension and declination apply. + The x value is here defined as the pixel value in the LINE_SAMPLE + direction, and the y value is defined as the pixel value in the LINE + direction. It is also the pixel coordinate used for computation of + target geometry. It is synonymous with the boresight reference + pixel. +
    +RIGHT_ASCENSION + +The right ascension of the camera boresight. The values are specified +relative to the J2000 inertial reference frame. +
    +DECLINATION + +The declination of the camera boresight. The values are specified relative +to the J2000 inertial reference frame. +
    +TWIST_ANGLE + +The angle of rotation about an optical axis relative to celestial +coordinates. It is defined as (180- CELESTIAL_NORTH_CLOCK_ANGLE) mod +360. Where CELESTIAL_NORTH_CLOCK_ANGLE is the direction of celestial +north at the center of an image. It is measured from the upward +direction, clockwise to the direction toward celestial north (declination += +90 degrees), when the image is displayed left to right and top to +bottom. The epoch of the celestial coordinate system is J2000. +
    +RETICLE_POINT_RA + +The right ascension of the principle points of the +camera. Note: For MESSENGER +the principle points are defined as the upper left pixel of the camera +(line 1,sample 1), the upper right pixel(line 1, last sample), lower left +(last line, sample 1), and lower right (last line, last sample). +
    +RETICLE_POINT_DECLINATION + +The declination of the principle points of the camera. For MESSENGER the +principle points are defined as in RETICLE_POINT_RA. +
    +SC_TARGET_POSITION_VECTOR + +X, Y, Z components of the position vector from observer to target center +expressed in J2000 coordinates, and corrected for light time and stellar +aberration, evaluated at epoch at which the image was taken. Units are +expressed in kilometers. +
    +TARGET_CENTER_DISTANCE + +Distance between the spacecraft and the center of the named target in +kilometers. +
    +SLANT_DISTANCE + +Distance from spacecraft to the camera boresight intercept point on the +surface in kilometers. +
    +CENTER_LATITUDE + +Latitude at the center of the full image frame. +
    +CENTER_LONGITUDE + +Longitude at the center of the full image frame. +
    +HORIZONTAL_PIXEL_SCALE + +The horizontal picture scale. +
    +VERTICAL_PIXEL_SCALE + +The vertical picture scale. +
    +SMEAR_MAGNITUDE + +Norm of velocity vector of camera boresight intercept point projected on +the target, multiplied by the exposure duration with the scale of the +image factored to obtain the smear in pixels. Spacecraft rotation is taken +into account. (Units are in pixels.) +
    +SMEAR_AZIMUTH + +Azimuth of smear velocity vector. The reference line for the angle +extends from the center of the image to the right edge of the image. The +angle increases in the clock-wise direction. The angle is measured to the +"image" of the smear velocity vector in the camera's focal plane. This +image is computed by orthogonal projection of the smear vector onto the +image plane and then applying transformations to orient the result +properly with respect to the image. The specific transformations to be +performed are given by the camera's I-kernel. +
    +NORTH_AZIMUTH + +Analogs to smear azimuth, but applies to the target north pole direction +vector. +
    +RETICLE_POINT_LATITUDE + +Latitudes of the surface intercept points of the principle points of the +camera. (see RETICLE_POINT_RA for definition of the reticule points for +MESSENGER). The units are expressed in degrees. +
    +RETICLE_POINT_LONGITUDE + +Longitudes of the surface intercept points of the principle points of the +camera. (see RETICLE_POINT_RA for definition of the reticule points for +MESSENGER). The units are expressed in degrees. +
    +SUB_SPACECRAFT_LATITUDE + +Planetocentric latitude of spacecraft-to-body-center surface intercept +vector. These parameters and the SPACECRAFT_ALTITUDE, +SUB_SPACECRAFT_AZIMUTH parameters described below are relative to the +central body for which the spacecraft is orbiting and not the target of +the observation. +
    +SUB_SPACECRAFT_LONGITUDE + +Planetocentric longitude of spacecraft-to-body-center surface intercept +vector. These parameters and the SPACECRAFT_ALTITUDE, +SUB_SPACECRAFT_AZIMUTH parameters described below are relative to the +central body for which the spacecraft is orbiting and not the target of +the observation. +
    +SPACECRAFT_ALTITUDE + +Altitude of the spacecraft above a reference ellipsoid. Distance is +measured to closest point on ellipsoid. +
    +SUB_SPACECRAFT_AZIMUTH + +Azimuth angle of sub-spacecraft point in image. Method of measurement is +the same as for SMEAR_AZIMUTH. +
    +SPACECRAFT_SOLAR_DISTANCE + +Analogous to TARGET_CENTER_DISTANCE but Sun replaces target body in +computation. +
    +SC_SUN_POSITION_VECTOR + +X ,Y ,Z components of the position vector from observer to sun, center +expressed in J2000 coordinates and corrected for light time and stellar +aberration, evaluated at epoch at which image was taken. Units are +kilometers. +
    +SC_SUN_VELOCITY_VECTOR + +x-, y-, and z- components of velocity vector of sun relative to the +observer, expressed in J2000 coordinates, and corrected for light time, +evaluated at epoch at which image was taken. Units are kilometers per +second. +
    +SOLAR_DISTANCE + +Distance from target body center to Sun. The Sun position used is that +described above. +
    +SUB_SOLAR_AZIMUTH + +Azimuth of the apparent sub-solar point, as seen by the spacecraft. This +point is the surface intercept of the target-center-to-Sun vector, +evaluated at the camera epoch minus one-way light time from target to +spacecraft at that epoch spacecraft at that epoch. Azimuth is measured as +described above. Target body position relative to the spacecraft is +corrected for light-time and stellar aberration. Target body orientation +is corrected for light-time. +
    +SUB_SOLAR_LATITUDE + +Planetocentric latitude of the apparent sub-solar point. +
    +SUB_SOLAR_LONGITUDE + +Planetocentric longitude of the apparent sub-solar point. +
    +INCIDENCE_ANGLE + +Provides a measure of the lighting condition at the intercept point. +Incidence angle is the angle between the local vertical at the intercept +point (surface) and a vector from the intercept point to the sun. The +incidence_angle varies from 0 degrees when the intercept point coincides +with the sub_solar point to 90 degrees when the intercept point is at the +terminator (i.e., in the shadowed or dark portion of the target body). +Thus, higher values of incidence_angle indicate the existence of a greater +number of surface shadows. +
    +PHASE_ANGLE + +Provides a measure of the relationship between the instrument viewing +position and incident illumination (such as solar light). Phase_angle is +measured at the target; it is the angle between a vector to the +illumination source and a vector to the instrument. If not specified, the +target is assumed to be at the center of the instrument field of view. If +illumination is from behind the instrument, phase_angle will be small. +
    +EMISSION_ANGLE + +Provides the value of the angle between the surface normal vector at the +intercept point and a vector from the intercept point to the spacecraft. +The emission_angle varies from 0 degrees when the spacecraft is viewing +the subspacecraft point (nadir viewing) to 90 degrees when the intercept +is tangent to the surface of the target body. Thus, higher values of +emission_angle indicate more oblique viewing of the target. +
    +LOCAL_HOUR_ANGLE + +Angle from the negative of the target-body-to-Sun vector to the projection +of the negative of the spacecraft-to-target vector onto the target's +instantaneous orbital plane. Both vectors are computed as in the +sub-spacecraft point computation. The angle is measured in a +counterclockwise direction when viewed from North of the ecliptic plane. +
    +
    + + + + Original version + + + Added ability to retain and reprocess the reticle keywords + in each SUBFRAME[12345]_PARAMETERS. In addition + the camera model now supports both subframe modes and + jailbar images. This rounds out complete support for imaging + modes in the camera model. + + + Modified the order in which the SPKs are loaded so that the planetary + ephemeris SPK (typically de405.bsp) is loaded before the spacecraft + SPK. The MESSENGER mission has been known to augment/update planet + ephemerides in its s/c SPK. + + + The SC_TARGET_POSITION_VECTOR and TARGET_CENTER_DISTANCE are defined for + all valid targets (other than Sky) even if none of the corners or center + reference pixels intersect the target. These keyword were previously + being computed only when the center reference pixel intersected the + target. It is now computed unconditionally for all valid targets except + Sky, which are set to N/A. + + + Corrected formatting of some units in arrays where the first unit is + undefined. This caused subsequent values with units to have the units + ignored. + + + Corrected computation of SMEAR_MAGNITUDE and SMEAR_AZIMUTH. + + + + + Messenger + + + + + + filename + input + Input PDS EDR or ISIS cube to compute geometric values for + +

    + This from file can be either a raw MESSENGER/MDIS EDR image (ending + in with a .IMG file extension) or an ISIS cube file that has been properly + initialize with SPICE kernel information. +

    +

    + MDIS PDS EDRs are converted to ISIS format using mdis2isis + and intialized with SPICE kernels using spiceinit. This is the + minimum expected processing for an ISIS cube provided as input + to mdiserdinfo. If and only if the input is an MDIS PDS EDR, + the temporary ISIS file created from it is deleted when the program + terminates (normally or abnormally). +

    +
    + *.IMG *.IMA *.cub +
    + + + filename + input + + File containing a row of keywords to extract after processing + + *.dat + None + +

    + This file contains at least one row that has a list of semi-colon + delimited keywords as specified in the EDR header. This row must + be the first row in the file. All other contents of the file are ignored. + This application computes all keyword values and places them in a table. + This table is then used to match the names from this single row of keyword + names and the keyword values are formatted in the same fashion as the list - + a semi-colon delineated list of values. This single row of values is then + appended to the TO file. +

    +

    + Note that this parameter is optional. If the TO file does not exist, it is created + and the row containing the keyword list is written to it. After which all keyword + values are appended to it. By this definition, the TO file can provide the + keyword list and the KEYLIST parameter is not longer required. It is only + really necessary when the TO file does not exist and it seeds the TO file + with the keyword list. +

    +

    + Below is an example of how this line may look: +

    +
    +FILENAME;RIGHT_ASCENSION;DECLINATION;SC_SUN_POSITION_VECTOR;RETICLE_POINT_LATITUDE
    +        
    +
    +
    + + + filename + output + + File where semi-colon delineated keyword values are written + + *.dat + None + +

    + This parameter provides the name of the file where + keyword values are written. The list of keyword names + can be provided in the KEYLIST parameter or, if the TO + file already exists, it may have the list of keywords in + the first line of this file. See the KEYLIST parameter for + further details. To use the TO file as the source of the + keyword list, do not provided the KEYLIST parameter. + Run this way implies the keyword list is in the TO file + provided here. +

    +

    + If the TO file does not exist, the list of keywords must be + provided in the KEYLIST parameter to seed the creation + of the TO file for subsequent use in this application. When + mdisedrinfo creates the TO file it writes the + semi-colon delineated list of keword names as the first + line of the file. The resulting values for those keywords + are appended to the contents of the TO after it is created + or if it already exists. +

    +

    + Each single run of mdisedrinfo results in a single + row of keyword values. This single row is appended to the + TO file. Each value is formatted according to PDS guidelines + and delineated by a semi-colon, following the same format as + the keyword name list supplied in KEYLIST. +

    +

    + TO is an optional output parameter as this program offers serveral + options for presentation of the resulting values. Below is an example + of an output line generated from the values as specified in the KEYLIST + example: +

    +
    +EW0031509051D.IMG;58.94599 <DEG>;23.52788 <DEG>;(-98852166.98839 <KM>,105701815.82312 <KM>,45826277.13516 <KM>);("N/A","N/A","N/A","N/A")
    +          
    +
    +
    + + filename + output + + File where Pvl-formatted keywords and values are written + + *.pvl + None + +

    + The name of a file where the keywords generated by + this application are written in PVL form. This is an optional file and not + generally used but does provide a more user-friendly view of the + output data created by mdisedrinfo. If KEYLIST or TO is + entered, the keywords listed in this source will also be the keywords + written, otherwise only the keywords that are changed are reported. +

    +

    + Below is an example of the expected output for the PVL format: +

    +
    +FILENAME                  = EW0031509051D.IMG
    +SOURCE_PRODUCT_ID         = (msgr_20040803_20120401_od094sc.bsp, 
    +                             msgr_v070.tf, 0089907251_mdis_atthist.bc, 
    +                             0001425715_0090876143_mdis_pivot.bc, de405.bsp, 
    +                             pck00008.tpc, pck00008_MSGR.tpc, 
    +                             mdisAddendum003.ti, naif0008.tls, 
    +                             messenger_390.tsc)
    +RA_DEC_REF_PIXEL          = (256.00000, 256.00000)
    +RIGHT_ASCENSION           = 58.94599 <DEG>
    +DECLINATION               = 23.52788 <DEG>
    +TWIST_ANGLE               = -169.91467 <DEG>
    +RETICLE_POINT_RA          = (63.79144, 52.09774, 65.35154, 54.51029) <DEG>
    +RETICLE_POINT_DECLINATION = (29.50223, 27.59525, 19.15652, 17.39244) <DEG>
    +SC_TARGET_POSITION_VECTOR = (-63778.06349, 18245.88488, -27909.07737) <KM>
    +TARGET_CENTER_DISTANCE    = 71968.53685 <KM>
    +SLANT_DISTANCE            = 67948.17343 <KM>
    +CENTER_LATITUDE           = -7.41010 <DEG>
    +CENTER_LONGITUDE          = 256.79419 <DEG>
    +HORIZONTAL_PIXEL_SCALE    = 24404.16696 <M>
    +VERTICAL_PIXEL_SCALE      = 24404.16696 <M>
    +SMEAR_MAGNITUDE           = "N/A"
    +SMEAR_AZIMUTH             = "N/A"
    +NORTH_AZIMUTH             = 253.70430 <DEG>
    +RETICLE_POINT_LATITUDE    = ("N/A", "N/A", "N/A", "N/A")
    +RETICLE_POINT_LONGITUDE   = ("N/A", "N/A", "N/A", "N/A")
    +SUB_SPACECRAFT_LATITUDE   = -22.86533 <DEG>
    +SUB_SPACECRAFT_LONGITUDE  = 305.16796 <DEG>
    +SPACECRAFT_ALTITUDE       = 65593.64024 <KM>
    +SUB_SPACECRAFT_AZIMUTH    = 358.70848 <DEG>
    +SPACECRAFT_SOLAR_DISTANCE = 151804718.18318 <KM>
    +SC_SUN_POSITION_VECTOR    = (-98852166.98839, 105701815.82312, 
    +                             45826277.13516) <KM>
    +SC_SUN_VELOCITY_VECTOR    = (18.82124, 14.64880, 4.90060) <KM/S>
    +SOLAR_DISTANCE            = 151801349.19267 <KM>
    +SUB_SOLAR_AZIMUTH         = 182.12965 <DEG>
    +SUB_SOLAR_LATITUDE        = 17.54908 <DEG>
    +SUB_SOLAR_LONGITUDE       = 203.65223 <DEG>
    +INCIDENCE_ANGLE           = 58.11450 <DEG>
    +PHASE_ANGLE               = 111.06803 <DEG>
    +EMISSION_ANGLE            = 52.98043 <DEG>
    +LOCAL_HOUR_ANGLE          = 233.14196 <DEG>
    +End
    +           
    +
    +
    +
    +
    +
    diff --git a/isis/src/messenger/apps/mdisedrinfo/tsts/Makefile b/isis/src/messenger/apps/mdisedrinfo/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/messenger/apps/mdisedrinfo/tsts/default/Makefile b/isis/src/messenger/apps/mdisedrinfo/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b5ff47018aeb07339b1c33886f767a78a27dbbc1 --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = mdisedrinfo + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from='$$messenger/testData/EW0031509051D.cub' \ + keylist=$(INPUT)/mdispdskeys.lis to=$(OUTPUT)/mdisedrinfo.txt \ + pvl=$(OUTPUT)/EW0031509051D.pvl > /dev/null; diff --git a/isis/src/messenger/apps/mdisedrinfo/tsts/kernelchk/Makefile b/isis/src/messenger/apps/mdisedrinfo/tsts/kernelchk/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46724d9fb4af9a1da9b72888e1ad8ff857809092 --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/tsts/kernelchk/Makefile @@ -0,0 +1,21 @@ +APPNAME = mdisedrinfo + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from='$$messenger/testData/EN0089576657M.IMG' \ + keylist=$(INPUT)/mdispdskeys.lis \ + to=$(OUTPUT)/mdisedrinfo.txt \ + pvl=$(OUTPUT)/EN0089576657M.pvl > /dev/null; + $(APPNAME) from='$$messenger/testData/EW0031592574E.IMG' \ + to=$(OUTPUT)/mdisedrinfo.txt \ + pvl=$(OUTPUT)/EW0031592574E.pvl > /dev/null; + $(APPNAME) from='$$messenger/testData/EW0089570936I.IMG' \ + to=$(OUTPUT)/mdisedrinfo.txt \ + pvl=$(OUTPUT)/EW0089570936I.pvl > /dev/null; + $(APPNAME) from='$$messenger/testData/EW0108827588A.IMG' \ + to=$(OUTPUT)/mdisedrinfo.txt \ + pvl=$(OUTPUT)/EW0108827588A.pvl > /dev/null; + $(APPNAME) from='$$messenger/testData/EN0108828426M.IMG' \ + to=$(OUTPUT)/mdisedrinfo.txt \ + pvl=$(OUTPUT)/EN0108828426M.pvl > /dev/null; diff --git a/isis/src/messenger/apps/mdisedrinfo/tsts/multi/Makefile b/isis/src/messenger/apps/mdisedrinfo/tsts/multi/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1f3746564f0d204712033514a0a0f172bf9e4f93 --- /dev/null +++ b/isis/src/messenger/apps/mdisedrinfo/tsts/multi/Makefile @@ -0,0 +1,18 @@ +APPNAME = mdisedrinfo + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from='$$messenger/testData/EN0089576657M.cub' \ + keylist=$(INPUT)/mdispdskeys.lis \ + to=$(OUTPUT)/mdisedrinfo.txt \ + pvl=$(OUTPUT)/EN0089576657M.pvl > /dev/null; + $(APPNAME) from='$$messenger/testData/EW0031592574E.cub' \ + to=$(OUTPUT)/mdisedrinfo.txt \ + pvl=$(OUTPUT)/EW0031592574E.pvl > /dev/null; + $(APPNAME) from='$$messenger/testData/EW0061073619F.IMG' \ + to=$(OUTPUT)/mdisedrinfo.txt \ + pvl=$(OUTPUT)/EW0061073619F.pvl > /dev/null; + $(APPNAME) from='$$messenger/testData/EW0089570936I.cub' \ + to=$(OUTPUT)/mdisedrinfo.txt \ + pvl=$(OUTPUT)/EW0089570936I.pvl > /dev/null; diff --git a/isis/src/messenger/apps/mdisproc/Makefile b/isis/src/messenger/apps/mdisproc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/messenger/apps/mdisproc/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/messenger/apps/mdisproc/mdisproc.cpp b/isis/src/messenger/apps/mdisproc/mdisproc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a22df7141cf78f4b567ae2d5491877198e31d652 --- /dev/null +++ b/isis/src/messenger/apps/mdisproc/mdisproc.cpp @@ -0,0 +1,70 @@ +#include "Isis.h" + +#include + +#include "UserInterface.h" +#include "Pipeline.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void IsisMain () { + UserInterface &ui = Application::GetUserInterface(); + if (!ui.GetBoolean("INGESTION") && !ui.GetBoolean("CALIBRATION") && !ui.GetBoolean("CDR")) { + string msg = "You must pick one of [INGESTION,CALIBRATION,CDR]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + Pipeline p("mdisproc"); + + p.SetInputFile("FROM","BANDS"); + p.SetOutputFile("TO"); + + p.KeepTemporaryFiles( !ui.GetBoolean("REMOVE") ); + + //--------------------------------------------------------------------------- + // Set up the ingestion run if requested + if (ui.GetBoolean("INGESTION")) { + string app = "mdis2isis"; + p.AddToPipeline(app); + p.Application(app).SetInputParameter("FROM",false); + p.Application(app).SetOutputParameter("TO","raw"); + } + + //--------------------------------------------------------------------------- + // Set up the calibration run if requested + if( ui.GetBoolean("CALIBRATION") ) { + string app = "mdiscal"; + p.AddToPipeline(app); + p.Application(app).SetInputParameter("FROM",true); + p.Application(app).SetOutputParameter("TO","lev1"); + p.Application(app).AddParameter("DARKCURRENT","DARKCURRENT"); + if ( ui.GetInteger("TRIM") == 0 || ui.GetInteger("TRIM") == 3 ) { + p.Application(app).AddConstParameter("KEEPDARK","true"); + } + p.Application(app).AddParameter("IOF","IOF"); + + // trim if needed + if ( ui.GetInteger("TRIM") != 0 && ui.GetInteger("TRIM") != 3 ) { + app = "trim"; + p.AddToPipeline(app); + p.Application(app).SetInputParameter("FROM",true); + p.Application(app).SetOutputParameter("TO","trim"); + p.Application(app).AddParameter("TRIM","LEFT"); + } + } + + //--------------------------------------------------------------------------- + // Set up the calibrated run when asked + if( ui.GetBoolean("CDR") ) { + string app = "mdis2pds"; + p.AddToPipeline(app); + p.Application(app).SetInputParameter("FROM",true); + p.Application(app).SetOutputParameter("TO","cdr","IMG"); + p.Application(app).AddParameter("BITS","BITS"); + } + + p.Run(); + +} diff --git a/isis/src/messenger/apps/mdisproc/mdisproc.xml b/isis/src/messenger/apps/mdisproc/mdisproc.xml new file mode 100644 index 0000000000000000000000000000000000000000..daeb399ed8e50ccf8f3795ea4a2671916014e041 --- /dev/null +++ b/isis/src/messenger/apps/mdisproc/mdisproc.xml @@ -0,0 +1,230 @@ + + + + Runs a raw Messenger cube through ingestion and calibration + + + + Runs a raw Messenger cube through ingestion and/or calibration. + With the optional CDR on, the final output will be a re-exported cdr img. + + + + + Original version + + + Fixed the trim option and added a test for it. + + + + + Messenger + + + + + + + + filename + input + + Input Messenger img + + + Input filename to be ingested, calebrated, and possibly re-exported into a cdr. + + + *.QUB *.imq *.ima *.img *.cub + + + + + cube + output + Automatic + + Final output filename. + + + Output filename from the last enabled processing sequence. By + default the filename will be generated from the input filename with an + .cdr.IMG extension. + + + + + string + All + + Process a subset of bands + + + This parameter allows the user to specify a sub-set of + bands to process. Enter bands separated by commas (no spaces + allowed). For example, 1,3,8 or 1-3,9 or 5 + + + + + boolean + Remove Intermediate Files + + This option allows the user to decide whether the intermediate files + created in the thmproc application are to be deleted. The default value + is TRUE. + + TRUE + + + + + + + + boolean + + YES + + + Import and initialize a Messenger RDR file. + + + Process the input file through all level0 steps. This includes mdis2isis. + + + + + boolean + YES + + Process the input file through the calibration phase. + + + Process the input file through level1. This includes mdiscal. + + + TRIM + DARKCURRENT + IOF + + + + + integer + Trim off poor left pixles + + Removes the first few pixels of each line of the final cdr prouct. + + 3 + + + + boolean + FALSE + Export the calibrated image to cdr + +

    Exports the calibrated cube back into cdr format.

    +

    If only this step needs to be ran, use mdis2pds instead.

    +
    + + BITS + +
    + +
    + + + + string + Dark current calibration method + + MODEL + + + + + + + + + boolean + True + + Convert to I/F units + + +

    + This option when set wil convert the output to I/F from radiance values. + To convert from radiance to I/F (also known as radiance factor, the ratio + of measured radiance to that which would be measured from a white + perfectly Lambertian surface), the following expression should is applied: +

    +I_over_F(f) = L(f) * PI * (SOLAR_DISTANCE/149597870.691)**2 / F(f)                
    +            
    + where L(f) is calibrated radiance calculated for some filter f, + SOLAR_DISTANCE is that value for distance of the target object from + the center of the sun in kilometers (as indicated by the keyword + SOLAR_DISTANCE), 149597870.691 is the number of kilometers in 1 AU + and F(f) is effective average solar irradiance sampled under the + filter bandpass. +

    +

    + If the observed target is not of a valid body as recognized by + NAIF, the output is left in radiance. +

    +
    +
    +
    + + + + integer + 32 + + Number of bits for the output DN + + + The number of bits to compress the input data to. The valid data as + well as the five special pixel values (NULL, LIS, LRS, HIS, HRS) will be + compressed into this number of bits. The output data type will be + automaticity choosen using this value. A value of 8 will create + unsigned byte output files. Values from 9 to 16 will create unsigned + word output files. Unused bits in the unsigned word output file will be + set to zero. + + 8 + 32 + + + +
    + +
    diff --git a/isis/src/messenger/apps/mdisproc/tsts/Makefile b/isis/src/messenger/apps/mdisproc/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/messenger/apps/mdisproc/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/messenger/apps/mdisproc/tsts/cdr/Makefile b/isis/src/messenger/apps/mdisproc/tsts/cdr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..66a3a1e81a28e2dad41464a6ce4321c082bb6256 --- /dev/null +++ b/isis/src/messenger/apps/mdisproc/tsts/cdr/Makefile @@ -0,0 +1,12 @@ +APPNAME = mdisproc + +include $(ISISROOT)/make/isismake.tsts + +output.pvl.IGNORELINES = PRODUCT_CREATION_TIME DARK_STRIP_MEAN MEAN MINIMUM MAXIMUM STANDARD_DEVIATION + +commands: + $(APPNAME) from=$(INPUT)/EN0108840044M.IMG \ + to=$(OUTPUT)/output cdr=true > /dev/null; + catlab from=$(OUTPUT)/output.IMG to=$(OUTPUT)/output.pvl > /dev/null; + pds2isis from=$(OUTPUT)/output.IMG to=$(OUTPUT)/output.cub > /dev/null; + $(RM) $(OUTPUT)/output.IMG; diff --git a/isis/src/messenger/apps/mdisproc/tsts/default/Makefile b/isis/src/messenger/apps/mdisproc/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b5b6b153f619eef27d992868ddc3795d1698f6b9 --- /dev/null +++ b/isis/src/messenger/apps/mdisproc/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = mdisproc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/EN0108840044M.IMG \ + to=$(OUTPUT)/output > /dev/null; diff --git a/isis/src/messenger/apps/mdisproc/tsts/trim/Makefile b/isis/src/messenger/apps/mdisproc/tsts/trim/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3be0a9babc2a12abcc9935af9276af1dc1dacb6a --- /dev/null +++ b/isis/src/messenger/apps/mdisproc/tsts/trim/Makefile @@ -0,0 +1,7 @@ +APPNAME = mdisproc + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/EN0108840044M.IMG \ + to=$(OUTPUT)/output trim=5 > /dev/null; diff --git a/isis/src/messenger/objs/Makefile b/isis/src/messenger/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/messenger/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/messenger/objs/MdisCamera/Camera.plugin b/isis/src/messenger/objs/MdisCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..179224bd74ee27cfa012630fd763c35d47f1a96f --- /dev/null +++ b/isis/src/messenger/objs/MdisCamera/Camera.plugin @@ -0,0 +1,11 @@ +Group = Messenger/MDIS-WAC + Version = 1 + Library = MdisCamera + Routine = MdisCameraPlugin +EndGroup +Group = Messenger/MDIS-NAC + Version = 1 + Library = MdisCamera + Routine = MdisCameraPlugin +EndGroup + diff --git a/isis/src/messenger/objs/MdisCamera/Makefile b/isis/src/messenger/objs/MdisCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bb75a3712c41dc9e2a7a8a40fc0be3de0db28ea1 --- /dev/null +++ b/isis/src/messenger/objs/MdisCamera/Makefile @@ -0,0 +1,6 @@ +INCS = MdisCamera.h TaylorCameraDistortionMap.h +SRCS = MdisCamera.cpp TaylorCameraDistortionMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs + diff --git a/isis/src/messenger/objs/MdisCamera/MdisCamera.cpp b/isis/src/messenger/objs/MdisCamera/MdisCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..745d24d2453cdb0f510df64035ea21501a0213a5 --- /dev/null +++ b/isis/src/messenger/objs/MdisCamera/MdisCamera.cpp @@ -0,0 +1,226 @@ +/** + * @file + * $Revision: 1.11 $ + * $Date: 2009/08/31 15:12:30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "MdisCamera.h" +#include "iString.h" +#include "iException.h" +#include "CameraDistortionMap.h" +#include "TaylorCameraDistortionMap.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" + +using namespace std; + +namespace Isis { + namespace Messenger { + /** + * @brief Initialize the MDIS camera model for NAC and WAC + * + * This constructor reads the Messenger/MDIS instrument addendum for many of + * its default parameters. + * + * This camera model does not support subframes of jailbar imaging modes. + * An exception is thrown in those cases. + * + * @param lab The label provided to initialize the camera model for. + * + * @throws iException:User - when images are subframes or jailbars. + */ + MdisCamera::MdisCamera (Isis::Pvl &lab) : Isis::FramingCamera(lab) { + + // Set up detector constants + const int MdisWac(-236800); +// const int MdisNac(-236820); + + PvlGroup &inst = lab.FindGroup ("Instrument",Isis::Pvl::Traverse); + + // Clarification on MDIS subframe image mode provides us the ability to + // support this mode now. The entire MDIS frame is geometrically valid + // but only portions of the full frame actually contain image data. The + // portions outside subframes should be NULL and not interfere in + // downstream processing, such as mosaics. +#if defined(MDIS_SUBFRAMES_UNSUPPORTED) + int subFrameMode = inst["SubFrameMode"]; + if (subFrameMode != 0) { + string msg = "Subframe imaging mode is not supported!"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } +#endif + + // According to the MDIS team, this is nothing to be concerned with and + // should be treated as other normal observations. So the test to + // disallow it has been effectively removed 2007-09-05 (KJB). +#if defined(MDIS_JAILBARS_UNSUPPORTED) + int jailBars = inst["JailBars"]; + if (jailBars != 0) { + string msg = "Jail bar observations are not currently supported!"; + throw iException::Message(iException::Programmer,msg, _FILEINFO_); + } +#endif + + // Determine filter number. Only conditional code required for + // NAC and WAC support! + int filterNumber(0); // Default appropriate for MDIS-NAC + if (NaifIkCode() == MdisWac) { + PvlGroup &bandBin = lab.FindGroup("BandBin", Pvl::Traverse); + filterNumber = bandBin["Number"]; + } + + // Set up instrument and filter code strings + iString ikCode((int) NaifIkCode()); + int fnCode(NaifIkCode() - filterNumber); + iString filterCode(fnCode); + std::string ikernKey; + + // Fetch the frame translations from the instrument kernels + ikernKey = "INS" + ikCode + "_REFERENCE_FRAME"; + iString baseFrame = GetString(ikernKey); + + ikernKey = "INS" + filterCode + "_FRAME"; + iString ikFrame = GetString(ikernKey); + + // Set up the camera info from ik/iak kernels + + // Turns out (2008-01-17) the WAC has different focal lengths for + // each filter. Added to the instrument kernel (IAK) on this date. + double focalLength = GetDouble("INS" + filterCode + "_FOCAL_LENGTH"); + SetFocalLength(focalLength); + + SetPixelPitch(); + +// Removed by Jeff Anderson. The refactor of the SPICE class +// uses frames always so this is no longer needed +// LoadFrameMounting(baseFrame, ikFrame, false); + + // Get the start time from labels as the starting image time plus half + // the exposure duration (in ) to get pointing attitude. + // !!NOTE: The ephemeris time MUST be set prior to creating the + // cache (CreateCache) because the kernels are all unloaded + // after the cache is done and this operation will fail!! + string stime = inst["SpacecraftClockCount"]; + double expTime = inst["ExposureDuration"]; + + SpiceDouble etStart; + scs2e_c (NaifSpkCode(),stime.c_str(),&etStart); + + // Setup camera detector map + CameraDetectorMap *detMap = new CameraDetectorMap(this); + + // Setup focal plane map, and detector origin for the instrument that + // may have a filter (WAC only!). + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,fnCode); + + // Retrieve boresight location from instrument kernel (IK) (addendum?) + ikernKey = "INS" + ikCode + "_BORESIGHT_SAMPLE"; + double sampleBoreSight = GetDouble(ikernKey); + + ikernKey = "INS" + ikCode + "_BORESIGHT_LINE"; + double lineBoreSight = GetDouble(ikernKey); + + // Apply the boresight + focalMap->SetDetectorOrigin(sampleBoreSight,lineBoreSight); + + // Determine summing. MDIS has two sources of summing or binning. + // One is performed in the FPU and the in the MP, post-observation, + // on-board after coming out of the FPGAs, where the FPU binning is + // performed. The FPU binning was programmed incorrectly and the + // actual pixels from the detector are peculiar. Hence, I have + // designed this camera model such that the offsets can be managed + // external to the code. See the MDIS instrument kernel addendum + // in $ISIS3DATA/messenger/kernels/iak/mdisAddendum???.ti for the + // offsets for *each* detector. Note that an offset is only applied + // when FPU binning is performed. + int fpuBinMode = inst["FpuBinningMode"]; + int pixelBinMode = inst["PixelBinningMode"]; + + int summing(1 + (1 * pixelBinMode)); + // FPU binning was performed, retrieve the FPU binning offsets and + // apply them to the focal plane mapping. + if (fpuBinMode == 1) { + ikernKey = "INS" + ikCode + "_FPUBIN_START_SAMPLE"; + double fpuStartingSample = GetDouble(ikernKey); + detMap->SetStartingDetectorSample(fpuStartingSample); + + ikernKey = "INS" + ikCode + "_FPUBIN_START_LINE"; + double fpuStartingLine = GetDouble(ikernKey); + detMap->SetStartingDetectorLine(fpuStartingLine); + + summing *= 2; + } + + // Set summing/binning modes as an accumulation of FPU and MP binning. + detMap->SetDetectorLineSumming(summing); + detMap->SetDetectorSampleSumming(summing); + + // Setup distortion map. As of 2007/12/06, we now have an actual model. + // Note that this model supports distinct distortion for each WAC filter. + // See $ISIS3DATA/messenger/kernels/iak/mdisAddendumXXX.ti or possibly + // $ISIS3DATA/messenger/kernels/ik/msgr_mdis_vXXX.ti for the *_OD_K + // parameters. + // NAC has a new implementation of its distortion contributed by + // Scott Turner and Lillian Nguyen at JHUAPL. + if (NaifIkCode() == MdisWac) { + CameraDistortionMap *distortionMap = new CameraDistortionMap(this); + distortionMap->SetDistortion(fnCode); + } + else { // Camera is the NAC, use new distortion model + try { + TaylorCameraDistortionMap *distortionMap = new TaylorCameraDistortionMap(this); + distortionMap->SetDistortion(NaifIkCode()); + } catch (iException &ie) { + string msg = "New MDIS/NAC distortion model invalidates previous " + "SPICE - you must rerun spiceinit to get new kernels"; + ie.Message(iException::User, msg, _FILEINFO_); + throw; + } + } + + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + // Create a cache and grab spice info since it does not change for + // a framing camera (fixed spacecraft position and pointing) after, + // of course applying the gimble offset which is handled in the SPICE + // kernels (thank you!). Note this was done automagically in the + // SetEpheremisTime call above. IMPORTANT that it be done prior to + // creating the cache since all kernels are unloaded, essentially + // clearing the pool and whacking the frames definitions, required to + double obsTime(etStart + ((expTime / 2.0) / 1000.0)); + SetEphemerisTime(obsTime); + LoadCache(); + } + } +} + +/** + * This is the function that is called in order to instantiate a MdisCamera + * object. + * + * @param lab Cube labels + * + * @return Isis::Camera* MdisCamera + */ +extern "C" Isis::Camera *MdisCameraPlugin (Isis::Pvl &lab) { + return new Isis::Messenger::MdisCamera(lab); +} diff --git a/isis/src/messenger/objs/MdisCamera/MdisCamera.h b/isis/src/messenger/objs/MdisCamera/MdisCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..682872806009902aecb3a6b6ffebbdfb5006dff7 --- /dev/null +++ b/isis/src/messenger/objs/MdisCamera/MdisCamera.h @@ -0,0 +1,78 @@ +#ifndef MdisCamera_h +#define MdisCamera_h +/** + * @file + * $Revision: 1.9 $ + * $Date: 2009/08/31 15:12:30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "FramingCamera.h" + +namespace Isis { + namespace Messenger { + /** + * @brief MESSENGER MDIS NAC and WAC Camera Model + * + * This is the camera model for both MESSENGER MDIS Wide Angle (WAC) and + * Narrow Angle (NAC) cameras. + * + * This camera model is desinfed to be externally managed as much as + * possible through the Messenger MDIS instrument kernel (IAK). See the + * file $ISIS3DATA/messenger/kernels/iak/mdisAddendum???.ti for details. + * + * @ingroup SpiceInstrumentsAndCameras + * @ingroup MESSENGER + * + * @author 2005-07-29 Kris Becker + * + * @internal + * @history 2006-10-31 Jeff Anderson - Updated to accomodate Spice class + * refactory. + * @history 2007-04-24 Kris Becker - Corrected problems with setting Ephemeris + * time after the cache is created; fixed problem with FPU binning + * geometry is mapped to detector map as described in the SIS. This + * problem is due to an FPGA coding bug on the camera. + * @history 2007-09-05 Kris Becker - Removed test for jailbar imaging mode + * as the MDIS team reports it should be treated as a normal + * image. + * @history 2007-09-06 Kris Becker - Removed test for subframe imaging mode + * as the team provided calification on its implications. + * @history 2007-12-06 Kris Becker - Added camera distortion model provided + * by Scott Turner, JHU/APL. + * @history 2008-08-08 Steven Lambright Now using the new LoadCache(...) + * method instead of CreateCache(...). + * @history 2009-01-21 Kris Becker Added a new implementation of the MDIS + * NAC distortion model contributed by Scott Turner and Lillian + * Nguyen at JHU/APL. + * @history 2009-06-11 Steven Lambright - Documentation fixes + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class MdisCamera : public FramingCamera { + public: + MdisCamera (Isis::Pvl &lab); + + /** + * This destroys the MdisCamera object + */ + ~MdisCamera () {}; + }; + }; +}; + +#endif diff --git a/isis/src/messenger/objs/MdisCamera/MdisCamera.truth b/isis/src/messenger/objs/MdisCamera/MdisCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..5bd6edb2cb893061bc6858fc0eebda450d49bcf7 --- /dev/null +++ b/isis/src/messenger/objs/MdisCamera/MdisCamera.truth @@ -0,0 +1,20 @@ +Unit Test for MdisCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/messenger/objs/MdisCamera/TaylorCameraDistortionMap.cpp b/isis/src/messenger/objs/MdisCamera/TaylorCameraDistortionMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b1c407ac3a524ca61667b53cc803e46e8bb14ef --- /dev/null +++ b/isis/src/messenger/objs/MdisCamera/TaylorCameraDistortionMap.cpp @@ -0,0 +1,277 @@ +/** + * @file + * This class describes a geometric distortion model which is + * approximated by a third-order Taylor series expansion. + * + * Please direct questions to + * Lillian Nguyen, JHUAPL, (443)778-5477, Lillian.Nguyen@jhuapl.edu + */ +#include +#include "iString.h" +#include "TaylorCameraDistortionMap.h" + +namespace Isis { + +/** Camera distortion map constructor + * + * Create a camera distortion map. This class maps between distorted + * and undistorted focal plane x/y's. The default mapping is the + * identity, that is, the focal plane x/y and undistorted focal plane + * x/y will be identical. + * + * @param parent the parent camera that will use this distortion map + * @param zDirection the direction of the focal plane Z-axis + * (either 1 or -1) + * + */ + TaylorCameraDistortionMap::TaylorCameraDistortionMap(Camera *parent, double zDirection): + CameraDistortionMap(parent, zDirection) + { + } + + /** Load distortion coefficients + * + * This method loads the distortion coefficients from the instrument + * kernel. The coefficients in the NAIF instrument kernel are + * expected to be in the form of: + * + * @code + * INSxxxxx_OD_T_X = ( xa, xb, xc, xd, xe, xf, xg, xh, xi, xj ) + * INSxxxxx_OD_T_Y = ( ya, yb, yc, yd, ye, yf, yg, yh, yi, yj ) + * + * where xxxxx is the instrument code (always a negative number) + * @endcode + * + * These coefficient will be used to convert between focal plane + * xp,yp to undistorted x,y as follows + * + * [ xp ] = [ xa xb xc xd xe xf xg xh xi xj ] * [ 1 ] + * [ yp ] [ ya yb yc yd ye yf yg yh yi yj ] [ x ] + * [ y ] + * [ x*x ] + * [ x*y ] + * [ y*y ] + * [ x*x*x ] + * [ x*x*y ] + * [ x*y*y ] + * [ y*y*y ] + * + * @param naifIkCode Code to search for in instrument kernel + */ + void TaylorCameraDistortionMap::SetDistortion(const int naifIkCode) { + std::string odtxkey = "INS" + Isis::iString(naifIkCode) + "_OD_T_X"; + std::string odtykey = "INS" + Isis::iString(naifIkCode) + "_OD_T_Y"; + for (int i = 0; i < 10; ++i) { + p_odtx.push_back(Spice::GetDouble(odtxkey, i)); + p_odty.push_back(Spice::GetDouble(odtykey, i)); + } + } + + /** Compute undistorted focal plane x/y + * + * Compute undistorted focal plane x/y given a distorted focal plane x/y. + * The undistorted coordinates are solved for using the Newton-Raphson + * method for root-finding if the SetDistortion method is invoked. + * After calling this method, you can obtain the undistorted x/y via + * the UndistortedFocalPlaneX and UndistortedFocalPlaneY methods. + * + * @param dx distorted focal plane x in millimeters + * @param dy distorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + * @todo Review the tolerance and maximum iterations of the root- + * finding algorithm. + * @todo Review the handling of non-convergence of the root-finding + * algorithm. + * @todo Add error handling for near-zero determinant. + */ + bool TaylorCameraDistortionMap::SetFocalPlane(const double dx, const double dy) { + p_focalPlaneX = dx; + p_focalPlaneY = dy; + + // No coefficients == no distortion + if (p_odtx.size() <= 0 && p_odty.size() <= 0) { + p_undistortedFocalPlaneX = dx; + p_undistortedFocalPlaneY = dy; + return true; + } + + // Solve the distortion equation using the Newton-Raphson method. + // Set the error tolerance to about one millionth of a NAC pixel. + const double tol = 1.4E-5; + + // The maximum number of iterations of the Newton-Raphson method. + const int maxTries = 20; + + double x; + double y; + double fx; + double fy; + double Jxx; + double Jxy; + double Jyx; + double Jyy; + + // Initial guess at the root + x = dx; + y = dy; + + this->DistortionFunction(x, y, &fx, &fy); + + for (int count = 1; ((fabs(fx) + fabs(fy)) > tol) && (count < maxTries); count++){ + + this->DistortionFunction(x, y, &fx, &fy); + + fx = dx - fx; + fy = dy - fy; + + this->DistortionFunctionJacobian(x, y, &Jxx, &Jxy, &Jyx, &Jyy); + + double determinant = Jxx*Jyy - Jxy*Jyx; + if (determinant < 1E-6) + { + // + // Near-zero determinant. Add error handling here. + // + //-- Just break out and return with no convergence + break; + } + + x = x + (Jyy*fx - Jxy*fy)/determinant; + y = y + (Jxx*fy - Jyx*fx)/determinant; + } + + if ((fabs(fx) + fabs(fy)) <= tol) + { + // The method converged to a root. + p_undistortedFocalPlaneX = x; + p_undistortedFocalPlaneY = y; + } + else + { + // The method did not converge to a root within the maximum + // number of iterations. Return with no distortion. + p_undistortedFocalPlaneX = dx; + p_undistortedFocalPlaneY = dy; + } + + return true; + } + + /** Compute distorted focal plane x/y + * + * Compute distorted focal plane x/y given an undistorted focal plane x/y. + * The distortion model is approximated by a third order Taylor series + * expansion of a generic function if the SetDistortion method was invoked. + * After calling this method, you can obtain the distorted x/y via the + * FocalPlaneX and FocalPlaneY methods + * + * @param ux undistorted focal plane x in millimeters + * @param uy undistorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + */ + bool TaylorCameraDistortionMap::SetUndistortedFocalPlane(const double ux, + const double uy) { + p_undistortedFocalPlaneX = ux; + p_undistortedFocalPlaneY = uy; + + // No coefficients == nodistortion + if (p_odtx.size() <= 0 && p_odty.size() <= 0) { + p_focalPlaneX = ux; + p_focalPlaneY = uy; + return true; + } + + this->DistortionFunction(ux, uy, &p_focalPlaneX, &p_focalPlaneY); + + return true; + } + + /** + * Compute distorted focal plane dx,dy given an undistorted focal plane ux,uy. + * This describes the third order Taylor approximation to the distortion model. + * + * @param ux Undistored x + * @param uy Undistored y + * @param dx Result distorted x + * @param dy Result distorted y + */ + void TaylorCameraDistortionMap::DistortionFunction(double ux, double uy, double* dx, double* dy) { + + double f[10]; + f[0] = 1; + f[1] = ux; + f[2] = uy; + f[3] = ux*ux; + f[4] = ux*uy; + f[5] = uy*uy; + f[6] = ux*ux*ux; + f[7] = ux*ux*uy; + f[8] = ux*uy*uy; + f[9] = uy*uy*uy; + + *dx = 0.0; + *dy = 0.0; + + for (int i = 0; i < 10; i++) { + *dx = *dx + f[i] * p_odtx[i]; + *dy = *dy + f[i] * p_odty[i]; + } + + } + + /** + * Jacobian of the distortion function. The Jacobian was computed + * algebraically from the function described in the DistortionFunction + * method. + * + * @param x + * @param y + * @param Jxx + * @param Jxy + * @param Jyx + * @param Jyy + */ + void TaylorCameraDistortionMap::DistortionFunctionJacobian(double x, double y, double* Jxx, double* Jxy, double* Jyx, double* Jyy) { + + double d_dx[10]; + d_dx[0] = 0; + d_dx[1] = 1; + d_dx[2] = 0; + d_dx[3] = 2*x; + d_dx[4] = y; + d_dx[5] = 0; + d_dx[6] = 3*x*x; + d_dx[7] = 2*x*y; + d_dx[8] = y*y; + d_dx[9] = 0; + double d_dy[10]; + d_dy[0] = 0; + d_dy[1] = 0; + d_dy[2] = 1; + d_dy[3] = 0; + d_dy[4] = x; + d_dy[5] = 2*y; + d_dy[6] = 0; + d_dy[7] = x*x; + d_dy[8] = 2*x*y; + d_dy[9] = 3*y*y; + + *Jxx = 0.0; + *Jxy = 0.0; + *Jyx = 0.0; + *Jyy = 0.0; + + for (int i = 0; i < 10; i++) { + *Jxx = *Jxx + d_dx[i] * p_odtx[i]; + *Jxy = *Jxy + d_dy[i] * p_odtx[i]; + *Jyx = *Jyx + d_dx[i] * p_odty[i]; + *Jyy = *Jyy + d_dy[i] * p_odty[i]; + } + } + +} + diff --git a/isis/src/messenger/objs/MdisCamera/TaylorCameraDistortionMap.h b/isis/src/messenger/objs/MdisCamera/TaylorCameraDistortionMap.h new file mode 100644 index 0000000000000000000000000000000000000000..c3da41d5a48873b2aa9199e3cbea3c7358ba5238 --- /dev/null +++ b/isis/src/messenger/objs/MdisCamera/TaylorCameraDistortionMap.h @@ -0,0 +1,53 @@ +/** + * @file + * This class describes a non-radial distortion map. The distortion + * map is a third-order Taylor series expansion of a generic function. + * + * Please direct questions to + * Lillian Nguyen, JHUAPL, (443)778-5477, Lillian.Nguyen@jhuapl.edu + */ +#ifndef TaylorCameraDistortionMap_h +#define TaylorCameraDistortionMap_h + +#ifndef CameraDistortionMap_h +#include "CameraDistortionMap.h" +#endif +#include "Camera.h" + +namespace Isis { + /** Distort/undistort focal plane coordinates + * + * Creates a map for adding/removing optical distortions + * from the focal plane of a camera. + * + * @ingroup Camera + * + * @see Camera + * + * @author + * + * @internal + */ + class TaylorCameraDistortionMap : public CameraDistortionMap { + public: + TaylorCameraDistortionMap(Camera *parent, double zDirection = 1.0); + + void SetDistortion(const int naifIkCode); + + //! Destructor + ~TaylorCameraDistortionMap() {}; + + bool SetFocalPlane(const double dx, const double dy); + + bool SetUndistortedFocalPlane(const double ux, const double uy); + + protected: + std::vector p_odtx; //!< distortion x coefficients + std::vector p_odty; //!< distortion y coefficients + + void DistortionFunction(double ux, double uy, double* dx, double* dy); + void DistortionFunctionJacobian(double x, double y, double* Jxx, double* Jxy, double* Jyx, double* Jyy); + }; +}; + +#endif /*TaylorCameraDistortionMap_h*/ diff --git a/isis/src/messenger/objs/MdisCamera/iak/MdisCameraDistortionModel1.msg b/isis/src/messenger/objs/MdisCamera/iak/MdisCameraDistortionModel1.msg new file mode 100644 index 0000000000000000000000000000000000000000..4e09396211833900f9c8ff62609ddbed34729a22 --- /dev/null +++ b/isis/src/messenger/objs/MdisCamera/iak/MdisCameraDistortionModel1.msg @@ -0,0 +1,73 @@ +"Turner, Scott" +12/03/2007 03:08 PM To +Kris J Becker +cc +Mark Robinson , "Prockter, Louise M." +bcc + +Subject +MDIS Geometric Distortion Models (Initial, rough estimate) + + + + Kris, + +Here are the initial distortion model coefficients based on my analysis of +the star cluster mosaic images taken back in April of 2005. I opted to +provide effective focal lengths (setting k1 in the model to 0), because it +was convenient at the time in my code. We can adjust them later if you +prefer a calibrated focal length instead, as Randy suggested was common +practice. The error bars are one-sigma, assuming a Gaussian profile to the +measurement error--which may or may not be appropriate. + +WAC: + + f = 78.177 mm +/- 0.0041 + k1 = 0.0 + k3 = 1.6520E-5 +/- 2.2637E-06 + k5 = -1.2035E-7 +/- 2.5833E-08 + +NAC: + + f = 549.273 mm +/- 0.5263 + k1 = 0.0 + k3 = 1.6902E-5 +/- 5.1195E-05 + k5 = -5.4783E-7 +/- 5.6724E-07 + +Clearly the NAC fit results are worse, but this is to be expected given that +we are data starved per exposure by comparison to the WAC. A couple of +other points worth mentioning, as we discussed last week I removed the +(x0,y0) parameters from the modeling effort and simply set them both to 0.0. +If you have time to include them in your implementation in ISIS, their +inclusion beats down the residuals a noticeable amount. + +And, speaking of residuals, for reference, the residuals for the WAC +regression are roughly in the 0.18 to 0.25 range (RMS average/exposure). +And the NAC residuals are a bit worse, ranging from 0.29 to 0.76 RMS +average/exposure. + +A few other observations, in my modeling efforts I have noticed that the +point spread function for the NAC appears to be about 1.6-1.7 times broader +than that of the WAC. I seem to recall some discussion about this with Mark +a year or so ago, but only in so much as the NAC's was more broad. I'm not +sure if this particular value was to be expected or not. Also, I have +observed that the alignment uncertainties in the fits are about an order of +magnitude or so higher for the NAC images. However, I was expecting this, +as though it is much higher resolution we have far fewer stars per exposure. + +Once you have things up and running, if you happen to have any insights into +the accuracy of these numbers please share them with me. I am still going +to continue trying to reduce/interpret the data to resolve some of the +issues with the values I have provided. + +Feel free to call or shoot me an email if you have any questions or concerns +about what I have provided here. Thanks again for all of your patience, + +Scott + +PS: I was going to put the parameters into an update to the I-kernel +addendum you created, but figured rather than make you wait until tomorrow I +would just send the numbers along. If you still want me to capture them in +the text kernel format, let me know. Otherwise, pass back the updated one +you create and I'll see that it gets incorporated into the actual I-kernel +released on the SOC webserver (http://bronte.jhuapl.edu). diff --git a/isis/src/messenger/objs/MdisCamera/iak/MdisCameraDistortionModel2.msg b/isis/src/messenger/objs/MdisCamera/iak/MdisCameraDistortionModel2.msg new file mode 100644 index 0000000000000000000000000000000000000000..963e0059cc3431024c17d4412bfa5e43bd05080c --- /dev/null +++ b/isis/src/messenger/objs/MdisCamera/iak/MdisCameraDistortionModel2.msg @@ -0,0 +1,25 @@ +"Turner, Scott" +12/03/2007 03:12 PM To +Kris J Becker , "Prockter, Louise M." , Mark Robinson + +cc + +bcc + +Subject +MDIS Geometric Distortion Model Part II + + + + Kris, + +I just realized, for absolute clarity, I am using the following values for +the other pieces of the model which I did not fit: + + Detector Center in Pixels (512,512) + Diagonal Scale Factors (assume 14 micrometer pixels): 71.42857 + Off Diagonal Elements: 0.0 + +Sorry for neglecting to mention these in my previous email. + +Scott diff --git a/isis/src/messenger/objs/MdisCamera/iak/mdisAddendumXXX.ti b/isis/src/messenger/objs/MdisCamera/iak/mdisAddendumXXX.ti new file mode 100644 index 0000000000000000000000000000000000000000..bd10523f4ba8b4e6b43b735a3adf82be887a11a8 --- /dev/null +++ b/isis/src/messenger/objs/MdisCamera/iak/mdisAddendumXXX.ti @@ -0,0 +1,248 @@ +Messenger/MDIS Instrument Kernel +============================================================= + +This instrument kernel (I-kernel) contains parameters that +describe the Messenger MDIS narrow angle (NAC) and wide angle (WAC) +camera + +Version and Date +------------------------------------------------------------- + +Version 2.0 -- July 31, 2005 -- Kris Becker, U.S. Geological Survey, + Flagstaff, AZ + Initial version. + +Version 3.0 -- April 24, 2007 -- Kris Becker, U.S. Geological Survey, + Updated for modifications/refinements to the framing kernel. These + changes were introduced in msgr_v070.tf. + +Version 4.0 -- December 06, 2007 -- Kris Becker, U.S. Geological Survey, + Added initial camera distortion parameter for both NAC and WAC as + well as update the focal lengths. This model is provided courtesy + of Scott Turner, JHU, on 2007/12/03. + +Version 5.0 -- January 17, 2008 - Kris Becker, U.S. Gelogical Survey + Turns out the MDIS WAC has different focal lengths for each + of the 12 filters. The distortion model development was done + using filter 2, the clear filter. The other filter focal lengths + are derived from the ratio of the published (SIS) length and + the new focal lenght of filter 2. + +$Id: mdisAddendumXXX.ti,v 1.3 2008/01/18 13:30:30 kbecker Exp $ +------------------------------------------------------------- + +The following is the definitions for the MDIS Narrow Angle Camera (MDIS-NAC). +The platform ID is used to establish pointing times. Some missions use have +time offsets that are needed in order to correct for timing into the SPICE +kernels. Set the CK time tolerances used when searching for camera pointing +attitude in the CK kernels. + + +In general, the PLATFORM_ID is the NAIF code for the spacecraft instrument +platform. IN this case, it is analogous to the MSGR_SPACECRAFT frame id. + +SPK and CK time biases are used in cases where an offset exists in these +kernels in relation to spacecraft clock time. These times are expressed in +seconds. The CK_TIME_TOLERANCE is used as a direct argument in the NAIF +routine (ckpg_c) that finds camera pointing. This is expressed in spacecraft +clock ticks. + +\begindata +INS-236820_PLATFORM_ID = -236000 +INS-236820_SPK_TIME_BIAS = 0.0 +INS-236820_CK_TIME_BIAS = 0.0 +INS-236820_CK_TIME_TOLERANCE = 1 + +\begintext + +The REFERENCE_FRAME and FRAME are used to specify the frames that translate +from spacecraft instrument platform to the instrument orientation. These +are specific to each mission and are defined in the frame kernel (FK). +For MESSENGER, these are defined in msgr_v???.tf. + +\begindata +INS-236820_REFERENCE_FRAME = 'MSGR_SPACECRAFT' +INS-236820_FRAME = 'MSGR_MDIS_NAC' + + +\begintext +Focal length and pixel pitch are specific to a particular instrument. They +are expressed in millimeters. + +The boresight samples and lines are used to specify the center of the detector +device. There are two methods to specify the center of the detector array. +The BORESIGHT_SAMPLE and LINE and the detector mapping equations, ITRANSX and +ITRANSY. The BORESIGHT parameters are expressed in pixels. For a 1024x1024 +array, the nominal center would be 512.5 sample and 512.5 line. Pixel centers +are exactly in the center of the pixel. The upper left edge of the pixel is +(0.5, 0.5). + +\begindata +INS-236820_FOCAL_LENGTH = 549.273 +INS-236820_PIXEL_PITCH = 14.0E-3 +INS-236820_BORESIGHT_SAMPLE = 512.5 +INS-236820_BORESIGHT_LINE = 512.5 + + +\begintext +The MDIS instruments both have a special binning mode that is performed in the +FPGA unit. According to the calibration document, the code to perform the +binning of pixels does not perform as intended. The values of the keywords +INS-XXXXXX_FPUBIN_OFFSET_SAMPLE is mostly affected and can be modified to +specify the first pixel in the sample element of the detector using this mode. +The INS-XXXXXX_FPUBIN_OFFSET_LINE specifies the starting line of this offset. +In addition, when this mode is used it sets the summing mode to 2 as every +other sample and line is combined (averaged) to create the output image. + +\begindata +INS-236820_FPUBIN_START_SAMPLE = 9.0 +INS-236820_FPUBIN_START_LINE = 1.0 + +\begintext +The following provides a mapping of pixel location to detector coordinates +(TRANSX, TRANSY), detector coordinates to pixels (ITRANSX, ITRANSY) and +camera distortion parameters (OD_K). + +\begindata +INS-236820_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236820_TRANSY = ( 0.0, 0.0, 14.0E-3) + +INS-236820_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236820_ITRANSL = ( 0.0, 0.0, 71.42857143) + +INS-236820_OD_K = ( 0.0, 1.6902E-5, -5.4783E-7) + +\begintext +This is the description of the Messenger MDIS wide angle camera (MDIS-WAC). +It has twelve filters on a wheel, however, the transforms for pixel/detector +coordinates are independantly defined to simplify maintainance of these +values should the need arise during flight. + +\begindata +INS-236800_PLATFORM_ID = -236000 +INS-236800_SPK_TIME_BIAS = 0.0 +INS-236800_CK_TIME_BIAS = 0 +INS-236800_CK_TIME_TOLERANCE = 1 + +INS-236800_REFERENCE_FRAME = 'MSGR_SPACECRAFT' +INS-236800_FRAME = 'MSGR_MDIS_WAC' + +INS-236800_FOCAL_LENGTH = 78.177 +INS-236800_PIXEL_PITCH = 14.0E-3 +INS-236800_BORESIGHT_SAMPLE = 512.5 +INS-236800_BORESIGHT_LINE = 512.5 + +INS-236800_FPUBIN_START_SAMPLE = 9.0 +INS-236800_FPUBIN_START_LINE = 1.0 + + +\begintext +The following provides a mapping of pixel location to detector coordinates +(TRANSX, TRANSY) and detector coordinates to pixels (ITRANSX, ITRANSY) and +camera distortion parameters (OD_K). + +\begindata + +INS-236800_FRAME = 'MSGR_MDIS_NADIR_SPACECRAFT' +INS-236800_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236800_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236800_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236800_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236800_OD_K = ( 0.0, 1.6520E-5, -1.2035E-7) + +INS-236801_FRAME = 'MSGR_MDIS_WAC_FILTER1' +INS-236801_FOCAL_LENGTH = 78.232010 +INS-236801_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236801_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236801_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236801_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236801_OD_K = ( 0.0, 1.6520E-5, -1.2035E-7) + +INS-236802_FRAME = 'MSGR_MDIS_WAC_FILTER2' +INS-236802_FOCAL_LENGTH = 78.177000 +INS-236802_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236802_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236802_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236802_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236802_OD_K = ( 0.0, 1.6520E-5, -1.2035E-7) + +INS-236803_FRAME = 'MSGR_MDIS_WAC_FILTER3' +INS-236803_FOCAL_LENGTH = 78.000968 +INS-236803_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236803_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236803_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236803_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236803_OD_K = ( 0.0, 1.6520E-5, -1.2035E-7) + +INS-236804_FRAME = 'MSGR_MDIS_WAC_FILTER4' +INS-236804_FOCAL_LENGTH = 78.036975 +INS-236804_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236804_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236804_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236804_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236804_OD_K = ( 0.0, 1.6520E-5, -1.2035E-7) + +INS-236805_FRAME = 'MSGR_MDIS_WAC_FILTER5' +INS-236805_FOCAL_LENGTH = 78.122990 +INS-236805_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236805_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236805_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236805_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236805_OD_K = ( 0.0, 1.6520E-5, -1.2035E-7) + +INS-236806_FRAME = 'MSGR_MDIS_WAC_FILTER6' +INS-236806_FOCAL_LENGTH = 78.088984 +INS-236806_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236806_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236806_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236806_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236806_OD_K = ( 0.0, 1.6520E-5, -1.2035E-7) + +INS-236807_FRAME = 'MSGR_MDIS_WAC_FILTER7' +INS-236807_FOCAL_LENGTH = 78.232010 +INS-236807_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236807_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236807_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236807_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236807_OD_K = ( 0.0, 1.6520E-5, -1.2035E-7) + +INS-236808_FRAME = 'MSGR_MDIS_WAC_FILTER8' +INS-236808_FOCAL_LENGTH = 78.463051 +INS-236808_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236808_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236808_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236808_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236808_OD_K = ( 0.0, 1.6520E-5, -1.2035E-7) + +INS-236809_FRAME = 'MSGR_MDIS_WAC_FILTER9' +INS-236809_FOCAL_LENGTH = 78.524062 +INS-236809_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236809_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236809_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236809_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236809_OD_K = ( 0.0, 1.6520E-5, -1.2035E-7) + +INS-236810_FRAME = 'MSGR_MDIS_WAC_FILTER10' +INS-236810_FOCAL_LENGTH = 78.404041 +INS-236810_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236810_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236810_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236810_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236810_OD_K = ( 0.0, 1.6520E-5, -1.2035E-7) + +INS-236811_FRAME = 'MSGR_MDIS_WAC_FILTER11' +INS-236811_FOCAL_LENGTH = 78.549067 +INS-236811_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236811_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236811_ITRANSS = ( 0.0, 71.42857143 , 0.0) +INS-236811_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236811_OD_K = ( 0.0 1.6520E-5, -1.2035E-7) + +INS-236812_FRAME = 'MSGR_MDIS_WAC_FILTER12' +INS-236812_FOCAL_LENGTH = 78.322026 +INS-236812_TRANSX = ( 0.0, 14.0E-3, 0.0) +INS-236812_TRANSY = ( 0.0, 0.0, 14.0E-3) +INS-236812_ITRANSS = ( 0.0, 71.42857143, 0.0) +INS-236812_ITRANSL = ( 0.0, 0.0, 71.42857143) +INS-236812_OD_K = ( 0.0, 1.6520E-5, -1.2035E-7) + diff --git a/isis/src/messenger/objs/MdisCamera/iak/wacfocallen.pro b/isis/src/messenger/objs/MdisCamera/iak/wacfocallen.pro new file mode 100644 index 0000000000000000000000000000000000000000..81288616b87ff5af38b70dc38773155ee8bedeb8 --- /dev/null +++ b/isis/src/messenger/objs/MdisCamera/iak/wacfocallen.pro @@ -0,0 +1,39 @@ +pro wacfocallen, newfl=newfl,iak=iak + +wacfls = [ 78.218D, 78.163D, 77.987D, 78.023D, 78.109D, 78.075D, $ + 78.218D, 78.449D, 78.510D, 78.390D, 78.535D, 78.308D ] + +; Filter two is the clear filter and used to construct the geometric +; distortion model. Any change in this filter is directly proportional +; to the other filters. +baseFilterIndex = 1 + +if (N_ELEMENTS(newfl) le 0) then $ + newfl = double(wacfls[baseFilterIndex]) + +fratio = double(newfl / wacfls[baseFilterIndex]) + +for i = 0, 11 do begin + flen = wacfls[i] * fratio + print, 'Filter',i+1,' :, FocalLength: ', flen +endfor + +if (N_ELEMENTS(iak) gt 0) then begin + +print, " " +print, " Naif Instrument Camera Kernel Focal Lengths" +wacN0 = -236801 +flen = wacfls[baseFilterIndex] * fratio +print, "INS" + strcompress(string(wacN0+1),/REMOVE_ALL) + "_FOCAL_LENGTH = ", flen +for i = 0, 11 do begin + flen = wacfls[i] * fratio + print, "INS" + strcompress(string(wacN0-i),/REMOVE_ALL) + "_FOCAL_LENGTH = ", flen +endfor + +endif + +return +end + + + diff --git a/isis/src/messenger/objs/MdisCamera/unitTest.cpp b/isis/src/messenger/objs/MdisCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5859f20de62c12044af457c00e9422e4305d63d --- /dev/null +++ b/isis/src/messenger/objs/MdisCamera/unitTest.cpp @@ -0,0 +1,90 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for MdisCamera..." << endl; + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownLat = -0.1675611160495559; + double knownLon = 224.9453228529497; + + //Isis::Pvl p("$mgs/testData/lub0428b.cub"); + Isis::Pvl p("$messenger/testData/EW0089570936I.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.001) deltaSamp = 0; + if (fabs(deltaLine) < 0.001) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/mex/Makefile b/isis/src/mex/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/mex/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/mex/apps/Makefile b/isis/src/mex/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/mex/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/mex/apps/hrsc2isis/Makefile b/isis/src/mex/apps/hrsc2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mex/apps/hrsc2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mex/apps/hrsc2isis/assets/images/h0279_0000_re2.in_zoomed.jpg b/isis/src/mex/apps/hrsc2isis/assets/images/h0279_0000_re2.in_zoomed.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3034734706fffe2d420a5d42cf2e305b92a778bf Binary files /dev/null and b/isis/src/mex/apps/hrsc2isis/assets/images/h0279_0000_re2.in_zoomed.jpg differ diff --git a/isis/src/mex/apps/hrsc2isis/assets/images/h0279_0000_re2.jpg b/isis/src/mex/apps/hrsc2isis/assets/images/h0279_0000_re2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bcdd69f38d6a6a76badb9c89de263ba3bea74662 Binary files /dev/null and b/isis/src/mex/apps/hrsc2isis/assets/images/h0279_0000_re2.jpg differ diff --git a/isis/src/mex/apps/hrsc2isis/assets/images/h0279_0000_re2.out.jpg b/isis/src/mex/apps/hrsc2isis/assets/images/h0279_0000_re2.out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..87b7d0a362c20723137df736bcdd2de79bbd148f Binary files /dev/null and b/isis/src/mex/apps/hrsc2isis/assets/images/h0279_0000_re2.out.jpg differ diff --git a/isis/src/mex/apps/hrsc2isis/assets/images/h0279_0000_re2.out_zoomed.jpg b/isis/src/mex/apps/hrsc2isis/assets/images/h0279_0000_re2.out_zoomed.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4946dc69b4ecadcb715677b3e81d9335b106b7ad Binary files /dev/null and b/isis/src/mex/apps/hrsc2isis/assets/images/h0279_0000_re2.out_zoomed.jpg differ diff --git a/isis/src/mex/apps/hrsc2isis/assets/thumbs/h0279_0000_re2.in_zoomed.jpg b/isis/src/mex/apps/hrsc2isis/assets/thumbs/h0279_0000_re2.in_zoomed.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0a98df99db784f22ac8888ad8066c6feddd9b497 Binary files /dev/null and b/isis/src/mex/apps/hrsc2isis/assets/thumbs/h0279_0000_re2.in_zoomed.jpg differ diff --git a/isis/src/mex/apps/hrsc2isis/assets/thumbs/h0279_0000_re2.jpg b/isis/src/mex/apps/hrsc2isis/assets/thumbs/h0279_0000_re2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1b6bbcb4c4b565f50b4c91e29405fc1dbfbbff02 Binary files /dev/null and b/isis/src/mex/apps/hrsc2isis/assets/thumbs/h0279_0000_re2.jpg differ diff --git a/isis/src/mex/apps/hrsc2isis/assets/thumbs/h0279_0000_re2.out.jpg b/isis/src/mex/apps/hrsc2isis/assets/thumbs/h0279_0000_re2.out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3334d0beb9e51e9a283fa5c271612f66a3d0b374 Binary files /dev/null and b/isis/src/mex/apps/hrsc2isis/assets/thumbs/h0279_0000_re2.out.jpg differ diff --git a/isis/src/mex/apps/hrsc2isis/assets/thumbs/h0279_0000_re2.out_zoomed.jpg b/isis/src/mex/apps/hrsc2isis/assets/thumbs/h0279_0000_re2.out_zoomed.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d9ae43a1eaa92debf2da630f804da1603e29dce Binary files /dev/null and b/isis/src/mex/apps/hrsc2isis/assets/thumbs/h0279_0000_re2.out_zoomed.jpg differ diff --git a/isis/src/mex/apps/hrsc2isis/hrsc2isis.cpp b/isis/src/mex/apps/hrsc2isis/hrsc2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..952a44767f24e3d9ccdef2ed30e013c95aa61b07 --- /dev/null +++ b/isis/src/mex/apps/hrsc2isis/hrsc2isis.cpp @@ -0,0 +1,289 @@ +#include "Isis.h" +#include "ProcessImportPds.h" + +#include "UserInterface.h" +#include "EndianSwapper.h" +#include "Table.h" +#include "CubeAttribute.h" +#include "LineManager.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void IgnoreData(Isis::Buffer &buf) {}; +void WriteOutput(Isis::Buffer &buf); +void TranslateHrscLabels(Pvl &inLabels, Pvl &outLabel); + +Cube *outCube = NULL; +long numLinesSkipped = 0; +std::vector< bool > lineInFile; + +/** + * This program imports Mars Express HRSC files + * + * This works by first determining whether or not the input file + * has prefix data. + * + * If there is prefix data, a StartProcess is called with the + * IgnoreData() function callback in order to get the import class to + * collect prefix data. Once the prefix data is populated, we go ahead + * and look for "gaps" - HRSC files can give us a time and exposure duration + * for each line, we look for where the time + exposure duration != next line's time. + * We populate a table (LineScanTimes) with the prefix data and lineInFile with whether or not + * a gap should be inserted. + * + * For all files, we now process the data using the WriteOutput callback. If there were gaps, + * WriteOutput will put them in their proper places. Finally, we translate the labels and put + * the LineScanTimes (if necessary) in the output cube. + * + * This is a two-pass system for files with prefix data, one-pass for files without. + * + * The Isis2 equivalent to this program is mex2isis.pl. It is worth noting that regardless of the + * input file's byte order, the prefix data byte order is always LSB. + */ +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + + try { + Pvl temp(ui.GetFilename("FROM")); + // Check for HRSC file + if(temp["INSTRUMENT_ID"][0] != "HRSC") throw iException::Message(iException::User, "", _FILEINFO_); + } + catch(iException e) { + e.Clear(); + iString msg = "File [" + ui.GetFilename("FROM") + + "] does not appear to be a Mars Express HRSC image."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + ProcessImportPds p; + Pvl label; + lineInFile.clear(); + numLinesSkipped = 0; + + p.SetPdsFile(ui.GetFilename("FROM"), "", label); + + CubeAttributeOutput outAtt(ui.GetFilename("TO")); + outCube = new Cube(); + + outCube->SetByteOrder(outAtt.ByteOrder()); + outCube->SetCubeFormat(outAtt.FileFormat()); + if(outAtt.DetachedLabel()) outCube->SetDetached(); + if(outAtt.AttachedLabel()) outCube->SetAttached(); + + /** + * Isis2 mex2isis.pl: + * if (index($detector_id,"MEX_HRSC_SRC") < 0 && + * $processing_level_id < 3) + */ + bool hasPrefix = (label["DETECTOR_ID"][0] != "MEX_HRSC_SRC" && (int)label["PROCESSING_LEVEL_ID"] < 3); + + TableField ephTimeField("EphemerisTime", TableField::Double); + TableField expTimeField("ExposureTime", TableField::Double); + TableField lineStartField("LineStart", TableField::Integer); + + TableRecord timesRecord; + timesRecord += ephTimeField; + timesRecord += expTimeField; + timesRecord += lineStartField; + + Table timesTable("LineScanTimes", timesRecord); + + if(hasPrefix) { + p.SetDataPrefixBytes((int)label.FindObject("IMAGE")["LINE_PREFIX_BYTES"]); + p.SaveDataPrefix(); + + p.Progress()->SetText("Reading Prefix Data"); + p.StartProcess(IgnoreData); + + // The prefix data is always in LSB format, regardless of the overall file format + EndianSwapper swapper("LSB"); + + std::vector ephemerisTimes; + std::vector exposureTimes; + std::vector< std::vector > prefix = p.DataPrefix(); + + for(int line = 0; line < p.Lines(); line++) { + double ephTime = swapper.Double((double *)prefix[0][line]); + double expTime = swapper.Float((float *)(prefix[0][line] + 8)) / 1000.0; + + if(line > 0) { + /** + * We know how many skipped lines with this equation. We take the + * difference in the current line and the last line's time, which will + * ideally be equal to the last line's exposure duration. We divide this by + * the last line's exposure duration, and the result is the 1-based count of + * how many exposures there were between the last line and the current line. + * We subtract one in order to remove the known exposure, and the remaining should + * be the 1-based count of how many lines were skipped. Add 0.5 to round up. + */ + int skippedLines = (int)((ephTime - ephemerisTimes.back()) / exposureTimes.back() - 1.0 + 0.5); + + for(int i = 0; i < skippedLines; i++) { + ephemerisTimes.push_back(ephemerisTimes.back() + exposureTimes.back()); + exposureTimes.push_back(exposureTimes.back()); + lineInFile.push_back(false); + } + } + + ephemerisTimes.push_back(ephTime); + exposureTimes.push_back(expTime); + lineInFile.push_back(true); + } + + double lastExp = 0.0; + for(unsigned int i = 0; i < ephemerisTimes.size(); i++) { + if(lastExp != exposureTimes[i]) { + lastExp = exposureTimes[i]; + timesRecord[0] = ephemerisTimes[i]; + timesRecord[1] = exposureTimes[i]; + timesRecord[2] = (int)i + 1; + timesTable += timesRecord; + } + } + + outCube->SetDimensions(p.Samples(), lineInFile.size(), p.Bands()); + } + else { + //Checks if in file is rdr + Filename inFile = ui.GetFilename("FROM"); + string msg = "[" + inFile.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + p.Progress()->SetText("Importing"); + outCube->Create(ui.GetFilename("TO")); + p.StartProcess(WriteOutput); + + if(hasPrefix) { + outCube->Write(timesTable); + } + + // Get as many of the other labels as we can + Pvl otherLabels; + + //p.TranslatePdsLabels (otherLabels); + TranslateHrscLabels(label, otherLabels); + + if(otherLabels.HasGroup("Mapping") && + (otherLabels.FindGroup("Mapping").Keywords() > 0)) { + outCube->PutGroup(otherLabels.FindGroup("Mapping")); + } + + if(otherLabels.HasGroup("Instrument") && + (otherLabels.FindGroup("Instrument").Keywords() > 0)) { + outCube->PutGroup(otherLabels.FindGroup("Instrument")); + } + + if(otherLabels.HasGroup("BandBin") && + (otherLabels.FindGroup("BandBin").Keywords() > 0)) { + outCube->PutGroup(otherLabels.FindGroup("BandBin")); + } + + if(otherLabels.HasGroup("Archive") && + (otherLabels.FindGroup("Archive").Keywords() > 0)) { + outCube->PutGroup(otherLabels.FindGroup("Archive")); + } + + if(otherLabels.HasGroup("Kernels") && + (otherLabels.FindGroup("Kernels").Keywords() > 0)) { + outCube->PutGroup(otherLabels.FindGroup("Kernels")); + } + + p.EndProcess(); + + outCube->Close(); + delete outCube; + outCube = NULL; + lineInFile.clear(); +} + +void WriteOutput(Isis::Buffer &buf) { + LineManager outLines(*outCube); + + if(lineInFile.size()) { + for(int i = 0; i < outLines.size(); i++) { + outLines[i] = Isis::Null; + } + + while(!lineInFile[(buf.Line()+numLinesSkipped) % lineInFile.size()]) { + outLines.SetLine(buf.Line() + numLinesSkipped, buf.Band()); + outCube->Write(outLines); + numLinesSkipped ++; + } + } + + outLines.SetLine(buf.Line() + numLinesSkipped, buf.Band()); + + // outLines.Copy(buf); doesn't work because the raw buffers don't match + for(int i = 0; i < outLines.size(); i++) + outLines[i] = buf[i]; + + outCube->Write(outLines); +} + +void TranslateHrscLabels(Pvl &inLabels, Pvl &outLabel) { + // Get the directory where the MRO HiRISE translation tables are. + PvlGroup dataDir(Preference::Preferences().FindGroup("DataDirectory")); + iString transDir = (string) dataDir["Mex"] + "/translations/"; + + // Translate the Instrument group + Filename transFile(transDir + "hrscInstrument.trn"); + PvlTranslationManager instrumentXlater(inLabels, transFile.Expanded()); + instrumentXlater.Auto(outLabel); + + if(inLabels.HasKeyword("MACROPIXEL_SIZE")) { + outLabel.FindGroup("Instrument", Pvl::Traverse) += PvlKeyword("Summing", (int)inLabels["MACROPIXEL_SIZE"]); + } + else { + outLabel.FindGroup("Instrument", Pvl::Traverse) += PvlKeyword("Summing", 1); + } + + // Remove 'Z' from times + iString startTime = outLabel.FindGroup("Instrument", Pvl::Traverse)["StartTime"][0]; + startTime = startTime.substr(0, startTime.size() - 1); + outLabel.FindGroup("Instrument", Pvl::Traverse)["StartTime"] = startTime; + + iString stopTime = outLabel.FindGroup("Instrument", Pvl::Traverse)["StopTime"][0]; + stopTime = stopTime.substr(0, stopTime.size() - 1); + outLabel.FindGroup("Instrument", Pvl::Traverse)["StopTime"] = stopTime; + + // Translate the BandBin group + transFile = transDir + "hrscBandBin.trn"; + PvlTranslationManager bandBinXlater(inLabels, transFile.Expanded()); + bandBinXlater.Auto(outLabel); + + // Translate the Archive group + transFile = transDir + "hrscArchive.trn"; + PvlTranslationManager archiveXlater(inLabels, transFile.Expanded()); + archiveXlater.Auto(outLabel); + + std::map naifIkCodes; + naifIkCodes.insert(std::pair("MEX_HRSC_HEAD", -41210)); + naifIkCodes.insert(std::pair("MEX_HRSC_S2", -41211)); + naifIkCodes.insert(std::pair("MEX_HRSC_RED", -41212)); + naifIkCodes.insert(std::pair("MEX_HRSC_P2", -41213)); + naifIkCodes.insert(std::pair("MEX_HRSC_BLUE", -41214)); + naifIkCodes.insert(std::pair("MEX_HRSC_NADIR", -41215)); + naifIkCodes.insert(std::pair("MEX_HRSC_GREEN", -41216)); + naifIkCodes.insert(std::pair("MEX_HRSC_P1", -41217)); + naifIkCodes.insert(std::pair("MEX_HRSC_IR", -41218)); + naifIkCodes.insert(std::pair("MEX_HRSC_S1", -41219)); + naifIkCodes.insert(std::pair("MEX_HRSC_SRC", -41220)); + + std::string key = outLabel.FindGroup("Archive", Pvl::Traverse)["DetectorId"]; + int ikCode = naifIkCodes[key]; + + if(ikCode < -41220 || ikCode > -41210) { + std::string msg = "Unrecognized Detector ID ["; + msg += key; + msg += "]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + PvlGroup kerns("Kernels"); + kerns += PvlKeyword("NaifIkCode", ikCode); + outLabel.AddGroup(kerns); +} diff --git a/isis/src/mex/apps/hrsc2isis/hrsc2isis.xml b/isis/src/mex/apps/hrsc2isis/hrsc2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..209e8832dad9e34528044b46c1c9585bd997424c --- /dev/null +++ b/isis/src/mex/apps/hrsc2isis/hrsc2isis.xml @@ -0,0 +1,140 @@ + + + + + Import HRSC image + + + This program imports Mars Express HRSC files. This works by first + determining whether or not the input file has prefix data. If there is + prefix data, the prefix data is collected and used to look for "gaps" - HRSC + files can give us a time and exposure duration for each line, we look for + where the time + exposure duration =/= next line's time. We populate a + table (LineScanTimes) with the prefix data and lineInFile with whether or + not a gap should be inserted. For all files, we now process the data and if + there were gaps, they will be put in their proper places. This is a two-pass + system for files with prefix data, one-pass for files without. The Isis2 + equivalent to this program is mex2isis.pl. It is worth noting that + regardless of the input file's byte order, the prefix data byte order is + always LSB. + + + + + Original version + + + Checks if input file is rdr based on whether or not the input file has + prefix data. + + + Removed references to CubeInfo + + + Updated to support the HRSC camera model. The Kernels group now has the IK code + properly added, the summing keyword is propagated, the times table is now compressed + into only having entries on time changes, and the times no longer have a 'Z' at the end + of them once imported. + + + + + mex2isis.pl + readpfx + + + + Mars Express + + + + + + filename + input + + Input HRSC Image + + + Use this parameter to select the PDS filename. This file + must contain the PDS labels, however the image data can + be detached and will be automatically obtained from the + PDS image pointer keyword. If the pointer is incorrect then + use the IMAGE parameter to specify the file containing the + binary image data. + + + *.lbl *.img + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + + + + Import an HRSC image with gaps + + This example covers importing an HRSC image and shows what happens when + gaps are found. + + + from=h0279_0000_re2.img to=h0279_0000_re2.cub + Run this program on "h0279_0000_re2.img" + + + + + This is the raw input image, not imported with this program + + This image was imported with pds2isis and then exported with isis2std, in order to get a + good idea of what the raw input image looks like. + + + + + + Input discontinuity from this example + + This is a zoomed in region of what will become a gap from this example. Notice the + features aren't aligned in the middle of the image, as if there are missing lines. + + + + + + + + Output image from this example + + This is the output from this example. The large "black" areas are NULL lines where data + was missing, according to the prefix data on the raw input image. + + + + + + A gap from this example + + This is a zoomed in region of a gap from this example. Notice the features on the top + and bottom would not normally line up if the gap did not exist. + + + + + + + diff --git a/isis/src/mex/apps/hrsc2isis/tsts/Makefile b/isis/src/mex/apps/hrsc2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mex/apps/hrsc2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mex/apps/hrsc2isis/tsts/default/Makefile b/isis/src/mex/apps/hrsc2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8c4b08f12b51391a93067e6c4809469af4514ae4 --- /dev/null +++ b/isis/src/mex/apps/hrsc2isis/tsts/default/Makefile @@ -0,0 +1,14 @@ +APPNAME = hrsc2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/h0279_0000_re2.img TO=$(OUTPUT)/h0279_0000_re2.cub > /dev/null; + tabledump FROM=$(OUTPUT)/h0279_0000_re2.cub TO=$(OUTPUT)/h0279_0000_re2.txt NAME=LineScanTimes > /dev/null; + catlab FROM=$(OUTPUT)/h0279_0000_re2.cub > $(OUTPUT)/h0279_0000_re2.pvl; + if [ `$(APPNAME) FROM=$(INPUT)/h1580_0008_sr3.img \ + TO=$(OUTPUT)/junk.cub\ + -preference=$(ISISROOT)/src/base/objs/Preference/TestPreferences \ + >& $(OUTPUT)/error.txt` ]; \ + then true; \ + fi; diff --git a/isis/src/mex/objs/HrscCamera/Camera.plugin b/isis/src/mex/objs/HrscCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..17f54525a7ba4c68b60ea1eb0a9db949e6b3db67 --- /dev/null +++ b/isis/src/mex/objs/HrscCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = MarsExpress/HRSC + Version = 1 + Library = HrscCamera + Routine = HrscCameraPlugin +EndGroup + diff --git a/isis/src/mex/objs/HrscCamera/HrscCamera.cpp b/isis/src/mex/objs/HrscCamera/HrscCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4f66a08b3092dc4ed006253395a5bfaa2942a9a3 --- /dev/null +++ b/isis/src/mex/objs/HrscCamera/HrscCamera.cpp @@ -0,0 +1,113 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/08/31 15:12:30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "HrscCamera.h" +#include "VariableLineScanCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraDistortionMap.h" +#include "LineScanCameraGroundMap.h" +#include "LineScanCameraSkyMap.h" +#include "iTime.h" +#include "Statistics.h" + +using namespace std; + +namespace Isis { + namespace Mex { + /** + * Creates a HrscCamera Camera Model + * + * @param lab Pvl label from the iamge + */ + HrscCamera::HrscCamera (Isis::Pvl &lab) : Isis::LineScanCamera(lab) { + // Setup camera characteristics from instrument and frame kernel + SetFocalLength(); + SetPixelPitch(0.007); + InstrumentRotation()->SetFrame(-41210); + + // Get required keywords from instrument group + Isis::PvlGroup &inst = lab.FindGroup ("Instrument",Isis::Pvl::Traverse); + iTime stime(inst["StartTime"][0]); + + ReadLineRates(lab.Filename()); + + // Setup detector map for transform of image pixels to detector position + new VariableLineScanCameraDetectorMap(this,p_lineRates); + DetectorMap()->SetDetectorSampleSumming(inst["Summing"]); + + // Setup focal plane map for transform of detector position to + // focal plane x/y. This will read the appropriate CCD + // transformation coefficients from the instrument kernel + + new CameraFocalPlaneMap(this, NaifIkCode()); + + string ikernKey = "INS" + iString((int)NaifIkCode()) + "_BORESIGHT_SAMPLE"; + double sampleBoresight = GetDouble(ikernKey); + + ikernKey = "INS" + iString((int)NaifIkCode()) + "_BORESIGHT_LINE"; + double lineBoresight = GetDouble(ikernKey); + + FocalPlaneMap()->SetDetectorOrigin(sampleBoresight, lineBoresight); + + // Setup distortion map. This will read the optical distortion + // coefficients from the instrument kernel + new CameraDistortionMap(this); + + // Setup the ground and sky map to transform undistorted focal + // plane x/y to lat/lon or ra/dec respectively. + new LineScanCameraGroundMap(this); + new LineScanCameraSkyMap(this); + + LoadCache(); + } + + //! Destroys the HiriseCamera object + HrscCamera::~HrscCamera () {} + + void HrscCamera::ReadLineRates(iString filename) { + Table timesTable("LineScanTimes", filename); + + if(timesTable.Records() <= 0) { + std::string msg = "Table [LineScanTimes] in ["; + msg += filename + "] must not be empty"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + + for(int i = 0; i < timesTable.Records(); i++) { + p_lineRates.push_back(LineRateChange((int)timesTable[i][2],(double)timesTable[i][0], timesTable[i][1])); + } + + if(p_lineRates.size() <= 0) { + std::string msg = "There is a problem with the data within the Table "; + msg += "[LineScanTimes] in [" + filename + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + } +} + +// H r s c C a m e r a P l u g i n +// +extern "C" Isis::Camera *HrscCameraPlugin (Isis::Pvl &lab) { + return new Isis::Mex::HrscCamera(lab); +} diff --git a/isis/src/mex/objs/HrscCamera/HrscCamera.h b/isis/src/mex/objs/HrscCamera/HrscCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..d82975e4c8061478a911dd3dd3a49ea219734404 --- /dev/null +++ b/isis/src/mex/objs/HrscCamera/HrscCamera.h @@ -0,0 +1,65 @@ +#ifndef HrscCamera_h +#define HrscCamera_h + +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/08/31 15:12:31 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "LineScanCamera.h" +#include "VariableLineScanCameraDetectorMap.h" + +namespace Isis { + namespace Mex { + /** + * @brief HRSC Camera Model + * + * This class is the implementation of the camera model + * for the MEX HRSC instrument. + * + * @ingroup SpiceInstrumentsAndCameras + * + * @author 2008-07-28 Steven Lambright + * + * @internal + * @history 2008-08-08 Steven Lambright Made the unit test work with a Sensor + * change. Also, now using the new LoadCache(...) method instead of + * CreateCache(...). Increased the delta line/samp tolerance in the + * unit test. + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class HrscCamera : public Isis::LineScanCamera { + public: + // Constructs a HiriseCamera object + HrscCamera (Isis::Pvl &lab); + + // Destroys the HiriseCamera object + ~HrscCamera (); + + private: + void ReadLineRates(iString filename); + + std::vector p_lineRates; + }; + }; +}; + +#endif diff --git a/isis/src/mex/objs/HrscCamera/HrscCamera.truth b/isis/src/mex/objs/HrscCamera/HrscCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..ab345925aa87b9ee04b743547cdc662add4df48d --- /dev/null +++ b/isis/src/mex/objs/HrscCamera/HrscCamera.truth @@ -0,0 +1,20 @@ +Unit Test for HrscCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/mex/objs/HrscCamera/Makefile b/isis/src/mex/objs/HrscCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..493b2cbeab1fc45ce33bf32a0d867c2cca6c9031 --- /dev/null +++ b/isis/src/mex/objs/HrscCamera/Makefile @@ -0,0 +1,5 @@ +INCS = HrscCamera.h +SRCS = HrscCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/mex/objs/HrscCamera/unitTest.cpp b/isis/src/mex/objs/HrscCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1176dd5e361f994548ec7a2171786f8a09d19e1a --- /dev/null +++ b/isis/src/mex/objs/HrscCamera/unitTest.cpp @@ -0,0 +1,117 @@ +using namespace std; + +#include +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); +/** + * @internal + * @history 2009-08-03 Jeannie Walldren - Changed known lat + * and lon. + * @history 2009-08-06 Jeannie Walldren - Added cmath include + * and changed calls to abs() to fabs() since the + * abs() function takes integer values while the + * fabs() takes floats. Changed Center Lat tolerance + * from 4E-10 to 4.1E-10 since the difference on + * Darwin powerpc was 4.07E-10. + */ +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for HrscCamera..." << endl; + /** HRSC: Corner tests offset a little, longitude tolerance increased. + * DeltaSamp/Line tolerances also increased. + */ + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + // double knownLat = -64.50313745696818; + // double knownLon = 43.52322196365473; + // double knownLat = -64.50313965814711; + // double knownLon = 43.5232222641892; + // double knownLat = -64.50313975280879; //blackflag + // double knownLon = 43.52322225395123; + // double knownLat = -64.50312208873054; + // double knownLon = 43.52322362019364; + // double knownLat = -64.50312199406929; + // double knownLon = 43.52322363043155; + // double knownLat = -64.50312208873054; + // double knownLon = 43.52322362019364; + double knownLat = -64.50314015330002;//blackflag + double knownLon = 43.52322224602578; + // double knownLat = -64.50312208873054;//hiclops + // double knownLon = 43.52322362019364; + + Isis::Pvl p("$mex/testData/h2254_0000_s12.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 2.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(fabs(cam->UniversalLatitude() - knownLat) < 1.81E-5) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(fabs(cam->UniversalLongitude() - knownLon) < 1.4E-6) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.008) deltaSamp = 0; + if (fabs(deltaLine) < 0.008) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/mex/objs/Makefile b/isis/src/mex/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/mex/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/mgs/Makefile b/isis/src/mgs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/mgs/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/mgs/apps/Makefile b/isis/src/mgs/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/mgs/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/mgs/apps/moc2isis/Makefile b/isis/src/mgs/apps/moc2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mgs/apps/moc2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mgs/apps/moc2isis/moc2isis.cpp b/isis/src/mgs/apps/moc2isis/moc2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..adff8d68e3f5461c28978fb99fb2f2d5cf3922b7 --- /dev/null +++ b/isis/src/mgs/apps/moc2isis/moc2isis.cpp @@ -0,0 +1,333 @@ +#include "Isis.h" + +#include +#include + +#include "ProcessImportPds.h" + +#include "UserInterface.h" +#include "Filename.h" +#include "iException.h" +#include "iException.h" +#include "iTime.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +void IsisMain () +{ + void TranslateMocEdrLabels (Filename &labelFile, Cube *ocube); + + ProcessImportPds p; + Pvl pdsLabel; + UserInterface &ui = Application::GetUserInterface(); + + // Get the input filename and make sure it is a MOC EDR + Filename in = ui.GetFilename("FROM"); + iString id; + bool compressed = false; + bool projected; + try { + Pvl lab(in.Expanded()); + id = (string) lab["DATA_SET_ID"]; + if (lab.FindObject("IMAGE").HasKeyword("ENCODING_TYPE")) compressed = true; + projected = lab.HasObject("IMAGE_MAP_PROJECTION"); + } + catch (iException &e) { + string msg = "Unable to read [DATA_SET_ID] from input file [" + + in.Expanded() + "]"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + //Checks if in file is rdr + if( projected ) { + string msg = "[" + in.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + id.ConvertWhiteSpace(); + id.Compress(); + id.Trim(" "); + if ((id != "MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0") && + (id != "MGS-M-MOC-NA/WA-2-SDP-L0-V1.0")) { + string msg = "Input file [" + in.Expanded() + "] does not appear to be " + + "in MOC EDR format. DATA_SET_ID [" + id + "]"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + + // Get a temporary file for the uncompressed version incase we need it + Filename uncompressed(in.Basename(), "img"); + + // Set up conditional transfer of PDS labels to output cube + Filename &translbl(in); + + // If the input file is compressed, use "mocuncompress" to uncompress it + if (compressed) { + iString command = "mocuncompress " + in.Expanded() + " " + + uncompressed.Expanded(); + if (system (command.c_str()) == 1) { + string msg = "Unable to execute [mocuncompress]"; + throw iException::Message(iException::Programmer,msg, _FILEINFO_); + } + p.SetPdsFile (uncompressed.Expanded(), "", pdsLabel); + translbl = uncompressed; + + } + else { + p.SetPdsFile (in.Expanded(), "", pdsLabel); + } + + Cube *ocube = p.SetOutputCube("TO"); + p.StartProcess (); + TranslateMocEdrLabels(translbl, ocube); + p.EndProcess (); + + if (compressed) { + string uncompressedName(uncompressed.Expanded()); + remove (uncompressedName.c_str()); + } + + return; +} + +void TranslateMocEdrLabels (Filename &labelFile, Cube *ocube) { + + string startTime, productId, clockCount; + + // Get the directory where the MOC translation tables are. + PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory"); + + // Transfer the instrument group to the output cube + iString transDir = (string) dataDir["Mgs"]; + Filename transFile (transDir + "/" + "translations/mocInstrument.trn"); + + // Get the translation manager ready + Pvl labelPvl (labelFile.Expanded()); + PvlTranslationManager instrumentXlater (labelPvl, transFile.Expanded()); + + PvlGroup inst("Instrument"); + + if (instrumentXlater.InputHasKeyword("SpacecraftName")) { + string str = instrumentXlater.Translate ("SpacecraftName"); + inst += PvlKeyword ("SpacecraftName", str); + } + + if (instrumentXlater.InputHasKeyword("InstrumentId")) { + string str = instrumentXlater.Translate ("InstrumentId"); + inst += PvlKeyword ("InstrumentId", str); + } + + if (instrumentXlater.InputHasKeyword("TargetName")) { + string str = instrumentXlater.Translate ("TargetName"); + inst += PvlKeyword ("TargetName", str); + } + + if (instrumentXlater.InputHasKeyword("StartTime")) { + string str = instrumentXlater.Translate ("StartTime"); + inst += PvlKeyword ("StartTime", str); + // isisLab.AddKeyword ("StartTime", str+"Z"); + startTime = str; + } + + if (instrumentXlater.InputHasKeyword("StopTime")) { + string str = instrumentXlater.Translate ("StopTime"); + inst += PvlKeyword ("StopTime", str); + // isisLab.AddKeyword ("StopTime", str+"Z"); + } + + if (instrumentXlater.InputHasKeyword("CrosstrackSumming")) { + string str = instrumentXlater.Translate ("CrosstrackSumming"); + inst += PvlKeyword ("CrosstrackSumming", str); + } + + if (instrumentXlater.InputHasKeyword("DowntrackSumming")) { + string str = instrumentXlater.Translate ("DowntrackSumming"); + inst += PvlKeyword ("DowntrackSumming", str); + } + + if (instrumentXlater.InputHasKeyword("FocalPlaneTemperature")) { + string str = instrumentXlater.Translate ("FocalPlaneTemperature"); + inst += PvlKeyword ("FocalPlaneTemperature", str); + } + + if (instrumentXlater.InputHasKeyword("GainModeId")) { + string str = instrumentXlater.Translate ("GainModeId"); + inst += PvlKeyword ("GainModeId", str); + } + + if (instrumentXlater.InputHasKeyword("LineExposureDuration")) { + string str = instrumentXlater.Translate ("LineExposureDuration"); + inst += PvlKeyword ("LineExposureDuration", str, "milliseconds"); + } + + if (instrumentXlater.InputHasKeyword("MissionPhaseName")) { + string str = instrumentXlater.Translate ("MissionPhaseName"); + inst += PvlKeyword ("MissionPhaseName", str); + } + + if (instrumentXlater.InputHasKeyword("OffsetModeId")) { + string str = instrumentXlater.Translate ("OffsetModeId"); + inst += PvlKeyword ("OffsetModeId", str); + } + + if (instrumentXlater.InputHasKeyword("SpacecraftClockCount")) { + string str = instrumentXlater.Translate ("SpacecraftClockCount"); + inst += PvlKeyword ("SpacecraftClockCount", str); + clockCount = str; + } + + if (instrumentXlater.InputHasKeyword("RationaleDesc")) { + string str = instrumentXlater.Translate ("RationaleDesc"); + inst += PvlKeyword ("RationaleDesc", str); + } + + if (instrumentXlater.InputHasKeyword("OrbitNumber")) { + string str = instrumentXlater.Translate ("OrbitNumber"); + inst += PvlKeyword ("OrbitNumber", str); + } + + if (instrumentXlater.InputHasKeyword("FirstLineSample")) { + iString str = instrumentXlater.Translate ("FirstLineSample"); + int num = str.ToInteger(); + num++; + inst += PvlKeyword ("FirstLineSample", num); + } + + // Add the instrument specific info to the output file + ocube->PutGroup(inst); + + + // Transfer the archive group to the output cube + transDir = (string) dataDir["Mgs"]; + Filename transFileArchive (transDir + "/" + "translations/mocArchive.trn"); + + // Get the translation manager ready for the archive group + PvlTranslationManager archiveXlater (labelPvl, transFileArchive.Expanded()); + + PvlGroup arch("Archive"); + + if (archiveXlater.InputHasKeyword("DataSetId")) { + string str = archiveXlater.Translate ("DataSetId"); + arch += PvlKeyword ("DataSetId", str); + } + + if (archiveXlater.InputHasKeyword("ProductId")) { + string str = archiveXlater.Translate ("ProductId"); + arch += PvlKeyword ("ProductId", str); + productId = str; + } + + if (archiveXlater.InputHasKeyword("ProducerId")) { + string str = archiveXlater.Translate ("ProducerId"); + arch += PvlKeyword ("ProducerId", str); + } + + if (archiveXlater.InputHasKeyword("ProductCreationTime")) { + string str = archiveXlater.Translate ("ProductCreationTime"); + arch += PvlKeyword ("ProductCreationTime", str); + } + + if (archiveXlater.InputHasKeyword("SoftwareName")) { + string str = archiveXlater.Translate ("SoftwareName"); + arch += PvlKeyword ("SoftwareName", str); + } + + if (archiveXlater.InputHasKeyword("UploadId")) { + string str = archiveXlater.Translate ("UploadId"); + arch += PvlKeyword ("UploadId", str); + } + + if (archiveXlater.InputHasKeyword("DataQualityDesc")) { + string str = archiveXlater.Translate ("DataQualityDesc"); + arch += PvlKeyword ("DataQualityDesc", str); + } + + + // New labels (not in the PDS file) + + // The ImageNumber is made up of pieces of the StartTime + // The first piece is the + // Last digit of the year (eg, 1997 => 7), followed by the + // Day of the year (Julian day) followed by the + // Last five digits of the ProductId + if (startTime.length() > 0 && productId.length() > 0) { + iTime tim(startTime); + string imageNumber = tim.YearString(); + imageNumber = imageNumber.substr(3, 1); + imageNumber += tim.DayOfYearString(); + + imageNumber += productId.substr(4); + + arch += PvlKeyword ("ImageNumber", imageNumber); + } + + + // The ImageKeyId is made up of the: + // First five digits of the SpacecraftClockCount followed by the + // Last five dights of the ProductId + if (clockCount.length() > 0 && productId.length() > 0) { + arch += PvlKeyword ("ImageKeyId", clockCount.substr(0,5) + + productId.substr(4)); + } + + // Add the archive info to the output file + ocube->PutGroup(arch); + + + // Create the BandBin Group and populate it + transDir = (string) dataDir["Mgs"]; + Filename transFileBandBin (transDir + "/" + "translations/mocBandBin.trn"); + + // Get the translation manager ready for the BandBin group + PvlTranslationManager bandBinXlater (labelPvl, transFileBandBin.Expanded()); + + + + + + PvlGroup bandBin("BandBin"); + string frameCode; + + if (bandBinXlater.InputHasKeyword("FilterName")) { + iString str = bandBinXlater.Translate ("FilterName"); + str.UpCase(); + + if (str == "BLUE") { + bandBin += PvlKeyword ("FilterName", str); + bandBin += PvlKeyword ("OriginalBand", 1); + bandBin += PvlKeyword ("Center", 0.4346, "micrometers"); + bandBin += PvlKeyword ("Width", 0.050, "micrometers"); + frameCode = "-94033"; + } + else if (str == "RED") { + bandBin += PvlKeyword ("FilterName", str); + bandBin += PvlKeyword ("OriginalBand", 1); + bandBin += PvlKeyword ("Center", 0.6134, "micrometers"); + bandBin += PvlKeyword ("Width", 0.050, "micrometers"); + frameCode = "-94032"; + } + else { + string msg = "Invalid value for filter name [" + str + "]"; + } + } + else { + bandBin += PvlKeyword ("FilterName", "BROAD_BAND"); + bandBin += PvlKeyword ("OriginalBand", 1); + bandBin += PvlKeyword ("Center", 0.700, "micrometers"); + bandBin += PvlKeyword ("Width", 0.400, "micrometers"); + frameCode = "-94031"; + } + + // Add the bandbin info to the output file + ocube->PutGroup(bandBin); + + + // Create the Kernel Group + PvlGroup kerns("Kernels"); + kerns += PvlKeyword("NaifFrameCode", frameCode); + ocube->PutGroup(kerns); +} + diff --git a/isis/src/mgs/apps/moc2isis/moc2isis.xml b/isis/src/mgs/apps/moc2isis/moc2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..4d0bbad8a1500c53b704f11380e9aa270b8e33cd --- /dev/null +++ b/isis/src/mgs/apps/moc2isis/moc2isis.xml @@ -0,0 +1,118 @@ + + + + + + Import PDS formatted MOC image cube into Isis format cube + + + + This program will import a PDS formatted MOC image into an Isis cube. The input file can be + in MOC compressed format (extension = ".imq" normally) or uncompressed (extension = "img"). + The program does not use the extension to determine if the file is compressed or not. It uses + the label keyword "ENCODING_TYPE". + + + + + Original version + + + Wrote for Isis 3. + + + Modified schema location from astrogeology... to isis.astrogeology..." + + + Fixed Makefile + + + Converted to use new IsisImport instead of IsisPdsImport + + + Modified pds2isis to become moc2isis + + + Changed OriginalSpacecraftClockCount to SpacecraftClockCount + Translated MARS_GLOBAL_SURVEYOR to "MARS GLOBAL SURVEYOR" + + + Fixed label band_bin group for the broad band. + + + Modified to have the "kernels" group added to the labels. The + only keyword (for now) is "NaifFrameCode". + + + Updated to use the new IsisImportPds class instead of the + IsisImport class. + + + Added new "Alpha" keywords to the instrument group. + + + Will attempt decompression using the ENCODING_TYPE keyword + instead of the DATA_SET_ID + + + Fixed bug due to PVL refactor + + + Modified to comply with changes to PvlTranslationManager and + PvlTranslationTable + + + Changed the way the temporary filename is created when + the file needs to be uncompressed. It now uses the input + base filename as the root of the file path. + + + Ensure the label of the uncompressed image is used in the + translation of PDS keywords, not the compressed image. + + + Checks if input file is rdr. + + + Removed references to CubeInfo + + + + + Mars Global Surveyor + + + + + + filename + input + + Input PDS formatted MOC EDR image file + + + Use this parameter to select the MOC image filename. The file can be + in either MOC compressed format or uncompressed format. The extension + is not used to determine the compression status. + + + *.imq *.img + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + diff --git a/isis/src/mgs/apps/moc2isis/tsts/Makefile b/isis/src/mgs/apps/moc2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mgs/apps/moc2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mgs/apps/moc2isis/tsts/case01/Makefile b/isis/src/mgs/apps/moc2isis/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..244b41c51cdb9aa724b065cf3d9740d81daf1295 --- /dev/null +++ b/isis/src/mgs/apps/moc2isis/tsts/case01/Makefile @@ -0,0 +1,7 @@ +APPNAME = moc2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.img \ + to=$(OUTPUT)/moc2isisTruth1.cub > /dev/null; diff --git a/isis/src/mgs/apps/moc2isis/tsts/case02/Makefile b/isis/src/mgs/apps/moc2isis/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ee00987fbb11e915ced96c82c209baf300132cb2 --- /dev/null +++ b/isis/src/mgs/apps/moc2isis/tsts/case02/Makefile @@ -0,0 +1,7 @@ +APPNAME = moc2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102402.img \ + to=$(OUTPUT)/moc2isisTruth2.cub > /dev/null; diff --git a/isis/src/mgs/apps/moc2isis/tsts/case03/Makefile b/isis/src/mgs/apps/moc2isis/tsts/case03/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..80f0600f75be8580ccdaaabbae27049230f79515 --- /dev/null +++ b/isis/src/mgs/apps/moc2isis/tsts/case03/Makefile @@ -0,0 +1,7 @@ +APPNAME = moc2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/m0402852.imq \ + to=$(OUTPUT)/moc2isisTruth3.cub >& /dev/null; diff --git a/isis/src/mgs/apps/moccal/Makefile b/isis/src/mgs/apps/moccal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mgs/apps/moccal/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mgs/apps/moccal/moccal.cpp b/isis/src/mgs/apps/moccal/moccal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1c0d3c253145164f5a1d0dead0b9f1ec099def7 --- /dev/null +++ b/isis/src/mgs/apps/moccal/moccal.cpp @@ -0,0 +1,409 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "MocLabels.h" +#include "iTime.h" +#include "iException.h" +#include "TextFile.h" +#include "LineManager.h" + +using namespace std; +using namespace Isis; + +// Working functions and parameters +namespace gbl { + void Calibrate (Buffer &in, Buffer &out); + void LoadCoefficients (const string &file, int ns); + void FixWagoLines (string file); + + double a; // Commanded system gain + double off; // Commanded system offset + double ex; // Exposure duration + double z; // Fixed zero offset + double dc; // dark current term + double g; // gain dependent offset + double w0; // omega naught + double iof; // conversion from counts/ms to IOF + + vector pixelGain; // Pixel dependent gain table + vector pixelOffset; // Pixel dependent offset table + + vector inLineAvg; // Average of each input line + vector outLineAvg; // Average of each output line + + Mgs::MocLabels *moc; + + bool nullWago; +} + +// Main moccal routine +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and make sure it is a moc file + UserInterface &ui = Application::GetUserInterface(); + Cube *icube = p.SetInputCube("FROM",OneBand); + gbl::moc = new Mgs::MocLabels(ui.GetFilename("FROM")); + + // If it is already calibrated then complain + if (icube->HasGroup("Radiometry")) { + string msg = "The MOC image [" + icube->Filename() + "] has already been "; + msg += "radiometrically calibrated"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Get label parameters we will need for calibration equation + gbl::a = gbl::moc->Gain(); + gbl::off = gbl::moc->Offset(); + gbl::ex = gbl::moc->ExposureDuration(); + + // Get the starting, ending, and activation et's. For now, the + // activation et is set to the largest double precision value. If + // The narrow angle B detectors ever get activated then the value + // will need to be changed to the appropriate et + iTime startTime(gbl::moc->StartTime()); + double etStart = startTime.Et(); + double etNABActivation = DBL_MAX; + + // Open the calibration kernel that contains constants for each camera + // and internalize it in a pvl object + string calKernelFile; + if (ui.WasEntered("CALKERNEL")) { + calKernelFile = ui.GetFilename("CALKERNEL"); + } + else { + calKernelFile = p.MissionData("mgs","/calibration/moccal.ker.???",true); + } + Pvl calKernel(calKernelFile); + + // Point to the right group of camera parameters + string camera; + if (gbl::moc->WideAngleRed()) { + camera = "WideAngleRed"; + } + else if (gbl::moc->WideAngleBlue()) { + camera = "WideAngleBlue"; + } + else if (etStart > etNABActivation) { + camera = "NarrowAngleB"; + } + else { + camera = "NarrowAngleA"; + } + PvlGroup &calCamera = calKernel.FindGroup(camera); + + // Get the camera specific calibration parameters from the kernel file + // and load detector coefficients (gain/offsets at each pixel) + gbl::z = calCamera["Z"]; + gbl::dc = calCamera["DC"]; + gbl::g = calCamera["G"]; + gbl::w0 = calCamera["W0"]; + string coefFile = calCamera["CoefFile"]; + gbl::LoadCoefficients(coefFile,icube->Samples()); + +#if 0 + // Override with these with any user selected parameters + if (ui.WasEntered("Z")) gbl::z = ui.GetDouble("Z"); + if (ui.WasEntered("DC")) gbl::dc = ui.GetDouble("DC"); + if (ui.WasEntered("G")) gbl::g = ui.GetDouble("G"); + if (ui.WasEntered("W0")) gbl::w0 = ui.GetDouble("W0"); +#endif + gbl::nullWago = ui.GetBoolean("NULLWAGO"); + + // Get the distance between Mars and the Sun at the given time in + // Astronomical Units (AU) + string bspKernel = p.MissionData("base","/kernels/spk/de???.bsp",true); + furnsh_c(bspKernel.c_str()); + string pckKernel = p.MissionData("base","/kernels/pck/pck?????.tpc",true); + furnsh_c(pckKernel.c_str()); + double sunpos[6],lt; + spkezr_c ("sun",etStart,"iau_mars","LT+S","mars",sunpos,<); + double dist = vnorm_c(sunpos); + double kmPerAU = 1.4959787066E8; + double sunAU = dist / kmPerAU; + unload_c (bspKernel.c_str()); + unload_c (pckKernel.c_str()); + + // See if the user wants counts/ms or i/f but if w0 is 0 then + // we must go to counts/ms + // iof = conversion factor from counts/ms to i/f + bool convertIOF = ui.GetBoolean("IOF") && (gbl::w0 > 0.0); + if (convertIOF) { + gbl::iof = sunAU * sunAU / gbl::w0; + } + else { + gbl::iof = 1.0; + } + + // Setup the output cube + Cube *ocube = p.SetOutputCube ("TO"); + + // Add the radiometry group + PvlGroup calgrp("Radiometry"); + calgrp += PvlKeyword("CalibrationKernel",calKernelFile); + calgrp += PvlKeyword("CoefficientFile",coefFile); + + calgrp += PvlKeyword("a",gbl::a); + calgrp["a"].AddComment("Radiometric equation in moccal"); + calgrp["a"].AddComment("r = (pixel - z + off) / a - g / ex - dc"); + calgrp += PvlKeyword("off",gbl::off); + calgrp += PvlKeyword("ex",gbl::ex); + calgrp += PvlKeyword("z",gbl::z); + calgrp += PvlKeyword("dc",gbl::dc); + calgrp += PvlKeyword("g",gbl::g); + + calgrp += PvlKeyword("w0",gbl::w0); + calgrp["w0"].AddComment("Reflectance = r * iof, where iof = (s * s) / w0"); + calgrp += PvlKeyword("s",sunAU); + calgrp += PvlKeyword("iof",gbl::iof); + + ocube->PutGroup(calgrp); + + // Start the line-by-line calibration sequence + p.StartProcess(gbl::Calibrate); + p.EndProcess(); + + // Now go fix errors around the wago changes + gbl::FixWagoLines(ui.GetFilename("TO")); + + // Cleanup + gbl::pixelGain.clear(); + gbl::pixelOffset.clear(); + gbl::inLineAvg.clear(); + gbl::outLineAvg.clear(); +} + +// Line processing routine +void gbl::Calibrate (Buffer &in, Buffer &out) { + // Initialize counters + double isum = 0.0; + double osum = 0.0; + int count = 0; + + // Get the line/time dependent gain/offset + gbl::a = gbl::moc->Gain((int)in.Line()); + gbl::off = gbl::moc->Offset((int)in.Line()); + + // Loop and apply calibration + for (int i=0; i 0) { + inAverage = isum / (double) count; + outAverage = osum / (double) count; + } + + // Need to keep track of the averages for each line so push them onto + // a stack + gbl::inLineAvg.push_back(inAverage); + gbl::outLineAvg.push_back(outAverage); +} + + +void gbl::LoadCoefficients(const string &file, int ns) { + // First create space for our coefficients + gbl::pixelGain.resize(ns); + gbl::pixelOffset.resize(ns); + + // Now initialize them to unity + for (int i=0; i gainCoef; + vector offsetCoef; + TextFile coef(file); + iString record, tok; + coef.GetLine(record,true); + int numCoefs = record.ToInteger(); + for (int i=0; iDetectors()) { + string msg = "Coefficient file [" + file + "] size is wrong ... should have ["; + msg += iString(gbl::moc->Detectors()) + "] gain/offset entries"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + + // The gain and offset will need to be based on the compression from + // detectors to sample (crosstrack summing mode) + for (int samp=1; samp<=ns; samp++) { + int ss = gbl::moc->StartDetector(samp); + int es = gbl::moc->EndDetector(samp); + int n; + double gsum = 0.0; + double osum = 0.0; + for (n = 0; ss <= es; ss++, n++) { + if (ss >= (int)gainCoef.size()) { + string msg = "Array bounds exceeded for gainCoef/offsetCoef"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + gsum += gainCoef[ss]; + osum += offsetCoef[ss]; + } + gbl::pixelGain[samp-1] = gsum / (double) n; + gbl::pixelOffset[samp-1] = osum / (double) n; + } +} + +void gbl::FixWagoLines(string file) { + // Nothing to do for narrow angle + if (gbl::moc->NarrowAngle()) return; + + // Open the cube to repair + Cube fix; + fix.Open(file,"rw"); + const int nl = fix.Lines(); + + // Create a line manager on the cube for I/O + LineManager lbuf(fix); + + // Determine which lines need to be examined + double lastGain = moc->Gain(); + double lastOffset = moc->Offset(); + vector fixList; + for (int line=2; line<=nl; line++) { + double gain = moc->Gain(line); + double offset = moc->Offset(line); + if ((lastGain != gain) || (lastOffset != offset)) fixList.push_back(line); + lastGain = gain; + lastOffset = offset; + } + + const int nlBefore = 2; + const int nlAfter = 2; + const int nlavg = 4; + const double fixFactor = 1.5; + + // Loop for each line to fix + for (unsigned int i=0; i nl) continue; + if (el > nl) continue; + + // Find the closest non-zero output line average before the wago line + int slBefore = sl; + int elBefore = sl+nlavg; + int indexBefore = -1; + for (int line = elBefore; line >= slBefore; line--) { + if (gbl::outLineAvg[line-1] != 0.0) { + indexBefore = line - 1; + break; + } + } + if (indexBefore < 0) continue; + double oavgBefore = gbl::outLineAvg[indexBefore]; + + // Find the closest non-zero output line average before the wago line + int slAfter = el-nlavg; + int elAfter = el; + int indexAfter = -1; + for (int line = slAfter; line <= elAfter; line++) { + if (gbl::outLineAvg[line-1] != 0.0) { + indexAfter = line - 1; + break; + } + } + if (indexAfter < 0) continue; + double oavgAfter = gbl::outLineAvg[indexAfter]; + + // Get the corresponding input averages and compute net WAGO change + // Don't do anything if the net change is invalid + double iavgBefore = gbl::inLineAvg[indexBefore]; + double iavgAfter = gbl::inLineAvg[indexAfter]; + + double sum = (iavgBefore / iavgAfter) / (oavgBefore / oavgAfter); + if (abs(1.0 - sum) < 0.05) continue; + + // Prep to fix the lines + sl = centerLine - nlBefore; + el = centerLine + nlAfter; + int nlFix = el - sl + 1; + double fixinc = (oavgAfter - oavgBefore) / (nlFix + 1); + double base = oavgBefore; + double avgTol = abs(fixinc * fixFactor); + + // Loop and fix each one + for (int line=sl; line <= el; line++) { + base += fixinc; + double avg = base - gbl::outLineAvg[line-1]; + + // Do we need to fix this line? + if (abs(avg) <= avgTol) continue; + + // Read the line + lbuf.SetLine(line); + fix.Read(lbuf); + + // Null it + if (gbl::nullWago) { + for (int samp = 0 ; samp < lbuf.size(); samp++) { + lbuf[samp] = Null; + } + outLineAvg[line-1] = 0.0; + } + + // or repair it + else { + avg = outLineAvg[line-1]; + outLineAvg[line-1] = base; + + for (int samp = 0; samp < lbuf.size(); samp++) { + if (IsValidPixel(lbuf[samp])) { + lbuf[samp] = lbuf[samp] / avg * base; + } + } + } + + // Write the line + fix.Write(lbuf); + } + } + + // Cleanup + fix.Close(); +} diff --git a/isis/src/mgs/apps/moccal/moccal.xml b/isis/src/mgs/apps/moccal/moccal.xml new file mode 100644 index 0000000000000000000000000000000000000000..48a03e79db2b05993058c5da3cbdc7be2fbfd00c --- /dev/null +++ b/isis/src/mgs/apps/moccal/moccal.xml @@ -0,0 +1,310 @@ + + + + + + Radiometrically calibrates a MOC image + + + +

    + moccal performs radiometric corrections to images acquired by the Mars + Global Surveyor (MGS) MOC camera. MOC has one Narrow Angle (NA) + detector and 2 Wide Angle (WA) detectors. It also has two camera + systems, A and B. The B camera system is a backup and currently has + very little or no radiometric calibration information. It is supported + to a very limited extent but is not in use at this time. +

    + +

    + The MGS MOC NA detector has a total of 2048 pixels. The WA Red and WA + Blue detectors have a total of 3456 pixels. Images from MOC may or may + not include all pixels in the acquired image. There are special summing + modes that are utilized on-board the spacecraft to average detector + pixels to combine them into a single output pixel value. Both NA and WA + detectors can utilize crosstrack (sample) and downtrack (line) summing + modes. The value of these modes indicate the number of samples and + lines, respectively, that were summed and averaged to result in the + pixel values stored in the input file to moccal specified in the FROM + parameter. These values are stored in the ISIS labels as + CROSSTRACK_SUMMING and DOWNTRACK_SUMMING, respectively. Note that this + will reduce the number of samples in the output image by a factor of at + most the crosstrack summing mode value. The NA is restricted to modes + of 1 through 8 for both crosstrack and downtrack summing. Furthermore, + the crosstrack and downtrack modes must be the same. For both WA + detectors, crosstrack and downtrack modes range from 1 to 127. Unlike + NA, WA crosstrack and downtrack summing modes can differ. There are two + additional special WA crosstrack summing modes. These modes are + indicated by crosstrack summing mode values of 13 and 27. Both of these + modes use specially configured tables to indicate the relative detector + hardware pixels involved in computing the output pixel value. These + modes are intended to maintain approximately equal spatial resolution + from nadir to limb. Crosstrack summing mode 13 has a resolution of + 7.5 km/pixel and maximum number of output pixels of 768; mode 27 has + a resolution of 3.75 km/pixel with the maximum number of output pixels + of 384. moccal recognizes both these modes and applies appropriate + measures to radiometrically correct them. +

    +

    + The MOC camera has the ability to acquire images of differing sizes in + both line and sample. The starting hardware detector pixel for the + acquired image is specified by the ISIS label keyword, + FIRST_LINE_SAMPLE. The first pixel in the detector is indicated by a + value of 1. (Note that in the original PDS image products this is the + EDIT_MODE_ID keyword and is 0-based. In ISIS, FIRST_LINE_SAMPLE is a + PDS standard and is 1 plus this value, a 1-based numbering scheme.) + Note that all corrections are applied relative to the actual hardware + pixel. +

    + + moccal has a number of parameters required to process MGS MOC image + data. Most of these parameters are read from an ISIS parameter defaults + file located in the the mgs directory specified in the IsisPreference file. + This file has the form: +
        
    +      $mgs/calibration/moccal.kernel.xxx
    +    
    +      where "xxx" is a positive number.
    +     
    + moccal will search for the parameter file with the highest number and + load all its defaults needed to process MOC images. Note that the + caller may explicity provide an alternative ISIS parameter defaults + file name in the "CALKERNEL" input parameter if they have their own + set of defaults that applies to MOC data. See an existing calibration + file for details on how to configure this file. + +

    + The MOC response equation (without pixel-to-pixel variation terms) is as + follows: +

    + +
    +           dn = a * (r * ex + dc * ex + g) + (z - off)
    +    
    +      where r is the average signal being generated at the focal
    +      plane (in DN/msec at minimum gain), z is the fixed zero
    +      offset, off is the commanded variable offset, dc is the dark
    +      current term (in DN/msec at minimum gain), g is the gain-
    +      dependent offset (in DN at minimum gain), a is the commanded
    +      system gain (where minimum gain is 1 and all other gains
    +      are >1) and ex is the exposure time in milliseconds.
    +    
    + + moccal computes "r" from "dn" at every pixel in the input MOC image. + Hence, the actual equation moccal implements is as follows: + +
    +           r = ((dn - z + off) / a - g) / ex - dc
    +    
    + +

    + Additional pixel-to-pixel variations are corrected by a detector + coefficient file also specified in the parameter defaults file. This + file has been provided after analysis of the calibration data taken + prior to and after the launch of MGS. Certain detectors may not have + these coefficients derived and thus will not have this correction + applied. If these files do exist, they are typically taken from the + mgs directory specified in the IsisPreference file. The coefficent file is expected to contain any number of + comments indicated by a '#' as the first character in a line. The + first non-blank or uncommented line must contain the number of values + (i.e., one per line) of pixel coefficients for this detector. This + must be the exact number of pixels in the given detector, 2048 for the + MOC NA detector and 3456 for the MOC WA Red and Blue detectors. All + non-blank, uncommented lines after the detector count expects two values + per line. The first is a multiplicative value followed by an additive + value. These values are applied to the value "r" computed in the above + equation to correct for individual pixel variation. Note that some + detectors, namely WA Blue, may not have a pixel variation correction + derived. For these cases, moccal will apply the + calibration equation without pixel-to-pixel variation applied. +

    + +

    + Prior to MGS MOC mapping phases, MOC NA downtrack summing modes + greater than 1 was implemented differently in onboard camera software. + A software patch was made at some point prior to normal mission + mapping phase that would be used throughout the mapping and extended + phases for the rest of the mission. moccal applies the following + algorithm for all MOC NA images: *ALL* NA images have the exposure + times multiplied by the downtrack summing mode. All NA images prior + to mapping phases has the recoreded GAIN mode value divided by the + downtrack summing mode and a new GAIN value is looked up in the table + that is closest to this value. It is substituted in the calibration + equation for the commanded gain value (a). The critical piece of + information needed for this algorithm is the time (spacecraft clock + count or SCLK) when this patch was uploaded to the spacecraft. This + time has been determined to be just prior to the first image acquired + in the normal mapping phase. This is image m0000001.imq and its SCLK + is 607568463:128 which corresponds to April 3, 1999, 01:00:40.4405 UTC. + None of the MOC WA images are affected by this algorithm. +

    + +
    +    References:
    +    
    +    "MOC2 Calibration Report, October 1997 [SCCS 10/17/97 version 1.3]"
    +    
    +    "Software Interface Specification, Narrow Angle and Wide Angle
    +       Standard Data Products (September 1999 (revised for MGS)
    +       (formatted April 7, 2000))"
    +    
    +
    + + + + Original version + + + Converted to Isis 3.0 + + + Fixed buffer overflow + + + Removed references to CubeInfo + + + Changed MocLabels references from IsNarrowAngle(), IsWideAngleBlue(), + IsWideAngleRed() to NarrowAngle(), WideAngleBlue(), WideAngleRed(), + respectively. + + + Fixed calls to AddComment. Removed "/*" that should not have been there. + + + + + + Mars Global Surveyor + + + + + mocevenodd + mocnoise50 + + + + + + + cube + input + + Level 0 MOC image + + + A uncalibrated MOC image. If the image is from the narrow angle camera, it should be run through mocevenodd + and mocnoise50 prior to moccal. + + + *.cub + + + + + cube + output + real + + Level 1 MOC image + + + The resultant radiometrically calibrated cube + + + + + filename + input + + PVL kernel containing calibration parameters + + Internal Default + + If you do not enter a file, mocal will search for a file with the form: +
        
    +          $mgs/calibration/moccal.kernel.xxx
    +        
    +          where "xxx" is a positive number.
    +         
    + The kernel with the highest version (xxx) will be used. + See an existing calibration + file for details on how to configure this file. +
    +
    +
    + + + + boolean + True + + Convert to I/F + + + The user has the option to request the output of moccal to be in + either units of percent reflectance (IOF="YES") or in average signal + level at the focal plane (IOF="NO") in DN/msec. moccal has a set of + default I/F (percent reflectance) factors for each detector, NA and both + WA. Should they not have this value, a W0 of 0.0 will be detected and + I/F cannot be generated. moccal will detect occurances of W0=0.0 and + report this to the user whilst functioning as if IOF="NO" irregardless + of what may have been provided by the user for IOF. Conversion to I/F + takes place after calibration and pixel-to-pixel variation correction. + + + + + boolean + False + + Null lines near WA gain/offset changes + + +

    + The MOC WA camera has an additional capability to change the commanded + gain state (a) and offset (off) at any time during image acquistion. + The approximate time these changes are made is provided in a file called + "wago.tab". This file can be found on all MOC CDROM products under the + "index" directory. This table, called a "WAGO" (Wide Angle Gain Offset) + table, contains one entry per line of four fields. All fields are + double quoted. The first field is the WA detector for which the gain + and offset change occurs, the second is the SCLK time of the change, the + third is the hexidecimal code of the new gain mode identifier and the + fourth is the offset mode identifier. The WA detector will be either + "RED" or "BLUE". The SCLK is the spacecraft clock count of the time at + which the command to change gain and offset was initiated. The gain + mode identifier indicates a gain value that is stored in a table of + gain values. The offset mode identifier is actually specified in + factors of 5 DN. Hence, if the commanded offset mode is "5", then "off" + in the above calibration equation is set to 25 (5 * 5 = 25). Any number + of these WAGO changes can occur during WA image acquisition. WAGO + changes are apparent as an abrupt change in brightness at a particular + line. Beware, not all changes are WAGOs as this is also a + characteristic of dropped data. +

    + +

    + As the timing knowledge of the gain-offset changes is only accurate to + 1/8 of a second, and the WA line rate is somewhat faster than this and + not an even multiple of 1/8 second, the line on which the brightness + discontinuity occurs may not match precisely the line computed from the + image start time, line rate, and known time of state change. In + addition, changes in highly-summed images (such as global map swaths) + may result in summed output lines having been created in the instrument + from unsummed input lines taken in different states. moccal attempts to + detect lines that exhibit this signature and corrects them using a + brightness matching algorithm. With the WA line rate at 75ms, for a + downtrack summing mode of 1, the change should occur no more than two + lines before or after the computed line of the change. moccal looks in + this window of transition lines and applies an averaging techinque to + correct them if NULLWAGO="NO". If NULLWAGO="YES", then these lines are + assigned the ISIS NULL value and can be handled later using alternative + processing techniques. +

    +
    +
    +
    +
    +
    diff --git a/isis/src/mgs/apps/moccal/tsts/Makefile b/isis/src/mgs/apps/moccal/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mgs/apps/moccal/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mgs/apps/moccal/tsts/default/Makefile b/isis/src/mgs/apps/moccal/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..82678edd0a2d64e690fc23921a244eaa3794c043 --- /dev/null +++ b/isis/src/mgs/apps/moccal/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = moccal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.cub \ + to=$(OUTPUT)/moccalTruth1.cub > /dev/null; diff --git a/isis/src/mgs/apps/moccal/tsts/iof/Makefile b/isis/src/mgs/apps/moccal/tsts/iof/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1747096b3877f82d052127b29f4fe7c8034d791b --- /dev/null +++ b/isis/src/mgs/apps/moccal/tsts/iof/Makefile @@ -0,0 +1,8 @@ +APPNAME = moccal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102402.cub \ + to=$(OUTPUT)/moccalTruth2.cub \ + iof=false > /dev/null; diff --git a/isis/src/mgs/apps/moccal/tsts/nullwago/Makefile b/isis/src/mgs/apps/moccal/tsts/nullwago/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a3e14a2f53c73aa962efe3add469bc9e9637198b --- /dev/null +++ b/isis/src/mgs/apps/moccal/tsts/nullwago/Makefile @@ -0,0 +1,8 @@ +APPNAME = moccal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/m0402852.cub \ + to=$(OUTPUT)/moccalTruth3.cub \ + nullwago=true >& /dev/null; diff --git a/isis/src/mgs/apps/mocevenodd/Makefile b/isis/src/mgs/apps/mocevenodd/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mgs/apps/mocevenodd/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mgs/apps/mocevenodd/mocevenodd.cpp b/isis/src/mgs/apps/mocevenodd/mocevenodd.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e45a505f873f606881f8ecc1194ef1490fc2e321 --- /dev/null +++ b/isis/src/mgs/apps/mocevenodd/mocevenodd.cpp @@ -0,0 +1,124 @@ +// +// mocevenodd.cpp +// +// Remove even/odd striping from a MOC cube +// +// outputCube = inputCube + {a correction offset to valid pixels} +// +// calc average dn of all valid pixels located in either even or odd columns. +// correction offset is 1/2 the difference between the even and odd average. +// subtract the offset from pixels in even columns +// add the offset to pixels in odd columns +// + +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "MocLabels.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void getStats (Buffer &in); +int evenCount, oddCount; +double evenSum, oddSum; + +void applyCorrectionOffset (Buffer &in,Buffer &out); +double correctionOffset; + + +void IsisMain() { + // Make sure we have a moc cube + ProcessByLine p; + p.SetInputCube("FROM"); + Mgs::MocLabels moc(Application::GetUserInterface().GetFilename("FROM")); + + // It must have crosstrack summing of 1 + if (moc.CrosstrackSumming() != 1) { + string msg = "MOC images do not have even/odd noise problems"; + msg += " if the crosstrack summing mode greater than one"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Get even and odd column statistics + evenCount = 0; + evenSum = 0.0; + oddCount = 0; + oddSum = 0.0; + Progress *progress = p.Progress(); + progress->SetText("Retrieving MOC Image Stats"); + p.StartProcess(getStats); + p.EndProcess(); + + // compute the correction offset + // + // 1/2 the difference between the even column average + // and the odd column average of valid pixel dn values. + // + // throw err if, pixel counts could result in division by zero + if ((oddCount == 0) || (evenCount == 0)) { + string msg = "Couldn't compute column averages"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + correctionOffset = ((evenSum / evenCount) - (oddSum / oddCount)) / 2.0; + + // output cube - apply offset + progress->SetText("Writing De-striped MOC Image"); + p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + p.StartProcess(applyCorrectionOffset); + p.EndProcess(); +} + + +void getStats (Buffer &in) { + + // ProcessByLine + // + // Count and sum all valid pixel values + // in even and odd image columns. + + bool odd = true; + + for (int i=0; i + + + + Remove even/odd detector striping + + + + This program will remove even/odd detector striping from a MOC narrow + angle image. It will check to ensure the crosstrack summing mode for + the image is 1, otherwise the destriping is unnecessary. The algorithm + gather the average of the even columns as well as the odd columns. The + difference between the averages is split (divided by two) to create + offsets for both columns which are then applied. + + + + + mocnoise50 + moccal + + + + + Mars Global Surveyor + + + + + Original version + + + Converted to Isis 3.0 + + + + + + + cube + input + + Input MOC narrow angle image + + + The input image must be a MOC narrow angle cube with + crosstrack summing of 1. + + + *.cub + + + + + cube + output + + Destriped MOC cube + + + The resultant destriped moc image. + + + *.cub + + + + + diff --git a/isis/src/mgs/apps/mocevenodd/tsts/Makefile b/isis/src/mgs/apps/mocevenodd/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mgs/apps/mocevenodd/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mgs/apps/mocevenodd/tsts/default/Makefile b/isis/src/mgs/apps/mocevenodd/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3197fdfa059d2a9b57af01ffeb49453275df729e --- /dev/null +++ b/isis/src/mgs/apps/mocevenodd/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME = mocevenodd + +include $(ISISROOT)/make/isismake.tsts + +commands: + moc2isis \ + from=$(INPUT)/fha00491.imq \ + to=$(OUTPUT)/mgsTemp.cub >& /dev/null; + spiceinit from=$(OUTPUT)/mgsTemp.cub >& /dev/null; + $(APPNAME) from=$(OUTPUT)/mgsTemp.cub \ + to=$(OUTPUT)/mocevenoddTruth.cub >& /dev/null; diff --git a/isis/src/mgs/apps/mocgap/Makefile b/isis/src/mgs/apps/mocgap/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mgs/apps/mocgap/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mgs/apps/mocgap/mocgap.cpp b/isis/src/mgs/apps/mocgap/mocgap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..efae548ae71650ac0c88b853831bc89eb936cea0 --- /dev/null +++ b/isis/src/mgs/apps/mocgap/mocgap.cpp @@ -0,0 +1,78 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "Statistics.h" +#include "SpecialPixel.h" +#include + +using namespace std; +using namespace Isis; + +double maxsd; + +void fixgap(Buffer &in, Buffer &out); + +void IsisMain() { + //We will be processing by line + ProcessByLine p; + + //Set up the input and output cubes, and set maximum standard deviation + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + UserInterface &ui = Application::GetUserInterface(); + maxsd = ui.GetDouble("MAXSD"); + + //Begin processing + p.StartProcess(fixgap); + p.EndProcess(); + +} + +void fixgap (Buffer &in, Buffer &out) { + //First, copy the entire line over + for (int i=0; i tempData; + for (int j=365; j<=369; ++j) { + if (!IsSpecial(in[j])) { + tempData.push_back(in[j]); + } + } + + //Move the values from the vector into an array of doubles. + //This step and the previous one are included because with the vector, we + //can acount for special pixels, otherwise we might end up with trailing zeros + //in the array, skewing the data. Also, Statistics requires a double array. + double data[tempData.size()]; + for (int i=0; i<(int)tempData.size(); ++i) { + data[i]=tempData[i]; + } + Statistics stats; + stats.AddData(data,tempData.size()); + //calulate average and standard deviation + double avg = stats.Average(); + double sd = stats.StandardDeviation(); + + //Determine the boundaries of the valid pixel value range + double upperbound = avg + sd / maxsd; + double lowerbound = avg - sd / maxsd; + //If the pixel at 371 is valid, there's no need to replace it + if ( in[370] <= upperbound && in[370] >= lowerbound ) { + return; + } + //Otherwise, we need to see if samples 372 and 370 are valid, and we'll + //replace 371 with the average of these two. + else if (in[369] >= lowerbound && in[369] <= upperbound) { + if (in[371] <= upperbound && in[371] >= lowerbound) { + out[370] = (in[369] + in[371])/2.0; + } + //If 372 isn't valid, we look out one farther and replace 371 and 372, + //using the average of 370 and 373, weighting the adjacent pixel higher + else if (in[372] <= upperbound && in[372] >= lowerbound) { + out[370] = (2.0 * in[369])/3.0 + in[372]/3.0; + out[371] = in[369]/3.0 + (2.0 * in[372])/3.0; + } + } +} diff --git a/isis/src/mgs/apps/mocgap/mocgap.xml b/isis/src/mgs/apps/mocgap/mocgap.xml new file mode 100644 index 0000000000000000000000000000000000000000..235af2ee26ae04d5f67908a8eee597ee2b921618 --- /dev/null +++ b/isis/src/mgs/apps/mocgap/mocgap.xml @@ -0,0 +1,75 @@ + + + + + Fix data gap in MOC images + + + + Fixes data gaps in MOC images that occur around detector 371. The program + calculates the average and standard deviation of the 5 pixels on a line + centered at detector 371 and + + + + Mars Global Surveyor + + + + + Original version + + + Converted to Isis3 + + + + + + + cube + input + + Input cube + + + This is the input cube to be procesed and fixed around detector 371. + must be an Isis cube from the Mars Global Surveyor Orbital Camera, + and it needs to have already been processed to a level 1 cube. + + + *.cub + + + + + cube + output + + Output cube + + + This is the cube to which we will output our data + + + *.cub + + + + + + double + + Maximum allowable deviance + + + This parameter describes how many standard deviations from the local + average are considered valid for the purpose of filling in the gap. + + + 1.0 + + + + + diff --git a/isis/src/mgs/apps/mocgap/tsts/Makefile b/isis/src/mgs/apps/mocgap/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mgs/apps/mocgap/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mgs/apps/mocgap/tsts/default/Makefile b/isis/src/mgs/apps/mocgap/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d48bdfcb9c94979ca4c257f3971b935655ba4db1 --- /dev/null +++ b/isis/src/mgs/apps/mocgap/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = mocgap + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/m0103126_premocgap.cub \ + to=$(OUTPUT)/mocgapTruth.cub \ + maxsd=1.0 > /dev/null; diff --git a/isis/src/mgs/apps/mocnoise50/Makefile b/isis/src/mgs/apps/mocnoise50/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mgs/apps/mocnoise50/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mgs/apps/mocnoise50/mocnoise50.cpp b/isis/src/mgs/apps/mocnoise50/mocnoise50.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd27098cd719fb0e13996c56cfbccd336267a742 --- /dev/null +++ b/isis/src/mgs/apps/mocnoise50/mocnoise50.cpp @@ -0,0 +1,322 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" +#include "iException.h" +#include "Pvl.h" +#include "MocLabels.h" + +using namespace std; +using namespace Isis; + +namespace gbl { + const int spikeInterval(50); + int averageWidth; + vector maxNoiseColumn; + vector column1Norm; + vector column2Norm; + vector column3Norm; + int delta; + int ssFirst; + double avg1,avg2,avg3; + + extern void CollectColumnStats(Buffer &in); + extern void Copy(Buffer &in, Buffer &out); + extern void RemoveNoise(Buffer &in, Buffer &out); +} + +void IsisMain() { + // Make sure we have a moc cube. If not spit out an appropriate error + // message + ProcessByLine p; + Cube *icube = p.SetInputCube("FROM",OneBand); + Mgs::MocLabels moc(Application::GetUserInterface().GetFilename("FROM")); + int nlines = icube->Lines(); + + // Must be narrow angle + if (moc.WideAngle()) { + string msg = "The 50 sample noise pattern does not occur in "; + msg += "MOC wide angle images"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Must have crosstrack summing of 1 + if (moc.CrosstrackSumming() != 1) { + string msg = "The 50 sample noise pattern does not occur in "; + msg += "MOC narrow angle images with crosstrack summing greater than one"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Initializations + gbl::maxNoiseColumn.clear(); + gbl::column1Norm.clear(); + gbl::column2Norm.clear(); + gbl::column3Norm.clear(); + gbl::averageWidth = Application::GetUserInterface().GetInteger("WIDTH"); + + // Now collect columnar statistical information about the noise + // on a line-by-line basis + p.Progress()->SetText("Collecting statistics"); + p.StartProcess(gbl::CollectColumnStats); + p.EndProcess(); + + // Compute a histogram of the line-by-line difference in max noise column + const int nhist = gbl::spikeInterval*2 + 1; + int noiseHist[nhist]; + + for (int i=0; i abs (gbl::spikeInterval + index)) { + index = gbl::spikeInterval + index; + } + index += gbl::spikeInterval; + + noiseHist[index]++; + } + + // Use the histogram to compute the delta change in noise position + // between lines + int noiseMode = 0; + gbl::delta = 0; + for (int i=0; i noiseMode) { + noiseMode = noiseHist[i]; + gbl::delta = i - gbl::spikeInterval; + } + } + + // Compute a histogram of the max noise column + int ssHist[gbl::spikeInterval]; + for (int i=0; i gbl::spikeInterval) { + imod -= gbl::spikeInterval * (imod/gbl::spikeInterval); + } + + ssHist[imod]++; + } + + // Use the histogram to compute the starting sample for the first line + gbl::ssFirst = ssHist[0]; + int ssMode = 0; + for (int i=0; i ssMode) { + ssMode = ssHist[i]; + gbl::ssFirst = i+1; + } + } + + // Compute the noise correction values + double sum1 = 0.0; + double sum2 = 0.0; + double sum3 = 0.0; + for (int line=0; lineSetText("Copying cube"); + p.StartProcess(gbl::Copy); + results += PvlKeyword("NoiseRemoved","No"); + string reason = "Less than 50% of the lines agreed on a delta sample"; + results += PvlKeyword("Reason",reason); + } + + // If less than 50% of the lines do not agree on a first same then + // we will assume no noise so just make a copy + else if (ssMode <= nlines/2) { + p.Progress()->SetText("Copying cube"); + p.StartProcess(gbl::Copy); + results += PvlKeyword("NoiseRemoved","No"); + string reason = "Less than 50% of the lines agreed on a starting sample"; + results += PvlKeyword("Reason",reason); + } + + // Remove that noise + else { + p.Progress()->SetText("Removing noise"); + p.StartProcess(gbl::RemoveNoise); + results += PvlKeyword("NoiseRemoved","Yes"); + } + + // Log information + Application::Log(results); + p.EndProcess(); +} + + +// Collect statistics about columns within a line +void gbl::CollectColumnStats (Buffer &in) { + // Initialize column arrays. + double columnSum[gbl::spikeInterval]; + double columnAverage[gbl::spikeInterval]; + double columnNorm[gbl::spikeInterval]; + int columnCount[gbl::spikeInterval]; + + for (int i=0; i 0.0)) { + columnSum[i] += in[index]; + columnCount[i]++; + } + } + } + } + + // Compute the average of the columns + for (int i=0; i (gbl::spikeInterval - 1)) col3 = 0; + + // Compute the change around the center column and see if it is a max + double change = (columnNorm[col2] - columnNorm[col1]) + + (columnNorm[col2] - columnNorm[col3]); + if (change > maxNoise) { + maxNoise = change; + column = col2; + } + } + gbl::maxNoiseColumn.push_back(column); + + // Compute average of column normals surrounding this noise spike + sum = 0.0; + for (int i=0; i gbl::spikeInterval-1) col2 = col2 - gbl::spikeInterval; + sum += columnNorm[col2]; + } + avg = sum / (double) (2 * gbl::averageWidth); + + // Calculate difference average surrounding the spike and the three + // columns within the spike. + int col1 = column - 1; + int col2 = column; + int col3 = column + 1; + + if (col1 < 0) col1 = gbl::spikeInterval - 1; + if (col3 > (gbl::spikeInterval-1)) col3 = 0; + + gbl::column1Norm.push_back(columnNorm[col1] - avg); + gbl::column2Norm.push_back(columnNorm[col2] - avg); + gbl::column3Norm.push_back(columnNorm[col3] - avg); +} + +// Remove the noise +void gbl::RemoveNoise(Buffer &in, Buffer &out) { + // First copy the entire line to the output + for (int i=0; i gbl::spikeInterval) { + ss = ss - ((ss/gbl::spikeInterval) * gbl::spikeInterval); + } + if (ss < 0) { + ss = gbl::spikeInterval + ss - + ((ss/gbl::spikeInterval) * gbl::spikeInterval); + } + + // Loop and remove the noise in each column + int ncols = in.size() / gbl::spikeInterval; + for (int i=0; i<=ncols; i++) { + int samp2 = ss + i*gbl::spikeInterval; + int samp1 = samp2 - 1; + int samp3 = samp2 + 1; + + if ((samp1 > 0) && (samp1 < in.size())) { + if ((IsValidPixel(in[samp1])) && (in[samp1] > 0)) { + out[samp1] = in[samp1] - gbl::avg1; + } + } + + if ((samp2 > 0) && (samp2 < in.size())) { + if ((IsValidPixel(in[samp2])) && (in[samp2] > 0)) { + out[samp2] = in[samp2] - gbl::avg2; + } + } + + if ((samp3 > 0) && (samp3 < in.size())) { + if ((IsValidPixel(in[samp3])) && (in[samp3] > 0)) { + out[samp3] = in[samp3] - gbl::avg3; + } + } + } +} + +// Just copy each line +void gbl::Copy(Buffer &in, Buffer &out) { + for (int i=0; i + + + + Removes noise from MOC narrow angle images + + + + MOC narrow angle images with a crosstrack summing mode of 1 exhibit diagnol noise patterns. This + program will statistically determine the pattern and remove it. + + + + Mars Global Surveyor + + + + + mocevenodd + + + + + + Original version + + + Converted to Isis 3.0 + + + Removed references to CubeInfo + + + Replaced reference to MocLabels::IsWideAngle() with MocLabels::WideAngle() + + + + + + + cube + input + + Input MOC cube + + + The MOC narrow angle cube to have the noise removed. It must have a crosstrack summing mode + of 1. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing cleaned-up data. + + + *.cub + + + + + + + integer + 5 + + Width around noise pattern to use when computing noise removal coefficients + + + After the noise pattern is detected, three correction coefficients are computed by examining + the average around the noise. The width defines how many pixels around the noise that will + be used for the average computation. + + 5 + + + + + + diff --git a/isis/src/mgs/apps/mocnoise50/tsts/Makefile b/isis/src/mgs/apps/mocnoise50/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mgs/apps/mocnoise50/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mgs/apps/mocnoise50/tsts/default/Makefile b/isis/src/mgs/apps/mocnoise50/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e15cf1bb8054bcb0d9168259013051dee54464d8 --- /dev/null +++ b/isis/src/mgs/apps/mocnoise50/tsts/default/Makefile @@ -0,0 +1,12 @@ +APPNAME = mocnoise50 + +include $(ISISROOT)/make/isismake.tsts + +commands: + moc2isis \ + from=$(INPUT)/fha00491.imq \ + to=$(OUTPUT)/mgsTemp.cub >& /dev/null; + spiceinit from=$(OUTPUT)/mgsTemp.cub >& /dev/null; + $(APPNAME) from=$(OUTPUT)/mgsTemp.cub \ + to=$(OUTPUT)/mocnoise50Truth.cub \ + width=5 >& /dev/null; diff --git a/isis/src/mgs/apps/mocproc/Makefile b/isis/src/mgs/apps/mocproc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mgs/apps/mocproc/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mgs/apps/mocproc/mocproc.cpp b/isis/src/mgs/apps/mocproc/mocproc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57c60a2fea82d28c6693199776483c1698ccd2c8 --- /dev/null +++ b/isis/src/mgs/apps/mocproc/mocproc.cpp @@ -0,0 +1,104 @@ +#include "Isis.h" + +#include + +#include "ProcessImport.h" + +#include "Filename.h" +#include "iException.h" +#include "iTime.h" +#include "Pipeline.h" + +using namespace std; +using namespace Isis; + +void IsisMain () { + UserInterface &ui = Application::GetUserInterface(); + + if (!ui.GetBoolean("INGESTION") && + !ui.GetBoolean("CALIBRATION") && + !ui.GetBoolean("MAPPING")) { + string m = "Please pick at least one of [INGESTION, CALIBRATION, MAPPING]"; + throw iException::Message(iException::User,m,_FILEINFO_); + } + + Pipeline p("mocproc"); + + p.SetInputFile("FROM", ""); + p.SetOutputFile("TO"); + + p.KeepTemporaryFiles(false); + + if(ui.GetBoolean("Ingestion")) { + p.AddToPipeline("moc2isis"); + p.Application("moc2isis").SetInputParameter("FROM", false); + p.Application("moc2isis").SetOutputParameter("TO", "lev0"); + + p.AddToPipeline("spiceinit"); + p.Application("spiceinit").SetInputParameter("FROM", false); + p.Application("spiceinit").AddParameter("PCK", "PCK"); + p.Application("spiceinit").AddParameter("CK", "CK"); + p.Application("spiceinit").AddParameter("SPK", "SPK"); + p.Application("spiceinit").AddParameter("CKNADIR", "CKNADIR"); + p.Application("spiceinit").AddParameter("SHAPE", "SHAPE"); + p.Application("spiceinit").AddParameter("MODEL", "MODEL"); + } + + if(ui.GetBoolean("Calibration")) { + p.AddToPipeline("moccal"); + p.Application("moccal").SetInputParameter("FROM", true); + p.Application("moccal").SetOutputParameter("TO", "lev1"); + + p.AddToPipeline("mocnoise50"); + p.Application("mocnoise50").SetInputParameter("FROM", true); + p.Application("mocnoise50").SetOutputParameter("TO", "noise"); + + p.AddToPipeline("mocevenodd"); + p.Application("mocevenodd").SetInputParameter("FROM", true); + p.Application("mocevenodd").SetOutputParameter("TO", "evenodd"); + + Pvl inputPvl(Filename(ui.GetFilename("FROM")).Expanded()); + + int summingMode = 0; + bool isNarrowAngle = false; + + if(inputPvl.HasKeyword("CROSSTRACK_SUMMING")) { + summingMode = inputPvl["CROSSTRACK_SUMMING"]; + isNarrowAngle = ((string)inputPvl["INSTRUMENT_ID"] == "MOC-NA"); + } + else { + PvlGroup &inst = inputPvl.FindGroup("Instrument", Pvl::Traverse); + summingMode = inst["CrosstrackSumming"]; + isNarrowAngle = ((string)inst["InstrumentId"] == "MOC-NA"); + } + + if(summingMode != 1) { + p.Application("mocnoise50").Disable(); + p.Application("mocevenodd").Disable(); + } + + if(!isNarrowAngle) { + p.Application("mocnoise50").Disable(); + } + } + + if(ui.GetBoolean("Mapping")) { + p.AddToPipeline("cam2map"); + p.Application("cam2map").SetInputParameter("FROM", true); + p.Application("cam2map").SetOutputParameter("TO", "lev2"); + p.Application("cam2map").AddParameter("MAP", "MAP"); + p.Application("cam2map").AddParameter("PIXRES", "RESOLUTION"); + + if (ui.WasEntered("PIXRES")) { + p.Application("cam2map").AddConstParameter("PIXRES", "MPP"); + } + else if(ui.WasEntered("MAP")) { + Pvl mapPvl(Filename(ui.GetFilename("MAP")).Expanded()); + if (mapPvl.FindGroup("Mapping", Pvl::Traverse).HasKeyword("PixelResolution")) { + p.Application("cam2map").AddConstParameter("PIXRES", "MAP"); + } + } + } + + p.Run(); +} diff --git a/isis/src/mgs/apps/mocproc/mocproc.xml b/isis/src/mgs/apps/mocproc/mocproc.xml new file mode 100644 index 0000000000000000000000000000000000000000..8bcc67374ff867e7354de69513567300c8f4a1fd --- /dev/null +++ b/isis/src/mgs/apps/mocproc/mocproc.xml @@ -0,0 +1,318 @@ + + + + Processes a MOC image through Levels 0, 1, and/or 2 + + + +

    + Runs Mars Global Surveyer, Mars Obital Camera (MGS/MOC) images through the + applications necessary to create a map projected product. There are three + stages of processing, ingestion, calibration, and mapping. Each stage can + be disabled and runs all the programs necessary to complete that stage if + not disabled. +

    +

    + All intermediate files will be generated in the users Isis temporary + directory and deleted after they are no longer needed. In case of a catastrophic + failure the intermediate files should be deleted. +

    +
    + + + + Original version + + + Converted from Perl to C++ for conversion to Isis 3.0 + + + Added extra error messages + + + Made use of the IsisProcessExecutable class + + + Fixed a filename bug that occured with the no mapping option and crosstrackSumming not equal to 1. + + + Fixed UI and parameters to be consistent with changes made to spiceinit + + + Removed the AUTOLON parameter (no longer an option in cam2map) + + + Documentation fixes + + + Fixed PIXRES handling issue caused by changes in cam2map + + + Added CKNADIR functionality + + + Removed references to CubeInfo + + + This program now uses the Pipeline class to accomplish its processing. + The 'Map' parameter now actually accepts projected cubes, as the documentation + specifies. In the past, an error would be thrown if a cube was specified. The 'Map' + parameter is also now set to be an input, as it is not being modified. This program also + ran "cam2map" with "DEFAULTRANGE=CAMERA," but is now using the default (MINIMIZE). + + + + + Mars Global Surveyor + + + + + + filename + input + + Input MOC EDR, Level0, or Level1 image file + + + Input filename. This file can be in one of four stages. A compressed + PDS formatted MOC EDR, an uncompressed PDS formatted MOC EDR, + a Level0 Isis cube with a complete kernels group in its label, or a + Level1 radiometriclly calibrated Isis cube. + + + *.imq *.img + + + + + filename + output + Automatic + + Final output filename. + + + Output filename from the last enabled processing sequence. By + default the filename will be generated from the input filename with + ".lev#" appended to the name, where "#" is the last level of + processing (i.e., INGESTION = "lev0", CALIBRATION = "lev1", + or MAPPING = "lev2"). + + + + + + + boolean + + YES + + + Import and initialize a moc EDR or RDR file. + + + Process the input file through all level0 steps. This includes "moc2isis" and " + spiceinit". + "moc2isis" will uncompress a compressed EDR automatically. + + + PCK + CK + SPK + SHAPE + CKNADIR + + + + + boolean + + YES + + + Process the input file through the calibration phase. + + + Process the input file through level1. This includes moccal, + mocnoise50, and mocevenodd, + + + + + boolean + + YES + + + Process the input file through the map phase. + + + Process the input file through level2. This include cam2map. + + + MAP + PIXRES + + + + + + + filename + none + input + + User defined target attitude and shape kernel file. + + + Naif kernel file to be used for the target attitude and shape. + + + $BASE/kernels/pck/ + + + Ingestion + + + + + filename + none + input + + User defined spacecraft pointing kernel file. + + + Naif kernel file to be used for the spacecraft pointing. + + + $MGS/kernels/ck/ + + + Ingestion + + + + + filename + none + input + + User defined spacecraaft position kernel file. + + + Naif kernel file to be used for the spacecraft position. + + + Ingestion + + + $MGS/kernels/spk/ + + + + + boolean + false + + Compute nadir pointing if no other kernels exist + + + Compute nadir pointing if no other kernels exist + + + + + + string + SYSTEM + + Ingestion + + + Select the definition of the shape model for spiceinit + + + ISIS camera models can use a shape model (a projected ISIS cube that defines the radii for a global or regional area). You can choose + to select a shape model or to use the definition of the ellipsoid found in the planetary constants (PCK) file. + + + + + + + + + + cube + input + + User defined ISIS cube shape model. + + + A map projected ISIS cube which contains the radii of the target. The file can cover more than the input cube + (FROM) but must minimally cover the data in the input cube. + + $base/dems/ + *.cub + + + + + + + filename + Sinusoidal + input + + File containing mapping parameters + + + A file containing the desired output mapping parameters in PVL form. This + file can be a simple hand produced label file. It can also be an existing cube + label which contains a Mapping group. + + *.map + + Mapping + + + + + double + Pixel resolution in meters + Automatic + + Specifies the resolution in meters per pixel. If not + entered the resolution will + be obtained from the MAP file. + If not in the MAP file the resolution will be computed from + the input camera cube. + + 0.0 + + Mapping + + + + +
    diff --git a/isis/src/mgs/apps/mocproc/tsts/Makefile b/isis/src/mgs/apps/mocproc/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mgs/apps/mocproc/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mgs/apps/mocproc/tsts/case01/Makefile b/isis/src/mgs/apps/mocproc/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..975622178f6a463f034b0f387c3a76e033fa7ba0 --- /dev/null +++ b/isis/src/mgs/apps/mocproc/tsts/case01/Makefile @@ -0,0 +1,15 @@ +APPNAME = mocproc + +mocprocTruth3.cub.TOLERANCE = 0.0000026 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102401.img ingestion=true calibration=false mapping=false \ + to=$(OUTPUT)/mocprocTruth1.cub > /dev/null; + + $(APPNAME) from=$(OUTPUT)/mocprocTruth1.cub ingestion=false calibration=true mapping=false \ + to=$(OUTPUT)/mocprocTruth2.cub > /dev/null; + + $(APPNAME) from=$(OUTPUT)/mocprocTruth2.cub ingestion=false calibration=false mapping=true \ + to=$(OUTPUT)/mocprocTruth3.cub > /dev/null; diff --git a/isis/src/mgs/apps/mocproc/tsts/case02/Makefile b/isis/src/mgs/apps/mocproc/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..24e1a43c74f1f1942ff13b8424233d796d3beea4 --- /dev/null +++ b/isis/src/mgs/apps/mocproc/tsts/case02/Makefile @@ -0,0 +1,15 @@ +APPNAME = mocproc + +mocprocTruth3.cub.TOLERANCE = 0.0009 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/ab102402.img ingestion=true calibration=false mapping=false \ + to=$(OUTPUT)/mocprocTruth1.cub > /dev/null; + + $(APPNAME) from=$(OUTPUT)/mocprocTruth1.cub ingestion=false calibration=true mapping=false \ + to=$(OUTPUT)/mocprocTruth2.cub > /dev/null; + + $(APPNAME) from=$(OUTPUT)/mocprocTruth2.cub ingestion=false calibration=false mapping=true \ + to=$(OUTPUT)/mocprocTruth3.cub > /dev/null; diff --git a/isis/src/mgs/apps/mocproc/tsts/case03/Makefile b/isis/src/mgs/apps/mocproc/tsts/case03/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d438b396b73511775b583b6295d770ecb8b563ad --- /dev/null +++ b/isis/src/mgs/apps/mocproc/tsts/case03/Makefile @@ -0,0 +1,15 @@ +APPNAME = mocproc + +mocprocTruth3.cub.TOLERANCE = 0.0000001 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/m0402852.imq ingestion=true calibration=false mapping=false \ + to=$(OUTPUT)/mocprocTruth1.cub > /dev/null; + + $(APPNAME) from=$(OUTPUT)/mocprocTruth1.cub ingestion=false calibration=true mapping=false \ + to=$(OUTPUT)/mocprocTruth2.cub > /dev/null; + + $(APPNAME) from=$(OUTPUT)/mocprocTruth2.cub ingestion=false calibration=false mapping=true \ + to=$(OUTPUT)/mocprocTruth3.cub > /dev/null; diff --git a/isis/src/mgs/apps/mocuncompress/CheckSum.c b/isis/src/mgs/apps/mocuncompress/CheckSum.c new file mode 100644 index 0000000000000000000000000000000000000000..e4d7f75a8962cc71f56e358f8788066bd29d6240 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/CheckSum.c @@ -0,0 +1,460 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)CheckSum.c 1.1 10/04/99"; + +/* +* DESCRIPTION +* +* COMMENTARY +*/ + +#include "fs.h" +#include "CheckSum.h" + +uint8 CS8EAC(d,l)register uint8 *d; register uint32 l;{ +/* +* Compute the eight bit end-around-carry checksum of a data vector. +* +* Pre: +* 0 < l < 1<<24 +* d[0..(l-1)] is data to compute checksum of. +* Post: +* rv is checksum of d[0..(l-1)] +* Notes: +* +* There are two typical applications of this algorithm: Method 1 +* is save checksum of data part in known location (the PDS method) +* and method 2 is cause the checksum of the data and cs field to +* be some known value (MOC method, known value is 0xff). +* +* In both cases, assume a checksum is to be put on uint8 data[n], +* with the checksum octet to be placed in data[n-1]. +* +* APPLY CS METHOD 1: +* uint8 t; +* t = CS8EAC(data,n-1); +* *(uint8*)&data[n-1] = t; +* CHECK CS METHOD 1: +* if(CS8EAC(data,n-1) != *(uint8*)&data[n-1])bad(); +* APPLY CS METHOD 2: +* uint8 t; +* t = 0xff - CS8EAC(data,n-1); +* *(uint8*)&data[n-1] = t; +* CHECK CS METHOD 2: +* if(CS8EAC(data,n) != 0xff)bad(); +*/ +register uint32 cs = 0; + while(l--){ + cs += *d++; + }; + while(cs > 255){ + cs = (cs&0xff)+(cs>>8); + }; + return (uint8)cs; +} + +#if defined(TEST) +uint8 tcs8eac(d,l)register uint8 *d; register uint32 l;{ +/* +* Canonical version of CS8EAC(). Used to test the fast version. +*/ +register uint32 cs = 0; + while(l--){ + cs += *d++; + if(cs>255)cs -= 255; + }; + return cs; +} +#endif + +void CS8EACA1(dat,len)register uint8 *dat;uint32 len;{ +/* +* Apply type 1 CS8EAC checksum to dat. +* Pre: +* dat[0..len-2] is value to checksum. +* dat[len-1] is place to put checksum. +* Post: +* CS8EAC(dat,len-1) == dat[len-1] +* Notes: +*/ +uint8 t; + t = CS8EAC(dat,len-1); + *(uint8*)&dat[len-1] = t; +} + +void CS8EACA2(dat,len)register uint8 *dat;uint32 len;{ +/* +* Apply type 2 CS8EAC checksum to dat. +* Pre: +* dat[0..len-2] is value to checksum. +* dat[len-1] is place to put checksum. +* Post: +* CS8EAC(dat,len) == 0xff +* Notes: +*/ +uint8 t; + t = CS8EAC(dat,len-1); + *(uint8*)&dat[len-1] = 0xff - t; +} + +UINT CS8EACC1(dat,len)register uint8 *dat;UINT len;{ +/* +* Check type 1 checksum. +* Pre: +* dat[0..len-1] is data to check checksum of. +* CS8EACA1() or equivalent used to apply checksum. +* Post: +* rv nz iff checksum valid. +* Notes: +*/ +UINT rv = 1; + if(CS8EAC(dat,len-1) != dat[len-1]){ + return rv = 0; + }; + return rv; +} + +UINT CS8EACC2(dat,len)register uint8 *dat;UINT len;{ +/* +* Check type 2 checksum. +* Pre: +* dat[0..len-1] is data to check checksum of. +* CS8EACA2() or equivalent used to apply checksum. +* Post: +* rv nz iff checksum valid. +* Notes: +*/ +UINT rv = 1; + if(CS8EAC(dat,len) != 0xff){ + return rv = 0; + }; + return rv; +} + +uint16 CS16EAC(d,len)register uint8 *d;uint32 len;{ +/* +* Compute the sixteen bit end-around-carry checksum of a data vector. +* +* Pre: +* d[0..(l-1)] is data to compute checksum of. +* Post: +* rv is checksum of d[0..(l-1)] +* Notes: +* If l is odd then last word summed has last byte in d[] in +* its low byte, zero in its high byte. +* +* There are two typical applications of this algorithm: Method 1 +* is save checksum of data part in known location (the PDS method) +* and method 2 is cause the checksum of the data and cs field to +* be some known value (MOC method, known value is 0xffff). +* +* In both cases, assume a checksum is to be put on uint8 data[n], +* with the two checksum octets to be placed in data[n-2] and +* data[n-1]. +* +* APPLY CS METHOD 1: +* uint16 t; +* t = CS16EAC(data,n-2); +* *(uint16*)&data[n-2] = t; +* CHECK CS METHOD 1: +* if(CS16EAC(data,n-2) != *(uint16*)&data[n-2])bad(); +* APPLY CS METHOD 2: +* uint16 t; +* t = 0xffff - CS16EAC(data,n-2); +* if(n&1)t = (t<<8)|(t>>8); +* *(uint16*)&data[n-2] = t; +* CHECK CS METHOD 2: +* if(CS16EAC(data,n) != 0xffff)bad(); +*/ +register uint32 cs = 0; +register uint32 l; +register uint16 t; + do{ + l = (len<100)?len:100; + len -= l; + for(;l > 1;l -= 2){ + t = *d | (*(d+1) << 8); + cs += t; + d += sizeof(uint16); + }; + if(l)cs += *d++; + while(cs > 0xffff)cs = (cs&0xffff) + (cs>>16); + }while(len); + return cs; +} + +#if defined(TEST) +uint16 tcs16eac(d,l)register uint8 *d; register uint32 l;{ +/* +* Canonical version of CS16EAC(). Used to test the fast version. +*/ +register uint32 cs = 0; + for(;l > 1;l -= 2){ + cs += (uint16) (*d | (*(d+1) << 8)); + if(cs > 0xffff)cs -= 0xffff; + d += sizeof(uint16); + }; + if(l)cs += *d++; + if(cs > 0xffff)cs -= 0xffff; + return cs; +} +#endif + +void CS16EACA1(dat,len)register uint8 *dat;uint32 len;{ +/* +* Apply type 1 CS16EAC checksum to dat. +* Pre: +* dat[0..len-3] is value to checksum. +* dat[len-2..len-1] is place to put checksum. +* Post: +* CS16EAC(dat,len-2) == dat[len-2..len-1] +* Notes: +*/ +uint16 t; + t = CS16EAC(dat,len-2); + dat[len-2] = t & 0xff; + dat[len-1] = t >> 8; + /* *(uint16*)&(dat[len-2]) = t; */ +} + +void CS16EACA2(dat,len)register uint8 *dat;uint32 len;{ +/* +* Apply type 2 CS16EAC checksum to dat. +* Pre: +* dat[0..len-3] is value to checksum. +* dat[len-2..len-1] is place to put checksum. +* Post: +* CS16EAC(dat,len) == 0xffff +* Notes: +*/ +uint16 t; + t = 0xffff - CS16EAC(dat,len-2); + if(len&1)t = (t<<8)|(t>>8); + dat[len-2] = t&0xff; + dat[len-1] = t >> 8; + /* *(uint16*)&(dat[len-2]) = t; */ +} + +UINT CS16EACC1(dat,len)register uint8 *dat;UINT len;{ +/* +* Check type 1 checksum. +* Pre: +* dat[0..len-1] is data to check checksum of. +* CS16EACA1() or equivalent used to apply checksum. +* Post: +* rv nz iff checksum valid. +* Notes: +*/ +UINT rv = 1; +uint16 t; + + t = dat[len-2] | (dat[len-1] << 8); + if(CS16EAC(dat,len-2) != t){ + return rv = 0; + }; + return rv; +} + +UINT CS16EACC2(dat,len)register uint8 *dat;UINT len;{ +/* +* Check type 2 checksum. +* Pre: +* dat[0..len-1] is data to check checksum of. +* CS16EACA2() or equivalent used to apply checksum. +* Post: +* rv nz iff checksum valid. +* Notes: +*/ +UINT rv = 1; + if(CS16EAC(dat,len) != 0xffff){ + return rv = 0; + }; + return rv; +} + +UINT ParityOf(d,l)register uint8 *d; register uint32 l;{ +/* +* Compute parity of data vector. +* Pre: +* d[0..(l-1)] is data to compute parity of. +* Post: +* rv is number of "one" bits in d[0..(l-1)] modulo 2. +* Notes: +* "Odd parity" means that there are an odd number of "one" bits +* in the data covered by the parity. "Even parity" means that +* there are an even number of "one" bits in the data covered by +* the parity. It follows that this routine returns one if the +* data is odd parity, and zero if it is even parity. +* REFINE make ParityOf() faster if used often or with large l endREFINE +*/ +register UINT cs=0; +register uint8 t; + while(l--){ + t = *d++; + while(t){ + cs ^= (t&1); + t >>= 1; + }; + }; + return cs; +} + +#if defined(TEST) + +/* +* #define TESTCS8 +* #define TESTCS16 +* #define TESTPARITY +*/ +#define TESTCS8 +#define TESTCS16 +#define TESTPARITY + +#include +main(){ +uint8 d[100]; +UINT i,ii,iii; +UINT cs1,cs2; +UINT oldii = 0;UINT nbad=0; +#if defined(TESTCS8) || defined(TESTCS16) + for(i=0;i<=sizeof(d)*255;i+=1 /*65537*/){ + ii = 0; + iii = i; + while(iii>255){ + d[ii++] = 255; + iii -= 255; + }; + d[ii++] = iii; + if(ii != oldii){ + oldii = ii; + printf("CS test %d of %d\n",ii,sizeof(d)); + }; +#if defined(TESTCS8) + cs1 = CS8EAC(d,ii); + cs2 = tcs8eac(d,ii); + if(cs1 != cs2){ + printf("cs8 failed %d %d %d \n",i,cs1,cs2); + nbad += 1; + }; + CS8EACA1(d,ii); + if(!CS8EACC1(d,ii)){ + printf("CS8EACT1() failed\n"); + nbad += 1; + }; + if(CS8EAC(d,ii-1) != d[ii-1]){ + printf("CS8EAC1() failed\n"); + nbad += 1; + }; + CS8EACA2(d,ii); + if(!CS8EACC2(d,ii)){ + printf("CS8EACT2() failed\n"); + nbad += 1; + }; + if(CS8EAC(d,ii) != 0xff){ + printf("CS8EAC2() failed\n"); + nbad += 1; + }; +#endif +#if defined(TESTCS16) + cs1 = CS16EAC(d,ii); + cs2 = tcs16eac(d,ii); + if(cs1 != cs2){ + printf("cs16 failed %d %d %d \n",i,cs1,cs2); + nbad += 1; + }; + if(ii > 1){ + CS16EACA1(d,ii); + if(!CS16EACC1(d,ii)){ + printf("CS16EACT1() failed\n"); + nbad += 1; + }; + d[1] ^= 0x12; + if(CS16EACC1(d,ii)){ + printf("CS16EACT1() failed\n"); + nbad += 1; + }; + d[1] ^= 0x12; + if(CS16EAC(d,ii-2) != (d[ii-2] | (d[ii-1] << 8))){ + printf("CS16EAC1() failed\n"); + nbad += 1; + }; + CS16EACA2(d,ii); + if(!CS16EACC2(d,ii)){ + printf("CS16EACT2() failed\n"); + nbad += 1; + }; + d[1] ^= 0x12; + if(CS16EACC2(d,ii)){ + printf("CS16EACT2() failed\n"); + nbad += 1; + }; + d[1] ^= 0x12; + if(CS16EAC(d,ii) != 0xffff){ + printf("CS16EAC2() failed\n"); + nbad += 1; + }; + }; +#endif + }; +#endif + +#if defined(TESTPARITY) + for(i=0;i<256*256;i+=1){UINT t,cs; + if(!(i%256)){ + printf("Parity test %d of %d\n",i,65536); + }; + cs = 0; + t = i; + while(t){ + if(t&1)cs += 1; + t >>= 1; + }; + if(cs&1 != ParityOf(&i,4)){ + printf("ParityOf() failed\n"); + nbad += 1; + }; + }; +#endif + if(nbad){ + printf("MODULE FAILED %d TESTS\n",nbad); + }else{ + printf("Module passed tests\n"); + }; +} +#endif diff --git a/isis/src/mgs/apps/mocuncompress/CheckSum.h b/isis/src/mgs/apps/mocuncompress/CheckSum.h new file mode 100644 index 0000000000000000000000000000000000000000..955f6d522140ac321bd28b738b35dbbae5f54f1d --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/CheckSum.h @@ -0,0 +1,55 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)CheckSum.h 1.1 10/04/99 +*/ +/* SCCShid @(#)CheckSum.h (CheckSum.h) 1.5 */ +#if !defined(CheckSum_h) +#define CheckSum_h +extern uint8 CS8EAC(); +extern void CS8EACA1(); +extern void CS8EACA2(); +extern UINT CS8EACC1(); +extern UINT CS8EACC2(); +extern uint16 CS16EAC(); +extern void CS16EACA1(); +extern void CS16EACA2(); +extern UINT CS16EACC1(); +extern UINT CS16EACC2(); +extern UINT ParityOf(); +#endif diff --git a/isis/src/mgs/apps/mocuncompress/Makefile b/isis/src/mgs/apps/mocuncompress/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c64ff3c5543f620a97dad1fc6a7aefb08eb65520 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.c) +OBJS = $(SRCS:%.c=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mgs/apps/mocuncompress/array.c b/isis/src/mgs/apps/mocuncompress/array.c new file mode 100644 index 0000000000000000000000000000000000000000..3bd86f02f952aee96ac0ae939b2049516706347d --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/array.c @@ -0,0 +1,159 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)array.c 1.1 10/04/99"; + +/* + Auto-expanding array package + Mike Caplinger, MOC GDS Design Scientist + SCCS @(#)array.c 1.2 10/18/91 + + Implements a simple auto-expanding array data structure. Include + "array.h" to use. +*/ + +#include +#include +#include "array.h" + +/* + Create a new array with an initial allocation of len (0 will work if + you can't make a better guess) and return it. +*/ +Array *array_new(len) +int len; +{ + Array *new = (Array *) malloc(sizeof(Array)); + + if(new == 0) return 0; + + new->len = 0; + new->free = len; + new->data = (char *) malloc(len); + + if(new->data == 0) return 0; + + return new; +} + +/* + Append len bytes of data at the end of the array. Returns 0 if the + operation fails, otherwise a positive number. +*/ +int array_append(a, data, len) +Array *a; +char *data; +int len; +{ + if(a->free < len) { + /* expand array */ + a->data = (char *) realloc(a->data, len+(a->len+a->free)*2); + if(a->data == 0) { + return 0; + } + a->free += len+(a->len+a->free); + } + + bcopy(data, a->data+a->len, len); + a->free -= len; + a->len += len; + return len; +} + +/* + Delete an entry from the array and shove the remaining contents, + if any, down. Returns 0 if the operation fails, otherwise a + positive number. +*/ +int array_slot_delete(a, slot, len) +Array *a; +int slot, len; +{ + if(a->len < (slot+1)*len) return 0; + bcopy(&a->data[(slot+1)*len], &a->data[(slot)*len], + (a->len/len-slot-1)*len); + a->free += len; + a->len -= len; + return 1; +} + +/* + Returns the current size of the array in bytes. +*/ +int array_len(a) +Array *a; +{ + return a->len; +} + +/* + Returns the data contained in the array. This is a contiguous vector + of bytes guaranteed to be array_len(a) in size. +*/ +char *array_data(a) +Array *a; +{ + return a->data; +} + +/* + Deallocate an array and its data. +*/ +void array_free(a) +Array *a; +{ + free(a->data); + free(a); +} + +#ifdef TEST +main() { + Array *t = array_new(0); + + array_append(t, "abcdef", 7); + array_slot_delete(t, 0, 1); + printf("%s\n", array_data(t)); + array_slot_delete(t, 2, 1); + printf("%s\n", array_data(t)); + array_slot_delete(t, 3, 1); + printf("%s\n", array_data(t)); + array_slot_delete(t, 3, 1); + array_append(t, "1234", 5); + printf("%s\n", array_data(t)); +} +#endif diff --git a/isis/src/mgs/apps/mocuncompress/array.h b/isis/src/mgs/apps/mocuncompress/array.h new file mode 100644 index 0000000000000000000000000000000000000000..a99d2112cc3a6754621adab28bcbae28daafa3dd --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/array.h @@ -0,0 +1,54 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)array.h 1.1 10/04/99 +*/ +/* SCCS @(#)array.h 1.2 10/18/91 */ + +typedef struct { + int len; + int free; + char *data; +} Array; + +Array *array_new(); +int array_append(); +int array_len(); +char *array_data(); +void array_free(); +int array_slot_delete(); diff --git a/isis/src/mgs/apps/mocuncompress/bitsOut.h b/isis/src/mgs/apps/mocuncompress/bitsOut.h new file mode 100644 index 0000000000000000000000000000000000000000..98e733e630bf4db5509bdcaaa5626fe255fe026a --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/bitsOut.h @@ -0,0 +1,61 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)bitsOut.h 1.1 10/04/99 +*/ +/* SCCShid @(#)bitsOut.h (bitsOut.h) 1.4 */ + +#if !defined(bitsOut_h) + +#define bitsOut_h + +#include "fs.h" + +typedef struct bitStruct BITSTRUCT; /* Shorthand for the following struct */ + +struct bitStruct { + uint8 *output; /* Next available output byte location */ + uint32 bitQueue; /* Currented queued bits (up to 32) */ + uint32 bitCount; /* Number of bits queued in "bitQueue" */ +}; + +extern void bitsOutStart(); +extern void bitsOut(); +extern void bitsOutEnd(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/decompNONE.c b/isis/src/mgs/apps/mocuncompress/decompNONE.c new file mode 100644 index 0000000000000000000000000000000000000000..a65fef44790d5f7de4b81306c9569a059bea2428 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/decompNONE.c @@ -0,0 +1,216 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)decompNONE.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif + +#include "fs.h" +#include "bitsOut.h" +#include "nextValue.h" + +#include "decompNONE.h" + +void decompNONE(curLine,size,code,left,right,bitStuff) register uint8 *curLine; register uint32 size; uint8 *code,*left,*right; BITSTRUCT *bitStuff; { +register uint32 bitCount; +register uint8 *data; +register uint8 cur; + + data = bitStuff->output; + bitCount = bitStuff->bitCount; + + cur = (*data) >> bitCount; + + /* Decode all pixels in this line */ + while (size > 0) { + /* Store decoded value */ + nextValue(*curLine,code,left,right,cur,bitCount,data); + curLine++; + size--; + }; + + bitStuff->output = data; + bitStuff->bitCount = bitCount; +} + +#ifdef TEST + +void initReverse(trans) uint8 *trans; { +/* +* This function generate the bit reversal array "trans" above +* +* pre: +* +* post: +* The array "tran" contains the bit reversal of each index in that +* index's location (e.g. trans[0x05] = 0xa0). +*/ +register uint32 t; /* Current index */ + + /* Do all 8 bit numbers */ + for (t = 0; t < 256; t++) { + register uint8 r; /* Reversed byte */ + register uint8 b; /* Bit count */ + register uint8 mask; /* Current bit in index */ + register uint8 bit; /* Current bit in reversed byte */ + + /* Reverse all 8 bits */ + r = 0; + for (b = 0, mask = 0x1, bit = 0x80; b < 8; b++) { + /* + * If the bit in index is set, set the corresponding + * bit in the reversed byte + */ + if (t & mask) { + r |= bit; + }; + + /* Move bit in index up and bit in reversed byte down */ + mask = mask << 1; + bit = bit >> 1; + }; + + /* Store the reversed byte */ + trans[t] = r; + }; +} + +void createIdentTree(code,left,right) uint8 *code,*left,*right; { +uint32 index; + + for (index = 0; index < 127; index++) { + code[index] = LEFT | RIGHT; + left[index] = 2*index + 1; + right[index] = 2*index + 2; + }; + + for (index = 127; index < 255; index++) { + code[index] = 0; + left[index] = ~(2*(index - 127)); + right[index] = ~(2*(index - 127) + 1); + }; +} + +#define MAXLINE 2048 + +uint8 reverse[256]; +uint8 data[2 * MAXLINE + 4]; + +uint32 tryNone(code,left,right,bitStuff) uint8 *code,*left,*right; BITSTRUCT *bitStuff; { +uint32 nerror; +uint8 curLine[MAXLINE]; +uint32 i; +uint8 known,actual; + + nerror = 0; + + for (i = 0; i < MAXLINE; i++) { + curLine[i] = 0; + }; + + decompNONE(curLine,MAXLINE,code,left,right,bitStuff); + + for (i = 0; i < MAXLINE; i++) { + known = ~reverse[(~i) & 0xFF]; + actual = curLine[i]; + + if (known != actual) { + printf("None: Cur pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + + }; + + for (i = 0; i < MAXLINE; i++) { + curLine[i] = 0; + }; + + decompNONE(curLine,MAXLINE,code,left,right,bitStuff); + + for (i = 0; i < MAXLINE; i++) { + known = ~reverse[(~(i+MAXLINE)) & 0xFF]; + actual = curLine[i]; + + if (known != actual) { + printf("None: Cur pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + }; + + return(nerror); +} + +main() { +uint32 nerror; +uint8 code[256]; +uint8 left[256]; +uint8 right[256]; +BITSTRUCT bitStuff; +uint32 i; + + /* No errors yet */ + nerror = 0; + + printf("Test started\n"); + + initReverse(reverse); + + createIdentTree(code,left,right); + + /* Check decompression */ + + for (i = 0; i < 2*MAXLINE + 4; i++) { + data[i] = ~i; + }; + + bitStuff.data = data; + bitStuff.bitQueue = 0; + bitStuff.bitCount = 0; + nerror = tryNone(code,left,right,&bitStuff); + + /* If no errors print message */ + if (nerror == 0) { + printf("Test succeeded\n"); + } else { + printf("Test failed: %d\n",nerror); + }; + + /* Exit with the number of errors */ + exit(nerror); +} +#endif diff --git a/isis/src/mgs/apps/mocuncompress/decompNONE.h b/isis/src/mgs/apps/mocuncompress/decompNONE.h new file mode 100644 index 0000000000000000000000000000000000000000..1c886772e380b879455acc125e1faab7130f8c5d --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/decompNONE.h @@ -0,0 +1,49 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)decompNONE.h 1.1 10/04/99 +*/ +/* SCCShid @(#)decompNONE.h (decompNONE.h) 1.2 */ + +#if !defined(decompNONE_h) + +#define decompNONE_h + +extern void decompNONE(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/decompSYNC.c b/isis/src/mgs/apps/mocuncompress/decompSYNC.c new file mode 100644 index 0000000000000000000000000000000000000000..61327c14bb1d31ee6b0d1eeeba9bc202a5263c88 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/decompSYNC.c @@ -0,0 +1,176 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)decompSYNC.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif + +#include "fs.h" +#include "bitsOut.h" +#include "nextValue.h" + +#include "decompSYNC.h" + +void decompSYNC(curLine,prevLine,size,sync,bitStuff) register uint8 *curLine,*prevLine; register uint32 size; uint16 sync; BITSTRUCT *bitStuff; { +register uint32 count; /* Pixel counter */ +register uint8 *scan; /* Pixel copying pointer */ + + /* Skip sync pattern (assumes alignment) */ + bitStuff->output += 2; + + /* Prepare to copy data */ + scan = bitStuff->output; + + /* Copy all pixels on this line */ + for (count = 0; count < size; count++) { + register uint8 cur; /* Current pixel value */ + + /* Get current pixel value */ + cur = *(scan++); + + /* Store the current pixel */ + *(curLine++) = cur; + + /* Store as the next pixel's previous pixel */ + *(prevLine++) = cur; + }; + + /* Update bit stream and align */ + bitStuff->output = scan; + bitStuff->bitCount = 0; +} + +#ifdef TEST + +#define MAXLINE 2048 + +uint8 data[2 * MAXLINE + 4]; + +uint32 trySync(bitStuff) BITSTRUCT *bitStuff; { +uint32 nerror; +uint16 sync; +uint8 prevLine[MAXLINE]; +uint8 curLine[MAXLINE]; +uint32 i; +uint8 known,actual; + + nerror = 0; + + sync = 0; + + for (i = 0; i < MAXLINE; i++) { + prevLine[i] = curLine[i] = 0; + }; + + decompSYNC(curLine,prevLine,MAXLINE,sync,bitStuff); + + for (i = 0; i < MAXLINE; i++) { + known = ~(i+2); + actual = curLine[i]; + + if (known != actual) { + printf("Sync: Cur pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + + actual = prevLine[i]; + + if (known != actual) { + printf("Sync: Prev pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + }; + + for (i = 0; i < MAXLINE; i++) { + prevLine[i] = curLine[i] = 0; + }; + + decompSYNC(curLine,prevLine,MAXLINE,sync,bitStuff); + + for (i = 0; i < MAXLINE; i++) { + known = ~(i+MAXLINE+4); + actual = curLine[i]; + + if (known != actual) { + printf("Sync: Cur pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + + actual = prevLine[i]; + + if (known != actual) { + printf("Sync: Prev pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + }; + + return(nerror); +} + +main() { +uint32 nerror; +BITSTRUCT bitStuff; +uint32 i; + + /* No errors yet */ + nerror = 0; + + printf("Test started\n"); + + /* Check decompression */ + + for (i = 0; i < 2*MAXLINE + 4; i++) { + data[i] = ~i; + }; + + bitStuff.data = data; + bitStuff.bitQueue = 0; + bitStuff.bitCount = 0; + nerror = trySync(&bitStuff); + + /* If no errors print message */ + if (nerror == 0) { + printf("Test succeeded\n"); + } else { + printf("Test failed: %d\n",nerror); + }; + + /* Exit with the number of errors */ + exit(nerror); +} +#endif diff --git a/isis/src/mgs/apps/mocuncompress/decompSYNC.h b/isis/src/mgs/apps/mocuncompress/decompSYNC.h new file mode 100644 index 0000000000000000000000000000000000000000..14ea7a92e61b621d07ae25fcc13657e74ebb6401 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/decompSYNC.h @@ -0,0 +1,49 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)decompSYNC.h 1.1 10/04/99 +*/ +/* SCCShid @(#)decompSYNC.h (decompSYNC.h) 1.2 */ + +#if !defined(decompSYNC_h) + +#define decompSYNC_h + +extern void decompSYNC(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/decompXPRED.c b/isis/src/mgs/apps/mocuncompress/decompXPRED.c new file mode 100644 index 0000000000000000000000000000000000000000..dee31eb7fb1eafc49e6bd2fcc56fc86287028d3a --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/decompXPRED.c @@ -0,0 +1,233 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)decompXPRED.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif + +#include "fs.h" +#include "bitsOut.h" +#include "nextValue.h" + +#include "decompXPRED.h" + +void decompXPRED(curLine,size,code,left,right,bitStuff) register uint8 *curLine; uint32 size; uint8 *code,*left,*right; BITSTRUCT *bitStuff; { +register uint8 prev; /* Previous pixel */ +register uint32 bitCount; +register uint8 *data; +register uint8 cur; + + /* The first "previous pixel" is zero */ + prev = 0; + + data = bitStuff->output; + bitCount = bitStuff->bitCount; + + cur = (*data) >> bitCount; + + /* Decode and decompress all pixels in this line */ + while (size > 0) { + register uint8 temp; + /* + * Decode and decompress this pixel and store it + * as the next pixel's previous pixel + */ + nextValue(temp,code,left,right,cur,bitCount,data); + prev += temp; + + /* Store the current pixel */ + *(curLine++) = prev; + + size--; + }; + + bitStuff->output = data; + bitStuff->bitCount = bitCount; +} + +#ifdef TEST + +void initReverse(trans) uint8 *trans; { +/* +* This function generate the bit reversal array "trans" above +* +* pre: +* +* post: +* The array "tran" contains the bit reversal of each index in that +* index's location (e.g. trans[0x05] = 0xa0). +*/ +register uint32 t; /* Current index */ + + /* Do all 8 bit numbers */ + for (t = 0; t < 256; t++) { + register uint8 r; /* Reversed byte */ + register uint8 b; /* Bit count */ + register uint8 mask; /* Current bit in index */ + register uint8 bit; /* Current bit in reversed byte */ + + /* Reverse all 8 bits */ + r = 0; + for (b = 0, mask = 0x1, bit = 0x80; b < 8; b++) { + /* + * If the bit in index is set, set the corresponding + * bit in the reversed byte + */ + if (t & mask) { + r |= bit; + }; + + /* Move bit in index up and bit in reversed byte down */ + mask = mask << 1; + bit = bit >> 1; + }; + + /* Store the reversed byte */ + trans[t] = r; + }; +} + +void createIdentTree(code,left,right) uint8 *code,*left,*right; { +uint32 index; + + for (index = 0; index < 127; index++) { + code[index] = LEFT | RIGHT; + left[index] = 2*index + 1; + right[index] = 2*index + 2; + }; + + for (index = 127; index < 255; index++) { + code[index] = 0; + left[index] = ~(2*(index - 127)); + right[index] = ~(2*(index - 127) + 1); + }; +} + +#define MAXLINE 2048 + +uint8 reverse[256]; +uint8 data[2 * MAXLINE + 4]; + +uint32 tryXpred(code,left,right,bitStuff) uint8 *code,*left,*right; BITSTRUCT *bitStuff; { +uint32 nerror; +uint8 curLine[MAXLINE]; +uint32 i; +uint8 known,actual,sum; + + nerror = 0; + + for (i = 0; i < MAXLINE; i++) { + curLine[i] = 0; + }; + + decompXPRED(curLine,MAXLINE,code,left,right,bitStuff); + + sum = 0; + + for (i = 0; i < MAXLINE; i++) { + sum += ~reverse[(~i) & 0xFF]; + known = sum; + actual = curLine[i]; + + if (known != actual) { + printf("X Pred: Cur pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + }; + + for (i = 0; i < MAXLINE; i++) { + curLine[i] = 0; + }; + + decompXPRED(curLine,MAXLINE,code,left,right,bitStuff); + + sum = 0; + + for (i = 0; i < MAXLINE; i++) { + sum += ~reverse[(~(i+MAXLINE)) & 0xFF]; + known = sum; + actual = curLine[i]; + + if (known != actual) { + printf("X Pred: Cur pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + }; + + return(nerror); +} + +main() { +uint32 nerror; +uint8 code[256]; +uint8 left[256]; +uint8 right[256]; +BITSTRUCT bitStuff; +uint32 i; + + /* No errors yet */ + nerror = 0; + + printf("Test started\n"); + + initReverse(reverse); + + createIdentTree(code,left,right); + + /* Check decompression */ + + for (i = 0; i < 2*MAXLINE + 4; i++) { + data[i] = ~i; + }; + + bitStuff.data = data; + bitStuff.bitQueue = 0; + bitStuff.bitCount = 0; + nerror = tryXpred(code,left,right,&bitStuff); + + /* If no errors print message */ + if (nerror == 0) { + printf("Test succeeded\n"); + } else { + printf("Test failed: %d\n",nerror); + }; + + /* Exit with the number of errors */ + exit(nerror); +} +#endif diff --git a/isis/src/mgs/apps/mocuncompress/decompXPRED.h b/isis/src/mgs/apps/mocuncompress/decompXPRED.h new file mode 100644 index 0000000000000000000000000000000000000000..95c8885a259b9735b73e67fb760076dbfbd15b91 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/decompXPRED.h @@ -0,0 +1,49 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)decompXPRED.h 1.1 10/04/99 +*/ +/* SCCShid @(#)decompXPRED.h (decompXPRED.h) 1.2 */ + +#if !defined(decompXPRED_h) + +#define decompXPRED_h + +extern void decompXPRED(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/decompXPREDYPRED.c b/isis/src/mgs/apps/mocuncompress/decompXPREDYPRED.c new file mode 100644 index 0000000000000000000000000000000000000000..a3cc53e04cae86026369e987f7535ed16d475099 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/decompXPREDYPRED.c @@ -0,0 +1,255 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)decompXPREDYPRED.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif + +#include "fs.h" +#include "bitsOut.h" +#include "nextValue.h" + +#include "decompXPREDYPRED.h" + +void decompXPREDYPRED(curLine,prevLine,size,code,left,right,bitStuff) register uint8 *curLine,*prevLine; register uint32 size; uint8 *code,*left,*right; BITSTRUCT *bitStuff; { +register uint8 prevDiff; /* Previous vertical difference */ +register uint32 bitCount; +register uint8 *data; +register uint8 cur; + + data = bitStuff->output; + bitCount = bitStuff->bitCount; + + cur = (*data) >> bitCount; + + /* The first "previous difference" is zero */ + prevDiff = 0; + + /* Decode and decompress all pixels in this line */ + while (size > 0) { + register uint8 prev; /* The previous pixel */ + + /* Decode and decompress this pixel */ + nextValue(prev,code,left,right,cur,bitCount,data); + prevDiff += prev; + + /* Get the previous pixel */ + prev = *prevLine; + prev += prevDiff; + + /* Store the current pixel */ + *(curLine++) = prev; + + /* Store as the next pixel's previous pixel */ + *(prevLine++) = prev; + + size--; + }; + + bitStuff->output = data; + bitStuff->bitCount = bitCount; +} + +#ifdef TEST + +void initReverse(trans) uint8 *trans; { +/* +* This function generate the bit reversal array "trans" above +* +* pre: +* +* post: +* The array "tran" contains the bit reversal of each index in that +* index's location (e.g. trans[0x05] = 0xa0). +*/ +register uint32 t; /* Current index */ + + /* Do all 8 bit numbers */ + for (t = 0; t < 256; t++) { + register uint8 r; /* Reversed byte */ + register uint8 b; /* Bit count */ + register uint8 mask; /* Current bit in index */ + register uint8 bit; /* Current bit in reversed byte */ + + /* Reverse all 8 bits */ + r = 0; + for (b = 0, mask = 0x1, bit = 0x80; b < 8; b++) { + /* + * If the bit in index is set, set the corresponding + * bit in the reversed byte + */ + if (t & mask) { + r |= bit; + }; + + /* Move bit in index up and bit in reversed byte down */ + mask = mask << 1; + bit = bit >> 1; + }; + + /* Store the reversed byte */ + trans[t] = r; + }; +} + +void createIdentTree(code,left,right) uint8 *code,*left,*right; { +uint32 index; + + for (index = 0; index < 127; index++) { + code[index] = LEFT | RIGHT; + left[index] = 2*index + 1; + right[index] = 2*index + 2; + }; + + for (index = 127; index < 255; index++) { + code[index] = 0; + left[index] = ~(2*(index - 127)); + right[index] = ~(2*(index - 127) + 1); + }; +} + +#define MAXLINE 2048 + +uint8 reverse[256]; +uint8 data[2 * MAXLINE + 4]; + +uint32 tryXYpred(code,left,right,bitStuff) uint8 *code,*left,*right; BITSTRUCT *bitStuff; { +uint32 nerror; +uint8 prevLine[MAXLINE]; +uint8 curLine[MAXLINE]; +uint32 i; +uint8 known,actual,prev,sum; + + nerror = 0; + + for (i = 0; i < MAXLINE; i++) { + prevLine[i] = curLine[i] = 0; + }; + + decompXPREDYPRED(curLine,prevLine,MAXLINE,code,left,right,bitStuff); + + prev = 0; + + for (i = 0; i < MAXLINE; i++) { + prev += ~reverse[(~i) & 0xFF]; + known = prev; + actual = curLine[i]; + + if (known != actual) { + printf("XY Pred: Cur pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + + actual = prevLine[i]; + + if (known != actual) { + printf("XY Pred: Prev pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + }; + + for (i = 0; i < MAXLINE; i++) { + curLine[i] = 0; + }; + + decompXPREDYPRED(curLine,prevLine,MAXLINE,code,left,right,bitStuff); + + sum = 0; + prev = 0; + + for (i = 0; i < MAXLINE; i++) { + sum += ~reverse[(~i) & 0xFF]; + known = (~reverse[(~(i+MAXLINE)) & 0xFF]) + sum + prev; + prev = known - sum; + actual = curLine[i]; + + if (known != actual) { + printf("XY Pred: Cur pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + + actual = prevLine[i]; + + if (known != actual) { + printf("XY Pred: Prev pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + }; + + return(nerror); +} + +main() { +uint32 nerror; +uint8 code[256]; +uint8 left[256]; +uint8 right[256]; +BITSTRUCT bitStuff; +uint32 i; + + /* No errors yet */ + nerror = 0; + + printf("Test started\n"); + + initReverse(reverse); + + createIdentTree(code,left,right); + + /* Check decompression */ + + for (i = 0; i < 2*MAXLINE + 4; i++) { + data[i] = ~i; + }; + + bitStuff.data = data; + bitStuff.bitQueue = 0; + bitStuff.bitCount = 0; + nerror = tryXYpred(code,left,right,&bitStuff); + + /* If no errors print message */ + if (nerror == 0) { + printf("Test succeeded\n"); + } else { + printf("Test failed: %d\n",nerror); + }; + + /* Exit with the number of errors */ + exit(nerror); +} +#endif diff --git a/isis/src/mgs/apps/mocuncompress/decompXPREDYPRED.h b/isis/src/mgs/apps/mocuncompress/decompXPREDYPRED.h new file mode 100644 index 0000000000000000000000000000000000000000..b521858486e49449fab9f4fe93e552d7f9c30cd7 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/decompXPREDYPRED.h @@ -0,0 +1,49 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)decompXPREDYPRED.h 1.1 10/04/99 +*/ +/* SCCShid @(#)decompXPREDYPRED.h (decompXPREDYPRED.h) 1.2 */ + +#if !defined(decompXPREDYPRED_h) + +#define decompXPREDYPRED_h + +extern void decompXPREDYPRED(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/decompYPRED.c b/isis/src/mgs/apps/mocuncompress/decompYPRED.c new file mode 100644 index 0000000000000000000000000000000000000000..fc3a48f6b91e74f62d654b897061ea3144e903c9 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/decompYPRED.c @@ -0,0 +1,239 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)decompYPRED.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif + +#include "fs.h" +#include "bitsOut.h" +#include "nextValue.h" + +#include "decompYPRED.h" + +void decompYPRED(curLine,prevLine,size,code,left,right,bitStuff) register uint8 *curLine,*prevLine; register uint32 size; uint8 *code,*left,*right; BITSTRUCT *bitStuff; { +register uint32 bitCount; +register uint8 *data; +register uint8 cur; + + data = bitStuff->output; + bitCount = bitStuff->bitCount; + + cur = (*data) >> bitCount; + + /* Decode and decompress all pixels in this line */ + while (size > 0) { + register uint8 prev; /* The previous pixel */ + + /* Decode and decompress this pixel */ + nextValue(prev,code,left,right,cur,bitCount,data); + prev += *prevLine; + + /* Store the current pixel */ + *(curLine++) = prev; + + /* Store as the next pixel's previous pixel */ + *(prevLine++) = prev; + + size--; + }; + + bitStuff->output = data; + bitStuff->bitCount = bitCount; +} + +#ifdef TEST + +void initReverse(trans) uint8 *trans; { +/* +* This function generate the bit reversal array "trans" above +* +* pre: +* +* post: +* The array "tran" contains the bit reversal of each index in that +* index's location (e.g. trans[0x05] = 0xa0). +*/ +register uint32 t; /* Current index */ + + /* Do all 8 bit numbers */ + for (t = 0; t < 256; t++) { + register uint8 r; /* Reversed byte */ + register uint8 b; /* Bit count */ + register uint8 mask; /* Current bit in index */ + register uint8 bit; /* Current bit in reversed byte */ + + /* Reverse all 8 bits */ + r = 0; + for (b = 0, mask = 0x1, bit = 0x80; b < 8; b++) { + /* + * If the bit in index is set, set the corresponding + * bit in the reversed byte + */ + if (t & mask) { + r |= bit; + }; + + /* Move bit in index up and bit in reversed byte down */ + mask = mask << 1; + bit = bit >> 1; + }; + + /* Store the reversed byte */ + trans[t] = r; + }; +} + +void createIdentTree(code,left,right) uint8 *code,*left,*right; { +uint32 index; + + for (index = 0; index < 127; index++) { + code[index] = LEFT | RIGHT; + left[index] = 2*index + 1; + right[index] = 2*index + 2; + }; + + for (index = 127; index < 255; index++) { + code[index] = 0; + left[index] = ~(2*(index - 127)); + right[index] = ~(2*(index - 127) + 1); + }; +} + +#define MAXLINE 2048 + +uint8 reverse[256]; +uint8 data[2 * MAXLINE + 4]; + +uint32 tryYpred(code,left,right,bitStuff) uint8 *code,*left,*right; BITSTRUCT *bitStuff; { +uint32 nerror; +uint8 prevLine[MAXLINE]; +uint8 curLine[MAXLINE]; +uint32 i; +uint8 known,actual; + + nerror = 0; + + for (i = 0; i < MAXLINE; i++) { + prevLine[i] = curLine[i] = 0; + }; + + decompYPRED(curLine,prevLine,MAXLINE,code,left,right,bitStuff); + + for (i = 0; i < MAXLINE; i++) { + known = ~reverse[(~i) & 0xFF]; + actual = curLine[i]; + + if (known != actual) { + printf("Y Pred: Cur pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + + actual = prevLine[i]; + + if (known != actual) { + printf("Y Pred: Prev pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + }; + + for (i = 0; i < MAXLINE; i++) { + curLine[i] = 0; + }; + + decompYPRED(curLine,prevLine,MAXLINE,code,left,right,bitStuff); + + for (i = 0; i < MAXLINE; i++) { + known = (~reverse[(~i) & 0xFF]) + (~reverse[(~(i+MAXLINE)) & 0xFF]); + actual = curLine[i]; + + if (known != actual) { + printf("Y Pred: Cur pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + + actual = prevLine[i]; + + if (known != actual) { + printf("Y Pred: Prev pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff->data - data,bitStuff->bitCount,known,known,actual,actual); + nerror += 1; + }; + }; + + return(nerror); +} + +main() { +uint32 nerror; +uint8 code[256]; +uint8 left[256]; +uint8 right[256]; +BITSTRUCT bitStuff; +uint32 i; + + /* No errors yet */ + nerror = 0; + + printf("Test started\n"); + + initReverse(reverse); + + createIdentTree(code,left,right); + + /* Check decompression */ + + for (i = 0; i < 2*MAXLINE + 4; i++) { + data[i] = ~i; + }; + + bitStuff.data = data; + bitStuff.bitQueue = 0; + bitStuff.bitCount = 0; + nerror = tryYpred(code,left,right,&bitStuff); + + /* If no errors print message */ + if (nerror == 0) { + printf("Test succeeded\n"); + } else { + printf("Test failed: %d\n",nerror); + }; + + /* Exit with the number of errors */ + exit(nerror); +} +#endif diff --git a/isis/src/mgs/apps/mocuncompress/decompYPRED.h b/isis/src/mgs/apps/mocuncompress/decompYPRED.h new file mode 100644 index 0000000000000000000000000000000000000000..9effff1d5222d08568a822933419fd86680ab1cc --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/decompYPRED.h @@ -0,0 +1,49 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)decompYPRED.h 1.1 10/04/99 +*/ +/* SCCShid @(#)decompYPRED.h (decompYPRED.h) 1.2 */ + +#if !defined(decompYPRED_h) + +#define decompYPRED_h + +extern void decompYPRED(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/encodeCoefs.static.h b/isis/src/mgs/apps/mocuncompress/encodeCoefs.static.h new file mode 100644 index 0000000000000000000000000000000000000000..a0700f88d9a78811f8917e432e87846df110cb39 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/encodeCoefs.static.h @@ -0,0 +1,554 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)encodeCoefs.static.h 1.1 10/04/99 +*/ +/* This file was automatically generated by 'makeEncode' */ + +#if !defined(encodeCoefs_static_h) + +#define encodeCoefs_static_h + +#include "fs.h" + +/* Number of valid bits (LSBs) in each entry in "code0" */ +static uint8 num0[25] = { + 24, 23, 20, 19, 16, 14, 13, 10, + 8, 6, 5, 3, 1, 2, 4, 7, + 9, 11, 12, 15, 17, 18, 21, 22, + 24, +}; + +/* Huffman code for encoding scheme 0, zero's code is index 12 */ +static uint32 code0[25] = { +0xffffff,0x3fffff,0x07ffff,0x03ffff,0x007fff,0x001fff,0x000fff,0x0001ff, +0x00007f,0x00001f,0x00000f,0x000003,0x000000,0x000001,0x000007,0x00003f, +0x0000ff,0x0003ff,0x0007ff,0x003fff,0x00ffff,0x01ffff,0x0fffff,0x1fffff, +0x7fffff, +}; + +/* Number of valid bits (LSBs) in each entry in "code1" */ +static uint8 num1[47] = { + 24, 24, 23, 22, 21, 20, 19, 18, + 17, 16, 15, 14, 13, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 2, 2, + 2, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 24, +}; + +/* Huffman code for encoding scheme 1, zero's code is index 23 */ +static uint32 code1[47] = { +0xffffff,0xbfffff,0x5fffff,0x2fffff,0x17ffff,0x0bffff,0x05ffff,0x02ffff, +0x017fff,0x00bfff,0x005fff,0x002fff,0x0017ff,0x000bff,0x0005ff,0x0002ff, +0x00017f,0x0000bf,0x00005f,0x00002f,0x000017,0x00000b,0x000002,0x000001, +0x000000,0x000003,0x000007,0x00000f,0x00001f,0x00003f,0x00007f,0x0000ff, +0x0001ff,0x0003ff,0x0007ff,0x000fff,0x001fff,0x003fff,0x007fff,0x00ffff, +0x01ffff,0x03ffff,0x07ffff,0x0fffff,0x1fffff,0x3fffff,0x7fffff, +}; + +/* Number of valid bits (LSBs) in each entry in "code2" */ +static uint8 num2[69] = { + 24, 24, 23, 23, 22, 22, 21, 20, + 19, 19, 18, 17, 17, 16, 16, 15, + 14, 14, 13, 12, 11, 11, 10, 9, + 9, 8, 7, 7, 6, 6, 5, 4, + 4, 3, 2, 3, 3, 4, 5, 5, + 6, 7, 8, 8, 9, 10, 10, 11, + 12, 12, 13, 13, 14, 15, 15, 16, + 17, 18, 18, 19, 20, 20, 21, 21, + 22, 23, 23, 24, 24, +}; + +/* Huffman code for encoding scheme 2, zero's code is index 34 */ +static uint32 code2[69] = { +0xffffff,0xfffffd,0x7ffffe,0x3ffffd,0x1ffffe,0x1fffff,0x0fffff,0x07fffe, +0x03fffe,0x03ffff,0x01fffd,0x00fffe,0x00ffff,0x007ffe,0x007fff,0x003fff, +0x001ffe,0x001fff,0x000fff,0x0007fe,0x0003fe,0x0003ff,0x0001fe,0x0000fe, +0x0000ff,0x00007d,0x00003e,0x00003d,0x00001d,0x00001f,0x00000d,0x000005, +0x000007,0x000001,0x000000,0x000003,0x000002,0x000006,0x00000f,0x00000e, +0x00001e,0x00003f,0x00007f,0x00007e,0x0000fd,0x0001ff,0x0001fd,0x0003fd, +0x0007ff,0x0007fd,0x000ffd,0x000ffe,0x001ffd,0x003ffd,0x003ffe,0x007ffd, +0x00fffd,0x01ffff,0x01fffe,0x03fffd,0x07ffff,0x07fffd,0x0ffffd,0x0ffffe, +0x1ffffd,0x3fffff,0x3ffffe,0x7ffffd,0x7fffff, +}; + +/* Number of valid bits (LSBs) in each entry in "code3" */ +static uint8 num3[109] = { + 23, 24, 24, 23, 23, 22, 22, 22, + 21, 21, 21, 20, 20, 19, 19, 18, + 18, 18, 17, 17, 16, 16, 16, 15, + 15, 14, 14, 14, 13, 13, 13, 12, + 12, 11, 11, 10, 10, 10, 9, 9, + 9, 8, 8, 7, 7, 6, 6, 6, + 5, 5, 4, 4, 4, 3, 3, 3, + 4, 4, 5, 5, 5, 6, 6, 7, + 7, 7, 8, 8, 8, 9, 9, 10, + 10, 11, 11, 11, 12, 12, 12, 13, + 13, 14, 14, 15, 15, 15, 16, 16, + 17, 17, 17, 18, 18, 19, 19, 19, + 20, 20, 20, 21, 21, 22, 22, 22, + 23, 23, 24, 24, 23, +}; + +/* Huffman code for encoding scheme 3, zero's code is index 54 */ +static uint32 code3[109] = { +0x7fffff,0xfffffd,0xdfffff,0x7ffffe,0x3ffffd,0x3ffffc,0x1ffffe,0x3ffffb, +0x0ffffe,0x0ffffd,0x0ffffb,0x07fffd,0x07ffff,0x03fffc,0x03ffff,0x01fffc, +0x01fffe,0x01ffff,0x00fffe,0x00fffd,0x007ffc,0x007ffd,0x007ffb,0x003ffc, +0x003fff,0x001ffc,0x001ffd,0x001fff,0x000ffc,0x000ffd,0x000ffb,0x0007fd, +0x0007fb,0x0003fe,0x0003fd,0x0001fc,0x0001fd,0x0001ff,0x0000fc,0x0000ff, +0x0000fb,0x00007d,0x00007b,0x00003c,0x00003d,0x00001c,0x00001e,0x00001b, +0x00000e,0x00000f,0x000004,0x000006,0x000003,0x000002,0x000001,0x000000, +0x000007,0x000005,0x00000b,0x00000d,0x00000c,0x00001f,0x00001d,0x00003b, +0x00003f,0x00003e,0x00007f,0x00007e,0x00007c,0x0000fd,0x0000fe,0x0001fb, +0x0001fe,0x0003fb,0x0003ff,0x0003fc,0x0007ff,0x0007fe,0x0007fc,0x000fff, +0x000ffe,0x001ffb,0x001ffe,0x003ffb,0x003ffd,0x003ffe,0x007fff,0x007ffe, +0x00fffb,0x00ffff,0x00fffc,0x01fffb,0x01fffd,0x03fffb,0x03fffd,0x03fffe, +0x07fffb,0x07fffe,0x07fffc,0x0fffff,0x0ffffc,0x1ffffb,0x1ffffd,0x1ffffc, +0x1fffff,0x3ffffe,0x5fffff,0x7ffffd,0x3fffff, +}; + +/* Number of valid bits (LSBs) in each entry in "code4" */ +static uint8 num4[169] = { + 22, 24, 24, 24, 24, 23, 23, 23, + 23, 22, 22, 22, 22, 21, 21, 21, + 21, 20, 20, 20, 20, 19, 19, 19, + 19, 18, 18, 18, 18, 17, 17, 17, + 17, 16, 16, 16, 16, 15, 15, 15, + 15, 14, 14, 14, 14, 13, 13, 13, + 13, 12, 12, 12, 12, 11, 11, 11, + 11, 10, 10, 10, 10, 9, 9, 9, + 9, 8, 8, 8, 8, 7, 7, 7, + 7, 6, 6, 6, 6, 5, 5, 5, + 5, 4, 4, 4, 3, 4, 4, 4, + 5, 5, 5, 5, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, + 9, 9, 9, 9, 10, 10, 10, 10, + 11, 11, 11, 11, 12, 12, 12, 12, + 13, 13, 13, 13, 14, 14, 14, 14, + 15, 15, 15, 15, 16, 16, 16, 16, + 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, + 21, 21, 21, 21, 22, 22, 22, 22, + 23, 23, 23, 23, 24, 24, 24, 24, + 22, +}; + +/* Huffman code for encoding scheme 4, zero's code is index 84 */ +static uint32 code4[169] = { +0x3fffff,0xf7ffff,0xe7ffff,0xfdffff,0xfffffe,0x27ffff,0x7bffff,0x3dffff, +0x5ffffe,0x17ffff,0x1bffff,0x3ffffc,0x2ffffe,0x0bffff,0x0dffff,0x17fffc, +0x17fffe,0x03ffff,0x0ffffd,0x0bfffc,0x0bfffe,0x03fffd,0x05fffd,0x05fffc, +0x05fffe,0x02ffff,0x02fffd,0x02fffc,0x02fffe,0x017fff,0x017ffd,0x017ffc, +0x017ffe,0x00bfff,0x00bffd,0x00bffc,0x00bffe,0x005fff,0x005ffd,0x005ffc, +0x005ffe,0x002fff,0x002ffd,0x002ffc,0x002ffe,0x0017ff,0x0017fd,0x0017fc, +0x0017fe,0x000bff,0x000bfd,0x000bfc,0x000bfe,0x0005ff,0x0005fd,0x0005fc, +0x0005fe,0x0002ff,0x0002fd,0x0002fc,0x0002fe,0x00017f,0x00017d,0x00017c, +0x00017e,0x0000bf,0x0000bd,0x0000bc,0x0000be,0x00005f,0x00005d,0x00005c, +0x00005e,0x00002f,0x00002d,0x00002c,0x00002e,0x000017,0x000015,0x000014, +0x000016,0x000009,0x000008,0x00000a,0x000003,0x000002,0x000000,0x000001, +0x000006,0x000004,0x000005,0x000007,0x00000e,0x00000c,0x00000d,0x00000f, +0x00001e,0x00001c,0x00001d,0x00001f,0x00003e,0x00003c,0x00003d,0x00003f, +0x00007e,0x00007c,0x00007d,0x00007f,0x0000fe,0x0000fc,0x0000fd,0x0000ff, +0x0001fe,0x0001fc,0x0001fd,0x0001ff,0x0003fe,0x0003fc,0x0003fd,0x0003ff, +0x0007fe,0x0007fc,0x0007fd,0x0007ff,0x000ffe,0x000ffc,0x000ffd,0x000fff, +0x001ffe,0x001ffc,0x001ffd,0x001fff,0x003ffe,0x003ffc,0x003ffd,0x003fff, +0x007ffe,0x007ffc,0x007ffd,0x007fff,0x00fffe,0x00fffc,0x00fffd,0x00ffff, +0x01fffe,0x01fffc,0x01fffd,0x01ffff,0x03fffe,0x03fffc,0x07fffd,0x05ffff, +0x07fffe,0x07fffc,0x0ffffc,0x0fffff,0x0ffffe,0x1ffffc,0x1dffff,0x07ffff, +0x1ffffe,0x3ffffe,0x3bffff,0x37ffff,0x7ffffe,0x7dffff,0x67ffff,0x77ffff, +0x1fffff, +}; + +/* Number of valid bits (LSBs) in each entry in "code5" */ +static uint8 num5[247] = { + 21, 24, 24, 24, 24, 24, 24, 23, + 23, 23, 23, 23, 23, 22, 22, 22, + 22, 22, 22, 22, 21, 21, 21, 21, + 21, 20, 20, 20, 20, 20, 20, 19, + 19, 19, 19, 19, 19, 18, 18, 18, + 18, 18, 18, 17, 17, 17, 17, 17, + 17, 16, 16, 16, 16, 16, 16, 15, + 15, 15, 15, 15, 15, 14, 14, 14, + 14, 14, 14, 13, 13, 13, 13, 13, + 13, 12, 12, 12, 12, 12, 12, 11, + 11, 11, 11, 11, 11, 10, 10, 10, + 10, 10, 10, 9, 9, 9, 9, 9, + 9, 8, 8, 8, 8, 8, 8, 7, + 7, 7, 7, 7, 7, 6, 6, 6, + 6, 6, 6, 5, 5, 5, 5, 5, + 5, 5, 4, 4, 4, 5, 5, 5, + 5, 5, 5, 5, 6, 6, 6, 6, + 6, 6, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 10, 10, 10, 10, + 10, 10, 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 12, 13, 13, + 13, 13, 13, 13, 14, 14, 14, 14, + 14, 14, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 17, 17, + 17, 17, 17, 17, 18, 18, 18, 18, + 18, 18, 19, 19, 19, 19, 19, 19, + 20, 20, 20, 20, 20, 20, 21, 21, + 21, 21, 21, 21, 22, 22, 22, 22, + 22, 22, 23, 23, 23, 23, 23, 23, + 24, 24, 24, 24, 24, 24, 21, +}; + +/* Huffman code for encoding scheme 5, zero's code is index 123 */ +static uint32 code5[247] = { +0x1fffff,0xfffffd,0xfffffe,0xfffffa,0xff7ffa,0xfffffc,0xfffff8,0x5ffffd, +0x3ffffd,0x7fbffe,0x3f7ffa,0x5ffffc,0x3ffffc,0x37ffff,0x3fdffd,0x1fbffe, +0x1f7ffa,0x2ffffc,0x2ffff8,0x1ffff8,0x0ffffd,0x0fbffe,0x0ffffa,0x17fffc, +0x17fff8,0x0bffff,0x07fffd,0x07bffe,0x077ffa,0x0bfffc,0x0bfff8,0x05ffff, +0x03fffd,0x03fffe,0x037ffa,0x05fffc,0x05fff8,0x02ffff,0x01dffd,0x01fffe, +0x017ffa,0x02fffc,0x02fff8,0x017fff,0x00fffd,0x00fffe,0x007ffa,0x017ffc, +0x017ff8,0x00bfff,0x005ffd,0x003ffe,0x00bffa,0x00bffc,0x00bff8,0x005fff, +0x001ffd,0x005ffe,0x005ffa,0x005ffc,0x005ff8,0x002fff,0x002ffd,0x002ffe, +0x002ffa,0x002ffc,0x002ff8,0x0017ff,0x0017fd,0x0017fe,0x0017fa,0x0017fc, +0x0017f8,0x000bff,0x000bfd,0x000bfe,0x000bfa,0x000bfc,0x000bf8,0x0005ff, +0x0005fd,0x0005fe,0x0005fa,0x0005fc,0x0005f8,0x0002ff,0x0002fd,0x0002fe, +0x0002fa,0x0002fc,0x0002f8,0x00017f,0x00017d,0x00017e,0x00017a,0x00017c, +0x000178,0x0000bf,0x0000bd,0x0000be,0x0000ba,0x0000bc,0x0000b8,0x00005f, +0x00005d,0x00005e,0x00005a,0x00005c,0x000058,0x00002f,0x00002d,0x00002e, +0x00002a,0x00002c,0x000028,0x000017,0x000015,0x000019,0x000016,0x000012, +0x000014,0x000010,0x00000b,0x000001,0x000003,0x000000,0x000004,0x000002, +0x000006,0x000009,0x000005,0x000007,0x000008,0x00000c,0x00000a,0x00000e, +0x00000d,0x00000f,0x000018,0x00001c,0x00001a,0x00001e,0x00001d,0x00001f, +0x000038,0x00003c,0x00003a,0x00003e,0x00003d,0x00003f,0x000078,0x00007c, +0x00007a,0x00007e,0x00007d,0x00007f,0x0000f8,0x0000fc,0x0000fa,0x0000fe, +0x0000fd,0x0000ff,0x0001f8,0x0001fc,0x0001fa,0x0001fe,0x0001fd,0x0001ff, +0x0003f8,0x0003fc,0x0003fa,0x0003fe,0x0003fd,0x0003ff,0x0007f8,0x0007fc, +0x0007fa,0x0007fe,0x0007fd,0x0007ff,0x000ff8,0x000ffc,0x000ffa,0x000ffe, +0x000ffd,0x000fff,0x001ff8,0x001ffc,0x001ffa,0x001ffe,0x003ffd,0x001fff, +0x003ff8,0x003ffc,0x003ffa,0x007ffe,0x007ffd,0x003fff,0x007ff8,0x007ffc, +0x00fffa,0x00bffe,0x00dffd,0x007fff,0x00fff8,0x00fffc,0x01fffa,0x01bffe, +0x01fffd,0x00ffff,0x01fff8,0x01fffc,0x03fffa,0x03bffe,0x03dffd,0x01ffff, +0x03fff8,0x03fffc,0x07fffa,0x07fffe,0x07dffd,0x03ffff,0x07fff8,0x07fffc, +0x0f7ffa,0x0ffffe,0x0fdffd,0x07ffff,0x0ffff8,0x0ffffc,0x1ffffa,0x1ffffe, +0x1fdffd,0x17ffff,0x3ffff8,0x1ffffc,0x3ffffa,0x3fbffe,0x3ffffe,0x1ffffd, +0x7ffff8,0x7ffffc,0x7f7ffa,0x7ffffa,0x7ffffe,0x7ffffd,0x0fffff, +}; + +/* Number of valid bits (LSBs) in each entry in "code6" */ +static uint8 num6[395] = { + 21, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, + 23, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 21, +}; + +/* Huffman code for encoding scheme 6, zero's code is index 197 */ +static uint32 code6[395] = { +0x1fffff,0xfffffe,0xfffffc,0xfffff8,0xffbff8,0xfffffd,0xfffff9,0xfffffb, +0xfffff3,0xfffff7,0x7ffffa,0x5ffffe,0x3ffffc,0x7fdffc,0x3ffff8,0x5ffffd, +0x3ffffd,0x6ffffb,0x3ffffb,0x5ffff7,0x1ffffa,0x3feffa,0x3fdffe,0x1fdffc, +0x1ffff8,0x2ffffd,0x2ffff9,0x0ffffb,0x1ffffb,0x37ffff,0x3fdff7,0x0feffa, +0x0fdffe,0x0fdffc,0x0ffff8,0x17fffd,0x17fff9,0x17fffb,0x17fff3,0x0ffff3, +0x0ffff7,0x07effa,0x07fffe,0x07fffc,0x07bff8,0x0bfffd,0x0bfff9,0x0bfffb, +0x0bfff3,0x0bffff,0x07dff7,0x03effa,0x03dffe,0x03fffc,0x03bff8,0x05fffd, +0x05fff9,0x05fffb,0x05fff3,0x05ffff,0x03fff7,0x01effa,0x01dffe,0x01fffc, +0x01bff8,0x02fffd,0x02fff9,0x02fffb,0x02fff3,0x02ffff,0x01dff7,0x00fffa, +0x00fffe,0x00dffc,0x00bff8,0x017ffd,0x017ff9,0x017ffb,0x017ff3,0x017fff, +0x00fff7,0x006ffa,0x007ffe,0x007ffc,0x003ff8,0x00bffd,0x00bff9,0x00bffb, +0x00bff3,0x00bfff,0x005ff7,0x003ffa,0x001ffe,0x003ffc,0x005ff8,0x005ffd, +0x005ff9,0x005ffb,0x005ff3,0x005fff,0x001ff7,0x001ffa,0x002ffe,0x002ffc, +0x002ff8,0x002ffd,0x002ff9,0x002ffb,0x002ff3,0x002fff,0x002ff7,0x0017fa, +0x0017fe,0x0017fc,0x0017f8,0x0017fd,0x0017f9,0x0017fb,0x0017f3,0x0017ff, +0x0017f7,0x000bfa,0x000bfe,0x000bfc,0x000bf8,0x000bfd,0x000bf9,0x000bfb, +0x000bf3,0x000bff,0x000bf7,0x0005fa,0x0005fe,0x0005fc,0x0005f8,0x0005fd, +0x0005f9,0x0005fb,0x0005f3,0x0005ff,0x0005f7,0x0002fa,0x0002fe,0x0002fc, +0x0002f8,0x0002fd,0x0002f9,0x0002fb,0x0002f3,0x0002ff,0x0002f7,0x00017a, +0x00017e,0x00017c,0x000178,0x00017d,0x000179,0x00017b,0x000173,0x00017f, +0x000177,0x0000ba,0x0000be,0x0000bc,0x0000b8,0x0000bd,0x0000b9,0x0000bb, +0x0000b3,0x0000bf,0x0000b7,0x00005a,0x00005e,0x00005c,0x000058,0x00005d, +0x000059,0x00005b,0x000053,0x00005f,0x000057,0x00002a,0x00002e,0x00002c, +0x000028,0x00002d,0x000029,0x000031,0x00002b,0x000023,0x00002f,0x000027, +0x000012,0x000016,0x000014,0x000010,0x000015,0x000001,0x000005,0x000000, +0x000004,0x000006,0x000002,0x000007,0x00000f,0x000003,0x00000b,0x000011, +0x000009,0x00000d,0x000008,0x00000c,0x00000e,0x00000a,0x000017,0x00001f, +0x000013,0x00001b,0x000019,0x00001d,0x000018,0x00001c,0x00001e,0x00001a, +0x000037,0x00003f,0x000033,0x00003b,0x000039,0x00003d,0x000038,0x00003c, +0x00003e,0x00003a,0x000077,0x00007f,0x000073,0x00007b,0x000079,0x00007d, +0x000078,0x00007c,0x00007e,0x00007a,0x0000f7,0x0000ff,0x0000f3,0x0000fb, +0x0000f9,0x0000fd,0x0000f8,0x0000fc,0x0000fe,0x0000fa,0x0001f7,0x0001ff, +0x0001f3,0x0001fb,0x0001f9,0x0001fd,0x0001f8,0x0001fc,0x0001fe,0x0001fa, +0x0003f7,0x0003ff,0x0003f3,0x0003fb,0x0003f9,0x0003fd,0x0003f8,0x0003fc, +0x0003fe,0x0003fa,0x0007f7,0x0007ff,0x0007f3,0x0007fb,0x0007f9,0x0007fd, +0x0007f8,0x0007fc,0x0007fe,0x0007fa,0x000ff7,0x000fff,0x000ff3,0x000ffb, +0x000ff9,0x000ffd,0x000ff8,0x000ffc,0x000ffe,0x000ffa,0x003ff7,0x001fff, +0x001ff3,0x001ffb,0x001ff9,0x001ffd,0x001ff8,0x001ffc,0x003ffe,0x002ffa, +0x007ff7,0x003fff,0x003ff3,0x003ffb,0x003ff9,0x003ffd,0x007ff8,0x005ffc, +0x005ffe,0x007ffa,0x00dff7,0x007fff,0x007ff3,0x007ffb,0x007ff9,0x007ffd, +0x00fff8,0x00fffc,0x00dffe,0x00effa,0x01fff7,0x00ffff,0x00fff3,0x00fffb, +0x00fff9,0x00fffd,0x01fff8,0x01dffc,0x01fffe,0x01fffa,0x03dff7,0x01ffff, +0x01fff3,0x01fffb,0x01fff9,0x01fffd,0x03fff8,0x03dffc,0x03fffe,0x03fffa, +0x07fff7,0x03ffff,0x03fff3,0x03fffb,0x03fff9,0x03fffd,0x07fff8,0x07dffc, +0x07dffe,0x07fffa,0x0fdff7,0x07ffff,0x07fff3,0x07fffb,0x07fff9,0x07fffd, +0x0fbff8,0x0ffffc,0x0ffffe,0x0ffffa,0x1fdff7,0x17ffff,0x1ffff3,0x1ffff9, +0x0ffff9,0x0ffffd,0x1fbff8,0x1ffffc,0x1fdffe,0x1feffa,0x3ffff7,0x1ffff7, +0x3ffff3,0x2ffffb,0x3ffff9,0x1ffffd,0x3fbff8,0x3fdffc,0x3ffffe,0x1ffffe, +0x3ffffa,0x7ffff7,0x7ffff3,0x7ffffb,0x7ffff9,0x7ffffd,0x7fbff8,0x7ffff8, +0x7ffffc,0x7ffffe,0x0fffff, +}; + +/* Number of valid bits (LSBs) in each entry in "code7" */ +static uint8 num7[609] = { + 20, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, + 24, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, + 23, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, + 22, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, + 20, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, + 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, + 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, + 20, +}; + +/* Huffman code for encoding scheme 7, zero's code is index 304 */ +static uint32 code7[609] = { +0x0fffff,0xfffffd,0xeffffd,0xfffff5,0xfffff9,0xfffff1,0xfffffb,0xfffff3, +0xfffff7,0xfdffff,0xedffff,0xfffffe,0xfffffa,0xfffffc,0xf7fffc,0xfffff8, +0xfffff0,0x2ffffd,0x77fff5,0x3ffff9,0x5ffff9,0x3ffffb,0x7bfffb,0x3ffff7, +0x5ffff7,0x2dffff,0x7bfffe,0x3ffffe,0x5ffffa,0x3ffffc,0x7ffff4,0x3ffff0, +0x5ffff0,0x0ffffd,0x1ffff5,0x37fff9,0x3bfff1,0x1ffffb,0x1bfffb,0x2ffff3, +0x2ffff7,0x1dffff,0x1bfffe,0x3bfffa,0x3ffff2,0x1ffffc,0x1ffff8,0x2ffff8, +0x2ffff0,0x17fffd,0x0ffff5,0x0ffff9,0x0bfff1,0x0bfffb,0x1bfff3,0x1bfff7, +0x1bffff,0x1ffff6,0x0ffffe,0x0ffffa,0x0ffff2,0x0ffff4,0x17fff4,0x17fff8, +0x17fff0,0x0bfffd,0x0bfff5,0x0bfff9,0x07fff1,0x07fffb,0x07fff3,0x03fff7, +0x03ffff,0x03fffe,0x07fffe,0x07fffa,0x0bfff2,0x0bfffc,0x0bfff4,0x0bfff8, +0x0bfff0,0x05fffd,0x05fff5,0x05fff9,0x05fff1,0x05fffb,0x05fff3,0x05fff7, +0x01ffff,0x05fff6,0x05fffe,0x05fffa,0x05fff2,0x05fffc,0x05fff4,0x05fff8, +0x05fff0,0x02fffd,0x02fff5,0x02fff9,0x02fff1,0x02fffb,0x02fff3,0x02fff7, +0x02ffff,0x02fff6,0x02fffe,0x02fffa,0x02fff2,0x02fffc,0x02fff4,0x02fff8, +0x02fff0,0x017ffd,0x017ff5,0x017ff9,0x017ff1,0x017ffb,0x017ff3,0x017ff7, +0x017fff,0x017ff6,0x017ffe,0x017ffa,0x017ff2,0x017ffc,0x017ff4,0x017ff8, +0x017ff0,0x00bffd,0x00bff5,0x00bff9,0x00bff1,0x00bffb,0x00bff3,0x00bff7, +0x00bfff,0x00bff6,0x00bffe,0x00bffa,0x00bff2,0x00bffc,0x00bff4,0x00bff8, +0x00bff0,0x005ffd,0x005ff5,0x005ff9,0x005ff1,0x005ffb,0x005ff3,0x005ff7, +0x005fff,0x005ff6,0x005ffe,0x005ffa,0x005ff2,0x005ffc,0x005ff4,0x005ff8, +0x005ff0,0x002ffd,0x002ff5,0x002ff9,0x002ff1,0x002ffb,0x002ff3,0x002ff7, +0x002fff,0x002ff6,0x002ffe,0x002ffa,0x002ff2,0x002ffc,0x002ff4,0x002ff8, +0x002ff0,0x0017fd,0x0017f5,0x0017f9,0x0017f1,0x0017fb,0x0017f3,0x0017f7, +0x0017ff,0x0017f6,0x0017fe,0x0017fa,0x0017f2,0x0017fc,0x0017f4,0x0017f8, +0x0017f0,0x000bfd,0x000bf5,0x000bf9,0x000bf1,0x000bfb,0x000bf3,0x000bf7, +0x000bff,0x000bf6,0x000bfe,0x000bfa,0x000bf2,0x000bfc,0x000bf4,0x000bf8, +0x000bf0,0x0005fd,0x0005f5,0x0005f9,0x0005f1,0x0005fb,0x0005f3,0x0005f7, +0x0005ff,0x0005f6,0x0005fe,0x0005fa,0x0005f2,0x0005fc,0x0005f4,0x0005f8, +0x0005f0,0x0002fd,0x0002f5,0x0002f9,0x0002f1,0x0002fb,0x0002f3,0x0002f7, +0x0002ff,0x0002f6,0x0002fe,0x0002fa,0x0002f2,0x0002fc,0x0002f4,0x0002f8, +0x0002f0,0x00017d,0x000175,0x000179,0x000171,0x00017b,0x000173,0x000177, +0x00017f,0x000176,0x00017e,0x00017a,0x000172,0x00017c,0x000174,0x000178, +0x000170,0x0000bd,0x0000b5,0x0000b9,0x0000b1,0x0000bb,0x0000b3,0x0000b7, +0x0000bf,0x0000b6,0x0000be,0x0000ba,0x0000b2,0x0000bc,0x0000b4,0x0000b8, +0x0000b0,0x00005d,0x000055,0x000059,0x000051,0x00005b,0x000053,0x000057, +0x00005f,0x000056,0x00005e,0x00005a,0x000052,0x00005c,0x000054,0x000058, +0x00002d,0x000025,0x000029,0x000021,0x00002b,0x000023,0x000027,0x00002f, +0x000026,0x00002e,0x00002a,0x000022,0x00002c,0x000024,0x000028,0x000020, +0x000010,0x000000,0x000008,0x000004,0x00000c,0x000002,0x00000a,0x00000e, +0x000006,0x00000f,0x000007,0x000003,0x00000b,0x000001,0x000009,0x000005, +0x00000d,0x000018,0x000014,0x00001c,0x000012,0x00001a,0x00001e,0x000016, +0x00001f,0x000017,0x000013,0x00001b,0x000011,0x000019,0x000015,0x00001d, +0x000030,0x000038,0x000034,0x00003c,0x000032,0x00003a,0x00003e,0x000036, +0x00003f,0x000037,0x000033,0x00003b,0x000031,0x000039,0x000035,0x00003d, +0x000070,0x000078,0x000074,0x00007c,0x000072,0x00007a,0x00007e,0x000076, +0x00007f,0x000077,0x000073,0x00007b,0x000071,0x000079,0x000075,0x00007d, +0x0000f0,0x0000f8,0x0000f4,0x0000fc,0x0000f2,0x0000fa,0x0000fe,0x0000f6, +0x0000ff,0x0000f7,0x0000f3,0x0000fb,0x0000f1,0x0000f9,0x0000f5,0x0000fd, +0x0001f0,0x0001f8,0x0001f4,0x0001fc,0x0001f2,0x0001fa,0x0001fe,0x0001f6, +0x0001ff,0x0001f7,0x0001f3,0x0001fb,0x0001f1,0x0001f9,0x0001f5,0x0001fd, +0x0003f0,0x0003f8,0x0003f4,0x0003fc,0x0003f2,0x0003fa,0x0003fe,0x0003f6, +0x0003ff,0x0003f7,0x0003f3,0x0003fb,0x0003f1,0x0003f9,0x0003f5,0x0003fd, +0x0007f0,0x0007f8,0x0007f4,0x0007fc,0x0007f2,0x0007fa,0x0007fe,0x0007f6, +0x0007ff,0x0007f7,0x0007f3,0x0007fb,0x0007f1,0x0007f9,0x0007f5,0x0007fd, +0x000ff0,0x000ff8,0x000ff4,0x000ffc,0x000ff2,0x000ffa,0x000ffe,0x000ff6, +0x000fff,0x000ff7,0x000ff3,0x000ffb,0x000ff1,0x000ff9,0x000ff5,0x000ffd, +0x001ff0,0x001ff8,0x001ff4,0x001ffc,0x001ff2,0x001ffa,0x001ffe,0x001ff6, +0x001fff,0x001ff7,0x001ff3,0x001ffb,0x001ff1,0x001ff9,0x001ff5,0x001ffd, +0x003ff0,0x003ff8,0x003ff4,0x003ffc,0x003ff2,0x003ffa,0x003ffe,0x003ff6, +0x003fff,0x003ff7,0x003ff3,0x003ffb,0x003ff1,0x003ff9,0x003ff5,0x003ffd, +0x007ff0,0x007ff8,0x007ff4,0x007ffc,0x007ff2,0x007ffa,0x007ffe,0x007ff6, +0x007fff,0x007ff7,0x007ff3,0x007ffb,0x007ff1,0x007ff9,0x007ff5,0x007ffd, +0x00fff0,0x00fff8,0x00fff4,0x00fffc,0x00fff2,0x00fffa,0x00fffe,0x00fff6, +0x00ffff,0x00fff7,0x00fff3,0x00fffb,0x00fff1,0x00fff9,0x00fff5,0x00fffd, +0x01fff0,0x01fff8,0x01fff4,0x01fffc,0x01fff2,0x01fffa,0x01fffe,0x01fff6, +0x03fff6,0x01fff7,0x01fff3,0x01fffb,0x01fff1,0x01fff9,0x01fff5,0x01fffd, +0x03fff0,0x03fff8,0x03fff4,0x03fffc,0x03fff2,0x07fff2,0x03fffa,0x07fff6, +0x05ffff,0x07fff7,0x03fff3,0x03fffb,0x03fff1,0x03fff9,0x03fff5,0x03fffd, +0x07fff0,0x07fff8,0x07fff4,0x07fffc,0x0ffffc,0x0bfffa,0x0bfffe,0x0ffff6, +0x0bffff,0x0bfff7,0x0bfff3,0x0ffffb,0x0ffff1,0x07fff9,0x07fff5,0x07fffd, +0x0ffff0,0x0ffff8,0x1ffff4,0x17fffc,0x1ffff2,0x1bfffa,0x1ffffe,0x0dffff, +0x0ffff7,0x0ffff3,0x1ffff3,0x1ffff1,0x1bfff1,0x17fff9,0x17fff5,0x1ffffd, +0x1ffff0,0x3ffff8,0x3ffff4,0x37fffc,0x1ffffa,0x3ffffa,0x3bfffe,0x3dffff, +0x1ffff7,0x3ffff3,0x3bfffb,0x3ffff1,0x1ffff9,0x3ffff5,0x37fff5,0x3ffffd, +0x7ffff0,0x7ffff8,0x77fffc,0x7ffffc,0x7ffffa,0x7ffffe,0x6dffff,0x7dffff, +0x7ffff7,0x7ffff3,0x7ffffb,0x7ffff1,0x7ffff9,0x7ffff5,0x6ffffd,0x7ffffd, +0x07ffff, +}; + +/* Size of each Huffman encoding scheme */ +static uint16 sizes[8] = { + 25, 47, 69, 109, 169, 247, 395, 609, +}; + +/* Array of bit count array pointers for each encoding scheme */ +static uint8 *counts[8] = { + num0, num1, num2, num3, num4, num5, num6, num7, +}; + +/* Array of Huffman code array pointers for each encoding scheme */ +static uint32 *encodings[8] = { + code0, code1, code2, code3, code4, code5, code6, code7, +}; + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/findsync.c b/isis/src/mgs/apps/mocuncompress/findsync.c new file mode 100644 index 0000000000000000000000000000000000000000..0f7212c989b3bc6c11f105ba90f3c74e9e928d2c --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/findsync.c @@ -0,0 +1,79 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)findsync.c 1.1 10/04/99"; +#include "fs.h" + +static int maxdelta = 64; + +static int delta_ok(p) +uint8 *p; +{ + int i, delta, md = 0; + + for(i = 1; i < 32; i++) { + delta = p[i]-p[i+1]; + if(delta < 0) delta = -delta; + if(delta > md) md = delta; + } + return md <= maxdelta; +} + +/* locate the first sync line following the location pointed to by p. + Note that a valid sync line must start with the 16-bit sync pattern + and that the uncompressed pixels following must pass a test based + on the maximum delta value pixel-to-pixel, which is forced to be <= + maxdelta. */ +uint8 *findsync(p, len, sync) +uint8 *p; +int len; +uint16 sync; +{ + uint16 s; + + p += 2; /* skip the previous sync value and search forward for the next */ + len -= 2; + while(len--) { + s = *p|(*(p+1)<<8); + if(s == sync && delta_ok(p+2)) { + return p; + } + else p += 1; + } + return 0; +} diff --git a/isis/src/mgs/apps/mocuncompress/fs.h b/isis/src/mgs/apps/mocuncompress/fs.h new file mode 100644 index 0000000000000000000000000000000000000000..37ea86b1dae901abdf2e9f7a38cb32633eaa1d23 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/fs.h @@ -0,0 +1,79 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)fs.h 1.1 10/04/99 +*/ +/* SCCShid @(#)fs.h (fs.h) 1.1 */ + +/* +* DESCRIPTION +* +* Typedefs for commonly used signed and unsigned integers of +* different length (in bits). +* +* COMMENTARY +* +* It is intended that these definitions refer to integers of +* the exact length specified and can be used as primitives in +* such things as arithmetic operations. +*/ + +#if !defined(fs_h) + +#define fs_h + +/* Unsigned integers of lengths 32, 16, and 8 bits, respectively */ + +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +/* An unsigned integer of unspecified length */ +/* The '#ifndef _TYPES_' is to avoid clash with */ + +#if !defined(_TYPES_) && !defined(_SYS_BSD_TYPES_H) +typedef unsigned int UINT; +#endif + +/* Signed integers of lengths 32, 16, and 8 bits, respectively */ + +typedef int int32; +typedef short int16; +typedef char int8; + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/getdecode.c b/isis/src/mgs/apps/mocuncompress/getdecode.c new file mode 100644 index 0000000000000000000000000000000000000000..44ab005c4513959ce1f6c4451d17052c3f7916b3 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/getdecode.c @@ -0,0 +1,257 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)getdecode.c 1.1 10/04/99"; + +/* + Huffman code tree module + Mike Caplinger, MOC GDS Design Scientist + SCCS @(#)getdecode.c 1.1 11/19/91 + + This module manages the Ligocki-style Huffman decoding trees for + the predictive decompressor. It is a little roundabout in that + it builds a Huffman code tree in node form from the flight software + encoding tables and then "tablefies" it; that way, separate decoding + tables don't have to be maintained. One can also just load an + existing decode file in (for testing.) + + This will probably all go away if the clean canonical decompressor + is ever written. +*/ + +#include +#include + +#include "fs.h" + +#define DEFINE_CODE_TABLES +#include "fs.h" +#include "predcode.h" + +typedef struct ht_node { + int value; + struct ht_node *zero, *one; +} Huffman_node; + +/* in TJL terminology, left is 0 and right is 1. */ +extern uint8 code[], left[], right[]; + +decodeLoad(decodefile) +char *decodefile; +{ + int decodeSize; + FILE *fd; + + if ((fd = fopen(decodefile,"r")) == NULL) { + (void)fprintf(stderr,"Unable to open '%s' for reading\n", + decodefile); + exit(1); + } + + if (fread((char *)(&decodeSize),sizeof(decodeSize),1,fd) != 1) { + fprintf(stderr,"Unable to read decode file, '%s'\n",decodefile); + exit(1); + } + + if (fread(code,sizeof(code[0]),decodeSize,fd) != decodeSize) { + fprintf(stderr,"Unable to read decode file, '%s'\n",decodefile); + exit(1); + } + + if (fread(left,sizeof(left[0]),decodeSize,fd) != decodeSize) { + fprintf(stderr,"Unable to read decode file, '%s'\n",decodefile); + exit(1); + } + + if (fread(right,sizeof(right[0]),decodeSize,fd) != decodeSize) { + fprintf(stderr,"Unable to read decode file, '%s'\n",decodefile); + exit(1); + } + + (void)fclose(fd); +} + +Huffman_node *ht_insert(root, value, code, len) +Huffman_node *root; +int value, code, len; +{ + int bit; + Huffman_node **branch; + + if(!root) { + root = (Huffman_node *) malloc(sizeof(Huffman_node)); + root->value = 0; + root->zero = root->one = NULL; + } + + if(len == 0) { + root->value = value; + } + else { + bit = code&0x1; + if(bit == 0) branch = &root->zero; + else branch = &root->one; + + if(*branch == 0) { + *branch = (Huffman_node *) malloc(sizeof(Huffman_node)); + (*branch)->value = 0; + (*branch)->zero = 0; + (*branch)->one = 0; + } + ht_insert(*branch, value, code>>1, len-1); + } + return root; +} + +int ht_lookup(root, code, len) +Huffman_node *root; +int code, len; +{ + int bit; + + if(root->zero == 0 && root->one == 0) return root->value; + bit = code&1; + if(bit == 0) return ht_lookup(root->zero, code>>1, len-1); + else return ht_lookup(root->one, code>>1, len-1); +} + +ht_dump(root, code, len) +Huffman_node *root; +int code, len; +{ + if(root->zero == 0 && root->one == 0) { + printf("%d %x(%d)\n", root->value, code, len); + } + else { + if(root->zero) { + ht_dump(root->zero, code, len+1); + } + if(root->one) { + ht_dump(root->one, code|(1<zero) { + if(root->zero->zero == 0 && root->zero->one == 0) { + flags[index] &= ~ZERO; + zero[index] = root->zero->value; + } + else { + i = ZERO; + flags[local_index] |= ZERO; + index += 1; + zero[local_index] = index; + index = ht_tablefy(root->zero, flags, zero, one, index); + } + } + if(root->one) { + if(root->one->zero == 0 && root->one->one == 0) { + flags[local_index] &= ~ONE; + one[local_index] = root->one->value; + } + else { + flags[local_index] |= ONE; + index += 1; + one[local_index] = index; + index = ht_tablefy(root->one, flags, zero, one, index); + } + } + return index; +} + +Huffman_node *ht_tree_gen(i) +int i; +{ + Huffman_node *tree = 0; + uint16 *code; + uint8 *len; + uint8 *requant; + + code = CodeBitsVec[i]; + len = CodeLenVec[i]; + requant = CodeRequantVec[i]; + + tree = ht_insert(tree, requant[0], code[0], len[0]); + + for(i = 1; i < 128; i++) { + if(requant[i] != requant[i-1]) + tree = ht_insert(tree, requant[i], code[i], len[i]); + } + + tree = ht_insert(tree, requant[255], code[255], len[255]); + + for(i = 254; i >= 128; i--) { + if(requant[i] != requant[i+1]) + tree = ht_insert(tree, requant[i], code[i], len[i]); + } + return tree; +} + +ht_free(root) +Huffman_node *root; +{ + if(root->zero) ht_free(root->zero); + if(root->one) ht_free(root->one); + free(root); +} + +decodeInit(n) { + Huffman_node *tree = 0; + int i; + uint8 flags[256], zero[256], one[256]; + + tree = ht_tree_gen(n); + /* i is the # of slots actually used... */ + i = ht_tablefy(tree, code, left, right, 0) + 1; + ht_free(tree); +} diff --git a/isis/src/mgs/apps/mocuncompress/header.c b/isis/src/mgs/apps/mocuncompress/header.c new file mode 100644 index 0000000000000000000000000000000000000000..455d6ab751a751be46660590b8fd468132bc7d8f --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/header.c @@ -0,0 +1,135 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)header.c 1.2 10/06/99"; +#include +#include +#include +#include "image_io.h" +#include + +int prefix(s, pre) +char *s, *pre; +{ + return strncmp(s, pre, strlen(pre)) == 0; +} + +/* write the image header and return the file descriptor to the open file */ +/*int write_header(width, height, infile, outfname)*/ +FILE *write_header(width, height, infile, outfname) +FILE *infile; +char *outfname; +{ + static int out = -1; + int pos; + FILE *outf; + char line[256]; + int nrec; + int i, pad; + + if(out < 0) { + i = remove(outfname); + if (errno == 0 || errno == 2) out = 1; + else { + fprintf(stderr, "can't create %s\n", outfname); + exit(1); + } +/* if((out = creat(outfname, 0666)) < 0) { + fprintf(stderr, "can't create %s\n", outfname); + exit(1); + }*/ + outf = fopen(outfname, "w+"); + } +/* i = lseek(out, 0l, 0);*/ + outf = fopen(outfname, "r+"); +/* outf = fdopen(dup(out), "r+");*/ + + nrec = 2048/width+(2048%width?1:0); + + /* copy the PDS header with a few modifications */ + pos = ftell(infile); + i = fseek(infile, 0, 0); + while(fgets(line, sizeof(line), infile)) { + i = strlen(line); + if(prefix(line, "RECORD_BYTES")) { + i = fprintf(outf, "RECORD_BYTES = %d\r\n", width); + } + else if(prefix(line, "FILE_RECORDS")) { + i = fprintf(outf, "FILE_RECORDS = %d\r\n", height+nrec); + } + else if(prefix(line, "^IMAGE")) { + i = fprintf(outf, "^IMAGE = %d\r\n", nrec+1); + } + else if(prefix(line, "LABEL_RECORDS")) { + i = fprintf(outf, "LABEL_RECORDS = %d\r\n", nrec); + } + else if(prefix(line, "DATA_SET_ID")) { + i = fprintf(outf, "DATA_SET_ID = \"MGS-M-MOC-NA/WA-2-DSDP-L0-V1.0\"\r\n"); + } + else if(prefix(line, "ENCODING_TYPE")) { + ; /* skip this in output */ + } + else if(prefix(line, "FILE_NAME")) { + i = fprintf(outf, "FILE_NAME = \"%s\"\r\n", outfname); + } + else if(prefix(line, "LINES")) { + i = fprintf(outf, "LINES = %d\r\n", height); + } + else if(prefix(line, "END\r")) { + i = fputs(line, outf); + break; + } + else { +/* i = fputs(line, outf); */ + i = fprintf(outf, "%s", line); + } + } + pad = nrec*width-(i = ftell(outf)); + if(pad < 0) { + fprintf(stderr, "Error: header too large\n"); + exit(1); + } + + for(i = 0; i < pad; i++) fputc(' ', outf); + +/* fclose(outf);*/ + i = fseek(outf, nrec*width, 0); + i = fseek(infile, pos, 0); +/* return out;*/ + return outf; +} diff --git a/isis/src/mgs/apps/mocuncompress/image_io.c b/isis/src/mgs/apps/mocuncompress/image_io.c new file mode 100644 index 0000000000000000000000000000000000000000..3221fd74897b13945dbafdba4170569be6cf42fd --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/image_io.c @@ -0,0 +1,143 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)image_io.c 1.1 10/04/99"; + +#include +#include +#include +#include "image_io.h" + +image_change_header(header) +struct image_header *header; +{ + static int hdr_buf[IMAGE_HEADER_LENGTH / sizeof(int)]; + + hdr_buf[0] = MAGIC; + hdr_buf[1] = header->height; + hdr_buf[2] = header->width; + hdr_buf[3] = header->bpe; + sprintf((char *)hdr_buf+IMAGE_LABEL_OFFSET, "%s", header->label); + + /* write the new header */ + lseek(header->fd, 0L, 0); + if(write(header->fd, hdr_buf, IMAGE_HEADER_LENGTH) < IMAGE_HEADER_LENGTH) { + printf("image_change_header : unable to write new header\n"); + exit(1); + } +} + +image_open(filename, header, mode) +char *filename; +struct image_header *header; +char *mode; +{ + int len; + char buf[64]; + static int hdr_buf[IMAGE_HEADER_LENGTH / sizeof(int)]; + int fd; + char *text_ptr; + + /* check to see if the filename ends in ".ddd" */ + len = strlen(filename); + if( (len > 4) && (!strcmp(&(filename[len-4]), ".ddd")) ) { + strcpy(buf, filename); + } + else { + sprintf(buf, "%s.ddd", filename); + } + if(((*mode == 'r')&&(mode[1] != 'w')) || (*mode == 'u')) { + if(strcmp(buf, "-.ddd")) fd = open(buf, (*mode == 'r') ? 0 : 2); + else fd = 0; + if(fd < 0) { + printf("image_open : Unable to open %s\n", buf); + exit(1); + } + if(read(fd, hdr_buf, IMAGE_HEADER_LENGTH) < IMAGE_HEADER_LENGTH) { + printf("image_open : %s is not a valid image file\n", buf); + exit(1); + } + if((*hdr_buf) != MAGIC) { + printf("image_open : %s is not a valid image file\n", buf); + exit(1); + } + header->height = hdr_buf[1]; + header->width = hdr_buf[2]; + header->bpe = hdr_buf[3]; + if(header->bpe == 0) + header->bpe = 8; + text_ptr = (char *) malloc(strlen(((char *)hdr_buf)+IMAGE_LABEL_OFFSET)); + strcpy(text_ptr, (char *) (((char *)hdr_buf)+IMAGE_LABEL_OFFSET)); + header->label = text_ptr; + header->fd = fd; + } + else if((*mode == 'w') || (!strncmp(mode, "rw", 2))) { + if((header->width == 0) || (header->height == 0)) { + printf("image_open : Invalid size for image\n"); + exit(1); + } + fd = creat(buf, 0666); + if(fd < 0) { + printf("image_open : Unable to create %s\n", buf); + exit(1); + } + if(*mode != 'w') { + close(fd); + fd = open(buf, 2); + if(fd < 0) { + printf("image_open : Unable ot open %s\n", buf); + exit(1); + } + } + header->fd = fd; + hdr_buf[0] = MAGIC; + hdr_buf[1] = header->height; + hdr_buf[2] = header->width; + hdr_buf[3] = header->bpe; + sprintf((char *)hdr_buf+IMAGE_LABEL_OFFSET, "%s", header->label); + if(write(fd, hdr_buf, IMAGE_HEADER_LENGTH) < IMAGE_HEADER_LENGTH) { + printf("image_open : unable to write header for %s\n", buf); + exit(1); + } + } + else { + printf("image_open : Invalid mode (%s)\n", mode); + exit(1); + } +} + diff --git a/isis/src/mgs/apps/mocuncompress/image_io.h b/isis/src/mgs/apps/mocuncompress/image_io.h new file mode 100644 index 0000000000000000000000000000000000000000..3edea280275e589ae0f3953e4252556ef133e57f --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/image_io.h @@ -0,0 +1,50 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)image_io.h 1.1 10/04/99 +*/ + +struct image_header { + int height, width, bpe; + int fd; + char *label; +}; + +#define IMAGE_HEADER_LENGTH 1024 +#define IMAGE_LABEL_OFFSET 24 +#define MAGIC 1659 diff --git a/isis/src/mgs/apps/mocuncompress/initBlock.c b/isis/src/mgs/apps/mocuncompress/initBlock.c new file mode 100644 index 0000000000000000000000000000000000000000..4f190064d2eec3e91c81c2e704d536391fd2dcf5 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/initBlock.c @@ -0,0 +1,199 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)initBlock.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif +/* +* DESCRIPTION +* +* COMMENTARY +*/ + +#include +#include + +#include "fs.h" +#include "limits.h" +#include "encodeCoefs.static.h" + +#include "initBlock.h" + +extern void exit(); + +BITTREE *encodeTrees[MAXCODES]; + +static uint32 bitReverse(num) register uint32 num; { +register uint32 rev; +register uint32 i; + + rev = 0; + + for (i = 0; ; i++) { + if (num & 0x1) { + rev |= 0x1; + }; + + if (i == 31) { + break; + }; + + num >>= 1; + rev <<= 1; + }; + + return(rev); +} + +static int32 compare(e1,e2) BITTREE *e1,*e2; { +register uint32 c1,c2; + c1 = e1->code; + c2 = e2->code; + + if (c1 < c2) { + return(-1); + } else { + if (c1 > c2) { + return(1); + } else { + return(0); + }; + }; +} + +BITTREE *makeTree(start,size,bit) BITTREE *start; uint32 size; uint32 bit; { +BITTREE *cur; +uint32 count; +BITTREE *scan; + + if (size == 1) { + cur = start; + } else { + if ((cur = (BITTREE *)malloc(sizeof(*cur))) == NULL) { + (void)fprintf(stderr,"Not enough memory for huffman trees\n"); + exit(1); + }; + + for (count = 0, scan = start; count < size && (scan->code & bit) == 0; count++, scan++) { + }; + + cur->zero = makeTree(start,count,bit << 1); + cur->one = makeTree(start+count,size-count,bit << 1); + }; + + return(cur); +} + +void initBlock() { +uint32 which,n; +uint32 size; +uint8 *count; +uint32 *encoding; +BITTREE *curTree; + + for (which = 0; which < MAXCODES; which++) { + BITTREE *scanTree; + + size = sizes[which]; + count = counts[which]; + encoding = encodings[which]; + + if ((encodeTrees[which] = (BITTREE *)malloc((uint32)(size * sizeof(*encodeTrees[which])))) == NULL) { + (void)fprintf(stderr,"Not enough memory for huffman trees\n"); + exit(1); + }; + + curTree = encodeTrees[which]; + scanTree = curTree; + + for (n = 0; n < size; n++, scanTree++) { + if (n == 0) { + scanTree->value = LARGE_NEGATIVE; + } else { + if (n == size-1) { + scanTree->value = LARGE_POSITIVE; + } else { + scanTree->value = n - size/2; + }; + }; + scanTree->count = count[n]; + scanTree->code = bitReverse(encoding[n]); + scanTree->zero = NULL; + scanTree->one = NULL; + }; + + qsort((char *)curTree,(int32)size,sizeof(*curTree),compare); + + scanTree = curTree; + + for (n = 0; n < size; n++, scanTree++) { + scanTree->code = bitReverse(scanTree->code); + }; + + encodeTrees[which] = makeTree(curTree,size,0x1); + }; +} + +freeTree(p) +BITTREE *p; +{ + if(p->zero) freeTree(p->zero); + if(p->one) freeTree(p->one); + free(p); +} + +dumpTree(p, top) +BITTREE *p; +{ + if(top) printf("dumping root "); + if(p->zero) dumpTree(p->zero, 0); + if(p->one) dumpTree(p->one, 0); + //printf("%#x(%#x,%#x)", p, p->zero, p->one); + if(top) putchar('\n'); +} + +freeAllTrees() { + int i; + + for(i = 0; i < MAXCODES; i++) { + if(0 && encodeTrees[i]) freeTree(encodeTrees[i]); + if(encodeTrees[i]) free(encodeTrees[i]); + } +} + +/* seems like maybe the standard Solaris malloc has a bug in it, since this crashes in freeTree, not dumpTree, indicating corruption during the freeing process. Actually, looking at the code maybe it's just our bug, since it looks like we free stuff that was never allocated. */ diff --git a/isis/src/mgs/apps/mocuncompress/initBlock.h b/isis/src/mgs/apps/mocuncompress/initBlock.h new file mode 100644 index 0000000000000000000000000000000000000000..6322afb65ac59fc107b36802ef370b9724e7412b --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/initBlock.h @@ -0,0 +1,63 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)initBlock.h 1.1 10/04/99 +*/ +/* SCCShid @(#)initBlock.h (initBlock.h) 1.2 */ + +#if !defined(initBlock_h) + +#define initBlock_h + +#define LARGE_NEGATIVE 0x1000000 +#define LARGE_POSITIVE 0x2000000 + +typedef struct bittree BITTREE; + +struct bittree { + int32 value; + uint8 count; + uint32 code; + BITTREE *zero,*one; +}; + +extern BITTREE *encodeTrees[]; + +extern void initBlock(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/invFdct16x16.c b/isis/src/mgs/apps/mocuncompress/invFdct16x16.c new file mode 100644 index 0000000000000000000000000000000000000000..c4f995c91f69bebbff8967122f5c290dfff2eab5 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/invFdct16x16.c @@ -0,0 +1,267 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)invFdct16x16.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif +/* +* DESCRIPTION +* +* COMMENTARY +*/ + +#include "fs.h" + +#include "invFdct16x16.h" + +#define MULTDOUBLE(r,v,c) (r) = (v) * (c); + +static double cosineDouble[16] = { + 1.00000000000000000000e+00, + 9.95184726672196890000e-01, + 9.80785280403230440000e-01, + 9.56940335732208870000e-01, + 9.23879532511286750000e-01, + 8.81921264348355040000e-01, + 8.31469612302545240000e-01, + 7.73010453362736970000e-01, + 7.07106781186547530000e-01, + 6.34393284163645500000e-01, + 5.55570233019602220000e-01, + 4.71396736825997660000e-01, + 3.82683432365089760000e-01, + 2.90284677254462360000e-01, + 1.95090322016128270000e-01, + 9.80171403295606040000e-02, +}; + +static void DCTinv16Double(in,out) double *in,*out; { +double tmp[16]; +register double tmp1,tmp2; + + tmp[0] = in[0]; + tmp[1] = in[8]; + tmp[2] = in[4]; + tmp[3] = in[12]; + tmp[4] = in[2]; + tmp[5] = in[10]; + tmp[6] = in[6]; + tmp[7] = in[14]; + MULTDOUBLE(tmp1,in[1],cosineDouble[15]); MULTDOUBLE(tmp2,in[15],cosineDouble[1]); + tmp[8] = tmp1 - tmp2; + MULTDOUBLE(tmp1,in[9],cosineDouble[7]); MULTDOUBLE(tmp2,in[7],cosineDouble[9]); + tmp[9] = tmp1 - tmp2; + MULTDOUBLE(tmp1,in[5],cosineDouble[11]); MULTDOUBLE(tmp2,in[11],cosineDouble[5]); + tmp[10] = tmp1 - tmp2; + MULTDOUBLE(tmp1,in[13],cosineDouble[3]); MULTDOUBLE(tmp2,in[3],cosineDouble[13]); + tmp[11] = tmp1 - tmp2; + MULTDOUBLE(tmp1,in[3],cosineDouble[3]); MULTDOUBLE(tmp2,in[13],cosineDouble[13]); + tmp[12] = tmp1 + tmp2; + MULTDOUBLE(tmp1,in[11],cosineDouble[11]); MULTDOUBLE(tmp2,in[5],cosineDouble[5]); + tmp[13] = tmp1 + tmp2; + MULTDOUBLE(tmp1,in[7],cosineDouble[7]); MULTDOUBLE(tmp2,in[9],cosineDouble[9]); + tmp[14] = tmp1 + tmp2; + MULTDOUBLE(tmp1,in[15],cosineDouble[15]); MULTDOUBLE(tmp2,in[1],cosineDouble[1]); + tmp[15] = tmp1 + tmp2; + + out[0] = tmp[0]; + out[1] = tmp[1]; + out[2] = tmp[2]; + out[3] = tmp[3]; + MULTDOUBLE(tmp1,tmp[4],cosineDouble[14]); MULTDOUBLE(tmp2,tmp[7],cosineDouble[2]); + out[4] = tmp1 - tmp2; + MULTDOUBLE(tmp1,tmp[5],cosineDouble[6]); MULTDOUBLE(tmp2,tmp[6],cosineDouble[10]); + out[5] = tmp1 - tmp2; + MULTDOUBLE(tmp1,tmp[6],cosineDouble[6]); MULTDOUBLE(tmp2,tmp[5],cosineDouble[10]); + out[6] = tmp1 + tmp2; + MULTDOUBLE(tmp1,tmp[7],cosineDouble[14]); MULTDOUBLE(tmp2,tmp[4],cosineDouble[2]); + out[7] = tmp1 + tmp2; + out[8] = tmp[8] + tmp[9]; + out[9] = -tmp[9] + tmp[8]; + out[10] = -tmp[10] + tmp[11]; + out[11] = tmp[11] + tmp[10]; + out[12] = tmp[12] + tmp[13]; + out[13] = -tmp[13] + tmp[12]; + out[14] = -tmp[14] + tmp[15]; + out[15] = tmp[15] + tmp[14]; + + tmp1 = out[0] + out[1]; + MULTDOUBLE(tmp[0],tmp1,cosineDouble[8]); + tmp1 = -out[1] + out[0]; + MULTDOUBLE(tmp[1],tmp1,cosineDouble[8]); + MULTDOUBLE(tmp1,out[2],cosineDouble[12]); MULTDOUBLE(tmp2,out[3],cosineDouble[4]); + tmp[2] = tmp1 - tmp2; + MULTDOUBLE(tmp1,out[3],cosineDouble[12]); MULTDOUBLE(tmp2,out[2],cosineDouble[4]); + tmp[3] = tmp1 + tmp2; + tmp[4] = out[4] + out[5]; + tmp[5] = -out[5] + out[4]; + tmp[6] = -out[6] + out[7]; + tmp[7] = out[7] + out[6]; + tmp[8] = out[8]; + MULTDOUBLE(tmp1,out[9],cosineDouble[4]); MULTDOUBLE(tmp2,out[14],cosineDouble[12]); + tmp[9] = -tmp1 + tmp2; + MULTDOUBLE(tmp1,out[10],cosineDouble[12]); MULTDOUBLE(tmp2,out[13],cosineDouble[4]); + tmp[10] = -tmp1 - tmp2; + tmp[11] = out[11]; + tmp[12] = out[12]; + MULTDOUBLE(tmp1,out[13],cosineDouble[12]); MULTDOUBLE(tmp2,out[10],cosineDouble[4]); + tmp[13] = tmp1 - tmp2; + MULTDOUBLE(tmp1,out[14],cosineDouble[4]); MULTDOUBLE(tmp2,out[9],cosineDouble[12]); + tmp[14] = tmp1 + tmp2; + tmp[15] = out[15]; + + out[0] = tmp[0] + tmp[3]; + out[1] = tmp[1] + tmp[2]; + out[2] = -tmp[2] + tmp[1]; + out[3] = -tmp[3] + tmp[0]; + out[4] = tmp[4]; + tmp1 = -tmp[5] + tmp[6]; + MULTDOUBLE(out[5],tmp1,cosineDouble[8]); + tmp1 = tmp[6] + tmp[5]; + MULTDOUBLE(out[6],tmp1,cosineDouble[8]); + out[7] = tmp[7]; + out[8] = tmp[8] + tmp[11]; + out[9] = tmp[9] + tmp[10]; + out[10] = -tmp[10] + tmp[9]; + out[11] = -tmp[11] + tmp[8]; + out[12] = -tmp[12] + tmp[15]; + out[13] = -tmp[13] + tmp[14]; + out[14] = tmp[14] + tmp[13]; + out[15] = tmp[15] + tmp[12]; + + tmp[0] = out[0] + out[7]; + tmp[1] = out[1] + out[6]; + tmp[2] = out[2] + out[5]; + tmp[3] = out[3] + out[4]; + tmp[4] = -out[4] + out[3]; + tmp[5] = -out[5] + out[2]; + tmp[6] = -out[6] + out[1]; + tmp[7] = -out[7] + out[0]; + tmp[8] = out[8]; + tmp[9] = out[9]; + tmp1 = -out[10] + out[13]; + MULTDOUBLE(tmp[10],tmp1,cosineDouble[8]); + tmp1 = -out[11] + out[12]; + MULTDOUBLE(tmp[11],tmp1,cosineDouble[8]); + tmp1 = out[12] + out[11]; + MULTDOUBLE(tmp[12],tmp1,cosineDouble[8]); + tmp1 = out[13] + out[10]; + MULTDOUBLE(tmp[13],tmp1,cosineDouble[8]); + tmp[14] = out[14]; + tmp[15] = out[15]; + + out[0] = tmp[0] + tmp[15]; + out[1] = tmp[1] + tmp[14]; + out[2] = tmp[2] + tmp[13]; + out[3] = tmp[3] + tmp[12]; + out[4] = tmp[4] + tmp[11]; + out[5] = tmp[5] + tmp[10]; + out[6] = tmp[6] + tmp[9]; + out[7] = tmp[7] + tmp[8]; + out[8] = -tmp[8] + tmp[7]; + out[9] = -tmp[9] + tmp[6]; + out[10] = -tmp[10] + tmp[5]; + out[11] = -tmp[11] + tmp[4]; + out[12] = -tmp[12] + tmp[3]; + out[13] = -tmp[13] + tmp[2]; + out[14] = -tmp[14] + tmp[1]; + out[15] = -tmp[15] + tmp[0]; +} + +void invFdct16x16(in,out) int16 *in,*out; { +uint32 i,j; +double data[256],*scanData,*other; +double temp; + + scanData = data; + + *(scanData++) = (uint16)(*(in++)); + + for (i = 1; i < 256; i++) { + *(scanData++) = *(in++); + }; + + for (i = 0, scanData = data; i < 16; i++, scanData += 16) { + DCTinv16Double(scanData,scanData); + }; + + for (i = 0, scanData = data, other = data+16; i < 16; i++, other += 17) { + double *scanOther; + + scanData += i+1; + scanOther = other; + + for (j = i+1; j < 16; j++, scanData++, scanOther += 16) { + temp = *scanData; + *scanData = *scanOther; + *scanOther = temp; + }; + }; + + for (i = 0, scanData = data; i < 16; i++, scanData += 16) { + DCTinv16Double(scanData,scanData); + }; + + for (i = 0, scanData = data, other = data+16; i < 16; i++, other += 17) { + double *scanOther; + + scanData += i+1; + scanOther = other; + + for (j = i+1; j < 16; j++, scanData++, scanOther += 16) { + temp = *scanData; + *scanData = *scanOther; + *scanOther = temp; + }; + }; + + for (i = 0, scanData = data; i < 256; i++) { + int16 cur; + cur = *(scanData++) / 127.0 + 0.5; + + if (cur < 0) { + cur = 0; + }; + + if (cur > 255) { + cur = 255; + }; + + *(out++) = cur; + }; +} diff --git a/isis/src/mgs/apps/mocuncompress/invFdct16x16.h b/isis/src/mgs/apps/mocuncompress/invFdct16x16.h new file mode 100644 index 0000000000000000000000000000000000000000..bb7ec7c72803b7439d42c195a472d575ca82977f --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/invFdct16x16.h @@ -0,0 +1,49 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)invFdct16x16.h 1.1 10/04/99 +*/ +/* SCCShid @(#)invFdct16x16.h (invFdct16x16.h) 1.2 */ + +#if !defined(invFdct16x16_h) + +#define invFdct16x16_h + +extern void invFdct16x16(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/invFwht16x16.c b/isis/src/mgs/apps/mocuncompress/invFwht16x16.c new file mode 100644 index 0000000000000000000000000000000000000000..a99cd9bc2bcd6c7dbd9d200e39410b60609471a4 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/invFwht16x16.c @@ -0,0 +1,281 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)invFwht16x16.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif +/* +* DESCRIPTION +* This module calcutes a "sequency" ordered, two dimensional +* inverse Walsh-Hadamard transform (WHT) on 16 x 16 blocks of +* data. It is done as two one dimensional transforms (one of the +* rows followed by one of the columns). Each one dimensional +* transform is implemented as a 16 point, 4 stage "butterfly". +* +* COMMENTARY +* These routines have been highly optimized to produce very fast +* 32000 executable code but still use C for coding (thus allowing +* compilation on other machines). +*/ + +#include + +#include "fs.h" + +#include "invFwht16x16.h" + +extern void exit(); + +/* +* This defines a four input (and output), two stage "butterfly" +* calculation done completely in registers (once the data is read from +* memory. Four input and two stages was picked to maximize the use of +* the 32000's registers. Eight of these are required to do a 16 point, +* one dimensional WHT. The "simple" formulas for this "butterfly" are: +* +* n0 = i0 + i1 +* n1 = i0 - i1 First stage +* n2 = i2 + i3 +* n3 = i2 - i3 +* +* o0 = n0 + n2 +* o1 = n1 + n3 Second stage +* o2 = n0 - n2 +* o3 = n1 - n3 +* +* All data (in and out) is assumed to be 16 bit integers. "in" is the +* base address of the input data array and "ii" is the scaling factor to +* use on the next four indexes into "in" (this allows moving by rows or +* columns through a two dimensional array stored as a one dimensional set +* of numbers). "i0", "i1", "i2", and "i3" are the unscaled indexes into +* "in". "out" is the base address of the output data array and "oi" is +* the scaling factor to use on the next four indexes into "out" (this +* allows moving by rows or columns through a two dimensional array stored +* as a one dimensional set of numbers). "o0", "o1", "o2", and "o3" are +* the unscaled indexes into "out". +*/ + +#define BUTTERFLY4(in,ii,i0,i1,i2,i3,out,oi,o0,o1,o2,o3) \ + { \ + register int32 t0,t1,t2,t3,t4; \ + \ + /* Load input into registers */ \ + t0 = in[(ii)*(i0)]; \ + t1 = in[(ii)*(i1)]; \ + t2 = in[(ii)*(i2)]; \ + t3 = in[(ii)*(i3)]; \ + \ + /* Do first stage */ \ + t4 = t0; \ + t4 += t1; \ + t0 -= t1; \ + \ + t1 = t2; \ + t1 += t3; \ + t2 -= t3; \ + \ + /* Do second stage */ \ + t3 = t4; \ + t3 += t1; \ + t4 -= t1; \ + \ + t1 = t0; \ + t1 += t2; \ + t0 -= t2; \ + \ + /* Store results from registers */ \ + out[(oi)*(o0)] = t3; \ + out[(oi)*(o1)] = t1; \ + out[(oi)*(o2)] = t4; \ + out[(oi)*(o3)] = t0; \ + } + +static void invFwht16_row(in,out) register int32 *in,*out; { +/* +* This function does a 16 point, one dimensional inverse WHT on 16, 32 +* bit integers stored as a vector (as in the rows of a two dimensional +* array) and puts the results in a 32 bit integer vector. The transform +* is not normalized but is in "sequency" order. +* +* pre: +* "in" - the 16 inputs stored as 32 bit integers in a vector. +* post: +* "out" - the 16 outputs stored as 32 bit integers in a vector. +*/ +int32 data[32]; /* Temporary storage used between stages */ +register int32 *tmp; /* Register pointer to the temporary storage */ + + /* Point at temporary storage */ + tmp = data; + + /* Perform first two stages of 16 point butterfly */ + BUTTERFLY4(in , 1, 0, 1, 2, 3,tmp, 1, 0, 1, 2, 3); + BUTTERFLY4(in , 1, 4, 5, 6, 7,tmp, 1, 4, 5, 6, 7); + BUTTERFLY4(in , 1, 8, 9,10,11,tmp, 1, 8, 9,10,11); + BUTTERFLY4(in , 1,12,13,14,15,tmp, 1,12,13,14,15); + + /* + * Perform last two stages of 16 point butterfly and store in + * "sequency" order + */ + BUTTERFLY4(tmp, 1, 0, 4, 8,12,out, 1, 0, 3, 1, 2); + BUTTERFLY4(tmp, 1, 1, 5, 9,13,out, 1,15,12,14,13); + BUTTERFLY4(tmp, 1, 2, 6,10,14,out, 1, 7, 4, 6, 5); + BUTTERFLY4(tmp, 1, 3, 7,11,15,out, 1, 8,11, 9,10); +} + +static void invFwht16_col(in,out) register int32 *in,*out; { +/* +* This function does a 16 point, one dimensional inverse WHT on 16, 32 +* bit integers stored as a vector in every 16th location (as in the +* columns of a two dimensional array stored as a one dimensional array by +* rows) and puts the results out in a similar manner. The transform is +* not normalized but is in "sequency" order. +* +* pre: +* "in" - the 16 inputs stored as 32 bit integers in every 16th location. +* post: +* "out" - the 16 outputs stored as 32 bit integers in every 16th location. +*/ +int32 data[16]; /* Temporary storage used between stages */ +register int32 *tmp; /* Register pointer to the temporary storage */ + + /* Point at temporary storage */ + tmp = data; + + /* Perform first two stages of 16 point butterfly */ + BUTTERFLY4(in ,16, 0, 1, 2, 3,tmp, 1, 0, 1, 2, 3); + BUTTERFLY4(in ,16, 4, 5, 6, 7,tmp, 1, 4, 5, 6, 7); + BUTTERFLY4(in ,16, 8, 9,10,11,tmp, 1, 8, 9,10,11); + BUTTERFLY4(in ,16,12,13,14,15,tmp, 1,12,13,14,15); + + /* + * Perform last two stages of 16 point butterfly and store in + * "sequency" order + */ + BUTTERFLY4(tmp, 1, 0, 4, 8,12,out,16, 0, 3, 1, 2); + BUTTERFLY4(tmp, 1, 1, 5, 9,13,out,16,15,12,14,13); + BUTTERFLY4(tmp, 1, 2, 6,10,14,out,16, 7, 4, 6, 5); + BUTTERFLY4(tmp, 1, 3, 7,11,15,out,16, 8,11, 9,10); +} + +void invFwht16x16(in,out) register int16 *in,*out; { +/* +* This function does a "sequency" ordered WHT on a 16 x 16 array of data +* (stored as 16 bit integers) stored in 256 contiguous locations. The +* transform is normalized. The input is assumed to be 16 bit signed +* integers EXCEPT for the DC entry which is be treated as UNSIGNED. The +* result is stored in a 16 x 16 array of the same structure. The output +* is all 8 bit, unsigned integers. +* +* pre: +* "in" - the 16 x 16 input block data stored as 16 bit integers. +* post: +* "out" - the 16 x 16 output block data stored as 16 bit integers. +*/ +uint32 i; /* Generic looping variable */ +int32 data[256]; /* Temporary storage for transform */ + + /* Convert 16 bit integers to 32 bit integers */ + { + register int16 *scanIn; + register int32 *scanData; + + scanIn = in; + scanData = data; + + *(scanData++) = (uint16)(*(scanIn++)); + + for (i = 1; i < 256; i++) { + *(scanData++) = *(scanIn++); + }; + }; + + { + register int32 *scanData; /* Current row start in "data" */ + + /* + * Pass each row in "data" array (as a vector of size 16) to the + * 16 point, 1D inverse WHT and store the results in contiguous + * 16 point locations in "data". At completion all rows have been + * inverse transformed in one dimension. + */ + for (i = 0, scanData = data; i < 16; i++, scanData += 16) { + invFwht16_row(scanData,scanData); + }; + }; + + { + register int32 *scanData; /* Current column start in "data" */ + + /* + * Inverse transform each column in the 16 x 16 block stored by rows + * as a 256 point vector. + */ + for (i = 0, scanData = data; i < 16; i++, scanData++) { + invFwht16_col(scanData,scanData); + }; + }; + + /* Convert 32 bit integers to 16 bit integers */ + { + register int32 *scanData; + register int16 *scanOut; + + scanData = data; + scanOut = out; + + for (i = 0; i < 256; i++) { + register int32 cur; + cur = *(scanData++); + + + cur >>= 8; + + if (cur < 0) { + cur = 0; + }; + + if (cur > 255) { + cur = 255; + }; + + *(scanOut++) = cur; + }; + }; +} diff --git a/isis/src/mgs/apps/mocuncompress/invFwht16x16.h b/isis/src/mgs/apps/mocuncompress/invFwht16x16.h new file mode 100644 index 0000000000000000000000000000000000000000..087a0eeb6272f22ef1f706c021c8006b3f69090b --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/invFwht16x16.h @@ -0,0 +1,49 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)invFwht16x16.h 1.1 10/04/99 +*/ +/* SCCShid @(#)invFwht16x16.h (invFwht16x16.h) 1.2 */ + +#if !defined(invFwht16x16_h) + +#define invFwht16x16_h + +extern void invFwht16x16(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/limits.h b/isis/src/mgs/apps/mocuncompress/limits.h new file mode 100644 index 0000000000000000000000000000000000000000..373c7a9df3fe1c205ed2cd444aec20ff57aefb92 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/limits.h @@ -0,0 +1,98 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)limits.h 1.1 10/04/99 +*/ +/* SCCShid @(#)limits.h (limits.h) 1.4 */ + +#if !defined(limits_h) + +#define limits_h + +/* +* The transform block size. IMPORTANT NOTE: If changed to another number +* EXTENSIVE re-thinking of the transform compressor is necessary. MANY +* calculations will not fit in their allocated word sizes (including the +* transform coefficients), the "unwound" loops will not execute the correct +* number of times, etc. This is defined here so SOME dependencies can use +* a common definition. +*/ +#define BLOCKSIZE 256 +/* The log (base 2) of the block size (used to avoid calculation overflow) */ +#define LOGBLOCKSIZE 8 +/* The size of the image block in the x and y direction */ +#define BLOCKDIMENSION 16 + +/* +* The maximum number of blocks in an image (and its log base 2). IMPORTANT +* NOTE: If changed to another number SUBSTANTIAL re-thinking of the +* transform compressor is necessary. SEVERAL calculations will not fit +* in their allocated word sizes, etc. This is defined here so SOME +* dependencies can use a common definition. +*/ +#define MAXBLOCKS 1024 +#define LOGMAXBLOCKS 10 + +/* +* The maximum number of ranking groups (and its log base 2). IMPORTANT +* NOTE: If changed to another number re-thinking of the transform +* compressor is necessary. This is defined here so SEVERAL dependencies +* can use a common definition. +*/ +#define MAXGROUPS 8 +#define LOGMAXGROUPS 3 + +/* +* The maximum number of encoding tables (and its log base 2). IMPORTANT +* NOTE: If changed to another number re-thinking of the transform +* compressor is necessary. This is defined here so SEVERAL dependencies +* can use a common definition. +*/ +#define MAXCODES 8 +#define LOGMAXCODES 3 + +/* +* The maximum size of an entry in the weighting table for the "AC energy" +* calculation (and its log base 2). IMPORTANT NOTE: If changed to another +* number re-thinking of the transform compressor is necessary. This is +* defined here so SEVERAL dependencies can use a common definition. +*/ +#define MAXWEIGHT 32 +#define LOGMAXWEIGHT 5 + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/mocuncompress.xml b/isis/src/mgs/apps/mocuncompress/mocuncompress.xml new file mode 100644 index 0000000000000000000000000000000000000000..0410f3084d3dc9ecb11a2ce7f38f5e68d88555d9 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/mocuncompress.xml @@ -0,0 +1,44 @@ + + + + + + Uncompresses moc EDR data files + + + + This program will uncompress MOC EDR data. It is not a standard Isis + program but is used internally within "moc2isis" when decompression + of the EDR is necessary. + + + + + Ported to LINUX under the Isis 3.0 conversion + + + Ported to LINUX under the Isis 3.0 conversion + + + Fixed problems with Sun OS Port + + + Added Janet Barrets fix to readBlock.c for discrete cosine + transform imqs. + + + Fixed problem on MacOSX that caused bus errors. + + + Changed "static char label[256]" to "static char label[1024]", which keeps + this program working on more systems. + + + Removed some unnecessary code that caused problems on some 64bit systems. + + + + + Mars Global Surveyor + + diff --git a/isis/src/mgs/apps/mocuncompress/msdp.h b/isis/src/mgs/apps/mocuncompress/msdp.h new file mode 100644 index 0000000000000000000000000000000000000000..2fee925be3707342c6fd107820ded20dd4ffd342 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/msdp.h @@ -0,0 +1,104 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)msdp.h 1.1 10/04/99 +*/ +typedef unsigned char pixel, byte; + +#define round(x) ((x) > 0.0 ? (x) + 0.5 : (x) - 0.5) + +/* + MSDP in a (large) nutshell: + +Offset Length Name Definition +(Octet) (Octet) + 0 2 SDID The ID number of the entire image. + 2 2 SDNUM The subimage number of this datagram. + 4 2 SDOFF The offset downtrack of this datagram. + 6 2 SDLINE The length downtrack of this datagram. + 8 5 SDTIME The timestamp of the start of the entire image. +13 1 SDSTAT Some of this datagram's status. +14 17 SDCMD The command that caused the entire image. +31 5 SDCTXT The context image parameters. +36 2 SDGO The camera gain and offset at the start of the entire + image. +38 2 SDGONM The number of additional gain and offset values in + SDDAT. +40 2 SDDOWN The number of lines downtrack in the entire image. +42 2 SDEDIT The crosstrack editing performed. +44 8 SDCOMP The compression table entry used for the entire image. +52 2 SDSENS The sensor values associate with the entire image. +54 4 SDOTHER The clocking rate of the camera CCD and dark reference + pixel flag at the start of the entire image. +58 4 SDLEN The number of octets in SDDAT part of this datagram. +62 SDLEN SDDAT The data portion of this datagram. +62+SDLEN 1 SDCS The checksum redundancy of this datagram. +*/ + +struct msdp_header +{ + byte id[2]; + byte fragment[2]; + byte down_offset[2]; + byte down_length[2]; + byte time[5]; + byte status; + byte cmd[17]; + byte context[5]; + byte gain; + byte offset; + byte gain_count[2]; + byte down_total[2]; + byte edit_start; + byte edit_length; /* units of 16 pixels */ + byte compression[8]; + byte sensors[2]; + byte other[4]; + byte len[4]; +}; + +#define MAKESHORT(p) ((p)[0] | ((p)[1] << 8)) +#define MAKE24BIT(p) ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16)) +#define MAKELONG(p) ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24)) + +#define BYTE0(i) ((i)&0xff) +#define BYTE1(i) (((i)&0xff00)>>8) +#define BYTE2(i) (((i)&0xff0000)>>16) +#define BYTE3(i) (((i)&0xff000000)>>24) + +#define STUFFSHORT(p,v) ((p)[0] = (v)&0xff, (p)[1] = (v)>>8) diff --git a/isis/src/mgs/apps/mocuncompress/nextValue.c b/isis/src/mgs/apps/mocuncompress/nextValue.c new file mode 100644 index 0000000000000000000000000000000000000000..1aab7e758b4b200cb03577b2adb202fa4bfec414 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/nextValue.c @@ -0,0 +1,175 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)nextValue.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif +/* +* DESCRIPTION +* +* COMMENTARY +*/ + +#include "fs.h" + +#include "nextValue.h" + +#ifdef TEST + +void initReverse(trans) uint8 *trans; { +/* +* This function generate the bit reversal array "trans" above +* +* pre: +* +* post: +* The array "tran" contains the bit reversal of each index in that +* index's location (e.g. trans[0x05] = 0xa0). +*/ +register uint32 t; /* Current index */ + + /* Do all 8 bit numbers */ + for (t = 0; t < 256; t++) { + register uint8 r; /* Reversed byte */ + register uint8 b; /* Bit count */ + register uint8 mask; /* Current bit in index */ + register uint8 bit; /* Current bit in reversed byte */ + + /* Reverse all 8 bits */ + r = 0; + for (b = 0, mask = 0x1, bit = 0x80; b < 8; b++) { + /* + * If the bit in index is set, set the corresponding + * bit in the reversed byte + */ + if (t & mask) { + r |= bit; + }; + + /* Move bit in index up and bit in reversed byte down */ + mask = mask << 1; + bit = bit >> 1; + }; + + /* Store the reversed byte */ + trans[t] = r; + }; +} + +void createIdentTree(code,left,right) uint8 *code,*left,*right; { +uint32 index; + + for (index = 0; index < 127; index++) { + code[index] = LEFT | RIGHT; + left[index] = 2*index + 1; + right[index] = 2*index + 2; + }; + + for (index = 127; index < 255; index++) { + code[index] = 0; + left[index] = ~(2*(index - 127)); + right[index] = ~(2*(index - 127) + 1); + }; +} + +#define MAXLINE 2048 + +uint8 reverse[256]; +uint8 data[2 * MAXLINE + 4]; + +main() { +uint32 nerror; +uint8 code[256]; +uint8 left[256]; +uint8 right[256]; +BITSTRUCT bitStuff; +uint32 i; +uint8 known,actual; + + /* No errors yet */ + nerror = 0; + + printf("Test started\n"); + + initReverse(reverse); + + createIdentTree(code,left,right); + + /* Check decoding function */ + for (i = 0; i < MAXLINE; i++) { + data[i] = i; + }; + + bitStuff.data = data; + bitStuff.bitQueue = 0; + bitStuff.bitCount = 0; + + for (i = 0; i < MAXLINE; i++) { + uint32 bitQueue; + uint32 bitCount; + uint8 *bitData; + + known = ~reverse[i & 0xFF]; + + bitData = bitStuff.data; + bitQueue = bitStuff.bitQueue; + bitCount = bitStuff.bitCount; + + nextValue(actual,code,left,right,bitQueue,bitCount,bitData); + + bitStuff.data = bitData; + bitStuff.bitQueue = bitQueue; + bitStuff.bitCount = bitCount; + + if (known != actual) { + printf("Decode: Pixel: %4d (%4d %1d), expected: %3d (%02x), got: %3d (%02x)\n",i,bitStuff.data - data,bitStuff.bitCount,known,known,actual,actual); + nerror += 1; + }; + }; + + /* If no errors print message */ + if (nerror == 0) { + printf("Test succeeded\n"); + } else { + printf("Test failed: %d\n",nerror); + }; + + /* Exit with the number of errors */ + exit(nerror); +} +#endif diff --git a/isis/src/mgs/apps/mocuncompress/nextValue.h b/isis/src/mgs/apps/mocuncompress/nextValue.h new file mode 100644 index 0000000000000000000000000000000000000000..2dfc64c4743501a1f3d833ab86ebfc20d224c3ec --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/nextValue.h @@ -0,0 +1,136 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)nextValue.h 1.1 10/04/99 +*/ +/* SCCShid @(#)nextValue.h (nextValue.h) 1.3 */ + +#if !defined(nextValue_h) + +#define nextValue_h + +#include "fs.h" +#include "bitsOut.h" +#include "predDecompCommon.h" + +#define nextValue(DEFvalue,DEFcode,DEFleft,DEFright,DEFcur,DEFbitCount,DEFdata) \ +{ \ +register uint8 *LCLcode,*LCLleft,*LCLright; \ +register uint32 LCLindex; /* Current internal node index */ \ + \ + LCLcode = (DEFcode); \ + LCLleft = (DEFleft); \ + LCLright = (DEFright); \ + \ + /* Start at the top of the huffman "tree" */ \ + LCLindex = 0; \ + \ + /* Proceed with decoding */ \ + while (1) { \ + /* Examine current bit of encoded byte */ \ + if ((DEFcur & 0x1) == 0x0) { \ + /* If current bit is a zero go "left" */ \ + /* Decide if "left" is another internal node or a leaf */ \ + if ((LCLcode[LCLindex] & LEFT) == 0) { \ + /* "left" is a leaf */ \ + /* Save decoded value and break out of loop */ \ + (DEFvalue) = LCLleft[LCLindex]; \ + break; \ + } else { \ + /* "left" is an internal node */ \ + /* Move to new node */ \ + LCLindex = LCLleft[LCLindex]; \ + } \ + } else { \ + /* If current bit is a one go "right" */ \ + /* Decide if "right" is another internal node or a leaf */ \ + if ((LCLcode[LCLindex] & RIGHT) == 0) { \ + /* "right" is a leaf */ \ + /* Save decoded value and break out of loop */ \ + (DEFvalue) = LCLright[LCLindex]; \ + break; \ + } else { \ + /* "right" is an internal node */ \ + /* Move to new node */ \ + LCLindex = LCLright[LCLindex]; \ + } \ + }; \ + \ + /* Move to next bit */ \ + DEFbitCount++; \ + \ + /* Are there any more bits in the current byte */ \ + if (DEFbitCount > 7) { \ + /* No more bits in current byte */ \ + /* Start at the beginning of the next byte */ \ + DEFbitCount = 0; \ + \ + /* Move pointer */ \ + DEFdata++; \ + \ + /* Get new byte */ \ + DEFcur = *DEFdata; \ + } else { \ + /* More bits in current byte */ \ + /* Shift next bit into position */ \ + DEFcur >>= 1; \ + } \ + }; \ + \ + /* Move to next bit */ \ + DEFbitCount++; \ + \ + /* Are there any more bits in the current byte */ \ + if (DEFbitCount > 7) { \ + /* No more bits in current byte */ \ + /* Start at the beginning of the next byte */ \ + DEFbitCount = 0; \ + \ + /* Move pointer */ \ + DEFdata++; \ + \ + /* Get new byte */ \ + DEFcur = *DEFdata; \ + } else { \ + /* More bits in current byte */ \ + /* Shift next bit into position */ \ + DEFcur >>= 1; \ + }; \ +} + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/pmain.c b/isis/src/mgs/apps/mocuncompress/pmain.c new file mode 100644 index 0000000000000000000000000000000000000000..aaea296831b6af533ea530a7ddfb7105bd6412b6 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/pmain.c @@ -0,0 +1,184 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)pmain.c 1.2 03/30/00"; + +/* +* DESCRIPTION +* +* COMMENTARY +*/ + +#include +#include +#include +#include + +#include "fs.h" +#include "predCompCommon.h" +#include "bitsOut.h" + +#include "predictiveDecompressor.h" + +extern void exit(); + +#define BUFFERSIZE 4096 + +/* Huffman tree (in table form) */ +uint8 code[256]; +uint8 left[256]; +uint8 right[256]; + +int pred_past_eof; + +/* + NOTE: the globals code, left, and right should be set up prior + to calling this routine. +*/ +uint8 *predictive_decomp_main(data, len, height, width, + doSync, sync, xpred, ypred, got_height) +uint8 *data; +int len; +uint8 doSync; /* Use sync pattern */ +uint16 sync; /* Sync pattern to use */ +int *got_height; +{ + uint8 *curLine; /* Current line */ + uint8 *prevLine; /* Previous line */ + BITSTRUCT bitStuff; /* Output bit stream structure */ + uint8 compType = 0; /* Type of compression */ + uint32 decodeSize; /* Size of huffman tables */ + uint32 y; /* Looping variable */ + uint32 index; /* Indexing variable */ + uint8 *result; + uint8 *lastsync; + uint16 gotsync; + extern int errors; + extern uint8 *findsync(uint8 *p, int len, uint16 sync); + + + pred_past_eof = 0; + + /* Allocate space for decompression */ + if ((prevLine = (uint8 *)malloc(width * sizeof(*prevLine))) == NULL) { + (void)fprintf(stderr,"Unable to get enough memory for line buffers\n"); + exit(1); + }; + + for (y = 0; y < width; y++) { + prevLine[y] = 0; + }; + + if ((curLine = (uint8 *)malloc(width * sizeof(*curLine))) == NULL) { + (void)fprintf(stderr,"Unable to get enough memory for line buffers\n"); + exit(1); + }; + + if ((result = (uint8 *) malloc(height*width)) == NULL) { + fprintf(stderr, "can't get memory for output image\n"); + exit(1); + } + + if (xpred) compType |= XPRED; + if (ypred) compType |= YPRED; + + bitStuff.output = data; + bitStuff.bitQueue = *(bitStuff.output); + bitStuff.bitCount = 0; + + lastsync = data; + + for (y = 0; y < height; y++) { + if ((y % 128 == 0) && (doSync == 1)) { + if (bitStuff.bitCount != 0) { + bitStuff.bitCount = 0; + bitStuff.output++; + }; + if (((bitStuff.output - data) & 0x1) == 0x1) { + bitStuff.output++; + }; + bitStuff.bitQueue = *(bitStuff.output); + /* check sync pattern: + NOTE this is kind of a funny place to do this, + but it's simplest to do it here due to the + structure of the code. mc, 11/11/98 */ + gotsync = *(bitStuff.output) | (*(bitStuff.output+1)<<8); + if (gotsync != sync) { + fprintf(stderr, "lost sync, line %d -- ", y); + errors += 1; +#define AUTOSYNC +#ifdef AUTOSYNC + if (!(lastsync = (uint8*)findsync(lastsync, + len-(lastsync-data), sync))) { +#else + if (1) { +#endif + *got_height = y; + if (bitStuff.output-data > len) { + /* we tried to read beyond the end of + the data. */ + pred_past_eof = 1; + } + fprintf(stderr, "aborting\n"); + return result; + } + else { + bitStuff.output = lastsync; + //fprintf(stderr, "restart at %#x\n", lastsync); + } + } + else { + lastsync = bitStuff.output; + } + + predictiveDecompressor(curLine,prevLine,width,compType | SYNC,code,left,right,sync,&bitStuff); + } + else { + predictiveDecompressor(curLine,prevLine,width,compType,code,left,right,sync,&bitStuff); + }; + + bcopy(curLine, result+y*width, width); + }; + + /* Free the temporary storage */ + free((char *)prevLine); + free((char *)curLine); + + *got_height = height; + return result; +} diff --git a/isis/src/mgs/apps/mocuncompress/predCompCommon.h b/isis/src/mgs/apps/mocuncompress/predCompCommon.h new file mode 100644 index 0000000000000000000000000000000000000000..be4527df39f14f6f9a4fb75b18192fb31c6459af --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/predCompCommon.h @@ -0,0 +1,55 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)predCompCommon.h 1.1 10/04/99 +*/ +/* SCCShid @(#)predCompCommon.h (predCompCommon.h) 1.2 */ + +#if !defined(predCompCommon_h) + +#define predCompCommon_h + +/* Possible "orthogonal" types of predictive compression */ + +#define NONE 0x00 /* No prediction (raw data) */ +#define REQUANT 0x01 /* Requantize data (before encoding) */ +#define XPRED 0x02 /* Prediction in the crosstrack direction */ +#define YPRED 0x04 /* Prediction in the downtrack direction */ +#define SYNC 0x08 /* Output a "sync" pattern on this line */ + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/predDecompCommon.h b/isis/src/mgs/apps/mocuncompress/predDecompCommon.h new file mode 100644 index 0000000000000000000000000000000000000000..1c5a95fec0074a80642c4d788d788021de8ac1dc --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/predDecompCommon.h @@ -0,0 +1,52 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)predDecompCommon.h 1.1 10/04/99 +*/ +/* SCCShid @(#)predDecompCommon.h (predDecompCommon.h) 1.1 */ + +#if !defined(predDecompCommon_h) + +#define predDecompCommon_h + +/* Flags indication left (or right) branch is not a leaf for decompression */ + +#define LEFT 0x01 /* Left branch is not a leaf */ +#define RIGHT 0x02 /* Right branch is not a leaf */ + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/predcode.h b/isis/src/mgs/apps/mocuncompress/predcode.h new file mode 100644 index 0000000000000000000000000000000000000000..5d56466e02322b1464cc924c7c967078ef8ffd00 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/predcode.h @@ -0,0 +1,563 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)predcode.h 1.1 10/04/99 +*/ +/* SCCSID @(#)predcode.h (predcode.h) 1.2 */ + +/* + Predictive compressor code and requant tables. + + NOTE this is a testing release only. The lossless tables + are fairly solid. Table 0 is an identity mapping for + testing only and should be deleted prior to flight. + The lossy table should be examined before committing. + + REFINE should PROM space be at a premium, the length tables + could be encoded into the code tables the same way the + hardware compressor does it. The expanded form is still + needed in RAM because that's what the WA predictive + compressor uses. +*/ + +#ifndef predcode_h +#define predcode_h + +#include "fs.h" + +#ifdef DEFINE_CODE_TABLES + +/* IDENTITY; NO COMPRESSION -- dumped from 'default.code' */ +uint16 Code0Bits[256] = { +0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, +0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, +0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, +0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, +0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, +0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, +0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, +0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, +0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, +0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, +0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, +0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, +0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, +0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, +0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, +0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, +0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, +0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, +0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, +0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, +0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, +0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, +0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, +0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, +0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, +0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, +0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, +0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, +0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, +0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, +0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff, +}; + +uint8 Code0Len[256] = { + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +}; + +/* dumped from 'exp01.code' */ +uint16 Code1Bits[256] = { +0x0000, 0x0001, 0x000d, 0x0055, 0x00f5, 0x0375, 0x0135, 0x1135, +0x5a75, 0x1a75, 0x6a75, 0x2a75, 0x4a75, 0x0a75, 0x7275, 0x3275, +0x5275, 0x1275, 0x6275, 0x2275, 0x4275, 0x0275, 0x7c75, 0x3c75, +0x5c75, 0x1c75, 0x6c75, 0x2c75, 0x4c75, 0x0c75, 0x7475, 0x3475, +0x5475, 0x1475, 0x6475, 0x2475, 0x4475, 0x0475, 0x7875, 0x3875, +0x5875, 0x1875, 0x6875, 0x2875, 0x4875, 0x0875, 0x7075, 0x3075, +0x5075, 0x1075, 0x6075, 0x2075, 0x4075, 0x0075, 0x7fb5, 0x3fb5, +0x5fb5, 0x1fb5, 0x6fb5, 0x2fb5, 0x4fb5, 0x0fb5, 0x77b5, 0x37b5, +0x57b5, 0x17b5, 0x67b5, 0x27b5, 0x47b5, 0x07b5, 0x7bb5, 0x3bb5, +0x5bb5, 0x1bb5, 0x6bb5, 0x2bb5, 0x4bb5, 0x0bb5, 0x73b5, 0x33b5, +0x53b5, 0x13b5, 0x63b5, 0x23b5, 0x43b5, 0x03b5, 0x7db5, 0x3db5, +0x5db5, 0x1db5, 0x6db5, 0x2db5, 0x4db5, 0x0db5, 0x75b5, 0x35b5, +0x55b5, 0x15b5, 0x65b5, 0x25b5, 0x45b5, 0x05b5, 0x79b5, 0x39b5, +0x59b5, 0x19b5, 0x69b5, 0x29b5, 0x49b5, 0x09b5, 0x71b5, 0x31b5, +0x51b5, 0x11b5, 0x61b5, 0x21b5, 0x41b5, 0x01b5, 0x7eb5, 0x3eb5, +0x5eb5, 0x1eb5, 0x3a75, 0x2eb5, 0x4eb5, 0x6eb5, 0x6675, 0x1675, +0x5675, 0x16b5, 0x66b5, 0x26b5, 0x46b5, 0x06b5, 0x7ab5, 0x3ab5, +0x5ab5, 0x1ab5, 0x6ab5, 0x2ab5, 0x4ab5, 0x0ab5, 0x72b5, 0x32b5, +0x52b5, 0x12b5, 0x62b5, 0x22b5, 0x42b5, 0x02b5, 0x7cb5, 0x3cb5, +0x5cb5, 0x1cb5, 0x6cb5, 0x2cb5, 0x4cb5, 0x0cb5, 0x74b5, 0x34b5, +0x54b5, 0x14b5, 0x64b5, 0x24b5, 0x44b5, 0x04b5, 0x78b5, 0x38b5, +0x58b5, 0x18b5, 0x68b5, 0x28b5, 0x48b5, 0x08b5, 0x70b5, 0x30b5, +0x50b5, 0x10b5, 0x60b5, 0x20b5, 0x40b5, 0x00b5, 0x0eb5, 0x3f35, +0x7f35, 0x1f35, 0x6f35, 0x2f35, 0x4f35, 0x0f35, 0x7735, 0x3735, +0x5735, 0x1735, 0x6735, 0x2735, 0x4735, 0x0735, 0x7b35, 0x3b35, +0x5b35, 0x1b35, 0x6b35, 0x2b35, 0x4b35, 0x0b35, 0x7335, 0x3335, +0x5335, 0x1335, 0x6335, 0x2335, 0x5f35, 0x4335, 0x7d35, 0x3d35, +0x5d35, 0x1d35, 0x6d35, 0x2d35, 0x4d35, 0x0d35, 0x7535, 0x3535, +0x5535, 0x1535, 0x6535, 0x0335, 0x2535, 0x0535, 0x7935, 0x3935, +0x5935, 0x1935, 0x6935, 0x4535, 0x2935, 0x0935, 0x7135, 0x4935, +0x5135, 0x3135, 0x56b5, 0x36b5, 0x76b5, 0x7a75, 0x0675, 0x4675, +0x2675, 0x3675, 0x0e75, 0x0175, 0x0035, 0x0015, 0x0005, 0x0003, +}; + +uint8 Code1Len[256] = { + 1, 3, 4, 7, 8, 10, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 12, 10, 9, 7, 5, 2, +}; + +/* dumped from 'exp02.code' */ +uint16 Code2Bits[256] = { +0x0002, 0x0000, 0x0005, 0x000c, 0x0011, 0x003c, 0x00fc, 0x0101, +0x0081, 0x0181, 0x0d81, 0x0dc1, 0x09c1, 0x0ec1, 0x76c1, 0x36c1, +0x56c1, 0x16c1, 0x66c1, 0x26c1, 0x46c1, 0x06c1, 0x7ac1, 0x3ac1, +0x5ac1, 0x1ac1, 0x6ac1, 0x2ac1, 0x4ac1, 0x0ac1, 0x72c1, 0x32c1, +0x52c1, 0x12c1, 0x62c1, 0x22c1, 0x42c1, 0x02c1, 0x7cc1, 0x3cc1, +0x5cc1, 0x1cc1, 0x6cc1, 0x2cc1, 0x4cc1, 0x0cc1, 0x74c1, 0x34c1, +0x54c1, 0x14c1, 0x64c1, 0x24c1, 0x44c1, 0x04c1, 0x78c1, 0x38c1, +0x58c1, 0x18c1, 0x68c1, 0x28c1, 0x48c1, 0x08c1, 0x70c1, 0x30c1, +0x50c1, 0x10c1, 0x60c1, 0x20c1, 0x40c1, 0x00c1, 0x7f41, 0x3f41, +0x5f41, 0x1f41, 0x6f41, 0x2f41, 0x4f41, 0x0f41, 0x7741, 0x3741, +0x5741, 0x1741, 0x6741, 0x2741, 0x4741, 0x0741, 0x7b41, 0x3b41, +0x5b41, 0x1b41, 0x6b41, 0x2b41, 0x4b41, 0x0b41, 0x7341, 0x3341, +0x5341, 0x1341, 0x6341, 0x2341, 0x4341, 0x0341, 0x7d41, 0x3d41, +0x5d41, 0x1d41, 0x6d41, 0x2d41, 0x4d41, 0x0d41, 0x7541, 0x3541, +0x5541, 0x1541, 0x6541, 0x2541, 0x4541, 0x0541, 0x7941, 0x3941, +0x7ec1, 0x6ec1, 0x21c1, 0x41c1, 0x4ec1, 0x5941, 0x61c1, 0x11c1, +0x51c1, 0x1141, 0x6141, 0x2141, 0x4141, 0x0141, 0x7e41, 0x3e41, +0x5e41, 0x1e41, 0x6e41, 0x2e41, 0x4e41, 0x0e41, 0x7641, 0x3641, +0x5641, 0x1641, 0x6641, 0x2641, 0x4641, 0x0641, 0x7a41, 0x3a41, +0x5a41, 0x1a41, 0x6a41, 0x2a41, 0x4a41, 0x0a41, 0x7241, 0x3241, +0x5241, 0x1241, 0x6241, 0x2241, 0x4241, 0x0241, 0x7c41, 0x3c41, +0x5c41, 0x1c41, 0x6c41, 0x2c41, 0x4c41, 0x0c41, 0x7441, 0x3441, +0x5441, 0x1441, 0x1941, 0x2941, 0x4941, 0x0441, 0x7841, 0x3841, +0x5841, 0x1841, 0x6841, 0x2841, 0x4841, 0x0841, 0x7041, 0x3041, +0x5041, 0x1041, 0x6041, 0x2041, 0x4041, 0x0041, 0x7f81, 0x3f81, +0x5f81, 0x1f81, 0x6f81, 0x2f81, 0x4f81, 0x2441, 0x0f81, 0x3781, +0x5781, 0x1781, 0x6781, 0x2781, 0x4781, 0x0781, 0x7b81, 0x3b81, +0x5b81, 0x1b81, 0x6b81, 0x7781, 0x2b81, 0x0b81, 0x7381, 0x3381, +0x5381, 0x1381, 0x4b81, 0x6381, 0x4381, 0x2381, 0x0381, 0x31c1, +0x4441, 0x6441, 0x7141, 0x0941, 0x2ec1, 0x6941, 0x1ec1, 0x5ec1, +0x3ec1, 0x01c1, 0x5141, 0x3141, 0x19c1, 0x05c1, 0x0581, 0x03c1, +0x0281, 0x0001, 0x007c, 0x0021, 0x001c, 0x0009, 0x0004, 0x0003, +}; + +uint8 Code2Len[256] = { + 2, 3, 3, 5, 5, 7, 8, 9, 10, 11, 12, 12, 13, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 13, 12, 12, 10, 10, 9, 8, 6, 6, 4, 4, 2, +}; + +/* dumped from 'exp04.code' */ +uint16 Code3Bits[256] = { +0x0004, 0x0006, 0x0007, 0x0005, 0x000b, 0x000d, 0x0018, 0x001d, +0x0038, 0x007d, 0x00f8, 0x0003, 0x0001, 0x0183, 0x01c3, 0x0343, +0x02c3, 0x0683, 0x0e81, 0x08c3, 0x0181, 0x0c83, 0x1181, 0x04c3, +0x5f41, 0x1f41, 0x6f41, 0x2f41, 0x4f41, 0x0f41, 0x7741, 0x3741, +0x5741, 0x1741, 0x6741, 0x2741, 0x4741, 0x0741, 0x7b41, 0x3b41, +0x5b41, 0x1b41, 0x6b41, 0x2b41, 0x4b41, 0x0b41, 0x7341, 0x3341, +0x5341, 0x1341, 0x6341, 0x2341, 0x4341, 0x0341, 0x7d41, 0x3d41, +0x5d41, 0x1d41, 0x6d41, 0x2d41, 0x4d41, 0x0d41, 0x7541, 0x3541, +0x5541, 0x1541, 0x6541, 0x2541, 0x4541, 0x0541, 0x7941, 0x3941, +0x5941, 0x1941, 0x6941, 0x2941, 0x4941, 0x0941, 0x7141, 0x3141, +0x5141, 0x1141, 0x6141, 0x2141, 0x4141, 0x0141, 0x7e41, 0x3e41, +0x5e41, 0x1e41, 0x6e41, 0x2e41, 0x4e41, 0x0e41, 0x7641, 0x3641, +0x5641, 0x1641, 0x6641, 0x2641, 0x4641, 0x0641, 0x7a41, 0x3a41, +0x5a41, 0x1a41, 0x6a41, 0x2a41, 0x4a41, 0x0a41, 0x7241, 0x4883, +0x7f41, 0x5883, 0x1883, 0x0483, 0x7883, 0x3f41, 0x3241, 0x3c41, +0x5c41, 0x1c41, 0x2483, 0x4483, 0x4c41, 0x0c41, 0x6483, 0x1483, +0x5483, 0x1441, 0x6441, 0x2441, 0x4441, 0x0441, 0x7841, 0x3841, +0x5841, 0x1841, 0x6841, 0x2841, 0x4841, 0x0841, 0x7041, 0x3041, +0x5041, 0x1041, 0x6041, 0x2041, 0x4041, 0x0041, 0x7f81, 0x3f81, +0x5f81, 0x1f81, 0x6f81, 0x2f81, 0x4f81, 0x0f81, 0x7781, 0x3781, +0x5781, 0x1781, 0x5241, 0x0241, 0x4781, 0x7c41, 0x6781, 0x3b81, +0x5b81, 0x1b81, 0x6b81, 0x2b81, 0x4b81, 0x0b81, 0x7381, 0x3381, +0x5381, 0x1381, 0x6381, 0x2381, 0x4381, 0x0381, 0x7d81, 0x3d81, +0x5d81, 0x1d81, 0x6d81, 0x2781, 0x0781, 0x7b81, 0x2d81, 0x3581, +0x5581, 0x1581, 0x6581, 0x2581, 0x4581, 0x0581, 0x7981, 0x7581, +0x4d81, 0x1981, 0x6981, 0x2981, 0x4981, 0x5981, 0x0981, 0x3181, +0x7181, 0x24c3, 0x3981, 0x0d81, 0x2241, 0x6241, 0x1241, 0x0083, +0x4083, 0x2083, 0x6083, 0x2883, 0x4241, 0x6883, 0x1083, 0x5083, +0x3083, 0x3883, 0x5441, 0x3441, 0x7441, 0x2c41, 0x6c41, 0x7083, +0x0883, 0x3483, 0x14c3, 0x1c83, 0x0cc3, 0x00c3, 0x0681, 0x0283, +0x0281, 0x0143, 0x0081, 0x0043, 0x0101, 0x00c1, 0x0078, 0x003d, +0x0023, 0x0021, 0x0013, 0x0011, 0x0008, 0x0009, 0x0000, 0x0002, +}; + +uint8 Code3Len[256] = { + 3, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10, +10, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 13, 13, 12, 12, 12, 11, +11, 10, 10, 9, 9, 8, 8, 7, 6, 6, 5, 5, 5, 4, 4, 3, +}; + +/* dumped from 'exp06.code' */ +uint16 Code4Bits[256] = { +0x0005, 0x0007, 0x0004, 0x0001, 0x0010, 0x000a, 0x0009, 0x0018, +0x001a, 0x0019, 0x0038, 0x003a, 0x0039, 0x0078, 0x007a, 0x0000, +0x0002, 0x0006, 0x0300, 0x0102, 0x0306, 0x0480, 0x0482, 0x0486, +0x0280, 0x0282, 0x0682, 0x0a80, 0x1680, 0x1d46, 0x0b46, 0x3e80, +0x2d46, 0x2680, 0x0680, 0x3646, 0x5646, 0x1646, 0x6646, 0x2646, +0x4646, 0x0646, 0x7a46, 0x3a46, 0x5a46, 0x1a46, 0x6a46, 0x2a46, +0x4a46, 0x0a46, 0x7246, 0x3246, 0x5246, 0x1246, 0x6246, 0x2246, +0x4246, 0x0246, 0x7c46, 0x3c46, 0x5c46, 0x1c46, 0x6c46, 0x2c46, +0x4c46, 0x0c46, 0x7446, 0x3446, 0x5446, 0x1446, 0x6446, 0x2446, +0x4446, 0x0446, 0x7846, 0x3846, 0x5846, 0x1846, 0x6846, 0x2846, +0x4846, 0x0846, 0x7046, 0x3046, 0x5046, 0x1046, 0x6046, 0x2046, +0x4046, 0x0046, 0x7f86, 0x3f86, 0x5f86, 0x1f86, 0x6f86, 0x2f86, +0x4f86, 0x0f86, 0x7786, 0x0546, 0x2546, 0x4546, 0x6786, 0x2786, +0x4786, 0x0786, 0x7b86, 0x3b86, 0x5b86, 0x1b86, 0x6b86, 0x2b86, +0x7646, 0x3786, 0x7386, 0x1546, 0x6546, 0x1386, 0x6386, 0x2386, +0x4386, 0x0386, 0x3546, 0x5546, 0x5d86, 0x1d86, 0x7546, 0x0d46, +0x4d46, 0x0d86, 0x7586, 0x3586, 0x5586, 0x1586, 0x6586, 0x2586, +0x4586, 0x0586, 0x7986, 0x3986, 0x5986, 0x1986, 0x6986, 0x2986, +0x4986, 0x5786, 0x4b86, 0x3186, 0x5186, 0x1186, 0x6186, 0x0b86, +0x0986, 0x0186, 0x7e86, 0x3e86, 0x5e86, 0x1e86, 0x6e86, 0x2e86, +0x4e86, 0x0e86, 0x7686, 0x3686, 0x5686, 0x1686, 0x6686, 0x2686, +0x7186, 0x2186, 0x7a86, 0x4186, 0x4686, 0x1a86, 0x6a86, 0x2a86, +0x4a86, 0x0a86, 0x7286, 0x0686, 0x3a86, 0x5a86, 0x3286, 0x2286, +0x4286, 0x5286, 0x6680, 0x0286, 0x6286, 0x1286, 0x1786, 0x0e46, +0x4e46, 0x2e46, 0x4d86, 0x2d86, 0x6d86, 0x3d86, 0x7d86, 0x5386, +0x3386, 0x6e46, 0x1e46, 0x5e46, 0x3e46, 0x7e46, 0x0146, 0x4146, +0x2146, 0x6146, 0x1146, 0x5146, 0x3146, 0x7146, 0x0946, 0x4946, +0x2946, 0x6946, 0x1946, 0x5946, 0x3946, 0x7946, 0x3346, 0x4680, +0x1346, 0x1e80, 0x1b46, 0x0346, 0x0e80, 0x1a80, 0x0e82, 0x0a82, +0x0746, 0x0086, 0x0082, 0x0080, 0x0106, 0x0302, 0x0100, 0x0182, +0x0180, 0x00c6, 0x00fa, 0x00f8, 0x0079, 0x0042, 0x0040, 0x0026, +0x0022, 0x0020, 0x0016, 0x0012, 0x0008, 0x000e, 0x000c, 0x0003, +}; + +uint8 Code4Len[256] = { + 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, + 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, +14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, +14, 14, 13, 13, 13, 13, 12, 12, 11, 11, 11, 11, 10, 10, 10, 9, + 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 5, 5, 5, 4, 4, 3, +}; + +/* dumped from 'exp08.code' */ +uint16 Code5Bits[256] = { +0x0008, 0x000c, 0x0006, 0x000d, 0x0007, 0x0012, 0x0009, 0x000b, +0x0010, 0x001a, 0x0019, 0x001b, 0x0040, 0x004a, 0x0041, 0x007b, +0x00f0, 0x00fa, 0x0003, 0x00c3, 0x000a, 0x0001, 0x0083, 0x0100, +0x010a, 0x028a, 0x0183, 0x0300, 0x030a, 0x0301, 0x0043, 0x0480, +0x008a, 0x0081, 0x0a43, 0x1080, 0x048a, 0x0679, 0x0643, 0x1e43, +0x148a, 0x3a79, 0x0c80, 0x1643, 0x4079, 0x0079, 0x7f81, 0x3f81, +0x5f81, 0x1f81, 0x6f81, 0x2f81, 0x4f81, 0x0f81, 0x7781, 0x3781, +0x5781, 0x1781, 0x6781, 0x2781, 0x4781, 0x0781, 0x7b81, 0x3b81, +0x5b81, 0x1b81, 0x6b81, 0x2b81, 0x4b81, 0x0b81, 0x7381, 0x3381, +0x5381, 0x1381, 0x6381, 0x2381, 0x4381, 0x0381, 0x7d81, 0x3d81, +0x5d81, 0x1d81, 0x6d81, 0x2d81, 0x4d81, 0x0d81, 0x7581, 0x3581, +0x5581, 0x1581, 0x6581, 0x2581, 0x4581, 0x0581, 0x6c79, 0x6079, +0x7c79, 0x3c79, 0x6279, 0x2279, 0x3279, 0x5279, 0x7181, 0x3181, +0x5181, 0x1181, 0x6181, 0x2079, 0x7981, 0x0181, 0x7e81, 0x3e81, +0x5e81, 0x1e81, 0x6e81, 0x0a79, 0x7279, 0x0e81, 0x7681, 0x3681, +0x5681, 0x1681, 0x2a79, 0x4a79, 0x4681, 0x0681, 0x6a79, 0x1a79, +0x5a79, 0x1a81, 0x6a81, 0x2a81, 0x4a81, 0x3981, 0x2181, 0x3281, +0x5281, 0x1281, 0x6281, 0x2281, 0x4181, 0x0a81, 0x7c81, 0x3c81, +0x5c81, 0x1c81, 0x6c81, 0x2c81, 0x4c81, 0x0c81, 0x7481, 0x3481, +0x5481, 0x7281, 0x4281, 0x2481, 0x0281, 0x1481, 0x7881, 0x3881, +0x5881, 0x1881, 0x6881, 0x6481, 0x4481, 0x2881, 0x748a, 0x4881, +0x0881, 0x4c80, 0x348a, 0x0481, 0x6981, 0x1981, 0x5981, 0x1079, +0x5079, 0x3079, 0x7079, 0x1c79, 0x4981, 0x2981, 0x5c79, 0x0879, +0x4879, 0x2879, 0x6879, 0x0279, 0x0981, 0x4279, 0x1879, 0x5879, +0x3879, 0x1279, 0x5a81, 0x3a81, 0x7a81, 0x2681, 0x6681, 0x4e81, +0x2e81, 0x7879, 0x0479, 0x4479, 0x2479, 0x6479, 0x1479, 0x5479, +0x3479, 0x7479, 0x0c79, 0x4c79, 0x2c79, 0x3643, 0x2e79, 0x0e79, +0x2c80, 0x0e43, 0x1e79, 0x1679, 0x1c80, 0x0080, 0x0243, 0x0c8a, +0x088a, 0x0880, 0x0443, 0x0701, 0x070a, 0x0700, 0x0383, 0x0101, +0x0280, 0x0143, 0x0179, 0x018a, 0x0180, 0x0000, 0x00f9, 0x007a, +0x0070, 0x003b, 0x0039, 0x003a, 0x0030, 0x0023, 0x0021, 0x002a, +0x0020, 0x0013, 0x0011, 0x0002, 0x000f, 0x0005, 0x000e, 0x0004, +}; + +uint8 Code5Len[256] = { + 4, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, + 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, +12, 12, 12, 13, 13, 13, 13, 13, 14, 14, 15, 14, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 14, 14, 14, 14, 13, 13, 13, 13, 13, 12, 12, +12, 12, 11, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 9, 8, 8, + 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 4, 4, 4, 4, +}; + +/* dumped from 'exp10.code' */ +uint16 Code6Bits[256] = { +0x000a, 0x000e, 0x0005, 0x000f, 0x0008, 0x001c, 0x0011, 0x000b, +0x0010, 0x0014, 0x0012, 0x0019, 0x0023, 0x0040, 0x0044, 0x0032, +0x0039, 0x003b, 0x0070, 0x0084, 0x0072, 0x00f9, 0x00fb, 0x01f0, +0x01f4, 0x00f2, 0x0103, 0x0000, 0x0204, 0x0002, 0x0009, 0x0183, +0x0500, 0x0304, 0x0302, 0x0509, 0x0383, 0x0900, 0x0f04, 0x0702, +0x0003, 0x0f83, 0x0004, 0x0804, 0x1f02, 0x1789, 0x1783, 0x0f00, +0x2102, 0x0102, 0x1803, 0x3100, 0x1100, 0x3803, 0x6e89, 0x2e89, +0x4e89, 0x0e89, 0x7689, 0x3689, 0x5689, 0x1689, 0x6689, 0x2689, +0x4689, 0x0689, 0x7a89, 0x3a89, 0x5a89, 0x1a89, 0x6a89, 0x2a89, +0x4a89, 0x0a89, 0x7289, 0x3289, 0x5289, 0x1289, 0x6289, 0x2289, +0x4289, 0x0289, 0x7c89, 0x3c89, 0x5c89, 0x1c89, 0x6c89, 0x2c89, +0x4c89, 0x0c89, 0x7589, 0x3589, 0x6d89, 0x2d89, 0x7d89, 0x3d89, +0x6389, 0x2389, 0x7389, 0x3389, 0x2b89, 0x4b89, 0x6889, 0x3e89, +0x5e89, 0x0889, 0x7089, 0x3089, 0x5089, 0x1089, 0x6089, 0x2089, +0x4089, 0x0089, 0x7f09, 0x1b89, 0x6b89, 0x1f09, 0x6f09, 0x2f09, +0x4f09, 0x0f09, 0x3b89, 0x5b89, 0x5709, 0x1709, 0x7b89, 0x0789, +0x4789, 0x7709, 0x7b09, 0x3b09, 0x5b09, 0x1b09, 0x6b09, 0x2b09, +0x4b09, 0x3709, 0x4709, 0x3309, 0x0709, 0x0b09, 0x6309, 0x2309, +0x4309, 0x7309, 0x5309, 0x0309, 0x7102, 0x3102, 0x5804, 0x1309, +0x5489, 0x1e89, 0x7489, 0x1489, 0x6489, 0x7e89, 0x5589, 0x0189, +0x4189, 0x2189, 0x6189, 0x0d89, 0x4489, 0x2489, 0x4d89, 0x1189, +0x5189, 0x3189, 0x7189, 0x1d89, 0x7889, 0x0489, 0x5d89, 0x0989, +0x4989, 0x2989, 0x6989, 0x0389, 0x5889, 0x3889, 0x4389, 0x1989, +0x5989, 0x3989, 0x7989, 0x1389, 0x1889, 0x5389, 0x0589, 0x4589, +0x2589, 0x0b89, 0x4889, 0x2709, 0x6709, 0x2889, 0x3489, 0x5f09, +0x3f09, 0x6589, 0x1589, 0x5100, 0x1804, 0x7100, 0x2789, 0x3804, +0x1102, 0x2f00, 0x0783, 0x0803, 0x0f02, 0x1004, 0x1f00, 0x0100, +0x0f89, 0x0902, 0x0704, 0x0700, 0x0403, 0x0109, 0x0502, 0x0404, +0x0300, 0x0203, 0x0209, 0x0202, 0x0104, 0x0200, 0x0083, 0x01f2, +0x00f4, 0x00f0, 0x007b, 0x0079, 0x0082, 0x0074, 0x0080, 0x0043, +0x0049, 0x0042, 0x0034, 0x0030, 0x001b, 0x0029, 0x0022, 0x0024, +0x0020, 0x0013, 0x0001, 0x000c, 0x0018, 0x0007, 0x000d, 0x0006, +}; + +uint8 Code6Len[256] = { + 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, + 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, +11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, +14, 14, 14, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, +14, 14, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, 11, 11, +11, 10, 10, 10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 8, 8, 7, + 7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, +}; + +/* LOSSY -- dumped from 'tmspread10.code' */ +uint16 Code7Bits[256] = { +0x0005, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, +0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, +0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, +0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, +0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, +0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, +0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, +0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, +0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, +0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, +0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, +0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, +0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, +0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, +0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, +0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d, +0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, +0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, +0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, +0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, +0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, +0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, +0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, +0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, +0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, +0x000d, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, +0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, +0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, +0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, +0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, +0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, +0x0003, 0x0003, 0x0003, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, +}; + +uint8 Code7Len[256] = { + 4, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +}; + +/* dumped from 'tmspread10.requant' */ +uint8 Code7Requant[256] = { + 0, 1, 1, 1, 1, 1, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 255, 255, 255, 255, 255, +}; + +/* dumped from 'default.requant' */ +/* REFINE this could be calculated instead of put into PROM (obviously) */ +uint8 CodeIdentRequant[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, +112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, +128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, +144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, +160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, +176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, +192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, +208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, +224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, +240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, +}; + +uint16 *CodeBitsVec[] = { Code0Bits, Code1Bits, Code2Bits, Code3Bits, + Code4Bits, Code5Bits, Code6Bits, Code7Bits }; + +uint8 *CodeLenVec[] = { Code0Len, Code1Len, Code2Len, Code3Len, + Code4Len, Code5Len, Code6Len, Code7Len }; + +uint8 *CodeRequantVec[] = { CodeIdentRequant, CodeIdentRequant, + CodeIdentRequant, CodeIdentRequant, + CodeIdentRequant, CodeIdentRequant, + CodeIdentRequant, Code7Requant }; + +#else +extern uint16 *CodeBitsVec[8]; +extern uint8 *CodeLenVec[8]; +extern uint8 *CodeRequantVec[8]; +#endif + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/predictiveDecompressor.c b/isis/src/mgs/apps/mocuncompress/predictiveDecompressor.c new file mode 100644 index 0000000000000000000000000000000000000000..d744c93fc5abaadbe224a6f5c6c3622320340fbd --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/predictiveDecompressor.c @@ -0,0 +1,148 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)predictiveDecompressor.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif +/* +* DESCRIPTION +* +* This module produces a single line of decompressed data from +* data that has been predictively compressed. The input is a bit +* stream, a huffman tree, and the previous line. The output is a +* line 8 bit pixels. +* +* COMMENTARY +*/ + +#include "fs.h" +#include "predCompCommon.h" +#include "bitsOut.h" + +#include "decompNONE.h" +#include "decompXPRED.h" +#include "decompYPRED.h" +#include "decompXPREDYPRED.h" +#include "decompSYNC.h" + +#include "predictiveDecompressor.h" + +void predictiveDecompressor(curLine,prevLine,size,type,code,left,right,sync,bitStuff) register uint8 *curLine,*prevLine; register uint32 size; uint8 type; uint8 *code,*left,*right; uint16 sync; BITSTRUCT *bitStuff; { +/* +* This function produces a single line of decompressed data from data +* that has been predictively compressed. The input is a bit stream, a +* huffman tree, and the previous line. The output is a line 8 bit +* pixels. +* +* pre: +* "curLine" - a place for the decoded, decompressed 8 bit output line. +* "prevLine" - the previous output line (for vertical decompression). +* "size" - the size of the above two lines of pixels. +* "type" - the type of predictive compression done to this line (NOTE: +* the "REQUANT" bit must not be set). +* "code" - part of the huffman tree in table form (set above). +* "left" - part of the huffman tree in table form (set above). +* "right" - part of the huffman tree in table form (set above). +* "sync" - the sync pattern. +* "bitStuff" - the bit stream containing the encoded, compressed data. +* +* post: +* "curLine" - the decoded, decompressed 8 bit output line. +* "prevLine" - same a "curLine" (used for next call). +* "bitStuff" - now references the first bit on the next line of encoded, +* compressed data. +*/ + + /* "Decode" the compression options */ + switch (type) { + + /* No "sync" pattern, no prediction, only encoding */ + case NONE: + decompNONE(curLine,size,code,left,right,bitStuff); + break; + + /* No "sync" pattern, crosstrack prediction, and encoding */ + case XPRED: + decompXPRED(curLine,size,code,left,right,bitStuff); + break; + + /* No "sync" pattern, downtrack prediction, and encoding */ + case YPRED: + decompYPRED(curLine,prevLine,size,code,left,right,bitStuff); + break; + + /* No "sync" pattern, 2D prediction, and encoding */ + case XPRED | YPRED: + decompXPREDYPRED(curLine,prevLine,size,code,left,right,bitStuff); + break; + + /* "sync" pattern */ + /* REFINE Should check sync pattern and bit alignment endREFINE */ + case SYNC: + case XPRED | SYNC: + case YPRED | SYNC: + case XPRED | YPRED | SYNC: + decompSYNC(curLine,prevLine,size,sync,bitStuff); + break; + + default: + break; + }; +} + +#ifdef TEST + +main() { +uint32 nerror; + + /* No errors yet */ + nerror = 0; + + printf("Test started\n"); + + /* If no errors print message */ + if (nerror == 0) { + printf("Test succeeded\n"); + } else { + printf("Test failed: %d\n",nerror); + }; + + /* Exit with the number of errors */ + exit(nerror); +} +#endif diff --git a/isis/src/mgs/apps/mocuncompress/predictiveDecompressor.h b/isis/src/mgs/apps/mocuncompress/predictiveDecompressor.h new file mode 100644 index 0000000000000000000000000000000000000000..24de074a13e3119759d256d03072815e7172eba1 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/predictiveDecompressor.h @@ -0,0 +1,49 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)predictiveDecompressor.h 1.1 10/04/99 +*/ +/* SCCShid @(#)predictiveDecompressor.h (predictiveDecompressor.h) 1.4 */ + +#if !defined(predictiveDecompressor_h) + +#define predictiveDecompressor_h + +extern void predictiveDecompressor(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/readBits.c b/isis/src/mgs/apps/mocuncompress/readBits.c new file mode 100644 index 0000000000000000000000000000000000000000..6e85d9734c05c01b3807bfb6408b5b741907a834 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/readBits.c @@ -0,0 +1,157 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)readBits.c 1.1 10/04/99"; + +/* + This is a low-level bit stream reader. It's adapted from a version + by Terry Ligocki with the SCCS id "@(#)readBits.c (readBits.c) 1.3". + + This version has been modified to read from memory rather than from + a stdio stream; the old code is retained and can be used by defining + FILEBITS at the top of readBits.h, but this HAS NOT BEEN TESTED. + There are known problems with reading a block too far in this mode + anyway. Use with caution. + + Mike Caplinger, June 1989. +*/ + +#include +#include +#include + +#include "fs.h" + +#include "readBits.h" + +extern void exit(); + +extern jmp_buf on_error; + +#ifdef FILEBITS +BITSTRUCT *initBits(file) FILE *file; { +BITSTRUCT *bitStuff; + + if ((bitStuff = (BITSTRUCT *)malloc(sizeof(*bitStuff))) == NULL) { + (void)fprintf(stderr,"Unable to allocate bit structure\n"); + longjmp(on_error, 1); + }; + + bitStuff->bitQueue = 0; + bitStuff->bitCount = 0; + bitStuff->file = file; + bitStuff->byteCount = 0; + bitStuff->queueSize = 0; + + return(bitStuff); +} +#else +BITSTRUCT *initBits(data, len) uint8 *data; { +BITSTRUCT *bitStuff; + + if ((bitStuff = (BITSTRUCT *)malloc(sizeof(*bitStuff))) == NULL) { + (void)fprintf(stderr,"Unable to allocate bit structure\n"); + longjmp(on_error, 1); + }; + + bitStuff->bitQueue = 0; + bitStuff->bitCount = 0; + bitStuff->byteCount = 0; + bitStuff->byteQueue = data; + bitStuff->queueSize = len; + + return(bitStuff); +} +#endif + +uint32 readBits(bitCount,bitStuff) register uint8 bitCount; register BITSTRUCT *bitStuff; { +register uint32 bitQueue; +register uint32 bitQueueCount; +register uint32 bits; + + if (bitCount > 24) { + (void)fprintf(stderr,"Asked for more than 24 bits: %d\n",bitCount); + exit(1); + }; + + bitQueue = bitStuff->bitQueue; + bitQueueCount = bitStuff->bitCount; + + if (bitCount > bitQueueCount) { + uint32 byteCount; + uint8 *byteQueue; + uint32 queueSize; + + byteCount = bitStuff->byteCount; + byteQueue = bitStuff->byteQueue; + queueSize = bitStuff->queueSize; + + while (bitQueueCount < 24) { + if (byteCount == queueSize) { +#ifdef FILEBITS + if ((queueSize = fread((char *)byteQueue,sizeof(*byteQueue),MAXQUEUESIZE,bitStuff->file)) == NULL) { +#else + if (1) { +#endif + if (bitQueueCount >= bitCount) { + byteCount = 0; + break; + } else { + (void)fprintf(stderr,"Unable to read %d bits\n",bitCount); + longjmp(on_error, 1); + }; + }; + byteCount = 0; + }; + bitQueue |= byteQueue[byteCount++] << bitQueueCount; + bitQueueCount += 8; + }; + + bitStuff->byteCount = byteCount; + bitStuff->queueSize = queueSize; + }; + + bits = bitQueue & (((uint32)0xFFFFFFFF) >> (32 - bitCount)); + bitQueue >>= bitCount; + bitQueueCount -= bitCount; + + bitStuff->bitQueue = bitQueue; + bitStuff->bitCount = bitQueueCount; + + return(bits); +} diff --git a/isis/src/mgs/apps/mocuncompress/readBits.h b/isis/src/mgs/apps/mocuncompress/readBits.h new file mode 100644 index 0000000000000000000000000000000000000000..a4abbc869dd81874f3ba32db49b65b3d1bfb74c2 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/readBits.h @@ -0,0 +1,71 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)readBits.h 1.1 10/04/99 +*/ +/* SCCShid @(#)readBits.h (readBits.h) 1.2 */ + +#if !defined(readBits_h) + +#define readBits_h + +#include + +#include "fs.h" + +#define MAXQUEUESIZE 4096 + +typedef struct bitStruct BITSTRUCT; + +struct bitStruct { + uint32 bitQueue; + uint8 bitCount; + FILE *file; + uint32 byteCount; +#ifdef FILEBITS + uint8 byteQueue[MAXQUEUESIZE]; +#else + uint8 *byteQueue; +#endif + uint32 queueSize; +}; + +extern BITSTRUCT *initBits(); +extern uint32 readBits(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/readBlock.c b/isis/src/mgs/apps/mocuncompress/readBlock.c new file mode 100644 index 0000000000000000000000000000000000000000..4923aeeb87dc0dda7e9a83f3b68866003977a24a --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/readBlock.c @@ -0,0 +1,110 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)readBlock.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif +/* +* DESCRIPTION +* +* COMMENTARY +*/ + +#include "fs.h" + +#include "readBits.h" +#include "initBlock.h" +#include "readBlock.h" +#include "readCoef.h" +#include "reorder.h" +#include "invFwht16x16.h" +#include "invFdct16x16.h" + +void readBlock(transform,spacing,minDC,rangeDC,var,x,y,xSize,image,bitStuff) uint32 transform,spacing; uint16 minDC,rangeDC; uint32 *var; uint32 x,y,xSize; uint8 *image; BITSTRUCT *bitStuff; { +int16 block[256],*scanBlock,*lastCoef; +uint32 i; +uint32 x0,y0; +uint16 dc; +uint16 numZeros; + + dc = readBits(8,bitStuff); + + /* The following line of code was fixed on March 26, 2004 + by Janet Barrett. The uint16 cast was added to get + consistent results between Linux and Solaris */ + block[0] = (uint16) ((double)dc * rangeDC / 255.0 + minDC); + var++; + + numZeros = readBits(8,bitStuff); + + scanBlock = &block[255]; + + for (i = 0; i < numZeros; i++) { + *(scanBlock--) = 0; + }; + + lastCoef = &block[255 - numZeros]; + + for (scanBlock = &block[1]; scanBlock <= lastCoef; ) { + *(scanBlock++) = readCoef(encodeTrees[*(var++)],bitStuff) * spacing; + }; + + scanBlock = block; + + reorder(block); + + scanBlock = block; + + switch (transform) { + case 0: + invFwht16x16(block,block); + break; + + case 1: + invFdct16x16(block,block); + break; + }; + + scanBlock = block; + + for (y0 = 0; y0 < 16; y0++) { + for (x0 = 0; x0 < 16; x0++) { + image[(y + y0) * xSize + (x + x0)] = *(scanBlock++); + }; + }; +} diff --git a/isis/src/mgs/apps/mocuncompress/readBlock.h b/isis/src/mgs/apps/mocuncompress/readBlock.h new file mode 100644 index 0000000000000000000000000000000000000000..cb553aedd37b291b85614cf308de1c791ad07ebc --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/readBlock.h @@ -0,0 +1,49 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)readBlock.h 1.1 10/04/99 +*/ +/* SCCShid @(#)readBlock.h (readBlock.h) 1.4 */ + +#if !defined(readBlock_h) + +#define readBlock_h + +extern void readBlock(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/readCoef.c b/isis/src/mgs/apps/mocuncompress/readCoef.c new file mode 100644 index 0000000000000000000000000000000000000000..73c63c9c8e447f322c4e2e9184fdfabb08833f1e --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/readCoef.c @@ -0,0 +1,78 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)readCoef.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif +/* +* DESCRIPTION +* +* COMMENTARY +*/ + +#include "fs.h" + +#include "readBits.h" +#include "initBlock.h" +#include "readCoef.h" + +int16 readCoef(encoding,bitStuff) BITTREE *encoding; BITSTRUCT *bitStuff; { +int16 coef; + + while (encoding->zero != NULL) { + if (readBits(1,bitStuff) == 0) { + encoding = encoding->zero; + } else { + encoding = encoding->one; + }; + }; + + if (encoding->value == LARGE_NEGATIVE) { + coef = readBits(15,bitStuff); + coef |= 0x8000; + } else { + if (encoding->value == LARGE_POSITIVE) { + coef = readBits(15,bitStuff); + coef &= 0x7FFF; + } else { + coef = encoding->value; + }; + }; + + return(coef); +} diff --git a/isis/src/mgs/apps/mocuncompress/readCoef.h b/isis/src/mgs/apps/mocuncompress/readCoef.h new file mode 100644 index 0000000000000000000000000000000000000000..7beb009a1be465071aa0d22130e1f8c40e75d054 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/readCoef.h @@ -0,0 +1,49 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)readCoef.h 1.1 10/04/99 +*/ +/* SCCShid @(#)readCoef.h (readCoef.h) 1.2 */ + +#if !defined(readCoef_h) + +#define readCoef_h + +extern int16 readCoef(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/readGroups.c b/isis/src/mgs/apps/mocuncompress/readGroups.c new file mode 100644 index 0000000000000000000000000000000000000000..ae5932851232b2c1c8086d1db4f76c2c557b80ab --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/readGroups.c @@ -0,0 +1,75 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)readGroups.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif +/* +* DESCRIPTION +* +* COMMENTARY +*/ + +#include +#include + +#include "fs.h" + +#include "readBits.h" +#include "readGroups.h" + +extern void exit(); + +uint32 *readGroups(numBlocks,bitStuff) register uint32 numBlocks; register BITSTRUCT *bitStuff; { +register uint32 block; +uint32 *groups; +register uint32 *scanGroups; + + if ((groups = (uint32 *)malloc((uint32)(numBlocks * sizeof(*groups)))) == NULL) { + (void)fprintf(stderr,"Not enough memory for decoding of image\n"); + exit(1); + }; + + scanGroups = groups; + + for (block = 0; block < numBlocks; block++) { + *(scanGroups++) = readBits(3,bitStuff); + }; + + return(groups); +} diff --git a/isis/src/mgs/apps/mocuncompress/readGroups.h b/isis/src/mgs/apps/mocuncompress/readGroups.h new file mode 100644 index 0000000000000000000000000000000000000000..c49c58531ba4232f34b87d29948c8874160a27e9 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/readGroups.h @@ -0,0 +1,49 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)readGroups.h 1.1 10/04/99 +*/ +/* SCCShid @(#)readGroups.h (readGroups.h) 1.2 */ + +#if !defined(readGroups_h) + +#define readGroups_h + +extern uint32 *readGroups(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/readmocisis.c b/isis/src/mgs/apps/mocuncompress/readmocisis.c new file mode 100644 index 0000000000000000000000000000000000000000..4fa3fd065c3496f3af77b865c63a6ba3d8dcd688 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/readmocisis.c @@ -0,0 +1,505 @@ +/* + +================================================== +2003-APR-17 Glenn Bennett - US Geological Survey + +Due to a conflict with XV - by John Bradley +- XV program also uses a version of this 'readmoc' +program ISIS system has renamed this file + + from: readmoc + to: readmocisis + +an accompanying program has also been renamed: + + from: readmocdrv + to: readmocdrvisis + +This will prevent problems encountered where two +packages have the same named underlying programs. +================================================== +================================================== +2003-OCT-15 Stuart Sides - US Geological Survey + +Converted calls to "gets" to "fgets" to satisfy +of compiler warning about "gets" being unsafe. These +calls were used to get the input and output filenames. +Changing from "gets" to "fgets" also required a check +to make sure there was no '\n' at the end of the input +string. +================================================== + + +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)readmocisis.c 1.2 04/10/00"; + +/* + SDP interpretation program + Mike Caplinger, MOC GDS Design Scientist + SCCS @(#)readmocisis.c 1.2 04/10/00 + + Reads and decompresses MOC SDP files to create PDS images. + Derived from the GDS readmsdp program. +*/ + +#include +#include +#include +#include +#include "image_io.h" +#include "array.h" +#include "msdp.h" + +extern FILE *write_header(int width, int height, + FILE *infile, char *outfname); +static int in;/*, out;*/ +static FILE *out; +static struct image_header inf; +static FILE *infile; +int errors; +static int test_pred; +static int rawencode = 0; + +static int verbose = 0; + +static int frag_offset[128]; + +static char infname[256], outfname[256]; +static int mbr = 0; + +byte *decode(); + +#define FRAGSIZE (256*1024) + +static char decode_file[128]; + +static unsigned int sync; + +static char label[1024]; + +static int status; +#define STAT_SHORT 2 +#define STAT_BADSEQ 4 +#define STAT_BADCS 8 + +enum { + RAW = 0, PRED, XFORM +} MocCompress = RAW; + +int main(argc, argv) +int argc; +char **argv; +{ + int height, width; + int frag_lines, n_frags; + pixel *frag; + int f; + float quant; + int actual_height; + int total_image = 0; + int total = 0; + int cs_check = 1; + int pad_cs = 0; + int i; + char s[8]; + int multi = 0; + int sequence = -1, processor = 0, n_processors = 1; + int last_frag = -1; + + sync = 0xf0ca; + + if (argc < 3) { + printf("\nEnter name of file to be decompressed: "); + fgets(infname,256,stdin); + int inLen = strlen(infname)-1; + if (inLen == '\n') infname[inLen] = '\0'; + printf("\nEnter name of uncompressed output file: "); + int outLen = strlen(outfname)-1; + if (outLen == '\n') outfname[outLen] = '\0'; + fgets(outfname,256,stdin); + } + else { + strcpy(infname, argv[1]); + strcpy(outfname, argv[2]); + } + + infile = fopen(infname, "r"); + if (infile == 0) { + fprintf(stderr, "Can't open %s\n", argv[1]); + } + + while (1) { + int count; + int len; + static int first = 1; + struct msdp_header h, lasth; + int datlen; + byte *indat, *chunk; + + lasth = h; + i = fseek(infile, total+2048, 0); + count = fread(&h, sizeof(h), 1, infile); + i = MAKELONG(h.len); + if (count && MAKELONG(h.len) == 0) { + /* simulate the EOF even though there's padding */ + count = 0; + h = lasth; + } + i = h.status&2; + if (count == 0 && MocCompress == PRED && (h.status&2) == 0) { + /* image was short -- last flag missing */ + h.status = 2; + frag = decode(h, indat, 0, &len, mbr); +/* write(out, frag, len);*/ + i = fwrite(frag, 1, len, out); + total_image += len; + } + if (count == 0) break; + if (MAKELONG(h.len) == 0) break; + sequence += 1; + + if (first && !multi) { + int edit[2]; + + width = h.edit_length*16; + init_output(h); + first = 0; + height = MAKESHORT(h.down_total)*16; + } + h.edit_length = width/16; + if (mbr) width = 512; + + datlen = MAKELONG(h.len); + + if (sequence%n_processors != processor) { + total += sizeof(struct msdp_header) + datlen + 1; + continue; + } + + if (!multi && MAKESHORT(h.fragment) != last_frag+1) { + int n_pad = MAKESHORT(h.fragment)-last_frag-1; + char *frag = (char *) malloc(240*1024); + /* don't pad predictively-compressed data */ + if (!(h.compression[0] & 3) && n_pad > 0) { + errors += 1; + status |= STAT_BADSEQ; + bzero(frag, 240*1024); + total_image += n_pad*240*1024; + if (verbose) fprintf(stderr, "padding %d frags\n", n_pad); +/* while(n_pad--) write(out, frag, 240*1024);*/ + while (n_pad--) i = fwrite(frag, 1, 240*1024, out); + } + free(frag); + } + last_frag = MAKESHORT(h.fragment); + + if (verbose) fprintf(stderr, "id %d/%d, len %d\n", MAKESHORT(h.id), + MAKESHORT(h.fragment), MAKELONG(h.len)); + chunk = (byte *) malloc(datlen+sizeof(struct msdp_header)+1); + indat = chunk+sizeof(struct msdp_header); + count = fread(indat, 1, datlen, infile); + if (count != datlen) { + if (verbose) fprintf(stderr, + "Error: short read (%d) of data part of fragment\n", + count); + errors += 1; + break; + } + + /* check MSDP checksum */ + if (cs_check) { + bcopy(&h, chunk, sizeof(h)); + fread(chunk+datlen+sizeof(h), 1, 1, infile); + if (!CS8EACC2(chunk, datlen+sizeof(h)+1)) { + if (verbose) fprintf(stderr, "Error: bad MSDP checksum\n"); + status |= STAT_BADCS; + errors += 1; + if (pad_cs) { + char *frag = (char *) malloc(240*1024); + bzero(frag, 240*1024); + total_image += 240*1024; + total += sizeof(struct msdp_header) + datlen + 1; + if (verbose) fprintf(stderr, "trashing bad frag\n"); +/* write(out, frag, 240*1024);*/ + i = fwrite(frag, 1, 240*1024, out); + free(frag); + continue; + } + } + } + + frag = decode(h, indat, datlen, &len, mbr); + i = sizeof(frag); + total_image += len; + if (verbose) fprintf(stderr, "fragment len %d => %d\n", datlen, len); + total += sizeof(struct msdp_header) + datlen + 1; +/* write(out, frag, len);*/ + i = fwrite(frag, 1, len, out); + if (0) free(frag); + free(chunk); + if (h.status&2) break; + } + fclose(out); + + actual_height = total_image/width; + if (!multi && actual_height != height) { + if (verbose) fprintf(stderr, + "Error: total MSDP height (%d) != actual height (%d)\n", + height, actual_height); + (void) write_header(width, actual_height, infile, outfname); + errors += 1; + status |= STAT_SHORT; + } + + if (status && verbose) fprintf(stderr, "error status %c%c%c%c\n", + MocCompress==RAW?'r':(MocCompress==PRED?'p':'t'), + status&STAT_BADCS?'c':'-', + status&STAT_BADSEQ?'n':'-', + status&STAT_SHORT?'s':'-' + ); + if (errors) exit((MocCompress << 4) | status | (errors?1:0)); + else exit(0); +} + +byte *decode(h, data, datlen, len, mbr) +struct msdp_header h; +byte *data; +int datlen, *len; +int mbr; +{ + int height, width; + unsigned int xcomp, pcomp, spacing, levels; + byte *transform_decomp_main(); + byte *predictive_decomp_main(); + byte *image; + static Array *tbuf; + static int init_decode; + int huffman_table; + + if (mbr) { + width = 512; + height = 480; + xcomp = 0; + pcomp = 0; + } + else { + width = h.edit_length*16; + height = MAKESHORT(h.down_length)*16; + xcomp = (h.compression[0] >> 2) & 3; + pcomp = (h.compression[0] & 3); + spacing = h.compression[4] | (h.compression[5] << 8); + levels = (h.compression[1] >> 5)+1; + huffman_table = h.compression[1]&0xf; + } + + *len = width*height; + + if (pcomp && xcomp) { + fprintf(stderr, "error: both pcomp and xcomp set\n"); + exit(1); + } + if (pcomp) MocCompress = PRED; + if (xcomp) MocCompress = XFORM; + + if (!rawencode && pcomp == 0 && xcomp == 0) { + /* raw image */ + image = data; + if (datlen > *len) { + if (verbose) fprintf(stderr, "Warning: MSDP line count (%d) < implied (%d), using latter\n", height, datlen/width); + *len = datlen; + height = datlen/width; + } + if (verbose) fprintf(stderr, "%d wide by %d high ", width, height); + if (verbose) fprintf(stderr, "raw fragment%s\n", mbr?" (MBR)":""); + } + else + if (verbose) fprintf(stderr, "%d wide by %d high ", width, height); + + if (xcomp > 0) { + /* transform compressed; 2 = DCT, 1 = WHT */ + if (verbose) fprintf(stderr, "%s transformed fragment (%d groups, %.2f requant)\n", + xcomp == 2 ? "dct" : "wht", levels, spacing/16.0); + image = transform_decomp_main(data, datlen, height, width, + xcomp-1, spacing, levels); + } + + if (rawencode || pcomp > 0) { + /* predictively compressed */ + if (rawencode) + if (verbose) fprintf(stderr, "raw encoded fragment\n"); + else + if (verbose) fprintf(stderr, "%s%s predictive fragment, table %d\n", + pcomp&1 ? "x" : "", (pcomp&2)>>1 ? "y" : "", + huffman_table); + + /* set up decode arrays */ + if (!init_decode) { + if (*decode_file) decodeLoad(decode_file); + else decodeInit(huffman_table); + } + + if (test_pred) { + int dummy; + + image = predictive_decomp_main(data, datlen, height, width, + (sync != 0), sync, + pcomp&1, (pcomp&2) >> 1, + &dummy); + } + else { + /* squirrel data away */ + if (!tbuf) tbuf = array_new(datlen*8); + if (datlen && !array_append(tbuf, data, datlen)) { + // FIXED 2008/10/29, "datalen" was part of the print statement and no arguments + // were provided for the %d. - Steven Lambright, pointed out by "novas0x2a" (Support Forum Member) + fprintf(stderr, "can't allocate temp space (%d bytes)\n", datlen); + exit(1); + } + image = 0; + *len = 0; + if (h.status & 2) { + int got_height; + extern int pred_past_eof; + int want_h = MAKESHORT(h.down_total)*16;; + if (verbose) fprintf(stderr, "decompressing %d wide by %d high image\n", + width, want_h); + image = + predictive_decomp_main(array_data(tbuf), + array_len(tbuf), + want_h, width, + (sync != 0), sync, + pcomp&1, (pcomp&2) >> 1, + &got_height); + /* This is tricky. We can get bad sync even without + checksum errors if anomaly 8 occurs. We want to + distinguish between this case and the case where + we just ran out of fragments during the NA image. + So if we run into a sync error and haven't run off + the end of the image, we force BADCS on. */ + if (got_height != want_h && !pred_past_eof) + status |= STAT_BADCS; + *len = got_height * width; + } + } + } + + return image; +} + +int worklist_init() { + struct msdp_header h; + int count; + int frag; + int height, width, xcomp; + int datlen; + + while (1) { + count = fread(&h, sizeof(h), 1, infile); + if (count == 0) break; + xcomp = (h.compression[0] >> 2) & 3; + if (!xcomp) return 0; + height = MAKESHORT(h.down_length)*16; + width = h.edit_length*16; + datlen = MAKELONG(h.len); + init_output(h); + frag_offset[frag+1] = frag_offset[frag]+height*width; + frag += 1; + fseek(infile, datlen+1, 1); + } + return 1; +} + +int init_output(h) +struct msdp_header h; +{ + int height, width; + char s[8]; + int i; + char buf[1024]; + + height = MAKESHORT(h.down_total)*16; + width = h.edit_length*16; + sprintf(label, "decompressed-from %s\nid %d time %u:%d\ngain 0x%x \ +offset %d\nstart %d cross %d down %d\ncmd ", infname, + MAKESHORT(h.id), + MAKELONG(h.time+1), h.time[0], + h.gain, h.offset, + h.edit_start*16, + h.edit_length*16, + MAKESHORT(h.down_total)*16); + switch (h.cmd[0]) { + case 1: + case 2: + strcat(label, "na "); + break; + case 3: + case 4: + strcat(label, "wa "); + break; + case 5: + case 6: + strcat(label, "global-map "); + break; + case 0x15: + case 0x16: + strcat(label, "mbr "); + mbr = 1; + width = 512; + height = 512; + break; + case 0xd: + strcat(label, "read-memory "); + break; + default: + strcat(label, "unknown "); + break; + } + for (i = 0; i < 17; i++) { + sprintf(s, "%02x", h.cmd[i]); + strcat(label, s); + } + + sprintf(buf, "\nsensor %d clocking %d system-id 0x%x", + MAKESHORT(h.sensors), + MAKESHORT(h.other+1), + h.other[3]); + strcat(label, buf); + + out = (FILE *) write_header(width, height, infile, outfname); +} diff --git a/isis/src/mgs/apps/mocuncompress/reorder.c b/isis/src/mgs/apps/mocuncompress/reorder.c new file mode 100644 index 0000000000000000000000000000000000000000..d1025e53e4ab94ab9c340d6cd9edc28bc9c59146 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/reorder.c @@ -0,0 +1,103 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)reorder.c 1.1 10/04/99"; +#if (!defined(NOSCCSID) && (!defined(LINT))) +#endif +/* +* DESCRIPTION +* +* COMMENTARY +*/ + +#include "fs.h" +#include "reorder.static.h" + +#include "reorder.h" + +void reorder(block) int16 *block; { +int16 temp[256]; +register int16 *scanBlock,*scanTemp; +register uint8 *scanTrans; +register uint32 i; + + scanBlock = block; + scanTrans = trans; + scanTemp = temp; + + for (i = 0; i < 16; i++) { + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + *(scanTemp++) = scanBlock[*(scanTrans++)]; + }; + + scanBlock = block; + scanTemp = temp; + + for (i = 0; i < 16; i++) { + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + *(scanBlock++) = *(scanTemp++); + }; +} diff --git a/isis/src/mgs/apps/mocuncompress/reorder.h b/isis/src/mgs/apps/mocuncompress/reorder.h new file mode 100644 index 0000000000000000000000000000000000000000..ce2d3df4992f81e958659cd18f67b1fff4bc1359 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/reorder.h @@ -0,0 +1,49 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)reorder.h 1.1 10/04/99 +*/ +/* SCCShid @(#)reorder.h (reorder.h) 1.2 */ + +#if !defined(reorder_h) + +#define reorder_h + +extern void reorder(); + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/reorder.static.h b/isis/src/mgs/apps/mocuncompress/reorder.static.h new file mode 100644 index 0000000000000000000000000000000000000000..860309601957b9152d6d20bd1720cc57d9161111 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/reorder.static.h @@ -0,0 +1,94 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)reorder.static.h 1.1 10/04/99 +*/ +/* This file was automatically generated by 'makeOrder' */ + +#if !defined(reorder_static_h) + +#define reorder_static_h + +#include "fs.h" + +/* +* Translation table for going from row ordered vector to +* radially order vector +*/ +static uint8 trans[256] = { + 0, 1, 4, 9, 15, 22, 33, 43, 56, 71, 86,104,121,142,166,189, + 2, 3, 6, 11, 17, 26, 35, 45, 58, 73, 90,106,123,146,168,193, + 5, 7, 8, 13, 20, 28, 37, 50, 62, 75, 92,108,129,150,170,195, + 10, 12, 14, 19, 23, 31, 41, 52, 65, 81, 96,113,133,152,175,201, + 16, 18, 21, 24, 30, 39, 48, 59, 69, 83,100,119,137,158,181,203, + 25, 27, 29, 32, 40, 46, 54, 67, 79, 94,109,127,143,164,185,210, + 34, 36, 38, 42, 49, 55, 64, 76, 87,102,117,135,154,176,197,216, + 44, 47, 51, 53, 60, 68, 77, 85, 98,114,131,147,162,183,208,222, + 57, 61, 63, 66, 70, 80, 88, 99,112,124,140,159,179,199,214,227, + 72, 74, 78, 82, 84, 95,103,115,125,139,156,173,190,211,224,233, + 89, 91, 93, 97,101,110,118,132,141,157,171,186,206,220,231,239, +105,107,111,116,120,128,136,148,160,174,187,205,218,229,237,244, +122,126,130,134,138,144,155,163,180,191,207,219,226,235,242,248, +145,149,151,153,161,165,177,184,200,212,221,230,236,241,246,251, +167,169,172,178,182,188,198,209,215,225,232,238,243,247,250,253, +192,194,196,202,204,213,217,223,228,234,240,245,249,252,254,255, +}; + +#ifdef TEST +/* Table for checking reordering */ +static uint8 index[256] = { + 0, 1, 16, 17, 2, 32, 18, 33, 34, 3, 48, 19, 49, 35, 50, 4, + 64, 20, 65, 51, 36, 66, 5, 52, 67, 80, 21, 81, 37, 82, 68, 53, + 83, 6, 96, 22, 97, 38, 98, 69, 84, 54, 99, 7,112, 23, 85,113, + 70,100, 39,114, 55,115, 86,101, 8,128, 24, 71,116,129, 40,130, +102, 56,131, 87,117, 72,132, 9,144, 25,145, 41,103,118,146, 88, +133, 57,147, 73,148,119, 10,104,134,160, 26,161, 42,162, 89,149, + 58,163,120,135, 74,164,105,150, 11,176, 27,177, 43, 90,165,178, +136, 59,121,151,179,106,166, 75,180, 12,192, 28,137,152,193, 91, +181, 44,194,122,167, 60,195,107,182, 76,196,153,138,168, 13, 92, +197,208, 29,123,183,209, 45,210, 61,211,108,198,154,169, 77,139, +184,212,124,199, 93,213, 14,224, 30,225, 46,170,226,155,185, 62, +109,214,227,140,200, 78,228,125,215, 94,171,186,229, 15,156,201, +240, 31,241, 47,242,110,230,141,216, 63,243, 79,244,187,172,202, +126,231, 95,157,217,245,142,232,111,246,188,203,173,218,127,247, +158,233,204,143,248,189,219,174,234,159,249,205,220,190,235,175, +250,221,206,236,191,251,222,237,207,252,238,223,253,239,254,255, +}; +#endif + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/tsts/Makefile b/isis/src/mgs/apps/mocuncompress/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mgs/apps/mocuncompress/tsts/case01/Makefile b/isis/src/mgs/apps/mocuncompress/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e68be5ef32251467434ff4bbcafeba7397e5b085 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/tsts/case01/Makefile @@ -0,0 +1,7 @@ +APPNAME = mocuncompress + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) $(INPUT)/m0402852.imq $(OUTPUT)/temp.imq > /dev/null; + pds2isis from=$(OUTPUT)/temp.imq to=$(OUTPUT)/mocuncompressTruth.cub > /dev/null; diff --git a/isis/src/mgs/apps/mocuncompress/types.h b/isis/src/mgs/apps/mocuncompress/types.h new file mode 100644 index 0000000000000000000000000000000000000000..5bb6ef8f1ec2bd4eda0df9c71cf9d47a36ca76f9 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/types.h @@ -0,0 +1,83 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. + +SCCSID @(#)types.h 1.1 10/04/99 +*/ +/* SCCShid @(#)types.h (types.h) 1.1 */ + +#if !defined(types_h) + +#define types_h + +/* 'real' data types */ + +typedef unsigned char cr; +typedef short sr; +typedef int ir; +typedef float fr; +typedef double dr; + +/* 'complex' data types */ + +typedef struct char_complex cc; +typedef struct short_complex sc; +typedef struct int_complex ic; +typedef struct float_complex fc; +typedef struct double_complex dc; + +struct char_complex { unsigned char r,i; }; +struct short_complex { short r,i; }; +struct int_complex { int r,i; }; +struct float_complex { float r,i; }; +struct double_complex { double r,i; }; + +/* Header constant (the third) flagging picture data type */ + +#define CHAR_REAL 0 +#define SHORT_REAL 1 +#define INT_REAL 2 +#define FLOAT_REAL 3 +#define DOUBLE_REAL 4 + +#define CHAR_COMPLEX 5 +#define SHORT_COMPLEX 6 +#define INT_COMPLEX 7 +#define FLOAT_COMPLEX 8 +#define DOUBLE_COMPLEX 9 + +#endif diff --git a/isis/src/mgs/apps/mocuncompress/xmain.c b/isis/src/mgs/apps/mocuncompress/xmain.c new file mode 100644 index 0000000000000000000000000000000000000000..2daf3ccc6c2e126f07509899fd4d5c1079a4b535 --- /dev/null +++ b/isis/src/mgs/apps/mocuncompress/xmain.c @@ -0,0 +1,171 @@ +/* +NOTICE + +The software accompanying this notice (the "Software") is provided to you +free of charge to facilitate your use of the data collected by the Mars +Orbiter Camera (the "MOC Data"). Malin Space Science Systems ("MSSS") +grants to you (either as an individual or entity) a personal, +non-transferable, and non-exclusive right (i) to use and reproduce the +Software solely for the purpose of accessing the MOC Data; (ii) to modify +the source code of the Software as necessary to maintain or adapt the +Software to run on alternate computer platforms; and (iii) to compile, use +and reproduce the modified versions of the Software solely for the purpose +of accessing the MOC Data. In addition, you may distribute the Software, +including any modifications thereof, solely for use with the MOC Data, +provided that (i) you must include this notice with all copies of the +Software to be distributed; (ii) you may not remove or alter any +proprietary notices contained in the Software; (iii) you may not charge any +third party for the Software; and (iv) you will not export the Software +without the appropriate United States and foreign government licenses. + +You acknowledge that no title to the intellectual property in the Software +is transferred to you. You further acknowledge that title and full +ownership rights to the Software will remain the exclusive property of MSSS +or its suppliers, and you will not acquire any rights to the Software +except as expressly set forth above. The Software is provided to you AS +IS. MSSS MAKES NO WARRANTY, EXPRESS OR IMPLIED, WITH RESPECT TO THE +SOFTWARE, AND SPECIFICALLY DISCLAIMS THE IMPLIED WARRANTIES OF +NON-INFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR +LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO SUCH LIMITATIONS OR +EXCLUSIONS MAY NOT APPLY TO YOU. + +Your use or reproduction of the Software constitutes your agreement to the +terms of this Notice. If you do not agree with the terms of this notice, +promptly return or destroy all copies of the Software in your possession. + +Copyright (C) 1999 Malin Space Science Systems. All Rights Reserved. +*/ +static char *sccsid = "@(#)xmain.c 1.1 10/04/99"; + +/* + MOC transform decompressor main routine + Mike Caplinger, MOC GDS Design Scientist + SCCS @(#)main.c 1.2 1/5/94 + + Adapted from a version by Terry Ligocki with SCCS + @(#)decompress.c (decompress.c) 1.6 +*/ + +#include +#include +#include +#include + +#include "fs.h" +#include "types.h" + +#include "readBits.h" +#include "readGroups.h" +#include "initBlock.h" +#include "readBlock.h" + +extern void exit(); + +jmp_buf on_error; + +uint8 *transform_decomp_main(data, len, height, width, transform, spacing, numLevels) +uint8 *data; +int height, width; +uint32 transform; +uint32 spacing; +uint32 numLevels; +{ + +uint32 xSize = width, ySize = height; +uint32 level; +uint32 numBlocks; +uint8 *image; +int32 hsize; +int32 header[3]; +BITSTRUCT *bitStuff; +uint32 *groups; +uint32 *occ; +uint32 x,y; +uint32 var[256]; +int used; + + bitStuff = initBits(data, len); + + if ((image = (uint8 *)malloc((uint32)(xSize * ySize * sizeof(*image)))) == NULL) { + (void)fprintf(stderr,"Not enough memory for image\n"); + return; + }; + + if ((occ = (uint32 *)malloc((uint32)(numLevels * sizeof(*occ)))) == NULL) { + (void)fprintf(stderr,"Not enough memory to decoding of image\n"); + return; + }; + + for (level = 0; level < numLevels; level++) { + occ[level] = 0; + }; + + if(setjmp(on_error)) { + goto out; + } + + numBlocks = (xSize * ySize) >> 8; + + groups = readGroups(numBlocks,bitStuff); + + { + uint32 block; + uint32 *scanGroups; + + scanGroups = groups; + + for (block = 0; block < numBlocks; block++) { + if (*scanGroups >= numLevels) { + (void)fprintf(stderr,"Group level too large: %d > %d\n",*scanGroups,numLevels-1); + bzero(image, width*height); + return image; + }; + + occ[*(scanGroups++)]++; + }; + }; + + initBlock(); + + for (level = 0; level < numLevels; level++) { + if (occ[level] != 0) { + uint16 minDC,maxDC,rangeDC; + uint32 *scanGroups,*scanVar; + uint32 i; + + minDC = readBits(16,bitStuff); + maxDC = readBits(16,bitStuff); + + rangeDC = maxDC - minDC; + + scanVar = var+1; + + for (i = 1; i < 256; i++) { + *(scanVar++) = readBits(3,bitStuff); + }; + + scanGroups = groups; + + for (x = 0; x < xSize; x += 16) { + for (y = 0; y < ySize; y += 16) { + if (*(scanGroups++) == level) { + readBlock(transform,spacing,minDC,rangeDC,var,x,y,xSize,image,bitStuff); + }; + }; + }; + }; + }; + + /* note that under some normal circumstances byteCount can get + reset to 0 -- this is OK, problems will be indicated by an + EOF from readBits above somewhere. */ + used = bitStuff->byteCount; + if(used != len && used > 0) { + fprintf(stderr, "Error: only used %d bytes out of %d\n", + used, len); + } +out: free(occ); + freeAllTrees(); + return image; +} diff --git a/isis/src/mgs/objs/Makefile b/isis/src/mgs/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/mgs/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/mgs/objs/MocLabels/Makefile b/isis/src/mgs/objs/MocLabels/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ef05fba04b6636e67c1f7442286223c1ca0fa1e7 --- /dev/null +++ b/isis/src/mgs/objs/MocLabels/Makefile @@ -0,0 +1,5 @@ +INCS = MocLabels.h +SRCS = MocLabels.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/mgs/objs/MocLabels/MocLabels.cpp b/isis/src/mgs/objs/MocLabels/MocLabels.cpp new file mode 100644 index 0000000000000000000000000000000000000000..777fc0abdacbb63f8caa444887e699c1189b07e7 --- /dev/null +++ b/isis/src/mgs/objs/MocLabels/MocLabels.cpp @@ -0,0 +1,600 @@ +#include +#include +#include +#include +#include + +#include "MocLabels.h" +#include "iException.h" +#include "iException.h" +#include "iString.h" +#include "iTime.h" +#include "mocxtrack.h" +#include "TextFile.h" +#include "AlphaCube.h" + +using namespace std; +namespace Isis { + namespace Mgs { + /** + * Construct MocLabels object using the file name + */ + MocLabels::MocLabels(const string &file) { + Pvl lab(file); + Init(lab); + } + + /** + * Construct MocLabels object using a Pvl object + */ + MocLabels::MocLabels(Pvl &lab) { + Init(lab); + } + + /** + * General initializer + * @param lab MOC label for the image + */ + void MocLabels::Init(Pvl &lab) { + // Initialize gain tables + InitGainMaps(); + + try { + ReadLabels(lab); + ValidateLabels(); + Compute(); + } + catch (iException &e) { + string msg = "Labels do not appear contain a valid MOC instrument"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + } + /** + * Reads required keywords from the labels + * @param MOC label for the image + */ + void MocLabels::ReadLabels(Pvl &lab) { + // Get stuff out of the instrument group + PvlGroup &inst = lab.FindGroup("Instrument",Pvl::Traverse); + p_instrumentId = (string) inst["InstrumentId"]; + p_startingSample = inst["FirstLineSample"]; + p_crosstrackSumming = inst["CrosstrackSumming"]; + p_downtrackSumming = inst["DowntrackSumming"]; + p_exposureDuration = inst["LineExposureDuration"]; + p_focalPlaneTemp = inst["FocalPlaneTemperature"]; + p_clockCount = (string) inst["SpacecraftClockCount"]; + p_orbitNumber = 0; + if (inst.HasKeyword("OrbitNumber")) { + p_orbitNumber = inst["OrbitNumber"]; + } + p_gainModeId = (string) inst["GainModeId"]; + p_offsetModeId = inst["OffsetModeId"]; + p_startTime = (string) inst["StartTime"]; + + // Get stuff out of the archive group + p_dataQuality = "Unknown"; + PvlGroup &arch = lab.FindGroup("Archive",Pvl::Traverse); + if (arch.HasKeyword("DataQualityDesc")) { + p_dataQuality = (string) arch["DataQualityDesc"]; + } + + // Get Stuff out of the band bind group + PvlGroup &bandBin = lab.FindGroup("BandBin",Pvl::Traverse); + p_filter = (string) bandBin["FilterName"]; + + // Get the number of samples in the initial cube as it may have been + // cropped or projected + AlphaCube a(lab); + p_ns = a.AlphaSamples(); + p_nl = a.AlphaLines(); + + // Get the two kernels for time computations + PvlGroup &kerns = lab.FindGroup("Kernels",Pvl::Traverse); + p_lsk = kerns["LeapSecond"]; + p_sclk = kerns["SpacecraftClock"]; + } + + /** + * Verifies that the labels are valid + */ + void MocLabels::ValidateLabels() { + // Validate the camera type + p_mocNA = false; + p_mocRedWA = false; + p_mocBlueWA = false; + + if (p_instrumentId == "MOC-NA") p_mocNA = true; + if (p_instrumentId == "MOC-WA") { + if (p_filter == "RED") p_mocRedWA = true; + if (p_filter == "BLUE") p_mocBlueWA = true; + } + + if (!p_mocNA && !p_mocRedWA && !p_mocBlueWA) { + string msg = "InstrumentID [" + p_instrumentId + "] and/or FilterName [" + + p_filter + "] are inappropriate for the MOC camera"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + + // Validate summing modes for narrow angle camera + if (p_mocNA) { + if ((p_crosstrackSumming < 1) || (p_crosstrackSumming > 8)) { + string msg = "MOC-NA keyword [CrosstrackSumming] must be between "; + msg += "1 and 8, but is [" + iString(p_crosstrackSumming) + "]"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + + if ((p_downtrackSumming < 1) || (p_downtrackSumming > 8)) { + string msg = "MOC-NA keyword [DowntrackSumming] must be between "; + msg += "1 and 8, but is [" + iString(p_downtrackSumming) + "]"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + } + + // Validate summing modes for the wide angle camera + if ((p_mocRedWA) || (p_mocBlueWA)) { + if ((p_crosstrackSumming < 1) || (p_crosstrackSumming > 127)) { + string msg = "MOC-WA keyword [CrosstrackSumming] must be between "; + msg += "1 and 127, but is [" + iString(p_crosstrackSumming) + "]"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + + if ((p_downtrackSumming < 1) || (p_downtrackSumming > 127)) { + string msg = "MOC-WA keyword [DowntrackSumming] must be between "; + msg += "1 and 127, but is [" + iString(p_downtrackSumming) + "]"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + } + } + /** + * Computes some constants + */ + void MocLabels::Compute() { + // Compute line rate in seconds + p_trueLineRate = p_exposureDuration * (double) p_downtrackSumming; + p_trueLineRate /= 1000.0; + + // Fix the exposure duration for NA images + if (NarrowAngle() && (p_downtrackSumming != 1)) { + p_exposureDuration *= p_downtrackSumming; + } + + // Lookup the gain using the gain mode in the gain maps + map::iterator p; + if (NarrowAngle()) { + p = p_gainMapNA.find(p_gainModeId); + if (p == p_gainMapNA.end()) { + string msg = "Invalid value for keyword GainModeId [" + + p_gainModeId + "]"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + } + else { + p = p_gainMapWA.find(p_gainModeId); + if (p == p_gainMapWA.end()) { + string msg = "Invalid value for keyword GainModeId [" + + p_gainModeId + "]"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + } + p_gain = p->second; + + // Compute the offset using the offset mode id + p_offset = p_offsetModeId * 5.0; + + // Ok the gain computation for narrow angle changed from + // pre-mapping to mapping phase. Fix it up if necessary + // (when the Downtrack summing is not 1) + if (NarrowAngle() && (p_downtrackSumming != 1)) { + iTime currentTime(p_startTime); + iTime mappingPhaseBeginTime("1999-04-03T01:00:40.441"); + if (currentTime < mappingPhaseBeginTime) { + double newGain = p_gain / (double) p_downtrackSumming; + double mindiff = DBL_MAX; + map::iterator p; + string index = ""; + p = p_gainMapNA.begin(); + while (p != p_gainMapNA.end()) { + double diff = abs(newGain - p->second); + if (diff < mindiff) { + index = p->first; + mindiff = diff; + } + + p ++; + } + + p = p_gainMapNA.find(index); + if (p == p_gainMapNA.end()) { + string msg = "Could not find new gain for pre-mapping narrow angle image"; + throw iException::Message(iException::Pvl,msg,_FILEINFO_); + } + p_gain = p->second; + } + } + + // Initialize the maps from sample coordinate to detector coordinates + InitDetectorMaps(); + + // Temporarily load some naif kernels + string lsk = p_lsk.Expanded(); + string sclk = p_sclk.Expanded(); + furnsh_c(lsk.c_str()); + furnsh_c(sclk.c_str()); + + // Compute the starting ephemeris time + scs2e_c(-94,p_clockCount.c_str(),&p_etStart); + p_etEnd = EphemerisTime((double)p_nl); + + // Unload the naif kernels + unload_c(lsk.c_str()); + unload_c(sclk.c_str()); + } + +/** + * Creates a lookup of gain modes to gain values. These come + * from the MSSS calibration report. + */ + void MocLabels::InitGainMaps() { + p_gainMapNA["F2"] = 1.0; + p_gainMapNA["D2"] = 1.456; + p_gainMapNA["B2"] = 2.076; + p_gainMapNA["92"] = 2.935; + p_gainMapNA["72"] = 4.150; + p_gainMapNA["52"] = 5.866; + p_gainMapNA["32"] = 8.292; + p_gainMapNA["12"] = 11.73; + p_gainMapNA["EA"] = 7.968; + p_gainMapNA["CA"] = 11.673; + p_gainMapNA["AA"] = 16.542; + p_gainMapNA["8A"] = 23.386; + p_gainMapNA["6A"] = 33.067; + p_gainMapNA["4A"] = 46.740; + p_gainMapNA["2A"] = 66.071; + p_gainMapNA["0A"] = 93.465; + + p_gainMapWA["9A"] = 1.0; + p_gainMapWA["8A"] = 1.412; + p_gainMapWA["7A"] = 2.002; + p_gainMapWA["6A"] = 2.832; + p_gainMapWA["5A"] = 4.006; + p_gainMapWA["4A"] = 5.666; + p_gainMapWA["3A"] = 8.014; + p_gainMapWA["2A"] = 11.34; + p_gainMapWA["1A"] = 16.03; + p_gainMapWA["0A"] = 22.67; + p_gainMapWA["96"] = 16.030; + p_gainMapWA["86"] = 22.634; + p_gainMapWA["76"] = 32.092; + p_gainMapWA["66"] = 45.397; + p_gainMapWA["56"] = 64.216; + p_gainMapWA["46"] = 90.826; + p_gainMapWA["36"] = 128.464; + p_gainMapWA["26"] = 181.780; + p_gainMapWA["16"] = 256.961; + p_gainMapWA["06"] = 363.400; + }; + + /** + * Converts from sample to starting detector + * @param sample Sample to be converted + * @returns @b int Converted start detector + */ + int MocLabels::StartDetector(int sample) const { + if ((sample < 1) || (sample > p_ns)) { + string msg = "Out of array bounds in MocLabels::StartDetector"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + return p_startDetector[sample-1]; + } + /** + * Converts from sample to ending detector + * @param sample Sample to be converted + * @returns @b int Converted ending detector + */ + int MocLabels::EndDetector(int sample) const { + if ((sample < 1) || (sample > p_ns)) { + string msg = "Out of array bounds in MocLabels::EndDetector"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + return p_endDetector[sample-1]; + } + /** + * Converts from detector to sample + * @param detector Detector to be converted + * @returns @b double Converted sample + */ + double MocLabels::Sample(int detector) const { + if ((detector < 0) || (detector >= Detectors())) { + string msg = "Out of array bounds in MocLabels::Sample"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + return p_sample[detector]; + } + /** + * Creates lookup table from sample to detectors and vice versa. + */ + void MocLabels::InitDetectorMaps() { + // Create sample to detector maps + if (p_crosstrackSumming == 13) { + for (int i=0; i=0; i--) { + if (etLine >= p_wagos[i].et) { + return p_wagos[i].gain; + } + } + + return p_gain; + } + /** + * Returns the offset at the given line. + * @param line Line to evaluate + * @returns @b double Offset + */ + double MocLabels::Offset(int line) { + if (NarrowAngle()) return p_offset; + InitWago(); + + double etLine = EphemerisTime((double)line); + for (int i=(int)p_wagos.size()-1; i>=0; i--) { + if (etLine >= p_wagos[i].et) { + return p_wagos[i].offset; + } + } + return p_offset; + } + /** + * Reads the wide-angle gain/offset table and internalizes + * @internal + * @history 2010-01-05 Jeannie Walldren - Fixed bug that + * passed sclkKern + * filename into + * scs2e_c instead of + * the sclk string. + */ + void MocLabels::InitWago() { + // Only do this once + static bool firstTime = true; + if (!firstTime) return; + firstTime = false; + + // Load naif kernels + string lskKern = p_lsk.Expanded(); + string sclkKern = p_sclk.Expanded(); + furnsh_c(lskKern.c_str()); + furnsh_c(sclkKern.c_str()); + + //Set up file for reading + Filename wagoFile("$mgs/calibration/MGSC_????_wago.tab"); + wagoFile.HighestVersion(); + string nameOfFile = wagoFile.Expanded(); + ifstream temp(nameOfFile.c_str()); + vector wholeFile; + + // Read file into a vector of bytes, ignoring EOL chars + while (temp.good()) { + int nextByte = temp.get(); + if ( nextByte != 10 && nextByte != 13) { + wholeFile.push_back(nextByte); + } + } + temp.close(); + + //Set up to binary search for the desired time + int low = 1; + int high = wholeFile.size()/35; + int middle; + iString line,filter,sclk,gainId,offsetId; + WAGO wago; + + //Binary search. This determines the middle of the current range and + //moves through the file until it reaches that line, at which point it + //analyzes to see if the time is within the set limits. + while( low <= high) { + middle = (low + high) / 2; + int SclkStart = middle*35 + 8; + int SclkEnd = SclkStart + 15; + string currentSclk; + + //Build sclk string and convert to an actual time + for (int i=SclkStart; i p_etStart) { + int linenum = middle; + int top = middle; + int bottom = middle; + + //First, find the highest line that will meet requirements + while (et >= p_etStart) { + linenum--; + int lineStart = (linenum*35); + int lineEnd = lineStart+35; + + string currentLine = ""; + for (int i=lineStart; i::iterator p; + p = p_gainMapWA.find(gainId); + if (p == p_gainMapWA.end()) { + // Unload the naif kernels + unload_c(lskKern.c_str()); + unload_c(sclkKern.c_str()); + + string msg = "Invalid GainModeId [" + gainId + "] in wago table"; + throw iException::Message(iException::Programmer,msg,_FILEINFO_); + } + double gain = p->second; + + // Compute the offset + double offset = offsetId.ToDouble() * 5.0; + + // Push everything onto a stack + wago.et = et; + wago.gain = gain; + wago.offset = offset; + p_wagos.push_back(wago); + + } + + low = high++; + } + //If we're too high, search beginning of array + else if( et < p_etStart ){ + low = middle + 1; + } + //If we're too low, search end of array + else { + high = middle- 1; + } + } + + // Ok sort and unique the wago list by time + sort(p_wagos.begin(),p_wagos.end()); + unique(p_wagos.begin(),p_wagos.end()); + + // Unload the naif kernels + unload_c(lskKern.c_str()); + unload_c(sclkKern.c_str()); + } + } +} diff --git a/isis/src/mgs/objs/MocLabels/MocLabels.h b/isis/src/mgs/objs/MocLabels/MocLabels.h new file mode 100644 index 0000000000000000000000000000000000000000..8efbc3d96c3b5272caa7a80668a537f77d526edd --- /dev/null +++ b/isis/src/mgs/objs/MocLabels/MocLabels.h @@ -0,0 +1,190 @@ +#ifndef MocLabels_h +#define MocLabels_h +/** + * @file + * $Revision: 1.8 $ + * $Date: 2010/01/05 20:56:07 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "Filename.h" + + +namespace Isis { + class Pvl; + namespace Mgs { + /** + * @brief Read values from MOC labels + * + * @ingroup MarsGlobalSurveyor + * @author 2007-01-30 Author Unknown + * + * @internal + * @history 2008-04-30 Steven Lambright corrected infinite loop + * @history 2008-05-29 Steven Lambright Fixed binary search indexing, + * bad calls to std::string::_cstr() references + * @history 2008-06-18 Steven Koechle - Fixed Documentation Errors + * @history 2008-08-11 Steven Lambright - Fixed definition of WAGO, + * problem pointed out by "novas0x2a" (Support Board Member) + * @history 2008-11-05 Jeannie Walldren - Changed + * IsNarrowAngle(), IsWideAngle(), IsWideAngleBlue(), + * and IsWideAngleRed() to NarrowAngle(), + * WideAngle(), WideAngleBlue(), and WideAngleRed(), + * respectively. Added documentation. + * @history 2008-11-07 Jeannie Walldren - Fixed documentation + * @history 2010-01-05 Jeannie Walldren - Fixed bug in + * InitWago() method. + */ + class MocLabels { + public: + MocLabels (Pvl &lab); + MocLabels (const std::string &file); + //! Empty destructor. + ~MocLabels () {}; + + /** + * Indicates whether the camera was narrow angle. + * @return @b bool True if the instrument ID is MOC-NA. + */ + inline bool NarrowAngle () const { return p_mocNA; }; + /** + * Indicates whether the camera was wide angle. + * @return @b bool True if the instrument ID is MOC-WA. + */ + inline bool WideAngle () const { return !p_mocNA; }; + /** + * Indicates whether the camera was red wide angle. + * @return @b bool True if the instrument ID is MOC-WA and + * filter name is RED. + */ + inline bool WideAngleRed () const { return p_mocRedWA; }; + /** + * Indicates whether the camera was blue wide angle. + * @return @b bool True if the instrument ID is MOC-WA and + * filter name is BLUE. + */ + inline bool WideAngleBlue () const { return p_mocBlueWA; }; + /** + * Returns value for CrosstrackSumming from the instrument + * group. + * @return @b int Crosstrack summing + */ + inline int CrosstrackSumming () const { return p_crosstrackSumming; }; + /** + * Returns value for DowntrackSumming from the instrument group. + * @return @b int Downtrack summing + */ + inline int DowntrackSumming () const { return p_downtrackSumming; }; + /** + * Returns value for FirstLineSample from the instrument group. + * @return @b int First line sample + */ + inline int FirstLineSample () const { return p_startingSample; }; + /** + * Returns value for FocalPlaneTemperature from the instrument + * group. + * @return @b double Focal plane temperature + */ + inline double FocalPlaneTemperature () const { return p_focalPlaneTemp; }; + /** + * Returns the value for the true line rate. This is calculated + * by dividing the product of LineExposureDuration and the + * DowntrackSumming by 1000. + * @return @b double Value for the true line rate + */ + inline double LineRate () const { return p_trueLineRate; }; + /** + * Returns the value for LineExposureDuration from the + * instrument group. + * @return @b double Line exposure duration + */ + inline double ExposureDuration() const { return p_exposureDuration; }; + /** + * Returns the value for StartTime from the instrument group. + * @return @b std::string Start time + */ + inline std::string StartTime() const { return p_startTime; }; + /** + * Returns 2048 if narrow angle and 3456 if wide angle. + * @return @b int Value of detectors. + */ + inline int Detectors() const { return p_mocNA ? 2048 : 3456; }; + int StartDetector(int sample) const; + int EndDetector(int sample) const; + double Sample(int detector) const; + double EphemerisTime(double line) const; + double Gain(int line=1); + double Offset(int line=1); + + private: + void Init (Pvl &lab); + void ReadLabels (Pvl &lab); + void ValidateLabels (); + void Compute(); + + int p_crosstrackSumming; + int p_downtrackSumming; + int p_startingSample; + int p_orbitNumber; + double p_exposureDuration; + double p_trueLineRate; + double p_focalPlaneTemp; + bool p_mocNA; + bool p_mocRedWA; + bool p_mocBlueWA; + std::string p_instrumentId; + std::string p_filter; + std::string p_clockCount; + std::string p_gainModeId; + int p_offsetModeId; + std::string p_startTime; + std::string p_dataQuality; + double p_etStart; + double p_etEnd; + + void InitGainMaps(); + std::map p_gainMapNA; + std::map p_gainMapWA; + double p_gain; + double p_offset; + + int p_nl; + int p_ns; + int p_startDetector[3456]; + int p_endDetector[3456]; + double p_sample[3456]; + void InitDetectorMaps(); + + struct WAGO { + double et; + double gain; + double offset; + inline bool operator<(const WAGO &w) const { return (et < w.et); }; + inline bool operator==(const WAGO &w) const { return (et == w.et); }; + }; + std::vector p_wagos; + void InitWago(); + + Filename p_lsk; + Filename p_sclk; + }; + }; +}; + +#endif diff --git a/isis/src/mgs/objs/MocLabels/MocLabels.truth b/isis/src/mgs/objs/MocLabels/MocLabels.truth new file mode 100644 index 0000000000000000000000000000000000000000..7cd1e2ca7b16157f5ebe3f6c73321d37d4a0ccd1 --- /dev/null +++ b/isis/src/mgs/objs/MocLabels/MocLabels.truth @@ -0,0 +1,41 @@ +Unit test for MocLabels +MocWideAngleCamera cub test... +NarrowAngle? 0 +WideAngle? 1 +WideAngleRed? 1 +WideAngleBlue? 0 +Crosstrack Summing = 4 +Downtrack Summing = 4 +First Line Sample = 673 +Focal Plane Temperature = 213.1 +Line Rate = 0.4 +Exposure Duration = 100 +Start Time = 1997-10-20T10:58:37.46 +Detectors = 3456 +StartDetector(1) = 672 +EndDetector(1) = 675 +Sample = 0.625 +EphemerisTime = -6.93828e+07 +Gain = 16.03 +Offset = 25 + +MocNarrowAngleCamera cub test... +NarrowAngle? 1 +WideAngle? 0 +WideAngleRed? 0 +WideAngleBlue? 0 +Crosstrack Summing = 1 +Downtrack Summing = 1 +First Line Sample = 1025 +Focal Plane Temperature = 251 +Line Rate = 0.0004821 +Exposure Duration = 0.4821 +Start Time = 1999-03-09T16:51:43.25 +Detectors = 2048 +StartDetector(1) = 1024 +EndDetector(1) = 1024 +Sample = 1 +EphemerisTime = -2.57296e+07 +Gain = 93.465 +Offset = 230 + diff --git a/isis/src/mgs/objs/MocLabels/mocxtrack.h b/isis/src/mgs/objs/MocLabels/mocxtrack.h new file mode 100644 index 0000000000000000000000000000000000000000..e05d2792e8d907132e60c79543ffc34a65c93a15 --- /dev/null +++ b/isis/src/mgs/objs/MocLabels/mocxtrack.h @@ -0,0 +1,1245 @@ +/*********************************************************************** +*_Title mocxtrack.h - MOC Cross Track Summing table maps +*_Args NONE + +*_Descr This include file defines mapping of MGS MOC WA output pixels +* to hardware pixels. It is taken from the "Software Interface +* Specification Narrow Angle and Wide Angle Standard Data Products" +* publication, September 1999, formatted April 7, 2000, Appendix F. +* This document was provided by Malin Space Science Systems, Inc., +* (MSSS) and specifies how on-board MOC WA varable summing relates +* to output pixel generation. These data are critical in proper +* radiometric calibration and geometric rectifications for these +* special WA cross track summing modes. + +* Note that it is very important to understand that the values +* in the starting and ending pixel are relative to the starting +* hardware detector pixel as specified in the FIRST_LINE_SAMPLE +* ISIS label keyword (EDIT_MODE_ID in MGS PDS labels). Thus, +* for example, the actual hardware pixel or pixels used to +* generate the first output pixel is: +* +* starting_hw_pixel = (FIRST_LINE_SAMPLE - 1) + table[0].starting_pixel +* ending_hw_pixel = (FIRST_LINE_SAMPLE - 1) + table[0].ending_pixel +* +* where "table" is either "mode27_table" or "mode13_table" depending +* on the value of CROSSTRACK_SUMMING in the ISIS label, 27 or 13, +* respectively. Generally, these images will always have the +* indicated number of samples per line for each mode. +*/ + +#ifndef MOCXTRACK_H +#define MOCXTRACK_H + +/****************************************************************** + Define the table structure for WA crosstrack summing modes +*******************************************************************/ + +/// @cond INTERNAL +typedef struct moc_xts_table { + int output_pixel; // Output pixel + int n_pixels; // Number of detectors in sum + int starting_pixel; // Starting hardware detector + int ending_pixel; // Ending hardware detector + double center_pixel; // Center hardware detector + double pixel_difference; // Difference between current + // center_pixel and previous + // center_pixel +} MOC_XTS_TABLE; +/// @endcond + +/********************************************************************/ +/* 10. Appendix F: global map crosstrack summing tables */ +/* */ +/* These tables map output pixel in the global map to the */ +/* number of input pixels summed and the offset of these pixels */ +/* from the starting pixel. Using the EDIT_MODE_ID to deter- */ +/* mine the start pixel of the image, the mapping to and from */ +/* detector pixel and global map pixel is determined. */ +/* */ +/* The tables have four columns: the output pixel number start- */ +/* ing from 0, the summing for that pixel, and the starting and */ +/* ending hardware pixel offsets relative to EDIT_MODE_ID that */ +/* are summed to form the output pixel. */ +/* */ +/* In ISIS, the EDIT_MODE_ID is actually the FIRST_LINE_SAMPLE */ +/* plus 1 as it is a 1-based entity not 0-based as the MGS PDS */ +/* keyword EDIT_MODE_ID is. Note that the tables are 0-based */ +/* indicies. */ +/********************************************************************/ + +/* 7.5 km/pixel nominal resolution; output width 384. This is */ +/* indicated by CROSSTRACK_SUMMING = 27 in the labels. */ + +#define MOC_XTS_MODE_27 384 +static MOC_XTS_TABLE mode27_table[MOC_XTS_MODE_27] = { + { 0, 1, 0, 0, 0.0, 1.0 }, + { 1, 1, 1, 1, 1.0, 1.0 }, + { 2, 1, 2, 2, 2.0, 1.0 }, + { 3, 1, 3, 3, 3.0, 1.0 }, + { 4, 1, 4, 4, 4.0, 1.0 }, + { 5, 1, 5, 5, 5.0, 1.0 }, + { 6, 1, 6, 6, 6.0, 1.0 }, + { 7, 1, 7, 7, 7.0, 1.0 }, + { 8, 1, 8, 8, 8.0, 1.0 }, + { 9, 1, 9, 9, 9.0, 1.0 }, + { 10, 1, 10, 10, 10.0, 1.0 }, + { 11, 1, 11, 11, 11.0, 1.0 }, + { 12, 1, 12, 12, 12.0, 1.0 }, + { 13, 1, 13, 13, 13.0, 1.0 }, + { 14, 1, 14, 14, 14.0, 1.0 }, + { 15, 1, 15, 15, 15.0, 1.0 }, + { 16, 1, 16, 16, 16.0, 1.0 }, + { 17, 1, 17, 17, 17.0, 1.0 }, + { 18, 1, 18, 18, 18.0, 1.0 }, + { 19, 1, 19, 19, 19.0, 1.0 }, + { 20, 1, 20, 20, 20.0, 1.0 }, + { 21, 1, 21, 21, 21.0, 1.0 }, + { 22, 1, 22, 22, 22.0, 1.0 }, + { 23, 1, 23, 23, 23.0, 1.0 }, + { 24, 1, 24, 24, 24.0, 1.0 }, + { 25, 1, 25, 25, 25.0, 1.0 }, + { 26, 1, 26, 26, 26.0, 1.0 }, + { 27, 1, 27, 27, 27.0, 1.0 }, + { 28, 1, 28, 28, 28.0, 1.0 }, + { 29, 1, 29, 29, 29.0, 1.0 }, + { 30, 1, 30, 30, 30.0, 1.0 }, + { 31, 1, 31, 31, 31.0, 1.0 }, + { 32, 1, 32, 32, 32.0, 1.0 }, + { 33, 1, 33, 33, 33.0, 1.0 }, + { 34, 1, 34, 34, 34.0, 1.0 }, + { 35, 1, 35, 35, 35.0, 1.0 }, + { 36, 1, 36, 36, 36.0, 1.0 }, + { 37, 1, 37, 37, 37.0, 1.0 }, + { 38, 1, 38, 38, 38.0, 1.0 }, + { 39, 1, 39, 39, 39.0, 1.0 }, + { 40, 1, 40, 40, 40.0, 1.0 }, + { 41, 1, 41, 41, 41.0, 1.0 }, + { 42, 1, 42, 42, 42.0, 1.0 }, + { 43, 1, 43, 43, 43.0, 1.0 }, + { 44, 1, 44, 44, 44.0, 1.0 }, + { 45, 1, 45, 45, 45.0, 1.0 }, + { 46, 1, 46, 46, 46.0, 1.0 }, + { 47, 1, 47, 47, 47.0, 1.0 }, + { 48, 1, 48, 48, 48.0, 1.0 }, + { 49, 2, 49, 50, 49.5, 1.5 }, + { 50, 2, 51, 52, 51.5, 2.0 }, + { 51, 2, 53, 54, 53.5, 2.0 }, + { 52, 2, 55, 56, 55.5, 2.0 }, + { 53, 2, 57, 58, 57.5, 2.0 }, + { 54, 2, 59, 60, 59.5, 2.0 }, + { 55, 2, 61, 62, 61.5, 2.0 }, + { 56, 2, 63, 64, 63.5, 2.0 }, + { 57, 2, 65, 66, 65.5, 2.0 }, + { 58, 2, 67, 68, 67.5, 2.0 }, + { 59, 2, 69, 70, 69.5, 2.0 }, + { 60, 2, 71, 72, 71.5, 2.0 }, + { 61, 2, 73, 74, 73.5, 2.0 }, + { 62, 2, 75, 76, 75.5, 2.0 }, + { 63, 2, 77, 78, 77.5, 2.0 }, + { 64, 2, 79, 80, 79.5, 2.0 }, + { 65, 2, 81, 82, 81.5, 2.0 }, + { 66, 2, 83, 84, 83.5, 2.0 }, + { 67, 2, 85, 86, 85.5, 2.0 }, + { 68, 2, 87, 88, 87.5, 2.0 }, + { 69, 2, 89, 90, 89.5, 2.0 }, + { 70, 2, 91, 92, 91.5, 2.0 }, + { 71, 2, 93, 94, 93.5, 2.0 }, + { 72, 3, 95, 97, 96.0, 2.5 }, + { 73, 3, 98, 100, 99.0, 3.0 }, + { 74, 3, 101, 103, 102.0, 3.0 }, + { 75, 3, 104, 106, 105.0, 3.0 }, + { 76, 3, 107, 109, 108.0, 3.0 }, + { 77, 3, 110, 112, 111.0, 3.0 }, + { 78, 3, 113, 115, 114.0, 3.0 }, + { 79, 3, 116, 118, 117.0, 3.0 }, + { 80, 3, 119, 121, 120.0, 3.0 }, + { 81, 3, 122, 124, 123.0, 3.0 }, + { 82, 3, 125, 127, 126.0, 3.0 }, + { 83, 3, 128, 130, 129.0, 3.0 }, + { 84, 3, 131, 133, 132.0, 3.0 }, + { 85, 3, 134, 136, 135.0, 3.0 }, + { 86, 3, 137, 139, 138.0, 3.0 }, + { 87, 3, 140, 142, 141.0, 3.0 }, + { 88, 4, 143, 146, 144.5, 3.5 }, + { 89, 4, 147, 150, 148.5, 4.0 }, + { 90, 4, 151, 154, 152.5, 4.0 }, + { 91, 4, 155, 158, 156.5, 4.0 }, + { 92, 4, 159, 162, 160.5, 4.0 }, + { 93, 4, 163, 166, 164.5, 4.0 }, + { 94, 4, 167, 170, 168.5, 4.0 }, + { 95, 4, 171, 174, 172.5, 4.0 }, + { 96, 4, 175, 178, 176.5, 4.0 }, + { 97, 4, 179, 182, 180.5, 4.0 }, + { 98, 4, 183, 186, 184.5, 4.0 }, + { 99, 4, 187, 190, 188.5, 4.0 }, + { 100, 5, 191, 195, 193.0, 4.5 }, + { 101, 5, 196, 200, 198.0, 5.0 }, + { 102, 5, 201, 205, 203.0, 5.0 }, + { 103, 5, 206, 210, 208.0, 5.0 }, + { 104, 5, 211, 215, 213.0, 5.0 }, + { 105, 5, 216, 220, 218.0, 5.0 }, + { 106, 5, 221, 225, 223.0, 5.0 }, + { 107, 5, 226, 230, 228.0, 5.0 }, + { 108, 5, 231, 235, 233.0, 5.0 }, + { 109, 6, 236, 241, 238.5, 5.5 }, + { 110, 6, 242, 247, 244.5, 6.0 }, + { 111, 6, 248, 253, 250.5, 6.0 }, + { 112, 6, 254, 259, 256.5, 6.0 }, + { 113, 7, 260, 266, 263.0, 6.5 }, + { 114, 7, 267, 273, 270.0, 7.0 }, + { 115, 7, 274, 280, 277.0, 7.0 }, + { 116, 7, 281, 287, 284.0, 7.0 }, + { 117, 7, 288, 294, 291.0, 7.0 }, + { 118, 7, 295, 301, 298.0, 7.0 }, + { 119, 7, 302, 308, 305.0, 7.0 }, + { 120, 8, 309, 316, 312.5, 7.5 }, + { 121, 8, 317, 324, 320.5, 8.0 }, + { 122, 8, 325, 332, 328.5, 8.0 }, + { 123, 8, 333, 340, 336.5, 8.0 }, + { 124, 8, 341, 348, 344.5, 8.0 }, + { 125, 8, 349, 356, 352.5, 8.0 }, + { 126, 9, 357, 365, 361.0, 8.5 }, + { 127, 9, 366, 374, 370.0, 9.0 }, + { 128, 9, 375, 383, 379.0, 9.0 }, + { 129, 9, 384, 392, 388.0, 9.0 }, + { 130, 9, 393, 401, 397.0, 9.0 }, + { 131, 10, 402, 411, 406.5, 9.5 }, + { 132, 10, 412, 421, 416.5, 10.0 }, + { 133, 10, 422, 431, 426.5, 10.0 }, + { 134, 10, 432, 441, 436.5, 10.0 }, + { 135, 10, 442, 451, 446.5, 10.0 }, + { 136, 11, 452, 462, 457.0, 10.5 }, + { 137, 11, 463, 473, 468.0, 11.0 }, + { 138, 11, 474, 484, 479.0, 11.0 }, + { 139, 11, 485, 495, 490.0, 11.0 }, + { 140, 12, 496, 507, 501.5, 11.5 }, + { 141, 13, 508, 520, 514.0, 12.5 }, + { 142, 13, 521, 533, 527.0, 13.0 }, + { 143, 13, 534, 546, 540.0, 13.0 }, + { 144, 13, 547, 559, 553.0, 13.0 }, + { 145, 14, 560, 573, 566.5, 13.5 }, + { 146, 14, 574, 587, 580.5, 14.0 }, + { 147, 14, 588, 601, 594.5, 14.0 }, + { 148, 14, 602, 615, 608.5, 14.0 }, + { 149, 15, 616, 630, 623.0, 14.5 }, + { 150, 15, 631, 645, 638.0, 15.0 }, + { 151, 15, 646, 660, 653.0, 15.0 }, + { 152, 16, 661, 676, 668.5, 15.5 }, + { 153, 16, 677, 692, 684.5, 16.0 }, + { 154, 16, 693, 708, 700.5, 16.0 }, + { 155, 17, 709, 725, 717.0, 16.5 }, + { 156, 17, 726, 742, 734.0, 17.0 }, + { 157, 18, 743, 760, 751.5, 17.5 }, + { 158, 18, 761, 778, 769.5, 18.0 }, + { 159, 19, 779, 797, 788.0, 18.5 }, + { 160, 19, 798, 816, 807.0, 19.0 }, + { 161, 19, 817, 835, 826.0, 19.0 }, + { 162, 20, 836, 855, 845.5, 19.5 }, + { 163, 20, 856, 875, 865.5, 20.0 }, + { 164, 20, 876, 895, 885.5, 20.0 }, + { 165, 21, 896, 916, 906.0, 20.5 }, + { 166, 21, 917, 937, 927.0, 21.0 }, + { 167, 21, 938, 958, 948.0, 21.0 }, + { 168, 22, 959, 980, 969.5, 21.5 }, + { 169, 22, 981, 1002, 991.5, 22.0 }, + { 170, 23, 1003, 1025, 1014.0, 22.5 }, + { 171, 24, 1026, 1049, 1037.5, 23.5 }, + { 172, 24, 1050, 1073, 1061.5, 24.0 }, + { 173, 24, 1074, 1097, 1085.5, 24.0 }, + { 174, 25, 1098, 1122, 1110.0, 24.5 }, + { 175, 25, 1123, 1147, 1135.0, 25.0 }, + { 176, 25, 1148, 1172, 1160.0, 25.0 }, + { 177, 25, 1173, 1197, 1185.0, 25.0 }, + { 178, 26, 1198, 1223, 1210.5, 25.5 }, + { 179, 26, 1224, 1249, 1236.5, 26.0 }, + { 180, 26, 1250, 1275, 1262.5, 26.0 }, + { 181, 26, 1276, 1301, 1288.5, 26.0 }, + { 182, 26, 1302, 1327, 1314.5, 26.0 }, + { 183, 27, 1328, 1354, 1341.0, 26.5 }, + { 184, 27, 1355, 1381, 1368.0, 27.0 }, + { 185, 27, 1382, 1408, 1395.0, 27.0 }, + { 186, 27, 1409, 1435, 1422.0, 27.0 }, + { 187, 27, 1436, 1462, 1449.0, 27.0 }, + { 188, 27, 1463, 1489, 1476.0, 27.0 }, + { 189, 27, 1490, 1516, 1503.0, 27.0 }, + { 190, 27, 1517, 1543, 1530.0, 27.0 }, + { 191, 27, 1544, 1570, 1557.0, 27.0 }, + { 192, 27, 1571, 1597, 1584.0, 27.0 }, + { 193, 27, 1598, 1624, 1611.0, 27.0 }, + { 194, 27, 1625, 1651, 1638.0, 27.0 }, + { 195, 27, 1652, 1678, 1665.0, 27.0 }, + { 196, 27, 1679, 1705, 1692.0, 27.0 }, + { 197, 27, 1706, 1732, 1719.0, 27.0 }, + { 198, 27, 1733, 1759, 1746.0, 27.0 }, + { 199, 27, 1760, 1786, 1773.0, 27.0 }, + { 200, 27, 1787, 1813, 1800.0, 27.0 }, + { 201, 26, 1814, 1839, 1826.5, 26.5 }, + { 202, 26, 1840, 1865, 1852.5, 26.0 }, + { 203, 26, 1866, 1891, 1878.5, 26.0 }, + { 204, 26, 1892, 1917, 1904.5, 26.0 }, + { 205, 26, 1918, 1943, 1930.5, 26.0 }, + { 206, 25, 1944, 1968, 1956.0, 25.5 }, + { 207, 25, 1969, 1993, 1981.0, 25.0 }, + { 208, 25, 1994, 2018, 2006.0, 25.0 }, + { 209, 25, 2019, 2043, 2031.0, 25.0 }, + { 210, 24, 2044, 2067, 2055.5, 24.5 }, + { 211, 24, 2068, 2091, 2079.5, 24.0 }, + { 212, 24, 2092, 2115, 2103.5, 24.0 }, + { 213, 23, 2116, 2138, 2127.0, 23.5 }, + { 214, 22, 2139, 2160, 2149.5, 22.5 }, + { 215, 22, 2161, 2182, 2171.5, 22.0 }, + { 216, 21, 2183, 2203, 2193.0, 21.5 }, + { 217, 21, 2204, 2224, 2214.0, 21.0 }, + { 218, 21, 2225, 2245, 2235.0, 21.0 }, + { 219, 20, 2246, 2265, 2255.5, 20.5 }, + { 220, 20, 2266, 2285, 2275.5, 20.0 }, + { 221, 20, 2286, 2305, 2295.5, 20.0 }, + { 222, 19, 2306, 2324, 2315.0, 19.5 }, + { 223, 19, 2325, 2343, 2334.0, 19.0 }, + { 224, 19, 2344, 2362, 2353.0, 19.0 }, + { 225, 18, 2363, 2380, 2371.5, 18.5 }, + { 226, 18, 2381, 2398, 2389.5, 18.0 }, + { 227, 17, 2399, 2415, 2407.0, 17.5 }, + { 228, 17, 2416, 2432, 2424.0, 17.0 }, + { 229, 16, 2433, 2448, 2440.5, 16.5 }, + { 230, 16, 2449, 2464, 2456.5, 16.0 }, + { 231, 16, 2465, 2480, 2472.5, 16.0 }, + { 232, 15, 2481, 2495, 2488.0, 15.5 }, + { 233, 15, 2496, 2510, 2503.0, 15.0 }, + { 234, 15, 2511, 2525, 2518.0, 15.0 }, + { 235, 14, 2526, 2539, 2532.5, 14.5 }, + { 236, 14, 2540, 2553, 2546.5, 14.0 }, + { 237, 14, 2554, 2567, 2560.5, 14.0 }, + { 238, 14, 2568, 2581, 2574.5, 14.0 }, + { 239, 13, 2582, 2594, 2588.0, 13.5 }, + { 240, 13, 2595, 2607, 2601.0, 13.0 }, + { 241, 13, 2608, 2620, 2614.0, 13.0 }, + { 242, 13, 2621, 2633, 2627.0, 13.0 }, + { 243, 12, 2634, 2645, 2639.5, 12.5 }, + { 244, 11, 2646, 2656, 2651.0, 11.5 }, + { 245, 11, 2657, 2667, 2662.0, 11.0 }, + { 246, 11, 2668, 2678, 2673.0, 11.0 }, + { 247, 11, 2679, 2689, 2684.0, 11.0 }, + { 248, 10, 2690, 2699, 2694.5, 10.5 }, + { 249, 10, 2700, 2709, 2704.5, 10.0 }, + { 250, 10, 2710, 2719, 2714.5, 10.0 }, + { 251, 10, 2720, 2729, 2724.5, 10.0 }, + { 252, 10, 2730, 2739, 2734.5, 10.0 }, + { 253, 9, 2740, 2748, 2744.0, 9.5 }, + { 254, 9, 2749, 2757, 2753.0, 9.0 }, + { 255, 9, 2758, 2766, 2762.0, 9.0 }, + { 256, 9, 2767, 2775, 2771.0, 9.0 }, + { 257, 9, 2776, 2784, 2780.0, 9.0 }, + { 258, 8, 2785, 2792, 2788.5, 8.5 }, + { 259, 8, 2793, 2800, 2796.5, 8.0 }, + { 260, 8, 2801, 2808, 2804.5, 8.0 }, + { 261, 8, 2809, 2816, 2812.5, 8.0 }, + { 262, 8, 2817, 2824, 2820.5, 8.0 }, + { 263, 8, 2825, 2832, 2828.5, 8.0 }, + { 264, 7, 2833, 2839, 2836.0, 7.5 }, + { 265, 7, 2840, 2846, 2843.0, 7.0 }, + { 266, 7, 2847, 2853, 2850.0, 7.0 }, + { 267, 7, 2854, 2860, 2857.0, 7.0 }, + { 268, 7, 2861, 2867, 2864.0, 7.0 }, + { 269, 7, 2868, 2874, 2871.0, 7.0 }, + { 270, 7, 2875, 2881, 2878.0, 7.0 }, + { 271, 6, 2882, 2887, 2884.5, 6.5 }, + { 272, 6, 2888, 2893, 2890.5, 6.0 }, + { 273, 6, 2894, 2899, 2896.5, 6.0 }, + { 274, 6, 2900, 2905, 2902.5, 6.0 }, + { 275, 5, 2906, 2910, 2908.0, 5.5 }, + { 276, 5, 2911, 2915, 2913.0, 5.0 }, + { 277, 5, 2916, 2920, 2918.0, 5.0 }, + { 278, 5, 2921, 2925, 2923.0, 5.0 }, + { 279, 5, 2926, 2930, 2928.0, 5.0 }, + { 280, 5, 2931, 2935, 2933.0, 5.0 }, + { 281, 5, 2936, 2940, 2938.0, 5.0 }, + { 282, 5, 2941, 2945, 2943.0, 5.0 }, + { 283, 5, 2946, 2950, 2948.0, 5.0 }, + { 284, 4, 2951, 2954, 2952.5, 4.5 }, + { 285, 4, 2955, 2958, 2956.5, 4.0 }, + { 286, 4, 2959, 2962, 2960.5, 4.0 }, + { 287, 4, 2963, 2966, 2964.5, 4.0 }, + { 288, 4, 2967, 2970, 2968.5, 4.0 }, + { 289, 4, 2971, 2974, 2972.5, 4.0 }, + { 290, 4, 2975, 2978, 2976.5, 4.0 }, + { 291, 4, 2979, 2982, 2980.5, 4.0 }, + { 292, 4, 2983, 2986, 2984.5, 4.0 }, + { 293, 4, 2987, 2990, 2988.5, 4.0 }, + { 294, 4, 2991, 2994, 2992.5, 4.0 }, + { 295, 4, 2995, 2998, 2996.5, 4.0 }, + { 296, 3, 2999, 3001, 3000.0, 3.5 }, + { 297, 3, 3002, 3004, 3003.0, 3.0 }, + { 298, 3, 3005, 3007, 3006.0, 3.0 }, + { 299, 3, 3008, 3010, 3009.0, 3.0 }, + { 300, 3, 3011, 3013, 3012.0, 3.0 }, + { 301, 3, 3014, 3016, 3015.0, 3.0 }, + { 302, 3, 3017, 3019, 3018.0, 3.0 }, + { 303, 3, 3020, 3022, 3021.0, 3.0 }, + { 304, 3, 3023, 3025, 3024.0, 3.0 }, + { 305, 3, 3026, 3028, 3027.0, 3.0 }, + { 306, 3, 3029, 3031, 3030.0, 3.0 }, + { 307, 3, 3032, 3034, 3033.0, 3.0 }, + { 308, 3, 3035, 3037, 3036.0, 3.0 }, + { 309, 3, 3038, 3040, 3039.0, 3.0 }, + { 310, 3, 3041, 3043, 3042.0, 3.0 }, + { 311, 3, 3044, 3046, 3045.0, 3.0 }, + { 312, 2, 3047, 3048, 3047.5, 2.5 }, + { 313, 2, 3049, 3050, 3049.5, 2.0 }, + { 314, 2, 3051, 3052, 3051.5, 2.0 }, + { 315, 2, 3053, 3054, 3053.5, 2.0 }, + { 316, 2, 3055, 3056, 3055.5, 2.0 }, + { 317, 2, 3057, 3058, 3057.5, 2.0 }, + { 318, 2, 3059, 3060, 3059.5, 2.0 }, + { 319, 2, 3061, 3062, 3061.5, 2.0 }, + { 320, 2, 3063, 3064, 3063.5, 2.0 }, + { 321, 2, 3065, 3066, 3065.5, 2.0 }, + { 322, 2, 3067, 3068, 3067.5, 2.0 }, + { 323, 2, 3069, 3070, 3069.5, 2.0 }, + { 324, 2, 3071, 3072, 3071.5, 2.0 }, + { 325, 2, 3073, 3074, 3073.5, 2.0 }, + { 326, 2, 3075, 3076, 3075.5, 2.0 }, + { 327, 2, 3077, 3078, 3077.5, 2.0 }, + { 328, 2, 3079, 3080, 3079.5, 2.0 }, + { 329, 2, 3081, 3082, 3081.5, 2.0 }, + { 330, 2, 3083, 3084, 3083.5, 2.0 }, + { 331, 2, 3085, 3086, 3085.5, 2.0 }, + { 332, 2, 3087, 3088, 3087.5, 2.0 }, + { 333, 2, 3089, 3090, 3089.5, 2.0 }, + { 334, 2, 3091, 3092, 3091.5, 2.0 }, + { 335, 1, 3093, 3093, 3093.0, 1.5 }, + { 336, 1, 3094, 3094, 3094.0, 1.0 }, + { 337, 1, 3095, 3095, 3095.0, 1.0 }, + { 338, 1, 3096, 3096, 3096.0, 1.0 }, + { 339, 1, 3097, 3097, 3097.0, 1.0 }, + { 340, 1, 3098, 3098, 3098.0, 1.0 }, + { 341, 1, 3099, 3099, 3099.0, 1.0 }, + { 342, 1, 3100, 3100, 3100.0, 1.0 }, + { 343, 1, 3101, 3101, 3101.0, 1.0 }, + { 344, 1, 3102, 3102, 3102.0, 1.0 }, + { 345, 1, 3103, 3103, 3103.0, 1.0 }, + { 346, 1, 3104, 3104, 3104.0, 1.0 }, + { 347, 1, 3105, 3105, 3105.0, 1.0 }, + { 348, 1, 3106, 3106, 3106.0, 1.0 }, + { 349, 1, 3107, 3107, 3107.0, 1.0 }, + { 350, 1, 3108, 3108, 3108.0, 1.0 }, + { 351, 1, 3109, 3109, 3109.0, 1.0 }, + { 352, 1, 3110, 3110, 3110.0, 1.0 }, + { 353, 1, 3111, 3111, 3111.0, 1.0 }, + { 354, 1, 3112, 3112, 3112.0, 1.0 }, + { 355, 1, 3113, 3113, 3113.0, 1.0 }, + { 356, 1, 3114, 3114, 3114.0, 1.0 }, + { 357, 1, 3115, 3115, 3115.0, 1.0 }, + { 358, 1, 3116, 3116, 3116.0, 1.0 }, + { 359, 1, 3117, 3117, 3117.0, 1.0 }, + { 360, 1, 3118, 3118, 3118.0, 1.0 }, + { 361, 1, 3119, 3119, 3119.0, 1.0 }, + { 362, 1, 3120, 3120, 3120.0, 1.0 }, + { 363, 1, 3121, 3121, 3121.0, 1.0 }, + { 364, 1, 3122, 3122, 3122.0, 1.0 }, + { 365, 1, 3123, 3123, 3123.0, 1.0 }, + { 366, 1, 3124, 3124, 3124.0, 1.0 }, + { 367, 1, 3125, 3125, 3125.0, 1.0 }, + { 368, 1, 3126, 3126, 3126.0, 1.0 }, + { 369, 1, 3127, 3127, 3127.0, 1.0 }, + { 370, 1, 3128, 3128, 3128.0, 1.0 }, + { 371, 1, 3129, 3129, 3129.0, 1.0 }, + { 372, 1, 3130, 3130, 3130.0, 1.0 }, + { 373, 1, 3131, 3131, 3131.0, 1.0 }, + { 374, 1, 3132, 3132, 3132.0, 1.0 }, + { 375, 1, 3133, 3133, 3133.0, 1.0 }, + { 376, 1, 3134, 3134, 3134.0, 1.0 }, + { 377, 1, 3135, 3135, 3135.0, 1.0 }, + { 378, 1, 3136, 3136, 3136.0, 1.0 }, + { 379, 1, 3137, 3137, 3137.0, 1.0 }, + { 380, 1, 3138, 3138, 3138.0, 1.0 }, + { 381, 1, 3139, 3139, 3139.0, 1.0 }, + { 382, 1, 3140, 3140, 3140.0, 1.0 }, + { 383, 1, 3141, 3141, 3141.0, 1.0 } +}; + +/* 3.75 km/pixel nominal resolution; output width 768. This is indicated */ +/* by the keyword CROSSTRACK_SUMMING = 13 in the labels. */ + +#define MOC_XTS_MODE_13 768 +static MOC_XTS_TABLE mode13_table[MOC_XTS_MODE_13] = { + { 0, 1, 0, 0, 0.0, 1.0 }, + { 1, 1, 1, 1, 1.0, 1.0 }, + { 2, 1, 2, 2, 2.0, 1.0 }, + { 3, 1, 3, 3, 3.0, 1.0 }, + { 4, 1, 4, 4, 4.0, 1.0 }, + { 5, 1, 5, 5, 5.0, 1.0 }, + { 6, 1, 6, 6, 6.0, 1.0 }, + { 7, 1, 7, 7, 7.0, 1.0 }, + { 8, 1, 8, 8, 8.0, 1.0 }, + { 9, 1, 9, 9, 9.0, 1.0 }, + { 10, 1, 10, 10, 10.0, 1.0 }, + { 11, 1, 11, 11, 11.0, 1.0 }, + { 12, 1, 12, 12, 12.0, 1.0 }, + { 13, 1, 13, 13, 13.0, 1.0 }, + { 14, 1, 14, 14, 14.0, 1.0 }, + { 15, 1, 15, 15, 15.0, 1.0 }, + { 16, 1, 16, 16, 16.0, 1.0 }, + { 17, 1, 17, 17, 17.0, 1.0 }, + { 18, 1, 18, 18, 18.0, 1.0 }, + { 19, 1, 19, 19, 19.0, 1.0 }, + { 20, 1, 20, 20, 20.0, 1.0 }, + { 21, 1, 21, 21, 21.0, 1.0 }, + { 22, 1, 22, 22, 22.0, 1.0 }, + { 23, 1, 23, 23, 23.0, 1.0 }, + { 24, 1, 24, 24, 24.0, 1.0 }, + { 25, 1, 25, 25, 25.0, 1.0 }, + { 26, 1, 26, 26, 26.0, 1.0 }, + { 27, 1, 27, 27, 27.0, 1.0 }, + { 28, 1, 28, 28, 28.0, 1.0 }, + { 29, 1, 29, 29, 29.0, 1.0 }, + { 30, 1, 30, 30, 30.0, 1.0 }, + { 31, 1, 31, 31, 31.0, 1.0 }, + { 32, 1, 32, 32, 32.0, 1.0 }, + { 33, 1, 33, 33, 33.0, 1.0 }, + { 34, 1, 34, 34, 34.0, 1.0 }, + { 35, 1, 35, 35, 35.0, 1.0 }, + { 36, 1, 36, 36, 36.0, 1.0 }, + { 37, 1, 37, 37, 37.0, 1.0 }, + { 38, 1, 38, 38, 38.0, 1.0 }, + { 39, 1, 39, 39, 39.0, 1.0 }, + { 40, 1, 40, 40, 40.0, 1.0 }, + { 41, 1, 41, 41, 41.0, 1.0 }, + { 42, 1, 42, 42, 42.0, 1.0 }, + { 43, 1, 43, 43, 43.0, 1.0 }, + { 44, 1, 44, 44, 44.0, 1.0 }, + { 45, 1, 45, 45, 45.0, 1.0 }, + { 46, 1, 46, 46, 46.0, 1.0 }, + { 47, 1, 47, 47, 47.0, 1.0 }, + { 48, 1, 48, 48, 48.0, 1.0 }, + { 49, 1, 49, 49, 49.0, 1.0 }, + { 50, 1, 50, 50, 50.0, 1.0 }, + { 51, 1, 51, 51, 51.0, 1.0 }, + { 52, 1, 52, 52, 52.0, 1.0 }, + { 53, 1, 53, 53, 53.0, 1.0 }, + { 54, 1, 54, 54, 54.0, 1.0 }, + { 55, 1, 55, 55, 55.0, 1.0 }, + { 56, 1, 56, 56, 56.0, 1.0 }, + { 57, 1, 57, 57, 57.0, 1.0 }, + { 58, 1, 58, 58, 58.0, 1.0 }, + { 59, 1, 59, 59, 59.0, 1.0 }, + { 60, 1, 60, 60, 60.0, 1.0 }, + { 61, 1, 61, 61, 61.0, 1.0 }, + { 62, 1, 62, 62, 62.0, 1.0 }, + { 63, 1, 63, 63, 63.0, 1.0 }, + { 64, 1, 64, 64, 64.0, 1.0 }, + { 65, 1, 65, 65, 65.0, 1.0 }, + { 66, 1, 66, 66, 66.0, 1.0 }, + { 67, 1, 67, 67, 67.0, 1.0 }, + { 68, 1, 68, 68, 68.0, 1.0 }, + { 69, 1, 69, 69, 69.0, 1.0 }, + { 70, 1, 70, 70, 70.0, 1.0 }, + { 71, 1, 71, 71, 71.0, 1.0 }, + { 72, 1, 72, 72, 72.0, 1.0 }, + { 73, 1, 73, 73, 73.0, 1.0 }, + { 74, 1, 74, 74, 74.0, 1.0 }, + { 75, 1, 75, 75, 75.0, 1.0 }, + { 76, 1, 76, 76, 76.0, 1.0 }, + { 77, 1, 77, 77, 77.0, 1.0 }, + { 78, 1, 78, 78, 78.0, 1.0 }, + { 79, 1, 79, 79, 79.0, 1.0 }, + { 80, 1, 80, 80, 80.0, 1.0 }, + { 81, 1, 81, 81, 81.0, 1.0 }, + { 82, 1, 82, 82, 82.0, 1.0 }, + { 83, 1, 83, 83, 83.0, 1.0 }, + { 84, 1, 84, 84, 84.0, 1.0 }, + { 85, 1, 85, 85, 85.0, 1.0 }, + { 86, 1, 86, 86, 86.0, 1.0 }, + { 87, 1, 87, 87, 87.0, 1.0 }, + { 88, 1, 88, 88, 88.0, 1.0 }, + { 89, 1, 89, 89, 89.0, 1.0 }, + { 90, 1, 90, 90, 90.0, 1.0 }, + { 91, 1, 91, 91, 91.0, 1.0 }, + { 92, 1, 92, 92, 92.0, 1.0 }, + { 93, 1, 93, 93, 93.0, 1.0 }, + { 94, 1, 94, 94, 94.0, 1.0 }, + { 95, 1, 95, 95, 95.0, 1.0 }, + { 96, 1, 96, 96, 96.0, 1.0 }, + { 97, 1, 97, 97, 97.0, 1.0 }, + { 98, 1, 98, 98, 98.0, 1.0 }, + { 99, 1, 99, 99, 99.0, 1.0 }, + { 100, 1, 100, 100, 100.0, 1.0 }, + { 101, 1, 101, 101, 101.0, 1.0 }, + { 102, 1, 102, 102, 102.0, 1.0 }, + { 103, 1, 103, 103, 103.0, 1.0 }, + { 104, 1, 104, 104, 104.0, 1.0 }, + { 105, 1, 105, 105, 105.0, 1.0 }, + { 106, 1, 106, 106, 106.0, 1.0 }, + { 107, 1, 107, 107, 107.0, 1.0 }, + { 108, 1, 108, 108, 108.0, 1.0 }, + { 109, 1, 109, 109, 109.0, 1.0 }, + { 110, 1, 110, 110, 110.0, 1.0 }, + { 111, 1, 111, 111, 111.0, 1.0 }, + { 112, 1, 112, 112, 112.0, 1.0 }, + { 113, 1, 113, 113, 113.0, 1.0 }, + { 114, 1, 114, 114, 114.0, 1.0 }, + { 115, 1, 115, 115, 115.0, 1.0 }, + { 116, 1, 116, 116, 116.0, 1.0 }, + { 117, 1, 117, 117, 117.0, 1.0 }, + { 118, 1, 118, 118, 118.0, 1.0 }, + { 119, 1, 119, 119, 119.0, 1.0 }, + { 120, 1, 120, 120, 120.0, 1.0 }, + { 121, 1, 121, 121, 121.0, 1.0 }, + { 122, 1, 122, 122, 122.0, 1.0 }, + { 123, 1, 123, 123, 123.0, 1.0 }, + { 124, 1, 124, 124, 124.0, 1.0 }, + { 125, 1, 125, 125, 125.0, 1.0 }, + { 126, 1, 126, 126, 126.0, 1.0 }, + { 127, 1, 127, 127, 127.0, 1.0 }, + { 128, 1, 128, 128, 128.0, 1.0 }, + { 129, 1, 129, 129, 129.0, 1.0 }, + { 130, 1, 130, 130, 130.0, 1.0 }, + { 131, 1, 131, 131, 131.0, 1.0 }, + { 132, 1, 132, 132, 132.0, 1.0 }, + { 133, 1, 133, 133, 133.0, 1.0 }, + { 134, 1, 134, 134, 134.0, 1.0 }, + { 135, 1, 135, 135, 135.0, 1.0 }, + { 136, 1, 136, 136, 136.0, 1.0 }, + { 137, 1, 137, 137, 137.0, 1.0 }, + { 138, 1, 138, 138, 138.0, 1.0 }, + { 139, 1, 139, 139, 139.0, 1.0 }, + { 140, 1, 140, 140, 140.0, 1.0 }, + { 141, 1, 141, 141, 141.0, 1.0 }, + { 142, 1, 142, 142, 142.0, 1.0 }, + { 143, 1, 143, 143, 143.0, 1.0 }, + { 144, 1, 144, 144, 144.0, 1.0 }, + { 145, 1, 145, 145, 145.0, 1.0 }, + { 146, 1, 146, 146, 146.0, 1.0 }, + { 147, 1, 147, 147, 147.0, 1.0 }, + { 148, 1, 148, 148, 148.0, 1.0 }, + { 149, 1, 149, 149, 149.0, 1.0 }, + { 150, 1, 150, 150, 150.0, 1.0 }, + { 151, 1, 151, 151, 151.0, 1.0 }, + { 152, 1, 152, 152, 152.0, 1.0 }, + { 153, 1, 153, 153, 153.0, 1.0 }, + { 154, 1, 154, 154, 154.0, 1.0 }, + { 155, 1, 155, 155, 155.0, 1.0 }, + { 156, 1, 156, 156, 156.0, 1.0 }, + { 157, 1, 157, 157, 157.0, 1.0 }, + { 158, 1, 158, 158, 158.0, 1.0 }, + { 159, 1, 159, 159, 159.0, 1.0 }, + { 160, 1, 160, 160, 160.0, 1.0 }, + { 161, 1, 161, 161, 161.0, 1.0 }, + { 162, 1, 162, 162, 162.0, 1.0 }, + { 163, 1, 163, 163, 163.0, 1.0 }, + { 164, 2, 164, 165, 164.5, 1.5 }, + { 165, 2, 166, 167, 166.5, 2.0 }, + { 166, 2, 168, 169, 168.5, 2.0 }, + { 167, 2, 170, 171, 170.5, 2.0 }, + { 168, 2, 172, 173, 172.5, 2.0 }, + { 169, 2, 174, 175, 174.5, 2.0 }, + { 170, 2, 176, 177, 176.5, 2.0 }, + { 171, 2, 178, 179, 178.5, 2.0 }, + { 172, 2, 180, 181, 180.5, 2.0 }, + { 173, 2, 182, 183, 182.5, 2.0 }, + { 174, 2, 184, 185, 184.5, 2.0 }, + { 175, 2, 186, 187, 186.5, 2.0 }, + { 176, 2, 188, 189, 188.5, 2.0 }, + { 177, 2, 190, 191, 190.5, 2.0 }, + { 178, 2, 192, 193, 192.5, 2.0 }, + { 179, 2, 194, 195, 194.5, 2.0 }, + { 180, 2, 196, 197, 196.5, 2.0 }, + { 181, 2, 198, 199, 198.5, 2.0 }, + { 182, 2, 200, 201, 200.5, 2.0 }, + { 183, 2, 202, 203, 202.5, 2.0 }, + { 184, 2, 204, 205, 204.5, 2.0 }, + { 185, 2, 206, 207, 206.5, 2.0 }, + { 186, 2, 208, 209, 208.5, 2.0 }, + { 187, 2, 210, 211, 210.5, 2.0 }, + { 188, 2, 212, 213, 212.5, 2.0 }, + { 189, 2, 214, 215, 214.5, 2.0 }, + { 190, 2, 216, 217, 216.5, 2.0 }, + { 191, 2, 218, 219, 218.5, 2.0 }, + { 192, 2, 220, 221, 220.5, 2.0 }, + { 193, 2, 222, 223, 222.5, 2.0 }, + { 194, 2, 224, 225, 224.5, 2.0 }, + { 195, 2, 226, 227, 226.5, 2.0 }, + { 196, 2, 228, 229, 228.5, 2.0 }, + { 197, 2, 230, 231, 230.5, 2.0 }, + { 198, 2, 232, 233, 232.5, 2.0 }, + { 199, 2, 234, 235, 234.5, 2.0 }, + { 200, 2, 236, 237, 236.5, 2.0 }, + { 201, 2, 238, 239, 238.5, 2.0 }, + { 202, 2, 240, 241, 240.5, 2.0 }, + { 203, 2, 242, 243, 242.5, 2.0 }, + { 204, 2, 244, 245, 244.5, 2.0 }, + { 205, 2, 246, 247, 246.5, 2.0 }, + { 206, 2, 248, 249, 248.5, 2.0 }, + { 207, 2, 250, 251, 250.5, 2.0 }, + { 208, 2, 252, 253, 252.5, 2.0 }, + { 209, 2, 254, 255, 254.5, 2.0 }, + { 210, 2, 256, 257, 256.5, 2.0 }, + { 211, 3, 258, 260, 259.0, 2.5 }, + { 212, 3, 261, 263, 262.0, 3.0 }, + { 213, 3, 264, 266, 265.0, 3.0 }, + { 214, 3, 267, 269, 268.0, 3.0 }, + { 215, 3, 270, 272, 271.0, 3.0 }, + { 216, 3, 273, 275, 274.0, 3.0 }, + { 217, 3, 276, 278, 277.0, 3.0 }, + { 218, 3, 279, 281, 280.0, 3.0 }, + { 219, 3, 282, 284, 283.0, 3.0 }, + { 220, 3, 285, 287, 286.0, 3.0 }, + { 221, 3, 288, 290, 289.0, 3.0 }, + { 222, 3, 291, 293, 292.0, 3.0 }, + { 223, 3, 294, 296, 295.0, 3.0 }, + { 224, 3, 297, 299, 298.0, 3.0 }, + { 225, 3, 300, 302, 301.0, 3.0 }, + { 226, 3, 303, 305, 304.0, 3.0 }, + { 227, 3, 306, 308, 307.0, 3.0 }, + { 228, 3, 309, 311, 310.0, 3.0 }, + { 229, 3, 312, 314, 313.0, 3.0 }, + { 230, 3, 315, 317, 316.0, 3.0 }, + { 231, 3, 318, 320, 319.0, 3.0 }, + { 232, 3, 321, 323, 322.0, 3.0 }, + { 233, 3, 324, 326, 325.0, 3.0 }, + { 234, 4, 327, 330, 328.5, 3.5 }, + { 235, 4, 331, 334, 332.5, 4.0 }, + { 236, 4, 335, 338, 336.5, 4.0 }, + { 237, 4, 339, 342, 340.5, 4.0 }, + { 238, 4, 343, 346, 344.5, 4.0 }, + { 239, 4, 347, 350, 348.5, 4.0 }, + { 240, 4, 351, 354, 352.5, 4.0 }, + { 241, 4, 355, 358, 356.5, 4.0 }, + { 242, 4, 359, 362, 360.5, 4.0 }, + { 243, 4, 363, 366, 364.5, 4.0 }, + { 244, 4, 367, 370, 368.5, 4.0 }, + { 245, 4, 371, 374, 372.5, 4.0 }, + { 246, 4, 375, 378, 376.5, 4.0 }, + { 247, 4, 379, 382, 380.5, 4.0 }, + { 248, 4, 383, 386, 384.5, 4.0 }, + { 249, 4, 387, 390, 388.5, 4.0 }, + { 250, 4, 391, 394, 392.5, 4.0 }, + { 251, 4, 395, 398, 396.5, 4.0 }, + { 252, 4, 399, 402, 400.5, 4.0 }, + { 253, 4, 403, 406, 404.5, 4.0 }, + { 254, 4, 407, 410, 408.5, 4.0 }, + { 255, 4, 411, 414, 412.5, 4.0 }, + { 256, 4, 415, 418, 416.5, 4.0 }, + { 257, 4, 419, 422, 420.5, 4.0 }, + { 258, 5, 423, 427, 425.0, 4.5 }, + { 259, 5, 428, 432, 430.0, 5.0 }, + { 260, 5, 433, 437, 435.0, 5.0 }, + { 261, 5, 438, 442, 440.0, 5.0 }, + { 262, 5, 443, 447, 445.0, 5.0 }, + { 263, 5, 448, 452, 450.0, 5.0 }, + { 264, 5, 453, 457, 455.0, 5.0 }, + { 265, 5, 458, 462, 460.0, 5.0 }, + { 266, 5, 463, 467, 465.0, 5.0 }, + { 267, 5, 468, 472, 470.0, 5.0 }, + { 268, 5, 473, 477, 475.0, 5.0 }, + { 269, 5, 478, 482, 480.0, 5.0 }, + { 270, 5, 483, 487, 485.0, 5.0 }, + { 271, 5, 488, 492, 490.0, 5.0 }, + { 272, 5, 493, 497, 495.0, 5.0 }, + { 273, 5, 498, 502, 500.0, 5.0 }, + { 274, 5, 503, 507, 505.0, 5.0 }, + { 275, 5, 508, 512, 510.0, 5.0 }, + { 276, 6, 513, 518, 515.5, 5.5 }, + { 277, 6, 519, 524, 521.5, 6.0 }, + { 278, 6, 525, 530, 527.5, 6.0 }, + { 279, 6, 531, 536, 533.5, 6.0 }, + { 280, 6, 537, 542, 539.5, 6.0 }, + { 281, 6, 543, 548, 545.5, 6.0 }, + { 282, 6, 549, 554, 551.5, 6.0 }, + { 283, 6, 555, 560, 557.5, 6.0 }, + { 284, 6, 561, 566, 563.5, 6.0 }, + { 285, 6, 567, 572, 569.5, 6.0 }, + { 286, 6, 573, 578, 575.5, 6.0 }, + { 287, 6, 579, 584, 581.5, 6.0 }, + { 288, 7, 585, 591, 588.0, 6.5 }, + { 289, 7, 592, 598, 595.0, 7.0 }, + { 290, 7, 599, 605, 602.0, 7.0 }, + { 291, 7, 606, 612, 609.0, 7.0 }, + { 292, 7, 613, 619, 616.0, 7.0 }, + { 293, 7, 620, 626, 623.0, 7.0 }, + { 294, 7, 627, 633, 630.0, 7.0 }, + { 295, 7, 634, 640, 637.0, 7.0 }, + { 296, 7, 641, 647, 644.0, 7.0 }, + { 297, 7, 648, 654, 651.0, 7.0 }, + { 298, 7, 655, 661, 658.0, 7.0 }, + { 299, 7, 662, 668, 665.0, 7.0 }, + { 300, 7, 669, 675, 672.0, 7.0 }, + { 301, 7, 676, 682, 679.0, 7.0 }, + { 302, 8, 683, 690, 686.5, 7.5 }, + { 303, 8, 691, 698, 694.5, 8.0 }, + { 304, 8, 699, 706, 702.5, 8.0 }, + { 305, 8, 707, 714, 710.5, 8.0 }, + { 306, 8, 715, 722, 718.5, 8.0 }, + { 307, 8, 723, 730, 726.5, 8.0 }, + { 308, 8, 731, 738, 734.5, 8.0 }, + { 309, 8, 739, 746, 742.5, 8.0 }, + { 310, 8, 747, 754, 750.5, 8.0 }, + { 311, 8, 755, 762, 758.5, 8.0 }, + { 312, 8, 763, 770, 766.5, 8.0 }, + { 313, 9, 771, 779, 775.0, 8.5 }, + { 314, 9, 780, 788, 784.0, 9.0 }, + { 315, 9, 789, 797, 793.0, 9.0 }, + { 316, 9, 798, 806, 802.0, 9.0 }, + { 317, 9, 807, 815, 811.0, 9.0 }, + { 318, 9, 816, 824, 820.0, 9.0 }, + { 319, 9, 825, 833, 829.0, 9.0 }, + { 320, 9, 834, 842, 838.0, 9.0 }, + { 321, 9, 843, 851, 847.0, 9.0 }, + { 322, 9, 852, 860, 856.0, 9.0 }, + { 323, 10, 861, 870, 865.5, 9.5 }, + { 324, 10, 871, 880, 875.5, 10.0 }, + { 325, 10, 881, 890, 885.5, 10.0 }, + { 326, 10, 891, 900, 895.5, 10.0 }, + { 327, 10, 901, 910, 905.5, 10.0 }, + { 328, 10, 911, 920, 915.5, 10.0 }, + { 329, 10, 921, 930, 925.5, 10.0 }, + { 330, 10, 931, 940, 935.5, 10.0 }, + { 331, 10, 941, 950, 945.5, 10.0 }, + { 332, 10, 951, 960, 955.5, 10.0 }, + { 333, 10, 961, 970, 965.5, 10.0 }, + { 334, 10, 971, 980, 975.5, 10.0 }, + { 335, 11, 981, 991, 986.0, 10.5 }, + { 336, 11, 992, 1002, 997.0, 11.0 }, + { 337, 11, 1003, 1013, 1008.0, 11.0 }, + { 338, 11, 1014, 1024, 1019.0, 11.0 }, + { 339, 11, 1025, 1035, 1030.0, 11.0 }, + { 340, 11, 1036, 1046, 1041.0, 11.0 }, + { 341, 12, 1047, 1058, 1052.5, 11.5 }, + { 342, 12, 1059, 1070, 1064.5, 12.0 }, + { 343, 12, 1071, 1082, 1076.5, 12.0 }, + { 344, 12, 1083, 1094, 1088.5, 12.0 }, + { 345, 12, 1095, 1106, 1100.5, 12.0 }, + { 346, 12, 1107, 1118, 1112.5, 12.0 }, + { 347, 12, 1119, 1130, 1124.5, 12.0 }, + { 348, 12, 1131, 1142, 1136.5, 12.0 }, + { 349, 12, 1143, 1154, 1148.5, 12.0 }, + { 350, 12, 1155, 1166, 1160.5, 12.0 }, + { 351, 12, 1167, 1178, 1172.5, 12.0 }, + { 352, 12, 1179, 1190, 1184.5, 12.0 }, + { 353, 12, 1191, 1202, 1196.5, 12.0 }, + { 354, 12, 1203, 1214, 1208.5, 12.0 }, + { 355, 12, 1215, 1226, 1220.5, 12.0 }, + { 356, 13, 1227, 1239, 1233.0, 12.5 }, + { 357, 13, 1240, 1252, 1246.0, 13.0 }, + { 358, 13, 1253, 1265, 1259.0, 13.0 }, + { 359, 13, 1266, 1278, 1272.0, 13.0 }, + { 360, 13, 1279, 1291, 1285.0, 13.0 }, + { 361, 13, 1292, 1304, 1298.0, 13.0 }, + { 362, 13, 1305, 1317, 1311.0, 13.0 }, + { 363, 13, 1318, 1330, 1324.0, 13.0 }, + { 364, 13, 1331, 1343, 1337.0, 13.0 }, + { 365, 13, 1344, 1356, 1350.0, 13.0 }, + { 366, 13, 1357, 1369, 1363.0, 13.0 }, + { 367, 13, 1370, 1382, 1376.0, 13.0 }, + { 368, 13, 1383, 1395, 1389.0, 13.0 }, + { 369, 13, 1396, 1408, 1402.0, 13.0 }, + { 370, 13, 1409, 1421, 1415.0, 13.0 }, + { 371, 13, 1422, 1434, 1428.0, 13.0 }, + { 372, 13, 1435, 1447, 1441.0, 13.0 }, + { 373, 13, 1448, 1460, 1454.0, 13.0 }, + { 374, 13, 1461, 1473, 1467.0, 13.0 }, + { 375, 13, 1474, 1486, 1480.0, 13.0 }, + { 376, 13, 1487, 1499, 1493.0, 13.0 }, + { 377, 13, 1500, 1512, 1506.0, 13.0 }, + { 378, 13, 1513, 1525, 1519.0, 13.0 }, + { 379, 13, 1526, 1538, 1532.0, 13.0 }, + { 380, 13, 1539, 1551, 1545.0, 13.0 }, + { 381, 13, 1552, 1564, 1558.0, 13.0 }, + { 382, 13, 1565, 1577, 1571.0, 13.0 }, + { 383, 13, 1578, 1590, 1584.0, 13.0 }, + { 384, 13, 1591, 1603, 1597.0, 13.0 }, + { 385, 13, 1604, 1616, 1610.0, 13.0 }, + { 386, 13, 1617, 1629, 1623.0, 13.0 }, + { 387, 13, 1630, 1642, 1636.0, 13.0 }, + { 388, 13, 1643, 1655, 1649.0, 13.0 }, + { 389, 13, 1656, 1668, 1662.0, 13.0 }, + { 390, 13, 1669, 1681, 1675.0, 13.0 }, + { 391, 13, 1682, 1694, 1688.0, 13.0 }, + { 392, 13, 1695, 1707, 1701.0, 13.0 }, + { 393, 13, 1708, 1720, 1714.0, 13.0 }, + { 394, 13, 1721, 1733, 1727.0, 13.0 }, + { 395, 13, 1734, 1746, 1740.0, 13.0 }, + { 396, 13, 1747, 1759, 1753.0, 13.0 }, + { 397, 13, 1760, 1772, 1766.0, 13.0 }, + { 398, 13, 1773, 1785, 1779.0, 13.0 }, + { 399, 13, 1786, 1798, 1792.0, 13.0 }, + { 400, 13, 1799, 1811, 1805.0, 13.0 }, + { 401, 13, 1812, 1824, 1818.0, 13.0 }, + { 402, 13, 1825, 1837, 1831.0, 13.0 }, + { 403, 13, 1838, 1850, 1844.0, 13.0 }, + { 404, 13, 1851, 1863, 1857.0, 13.0 }, + { 405, 13, 1864, 1876, 1870.0, 13.0 }, + { 406, 13, 1877, 1889, 1883.0, 13.0 }, + { 407, 13, 1890, 1902, 1896.0, 13.0 }, + { 408, 13, 1903, 1915, 1909.0, 13.0 }, + { 409, 13, 1916, 1928, 1922.0, 13.0 }, + { 410, 13, 1929, 1941, 1935.0, 13.0 }, + { 411, 13, 1942, 1954, 1948.0, 13.0 }, + { 412, 12, 1955, 1966, 1960.5, 12.5 }, + { 413, 12, 1967, 1978, 1972.5, 12.0 }, + { 414, 12, 1979, 1990, 1984.5, 12.0 }, + { 415, 12, 1991, 2002, 1996.5, 12.0 }, + { 416, 12, 2003, 2014, 2008.5, 12.0 }, + { 417, 12, 2015, 2026, 2020.5, 12.0 }, + { 418, 12, 2027, 2038, 2032.5, 12.0 }, + { 419, 12, 2039, 2050, 2044.5, 12.0 }, + { 420, 12, 2051, 2062, 2056.5, 12.0 }, + { 421, 12, 2063, 2074, 2068.5, 12.0 }, + { 422, 12, 2075, 2086, 2080.5, 12.0 }, + { 423, 12, 2087, 2098, 2092.5, 12.0 }, + { 424, 12, 2099, 2110, 2104.5, 12.0 }, + { 425, 12, 2111, 2122, 2116.5, 12.0 }, + { 426, 12, 2123, 2134, 2128.5, 12.0 }, + { 427, 11, 2135, 2145, 2140.0, 11.5 }, + { 428, 11, 2146, 2156, 2151.0, 11.0 }, + { 429, 11, 2157, 2167, 2162.0, 11.0 }, + { 430, 11, 2168, 2178, 2173.0, 11.0 }, + { 431, 11, 2179, 2189, 2184.0, 11.0 }, + { 432, 11, 2190, 2200, 2195.0, 11.0 }, + { 433, 10, 2201, 2210, 2205.5, 10.5 }, + { 434, 10, 2211, 2220, 2215.5, 10.0 }, + { 435, 10, 2221, 2230, 2225.5, 10.0 }, + { 436, 10, 2231, 2240, 2235.5, 10.0 }, + { 437, 10, 2241, 2250, 2245.5, 10.0 }, + { 438, 10, 2251, 2260, 2255.5, 10.0 }, + { 439, 10, 2261, 2270, 2265.5, 10.0 }, + { 440, 10, 2271, 2280, 2275.5, 10.0 }, + { 441, 10, 2281, 2290, 2285.5, 10.0 }, + { 442, 10, 2291, 2300, 2295.5, 10.0 }, + { 443, 10, 2301, 2310, 2305.5, 10.0 }, + { 444, 10, 2311, 2320, 2315.5, 10.0 }, + { 445, 9, 2321, 2329, 2325.0, 9.5 }, + { 446, 9, 2330, 2338, 2334.0, 9.0 }, + { 447, 9, 2339, 2347, 2343.0, 9.0 }, + { 448, 9, 2348, 2356, 2352.0, 9.0 }, + { 449, 9, 2357, 2365, 2361.0, 9.0 }, + { 450, 9, 2366, 2374, 2370.0, 9.0 }, + { 451, 9, 2375, 2383, 2379.0, 9.0 }, + { 452, 9, 2384, 2392, 2388.0, 9.0 }, + { 453, 9, 2393, 2401, 2397.0, 9.0 }, + { 454, 9, 2402, 2410, 2406.0, 9.0 }, + { 455, 8, 2411, 2418, 2414.5, 8.5 }, + { 456, 8, 2419, 2426, 2422.5, 8.0 }, + { 457, 8, 2427, 2434, 2430.5, 8.0 }, + { 458, 8, 2435, 2442, 2438.5, 8.0 }, + { 459, 8, 2443, 2450, 2446.5, 8.0 }, + { 460, 8, 2451, 2458, 2454.5, 8.0 }, + { 461, 8, 2459, 2466, 2462.5, 8.0 }, + { 462, 8, 2467, 2474, 2470.5, 8.0 }, + { 463, 8, 2475, 2482, 2478.5, 8.0 }, + { 464, 8, 2483, 2490, 2486.5, 8.0 }, + { 465, 8, 2491, 2498, 2494.5, 8.0 }, + { 466, 7, 2499, 2505, 2502.0, 7.5 }, + { 467, 7, 2506, 2512, 2509.0, 7.0 }, + { 468, 7, 2513, 2519, 2516.0, 7.0 }, + { 469, 7, 2520, 2526, 2523.0, 7.0 }, + { 470, 7, 2527, 2533, 2530.0, 7.0 }, + { 471, 7, 2534, 2540, 2537.0, 7.0 }, + { 472, 7, 2541, 2547, 2544.0, 7.0 }, + { 473, 7, 2548, 2554, 2551.0, 7.0 }, + { 474, 7, 2555, 2561, 2558.0, 7.0 }, + { 475, 7, 2562, 2568, 2565.0, 7.0 }, + { 476, 7, 2569, 2575, 2572.0, 7.0 }, + { 477, 7, 2576, 2582, 2579.0, 7.0 }, + { 478, 7, 2583, 2589, 2586.0, 7.0 }, + { 479, 7, 2590, 2596, 2593.0, 7.0 }, + { 480, 6, 2597, 2602, 2599.5, 6.5 }, + { 481, 6, 2603, 2608, 2605.5, 6.0 }, + { 482, 6, 2609, 2614, 2611.5, 6.0 }, + { 483, 6, 2615, 2620, 2617.5, 6.0 }, + { 484, 6, 2621, 2626, 2623.5, 6.0 }, + { 485, 6, 2627, 2632, 2629.5, 6.0 }, + { 486, 6, 2633, 2638, 2635.5, 6.0 }, + { 487, 6, 2639, 2644, 2641.5, 6.0 }, + { 488, 6, 2645, 2650, 2647.5, 6.0 }, + { 489, 6, 2651, 2656, 2653.5, 6.0 }, + { 490, 6, 2657, 2662, 2659.5, 6.0 }, + { 491, 6, 2663, 2668, 2665.5, 6.0 }, + { 492, 5, 2669, 2673, 2671.0, 5.5 }, + { 493, 5, 2674, 2678, 2676.0, 5.0 }, + { 494, 5, 2679, 2683, 2681.0, 5.0 }, + { 495, 5, 2684, 2688, 2686.0, 5.0 }, + { 496, 5, 2689, 2693, 2691.0, 5.0 }, + { 497, 5, 2694, 2698, 2696.0, 5.0 }, + { 498, 5, 2699, 2703, 2701.0, 5.0 }, + { 499, 5, 2704, 2708, 2706.0, 5.0 }, + { 500, 5, 2709, 2713, 2711.0, 5.0 }, + { 501, 5, 2714, 2718, 2716.0, 5.0 }, + { 502, 5, 2719, 2723, 2721.0, 5.0 }, + { 503, 5, 2724, 2728, 2726.0, 5.0 }, + { 504, 5, 2729, 2733, 2731.0, 5.0 }, + { 505, 5, 2734, 2738, 2736.0, 5.0 }, + { 506, 5, 2739, 2743, 2741.0, 5.0 }, + { 507, 5, 2744, 2748, 2746.0, 5.0 }, + { 508, 5, 2749, 2753, 2751.0, 5.0 }, + { 509, 5, 2754, 2758, 2756.0, 5.0 }, + { 510, 4, 2759, 2762, 2760.5, 4.5 }, + { 511, 4, 2763, 2766, 2764.5, 4.0 }, + { 512, 4, 2767, 2770, 2768.5, 4.0 }, + { 513, 4, 2771, 2774, 2772.5, 4.0 }, + { 514, 4, 2775, 2778, 2776.5, 4.0 }, + { 515, 4, 2779, 2782, 2780.5, 4.0 }, + { 516, 4, 2783, 2786, 2784.5, 4.0 }, + { 517, 4, 2787, 2790, 2788.5, 4.0 }, + { 518, 4, 2791, 2794, 2792.5, 4.0 }, + { 519, 4, 2795, 2798, 2796.5, 4.0 }, + { 520, 4, 2799, 2802, 2800.5, 4.0 }, + { 521, 4, 2803, 2806, 2804.5, 4.0 }, + { 522, 4, 2807, 2810, 2808.5, 4.0 }, + { 523, 4, 2811, 2814, 2812.5, 4.0 }, + { 524, 4, 2815, 2818, 2816.5, 4.0 }, + { 525, 4, 2819, 2822, 2820.5, 4.0 }, + { 526, 4, 2823, 2826, 2824.5, 4.0 }, + { 527, 4, 2827, 2830, 2828.5, 4.0 }, + { 528, 4, 2831, 2834, 2832.5, 4.0 }, + { 529, 4, 2835, 2838, 2836.5, 4.0 }, + { 530, 4, 2839, 2842, 2840.5, 4.0 }, + { 531, 4, 2843, 2846, 2844.5, 4.0 }, + { 532, 4, 2847, 2850, 2848.5, 4.0 }, + { 533, 4, 2851, 2854, 2852.5, 4.0 }, + { 534, 3, 2855, 2857, 2856.0, 3.5 }, + { 535, 3, 2858, 2860, 2859.0, 3.0 }, + { 536, 3, 2861, 2863, 2862.0, 3.0 }, + { 537, 3, 2864, 2866, 2865.0, 3.0 }, + { 538, 3, 2867, 2869, 2868.0, 3.0 }, + { 539, 3, 2870, 2872, 2871.0, 3.0 }, + { 540, 3, 2873, 2875, 2874.0, 3.0 }, + { 541, 3, 2876, 2878, 2877.0, 3.0 }, + { 542, 3, 2879, 2881, 2880.0, 3.0 }, + { 543, 3, 2882, 2884, 2883.0, 3.0 }, + { 544, 3, 2885, 2887, 2886.0, 3.0 }, + { 545, 3, 2888, 2890, 2889.0, 3.0 }, + { 546, 3, 2891, 2893, 2892.0, 3.0 }, + { 547, 3, 2894, 2896, 2895.0, 3.0 }, + { 548, 3, 2897, 2899, 2898.0, 3.0 }, + { 549, 3, 2900, 2902, 2901.0, 3.0 }, + { 550, 3, 2903, 2905, 2904.0, 3.0 }, + { 551, 3, 2906, 2908, 2907.0, 3.0 }, + { 552, 3, 2909, 2911, 2910.0, 3.0 }, + { 553, 3, 2912, 2914, 2913.0, 3.0 }, + { 554, 3, 2915, 2917, 2916.0, 3.0 }, + { 555, 3, 2918, 2920, 2919.0, 3.0 }, + { 556, 3, 2921, 2923, 2922.0, 3.0 }, + { 557, 2, 2924, 2925, 2924.5, 2.5 }, + { 558, 2, 2926, 2927, 2926.5, 2.0 }, + { 559, 2, 2928, 2929, 2928.5, 2.0 }, + { 560, 2, 2930, 2931, 2930.5, 2.0 }, + { 561, 2, 2932, 2933, 2932.5, 2.0 }, + { 562, 2, 2934, 2935, 2934.5, 2.0 }, + { 563, 2, 2936, 2937, 2936.5, 2.0 }, + { 564, 2, 2938, 2939, 2938.5, 2.0 }, + { 565, 2, 2940, 2941, 2940.5, 2.0 }, + { 566, 2, 2942, 2943, 2942.5, 2.0 }, + { 567, 2, 2944, 2945, 2944.5, 2.0 }, + { 568, 2, 2946, 2947, 2946.5, 2.0 }, + { 569, 2, 2948, 2949, 2948.5, 2.0 }, + { 570, 2, 2950, 2951, 2950.5, 2.0 }, + { 571, 2, 2952, 2953, 2952.5, 2.0 }, + { 572, 2, 2954, 2955, 2954.5, 2.0 }, + { 573, 2, 2956, 2957, 2956.5, 2.0 }, + { 574, 2, 2958, 2959, 2958.5, 2.0 }, + { 575, 2, 2960, 2961, 2960.5, 2.0 }, + { 576, 2, 2962, 2963, 2962.5, 2.0 }, + { 577, 2, 2964, 2965, 2964.5, 2.0 }, + { 578, 2, 2966, 2967, 2966.5, 2.0 }, + { 579, 2, 2968, 2969, 2968.5, 2.0 }, + { 580, 2, 2970, 2971, 2970.5, 2.0 }, + { 581, 2, 2972, 2973, 2972.5, 2.0 }, + { 582, 2, 2974, 2975, 2974.5, 2.0 }, + { 583, 2, 2976, 2977, 2976.5, 2.0 }, + { 584, 2, 2978, 2979, 2978.5, 2.0 }, + { 585, 2, 2980, 2981, 2980.5, 2.0 }, + { 586, 2, 2982, 2983, 2982.5, 2.0 }, + { 587, 2, 2984, 2985, 2984.5, 2.0 }, + { 588, 2, 2986, 2987, 2986.5, 2.0 }, + { 589, 2, 2988, 2989, 2988.5, 2.0 }, + { 590, 2, 2990, 2991, 2990.5, 2.0 }, + { 591, 2, 2992, 2993, 2992.5, 2.0 }, + { 592, 2, 2994, 2995, 2994.5, 2.0 }, + { 593, 2, 2996, 2997, 2996.5, 2.0 }, + { 594, 2, 2998, 2999, 2998.5, 2.0 }, + { 595, 2, 3000, 3001, 3000.5, 2.0 }, + { 596, 2, 3002, 3003, 3002.5, 2.0 }, + { 597, 2, 3004, 3005, 3004.5, 2.0 }, + { 598, 2, 3006, 3007, 3006.5, 2.0 }, + { 599, 2, 3008, 3009, 3008.5, 2.0 }, + { 600, 2, 3010, 3011, 3010.5, 2.0 }, + { 601, 2, 3012, 3013, 3012.5, 2.0 }, + { 602, 2, 3014, 3015, 3014.5, 2.0 }, + { 603, 2, 3016, 3017, 3016.5, 2.0 }, + { 604, 1, 3018, 3018, 3018.0, 1.5 }, + { 605, 1, 3019, 3019, 3019.0, 1.0 }, + { 606, 1, 3020, 3020, 3020.0, 1.0 }, + { 607, 1, 3021, 3021, 3021.0, 1.0 }, + { 608, 1, 3022, 3022, 3022.0, 1.0 }, + { 609, 1, 3023, 3023, 3023.0, 1.0 }, + { 610, 1, 3024, 3024, 3024.0, 1.0 }, + { 611, 1, 3025, 3025, 3025.0, 1.0 }, + { 612, 1, 3026, 3026, 3026.0, 1.0 }, + { 613, 1, 3027, 3027, 3027.0, 1.0 }, + { 614, 1, 3028, 3028, 3028.0, 1.0 }, + { 615, 1, 3029, 3029, 3029.0, 1.0 }, + { 616, 1, 3030, 3030, 3030.0, 1.0 }, + { 617, 1, 3031, 3031, 3031.0, 1.0 }, + { 618, 1, 3032, 3032, 3032.0, 1.0 }, + { 619, 1, 3033, 3033, 3033.0, 1.0 }, + { 620, 1, 3034, 3034, 3034.0, 1.0 }, + { 621, 1, 3035, 3035, 3035.0, 1.0 }, + { 622, 1, 3036, 3036, 3036.0, 1.0 }, + { 623, 1, 3037, 3037, 3037.0, 1.0 }, + { 624, 1, 3038, 3038, 3038.0, 1.0 }, + { 625, 1, 3039, 3039, 3039.0, 1.0 }, + { 626, 1, 3040, 3040, 3040.0, 1.0 }, + { 627, 1, 3041, 3041, 3041.0, 1.0 }, + { 628, 1, 3042, 3042, 3042.0, 1.0 }, + { 629, 1, 3043, 3043, 3043.0, 1.0 }, + { 630, 1, 3044, 3044, 3044.0, 1.0 }, + { 631, 1, 3045, 3045, 3045.0, 1.0 }, + { 632, 1, 3046, 3046, 3046.0, 1.0 }, + { 633, 1, 3047, 3047, 3047.0, 1.0 }, + { 634, 1, 3048, 3048, 3048.0, 1.0 }, + { 635, 1, 3049, 3049, 3049.0, 1.0 }, + { 636, 1, 3050, 3050, 3050.0, 1.0 }, + { 637, 1, 3051, 3051, 3051.0, 1.0 }, + { 638, 1, 3052, 3052, 3052.0, 1.0 }, + { 639, 1, 3053, 3053, 3053.0, 1.0 }, + { 640, 1, 3054, 3054, 3054.0, 1.0 }, + { 641, 1, 3055, 3055, 3055.0, 1.0 }, + { 642, 1, 3056, 3056, 3056.0, 1.0 }, + { 643, 1, 3057, 3057, 3057.0, 1.0 }, + { 644, 1, 3058, 3058, 3058.0, 1.0 }, + { 645, 1, 3059, 3059, 3059.0, 1.0 }, + { 646, 1, 3060, 3060, 3060.0, 1.0 }, + { 647, 1, 3061, 3061, 3061.0, 1.0 }, + { 648, 1, 3062, 3062, 3062.0, 1.0 }, + { 649, 1, 3063, 3063, 3063.0, 1.0 }, + { 650, 1, 3064, 3064, 3064.0, 1.0 }, + { 651, 1, 3065, 3065, 3065.0, 1.0 }, + { 652, 1, 3066, 3066, 3066.0, 1.0 }, + { 653, 1, 3067, 3067, 3067.0, 1.0 }, + { 654, 1, 3068, 3068, 3068.0, 1.0 }, + { 655, 1, 3069, 3069, 3069.0, 1.0 }, + { 656, 1, 3070, 3070, 3070.0, 1.0 }, + { 657, 1, 3071, 3071, 3071.0, 1.0 }, + { 658, 1, 3072, 3072, 3072.0, 1.0 }, + { 659, 1, 3073, 3073, 3073.0, 1.0 }, + { 660, 1, 3074, 3074, 3074.0, 1.0 }, + { 661, 1, 3075, 3075, 3075.0, 1.0 }, + { 662, 1, 3076, 3076, 3076.0, 1.0 }, + { 663, 1, 3077, 3077, 3077.0, 1.0 }, + { 664, 1, 3078, 3078, 3078.0, 1.0 }, + { 665, 1, 3079, 3079, 3079.0, 1.0 }, + { 666, 1, 3080, 3080, 3080.0, 1.0 }, + { 667, 1, 3081, 3081, 3081.0, 1.0 }, + { 668, 1, 3082, 3082, 3082.0, 1.0 }, + { 669, 1, 3083, 3083, 3083.0, 1.0 }, + { 670, 1, 3084, 3084, 3084.0, 1.0 }, + { 671, 1, 3085, 3085, 3085.0, 1.0 }, + { 672, 1, 3086, 3086, 3086.0, 1.0 }, + { 673, 1, 3087, 3087, 3087.0, 1.0 }, + { 674, 1, 3088, 3088, 3088.0, 1.0 }, + { 675, 1, 3089, 3089, 3089.0, 1.0 }, + { 676, 1, 3090, 3090, 3090.0, 1.0 }, + { 677, 1, 3091, 3091, 3091.0, 1.0 }, + { 678, 1, 3092, 3092, 3092.0, 1.0 }, + { 679, 1, 3093, 3093, 3093.0, 1.0 }, + { 680, 1, 3094, 3094, 3094.0, 1.0 }, + { 681, 1, 3095, 3095, 3095.0, 1.0 }, + { 682, 1, 3096, 3096, 3096.0, 1.0 }, + { 683, 1, 3097, 3097, 3097.0, 1.0 }, + { 684, 1, 3098, 3098, 3098.0, 1.0 }, + { 685, 1, 3099, 3099, 3099.0, 1.0 }, + { 686, 1, 3100, 3100, 3100.0, 1.0 }, + { 687, 1, 3101, 3101, 3101.0, 1.0 }, + { 688, 1, 3102, 3102, 3102.0, 1.0 }, + { 689, 1, 3103, 3103, 3103.0, 1.0 }, + { 690, 1, 3104, 3104, 3104.0, 1.0 }, + { 691, 1, 3105, 3105, 3105.0, 1.0 }, + { 692, 1, 3106, 3106, 3106.0, 1.0 }, + { 693, 1, 3107, 3107, 3107.0, 1.0 }, + { 694, 1, 3108, 3108, 3108.0, 1.0 }, + { 695, 1, 3109, 3109, 3109.0, 1.0 }, + { 696, 1, 3110, 3110, 3110.0, 1.0 }, + { 697, 1, 3111, 3111, 3111.0, 1.0 }, + { 698, 1, 3112, 3112, 3112.0, 1.0 }, + { 699, 1, 3113, 3113, 3113.0, 1.0 }, + { 700, 1, 3114, 3114, 3114.0, 1.0 }, + { 701, 1, 3115, 3115, 3115.0, 1.0 }, + { 702, 1, 3116, 3116, 3116.0, 1.0 }, + { 703, 1, 3117, 3117, 3117.0, 1.0 }, + { 704, 1, 3118, 3118, 3118.0, 1.0 }, + { 705, 1, 3119, 3119, 3119.0, 1.0 }, + { 706, 1, 3120, 3120, 3120.0, 1.0 }, + { 707, 1, 3121, 3121, 3121.0, 1.0 }, + { 708, 1, 3122, 3122, 3122.0, 1.0 }, + { 709, 1, 3123, 3123, 3123.0, 1.0 }, + { 710, 1, 3124, 3124, 3124.0, 1.0 }, + { 711, 1, 3125, 3125, 3125.0, 1.0 }, + { 712, 1, 3126, 3126, 3126.0, 1.0 }, + { 713, 1, 3127, 3127, 3127.0, 1.0 }, + { 714, 1, 3128, 3128, 3128.0, 1.0 }, + { 715, 1, 3129, 3129, 3129.0, 1.0 }, + { 716, 1, 3130, 3130, 3130.0, 1.0 }, + { 717, 1, 3131, 3131, 3131.0, 1.0 }, + { 718, 1, 3132, 3132, 3132.0, 1.0 }, + { 719, 1, 3133, 3133, 3133.0, 1.0 }, + { 720, 1, 3134, 3134, 3134.0, 1.0 }, + { 721, 1, 3135, 3135, 3135.0, 1.0 }, + { 722, 1, 3136, 3136, 3136.0, 1.0 }, + { 723, 1, 3137, 3137, 3137.0, 1.0 }, + { 724, 1, 3138, 3138, 3138.0, 1.0 }, + { 725, 1, 3139, 3139, 3139.0, 1.0 }, + { 726, 1, 3140, 3140, 3140.0, 1.0 }, + { 727, 1, 3141, 3141, 3141.0, 1.0 }, + { 728, 1, 3142, 3142, 3142.0, 1.0 }, + { 729, 1, 3143, 3143, 3143.0, 1.0 }, + { 730, 1, 3144, 3144, 3144.0, 1.0 }, + { 731, 1, 3145, 3145, 3145.0, 1.0 }, + { 732, 1, 3146, 3146, 3146.0, 1.0 }, + { 733, 1, 3147, 3147, 3147.0, 1.0 }, + { 734, 1, 3148, 3148, 3148.0, 1.0 }, + { 735, 1, 3149, 3149, 3149.0, 1.0 }, + { 736, 1, 3150, 3150, 3150.0, 1.0 }, + { 737, 1, 3151, 3151, 3151.0, 1.0 }, + { 738, 1, 3152, 3152, 3152.0, 1.0 }, + { 739, 1, 3153, 3153, 3153.0, 1.0 }, + { 740, 1, 3154, 3154, 3154.0, 1.0 }, + { 741, 1, 3155, 3155, 3155.0, 1.0 }, + { 742, 1, 3156, 3156, 3156.0, 1.0 }, + { 743, 1, 3157, 3157, 3157.0, 1.0 }, + { 744, 1, 3158, 3158, 3158.0, 1.0 }, + { 745, 1, 3159, 3159, 3159.0, 1.0 }, + { 746, 1, 3160, 3160, 3160.0, 1.0 }, + { 747, 1, 3161, 3161, 3161.0, 1.0 }, + { 748, 1, 3162, 3162, 3162.0, 1.0 }, + { 749, 1, 3163, 3163, 3163.0, 1.0 }, + { 750, 1, 3164, 3164, 3164.0, 1.0 }, + { 751, 1, 3165, 3165, 3165.0, 1.0 }, + { 752, 1, 3166, 3166, 3166.0, 1.0 }, + { 753, 1, 3167, 3167, 3167.0, 1.0 }, + { 754, 1, 3168, 3168, 3168.0, 1.0 }, + { 755, 1, 3169, 3169, 3169.0, 1.0 }, + { 756, 1, 3170, 3170, 3170.0, 1.0 }, + { 757, 1, 3171, 3171, 3171.0, 1.0 }, + { 758, 1, 3172, 3172, 3172.0, 1.0 }, + { 759, 1, 3173, 3173, 3173.0, 1.0 }, + { 760, 1, 3174, 3174, 3174.0, 1.0 }, + { 761, 1, 3175, 3175, 3175.0, 1.0 }, + { 762, 1, 3176, 3176, 3176.0, 1.0 }, + { 763, 1, 3177, 3177, 3177.0, 1.0 }, + { 764, 1, 3178, 3178, 3178.0, 1.0 }, + { 765, 1, 3179, 3179, 3179.0, 1.0 }, + { 766, 1, 3180, 3180, 3180.0, 1.0 }, + { 767, 1, 3181, 3181, 3181.0, 1.0 } +}; + +#endif + +/* +*_Hist Jan 24 2001 Kris Becker USGS, Flagstaff Original Version +* Dec 20 2002 Janet Barrett, Added components for piecewise linear +* equations for mapping between the image sample and +* detector. +*_End +*************************************************************************/ diff --git a/isis/src/mgs/objs/MocLabels/unitTest.cpp b/isis/src/mgs/objs/MocLabels/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e1701faa6c0891e8120ee23e0555da4142dfc603 --- /dev/null +++ b/isis/src/mgs/objs/MocLabels/unitTest.cpp @@ -0,0 +1,64 @@ +#include "iException.h" +#include "Pvl.h" +#include "MocLabels.h" +#include "Preference.h" + +using namespace std; + +int main () { + Isis::Preference::Preferences(true); + + try { + cout << "Unit test for MocLabels" << endl; + cout << "MocWideAngleCamera cub test..." << endl; + Isis::Pvl p1("$mgs/testData/ab102401.cub"); + Isis::Mgs::MocLabels lab1(p1); + + cout << "NarrowAngle? " << lab1.NarrowAngle() << endl; + cout << "WideAngle? " << lab1.WideAngle() << endl; + cout << "WideAngleRed? " << lab1.WideAngleRed() << endl; + cout << "WideAngleBlue? " << lab1.WideAngleBlue() << endl; + cout << "Crosstrack Summing = " << lab1.CrosstrackSumming() << endl; + cout << "Downtrack Summing = " << lab1.DowntrackSumming() << endl; + cout << "First Line Sample = " << lab1.FirstLineSample() << endl; + cout << "Focal Plane Temperature = " << lab1.FocalPlaneTemperature() << endl; + cout << "Line Rate = " << lab1.LineRate() << endl; + cout << "Exposure Duration = " << lab1.ExposureDuration() << endl; + cout << "Start Time = " << lab1.StartTime() << endl; + cout << "Detectors = " << lab1.Detectors() << endl; + cout << "StartDetector(1) = " << lab1.StartDetector(1) << endl; + cout << "EndDetector(1) = " << lab1.EndDetector(1) << endl; + cout << "Sample = " << lab1.Sample(lab1.StartDetector(1)) << endl; + cout << "EphemerisTime = " << lab1.EphemerisTime(1) << endl; + cout << "Gain = " << lab1.Gain() << endl; + cout << "Offset = " << lab1.Offset() << endl << endl; + + cout << "MocNarrowAngleCamera cub test..." << endl; + Isis::Pvl p2("$mgs/testData/fha00491.lev1.cub"); + Isis::Mgs::MocLabels lab2(p2); + + cout << "NarrowAngle? " << lab2.NarrowAngle() << endl; + cout << "WideAngle? " << lab2.WideAngle() << endl; + cout << "WideAngleRed? " << lab2.WideAngleRed() << endl; + cout << "WideAngleBlue? " << lab2.WideAngleBlue() << endl; + cout << "Crosstrack Summing = " << lab2.CrosstrackSumming() << endl; + cout << "Downtrack Summing = " << lab2.DowntrackSumming() << endl; + cout << "First Line Sample = " << lab2.FirstLineSample() << endl; + cout << "Focal Plane Temperature = " << lab2.FocalPlaneTemperature() << endl; + cout << "Line Rate = " << lab2.LineRate() << endl; + cout << "Exposure Duration = " << lab2.ExposureDuration() << endl; + cout << "Start Time = " << lab2.StartTime() << endl; + cout << "Detectors = " << lab2.Detectors() << endl; + cout << "StartDetector(1) = " << lab2.StartDetector(1) << endl; + cout << "EndDetector(1) = " << lab2.EndDetector(1) << endl; + cout << "Sample = " << lab2.Sample(lab2.StartDetector(1)) << endl; + cout << "EphemerisTime = " << lab2.EphemerisTime(1) << endl; + cout << "Gain = " << lab2.Gain() << endl; + cout << "Offset = " << lab2.Offset() << endl << endl; + + } + catch (Isis::iException &e) { + e.Report(); + } +} + diff --git a/isis/src/mgs/objs/MocNarrowAngleCamera/Camera.plugin b/isis/src/mgs/objs/MocNarrowAngleCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..502d685024346847a178aa99cba2c7c93bfbd9ee --- /dev/null +++ b/isis/src/mgs/objs/MocNarrowAngleCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = MarsGlobalSurveyor/MOC-NA + Version = 1 + Library = MocNarrowAngleCamera + Routine = MocNarrowAngleCameraPlugin +EndGroup + diff --git a/isis/src/mgs/objs/MocNarrowAngleCamera/Makefile b/isis/src/mgs/objs/MocNarrowAngleCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46c354a2bf80a4d8537bda94dd2c49c3207d8d2d --- /dev/null +++ b/isis/src/mgs/objs/MocNarrowAngleCamera/Makefile @@ -0,0 +1,5 @@ +INCS = MocNarrowAngleCamera.h +SRCS = MocNarrowAngleCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/mgs/objs/MocNarrowAngleCamera/MocNarrowAngleCamera.cpp b/isis/src/mgs/objs/MocNarrowAngleCamera/MocNarrowAngleCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6adde2ba19240f2ba2fee830b65ec234ffa3b3a --- /dev/null +++ b/isis/src/mgs/objs/MocNarrowAngleCamera/MocNarrowAngleCamera.cpp @@ -0,0 +1,61 @@ +#include "MocNarrowAngleCamera.h" +#include "iString.h" +#include "iException.h" +#include "LineScanCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraDistortionMap.h" +#include "LineScanCameraGroundMap.h" +#include "LineScanCameraSkyMap.h" + +using namespace std; +namespace Isis { + namespace Mgs { + // constructors + MocNarrowAngleCamera::MocNarrowAngleCamera (Isis::Pvl &lab) : Isis::LineScanCamera(lab) { + // Set up the camera info from ik/iak kernels +// LoadEulerMounting(); + SetFocalLength(); + SetPixelPitch(); + InstrumentRotation()->SetTimeBias(-1.15); + + // Get the start time from labels + Isis::PvlGroup &inst = lab.FindGroup ("Instrument",Isis::Pvl::Traverse); + string stime = inst["SpacecraftClockCount"]; + SpiceDouble etStart; + scs2e_c (NaifSpkCode(),stime.c_str(),&etStart); + + // Get other info from labels + double csum = inst["CrosstrackSumming"]; + double dsum = inst["DowntrackSumming"]; + double lineRate = (double) inst["LineExposureDuration"] / 1000.0; + lineRate *= dsum; + double ss = inst["FirstLineSample"]; + + // Setup detector map + LineScanCameraDetectorMap *detectorMap = + new LineScanCameraDetectorMap(this,etStart,lineRate); + detectorMap->SetDetectorSampleSumming(csum); + detectorMap->SetDetectorLineSumming(dsum); + detectorMap->SetStartingDetectorSample(ss); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap = + new CameraFocalPlaneMap(this,NaifIkCode()); + focalMap->SetDetectorOrigin(1024.5,0.0); + focalMap->SetDetectorOffset(0.0,0.0); + + // Setup distortion map + new CameraDistortionMap(this); + + // Setup the ground and sky map + new LineScanCameraGroundMap(this); + new LineScanCameraSkyMap(this); + + LoadCache(); + } + } +} + +extern "C" Isis::Camera *MocNarrowAngleCameraPlugin (Isis::Pvl &lab) { + return new Isis::Mgs::MocNarrowAngleCamera(lab); +} diff --git a/isis/src/mgs/objs/MocNarrowAngleCamera/MocNarrowAngleCamera.h b/isis/src/mgs/objs/MocNarrowAngleCamera/MocNarrowAngleCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..400053d3d8065711bb734c74985553290e9ea97c --- /dev/null +++ b/isis/src/mgs/objs/MocNarrowAngleCamera/MocNarrowAngleCamera.h @@ -0,0 +1,26 @@ +#ifndef MocNarrowAngleCamera_h +#define MocNarrowAngleCamera_h + +#include "LineScanCamera.h" + +namespace Isis { + namespace Mgs { + /** + * @internal + * @history 2008-08-08 Steven Lambright Now using the new LoadCache(...) + * method instead of CreateCache(...). + * @history 2009-03-07 Debbie A. Cook Removed reference to obsolute + * CameraDetectorMap methods + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class MocNarrowAngleCamera : public LineScanCamera { + public: + MocNarrowAngleCamera (Isis::Pvl &lab); + + ~MocNarrowAngleCamera () {}; + }; + }; +}; + +#endif diff --git a/isis/src/mgs/objs/MocNarrowAngleCamera/MocNarrowAngleCamera.truth b/isis/src/mgs/objs/MocNarrowAngleCamera/MocNarrowAngleCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..5940d71502d28b2f51bec8e0f3101d56e1640ebd --- /dev/null +++ b/isis/src/mgs/objs/MocNarrowAngleCamera/MocNarrowAngleCamera.truth @@ -0,0 +1,20 @@ +Unit Test for MocNarrowAngleCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/mgs/objs/MocNarrowAngleCamera/unitTest.cpp b/isis/src/mgs/objs/MocNarrowAngleCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5b045a7e098a7b4cc5b87d4e60730afb97a4071e --- /dev/null +++ b/isis/src/mgs/objs/MocNarrowAngleCamera/unitTest.cpp @@ -0,0 +1,116 @@ +using namespace std; + +#include +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); +/** + * @internal + * @history 2009-08-03 Jeannie Walldren - Changed known lat + * and lon. + * @history 2009-08-06 Jeannie Walldren - Added cmath include + * and changed calls to abs() to fabs() since the + * abs() function takes integer values while the + * fabs() takes floats. Changed Center Lat tolerance + * from 1E-10 to 2E-10 since the difference on Darwin powerpc + * was 1.93E-10. Changed Center Lon tolerance from + * 1E-10 to 1.1E-10 since the difference on Darwin powerpc + * was 1.03E-10. + * @history 2010-02-24 Christopher Austin - Changed the knowLat/Lon + * in accordence with the system changes + */ + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for MocNarrowAngleCamera..." << endl; + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + // double knownLat = -9.931519304695483; + // double knownLon = 286.6184572896669; + // double knownLat = -9.931519304671058; + // double knownLon = 286.6184572896659; + // blackflag + // double knownLat = -9.931519304119526; + // double knownLon = 286.6184572896647; + // deet (current) + // double knownLat = -9.931519304735847; + // double knownLon = 286.6184572896974; + double knownLat = -9.931519304735847; + double knownLon = 286.6184572896974; + + //Isis::Pvl p("$mgs/testData/lub0428b.cub"); + Isis::Pvl p("$mgs/testData/fha00491.lev1.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(fabs(cam->UniversalLatitude() - knownLat) < 2E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(fabs(cam->UniversalLongitude() - knownLon) < 1.1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.001) deltaSamp = 0; + if (fabs(deltaLine) < 0.001) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/mgs/objs/MocNarrowAngleSumming/Makefile b/isis/src/mgs/objs/MocNarrowAngleSumming/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..94eb35552f5b01ebc7f65be3d02b23f25634c64e --- /dev/null +++ b/isis/src/mgs/objs/MocNarrowAngleSumming/Makefile @@ -0,0 +1,5 @@ +INCS = MocNarrowAngleSumming.h +SRCS = +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/mgs/objs/MocNarrowAngleSumming/MocNarrowAngleSumming.h b/isis/src/mgs/objs/MocNarrowAngleSumming/MocNarrowAngleSumming.h new file mode 100644 index 0000000000000000000000000000000000000000..1168348d8bbc80ad1fe5505bba95a0b93ce1fb74 --- /dev/null +++ b/isis/src/mgs/objs/MocNarrowAngleSumming/MocNarrowAngleSumming.h @@ -0,0 +1,33 @@ +#ifndef MocNarrowAngleSumming_h +#define MocNarrowAngleSumming_h + +namespace Isis { + namespace Mgs { + class MocNarrowAngleSumming { + public: + // constructors + MocNarrowAngleSumming (int csum, int ss) { + p_csum = csum; + p_ss = ((double) csum / 2.0) + 0.5 + (double) (ss - 1); + } + + // destructor + ~MocNarrowAngleSumming () {}; + + inline double Detector (double sample) const { + return (sample - 1.0) * (double) p_csum + p_ss; + } + + inline double Sample (double detector) const { + return (detector - p_ss) / ((double) p_csum) + 1.0; + } + + private: + int p_csum; + double p_ss; + + }; + }; +}; + +#endif diff --git a/isis/src/mgs/objs/MocNarrowAngleSumming/MocNarrowAngleSumming.truth b/isis/src/mgs/objs/MocNarrowAngleSumming/MocNarrowAngleSumming.truth new file mode 100644 index 0000000000000000000000000000000000000000..ddb4725577877bddb2a270bb62864aca68380bfb --- /dev/null +++ b/isis/src/mgs/objs/MocNarrowAngleSumming/MocNarrowAngleSumming.truth @@ -0,0 +1,24 @@ +Unit test for Isis::Mgs::MocNarrowAngleSumming +Testing csum=1, ss=1 +1 +2 +3 +1 +2 +3 + +Testing csum=2, ss=1 +1.5 +3.5 +5.5 +1 +2 +3 + +Testing csum=3, ss=10 +11 +14 +17 +1 +2 +3 diff --git a/isis/src/mgs/objs/MocNarrowAngleSumming/unitTest.cpp b/isis/src/mgs/objs/MocNarrowAngleSumming/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dae60e58aa3f0ad737c7fc6770ebcdcd0dcf4200 --- /dev/null +++ b/isis/src/mgs/objs/MocNarrowAngleSumming/unitTest.cpp @@ -0,0 +1,42 @@ +using namespace std; + +#include +#include + +#include "MocNarrowAngleSumming.h" +#include "Preference.h" +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Unit test for Isis::Mgs::MocNarrowAngleSumming" << endl; + + cout << "Testing csum=1, ss=1" << endl; + Isis::Mgs::MocNarrowAngleSumming s1(1,1); + cout << s1.Detector(1.0) << endl; + cout << s1.Detector(2.0) << endl; + cout << s1.Detector(3.0) << endl; + cout << s1.Sample(s1.Detector(1.0)) << endl; + cout << s1.Sample(s1.Detector(2.0)) << endl; + cout << s1.Sample(s1.Detector(3.0)) << endl; + cout << endl; + + cout << "Testing csum=2, ss=1" << endl; + Isis::Mgs::MocNarrowAngleSumming s2(2,1); + cout << s2.Detector(1.0) << endl; + cout << s2.Detector(2.0) << endl; + cout << s2.Detector(3.0) << endl; + cout << s2.Sample(s2.Detector(1.0)) << endl; + cout << s2.Sample(s2.Detector(2.0)) << endl; + cout << s2.Sample(s2.Detector(3.0)) << endl; + cout << endl; + + cout << "Testing csum=3, ss=10" << endl; + Isis::Mgs::MocNarrowAngleSumming s3(3,10); + cout << s3.Detector(1.0) << endl; + cout << s3.Detector(2.0) << endl; + cout << s3.Detector(3.0) << endl; + cout << s3.Sample(s3.Detector(1.0)) << endl; + cout << s3.Sample(s3.Detector(2.0)) << endl; + cout << s3.Sample(s3.Detector(3.0)) << endl; +} + diff --git a/isis/src/mgs/objs/MocWideAngleCamera/Camera.plugin b/isis/src/mgs/objs/MocWideAngleCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..62c0de7205f8e059375d8784ff34cc1822643604 --- /dev/null +++ b/isis/src/mgs/objs/MocWideAngleCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = MarsGlobalSurveyor/MOC-WA + Version = 1 + Library = MocWideAngleCamera + Routine = MocWideAngleCameraPlugin +EndGroup + diff --git a/isis/src/mgs/objs/MocWideAngleCamera/Makefile b/isis/src/mgs/objs/MocWideAngleCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f7e4482ae1a1874ec5effdefe05cd96e003a1473 --- /dev/null +++ b/isis/src/mgs/objs/MocWideAngleCamera/Makefile @@ -0,0 +1,5 @@ +INCS = MocWideAngleCamera.h MocWideAngleDistortionMap.h MocWideAngleDetectorMap.h +SRCS = MocWideAngleCamera.cpp MocWideAngleDistortionMap.cpp MocWideAngleDetectorMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleCamera.cpp b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b498066cf36ab5db186b38aa7450227ffd01677d --- /dev/null +++ b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleCamera.cpp @@ -0,0 +1,78 @@ +#include "MocWideAngleCamera.h" +#include "MocWideAngleDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "MocWideAngleDistortionMap.h" +#include "LineScanCameraGroundMap.h" +#include "LineScanCameraSkyMap.h" +#include "MocLabels.h" + +using namespace std; +namespace Isis { + namespace Mgs { + // constructors + /** + * @internal + * @history 2008-11-05 Jeannie Walldren - Replaced reference + * to MocLabels IsWideAngleRed() with MocLabels + * WideAngleRed(). + */ + MocWideAngleCamera::MocWideAngleCamera (Isis::Pvl &lab) : LineScanCamera(lab) { + // See if we have a moc camera + MocLabels *moclab = new Isis::Mgs::MocLabels(lab); + double lineRate = moclab->LineRate(); + double csum = moclab->CrosstrackSumming(); + double dsum = moclab->DowntrackSumming(); + double ss = moclab->FirstLineSample(); + bool isRed = moclab->WideAngleRed(); + + // Set up the camera info from ik/iak kernels + // LoadEulerMounting(); + SetFocalLength(); + SetPixelPitch(); + + if ( PixelPitch() == 1) { + throw iException::Message(iException::User, + "Cube file needs to be spiceinit'd with updated iak",_FILEINFO_); + } + InstrumentRotation()->SetTimeBias(-1.15); + + // Get the start time from labels + Isis::PvlGroup &inst = lab.FindGroup ("Instrument",Isis::Pvl::Traverse); + string stime = inst["SpacecraftClockCount"]; + SpiceDouble etStart; + scs2e_c (NaifSpkCode(),stime.c_str(),&etStart); + + // Setup detector map + MocWideAngleDetectorMap *detectorMap = + new MocWideAngleDetectorMap(this,etStart,lineRate,moclab); + detectorMap->SetDetectorSampleSumming(csum); + detectorMap->SetDetectorLineSumming(dsum); + detectorMap->SetStartingDetectorSample(ss); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap = + new CameraFocalPlaneMap(this,NaifIkCode()); + if (isRed) { + focalMap->SetDetectorOrigin(1674.65,0.0); + focalMap->SetDetectorOffset(0.0,6.7785); + } + else { + focalMap->SetDetectorOrigin(1688.58,0.0); + focalMap->SetDetectorOffset(0.0,-0.8486); + } + + // Setup distortion map + new MocWideAngleDistortionMap(this,isRed); + + // Setup the ground and sky map + new LineScanCameraGroundMap(this); + new LineScanCameraSkyMap(this); + + LoadCache(); + } + } +} + +extern "C" Isis::Camera *MocWideAngleCameraPlugin (Isis::Pvl &lab) { + return new Isis::Mgs::MocWideAngleCamera(lab); +} diff --git a/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleCamera.h b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..be742953bf86ef6675459dd28cb53d20d854fd24 --- /dev/null +++ b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleCamera.h @@ -0,0 +1,34 @@ +#ifndef MocWideAngleCamera_h +#define MocWideAngleCamera_h + +#include "LineScanCamera.h" + +namespace Isis { + namespace Mgs { + /** + * @brief Moc Wide Angle Camera Class + * + * @internal + * @history 2008-08-08 Steven Lambright Now using the new LoadCache(...) + * method instead of CreateCache(...). + * @history 2008-11-05 Jeannie Walldren - Replaced reference to + * MocLabels IsWideAngleRed() with MocLabels + * WideAngleRed(). + * @history 2008-11-07 Jeannie Walldren - Fixed documentation + * @history 2009-03-07 Debbie A. Cook Removed reference to obsolute + * CameraDetectorMap methods + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class MocWideAngleCamera : public Isis::LineScanCamera { + public: + // constructors + MocWideAngleCamera (Isis::Pvl &lab); + + // destructor + ~MocWideAngleCamera () {}; + }; + }; +}; + +#endif diff --git a/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleCamera.truth b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..d7a4afde0566eb0b5cc1006156a53b62cc8bb2f1 --- /dev/null +++ b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleCamera.truth @@ -0,0 +1,20 @@ +Unit Test for MocWideAngleCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleDetectorMap.cpp b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleDetectorMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b12cbf2c859192959fb22fdba992374a96ac9bdc --- /dev/null +++ b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleDetectorMap.cpp @@ -0,0 +1,60 @@ +#include "MocWideAngleDetectorMap.h" + +using namespace std; +namespace Isis { + namespace Mgs { + bool MocWideAngleDetectorMap::SetDetector(const double sample, + const double line) { + if (!LineScanCameraDetectorMap::SetDetector(sample,line)) return false; + + if ((p_moclab->CrosstrackSumming() == 13) || + (p_moclab->CrosstrackSumming() == 27)) { + int detector = (int) sample; + if (detector < 1) detector = 1; + if (detector >= p_moclab->Detectors()) detector = p_moclab->Detectors()-1; + double samp1 = p_moclab->Sample(detector-1); + double samp2 = p_moclab->Sample(detector); + if (samp1 < 0.0) return false; + if (samp2 < 0.0) return false; + + double m = (samp2 - samp1); + p_parentSample = m * (sample - detector) + samp2; + } + + return true; + } + + bool MocWideAngleDetectorMap::SetParent(const double sample, + const double line) { + if (!LineScanCameraDetectorMap::SetParent(sample,line)) return false; + + // Handle variable summing if necessary + if ((p_moclab->CrosstrackSumming() == 13) || + (p_moclab->CrosstrackSumming() == 27)) { + int isamp = (int) sample; + if (isamp < 2) { + p_detectorSample = p_moclab->StartDetector(1); + p_detectorSample += sample - 1.0; + } + else if (isamp > p_camera->Samples()) { + p_detectorSample = p_moclab->StartDetector(p_camera->Samples()); + p_detectorSample += sample - p_camera->Samples(); + } + else { + int ss = p_moclab->StartDetector(isamp-1); + int es = p_moclab->EndDetector(isamp-1); + double samp1 = (ss + es) / 2.0; + + ss = p_moclab->StartDetector(isamp); + es = p_moclab->EndDetector(isamp); + double samp2 = (ss + es) / 2.0; + + double m = (samp2 - samp1); + p_detectorSample = m * (sample - isamp) + samp1; + } + } + + return true; + } + } +} diff --git a/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleDetectorMap.h b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleDetectorMap.h new file mode 100644 index 0000000000000000000000000000000000000000..73da11b6a451ef12b509e379e7b4775406a811fe --- /dev/null +++ b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleDetectorMap.h @@ -0,0 +1,55 @@ +#ifndef MocWideAngleDetectorMap_h +#define MocWideAngleDetectorMap_h + +#include "LineScanCameraDetectorMap.h" +#include "MocLabels.h" + +namespace Isis { + namespace Mgs { + /** Convert between parent image coordinates and detector coordinates + * + * This class is used to convert between parent dector coordinates + * (sample/line) and detector coordinates for a the Moc wide angle + * camera. It is needed to handle variable summing modes + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2005-02-09 Jeff Anderson + * Original version + * + */ + class MocWideAngleDetectorMap : public LineScanCameraDetectorMap { + public: + /** + * Construct a detector map for line scan cameras + * + * @param parent The parent Camera Model + * @param etStart starting ephemeris time in seconds + * at the top of the first line + * @param lineRate the time in seconds between lines + * @param moclab The moc labels to use for the camera creation + * + */ + MocWideAngleDetectorMap(Camera *parent, const double etStart, + const double lineRate, MocLabels *moclab) : + LineScanCameraDetectorMap(parent,etStart,lineRate) { + p_moclab = moclab; + } + + //! Destructor + virtual ~MocWideAngleDetectorMap() {}; + + virtual bool SetParent(const double sample, const double line); + + virtual bool SetDetector(const double sample, const double line); + + private: + MocLabels *p_moclab; + }; + }; +}; +#endif diff --git a/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleDistortionMap.cpp b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleDistortionMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe43aa33e2d9865f18448cfb22df2417045aa365 --- /dev/null +++ b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleDistortionMap.cpp @@ -0,0 +1,117 @@ +#include "MocWideAngleDistortionMap.h" + +using namespace std; +namespace Isis { + namespace Mgs { + /** Constructor for MocWideAngleDistortionMap class + * + * Define the distortion model coefficients for a Moc Wide + * Angle camera. + * + * @param parent A pointer to the parent camera object + * @param red A flag indicating whether the filter is red or not + * + * @internal + * + * @history 2005-02-01 Jeff Anderson Original version + * @history 2007-02-24 Debbie A. Cook Changed to p_scale value for -1 to 1 + * to reflect the change to the affine coefficients + * in the new MocAddendum003.ti file + * + */ + MocWideAngleDistortionMap::MocWideAngleDistortionMap (Camera *parent, bool red) : + CameraDistortionMap (parent,1.0) { + // Set up distortion coefficients + if (red) { + p_coefs.push_back(0.9993258); + p_coefs.push_back(0.4655529); + p_coefs.push_back(-0.1548756); + p_coefs.push_back(1.827967); + p_coefs.push_back(-3.057435); + p_coefs.push_back(2.226331); + p_scale = 1.0; + p_icoefs.push_back(0.9995458); + p_icoefs.push_back(-0.4237090); + p_icoefs.push_back(0.2810857); + p_icoefs.push_back(-0.1697522); + p_icoefs.push_back(0.068131536); + p_icoefs.push_back(-0.012665644); + } + else { + p_coefs.push_back(1.000246); + p_coefs.push_back(0.4612695); + p_coefs.push_back(0.2352545); + p_coefs.push_back(0.3535922); + p_coefs.push_back(-0.2853861); + p_coefs.push_back(0.5574971); + p_scale = 1.000452; + p_icoefs.push_back(0.9994557); + p_icoefs.push_back(-0.4515307); + p_icoefs.push_back(0.3152195); + p_icoefs.push_back(-0.1993053); + p_icoefs.push_back(0.081707217); + p_icoefs.push_back(-0.014814299); + } + p_numCoefs = 6; + } + + + bool MocWideAngleDistortionMap::SetFocalPlane(const double dx, + const double dy) { + // Apply scale factor + p_focalPlaneX = dx; + p_focalPlaneY = dy; + double sdy = dy / p_scale; + + // See if we are close to the boresight which implies no distortion + double s2 = dx * dx + sdy * sdy; + if (s2 <= 1.0E-6) { + p_undistortedFocalPlaneX = dx; + p_undistortedFocalPlaneY = sdy; + return true; + } + + // Remove distortion + double s = sqrt(s2); + double ang = atan(s / p_camera->FocalLength()); + double ang2 = ang * ang; + double angp = p_coefs[p_numCoefs-1]; + for (int i=p_numCoefs-2; i>=0; i--) { + angp = angp * ang2 + p_coefs[i]; + } + angp = angp * ang; + double sp = p_camera->FocalLength() * tan(angp); + p_undistortedFocalPlaneX = dx * sp / s; + p_undistortedFocalPlaneY = sdy * sp / s; + return true; + } + + bool MocWideAngleDistortionMap::SetUndistortedFocalPlane(const double ux, + const double uy) { + p_undistortedFocalPlaneX = ux; + p_undistortedFocalPlaneY = uy; + + // See if we are close to boresight + double sp2 = ux * ux + uy * uy; + if (sp2 <= 1.0E-6) { + p_focalPlaneX = ux; + p_focalPlaneY = uy * p_scale; + return true; + } + + // Add distortion + double sp = sqrt(sp2); + double angp = atan(sp / p_camera->FocalLength()); + double angp2 = angp * angp; + double ang = p_icoefs[p_numCoefs-1]; + for (int i=p_numCoefs-2; i>=0; i--) { + ang = ang * angp2 + p_icoefs[i]; + } + ang = ang * angp; + double s = p_camera->FocalLength() * tan(ang); + p_focalPlaneX = ux * s / sp; + p_focalPlaneY = uy * s / sp * p_scale; + return true; + } + } +} diff --git a/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleDistortionMap.h b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleDistortionMap.h new file mode 100644 index 0000000000000000000000000000000000000000..f0760116e3551689a0413e30a67ba6a5502625a3 --- /dev/null +++ b/isis/src/mgs/objs/MocWideAngleCamera/MocWideAngleDistortionMap.h @@ -0,0 +1,40 @@ +#ifndef MocWideAngleDistortionMap_h +#define MocWideAngleDistortionMap_h + +#include +#include "CameraDistortionMap.h" + +namespace Isis { + namespace Mgs { + /** Distort/undistort focal plane coordinates + * + * Creates a map for adding/removing optical distortions + * from the focal plane of the Moc wide angle camera. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2005-02-01 Jeff Anderson + * Original version + * + */ + class MocWideAngleDistortionMap : public CameraDistortionMap { + public: + MocWideAngleDistortionMap(Camera *parent, bool red); + + virtual bool SetFocalPlane(const double dx, const double dy); + + virtual bool SetUndistortedFocalPlane(const double ux, const double uy); + + private: + std::vector p_coefs; + std::vector p_icoefs; + double p_scale; + int p_numCoefs; + }; + }; +}; +#endif diff --git a/isis/src/mgs/objs/MocWideAngleCamera/unitTest.cpp b/isis/src/mgs/objs/MocWideAngleCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f80e0b01baf057fcc228c4bed8d89f5dab7885ed --- /dev/null +++ b/isis/src/mgs/objs/MocWideAngleCamera/unitTest.cpp @@ -0,0 +1,118 @@ +using namespace std; + +#include +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); +/** + * @internal + * @history 2009-08-03 Jeannie Walldren - Changed known lat + * and lon. + * @history 2009-08-06 Jeannie Walldren - Added cmath include + * and changed calls to abs() to fabs() since the + * abs() function takes integer values while the + * fabs() takes floats. Changed Center Lat tolerance + * from 1E-10 to 1.7E-10 since the difference on + * Linux i686 was 1.68E-10. + * @history 2010-02-24 Christopher Austin - Altered knownLat/Lon + * for the new naif precision + */ +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for MocWideAngleCamera..." << endl; + /* + * MocWideAngleCamera: The line,samp to lat,lon to line,samp tolerance was increased for this + * camera model test. + */ + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + // double knownLat = 22.75215777208721; + // double knownLon = 225.6312171563951; + // double knownLat = 22.7521581002579; + // double knownLon = 225.6312103276302; + // double knownLat = 22.75215722648675; + // double knownLon = 225.6312106938898; + // blackflag + // double knownLat = 22.75215722969901; + // double knownLon = 225.6312106946057; + // deet + // double knownLat = 22.75215809276655; + // double knownLon = 225.6312105606938; + double knownLat = 22.75215809276655; + double knownLon = 225.6312105606938; + + Isis::Pvl p("$mgs/testData/ab102401.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(fabs(cam->UniversalLatitude() - knownLat) < 3.39E-9) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(fabs(cam->UniversalLongitude() - knownLon) < 7.97E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.01) deltaSamp = 0; + if (fabs(deltaLine) < 0.001) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/mgs/tsts/Makefile b/isis/src/mgs/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..016388fc898d8c89f380cae1fd08942c29611582 --- /dev/null +++ b/isis/src/mgs/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-42s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mgs/tsts/moc/Makefile b/isis/src/mgs/tsts/moc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..39795a4f2c985b654a6484123b6501c031440fc2 --- /dev/null +++ b/isis/src/mgs/tsts/moc/Makefile @@ -0,0 +1,40 @@ +APP1NAME = moc2isis +APP2NAME = spiceinit +APP3NAME = campt +APP4NAME = getsn + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APP1NAME) from= $(INPUT)/ab102302.img \ + to= $(OUTPUT)/ab102302.img--moc2isis-spiceinit.cub > /dev/null + + $(APP2NAME) from= $(OUTPUT)/ab102302.img--moc2isis-spiceinit.cub \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/ab102302.img--moc2isis-spiceinit.cub \ + to= $(OUTPUT)/ab102302.img--finalOutput.pvl SAMPLE=2 LINE=2 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/ab102302.img--moc2isis-spiceinit.cub \ + to= $(OUTPUT)/ab102302.img--finalOutput.pvl SAMPLE=335 LINE=2 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/ab102302.img--moc2isis-spiceinit.cub \ + to= $(OUTPUT)/ab102302.img--finalOutput.pvl SAMPLE=335 LINE=639 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/ab102302.img--moc2isis-spiceinit.cub \ + to= $(OUTPUT)/ab102302.img--finalOutput.pvl SAMPLE=2 LINE=639 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/ab102302.img--moc2isis-spiceinit.cub \ + to= $(OUTPUT)/ab102302.img--finalOutput.pvl SAMPLE=194 LINE=335 ALLOWOUTSIDE=no \ + > /dev/null + + echo -e "\nOutput of getsn..." > $(OUTPUT)/ab102302.img--getsnOutput.txt && \ + $(APP4NAME) from= $(OUTPUT)/ab102302.img--moc2isis-spiceinit.cub \ + >> $(OUTPUT)/ab102302.img--getsnOutput.txt + + $(RM) $(OUTPUT)/ab102302.img--moc2isis-spiceinit.cub > /dev/null + $(RM) $(OUTPUT)/../print.prt > /dev/null diff --git a/isis/src/mro/Makefile b/isis/src/mro/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/mro/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/mro/apps/Makefile b/isis/src/mro/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/mro/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/mro/apps/crism2isis/Makefile b/isis/src/mro/apps/crism2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/crism2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/crism2isis/crism2isis.cpp b/isis/src/mro/apps/crism2isis/crism2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f320dc909ca703a531dfa2d45c538360929ed15b --- /dev/null +++ b/isis/src/mro/apps/crism2isis/crism2isis.cpp @@ -0,0 +1,152 @@ +#include "Isis.h" + +#include "ProcessImportPds.h" +#include "UserInterface.h" +#include "Filename.h" +#include "TextFile.h" + +using namespace std; +using namespace Isis; + +void IsisMain() +{ + ProcessImportPds p; + Pvl pdsLabel; + UserInterface &ui = Application::GetUserInterface(); + + Filename inFile = ui.GetFilename("FROM"); + + p.SetPdsFile (inFile.Expanded(), "", pdsLabel); + //65535 is set to NULL + p.SetNull(65535, 65535); + + Cube *ocube = p.SetOutputCube("TO"); + + Pvl outLabel; + + Pvl labelPvl (inFile.Expanded()); + + iString prodType; + + if(labelPvl.HasKeyword("PRODUCT_TYPE")) { + prodType = (string)labelPvl.FindKeyword("PRODUCT_TYPE"); + } + else { + string msg = "Unsupported CRISM file type, supported types are: DDR, MRDR, and TRDR"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + if(prodType.Equal("MAP_PROJECTED_MULTISPECTRAL_RDR")) { + iString prodId; + if(labelPvl.HasKeyword("PRODUCT_ID")) { + prodId = (string)labelPvl.FindKeyword("PRODUCT_ID"); + prodId = prodId.substr(prodId.find("_")+1, prodId.find("_")); + } + else { + string msg = "Could not find label PRODUCT_ID, invalid MRDR"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + //If the product type is AL (Lambert albedo) or IF (I/F) + //Read the wavelength table and put the corresponding + //widths in the band bin group + if(prodId.Equal("MRRAL") || prodId.Equal("MRRIF")) { + //If the wavelength file is specified in the label + if(labelPvl.HasKeyword("MRO:WAVELENGTH_FILE_NAME")) { + PvlGroup bandBin = PvlGroup("BandBin"); + PvlKeyword origBand = PvlKeyword("OriginalBand"); + PvlKeyword widths = PvlKeyword("Width"); + iString tablePath = (string)labelPvl.FindKeyword("MRO:WAVELENGTH_FILE_NAME"); + tablePath = tablePath.DownCase(); + Filename tableFile = inFile.Path() + "/" + tablePath; + //Check if the wavelength file exists + if(tableFile.Exists()) { + TextFile *fin = new TextFile(tableFile.Expanded()); + // Open table file + if (!fin->OpenChk()) { + string msg = "Cannot open wavelength table [" + tableFile.Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + //For each line in the wavelength table, add the width to + //The band bin group + iString st; + int band = 1; + while(fin->GetLine(st)) { + st.Token(","); + st.Token(","); + origBand += band; + widths += st.Token(",").ConvertWhiteSpace().Trim(" ").ToDouble(); + band++; + } + delete fin; + + bandBin.AddKeyword(origBand); + bandBin.AddKeyword(widths); + ocube->PutGroup(bandBin); + } + //Otherwise throw an error + else { + string msg = "Cannot fine wavelength table [" + tableFile.Expanded() + "]"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + } + } + //If the product type is DE (Derived products for I/F) or DL + //(Derived products for Lambert albedo) write the band names + //to the band bin group + else if(prodId.Equal("MRRDE") || prodId.Equal("MRRDL")) { + PvlGroup bandBin = PvlGroup("BandBin"); + PvlKeyword origBand = PvlKeyword("OriginalBand"); + PvlKeyword bandName = PvlKeyword("BandName"); + PvlKeyword bandNames = labelPvl.FindObject("IMAGE").FindKeyword("BAND_NAME"); + for (int i = 0; i < bandNames.Size(); i++) { + origBand += (i+1); + bandName += bandNames[i]; + } + bandBin.AddKeyword(origBand); + bandBin.AddKeyword(bandName); + ocube->PutGroup(bandBin); + } + //Translate the Mapping group + p.TranslatePdsProjection(outLabel); + ocube->PutGroup(outLabel.FindGroup("Mapping", Pvl::Traverse)); + } + else if(prodType.Equal("TARGETED_RDR")) { + } + else if(prodType.Equal("DDR")) { + PvlGroup bandBin = PvlGroup("BandBin"); + PvlKeyword origBand = PvlKeyword("OriginalBand"); + PvlKeyword bandName = PvlKeyword("BandName"); + PvlKeyword bandNames = labelPvl.FindObject("FILE").FindObject("IMAGE").FindKeyword("BAND_NAME"); + for (int i = 0; i < bandNames.Size(); i++) { + origBand += (i+1); + bandName += bandNames[i]; + } + bandBin.AddKeyword(origBand); + bandBin.AddKeyword(bandName); + ocube->PutGroup(bandBin); + } + else { + string msg = "Unsupported CRISM file type, supported types are: DDR, MRDR, and TRDR"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + + // Translate the Instrument group + Filename transFile ("$mro/translations/crismInstrument.trn"); + PvlTranslationManager instrumentXlater (labelPvl, transFile.Expanded()); + instrumentXlater.Auto (outLabel); + + // Translate the Archive group + transFile = "$mro/translations/crismArchive.trn"; + PvlTranslationManager archiveXlater (labelPvl, transFile.Expanded()); + archiveXlater.Auto (outLabel); + + ocube->PutGroup(outLabel.FindGroup("Instrument", Pvl::Traverse)); + ocube->PutGroup(outLabel.FindGroup("Archive", Pvl::Traverse)); + + p.StartProcess(); + p.EndProcess(); + + return; +} diff --git a/isis/src/mro/apps/crism2isis/crism2isis.xml b/isis/src/mro/apps/crism2isis/crism2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..9fdf34d88acb21f8a337cbcea4cab7cf43586116 --- /dev/null +++ b/isis/src/mro/apps/crism2isis/crism2isis.xml @@ -0,0 +1,72 @@ + + + + + Import MRO CRISM PDS image cube into Isis format cube + + + This program will import an MRO CRISM PDS image into an Isis cube. The + following CRISM formats are supported: +
      +
    • + DDR +
    • +
    • + TRDR +
    • +
    • + MRDR +
    • +
    +
    + + + + Original version + + + Moved from base directory to mro directory. + + + + + Mars Reconnaissance Orbiter + + + + + + filename + input + + Input MRO CRISM PDS file + + + Use this parameter to select the PDS filename. This file + must contain the PDS labels, however the image data can + be detached and will be automatically obtained from the + PDS image pointer keyword. If the pointer is incorrect then + use the IMAGE parameter to specify the file containing the + binary image data. + + + *.lbl + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + +
    diff --git a/isis/src/mro/apps/crism2isis/tsts/Makefile b/isis/src/mro/apps/crism2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/crism2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/crism2isis/tsts/ddr/Makefile b/isis/src/mro/apps/crism2isis/tsts/ddr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cbfe084e8b65500f762c36b7343a9342b5a3e055 --- /dev/null +++ b/isis/src/mro/apps/crism2isis/tsts/ddr/Makefile @@ -0,0 +1,7 @@ +APPNAME = crism2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/frt00003e25_01_de156l_ddr1.lbl \ + to=$(OUTPUT)/ddrtruth.cub > /dev/null; diff --git a/isis/src/mro/apps/crism2isis/tsts/mrdr/Makefile b/isis/src/mro/apps/crism2isis/tsts/mrdr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fbcf796cf24dd4b6038d2093806599b4d8f9643f --- /dev/null +++ b/isis/src/mro/apps/crism2isis/tsts/mrdr/Makefile @@ -0,0 +1,7 @@ +APPNAME = crism2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/t1865_mrrde_70n185_0256_1.lbl \ + to=$(OUTPUT)/mrdrtruth.cub > /dev/null; diff --git a/isis/src/mro/apps/crism2isis/tsts/trdr/Makefile b/isis/src/mro/apps/crism2isis/tsts/trdr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..126709dbef67b80bb96fdc755c03b3d05517bd76 --- /dev/null +++ b/isis/src/mro/apps/crism2isis/tsts/trdr/Makefile @@ -0,0 +1,7 @@ +APPNAME = crism2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/frt00003b73_01_if156s_trr2.lbl \ + to=$(OUTPUT)/trdrtruth.cub > /dev/null; diff --git a/isis/src/mro/apps/ctxcal/Makefile b/isis/src/mro/apps/ctxcal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/ctxcal/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/ctxcal/ctxcal.cpp b/isis/src/mro/apps/ctxcal/ctxcal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30a48c04d59604bf263b6be209ec05c12ea1508f --- /dev/null +++ b/isis/src/mro/apps/ctxcal/ctxcal.cpp @@ -0,0 +1,238 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iTime.h" +#include "iException.h" +#include "TextFile.h" +#include "LineManager.h" +#include "Brick.h" +#include "Table.h" + +using namespace std; +using namespace Isis; + +// Working functions and parameters +void Calibrate (Buffer &in, Buffer &out); + +Brick *flat; +vector dcA; +vector dcB; +vector dc; + +double exposure; // Exposure duration +int sum; // Summing mode +int firstSamp; // First sample +double iof; // conversion from counts/ms to IOF + + + +// Main moccal routine +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and make sure it is a ctx file + UserInterface &ui = Application::GetUserInterface(); + + Isis::Pvl lab(ui.GetFilename("FROM")); + Isis::PvlGroup &inst = + lab.FindGroup("Instrument",Pvl::Traverse); + + std::string instId = inst["InstrumentId"]; + if (instId != "CTX") { + string msg = "This is not a CTX image. Ctxcal requires a CTX image."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + Cube *icube = p.SetInputCube("FROM",OneBand); + + Cube flatFile; + if (ui.WasEntered ("FLATFILE")) { + flatFile.Open(ui.GetFilename("FLATFILE")); + } + else { + Filename flat("$mro/calibration/ctxFlat_????.cub"); + flat.HighestVersion(); + flatFile.Open(flat.Expanded()); + } + flat = new Brick(5000,1,1,flatFile.PixelType()); + flat->SetBasePosition(1,1,1); + flatFile.Read(*flat); + + // If it is already calibrated then complain + if (icube->HasGroup("Radiometry")) { + string msg = "The CTX image [" + icube->Filename() + "] has already been "; + msg += "radiometrically calibrated"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Get label parameters we will need for calibration equation + iTime startTime((string) inst["StartTime"]); + double etStart = startTime.Et(); + + // Read exposure and convert to milliseconds + exposure = inst["LineExposureDuration"]; + //exposure *= 1000.; + + sum = inst["SpatialSumming"]; + // If firstSamp > 0, adjust by 38 to account for prefix pixels. + firstSamp = inst["SampleFirstPixel"]; + if (firstSamp > 0) firstSamp -= 38; + + // Read dark current info, if no dc exit? + Table dcTable("Ctx Prefix Dark Pixels"); + icube->Read(dcTable); + // TODO:: make sure dc records match cube nlines. + + // If summing mode = 1 , average odd & even dc pixels separately for + // a & b channels. + // If summing mode != 1, average all dc pixels and use for both + + + for (int rec=0; rec darks = dcTable[rec]["DarkPixels"]; + + bool aChannel = true; + double dcASum = 0.; + double dcBSum = 0.; + int dcACount = 0; + int dcBCount = 0; + + double dcSum = 0; + int dcCount = 0; + + for (int i=0; i<(int)darks.size(); i++) { + + if (sum == 1) { + if (aChannel == true) { + dcASum += (double)darks.at(i); + dcACount++; + } + else { + dcBSum += (double)darks.at(i); + dcBCount++; + } + aChannel = !aChannel; + } + else if (sum > 1) { + dcSum += (double)darks.at(i); + dcCount ++; + } + } + if (sum == 1) { + dcA.push_back(dcASum / (double)dcACount); + dcB.push_back(dcBSum / (double)dcBCount); + } + else { + dc.push_back(dcSum / (double)dcCount); + } + } + + // See if the user wants counts/ms or i/f + // iof = conversion factor from counts/ms to i/f + bool convertIOF = ui.GetBoolean("IOF"); + if (convertIOF) { + // Get the distance between Mars and the Sun at the given time in + // Astronomical Units (AU) + string bspKernel = p.MissionData("base","/kernels/spk/de???.bsp",true); + furnsh_c(bspKernel.c_str()); + string pckKernel = p.MissionData("base","/kernels/pck/pck?????.tpc",true); + furnsh_c(pckKernel.c_str()); + double sunpos[6],lt; + spkezr_c ("sun",etStart,"iau_mars","LT+S","mars",sunpos,<); + double dist1 = vnorm_c(sunpos); + unload_c (bspKernel.c_str()); + unload_c (pckKernel.c_str()); + + double dist = 2.07E8; + double w0 = 3660.5; + double w1 = w0 * ( (dist*dist) / (dist1*dist1) ); + if (exposure*w1 == 0.0) { + string msg = icube->Filename() + ": exposure or w1 has value of 0.0 "; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + iof = 1.0 / (exposure * w1); + } + else { + iof = 1.0; + } + + // Setup the output cube + Cube *ocube = p.SetOutputCube ("TO"); + + // Add the radiometry group + PvlGroup calgrp("Radiometry"); + + calgrp += PvlKeyword("FlatFile",flatFile.Filename()); + calgrp += PvlKeyword("iof",iof); + + + ocube->PutGroup(calgrp); + + // Start the line-by-line calibration sequence + p.StartProcess(Calibrate); + p.EndProcess(); + +} + +// Line processing routine +void Calibrate (Buffer &in, Buffer &out) { + + + + // TODO:: Check for valid dc & flat + + double dark = 0.; + if (sum != 1) { + dark = dc.at(in.Line()-1); + } + + bool aChannel = true; + // Loop and apply calibration + for (int i=0; i + + + + + Radiometrically calibrates a CTX image + + + +

    + ctxcal performs radiometric corrections to images acquired by the Context + Imager aboard the Mars Reconnaissance Orbiter spacecraft. The CTX camera + will make observations simulteously with the HiRise camera. +

    + +

    + The MRO CTX detector has a total of 5000 pixels, divided among an A + channel and a B channel. The pixels alternate between the two channels: + ABABABAB, etc. Images from CTX may or may not include all pixels in the + acquired image. There are special summing modes that are utilized + on-board the spacecraft to average detector pixels to combine them into a + single output pixel value. The value of the ISIS label keyord, + SpatialSumming, indicates the number of samples that were summed and + averaged to result in the pixel values stored in the file. Note that this + will reduce the number of samples in the output image by a factor of at + most the SpatialSumming mode value. +

    +

    + The CTX camera has the ability to acquire images of differing sizes in + both line and sample. The starting hardware detector pixel for the + acquired image is specified by the ISIS label keyword, SampleFirstPixel. + The first pixel in the detector is indicated by a value of 0. +

    + +

    + Dark current pixels are taken for each line and are stored in the Isis + cube as a table, named "Ctx Prefix Dark Pixels". The number of dark + current pixels in this table is dependent on the SpatialSumming and the + SampleFirstPixel keywords from the labels. The following table shows the + association between these keywords and dark current pixels. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Association between keywords the number of dark current pixels +
    SpatialSummingSampleFirstPixelNumber of Dark current pixels in the table
    1024 (12 for each channel, stored as ABABABABABABABABABABABAB)
    1>016 (8 for each channel, stored as ABABABABABABABAB)
    2012 (The dc pixels for the A and B channel have been summed together)
    2>08 (The dc pixels for the A and B channel have been summed together)
    + +

    + If SpatialSumming is 1 the dark current pixels are averaged together then + this average is subtracted from all image pixels. If SpatialSumming is 2, + the dark current pixels for the A and B channel are averaged separately, + then the A channel dark average is subtracted from the A channel image + pixels and the B channel dark average is subtracted from the B channel + image pixels. +

    + +

    + The equation ctxcal implements is as follows: + +

    +    r = ( dn - dc / (gain(i,j) * exp)
    +    
    + + where r is the average signal being generated at the focal plane (in + DN/msec), dc is the dark current term (in DN/msec), gain(i,j) is the pixel + dependent gain, and ex is the exposure time in milliseconds. +

    + +

    + If the IOF parameter is chosen, the output pixels are converted to + relative reflectance (I/F) using the solar radiance, with an albedo 1 + target at normal incidence at Mars perihelion distance (2.07e+08 km) and + a CTX response of 3660.5 DN/msec. +

    + +
    + + + + Original version + + + Moved the flat file into the mro calibration data area and changed the code to point to that area. + + + Make sure input cube is a ctx image. + + + + Added an application test + + + Removed references to CubeInfo + + + Removed hard coded flatfile, now searchs for highest version + + + + + Mars Reconnaissance Orbiter + + + + + ctxevenodd + + + + + + + cube + input + + Level 0 CTX image + + + An uncalibrated CTX image. + + + *.cub + + + + + cube + output + real + + Level 1 CTX image + + + The resultant radiometrically calibrated cube + + + + + cube + input + real + + Flat Field file (pixel dependent gain) + + Internal Default + + Flat Field file (pixel dependent gain). If no file is entered, the + default will be used. + + + + + + + boolean + True + + Convert to I/F + + + The user has the option to request the output of ctxcal to be in + either units of percent reflectance (IOF="YES") or in average signal + level at the focal plane (IOF="NO") in DN/msec. Ctxcal has a + default I/F (percent reflectance) factor of 3660.5 DN/msecond response + with an albedo 1 target a normal incidence at Mars perihelion distance + (2.07 e+08). Conversion to I/F takes place after calibration and + pixel-to-pixel variation corrections. + + + + + +
    diff --git a/isis/src/mro/apps/ctxcal/tsts/Makefile b/isis/src/mro/apps/ctxcal/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/ctxcal/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/ctxcal/tsts/calibration/Makefile b/isis/src/mro/apps/ctxcal/tsts/calibration/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7af8a1473610000ed6b718c4bc5f7a7f2f739679 --- /dev/null +++ b/isis/src/mro/apps/ctxcal/tsts/calibration/Makefile @@ -0,0 +1,9 @@ +APPNAME = ctxcal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/P01_001473_2479_XI_67N185W.cub \ + TO=$(OUTPUT)/P01_001473_2479_XI_67N185W.cal.cub \ + flatfile=/usgs/cpkgs/isis3/data/mro/calibration/ctxFlat_0001.cub \ + IOF=false > /dev/null; diff --git a/isis/src/mro/apps/ctxcal/tsts/default/Makefile b/isis/src/mro/apps/ctxcal/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f22d2ca04a6acddbe6949916e6302cbbb88d36c6 --- /dev/null +++ b/isis/src/mro/apps/ctxcal/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = ctxcal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/P01_001473_2479_XI_67N185W.cub \ + TO=$(OUTPUT)/P01_001473_2479_XI_67N185W.cal.cub \ + flatfile=/usgs/cpkgs/isis3/data/mro/calibration/ctxFlat_0001.cub \ + > /dev/null; diff --git a/isis/src/mro/apps/ctxevenodd/Makefile b/isis/src/mro/apps/ctxevenodd/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/ctxevenodd/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/ctxevenodd/ctxevenodd.cpp b/isis/src/mro/apps/ctxevenodd/ctxevenodd.cpp new file mode 100644 index 0000000000000000000000000000000000000000..72aed4dddf0e94a890eebe1ba277805a57ab079c --- /dev/null +++ b/isis/src/mro/apps/ctxevenodd/ctxevenodd.cpp @@ -0,0 +1,135 @@ +// +// ctxevenodd.cpp +// +// Remove even/odd striping from a CTX cube +// +// outputCube = inputCube + {a correction offset to valid pixels} +// +// calc average dn of all valid pixels located in either even or odd columns. +// correction offset is 1/2 the difference between the even and odd average. +// subtract the offset from pixels in even columns +// add the offset to pixels in odd columns +// + +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +void getStats (Buffer &in); +int evenCount, oddCount; +double evenSum, oddSum; + +void applyCorrectionOffset (Buffer &in,Buffer &out); +double correctionOffset; + + +void IsisMain() { + ProcessByLine p; + p.SetInputCube("FROM"); + + // Make sure we have a ctx cube and it has SpatialSumming of 1 + UserInterface &ui = Application::GetUserInterface(); + Isis::Pvl lab(ui.GetFilename("FROM")); + Isis::PvlGroup &inst = + lab.FindGroup("Instrument",Pvl::Traverse); + + std::string instId = inst["InstrumentId"]; + if (instId != "CTX") { + string msg = "This is not a CTX image. Ctxcevenodd requires a CTX image."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + int sum = inst["SpatialSumming"]; + if (sum != 1) { + string msg = "CTX images do not have even/odd noise problems"; + msg += " if the SpatialSumming is greater than one."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Get even and odd column statistics + evenCount = 0; + evenSum = 0.0; + oddCount = 0; + oddSum = 0.0; + Progress *progress = p.Progress(); + progress->SetText("Retrieving CTX Image Stats"); + p.StartProcess(getStats); + p.EndProcess(); + + // compute the correction offset + // + // 1/2 the difference between the even column average + // and the odd column average of valid pixel dn values. + // + // throw err if, pixel counts could result in division by zero + if ((oddCount == 0) || (evenCount == 0)) { + string msg = "Couldn't compute column averages"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // from mocevenodd + correctionOffset = ((evenSum / evenCount) - (oddSum / oddCount)) / 2.0; + + + // output cube - apply offset + progress->SetText("Writing De-striped CTX Image"); + p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + p.StartProcess(applyCorrectionOffset); + p.EndProcess(); +} + + +void getStats (Buffer &in) { + + // ProcessByLine + // + // Count and sum all valid pixel values + // in even and odd image columns. + + bool odd = true; + + for (int i=0; i + + + + Remove even/odd detector striping from MRO Ctx images + + + + This program will remove even/odd detector striping from a Mars + Reconnaissance Oribiter Context Imager cube. The algorithm + gathers the average of the even columns as well as the odd columns. The + difference between the averages is split (divided by two) to create + offsets for both columns which are then applied. + + Note: Ctxcal should be run prior to this program. + + + + + ctxcal + + + + + Mars Reconnaissance Orbiter + + + + + Original version + + + Make sure image is a CTX cube and the SpatialSumming + is equal to 1. + + + Added an application test + + + + + + + cube + input + + Input CTX image + + + The input image CTX image. + + + *.cub + + + + + cube + output + + Destriped CTX cube + + + The resultant destriped CTX image. + + + *.cub + + + + + diff --git a/isis/src/mro/apps/ctxevenodd/tsts/Makefile b/isis/src/mro/apps/ctxevenodd/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/ctxevenodd/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/ctxevenodd/tsts/default/Makefile b/isis/src/mro/apps/ctxevenodd/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8ebaebdfe5a52be50200873d60b70405ee7f7fbd --- /dev/null +++ b/isis/src/mro/apps/ctxevenodd/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = ctxevenodd + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM= $(INPUT)/P01_001473_2479_XI_67N185W.cal.cub \ + TO= $(OUTPUT)/P01_001473_2479_XI_67N185W.evenodd.cub > /dev/null; diff --git a/isis/src/mro/apps/hi2isis/Makefile b/isis/src/mro/apps/hi2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hi2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hi2isis/assets/hi2isis_diagram.png b/isis/src/mro/apps/hi2isis/assets/hi2isis_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..7c41530de4e00175a751189afc47e7a2f3346d0a Binary files /dev/null and b/isis/src/mro/apps/hi2isis/assets/hi2isis_diagram.png differ diff --git a/isis/src/mro/apps/hi2isis/assets/hi2isis_diagram.vsd b/isis/src/mro/apps/hi2isis/assets/hi2isis_diagram.vsd new file mode 100644 index 0000000000000000000000000000000000000000..7a1752db7bfd18777a48d2dfe4c5edf910e5e619 Binary files /dev/null and b/isis/src/mro/apps/hi2isis/assets/hi2isis_diagram.vsd differ diff --git a/isis/src/mro/apps/hi2isis/hi2isis.cpp b/isis/src/mro/apps/hi2isis/hi2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee8e63306e6447acb2c1ff5878ff4540b3960fc8 --- /dev/null +++ b/isis/src/mro/apps/hi2isis/hi2isis.cpp @@ -0,0 +1,362 @@ +#include "Isis.h" + +#include +#include + +#include "ProcessImportPds.h" +#include "ProcessByLine.h" + +#include "UserInterface.h" +#include "Filename.h" +#include "iException.h" +#include "iTime.h" +#include "Preference.h" +#include "Buffer.h" +#include "PvlGroup.h" +#include "PvlKeyword.h" +#include "PvlSequence.h" +#include "Stretch.h" + +using namespace std; +using namespace Isis; + +// Global variables for processing functions +Stretch stretch; + +// The input raw EDR contains 6 sections. The following counts keep track +// of the types of pixels found in each section. The order of sections +// is the order they arae encountered within the raw EDR. (i.e., calibration +// buffer, calibration image, calibration dark/reference, image buffer, +// image, image dark/reference) +int gapCount[6]; +int suspectGapCount[6]; +int invalidCount[6]; +int lisCount[6]; +int hisCount[6]; +int validCount[6]; +int section; + +bool lsbGap; + + +void IsisMain () +{ + stretch.ClearPairs(); + + for (int i=0; i<6; i++) { + gapCount[i] = 0; + suspectGapCount[i] = 0; + invalidCount[i] = 0; + lisCount[i] = 0; + hisCount[i] = 0; + validCount[i] = 0; + } + + void TranslateHiriseEdrLabels (Filename &labelFile, Cube *); + void SaveHiriseCalibrationData (ProcessImportPds &process, Cube *, + Pvl &pdsLabel); + void SaveHiriseAncillaryData (ProcessImportPds &process, Cube *); + void FixDns8 (Buffer &buf); + void FixDns16 (Buffer &buf); + + ProcessImportPds p; + Pvl pdsLabel; + UserInterface &ui = Application::GetUserInterface(); + + // Get the input filename and make sure it is a HiRISE EDR + Filename inFile = ui.GetFilename("FROM"); + iString id; + bool projected; + try { + Pvl lab(inFile.Expanded()); + id = (string) lab.FindKeyword ("DATA_SET_ID"); + projected = lab.HasObject("IMAGE_MAP_PROJECTION"); + } + catch (iException &e) { + string msg = "Unable to read [DATA_SET_ID] from input file [" + + inFile.Expanded() + "]"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + //Checks if in file is rdr + if( projected ) { + string msg = "[" + inFile.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + id.ConvertWhiteSpace(); + id.Compress(); + id.Trim(" "); + if (id != "MRO-M-HIRISE-2-EDR-V1.0") { + string msg = "Input file [" + inFile.Expanded() + "] does not appear to be " + + "in HiRISE EDR format. DATA_SET_ID is [" + id + "]"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + p.SetPdsFile (inFile.Expanded(), "", pdsLabel); + + // Make sure the data we need for the BLOBs is saved by the Process + p.SaveFileHeader(); + p.SaveDataPrefix(); + p.SaveDataSuffix(); + + // Let the Process create the output file but override any commandline + // output bit type and min/max. It has to be 16bit for the rest of hi2isis + // to run. + // Setting the min/max to the 16 bit min/max keeps all the dns (including + // the 8 bit special pixels from changing their value when they are mapped + // to the 16 bit output. + CubeAttributeOutput &outAtt = ui.GetOutputAttribute("TO"); + outAtt.PixelType (Isis::SignedWord); + outAtt.Minimum((double)VALID_MIN2); + outAtt.Maximum((double)VALID_MAX2); + Cube *ocube = p.SetOutputCube(ui.GetFilename("TO"), outAtt); + p.StartProcess (); + TranslateHiriseEdrLabels (inFile, ocube); + + // Pull out the lookup table so we can apply it in the second pass + // and remove it from the labels. + // Add the UNLUTTED keyword to the instrument group so we know + // if the lut has been used to convert back to 14 bit data + PvlGroup &instgrp = ocube->GetGroup("Instrument"); + PvlKeyword lutKey = instgrp["LookupTable"]; + PvlSequence lutSeq; + lutSeq = lutKey; + + // Set up the Stretch object with the info from the lookup table + // If the first entry is (0,0) then no lut was applied. + if ((lutKey.IsNull()) || + (lutSeq.Size()==1 && lutSeq[0][0]=="0" && lutSeq[0][1]=="0")) { + stretch.AddPair(0.0, 0.0); + stretch.AddPair(65536.0, 65536.0); + instgrp.AddKeyword(PvlKeyword("Unlutted","TRUE")); + instgrp.DeleteKeyword ("LookupTable"); + } + // The user wants it unlutted + else if (ui.GetBoolean("UNLUT")) { + for (int i=0; iPutGroup(instgrp); + + // Save the calibration and ancillary data as BLOBs. Both get run thru the + // lookup table just like the image data. + SaveHiriseCalibrationData (p, ocube, pdsLabel); + SaveHiriseAncillaryData (p, ocube); + + // Save off the input bit type so we know how to process it on the + // second pass below. + Isis::PixelType inType = p.PixelType(); + + // All finished with the ImportPds object + p.EndProcess (); + + + // Make another pass thru the data using the output file in read/write mode + // This allows us to correct gaps, remap special pixels and accumulate some + // counts + lsbGap = ui.GetBoolean("LSBGAP"); + ProcessByLine p2; + string ioFile = ui.GetFilename("TO"); + CubeAttributeInput att; + p2.SetInputCube(ioFile, att, ReadWrite); + p2.Progress()->SetText("Converting special pixels"); + section = 4; + p2.StartProcess((inType == Isis::UnsignedByte) ? FixDns8 : FixDns16); + p2.EndProcess(); + + + // Log the results of the image conversion + PvlGroup results("Results"); + results += PvlKeyword ("From", inFile.Expanded()); + + results += PvlKeyword ("CalibrationBufferGaps", gapCount[0]); + results += PvlKeyword ("CalibrationBufferLIS", lisCount[0]); + results += PvlKeyword ("CalibrationBufferHIS", hisCount[0]); + results += PvlKeyword ("CalibrationBufferPossibleGaps", suspectGapCount[0]); + results += PvlKeyword ("CalibrationBufferInvalid", invalidCount[0]); + results += PvlKeyword ("CalibrationBufferValid", validCount[0]); + + results += PvlKeyword ("CalibrationImageGaps", gapCount[1]); + results += PvlKeyword ("CalibrationImageLIS", lisCount[1]); + results += PvlKeyword ("CalibrationImageHIS", hisCount[1]); + results += PvlKeyword ("CalibrationImagePossibleGaps", suspectGapCount[1]); + results += PvlKeyword ("CalibrationImageInvalid", invalidCount[1]); + results += PvlKeyword ("CalibrationImageValid", validCount[1]); + + results += PvlKeyword ("CalibrationDarkGaps", gapCount[2]); + results += PvlKeyword ("CalibrationDarkLIS", lisCount[2]); + results += PvlKeyword ("CalibrationDarkHIS", hisCount[2]); + results += PvlKeyword ("CalibrationDarkPossibleGaps", suspectGapCount[2]); + results += PvlKeyword ("CalibrationDarkInvalid", invalidCount[2]); + results += PvlKeyword ("CalibrationDarkValid", validCount[2]); + + results += PvlKeyword ("ObservationBufferGaps", gapCount[3]); + results += PvlKeyword ("ObservationBufferLIS", lisCount[3]); + results += PvlKeyword ("ObservationBufferHIS", hisCount[3]); + results += PvlKeyword ("ObservationBufferPossibleGaps", suspectGapCount[3]); + results += PvlKeyword ("ObservationBufferInvalid", invalidCount[3]); + results += PvlKeyword ("ObservationBufferValid", validCount[3]); + + results += PvlKeyword ("ObservationImageGaps", gapCount[4]); + results += PvlKeyword ("ObservationImageLIS", lisCount[4]); + results += PvlKeyword ("ObservationImageHIS", hisCount[4]); + results += PvlKeyword ("ObservationImagePossibleGaps", suspectGapCount[4]); + results += PvlKeyword ("ObservationImageInvalid", invalidCount[4]); + results += PvlKeyword ("ObservationImageValid", validCount[4]); + + results += PvlKeyword ("ObservationDarkGaps", gapCount[5]); + results += PvlKeyword ("ObservationDarkLIS", lisCount[5]); + results += PvlKeyword ("ObservationDarkHIS", hisCount[5]); + results += PvlKeyword ("ObservationDarkPossibleGaps", suspectGapCount[5]); + results += PvlKeyword ("ObservationDarkInvalid", invalidCount[5]); + results += PvlKeyword ("ObservationDarkValid", validCount[5]); + + // Write the results to the log + Application::Log(results); + + return; +} + + +void TranslateHiriseEdrLabels (Filename &labelFile, Cube *ocube) { + + //Create a PVL to store the translated labels + Pvl outLabel; + + // Get the directory where the MRO HiRISE translation tables are. + PvlGroup dataDir (Preference::Preferences().FindGroup("DataDirectory")); + iString transDir = (string) dataDir["Mro"] + "/translations/"; + + // Get a filename for the HiRISE EDR label + Pvl labelPvl (labelFile.Expanded()); + + // Translate the Instrument group + Filename transFile (transDir + "hiriseInstrument.trn"); + PvlTranslationManager instrumentXlater (labelPvl, transFile.Expanded()); + instrumentXlater.Auto (outLabel); + + // Translate the BandBin group + transFile = transDir + "hiriseBandBin.trn"; + PvlTranslationManager bandBinXlater (labelPvl, transFile.Expanded()); + bandBinXlater.Auto (outLabel); + + // Translate the Archive group + transFile = transDir + "hiriseArchive.trn"; + PvlTranslationManager archiveXlater (labelPvl, transFile.Expanded()); + archiveXlater.Auto (outLabel); + + // Create the Instrument group keyword CcdId from the ProductId + // SCS 28-03-06 Do it in the instrument translation table instead of here +// PvlGroup &archiveGroup(outLabel.FindGroup("Archive", Pvl::Traverse)); +// iString productId = (string)archiveGroup.FindKeyword("ProductId"); +// productId.Token("_"); +// productId.Token("_"); +// productId = productId.Token("_"); +// outLabel.FindGroup("Instrument", Pvl::Traverse) += +// PvlKeyword ("CcdId", productId); + + // Create the Kernel Group + PvlGroup kerns("Kernels"); + kerns += PvlKeyword("NaifIkCode", "-74699"); + + // Write the Instrument, BandBin, Archive, and Kernels groups to the output + // cube label + ocube->PutGroup (outLabel.FindGroup("Instrument", Pvl::Traverse)); + ocube->PutGroup (outLabel.FindGroup("BandBin", Pvl::Traverse)); + ocube->PutGroup (outLabel.FindGroup("Archive", Pvl::Traverse)); + ocube->PutGroup (kerns); +} + + +// The input buffer has a raw 16 bit buffer but the values are still 0 to 255 +void FixDns8 (Buffer &buf) { + + // Convert all 8bit image values of =255 (xFF) to 16bit NULL, count as gap + // Convert all 8bit image values of =254 (xFE) to 16bit HIS, count as HIS + // Convert all 8bit image values of =0 (x00) to 16bit LIS, count as NULL + // Convert 8bit image data to 16bit by applying the LUT + + short int *raw = (short int*)(buf.RawBuffer()); + + for (int i=0; i16383 (x3FFF) to NULL, count as gap + // Convert 16-bit image values of =16383 (x3FFF) to HIS, count as HIS + // Convert 16-bit image values of =0 (x00) to LIS, count as LIS + + short int *raw = (short int*)(buf.RawBuffer()); + + for (int i=0; i 16383) || (raw[i] < 0)) { + buf[i] = Isis::NULL8; + invalidCount[section]++; + } + // This pixel is saturated on the bright end + else if (raw[i] == 16383) { // Max value for instrument + buf[i] = Isis::HIGH_INSTR_SAT8; + hisCount[section]++; + } + // This pixel is saturated on the dark end + // Shouldn't happen because dark currents are above zero (0) + else if (raw[i] == 0) { + buf[i] = Isis::LOW_INSTR_SAT8; + lisCount[section]++; + } + // Pixel value is ok, so just leave it alone + else { + validCount[section]++; + } + } +} + diff --git a/isis/src/mro/apps/hi2isis/hi2isis.xml b/isis/src/mro/apps/hi2isis/hi2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..81c8aaf5aa7a4bc0804f9bd332f4d185b9e147d9 --- /dev/null +++ b/isis/src/mro/apps/hi2isis/hi2isis.xml @@ -0,0 +1,284 @@ + + + + + + Import HiRISE EDR images into Isis cube format + + + +

    + Converts a single channel HiRISE EDR into an Isis Cube file. + The observation image data from the EDR is transfered into the Isis Cube data. + The observation line prefix and suffix data will be combined into a single Isis table + named "HiRISE Ancillary". The calibration image data will be placed into an Isis + table named "HiRISE Calibration Image", and the calibration line prefix and suffix + data will be combined into a single Isis table named "HiRISE Calibration Ancillary". +

    +

    + 8 bit EDR pixels are checked for invalid values in the following order: + gaps (255 = 0xFF), high instrument saturation (254 = 0xFE), and low + instrument saturation (0 = 0x00). See the following table for what these + values are converted to. Once the special pixels have been delt with the + 8 bit data is processed in one of two ways depending on the UNLUT + parameter. If UNLUT is false then the 8 bit values are simply moved into + a signed 16 bit integer without modifying their magnitude. If UNLUT is + true, the 8 bit values are converted to their 14 bit value by applying + the lookup table and stored in a signed 16 bit integer. The lookup table + from the EDR labels contaings 256 pairs of 14 bit values. The first pair + is the range of 14 bit pixels that were compressed to 8 bit pixel value + zero (0). The second pair is the range compressed to pixel value one (1), + and so on. 8 bit pixels are mapped to the corresponding average of the + 14 bit lookup table range. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    8 bit EDR pixel mapping and stats
    Input DNOutput DNCounterExplanation
    255 (0xFF)NULLGapDownlink data gaps are filled with 255s
    254 (0xFE)HISHISSensor saturated on the high end
    0 (0x00)LISLISSensor saturated on the low end
    + +

    + 16 bit EDR pixels are checked for invalid values in the following order: + gaps (-1 = 0xFFFF), low order byte appears to be the beginning of a gap + (0x??FF), outside of unsigned 14 bit range (0 to 16383), high instrument saturation + (16383 = 0x3FFF), and low instrument saturation (0 = 0x0000). + Since the byte order of all HiRISE + EDR products is most significant byte first all integer values within the EDR + will be converted to the native byte order of the machine running "hi2isis" + unless the cube attribute specifies otherwise. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    16 bit EDR pixel mapping and stats
    Input DNOutput DNCounterExplanation
    -1 (65535) (0xFFFF)NULLGapDownlink data gaps are filled with 255s (0xFF)
    (0x??FF) followed by (0xFFFF)NULL (possibly)SuspectedBeginning of a gap (see LSBGAP parameter)
    0 < pixel > 16383NULLInvalidThe pixel is not in the unsigned 14 bit legal range
    16383 (0x3FFF)HISHISSensor saturated on the high end
    0 (0x00)LISLISSensor saturated on the low end
    + +

    + The line prefix and suffix data for the calibration and observation image are converted + and stored into their respective tables in the same manner as the image pixels. + The Isis tables which hold + prefix and suffix data have four, four byte integer fields. These are "Gap Flag", + "LineNumber", "BufferPixels", and "DarkPixels". The BufferPixel field contains twelve + integers and the DarkPixel field contains sixteen integers. Other information from the + EDR prefix tables such as the synchronization pattern are not transfered to the Isis file. +

    +

    + The "GapFlag" is taken directly from byte zero of the EDR line prefix data and is stored + in the least significant byte of the four byte field integer. The upper three bytes are set to all + zeros. The byte from the EDR has two possible values, all zeros and all ones. This means + the Isis GapFlag value as an integer has two possible values, 255 and zero (0). +

    + The "LineNumber" is taken from bytes three, four and five of the EDR line prefix data and + is stored into a single four byte integer with the most significant byte set to zero. +

    +

    + The twelve values for "BufferPixels" are taken from the EDR line prefix buffer pixels. + 8-bit buffer pixels are converted to 16 bit values in exactly the same way as image pixels. + All buffer pixels are stored in the + corresponding Isis "BufferPixels" array. All pixel values will be + stored in the low order two bytes and will be swapped if the native byte order is least + significant byte first. +

    + The sixteen values for "DarkPixels" are taken from the EDR line suffix dark pixels, and are + handled in the same manner as the buffer pixels. +

    + Diagram of output Isis cube + +
    + + + + Original version + + + Updated according to new SIS. Added Calibration, Ancillary calibration + and Ancillary Image BLOBs. + + + Added documentation specific to the Isis tables that are created. + + + Fixed a bug with the allocation of the TableField "image". It now works for + HiRISE EDRs that have a binning mode other than one (1). + + + Added gap and lookup table handling. Both 8 and 16 bit inputs are now + converted to 16 bit output. The lookup table for 8 bit is applied. The output + DN for an 8 bit input is the average of the lookup table range values. Added + new option (LSBGAP) to handle 16 bit pixels with a low order byte of 0xff immediately + before a gap. By default, this new option will convert these pixels to a gap. With + the option turned off, these pixels will be left unaltered. + + + Added the parameter UNLUT to give the ability to apply the 8 to 14 bit + look up table or not. Also fixed problem with gaps, LIS and HIS being reported + correctly but not converted correctly to double precision values before + being inserted into the BUFFER. + + + Added new keywords to the results group. For each of the six sections, the + program now outputs the number gaps, LIS, HIS, PossibleGaps, and Invalid + pixels. + + + Fixed a bug with signedword data where gaps were being reported as LIS + instead of gap. Added more progress information. + + + Removed call to OriginalLabel, ProcessImportPds now handles this + + + Documentation fixes + + + Added blob testing to default appTest + + + Checks if input file is rdr. + + + Removed references to CubeInfo + + + + + Mars Reconnaissance Orbiter + + + + + + filename + input + + Input PDS formatted HiRISE EDR image file. + + + Use this parameter to select the HiRISE EDR image filename. This must + be a single channel original HiRISE EDR file. + + + *.img *.IMG + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename. The output file will + contain the observation, buffer, and dark pixels from both the main + image and the calibration areas. + + + *.cub + + + + + + + boolean + + true + + + Ignore least significant byte of 0xFF before a gap. + + + Ignore legal 16 bit pixels with a low order byte of 0xff immediately + preceding a gap. Pixels like this are normally treated as a gap + and converted to NULL. + Set this parameter to FALSE if you want these pixels treated as + if they were valid data. Set this parameter to TRUE if you want + these pixels treated as if they were gaps. + + + + + boolean + + true + + + Convert 8-bit values back to 14-bit values + + +

    + If the input data is stored in 8-bit values, and this parameters is + set to true then the lookup table will be used to convert all valid + image, buffer and dark pixels back to 14-bit values. This includes + both the main image and calibration areas. If this parameter is false + then the valid pixels will be left at their 8 bit lutted values. +

    +

    + The label keyword "Unlutted" in the "Instrument" object is used to + indicate if the valid pixels are in their 8 bit lutted (Unlutted = FALSE), + or their 14 bit unlutted (Unlutted = TRUE) representation. Note: Invalid + pixels (i.e., Gaps, NULL, HRS, HIS, LRS, and LIS) are always represented + as 16 bit special pixel values. +

    +
    +
    +
    +
    +
    diff --git a/isis/src/mro/apps/hi2isis/hiAncillary.cpp b/isis/src/mro/apps/hi2isis/hiAncillary.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3878e8868cdfebea8b527d1cc5264bd0d51c20bb --- /dev/null +++ b/isis/src/mro/apps/hi2isis/hiAncillary.cpp @@ -0,0 +1,90 @@ +#include "ProcessImportPds.h" + +#include "TableRecord.h" +#include "Table.h" + +using namespace std; +using namespace Isis; + +extern int gapCount[6]; +extern int suspectGapCount[6]; +extern int invalidCount[6]; +extern int lisCount[6]; +extern int hisCount[6]; +extern int validCount[6]; +extern int section; + +// Construct a BLOb to contain the Hirise main line suffix and prefix data +void SaveHiriseAncillaryData (ProcessImportPds &process, Cube *ocube) { + + vector ConvertCalibrationPixels (int samples, + Isis::PixelType pixelType, + unsigned char *data); + + + // Setup a Table to hold the main image prefix/suffix data + TableField gap("GapFlag", TableField::Integer); + TableField line("LineNumber", TableField::Integer); + TableField buffer("BufferPixels", TableField::Integer, 12); + TableField dark("DarkPixels", TableField::Integer, 16); + + TableRecord rec; + rec += gap; + rec += line; + rec += buffer; + rec += dark; + + Table table("HiRISE Ancillary", rec); + table.SetAssociation (Table::Lines); + + // Loop through all the prefix and suffix data and construct the table records + // In the case of HiRISE there is only one band so the outside vector + // only contains one entry. The inside vector contains nl entries. + vector > pre = process.DataPrefix(); + vector > suf = process.DataSuffix(); + vector prefix = pre.at(0); + vector suffix = suf.at(0); + + Progress progress; + progress.SetText("Saving ancillary data"); + progress.SetMaximumSteps(prefix.size()); + progress.CheckStatus(); + + for (unsigned int l=0; lWrite(table); +} diff --git a/isis/src/mro/apps/hi2isis/hiCalibration.cpp b/isis/src/mro/apps/hi2isis/hiCalibration.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba0163482d3778471612ce4dc9e245b4e9ed856c --- /dev/null +++ b/isis/src/mro/apps/hi2isis/hiCalibration.cpp @@ -0,0 +1,159 @@ +#include + +#include "ProcessImportPds.h" + +#include "Buffer.h" +#include "Table.h" + +using namespace std; +using namespace Isis; + +extern int gapCount[6]; +extern int suspectGapCount[6]; +extern int invalidCount[6]; +extern int lisCount[6]; +extern int hisCount[6]; +extern int validCount[6]; +extern int section; + + +// Construct two BLOBs one to hold the Hirise calibration line prefix/suffix data +// and the other to hold the calibration image line +void SaveHiriseCalibrationData (ProcessImportPds &process, Cube *ocube, + Pvl &pdsLabel) { + + vector ConvertCalibrationPixels (int samples, + Isis::PixelType pixelType, + unsigned char *data); + + // Create the Table to hold the prefix/suffix data + TableField gap("GapFlag", TableField::Integer); + TableField line("LineNumber", TableField::Integer); + TableField buffer("BufferPixels", TableField::Integer, 12); + TableField dark("DarkPixels", TableField::Integer, 16); + + TableRecord calAncillaryRecord; + calAncillaryRecord += gap; + calAncillaryRecord += line; + calAncillaryRecord += buffer; + calAncillaryRecord += dark; + + Table calAncillaryTable("HiRISE Calibration Ancillary", calAncillaryRecord); + + // Create the Table to hold the calibration lines + TableField image("Calibration", TableField::Integer, ocube->Samples()); + + TableRecord calImageRecord; + calImageRecord += image; + + Table calImageTable("HiRISE Calibration Image", calImageRecord); + + + // Find the beginning of the calibration data + unsigned char *header = (unsigned char *)process.FileHeader(); + header += (int)pdsLabel["^CALIBRATION_LINE_PREFIX_TABLE"] - 1; + + // Get the number of lines in the calibration area. This includes the + // calibration, mask and ramp lines + int calsize = (int)(pdsLabel.FindObject("CALIBRATION_IMAGE")["LINES"]); + + // Loop through the calibration lines and extract the info needed for the + // tables. + for (unsigned int l=0; l<(unsigned int)calsize; l++) { + + // Pull out the gap byte (in byte 0) + calAncillaryRecord[0] = (int)(*header++); + + // Skip the sync patterns and channel number (bytes 1 and 2) + header++; + header++; + + // Pull out the line number (bytes 3-5 3=MSB, 5=LSB) + int lineCounter = 0; + lineCounter += (int)(*header++) << 16; + lineCounter += (int)(*header++) << 8; + lineCounter += (int)(*header++); + calAncillaryRecord[1] = lineCounter; + + // Pull the 12 buffer pixels (same type as image data) + section = 0; + calAncillaryRecord[2] = ConvertCalibrationPixels (12, process.PixelType(), + header); + header += 12 * SizeOf(process.PixelType()); + + // Don't add this record to the table yet. It still needs the dark pixels. + + // Pull the calibration pixels out (same type as image data) + section = 1; + calImageRecord[0] = ConvertCalibrationPixels (ocube->Samples(), + process.PixelType(), header); + header += ocube->Samples() * SizeOf(process.PixelType()); + calImageTable += calImageRecord; + + + // Pull the 16 dark pixels (same type as image data) + section = 2; + calAncillaryRecord[3] = ConvertCalibrationPixels (16, process.PixelType(), + header); + header += 16 * SizeOf(process.PixelType()); + + // Add this record to the table + calAncillaryTable += calAncillaryRecord; + } + + // Add the tables to the output cube + ocube->Write(calAncillaryTable); + ocube->Write(calImageTable); +} + + + +vector ConvertCalibrationPixels (int samples, + Isis::PixelType pixelType, + unsigned char *data) { + void FixDns8(Buffer &buf); + void FixDns16(Buffer &buf); + + + // Pull the calibration pixels out (same type as image data) + // The buffer is always 16-bit because FixDn8/16 both expect a 16-bit + // buffer, but are looking for original data ranges and specific values + Isis::Buffer pixelBuf(samples, 1, 1, Isis::SignedWord); + + for (int b=0; b calibrationPixels; + double pixel; + for (int b=0; b /dev/null; + $(APPNAME) from=$(INPUT)/PSP_001446_1790_BG12_1.IMG \ + to=$(OUTPUT)/hi2isis_BG1.cub > /dev/null; + $(APPNAME) from=$(INPUT)/PSP_001446_1790_IR11_0.IMG \ + to=$(OUTPUT)/hi2isis_IR0.cub > /dev/null; + $(APPNAME) from=$(INPUT)/PSP_001446_1790_IR11_1.IMG \ + to=$(OUTPUT)/hi2isis_IR1.cub > /dev/null; + $(APPNAME) from=$(INPUT)/PSP_001446_1790_RED2_0.IMG \ + to=$(OUTPUT)/hi2isis_RED0.cub > /dev/null; + $(APPNAME) from=$(INPUT)/PSP_001446_1790_RED2_1.IMG \ + to=$(OUTPUT)/hi2isis_RED1.cub > /dev/null; + + tabledump from=$(OUTPUT)/hi2isis_BG0.cub \ + to=$(OUTPUT)/BG0_CalibrationImage.txt \ + name="HiRISE Calibration Image" >/dev/null; + tabledump from=$(OUTPUT)/hi2isis_BG0.cub \ + to=$(OUTPUT)/BG0_CalibrationAncillary.txt \ + name="HiRISE Calibration Ancillary" >/dev/null; + tabledump from=$(OUTPUT)/hi2isis_BG0.cub \ + to=$(OUTPUT)/BG0_Ancillary.txt \ + name="HiRISE Ancillary" >/dev/null; + + tabledump from=$(OUTPUT)/hi2isis_BG1.cub \ + to=$(OUTPUT)/BG1_CalibrationImage.txt \ + name="HiRISE Calibration Image" >/dev/null; + tabledump from=$(OUTPUT)/hi2isis_BG1.cub \ + to=$(OUTPUT)/BG1_CalibrationAncillary.txt \ + name="HiRISE Calibration Ancillary" >/dev/null; + tabledump from=$(OUTPUT)/hi2isis_BG1.cub \ + to=$(OUTPUT)/BG1_Ancillary.txt \ + name="HiRISE Ancillary" >/dev/null; + + tabledump from=$(OUTPUT)/hi2isis_IR0.cub \ + to=$(OUTPUT)/IR0_CalibrationImage.txt \ + name="HiRISE Calibration Image" >/dev/null; + tabledump from=$(OUTPUT)/hi2isis_IR0.cub \ + to=$(OUTPUT)/IR0_CalibrationAncillary.txt \ + name="HiRISE Calibration Ancillary" >/dev/null; + tabledump from=$(OUTPUT)/hi2isis_IR0.cub \ + to=$(OUTPUT)/IR0_Ancillary.txt \ + name="HiRISE Ancillary" >/dev/null; + + tabledump from=$(OUTPUT)/hi2isis_IR1.cub \ + to=$(OUTPUT)/IR1_CalibrationImage.txt \ + name="HiRISE Calibration Image" >/dev/null; + tabledump from=$(OUTPUT)/hi2isis_IR1.cub \ + to=$(OUTPUT)/IR1_CalibrationAncillary.txt \ + name="HiRISE Calibration Ancillary" >/dev/null; + tabledump from=$(OUTPUT)/hi2isis_IR1.cub \ + to=$(OUTPUT)/IR1_Ancillary.txt \ + name="HiRISE Ancillary" >/dev/null; + + tabledump from=$(OUTPUT)/hi2isis_RED0.cub \ + to=$(OUTPUT)/RED0_CalibrationImage.txt \ + name="HiRISE Calibration Image" >/dev/null; + tabledump from=$(OUTPUT)/hi2isis_RED0.cub \ + to=$(OUTPUT)/RED0_CalibrationAncillary.txt \ + name="HiRISE Calibration Ancillary" >/dev/null; + tabledump from=$(OUTPUT)/hi2isis_RED0.cub \ + to=$(OUTPUT)/RED0_Ancillary.txt \ + name="HiRISE Ancillary" >/dev/null; + + tabledump from=$(OUTPUT)/hi2isis_RED1.cub \ + to=$(OUTPUT)/RED1_CalibrationImage.txt \ + name="HiRISE Calibration Image" >/dev/null; + tabledump from=$(OUTPUT)/hi2isis_RED1.cub \ + to=$(OUTPUT)/RED1_CalibrationAncillary.txt \ + name="HiRISE Calibration Ancillary" >/dev/null; + tabledump from=$(OUTPUT)/hi2isis_RED1.cub \ + to=$(OUTPUT)/RED1_Ancillary.txt \ + name="HiRISE Ancillary" >/dev/null; diff --git a/isis/src/mro/apps/hi2isis/tsts/default_worstcase/Makefile b/isis/src/mro/apps/hi2isis/tsts/default_worstcase/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d5cd0d100107ee15fe3e0f807d457e0c2e9e5d69 --- /dev/null +++ b/isis/src/mro/apps/hi2isis/tsts/default_worstcase/Makefile @@ -0,0 +1,7 @@ +APPNAME = hi2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/PSP_001331_2260_IR10_1.IMG \ + to=$(OUTPUT)/hi2isis_truth.cub > /dev/null; diff --git a/isis/src/mro/apps/hi2isis/tsts/unlut/Makefile b/isis/src/mro/apps/hi2isis/tsts/unlut/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..459a35117307da434b6adb3263f9f5c3026f9807 --- /dev/null +++ b/isis/src/mro/apps/hi2isis/tsts/unlut/Makefile @@ -0,0 +1,8 @@ +APPNAME = hi2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/PSP_001446_1790_BG12_0.IMG \ + to=$(OUTPUT)/hi2isis_truth.cub \ + unlut=false > /dev/null; diff --git a/isis/src/mro/apps/hical/Component.h b/isis/src/mro/apps/hical/Component.h new file mode 100644 index 0000000000000000000000000000000000000000..75ec8d990392be030657fad5a480d5c092f89861 --- /dev/null +++ b/isis/src/mro/apps/hical/Component.h @@ -0,0 +1,168 @@ +#if !defined(Component_h) +#define Component_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:22 $ + * $Id: Component.h,v 1.1 2009/09/16 03:37:22 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include + +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "PvlKeyword.h" +#include "PvlGroup.h" +#include "iException.h" + +namespace Isis { + + class PvlGroup; + + /** + * @brief Component manages HiRISE calibration vectors from various sources + * + * @ingroup Utility + * @author 2007-10-05 Kris Becker + */ + class Component { + public: + friend std::ostream &operator<<(std::ostream &o, const Component &c) { + c.printOn(o); + return (o); + } + + public: + // Constructors and Destructor + Component() : _name("Component"), _data(), _history(), + _fmtWidth(DefaultWidth), _fmtPrecision(DefaultPrecision) { } + Component(const std::string &name) : _name(name), _data(), _history(), + _fmtWidth(DefaultWidth), _fmtPrecision(DefaultPrecision) { } + Component(const std::string &name, const HiHistory &history) : + _name(name), _data(), _history(history), + _fmtWidth(DefaultWidth), _fmtPrecision(DefaultPrecision) { } + Component(const std::string &name, const Component &c) : _name(name), + _data(c._data), _history(c._history), _fmtWidth(c._fmtWidth), + _fmtPrecision(c._fmtPrecision) { } + Component(const Component &c) : _name(c._name), _data(c._data), + _history(c._history), + _fmtWidth(c._fmtWidth), + _fmtPrecision(c._fmtPrecision) { } + + + /** Destructor */ + virtual ~Component() { } + + inline std::string name() const { return (_name); } + inline int size() const { return (_data.dim()); } + + virtual void Process(const Component &c) { + Process(c.ref()); + } + + virtual void Process(const HiVector &v) { + _data = v; + return; + } + + const HiVector &ref() const { return (_data); } + inline double operator()(int index) const { return (_data[index]);} + + const HiHistory &History() const { return (_history); } + + virtual void record(PvlGroup &pvl, + const std::string keyname = "ComponentHistory") + const { + pvl += _history.makekey(keyname); + return; + } + + /** + * @brief Dumps the component to a specified file + * + * @param fname Name of file to dump contents to + * + */ + void Dump(const std::string &fname) const { + Filename dumpc(fname); + std::string dumpcFile = dumpc.Expanded(); + std::ofstream ofile(dumpcFile.c_str(), std::ios::out); + if (!ofile) { + std::string mess = "Unable to open/create module dump file " + + dumpc.Expanded(); + throw iException::Message(iException::User, mess, _FILEINFO_); + } + ofile << *this; + ofile.close(); + return; + } + + + protected: + enum { DefaultWidth = 10, DefaultPrecision = 6}; + + std::string _name; //!< Name of component + HiVector _data; //!< Data vector + HiHistory _history; //!< Hierarchial component history + int _fmtWidth; //!< Default field with of double + int _fmtPrecision; //!< Default field with of double + + /** + * @brief Properly format values that could be special pixels + * + * This method applies ISIS special pixel value conventions to properly + * print pixel values. + * + * @param[in] (double) value Input value to test for specialness and print + * as requested by caller + * @param[in] (int) width Width of field in which to print the value + * @param[in] (int) prec Precision used to format the value + * @return (string) Formatted double value + */ + inline std::string formatDbl(const double &value) const { + std::ostringstream ostr; + if (IsSpecial(value)) { + ostr << std::setw(_fmtWidth) << PixelToString(value); + return (std::string(ostr.str())); + } + else { + // Its not special so format to callers specs + ostr << std::setw(_fmtWidth) << std::setprecision(_fmtPrecision) << value; + return (std::string(ostr.str())); + } + } + + virtual void printOn(std::ostream &o) const { + o << "# History = " << _history << std::endl; + o << "# Count = " << _data.dim() << std::endl; + for (int i = 0 ; i < _data.dim() ; i++) { + o << formatDbl(_data[i]) << std::endl; + } + return; + } + + }; + +} // namespace Isis +#endif diff --git a/isis/src/mro/apps/hical/DarkSubtractComp.h b/isis/src/mro/apps/hical/DarkSubtractComp.h new file mode 100644 index 0000000000000000000000000000000000000000..d7f23474f1b56e5affa19881bf1a89ce70287082 --- /dev/null +++ b/isis/src/mro/apps/hical/DarkSubtractComp.h @@ -0,0 +1,209 @@ +#if !defined(DarkSubtractComp_h) +#define DarkSubtractComp_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:22 $ + * $Id: DarkSubtractComp.h,v 1.1 2009/09/16 03:37:22 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "Component.h" +#include "Filename.h" +#include "CSVReader.h" +#include "Statistics.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Computes a complex dark subtraction component + * + * This class computes the HiRISE dark correction component using a + * combination of the B matrix, slope/intercept components and temperature + * profiles. + * + * @ingroup Utility + * + * @author 2008-01-10 Kris Becker + * @internal + * @history 2008-06-13 Kris Becker - Added PrintOn method to produce more + * detailed data dump; Added computation of statistics + * + */ + class DarkSubtractComp : public Component { + + public: + // Constructors and Destructor + DarkSubtractComp() : Component("DarkSubtract") { } + DarkSubtractComp(const HiCalConf &conf) : Component("DarkSubtract") { + init(conf); + } + + /** Destructor */ + virtual ~DarkSubtractComp() { } + + /** + * @brief Return statistics for filtered - raw Buffer + * + * @return const Statistics& Statistics class with all stats + */ + const Statistics &Stats() const { return (_stats); } + + private: + int _tdi; + int _bin; + int _ccd; + int _channel; + + HiVector _BM; + HiVector _slope; + HiVector _intercept; + HiVector _tempProf; + + double _refTemp; + + Statistics _stats; + + void init(const HiCalConf &conf) { + _history.clear(); + DbProfile prof = conf.getMatrixProfile(); + _history.add("Profile["+ prof.Name()+"]"); + _tdi = ToInteger(prof("Tdi")); + _bin = ToInteger(prof("Summing")); + int samples = ToInteger(prof("Samples")); + + // Get B matrix and slope/intercept parameters + _BM = conf.getMatrix("B", prof); + _history.add("LoadMatrix(B[" + conf.getMatrixSource("B",prof) + + "],Band[" + ToString(conf.getMatrixBand(prof)) + "])"); + + int skip = ConfKey(prof, "SkipLines", 0); + _slope = loadCsv(conf.getMatrixSource("Slope",prof), _tdi, skip); + _intercept = loadCsv(conf.getMatrixSource("Intercept",prof), _tdi, skip); + + _refTemp = ConfKey(prof, "FpaReferenceTemperature", 21.0); + + // Smooth/filter if requested + int width = ConfKey(prof,"ZbFilterWidth",3); + int iters = ConfKey(prof,"ZbFilterIterations",0); + LowPassFilterComp smooth(width, iters); + _history.add("Smooth(Width["+ToString(width)+"],Iters["+ToString(iters)+"])"); + + // Set average tempuratures + double fpa_py_temp = ToDouble(prof("FpaPositiveYTemperature")); + double fpa_my_temp = ToDouble(prof("FpaNegativeYTemperature")); + double temp = (fpa_py_temp+fpa_my_temp) / 2.0; + _history.add("BaseTemperature[" + ToString(temp) + "]"); + + // Filter the slope/intercept + smooth.Process(_slope); + _slope = smooth.ref(); + + smooth.Process(_intercept); + _intercept = smooth.ref(); + + HiVector t_prof(_slope.dim()); + for (int i = 0 ; i < _slope.dim() ; i++) { + t_prof[i] = _intercept[i] + _slope[i] * temp; + } + + _tempProf = rebin(t_prof, samples); + _history.add("Rebin(T_Profile," + ToString(t_prof.dim()) + "," + + ToString(samples) +")"); + + HiVector dc(samples); + double linetime = ToDouble(prof("ScanExposureDuration")); + double scale = linetime * 1.0E-6 * (_bin*_bin) * + (20.0*103.0/89.0 + _tdi); + double baseT = HiTempEqn(_refTemp); + for (int j = 0 ; j < samples ; j++) { + dc[j] = _BM[j] * scale * HiTempEqn(_tempProf[j]) / baseT; + } + + // Filter it yet again + smooth.Process(dc); + _data = smooth.ref(); + + // Compute statistics and record to history + _stats.Reset(); + for ( int i = 0 ; i < _data.dim() ; i++ ) { + _stats.AddData(_data[i]); + } + _history.add("Statistics(Average["+ToString(_stats.Average())+ + "],StdDev["+ToString(_stats.StandardDeviation())+"])"); + return; + } + + HiVector loadCsv(const std::string &fname, int tdi, int skip) { + Filename csvfile(fname); + CSVReader csv(csvfile.Expanded(), true, skip); + iString myHead = "TDI " + iString(tdi); + + CSVReader::CSVAxis header(csv.getHeader()); + for (int i = 0 ; i < header.dim() ; i++) { + if (iString::Equal(myHead,iString(header[i]).Trim(" \r\t"))) { + _history.add("LoadCSV("+ fname +",TDI[" + ToString(tdi) + + "],Skip["+ ToString(skip) + "],Column[" + + ToString(i) + "])") ; + return (convert(csv.getColumn(i))); + } + } + + std::ostringstream mess; + mess << "Column " << myHead << " not found in file " << fname + << "!"; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + HiVector convert(const CSVReader::CSVAxis &v) const { + HiVector newV(v.dim()); + for ( int i = 0 ; i < v.dim() ; i++ ) { + newV[i] = ToDouble(v[i]); + } + return (newV); + } + + virtual void printOn(std::ostream &o) const { + o << "# History = " << _history << std::endl; + // Write out the header + o << std::setw(_fmtWidth) << "BMatrix" + << std::setw(_fmtWidth+1) << "RebinTemp" + << std::setw(_fmtWidth+1) << "Dark\n"; + + for (int i = 0 ; i < _data.dim() ; i++) { + o << formatDbl(_BM[i]) << " " + << formatDbl(_tempProf[i]) << " " + << formatDbl(_data[i]) << std::endl; + } + return; + } + + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hical/DriftBuffer.h b/isis/src/mro/apps/hical/DriftBuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..5feff2e2296c9c389fcabf73816de25d054841e8 --- /dev/null +++ b/isis/src/mro/apps/hical/DriftBuffer.h @@ -0,0 +1,130 @@ +#if !defined(DriftBuffer_h) +#define DriftBuffer_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:22 $ + * $Id: DriftBuffer.h,v 1.1 2009/09/16 03:37:22 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include + + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "Component.h" +#include "SplineFillComp.h" +#include "LowPassFilterComp.h" +#include "Statistics.h" +#include "SpecialPixel.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Loads and processes Buffer calibration data + * + * This class loads and processes the Buffer data from a HiRISE image for + * drift correction purposes. Additional processing may occur in subsequent + * modules. + * + * @ingroup Utility + * + * @author 2008-06-10 Kris Becker + */ + class DriftBuffer : public Component { + + public: + // Constructors and Destructor + DriftBuffer() : Component("DriftBuffer") { } + DriftBuffer(HiCalData &cal, const HiCalConf &conf) : + Component("DriftBuffer") { + init(cal, conf); + } + + /** Destructor */ + virtual ~DriftBuffer() { } + + /** + * @brief Return statistics for filtered - raw Buffer + * + * @return const Statistics& Statistics class with all stats + */ + const Statistics &Stats() const { return (_stats); } + + private: + HiVector _buffer; + Statistics _stats; + + void init(HiCalData &cal, const HiCalConf &conf) { + DbProfile prof = conf.getMatrixProfile(); + _history.clear(); + _history.add("Profile["+ prof.Name()+"]"); + + int samp0 = ConfKey(prof,"ZfFirstSample",0); + int sampN = ConfKey(prof,"ZfLastSample",11); + _buffer = averageSamples(cal.getBuffer(), samp0, sampN); + _history.add("AveCols(Buffer["+ToString(samp0)+","+ToString(sampN)+"])"); + + // Smooth/filter the averages + LowPassFilterComp bufter(_buffer, _history, + ConfKey(prof,"ZfFilterWidth",201), + ConfKey(prof,"ZfFilterIterations",2)); + // If need be, fill the data with a cubic spline + SplineFillComp spline(bufter); + _data = spline.ref(); + _history = spline.History(); + + // Compute statistics and record to history + _stats.Reset(); + for ( int i = 0 ; i < _data.dim() ; i++ ) { + // Spline guarantees _data is non-null! + if ( !IsSpecial(_buffer[i]) ) { + _stats.AddData(_data[i] - _buffer[i]); + } + } + _history.add("Statistics(Average["+ToString(_stats.Average())+ + "],StdDev["+ToString(_stats.StandardDeviation())+"])"); + return; + } + + virtual void printOn(std::ostream &o) const { + o << "# History = " << _history << std::endl; + // Write out the header + o << std::setw(_fmtWidth) << "RawBuffer" + << std::setw(_fmtWidth+1) << "Filtered\n"; + + for (int i = 0 ; i < _data.dim() ; i++) { + o << formatDbl(_buffer[i]) << " " + << formatDbl(_data[i]) << std::endl; + } + return; + } + + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hical/DriftCorrect.cpp b/isis/src/mro/apps/hical/DriftCorrect.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8fb49d56f225cf4881609ec43b3cd94efacf6d26 --- /dev/null +++ b/isis/src/mro/apps/hical/DriftCorrect.cpp @@ -0,0 +1,295 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:22 $ + * $Id: DriftCorrect.cpp,v 1.1 2009/09/16 03:37:22 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include +#include + +#include "DriftCorrect.h" +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "LeastSquares.h" +#include "LowPassFilterComp.h" +#include "MultivariateStatistics.h" +#include "iException.h" + +using namespace std; + +namespace Isis { + + DriftCorrect::DriftCorrect(const HiCalConf &conf) : + NonLinearLSQ(), Component("DriftCorrect") { + DbProfile prof = conf.getMatrixProfile(); + _history.add("Profile["+ prof.Name()+"]"); + _timet.setBin(ToInteger(prof("Summing"))); + _timet.setLineTime(ToDouble(prof("ScanExposureDuration"))); + + + _skipFit = IsEqual(ConfKey(prof, "ZdSkipFit", std::string("TRUE")), "TRUE"); + _useLinFit = IsTrueValue(prof, "ZdOnFailUseLinear"); + + _absErr = ConfKey(prof, "AbsoluteError", 1.0E-4); + _relErr = ConfKey(prof, "RelativeError", 1.0E-4); + + _sWidth = ConfKey(prof, "GuessFilterWidth", 17); + _sIters = ConfKey(prof, "GuessFilterIterations", 1); + + if ( prof.exists("MaximumIterations") ) { + setMaxIters(ToInteger(prof("MaximumIterations"))); + } + + _maxLog = ConfKey(prof, "MaximumLog", 709.0); + _badLines = ToInteger(prof("TrimLines"))/ToInteger(prof("Summing")); + _minLines = ConfKey(prof,"ZdMinimumLines", 100); + + string histstr = "DriftCorrect(AbsErr[" + ToString(_absErr) + + "],RelErr[" + ToString(_relErr) + + "],MaxIter[" + ToString(maxIters()) + "])"; + _history.add(histstr); + } + + HiVector DriftCorrect::Solve(const HiVector &d) { + ostringstream hist; + _data = d; + if ( _skipFit || (!gotGoodLines(d))) { + _b2 = _data; + _coefs = HiVector(4, 0.0); + _uncert = _coefs; + _cc = HiVector(2, 0.0); + _chisq = 0.0; + if ( !gotGoodLines(d) ) { + hist << "NotEnoughLines(GoodLines[" << goodLines(d) + << "],MinimumLines[" << _minLines << "]);"; + } + + hist << "SkipFit(TRUE: Not using LMFit)"; + _history.add(hist.str()); + } + else { + hist << "Fit("; + _b2 = HiVector(goodLines(_data)); + if ( success(curvefit()) ) { + _coefs = coefs(); + _uncert = uncert(); + hist << "Solved,#Iters[" << nIterations() << "],ChiSq[" << Chisq() + << "],DoF[" << DoF() << "])"; + _history.add(hist.str()); + _history.add("a0("+ToString(_coefs[0])+"+-"+ToString(_uncert[0])+")"); + _history.add("a1("+ToString(_coefs[1])+"+-"+ToString(_uncert[1])+")"); + _history.add("a2("+ToString(_coefs[2])+"+-"+ToString(_uncert[2])+")"); + _history.add("a3("+ToString(_coefs[3])+"+-"+ToString(_uncert[3])+")"); + } + else { + // Punt, fit a straight line to the data + _cc = poly_fit(d); + HiVector a(4); + a[0] = _cc[0]; + a[1] = _cc[1]; + a[2] = 0.0; + a[3] = 0.0; + _coefs = a; + + hist << "Failed::Reason("<< statusstr() << "),#Iters[" + << nIterations() << "])"; + _history.add(hist.str()); + _history.add("a0("+ToString(_coefs[0])+")"); + _history.add("a1("+ToString(_coefs[1])+")"); + _history.add("a2("+ToString(_coefs[2])+")"); + _history.add("a3("+ToString(_coefs[3])+")"); + if ( _useLinFit ) { + _history.add("OnFailureUse(LinearFit(Zf))"); + } + else { + _skipFit = true; + _history.add("OnFailureUse(ZfBuffer)"); + } + } + } + return (Yfit()); + } + + /** + * @brief Compute the initial guess of the fit + * + * This method provides the non-linear fit with an initial guess of the + * solution. It involves a linear fit to the latter half of the data to + * provide the first two coefficents, the difference of the averages of the + * residuals at both ends of the data set and 5 times the last line time as + * the final (fourth) element...a bit involved really. + * + * @return NLVector 4-element vector of the initial guess coefficients + */ + NonLinearLSQ::NLVector DriftCorrect::guess() { + int n = _data.dim(); + int nb = n - _badLines; + + HiVector b1 = _data.subarray(0, nb-1); + LowPassFilterComp gfilter(b1, _history, _sWidth, _sIters); + + int nb2 = nb/2; + _b2 = gfilter.ref(); + HiVector cc = poly_fit(_b2.subarray(nb2,_b2.dim()-1), nb2-1); + + // Compute the 3rd term guess by getting the average of the residual + // at both ends of the data set. + Statistics s; + + // Get the head of the data set + int n0 = MIN(nb, 20); + for ( int k = 0 ; k < n0 ; k++ ) { + double d = _b2[k] - (cc[0] + cc[1] * _timet(k)); + s.AddData(&d, 1); + } + double head = s.Average(); + + // Get the tail of the data set + s.Reset(); + n0 = (int) (0.9 * nb); + for ( int l = n0 ; l < nb ; l++ ) { + double d = _b2[l] - (cc[0] + cc[1] * _timet(l)); + s.AddData(&d, 1); + } + double tail = s.Average(); + + // Populate the guess with the results + NLVector g(4, 0.0); + g[0] = cc[0]; + g[1] = cc[1]; + g[2] = head-tail; + g[3] = -5.0/_timet(nb-1); + _guess = g; + _history.add("Guess["+ToString(_guess[0])+ ","+ + ToString(_guess[1])+ ","+ + ToString(_guess[2])+ ","+ + ToString(_guess[3])+ "]"); + return (g); + } + + int DriftCorrect::checkIteration(const int Iter, const NLVector &fitcoefs, + const NLVector &uncerts, double cplxconj, + int Istatus) { + _chisq = pow(cplxconj, 2.0); + return (Istatus); + } + + NonLinearLSQ::NLVector DriftCorrect::f_x(const NLVector &a) { + double a0 = a[0]; + double a1 = a[1]; + double a2 = a[2]; + double a3 = a[3]; + + int n = _b2.dim(); + NLVector f(n); + for (int i = 0 ; i < n ; i++) { + double lt = _timet(i); + double et = a3 * lt; + double Yi = a0 + (a1 * lt) + a2 * exp(MIN(et,_maxLog)); + f[i] = (Yi - _b2[i]); + } + return (f); + } + + NonLinearLSQ::NLMatrix DriftCorrect::df_x(const NLVector &a) { + // double a0 = a[0]; + // double a1 = a[1]; + double a2 = a[2]; + double a3 = a[3]; + + int n = _b2.dim(); + NLMatrix J(n, 4); + for (int i = 0; i < n; i++) { + double lt = _timet(i); + double et = a3 * lt; + double p0 = exp (MIN(et,_maxLog)); + J[i][0] = 1.0; + J[i][1] = lt; + J[i][2] = p0; + J[i][3] = a2 * lt * p0; + } + return (J); + } + + HiVector DriftCorrect::Yfit() const { + if ( _skipFit || (!gotGoodLines(_data))) { + return (_data.copy()); + } + else { + HiVector dcorr(_data.dim()); + HiVector a = _coefs; + for ( int i = 0 ; i < dcorr.dim() ; i++ ) { + double lt = _timet(i); + dcorr[i] = a[0] + (a[1] * lt) + a[2] * exp(a[3] * lt); + } + return (dcorr); + } + } + + HiVector DriftCorrect::Normalize(const HiVector &v) { + HiVector vNorm(v.dim()); + double v0 = v[0]; + for ( int i = 0 ; i < v.dim() ; i++ ) { + vNorm[i] = v[i] - v0; + } + _history.add("Normalize[" + ToString(v0) + "]"); + return (vNorm); + } + + HiVector DriftCorrect::poly_fit(const HiVector &d, const double line0) const { + // Needs a linear fit to latter half of data + MultivariateStatistics fit; + int n = d.dim(); + for ( int i = 0 ; i < n ; i++ ) { + double t = _timet(line0+i); + fit.AddData(&t, &d[i], 1); + } + NLVector cc(2); + fit.LinearRegression(cc[0], cc[1]); + return (cc); + } + + void DriftCorrect::printOn(std::ostream &o) const { + o << "# History = " << _history << endl; + // Write out the header + o << setw(_fmtWidth) << "Line" + << setw(_fmtWidth+1) << "Time" + << setw(_fmtWidth+1) << "Data" + << setw(_fmtWidth+1) << "Fit\n"; + + HiVector fit = Yfit(); + for (int i = 0 ; i < _data.dim() ; i++) { + o << formatDbl(i) << " " + << formatDbl(_timet(i)) << " " + << formatDbl(_data[i]) << " " + << formatDbl(fit[i]) << endl; + } + return; + } + +} // namespace Isis + + diff --git a/isis/src/mro/apps/hical/DriftCorrect.h b/isis/src/mro/apps/hical/DriftCorrect.h new file mode 100644 index 0000000000000000000000000000000000000000..3a3456618c9b995d76d935cb8ab5cabc93230e8d --- /dev/null +++ b/isis/src/mro/apps/hical/DriftCorrect.h @@ -0,0 +1,162 @@ +#if !defined(DriftCorrect_h) +#define DriftCorrect_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:22 $ + * $Id: DriftCorrect.h,v 1.1 2009/09/16 03:37:22 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include + +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "NonLinearLSQ.h" +#include "Component.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Computes non-linear lsq fit of HiRISE Drift + * + * This class is best used with individual HiRISE images as the number of + * lines is critical to proper use. It is best applied by getting the buffer + * as a reference and applying it during systematic processing. There really + * is no direct method to handle line access. + * + * @ingroup Utility + * + * @author 2007-11-07 Kris Becker + * @internal + * @history 2008-05-23 Kris Becker Added the ZdOnFailUseLinear option + */ + class DriftCorrect : public NonLinearLSQ, public Component { + + public: + DriftCorrect(const HiCalConf &conf); + virtual ~DriftCorrect() { } + + /** + * @brief Set binning/summing mode + * + * @param bin Summing mode of observatio + */ + void setBin(int bin) { _timet.setBin(bin); } + + /** + * @brief Set scan line time + * + * @param ltime Scan line time + */ + void setLineTime(double ltime) { _timet.setLineTime(ltime); } + + /** + * @brief Returns the size of the data buffer + * + * This is the size of the original data buffer. + * + * @see nSize() + * @return int Size of the input buffer + */ + inline int size() const { return (_data.dim()); } + + /** + * @brief Returns the size of the fitted buffer + * + * \b Important: This returns the size of the buffer being + * fitted and not the size of original data buffer. This is + * a requirement of the NonLinearLSQ class. USE WITH + * CAUTION! + * + * + * @return int Size of buffer being fitted + */ + int nSize() const { return (_b2.dim()); } + + /** + * @brief Number of parameter to be fitted + * + * This is the number of parameters that DriftCorrect needs to + * fit. This functin is a requirement of the NonLinearLSQ + * class. + * + * @return int Number of parameter to fit + */ + int nParms() const { return (4); } + + /** Sets the absolute error parameter */ + void setabsErr(double absError) { _absErr = absError; } + /** Sets the relative error parameter */ + void setrelErr(double relError) { _relErr = relError; } + /** Returns the current value of the absolute error */ + double absErr() const { return (_absErr); } + /** Returns the current value of the relative error */ + double relErr() const { return (_relErr); } + + HiVector Solve(const HiVector &d); + NLVector guess(); + int checkIteration(const int Iter, const NLVector &fitcoefs, + const NLVector &uncerts, double cplxconj, + int Istatus); + + NLVector f_x(const NLVector &a); + NLMatrix df_x(const NLVector &a); + + /** Returns the Chi-Square value of the fit solution */ + double Chisq() const { return (_chisq); } + /** Returns the Degrees of Freedom */ + int DoF() const { return (nSize() - nParms()); } + + HiVector Yfit() const; + HiVector Normalize(const HiVector &v); + + private: + HiLineTimeEqn _timet; // This is the X data set + HiVector _data; // Typically will be the HiRISE buffer data + HiVector _b2; // Data buffer used in fitting + double _absErr; // Absolute error convergence test + double _relErr; // Relative error convergence test + double _maxLog; // Maximum log value to constrain + int _badLines; // Exclude lines at end of buffer + int _sWidth; // Width of guestimate filter + int _sIters; // Filter interations + bool _skipFit; // Skip fitting and pass input through + bool _useLinFit; // Use linear fit on failure of LM, else Zf + int _minLines; // Minimum number of lines to fit (Default: 100) + HiVector _cc; // Parameter of 2-D fit + HiVector _guess; // Initial guestimate of solutions + HiVector _coefs; // Coefficients of solution + HiVector _uncert; // Uncertanties + double _chisq; // ChiSq of NonLinear equation + + HiVector poly_fit(const HiVector &d, const double line0 = 0.0) const; + virtual void printOn(std::ostream &o) const; + int goodLines(const HiVector &d) const { return (d.dim() - _badLines); } + bool gotGoodLines(const HiVector &d) const { + return (goodLines(d) >= _minLines); + } + }; + +} // namespace Isis +#endif + + diff --git a/isis/src/mro/apps/hical/FlatFieldComp.h b/isis/src/mro/apps/hical/FlatFieldComp.h new file mode 100644 index 0000000000000000000000000000000000000000..18988acd6e09912eda8d7f9c59a931a304e4a61c --- /dev/null +++ b/isis/src/mro/apps/hical/FlatFieldComp.h @@ -0,0 +1,102 @@ +#if !defined(FlatFieldComp_h) +#define FlatFieldComp_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:22 $ + * $Id: FlatFieldComp.h,v 1.1 2009/09/16 03:37:22 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "Component.h" +#include "Filename.h" +#include "CSVReader.h" +#include "Statistics.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Za Module - Computes flat field correction for each sample (column) + * + * This class computes the HiRISE flat field correction component using the A + * matrix. + * + * @ingroup Utility + * + * @author 2008-03-04 Kris Becker + * @history 2009-09-14 Kris Becker Removed temperature components and placed + * them in the Zt (TempGainCorrect) module. + */ + class FlatFieldComp : public Component { + + public: + // Constructors and Destructor + FlatFieldComp() : Component("FlatFieldComp") { } + FlatFieldComp(const HiCalConf &conf) : Component("FlatField") { + init(conf); + } + + /** Destructor */ + virtual ~FlatFieldComp() { } + + /** + * @brief Return statistics A matrix corection + * + * @return const Statistics& Statistics class with all stats + */ + const Statistics &Stats() const { return (_stats); } + + private: + std::string _amatrix; + Statistics _stats; // Stats Results + + void init(const HiCalConf &conf) { + _history.clear(); + DbProfile prof = conf.getMatrixProfile(); + _history.add("Profile["+ prof.Name()+"]"); + + // Get parameters from gainVline coefficients file + _amatrix = conf.getMatrixSource("A", prof); + _data = conf.getMatrix("A",prof); + _history.add("LoadMatrix(A[" + _amatrix + + "],Band[" + ToString(conf.getMatrixBand(prof)) + "])"); + + _stats.Reset(); + for ( int i = 0 ; i < _data.dim() ; i++ ) { + _stats.AddData(_data[i]); + } + + _history.add("Statistics(Average["+ToString(_stats.Average())+ + "],StdDev["+ToString(_stats.StandardDeviation())+"])"); + return; + } + + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hical/GainVLineComp.h b/isis/src/mro/apps/hical/GainVLineComp.h new file mode 100644 index 0000000000000000000000000000000000000000..4e0b3bedc5fe6ebdb185c123c477739fd3b230b6 --- /dev/null +++ b/isis/src/mro/apps/hical/GainVLineComp.h @@ -0,0 +1,138 @@ +#if !defined(GainVLineComp_h) +#define GainVLineComp_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:22 $ + * $Id: GainVLineComp.h,v 1.1 2009/09/16 03:37:22 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "Component.h" +#include "Filename.h" +#include "CSVReader.h" + +#include "iException.h" + +namespace Isis { + + /** + * @brief Computes a gain correction for each line + * + * This class computes the HiRISE dark correction component using a + * combination of the B matrix, slope/intercept components and temperature + * profiles. + * + * @ingroup Utility + * + * @author 2008-01-10 Kris Becker + */ + class GainVLineComp : public Component { + + public: + // Constructors and Destructor + GainVLineComp() : Component("GainVLineComp") { } + GainVLineComp(const HiCalConf &conf) : Component("GainVLine") { + init(conf); + } + + /** Destructor */ + virtual ~GainVLineComp() { } + + private: + std::string _gdfile; + int _ccd; + int _channel; + HiVector _coefs; + + void init(const HiCalConf &conf) { + _history.clear(); + DbProfile prof = conf.getMatrixProfile(); + _history.add("Profile["+ prof.Name()+"]"); + _ccd = CpmmToCcd(ToInteger(prof("CpmmNumber"))); + _channel = ToInteger(prof("ChannelNumber")); + + // Get parameters from gainVline coefficients file + int skip = ConfKey(prof, "SkipLines", 0); + _gdfile = conf.getMatrixSource("GainLineCoefficients", prof); + _coefs = loadCsv(_gdfile, _ccd, _channel, skip); + + _history.add("Coefs["+ToString(_coefs[0])+ ","+ + ToString(_coefs[1])+ ","+ + ToString(_coefs[2])+ ","+ + ToString(_coefs[3])+ "]"); + + int bin = ToInteger(prof("Summing")); + double linetime = ToDouble(prof("ScanExposureDuration")); + HiLineTimeEqn timet(bin, linetime); + int nlines = ToInteger(prof("Lines")); + + HiVector gainV(nlines); + for ( int i = 0 ; i < nlines ; i++ ) { + double lt = timet(i); + gainV[i] = _coefs[0] + (_coefs[1] * lt) + + _coefs[2] * exp(_coefs[3] * lt); + } + + _data = gainV; + return; + } + + + HiVector loadCsv(const std::string &fname, int ccd, int channel, + int skip) { + Filename csvfile(fname); + CSVReader csv(csvfile.Expanded(), true, skip); + CSVReader::CSVIntVector ccds = csv.convert(csv.getColumn(0)); + CSVReader::CSVIntVector chans = csv.convert(csv.getColumn(1)); + + for (int i = 0 ; i < ccds.dim() ; i++) { + if ( (ccds[i] == ccd) && (chans[i] == channel) ) { + // Got it, extract the indicated row and translate + CSVReader::CSVAxis coefRow = csv.getRow(i); + HiVector coef(4); + for (int c = 0 ; c < 4 ; c++) { + coef[c] = (coefRow[c+2].Trim(" \r\n\t")).ToDouble(); + } + _history.add("LoadCSV("+ fname +",Ccd[" + ToString(ccd) + + "],Channel[" + ToString(channel) + + "],Skip["+ ToString(skip) + "],Row[" + + ToString(i) + "])") ; + return (coef); + } + } + + // Did not find the proper row + std::ostringstream mess; + mess << "Cannot find Ccd/Channel (" << _ccd << "/" << _channel + << ") match in CSV file " << fname; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hical/HISTORY b/isis/src/mro/apps/hical/HISTORY new file mode 100644 index 0000000000000000000000000000000000000000..b4dd46cb9fdb654aabcc7e2f76fc358a737c3a99 --- /dev/null +++ b/isis/src/mro/apps/hical/HISTORY @@ -0,0 +1,9 @@ + hical Snapshot History + September 15, 2009 + +The contents of this file record hical snapshot hicalbeta update events. They +are listed in chronologic order. + +2009-09-15 +Original version of hical created from current version of hicalbeta. +hical.0015.conf is the current version of the config file. diff --git a/isis/src/mro/apps/hical/HiBlob.h b/isis/src/mro/apps/hical/HiBlob.h new file mode 100644 index 0000000000000000000000000000000000000000..46127dced1e7e58b1f22a6e34f74e5a6c09fa84e --- /dev/null +++ b/isis/src/mro/apps/hical/HiBlob.h @@ -0,0 +1,76 @@ +#if !defined(HiBlob_h) +#define HiBlob_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:22 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "Blobber.h" +#include "HiCalTypes.h" + +namespace Isis { + +/** + * @brief BLOB extraction class + * + * This class provides access and processing of HiRISE data as + * stored in an ISIS BLOB (Table). + * + * Note that the file provided must be a HiRISE ISIS cube file + * that is freshly converted from a PDS compatable EDR + * (hi2isis). It must contain an ISIS Table named "HiRISE + * Calibration Image". From that table, data is extracted from + * the "Calibration" field. + * + * @ingroup MarsReconnaissanceOrbiter + * + * @author 2007-10-09 Kris Becker + * @see Blobber + * + * @internal + * @history 2008-05-12 Steven Lambright - Removed references to CubeInfo + */ + class HiBlob : public Blobber { + public: + /** + * @brief Default, mostly useless constructor + */ + HiBlob(): Blobber() { } + + /** + * @brief Constructor providing interface to an ISIS Cube object + */ + HiBlob(Cube &cube, const std::string &tblname, + const std::string &field, + const std::string &name = "HiBlob") : + Blobber(cube, tblname, field, name) { } + + /** Destructor */ + virtual ~HiBlob() { } + + /** Return a reference to the data */ + const HiMatrix &buffer() const { return (ref()); } + + }; +}; + +#endif diff --git a/isis/src/mro/apps/hical/HiCalConf.cpp b/isis/src/mro/apps/hical/HiCalConf.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8d69c3c3c20df2b3a440460f8d0b2165f43d933 --- /dev/null +++ b/isis/src/mro/apps/hical/HiCalConf.cpp @@ -0,0 +1,602 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2009/12/29 23:03:52 $ + * $Id: HiCalConf.cpp,v 1.2 2009/12/29 23:03:52 ehyer Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include + +#include "HiCalConf.h" +#include "HiCalUtil.h" +#include "Pvl.h" +#include "Filename.h" +#include "Cube.h" +#include "Brick.h" +#include "SpecialPixel.h" +#include "iString.h" +#include "iException.h" + +#include "naif/SpiceUsr.h" + +using namespace std; + +namespace Isis { + +bool HiCalConf::_naifLoaded = false; + +/** + * @brief Default constructor for HiCalConf + */ + HiCalConf::HiCalConf() : DbAccess() { + _profName.clear(); + init(); + } + + + /** + * @brief Construct from a HiRISE label + * @param label Label from HiRISE cube file + */ + HiCalConf::HiCalConf(Pvl &label) : DbAccess() { + _profName.clear(); + init(label); + } + + /** + * @brief Construct from HiRISE label and configuration file + * + * @param label Label from HiRISE cube file + * @param conf Name of configuration file to use + */ + HiCalConf::HiCalConf(Pvl &label, const std::string &conf) : + DbAccess(Pvl(filepath(conf)).FindObject("Hical", PvlObject::Traverse)) { + _profName.clear(); + init(label); + } + + /** + * @brief Define label to initialize parameters from + * + * @param label Label from HiRISE cube file + */ + void HiCalConf::setLabel(Pvl &label) { + init(label); + return; + } + + /** + * @brief Resolve a file path validating existance + * + * This method determines if a filepath is versioned (as indicated with one or + * more '?') and returns the expanded file name \b only. It does not expand + * the path portion of the filespec. This is so to make use of the results of + * this method in reporting files in labels...to make it tidy. + * + * @param fname File specification with or without versioning patterns + * + * @return string Expanded filename but not the filepath + */ + string HiCalConf::filepath(const std::string &fname) const { + string::size_type start = fname.find_first_of("?"); + if (start != string::npos) { + Filename efile(fname); + + string path(efile.OriginalPath()); + if (!path.empty()) path += "/"; + + efile.HighestVersion(); + + return (path + efile.Name()); + } + return (fname); + } + + + /** + * @brief Establish the configuration file used for calibration parameters + * + * This file can be established at any point in the processing as parameters + * are resolved as needed (lazy instantiation). One must be established + * before any calibration can take place. + * + * @param conf Name of configuration file to use + */ + void HiCalConf::setConf(const std::string &conf) { + load(Pvl(filepath(conf)).FindObject("Hical", PvlObject::Traverse)); + } + + /** + * @brief Selects a profile other than the default + * + * Use of this method is to explicitly select a named profile in the + * configuration file. If this is used, additional profile options are not + * loaded. + * + * @param profile Name of existing profile in the configuration file + */ + void HiCalConf::selectProfile(const std::string &profile) { + _profName = profile; + return; + } + + /** + * @brief Returns the fully optioned profile name used + * + * This method returns the fully optioned profile used to define calibration + * processing parameters. It has the form: + * @code + * default+[option1]+[option2]+...+[optionN] + * @endcode + * This specifies the name of the default profile and any additional option + * profile loaded in the indicated order. + * + * @return string Combined profile name + */ + string HiCalConf::getProfileName() const { + return (getMatrixProfile().Name()); + } + + /** + * @brief Returns the named expanded matrix file reference + * + * This method returns the name of a matrix file reference variable from the + * \b Matrices keyword as determined from the fully option profile. It then + * expands the filename portion (not the filepath!) and returns the result as + * a string for subsequent use. See also getMatrixList and getMatrix. + * + * @param name Name of Matrix to resolve. It must be one in the \b Matrices + * keyword from the configuration file + * + * @return std::string The expanded file name reference for the matrix + */ + std::string HiCalConf::getMatrixSource(const std::string &name) const { + return (getMatrixSource(name, getMatrixProfile())); + } + + /** + * @brief Returns the named expanded matrix file reference + * + * This method returns the name of a matrix file reference variable from the + * \b Matrices keyword as determined from the specified profile. It then + * expands the filename portion (not the filepath!) and returns the result as + * a string for subsequent use. See also getMatrixList and getMatrix. + * + * @param name Name of Matrix to resolve. It must be one in the \b Matrices + * keyword from the configuration file + * @param matconf Profile to extract the named matrix source from + * + * @return std::string The expanded file name reference for the matrix + */ + std::string HiCalConf::getMatrixSource(const std::string &name, + const DbProfile &matconf) const { + + std::string mfile = parser(matconf.value(name), + getList(matconf,"OptionKeywords"), + matconf); + +// Translate and return + return (filepath(mfile)); + } + + HiVector HiCalConf::getMatrix(const std::string &name, + int expected_size) const { + return (getMatrix(name,getMatrixProfile(), expected_size)); + } + + + std::string HiCalConf::resolve(const std::string &composite, + const DbProfile &matconf) const { + return (parser(composite,getList(matconf,"OptionKeywords"), matconf)); + } + + + + /** + * @brief Returns the named matrix from the specified file reference + * + * The matrix specified in the name parameter must exist in the \b Matrices + * keyword in the \b Hical object of the configuration file. A fully option + * profile is created within this method and the keyword of the named variable + * is retreived from it. The fully qualified filepath is generated to + * finally resolve to a multi-band, single line, Isis cube file. A specific + * band is extracted from the cube file as determined by the CCD channel + * (provide by the getMatrixBand method) and returned in a HiVector data + * array. + * + * Note that the caller can specify the number of samples expected from the + * matrix cube in the expected_size parameter if it is non-zero. Once the + * matrix cube is opened, the number of samples is checked against this + * parameter and if they do not match, an exception is thrown. + * + * @param name Name of matrix to retreive + * @param profile Specfied profile providing all parameters + * @param expected_size Expected number of samples in the matrix cube + * + * @return HiCalConf::HiVector Returns the extracted band from the cube + */ + HiVector HiCalConf::getMatrix(const std::string &name, + const DbProfile &profile, + int expected_size) const { + + std::string mfile = getMatrixSource(name, profile); + +// Crack the file and read the appropriate band + Cube cube; + cube.Open(mfile); + +// Check for proper size if specifeid + if (expected_size != 0) { + if (cube.Samples() != expected_size) { + ostringstream mess; + mess << "Specifed matrix (" << name + << ") from file \"" << mfile + << "\" does not have expected samples (" << expected_size + << ") but has " << cube.Samples(); + cube.Close(); + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + } + +// Read the specifed region + Brick bandio(cube.Samples(), 1, 1, Real); + bandio.SetBasePosition(1,1,getMatrixBand(profile)); + cube.Read(bandio); + +// Now create the output buffer with some TNT funny business + HiVector temp(cube.Samples(), bandio.DoubleBuffer()); + HiVector out(cube.Samples()); + out.inject(temp); + cube.Close(); + return (out); + } + + /** + * @brief Returns a named scalar constant + * + * This method returns a named scalar constant parameter retrieved from the + * configuration file through a fully optioned profile. This keyword does not + * necessarily have to exist in the \b Scalars keyword in the \b Hical object, + * but is required to be a floating point value (or values). The result is + * returned as a HiVector data array. + * + * @param name Name of scalar constant to return + * @param expected_size Expected size of constant if non-zero + * + * @return HiCalConf::HiVector Values of scalar constants + */ + HiVector HiCalConf::getScalar(const std::string &name, + const DbProfile &profile, + int expected_size) const { + int nvals = profile.count(name); + + // Check for proper size if specifeid + if (expected_size != 0) { + if (nvals != expected_size) { + ostringstream mess; + mess << "Specifed scalar (" << name + << ") does not have expected size (" << expected_size + << ") but has " << nvals; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + } +// All is OK + HiVector mtx(nvals, Null); + for (int i = 0 ; i < nvals ; i++) { + mtx[i] = ToDouble(profile(name, i)); + } + return (mtx); + } + + /** + * @brief Computes the distance from the Sun to the observed body + * + * This method requires the appropriate NAIK kernels to be loaded that + * provides instrument time support, leap seconds and planet body ephemeris. + * + * @return double Distance in AU between Sun and observed body + */ + double HiCalConf::sunDistanceAU() { + loadNaifTiming(); + + string scStartTime = getKey("SpacecraftClockStartCount", "Instrument"); + double obsStartTime; + scs2e_c (-74999,scStartTime.c_str(),&obsStartTime); + + string targetName = getKey("TargetName", "Instrument"); + if ( (iString::Equal(targetName, "Sky")) || + (iString::Equal(targetName, "Cal")) || + (iString::Equal(targetName, "Phobos")) || + (iString::Equal(targetName, "Deimos")) ) { + targetName = "Mars"; + } + double sunv[3]; + double lt; + (void) spkpos_c(targetName.c_str(), obsStartTime, "J2000", "LT+S", "sun", + sunv, <); + double sunkm = vnorm_c(sunv); + // Return in AU units + return (sunkm/1.49597870691E8); + } + + + /** + * @brief Returns the band number of a Matrix file given CCD, Channel number + * + * The ordering of HiRISE Isis matrix cubes are required to be ordered by CCD + * and channel number. The band number is computed as: + * @code + * band = 1 + ccd * 2 + channel + * @endcode + * + * Note that this method extracts the values from a stored cube label. It + * must be initialized with a label or an error will occur. + * + * @return int Band number of matrix cube + */ + int HiCalConf::getMatrixBand() const { + Pvl label = _label; + DbProfile parms = makeParameters(label); + return (getMatrixBand(parms)); + } + + /** + * @brief Returns the band number of a Matrix file from a profile + * + * The ordering of HiRISE Isis matrix cubes are required to be ordered by CCD + * and CHANNEL number. The band number is computed as: + * @code + * band = 1 + ccd * 2 + channel + * @endcode + * + * @param DbProfile Profile to get CCD and CHANNEL values from + * @return int Band number of matrix cube + */ + + int HiCalConf::getMatrixBand(const DbProfile &p) const { + return (1 + ToInteger(p("CCD"))*2 + ToInteger(p("CHANNEL"))); + } + + /** + * @brief Generic profile keyword value extractor + * + * This method retrieves a profile keyword from the given profile and returns + * all its values a a list of strings. An exception will be thrown + * incidentally if the keyword does not exist. + * + * @param profile Profile containing the keyword to extract + * @param key Name of keyword to retrieve + * + * @return std::vector List of values from profile keyword + */ + HiCalConf::ValueList HiCalConf::getList(const DbProfile &profile, + const std::string &key) const { + ValueList slist; + +// Get keyword parameters + if ( profile.exists(key) ) { + int nvals = profile.count(key); + for (int i = 0 ; i < nvals ; i++) { + slist.push_back(profile.value(key, i)); + } + } + return (slist); + } + +/** + * @brief Load required NAIF kernels required for timing needs + * + * This method maintains the loading of kernels for HiRISE timing and planetary + * body ephemerides to support time and relative positions of planet bodies. + */ +void HiCalConf::loadNaifTiming( ) { + if (!_naifLoaded) { +// Load the NAIF kernels to determine timing data + Isis::Filename leapseconds("$base/kernels/lsk/naif????.tls"); + leapseconds.HighestVersion(); + + Isis::Filename sclk("$mro/kernels/sclk/MRO_SCLKSCET.?????.65536.tsc"); + sclk.HighestVersion(); + + Isis::Filename pck("$base/kernels/spk/de???.bsp"); + pck.HighestVersion(); + +// Load the kernels + string lsk = leapseconds.Expanded(); + string sClock = sclk.Expanded(); + string pConstants = pck.Expanded(); + furnsh_c(lsk.c_str()); + furnsh_c(sClock.c_str()); + furnsh_c(pConstants.c_str()); + +// Ensure it is loaded only once + _naifLoaded = true; + } + return; +} + +/** + * @brief Intialization of object variables + */ +void HiCalConf::init() { + _label.Clear(); + return; +} + +/** + * @brief Initialization of object using HiRISE label + * + * This method initializes the object from a HiRISE label. Note that a copy of + * the label is created so that subsequent operations can be supported and it is + * not dependant upon callers behaviour. + * + * @param label Pvl label of HiRISE cube + */ +void HiCalConf::init(Pvl &label) { + init(); + _label = label; + return; +} + +/** + * @brief Get a label keyword + * + * Retreives a keyword from a HiRISE label and returns a reference to it. If it + * does not exist, an exception is thrown incidentally. + * + * @param key Name of keyword in label to retrieve + * @param group Optional group name to use if non-empty. + * + * @return PvlKeyword& Reference to retrieved label keyword + */ +PvlKeyword &HiCalConf::getKey(const std::string &key, + const std::string &group) { + if (!group.empty()) { + PvlGroup &grp = _label.FindGroup(group, Pvl::Traverse); + return (grp[key]); + } + else { + return (_label.FindKeyword(key)); + } +} + +/** + * @brief Returns the Matrix profile + * + * This method constructs a fully optioned matrix profile from the + * configuration file. If the caller has designated a specific named profile, + * the options profiles are not loaded. + * + * Options profiles are read from the \b ProfileOptions configuration keyword + * and resolved through pattern replacement of FILTER, TDI, BIN, CCD and CHANNEL + * values are determined from the HiRISE label. If named profiles exist after + * the textual substitutions of these values they are added to the base default + * profile. This process will replace existing default keywords of the same + * name in subseqent optional keywords. + * + * @param profile Optional name of the profile to retrieve. It will use the + * default profile if this parameter is not provided (empty). + * @return DbProfile Returns a fully optioned profile + */ +DbProfile HiCalConf::getMatrixProfile(const std::string &profile) const { + string myprof = (!profile.empty()) ? profile : _profName; + DbProfile matconf = getProfile(myprof); + if (!matconf.isValid()) { + ostringstream mess; + mess << "Specifed matrix profile (" << matconf.Name() + << ") does not exist or is invalid!"; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + // Profile the label and merge them. Order is important. + matconf = DbProfile(getLabelProfile(matconf), matconf, matconf.Name()); + + // Add special parameters. Again, order is important. + matconf = DbProfile(matconf, makeParameters(matconf), matconf.Name()); + +// Load any optional ones + ValueList profkeys = getList(matconf,"OptionKeywords"); + ValueList proforder = getList(matconf,"ProfileOptions"); + string pName(matconf.Name()); + for (unsigned int i = 0 ; i < proforder.size() ; i++) { + std::string profile = parser(proforder[i], profkeys, matconf); + if (profileExists(profile)) { + pName += "+[" + profile + "]"; + matconf = DbProfile(matconf,getProfile(profile), pName); + } + } + return (matconf); +} + + +DbProfile HiCalConf::getLabelProfile(const DbProfile &profile) const { + DbProfile lblprof("Label"); + if ( profile.exists("LabelGroups") ) { + int ngroups = profile.count("LabelGroups"); + Pvl label = _label; + for ( int g = 0 ; g < ngroups ; g++ ) { + string group = profile("LabelGroups", g); + PvlGroup grp = label.FindGroup(group, Pvl::Traverse); + lblprof = DbProfile(lblprof,DbProfile(grp)); + } + } + return (lblprof); +} + + +DbProfile HiCalConf::makeParameters(Pvl &label) const { + PvlGroup inst = label.FindGroup("Instrument", Pvl::Traverse); + DbProfile parms("Parameters"); + + int ccd = CpmmToCcd((int) inst["CpmmNumber"]); + parms.add("CCD",ToString(ccd)); + parms.add("CHANNEL", inst["ChannelNumber"]); + parms.add("TDI", inst["Tdi"]); + parms.add("BIN", inst["Summing"]); + parms.add("FILTER", CcdToFilter(ccd)); + return (parms); +} + +DbProfile HiCalConf::makeParameters(const DbProfile &profile) const { + DbProfile parms("Parameters"); + int ccd = CpmmToCcd(ToInteger(profile("CpmmNumber"))); + parms.add("CCD",ToString(ccd)); + parms.add("CHANNEL", profile("ChannelNumber")); + parms.add("TDI", profile("Tdi")); + parms.add("BIN", profile("Summing")); + parms.add("FILTER", CcdToFilter(ccd)); + return (parms); +} + +std::string HiCalConf::makePattern(const std::string &str) const { + return (string("{" + str + "}")); +} + +/** + * @brief Performs a search and replace operation for the given string + * + * This method will search the input string s for predefined keywords (FILTER, + * TDI, BIN, CCD and CHANNEL) delimited by {} and replace these occurances with + * the textual equivalent. + * + * @param s String to conduct search/replace of values + * + * @return std::string Results of search/replace + */ +std::string HiCalConf::parser(const std::string &s, const ValueList &vlist, + const DbProfile &prof) const { + string sout(s); + + ValueList::const_iterator ciVlist; + for ( ciVlist = vlist.begin() ; ciVlist != vlist.end() ; ++ciVlist ) { + std::string str(*ciVlist); + if ( prof.exists(str) ) { + sout = iString::Replace(sout, makePattern(str), prof(str)); + } + } + + return (sout); +} + +} // namespace Isis + diff --git a/isis/src/mro/apps/hical/HiCalConf.h b/isis/src/mro/apps/hical/HiCalConf.h new file mode 100644 index 0000000000000000000000000000000000000000..332aef1c48b4cd6f641d29d1b176af73785e527b --- /dev/null +++ b/isis/src/mro/apps/hical/HiCalConf.h @@ -0,0 +1,154 @@ +#if !defined(HiCalConf_h) +#define HiCalConf_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:23 $ + * $Id: HiCalConf.h,v 1.1 2009/09/16 03:37:23 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "Pvl.h" +#include "DbAccess.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief HiCalConf manages HiRISE calibration matrices + * that alter some or all of the + * parameters contained in the Object section of the file. + * This object accepts a configuration file that contains a generic format of + * HiRISE Calibration matrices and loads the appropriate set based upon TDI, + * BIN, and channel number minimally. + * + * Below is the basic unprofiled version of the configuration (database) + * file: + * + * @code + * Object = Database + * A = "$mro/calibration/matrices/A_TDI{TDI}_BIN{BIN}_????.cub" + * B = "$mro/calibration/matrices/B_TDI{TDI}_BIN{BIN}_????.cub" + * G = "$mro/calibration/matrices/G_TDI{TDI}_BIN{BIN}_????.cub" + * EndObject + * + * @endcode + * + * The \b {TDI} and \b {BIN} will be replaced with the textual translation of + * the TDI (128, 64, 32, 16, 8) and BIN (1, 2, 3, 4, 8, 16) numbers. This + * makes for easy defaulting to set up specific profiling of combinations. + * + * Additionally, you can add profiles for a TDI/BIN mode combination should + * the need arise. Simply add one or more \a Profile groups that specify + * different files for the observation conditions. + * @endcode + * + * This object will retain B, G and IF references from the main Database + * object but replace A with the one specified in the "TDI128/BIN2" Profile + * called "MyNew_A_Matrix.cub" for all HiRISE images that were acquired with + * TDI128 and BIN2 imaging parameters. + * @code + * Object = Database + * Matrices = ("A", "B", "G") + * + * A = "$mro/calibration/matrices/A_TDI{TDI}_BIN{BIN}_????.cub" + * B ="$mro/calibration/matrices/B_TDI{TDI}_BIN{BIN}_????.cub" + * G = "$mro/calibration/matrices/G_TDI{TDI}_BIN{BIN}_????.cub" + * + * Group = Profile + * Name = "TDI128/BIN2" + * A = "MyNew_A_Matrix.cub" + * EndGroup + * EndObject + * @ingroup Utility + * @author 2007-06-27 Kris Becker + * @history 2008-04-01 Kris Becker Added Phobos and Deimos to I/F modified + * target list as Mars in sundistanceAU() method so it returns + * acceptable distances + */ + class HiCalConf : public DbAccess { + public: + typedef enum { Matrix, Scalar, Keyword } CalType; + typedef std::vector ValueList; + + public: + // Constructors and Destructor + HiCalConf(); + HiCalConf(Pvl &label); + HiCalConf(Pvl &label, const std::string &conf); + + /** Destructor ensures everything is cleaned up properly */ + virtual ~HiCalConf () { } + + void setLabel(Pvl &label); + PvlKeyword &getKey(const std::string &key, const std::string &group = ""); + + std::string filepath(const std::string &fname) const; + void setConf(const std::string &conf); + void selectProfile(const std::string &profile = ""); + + std::string getProfileName() const; + std::string getMatrixSource(const std::string &name) const; + std::string getMatrixSource(const std::string &name, + const DbProfile &matconf) const; + HiVector getMatrix(const std::string &name, int expected_size = 0) const; + HiVector getMatrix(const std::string &name, const DbProfile &profile, + int expected_size = 0) const; + HiVector getScalar(const std::string &name, const DbProfile &profile, + int expected_size) const; + int getMatrixBand() const; + int getMatrixBand(const DbProfile &p) const; + + double sunDistanceAU(); + + DbProfile getMatrixProfile(const std::string &profile = "") const; + ValueList getList(const DbProfile &profile, const std::string &key) const; + std::string resolve(const std::string &composite, + const DbProfile &matconf) const; + + private: + static bool _naifLoaded; //!< Ensures one instance of NAIF kernels + std::string _profName; //!< Specified name of profile + Pvl _label; //!< Hold label for future references + + int _ccd; //!< CCD Number + int _channel; //!< Channel number + int _tdi; //!< TDI mode of operation + int _binMode; //!< Binning mode + std::string _filter; //!< Filter set name (RED, IR, BG) + + + void init(); + void init(Pvl &label); + void loadNaifTiming(); + DbProfile getLabelProfile(const DbProfile &profile) const; + DbProfile makeParameters(Pvl &label) const; + DbProfile makeParameters(const DbProfile &profile) const; + std::string makePattern(const std::string &str) const; + std::string parser(const std::string &s, const ValueList &options, + const DbProfile &prof ) const; + }; + +} // namespace Isis +#endif diff --git a/isis/src/mro/apps/hical/HiCalData.h b/isis/src/mro/apps/hical/HiCalData.h new file mode 100644 index 0000000000000000000000000000000000000000..0da2c175c35964641bc4275ec13f0f6c53ff110d --- /dev/null +++ b/isis/src/mro/apps/hical/HiCalData.h @@ -0,0 +1,167 @@ +#if !defined(HiCalData_h) +#define HiCalData_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:23 $ + * $Id: HiCalData.h,v 1.1 2009/09/16 03:37:23 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiBlob.h" +#include "Cube.h" + +#include "iException.h" + +namespace Isis { + + /** + * @brief Container for HiRISE calibration data + * + * @ingroup Utility + * + * @author 2007-10-09 Kris Becker + * + * @internal + * @history 2008-05-12 Steven Lambright - Removed references to CubeInfo + */ + class HiCalData { + + public: + // Constructors and Destructor + HiCalData() : _calimage(), _calbuffer(), _caldark(), _buffer(), + _dark(), _binning(0), _tdi(0),_cpmm(0), _channelNo(0), + _firstReverseLine(0), _lastReverseLine(0), + _firstMaskLine(0), _lastMaskLine(0), + _firstRampLine(0), _lastRampLine(0) { } + HiCalData(Cube &cube) { load(cube); } + + /** Destructor */ + virtual ~HiCalData() { } + + void load(Cube &cube) { + Progress progress; + progress.SetText("HiCalData"); + + _calimage = HiBlob(cube,"HiRISE Calibration Image", "Calibration").buffer(); + _calbuffer = HiBlob(cube,"HiRISE Calibration Ancillary", "BufferPixels").buffer(); + _caldark = HiBlob(cube,"HiRISE Calibration Ancillary", "DarkPixels").buffer(); + _buffer = HiBlob(cube,"HiRISE Ancillary", "BufferPixels").buffer(); + _dark = HiBlob(cube,"HiRISE Ancillary", "DarkPixels").buffer(); + + PvlGroup &instrument = cube.GetGroup("Instrument"); + +// Extract what is needed + _binning = instrument["Summing"]; + _tdi = instrument["Tdi"]; + _cpmm = instrument["CpmmNumber"]; + _channelNo = instrument["ChannelNumber"]; + +// Determine start/end lines + _firstReverseLine = 0; + _lastReverseLine = 19; + +// Set the mask depending on the binning mode + _firstMaskLine = 20; + _lastMaskLine = _firstMaskLine + 20/_binning - 1; + _firstRampLine = _lastMaskLine + 1; + _lastRampLine = _calimage.dim1() - 1; + } + + + HiMatrix getReverseClock() { + return (cropLines(_calimage,_firstReverseLine,_lastReverseLine)); + } + HiMatrix getMask() { + return (cropLines(_calimage, _firstMaskLine, _lastMaskLine)); + } + HiMatrix getRamp() { + return (cropLines(_calimage, _firstRampLine, _lastRampLine)); + } + + HiMatrix getDark() { return (_dark.copy()); } + HiMatrix getBuffer() { return (_buffer.copy()); } + + HiMatrix getReverseClockExtended() { + return ( + appendSamples( + appendSamples( + cropLines(_calbuffer,_firstReverseLine,_lastReverseLine), + cropLines(_calimage,_firstReverseLine,_lastReverseLine)), + cropLines(_caldark, _firstReverseLine,_lastReverseLine) + ) + ); + } + HiMatrix getMaskExtended() { + return ( + appendSamples( + appendSamples(cropLines(_calbuffer,_firstMaskLine,_lastMaskLine), + cropLines(_calimage,_firstMaskLine,_lastMaskLine)), + cropLines(_caldark, _firstMaskLine,_lastMaskLine) + ) + ); + } + HiMatrix getRampExtended() { + return ( + appendSamples( + appendSamples(cropLines(_calbuffer,_firstRampLine,_lastRampLine), + cropLines(_calimage,_firstRampLine,_lastRampLine)), + cropLines(_caldark, _firstRampLine,_lastRampLine) + ) + ); + + } + HiMatrix getDarkExtended() { + return (appendLines(_caldark, _dark)); + } + HiMatrix getBufferExtended() { + return (appendLines(_calbuffer, _buffer)); + } + + private: + + HiMatrix _calimage; + HiMatrix _calbuffer; + HiMatrix _caldark; + HiMatrix _buffer; + HiMatrix _dark; + + int _binning; + int _tdi; + int _cpmm; + int _channelNo; + + int _firstReverseLine; + int _lastReverseLine; + int _firstMaskLine; + int _lastMaskLine; + int _firstRampLine; + int _lastRampLine; + }; + +} // namespace Isis +#endif + + diff --git a/isis/src/mro/apps/hical/HiCalTypes.h b/isis/src/mro/apps/hical/HiCalTypes.h new file mode 100644 index 0000000000000000000000000000000000000000..6115c7cda92afa5eefb6539be6e3a26d80d969fc --- /dev/null +++ b/isis/src/mro/apps/hical/HiCalTypes.h @@ -0,0 +1,87 @@ +#if !defined(HiCalTypes_h) +#define HiCalTypes_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:23 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include + +#include "tnt_array1d.h" +#include "tnt_array1d_utils.h" +#include "tnt_array2d.h" +#include "tnt_array2d_utils.h" +#include "PvlKeyword.h" + +namespace Isis { + +typedef TNT::Array1D HiVector; //!< 1-D Buffer +typedef TNT::Array2D HiMatrix; //!< 2-D buffer + +class HiHistory { + public: + /** + * @brief Output operator for history events + * @param o Output stream + * @param h History class to write contents of + * + * @return std::ostream& Returns new state of stream + */ + friend std::ostream &operator<<(std::ostream &o, const HiHistory &h) { + std::copy(h._events.begin(), h._events.end(), + std::ostream_iterator(o,"; ")); + return (o); + } + + public: + HiHistory() { } + HiHistory(const HiHistory &h) : _events(h._events) { } + virtual ~HiHistory() { } + + inline int size() const { return (_events.size()); } + void add(const std::string &event) { _events.push_back(event); } + std::string get(unsigned int index = 0) const { + if (index < _events.size()) { + return (_events[index]); + } + else { + return (std::string("")); + } + } + + void clear() { _events.clear(); } + + PvlKeyword makekey(const std::string &name = "History") const { + PvlKeyword key(name); + for (unsigned int i = 0 ; i < _events.size() ; i++) { + key.AddValue(_events[i]); + } + return (key); + } + + private: + std::vector _events; +}; + +}; +#endif diff --git a/isis/src/mro/apps/hical/HiCalUtil.h b/isis/src/mro/apps/hical/HiCalUtil.h new file mode 100644 index 0000000000000000000000000000000000000000..48365c4e8f2f77fb5d9f9f43f2b1c8a1a558ed39 --- /dev/null +++ b/isis/src/mro/apps/hical/HiCalUtil.h @@ -0,0 +1,476 @@ +#if !defined(HiCalUtil_h) +#define HiCalUtil_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:23 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include + +#include "HiCalTypes.h" +#include "DbProfile.h" +#include "iString.h" +#include "Statistics.h" +#include "PvlKeyword.h" +#include "NumericalApproximation.h" +#include "Filename.h" +#include "Pvl.h" +#include "iException.h" + +namespace Isis { + + template inline T MIN(const T &A, const T &B) { + if ( A < B ) { return (A); } + else { return (B); } + } + + template inline T MAX(const T &A, const T &B) { + if ( A > B ) { return (A); } + else { return (B); } + } + +/** + * @brief Counts number of valid pixels in vector + * @param v Vector to inspect + * @return int Number valid pixels in vector + */ +inline int ValidCount(const HiVector &v) { + int n = 0; + for (int i = 0 ; i < v.dim() ; i++) { + if (!IsSpecial(v[i])) n++; + } + return (n); +} + +/** + * @brief Counts number of invalid pixels in vector + * @param v Vector to inspect + * @return int Number invalid (special) pixels in vector + */ +inline int InValidCount(const HiVector &v) { + int n = 0; + for (int i = 0 ; i < v.dim() ; i++) { + if (IsSpecial(v[i])) n++; + } + return (n); +} + +/** + * @brief Convert HiRISE Cpmm number to Ccd number + * + * @param cpmm Cpmm number + */ +inline int CpmmToCcd(int cpmm) { + const int cpmm2ccd[] = {0,1,2,3,12,4,10,11,5,13,6,7,8,9}; + if ( (cpmm < 0) || (cpmm >= (int)(sizeof(cpmm2ccd)/sizeof(int))) ) { + std::string mess = "CpmmToCdd: Bad CpmmNumber (" + iString(cpmm) + ")"; + throw iException::Message(iException::User, mess.c_str(), _FILEINFO_); + } + return (cpmm2ccd[cpmm]); +} + + +/** + * @brief Convert HiRISE Ccd number to string filter name + * + * @param ccd Ccd number of device + */ +inline std::string CcdToFilter(int ccd) { + if ( (ccd < 0) || (ccd > 13) ) { + std::string mess = "CcdToFilter: Bad Ccd Number (" + iString(ccd) + ")"; + throw iException::Message(iException::User, mess.c_str(), _FILEINFO_); + } + + std::string filter; + if ( ccd <= 9 ) { filter = "RED"; } + else if (ccd <= 11) { filter = "IR"; } + else { filter = "BG"; } + return (filter); +} + +/** + * @brief Crop specified lines from a buffer + * + * This function extracts lines from a buffer and returns a new buffer with the + * extracted lines. + * + * @param m Buffer to extract lines from + * @param sline Starting line number (first line is 0) + * @param eline Last line to extract + * + * @return HiMatrix Buffer containing cropped lines + */ +inline HiMatrix cropLines(const HiMatrix &m, int sline, int eline) { + int nlines(eline-sline+1); + HiMatrix mcrop(nlines, m.dim2()); + for (int l = 0 ; l < nlines ; l++) { + for (int s = 0 ; s < m.dim2() ; s++) { + mcrop[l][s] = m[l+sline][s]; + } + } + return (mcrop); +} + +/** + * @brief Crop specified samples from a buffer + * + * This function extracts samples from a buffer and returns a new buffer with + * the extracted samples. + * + * @param m Buffer to extract samples from + * @param ssamp Startling sample (first sample 0) + * @param esamp Ending sample to extract + * + * @return HiMatrix Buffer with cropped samples + */ +inline HiMatrix cropSamples(const HiMatrix &m, int ssamp, int esamp) { + int nsamps(esamp-ssamp+1); + HiMatrix mcrop(m.dim1(), nsamps); + for (int l = 0 ; l < m.dim1() ; l++) { + for (int s = 0 ; s < nsamps ; s++) { + mcrop[l][s] = m[l][s+ssamp]; + } + } + return (mcrop); +} + +/** + * @brief Reduces by averaging specified lines from a buffer + * + * This function produces a vector from a 2-D buffer of averaged lines at each + * vertical sample location + * + * @param m Buffer to reduce + * @param sline Starting line number (first line is 0) + * @param eline Last line to average (-1 means use all lines) + * + * @return HiVector Buffer containing averaged lines + */ +inline HiVector averageLines(const HiMatrix &m, int sline = 0, int eline = -1) { + eline = (eline == -1) ? m.dim1() - 1 : eline; + HiVector v(m.dim2()); + for (int s = 0 ; s < m.dim2() ; s++) { + Statistics stats; + for (int l = sline ; l <= eline ; l++) { + stats.AddData(&m[l][s], 1); + } + v[s] = stats.Average(); + } + return (v); +} + +/** + * @brief Reduces by averaging specified samples from a buffer + * + * This function produces a vector from a 2-D buffer of averaged samples at each + * horizontal line location + * + * @param m Buffer to reduce + * @param ssamp Starting sample number (first sample is 0) + * @param esamp Last sample to average (-1 means use all samples) + * + * @return HiVector Buffer containing averaged samples + */ +inline HiVector averageSamples(const HiMatrix &m, int ssamp = 0, + int esamp = -1) { + esamp = (esamp == -1) ? m.dim2() - 1 : esamp; + HiVector v(m.dim1()); + for (int l = 0 ; l < m.dim1() ; l++) { + Statistics stats; + for (int s = ssamp ; s <= esamp ; s++) { + stats.AddData(&m[l][s], 1); + } + v[l] = stats.Average(); + } + return (v); +} + +/** + * @brief Find a keyword in a profile using default for non-existant keywords + * + * This template function will extract keyword values from a profile and provide + * the values at the indicated index. If the keyword does not exist or the + * indicated value at index, the provided default will be used instead. + * + */ +template + T ConfKey(const DbProfile &conf, const std::string &keyname, const T &defval, + int index = 0) { + if (!conf.exists(keyname)) { return (defval); } + if (conf.count(keyname) < index) { return (defval); } + iString iValue(conf.value(keyname, index)); + T value = iValue; // This makes it work with a string? + return (value); +} + +/** + * @brief Helper function to convert values to Integers + * + * @param T Type of value to convert + * @param value Value to convert + * + * @return int Converted value + */ +template int ToInteger(const T &value) { + return (iString(value).Trim(" \r\t\n").ToInteger()); +} + +/** + * @brief Helper function to convert values to doubles + * + * @param T Type of value to convert + * @param value Value to convert + * + * @return double Converted value + */ +template double ToDouble(const T &value) { + return (iString(value).Trim(" \r\t\n").ToDouble()); +} + +/** + * @brief Helper function to convert values to strings + * + * @param T Type of value to convert + * @param value Value to convert + * + * @return string Converted value + */ +template std::string ToString(const T &value) { + return (iString(value).Trim(" \r\t\n")); +} + +/** + * @brief Shortened string equality test + * + * @param v1 First value + * @param v2 Second value + * + * @return bool True if they are equal w/o regard to case + */ +inline bool IsEqual(const std::string &v1, const std::string &v2 = "TRUE") { + return (iString::UpCase(v1) == iString::UpCase(v2)); +} + +/** + * @brief Determines if the keyword value is the expected value + * + * This function checks the existance of a keyword in a profile, extracts the + * first value and tests it for equivelance to the expected value. Note this + * test is case insensitive. + * + * @param prof Profile to find the expected keyword in + * @param key Name of keyword in profile to test + * @param value Value to test for in keyword + * + * @return bool Returns true only if the keyword exists in the profile and it is + * the value expected. + */ +inline bool IsTrueValue(const DbProfile &prof, const std::string &key, + const std::string &value = "TRUE") { + if ( prof.exists(key) ) { + return (IsEqual(prof(key), value)); + } + return (false); +} + +/** + * @brief Checks profile flag to skip the current Module + * + * This function looks for the keyword \b Debug::SkipModule and checks its + * value. True is returned if the value is TRUE (case insensentive). + * + * @param prof Module profile from config file + * + * @return bool True if the value of the Debug::SkipModule keyword is TRUE, + * otherwise it returns false for all other values. + */ +inline bool SkipModule(const DbProfile &prof) { + return (IsTrueValue(prof, "Debug::SkipModule", "TRUE")); +} + + +inline HiMatrix appendLines(const HiMatrix &top, const HiMatrix &bottom) { + // Ensure same number samples + if (top.dim2() != bottom.dim2()) { + std::ostringstream mess; + mess << "Top buffer samples (" << top.dim2() + << ") do not match bottom buffer samples (" << bottom.dim2() + << ")"; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + int nlines(top.dim1()+bottom.dim1()); + HiMatrix mat(nlines, top.dim2()); + for (int lt = 0 ; lt < top.dim1() ; lt++) { + for (int s = 0 ; s < top.dim2() ; s++) { + mat[lt][s] = top[lt][s]; + } + } + + int topl = top.dim1(); + for (int lb = 0 ; lb < bottom.dim1() ; lb++) { + for (int s = 0 ; s < top.dim2() ; s++) { + mat[topl+lb][s] = bottom[lb][s]; + } + } + return (mat); +} + +inline HiMatrix appendSamples(const HiMatrix &left, const HiMatrix &right) { + // Ensure same number samples + if (right.dim1() != right.dim1()) { + std::ostringstream mess; + mess << "Left buffer lines (" << left.dim1() + << ") do not match right buffer lines (" << right.dim1() + << ")"; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + int nsamps(left.dim2()+right.dim2()); + HiMatrix mat(left.dim1(), nsamps); + for (int ll = 0 ; ll < left.dim1() ; ll++) { + for (int s = 0 ; s < left.dim2() ; s++) { + mat[ll][s] = left[ll][s]; + } + } + + int lefts = left.dim2(); + for (int lr = 0 ; lr < right.dim1() ; lr++) { + for (int s = 0 ; s < right.dim2() ; s++) { + mat[lr][lefts+s] = right[lr][s]; + } + } + return (mat); +} + +/** + * @brief Compute HiRISE line times + * + * This class will compute the time (in seconds) for a HiRISE observation line + * based upon the binning mode and line number. It is assumed that the first + * line will be time 0, but that is up to the caller to keep that straight. + */ +class HiLineTimeEqn { + public: + HiLineTimeEqn() : _bin(1), _ltime(1.0) { } + HiLineTimeEqn(int bin, double ltime) : _bin(bin), _ltime(ltime) { } + virtual ~HiLineTimeEqn() { } + + void setLineTime(double ltime) { _ltime = ltime; } + void setBin(int bin) { _bin = bin; } + double Time(const double line) const { + return (line * (_bin * _ltime * 1.0E-6)); + } + double operator()(const double line) const { return (Time(line)); } + + private: + double _bin; + double _ltime; +}; + +/** + * @brief Implements (classic) HiRISE temperature equation + * + * This function computes the dark current temperature and returns the results + * in electrons/sec/pixel. + * + * @param temperature Temperature (typically of the FPGA) + * @param napcm2 Dark current for silicone diodes (nano-ampres/cm^2) + * @param px Pixel size in microns + * + * @return double Dark current temperature (electrons/sec/pixel) + */ +inline double HiTempEqn(const double temperature, const double napcm2 = 2.0, + const double px = 12.0) { + double temp = temperature + 273.0; + double eg = 1.1557 - (7.021E-4 * temp * temp) / (1108.0 + temp); + const double K = 1.38E-23; + const double Q = 1.6E-19; + return (napcm2*(px*px)*2.55E7*std::pow(temp,1.5)*std::exp(-eg*Q/2.0/K/temp)); +} + +/** + * @brief Rebins a vector to a different size + * + * This function can rebin to both larger and smaller sizes. It fits the data + * to a cubic spline and then computes the value at the rebin pixel index. One + * advantage to this approach is that on input, special pixels are ignored - on + * output there will never be special pixels unless there are not enough points + * to conpute the cubic spline on which case this function throws an exception. + * + * @param v Input vector to rebin + * @param n Size of the new output vector + * + * @return HiVector + * @history 2008-11-05 Jeannie Walldren Replaced references to + * DataInterp class with NumericalApproximation. + */ +inline HiVector rebin(const HiVector &v, int n) { + if ( n == v.dim() ) { return (v); } + NumericalApproximation nterp(NumericalApproximation::CubicNatural); + double mag((double) v.dim()/ (double) n); + + for ( int i = 0 ; i < v.dim() ; i++ ) { + double x((double) i); + if ( !IsSpecial(v[i]) ) { + nterp.AddData(x,v[i]); + } + } + + // Compute the spline and fill the output vector + HiVector vout(n); + for ( int j = 0 ; j < n ; j++ ) { + double x = (double) j * mag; + vout[j] = nterp.Evaluate(x, NumericalApproximation::NearestEndpoint); + } + return (vout); +} + +/** + * @brief Deletes HiRISE specific BLOBS from cube file + * + * Ths function removes only the HiRISE specific + * + * @param label Input label associated with file from which to remove the HiRISE + * blobs + */ +inline void RemoveHiBlobs(Pvl &label) { + for ( int blob = 0 ; blob < label.Objects() ; blob++ ) { + if ( label.Object(blob).IsNamed("Table") ) { + std::string name = label.Object(blob)["Name"][0]; + if ( iString::Equal(name,"HiRISE Calibration Ancillary") || + iString::Equal(name,"HiRISE Calibration Image") || + iString::Equal(name,"HiRISE Ancillary") ) { + label.DeleteObject(blob); + blob--; + } + } + } + return; +} + + +}; // namespace Isis +#endif diff --git a/isis/src/mro/apps/hical/LowPassFilterComp.h b/isis/src/mro/apps/hical/LowPassFilterComp.h new file mode 100644 index 0000000000000000000000000000000000000000..6d8d376ac0174cb324e2692a317aa232a9ddfcf9 --- /dev/null +++ b/isis/src/mro/apps/hical/LowPassFilterComp.h @@ -0,0 +1,110 @@ +#if !defined(LowPassFilterComp_h) +#define LowPassFilterComp_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:23 $ + * $Id: LowPassFilterComp.h,v 1.1 2009/09/16 03:37:23 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "iString.h" +#include "HiCalUtil.h" +#include "Component.h" +#include "QuickFilter.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Compute a low pass filter from a Component class content + * + * @ingroup Utility + * + * @author 2007-10-09 Kris Becker + */ + class LowPassFilterComp : public Component { + + public: + // Constructors and Destructor + LowPassFilterComp() : Component("LowPassFilter"), _width(3), + _iterations(1) { } + LowPassFilterComp(int width, int iterations = 1) : + Component("LowPassFilter"), _width(width), _iterations(iterations) { } + + LowPassFilterComp(const Component &c, int width = 3, int iterations = 1) : + Component("LowPassFilter", c), _width(width), + _iterations(iterations) { + _data = filterIterator(c.ref(), _width, _iterations); + _history.add(formHistory()); + } + + LowPassFilterComp(const HiVector &v, const HiHistory &h, + int width = 3, int iterations = 1) : + Component("LowPassFilter", h), _width(width), + _iterations(iterations) { + _data = filterIterator(v, _width, _iterations); + _history.add(formHistory()); + } + + /** Destructor */ + virtual ~LowPassFilterComp() { } + + void Process(const HiVector &v) { + _data = filterIterator(v, _width, _iterations); + _history.clear(); + _history.add(formHistory()); + } + + inline int Width() const { return (_width); } + + private: + int _width; //!< Filter width + int _iterations; // Number iterations to apply filter + + std::string formHistory() { + return (std::string("LowPassFilter(Width[" + ToString(_width) + + "],Iters["+ToString(_iterations)+"])")); + } + + HiVector filterIterator(const HiVector &v, int width, int iterations) { + HiVector vout(v.copy()); + for (int i = 0 ; i < iterations; i++) { + vout = filter(vout,width); + } + return (vout); + } + + HiVector filter(const HiVector &v, int width) { + QuickFilter lowpass(v.dim(), width, 1); + lowpass.AddLine(&v[0]); + HiVector vout(v.dim()); + for (int i = 0 ; i < v.dim() ; i ++) { + vout[i] = lowpass.Average(i); + } + return (vout); + } + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hical/Makefile b/isis/src/mro/apps/hical/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9b949b0e2916aca85db9b5c63c4d595dbbe34b68 --- /dev/null +++ b/isis/src/mro/apps/hical/Makefile @@ -0,0 +1,7 @@ +SRCS = hical.cpp HiCalConf.cpp NonLinearLSQ.cpp DriftCorrect.cpp +OBJS = $(SRCS:%.cpp=%.o) +BINS = hical + +include $(ISISROOT)/make/isismake.apps + + diff --git a/isis/src/mro/apps/hical/Makefile.snapshot b/isis/src/mro/apps/hical/Makefile.snapshot new file mode 100644 index 0000000000000000000000000000000000000000..f3d8879849d37b83d0375fbebbbb0ade7e5f7c5b --- /dev/null +++ b/isis/src/mro/apps/hical/Makefile.snapshot @@ -0,0 +1,51 @@ +include $(ISISROOT)/make/isismake.macros + +RM = rm -rf + +STAGE := hical_stage +CVS3 := cvs -d :ext:$(USER)@blackflag:/usgs/cpkgs/isis3/cvs +REPLACE := $(PWD)/tools/replacetxt +TARGETS := $(shell find . -name '*.h' -exec fgrep -l hicalbeta {} \;) \ + $(shell find . -name '*.cpp' -exec fgrep -l -i hicalbeta {} \;) \ + $(shell find . -name Makefile -exec fgrep -l -i hicalbeta {} \;) \ + $(shell find . -name '*.conf' -exec fgrep -l -i hicalbeta {} \;) \ + $(shell find . -name '*.xml' -exec fgrep -l -i hicalbeta {} \;) +BETAS := $(filter %.xml %.conf, $(TARGETS)) + +.SUFFIXES: +.PHONY: +.PHONY: snapshot clone targets $(TARGETS) betas $(BETAS) rename clean + +snapshot: export clone rename + +export: + @echo "Exporting hicalbeta to $(STAGE)..." + $(RM) $(STAGE) + $(CVS3) export -D now -d $(STAGE) isis/src/mro/apps/hicalbeta + $(RSYNC) -av $(STAGE)/ . + $(RM) $(STAGE) + + +clone: + @echo "Cloning designated targets AND betas..." + $(MAKE) -f Makefile.snapshot targets betas + +rename: hicalbeta.cpp hicalbeta.xml + $(MV) hicalbeta.cpp hical.cpp + $(MV) hicalbeta.xml hical.xml + $(MV) assets/hicalbeta.XXXX.conf assets/hical.XXXX.conf + +targets: $(TARGETS) + +betas: $(BETAS) + +$(TARGETS):: + @echo "Converting hicalbeta to hical in $@..." + $(REPLACE) hicalbeta hical $@ + +$(BETAS):: + @echo "Converting /beta/ to / in $@..." + $(REPLACE) '/beta/' '/' $@ + +clean: + $(RM) $(STAGE) $(shell find . -name '*.bak') diff --git a/isis/src/mro/apps/hical/NonLinearLSQ.cpp b/isis/src/mro/apps/hical/NonLinearLSQ.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6295814db5142c064e8668d65564bf1c3c23d943 --- /dev/null +++ b/isis/src/mro/apps/hical/NonLinearLSQ.cpp @@ -0,0 +1,213 @@ +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:23 $ + * $Id: NonLinearLSQ.cpp,v 1.1 2009/09/16 03:37:23 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "NonLinearLSQ.h" +#include "iException.h" + +using namespace std; + +namespace Isis { + + +int NonLinearLSQ::curvefit() { + + size_t n(nSize()); + size_t p(nParms()); + + // Initialize the solver function information + _nlsqPointer d = { this }; + gsl_multifit_function_fdf mf; + mf.f = &f; + mf.df = &df; + mf.fdf = &fdf; + mf.n = n; + mf.p = p; + mf.params = &d; + + const gsl_multifit_fdfsolver_type *T = gsl_multifit_fdfsolver_lmsder; + gsl_multifit_fdfsolver *s = gsl_multifit_fdfsolver_alloc(T, n, p); + + _fitParms = guess(); + gsl_vector *x = NlsqTogsl(_fitParms); + gsl_matrix *covar = gsl_matrix_alloc(p, p); + gsl_multifit_fdfsolver_set(s, &mf, x); + + _nIters = 0; + checkIteration(_nIters, gslToNlsq(s->x), NLVector(p,999.0), + gsl_blas_dnrm2(s->f), GSL_CONTINUE); + + + do { + _nIters++; + + _status = gsl_multifit_fdfsolver_iterate(s); + _fitParms = gslToNlsq(s->x); + + gsl_multifit_covar(s->J, 0.0, covar); + _uncert = getUncertainty(covar); + + _status = checkIteration(_nIters, _fitParms, _uncert, gsl_blas_dnrm2(s->f), + _status); + if ( _status ) { break; } + if(!doContinue()) { break; } + + _status = gsl_multifit_test_delta(s->dx, s->x, absErr(), relErr()); + } while ((_status == GSL_CONTINUE) && (_nIters < _maxIters)); + + // Clean up + gsl_multifit_fdfsolver_free(s); + gsl_matrix_free(covar); + + return (_status); +} + + +void NonLinearLSQ::Terminate(const std::string &message) { + _userMessage = message; + _userTerminated = true; + _status = GSL_SUCCESS; + return; +} + +void NonLinearLSQ::Abort(const std::string &reason) { + _userMessage = reason; + _userTerminated = true; + _status = GSL_FAILURE; + return; +} + + +int NonLinearLSQ::f(const gsl_vector *x, void *params, gsl_vector *fx) { + NonLinearLSQ *nlsq = (static_cast<_nlsqPointer *> (params))->nlsq; + int n = nlsq->nSize(); + NLVector fxv = nlsq->f_x(nlsq->gslToNlsq(x)); + for (int i = 0 ; i < n ; i++ ) { + gsl_vector_set(fx, i, fxv[i]); + } + return (GSL_SUCCESS); +} + +int NonLinearLSQ::df(const gsl_vector *x, void *params, gsl_matrix *J) { + NonLinearLSQ *nlsq = (static_cast<_nlsqPointer *> (params))->nlsq; + int n = nlsq->nSize(); + int p = nlsq->nParms(); + + NLMatrix m = nlsq->df_x(nlsq->gslToNlsq(x)); + + for (int i = 0 ; i < n ; i++ ) { + for (int j = 0 ; j < p ; j++ ) { + gsl_matrix_set(J, i, j, m[i][j]); + } + } + return (GSL_SUCCESS); +} + +int NonLinearLSQ::fdf(const gsl_vector *x, void *params, gsl_vector *fx, + gsl_matrix *J) { + f(x,params,fx); + df(x,params,J); + return (GSL_SUCCESS); +} + + +NonLinearLSQ::NLVector NonLinearLSQ::getUncertainty(const gsl_matrix *covar) + const { + NLVector unc(covar->size1); + for (size_t i = 0 ; i < covar->size1 ; i++ ) { + unc[i] = sqrt(gsl_matrix_get(covar, i, i)); + } + return (unc); +} + +NonLinearLSQ::NLVector NonLinearLSQ::gslToNlsq(const gsl_vector *v) const { + size_t n = v->size; + NLVector Nv(n); + for (size_t i = 0 ; i < n ; i++) { + Nv[i] = gsl_vector_get(v, i); + } + return (Nv); +} + +NonLinearLSQ::NLMatrix NonLinearLSQ::gslToNlsq(const gsl_matrix *m) const { + size_t nrows = m->size1; + size_t ncols = m->size2; + NLMatrix Nm(nrows, ncols); + for (size_t i = 0 ; i < nrows ; i++) { + for (size_t j = 0 ; j < ncols ; j++) { + Nm[i][j] = gsl_matrix_get(m,i,j); + } + } + return (Nm); +} + +gsl_vector *NonLinearLSQ::NlsqTogsl(const NonLinearLSQ::NLVector &v, + gsl_vector *gv) const { + if (gv == 0) { + gv = gsl_vector_alloc(v.dim()); + } + else if (gv->size != (size_t) v.dim()) { + ostringstream mess; + mess << "Size of NL vector (" << v.dim() << ") not same as GSL vector (" + << gv->size << ")"; + throw iException::Message(iException::Programmer, mess.str(), _FILEINFO_); + } + + for (int i = 0 ; i < v.dim() ; i++) { + gsl_vector_set(gv, i, v[i]); + } + return (gv); +} + +gsl_matrix *NonLinearLSQ::NlsqTogsl(const NonLinearLSQ::NLMatrix &m, + gsl_matrix *gm) const { + if (gm == 0) { + gm = gsl_matrix_alloc(m.dim1(), m.dim2()); + } + else if ((gm->size1 != (size_t) m.dim1()) && + (gm->size2 != (size_t) m.dim2()) ) { + ostringstream mess; + mess << "Size of NL matrix (" << m.dim1() << "," << m.dim2() + << ") not same as GSL matrix (" << gm->size1 << "," << gm->size2 + << ")"; + throw iException::Message(iException::Programmer, mess.str(), _FILEINFO_); + } + + for (int i = 0 ; i < m.dim1() ; i++) { + for (int j = 0 ; j < m.dim2() ; j++) { + gsl_matrix_set(gm, i, j, m[i][j]); + } + } + return (gm); +} + +} // namespace ISIS diff --git a/isis/src/mro/apps/hical/NonLinearLSQ.h b/isis/src/mro/apps/hical/NonLinearLSQ.h new file mode 100644 index 0000000000000000000000000000000000000000..7e01928727007ca2b140e972d1f10b817dc438d3 --- /dev/null +++ b/isis/src/mro/apps/hical/NonLinearLSQ.h @@ -0,0 +1,148 @@ +#if !defined(NonLinearLSQ_h) +#define NonLinearLSQ_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:23 $ + * $Id: NonLinearLSQ.h,v 1.1 2009/09/16 03:37:23 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include + +#include "tnt_array1d.h" +#include "tnt_array1d_utils.h" +#include "tnt_array2d.h" +#include "tnt_array2d_utils.h" + +#include +#include +#include +#include + +#include "iException.h" + +namespace Isis { + + /** + * @brief NonLinearLSQ Computes a fit using a Levenberg-Marquardt algorithm + * + * This virtual base class uses the GSL toolkit to apply the + * Levenberg-Marquardt algorithm to fit data to a non-linear equation using + * least squares. + * + * @ingroup Utility + * @author 2007-11-15 Kris Becker + */ + class NonLinearLSQ { + public: + typedef TNT::Array1D NLVector; + typedef TNT::Array2D NLMatrix; + + // Constructors and Destructor + NonLinearLSQ() : _fitParms(), _uncert(), _nIters(0), _maxIters(50), + _status(0), _userTerminated(false), _userMessage() {} + + /** Destructor */ + virtual ~NonLinearLSQ() { } + + virtual int nSize() const = 0; + virtual int nParms() const = 0; + + /** + * @brief Sets the maximum number of iterations + * + * @param m User provides the maximum number iterations + */ + void setMaxIters(int m) { _maxIters = m; } + + /** + * @brief Maximum number iterations for valid solution + * + * + * @return int Maximum resolutions + */ + int maxIters() const { return (_maxIters); } + + virtual NLVector guess() = 0; + virtual NLVector f_x(const NLVector &x) = 0; + virtual NLMatrix df_x(const NLVector &x) = 0; + + virtual double absErr() const { return (1.0E-4); } + virtual double relErr() const { return (1.0E-4); } + + int curvefit(); + inline int status() const { return (_status); } + inline bool success() const { return (_status == GSL_SUCCESS); } + inline bool success(int status) const { return (status == GSL_SUCCESS); } + inline std::string statusstr() const { + return (std::string(gsl_strerror(_status))); + } + inline std::string statusstr(int status) const { + return (std::string(gsl_strerror(status))); + } + + virtual int checkIteration(const int Iter, const NLVector &fitcoefs, + const NLVector &uncerts, double cplxconj, + int Istatus) { + return (Istatus); + } + + inline NLVector coefs() const { return (_fitParms); } + inline NLVector uncert() const { return (_uncert); } + inline int nIterations() const { return (_nIters); } + + protected: + void Terminate(const std::string &message = ""); + void Abort(const std::string &reason = ""); + + bool doContinue() const { return (!_userTerminated); } + + + private: + NLVector _fitParms; + NLVector _uncert; + int _nIters; + int _maxIters; + int _status; + bool _userTerminated; + std::string _userMessage; + + struct _nlsqPointer { + NonLinearLSQ *nlsq; + }; + static int f(const gsl_vector *x, void *params, gsl_vector *fx); + static int df(const gsl_vector *x, void *params, gsl_matrix *J); + static int fdf(const gsl_vector *x, void *params, gsl_vector *fx, + gsl_matrix *J); + + NLVector gslToNlsq(const gsl_vector *v) const; + NLMatrix gslToNlsq(const gsl_matrix *m) const; + gsl_vector *NlsqTogsl(const NLVector &v, gsl_vector *gv = 0) const; + gsl_matrix *NlsqTogsl(const NLMatrix &m, gsl_matrix *gm = 0) const; + NLVector getUncertainty(const gsl_matrix *m) const; + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hical/OffsetCorrect.h b/isis/src/mro/apps/hical/OffsetCorrect.h new file mode 100644 index 0000000000000000000000000000000000000000..39405784312106743800e0f878cc2588c796c799 --- /dev/null +++ b/isis/src/mro/apps/hical/OffsetCorrect.h @@ -0,0 +1,180 @@ +#if !defined(OffsetCorrect_h) +#define OffsetCorrect_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:23 $ + * $Id: OffsetCorrect.h,v 1.1 2009/09/16 03:37:23 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include + + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "Component.h" +#include "SplineFillComp.h" +#include "LowPassFilterComp.h" +#include "Statistics.h" +#include "SpecialPixel.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Loads and processes Reverse Clock calibration data + * + * This class loads and processes the Reverse Clock data from a HiRISE image + * for offset correction purposes. Additional processing may occur in + * subsequent modules. + * + * This module implements th Zz module. + * + * @ingroup Utility + * + * @author 2008-06-13 Kris Becker + */ + class OffsetCorrect : public Component { + + public: + // Constructors and Destructor + OffsetCorrect() : Component("OffsetCorrect") { } + OffsetCorrect(HiCalData &cal, const HiCalConf &conf) : + Component("OffsetCorrect") { + init(cal, conf); + } + + /** Destructor */ + virtual ~OffsetCorrect() { } + + /** + * @brief Return statistics for raw Reverse Clock buffer + * + * @return const Statistics& Statistics class with all stats + */ + const Statistics &Stats() const { return (_stats); } + + /** + * @brief Specifies if the input trigger conditions were met + * + * If trigger conditions where met, the reverse clock correction becomes a + * constant as opposed to processed reverse cloc pixels. + * + * @return bool True if triggered, false otherwise + */ + bool wasTriggered() const { return (_triggered); } + + private: + HiVector _revClock; + Statistics _stats; + bool _triggered; + + + void init(HiCalData &cal, const HiCalConf &conf) { + DbProfile prof = conf.getMatrixProfile(); + _history.clear(); + _history.add("Profile["+ prof.Name()+"]"); + + int line0 = ConfKey(prof,"ZzFirstLine",0); + int lineN = ConfKey(prof,"ZzLastLine",19); + std::string tfile= conf.getMatrixSource("ReverseClockStatistics",prof); + + HiMatrix revclk = cropLines(cal.getReverseClock(), line0, lineN); + _stats.Reset(); + _stats.AddData(revclk[0], revclk.dim1()*revclk.dim2()); + + _revClock = averageLines(revclk); + _history.add("RevClock(CropLines["+ToString(line0)+","+ToString(lineN) + + "],Mean["+ToString(_stats.Average()) + + "],StdDev["+ToString(_stats.StandardDeviation()) + + "],LisPixels["+ToString(_stats.LisPixels())+ + "],HisPixels["+ToString(_stats.HisPixels()) + + "],NulPixels["+ToString(_stats.NullPixels())+ "])"); + + DbAccess triggers(Pvl(tfile).FindObject("ReverseClockStatistics")); + std::string tprofName = conf.resolve("{FILTER}{CCD}_{CHANNEL}_{BIN}",prof); + _history.add("ReverseClockStatistics(File["+tfile+ + "],Profile["+tprofName+"])"); + + _triggered= false; + if (triggers.profileExists(tprofName)) { + DbProfile tprof(prof, triggers.getProfile(tprofName), tprofName); + double revmean = ConfKey(tprof,"RevMeanTrigger", _stats.Average()); + double revstddev = ConfKey(tprof,"RevStdDevTrigger", DBL_MAX); + int lisTol = ConfKey(tprof, "RevLisTolerance", 1); + int hisTol = ConfKey(tprof, "RevHisTolerance", 1); + int nulTol = ConfKey(tprof, "RevNulTolerance", 1); + + _history.add("TriggerLimits(RevMeanTrigger["+ToString(revmean) + + "],RevStdDevTrigger["+ToString(revstddev)+ + "],RevLisTolerance["+ToString(lisTol)+ + "],RevHisTolerance["+ToString(hisTol)+ + "],RevNulTolerance["+ToString(nulTol)+ "])"); + + if ((_stats.LisPixels() > lisTol) || (_stats.HisPixels() > hisTol) || + (_stats.NullPixels() > nulTol) || + (_stats.StandardDeviation() > revstddev)) { + _triggered = true; + _data = HiVector(_revClock.dim1(), revmean); + _history.add("Trigger(True - Reverse Clock set to constant," + "ReverseClock["+ToString(revmean)+"])"); + } + else { + _history.add("Trigger(False - Reverse Clock processing invoked)"); + _triggered = false; + } + } + else { + _history.add("Trigger(Profile["+tprofName+"],NotFound!)"); + _triggered = false; + } + + if (!_triggered) { + SplineFillComp spline(_revClock, _history); + _data = spline.ref(); + _history = spline.History(); + } + + return; + } + + virtual void printOn(std::ostream &o) const { + o << "# History = " << _history << std::endl; + // Write out the header + o << std::setw(_fmtWidth) << "RevClock" + << std::setw(_fmtWidth+1) << "Applied\n"; + + for (int i = 0 ; i < _data.dim() ; i++) { + o << formatDbl(_revClock[i]) << " " + << formatDbl(_data[i]) << std::endl; + } + return; + } + + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hical/README b/isis/src/mro/apps/hical/README new file mode 100644 index 0000000000000000000000000000000000000000..eaa42b45da7e249976f61601e6aacd48ef0d6c55 --- /dev/null +++ b/isis/src/mro/apps/hical/README @@ -0,0 +1,63 @@ + HiRISE hical Appication + September 15, 2009 + $Revision: 1.2 $ + + +Calibrating HiRISE image data is still currently undergoing active development +due to the complex nature of the instrument and its operating conditions. As +such, the ISIS HiRISE calibration program, hicalbeta, is also evolving. In +order to continue improvements to HiRISE calibration whilst providing a stable, +best order calibration program, the hical program will be a snapshot of the +hicalbeta application. hicalbeta is also distributed with each ISIS release so +both are simultaneously available. + +The hical program that existed prior to this event has completely removed and +will no longer be available. These periodic snapshots of hicalbeta will +replace existing versions of hical from henceforth and until further notice. + +We will continue to actively develop hicalbeta and periodically, when deemed +appropriate by the HiRISE team and ISIS Development team, generate a hicalbeta +snapshot creating a new version of hical. The file, HISTORY, will contain a +log of these events and list files that are affected. + +This action has been taken in order to minimize confusion and provide a stable +HiRISE calibration resource (program). Other applications that are affected +by this action are: + +hiclean +hiclean2 +hipical + +The three above applications have been completely removed from the ISIS system +as of release 3.1.21. They will no longer be maintained or distributed from +this time forward. All HiRISE users should use hical. hicalbeta should be +used ONLY at your own risk! + +The steps to make a hicalbeta clone are: + +1) Check out the hical application from the CVS repository +2) Execute the make file to create the snapshot as such: + make -f Makefile.snapshot snapshot clean +3) Run a check against what has changed to see if anything new needs to be + added. This is done using the cvs command: + cvs3 -nq update + Anything with a ? in front of the name needs to be determined if it should + be added to the hical respository. If so add it with 'cvs3 add '. +4) Commit all changes to CVS with: + cvs3 commit -m "New hical snapshot" + +5) Now as isis3mgr, you must update/copy assets/hical.XXXX.conf to + $ISIS3DATA/mro/calibration ensuring the 'XXXX' is exactly what the last + 'XXXX' in hicalbeta.XXXX.conf is. This makes it consistant with hicalbeta. +6) Then inspect $ISIS3DATA/mro/calibration/matrices/beta for new files or + files with higher version numbers and copy them to + $ISIS3DATA/mro/calibration/matrices. Ensure that any of files that have + 'hicalbeta' in the name are converted to 'hical' as this is what the + snapshot process will rename. + +7) Now rerun the app tests and update accordingly. This will almost always + require updates to the truth files. They should be consistant with any + hicalbeta updates. +8) Update the HISTORY file with changes. + +At this point hical and hicalbeta should produce consistant results. diff --git a/isis/src/mro/apps/hical/SplineFillComp.h b/isis/src/mro/apps/hical/SplineFillComp.h new file mode 100644 index 0000000000000000000000000000000000000000..093b747076f229c8f4012ed6d47aa73f1b1145d7 --- /dev/null +++ b/isis/src/mro/apps/hical/SplineFillComp.h @@ -0,0 +1,117 @@ +#if !defined(SplineFillComp_h) +#define SplineFillComp_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:23 $ + * $Id: SplineFillComp.h,v 1.1 2009/09/16 03:37:23 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "iString.h" +#include "Component.h" +#include "NumericalApproximation.h" +#include "SpecialPixel.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Compute a low pass filter from a Component class content + * + * @ingroup Utility + * + * @author 2007-10-09 Kris Becker + * @history 2008-11-05 Jeannie Walldren Replaced references to + * DataInterp class with NumericalApproximation. + */ + class SplineFillComp : public Component { + + public: + // Constructors and Destructor + SplineFillComp() : Component("SplineFill"), _filled(0) { } + + SplineFillComp(const Component &c) : + Component("SplineFill", c), _filled(0) { + fill(c.ref()); + _history.add(formHistory()); + } + + SplineFillComp(const HiVector &v) : + Component("SplineFill"), _filled(0) { + fill(v); + _history.add(formHistory()); + } + SplineFillComp(const HiVector &v, const HiHistory &h) : + Component("SplineFill", h), _filled(0) { + fill(v); + _history.add(formHistory()); + } + + /** Destructor */ + virtual ~SplineFillComp() { } + + void Process(const HiVector &v) { + fill(v); + _history.clear(); + _history.add(formHistory()); + } + + inline int Filled() const { return (_filled); } + + private: + int _filled; //!< Number values replaced + + std::string formHistory() { + iString cfilled(_filled); + return (std::string("SplineFill(Cubic,Filled[" + cfilled + "])")); + } + + void fill(const HiVector &v) { + NumericalApproximation spline(NumericalApproximation::CubicNatural); + for (int i = 0 ; i < v.dim() ; i++) { + if (!IsSpecial(v[i])) { + spline.AddData(i, v[i]); + } + } + + // Compute the spline and fill missing data + HiVector vout(v.dim()); + _filled = 0; + for (int j = 0 ; j < v.dim() ; j++) { + if (IsSpecial(v[j])) { + vout[j] = spline.Evaluate(j,NumericalApproximation::NearestEndpoint); + _filled++; + } + else { + vout[j] = v[j]; + } + } + + _data = vout; + return; + } + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hical/TempGainCorrect.h b/isis/src/mro/apps/hical/TempGainCorrect.h new file mode 100644 index 0000000000000000000000000000000000000000..9e0c42533a4ba2e7145d305cfadf05d7a88eae34 --- /dev/null +++ b/isis/src/mro/apps/hical/TempGainCorrect.h @@ -0,0 +1,158 @@ +#if !defined(TempGainCorrect_h) +#define TempGainCorrect_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/16 03:37:23 $ + * $Id: TempGainCorrect.h,v 1.1 2009/09/16 03:37:23 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "Component.h" +#include "Filename.h" +#include "CSVReader.h" +#include "Statistics.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Zt Module - Applies temperature-dependant gain correction (column) + * + * This class computes the temperature dependant gain correction. It has a + * comma separated value (CSV) file in the config file parameter + * "FpaTemperatureFactorFile". This file is assumed to contain three columns + * of data: column 0: CCD identifier (Ex: RED0), column 1: FPA factor for + * channel 0, and column 2: FPA factor for channel 1. It should have 14 rows, + * 1 for each HiRISE CCD. + * + * @ingroup Utility + * + * @author 2009-09-14 Kris Becker + */ + class TempGainCorrect : public Component { + + public: + // Constructors and Destructor + TempGainCorrect() : Component("TempGainCorrect") { } + TempGainCorrect(const HiCalConf &conf) : Component("TempGainCorrect") { + init(conf); + } + + /** Destructor */ + virtual ~TempGainCorrect() { } + + private: + std::string _fpaFile; + double _refTemp; // Reference temperature + double _fpaFactor; // Temperature factor + double _baseT; // Base temperature + + void init(const HiCalConf &conf) { + _history.clear(); + DbProfile prof = conf.getMatrixProfile(); + _history.add("Profile["+ prof.Name()+"]"); + + // Get parameters from gainVline coefficients file + _fpaFile = conf.getMatrixSource("FpaTemperatureFactorFile", prof); + _fpaFactor = fetchFactor(_fpaFile, prof); + + // Get temperature parameters + _refTemp = ConfKey(prof, "FpaReferenceTemperature", 21.0); + + double fpa_py_temp = ToDouble(prof("FpaPositiveYTemperature")); + double fpa_my_temp = ToDouble(prof("FpaNegativeYTemperature")); + + + double FPA_temp = (fpa_py_temp+fpa_my_temp) / 2.0; + double _baseT = 1.0 + (_fpaFactor * (FPA_temp - _refTemp)); + + // Create data + int nsamps = ToInteger(prof("Samples")); + _data = HiVector(nsamps, _baseT); + + // History + _history.add("FpaTemperatureFactor[" + ToString(_fpaFactor) + "]"); + _history.add("FpaAverageTemperature[" + ToString(FPA_temp) + "]"); + _history.add("FpaReferenceTemperature[" + ToString(_refTemp) + "]"); + _history.add("Correction[" + ToString(_baseT) + "]"); + return; + } + + double fetchFactor(const std::string &fname, const DbProfile &prof) { + + // Determine file and load characteristics + int skip = ConfKey(prof, "FpaTemperatureFactorSkipLines", 0); + bool header = IsTrueValue(prof, "FpaTemperatureFactorHeader"); + int nSkipped = skip + ((header) ? 1 : 0); + + + // Crack the file + Filename csvfile(fname); + CSVReader csv(csvfile.Expanded(), header, skip); + + // Set row/column targets + std::string ccdId = prof("Filter") + prof("Ccd"); + int channel = ToInteger(prof("Channel")); + + // Find the proper row + for (int i = 0 ; i < csv.rows() ; i++) { + CSVReader::CSVAxis cRow = csv.getRow(i); + iString csvCcdId = cRow[0]; + if (!csvCcdId.empty()) { + if (IsEqual(ccdId, csvCcdId.Trim(" \r\n\t"))) { + iString cfactor = cRow[channel+1]; + if (!cfactor.empty()) { + double factor = cfactor.Trim(" \r\n\t").ToDouble(); + _history.add("LoadCSV("+ fname +",Ccd[" + ToString(ccdId) + + "],Channel[" + ToString(channel) + + "],Skip["+ ToString(skip) + "],Row[" + + ToString(i+1) + "])") ; + return (factor); + } + else { + std::ostringstream mess; + mess << "Bad (empty) value in row " << nSkipped+i+1 + << ", column " << channel+2 + << " in CSV file " << fname; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + } + } + } + + // Did not find the proper row + std::ostringstream mess; + mess << "Cannot find Ccd/Channel (" << ccdId << "/" << channel + << ") match in CSV file " << fname; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hical/assets/DriftCorrect.pro b/isis/src/mro/apps/hical/assets/DriftCorrect.pro new file mode 100644 index 0000000000000000000000000000000000000000..1bade01acb9073eee8486cff1bdb5ef5871b708e --- /dev/null +++ b/isis/src/mro/apps/hical/assets/DriftCorrect.pro @@ -0,0 +1,88 @@ +;driftcorrect.pro Version 10Oct 07 +PRO gauss4, x, a, f, pder +; Implement the function y = a[0] + a[1]*x + a[2] * exp(a[3] * x) +; return the value of the function as f, and the value of +; the partials at the value of x in pder[4]. +; let p0 = exp(a[3]*x) +; dy/da[0] = 1. +; dy/da[1] = x +; dy/da[2] = p0 +; dy/da[3] = a[2] * x * p0 + +nx = n_elements(x) +; Note: the next two lines of code are added/changed +maxLog = 87.0 ;approx log of max finite single FP value +; Note, if you use double throughout, maxLog is around 709. It +; shouldn't matter because normally the term should be < 1. +p0 = double(exp(a[3]*x < maxLog)) +f = a[0] + a[1] * x + a[2] * p0 +if total(finite(f)) ne nx then stop +; Partial of y with respsect to a[i]: +pder = [[ replicate(1., nx)], [x], [p0], [a[2]*x*p0]] +end + +Function DriftCorrect, buffer, info, params, x, STATUS=status +; return the drift correction profile for an image. This is obtained by +; fitting the function y = a[0] + a[1]*x + a[2] * exp(a[3] * x) +; to the mean of the buffer pixels for each line. +; +; Inputs: +; buffer[info.nline] = mean of buffer pixel columns [5:11] for each line of image. +; info = header structure for image +; Outputs: +; params = parameters of function fit to the buffer area [4]. +; Function value = [info.nline] vector of drift values / line. +; Time 0 is defined as the time of the start of the 1st image line. +; x = time vector [info.nline], in seconds. +; STATUS = status of fit. 0 for OK, 1 for ChiSq increasing without +; bounds, 2 for did not converge. +; + +sWidth = 17 ;Width of our smoother +n0 = 20 + (20 + info.tdi) / info.bin ;Image starting line +n = info.nline - n0 ;# of image lines + +if info.nline lt 4000 then begin ;short image? + x = findgen(n) * (info.bin * info.linetime * 1.0e-6) ;time in seconds [n] + cc = poly_fit(x, buffer[n0:*], 1, yfit2) ;just use linear + params = [cc[0], cc[1], 0.0, 1.0] + status = 0 + return, yfit2 +endif + +last = info.nline - info.trim/info.bin - 1 ;Last line to use +b1 = buffer[n0 : last] ;Extract rows we care about +nb = n_elements(b1) +b2 = smooth(b1, sWidth, /EDGE) ;Smooth +x = findgen(nb) * (info.bin * info.linetime * 1.0e-6) ;time in seconds [nb] +xmax = x[nb-1] ;Last time value + +; Fit a straight line to latter half of data for initial estimates +nb2 = nb/2 +cc = poly_fit(x[nb2:*], b2[nb2:*], 1) ;linear fit +resid = b2 - (cc[0] + x * cc[1]) ;residuals + +tail = mean(resid[0.9*nb : *]) ;mean of tail area +head = mean(resid[0:20]) ;mean of start area + + ; fit y = a[0] + a[1]*x + a[2] * exp(a[3] * x) GAUSS4 +a = [cc[0], cc[1], head-tail, -5./xmax] ;Initial guess for params +a0 = a +yfit2 = curvefit(x, b1, replicate(1., nb), a, $ + FUNCTION_NAME="GAUSS4", STATUS=status, ITER=iter, ITMAX=100) +; print, 'ITER = ', iter +if status ne 0 then begin ;Did fit work?? it might not have converged. + print, 'Could not fit, using straight line., status = ', status + print, info.obs_id, ', CCD/CHL ', info.ccd, info.channel + print, 'Initial: ', a0 + print, 'Fit: ', a + cc = poly_fit(x, b1, 1) ;Punt & fit a straight line + a = [cc[0], cc[1], 0.0, -1.0] ;i.e. exp coeff = 0 +endif + +; recalculate x and yfit2 for entire image area +x = findgen(info.nline-n0) * (info.bin * info.linetime * 1.0e-6) ;time in seconds +yfit2 = a[0] + a[1] * x + a[2] * exp(a[3] * x) +params = a ;Return function params. +return, yfit2 +end diff --git a/isis/src/mro/apps/hical/assets/ReverseClockStatistics.XXXX.conf b/isis/src/mro/apps/hical/assets/ReverseClockStatistics.XXXX.conf new file mode 100644 index 0000000000000000000000000000000000000000..e0da6ee34cad5bb9f51b5380e4f6a851423cf5cb --- /dev/null +++ b/isis/src/mro/apps/hical/assets/ReverseClockStatistics.XXXX.conf @@ -0,0 +1,607 @@ +# This file provides statistical triggers for the Reverse Clock region +# while processing the Zz hical module for OffsetCorrection. +# Updates made by EME 03/18/2009 - trigger STD values have been increased for most +# CCD/Channel/Binning combinations. Noise levels should be higher before reverting to +# use of the RevMeanTrigger value. In each profile, the comment line refers to the +# original value. +# +# $Id: ReverseClockStatistics.XXXX.conf,v 1.1 2009/09/16 03:37:23 kbecker Exp $ +#CCD,CHN,BIN,Mean of Reverse Readout Mean,Reverse Readout STD Trigger, +Object = ReverseClockStatistics + ModuleAddendum = "hical::Zz" + Name = "ZzTriggers" + + Group = Profile +#RED0,0,1,1377.437,15.500 + Name = RED0_0_1 + RevMeanTrigger = 1377.437 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED1,0,1,1146.000,20.000 + Name = RED1_0_1 + RevMeanTrigger = 1146.000 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED2,0,1,1297.331,20.000 + Name = RED2_0_1 + RevMeanTrigger = 1297.331 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED3,0,1,1171.321,20.000, + Name = RED3_0_1 + RevMeanTrigger = 1171.321 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED4,0,1,1209.981,20.000, + Name = RED4_0_1 + RevMeanTrigger = 1209.981 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED5,0,1,1267.364,20.000, + Name = RED5_0_1 + RevMeanTrigger = 1267.364 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED6,0,1,1091.817,20.000 + Name = RED6_0_1 + RevMeanTrigger = 1091.817 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED7,0,1,1165.365,20.000, + Name = RED7_0_1 + RevMeanTrigger = 1165.365 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED8,0,1,1379.488,20.000, + Name = RED8_0_1 + RevMeanTrigger = 1379.488 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED9,0,1,1224.398,15.000, + Name = RED9_0_1 + RevMeanTrigger = 1224.398 + RevStdDevTrigger = 50.000 + EndGroup + + + + Group = Profile +#IR10,0,1,1252.294,12.500, + Name = IR10_0_1 + RevMeanTrigger = 1252.294 + RevStdDevTrigger = 50.0 + EndGroup + + + + Group = Profile +#IR11,0,1,1258.578,15.000, + Name = IR11_0_1 + RevMeanTrigger = 1258.578 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG12,0,1,1086.998,15.000, + Name = BG12_0_1 + RevMeanTrigger = 1086.998 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG13,0,1,1133.021,15.000, + Name = BG13_0_1 + RevMeanTrigger = 1133.021 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED0,0,2,1334.809,15.000, + Name = RED0_0_2 + RevMeanTrigger = 1334.809 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED1,0,2,1124.000,20.000 + Name = RED1_0_2 + RevMeanTrigger = 1124.000 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED2,0,2,1249.964,20.000 + Name = RED2_0_2 + RevMeanTrigger = 1249.964 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED3,0,2,1128.152,20.000 + Name = RED3_0_2 + RevMeanTrigger = 1128.152 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED4,0,2,1171.630,20.000 + Name = RED4_0_2 + RevMeanTrigger = 1171.630 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED5,0,2,1224.266,20.000 + Name = RED5_0_2 + RevMeanTrigger = 1224.266 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED6,0,2,1052.319,20.000 + Name = RED6_0_2 + RevMeanTrigger = 1052.319 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED7,0,2,1131.409,20.000 + Name = RED7_0_2 + RevMeanTrigger = 1131.409 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED8,0,2,1334.491,20.000 + Name = RED8_0_2 + RevMeanTrigger = 1334.491 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED9,0,2,1180.286,15.000 + Name = RED9_0_2 + RevMeanTrigger = 1180.286 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#IR10,1,1,1179.370,20.000 + Name = IR10_1_1 + RevMeanTrigger = 1179.370 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#IR11,1,1,1248.003,15.000 + Name = IR11_1_1 + RevMeanTrigger = 1248.003 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG12,1,1,1256.323,15.000 + Name = BG12_1_1 + RevMeanTrigger = 1256.323 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG13,1,1,1103.845,15.000 + Name = BG13_1_1 + RevMeanTrigger = 1103.845 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED0,0,4,1320.622,25.000 + Name = RED0_0_4 + RevMeanTrigger = 1320.622 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED1,0,4,1105.277,30.000 + Name = RED1_0_4 + RevMeanTrigger = 1105.277 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED2,0,4,1237.360,30.000 + Name = RED2_0_4 + RevMeanTrigger = 1237.360 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED3,0,4,1117.122,30.000 + Name = RED3_0_4 + RevMeanTrigger = 1117.122 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED4,0,4,1169.959,30.000 + Name = RED4_0_4 + RevMeanTrigger = 1169.959 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED5,0,4,1222.106,30.000 + Name = RED5_0_4 + RevMeanTrigger = 1222.106 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED6,0,4,1042.101,30.000 + Name = RED6_0_4 + RevMeanTrigger = 1042.101 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED7,0,4,1124.990,30.000 + Name = RED7_0_4 + RevMeanTrigger = 1124.990 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED8,0,4,1320.220,30.000 + Name = RED8_0_4 + RevMeanTrigger = 1320.220 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED9,0,4,1164.266,30.000 + Name = RED9_0_4 + RevMeanTrigger = 1164.266 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#IR10,0,2,1214.563,12.500 + Name = IR10_0_2 + RevMeanTrigger = 1214.563 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#IR11,0,2,1223.046,15.000 + Name = IR11_0_2 + RevMeanTrigger = 1223.046 + RevStdDevTrigger = 50.00 + EndGroup + + Group = Profile +#BG12,0,2,1052.550,15.000 + Name = BG12_0_2 + RevMeanTrigger = 1052.550 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG13,0,2,1107.637,15.000 + Name = BG13_0_2 + RevMeanTrigger = 1107.637 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED0,1,1,1477.663,30.000 + Name = RED0_1_1 + RevMeanTrigger = 1477.663 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED1,1,1,1223.837,20.000 + Name = RED1_1_1 + RevMeanTrigger = 1223.837 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED2,1,1,1204.893,20.000 + Name = RED2_1_1 + RevMeanTrigger = 1204.893 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED3,1,1,1308.787,20.000 + Name = RED3_1_1 + RevMeanTrigger = 1308.787 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED4,1,1,1187.757,20.000 + Name = RED4_1_1 + RevMeanTrigger = 1187.757 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED5,1,1,1470.160,25.000 + Name = RED5_1_1 + RevMeanTrigger = 1470.160 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED6,1,1,1283.151,20.000 + Name = RED6_1_1 + RevMeanTrigger = 1283.151 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED7,1,1,1487.898,20.000 + Name = RED7_1_1 + RevMeanTrigger = 1487.898 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED8,1,1,1501.543,20.000 + Name = RED8_1_1 + RevMeanTrigger = 1501.543 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED9,1,1,1388.820,15.000 + Name = RED9_1_1 + RevMeanTrigger = 1388.820 + RevStdDevTrigger = 60.000 + EndGroup + + Group = Profile +#IR10,1,2,1099.481,20.000 + Name = IR10_1_2 + RevMeanTrigger = 1099.481 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#IR11,1,2,1213.113,15.000 + Name = IR11_1_2 + RevMeanTrigger = 1213.113 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG12,1,2,1222.681,15.000 + Name = BG12_1_2 + RevMeanTrigger = 1222.681 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG13,1,2,1079.180,15.000 + Name = BG13_1_2 + RevMeanTrigger = 1079.180 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED0,1,2,1428.761,20.000 + Name = RED0_1_2 + RevMeanTrigger = 1428.761 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED1,1,2,1182.345,20.000 + Name = RED1_1_2 + RevMeanTrigger = 1182.345 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED2,1,2,1158.733,20.000 + Name = RED2_1_2 + RevMeanTrigger = 1158.733 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED3,1,2,1259.021,20.000 + Name = RED3_1_2 + RevMeanTrigger = 1259.021 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED4,1,2,1148.770,20.000 + Name = RED4_1_2 + RevMeanTrigger = 1148.770 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED5,1,2,1414.494,20.000 + Name = RED5_1_2 + RevMeanTrigger = 1414.494 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED6,1,2,1239.251,20.000 + Name = RED6_1_2 + RevMeanTrigger = 1239.251 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED7,1,2,1434.345,20.000 + Name = RED7_1_2 + RevMeanTrigger = 1434.345 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED8,1,2,1451.082,20.000 + Name = RED8_1_2 + RevMeanTrigger = 1451.082 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED9,1,2,1337.753,15.000 + Name = RED9_1_2 + RevMeanTrigger = 1337.753 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#IR10,0,4,1206.694,22.500 + Name = IR10_0_4 + RevMeanTrigger = 1206.694 + RevStdDevTrigger = 100.0 + EndGroup + + Group = Profile +#IR11,0,4,1216.140,30.000 + Name = IR11_0_4 + RevMeanTrigger = 1216.140 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#BG12,0,4,1045.235,30.000 + Name = BG12_0_4 + RevMeanTrigger = 1045.235 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#BG13,0,4,1097.588,30.000 + Name = BG13_0_4 + RevMeanTrigger = 1097.588 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED0,1,4,1414.764,30.000 + Name = RED0_1_4 + RevMeanTrigger = 1414.764 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED1,1,4,1161.233,30.000 + Name = RED1_1_4 + RevMeanTrigger = 1161.233 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED2,1,4,1147.600,30.000 + Name = RED2_1_4 + RevMeanTrigger = 1147.600 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED3,1,4,1246.268,30.000 + Name = RED3_1_4 + RevMeanTrigger = 1246.268 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED4,1,4,1147.855,30.000 + Name = RED4_1_4 + RevMeanTrigger = 1147.855 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED5,1,4,1399.185,30.000 + Name = RED5_1_4 + RevMeanTrigger = 1399.185 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED6,1,4,1224.519,30.000 + Name = RED6_1_4 + RevMeanTrigger = 1224.519 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED7,1,4,1414.525,30.000 + Name = RED7_1_4 + RevMeanTrigger = 1414.525 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED8,1,4,1436.337,30.000 + Name = RED8_1_4 + RevMeanTrigger = 1436.337 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED9,1,4,1322.071,30.000 + Name = RED9_1_4 + RevMeanTrigger = 1322.071 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#IR10,1,4,1092.773,30.000 + Name = IR10_1_4 + RevMeanTrigger = 1092.773 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#IR11,1,4,1205.192,30.000 + Name = IR11_1_4 + RevMeanTrigger = 1205.192 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#BG12,1,4,1212.918,30.000 + Name = BG12_1_4 + RevMeanTrigger = 1212.918 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#BG13,1,4,1069.859,30.000 + Name = BG13_1_4 + RevMeanTrigger = 1069.859 + RevStdDevTrigger = 100.000 + EndGroup +EndObject + + diff --git a/isis/src/mro/apps/hical/assets/clean6.pro b/isis/src/mro/apps/hical/assets/clean6.pro new file mode 100644 index 0000000000000000000000000000000000000000..d74281318828fae5fe7a80629f0e45c25a97d86a --- /dev/null +++ b/isis/src/mro/apps/hical/assets/clean6.pro @@ -0,0 +1,70 @@ +;clean6.pro +;need the following +;restore, 'c:\hirise\data\dark4\b_matrix_25nov07.sav +; dark current matrices 28 channels of 1024/bin columns by 4 tdi +; +;restore,'c:\hirise\data\dark4\temp_profiles.sav' +; temperature profiles matrices 256 columns by 4 tdi by intercept and slope +; +;History +; 1/5/08 Alan changed image variable from zz to z to use less memory +;10 jan 08 Alan added provision for having no b_matrix +; +function clean6,z,info,b_matrix,t_intercept,t_slope +nc=info.ncol +tdi=info.tdi +case tdi of +128: itdi=0 +64: itdi=1 +32: itdi=2 +8: itdi=3 +endcase +;z=zz ; i preserved original for debugging +; +removemissing, z, bad=fmissing ; get rid of gaps +; +;drift correction + swidth=11 + ave_cols, z, 5, 11, b ;get row means for buffer pixels, cols[5:11] + iccd = info.ccd + ichl = info.channel + l0 = 20 + (20 + info.tdi) / info.bin ;image starting line + b = smooth(b, swidth, /edge) ; need for initial parameters + drift = driftcorrect(b, info, params, x, status=status) ;get drift function +; print,params ;for debugging and watching progress + drift=drift-drift(0) + nl=info.nline + for iline=long(l0),nl-1 do z(*,iline)=z(*,iline)-drift(iline-l0) + ; +;offset correction +ave_lines,z,1,19,offset,sd +for iline=0l,nl-1 do z[0,iline] = z[*,iline]-offset +; +;dc subtraction + w=where(b_matrix.ccd eq info.ccd and $ + b_matrix.ch eq info.channel and $ + b_matrix.tdi eq info.tdi and $ + b_matrix.bin eq info.bin, count) ;finds right dark current matrix +if w(0) eq -1 then print,info.obs_id, ' No b_matrix available used mask' + +temp=(info.fpa_py_temp+info.fpa_my_temp)/2 ;use average baseplate temperature +t_prof=rebin(smooth(t_intercept(*,itdi),3,/edge)+smooth(t_slope(*,itdi),3,/edge)*temp,1024/info.bin);convert to correct number of columns +; i have left the smoothing in for the time being. after testing we can fix it +t_profile=[fltarr(12)+temp,t_prof,fltarr(16)+temp] ;i process all columns as it is useful for diagnostic tests +; +if w(0) ne -1 then dc = b_matrix(w).matrix(0:nc-1) * $ ;b[nc] = dn / px / sec + info.linetime * 1e-6 * $ ;scale by time + info.bin^2 * $ ;bin area + (20*103/89. + info.tdi) * $ ;we're doing 20 masked lines of larger area + tdi area + tempeqn(t_profile, 2, 12) / tempeqn(21, 2, 12) $ ;dc at temp=21c. is the reference + else ave_lines,z,20,20+20/info.bin-1,dc + + + dcs = smooth(dc[12:nc-17],3,/edge) + dc[12:nc-17] = dcs ;replace by smoothed b + + for iline=20l,nl-1 do z[0,iline] = z[*,iline]-dc +;__________________________________________________ +;stop +return,z +end diff --git a/isis/src/mro/apps/hical/assets/hical.XXXX.conf b/isis/src/mro/apps/hical/assets/hical.XXXX.conf new file mode 100644 index 0000000000000000000000000000000000000000..07416d40869d61e0a274c62d89e945f89771234e --- /dev/null +++ b/isis/src/mro/apps/hical/assets/hical.XXXX.conf @@ -0,0 +1,243 @@ +# HiRISE Calibration Matricies configuration file +# See documentation for the hical application on the content and form of +# this file. +# $Id: hical.XXXX.conf,v 1.1 2009/09/16 03:37:24 kbecker Exp $ +Object = Hical + + Program = "hical" + + Name = "HiMatrices" + DefaultProfile = "HiMatrices" + +/* If you want to rerun hical, you must set PropagateTables to True. Use */ +/* this in conjuction with Debug::SkipModule = True option for each module. */ + PropagateTables = False + +/* Define label groups that are loaded for each profile reference */ +/* Note all keywords in these groups become available to all profiles. */ +/* Thus, you can use them in the OptionKeywords and ProfileOptions keywords */ +/* to create very specialized profiles for special needs. */ +/* Specify the FPA reference temperature. It is used in several modules so */ +/* it is specified at the top level */ + + LabelGroups = ( "Dimensions", "Instrument", "Archive") + +/* These keywords are used in ProfileOptions mapping. Note that order and */ +/* case matter! WARNING: You can easily break file lookups if these keys */ +/* are deleted or modified improperly!!! */ + OptionKeywords = ("FILTER", "CCD", "CHANNEL", "TDI", "BIN", "ProductId", + "Program", "Module", "OPATH", "CalOptions") + +/* Additional profile combinations and order load hierarchy. These keywords */ +/* are defined when the LabelGroups are loaded. */ +/* Kris Becker & Eric Eliason updated 10/24/2008 */ +/* ProfileOptions value added: {Module}_{CalOptions} */ + ProfileOptions = ("{FILTER}", "TDI{TDI}", "BIN{BIN}", "TDI{TDI}/BIN{BIN}", + "{FILTER}{CCD}_{CHANNEL}", + "{FILTER}{CCD}_{CHANNEL}/TDI{TDI}/BIN{BIN}", "Debug", + "{Module}_{CalOptions}") + +/* Specify the FPA reference temperature. It is used in several modules so */ +/* it is specified at the top level */ + FpaReferenceTemperature = 21.0 + +/* This profile contains parameters pertinent to processing the buffer */ +/* pixels for subsequent using in the drift correction, Zd module */ + Group = Profile + Name = Zf + Module = Zf + ZfFirstSample = 5 + ZfLastSample = 11 + + ZfFilterWidth = 201 + ZfFilterIterations = 2 + End_Group + +/* This profile contains parameters pertinent to processing drift correction */ + Group = Profile + Name = Zd + Module = Zd + + /* Uncomment to turn off non linear fitting of Zf data and pass it thru */ + ZdSkipFit = True + + /* Uncomment to use linear fitting of Zf data when non-linear fails */ + /* Default is to pass thru filtered Zf data */ + /* ZdOnFailUseLinear = True */ + + /* Minimum number of good lines (NLines - (TrimLines/Summing)) to fit */ + ZdMinimumLines = 250 + + /* Maximum number of iterations for the algorithm to converge and */ + /* other limits */ + MaximumIterations = 100 + MaximumLog = 709.0 + + /* Convergence parameters for Levenberg-Marquardt algorithm */ + /* Equation is solved when |dx_i| < AbsoluteError + RelativeError * |x_i| */ + /* where dx is the last step and x is the current step for each i-th */ + /* value */ + AbsoluteError = 1.0E-4 + RelativeError = 1.0E-4 + + /* Filtering of the guestimate buffer */ + GuessFilterWidth = 17 + GuessFilterIterations = 1 + +# DumpModuleFile = "{ProductId}_{Module}.log" + End_Group + +/* This profile contains parameters pertinent to processing the offset */ + Group = Profile + Name = Zz + Module = Zz + +/* Set calibration parameters for hiclean operations. Indexes are all 0-based */ + ZzFirstLine = 1 + ZzLastLine = 19 + + +/* Reverse Clock trigger Statistics profiles */ + ReverseClockStatistics = "$mro/calibration/matrices/ReverseClockStatistics.????.conf" + RevLisTolerance = 1 + RevHisTolerance = 1 + RevNulTolerance = 1 + End_Group + +/* Skip reverse clock if the ReverseReadoutNoise is to large */ +/* Profile added by Kris Becker & Eric Eliason, 10/25/2008 */ + Group = Profile + Name = Zz_ReverseReadoutNoise + Debug::SkipModule = True + End_Group + +/* This profile contains parameters pertinent to processing dark current. */ +/* Required label keywords: Summing, Tdi, FpaPositiveYTemperature, */ +/* and FpaNegativeYTemperature, Lines */ +/* Also needs LineTime which is computed. */ + Group = Profile + Name = Zb + Module = Zb + +/* Define the B matrix file reference */ + B = "$mro/calibration/matrices/B_TDI{TDI}_BIN{BIN}_hical_????.cub" + SkipLines = 1 + Slope = "$mro/calibration/matrices/t_slope_CH{CHANNEL}_hical_????.csv" + Intercept = "$mro/calibration/matrices/t_intercept_CH{CHANNEL}_hical_????.csv" + + /* Do filtering? */ + ZbFilterWidth = 3 + ZbFilterIterations = 1 + End_Group + +/* This profile contains parameters pertinent to processing gain correction. */ +/* Required label keywords: CpmmNumber, ChannelNumber, Lines */ + Group = Profile + Name = Zg + Module = Zg + +/* As of 2008-06-25, this is the default */ + Debug::SkipModule = True + + SkipLines = 1 +/* Added "_hical" to filename as of 2008-04-02. This is consistant with */ +/* naming convention used for the beta version of hical. */ + GainLineCoefficients = "$mro/calibration/matrices/line_correct_{BIN}_hical_????.csv" + End_Group + +/* This profile contains parameters pertinent to processing gain correction. */ +/* Required label keywords: CpmmNumber, ChannelNumber, Lines */ + Group = Profile + Name = Zgg + Module = Zgg + +/* Define the G matrix file reference */ + G = "$mro/calibration/matrices/G_TDI{TDI}_BIN{BIN}_hical_????.cub" + End_Group + +/* This profile contains parameters pertinent to processing gain correction. */ +/* Required label keywords: CpmmNumber, ChannelNumber, Tdi, Lines */ + Group = Profile + Name = Za + Module = Za + +/* Applies a temperature correction factor to A matrix */ +/*** As of 2009-09-15 this parameter is implemented in the Zt module ***/ +/*** It remains here for backward compatability for now. It will be ***/ +/*** removed at some point in future releases. ***/ + ZaFpaTemperatureFactor = 0.005 + +/* Define the A matrix file reference */ + A = "$mro/calibration/matrices/A_TDI{TDI}_BIN{BIN}_hical_????.cub" + End_Group + +/* This profile contains parameters pertinent to processing */ +/* temperature-dependant gain correction. Formally in Za module. */ +/* Required label keywords: CpmmNumber, ChannelNumber, Samples */ + Group = Profile + Name = Zt + Module = Zt + +/ Define temperature-dependant gain correction CSV file */ + FpaTemperatureFactorSkipLines = 4 + FpaTemperatureFactorHeader = True + FpaTemperatureFactorFile = "$mro/calibration/matrices/FpaTemperatureGain_BIN{BIN}.????.csv" + End_Group + +/* This profile contains parameters pertinent to processing I/F conversion. */ +/* Required label keywords: ScanExposureDuration */ + Group = Profile + Name = Ziof + Module = Ziof + +/* I/F correction for tdi/bin - currently set at 1.0 for all tdi/bin */h +/* combinations. */ + ZiofBinFactor = 1.0 + End_Group + +/* Here are the filter profiles. All keywords that pertain to a filter set */ +/* should be specified here. FilterGainCorrection are I/F corrections in */ +/* units of DN/s. */ + Group = Profile + Name = RED + FilterGainCorrection = 159423899.0 + End_Group + + Group = Profile + Name = IR + FilterGainCorrection = 58018177.0 + End_Group + + Group = Profile + Name = BG + FilterGainCorrection = 108811104.0 + End_Group + + Group = Profile + Name = IR10_1 +# LastGoodLine = 3100 + End_Group + + + Group = Profile + Name = Debug + +/** Current disables writting to label history due to bug in keyword formatter in ISIS **/ +/* The bug has the following error signature: */ +/* terminate called after throwing an instance of 'std::out_of_range' */ +/* what(): basic_string::substr */ +/* Abort */ +/* You must set this to false when this occurs as a workaround and use the */ +/* DumpHistoryFile parameter to see the parameter history. */ + LogParameterHistory = False + +/* Uncomment this line to write parameter history to the ProductId log */ + DumpHistoryFile = "{OPATH}/{ProductId}.{Program}.log" + +/* Uncomment this line to dump Module data for every module when using Debug */ +/* profiling. */ +# DumpModuleFile = "{OPATH}/{ProductId}_{Module}.log" + End_Group + +End_Object + diff --git a/isis/src/mro/apps/hical/assets/line_correction.pro b/isis/src/mro/apps/hical/assets/line_correction.pro new file mode 100644 index 0000000000000000000000000000000000000000..5f0b180737b84f6c0535affb32dcd16b88535b51 --- /dev/null +++ b/isis/src/mro/apps/hical/assets/line_correction.pro @@ -0,0 +1,20 @@ +;line_correction.pro +function line_correction,z,info,line_correct +l=findgen(info.nline) +t=l*info.linetime*1e-6*info.bin +i=info.ccd +k=info.channel +; +case info.bin of +1: ibin=0 +2: ibin=1 +4: ibin=2 +endcase +; +lin_cor=line_correct(i,k,ibin,0)+line_correct(i,k,ibin,1)*t+line_correct(i,k,ibin,2)*exp(line_correct(i,k,ibin,3)*t) +start=20l+(20+info.tdi)/info.bin +nl=info.nline +;stop +for il=start,nl-1 do z(*,il)=z(*,il)/lin_cor(il-start) +return,z +end diff --git a/isis/src/mro/apps/hical/assets/test_mdr_15feb08.pro b/isis/src/mro/apps/hical/assets/test_mdr_15feb08.pro new file mode 100644 index 0000000000000000000000000000000000000000..331b015d501cf641a44ec23c0948b71fda67df1d --- /dev/null +++ b/isis/src/mro/apps/hical/assets/test_mdr_15feb08.pro @@ -0,0 +1,91 @@ +;test_mdr_15feb08.pro +pro test_mdr, obs +; +files=file_search(obs,'*.IMG') +nf=n_elements(files) + mode_bin=intarr(14,2) + mode_tdi=intarr(14,2) + n_lines=lonarr(14,2) + w_times=fltarr(14,2) +; +t0=systime(1) +; +for j=0,nf-1 do begin + if files(j) ne '' then begin + rheader,files(j),info,0 + iccd=info.ccd & ich=info.channel + bin=info.bin + tdi=info.tdi + start= 20+(20+tdi)/bin + n_lines(iccd,ich)=long(info.nline-start)*bin + w_times(iccd,ich)=time_secs(info.start_time)-time_secs(info.analog_on_time) + mode_bin(iccd,ich)=bin + mode_tdi(iccd,ich)=tdi + endif + endfor +max_lines=max(n_lines) + +center0=fltarr(14,2,max_lines) +overlap=center0 +imagemean= center0 +restore,'c:\hirise_idl\matrices\save\a_matrix_composite_1feb08.sav' +restore,'c:\hirise_idl\matrices\save\b_matrix_2dec07.sav' +restore,'c:\hirise_idl\matrices\save\gain_15feb08.sav' +restore,'c:\hirise_idl\matrices\save\temp_profiles.sav' +restore,'c:\hirise_idl\matrices\save\line_correct_15Feb08A.sav' +ggain=gain +t0=systime(1) +print,systime(1)-t0 +for i= 0,nf-1 do begin + rchannel,files(i),z,info,0 +; if info.luntype ne 0 then print,'lutted image',info.file + if (time_secs(info.start_time)-time_secs(info.analog_on_time)) gt 150 then begin + start=20+(20+info.tdi)/info.bin + nc=info.ncol + ncol=info.ncol + nlines = info.nline + ccd=info.ccd & ch =info.channel & tdi=info.tdi & bin=info.bin + w=where((a_matrix.ccd eq ccd) and (a_matrix.ch eq ch )and a_matrix.tdi eq tdi and a_matrix.bin eq bin) ;& help,w + if w(0) ne -1 then a=1/a_matrix(w).matrix else a=fltarr(1052)+1 + z=clean6(z,info,b_matrix,t_intercept,t_slope) + + z=line_correction(z,info,line_correct) + + FPA_temp=(info.fpa_py_temp+info.fpa_my_temp)/2 + for j=0l,info.nline-1 do z(12,j) =z(12:info.ncol-16-1,j)*a(12:info.ncol-16-1)*(1+0.005*(FPA_temp-21)) + +; print,i,' ccd=',ccd,' ch=',ch,' tdi=',tdi,' bin=',bin,ncol,nlines + + case bin of + 1: ibin=0 + 2: ibin=1 + 4: ibin=2 + 8: ibin=3 + else: stop,'wrong bin number' + endcase + + factor=ggain(info.ccd,info.channel,ibin)*128/tdi/bin^2 ;normalizes gain + nl=info.nline + for il=0l,nl-1 do z(*,il)=z(*,il)*factor +;--------------------------------------- + wchannel_mdr,files(i),z>0,0 + start= 20+(20+info.tdi)/bin + endline=info.nline-1 + ave_cols,z(12:12+1024/bin-1,start:endline),0,24/bin,c + center0(info.ccd,info.channel,0:(endline-start+1)*info.bin-1) = rebin(c,max_lines) + ave_cols,z(12:12+1024/bin-1,start:endline),(1024-24)/bin,1024/bin-1,over + overlap(info.ccd,info.channel,0:(endline-start+1)*info.bin-1) = rebin(over,max_lines) + ave_cols,z(12:12+1024/bin-1,start:endline),0,1024/bin-1,m + + imagemean(info.ccd,info.channel,0:(endline-start+1)*info.bin-1)=rebin(m,max_lines) +; + endif ; + print,files(i),systime(1)-t0 + wait,0.05 + endfor + pos=strpos(obs,'PSP') +obsname=strmid(obs,pos,15) +fileb= 'C:\HiRISE\Data\test_mdr_images\results\'+obsname+'_join_data_A.sav' +save,filename=fileb,files,center0,overlap,imagemean,mode_bin,mode_tdi,info +; +end diff --git a/isis/src/mro/apps/hical/hical.cpp b/isis/src/mro/apps/hical/hical.cpp new file mode 100644 index 0000000000000000000000000000000000000000..552943ae1c273431e9d443b79315c76b960136c6 --- /dev/null +++ b/isis/src/mro/apps/hical/hical.cpp @@ -0,0 +1,473 @@ +// $Id: hical.cpp,v 1.9 2009/09/16 03:37:23 kbecker Exp $ +#include "Isis.h" + +#include +#include +#include +#include +#include +#include + +#include "Filename.h" +#include "ProcessByLine.h" +#include "UserInterface.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iString.h" +#include "HiCalConf.h" +#include "CollectorMap.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalData.h" +#include "SplineFillComp.h" +#include "LowPassFilterComp.h" +#include "DriftBuffer.h" +#include "DriftCorrect.h" +#include "OffsetCorrect.h" +#include "DarkSubtractComp.h" +#include "GainVLineComp.h" +#include "FlatFieldComp.h" +#include "TempGainCorrect.h" + + +using namespace Isis; +using namespace std; + +//!< Define the matrix container for systematic processing +typedef CollectorMap MatrixList; + +// Calibration parameter container +MatrixList *calVars = 0; + +/** + * @brief Apply calibration to each HiRISE image line + * + * This function applies the calbration equation to each input image line. It + * gets matrices and constants from the \b calVars container that is established + * in the main with some user input via the configuration (CONF) parameter. + * + * @param in Input raw image line buffer + * @param out Output calibrated image line buffer + */ +void calibrate(Buffer &in, Buffer &out) { + const HiVector &Zd = calVars->get("Zd"); + const HiVector &Zz = calVars->get("Zz"); + const HiVector &Zb = calVars->get("Zb"); + const HiVector &Zg = calVars->get("Zg"); + const HiVector &Zgg = calVars->get("Zgg"); + const HiVector &Za = calVars->get("Za"); + const HiVector &Zt = calVars->get("Zt"); + double Ziof = calVars->get("Ziof")[0]; + + // Set current line (index) + int line(in.Line()-1); + if (calVars->exists("LastGoodLine")) { + int lastline = ((int) (calVars->get("LastGoodLine"))[0]) - 1; + if ( line > lastline ) { line = lastline; } + } + + // Apply correction + for (int i = 0 ; i < in.size() ; i++) { + if (IsSpecial(in[i])) { + out[i] = in[i]; + } + else { + double hdn; + hdn = (in[i] - Zd[line] - Zz[i] - Zb[i]); // Drift, Offset, Dark + hdn = hdn / Zg[line] * Zgg[i] * Za[i] * Zt[i]; // GainVLine, Gain, FlatField, TempGain + out[i] = hdn / Ziof; // I/F or DN or DN/US + } + } + return; +} + + +void IsisMain(){ + + const std::string hical_program = "hical"; + const std::string hical_version = "3.5"; + const std::string hical_revision = "$Revision: 1.9 $"; + const std::string hical_runtime = Application::DateTime(); + + UserInterface &ui = Application::GetUserInterface(); + + string procStep("prepping phase"); + try { +// The output from the last processing is the input into subsequent processing + ProcessByLine p; + + Cube *hifrom = p.SetInputCube("FROM"); + int nsamps = hifrom->Samples(); + int nlines = hifrom->Lines(); + +// Initialize the configuration file + string conf(ui.GetAsString("CONF")); + HiCalConf hiconf(*(hifrom->Label()), conf); + DbProfile hiprof = hiconf.getMatrixProfile(); + +// Check for label propagation and set the output cube + Cube *ocube = p.SetOutputCube("TO"); + if ( !IsTrueValue(hiprof,"PropagateTables", "TRUE") ) { + RemoveHiBlobs(*(ocube->Label())); + } + +// Set specified profile if entered by user + if (ui.WasEntered("PROFILE")) { + hiconf.selectProfile(ui.GetAsString("PROFILE")); + } + + +// Add OPATH parameter to profiles + if (ui.WasEntered("OPATH")) { + hiconf.add("OPATH",ui.GetAsString("OPATH")); + } + else { + // Set default to output directory + hiconf.add("OPATH", Filename(ocube->Filename()).Path()); + } + +// Do I/F output DN conversions + string units = ui.GetString("UNITS"); + + // Allocate the calibration list + calVars = new MatrixList; + +// Set up access to HiRISE ancillary data (tables, blobs) here. Note it they +// are gone, this will error out. See PropagateTables in conf file. + HiCalData caldata(*hifrom); + +//////////////////////////////////////////////////////////////////////////// +// FixGaps (Z_f) Get buffer pixels and compute coefficients for equation +// y = a[0] + a[1]*x + a[2] * exp(a[3] * x) +// where y is the average of the buffer pixel region, +// and x is the time at each line in electrons/sec/pixel + procStep = "Zf module"; + hiconf.selectProfile("Zf"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZfHist; + ZfHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + DriftBuffer driftB(caldata, hiconf); + calVars->add("Zf", driftB.ref()); + ZfHist = driftB.History(); + if ( hiprof.exists("DumpModuleFile") ) { + driftB.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + // NOT RECOMMENDED! This is required for the next step! + // SURELY must be skipped with Z_d step as well! + calVars->add("Zf", HiVector(nlines, 0.0)); + ZfHist.add("Debug::SkipModule invoked!"); + } + +///////////////////////////////////////////////////////////////////// +// DriftCorrect (Z_d) +// Now compute the equation of fit +// + procStep = "Zd module"; + HiHistory ZdHist; + hiconf.selectProfile("Zd"); + hiprof = hiconf.getMatrixProfile(); + ZdHist.add("Profile["+ hiprof.Name()+"]"); + if (!SkipModule(hiconf.getMatrixProfile("Zd")) ) { + DriftCorrect driftC(hiconf); + calVars->add("Zd", driftC.Normalize(driftC.Solve(calVars->get("Zf")))); + ZdHist = driftC.History(); + if ( hiprof.exists("DumpModuleFile") ) { + driftC.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Zd", HiVector(nlines, 0.0)); + ZdHist.add("Debug::SkipModule invoked!"); + } + + + //////////////////////////////////////////////////////////////////// + // ZeroCorrect (Z_z) Get reverse clock + procStep = "Zz module"; + hiconf.selectProfile("Zz"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZzHist; + ZzHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + OffsetCorrect zoff(caldata, hiconf); + calVars->add("Zz", zoff.ref()); + ZzHist = zoff.History(); + if ( hiprof.exists("DumpModuleFile") ) { + zoff.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Zz", HiVector(nsamps, 0.0)); + ZzHist.add("Debug::SkipModule invoked!"); + } + +///////////////////////////////////////////////////////////////// +// DarkSubtract (Z_b) Remove dark current +// + procStep = "Zb module"; + hiconf.selectProfile("Zb"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZbHist; + ZbHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + DarkSubtractComp dark(hiconf); + calVars->add("Zb", dark.ref()); + ZbHist = dark.History(); + if ( hiprof.exists("DumpModuleFile") ) { + dark.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Zb", HiVector(nsamps, 0.0)); + ZbHist.add("Debug::SkipModule invoked!"); + } + +//////////////////////////////////////////////////////////////////// +// GainVLineCorrect (Z_g) Correct for gain-based drift +// + procStep = "Zg module"; + hiconf.selectProfile("Zg"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZgHist; + ZgHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + GainVLineComp gainV(hiconf); + calVars->add("Zg", gainV.ref()); + ZgHist = gainV.History(); + if ( hiprof.exists("DumpModuleFile") ) { + gainV.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Zg", HiVector(nlines, 1.0)); + ZgHist.add("Debug::SkipModule invoked!"); + } + + +//////////////////////////////////////////////////////////////////// +// GainCorrect (Z_gg) Correct for gain with the G matrix + procStep = "Zgg module"; + hiconf.selectProfile("Zgg"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZggHist; + ZggHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + double bin = ToDouble(hiprof("Summing")); + double tdi = ToDouble(hiprof("Tdi")); + double factor = 128.0 / tdi / (bin*bin); + HiVector zgg = hiconf.getMatrix("G", hiprof); + for ( int i = 0 ; i < zgg.dim() ; i++ ) { zgg[i] *= factor; } + calVars->add("Zgg", zgg);; + ZggHist.add("LoadMatrix(G[" + hiconf.getMatrixSource("G",hiprof) + + "],Band[" + ToString(hiconf.getMatrixBand(hiprof)) + + "],Factor[" + ToString(factor) + "])"); + if ( hiprof.exists("DumpModuleFile") ) { + Component zg("GMatrix", ZggHist); + zg.Process(zgg); + zg.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Zgg", HiVector(nsamps, 1.0)); + ZggHist.add("Debug::SkipModule invoked!"); + } + +//////////////////////////////////////////////////////////////////// +// FlatField (Z_a) Flat field correction with A matrix + procStep = "Za module"; + hiconf.selectProfile("Za"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZaHist; + ZaHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + FlatFieldComp flat(hiconf); + calVars->add("Za", flat.ref()); + ZaHist = flat.History(); + if ( hiprof.exists("DumpModuleFile") ) { + flat.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Za", HiVector(nsamps, 1.0)); + ZaHist.add("Debug::SkipModule invoked!"); + } + +//////////////////////////////////////////////////////////////////// +// FlatField (Z_t) Temperature-dependant gain correction + procStep = "Zt module"; + hiconf.selectProfile("Zt"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZtHist; + ZtHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + TempGainCorrect tcorr(hiconf); + calVars->add("Zt", tcorr.ref()); + ZtHist = tcorr.History(); + if ( hiprof.exists("DumpModuleFile") ) { + tcorr.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Zt", HiVector(nsamps, 1.0)); + ZtHist.add("Debug::SkipModule invoked!"); + } + + +//////////////////////////////////////////////////////////////////// +// I/FCorrect (Z_iof) Conversion to I/F +// + procStep = "Ziof module"; + hiconf.selectProfile("Ziof"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZiofHist; + ZiofHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + double sed = ToDouble(hiprof("ScanExposureDuration")); // units = us + if ( IsEqual(units, "IOF") ) { + // Add solar I/F correction parameters + double au = hiconf.sunDistanceAU(); + ZiofHist.add("SunDist[" + ToString(au) + " (AU)]"); + double suncorr = 1.5 / au; + suncorr *= suncorr; + + double zbin = ToDouble(hiprof("ZiofBinFactor")); + ZiofHist.add("ZiofBinFactor[" + ToString(zbin) + "]"); + + double zgain = ToDouble(hiprof("FilterGainCorrection")); + ZiofHist.add("FilterGainCorrection[" + ToString(zgain) + "]"); + ZiofHist.add("ScanExposureDuration[" + ToString(sed) + "]"); + double ziof = (zbin * zgain) * (sed * 1.0e-6) * suncorr; + + calVars->add("Ziof", HiVector(1, ziof)); + ZiofHist.add("I/F_Factor[" + ToString(ziof) + "]"); + ZiofHist.add("Units[I/F Reflectance]"); + } + else if ( IsEqual(units, "DN/US") ) { + // Ziof is a divisor in calibration equation + double ziof = sed; + calVars->add("Ziof", HiVector(1, ziof)); + ZiofHist.add("ScanExposureDuration[" + ToString(sed) + "]"); + ZiofHist.add("DN/US_Factor[" + ToString(ziof) + "]"); + ZiofHist.add("Units[DNs/microsecond]"); + } + else { + // Units are already in DN + double ziof = 1.0; + calVars->add("Ziof", HiVector(1, ziof)); + ZiofHist.add("DN_Factor[" + ToString(ziof) + "]"); + ZiofHist.add("Units[DN]"); + } + } + else { + calVars->add("Ziof", HiVector(1,1.0)); + ZiofHist.add("Debug::SkipModule invoked!"); + ZiofHist.add("Units[Unknown]"); + } + + // Reset the profile selection to default + hiconf.selectProfile(); + +//---------------------------------------------------------------------- +// +///////////////////////////////////////////////////////////////////////// +// Call the processing function + procStep = "calibration phase"; + p.StartProcess(calibrate); + + // Get the default profile for logging purposes + hiprof = hiconf.getMatrixProfile(); + const std::string conf_file = hiconf.filepath(conf); + + // Quitely dumps parameter history to alternative format file. This + // is completely controlled by the configuration file + if ( hiprof.exists("DumpHistoryFile") ) { + procStep = "logging/reporting phase"; + Filename hdump(hiconf.getMatrixSource("DumpHistoryFile",hiprof)); + string hdumpFile = hdump.Expanded(); + ofstream ofile(hdumpFile.c_str(), ios::out); + if (!ofile) { + string mess = "Unable to open/create history dump file " + + hdump.Expanded(); + iException::Message(iException::User, mess, _FILEINFO_).Report(); + } + else { + ofile << "Program: " << hical_program << endl; + ofile << "RunTime: " << hical_runtime << endl; + ofile << "Version: " << hical_version << endl; + ofile << "Revision: " << hical_revision << endl << endl; + + ofile << "FROM: " << hifrom->Filename() << endl; + ofile << "TO: " << ocube->Filename() << endl; + ofile << "CONF: " << conf_file << endl << endl; + + ofile << "/* " << hical_program << " application equation */" << endl + << "/* hdn = (idn - Zd(Zf) - Zz - Zb) */" + << endl << "/* odn = hdn / Zg * Zgg * Za * Zt / Ziof */" + << endl << endl; + + ofile << "****** PARAMETER GENERATION HISTORY *******" << endl; + ofile << "\nZf = " << ZfHist << endl; + ofile << "\nZd = " << ZdHist << endl; + ofile << "\nZz = " << ZzHist << endl; + ofile << "\nZb = " << ZbHist << endl; + ofile << "\nZg = " << ZgHist << endl; + ofile << "\nZgg = " << ZggHist << endl; + ofile << "\nZa = " << ZaHist << endl; + ofile << "\nZt = " << ZtHist << endl; + ofile << "\nZiof = " << ZiofHist << endl; + + ofile.close(); + } + } + +// Ensure the RadiometricCalibration group is out there + const std::string rcalGroup("RadiometricCalibration"); + if (!ocube->HasGroup(rcalGroup)) { + PvlGroup temp(rcalGroup); + ocube->PutGroup(temp); + } + + PvlGroup &rcal = ocube->GetGroup(rcalGroup); + rcal += PvlKeyword("Program", hical_program); + rcal += PvlKeyword("RunTime", hical_runtime); + rcal += PvlKeyword("Version",hical_version); + rcal += PvlKeyword("Revision",hical_revision); + + PvlKeyword key("Conf", conf_file); + key.AddCommentWrapped("/* " + hical_program + " application equation */"); + key.AddComment("/* hdn = (idn - Zd(Zf) - Zz - Zb) */"); + key.AddComment("/* odn = hdn / Zg * Zgg * Za * Zt / Ziof */"); + rcal += key; + + // Record parameter generation history. Controllable in configuration + // file. Note this is optional because of a BUG!! in the ISIS label + // writer as this application was initially developed + if ( IsEqual(ConfKey(hiprof,"LogParameterHistory",string("TRUE")),"TRUE")) { + rcal += ZfHist.makekey("Zf"); + rcal += ZdHist.makekey("Zd"); + rcal += ZzHist.makekey("Zz"); + rcal += ZbHist.makekey("Zb"); + rcal += ZgHist.makekey("Zg"); + rcal += ZggHist.makekey("Zgg"); + rcal += ZaHist.makekey("Za"); + rcal += ZiofHist.makekey("Ziof"); + } + + p.EndProcess(); + } + catch (iException &ie) { + delete calVars; + calVars = 0; + string mess = "Failed in " + procStep; + ie.Message(iException::User, mess.c_str(), _FILEINFO_); + throw; + } + +// Clean up parameters + delete calVars; + calVars = 0; +} + diff --git a/isis/src/mro/apps/hical/hical.xml b/isis/src/mro/apps/hical/hical.xml new file mode 100644 index 0000000000000000000000000000000000000000..9a44f8765639eadf1a8c8f1bf008d6d4c6d7d39b --- /dev/null +++ b/isis/src/mro/apps/hical/hical.xml @@ -0,0 +1,1389 @@ + + + + + + + Performs radiometric calibration of HiRISE channel images + + + +

    + hical appiles radiometric calibration correction to HiRISE + images. This particular version is deemed experimental, thus the beta + designation. The radiometric calibration correction is performed on + each individual HiRISE channel file (EDR) correcting for drift, + instrument offset, dark current, line-dependant gain, gain, flat field + and finally, conversion to I/F reflectance, DN/US or DNs. +

    +

    + The calibration is carried out in a series of modules. These modules + provide various contributions to the calibration process. The + parameters that govern the behavior of these modules are contained in + the program configuration file as specified in the CONF program + parameter. + The default file is $ISIS3DATA/mro/calibration/hical.????.conf + where '????' is the current version of the file. + + Each of the calibration modules have their own unique set of keywords + that govern is behavior. This is documented in the CONF parameter. + + The equation that is applied is described below: +

    +
    + Processing:
    +
    +          Zf = Fix gaps(Z)
    +          Zd = DriftCorrect(Zf)
    +          Zz = zero_correct(Zd - Offset)
    +          Zb = dark_subtract(Zz - B)     [B + T]
    +          Zg = gain_v_line_correct(Zb) [GvL Parameters]
    +          Zgg = gain_correct(Zg)          [G]
    +          Za = Flat_field_correct(Zgg)  [A]
    +          Zt = Temperature dependant gain correction (Za)
    +          Ziof = I/F conversion(Zt)
    +
    +  The correction is: 
    +
    +    oDN = (iDN - Zd(Zf) - Zz - Zb)  / Zg * Zgg * Za * Zt /  Ziof 
    +      
    +

    + How these radiometric components are computed are governed by the + CONF configuration file. This file is highly customizable to + accomodate as many specialized processing needs as is imaginable. + The contents of this file and how it may be used/customized is + fully described in the CONF documentation section. +

    +

    + Individual CCD channels may also require adjustments to radiometrically + match at the seam where the two channels come together. The + histitich application combines the two adjacent channel CCDs while + taking into account any residual seam mismatches. +

    +
    + + + + Original version + + + Wrote application test + + + Added examples + + + Added processing of DarkPixel object data. The median of the 16 dark pixels in + subtracted from the original DN. + Also added the DARKSTATS output file. + + + Extensively modified to implement latest state of HiRISE calibration. + + + This version is created from hical as a starting point. It has been + again extensively modified for maximum flexibility and usefullness. + + + Corrected the DriftCorrect class to properly compute the initial guess + of the fit parameters. It was not quite the same as the model. Also + added capability to dump individual module data via the configuration + file. + + + Added the OPATH parameter and made it available for subsititution in + the configuration parameters; Added the ZdSkipFit configuration + parameter to skip the non-linear fitting process in the Zd module + (when invoked, it will use the result of the Zf module); Added in the + percent additional contribution for the FPA temperature/gain + correction; Added ZdMinimumLines option to constrain the size of an + image that is fitted (properly). + + + Added missing factor (128/tdi/bin^2) to Zgg G-matrix gain module. + Explicitly recognize Phobos and Deimos targets as Mars so that I/F can + be computed. + + + Fixed removal of HiRISE calibration ancillary BLOBS (tables) so that + it only removes these tables and not all others, such as SPICE tables. + + + Removed references to CubeInfo + + + Added the ZdOnFailUseLinear flag to specify behavior when the + non-linear DriftCorrect Zd module fails. + + + Change default Zf filter defaults to 201 width with 2 interations; Add + reporting of raw buffer data to Zf module data dump; Added computation + of average and standard deviation to difference of raw buffer and post + filtering in Zf module; Set Zd default behavior to skip LM fitting and + eliminate unnecessary linear fitting in skip mode. + + + Abstracted Buffer pixel processing to DriftBuffer class (Zf); Added + robustness to some module dumps (Zf, Zb, Za); Added statistics + computations to several modules (Zf, Zz, Zb,Za); Abstracted dark + offset processing of Reverse Clock data to OffsetCorrect class (Zz). + + + Replaced references to DataInterp class with NumericalApproximation. + + + Added additional code to implement Zz module trigger options. This + option provides the ability to trigger a constant used in the Reverse + Clock calibration data based upon noise. See the discussion on the Zz + module in this program documentation. + + + Change default for OPATH to output (TO) directory; Removed the IOF + parameter and replaced it with the UNITS parameter; Added the Zt + module which corrects temperature dependant gain previously in the Za + module; updated documentation. + + + + + Mars Reconnaissance Orbiter + + + + + + cube + input + Input cube to calibrate + + The name of the cube to which the correction will be applied. The + correction will apply to every non-special pixel in the image. + + *.cub + + + + filename + input + $mro/calibration + $mro/calibration/hical.????.conf + + File containing HiRISE calibration and matrix configuration parameters + + *.conf + +

    + This important file provides all parameters used + in the calibration process. It contains references to + calibration matrices (such as flat fields, instrument gains, + etc...), label keywords and parameter constants used in the + radiometric calibration process. +

    +

    + The format of this PVL file is highly flexible for managing + HiRISE calibration data. This configuration file contains + numerous module profiles that govern the behavior of each phase + in the calibration process. These modules each have parameters + that are specific to its requirements. There are 6 different + modules that are used in the application. However, you will + typically see many other profiles in the configuration file. + The technique employed here is that you can take advantage of + the ability to merge other profiles into one or more of the + other main profiles, simply by the content of the labels or + observing conditions of the image. +

    +

    + The file must contain a top level Hical object. Within + this object is numerous profiles. The keywords that are + contained in the Object section of the file are always used in + every profile and can be superceded by any subsequent profile + loaded after the initial one. Optional profile names are + contructed by the combination of the OptionKeywords and + ProfileOptions keywords. The OptionKeywords + lists keywords in the configuration file and or label that can + be used to textually replace the patterns surrounded by the {} + in the ProfileOptions keyword. The kewords FILTER, CCD, + CHANNEL, TDI and BIN are always generated after the initial + module and label are loaded in. After the initial profile is + loaded, the FROM file label is loaded using the + LabelGroups to determine which keywords are loaded. Note + that the groups must exist or an error is issued. Other than + that you can specify any defined keyword in the + OptionsKeywords to apply to profile names. +

    +

    + The process by which a file name is determined also utilizes the + OptionKeywords to replace patterns that exist in + retrieval of all filename references in the configuration file. + This includes virtually all files including matrix and CSV + files. +

    +

    + Matrices are currently multi-band ISIS cube files that contain + one line and up to 1024 samples. There are expected to be + 28 bands in each one of these calibration matrices, one for each + CCD channel. There are 14 different CCDs with 2 channels each + for a total of 28 channels. (Note that channels are the basic + HiRISE image product where calibration is applied.) There will + always be one line for these cubes since HiRISE detectors are + line scan instruments. There will be a minimum of 64 (for + summing mode of 16) and a maximum of 1024 (summing mode of 1) + samples in these cubes. The content of these matrix files are + dependant upon summing mode and the time delay integration (TDI) + mode used during image acquisition. TDI allows varying number + of line scans, in conjunction with exposure time, to pass over + the same point on the surface of Mars to increase the + signal-to-noise ration (SNR) as well as resolution. There are 4 + selectable modes of TDI: 128, 64, 32 and 8. Coupled with 6 + difference summing modes (1, 2, 3, 4, 8, and 16), there are at + most 24 calibration cubes per set of matrices. These matrices + are referenced as file paths of the form: +

    + A = $mro/calibration/matrices/A_TDI{TDI}_BIN{BIN}_????.cub
    +                
    + Here, {TD} and {BIN} correspond to the TDI and summming mode + used during image acquisition, respectively. (More on how these + values are determined is provided in the follow text.) Matrix variables + are equated to file references using the pattern substituion of + keywords enclosed in {} in the configuration file. Matrix file + paths are also subjected to pattern replacement in the same + fashion as profiles. This will minimize the content management + aspect of the configuration file and encourage consistant file + naming schemes. +

    +

    + The real power of the configuration file is its use of named Profiles. + Profiles are groups of keywords that can be associated to a + unique definition. The hical PVL configuration file consists of a + single Hical object with numerous named Profile + groups. Each of the Profile groups must contain a Name + keyword that uniquely identifies it within the Hical object. + This allows us to create Profiles that pertain to particular + combinations of filter (RED, IR, BG), CCD (RED0-9, IR10/11, + or BG12/13), TDI (128, 64, 32, 8), BIN (1, 2, 3, 4, 8, 16) or + CHANNEL (0 or 1). These values are determined from the content + of the HiRISE label. Combinations of profiles that are added + after the initial default are specified in the + ProfileOptions keyword. Profile combinations can + consist of any combination or use of these defined values. + These defined values are specified as or with the Name + keyword in Profile groups delimited by curly braces. Given + this definition one can specify a particular group of calibration + parameters for a specific CCD channel with the pattern + {FILTER}{CCD}_{CHANNEL}. Then, one can define a special + collection of calibration matrices, keywords or scalars for any + one (or none) of the filters. So, for the problematic BG13, you + can have a named profile called BG13_1 whose keywords in the + profile are loaded when calibrating a BG13_1 channel, thus + overriding any defaulted keywords. Should named + profiles using this option not exist, they are ignored. Also, + Profiles specified in this manner are loaded in the + order specified in the ProfileOptions keyword, thus + creating a hierarchy of calibration specification configurations. +

    +

    + Below is an example of a complete PVL configuration file that + demonstrates some of the features described: +

    +
    +#  HiRISE Calibration Matricies configuration file
    +#  See documentation for the hical application on the content and form of
    +#  this file.
    +Object = Hical
    +
    +  Program = "hical"
    +
    +  Name           = "HiMatrices"
    +  DefaultProfile = "HiMatrices"
    +
    +/* If you want to rerun hical, you must set PropagateTables to True.  Use */
    +/* this in conjuction with Debug::SkipModule = True option for each module. */
    +  PropagateTables = False
    +
    +/* Define label groups that are loaded for each profile reference */
    +/* Note all keywords in these groups become available to all profiles. */
    +/* Thus, you can use them in the OptionKeywords and ProfileOptions keywords */
    +/* to create very specialized profiles for special needs. */
    +/* Specify the FPA reference temperature.  It is used in several modules so */
    +/* it is specified at the top level */
    +
    +  LabelGroups = ( "Dimensions", "Instrument", "Archive")
    +
    +/* These keywords are used in ProfileOptions mapping.  Note that order and */
    +/* case matter!  WARNING:  You can easily break file lookups if these keys */
    +/* are deleted or modified improperly!!! */
    +  OptionKeywords = ("FILTER", "CCD", "CHANNEL", "TDI", "BIN", "ProductId",
    +                    "Program", "Module", "OPATH", "CalOptions")
    +
    +/* Additional profile combinations and order load hierarchy.  These keywords */
    +/* are defined when the LabelGroups are loaded. */ 
    +/* Kris Becker & Eric Eliason updated 10/24/2008 */
    +/* ProfileOptions value added: {Module}_{CalOptions} */
    +  ProfileOptions = ("{FILTER}", "TDI{TDI}", "BIN{BIN}", "TDI{TDI}/BIN{BIN}",
    +                    "{FILTER}{CCD}_{CHANNEL}",
    +                    "{FILTER}{CCD}_{CHANNEL}/TDI{TDI}/BIN{BIN}", "Debug",
    +                    "{Module}_{CalOptions}")
    +
    +/* Specify the FPA reference temperature.  It is used in several modules so */
    +/* it is specified at the top level */
    +  FpaReferenceTemperature = 21.0
    +
    +/* This profile contains parameters pertinent to processing the buffer */
    +/* pixels for subsequent using in the drift correction, Zd module */
    +  Group = Profile
    +    Name = Zf
    +    Module = Zf
    +    ZfFirstSample = 5
    +    ZfLastSample = 11
    +
    +    ZfFilterWidth = 201
    +    ZfFilterIterations = 2
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing drift correction */
    +  Group = Profile
    +    Name = Zd
    +    Module = Zd
    +
    +  /* Uncomment to turn off non linear fitting of Zf data and pass it thru */
    +    ZdSkipFit = True
    +
    +  /* Uncomment to use linear fitting of Zf data when non-linear fails */
    +  /* Default is to pass thru filtered Zf data */
    +  /* ZdOnFailUseLinear = True */
    +
    +  /* Minimum number of good lines (NLines - (TrimLines/Summing)) to fit */
    +    ZdMinimumLines = 250
    +
    +  /* Maximum  number of iterations for the algorithm to converge and */
    +  /* other limits */
    +    MaximumIterations = 100
    +    MaximumLog        = 709.0
    +
    +  /*  Convergence parameters for Levenberg-Marquardt algorithm */
    +  /*  Equation is solved when |dx_i| < AbsoluteError + RelativeError * |x_i| */
    +  /*    where dx is the last step and x is the current step for each i-th */
    +  /*    value */
    +    AbsoluteError = 1.0E-4
    +    RelativeError = 1.0E-4
    +
    +  /* Filtering of the guestimate buffer */
    +    GuessFilterWidth = 17
    +    GuessFilterIterations = 1
    +
    +#    DumpModuleFile = "{ProductId}_{Module}.log"
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing the offset */
    +  Group = Profile
    +    Name = Zz
    +    Module = Zz
    +
    +/* Set calibration parameters for hiclean operations.  Indexes are all 0-based */
    +    ZzFirstLine = 1
    +    ZzLastLine  = 19
    +
    +
    +/* Reverse Clock trigger Statistics profiles */
    +    ReverseClockStatistics = "$mro/calibration/matrices/ReverseClockStatistics.????.conf"
    +    RevLisTolerance = 1
    +    RevHisTolerance = 1
    +    RevNulTolerance = 1
    +  End_Group
    +
    +/*  Skip reverse clock if the ReverseReadoutNoise is to large */
    +/*  Profile added by Kris Becker & Eric Eliason, 10/25/2008 */
    +  Group = Profile
    +    Name = Zz_ReverseReadoutNoise
    +    Debug::SkipModule = True
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing dark current. */
    +/* Required label keywords:  Summing, Tdi, FpaPositiveYTemperature, */
    +/*                           and FpaNegativeYTemperature, Lines */
    +/* Also needs LineTime which is computed. */
    +  Group = Profile
    +    Name = Zb
    +    Module = Zb
    +
    +/* Define the B matrix file reference */
    +    B = "$mro/calibration/matrices/B_TDI{TDI}_BIN{BIN}_hical_????.cub"
    +    SkipLines        = 1
    +    Slope            = "$mro/calibration/matrices/t_slope_CH{CHANNEL}_hical_????.csv"
    +    Intercept        = "$mro/calibration/matrices/t_intercept_CH{CHANNEL}_hical_????.csv"
    +
    +    /* Do filtering? */
    +    ZbFilterWidth      = 3
    +    ZbFilterIterations = 1
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing gain correction. */
    +/* Required label keywords: CpmmNumber, ChannelNumber, Lines */
    +  Group = Profile
    +    Name = Zg
    +    Module = Zg
    +
    +/*  As of 2008-06-25, this is the default */
    +    Debug::SkipModule = True
    +
    +    SkipLines            = 1
    +/* Added "_hical" to filename as of 2008-04-02.  This is consistant with */
    +/* naming convention used for the beta version of hical. */
    +    GainLineCoefficients = "$mro/calibration/matrices/line_correct_{BIN}_hical_????.csv"
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing gain correction. */
    +/* Required label keywords: CpmmNumber, ChannelNumber, Lines */
    +  Group = Profile
    +    Name = Zgg
    +    Module = Zgg
    +
    +/* Define the G matrix file reference */
    +    G = "$mro/calibration/matrices/G_TDI{TDI}_BIN{BIN}_hical_????.cub"
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing gain correction. */
    +/* Required label keywords: CpmmNumber, ChannelNumber, Tdi, Lines */
    +  Group = Profile
    +    Name = Za
    +    Module = Za
    +
    +/* Applies a temperature correction factor to A matrix */
    +/*** As of 2009-09-15 this parameter is implemented in the Zt module   ***/
    +/***   It remains here for backward compatability for now.  It will be ***/
    +/***   removed at some point in future releases.                       ***/
    +    ZaFpaTemperatureFactor = 0.005
    +
    +/* Define the A matrix file reference */
    +     A = "$mro/calibration/matrices/A_TDI{TDI}_BIN{BIN}_hical_????.cub"
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing */
    +/* temperature-dependant gain correction. */
    +/* Required label keywords: CpmmNumber, ChannelNumber, Samples */
    +  Group = Profile
    +    Name = Zt
    +    Module = Zt
    +
    +/ Define temperature-dependant gain correction CSV file */
    +    FpaTemperatureFactorSkipLines = 4
    +    FpaTemperatureFactorHeader = True
    +    FpaTemperatureFactorFile = "$mro/calibration/matrices/FpaTemperatureGain_BIN{BIN}.????.csv"
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing I/F conversion. */
    +/*  Required label keywords: ScanExposureDuration */
    +  Group = Profile
    +    Name = Ziof
    +    Module = Ziof
    +
    +/* I/F correction for tdi/bin - currently set at 1.0 for all tdi/bin */
    +/* combinations. */
    +    ZiofBinFactor = 1.0
    +  End_Group
    +
    +/* Here are the filter profiles.  All keywords that pertain to a filter set */
    +/* should be specified here.  FilterGainCorrection are I/F corrections in */
    +/* units of DN/s. */
    +  Group = Profile
    +    Name = RED
    +    FilterGainCorrection = 159423899.0
    +  End_Group
    +
    +  Group = Profile
    +    Name = IR
    +    FilterGainCorrection  =  58018177.0
    +  End_Group
    +
    +  Group = Profile
    +    Name = BG
    +    FilterGainCorrection  =  108811104.0
    +  End_Group
    +
    +  Group = Profile
    +    Name = IR10_1
    +#   LastGoodLine = 3100
    +  End_Group
    +
    +
    +  Group = Profile
    +    Name = Debug
    +
    +/** Current disables writting to label history due to bug in keyword formatter in ISIS **/
    +/* The bug has the following error signature: */
    +/*        terminate called after throwing an instance of 'std::out_of_range'  */
    +/*          what():  basic_string::substr                                     */
    +/*         Abort                                                              */
    +/* You must set this to false when this occurs as a workaround and use the */
    +/* DumpHistoryFile parameter to see the parameter history. */
    +    LogParameterHistory = False
    +
    +/* Uncomment this line to write parameter history to the ProductId log */
    +   DumpHistoryFile = "{OPATH}/{ProductId}.{Program}.log"
    +
    +/* Uncomment this line to dump Module data for every module when using Debug */
    +/* profiling. */
    +#    DumpModuleFile = "{OPATH}/{ProductId}_{Module}.log"
    +  End_Group
    +
    +End_Object
    +            
    + The filter profiles each contain a scalar constant of the same name + for each of the three filter sets. The ProfileOrder keyword + contains the {FILTER} pattern that will select the appropriate + filter gleened from the label. Other profiles that satisfy the remaining + patterns are excluded but can be added when necessary. +

    + The final resutling matrices, constants and keywords used in + the calibration equation are recorded in the + RadiometricCalibration group of the output label. +

    +

    Application Control Parameters


    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Description of main hical configuration + parameters. These parameters govern profile loading, + filename pattern replacement and debugging operations. +
    ParameterDescription
    Program + This keyword is set to the name of the application and can + be used to create unique filenames as described previously. +
    Name + The name of the current profile. This keyword is + required and is present in the Object keyword section as + well as in all other Profile groups. This uniquely + identifies the final comingled profile. +
    DefaultProifile + This names the default profile that is loaded when none + are specifically called for in the application. It can + be any profile (Debug might be an interesting + alternative) but is generally the Object profile. This + will cause no other profiles to be added when a generic + one is retrieved. +
    ProgagateTables + Specifies the behavior of the table progation of the FROM + file to the TO file when the file is completed. This has + some interesting implications. When False, all Table + objects in the FROM file are removed in the TO file, which + in effect prevents hical from being able to run again. + However, because of debugging capabilities, one may want ot + select which calibration modules are run. Setting this to + True will propagate all Table objects (BLOBs) in the FROM + file to be copied to the TO file. +
    LabelGroups + This keyword identifies which Groups in the FROM ISIS + cube label are included in profiles. This allows any + label keyword in the ISIS label to become available for + profiling and filename generation. Its handy for + creating very specific profiles for problem images and + other debugging purposes. +
    OptionKeywords + This keyword selects other keywords in the configuration + file or the FROM label groups as defined in the + LabelGroups keyword. This list is used to specify + additional profiles that can be loaded (via + ProfileOptions) and variable substitution within file + names (such as B, G and A matrix files). +
    Debug::SkipModule + This special keyword exists to provide the ability + to complete bypass processing of a module. If this + configuration keyword resolves to True in any module + configuration profile, then the module is not + invoked and the resulting contribution is set + appropriately such that it does not contribute to + the calibration process. This is very useful for + debugging and seeing how each module contributes. + Be sure to set ProgagateTables to True if you + intend to perform subsequent runs of hical. +
    OPATH + This keyword is the value of the OPATH parameter + entered when the program is executed. It can be + used to specify a path where log files are written + when that option is invoked. If the user did not + specify a value for this keyword, the current path + is supplied by default. +
    DumpModuleFile + This special keyword exists to provide the ability + to dump data from each Module. Each Module + implements a data dump that will be written to this + file. The file name can be made up of a combination + of any label or configuration keyword. The example + provided in the config file section uses the + ProductId and the name of the Module with a .log + extension. This keyword can be included in + individual Module Groups or at the top level which + will effectively dump all Modules. Note that the + Ziof Module is excluded from this feature as its + data is contained entirely in the history report. +
    DumpHistoryFile + This special keyword exists to provide the ability + to dump the Module history from each Module. Each + Module maintains a processing history that will be + written to this file. The file name can be made up + of a combination of any label or configuration + keyword. The example provided in the config file + section uses the ProductId and the name of the + Program with a .log extension. +
    + +

    Zf Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + This module is responsible for reading and processing of + the Buffer pixels for input into the DriftCorrect module. + It averages lines, runs smoothing filters and ensures + there are no gaps by resorting to a Spline Fill of any + remaining missing data. +
    ParameterDescription
    Name + Must be set to Zf as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    ZfFirstSample + Specifies the first (0-based) Buffer sample to start the + average. +
    ZfLastSample + Specifies the last (0-based) Buffer sample to end the + average. +
    ZfFilterWidth + Specifies the width of the filter to smooth and fill + gaps in the resulting Buffer averages. [Default: 201] +
    ZfFIlterIterations + Specifies the number of sequential filters to apply to + the averaged buffer pixels before finally filling with a + spline. [Default: 2] +
    + +

    Zd Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + The DriftCorrect Module. This module uses the Zf results + and computes a non-linear equation that removes the drift + component. It uses a Levenberg-Marquardt algorithm to + solve the equation f(x) = a0 + a1 * linetime + a2 * exp(a3 + * linetime). +
    ParameterDescription
    Name + Must be set to Zd as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    ZdSkipFit + This parameter can is used to turn on/off the + non-linear fitting process described above. When + missing or set to TRUE, the result of the Zf module is + used. If FALSE, the DriftCorrect fitting is applied + using the parameters provided. +
    ZdOnFailUseLinear + This parameter can be used to select the behavior of + the data produced by the Zd module when the non-linear + fitting process has failed (typically due to + non-convergence). If set to TRUE, a linear fit to the + latter half of the Zf (buffer pixel) data is computed. + If FALSE or non-existant, the result of the Zf module + is used as is. +
    ZdMinimumLines + Minimum number lines required to apply the non-linear + fit processing. The actual number of lines used is the + total lines less TrimLines/Summing. If there are not + enough lines, then the result of the Zf module (filtered + Buffer pixel data) is simply passed through as is. This + results in the same behaviour when the ZdSkipFit + parameter is invoked. +
    MaximumIterations + The maximum number of iterations to allow the equation + to converge. +
    MaximumLog + Constrains the last term in the equation such that the + exponenent will not cause an overflow. +
    AbsoluteError + Specifies the absolute maximum error to determine + convergence. +
    RelativeError + Specifed the relative maximum error to determine + convergence. +
    GuessFilterWidth + The data used to fit the non-linear equation can be + optionally filtered before fitting. This controls the + width of the filter [Default: 17]. +
    GuessFilterIterations + This parameter controls the number of times the fit + buffer is filtered prior to non-linear fitting. Set + this to 0 to turn off this processing and use the data + as is [Default: 1]. +
    + +

    Zz Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Computes the Offset component. This module uses the + Reverse Clock region to compute the offset that is then + subtracted from the result of the Zd module. Processing + is governed by some statistical properties of this region. + The standard deviation and special counts are compared to + tolerances provided in the ReverseClockStatistics file + that will trigger the use of a constant mean value for + this correction. The result of these values are + subtracted from each sample pixel column. +
    ParameterDescription
    Name + Must be set to Zz as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    ZzFirstLine + Specifies the first of the Reverse clock region in the + input FROM file to average for dark current correction. +
    ZzLastLine + Specifies the last line in the Reverse clock region in + the input FROM file to average for dark current + correction. +
    ReverseClockStatistics +

    ReverseClockStatistics

    +
    + + + + + + + + + + + + + + + + + + +
    + This is the name of a file that contains profiles + for individual channel images and summing modes for + trigger and mean values that govern how the offset + component is determined. The default file name is + "ReverseClockStatistics.XXXX.conf" where "XXXX" is a + version number. Note that the contents of the + composed hical configuration profile is used to + provide initial values for the profile loaded out of + this file. +
    ParameterDescription
    Name + This names each image profile. The name is a + combination of FILTER(e.g., RED, BG, IR), CCD + (1-13) followed by an underscore and the channel + number (0, 1) followed by another underscore and + the summing mode (0-8). Example: RED0_1_1. +
    RevMeanTrigger + Maximum mean value of the Reverse Clock data region. + Means that exceed this value will instead use this + value as the offset correction value for all samples. +
    RevStdDevTrigger + Maximum standard deviation value of the Reverse + Clock data region. Standard deviations that exceed + this value will instead cause the RevMeanTrigger + value to be used as the offset constant for all + samples. +
    +
    RevLisTolerance + The maximum number of low instrument saturation (LIS) + special pixels that can exist in the Reverse Clock + calibration data region. If more LIS pixels exist in + this region, then the RevMeanTrigger value is used in + lieu of the processed Reverse Clock data. This value + provides the default (1) for all HiRISE images which can + be changed in subsequently loaded profiles (such as the + one loaded in the ReverseClockStatistics file). +
    RevHisTolerance + The maximum number of high instrument saturation (HIS) + special pixels that can exist in the Reverse Clock + calibration data region. If more HIS pixels exist in + this region, then the RevMeanTrigger value is used in + lieu of the processed Reverse Clock data. This value + provides the default (1) for all HiRISE images which can + be changed in subsequently loaded profiles (such as the + one loaded in the ReverseClockStatistics file). +
    RevNulTolerance + The maximum number of null (NULL) special pixels that + can exist in the Reverse Clock calibration data region. + If more NUL pixels exist in this region, then the + RevMeanTrigger value is used in lieu of the processed + Reverse Clock data. This value provides the default + (1) for all HiRISE images which can be changed in + subsequently loaded profiles (such as the one loaded in + the ReverseClockStatistics file). +
    + +

    Zb Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + The Dark Subtract module. This module uses the + Slope/Intercept Temperature profile. +
    ParameterDescription
    Name + Must be set to Zb as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    B + This the B matrix cube that is derived to remove the + dark current. In addition, it uses an elaborate + temperature model for this component. +
    SkipLines + Specifies the number of lines to skip in the Slope and + Intercept temperature profile CSV files. [Default: 0] +
    Slope + Specifies the file pattern of the slope component of the + Temperature profile. +
    Intercept + Specifies the file pattern for the intecept component of + the Temperature profile. +
    ReferenceTemperature + Specifies the reference temperature to normalize the + temperature profile equation. [Default: 21C] +
    ZbFilterWidth + Width of the smooth filter component for the temperature + profile. +
    ZbFilterIterations + Specifies the number of sequential filters to apply to + the resulting temperature profile. [Default: 1] +
    + + +

    Zg Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + +
    + Computes the Gain versus Line correction. This will read + in the line correction gain coefficients file and apply + the same non-linear equation used in the Zd module. +
    ParameterDescription
    Name + Must be set to Zg as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    SkipLines + Specifies the number of lines to skip in the gain + coefficients CSV files. [Default: 0] +
    GainLineCoefficients + Specifies the file pattern of the gain/line + coefficients. +
    + +

    Zgg Module Parameters


    + + + + + + + + + + + + + + + + + + +
    + This module loads the Gain correction matrix file. +
    ParameterDescription
    Name + Must be set to Zgg as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    G + This the G matrix cube that is derived to remove the + effects of image gain. +
    + +

    Za Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + +
    + This module loads the flat field correction matrix file. +
    ParameterDescription
    Name + Must be set to Za as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    ZaFpaTemperatureFactor + This parameter specifies the temperature dependant + gain correction factor applied to the A matrix. + + NOTE: As of 2009-09-15, this parameter is obsolete. + The temperature dependant gain is now being + maintained in a module all its own, the Zt module. + It will be removed in a future release but is + retained here for backwards compatability. + +
    A + This the A matrix cube that is derived to remove the + flat field effects of image. +
    + +

    Zt Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + This module contains parameters specific to temperature + dependant gain correction +
    ParameterDescription
    Name + Must be set to Zt as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    FpaTemperatureFactorSkipLines + Number of comment lines at the top of the + FpaTemperatureFactorFile. If not provided, the + default is no lines. This does not include the header line. +
    FpaTemperatureFactorHeader + True/False value indicates whether a header line exists + prior to data in the FpaTemperatureFactorFile CSV + file. +
    FpaTemperatureFactorFile + This CSV file contains three columns of data that + specify the temperature dependant coefficient. The + first column is the CCD (ex: RED2), the second column is + the coefficient for channel 0 and third contains the + coefficient for channel 1. +
    + +

    Ziof Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + +
    + This module computes values necessary to convert DNs to + user selected calibration unit values. +
    ParameterDescription
    Name + Must be set to Ziof as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    ZiofBinFactor + Specifies the factor that takes into account binning of + the image data. It is currently set to 1.0. +
    FilterGainCorrection + Specifies the filter dependant gain correction factor. + Note that these values are found in the RED, BG, IR + profiles and relies on the profile options to load the + proper parameter in at runtime. +
    +
    +
    + + + cube + real + output + + Output radiometrically corrected cube file + + + Use this parameter to specify the name of the output cube. + If you do not include an extension of ".cub" it will be added + automatically. + + +
    + + + + string + None + + Name of specific configuration profile to use + + +

    + This is the name of a named Profile group in the hical matrix + configuration file that users can choose for specific + selection of HiRISE calibration parameters and matrix files. +

    +

    + Note that when using this option, the additional profiles + specified in the ProfileOptions key are not applied. + This option is primarily to assist in testing and specific + application conditions. +

    +
    +
    + + string + IOF + Desired output calibration units + + A feature which calculates the average on each channel and multiplies one side with + the ratio of the averages + + + + + + + + + string + None + + Alternative path to use when logging is invoked + + +

    + This parameter is used to specify a directory path that is + intended to be used in output file specifications. OPATH can + be useful for directing specifically where log files are + written when that option is invoked. This option is + automatically added and available to all profiles and is + included in the output specifications of all log files. +

    +

    + The default behavior is to place all log files in the same + directory as the output file specifed in the TO parameter. +

    +
    +
    +
    +
    +
    diff --git a/isis/src/mro/apps/hical/tools/replacetxt b/isis/src/mro/apps/hical/tools/replacetxt new file mode 100755 index 0000000000000000000000000000000000000000..e68271fe1a858bd7e81877b8933aaf82bd2ef3ae --- /dev/null +++ b/isis/src/mro/apps/hical/tools/replacetxt @@ -0,0 +1,77 @@ +#!/usr/bin/perl -wi.bak +($progname) = ($0 =~ m#([^/]+)$#); # get the name of this program + +$usage = "Usage: $progname [-i] [-r] [-e] [-v] oldname newname filedesc +where + -i causes case to be ignored. + -r allows Perl regular expressions to be used within the pattern. + (Default is that no characters have special meaning. + Be sure to use single quotes to protect characters from + the shell.) + -e Allows newname to be an expression. This automatically turns + on -r. + -v specifies verbose mode +"; + +die "$usage\n" if @ARGV == 0; +$opt = ''; +$regexp = $verbose = 0; +while ($ARGV[0] =~ /^-([a-z]$)/) { + $switch = $1; + shift; + if ($switch eq 'i') { + $opt .= 'i'; + } elsif ($switch eq 'r') { + $regexp = 1; + } elsif ($switch eq 'e') { + $opt .= 'e'; + $regexp = 1; + } elsif ($switch eq 'v') { + $verbose = 1; + } else { + die "$usage\n"; + } +} +die "$usage\n" if @ARGV < 3; + +$opt .= 'g'; +$old = shift; +$new = shift; + +if ($verbose) { + print STDERR "Replacing $old with $new\n"; + $mode1 = $regexp ? 'Regular Expression' : 'Literal'; + $mode2 = ($opt =~ /i/) ? 'in' : ''; + print STDERR "Operating in $mode1 mode, case ${mode2}sensitive\n"; +} + +#warn "Before: old = $old\t\tnew = $new\n"; +$old = quotemeta $old unless $regexp; +$new = quotemeta $new unless $regexp; +#warn "After: old = $old\t\tnew = $new\n"; + +$command = "s#$old#$new#$opt"; +#warn "\$command = $command\n"; + +$linec = $n = 0; +$oldname = ''; +while (<>) { + if ($verbose) { + if ($ARGV ne $oldname) { # on new file + if ($oldname ne '') { + print STDERR "$oldname ($linec line(s)): Replaced $n occurrence(s)\n"; + } + $linec = 0; + $n = 0; + $oldname = $ARGV; + } + ++$linec; + } + $n += eval "$command"; + print; +} + +if ($verbose) { + print STDERR "$oldname ($linec line(s)): Replaced $n occurrence(s)\n"; + print STDERR "Done\n"; +} diff --git a/isis/src/mro/apps/hical/tsts/Makefile b/isis/src/mro/apps/hical/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hical/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hical/tsts/default/Makefile b/isis/src/mro/apps/hical/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9e7380e77a744a09ad7f5beaee09481a68bdbf37 --- /dev/null +++ b/isis/src/mro/apps/hical/tsts/default/Makefile @@ -0,0 +1,12 @@ +APPNAME = hical + +output.txt.SKIPLINES = 7 +output.txt.IGNORELINES = CONF + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/PSP_001446_1790_RED2_0.cub \ + TO=$(OUTPUT)/output.cub OPATH=. > /dev/null; + $(MV) PSP_001446_1790_RED2_0.hical.log \ + $(OUTPUT)/output.txt; diff --git a/isis/src/mro/apps/hical/tsts/dnpermicrosecs/Makefile b/isis/src/mro/apps/hical/tsts/dnpermicrosecs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0253c4afbafb1889c08910472d208feda04ee6c4 --- /dev/null +++ b/isis/src/mro/apps/hical/tsts/dnpermicrosecs/Makefile @@ -0,0 +1,12 @@ +APPNAME = hical + +output.txt.SKIPLINES = 7 +output.txt.IGNORELINES = CONF + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/PSP_001446_1790_RED2_0.cub \ + TO=$(OUTPUT)/output.cub OPATH=. UNITS=DN/US > /dev/null; + $(MV) PSP_001446_1790_RED2_0.hical.log \ + $(OUTPUT)/output.txt; diff --git a/isis/src/mro/apps/hical/tsts/dns/Makefile b/isis/src/mro/apps/hical/tsts/dns/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..dd0161d00c90aa341c0ad359bf232563cee1cbbc --- /dev/null +++ b/isis/src/mro/apps/hical/tsts/dns/Makefile @@ -0,0 +1,12 @@ +APPNAME = hical + +output.txt.SKIPLINES = 7 +output.txt.IGNORELINES = CONF + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/PSP_001446_1790_RED2_0.cub \ + TO=$(OUTPUT)/output.cub OPATH=. UNITS=DN > /dev/null; + $(MV) PSP_001446_1790_RED2_0.hical.log \ + $(OUTPUT)/output.txt; diff --git a/isis/src/mro/apps/hicalbeta/Component.h b/isis/src/mro/apps/hicalbeta/Component.h new file mode 100644 index 0000000000000000000000000000000000000000..55a4beb5b99340a31e6d4ce4eed5a949c7f87f14 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/Component.h @@ -0,0 +1,168 @@ +#if !defined(Component_h) +#define Component_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/07/16 16:38:00 $ + * $Id: Component.h,v 1.4 2008/07/16 16:38:00 skoechle Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include + +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "PvlKeyword.h" +#include "PvlGroup.h" +#include "iException.h" + +namespace Isis { + + class PvlGroup; + + /** + * @brief Component manages HiRISE calibration vectors from various sources + * + * @ingroup Utility + * @author 2007-10-05 Kris Becker + */ + class Component { + public: + friend std::ostream &operator<<(std::ostream &o, const Component &c) { + c.printOn(o); + return (o); + } + + public: + // Constructors and Destructor + Component() : _name("Component"), _data(), _history(), + _fmtWidth(DefaultWidth), _fmtPrecision(DefaultPrecision) { } + Component(const std::string &name) : _name(name), _data(), _history(), + _fmtWidth(DefaultWidth), _fmtPrecision(DefaultPrecision) { } + Component(const std::string &name, const HiHistory &history) : + _name(name), _data(), _history(history), + _fmtWidth(DefaultWidth), _fmtPrecision(DefaultPrecision) { } + Component(const std::string &name, const Component &c) : _name(name), + _data(c._data), _history(c._history), _fmtWidth(c._fmtWidth), + _fmtPrecision(c._fmtPrecision) { } + Component(const Component &c) : _name(c._name), _data(c._data), + _history(c._history), + _fmtWidth(c._fmtWidth), + _fmtPrecision(c._fmtPrecision) { } + + + /** Destructor */ + virtual ~Component() { } + + inline std::string name() const { return (_name); } + inline int size() const { return (_data.dim()); } + + virtual void Process(const Component &c) { + Process(c.ref()); + } + + virtual void Process(const HiVector &v) { + _data = v; + return; + } + + const HiVector &ref() const { return (_data); } + inline double operator()(int index) const { return (_data[index]);} + + const HiHistory &History() const { return (_history); } + + virtual void record(PvlGroup &pvl, + const std::string keyname = "ComponentHistory") + const { + pvl += _history.makekey(keyname); + return; + } + + /** + * @brief Dumps the component to a specified file + * + * @param fname Name of file to dump contents to + * + */ + void Dump(const std::string &fname) const { + Filename dumpc(fname); + std::string dumpcFile = dumpc.Expanded(); + std::ofstream ofile(dumpcFile.c_str(), std::ios::out); + if (!ofile) { + std::string mess = "Unable to open/create module dump file " + + dumpc.Expanded(); + throw iException::Message(iException::User, mess, _FILEINFO_); + } + ofile << *this; + ofile.close(); + return; + } + + + protected: + enum { DefaultWidth = 10, DefaultPrecision = 6}; + + std::string _name; //!< Name of component + HiVector _data; //!< Data vector + HiHistory _history; //!< Hierarchial component history + int _fmtWidth; //!< Default field with of double + int _fmtPrecision; //!< Default field with of double + + /** + * @brief Properly format values that could be special pixels + * + * This method applies ISIS special pixel value conventions to properly + * print pixel values. + * + * @param[in] (double) value Input value to test for specialness and print + * as requested by caller + * @param[in] (int) width Width of field in which to print the value + * @param[in] (int) prec Precision used to format the value + * @return (string) Formatted double value + */ + inline std::string formatDbl(const double &value) const { + std::ostringstream ostr; + if (IsSpecial(value)) { + ostr << std::setw(_fmtWidth) << PixelToString(value); + return (std::string(ostr.str())); + } + else { + // Its not special so format to callers specs + ostr << std::setw(_fmtWidth) << std::setprecision(_fmtPrecision) << value; + return (std::string(ostr.str())); + } + } + + virtual void printOn(std::ostream &o) const { + o << "# History = " << _history << std::endl; + o << "# Count = " << _data.dim() << std::endl; + for (int i = 0 ; i < _data.dim() ; i++) { + o << formatDbl(_data[i]) << std::endl; + } + return; + } + + }; + +} // namespace Isis +#endif diff --git a/isis/src/mro/apps/hicalbeta/DarkSubtractComp.h b/isis/src/mro/apps/hicalbeta/DarkSubtractComp.h new file mode 100644 index 0000000000000000000000000000000000000000..6ef7de829067b0c5ec8a91465c4880712e5026c8 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/DarkSubtractComp.h @@ -0,0 +1,209 @@ +#if !defined(DarkSubtractComp_h) +#define DarkSubtractComp_h +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/06/13 22:28:55 $ + * $Id: DarkSubtractComp.h,v 1.5 2008/06/13 22:28:55 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "Component.h" +#include "Filename.h" +#include "CSVReader.h" +#include "Statistics.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Computes a complex dark subtraction component + * + * This class computes the HiRISE dark correction component using a + * combination of the B matrix, slope/intercept components and temperature + * profiles. + * + * @ingroup Utility + * + * @author 2008-01-10 Kris Becker + * @internal + * @history 2008-06-13 Kris Becker - Added PrintOn method to produce more + * detailed data dump; Added computation of statistics + * + */ + class DarkSubtractComp : public Component { + + public: + // Constructors and Destructor + DarkSubtractComp() : Component("DarkSubtract") { } + DarkSubtractComp(const HiCalConf &conf) : Component("DarkSubtract") { + init(conf); + } + + /** Destructor */ + virtual ~DarkSubtractComp() { } + + /** + * @brief Return statistics for filtered - raw Buffer + * + * @return const Statistics& Statistics class with all stats + */ + const Statistics &Stats() const { return (_stats); } + + private: + int _tdi; + int _bin; + int _ccd; + int _channel; + + HiVector _BM; + HiVector _slope; + HiVector _intercept; + HiVector _tempProf; + + double _refTemp; + + Statistics _stats; + + void init(const HiCalConf &conf) { + _history.clear(); + DbProfile prof = conf.getMatrixProfile(); + _history.add("Profile["+ prof.Name()+"]"); + _tdi = ToInteger(prof("Tdi")); + _bin = ToInteger(prof("Summing")); + int samples = ToInteger(prof("Samples")); + + // Get B matrix and slope/intercept parameters + _BM = conf.getMatrix("B", prof); + _history.add("LoadMatrix(B[" + conf.getMatrixSource("B",prof) + + "],Band[" + ToString(conf.getMatrixBand(prof)) + "])"); + + int skip = ConfKey(prof, "SkipLines", 0); + _slope = loadCsv(conf.getMatrixSource("Slope",prof), _tdi, skip); + _intercept = loadCsv(conf.getMatrixSource("Intercept",prof), _tdi, skip); + + _refTemp = ConfKey(prof, "FpaReferenceTemperature", 21.0); + + // Smooth/filter if requested + int width = ConfKey(prof,"ZbFilterWidth",3); + int iters = ConfKey(prof,"ZbFilterIterations",0); + LowPassFilterComp smooth(width, iters); + _history.add("Smooth(Width["+ToString(width)+"],Iters["+ToString(iters)+"])"); + + // Set average tempuratures + double fpa_py_temp = ToDouble(prof("FpaPositiveYTemperature")); + double fpa_my_temp = ToDouble(prof("FpaNegativeYTemperature")); + double temp = (fpa_py_temp+fpa_my_temp) / 2.0; + _history.add("BaseTemperature[" + ToString(temp) + "]"); + + // Filter the slope/intercept + smooth.Process(_slope); + _slope = smooth.ref(); + + smooth.Process(_intercept); + _intercept = smooth.ref(); + + HiVector t_prof(_slope.dim()); + for (int i = 0 ; i < _slope.dim() ; i++) { + t_prof[i] = _intercept[i] + _slope[i] * temp; + } + + _tempProf = rebin(t_prof, samples); + _history.add("Rebin(T_Profile," + ToString(t_prof.dim()) + "," + + ToString(samples) +")"); + + HiVector dc(samples); + double linetime = ToDouble(prof("ScanExposureDuration")); + double scale = linetime * 1.0E-6 * (_bin*_bin) * + (20.0*103.0/89.0 + _tdi); + double baseT = HiTempEqn(_refTemp); + for (int j = 0 ; j < samples ; j++) { + dc[j] = _BM[j] * scale * HiTempEqn(_tempProf[j]) / baseT; + } + + // Filter it yet again + smooth.Process(dc); + _data = smooth.ref(); + + // Compute statistics and record to history + _stats.Reset(); + for ( int i = 0 ; i < _data.dim() ; i++ ) { + _stats.AddData(_data[i]); + } + _history.add("Statistics(Average["+ToString(_stats.Average())+ + "],StdDev["+ToString(_stats.StandardDeviation())+"])"); + return; + } + + HiVector loadCsv(const std::string &fname, int tdi, int skip) { + Filename csvfile(fname); + CSVReader csv(csvfile.Expanded(), true, skip); + iString myHead = "TDI " + iString(tdi); + + CSVReader::CSVAxis header(csv.getHeader()); + for (int i = 0 ; i < header.dim() ; i++) { + if (iString::Equal(myHead,iString(header[i]).Trim(" \r\t"))) { + _history.add("LoadCSV("+ fname +",TDI[" + ToString(tdi) + + "],Skip["+ ToString(skip) + "],Column[" + + ToString(i) + "])") ; + return (convert(csv.getColumn(i))); + } + } + + std::ostringstream mess; + mess << "Column " << myHead << " not found in file " << fname + << "!"; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + HiVector convert(const CSVReader::CSVAxis &v) const { + HiVector newV(v.dim()); + for ( int i = 0 ; i < v.dim() ; i++ ) { + newV[i] = ToDouble(v[i]); + } + return (newV); + } + + virtual void printOn(std::ostream &o) const { + o << "# History = " << _history << std::endl; + // Write out the header + o << std::setw(_fmtWidth) << "BMatrix" + << std::setw(_fmtWidth+1) << "RebinTemp" + << std::setw(_fmtWidth+1) << "Dark\n"; + + for (int i = 0 ; i < _data.dim() ; i++) { + o << formatDbl(_BM[i]) << " " + << formatDbl(_tempProf[i]) << " " + << formatDbl(_data[i]) << std::endl; + } + return; + } + + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hicalbeta/DriftBuffer.h b/isis/src/mro/apps/hicalbeta/DriftBuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..cb30f2821db909c0f090d7a372e359849ec4105a --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/DriftBuffer.h @@ -0,0 +1,130 @@ +#if !defined(DriftBuffer_h) +#define DriftBuffer_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/13 22:28:55 $ + * $Id: DriftBuffer.h,v 1.2 2008/06/13 22:28:55 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include + + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "Component.h" +#include "SplineFillComp.h" +#include "LowPassFilterComp.h" +#include "Statistics.h" +#include "SpecialPixel.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Loads and processes Buffer calibration data + * + * This class loads and processes the Buffer data from a HiRISE image for + * drift correction purposes. Additional processing may occur in subsequent + * modules. + * + * @ingroup Utility + * + * @author 2008-06-10 Kris Becker + */ + class DriftBuffer : public Component { + + public: + // Constructors and Destructor + DriftBuffer() : Component("DriftBuffer") { } + DriftBuffer(HiCalData &cal, const HiCalConf &conf) : + Component("DriftBuffer") { + init(cal, conf); + } + + /** Destructor */ + virtual ~DriftBuffer() { } + + /** + * @brief Return statistics for filtered - raw Buffer + * + * @return const Statistics& Statistics class with all stats + */ + const Statistics &Stats() const { return (_stats); } + + private: + HiVector _buffer; + Statistics _stats; + + void init(HiCalData &cal, const HiCalConf &conf) { + DbProfile prof = conf.getMatrixProfile(); + _history.clear(); + _history.add("Profile["+ prof.Name()+"]"); + + int samp0 = ConfKey(prof,"ZfFirstSample",0); + int sampN = ConfKey(prof,"ZfLastSample",11); + _buffer = averageSamples(cal.getBuffer(), samp0, sampN); + _history.add("AveCols(Buffer["+ToString(samp0)+","+ToString(sampN)+"])"); + + // Smooth/filter the averages + LowPassFilterComp bufter(_buffer, _history, + ConfKey(prof,"ZfFilterWidth",201), + ConfKey(prof,"ZfFilterIterations",2)); + // If need be, fill the data with a cubic spline + SplineFillComp spline(bufter); + _data = spline.ref(); + _history = spline.History(); + + // Compute statistics and record to history + _stats.Reset(); + for ( int i = 0 ; i < _data.dim() ; i++ ) { + // Spline guarantees _data is non-null! + if ( !IsSpecial(_buffer[i]) ) { + _stats.AddData(_data[i] - _buffer[i]); + } + } + _history.add("Statistics(Average["+ToString(_stats.Average())+ + "],StdDev["+ToString(_stats.StandardDeviation())+"])"); + return; + } + + virtual void printOn(std::ostream &o) const { + o << "# History = " << _history << std::endl; + // Write out the header + o << std::setw(_fmtWidth) << "RawBuffer" + << std::setw(_fmtWidth+1) << "Filtered\n"; + + for (int i = 0 ; i < _data.dim() ; i++) { + o << formatDbl(_buffer[i]) << " " + << formatDbl(_data[i]) << std::endl; + } + return; + } + + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hicalbeta/DriftCorrect.cpp b/isis/src/mro/apps/hicalbeta/DriftCorrect.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d671ca9d8faa3ad0a4fe35c804127da1fe1f275d --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/DriftCorrect.cpp @@ -0,0 +1,295 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/06/11 00:56:51 $ + * $Id: DriftCorrect.cpp,v 1.4 2008/06/11 00:56:51 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include +#include + +#include "DriftCorrect.h" +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "LeastSquares.h" +#include "LowPassFilterComp.h" +#include "MultivariateStatistics.h" +#include "iException.h" + +using namespace std; + +namespace Isis { + + DriftCorrect::DriftCorrect(const HiCalConf &conf) : + NonLinearLSQ(), Component("DriftCorrect") { + DbProfile prof = conf.getMatrixProfile(); + _history.add("Profile["+ prof.Name()+"]"); + _timet.setBin(ToInteger(prof("Summing"))); + _timet.setLineTime(ToDouble(prof("ScanExposureDuration"))); + + + _skipFit = IsEqual(ConfKey(prof, "ZdSkipFit", std::string("TRUE")), "TRUE"); + _useLinFit = IsTrueValue(prof, "ZdOnFailUseLinear"); + + _absErr = ConfKey(prof, "AbsoluteError", 1.0E-4); + _relErr = ConfKey(prof, "RelativeError", 1.0E-4); + + _sWidth = ConfKey(prof, "GuessFilterWidth", 17); + _sIters = ConfKey(prof, "GuessFilterIterations", 1); + + if ( prof.exists("MaximumIterations") ) { + setMaxIters(ToInteger(prof("MaximumIterations"))); + } + + _maxLog = ConfKey(prof, "MaximumLog", 709.0); + _badLines = ToInteger(prof("TrimLines"))/ToInteger(prof("Summing")); + _minLines = ConfKey(prof,"ZdMinimumLines", 100); + + string histstr = "DriftCorrect(AbsErr[" + ToString(_absErr) + + "],RelErr[" + ToString(_relErr) + + "],MaxIter[" + ToString(maxIters()) + "])"; + _history.add(histstr); + } + + HiVector DriftCorrect::Solve(const HiVector &d) { + ostringstream hist; + _data = d; + if ( _skipFit || (!gotGoodLines(d))) { + _b2 = _data; + _coefs = HiVector(4, 0.0); + _uncert = _coefs; + _cc = HiVector(2, 0.0); + _chisq = 0.0; + if ( !gotGoodLines(d) ) { + hist << "NotEnoughLines(GoodLines[" << goodLines(d) + << "],MinimumLines[" << _minLines << "]);"; + } + + hist << "SkipFit(TRUE: Not using LMFit)"; + _history.add(hist.str()); + } + else { + hist << "Fit("; + _b2 = HiVector(goodLines(_data)); + if ( success(curvefit()) ) { + _coefs = coefs(); + _uncert = uncert(); + hist << "Solved,#Iters[" << nIterations() << "],ChiSq[" << Chisq() + << "],DoF[" << DoF() << "])"; + _history.add(hist.str()); + _history.add("a0("+ToString(_coefs[0])+"+-"+ToString(_uncert[0])+")"); + _history.add("a1("+ToString(_coefs[1])+"+-"+ToString(_uncert[1])+")"); + _history.add("a2("+ToString(_coefs[2])+"+-"+ToString(_uncert[2])+")"); + _history.add("a3("+ToString(_coefs[3])+"+-"+ToString(_uncert[3])+")"); + } + else { + // Punt, fit a straight line to the data + _cc = poly_fit(d); + HiVector a(4); + a[0] = _cc[0]; + a[1] = _cc[1]; + a[2] = 0.0; + a[3] = 0.0; + _coefs = a; + + hist << "Failed::Reason("<< statusstr() << "),#Iters[" + << nIterations() << "])"; + _history.add(hist.str()); + _history.add("a0("+ToString(_coefs[0])+")"); + _history.add("a1("+ToString(_coefs[1])+")"); + _history.add("a2("+ToString(_coefs[2])+")"); + _history.add("a3("+ToString(_coefs[3])+")"); + if ( _useLinFit ) { + _history.add("OnFailureUse(LinearFit(Zf))"); + } + else { + _skipFit = true; + _history.add("OnFailureUse(ZfBuffer)"); + } + } + } + return (Yfit()); + } + + /** + * @brief Compute the initial guess of the fit + * + * This method provides the non-linear fit with an initial guess of the + * solution. It involves a linear fit to the latter half of the data to + * provide the first two coefficents, the difference of the averages of the + * residuals at both ends of the data set and 5 times the last line time as + * the final (fourth) element...a bit involved really. + * + * @return NLVector 4-element vector of the initial guess coefficients + */ + NonLinearLSQ::NLVector DriftCorrect::guess() { + int n = _data.dim(); + int nb = n - _badLines; + + HiVector b1 = _data.subarray(0, nb-1); + LowPassFilterComp gfilter(b1, _history, _sWidth, _sIters); + + int nb2 = nb/2; + _b2 = gfilter.ref(); + HiVector cc = poly_fit(_b2.subarray(nb2,_b2.dim()-1), nb2-1); + + // Compute the 3rd term guess by getting the average of the residual + // at both ends of the data set. + Statistics s; + + // Get the head of the data set + int n0 = MIN(nb, 20); + for ( int k = 0 ; k < n0 ; k++ ) { + double d = _b2[k] - (cc[0] + cc[1] * _timet(k)); + s.AddData(&d, 1); + } + double head = s.Average(); + + // Get the tail of the data set + s.Reset(); + n0 = (int) (0.9 * nb); + for ( int l = n0 ; l < nb ; l++ ) { + double d = _b2[l] - (cc[0] + cc[1] * _timet(l)); + s.AddData(&d, 1); + } + double tail = s.Average(); + + // Populate the guess with the results + NLVector g(4, 0.0); + g[0] = cc[0]; + g[1] = cc[1]; + g[2] = head-tail; + g[3] = -5.0/_timet(nb-1); + _guess = g; + _history.add("Guess["+ToString(_guess[0])+ ","+ + ToString(_guess[1])+ ","+ + ToString(_guess[2])+ ","+ + ToString(_guess[3])+ "]"); + return (g); + } + + int DriftCorrect::checkIteration(const int Iter, const NLVector &fitcoefs, + const NLVector &uncerts, double cplxconj, + int Istatus) { + _chisq = pow(cplxconj, 2.0); + return (Istatus); + } + + NonLinearLSQ::NLVector DriftCorrect::f_x(const NLVector &a) { + double a0 = a[0]; + double a1 = a[1]; + double a2 = a[2]; + double a3 = a[3]; + + int n = _b2.dim(); + NLVector f(n); + for (int i = 0 ; i < n ; i++) { + double lt = _timet(i); + double et = a3 * lt; + double Yi = a0 + (a1 * lt) + a2 * exp(MIN(et,_maxLog)); + f[i] = (Yi - _b2[i]); + } + return (f); + } + + NonLinearLSQ::NLMatrix DriftCorrect::df_x(const NLVector &a) { + // double a0 = a[0]; + // double a1 = a[1]; + double a2 = a[2]; + double a3 = a[3]; + + int n = _b2.dim(); + NLMatrix J(n, 4); + for (int i = 0; i < n; i++) { + double lt = _timet(i); + double et = a3 * lt; + double p0 = exp (MIN(et,_maxLog)); + J[i][0] = 1.0; + J[i][1] = lt; + J[i][2] = p0; + J[i][3] = a2 * lt * p0; + } + return (J); + } + + HiVector DriftCorrect::Yfit() const { + if ( _skipFit || (!gotGoodLines(_data))) { + return (_data.copy()); + } + else { + HiVector dcorr(_data.dim()); + HiVector a = _coefs; + for ( int i = 0 ; i < dcorr.dim() ; i++ ) { + double lt = _timet(i); + dcorr[i] = a[0] + (a[1] * lt) + a[2] * exp(a[3] * lt); + } + return (dcorr); + } + } + + HiVector DriftCorrect::Normalize(const HiVector &v) { + HiVector vNorm(v.dim()); + double v0 = v[0]; + for ( int i = 0 ; i < v.dim() ; i++ ) { + vNorm[i] = v[i] - v0; + } + _history.add("Normalize[" + ToString(v0) + "]"); + return (vNorm); + } + + HiVector DriftCorrect::poly_fit(const HiVector &d, const double line0) const { + // Needs a linear fit to latter half of data + MultivariateStatistics fit; + int n = d.dim(); + for ( int i = 0 ; i < n ; i++ ) { + double t = _timet(line0+i); + fit.AddData(&t, &d[i], 1); + } + NLVector cc(2); + fit.LinearRegression(cc[0], cc[1]); + return (cc); + } + + void DriftCorrect::printOn(std::ostream &o) const { + o << "# History = " << _history << endl; + // Write out the header + o << setw(_fmtWidth) << "Line" + << setw(_fmtWidth+1) << "Time" + << setw(_fmtWidth+1) << "Data" + << setw(_fmtWidth+1) << "Fit\n"; + + HiVector fit = Yfit(); + for (int i = 0 ; i < _data.dim() ; i++) { + o << formatDbl(i) << " " + << formatDbl(_timet(i)) << " " + << formatDbl(_data[i]) << " " + << formatDbl(fit[i]) << endl; + } + return; + } + +} // namespace Isis + + diff --git a/isis/src/mro/apps/hicalbeta/DriftCorrect.h b/isis/src/mro/apps/hicalbeta/DriftCorrect.h new file mode 100644 index 0000000000000000000000000000000000000000..301ce6946918b24462fef226a3f056f2e7c1eb9c --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/DriftCorrect.h @@ -0,0 +1,162 @@ +#if !defined(DriftCorrect_h) +#define DriftCorrect_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/05/23 19:15:17 $ + * $Id: DriftCorrect.h,v 1.4 2008/05/23 19:15:17 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include + +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "NonLinearLSQ.h" +#include "Component.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Computes non-linear lsq fit of HiRISE Drift + * + * This class is best used with individual HiRISE images as the number of + * lines is critical to proper use. It is best applied by getting the buffer + * as a reference and applying it during systematic processing. There really + * is no direct method to handle line access. + * + * @ingroup Utility + * + * @author 2007-11-07 Kris Becker + * @internal + * @history 2008-05-23 Kris Becker Added the ZdOnFailUseLinear option + */ + class DriftCorrect : public NonLinearLSQ, public Component { + + public: + DriftCorrect(const HiCalConf &conf); + virtual ~DriftCorrect() { } + + /** + * @brief Set binning/summing mode + * + * @param bin Summing mode of observatio + */ + void setBin(int bin) { _timet.setBin(bin); } + + /** + * @brief Set scan line time + * + * @param ltime Scan line time + */ + void setLineTime(double ltime) { _timet.setLineTime(ltime); } + + /** + * @brief Returns the size of the data buffer + * + * This is the size of the original data buffer. + * + * @see nSize() + * @return int Size of the input buffer + */ + inline int size() const { return (_data.dim()); } + + /** + * @brief Returns the size of the fitted buffer + * + * \b Important: This returns the size of the buffer being + * fitted and not the size of original data buffer. This is + * a requirement of the NonLinearLSQ class. USE WITH + * CAUTION! + * + * + * @return int Size of buffer being fitted + */ + int nSize() const { return (_b2.dim()); } + + /** + * @brief Number of parameter to be fitted + * + * This is the number of parameters that DriftCorrect needs to + * fit. This functin is a requirement of the NonLinearLSQ + * class. + * + * @return int Number of parameter to fit + */ + int nParms() const { return (4); } + + /** Sets the absolute error parameter */ + void setabsErr(double absError) { _absErr = absError; } + /** Sets the relative error parameter */ + void setrelErr(double relError) { _relErr = relError; } + /** Returns the current value of the absolute error */ + double absErr() const { return (_absErr); } + /** Returns the current value of the relative error */ + double relErr() const { return (_relErr); } + + HiVector Solve(const HiVector &d); + NLVector guess(); + int checkIteration(const int Iter, const NLVector &fitcoefs, + const NLVector &uncerts, double cplxconj, + int Istatus); + + NLVector f_x(const NLVector &a); + NLMatrix df_x(const NLVector &a); + + /** Returns the Chi-Square value of the fit solution */ + double Chisq() const { return (_chisq); } + /** Returns the Degrees of Freedom */ + int DoF() const { return (nSize() - nParms()); } + + HiVector Yfit() const; + HiVector Normalize(const HiVector &v); + + private: + HiLineTimeEqn _timet; // This is the X data set + HiVector _data; // Typically will be the HiRISE buffer data + HiVector _b2; // Data buffer used in fitting + double _absErr; // Absolute error convergence test + double _relErr; // Relative error convergence test + double _maxLog; // Maximum log value to constrain + int _badLines; // Exclude lines at end of buffer + int _sWidth; // Width of guestimate filter + int _sIters; // Filter interations + bool _skipFit; // Skip fitting and pass input through + bool _useLinFit; // Use linear fit on failure of LM, else Zf + int _minLines; // Minimum number of lines to fit (Default: 100) + HiVector _cc; // Parameter of 2-D fit + HiVector _guess; // Initial guestimate of solutions + HiVector _coefs; // Coefficients of solution + HiVector _uncert; // Uncertanties + double _chisq; // ChiSq of NonLinear equation + + HiVector poly_fit(const HiVector &d, const double line0 = 0.0) const; + virtual void printOn(std::ostream &o) const; + int goodLines(const HiVector &d) const { return (d.dim() - _badLines); } + bool gotGoodLines(const HiVector &d) const { + return (goodLines(d) >= _minLines); + } + }; + +} // namespace Isis +#endif + + diff --git a/isis/src/mro/apps/hicalbeta/FlatFieldComp.h b/isis/src/mro/apps/hicalbeta/FlatFieldComp.h new file mode 100644 index 0000000000000000000000000000000000000000..e94d477b12296bf7bdb98107c05609cbada2a550 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/FlatFieldComp.h @@ -0,0 +1,102 @@ +#if !defined(FlatFieldComp_h) +#define FlatFieldComp_h +/** + * @file + * $Revision: 1.4 $ + * $Date: 2009/09/15 21:56:44 $ + * $Id: FlatFieldComp.h,v 1.4 2009/09/15 21:56:44 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "Component.h" +#include "Filename.h" +#include "CSVReader.h" +#include "Statistics.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Za Module - Computes flat field correction for each sample (column) + * + * This class computes the HiRISE flat field correction component using the A + * matrix. + * + * @ingroup Utility + * + * @author 2008-03-04 Kris Becker + * @history 2009-09-14 Kris Becker Removed temperature components and placed + * them in the Zt (TempGainCorrect) module. + */ + class FlatFieldComp : public Component { + + public: + // Constructors and Destructor + FlatFieldComp() : Component("FlatFieldComp") { } + FlatFieldComp(const HiCalConf &conf) : Component("FlatField") { + init(conf); + } + + /** Destructor */ + virtual ~FlatFieldComp() { } + + /** + * @brief Return statistics A matrix corection + * + * @return const Statistics& Statistics class with all stats + */ + const Statistics &Stats() const { return (_stats); } + + private: + std::string _amatrix; + Statistics _stats; // Stats Results + + void init(const HiCalConf &conf) { + _history.clear(); + DbProfile prof = conf.getMatrixProfile(); + _history.add("Profile["+ prof.Name()+"]"); + + // Get parameters from gainVline coefficients file + _amatrix = conf.getMatrixSource("A", prof); + _data = conf.getMatrix("A",prof); + _history.add("LoadMatrix(A[" + _amatrix + + "],Band[" + ToString(conf.getMatrixBand(prof)) + "])"); + + _stats.Reset(); + for ( int i = 0 ; i < _data.dim() ; i++ ) { + _stats.AddData(_data[i]); + } + + _history.add("Statistics(Average["+ToString(_stats.Average())+ + "],StdDev["+ToString(_stats.StandardDeviation())+"])"); + return; + } + + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hicalbeta/GainVLineComp.h b/isis/src/mro/apps/hicalbeta/GainVLineComp.h new file mode 100644 index 0000000000000000000000000000000000000000..bac6fe1606a72b7795d088721ae1a2a60d80b1e7 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/GainVLineComp.h @@ -0,0 +1,138 @@ +#if !defined(GainVLineComp_h) +#define GainVLineComp_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/05/14 21:07:22 $ + * $Id: GainVLineComp.h,v 1.2 2008/05/14 21:07:22 slambright Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "Component.h" +#include "Filename.h" +#include "CSVReader.h" + +#include "iException.h" + +namespace Isis { + + /** + * @brief Computes a gain correction for each line + * + * This class computes the HiRISE dark correction component using a + * combination of the B matrix, slope/intercept components and temperature + * profiles. + * + * @ingroup Utility + * + * @author 2008-01-10 Kris Becker + */ + class GainVLineComp : public Component { + + public: + // Constructors and Destructor + GainVLineComp() : Component("GainVLineComp") { } + GainVLineComp(const HiCalConf &conf) : Component("GainVLine") { + init(conf); + } + + /** Destructor */ + virtual ~GainVLineComp() { } + + private: + std::string _gdfile; + int _ccd; + int _channel; + HiVector _coefs; + + void init(const HiCalConf &conf) { + _history.clear(); + DbProfile prof = conf.getMatrixProfile(); + _history.add("Profile["+ prof.Name()+"]"); + _ccd = CpmmToCcd(ToInteger(prof("CpmmNumber"))); + _channel = ToInteger(prof("ChannelNumber")); + + // Get parameters from gainVline coefficients file + int skip = ConfKey(prof, "SkipLines", 0); + _gdfile = conf.getMatrixSource("GainLineCoefficients", prof); + _coefs = loadCsv(_gdfile, _ccd, _channel, skip); + + _history.add("Coefs["+ToString(_coefs[0])+ ","+ + ToString(_coefs[1])+ ","+ + ToString(_coefs[2])+ ","+ + ToString(_coefs[3])+ "]"); + + int bin = ToInteger(prof("Summing")); + double linetime = ToDouble(prof("ScanExposureDuration")); + HiLineTimeEqn timet(bin, linetime); + int nlines = ToInteger(prof("Lines")); + + HiVector gainV(nlines); + for ( int i = 0 ; i < nlines ; i++ ) { + double lt = timet(i); + gainV[i] = _coefs[0] + (_coefs[1] * lt) + + _coefs[2] * exp(_coefs[3] * lt); + } + + _data = gainV; + return; + } + + + HiVector loadCsv(const std::string &fname, int ccd, int channel, + int skip) { + Filename csvfile(fname); + CSVReader csv(csvfile.Expanded(), true, skip); + CSVReader::CSVIntVector ccds = csv.convert(csv.getColumn(0)); + CSVReader::CSVIntVector chans = csv.convert(csv.getColumn(1)); + + for (int i = 0 ; i < ccds.dim() ; i++) { + if ( (ccds[i] == ccd) && (chans[i] == channel) ) { + // Got it, extract the indicated row and translate + CSVReader::CSVAxis coefRow = csv.getRow(i); + HiVector coef(4); + for (int c = 0 ; c < 4 ; c++) { + coef[c] = (coefRow[c+2].Trim(" \r\n\t")).ToDouble(); + } + _history.add("LoadCSV("+ fname +",Ccd[" + ToString(ccd) + + "],Channel[" + ToString(channel) + + "],Skip["+ ToString(skip) + "],Row[" + + ToString(i) + "])") ; + return (coef); + } + } + + // Did not find the proper row + std::ostringstream mess; + mess << "Cannot find Ccd/Channel (" << _ccd << "/" << _channel + << ") match in CSV file " << fname; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hicalbeta/HiBlob.h b/isis/src/mro/apps/hicalbeta/HiBlob.h new file mode 100644 index 0000000000000000000000000000000000000000..a1e086805768c349a7d9c5bbde2ff646559b75aa --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/HiBlob.h @@ -0,0 +1,76 @@ +#if !defined(HiBlob_h) +#define HiBlob_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/05/12 18:17:33 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "Blobber.h" +#include "HiCalTypes.h" + +namespace Isis { + +/** + * @brief BLOB extraction class + * + * This class provides access and processing of HiRISE data as + * stored in an ISIS BLOB (Table). + * + * Note that the file provided must be a HiRISE ISIS cube file + * that is freshly converted from a PDS compatable EDR + * (hi2isis). It must contain an ISIS Table named "HiRISE + * Calibration Image". From that table, data is extracted from + * the "Calibration" field. + * + * @ingroup MarsReconnaissanceOrbiter + * + * @author 2007-10-09 Kris Becker + * @see Blobber + * + * @internal + * @history 2008-05-12 Steven Lambright - Removed references to CubeInfo + */ + class HiBlob : public Blobber { + public: + /** + * @brief Default, mostly useless constructor + */ + HiBlob(): Blobber() { } + + /** + * @brief Constructor providing interface to an ISIS Cube object + */ + HiBlob(Cube &cube, const std::string &tblname, + const std::string &field, + const std::string &name = "HiBlob") : + Blobber(cube, tblname, field, name) { } + + /** Destructor */ + virtual ~HiBlob() { } + + /** Return a reference to the data */ + const HiMatrix &buffer() const { return (ref()); } + + }; +}; + +#endif diff --git a/isis/src/mro/apps/hicalbeta/HiCalConf.cpp b/isis/src/mro/apps/hicalbeta/HiCalConf.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f31431d5172c2e282a0c91893192c2a5ec70c29 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/HiCalConf.cpp @@ -0,0 +1,602 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2009/12/29 23:03:52 $ + * $Id: HiCalConf.cpp,v 1.5 2009/12/29 23:03:52 ehyer Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include + +#include "HiCalConf.h" +#include "HiCalUtil.h" +#include "Pvl.h" +#include "Filename.h" +#include "Cube.h" +#include "Brick.h" +#include "SpecialPixel.h" +#include "iString.h" +#include "iException.h" + +#include "naif/SpiceUsr.h" + +using namespace std; + +namespace Isis { + +bool HiCalConf::_naifLoaded = false; + +/** + * @brief Default constructor for HiCalConf + */ + HiCalConf::HiCalConf() : DbAccess() { + _profName.clear(); + init(); + } + + + /** + * @brief Construct from a HiRISE label + * @param label Label from HiRISE cube file + */ + HiCalConf::HiCalConf(Pvl &label) : DbAccess() { + _profName.clear(); + init(label); + } + + /** + * @brief Construct from HiRISE label and configuration file + * + * @param label Label from HiRISE cube file + * @param conf Name of configuration file to use + */ + HiCalConf::HiCalConf(Pvl &label, const std::string &conf) : + DbAccess(Pvl(filepath(conf)).FindObject("Hical", PvlObject::Traverse)) { + _profName.clear(); + init(label); + } + + /** + * @brief Define label to initialize parameters from + * + * @param label Label from HiRISE cube file + */ + void HiCalConf::setLabel(Pvl &label) { + init(label); + return; + } + + /** + * @brief Resolve a file path validating existance + * + * This method determines if a filepath is versioned (as indicated with one or + * more '?') and returns the expanded file name \b only. It does not expand + * the path portion of the filespec. This is so to make use of the results of + * this method in reporting files in labels...to make it tidy. + * + * @param fname File specification with or without versioning patterns + * + * @return string Expanded filename but not the filepath + */ + string HiCalConf::filepath(const std::string &fname) const { + string::size_type start = fname.find_first_of("?"); + if (start != string::npos) { + Filename efile(fname); + + string path(efile.OriginalPath()); + if (!path.empty()) path += "/"; + + efile.HighestVersion(); + + return (path + efile.Name()); + } + return (fname); + } + + + /** + * @brief Establish the configuration file used for calibration parameters + * + * This file can be established at any point in the processing as parameters + * are resolved as needed (lazy instantiation). One must be established + * before any calibration can take place. + * + * @param conf Name of configuration file to use + */ + void HiCalConf::setConf(const std::string &conf) { + load(Pvl(filepath(conf)).FindObject("Hical", PvlObject::Traverse)); + } + + /** + * @brief Selects a profile other than the default + * + * Use of this method is to explicitly select a named profile in the + * configuration file. If this is used, additional profile options are not + * loaded. + * + * @param profile Name of existing profile in the configuration file + */ + void HiCalConf::selectProfile(const std::string &profile) { + _profName = profile; + return; + } + + /** + * @brief Returns the fully optioned profile name used + * + * This method returns the fully optioned profile used to define calibration + * processing parameters. It has the form: + * @code + * default+[option1]+[option2]+...+[optionN] + * @endcode + * This specifies the name of the default profile and any additional option + * profile loaded in the indicated order. + * + * @return string Combined profile name + */ + string HiCalConf::getProfileName() const { + return (getMatrixProfile().Name()); + } + + /** + * @brief Returns the named expanded matrix file reference + * + * This method returns the name of a matrix file reference variable from the + * \b Matrices keyword as determined from the fully option profile. It then + * expands the filename portion (not the filepath!) and returns the result as + * a string for subsequent use. See also getMatrixList and getMatrix. + * + * @param name Name of Matrix to resolve. It must be one in the \b Matrices + * keyword from the configuration file + * + * @return std::string The expanded file name reference for the matrix + */ + std::string HiCalConf::getMatrixSource(const std::string &name) const { + return (getMatrixSource(name, getMatrixProfile())); + } + + /** + * @brief Returns the named expanded matrix file reference + * + * This method returns the name of a matrix file reference variable from the + * \b Matrices keyword as determined from the specified profile. It then + * expands the filename portion (not the filepath!) and returns the result as + * a string for subsequent use. See also getMatrixList and getMatrix. + * + * @param name Name of Matrix to resolve. It must be one in the \b Matrices + * keyword from the configuration file + * @param matconf Profile to extract the named matrix source from + * + * @return std::string The expanded file name reference for the matrix + */ + std::string HiCalConf::getMatrixSource(const std::string &name, + const DbProfile &matconf) const { + + std::string mfile = parser(matconf.value(name), + getList(matconf,"OptionKeywords"), + matconf); + +// Translate and return + return (filepath(mfile)); + } + + HiVector HiCalConf::getMatrix(const std::string &name, + int expected_size) const { + return (getMatrix(name,getMatrixProfile(), expected_size)); + } + + + std::string HiCalConf::resolve(const std::string &composite, + const DbProfile &matconf) const { + return (parser(composite,getList(matconf,"OptionKeywords"), matconf)); + } + + + + /** + * @brief Returns the named matrix from the specified file reference + * + * The matrix specified in the name parameter must exist in the \b Matrices + * keyword in the \b Hical object of the configuration file. A fully option + * profile is created within this method and the keyword of the named variable + * is retreived from it. The fully qualified filepath is generated to + * finally resolve to a multi-band, single line, Isis cube file. A specific + * band is extracted from the cube file as determined by the CCD channel + * (provide by the getMatrixBand method) and returned in a HiVector data + * array. + * + * Note that the caller can specify the number of samples expected from the + * matrix cube in the expected_size parameter if it is non-zero. Once the + * matrix cube is opened, the number of samples is checked against this + * parameter and if they do not match, an exception is thrown. + * + * @param name Name of matrix to retreive + * @param profile Specfied profile providing all parameters + * @param expected_size Expected number of samples in the matrix cube + * + * @return HiCalConf::HiVector Returns the extracted band from the cube + */ + HiVector HiCalConf::getMatrix(const std::string &name, + const DbProfile &profile, + int expected_size) const { + + std::string mfile = getMatrixSource(name, profile); + +// Crack the file and read the appropriate band + Cube cube; + cube.Open(mfile); + +// Check for proper size if specifeid + if (expected_size != 0) { + if (cube.Samples() != expected_size) { + ostringstream mess; + mess << "Specifed matrix (" << name + << ") from file \"" << mfile + << "\" does not have expected samples (" << expected_size + << ") but has " << cube.Samples(); + cube.Close(); + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + } + +// Read the specifed region + Brick bandio(cube.Samples(), 1, 1, Real); + bandio.SetBasePosition(1,1,getMatrixBand(profile)); + cube.Read(bandio); + +// Now create the output buffer with some TNT funny business + HiVector temp(cube.Samples(), bandio.DoubleBuffer()); + HiVector out(cube.Samples()); + out.inject(temp); + cube.Close(); + return (out); + } + + /** + * @brief Returns a named scalar constant + * + * This method returns a named scalar constant parameter retrieved from the + * configuration file through a fully optioned profile. This keyword does not + * necessarily have to exist in the \b Scalars keyword in the \b Hical object, + * but is required to be a floating point value (or values). The result is + * returned as a HiVector data array. + * + * @param name Name of scalar constant to return + * @param expected_size Expected size of constant if non-zero + * + * @return HiCalConf::HiVector Values of scalar constants + */ + HiVector HiCalConf::getScalar(const std::string &name, + const DbProfile &profile, + int expected_size) const { + int nvals = profile.count(name); + + // Check for proper size if specifeid + if (expected_size != 0) { + if (nvals != expected_size) { + ostringstream mess; + mess << "Specifed scalar (" << name + << ") does not have expected size (" << expected_size + << ") but has " << nvals; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + } +// All is OK + HiVector mtx(nvals, Null); + for (int i = 0 ; i < nvals ; i++) { + mtx[i] = ToDouble(profile(name, i)); + } + return (mtx); + } + + /** + * @brief Computes the distance from the Sun to the observed body + * + * This method requires the appropriate NAIK kernels to be loaded that + * provides instrument time support, leap seconds and planet body ephemeris. + * + * @return double Distance in AU between Sun and observed body + */ + double HiCalConf::sunDistanceAU() { + loadNaifTiming(); + + string scStartTime = getKey("SpacecraftClockStartCount", "Instrument"); + double obsStartTime; + scs2e_c (-74999,scStartTime.c_str(),&obsStartTime); + + string targetName = getKey("TargetName", "Instrument"); + if ( (iString::Equal(targetName, "Sky")) || + (iString::Equal(targetName, "Cal")) || + (iString::Equal(targetName, "Phobos")) || + (iString::Equal(targetName, "Deimos")) ) { + targetName = "Mars"; + } + double sunv[3]; + double lt; + (void) spkpos_c(targetName.c_str(), obsStartTime, "J2000", "LT+S", "sun", + sunv, <); + double sunkm = vnorm_c(sunv); + // Return in AU units + return (sunkm/1.49597870691E8); + } + + + /** + * @brief Returns the band number of a Matrix file given CCD, Channel number + * + * The ordering of HiRISE Isis matrix cubes are required to be ordered by CCD + * and channel number. The band number is computed as: + * @code + * band = 1 + ccd * 2 + channel + * @endcode + * + * Note that this method extracts the values from a stored cube label. It + * must be initialized with a label or an error will occur. + * + * @return int Band number of matrix cube + */ + int HiCalConf::getMatrixBand() const { + Pvl label = _label; + DbProfile parms = makeParameters(label); + return (getMatrixBand(parms)); + } + + /** + * @brief Returns the band number of a Matrix file from a profile + * + * The ordering of HiRISE Isis matrix cubes are required to be ordered by CCD + * and CHANNEL number. The band number is computed as: + * @code + * band = 1 + ccd * 2 + channel + * @endcode + * + * @param DbProfile Profile to get CCD and CHANNEL values from + * @return int Band number of matrix cube + */ + + int HiCalConf::getMatrixBand(const DbProfile &p) const { + return (1 + ToInteger(p("CCD"))*2 + ToInteger(p("CHANNEL"))); + } + + /** + * @brief Generic profile keyword value extractor + * + * This method retrieves a profile keyword from the given profile and returns + * all its values a a list of strings. An exception will be thrown + * incidentally if the keyword does not exist. + * + * @param profile Profile containing the keyword to extract + * @param key Name of keyword to retrieve + * + * @return std::vector List of values from profile keyword + */ + HiCalConf::ValueList HiCalConf::getList(const DbProfile &profile, + const std::string &key) const { + ValueList slist; + +// Get keyword parameters + if ( profile.exists(key) ) { + int nvals = profile.count(key); + for (int i = 0 ; i < nvals ; i++) { + slist.push_back(profile.value(key, i)); + } + } + return (slist); + } + +/** + * @brief Load required NAIF kernels required for timing needs + * + * This method maintains the loading of kernels for HiRISE timing and planetary + * body ephemerides to support time and relative positions of planet bodies. + */ +void HiCalConf::loadNaifTiming( ) { + if (!_naifLoaded) { +// Load the NAIF kernels to determine timing data + Isis::Filename leapseconds("$base/kernels/lsk/naif????.tls"); + leapseconds.HighestVersion(); + + Isis::Filename sclk("$mro/kernels/sclk/MRO_SCLKSCET.?????.65536.tsc"); + sclk.HighestVersion(); + + Isis::Filename pck("$base/kernels/spk/de???.bsp"); + pck.HighestVersion(); + +// Load the kernels + string lsk = leapseconds.Expanded(); + string sClock = sclk.Expanded(); + string pConstants = pck.Expanded(); + furnsh_c(lsk.c_str()); + furnsh_c(sClock.c_str()); + furnsh_c(pConstants.c_str()); + +// Ensure it is loaded only once + _naifLoaded = true; + } + return; +} + +/** + * @brief Intialization of object variables + */ +void HiCalConf::init() { + _label.Clear(); + return; +} + +/** + * @brief Initialization of object using HiRISE label + * + * This method initializes the object from a HiRISE label. Note that a copy of + * the label is created so that subsequent operations can be supported and it is + * not dependant upon callers behaviour. + * + * @param label Pvl label of HiRISE cube + */ +void HiCalConf::init(Pvl &label) { + init(); + _label = label; + return; +} + +/** + * @brief Get a label keyword + * + * Retreives a keyword from a HiRISE label and returns a reference to it. If it + * does not exist, an exception is thrown incidentally. + * + * @param key Name of keyword in label to retrieve + * @param group Optional group name to use if non-empty. + * + * @return PvlKeyword& Reference to retrieved label keyword + */ +PvlKeyword &HiCalConf::getKey(const std::string &key, + const std::string &group) { + if (!group.empty()) { + PvlGroup &grp = _label.FindGroup(group, Pvl::Traverse); + return (grp[key]); + } + else { + return (_label.FindKeyword(key)); + } +} + +/** + * @brief Returns the Matrix profile + * + * This method constructs a fully optioned matrix profile from the + * configuration file. If the caller has designated a specific named profile, + * the options profiles are not loaded. + * + * Options profiles are read from the \b ProfileOptions configuration keyword + * and resolved through pattern replacement of FILTER, TDI, BIN, CCD and CHANNEL + * values are determined from the HiRISE label. If named profiles exist after + * the textual substitutions of these values they are added to the base default + * profile. This process will replace existing default keywords of the same + * name in subseqent optional keywords. + * + * @param profile Optional name of the profile to retrieve. It will use the + * default profile if this parameter is not provided (empty). + * @return DbProfile Returns a fully optioned profile + */ +DbProfile HiCalConf::getMatrixProfile(const std::string &profile) const { + string myprof = (!profile.empty()) ? profile : _profName; + DbProfile matconf = getProfile(myprof); + if (!matconf.isValid()) { + ostringstream mess; + mess << "Specifed matrix profile (" << matconf.Name() + << ") does not exist or is invalid!"; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + // Profile the label and merge them. Order is important. + matconf = DbProfile(getLabelProfile(matconf), matconf, matconf.Name()); + + // Add special parameters. Again, order is important. + matconf = DbProfile(matconf, makeParameters(matconf), matconf.Name()); + +// Load any optional ones + ValueList profkeys = getList(matconf,"OptionKeywords"); + ValueList proforder = getList(matconf,"ProfileOptions"); + string pName(matconf.Name()); + for (unsigned int i = 0 ; i < proforder.size() ; i++) { + std::string profile = parser(proforder[i], profkeys, matconf); + if (profileExists(profile)) { + pName += "+[" + profile + "]"; + matconf = DbProfile(matconf,getProfile(profile), pName); + } + } + return (matconf); +} + + +DbProfile HiCalConf::getLabelProfile(const DbProfile &profile) const { + DbProfile lblprof("Label"); + if ( profile.exists("LabelGroups") ) { + int ngroups = profile.count("LabelGroups"); + Pvl label = _label; + for ( int g = 0 ; g < ngroups ; g++ ) { + string group = profile("LabelGroups", g); + PvlGroup grp = label.FindGroup(group, Pvl::Traverse); + lblprof = DbProfile(lblprof,DbProfile(grp)); + } + } + return (lblprof); +} + + +DbProfile HiCalConf::makeParameters(Pvl &label) const { + PvlGroup inst = label.FindGroup("Instrument", Pvl::Traverse); + DbProfile parms("Parameters"); + + int ccd = CpmmToCcd((int) inst["CpmmNumber"]); + parms.add("CCD",ToString(ccd)); + parms.add("CHANNEL", inst["ChannelNumber"]); + parms.add("TDI", inst["Tdi"]); + parms.add("BIN", inst["Summing"]); + parms.add("FILTER", CcdToFilter(ccd)); + return (parms); +} + +DbProfile HiCalConf::makeParameters(const DbProfile &profile) const { + DbProfile parms("Parameters"); + int ccd = CpmmToCcd(ToInteger(profile("CpmmNumber"))); + parms.add("CCD",ToString(ccd)); + parms.add("CHANNEL", profile("ChannelNumber")); + parms.add("TDI", profile("Tdi")); + parms.add("BIN", profile("Summing")); + parms.add("FILTER", CcdToFilter(ccd)); + return (parms); +} + +std::string HiCalConf::makePattern(const std::string &str) const { + return (string("{" + str + "}")); +} + +/** + * @brief Performs a search and replace operation for the given string + * + * This method will search the input string s for predefined keywords (FILTER, + * TDI, BIN, CCD and CHANNEL) delimited by {} and replace these occurances with + * the textual equivalent. + * + * @param s String to conduct search/replace of values + * + * @return std::string Results of search/replace + */ +std::string HiCalConf::parser(const std::string &s, const ValueList &vlist, + const DbProfile &prof) const { + string sout(s); + + ValueList::const_iterator ciVlist; + for ( ciVlist = vlist.begin() ; ciVlist != vlist.end() ; ++ciVlist ) { + std::string str(*ciVlist); + if ( prof.exists(str) ) { + sout = iString::Replace(sout, makePattern(str), prof(str)); + } + } + + return (sout); +} + +} // namespace Isis + diff --git a/isis/src/mro/apps/hicalbeta/HiCalConf.h b/isis/src/mro/apps/hicalbeta/HiCalConf.h new file mode 100644 index 0000000000000000000000000000000000000000..e4233303131ad3dd369c30f9e02ecc887d3da3d3 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/HiCalConf.h @@ -0,0 +1,154 @@ +#if !defined(HiCalConf_h) +#define HiCalConf_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/11/18 06:59:48 $ + * $Id: HiCalConf.h,v 1.3 2008/11/18 06:59:48 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "Pvl.h" +#include "DbAccess.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief HiCalConf manages HiRISE calibration matrices + * that alter some or all of the + * parameters contained in the Object section of the file. + * This object accepts a configuration file that contains a generic format of + * HiRISE Calibration matrices and loads the appropriate set based upon TDI, + * BIN, and channel number minimally. + * + * Below is the basic unprofiled version of the configuration (database) + * file: + * + * @code + * Object = Database + * A = "$mro/calibration/matrices/A_TDI{TDI}_BIN{BIN}_????.cub" + * B = "$mro/calibration/matrices/B_TDI{TDI}_BIN{BIN}_????.cub" + * G = "$mro/calibration/matrices/G_TDI{TDI}_BIN{BIN}_????.cub" + * EndObject + * + * @endcode + * + * The \b {TDI} and \b {BIN} will be replaced with the textual translation of + * the TDI (128, 64, 32, 16, 8) and BIN (1, 2, 3, 4, 8, 16) numbers. This + * makes for easy defaulting to set up specific profiling of combinations. + * + * Additionally, you can add profiles for a TDI/BIN mode combination should + * the need arise. Simply add one or more \a Profile groups that specify + * different files for the observation conditions. + * @endcode + * + * This object will retain B, G and IF references from the main Database + * object but replace A with the one specified in the "TDI128/BIN2" Profile + * called "MyNew_A_Matrix.cub" for all HiRISE images that were acquired with + * TDI128 and BIN2 imaging parameters. + * @code + * Object = Database + * Matrices = ("A", "B", "G") + * + * A = "$mro/calibration/matrices/A_TDI{TDI}_BIN{BIN}_????.cub" + * B ="$mro/calibration/matrices/B_TDI{TDI}_BIN{BIN}_????.cub" + * G = "$mro/calibration/matrices/G_TDI{TDI}_BIN{BIN}_????.cub" + * + * Group = Profile + * Name = "TDI128/BIN2" + * A = "MyNew_A_Matrix.cub" + * EndGroup + * EndObject + * @ingroup Utility + * @author 2007-06-27 Kris Becker + * @history 2008-04-01 Kris Becker Added Phobos and Deimos to I/F modified + * target list as Mars in sundistanceAU() method so it returns + * acceptable distances + */ + class HiCalConf : public DbAccess { + public: + typedef enum { Matrix, Scalar, Keyword } CalType; + typedef std::vector ValueList; + + public: + // Constructors and Destructor + HiCalConf(); + HiCalConf(Pvl &label); + HiCalConf(Pvl &label, const std::string &conf); + + /** Destructor ensures everything is cleaned up properly */ + virtual ~HiCalConf () { } + + void setLabel(Pvl &label); + PvlKeyword &getKey(const std::string &key, const std::string &group = ""); + + std::string filepath(const std::string &fname) const; + void setConf(const std::string &conf); + void selectProfile(const std::string &profile = ""); + + std::string getProfileName() const; + std::string getMatrixSource(const std::string &name) const; + std::string getMatrixSource(const std::string &name, + const DbProfile &matconf) const; + HiVector getMatrix(const std::string &name, int expected_size = 0) const; + HiVector getMatrix(const std::string &name, const DbProfile &profile, + int expected_size = 0) const; + HiVector getScalar(const std::string &name, const DbProfile &profile, + int expected_size) const; + int getMatrixBand() const; + int getMatrixBand(const DbProfile &p) const; + + double sunDistanceAU(); + + DbProfile getMatrixProfile(const std::string &profile = "") const; + ValueList getList(const DbProfile &profile, const std::string &key) const; + std::string resolve(const std::string &composite, + const DbProfile &matconf) const; + + private: + static bool _naifLoaded; //!< Ensures one instance of NAIF kernels + std::string _profName; //!< Specified name of profile + Pvl _label; //!< Hold label for future references + + int _ccd; //!< CCD Number + int _channel; //!< Channel number + int _tdi; //!< TDI mode of operation + int _binMode; //!< Binning mode + std::string _filter; //!< Filter set name (RED, IR, BG) + + + void init(); + void init(Pvl &label); + void loadNaifTiming(); + DbProfile getLabelProfile(const DbProfile &profile) const; + DbProfile makeParameters(Pvl &label) const; + DbProfile makeParameters(const DbProfile &profile) const; + std::string makePattern(const std::string &str) const; + std::string parser(const std::string &s, const ValueList &options, + const DbProfile &prof ) const; + }; + +} // namespace Isis +#endif diff --git a/isis/src/mro/apps/hicalbeta/HiCalData.h b/isis/src/mro/apps/hicalbeta/HiCalData.h new file mode 100644 index 0000000000000000000000000000000000000000..1f011ecae48248f12540ec3f141a5cf1ea145cd4 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/HiCalData.h @@ -0,0 +1,167 @@ +#if !defined(HiCalData_h) +#define HiCalData_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/05/14 21:07:22 $ + * $Id: HiCalData.h,v 1.3 2008/05/14 21:07:22 slambright Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiBlob.h" +#include "Cube.h" + +#include "iException.h" + +namespace Isis { + + /** + * @brief Container for HiRISE calibration data + * + * @ingroup Utility + * + * @author 2007-10-09 Kris Becker + * + * @internal + * @history 2008-05-12 Steven Lambright - Removed references to CubeInfo + */ + class HiCalData { + + public: + // Constructors and Destructor + HiCalData() : _calimage(), _calbuffer(), _caldark(), _buffer(), + _dark(), _binning(0), _tdi(0),_cpmm(0), _channelNo(0), + _firstReverseLine(0), _lastReverseLine(0), + _firstMaskLine(0), _lastMaskLine(0), + _firstRampLine(0), _lastRampLine(0) { } + HiCalData(Cube &cube) { load(cube); } + + /** Destructor */ + virtual ~HiCalData() { } + + void load(Cube &cube) { + Progress progress; + progress.SetText("HiCalData"); + + _calimage = HiBlob(cube,"HiRISE Calibration Image", "Calibration").buffer(); + _calbuffer = HiBlob(cube,"HiRISE Calibration Ancillary", "BufferPixels").buffer(); + _caldark = HiBlob(cube,"HiRISE Calibration Ancillary", "DarkPixels").buffer(); + _buffer = HiBlob(cube,"HiRISE Ancillary", "BufferPixels").buffer(); + _dark = HiBlob(cube,"HiRISE Ancillary", "DarkPixels").buffer(); + + PvlGroup &instrument = cube.GetGroup("Instrument"); + +// Extract what is needed + _binning = instrument["Summing"]; + _tdi = instrument["Tdi"]; + _cpmm = instrument["CpmmNumber"]; + _channelNo = instrument["ChannelNumber"]; + +// Determine start/end lines + _firstReverseLine = 0; + _lastReverseLine = 19; + +// Set the mask depending on the binning mode + _firstMaskLine = 20; + _lastMaskLine = _firstMaskLine + 20/_binning - 1; + _firstRampLine = _lastMaskLine + 1; + _lastRampLine = _calimage.dim1() - 1; + } + + + HiMatrix getReverseClock() { + return (cropLines(_calimage,_firstReverseLine,_lastReverseLine)); + } + HiMatrix getMask() { + return (cropLines(_calimage, _firstMaskLine, _lastMaskLine)); + } + HiMatrix getRamp() { + return (cropLines(_calimage, _firstRampLine, _lastRampLine)); + } + + HiMatrix getDark() { return (_dark.copy()); } + HiMatrix getBuffer() { return (_buffer.copy()); } + + HiMatrix getReverseClockExtended() { + return ( + appendSamples( + appendSamples( + cropLines(_calbuffer,_firstReverseLine,_lastReverseLine), + cropLines(_calimage,_firstReverseLine,_lastReverseLine)), + cropLines(_caldark, _firstReverseLine,_lastReverseLine) + ) + ); + } + HiMatrix getMaskExtended() { + return ( + appendSamples( + appendSamples(cropLines(_calbuffer,_firstMaskLine,_lastMaskLine), + cropLines(_calimage,_firstMaskLine,_lastMaskLine)), + cropLines(_caldark, _firstMaskLine,_lastMaskLine) + ) + ); + } + HiMatrix getRampExtended() { + return ( + appendSamples( + appendSamples(cropLines(_calbuffer,_firstRampLine,_lastRampLine), + cropLines(_calimage,_firstRampLine,_lastRampLine)), + cropLines(_caldark, _firstRampLine,_lastRampLine) + ) + ); + + } + HiMatrix getDarkExtended() { + return (appendLines(_caldark, _dark)); + } + HiMatrix getBufferExtended() { + return (appendLines(_calbuffer, _buffer)); + } + + private: + + HiMatrix _calimage; + HiMatrix _calbuffer; + HiMatrix _caldark; + HiMatrix _buffer; + HiMatrix _dark; + + int _binning; + int _tdi; + int _cpmm; + int _channelNo; + + int _firstReverseLine; + int _lastReverseLine; + int _firstMaskLine; + int _lastMaskLine; + int _firstRampLine; + int _lastRampLine; + }; + +} // namespace Isis +#endif + + diff --git a/isis/src/mro/apps/hicalbeta/HiCalTypes.h b/isis/src/mro/apps/hicalbeta/HiCalTypes.h new file mode 100644 index 0000000000000000000000000000000000000000..d55e835eb90b745038dc6df0e1bcf7db46e428c1 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/HiCalTypes.h @@ -0,0 +1,87 @@ +#if !defined(HiCalTypes_h) +#define HiCalTypes_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/01/13 08:12:58 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include + +#include "tnt_array1d.h" +#include "tnt_array1d_utils.h" +#include "tnt_array2d.h" +#include "tnt_array2d_utils.h" +#include "PvlKeyword.h" + +namespace Isis { + +typedef TNT::Array1D HiVector; //!< 1-D Buffer +typedef TNT::Array2D HiMatrix; //!< 2-D buffer + +class HiHistory { + public: + /** + * @brief Output operator for history events + * @param o Output stream + * @param h History class to write contents of + * + * @return std::ostream& Returns new state of stream + */ + friend std::ostream &operator<<(std::ostream &o, const HiHistory &h) { + std::copy(h._events.begin(), h._events.end(), + std::ostream_iterator(o,"; ")); + return (o); + } + + public: + HiHistory() { } + HiHistory(const HiHistory &h) : _events(h._events) { } + virtual ~HiHistory() { } + + inline int size() const { return (_events.size()); } + void add(const std::string &event) { _events.push_back(event); } + std::string get(unsigned int index = 0) const { + if (index < _events.size()) { + return (_events[index]); + } + else { + return (std::string("")); + } + } + + void clear() { _events.clear(); } + + PvlKeyword makekey(const std::string &name = "History") const { + PvlKeyword key(name); + for (unsigned int i = 0 ; i < _events.size() ; i++) { + key.AddValue(_events[i]); + } + return (key); + } + + private: + std::vector _events; +}; + +}; +#endif diff --git a/isis/src/mro/apps/hicalbeta/HiCalUtil.h b/isis/src/mro/apps/hicalbeta/HiCalUtil.h new file mode 100644 index 0000000000000000000000000000000000000000..16f56e4b7f78668409dec0cc5ea6105b2643ec4d --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/HiCalUtil.h @@ -0,0 +1,476 @@ +#if !defined(HiCalUtil_h) +#define HiCalUtil_h +/** + * @file + * $Revision: 1.6 $ + * $Date: 2008/11/06 00:08:15 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include + +#include "HiCalTypes.h" +#include "DbProfile.h" +#include "iString.h" +#include "Statistics.h" +#include "PvlKeyword.h" +#include "NumericalApproximation.h" +#include "Filename.h" +#include "Pvl.h" +#include "iException.h" + +namespace Isis { + + template inline T MIN(const T &A, const T &B) { + if ( A < B ) { return (A); } + else { return (B); } + } + + template inline T MAX(const T &A, const T &B) { + if ( A > B ) { return (A); } + else { return (B); } + } + +/** + * @brief Counts number of valid pixels in vector + * @param v Vector to inspect + * @return int Number valid pixels in vector + */ +inline int ValidCount(const HiVector &v) { + int n = 0; + for (int i = 0 ; i < v.dim() ; i++) { + if (!IsSpecial(v[i])) n++; + } + return (n); +} + +/** + * @brief Counts number of invalid pixels in vector + * @param v Vector to inspect + * @return int Number invalid (special) pixels in vector + */ +inline int InValidCount(const HiVector &v) { + int n = 0; + for (int i = 0 ; i < v.dim() ; i++) { + if (IsSpecial(v[i])) n++; + } + return (n); +} + +/** + * @brief Convert HiRISE Cpmm number to Ccd number + * + * @param cpmm Cpmm number + */ +inline int CpmmToCcd(int cpmm) { + const int cpmm2ccd[] = {0,1,2,3,12,4,10,11,5,13,6,7,8,9}; + if ( (cpmm < 0) || (cpmm >= (int)(sizeof(cpmm2ccd)/sizeof(int))) ) { + std::string mess = "CpmmToCdd: Bad CpmmNumber (" + iString(cpmm) + ")"; + throw iException::Message(iException::User, mess.c_str(), _FILEINFO_); + } + return (cpmm2ccd[cpmm]); +} + + +/** + * @brief Convert HiRISE Ccd number to string filter name + * + * @param ccd Ccd number of device + */ +inline std::string CcdToFilter(int ccd) { + if ( (ccd < 0) || (ccd > 13) ) { + std::string mess = "CcdToFilter: Bad Ccd Number (" + iString(ccd) + ")"; + throw iException::Message(iException::User, mess.c_str(), _FILEINFO_); + } + + std::string filter; + if ( ccd <= 9 ) { filter = "RED"; } + else if (ccd <= 11) { filter = "IR"; } + else { filter = "BG"; } + return (filter); +} + +/** + * @brief Crop specified lines from a buffer + * + * This function extracts lines from a buffer and returns a new buffer with the + * extracted lines. + * + * @param m Buffer to extract lines from + * @param sline Starting line number (first line is 0) + * @param eline Last line to extract + * + * @return HiMatrix Buffer containing cropped lines + */ +inline HiMatrix cropLines(const HiMatrix &m, int sline, int eline) { + int nlines(eline-sline+1); + HiMatrix mcrop(nlines, m.dim2()); + for (int l = 0 ; l < nlines ; l++) { + for (int s = 0 ; s < m.dim2() ; s++) { + mcrop[l][s] = m[l+sline][s]; + } + } + return (mcrop); +} + +/** + * @brief Crop specified samples from a buffer + * + * This function extracts samples from a buffer and returns a new buffer with + * the extracted samples. + * + * @param m Buffer to extract samples from + * @param ssamp Startling sample (first sample 0) + * @param esamp Ending sample to extract + * + * @return HiMatrix Buffer with cropped samples + */ +inline HiMatrix cropSamples(const HiMatrix &m, int ssamp, int esamp) { + int nsamps(esamp-ssamp+1); + HiMatrix mcrop(m.dim1(), nsamps); + for (int l = 0 ; l < m.dim1() ; l++) { + for (int s = 0 ; s < nsamps ; s++) { + mcrop[l][s] = m[l][s+ssamp]; + } + } + return (mcrop); +} + +/** + * @brief Reduces by averaging specified lines from a buffer + * + * This function produces a vector from a 2-D buffer of averaged lines at each + * vertical sample location + * + * @param m Buffer to reduce + * @param sline Starting line number (first line is 0) + * @param eline Last line to average (-1 means use all lines) + * + * @return HiVector Buffer containing averaged lines + */ +inline HiVector averageLines(const HiMatrix &m, int sline = 0, int eline = -1) { + eline = (eline == -1) ? m.dim1() - 1 : eline; + HiVector v(m.dim2()); + for (int s = 0 ; s < m.dim2() ; s++) { + Statistics stats; + for (int l = sline ; l <= eline ; l++) { + stats.AddData(&m[l][s], 1); + } + v[s] = stats.Average(); + } + return (v); +} + +/** + * @brief Reduces by averaging specified samples from a buffer + * + * This function produces a vector from a 2-D buffer of averaged samples at each + * horizontal line location + * + * @param m Buffer to reduce + * @param ssamp Starting sample number (first sample is 0) + * @param esamp Last sample to average (-1 means use all samples) + * + * @return HiVector Buffer containing averaged samples + */ +inline HiVector averageSamples(const HiMatrix &m, int ssamp = 0, + int esamp = -1) { + esamp = (esamp == -1) ? m.dim2() - 1 : esamp; + HiVector v(m.dim1()); + for (int l = 0 ; l < m.dim1() ; l++) { + Statistics stats; + for (int s = ssamp ; s <= esamp ; s++) { + stats.AddData(&m[l][s], 1); + } + v[l] = stats.Average(); + } + return (v); +} + +/** + * @brief Find a keyword in a profile using default for non-existant keywords + * + * This template function will extract keyword values from a profile and provide + * the values at the indicated index. If the keyword does not exist or the + * indicated value at index, the provided default will be used instead. + * + */ +template + T ConfKey(const DbProfile &conf, const std::string &keyname, const T &defval, + int index = 0) { + if (!conf.exists(keyname)) { return (defval); } + if (conf.count(keyname) < index) { return (defval); } + iString iValue(conf.value(keyname, index)); + T value = iValue; // This makes it work with a string? + return (value); +} + +/** + * @brief Helper function to convert values to Integers + * + * @param T Type of value to convert + * @param value Value to convert + * + * @return int Converted value + */ +template int ToInteger(const T &value) { + return (iString(value).Trim(" \r\t\n").ToInteger()); +} + +/** + * @brief Helper function to convert values to doubles + * + * @param T Type of value to convert + * @param value Value to convert + * + * @return double Converted value + */ +template double ToDouble(const T &value) { + return (iString(value).Trim(" \r\t\n").ToDouble()); +} + +/** + * @brief Helper function to convert values to strings + * + * @param T Type of value to convert + * @param value Value to convert + * + * @return string Converted value + */ +template std::string ToString(const T &value) { + return (iString(value).Trim(" \r\t\n")); +} + +/** + * @brief Shortened string equality test + * + * @param v1 First value + * @param v2 Second value + * + * @return bool True if they are equal w/o regard to case + */ +inline bool IsEqual(const std::string &v1, const std::string &v2 = "TRUE") { + return (iString::UpCase(v1) == iString::UpCase(v2)); +} + +/** + * @brief Determines if the keyword value is the expected value + * + * This function checks the existance of a keyword in a profile, extracts the + * first value and tests it for equivelance to the expected value. Note this + * test is case insensitive. + * + * @param prof Profile to find the expected keyword in + * @param key Name of keyword in profile to test + * @param value Value to test for in keyword + * + * @return bool Returns true only if the keyword exists in the profile and it is + * the value expected. + */ +inline bool IsTrueValue(const DbProfile &prof, const std::string &key, + const std::string &value = "TRUE") { + if ( prof.exists(key) ) { + return (IsEqual(prof(key), value)); + } + return (false); +} + +/** + * @brief Checks profile flag to skip the current Module + * + * This function looks for the keyword \b Debug::SkipModule and checks its + * value. True is returned if the value is TRUE (case insensentive). + * + * @param prof Module profile from config file + * + * @return bool True if the value of the Debug::SkipModule keyword is TRUE, + * otherwise it returns false for all other values. + */ +inline bool SkipModule(const DbProfile &prof) { + return (IsTrueValue(prof, "Debug::SkipModule", "TRUE")); +} + + +inline HiMatrix appendLines(const HiMatrix &top, const HiMatrix &bottom) { + // Ensure same number samples + if (top.dim2() != bottom.dim2()) { + std::ostringstream mess; + mess << "Top buffer samples (" << top.dim2() + << ") do not match bottom buffer samples (" << bottom.dim2() + << ")"; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + int nlines(top.dim1()+bottom.dim1()); + HiMatrix mat(nlines, top.dim2()); + for (int lt = 0 ; lt < top.dim1() ; lt++) { + for (int s = 0 ; s < top.dim2() ; s++) { + mat[lt][s] = top[lt][s]; + } + } + + int topl = top.dim1(); + for (int lb = 0 ; lb < bottom.dim1() ; lb++) { + for (int s = 0 ; s < top.dim2() ; s++) { + mat[topl+lb][s] = bottom[lb][s]; + } + } + return (mat); +} + +inline HiMatrix appendSamples(const HiMatrix &left, const HiMatrix &right) { + // Ensure same number samples + if (right.dim1() != right.dim1()) { + std::ostringstream mess; + mess << "Left buffer lines (" << left.dim1() + << ") do not match right buffer lines (" << right.dim1() + << ")"; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + int nsamps(left.dim2()+right.dim2()); + HiMatrix mat(left.dim1(), nsamps); + for (int ll = 0 ; ll < left.dim1() ; ll++) { + for (int s = 0 ; s < left.dim2() ; s++) { + mat[ll][s] = left[ll][s]; + } + } + + int lefts = left.dim2(); + for (int lr = 0 ; lr < right.dim1() ; lr++) { + for (int s = 0 ; s < right.dim2() ; s++) { + mat[lr][lefts+s] = right[lr][s]; + } + } + return (mat); +} + +/** + * @brief Compute HiRISE line times + * + * This class will compute the time (in seconds) for a HiRISE observation line + * based upon the binning mode and line number. It is assumed that the first + * line will be time 0, but that is up to the caller to keep that straight. + */ +class HiLineTimeEqn { + public: + HiLineTimeEqn() : _bin(1), _ltime(1.0) { } + HiLineTimeEqn(int bin, double ltime) : _bin(bin), _ltime(ltime) { } + virtual ~HiLineTimeEqn() { } + + void setLineTime(double ltime) { _ltime = ltime; } + void setBin(int bin) { _bin = bin; } + double Time(const double line) const { + return (line * (_bin * _ltime * 1.0E-6)); + } + double operator()(const double line) const { return (Time(line)); } + + private: + double _bin; + double _ltime; +}; + +/** + * @brief Implements (classic) HiRISE temperature equation + * + * This function computes the dark current temperature and returns the results + * in electrons/sec/pixel. + * + * @param temperature Temperature (typically of the FPGA) + * @param napcm2 Dark current for silicone diodes (nano-ampres/cm^2) + * @param px Pixel size in microns + * + * @return double Dark current temperature (electrons/sec/pixel) + */ +inline double HiTempEqn(const double temperature, const double napcm2 = 2.0, + const double px = 12.0) { + double temp = temperature + 273.0; + double eg = 1.1557 - (7.021E-4 * temp * temp) / (1108.0 + temp); + const double K = 1.38E-23; + const double Q = 1.6E-19; + return (napcm2*(px*px)*2.55E7*std::pow(temp,1.5)*std::exp(-eg*Q/2.0/K/temp)); +} + +/** + * @brief Rebins a vector to a different size + * + * This function can rebin to both larger and smaller sizes. It fits the data + * to a cubic spline and then computes the value at the rebin pixel index. One + * advantage to this approach is that on input, special pixels are ignored - on + * output there will never be special pixels unless there are not enough points + * to conpute the cubic spline on which case this function throws an exception. + * + * @param v Input vector to rebin + * @param n Size of the new output vector + * + * @return HiVector + * @history 2008-11-05 Jeannie Walldren Replaced references to + * DataInterp class with NumericalApproximation. + */ +inline HiVector rebin(const HiVector &v, int n) { + if ( n == v.dim() ) { return (v); } + NumericalApproximation nterp(NumericalApproximation::CubicNatural); + double mag((double) v.dim()/ (double) n); + + for ( int i = 0 ; i < v.dim() ; i++ ) { + double x((double) i); + if ( !IsSpecial(v[i]) ) { + nterp.AddData(x,v[i]); + } + } + + // Compute the spline and fill the output vector + HiVector vout(n); + for ( int j = 0 ; j < n ; j++ ) { + double x = (double) j * mag; + vout[j] = nterp.Evaluate(x, NumericalApproximation::NearestEndpoint); + } + return (vout); +} + +/** + * @brief Deletes HiRISE specific BLOBS from cube file + * + * Ths function removes only the HiRISE specific + * + * @param label Input label associated with file from which to remove the HiRISE + * blobs + */ +inline void RemoveHiBlobs(Pvl &label) { + for ( int blob = 0 ; blob < label.Objects() ; blob++ ) { + if ( label.Object(blob).IsNamed("Table") ) { + std::string name = label.Object(blob)["Name"][0]; + if ( iString::Equal(name,"HiRISE Calibration Ancillary") || + iString::Equal(name,"HiRISE Calibration Image") || + iString::Equal(name,"HiRISE Ancillary") ) { + label.DeleteObject(blob); + blob--; + } + } + } + return; +} + + +}; // namespace Isis +#endif diff --git a/isis/src/mro/apps/hicalbeta/LowPassFilterComp.h b/isis/src/mro/apps/hicalbeta/LowPassFilterComp.h new file mode 100644 index 0000000000000000000000000000000000000000..7675e90a00dd95c7af296dd9353460b5d31b1b11 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/LowPassFilterComp.h @@ -0,0 +1,110 @@ +#if !defined(LowPassFilterComp_h) +#define LowPassFilterComp_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2008/01/13 08:12:59 $ + * $Id: LowPassFilterComp.h,v 1.1 2008/01/13 08:12:59 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "iString.h" +#include "HiCalUtil.h" +#include "Component.h" +#include "QuickFilter.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Compute a low pass filter from a Component class content + * + * @ingroup Utility + * + * @author 2007-10-09 Kris Becker + */ + class LowPassFilterComp : public Component { + + public: + // Constructors and Destructor + LowPassFilterComp() : Component("LowPassFilter"), _width(3), + _iterations(1) { } + LowPassFilterComp(int width, int iterations = 1) : + Component("LowPassFilter"), _width(width), _iterations(iterations) { } + + LowPassFilterComp(const Component &c, int width = 3, int iterations = 1) : + Component("LowPassFilter", c), _width(width), + _iterations(iterations) { + _data = filterIterator(c.ref(), _width, _iterations); + _history.add(formHistory()); + } + + LowPassFilterComp(const HiVector &v, const HiHistory &h, + int width = 3, int iterations = 1) : + Component("LowPassFilter", h), _width(width), + _iterations(iterations) { + _data = filterIterator(v, _width, _iterations); + _history.add(formHistory()); + } + + /** Destructor */ + virtual ~LowPassFilterComp() { } + + void Process(const HiVector &v) { + _data = filterIterator(v, _width, _iterations); + _history.clear(); + _history.add(formHistory()); + } + + inline int Width() const { return (_width); } + + private: + int _width; //!< Filter width + int _iterations; // Number iterations to apply filter + + std::string formHistory() { + return (std::string("LowPassFilter(Width[" + ToString(_width) + + "],Iters["+ToString(_iterations)+"])")); + } + + HiVector filterIterator(const HiVector &v, int width, int iterations) { + HiVector vout(v.copy()); + for (int i = 0 ; i < iterations; i++) { + vout = filter(vout,width); + } + return (vout); + } + + HiVector filter(const HiVector &v, int width) { + QuickFilter lowpass(v.dim(), width, 1); + lowpass.AddLine(&v[0]); + HiVector vout(v.dim()); + for (int i = 0 ; i < v.dim() ; i ++) { + vout[i] = lowpass.Average(i); + } + return (vout); + } + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hicalbeta/Makefile b/isis/src/mro/apps/hicalbeta/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ee1865e45a549e9d9813b20bc4e016d3306af967 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/Makefile @@ -0,0 +1,7 @@ +SRCS = hicalbeta.cpp HiCalConf.cpp NonLinearLSQ.cpp DriftCorrect.cpp +OBJS = $(SRCS:%.cpp=%.o) +BINS = hicalbeta + +include $(ISISROOT)/make/isismake.apps + + diff --git a/isis/src/mro/apps/hicalbeta/NonLinearLSQ.cpp b/isis/src/mro/apps/hicalbeta/NonLinearLSQ.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4dd8d0d0d573e89a505b5b961253613aa42f385e --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/NonLinearLSQ.cpp @@ -0,0 +1,213 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/02/08 21:31:01 $ + * $Id: NonLinearLSQ.cpp,v 1.2 2008/02/08 21:31:01 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "NonLinearLSQ.h" +#include "iException.h" + +using namespace std; + +namespace Isis { + + +int NonLinearLSQ::curvefit() { + + size_t n(nSize()); + size_t p(nParms()); + + // Initialize the solver function information + _nlsqPointer d = { this }; + gsl_multifit_function_fdf mf; + mf.f = &f; + mf.df = &df; + mf.fdf = &fdf; + mf.n = n; + mf.p = p; + mf.params = &d; + + const gsl_multifit_fdfsolver_type *T = gsl_multifit_fdfsolver_lmsder; + gsl_multifit_fdfsolver *s = gsl_multifit_fdfsolver_alloc(T, n, p); + + _fitParms = guess(); + gsl_vector *x = NlsqTogsl(_fitParms); + gsl_matrix *covar = gsl_matrix_alloc(p, p); + gsl_multifit_fdfsolver_set(s, &mf, x); + + _nIters = 0; + checkIteration(_nIters, gslToNlsq(s->x), NLVector(p,999.0), + gsl_blas_dnrm2(s->f), GSL_CONTINUE); + + + do { + _nIters++; + + _status = gsl_multifit_fdfsolver_iterate(s); + _fitParms = gslToNlsq(s->x); + + gsl_multifit_covar(s->J, 0.0, covar); + _uncert = getUncertainty(covar); + + _status = checkIteration(_nIters, _fitParms, _uncert, gsl_blas_dnrm2(s->f), + _status); + if ( _status ) { break; } + if(!doContinue()) { break; } + + _status = gsl_multifit_test_delta(s->dx, s->x, absErr(), relErr()); + } while ((_status == GSL_CONTINUE) && (_nIters < _maxIters)); + + // Clean up + gsl_multifit_fdfsolver_free(s); + gsl_matrix_free(covar); + + return (_status); +} + + +void NonLinearLSQ::Terminate(const std::string &message) { + _userMessage = message; + _userTerminated = true; + _status = GSL_SUCCESS; + return; +} + +void NonLinearLSQ::Abort(const std::string &reason) { + _userMessage = reason; + _userTerminated = true; + _status = GSL_FAILURE; + return; +} + + +int NonLinearLSQ::f(const gsl_vector *x, void *params, gsl_vector *fx) { + NonLinearLSQ *nlsq = (static_cast<_nlsqPointer *> (params))->nlsq; + int n = nlsq->nSize(); + NLVector fxv = nlsq->f_x(nlsq->gslToNlsq(x)); + for (int i = 0 ; i < n ; i++ ) { + gsl_vector_set(fx, i, fxv[i]); + } + return (GSL_SUCCESS); +} + +int NonLinearLSQ::df(const gsl_vector *x, void *params, gsl_matrix *J) { + NonLinearLSQ *nlsq = (static_cast<_nlsqPointer *> (params))->nlsq; + int n = nlsq->nSize(); + int p = nlsq->nParms(); + + NLMatrix m = nlsq->df_x(nlsq->gslToNlsq(x)); + + for (int i = 0 ; i < n ; i++ ) { + for (int j = 0 ; j < p ; j++ ) { + gsl_matrix_set(J, i, j, m[i][j]); + } + } + return (GSL_SUCCESS); +} + +int NonLinearLSQ::fdf(const gsl_vector *x, void *params, gsl_vector *fx, + gsl_matrix *J) { + f(x,params,fx); + df(x,params,J); + return (GSL_SUCCESS); +} + + +NonLinearLSQ::NLVector NonLinearLSQ::getUncertainty(const gsl_matrix *covar) + const { + NLVector unc(covar->size1); + for (size_t i = 0 ; i < covar->size1 ; i++ ) { + unc[i] = sqrt(gsl_matrix_get(covar, i, i)); + } + return (unc); +} + +NonLinearLSQ::NLVector NonLinearLSQ::gslToNlsq(const gsl_vector *v) const { + size_t n = v->size; + NLVector Nv(n); + for (size_t i = 0 ; i < n ; i++) { + Nv[i] = gsl_vector_get(v, i); + } + return (Nv); +} + +NonLinearLSQ::NLMatrix NonLinearLSQ::gslToNlsq(const gsl_matrix *m) const { + size_t nrows = m->size1; + size_t ncols = m->size2; + NLMatrix Nm(nrows, ncols); + for (size_t i = 0 ; i < nrows ; i++) { + for (size_t j = 0 ; j < ncols ; j++) { + Nm[i][j] = gsl_matrix_get(m,i,j); + } + } + return (Nm); +} + +gsl_vector *NonLinearLSQ::NlsqTogsl(const NonLinearLSQ::NLVector &v, + gsl_vector *gv) const { + if (gv == 0) { + gv = gsl_vector_alloc(v.dim()); + } + else if (gv->size != (size_t) v.dim()) { + ostringstream mess; + mess << "Size of NL vector (" << v.dim() << ") not same as GSL vector (" + << gv->size << ")"; + throw iException::Message(iException::Programmer, mess.str(), _FILEINFO_); + } + + for (int i = 0 ; i < v.dim() ; i++) { + gsl_vector_set(gv, i, v[i]); + } + return (gv); +} + +gsl_matrix *NonLinearLSQ::NlsqTogsl(const NonLinearLSQ::NLMatrix &m, + gsl_matrix *gm) const { + if (gm == 0) { + gm = gsl_matrix_alloc(m.dim1(), m.dim2()); + } + else if ((gm->size1 != (size_t) m.dim1()) && + (gm->size2 != (size_t) m.dim2()) ) { + ostringstream mess; + mess << "Size of NL matrix (" << m.dim1() << "," << m.dim2() + << ") not same as GSL matrix (" << gm->size1 << "," << gm->size2 + << ")"; + throw iException::Message(iException::Programmer, mess.str(), _FILEINFO_); + } + + for (int i = 0 ; i < m.dim1() ; i++) { + for (int j = 0 ; j < m.dim2() ; j++) { + gsl_matrix_set(gm, i, j, m[i][j]); + } + } + return (gm); +} + +} // namespace ISIS diff --git a/isis/src/mro/apps/hicalbeta/NonLinearLSQ.h b/isis/src/mro/apps/hicalbeta/NonLinearLSQ.h new file mode 100644 index 0000000000000000000000000000000000000000..c326936fefc08a444c656867f27a936ea88619a4 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/NonLinearLSQ.h @@ -0,0 +1,148 @@ +#if !defined(NonLinearLSQ_h) +#define NonLinearLSQ_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/02/08 21:31:01 $ + * $Id: NonLinearLSQ.h,v 1.2 2008/02/08 21:31:01 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include + +#include "tnt_array1d.h" +#include "tnt_array1d_utils.h" +#include "tnt_array2d.h" +#include "tnt_array2d_utils.h" + +#include +#include +#include +#include + +#include "iException.h" + +namespace Isis { + + /** + * @brief NonLinearLSQ Computes a fit using a Levenberg-Marquardt algorithm + * + * This virtual base class uses the GSL toolkit to apply the + * Levenberg-Marquardt algorithm to fit data to a non-linear equation using + * least squares. + * + * @ingroup Utility + * @author 2007-11-15 Kris Becker + */ + class NonLinearLSQ { + public: + typedef TNT::Array1D NLVector; + typedef TNT::Array2D NLMatrix; + + // Constructors and Destructor + NonLinearLSQ() : _fitParms(), _uncert(), _nIters(0), _maxIters(50), + _status(0), _userTerminated(false), _userMessage() {} + + /** Destructor */ + virtual ~NonLinearLSQ() { } + + virtual int nSize() const = 0; + virtual int nParms() const = 0; + + /** + * @brief Sets the maximum number of iterations + * + * @param m User provides the maximum number iterations + */ + void setMaxIters(int m) { _maxIters = m; } + + /** + * @brief Maximum number iterations for valid solution + * + * + * @return int Maximum resolutions + */ + int maxIters() const { return (_maxIters); } + + virtual NLVector guess() = 0; + virtual NLVector f_x(const NLVector &x) = 0; + virtual NLMatrix df_x(const NLVector &x) = 0; + + virtual double absErr() const { return (1.0E-4); } + virtual double relErr() const { return (1.0E-4); } + + int curvefit(); + inline int status() const { return (_status); } + inline bool success() const { return (_status == GSL_SUCCESS); } + inline bool success(int status) const { return (status == GSL_SUCCESS); } + inline std::string statusstr() const { + return (std::string(gsl_strerror(_status))); + } + inline std::string statusstr(int status) const { + return (std::string(gsl_strerror(status))); + } + + virtual int checkIteration(const int Iter, const NLVector &fitcoefs, + const NLVector &uncerts, double cplxconj, + int Istatus) { + return (Istatus); + } + + inline NLVector coefs() const { return (_fitParms); } + inline NLVector uncert() const { return (_uncert); } + inline int nIterations() const { return (_nIters); } + + protected: + void Terminate(const std::string &message = ""); + void Abort(const std::string &reason = ""); + + bool doContinue() const { return (!_userTerminated); } + + + private: + NLVector _fitParms; + NLVector _uncert; + int _nIters; + int _maxIters; + int _status; + bool _userTerminated; + std::string _userMessage; + + struct _nlsqPointer { + NonLinearLSQ *nlsq; + }; + static int f(const gsl_vector *x, void *params, gsl_vector *fx); + static int df(const gsl_vector *x, void *params, gsl_matrix *J); + static int fdf(const gsl_vector *x, void *params, gsl_vector *fx, + gsl_matrix *J); + + NLVector gslToNlsq(const gsl_vector *v) const; + NLMatrix gslToNlsq(const gsl_matrix *m) const; + gsl_vector *NlsqTogsl(const NLVector &v, gsl_vector *gv = 0) const; + gsl_matrix *NlsqTogsl(const NLMatrix &m, gsl_matrix *gm = 0) const; + NLVector getUncertainty(const gsl_matrix *m) const; + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hicalbeta/OffsetCorrect.h b/isis/src/mro/apps/hicalbeta/OffsetCorrect.h new file mode 100644 index 0000000000000000000000000000000000000000..f4b53e5a8afd8508b71b9c18966490925a3e0f9b --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/OffsetCorrect.h @@ -0,0 +1,180 @@ +#if !defined(OffsetCorrect_h) +#define OffsetCorrect_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/11/18 07:29:12 $ + * $Id: OffsetCorrect.h,v 1.3 2008/11/18 07:29:12 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include +#include +#include + + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "Component.h" +#include "SplineFillComp.h" +#include "LowPassFilterComp.h" +#include "Statistics.h" +#include "SpecialPixel.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Loads and processes Reverse Clock calibration data + * + * This class loads and processes the Reverse Clock data from a HiRISE image + * for offset correction purposes. Additional processing may occur in + * subsequent modules. + * + * This module implements th Zz module. + * + * @ingroup Utility + * + * @author 2008-06-13 Kris Becker + */ + class OffsetCorrect : public Component { + + public: + // Constructors and Destructor + OffsetCorrect() : Component("OffsetCorrect") { } + OffsetCorrect(HiCalData &cal, const HiCalConf &conf) : + Component("OffsetCorrect") { + init(cal, conf); + } + + /** Destructor */ + virtual ~OffsetCorrect() { } + + /** + * @brief Return statistics for raw Reverse Clock buffer + * + * @return const Statistics& Statistics class with all stats + */ + const Statistics &Stats() const { return (_stats); } + + /** + * @brief Specifies if the input trigger conditions were met + * + * If trigger conditions where met, the reverse clock correction becomes a + * constant as opposed to processed reverse cloc pixels. + * + * @return bool True if triggered, false otherwise + */ + bool wasTriggered() const { return (_triggered); } + + private: + HiVector _revClock; + Statistics _stats; + bool _triggered; + + + void init(HiCalData &cal, const HiCalConf &conf) { + DbProfile prof = conf.getMatrixProfile(); + _history.clear(); + _history.add("Profile["+ prof.Name()+"]"); + + int line0 = ConfKey(prof,"ZzFirstLine",0); + int lineN = ConfKey(prof,"ZzLastLine",19); + std::string tfile= conf.getMatrixSource("ReverseClockStatistics",prof); + + HiMatrix revclk = cropLines(cal.getReverseClock(), line0, lineN); + _stats.Reset(); + _stats.AddData(revclk[0], revclk.dim1()*revclk.dim2()); + + _revClock = averageLines(revclk); + _history.add("RevClock(CropLines["+ToString(line0)+","+ToString(lineN) + + "],Mean["+ToString(_stats.Average()) + + "],StdDev["+ToString(_stats.StandardDeviation()) + + "],LisPixels["+ToString(_stats.LisPixels())+ + "],HisPixels["+ToString(_stats.HisPixels()) + + "],NulPixels["+ToString(_stats.NullPixels())+ "])"); + + DbAccess triggers(Pvl(tfile).FindObject("ReverseClockStatistics")); + std::string tprofName = conf.resolve("{FILTER}{CCD}_{CHANNEL}_{BIN}",prof); + _history.add("ReverseClockStatistics(File["+tfile+ + "],Profile["+tprofName+"])"); + + _triggered= false; + if (triggers.profileExists(tprofName)) { + DbProfile tprof(prof, triggers.getProfile(tprofName), tprofName); + double revmean = ConfKey(tprof,"RevMeanTrigger", _stats.Average()); + double revstddev = ConfKey(tprof,"RevStdDevTrigger", DBL_MAX); + int lisTol = ConfKey(tprof, "RevLisTolerance", 1); + int hisTol = ConfKey(tprof, "RevHisTolerance", 1); + int nulTol = ConfKey(tprof, "RevNulTolerance", 1); + + _history.add("TriggerLimits(RevMeanTrigger["+ToString(revmean) + + "],RevStdDevTrigger["+ToString(revstddev)+ + "],RevLisTolerance["+ToString(lisTol)+ + "],RevHisTolerance["+ToString(hisTol)+ + "],RevNulTolerance["+ToString(nulTol)+ "])"); + + if ((_stats.LisPixels() > lisTol) || (_stats.HisPixels() > hisTol) || + (_stats.NullPixels() > nulTol) || + (_stats.StandardDeviation() > revstddev)) { + _triggered = true; + _data = HiVector(_revClock.dim1(), revmean); + _history.add("Trigger(True - Reverse Clock set to constant," + "ReverseClock["+ToString(revmean)+"])"); + } + else { + _history.add("Trigger(False - Reverse Clock processing invoked)"); + _triggered = false; + } + } + else { + _history.add("Trigger(Profile["+tprofName+"],NotFound!)"); + _triggered = false; + } + + if (!_triggered) { + SplineFillComp spline(_revClock, _history); + _data = spline.ref(); + _history = spline.History(); + } + + return; + } + + virtual void printOn(std::ostream &o) const { + o << "# History = " << _history << std::endl; + // Write out the header + o << std::setw(_fmtWidth) << "RevClock" + << std::setw(_fmtWidth+1) << "Applied\n"; + + for (int i = 0 ; i < _data.dim() ; i++) { + o << formatDbl(_revClock[i]) << " " + << formatDbl(_data[i]) << std::endl; + } + return; + } + + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hicalbeta/SplineFillComp.h b/isis/src/mro/apps/hicalbeta/SplineFillComp.h new file mode 100644 index 0000000000000000000000000000000000000000..f5047898029ef68f618eca06ae932af32947b932 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/SplineFillComp.h @@ -0,0 +1,117 @@ +#if !defined(SplineFillComp_h) +#define SplineFillComp_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/11/06 00:08:15 $ + * $Id: SplineFillComp.h,v 1.2 2008/11/06 00:08:15 jwalldren Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +#include "iString.h" +#include "Component.h" +#include "NumericalApproximation.h" +#include "SpecialPixel.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Compute a low pass filter from a Component class content + * + * @ingroup Utility + * + * @author 2007-10-09 Kris Becker + * @history 2008-11-05 Jeannie Walldren Replaced references to + * DataInterp class with NumericalApproximation. + */ + class SplineFillComp : public Component { + + public: + // Constructors and Destructor + SplineFillComp() : Component("SplineFill"), _filled(0) { } + + SplineFillComp(const Component &c) : + Component("SplineFill", c), _filled(0) { + fill(c.ref()); + _history.add(formHistory()); + } + + SplineFillComp(const HiVector &v) : + Component("SplineFill"), _filled(0) { + fill(v); + _history.add(formHistory()); + } + SplineFillComp(const HiVector &v, const HiHistory &h) : + Component("SplineFill", h), _filled(0) { + fill(v); + _history.add(formHistory()); + } + + /** Destructor */ + virtual ~SplineFillComp() { } + + void Process(const HiVector &v) { + fill(v); + _history.clear(); + _history.add(formHistory()); + } + + inline int Filled() const { return (_filled); } + + private: + int _filled; //!< Number values replaced + + std::string formHistory() { + iString cfilled(_filled); + return (std::string("SplineFill(Cubic,Filled[" + cfilled + "])")); + } + + void fill(const HiVector &v) { + NumericalApproximation spline(NumericalApproximation::CubicNatural); + for (int i = 0 ; i < v.dim() ; i++) { + if (!IsSpecial(v[i])) { + spline.AddData(i, v[i]); + } + } + + // Compute the spline and fill missing data + HiVector vout(v.dim()); + _filled = 0; + for (int j = 0 ; j < v.dim() ; j++) { + if (IsSpecial(v[j])) { + vout[j] = spline.Evaluate(j,NumericalApproximation::NearestEndpoint); + _filled++; + } + else { + vout[j] = v[j]; + } + } + + _data = vout; + return; + } + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hicalbeta/TempGainCorrect.h b/isis/src/mro/apps/hicalbeta/TempGainCorrect.h new file mode 100644 index 0000000000000000000000000000000000000000..a64035b9d2d2f76181b77343d474c01f5d2609e1 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/TempGainCorrect.h @@ -0,0 +1,158 @@ +#if !defined(TempGainCorrect_h) +#define TempGainCorrect_h +/** + * @file + * $Revision: 1.1 $ + * $Date: 2009/09/15 21:56:44 $ + * $Id: TempGainCorrect.h,v 1.1 2009/09/15 21:56:44 kbecker Exp $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include +#include +#include + +#include "iString.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalConf.h" +#include "Component.h" +#include "Filename.h" +#include "CSVReader.h" +#include "Statistics.h" +#include "iException.h" + +namespace Isis { + + /** + * @brief Zt Module - Applies temperature-dependant gain correction (column) + * + * This class computes the temperature dependant gain correction. It has a + * comma separated value (CSV) file in the config file parameter + * "FpaTemperatureFactorFile". This file is assumed to contain three columns + * of data: column 0: CCD identifier (Ex: RED0), column 1: FPA factor for + * channel 0, and column 2: FPA factor for channel 1. It should have 14 rows, + * 1 for each HiRISE CCD. + * + * @ingroup Utility + * + * @author 2009-09-14 Kris Becker + */ + class TempGainCorrect : public Component { + + public: + // Constructors and Destructor + TempGainCorrect() : Component("TempGainCorrect") { } + TempGainCorrect(const HiCalConf &conf) : Component("TempGainCorrect") { + init(conf); + } + + /** Destructor */ + virtual ~TempGainCorrect() { } + + private: + std::string _fpaFile; + double _refTemp; // Reference temperature + double _fpaFactor; // Temperature factor + double _baseT; // Base temperature + + void init(const HiCalConf &conf) { + _history.clear(); + DbProfile prof = conf.getMatrixProfile(); + _history.add("Profile["+ prof.Name()+"]"); + + // Get parameters from gainVline coefficients file + _fpaFile = conf.getMatrixSource("FpaTemperatureFactorFile", prof); + _fpaFactor = fetchFactor(_fpaFile, prof); + + // Get temperature parameters + _refTemp = ConfKey(prof, "FpaReferenceTemperature", 21.0); + + double fpa_py_temp = ToDouble(prof("FpaPositiveYTemperature")); + double fpa_my_temp = ToDouble(prof("FpaNegativeYTemperature")); + + + double FPA_temp = (fpa_py_temp+fpa_my_temp) / 2.0; + double _baseT = 1.0 + (_fpaFactor * (FPA_temp - _refTemp)); + + // Create data + int nsamps = ToInteger(prof("Samples")); + _data = HiVector(nsamps, _baseT); + + // History + _history.add("FpaTemperatureFactor[" + ToString(_fpaFactor) + "]"); + _history.add("FpaAverageTemperature[" + ToString(FPA_temp) + "]"); + _history.add("FpaReferenceTemperature[" + ToString(_refTemp) + "]"); + _history.add("Correction[" + ToString(_baseT) + "]"); + return; + } + + double fetchFactor(const std::string &fname, const DbProfile &prof) { + + // Determine file and load characteristics + int skip = ConfKey(prof, "FpaTemperatureFactorSkipLines", 0); + bool header = IsTrueValue(prof, "FpaTemperatureFactorHeader"); + int nSkipped = skip + ((header) ? 1 : 0); + + + // Crack the file + Filename csvfile(fname); + CSVReader csv(csvfile.Expanded(), header, skip); + + // Set row/column targets + std::string ccdId = prof("Filter") + prof("Ccd"); + int channel = ToInteger(prof("Channel")); + + // Find the proper row + for (int i = 0 ; i < csv.rows() ; i++) { + CSVReader::CSVAxis cRow = csv.getRow(i); + iString csvCcdId = cRow[0]; + if (!csvCcdId.empty()) { + if (IsEqual(ccdId, csvCcdId.Trim(" \r\n\t"))) { + iString cfactor = cRow[channel+1]; + if (!cfactor.empty()) { + double factor = cfactor.Trim(" \r\n\t").ToDouble(); + _history.add("LoadCSV("+ fname +",Ccd[" + ToString(ccdId) + + "],Channel[" + ToString(channel) + + "],Skip["+ ToString(skip) + "],Row[" + + ToString(i+1) + "])") ; + return (factor); + } + else { + std::ostringstream mess; + mess << "Bad (empty) value in row " << nSkipped+i+1 + << ", column " << channel+2 + << " in CSV file " << fname; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + } + } + } + + // Did not find the proper row + std::ostringstream mess; + mess << "Cannot find Ccd/Channel (" << ccdId << "/" << channel + << ") match in CSV file " << fname; + throw iException::Message(iException::User, mess.str(), _FILEINFO_); + } + + }; + +} // namespace Isis +#endif + diff --git a/isis/src/mro/apps/hicalbeta/assets/DriftCorrect.pro b/isis/src/mro/apps/hicalbeta/assets/DriftCorrect.pro new file mode 100644 index 0000000000000000000000000000000000000000..1bade01acb9073eee8486cff1bdb5ef5871b708e --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/assets/DriftCorrect.pro @@ -0,0 +1,88 @@ +;driftcorrect.pro Version 10Oct 07 +PRO gauss4, x, a, f, pder +; Implement the function y = a[0] + a[1]*x + a[2] * exp(a[3] * x) +; return the value of the function as f, and the value of +; the partials at the value of x in pder[4]. +; let p0 = exp(a[3]*x) +; dy/da[0] = 1. +; dy/da[1] = x +; dy/da[2] = p0 +; dy/da[3] = a[2] * x * p0 + +nx = n_elements(x) +; Note: the next two lines of code are added/changed +maxLog = 87.0 ;approx log of max finite single FP value +; Note, if you use double throughout, maxLog is around 709. It +; shouldn't matter because normally the term should be < 1. +p0 = double(exp(a[3]*x < maxLog)) +f = a[0] + a[1] * x + a[2] * p0 +if total(finite(f)) ne nx then stop +; Partial of y with respsect to a[i]: +pder = [[ replicate(1., nx)], [x], [p0], [a[2]*x*p0]] +end + +Function DriftCorrect, buffer, info, params, x, STATUS=status +; return the drift correction profile for an image. This is obtained by +; fitting the function y = a[0] + a[1]*x + a[2] * exp(a[3] * x) +; to the mean of the buffer pixels for each line. +; +; Inputs: +; buffer[info.nline] = mean of buffer pixel columns [5:11] for each line of image. +; info = header structure for image +; Outputs: +; params = parameters of function fit to the buffer area [4]. +; Function value = [info.nline] vector of drift values / line. +; Time 0 is defined as the time of the start of the 1st image line. +; x = time vector [info.nline], in seconds. +; STATUS = status of fit. 0 for OK, 1 for ChiSq increasing without +; bounds, 2 for did not converge. +; + +sWidth = 17 ;Width of our smoother +n0 = 20 + (20 + info.tdi) / info.bin ;Image starting line +n = info.nline - n0 ;# of image lines + +if info.nline lt 4000 then begin ;short image? + x = findgen(n) * (info.bin * info.linetime * 1.0e-6) ;time in seconds [n] + cc = poly_fit(x, buffer[n0:*], 1, yfit2) ;just use linear + params = [cc[0], cc[1], 0.0, 1.0] + status = 0 + return, yfit2 +endif + +last = info.nline - info.trim/info.bin - 1 ;Last line to use +b1 = buffer[n0 : last] ;Extract rows we care about +nb = n_elements(b1) +b2 = smooth(b1, sWidth, /EDGE) ;Smooth +x = findgen(nb) * (info.bin * info.linetime * 1.0e-6) ;time in seconds [nb] +xmax = x[nb-1] ;Last time value + +; Fit a straight line to latter half of data for initial estimates +nb2 = nb/2 +cc = poly_fit(x[nb2:*], b2[nb2:*], 1) ;linear fit +resid = b2 - (cc[0] + x * cc[1]) ;residuals + +tail = mean(resid[0.9*nb : *]) ;mean of tail area +head = mean(resid[0:20]) ;mean of start area + + ; fit y = a[0] + a[1]*x + a[2] * exp(a[3] * x) GAUSS4 +a = [cc[0], cc[1], head-tail, -5./xmax] ;Initial guess for params +a0 = a +yfit2 = curvefit(x, b1, replicate(1., nb), a, $ + FUNCTION_NAME="GAUSS4", STATUS=status, ITER=iter, ITMAX=100) +; print, 'ITER = ', iter +if status ne 0 then begin ;Did fit work?? it might not have converged. + print, 'Could not fit, using straight line., status = ', status + print, info.obs_id, ', CCD/CHL ', info.ccd, info.channel + print, 'Initial: ', a0 + print, 'Fit: ', a + cc = poly_fit(x, b1, 1) ;Punt & fit a straight line + a = [cc[0], cc[1], 0.0, -1.0] ;i.e. exp coeff = 0 +endif + +; recalculate x and yfit2 for entire image area +x = findgen(info.nline-n0) * (info.bin * info.linetime * 1.0e-6) ;time in seconds +yfit2 = a[0] + a[1] * x + a[2] * exp(a[3] * x) +params = a ;Return function params. +return, yfit2 +end diff --git a/isis/src/mro/apps/hicalbeta/assets/ReverseClockStatistics.XXXX.conf b/isis/src/mro/apps/hicalbeta/assets/ReverseClockStatistics.XXXX.conf new file mode 100644 index 0000000000000000000000000000000000000000..cd142da3efd2626a85fc65ee801da1b297f17e31 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/assets/ReverseClockStatistics.XXXX.conf @@ -0,0 +1,607 @@ +# This file provides statistical triggers for the Reverse Clock region +# while processing the Zz hicalbeta module for OffsetCorrection. +# Updates made by EME 03/18/2009 - trigger STD values have been increased for most +# CCD/Channel/Binning combinations. Noise levels should be higher before reverting to +# use of the RevMeanTrigger value. In each profile, the comment line refers to the +# original value. +# +# $Id: ReverseClockStatistics.XXXX.conf,v 1.2 2009/03/31 23:14:02 kbecker Exp $ +#CCD,CHN,BIN,Mean of Reverse Readout Mean,Reverse Readout STD Trigger, +Object = ReverseClockStatistics + ModuleAddendum = "hicalbeta::Zz" + Name = "ZzTriggers" + + Group = Profile +#RED0,0,1,1377.437,15.500 + Name = RED0_0_1 + RevMeanTrigger = 1377.437 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED1,0,1,1146.000,20.000 + Name = RED1_0_1 + RevMeanTrigger = 1146.000 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED2,0,1,1297.331,20.000 + Name = RED2_0_1 + RevMeanTrigger = 1297.331 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED3,0,1,1171.321,20.000, + Name = RED3_0_1 + RevMeanTrigger = 1171.321 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED4,0,1,1209.981,20.000, + Name = RED4_0_1 + RevMeanTrigger = 1209.981 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED5,0,1,1267.364,20.000, + Name = RED5_0_1 + RevMeanTrigger = 1267.364 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED6,0,1,1091.817,20.000 + Name = RED6_0_1 + RevMeanTrigger = 1091.817 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#RED7,0,1,1165.365,20.000, + Name = RED7_0_1 + RevMeanTrigger = 1165.365 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED8,0,1,1379.488,20.000, + Name = RED8_0_1 + RevMeanTrigger = 1379.488 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED9,0,1,1224.398,15.000, + Name = RED9_0_1 + RevMeanTrigger = 1224.398 + RevStdDevTrigger = 50.000 + EndGroup + + + + Group = Profile +#IR10,0,1,1252.294,12.500, + Name = IR10_0_1 + RevMeanTrigger = 1252.294 + RevStdDevTrigger = 50.0 + EndGroup + + + + Group = Profile +#IR11,0,1,1258.578,15.000, + Name = IR11_0_1 + RevMeanTrigger = 1258.578 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG12,0,1,1086.998,15.000, + Name = BG12_0_1 + RevMeanTrigger = 1086.998 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG13,0,1,1133.021,15.000, + Name = BG13_0_1 + RevMeanTrigger = 1133.021 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED0,0,2,1334.809,15.000, + Name = RED0_0_2 + RevMeanTrigger = 1334.809 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED1,0,2,1124.000,20.000 + Name = RED1_0_2 + RevMeanTrigger = 1124.000 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED2,0,2,1249.964,20.000 + Name = RED2_0_2 + RevMeanTrigger = 1249.964 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED3,0,2,1128.152,20.000 + Name = RED3_0_2 + RevMeanTrigger = 1128.152 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED4,0,2,1171.630,20.000 + Name = RED4_0_2 + RevMeanTrigger = 1171.630 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED5,0,2,1224.266,20.000 + Name = RED5_0_2 + RevMeanTrigger = 1224.266 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED6,0,2,1052.319,20.000 + Name = RED6_0_2 + RevMeanTrigger = 1052.319 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED7,0,2,1131.409,20.000 + Name = RED7_0_2 + RevMeanTrigger = 1131.409 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED8,0,2,1334.491,20.000 + Name = RED8_0_2 + RevMeanTrigger = 1334.491 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED9,0,2,1180.286,15.000 + Name = RED9_0_2 + RevMeanTrigger = 1180.286 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#IR10,1,1,1179.370,20.000 + Name = IR10_1_1 + RevMeanTrigger = 1179.370 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#IR11,1,1,1248.003,15.000 + Name = IR11_1_1 + RevMeanTrigger = 1248.003 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG12,1,1,1256.323,15.000 + Name = BG12_1_1 + RevMeanTrigger = 1256.323 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG13,1,1,1103.845,15.000 + Name = BG13_1_1 + RevMeanTrigger = 1103.845 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED0,0,4,1320.622,25.000 + Name = RED0_0_4 + RevMeanTrigger = 1320.622 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED1,0,4,1105.277,30.000 + Name = RED1_0_4 + RevMeanTrigger = 1105.277 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED2,0,4,1237.360,30.000 + Name = RED2_0_4 + RevMeanTrigger = 1237.360 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED3,0,4,1117.122,30.000 + Name = RED3_0_4 + RevMeanTrigger = 1117.122 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED4,0,4,1169.959,30.000 + Name = RED4_0_4 + RevMeanTrigger = 1169.959 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED5,0,4,1222.106,30.000 + Name = RED5_0_4 + RevMeanTrigger = 1222.106 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED6,0,4,1042.101,30.000 + Name = RED6_0_4 + RevMeanTrigger = 1042.101 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED7,0,4,1124.990,30.000 + Name = RED7_0_4 + RevMeanTrigger = 1124.990 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED8,0,4,1320.220,30.000 + Name = RED8_0_4 + RevMeanTrigger = 1320.220 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED9,0,4,1164.266,30.000 + Name = RED9_0_4 + RevMeanTrigger = 1164.266 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#IR10,0,2,1214.563,12.500 + Name = IR10_0_2 + RevMeanTrigger = 1214.563 + RevStdDevTrigger = 50.0 + EndGroup + + Group = Profile +#IR11,0,2,1223.046,15.000 + Name = IR11_0_2 + RevMeanTrigger = 1223.046 + RevStdDevTrigger = 50.00 + EndGroup + + Group = Profile +#BG12,0,2,1052.550,15.000 + Name = BG12_0_2 + RevMeanTrigger = 1052.550 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG13,0,2,1107.637,15.000 + Name = BG13_0_2 + RevMeanTrigger = 1107.637 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED0,1,1,1477.663,30.000 + Name = RED0_1_1 + RevMeanTrigger = 1477.663 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED1,1,1,1223.837,20.000 + Name = RED1_1_1 + RevMeanTrigger = 1223.837 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED2,1,1,1204.893,20.000 + Name = RED2_1_1 + RevMeanTrigger = 1204.893 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED3,1,1,1308.787,20.000 + Name = RED3_1_1 + RevMeanTrigger = 1308.787 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED4,1,1,1187.757,20.000 + Name = RED4_1_1 + RevMeanTrigger = 1187.757 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED5,1,1,1470.160,25.000 + Name = RED5_1_1 + RevMeanTrigger = 1470.160 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED6,1,1,1283.151,20.000 + Name = RED6_1_1 + RevMeanTrigger = 1283.151 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED7,1,1,1487.898,20.000 + Name = RED7_1_1 + RevMeanTrigger = 1487.898 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED8,1,1,1501.543,20.000 + Name = RED8_1_1 + RevMeanTrigger = 1501.543 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED9,1,1,1388.820,15.000 + Name = RED9_1_1 + RevMeanTrigger = 1388.820 + RevStdDevTrigger = 60.000 + EndGroup + + Group = Profile +#IR10,1,2,1099.481,20.000 + Name = IR10_1_2 + RevMeanTrigger = 1099.481 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#IR11,1,2,1213.113,15.000 + Name = IR11_1_2 + RevMeanTrigger = 1213.113 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG12,1,2,1222.681,15.000 + Name = BG12_1_2 + RevMeanTrigger = 1222.681 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#BG13,1,2,1079.180,15.000 + Name = BG13_1_2 + RevMeanTrigger = 1079.180 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED0,1,2,1428.761,20.000 + Name = RED0_1_2 + RevMeanTrigger = 1428.761 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED1,1,2,1182.345,20.000 + Name = RED1_1_2 + RevMeanTrigger = 1182.345 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED2,1,2,1158.733,20.000 + Name = RED2_1_2 + RevMeanTrigger = 1158.733 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED3,1,2,1259.021,20.000 + Name = RED3_1_2 + RevMeanTrigger = 1259.021 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED4,1,2,1148.770,20.000 + Name = RED4_1_2 + RevMeanTrigger = 1148.770 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED5,1,2,1414.494,20.000 + Name = RED5_1_2 + RevMeanTrigger = 1414.494 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED6,1,2,1239.251,20.000 + Name = RED6_1_2 + RevMeanTrigger = 1239.251 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED7,1,2,1434.345,20.000 + Name = RED7_1_2 + RevMeanTrigger = 1434.345 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED8,1,2,1451.082,20.000 + Name = RED8_1_2 + RevMeanTrigger = 1451.082 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#RED9,1,2,1337.753,15.000 + Name = RED9_1_2 + RevMeanTrigger = 1337.753 + RevStdDevTrigger = 50.000 + EndGroup + + Group = Profile +#IR10,0,4,1206.694,22.500 + Name = IR10_0_4 + RevMeanTrigger = 1206.694 + RevStdDevTrigger = 100.0 + EndGroup + + Group = Profile +#IR11,0,4,1216.140,30.000 + Name = IR11_0_4 + RevMeanTrigger = 1216.140 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#BG12,0,4,1045.235,30.000 + Name = BG12_0_4 + RevMeanTrigger = 1045.235 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#BG13,0,4,1097.588,30.000 + Name = BG13_0_4 + RevMeanTrigger = 1097.588 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED0,1,4,1414.764,30.000 + Name = RED0_1_4 + RevMeanTrigger = 1414.764 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED1,1,4,1161.233,30.000 + Name = RED1_1_4 + RevMeanTrigger = 1161.233 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED2,1,4,1147.600,30.000 + Name = RED2_1_4 + RevMeanTrigger = 1147.600 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED3,1,4,1246.268,30.000 + Name = RED3_1_4 + RevMeanTrigger = 1246.268 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED4,1,4,1147.855,30.000 + Name = RED4_1_4 + RevMeanTrigger = 1147.855 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED5,1,4,1399.185,30.000 + Name = RED5_1_4 + RevMeanTrigger = 1399.185 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED6,1,4,1224.519,30.000 + Name = RED6_1_4 + RevMeanTrigger = 1224.519 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED7,1,4,1414.525,30.000 + Name = RED7_1_4 + RevMeanTrigger = 1414.525 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED8,1,4,1436.337,30.000 + Name = RED8_1_4 + RevMeanTrigger = 1436.337 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#RED9,1,4,1322.071,30.000 + Name = RED9_1_4 + RevMeanTrigger = 1322.071 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#IR10,1,4,1092.773,30.000 + Name = IR10_1_4 + RevMeanTrigger = 1092.773 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#IR11,1,4,1205.192,30.000 + Name = IR11_1_4 + RevMeanTrigger = 1205.192 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#BG12,1,4,1212.918,30.000 + Name = BG12_1_4 + RevMeanTrigger = 1212.918 + RevStdDevTrigger = 100.000 + EndGroup + + Group = Profile +#BG13,1,4,1069.859,30.000 + Name = BG13_1_4 + RevMeanTrigger = 1069.859 + RevStdDevTrigger = 100.000 + EndGroup +EndObject + + diff --git a/isis/src/mro/apps/hicalbeta/assets/clean6.pro b/isis/src/mro/apps/hicalbeta/assets/clean6.pro new file mode 100644 index 0000000000000000000000000000000000000000..d74281318828fae5fe7a80629f0e45c25a97d86a --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/assets/clean6.pro @@ -0,0 +1,70 @@ +;clean6.pro +;need the following +;restore, 'c:\hirise\data\dark4\b_matrix_25nov07.sav +; dark current matrices 28 channels of 1024/bin columns by 4 tdi +; +;restore,'c:\hirise\data\dark4\temp_profiles.sav' +; temperature profiles matrices 256 columns by 4 tdi by intercept and slope +; +;History +; 1/5/08 Alan changed image variable from zz to z to use less memory +;10 jan 08 Alan added provision for having no b_matrix +; +function clean6,z,info,b_matrix,t_intercept,t_slope +nc=info.ncol +tdi=info.tdi +case tdi of +128: itdi=0 +64: itdi=1 +32: itdi=2 +8: itdi=3 +endcase +;z=zz ; i preserved original for debugging +; +removemissing, z, bad=fmissing ; get rid of gaps +; +;drift correction + swidth=11 + ave_cols, z, 5, 11, b ;get row means for buffer pixels, cols[5:11] + iccd = info.ccd + ichl = info.channel + l0 = 20 + (20 + info.tdi) / info.bin ;image starting line + b = smooth(b, swidth, /edge) ; need for initial parameters + drift = driftcorrect(b, info, params, x, status=status) ;get drift function +; print,params ;for debugging and watching progress + drift=drift-drift(0) + nl=info.nline + for iline=long(l0),nl-1 do z(*,iline)=z(*,iline)-drift(iline-l0) + ; +;offset correction +ave_lines,z,1,19,offset,sd +for iline=0l,nl-1 do z[0,iline] = z[*,iline]-offset +; +;dc subtraction + w=where(b_matrix.ccd eq info.ccd and $ + b_matrix.ch eq info.channel and $ + b_matrix.tdi eq info.tdi and $ + b_matrix.bin eq info.bin, count) ;finds right dark current matrix +if w(0) eq -1 then print,info.obs_id, ' No b_matrix available used mask' + +temp=(info.fpa_py_temp+info.fpa_my_temp)/2 ;use average baseplate temperature +t_prof=rebin(smooth(t_intercept(*,itdi),3,/edge)+smooth(t_slope(*,itdi),3,/edge)*temp,1024/info.bin);convert to correct number of columns +; i have left the smoothing in for the time being. after testing we can fix it +t_profile=[fltarr(12)+temp,t_prof,fltarr(16)+temp] ;i process all columns as it is useful for diagnostic tests +; +if w(0) ne -1 then dc = b_matrix(w).matrix(0:nc-1) * $ ;b[nc] = dn / px / sec + info.linetime * 1e-6 * $ ;scale by time + info.bin^2 * $ ;bin area + (20*103/89. + info.tdi) * $ ;we're doing 20 masked lines of larger area + tdi area + tempeqn(t_profile, 2, 12) / tempeqn(21, 2, 12) $ ;dc at temp=21c. is the reference + else ave_lines,z,20,20+20/info.bin-1,dc + + + dcs = smooth(dc[12:nc-17],3,/edge) + dc[12:nc-17] = dcs ;replace by smoothed b + + for iline=20l,nl-1 do z[0,iline] = z[*,iline]-dc +;__________________________________________________ +;stop +return,z +end diff --git a/isis/src/mro/apps/hicalbeta/assets/hicalbeta.XXXX.conf b/isis/src/mro/apps/hicalbeta/assets/hicalbeta.XXXX.conf new file mode 100644 index 0000000000000000000000000000000000000000..ff99e1c90ec8892a0c0a38e03f94a5768ee13cf8 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/assets/hicalbeta.XXXX.conf @@ -0,0 +1,241 @@ +# HiRISE Calibration Matricies configuration file +# See documentation for the hical application on the content and form of +# this file. +# $Id: hicalbeta.XXXX.conf,v 1.16 2010/01/29 16:09:51 kbecker Exp $ +Object = Hical + + Program = "hicalbeta" + + Name = "HiMatrices" + DefaultProfile = "HiMatrices" + +/* If you want to rerun hical, you must set PropagateTables to True. Use */ +/* this in conjuction with Debug::SkipModule = True option for each module. */ + PropagateTables = False + +/* Define label groups that are loaded for each profile reference */ +/* Note all keywords in these groups become available to all profiles. */ +/* Thus, you can use them in the OptionKeywords and ProfileOptions keywords */ +/* to create very specialized profiles for special needs. */ +/* Specify the FPA reference temperature. It is used in several modules so */ +/* it is specified at the top level */ + + LabelGroups = ( "Dimensions", "Instrument", "Archive") + +/* These keywords are used in ProfileOptions mapping. Note that order and */ +/* case matter! WARNING: You can easily break file lookups if these keys */ +/* are deleted or modified improperly!!! */ + OptionKeywords = ("FILTER", "CCD", "CHANNEL", "TDI", "BIN", "ProductId", + "Program", "Module", "OPATH", "CalOptions") + +/* Additional profile combinations and order load hierarchy. These keywords */ +/* are defined when the LabelGroups are loaded. */ +/* Kris Becker & Eric Eliason updated 10/24/2008 */ +/* ProfileOptions value added: {Module}_{CalOptions} */ + ProfileOptions = ("{FILTER}", "TDI{TDI}", "BIN{BIN}", "TDI{TDI}/BIN{BIN}", + "{FILTER}{CCD}_{CHANNEL}", + "{FILTER}{CCD}_{CHANNEL}/TDI{TDI}/BIN{BIN}", "Debug", + "{Module}_{CalOptions}") + +/* Specify the FPA reference temperature. It is used in several modules so */ +/* it is specified at the top level */ + FpaReferenceTemperature = 21.0 + +/* This profile contains parameters pertinent to processing the buffer */ +/* pixels for subsequent using in the drift correction, Zd module */ + Group = Profile + Name = Zf + Module = Zf + ZfFirstSample = 5 + ZfLastSample = 11 + + ZfFilterWidth = 201 + ZfFilterIterations = 2 + End_Group + +/* This profile contains parameters pertinent to processing drift correction */ + Group = Profile + Name = Zd + Module = Zd + + /* Uncomment to turn off non linear fitting of Zf data and pass it thru */ + ZdSkipFit = True + + /* Uncomment to use linear fitting of Zf data when non-linear fails */ + /* Default is to pass thru filtered Zf data */ + /* ZdOnFailUseLinear = True */ + + /* Minimum number of good lines (NLines - (TrimLines/Summing)) to fit */ + ZdMinimumLines = 250 + + /* Maximum number of iterations for the algorithm to converge and */ + /* other limits */ + MaximumIterations = 100 + MaximumLog = 709.0 + + /* Convergence parameters for Levenberg-Marquardt algorithm */ + /* Equation is solved when |dx_i| < AbsoluteError + RelativeError * |x_i| */ + /* where dx is the last step and x is the current step for each i-th */ + /* value */ + AbsoluteError = 1.0E-4 + RelativeError = 1.0E-4 + + /* Filtering of the guestimate buffer */ + GuessFilterWidth = 17 + GuessFilterIterations = 1 + +# DumpModuleFile = "{ProductId}_{Module}.log" + End_Group + +/* This profile contains parameters pertinent to processing the offset */ + Group = Profile + Name = Zz + Module = Zz + +/* Set calibration parameters for hiclean operations. Indexes are all 0-based */ + ZzFirstLine = 1 + ZzLastLine = 19 + + +/* Reverse Clock trigger Statistics profiles */ + ReverseClockStatistics = "$mro/calibration/matrices/beta/ReverseClockStatistics.????.conf" + RevLisTolerance = 1 + RevHisTolerance = 1 + RevNulTolerance = 1 + End_Group + +/* Skip reverse clock if the ReverseReadoutNoise is to large */ +/* Profile added by Kris Becker & Eric Eliason, 10/25/2008 */ + Group = Profile + Name = Zz_ReverseReadoutNoise + Debug::SkipModule = True + End_Group + +/* This profile contains parameters pertinent to processing dark current. */ +/* Required label keywords: Summing, Tdi, FpaPositiveYTemperature, */ +/* and FpaNegativeYTemperature, Lines */ +/* Also needs LineTime which is computed. */ + Group = Profile + Name = Zb + Module = Zb + +/* Define the B matrix file reference */ + B = "$mro/calibration/matrices/beta/B_TDI{TDI}_BIN{BIN}_hicalbeta_????.cub" + SkipLines = 1 + Slope = "$mro/calibration/matrices/beta/t_slope_CH{CHANNEL}_hicalbeta_????.csv" + Intercept = "$mro/calibration/matrices/beta/t_intercept_CH{CHANNEL}_hicalbeta_????.csv" + + /* Do filtering? */ + ZbFilterWidth = 3 + ZbFilterIterations = 1 + End_Group + +/* This profile contains parameters pertinent to processing gain correction. */ +/* Required label keywords: CpmmNumber, ChannelNumber, Lines */ +/* This module has been reactivated as of 2010-01-29 */ + Group = Profile + Name = Zg + Module = Zg + + SkipLines = 1 +/* Added "_hicalbeta" to filename as of 2008-04-02. This is consistant with */ +/* naming convention used for the beta version of hical. */ + GainLineCoefficients = "$mro/calibration/matrices/beta/line_correct_{BIN}_hicalbeta_????.csv" + End_Group + +/* This profile contains parameters pertinent to processing gain correction. */ +/* Required label keywords: CpmmNumber, ChannelNumber, Lines */ + Group = Profile + Name = Zgg + Module = Zgg + +/* Define the G matrix file reference */ + G = "$mro/calibration/matrices/beta/G_TDI{TDI}_BIN{BIN}_hicalbeta_????.cub" + End_Group + +/* This profile contains parameters pertinent to processing gain correction. */ +/* Required label keywords: CpmmNumber, ChannelNumber, Tdi, Lines */ + Group = Profile + Name = Za + Module = Za + +/* Applies a temperature correction factor to A matrix */ +/*** As of 2009-09-15 this parameter is implemented in the Zt module ***/ +/*** It remains here for backward compatability for now. It will be ***/ +/*** removed at some point in future releases. ***/ + ZaFpaTemperatureFactor = 0.005 + +/* Define the A matrix file reference */ + A = "$mro/calibration/matrices/beta/A_TDI{TDI}_BIN{BIN}_hicalbeta_????.cub" + End_Group + +/* This profile contains parameters pertinent to processing */ +/* temperature-dependant gain correction. Formally in Za module. */ +/* Required label keywords: CpmmNumber, ChannelNumber, Samples */ + Group = Profile + Name = Zt + Module = Zt + +/* Define temperature-dependant gain correction CSV file */ + FpaTemperatureFactorSkipLines = 4 + FpaTemperatureFactorHeader = True + FpaTemperatureFactorFile = "$mro/calibration/matrices/beta/FpaTemperatureGain_BIN{BIN}.????.csv" + End_Group + +/* This profile contains parameters pertinent to processing I/F conversion. */ +/* Required label keywords: ScanExposureDuration */ + Group = Profile + Name = Ziof + Module = Ziof + +/* I/F correction for tdi/bin - currently set at 1.0 for all tdi/bin */h +/* combinations. */ + ZiofBinFactor = 1.0 + End_Group + +/* Here are the filter profiles. All keywords that pertain to a filter set */ +/* should be specified here. FilterGainCorrection are I/F corrections in */ +/* units of DN/s. */ + Group = Profile + Name = RED + FilterGainCorrection = 159423899.0 + End_Group + + Group = Profile + Name = IR + FilterGainCorrection = 58018177.0 + End_Group + + Group = Profile + Name = BG + FilterGainCorrection = 108811104.0 + End_Group + + Group = Profile + Name = IR10_1 +# LastGoodLine = 3100 + End_Group + + + Group = Profile + Name = Debug + +/** Current disables writting to label history due to bug in keyword formatter in ISIS **/ +/* The bug has the following error signature: */ +/* terminate called after throwing an instance of 'std::out_of_range' */ +/* what(): basic_string::substr */ +/* Abort */ +/* You must set this to false when this occurs as a workaround and use the */ +/* DumpHistoryFile parameter to see the parameter history. */ + LogParameterHistory = False + +/* Uncomment this line to write parameter history to the ProductId log */ + DumpHistoryFile = "{OPATH}/{ProductId}.{Program}.log" + +/* Uncomment this line to dump Module data for every module when using Debug */ +/* profiling. */ +# DumpModuleFile = "{OPATH}/{ProductId}_{Module}.log" + End_Group + +End_Object + diff --git a/isis/src/mro/apps/hicalbeta/assets/line_correction.pro b/isis/src/mro/apps/hicalbeta/assets/line_correction.pro new file mode 100644 index 0000000000000000000000000000000000000000..5f0b180737b84f6c0535affb32dcd16b88535b51 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/assets/line_correction.pro @@ -0,0 +1,20 @@ +;line_correction.pro +function line_correction,z,info,line_correct +l=findgen(info.nline) +t=l*info.linetime*1e-6*info.bin +i=info.ccd +k=info.channel +; +case info.bin of +1: ibin=0 +2: ibin=1 +4: ibin=2 +endcase +; +lin_cor=line_correct(i,k,ibin,0)+line_correct(i,k,ibin,1)*t+line_correct(i,k,ibin,2)*exp(line_correct(i,k,ibin,3)*t) +start=20l+(20+info.tdi)/info.bin +nl=info.nline +;stop +for il=start,nl-1 do z(*,il)=z(*,il)/lin_cor(il-start) +return,z +end diff --git a/isis/src/mro/apps/hicalbeta/assets/test_mdr_15feb08.pro b/isis/src/mro/apps/hicalbeta/assets/test_mdr_15feb08.pro new file mode 100644 index 0000000000000000000000000000000000000000..331b015d501cf641a44ec23c0948b71fda67df1d --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/assets/test_mdr_15feb08.pro @@ -0,0 +1,91 @@ +;test_mdr_15feb08.pro +pro test_mdr, obs +; +files=file_search(obs,'*.IMG') +nf=n_elements(files) + mode_bin=intarr(14,2) + mode_tdi=intarr(14,2) + n_lines=lonarr(14,2) + w_times=fltarr(14,2) +; +t0=systime(1) +; +for j=0,nf-1 do begin + if files(j) ne '' then begin + rheader,files(j),info,0 + iccd=info.ccd & ich=info.channel + bin=info.bin + tdi=info.tdi + start= 20+(20+tdi)/bin + n_lines(iccd,ich)=long(info.nline-start)*bin + w_times(iccd,ich)=time_secs(info.start_time)-time_secs(info.analog_on_time) + mode_bin(iccd,ich)=bin + mode_tdi(iccd,ich)=tdi + endif + endfor +max_lines=max(n_lines) + +center0=fltarr(14,2,max_lines) +overlap=center0 +imagemean= center0 +restore,'c:\hirise_idl\matrices\save\a_matrix_composite_1feb08.sav' +restore,'c:\hirise_idl\matrices\save\b_matrix_2dec07.sav' +restore,'c:\hirise_idl\matrices\save\gain_15feb08.sav' +restore,'c:\hirise_idl\matrices\save\temp_profiles.sav' +restore,'c:\hirise_idl\matrices\save\line_correct_15Feb08A.sav' +ggain=gain +t0=systime(1) +print,systime(1)-t0 +for i= 0,nf-1 do begin + rchannel,files(i),z,info,0 +; if info.luntype ne 0 then print,'lutted image',info.file + if (time_secs(info.start_time)-time_secs(info.analog_on_time)) gt 150 then begin + start=20+(20+info.tdi)/info.bin + nc=info.ncol + ncol=info.ncol + nlines = info.nline + ccd=info.ccd & ch =info.channel & tdi=info.tdi & bin=info.bin + w=where((a_matrix.ccd eq ccd) and (a_matrix.ch eq ch )and a_matrix.tdi eq tdi and a_matrix.bin eq bin) ;& help,w + if w(0) ne -1 then a=1/a_matrix(w).matrix else a=fltarr(1052)+1 + z=clean6(z,info,b_matrix,t_intercept,t_slope) + + z=line_correction(z,info,line_correct) + + FPA_temp=(info.fpa_py_temp+info.fpa_my_temp)/2 + for j=0l,info.nline-1 do z(12,j) =z(12:info.ncol-16-1,j)*a(12:info.ncol-16-1)*(1+0.005*(FPA_temp-21)) + +; print,i,' ccd=',ccd,' ch=',ch,' tdi=',tdi,' bin=',bin,ncol,nlines + + case bin of + 1: ibin=0 + 2: ibin=1 + 4: ibin=2 + 8: ibin=3 + else: stop,'wrong bin number' + endcase + + factor=ggain(info.ccd,info.channel,ibin)*128/tdi/bin^2 ;normalizes gain + nl=info.nline + for il=0l,nl-1 do z(*,il)=z(*,il)*factor +;--------------------------------------- + wchannel_mdr,files(i),z>0,0 + start= 20+(20+info.tdi)/bin + endline=info.nline-1 + ave_cols,z(12:12+1024/bin-1,start:endline),0,24/bin,c + center0(info.ccd,info.channel,0:(endline-start+1)*info.bin-1) = rebin(c,max_lines) + ave_cols,z(12:12+1024/bin-1,start:endline),(1024-24)/bin,1024/bin-1,over + overlap(info.ccd,info.channel,0:(endline-start+1)*info.bin-1) = rebin(over,max_lines) + ave_cols,z(12:12+1024/bin-1,start:endline),0,1024/bin-1,m + + imagemean(info.ccd,info.channel,0:(endline-start+1)*info.bin-1)=rebin(m,max_lines) +; + endif ; + print,files(i),systime(1)-t0 + wait,0.05 + endfor + pos=strpos(obs,'PSP') +obsname=strmid(obs,pos,15) +fileb= 'C:\HiRISE\Data\test_mdr_images\results\'+obsname+'_join_data_A.sav' +save,filename=fileb,files,center0,overlap,imagemean,mode_bin,mode_tdi,info +; +end diff --git a/isis/src/mro/apps/hicalbeta/hicalbeta.cpp b/isis/src/mro/apps/hicalbeta/hicalbeta.cpp new file mode 100644 index 0000000000000000000000000000000000000000..85189b584cf5bb1ded8f88e1fe064603f276bf29 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/hicalbeta.cpp @@ -0,0 +1,473 @@ +// $Id: hicalbeta.cpp,v 1.14 2009/09/15 21:56:44 kbecker Exp $ +#include "Isis.h" + +#include +#include +#include +#include +#include +#include + +#include "Filename.h" +#include "ProcessByLine.h" +#include "UserInterface.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "iString.h" +#include "HiCalConf.h" +#include "CollectorMap.h" +#include "HiCalTypes.h" +#include "HiCalUtil.h" +#include "HiCalData.h" +#include "SplineFillComp.h" +#include "LowPassFilterComp.h" +#include "DriftBuffer.h" +#include "DriftCorrect.h" +#include "OffsetCorrect.h" +#include "DarkSubtractComp.h" +#include "GainVLineComp.h" +#include "FlatFieldComp.h" +#include "TempGainCorrect.h" + + +using namespace Isis; +using namespace std; + +//!< Define the matrix container for systematic processing +typedef CollectorMap MatrixList; + +// Calibration parameter container +MatrixList *calVars = 0; + +/** + * @brief Apply calibration to each HiRISE image line + * + * This function applies the calbration equation to each input image line. It + * gets matrices and constants from the \b calVars container that is established + * in the main with some user input via the configuration (CONF) parameter. + * + * @param in Input raw image line buffer + * @param out Output calibrated image line buffer + */ +void calibrate(Buffer &in, Buffer &out) { + const HiVector &Zd = calVars->get("Zd"); + const HiVector &Zz = calVars->get("Zz"); + const HiVector &Zb = calVars->get("Zb"); + const HiVector &Zg = calVars->get("Zg"); + const HiVector &Zgg = calVars->get("Zgg"); + const HiVector &Za = calVars->get("Za"); + const HiVector &Zt = calVars->get("Zt"); + double Ziof = calVars->get("Ziof")[0]; + + // Set current line (index) + int line(in.Line()-1); + if (calVars->exists("LastGoodLine")) { + int lastline = ((int) (calVars->get("LastGoodLine"))[0]) - 1; + if ( line > lastline ) { line = lastline; } + } + + // Apply correction + for (int i = 0 ; i < in.size() ; i++) { + if (IsSpecial(in[i])) { + out[i] = in[i]; + } + else { + double hdn; + hdn = (in[i] - Zd[line] - Zz[i] - Zb[i]); // Drift, Offset, Dark + hdn = hdn / Zg[line] * Zgg[i] * Za[i] * Zt[i]; // GainVLine, Gain, FlatField, TempGain + out[i] = hdn / Ziof; // I/F or DN or DN/US + } + } + return; +} + + +void IsisMain(){ + + const std::string hical_program = "hicalbeta"; + const std::string hical_version = "3.5"; + const std::string hical_revision = "$Revision: 1.14 $"; + const std::string hical_runtime = Application::DateTime(); + + UserInterface &ui = Application::GetUserInterface(); + + string procStep("prepping phase"); + try { +// The output from the last processing is the input into subsequent processing + ProcessByLine p; + + Cube *hifrom = p.SetInputCube("FROM"); + int nsamps = hifrom->Samples(); + int nlines = hifrom->Lines(); + +// Initialize the configuration file + string conf(ui.GetAsString("CONF")); + HiCalConf hiconf(*(hifrom->Label()), conf); + DbProfile hiprof = hiconf.getMatrixProfile(); + +// Check for label propagation and set the output cube + Cube *ocube = p.SetOutputCube("TO"); + if ( !IsTrueValue(hiprof,"PropagateTables", "TRUE") ) { + RemoveHiBlobs(*(ocube->Label())); + } + +// Set specified profile if entered by user + if (ui.WasEntered("PROFILE")) { + hiconf.selectProfile(ui.GetAsString("PROFILE")); + } + + +// Add OPATH parameter to profiles + if (ui.WasEntered("OPATH")) { + hiconf.add("OPATH",ui.GetAsString("OPATH")); + } + else { + // Set default to output directory + hiconf.add("OPATH", Filename(ocube->Filename()).Path()); + } + +// Do I/F output DN conversions + string units = ui.GetString("UNITS"); + + // Allocate the calibration list + calVars = new MatrixList; + +// Set up access to HiRISE ancillary data (tables, blobs) here. Note it they +// are gone, this will error out. See PropagateTables in conf file. + HiCalData caldata(*hifrom); + +//////////////////////////////////////////////////////////////////////////// +// FixGaps (Z_f) Get buffer pixels and compute coefficients for equation +// y = a[0] + a[1]*x + a[2] * exp(a[3] * x) +// where y is the average of the buffer pixel region, +// and x is the time at each line in electrons/sec/pixel + procStep = "Zf module"; + hiconf.selectProfile("Zf"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZfHist; + ZfHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + DriftBuffer driftB(caldata, hiconf); + calVars->add("Zf", driftB.ref()); + ZfHist = driftB.History(); + if ( hiprof.exists("DumpModuleFile") ) { + driftB.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + // NOT RECOMMENDED! This is required for the next step! + // SURELY must be skipped with Z_d step as well! + calVars->add("Zf", HiVector(nlines, 0.0)); + ZfHist.add("Debug::SkipModule invoked!"); + } + +///////////////////////////////////////////////////////////////////// +// DriftCorrect (Z_d) +// Now compute the equation of fit +// + procStep = "Zd module"; + HiHistory ZdHist; + hiconf.selectProfile("Zd"); + hiprof = hiconf.getMatrixProfile(); + ZdHist.add("Profile["+ hiprof.Name()+"]"); + if (!SkipModule(hiconf.getMatrixProfile("Zd")) ) { + DriftCorrect driftC(hiconf); + calVars->add("Zd", driftC.Normalize(driftC.Solve(calVars->get("Zf")))); + ZdHist = driftC.History(); + if ( hiprof.exists("DumpModuleFile") ) { + driftC.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Zd", HiVector(nlines, 0.0)); + ZdHist.add("Debug::SkipModule invoked!"); + } + + + //////////////////////////////////////////////////////////////////// + // ZeroCorrect (Z_z) Get reverse clock + procStep = "Zz module"; + hiconf.selectProfile("Zz"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZzHist; + ZzHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + OffsetCorrect zoff(caldata, hiconf); + calVars->add("Zz", zoff.ref()); + ZzHist = zoff.History(); + if ( hiprof.exists("DumpModuleFile") ) { + zoff.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Zz", HiVector(nsamps, 0.0)); + ZzHist.add("Debug::SkipModule invoked!"); + } + +///////////////////////////////////////////////////////////////// +// DarkSubtract (Z_b) Remove dark current +// + procStep = "Zb module"; + hiconf.selectProfile("Zb"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZbHist; + ZbHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + DarkSubtractComp dark(hiconf); + calVars->add("Zb", dark.ref()); + ZbHist = dark.History(); + if ( hiprof.exists("DumpModuleFile") ) { + dark.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Zb", HiVector(nsamps, 0.0)); + ZbHist.add("Debug::SkipModule invoked!"); + } + +//////////////////////////////////////////////////////////////////// +// GainVLineCorrect (Z_g) Correct for gain-based drift +// + procStep = "Zg module"; + hiconf.selectProfile("Zg"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZgHist; + ZgHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + GainVLineComp gainV(hiconf); + calVars->add("Zg", gainV.ref()); + ZgHist = gainV.History(); + if ( hiprof.exists("DumpModuleFile") ) { + gainV.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Zg", HiVector(nlines, 1.0)); + ZgHist.add("Debug::SkipModule invoked!"); + } + + +//////////////////////////////////////////////////////////////////// +// GainCorrect (Z_gg) Correct for gain with the G matrix + procStep = "Zgg module"; + hiconf.selectProfile("Zgg"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZggHist; + ZggHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + double bin = ToDouble(hiprof("Summing")); + double tdi = ToDouble(hiprof("Tdi")); + double factor = 128.0 / tdi / (bin*bin); + HiVector zgg = hiconf.getMatrix("G", hiprof); + for ( int i = 0 ; i < zgg.dim() ; i++ ) { zgg[i] *= factor; } + calVars->add("Zgg", zgg);; + ZggHist.add("LoadMatrix(G[" + hiconf.getMatrixSource("G",hiprof) + + "],Band[" + ToString(hiconf.getMatrixBand(hiprof)) + + "],Factor[" + ToString(factor) + "])"); + if ( hiprof.exists("DumpModuleFile") ) { + Component zg("GMatrix", ZggHist); + zg.Process(zgg); + zg.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Zgg", HiVector(nsamps, 1.0)); + ZggHist.add("Debug::SkipModule invoked!"); + } + +//////////////////////////////////////////////////////////////////// +// FlatField (Z_a) Flat field correction with A matrix + procStep = "Za module"; + hiconf.selectProfile("Za"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZaHist; + ZaHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + FlatFieldComp flat(hiconf); + calVars->add("Za", flat.ref()); + ZaHist = flat.History(); + if ( hiprof.exists("DumpModuleFile") ) { + flat.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Za", HiVector(nsamps, 1.0)); + ZaHist.add("Debug::SkipModule invoked!"); + } + +//////////////////////////////////////////////////////////////////// +// FlatField (Z_t) Temperature-dependant gain correction + procStep = "Zt module"; + hiconf.selectProfile("Zt"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZtHist; + ZtHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + TempGainCorrect tcorr(hiconf); + calVars->add("Zt", tcorr.ref()); + ZtHist = tcorr.History(); + if ( hiprof.exists("DumpModuleFile") ) { + tcorr.Dump(hiconf.getMatrixSource("DumpModuleFile",hiprof)); + } + } + else { + calVars->add("Zt", HiVector(nsamps, 1.0)); + ZtHist.add("Debug::SkipModule invoked!"); + } + + +//////////////////////////////////////////////////////////////////// +// I/FCorrect (Z_iof) Conversion to I/F +// + procStep = "Ziof module"; + hiconf.selectProfile("Ziof"); + hiprof = hiconf.getMatrixProfile(); + HiHistory ZiofHist; + ZiofHist.add("Profile["+ hiprof.Name()+"]"); + if ( !SkipModule(hiprof) ) { + double sed = ToDouble(hiprof("ScanExposureDuration")); // units = us + if ( IsEqual(units, "IOF") ) { + // Add solar I/F correction parameters + double au = hiconf.sunDistanceAU(); + ZiofHist.add("SunDist[" + ToString(au) + " (AU)]"); + double suncorr = 1.5 / au; + suncorr *= suncorr; + + double zbin = ToDouble(hiprof("ZiofBinFactor")); + ZiofHist.add("ZiofBinFactor[" + ToString(zbin) + "]"); + + double zgain = ToDouble(hiprof("FilterGainCorrection")); + ZiofHist.add("FilterGainCorrection[" + ToString(zgain) + "]"); + ZiofHist.add("ScanExposureDuration[" + ToString(sed) + "]"); + double ziof = (zbin * zgain) * (sed * 1.0e-6) * suncorr; + + calVars->add("Ziof", HiVector(1, ziof)); + ZiofHist.add("I/F_Factor[" + ToString(ziof) + "]"); + ZiofHist.add("Units[I/F Reflectance]"); + } + else if ( IsEqual(units, "DN/US") ) { + // Ziof is a divisor in calibration equation + double ziof = sed; + calVars->add("Ziof", HiVector(1, ziof)); + ZiofHist.add("ScanExposureDuration[" + ToString(sed) + "]"); + ZiofHist.add("DN/US_Factor[" + ToString(ziof) + "]"); + ZiofHist.add("Units[DNs/microsecond]"); + } + else { + // Units are already in DN + double ziof = 1.0; + calVars->add("Ziof", HiVector(1, ziof)); + ZiofHist.add("DN_Factor[" + ToString(ziof) + "]"); + ZiofHist.add("Units[DN]"); + } + } + else { + calVars->add("Ziof", HiVector(1,1.0)); + ZiofHist.add("Debug::SkipModule invoked!"); + ZiofHist.add("Units[Unknown]"); + } + + // Reset the profile selection to default + hiconf.selectProfile(); + +//---------------------------------------------------------------------- +// +///////////////////////////////////////////////////////////////////////// +// Call the processing function + procStep = "calibration phase"; + p.StartProcess(calibrate); + + // Get the default profile for logging purposes + hiprof = hiconf.getMatrixProfile(); + const std::string conf_file = hiconf.filepath(conf); + + // Quitely dumps parameter history to alternative format file. This + // is completely controlled by the configuration file + if ( hiprof.exists("DumpHistoryFile") ) { + procStep = "logging/reporting phase"; + Filename hdump(hiconf.getMatrixSource("DumpHistoryFile",hiprof)); + string hdumpFile = hdump.Expanded(); + ofstream ofile(hdumpFile.c_str(), ios::out); + if (!ofile) { + string mess = "Unable to open/create history dump file " + + hdump.Expanded(); + iException::Message(iException::User, mess, _FILEINFO_).Report(); + } + else { + ofile << "Program: " << hical_program << endl; + ofile << "RunTime: " << hical_runtime << endl; + ofile << "Version: " << hical_version << endl; + ofile << "Revision: " << hical_revision << endl << endl; + + ofile << "FROM: " << hifrom->Filename() << endl; + ofile << "TO: " << ocube->Filename() << endl; + ofile << "CONF: " << conf_file << endl << endl; + + ofile << "/* " << hical_program << " application equation */" << endl + << "/* hdn = (idn - Zd(Zf) - Zz - Zb) */" + << endl << "/* odn = hdn / Zg * Zgg * Za * Zt / Ziof */" + << endl << endl; + + ofile << "****** PARAMETER GENERATION HISTORY *******" << endl; + ofile << "\nZf = " << ZfHist << endl; + ofile << "\nZd = " << ZdHist << endl; + ofile << "\nZz = " << ZzHist << endl; + ofile << "\nZb = " << ZbHist << endl; + ofile << "\nZg = " << ZgHist << endl; + ofile << "\nZgg = " << ZggHist << endl; + ofile << "\nZa = " << ZaHist << endl; + ofile << "\nZt = " << ZtHist << endl; + ofile << "\nZiof = " << ZiofHist << endl; + + ofile.close(); + } + } + +// Ensure the RadiometricCalibration group is out there + const std::string rcalGroup("RadiometricCalibration"); + if (!ocube->HasGroup(rcalGroup)) { + PvlGroup temp(rcalGroup); + ocube->PutGroup(temp); + } + + PvlGroup &rcal = ocube->GetGroup(rcalGroup); + rcal += PvlKeyword("Program", hical_program); + rcal += PvlKeyword("RunTime", hical_runtime); + rcal += PvlKeyword("Version",hical_version); + rcal += PvlKeyword("Revision",hical_revision); + + PvlKeyword key("Conf", conf_file); + key.AddCommentWrapped("/* " + hical_program + " application equation */"); + key.AddComment("/* hdn = (idn - Zd(Zf) - Zz - Zb) */"); + key.AddComment("/* odn = hdn / Zg * Zgg * Za * Zt / Ziof */"); + rcal += key; + + // Record parameter generation history. Controllable in configuration + // file. Note this is optional because of a BUG!! in the ISIS label + // writer as this application was initially developed + if ( IsEqual(ConfKey(hiprof,"LogParameterHistory",string("TRUE")),"TRUE")) { + rcal += ZfHist.makekey("Zf"); + rcal += ZdHist.makekey("Zd"); + rcal += ZzHist.makekey("Zz"); + rcal += ZbHist.makekey("Zb"); + rcal += ZgHist.makekey("Zg"); + rcal += ZggHist.makekey("Zgg"); + rcal += ZaHist.makekey("Za"); + rcal += ZiofHist.makekey("Ziof"); + } + + p.EndProcess(); + } + catch (iException &ie) { + delete calVars; + calVars = 0; + string mess = "Failed in " + procStep; + ie.Message(iException::User, mess.c_str(), _FILEINFO_); + throw; + } + +// Clean up parameters + delete calVars; + calVars = 0; +} + diff --git a/isis/src/mro/apps/hicalbeta/hicalbeta.xml b/isis/src/mro/apps/hicalbeta/hicalbeta.xml new file mode 100644 index 0000000000000000000000000000000000000000..978dc6198cf2d8fd67142b8325808b827467187b --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/hicalbeta.xml @@ -0,0 +1,1389 @@ + + + + + + + Performs radiometric calibration of HiRISE channel images + + + +

    + hicalbeta appiles radiometric calibration correction to HiRISE + images. This particular version is deemed experimental, thus the beta + designation. The radiometric calibration correction is performed on + each individual HiRISE channel file (EDR) correcting for drift, + instrument offset, dark current, line-dependant gain, gain, flat field + and finally, conversion to I/F reflectance, DN/US or DNs. +

    +

    + The calibration is carried out in a series of modules. These modules + provide various contributions to the calibration process. The + parameters that govern the behavior of these modules are contained in + the program configuration file as specified in the CONF program + parameter. + The default file is $ISIS3DATA/mro/calibration/hicalbeta.????.conf + where '????' is the current version of the file. + + Each of the calibration modules have their own unique set of keywords + that govern is behavior. This is documented in the CONF parameter. + + The equation that is applied is described below: +

    +
    + Processing:
    +
    +          Zf = Fix gaps(Z)
    +          Zd = DriftCorrect(Zf)
    +          Zz = zero_correct(Zd - Offset)
    +          Zb = dark_subtract(Zz - B)     [B + T]
    +          Zg = gain_v_line_correct(Zb) [GvL Parameters]
    +          Zgg = gain_correct(Zg)          [G]
    +          Za = Flat_field_correct(Zgg)  [A]
    +          Zt = Temperature dependant gain correction (Za)
    +          Ziof = I/F conversion(Zt)
    +
    +  The correction is: 
    +
    +    oDN = (iDN - Zd(Zf) - Zz - Zb)  / Zg * Zgg * Za * Zt /  Ziof 
    +      
    +

    + How these radiometric components are computed are governed by the + CONF configuration file. This file is highly customizable to + accomodate as many specialized processing needs as is imaginable. + The contents of this file and how it may be used/customized is + fully described in the CONF documentation section. +

    +

    + Individual CCD channels may also require adjustments to radiometrically + match at the seam where the two channels come together. The + histitich application combines the two adjacent channel CCDs while + taking into account any residual seam mismatches. +

    +
    + + + + Original version + + + Wrote application test + + + Added examples + + + Added processing of DarkPixel object data. The median of the 16 dark pixels in + subtracted from the original DN. + Also added the DARKSTATS output file. + + + Extensively modified to implement latest state of HiRISE calibration. + + + This version is created from hical as a starting point. It has been + again extensively modified for maximum flexibility and usefullness. + + + Corrected the DriftCorrect class to properly compute the initial guess + of the fit parameters. It was not quite the same as the model. Also + added capability to dump individual module data via the configuration + file. + + + Added the OPATH parameter and made it available for subsititution in + the configuration parameters; Added the ZdSkipFit configuration + parameter to skip the non-linear fitting process in the Zd module + (when invoked, it will use the result of the Zf module); Added in the + percent additional contribution for the FPA temperature/gain + correction; Added ZdMinimumLines option to constrain the size of an + image that is fitted (properly). + + + Added missing factor (128/tdi/bin^2) to Zgg G-matrix gain module. + Explicitly recognize Phobos and Deimos targets as Mars so that I/F can + be computed. + + + Fixed removal of HiRISE calibration ancillary BLOBS (tables) so that + it only removes these tables and not all others, such as SPICE tables. + + + Removed references to CubeInfo + + + Added the ZdOnFailUseLinear flag to specify behavior when the + non-linear DriftCorrect Zd module fails. + + + Change default Zf filter defaults to 201 width with 2 interations; Add + reporting of raw buffer data to Zf module data dump; Added computation + of average and standard deviation to difference of raw buffer and post + filtering in Zf module; Set Zd default behavior to skip LM fitting and + eliminate unnecessary linear fitting in skip mode. + + + Abstracted Buffer pixel processing to DriftBuffer class (Zf); Added + robustness to some module dumps (Zf, Zb, Za); Added statistics + computations to several modules (Zf, Zz, Zb,Za); Abstracted dark + offset processing of Reverse Clock data to OffsetCorrect class (Zz). + + + Replaced references to DataInterp class with NumericalApproximation. + + + Added additional code to implement Zz module trigger options. This + option provides the ability to trigger a constant used in the Reverse + Clock calibration data based upon noise. See the discussion on the Zz + module in this program documentation. + + + Change default for OPATH to output (TO) directory; Removed the IOF + parameter and replaced it with the UNITS parameter; Added the Zt + module which corrects temperature dependant gain previously in the Za + module; updated documentation. + + + + + Mars Reconnaissance Orbiter + + + + + + cube + input + Input cube to calibrate + + The name of the cube to which the correction will be applied. The + correction will apply to every non-special pixel in the image. + + *.cub + + + + filename + input + $mro/calibration + $mro/calibration/hicalbeta.????.conf + + File containing HiRISE calibration and matrix configuration parameters + + *.conf + +

    + This important file provides all parameters used + in the calibration process. It contains references to + calibration matrices (such as flat fields, instrument gains, + etc...), label keywords and parameter constants used in the + radiometric calibration process. +

    +

    + The format of this PVL file is highly flexible for managing + HiRISE calibration data. This configuration file contains + numerous module profiles that govern the behavior of each phase + in the calibration process. These modules each have parameters + that are specific to its requirements. There are 6 different + modules that are used in the application. However, you will + typically see many other profiles in the configuration file. + The technique employed here is that you can take advantage of + the ability to merge other profiles into one or more of the + other main profiles, simply by the content of the labels or + observing conditions of the image. +

    +

    + The file must contain a top level Hical object. Within + this object is numerous profiles. The keywords that are + contained in the Object section of the file are always used in + every profile and can be superceded by any subsequent profile + loaded after the initial one. Optional profile names are + contructed by the combination of the OptionKeywords and + ProfileOptions keywords. The OptionKeywords + lists keywords in the configuration file and or label that can + be used to textually replace the patterns surrounded by the {} + in the ProfileOptions keyword. The kewords FILTER, CCD, + CHANNEL, TDI and BIN are always generated after the initial + module and label are loaded in. After the initial profile is + loaded, the FROM file label is loaded using the + LabelGroups to determine which keywords are loaded. Note + that the groups must exist or an error is issued. Other than + that you can specify any defined keyword in the + OptionsKeywords to apply to profile names. +

    +

    + The process by which a file name is determined also utilizes the + OptionKeywords to replace patterns that exist in + retrieval of all filename references in the configuration file. + This includes virtually all files including matrix and CSV + files. +

    +

    + Matrices are currently multi-band ISIS cube files that contain + one line and up to 1024 samples. There are expected to be + 28 bands in each one of these calibration matrices, one for each + CCD channel. There are 14 different CCDs with 2 channels each + for a total of 28 channels. (Note that channels are the basic + HiRISE image product where calibration is applied.) There will + always be one line for these cubes since HiRISE detectors are + line scan instruments. There will be a minimum of 64 (for + summing mode of 16) and a maximum of 1024 (summing mode of 1) + samples in these cubes. The content of these matrix files are + dependant upon summing mode and the time delay integration (TDI) + mode used during image acquisition. TDI allows varying number + of line scans, in conjunction with exposure time, to pass over + the same point on the surface of Mars to increase the + signal-to-noise ration (SNR) as well as resolution. There are 4 + selectable modes of TDI: 128, 64, 32 and 8. Coupled with 6 + difference summing modes (1, 2, 3, 4, 8, and 16), there are at + most 24 calibration cubes per set of matrices. These matrices + are referenced as file paths of the form: +

    + A = $mro/calibration/matrices/A_TDI{TDI}_BIN{BIN}_????.cub
    +                
    + Here, {TD} and {BIN} correspond to the TDI and summming mode + used during image acquisition, respectively. (More on how these + values are determined is provided in the follow text.) Matrix variables + are equated to file references using the pattern substituion of + keywords enclosed in {} in the configuration file. Matrix file + paths are also subjected to pattern replacement in the same + fashion as profiles. This will minimize the content management + aspect of the configuration file and encourage consistant file + naming schemes. +

    +

    + The real power of the configuration file is its use of named Profiles. + Profiles are groups of keywords that can be associated to a + unique definition. The hical PVL configuration file consists of a + single Hical object with numerous named Profile + groups. Each of the Profile groups must contain a Name + keyword that uniquely identifies it within the Hical object. + This allows us to create Profiles that pertain to particular + combinations of filter (RED, IR, BG), CCD (RED0-9, IR10/11, + or BG12/13), TDI (128, 64, 32, 8), BIN (1, 2, 3, 4, 8, 16) or + CHANNEL (0 or 1). These values are determined from the content + of the HiRISE label. Combinations of profiles that are added + after the initial default are specified in the + ProfileOptions keyword. Profile combinations can + consist of any combination or use of these defined values. + These defined values are specified as or with the Name + keyword in Profile groups delimited by curly braces. Given + this definition one can specify a particular group of calibration + parameters for a specific CCD channel with the pattern + {FILTER}{CCD}_{CHANNEL}. Then, one can define a special + collection of calibration matrices, keywords or scalars for any + one (or none) of the filters. So, for the problematic BG13, you + can have a named profile called BG13_1 whose keywords in the + profile are loaded when calibrating a BG13_1 channel, thus + overriding any defaulted keywords. Should named + profiles using this option not exist, they are ignored. Also, + Profiles specified in this manner are loaded in the + order specified in the ProfileOptions keyword, thus + creating a hierarchy of calibration specification configurations. +

    +

    + Below is an example of a complete PVL configuration file that + demonstrates some of the features described: +

    +
    +#  HiRISE Calibration Matricies configuration file
    +#  See documentation for the hical application on the content and form of
    +#  this file.
    +Object = Hical
    +
    +  Program = "hicalbeta"
    +
    +  Name           = "HiMatrices"
    +  DefaultProfile = "HiMatrices"
    +
    +/* If you want to rerun hical, you must set PropagateTables to True.  Use */
    +/* this in conjuction with Debug::SkipModule = True option for each module. */
    +  PropagateTables = False
    +
    +/* Define label groups that are loaded for each profile reference */
    +/* Note all keywords in these groups become available to all profiles. */
    +/* Thus, you can use them in the OptionKeywords and ProfileOptions keywords */
    +/* to create very specialized profiles for special needs. */
    +/* Specify the FPA reference temperature.  It is used in several modules so */
    +/* it is specified at the top level */
    +
    +  LabelGroups = ( "Dimensions", "Instrument", "Archive")
    +
    +/* These keywords are used in ProfileOptions mapping.  Note that order and */
    +/* case matter!  WARNING:  You can easily break file lookups if these keys */
    +/* are deleted or modified improperly!!! */
    +  OptionKeywords = ("FILTER", "CCD", "CHANNEL", "TDI", "BIN", "ProductId",
    +                    "Program", "Module", "OPATH", "CalOptions")
    +
    +/* Additional profile combinations and order load hierarchy.  These keywords */
    +/* are defined when the LabelGroups are loaded. */ 
    +/* Kris Becker & Eric Eliason updated 10/24/2008 */
    +/* ProfileOptions value added: {Module}_{CalOptions} */
    +  ProfileOptions = ("{FILTER}", "TDI{TDI}", "BIN{BIN}", "TDI{TDI}/BIN{BIN}",
    +                    "{FILTER}{CCD}_{CHANNEL}",
    +                    "{FILTER}{CCD}_{CHANNEL}/TDI{TDI}/BIN{BIN}", "Debug",
    +                    "{Module}_{CalOptions}")
    +
    +/* Specify the FPA reference temperature.  It is used in several modules so */
    +/* it is specified at the top level */
    +  FpaReferenceTemperature = 21.0
    +
    +/* This profile contains parameters pertinent to processing the buffer */
    +/* pixels for subsequent using in the drift correction, Zd module */
    +  Group = Profile
    +    Name = Zf
    +    Module = Zf
    +    ZfFirstSample = 5
    +    ZfLastSample = 11
    +
    +    ZfFilterWidth = 201
    +    ZfFilterIterations = 2
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing drift correction */
    +  Group = Profile
    +    Name = Zd
    +    Module = Zd
    +
    +  /* Uncomment to turn off non linear fitting of Zf data and pass it thru */
    +    ZdSkipFit = True
    +
    +  /* Uncomment to use linear fitting of Zf data when non-linear fails */
    +  /* Default is to pass thru filtered Zf data */
    +  /* ZdOnFailUseLinear = True */
    +
    +  /* Minimum number of good lines (NLines - (TrimLines/Summing)) to fit */
    +    ZdMinimumLines = 250
    +
    +  /* Maximum  number of iterations for the algorithm to converge and */
    +  /* other limits */
    +    MaximumIterations = 100
    +    MaximumLog        = 709.0
    +
    +  /*  Convergence parameters for Levenberg-Marquardt algorithm */
    +  /*  Equation is solved when |dx_i| < AbsoluteError + RelativeError * |x_i| */
    +  /*    where dx is the last step and x is the current step for each i-th */
    +  /*    value */
    +    AbsoluteError = 1.0E-4
    +    RelativeError = 1.0E-4
    +
    +  /* Filtering of the guestimate buffer */
    +    GuessFilterWidth = 17
    +    GuessFilterIterations = 1
    +
    +#    DumpModuleFile = "{ProductId}_{Module}.log"
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing the offset */
    +  Group = Profile
    +    Name = Zz
    +    Module = Zz
    +
    +/* Set calibration parameters for hiclean operations.  Indexes are all 0-based */
    +    ZzFirstLine = 1
    +    ZzLastLine  = 19
    +
    +
    +/* Reverse Clock trigger Statistics profiles */
    +    ReverseClockStatistics = "$mro/calibration/matrices/beta/ReverseClockStatistics.????.conf"
    +    RevLisTolerance = 1
    +    RevHisTolerance = 1
    +    RevNulTolerance = 1
    +  End_Group
    +
    +/*  Skip reverse clock if the ReverseReadoutNoise is to large */
    +/*  Profile added by Kris Becker & Eric Eliason, 10/25/2008 */
    +  Group = Profile
    +    Name = Zz_ReverseReadoutNoise
    +    Debug::SkipModule = True
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing dark current. */
    +/* Required label keywords:  Summing, Tdi, FpaPositiveYTemperature, */
    +/*                           and FpaNegativeYTemperature, Lines */
    +/* Also needs LineTime which is computed. */
    +  Group = Profile
    +    Name = Zb
    +    Module = Zb
    +
    +/* Define the B matrix file reference */
    +    B = "$mro/calibration/matrices/beta/B_TDI{TDI}_BIN{BIN}_hicalbeta_????.cub"
    +    SkipLines        = 1
    +    Slope            = "$mro/calibration/matrices/beta/t_slope_CH{CHANNEL}_hicalbeta_????.csv"
    +    Intercept        = "$mro/calibration/matrices/beta/t_intercept_CH{CHANNEL}_hicalbeta_????.csv"
    +
    +    /* Do filtering? */
    +    ZbFilterWidth      = 3
    +    ZbFilterIterations = 1
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing gain correction. */
    +/* Required label keywords: CpmmNumber, ChannelNumber, Lines */
    +  Group = Profile
    +    Name = Zg
    +    Module = Zg
    +
    +/*  As of 2008-06-25, this is the default */
    +    Debug::SkipModule = True
    +
    +    SkipLines            = 1
    +/* Added "_hicalbeta" to filename as of 2008-04-02.  This is consistant with */
    +/* naming convention used for the beta version of hical. */
    +    GainLineCoefficients = "$mro/calibration/matrices/beta/line_correct_{BIN}_hicalbeta_????.csv"
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing gain correction. */
    +/* Required label keywords: CpmmNumber, ChannelNumber, Lines */
    +  Group = Profile
    +    Name = Zgg
    +    Module = Zgg
    +
    +/* Define the G matrix file reference */
    +    G = "$mro/calibration/matrices/beta/G_TDI{TDI}_BIN{BIN}_hicalbeta_????.cub"
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing gain correction. */
    +/* Required label keywords: CpmmNumber, ChannelNumber, Tdi, Lines */
    +  Group = Profile
    +    Name = Za
    +    Module = Za
    +
    +/* Applies a temperature correction factor to A matrix */
    +/*** As of 2009-09-15 this parameter is implemented in the Zt module   ***/
    +/***   It remains here for backward compatability for now.  It will be ***/
    +/***   removed at some point in future releases.                       ***/
    +    ZaFpaTemperatureFactor = 0.005
    +
    +/* Define the A matrix file reference */
    +     A = "$mro/calibration/matrices/beta/A_TDI{TDI}_BIN{BIN}_hicalbeta_????.cub"
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing */
    +/* temperature-dependant gain correction. */
    +/* Required label keywords: CpmmNumber, ChannelNumber, Samples */
    +  Group = Profile
    +    Name = Zt
    +    Module = Zt
    +
    +/ Define temperature-dependant gain correction CSV file */
    +    FpaTemperatureFactorSkipLines = 4
    +    FpaTemperatureFactorHeader = True
    +    FpaTemperatureFactorFile = "$mro/calibration/matrices/beta/FpaTemperatureGain_BIN{BIN}.????.csv"
    +  End_Group
    +
    +/* This profile contains parameters pertinent to processing I/F conversion. */
    +/*  Required label keywords: ScanExposureDuration */
    +  Group = Profile
    +    Name = Ziof
    +    Module = Ziof
    +
    +/* I/F correction for tdi/bin - currently set at 1.0 for all tdi/bin */
    +/* combinations. */
    +    ZiofBinFactor = 1.0
    +  End_Group
    +
    +/* Here are the filter profiles.  All keywords that pertain to a filter set */
    +/* should be specified here.  FilterGainCorrection are I/F corrections in */
    +/* units of DN/s. */
    +  Group = Profile
    +    Name = RED
    +    FilterGainCorrection = 159423899.0
    +  End_Group
    +
    +  Group = Profile
    +    Name = IR
    +    FilterGainCorrection  =  58018177.0
    +  End_Group
    +
    +  Group = Profile
    +    Name = BG
    +    FilterGainCorrection  =  108811104.0
    +  End_Group
    +
    +  Group = Profile
    +    Name = IR10_1
    +#   LastGoodLine = 3100
    +  End_Group
    +
    +
    +  Group = Profile
    +    Name = Debug
    +
    +/** Current disables writting to label history due to bug in keyword formatter in ISIS **/
    +/* The bug has the following error signature: */
    +/*        terminate called after throwing an instance of 'std::out_of_range'  */
    +/*          what():  basic_string::substr                                     */
    +/*         Abort                                                              */
    +/* You must set this to false when this occurs as a workaround and use the */
    +/* DumpHistoryFile parameter to see the parameter history. */
    +    LogParameterHistory = False
    +
    +/* Uncomment this line to write parameter history to the ProductId log */
    +   DumpHistoryFile = "{OPATH}/{ProductId}.{Program}.log"
    +
    +/* Uncomment this line to dump Module data for every module when using Debug */
    +/* profiling. */
    +#    DumpModuleFile = "{OPATH}/{ProductId}_{Module}.log"
    +  End_Group
    +
    +End_Object
    +            
    + The filter profiles each contain a scalar constant of the same name + for each of the three filter sets. The ProfileOrder keyword + contains the {FILTER} pattern that will select the appropriate + filter gleened from the label. Other profiles that satisfy the remaining + patterns are excluded but can be added when necessary. +

    + The final resutling matrices, constants and keywords used in + the calibration equation are recorded in the + RadiometricCalibration group of the output label. +

    +

    Application Control Parameters


    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Description of main hicalbeta configuration + parameters. These parameters govern profile loading, + filename pattern replacement and debugging operations. +
    ParameterDescription
    Program + This keyword is set to the name of the application and can + be used to create unique filenames as described previously. +
    Name + The name of the current profile. This keyword is + required and is present in the Object keyword section as + well as in all other Profile groups. This uniquely + identifies the final comingled profile. +
    DefaultProifile + This names the default profile that is loaded when none + are specifically called for in the application. It can + be any profile (Debug might be an interesting + alternative) but is generally the Object profile. This + will cause no other profiles to be added when a generic + one is retrieved. +
    ProgagateTables + Specifies the behavior of the table progation of the FROM + file to the TO file when the file is completed. This has + some interesting implications. When False, all Table + objects in the FROM file are removed in the TO file, which + in effect prevents hicalbeta from being able to run again. + However, because of debugging capabilities, one may want ot + select which calibration modules are run. Setting this to + True will propagate all Table objects (BLOBs) in the FROM + file to be copied to the TO file. +
    LabelGroups + This keyword identifies which Groups in the FROM ISIS + cube label are included in profiles. This allows any + label keyword in the ISIS label to become available for + profiling and filename generation. Its handy for + creating very specific profiles for problem images and + other debugging purposes. +
    OptionKeywords + This keyword selects other keywords in the configuration + file or the FROM label groups as defined in the + LabelGroups keyword. This list is used to specify + additional profiles that can be loaded (via + ProfileOptions) and variable substitution within file + names (such as B, G and A matrix files). +
    Debug::SkipModule + This special keyword exists to provide the ability + to complete bypass processing of a module. If this + configuration keyword resolves to True in any module + configuration profile, then the module is not + invoked and the resulting contribution is set + appropriately such that it does not contribute to + the calibration process. This is very useful for + debugging and seeing how each module contributes. + Be sure to set ProgagateTables to True if you + intend to perform subsequent runs of hicalbeta. +
    OPATH + This keyword is the value of the OPATH parameter + entered when the program is executed. It can be + used to specify a path where log files are written + when that option is invoked. If the user did not + specify a value for this keyword, the current path + is supplied by default. +
    DumpModuleFile + This special keyword exists to provide the ability + to dump data from each Module. Each Module + implements a data dump that will be written to this + file. The file name can be made up of a combination + of any label or configuration keyword. The example + provided in the config file section uses the + ProductId and the name of the Module with a .log + extension. This keyword can be included in + individual Module Groups or at the top level which + will effectively dump all Modules. Note that the + Ziof Module is excluded from this feature as its + data is contained entirely in the history report. +
    DumpHistoryFile + This special keyword exists to provide the ability + to dump the Module history from each Module. Each + Module maintains a processing history that will be + written to this file. The file name can be made up + of a combination of any label or configuration + keyword. The example provided in the config file + section uses the ProductId and the name of the + Program with a .log extension. +
    + +

    Zf Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + This module is responsible for reading and processing of + the Buffer pixels for input into the DriftCorrect module. + It averages lines, runs smoothing filters and ensures + there are no gaps by resorting to a Spline Fill of any + remaining missing data. +
    ParameterDescription
    Name + Must be set to Zf as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    ZfFirstSample + Specifies the first (0-based) Buffer sample to start the + average. +
    ZfLastSample + Specifies the last (0-based) Buffer sample to end the + average. +
    ZfFilterWidth + Specifies the width of the filter to smooth and fill + gaps in the resulting Buffer averages. [Default: 201] +
    ZfFIlterIterations + Specifies the number of sequential filters to apply to + the averaged buffer pixels before finally filling with a + spline. [Default: 2] +
    + +

    Zd Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + The DriftCorrect Module. This module uses the Zf results + and computes a non-linear equation that removes the drift + component. It uses a Levenberg-Marquardt algorithm to + solve the equation f(x) = a0 + a1 * linetime + a2 * exp(a3 + * linetime). +
    ParameterDescription
    Name + Must be set to Zd as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    ZdSkipFit + This parameter can is used to turn on/off the + non-linear fitting process described above. When + missing or set to TRUE, the result of the Zf module is + used. If FALSE, the DriftCorrect fitting is applied + using the parameters provided. +
    ZdOnFailUseLinear + This parameter can be used to select the behavior of + the data produced by the Zd module when the non-linear + fitting process has failed (typically due to + non-convergence). If set to TRUE, a linear fit to the + latter half of the Zf (buffer pixel) data is computed. + If FALSE or non-existant, the result of the Zf module + is used as is. +
    ZdMinimumLines + Minimum number lines required to apply the non-linear + fit processing. The actual number of lines used is the + total lines less TrimLines/Summing. If there are not + enough lines, then the result of the Zf module (filtered + Buffer pixel data) is simply passed through as is. This + results in the same behaviour when the ZdSkipFit + parameter is invoked. +
    MaximumIterations + The maximum number of iterations to allow the equation + to converge. +
    MaximumLog + Constrains the last term in the equation such that the + exponenent will not cause an overflow. +
    AbsoluteError + Specifies the absolute maximum error to determine + convergence. +
    RelativeError + Specifed the relative maximum error to determine + convergence. +
    GuessFilterWidth + The data used to fit the non-linear equation can be + optionally filtered before fitting. This controls the + width of the filter [Default: 17]. +
    GuessFilterIterations + This parameter controls the number of times the fit + buffer is filtered prior to non-linear fitting. Set + this to 0 to turn off this processing and use the data + as is [Default: 1]. +
    + +

    Zz Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Computes the Offset component. This module uses the + Reverse Clock region to compute the offset that is then + subtracted from the result of the Zd module. Processing + is governed by some statistical properties of this region. + The standard deviation and special counts are compared to + tolerances provided in the ReverseClockStatistics file + that will trigger the use of a constant mean value for + this correction. The result of these values are + subtracted from each sample pixel column. +
    ParameterDescription
    Name + Must be set to Zz as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    ZzFirstLine + Specifies the first of the Reverse clock region in the + input FROM file to average for dark current correction. +
    ZzLastLine + Specifies the last line in the Reverse clock region in + the input FROM file to average for dark current + correction. +
    ReverseClockStatistics +

    ReverseClockStatistics

    +
    + + + + + + + + + + + + + + + + + + +
    + This is the name of a file that contains profiles + for individual channel images and summing modes for + trigger and mean values that govern how the offset + component is determined. The default file name is + "ReverseClockStatistics.XXXX.conf" where "XXXX" is a + version number. Note that the contents of the + composed hicalbeta configuration profile is used to + provide initial values for the profile loaded out of + this file. +
    ParameterDescription
    Name + This names each image profile. The name is a + combination of FILTER(e.g., RED, BG, IR), CCD + (1-13) followed by an underscore and the channel + number (0, 1) followed by another underscore and + the summing mode (0-8). Example: RED0_1_1. +
    RevMeanTrigger + Maximum mean value of the Reverse Clock data region. + Means that exceed this value will instead use this + value as the offset correction value for all samples. +
    RevStdDevTrigger + Maximum standard deviation value of the Reverse + Clock data region. Standard deviations that exceed + this value will instead cause the RevMeanTrigger + value to be used as the offset constant for all + samples. +
    +
    RevLisTolerance + The maximum number of low instrument saturation (LIS) + special pixels that can exist in the Reverse Clock + calibration data region. If more LIS pixels exist in + this region, then the RevMeanTrigger value is used in + lieu of the processed Reverse Clock data. This value + provides the default (1) for all HiRISE images which can + be changed in subsequently loaded profiles (such as the + one loaded in the ReverseClockStatistics file). +
    RevHisTolerance + The maximum number of high instrument saturation (HIS) + special pixels that can exist in the Reverse Clock + calibration data region. If more HIS pixels exist in + this region, then the RevMeanTrigger value is used in + lieu of the processed Reverse Clock data. This value + provides the default (1) for all HiRISE images which can + be changed in subsequently loaded profiles (such as the + one loaded in the ReverseClockStatistics file). +
    RevNulTolerance + The maximum number of null (NULL) special pixels that + can exist in the Reverse Clock calibration data region. + If more NUL pixels exist in this region, then the + RevMeanTrigger value is used in lieu of the processed + Reverse Clock data. This value provides the default + (1) for all HiRISE images which can be changed in + subsequently loaded profiles (such as the one loaded in + the ReverseClockStatistics file). +
    + +

    Zb Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + The Dark Subtract module. This module uses the + Slope/Intercept Temperature profile. +
    ParameterDescription
    Name + Must be set to Zb as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    B + This the B matrix cube that is derived to remove the + dark current. In addition, it uses an elaborate + temperature model for this component. +
    SkipLines + Specifies the number of lines to skip in the Slope and + Intercept temperature profile CSV files. [Default: 0] +
    Slope + Specifies the file pattern of the slope component of the + Temperature profile. +
    Intercept + Specifies the file pattern for the intecept component of + the Temperature profile. +
    ReferenceTemperature + Specifies the reference temperature to normalize the + temperature profile equation. [Default: 21C] +
    ZbFilterWidth + Width of the smooth filter component for the temperature + profile. +
    ZbFilterIterations + Specifies the number of sequential filters to apply to + the resulting temperature profile. [Default: 1] +
    + + +

    Zg Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + +
    + Computes the Gain versus Line correction. This will read + in the line correction gain coefficients file and apply + the same non-linear equation used in the Zd module. +
    ParameterDescription
    Name + Must be set to Zg as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    SkipLines + Specifies the number of lines to skip in the gain + coefficients CSV files. [Default: 0] +
    GainLineCoefficients + Specifies the file pattern of the gain/line + coefficients. +
    + +

    Zgg Module Parameters


    + + + + + + + + + + + + + + + + + + +
    + This module loads the Gain correction matrix file. +
    ParameterDescription
    Name + Must be set to Zgg as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    G + This the G matrix cube that is derived to remove the + effects of image gain. +
    + +

    Za Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + +
    + This module loads the flat field correction matrix file. +
    ParameterDescription
    Name + Must be set to Za as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    ZaFpaTemperatureFactor + This parameter specifies the temperature dependant + gain correction factor applied to the A matrix. + + NOTE: As of 2009-09-15, this parameter is obsolete. + The temperature dependant gain is now being + maintained in a module all its own, the Zt module. + It will be removed in a future release but is + retained here for backwards compatability. + +
    A + This the A matrix cube that is derived to remove the + flat field effects of image. +
    + +

    Zt Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + This module contains parameters specific to temperature + dependant gain correction +
    ParameterDescription
    Name + Must be set to Zt as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    FpaTemperatureFactorSkipLines + Number of comment lines at the top of the + FpaTemperatureFactorFile. If not provided, the + default is no lines. This does not include the header line. +
    FpaTemperatureFactorHeader + True/False value indicates whether a header line exists + prior to data in the FpaTemperatureFactorFile CSV + file. +
    FpaTemperatureFactorFile + This CSV file contains three columns of data that + specify the temperature dependant coefficient. The + first column is the CCD (ex: RED2), the second column is + the coefficient for channel 0 and third contains the + coefficient for channel 1. +
    + +

    Ziof Module Parameters


    + + + + + + + + + + + + + + + + + + + + + + +
    + This module computes values necessary to convert DNs to + user selected calibration unit values. +
    ParameterDescription
    Name + Must be set to Ziof as it names this Profile Module. The + program will fail without this Group/Name/Module. +
    Module + The name of the current processing module. It is + intended to be used as an identifer. Name is such a + generic name that it has the potential to be superceded + by some other profile loading operation (such as label + activities). +
    ZiofBinFactor + Specifies the factor that takes into account binning of + the image data. It is currently set to 1.0. +
    FilterGainCorrection + Specifies the filter dependant gain correction factor. + Note that these values are found in the RED, BG, IR + profiles and relies on the profile options to load the + proper parameter in at runtime. +
    +
    +
    + + + cube + real + output + + Output radiometrically corrected cube file + + + Use this parameter to specify the name of the output cube. + If you do not include an extension of ".cub" it will be added + automatically. + + +
    + + + + string + None + + Name of specific configuration profile to use + + +

    + This is the name of a named Profile group in the hical matrix + configuration file that users can choose for specific + selection of HiRISE calibration parameters and matrix files. +

    +

    + Note that when using this option, the additional profiles + specified in the ProfileOptions key are not applied. + This option is primarily to assist in testing and specific + application conditions. +

    +
    +
    + + string + IOF + Desired output calibration units + + A feature which calculates the average on each channel and multiplies one side with + the ratio of the averages + + + + + + + + + string + None + + Alternative path to use when logging is invoked + + +

    + This parameter is used to specify a directory path that is + intended to be used in output file specifications. OPATH can + be useful for directing specifically where log files are + written when that option is invoked. This option is + automatically added and available to all profiles and is + included in the output specifications of all log files. +

    +

    + The default behavior is to place all log files in the same + directory as the output file specifed in the TO parameter. +

    +
    +
    +
    +
    +
    diff --git a/isis/src/mro/apps/hicalbeta/tsts/Makefile b/isis/src/mro/apps/hicalbeta/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hicalbeta/tsts/default/Makefile b/isis/src/mro/apps/hicalbeta/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cb4fef178cffdc53e3636ddba162a228d0fa1a9c --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/tsts/default/Makefile @@ -0,0 +1,12 @@ +APPNAME = hicalbeta + +output.txt.SKIPLINES = 7 +output.txt.IGNORELINES = CONF + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/PSP_001446_1790_RED2_0.cub \ + TO=$(OUTPUT)/output.cub OPATH=. > /dev/null; + $(MV) PSP_001446_1790_RED2_0.hicalbeta.log \ + $(OUTPUT)/output.txt; diff --git a/isis/src/mro/apps/hicalbeta/tsts/dnpermicrosecs/Makefile b/isis/src/mro/apps/hicalbeta/tsts/dnpermicrosecs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e4f3176674970f2daab2a937b51d6c7bb6b6aefa --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/tsts/dnpermicrosecs/Makefile @@ -0,0 +1,12 @@ +APPNAME = hicalbeta + +output.txt.SKIPLINES = 7 +output.txt.IGNORELINES = CONF + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/PSP_001446_1790_RED2_0.cub \ + TO=$(OUTPUT)/output.cub OPATH=. UNITS=DN/US > /dev/null; + $(MV) PSP_001446_1790_RED2_0.hicalbeta.log \ + $(OUTPUT)/output.txt; diff --git a/isis/src/mro/apps/hicalbeta/tsts/dns/Makefile b/isis/src/mro/apps/hicalbeta/tsts/dns/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8a7d7913a41e7da3ed3f103d51058cbc1057eb40 --- /dev/null +++ b/isis/src/mro/apps/hicalbeta/tsts/dns/Makefile @@ -0,0 +1,12 @@ +APPNAME = hicalbeta + +output.txt.SKIPLINES = 7 +output.txt.IGNORELINES = CONF + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/PSP_001446_1790_RED2_0.cub \ + TO=$(OUTPUT)/output.cub OPATH=. UNITS=DN > /dev/null; + $(MV) PSP_001446_1790_RED2_0.hicalbeta.log \ + $(OUTPUT)/output.txt; diff --git a/isis/src/mro/apps/hiccdstitch/Makefile b/isis/src/mro/apps/hiccdstitch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hiccdstitch/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hiccdstitch/hiccdstitch.cpp b/isis/src/mro/apps/hiccdstitch/hiccdstitch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a367f51e317123130d0621b18fbab499123dcb1c --- /dev/null +++ b/isis/src/mro/apps/hiccdstitch/hiccdstitch.cpp @@ -0,0 +1,523 @@ +#define GUIHELPERS + +#include "Isis.h" + +#include +#include + +#include "UserInterface.h" +#include "Cube.h" +#include "Portal.h" +#include "Interpolator.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "ProcessMosaic.h" +#include "ProcessByLine.h" +#include "Brick.h" +#include "FileList.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +//helper button functins in the code +void helperButtonLog(); + +map GuiHelpers(){ + map helper; + helper ["helperButtonLog"] = (void*) helperButtonLog; + return helper; +} + + +typedef struct { + Cube *cube; // Cube object + Portal *portal; // Portal for interpolation + string filename; // Name of the CCD file + string ccdName; // Name of ccd + int ccdNumber; + int mosOrder; // Mosaic order, default is summing mode + int summing; // Summing mode + int sumLines; // iTime delay summing line offset + int tdi; // TDI mode + int trimLines; // Commanded trim lines + int fpsamp; // Location of focal plane sample + int fpline; // Location (offset, actually) of focal plane line + int ns; // Number of samples in the input CCD file + int nl; // Number of lines in the input CCD file + int nb; // Number bands in image + int ss; // Input CCD file Starting Sample (before expansion) + // of the piece to put into output file + int es; // Input CCD file Ending Sample (before expansion) + // of the piece to put into output file + int expFactor; // Expansion factor to be used + int outss; // Starting sample in the output file of where + // the piece should go + int outsl; // Output starting line +} HiriseCCD; + +typedef struct { + double sample; + double startLine; + double lineInc; + Portal *portal; + Cube *cube; +} HiriseCCDLocation; + +vector CCDlist; +vector::size_type CCDindex; + +vector CCDlocation(21000); + +bool compareCcd(const HiriseCCD& x, const HiriseCCD& y); +bool compareMos(const HiriseCCD& x, const HiriseCCD& y); +void InitCCDLocation (int outns); +void PlaceCCDs (Buffer &buf); + +Interpolator *interp; + +void IsisMain() { + + + // X offset (pixels) of each CCD relative to CCD 10 + const char * const ccdNames[] = { "RED0", "RED1", "RED2", "RED3", "RED4", + "RED5", "RED6", "RED7", "RED8", "RED9", + "IR10", "IR11", "BG12", "BG13" }; + + // Initial locations of samples and lines for each CCD + const int xoffset[] = {-8000,-6000,-4004,-2003,0,2000, 4000,6000, 8000,10000, + 0,2000,0,2000}; + const int yoffset[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + + // For converting a CPMM number to a CCD number + const int cpmm2ccd[] = {0,1,2,3,12,4,10,11,5,13,6,7,8,9}; + + // Line delays for summing modes that cause shifts. All shifts are relative + // to bin mode 1. They appear to be multiples of 180 * BinMode. + const int SummingModeLineOffsets[] = { 0, 0, 180, 360, 540, 0, 0, 0, 1260, + 0, 0, 0, 0, 0, 0, 0, 2700 }; + + typedef vector::size_type vec_sz; + + // Get the list of names of input CCD cubes to stitch together + FileList list; + UserInterface &ui = Application::GetUserInterface(); + list.Read(ui.GetFilename("FROMLIST")); + if (list.size() < 1) { + string msg = "The list file[" + ui.GetFilename("FROMLIST") + + " does not contain any filenames"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + +#if 0 +// Commented out as HiRISE Team is requesting a single file to be processed +// to simplify pipeline logic + if (list.size() == 1) { + string msg = "The list file[" + ui.GetFilename("FROMLIST") + + " must contain at least two filenames"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } +#endif + + // What type of interpolator is needed + if (ui.GetString("INTERP") == "NEARESTNEIGHBOR") { + interp = new Interpolator(Interpolator::NearestNeighborType); + } + else if (ui.GetString("INTERP") == "BILINEAR") { + interp = new Interpolator(Interpolator::BiLinearType); + } + else if (ui.GetString("INTERP") == "CUBICCONVOLUTION") { + interp = new Interpolator(Interpolator::CubicConvolutionType); + } + else { + string msg = "Unknow value for INTERP [" + + ui.GetString("INTERP") + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + +// Open the shift definitions file + Pvl shiftdef; + shiftdef.Read(ui.GetFilename("SHIFTDEF")); + + PvlObject &stitch = shiftdef.FindObject("Hiccdstitch", Pvl::Traverse); + + // Get information about each of the input cubes + bool gotRed = false; + bool gotNir = false; + bool gotBg = false; + bool first = true; + string obsId; // ObservationId keyword value + int maxBands = 0; + + for (unsigned int i=0; iOpen(list[i]); + + PvlGroup arch = cube->Label()->FindGroup("Archive", Pvl::Traverse); + if (first) { + obsId = (string) arch["ObservationId"]; + first = false; + } else { + if (obsId != (string) arch["ObservationId"]) { + string msg = "Input file " + list[i] + + " has a different ObservationId"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + PvlGroup inst = cube->Label()->FindGroup("Instrument", Pvl::Traverse); + int chan = inst["ChannelNumber"]; + if (chan != 2) { + string msg = "Input file " + list[i] + " contains a single channel"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + int cpmm = inst["CpmmNumber"]; + int ccd = cpmm2ccd[cpmm]; + if (ccd >= 0 && ccd <= 9) { + gotRed = true; + } + else if (ccd == 10 || ccd == 11) { + gotNir = true; + } + else { + gotBg = true; + } + + CCDinfo.cube = cube; + CCDinfo.filename = list[i]; + CCDinfo.ccdName = ccdNames[ccd]; + CCDinfo.ccdNumber = ccd; + CCDinfo.summing = inst["Summing"]; + CCDinfo.sumLines = SummingModeLineOffsets[CCDinfo.summing]; + CCDinfo.tdi = inst["Tdi"]; + CCDinfo.trimLines = arch["TrimLines"]; + CCDinfo.fpsamp = xoffset[ccd]; + CCDinfo.fpline = yoffset[ccd]; + CCDinfo.ns = cube->Samples(); + CCDinfo.nl = cube->Lines(); + CCDinfo.nb = cube->Bands(); + if (CCDinfo.nb > maxBands) maxBands = CCDinfo.nb; + CCDinfo.outss = 1; + CCDinfo.outsl = 1; + CCDinfo.ss = 1; + // The sort routine compare uses the > operator on mosOrder (highest mosOrder + // stitched first. + // + // Scale summing so that if user enters mosaicOrder in def file, + // which would have values of -1, or 1-14, that order takes precedent + // over summing modes. For example: + // Red9 : mosaicOrder = -1 + // Red0 : mosaicOrder = 1 + // Red3 : mosaicOrder = 2 + // Red5 : mosaicOrder = 3 + // Rest of ccd's laid down highest summing mode first, then by ccd number. + // Using summing, mosOrder will have default values of 25,20,18,17,16,15 + // for ascending sort. + CCDinfo.mosOrder = (int)(1./(float)CCDinfo.summing * 10. + 14.); + + // Determine if a shift of the CCD exists in the definitions file + // Combine summing/tdi into a string + std::string sumTdi = Isis::iString(CCDinfo.summing)+"/"+ + Isis::iString(CCDinfo.tdi); + + std::string ccdId = ccdNames[ccd]; + if (stitch.HasObject(ccdId)) { + PvlObject &ccddef = stitch.FindObject(ccdId, Pvl::Traverse); + if (ccddef.HasKeyword("MosaicOrder")) { + CCDinfo.mosOrder = (int) ccddef["MosaicOrder"]; + } + if (ccddef.HasKeyword("SampleOffset")) { + CCDinfo.fpsamp = xoffset[ccd] + (int) ccddef["SampleOffset"]; + } + if (ccddef.HasKeyword("LineOffset")) { + CCDinfo.fpline = yoffset[ccd] + (int) ccddef["LineOffset"]; + } + // See if there is a binning group + if (ccddef.HasGroup(sumTdi)) { + PvlGroup &sumGroup = ccddef.FindGroup(sumTdi); + if (sumGroup.HasKeyword("SampleOffset")) { + CCDinfo.fpsamp = xoffset[ccd] + (int) sumGroup["SampleOffset"]; + } + if (sumGroup.HasKeyword("LineOffset")) { + CCDinfo.fpline = yoffset[ccd] + (int) sumGroup["LineOffset"]; + } + } + } + + // Set up portal + CCDinfo.portal = new Portal(interp->Samples(),interp->Lines(), + cube->PixelType(), + interp->HotSample(),interp->HotLine()); + CCDlist.push_back(CCDinfo); + +//cout << "CCD: " << ccd << " Summing: " << CCDinfo.summing << endl; + +// cube->Close(); + } + + // Check for consistent filters + if ((gotRed && gotNir) || (gotRed && gotBg) || (gotNir && gotBg)) { + string msg = "Cannot stitch together different filter images"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Sort the list of CCD info structs according to ascending CCD numbers + sort(CCDlist.begin(), CCDlist.end(), compareCcd); + +#if defined(FORCE_ADJACENT) + // Check to make sure we have a set of adjacent CCDs + int prevCCD = CCDlist[0].ccdNumber; + for (vec_sz i = 1; i < CCDlist.size(); ++i) { + if (CCDlist[i].ccdNumber != prevCCD+1) { + string msg = "CCD numbers are not adjacent"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + prevCCD = CCDlist[i].ccdNumber; + } +#endif + + // Determine expansion factors for transferring data to output file + int minSum = 100; // Minimum summing factor + int minLine(CCDlist[0].fpline); + for (vec_sz i = 0; i < CCDlist.size(); ++i) { + minSum = min(minSum, CCDlist[i].summing); + minLine = min(minLine, CCDlist[i].fpline); + } + + // Set the summing mode offset line as to the minimum summing mode found + int minLineOffset = SummingModeLineOffsets[minSum]; + + // Adjust for summing mode 3 and force it to summing mode 1. + if (CCDlist.size() != 1) { + if (minSum == 3) minSum = 1; + } + + for (vec_sz i = 0; i < CCDlist.size(); ++i) { + CCDlist[i].expFactor = CCDlist[i].summing / minSum; + } + + // Determine number of lines in output file + // 2006-09-27 account for summing mode line time delay in lineOffset (KJB) + int outnl = 0; + for (vec_sz i = 0; i < CCDlist.size(); ++i) { + int lineOffset = (CCDlist[i].fpline - minLine) / minSum + + ((CCDlist[i].sumLines - minLineOffset)/ minSum); + int ccdLines = CCDlist[i].nl * CCDlist[i].expFactor + lineOffset; + outnl = max(outnl, ccdLines); + CCDlist[i].outsl = lineOffset + 1; + } + + // Determine the starting input sample numbers of the pieces of each input + // file to be used and where these pieces should go in the ouput file + CCDlist[0].ss = 1; // First CCD starts at input sample 1 + CCDlist[0].outss = 1; // It goes to sample 1 in output file + int nBandErrs = 0; // Good a place as any to check this + for (vec_sz i=1; i < CCDlist.size(); i++) { + CCDlist[i].ss = 1; + CCDlist[i].outss = ((CCDlist[i].fpsamp - CCDlist[0].fpsamp) / minSum) + 1; + // Check for appropriate bands + if (CCDlist[i].nb != maxBands) { + std::ostringstream mess; + mess << "File " << CCDlist[i].filename << " does not have the required " + << maxBands << " bands, but only " << CCDlist[i].nb; + iException::Message(iException::User,mess.str(),_FILEINFO_); + nBandErrs++; + } + } + +// If we find any band count inconsistancies, gotta give up the ghost + if (nBandErrs > 0) { + std::string mess = "Band count inconsistancies exist in input cubes!"; + throw iException::Message(iException::User,mess.c_str(),_FILEINFO_); + } + + // Compute number of samples in output file + int outns = CCDlist[CCDlist.size()-1].outss + (2048/minSum) - 1; + + // Set up which input cube will be used to propagate labels + // before sorting is done so that the lowest ccd is used. + ProcessByLine placing; + CubeAttributeInput att; + placing.SetInputCube(CCDlist[0].filename, att); + placing.PropagateLabels(true); + Cube *ocube = placing.SetOutputCube("TO", outns,outnl,maxBands); + + // Delete ChannelNumber and CpmmNumber so that the output cannot be projected. + PvlGroup oinst = ocube->GetGroup("Instrument"); + oinst.DeleteKeyword("ChannelNumber"); + oinst.DeleteKeyword("CpmmNumber"); + ocube->PutGroup(oinst); + + placing.ClearInputCubes(); + + + // Sort the list of CCD info structs according to ascending mosaicOrder + sort(CCDlist.begin(), CCDlist.end(), compareMos); + + // Initialiize the ccdLocation arrays + InitCCDLocation (outns); + + PvlObject results("Hiccdstitch"); + // Write ccd order to results + for (CCDindex = 0; CCDindex < CCDlist.size(); CCDindex++) { + + PvlGroup ccdGroup(CCDlist[CCDindex].ccdName); + + ccdGroup += PvlKeyword("File",CCDlist[CCDindex].filename); + ccdGroup += PvlKeyword("FocalPlaneSample",CCDlist[CCDindex].fpsamp); + ccdGroup += PvlKeyword("FocalPlaneLine",CCDlist[CCDindex].fpline); + ccdGroup += PvlKeyword("ImageSample",CCDlist[CCDindex].outss); + ccdGroup += PvlKeyword("ImageLine",CCDlist[CCDindex].outsl); + + int ccd = CCDlist[CCDindex].ccdNumber; + ccdGroup += PvlKeyword("SampleOffset",CCDlist[CCDindex].fpsamp-xoffset[ccd]); + ccdGroup += PvlKeyword("LineOffset",CCDlist[CCDindex].fpline-yoffset[ccd]); + + results.AddGroup(ccdGroup); + } + + // Process by output file + placing.Progress()->SetText("Stitching "); + placing.StartProcess(PlaceCCDs); + placing.EndProcess(); + + // close all inputs + for (vec_sz i = 0; i < CCDlist.size(); ++i) { + CCDlist[i].cube->Close(); + } + +// Write the object if requested + if (ui.WasEntered("PLACEMENT")) { + std::string placefile = ui.GetFilename("PLACEMENT"); + std::ofstream pfile; + pfile.open(placefile.c_str(), std::ios::out | std::ios::trunc); + pfile << results << endl; + pfile.close(); + } + +} // End of IsisMain + + + +// c o m p a r e CCD's +bool compareCcd(const HiriseCCD& x, const HiriseCCD& y) { + return x.ccdNumber < y.ccdNumber; +} + + + +// c o m p a r e MosaicOrder ascending +bool compareMos(const HiriseCCD& x, const HiriseCCD& y) { + if (x.mosOrder < y.mosOrder) { + return true; + } + else if (x.mosOrder == y.mosOrder) { + if (x.summing > y.summing) { + return true; + } + else if (x.summing == y.summing && x.ccdNumber < y.ccdNumber) { + return true; + } + } + + return false; + +} + + +// C r e a t e S t i t c h +void CreateStitch ( Buffer &buf) { + for (int i=0; iSetPosition(inSamp,inLine,obuf.Band()); + CCDlocation[i].cube->Read(*(CCDlocation[i].portal)); + obuf[i] = interp->Interpolate(inSamp,inLine, + CCDlocation[i].portal->DoubleBuffer()); + } + } +} + +#if 0 +// P l a c e C C D +void PlaceCCD (Buffer &buf) { + // Copy input pixels into the output Brick buffer. This includes + // inserting multiple copies of the pixel by applying the expansion factor. + int bindex = 0; // Index into the output Brick + for (int i=CCDlist[CCDindex].ss; i<=CCDlist[CCDindex].ns; i++) { + // Process an input pixel + for (int j = 0; j!=CCDlist[CCDindex].expFactor; j++) { + // Put a copy of input pixel into the output Brick + (*brick)[bindex++] = buf[i-1]; + } + } + + // Write the output Brick buffer line to the ouput file. This includes + // writing multiple copies by applying the expansion factor. + int outLine = ((buf.Line()-1) * CCDlist[CCDindex].expFactor) + + CCDlist[CCDindex].outsl; + for (int j = 0; j!=CCDlist[CCDindex].expFactor; j++) { + brick->SetBaseLine( outLine++ ); + stitchCube->Write(*brick); + } +} + +#endif + +//Helper function to output the regdeft file to log. +void helperButtonLog () { + UserInterface &ui = Application::GetUserInterface(); + string file(ui.GetFilename("SHIFTDEF")); + Pvl p; + p.Read(file); + Application::GuiLog(p); +} +//...........end of helper function ........ + diff --git a/isis/src/mro/apps/hiccdstitch/hiccdstitch.xml b/isis/src/mro/apps/hiccdstitch/hiccdstitch.xml new file mode 100644 index 0000000000000000000000000000000000000000..076cd6c7e3d0331ee83d636f3cd964a54602c457 --- /dev/null +++ b/isis/src/mro/apps/hiccdstitch/hiccdstitch.xml @@ -0,0 +1,321 @@ + + + + + Stitch together multiple HiRISE CCD images + + + +

    + This program combines images from multiple HiRISE CCDs into a single + output image file. The output file can be considered to be a special + type of mosaic in which the different CCD images are placed next to + each other in positions that correspond to detector numbers. The input + files must each contain both channels of a single detector, which are + the files produced by the "histitch" program. CCD images with lower + CCD numbers are placed into the output file to the left of CCD images + with higher CCD numbers. By default the CCD images are placed into the + output file from left to right, i.e., in order of increasing CCD number. This + order can be changed with the MosaicOrder keyword in the "shiftdef" + file. +

    +

    + Images are inserted at locations + corresponding to the relative offsets of the detectors. In most cases, + pixel replication is used when processing an input image so that it + matches the scale of the image with the lowest summing mode. However, + if any of the input images were observed with a summing mode of 3, then + pixel replication is used for all images to match the scale that would + have been obtained with a summing mode of 1. No resampling of input + pixel values is done. +

    +

    + In many cases, adjacent images do not line up vertically due to observing + conditions and other factors. The SHIFTDEF parameter allows the user to + apply arbitrary offsets in lines to any or all the input images so they align + properly. +

    +

    + It has been determined that summing modes add an additional delay to + imaging due to pre-cycling of the detector electronics. Typically, images + have an additional 180 * (summing mode - 1) lines delay + in the actual imaging + of the target. These lines are unbinned, not subject to the summing mode + applied during imaging. This is not an issue if all images being stitched by + this application are the same summing mode. If images with different + summing modes are acquired in the same observation, then this offset + is automatically applied to the images with differing summing modes. This + will result in adding + lines of offset to some images and increasing the number of lines in the + resulting output image. +

    +

    + The input files may contain multiple bands but all input files must contain + the same number of bands. This is useful for creating color products + where the input files are compatable with the constraints of this application. +

    +
    + + + Mars Reconnaissance Orbiter + + + + + Original version + + + Eliminated the requirement that all CCDs be adjacent. As a side + effect, 24 pixels on the left edge of the adjacent CCDs are no + longer clipped but are layed on top of the last 24 pixels on the + right side of preceding CCDs. + + + Added the SHIFTDEF parameter that allows for offsets to be provided + for any CCD. Also added the PLACEMENT parameter that writes the + line and sample coordinate of each CCD in the output TO file. + + + Added recently discovered time delay as a function of summing modes. + This adds lines of offset to images with higher summing modes. These + lines are unbinned but are subject to the smallest occuring summing + mode in that the offsets are reduced by the number of offsets divided by + the minimum summing mode. + + + Modified to allow a single CCD image file as input to hiccdstitch. + Previously, two or more CCDs image files were required. With this + change only one need be provided (to expedite pipeline processing). + + + Modified to allow user to determine the order the ccd's are laid down + through the use of the MosaicOrder keyword in the shiftdef file. + Also added option to replicate pixels by nearestNeighbor, Bilinear + or cubicConvolution. Also deleted ChannelNumber and CpmmNumber + keywords so that output image cannot be projected. + + + Modified to allow for stitching of multiband cubes. This will allow + users to create color products as long all files have the same + number of bands. + + + Removed references to CubeInfo + + + + + + + filename + input + + List of cubes to stitch together + + + The name of a file containing a list of HiRISE image files to be + stitched together. Each file should be listed on a separate + line. + + + * + + + + + filename + input + + + helperButtonLog + View file in log area + This helper button will display the shiftdef file in the log area + $ISIS3DATA/base/icons/view_text.png + + + + *.def + + $mro/calibration + $mro/calibration/HiccdstitchOffsets.def + + Pvl file containing mosaic order for ccd's and the absolute shifts for CCD + lines and samples. + + +

    + This file contains objects for each CCD and for each combo + of binning/tdi that requires a + modification to its placement in the mapping of the HiRISE + focal plane. The name of each object is the CCD name for + which the shift in line or sample is needed. For example, the + leftmost CCD, CCD 0 is named "RED0", the next "RED1" and + so on. The binning/tdi groups are named by combining the + binning and tdi mode. For example, summing=1 and tdi=64 the + group would be "1/64". Hiccdstitch searches for names of objects that match + the stitched input cube files ccd then for the proper combo of summing and tdi. + If the group for summing/tdi isn't found, values from the ccd object will be + used. These offsets will be applied to the + default sample and line location of where the CCD is mapped to + in the focal plane. +

    +

    + Offsets for both line and sample can be supplied. None, one or + both can be provided for any CCD. Negative values shift the + image left if a sample offset is given or up if a line offset is given. + Positive values in sample and line shift the image right and down, + respectively. +

    +

    + These shifts are absolute shifts and only apply to + the specified CCD and are not propagated to subsequent CCDs + left to right in the focal plane layout. (HiRISE CCD arrangement + is always left to right as far as hiccdstitch is concerned, unless + overiridden by the MosaicOrder keyword.) For + example, if stitching all 10 RED CCDs in an image you find that + RED5 must be shifted left 20 pixels but all other CCDs line up file + to the right, meaning RED6 through RED9, then you are required + to privide groups for RED6, RED7, RED8 and RED9 with the same + SampleOffset provided for RED5. This is the only way proper + sample alignment is retained. +

    +

    + Below is an example of the format of the input file for the + SHIFTDEF file: +

    +
    +            Object = Hiccdstitch
    +
    +            # Defaults for Red0 images
    +              Object = RED0
    +                SampleOffset     = -10
    +                LineOffset       = 5
    +
    +                # Summing=1, Tdi=64 values.  Any of the three keywords (MosaicOrder, SampleOffset, LineOffset) 
    +                #  can exist in the summing/tdi groups that will override the defaults in the RED0 object.
    +                Group = 1/64
    +                  SampleOffset = 0
    +                  LineOffset = 0
    +                End_Group
    +
    +                # Summing=1, Tdi=128
    +                Group = 1/128
    +                  SampleOffset = 20
    +                End_Group
    +
    +                # If a summing/tdi group does not exist, the ccd defaults are used
    +              End_Object
    +
    +              Object = RED3
    +                SampleOffset     = 13
    +                LineOffset       = -5
    +              End_Object
    +
    +              Object = RED5
    +                LineOffset       = 22
    +              End_Object
    +
    +              Object = RED9
    +                # MosaicOrder of -1, indicates the ccd is placed in mosaic first.
    +                 MosaicOrder = -1
    +               End_Object
    +
    +               Object = IR11
    +                SampleOffset     = -4
    +                LineOffset       = 2
    +              End_Object
    +
    +              Object = BG12
    +                SampleOffset     = 12
    +              End_Object
    +            End_Object
    +            End
    +            
    +

    + The only keywords that hiccdstitch reads from this file + are SampleOffset , LineOffset and + MosaicOrder. All other keywords are ignored. + All CCD objects must be contained within the + Hiccdstitch object. +

    +

    + Note that this file is an optional parameter. If it is not + provided, then all CCD files provided are mapped to + focal plane positions as specified in the HiRISE + Instrument Operations Handbook. Note that the size + of a HiRISE pixel is 0.012 millimeters and the measurements + in the handbook are also in millimeters. +

    +
    +
    +
    + + + + cube + output + + Output stitched cube + + + The output cube into which the input cubes will be placed. + + + *.cub + + + + filename + None + output + + Output file providing the placement of CCDs in the TO cube + + + If provided, the actual line and sample locations of each CCD as + they map to the TO cube are recorded here. This format is the + the same as the format provided in the STITCHDEF file. + + + *.def + + + + + + string + + NEARESTNEIGHBOR + + Type of interpolation + + This is the type of interpolation to be performed on the input when + ccds of different summing modes are combined. + + + + + + + + +
    +
    diff --git a/isis/src/mro/apps/hiccdstitch/template/Makefile b/isis/src/mro/apps/hiccdstitch/template/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..90c29e8845d1da5f25e9dc3b90690ee73e22f88e --- /dev/null +++ b/isis/src/mro/apps/hiccdstitch/template/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = genTemplate + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hiccdstitch/template/genTemplate.cpp b/isis/src/mro/apps/hiccdstitch/template/genTemplate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..880a9ac0df57f2607fc30e298ecfb948ad67d46e --- /dev/null +++ b/isis/src/mro/apps/hiccdstitch/template/genTemplate.cpp @@ -0,0 +1,60 @@ +#include "Pvl.h" +#include "ProcessMosaic.h" +#include "ProcessByLine.h" +#include "Brick.h" +#include "FileList.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + + +int main(int argc, char *argv[]) { + + + // X offset (pixels) of each CCD relative to CCD 10 + const char * const ccdNames[] = { "RED0", "RED1", "RED2", "RED3", "RED4", + "RED5", "RED6", "RED7", "RED8", "RED9", + "IR10", "IR11", "BG12", "BG13" }; + + const int xFPloc[] = {-8000,-6000,-4004,-2003,0,2000, 4000,6000, 8000,10000, + 0,2000,0,2000}; + const int yFPloc[] = { -1219, -1793, -1171, -1791, -1205, -1789, -1189, + -1786, -1210, -1817, 0, -606, -2396, -3002 }; + + const int xoffset[] = {-8000-10,-6000+11,-4004-17+3,-2003+10+3,0-13+3, + 2000+16+3, 4000-16+3,6000+18+3, 8000-18+3,10000+20+3, + 0,2000,0,2000}; + const int yoffset[] = { 0+0+5, 0+6+5, 0+14+5, 0+15+5, 0+17+5, 0+17+5, 0+16+5, + 0+11+5, 0+5+5, 0-5+5, 0, 0, 0, 0}; + + PvlObject hiCCD("Hiccdstitch"); + hiCCD.AddComment("This file describes the line and sample offsets for each HiRISE"); + hiCCD.AddComment("CCD in the focal plane. Negative values shift CCDs left and up."); + hiCCD.AddComment("Positive values shift CCD right and down."); + + for (int i = 0 ; i < 14 ; i++) { + PvlGroup ccdGroup(ccdNames[i]); + ccdGroup += PvlKeyword("FocalPlaneSample",xFPloc[i]); + ccdGroup += PvlKeyword("FocalPlaneLine",yFPloc[i]); + ccdGroup += PvlKeyword("ImageSample",xFPloc[i]-xFPloc[0]+1); + ccdGroup += PvlKeyword("ImageLine",1); +#if defined(RED_00001_0000) + ccdGroup += PvlKeyword("SampleOffset",xoffset[i]-xFPloc[i]); + ccdGroup += PvlKeyword("LineOffset",0+yoffset[i]); +#else + ccdGroup += PvlKeyword("SampleOffset",0); + ccdGroup += PvlKeyword("LineOffset",0); +#endif + hiCCD.AddGroup(ccdGroup); + } + + Pvl pvl; + pvl.AddObject(hiCCD); +#if defined(RED_00001_0000) + pvl.Write("hiccdstitch.000001_0000_RED.def"); +#else + pvl.Write("hiccdstitch.offsets.def"); +#endif + return (0); +} // End of IsisMain diff --git a/isis/src/mro/apps/hiccdstitch/template/hiccdstitch.000001_0000_RED.def b/isis/src/mro/apps/hiccdstitch/template/hiccdstitch.000001_0000_RED.def new file mode 100644 index 0000000000000000000000000000000000000000..638b61efef844893f2030ad956025216da41daeb --- /dev/null +++ b/isis/src/mro/apps/hiccdstitch/template/hiccdstitch.000001_0000_RED.def @@ -0,0 +1,131 @@ +# This file describes the line and sample offsets for each HiRISE +# CCD in the focal plane. Negative values shift CCDs left and up. +# Positive values shift CCD right and down. +Object = Hiccdstitch + Group = RED0 + FocalPlaneSample = -8000 + FocalPlaneLine = -1219 + ImageSample = 1 + ImageLine = 1 + SampleOffset = -10 + LineOffset = 5 + End_Group + + Group = RED1 + FocalPlaneSample = -6000 + FocalPlaneLine = -1793 + ImageSample = 2001 + ImageLine = 1 + SampleOffset = 11 + LineOffset = 11 + End_Group + + Group = RED2 + FocalPlaneSample = -4004 + FocalPlaneLine = -1171 + ImageSample = 3997 + ImageLine = 1 + SampleOffset = -14 + LineOffset = 19 + End_Group + + Group = RED3 + FocalPlaneSample = -2003 + FocalPlaneLine = -1791 + ImageSample = 5998 + ImageLine = 1 + SampleOffset = 13 + LineOffset = 20 + End_Group + + Group = RED4 + FocalPlaneSample = 0 + FocalPlaneLine = -1205 + ImageSample = 8001 + ImageLine = 1 + SampleOffset = -10 + LineOffset = 22 + End_Group + + Group = RED5 + FocalPlaneSample = 2000 + FocalPlaneLine = -1789 + ImageSample = 10001 + ImageLine = 1 + SampleOffset = 19 + LineOffset = 22 + End_Group + + Group = RED6 + FocalPlaneSample = 4000 + FocalPlaneLine = -1189 + ImageSample = 12001 + ImageLine = 1 + SampleOffset = -13 + LineOffset = 21 + End_Group + + Group = RED7 + FocalPlaneSample = 6000 + FocalPlaneLine = -1786 + ImageSample = 14001 + ImageLine = 1 + SampleOffset = 21 + LineOffset = 16 + End_Group + + Group = RED8 + FocalPlaneSample = 8000 + FocalPlaneLine = -1210 + ImageSample = 16001 + ImageLine = 1 + SampleOffset = -15 + LineOffset = 10 + End_Group + + Group = RED9 + FocalPlaneSample = 10000 + FocalPlaneLine = -1817 + ImageSample = 18001 + ImageLine = 1 + SampleOffset = 23 + LineOffset = 0 + End_Group + + Group = IR10 + FocalPlaneSample = 0 + FocalPlaneLine = 0 + ImageSample = 8001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = IR11 + FocalPlaneSample = 2000 + FocalPlaneLine = -606 + ImageSample = 10001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = BG12 + FocalPlaneSample = 0 + FocalPlaneLine = -2396 + ImageSample = 8001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = BG13 + FocalPlaneSample = 2000 + FocalPlaneLine = -3002 + ImageSample = 10001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group +End_Object +End \ No newline at end of file diff --git a/isis/src/mro/apps/hiccdstitch/template/hiccdstitch.offsets.def b/isis/src/mro/apps/hiccdstitch/template/hiccdstitch.offsets.def new file mode 100644 index 0000000000000000000000000000000000000000..2c9c4771e8eaaee59243e805376a8e640a2a1f7a --- /dev/null +++ b/isis/src/mro/apps/hiccdstitch/template/hiccdstitch.offsets.def @@ -0,0 +1,131 @@ +# This file describes the line and sample offsets for each HiRISE +# CCD in the focal plane. Negative values shift CCDs left and up. +# Positive values shift CCD right and down. +Object = Hiccdstitch + Group = RED0 + FocalPlaneSample = -8000 + FocalPlaneLine = -1219 + ImageSample = 1 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = RED1 + FocalPlaneSample = -6000 + FocalPlaneLine = -1793 + ImageSample = 2001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = RED2 + FocalPlaneSample = -4004 + FocalPlaneLine = -1171 + ImageSample = 3997 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = RED3 + FocalPlaneSample = -2003 + FocalPlaneLine = -1791 + ImageSample = 5998 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = RED4 + FocalPlaneSample = 0 + FocalPlaneLine = -1205 + ImageSample = 8001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = RED5 + FocalPlaneSample = 2000 + FocalPlaneLine = -1789 + ImageSample = 10001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = RED6 + FocalPlaneSample = 4000 + FocalPlaneLine = -1189 + ImageSample = 12001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = RED7 + FocalPlaneSample = 6000 + FocalPlaneLine = -1786 + ImageSample = 14001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = RED8 + FocalPlaneSample = 8000 + FocalPlaneLine = -1210 + ImageSample = 16001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = RED9 + FocalPlaneSample = 10000 + FocalPlaneLine = -1817 + ImageSample = 18001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = IR10 + FocalPlaneSample = 0 + FocalPlaneLine = 0 + ImageSample = 8001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = IR11 + FocalPlaneSample = 2000 + FocalPlaneLine = -606 + ImageSample = 10001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = BG12 + FocalPlaneSample = 0 + FocalPlaneLine = -2396 + ImageSample = 8001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group + + Group = BG13 + FocalPlaneSample = 2000 + FocalPlaneLine = -3002 + ImageSample = 10001 + ImageLine = 1 + SampleOffset = 0 + LineOffset = 0 + End_Group +End_Object +End \ No newline at end of file diff --git a/isis/src/mro/apps/hiccdstitch/tsts/Makefile b/isis/src/mro/apps/hiccdstitch/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hiccdstitch/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hiccdstitch/tsts/placement/Makefile b/isis/src/mro/apps/hiccdstitch/tsts/placement/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0972fbe2b4c0c47a2e7b6ee3f47e775dd989bdbd --- /dev/null +++ b/isis/src/mro/apps/hiccdstitch/tsts/placement/Makefile @@ -0,0 +1,10 @@ +APPNAME = hiccdstitch + +include $(ISISROOT)/make/isismake.tsts + +commands: + t=`ls $(INPUT)/PSP_001446_1790_RED?.cub > $(OUTPUT)/list.temp`; \ + $(APPNAME) fromlist=$(OUTPUT)/list.temp \ + to=$(OUTPUT)/combined.cub \ + placement=$(OUTPUT)/placement.pvl > /dev/null; \ + t=`rm -f $(OUTPUT)/list.temp`; diff --git a/isis/src/mro/apps/hiccdstitch/tsts/shiftdef/Makefile b/isis/src/mro/apps/hiccdstitch/tsts/shiftdef/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0638bc87903d617a10766fa341fe52d91d85a6db --- /dev/null +++ b/isis/src/mro/apps/hiccdstitch/tsts/shiftdef/Makefile @@ -0,0 +1,11 @@ +APPNAME = hiccdstitch + +include $(ISISROOT)/make/isismake.tsts + +commands: + t=`ls $(INPUT)/PSP_001446_1790_RED?.cub > $(OUTPUT)/list.temp`; \ + $(APPNAME) fromlist=$(OUTPUT)/list.temp \ + shiftdef=$(INPUT)/shift.txt \ + to=$(OUTPUT)/combined.cub \ + placement=$(OUTPUT)/placement.pvl > /dev/null; \ + t=`rm -f $(OUTPUT)/list.temp`; diff --git a/isis/src/mro/apps/hicolormos/Makefile b/isis/src/mro/apps/hicolormos/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hicolormos/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hicolormos/hicolormos.cpp b/isis/src/mro/apps/hicolormos/hicolormos.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf601266f0c2580516ada02a21072993ae5b7ed5 --- /dev/null +++ b/isis/src/mro/apps/hicolormos/hicolormos.cpp @@ -0,0 +1,270 @@ +#include "Isis.h" +#include "Process.h" +#include "FileList.h" +#include "iException.h" +#include "Cube.h" +#include "CameraFactory.h" +#include "Camera.h" +#include "Projection.h" +#include "UserInterface.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Application.h" +#include "iString.h" +#include "OriginalLabel.h" +#include "TextFile.h" +#include "Filename.h" + +using namespace std; +using namespace Isis; + +//functions in the code +void IsisMain() { + + // Get the values for the from 1 cube + UserInterface &ui = Application::GetUserInterface(); + string from1 = ui.GetFilename("FROM1"); + + // Make a temporary list file for automos + Filename tempFile; + tempFile.Temporary("hicolormos.temp","lis"); + TextFile tf; + tf.Open(tempFile.Expanded(),"output"); + tf.PutLine(from1+"\n"); + + Pvl from1lab(from1); + PvlGroup from1Mosaic = from1lab.FindGroup("Mosaic",Pvl::Traverse); + + // Make the procuct ID (from1 archive group) + string ProdId = from1lab.FindGroup("Archive",Pvl::Traverse)["ObservationId"]; + ProdId += "_COLOR"; + + // Prep for second image if we have one + Pvl from2lab; + PvlGroup from2Mosaic("Mosaic"); + if (ui.WasEntered("FROM2")) { + string from2 = ui.GetFilename("FROM2"); + //Add from2 file to the temporary automos input list + tf.PutLine(from2+"\n"); + from2lab.Read(from2); + + // Test the observation ID between from1 and from2 + if ((string)from1lab.FindGroup("Archive",Pvl::Traverse)["ObservationId"] != + (string)from2lab.FindGroup("Archive",Pvl::Traverse)["ObservationId"]) { + string msg = "Images not from the same observation"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + from2Mosaic = from2lab.FindGroup("Mosaic",Pvl::Traverse); + } + tf.Close(); // Close list remember to delete + + // Make the source product ID (from1 mosaic group) + PvlKeyword sourceProductId = from1Mosaic["SourceProductId"]; + if (ui.WasEntered("FROM2")) { + // Add source product Id for from2 + PvlKeyword from2SPI = from2Mosaic["SourceProductId"]; + for (int i=0; i < (int)from2SPI.Size(); i++) { + sourceProductId += from2SPI[i]; + } + } + + // Work with latitude and longitude use projection factory (from1) + Projection *proj = Isis::ProjectionFactory::CreateFromCube(from1lab); + double minLat = proj->MinimumLatitude(); + double maxLat = proj->MaximumLatitude(); + double minLon = proj->MinimumLongitude(); + double maxLon = proj->MaximumLongitude(); + if (ui.WasEntered("FROM2")) { + Projection *proj = Isis::ProjectionFactory::CreateFromCube(from2lab); + if (proj->MinimumLatitude() < minLat) minLat = proj->MinimumLatitude(); + if (proj->MaximumLatitude() > maxLat) maxLat = proj->MaximumLatitude(); + if (proj->MinimumLongitude() < minLon) minLon = proj->MinimumLongitude(); + if (proj->MaximumLongitude() > maxLon) maxLon = proj->MaximumLongitude(); + } + + double avgLat = (minLat + maxLat) / 2; + double avgLon = (minLon + maxLon) / 2; + proj->SetGround(avgLat,avgLon); + avgLat = proj->UniversalLatitude(); + avgLon = proj->UniversalLongitude(); + + //Added 10/07 this bool will used to determain if need to use X and Y avg. + // to find an intersection. Added because of polor image problems. + bool runXY=true; + // Use camera class to get from1 emsiion, phase, and incidence. + double Cemiss; + double Cphase; + double Cincid; + double ClocalSolTime; + double CsolarLong; + double CnorthAzimuth; + double CsunAzimuth; + + //The code that sets the universal grond with projection avglat and avglon + // has been left in to be backward compatiable. See code below that sets + // image, this was in 10/07 because pole images would not find an + // intersect in projection lat. lon. space. + Camera *cam = Isis::CameraFactory::Create(from1lab); + if (cam->SetUniversalGround(avgLat,avgLon)) { + Cemiss = cam->EmissionAngle(); + Cphase = cam->PhaseAngle(); + Cincid = cam->IncidenceAngle(); + ClocalSolTime = cam->LocalSolarTime(); + CsolarLong = cam->SolarLongitude(); + CnorthAzimuth = cam->NorthAzimuth(); + CsunAzimuth = cam->SunAzimuth(); + runXY=false; + } + else if (ui.WasEntered("FROM2")) { + Camera *cam = Isis::CameraFactory::Create(from2lab); + if (cam->SetUniversalGround(avgLat,avgLon)) { + Cemiss = cam->EmissionAngle(); + Cphase = cam->PhaseAngle(); + Cincid = cam->IncidenceAngle(); + ClocalSolTime = cam->LocalSolarTime(); + CsolarLong = cam->SolarLongitude(); + CnorthAzimuth = cam->NorthAzimuth(); + CsunAzimuth = cam->SunAzimuth(); + runXY=false; + } + } + + //The code within the if runXY was added in 10/07 to find an intersect with + //pole images that would fail when using projection set universal ground. + // This is run if no intersect is found when using lat and lon in + // projection space. + if (runXY) { + Projection *proj = Isis::ProjectionFactory::CreateFromCube(from1lab); + proj->SetWorld(0.5,0.5); + double startX = proj->XCoord(); + double endY = proj->YCoord(); + double nlines = from1lab.FindGroup("Dimensions",Pvl::Traverse)["Lines"]; + double nsamps = from1lab.FindGroup("Dimensions",Pvl::Traverse)["Samples"]; + proj->SetWorld((nsamps+0.5),(nlines+0.5)); + double endX = proj->XCoord(); + double startY = proj->YCoord(); + + if (ui.WasEntered("FROM2")) { + Projection *proj = Isis::ProjectionFactory::CreateFromCube(from2lab); + proj->SetWorld(0.5,0.5); + if (proj->XCoord() < startX) startX = proj->XCoord(); + if (proj->YCoord() > endY) endY = proj->YCoord(); + nlines = from2lab.FindGroup("Dimensions",Pvl::Traverse)["Lines"]; + nsamps = from2lab.FindGroup("Dimensions",Pvl::Traverse)["Samples"]; + proj->SetWorld((nsamps+0.5),(nlines+0.5)); + if (proj->XCoord() > endX) endX = proj->XCoord(); + if (proj->YCoord() < startY) startY = proj->YCoord(); + } + + double avgX = (startX + endX) / 2; + double avgY = (startY + endY) / 2; + double sample = proj->ToWorldX(avgX); + double line = proj->ToWorldY(avgY); + Camera *cam = Isis::CameraFactory::Create(from1lab); + if (cam->SetImage(sample,line)){ + Cemiss = cam->EmissionAngle(); + Cphase = cam->PhaseAngle(); + Cincid = cam->IncidenceAngle(); + ClocalSolTime = cam->LocalSolarTime(); + CsolarLong = cam->SolarLongitude(); + CnorthAzimuth = cam->NorthAzimuth(); + CsunAzimuth = cam->SunAzimuth(); + runXY=false; + } + else if (ui.WasEntered("FROM2")){ + Camera *cam = Isis::CameraFactory::Create(from2lab); + if (cam->SetImage(sample,line)){ + Cemiss = cam->EmissionAngle(); + Cphase = cam->PhaseAngle(); + Cincid = cam->IncidenceAngle(); + ClocalSolTime = cam->LocalSolarTime(); + CsolarLong = cam->SolarLongitude(); + CnorthAzimuth = cam->NorthAzimuth(); + CsunAzimuth = cam->SunAzimuth(); + runXY=false; + } + } + } + + if (runXY){ + string tmp(tempFile.Expanded()); + remove(tmp.c_str()); + string msg = "Camera did not intersect images to gather stats"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + //work on the times (from mosaic group) + string startTime = from1Mosaic["StartTime"]; + string stopTime = from1Mosaic["StopTime"]; + string startClk = from1Mosaic["SpacecraftClockStartCount"]; + string stopClk = from1Mosaic["SpacecraftClockStopCount"]; + + if (ui.WasEntered("FROM2")) { + if ((string)from2Mosaic["StartTime"] < startTime) startTime = (string)from2Mosaic["StartTime"]; + if ((string)from2Mosaic["StopTime"] > stopTime) stopTime = (string)from2Mosaic["StopTime"]; + if ((string)from2Mosaic["SpacecraftClockStartCount"] < startClk) startClk = (string)from2Mosaic["SpacecraftClockStartCount"]; + if ((string)from2Mosaic["SpacecraftClockStopCount"] < stopClk) stopClk = (string)from2Mosaic["SpacecraftClockStopCount"]; + } + + // Get TDI and summing array + PvlKeyword cpmmTdiFlag = from1Mosaic["cpmmTdiFlag"]; + PvlKeyword cpmmSummingFlag = from1Mosaic["cpmmSummingFlag"]; + PvlKeyword specialProcessingFlag = from1Mosaic["SpecialProcessingFlag"]; + if (ui.WasEntered("FROM2")){ + for (int i=0; i<14; i++){ + if (! from2Mosaic["cpmmTdiFlag"].IsNull(i)){ + cpmmTdiFlag[i] = from2Mosaic["cpmmTdiFlag"][i]; + } + if (!from2Mosaic["cpmmSummingFlag"].IsNull(i)){ + cpmmSummingFlag[i] = from2Mosaic["cpmmSummingFlag"][i]; + } + if (!from2Mosaic["SpecialProcessingFlag"].IsNull()){ + specialProcessingFlag[i] = from2Mosaic["SpecialProcessingFlag"][i]; + } + } + } + + + // automos step + string MosaicPriority = ui.GetString("PRIORITY"); + + string parameters = "FROMLIST=" + tempFile.Expanded() + + " MOSAIC=" + ui.GetFilename("TO") + + " PRIORITY=" + MosaicPriority; + Isis::iApp ->Exec("automos",parameters); + + PvlGroup mos("Mosaic"); + mos += PvlKeyword("ProductId ", ProdId); + mos += sourceProductId; + mos += PvlKeyword("StartTime ", startTime); + mos += PvlKeyword("SpacecraftClockStartCount ", startClk); + mos += PvlKeyword("StopTime ", stopTime); + mos += PvlKeyword("SpacecraftClockStopCount ", stopClk); + mos += PvlKeyword("IncidenceAngle ", Cincid, "DEG"); + mos += PvlKeyword("EmissionAngle ", Cemiss, "DEG"); + mos += PvlKeyword("PhaseAngle ", Cphase, "DEG"); + mos += PvlKeyword("LocalTime ", ClocalSolTime, "LOCALDAY/24"); + mos += PvlKeyword("SolarLongitude ", CsolarLong, "DEG"); + mos += PvlKeyword("SubSolarAzimuth ", CsunAzimuth, "DEG"); + mos += PvlKeyword("NorthAzimuth ", CnorthAzimuth, "DEG"); + mos += cpmmTdiFlag; + mos += cpmmSummingFlag; + mos += specialProcessingFlag; + + //get the orginal label + OriginalLabel from1OrgLab; + from1OrgLab.Blob::Read(from1); + + Cube c; + c.Open(ui.GetFilename("TO"),"rw"); + c.Label()->FindObject("IsisCube",Pvl::Traverse).AddGroup(mos); + c.Write(from1OrgLab); + c.Close(); + + // Clean up the temporary automos list file + string tmp(tempFile.Expanded()); + remove(tmp.c_str()); +} // end of isis main + + diff --git a/isis/src/mro/apps/hicolormos/hicolormos.xml b/isis/src/mro/apps/hicolormos/hicolormos.xml new file mode 100644 index 0000000000000000000000000000000000000000..ed6932e8094413a4a321182de7da5ee6c872820f --- /dev/null +++ b/isis/src/mro/apps/hicolormos/hicolormos.xml @@ -0,0 +1,139 @@ + + + + + Create a color mosaic of a HiRISE cubes from an observation and update labels required by hirdrgen. + + + +

    + ** The output from this program is required by hirdrgen **
    + If the final product wil not be an RDR, mapmos or automos can be used to produce a mosaic. + This program produces a mosaic and adds keywords to the label group "Mosaic" that are required + by hirdrgen.
    + + The input cubes to this program must be from the same observation, stacked by hicubeit, and + map projected.
    + + the CCDs of the HiRISE instrument are arranged in a way that color products can only be produced in two + positions of the CCD array. The CCDs that overlap for a color product are RED4, IR10, and + BG12 or RED5, IR11, and BG13. The program hicubeit is used to stack the individual CCDs into + a multi band cube. The output from hicubeit is the required input for hicolormos. The from1 and + from2 parameters allow these two CCD stacks to be input. The program hicolormos can also be run + with only the from1 parameter.
    + + A new label group, that is required by hirdrgen, called "Mosaic" is added to the image labels of + the output cube. The original label blob is also propagated from the from1 input file. +

    + +

    + processing sequence for color products that will become RDRs
    + Slither - match the blue-green and/or the infer-red to the red CCD.
    + hicubeit - stack the matching CCDs to make a three band cube.
    + cam2map - project the cube. hicolormos requiers a map projected cube.
    + hicolormos - mosaic files and add keywords to the mosaic group.
    + hirdrgen - produce a RDR product.
    +

    +
    + + + Mars Reconnaissance Orbiter + + + + + Original version, + + + Changed OriginalLabel name to IsisCube + + + Added keywords SubSolarAzimuth, NorthAzimuth, and SpecialProcessingFlag to mosaic group in output labels. + + + Fixed a bug, needed to add traverse when looking for PVL group archive. + + + Added code to get the avg line and sample for gathering camera infomation if using the avg latitude and longitude fails. + We contine to use the latitude and logitude so that we are backwards compatible. We added this new code because + the camera could not find an itersect for some images (polar) if we used projection latitude and longitude to "setGround". + + + + + + + cube + input + + First input file + + + The first file that will be added to a color mosaic. This file is also used to propagate + the Original label blob. This file must be the output file from hicubeit and map projected. + + + *.cub + + + + cube + input + None + + Second input file. this file is not required. + + + This is the second cube that will be added to a color masaic. This file should be the output + from hicubeit and map projected. This input file is not required. + + + *.cub + + + + + cube + output + + The name of the output cube + + + This is the name that will be given to the output cube. this cube is a mosaic of the two + from files and has the new group "mosaic' added. + + + *.cub + + + + + string + + ONTOP + + The priority of pixel placement + + This parameter is used to select one of two ways to masaic the + pixels in areas of overlap. + + + + + + + + + +
    diff --git a/isis/src/mro/apps/hicolormos/tsts/Makefile b/isis/src/mro/apps/hicolormos/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hicolormos/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hicolormos/tsts/case01/Makefile b/isis/src/mro/apps/hicolormos/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b8a320d1e93dfb3bdb06307361e2ca13f2ce8cd0 --- /dev/null +++ b/isis/src/mro/apps/hicolormos/tsts/case01/Makefile @@ -0,0 +1,8 @@ +APPNAME = hicolormos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from1=$(INPUT)/test_hicubeitOUT_sinu_070419.cub \ + to=$(OUTPUT)/test_hicolormos.cub > /dev/null; + catlab from=$(OUTPUT)/test_hicolormos.cub > $(OUTPUT)/hicolormos.pvl; diff --git a/isis/src/mro/apps/hicubeit/Makefile b/isis/src/mro/apps/hicubeit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hicubeit/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hicubeit/hicubeit.cpp b/isis/src/mro/apps/hicubeit/hicubeit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4453cb921a4e318361ce48e3a0bd9062481ec22d --- /dev/null +++ b/isis/src/mro/apps/hicubeit/hicubeit.cpp @@ -0,0 +1,181 @@ +#include "Isis.h" +#include "TextFile.h" +#include "Pvl.h" +#include "Cube.h" +#include "OriginalLabel.h" +#include + +using namespace std; +using namespace Isis; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + string redFile = ui.GetFilename("RED"); + string irFile = ui.GetFilename("IR"); + string bgFile = ui.GetFilename("BG"); + + Filename tempFile; + tempFile.Temporary("hicubeit.temp","lis"); + TextFile tf; + tf.Open(tempFile.Expanded(),"output"); + tf.PutLine(irFile+"\n"); + tf.PutLine(redFile+"\n"); + tf.PutLine(bgFile+"\n"); + tf.Close(); + + string parameters = string(" LIST = ") + tempFile.Expanded() + + string(" TO = ") + ui.GetFilename("TO") + + string(" PROPLAB = ") + redFile; + iApp->Application::Exec("cubeit",parameters); + remove(tempFile.Expanded().c_str()); + + // Get the instrument group from each file + Pvl redLab(redFile); + Pvl irLab(irFile); + Pvl bgLab(bgFile); + + PvlGroup redInst = redLab.FindGroup("Instrument",Pvl::Traverse); + PvlGroup irInst = irLab.FindGroup("Instrument",Pvl::Traverse); + PvlGroup bgInst = bgLab.FindGroup("Instrument",Pvl::Traverse); + + // Error check to make sure the proper ccds are stacked + if ((int)redInst["CpmmNumber"] == 5) { + if (((int)irInst["CpmmNumber"] != 6) || ((int)bgInst["CpmmNumber"] != 4)) { + string msg = "You can only stack color images with RED4, IR10, and BG12 "; + msg += "or RED5, IR11, and BG13"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + else if ((int)redInst["CpmmNumber"] == 8) { + if (((int)irInst["CpmmNumber"] != 7) || ((int)bgInst["CpmmNumber"] != 9)) { + string msg = "You can only stack color images with RED4, IR10, and BG12 "; + msg += "or RED5, IR11, and BG13"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + else { + string msg = "You can only stack color images with RED4, IR10, and BG12 "; + msg += "or RED5, IR11, and BG13"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Concatenate all the source products into one keyword + PvlKeyword sourceProductId("SourceProductId"); + sourceProductId += (string)bgInst["StitchedProductIds"][0]; + if (bgInst["StitchedProductIds"].Size() > 1) { + sourceProductId += (string)bgInst["StitchedProductIds"][1]; + } + sourceProductId += (string)redInst["StitchedProductIds"][0]; + if (redInst["StitchedProductIds"].Size() > 1) { + sourceProductId += (string)redInst["StitchedProductIds"][1]; + } + sourceProductId += (string)irInst["StitchedProductIds"][0]; + if (irInst["StitchedProductIds"].Size() > 1) { + sourceProductId += (string)irInst["StitchedProductIds"][1]; + } + + // Get min start and max stop time + PvlKeyword startTime = redInst["StartTime"]; + PvlKeyword stopTime = redInst["StopTime"]; + PvlKeyword startClk = redInst["SpacecraftClockStartCount"]; + PvlKeyword stopClk = redInst["SpacecraftClockStopCount"]; + + if ((string) irInst["StartTime"] < (string)startTime) { + startTime = irInst["StartTime"]; + } + if ((string) bgInst["StartTime"] < (string)startTime) { + startTime = bgInst["StartTime"]; + } + + if ((string) irInst["StopTime"] > (string)stopTime) { + stopTime = irInst["StopTime"]; + } + if ((string) bgInst["StopTime"] > (string)stopTime) { + stopTime = bgInst["StopTime"]; + } + + if ((string) irInst["SpacecraftClockStartCount"] < (string)startClk) { + startClk = irInst["SpacecraftClockStartCount"]; + } + if ((string) bgInst["SpacecraftClockStartCount"] < (string)startClk) { + startClk = bgInst["SpacecraftClockStartCount"]; + } + + if ((string) irInst["SpacecraftClockStopCount"] > (string)stopClk) { + stopClk = irInst["SpacecraftClockStopCount"]; + } + if ((string) bgInst["SpacecraftClockStopCount"] > (string)stopClk) { + stopClk = bgInst["SpacecraftClockStopCount"]; + } + + // Concatenate all TDIs into one keyword + OriginalLabel redOrgLab; + redOrgLab.Blob::Read(redFile); + OriginalLabel irOrgLab; + irOrgLab.Blob::Read(irFile); + OriginalLabel bgOrgLab; + bgOrgLab.Blob::Read(bgFile); + + PvlGroup redGrp = redOrgLab.ReturnLabels().FindGroup("INSTRUMENT_SETTING_PARAMETERS",Pvl::Traverse); + PvlGroup irGrp = irOrgLab.ReturnLabels().FindGroup("INSTRUMENT_SETTING_PARAMETERS",Pvl::Traverse); + PvlGroup bgGrp = bgOrgLab.ReturnLabels().FindGroup("INSTRUMENT_SETTING_PARAMETERS",Pvl::Traverse); + + PvlKeyword cpmmTdiFlag("cpmmTdiFlag"); + for (int i=0; i<14; i++) { + cpmmTdiFlag += (string) ""; + } + cpmmTdiFlag[(int)redInst["CpmmNumber"]] = (string) redGrp["MRO:TDI"]; + cpmmTdiFlag[(int)irInst["CpmmNumber"]] = (string) irGrp["MRO:TDI"]; + cpmmTdiFlag[(int)bgInst["CpmmNumber"]] = (string) bgGrp["MRO:TDI"]; + + // Concatenate all summing modes into one keyword + PvlKeyword cpmmSummingFlag("cpmmSummingFlag"); + for (int i=0; i<14; i++) { + cpmmSummingFlag += (string) ""; + } + cpmmSummingFlag[(int)redInst["CpmmNumber"]] = (string) redGrp["MRO:BINNING"]; + cpmmSummingFlag[(int)irInst["CpmmNumber"]] = (string) irGrp["MRO:BINNING"]; + cpmmSummingFlag[(int)bgInst["CpmmNumber"]] = (string) bgGrp["MRO:BINNING"]; + + //Concatenate all the Special_Processing_Flag into one keyword + PvlKeyword specialProcessingFlag("SpecialProcessingFlag"); + for (int i=0; i<14; i++) { + specialProcessingFlag += (string) ""; + } + //keyword Special_Processing_Flag may not be present so need to test + // if not present set to NOMINAL + if(redInst.HasKeyword("Special_Processing_Flag")) { + specialProcessingFlag[redInst["CpmmNumber"]] = (string) redInst["Special_Processing_Flag"]; + } + else { + specialProcessingFlag[redInst["CpmmNumber"]] = "NOMINAL"; + } + if(irInst.HasKeyword("Special_Processing_Flag")) { + specialProcessingFlag[irInst["CpmmNumber"]] = (string) irInst["Special_Processing_Flag"]; + } + else { + specialProcessingFlag[irInst["CpmmNumber"]] = "NOMINAL"; + } + if(bgInst.HasKeyword("Special_Processing_Flag")) { + specialProcessingFlag[bgInst["CpmmNumber"]] = (string) bgInst["Special_Processing_Flag"]; + } + else { + specialProcessingFlag[bgInst["CpmmNumber"]] = "NOMINAL"; + } + // Put them in a group + PvlGroup mos("Mosaic"); + mos += sourceProductId; + mos += startTime; + mos += stopTime; + mos += startClk; + mos += stopClk; + mos += cpmmTdiFlag; + mos += cpmmSummingFlag; + mos += specialProcessingFlag; + + // Add the group to the output cube + Cube c; + c.Open(ui.GetFilename("TO"),"rw"); + c.Label()->FindObject("IsisCube",Pvl::Traverse).AddGroup(mos); + c.Close(); +} diff --git a/isis/src/mro/apps/hicubeit/hicubeit.xml b/isis/src/mro/apps/hicubeit/hicubeit.xml new file mode 100644 index 0000000000000000000000000000000000000000..87fef9770d788519fd246c4df5e9fbc090ca5da4 --- /dev/null +++ b/isis/src/mro/apps/hicubeit/hicubeit.xml @@ -0,0 +1,94 @@ + + + + + Stack slithered HiRISE red, bg, and ir cubes + + + + This program will stack HiRISE color images. The images must have been run through the "slither" procedure so that the pixels are spectrally aligned. The output cube will contain three bands in + blue-green, red, and infrared order. The Mosaic group will be written to the labels of the output cube which defines information about the three stacked bands. This information is used in the + program "hirdrgen". Using the program "cubeit" will not create this group and therefore "cubeit" products can not be written in RDR format. + Note that only CCDs + RED4, IR10, and BG12 or RED5, IR11, and BG13 can be stacked. The program will report an error if invalid CCD combinations are given. + + + + Mars Reconnaissance Orbiter + + + + + Original version + + + Changed OriginalLabel name to IsisCube + + + Added keyword SpecialProcessingFlag to the mosaic group in output labels + + + Reordered from BGR to RGB format + + + + + + + cube + input + + Input red HiRISE cube + + + The red HiRISE cube, either RED4 or RED5 + + + *.cub + + + + + cube + input + + Input infrared HiRISE cube + + + The infrared HiRISE cube, either IR10 or IR11 + + + *.cub + + + + + cube + input + + Input blue-green HiRISE cube + + + The blue-green HiRISE cube, either BG12 or BG13 + + + *.cub + + + + + cube + output + + Combined output cube + + + This will contain a three band output cube stacked in the order of BG, RED, and IR. + + + *.cub + + + + + diff --git a/isis/src/mro/apps/hicubeit/tsts/Makefile b/isis/src/mro/apps/hicubeit/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hicubeit/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hicubeit/tsts/default/Makefile b/isis/src/mro/apps/hicubeit/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b9330cfe27acc96c02ab99619ea5ba707853e47f --- /dev/null +++ b/isis/src/mro/apps/hicubeit/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = hicubeit + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) RED=$(INPUT)/RED4slither.cub \ + IR=$(INPUT)/IR10slither.cub BG=$(INPUT)/BG12slither.cub \ + TO=$(OUTPUT)/slither.cub > /dev/null; + catlab FROM=$(OUTPUT)/slither.cub >& $(OUTPUT)/slither.pvl; diff --git a/isis/src/mro/apps/hicubenorm/Makefile b/isis/src/mro/apps/hicubenorm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hicubenorm/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hicubenorm/hicubenorm.cpp b/isis/src/mro/apps/hicubenorm/hicubenorm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b152db4ca51e712f67215bcebacabb7bda6a5f12 --- /dev/null +++ b/isis/src/mro/apps/hicubenorm/hicubenorm.cpp @@ -0,0 +1,558 @@ +#include "Isis.h" + +// system include files go first +#include +#include +#include +#include +#include + +// Isis specific include files go next +#include "ProcessByTile.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "iException.h" +#include "Pvl.h" +#include "Statistics.h" +#include "VecFilter.h" + +using namespace std; +using namespace Isis; + +// These global vectors are used to keep track of info for columns +// of image data. For example, a 100 sample x 200 line x 2 band cube will +// have a vectors of 200 columns (100 samples x 2 bands). +vector stddev; +vector validpixels; +vector minimum; +vector maximum; +vector band; +vector element; +vector median; +vector average; +vector normalizer; + +// Size of the cube +int totalLines; +int totalSamples; + +enum Mode {SUBTRACT,DIVIDE}; + +// function prototypes +void getStats(Buffer &in); +void multiply(Buffer &in, Buffer &out); +void subtract(Buffer &in, Buffer &out); +void pvlOut(const string &pv); +void tableOut(const string &pv); +void PVLIn(const Isis::Filename & filename); +void tableIn(const Isis::Filename & filename); +void keepSame(int &totalBands, int &rowcol, Mode mode); +void filterStats(vector &filter,int &filtsize, bool &pause_crop, + int &channel); + +// Main Program +void IsisMain() { + vector filter; + int rowcol; // how many rows or cols per band + bool normalizeUsingAverage; // mult/sub using average or median? + int totalBands; + // Used for filtering the initial cubenorm averages and median values + int filtsize; + bool pause_crop; + int channel; + // ERROR CHECK: The user must specify at least the TO or STATS + // parameters. + UserInterface &ui = Application::GetUserInterface(); + if (!(ui.WasEntered("TO")) && !(ui.WasEntered("STATS"))) { + string msg = "User must specify a TO and/or STATS file."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // We will be processing by tile. + ProcessByTile p; + + // Setup the input cube; + // Obtain information from the input file + Cube *icube = p.SetInputCube("FROM"); + totalSamples = icube->Samples(); + totalLines = icube->Lines(); + totalBands = icube->Bands(); + channel = icube->GetGroup("Instrument")["ChannelNumber"]; + + // Setup the tile size for columnar processing + p.SetTileSize(1, totalLines); + rowcol = totalSamples; + + // Now get the statistics for each column + normalizeUsingAverage = ui.GetString("NORMALIZER") == "AVERAGE"; + + //gather statistics + if (ui.GetString("STATSOURCE") == "CUBE"){ + p.StartProcess(getStats); + } + else if (ui.GetString("STATSOURCE") == "TABLE"){ + tableIn(ui.GetFilename("FROMSTATS")); + } + else{ + PVLIn(ui.GetFilename("FROMSTATS")); + } + + //check to make sure the first vector has as many elements as the last + // vector, and that there is a vector element for each row/col + if (band.size() != (unsigned int)(rowcol*totalBands)) { + string message = "You have entered an invalid input file " + + ui.GetFilename("FROMSTATS"); + throw iException::Message(Isis::iException::Io, message, + _FILEINFO_); + } + + //get information needed to filter the statistics + filtsize = ui.GetInteger("FILTER"); + pause_crop = ui.GetBoolean("PAUSECROP"); + + //filter the column averages + filter = average; + filterStats(filter,filtsize,pause_crop,channel); + average = filter; + + //filter the column medians + filter = median; + filterStats(filter,filtsize,pause_crop,channel); + median = filter; + + //If a STATS file was specified then create statistics file + if (ui.WasEntered("STATS")) { + string op = ui.GetString("FORMAT"); + if (op == "PVL") pvlOut(ui.GetFilename("STATS")); + if (op == "TABLE") tableOut(ui.GetFilename("STATS")); + } + + // Update the statistics vectors before creating the output + // file + if (normalizeUsingAverage) { + normalizer = average; + } else { + normalizer = median; + } + + // If an output file was specified then normalize the cube + if (ui.WasEntered ("TO")) { + // Before creating a normalized cube check to see if there + // are any column averages less than or equal to zero. + if (ui.GetString("MODE") == "MULTIPLY") { + for (unsigned int i=0; i pixels; + for (int i=0; i 0) { + results += PvlKeyword("Mean",average[i]); + results += PvlKeyword("Median",median[i]); + results += PvlKeyword("Std",stddev[i]); + results += PvlKeyword("Minimum",minimum[i]); + results += PvlKeyword("Maximum",maximum[i]); + } + else { + results += PvlKeyword("Mean",0.0); + results += PvlKeyword("Median",0.0); + results += PvlKeyword("Std",0.0); + results += PvlKeyword("Minimum",0.0); + results += PvlKeyword("Maximum",0.0); + } + } + + Pvl t; + t.AddGroup(results); + t.Write(StatFile); +} + +//******************************************************** +// Create Tabular output of statistics +//******************************************************* +void tableOut(const string &StatFile) { + // Open output file + // TODO check status and throw error + ofstream out; + out.open(StatFile.c_str(),std::ios::out); + + // Output a header + out << std::setw(8) << "Band"; + out << std::setw(8) << "RowCol"; + out << std::setw(15) << "ValidPoints"; + out << std::setw(15) << "Average"; + out << std::setw(15) << "Median"; + out << std::setw(15) << "StdDev"; + out << std::setw(15) << "Minimum"; + out << std::setw(15) << "Maximum"; + out << endl; + + // Print out the table results + for (unsigned int i=0; i 0) { + out << std::setw(15) << average[i]; + out << std::setw(15) << median[i]; + //Make sure the table's SD is 0 for RowCols with 1 or less valid pixels + if( validpixels[i] > 1 ) { + out << std::setw(15) << stddev[i]; + } + else { + out << std::setw(15) << 0; + } + out << std::setw(15) << minimum[i]; + out << std::setw(15) << maximum[i]; + } + else { + out << std::setw(15) << 0; + out << std::setw(15) << 0; + out << std::setw(15) << 0; + out << std::setw(15) << 0; + out << std::setw(15) << 0; + } + out << endl; + } + out.close(); +} + +//******************************************************** +// Gather statistics from a PVL input file +//******************************************************* +void PVLIn(const Isis::Filename &filename){ + Pvl pvlFileIn; + pvlFileIn.Read(filename.Name()); + PvlGroup results = pvlFileIn.FindGroup("Results"); + PvlObject::PvlKeywordIterator itr = results.Begin(); + + while (itr != results.End()){ + band.push_back((*itr)[0]); + itr++; + element.push_back((*itr)[0]); + itr++; + validpixels.push_back((*itr)[0]); + itr++; + average.push_back((*itr)[0]); + itr++; + median.push_back((*itr)[0]); + itr++; + stddev.push_back((*itr)[0]); + itr++; + minimum.push_back((*itr)[0]); + itr++; + maximum.push_back((*itr)[0]); + itr++; + } +} + +//******************************************************** +// Gather statistics from a table input file +//******************************************************* +void tableIn(const Isis::Filename & filename){ + ifstream in; + string expanded(filename.Expanded()); + in.open(expanded.c_str(),std::ios::in); + + + if (!in){ + string message = "Error opening " + filename.Expanded(); + throw iException::Message(Isis::iException::Io, message, + _FILEINFO_); + } + + //skip the header (106 bytes) + in.seekg(106); + + + //read it + iString inString; + while (in >> inString){ + band.push_back(inString); + in>> inString; + element.push_back(inString); + in>> inString; + validpixels.push_back(inString); + in >> inString; + average.push_back(inString); + in >> inString; + median.push_back(inString); + in >> inString; + stddev.push_back(inString); + in >> inString; + minimum.push_back(inString); + in >> inString; + maximum.push_back(inString); + //Make sure Standard Deviation is not < 0 when reading in from a table + vector::iterator p; + p = stddev.end() - 1; + if( *p < 0 ) { + *p = 0; + } + } + in.close(); +} + +//******************************************************** +// Compute coefficients such that when we subtract/divide +// using the coefficient the average or median of the +// output image stays the same +void keepSame(int &totalBands,int &rowcol,Mode mode) { + // Loop for each band + for (int iband=1; iband<=totalBands; iband++) { + double sumAverage = 0.0; + double sumValidPixels = 0; + for (int i=0; i &filter, int &filtsize, bool &pause_crop, + int &channel) { + int fsize = (int)filter.size(); + const int left_cut = 4; + const int right_cut = 4; + const int ch_pause_cnt = 3; + const int ch_pause[2][ch_pause_cnt] = {{252,515,778},{247,510,773}}; + const int ch_width[2][ch_pause_cnt] = {{11,11,11},{11,11,11}}; + const string ch_direc[2] = {"RIGHT","LEFT"}; + const int iterations = 10; + vector filtin; + vector filtout; + vector filtorig; + VecFilter vfilter; + + filtorig = filter; + + // To avoid filter ringing, cut out those areas in the data that + // are especially problematic such as the left and right edges and + // at the pause points + for (int i=0; i<=left_cut-1; i++) { + filter[i] = 0.0; + } + for (int i=fsize-1; i>=fsize-right_cut; i--) { + filter[i] = 0.0; + } + + // Zero out the pause point pixels if requested and the input + // image file has a bin mode of 1 + if (pause_crop && fsize == 1024) { + for (int i=0; i fsize-1) i2 = fsize - 1; + for (int j=i1; j<=i2; j++) { + filter[j] = 0.0; + } + } + } + + // Here is the boxfilter - the outer most loop is for the number + // of filter iterations + filtin = filter; + + for (int pass=1; pass<=3; pass++) { + for (int it=1; it<=iterations; it++) { + filtout = vfilter.LowPass(filter,filtsize); + filter = filtout; + } + + // Zero out any columns that are different from the average by more + // than a specific percent + if (pass < 3) { + double frac = .25; + if (pass == 2) frac = .125; + for (int k=0; k frac) { + filtin[k] = 0.0; + } + } + } + filter = filtin; + } + } + + // Perform the highpass by differencing the original from the lowpass + filter = vfilter.HighPass(filtorig,filtout); + + filtin.clear(); + filtout.clear(); + filtorig.clear(); +} diff --git a/isis/src/mro/apps/hicubenorm/hicubenorm.xml b/isis/src/mro/apps/hicubenorm/hicubenorm.xml new file mode 100644 index 0000000000000000000000000000000000000000..8fc49a19cc588bddd5fbce3c0e2124124cdd54af --- /dev/null +++ b/isis/src/mro/apps/hicubenorm/hicubenorm.xml @@ -0,0 +1,401 @@ + + + + + + Normalize columns in a HiRise cube by performing a lowpass/highpass filter + + + +

    + This program was created by adding the HiRise specific code from Eric + Eliason's Cubenorm_Filter script to the cubenorm program. Statistics + are first acquired from an input cube or from a PVL file or table that + was previously generated by the cubenorm program. +

    + A combination lowpass/highpass filter is run on the columnar averages + and median values for the input cube. The filter used to do the lowpass + filtering is a one dimensional filter whose long dimension is an odd + positive value greater than one. +

    + There is an option to create a normalized output cube by applying either + a multiplicative or subtractive correction to the data of the input cube. + The normalization is performed using the updated statistics that have been + filtered. The columnar averages or medians can be chosen as the normalizer. + Each pixel is normalized by subtracting the normalization factor or + by multiplying by the normalization factor. + + + + + Original version (as colnorm) + + + Added options for subtractive corrections + + + Added process by line option and rename to cubenorm + + + Modified unit test to take new options in to account + + + Major reworking and bug fixes + + + Specialized to run using input files. + + + Incorporate UA cubenorm_plus version functionality + + + Changed a single valid pixel's RowCol's Standard Deviation to 0 instead of + Isis:Null. When reading in a table file, all Standard Deviations less + than 0 are considered 0. + + + Removed references to CubeInfo + + + Fixed check in getstats method that sees whether you are processing by + line or column. + + + Changed name to hicubenorm and added Eric Eliason's highpass filter + code from the Cubenorm_Filter Perl script used in the pipeline at + UofA. + + + + + Mars Reconnaissance Orbiter + + + + + ratio + poly + stats + + + + + + + cube + input + + Input cube + + + Use this parameter to select input HiRise file + + + *.cub + + + + + cube + real + output + + No Output file will be created + + + Optional output cube + + + Output file with input columns divided by the column average + + + + + filename + output + + No Output file will be created + + + Optional stats file + + + Statistical output of each column + (band #, column #, valid pixels, average, median, std, min, max) + + + + + string + TABLE + Format type of STATS file (TABLE or PVL) + + Specify the format type of the statistics file, either + use tabular or PVL style format. + + + + + + + + + + + string + CUBE + Input source of statistics to apply to FROM cube + +

    + This option is intended to be used when the statistics come from + a source other than the input cube (default). cubenorm initial + derives all its statistics from the input cube and applies it as + specified by the user in the same run. This works for most + conditions but does not works so well with abrupt changes + in brightness such as craters or poles. +

    +

    + With this option, it is now possible to have the statistics come + a file in a format compatable with the STATS output file. This can + be a TABLE or PVL formatted input file. This allows statistics + from other cubenorm runs to be used as input statistics source. + It also allows intermediate processing on the FROM stats to + apply additional smoothing or culling techniques. +

    +
    + + + + + + + + filename + input + Optional statistics input file source + +

    + This optional file provides the statistics that are applied to the input + FROM file. Its format must be TABLE or PVL and consistant with + the STATS file output format. +

    +

    + If this option is utilized, the statistics gathering step is bypassed. +

    +
    + *.txt +
    + + + + + integer + Size of boxcar filter + + This is the total number of samples in the boxcar. It must be a + positive odd integer. + + + 3 + + + boolean + TRUE + Exclude column averages at the pause points + + This option is used to exclude the column averages (11 pixels) at the pause points + in the image array. This option only applies to images with a bin mode of 1. + + + + + + + string + MEDIAN + + Apply normalization using average or median + + + This option is used to select if column or line is normalized using its average or median + + + + + + + + + string + DIVIDE + + Apply coefficients through subtraction or division + + + This option is used to select select how normalization coefficients are applied, either subtracting or dividing by + the average or median. + + + + + + + + + boolean + TRUE + Preserve the input image median/average + + This option is used to preserve the average/median of the input image. If turned off, the output image + average of the data will be one (unity) for the DIVIDE mode or zero for the SUBTRACT mode. + + + + + + + + + Before and after example of sample column normalization + + The image example shows before and after results from applying the + cubenorm program (MGS/MOC image was used in the example). The + cubenorm program is useful to cosmetically correct the horizontal + stripping pattern seen in push-broom imaging systems such as MGS/MOC + and MRO/HiRISE. +

    + In this example, the MODEOPT=AVERAGE option was chosen to normalize + the sample columns of the image. The MODEOPT=MEDIAN is recommended + for most applications because the normalization results are less + sensitive to scene variations. + + + from=moc.cub to=out.cub modeopt=average + + Perform sample column normalization with the average option + + + + + Input image + + This input image image is a MGS/MOC narrow-angle camera image. + Note the vertical stripping of the push-broom system due to the + varying sensitivity of the detectors in the push-broom array. + + + FROM + + + + + Output image + + The output image has been cosmetically corrected for the vertical stripping pattern + seen in the raw MGS/MOC image input file. + + + TO + + + + + + Example GUI + Screen shot of cubenorm GUI + + + + + + + Example of table output of sample column statistics + + In this example, the user requested tabular output of the sample + column statistics. Tabluated are the band number, sample column number, number of + valid pixels, average, median, standard deviation, minimum, and maximum for each + sample column. Note that the user did not specify a TO parameter so only the + statistics table file is created. Tabulated output is shown below. +

    +Band SampCol ValidPoints  Average  Median  StdDev   Minimum  Maximum
    +   1       1        6016  151.862     153    8.278      101       171
    +   1       2        6016  150.537     152  8.36067      100       169
    +   1       3        6016  149.479     151  8.336186       97       170
    +   1       4        6016  154.333     156  8.63899       97       176
    +   1       5        6016  151.366     153  8.61287      100       172
    +   1       6        6016  152.868     154  8.76716       98       173
    +   1       7        6016  152.182     154  8.71654       97       172
    +   1       8        6016  152.165     154   8.7582       98       173
    +   1       9        6016  151.945     153  8.67002       93       175
    +   1      10        6016   152.28     154  8.64981       97       173
    +   1      11        6016  152.035     153  8.54126       99       171
    +   1      12        6016   152.57     154  8.65598       99       172
    +   1      13        6016  152.515     154  8.6498        94       174
    +   1      14        6016  152.811     154  8.69562       92       174
    +   1      15        6016  152.425     154 8.60978        93       171
    +      
    +
    + + from=moc.cub stats=output.dat statsopt=table + + Create a table file of sample column averages. + + +
    +
    + +
    diff --git a/isis/src/mro/apps/hicubenorm/tsts/Makefile b/isis/src/mro/apps/hicubenorm/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hicubenorm/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hicubenorm/tsts/avgFalse/Makefile b/isis/src/mro/apps/hicubenorm/tsts/avgFalse/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..61c70a6290649266f9ada75d99e2d9a2186212b4 --- /dev/null +++ b/isis/src/mro/apps/hicubenorm/tsts/avgFalse/Makefile @@ -0,0 +1,12 @@ +APPNAME = hicubenorm + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/PSP_001331_2260_RED5_0.cub \ + to= $(OUTPUT)/PSP_001331_2260_RED5_0.avgFalse.cub \ + normalizer = average \ + mode = subtract \ + filter = 5 \ + preserve = true \ + pausecrop = false > /dev/null; diff --git a/isis/src/mro/apps/hicubenorm/tsts/avgTrue/Makefile b/isis/src/mro/apps/hicubenorm/tsts/avgTrue/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..506247d0dfa9f7a2b9d8ed787fde669ccc255adf --- /dev/null +++ b/isis/src/mro/apps/hicubenorm/tsts/avgTrue/Makefile @@ -0,0 +1,12 @@ +APPNAME = hicubenorm + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/PSP_001331_2260_RED5_0.cub \ + to= $(OUTPUT)/PSP_001331_2260_RED5_0.avgTrue.cub \ + normalizer = average \ + mode = subtract \ + filter = 5 \ + preserve = false \ + pausecrop = true > /dev/null; diff --git a/isis/src/mro/apps/hicubenorm/tsts/medFalse/Makefile b/isis/src/mro/apps/hicubenorm/tsts/medFalse/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7a8ff5587e537ab7312493319cea93af7ad77e54 --- /dev/null +++ b/isis/src/mro/apps/hicubenorm/tsts/medFalse/Makefile @@ -0,0 +1,12 @@ +APPNAME = hicubenorm + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/PSP_001331_2260_RED5_0.cub \ + to= $(OUTPUT)/PSP_001331_2260_RED5_0.medFalse.cub \ + normalizer = median \ + mode = subtract \ + filter = 5 \ + preserve = true \ + pausecrop = false > /dev/null; diff --git a/isis/src/mro/apps/hicubenorm/tsts/medTrue/Makefile b/isis/src/mro/apps/hicubenorm/tsts/medTrue/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ee7c398ab826b254984dfe287a19ab0926c285a6 --- /dev/null +++ b/isis/src/mro/apps/hicubenorm/tsts/medTrue/Makefile @@ -0,0 +1,12 @@ +APPNAME = hicubenorm + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/PSP_001331_2260_RED5_0.cub \ + to= $(OUTPUT)/PSP_001331_2260_RED5_0.medTrue.cub \ + normalizer = median \ + mode = subtract \ + filter = 5 \ + preserve = false \ + pausecrop = true > /dev/null; diff --git a/isis/src/mro/apps/hidestripe/Makefile b/isis/src/mro/apps/hidestripe/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hidestripe/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hidestripe/hidestripe.cpp b/isis/src/mro/apps/hidestripe/hidestripe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a4a6926f1c2e74f77d8b4c6ee1eb25a643d7ca71 --- /dev/null +++ b/isis/src/mro/apps/hidestripe/hidestripe.cpp @@ -0,0 +1,273 @@ +#include "Isis.h" + +// system include files go first +#include +#include +#include +#include +#include + +// Isis specific include files go next +#include "LineManager.h" +#include "ProcessByLine.h" +#include "Statistics.h" +#include "iException.h" +#include "Pvl.h" +#include "Table.h" + +using namespace std; +using namespace Isis; + +// These global vectors are used to keep track of info for columns or rows +// of image data. For example, a 100 sample x 200 line x 2 band cube will +// have a vectors of 200 columns when processing in the column direction +// (100 samples x 2 bands). Likewise, the vectors will have 400 rows when +// processing in the line direction (200 lines x 2 bands) +Statistics stats; +static Statistics lineStats[4]; +static vector lines[4]; + +// Size of the cube +static int totalLines; +static int totalSamples; +static unsigned int myIndex = 0; +static int offset; +static int mode = 1; + +// function prototypes +void getStats(Buffer &in); +void fix(Buffer &in, Buffer &out); + +int channel0Phases[] = {252,515,778,1024}; +int channel1Phases[] = {247,510,773,1024}; +static int * phases; +const int num_phases = 4; + +// Main Program +void IsisMain() { + + UserInterface &ui = Application::GetUserInterface(); + Isis::Filename fromFile = ui.GetFilename("FROM"); + + Isis::Cube inputCube; + inputCube.Open(fromFile.Expanded()); + + //Check to make sure we got the cube properly + if (!inputCube.IsOpen()){ + string msg = "Could not open FROM cube" + fromFile.Expanded(); + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + ProcessByLine processByLine; + Cube *icube = processByLine.SetInputCube("FROM"); + totalLines = icube->Lines(); + totalSamples = icube->Samples(); + + //We'll be going through the cube by line, manually differentiating + // between phases + Isis::LineManager lineManager(inputCube); + lineManager.begin(); + + + Table hifix("HiRISE Ancillary"); + int channel = icube->GetGroup("Instrument")["ChannelNumber"]; + + if (channel == 0){ + phases = channel0Phases; + } + else{ + phases = channel1Phases; + } + int binning_mode = icube->GetGroup("Instrument")["Summing"]; + if (binning_mode != 1 && binning_mode != 2){ + iString msg = "You may only use input with binning mode 1 or 2, not"; + msg += binning_mode; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + //Adjust phase breaks based on the binning mode + for (int i = 0 ; i < num_phases ; i++){ + phases[i] /= binning_mode; + } + + //Phases must be able to stretch across the entire cube + if (totalSamples != phases[3]){ + iString required_samples(phases[3]); + iString bin_string(binning_mode); + string msg = "image must have exactly "; + msg += required_samples; + msg += " samples per line for binning mode "; + msg += bin_string; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + //Index starts at 1 and will go up to totalLines. This must be done since + // lines go into different statistics vectors based on their index + myIndex = 1; + processByLine.StartProcess(getStats); + + //This program is trying to find horizontal striping in the image that occurs + // in every other line, but at runtime we do not know whether that striping + // occurs on the odd numbered lines (1, 3, 5, etc.) or the even numbered + // ones (2, 4, 6, etc.). The below algorithm determines which of these is the + // case. + + string parity = ui.GetString ("PARITY"); + if (parity == "EVEN"){ + offset = 1; + } + else if (parity == "ODD"){ + offset = 0; + } + else{ + //PRECONDITION: getStats must have been run + long double maxDiff = 0; + int maxDiffIndex = 0; + for (int i = 0 ; i < num_phases ; i++){ + long double thisDiff; + thisDiff = lineStats[i].Average() - stats.Average(); + if (thisDiff < 0){ + thisDiff *= -1; + } + if (thisDiff > maxDiff){ + maxDiff = thisDiff; + maxDiffIndex = i; + } + } + if (maxDiffIndex == 1 || maxDiffIndex == 3) + {offset = 1;} + else + {offset = 0;} + } + + //Again we must reset the index, because we apply corrections only on every + // other line and the fix processing function has no concept of where it is + // in the cube. + myIndex = 1; + + mode = (ui.GetString("CORRECTION") == "MULTIPLY"); + + processByLine.SetOutputCube("TO"); + processByLine.StartProcess(fix); + processByLine.EndProcess(); + +} + +//********************************************************** +// Get statistics on a line of pixels and break it into phases +//********************************************************** + //add all the data to the stats statistics object. When we compare which of + // the lines (%4 = 0, %4 = 1, %4 = 2, %4 = 3) is the furtherest from the + // total average, we use stats for the "total average" +void getStats(Buffer &in) +{ +stats.AddData(in.DoubleBuffer(),in.size()); + + //Phase 1 processing + { + Buffer proc(phases[0], 1, 1, in.PixelType()); + for (int quad1 = 0 ; quad1 < phases[0] ; quad1++) + {proc[quad1] = in[quad1];} + Statistics temp; + temp.AddData(proc.DoubleBuffer(), proc.size()); + lines[0].push_back(temp); + stats.AddData(proc.DoubleBuffer(), proc.size()); + lineStats[0].AddData(proc.DoubleBuffer(), proc.size()); + } + + //Phase 2 processing + { + Buffer proc(phases[1] - phases[0], 1, 1, in.PixelType()); + for (int quad2 = phases[0] ; quad2 < phases[1] ; quad2++) + {proc[quad2 - phases[0]] = in[quad2];} + Statistics temp; + temp.AddData(proc.DoubleBuffer(), proc.size()); + lines[1].push_back(temp); + stats.AddData(proc.DoubleBuffer(), proc.size()); + lineStats[1].AddData(proc.DoubleBuffer(), proc.size()); + } + + //Phase 3 processing + { + Buffer proc(phases[2] - phases[1], 1, 1, in.PixelType()); + for (int quad3 = phases[1] ; quad3 < phases[2] ; quad3++) + {proc[quad3 - phases[1]] = in[quad3];} + Statistics temp; + temp.AddData(proc.DoubleBuffer(), proc.size()); + lines[2].push_back(temp); + stats.AddData(proc.DoubleBuffer(), proc.size()); + lineStats[2].AddData(proc.DoubleBuffer(), proc.size()); + } + + //Phase 4 processing + { + Buffer proc(phases[3] - phases[2], 1, 1, in.PixelType()); + for (int quad4 = phases[2] ; quad4 < phases[3] ; quad4++) + {proc[quad4 - phases[2]] = in[quad4];} + Statistics temp; + temp.AddData(proc.DoubleBuffer(), proc.size()); + lines[3].push_back(temp); + stats.AddData(proc.DoubleBuffer(), proc.size()); + lineStats[3].AddData(proc.DoubleBuffer(), proc.size()); + } + +myIndex++; +} + +// Apply coefficients based on mode +void fix(Buffer &in, Buffer &out) +{ +//If this is an "off" line, no correction needs to be applied +if (myIndex % 2 == (unsigned int)offset) + { + //This is an "off" line, so just copy the data from the input + for (int i = 0 ; i < in.size() ; i++) + {out[i] = in[i]; } + } +else + { + //This is not an "off" line, so apply the correction + for (int i=0; i + + + Corrects a known striping pattern in HiRISE images. + + + +

    + In mixed mode HiRISE images, there is a tendency for every other line in the + ccd with the lower binning mode to be significantly darker or lighter than + normal image data would suggest. This program attempts to correct that + problem. 2 passes through a cube are necessary to perform the correction. The + first pass gathers information on each line of the cube to determine if the + striping phenomenon occurs in odd numbered lines or in even numbered lines, and + also gathers information to perform the actual correction. +

    + The second pass through the data performs the actual correction, of which there + are two different types. The default, an additive correction, is of the following + form for each pixel + +
    +    					     
    +                                         ((Line[i-1]) + Line[i+1])
    +                Pixel[i,j] - Line[i] +   --------------------------
    +                                                      2
    +    
    + + The other correction, a multiplicative correction of a similar style, is of + the form + +
    +                Pixel        ((Line[i-1]) + Line[i+1])
    +               -------   *  ---------------------------
    +               Line[i]                    2
    +    
    +

    + It should finally be noted that the striping pattern has been observed to + be most prevalent in a certain quardrant of the image, though that phase + is not the same for all images. In order to address this irregularitiy, the + line averages shown above are not for the entire line, but only for the + quarter of the line in which sample i exists. +

    +

    + Caution should be taken when running hidestripe: it should only be run on + images where different CCDs are run at different binning modes. Of those, + only channels that are not used in the highest binning mode of the image + should be corrected. For example, if an image has binning modes 1, 2, and 4 + the CCDs with modes 1 and 2 may be hidestripe'd, but in an image that is + only binned in modes 1 and 2, the bin 1 CCDs are the only ones that need + the hidestripe correction. +

    +
    + + + Mars Reconnaissance Orbiter + + + + + Original version + + + Changed to calculate phase limits differently for Channel 1 + + + Added capability to process bin 2 data + + + Allowed users to specify odd or even correction + + + Removed references to CubeInfo + + + + + + + cube + input + + Single hirise channel in cub form + + + input channel file. The file must have a number of samples divisible + by four so that it may be equally divided into phases. Also, the + image should exibit the horizontal striping problem addressed above. + Otherwise, this program will do an unwanted normalization. + + + *.cub + + + + + cube + output + + Output cube to contain cub with correction. + + + This image will have the hidestripe correction applied to it. + + + *.cub + + + + + + + string + Type of correction to apply + + A correction that is either multiplicative or additive in nature. + For more specific information on the nature of the correction, see + the general program description + + ADD + + + + + + + + + + string + Specify line stripes as an even or odd pattern + + AUTO + + + + + + + + + + + + + + + Additive correction + + This example shows the default additive correction applied to a binned + 1 image in an image that is mixed and includes binning modes 1 and 4 + + + + from=HiRISE/cubs/RED5_bin1.cub to=HIRISE/cubs/RED5_bin1_corrected.cub + + + Note that the defaults are not changed, and thus the additive + correction is applied. + + + + + + Input image before hidestripe + + The image before the correction is applied. Note the horizontal + stripes. + + + FROM + + + + + + Output image after hidestripe + + The same image has now been smoothed such that the horizontal + stripes are removed. + + + TO + + + + + + + Example Gui + + Parameters set to perform additive correction. No options have + been changed from their defaults (though required TO/FROM have). + + + + + + + + +
    diff --git a/isis/src/mro/apps/hidestripe/tsts/Makefile b/isis/src/mro/apps/hidestripe/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hidestripe/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hidestripe/tsts/default/Makefile b/isis/src/mro/apps/hidestripe/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9f1288631b24324cbc4d1a496d2dfd74f5a15ba1 --- /dev/null +++ b/isis/src/mro/apps/hidestripe/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = hidestripe + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/AEB_000001_0000_BG12_0.cub \ + to=$(OUTPUT)/hidestripeTruth.cub > /dev/null; diff --git a/isis/src/mro/apps/hiequal/Makefile b/isis/src/mro/apps/hiequal/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hiequal/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hiequal/assets/images/after.jpg b/isis/src/mro/apps/hiequal/assets/images/after.jpg new file mode 100755 index 0000000000000000000000000000000000000000..10f48779843bd008cc9f85e19d1d5204921c3b64 Binary files /dev/null and b/isis/src/mro/apps/hiequal/assets/images/after.jpg differ diff --git a/isis/src/mro/apps/hiequal/assets/images/before.jpg b/isis/src/mro/apps/hiequal/assets/images/before.jpg new file mode 100755 index 0000000000000000000000000000000000000000..3b8aeb59a93e060c3b916066b9a73b58cd118706 Binary files /dev/null and b/isis/src/mro/apps/hiequal/assets/images/before.jpg differ diff --git a/isis/src/mro/apps/hiequal/assets/thumbs/after.jpg b/isis/src/mro/apps/hiequal/assets/thumbs/after.jpg new file mode 100755 index 0000000000000000000000000000000000000000..12b03dd4d93fd422993a14ee4c6d32229a12afa4 Binary files /dev/null and b/isis/src/mro/apps/hiequal/assets/thumbs/after.jpg differ diff --git a/isis/src/mro/apps/hiequal/assets/thumbs/before.jpg b/isis/src/mro/apps/hiequal/assets/thumbs/before.jpg new file mode 100755 index 0000000000000000000000000000000000000000..9d0a101c482cb832214cd4256429777f3839c2a4 Binary files /dev/null and b/isis/src/mro/apps/hiequal/assets/thumbs/before.jpg differ diff --git a/isis/src/mro/apps/hiequal/hiequal.cpp b/isis/src/mro/apps/hiequal/hiequal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b314d204c19b9248a7ee174efee001ee9f7efea8 --- /dev/null +++ b/isis/src/mro/apps/hiequal/hiequal.cpp @@ -0,0 +1,359 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "FileList.h" +#include "iString.h" +#include "Statistics.h" +#include "OverlapNormalization.h" +#include "CubeAttribute.h" + +using namespace Isis; + +void GatherStatistics(Buffer &in); +void Apply(Buffer &in, Buffer &out); +void ErrorCheck(FileList &imageList, FileList &outList); + +OverlapNormalization *g_oNorm; +Statistics g_s, g_sl, g_sr; +std::vector g_allStats, g_leftStats, g_rightStats; +int g_imageNum; + +void IsisMain() { + + // Get the list of cubes to process + FileList imageList; + UserInterface &ui = Application::GetUserInterface(); + imageList.Read(ui.GetFilename("FROMLIST")); + + // Read to list if one was entered + FileList outList; + if (ui.WasEntered("TOLIST")) { + outList.Read(ui.GetFilename("TOLIST")); + } + + // Check for user input errors and return the file list sorted by CCD numbers + ErrorCheck(imageList, outList); + + // Adds statistics for whole and side regions of every cube + for (int img=0; img<(int)imageList.size(); img++) { + g_s.Reset(); + g_sl.Reset(); + g_sr.Reset(); + + iString maxCube ((int)imageList.size()); + iString curCube (img+1); + ProcessByLine p; + p.Progress()->SetText("Gathering Statistics for Cube " + + curCube + " of " + maxCube); + CubeAttributeInput att; + const std::string inp = imageList[img]; + p.SetInputCube(inp, att); + p.StartProcess(GatherStatistics); + p.EndProcess(); + + g_allStats.push_back(g_s); + g_leftStats.push_back(g_sl); + g_rightStats.push_back(g_sr); + } + + // Initialize the object that will calculate the gains and offsets + g_oNorm = new OverlapNormalization(g_allStats); + + // Add the known overlaps between two cubes, and apply a weight to each + // overlap equal the number of pixels in the overlapping area + for (int i=0; i<(int)imageList.size()-1; i++) { + int j = i+1; + g_oNorm->AddOverlap(g_rightStats[i], i, g_leftStats[j], j, + g_rightStats[i].ValidPixels()); + } + + // Read in and then set the holdlist + FileList holdList; + holdList.Read(ui.GetFilename("HOLD")); + + for (unsigned i=0; iAddHold(index); + } + } + } + + // Attempt to solve the least squares equation + g_oNorm->Solve(OverlapNormalization::Both); + + // Apply correction to the cubes if desired + bool applyopt = ui.GetBoolean("APPLY"); + if (applyopt) { + // Loop through correcting the gains and offsets by line for every cube + for (int img=0; img<(int)imageList.size(); img++) { + g_imageNum = img; + ProcessByLine p; + iString max_cube ((int)imageList.size()); + iString cur_cube (img+1); + p.Progress()->SetText("Equalizing Cube " + cur_cube + " of " + max_cube); + CubeAttributeInput att; + const std::string inp = imageList[img]; + Cube *icube = p.SetInputCube(inp, att); + Filename file = imageList[img]; + + // Establish the output file depending upon whether or not a to list + // was entered + std::string out; + if (ui.WasEntered("TOLIST")) { + out = outList[img]; + } + else { + Filename file = imageList[img]; + out = file.Path() + "/" + file.Basename() + ".equ." + file.Extension(); + } + + CubeAttributeOutput outAtt; + p.SetOutputCube(out,outAtt,icube->Samples(),icube->Lines(),icube->Bands()); + p.StartProcess(Apply); + p.EndProcess(); + } + } + + // Setup the output text file if the user requested one + if (ui.WasEntered("OUTSTATS")) { + std::string out = Filename(ui.GetFilename("OUTSTATS")).Expanded(); + std::ofstream os; + os.open(out.c_str(),std::ios::app); + + // Get statistics for each cube with PVL + Pvl p; + PvlObject equ("EqualizationInformation"); + for (int img=0; img<(int)imageList.size(); img++) { + std::string cur = imageList[img]; + PvlGroup a("Adjustment"); + a += PvlKeyword("FileName", cur); + a += PvlKeyword("Average", g_oNorm->Average(img)); + a += PvlKeyword("Base", g_oNorm->Offset(img)); + a += PvlKeyword("Multiplier", g_oNorm->Gain(img)); + equ.AddGroup(a); + } + p.AddObject(equ); + + os << p << std::endl; + } + + PvlGroup results ("Results"); + for (int img=0; img<(int)imageList.size(); img++) { + results += PvlKeyword("FileName", imageList[img]); + results += PvlKeyword("Average", g_oNorm->Average(img)); + results += PvlKeyword("Base", g_oNorm->Offset(img)); + results += PvlKeyword("Multiplier", g_oNorm->Gain(img)); + } + Application::Log(results); + + // Clean-up for batch list runs + delete g_oNorm; + g_oNorm = NULL; + + g_allStats.clear(); + g_leftStats.clear(); + g_rightStats.clear(); +} + +// Gather statistics for the cube +void GatherStatistics(Buffer &in) { + // Number of samples per line that intersect with the next and the + // previous images + unsigned int intersect; + + // Check if samples equal 682 or 683 + if (in.size() == 682 || in.size() == 683) { + intersect = 18; + } + // If not the above case, then we perform an algorithm to account for binning + else { + // Number of intersecting samples is directly related to total + // number of samples in the line, with 2048 being the maximum possible + unsigned int div = 2048 / in.size(); + intersect = 48 / div; + } + + g_s.AddData(&in[0], in.size()); + g_sl.AddData(&in[0], intersect); + g_sr.AddData(&in[in.size()-intersect], intersect); +} + +// Apply equalization to the cube +void Apply(Buffer &in, Buffer &out) { + for (int i=0; iEvaluate(in[i],g_imageNum); + } +} + +// Checks for user input errors where present and attempts to correct them +// where possible +void ErrorCheck(FileList &imageList, FileList &outList) { + UserInterface &ui = Application::GetUserInterface(); + + // Ensures number of images is within bound + if (imageList.size() < 2) { + std::string msg = "The input file [" + ui.GetFilename("FROMLIST") + + "] must contain at least 2 file names"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + if (imageList.size() > 10) { + std::string msg = "The input file [" + ui.GetFilename("FROMLIST") + + "] cannot contain more than 10 file names"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Make sure the user enters a "OUTSTATS" file if the apply option is not selected + if (!ui.GetBoolean("APPLY")) { + if (!ui.WasEntered("OUTSTATS")) { + std::string msg = "If the apply option is not selected, you must enter a"; + msg += " OUTSTATS file"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + // Reference for converting a CPMM number to a CCD number + const int cpmm2ccd[] = {0,1,2,3,12,4,10,11,5,13,6,7,8,9}; + + // Place ccd in vector, try-catch opening cubes + std::vector ccds; + for (int i=0; i<(int)imageList.size(); i++) { + try { + Cube cube1; + cube1.Open(imageList[i]); + PvlGroup &from1Instrument = cube1.GetGroup("INSTRUMENT"); + int cpmmNumber = from1Instrument["CpmmNumber"]; + ccds.push_back(cpmm2ccd[cpmmNumber]); + } + // If any part of the above didn't work, we can safely assume the current + // file is not a valid HiRise image + catch (...) { + std::string msg = "The [" + imageList[i] + + "] file is not a valid HiRise image"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + // Error check TO LIST if was entered + if (ui.WasEntered("TOLIST")) { + + // Make sure each file in the tolist matches a file in the fromlist + if (outList.size() != imageList.size()) { + std::string msg = "Each input file in the FROM LIST must have a "; + msg += "corresponding output file in the TO LIST."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Make sure that all output files do not have the same names as their + // corresponding input files + for (unsigned i = 0; i < outList.size(); i++) { + if (outList[i].compare(imageList[i]) == 0) { + std::string msg = "The TO LIST file [" + outList[i] + + "] has the same name as its corresponding FROM LIST file."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + } + + // Insertion sorts a list of filenames by their CCD numbers + for (int i=1; i<(int)imageList.size(); i++) { + int ccd1 = ccds[i]; + std::string temp = imageList[i]; + + int j=i-1; + int ccd2 = ccds[j]; + + while (j >= 0 && ccd2 > ccd1) { + imageList[j+1] = imageList[j]; + ccds[j+1] = ccds[j]; + if (ui.WasEntered("TOLIST")) outList[j+1] = outList[j]; + + j--; + if (j >= 0) { + ccd2 = ccds[j]; + } + } + imageList[j+1] = temp; + ccds[j+1] = ccd1; + if (ui.WasEntered("TOLIST")) outList[j+1] = outList[i]; + } + + // Ensures BG and IR only have two files + if (ccds[0] == 10 || ccds[0] == 11) { + if (imageList.size() != 2) { + std::string msg = "A list of IR images must have exactly two "; + msg += "file names"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + if (ccds[0] == 12 || ccds[0] == 13) { + if (imageList.size() != 2) { + std::string msg = "A list of BG images must have exactly two "; + msg += "file names"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + // Error checking to ensure CCDID types match and the filenames follow a + // strict sequence + for (int i=0; i<(int)imageList.size()-1; i++) { + int ccd1 = ccds[i]; + + // CCDID type + int id1; + // RED + if (ccd1 >= 0 && ccd1 <= 9) id1 = 0; + // IR + else if (ccd1 == 10 || ccd1 == 11) id1 = 1; + // BG + else id1 = 2; + + int ccd2 = ccds[i+1]; + + int id2; + if (ccd2 >= 0 && ccd2 <= 9) id2 = 0; + else if (ccd2 == 10 || ccd2 == 11) id2 = 1; + else id2 = 2; + + // CCDID types don't match + if (id1 != id2) { + std::string msg = "The list of input images must be all RED, all IR, or "; + msg += "all BG"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Doesn't follow strict sequence for RED CCDID + if (ccd2 != ccd1+1) { + std::string msg = "The list of input images do not numerically follow "; + msg += "one another"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + + // Make sure each file in the holdlist matches a file in the fromlist + FileList holdList; + holdList.Read(ui.GetFilename("HOLD")); + if (holdList.size() > imageList.size()) { + std::string msg = "The list of identifiers to be held must be less than or "; + msg += "equal to the total number of identitifers."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + for (int i=0; i<(int)holdList.size(); i++) { + bool matched = false; + for (int j=0; j<(int)imageList.size(); j++) { + if (holdList[i] == imageList[j]) { + matched = true; + break; + } + } + if (!matched) { + std::string msg = "The hold list file [" + holdList[i] + + "] does not match a file in the from list"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } +} + diff --git a/isis/src/mro/apps/hiequal/hiequal.xml b/isis/src/mro/apps/hiequal/hiequal.xml new file mode 100644 index 0000000000000000000000000000000000000000..1182eb6b628ad948a72b643efa5448cede0cb232 --- /dev/null +++ b/isis/src/mro/apps/hiequal/hiequal.xml @@ -0,0 +1,220 @@ + + + + + + Tonematches a set of HiRISE cubes prior to mosaicking + + + +

    + This program can be used to tonematch or equalize the brightness and + contrast of the input HiRISE cubes prior to mosaicking. The set of N + cubes inputed must be all Red, all Blue-Green, or all Infared, where N + is an integer 2-10 for RED sets and exactly 2 both for IR and BG sets. + The order the cube names are provided in does not matter, but the cubes + must all follow a linear sequence without skipping cubes all the same + (i.e., the user cannot run this application on cubes RED1-RED3 and RED5 + without also providing the program RED4). Statistics are gathered by + line, taking into account the bin number of the cube (automatically + derived from the number of samples in the line). The statistics are + used in an IntersectionStatistics object's least squares solution to + determine multiplicative and additive corrections to each image. The + user has the option to stop the processing after the statistics and + corrective factors have been computed for examination. Alternatively, + the processing can continue and the corrective factors will be applied + to each image (by making sure the APPLY checkbox is ticked). The actual + equation to be used for each cube is: +

    +            newdn(s,l)   =   (olddn(s,l) - avg()) * MULT() + avg() + BASE()
    +        
    where +
    +            s = sample index
    +            l = line index 
    +          
    +

    + +

    + The BASE and MULT values are computed independently for each image, therefore we have two + least squares computations with M unknowns, where M is the number of + cubes to be equalized. The intersections, O, between all the cubes are + computed and O < M should hold in all cases. In order for the + least squares equation to be solved, there must be at least as many + knowns as unknowns. Therefore, you must hold one or more cubes to + alleviate this problem. Holding a cube forces MULT and BASE to 1.0 + and 0.0 respectively. +

    + +

    + If the APPLY option is selected, the equalized cubes will be named the same as the input cubes + with the addition of a '.equ' prior to the '.cub' extension. +

    +
    + + + Mars Reconnaissance Orbiter + + + + + equalizer + + + + + + Original version + + + Fixed test data for compatibility across all systems and improved + documentation for clarity + + + Changed parameter TO to OUTSTATS and added parameter TOLIST allowing the + user to specify the location of output files. Output files are now placed + into the directory of the input cube when TOLIST is on the default + setting. Statistic gathering results are now placed in the print file. + + + + + + + filename + input + + List of cubes to equalize + + + A list of HiRISE cubes to equalize. The types (i.e., RED, BG, IR) + must match in order to do the equalization. + + + + + filename + input + + List of filenames to hold + + + List of cubes that are to be held in the equalization. + An additive and a multiplicative factor of 0 and 1 will be applied + to all cubes that were held. All cubes listed in this file must + also be contained in FROMLIST. + + None + + *.txt *.lis *.lst + + + + + filename + input + + The list of the equalized cubes to be created + + + This list of output files should contain a file to correspond to each + input file. The output files will be written to the exact location + with the exact name specified unless it happens to be identical to + that of its corresponding input file, in which case an error will be + thrown. If this file is not specified, but the APPLY option is + still selected, the output cubes will be placed in the directory of + its input file, and named the same with the exception of ".equ" + extension (e.g. "foobar.cub" becomes foobar.equ.cub"). + + Automatic + + *.txt *.lis *.lst + + + + + filename + output + + Text file containing thorough equalization related statistics + + + This file will contain the statistics of all of the intersecting + areas along with the computed equalizing factors + (BASE and MULT). Specifying this output file is optional. + + None + + *.txt *.pvl *.lis *.lst + + + + + boolean + + Apply correction to the cubes + + + This option allows the user to decide whether they want to do the + equalization calculations only, or do the calculations and apply the + correction to the images. If the APPLY option is not selected, you must + specify a TO file. If it is selected you can still optionally specify a TO file and + the MULT/BASE values will be applied to each input cube. The output cubes + will be named the same with the exception of ".equ" extension (e.g. "foobar.cub" + becomes "foobar.equ.cub"). + + + TOLIST + + TRUE + + + + + + + RED Images Equalized + + This example shows the use of the hiequal application with default + settings (i.e., no TO file with APPLY set true). For demonstrative + purposes, the first image (RED0) has had its pixel values multiplied by + .8 with the "fx" application, and the two images have been mosaicked + together with "hiccdstitch". + + + fromlist= ../RedList.lst holdlist= ../RedHoldList.lst + + + Specify a list of 2 adjacent RED images to equalize along with a + holding list of one of the images (RED1) that enables the necessary + calculations to be performed. All other options are at default + values. + + + + + + Mosaic of the input images for hiequal + + This is a small section of the two input images for this example + mosaicked together, showing part of the intersection line prior to + tonematching. + + + FROMLIST + + + + + + Mosaic of the output images for hiequal + + The same section of the equalized output images mosaicked + together after the tonematching has been applied. + + + + + + + +
    diff --git a/isis/src/mro/apps/hiequal/tsts/Makefile b/isis/src/mro/apps/hiequal/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hiequal/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hiequal/tsts/default/Makefile b/isis/src/mro/apps/hiequal/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e17e1c08202c47d97f2cab8c7d95fcda2413cb9b --- /dev/null +++ b/isis/src/mro/apps/hiequal/tsts/default/Makefile @@ -0,0 +1,19 @@ +APPNAME = hiequal + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) -1 $(INPUT)/*.cub > fromList.lst; + $(LS) $(INPUT)/RED2.cub > holdList.lst; + $(APPNAME) fromlist=fromList.lst \ + holdlist=holdList.lst \ + tolist=$(INPUT)/toList.lst \ + outstats=$(OUTPUT)/stat.pvl \ + > /dev/null; + + $(MV) RED0.equ.cub $(OUTPUT)/hiequalTruth1.cub; + $(MV) RED1.equ.cub $(OUTPUT)/hiequalTruth2.cub; + $(MV) RED2.equ.cub $(OUTPUT)/hiequalTruth3.cub; + + $(RM) fromList.lst holdList.lst \ + > /dev/null; diff --git a/isis/src/mro/apps/hifringe/Makefile b/isis/src/mro/apps/hifringe/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hifringe/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hifringe/assets/red5.pvl b/isis/src/mro/apps/hifringe/assets/red5.pvl new file mode 100644 index 0000000000000000000000000000000000000000..ec557c1b79a2d5ee7b67294ee27395c9ba6072db --- /dev/null +++ b/isis/src/mro/apps/hifringe/assets/red5.pvl @@ -0,0 +1,16 @@ +Group = "Left Side" + ValidPixels = 2604 + Mean = 7050.6720430108 + Std = 216.20715611304 + Minimum = 6483.0 + Maximum = 7286.0 +End_Group + +Group = "Right Side" + ValidPixels = 2604 + Mean = 6888.8667434716 + Std = 22.370305423197 + Minimum = 6818.0 + Maximum = 6961.0 +End_Group +End \ No newline at end of file diff --git a/isis/src/mro/apps/hifringe/hifringe.cpp b/isis/src/mro/apps/hifringe/hifringe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..006d2c90114edd2d56e9419dac0c177945f99b2f --- /dev/null +++ b/isis/src/mro/apps/hifringe/hifringe.cpp @@ -0,0 +1,219 @@ +/* +$Id: hifringe.cpp,v 1.6 2008/05/14 21:07:24 slambright Exp $ + +Copyright (C) 2005, 2006 Arizona Board of Regents on behalf of the +Planetary Image Research Laboratory, Lunar and Planetary Laboratory at +the University of Arizona. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License, version 2.1, +as published by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +#include "Isis.h" + +#include + +#include "Process.h" +#include "Statistics.h" +#include "LineManager.h" +#include "Filename.h" +#include "iString.h" + +using namespace std; +using namespace Isis; + + +void pvlOut(Statistics stats1, Statistics stats2, string name, int start, + int end, PvlObject * one, PvlObject * two); + +static const char* const + ID = "PIRL::hifringe ($Revision: 1.6 $ $Date: 2008/05/14 21:07:24 $)"; + +void IsisMain() { + UserInterface &ui = Application::GetUserInterface(); + Isis::Filename fromFile = ui.GetFilename("FROM"); + + Isis::Cube inputCube; + inputCube.Open(fromFile.Expanded()); + + //Check to make sure we got the cube properly + if (!inputCube.IsOpen()){ + string msg = "Could not open FROM cube" + fromFile.Expanded(); + throw iException::Message(iException::User,msg,_FILEINFO_); + } + Process p; + Cube *icube = p.SetInputCube("FROM"); + + int totalSamples = icube->Samples(); + int totalLines = icube->Lines(); + + Isis::LineManager lineManager(inputCube); + lineManager.begin(); + + int leftFringe, rightFringe; + int binningMode = icube->GetGroup("Instrument")["Summing"]; + + //determine the edges between which no statistics should be gathered + leftFringe = 48 / binningMode; + rightFringe = totalSamples - leftFringe; + + + int numSections = ui.GetInteger("SECTIONS"); + if (numSections > 9){ + string msg = "You may have no more than 9 sections per side"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + int sectionLength = 0; + if (!ui.WasEntered("LINESIZE")){ //User didn't enter number of lines + if (numSections == 0 ){ + sectionLength = 0; + } + else{ + sectionLength = totalLines / numSections; + } + } + else{ + sectionLength = ui.GetInteger("LINESIZE"); + if ((sectionLength * numSections > totalLines) || sectionLength < 1){ + sectionLength = totalLines / numSections; + } + } + + Statistics sections[numSections][2]; + Statistics leftTotal, rightTotal; + int sectionStarts[numSections]; + sectionStarts[0] = 0; + for (int i = 1 ; i < numSections - 1 ; i ++){ + sectionStarts[i] = (totalLines / numSections) * i; + } + if (numSections > 0){ + sectionStarts[numSections -1] = totalLines - sectionLength; + } + + int currentSection = 0; + Buffer leftFringeBuf(leftFringe, 1, 1, lineManager.PixelType()); + Buffer rightFringeBuf(leftFringe, 1, 1, lineManager.PixelType()); + + //Walk down the cube + for (int lineCount = 0 ; lineCount < totalLines ; lineCount++){ + inputCube.Read(lineManager); + //Read the edges into the fringe buffers + for (int i = 0 ; i < leftFringe ; i++){ + leftFringeBuf[i] = lineManager[i]; + } + for (int i = rightFringe ; i < totalSamples ; i++){ + rightFringeBuf[i - rightFringe] = lineManager[i]; + } + + //No matter what, add the fringe buffers to the totals for that side + leftTotal.AddData(leftFringeBuf.DoubleBuffer(), leftFringeBuf.size()); + rightTotal.AddData(rightFringeBuf.DoubleBuffer(), rightFringeBuf.size()); + + if (numSections == 0){ + continue; + } + //Index is not too large for this fringe section + if (lineCount < sectionStarts[currentSection] + sectionLength){ + //Index is not too small for this fringe section + if (lineCount >= sectionStarts[currentSection]){ + sections[currentSection][0].AddData(leftFringeBuf.DoubleBuffer(), + leftFringeBuf.size()); + sections[currentSection][1].AddData(rightFringeBuf.DoubleBuffer(), + rightFringeBuf.size()); + } + } + else{ + currentSection++; + //Since sections may butt up against each other, it is possible that + // we have to add this data to the next section. + if (lineCount >= sectionStarts[currentSection]){ + sections[currentSection][0].AddData(leftFringeBuf.DoubleBuffer(), + leftFringeBuf.size()); + sections[currentSection][1].AddData(rightFringeBuf.DoubleBuffer(), + rightFringeBuf.size()); + } + } + } + + // Write the results to the output file if the user specified one +PvlObject leftSide("LeftSide"), rightSide("RightSide"); + for (int i = 0 ; i < numSections ; i++){ + iString sectionNumber = i + 1; + string sectionName = "Section" + sectionNumber; + pvlOut(sections[i][0], //Stats to add to the left Object + sections[i][1], //Stats to add to the right Object + sectionName, //Name for the new groups + sectionStarts[i], //start line + sectionStarts[i] + sectionLength, //end line + &leftSide, //Object to add left group to + &rightSide //Object to add right group to + ); + } + pvlOut(leftTotal, //Stats to add to the left Object + rightTotal, //Stats to add to the right Object + "Total", //Name for the new groups + 0, //start line + totalLines, //end line + &leftSide, //Object to add left group to + &rightSide //Object to add right group to + ); + Pvl outputPvl; + PvlGroup sourceInfo("SourceInfo"); + + sourceInfo += PvlKeyword("From", fromFile.Expanded()); + sourceInfo += icube->GetGroup("Archive")["ProductId"]; + outputPvl.AddGroup(sourceInfo); + if (numSections > 0){ + outputPvl.AddObject(leftSide); + outputPvl.AddObject(rightSide); + } + else{ + PvlGroup leftGroup = leftSide.FindGroup("Total"); + PvlGroup rightGroup = rightSide.FindGroup("Total"); + leftGroup.SetName("LeftSide"); + rightGroup.SetName("RightSide"); + outputPvl.AddGroup(leftGroup); + outputPvl.AddGroup(rightGroup); + } + outputPvl.Write(ui.GetFilename("TO")); +} + +void pvlOut(Statistics stats1, Statistics stats2, string name, int start, + int end, PvlObject *one, PvlObject *two){ + PvlGroup left(name); + left += PvlKeyword ("StartLine", start + 1); + left += PvlKeyword ("EndLine", end); + left += PvlKeyword ("TotalPixels", stats1.TotalPixels()); + left += PvlKeyword("ValidPixels",stats1.ValidPixels()); + if (stats1.ValidPixels() > 0) { + left += PvlKeyword("Mean", stats1.Average()); + left += PvlKeyword("StandardDeviation", stats1.StandardDeviation()); + left += PvlKeyword("Minimum", stats1.Minimum()); + left += PvlKeyword("Maximum", stats1.Maximum()); + } + one->AddGroup(left); + + PvlGroup right(name); + right += PvlKeyword ("StartLine", start + 1); + right += PvlKeyword ("EndLine", end); + right += PvlKeyword ("TotalPixels", stats2.TotalPixels()); + right += PvlKeyword("ValidPixels",stats2.ValidPixels()); + if (stats2.ValidPixels() > 0) { + right += PvlKeyword("Mean", stats2.Average()); + right += PvlKeyword("StandardDeviation", stats2.StandardDeviation()); + right += PvlKeyword("Minimum", stats2.Minimum()); + right += PvlKeyword("Maximum", stats2.Maximum()); + } + two->AddGroup(right); +} diff --git a/isis/src/mro/apps/hifringe/hifringe.xml b/isis/src/mro/apps/hifringe/hifringe.xml new file mode 100644 index 0000000000000000000000000000000000000000..726cf7f9d5cc6509a4207cb7cb5c6432ed381912 --- /dev/null +++ b/isis/src/mro/apps/hifringe/hifringe.xml @@ -0,0 +1,146 @@ + + + + Gathers statistics on the first and last several samples of a channel + + + + Gathers several statistics on the "fringe" of a channel file. These + statistics are then output to a pvl file that can be viewed to see if several + channel files, based upon those statistics, are suitable for stitching + together. The number of lines that are gathered is a function of the binning + mode of the channel file being input as follows: +
    +  binning mode 1          48 rightmost and 48 leftmost samples gathered
    +  binning mode 2          24 rightmost and 24 leftmost samples gathered
    +  binning mode 3          16 rightmost and 16 leftmost samples gathered
    +  binning mode 4          12 rightmost and 12 leftmost samples gathered
    +  binning mode 8           6 rightmost and  6 leftmost samples gathered
    +  
    + + The following statistics are gathered: +
    +  Valid Pixels
    +  Standard Deviation
    +  Average
    +  Minimum
    +  Maximum
    +  
    +
    + + + Mars Reconnaissance Orbiter + + + + + + Original version + + + Added the ability to sample multiple sections + + + Removed references to CubeInfo + + + + + + stats + + + + + + + cube + input + + Single hirise channel in cub form + + + input channel file. Although this program is meant to be used solely + for stitching channel files together, it could be used on any hirise + image at all. + + + *.cub + + + + + filename + output + + Output file to contain statistics + + + This pvl file will contain two groups. The first group will be + statistics for the leftmost samples, and the second group will be + statistics for the rightmost samples. + + + *.pvl + + + + + + + integer + Number of sections + 5 + + This is the number of sub-areas that are extracted from each side of + the cube. They will be spaced in such a way that there will be a + section starting at the
    l/n
    th line where
    l
    is + the total number of lines in the cube and
    n
    is the number + of sections specified. +
    +
    + + + integer + Number of lines in each section + complete coverage + + This is the number of lines in each section. If the user + does not enter anything, or specifies an invalid number + of lines (i.e. more lines than exist in the cube), the + sections will be stretched to cover as many lines of the + cube as possible + + +
    + +
    + + + + Calculating statistics for a band in a cube + + This example shows the statistics gathered from a single band of + a cube. + + + + from= ATL_MarsCube_RED5_0.cub to= red5.pvl + + + Running hifringe on a channel file. + + + + + + Output from stats + + + This is the output captured in "red5.pvl". + + + + + +
    diff --git a/isis/src/mro/apps/hifringe/tsts/Makefile b/isis/src/mro/apps/hifringe/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hifringe/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hifringe/tsts/default/Makefile b/isis/src/mro/apps/hifringe/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d5dd8c6f653feda6d1fd7886b4b22e5c73c78150 --- /dev/null +++ b/isis/src/mro/apps/hifringe/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = hifringe + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/mroTruth.cub \ + to=$(OUTPUT)/hifringeTruth.pvl > /dev/null; diff --git a/isis/src/mro/apps/hifurrows/Makefile b/isis/src/mro/apps/hifurrows/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hifurrows/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hifurrows/hifurrows.cpp b/isis/src/mro/apps/hifurrows/hifurrows.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf1611c2c544fd8a18bb7ce88de8912b4e882ecc --- /dev/null +++ b/isis/src/mro/apps/hifurrows/hifurrows.cpp @@ -0,0 +1,146 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "HiLab.h" +#include "MultivariateStatistics.h" +#include "PvlGroup.h" + +#include + +using namespace std; +using namespace Isis; + +int channel, bin; +double correlation; +struct furrow { + int startSample; + int endSample; + int increment; + vector mvstats; +}; +vector furrows; + +void furrowCheck(Buffer &in, Buffer &out); +void getStats(Buffer &in); + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Setup the input and output cubes + Cube* icube = p.SetInputCube("FROM"); + + UserInterface &ui = Application::GetUserInterface(); + correlation = ui.GetDouble("CORRELATION"); + HiLab hiInfo(icube); + channel = hiInfo.getChannel(); + bin = hiInfo.getBin(); + + // Bin 1 images have up to four furrows; others have only one + if(bin == 1) { + // Numbers derived from TRA_000827_0985 + furrows.resize(4); + furrows[0].startSample = 5; + furrows[0].endSample = 1; + furrows[0].increment = -1; + + furrows[1].startSample = 255; + furrows[1].endSample = 251; + furrows[1].increment = -1; + + furrows[2].startSample = 518; + furrows[2].endSample = 514; + furrows[2].increment = -1; + + furrows[3].startSample = 781; + furrows[3].endSample = 777; + furrows[3].increment = -1; + } + else { + furrows.resize(1); + if(channel == 0) { + furrows[0].startSample = 5; + furrows[0].endSample = 1; + furrows[0].increment = -1; + } + else if(channel == 1) { + furrows[0].startSample = icube->Samples() - 5 + 1; + furrows[0].endSample = icube->Samples(); + furrows[0].increment = 1; + } + else { + string msg = "Cannot process merged images."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + } + + for(int i = 0; i < (int)furrows.size(); i++) { + int n = abs(furrows[i].startSample - furrows[i].endSample); + furrows[i].mvstats.resize(n); + } + + p.StartProcess(getStats); + PvlGroup stats("Correlations"); + p.SetOutputCube ("TO"); + + // Add correlation data to cube label + for(int i = 0; i < (int)furrows.size(); i++) { + for(int j = 0; j < (int)furrows[i].mvstats.size(); j++) { + string label, begin, finish; + stringstream ss; + + if(channel == 0) { + ss << furrows[i].startSample-j; + ss >> begin; + ss.clear(); + ss << furrows[i].startSample-j-1; + ss >> finish; + } + else if(channel == 1) { + ss << furrows[i].startSample+j; + ss >> begin; + ss.clear(); + ss << furrows[i].startSample+j+1; + ss >> finish; + } + label += "Column" + begin + "to" + finish; + stats += PvlKeyword(label, furrows[i].mvstats[j].Correlation()); + } + } + Application::Log(stats); + + p.StartProcess(furrowCheck); + p.EndProcess(); +} + +// Populate mvstats vector with column data (first or last five columns) +void getStats(Buffer &in) { + for(int i = 0; i < (int)furrows.size(); i++) { + for(int j = 0; j < (int)furrows[i].mvstats.size(); j++) { + int index = furrows[i].startSample + j * furrows[i].increment - 1; + furrows[i].mvstats[j].AddData(&in[index], + &in[index+furrows[i].increment], 1); + } + } +} + +void furrowCheck(Buffer &in, Buffer &out) { + bool bFurrows = false; + // Copy first, then correct furrows + for(int i = 0; i < in.size(); i++) { + out[i] = in[i]; + } + + for(int i = 0; i < (int)furrows.size(); i++) { + for(int j = (int)furrows[i].mvstats.size(); j > 0; j--) { + if(furrows[i].mvstats[j-1].Correlation() < correlation || bFurrows == true) { + bFurrows = true; + if(channel == 0) { + out[furrows[i].startSample-j-1] = Isis::Null; + } + else { + out[furrows[i].startSample+j-1] = Isis::Null; + } + } + } + } +} diff --git a/isis/src/mro/apps/hifurrows/hifurrows.xml b/isis/src/mro/apps/hifurrows/hifurrows.xml new file mode 100644 index 0000000000000000000000000000000000000000..388e1ea2b15639df3b2aeccd407cd1ccc6bac37d --- /dev/null +++ b/isis/src/mro/apps/hifurrows/hifurrows.xml @@ -0,0 +1,90 @@ + + + + + Null furrowed pixels + + + + This program works by finding the correlation between the columns + in an input image. With a Channel 0 image, the first five columns + are examined; in a Channel 1 image, the last five columns are + examined (Channel 2 images are not supported). If the statistical + results suggest a furrow is detected (i.e. the correlation between + two columns is below a certain threshold), then the affected column is + replaced with Null pixels.



    + If a an input image does not have a furrow, none of its pixels will be + altered. The label of all output files will include a new group called + "Correlations." This group lists the correlations between the relevant + columns. For example, "Column3to2 0.987..." means there is a strong + positive correlation between columns 2 and 3 (and very unlikely to have + a furrow in the area). +
    + + + Mars Reconnaissance Orbiter + + + + + hiclean + hifringe + + + + + + Original version + + + Removed references to CubeInfo + + + + + + + cube + input + + Input file + + + The cube to be corrected + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the modified data. + + + *.cub + + + + + + + double + 0.75 + Correlation threshold + + The maximum correlation from pixel to pixel. If the correlation + between two pixels suddenly drops below this value, then a furrow + has been detected. + + 0.0 + + + + +
    diff --git a/isis/src/mro/apps/hifurrows/tsts/Makefile b/isis/src/mro/apps/hifurrows/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hifurrows/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hifurrows/tsts/default/Makefile b/isis/src/mro/apps/hifurrows/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b0d62a4b92a46acf7508989d6bbb115ab9b4adba --- /dev/null +++ b/isis/src/mro/apps/hifurrows/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = hifurrows + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from= $(INPUT)/TRA_000880_1905_RED0_0.cub \ + to= $(OUTPUT)/hifurrowsTruth.cub > /dev/null; diff --git a/isis/src/mro/apps/higlob/Makefile b/isis/src/mro/apps/higlob/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/higlob/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/higlob/assets/higlob_diagram.png b/isis/src/mro/apps/higlob/assets/higlob_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..7437472609ecb916ea0493faa3c45ec3d5792f5b Binary files /dev/null and b/isis/src/mro/apps/higlob/assets/higlob_diagram.png differ diff --git a/isis/src/mro/apps/higlob/assets/higlob_diagram.vsd b/isis/src/mro/apps/higlob/assets/higlob_diagram.vsd new file mode 100644 index 0000000000000000000000000000000000000000..bcf9e13b15bd1147d4ae26f97146f0855ed01c5e Binary files /dev/null and b/isis/src/mro/apps/higlob/assets/higlob_diagram.vsd differ diff --git a/isis/src/mro/apps/higlob/higlob.cpp b/isis/src/mro/apps/higlob/higlob.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b13e84d12ff826a06a7c71e3abe823cf76abd173 --- /dev/null +++ b/isis/src/mro/apps/higlob/higlob.cpp @@ -0,0 +1,164 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "LineManager.h" +#include "Filename.h" +#include "iException.h" +#include "Table.h" + +using namespace std; +using namespace Isis; + +// Globals and prototypes +Cube cube; +LineManager *in; + +Table hifix("HiRISE Ancillary"); +Table calfix("HiRISE Calibration Ancillary"); +Table calimg("HiRISE Calibration Image"); + +bool flip; +void glob (Buffer &out); + +void IsisMain() { + ProcessByLine p; + + // Initialize the output size + int samples = 0; + int lines = 0; + int bands = 0; + + // Open the input cube + UserInterface &ui = Application::GetUserInterface(); + string from = ui.GetFilename("FROM"); + cube.Open(from); + + samples = cube.Samples(); + lines = cube.Lines(); + bands = cube.Bands(); + + // Get a cube packet to the input file + Cube *icube = p.SetInputCube("FROM"); + + // Get the cube prefix and suffix table + icube->Read(hifix); + + // Get the calibration prefix and suffix table + icube->Read(calfix); + + // Get the calibration image table + icube->Read(calimg); + + // Add the number of buffer pixels and dark pixels to the ouput NS + samples += hifix[0]["BufferPixels"].Size() + hifix[0]["DarkPixels"].Size(); + + // Add the number of lines in the calibration image to the output NL + lines += calimg.Records(); + + // Decide if the calibration and observation data should be flipped. + flip = false; + PvlGroup &ins = icube->GetGroup("Instrument"); + int chan = ins["ChannelNumber"]; + + iString flipChan = ui.GetString("FLIP"); + if (flipChan.UpCase() != "NONE") { + if (flipChan.ToInteger() == chan) flip = true; + } + + // Allocate the output file and make sure things get propogated nicely + p.PropagateTables(false); + p.SetOutputCube ("TO",samples,lines,bands); + p.ClearInputCubes(); + + // Create a buffer for reading the input cube + in = new LineManager(cube); + + // Crop the input cube + p.StartProcess(glob); + + // Cleanup + p.EndProcess(); + delete in; + cube.Close(); +} + +// Line processing routine +void glob (Buffer &out) { + double int2ToDouble (int value); + + // Transfer the calibration buffer, image, and dark pixels + if (out.Line() <= calimg.Records()) { + int outPos = 0; + + // Buffer pixels + vector buf = calfix[out.Line()-1]["BufferPixels"]; + for (int i=0; i<(int)buf.size(); i++) { + out[outPos++] = int2ToDouble(buf[i]); + } + + // Main calibration pixels + vector cal = calimg[out.Line()-1]["Calibration"]; + if (flip) { + for (int i=(int)cal.size()-1; i>=0; i--) { + out[outPos++] = int2ToDouble(cal[i]); + } + } + else { + for (int i=0; i<(int)cal.size(); i++) { + out[outPos++] = int2ToDouble(cal[i]); + } + } + + // Dark pixels + vector dark = calfix[out.Line()-1]["DarkPixels"]; + for (int i=0; i<(int)dark.size(); i++) { + out[outPos++] = int2ToDouble(dark[i]); + } + + } // End calibration if + + // We are done with the calibration lines so now + // transfer the image buffer, observation, and dark pixels + else { + int outPos = 0; + + // Buffer pixels + vector buf = hifix[out.Line()-calimg.Records()-1]["BufferPixels"]; + for (int i=0; i<(int)buf.size(); i++) { + out[outPos++] = int2ToDouble(buf[i]); + } + + // Main observation pixels + in->SetLine(out.Line()-calimg.Records(), 1); + cube.Read(*in); + + if (flip) { + for (int i=in->size()-1; i>=0; i--) { + out[outPos++] = (*in)[i]; + } + } + else { + for (int i=0; isize(); i++) { + out[outPos++] = (*in)[i]; + } + } + + // Dark pixels + vector dark = hifix[out.Line()-calimg.Records()-1]["DarkPixels"]; + for (int i=0; i<(int)dark.size(); i++) { + out[outPos++] = int2ToDouble(dark[i]); + } + + } // End main image else +} // End function + +double int2ToDouble (int value) { + if (value == NULL2) return NULL8; + else if (value == LOW_REPR_SAT2) return LOW_REPR_SAT8; + else if (value == LOW_INSTR_SAT2) return LOW_INSTR_SAT8; + else if (value == HIGH_INSTR_SAT2) return HIGH_INSTR_SAT8; + else if (value == HIGH_REPR_SAT2) return HIGH_REPR_SAT8; + else return value; + +} + diff --git a/isis/src/mro/apps/higlob/higlob.xml b/isis/src/mro/apps/higlob/higlob.xml new file mode 100644 index 0000000000000000000000000000000000000000..e7323495c950b57b2fb742ebd6ee46aea567f044 --- /dev/null +++ b/isis/src/mro/apps/higlob/higlob.xml @@ -0,0 +1,136 @@ + + + + + Combines HiRISE image data with all pixel data in the blobs + + + +

    + This program will create a new image with the calibration pixel data + at the top, followed by the main image data. Both the calibration and main image + will have the buffer pixels added to the left side and the dark pixels to the right + side. +

    + Diagram of output pixel groups +

    + The pixel values are retrieved from either the Isis tables or the main image. + The calibration buffer and dark pixels are pulled from the "HiRISE Ancillary" table. The main + calibration image pixels come from the "HiRISE Calibration Image" table. The image buffer + and dark pixels come from the "HiRISE Ancillary" table. The observation pixels come from + the main Isis cube. +

    +

    + The calibration image and observation image pixels of a HiRISE image can be flipped from left to right + using the "FLIP" parameter. See the "FLIP" parameter description for details. +

    +
    + + + Mars Reconnaissance Orbiter + + + + + Original version + + + Fixed problem with special pixels in image ancillary, calibration and calibration ancillary + areas. They are now converted to double precision special pixels before being inserted + into the Buffer. + + + Fixed another problem with special pixels in the image ancillary table. The + 16 bit integer special pixel values in table were not being converted to double + special pixels when being dumped into the output buffer. + + + During our first observation in cruise, it was determined that channel 1 required + flippping rather than channel 0. This confusion due to assumptions of which channel, + 0 or 1, was on the left or right side of the CCD. Channel 1 is on the left, channel 0 on the + right. Also changed the FLIP parameter to an integer to allow the user to choose + either channel to flip (so we don't have to do this again!) + + + Fixed a memory leak caused by not deleting a global pointer. + + + Documentation fixes + + + Removed references to CubeInfo + + + + + + + cube + input + + Input HiRISE cube + + + The HiRISE cube containing the image and tables from the EDR product. This must + be an Isis cube (i.e., "hi2isis" must be run before "higlob"). + + + *.cub + + + + + cube + output + + Combined output cube + + + The output cube containing the main image data, calibration data, buffer pixels + and dark pixels. + + + *.cub + + + + + + + string + Specify HiRISE channel (0 or 1) image & calibration image to flip + 1 + +

    + This is typically channel 1 (discovered after launch!) rather than 0, but this + option allows you to choose the channel you want to flip. The default (1) is + the one designated as the channel to flip to best assist in calibration analysis. +

    +

    + If FLIP matches the value of the ChannelNumber keyword in the Instrument + group, then both the observation and calibration image data will be filpped left to + right. This does not modify the byte order of the individual pixels, and does not + flip any of the buffer or dark pixels. +

    +

    + To ensure that you flip no channel, set FLIP to "None". +

    +
    + + + + + +
    +
    +
    +
    diff --git a/isis/src/mro/apps/higlob/tsts/Makefile b/isis/src/mro/apps/higlob/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/higlob/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/higlob/tsts/default/Makefile b/isis/src/mro/apps/higlob/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3942a91e5e49177446f016fb6006073ff2df1f5c --- /dev/null +++ b/isis/src/mro/apps/higlob/tsts/default/Makefile @@ -0,0 +1,11 @@ +APPNAME = higlob + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/PSP_001331_2260_IR10_0.cub \ + to=$(OUTPUT)/higlob_default_truth0.cub \ + flip=0 > /dev/null; + $(APPNAME) from=$(INPUT)/PSP_001331_2260_IR10_1.cub \ + to=$(OUTPUT)/higlob_default_truth1.cub \ + flip=1 > /dev/null; diff --git a/isis/src/mro/apps/higlob/tsts/flip/Makefile b/isis/src/mro/apps/higlob/tsts/flip/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1df27e7d312ef0d4a18bd792733a56bf26403751 --- /dev/null +++ b/isis/src/mro/apps/higlob/tsts/flip/Makefile @@ -0,0 +1,11 @@ +APPNAME = higlob + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/PSP_001331_2260_IR10_0.cub \ + to=$(OUTPUT)/higlob_default_truth0.cub \ + flip=none > /dev/null; + $(APPNAME) from=$(INPUT)/PSP_001331_2260_IR10_1.cub \ + to=$(OUTPUT)/higlob_default_truth1.cub \ + flip=none > /dev/null; diff --git a/isis/src/mro/apps/hijitreg/Exceptions.cpp b/isis/src/mro/apps/hijitreg/Exceptions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..271729029e4da7b3d863249a0bf150aaba0cfc7d --- /dev/null +++ b/isis/src/mro/apps/hijitreg/Exceptions.cpp @@ -0,0 +1,144 @@ +/* Exception + +PIRL CVS ID: $Id: Exceptions.cpp,v 1.2 2009/02/23 16:36:10 slambright Exp $ + +Copyright (C) 2003 Arizona Board of Regents on behalf of the Planetary +Image Research Laboratory, Lunar and Planetary Laboratory at the +University of Arizona. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License, version 2.1, +as published by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +*/ + +#include +#include +#include "Exceptions.hh" + +#if defined (DEBUG) + +/*=***************************************************************************** +Debug Controls + +Define any of the following options to obtain the desired debug reports. +*******************************************************************************/ + +#define DEBUG_ALL (-1) +#define DEBUG_EXCEPTIONS (1 << 0) + +#include +using std::cerr; +using std::endl; + +#endif +// End DEBUG + +namespace UA +{ +namespace HiRISE +{ +/*============================================================================== +Constants +*/ +const char* const + Exception::ID = + "UA::HiRISE::Exception ($Revision: 1.2 $ $Date: 2009/02/23 16:36:10 $)"; + +/*============================================================================== +Constructor +*/ + +Exception::Exception +( + const std::string& message, + const char* caller_id +) +: Message + ( + std::string (ID) + + (caller_id ? (std::string ("\n") + caller_id) : "") + + '\n' + message + ) +{ + if (! Message.empty () && Message [Message.size () - 1] == '\n') + // Remove the trailing newline. + Message.erase (Message.size () - 1); + User_Message_Index = + strlen (ID) + (caller_id ? (strlen (caller_id) + 2) : 1); +#if ((DEBUG) & DEBUG_EXCEPTIONS) + cerr + << ">-< Exception" << endl + << " message -" << endl << message << endl + << " caller_id -" << endl; + if (caller_id) + cerr << caller_id << endl; + else + cerr << "NULL" << endl; + cerr + << " Message -" << endl << Message << endl + << " User_Message_Index: " << User_Message_Index << endl; +#endif +} + +/*============================================================================== +Accessors +*/ + +const char* Exception::what () +const +throw () +{ return Message.c_str (); } + +std::string Exception::message () +const +throw () +{ + // Exclude the Exception ID but include the caller_id (if it exists). + std::string::size_type index = strlen (ID) + 1; + if (index > Message.size ()) + index = 0; + return Message.substr (index); +} + +void Exception::message +( + const std::string& new_message +) +{ +#if ((DEBUG) & DEBUG_EXCEPTION) + cerr + << ">>> Exception::message" << endl + << " Message -" << endl << Message << endl + << " new_message -" << endl << new_message << endl + << " Message.length: " << Message.length () << endl + << " User_Message_Index: " << User_Message_Index << endl + << " new_message.length: " << new_message.length () << endl; +#endif + if (User_Message_Index >= Message.length ()) + // Then there is no message to replace; append on the next line. + (Message += '\n') += new_message; + else + // Replace the trailing user message portion of the Message. + Message.replace (User_Message_Index, + Message.length () - User_Message_Index, new_message); + if (! Message.empty () && Message [Message.size () - 1] == '\n') + // Remove the trailing newline. + Message.erase (Message.size () - 1); +#if ((DEBUG) & DEBUG_EXCEPTION) + cerr + << "<<< Exception::message" << endl; +#endif +} + +} // namespace HiRISE +} // namespace UA diff --git a/isis/src/mro/apps/hijitreg/Exceptions.hh b/isis/src/mro/apps/hijitreg/Exceptions.hh new file mode 100644 index 0000000000000000000000000000000000000000..6bbaf0e946ee519dd6019dc4297ede6ce700eef8 --- /dev/null +++ b/isis/src/mro/apps/hijitreg/Exceptions.hh @@ -0,0 +1,242 @@ +/* HiRISE Exceptions + +PIRL CVS ID: $Id: Exceptions.hh,v 1.1.1.1 2006/10/31 23:18:15 isis3mgr Exp $ + +Copyright (C) 2003, 2004, 2005 Arizona Board of Regents on behalf of the +Planetary Image Research Laboratory, Lunar and Planetary Laboratory at +the University of Arizona. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License, version 2.1, +as published by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +*/ + +#ifndef _UA_HIRISE_EXCEPTIONS_HEADER_ +#define _UA_HIRISE_EXCEPTIONS_HEADER_ + +#include +#include +#include + +namespace UA +{ + +namespace HiRISE +{ + +/*=***************************************************************************** +Exception Class +*******************************************************************************/ + +/** An exception thrown by UA::HiRISE classes. + + This class is at the root of a hierarchy of classes used to signal + exceptions: + +
    +
    Error +
    An unrecoverable error condition. +
    +
    Invalid_Argument [std::invalid_argument] +
    An invalid or otherwise unrecognized argument value from + which no recovery is possible. +
    Out_of_Range [std::out_of_range] +
    A value is outside the acceptable range. +
    +
    + + An Exception has a message string that describes the reason for the + exception. The message method will return this message, + while the what method will prepend the Exception class + ID to the message and return that. + + @author Bradford Castalia, Christian Schaller - UA/PIRL + @version $Revision: 1.1.1.1 $ +*/ +class Exception +: public std::exception +{ + +public: + +/*============================================================================== +Constants +*/ +//! Class identification name with source code version and date. +static const char* const + ID; + +/*============================================================================== +Constructors +*/ + +/** Constructs an Exception with a message. + + If the message ends with a newline character ('\n'), it is removed. + If a caller_id is provided, it preceeds the message string separated + by a newline character. + + @param message The message string. Default: "" + @param caller_id An optional C-string identifying the source + of the Exception. Default: NULL +*/ +explicit Exception +( + const std::string& message = "", + const char* caller_id = NULL +); + +// Destructor +virtual ~Exception () throw () {} + +/*============================================================================== +Accessors +*/ + +/** Gets a C-string that describes the condition that created the + Exception. + + @return The C-string that includes the Exception ID as the first + followed by the caller_id and the message string. +*/ +const char* what () const throw (); + +/** Gets the user-provided called_id (if any) and message string. + + @return The message string, which is the caller_id followed by + the user message. +*/ +std::string message () const throw (); + +/** Sets the message string. + + If the message ends with a newline character ('\n'), it is removed. + If a caller_id was provided when the Exception was created it + remains; the new message is substituted in place of the previous + message. + + @param new_message A string to replace the previous message. +*/ +void message (const std::string& new_message); + +private: + +/*============================================================================== +Private Data +*/ + +std::string + Message; +std::string::size_type + User_Message_Index; + +}; // Exception class + +/*=***************************************************************************** +Error Struct (Class) +*******************************************************************************/ + +/** Error exception. + + An unrecoverable error condition. +*/ +struct Error +: public Exception +{ +/** Constructs an Error Exception with a message. + + @param message The message string. Default: "" + @param caller_id An optional C-string identifying the source + of the Exception. Default: NULL +*/ +explicit Error +( + const std::string& message = "", + const char *caller_id = NULL +) +: Exception (std::string ("Error: ") + message, caller_id) +{} + +}; // Error struct + +/*=***************************************************************************** +Invalid_Argument Struct (Class) +*******************************************************************************/ + +/** Invalid_Argument exception. + + An invalid or otherwise unrecognized argument value was detected. +*/ +struct Invalid_Argument +: public Error, + public std::invalid_argument +{ +/** Constructs an Invalid_Argument Error with a message. + + @param message The message string. Default: "" + @param caller_id An optional C-string identifying the source + of the Error. Default: NULL +*/ +explicit Invalid_Argument +( + const std::string& message = "", + const char *caller_id = NULL +) +: Error (std::string ("Invalid_Argument\n") + message, caller_id), + std::invalid_argument + ( + std::string (Exception::ID) + + (caller_id ? (std::string ("\n") + caller_id) : "") + ) +{} + +}; // Invalid_Argument struct + +/*=***************************************************************************** +Out_of_Range Struct (Class) +*******************************************************************************/ + +/** Out_of_Range exception. + + A value is outside the acceptable range. +*/ +struct Out_of_Range : + public Error, + public std::out_of_range +{ +/** Constructs an Out_of_Range Error with a message. + + @param message The message string. Default: "" + @param caller_id An optional C-string identifying the source + of the Error. Default: NULL +*/ +explicit Out_of_Range +( + const std::string& message = "", + const char *caller_id = NULL +) +: Error (std::string ("Out_of_Range\n") + message, caller_id), + std::out_of_range + ( + std::string (Exception::ID) + + (caller_id ? (std::string ("\n") + caller_id) : "") + ) +{} + +}; // Out_of_Range struct + +} // HiRISE namespace + +} // UA namespace + +#endif diff --git a/isis/src/mro/apps/hijitreg/HiJitCube.cpp b/isis/src/mro/apps/hijitreg/HiJitCube.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a84d59535f50d7a8b5b78c5eacf90e0f02e7d0ee --- /dev/null +++ b/isis/src/mro/apps/hijitreg/HiJitCube.cpp @@ -0,0 +1,398 @@ +/** + * @file + * $Revision: 1.7 $ + * $Date: 2009/12/29 23:03:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "naif/SpiceUsr.h" + +#include "HiJitCube.h" +#include "Instrument.hh" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Filename.h" + +using namespace UA::HiRISE; +using std::string; +using std::endl; +using std::ostringstream; + + +namespace Isis { + + +static geos::geom::GeometryFactory geosFactory; +bool HiJitCube::naifLoaded = false; +int npSamp0[] = {0,1971,3964,5963,7970,7971,7971,9975,9976,9976,11981,13986,15984,17982}; +int npSamps[] = {2021,2043,2048,2052,2055,2053,2053,2053,2054,2055,2051,2049,2043,2018}; +bool sampinit=false; +bool originst; + +/** + * @brief Default constructor with no cube + */ +HiJitCube::HiJitCube() { + initLocal(); +} + +/** + * @brief Constructor with file to open + */ +HiJitCube::HiJitCube(const std::string &filename) { + initLocal(); + OpenCube(filename); +} + +/** + * @brief Constructor with file to open and potential shift applied + */ +HiJitCube::HiJitCube(const std::string &filename, PvlObject &shift) { + initLocal(); + OpenCube(filename, shift); +} + + +/** + * @brief Destructor + */ +HiJitCube::~HiJitCube() { + delete fpGeom; + Close(); +} + +void HiJitCube::setSampleOffset(int soff) { + jdata.sampOffset = soff; + if (IsOpen()) computePoly(); + return; +} + +void HiJitCube::setLineOffset(int loff) { + jdata.lineOffset = loff; + if (IsOpen()) computePoly(); + return; +} + + +void HiJitCube::OpenCube(const std::string &filename) { + Open(filename); + Init(); + return; +} + +void HiJitCube::OpenCube(const std::string &filename, PvlObject &shift) { + OpenCube(filename); + +// Determine if a shift of the CCD exists in the definitions file + if (shift.HasGroup(jdata.ccdName)) { + PvlGroup &ccddef = shift.FindGroup(jdata.ccdName, Pvl::Traverse); + if (ccddef.HasKeyword("SampleOffset")) { + jdata.sampOffset = (int) ccddef["SampleOffset"]; + } + if (ccddef.HasKeyword("LineOffset")) { + jdata.lineOffset = (int) ccddef["LineOffset"]; + } + computePoly(); + } + + return; +} + +double HiJitCube::getLineTime(double line) const { + return (((line-1.0) * jdata.linerate) + jdata.obsStartTime); +} + +void HiJitCube::Compatable(HiJitCube &cube) throw (iException &) { + JitInfo other = cube.GetInfo(); + + if (jdata.summing != other.summing) { + ostringstream msg; + msg << "Summing mode (" << jdata.summing + << ") in file " << Filename() << " is not equal to summing mode (" + << other.summing << ") in file " << cube.Filename() << endl; + throw iException::Message(iException::User,msg.str(),_FILEINFO_); + } + return; +} + + +bool HiJitCube::intersects(const HiJitCube &cube) const { + return (fpGeom->intersects(cube.Poly())); +} + +bool HiJitCube::overlap(const HiJitCube &cube, Corners &ovlCorners) { + geos::geom::Geometry *ovl = fpGeom->intersection(cube.Poly()); +// cout << "Overlap: " << ovl->toString() << std::endl; + ovlCorners = FocalPlaneToImage(getCorners(*ovl)); + delete ovl; + return (ovlCorners.good); +} + + +void HiJitCube::loadNaifTiming( ) { + if (!naifLoaded) { +// Load the NAIF kernels to determine timing data + Isis::Filename leapseconds("$base/kernels/lsk/naif????.tls"); + leapseconds.HighestVersion(); + + Isis::Filename sclk("$mro/kernels/sclk/MRO_SCLKSCET.?????.65536.tsc"); + sclk.HighestVersion(); + +// Load the kernels + string lsk = leapseconds.Expanded(); + string sClock = sclk.Expanded(); + furnsh_c(lsk.c_str()); + furnsh_c(sClock.c_str()); + +// Ensure it is loaded only once + naifLoaded = true; + } + return; +} + +void HiJitCube::computeStartTime() { + loadNaifTiming(); + +// Compute the unbinned and binned linerates in seconds + jdata.unBinnedRate = ((Instrument::LINE_TIME_PRE_OFFSET + + (jdata.dltCount/Instrument::HIRISE_CLOCK_SUBTICK_MICROS)) + / 1000000.0); + jdata.linerate = jdata.unBinnedRate * ((double) jdata.summing); + + if (!jdata.scStartTime.empty()) { + string scStartTimeString = jdata.scStartTime; + scs2e_c (-74999,scStartTimeString.c_str(),&jdata.obsStartTime); + // Adjust the start time so that it is the effective time for + // the first line in the image file + jdata.obsStartTime -= (jdata.unBinnedRate * (((double(jdata.tdiMode/2.0) + - 0.5)))); + // Effective observation + // time for all the TDI lines used for the + // first line before doing binning + jdata.obsStartTime += (jdata.unBinnedRate * (((double) jdata.summing/2.0) + - 0.5)); + } + return; +} + +void HiJitCube::initLocal() { + jdata.filename = "_none_"; + jdata.productId = "__undetermined__"; + jdata.lines = 0; + jdata.samples = 0; + jdata.sampOffset = 0; + jdata.lineOffset = 0; + jdata.tdiMode = 0; + jdata.summing = 0; + jdata.channelNumber = 0; + jdata.cpmmNumber = 0; + jdata.ccdName ="_unknown_"; + jdata.dltCount = 0.0; + jdata.UTCStartTime = ""; + jdata.scStartTime = ""; + jdata.obsStartTime = 0.0; + jdata.unBinnedRate = 0.0; + jdata.linerate = 0.0; + jdata.fpSamp0 = 0; + jdata.fpLine0 = 0; + jdata.pixpitch = 0.0; + + fpGeom = 0; +} + +void HiJitCube::Init() throw (iException &) { + // Get required keywords from instrument group + Pvl *label(Label()); + Isis::PvlGroup inst; + Isis::PvlGroup idinst; + jdata.filename = Filename(); + Isis::PvlGroup &archive = label->FindGroup ("Archive",Isis::Pvl::Traverse); + jdata.productId = (string) archive["ProductId"]; + + jdata.lines = Lines(); + if (label->FindObject("IsisCube").HasGroup("OriginalInstrument")) { + inst = label->FindGroup ("OriginalInstrument",Isis::Pvl::Traverse); + originst = true; + } else { + inst = label->FindGroup ("Instrument",Isis::Pvl::Traverse); + originst = false; + } + jdata.tdiMode = inst["Tdi"]; + jdata.summing = inst["Summing"]; + if (label->FindObject("IsisCube").HasGroup("Instrument") && originst) { + idinst = label->FindGroup ("Instrument",Isis::Pvl::Traverse); + jdata.pixpitch = idinst["PixelPitch"]; + jdata.summing = (int) (jdata.pixpitch/.012); + } + if (originst && jdata.summing != 1 && !sampinit) { + for (int i=0; i<14; i++) { + npSamps[i] = (int) (npSamps[i]/(float)jdata.summing + 0.5); + npSamp0[i] = (int) (npSamp0[i]/(float)jdata.summing + 0.5); + } + sampinit = true; + } + jdata.channelNumber = inst["ChannelNumber"]; + jdata.cpmmNumber = inst["CpmmNumber"]; + if (originst) { + jdata.samples = npSamps[jdata.cpmmNumber]; + } else { + jdata.samples = Samples(); + } + jdata.ccdName = Instrument::CCD_NAMES[jdata.cpmmNumber]; + jdata.dltCount = inst["DeltaLineTimerCount"]; + jdata.UTCStartTime = (string) inst["StartTime"]; + jdata.scStartTime = (string) inst["SpacecraftClockStartCount"]; + + try { + if (originst) { + jdata.fpSamp0 = npSamp0[jdata.cpmmNumber]; + } else { + jdata.fpSamp0 = Instrument::focal_plane_x_offset(jdata.cpmmNumber, + jdata.summing); + } + } catch (Exception hiExc) { + ostringstream msg; + msg << "Summing mode (" << jdata.summing + << ") is illegal (must be > 0) or CPMM number (" << jdata.cpmmNumber + << ") is invalid in file " << Filename() << endl; + throw iException::Message(iException::User,msg.str(),_FILEINFO_); + } + +// It is assumed all images start at the line location in the focal plane + jdata.fpLine0 = 0; + +// Validate channel number and adjust starting sample + if ((jdata.channelNumber > 2) || (jdata.channelNumber < 0)) { + ostringstream msg; + msg << "Channel number (" << jdata.channelNumber + << ") is invalid (must be 0, 1 or 2) in file " << Filename() << endl; + throw iException::Message(iException::User,msg.str(),_FILEINFO_); + } + else { + if (originst) { + if (jdata.channelNumber == 0) jdata.fpSamp0 += npSamps[jdata.cpmmNumber]; + } else { + if (jdata.channelNumber == 0) jdata.fpSamp0 += Samples(); + } + } + +// Determine starting time of image and compute the binning rates + computeStartTime(); + +// Compute the focal plane polygon for this image + computePoly(); + return; +} + + +int HiJitCube::getBinModeIndex(int summing) const throw (iException &) { + for (unsigned int i = 0 ; i < Instrument::TOTAL_BINNING_FACTORS ; i++) { + int binFactor = Instrument::BINNING_FACTORS[i]; + if (binFactor == summing) return (i); + } + + ostringstream msg; + msg << "Invalid summing mode (" << summing << ") for file " << + Filename() << std::endl; + throw iException::Message(iException::User,msg.str(),_FILEINFO_); +} + + +void HiJitCube::computePoly() { + +// Compute sample and line coordinates in the focal plane + int samp0,sampN; + if (originst) { + samp0=jdata.fpSamp0 + jdata.sampOffset; + sampN=samp0 + npSamps[jdata.cpmmNumber] - 1; + } else { + samp0=jdata.fpSamp0 + jdata.sampOffset; + sampN=samp0 + Samples() - 1; + } + int line0(jdata.fpLine0 + jdata.lineOffset), lineN(line0 + Lines() - 1); + +// Allocate a new coordinate sequence and define it + geos::geom::CoordinateSequence *pts = new geos::geom::CoordinateArraySequence(); + pts->add(geos::geom::Coordinate(samp0, lineN)); + pts->add(geos::geom::Coordinate(sampN, lineN)); + pts->add(geos::geom::Coordinate(sampN, line0)); + pts->add(geos::geom::Coordinate(samp0, line0)); + pts->add(geos::geom::Coordinate(samp0, lineN)); + + +// Make this reentrant and delete previous one if it exists and get the +// new one + delete fpGeom; + fpGeom = geosFactory.createPolygon(geosFactory.createLinearRing(pts), 0); + return; +} + +HiJitCube::Corners HiJitCube::FocalPlaneToImage(const Corners &fp) const { + Corners image; + if (fp.good) { + double samp0; +// Compute sample and line coordinates in the focal plane + if (originst) { + samp0 = 0; + } else { + samp0 = jdata.fpSamp0 + jdata.sampOffset; + } + double line0(jdata.fpLine0 + jdata.lineOffset); + + image.topLeft.sample = fp.topLeft.sample - samp0 + 1.0; + image.topLeft.line = fp.topLeft.line - line0 + 1.0; + image.lowerRight.sample = fp.lowerRight.sample - samp0 + 1.0; + image.lowerRight.line = fp.lowerRight.line - line0 + 1.0; + image.good = true; + } + return (image); +} + +HiJitCube::Corners HiJitCube::getCorners(const geos::geom::Geometry &poly) const { + Corners corners; + if ((poly.isValid()) && (!poly.isEmpty())) { + +// Get the coordinate list + geos::geom::CoordinateSequence *clist = poly.getCoordinates(); + const geos::geom::Coordinate *minpt = clist->minCoordinate(); +// cout << "MinPoint: " << minpt->x << ", " << minpt->y << std::endl; + + geos::geom::Coordinate maxpt(clist->getAt(0)); + for (unsigned int i = 1 ; i < clist->getSize() ; i++) { + geos::geom::Coordinate pt = clist->getAt(i); + if ((pt.x >= maxpt.x) && (pt.y >= maxpt.y)) maxpt = pt; + } +// cout << "MaxPoint: " << maxpt.x << ", " << maxpt.y << std::endl; + + corners.topLeft.sample = minpt->x; + corners.topLeft.line = minpt->y; + corners.lowerRight.sample = maxpt.x; + corners.lowerRight.line = maxpt.y; + corners.good = true; + + delete clist; + } + return (corners); +} + + +} diff --git a/isis/src/mro/apps/hijitreg/HiJitCube.h b/isis/src/mro/apps/hijitreg/HiJitCube.h new file mode 100644 index 0000000000000000000000000000000000000000..897ce76c6cf783e9dbcd3291bf2687260de6dd30 --- /dev/null +++ b/isis/src/mro/apps/hijitreg/HiJitCube.h @@ -0,0 +1,150 @@ +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/08/19 22:37:41 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef HiJitCube_h +#define HiJitCube_h + +#include "Cube.h" +#include "geos/geom/Polygon.h" +#include "geos/geom/Geometry.h" +#include "geos/geom/CoordinateSequence.h" +#include "geos/geom/Envelope.h" +#include "geos/geom/GeometryFactory.h" +#include "geos/geom/CoordinateArraySequence.h" + +namespace Isis { + + class PvlObject; +/** + * @brief HiRISE cube detailer for jitter characterization + * + * HiJitCube is designed to open and manage HiRISE image cubes for the + * purpose of jitter characterization. Inheriting the Isis Cube class, + * it provides opening and closeing of the cube, but its main function + * is gathering data from the label, validating against other instances + * of this same object on other HiRISE cubes and computing focal plane + * mapping expressly to determine overlapping regions of images. + * + * @ingroup MarsReconnaissanceOrbiter + * + * @author 2006-05-04 Kris Becker + * + */ + class HiJitCube : public Cube { + public: + + /** + * Structure that contains all pertinent data for the cube + */ + struct JitInfo { + std::string filename; + std::string productId; + int lines; + int samples; + int sampOffset; + int lineOffset; + int tdiMode; + int summing; + int channelNumber; + int cpmmNumber; + std::string ccdName; + double dltCount; + std::string UTCStartTime; + std::string scStartTime; + double obsStartTime; + double unBinnedRate; + double linerate; + int fpSamp0; + int fpLine0; + double pixpitch; + }; + + /** + * Structure containing cube coordinates + */ + struct CubeCoords { + double line; + double sample; + CubeCoords() : line(0.0), sample(0.0) { } + }; + + /** + * Structure containing corners of a region + */ + struct Corners { + CubeCoords topLeft; + CubeCoords lowerRight; + bool good; + Corners() : topLeft(), lowerRight(), good(false) { } + }; + + public: + HiJitCube(); + HiJitCube(const std::string &filename); + HiJitCube(const std::string &filename, PvlObject &shift); + ~HiJitCube(); + + void setSampleOffset(int soff); + void setLineOffset(int loff); + + /** + * Returns the sample offset for this image + */ + inline int getSampleOffset() const { return (jdata.sampOffset); } + /** + * Returns the line offset for this image + */ + inline int getLineOffset() const { return (jdata.lineOffset); } + + void OpenCube(const std::string &filename); + void OpenCube(const std::string &filename, PvlObject &shift); + inline const JitInfo &GetInfo() const { return (jdata); } + double getLineTime(double line = 1.0) const; + + + void Compatable(HiJitCube &cube) throw (iException &); + + geos::geom::Polygon const *Poly() const { return (fpGeom); } + bool intersects(const HiJitCube &cube) const; + bool overlap(const HiJitCube &cube, Corners &ovlCorners); + /** + * Returns the string representation of the overlapping region + */ + std::string PolyToString() const { return (fpGeom->toString()); } + + private: + JitInfo jdata; //!< Cube information + geos::geom::Polygon *fpGeom; //!< Polygon construction and manipulation + static bool naifLoaded; //!< Status of NAIF required kernels for times + + void initLocal(); + void loadNaifTiming(); + void computeStartTime(); + void Init( ) throw (iException &); + int getBinModeIndex(int summing) const throw (iException &); + void computePoly(); + Corners FocalPlaneToImage(const Corners &fp) const; + Corners getCorners(const geos::geom::Geometry &poly) const; + }; + +} // namespace Isis +#endif diff --git a/isis/src/mro/apps/hijitreg/Instrument.cpp b/isis/src/mro/apps/hijitreg/Instrument.cpp new file mode 100644 index 0000000000000000000000000000000000000000..298b8434c7bdfa56010e2dd490a24d9f852037f2 --- /dev/null +++ b/isis/src/mro/apps/hijitreg/Instrument.cpp @@ -0,0 +1,440 @@ +/* HiRISE Instrument + +PIRL CVS ID: $Id: Instrument.cpp,v 1.2 2009/02/23 16:36:10 slambright Exp $ + +Copyright (C) 2003-2006 Arizona Board of Regents on behalf of the +Planetary Image Research Laboratory, Lunar and Planetary Laboratory at +the University of Arizona. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License, version 2.1, +as published by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ +#include "Instrument.hh" + +#include +#include +#include +using std::endl; + +#include +using std::ostringstream; + + +namespace UA +{ +namespace HiRISE +{ +/*=***************************************************************************** + Instrument +*/ +/*============================================================================== + Constants: +*/ +const char* const + Instrument::ID = "UA::HiRISE::Instrument ($Revision: 1.2 $ $Date: 2009/02/23 16:36:10 $)"; + +const unsigned int + Instrument::CCDS = 14; + +const unsigned int + Instrument::CCD_UNKNOWN = 99; + +const char* const + Instrument::CCD_NAMES[] = + { + "RED0", + "RED1", + "RED2", + "RED3", + "BG12", + "RED4", + "IR10", + "IR11", + "RED5", + "BG13", + "RED6", + "RED7", + "RED8", + "RED9" + }; +const char* const + Instrument::CCD_FILTER_NAMES[] = + { + "RED", + "RED", + "RED", + "RED", + "BLUE-GREEN", + "RED", + "NEAR-INFRARED", + "NEAR-INFRARED", + "RED", + "BLUE-GREEN", + "RED", + "RED", + "RED", + "RED" + }; + +const unsigned int + Instrument::CCD_BY_CPMM[] = + { + 0, + 1, + 2, + 3, + 12, + 4, + 10, + 11, + 5, + 13, + 6, + 7, + 8, + 9 + }; + +const unsigned int + Instrument::CPMM_BY_CCD[] = + { + 0, + 1, + 2, + 3, + 5, + 8, + 10, + 11, + 12, + 13, + 6, + 7, + 4, + 9 + }; + + +const char + * const Instrument::WAVELENGTH_UNITS = "NANOMETERS"; + +const unsigned int + Instrument::CCD_CENTER_WAVELENGTHS[] = + { + 700, + 700, + 700, + 700, + 500, + 700, + 900, + 900, + 700, + 500, + 700, + 700, + 700, + 700 + }; + +const unsigned int + Instrument::CCD_BANDWIDTHS[] = + { + 300, + 300, + 300, + 300, + 200, + 300, + 200, + 200, + 300, + 200, + 300, + 300, + 300, + 300 + }; + + +const double + Instrument::CCD_FOCAL_PLANE_X_OFFSETS_MM[] = + { + -96.0000, + -71.9985, + -48.0499, + -24.0400, + 0.0000, + 0.0000, + 0.0000, + 24.0000, + 24.0000, + 24.0000, + 48.0000, + 72.0045, + 96.0014, + 120.0025 + }; + +const double + Instrument::CCD_FOCAL_PLANE_Y_OFFSETS_MM[] = + { + -14.6257, + -21.5130, + -14.0498, + -21.4869, + -28.7552, + -14.4594, + 0.0000, + -7.2767, + -21.4662, + -36.0247, + -14.2603, + -21.4359, + -14.5152, + -21.8000 + }; + +const double + Instrument::CCD_PIXEL_SIZE_MM = 0.012; + + +const unsigned int + Instrument::CCD_CHANNELS = 2; + +const unsigned int + Instrument::CCD_CHANNEL_UNKNOWN = 9; + + +const unsigned int + Instrument::CCD_IMAGE_SENSORS = 1024; + +const unsigned int + Instrument::MAX_BYTES_PER_PIXEL = 2; + +const unsigned int + Instrument::MAX_PIXEL_VALUES[MAX_BYTES_PER_PIXEL] = + { + 254, + 0x3FFF // 14 bits. + }; + + +/* The maximum number of image lines: CPMM RAM limited. + + Subject: Re: Maximum HiRISE image lines + Date: Mon, 21 Feb 2005 11:53:20 -0800 + From: Nathan Bridges + To: hisys@pirl.lpl.Arizona.EDU + +HiSYS, + +My understanding is that LUTing occurs after putting data on the CPMMs, +such that we can only use 16-bits to compute the maximum number of +lines. Can someone confirm if this correct or not? If so, the maximum +number of pre-binned lines (L) is + +L = (2x1024^3)*B/(16[2048/B+56]) + +where the CPMM data volume is 2x1024^3 bits and B is the bin factor. +This equation takes into account that the buffer and dark pixels are not +serially binned. The number of post-binned lines (L') is simply the +above equation divided by the bin factor: + +L' = (2x1024^3)/(16[2048/B+56]) + +the result is (I rounded down all numbers): + +Bin Maximum # Pre-Binned Lines Maximum # Post-Binned Lines +1 63,791 63,791 +2 248,551 124,275 +3 545,108 181,702 +4 945,195 236,298 +8 3,441,480 430,185 +16 11,671,106 729,444 + +The attached spreadsheet has the computations + +I guess the actual numbers are even slightly smaller because of line +headers and maybe other extra things I'm not including. However, using +the above as a maximum should work. + + Nathan +*/ +/* The upper limit (exclusive) of the number of image lines based on the + available number of line header line number field bits. +*/ +const unsigned int + Instrument::MAX_IMAGE_LINES = (1 << 23); + + +const unsigned int + Instrument::TOTAL_TDI_STAGES = 4; + +const unsigned int + Instrument::TDI_STAGES[TOTAL_TDI_STAGES] = + { + 8, + 32, + 64, + 128 + }; + + +const unsigned int + Instrument::TOTAL_BINNING_FACTORS = 6; + +const unsigned int + Instrument::BINNING_FACTORS[TOTAL_BINNING_FACTORS] = + { + 1, + 2, + 3, + 4, + 8, + 16 + }; + +const unsigned int + Instrument::CCD_BINNED_PIXELS[TOTAL_BINNING_FACTORS] = + { + 2048, + 1024, + 684, + 512, + 256, + 128 + }; + + +const unsigned int + Instrument::STORED_LUTS = 28; + + +const unsigned int + Instrument::STIMULATOR_LEDS = 3; + +const char* const + Instrument::STIMULATOR_LED_NAMES[] = + { + "RED", + "BLUE-GREEN", + "NEAR-INFRARED" + }; + + +const double + Instrument::EXPOSURE_SETUP_MICROS = 99.48; + +const unsigned int + Instrument::DELTA_LINE_TIME_MAX = 4194303; + +const double + Instrument::DELTA_LINE_TIME_TICK_NANOS = 62.5; + +const double + Instrument::LINE_TIME_PRE_OFFSET = 74.0; + +const unsigned int + Instrument::TRIM_ADDITION_LINES = 180, + Instrument::REVERSE_READOUT_LINES = 20, + Instrument::MASKED_LINES = 20; + + +const unsigned int + Instrument::DLL_LOCKED = 0x11, + Instrument::DLL_NOT_LOCKED = 0x5A; + + +#ifndef MRO_EPOCH +#define MRO_EPOCH 1980 +#endif +const unsigned int + Instrument::SPACECRAFT_EPOCH = MRO_EPOCH; + +const double + Instrument::MRO_CLOCK_SUBTICK_MICROS = (1000000.0 / (1 << 16)), + Instrument::HIRISE_CLOCK_SUBTICK_MICROS = 16.0; + +const int + Instrument::SPACECRAFT_NAIF_ID = -74; + + +const unsigned int + Instrument::SSR_BYTE_BOUNDARY = 4; + + +const int + Instrument::UNKNOWN_NUMBER = -9999, + Instrument::NOT_APPLICABLE_NUMBER = -9998; +const char + * const Instrument::UNKNOWN_STRING = "UNKNOWN"; +const char + * const Instrument::NOT_APPLICABLE_STRING = "N/A"; + +/*============================================================================== + Functions +*/ +unsigned int +Instrument::calibration_lines_minimum + ( + unsigned int TDI, + unsigned int binning + ) +{ +if (binning == 0) + binning = 1; +return + REVERSE_READOUT_LINES + + static_cast(ceil (static_cast(MASKED_LINES + TDI) + / static_cast(binning))); +} + + +int +Instrument::focal_plane_x_offset + ( + unsigned int CPMM, + unsigned int binning + ) + throw (Out_of_Range, Invalid_Argument) +{ +if ((CPMM < 0) || (CPMM >= CCDS)) + { + ostringstream + message; + message << "Unable to determine the focal plane offset" << endl + << "for CPMM " << CPMM + << " with binning factor " << binning << '.' << endl + << "The CPMM number is invalid."; + throw Out_of_Range (message.str(), ID); + } + +if (binning == 0) + { + ostringstream + message; + message << "Unable to determine the focal plane offset" << endl + << "for CPMM " << CPMM + << " with binning factor " << binning << '.' << endl + << "The binning factor must not be zero."; + throw Invalid_Argument (message.str(), ID); + } + +return + (int)rint (CCD_FOCAL_PLANE_X_OFFSETS_MM[CPMM] + / (CCD_PIXEL_SIZE_MM * binning)); +} + +} // namespace HiRISE +} // namespace UA diff --git a/isis/src/mro/apps/hijitreg/Instrument.hh b/isis/src/mro/apps/hijitreg/Instrument.hh new file mode 100644 index 0000000000000000000000000000000000000000..ced9c3e5a5395cea5b397464d4ecf105a7e8f02a --- /dev/null +++ b/isis/src/mro/apps/hijitreg/Instrument.hh @@ -0,0 +1,409 @@ +/* HiRISE Instrument + +PIRL CVS ID: $Id: Instrument.hh,v 1.1.1.1 2006/10/31 23:18:15 isis3mgr Exp $ + +Copyright (C) 2003 Arizona Board of Regents on behalf of the Planetary +Image Research Laboratory, Lunar and Planetary Laboratory at the +University of Arizona. + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License, version 2.1, +as published by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +#ifndef _HiRISE_Instrument_ +#define _HiRISE_Instrument_ + +#include "Exceptions.hh" + +/** University of Arizona +*/ +namespace UA +{ +/** High Resolution Imaging Science Experiment +*/ +namespace HiRISE +{ + +/*=***************************************************************************** + Instrument +*/ +/** The Instrument defines constants and static functions used to + characterize the MRO HiRISE instrument. +

    +@author Bradford Castalia, UA/PIRL +$Revision: 1.1.1.1 $ +*/ + +class Instrument +{ +public: +/*============================================================================== + Constants +*/ +//! Class identification name with source code version and date. +static const char* const + ID; + + +//! Total number of CCD array assemblies. +static const unsigned int + CCDS; + +//! Special CCD number when the actual CCD/CPMM number is unknown. +static const unsigned int + CCD_UNKNOWN; + +/** The identification names associated with each CCD, indexed by CPMM number. + + Each CCD sensor array has been given a name that includes an + abbreviation for the {@link #CCD_FILTER_NAMES color filter} it uses + and its CCD sensor array number. N.B.: The CCD sensor array + number is not the same as the CPPM number reported by the + instrument; use the {@link #CCD_BY_CPMM} array to map CPMM numbers + to CCD sensor array numbers, and the {@link #CPMM_BY_CCD} to map CCD + sensor array numbers to CPMM numbers. +*/ +static const char* const + CCD_NAMES[]; + +//! The filter names associated with each CCD, indexed by CPMM number. +static const char* const + CCD_FILTER_NAMES[]; + +/** CCD sensor array numbers associated with each CCD, indexed by CPMM number. + + The instrument software refers to CCDs by their CPMM number. + However, due to the way the CCD sensor arrays were wired to the CPPM + modules the CCD sensor array numbers are not always the same as the + CPMM number. This array maps CPMM numbers to the corresponding CCD + sensor array number. + + @see #CPMM_BY_CCD +*/ +static const unsigned int + CCD_BY_CPMM[]; + +/** CPMM numbers associated with each CCD, indexed by CCD sensor array number. + + N.B.: All other arrays in this Instrument class are indexed by + CPMM number. + + @see #CCD_BY_CPMM +*/ +static const unsigned int + CPMM_BY_CCD[]; + + +//! The units of wavelength measurement for the CCD filters. +static const char* const + WAVELENGTH_UNITS; + +/** The filter center wavelength for each CCD, indexed by CPMM number. + + Wavelength values are measured in {@link #WAVELENGTH_UNITS}. +*/ +static const unsigned int + CCD_CENTER_WAVELENGTHS[]; + +/** The filter wavelength bandwidth for each CCD, indexed by CPMM number. + + Wavelength values are measured in {@link #WAVELENGTH_UNITS}. +*/ +static const unsigned int + CCD_BANDWIDTHS[]; + + +/** Focal plane X offset in millimeters for each CCD, indexed by CPMM number. + + The X offset of each CCD's first detector pixel measured in + millimeters in the HiRISE focal plane assembly relative to CPMM 6 + (CCD sensor array 10) left fiducial. + + @see #CCD_FOCAL_PLANE_Y_OFFSETS_MM +*/ +static const double + CCD_FOCAL_PLANE_X_OFFSETS_MM[]; + +/** Focal plane Y offset in millimeters for each CCD, indexed by CPMM number. + + The Y offset of each CCD's first detector pixel measured in + millimeters in the HiRISE focal plane assembly relative to CPMM 6 + (CCD sensor array 10) left fiducial. + + @see #CCD_FOCAL_PLANE_X_OFFSETS_MM +*/ +static const double + CCD_FOCAL_PLANE_Y_OFFSETS_MM[]; + +//! CCD detector pixel size in millimeters. +static const double + CCD_PIXEL_SIZE_MM; + + +/** The number of data channels for each CCD assembly. + + Each CCD array assembly is composed of a pair of CCD channels. + Both channels act together as an image scanning unit, but each + channel has its own distinct imaging sensors and pixel line data + store. All instrument observation data is organized by channel. +*/ +static const unsigned int + CCD_CHANNELS; + +//! Special channel number when the actual channel number is unknown. +static const unsigned int + CCD_CHANNEL_UNKNOWN; + + +/** The number of image sensors in a single CCD channel line. + + Each CCD device of an instrument channel is an array of sensors + organized as across-track lines and down-track TDI line stages. Each + line contains the same number of sensors. +*/ +static const unsigned int + CCD_IMAGE_SENSORS; + +//! The maximum number of bytes per pixel value. +static const unsigned int + MAX_BYTES_PER_PIXEL; + +/** The maximum valid pixel values. + + Any pixel value above the maximum is invalid. The instrument is + expected to guarantee that only valid pixel values are produced. + This array is indexed by the number of bytes per pixel - 1. + + During data downlink operations from the spacecraft lost packets + gaps are filled with values with all bits set. Pixels with gap + values are therefore certain to be above the MAX_PIXEL_VALUES for + any number of bytes per pixel. +*/ +static const unsigned int + MAX_PIXEL_VALUES[]; + + +/** Image lines upper limit (exclusive). + + Line header bytes 3-5 contain the observation line number as recorded + by the instrument. The most significant bit of this field is being + reserved to accommodate an additional "bad line" flag. The instrument + can not generate enough observation lines to cause this reserved bit + to be set by a valid line number. +*/ +static const unsigned int + MAX_IMAGE_LINES; + + +/** The number of time delay integration (TDI) stages available to each CCD. + + Each CCD device of an instrument channel is an array of sensors + organized a across-track lines and down-track TDI line stages. Only + one line has its sensor values sampled and scanned out to the CPMM + storage for further processing. The sensor values from lines + preceeding (up-track) the TDI line are cascaded into the following + line to accumulate down-track sensor values. Since the rate at + which sensor line values cascade (the scan line time) is set at the + time the observation starts to coincide with the rate at which the + image scene moves across the sensor lines, the effect is to build + image signal strength and improve the signal-to-noise ratio at the + expense of some image blurring due to timing and alignment + inaccuracies. + + @see #TDI_STAGES +*/ +static const unsigned int + TOTAL_TDI_STAGES; + +//! Valid TDI stages values. +static const unsigned int + TDI_STAGES[]; + + +/** The number of binning factors available to each CCD. + + After the selected CCD sensor line has its values read out into + CPMM storage the accumulated observation sensor readings may be + summed - binned - by pixel groups in both the cross-track and + down-track directions. Each non-overlapping pixel group is square + with a size specified by the binning factor. Each square of pixels + is a patch of the image observation that, as a result of binning, + produces a single new pixel value. + + @see #BINNING_FACTORS +*/ +static const unsigned int + TOTAL_BINNING_FACTORS; + +//! Valid binning factor values. +static const unsigned int + BINNING_FACTORS[]; + +/** The number of image pixels per line for each binning factor. + + Normally the number of pixels per line is the number of {@link + #CCD_IMAGE_SENSORS} divided by the binning factor in use. However, + for the odd binning factor 3 the number of pixels per line is + rounded up to a multiple of 4 due to the contrainst of the + {@link #SSR_BYTE_BOUNDARY}. +*/ +static const unsigned int + CCD_BINNED_PIXELS[]; + + +//! The number of stored LUTS available. +static const unsigned int + STORED_LUTS; + + +//! The number of stimulator LEDs. +static const unsigned int + STIMULATOR_LEDS; + +//! The identification names associated with each stim lamp. +static const char* const + STIMULATOR_LED_NAMES[]; + + +//! Exposure operation setup time. +static const double + EXPOSURE_SETUP_MICROS; + +//! Engineering_Header Delta_Line_Time maximum valid value. +static const unsigned int + DELTA_LINE_TIME_MAX; + +//! Engineering_Header Delta_Line_Time nanoseconds per tick. +static const double + DELTA_LINE_TIME_TICK_NANOS; + +//! Offset for Engineering_Header Delta_Line_Time when calculating line time. +static const double + LINE_TIME_PRE_OFFSET; + +//! Number of scan lines after the trim lines before the first observation line. +static const unsigned int + TRIM_ADDITION_LINES; + +//! Number of initial unbinned reverse readout observation lines. +static const unsigned int + REVERSE_READOUT_LINES; + +//! Number of binned masked lines following the reverse readout lines. +static const unsigned int + MASKED_LINES; + + +//! 96 MHz DLL locked telemetry value. +static const unsigned int + DLL_LOCKED; +//! 96 MHz DLL out of lock telemetry value. +static const unsigned int + DLL_NOT_LOCKED; + + +//! MRO spacecraft clock epoch (year). +static const unsigned int + SPACECRAFT_EPOCH; + +//! MRO spacecraft clock microseconds per subseconds tick. +static const double + MRO_CLOCK_SUBTICK_MICROS; + +//! HiRISE clock microseconds per subseconds tick. +static const double + HIRISE_CLOCK_SUBTICK_MICROS; + +//! MRO NAIF spacecraft clock identifier. +static const int + SPACECRAFT_NAIF_ID; + + +//! Byte boundary (byte count modulus) for the solid state recorder. +static const unsigned int + SSR_BYTE_BOUNDARY; + + +//! Special integer value when the actual value is unknown. +static const int + UNKNOWN_NUMBER; + +//! Special integer value when it is not applicable in context. +static const int + NOT_APPLICABLE_NUMBER; + +//! Special text value when the actual value is unknown. +static const char + * const UNKNOWN_STRING; + +//! Special text value when it is not applicable in context. +static const char + * const NOT_APPLICABLE_STRING; + +/*============================================================================== + Functions +*/ +/** Gets the minimum number of calibration lines. + + The minimum number of calibration lines is: + + REVERSE_READOUT_LINES + ceil ((MASKED_LINES + TDI) / binning) + + Where the number of #REVERSE_READOUT_LINES and #MASKED_LINES are + Instrument constants, and TDI and Binning are the Engineering Header + TDI_Stages and Binning_Factor values respectively. The calculated + real value is rounded up to the next line boundary; i.e. any partial + line resulting from the division is entirely included as a + calibration line. + + N.B.: The calculated number of calibration lines is the + minimum that contain data only suitable for calibration purposes, as + opposed to observation image lines that contain data for the target + image acquisition. However, it is possible for additional image + lines to be designated as calibration lines. + + @param TDI The number of time delay integration stages. + @param binning The line binning factor. + @return The minimum number of calibration lines. +*/ +static unsigned int calibration_lines_minimum + (unsigned int TDI, unsigned int binning); + +/** Gets the focal plane X offset pixels. + + The X offset in pixels of the first pixel within a CCD sensor array + is provided for a given CPMM number and binning mode. This is useful + for determining how each CCD channel is mapped into the focal + plane. Note: CCD Channel 1 is to the left, and channel 0 is to the + right, of the image observation data generated by each CCD array + assembly. + + @param CPMM The CPMM number for which the offset is to be calculated. + @param binning The applicable binning factor. + @return The pixel offset relative to CPMM 6 (CCD sensor array 10), + which is at offset 0. + @throws Out_of_Range If the CPMM index is invalid. + @throws Invalid_Argument If binning is 0. Any other binning factor is + accepted. + @see #CCD_CHANNELS + @see #BINNING_FACTORS +*/ +static int focal_plane_x_offset + (unsigned int CPMM, unsigned int binning = 1) + throw (Out_of_Range, Invalid_Argument); + +}; // class Instrument + +} // namespace HiRISE +} // namespace UA +#endif diff --git a/isis/src/mro/apps/hijitreg/Makefile b/isis/src/mro/apps/hijitreg/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..54773fbb3f7c79f1a406ceb5534a27bd71d89e06 --- /dev/null +++ b/isis/src/mro/apps/hijitreg/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = hijitreg + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hijitreg/hijitreg.cpp b/isis/src/mro/apps/hijitreg/hijitreg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd29b3abf4b636014e430037a8016ee6d7aace47 --- /dev/null +++ b/isis/src/mro/apps/hijitreg/hijitreg.cpp @@ -0,0 +1,498 @@ +#include "Isis.h" + +#include +#include +#include +#include +#include +#include + +#include "PvlGroup.h" +#include "UserInterface.h" +#include "Cube.h" +#include "Chip.h" +#include "Progress.h" +#include "iException.h" +#include "AutoReg.h" +#include "AutoRegFactory.h" +#include "Statistics.h" +#include "MultivariateStatistics.h" +#include "HiJitCube.h" +#include "ControlNet.h" +#include "SerialNumber.h" +#include "ControlMeasure.h" +#include "iTime.h" + +using namespace std; +using namespace Isis; + + +struct RegData { + double fLine; + double fSamp; + double fLTime; + double mLine; + double mSamp; + double mLTime; + double regLine; + double regSamp; + double regCorr; + double B0; // RegList; + +static ostream &dumpResults(ostream &out, const RegList ®s, + const JitterParms &jparms, const AutoReg &ar); + +void IsisMain() { + + // Get user interface + UserInterface &ui = Application::GetUserInterface(); + +// Open the shift definitions file + Pvl shiftdef; + if (ui.WasEntered("SHIFTDEF")) { + shiftdef.Read(ui.GetFilename("SHIFTDEF")); + } + else { + shiftdef.AddObject(PvlObject("Hiccdstitch")); + } + + PvlObject &stitch = shiftdef.FindObject("Hiccdstitch", Pvl::Traverse); + + + // Open the first cube. It will be matched to the second input cube. + HiJitCube trans; + CubeAttributeInput &attTrans = ui.GetInputAttribute("FROM"); + vector bandTrans = attTrans.Bands(); + trans.SetVirtualBands(bandTrans); + trans.OpenCube(ui.GetFilename("FROM"), stitch); + + + // Open the second cube, it is held in place. We will be matching the + // first to this one by attempting to compute a sample/line translation + HiJitCube match; + CubeAttributeInput &attMatch = ui.GetInputAttribute("MATCH"); + vector bandMatch = attMatch.Bands(); + match.SetVirtualBands(bandMatch); + match.OpenCube(ui.GetFilename("MATCH"), stitch); + +// Ensure only one band + if ((trans.Bands() != 1) || (match.Bands() != 1)) { + string msg = "Input Cubes must have only one band!"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + +// Now test compatability (basically summing) + trans.Compatable(match); + +// Determine intersection + if (!trans.intersects(match)) { + string msg = "Input Cubes do not overlap!"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + +// Get overlapping regions of each cube + HiJitCube::Corners fcorns, mcorns; + trans.overlap(match, fcorns); + match.overlap(trans, mcorns); + +#if defined(ISIS_DEBUG) + cout << "FROM Poly: " << trans.PolyToString() << std::endl; + cout << "MATCH Poly: " << match.PolyToString() << std::endl; + cout << "From Overlap: (" << fcorns.topLeft.sample << "," + << fcorns.topLeft.line << "), (" + << fcorns.lowerRight.sample << "," + << fcorns.lowerRight.line << ")\n" ; + cout << "Match Overlap: (" << mcorns.topLeft.sample << "," + << mcorns.topLeft.line << "), (" + << mcorns.lowerRight.sample << "," + << mcorns.lowerRight.line << ")\n" ; +#endif + + + // We need to get a user definition of how to auto correlate around each + // of the grid points. + Pvl regdef; + Filename regFile(ui.GetFilename("REGDEF")); + regdef.Read(regFile.Expanded()); + AutoReg *ar = AutoRegFactory::Create(regdef); + + + double flines(fcorns.lowerRight.line - fcorns.topLeft.line + 1.0); + double fsamps(fcorns.lowerRight.sample - fcorns.topLeft.sample + 1.0); + + // We want to create a grid of control points that is N rows by M columns. + // Get row and column variables, if not entered, default to 1% of the input + // image size + int rows(1), cols(1); + if (ui.WasEntered("ROWS")) { + rows = ui.GetInteger("ROWS"); + } + else { + rows = (int)(((flines - 1.0) / ar->SearchChip()->Lines()) + 1); + } + + cols = ui.GetInteger("COLUMNS"); + if (cols == 0) { + cols = (int)(((fsamps - 1.0) / ar->SearchChip()->Samples()) + 1); + } + + // Calculate spacing for the grid of points + double lSpacing = floor(flines / rows); + double sSpacing = floor(fsamps / cols); + +#if defined(ISIS_DEBUG) + cout << "# Samples in Overlap: " << fsamps << endl; + cout << "# Lines in Overlap : " << flines << endl; + cout << "# Rows: " << rows << endl; + cout << "# Columns: " << cols << endl; + cout << "Line Spacing: " << lSpacing << endl; + cout << "Sample Spacing: " << sSpacing << endl; +#endif + + // Display the progress...10% 20% etc. + Progress prog; + prog.SetMaximumSteps(rows * cols); + prog.CheckStatus(); + + // Initialize control point network + ControlNet cn; + cn.SetType(ControlNet::ImageToImage); + cn.SetUserName(Application::UserName()); + cn.SetCreatedDate(iTime::CurrentLocalTime()); + + // Get serial numbers for input cubes + string transSN = SerialNumber::Compose(trans, true); + string matchSN = SerialNumber::Compose(match, true); + + cn.SetTarget(transSN); + cn.SetDescription("Records s/c jitter between two adjacent HiRISE images"); + +// Set up results parameter saves + JitterParms jparms; + jparms.fromCorns = fcorns; + jparms.fromJit = trans.GetInfo(); + jparms.matchCorns = mcorns; + jparms.matchJit = match.GetInfo(); + jparms.regFile = regFile.Expanded(); + jparms.cols = cols; + jparms.rows = rows; + jparms.lSpacing = lSpacing; + jparms.sSpacing = sSpacing; + jparms.nSuspects = 0; + + // Loop through grid of points and get statistics to compute + // translation values + RegList reglist; + double fline0(fcorns.topLeft.line-1.0), fsamp0(fcorns.topLeft.sample-1.0); + double mline0(mcorns.topLeft.line-1.0), msamp0(mcorns.topLeft.sample-1.0); + + for (int r=0; rPatternChip()->TackCube(msamp0+samp, mline0+line); + ar->PatternChip()->Load(match); + ar->SearchChip()->TackCube(fsamp0+samp, fline0+line); + ar->SearchChip()->Load(trans); + + // Set up ControlMeasure for cube to translate + ControlMeasure cmTrans; + cmTrans.SetCubeSerialNumber(transSN); + cmTrans.SetCoordinate(msamp0+samp, mline0+line, + ControlMeasure::Unmeasured); + cmTrans.SetChooserName("hijitreg"); + cmTrans.SetReference(false); + + // Set up ControlMeasure for the pattern/Match cube + ControlMeasure cmMatch; + cmMatch.SetCubeSerialNumber(matchSN); + cmMatch.SetCoordinate(fsamp0+samp, fline0+line, + ControlMeasure::Automatic); + cmMatch.SetChooserName("hijitreg"); + cmMatch.SetReference(true); + + + // Match found + if (ar->Register()==AutoReg::Success) { + RegData reg; + reg.fLine = fline0 + line; + reg.fSamp = fsamp0 + samp; + reg.fLTime = trans.getLineTime(reg.fLine); + reg.mLine = mline0 + line; + reg.mSamp = msamp0 + samp; + reg.mLTime = match.getLineTime(reg.mLine); + reg.regLine = ar->CubeLine(); + reg.regSamp = ar->CubeSample(); + reg.regCorr = ar->GoodnessOfFit(); + + + if (fabs(reg.regCorr) > 1.0) jparms.nSuspects++; + + double sDiff = reg.fSamp - reg.regSamp; + double lDiff = reg.fLine - reg.regLine; + jparms.sStats.AddData(&sDiff,(unsigned int)1); + jparms.lStats.AddData(&lDiff,(unsigned int)1); + +// Record the translation in the control point + cmTrans.SetCoordinate(ar->CubeSample(), ar->CubeLine(), + ControlMeasure::Automatic); + cmTrans.SetError(sDiff, lDiff); + cmTrans.SetGoodnessOfFit(ar->GoodnessOfFit()); + +// Reread the chip location centering the offset and compute +// linear regression statistics + try { + Chip &pchip(*ar->PatternChip()); + Chip fchip(pchip.Samples(), pchip.Lines()); + fchip.TackCube(ar->CubeSample(), ar->CubeLine()); + fchip.Load(trans); + +// Writes correlated chips to files for visual inspection +#if defined(ISIS_DEBUG) + ostringstream tstr; + tstr << "R" << r << "C" << c << "_chip.cub"; + string fcname("from" + tstr.str()); + string mcname("match" + tstr.str()); + + pchip.Write(mcname); + fchip.Write(fcname); +#endif + + MultivariateStatistics mstats; + for (int line = 1 ; line <= fchip.Lines() ; line++) { + for(int sample = 1; sample < fchip.Samples(); sample++) { + double fchipValue = fchip.GetValue(sample,line); + double pchipValue = pchip.GetValue(sample,line); + mstats.AddData(&fchipValue, &pchipValue, 1); + } + } + +// Get regression and correlation values + mstats.LinearRegression(reg.B0, reg.B1); + reg.Bcorr = mstats.Correlation(); + if (IsSpecial(reg.B0)) throw 1; + if (IsSpecial(reg.B1)) throw 2; + if (IsSpecial(reg.Bcorr)) throw 3; + } + catch (...) { +// If fails, flag this condition + reg.B0 = 0.0; + reg.B1= 0.0; + reg.Bcorr = 0.0; + } + + reglist.push_back(reg); + } + + // Add the measures to a control point + string str = "Row " + iString(r) + " Column " + iString(c); + ControlPoint cp(str); + cp.SetType(ControlPoint::Tie); + cp.Add(cmTrans); + cp.Add(cmMatch); + if (!cmTrans.IsMeasured()) cp.SetIgnore(true); + cn.Add(cp); + prog.CheckStatus(); + } + } + + // If flatfile was entered, create the flatfile + // The flatfile is comma seperated and can be imported into an excel + // spreadsheet + if (ui.WasEntered("FLATFILE")) { + string fFile = ui.GetFilename("FLATFILE"); + ofstream os; + string fFileExpanded = Filename(fFile).Expanded(); + os.open(fFileExpanded.c_str(),ios::out); + dumpResults(os, reglist, jparms, *ar); + } + + // If a cnet file was entered, write the ControlNet pvl to the file + if (ui.WasEntered("CNETFILE")) { + cn.Write(ui.GetFilename("CNETFILE")); + } + + // Don't need the cubes opened anymore + trans.Close(); + match.Close(); + + + // Write translation to log + PvlGroup results("AverageTranslation"); + if (jparms.sStats.ValidPixels() > 0) { + double sTrans = (int)(jparms.sStats.Average() * 100.0) / 100.0; + double lTrans = (int)(jparms.lStats.Average() * 100.0) / 100.0; + results += PvlKeyword ("Sample",sTrans); + results += PvlKeyword ("Line",lTrans); + results += PvlKeyword ("NSuspects",jparms.nSuspects); + } + else { + results += PvlKeyword ("Sample","NULL"); + results += PvlKeyword ("Line","NULL"); + } + + Application::Log(results); + + // add the auto registration information to print.prt + PvlGroup autoRegTemplate = ar->RegTemplate(); + Application::Log(autoRegTemplate); + + return; +} + + +static ostream &dumpResults(ostream &out, const RegList ®s, + const JitterParms &jparms, const AutoReg &ar) { + + std::ios::fmtflags oldFlags = out.flags(); + out.setf(std::ios::fixed); + + const HiJitCube::JitInfo &fJit = jparms.fromJit; + const HiJitCube::JitInfo &mJit = jparms.matchJit; + const HiJitCube::Corners &fcorns = jparms.fromCorns; + const HiJitCube::Corners &mcorns = jparms.matchCorns; + + out << "# Hijitreg ISIS Application Results" << endl; + out << "# Coordinates are (Sample, Line) unless indicated" << endl; + out << "# RunDate: " << iTime::CurrentLocalTime() << endl; + out << "#\n# **** Image Input Information ****\n"; + out << "# FROM: " << fJit.filename << endl; + out << "# Lines: " << setprecision(0) << fJit.lines << endl; + out << "# Samples: " << setprecision(0) << fJit.samples << endl; + out << "# FPSamp0: " << setprecision(0) << fJit.fpSamp0 << endl; + out << "# SampOffset: " << fJit.sampOffset << endl; + out << "# LineOffset: " << fJit.lineOffset << endl; + out << "# CPMMNumber: " << fJit.cpmmNumber << endl; + out << "# Summing: " << fJit.summing << endl; + out << "# TdiMode: " << fJit.tdiMode << endl; + out << "# Channel: " << fJit.channelNumber << endl; + out << "# LineRate: " << setprecision(8) << fJit.linerate + << " " << endl; + out << "# TopLeft: " << setw(7) << setprecision(0) + << fcorns.topLeft.sample << " " + << setw(7) << setprecision(0) + << fcorns.topLeft.line << endl; + out << "# LowerRight: " << setw(7) << setprecision(0) + << fcorns.lowerRight.sample << " " + << setw(7) << setprecision(0) + << fcorns.lowerRight.line << endl; + out << "# StartTime: " << fJit.UTCStartTime << " " << endl; + out << "# SCStartTime: " << fJit.scStartTime << " " << endl; + out << "# StartTime: " << setprecision(8) << fJit.obsStartTime + << " " << endl; + out << "\n"; + out << "# MATCH: " << mJit.filename << endl; + out << "# Lines: " << setprecision(0) << mJit.lines << endl; + out << "# Samples: " << setprecision(0) << mJit.samples << endl; + out << "# FPSamp0: " << setprecision(0) << mJit.fpSamp0 << endl; + out << "# SampOffset: " << mJit.sampOffset << endl; + out << "# LineOffset: " << mJit.lineOffset << endl; + out << "# CPMMNumber: " << mJit.cpmmNumber << endl; + out << "# Summing: " << mJit.summing << endl; + out << "# TdiMode: " << mJit.tdiMode << endl; + out << "# Channel: " << mJit.channelNumber << endl; + out << "# LineRate: " << setprecision(8) << mJit.linerate + << " " << endl; + out << "# TopLeft: " << setw(7) << setprecision(0) + << mcorns.topLeft.sample << " " + << setw(7) << setprecision(0) + << mcorns.topLeft.line << endl; + out << "# LowerRight: " << setw(7) << setprecision(0) + << mcorns.lowerRight.sample << " " + << setw(7) << setprecision(0) + << mcorns.lowerRight.line << endl; + out << "# StartTime: " << mJit.UTCStartTime << " " << endl; + out << "# SCStartTime: " << mJit.scStartTime << " " << endl; + out << "# StartTime: " << setprecision(8) << mJit.obsStartTime + << " " << endl; + out << "\n"; + + double nlines(fcorns.lowerRight.line - fcorns.topLeft.line + 1); + double nsamps(fcorns.lowerRight.sample - fcorns.topLeft.sample + 1); + out << "\n# **** Registration Data ****\n"; + out << "# RegFile: " << jparms.regFile << endl; + out << "# OverlapSize: " << setw(7) << (int) nsamps << " " + << setw(7) << (int) nlines << "\n"; + out << "# Sample Spacing: " << setprecision(1) << jparms.sSpacing << endl; + out << "# Line Spacing: " << setprecision(1) << jparms.lSpacing << endl; + out << "# Columns, Rows: " << jparms.cols << " " << jparms.rows << endl; + out << "# Corr. Algorithm: " << ar.AlgorithmName() << endl; + out << "# Corr. Tolerance: " << setprecision(2) << ar.Tolerance() << endl; + out << "# Total Registers: " << regs.size() << " of " + << (jparms.rows * jparms.cols) << endl; + out << "# Number Suspect: " << jparms.nSuspects << endl; + if (jparms.sStats.ValidPixels() > 0) { + out << "# Average Sample Offset: " << setprecision(4) + << jparms.sStats.Average() + << " StdDev: " << setprecision(4) << jparms.sStats.StandardDeviation() + << endl; + out << "# Average Line Offset: " << setprecision(4) + << jparms.lStats.Average() + << " StdDev: " << setprecision(4) << jparms.lStats.StandardDeviation() + << endl; + } + else { + out << "# Average Sample Offset: " << "NULL\n"; + out << "# Average Line Offset: " << "NULL\n"; + } + + out << "\n# Column Headers and Data\n"; + +// Write headers + out + << setw(20) << "FromTime" + << setw(10) << "FromSamp" + << setw(10) << "FromLine" + << setw(20) << "MatchTime" + << setw(10) << "MatchSamp" + << setw(10) << "MatchLine" + << setw(15) << "RegSamp" + << setw(15) << "RegLine" + << setw(10) << "RegCorr" + << setw(15) << "B0_Offset" + << setw(15) << "B1_Slope" + << setw(10) << "B_RCorr" + << endl; + + RegList::const_iterator reg; + for (reg = regs.begin() ; reg != regs.end() ; ++reg) { + out << setw(20) << setprecision(8) << reg->fLTime + << setw(10) << setprecision(0) << reg->fSamp + << setw(10) << setprecision(0) << reg->fLine + << setw(20) << setprecision(8) << reg->mLTime + << setw(10) << setprecision(0) << reg->mSamp + << setw(10) << setprecision(0) << reg->mLine + << setw(15) << setprecision(4) << reg->regSamp + << setw(15) << setprecision(4) << reg->regLine + << setw(10) << setprecision(6) << reg->regCorr + << setw(15) << setprecision(6) << reg->B0 + << setw(15) << setprecision(6) << reg->B1 + << setw(10) << setprecision(6) << reg->Bcorr + << std::endl; + } + + out.setf(oldFlags); + return (out); +} diff --git a/isis/src/mro/apps/hijitreg/hijitreg.xml b/isis/src/mro/apps/hijitreg/hijitreg.xml new file mode 100644 index 0000000000000000000000000000000000000000..de951c68a2bbbde32bb11e9702614bacd345dd16 --- /dev/null +++ b/isis/src/mro/apps/hijitreg/hijitreg.xml @@ -0,0 +1,559 @@ + + + + + + Characterize HiRISE image jitter with co-registration + + + +

    + This program co-registers two HiRISE image overlaping sections. The + section of overlap of each image is determined by their relative positions + in the HiRISE focal plane assembly. Its intended use is to characterize + spacecraft jitter, but may also have other uses, such as determining + relative gains and zero-level offsets of adjacent CCDs, this from the + linear regression data computed for each registration chip. +

    +

    + hijitreg requires the two images provided in FROM and MATCH have + some portion of overlap. This is typically adjacent CCDs, such as RED4 + and RED5 but individual CCD channels can be processed as well. + The appropriate channel will need to be provided, however. For example, + RED4_0 and RED5_1 are overlapping channel files, but RED4_1 and + RED3_1 are not. Furthermore, this application can be used to + characterize offsets of the color sets as well. I will describe these + scenarios in more detail below. +

    +

    + The offsets are determined using HiRISE focal plane locations for + each CCD. Adjacent CCDs are designed to have at least 48 pixels + of overlap between them. + However, it has been determined the amount of overlap can vary under + most viewing conditions. Thus, hijitreg can utilize the same sample and + line offset information used by hiccdstitch to adjust each CCD's + relative position within the HiRISE focal plane. hijitreg then makes the + appropriate localized adjustments to determine the final overlap used to + characterize the two image sections. See the documentation for the + SHIFTDEF parameter for hiccdstitch for further details. +

    +

    + The type of registration algorithm and appropriate parameters for its + use is determined by the REGDEF parameter. This follows the Isis + standard. Below is an example of the PVL-format that is expected + in the file provided. +

    +
    +         Object = AutoRegistration
    +           Group = Algorithm
    +             Name         = MaximumCorrelation
    +             Tolerance    = 0.7
    +           EndGroup
    +
    +           Group = PatternChip
    +             Samples = 17
    +             Lines   = 45
    +           EndGroup
    +
    +           Group = SearchChip
    +             Samples = 30
    +             Lines   = 70
    +           EndGroup
    +         EndObject
    +     
    +

    + A chip registration grid is defined across the MATCH image using the + parameters ROWS and COLUMNS. If the user does not provide + values for the grid size, it will be automatically computed as + follows: ROWS = (line overlap - 1) / search chip lines + 1. The + default for COLUMNS is set to 1. This default condition assumes + processing of overlapping regions that are approximately 48 pixels. + However, if you specify 0, then the computation for + COLUMNS is the same as it is for ROWS only using sample overlap. + Conceptually, the chip grid defined by ROWS and COLUMNS will be + laid on top of both images with even spacing between the rows (or + columns) and but no row will touch the top or bottom of the image. + That is, the grid is internal to the image. +

    +

    + At each grid intersection, a translation will be computed. This is done + by centering the search chip at the grid intersection for the image to + be translated (FROM) and centering the pattern chip at the grid + intersection for the held image (MATCH). The pattern chip is walked + through the search chip to find the best registration (if any). The + details of how this is done is described in the document "Automatic + Registation in Isis 3.0". The local translation is recorded at all grid + intersections that had a successful registration. It will be written to + the FLATFILE if requested. The average and standard deviation of the + local translations is computed and reported as well.. +

    +

    + Some tips to improve odds of a successful registration. In general + don't go too small with the pattern chip size, 17x45 is the nomimal + starting point. Also, the larger the translation, the larger the search + chip size will need to be. So if your translation is only a couple of + pixels keep the search chip slightly bigger than the pattern + (e.g., 25x55 vs 17x45). However if the translation is large you will + need to expand the search area. For example, if the translation is + roughly 45 pixels and your pattern is 20x20 the search area should + be 20+2*45 or 110x110. +

    +

    + A word of caution. In testing, we found that some of the correlations + reported were wildly huge. This indicates that the best fitting offset is + at the very edge of the search chip. When using the MaximumCorrelation + algorithm, they should be between -1 and 1. There is a keyword added + to the log file called NSuspects that indicates the number of + occurances of this condition. If this is not 0, then chances are this + issue occured. This may only apply to the MaximumCorrelation + algorithm. + + To rectify this problem, + examine the RegLine and RegSamp values and compare with the FromLine + and FromSamp, respectively. If the registering sample or line is near + the search chip threshold (i.e., FromSamp+(SearchChip/Samples/2) or + FromLine+(SearchChip/Lines/2)) then increase the size of the search + chip dimensions appropriately. +

    +

    + A typical command line run of hijitreg will look like: +

    +          hijitreg FROM=AEB_000002_0050_RED5.cub MATCH=AEB_000002_0050_RED4.cub \
    +                      REGDEF='$mro/calibration/hijitreg.p1745.s3070.def' \
    +                      SHIFTDEF='$mro/calibration/hiccdstitch.000002_0050_RED.def' \
    +                      FLATFILE=AEB_000002_0050_RED5.dat
    +         
    + To register RED to IR or BG images, you will typically need to insure + that, at a minumum, the summing modes are equivalent. If they are not, + you must run enlarge or reduce, whichever makes sense, + and then use editlab to change the /IsisCube/Instrument/Summing + keyword to the appropriate mode. The keyword values in both images + must be the same number. Note that both samples and lines must be + increased or decreased in order to yield appropriate results. + Once equivalent summing modes are achieved, you will likely have to get + the images lined up using sample and line offsets. This is done via the + SHIFTDEF parameter. Further adjustments should be considered. For + example, now a much large portion of the images are overlapping. You + may wish to specify 3 columns, evenly spaced, to register. Set the + COLUMNS and ROWS parameters appropriately. +

    + + + + Mars Reconnaissance Orbiter + + + + + autoregtemplate + coreg + + + + Automatic Registration in Isis 3.0 + + + + + + + Original Version + + + Added CNETFILE parameter to provide easier input into transform + applications such as the 1-D transform anticipated to operate on + the results of this application. + + + Added specification of reference image in the control net file to + support subsequent use (e.g., 1-D transform). + + + Documentation fixes + + + Modified calls to get current time to use Time class, instead of + Application class + + + Modified to conform to changes made to SerialNumber + + + Added support for noproj'ed files. The files are required to + have a summing mode of 1. Support for noproj'ed files with + other summing modes will be added later. Noproj'ed files are + also required to have 20000 samples. This will be fixed later. + + + Modified program so that noproj'ed files are no longer + required to have a summing mode of 1. Support was also added + for noproj'ed IR and BG files. + + + Modified program to look at the PixelPitch keyword in the + Instrument group of noproj'ed images to determine what the + summing mode is. The PixelPitch value is divided by .012 + to calculate the summing mode. + + + Updated to properly check AutoReg::Register()'s return status + + + Updated to work with Geos 3.0.0 + + + Auto registration parameters are now placed into the print file. + + + + + + + cube + input + + HiRISE image that will have line/sample offsets computed for + + + This cube will be registered to the MATCH cube and corresponds to + the search chip (the larger sized chip). This file can be either a stitched + CCD or an individual CCD channel. If a channel is provided, be sure it + one that shares common overlap with the MATCH cube. + + + *.cub + + + + + cube + input + + HiRISE image that will contain the pattern to match the FROM image + + + This HiRISE cube will be held fixed in the registration process. The + FROM cube will be translated to match this cube. + It corresponds to the pattern chip (the smaller sized chip). + This file can be either a stitched + CCD or an individual CCD channel. If a channel is provided, be sure it + one that shares common overlap with the FROM cube. + + + *.cub + + + + + filename + input + + The Auto Registration template + + + The registration template for correlations. Default will be MaximumCorrelation function + with a tolerance of 0.7, a search chip of 30X70 pixels, and a pattern chip of 17X45 pixels. + There may also be other templates available in the default MRO directory as well as + the base templates directory, $base/templates/autoreg. + + + *.def + + $mro/calibration/hijitreg.p1745.s3070.def + $mro/calibration + + + + filename + input + None + + Pvl file containing absolute shifts for CCD lines and samples. + + +

    + For convenience and consistancy, the same offset file used in + the hiccdstitch application can be used here to specify line and + sample offsets for each HiRISE CCD. The documentation below + is the same as it is for hiccdstitch. +

    +

    + This file contains groups for each CCD that requires a + modification to its placement into the HiRISE + focal plane. The name of each group is the CCD name for + which the shift in line or sample is needed. For example, the + leftmost CCD, CCD 0 is named "RED0", the next "RED1" and + so on. hiccdstitch searches for names of groups that match + the stitched input cube files and will apply offsets to the + default sample and line location of where the CCD is mapped to + in the focal plane. +

    +

    + Offsets for both line and sample can be supplied. None, one or + both can be provided for any CCD. Negative values shift the + image left if a sample offset is given or up if a line offset is given. + Positive values in sample and line shift the image right and down, + respectively. +

    +

    + These shifts are absolute shifts and only apply to + the specified CCD and are not propagated to subsequent CCDs + left to right in the focal plane layout. (HiRISE CCD arrangement + is always left to right as far as hijitreg is concerned.) +

    +

    + Below is an example of the format of the input file for the + SHIFTDEF file: +

    +
    +            Object = Hiccdstitch
    +              Group = RED0
    +                SampleOffset     = -10
    +                LineOffset       = 5
    +              End_Group
    +
    +              Group = RED3
    +                SampleOffset     = 13
    +                LineOffset       = -5
    +              End_Group
    +
    +              Group = RED5
    +                LineOffset       = 22
    +              End_Group
    +
    +               Group = IR11
    +                SampleOffset     = -4
    +                LineOffset       = 2
    +              End_Group
    +
    +              Group = BG12
    +                SampleOffset     = 12
    +              End_Group
    +            End_Object
    +            End
    +            
    +

    + The only keywords that hiccdstitch reads from this file + are SampleOffset and LineOffset. All + other keywords are ignored. Note that groups named + by CCD name must exist as well as all specified groups + must be contained within the Hiccdstitch object. +

    +

    + Note that this file is an optional parameter. If it is not + provided, then all CCD files provided are mapped to + focal plane positions as specified in the HiRISE + Instrument Operations Handbook. The size + of a HiRISE pixel is 0.012 millimeters and the measurements + in the handbook are also in millimeters. +

    +
    + + *.def + + $mro/calibration +
    +
    + + + + integer + + Number of Rows of grid points to use. + + + The number of rows of grid points to use in the registration + process. If not entered, it will default to + ROWS = (lines of overlap - 1) / search chip lines + 1. + + Automatic + 1 + + + + integer + + Number of Columns grids points to register. + + + The number of columns of grid points to use in the registration process. + If not entered, the default is set to 1. This assumes we are registering + adjacent CCD overlap. The user can have the application compute the + number of grid columns similar to how ROWS is done. To use this + option, set COLUMNS = 0. The application will then compute + the number of grid columns as + COLUMNS = (samples of overlap - 1) / search chip samples + 1. + + 1 + 0 + + + + + + filename + output + + Text file of registration data + + +

    + This file will contain the data collected from the application. + Data pertaining to the input images that may have relevance + to the analysis is provided in free form. This includes lines, + samples, offsets, CPMM number, summing, TDI mode, overlap + and timing information. In addition, there is registration data + included such as sample and line spacing (which is typically + a single column), registration algorithm and tolerances and + the results of the correlation processing. +

    +

    + In addition to the above general information, a table of information + follows where each row contains registration information for each + chip. There are 12 columns of data for each chip (row). Below is + a description of each column: +

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Column description for FLATFILE data
    HeadingColumn Description
    FromTime + The time the line in the FROM image was observed + (scanned) expressed in ephemeris time +
    FromSamp + Image sample in the FROM file of the center of + the correlation chip +
    FromLine + Image line in the FROM file of the center of the + correlation chip +
    MatchTime + The time the line in the MATCH image was observed + (scanned) expressed in ephemeris time +
    MatchSamp + Image sample in the MATCH file of the center of + the correlation chip +
    MatchLine + Image line in the MATCH file of the center of the + correlation chip +
    RegSamp + Best registering sample in the FROM file resulting + from the correlation. +
    RegLine + Best registering line in the FROM file resulting + from the correlation +
    RegCorr + Correlation coefficient of the best registering sample + and line in the FROM file. This will typically be between + 1.0 and -1.0. NOTE: At times these values can + be wildly huge, as indicated by the NSuspects + log file keyword. This typically indicates the specified + search chip is not large enough. Inspect the + registering sample and line to determine which size + to increase and rerun the correlation. +
    B0_Offset + This is the offset in the linear regression analysis of the + best registering chip +
    B1_Slope + This is the slope in the linear regression analysis of the + best registering chip +
    B_RCorr + This is the correlation coefficient resulting from the linear + regression analysis of the best registering chip in the FROM + image compared to the corresponding area from the MATCH + chip. The Linear Regression equation is: +
    +                                  y = B0_Offset + B1_Slope * x
    +                              
    + Here, y is the output FROM Dn and x is the + FROM input Dn. In theory, one could use poly to + apply this to the FROM image and it will adjust FROM + to look closer to MATCH in brightness levels. +
    +

    +

    + Linear regression analysis is performed on each chip. The best + registering sample and line is computed at the sub-pixel level (this + can be modified in the REGDEF file). The best registered chip + is read from the FROM file at the subpixel level and compared + with the correlated search chip in the MATCH file. +

    + +
    + None + + *.txt *.lis *.lst + +
    + + + filename + output + + Crontrol net file for input into transform applications + + + This file will contain the ControlNet created in the hijitreg application. The data + will be in Pvl format. This option is required if the subsequent transformations of + the FROM files is desired. hijitreg is specifically designed to apply a 1-D + transform that shifts each line in the line and sample direction as indicated in + the control net. + + None + + *.txt *.lis *.lst + + +
    +
    + diff --git a/isis/src/mro/apps/hijitreg/tsts/Makefile b/isis/src/mro/apps/hijitreg/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hijitreg/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hijitreg/tsts/default/Makefile b/isis/src/mro/apps/hijitreg/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..92c64d6ec047679703e2b8214231eb429894b94c --- /dev/null +++ b/isis/src/mro/apps/hijitreg/tsts/default/Makefile @@ -0,0 +1,12 @@ +APPNAME = hijitreg + +include $(ISISROOT)/make/isismake.tsts + +PSP_001446_1790_RED.flat.txt.IGNORELINES = RunDate: FROM MATCH RegFile +PSP_001446_1790_RED.net.txt.IGNORELINES = Created UserName LastModified + +commands: + $(APPNAME) from=$(INPUT)/PSP_001446_1790_RED2.balance.cub \ + match=$(INPUT)/PSP_001446_1790_RED3.balance.cub \ + flatfile=$(OUTPUT)/PSP_001446_1790_RED.flat.txt \ + cnetfile=$(OUTPUT)/PSP_001446_1790_RED.net.txt > /dev/null diff --git a/isis/src/mro/apps/hijitter/Makefile b/isis/src/mro/apps/hijitter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hijitter/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hijitter/hijitter.cpp b/isis/src/mro/apps/hijitter/hijitter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b8b2c393b70d5bef088a4aa8c1092592b97b8e4 --- /dev/null +++ b/isis/src/mro/apps/hijitter/hijitter.cpp @@ -0,0 +1,358 @@ +#include "Isis.h" + +#include "UserInterface.h" +#include "FileList.h" +#include "Pipeline.h" +#include "SpecialPixel.h" +#include "TextFile.h" +#include "Camera.h" +#include "CameraDetectorMap.h" +#include "CameraFactory.h" + +using namespace std; +using namespace Isis; + +vector redFiles; +vector tempFiles; +int firstFilter; +int numFiles; +Filename FindRed(FileList &inList, int n); +void ProcessNoprojFiles(Pipeline &p); + +// avgOffsets[i][Sample = 0, Line = 1] +// where i is in the table just above +// lineOff's declaration +double avgOffsets[9][2]; + +/* + lineoff table +------------------------ + i | ccd-ccd | lineoff[i] +------------------------ + 0 | 0-1 | 574 + 1 | 1-2 | -622 + 2 | 2-3 | 620 + 3 | 3-4 | -586 + 4 | 4-5 | 584 + 5 | 5-6 | -600 + 6 | 6-7 | 597 + 7 | 7-8 | -576 + 8 | 8-9 | 607 +*/ +const double lineOff[9] = { + 574, + -622, + 620, + -586, + 584, + -600, + 597, + -576, + 607 +}; + +void IsisMain() { + // Initialize globals + redFiles.clear(); + tempFiles.clear(); + + // Get user interface + UserInterface &ui = Application::GetUserInterface(); + + FileList inputList(ui.GetFilename("FROMLIST")); + + // We dont actually need all 10... so dont do this exception + //if(inputList.size() != 10) { + // iString msg = "Input list file must have 10 entries, one for each CCD (0 to 9)"; + // throw iException::Message(iException::User, msg, _FILEINFO_); + //} + + int masterFileNum = ui.GetInteger("MASTER"); + + // This will initialize our global variables + FindRed(inputList, masterFileNum); + + if(masterFileNum - firstFilter > numFiles || masterFileNum - firstFilter < 0) { + iString msg = "Input list does not contain the MASTER [RED" + iString(masterFileNum) + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + Pipeline matchfilePipeline("hijitter - match"); + + matchfilePipeline.SetInputFile(FindRed(inputList, masterFileNum)); + matchfilePipeline.SetOutputFile(Filename("$TEMPORARY/matchMaster.cub")); + tempFiles.push_back(Filename("$TEMPORARY/matchMaster.cub").Expanded()); + + matchfilePipeline.KeepTemporaryFiles(false); + + matchfilePipeline.AddToPipeline("cubeatt"); + matchfilePipeline.Application("cubeatt").SetInputParameter("FROM", true); + matchfilePipeline.Application("cubeatt").SetOutputParameter("TO", "copy"); + + matchfilePipeline.AddToPipeline("spiceinit"); + matchfilePipeline.Application("spiceinit").SetInputParameter("FROM", false); + matchfilePipeline.Application("spiceinit").AddConstParameter("ATTACH", "NO"); + + matchfilePipeline.AddToPipeline("spicefit"); + matchfilePipeline.Application("spicefit").SetInputParameter("FROM", false); + + matchfilePipeline.Run(); + + Pipeline p("hijitter"); + + p.SetInputListFile("FROM"); + p.SetOutputFile(Filename("$TEMPORARY/noproj")); + + for(int i = 0; i < numFiles; i++) { + tempFiles.push_back( + Filename("$TEMPORARY/noproj.FROM" + iString(i+1) +".noproj.cub").Expanded() + ); + } + + p.KeepTemporaryFiles(false); + + p.AddToPipeline("cubeatt"); + p.Application("cubeatt").SetInputParameter("FROM", true); + p.Application("cubeatt").SetOutputParameter("TO", "copy"); + + p.AddToPipeline("spiceinit"); + p.Application("spiceinit").SetInputParameter("FROM", false); + p.Application("spiceinit").AddConstParameter("ATTACH", "NO"); + + p.AddToPipeline("appjit"); + p.Application("appjit").SetInputParameter("FROMLIST", PipelineApplication::LastAppOutputListNoMerge, false); + p.Application("appjit").AddParameter("JITTER", "JITTER"); + p.Application("appjit").AddParameter("DEGREE", "DEGREE"); + + p.AddToPipeline("noproj"); + p.Application("noproj").SetInputParameter("FROM", true); + p.Application("noproj").AddConstParameter("MATCH", Filename("$TEMPORARY/matchMaster.cub").Expanded()); + p.Application("noproj").SetOutputParameter("TO", Filename("$TEMPORARY/noproj").Expanded()); + + p.Prepare(); + + iString masterFile = p.Application("cubeatt").GetOutputs()[masterFileNum - firstFilter]; + p.Application("appjit").AddConstParameter("MASTER", masterFile); + + p.Run(); + + + // the outputs are temporary files + for(int redNum = 0; redNum < numFiles; redNum++) { + tempFiles.push_back(Filename("$TEMPORARY/noproj.FROM" + iString(redNum+1) + ".cub").Expanded()); + } + + // Do some calculations, delete the final outputs from the pipeline + ProcessNoprojFiles(p); + + p.SetOutputListFile("TO"); + p.Application("noproj").SetOutputParameter("TO", "jitter"); + + p.Prepare(); + + masterFile = p.Application("cubeatt").GetOutputs()[masterFileNum - firstFilter]; + p.Application("appjit").AddConstParameter("MASTER", masterFile); + + p.Run(); + + + for(unsigned int tempFile = 0; tempFile < tempFiles.size(); tempFile++) { + remove(tempFiles[tempFile].c_str()); + } + + tempFiles.clear(); + redFiles.clear(); +} + +/** + * This method will initialize global variables when it is + * called for the first time and will return the filename of CCD n given + * the file list. + * + * @param inList Input file list + * @param n Red CCD to return + * + * @return Filename Name of the CCD file + */ +Filename FindRed(FileList &inList, int n) { + iString nonMroFile = ""; + + if(n > 9 || n < 0) { + iString msg = "Parameter n must be [0-9] but found [" + iString(n) + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + if(!redFiles.empty() && redFiles[n].empty()) { + iString msg = "Filter [RED" + iString(n) + "] is not in the input list"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + if(!redFiles.empty()) return redFiles[n]; + redFiles.resize(10); + numFiles = 0; + + int lastRedNum = -1; + for(unsigned int i = 0; nonMroFile.empty() && i < inList.size(); i++) { + try { + Pvl labels(Filename(inList[i]).Expanded()); + PvlGroup &inst = labels.FindGroup("Instrument", Pvl::Traverse); + + string redNum = ((string)inst["CcdId"]).substr(3); + int redNumber = (int)(iString)redNum; + + if(redNumber < 0 || redNumber > 9) { + iString msg = "CcdId value of [" + redNum + "] found in [" + inList[i] + "] not supported"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + if(lastRedNum == -1) { + lastRedNum = redNumber; + firstFilter = redNumber; + numFiles ++; + } + else if(lastRedNum + 1 == redNumber) { + lastRedNum = redNumber; + numFiles ++; + } + else { + iString msg = "The input file list must be in order from RED0 to RED9"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + redFiles[redNumber] = inList[i]; + } + catch (iException &e) { + nonMroFile = inList[i]; + } + } + + if(!nonMroFile.empty()) { + iString message = "File [" + nonMroFile + "] is not a valid MRO cube"; + throw iException::Message(iException::User, message, _FILEINFO_); + } + + // Look for missing files + bool foundFirstFile = false; + bool foundLastFile = false; + for(unsigned int i = 0; i < redFiles.size(); i++) { + if(!foundFirstFile && !redFiles[i].empty()) { + foundFirstFile = true; + } + else if(foundFirstFile && !foundLastFile && redFiles[i].empty()) { + foundLastFile = true; + } + else if(foundFirstFile && foundLastFile && !redFiles[i].empty()) { + iString msg = "Filter [RED" + iString((int)i) + "] is not consecutive"; + } + } + + return FindRed(inList, n); +} + +void ProcessNoprojFiles(Pipeline &p) { + UserInterface &ui = Application::GetUserInterface(); + + // This will be decremented on error, it's easier this way + int count = numFiles-1; + + for(int i = 0; i < numFiles-1; i++) { + iString tempDir = Filename("$TEMPORARY").Expanded(); + iString flatFileLoc = tempDir + "/first" + iString(firstFilter+i) + "-" + iString(firstFilter+i+1) + ".flat"; + + iString params = "FROM=" + tempDir + "/noproj.FROM" + iString(i+1) + ".cub"; + params += " MATCH=" + tempDir + "/noproj.FROM" + iString(i+2) + ".cub"; + params += " REGDEF=" + ui.GetFilename("REGDEF"); + params += " FLAT=" + flatFileLoc; + + try { + Isis::iApp->Exec("hijitreg", params); + } + catch (iException &e) { + e.Clear(); + count --; + continue; + } + + // Read offsets + + TextFile flatFile(flatFileLoc); + tempFiles.push_back(flatFileLoc); + + string line; + avgOffsets[i][0] = Isis::Null; + avgOffsets[i][1] = Isis::Null; + + try { + while(flatFile.GetLine(line, false) && + (avgOffsets[i][0] == Isis::Null || avgOffsets[i][1] == Isis::Null)) { + line = iString(line).Compress(); + string::size_type pos = line.find("Average Sample Offset: "); + + if(pos != string::npos) { + // cut off text before our number (start pos + strlen + 1) + line = line.substr(pos + strlen("Average Sample Offset: ")); + + // cut off text after our number + line = line.substr(0, line.find(" ")); + + avgOffsets[i][0] = (double)(iString)line; + pos = string::npos; + } + + pos = line.find("Average Line Offset: "); + + if(pos != string::npos) { + // cut off text before our number (start pos + strlen + 1) + line = line.substr(pos + strlen("Average Line Offset: ")); + + // cut off text after our number + line = line.substr(0, line.find(" ")); + + avgOffsets[i][1] = (double)(iString)line; + pos = string::npos; + } + } + } + catch(iException &e) { + //iString msg = "Unable to find average sample/line offsets in hijitreg results for CCDs [" + iString(i) + "-" + iString(i+1) + "]"; + //throw iException::Message(iException::Programmer, msg, _FILEINFO_); + count --; + e.Clear(); + } + } + + if(count <= 0) { + iString msg = "Unable to calculate average sample/line offsets from hijitreg results"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + Pvl labels(Filename("$TEMPORARY/noproj.FROM1.cub").Expanded()); + Camera *cam = CameraFactory::Create(labels); + + double lineRate = cam->DetectorMap()->LineRate(); + + delete cam; + cam = NULL; + + // pitchRate (radians/sec) = 0.000001 * + // sum(averageLineOffset[i]/(lineOff[i] * lineRate) / 9., + // where i = (0,8), averageLineOffset[i] is the lineOffset from first0-1.flat, + // lineOff[i] is listed in table below. + double pitchRate = 0.0; + + // yaw (radians) = sum( arctan(averageSampleOffset[i])/lineOff[i]) / 9., + // where i = (0,8), the angles are small enough that the arctan is optional, + // averageSampleOffset[i] is the sampleOffset from first0-1.flat, + double yaw = 0.0; + + for(int i = 0; i < numFiles; i++) { + if(IsSpecial(avgOffsets[i][0]) || IsSpecial(avgOffsets[i][1])) continue; + + pitchRate += 0.000001 * (avgOffsets[i][1] / (lineOff[i] * lineRate)) / (double)count; + yaw += atan( avgOffsets[i][0] / lineOff[i] ) / (double)count; + } + + p.Application("appjit").AddConstParameter("PITCHRATE", iString(pitchRate)); + p.Application("appjit").AddConstParameter("YAW", iString(yaw)); +} + diff --git a/isis/src/mro/apps/hijitter/hijitter.xml b/isis/src/mro/apps/hijitter/hijitter.xml new file mode 100644 index 0000000000000000000000000000000000000000..c8de0b1ec71622a7a189968897ab86f695734be7 --- /dev/null +++ b/isis/src/mro/apps/hijitter/hijitter.xml @@ -0,0 +1,143 @@ + + + + + Correct jitter in input cubes and output corrected undistorted cubes + + + + This application computes angular corrections from pixel offsets in the + input jitter file and applies the corrections to the undistorted output + cube. This application is procedural in that it runs other applications. + It runs through a series of applications twice. The first time it applies + the jitter corrections and calculates additional pitch rate and yaw angles + to center the remaining camera pointing errors around zero. The output + cube files are deleted and the series of applications is run again, + including the additional pitch rate and yaw corrections. + + The first step it performs is to run spiceinit on all the FROMLIST cubes + with the parameter attach=no. A version of the MASTER file is saved and + run through the application spicefit to remove noise in the camera + pointing. This file will be used in the noproj runs as the match cube. + The next application run is appjit and it needs to load the Spice from the + files directly in order have access to Spice information not typically + stored on the Isis cube labels. This application applies the corrections + from the JITTER file to the camera pointing in the FROMLIST cubes. Now the + FROMLIST cubes are run through noproj, removing the jitter from the pixel + positions and the camera distortion. The results are measured on adjacent + ccd's by the application hijitreg and used to compute the additional pitch + rate and yaw required to center the errors around zero. + + Now the procedure is repeated with the calculated pitch and yaw passed into + appjit as input parameters. The jitter-reduced and distortion-free output + cubes are created by the final set of noproj runs on adjacent ccd's. + + + + Mars Reconnaissance Orbiter + + + + + Original Version + + + Added documentation + + + + + + + filename + input + + Cubes to correct + + + This file is a list of the file specifications for the input cubes all + from the save observation and containing pointing errors due to jitter + modeled by the pixel offsets in the JITTER file. + + + *.lis + + + + + filename + input + + Ascii table of pixel offsets representing jitter for a given time + + + The file specification of the Ascii table of pixel offsets modeling + the jitter errors in the camera pointing based on time. The table has + three columns: sampleOffset, lineOffset, and ephemerisTimeSeconds. + + + *.txt + + + + + filename + input + + The Auto Registration template used in hijitreg + + + The registration template for correlating the overlapping input cubes + of the observation. See hijitreg for more information. + + + *.txt + + + + + filename + output + + The list of the corrected undistorted cubes to be created + + + This list of output files should contain a file to correspond to each + input file. The output files will have both the jitter removed, as + modeled in the input JITTER file, and camera distortions by the + application noproj. The MASTER file with its camera pointing adjusted + by the application spicefit, will be used as the MATCH file in noproj + + Automatic + + + + + + integer + 0 + 9 + + The file to use as the MASTER + + + The application appjit applies the jitter corrections to the + camera pointing in the MASTER file first and then copies it to the + other files in the FROMLIST. The MASTER file is also used as the + MATCH file in the application NOPROJ + + 5 + + + integer + + The degree of fit used in appjit + + + Enter the degree of the polynomial to fit to the data + + 2 + + + + diff --git a/isis/src/mro/apps/hijitter/tsts/Makefile b/isis/src/mro/apps/hijitter/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hijitter/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hijitter/tsts/default/Makefile b/isis/src/mro/apps/hijitter/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0578f68bc5deecf958091ca8406e5a14a9d2d77a --- /dev/null +++ b/isis/src/mro/apps/hijitter/tsts/default/Makefile @@ -0,0 +1,12 @@ +APPNAME = hijitter + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) $(INPUT)/*.cub > $(OUTPUT)/files.lis; + $(CP) $(INPUT)/*.cub $(OUTPUT)/; + $(LS) $(OUTPUT)/*.cub > $(OUTPUT)/outlist.lis; + $(APPNAME) FROMLIST=$(OUTPUT)/files.lis MASTER=5 \ + JITTER=$(INPUT)/PSP_007556_2010.cropped.txt \ + REGDEF=$(INPUT)/hijitreg.p0745.s1570.def TO=$(OUTPUT)/outlist.lis > /dev/null ; + $(RM) $(OUTPUT)/files.lis $(OUTPUT)/outlist.lis > /dev/null; diff --git a/isis/src/mro/apps/himos/Makefile b/isis/src/mro/apps/himos/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/himos/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/himos/himos.cpp b/isis/src/mro/apps/himos/himos.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c74770a066b5260fa311e91fc498100b0d7dbe6 --- /dev/null +++ b/isis/src/mro/apps/himos/himos.cpp @@ -0,0 +1,316 @@ +#include "Isis.h" +#include "Process.h" +#include "FileList.h" +#include "iException.h" +#include "Cube.h" +#include "Camera.h" +#include "UserInterface.h" +#include "Pvl.h" +#include "Application.h" +#include "iString.h" +#include "OriginalLabel.h" + + +using namespace std; +using namespace Isis; + +#include + +//functions in the code +void CompareLabels(Pvl &match, Pvl &comp); + + +void IsisMain() { + + // Get the list of cubes to mosaic + + UserInterface &ui = Application::GetUserInterface(); + FileList flist(ui.GetFilename("FROMLIST")); + + + vector clist; + try { + if (flist.size() < 1) { + string msg = "the list file [" +ui.GetFilename("FROMLIST") + + "does not contain any data"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // open all the cube and place in vector clist + + for (int i=0; i<(int)flist.size(); i++) { + Cube *c = new Cube(); + clist.push_back(c); + c->Open(flist[i]); + } + + + + // run the compair function here. This will conpair the + // labels of the first cube to the labels of each following cube. + PvlKeyword sourceProductId("SourceProductId"); + string ProdId; + for (int i=0; i<(int)clist.size(); i++) { + Pvl *pmatch = clist[0]->Label(); + Pvl *pcomp = clist[i]->Label(); + CompareLabels(*pmatch, *pcomp); + PvlGroup g = pcomp->FindGroup("Instrument",Pvl::Traverse); + if (g.HasKeyword("StitchedProductIds")) { + PvlKeyword k = g["StitchedProductIds"]; + for (int j=0; j<(int)k.Size(); j++) { + sourceProductId += g["stitchedProductIds"][j]; + } + } + ProdId = (string)pmatch->FindGroup("Archive",Pvl::Traverse)["ObservationId"]; + iString bandname = (string)pmatch->FindGroup("BandBin",Pvl::Traverse)["Name"]; + bandname = bandname.UpCase(); + ProdId = ProdId + "_" + bandname; + } + bool runXY=true; + + //calculate the min and max lon + double minLat = DBL_MAX; + double maxLat = -DBL_MAX; + double minLon = DBL_MAX; + double maxLon = -DBL_MAX; + double avgLat; + double avgLon; + for (int i=0; i<(int)clist.size(); i++) { + Projection *proj = clist[i]->Projection(); + if (proj->MinimumLatitude() < minLat) minLat = proj->MinimumLatitude(); + if (proj->MaximumLatitude() > maxLat) maxLat = proj->MaximumLatitude(); + if (proj->MinimumLongitude() < minLon) minLon = proj->MinimumLongitude(); + if (proj->MaximumLongitude() > maxLon) maxLon = proj->MaximumLongitude(); + } + avgLat = (minLat + maxLat) / 2; + avgLon = (minLon + maxLon) / 2; + Projection *proj = clist[0]->Projection(); + proj->SetGround(avgLat,avgLon); + avgLat = proj->UniversalLatitude(); + avgLon = proj->UniversalLongitude(); + + // Use camera class to get Inc., emi., phase, and other values + double Cemiss; + double Cphase; + double Cincid; + double ClocalSolTime; + double CsolarLong; + double CsunAzimuth; + double CnorthAzimuth; + for (int i=0; i<(int)clist.size(); i++) { + Camera *cam = clist[i]->Camera(); + if (cam->SetUniversalGround(avgLat,avgLon)) { + Cemiss = cam->EmissionAngle(); + Cphase = cam->PhaseAngle(); + Cincid = cam->IncidenceAngle(); + ClocalSolTime = cam->LocalSolarTime(); + CsolarLong = cam->SolarLongitude(); + CsunAzimuth = cam->SunAzimuth(); + CnorthAzimuth = cam->NorthAzimuth(); + runXY = false; + break; + } + } + + //The code within the if runXY was added in 10/07 to find an intersect with + //pole images that would fail when using projection set universal ground. + // This is run if no intersect is found when using lat and lon in + // projection space. + if (runXY) { + double startX = DBL_MAX; + double endX = DBL_MIN; + double startY = DBL_MAX; + double endY = DBL_MIN; + for (int i=0; i<(int)clist.size(); i++) { + Projection *proj = clist[i]->Projection(); + proj->SetWorld(0.5,0.5); + if (i==0) { + startX = proj->XCoord(); + endY = proj->YCoord(); + } + else { + if (proj->XCoord() < startX) startX = proj->XCoord(); + if (proj->YCoord() > endY) endY = proj->YCoord(); + } + Pvl *p = clist[i]->Label(); + double nlines = p->FindGroup("Dimensions",Pvl::Traverse)["Lines"]; + double nsamps = p->FindGroup("Dimensions",Pvl::Traverse)["Samples"]; + + proj->SetWorld((nsamps+0.5),(nlines+0.5)); + if (i==0) { + endX = proj->XCoord(); + startY = proj->YCoord(); + } + else { + if (proj->XCoord() > endX) endX = proj->XCoord(); + if (proj->YCoord() < startY) startY = proj->YCoord(); + } + } + + double avgX = (startX + endX) / 2; + double avgY = (startY + endY) / 2; + double sample = proj->ToWorldX(avgX); + double line = proj->ToWorldY(avgY); + + for (int i=0; i<(int)clist.size(); i++) { + Camera *cam = clist[i]->Camera(); + if (cam->SetImage(sample,line)) { + Cemiss = cam->EmissionAngle(); + Cphase = cam->PhaseAngle(); + Cincid = cam->IncidenceAngle(); + ClocalSolTime = cam->LocalSolarTime(); + CsolarLong = cam->SolarLongitude(); + CsunAzimuth = cam->SunAzimuth(); + CnorthAzimuth = cam->NorthAzimuth(); + runXY = false; + break; + } + } + } + if (runXY) { + string msg = "Camera did not intersect images to gather stats"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // get the min and max SCLK values ( do this with string comp.) + // get the value from the original label blob + string startClock; + string stopClock; + string startTime; + string stopTime; + for (int i=0; i<(int)clist.size(); i++) { + OriginalLabel origLab; + clist[i]->Read(origLab); + PvlGroup timegrp = origLab.ReturnLabels().FindGroup("TIME_PARAMETERS",Pvl::Traverse); + if (i==0) { + startClock = (string)timegrp["SpacecraftClockStartCount"]; + stopClock = (string)timegrp["SpacecraftClockStopCount"]; + startTime = (string)timegrp["StartTime"]; + stopTime = (string)timegrp["StopTime"]; + } + else { + string testStartTime = (string)timegrp["StartTime"]; + string testStopTime = (string)timegrp["StopTime"]; + if (testStartTime < startTime) { + startTime = testStartTime; + startClock = (string)timegrp["SpacecraftClockStartCount"]; + } + if (testStopTime > stopTime) { + stopTime = testStopTime; + stopClock = (string)timegrp["spacecraftClockStopCount"]; + } + } + } + + // Concatenate all TDI's and summing and specialProcessingFlat into one keyword + PvlKeyword cpmmTdiFlag("cpmmTdiFlag"); + PvlKeyword cpmmSummingFlag("cpmmSummingFlag"); + PvlKeyword specialProcessingFlag("SpecialProcessingFlag"); + for (int i=0; i<14; i++) { + cpmmTdiFlag +=(string)""; + cpmmSummingFlag +=(string)""; + specialProcessingFlag +=(string)""; + } + + for (int i=0; i<(int)clist.size(); i++) { + Pvl *clab = clist[i]->Label(); + PvlGroup cInst = clab->FindGroup("Instrument",Pvl::Traverse); + OriginalLabel cOrgLab; + clist[i]->Read(cOrgLab); + PvlGroup cGrp = cOrgLab.ReturnLabels().FindGroup("INSTRUMENT_SETTING_PARAMETERS",Pvl::Traverse); + cpmmTdiFlag[(int)cInst["CpmmNumber"]] = (string) cGrp["MRO:TDI"]; + cpmmSummingFlag[(int)cInst["CpmmNumber"]] = (string) cGrp["MRO:BINNING"]; + + if (cInst.HasKeyword("Special_Processing_Flag")) { + specialProcessingFlag[cInst["CpmmNumber"]] = (string) cInst["Special_Processing_Flag"]; + } + else { + // there may not be the keyword Special_Processing_Flag if no + //keyword then set the output to NOMINAL + specialProcessingFlag[cInst["CpmmNumber"]] = "NOMINAL"; + } + } + + + // Get the blob of original labels from first image in list + OriginalLabel org; + clist[0]->Read(org); + + //close all cubes + for (int i=0; i<(int)clist.size(); i++) { + clist[i]->Close(); + delete clist[i]; + } + clist.clear(); + + // automos step + string list = ui.GetFilename("FROMLIST"); + string toMosaic = ui.GetFilename("TO"); + string MosaicPriority = ui.GetString("PRIORITY"); + + string parameters = "FROMLIST=" + list + " MOSAIC=" + toMosaic + " PRIORITY=" + MosaicPriority; + Isis::iApp ->Exec("automos",parameters); + + // write out new information to new group mosaic + + PvlGroup mos("Mosaic"); + mos += PvlKeyword("ProductId ", ProdId); + mos += PvlKeyword(sourceProductId); + mos += PvlKeyword("StartTime ", startTime); + mos += PvlKeyword("SpacecraftClockStartCount ", startClock); + mos += PvlKeyword("StopTime ", stopTime); + mos += PvlKeyword("SpacecraftClockStopCount ", stopClock); + mos += PvlKeyword("IncidenceAngle ", Cincid, "DEG"); + mos += PvlKeyword("EmissionAngle ", Cemiss, "DEG"); + mos += PvlKeyword("PhaseAngle ", Cphase, "DEG"); + mos += PvlKeyword("LocalTime ", ClocalSolTime, "LOCALDAY/24"); + mos += PvlKeyword("SolarLongitude ", CsolarLong, "DEG"); + mos += PvlKeyword("SubSolarAzimuth ", CsunAzimuth, "DEG"); + mos += PvlKeyword("NorthAzimuth ", CnorthAzimuth, "DEG"); + mos += cpmmTdiFlag; + mos += cpmmSummingFlag; + mos += specialProcessingFlag; + + Cube mosCube; + mosCube.Open(ui.GetFilename("TO"), "rw"); + PvlObject &lab=mosCube.Label()->FindObject("IsisCube"); + lab.AddGroup(mos); + //add orginal label blob to the output cube + mosCube.Write(org); + mosCube.Close(); + + } + catch (iException &e) { + for (int i=0; i<(int)clist.size(); i++) { + clist[i]->Close(); + delete clist[i]; + } + string msg = "The mosaic [" + ui.GetFilename("TO") + "] was NOT created"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } +} // end of isis main + +//Function to compare label - CompareLabels +void CompareLabels(Pvl &pmatch, Pvl &pcomp) { + // test of the ObservationId + PvlGroup matchgrp = pmatch.FindGroup("Archive",Pvl::Traverse); + PvlGroup compgrp = pcomp.FindGroup("Archive",Pvl::Traverse); + string obsMatch = matchgrp["ObservationId"]; + string obsComp = compgrp["ObservationId"]; + + if (obsMatch != obsComp) { + string msg = "Images not from the same observation"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Test of the BandBin filter name + PvlGroup bmatchgrp = pmatch.FindGroup("BandBin",Pvl::Traverse); + PvlGroup bcompgrp = pcomp.FindGroup("BandBin",Pvl::Traverse); + string bandMatch = bmatchgrp["Name"]; + string bandComp = bcompgrp["Name"]; + + if (bandMatch != bandComp) { + string msg = "Images not the same filter"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } +} diff --git a/isis/src/mro/apps/himos/himos.xml b/isis/src/mro/apps/himos/himos.xml new file mode 100644 index 0000000000000000000000000000000000000000..3e67fdc1966344a34d81d3667602f67449adb004 --- /dev/null +++ b/isis/src/mro/apps/himos/himos.xml @@ -0,0 +1,113 @@ + + + + + Produce an output mosaic of HiRISE CCD images from the same observation and filter. + + + +

    + ** The output from this program is required by hirdrgen **
    + If the final product wil not be an RDR, mapmos or automos can be used to produce a mosaic. + This program produces a mosaic and adds keywords to the label group "Mosaic" that are required + by hirdrgen.
    + + The input cubes to this program must be from the same observation, same filter, and map projected.
    + + A new label group, required by hirdrgen, called "Mosaic" is added to the image labels of + the output cube. The original label blob is also propagated from the first file in the input list.
    +

    + +

    + processing sequence for single filter products that will become RDRs
    + cam2map - project the cube. hicolormos requiers a map projected cube.
    + himos - mosaic files and add keywords to the mosaic group.
    + hirdrgen - produce a RDR product.
    +

    + +
    + + + Mars Reconnaissance Orbiter + + + + + Original version, + + + Changed OriginalLabel name to IsisCube + + + Added NothAzimuth, SubSolarAzimuth, and SpecialProcessingFlag keywords + to the output mosaic group + + + Added code to get the avg line and sample for gathering camera infomation if using the avg latitude and longitude fails. + We contine to use the latitude and logitude so that we are backwards compatible. We added this new code because + the camera could not find an itersect for some images (polar) if we used projection latitude and longitude to "setGround". + + + + + + + filename + input + + Input list of files + + + A single colume list of HiRISE CCD files that will be mosaiced together. The input + files must be from the some observation and be from the same filter. The files must also + be map projected. + + + *.lis *.lst *.txt + + + + + cube + output + + Output mosaic + + + the output mosaic cube with the new mosaic label group added.. + + + *.cub + + + + + string + + ONTOP + + The priority of pixel placement + + This parameter is used to select one of two ways to masaic the + pixels in areas of overlap. + + + + + + + + + +
    diff --git a/isis/src/mro/apps/himos/tsts/Makefile b/isis/src/mro/apps/himos/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/himos/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/himos/tsts/case01/Makefile b/isis/src/mro/apps/himos/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8ac16bff94666e365f845dec07f0291822adc529 --- /dev/null +++ b/isis/src/mro/apps/himos/tsts/case01/Makefile @@ -0,0 +1,10 @@ +APPNAME = himos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) -1 $(INPUT)/*.cub > $(OUTPUT)/cube.lis; + $(APPNAME) fromlist=$(OUTPUT)/cube.lis \ + to=$(OUTPUT)/test_himos_070418.cub > /dev/null; + catlab from=$(OUTPUT)/test_himos_070418.cub > $(OUTPUT)/himos.pvl; + $(RM) $(OUTPUT)/cube.lis; diff --git a/isis/src/mro/apps/himos/tsts/case02pole/Makefile b/isis/src/mro/apps/himos/tsts/case02pole/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7f20f5dcdeef79f4e901bd28d0edb5c09f33a878 --- /dev/null +++ b/isis/src/mro/apps/himos/tsts/case02pole/Makefile @@ -0,0 +1,10 @@ +APPNAME = himos + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(LS) -1 $(INPUT)/*.cub > $(OUTPUT)/cube.lis; + $(APPNAME) fromlist=$(OUTPUT)/cube.lis \ + to=$(OUTPUT)/test_himos_pole.cub > /dev/null; + catlab from=$(OUTPUT)/test_himos_pole.cub > $(OUTPUT)/himos_pole.pvl; + $(RM) $(OUTPUT)/cube.lis; diff --git a/isis/src/mro/apps/hinoise/Makefile b/isis/src/mro/apps/hinoise/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hinoise/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hinoise/hinoise.cpp b/isis/src/mro/apps/hinoise/hinoise.cpp new file mode 100644 index 0000000000000000000000000000000000000000..00ebe9488a1a882c664d6923a2e06f2900644d0a --- /dev/null +++ b/isis/src/mro/apps/hinoise/hinoise.cpp @@ -0,0 +1,323 @@ +#include "Isis.h" +#include +#include +#include "Filename.h" +#include "iException.h" +#include "Histogram.h" +#include "ProcessByLine.h" +#include "Pixel.h" + + +using namespace std; +using namespace Isis; + +// global Filenames // Perl script identifiers +string g_zapFilename; // tfile1 +string g_lpfFilename; // tfile1a +string g_hpfFilename; // tfile1b +string g_addFilename; // tfile1c +string g_noisefilter1Filename; // tfile2 +string g_noisefilter2Filename; // tfile2a +string g_noisefilter3Filename; // tfile2b +string g_lpfz1Filename; // tfile3 +string g_lpfz2Filename; // tfile3a +string g_isisnormFilenameSuffix = ""; // isisnorm + +// global data +vector g_validPixelCounts; +int g_maxValidPixelCount; +double g_nonValidFraction; +enum status { good, bad }; +vector g_columnStatus; + +// function prototypes +void defineFilenames(); +void getCounts(Buffer & in); +bool areaFailed(const pair & someArea); +void zapAllAreas(const pair areas[4]); +void applyColumnStatus(Buffer & in, Buffer & out); +void rmTempFiles(); + +void IsisMain() { + UserInterface & ui = Application::GetUserInterface(); + defineFilenames(); + + // *********** vertical destriping *********** + + // The idea here is that some columns in the input cube have too many invalid pixels + // where "too many invalid pixels" is defined by the user with the parameter + // NONVALIDFRACTION. If the cube's binning is anything other than 1 then all + // columns are checked. If a column has too many invalid pixels then every dn in + // that column is set to 0. If the binning is 1 then only columns in known problem + // areas (pause points) are checked. If one of these checked columns fails then + // every column in area has its valid dns set to NULL. After all this the resulting + // cube is run through lowpass and highpass with the results from each merged back + // together + + // First get valid pixel counts for all columns. + // Next get the maximum of these counts and the NONVALIDFRACTION. + // Then build a column status vector based on the cubes binning. + // - The column status vector has elements such that each element represents + // - a column of the cube and contains a value of either good if the column + // - is ok or bad if the column is out of tolerance. + // Finally use the column status vector to destripe the cube + // After all this run lowpass, highpass, and algebra for further destriping + + + // get valid pixel counts for all columns of the cube + ProcessByLine p; + Cube * inCube = p.SetInputCube("FROM"); + g_validPixelCounts.assign(inCube->Samples(), 0); + p.StartProcess(getCounts); + + // get the maximum count and the nonValidFraction + g_maxValidPixelCount = g_validPixelCounts[0]; + for (unsigned int i = 1; i < g_validPixelCounts.size(); i++) { + if (g_maxValidPixelCount < g_validPixelCounts[i]) { + g_maxValidPixelCount = g_validPixelCounts[i]; + } + } + g_nonValidFraction = ui.GetDouble("NONVALIDFRACTION"); + + // build column status vector + g_columnStatus.assign(inCube->Samples(), good); + int binning = inCube->GetGroup("Instrument").FindKeyword("Summing")[0]; + if (binning != 1) { + for (unsigned int i = 0; i < g_columnStatus.size(); i++) { + if ((double) g_validPixelCounts[i] / g_maxValidPixelCount < g_nonValidFraction) { + g_columnStatus[i] = bad; + } + } + } + else { + // First define the problem areas to be tested, which depend on what + // channel this cube happens to be. Each area is stored as a pair + // where the starting column is first and the ending column is second. + // The boundries defining an area are INCLUSIVE! + pair testAreas[4]; + int channel = inCube->GetGroup("Instrument").FindKeyword("ChannelNumber")[0]; + switch (channel) { + case 1: + testAreas[0].first = 241; + testAreas[0].second = 246; + testAreas[1].first = 505; + testAreas[1].second = 509; + testAreas[2].first = 768; + testAreas[2].second = 772; + testAreas[3].first = 1021; + testAreas[3].second = 1023; + break; + case 0: + testAreas[0].first = 0; + testAreas[0].second = 2; + testAreas[1].first = 251; + testAreas[1].second = 255; + testAreas[2].first = 514; + testAreas[2].second = 518; + testAreas[3].first = 777; + testAreas[3].second = 781; + break; + default: + // this should really never happen unless histitch was ran! + string message = "Cube has invalid channel number!\n"; + message += "valid channels are 0 and 1\n\n"; + message += "If this cube is the result of merging then\n"; + message += "it is too late for vertical destriping."; + throw Isis::iException::Message(Isis::iException::User, message, _FILEINFO_); + } + for (int k = 0; k < 4; k++) { + if (areaFailed(testAreas[k])) { + zapAllAreas(testAreas); + break; + } + } + } + + // Finally use the column status vector to zero the bad columns + CubeAttributeOutput atts; + p.SetOutputCube(g_zapFilename, atts, inCube->Samples(), inCube->Lines(), inCube->Bands()); + p.StartProcess(applyColumnStatus); + p.EndProcess(); + + // Now run lowpass, highpass, and algebra for further destriping + Isis::iApp->Exec("lowpass", "FROM=" + g_zapFilename + " TO=" + + g_lpfFilename + "+32bit NULL=FALSE HRS=FALSE HIS=FALSE LRS=FALSE LIS=FALSE LINE=" + + ui.GetString("LPFLINE") + " SAMP=" + ui.GetString("LPFSAMP") + + " MINOPT=PERCENT MINIMUM=" + ui.GetString("LPFMINPER") + + " REPLACE=NULL"); + Isis::iApp->Exec("highpass", "FROM=" + g_zapFilename + " TO=" + g_hpfFilename + + " LINE=" + ui.GetString("HPFLINE") + " SAMP=" + ui.GetString("HPFSAMP") + + " MINOPT=PERCENT" + " MINIMUM=" + ui.GetString("HPFMINPER")); + Isis::iApp->Exec("algebra", "FROM1=" + g_lpfFilename + " FROM2=" + + g_hpfFilename + " TO=" + g_addFilename + g_isisnormFilenameSuffix + " OPERATOR=ADD"); + + // ******** vertical destriping done ********* + + + // ************* noise filtering ************* + + // noise filters need FLATTOL, LOW, HIGH, TOLMIN, and TOLMAX parameters + // calculated first + + // get FLATTOL + Cube cube; + cube.Open(ui.GetFilename("FROM")); + Histogram * hist = cube.Histogram(); + double flattol = hist->StandardDeviation() * ui.GetDouble("FLATTOL"); + + // Get HIGH + double lisPixels = hist->LisPixels(); + double HardFiltering = ui.GetDouble("HARDFILTERING"); + double high; + double HardHighEnd = ui.GetDouble("HARDHIGHENDPERCENT"); + double HighEnd = ui.GetDouble("HIGHENDPERCENT"); + if (lisPixels > HardFiltering) { + high = hist->Percent(HardHighEnd); + } + else { + high = hist->Percent(HighEnd); + } + + // don't need hist anymore so close cube, + // which needs done now before noisefilter is called + cube.Close(); + + // get TOLMIN and TOLMAX + double tolmin = ui.GetDouble("TOLMIN"); + double tolmax = ui.GetDouble("TOLMAX"); + if (lisPixels >= HardFiltering) { + tolmin = ui.GetDouble("HARDTOLMIN"); + tolmax = ui.GetDouble("HARDTOLMAX"); + } + + // run first noise filter + Isis::iApp->Exec("noisefilter", "FROM=" + g_addFilename + " TO=" + g_noisefilter1Filename + + g_isisnormFilenameSuffix + " FLATTOL=" + iString(flattol) + " TOLDEF=STDDEV LOW=" + + ui.GetAsString("LOW") + " HIGH=" + iString(high) + " TOLMIN=" + iString(tolmin) + " TOLMAX=" + + iString(tolmax) + " REPLACE=NULL SAMPLE=" + ui.GetString("NOISESAMPLE") + " LINE=" + + ui.GetString("NOISELINE") + " LISISNOISE=true LRSISNOISE=true"); + + // run second noise filter + Isis::iApp->Exec("noisefilter", "FROM=" + g_noisefilter1Filename + " TO=" + + g_noisefilter2Filename + g_isisnormFilenameSuffix + " FLATTOL=" + iString(flattol) + + " TOLDEF=STDDEV LOW=" + ui.GetAsString("LOW") + " HIGH=" + iString(high) + " TOLMIN=" + + iString(tolmin) + " TOLMAX=" + iString(tolmax) + " REPLACE=NULL SAMPLE=" + + ui.GetString("NOISESAMPLE") + " LINE=" + ui.GetString("NOISELINE") + + " LISISNOISE=true LRSISNOISE=true"); + + // run third noise filter + Isis::iApp->Exec("noisefilter", "FROM=" + g_noisefilter2Filename + " TO=" + + g_noisefilter3Filename + g_isisnormFilenameSuffix + " FLATTOL=" + iString(flattol) + + " TOLDEF=STDDEV LOW=" + ui.GetAsString("LOW") + " HIGH=" + iString(high) + " TOLMIN=" + + iString(tolmin) + " TOLMAX=" + iString(tolmax) + " REPLACE=NULL SAMPLE=" + + ui.GetString("NOISESAMPLE") + " LINE=" + ui.GetString("NOISELINE") + + " LISISNOISE=true LRSISNOISE=true"); + + // ********** noise filtering done ********** + + + // ************** fill in holes ************** + + Isis::iApp->Exec("lowpass", "FROM=" + g_noisefilter3Filename + " TO=" + g_lpfz1Filename + + g_isisnormFilenameSuffix + " sample=3 line=3 minopt=COUNT minimum=3 filter=OUTSIDE" + + " null=TRUE hrs=FALSE his=TRUE lrs=TRUE lis=TRUE"); + + // if binning is not 1 then stop after next lowpass + string outFile = g_lpfz2Filename; + if (binning != 1) { + outFile = ui.GetFilename("TO"); + } + + // get minimum and use it for another lowpass + int lpfzsamples = ui.GetInteger("LPFZSAMPLES"); + int lpfzlines = ui.GetInteger("LPFZLINES"); + int minimum = (int) ((lpfzlines * lpfzsamples) / 3); + Isis::iApp->Exec("lowpass", "FROM=" + g_lpfz1Filename + " TO=" + outFile + + g_isisnormFilenameSuffix + " sample=" + iString(lpfzsamples) + " line=" + iString(lpfzlines) + " minopt=COUNT" + + " minimum=" + iString(minimum) + " filter=OUTSIDE null=TRUE hrs=FALSE his=TRUE " + + "lrs=TRUE lis=TRUE"); + + // ************** holes filled *************** + + // if binning is 1 then need to check pause point areas again + if (binning == 1) { + CubeAttributeInput atts; + ProcessByLine p2; + p2.SetInputCube(g_lpfz2Filename, atts); + p2.SetOutputCube("TO"); + p2.StartProcess(applyColumnStatus); + p2.EndProcess(); + } + + rmTempFiles(); + +} // of IsisMain() + +void defineFilenames() { + UserInterface & ui = Application::GetUserInterface(); + Filename fn; + fn.Temporary("hinoise-zap", "cub"); g_zapFilename = fn.Expanded(); + fn.Temporary("hinoise-lpf", "cub"); g_lpfFilename = fn.Expanded(); + fn.Temporary("hinoise-hpf", "cub"); g_hpfFilename = fn.Expanded(); + fn.Temporary("hinoise-add", "cub"); g_addFilename = fn.Expanded(); + fn.Temporary("hinoise-noisefilter1", "cub"); g_noisefilter1Filename = fn.Expanded(); + fn.Temporary("hinoise-noisefilter2", "cub"); g_noisefilter2Filename = fn.Expanded(); + fn.Temporary("hinoise-noisefilter3", "cub"); g_noisefilter3Filename = fn.Expanded(); + fn.Temporary("hinoise-lpfz1", "cub"); g_lpfz1Filename = fn.Expanded(); + fn.Temporary("hinoise-lpfz2", "cub"); g_lpfz2Filename = fn.Expanded(); + + if (ui.GetString("MINNORMALIZATION") != "Null" && ui.GetString("MAXNORMALIZATION") != "Null") { + g_isisnormFilenameSuffix = "+SignedWord+" + ui.GetString("MINNORMALIZATION") + ":" + + ui.GetString("MAXNORMALIZATION"); + } +} + +void getCounts(Buffer & in) { + // get the counts + for (unsigned int i = 0; i < g_validPixelCounts.size(); i++) { + if (Pixel::IsValid(in[i])) { + g_validPixelCounts[i]++; + } + } +} + + +bool areaFailed(const pair & someArea) { + for (int i = someArea.first; i <= someArea.second; i++) { + if ((double) g_validPixelCounts[i] / g_maxValidPixelCount < g_nonValidFraction) { + return true; + } + } + return false; +} + +void zapAllAreas(const pair areas[4]) { + for (int i = 0; i < 4; i++) { + for (int j = areas[i].first; j <= areas[i].second; j++) { + g_columnStatus[j] = bad; + } + } +} + +void applyColumnStatus(Buffer & in, Buffer & out) { + for (int i = 0; i < in.size(); i++) { + if (g_columnStatus[i] == bad && Pixel::IsValid(in[i])) { + out[i] = NULL8; + } + else { + out[i] = in[i]; + } + } +} + +void rmTempFiles() { + remove(g_zapFilename.c_str()); + remove(g_lpfFilename.c_str()); + remove(g_hpfFilename.c_str()); + remove(g_addFilename.c_str()); + remove(g_noisefilter1Filename.c_str()); + remove(g_noisefilter2Filename.c_str()); + remove(g_noisefilter3Filename.c_str()); + remove(g_lpfz1Filename.c_str()); + remove(g_lpfz2Filename.c_str()); +} diff --git a/isis/src/mro/apps/hinoise/hinoise.xml b/isis/src/mro/apps/hinoise/hinoise.xml new file mode 100644 index 0000000000000000000000000000000000000000..20bf2e0d9c2b1f56d03c0de1f263e2a69dee3edc --- /dev/null +++ b/isis/src/mro/apps/hinoise/hinoise.xml @@ -0,0 +1,279 @@ + + + + + + Check pause points and remove noise from HiRISE cubes. + + + + This application removes noise from HiRISE cubes. It also checks the + pause points and removes any artifacts there. + + + + Utility + + + + + Original version converted from Eric Eliason's Perl + + + + + + + cube + input + + Input file + + + Input cube to remove noise from + + + *.cub + + + + + cube + real + output + + Output file + + + Output cube with noise removed + + + + + + + + + string + 251 + lowpass LINES parameter + + This is the LINES parameter for lowpass. See the lowpass + application for details. + + + + + string + 3 + lowpass SAMPLES parameter + + This is the Samples parameter for lowpass. See the lowpass + application for details. + + + + + string + 5 + lowpass MINIMUM parameter (as a percentage) + + lowpass is called such that MINOPT=PERCENTAGE and MINIMUM is this + parameter here. See the lowpass application for details. + + + + + + + + + string + 251 + highpass LINES parameter + + This is the LINES parameter for highpass. See the highpass + application for details. + + + + + string + 1 + highpass SAMPLES parameter + + This is the SAMPLES parameter for highpass. See the highpass + application for details. + + + + + string + 5 + highpass MINIMUM parameter (as a percentage) + + highpass is called such that MINOPT=PERCENTAGE and MINIMUM is this + parameter here. See the lowpass application for details. + + + + + + + + string + 7 + noisefilter LINES parameter + + This is the LINES parameter for noisefilter. See the noisefilter + application for details. + + + + + string + 7 + noisefilter SAMPLES paramater + + This is the SAMPLES parameter for noisefilter. See the noisefilter + application for details. + + + + + double + 0.90 + Pause point tolerance fraction + + For each column of the cube a count is calculated of the number of + valid pixels in the column. If any columns count divided by the + maximum count is less than NONVALIDFRACTION then the pause points + are nulled out. If the binning is anything other than one then all + columns are checked with only the failing columns getting nulled out. + + + + + string + + Maximum normalization + + + + + + string + + Minimum normalization + + + + + + double + 3.5 + noisefilter TOLMIN parameter + + This is the TOLMIN parameter for noisefilter. See the noisefilter + application for details. + + + + + double + 3.5 + noisefilter TOLMAX parameter + + This is the TOLMAX parameter for noisefilter. See the noisefilter + application for details. + + + + + double + 0 + noisefilter LOW parameter + + This is the LOW parameter for noisefilter. See the noisefilter + application for details. + + + + + double + 0.1 + Percent of LIS pixels to switch to hard noise filtering + + Percent of LIS pixels to switch to hard noise filtering + + + + + double + 99.999 + Fraction of high-end pixels to zap + + Fraction of high-end pixels to zap + + + + + double + 99.99 + Fraction of high-end pixels to zap for hard noise filtering + + Fraction of high-end pixels to zap for hard noise filtering + + + + + double + 3.5 + noisefilter TOLMIN parameter for hard noise filtering + + Use this value for noisefilter's TOLMIN parameter when doing + hard noise filtering + + + + + double + 3.5 + noisefilter TOLMAX parameter for hard noise filtering + + Use this value for noisefilter's TOLMAX parameter when doing + hard noise filtering + + + + + double + 1 + noisefilter FLATTOL parameter + + This is the FLATTOL parameter for noisefilter. See the noisefilter + application for details. + + + + + integer + 5 + lowpass LINES parameter for LPFZ + + + + + + integer + 5 + lowpass SAMPLES parameter for LPFZ + + + + + + + + + diff --git a/isis/src/mro/apps/hinoise/tsts/Makefile b/isis/src/mro/apps/hinoise/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hinoise/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hinoise/tsts/binningIsOne/Makefile b/isis/src/mro/apps/hinoise/tsts/binningIsOne/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c6e07e1442a49899e07288bdadeb45134cb9fb9f --- /dev/null +++ b/isis/src/mro/apps/hinoise/tsts/binningIsOne/Makefile @@ -0,0 +1,13 @@ +APPNAME = hinoise + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/PSP_001853_1900_RED9_0.cub \ + to=$(OUTPUT)/PSP_001853_1900_RED9_0-binningIsOne.cub \ + > /dev/null; + + $(APPNAME) from=$(INPUT)/PSP_001853_1900_RED9_1.cub \ + to=$(OUTPUT)/PSP_001853_1900_RED9_1-binningIsOne.cub \ + > /dev/null; + diff --git a/isis/src/mro/apps/hinoise/tsts/binningNotOne/Makefile b/isis/src/mro/apps/hinoise/tsts/binningNotOne/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..dca9ef2a84f29e6a680dcaa5d640cda960461354 --- /dev/null +++ b/isis/src/mro/apps/hinoise/tsts/binningNotOne/Makefile @@ -0,0 +1,8 @@ +APPNAME = hinoise + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/PSP_001853_1900_BG12_0.cub \ + to=$(OUTPUT)/PSP_001853_1900_BG12_0-binningNotOne.cub \ + > /dev/null; diff --git a/isis/src/mro/apps/hirdr2isis/Makefile b/isis/src/mro/apps/hirdr2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hirdr2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hirdr2isis/hirdr2isis.cpp b/isis/src/mro/apps/hirdr2isis/hirdr2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d19d71f2b1227031cf9ac9ebf93bf1b6cdba08a --- /dev/null +++ b/isis/src/mro/apps/hirdr2isis/hirdr2isis.cpp @@ -0,0 +1,114 @@ +#include "Isis.h" + +#include +#include + +#include "ProcessImportPds.h" + +#include "UserInterface.h" +#include "Filename.h" +#include "Spice.h" + +using namespace std; +using namespace Isis; + +void IsisMain () +{ + ProcessImportPds p; + Pvl label; + UserInterface &ui = Application::GetUserInterface(); + + string labelFile = ui.GetFilename("FROM"); + + p.SetPdsFile (labelFile, "", label); + Cube *ocube = p.SetOutputCube("TO"); + + p.StartProcess (); + + // Get the mapping labels + Pvl otherLabels; + p.TranslatePdsProjection(otherLabels); + + // Get the directory where the MRO HiRISE RDR translation tables are. + PvlGroup dataDir (Preference::Preferences().FindGroup("DataDirectory")); + iString transDir = (string) dataDir["Mro"] + "/translations/"; + + // Translate the BandBin group + Filename transFile (transDir + "hiriseRdrBandBin.trn"); + PvlTranslationManager bandBinXlater (label, transFile.Expanded()); + bandBinXlater.Auto(otherLabels); + + // Translate the Mosaic group + transFile = transDir + "hiriseRdrMosaic.trn"; + PvlTranslationManager archiveXlater (label, transFile.Expanded()); + archiveXlater.Auto(otherLabels); + + // Write the BandBin, Archive, and Mapping groups to the output cube label + ocube->PutGroup(otherLabels.FindGroup("BandBin")); + + // Reorder CPMM keywords back to original arrangement. This copies the values + // back to keywords in place. + PvlGroup mosgrp = otherLabels.FindGroup("Mosaic"); + PvlKeyword &ccdFlag = mosgrp.FindKeyword("SpecialProcessingFlag"); + PvlKeyword &ccdBin = mosgrp.FindKeyword("cpmmSummingFlag"); + PvlKeyword &ccdTdi = mosgrp.FindKeyword("cpmmTdiFlag"); + + // Make temp copies of keywords + PvlKeyword tempccdFlag = ccdFlag; + PvlKeyword tempccdBin = ccdBin; + PvlKeyword tempccdTdi = ccdTdi; + const unsigned int cpmmByCcd[] = {0,1,2,3,5,8,10,11,12,13,6,7,4,9}; + for (int ccd=0; ccd<14; ++ccd) { + ccdFlag[cpmmByCcd[ccd]] = tempccdFlag[ccd]; + ccdBin[cpmmByCcd[ccd]] = tempccdBin[ccd]; + ccdTdi[cpmmByCcd[ccd]] = tempccdTdi[ccd]; + } + ocube->PutGroup(mosgrp); + +// Modify the output Mosaic group if the Projection is of type +// Equirectangular. + PvlGroup mapgrp = otherLabels.FindGroup("Mapping"); + if ( iString::UpCase(mapgrp["ProjectionName"]) == "EQUIRECTANGULAR" ) { + static bool pckLoaded(false); + if ( !pckLoaded ) { + Filename pck("$base/kernels/pck/pck?????.tpc"); + pck.HighestVersion(); + furnsh_c(pck.Expanded().c_str()); + pckLoaded = true; + } + + // Get the target and check for validity + PvlKeyword &target = label.FindKeyword("TargetName", PvlObject::Traverse); + SpiceInt tcode; + SpiceBoolean found; + (void) bodn2c_c(target[0].c_str(), &tcode, &found); + if (found) { + // Get radii and fix labels + SpiceInt n; + SpiceDouble radii[3]; + bodvar_c(tcode,"RADII",&n,radii); + + // Set existing radius to CenterLatitudeRadius + PvlKeyword &eqRadius = mapgrp.FindKeyword("EquatorialRadius"); + PvlKeyword &polRadius = mapgrp.FindKeyword("PolarRadius"); + + // Derive (copy, actually) the center radius from the equator radii and + // update the name + PvlKeyword clatrad = eqRadius; + clatrad.SetName("CenterLatitudeRadius"); + + // Assign the proper radii to the group keywords + eqRadius.SetValue(iString(radii[0]*1000.0), "meters"); + polRadius.SetValue(iString(radii[2]*1000.0), "meters"); + mapgrp += clatrad; // Don't do this before updating the above + // keyword references! Bad things happen! + } + } + + // Write the group to the label + ocube->PutGroup(mapgrp); + + p.EndProcess (); + + return; +} diff --git a/isis/src/mro/apps/hirdr2isis/hirdr2isis.xml b/isis/src/mro/apps/hirdr2isis/hirdr2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..31a2ecc9a2b51d4ade47a8be117a202bdec7421c --- /dev/null +++ b/isis/src/mro/apps/hirdr2isis/hirdr2isis.xml @@ -0,0 +1,98 @@ + + + + + Import PDS formatted HiRISE RDR image cube into Isis format cube + + +

    + This program will import a PDS formatted HiRISE RDR image into an Isis + cube. The normal generic application is pds2isis, however HiRISE + images require special consideration. These considerations are based upon + requirements placed on the process of converting original HiRISE ISIS + products into PDS archive format and back again. The HiRISE team requires + a certain level of preservation so that science analysis on the PDS + archived product, particularly in the ISIS system, is not compromised. +

    +

    + One consequence of the PDS storage requirements is the conversion of + ISIS data to unsigned 16-bit integers. This data storage type is not + support inherently in the ISIS system, but this application converts + it to the best data representation possible - 32-bit floating point + values. Comparisons of the conversion process falls within acceptable + precision loss (approximately 1.0E-6). +

    +

    + Much of what this program does is ensure labels are properly copied + and translated from PDS archival form that is consistant and highly + comparable to the original ISIS product. The strictest requirement is + label integrity which applies mainly to geometric datum contained in + the ISIS labels. The goal is to ensure geometric behavior is within + acceptable limits of the original product. +

    +
    + + + + Original version + + + The following modifications where made to more closely adhere to the + orginal ISIS himos source: map the PDS Archive group back to the + ISIS Mosaic group; PDS NULL values of -9998 are mapped back to + ISIS Null; order of the groups are written in the same order as the + ISIS input file; Target radius values are updated for the + Equirectangular projection only such that the existing + (EquatorialRadius) radius value is copied to the CenterLatitudeRadius + keyword and the actual NAIF radii replace EquatorialRadius and + PolarRadius values if it is a valid NAIF target; the order of the + values in keywords cpmmTdiFlag, cpmmSummingFlag and + SpecialProcessingFlag are reordered according to CPMM order as it is + in the original source; and added a bit more documentation. + + + Removed references to CubeInfo + + + + + Mars Reconnaissance Orbiter + + + + + + filename + input + + Input PDS formatted HiRISE RDR file + + + Use this parameter to select the HiRISE RDR filename. This + file must contain the PDS labels. This file must have been generated + by the ISIS hirdrgen application. These files are assumed to + be projected products. + + + *.img *.IMG + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the ISIS output filename. This file + will compare very closely with the original input file to the ISIS + hirdrgen application. + + + *.cub + + + + +
    diff --git a/isis/src/mro/apps/hirdr2isis/tsts/Makefile b/isis/src/mro/apps/hirdr2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hirdr2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hirdr2isis/tsts/default/Makefile b/isis/src/mro/apps/hirdr2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..44ba2585f406bab4c1e27e351ca774caf735be88 --- /dev/null +++ b/isis/src/mro/apps/hirdr2isis/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = hirdr2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/test_himos_070418.img \ + TO=$(OUTPUT)/test_himos_070418.cub \ + > /dev/null; diff --git a/isis/src/mro/apps/hirdrgen/Makefile b/isis/src/mro/apps/hirdrgen/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hirdrgen/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hirdrgen/hirdrgen.cpp b/isis/src/mro/apps/hirdrgen/hirdrgen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fcbeb18de74d6198d1957efe191974d7c66c6cde --- /dev/null +++ b/isis/src/mro/apps/hirdrgen/hirdrgen.cpp @@ -0,0 +1,525 @@ +#include "Isis.h" + +#include +#include + +#include "iTime.h" +#include "iString.h" +#include "ProcessExportPds.h" +#include "LineManager.h" +#include "OriginalLabel.h" +#include "PvlTranslationManager.h" +#include "PvlFormatPds.h" +#include "PixelType.h" +#include "Histogram.h" +#include "ProjectionFactory.h" +#include "JP2Encoder.h" + +using namespace Isis; +using namespace std; + +double *g_min, *g_max; + +PixelType oType; +char **jp2buf; +JP2Encoder *JP2_encoder; +int jp2ns; +int jp2nb; +int jp2band; + +void writeJP2Image(Buffer &in); + +void IsisMain() { + + string projName; + + Process pHist; + Cube *icube = pHist.SetInputCube("FROM"); + + // Check to see if the input cube looks like a HiRISE RDR + if (icube->Bands() > 3) { + string msg = "Input file [" + + Application::GetUserInterface().GetFilename("FROM") + + "] does not appear to be a HiRISE RDR product. Number of " + + "bands is greater than 3"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + // Setup to get a histogram for each band + g_min = new double[icube->Bands()]; + g_max = new double[icube->Bands()]; + + UserInterface &ui = Application::GetUserInterface(); + + // Determine if the data is to be converted to JPEG2000 + iString enctype = ui.GetString("ENCODING_TYPE"); + enctype.DownCase(); + + for (int band=1; band<=icube->Bands(); ++band) { + + if (ui.GetString("TYPE").compare("AUTOMATIC")==0) { + // Set up a histogram for this band. This call sets the input range + // by making an initial stats pass to find the data min and max + Histogram hist(*icube, band, pHist.Progress()); + + // Loop and accumulate histogram + pHist.Progress()->SetText("Gathering Histogram"); + pHist.Progress()->SetMaximumSteps(icube->Lines()); + pHist.Progress()->CheckStatus(); + LineManager line(*icube); + for (int i=1; i<=icube->Lines(); i++) { + line.SetLine(i, band); + icube->Read(line); + hist.AddData(line.DoubleBuffer(),line.size()); + pHist.Progress()->CheckStatus(); + } + + // get the requested cumulative percentages + g_min[band-1] = ui.GetDouble("MINPER")==0.0?hist.Minimum():hist.Percent(ui.GetDouble("MINPER")); + g_max[band-1] = ui.GetDouble("MAXPER")==0.0?hist.Maximum():hist.Percent(ui.GetDouble("MAXPER")); + } else { + g_min[band-1] = ui.GetDouble("MIN"); + g_max[band-1] = ui.GetDouble("MAX"); + } + } + + // Find the minimum min and maximum max for all bands + double minmin = g_min[0]; + double maxmax = g_max[0]; + for (int band=1; bandBands(); ++band) { + if (g_min[band] < minmin) minmin = g_min[band]; + if (g_max[band] > maxmax) maxmax = g_max[band]; + } + + pHist.EndProcess(); + + // Set up for writing the data to a PDS formatted file + ProcessExportPds p; + Cube *icube2 = p.SetInputCube("FROM"); + + if (enctype.Equal("jp2")) { + jp2buf = new char* [icube2->Bands()]; + Filename lblFile(ui.GetFilename("TO")); + string lblFilename = lblFile.Path() + "/" + lblFile.Basename() + ".lbl"; + p.SetDetached(true,lblFilename); + p.SetFormat(ProcessExport::JP2); + } + + // Set the output pixel type and the special pixel values + int nbits = ui.GetInteger("BITS"); + if (nbits == 8) { + if (enctype.Equal("jp2")) { + for (int i=0; iBands(); i++) { + jp2buf[i] = new char[icube2->Samples()]; + } + } + oType = Isis::UnsignedByte; + p.SetOutputType(oType); + p.SetOutputRange(VALID_MIN1, VALID_MAX1); + p.SetOutputNull(NULL1); + p.SetOutputLis(LOW_INSTR_SAT1); + p.SetOutputLrs(LOW_REPR_SAT1); + p.SetOutputHis(HIGH_INSTR_SAT1); + p.SetOutputHrs(HIGH_REPR_SAT1); + } else if (nbits == 16) { + if (enctype.Equal("jp2")) { + for (int i=0; iBands(); i++) { + jp2buf[i] = new char[icube2->Samples()*2]; + } + } + oType = UnsignedWord; + p.SetOutputType(oType); + p.SetOutputRange(VALID_MINU2, VALID_MAXU2); + p.SetOutputNull(NULLU2); + p.SetOutputLis(LOW_INSTR_SATU2); + p.SetOutputLrs(LOW_REPR_SATU2); + p.SetOutputHis(HIGH_INSTR_SATU2); + p.SetOutputHrs(HIGH_REPR_SATU2); + } else { + if (enctype.Equal("jp2")) { + for (int i=0; iBands(); i++) { + jp2buf[i] = new char[icube2->Samples()*2]; + } + } + oType = UnsignedWord; + p.SetOutputType(oType); + p.SetOutputRange(3.0, pow(2.0, (double)(nbits))-1.0-2.0); + p.SetOutputNull(0); + p.SetOutputLrs(1); + p.SetOutputLis(2); + p.SetOutputHis(pow(2.0, (double)(nbits))-1.0-1.0); + p.SetOutputHrs(pow(2.0, (double)(nbits))-1.0); + } + p.SetOutputEndian(Isis::Msb); + p.SetInputRange(minmin, maxmax); + + // Get the PDS label from the process + ProcessExportPds::PdsFileType type; + if (enctype.Equal("jp2")) { + type = ProcessExportPds::JP2Image; + } else { + type = ProcessExportPds::Image; + } + Pvl &pdsLabel = p.StandardPdsLabel(type); + + // Translate the keywords from the input cube label that go in the PDS label + PvlTranslationManager cubeLab(*(icube2->Label()), + "$mro/translations/hirisePdsRdrCubeLabel.trn"); + cubeLab.Auto(pdsLabel); + + // Translate the keywords from the original EDR PDS label that go in + // this RDR PDS label + OriginalLabel origBlob; + icube2->Read(origBlob); + Pvl origLabel; + PvlObject origLabelObj = origBlob.ReturnLabels(); + origLabelObj.SetName("OriginalLabelObject"); + origLabel.AddObject(origLabelObj); + PvlTranslationManager orig(origLabel, + "$mro/translations/hirisePdsRdrOriginalLabel.trn"); + orig.Auto(pdsLabel); + + // Add labels to the PDS product that could not be handled by the translater + + if(ui.WasEntered("RATIONALE_DESC")) { + pdsLabel.AddKeyword(PvlKeyword("RATIONALE_DESC", ui.GetString("RATIONALE_DESC")), Pvl::Replace); + } + + // Add PRODUCT_CREATION_TIME + time_t startTime = time(NULL); + struct tm *tmbuf = gmtime(&startTime); + char timestr[80]; + strftime(timestr,80,"%Y-%m-%dT%H:%M:%S",tmbuf); + string dateTime = (string) timestr; + iTime tmpDateTime(dateTime); + PvlGroup &timeParam = pdsLabel.FindGroup("TIME_PARAMETERS"); + timeParam += PvlKeyword("PRODUCT_CREATION_TIME", tmpDateTime.UTC()); + + // Add the N/A constant keyword to the ROOT + pdsLabel += PvlKeyword ("NOT_APPLICABLE_CONSTANT", -9998); + + // Add SOFTWARE_NAME to the ROOT + iString sfname; + sfname.clear(); + sfname += "Isis " + Isis::version + " " + Application::GetUserInterface().ProgramName(); + pdsLabel += PvlKeyword("SOFTWARE_NAME", sfname); + + // Add the PRODUCT_VERSION_ID from the user parameter VERSION + pdsLabel += PvlKeyword ("PRODUCT_VERSION_ID", ui.GetString("VERSION")); + + // Add MRO:CCD_FLAG, MRO:BINNING, MRO:TDI + // As pulled from the input Isis cube, the values are in CPMM order, so + // convert them to CCD order + PvlKeyword ccdFlag("MRO:CCD_FLAG"); + PvlKeyword &cpmmFlag = origLabel.FindObject("OriginalLabelObject"). + FindGroup("INSTRUMENT_SETTING_PARAMETERS"). + FindKeyword("MRO:POWERED_CPMM_FLAG"); + PvlKeyword ccdBin("MRO:BINNING"); + PvlKeyword &cpmmBin = icube2->Label()->FindObject("IsisCube"). + FindGroup("Mosaic")["cpmmSummingFlag"]; + PvlKeyword ccdTdi("MRO:TDI"); + PvlKeyword &cpmmTdi = icube2->Label()->FindObject("IsisCube"). + FindGroup("Mosaic")["cpmmTdiFlag"]; + PvlKeyword ccdSpecial("MRO:SPECIAL_PROCESSING_FLAG"); + PvlKeyword &cpmmSpecial = icube2->Label()->FindObject("IsisCube"). + FindGroup("Mosaic")["SpecialProcessingFlag"]; + for (int ccd=0; ccd<14; ++ccd) { + const unsigned int cpmmByCcd[] = {0,1,2,3,5,8,10,11,12,13,6,7,4,9}; + ccdFlag.AddValue(cpmmFlag[cpmmByCcd[ccd]]); + ccdBin.AddValue(cpmmBin[cpmmByCcd[ccd]] != "Null" ? cpmmBin[cpmmByCcd[ccd]]:"-9998"); + ccdTdi.AddValue(cpmmTdi[cpmmByCcd[ccd]] != "Null" ? cpmmTdi[cpmmByCcd[ccd]]:"-9998"); + iString tmp = cpmmSpecial[cpmmByCcd[ccd]]; + tmp.Trim("\""); + ccdSpecial.AddValue(tmp); + } + + if (!pdsLabel.HasGroup("INSTRUMENT_SETTING_PARAMETERS")) { + pdsLabel.AddGroup(PvlGroup("INSTRUMENT_SETTING_PARAMETERS")); + } + pdsLabel.FindGroup("INSTRUMENT_SETTING_PARAMETERS") += ccdFlag; + pdsLabel.FindGroup("INSTRUMENT_SETTING_PARAMETERS") += ccdBin; + pdsLabel.FindGroup("INSTRUMENT_SETTING_PARAMETERS") += ccdTdi; + pdsLabel.FindGroup("INSTRUMENT_SETTING_PARAMETERS") += ccdSpecial; + + // Add/modify projection info if there is a projection + if (pdsLabel.HasObject("IMAGE_MAP_PROJECTION")) { + PvlObject &mapObject = pdsLabel.FindObject("IMAGE_MAP_PROJECTION"); + mapObject += PvlKeyword("^DATA_SET_MAP_PROJECTION", "DSMAP.CAT"); + + // Add the HiRISE comment to the CENTER_LATITUDE keyword + PvlKeyword &clat = mapObject["CENTER_LATITUDE"]; + clat.AddComment("/* NOTE: CENTER_LATITUDE and CENTER_LONGITUDE describe the location */"); + clat.AddComment("/* of the center of projection, which is not necessarily equal to the */"); + clat.AddComment("/* location of the center point of the image. */"); + + if (mapObject.HasKeyword("CENTER_LATITUDE")) { + PvlKeyword ¢erLat = mapObject["CENTER_LATITUDE"]; + // if (centerLat[0] == "N/A") centerLat = -9998; + if (centerLat[0] == "N/A") mapObject.DeleteKeyword("CENTER_LATITUDE"); + } + if (mapObject.HasKeyword("CENTER_LONGITUDE")) { + PvlKeyword ¢erLon = mapObject["CENTER_LONGITUDE"]; + // if (centerLon[0] == "N/A") centerLon = -9998; + if (centerLon[0] == "N/A") mapObject.DeleteKeyword("CENTER_LONGITUDE"); + } + if (mapObject.HasKeyword("REFERENCE_LATITUDE")) { + PvlKeyword &refLat = mapObject["REFERENCE_LATITUDE"]; + // if (refLat[0] == "N/A") refLat = -9998; + if (refLat[0] == "N/A") mapObject.DeleteKeyword("REFERENCE_LATITUDE"); + } + if (mapObject.HasKeyword("REFERENCE_LONGITUE")) { + PvlKeyword &refLon = mapObject["REFERENCE_LONGITUDE"]; + // if (refLon[0] == "N/A") refLon = -9998; + if (refLon[0] == "N/A") mapObject.DeleteKeyword("REFERENCE_LONGITUDE"); + } + if (mapObject.HasKeyword("FIRST_STANDARD_PARALLEL")) { + PvlKeyword &firstSP = mapObject["FIRST_STANDARD_PARALLEL"]; + // if (firstSP[0] == "N/A") firstSP = -9998; + if (firstSP[0] == "N/A") mapObject.DeleteKeyword("FIRST_STANDARD_PARALLEL"); + } + if (mapObject.HasKeyword("SECOND_STANDARD_PARALLEL")) { + PvlKeyword &secondSP = mapObject["SECOND_STANDARD_PARALLEL"]; + // if (secondSP[0] == "N/A") secondSP = -9998; + if (secondSP[0] == "N/A") mapObject.DeleteKeyword("SECOND_STANDARD_PARALLEL"); + } + + // For Equirectangular ONLY + // Modify the radii in the pds label to use the radius at the center latitude + // instead of the target radii from NAIF + if (mapObject["MAP_PROJECTION_TYPE"][0] == "EQUIRECTANGULAR") { + Projection *proj = ProjectionFactory::CreateFromCube(*icube2); + PvlGroup &mapping = icube2->Label()->FindGroup("MAPPING",Pvl::Traverse); + double radius = proj->LocalRadius((double)mapping["CenterLatitude"]) / 1000.0; + mapObject["A_AXIS_RADIUS"].SetValue(radius, "KM"); + mapObject["B_AXIS_RADIUS"].SetValue(radius, "KM"); + mapObject["C_AXIS_RADIUS"].SetValue(radius, "KM"); + } + + projName = mapObject["MAP_PROJECTION_TYPE"][0]; + } + + // Calculate the min/max per band keywords + // These come from the input real DN and are converted to the PDS file DN + // The input to output mapping is opposite from the one above + double slope = (p.GetOutputMaximum() - p.GetOutputMinimum()) / (maxmax - minmin); + double intercept = p.GetOutputMaximum() - slope * maxmax; + PvlKeyword minimum("MRO:MINIMUM_STRETCH", slope * g_min[0] + intercept); + PvlKeyword maximum("MRO:MAXIMUM_STRETCH", slope * g_max[0] + intercept); + for (int band=1; bandBands(); ++band) { + minimum += slope * g_min[band] + intercept; + maximum += slope * g_max[band] + intercept; + } + + if (enctype.Equal("jp2")) { + // Add keywords to the PDS JP2 IMAGE object + PvlObject &imagejp2 = pdsLabel.FindObject("UNCOMPRESSED_FILE").FindObject("IMAGE"); + + // Add the HiRISE specific description of the IMAGE object + imagejp2 += PvlKeyword("DESCRIPTION", "HiRISE projected and mosaicked product"); + + // Add the SCALLING_FACTOR and OFFSET keywords + imagejp2.AddKeyword(PvlKeyword("SCALING_FACTOR", slope), Pvl::Replace); + imagejp2.AddKeyword(PvlKeyword("OFFSET", intercept), Pvl::Replace); + + // Reformat some keyword units in the image object + // This is lame, but PDS units are difficult to work with, so for now??? + PvlKeyword &oldFilterNamejp2 = imagejp2["FILTER_NAME"]; + PvlKeyword newFilterName("FILTER_NAME"); + for (int val=0; valAdd("$mro/translations/hirisePdsRdrExtras.typ"); + + // Add an output format template (group, object, & keyword output order) to + // the PDS PVL + if (projName == "EQUIRECTANGULAR") { + if (enctype.Equal("jp2")) { + pdsLabel.SetFormatTemplate ("$mro/templates/labels/hirisePdsRdrEquiJP2.pft"); + } else { + pdsLabel.SetFormatTemplate ("$mro/templates/labels/hirisePdsRdrEqui.pft"); + } + } else { + if (enctype.Equal("jp2")) { + pdsLabel.SetFormatTemplate ("$mro/templates/labels/hirisePdsRdrPolarJP2.pft"); + } else { + pdsLabel.SetFormatTemplate ("$mro/templates/labels/hirisePdsRdrPolar.pft"); + } + } + + // Open the output PDS file and dump the label and cube data + if (enctype.Equal("jp2")) { + p.OutputDetatchedLabel(); + JP2_encoder = new JP2Encoder(ui.GetFilename("TO"),icube2->Samples(), + icube2->Lines(),icube2->Bands(),oType); + JP2_encoder->OpenFile(); + jp2ns = icube2->Samples(); + jp2nb = icube2->Bands(); + jp2band = 0; + p.StartProcess(writeJP2Image); + p.EndProcess(); + delete JP2_encoder; + for (int i=0; iBands(); i++) { + delete [] jp2buf[i]; + } + } else { + Filename outFile(ui.GetFilename("TO")); + ofstream oCube(outFile.Expanded().c_str()); + p.OutputLabel(oCube); + p.StartProcess(oCube); + oCube.close(); + p.EndProcess(); + } + + delete [] g_min; + delete [] g_max; +} + +void writeJP2Image(Buffer &in) { + for (int i=0; iWrite((unsigned char**)jp2buf); + } else { + JP2_encoder->Write((short int**)jp2buf); + } + } +} diff --git a/isis/src/mro/apps/hirdrgen/hirdrgen.xml b/isis/src/mro/apps/hirdrgen/hirdrgen.xml new file mode 100644 index 0000000000000000000000000000000000000000..cbe37fabb6b5a044e9bf2f7862ad0c872df664b1 --- /dev/null +++ b/isis/src/mro/apps/hirdrgen/hirdrgen.xml @@ -0,0 +1,291 @@ + + + + + Converts HiRISE RDR cubes into PDS standard format + + + +

    + Takes an input Isis cube with HiRISE RDR specific labels, and outputs a PDS compatible file. + The DN values are NOT assumed to be between 0.0 and 1.0. + All DN values between MINPER and MAXPER will be stretched to an unsigned integer with + a size equal to the number of bits specified by BITS, excluding the special pixels. +

    + NOTE: This program does not generate the final PDS HiRISE product. The output + from this program is converted to a JPEG 2000 in the HiRISE pipeline processing. +

    +

    +

    + For NBITS=8, two values are reserved for special pixels. + For NBITS=9 through 16, five values are reserved for special pixels. + + + + + + + + + + + + + + + + + + + + + +
    RDR special pixel mapping
    Special Pixel 8 Bit Output Value 9-16 Bit Output Value
    NULL 0 0
    LRS 0 1
    LIS 0 2
    HIS 255 (2**BITS)-2
    HRS 255 (2**BITS)-1
    +

    +
    + + + Mars Reconnaissance Orbiter + + + + + Original Version + + + Modified labels to meet PDS standards and add new keywords. + + + Modified to output 8-bit products. + + + Modified with new keywords (NBITS, MINPER, MAXPER). Remove the OUTTYPE keyword. + It is now infered by NBITS. + + + Modified to convert FILTER_NAME from BLUEGREEN to BLUE-GREEN and + NEARINFRARED to NEAR-INFRARED to comply with PDS. + + Added parameters to allow + for a user specified manual stretch. + + + Removed references to CubeInfo + + + Changed output keyword PRODUCT_VERSION_ID from an automatic + translation to a user input parameter + + + Added Rationale Description option + + + Added ability to write output file in JPEG2000 format. + + + Fixed an error which misplaced the proper SCALING_FACTOR and OFFSET + keyword values. + + + + + + + cube + input + + The input cube + + + This is the Isis cube to be exported to PDS format. All bands of the cube will be exported to the PDS file. + + *.cub + + + + filename + output + + The ouput file + + + This is the destination file, where the input cube data will + be written in PDS format. This file will have unsigned 16 bit DN values in the + PDS IMAGE object no matter what type the input file is. All valid data from the input + cube will be converted to unsigned, 16 bit, most significant byte first (Big Endian). + + + + + + + string + AUTOMATIC + + Select the type of stretch + + + This parameter is used to select one of two ways to stretch output + pixels. The are AUTOMATIC or MANUAL. + + + + + + + + double + + Lower bound of the stretch + + + Lower bound for the manually specified stretch. + + + + double + + Upper bound of the stretch + + + Upper bound for the manually specified stretch. + + + + double + + 0.0 + + + Minimum DN valid percentage + + + The cumulative percentage value to be mapped to the minimum + valid pixel for the specified number of bits. For example: With BITS=10 + and MINPER=1.0, the DN which corresponds to the cummulative + percent of 1.0 will be mapped to 3, where 0 represents NULL, 1 + represents LRS and 2 represents LIS. + + 0.0 + 100.0 + + + MAXPER + + + + + + double + + 100.0 + + + Mazimum DN valid percentage + + + The cumulative percentage value to be mapped to the maximum + valid pixel for the specified number of bits. For example: With BITS=10 + and MINPER=99.0, the DN which corresponds to the cummulative + percent of 99.0 will be mapped to 1021, 1021=(2**bits)-1-2. + Where 1023 represents HIS and 1022 represents HRS. + + 0.0 + 100.0 + + + MINPER + + + + + + + + integer + + 10 + + + Number of bits for the output DN + + + The number of bits to compress the input data to. The valid data as + well as the five special pixel values (NULL, LIS, LRS, HIS, HRS) will be + compressed into this number of bits. The output data type will be + automaticity choosen using this value. A value of 8 will create + unsigned byte output files. Values from 9 to 16 will create unsigned + word output files. Unused bits in the unsigned word output file will be + set to zero. + + 8 + 16 + + + string + NONE + + Determine if data is to be encoded as JPEG2000 + + + This parameter is used to determine if the output data will + encoded using JPEG2000. The options are NONE or JP2. + + + + + + + + + + + string + + 1.0 + + + Value for the output PDS keyword PRODUCT_VERSION_ID + + + This parameter allows the user to specify the value of the standard + PDS keyword PRODUCT_VERSION_ID within the output PDS label. This + keyword will be located in the Root of the PDS PVL label. + + + + string + Preserve Original Rationale Description + + Value for the output PDS keyword RATIONALE_DESC + + + This parameter allows the user to specify the value of the standard + PDS keyword RATIONALE_DESC within the output PDS label. This keyword + will be located in the Root of the PDS PVL label. + + + + + +
    diff --git a/isis/src/mro/apps/hirdrgen/tsts/Makefile b/isis/src/mro/apps/hirdrgen/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hirdrgen/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hirdrgen/tsts/color/Makefile b/isis/src/mro/apps/hirdrgen/tsts/color/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3b25638071b5fe15fea2d3a33ddfbb31dc13c037 --- /dev/null +++ b/isis/src/mro/apps/hirdrgen/tsts/color/Makefile @@ -0,0 +1,13 @@ +APPNAME = hirdrgen + +include $(ISISROOT)/make/isismake.tsts + + +commands: + $(APPNAME) from=$(INPUT)/test_color_070419.cub \ + to=$(OUTPUT)/test_color_070419.img version=3.0> /dev/null; + catlab from=$(OUTPUT)/test_color_070419.img \ + > $(OUTPUT)/test_color_070419_imglabels.pvl; + pds2isis from=$(OUTPUT)/test_color_070419.img \ + to=$(OUTPUT)/test_color_070419_reimport.cub > /dev/null; + rm $(OUTPUT)/test_color_070419.img; diff --git a/isis/src/mro/apps/hirdrgen/tsts/manual/Makefile b/isis/src/mro/apps/hirdrgen/tsts/manual/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..57c64941cb1d36023dcdc7dba015d645774d8ea8 --- /dev/null +++ b/isis/src/mro/apps/hirdrgen/tsts/manual/Makefile @@ -0,0 +1,27 @@ +APPNAME = hirdrgen + +test_himos_070418_reimport.cub.TOLERANCE = .00019 +test_himos_070418_16_reimport.cub.TOLERANCE = .00025 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/test_himos_070418.cub \ + to=$(OUTPUT)/test_himos_070418.img type=manual \ + min=0.0265114 max=0.107671 version=2.0 \ + rationale='Testing123' > /dev/null; + catlab from=$(OUTPUT)/test_himos_070418.img \ + > $(OUTPUT)/test_himos_070418_imglabels.pvl; + pds2isis from=$(OUTPUT)/test_himos_070418.img \ + to=$(OUTPUT)/test_himos_070418_reimport.cub > /dev/null; + rm $(OUTPUT)/test_himos_070418.img; + + $(APPNAME) from=$(INPUT)/test_himos_polar_070508.cub \ + to=$(OUTPUT)/test_himos_polar_070508.img bits=8 type=manual \ + min=0.0359667 max=0.0931104> /dev/null; + catlab from=$(OUTPUT)/test_himos_polar_070508.img \ + > $(OUTPUT)/test_himos_polar_070508_imglabels.pvl; + pds2isis from=$(OUTPUT)/test_himos_polar_070508.img \ + to=$(OUTPUT)/test_himos_polar_070508_reimport.cub > /dev/null; + rm $(OUTPUT)/test_himos_polar_070508.img; + diff --git a/isis/src/mro/apps/hirdrgen/tsts/red/Makefile b/isis/src/mro/apps/hirdrgen/tsts/red/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e56540214b8c2505c4d6839414bbd223691385e8 --- /dev/null +++ b/isis/src/mro/apps/hirdrgen/tsts/red/Makefile @@ -0,0 +1,33 @@ +APPNAME = hirdrgen + +test_himos_070418_reimport.cub.TOLERANCE = .00019 +test_himos_070418_16_reimport.cub.TOLERANCE = .00025 +test_himos_polar_070508_reimport.cub.TOLERANCE = .00026 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/test_himos_070418.cub \ + to=$(OUTPUT)/test_himos_070418.img > /dev/null; + catlab from=$(OUTPUT)/test_himos_070418.img \ + > $(OUTPUT)/test_himos_070418_imglabels.pvl; + pds2isis from=$(OUTPUT)/test_himos_070418.img \ + to=$(OUTPUT)/test_himos_070418_reimport.cub > /dev/null; + rm $(OUTPUT)/test_himos_070418.img; + + $(APPNAME) from=$(INPUT)/test_himos_070418.cub \ + to=$(OUTPUT)/test_himos_070418_16.img bits=16 > /dev/null; + catlab from=$(OUTPUT)/test_himos_070418_16.img \ + > $(OUTPUT)/test_himos_070418_16_imglabels.pvl; + pds2isis from=$(OUTPUT)/test_himos_070418_16.img \ + to=$(OUTPUT)/test_himos_070418_16_reimport.cub > /dev/null; + rm $(OUTPUT)/test_himos_070418_16.img; + + $(APPNAME) from=$(INPUT)/test_himos_polar_070508.cub \ + to=$(OUTPUT)/test_himos_polar_070508.img bits=8 minper=0.5 maxper=99.5> /dev/null; + catlab from=$(OUTPUT)/test_himos_polar_070508.img \ + > $(OUTPUT)/test_himos_polar_070508_imglabels.pvl; + pds2isis from=$(OUTPUT)/test_himos_polar_070508.img \ + to=$(OUTPUT)/test_himos_polar_070508_reimport.cub > /dev/null; + rm $(OUTPUT)/test_himos_polar_070508.img; + diff --git a/isis/src/mro/apps/hirdrgen/tsts/red2/Makefile b/isis/src/mro/apps/hirdrgen/tsts/red2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..21179952270855fc5341214e4d1ae03f15bc5215 --- /dev/null +++ b/isis/src/mro/apps/hirdrgen/tsts/red2/Makefile @@ -0,0 +1,15 @@ +APPNAME = hirdrgen + +test_himos_070418_8_reimport.cub.TOLERANCE = .00026 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/test_himos_070418.cub \ + to=$(OUTPUT)/test_himos_070418_8.img bits=8 minper=0.5 maxper=99.5> /dev/null; + catlab from=$(OUTPUT)/test_himos_070418_8.img \ + > $(OUTPUT)/test_himos_070418_8_imglabels.pvl; + pds2isis from=$(OUTPUT)/test_himos_070418_8.img \ + to=$(OUTPUT)/test_himos_070418_8_reimport.cub > /dev/null; + rm $(OUTPUT)/test_himos_070418_8.img; + diff --git a/isis/src/mro/apps/hisharpen/Makefile b/isis/src/mro/apps/hisharpen/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/hisharpen/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/hisharpen/assets/images/gui.jpg b/isis/src/mro/apps/hisharpen/assets/images/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b502929f08de030ad1c738112800d348a4692478 Binary files /dev/null and b/isis/src/mro/apps/hisharpen/assets/images/gui.jpg differ diff --git a/isis/src/mro/apps/hisharpen/assets/images/input.jpg b/isis/src/mro/apps/hisharpen/assets/images/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..12cfa5a32fc1997e7df81f6432c62e596148743a Binary files /dev/null and b/isis/src/mro/apps/hisharpen/assets/images/input.jpg differ diff --git a/isis/src/mro/apps/hisharpen/assets/images/output.jpg b/isis/src/mro/apps/hisharpen/assets/images/output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..993a7347ebc8a7cb89cd1b586110bf7df9c29d85 Binary files /dev/null and b/isis/src/mro/apps/hisharpen/assets/images/output.jpg differ diff --git a/isis/src/mro/apps/hisharpen/assets/thumbs/gui.jpg b/isis/src/mro/apps/hisharpen/assets/thumbs/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7c8222ff3bd4fb07d4606ed2aaefae09dea66610 Binary files /dev/null and b/isis/src/mro/apps/hisharpen/assets/thumbs/gui.jpg differ diff --git a/isis/src/mro/apps/hisharpen/assets/thumbs/input.jpg b/isis/src/mro/apps/hisharpen/assets/thumbs/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ea5763581b3a5f25aa0f8022fac3d5fe0a640177 Binary files /dev/null and b/isis/src/mro/apps/hisharpen/assets/thumbs/input.jpg differ diff --git a/isis/src/mro/apps/hisharpen/assets/thumbs/output.jpg b/isis/src/mro/apps/hisharpen/assets/thumbs/output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a1e6ac5e3a23a38d246d5989ecd9507d3cb2d63c Binary files /dev/null and b/isis/src/mro/apps/hisharpen/assets/thumbs/output.jpg differ diff --git a/isis/src/mro/apps/hisharpen/hisharpen.cpp b/isis/src/mro/apps/hisharpen/hisharpen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5139f48d029cd5df14b6815f84f6a3afb27d90b7 --- /dev/null +++ b/isis/src/mro/apps/hisharpen/hisharpen.cpp @@ -0,0 +1,266 @@ +#include "Isis.h" +#include "Pipeline.h" +#include "Cube.h" +#include "LineManager.h" +#include "Progress.h" + +using namespace Isis; + +//! Create point spread function file +void CreatePsf(Pipeline &p); + +//! Clean up anything done by CreatePsf +void CleanPsf(); + +//! Test to see if a number is a power of 2 +bool IsPowerOf2(unsigned int num); + +//! True if PSF was originally specified +bool manualPsf; + +void IsisMain () { + UserInterface &ui = Application::GetUserInterface(); + + manualPsf = ui.WasEntered("PSF"); + + // This is the equation that hisharpen needs to perform + // Final magnitude/phase equations + iString magniEq = "sqrt( oreal^2 + oimag^2 )"; + iString phaseEq = "atan2( oimag , oreal )"; + + // Insert oreal/oimag + magniEq.Replace("oreal", "((real*freal + imag*fimag)/(freal*freal + fimag*fimag))"); + phaseEq.Replace("oreal", "((real*freal + imag*fimag)/(freal*freal + fimag*fimag))"); + magniEq.Replace("oimag", "((imag*freal - real*fimag)/(freal*freal + fimag*fimag))"); + phaseEq.Replace("oimag", "((imag*freal - real*fimag)/(freal*freal + fimag*fimag))"); + + // Insert real/freal (real/psf real), imag/fimag (imaginary/psf imaginary) + magniEq.Replace("freal", "(f2*cos(f3))"); + phaseEq.Replace("freal", "(f2*cos(f3))"); + magniEq.Replace("real", "(f1*cos(f4))"); + phaseEq.Replace("real", "(f1*cos(f4))"); + magniEq.Replace("fimag", "(f2*sin(f3))"); + phaseEq.Replace("fimag", "(f2*sin(f3))"); + magniEq.Replace("imag", "(f1*sin(f4))"); + phaseEq.Replace("imag", "(f1*sin(f4))"); + + // Strip spaces + phaseEq.Replace(" ", ""); + magniEq.Replace(" ", ""); + + Pipeline p; + + CreatePsf(p); + + p.SetInputFile("FROM"); + p.SetInputFile("PSF"); + p.SetOutputFile("TO"); + + p.KeepTemporaryFiles(!ui.GetBoolean("CLEANUP")); + + p.AddToPipeline("fft"); + p.Application("fft").SetInputParameter("FROM", true); + p.Application("fft").AddBranch("mag", PipelineApplication::ConstantStrings); + p.Application("fft").AddBranch("phase", PipelineApplication::ConstantStrings); + p.Application("fft").SetOutputParameter("FROM.mag", "MAGNITUDE", "fft", "cub"); + p.Application("fft").SetOutputParameter("FROM.phase", "PHASE", "fft", "cub"); + p.Application("fft").SetOutputParameter("PSF.mag", "MAGNITUDE", "fft", "cub"); + p.Application("fft").SetOutputParameter("PSF.phase", "PHASE", "fft", "cub"); + + p.AddToPipeline("fx"); + p.Application("fx").SetInputParameter("FROMLIST", PipelineApplication::LastAppOutputListNoMerge, false); + p.Application("fx").SetOutputParameter("FROM.mag", "TO", "fx", "cub"); + p.Application("fx").SetOutputParameter("PSF.phase", "TO", "fx", "cub"); + p.Application("fx").AddConstParameter("FROM.mag", "equation", magniEq); + p.Application("fx").AddConstParameter("PSF.phase", "equation", phaseEq); + p.Application("fx").AddConstParameter("MODE", "list"); + + p.AddToPipeline("ifft"); + p.Application("ifft").SetInputParameter("MAGNITUDE", true); + p.Application("ifft").AddParameter("PHASE", PipelineApplication::LastOutput); + p.Application("ifft").SetOutputParameter("FROM.mag", "TO", "untranslated", "cub"); + + p.AddToPipeline("translate"); + p.Application("translate").SetInputParameter("FROM", true); + p.Application("translate").AddConstParameter("STRANS", "-1"); + p.Application("translate").AddConstParameter("LTRANS", "-1"); + p.Application("translate").AddConstParameter("INTERP", "near"); + p.Application("translate").SetOutputParameter("FROM.mag", "TO", "final", "cub"); + + p.Run(); + + CleanPsf(); +} + + +/** + * This method creates a point spread function file if one is needed. A + * point spread function file is a picture, taken by the instrument, of + * a point of light. This file needs to be normalized, and the point of light + * should be at the edges of the image: + * + * Typical Picture of a point Expected File + * ------------------ ------------------ + * | | |* *| + * | * | | | + * | *** | | | + * | * | ===> | | + * | | | | + * | | |* *| + * ------------------ ------------------ + * + * where the blank areas in these cubes are zeros, and the *'s are data with a + * sum of 1. What's meant by creating these cubes, and what this function does, + * is find a valid point spread function and pads the center of the image with + * zeros. This allows for the sum of the image to not change, and there + * shouldnt be more light away from the point of light. + * + * + * @param p The pipeline; not modified, only used to get correct temp folder + */ +void CreatePsf(Pipeline &p) { + if(manualPsf) return; + + UserInterface &ui = Application::GetUserInterface(); + + // calculate the temp file filename + iString tmpFile = p.TemporaryFolder() + "/"; + tmpFile += Filename(ui.GetAsString("TO")).Basename(); + tmpFile += ".psf.cub"; + + // We need the base input and psf cubes to make the temporary psf cube + Cube fromCube; + fromCube.Open(ui.GetFilename("FROM")); + + // Verify the image looks like a hirise image + try { + const PvlGroup &instGrp = fromCube.Label()->FindGroup("Instrument", Pvl::Traverse); + iString instrument = (std::string)instGrp["InstrumentId"]; + + if(instrument != "HIRISE") { + iString message = "This program is meant to be run on HiRISE images only, found " + "[InstrumentId] to be [" + instrument + "] and was expecting [HIRISE]"; + throw iException::Message(iException::User, message, _FILEINFO_); + } + } + catch (iException &e) { + iString message = "The [FROM] file is not a valid HIRISE cube. " + "Please make sure it was imported using hi2isis."; + throw iException::Message(iException::User, message, _FILEINFO_); + } + + if(fromCube.Lines() != fromCube.Samples()) { + iString message = "This program only works on square cubes, the number of samples [" + + iString(fromCube.Samples()) + "] must match the number of lines [" + + iString(fromCube.Lines()) + "]"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + + // Let's figure out which point spread function we're supposed to be using + iString psfFile = "$mro/calibration/psf/PSF_"; + iString filter = (std::string)fromCube.Label()->FindGroup("Instrument", Pvl::Traverse)["CcdId"]; + + if(filter.find("RED") != string::npos) { + psfFile += "RED"; + } + else if(filter.find("BG") != string::npos) { + psfFile += "BG"; + } + else if(filter.find("IR") != string::npos) { + psfFile += "IR"; + } + else { + iString message = "The filter [" + filter + "] does not have a default point spread function. Please provide one using the [PSF] parameter."; + throw iException::Message(iException::Programmer, message, _FILEINFO_); + } + + psfFile += ".cub"; + + Cube psfCube; + psfCube.Open(psfFile); + + if(psfCube.Lines() > fromCube.Lines()) { + iString message = "The input cube dimensions must be at least [" + iString(psfCube.Lines()); + message += "] pixels in the line and sample dimensions"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + + if(!IsPowerOf2(fromCube.Lines())) { + iString message = "The input cube dimensions must be a power of 2 (found [" + + iString(fromCube.Lines()) + "])"; + throw iException::Message(iException::User,message,_FILEINFO_); + } + + LineManager psfMgr(psfCube); + psfMgr.SetLine(1,1); + + // We also need the output temp psf cube + Cube outPsfCube; + outPsfCube.SetDimensions(fromCube.Samples(), fromCube.Lines(), 1); + outPsfCube.Create(tmpFile); + + LineManager outMgr(outPsfCube); + outMgr.SetLine(1,1); + + Progress progress; + progress.SetText("Creating PSF File"); + progress.SetMaximumSteps(fromCube.Lines()); + progress.CheckStatus(); + + const int halfInSamples = psfCube.Samples() / 2; + for(int line = 0; line < outPsfCube.Lines(); line++) { + psfCube.Read(psfMgr); + + for(int sample = 0; sample < outPsfCube.Samples(); sample++) { + if(sample < halfInSamples) { + outMgr[sample] = psfMgr[sample]; + } + else if(sample >= outPsfCube.Samples() - halfInSamples) { + outMgr[sample] = psfMgr[psfCube.Samples() - (outPsfCube.Samples() - sample)]; + } + else { + outMgr[sample] = 0.0; + } + } + + outPsfCube.Write(outMgr); + + if(line < psfCube.Lines()/2) { + psfMgr ++; + } + else if(line >= outPsfCube.Lines() - psfCube.Lines()/2) { + psfMgr ++; + } + + outMgr ++; + progress.CheckStatus(); + } + + ui.PutAsString("PSF", tmpFile); +} + + +void CleanPsf() { + UserInterface &ui = Application::GetUserInterface(); + + if(!manualPsf) { + iString psfTempFile = Filename(ui.GetAsString("PSF")).Expanded(); + + if(ui.GetBoolean("CLEANUP")) { + remove(psfTempFile.c_str()); + } + + ui.Clear("PSF"); + } +} + +bool IsPowerOf2(unsigned int num) { + if(num == 0) return false; + + while(num != 1) { + if(num % 2 == 1) return false; + num /= 2; + } + + return true; +} diff --git a/isis/src/mro/apps/hisharpen/hisharpen.xml b/isis/src/mro/apps/hisharpen/hisharpen.xml new file mode 100644 index 0000000000000000000000000000000000000000..5ea72e82b6a8382d91065299221e5cf8f2f8248e --- /dev/null +++ b/isis/src/mro/apps/hisharpen/hisharpen.xml @@ -0,0 +1,147 @@ + + + + + +HiSharpen uses a linear frequency domain filter to remove the minor +blur caused by the optical system of the HiRISE camera. + + + +HiSharpen uses a linear frequency domain filter to remove the minor +blur caused by the optical system of the HiRISE camera. This blur is +estimated from prelaunch measurements of the camera's point spread +function (PSF) supplied by Alan Delamere of Ball Aerospace. The +program accepts as input a HiRISE subimage of dimensions 2**n square. +The program determines which filter (Red, BG, IR) was used for +acquiring the HiRISE image and then selects the corresponding PSF and +scales it to match the dimensions of the input image. First, the +Fourier transforms of both the image and the PSF are calculated using +the Fast Fourier Transform (FFT) algorithm. Next, the transform of the +image is divided by the transform of the PSF (the Modulation Transfer +Function, or MTF). The quotient is then transformed back to the +spatial domain by an inverse FFT. + +Note that no pre-whitening or other noise suppression is done by +HiSharpen. Random noise and pixel-to-pixel variations will be +accentuated by HiSharpen unless steps have been taken to reduce the +noise in the input image prior to sharpening. + +Note also that the FFT algorithm assumes that the input image is +periodic, i.e. the left side of the image is repeated when the right +edge of the image is reached. HiSharpen may therefore produce severe +ringing in input images with low spatial frequency variations. + + + + + Original Version + + + Converted to Isis 3 + + + + + Mars Reconnaissance Orbiter + + + + + + cube + input + + Input file + + + + + + + cube + input + + Input file + + + + + Automatic + + + + + cube + real + output + + + + + + *.cub + + + + + boolean + true + + + + + + *.cub + + + + + + + + Typical Run (256x256 input) + + This is hisharpen being run on a cropped version of a hirise cube, + the cropped area has dimensions of 256 by 256. + + + from=PSP_008530_1560_IR10_0.cub to=PSP_008530_1560_IR10_0.sharp.cub + + + FROM and TO are the only required parameters + + + + + + Input image for this program + This is the input image to be sharpened + + + FROM + + + + + + Output image for this program + This is the sharpened output image. + + + TO + + + + + + + Example Gui + Screenshot of GUI for this run of the program + + + + + + + diff --git a/isis/src/mro/apps/hisharpen/tsts/Makefile b/isis/src/mro/apps/hisharpen/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/hisharpen/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/hisharpen/tsts/default/Makefile b/isis/src/mro/apps/hisharpen/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..337b8ab962759212c887a70378503d35db9a52fc --- /dev/null +++ b/isis/src/mro/apps/hisharpen/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = hisharpen + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/PSP_008530_1560_BG12_0.cub TO=$(OUTPUT)/bg.cub > /dev/null; + $(APPNAME) FROM=$(INPUT)/PSP_008530_1560_IR10_0.cub TO=$(OUTPUT)/ir.cub > /dev/null; diff --git a/isis/src/mro/apps/histat/Makefile b/isis/src/mro/apps/histat/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/histat/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/histat/assets/histat.txt b/isis/src/mro/apps/histat/assets/histat.txt new file mode 100644 index 0000000000000000000000000000000000000000..5351f94fa4719b4db8fbf347fc155f4a46ad92bb --- /dev/null +++ b/isis/src/mro/apps/histat/assets/histat.txt @@ -0,0 +1,90 @@ +Group = Image + Average = 3647.6194437663 + StandardDeviation = 4959.1813476707 + Variance = 24593479.639085 + Minimum = 626.0 + Maximum = 14296.0 + TotalPixels = 491520.0 + ValidPixels = 491520.0 + NullPixels = 0.0 + LisPixels = 0.0 + LrsPixels = 0.0 + HisPixels = 0.0 + HrsPixels = 0.0 +EndGroup + +Group = ImageDarkReference + Average = 3758.5634114583 + StandardDeviation = 5295.5828428429 + Variance = 28043197.645412 + Minimum = 680.0 + Maximum = 14294.0 + TotalPixels = 7680.0 + ValidPixels = 7680.0 + NullPixels = 0.0 + LisPixels = 0.0 + LrsPixels = 0.0 + HisPixels = 0.0 + HrsPixels = 0.0 +EndGroup + +Group = ImageBuffer + Average = 692.12378472222 + StandardDeviation = 44.264879248685 + Variance = 1959.3795349007 + Minimum = 546.0 + Maximum = 771.0 + TotalPixels = 5760.0 + ValidPixels = 5760.0 + NullPixels = 0.0 + LisPixels = 0.0 + LrsPixels = 0.0 + HisPixels = 0.0 + HrsPixels = 0.0 +EndGroup + +Group = CalibrationImage + Average = 12972.213427734 + StandardDeviation = 3042.8299293759 + Variance = 9258813.9791058 + Minimum = 1.0 + Maximum = 65280.0 + TotalPixels = 20480.0 + ValidPixels = 20480.0 + NullPixels = 0.0 + LisPixels = 0.0 + LrsPixels = 0.0 + HisPixels = 0.0 + HrsPixels = 0.0 +EndGroup + +Group = CalibrationImageDarkReference + Average = 13543.959375 + StandardDeviation = 764.18916906662 + Variance = 583985.08611873 + Minimum = 9236.0 + Maximum = 14528.0 + TotalPixels = 320.0 + ValidPixels = 320.0 + NullPixels = 0.0 + LisPixels = 0.0 + LrsPixels = 0.0 + HisPixels = 0.0 + HrsPixels = 0.0 +EndGroup + +Group = CalibrationImageBuffer + Average = 12263.816666667 + StandardDeviation = 3943.5486036918 + Variance = 15551575.589679 + Minimum = 0.0 + Maximum = 14524.0 + TotalPixels = 240.0 + ValidPixels = 240.0 + NullPixels = 0.0 + LisPixels = 0.0 + LrsPixels = 0.0 + HisPixels = 0.0 + HrsPixels = 0.0 +EndGroup +End \ No newline at end of file diff --git a/isis/src/mro/apps/histat/assets/histatExampleNoOffsetStats.log b/isis/src/mro/apps/histat/assets/histatExampleNoOffsetStats.log new file mode 100644 index 0000000000000000000000000000000000000000..54ecdaacc68578c3b1915325b345466d84d87bcf --- /dev/null +++ b/isis/src/mro/apps/histat/assets/histatExampleNoOffsetStats.log @@ -0,0 +1,150 @@ +Group = IMAGE_POSTRAMP + Average = 3370.1694010417 + StandardDeviation = 133.48696067032 + Variance = 17818.768668999 + Minimum = 2901.0 + Maximum = 4147.0 + TotalPixels = 7680 + ValidPixels = 7680 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 +End_Group + +Group = IMAGE + Average = 3334.2398034794 + StandardDeviation = 146.94654623209 + Variance = 21593.287449541 + Minimum = 2530.0 + Maximum = 4430.0 + TotalPixels = 248320 + ValidPixels = 248320 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 +End_Group + +Group = IMAGE_DARK + Average = 1270.5005969981 + StandardDeviation = 70.658578091737 + Variance = 4992.6346579461 + Minimum = 1215.0 + Maximum = 1700.0 + TotalPixels = 159968 + ValidPixels = 159967 + NullPixels = 0 + LisPixels = 1 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 +End_Group + +Group = IMAGE_BUFFER + Average = 1211.7019737281 + StandardDeviation = 18.413955445191 + Variance = 339.0737551375 + Minimum = 1179.0 + Maximum = 1286.0 + TotalPixels = 119976 + ValidPixels = 119976 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 +End_Group + +Group = CAL_REVERSE + Average = 1199.3069053708 + StandardDeviation = 18.180739136806 + Variance = 330.53927556058 + Minimum = 1143.0 + Maximum = 1268.0 + TotalPixels = 4301 + ValidPixels = 4301 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 +End_Group + +Group = CAL_MASK + Average = 1252.871541502 + StandardDeviation = 47.386522088447 + Variance = 2245.4824756389 + Minimum = 1179.0 + Maximum = 1429.0 + TotalPixels = 506 + ValidPixels = 506 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 +End_Group + +Group = CAL_RAMP + Average = 3786.06796875 + StandardDeviation = 795.72403145508 + Variance = 633176.73423512 + Minimum = 2415.0 + Maximum = 5617.0 + TotalPixels = 1280 + ValidPixels = 1280 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 +End_Group + +Group = CAL_DARK + Average = 1245.2973484848 + StandardDeviation = 52.463745795903 + Variance = 2752.4446229372 + Minimum = 1215.0 + Maximum = 1901.0 + TotalPixels = 528 + ValidPixels = 528 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 +End_Group + +Group = CAL_DARK_RAMP + Average = 1297.9375 + StandardDeviation = 89.282561517573 + Variance = 7971.3757911392 + Minimum = 1250.0 + Maximum = 1815.0 + TotalPixels = 80 + ValidPixels = 80 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 +End_Group + +Group = CAL_BUFFER + Average = 1230.4116161616 + StandardDeviation = 18.608144845648 + Variance = 346.2630545966 + Minimum = 1197.0 + Maximum = 1286.0 + TotalPixels = 396 + ValidPixels = 396 + NullPixels = 0 + LisPixels = 0 + LrsPixels = 0 + HisPixels = 0 + HrsPixels = 0 +End_Group +End diff --git a/isis/src/mro/apps/histat/assets/images/histatExample.jpg b/isis/src/mro/apps/histat/assets/images/histatExample.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e62f6fa6839147efbf2d4fc1b3ab088d9296413a Binary files /dev/null and b/isis/src/mro/apps/histat/assets/images/histatExample.jpg differ diff --git a/isis/src/mro/apps/histat/assets/images/histatNoOffsetGui.jpg b/isis/src/mro/apps/histat/assets/images/histatNoOffsetGui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..138cf28dae37acb13c59c93536cf52da8d13c2df Binary files /dev/null and b/isis/src/mro/apps/histat/assets/images/histatNoOffsetGui.jpg differ diff --git a/isis/src/mro/apps/histat/assets/thumbs/histatExampleThumb.jpg b/isis/src/mro/apps/histat/assets/thumbs/histatExampleThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fb7c81ab02287a9a3a6703e366b86cde0f715f7a Binary files /dev/null and b/isis/src/mro/apps/histat/assets/thumbs/histatExampleThumb.jpg differ diff --git a/isis/src/mro/apps/histat/assets/thumbs/histatNoOffsetGuiThumb.jpg b/isis/src/mro/apps/histat/assets/thumbs/histatNoOffsetGuiThumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b5d118cafc3b3a2422997cf094cfa03d822fbbba Binary files /dev/null and b/isis/src/mro/apps/histat/assets/thumbs/histatNoOffsetGuiThumb.jpg differ diff --git a/isis/src/mro/apps/histat/histat.cpp b/isis/src/mro/apps/histat/histat.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd269face0142f23bbfca601780cc30c5c81a74d --- /dev/null +++ b/isis/src/mro/apps/histat/histat.cpp @@ -0,0 +1,313 @@ +#include "Isis.h" + +#include + +#include "Process.h" +#include "Pvl.h" +#include "LineManager.h" +#include "Statistics.h" +#include "Table.h" + +using namespace std; +using namespace Isis; + +PvlGroup PvlStats(Statistics &stats, const string &name); +void ThrowException(int, int, int, string); + +const int LINES_POSTRAMP = 30; + +void IsisMain() { + + //get the number of samples to skip from the left and right ends + // of the prefix and suffix data + UserInterface &ui = Application::GetUserInterface(); + + int imageLeft = 0; + int imageRight = 0; + int rampLeft = 0; + int rampRight = 0; + int calLeftBuffer = 0; + int calRightBuffer = 0; + int calLeftDark = 0; + int calRightDark = 0; + int leftBuffer = 0; + int rightBuffer = 0; + int leftDark = 0; + int rightDark = 0; + + if (ui.GetBoolean("USEOFFSETS")){ + imageLeft = ui.GetInteger("LEFTIMAGE"); + imageRight = ui.GetInteger("RIGHTIMAGE"); + rampLeft = ui.GetInteger("LEFTIMAGE"); + rampRight = ui.GetInteger("RIGHTIMAGE"); + calLeftBuffer = ui.GetInteger("LEFTCALBUFFER"); + calRightBuffer = ui.GetInteger("LEFTCALBUFFER"); + calLeftDark = ui.GetInteger("LEFTCALDARK"); + calRightDark = ui.GetInteger("RIGHTCALDARK"); + leftBuffer = ui.GetInteger("LEFTBUFFER"); + rightBuffer = ui.GetInteger("RIGHTBUFFER"); + leftDark = ui.GetInteger("LEFTDARK"); + rightDark = ui.GetInteger("RIGHTDARK"); + } + + + Isis::Filename fromFile = ui.GetFilename("FROM"); + Isis::Cube inputCube; + inputCube.Open(fromFile.Expanded()); + + //Check to make sure we got the cube properly + if (!inputCube.IsOpen()){ + string msg = "Could not open FROM cube" + fromFile.Expanded(); + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + Process p; + Cube *icube = p.SetInputCube("FROM"); + + // Get statistics from the cube prefix and suffix data + Table hifix("HiRISE Ancillary"); + icube->Read(hifix); + Statistics darkStats, bufStats, rampDarkStats; + int tdi = icube->GetGroup("Instrument")["Tdi"]; + int binning_mode = icube->GetGroup("Instrument")["Summing"]; + + //This gets us the statistics for the dark and buffer pixels + // alongside of the image itself + for (int rec=2; rec dark = hifix[rec]["DarkPixels"]; + vector buf = hifix[rec]["BufferPixels"]; + if (buf.size() <= (unsigned int)(leftBuffer + rightBuffer)){ + ThrowException(buf.size(), leftBuffer, rightBuffer, "image buffer"); + } + if (dark.size() <= (unsigned int)(leftDark + rightDark)){ + ThrowException(dark.size(), leftDark, rightDark, "image dark reference"); + } + + for (int i=leftDark; i<(int)dark.size()-rightDark; i++) { + double d; + if (dark[i] == NULL2) d = NULL8; + else if (dark[i] == LOW_REPR_SAT2) d = LOW_REPR_SAT8; + else if (dark[i] == LOW_INSTR_SAT2) d = LOW_INSTR_SAT8; + else if (dark[i] == HIGH_INSTR_SAT2) d = HIGH_INSTR_SAT8; + else if (dark[i] == HIGH_REPR_SAT2) d = HIGH_REPR_SAT8; + else d = dark[i]; + darkStats.AddData(&d,1); + } + + + for (int i=leftBuffer; i<(int)buf.size() - rightBuffer; i++) { + double d; + if (buf[i] == NULL2) d = NULL8; + else if (buf[i] == LOW_REPR_SAT2) d = LOW_REPR_SAT8; + else if (buf[i] == LOW_INSTR_SAT2) d = LOW_INSTR_SAT8; + else if (buf[i] == HIGH_INSTR_SAT2) d = HIGH_INSTR_SAT8; + else if (buf[i] == HIGH_REPR_SAT2) d = HIGH_REPR_SAT8; + else d = buf[i]; + bufStats.AddData(&d,1); + } + } + + // Get statistics from the calibration image + + //Calculate boundaries of the reverse readout lines, + // Masked lines, and ramp lines. + + //There are always 20 reverse readout lines + int reverseReadoutLines = 20; + + //Number of mask pixels depends on Binning mode + int maskLines; + maskLines = 20/binning_mode; + + //mask lines go after reverse lines + maskLines += reverseReadoutLines; + + // Actual starting line, number Ramp lines + int rampStart = maskLines; + int rampLines = tdi/binning_mode; + + Table calimg("HiRISE Calibration Image"); + icube->Read(calimg); + Statistics calStats; + //Statistics for the Reverse readout lines of the cal image + Statistics reverseStats; + //Statistics for the masked lines of the cal image + Statistics maskStats; + //Statistics for the ramped lines of the cal image + Statistics rampStats; + + //Iterate through the calibration image + + //Add in reverse data + for (int rec = 2 ; rec <= 18 ; rec++){ //Lines [2,18] + vector lineBuffer = calimg[rec]["Calibration"]; + for (unsigned int i = 2 ; i < lineBuffer.size() -1 ; i++){ //Samples [2, * -1] + double d = lineBuffer[i]; + if (lineBuffer[i] == NULL2) { d = NULL8;} + else if (lineBuffer[i] == LOW_REPR_SAT2) { d = LOW_REPR_SAT8; } + else if (lineBuffer[i] == LOW_INSTR_SAT2) { d = LOW_INSTR_SAT8; } + else if (lineBuffer[i] == HIGH_INSTR_SAT2){ d = HIGH_INSTR_SAT8;} + else if (lineBuffer[i] == HIGH_REPR_SAT2) { d = HIGH_REPR_SAT8; } + reverseStats.AddData(&d, 1); + } + } + + //Add in the mask data + for (int rec = 22 ; rec < maskLines - 1 ; rec++){//Lines [22, 38] !!!!dependant on bin + vector lineBuffer = calimg[rec]["Calibration"]; + for (int i = 2 ; i < (int)lineBuffer.size() - 1 ; i++){ //Samples [2, *-1] + double d = lineBuffer[i]; + if (d == NULL2) { d = NULL8;} + else if (d == LOW_REPR_SAT2) { d = LOW_REPR_SAT8; } + else if (d == LOW_INSTR_SAT2) { d = LOW_INSTR_SAT8; } + else if (d == HIGH_INSTR_SAT2){ d = HIGH_INSTR_SAT8;} + else if (d == HIGH_REPR_SAT2) { d = HIGH_REPR_SAT8; } + maskStats.AddData(&d, 1); + } + } + + //Add in the ramp data + for (int rec= maskLines + 2; rec < calimg.Records() - 1; rec++) { + vector buf = calimg[rec]["Calibration"]; + //loop through all but the first and last sample of the calibration image + for (int i=rampLeft; i< (int)buf.size() - rampRight; i++) { + double d; + if (buf[i] == NULL2) d = NULL8; + else if (buf[i] == LOW_REPR_SAT2) d = LOW_REPR_SAT8; + else if (buf[i] == LOW_INSTR_SAT2) d = LOW_INSTR_SAT8; + else if (buf[i] == HIGH_INSTR_SAT2) d = HIGH_INSTR_SAT8; + else if (buf[i] == HIGH_REPR_SAT2) d = HIGH_REPR_SAT8; + else d = buf[i]; + //Determine which group of stats to add to + rampStats.AddData(&d,1); + } + } + + // Get statistics from the calibration prefix and suffix data + Table calfix("HiRISE Calibration Ancillary"); + icube->Read(calfix); + Statistics calDarkStats, calBufStats; + int rampLine0 = rampStart + 1; + int rampLineN = (rampStart + rampLines -1) - 1; + rampLineN = calfix.Records() - 1; + for (int rec=0; rec dark = calfix[rec]["DarkPixels"]; + vector buf = calfix[rec]["BufferPixels"]; + if (buf.size() <= (unsigned int)(calLeftBuffer + calRightBuffer)){ + ThrowException(buf.size(), calLeftBuffer, calRightBuffer, "calibration buffer"); + } + if (dark.size() <= (unsigned int)(calLeftDark + calRightDark)){ + ThrowException(dark.size(), calLeftDark, calRightDark, "calibration dark reference"); + } + for (int i=calLeftDark; i<(int)dark.size() - calRightDark; i++) { + double d; + if (dark[i] == NULL2) d = NULL8; + else if (dark[i] == LOW_REPR_SAT2) d = LOW_REPR_SAT8; + else if (dark[i] == LOW_INSTR_SAT2) d = LOW_INSTR_SAT8; + else if (dark[i] == HIGH_INSTR_SAT2) d = HIGH_INSTR_SAT8; + else if (dark[i] == HIGH_REPR_SAT2) d = HIGH_REPR_SAT8; + else d = dark[i]; + calDarkStats.AddData(&d,1); + if ((rec > rampLine0) && (rec < rampLineN)){ + rampDarkStats.AddData(&d, 1); + } + } + for (int i=calLeftBuffer; i<(int)buf.size() - calRightBuffer; i++) { + double d; + if (buf[i] == NULL2) d = NULL8; + else if (buf[i] == LOW_REPR_SAT2) d = LOW_REPR_SAT8; + else if (buf[i] == LOW_INSTR_SAT2) d = LOW_INSTR_SAT8; + else if (buf[i] == HIGH_INSTR_SAT2) d = HIGH_INSTR_SAT8; + else if (buf[i] == HIGH_REPR_SAT2) d = HIGH_REPR_SAT8; + else d = buf[i]; + calBufStats.AddData(&d,1); + } + } + + Statistics linesPostrampStats; + Statistics imageStats; + Isis::LineManager imageBuffer(inputCube); + imageBuffer.begin(); + + Buffer out(imageBuffer.SampleDimension() - (imageLeft + imageRight), + imageBuffer.LineDimension(), + imageBuffer.BandDimension(), + imageBuffer.PixelType()); + + + for (int postRampLine = 0 ; postRampLine < LINES_POSTRAMP ; postRampLine++){ + inputCube.Read(imageBuffer); + for (int postRampSamp = 0 ; postRampSamp < out.SampleDimension() ; postRampSamp++){ + out[postRampSamp] = imageBuffer[postRampSamp + imageLeft]; + } + linesPostrampStats.AddData(out.DoubleBuffer(), out.size()); + imageBuffer++; + } + + for (int imageLine=LINES_POSTRAMP; imageLine + + + Generates statistics about a HiRISE cube and ancillary data + + + + This program computes statistics about the HiRISE image and it's + associated ancillary data including the calibration image, + dark reference pixels, and buffer pixels. There are ten sets + of statistics that will be produced using: +
      +
    • IMAGE_POSTRAMP +
        +
      • Lines postramp
      • +
      • The first 30 lines of image data
      • +
      +
    • +
    • IMAGE +
        +
      • Remaining lines of image data after the postramp.
      • +
      • If the input image is 30 lines or less, then all statistics will be zero
      • +
      +
    • +
    • IMAGE_DARK +
        +
      • Image dark reference pixels
      • +
      • 16 pixels per line
      • +
      +
    • +
    • IMAGE_BUFFER +
        +
      • Image buffer pixels
      • +
      • 12 pixels per line
      • +
      +
    • +
    • CAL_REVERSE +
        +
      • Calibration image reverse lines
      • +
      • First 20 lines of calibration image
      • +
      +
    • +
    • CAL_MASK +
        +
      • Calibration masked lines
      • +
      • From 5 - 20 lines after reverse depending on TDI
      • +
      +
    • +
    • CAL_RAMP +
        +
      • Calibration ramp
      • +
      • Remaining lines after masked lines
      • +
      +
    • +
    • CAL_DARK +
        +
      • Calibration image dark reference pixels
      • +
      • 16 pixels per line
      • +
      +
    • +
    • CAL_DARK_RAMP +
    • +
    • CAL_BUFFER +
        +
      • The calibration image buffer pixels
      • +
      • 12 pixels per line
      • +
      +
    • +
    + The following statistics for each data set will be produced: +
      +
    • Average
    • +
    • Standard deviation
    • +
    • Variance
    • +
    • Minimum
    • +
    • Maximum
    • +
    • Total pixels
    • +
    • Valid pixels
    • +
    • Null pixels
    • +
    • Low instrument saturation pixels
    • +
    • Low representation saturation pixels
    • +
    • High instrument saturation pixels
    • +
    • High representation saturation pixels
    • +
    + The statistics will be output to the print file and additionally, if the user specifies, a file using the + TO parameter, the statistics will be written to the file in a standard PVL format which can then be read using + the getkey program. Because the very edges of several parts of the image are + often inaccurate, histat also has the ability to disregard some pixels. + The first and last line of the calibration image is not regarded, nor are the + first and last samples of any line in the calibration image. For this reason, + an image with a calibration image of 62 lines by 512 samples will be broken + down as follows: +

    + Last 19 lines of the reverse readout pixels (all but the first) +
    + All 6 (in this case) lines of the masked pixels +
    + First 33 lines of the ramp pixels (all but the last) +
    + Since the first and last samples of each of these lines is disregarded + automatically, the user is left statistics for the three sections of a + 60 line by 510 sample calbration image. + +

    + The user is given much more flexibility in excluding samples from the + calibration and dark reference areas of the actual (not calibration) + image. The specific parameters used are described in the "Parameters" + section. +

    +
    + + + Mars Reconnaissance Orbiter + + + + + Original version + + + Fixed reporting of special pixels within the HiRISE tables. Special pixels were + not being converted from 16 bit signed word to 32 bit double values before + being sent to the Statistics objects. + + + Added the ability to use offsets so that edges of the calibration data may + be disregarded. + + + Seperated calibration image into reverse, masked, and ramp groups. + + + Changed the default offsets, keywords, and internal offsets, Also added + the CAL_DARK_RAMP group and the IMAGE_POSTRAMP group + + + Fixed bug where the number of mask lines was calculated. This also + effected the number of ramp lines. + + + Modified brief and full descriptions of the keywords for ignoring left and + right edges of the different calibration and main image portions of the + observation to eliminate identical descriptions. + + + Merged the changes made by Drew Davidson with the USGS version + to provide single source code management. Changed how the data + is recorded. When a TO file is given output is not written to the terminal + or the log file. If TO is not given, output is written to the terminal and + the log file (default: print.prt). + + + Removed references to CubeInfo + + + Corrected bug in computation of CAL_DARK_RAMP dataset. It was + hardcoded for handling summing mode 1. It has been corrected to + handle all summing/tdi combinations. + + + Removed tabs in source code, fixed the example, expanded and structured + documentation. + + + + + + + cube + input + + A HiRISE cube from the "hirise2isis" program. + + + The file specification for the input HiRISE cube. + + + *.cub + + + + + filename + output + + Output file to contain statistics + + + No Output file will be created + + + This ascii file will contain the statistics of the various HiRISE components. + It is written in such a format that the values can be read using the getkey program. + This is useful for when developing + scripts. + + + *.txt + + + + + + boolean + crop the edge columns of regions + + Boolean option to include offsets to disregard the edge columns (true) + or to include all columns from all buffers (false). + + TRUE + + LEFTIMAGE + RIGHTIMAGE + LEFTCALBUFFER + RIGHTCALBUFFER + LEFTCALDARK + RIGHTCALDARK + LEFTDARK + RIGHTDARK + LEFTBUFFER + RIGHTBUFFER + + + + + + + integer + Offset for the left side of the image area + 0 + 0 + + this number of pixels will be ignored on the right side of the + ramp, lines postramp, and image areas + + + + integer + Offset for the right side of the image area + 1 + 1 + + this number of pixels will be ignored on the right side of the + ramp, lines postramp, and image areas + + + + integer + Offset for the left side of the calibration buffer + 3 + 3 + + This number of pixels will be ignored on the left side of the + buffer area of the calibration image + + + + integer + Offset for the right side of the calibration buffer + 1 + + This number of pixels will be ignored on the right side of the + buffer area of the calibration image + + + + integer + Offset for the left side of the calibration dark pixels + 3 + + This number of pixels will be ignored on the left side of the + dark area of the calibration image + + + + integer + Offset for the right side of the calibration dark pixels + 1 + + This number of pixels will be ignored on the right side of the + dark area of the calibration image + + + + integer + Offset for the left side of the image buffer + 3 + + This number of pixels will be ignored on the left side of the + buffer area of the main image + + + + integer + Offset for the right side of the image buffer + 1 + + This number of pixels will be ignored on the right side of the + buffer area of the main image + + + + integer + Offset for the left side of the image dark pixels + 3 + + This number of pixels will be ignored on the left side of the + dark area of the main image + + + + integer + Offset for the right side of the image dark pixels + 1 + + This number of pixels will be ignored on the right side of the + dark area of the main image + + + + + + + + + + No offsets used + + Gathering statistics including all buffer and dark pixel values. + + + + from=histatExample.cub to=histatExampleStats.log useoffsets=false + + + In this example we disregard the ability to use offsets on the buffers. + Since the default is to include offset values, we must explicitly set + useoffsets to false. + + + + + + HiRISE input image for histat + This is the input image for which we will gather statistics. + + FROM + + + + + + + Output from histats without offsets + + + This is the output file from running histats without any offsets. + + + + + + + + Example Gui + Screenshot of GUI with parameters set to gather stats without offsets. + + + + + + + + + +
    diff --git a/isis/src/mro/apps/histat/tsts/Makefile b/isis/src/mro/apps/histat/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/histat/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/histat/tsts/default/Makefile b/isis/src/mro/apps/histat/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f85e6a187312f08d41cc2d5ff09b2dc3da56be89 --- /dev/null +++ b/isis/src/mro/apps/histat/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = histat + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/PSP_001331_2260_IR11_1.cub \ + to=$(OUTPUT)/histat_truth1.txt > /dev/null; diff --git a/isis/src/mro/apps/histat/tsts/useoffsets/Makefile b/isis/src/mro/apps/histat/tsts/useoffsets/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ab652115bf7ce4e0413dde5bbc08231589dfe8b1 --- /dev/null +++ b/isis/src/mro/apps/histat/tsts/useoffsets/Makefile @@ -0,0 +1,8 @@ +APPNAME = histat + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/PSP_001331_2260_IR11_1.cub \ + to=$(OUTPUT)/histat_truth1.txt \ + useoffsets=false > /dev/null; diff --git a/isis/src/mro/apps/histitch/Makefile b/isis/src/mro/apps/histitch/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/histitch/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/histitch/assets/image/hiStitchGUI.JPG b/isis/src/mro/apps/histitch/assets/image/hiStitchGUI.JPG new file mode 100755 index 0000000000000000000000000000000000000000..d6eea6ed8268690bcbdb24cc9bb0f9ecb6d6de61 Binary files /dev/null and b/isis/src/mro/apps/histitch/assets/image/hiStitchGUI.JPG differ diff --git a/isis/src/mro/apps/histitch/assets/image/newStitch.JPG b/isis/src/mro/apps/histitch/assets/image/newStitch.JPG new file mode 100755 index 0000000000000000000000000000000000000000..4d3a61bfaa5a24d5351d08ddd4a37c804d0b1a24 Binary files /dev/null and b/isis/src/mro/apps/histitch/assets/image/newStitch.JPG differ diff --git a/isis/src/mro/apps/histitch/assets/image/oldStitch.JPG b/isis/src/mro/apps/histitch/assets/image/oldStitch.JPG new file mode 100755 index 0000000000000000000000000000000000000000..9dc652b984db24c804e9a4be2ddd58365fdd7134 Binary files /dev/null and b/isis/src/mro/apps/histitch/assets/image/oldStitch.JPG differ diff --git a/isis/src/mro/apps/histitch/assets/thumb/hiStitchGUI.JPG b/isis/src/mro/apps/histitch/assets/thumb/hiStitchGUI.JPG new file mode 100755 index 0000000000000000000000000000000000000000..d750afe9d3174429e33a8135bef860ad48b69b45 Binary files /dev/null and b/isis/src/mro/apps/histitch/assets/thumb/hiStitchGUI.JPG differ diff --git a/isis/src/mro/apps/histitch/assets/thumb/newStitch.JPG b/isis/src/mro/apps/histitch/assets/thumb/newStitch.JPG new file mode 100755 index 0000000000000000000000000000000000000000..dd3b3c71a69965a38b525bca43476589732f5ced Binary files /dev/null and b/isis/src/mro/apps/histitch/assets/thumb/newStitch.JPG differ diff --git a/isis/src/mro/apps/histitch/assets/thumb/oldStitch.JPG b/isis/src/mro/apps/histitch/assets/thumb/oldStitch.JPG new file mode 100755 index 0000000000000000000000000000000000000000..1f70d089d2cbf212f6002886c7fe1da26f367b5c Binary files /dev/null and b/isis/src/mro/apps/histitch/assets/thumb/oldStitch.JPG differ diff --git a/isis/src/mro/apps/histitch/histitch.cpp b/isis/src/mro/apps/histitch/histitch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eefd11729c3eded6bed5f15635c6ea58b8c23079 --- /dev/null +++ b/isis/src/mro/apps/histitch/histitch.cpp @@ -0,0 +1,427 @@ +#include +#include "Isis.h" +#include "QuickFilter.h" +#include "NumericalApproximation.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include "Pvl.h" + +#include "Buffer.h" +#include "Statistics.h" +#include "MultivariateStatistics.h" +#include "Table.h" + +#include "tnt_array1d.h" + +typedef TNT::Array1D HiVector; //!< 1-D Buffer + +using namespace Isis; +using namespace std; + +void histitch (vector &in, vector &out); +void getStats(std::vector &in, + std::vector &out); + +Statistics stats0; +Statistics stats1; +MultivariateStatistics stats; + +struct ChannelInfo { + int ChnNumber; + unsigned nLines; + unsigned nSamples; + unsigned offset; + HiVector mult, add; + ChannelInfo() : ChnNumber(1), nLines(0),nSamples(0), offset(0) { } +}; + +static ChannelInfo fromData[2]; +double average0 = Isis::Null; +double average1= Isis::Null; +HiVector f0LineAvg; +HiVector f1LineAvg; +double coeff; +string balance; +int seamSize; +int skipSize; + + +inline HiVector filter(const HiVector &v, int width) { + QuickFilter lowpass(v.dim(), width, 1); + lowpass.AddLine(&v[0]); + HiVector vout(v.dim()); + for (int i = 0 ; i < v.dim() ; i ++) { + vout[i] = lowpass.Average(i); + } + return (vout); +} + +//2008-11-05 Jeannie Walldren Replaced references to DataInterp class with NumericalApproximation. +inline HiVector filler(const HiVector &v, int &nfilled) { + NumericalApproximation spline(NumericalApproximation::CubicNatural); + for (int i = 0 ; i < v.dim() ; i++) { + if (!IsSpecial(v[i])) { + spline.AddData(i, v[i]); + } + } + + // Compute the spline and fill missing data + HiVector vout(v.dim()); + nfilled = 0; + for (int j = 0 ; j < v.dim() ; j++) { + if (IsSpecial(v[j])) { + vout[j] = spline.Evaluate(j,NumericalApproximation::NearestEndpoint); + nfilled++; + } + else { + vout[j] = v[j]; + } + } + return (vout); +} + +HiVector compRatio(const HiVector &c0, const HiVector &c1, int &nNull) { + nNull = 0; + HiVector vout(c0.dim()); + for (int i = 0 ; i < c0.dim() ; i++) { + if (IsSpecial(c0[i]) || IsSpecial(c1[i]) || (c1[i] == 0.0)) { + vout[i] = 1.0; + nNull++; + } + else { + vout[i] = c0[i] / c1[i]; + } + } + return (vout); +} + +HiVector compAdd(const HiVector &c0, const HiVector &c1, int &nNull) { + nNull = 0; + HiVector vout(c0.dim()); + for (int i = 0 ; i < c0.dim() ; i++) { + if (IsSpecial(c0[i]) || IsSpecial(c1[i])) { + vout[i] = 0.0; + nNull++; + } + else { + vout[i] = c0[i] - c1[i]; + } + } + return (vout); +} + + + +void IsisMain() { +// Get user interface to test for input conditions + UserInterface &ui = Application::GetUserInterface(); + balance = ui.GetString("BALANCE"); + seamSize = ui.GetInteger("SEAMSIZE"); + skipSize = ui.GetInteger ("SKIP"); + int filterWidth = ui.GetInteger("WIDTH"); + bool fillNull = ui.GetBoolean("FILL"); + int hiChannel = ui.GetInteger("CHANNEL"); + string fixop = ui.GetString("OPERATOR"); + coeff = 1; + + // Define the processing to be by line + ProcessByLine p; + + //Set string to gather ProductIds. + string stitchedProductIds; + +// Obtain lines and samples of the input files. Note that conditions +// are obtained from the first input file only unless provided from a +// second file + Cube *icube1 = p.SetInputCube("FROM1"); + fromData[0].nLines = fromData[1].nLines = icube1->Lines(); + fromData[0].nSamples = fromData[1].nSamples = icube1->Samples(); + fromData[0].mult = HiVector(icube1->Lines(), 1.0); + fromData[0].add = HiVector(icube1->Lines(), 0.0); + + if(seamSize + skipSize > icube1->Samples()) { + string msg = "SEAMSIZE [" + iString(seamSize) + "] + SKIP [" + iString(skipSize) + "] must "; + msg += " be less than the number of samples [" + iString(icube1->Samples()) + "] in "; + msg += "[" + ui.GetAsString("FROM1") + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + PvlGroup &from1Archive = icube1->GetGroup("ARCHIVE"); + PvlGroup &from1Instrument = icube1->GetGroup("INSTRUMENT"); + fromData[0].ChnNumber = from1Instrument["ChannelNumber"]; + + stitchedProductIds = (string)from1Archive["ProductId"][0]; + +// Set initial conditions for one input file + if (fromData[0].ChnNumber == 1) { + fromData[0].offset = 0; + } + else { + if (fromData[0].ChnNumber != 0) { + string msg = "FROM1 channel number must be 1 or 2"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + fromData[0].offset = fromData[0].nSamples; + } + +// Only get the second input file if entered by the user + if (ui.WasEntered("FROM2")) { + Cube *icube2 = p.SetInputCube("FROM2"); + fromData[1].nLines = icube2->Lines(); + fromData[1].nSamples = icube2->Samples(); + fromData[1].mult = HiVector(icube2->Lines(), 1.0); + fromData[1].add = HiVector(icube2->Lines(), 0.0); + + if(seamSize + skipSize > icube2->Samples()) { + string msg = "SEAMSIZE [" + iString(seamSize) + "] + SKIP [" + iString(skipSize) + "] must "; + msg += " be less than the number of samples [" + iString(icube2->Samples()) + " in "; + msg += "[" + ui.GetAsString("FROM2") + "]"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + //Test to make sure input files are compatable + PvlGroup &from2Archive = icube2->GetGroup("ARCHIVE"); + + //Make sure observation id's are the same + string from1ObsId = from1Archive["ObservationId"]; + string from2ObsId = from2Archive["ObservationId"]; + if ( from1ObsId != from2ObsId ) { + string msg = "The input files Observation Id's are not compatable"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + stitchedProductIds = "(" + stitchedProductIds + ", " + + (string)from2Archive["ProductId"][0] + ")"; + + PvlGroup &from2Instrument = icube2->GetGroup("INSTRUMENT"); + + //Make sure CCD Id's are the same + string from1CcdId = from1Instrument["CCDId"]; + string from2CcdId = from2Instrument["CCDId"]; + if ( from1CcdId != from2CcdId ) { + string msg = "The input files CCD Id's are not compatable"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + //Make sure channel numbers are equal to 0 & 1 + fromData[1].ChnNumber = from2Instrument["ChannelNumber"]; + if ( !((fromData[0].ChnNumber == 0) && (fromData[1].ChnNumber == 1)) && + !((fromData[0].ChnNumber == 1) && (fromData[1].ChnNumber == 0)) ) { + string msg = "The input files Channel numbers must be equal to 0 and 1"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + +// Set up offsets + if (fromData[0].ChnNumber == 1) { + fromData[0].offset = 0; + fromData[1].offset = fromData[0].nSamples; + } + else { + fromData[1].offset = 0; + fromData[0].offset = fromData[1].nSamples; + } + } + + unsigned int LinesOut = max(fromData[0].nLines, fromData[1].nLines); + unsigned int SampsOut = fromData[0].nSamples + fromData[1].nSamples; + unsigned int BandsOut = 1; + + Cube *ocube = p.SetOutputCube("TO",SampsOut, LinesOut, BandsOut); + + // Change Channel Number on output cube to 2 + PvlGroup &InstrumentOut = ocube->GetGroup("INSTRUMENT"); + InstrumentOut["ChannelNumber"] = 2; + + // Set StitchedChannels and Stitched ProductIds keywords + if (ui.WasEntered("FROM2")) { + InstrumentOut += PvlKeyword("StitchedChannels", "(0,1)"); + InstrumentOut += PvlKeyword("StitchedProductIds", stitchedProductIds); + } + else { + InstrumentOut += PvlKeyword("StitchedChannels", iString(fromData[0].ChnNumber)); + InstrumentOut += PvlKeyword("StitchedProductIds", stitchedProductIds); + } + + // Do balance correction + PvlGroup results("Results"); + results += PvlKeyword("Balance", balance); + if ((balance == "TRUE") || (balance == "EQUALIZE")) { + ProcessByLine pAvg; + + if(ui.WasEntered("FROM2")) { + + + int ch0Index = 0; + int ch1Index = 1; + if(fromData[0].ChnNumber == 0) { + pAvg.SetInputCube("FROM1"); + pAvg.SetInputCube("FROM2"); + } + + if(fromData[1].ChnNumber == 0) { + ch0Index = 1; + ch1Index = 0; + pAvg.SetInputCube("FROM2"); + pAvg.SetInputCube("FROM1"); + } + + stats.Reset(); + f0LineAvg = HiVector(icube1->Lines()); + f1LineAvg = HiVector(icube1->Lines()); + pAvg.StartProcess (getStats); + pAvg.EndProcess (); + + if (balance == "TRUE") { + average0 = stats.X().Average(); + average1 = stats.Y().Average(); + if (hiChannel == 0) { + if(average1 != Isis::Null) { + coeff = average0/average1; + fromData[ch1Index].mult = coeff; + } + } + else { + if(average0 != Isis::Null) { + coeff = average1/average0; + fromData[ch0Index].mult = coeff; + } + } + results += PvlKeyword("TruthChannel", hiChannel); + results += PvlKeyword("BalanceRatio", coeff); + } + else { + // Store off original averages for table + HiVector ch0_org = f0LineAvg; + HiVector ch1_org = f1LineAvg; + + results += PvlKeyword("FilterWidth", filterWidth); + if (filterWidth > 0) { + f0LineAvg = filter(f0LineAvg, filterWidth); + f1LineAvg = filter(f1LineAvg, filterWidth); + } + + results += PvlKeyword("Fill", ((fillNull) ? "TRUE" : "FALSE")); + if (fillNull) { + int nfilled; + f0LineAvg = filler(f0LineAvg, nfilled); + results += PvlKeyword("Channel0Filled", nfilled); + f1LineAvg = filler(f1LineAvg, nfilled); + results += PvlKeyword("Channel1Filled", nfilled); + } + + results += PvlKeyword("TruthChannel", hiChannel); + results += PvlKeyword("Operator", fixop); + int nunfilled(0); + HiVector ch0_fixed(icube1->Lines(), 1.0); + HiVector ch1_fixed(icube1->Lines(), 1.0); + if (fixop == "MULTIPLY") { + if (hiChannel == 0) { + fromData[ch1Index].mult = compRatio(f0LineAvg, f1LineAvg, nunfilled); + ch1_fixed = fromData[ch1Index].mult; + } + else { + fromData[ch0Index].mult = compRatio(f1LineAvg, f0LineAvg, nunfilled); + ch0_fixed = fromData[ch0Index].mult; + } + } + else { + if (hiChannel == 0) { + fromData[ch1Index].add = compAdd(f0LineAvg, f1LineAvg, nunfilled); + ch1_fixed = fromData[ch1Index].add; + ch0_fixed = 0.0; + } + else { + fromData[ch0Index].add = compAdd(f1LineAvg, f0LineAvg, nunfilled); + ch0_fixed = fromData[ch0Index].mult; + ch1_fixed = 0.0; + } + } + results += PvlKeyword("UnFilled", nunfilled); + + // Add a table to the output file of the data values + TableField f1("Channel1Original", Isis::TableField::Double); + TableField f2("Channel0Original", Isis::TableField::Double); + TableField f3("Channel1Correction", Isis::TableField::Double); + TableField f4("Channel0Correction", Isis::TableField::Double); + TableRecord rec; + rec += f1; + rec += f2; + rec += f3; + rec += f4; + Table table("HistitchStats", rec); + for (int i = 0 ; i < ch1_org.dim() ; i++) { + rec[0] = ch1_org[i]; + rec[1] = ch0_org[i]; + rec[2] = ch1_fixed[i]; + rec[3] = ch0_fixed[i]; + table += rec; + } + + PvlGroup stitch = results; + stitch.SetName("HiStitch"); + table.Label().AddGroup(stitch); + ocube->Write(table); + } + } + + } // end if balance = TRUE + + // Begin processing the input cubes to output cube. + p.StartProcess(histitch); + // All Done + PvlGroup stitch = results; + stitch.SetName("HiStitch"); + ocube->PutGroup(stitch); + p.EndProcess(); + Application::Log(results); +} + +void getStats(std::vector &in, std::vector &out) { + Buffer &channel0 = *in[0]; + Buffer &channel1 = *in[1]; + double x,y; + + Statistics c0, c1; + for (int i = 0; i < seamSize+1; i++) { + + // set the x value + x = channel0[skipSize + i]; + c0.AddData(x); + + // set the y value + y = channel1[channel1.size() - (skipSize + 1) - i] ; + c1.AddData(y); + + stats.AddData(&x, &y, 1); + } + + f0LineAvg[channel0.Line()-1] = c0.Average(); + f1LineAvg[channel1.Line()-1] = c1.Average(); +} + +// Line processing routine +void histitch (vector &in, vector &out) { + Buffer &ot = *out[0]; + +// Initialize the buffer + for (int n = 0 ; n < ot.size() ; n++) ot[n] = NULL8; + +// Place the channel data into the output buffer + vector::iterator ibuf; + int ifrom; + int line = ot.Line()-1; + for (ibuf = in.begin(), ifrom = 0 ; ibuf != in.end() ; ++ibuf, ++ifrom) { + Buffer &inbuf = *(*ibuf); + const HiVector &mult = fromData[ifrom].mult; + const HiVector &add = fromData[ifrom].add; + + unsigned int oIndex(fromData[ifrom].offset); + for (int i = 0; i < inbuf.size(); i++, oIndex++) { + if(Isis::IsSpecial(inbuf[i])){ + ot[oIndex] = inbuf[i]; + } else { + ot[oIndex] = inbuf[i] * mult[line] + add[line]; + } + } + } + return; +} diff --git a/isis/src/mro/apps/histitch/histitch.xml b/isis/src/mro/apps/histitch/histitch.xml new file mode 100644 index 0000000000000000000000000000000000000000..58a8767bcd460533a31d1465bd4a52f1d5bdbd9e --- /dev/null +++ b/isis/src/mro/apps/histitch/histitch.xml @@ -0,0 +1,355 @@ + + + + + Merge a HiRISE channel pair to make a single image + + + +

    + The program allows the user to combine two HiRISE channels to form a + single CCD image. Histitch will typically be run after radiometric + correction and prior to geometric processing. The two input files + must be the individual channel files (channels 0 and 1) of the + same CCD observation. The program will test to make sure the + Observation IDs and CCD IDs of the input cubes match, and that one + cube is channel 0 and the other is channel 1. The program is clever enough + to figure out the channels associated with each input file and correctly + order them in the output file. Any ancillary data "blobs" + will not be propagated to the output file. The channel number on + the output cube is set to 2 to signify that it is the combination of channels + 0 and 1. +

    +

    + histitch can create a CCD image if when only one channel is provided. + The proper placement, left half of CCD for channel 1 images, right half for + channel 0, is determined from the input file and the remainder of the CCD + is filled with Nulls. +

    +
    + + + Mars Reconnaissance Orbiter + + + + + Original version + + + Added obsevation id, ccd id, and channel number tests + + + Made FROM2 optional and allow creation of full CCD with just one + channel file. + + + Added StitchedChannels keyword to Instrument Group, to identify + which channels were used. + + + Added StitchedProductIds keyword to Instrument group, to identify + which images were used. + + + Documentation fixes + + + Added the balance option. + + + Removed references to CubeInfo + + + Added new EQUALIZE balance option that has utilizes new options WIDTH, + FILL, CHANNEL and OPERATOR parameters. This new option applies a + line-by-line equalization of the CCD channels using and addative or + multiplicative option. + + + Replaced references to DataInterp class with NumericalApproximation. + + + Set channel 1 (left) as the default to hold instead of channel 0. + Added reporting of results to label in the Histitch group. Also added + creation of a Table of data when the EQUALIZE BALANCE option is + selected. + + + The BALANCE=TRUE option now honors the CHANNEL parameter and applies the + coefficient/ratio to the other channel. + + + Added error checking to SKIP and SEAMSIZE parameters. Fixed problem + with accessing out of array bounds. + + + + + + + cube + input + + First HiRISE Channel file. + + + This is the first of a pair of input HiRISE channel + image files. This file can be either the channel 0 + or 1 file. The pair of input files must correspond + to the the same observation of a HiRISE CCD. + + + *.cub + + + + cube + input + None + + Second HiRISE Channel file. + + +

    + This is the second of a pair of input HiRISE channel + image files. This file can be either the channel 0 + or 1 file. The pair of input files must correspond + to the the same observation of a HiRISE CCD. +

    +

    + If the user does not provide a file for the second file, histitch + will create a full CCD and map the FROM1 file into the proper + location in the CCD. This allows creation of the full CCD without + both channels being required. +

    +
    + + *.cub + +
    + + + cube + output + + Output HiRISE CCD image. + + + The output cube is a HiRISE CCD image with the two channel + files combined. The channel number for this cube is set to 2. + + + *.cub + + +
    + + + string + FALSE + Option to balance channel 0 and channel 1 + + A feature which calculates the average on each channel and multiplies one side with + the ratio of the averages + + + + + + + + + integer + + 7 + + 0 + Number of Pixels to skip on the edges of the image. + + Number of pixels to skip on each side of the seam before the program + starts to accumulate pixel DN's to calculate the seam average value. + + + + integer + + 11 + + 1 + Number of Pixels on the seam + + Number of pixels (after skipping 'SKIP' number of pixels) used to + compute the averages on each side of the seam. + + + + integer + Width of filter to apply to line averages + 0 + + + Specify the width of the filter to apply to both channel line + averages. This is turned off with a value of 0. + + + + boolean + true + + Apply spline interpolation to channel line averages + + + Apply a spline interpolation to each line average to fill any gaps + that may exist + + + + integer + 1 + Specify channel to normalize to (hold as truth) + 0 + 1 + + Typically, channel 1, the left channel, is held and channel 0, the + right channel, is corrected. This option allows the user to select + which channel to hold. + + + + string + MULTIPLY + Option to balance channel 0 and channel 1 + + A feature which calculates the average on each channel and multiplies one side with + the ratio of the averages + + + + + + + +
    + + + HiRISE image + + This example shows the hiStitch application. + + + from1=IN/Channel0.cub from2=IN/Channel1.cub to=OUT/output.cub balance=true skip=7 seamsize=11 + + + hiStitch gui example + + + + + + Input images for hiStitch + These are input images stitched together without the balance option on. + + + FROM1,FROM2 + + + + + + Output image for hiStitch + This is the output image with the balance option TRUE. + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform a hiStitch operation on the input images. + + + + + + +
    diff --git a/isis/src/mro/apps/histitch/tsts/Makefile b/isis/src/mro/apps/histitch/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/histitch/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/histitch/tsts/add/Makefile b/isis/src/mro/apps/histitch/tsts/add/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..019104e60ff1746c13515e701e30b8d4ce4e3a2e --- /dev/null +++ b/isis/src/mro/apps/histitch/tsts/add/Makefile @@ -0,0 +1,10 @@ +APPNAME = histitch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from1=$(INPUT)/Channel0.cub \ + from2=$(INPUT)/Channel1.cub \ + to=$(OUTPUT)/histitch_RED_balanced_add.cub \ + balance=equalize skip=0 seamsize=3 channel=0 \ + width=201 fill=true operator=add > /dev/null; diff --git a/isis/src/mro/apps/histitch/tsts/balance/Makefile b/isis/src/mro/apps/histitch/tsts/balance/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ad3e372299b1b3c8a4cd9f90b95fed003214fb91 --- /dev/null +++ b/isis/src/mro/apps/histitch/tsts/balance/Makefile @@ -0,0 +1,9 @@ +APPNAME = histitch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from1=$(INPUT)/Channel0.cub \ + from2=$(INPUT)/Channel1.cub \ + to=$(OUTPUT)/histitch_RED_balanced.cub \ + channel=0 balance=true skip=7 seamsize=11 > /dev/null; diff --git a/isis/src/mro/apps/histitch/tsts/dual/Makefile b/isis/src/mro/apps/histitch/tsts/dual/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4a57a4d1707e1c914d1dc0efe86e765ab2d6c73c --- /dev/null +++ b/isis/src/mro/apps/histitch/tsts/dual/Makefile @@ -0,0 +1,8 @@ +APPNAME = histitch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from1=$(INPUT)/PSP_001446_1790_RED2_0.cub \ + from2=$(INPUT)/PSP_001446_1790_RED2_1.cub \ + to=$(OUTPUT)/histitch_RED.cub > /dev/null; diff --git a/isis/src/mro/apps/histitch/tsts/multiply/Makefile b/isis/src/mro/apps/histitch/tsts/multiply/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..12511f39656b29b33539e96315db8004785c526f --- /dev/null +++ b/isis/src/mro/apps/histitch/tsts/multiply/Makefile @@ -0,0 +1,10 @@ +APPNAME = histitch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from1=$(INPUT)/Channel0.cub \ + from2=$(INPUT)/Channel1.cub \ + to=$(OUTPUT)/histitch_RED_balanced_mult.cub \ + balance=equalize skip=0 seamsize=3 channel=0 \ + width=201 fill=true operator=multiply > /dev/null; diff --git a/isis/src/mro/apps/histitch/tsts/single/Makefile b/isis/src/mro/apps/histitch/tsts/single/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f01f4ffadcc4c366680faba8dfc39cb13f8da22e --- /dev/null +++ b/isis/src/mro/apps/histitch/tsts/single/Makefile @@ -0,0 +1,9 @@ +APPNAME = histitch + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from1=$(INPUT)/PSP_001446_1790_RED2_0.cub \ + to=$(OUTPUT)/histitch_RED0.cub > /dev/null; + $(APPNAME) from1=$(INPUT)/PSP_001446_1790_RED2_1.cub \ + to=$(OUTPUT)/histitch_RED1.cub > /dev/null; diff --git a/isis/src/mro/apps/marci2isis/Makefile b/isis/src/mro/apps/marci2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/marci2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/marci2isis/assets/images/T02_001000_1199_MC_00N230W.auto.jpg b/isis/src/mro/apps/marci2isis/assets/images/T02_001000_1199_MC_00N230W.auto.jpg new file mode 100644 index 0000000000000000000000000000000000000000..44d15e2fa93a0a06c6af3df448c915a7ac94c5f0 Binary files /dev/null and b/isis/src/mro/apps/marci2isis/assets/images/T02_001000_1199_MC_00N230W.auto.jpg differ diff --git a/isis/src/mro/apps/marci2isis/assets/images/T02_001000_1199_MC_00N230W.noflip.jpg b/isis/src/mro/apps/marci2isis/assets/images/T02_001000_1199_MC_00N230W.noflip.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ef366caeb196dd414ec6e08f45a02668fac93a15 Binary files /dev/null and b/isis/src/mro/apps/marci2isis/assets/images/T02_001000_1199_MC_00N230W.noflip.jpg differ diff --git a/isis/src/mro/apps/marci2isis/assets/images/gui.jpg b/isis/src/mro/apps/marci2isis/assets/images/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25300fb1a931658a43432c311eb7061feb6bbe59 Binary files /dev/null and b/isis/src/mro/apps/marci2isis/assets/images/gui.jpg differ diff --git a/isis/src/mro/apps/marci2isis/assets/thumbs/T02_001000_1199_MC_00N230W.auto.jpg b/isis/src/mro/apps/marci2isis/assets/thumbs/T02_001000_1199_MC_00N230W.auto.jpg new file mode 100644 index 0000000000000000000000000000000000000000..73c2096c4e39cbdcfd75d1b5f1423ecdf14e4061 Binary files /dev/null and b/isis/src/mro/apps/marci2isis/assets/thumbs/T02_001000_1199_MC_00N230W.auto.jpg differ diff --git a/isis/src/mro/apps/marci2isis/assets/thumbs/T02_001000_1199_MC_00N230W.noflip.jpg b/isis/src/mro/apps/marci2isis/assets/thumbs/T02_001000_1199_MC_00N230W.noflip.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2d76d1c36ec6f1156f5c486b7dce2d13e6507e14 Binary files /dev/null and b/isis/src/mro/apps/marci2isis/assets/thumbs/T02_001000_1199_MC_00N230W.noflip.jpg differ diff --git a/isis/src/mro/apps/marci2isis/assets/thumbs/gui.jpg b/isis/src/mro/apps/marci2isis/assets/thumbs/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..77d9162ca87a668cb2fbc51509964117a5b962a0 Binary files /dev/null and b/isis/src/mro/apps/marci2isis/assets/thumbs/gui.jpg differ diff --git a/isis/src/mro/apps/marci2isis/marci2isis.cpp b/isis/src/mro/apps/marci2isis/marci2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8d811bb11532dce4d2a754c6da0c17e38d0a88d --- /dev/null +++ b/isis/src/mro/apps/marci2isis/marci2isis.cpp @@ -0,0 +1,419 @@ +#include "Isis.h" +#include "ProcessImportPds.h" +#include "Filename.h" +#include "Brick.h" +#include "MultivariateStatistics.h" +#include "OriginalLabel.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +std::vector outputCubes; +std::vector currentLine; +int numFilters; +int filterHeight = 16; +int flip = 0; +int cubeHeight = 0; +int colorOffset; +std::vector padding; +Isis::Brick *flipDataBrick1 = NULL; +Isis::Brick *flipDataBrick2 = NULL; + +const std::string knownFilters[] = { + "NIR", + "RED", + "ORANGE", + "GREEN", + "BLUE", + "LONG_UV", + "SHORT_UV" + }; + +void writeCubeOutput(Isis::Buffer &data); +void translateMarciLabels(Pvl &pdsLabel, Pvl &cubeLabel); +void writeFlipBricks(); +void writeOutputPadding(); + +void IsisMain () { + flipDataBrick1 = NULL; + flipDataBrick2 = NULL; + ProcessImportPds p; + + // Input data for MARCI is unsigned byte + p.SetPixelType(Isis::UnsignedByte); + + UserInterface &ui = Application::GetUserInterface(); + Filename inFile = ui.GetFilename("FROM"); + + //Checks if in file is rdr + Pvl lab(inFile.Expanded()); + if( lab.HasObject("IMAGE_MAP_PROJECTION") ) { + string msg = "[" + inFile.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + Pvl pdsLab; + p.SetPdsFile(inFile.Expanded(), "", pdsLab); + + if((int)pdsLab["SAMPLING_FACTOR"] == 12) { + throw iException::Message(iException::User, "Summing mode of 12 not supported", _FILEINFO_); + } + + // We need to know how many filters and their height to import the data properly + numFilters = pdsLab["FILTER_NAME"].Size(); + currentLine.resize(numFilters); + filterHeight = 16 / (int)pdsLab["SAMPLING_FACTOR"]; + + // For simplicity, we'll keep track of line #'s on each band that we've written so far. + for(int band = 0; band < numFilters; band ++) { + currentLine[band] = 1; + } + + int maxPadding = 0; + + padding.resize(numFilters); + for(int filter = 0; filter < numFilters; filter++) { + if(ui.GetBoolean("COLOROFFSET") == true) { + colorOffset = ui.GetInteger("COLOROFFSET_SIZE"); + + // find the filter num + int filtNum = 0; + int numKnownFilters = sizeof(knownFilters) / sizeof(std::string); + + while(filtNum < numKnownFilters && + (std::string)pdsLab["FILTER_NAME"][filter] != knownFilters[filtNum]) { + filtNum ++; + } + + if(filtNum >= numKnownFilters) { + throw iException::Message(iException::Pvl, + "Nothing is known about the [" + pdsLab["FILTER_NAME"][filter] + "] filter. COLOROFFSET not possible.", + _FILEINFO_); + } + else { + padding[filter] = (colorOffset * filterHeight) * filtNum; + maxPadding = max(maxPadding, padding[filter]); + } + } + else { + colorOffset = 0; + padding[filter] = 0; + } + } + + // Output lines/samps. + + int numLines = (int)p.Lines() / numFilters + maxPadding; + int numSamples = pdsLab.FindKeyword("LINE_SAMPLES", Pvl::Traverse); + cubeHeight = numLines; + + outputCubes.push_back(new Isis::Cube()); + outputCubes.push_back(new Isis::Cube()); + + outputCubes[0]->SetDimensions(numSamples, numLines, numFilters); + outputCubes[1]->SetDimensions(numSamples, numLines, numFilters); + + Filename outputFile(ui.GetFilename("TO")); + iString evenFile = outputFile.Path() + "/" + outputFile.Basename() + ".even.cub"; + iString oddFile = outputFile.Path() + "/" + outputFile.Basename() + ".odd.cub"; + + outputCubes[0]->Create(evenFile); + outputCubes[1]->Create(oddFile); + + if(ui.GetString("FLIP") == "AUTO") { + flip = -1; // Flip is unknown, this let's us know we need to figure it out later + flipDataBrick1 = new Isis::Brick(numSamples, filterHeight, numFilters, Isis::UnsignedByte); + flipDataBrick2 = new Isis::Brick(numSamples, filterHeight, numFilters, Isis::UnsignedByte); + } + else if(ui.GetString("FLIP") == "YES") { + flip = 1; + } + else { + flip = 0; + } + + writeOutputPadding(); + p.StartProcess(writeCubeOutput); + + // Add original labels + OriginalLabel origLabel(pdsLab); + + std::vector framelets; + + framelets.push_back("Even"); + framelets.push_back("Odd"); + + // Translate labels to every image and close output cubes before calling EndProcess + for(unsigned int i = 0; i < outputCubes.size(); i++) { + translateMarciLabels(pdsLab, *outputCubes[i]->Label()); + + PvlObject &isisCube = outputCubes[i]->Label()->FindObject("IsisCube"); + isisCube.FindGroup("Instrument").AddKeyword(PvlKeyword("Framelets", framelets[i])); + + outputCubes[i]->Write(origLabel); + delete outputCubes[i]; + } + + outputCubes.clear(); + + if(flipDataBrick1 != NULL) { + delete flipDataBrick1; + delete flipDataBrick2; + flipDataBrick1 = NULL; + flipDataBrick2 = NULL; + } + + p.EndProcess(); +} + +void writeCubeOutput(Isis::Buffer &data) { + // The framelet number is necessary for deciding which cube to put the framelet's data in, EVEN or ODD. + // Getting the framelet is just a matter of (line / (height of framelet)) + int framelet = (data.Line()-1) / (filterHeight * numFilters); + + // The filter number is important for telling us which band we're processing. This can be calculated with + // (line / (height of filter)), very similar to the framelet calculation. + int filter = (data.Line()-1) / filterHeight; + + // The band number is the filter modulus the number of filters. + int band = filter % numFilters; + + // If flip is -1, then we've got to auto-detect it still. The auto-detect works by first reading in the first two + // framelets into two bricks, the size of a framelet in the output. Then a correlation is done between the end of + // the first framelet, first band, and the ends of the second framelet, first band. Once the flip has + // been determined (yes or no), the two framelets in memory are written into the output cube and the program continues + // normal execution from then on. + if(flip == -1 && framelet < 2) { + // If we're in the first two framelets, just read into memory. + if(currentLine[band] <= filterHeight) { + for(int i = 0; i < data.SampleDimension(); i++) { + (*flipDataBrick1)[flipDataBrick1->Index(i, currentLine[band] - 1, band)] = data[i]; + } + } + else { + for(int i = 0; i < data.SampleDimension(); i++) { + (*flipDataBrick2)[flipDataBrick2->Index(i, currentLine[band] - filterHeight - 1, band)] = data[i]; + } + } + } + // Not in the first two framelets, flip is unknown, we should figure it out! + else if(flip == -1) { + // We'll do two correlations against baseLine, which is the last line of the first framelet's first band + Isis::Brick baseLine(flipDataBrick2->SampleDimension(), 1, 1, Isis::Real); + Isis::Brick firstLine(flipDataBrick2->SampleDimension(), 1, 1, Isis::Real); + Isis::Brick lastLine(flipDataBrick2->SampleDimension(), 1, 1, Isis::Real); + + // Populate our lines that will be correlated + for(int i = 0; i < flipDataBrick2->SampleDimension(); i++) { + baseLine[i] = (*flipDataBrick1)[flipDataBrick2->Index(i, flipDataBrick2->LineDimension()-1,0)]; + firstLine[i] = (*flipDataBrick2)[i]; + lastLine[i] = (*flipDataBrick2)[flipDataBrick2->Index(i, flipDataBrick2->LineDimension()-1,0)]; + } + + // The MultivariateStatistics will do our correlation for us. Pass it the first set of data, correlate, + // remove the data, pass it the second set and correlate. If the second correlation is better, flip. + MultivariateStatistics stats; + stats.AddData(baseLine.DoubleBuffer(), firstLine.DoubleBuffer(), flipDataBrick1->SampleDimension()); + double corr1 = fabs(stats.Correlation()); + stats.RemoveData(flipDataBrick1->DoubleBuffer(), firstLine.DoubleBuffer(), flipDataBrick1->SampleDimension()); + stats.AddData(baseLine.DoubleBuffer(), lastLine.DoubleBuffer(), flipDataBrick1->SampleDimension()); + double corr2 = fabs(stats.Correlation()); + + // Failure = No Flip + if(Isis::IsSpecial(corr1) || Isis::IsSpecial(corr2) || corr1 >= corr2) { + flip = 0; + } + else { + flip = 1; + } + + // Write the two bricks in memory to the output + writeFlipBricks(); + } + + // We're going to write every cube, regardless of if it's the right cube. We'll be populating the extra data with nulls. + for(unsigned int cube = 0; (flip != -1) && (cube < outputCubes.size()); cube++) { + // The data will be copied into a brick, and the brick written. We do this so we can set the position to write + // the output data. + Brick output(data.SampleDimension(), data.LineDimension(), 1, Isis::Real); + + // currentLine[] is 1-based + if(flip == 0) { + output.SetBasePosition(1, currentLine[band] + padding[band], band+1); + } + else if(flip == 1) { + int outLine = outputCubes[cube]->Lines() - filterHeight - + ((currentLine[band] - 1) / filterHeight) * filterHeight + (currentLine[band]-1) % filterHeight; + + output.SetBasePosition(1, outLine+1 - padding[band], band+1); + } + + // If the 1-based framelet number mod the output cubes equals the current cube, it's the proper cube to use. + // Flipped data can end up with even/odd flipped, and indeed probably will, but this isn't a concern. + if((framelet+1) % outputCubes.size() == cube) { + for(int i = 0; i < data.size(); i++) { + output[i] = data[i]; + } + } + else { + for(int i = 0; i < data.size(); i++) { + output[i] = Isis::Null; + } + } + + // Data is in our brick, let's write it into the cube. + outputCubes[cube]->Write(output); + } + + currentLine[band] ++; +} + +void translateMarciLabels(Pvl &pdsLabel, Pvl &cubeLabel) { + PvlGroup arch("Archive"); + + if(pdsLabel.HasKeyword("SAMPLE_BIT_MODE_ID")) { + arch += PvlKeyword("SampleBitModeId", (string)pdsLabel["SAMPLE_BIT_MODE_ID"]); + } + + PvlGroup inst("Instrument"); + + if((string)pdsLabel["SPACECRAFT_NAME"] == "MARS_RECONNAISSANCE_ORBITER") { + inst += PvlKeyword("SpacecraftName", "MARS RECONNAISSANCE ORBITER"); + } + else { + throw iException::Message(iException::User, "The input file does not appear to be a MARCI image", _FILEINFO_); + } + + if((string)pdsLabel["INSTRUMENT_ID"] == "MARCI") { + inst += PvlKeyword("InstrumentId", "Marci"); + } + else { + throw iException::Message(iException::User, "The input file does not appear to be a MARCI image", _FILEINFO_); + } + + inst += PvlKeyword("TargetName", (string)pdsLabel["TARGET_NAME"]); + inst += PvlKeyword("SummingMode", (string)pdsLabel["SAMPLING_FACTOR"]); + inst += PvlKeyword("StartTime", (string) pdsLabel["START_TIME"]); + inst += PvlKeyword("StopTime", (string) pdsLabel["STOP_TIME"]); + inst += PvlKeyword("SpacecraftClockCount",(string)pdsLabel["SPACECRAFT_CLOCK_START_COUNT"]); + inst += PvlKeyword("DataFlipped", (flip == 1)); + inst += PvlKeyword("ColorOffset", colorOffset); + inst += PvlKeyword("InterframeDelay", (iString)((double)pdsLabel["INTERFRAME_DELAY"]), "seconds"); + inst += PvlKeyword("ExposureDuration", (iString)((double)pdsLabel["LINE_EXPOSURE_DURATION"] / 1000.0), "seconds"); + + PvlGroup bandBin("BandBin"); + PvlKeyword filterName("FilterName"); + PvlKeyword origBands("OriginalBand"); + for(int filter = 0; filter < pdsLabel["FILTER_NAME"].Size(); filter++) { + filterName += pdsLabel["FILTER_NAME"][filter]; + origBands += iString(filter+1); + } + + bandBin += filterName; + bandBin += origBands; + + PvlObject &isisCube = cubeLabel.FindObject("IsisCube"); + isisCube.AddGroup(inst); + isisCube.AddGroup(bandBin); + isisCube.AddGroup(arch); + + // Map VIS/UV to NaifIkCode + std::map naifIkCodes; + naifIkCodes.insert( std::pair("MRO_MARCI", -74400) ); + naifIkCodes.insert( std::pair("MRO_MARCI_VIS", -74410) ); + naifIkCodes.insert( std::pair("MRO_MARCI_UV", -74420) ); + + // Map from filter name to VIS/UV + std::map bandUvVis; + bandUvVis.insert( std::pair("BLUE", "MRO_MARCI_VIS") ); + bandUvVis.insert( std::pair("GREEN", "MRO_MARCI_VIS") ); + bandUvVis.insert( std::pair("ORANGE", "MRO_MARCI_VIS") ); + bandUvVis.insert( std::pair("RED", "MRO_MARCI_VIS") ); + bandUvVis.insert( std::pair("NIR", "MRO_MARCI_VIS") ); + bandUvVis.insert( std::pair("LONG_UV", "MRO_MARCI_UV") ); + bandUvVis.insert( std::pair("SHORT_UV", "MRO_MARCI_UV") ); + + PvlGroup kerns("Kernels"); + string uvvis = bandUvVis.find((std::string)bandBin["FilterName"][0])->second; + int iakCode = naifIkCodes.find(uvvis)->second; + kerns += PvlKeyword("NaifIkCode", iakCode); + + isisCube.AddGroup(kerns); +} + +/** + * This method will write the two bricks that were read into memory in order to + * auto-detect if the image needed flipped. + */ +void writeFlipBricks() { + Isis::Brick nullBrick(flipDataBrick1->SampleDimension(), flipDataBrick1->LineDimension(), 1, Isis::Real); + + for(int i = 0; i < nullBrick.size(); i++) { + nullBrick[i] = Isis::Null; + } + + for(unsigned int cube = 0; cube < outputCubes.size(); cube++) { + for(int framelet = 0; framelet < 2; framelet++) { + for(int band = 0; band < numFilters; band++) { + Isis::Brick outBrick(flipDataBrick1->SampleDimension(), flipDataBrick1->LineDimension(), 1, Isis::Real); + + if((framelet+1) % outputCubes.size() == cube) { + for(int i = 0; i < outBrick.size(); i++) { + if(framelet == 0) { + outBrick[i] = (*flipDataBrick1)[flipDataBrick1->Index(0, 0, band) + i]; + } + else { + outBrick[i] = (*flipDataBrick2)[flipDataBrick2->Index(0, 0, band) + i]; + } + } + } + else { + outBrick.Copy(nullBrick); + } + + if(flip == 0) { + if(framelet == 0) { + outBrick.SetBasePosition(1, 1 + padding[band], band+1); + } + else { + outBrick.SetBasePosition(1, filterHeight + 1 + padding[band], band+1); + } + } + else { + int outLine = outputCubes[cube]->Lines() - (filterHeight * (framelet+1)) - padding[band]; + outBrick.SetBasePosition(1, outLine+1, band+1); + } + + outputCubes[cube]->Write(outBrick); + } + } + } +} + +// This writes nulls to the bricks where their padding goes +void writeOutputPadding() { + int paddingHeight = 0; + + for(unsigned int pad = 0; pad < padding.size(); pad++) { + paddingHeight = max(paddingHeight, padding[pad]); + } + + if(paddingHeight == 0) return; // no padding + + for(unsigned int cube = 0; cube < outputCubes.size(); cube++) { + Isis::Brick nullBrick(outputCubes[cube]->Samples(), paddingHeight, outputCubes[cube]->Bands(), Isis::Real); + + for(int i = 0; i < nullBrick.size(); i++) { + nullBrick[i] = Isis::Null; + } + + // Write padding to the beginning & end of all cubes, to ensure it's all set to null + nullBrick.SetBasePosition(1, 1, 1); + outputCubes[cube]->Write(nullBrick); + + nullBrick.SetBasePosition(1, outputCubes[cube]->Lines() - paddingHeight, 1); + outputCubes[cube]->Write(nullBrick); + } +} diff --git a/isis/src/mro/apps/marci2isis/marci2isis.xml b/isis/src/mro/apps/marci2isis/marci2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..74e33b16c12c0a979138cb6ce04cc3f0c2492f1e --- /dev/null +++ b/isis/src/mro/apps/marci2isis/marci2isis.xml @@ -0,0 +1,174 @@ + + + + + + Import an MRO MARCI image to an Isis cube + + + + This program takes an image from the Mars Reconnaissance Orbiter Color Imager + and produces an Isis cube containing the image data. + + + + + Original Version + + + Checks if input file is rdr. + + + The COLOROFFSET keyword in the output instrument group labels + is now properly set when no color offset is used. + + + + + Mars Reconnaissance Orbiter + + + + + + filename + input + + Input file + + + The EDR to be processed + + + *.img + + + + + cube + real + output + + Even bands of the output cube + + + This should be the base filename of resultant cube. The output will actually be two cubes, + with "even" and "odd" added to the filename. + + + *.cub + + + + + + + boolean + Add padding to align bands + + The result of how MARCI takes pictures leaves a filter height offset in adjacent filters. This will correct that offset + by adding padding to the top of the image file, aligning color images correctly. + + true + COLOROFFSET_SIZE + + + + integer + Amount of filter heights to pad with for COLOROFFSET + + The filters are offset by a certain number of filters, which is a multiple of their height. It appears + the filters are all offset by twice their height, or two filter heights. One filter height can be explained by + the method of taking pictures: the first filter on the first framelet is one higher than the second filter on + the first framelet. + + 2 + 0 + + + + string + Flip the framelets for pictures taken on ascending orbits + This corrects pictures taken on an ascending orbit + AUTO + + + + + + + + + + + + + + Importing a MARCI EDR + + + This example covers importing a typical MARCI EDR using the various FLIP options. + + + + FROM=T02_001000_1199_MC_00N230W.IMG TO=T02_001000_1199_MC_00N230W.cub FLIP=AUTO|YES|NO + + + This is the command line for running this program with a typical EDR. FLIP should be AUTO, YES, or NO. + + + + + + Running with default options + + This is what the interface should look like when running this example with FLIP set to AUTO. + + + + + + + + The output images (combined), using AUTO flip, cropped and colorized for this example + + Since this particular input image had a RED, GREEN, and ORANGE filter, it was possible to display the image + in color. To give a better picture of the outputs, because MARCI takes long strips of data, this image was + cropped at line 2800 to a height of 1000 pixels. This image was created with FLIP set to AUTO, which decided to + flip the data. + + + + + The output images (combined), using NO flip, cropped and colorized for this example + + Since this particular input image had a RED, GREEN, and ORANGE filter, it was possible to display the image + in color. To give a better picture of the outputs, because MARCI takes long strips of data, this image was + cropped. In order to show the same feature as the flipped image, the crop was at line 5800 to a height of 1000 pixels. + This image was created with FLIP set to NO, because AUTO flipped the data. When you look closely, especially compared + to the flipped data, the features in this data are distorted. + + + + + + + diff --git a/isis/src/mro/apps/marci2isis/tsts/Makefile b/isis/src/mro/apps/marci2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/marci2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/marci2isis/tsts/coloroffset/Makefile b/isis/src/mro/apps/marci2isis/tsts/coloroffset/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..71c1b583ca51319859eac394a4d53581d2982c30 --- /dev/null +++ b/isis/src/mro/apps/marci2isis/tsts/coloroffset/Makefile @@ -0,0 +1,18 @@ +APPNAME = marci2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/T02_001251_1292_MU_00N237W.IMG \ + TO=$(OUTPUT)/nooffset.cub COLOROFFSET=false > /dev/null; + catlab FROM=$(OUTPUT)/nooffset.even.cub > $(OUTPUT)/nooffset.pvl; + $(APPNAME) FROM=$(INPUT)/T02_001251_1292_MU_00N237W.IMG \ + TO=$(OUTPUT)/offset1.cub COLOROFFSET_SIZE=1 > /dev/null; + $(APPNAME) FROM=$(INPUT)/T02_001251_1292_MU_00N237W.IMG \ + TO=$(OUTPUT)/offset2.cub COLOROFFSET_SIZE=2 > /dev/null; + $(APPNAME) FROM=$(INPUT)/T02_001251_1292_MU_00N237W.IMG \ + TO=$(OUTPUT)/offset3.cub COLOROFFSET_SIZE=3 > /dev/null; + catlab FROM=$(OUTPUT)/offset3.odd.cub > $(OUTPUT)/offset3.pvl; + $(APPNAME) FROM=$(INPUT)/T02_001251_1292_MU_00N237W.IMG \ + TO=$(OUTPUT)/flipped.cub FLIP=yes \ + COLOROFFSET_SIZE=3 > /dev/null; diff --git a/isis/src/mro/apps/marci2isis/tsts/default/Makefile b/isis/src/mro/apps/marci2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9928d69f746d093570f5ec89609848acbd3ace16 --- /dev/null +++ b/isis/src/mro/apps/marci2isis/tsts/default/Makefile @@ -0,0 +1,10 @@ +APPNAME = marci2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/MOI_000009_0294_MU_00N044W.IMG TO=$(OUTPUT)/out.cub > /dev/null; + catlab FROM=$(OUTPUT)/out.even.cub > $(OUTPUT)/even.pvl; + catlab FROM=$(OUTPUT)/out.odd.cub > $(OUTPUT)/odd.pvl; + $(APPNAME) FROM=$(INPUT)/T02_001251_1292_MU_00N237W.IMG flip=NO TO=$(OUTPUT)/unflipped.cub > /dev/null; + catlab FROM=$(OUTPUT)/unflipped.even.cub > $(OUTPUT)/unflipped.pvl; diff --git a/isis/src/mro/apps/marcical/Makefile b/isis/src/mro/apps/marcical/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/marcical/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/marcical/marcical.cpp b/isis/src/mro/apps/marcical/marcical.cpp new file mode 100644 index 0000000000000000000000000000000000000000..09e328866935bf7410ae486b814aee744252f4ca --- /dev/null +++ b/isis/src/mro/apps/marcical/marcical.cpp @@ -0,0 +1,301 @@ +#include "Isis.h" +#include "SpecialPixel.h" +#include "CubeAttribute.h" +#include "Cube.h" +#include "LineManager.h" +#include "Progress.h" +#include "Camera.h" +#include "Constants.h" +#include "Statistics.h" +#include "TextFile.h" +#include "Stretch.h" +#include "iTime.h" + +using namespace Isis; +using namespace std; + +Stretch stretch; + +void IsisMain () { + UserInterface &ui = Application::GetUserInterface(); + + CubeAttributeInput inAtt = ui.GetInputAttribute("FROM"); + Cube icube; + + if(inAtt.Bands().size() != 0) { + icube.SetVirtualBands(inAtt.Bands()); + } + + icube.Open(Filename(ui.GetFilename("FROM")).Expanded()); + + // Make sure it is a Marci cube + Filename inFilename = ui.GetFilename("FROM"); + try { + if (icube.GetGroup("Instrument")["InstrumentID"][0] != "Marci") { + throw iException::Message(iException::User,"",_FILEINFO_); + } + + if(!icube.GetGroup("Archive").HasKeyword("SampleBitModeId")) { + throw iException::Message(iException::User,"",_FILEINFO_); + } + } + catch (iException &e) { + e.Clear(); + string msg = "This program is intended for use on MARCI images only. ["; + msg += inFilename.Expanded() + "] does not appear to be a MARCI image."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + if(icube.GetGroup("Archive")["SampleBitModeId"][0] != "SQROOT") { + string msg = "Sample bit mode [" + icube.GetGroup("Archive")["SampleBitModeId"][0] + "] is not supported."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Read in calibration coefficients + Filename calFile("$mro/calibration/marci/marciCoefficients_v???.pvl"); + calFile.HighestVersion(); + + vector decimation; + + // Decimation is described in the MRO MARCI Instrument and Calibration document pg. 63 + for(int i = 0; i < 6; i++) { + // Decimation is 1.0 for bands 1-6 + decimation.push_back(1.0); + } + + iString startTime = icube.Label()->FindGroup("Instrument", Pvl::Traverse)["StartTime"][0]; + iTime start(startTime); + iTime changeTime("November 6, 2006 21:30:00 UTC"); + + if(start < changeTime) { + decimation.push_back(1.0); + } + else { + decimation.push_back(0.25); + } + + // Get the LUT data + Filename temp("$mro/calibration/marcisqroot_???.lut"); + temp.HighestVersion(); + TextFile stretchPairs(temp.Expanded()); + + // Create the stretch pairs + stretch.ClearPairs(); + for (int i=0; i > calibrationCoeffs; + + // Check our coefficient file + if(calibrationData.Objects() != 7) { + iString msg = "Calibration file [" + calFile.Expanded() + "] must contain data for 7 filters in ascending order;"; + msg += " only [" + iString(calibrationData.Objects()) + "] objects were found"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + // Read it, make sure it's ordered + for(int obj = 0; obj < calibrationData.Objects(); obj ++) { + PvlObject &calObj = calibrationData.Object(obj); + + if((int)calObj["FilterNumber"] != obj+1) { + iString msg = "Calibration file [" + calFile.Expanded() + "] must have the filters in ascending order"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + pair calData(calObj["RadianceCoefficient"], calObj["SolarSpectralDistance"]); + calibrationCoeffs.push_back(calData); + } + + vector flatcubes; + vector fcubeMgrs; + int summing = icube.GetGroup("Instrument")["SummingMode"][0]; + + // Read in the flat files + for(int band = 0; band < 7; band++) { + string filePattern = "$mro/calibration/marci/"; + + if(band < 5) { + filePattern += "vis"; + } + else { + filePattern += "uv"; + } + + // UV cubes are always summing mode = 8, we can assume this rule will never + // be broken + if(band >= 5 && summing != 8) { + continue; + } + + filePattern += "flat_band" + iString(band+1); + filePattern += "_summing" + iString(summing) + "_v???.cub"; + + Filename flatFile(filePattern); + flatFile.HighestVersion(); + Cube *fcube = new Cube(); + fcube->Open(flatFile.Expanded()); + flatcubes.push_back(fcube); + + LineManager *fcubeMgr = new LineManager(*fcube); + fcubeMgr->SetLine(1,1); + fcubeMgrs.push_back(fcubeMgr); + } + + // Prepare the output cube + Cube ocube; + + CubeAttributeOutput outAtt = ui.GetOutputAttribute("TO"); + ocube.SetDimensions(icube.Samples(), icube.Lines(), icube.Bands()); + ocube.SetByteOrder(outAtt.ByteOrder()); + ocube.SetCubeFormat(outAtt.FileFormat()); + if(outAtt.DetachedLabel()) ocube.SetDetached(); + if(outAtt.AttachedLabel()) ocube.SetAttached(); + ocube.SetPixelType(outAtt.PixelType()); + + ocube.Create(Filename(ui.GetFilename("TO")).Expanded()); + + LineManager icubeMgr(icube); + + // This will store a direct translation from band to filter index + vector filter; + + // Conversion from filter name to filter index + map filterNameToFilterIndex; + filterNameToFilterIndex.insert(pair("BLUE", 1)); + filterNameToFilterIndex.insert(pair("GREEN", 2)); + filterNameToFilterIndex.insert(pair("ORANGE", 3)); + filterNameToFilterIndex.insert(pair("RED", 4)); + filterNameToFilterIndex.insert(pair("NIR", 5)); + filterNameToFilterIndex.insert(pair("SHORT_UV", 6)); + filterNameToFilterIndex.insert(pair("LONG_UV", 7)); + + PvlKeyword &filtNames = icube.Label()->FindGroup("BandBin", Pvl::Traverse)["FilterName"];; + for(int i = 0; i < filtNames.Size(); i++) { + if(filterNameToFilterIndex.find(filtNames[i]) != filterNameToFilterIndex.end()) { + filter.push_back(filterNameToFilterIndex.find(filtNames[i])->second); + } + else { + iString msg = "Unrecognized filter name [" + iString(filtNames[i]) + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + bool iof = ui.GetBoolean("IOF"); + double exposure = ((double)icube.Label()->FindGroup("Instrument", Pvl::Traverse)["ExposureDuration"]) * 1000.0; + Camera *cam = NULL; + double solarDist = Isis::Null; + + if(iof) { + cam = icube.Camera(); + cam->SetImage(icubeMgr.size() / 2.0, 0.5 + (16 / 2) / summing); + solarDist = cam->SolarDistance(); + } + + LineManager ocubeMgr(ocube); + ocubeMgr.SetLine(1,1); + + Progress prog; + prog.SetText("Calibrating Image"); + prog.SetMaximumSteps(ocube.Lines() * ocube.Bands()); + prog.CheckStatus(); + + Statistics stats; + + do { + icube.Read(icubeMgr); + ocube.Read(ocubeMgr); + + int fcubeIndex = filter[ocubeMgr.Band()-1] - 1; + flatcubes[fcubeIndex]->Read((*fcubeMgrs[fcubeIndex])); + + for(int i = 0; i < ocubeMgr.size(); i++) { + if(IsSpecial((*fcubeMgrs[fcubeIndex])[i]) || (*fcubeMgrs[fcubeIndex])[i] == 0.0) { + ocubeMgr[i] = Isis::Null; + } + else if(IsSpecial(icubeMgr[i])) { + ocubeMgr[i] = icubeMgr[i]; + } + else { + ocubeMgr[i] = stretch.Map(icubeMgr[i]) / (*fcubeMgrs[fcubeIndex])[i]; + + ocubeMgr[i] = ocubeMgr[i] / exposure / (summing * decimation[fcubeIndex]) / calibrationCoeffs[fcubeIndex].first; + + // Convert to I/F? + if(iof) { + ocubeMgr[i] /= calibrationCoeffs[fcubeIndex].second / Isis::PI / (solarDist * solarDist); + } + } + } + + ocube.Write(ocubeMgr); + + icubeMgr++; + ocubeMgr++; + + bool newFramelet = false; + + for(int i = 0; i < (int)fcubeMgrs.size(); i++) { + (*fcubeMgrs[i]) ++; + + if(fcubeMgrs[i]->end()) { + fcubeMgrs[i]->SetLine(1,1); + newFramelet = true; + } + } + + if(newFramelet && cam != NULL) { + // center the cameras position on the new framelet to keep the solar distance accurate + cam->SetBand(icubeMgr.Band()); + cam->SetImage(icubeMgr.size() / 2.0 + 0.5, (icubeMgr.Line() - 0.5) + (16 / 2) / summing); + solarDist = cam->SolarDistance(); + } + + prog.CheckStatus(); + } + while(!ocubeMgr.end()); + + // Propagate labels and objects (in case of spice data) + PvlObject &inCubeObj = icube.Label()->FindObject("IsisCube"); + PvlObject &outCubeObj = ocube.Label()->FindObject("IsisCube"); + + for(int g = 0; g < inCubeObj.Groups(); g++) { + outCubeObj.AddGroup(inCubeObj.Group(g)); + } + + for(int o = 0; o < icube.Label()->Objects(); o++) { + if(icube.Label()->Object(o).IsNamed("Table")) { + Blob t(icube.Label()->Object(o)["Name"], icube.Label()->Object(o).Name()); + icube.Read(t); + ocube.Write(t); + } + } + + icube.Close(); + ocube.Close(); + + // The cube still owns this + cam = NULL; + + for(int i = 0; i < (int)flatcubes.size(); i++) { + delete fcubeMgrs[i]; + delete flatcubes[i]; + } + + fcubeMgrs.clear(); + flatcubes.clear(); +} + diff --git a/isis/src/mro/apps/marcical/marcical.xml b/isis/src/mro/apps/marcical/marcical.xml new file mode 100644 index 0000000000000000000000000000000000000000..58a0e148d5f95ca8783ca12f5857d36c55559f3a --- /dev/null +++ b/isis/src/mro/apps/marcical/marcical.xml @@ -0,0 +1,89 @@ + + + + + + This program calibrates MARCI images + + + + This program applies a flat-field correction for each framelet based on the + band's filter number. In order to output in I/F units, the cube must have spice + data. This calibration problem follows the algorithms described the document titled:

    + +Mars Reconnaissance Orbiter Mars Color Imager (MARCI):
    +Instrument Description, Calibration, and Performance

    + +J.F. Bell III, M.J. Wolff, M.C. Malin, W.M. Calvin, B.A. Cantor, +M.A. Caplinger, R.T. Clancy, K.S. Edgett3, L.J. Edwards5, J. Fahle, +F. Ghaemi, R.M. Haberle, A. Hale, P.B. James, S.W. Lee, +T. McConnochie, E. Noe Dobrea1, M.A. Ravine, D. Schaeffer, +K.D. Supulver, and P.C. Thomas +
    + + + Mars Reconnaissance Orbiter + + + + + Original version + + + Added lookup table + + + Fixed a problem where segmentation faults would occur if run + with the option "IOF=false" + + + + + + + cube + input + + Input MARCI Image + + + This is the non-flat-field corrected, unprojected MARCI cube + + + *.cub + + + + + cube + output + real + + Output MARCI Image + + + This is the flat-field corrected MARCI cube + + + *.cub + + + + + + + boolean + + Make the output MARCI image in units of I/F + + + This makes the output MARCI image in I/F units instead of radiance + + + *.cub + + true + + + +
    diff --git a/isis/src/mro/apps/marcical/tsts/Makefile b/isis/src/mro/apps/marcical/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/marcical/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/marcical/tsts/default/Makefile b/isis/src/mro/apps/marcical/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5223cc59b8af7053fd75ce8a594563816f47188c --- /dev/null +++ b/isis/src/mro/apps/marcical/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = marcical + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/crop.cub \ + TO=$(OUTPUT)/truth_default.cub > /dev/null; + $(APPNAME) FROM=$(INPUT)/crop.cub iof=no \ + TO=$(OUTPUT)/truth_not_iof.cub > /dev/null; diff --git a/isis/src/mro/apps/marciflip/Makefile b/isis/src/mro/apps/marciflip/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/marciflip/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/marciflip/assets/images/T02_001000_1199_MC_00N230W.jpg b/isis/src/mro/apps/marciflip/assets/images/T02_001000_1199_MC_00N230W.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c564911890ae997403b44cc8f7e398ecdac459a2 Binary files /dev/null and b/isis/src/mro/apps/marciflip/assets/images/T02_001000_1199_MC_00N230W.jpg differ diff --git a/isis/src/mro/apps/marciflip/assets/images/T02_001000_1199_MC_00N230W.noflip.jpg b/isis/src/mro/apps/marciflip/assets/images/T02_001000_1199_MC_00N230W.noflip.jpg new file mode 100644 index 0000000000000000000000000000000000000000..519f71ef28282b91d84cd7e3ecd9ea95a24c3d49 Binary files /dev/null and b/isis/src/mro/apps/marciflip/assets/images/T02_001000_1199_MC_00N230W.noflip.jpg differ diff --git a/isis/src/mro/apps/marciflip/assets/images/gui.jpg b/isis/src/mro/apps/marciflip/assets/images/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1c51b4e571141aa2ba1e9e85814d5cef94d46041 Binary files /dev/null and b/isis/src/mro/apps/marciflip/assets/images/gui.jpg differ diff --git a/isis/src/mro/apps/marciflip/assets/thumbs/T02_001000_1199_MC_00N230W.jpg b/isis/src/mro/apps/marciflip/assets/thumbs/T02_001000_1199_MC_00N230W.jpg new file mode 100644 index 0000000000000000000000000000000000000000..05e5f3572be6c872d86414804cd2f4a97f2862d4 Binary files /dev/null and b/isis/src/mro/apps/marciflip/assets/thumbs/T02_001000_1199_MC_00N230W.jpg differ diff --git a/isis/src/mro/apps/marciflip/assets/thumbs/T02_001000_1199_MC_00N230W.noflip.jpg b/isis/src/mro/apps/marciflip/assets/thumbs/T02_001000_1199_MC_00N230W.noflip.jpg new file mode 100644 index 0000000000000000000000000000000000000000..974028865d1e7eb4af68617c5582cb755e4b3563 Binary files /dev/null and b/isis/src/mro/apps/marciflip/assets/thumbs/T02_001000_1199_MC_00N230W.noflip.jpg differ diff --git a/isis/src/mro/apps/marciflip/assets/thumbs/gui.jpg b/isis/src/mro/apps/marciflip/assets/thumbs/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1fcfbfe93447238f427199bc7086fc9bf904a293 Binary files /dev/null and b/isis/src/mro/apps/marciflip/assets/thumbs/gui.jpg differ diff --git a/isis/src/mro/apps/marciflip/marciflip.cpp b/isis/src/mro/apps/marciflip/marciflip.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d8248834032bf5ee70c98001cbf94e80e5c955a9 --- /dev/null +++ b/isis/src/mro/apps/marciflip/marciflip.cpp @@ -0,0 +1,64 @@ +#include "Isis.h" +#include "ProcessImportPds.h" +#include "Filename.h" +#include "Brick.h" +#include "ProcessByBrick.h" +#include "OriginalLabel.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +Isis::Cube *outputCube = NULL; +int currentLine; +int filterHeight = 16; + +void flipCube(Isis::Buffer &data); + +void IsisMain (){ + ProcessByBrick p; + + Cube *icube = p.SetInputCube("FROM"); + + filterHeight = 16 / (int)icube->GetGroup("Instrument")["SummingMode"]; + p.SetBrickSize(icube->Samples(), filterHeight, icube->Bands()); + currentLine = icube->Lines(); + + UserInterface &ui = Application::GetUserInterface(); + outputCube = new Isis::Cube(); + outputCube->SetDimensions(icube->Samples(), icube->Lines(), icube->Bands()); + outputCube->Create(ui.GetFilename("TO")); + + if(icube->HasGroup("Instrument")) { + PvlGroup inst = icube->GetGroup("Instrument"); + + // change flipped keyword + inst["DataFlipped"] = ((int)inst["DataFlipped"] + 1) % 2; + + outputCube->Label()->FindObject("IsisCube").AddGroup(inst); + } + + if(icube->HasGroup("BandBin")) { + outputCube->Label()->FindObject("IsisCube").AddGroup(icube->GetGroup("BandBin")); + } + + if(icube->Label()->HasObject("OriginalLabel")) { + OriginalLabel origLabel; + icube->Read(origLabel); + outputCube->Write(origLabel); + } + + p.StartProcess(flipCube); + p.EndProcess(); + + outputCube->Close(); + delete outputCube; +} + +void flipCube(Isis::Buffer &data) { + currentLine -= filterHeight; + Brick outBrick(data.SampleDimension(), data.LineDimension(), data.BandDimension(), data.PixelType()); + outBrick.Copy(data); + outBrick.SetBasePosition(1, currentLine+1, data.Band()); + outputCube->Write(outBrick); +} diff --git a/isis/src/mro/apps/marciflip/marciflip.xml b/isis/src/mro/apps/marciflip/marciflip.xml new file mode 100644 index 0000000000000000000000000000000000000000..4d45f9d8b34168f2e80ccc1c77c6e00b90e57b6b --- /dev/null +++ b/isis/src/mro/apps/marciflip/marciflip.xml @@ -0,0 +1,113 @@ + + + + + + Flip the framelets on an MRO MARCI image + + + + This program takes an image from the Mars Reconnaissance Orbiter Color Imager + and flips the framelets, which corrects image data taken on ascending orbits. + + + + + Original Version + + + Removed references to CubeInfo + + + + + Mars Reconnaissance Orbiter + + + + + + cube + input + + Input file + + + The image to be processed + + + *.cub + + + + + cube + real + output + + Output cube + + + This is the resultant cube, containing the image data with flipped framelets. + + + *.cub + + + + + + + + + Correcting a MARCI image + + + This example covers using marciflip on a typical MARCI image + + + + FROM=T02_001000_1199_MC_00N230W.noflip.cub TO=T02_001000_1199_MC_00N230W.cub + + + This is the command line for running this program with a typical MARCI image. + + + + + + Running with default options + + This is what the interface should look like when running this program. + + + + + + + + The input image, not flipped, cropped and colorized for this example + + Since this particular input image had a RED, GREEN, and ORANGE filter, it was possible to display the image + in color. To give a better picture of the output, because MARCI takes long strips of data, this image was + cropped. In order to show the same feature as the flipped image, the crop was at line 5800 to a height of 1000 pixels. + This image was created with FLIP set to NO in marci2isis, because AUTO flipped the data. When you look closely, especially compared + to the flipped data, the features in this data are distorted. + + + + + + + The output image, cropped and colorized for this example + + Since this particular input image had a RED, GREEN, and ORANGE filter, it was possible to display the image + in color. To give a better picture of the output, because MARCI takes long strips of data, this image was + cropped at line 2800 to a height of 1000 pixels. The distortions in the original image are now gone. + + + + + + + diff --git a/isis/src/mro/apps/marciflip/tsts/Makefile b/isis/src/mro/apps/marciflip/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/marciflip/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/marciflip/tsts/default/Makefile b/isis/src/mro/apps/marciflip/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..88af4db52eac8219143299f47cd6d0e4286e0c2e --- /dev/null +++ b/isis/src/mro/apps/marciflip/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = marciflip + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/T02_001002_1200_MC_00N284W.cub \ + TO=$(OUTPUT)/flipped.cub > /dev/null; + catlab FROM=$(OUTPUT)/flipped.cub > $(OUTPUT)/flipped.pvl; diff --git a/isis/src/mro/apps/mroctx2isis/Makefile b/isis/src/mro/apps/mroctx2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/mro/apps/mroctx2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/mro/apps/mroctx2isis/mroctx2isis.cpp b/isis/src/mro/apps/mroctx2isis/mroctx2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d70e6205eed42fc077c6b60e914a4e362cec5a8b --- /dev/null +++ b/isis/src/mro/apps/mroctx2isis/mroctx2isis.cpp @@ -0,0 +1,300 @@ +#include "Isis.h" +#include "ProcessImportPds.h" +#include "ProcessByLine.h" +#include "UserInterface.h" +#include "Filename.h" +#include "iException.h" +#include "Preference.h" +#include "iString.h" +#include "Pvl.h" +#include "Table.h" +#include "Stretch.h" +#include "TextFile.h" +#include "PixelType.h" + +using namespace std; +using namespace Isis; + +// Global variables for processing functions +Stretch stretch; + +void FixDns8 (Buffer &buf); +void TranslateMroCtxLabels (Filename &labelFile, Cube *ocube); +void SaveDarkData(ProcessImportPds &process, Cube *ocube, int startPix, int endPix); +vector ConvertDarkPixels (int samples, Isis::PixelType pixelType, + unsigned char *data); +bool fillGap; + +void IsisMain (){ + ProcessImportPds p; + + //Check that the file comes from the right camera + UserInterface &ui = Application::GetUserInterface(); + Filename inFile = ui.GetFilename("FROM"); + fillGap = false; + iString id,bitMode; + int sumMode,editMode; + bool projected; + try { + Pvl lab(inFile.Expanded()); + id = (string) lab.FindKeyword ("DATA_SET_ID"); + projected = lab.HasObject("IMAGE_MAP_PROJECTION"); + if (lab.HasKeyword("SPATIAL_SUMMING")) { + sumMode = (int)lab.FindKeyword("SPATIAL_SUMMING"); + } + else { + sumMode = (int)lab.FindKeyword("SAMPLING_FACTOR"); + } + + bitMode = (string) lab.FindKeyword("SAMPLE_BIT_MODE_ID"); + if (lab.HasKeyword("EDIT_MODE_ID")) { + editMode = (int)lab.FindKeyword("EDIT_MODE_ID"); + } + else { + editMode = (int)lab.FindKeyword("SAMPLE_FIRST_PIXEL"); + } + + } + catch (iException &e) { + string msg = "Unable to read [DATA_SET_ID] from input file [" + + inFile.Expanded() + "]"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + //Checks if in file is rdr + if( projected ) { + string msg = "[" + inFile.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + id.ConvertWhiteSpace(); + id.Compress(); + id.Trim(" "); + if (id != "MRO-M-CTX-2-EDR-L0-V1.0") { + string msg = "Input file [" + inFile.Expanded() + "] does not appear to be " + + "in MRO-CTX EDR format. DATA_SET_ID is [" + id + "]"; + throw iException::Message(iException::Io,msg, _FILEINFO_); + } + + // Check to make sure the SampleBitModeId is SQROOT + if (bitMode != "SQROOT") { + string msg = "Can't handle Sample Bit Mode [" + bitMode + "]"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + //Process the file + Pvl pdsLab; + p.SetPdsFile(inFile.Expanded(), "", pdsLab); + + int startPix = 0; + int endPix = 0; + int suf = 0; + + // Set the data prefix and suffix values + if (ui.WasEntered("PREFIX")) { + endPix = ui.GetInteger("PREFIX"); + } + else { + if (sumMode == 1) { + if (editMode == 0) { + startPix = 14; + endPix = 37; + } + else { + startPix = 0; + endPix = 15; + } + } + else if (sumMode == 2) { + if (editMode == 0) { + startPix = 7; + endPix = 18; + } + else { + startPix = 0; + endPix = 7; + } + } + } + if (ui.WasEntered("SUFFIX")) { + suf = ui.GetInteger("SUFFIX"); + } + else { + if (sumMode == 1) { + if (editMode == 0) { + suf = 18; + } + else { + suf = 0; + } + } + else if (sumMode == 2) { + if (editMode == 0) { + suf = 9; + } + else { + suf = 0; + } + } + } + p.SetDataPrefixBytes(endPix+1); + p.SetDataSuffixBytes(suf); + int samps = p.Samples() - endPix - suf - 1; + p.SetDimensions(samps,p.Lines(),p.Bands()); + + // Save off the dark pixel data + p.SaveDataPrefix(); + + // Set the output bit type to Real + CubeAttributeOutput &outAtt = ui.GetOutputAttribute("TO"); + outAtt.PixelType (Isis::SignedWord); + outAtt.Minimum((double)VALID_MIN2); + outAtt.Maximum((double)VALID_MAX2); + Cube *ocube = p.SetOutputCube(ui.GetFilename("TO"), outAtt); + + // Translate the labels + p.StartProcess(); + TranslateMroCtxLabels(inFile, ocube); + + // Set up the strech for the 8 to 12 bit conversion from file + Filename *temp = new Filename("$mro/calibration/ctxsqroot_???.lut"); + temp->HighestVersion(); + TextFile *stretchPairs = new TextFile(temp->Expanded()); + + // Create the stretch pairs + stretch.ClearPairs(); + for (int i=0; iLineCount(); i++) { + iString line; + stretchPairs->GetLine(line,true); + int temp1 = line.Token(" "); + int temp2 = line.Trim(" "); + stretch.AddPair(temp1,temp2); + } + + stretchPairs->Close(); + + SaveDarkData(p, ocube, startPix, endPix); + p.EndProcess(); + + // Do 8 bit to 12 bit conversion + fillGap = ui.GetBoolean("FILLGAP"); + ProcessByLine p2; + string ioFile = ui.GetFilename("TO"); + CubeAttributeInput att; + p2.SetInputCube(ioFile, att, ReadWrite); + p2.Progress()->SetText("Converting 8 bit pixels to 16 bit"); + p2.StartProcess(FixDns8); + p2.EndProcess(); +} + +// The input buffer has a raw 16 bit buffer but the values are still 0 to 255 +void FixDns8 (Buffer &buf) { + for (int i=0; iPutGroup (inst); + ocube->PutGroup (outLabel.FindGroup("Archive", Pvl::Traverse)); + ocube->PutGroup (bbin); + ocube->PutGroup (kern); +} + +void SaveDarkData(ProcessImportPds &process, Cube *ocube, int startPix, int endPix) { + int pixNum = endPix - startPix + 1; + TableField dark("DarkPixels", TableField::Integer, pixNum); + TableRecord darkRecord; + darkRecord += dark; + Table darkTable("Ctx Prefix Dark Pixels", darkRecord); + vector > pre = process.DataPrefix(); + vector prefix = pre.at(0); + + for (int l=0; l<(int)prefix.size(); l++) { + unsigned char *linePrefix = (unsigned char *)(prefix[l]+startPix*SizeOf(process.PixelType())); + darkRecord[0] = ConvertDarkPixels(pixNum, process.PixelType(),linePrefix); + darkTable += darkRecord; + } + ocube->Write(darkTable); +} + +vector ConvertDarkPixels (int samples, Isis::PixelType pixelType, + unsigned char *data) { + Isis::Buffer pixelBuf(samples, 1, 1, Isis::SignedWord); + + for (int b=0; b calibrationPixels; + double pixel; + for (int b=0; b + + + + + Import an MRO CTX image as an Isis cube + + + + This program takes an image from the Mars Reconnaissance Orbiter Context Imager + and produces an Isis cube containing the image data. + + + + + Original Version + + + Added NaifFrameCode keyword to the Kernels group + + + Documentation fixes + + + Modified to convert from 8 to 12 bit data and pulled prefix and suffix data out of cube + + + Put dark prefix data in a table blob + + + Modified keywords to handle keywords that were modified in new data files. Modified + the PREFIX and SUFFIX parameters to automatically compute, and added documentation. + + + Added an application test + + + Added a fillgap option + + + Checks if input file is rdr. + + + Removed references to CubeInfo + + + Fixed bug where dark current data could be corrupted if FILLGAP was true + + + + + Mars Reconnaissance Orbiter + + + + + + filename + input + + Input file + + + The image to be processed + + + *.img + + + + + cube + output + + Output cube + + + This is the resultant cube, containing the image and label data. + + + *.cub + + + + + + + integer + Prefix Pixels + + Prefix dark pixels to strip off and put in a BLOB table. The default value is computed. This will compute + what is believed to be the number of suffix pixels based on data in the labels. If you find that suffix pixels are + being left on the edge of the image, adjust this parameter accordingly. + + 0 + Computed + + + integer + Suffix Pixels + + Suffix dark pixels to strip off and put in a BLOB table. The default value is computed. This will compute + what is believed to be the number of suffix pixels based on data in the labels. If you find that suffix pixels are + being left on the edge of the image, adjust this parameter accordingly. + + 0 + Computed + + + boolean + Set zeros to null + + The CTX table for the SQROOT SAMPLE_BIT_MODE_ID correlates the DN value + zero to one. Errorenous data is also set to a DN value of zero. When enabled, this + option assumes the DN values of zero are errenous data and thus zeros are set to NULL. + When disabled, this data is preserved. + + true + + + + diff --git a/isis/src/mro/apps/mroctx2isis/tsts/Makefile b/isis/src/mro/apps/mroctx2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/mro/apps/mroctx2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/apps/mroctx2isis/tsts/default/Makefile b/isis/src/mro/apps/mroctx2isis/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ce9d3c1580168b2f2c71ce4200d547aec8aaa486 --- /dev/null +++ b/isis/src/mro/apps/mroctx2isis/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = mroctx2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/P01_001473_2479_XI_67N185W.img \ + TO=$(OUTPUT)/P01_001473_2479_XI_67N185W.cub > /dev/null; diff --git a/isis/src/mro/objs/CTXCamera/CTXCamera.cpp b/isis/src/mro/objs/CTXCamera/CTXCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..313ef6d3c28ae5cfcb48dbae383e42f5ce9a2209 --- /dev/null +++ b/isis/src/mro/objs/CTXCamera/CTXCamera.cpp @@ -0,0 +1,67 @@ +#include "CTXCamera.h" +#include "iString.h" +#include "iException.h" +#include "LineScanCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraDistortionMap.h" +#include "LineScanCameraGroundMap.h" +#include "LineScanCameraSkyMap.h" + +using namespace std; +namespace Isis { + namespace Mro { + // constructors + CTXCamera::CTXCamera (Isis::Pvl &lab) : Isis::LineScanCamera(lab) { + // Set up the camera info from ik/iak kernels + SetFocalLength(); + SetPixelPitch(); + + // Get the start time from labels + Isis::PvlGroup &inst = lab.FindGroup ("Instrument",Isis::Pvl::Traverse); + string stime = inst["SpacecraftClockCount"]; + SpiceDouble etStart; + scs2e_c (NaifSpkCode(),stime.c_str(),&etStart); + + // Get other info from labels + double csum = inst["SpatialSumming"]; + double lineRate = (double) inst["LineExposureDuration"] / 1000.0; +// lineRate *= csum; + double ss = inst["SampleFirstPixel"]; + ss += 1.0; + + // Setup detector map + LineScanCameraDetectorMap *detectorMap = + new LineScanCameraDetectorMap(this,etStart,lineRate); + detectorMap->SetDetectorSampleSumming(csum); + detectorMap->SetStartingDetectorSample(ss); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap =new CameraFocalPlaneMap(this,NaifIkCode()); + + // Retrieve boresight location from instrument kernel (IK) (addendum?) + iString ikernKey = "INS" + iString((int)NaifIkCode()) + "_BORESIGHT_SAMPLE"; + double sampleBoreSight = GetDouble(ikernKey); + + ikernKey = "INS" + iString((int)NaifIkCode()) + "_BORESIGHT_LINE"; + double lineBoreSight = GetDouble(ikernKey); + + focalMap->SetDetectorOrigin(sampleBoreSight, lineBoreSight); + focalMap->SetDetectorOffset(0.0,0.0); + + // Setup distortion map + CameraDistortionMap *distMap = new CameraDistortionMap(this); + distMap->SetDistortion(NaifIkCode()); + + + // Setup the ground and sky map + new LineScanCameraGroundMap(this); + new LineScanCameraSkyMap(this); + + LoadCache(); + } + } +} + +extern "C" Isis::Camera *CTXCameraPlugin (Isis::Pvl &lab) { + return new Isis::Mro::CTXCamera(lab); +} diff --git a/isis/src/mro/objs/CTXCamera/CTXCamera.h b/isis/src/mro/objs/CTXCamera/CTXCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..a266d86f66426eeb8c32bc57afcb1b4d5d27746d --- /dev/null +++ b/isis/src/mro/objs/CTXCamera/CTXCamera.h @@ -0,0 +1,35 @@ +#ifndef CTXCamera_h +#define CTXCamera_h + +#include "LineScanCamera.h" + +namespace Isis { + namespace Mro { + /** + * @internal + * @todo Allow the programmer to apply scale and shear. + * @todo Write multiplaction method (operator*) for Affine * Affine. + * + * @history 2006-08-03 Tracie Sucharski, Added Scale method + * @history 2007-07-12 Debbie A. Cook, Added methods Coefficients and + * InverseCoefficients + * @history 2008-02-21 Steven Lambright Boresight, focal length, pixel pitch + * keywords now loaded from kernels instead of being hard-coded. + * The distortion map is now being used. + * @history 2008-08-08 Steven Lambright Made the unit test work with a Sensor + * change. Also, now using the new LoadCache(...) method instead of + * CreateCache(...). + * @history 2009-03-07 Debbie A. Cook Removed obsolute CameraDetectorMap methods + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class CTXCamera : public LineScanCamera { + public: + CTXCamera (Isis::Pvl &lab); + + ~CTXCamera () {}; + }; + }; +}; + +#endif diff --git a/isis/src/mro/objs/CTXCamera/CTXCamera.truth b/isis/src/mro/objs/CTXCamera/CTXCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..5423ffef0072faf938228ac8785167ec61901b1b --- /dev/null +++ b/isis/src/mro/objs/CTXCamera/CTXCamera.truth @@ -0,0 +1,43 @@ +Unit Test for CTXCamera... +Testing image $mro/testData/ctx_pmoi_i_00003.bottom.cub ... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK + +Testing image $mro/testData/ctx_pmoi_i_00003.top.cub ... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK + diff --git a/isis/src/mro/objs/CTXCamera/Camera.plugin b/isis/src/mro/objs/CTXCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..734693a13ec136f8ef9f7ed0c34307c5dcca89ab --- /dev/null +++ b/isis/src/mro/objs/CTXCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = MARS_RECONNAISSANCE_ORBITER/CTX + Version = 1 + Library = CTXCamera + Routine = CTXCameraPlugin +EndGroup + diff --git a/isis/src/mro/objs/CTXCamera/Makefile b/isis/src/mro/objs/CTXCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..30bcedffaf1585544c61bac4bd1d027cf6291c34 --- /dev/null +++ b/isis/src/mro/objs/CTXCamera/Makefile @@ -0,0 +1,5 @@ +INCS = CTXCamera.h +SRCS = CTXCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/mro/objs/CTXCamera/unitTest.cpp b/isis/src/mro/objs/CTXCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c93431cd396d31a3fa8aacd26d88c45a47f50d67 --- /dev/null +++ b/isis/src/mro/objs/CTXCamera/unitTest.cpp @@ -0,0 +1,96 @@ +using namespace std; + +#include +#include "iException.h" +#include "Camera.h" +#include "CameraFactory.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (int argc, char *argv[]) { + Isis::Preference::Preferences(true); + + cout << "Unit Test for CTXCamera..." << endl; + + /** CTX: The line,samp to lat,lon to line,samp tolerance was increased for this + * camera model test. + */ + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownLat[2] = {-22.00025221053369, -15.08767100514901}; + double knownLon[2] = {307.9151038426381, 309.8666470890192}; + char files[2][1024] = { "$mro/testData/ctx_pmoi_i_00003.bottom.cub", "$mro/testData/ctx_pmoi_i_00003.top.cub" }; + + for(unsigned int i = 0; i < sizeof(knownLat)/sizeof(double); i++) { + Isis::Pvl p(files[i]); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + cout << "Testing image " << files[i] << " ..." << endl; + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat[i]) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat[i] << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon[i]) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon[i] << endl; + } + + cout << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.01) deltaSamp = 0; + if (fabs(deltaLine) < 0.01) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} diff --git a/isis/src/mro/objs/HiLab/HiLab.cpp b/isis/src/mro/objs/HiLab/HiLab.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13573c4255c9b97e8c3e7f98a1b6cb64224f5bc3 --- /dev/null +++ b/isis/src/mro/objs/HiLab/HiLab.cpp @@ -0,0 +1,57 @@ +#ifndef hiLab_cpp +#define hiLab_cpp +/** + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "HiLab.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + + //! Constructs a HiLab Object + HiLab::HiLab(Cube *cube){ + PvlGroup group = cube->GetGroup("Instrument"); + p_cpmmNumber = group["CpmmNumber"]; + p_channel = group["ChannelNumber"]; + + if (group.HasKeyword("Summing")) { + p_bin = group["Summing"]; + } + else { + std::string msg = "Cannot find required Summing keyword in label"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + if (group.HasKeyword("Tdi")) { + p_tdi = group["Tdi"]; + } + else { + std::string msg = "Cannot find required Tdi keyword in label"; + throw Isis::iException::Message(Isis::iException::Io,msg,_FILEINFO_); + } + + } + //! Returns the ccd from a lookup table based on the cpmm number + int HiLab::getCcd(){ + const int cpmm2ccd[] = {0,1,2,3,12,4,10,11,5,13,6,7,8,9}; + return cpmm2ccd[p_cpmmNumber]; + } + +#endif diff --git a/isis/src/mro/objs/HiLab/HiLab.h b/isis/src/mro/objs/HiLab/HiLab.h new file mode 100644 index 0000000000000000000000000000000000000000..0cff3523a81b4d9bc8f6098f17d9bfb40fe61a2b --- /dev/null +++ b/isis/src/mro/objs/HiLab/HiLab.h @@ -0,0 +1,71 @@ +#ifndef hiLab_h +#define hiLab_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2008/05/14 21:07:26 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Cube.h" +#include "Pvl.h" + +using namespace Isis; +/** + * @brief Process HiRise label + * + * This class retrieves label keyword values from an Isis3 + * HiRise cube file. This class receives a Cube object from + * an opened HiRise cube file and has methods to return HiRise + * specific keyword values from the label. + * + * @ingroup MarsReconnaissanceOrbiter + * + * @author 2005-06-29 unknown + * + * @internal + * @history 2005-06-29 unknown - Original Version + * @history 2006-08-17 Debbie A. Cook - Added members p_bin and p_tdi + * along with methods to retrieve them and the ccd + * @history 2008-05-12 Steven Lambright - Removed references to CubeInfo + */ +class HiLab{ + public: + HiLab(Cube *cube); + + //! Returns the cpmm number read from the labels of a hiris cube + int getCpmmNumber(){return p_cpmmNumber;}; + + //! Returns the channel read from the labels of a hirise cube + int getChannel(){return p_channel;}; + + //! Returns the bin read as Summing from the labels of a hirise cube + int getBin(){return p_bin;}; + + //! Returns the tdi read from the labels of a hirise cube + int getTdi(){return p_tdi;}; + + int getCcd(); + + private: + int p_cpmmNumber; + int p_channel; + int p_bin; + int p_tdi; +}; +#endif diff --git a/isis/src/mro/objs/HiLab/HiLab.truth b/isis/src/mro/objs/HiLab/HiLab.truth new file mode 100644 index 0000000000000000000000000000000000000000..bd3830bb7bcf92ad0adbbe27eb8ddc29fa09d880 --- /dev/null +++ b/isis/src/mro/objs/HiLab/HiLab.truth @@ -0,0 +1,11 @@ +Testing constructor ... +Testing getCpmmNumber() ... +CpmmNumber 3 +Testing getChannel() ... +Channel 0 +Testing getBin() ... +Bin 4 +Testing getTdi() ... +Tdi 128 +Testing getCcd() ... +Ccd 3 diff --git a/isis/src/mro/objs/HiLab/Makefile b/isis/src/mro/objs/HiLab/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c859f3bea1f8c9a139f6b72c4902787c220fa963 --- /dev/null +++ b/isis/src/mro/objs/HiLab/Makefile @@ -0,0 +1,5 @@ +INCS = HiLab.h +SRCS = HiLab.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/mro/objs/HiLab/unitTest.cpp b/isis/src/mro/objs/HiLab/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bb119d1363594bab6887374ad231e3c6384ab30e --- /dev/null +++ b/isis/src/mro/objs/HiLab/unitTest.cpp @@ -0,0 +1,30 @@ +#include + +#include "HiLab.h" +#include "Preference.h" + +using namespace std; +using namespace Isis; + +int main(){ + Isis::Preference::Preferences(true); + + //create a dummy Isis::Progress object + Cube cube; + cube.Open("red3Test.cub"); + + cout << "Testing constructor ...\n"; + HiLab hiLab(&cube); + cout << "Testing getCpmmNumber() ...\n"; + cout << "CpmmNumber " << hiLab.getCpmmNumber() < +#include "HiriseCamera.h" +#include "LineScanCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "CameraDistortionMap.h" +#include "LineScanCameraGroundMap.h" +#include "LineScanCameraSkyMap.h" +#include + + +namespace Isis { + namespace Mro { + + + /** + * Creates a Hirise Camera Model + * + * @param lab Pvl label from the iamge + */ + HiriseCamera::HiriseCamera (Isis::Pvl &lab) : Isis::LineScanCamera(lab) { + // Setup camera characteristics from instrument and frame kernel + SetFocalLength(); + SetPixelPitch(); + //LoadFrameMounting("MRO_SPACECRAFT", "MRO_HIRISE_OPTICAL_AXIS"); + InstrumentRotation()->SetFrame(-74690); + + // Get required keywords from instrument group + Isis::PvlGroup &inst = lab.FindGroup ("Instrument",Isis::Pvl::Traverse); + int tdiMode = inst["Tdi"]; + double binMode = inst["Summing"]; + int chan = inst["ChannelNumber"]; + int cpmm = inst["CpmmNumber"]; + double deltaLineTimerCount = inst["DeltaLineTimerCount"]; + std::string stime = inst["SpacecraftClockStartCount"]; + + // Convert CPMM number to CCD number + static int cpmm2ccd[] = {0,1,2,3,12,4,10,11,5,13,6,7,8,9}; + int ccd = cpmm2ccd[cpmm]; + + // Compute the line rate, convert to seconds, and multiply by the + // downtrack summing + double unBinnedRate = (74.0 + (deltaLineTimerCount/16.0)) / 1000000.0; + double lineRate = unBinnedRate * binMode; + + // Convert the spacecraft clock count to ephemeris time + SpiceDouble et; + // The -74999 is the code to select the transformation from + // high-precision MRO SCLK to ET + scs2e_c (-74999,stime.c_str(),&et); + // Adjust the start time so that it is the effective time for + // the first line in the image file. Note that on 2006-03-29, this + // time is now subtracted as opposed to adding it. The computed start + // time in the EDR is at the first serial line. + et -= unBinnedRate * (((double) tdiMode/2.0) - 0.5); + // Effective observation + // time for all the TDI lines used for the + // first line before doing binning + et += unBinnedRate * (((double) binMode/2.0) - 0.5); + // Effective observation time of the first line + // in the image file, which is possibly binned + + // Compute effective line number within the CCD (in pixels) for the + // given TDI mode. + // This is the "centered" 0-based line number, where line 0 is the + // center of the detector array and line numbers decrease going + // towards the serial readout. Line number +64 sees a spot + // on the ground before line number 0 or -64. + double ccdLine_c = -64.0 + ((double) tdiMode / 2.0); + + // Setup detector map for transform of image pixels to detector position + // CameraDetectorMap *detectorMap = + // new LineScanCameraDetectorMap(this,et,lineRate); + LineScanCameraDetectorMap *detectorMap = + new LineScanCameraDetectorMap(this,et,lineRate); + detectorMap->SetDetectorSampleSumming(binMode); + detectorMap->SetDetectorLineSumming(binMode); + if (chan == 0) { + detectorMap->SetStartingDetectorSample(1025.0); + } + + // Setup focal plane map for transform of detector position to + // focal plane x/y. This will read the appropriate CCD + // transformation coefficients from the instrument kernel + CameraFocalPlaneMap *focalMap = + new CameraFocalPlaneMap(this,-74600-ccd); + focalMap->SetDetectorOrigin(1024.5,0.0); + focalMap->SetDetectorOffset(0.0,ccdLine_c); + + // Setup distortion map. This will read the optical distortion + // coefficients from the instrument kernel + CameraDistortionMap *distortionMap = new CameraDistortionMap(this); + distortionMap->SetDistortion(NaifIkCode()); + + // Setup the ground and sky map to transform undistorted focal + // plane x/y to lat/lon or ra/dec respectively. + new LineScanCameraGroundMap(this); + new LineScanCameraSkyMap(this); + + LoadCache(); + } + + //! Destroys the HiriseCamera object + HiriseCamera::~HiriseCamera () {} + } +} + +// H i r i s e C a m e r a P l u g i n +// +extern "C" Isis::Camera *HiriseCameraPlugin (Isis::Pvl &lab) { + return new Isis::Mro::HiriseCamera(lab); +} diff --git a/isis/src/mro/objs/HiriseCamera/HiriseCamera.h b/isis/src/mro/objs/HiriseCamera/HiriseCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..e19e0f36996b93992e1b65651361581f7e0bdfb9 --- /dev/null +++ b/isis/src/mro/objs/HiriseCamera/HiriseCamera.h @@ -0,0 +1,63 @@ +#ifndef HiriseCamera_h +#define HiriseCamera_h + +/** + * @file + * $Revision: 1.4 $ + * $Date: 2009/08/31 15:12:31 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "LineScanCamera.h" + +namespace Isis { + namespace Mro { + /** + * @brief Hirise Camera Model + * + * This class is the implementation of the camera model + * for the MRO HiRISE instrument. + * + * @ingroup SpiceInstrumentsAndCameras + * @ingroup MarsReconnaissanceOrbiter + * + * @author 2005-02-22 Jim Torson + * + * @internal + * @history 2005-10-03 Elizabeth Miller - Modified file to support Doxygen + * documentation + * @history 2008-08-08 Steven Lambright Made the unit test work with a Sensor + * change. Also, now using the new LoadCache(...) method instead of + * CreateCache(...). + * @history 2009-03-08 Debbie A. Cook Removed reference to obsolete LineScanCameraDetectorMap + * method SetXAxisTimeDependent + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class HiriseCamera : public Isis::LineScanCamera { + public: + // Constructs a HiriseCamera object + HiriseCamera (Isis::Pvl &lab); + + // Destroys the HiriseCamera object + ~HiriseCamera (); + }; + }; +}; + +#endif diff --git a/isis/src/mro/objs/HiriseCamera/HiriseCamera.truth b/isis/src/mro/objs/HiriseCamera/HiriseCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..e94f851ff39443075abafafa19ebd41510e2a060 --- /dev/null +++ b/isis/src/mro/objs/HiriseCamera/HiriseCamera.truth @@ -0,0 +1,20 @@ +Unit Test for HiriseCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/mro/objs/HiriseCamera/Makefile b/isis/src/mro/objs/HiriseCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a9d66c7fb11580f422566fd7c92f6d906447f351 --- /dev/null +++ b/isis/src/mro/objs/HiriseCamera/Makefile @@ -0,0 +1,5 @@ +INCS = HiriseCamera.h +SRCS = HiriseCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/mro/objs/HiriseCamera/unitTest.cpp b/isis/src/mro/objs/HiriseCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64cab2f56b238d24dfd80612903473f892908dd5 --- /dev/null +++ b/isis/src/mro/objs/HiriseCamera/unitTest.cpp @@ -0,0 +1,94 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for HiriseCamera..." << endl; + /** HIRISE: The line,samp to lat,lon to line,samp tolerance was increased for this + * camera model test. + */ + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + // double knownLat = -1.111697540639317; + // double knownLon = 203.272499681125; + double knownLat = -1.111697574811016; + double knownLon = 203.2724994115664; + + Isis::Pvl p("$mro/testData/PSP_001446_1790_BG12_0.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.08) deltaSamp = 0; + if (fabs(deltaLine) < 0.08) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/mro/objs/Makefile b/isis/src/mro/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/mro/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/mro/objs/MarciCamera/Camera.plugin b/isis/src/mro/objs/MarciCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..ccbb8d1d79945d5430dd754a54bf3c17123da242 --- /dev/null +++ b/isis/src/mro/objs/MarciCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = MarsReconnaissanceOrbiter/Marci + Version = 1 + Library = MarciCamera + Routine = MarciCameraPlugin +EndGroup + diff --git a/isis/src/mro/objs/MarciCamera/Makefile b/isis/src/mro/objs/MarciCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..18148163f7fc1c095e480629fbe0e1d311d935b6 --- /dev/null +++ b/isis/src/mro/objs/MarciCamera/Makefile @@ -0,0 +1,5 @@ +INCS = MarciDistortionMap.h MarciCamera.h +SRCS = MarciDistortionMap.cpp MarciCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/mro/objs/MarciCamera/MarciCamera.cpp b/isis/src/mro/objs/MarciCamera/MarciCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..14cb50d75b7cb08171417804253fbbd9c98228de --- /dev/null +++ b/isis/src/mro/objs/MarciCamera/MarciCamera.cpp @@ -0,0 +1,166 @@ +#include + +#include "MarciCamera.h" +#include "PushFrameCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "PushFrameCameraGroundMap.h" +#include "CameraSkyMap.h" +#include "MarciDistortionMap.h" + +using namespace std; + +namespace Isis { + namespace Mro { + + /** + * Constructor for the Marci Camera Model + * + * @param lab Pvl Label to create the camera model from + * + * @throws Isis::iException::User - The image does not appear to be a Marci + * image + */ + MarciCamera::MarciCamera (Isis::Pvl &lab) : Isis::PushFrameCamera(lab) { + Isis::PvlGroup &inst = lab.FindGroup ("Instrument",Isis::Pvl::Traverse); + // make sure it is a marci image + if (inst["InstrumentId"][0] != "Marci") { + string msg = "The image does not appear to be a Marci Image"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Set up the camera characteristics + SetFocalLength(); + + string pixelPitchKey = "INS" + iString((int)NaifIkCode()) + "_PIXEL_SIZE"; + SetPixelPitch(GetDouble(pixelPitchKey)); + + // Get necessary variables + p_exposureDur = inst["ExposureDuration"]; + p_interframeDelay = inst["InterframeDelay"]; + int sumMode = inst["SummingMode"]; + + // Get the start and end time + double et; + string stime = inst["SpacecraftClockCount"]; + scs2e_c (NaifSclkCode(),stime.c_str(),&et); + p_etStart = et - ((p_exposureDur / 1000.0) / 2.0); + p_nframelets = ParentLines() / sumMode; + + // These numbers came from "MARCI_CTX_Cal_Report_v1.5.pdf" page 7 (Bandpasses & downlinked detector rows) + std::map filterToDetectorOffset; + filterToDetectorOffset.insert( std::pair("BLUE", 709) ); + filterToDetectorOffset.insert( std::pair("GREEN", 734) ); + filterToDetectorOffset.insert( std::pair("ORANGE", 760) ); + filterToDetectorOffset.insert( std::pair("RED", 786) ); + filterToDetectorOffset.insert( std::pair("NIR", 811) ); + filterToDetectorOffset.insert( std::pair("LONG_UV", 266) ); + filterToDetectorOffset.insert( std::pair("SHORT_UV", 293) ); + + std::map filterToFilterNumbers; + filterToFilterNumbers.insert( std::pair("BLUE", 0) ); + filterToFilterNumbers.insert( std::pair("GREEN", 1) ); + filterToFilterNumbers.insert( std::pair("ORANGE", 2) ); + filterToFilterNumbers.insert( std::pair("RED", 3) ); + filterToFilterNumbers.insert( std::pair("NIR", 4) ); + filterToFilterNumbers.insert( std::pair("LONG_UV", 5) ); + filterToFilterNumbers.insert( std::pair("SHORT_UV", 6) ); + + int frameletOffsetFactor = inst["ColorOffset"]; + + if((int)inst["DataFlipped"] != 0) frameletOffsetFactor *= -1; + std::map filterToFrameletOffset; + filterToFrameletOffset.insert( std::pair("NIR", 0*frameletOffsetFactor) ); + filterToFrameletOffset.insert( std::pair("RED", 1*frameletOffsetFactor) ); + filterToFrameletOffset.insert( std::pair("ORANGE", 2*frameletOffsetFactor) ); + filterToFrameletOffset.insert( std::pair("GREEN", 3*frameletOffsetFactor) ); + filterToFrameletOffset.insert( std::pair("BLUE", 4*frameletOffsetFactor) ); + filterToFrameletOffset.insert( std::pair("LONG_UV", 5*frameletOffsetFactor) ); + filterToFrameletOffset.insert( std::pair("SHORT_UV", 6*frameletOffsetFactor) ); + + // Get the keywords from labels + const PvlGroup &bandBin = lab.FindGroup("BandBin",Isis::Pvl::Traverse); + const PvlKeyword &filtNames = bandBin["FilterName"]; + + for (int i=0; isecond); + p_filterNumbers.push_back(filterToFilterNumbers.find(filtNames[i])->second); + p_frameletOffsets.push_back(filterToFrameletOffset.find(filtNames[i])->second); + } + + // Setup detector map + double frameletRate = p_interframeDelay; + PushFrameCameraDetectorMap *dmap = + new PushFrameCameraDetectorMap(this,p_etStart,frameletRate,16); + dmap->SetDetectorSampleSumming(sumMode); + dmap->SetDetectorLineSumming(sumMode); + dmap->SetGeometricallyFlippedFramelets(false); + + int numFramelets = ParentLines() / (16 / sumMode); + bool flippedFramelets = (int)inst["DataFlipped"] != 0; + dmap->SetFlippedFramelets(flippedFramelets, numFramelets); + + // Setup focal plane map + new CameraFocalPlaneMap(this, -74400); + + if((int)NaifIkCode() == -74410) { + // The line detector origin is in the middle of the orange framelet + FocalPlaneMap()->SetDetectorOrigin(512.5, 760.0 + 8.5); + } + else if((int)NaifIkCode() == -74420) { + FocalPlaneMap()->SetDetectorOrigin(512.5, 288.5); + } + else { + string msg = "Unrecognized NaifIkCode [" + iString((int)NaifIkCode()) + "]"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + + // Setup distortion map + new MarciDistortionMap(this, NaifIkCode()); + + // Setup the ground and sky map + bool evenFramelets = (inst["Framelets"][0] == "Even"); + new PushFrameCameraGroundMap(this, evenFramelets); + new CameraSkyMap(this); + LoadCache(); + + if(sumMode == 1) { + SetGeometricTilingHint(16, 4); + } + else if(sumMode == 2) { + SetGeometricTilingHint(8, 4); + } + else if(sumMode == 4) { + SetGeometricTilingHint(4, 4); + } + else { + SetGeometricTilingHint(2, 2); + } + } + + /** + * Sets the band in the camera model + * + * @param vband The band number to set + */ + void MarciCamera::SetBand (const int vband) { + Camera::SetBand(vband); + + PushFrameCameraDetectorMap *dmap = (PushFrameCameraDetectorMap *)DetectorMap(); + dmap->SetBandFirstDetectorLine(p_detectorStartLines[vband-1]); + dmap->SetFrameletOffset(p_frameletOffsets[vband-1]); + + MarciDistortionMap *distmap = (MarciDistortionMap *)DistortionMap(); + distmap->SetFilter(p_filterNumbers[vband-1]); + } + } +} + +// Plugin +extern "C" Isis::Camera *MarciCameraPlugin (Isis::Pvl &lab) { + return new Isis::Mro::MarciCamera(lab); +} diff --git a/isis/src/mro/objs/MarciCamera/MarciCamera.h b/isis/src/mro/objs/MarciCamera/MarciCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..25adeddfe5aa2c8bf5af277927629546ea38b5bd --- /dev/null +++ b/isis/src/mro/objs/MarciCamera/MarciCamera.h @@ -0,0 +1,65 @@ +#ifndef MarciCamera_h +#define MarciCamera_h + +#include "PushFrameCamera.h" + +namespace Isis { + namespace Mro { + /** + * @brief Marci Camera Model + * + * This is the camera model for the MARCI Instrument + * + * @ingroup SpiceInstrumentsAndCameras + * @ingroup MarsReconnaissanceOrbiter + * + * @author 2008-10-23 Steven Lambright + * + * @internal + * @history 2008-11-19 Steven Lambright - Added distortion model, made VIS + * bands other than orange work + * @history 2008-11-25 Steven Lambright - The coloroffset now works properly; + * if an offset is supplied in marci2isis the cube will still project + * properly. + * @history 2009-03-17 Steven Lambright - Fixed UV to work with the distortion + * model correctly + * @history 2009-05-21 Steven Lambright - Fixed GeometricTilingHint for summed + * images + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class MarciCamera : public Isis::PushFrameCamera { + public: + // constructor + MarciCamera (Isis::Pvl &lab); + + //! Destroys the Themis Vis Camera object + ~MarciCamera () {}; + + // Sets the band to the band number given + void SetBand (const int band); + + /** + * The camera model is band dependent, so this method returns false + * + * @return bool False + */ + bool IsBandIndependent () { return false; }; + + private: + void StoreCoefficients(int naifIkCode); + void RestoreCoefficients(int vband); + + double p_etStart; //! p_detectorStartLines; + std::vector p_filterNumbers; + std::vector p_frameletOffsets; + }; + }; +}; +#endif + diff --git a/isis/src/mro/objs/MarciCamera/MarciCamera.truth b/isis/src/mro/objs/MarciCamera/MarciCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..47521504f16167a4e77d97d8539611dc46712ead --- /dev/null +++ b/isis/src/mro/objs/MarciCamera/MarciCamera.truth @@ -0,0 +1,20 @@ +Unit Test for MarciCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/mro/objs/MarciCamera/MarciDistortionMap.cpp b/isis/src/mro/objs/MarciCamera/MarciDistortionMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8ad575b0abc282d1775fcc14b6e8c4fec2d7fd2 --- /dev/null +++ b/isis/src/mro/objs/MarciCamera/MarciDistortionMap.cpp @@ -0,0 +1,197 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/11/24 16:40:30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include + +#include "iString.h" +#include "MarciDistortionMap.h" + +namespace Isis { + /** Camera distortion map constructor + * + * Create a camera distortion map. This class maps between distorted + * and undistorted focal plane x/y's. The default mapping is the + * identity, that is, the focal plane x/y and undistorted focal plane + * x/y will be identical. + * + * @param parent the parent camera that will use this distortion map + * @param zDirection the direction of the focal plane Z-axis + * (either 1 or -1) + * + */ + MarciDistortionMap::MarciDistortionMap(Camera *parent, int naifIkCode) : CameraDistortionMap(parent) { + std::string odkkey = "INS" + Isis::iString(naifIkCode) + "_DISTORTION_COEFFS"; + + for(int i = 0; i < 4; i++) { + p_odk.push_back(p_camera->GetDouble(odkkey, i)); + } + } + + /** Compute undistorted focal plane x/y + * + * Compute undistorted focal plane x/y given a distorted focal plane x/y. + * + * @param dx distorted focal plane x in millimeters + * @param dy distorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + * @todo Generalize polynomial equation + */ + bool MarciDistortionMap::SetFocalPlane(const double dx, const double dy) { + p_focalPlaneX = dx; + p_focalPlaneY = dy; + + double dxPix = p_focalPlaneX / p_camera->PixelPitch(); + double dyPix = p_focalPlaneY / p_camera->PixelPitch(); + + // Get the distance from the focal plane center and if we are close + // then skip the distortion + double radialDist2 = (dxPix * dxPix) + (dyPix * dyPix); + + if (radialDist2 <= 1.0E-3) { + p_undistortedFocalPlaneX = dx; + p_undistortedFocalPlaneY = dy; + return true; + } + + // Ok we need to apply distortion correction + double radialDist4 = radialDist2 * radialDist2; + double radialDist6 = radialDist4 * radialDist2; + + double uRadialDist = p_odk[0] + radialDist2 * p_odk[1] + + radialDist4 * p_odk[2] + + radialDist6 * p_odk[3]; + + // double radialDist = sqrt(radialDist2); + double uxPix = dxPix * uRadialDist; + double uyPix = dyPix * uRadialDist; + + + p_undistortedFocalPlaneX = uxPix * p_camera->PixelPitch(); + p_undistortedFocalPlaneY = uyPix * p_camera->PixelPitch(); + + return true; + } + + /** Compute distorted focal plane x/y + * + * Compute distorted focal plane x/y given an undistorted focal plane x/y. + * + * @param ux undistorted focal plane x in millimeters + * @param uy undistorted focal plane y in millimeters + * + * @return if the conversion was successful + * @see SetDistortion + * @todo Generalize polynomial equation + * @todo Figure out a better solution for divergence condition + */ + bool MarciDistortionMap::SetUndistortedFocalPlane(const double ux, + const double uy) { + p_undistortedFocalPlaneX = ux; + p_undistortedFocalPlaneY = uy; + + double uxPix = ux / p_camera->PixelPitch(); + double uyPix = uy / p_camera->PixelPitch(); + + double dxPix = GuessDx(uxPix); + double dyPix = uyPix; + + // Get the distance from the focal plane center and if we are close + // then skip the distortion + double Ru = sqrt((uxPix * uxPix) + (uyPix *uyPix)); + + if (Ru <= 1.0E-6) { + p_focalPlaneX = ux; + p_focalPlaneY = uy; + return true; + } + + double delta = 1.0; + int iter = 0; + + double Rd = sqrt((dxPix * dxPix) + (dyPix *dyPix)); + + while(fabs(delta) > 1E-9) { + if(fabs(delta) > 1E30 || iter > 50) { + return false; + } + + double Rd2 = Rd * Rd; + double Rd3 = Rd2 * Rd; + double Rd4 = Rd3 * Rd; + double Rd5 = Rd4 * Rd; + double Rd6 = Rd5 * Rd; + + double fRd = p_odk[0] + Rd2 * p_odk[1] + + Rd4 * p_odk[2] + + Rd6 * p_odk[3] - Ru * (1.0 / Rd); + + double fRd2 = 2 * p_odk[1] * Rd + + 4 * p_odk[2] * Rd3 + + 6 * p_odk[3] * Rd5 + + Ru * (1.0 / Rd2); + + delta = fRd / fRd2; + + Rd = Rd - delta; + + iter ++; + } + + dxPix = uxPix * (Rd / Ru); + dyPix = uyPix * (Rd / Ru); + + p_focalPlaneX = dxPix * p_camera->PixelPitch(); + p_focalPlaneY = dyPix * p_camera->PixelPitch(); + + return true; + } + + double MarciDistortionMap::GuessDx(double uX) { + // We're using natural log fits, but if uX < 1 the fit doesnt work + if(fabs(uX) < 1) return uX; + + if(p_filter == 0) { // BLUE FILTER + return (1.4101 * log(fabs(uX))); + } + + else if(p_filter == 1) { // GREEN FILTER + return (1.1039 * log(fabs(uX))); + } + + else if(p_filter == 2) { // ORANGE FILTER + return (0.8963 * log(fabs(uX)) + 2.1644); + } + + else if(p_filter == 3) { // RED FILTER + return (1.1039 * log(fabs(uX))); + } + + else if(p_filter == 4) { // NIR FILTER + return (1.4101 * log(fabs(uX))); + } + + return uX; + } +} + diff --git a/isis/src/mro/objs/MarciCamera/MarciDistortionMap.h b/isis/src/mro/objs/MarciCamera/MarciDistortionMap.h new file mode 100644 index 0000000000000000000000000000000000000000..01b535e13ca472585db7e0b882074c06b50d6ab6 --- /dev/null +++ b/isis/src/mro/objs/MarciCamera/MarciDistortionMap.h @@ -0,0 +1,61 @@ +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/11/24 16:40:31 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#ifndef MarciDistortionMap_h +#define MarciDistortionMap_h + +#include +#include "CameraDistortionMap.h" + +namespace Isis { + /** Distort/undistort focal plane coordinates + * + * Creates a map for adding/removing optical distortions + * from the focal plane of a camera. + * + * @ingroup Camera + * + * @see Camera + * + * @author 2008-08-22 Steven Lambright + * + * @internal + */ + class MarciDistortionMap : public CameraDistortionMap { + public: + MarciDistortionMap(Camera *parent, int naifIkCode); + + //! Destructor + virtual ~MarciDistortionMap() {}; + + virtual bool SetFocalPlane(const double dx, const double dy); + + virtual bool SetUndistortedFocalPlane(const double ux, const double uy); + + void SetFilter(int filter) { p_filter = filter; } + + private: + double GuessDx(double uX); + int p_filter; + }; +}; +#endif diff --git a/isis/src/mro/objs/MarciCamera/unitTest.cpp b/isis/src/mro/objs/MarciCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f7b30f412c9f692b38cdb30820f98020de7ebf58 --- /dev/null +++ b/isis/src/mro/objs/MarciCamera/unitTest.cpp @@ -0,0 +1,93 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for MarciCamera..." << endl; + /** HIRISE: The upper corner positions were changed for this unit test + */ + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + // double knownLat = -87.58875692974748; + // double knownLon = 21.19902564370578; + double knownLat = -87.58875742697279; + double knownLon = 21.198690065427; + + Isis::Pvl p("$mro/testData/P12_005911_3396_MA_00N009W.cropped.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 20); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 17.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 1E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.01) deltaSamp = 0; + if (fabs(deltaLine) < 0.01) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/mro/tsts/Makefile b/isis/src/mro/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..016388fc898d8c89f380cae1fd08942c29611582 --- /dev/null +++ b/isis/src/mro/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-42s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/mro/tsts/hirise/Makefile b/isis/src/mro/tsts/hirise/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9a1cdda5f70c91da6c53527c9e33ff2cdf104281 --- /dev/null +++ b/isis/src/mro/tsts/hirise/Makefile @@ -0,0 +1,40 @@ +APP1NAME = hi2isis +APP2NAME = spiceinit +APP3NAME = campt +APP4NAME = getsn + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APP1NAME) from= $(INPUT)/PSP_010186_1785_RED3_1.IMG \ + to= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--hi2isis-spiceinit.cub > /dev/null + + $(APP2NAME) from= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--hi2isis-spiceinit.cub \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--hi2isis-spiceinit.cub \ + to= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--finalOutput.pvl SAMPLE=1 LINE=1 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--hi2isis-spiceinit.cub \ + to= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--finalOutput.pvl SAMPLE=256 LINE=1 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--hi2isis-spiceinit.cub \ + to= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--finalOutput.pvl SAMPLE=256 LINE=5000 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--hi2isis-spiceinit.cub \ + to= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--finalOutput.pvl SAMPLE=1 LINE=5000 ALLOWOUTSIDE=no \ + > /dev/null + + $(APP3NAME) from= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--hi2isis-spiceinit.cub \ + to= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--finalOutput.pvl SAMPLE=128 LINE=2500 ALLOWOUTSIDE=no \ + > /dev/null + + echo -e "\nOutput of getsn..." > $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--getsnOutput.txt && \ + $(APP4NAME) from= $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--hi2isis-spiceinit.cub \ + >> $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--getsnOutput.txt + + $(RM) $(OUTPUT)/PSP_010186_1785_RED3_1.IMG--hi2isis-spiceinit.cub > /dev/null + $(RM) $(OUTPUT)/../print.prt > /dev/null diff --git a/isis/src/odyssey/Makefile b/isis/src/odyssey/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/odyssey/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/odyssey/apps/Makefile b/isis/src/odyssey/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/odyssey/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/odyssey/apps/thm2isis/Makefile b/isis/src/odyssey/apps/thm2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/odyssey/apps/thm2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/odyssey/apps/thm2isis/assets/images/gui.jpg b/isis/src/odyssey/apps/thm2isis/assets/images/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3f3708062efb5dec7f6a391abd918761626ad7d Binary files /dev/null and b/isis/src/odyssey/apps/thm2isis/assets/images/gui.jpg differ diff --git a/isis/src/odyssey/apps/thm2isis/assets/images/input.jpg b/isis/src/odyssey/apps/thm2isis/assets/images/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c7fc2b29347d34c84751d474c38f2a9fe741cfb0 Binary files /dev/null and b/isis/src/odyssey/apps/thm2isis/assets/images/input.jpg differ diff --git a/isis/src/odyssey/apps/thm2isis/assets/images/output1.jpg b/isis/src/odyssey/apps/thm2isis/assets/images/output1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..adce0f67178d3356ed215657061ae374020bcbad Binary files /dev/null and b/isis/src/odyssey/apps/thm2isis/assets/images/output1.jpg differ diff --git a/isis/src/odyssey/apps/thm2isis/assets/images/output2.jpg b/isis/src/odyssey/apps/thm2isis/assets/images/output2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4c78dd5607bba66f2664411a41b243195c083f6f Binary files /dev/null and b/isis/src/odyssey/apps/thm2isis/assets/images/output2.jpg differ diff --git a/isis/src/odyssey/apps/thm2isis/assets/thumbs/gui.jpg b/isis/src/odyssey/apps/thm2isis/assets/thumbs/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4cbb8dc941f54748060eeb89507c325f64c053ef Binary files /dev/null and b/isis/src/odyssey/apps/thm2isis/assets/thumbs/gui.jpg differ diff --git a/isis/src/odyssey/apps/thm2isis/assets/thumbs/input.jpg b/isis/src/odyssey/apps/thm2isis/assets/thumbs/input.jpg new file mode 100644 index 0000000000000000000000000000000000000000..30d3a3fe0efa7332fe5a8627cc41583a171413bf Binary files /dev/null and b/isis/src/odyssey/apps/thm2isis/assets/thumbs/input.jpg differ diff --git a/isis/src/odyssey/apps/thm2isis/assets/thumbs/output1.jpg b/isis/src/odyssey/apps/thm2isis/assets/thumbs/output1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..56880434df02ae08676a631a2b9e2d2fcf4be82c Binary files /dev/null and b/isis/src/odyssey/apps/thm2isis/assets/thumbs/output1.jpg differ diff --git a/isis/src/odyssey/apps/thm2isis/assets/thumbs/output2.jpg b/isis/src/odyssey/apps/thm2isis/assets/thumbs/output2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f357f85ae0a68228c3f0234cdc3d90d4b8db17b4 Binary files /dev/null and b/isis/src/odyssey/apps/thm2isis/assets/thumbs/output2.jpg differ diff --git a/isis/src/odyssey/apps/thm2isis/thm2isis.cpp b/isis/src/odyssey/apps/thm2isis/thm2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f4b7bc3ff8be0ced019f70519acdcc816afea08 --- /dev/null +++ b/isis/src/odyssey/apps/thm2isis/thm2isis.cpp @@ -0,0 +1,263 @@ +#include "Isis.h" + +#include +#include + +#include "ProcessImportPds.h" +#include "LineManager.h" +#include "UserInterface.h" +#include "CubeAttribute.h" +#include "Filename.h" +#include "iException.h" +#include "iTime.h" +#include "ProcessByBrick.h" +#include "Brick.h" +#include "OriginalLabel.h" + +using namespace std; +using namespace Isis; + +vector outputCubes; +int frameletLines; +void TranslateLabels(Pvl &labelFile, Pvl &isis3, int numBands); +void separateFrames(Buffer &in); + +void IsisMain() +{ + // Grab the file to import + ProcessImportPds p; + outputCubes.clear(); + frameletLines = 192; + UserInterface &ui = Application::GetUserInterface(); + Filename in = ui.GetFilename("FROM"); + + // Make sure it is a Themis EDR/RDR + bool projected; + try + { + Pvl lab(in.Expanded()); + projected = lab.HasObject("IMAGE_MAP_PROJECTION"); + iString id; + id = (string)lab["DATA_SET_ID"]; + id.ConvertWhiteSpace(); + id.Compress(); + id.Trim(" "); + if(id.find("ODY-M-THM") == string::npos) + { + string msg = "Invalid DATA_SET_ID [" + id + "]"; + throw iException::Message(iException::Pvl, msg, _FILEINFO_); + } + } + catch(iException &e) + { + string msg = "Input file [" + in.Expanded() + + "] does not appear to be " + + "in Themis EDR/RDR format"; + throw iException::Message(iException::Io, msg, _FILEINFO_); + } + + //Checks if in file is rdr + if(projected) + { + string msg = "[" + in.Name() + "] appears to be an rdr file."; + msg += " Use pds2isis."; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + // Ok looks good ... set it as the PDS file + Pvl pdsLab; + p.SetPdsFile(in.Expanded(), "", pdsLab); + + OriginalLabel origLabels(pdsLab); + + Pvl isis3Lab; + TranslateLabels(pdsLab, isis3Lab, p.Bands()); + + // Set up the output cube + Filename outFile(ui.GetFilename("TO")); + PvlGroup &inst = isis3Lab.FindGroup("Instrument", Pvl::Traverse); + + if((string)inst["InstrumentId"] == "THEMIS_VIS") + { + Cube *even = new Cube(); + Cube *odd = new Cube(); + + even->SetDimensions(p.Samples(), p.Lines(), p.Bands()); + even->SetPixelType(Isis::Real); + odd->SetDimensions(p.Samples(), p.Lines(), p.Bands()); + odd->SetPixelType(Isis::Real); + + string evenFile = outFile.Path() + "/" + outFile.Basename() + ".even.cub"; + string oddFile = outFile.Path() + "/" + outFile.Basename() + ".odd.cub"; + + even->Create(evenFile); + odd->Create(oddFile); + + frameletLines = 192 / ((int)inst["SpatialSumming"]); + + outputCubes.push_back(odd); + outputCubes.push_back(even); + } + else + { + Cube *outCube = new Cube(); + outCube->SetDimensions(p.Samples(), p.Lines(), p.Bands()); + outCube->SetPixelType(Isis::Real); + + outCube->Create(outFile.Expanded()); + outputCubes.push_back(outCube); + } + + // Import the file and then translate labels + p.StartProcess(separateFrames); + p.EndProcess(); + + for(int i = 0; i < (int)outputCubes.size(); i++) + { + for(int grp = 0; grp < isis3Lab.Groups(); grp++) + { + + // vis image? + if(outputCubes.size() != 1) + { + int numFramelets = p.Lines() / frameletLines; + isis3Lab.FindGroup("Instrument").AddKeyword( + PvlKeyword("NumFramelets", numFramelets), Pvl::Replace + ); + + string frameletType = ((i == 0) ? "Odd" : "Even"); + isis3Lab.FindGroup("Instrument").AddKeyword( + PvlKeyword("Framelets", frameletType), Pvl::Replace + ); + } + + outputCubes[i]->PutGroup(isis3Lab.Group(grp)); + } + + outputCubes[i]->Write(origLabels); + outputCubes[i]->Close(); + delete outputCubes[i]; + } + + outputCubes.clear(); +} + +//! Separates each of the individual VIS frames into their own file +void separateFrames(Buffer &in) +{ + // (line-1)/frameletHeight % numOutImages + int outputCube = (in.Line() - 1) / frameletLines % outputCubes.size(); + LineManager mgr(*outputCubes[outputCube]); + mgr.SetLine(in.Line(), in.Band()); + + // mgr.Copy(in); doesn't work because the raw buffers dont match + for(int i = 0; i < mgr.size(); i++) + mgr[i] = in[i]; + + outputCubes[outputCube]->Write(mgr); + + // Null out every other cube + for(int i = 0; i < (int)outputCubes.size(); i++) + { + if(i == outputCube) continue; + + LineManager mgr(*outputCubes[i]); + mgr.SetLine(in.Line(), in.Band()); + + for(int j = 0; j < mgr.size(); j++) + { + mgr[j] = Isis::Null; + } + + outputCubes[i]->Write(mgr); + } +} + +void TranslateLabels(Pvl &pdsLab, Pvl &isis3, int numBands) +{ + // Create the Instrument Group + PvlGroup inst("Instrument"); + inst += PvlKeyword("SpacecraftName", "MARS_ODYSSEY"); + string instId = (string) pdsLab["InstrumentId"] + "_" + + (string) pdsLab["DetectorId"]; + inst += PvlKeyword("InstrumentId", instId); + inst += PvlKeyword("TargetName", (string) pdsLab["TargetName"]); + inst += PvlKeyword("MissionPhaseName", (string) pdsLab["MissionPhaseName"]); + inst += PvlKeyword("StartTime", (string)pdsLab["StartTime"]); + inst += PvlKeyword("StopTime", (string)pdsLab["StopTime"]); + inst += PvlKeyword("SpacecraftClockCount", + (string) pdsLab["SpacecraftClockStartCount"]); + + PvlObject &sqube = pdsLab.FindObject("SPECTRAL_QUBE"); + if(instId == "THEMIS_IR") + { + inst += PvlKeyword("GainNumber", (string)sqube["GainNumber"]); + inst += PvlKeyword("OffsetNumber", (string)sqube["OffsetNumber"]); + inst += PvlKeyword("MissingScanLines", (string)sqube["MissingScanLines"]); + inst += PvlKeyword("TimeDelayIntegration", + (string)sqube["TimeDelayIntegrationFlag"]); + if(sqube.HasKeyword("SpatialSumming")) + { + inst += PvlKeyword("SpatialSumming", (string)sqube["SpatialSumming"]); + } + } + else + { + inst += PvlKeyword("ExposureDuration", (string)sqube["ExposureDuration"]); + inst += PvlKeyword("InterframeDelay", (string)sqube["InterframeDelay"]); + inst += PvlKeyword("SpatialSumming", (string)sqube["SpatialSumming"]); + } + + // Add at time offset to the Instrument group + UserInterface &ui = Application::GetUserInterface(); + double spacecraftClockOffset = ui.GetDouble("TIMEOFFSET"); + inst += PvlKeyword("SpacecraftClockOffset", spacecraftClockOffset, "seconds"); + + isis3.AddGroup(inst); + + // Create the Band bin Group + PvlGroup bandBin("BandBin"); + PvlKeyword originalBand("OriginalBand"); + for(int i = 1; i <= numBands; i++) + { + originalBand.AddValue(i); + } + bandBin += originalBand; + bandBin += sqube.FindGroup("BandBin")["BandBinCenter"]; + bandBin += sqube.FindGroup("BandBin")["BandBinWidth"]; + bandBin += sqube.FindGroup("BandBin")["BandBinFilterNumber"]; + bandBin["BandBinCenter"].SetName("Center"); + bandBin["BandBinWidth"].SetName("Width"); + bandBin["BandBinFilterNumber"].SetName("FilterNumber"); + isis3.AddGroup(bandBin); + + // Create the archive Group + PvlGroup arch("Archive"); + arch += PvlKeyword("DataSetId", (string)pdsLab["DataSetId"]); + arch += PvlKeyword("ProducerId", (string)pdsLab["ProducerId"]); + arch += PvlKeyword("ProductId", (string)pdsLab["ProductId"]); + arch += PvlKeyword("ProductCreationTime", + (string)pdsLab["ProductCreationTime"]); + arch += PvlKeyword("ProductVersionId", (string)pdsLab["ProductVersionId"]); +// arch += PvlKeyword("ReleaseId",(string)pdsLab["ReleaseId"]); + arch += PvlKeyword("OrbitNumber", (string)pdsLab["OrbitNumber"]); + + arch += PvlKeyword("FlightSoftwareVersionId", + (string)sqube["FlightSoftwareVersionId"]); + arch += PvlKeyword("CommandSequenceNumber", + (string)sqube["CommandSequenceNumber"]); + arch += PvlKeyword("Description", (string)sqube["Description"]); + isis3.AddGroup(arch); + + // Create the Kernel Group + PvlGroup kerns("Kernels"); + if(instId == "THEMIS_IR") + { + kerns += PvlKeyword("NaifFrameCode", -53031); + } + else + { + kerns += PvlKeyword("NaifFrameCode", -53032); + } + isis3.AddGroup(kerns); +} diff --git a/isis/src/odyssey/apps/thm2isis/thm2isis.xml b/isis/src/odyssey/apps/thm2isis/thm2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..b2faa7ffc9304bbd5335b4e4b8205c8913b1cf16 --- /dev/null +++ b/isis/src/odyssey/apps/thm2isis/thm2isis.xml @@ -0,0 +1,187 @@ + + + + + + Import a Themis IR/VIS RDR or EDR + + + + Converts a Themis VIS or IR PDS spectral cube into an Isis Cube. Themis IR + cube will automatically be converted to 32-bit floating point unless the + user specifies differently. This is done to accommodate different + core/base multiplier values for each band. Themis VIS cubes will automatically + create framelet files. These framelet files will have the name of the TO parameter with + a ".frame" followed by the frame number inserted prior to the ".cub" extension. For example, + if the TO parameter was out.cub, the first frame of the output would be named + out.frame1.cub. If you do not want framelet files, run the cube through pds2isis instead. + + + + + Original version + + + Converted to Isis 3.0 + + + Added AlphaCube keywords + + + Added visual image processing and framelet extraction option + + + Added Frames keyword to framelet labels for the ThemisVis Camera model + + + Modified AppTest to remove framelet files + + + Removed Framelets option, it always creates them now + + + Removed the ReleaseId keyword from the archive group + + + Modified VIS processing portion to no longer call crop and editlab, but + to split the frames apart in the application itself. This helps increase the + speed of the application + + + Fixed bugs with pathname and extensions of filenames in the VIS processing + + + Changed OriginalLabel name to IsisCube + + + Transfered SpatialSumming parameter for IR camera + + + Checks if input file is rdr. + + + Removed references to CubeInfo + + + The original labels are now being preserved in the Isis 3 cube + + + + + + Mars Odyssey + + + + + + filename + input + + Input PDS Themis EDR/RDR file + + + Must contain a valid Themis EDR or a Themis RDR which has only been through radiometric calibration. + + + *.imq *.img *.QUB + + + + + cube + output + + Output Isis cube + + + The name of the output Isis cube. If the input cube is a VIS image, the output file will have a + ".frame" and frame number inserted in the output name prior to the ".cub" extension. + + + *.cub + + + + + + + + double + 0.0 + + Time offset to the spacecraft clock count + + +The software assumes that the SCLK (spacecraft clock) recorded for an IR image is the time at which the first detector frame readout occurs. Apparently, the actual first readout can be delayed from this by the following amounts: +
    +8 microseconds - PACI write 
    +0 to 1/30 sec - delay of the image acquisition after receipt of the command 
    +0 to 0.1 sec - delay for the command sending by the HPP code so that it is aligned on a 0.1 second boundary 
    +
    +Currently, the software ignores these three because the 8 microseconds is a negligible fraction of the 1/30 second line rate and the other two are (apparently) variable and unknowable. However, this can result in an incorrect absolute position of as much as four pixels. + +Similar timing uncertainties probably are applicable to the VIS images. + +The effect of these timing uncertainties is primarily to potentially introduce errors in absolute coordinates in the along-track direction. This in turn can result in misalignment when mosaicking multiple observations together. + +The TIMEOFFSET parameter on "thm2isis" allows the user to apply a correction for this time delay, which can thus improve absolute coordinate accuracy and improve mosaic alignments. This offset is stored in the Instrument group of the output Isis cube as SpacecraftClockOffset. +
    +
    +
    +
    + + + + Importing a Themis Vis EDR + + This program imports both Themis VIS and Themis IR images. Themis VIS images are split into + even and odd files. + + + from=V04860003EDR.QUB to=V04860003EDR + This is how to run thm2isis on any themis EDR/RDR + + + + + The GUI when running this program + + This is what the interface looks like when you run this program. + + + + + + + + The input EDR V04860003EDR + + This is the input raw data + + + + + + + The output odd themis vis cube + + This is the outputted cube "V04860003EDR.odd.cub" + + + + + The output even themis vis cube + + This is the outputted cube "V04860003EDR.even.cub" + + + + + + +
    diff --git a/isis/src/odyssey/apps/thm2isis/tsts/Makefile b/isis/src/odyssey/apps/thm2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/odyssey/apps/thm2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/odyssey/apps/thm2isis/tsts/case01/Makefile b/isis/src/odyssey/apps/thm2isis/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e049fe3b6cc3a97a723cf55893e93bbc6832fa7b --- /dev/null +++ b/isis/src/odyssey/apps/thm2isis/tsts/case01/Makefile @@ -0,0 +1,7 @@ +APPNAME = thm2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/I00831002RDR.QUB \ + to=$(OUTPUT)/truth.cub > /dev/null; diff --git a/isis/src/odyssey/apps/thm2isis/tsts/case02/Makefile b/isis/src/odyssey/apps/thm2isis/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d8e8ddf0b4d202f8293d4eac1af276bea5dfcb83 --- /dev/null +++ b/isis/src/odyssey/apps/thm2isis/tsts/case02/Makefile @@ -0,0 +1,6 @@ +APPNAME = thm2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/V00821003RDR.QUB to=$(OUTPUT)/thm2isis-Truth3.cub+32bit > /dev/null; diff --git a/isis/src/odyssey/apps/thmdriftcor/Makefile b/isis/src/odyssey/apps/thmdriftcor/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/odyssey/apps/thmdriftcor/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/odyssey/apps/thmdriftcor/thmdriftcor.cpp b/isis/src/odyssey/apps/thmdriftcor/thmdriftcor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c7ea343f6cc73944647b7005d0e878b3540579d --- /dev/null +++ b/isis/src/odyssey/apps/thmdriftcor/thmdriftcor.cpp @@ -0,0 +1,61 @@ +#include "Isis.h" + +#include + +#include "ProcessByLine.h" +#include "UserInterface.h" +#include "QuickFilter.h" +#include "Statistics.h" + +using namespace std; +using namespace Isis; + +vector lineAverage; +void getStats(Buffer &in); +void driftcor(Buffer &in, Buffer &out); + +void IsisMain () { + + lineAverage.clear(); + ProcessByLine p; + p.SetInputCube("ATM",Isis::OneBand); + p.StartProcess(getStats); + p.EndProcess(); + + QuickFilter filt(lineAverage.size(),257,1); + filt.AddLine(&lineAverage[0]); + + for (int i=0; i<(int)lineAverage.size(); i++) { + lineAverage[i] = filt.Average(i); + } + + double base = lineAverage[lineAverage.size()-1]; + for (int i=0; i<(int)lineAverage.size(); i++) { + lineAverage[i] = lineAverage[i] - base; + lineAverage[i] = lineAverage[i] * 12854.7 / 11960.5; + } + + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + p.StartProcess(driftcor); + p.EndProcess(); + + return; +} + +void getStats(Buffer &in) { + Statistics stats; + stats.AddData(in.DoubleBuffer(),in.size()); + if( stats.Average() == Isis::Null ) { + lineAverage.push_back( 0.0 ); + } + else { + lineAverage.push_back(stats.Average()); + } +} + +void driftcor(Buffer &in, Buffer &out) { + for (int i=0; i + + + + + Apply thermal drift correction to THEMIS images + + + + This program applies a thermal drift correction to calibrated THEMIS RDR cubes. It requires as input the atmospheric band (band 10) and Band 9 which will be corrected for thermal drift. + + + + + Original version + + + Fixed a bug which occured when there were Null lines in the input cube. + + + + + Mars Odyssey + + + + + + cube + input + + Input THEMIS cube + + + This is the input THEMIS cube to be corrected. Note only band 9 + can be corrected for atmospheric drift. + + + *.cub + + + + + cube + input + + Input THEMIS cube atmospheric band + + + This is the input THEMIS cube with the atmospheric band (10) which + will be used to correct band 9 for thermal drift. + + + *.cub + + + + + cube + output + + Output Isis cube + + + A THEMIS image that has been corrected for thermal drift + + + *.cub + + + + + + diff --git a/isis/src/odyssey/apps/thmdriftcor/tsts/Makefile b/isis/src/odyssey/apps/thmdriftcor/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/odyssey/apps/thmdriftcor/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/odyssey/apps/thmdriftcor/tsts/case01/Makefile b/isis/src/odyssey/apps/thmdriftcor/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8fbfa373fb9702e6dfaced7b76898c2c4f346974 --- /dev/null +++ b/isis/src/odyssey/apps/thmdriftcor/tsts/case01/Makefile @@ -0,0 +1,8 @@ +APPNAME = thmdriftcor + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/I02446002RDR_b9.cub \ + atm=$(INPUT)/I02446002RDR_b10.cub \ + to=$(OUTPUT)/test_thmdriftcor.cub > /dev/null; diff --git a/isis/src/odyssey/apps/thmproc/Makefile b/isis/src/odyssey/apps/thmproc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/odyssey/apps/thmproc/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/odyssey/apps/thmproc/assets/images/gui.jpg b/isis/src/odyssey/apps/thmproc/assets/images/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d68fa39bfddf1f3177346548580b8046e97c74f5 Binary files /dev/null and b/isis/src/odyssey/apps/thmproc/assets/images/gui.jpg differ diff --git a/isis/src/odyssey/apps/thmproc/assets/images/out.jpg b/isis/src/odyssey/apps/thmproc/assets/images/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4f6c5d4af0a433ad46f988618ce1475fe6b25dcd Binary files /dev/null and b/isis/src/odyssey/apps/thmproc/assets/images/out.jpg differ diff --git a/isis/src/odyssey/apps/thmproc/assets/images/raw.jpg b/isis/src/odyssey/apps/thmproc/assets/images/raw.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dbf1748095afd4a0e56cfb6c60f27ccb55dbea0c Binary files /dev/null and b/isis/src/odyssey/apps/thmproc/assets/images/raw.jpg differ diff --git a/isis/src/odyssey/apps/thmproc/assets/thumbs/gui.jpg b/isis/src/odyssey/apps/thmproc/assets/thumbs/gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..06ea22fd84e2dbb587ae1d0c70759230fc9dccaa Binary files /dev/null and b/isis/src/odyssey/apps/thmproc/assets/thumbs/gui.jpg differ diff --git a/isis/src/odyssey/apps/thmproc/assets/thumbs/out.jpg b/isis/src/odyssey/apps/thmproc/assets/thumbs/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7cb810f0d7df5ca8dfe971f0b269a614dbccb313 Binary files /dev/null and b/isis/src/odyssey/apps/thmproc/assets/thumbs/out.jpg differ diff --git a/isis/src/odyssey/apps/thmproc/assets/thumbs/raw.jpg b/isis/src/odyssey/apps/thmproc/assets/thumbs/raw.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ff8513a78a2d79e6f735576a8af05142aa9bc505 Binary files /dev/null and b/isis/src/odyssey/apps/thmproc/assets/thumbs/raw.jpg differ diff --git a/isis/src/odyssey/apps/thmproc/thmproc.cpp b/isis/src/odyssey/apps/thmproc/thmproc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..09fa279a41ced4ca5c1753e63c97cc17607ddf10 --- /dev/null +++ b/isis/src/odyssey/apps/thmproc/thmproc.cpp @@ -0,0 +1,160 @@ +#include "Isis.h" +#include "Pipeline.h" + +using namespace Isis; + +void ProcessVis(bool isRdr); +void ProcessIr(); + +void IsisMain () { + UserInterface &ui = Application::GetUserInterface(); + + if (!ui.GetBoolean("INGESTION") && !ui.GetBoolean("MAPPING")) { + string msg = "You must pick one of [INGESTION,MAPPING]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + if(ui.GetBoolean("INGESTION")) { + Pvl labels(ui.GetFilename("FROM")); + + if((iString)labels["DETECTOR_ID"][0] == "VIS") { + if(((string)labels["DATA_SET_ID"]).find("RDR") != string::npos) { + ProcessVis(true); + } + else { + ProcessVis(false); + } + } + else { + ProcessIr(); + } + } + else { + ProcessIr(); + } +} + +void ProcessVis(bool isRdr) { + UserInterface &ui = Application::GetUserInterface(); + Pipeline p("thmproc"); + + p.SetInputFile("FROM", "BANDS"); + p.SetOutputFile("TO"); + p.KeepTemporaryFiles(!ui.GetBoolean("REMOVE")); + + p.AddToPipeline("thm2isis"); + p.Application("thm2isis").SetInputParameter("FROM", false); + p.Application("thm2isis").SetOutputParameter("TO", "raw"); + p.Application("thm2isis").AddBranch("even", PipelineApplication::ConstantStrings); + p.Application("thm2isis").AddBranch("odd", PipelineApplication::ConstantStrings); + + p.AddToPipeline("spiceinit"); + p.Application("spiceinit").SetInputParameter("FROM", false); + p.Application("spiceinit").AddParameter("PCK", "PCK"); + p.Application("spiceinit").AddParameter("CK", "CK"); + p.Application("spiceinit").AddParameter("SPK", "SPK"); + p.Application("spiceinit").AddParameter("SHAPE", "SHAPE"); + p.Application("spiceinit").AddParameter("MODEL", "MODEL"); + p.Application("spiceinit").AddParameter("CKNADIR", "CKNADIR"); + + p.AddToPipeline("thmvisflat"); + p.Application("thmvisflat").SetInputParameter("FROM", true); + p.Application("thmvisflat").SetOutputParameter("TO", "flat"); + + p.AddToPipeline("thmvistrim"); + p.Application("thmvistrim").SetInputParameter("FROM", true); + p.Application("thmvistrim").SetOutputParameter("TO", "cal"); + + if(!ui.GetBoolean("VISCLEANUP")) { + p.Application("thmvisflat").Disable(); + p.Application("thmvistrim").Disable(); + } + + if(isRdr) { + p.Application("thmvisflat").Disable(); + } + + p.AddToPipeline("cam2map"); + p.Application("cam2map").SetInputParameter("FROM", true); + p.Application("cam2map").SetOutputParameter("TO", "lev2"); + + p.Application("cam2map").AddParameter("even", "MAP", "MAP"); + p.Application("cam2map").AddParameter("even", "PIXRES", "RESOLUTION"); + + if(ui.WasEntered("PIXRES")) { + p.Application("cam2map").AddConstParameter("even", "PIXRES", "MPP"); + } + + p.Application("cam2map").AddParameter("odd", "MAP", PipelineApplication::LastOutput); + p.Application("cam2map").AddConstParameter("odd", "PIXRES", "MAP"); + p.Application("cam2map").AddConstParameter("odd", "DEFAULTRANGE", "MAP"); + + p.AddToPipeline("automos"); + p.Application("automos").SetInputParameter("FROMLIST", PipelineApplication::LastAppOutputList, false); + p.Application("automos").SetOutputParameter("MOSAIC", "mos"); + + if(ui.GetBoolean("INGESTION")) { + p.SetFirstApplication("thm2isis"); + } + else{ + p.SetFirstApplication("spiceinit"); + } + + if(ui.GetBoolean("MAPPING")) { + p.SetLastApplication("automos"); + } + else { + p.SetLastApplication("thmvistrim"); + } + + p.Run(); +} + +void ProcessIr() { + UserInterface &ui = Application::GetUserInterface(); + Pipeline p; + + p.SetInputFile("FROM", "BANDS"); + p.SetOutputFile("TO"); + + p.KeepTemporaryFiles(!ui.GetBoolean("REMOVE")); + + p.AddToPipeline("thm2isis"); + p.Application("thm2isis").SetInputParameter("FROM", false); + p.Application("thm2isis").SetOutputParameter("TO", "raw"); + + p.AddToPipeline("spiceinit"); + p.Application("spiceinit").SetInputParameter("FROM", false); + p.Application("spiceinit").AddParameter("PCK", "PCK"); + p.Application("spiceinit").AddParameter("CK", "CK"); + p.Application("spiceinit").AddParameter("SPK", "SPK"); + p.Application("spiceinit").AddParameter("SHAPE", "SHAPE"); + p.Application("spiceinit").AddParameter("MODEL", "MODEL"); + p.Application("spiceinit").AddParameter("CKNADIR", "CKNADIR"); + + p.AddToPipeline("cam2map"); + p.Application("cam2map").SetInputParameter("FROM", true); + p.Application("cam2map").SetOutputParameter("TO", "lev2"); + p.Application("cam2map").AddParameter("MAP", "MAP"); + p.Application("cam2map").AddParameter("PIXRES", "RESOLUTION"); + + if(ui.WasEntered("PIXRES")) { + p.Application("cam2map").AddConstParameter("PIXRES", "MPP"); + } + + if(ui.GetBoolean("INGESTION")) { + p.SetFirstApplication("thm2isis"); + } + else{ + p.SetFirstApplication("spiceinit"); + } + + if(ui.GetBoolean("MAPPING")) { + p.SetLastApplication("cam2map"); + } + else { + p.SetLastApplication("spiceinit"); + } + + p.Run(); +} diff --git a/isis/src/odyssey/apps/thmproc/thmproc.xml b/isis/src/odyssey/apps/thmproc/thmproc.xml new file mode 100644 index 0000000000000000000000000000000000000000..02175d4e750a28fc4b75ec9a3abf5daa9018b05a --- /dev/null +++ b/isis/src/odyssey/apps/thmproc/thmproc.xml @@ -0,0 +1,418 @@ + + + + Runs a Themis cube through the processing for levels 0 and/or 2 + + + +

    + Runs Mars Odyssey Themis images through the applications necessary to create a + map projected product. There are two stages of processing, ingestion and mapping + (radiometric calibration is assumed as Themis RDRs are available). Each stage can + be disabled and runs all the programs necessary to complete that stage if + not disabled. +

    +

    + All intermediate files will be generated in the users Isis temporary + directory and deleted after they are no longer needed. In case of a catastrophic + failure the intermediate files should be deleted. Their names will be the + name of the application appended to the original file name followed by a + 6 digit unique number. +

    +
    + + + + Original version + + + Changed mocproc into thmproc + + + Added Bands parameter and utilized IsisProcessExecutable class + + + Fixed bug in output file naming + + + Modified to output number of bands specified even when just doing ingestion + + + Modified UI and parameters to be consistent with changes made to spiceinit + + + Removed the AUTOLON parameter (no longer a parameter in cam2map) + + + Added support for the themisVis camera model + + + Documentation fixes + + + Fixed bug in PIXRES use caused by changes in cam2map + + + Added CKNADIR parameter for spiceinit. + + + Updated to use new themis vis functionality. Instead of the themis images + being split into a framelet per cube, they are now split into even and odd + cubes. + + + Updated to guarantee vis images have matching mapping groups, changed + tempory file naming conventions, enabled thmvistrim on rdr files. + + + Updated to fix problem with BANDS parameter. Before, the bands option + would sometimes cause an error incorrectly. Also fixed a case where the + input file would be deleted. + + + Updated to fix problem with BANDS parameter with IR images. This parameter had + a chance to not take effect. + + + Updated to use new pipeline class. + + + + + Mars Odyssey + + + + + + filename + input + + Input Themis PDS RDR or an ISIS Themis level 1 cube + + + Input filename. This file can be in one of two stages. A raw PDS Themis RDR or + an ISIS Level 0/1 cube. The level 0/1 cube is assumed to have been run + through thm2isis and spiceinit. + + + *.QUB *.imq *.img *.cub + + + + + cube + output + Automatic + + Final output filename. + + + Output filename from the last enabled processing sequence. By + default the filename will be generated from the input filename with + ".lev#" appended to the name, where "#" is the last level of + processing (i.e., INGESTION = "lev1" or MAPPING = "lev2"). + For ThemisVIS images, if processing is stopped at the ingestion + phase, there will be an output cube for each frame in the image, + with a ".frame#" appended to the end of the filename. + + + + + string + All + + Process a subset of bands + + + This parameter allows the user to specify a sub-set of + bands to process. Enter bands separated by commas (no spaces + allowed). For example, 1,3,8 or 1-3,9 or 5 + + + + + boolean + Remove Intermediate Files + + This option allows the user to decide whether the intermediate files + created in the thmproc application are to be deleted. The default value + is TRUE. + + TRUE + + + + + + boolean + + YES + + + Import and initialize a Themis EDR/RDR file. + + + Process the input file through all steps. This includes "thm2isis" and + "spiceinit" + + + PCK + CK + SPK + SHAPE + CKNADIR + + + + + boolean + + YES + + + Process the input file through the map projection phase. + + + Process the input file through level2. This includes cam2map. + + + MAP + PIXRES + + + + + + + filename + none + input + + User defined target attitude and shape kernel file. + + + Naif kernel file to be used for the target attitude and shape. + + + $BASE/kernels/pck/ + + + INGESTION + + + + + filename + none + input + + User defined spacecraft pointing kernel file. + + + Naif kernel file to be used for the spacecraft pointing. + + + $odyssey/kernels/ck/ + + + INGESTION + + + + + filename + none + input + + + User defined spacecraaft position kernel file. + + + Naif kernel file to be used for the spacecraft position. + + + $odyessy/kernels/spk/ + + + INGESTION + + + + + boolean + false + + Compute nadir pointing if no other kernels exist + + + Compute nadir pointing if no other kernels exist + + + + + string + SYSTEM + + INGESTION + + + Select the definition of the shape model + + + ISIS camera models can use a shape model (a projected ISIS cube that defines the radii for a global or regional area). You can choose + to select a shape model or to use the definition of the ellipsoid found in the planetary constants (PCK) file. + + + + + + + + + + cube + input + + User defined ISIS cube shape model. + + + A map projected ISIS cube which contains the radii of the target. The file can + cover more than the input cube (FROM) but must minimally cover the data in the input cube. + + $base//dems/ + *.cub + + + + + + filename + Sinusoidal + + File containing mapping parameters + + + A file containing the desired output mapping parameters in PVL form. This + file can be a simple hand produced label file. It can also be an existing cube + label which contains a Mapping group. + + *.map + + MAPPING + + + + + double + Pixel resolution in meters + Automatic + + Specifies the resolution in meters per pixel. + If not in the MAP file the resolution will be computed from + the themis level 1 cube. + + 0.0 + + MAPPING + + + + + + + boolean + Run thmvistrim and thmvisflat + + thmvistrim removes the overlap between framelets, which often contains both valid and + invalid data. Set this to false to preserve this data. thmvisflat applies a flat-field + correction to the data. + + true + + + + + + + + Running this program on a Themis VIS EDR + + + This program will process this themis edr from ingestion to mapping. + Since the file is a VIS file, the intermediate processes will split the + image into even and odd framelets which are recombined once mapped. + Since this file is an EDR, thmvistrim and thmvisflat will be run by + default to clean up the image. + + + from=V20018003EDR.QUB + + This runs this program with the defaults; the output is automatically + determined. + + + + + + + This is the default GUI + + + This is what the GUI looks like when running this program with + default parameters + + + + + + + + + Raw Input Data + + + This is the raw input data + + + + + + + + The projected image (final output) + + + This is the output from this program. It was cleaned up and + projected. + + + + + + +
    diff --git a/isis/src/odyssey/apps/thmproc/tsts/Makefile b/isis/src/odyssey/apps/thmproc/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/odyssey/apps/thmproc/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/odyssey/apps/thmproc/tsts/ir/Makefile b/isis/src/odyssey/apps/thmproc/tsts/ir/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6b38e5746b47cae5826809c3da8676741d0fe956 --- /dev/null +++ b/isis/src/odyssey/apps/thmproc/tsts/ir/Makefile @@ -0,0 +1,13 @@ +APPNAME = thmproc + +I02343002RDR.lev2.cub.TOLERANCE = 0.00000000001 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/I02343002RDR.QUB \ + TO=$(OUTPUT)/I02343002RDR.lev1.cub \ + MAPPING=no BANDS=2 > /dev/null; + $(APPNAME) FROM=$(INPUT)/I02343002RDR.cub \ + TO=$(OUTPUT)/I02343002RDR.lev2.cub \ + BANDS=1 PIXRES=951.5269 INGEST=NO > /dev/null; diff --git a/isis/src/odyssey/apps/thmproc/tsts/vis/Makefile b/isis/src/odyssey/apps/thmproc/tsts/vis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..986f7f622dce114c030f8262c2817789ad221c97 --- /dev/null +++ b/isis/src/odyssey/apps/thmproc/tsts/vis/Makefile @@ -0,0 +1,13 @@ +APPNAME = thmproc + +V05642009RDR.cub.TOLERANCE = 0.0000000002 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/V05642009EDR.QUB \ + TO=$(OUTPUT)/V05642009EDR \ + MAPPING=no BANDS=2 > /dev/null; + $(APPNAME) FROM=$(INPUT)/V05642009RDR.QUB \ + TO=$(OUTPUT)/V05642009RDR \ + MAPPING=yes BANDS=2 PIXRES=200 > /dev/null; diff --git a/isis/src/odyssey/apps/thmvisflat/Makefile b/isis/src/odyssey/apps/thmvisflat/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/odyssey/apps/thmvisflat/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/odyssey/apps/thmvisflat/assets/images/out.jpg b/isis/src/odyssey/apps/thmvisflat/assets/images/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7d0e6f03926ed066de31219323d5ca6b07d8e494 Binary files /dev/null and b/isis/src/odyssey/apps/thmvisflat/assets/images/out.jpg differ diff --git a/isis/src/odyssey/apps/thmvisflat/assets/images/raw.jpg b/isis/src/odyssey/apps/thmvisflat/assets/images/raw.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6dec8595fc10c83422be2a9080b7ec242beb3435 Binary files /dev/null and b/isis/src/odyssey/apps/thmvisflat/assets/images/raw.jpg differ diff --git a/isis/src/odyssey/apps/thmvisflat/assets/thumbs/out.jpg b/isis/src/odyssey/apps/thmvisflat/assets/thumbs/out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3697f904a9ec17849a17d33d851f3fc87f0b1260 Binary files /dev/null and b/isis/src/odyssey/apps/thmvisflat/assets/thumbs/out.jpg differ diff --git a/isis/src/odyssey/apps/thmvisflat/assets/thumbs/raw.jpg b/isis/src/odyssey/apps/thmvisflat/assets/thumbs/raw.jpg new file mode 100644 index 0000000000000000000000000000000000000000..458fec7e1bea2a4a4d5e01dba43a1f6435531ad9 Binary files /dev/null and b/isis/src/odyssey/apps/thmvisflat/assets/thumbs/raw.jpg differ diff --git a/isis/src/odyssey/apps/thmvisflat/thmvisflat.cpp b/isis/src/odyssey/apps/thmvisflat/thmvisflat.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b660c62e7f2fea323b7d090f028ccbaa111a806 --- /dev/null +++ b/isis/src/odyssey/apps/thmvisflat/thmvisflat.cpp @@ -0,0 +1,148 @@ +#include "Isis.h" +#include "SpecialPixel.h" +#include "CubeAttribute.h" +#include "Cube.h" +#include "LineManager.h" +#include "Progress.h" + +using namespace Isis; +using namespace std; + +void IsisMain () { + UserInterface &ui = Application::GetUserInterface(); + + CubeAttributeInput inAtt = ui.GetInputAttribute("FROM"); + Cube icube; + + if(inAtt.Bands().size() != 0) { + icube.SetVirtualBands(inAtt.Bands()); + } + + icube.Open(Filename(ui.GetFilename("FROM")).Expanded()); + + // Make sure it is a Themis EDR/RDR + Filename inFilename = ui.GetFilename("FROM"); + try { + if (icube.GetGroup("Instrument")["InstrumentID"][0] != "THEMIS_VIS") { + string msg = "This program is intended for use on THEMIS VIS images only. ["; + msg += inFilename.Expanded() + "] does not appear to be a THEMIS VIS image."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + catch (iException &e) { + string msg = "This program is intended for use on THEMIS VIS images only. ["; + msg += inFilename.Expanded() + "] does not appear to be a THEMIS VIS image."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + vector flatcubes; + vector fcubeMgrs; + int summing = icube.GetGroup("Instrument")["SpatialSumming"][0]; + + for(int filt = 0; filt < 5; filt++) { + string filePattern = "$odyssey/calibration/flat_filter_"; + filePattern += iString(filt+1) + "_summing_"; + filePattern += iString(summing) + "_v????.cub"; + Filename flatFile(filePattern); + flatFile.HighestVersion(); + Cube *fcube = new Cube(); + fcube->Open(flatFile.Expanded()); + flatcubes.push_back(fcube); + + LineManager *fcubeMgr = new LineManager(*fcube); + fcubeMgr->SetLine(1,1); + fcubeMgrs.push_back(fcubeMgr); + } + + Cube ocube; + + CubeAttributeOutput outAtt = ui.GetOutputAttribute("TO"); + ocube.SetDimensions(icube.Samples(), icube.Lines(), icube.Bands()); + ocube.SetByteOrder(outAtt.ByteOrder()); + ocube.SetCubeFormat(outAtt.FileFormat()); + if(outAtt.DetachedLabel()) ocube.SetDetached(); + if(outAtt.AttachedLabel()) ocube.SetAttached(); + ocube.SetPixelType(outAtt.PixelType()); + + ocube.Create(Filename(ui.GetFilename("TO")).Expanded()); + + LineManager icubeMgr(icube); + vector filter; + + PvlKeyword &filtNums = icube.Label()->FindGroup("BandBin", Pvl::Traverse)["FilterNumber"];; + for(int i = 0; i < filtNums.Size(); i++) { + filter.push_back(filtNums[i]); + } + + LineManager ocubeMgr(ocube); + ocubeMgr.SetLine(1,1); + + Progress prog; + prog.SetText("Applying Flat-Field Correction"); + prog.SetMaximumSteps(ocube.Lines() * ocube.Bands()); + prog.CheckStatus(); + + do { + icube.Read(icubeMgr); + ocube.Read(ocubeMgr); + + int fcubeIndex = filter[ocubeMgr.Band()-1] - 1; + flatcubes[fcubeIndex]->Read((*fcubeMgrs[fcubeIndex])); + + for(int i = 0; i < ocubeMgr.size(); i++) { + if(IsSpecial((*fcubeMgrs[fcubeIndex])[i]) || (*fcubeMgrs[fcubeIndex])[i] == 0.0) { + ocubeMgr[i] = Isis::Null; + } + else if(IsSpecial(icubeMgr[i])) { + ocubeMgr[i] = icubeMgr[i]; + } + else { + ocubeMgr[i] = icubeMgr[i] / (*fcubeMgrs[fcubeIndex])[i]; + } + } + + ocube.Write(ocubeMgr); + + icubeMgr++; + ocubeMgr++; + + for(int i = 0; i < (int)fcubeMgrs.size(); i++) { + (*fcubeMgrs[i]) ++; + + if(fcubeMgrs[i]->end()) { + fcubeMgrs[i]->SetLine(1,1); + } + } + + prog.CheckStatus(); + } + while(!ocubeMgr.end()); + + // Propagate labels and objects (in case of spice data) + PvlObject &inCubeObj = icube.Label()->FindObject("IsisCube"); + PvlObject &outCubeObj = ocube.Label()->FindObject("IsisCube"); + + for(int g = 0; g < inCubeObj.Groups(); g++) { + outCubeObj.AddGroup(inCubeObj.Group(g)); + } + + for(int o = 0; o < icube.Label()->Objects(); o++) { + if(icube.Label()->Object(o).IsNamed("Table")) { + Blob t(icube.Label()->Object(o)["Name"], icube.Label()->Object(o).Name()); + icube.Read(t); + ocube.Write(t); + } + } + + icube.Close(); + ocube.Close(); + + for(int i = 0; i < (int)flatcubes.size(); i++) { + delete fcubeMgrs[i]; + delete flatcubes[i]; + } + + fcubeMgrs.clear(); + flatcubes.clear(); +} + diff --git a/isis/src/odyssey/apps/thmvisflat/thmvisflat.xml b/isis/src/odyssey/apps/thmvisflat/thmvisflat.xml new file mode 100644 index 0000000000000000000000000000000000000000..6d475e282f87b7d4b373318fdb259e970c2e9e16 --- /dev/null +++ b/isis/src/odyssey/apps/thmvisflat/thmvisflat.xml @@ -0,0 +1,103 @@ + + + + + + This program applies a flat field correction to Themis VIS Images + + + + This program applies a flat-field correction for each framelet based on the + band's filter number + + + + + Original version + + + + + Mars Odyssey + + + + + + cube + input + + Input Themis VIS image + + + This is the non-flat-field corrected, unprojected themis cube + + + *.cub + + + + + cube + output + real + + Output Themis VIS Imagw + + + This is the flat-field corrected themis cube + + + *.cub + + + + + + + + + Running this program on a themis vis image + + + This program applies a flat-field correction to the input Themis Vis + image + + + + from=V04860003EDR.even.cub to=V04860003EDR.even.flat.cub + + + This applies a flat-field correction to the V04860003EDR.even.cub + themis vis cube + + + + + + Input Cube Data + + + This is the raw input data; notice the bottom of each framelet is + darker than the rest (fades to black). This is a consistent problem + with the camera. + + + + + + + + The corrected image + + + This is the output from this program; notice each framelet ends + sharply now. Other minor corrections exist, but the most noticable + correction is data from the darker area is brightened. + + + + + + + diff --git a/isis/src/odyssey/apps/thmvisflat/tsts/Makefile b/isis/src/odyssey/apps/thmvisflat/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/odyssey/apps/thmvisflat/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/odyssey/apps/thmvisflat/tsts/default/Makefile b/isis/src/odyssey/apps/thmvisflat/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9964704f8279f15aef330c37d8390685e74fdeeb --- /dev/null +++ b/isis/src/odyssey/apps/thmvisflat/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = thmvisflat + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/V20018003EDR.even.cub TO=$(OUTPUT)/V20018003EDR.cub > /dev/null; diff --git a/isis/src/odyssey/apps/thmvistrim/Makefile b/isis/src/odyssey/apps/thmvistrim/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/odyssey/apps/thmvistrim/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/odyssey/apps/thmvistrim/thmvistrim.cpp b/isis/src/odyssey/apps/thmvistrim/thmvistrim.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7608643a706cb3b1c36c6de6f296bf0add9a9089 --- /dev/null +++ b/isis/src/odyssey/apps/thmvistrim/thmvistrim.cpp @@ -0,0 +1,139 @@ +#include "Isis.h" + +#include + +#include "ThemisVisCamera.h" +#include "SpecialPixel.h" +#include "ProcessByLine.h" +#include "CameraFactory.h" +#include "PushFrameCameraGroundMap.h" + +using namespace Isis; +using namespace std; + +void TrimFramelets(Buffer &, Buffer &); +bool NeedsTrimmed(int); +int frameletSize; +int frameletTopTrimSize, frameletBottomTrimSize, + frameletLeftTrimSize, frameletRightTrimSize; + +void CalculateBottomTrim(Cube *icube); + +void IsisMain () { + // Grab the file to import + ProcessByLine p; + UserInterface &ui = Application::GetUserInterface(); + Cube *icube = p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + + // Make sure it is a Themis EDR/RDR + Filename inFilename = ui.GetFilename("FROM"); + try { + if (icube->GetGroup("Instrument")["InstrumentID"][0] != "THEMIS_VIS") { + string msg = "This program is intended for use on THEMIS VIS images only. ["; + msg += inFilename.Expanded() + "] does not appear to be a THEMIS VIS image."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + catch (iException &e) { + string msg = "This program is intended for use on THEMIS VIS images only. ["; + msg += inFilename.Expanded() + "] does not appear to be a THEMIS VIS image."; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + frameletSize = 192 / (int)icube->GetGroup("Instrument")["SpatialSumming"][0]; + frameletTopTrimSize = ui.GetInteger("TOPTRIM"); + frameletLeftTrimSize = ui.GetInteger("LEFTTRIM"); + frameletRightTrimSize = ui.GetInteger("RIGHTTRIM"); + + if(ui.WasEntered("BOTTOMTRIM")) { + frameletBottomTrimSize = ui.GetInteger("BOTTOMTRIM"); + } + else { + CalculateBottomTrim(icube); + } + + p.StartProcess(TrimFramelets); + p.EndProcess(); +} + +void TrimFramelets(Buffer &inBuffer, Buffer &outBuffer) { + if(NeedsTrimmed(inBuffer.Line())) { + for(int i = 0; i < outBuffer.size(); i++) { + outBuffer[i] = Isis::Null; + } + } + else { + for(int i = 0; i < outBuffer.size(); i++) { + if((i > frameletLeftTrimSize) && (i < outBuffer.size() - frameletRightTrimSize)) { + outBuffer[i] = inBuffer[i]; + } + else { + outBuffer[i] = Isis::Null; + } + } + } +} + +bool NeedsTrimmed(int line) { + int frameletLine = (line-1) % frameletSize + 1; + return (frameletLine <= frameletTopTrimSize) || (frameletLine > (frameletSize-frameletBottomTrimSize)); +} + +/** + * This method uses the cube's camera to determine how much + * overlap exists. The lat,lon for the beginning of the + * second framelet is calculated, and then we determine where + * that lat,lon occurs in the first framelet. That occurring line + * minus the framelet size is how much vertical overlap there is. + * The top overlap is subtracted from the overlap because there is + * that much less vertical overlap. + * + * @param icube The input themis vis cube + */ +void CalculateBottomTrim(Cube *icube) { + frameletBottomTrimSize = 0; + + if(icube->Camera() == NULL) { + string msg = "A camera is required to automatically "; + msg += "calculate the bottom trim of a cube. Please run spiceinit on the input cube"; + throw iException::Message(iException::Camera,msg,_FILEINFO_); + } + + // We really don't care at all about the original camera. What's needed is + // a known even-framelet camera and a known odd-framelet camera. In order + // to get these, we change the cube labels in a local copy and create an + // odd framelet and an even framelet camera. + Pvl cubeLabels = *icube->Label(); + PvlKeyword &framelets = cubeLabels.FindGroup("Instrument", Pvl::Traverse)["Framelets"]; + framelets = "Even"; + Camera *camEven = CameraFactory::Create(cubeLabels); + + framelets = "Odd"; + Camera *camOdd = CameraFactory::Create(cubeLabels); + + // Framelet 2 is even, so let's use the even camera to find the lat,lon at it's beginning + if(camEven->SetImage(1,frameletSize+1)) { + double framelet2StartLat = camEven->UniversalLatitude(); + double framelet2StartLon = camEven->UniversalLongitude(); + + // Let's figure out where this is in the nearest odd framelet (hopefully framelet 1) + if(camOdd->SetUniversalGround(framelet2StartLat, framelet2StartLon)) { + // The equivalent line to the start of framelet 2 is this found line + int equivalentLine = (int)(camOdd->Line() + 0.5); + + // Trim the vertical overlap... + frameletBottomTrimSize = frameletSize - equivalentLine; + + // Compensate for the top trim... + frameletBottomTrimSize -= frameletTopTrimSize; + + // This will happen if the top trim is bigger than the overlap, + // make sure the bottom trim is good + if(frameletBottomTrimSize < 0) frameletBottomTrimSize = 0; + } + } + + delete camEven; + delete camOdd; +} diff --git a/isis/src/odyssey/apps/thmvistrim/thmvistrim.xml b/isis/src/odyssey/apps/thmvistrim/thmvistrim.xml new file mode 100644 index 0000000000000000000000000000000000000000..b227e2195acdbb1d65040fdd5f0f096c226b1636 --- /dev/null +++ b/isis/src/odyssey/apps/thmvistrim/thmvistrim.xml @@ -0,0 +1,92 @@ + + + + + + Trims data from framelets on Themis Vis images + + + + This program nulls out data on a per-framelet basis. By default, only the + bottom is trimmed and just enough so that data won't be repeated in + projected space. This program removes the data from the bottom of the + framelets because the themis camera produces the worst data at that point. + + + + + Original version + + + + + Mars Odyssey + + + + + + cube + input + + + + + + *.cub + + + + + cube + output + + + + + + *.cub + + + + + + + integer + + + + + 0 + 0 + + + integer + + + + + 0 + Automatically Determine + + + integer + + + + + 0 + 0 + + + integer + + + + + 0 + 0 + + + + diff --git a/isis/src/odyssey/apps/thmvistrim/tsts/Makefile b/isis/src/odyssey/apps/thmvistrim/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/odyssey/apps/thmvistrim/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/odyssey/apps/thmvistrim/tsts/default/Makefile b/isis/src/odyssey/apps/thmvistrim/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..824a9821b26143b09f28820cdd14d3edc56543bf --- /dev/null +++ b/isis/src/odyssey/apps/thmvistrim/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = thmvistrim + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) FROM=$(INPUT)/V20018003EDR.even.cub TO=$(OUTPUT)/V20018003EDR.cub > /dev/null; diff --git a/isis/src/odyssey/objs/Makefile b/isis/src/odyssey/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/odyssey/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/odyssey/objs/ThemisIrCamera/Camera.plugin b/isis/src/odyssey/objs/ThemisIrCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..085a8639678f00d037c1622df18fde50af903534 --- /dev/null +++ b/isis/src/odyssey/objs/ThemisIrCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = Mars_Odyssey/Themis_Ir + Version = 2 + Library = ThemisIrCamera + Routine = ThemisIrCameraPlugin +EndGroup + diff --git a/isis/src/odyssey/objs/ThemisIrCamera/Makefile b/isis/src/odyssey/objs/ThemisIrCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..41f1e7f13ee1e0a60d3efac0578a920ddf81bde7 --- /dev/null +++ b/isis/src/odyssey/objs/ThemisIrCamera/Makefile @@ -0,0 +1,5 @@ +INCS = ThemisIrCamera.h ThemisIrDistortionMap.h +SRCS = ThemisIrCamera.cpp ThemisIrDistortionMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrCamera.cpp b/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd0c5032e778f6f2e4d8103ae92a2d1a4eb52f90 --- /dev/null +++ b/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrCamera.cpp @@ -0,0 +1,171 @@ +using namespace std; + +#include "ThemisIrCamera.h" +#include "LineScanCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "ThemisIrDistortionMap.h" +#include "LineScanCameraGroundMap.h" +#include "LineScanCameraSkyMap.h" + +namespace Isis { + namespace Odyssey { + ThemisIrCamera::ThemisIrCamera (Isis::Pvl &lab) : Isis::LineScanCamera(lab) { + // Set the detector size + SetPixelPitch(0.05); + SetFocalLength(203.9213); + + // Get the start time. This includes adding a time offset that could + // have been put in the labels during ingestion (thm2isis). This is meant + // to handle a random timing errors which can be up to four pixels + Isis::PvlGroup &inst = lab.FindGroup ("Instrument",Isis::Pvl::Traverse); + string stime = inst["SpacecraftClockCount"]; + scs2e_c (NaifSclkCode(),stime.c_str(),&p_etStart); + double offset = inst["SpacecraftClockOffset"]; + p_etStart += offset; + + // If bands have been extracted from the original image then we + // need to read the band bin group so we can map from the cube band + // number to the instrument band number + Isis::PvlGroup &bandBin = lab.FindGroup("BandBin",Isis::Pvl::Traverse); + Isis::PvlKeyword &orgBand = bandBin["FilterNumber"]; + for (int i=0; iSetDetectorSampleSumming(sumMode); + detectorMap->SetDetectorLineSumming(sumMode); + + // The focal plane map tells us how to go from detector position + // to focal plane x/y (distorted). That is, (sample,time) to (x,y). + // This is band dependent so it will change in SetBand + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + + // The boresight sample in the K-T model was 164.25. In Duxbury's it is + // 160.5 or half the detector width. The detector offset varies by band + // and is set to the proper value for band 1 for now + focalMap->SetDetectorOrigin(160.5,0.0); + focalMap->SetDetectorOffset(0.0,120.5-8.5); + + // The camera has a distortion map which scales in the X direction, + // effectively a variable focal length, and an independent Y direction. + // Both are based on the band number + new ThemisIrDistortionMap(this); + + // Setup the ground and sky map + new LineScanCameraGroundMap(this); + new LineScanCameraSkyMap(this); + + LoadCache(); + } + + /** + * Change the THEMIS IR camera parameters based on the band + * number + * + * @author janderson (2/26/2009) + * + * @param vband + */ + void ThemisIrCamera::SetBand (const int vband) { + // Lookup the original band from the band bin group. Unless there is + // a reference band which means the data has all been aligned in the + // band dimension + int band; + if (HasReferenceBand()) { + band = ReferenceBand(); + if ((band < 1) || (band > 10)) { + string msg = "Invalid Reference Band [" + iString(band) + "]"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + else { + if (vband > (int) p_originalBand.size()) { + string msg = "Band number out of array bounds in ThemisIRCamera"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + band = p_originalBand[vband-1]; + } + + // Get the detector line in the CCD. If TDI mode is enabled then + // we used the middle of the 16 lines which were summed. Otherwise + // an individual line was read out. It is not clear where/how the + // noTDI offsets were derived. Hopefully from some THEMIS document. + // They were copied from ISIS2 code and the only suspicious value is + // at 52. Also, Duxbury's 1/22/09 email used 128.5 vs 129.5 for the + // center of the TDI enable detector line positions. + double detectorLine; + if (p_tdiMode == "ENABLED") { + double bandDetector_TDI[] = {8.5,24.5,50.5,76.5,102.5, + 128.5,154.5,180.5,205.5,231.5}; + detectorLine = bandDetector_TDI[band-1]; + } + else { + int bandDetector_noTDI[] = {9,24,52,77,102,129,155,181,206,232}; + detectorLine = (double) bandDetector_noTDI[band-1]; + } + + // Compute the time offset for this band (using detector line) + // Subtracting 1.0 as in Duxbury's example would be the offset to + // the center of the pixel but we want to the top edge so we + // subtract 0.5 + p_bandTimeOffset = (detectorLine - 0.5) * p_lineRate; + p_bandTimeOffset /= this->DetectorMap()->LineScaleFactor(); + + // Adjust the starting time in the detector map for this band + LineScanCameraDetectorMap *detectorMap = + (LineScanCameraDetectorMap *) this->DetectorMap(); + detectorMap->SetStartTime(p_etStart + p_bandTimeOffset); + + // Compute the along track offset at this detector line. That is, + // the number of pixels away from the boresight line. In the K-T model + // the boresight line was 109.5. In Duxbury's it is half of the + // detector height or 120.5 + double alongtrackOffset = 120.5 - detectorLine; + + // Adjust alongtrackOffset using Kirk's empirically fitted numbers from + // Apr 2009 + double empiricalOffset[] = { -0.076, -0.098, -0.089, -0.022, 0.0, + -0.020, -0.005, -0.069, 0.025, 0.0 }; + alongtrackOffset += empiricalOffset[band-1]; + this->FocalPlaneMap()->SetDetectorOffset(0.0,alongtrackOffset); + + // Adjust the sample boresight using Kirk's empirically fitted numbers + // from Apr 2009 + double sampleBoresight = 160.5; + double empiricalBoresightOffset[] = { 0.021, 0.027, 0.005, 0.005, 0.0, + -0.007, -0.012, -0.039, -0.045, 0.0 }; + sampleBoresight -= empiricalBoresightOffset[band-1]; + this->FocalPlaneMap()->SetDetectorOrigin(sampleBoresight,0.0); + + // Finally, adjust the optical distortion model based on the band + ThemisIrDistortionMap *distMap = + (ThemisIrDistortionMap *) DistortionMap(); + distMap->SetBand(band); + } + } +} + +// Plugin +extern "C" Isis::Camera *ThemisIrCameraPlugin (Isis::Pvl &lab) { + return new Isis::Odyssey::ThemisIrCamera(lab); +} diff --git a/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrCamera.h b/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..1adf5b4924d072f8eb23c59b4468d62b75e3d322 --- /dev/null +++ b/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrCamera.h @@ -0,0 +1,52 @@ +#ifndef ThemisIrCamera_h +#define ThemisIrCamera_h + +#include "LineScanCamera.h" + +namespace Isis { + namespace Odyssey { + class ThemisIrDistortionMap; + + /** + * @brief THEMIS IR Camera + * + * This is the camera class for the THEMIS IR camera + * + * @ingroup MarsOdyssey + * + * @author 2005-01-01 Jeff Anderson + * + * @internal + * @history 2007-07-13 Jeff Anderson Added support for spatial summing + * @history 2008-08-08 Steven Lambright Now using the new LoadCache(...) + * method instead of CreateCache(...). + * @history 2009-05-12 Jeff Anderson Reworked code for changes from + * Kiefer-Torson model to Duxbury model. The majors changes + * where the removal of a ~1% error in focal lenght and the + * improving the spectral band registration to better than + * 1/20th of a pixel + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class ThemisIrCamera : public Isis::LineScanCamera { + public: + // constructors + ThemisIrCamera (Isis::Pvl &lab); + + // destructor + ~ThemisIrCamera () {}; + + // Band dependent + void SetBand (const int band); + bool IsBandIndependent () { return false; }; + + private: + double p_etStart; + double p_lineRate; + double p_bandTimeOffset; + std::string p_tdiMode; + std::vector p_originalBand; + }; + }; +}; +#endif diff --git a/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrCamera.truth b/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..45b7ad056d6c215ef38840d1472d3b41c55cc0c4 --- /dev/null +++ b/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrCamera.truth @@ -0,0 +1,20 @@ +Unit Test for ThemisIrCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrDistortionMap.cpp b/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrDistortionMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3bd8d317d9fe906fa5f26eb2e0b391e56b8d2d5 --- /dev/null +++ b/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrDistortionMap.cpp @@ -0,0 +1,58 @@ +using namespace std; + +#include +#include "ThemisIrDistortionMap.h" + +namespace Isis { + namespace Odyssey { + ThemisIrDistortionMap::ThemisIrDistortionMap (Camera *parent) : + CameraDistortionMap (parent,1.0) { + SetBand(1); + p_alpha1 = 0.00447623; // Currently not used + p_alpha2 = 0.00107556; // Disabled Y portion of optical distortion + } + + void ThemisIrDistortionMap::SetBand (const int band) { + if (band < 1 || band > 10) { + string msg = "Band number out of array bounds in ThemisIRDistortionMap"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + double k[] = { 0.996005, 0.995358, 0.994260, 0.993290, 0.992389, + 0.991474, 0.990505, 0.989611, 0.988653, 0.9877 }; + + p_k = k[band-1]; + } + + + bool ThemisIrDistortionMap::SetFocalPlane(const double dx, + const double dy) { + p_focalPlaneX = dx; + p_focalPlaneY = dy; + + p_undistortedFocalPlaneX = p_focalPlaneX / p_k; + + double radical = (1.0 + p_alpha1) * (1.0 + p_alpha1) + 4.0 * p_alpha2 * dy; + if (radical < 0.0) return false; + radical = sqrt(radical); + double denom = 1.0 + p_alpha1 + radical; + if (denom == 0.0) return false; + p_undistortedFocalPlaneY = 2.0 * dy / denom; + + return true; + } + + bool ThemisIrDistortionMap::SetUndistortedFocalPlane(const double ux, + const double uy) { + p_undistortedFocalPlaneX = ux; + p_undistortedFocalPlaneY = uy; + + p_focalPlaneX = p_undistortedFocalPlaneX * p_k; + + p_focalPlaneY = p_undistortedFocalPlaneY + + p_alpha1*p_undistortedFocalPlaneY + + p_alpha2*p_undistortedFocalPlaneY * p_undistortedFocalPlaneY; + + return true; + } + } +} diff --git a/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrDistortionMap.h b/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrDistortionMap.h new file mode 100644 index 0000000000000000000000000000000000000000..796285051e756323779e9b0012bc6cd49fb20682 --- /dev/null +++ b/isis/src/odyssey/objs/ThemisIrCamera/ThemisIrDistortionMap.h @@ -0,0 +1,44 @@ +#ifndef ThemisIrDistortionMap_h +#define ThemisIrDistortionMap_h + +#include "CameraDistortionMap.h" + +namespace Isis { + namespace Odyssey { + /** Distort/undistort focal plane coordinates + * + * Creates a map for adding/removing optical distortions + * from the focal plane of the Themis IR camera. + * + * @ingroup Camera + * + * @see Camera + * + * @internal + * + * @history 2005-02-01 Jeff Anderson + * Original version + * + * @history 2009-03-27 Jeff Anderson + * Modified to use Duxbury's distortion model from Feb 2009 + * email with attached PDF document + * + */ + class ThemisIrDistortionMap : public CameraDistortionMap { + public: + ThemisIrDistortionMap(Camera *parent); + + virtual bool SetFocalPlane(const double dx, const double dy); + + virtual bool SetUndistortedFocalPlane(const double ux, const double uy); + + void SetBand (int band); + + private: + double p_k; + double p_alpha1; + double p_alpha2; + }; + }; +}; +#endif diff --git a/isis/src/odyssey/objs/ThemisIrCamera/unitTest.cpp b/isis/src/odyssey/objs/ThemisIrCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..200e5f08b46f4eea3e5c875b1735017c3af27c07 --- /dev/null +++ b/isis/src/odyssey/objs/ThemisIrCamera/unitTest.cpp @@ -0,0 +1,93 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + /** + * ThemisIrCamera unit test modified to have increased known lat/lon + * tolerances + */ + cout << "Unit Test for ThemisIrCamera..." << endl; + try { + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + double knownLat = -21.40308964655525; + double knownLon = 176.4512636738105; + + Isis::Pvl p("$odyssey/testData/I00831002RDR.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-8) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 1E-9) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.001) deltaSamp = 0; + if (fabs(deltaLine) < 0.001) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/odyssey/objs/ThemisVisCamera/Camera.plugin b/isis/src/odyssey/objs/ThemisVisCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..f178a6b4c168af309754c5cf955a4fd9658c0088 --- /dev/null +++ b/isis/src/odyssey/objs/ThemisVisCamera/Camera.plugin @@ -0,0 +1,6 @@ +Group = Mars_Odyssey/Themis_Vis + Version = 1 + Library = ThemisVisCamera + Routine = ThemisVisCameraPlugin +EndGroup + diff --git a/isis/src/odyssey/objs/ThemisVisCamera/Makefile b/isis/src/odyssey/objs/ThemisVisCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..34129b8532be4efc93ecf4c50a5000e50312d2d8 --- /dev/null +++ b/isis/src/odyssey/objs/ThemisVisCamera/Makefile @@ -0,0 +1,5 @@ +INCS = ThemisVisCamera.h ThemisVisDistortionMap.h +SRCS = ThemisVisCamera.cpp ThemisVisDistortionMap.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/odyssey/objs/ThemisVisCamera/ThemisVisCamera.cpp b/isis/src/odyssey/objs/ThemisVisCamera/ThemisVisCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d773fb35bbc9f357e95575c2bd36807ee508d57b --- /dev/null +++ b/isis/src/odyssey/objs/ThemisVisCamera/ThemisVisCamera.cpp @@ -0,0 +1,120 @@ +using namespace std; +#include +#include "ThemisVisCamera.h" +#include "PushFrameCameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "ThemisVisDistortionMap.h" +#include "PushFrameCameraGroundMap.h" +#include "CameraSkyMap.h" + +namespace Isis { + namespace Odyssey { + + /** + * Constructor for the Themis Vis Camera Model + * + * @param lab Pvl Label to create the camera model from + * + * @throws Isis::iException::User - The image does not appear to be a Themis + * VIS image + */ + ThemisVisCamera::ThemisVisCamera (Isis::Pvl &lab) : Isis::PushFrameCamera(lab) { + // Set up the camera characteristics + // LoadFrameMounting("M01_SPACECRAFT","M01_THEMIS_VIS"); + SetFocalLength(203.9); + SetPixelPitch(0.009); + + Isis::PvlGroup &inst = lab.FindGroup ("Instrument",Isis::Pvl::Traverse); + // make sure it is a themis vis image + if (inst["InstrumentId"][0] != "THEMIS_VIS") { + string msg = "The image does not appear to be a Themis Vis Image"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + // Get necessary variables + p_exposureDur = inst["ExposureDuration"]; + p_interframeDelay = inst["InterframeDelay"]; + int sumMode = inst["SpatialSumming"]; + + // Get the start and end time + double et; + string stime = inst["SpacecraftClockCount"]; + scs2e_c (NaifSclkCode(),stime.c_str(),&et); + double offset = inst["SpacecraftClockOffset"]; + p_etStart = et + offset - ((p_exposureDur / 1000.0) / 2.0); + p_nframes = inst["NumFramelets"]; + + // Get the keywords from labels + Isis::PvlGroup &bandBin = lab.FindGroup("BandBin",Isis::Pvl::Traverse); + Isis::PvlKeyword &orgBand = bandBin["OriginalBand"]; + for (int i=0; iSetDetectorSampleSumming(sumMode); + dmap->SetDetectorLineSumming(sumMode); + + // Setup focal plane map + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + focalMap->SetDetectorOrigin(512.5,512.5); + + // Setup distortion map + new ThemisVisDistortionMap(this); + + // Setup the ground and sky map + bool evenFramelets = (inst["Framelets"][0] == "Even"); + new PushFrameCameraGroundMap(this, evenFramelets); + new CameraSkyMap(this); + + LoadCache(); + } + + /** + * Sets the band in the camera model + * + * @param vband The band number to set + */ + void ThemisVisCamera::SetBand (const int vband) { + Camera::SetBand(vband); + + // Set the et + SetEphemerisTime(p_etStart + BandEphemerisTimeOffset(vband)); + PushFrameCameraDetectorMap *dmap = (PushFrameCameraDetectorMap *)this->DetectorMap(); + dmap->SetStartTime(p_etStart + BandEphemerisTimeOffset(vband)); + } + + double ThemisVisCamera::BandEphemerisTimeOffset(int vband) { + int waveToTimeBand[] = {2,5,3,4,1}; + int visBandFirstRow[] = {4,203,404,612,814}; + + // Lookup the original band from the band bin group. Unless there is + // a reference band which means the data has all been aligned in the + // band dimension + int band = p_originalBand[vband-1]; + if (HasReferenceBand()) { + band = ReferenceBand(); + } + + // convert wavelength band the time band + band = waveToTimeBand[band-1]; + + // Compute the time offset for this detector line + p_bandTimeOffset = ((band-1) * p_interframeDelay) - + ((p_exposureDur / 1000.0) / 2.0); + + PushFrameCameraDetectorMap *dmap = (PushFrameCameraDetectorMap *)this->DetectorMap(); + dmap->SetBandFirstDetectorLine(visBandFirstRow[band-1]); + + return p_bandTimeOffset; + } + } +} + +// Plugin +extern "C" Isis::Camera *ThemisVisCameraPlugin (Isis::Pvl &lab) { + return new Isis::Odyssey::ThemisVisCamera(lab); +} diff --git a/isis/src/odyssey/objs/ThemisVisCamera/ThemisVisCamera.h b/isis/src/odyssey/objs/ThemisVisCamera/ThemisVisCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..452146a82ce453198dd8e04e818db102be0c62c6 --- /dev/null +++ b/isis/src/odyssey/objs/ThemisVisCamera/ThemisVisCamera.h @@ -0,0 +1,62 @@ +#ifndef ThemisVisCamera_h +#define ThemisVisCamera_h + +#include "PushFrameCamera.h" + +namespace Isis { + namespace Odyssey { + /** + * @brief Themis VIS Camera Model + * + * This is the camera model for the Themis Vis Framing camera + * + * @ingroup SpiceInstrumentsAndCameras + * @ingroup MarsOdyssey + * + * @author 2006-01-06 Elizabeth Ribelin + * + * @internal + * @history 2006-05-17 Elizabeth Miller - Depricated CameraManager to + * CameraFactory in unitTest + * + * @history 2006-09-12 Elizabeth Miller - Fixed bug in detector map + * caused by the deletion of the + * alphacube group in the labels + * @history 2008-06-16 Steven Lambright - Made camera work with + * new push frame + * classes + * @history 2009-08-28 Steven Lambright - Changed inheritance to no longer + * inherit directly from Camera + */ + class ThemisVisCamera : public Isis::PushFrameCamera { + public: + // constructor + ThemisVisCamera (Isis::Pvl &lab); + + //! Destroys the Themis Vis Camera object + ~ThemisVisCamera () {}; + + // Sets the band to the band number given + void SetBand (const int band); + + double BandEphemerisTimeOffset(int vband); + + /** + * The camera model is band dependent, so this method returns false + * + * @return bool False + */ + bool IsBandIndependent () { return false; }; + + private: + double p_etStart; //! p_originalBand; //! +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +using namespace std; + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for ThemisVisCamera..." << endl; + /** + * unit test changed for themis vis camera + */ + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + // double knownLat = 48.53342079272975; + // double knownLon = 332.0434164961534; + double knownLat = 48.53342078845403; + double knownLon = 332.0434164973285; + + Isis::Pvl p("$odyssey/testData/V14093008RDR.even.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 193.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 193.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + if(abs(cam->UniversalLatitude() - knownLat) < 1E-10) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + if(abs(cam->UniversalLongitude() - knownLon) < 2E-10) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 1.01) deltaSamp = 0; + if (fabs(deltaLine) < 0.005) deltaLine = 0; + + if(fabs(fabs(deltaSamp) - 5.04) < .001) deltaSamp = 0; + if(fabs(fabs(deltaSamp) - 3.919) < .001) deltaSamp = 0; + if(fabs(fabs(deltaLine) - 19.1) < .01) deltaLine = 0; + + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/qisis/Makefile b/isis/src/qisis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/qisis/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/qisis/apps/Makefile b/isis/src/qisis/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/qisis/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/qisis/apps/qnet/Makefile b/isis/src/qisis/apps/qnet/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..888e3452d23bbc8f5b0692c688107f4efa544ee0 --- /dev/null +++ b/isis/src/qisis/apps/qnet/Makefile @@ -0,0 +1,15 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +BINS := $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps + +QnetDeletePointDialog.o: QnetDeletePointDialog.h QnetDeletePointDialog.ui + $(UIC) -o ui_QnetDeletePointDialog.h QnetDeletePointDialog.ui + $(CXX) $(ALLINCDIRS) $(ISISCPPFLAGS) $(CPPFLAGS) -c -o $@ QnetDeletePointDialog.cpp diff --git a/isis/src/qisis/apps/qnet/QnetCubeDistanceFilter.cpp b/isis/src/qisis/apps/qnet/QnetCubeDistanceFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c305f7ce312130d25f9cd24459eb3885cce7d84a --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetCubeDistanceFilter.cpp @@ -0,0 +1,231 @@ +#include +#include +#include +#include +#include "QnetCubeDistanceFilter.h" +#include "QnetNavTool.h" +#include "ControlNet.h" +#include "SerialNumberList.h" +#include "qnet.h" + +using namespace Qisis::Qnet; + +namespace Qisis { + /** + * Contructor for the Cube Distance filter. It + * creates the Distance filter window found in + * the navtool + * + * @param parent The parent widget for the cube + * distance filter + * @internal + * @history 2008-12-03 Jeannie Walldren - Added radio button + * so user may choose to filter + * distance in pixels or meters. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null. + * + */ + QnetCubeDistanceFilter::QnetCubeDistanceFilter (QWidget *parent) : QnetFilter(parent) { + p_lineEdit = NULL; + p_pixels = NULL; + p_meters = NULL; + + // Create components for the filter window + QLabel *label = new QLabel("Filter by distance between points in cube"); + QLabel *lessThan = new QLabel("Contains points within "); + p_lineEdit = new QLineEdit(); + p_pixels = new QRadioButton("pixels"); + p_meters = new QRadioButton("meters"); + p_pixels->setChecked(true); + QLabel *pad = new QLabel(); + + // create layout for radio buttons + QVBoxLayout *units = new QVBoxLayout(); + units->addWidget(p_pixels); + units->addWidget(p_meters); + + // Create the layout and add the components to it + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->addWidget(label,0,0,1,2); + gridLayout->addWidget(lessThan,1,0); + gridLayout->addWidget(p_lineEdit,1,1); + gridLayout->addLayout(units,1,2); + gridLayout->addWidget(pad,2,0); + gridLayout->setRowStretch(2,50); + this->setLayout(gridLayout); + } + + /** + * Filters a list of images for images that have points that are less than + * the user entered distance from other points in the image. The filtered + * list will appear in the navtools images list display. + * @internal + * @history 2008-12-03 Jeannie Walldren - Reorganized method + * so it is working properly, to + * increase efficiency (by breaking out + * of loops when possible) and to allow + * filtering for a distance in meters + * or pixels. Renamed variables for + * clarity. + * @history 2009-01-08 Jeannie Walldren - Modified to replace + * existing filtered list with a subset + * of that list. Previously, a new + * filtered list was created from the + * entire serial number list each time. + */ + void QnetCubeDistanceFilter::filter() { + // Make sure we have a list of files to filter + if ( g_serialNumberList == NULL ) { + QMessageBox::information((QWidget *)parent(), + "Error","No cubes to filter"); + return; + } + + // Make sure the user entered a filtering value + if ( p_lineEdit->text() == "" ) { + QMessageBox::information((QWidget *)parent(), + "Error","Distance value must be entered"); + return; + } + + // Get the user entered value for filtering + int userEntered = p_lineEdit->text().toInt(); + + // create temporary QList to contain new filtered images + QList temp; + // Loop through each image in the currently filtered list + // Loop in reverse order for consistency with other filters + for (int i = g_filteredImages.size()-1; i >= 0; i--) { + + // Loop through every control point in the control net + for (int cp1 = 0; cp1 < g_controlNetwork->Size(); cp1++) { + Isis::ControlPoint controlPt1 = (*g_controlNetwork)[cp1]; + Isis::ControlMeasure controlMeas1; + // Loop through each control measure of this point until we find this image + for (int cm1 = 0; cm1 < controlPt1.Size(); cm1++) { + // Check control measure to see if this point is in the current image + if ( controlPt1[cm1].CubeSerialNumber() == g_serialNumberList->SerialNumber(g_filteredImages[i]) ) { + // this measure matches the image, set controlMeas1 variable and break out of loop + controlMeas1 = controlPt1[cm1]; + break; + } + // this measure does not match this cube, keep looking, continue to next measure + else continue; + } // if no matching measure was found, controlMeas1 defaults to sample,line = 0 + + // If the measure for this image has no line/sample values, + // we can not measure distance, so continue to the next control point, cp1 + if(controlMeas1.Sample() == 0 && controlMeas1.Line() == 0) continue; + // if the user chooses distance in meters, create camera to find lat/lon for this measure + double rad=0, lat1=0, lon1=0; + if (p_meters->isChecked()) { + Isis::Camera *cam1; + cam1 = g_controlNetwork->Camera(g_filteredImages[i]); + // try to set image using sample/line values + if (cam1->SetImage(controlMeas1.Sample(),controlMeas1.Line())) { + rad = cam1->LocalRadius(); + lat1 = cam1->UniversalLatitude(); + lon1 = cam1->UniversalLongitude(); + } + else { + // if SetImage fails for this measure, don't calculate the distance from this point + // continue to next control point, cp1 + continue; + } + } + // Loop through the remaining control points to compute distances + for (int cp2 = (cp1 + 1); cp2 < g_controlNetwork->Size(); cp2++) { + Isis::ControlPoint controlPt2 = (*g_controlNetwork)[cp2]; + Isis::ControlMeasure controlMeas2; + // Loop through each measure of the second point until we find this image + for (int cm2 = 0; cm2 < controlPt2.Size(); cm2++) { + // Check to see if this point is in the image + if ( controlPt2[cm2].CubeSerialNumber() == g_serialNumberList->SerialNumber(g_filteredImages[i]) ) { + // this measure matches the image, set controlMeas2 variable and break out of loop + controlMeas2 = controlPt2[cm2]; + break; + } + // this measure does not match this cube, keep looking, continue to next measure + else continue; + } // if no matching measure was found, controlMeas1 defaults to sample,line = 0 + + // If the measure has no samp/line values, continue to next point, cp2 + if(controlMeas2.Sample() == 0 && controlMeas2.Line() == 0) continue; + + // Now determine distance based on the units chosen + double dist = 0; + if (p_pixels->isChecked()) { + double deltaSamp = controlMeas1.Sample() - controlMeas2.Sample(); + double deltaLine = controlMeas1.Line() - controlMeas2.Line(); + // use the distance formula for cartesian coordinates + dist = sqrt((deltaSamp * deltaSamp) + (deltaLine * deltaLine)); + } + else { // meters is checked + // create camera to find lat/lon for this measure + double lat2=0, lon2=0; + Isis::Camera *cam2; + cam2 = g_controlNetwork->Camera(g_filteredImages[i]); + // try to set image using sample/line values + if (cam2->SetImage(controlMeas2.Sample(),controlMeas2.Line())) { + lat2 = cam2->UniversalLatitude(); + lon2 = cam2->UniversalLongitude(); + } + else { + // if SetImage fails, don't calculate the distance to this point + // continue to the next control point, cp2 + continue; + } + // Calculate the distance between the two points + // Get the distance from the camera class + dist = Isis::Camera::Distance(lat1,lon1,lat2,lon2,rad); + } + + if (dist == 0) { + // distance not calculated, continue to next cp2 + continue; + } + + // If the distance is less than the value entered by the user, + // keep the cube in the list + if ( dist < userEntered ) { + if (!temp.contains(g_filteredImages[i])) { + // this image is added to the filtered list + temp.push_back(g_filteredImages[i]); + } + } + if (temp.contains(g_filteredImages[i])) { + // g_filteredImages[i] is already added to the filtered list, + // no point in checking other distances, + // break out of cp2 loop and continue to next cp1 + break; + } + } // this ends cp2 loop + + if (temp.contains(g_filteredImages[i])) { + // g_filteredImages[i] is already added to the filtered list, + // no point in checking other distances, + // break out of cp1 loop and continue to next value of i + break; + } + } // this ends cp1 loop + } // this ends i loop + + // Sort QList of filtered points before displaying list to user + qSort(temp.begin(), temp.end()); + // replace existing filter list with this one + g_filteredImages = temp; + + // Tell the nav tool that a list has been filtered and it needs to updated + emit filteredListModified(); + return; + } +} + + + + + + + + diff --git a/isis/src/qisis/apps/qnet/QnetCubeDistanceFilter.h b/isis/src/qisis/apps/qnet/QnetCubeDistanceFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..bf6263d86c242885fe185f69300dcc04bc1cf3b0 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetCubeDistanceFilter.h @@ -0,0 +1,52 @@ +#ifndef QnetCubeDistanceFilter_h +#define QnetCubeDistanceFilter_h + +#include +#include +#include +#include +#include +#include +#include +#include "QnetFilter.h" + + +namespace Qisis { + /** + * Defines the Distance filter for the QnetNavTool's Cubes + * section. The user must enter a Minimum Distance value. This + * class is designed to remove cubes from the current filtered + * list that contain no points within the given distance. + * + * @internal + * @history 2008-12-03 Jeannie Walldren - Changed variable + * names and labels for clarity. Added + * radio buttons so the user may choose + * a distance in meters or pixels. + * Rewrote filter() method since it did + * not seem to be working properly, to + * increase efficiency and to allow + * filtering for a distance in meters + * or pixels. + * @history 2009-01-08 Jeannie Walldren - Modified filter() + * method to replace existing filtered + * list with a subset of that list. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null in constructor + * + */ + class QnetCubeDistanceFilter : public QnetFilter { + Q_OBJECT + + public: + QnetCubeDistanceFilter (QWidget *parent=0); + virtual void filter(); + + private: + QLineEdit *p_lineEdit; + QRadioButton *p_pixels; + QRadioButton *p_meters; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetCubeNameFilter.cpp b/isis/src/qisis/apps/qnet/QnetCubeNameFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48790e390058a783fdd96cb65a5300003c124750 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetCubeNameFilter.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include "QnetCubeNameFilter.h" +#include "QnetNavTool.h" +#include "ControlNet.h" +#include "SerialNumberList.h" + +#include "qnet.h" + +using namespace Qisis::Qnet; +using namespace std; + +namespace Qisis { + /** + * Contructor for the Cube Image filter. It creates the Cube Name filter window + * found in the navtool + * + * @param parent The parent widget for the + * cube points filter + * @internal + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null + * + */ + QnetCubeNameFilter::QnetCubeNameFilter (QWidget *parent) : QnetFilter(parent) { + p_cubeNameEdit = NULL; + // Create the components for the filter window + QLabel *label = new QLabel("Filter by cube name (Regular Expressions"); + p_cubeNameEdit = new QLineEdit(); + + // Create the layout and add the components to it + QVBoxLayout *vertLayout = new QVBoxLayout(); + vertLayout->addWidget(label); + vertLayout->addWidget(p_cubeNameEdit); + vertLayout->addStretch(); + this->setLayout(vertLayout); + } + + /** + * Filters a list of images looking for cube names using the regular expression + * entered. The filtered list will appear in the navtools cube list display. + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified to create + * new filtered list from images in the + * existing filtered list. Previously, + * a new filtered list was created from + * the entire serial number list each + * time. + */ + void QnetCubeNameFilter::filter() { + // Make sure we have a list of images to filter + if (g_serialNumberList == NULL) { + QMessageBox::information((QWidget *)parent(), + "Error","No cubes to filter"); + return; + } + + // Make sure the user has entered a regular expression for filtering + QRegExp rx(p_cubeNameEdit->text()); + rx.setPatternSyntax(QRegExp::Wildcard); + if (rx.isEmpty()) { + QMessageBox::information((QWidget *)parent(), + "Error","Enter search string"); + return; + } + + + // Loop through each image in the filtered list + // Loop in reverse order since removal list of elements affects index number + for (int i = g_filteredImages.size()-1; i >= 0; i--) { + string tempFilename = g_serialNumberList->Filename(g_filteredImages[i]); + // this name contains the string, keep it in the filtered list + if (rx.indexIn(QString(tempFilename.c_str())) != -1) { + continue; + } + // if there is no match, remove image from filtered list + else g_filteredImages.removeAt(i); + + } + // Tell the navtool a list has been filtered and it needs to update + emit filteredListModified(); + return; + + } +} diff --git a/isis/src/qisis/apps/qnet/QnetCubeNameFilter.h b/isis/src/qisis/apps/qnet/QnetCubeNameFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..4cc5ad0cc1ccce74ece748b183556a08cab984b9 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetCubeNameFilter.h @@ -0,0 +1,42 @@ +#ifndef QnetCubeNameFilter_h +#define QnetCubeNameFilter_h + +#include +#include +#include +#include +#include +#include +#include +#include "QnetFilter.h" + + +namespace Qisis { + /** + * Defines the Name filter for the QnetNavTool's Cubes + * section. The user must enter a string. This class is + * designed to remove cubes from the current filtered list + * whose filename does not contain the string. + * + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified filter() + * method to create new filtered list + * from images in the existing filtered + * list. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null in constructor + * + */ + class QnetCubeNameFilter : public QnetFilter { + Q_OBJECT + + public: + QnetCubeNameFilter (QWidget *parent=0); + virtual void filter(); + + private: + QLineEdit *p_cubeNameEdit; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetCubePointsFilter.cpp b/isis/src/qisis/apps/qnet/QnetCubePointsFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e45ba72419dc255609a6e4306e65829460c3b545 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetCubePointsFilter.cpp @@ -0,0 +1,121 @@ +#include +#include +#include "QnetCubePointsFilter.h" +#include "QnetNavTool.h" +#include "ControlNet.h" +#include "SerialNumberList.h" + +#include "qnet.h" + +using namespace Qisis::Qnet; + +namespace Qisis { + /** + * Contructor for the Cube Points filter. It + * creates the Points filter window found in + * the navtool + * + * @param parent The parent widget for the + * cube points filter + * @internal + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null. + * + */ + QnetCubePointsFilter::QnetCubePointsFilter (QWidget *parent) : QnetFilter(parent) { + p_lessThanRB = NULL; + p_greaterThanRB = NULL; + p_pointEdit = NULL; + + // Create the components for the filter window + QLabel *label = new QLabel("Filter by number of points in cube"); + p_lessThanRB = new QRadioButton("Less than (undercontrolled)"); + p_greaterThanRB = new QRadioButton("Greater than (overcontrolled)"); + p_pointEdit = new QLineEdit(); + QLabel *units = new QLabel ("points"); + p_lessThanRB->setChecked(true); + QLabel *pad = new QLabel(); + + // Create the layout and add the components to it + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->addWidget(label,0,0,1,2); + gridLayout->addWidget(p_lessThanRB,1,0,1,2); + gridLayout->addWidget(p_greaterThanRB,2,0,1,2); + gridLayout->addWidget(p_pointEdit,3,0); + gridLayout->addWidget(units,3,1); + gridLayout->addWidget(pad,4,0); + gridLayout->setRowStretch(4,50); + this->setLayout(gridLayout); + } + + /** + * Filters a list of images for images that have more or less + * than the user entered number of points. The filtered list + * will appear in the navtools cube list display. + * + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified to create + * new filtered list from images in the + * existing filtered list. Previously, + * a new filtered list was created from + * the entire serial number list each + * time. + */ + void QnetCubePointsFilter::filter() { + // Make sure we have a list of images to filter + if (g_serialNumberList == NULL) { + QMessageBox::information((QWidget *)parent(), + "Error","No cubes to filter"); + return; + } + + // Make sure the user has entered a value for filtering + int num = -1; + if (p_pointEdit->text() == "") { + QMessageBox::information((QWidget *)parent(), + "Error","Point value must be entered"); + return; + } + + // Get the value the user entered for filtering + num = p_pointEdit->text().toInt(); + + // Loop through each image in the list + // Loop in reverse order since removal of list elements affects index number + for (int i = g_filteredImages.size()-1; i >= 0; i--) { + + // Set up a counter parameter + int count = 0; + + // Loop through each control point in the network + for (int c=0; cSize(); c++) { + Isis::ControlPoint cp = (*g_controlNetwork)[c]; + + // Check to see if it has a measure on the current image + for (int cm=0; cmisChecked()) { + if (count > num) continue; + else g_filteredImages.removeAt(i); + } + // If the count is less than the number the user entered and the less than + // option was selected, add the image to the filtered list + else if (p_lessThanRB->isChecked()) { + if (count < num) continue; + else g_filteredImages.removeAt(i); + } + } + // Tell the navtool a list has been filtered and it needs to update + emit filteredListModified(); + return; + } +} diff --git a/isis/src/qisis/apps/qnet/QnetCubePointsFilter.h b/isis/src/qisis/apps/qnet/QnetCubePointsFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..67e9605916caf2904f8c687479bb1e5cad3cfa30 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetCubePointsFilter.h @@ -0,0 +1,46 @@ +#ifndef QnetCubePointsFilter_h +#define QnetCubePointsFilter_h + +#include +#include +#include +#include +#include +#include +#include +#include "QnetFilter.h" + + +namespace Qisis { + /** + * Defines the Points filter for the QnetNavTool's Cubes + * section. The user may choose to enter a maximum or minimum + * number of points. This class is designed to remove cubes from + * the current filtered list that contain more than the maximum + * or less than the minimum number of points. + * + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified filter() + * method to create a new filtered list + * from images in the existing filtered + * list. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null in constructor + * + * + */ + class QnetCubePointsFilter : public QnetFilter { + Q_OBJECT + + public: + QnetCubePointsFilter (QWidget *parent=0); + virtual void filter(); + + private: + QRadioButton *p_lessThanRB; + QRadioButton *p_greaterThanRB; + QLineEdit *p_pointEdit; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetDeletePointDialog.cpp b/isis/src/qisis/apps/qnet/QnetDeletePointDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db0d90978701f9cac9172a33d13f19b12fc949cb --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetDeletePointDialog.cpp @@ -0,0 +1,16 @@ +#include + +#include "QnetDeletePointDialog.h" + +#include "qnet.h" + +using namespace Qisis::Qnet; + +QnetDeletePointDialog::QnetDeletePointDialog(QWidget *parent) : QDialog(parent) { + + setupUi(this); + connect(okButton, SIGNAL(clicked()),this, SLOT(accept())); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + +} + diff --git a/isis/src/qisis/apps/qnet/QnetDeletePointDialog.h b/isis/src/qisis/apps/qnet/QnetDeletePointDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..085a11b1b1d83b9b0d5d45737973cbafe01beb3a --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetDeletePointDialog.h @@ -0,0 +1,16 @@ +#ifndef QnetDeletePointDialog_h +#define QnetDeletePointDialog_h + +#include + +#include "ui_QnetDeletePointDialog.h" + +class QnetDeletePointDialog : public QDialog, public Ui::QnetDeletePointDialog { + Q_OBJECT + + public: + QnetDeletePointDialog(QWidget *parent=0); + +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetDeletePointDialog.ui b/isis/src/qisis/apps/qnet/QnetDeletePointDialog.ui new file mode 100644 index 0000000000000000000000000000000000000000..7a875eead27ea6cb24b412a77f91f4549155ea1c --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetDeletePointDialog.ui @@ -0,0 +1,228 @@ + + + + + QnetDeletePointDialog + + + + 0 + 0 + 278 + 374 + + + + Delete ControlPoint + + + true + + + + + 20 + 250 + 351 + 33 + + + + + + + 10 + 10 + 258 + 284 + + + + + + + 10 + 20 + 258 + 321 + + + + + + + 10 + 10 + 258 + 348 + + + + + 0 + + + 6 + + + + + 0 + + + 6 + + + + + ControlPoint ID: + + + + + + + true + + + + + + + + + Delete ControlPoint + + + + + + + 0 + + + 6 + + + + + Or + + + Qt::AlignHCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Select images to remove from ControlPoint + + + + + + + QAbstractItemView::ExtendedSelection + + + + + + + 0 + + + 6 + + + + + Qt::Horizontal + + + + 41 + 31 + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + + + pointIdValue + fileList + deleteAllCheckBox + okButton + cancelButton + + + + + okButton + clicked() + QnetDeletePointDialog + accept() + + + 278 + 253 + + + 96 + 254 + + + + + cancelButton + clicked() + QnetDeletePointDialog + reject() + + + 369 + 253 + + + 179 + 282 + + + + + diff --git a/isis/src/qisis/apps/qnet/QnetFileTool.cpp b/isis/src/qisis/apps/qnet/QnetFileTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39e48f71e5ce8aa675be49c3756cb561075e83aa --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetFileTool.cpp @@ -0,0 +1,270 @@ +#include +#include +#include +#include + +#include "Application.h" +#include "Filename.h" +#include "MdiCubeViewport.h" +#include "QnetFileTool.h" +#include "SerialNumber.h" +#include "SerialNumberList.h" +#include "Workspace.h" + +#include "qnet.h" +using namespace Qisis::Qnet; +using namespace std; + +namespace Qisis { + /** + * Constructor + * + * @internal + * @history 2008-12-10 Jeannie Walldren - Reworded "What's this?" description + * for saveAs action. Changed "Save As" action text to + * match QnetTool's "Save As" action + */ + QnetFileTool::QnetFileTool (QWidget *parent) : Qisis::FileTool(parent) { + openAction()->setToolTip("Open network"); + QString whatsThis = + "Function: Open a control network \ +

    Shortcut: Ctrl+O\n

    "; + openAction()->setWhatsThis(whatsThis); + + saveAction()->setText("Save Control Network &As..."); + whatsThis = + "Function: Save the current control network under chosen filename"; + saveAction()->setWhatsThis(whatsThis); + saveAction()->setEnabled(true); + + p_saveNet = false; + + + } + + /** + * Open a list of cubes + * + * @author 2007-05-01 Elizabeth Ribelin + * + * @internal + * @history 2007-06-07 Tracie Sucharski - Allow new network to be opened, + * prompt to save old network. + * @history 2008-11-26 Tracie Sucharski - Remove all polygon/overlap + * references, this functionality will be qmos. + * @history 2008-11-26 Jeannie Walldren - Uncommented "emit + * controlNetworkUpdated()" line and added parameter name + * defined in this method. + * @history 2008-12-10 Jeannie Walldren - Fixed documentation + * @history 2010-07-01 Jeannie Walldren - Added file extension filters for + * input control network + * + */ + void QnetFileTool::open () { + + // If network already opened, prompt for saving + if (g_serialNumberList != NULL && p_saveNet) { + // If control net has been changed , prompt for user to save + int resp = QMessageBox::warning((QWidget*)parent(),"Qnet", + "The control network files has been modified.\n" + "Do you want to save your changes?", + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No, + QMessageBox::Cancel | QMessageBox::Escape); + if (resp == QMessageBox::Yes) { + saveAs(); + } + p_saveNet = false; + } + + QString filter = "List of cubes (*.lis *.lst *.list);;"; + filter += "Text file (*.txt);;"; + filter += "All (*)"; + QString list = QFileDialog::getOpenFileName((QWidget*)parent(), + "Select a list of cubes", + ".", + filter); + if (list.isEmpty()) return; + + // Find directory and save for use in file dialog for net file + Isis::Filename file(list.toStdString()); + QString dir = file.absolutePath(); + + QApplication::setOverrideCursor(Qt::WaitCursor); + // Use the list to get serial numbers and polygons + try { + if (g_serialNumberList != NULL) { + delete g_serialNumberList; + g_serialNumberList = NULL; + } + g_serialNumberList = new Isis::SerialNumberList(list.toStdString()); + + if (g_controlNetwork != NULL) { + delete g_controlNetwork; + g_controlNetwork = NULL; + } + } + catch (Isis::iException &e) { + QString message = "Error processing cube list. \n"; + string errors = e.Errors(); + message += errors.c_str(); + e.Clear (); + QMessageBox::information((QWidget *)parent(),"Error",message); + QApplication::restoreOverrideCursor(); + return; + } + + QApplication::restoreOverrideCursor(); + filter = "Control net (*.net *.cnet *.ctl);;"; + filter += "Pvl file (*.pvl);;"; + filter += "Text file (*.txt);;"; + filter += "All (*)"; + cNetFilename = QFileDialog::getOpenFileName((QWidget*)parent(), + "Select a control network", + dir, + filter); + QApplication::setOverrideCursor(Qt::WaitCursor); + if (cNetFilename.isEmpty()) { + g_controlNetwork = new Isis::ControlNet(); + g_controlNetwork->SetType(Isis::ControlNet::ImageToGround); + g_controlNetwork->SetUserName(Isis::Application::UserName()); + } + else { + try { + g_controlNetwork = new Isis::ControlNet(cNetFilename.toStdString()); + } + catch (Isis::iException &e) { + QString message = "Invalid control network. \n"; + string errors = e.Errors(); + message += errors.c_str(); + e.Clear (); + QMessageBox::information((QWidget *)parent(),"Error",message); + QApplication::restoreOverrideCursor(); + return; + } + } + + // Initialize cameras for control net + g_controlNetwork->SetImages (*g_serialNumberList); + + serialNumberListUpdated(); + emit controlNetworkUpdated(cNetFilename); + QApplication::restoreOverrideCursor(); + return; + } + + /** + * Exit the program + */ + void QnetFileTool::exit() { + // If control net has been changed , prompt for user to save + if (p_saveNet) { + int resp = QMessageBox::warning((QWidget*)parent(),"QnetTool", + "The control network files has been modified.\n" + "Do you want to save your changes?", + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No, + QMessageBox::Cancel | QMessageBox::Escape); + if (resp == QMessageBox::Yes) { + saveAs(); + } + if (resp == QMessageBox::Cancel) { + return; + } + } + qApp->quit(); + } + + /** + * Save control network with given file + * @internal + * @history 2010-07-01 Jeannie Walldren - Added file extension filters for + * input control network + * + */ + void QnetFileTool::saveAs() { + QString filter = "Control net (*.net *.cnet *.ctl);;"; + filter += "Pvl file (*.pvl);;"; + filter += "Text file (*.txt);;"; + filter += "All (*)"; + QString fn=QFileDialog::getSaveFileName((QWidget*)parent(), + "Choose filename to save under", + ".", filter); + if ( !fn.isEmpty() ) { + try { + g_controlNetwork->Write(fn.toStdString()); + } + catch (Isis::iException &e) { + QString message = "Error saving control network. \n"; + string errors = e.Errors(); + message += errors.c_str(); + e.Clear (); + QMessageBox::information((QWidget *)parent(),"Error",message); + return; + } + } + else { + QMessageBox::information((QWidget *)parent(), + "Error","Saving Aborted"); + } + p_saveNet = false; + } + + /** + * Load given cube in Workspace + * + * @param serialNumber [in] (QString) Serial number of cube to display + * + * @author 2007-05-01 Elizabeth Ribelin + * + * @internal + * @history 2008-10-08 Tracie Sucharski - Do not display cube if it is + * already displayed, set as active window. + * @history 2008-12-10 Jeannie Walldren - Fixed documentation + * @history 2010-06-03 Jeannie Walldren - Removed "std::" since "using + * namespace std" + * + */ + void QnetFileTool::loadImage(const QString &serialNumber) { + if (g_serialNumberList->HasSerialNumber(serialNumber.toStdString())) { + string tempFilename = g_serialNumberList->Filename(serialNumber.toStdString()); + QString filename = tempFilename.c_str(); + QVector< MdiCubeViewport * > * cvpList = + g_vpMainWindow->workspace()->cubeViewportList(); + bool found = false; + for (int i=0; i<(int)cvpList->size(); i++) { + string sn = Isis::SerialNumber::Compose(*((*cvpList)[i]->cube())); + if (sn == serialNumber.toStdString()) { + g_vpMainWindow->workspace()->setActiveSubWindow((QMdiSubWindow *)(*cvpList)[i]->parentWidget()); + found = true; + break; + } + } + if (!found) emit fileSelected(filename); + } + else { + // TODO: Handle error? + } + } + + /** + * Load given point + * + * @param point Control point to load + */ + void QnetFileTool::loadPoint(Isis::ControlPoint *point) { + for (int i=0; iSize(); i++) { + string cubeSN = (*point)[i].CubeSerialNumber(); + loadImage(cubeSN.c_str()); + } + } + + /** + * Sets save net flag to true. + */ + void QnetFileTool::setSaveNet() { + p_saveNet = true; + } + + +} diff --git a/isis/src/qisis/apps/qnet/QnetFileTool.h b/isis/src/qisis/apps/qnet/QnetFileTool.h new file mode 100644 index 0000000000000000000000000000000000000000..de8d115581b3cedb4146babb211b39b07d31bc92 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetFileTool.h @@ -0,0 +1,89 @@ +#ifndef QnetFileTool_h +#define QnetFileTool_h + +/** + * @file + * $Revision: 1.9 $ + * $Date: 2010/07/01 19:04:52 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "ControlPoint.h" +#include "FileTool.h" // parent + +// forward declarations +class QString; +class QWidget; + +namespace Qisis { + +/** + * @brief Qnet File operations + * + * @ingroup Visualization Tools + * + * @author 2006-02-01 Jeff Anderson + * + * @internal + * @history 2006-08-02 Tracie Sucharski - Initialize cameras for every image + * in cube list. + * @history 2008-11-24 Jeannie Walldren - Replace references to PointEdit class + * with ControlPointEdit + * @history 2008-11-26 Jeannie Walldren - Added cNetName parameter to + * controlNetworkUpdated() so that QnetTool can read the + * name of the control net file. + * @history 2008-11-26 Tracie Sucharski - Remove all polygon/overlap + * polygon/overlap references, this functionality will + * be in qmos. + * @history 2008-12-10 Jeannie Walldren - Reworded "What's this?" description + * for saveAs action. Changed "Save As" action text to + * match QnetTool's "Save As" action 2010-06-03 Jeannie + * Walldren - Removed "std::" in .cpp file since "using + * namespace std" + * @history 2010-07-01 Jeannie Walldren - Added file extension filters for + * input control network. Replaced #includes with + * forward class declarations and moved #include to + * .cpp file. + * + */ + + class QnetFileTool : public FileTool { + Q_OBJECT + + signals: + void serialNumberListUpdated(); + void controlNetworkUpdated(QString cNetName); + + public: + QnetFileTool (QWidget *parent); + QString cNetFilename; + + public slots: + virtual void open(); + virtual void exit(); + virtual void saveAs(); + void loadPoint(Isis::ControlPoint *point); + void loadImage(const QString &serialNumber); + void setSaveNet(); + + private: + bool p_saveNet; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetFilter.cpp b/isis/src/qisis/apps/qnet/QnetFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..caead79f1b2beaccb48de828dc2b2d1b87117172 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetFilter.cpp @@ -0,0 +1,12 @@ +#include "QnetFilter.h" +#include "ControlNet.h" +#include "SerialNumberList.h" + +#include "qnet.h" +using namespace Qisis::Qnet; + +namespace Qisis { + // Constructor + QnetFilter::QnetFilter (QWidget *parent) : QWidget(parent) { + } +} diff --git a/isis/src/qisis/apps/qnet/QnetFilter.h b/isis/src/qisis/apps/qnet/QnetFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..7ef93f8b473d61f5e1755bf8a23b8728c045669d --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetFilter.h @@ -0,0 +1,25 @@ +#ifndef QnetFilter_h +#define QnetFilter_h + +#include +#include +#include +#include +#include + + +namespace Qisis { + class QnetFilter : public QWidget { + Q_OBJECT + + public: + QnetFilter (QWidget *parent); + virtual ~QnetFilter () {}; + virtual void filter() { return; }; + + signals: + void filteredListModified(); + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetHoldPointDialog.cpp b/isis/src/qisis/apps/qnet/QnetHoldPointDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..02784f0ce75cf982072ab1eedd440381cc3ee609 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetHoldPointDialog.cpp @@ -0,0 +1,148 @@ +#include + +#include +#include +#include +#include +#include +#include + + +#include + +#include "QnetHoldPointDialog.h" +#include "SerialNumberList.h" +#include "ControlPoint.h" +#include "Camera.h" + +#include "qnet.h" + +using namespace Qisis::Qnet; +using namespace std; + +namespace Qisis { + + /** + * Constructor. + * + * @internal + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null. + */ + QnetHoldPointDialog::QnetHoldPointDialog (QWidget *parent) : QDialog (parent) { + p_avg = NULL; + p_select = NULL; + p_fileList = NULL; + p_okButton = NULL; + p_point = NULL; + + p_avg = new QRadioButton("Average Measures"); + p_avg->setChecked(true); + p_select = new QRadioButton("Select Measures"); + p_select->setChecked(false); + connect(p_avg,SIGNAL(clicked()),this,SLOT(selectMeasures())); + connect(p_select,SIGNAL(clicked()),this,SLOT(selectMeasures())); + + QLabel *listLabel = new QLabel("Select Files:"); + + p_fileList = new QListWidget(); + p_fileList->setSelectionMode(QAbstractItemView::SingleSelection); + p_fileList->setEnabled(false); + + // Create OK & Cancel buttons + p_okButton = new QPushButton("OK"); + p_okButton->setDefault(true); + p_okButton->setEnabled(true); + QPushButton *cancelButton = new QPushButton("Cancel"); + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addWidget(p_okButton); + buttonLayout->addWidget(cancelButton); + + connect(p_okButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->addWidget(p_avg); + vLayout->addWidget(p_select); + vLayout->addWidget(listLabel); + vLayout->addWidget(p_fileList); + vLayout->addLayout(buttonLayout); + + setLayout(vLayout); + setWindowTitle("Create Hold ControlPoint"); + + } + + void QnetHoldPointDialog::setPoint (Isis::ControlPoint &point) { + p_point = &point; + + // Find all files for this point + for (int i=0; iSize(); i++) { + QListWidgetItem *item = new QListWidgetItem(p_fileList); + string fname = g_serialNumberList->Filename((*p_point)[i].CubeSerialNumber()); + item->setText(QString(fname.c_str())); + } + } + + + + void QnetHoldPointDialog::selectMeasures () { + if (p_select->isChecked()) { + p_fileList->setEnabled(true); + } + else { + p_fileList->setEnabled(false); + } + } + + + void QnetHoldPointDialog::accept () { + + if (p_avg->isChecked()) { + p_point->ComputeApriori(); + } + else { + int i = p_fileList->currentRow(); + Isis::Camera *cam = (*p_point)[i].Camera(); + if (cam->SetImage((*p_point)[i].Sample(),(*p_point)[i].Line())) { + double lat = cam->UniversalLatitude(); + double lon = cam->UniversalLongitude(); + double rad = cam->LocalRadius(); + p_point->SetUniversalGround(lat,lon,rad); + } + else { + QString msg = "Cannot compute lat/lon for this control point " + + QString::fromStdString(p_point->Id()) + " pick another point."; + QMessageBox::information((QWidget *)parent(),"Error",msg); + return; + } + + } + + p_point->SetHeld(true); + emit holdPoint (*p_point); + + QDialog::accept(); + } + + + + + + /** + * This method will emit a signal that the "Cancel" button has + * been selected in the dialog. This signal will be picked up + * in the QnetTool to uncheck the Hold Point box and return. + * + * @author Jeannie Walldren + * @internal + * @history 2010-06-02 Jeannie Walldren - Original Version. + */ + + void QnetHoldPointDialog::reject () { + emit holdCancelled(); + QDialog::reject(); + } + +} + diff --git a/isis/src/qisis/apps/qnet/QnetHoldPointDialog.h b/isis/src/qisis/apps/qnet/QnetHoldPointDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..d63533aa2a53fa8904fa13a7e5368e7d11660e86 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetHoldPointDialog.h @@ -0,0 +1,65 @@ +#ifndef QnetHoldPointDialog_h +#define QnetHoldPointDialog_h + +#include + +class QListWidget; +class QRadioButton; +class QPushButton; + +#include "ControlPoint.h" + +#include + +namespace Qisis { + /** + * Dialog box to help user choose how to determine lat/lon/rad + * for selected hold point. + * + * @internal + * @history 2008-12-29 Jeannie Walldren - Changed name from + * QnetGroundPointDialog + * @history 2010-06-02 Jeannie Walldren - Added overridden + * reject() method to emit the + * holdCancelled() signal to indicate + * that the "Cancel" button was + * clicked. This signal is connected in + * QnetTool's setHoldPoint() method. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null in constructor + * + */ + class QnetHoldPointDialog : public QDialog { + Q_OBJECT + + public: + QnetHoldPointDialog (QWidget *parent=0); + void setPoint (Isis::ControlPoint &point); + + + signals: + void holdPoint (Isis::ControlPoint &point); + void holdCancelled(); + + private: + + QRadioButton *p_avg; + QRadioButton *p_select; + QListWidget *p_fileList; + + QPushButton *p_okButton; + + Isis::ControlPoint *p_point; + + private slots: + void selectMeasures (); + void accept (); + void reject (); + }; +}; + +#endif + + + + diff --git a/isis/src/qisis/apps/qnet/QnetNavTool.cpp b/isis/src/qisis/apps/qnet/QnetNavTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8dd3f3ce1295712314c1f5444d3f8272d16fadf9 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetNavTool.cpp @@ -0,0 +1,886 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "QnetCubeDistanceFilter.h" +#include "QnetCubeNameFilter.h" +#include "QnetCubePointsFilter.h" +#include "QnetNavTool.h" +#include "QnetPointCubeNameFilter.h" +#include "QnetPointDistanceFilter.h" +#include "QnetPointErrorFilter.h" +#include "QnetPointGoodnessFilter.h" +#include "QnetPointIdFilter.h" +#include "QnetPointImagesFilter.h" +#include "QnetPointMeasureFilter.h" +#include "QnetPointRangeFilter.h" +#include "QnetPointTypeFilter.h" + +#include "qnet.h" +using namespace Qisis::Qnet; +using namespace std; + +namespace Qisis { + /** + * Consructs the Navigation Tool window + * + * @param parent The parent widget for the navigation tool + * + * @internal + * @history 2008-12-09 Tracie Sucharski - Added p_filtered indicating whether + * the listBox contains filtered or unfiltered + * list. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers to null. + * + */ + QnetNavTool::QnetNavTool (QWidget *parent) : Qisis::Tool(parent) { + p_navDialog = NULL; + p_filter = NULL; + p_tie = NULL; + p_multiIgnore = NULL; + p_multiDelete = NULL; + p_filterStack = NULL; + p_listCombo = NULL; + p_listBox = NULL; + p_filterCountLabel = NULL; + createNavigationDialog(parent); + connect (this,SIGNAL(deletedPoints()), + this,SLOT(refreshList())); + p_filtered = false; + } + + /** + * Creates and shows the dialog box for the navigation tool + * + * @param parent The parent widget for the navigation dialopg + * + * @internal + * @history 2008-10-29 Tracie Sucharski - Added filter count + * @history 2008-12-31 Jeannie Walldren - Added keyboard shortcuts + */ + void QnetNavTool::createNavigationDialog(QWidget *parent) { + // Create the combo box selector + p_listCombo = new QComboBox (); + p_listCombo->addItem("Points"); + p_listCombo->addItem("Cubes"); + p_listBox = new QListWidget(); + p_listBox->setSelectionMode(QAbstractItemView::ExtendedSelection); + connect (p_listBox,SIGNAL(itemDoubleClicked(QListWidgetItem *)), + this,SLOT(editPoint(QListWidgetItem *))); + + // Create the filter area + QLabel *filterLabel = new QLabel ("Filters"); + filterLabel->setAlignment(Qt::AlignHCenter); + p_filterStack = new QStackedWidget (); + + connect(p_listCombo,SIGNAL(activated(int)), + p_filterStack,SLOT(setCurrentIndex(int))); + connect(p_listCombo,SIGNAL(activated(int)), + this,SLOT(resetList())); + connect(p_listCombo,SIGNAL(activated(int)), + this,SLOT(enableButtons())); + + // Create filter count label + p_filterCountLabel = new QLabel("Filter Count: "); + + // Create action options + QWidget *actionArea = new QWidget(); + QPushButton *load = new QPushButton("&View Cube(s)",actionArea); + load->setToolTip("Open Selected Images"); + load->setWhatsThis("Function: Opens all selected images, or images \ + that are associated with the given point or overlap. \ +

    Hint: You can select more than one item in \ + the list by using the shift or control key.

    "); + connect(load,SIGNAL(clicked()), + this,SLOT(load())); + p_tie = new QPushButton("&Modify Point",actionArea); + p_tie->setToolTip("Modify Selected Point"); + p_tie->setWhatsThis("Function: Opens the tie tool to modify the \ + selected point from the list. This option is only \ + available when the nav tool is in point mode"); + connect(p_tie,SIGNAL(clicked()), + this,SLOT(tie())); + + p_multiIgnore = new QPushButton("&Ignore Points",actionArea); + p_multiIgnore->setToolTip("Set selected points to Ignore"); + p_multiIgnore->setWhatsThis("Function: Sets the selected points \ + Ignore = True. You will not be able to preview \ + in the Point Editor before their Ignore switch \ + is set to true. \ +

    Hint: You can select more than one \ + item in the list by using the shift or control \ + key.

    "); + connect(p_multiIgnore,SIGNAL(clicked()), + this,SLOT(ignorePoints())); + + p_multiDelete = new QPushButton("&Delete Points",actionArea); + p_multiIgnore->setToolTip("Set selected points to Delete"); + p_multiIgnore->setWhatsThis("Function: Delete the selected points \ + from control network. You will not be able to \ + preview in the Point Editor before they are \ + deleted. \ +

    Hint: You can select more than one \ + item in the list by using the shift or control \ + key.

    "); + connect(p_multiDelete,SIGNAL(clicked()), + this,SLOT(deletePoints())); + + p_filter = new QPushButton("&Filter",actionArea); + p_filter->setToolTip("Filter Current List"); + p_filter->setWhatsThis("Function: Filters the current list by user \ + specifications made in the selected filter. \ +

    Note: Any filter options selected in a \ + filter that is not showing will be ignored.

    "); + connect(p_filter,SIGNAL(clicked()), + this,SLOT(filter())); + + QPushButton *reset = new QPushButton("&Show All",actionArea); + reset->setToolTip("Reset the Current List to show all the values in the list"); + reset->setWhatsThis("Function: Resets the list of points, \ + overlaps, or images to the complete initial list. \ + Any filtering that has been done will be lost."); + connect(reset,SIGNAL(clicked()), + this,SLOT(resetList())); + connect(reset,SIGNAL(clicked()), + this,SLOT(resetFilter())); + + // Set up layout + QHBoxLayout *layout = new QHBoxLayout(); + layout->addWidget(load); + layout->addWidget(p_tie); + layout->addWidget(p_multiIgnore); + layout->addWidget(p_multiDelete); + layout->addWidget(p_filter); + layout->addWidget(reset); + + // Create filter stacked widgets + createFilters(); + p_filterStack->adjustSize(); + + // Set up the main window + p_navDialog = new QDialog(parent); + p_navDialog->setWindowTitle("Control Network Navigator"); + + // Layout everything in the dialog + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->addWidget(p_listCombo,0,0); + gridLayout->addWidget(filterLabel,0,1); + gridLayout->addWidget(p_listBox,1,0); + gridLayout->addWidget(p_filterStack,1,1); + gridLayout->addWidget(p_filterCountLabel,2,0); + gridLayout->addLayout(layout,3,0,1,2); + p_navDialog->setLayout(gridLayout); + + // View the dialog + p_navDialog->setShown(true); + } + + /** + * Sets up the tabbed widgets for the different types of filters available + * + * @internal + * @history 2007-06-05 Tracie Sucharski - Added enumerators for the filter + * indices to make it easier to re-order filters. + * Also, re-ordered the filters to put commonly used + * first. Comment out overlap/polygon code + * temporarily. + * @history 2008-11-26 Jeannie Walldren - Added Goodness of Fit to the filter + * tabs. + * @history 2008-12-31 Jeannie Walldren - Added keyboard shortcuts to tabs. + * @history 2009-01-26 Jeannie Walldren - Clarified tab names. Added points + * cube name filter tab. + * @history 2010-06-02 Jeannie Walldren - Changed tab labels from "Type" to + * "Properties". Updated "What's This?" documentation + * for Measure Properties to explain use of ignore + * status and measure type filters. + */ + void QnetNavTool::createFilters() { + // Set up the point filters + QTabWidget *pointFilters = new QTabWidget(); + + QWidget *errorFilter = new QnetPointErrorFilter(); + connect(errorFilter,SIGNAL(filteredListModified()), + this,SLOT(filterList())); + pointFilters->insertTab(Errors,errorFilter,"&Error"); + pointFilters->setTabToolTip(Errors,"Filter Points by Error"); + pointFilters->setTabWhatsThis(Errors, + "Function: Filter points list by \ + the bundle adjust error value at each \ + point. You can filter for points that \ + have an error greater than, or less than \ + the entered value."); + + QWidget *ptIdFilter = new QnetPointIdFilter(); + connect(ptIdFilter,SIGNAL(filteredListModified()), + this,SLOT(filterList())); + pointFilters->insertTab(Id,ptIdFilter,"&Point ID"); + pointFilters->setTabToolTip(Id,"Filter Points by PointID"); + + QWidget *ptImageFilter = new QnetPointImagesFilter(); + connect(ptImageFilter,SIGNAL(filteredListModified()), + this,SLOT(filterList())); + pointFilters->insertTab(NumberImages,ptImageFilter,"&Number of Measures"); + pointFilters->setTabToolTip(NumberImages,"Filter Points by Number of Images"); + pointFilters->setTabWhatsThis(NumberImages,"Function: Filter points list \ + by the number of images that are in \ + each point. You can filter for \ + points that have more than the given \ + number of images, or less than the \ + given number of images. Points with \ + the exact number of images specified \ + will not be included in the filtered \ + list."); + QWidget *typeFilter = new QnetPointTypeFilter(); + connect(typeFilter,SIGNAL(filteredListModified()), + this,SLOT(filterList())); + pointFilters->insertTab(Type,typeFilter,"Point Properties"); + pointFilters->setTabToolTip(Type,"Filter Points by Listed Properties"); + pointFilters->setTabWhatsThis(Type,"Function: Filter points list by \ + their Point Type, Ignore status, or Held status properties"); + QWidget *rangeFilter = new QnetPointRangeFilter(); + connect(rangeFilter,SIGNAL(filteredListModified()), + this,SLOT(filterList())); + pointFilters->insertTab(LatLonRange,rangeFilter,"&Range"); + pointFilters->setTabToolTip(LatLonRange,"Filter Points by Range"); + pointFilters->setTabWhatsThis(LatLonRange,"Function: Filters out points \ + that are within a user set range lat/lon \ + range."); + QWidget *ptDistFilter = new QnetPointDistanceFilter(); + connect(ptDistFilter,SIGNAL(filteredListModified()), + this,SLOT(filterList())); + pointFilters->insertTab(Distance,ptDistFilter,"Dist&ance"); + pointFilters->setTabToolTip(Distance,"Filter Points by Distance"); + pointFilters->setTabWhatsThis(Distance, + "Function: Filter points list by \ + a user specified maximum distance from \ + any other point."); + QWidget *measureFilter = new QnetPointMeasureFilter(); + connect(measureFilter,SIGNAL(filteredListModified()), + this,SLOT(filterList())); + pointFilters->insertTab(MeasureType,measureFilter,"Measure Properties"); + pointFilters->setTabToolTip(MeasureType,"Filter Points by Listed Measure Properties"); + pointFilters->setTabWhatsThis(MeasureType, + "Function: Filter points list by \ + the properties of their measures. User may \ + filter by Measure Type or Ignore status. \ + If one or more measure from a point is found to \ + match a selected measure type, and that measure \ + satisfies the ignore status selected, the point \ + will be left in the filtered list. More \ + than one measure type can be selected. \ + Only one Ignore status may be selected."); + + QWidget *goodnessFilter = new QnetPointGoodnessFilter(); + connect(goodnessFilter,SIGNAL(filteredListModified()), + this,SLOT(filterList())); + pointFilters->insertTab(GoodnessOfFit,goodnessFilter,"&Goodness of Fit"); + pointFilters->setTabToolTip(GoodnessOfFit,"Filter Points by the Goodness of Fit of its measures"); + pointFilters->setTabWhatsThis(GoodnessOfFit, + "Function: Filter points list by \ + the goodness of fit."); + QWidget *cubeNamesFilter = new QnetPointCubeNameFilter(); + connect(cubeNamesFilter,SIGNAL(filteredListModified()), + this,SLOT(filterList())); + connect(this,SIGNAL(serialListModified()), + cubeNamesFilter,SLOT(createCubeList())); + + pointFilters->insertTab(CubeName,cubeNamesFilter,"&Cube Name(s)"); + pointFilters->setTabToolTip(CubeName,"Filter Points by Cube Filename(s)"); + pointFilters->setTabWhatsThis(CubeName, + "Function: Filter points list by \ + the filenames of cubes. This filter will \ + show all points contained in a single \ + image or all points contained in every \ + cube selected."); + // Set up the cube filters + QTabWidget *cubeFilters = new QTabWidget(); + + QWidget *cubeNameFilter = new QnetCubeNameFilter(); + connect(cubeNameFilter,SIGNAL(filteredListModified()), + this,SLOT(filterList())); + cubeFilters->insertTab(Name,cubeNameFilter,"&Cube Name"); + cubeFilters->setTabToolTip(Name,"Filter Images by Cube Name"); + + QWidget *cubePtsFilter = new QnetCubePointsFilter(); + connect(cubePtsFilter,SIGNAL(filteredListModified()), + this,SLOT(filterList())); + cubeFilters->insertTab(NumberPoints,cubePtsFilter,"&Number of Points"); + cubeFilters->setTabToolTip(NumberPoints,"Filter Images by Number of Points"); + cubeFilters->setTabWhatsThis(NumberPoints, + "Function: Filter images list by \ + the number of points that are in each \ + image. You can filter for images that have \ + more than the given number of points, or \ + less than the given number of point. \ + Images with the exact number of points \ + specified will not be included in the \ + filtered list."); + QWidget *cubeDistFilter = new QnetCubeDistanceFilter(); + connect(cubeDistFilter,SIGNAL(filteredListModified()), + this,SLOT(filterList())); + cubeFilters->insertTab(PointDistance,cubeDistFilter,"Dist&ance"); + cubeFilters->setTabToolTip(PointDistance,"Filter Images by Distance between Points"); + cubeFilters->setTabWhatsThis(PointDistance, + "Function: Filter images list by \ + a user specified distance between points \ + in the image. This may be calculated in \ + meters or by pixel distance."); + + // Add widgets to the filter stack + p_filterStack->addWidget(pointFilters); + p_filterStack->addWidget(cubeFilters); + } + + /** + * Resets the list box with whatever is in the global lists + * + * @internal + * @history 2007-06-05 Tracie Sucharski - Use enumerators to test which + * filter is chosen. Comment overlap/polygon code + * temporarily. + * @history 2008-10-29 Tracie Sucharski - Added filter count 2008-11-26 + * Tracie Sucharski - Remove all polygon/overlap + * references, this functionality will be qmos. + * @history 2008-12-09 Tracie Sucharski - Renamed method from updateList to + * resetList since it it reseting all of the filtered + * lists and the listBox to the entire network of + * points and serial numbers. + * @history 2008-12-09 Tracie Sucharski - Added p_filtered indicating whether + * the listBox contains filtered or unfiltered list. + * @history 2009-01-08 Jeannie Walldren - Reset filtered list with all points + * in control net and all images in serial number + * list. + */ + void QnetNavTool::resetList() { + p_filtered = false; + // Dont do anything if there are no cubes loaded + if (g_serialNumberList == NULL) return; + + // Clear the old list and filtered lists and update with the entire list + p_listBox->setCurrentRow(-1); + p_listBox->clear(); + g_filteredPoints.clear(); + g_filteredImages.clear(); + + // copy the control net indices into the filtered points list + for (int i = 0; i < g_controlNetwork->Size(); i++) { + g_filteredPoints.push_back(i); + } + // copy the serial number indices into the filtered images list + for (int i = 0; i < g_serialNumberList->Size(); i++) { + g_filteredImages.push_back(i); + } + + // We are dealing with points so output the point numbers + if (p_listCombo->currentIndex() == Points) { + //p_listBox->setSelectionMode(QAbstractItemView::SingleSelection); + for (int i=0; iSize(); i++) { + string cNetId = (*g_controlNetwork)[i].Id(); + QString itemString = cNetId.c_str(); + p_listBox->insertItem(i,itemString); + int images = (*g_controlNetwork)[i].Size(); + p_listBox->item(i)->setToolTip(QString::number(images)+" image(s) in point"); + } + // Make sure edit point is selected and in view. + updateEditPoint (p_editPointId); + + QString msg = "Filter Count: " + QString::number(p_listBox->count()) + + " / " + QString::number(g_controlNetwork->Size()); + p_filterCountLabel->setText(msg); + } + // We are dealing with images so output the cube names + else if (p_listCombo->currentIndex() == Cubes) { + //p_listBox->setSelectionMode(QAbstractItemView::ExtendedSelection); + for (int i=0; iSize(); i++) { + Isis::Filename filename = Isis::Filename(g_serialNumberList->Filename(i)); + string tempFilename = filename.Name(); + p_listBox->insertItem(i,tempFilename.c_str()); + } + QString msg = "Filter Count: " + QString::number(p_listBox->count()) + + " / " + QString::number(g_serialNumberList->Size()); + p_filterCountLabel->setText(msg); + + } + } + + + /** + * Update the list showing the new point highlighted. + * + * @param pointId Value of the PointId keyword for the new point. + * @internal + * @history 2008-12-30 Jeannie Walldren - Modified to setCurrentItem() rather + * than simply highlight the new point using + * setItemSelected() and scrollToItem(). + */ + void QnetNavTool::updateEditPoint (string pointId) { + + p_editPointId = pointId; + if (pointId == "") return; + + QList items = p_listBox->findItems(QString(pointId.c_str()), + Qt::MatchExactly); + if (items.isEmpty()) { + p_listBox->clearSelection(); + } + else { + p_listBox->setCurrentItem(items.at(0)); + } + return; + } + + + + /** + * Slot to refresh the listBox + * + * @internal + * @history 2008-12-09 Tracie Sucharski - Slot to refresh the ListBox + */ + void QnetNavTool::refreshList () { + + if (p_filtered) { + filter(); + } + else { + resetList(); + } + + } + + /** + * Resets the visible filter to the default values + */ + void QnetNavTool::resetFilter() { + + } + + /** + * Updates the list box in the nav window with a new list from one of the + * filters + * + * @internal + * @history 2007-06-05 Tracie Sucharski - Use enumerators for the filter + * indices. Comment out overlap/polygon code + * temporarily. + * @history 2008-10-29 Tracie Sucharski - Added filter count + * + */ + void QnetNavTool::filterList() { + // Don't do anything if there are no cubes loaded + if (g_serialNumberList == NULL) return; + + // Clears the old list and puts the filtered list in its place + p_listBox->setCurrentRow(-1); + p_listBox->clear(); + + // We are dealing with points so output the point numbers + if (p_listCombo->currentIndex() == Points) { + for (int i=0; iinsertItem(i,itemString); + int images = (*g_controlNetwork)[g_filteredPoints[i]].Size(); + p_listBox->item(i)->setToolTip(QString::number(images)+" image(s) in point"); + } + QString msg = "Filter Count: " + QString::number(p_listBox->count()) + + " / " + QString::number(g_controlNetwork->Size()); + p_filterCountLabel->setText(msg); + } + // We are dealing with images so write out the cube names + else if (p_listCombo->currentIndex() == Cubes) { + for (int i=0; iFilename(g_filteredImages[i])); + string tempFilename = filename.Name(); + p_listBox->insertItem(i,tempFilename.c_str()); + } + QString msg = "Filter Count: " + QString::number(p_listBox->count()) + + " / " + QString::number(g_serialNumberList->Size()); + p_filterCountLabel->setText(msg); + } + } + + + + /** + * Tells the filetool to load an image, point, or overlap + * + * @internal + * @history 2007-06-05 Tracie Sucharski - Use enumerators for the filter + * indices. Comment out overlap/polygon code + * temporarily. + * @history 2008-11-19 Jeannie Walldren - Added Qt::WaitCursor (i.e. clock or + * hourglass) to indicate that there is background + * activity while this method is running + * @history 2008-11-26 Tracie Sucharski - Remove all polygon/overlap + * references, this functionality will be qmos. + * @history 2010-06-03 Jeannie Walldren - Modified "No file selected" warning + * to check whether selected list is empty rather than + * the index of current row. + */ + void QnetNavTool::load() { + // Dont do anything if no cubes are loaded + if (g_serialNumberList == NULL) return; + + // TODO: How do we handle them opening 2 overlaps or points that have the + // cube in them, open 2 of the same file or only open 1??? + QList selected = p_listBox->selectedItems(); + if (selected.size() < 1 ){ + QMessageBox::information((QWidget *)parent(), + "Error","No file selected to load."); + return; + } + + QApplication::setOverrideCursor(Qt::WaitCursor); + for (int i=0; irow(selected[i]); + // Tell the filetool to load all images for the given point + if (p_listCombo->currentIndex() == Points) { + if (g_filteredPoints.size() == 0) { + emit loadPoint(&((*g_controlNetwork)[index])); + } + else { + emit loadPoint(&((*g_controlNetwork)[g_filteredPoints[index]])); + } + } + // Tell the filetool to load the given image + else if (p_listCombo->currentIndex() == Cubes) { + if (g_filteredImages.size() == 0) { + string serialNumberList = (*g_serialNumberList).SerialNumber(index); + QString sn = serialNumberList.c_str(); + emit loadImage(sn); + } + else { + string serialNumberList = (*g_serialNumberList).SerialNumber(g_filteredImages[index]); + QString sn = serialNumberList.c_str(); + emit loadImage(sn); + } + } + } + QApplication::restoreOverrideCursor(); + return; + } + + + /** + * Emits a modifyPoint signal + * + * @param ptItem + */ + void QnetNavTool::editPoint(QListWidgetItem *ptItem) { + + int index = p_listBox->row(ptItem); + if (g_filteredPoints.size() == 0) { + emit modifyPoint(&((*g_controlNetwork)[index])); + } + else { + emit modifyPoint(&((*g_controlNetwork)[g_filteredPoints[index]])); + } + + } + + /** + * Calls the qnet tool for the given control point. + * @internal + * @history 2010-06-03 Jeannie Walldren - Modified "No file selected" warning + * to check whether selected list is empty rather than + * the index of current row. + */ + void QnetNavTool::tie() { + + QList selected = p_listBox->selectedItems(); + if (selected.size() > 1) { + QMessageBox::information((QWidget *)parent(), + "Error","Only one point can be modified at a time"); + return; + } + else if (selected.size() < 1 ){ + QMessageBox::information((QWidget *)parent(), + "Error","No point selected to modify."); + return; + } + int index = p_listBox->row(selected[0]); + if (g_filteredPoints.size() == 0) { + emit modifyPoint(&((*g_controlNetwork)[index])); + } + else { + emit modifyPoint(&((*g_controlNetwork)[g_filteredPoints[index]])); + } + } + + + /** + * Set Ignored=True for selected Points + * + * @author 2008-12-09 Tracie Sucharski + * @internal + * @history 2008-12-29 Jeannie Walldren - Added question box to verify that + * the user wants to set the selected points to + * ignore=true. + * + */ + void QnetNavTool::ignorePoints () { + // do nothing if no cubes are loaded + if (g_serialNumberList == NULL) return; + + int index = p_listBox->currentRow(); + if (index < 0) { + QApplication::restoreOverrideCursor(); + QMessageBox::information((QWidget *)parent(), + "Error","No point selected to ignore"); + return; + } + QList selected = p_listBox->selectedItems(); + switch(QMessageBox::question((QWidget *)parent(), + "Control Network Navigator - Ignore Points", + "You have chosen to set " + + QString::number(selected.size()) + + " point(s) to ignore. Do you want to continue?", + "&Yes", "&No", 0, 0)){ + case 0: // Yes was clicked or Enter was pressed, delete points + QApplication::setOverrideCursor(Qt::WaitCursor); + for (int i=0; irow(selected[i]); + if (g_filteredPoints.size() == 0) { + (*g_controlNetwork)[index].SetIgnore(true); + } + else { + (*g_controlNetwork)[g_filteredPoints[index]].SetIgnore(true); + } + } + QApplication::restoreOverrideCursor(); + emit deletedPoints(); + emit netChanged(); + break; + // case 1: // No was clicked, close window and do nothing to points + } + return; + } + + + + /** + * Delete selected Points from control network + * + * @author 2008-12-09 Tracie Sucharski + * @internal + * @history 2008-12-29 Jeannie Walldren - Added question box to verify that + * the user wants to delete the selected points. + */ + void QnetNavTool::deletePoints () { + // do nothing if no cubes are loaded + if (g_serialNumberList == NULL) return; + + int index = p_listBox->currentRow(); + if (index < 0) { + QApplication::restoreOverrideCursor(); + QMessageBox::information((QWidget *)parent(), + "Error","No point selected to delete"); + return; + } + + QList selected = p_listBox->selectedItems(); + switch(QMessageBox::question((QWidget *)parent(), + "Control Network Navigator - Delete Points", + "You have chosen to delete " + + QString::number(selected.size()) + + " point(s). Do you want to continue?", + "&Yes", "&No", 0, 0)){ + case 0: // Yes was clicked or Enter was pressed, delete points + QApplication::setOverrideCursor(Qt::WaitCursor); + + int editPointIndex = 0; + vector deletedRows; + for (int i=0; itext().toStdString(); + // Keep track of rows #'s that are being deleted. + deletedRows.push_back(p_listBox->row(selected.at(i))); + if (id == p_editPointId) { + editPointIndex = deletedRows[i]; + } + g_controlNetwork->Delete(id); + } + QApplication::restoreOverrideCursor(); + emit deletedPoints(); + emit netChanged(); + break; + // case 1: // No was clicked, close window and do nothing to points + } + return; + } + + + + /** + * Figures out what type of widget the filter was selected for and calls the + * filter method for that filter class + * + * @internal + * @history 2007-06-05 Tracie Sucharski - Use enumerators for the filter + * indices. Comment out overlap/polygon code + * temporarily. + * @history 2008-11-19 Jeannie Walldren - Added WaitCursor (i.e. clock or + * hourglass) to indicate that there is background + * activity while this method is running + * @history 2008-11-26 Tracie Sucharski - Remove all polygon/overlap + * references, this functionality will be qmos. + * @history 2008-12-09 Tracie Sucharski - Added p_filtered indicating whether + * the listBox contains filtered or unfiltered list. + * @history 2009-01-08 Jeannie Walldren - Removed command to clear filtered + * points and images lists + * @history 2009-01-26 Jeannie Walldren - Added filter call for points cube + * name filter. + * + */ + void QnetNavTool::filter() { + + p_filtered = true; + QApplication::setOverrideCursor(Qt::WaitCursor); + p_filter->setEnabled(false); + + QTabWidget *tab = (QTabWidget*)(p_filterStack->currentWidget()); + + // We're dealing with points + if (p_listCombo->currentIndex() == Points) { + PointFilterIndex pointIndex = (PointFilterIndex) tab->currentIndex(); + // We have an errors filter + if (pointIndex == Errors) { + QnetPointErrorFilter *widget = + (QnetPointErrorFilter*)(tab->currentWidget()); + widget->filter(); + } + // We have a point id filter + else if (pointIndex == Id) { + QnetPointIdFilter *widget = + (QnetPointIdFilter*)(tab->currentWidget()); + widget->filter(); + } + // We have a number of images filter + else if (pointIndex == NumberImages) { + QnetPointImagesFilter *widget = + (QnetPointImagesFilter*)(tab->currentWidget()); + widget->filter(); + } + // We have a point type filter + else if (pointIndex == Type) { + QnetPointTypeFilter *widget = + (QnetPointTypeFilter*)(tab->currentWidget()); + widget->filter(); + } + // We have a lat/lon range filter + else if (pointIndex == LatLonRange) { + QnetPointRangeFilter *widget = + (QnetPointRangeFilter*)(tab->currentWidget()); + widget->filter(); + } + // We have a distance filter + else if (pointIndex == Distance) { + QnetPointDistanceFilter *widget = + (QnetPointDistanceFilter*)(tab->currentWidget()); + widget->filter(); + } + // We have a measure filter + else if (pointIndex == MeasureType) { + QnetPointMeasureFilter *widget = + (QnetPointMeasureFilter*)(tab->currentWidget()); + widget->filter(); + } + // We have a goodness of fit filter + else if (pointIndex == GoodnessOfFit) { + QnetPointGoodnessFilter *widget = + (QnetPointGoodnessFilter*)(tab->currentWidget()); + widget->filter(); + } + // We have a cube name filter + else if (pointIndex == CubeName) { + QnetPointCubeNameFilter *widget = + (QnetPointCubeNameFilter*)(tab->currentWidget()); + widget->filter(); + } + } + + // We're dealing with cubes + else if (p_listCombo->currentIndex() == Cubes) { + CubeFilterIndex cubeIndex = (CubeFilterIndex) tab->currentIndex(); + // We have a cube name filter + if (cubeIndex == Name) { + QnetCubeNameFilter *widget = + (QnetCubeNameFilter*)(tab->currentWidget()); + widget->filter(); + } + // We have a point filter + else if (cubeIndex == NumberPoints) { + QnetCubePointsFilter *widget = + (QnetCubePointsFilter*)(tab->currentWidget()); + widget->filter(); + } + // We have a distance filter + else if (cubeIndex == PointDistance) { + QnetCubeDistanceFilter *widget = + (QnetCubeDistanceFilter*)(tab->currentWidget()); + widget->filter(); + } + } + p_filter->setEnabled(true); + QApplication::restoreOverrideCursor(); + return; + } + + /** + * Enable/disable buttons depending on whether Points or Cubes is chosen + * + * @internal + * @history 2008-12-09 Tracie Sucharski - Renamed from enableTie to + * enableButtons. Added ignore and delete buttons. + */ + void QnetNavTool::enableButtons() { + if (p_listCombo->currentIndex() == Points) { + p_tie->setEnabled(true); + p_multiIgnore->setEnabled(true); + p_multiDelete->setEnabled(true); + } + else { + p_tie->setEnabled(false); + p_multiIgnore->setEnabled(false); + p_multiDelete->setEnabled(false); + } + } + + /** + * This slot is connected to the file tool in qnet.cpp. + * It emits a signal that the serial list has been modified so + * the points cube name filter knows to change the list box + * displayed. + * @see QnetPointCubeNameFilter + * @internal + * @history 2009-01-26 Jeannie Walldren - Original version. + */ + void QnetNavTool::resetCubeList(){ + emit serialListModified(); + } + + /** + * This method sets the Navigation Dialog window to shown=true. + * + * @author Jeannie Walldren + * @internal + * @history 2010-07-01 Jeannie Walldren - Original version. + */ + void QnetNavTool::showNavTool(){ + p_navDialog->setShown(true); + } +} + diff --git a/isis/src/qisis/apps/qnet/QnetNavTool.h b/isis/src/qisis/apps/qnet/QnetNavTool.h new file mode 100644 index 0000000000000000000000000000000000000000..259477acce9bcfc58292d3723a6a7577c78ea8d3 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetNavTool.h @@ -0,0 +1,177 @@ +#ifndef QnetNavTool_h +#define QnetNavTool_h + +/** + * @file + * $Date: 2010/07/01 19:04:52 $ $Revision: 1.20 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +#include "ControlPoint.h" +#include "Tool.h" // parent + +// forward declarations +class QComboBox; +class QDialog; +class QLabel; +class QListWidget; +class QListWidgetItem; +class QPushButton; +class QStackedWidget; +class QString; +class QWidget; + +using namespace std; +namespace Qisis { + /** + * @brief Qnet Navigation Tool + * + * @ingroup Visualization Tools + * + * @author Elizabeth Ribelin - 2006-11-07 + * + * @internal + * @history 2007-06-05 Tracie Sucharski - Added enumerators for filter indices + * @history 2008-11-24 Jeannie Walldren - Replace references to PointEdit + * class with ControlPointEdit + * @history 2008-11-26 Jeannie Walldren - Added GoodnessOfFit to + * PointFilterIndex enumeration + * @history 2008-11-26 Tracie Sucharski - Remove all polygon/overlap + * references, this functionality will be qmos + * @history 2008-12-09 Tracie Sucharski - Cleaned up some signal/slot + * connections between QnetTool and QnetNavTool for + * deleting or adding ControlPoints. Also added + * p_filtered indicating whether the listBox contains + * filtered or unfiltered lists. + * @history 2008-12-29 Jeannie Walldren - Added question boxes to the "Delete + * Points" and "Ignore Points" buttons to verify that + * the user wants to delete or ignore the selected + * points + * @history 2008-12-30 Jeannie Walldren - Modified updateEditPoint() method to + * set current item rather than simply highlight the + * new point. Now the point does not have to be clicked + * before "Delete Point(s)" is chosen. Removed "std::" + * in cpp file since we are using std namespace. + * @history 2008-12-31 Jeannie Walldren - Added keyboard shortcuts to + * createNavigationDialog() and createFilters() + * methods. + * @history 2009-01-08 Jeannie Walldren - In resetList(), fill filtered lists + * with all points in control net and all images in + * serial number list so that filters can remove + * unwanted members from this list. In filter() remove + * command to clear these lists so that we may filter + * filtered lists rather than start with the entire + * points/image list each time it is called. + * @history 2009-01-26 Jeannie Walldren - The following changes were made in + * order to create a Cube Names filter on the Points + * list: Added CubeNames to PointFilterIndex + * enumerated values. Added resetCubeList() slot and + * serialListModified() signal. Modified filter() and + * createFilters(). + * @history 2010-06-02 Jeannie Walldren - Changed tab labels from "Point + * Type" to "Point Properties" and "Measure Type(s)" + * to "Measure Properties" for better accuracy. Also + * updated "What's This?" description for "Measure + * Properties". + * @history 2010-06-03 Jeannie Walldren - Initialized pointers to null in + * constructor. Modified tie() and load() methods. + * @history 2010-07-01 Jeannie Walldren - Added showNavTool() slot method. + * This method is connected to the QnetTool in order to + * reopen the navigator dialog whenever the Tie tool + * button or "Show Nav Tool" button are activated. + * Replaced #includes with forward class declarations + * and moved #include to .cpp file. + * + * + */ + class QnetNavTool : public Tool { + Q_OBJECT + + public: + QnetNavTool (QWidget *parent); + + enum FilterIndex { + Points, + Cubes + }; + enum PointFilterIndex { + Errors, + Id, + NumberImages, + Type, + LatLonRange, + Distance, + MeasureType, + GoodnessOfFit, + CubeName + }; + enum CubeFilterIndex { + Name, + NumberPoints, + PointDistance + }; + + + public slots: + void resetList(); + void refreshList(); + void updateEditPoint(string pointId); + + private slots: + void load(); + void tie(); + void filter(); + void editPoint(QListWidgetItem *ptItem); + void filterList(); + void resetFilter(); + void enableButtons(); + void ignorePoints(); + void deletePoints(); + void resetCubeList(); + void showNavTool(); + + signals: + void loadPoint (Isis::ControlPoint *); + void loadImage (const QString &); + void modifyPoint(Isis::ControlPoint *); + void ignoredPoints(); + void deletedPoints(); + void netChanged(); + void serialListModified(); + + private: + void createNavigationDialog(QWidget *parent); + void createFilters(); + + + QDialog *p_navDialog; + QPushButton *p_filter; + bool p_filtered; + QPushButton *p_tie; + QPushButton *p_multiIgnore; + QPushButton *p_multiDelete; + QStackedWidget *p_filterStack; + QComboBox *p_listCombo; + QListWidget *p_listBox; + QLabel *p_filterCountLabel; + int p_filterCount; + + string p_editPointId; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetNewMeasureDialog.cpp b/isis/src/qisis/apps/qnet/QnetNewMeasureDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f1bd2b3f9158912b3af832d51469ec3e01b9c33 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetNewMeasureDialog.cpp @@ -0,0 +1,95 @@ +#include + +#include + +#include "QnetNewMeasureDialog.h" +#include "SerialNumberList.h" + +#include "qnet.h" + +using namespace Qisis::Qnet; +using namespace std; + +namespace Qisis { + /** + * Contructor. + * + * @param parent The parent widget for the + * cube points filter + * @internal + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null. + * + */ + QnetNewMeasureDialog::QnetNewMeasureDialog (QWidget *parent) : QDialog (parent) { + fileList = NULL; + p_okButton = NULL; + p_pointFiles = NULL; + + + QLabel *listLabel = new QLabel("Select Files:"); + + fileList = new QListWidget; + fileList->setSelectionMode(QAbstractItemView::ExtendedSelection); + + // Create OK & Cancel buttons + p_okButton = new QPushButton("OK"); + //p_okButton->setEnabled(false); + QPushButton *cancelButton = new QPushButton("Cancel"); + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addWidget(p_okButton); + buttonLayout->addWidget(cancelButton); + + connect(p_okButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->addWidget(listLabel); + vLayout->addWidget(fileList); + vLayout->addLayout(buttonLayout); + + setLayout(vLayout); + setWindowTitle("Add Measures to ControlPoint"); + + } + + + /** + * @internal + * @history 2010-06-03 Jeannie Walldren - Removed "std::" + * since "using namespace std" + */ + void QnetNewMeasureDialog::SetFiles (const Isis::ControlPoint &point, + vector &pointFiles) { + // TODO:: make pointFiles const??? + p_pointFiles = &pointFiles; + Isis::ControlPoint pt = point; + + // Add all files to list , selecting those in pointFiles which are + // those files which contain the point. + for (int i=0; iSize(); i++) { + // Don't add if already in this point + string sn = g_serialNumberList->SerialNumber(i); + if (pt.HasSerialNumber(sn)) continue; + //if (point.HasSN(sn)) continue; + + QListWidgetItem *item = new QListWidgetItem(fileList); + string tempFilename = g_serialNumberList->Filename(i); + item->setText(QString(tempFilename.c_str())); + vector::iterator pos; + pos = std::find(p_pointFiles->begin(),p_pointFiles->end(), + g_serialNumberList->Filename(i)); + if (pos != p_pointFiles->end()) { + fileList->setItemSelected(item,true); + } + } + + } + + + void QnetNewMeasureDialog::enableOkButton (const QString &text) { + p_okButton->setEnabled(!text.isEmpty()); + } + + +} diff --git a/isis/src/qisis/apps/qnet/QnetNewMeasureDialog.h b/isis/src/qisis/apps/qnet/QnetNewMeasureDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..1dad937026914e557209459ebec6db2e2af68e8b --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetNewMeasureDialog.h @@ -0,0 +1,50 @@ +#ifndef QnetNewMeasureDialog_h +#define QnetNewMeasureDialog_h + +#include + +class QLabel; +class QListWidget; +class QPushButton; + +#include "ControlPoint.h" + +#include + +using namespace std; +namespace Qisis { + /** + * + * @internal + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null in constructor. Removed "std::" + * since "using namespace std" in + * header and .cpp files. + * + */ + + class QnetNewMeasureDialog : public QDialog { + Q_OBJECT + + public: + QnetNewMeasureDialog (QWidget *parent=0); + void SetFiles (const Isis::ControlPoint &point, + vector &pointFiles); + + QListWidget *fileList; + + private: + + QPushButton *p_okButton; + + vector *p_pointFiles; + + private slots: + void enableOkButton(const QString &text); + + }; +}; + +#endif + + diff --git a/isis/src/qisis/apps/qnet/QnetNewPointDialog.cpp b/isis/src/qisis/apps/qnet/QnetNewPointDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..757650e80bf9d6a616cd5b764319d7360b7e1312 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetNewPointDialog.cpp @@ -0,0 +1,115 @@ +#include +#include + +#include + +#include "QnetNewPointDialog.h" +#include "SerialNumberList.h" + +#include "qnet.h" + +using namespace Qisis::Qnet; +using namespace std; + +namespace Qisis { + // initialize static variable + QString QnetNewPointDialog::lastPtIdValue = ""; + + /** + * QnetNewPointDialog constructor + * @param parent The parent widget for the + * cube points filter + * + * @internal + * @history 2008-11-26 Jeannie Walldren - Set lastPointIdValue + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null. + * + */ + QnetNewPointDialog::QnetNewPointDialog (QWidget *parent) : QDialog (parent) { + + ptIdValue = NULL; + fileList = NULL; + p_ptIdLabel = NULL; + p_okButton = NULL; + p_pointFiles = NULL; + + p_ptIdLabel = new QLabel("Point ID:"); + ptIdValue = new QLineEdit; + p_ptIdLabel->setBuddy(ptIdValue); + ptIdValue->setText(lastPtIdValue); + ptIdValue->selectAll(); + connect(ptIdValue,SIGNAL(textChanged(const QString &)), + this,SLOT(enableOkButton(const QString &))); + + QLabel *listLabel = new QLabel("Select Files:"); + + fileList = new QListWidget; + fileList->setSelectionMode(QAbstractItemView::ExtendedSelection); + + // Create OK & Cancel buttons + p_okButton = new QPushButton("OK"); + p_okButton->setEnabled(false); + QPushButton *cancelButton = new QPushButton("Cancel"); + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addWidget(p_okButton); + buttonLayout->addWidget(cancelButton); + + connect(p_okButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + QHBoxLayout *ptIdLayout = new QHBoxLayout; + ptIdLayout->addWidget(p_ptIdLabel); + ptIdLayout->addWidget(ptIdValue); + + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->addLayout(ptIdLayout); + vLayout->addWidget(listLabel); + vLayout->addWidget(fileList); + vLayout->addLayout(buttonLayout); + + setLayout(vLayout); + setWindowTitle("Create New ControlPoint"); + + } + + /** + * @internal + * @history 2010-06-03 Jeannie Walldren - Removed "std::" + * since "using namespace std" + */ + void QnetNewPointDialog::SetFiles (vector &pointFiles) { + // TODO:: make pointFiles const??? + p_pointFiles = &pointFiles; + + // Add all files to list , selecting those in pointFiles which are + // those files which contain the point. + for (int i=0; iSize(); i++) { + QListWidgetItem *item = new QListWidgetItem(fileList); + string tempFilename = g_serialNumberList->Filename(i); + item->setText(QString(tempFilename.c_str())); + vector::iterator pos; + pos = std::find(p_pointFiles->begin(),p_pointFiles->end(), + g_serialNumberList->Filename(i)); + if (pos != p_pointFiles->end()) { + fileList->setItemSelected(item,true); + } + } + + } + + + /** + * + * @param text + * @internal + * @history 2008-11-26 Jeannie Walldren - Set lastPointIdValue + * to the p_ptIdValue + */ + void QnetNewPointDialog::enableOkButton (const QString &text) { + QnetNewPointDialog::lastPtIdValue = ptIdValue->text(); + p_okButton->setEnabled(!text.isEmpty()); + } + + +} diff --git a/isis/src/qisis/apps/qnet/QnetNewPointDialog.h b/isis/src/qisis/apps/qnet/QnetNewPointDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..f52a16fe6517f5e6a221563b74acb8a686d1e1b6 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetNewPointDialog.h @@ -0,0 +1,54 @@ +#ifndef QnetNewPointDialog_h +#define QnetNewPointDialog_h + +#include +#include + +class QLabel; +class QLineEdit; +class QListWidget; +class QPushButton; + +#include +using namespace std; + +namespace Qisis { + /** + * @internal + * @history 2008-11-26 Jeannie Walldren - Added functionality + * to show the last Point ID entered + * into a new point dialog box. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * in constructor. Removed "std::" in + * header and .cpp files. + */ + class QnetNewPointDialog : public QDialog { + Q_OBJECT + + + public: + static QString lastPtIdValue; + + QnetNewPointDialog (QWidget *parent=0); + + QLineEdit *ptIdValue; + void SetFiles (vector &pointFiles); + + QListWidget *fileList; + + private: + + QLabel *p_ptIdLabel; + QPushButton *p_okButton; + + vector *p_pointFiles; + + private slots: + void enableOkButton(const QString &text); + + }; +}; + +#endif + + diff --git a/isis/src/qisis/apps/qnet/QnetPointCubeNameFilter.cpp b/isis/src/qisis/apps/qnet/QnetPointCubeNameFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10ae8a331be5a32cf1443d8fd1c91c27aa96696c --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointCubeNameFilter.cpp @@ -0,0 +1,131 @@ +#include +#include +#include "QnetPointCubeNameFilter.h" +#include "QnetNavTool.h" +#include "ControlNet.h" +#include "SerialNumberList.h" +#include "qnet.h" + +using namespace Qisis::Qnet; +using namespace std; + +namespace Qisis { + /** + * Contructor for the Point Cube Name filter. It creates the + * Cube Name filter window found in the navtool + * + * @param parent The parent widget for the point type + * filter + * @internal + * @history 2010-06-03 Jeannie Walldren - Initialized pointer + * to null + * + */ + QnetPointCubeNameFilter::QnetPointCubeNameFilter (QWidget *parent) : QnetFilter(parent) { + p_listBox = NULL; + + QLabel *label = new QLabel ("Select cube(s) from the list:"); + p_listBox = new QListWidget(); + p_listBox->setSelectionMode(QAbstractItemView::ExtendedSelection); + //connect (p_listBox,SIGNAL(itemDoubleClicked(QListWidgetItem *)), + // this,SLOT(editPoint(QListWidgetItem *))); + + // Create the layout and add the components to it + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->addWidget(label,0,0); + gridLayout->addWidget(p_listBox,1,0); + this->setLayout(gridLayout); + //if (g_serialNumberList != NULL) createCubeList(); + return; + } + + /** + * @brief Method overwrites parent method. + * This method keeps all points that contain at least one + * measure whose CubeName is within the range specified by the + * user. + * + * @internal + * @history 2009-01-26 Jeannie Walldren - Original Version + */ + void QnetPointCubeNameFilter::filter() { + // Make sure there is a control net loaded + if (g_controlNetwork == NULL) { + QMessageBox::information((QWidget *)parent(), + "Error","No points to filter"); + return; + } + + if (g_serialNumberList == NULL) { + QMessageBox::information((QWidget *)parent(), + "Error","No cubes to filter"); + return; + } + + // load??? + int index = p_listBox->currentRow(); + if (index < 0) { + QApplication::restoreOverrideCursor(); + QMessageBox::information((QWidget *)parent(), + "Error","No file selected to filter"); + return; + } + + QList selected = p_listBox->selectedItems(); + + for (int i=0; irow(selected[i]); + string selectedCubeSerNum = (*g_serialNumberList).SerialNumber(index); + + // Loop through each value of the filtered points list + // checking the types of each control measure for each + // of the control points. If no measures match, we remove + // it from the filtered list + // Loop in reverse order since removal list of elements affects index number + for (int i = g_filteredPoints.size()-1; i >= 0; i--) { + Isis::ControlPoint cp = (*g_controlNetwork)[g_filteredPoints[i]]; + int numMeasNotMatching = 0; + for (int j=0; jsetCurrentRow(-1); + p_listBox->clear(); + + for (int i = 0; i < g_serialNumberList->Size(); i++) { + Isis::Filename filename = Isis::Filename(g_serialNumberList->Filename(i)); + string tempFilename = filename.Name(); + p_listBox->insertItem(i,tempFilename.c_str()); + } + } +} + + + + + diff --git a/isis/src/qisis/apps/qnet/QnetPointCubeNameFilter.h b/isis/src/qisis/apps/qnet/QnetPointCubeNameFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..f657351dadf9c9ab684764fea3fd3702a406a23f --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointCubeNameFilter.h @@ -0,0 +1,63 @@ +#ifndef QnetPointCubeNameFilter_h +#define QnetPointCubeNameFilter_h +/** + * @file + * $Date: 2010/06/03 20:13:53 $ + * $Revision: 1.2 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + + +#include +#include +#include +#include +#include +#include +#include "QnetFilter.h" + + +namespace Qisis { + /** + * Defines the Cube Name filter for the QnetNavTool's + * Points section. The user must choose from a list of cubes. + * This class is designed to remove points from the current + * filtered list if no measures match the chosen image. + * + * @author 2009-01-26 Jeannie Walldren + * @internal + * @history 2009-01-26 Jeannie Walldren - Original Version + * @history 2010-06-03 Jeannie Walldren - Initialized pointer + * to null in constructor + */ + + class QnetPointCubeNameFilter : public QnetFilter { + Q_OBJECT + + public: + QnetPointCubeNameFilter (QWidget *parent=0); + virtual void filter(); + + public slots: + void createCubeList(); + + private: + QListWidget *p_listBox; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetPointDistanceFilter.cpp b/isis/src/qisis/apps/qnet/QnetPointDistanceFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..53636756075b8a52244f4c2345b4bc48044798ea --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointDistanceFilter.cpp @@ -0,0 +1,164 @@ +#include +#include +#include +#include "QnetPointDistanceFilter.h" +#include "QnetNavTool.h" +#include "ControlNet.h" +#include "SerialNumberList.h" +#include "Camera.h" + +#include "qnet.h" + +using namespace Qisis::Qnet; + +namespace Qisis { + /** + * Contructor for the Point Distance filter. It creates the + * Distance filter window found in the navtool + * + * @param parent The parent widget for the point distance + * filter + * @internal + * @history 2008-11-26 Jeannie Walldren - Clarified label for + * distance filter value. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null. + * + * + */ + QnetPointDistanceFilter::QnetPointDistanceFilter (QWidget *parent) : QnetFilter(parent) { + p_lineEdit = NULL; + + // Create the labels and widgets to be added to the main window + QLabel *label = new QLabel("Filter points that are within given distance of some other point."); + QLabel *lessThan = new QLabel("Minimum distance is less than"); + p_lineEdit = new QLineEdit(); + QLabel *meters = new QLabel("meters"); + QLabel *pad = new QLabel(); + + // Create the layout and add the widgets to the window + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->addWidget(label,0,0,1,2); + gridLayout->addWidget(lessThan,1,0); + gridLayout->addWidget(p_lineEdit,1,1); + gridLayout->addWidget(meters,1,2); + gridLayout->addWidget(pad,2,0); + gridLayout->setRowStretch(2,50); + this->setLayout(gridLayout); + } + + /** + * Filters a list of points for points that are less than the user entered + * distance from another point in the control net. The filtered list will + * appear in the navtools point list display. + * @internal + * @history 2008-11-26 Jeannie Walldren - Modified code to + * handle case in which the lat/lon of + * the point is Null. In this event, + * the Camera class will be used to + * determine lat/lon/rad for the + * reference measure or for the first + * measure. Changed variable names for + * clarity. Adjusted inner "for" loop + * to reduce number of iterations. + * @history 2009-01-08 Jeannie Walldren - Modified to replace + * existing filtered list with a subset + * of that list. Previously, a new + * filtered list was created from the + * entire control net each time. + */ + void QnetPointDistanceFilter::filter() { + // Make sure we have a control network to filter through + if (g_controlNetwork == NULL) { + QMessageBox::information((QWidget *)parent(), + "Error","No points to filter"); + return; + } + + // Make sure the user entered a filtering value + if (p_lineEdit->text() == "") { + QMessageBox::information((QWidget *)parent(), + "Error","Distance value must be entered"); + return; + } + // Get the user entered value for filtering + int userEntered = p_lineEdit->text().toInt(); + + // create temporary QList to contain new filtered images + QList temp; + // Loop through each value of the filtered points list + // Loop in reverse order for consistency with other filter methods + for (int i = g_filteredPoints.size()-1; i >= 0; i--) { + Isis::ControlPoint cp1 = (*g_controlNetwork)[g_filteredPoints[i]]; + // Get necessary info from the control point for later use + double rad = cp1.Radius(); + double lat1 = cp1.UniversalLatitude(); + double lon1 = cp1.UniversalLongitude(); + + // If no lat/lon for this point, use lat/lon of first measure + if ((lat1 == Isis::Null) || (lon1 == Isis::Null)) { + Isis::Camera *cam1; + Isis::ControlMeasure cm1; + // first try to get info from reference measure, if one exists + if (cp1.HasReference()) { + cm1 = cp1[cp1.ReferenceIndex()]; + } + // if no reference measure exists, use the first control measure of the point + else cm1 = cp1[0]; + int camIndex1 = g_serialNumberList->SerialNumberIndex(cm1.CubeSerialNumber()); + cam1 = g_controlNetwork->Camera(camIndex1); + cam1->SetImage(cm1.Sample(),cm1.Line()); + rad = cam1->LocalRadius(); + lat1 = cam1->UniversalLatitude(); + lon1 = cam1->UniversalLongitude(); + } + // Loop through each control point, comparing it to the initial point + // from the filtered list + for (int j = 0; j < g_controlNetwork->Size(); j++) { + if (j == g_filteredPoints[i]) { + // cp1 = cp2, go to next value of j + continue; + } + Isis::ControlPoint cp2 = (*g_controlNetwork)[j]; + double lat2 = cp2.UniversalLatitude(); + double lon2 = cp2.UniversalLongitude(); + + // If no lat/lon for this point, use lat/lon of first measure + if ((lat2 == Isis::Null) || (lon2 == Isis::Null)) { + Isis::Camera *cam2; + Isis::ControlMeasure cm2; + // first try to get info from reference measure, if one exists + if (cp2.HasReference()) { + cm2 = cp2[cp2.ReferenceIndex()]; + } + // if no reference measure exists, use the first control measure of the point + else cm2 = cp2[0]; + int camIndex2 = g_serialNumberList->SerialNumberIndex(cm2.CubeSerialNumber()); + cam2 = g_controlNetwork->Camera(camIndex2); + cam2->SetImage(cm2.Sample(),cm2.Line()); + lat2 = cam2->UniversalLatitude(); + lon2 = cam2->UniversalLongitude(); + } + // Get the distance from the camera class + double dist = Isis::Camera::Distance(lat1,lon1,lat2,lon2,rad); + // If the distance found is less than the input number, add the + // control points' indices to the new filtered points list + if (dist < userEntered) { + if(!temp.contains(g_filteredPoints[i])) { + temp.push_back(g_filteredPoints[i]); + } + break; + } + } + } + + // Sort QList of filtered points before displaying list to user + qSort(temp.begin(), temp.end()); + // replace existing filter list with this one + g_filteredPoints = temp; + + // Tell the nav tool that a list has been filtered and needs to be updated + emit filteredListModified(); + return; + } +} diff --git a/isis/src/qisis/apps/qnet/QnetPointDistanceFilter.h b/isis/src/qisis/apps/qnet/QnetPointDistanceFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..f4f538ca159002e88a8f8e9f279513b5e1598594 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointDistanceFilter.h @@ -0,0 +1,47 @@ +#ifndef QnetPointDistanceFilter_h +#define QnetPointDistanceFilter_h + +#include +#include +#include +#include +#include +#include +#include "QnetFilter.h" + + +namespace Qisis { + /** + * Defines the Distance filter for the QnetNavTool's Points + * section. The user must enter a Minimum Distance value. This + * class is designed to remove points from the current filtered + * list whose distance from all other points in the control net + * is greater than or equal to the given value. + * + * @internal + * @history 2008-11-26 Jeannie Walldren - Changed variable + * names and labels for clarity. + * Modified filter() to handle case in + * which the lat/lon of the point is + * Null. And to increase efficiency. + * @history 2009-01-08 Jeannie Walldren - Modified filter() + * method to create new filtered list + * from points in the existing filtered + * list. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null in constructor. + * + */ + class QnetPointDistanceFilter : public QnetFilter { + Q_OBJECT + + public: + QnetPointDistanceFilter (QWidget *parent=0); + virtual void filter(); + + private: + QLineEdit *p_lineEdit; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetPointErrorFilter.cpp b/isis/src/qisis/apps/qnet/QnetPointErrorFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d25b18321dc6d9fae6d73c69925411a4433de17b --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointErrorFilter.cpp @@ -0,0 +1,170 @@ +#include +#include +#include "QnetPointErrorFilter.h" +#include "QnetNavTool.h" +#include "ControlNet.h" +#include "SerialNumberList.h" + +#include "qnet.h" + +using namespace Qisis::Qnet; + +namespace Qisis { + /** + * Contructor for the Point Error filter. It + * creates the Error filter window found in the + * navtool + * + * @param parent The parent widget for the point + * error filter + * + * @internal + * @history 2008-08-06 Tracie Sucharski - Added functionality + * of filtering range of errors. + * @history 2010-06-02 Jeannie Walldren - Modify default + * settings of checkboxes and line edits + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null. + * + */ + QnetPointErrorFilter::QnetPointErrorFilter (QWidget *parent) : QnetFilter(parent) { + p_lessThanCB = NULL; + p_greaterThanCB = NULL; + p_lessErrorEdit = NULL; + p_greaterErrorEdit = NULL; + + // Create the components for the filter window + QLabel *label = new QLabel("Filter bundle-adjustment error"); + p_lessThanCB = new QCheckBox("Less than (undercontrolled)"); + p_lessErrorEdit = new QLineEdit(); + p_greaterThanCB = new QCheckBox("Greater than (overcontrolled)"); + p_greaterErrorEdit = new QLineEdit(); + QLabel *pixels = new QLabel ("pixels"); + QLabel *pad = new QLabel(); + + p_lessThanCB->setChecked(false); + p_lessErrorEdit->setEnabled(false); + p_greaterThanCB->setChecked(true); + p_greaterErrorEdit->setEnabled(true); + + connect(p_lessThanCB,SIGNAL(clicked()),this,SLOT(clearEdit())); + connect(p_greaterThanCB,SIGNAL(clicked()),this,SLOT(clearEdit())); + + // Create the layout and add the components to it + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->addWidget(label,0,0,1,2); + gridLayout->addWidget(p_lessThanCB,1,0,1,2); + gridLayout->addWidget(p_lessErrorEdit,2,0); + gridLayout->addWidget(pixels,2,1); + gridLayout->addWidget(p_greaterThanCB,3,0,1,2); + gridLayout->addWidget(p_greaterErrorEdit,4,0); + gridLayout->addWidget(pixels,4,1); + gridLayout->addWidget(pad,5,0); + gridLayout->setRowStretch(5,50); + this->setLayout(gridLayout); + } + + /** + * Filters a list of points for points that have less than or greater + * than the entered bundle adjust error values. The filtered list will + * appear in the navtools point list display. + * + * @internal + * @history 2007-06-05 Tracie Sucharski - Look at ControlPoint::MaximumError + * instead of ControlPoint::AverageError + * @history 2008-08-06 Tracie Sucharski - Added functionality of filtering + * range of errors. + * @history 2009-01-08 Jeannie Walldren - Modified to remove + * new filter points from the existing + * filtered list. Previously, a new + * filtered list was created from the + * entire control net each time. + */ + void QnetPointErrorFilter::filter() { + // Make sure we have a list of control points to filter + if (g_controlNetwork == NULL) { + QMessageBox::information((QWidget *)parent(), + "Error","No points to filter"); + return; + } + + // Make sure the user entered a value to use in the filtering + double lessNum = -1.; + if (p_lessThanCB->isChecked() && p_lessErrorEdit->text() == "") { + QMessageBox::information((QWidget *)parent(), + "Error","Error value must be entered"); + return; + } + double greaterNum = -1.; + if (p_greaterThanCB->isChecked() && p_greaterErrorEdit->text() == "") { + QMessageBox::information((QWidget *)parent(), + "Error","Error value must be entered"); + return; + } + + // Get the user entered filtering value + lessNum = p_lessErrorEdit->text().toDouble(); + greaterNum = p_greaterErrorEdit->text().toDouble(); + + // Loop through each value of the filtered points list comparing the error of its + // corresponding point with error with the user entered value and remove it from + // the filtered list if it is outside the filtering range + // Loop in reverse order since removal list of elements affects index number + for (int i = g_filteredPoints.size()-1; i >= 0; i--) { + Isis::ControlPoint cp = (*g_controlNetwork)[g_filteredPoints[i]]; + if (p_lessThanCB->isChecked() && p_greaterThanCB->isChecked()) { + if ( (cp.MaximumError() < lessNum) && + (cp.MaximumError() > greaterNum) ) { + continue; + } + else g_filteredPoints.removeAt(i); + } + else if (p_lessThanCB->isChecked()) { + if (cp.MaximumError() < lessNum) { + continue; + } + else g_filteredPoints.removeAt(i); + } + else if (p_greaterThanCB->isChecked()) { + if (cp.MaximumError() > greaterNum) { + continue; + } + else g_filteredPoints.removeAt(i); + } + } + // Tell the navtool that a list has been filtered and it needs to update + emit filteredListModified(); + return; + } + + + /** + * Clears and disables the corresponding line edit if the "less + * than" or "greater than" checkBox is "unchecked". + * + * @internal + * @history 2008-08-06 Tracie Sucharski - New method for + * added functionality filtering range + * of errors. + * @history 2010-06-02 Jeannie Walldren - Disable the line + * edit so the user can not enter a value unless the + * corresponding box is checked. + */ + void QnetPointErrorFilter::clearEdit() { + + if (p_lessThanCB->isChecked()) { + p_lessErrorEdit->setEnabled(true); + } + else { + p_lessErrorEdit->clear(); + p_lessErrorEdit->setEnabled(false); + } + if (p_greaterThanCB->isChecked()) { + p_greaterErrorEdit->setEnabled(true); + } + else { + p_greaterErrorEdit->clear(); + p_greaterErrorEdit->setEnabled(false); + } + } +} diff --git a/isis/src/qisis/apps/qnet/QnetPointErrorFilter.h b/isis/src/qisis/apps/qnet/QnetPointErrorFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..e85b1022753a3507920dae63396ff54b01a6f141 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointErrorFilter.h @@ -0,0 +1,76 @@ +#ifndef QnetPointErrorFilter_h +#define QnetPointErrorFilter_h +/** + * @file + * $Date: 2010/06/03 20:13:53 $ + * $Revision: 1.6 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + + +#include +#include +#include +#include +#include +#include +#include +#include "QnetFilter.h" + + +namespace Qisis { + /** + * Defines the Error filter for the QnetNavTool's Points + * section. The user may enter values for Less Than and/or + * Greater Than. This class is designed to remove points from + * the current filtered list that lie outside of the given + * range. + * + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified filter() + * method to remove new filter points + * from the existing filtered list. + * @history 2010-06-02 Jeannie Walldren - Modified clearEdit() + * method to disable the line edit if + * the corresponding check box is not + * checked. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null in constructor. + * + * + */ + class QnetPointErrorFilter : public QnetFilter { + Q_OBJECT + + public: + QnetPointErrorFilter (QWidget *parent=0); + virtual void filter(); + + public slots: + + private: + QCheckBox *p_lessThanCB; + QCheckBox *p_greaterThanCB; + QLineEdit *p_lessErrorEdit; + QLineEdit *p_greaterErrorEdit; + + private slots: + void clearEdit(); + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetPointGoodnessFilter.cpp b/isis/src/qisis/apps/qnet/QnetPointGoodnessFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..732c8339b88793c94d6fc0071e38ec7f393453e5 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointGoodnessFilter.cpp @@ -0,0 +1,159 @@ +#include +#include +#include "QnetPointGoodnessFilter.h" +#include "QnetNavTool.h" +#include "ControlNet.h" +#include "SerialNumberList.h" +#include "qnet.h" + +using namespace Qisis::Qnet; + +namespace Qisis { + /** + * Contructor for the Point Goodness of Fit filter. It creates + * the Goodness of Fit filter window found in the navtool + * + * @param parent The parent widget for the point type + * filter + * @internal + * @history 2010-06-02 Jeannie Walldren - Modify default + * settings of checkboxes and line edits + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null in constructor. + * + */ + QnetPointGoodnessFilter::QnetPointGoodnessFilter (QWidget *parent) : QnetFilter(parent) { + p_lessThanCB = NULL; + p_greaterThanCB = NULL; + p_maxValueEdit = NULL; + p_minValueEdit = NULL; + + // Create the components for the filter window + p_lessThanCB = new QCheckBox("Less than "); + p_maxValueEdit = new QLineEdit(); + p_greaterThanCB = new QCheckBox("Greater than "); + p_minValueEdit = new QLineEdit(); + QLabel *pad = new QLabel(); + + p_lessThanCB->setChecked(false); + p_maxValueEdit->setEnabled(false); + p_greaterThanCB->setChecked(false); + p_minValueEdit->setEnabled(false); + + connect(p_lessThanCB,SIGNAL(clicked()),this,SLOT(clearEdit())); + connect(p_greaterThanCB,SIGNAL(clicked()),this,SLOT(clearEdit())); + + // Create the layout and add the components to it + QGridLayout *gridLayout = new QGridLayout(); + //gridLayout->addWidget(label,0,0,1,2); + gridLayout->addWidget(p_lessThanCB,1,0,1,2); + gridLayout->addWidget(p_maxValueEdit,2,0); + gridLayout->addWidget(p_greaterThanCB,3,0,1,2); + gridLayout->addWidget(p_minValueEdit,4,0); + gridLayout->addWidget(pad,5,0); + gridLayout->setRowStretch(5,50); + this->setLayout(gridLayout); + } + + /** + * @brief Method overwrites parent method. + * This method keeps all points that contain at least one + * measure whose Goodness of Fit is within the range specified + * by the user. + * + * @internal + * @history 2008-11-26 Jeannie Walldren - Original Version + * @history 2009-01-08 Jeannie Walldren - Modified to remove + * new filter points from the existing + * filtered list. Previously, a new + * filtered list was created from the + * entire control net each time. + */ + void QnetPointGoodnessFilter::filter() { + // Make sure there is a control net loaded + if (g_controlNetwork == NULL) { + QMessageBox::information((QWidget *)parent(), + "Error","No points to filter"); + return; + } + + // Make sure the user entered a value to use in the filtering + if (p_lessThanCB->isChecked() && p_maxValueEdit->text() == "") { + QMessageBox::information((QWidget *)parent(), + "Error","Maximum Goodness of Fit value must be entered"); + return; + } + if (p_greaterThanCB->isChecked() && p_minValueEdit->text() == "") { + QMessageBox::information((QWidget *)parent(), + "Error","Minimum Goodness of Fit value must be entered"); + return; + } + + // Get the user entered filtering value + double maxValue = p_maxValueEdit->text().toDouble(); + double minValue = p_minValueEdit->text().toDouble(); + + // Loop through each value of the filtered points list + // Loop in reverse order since removal list of elements affects index number + for (int i = g_filteredPoints.size()-1; i >= 0; i--) { + Isis::ControlPoint cp = (*g_controlNetwork)[g_filteredPoints[i]]; + int numMeasOutsideRange = 0; + // Loop through each measure of the point at this index of the control net + for (int j = 0; j < cp.Size(); j++) { + + if (cp[j].GoodnessOfFit() == Isis::Null) { + numMeasOutsideRange++; + } + else if (p_lessThanCB->isChecked() && p_greaterThanCB->isChecked()) { + if (cp[j].GoodnessOfFit() < maxValue && + cp[j].GoodnessOfFit() > minValue) break; + else numMeasOutsideRange++; + } + else if (p_lessThanCB->isChecked()) { + if (cp[j].GoodnessOfFit() < maxValue) break; + else numMeasOutsideRange++; + } + else if (p_greaterThanCB->isChecked()) { + if (cp[j].GoodnessOfFit() > minValue) break; + else numMeasOutsideRange++; + } + } + // if no measures are within the range, remove from filter list + if (cp.Size() == numMeasOutsideRange) { + g_filteredPoints.removeAt(i); + } + } + + // Tell the navtool that a list has been filtered and it needs to update + emit filteredListModified(); + return; + } + /** + * Clears and disables the corresponding line edit if the "less + * than" or "greater than" checkBox is "unchecked". Method + * overrides parent method. + * + * @internal + * @history 2010-06-02 Jeannie Walldren - Disable the line + * edit so the user can not enter a value unless the + * corresponding box is checked. + * + */ + void QnetPointGoodnessFilter::clearEdit() { + + if (p_lessThanCB->isChecked()) { + p_maxValueEdit->setEnabled(true); + } + else { + p_maxValueEdit->clear(); + p_maxValueEdit->setEnabled(false); + } + if (p_greaterThanCB->isChecked()) { + p_minValueEdit->setEnabled(true); + } + else { + p_minValueEdit->clear(); + p_minValueEdit->setEnabled(false); + } + } +} diff --git a/isis/src/qisis/apps/qnet/QnetPointGoodnessFilter.h b/isis/src/qisis/apps/qnet/QnetPointGoodnessFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..f699c8eb8798e4300fc460d9f63ba2a89c65f7f9 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointGoodnessFilter.h @@ -0,0 +1,77 @@ +#ifndef QnetPointGoodnessFilter_h +#define QnetPointGoodnessFilter_h +/** + * @file + * $Date: 2010/06/03 20:13:53 $ + * $Revision: 1.4 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + + +#include +#include +#include +#include +#include +#include +#include +#include "QnetFilter.h" + + +namespace Qisis { + /** + * Defines the Goodness of Fit filter for the QnetNavTool's + * Points section. The user may enter Less Than and Greater + * Than. This class is designed to remove points from the + * current filtered list if all measures have goodness of fit + * values that lie outside the given range. + * + * @author 2008-11-26 Jeannie Walldren + * @internal + * @history 2008-11-26 Jeannie Walldren - Original Version + * @history 2009-01-08 Jeannie Walldren - Modified filter() + * method to remove new filter points + * from the existing filtered list. + * @history 2010-06-02 Jeannie Walldren - Modified clearEdit() + * method to disable the line edit if + * the corresponding check box is not + * checked. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null in constructor. + */ + + class QnetPointGoodnessFilter : public QnetFilter { + Q_OBJECT + + public: + QnetPointGoodnessFilter (QWidget *parent=0); + virtual void filter(); + + public slots: + + private: + QCheckBox *p_lessThanCB; + QCheckBox *p_greaterThanCB; + QLineEdit *p_maxValueEdit; + QLineEdit *p_minValueEdit; + + private slots: + void clearEdit(); + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetPointIdFilter.cpp b/isis/src/qisis/apps/qnet/QnetPointIdFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9178ef24fc85cfd39b3f018d8702e30830ca7b9 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointIdFilter.cpp @@ -0,0 +1,85 @@ +#include +#include +#include +#include "QnetPointIdFilter.h" +#include "QnetNavTool.h" +#include "ControlNet.h" +#include "SerialNumberList.h" + +#include "qnet.h" + +using namespace Qisis::Qnet; +using namespace std; + +namespace Qisis { + /** + * Contructor for the Cube Image filter. It creates the Cube Name filter window + * found in the navtool + * + * @param parent The parent widget for the + * cube points filter + * @internal + * @history 2010-06-03 Jeannie Walldren - Initialized pointer + * to null. + * + */ + QnetPointIdFilter::QnetPointIdFilter (QWidget *parent) : QnetFilter(parent) { + p_pointIdEdit = NULL; + + // Create the components for the filter window + QLabel *label = new QLabel("Filter by Point ID (Regular Expressions)"); + p_pointIdEdit = new QLineEdit(); + + // Create the layout and add the components to it + QVBoxLayout *vertLayout = new QVBoxLayout(); + vertLayout->addWidget(label); + vertLayout->addWidget(p_pointIdEdit); + vertLayout->addStretch(); + this->setLayout(vertLayout); + } + + /** + * Filters a list of images looking for cube names using the regular expression + * entered. The filtered list will appear in the navtools cube list display. + * + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified to remove + * new filter points from the existing + * filtered list. + */ + void QnetPointIdFilter::filter() { + + // Make sure there is a control net loaded + if (g_controlNetwork == NULL) { + QMessageBox::information((QWidget *)parent(), + "Error","No points to filter"); + return; + } + + // Make sure the user has entered a regular expression for filtering + QRegExp rx(p_pointIdEdit->text()); + rx.setPatternSyntax(QRegExp::Wildcard); + if (rx.isEmpty()) { + QMessageBox::information((QWidget *)parent(), + "Error","Enter search string"); + return; + } + + + // Loop through each value of the filtered points list checking + // the types of each control measure for each of the control points + // Loop in reverse order since removal list of elements affects index number + for (int i = g_filteredPoints.size()-1; i >= 0; i--) { + + string cNetId = (*g_controlNetwork)[g_filteredPoints[i]].Id(); + if (rx.indexIn(QString(cNetId.c_str())) != -1) { + continue; + } + else g_filteredPoints.removeAt(i); + } + + // Tell the navtool a list has been filtered and it needs to update + emit filteredListModified(); + return; + } +} diff --git a/isis/src/qisis/apps/qnet/QnetPointIdFilter.h b/isis/src/qisis/apps/qnet/QnetPointIdFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..c9fcba9ba6642e67dbd203807a2360be1f8d6519 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointIdFilter.h @@ -0,0 +1,43 @@ +#ifndef QnetPointIdFilter_h +#define QnetPointIdFilter_h + +#include +#include +#include +#include +#include +#include +#include +#include "QnetFilter.h" + + +namespace Qisis { + /** + * Defines the Point ID filter for the QnetNavTool's Points + * section. The user must enter a string. This class is + * designed to remove points from the current filtered list + * whose PointId keyword values do not contain the string. + * + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified filter() + * method to remove new filter points + * from the existing filtered list. + * @history 2010-06-03 Jeannie Walldren - Initialized pointer + * to null in constructor + * + * + */ + + class QnetPointIdFilter : public QnetFilter { + Q_OBJECT + + public: + QnetPointIdFilter (QWidget *parent=0); + virtual void filter(); + + private: + QLineEdit *p_pointIdEdit; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetPointImagesFilter.cpp b/isis/src/qisis/apps/qnet/QnetPointImagesFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10b3ecdd4ecef8496a7a8b533ce3a8eedb6d26a9 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointImagesFilter.cpp @@ -0,0 +1,101 @@ +#include +#include +#include "QnetPointImagesFilter.h" +#include "QnetNavTool.h" +#include "ControlNet.h" +#include "SerialNumberList.h" + +#include "qnet.h" + +using namespace Qisis::Qnet; + +namespace Qisis { + /** + * Contructor for the Point Images filter. + * It creates the Images filter window found + * in the navtool + * + * @param parent The parent widget for the + * point points filter + * @internal + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null. + * + */ + QnetPointImagesFilter::QnetPointImagesFilter (QWidget *parent) : QnetFilter(parent) { + p_lessThanRB = NULL; + p_greaterThanRB = NULL; + p_imageEdit = NULL; + // Create the components for the main window + QLabel *label = new QLabel("Filter by number of images in each point"); + p_lessThanRB = new QRadioButton("Less than"); + p_greaterThanRB = new QRadioButton("Greater than"); + p_imageEdit = new QLineEdit(); + QLabel *units = new QLabel ("images"); + p_lessThanRB->setChecked(true); + QLabel *pad = new QLabel(); + + // Create the layout and add the components to it + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->addWidget(label,0,0,1,2); + gridLayout->addWidget(p_lessThanRB,1,0,1,2); + gridLayout->addWidget(p_greaterThanRB,2,0,1,2); + gridLayout->addWidget(p_imageEdit,3,0); + gridLayout->addWidget(units,3,1); + gridLayout->addWidget(pad,4,0); + gridLayout->setRowStretch(4,50); + this->setLayout(gridLayout); + } + + /** + * Filters a list of points for points that have less than or greater + * than the entered number of images. The filtered list will appear in + * the navtools point list display. + * + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified filter() + * method to remove new filter points + * from the existing filtered list. + * Previously, a new filtered list was + * created from the entire control net + * each time. + */ + void QnetPointImagesFilter::filter() { + // Make sure we have points to filter + if (g_controlNetwork == NULL) { + QMessageBox::information((QWidget *)parent(), + "Error","No points to filter"); + return; + } + + // Make sure the user has entered a value for the filtering + int num = -1; + if (p_imageEdit->text() == "") { + QMessageBox::information((QWidget *)parent(), + "Error","Image filter value must be entered"); + return; + } + + // Get the user entered filter value + num = p_imageEdit->text().toInt(); + + // Loop through each value of the filtered points list the user + // entered value with the number of measures in the point and + // remove it from the list if it is outside the filtering value range + // Loop in reverse order since removal list of elements affects index number + for (int i = g_filteredPoints.size()-1; i >= 0; i--) { + Isis::ControlPoint cp = (*g_controlNetwork)[g_filteredPoints[i]]; + if (p_lessThanRB->isChecked()) { + if (cp.Size() < num) continue; + else g_filteredPoints.removeAt(i); + } + else if (p_greaterThanRB->isChecked()) { + if (cp.Size() > num) continue; + else g_filteredPoints.removeAt(i); + } + } + // Tell the navtool that a list has been filtered and it needs to update + emit filteredListModified(); + return; + } +} diff --git a/isis/src/qisis/apps/qnet/QnetPointImagesFilter.h b/isis/src/qisis/apps/qnet/QnetPointImagesFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..e92f77bafe6ee00ad9092d598d646b8d1f2f9f61 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointImagesFilter.h @@ -0,0 +1,44 @@ +#ifndef QnetPointImagesFilter_h +#define QnetPointImagesFilter_h + +#include +#include +#include +#include +#include +#include +#include +#include "QnetFilter.h" + + +namespace Qisis { + /** + * Defines the Images filter for the QnetNavTool's Points + * section, i.e. the number of measures in control point. The + * user may enter values for Less Than and/or Greater Than. This + * class is designed to remove points from the current filtered + * list that lie outside of the given range. + * + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified filter() + * method to remove new filter points + * from the existing filtered list. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null in constructor + * + */ + class QnetPointImagesFilter : public QnetFilter { + Q_OBJECT + + public: + QnetPointImagesFilter (QWidget *parent=0); + virtual void filter(); + + private: + QRadioButton *p_lessThanRB; + QRadioButton *p_greaterThanRB; + QLineEdit *p_imageEdit; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetPointMeasureFilter.cpp b/isis/src/qisis/apps/qnet/QnetPointMeasureFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eea942cfda07c686ca8ce3ced8d629ace103cba6 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointMeasureFilter.cpp @@ -0,0 +1,297 @@ +#include +#include +#include "QnetPointMeasureFilter.h" +#include "QnetNavTool.h" +#include "ControlMeasure.h" +#include "ControlNet.h" +#include "SerialNumberList.h" + +#include "qnet.h" + +using namespace std; +using namespace Qisis::Qnet; + +namespace Qisis { + /** + * Contructor for the Point Measure filter. It creates the + * Measure filter window found in the navtool + * + * @param parent The parent widget for the point measure + * filter + * @internal + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null. + * + */ + QnetPointMeasureFilter::QnetPointMeasureFilter (QWidget *parent) : QnetFilter(parent) { + p_measureType = NULL; + p_unmeasured = NULL; + p_manual = NULL; + p_estimated = NULL; + p_automatic = NULL; + p_validatedManual = NULL; + p_validatedAutomatic = NULL; + p_ignoreStatus = NULL; + p_ignored = NULL; + p_notIgnored = NULL; + + // Create the components for the filter window + p_measureType = new QCheckBox("Filter by Measure Type(s)"); + p_unmeasured = new QCheckBox("Unmeasured"); + p_manual = new QCheckBox("Manual"); + p_estimated = new QCheckBox("Estimated"); + p_automatic = new QCheckBox("Auto-Registered"); + p_validatedManual = new QCheckBox("Manual/Validated"); + p_validatedAutomatic = new QCheckBox("Auto-Registered/Validated"); + + p_measureType->setChecked(false); + p_unmeasured->setEnabled(false); + p_manual->setEnabled(false); + p_estimated->setEnabled(false); + p_automatic->setEnabled(false); + p_validatedManual->setEnabled(false); + p_validatedAutomatic->setEnabled(false); + connect(p_measureType,SIGNAL(toggled(bool)),this,SLOT(enableTypeFilter())); + + p_ignoreStatus = new QCheckBox("Filter by Ignore Status"); + p_ignored = new QRadioButton("Ignored"); + p_notIgnored = new QRadioButton("Not Ignored"); + + p_ignoreStatus->setChecked(false); + p_ignored->setChecked(true); + p_ignored->setEnabled(false); + p_notIgnored->setEnabled(false); + connect(p_ignoreStatus,SIGNAL(toggled(bool)),this,SLOT(enableIgnoreFilter())); + + QLabel *pad = new QLabel(); + + + // Create the layout and add the components to it + QVBoxLayout *ignorelayout = new QVBoxLayout(); + ignorelayout->addWidget(p_ignoreStatus); + ignorelayout->addWidget(p_ignored); + ignorelayout->addWidget(p_notIgnored); + ignorelayout->addWidget(pad); + ignorelayout->addWidget(pad); + ignorelayout->addWidget(pad); + + QVBoxLayout *typelayout = new QVBoxLayout(); + typelayout->addWidget(p_measureType); + typelayout->addWidget(p_unmeasured); + typelayout->addWidget(p_manual); + typelayout->addWidget(p_estimated); + typelayout->addWidget(p_automatic); + typelayout->addWidget(p_validatedManual); + typelayout->addWidget(p_validatedAutomatic); + typelayout->addWidget(pad); + typelayout->addWidget(pad); + + QHBoxLayout *layout = new QHBoxLayout(); + layout->addLayout(typelayout); + layout->addLayout(ignorelayout); + this->setLayout(layout); + } + + + + /** + * Filters a list of points for points that have at least one measure + * of the selected type(s). The filtered list will appear in the + * navtools point list display. + * + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified to remove + * new filter points from the existing + * filtered list. Previously, a new + * filtered list was created from the + * entire control net each time. + * @history 2010-06-02 Jeannie Walldren - Added functionality + * to filter by ignore status in + * addition to measure type + */ + void QnetPointMeasureFilter::filter() { + // Make sure there is a control net loaded to filter + if (g_controlNetwork == NULL) { + QMessageBox::information((QWidget *)parent(), + "Error","No points to filter"); + return; + } + + // Make sure they selected at least one type to filter for + if (!(p_measureType->isChecked()) && !(p_ignoreStatus->isChecked())) { + QMessageBox::information((QWidget *)parent(),"Error", + "You must select at least one measure property to filter"); + return; + } + // if Filter by Measure Type is selected but no Measure Type is checked, throw error + if ((p_measureType->isChecked()) && + !(p_unmeasured->isChecked() || + p_manual->isChecked() || + p_estimated->isChecked() || + p_automatic->isChecked() || + p_validatedAutomatic->isChecked() || + p_validatedManual->isChecked())) { + QMessageBox::information((QWidget *)parent(),"Error", + "Filter by Measure Type is selected. You must choose at least one Measure Type to filter"); + return; + } + + + // Loop through each value of the filtered points list + // checking the types of each control measure for each + // of the control points. If no measures match, we remove + // it from the filtered list + // Loop in reverse order since removal list of elements affects index number + for (int i = g_filteredPoints.size()-1; i >= 0; i--) { + Isis::ControlPoint cp = (*g_controlNetwork)[g_filteredPoints[i]]; + int numMeasNotMatching = 0; + for (int j=0; jisChecked()) { + // if the point contains a measure whose ignore status matches + // the user's selection, check whether the measure type matches + if (p_ignored->isChecked() && cp[j].Ignore()) { + if (p_measureType->isChecked()) { + if (MeasureTypeMatched(cp[j].Type())){ + // keep this point in the list and go on to the next point + break; + } + } + else { + // keep this point in the list and go on to the next point + break; + } + } + else if (p_notIgnored->isChecked() && !cp[j].Ignore()) { + if (p_measureType->isChecked()) { + // keep this point in the list and go on to the next point + if (MeasureTypeMatched(cp[j].Type())){ + break; + } + } + else { + // keep this point in the list and go on to the next point + break; + } + } + } + else { // ignore status not selected, only filter by measure type + if (MeasureTypeMatched(cp[j].Type())){ + // keep this point in the list and go on to the next point + break; + } + } + // if this measure doesn't match any of the checked values, increment + numMeasNotMatching++; + } + + int numMeasures = cp.Size(); + + // if no measures match the checked values, + // remove this point from the filter list + if (numMeasNotMatching == numMeasures) { + g_filteredPoints.removeAt(i); + } + } + + // Tell the navtool that a list has been filtered and it needs to update + emit filteredListModified(); + return; + } + + /** + * @brief Returns whether the measure type passed in matches a + * type selected by the user. + * + * This method is called by the filter() method to checks + * whether a particular measure type matches any of the + * checkboxes selected by the user. + * + * @param cmType ControlMeasure type to compare with user + * selection. + * @return bool True if the measure type matches a type + * selected by the user. + */ + bool QnetPointMeasureFilter::MeasureTypeMatched(int cmType){ + if (p_unmeasured->isChecked() && cmType == Isis::ControlMeasure::Unmeasured) { + return true;; + } + if (p_manual->isChecked() && cmType == Isis::ControlMeasure::Manual) { + return true;; + } + if (p_estimated->isChecked() && cmType == Isis::ControlMeasure::Estimated) { + return true;; + } + if (p_automatic->isChecked() && cmType == Isis::ControlMeasure::Automatic) { + return true;; + } + if (p_validatedManual->isChecked() && cmType == Isis::ControlMeasure::ValidatedManual) { + return true;; + } + if (p_validatedAutomatic->isChecked() && cmType == Isis::ControlMeasure::ValidatedAutomatic) { + return true;; + } + return false; + } + + /** + * @brief Enables ignore status filter when corresponding + * checkbox is selected. + * + * This slot is connected to the toggle signal of the "Filter by + * Ignore Status" checkbox. When the box is checked, the radio + * buttons are enabled. + * + * + * @internal + * @history 2010-06-02 Jeannie Walldren - Original version + */ + void QnetPointMeasureFilter::enableIgnoreFilter() { + if (p_ignoreStatus->isChecked()) { + p_ignored->setEnabled(true); + p_notIgnored->setEnabled(true); + } + else{ + p_ignored->setEnabled(false); + p_notIgnored->setEnabled(false); + } + + } + + /** + * @brief Enables measure type filter when corresponding + * checkbox is selected. + * + * This slot is connected to the toggle signal of the "Filter by + * Measure Type" checkbox. When the box is checked, the + * checkboxes below are enabled. + * + * @internal + * @history 2010-06-02 Jeannie Walldren - Original version + */ + void QnetPointMeasureFilter::enableTypeFilter() { + if (p_measureType->isChecked()) { + p_unmeasured->setEnabled(true); + p_manual->setEnabled(true); + p_estimated->setEnabled(true); + p_automatic->setEnabled(true); + p_validatedManual->setEnabled(true); + p_validatedAutomatic->setEnabled(true); + } + else{ + p_unmeasured->setEnabled(false); + p_manual->setEnabled(false); + p_estimated->setEnabled(false); + p_automatic->setEnabled(false); + p_validatedManual->setEnabled(false); + p_validatedAutomatic->setEnabled(false); + p_unmeasured->setChecked(false); + p_manual->setChecked(false); + p_estimated->setChecked(false); + p_automatic->setChecked(false); + p_validatedManual->setChecked(false); + p_validatedAutomatic->setChecked(false); + } + + } + +} diff --git a/isis/src/qisis/apps/qnet/QnetPointMeasureFilter.h b/isis/src/qisis/apps/qnet/QnetPointMeasureFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..12289e116e0eb7e7ba2acf7460ea489dfd82f613 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointMeasureFilter.h @@ -0,0 +1,66 @@ +#ifndef QnetPointMeasureFilter_h +#define QnetPointMeasureFilter_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include "QnetFilter.h" + + +namespace Qisis { + /** + * Defines the Measure Properties filter for the QnetNavTool's + * Points section. This class filters points whose + * measures have at least one measure with the selected + * properties. If the user chooses more than one measure type, + * the list will contain points with at least one measure with + * either of these types. If the user chooses to filter by + * measure type and ignore status, the list will contain points + * with at least one measure that contains both of these + * properties. This class is designed to remove points from the + * current filtered list that do not contain any measures of the + * selected type. + * + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified filter() + * method to remove new filter points + * from the existing filtered list. + * @history 2010-06-02 Jeannie Walldren - Created MeasureTypeMatched() + * method. Modified filter() to add + * the Ignore Status filter + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null in constructor. + * + */ + class QnetPointMeasureFilter : public QnetFilter { + Q_OBJECT + + public: + QnetPointMeasureFilter (QWidget *parent=0); + virtual void filter(); + bool MeasureTypeMatched(int cmType); + + private slots: + void enableIgnoreFilter(); + void enableTypeFilter(); + + private: + QCheckBox *p_measureType; + QCheckBox *p_unmeasured; + QCheckBox *p_manual; + QCheckBox *p_estimated; + QCheckBox *p_automatic; + QCheckBox *p_validatedManual; + QCheckBox *p_validatedAutomatic; + QCheckBox *p_ignoreStatus; + QRadioButton *p_ignored; + QRadioButton *p_notIgnored; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetPointRangeFilter.cpp b/isis/src/qisis/apps/qnet/QnetPointRangeFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43056cae0d2bbab16b667c25e8996a91fa3fd908 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointRangeFilter.cpp @@ -0,0 +1,171 @@ +#include +#include +#include "QnetPointRangeFilter.h" +#include "QnetNavTool.h" +#include "ControlNet.h" +#include "SerialNumberList.h" +//#include "geos.h" +#include "qnet.h" + +#include "geos/geom/Coordinate.h" +#include "geos/geom/GeometryFactory.h" +#include "geos/geom/CoordinateSequenceFactory.h" +#include "geos/geom/LinearRing.h" +#include "geos/geom/Polygon.h" +#include "geos/geom/Point.h" + +using namespace Qisis::Qnet; +using namespace std; + +namespace Qisis { + /** + * Contructor for the Point Range filter. It creates the + * Range filter window found in the navtool + * + * @param parent The parent widget for the point Range + * filter + * @internal + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null. + * + */ + QnetPointRangeFilter::QnetPointRangeFilter (QWidget *parent) : QnetFilter(parent) { + p_minlat = NULL; + p_maxlat = NULL; + p_minlon = NULL; + p_maxlon = NULL; + + // Create the components for the filter window + p_minlat = new QLineEdit(); + p_maxlat = new QLineEdit(); + p_minlon = new QLineEdit(); + p_maxlon = new QLineEdit(); + + // Disable all range line edits since the lat/lon range is not selected + // p_minlat->setEnabled(false); + // p_maxlat->setEnabled(false); + // p_minlon->setEnabled(false); + // p_maxlon->setEnabled(false); + + // Create labels for the latitude range values + QLabel *minlatLabel = new QLabel("Minimum Latitude"); + QLabel *maxlatLabel = new QLabel("Maximum Latitude"); + QLabel *minlonLabel = new QLabel("Minimum Longitude"); + QLabel *maxlonLabel = new QLabel("Maximum Longitude"); + QLabel *pad = new QLabel(); + + // Create the layout and add the components to it + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->addWidget(minlatLabel,0,0,1,1); + gridLayout->addWidget(p_minlat,0,1,1,1); + gridLayout->addWidget(maxlatLabel,1,0,1,1); + gridLayout->addWidget(p_maxlat,1,1,1,1); + gridLayout->addWidget(minlonLabel,2,0,1,1); + gridLayout->addWidget(p_minlon,2,1,1,1); + gridLayout->addWidget(maxlonLabel,3,0,1,1); + gridLayout->addWidget(p_maxlon,3,1,1,1); + gridLayout->addWidget(pad,4,0); + gridLayout->setRowStretch(4,50); + this->setLayout(gridLayout); + } + + /** + * Filters a list of points for points that are of the selected + * Range or in the given range. The filtered list will appear in + * the navtools point list display. + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified to remove + * new filter points from the existing + * filtered list. Previously, a new + * filtered list was created from the + * entire control net each time. + * @history 2010-06-03 Jeannie Walldren - Removed "std::" + * since "using namespace std" + * + */ + void QnetPointRangeFilter::filter() { + // Make sure there is a control net loaded + if (g_controlNetwork == NULL) { + QMessageBox::information((QWidget *)parent(), + "Error","No points to filter"); + return; + } + + // Make sure all the values we need have been entered by the user + if ((p_minlat->text() == "") || (p_maxlat->text() == "") || + (p_minlon->text() == "") || (p_maxlon->text() == "")) { + QMessageBox::information((QWidget *)parent(), + "Error","All lat/lon range values must be entered"); + return; + } + else { + // Get the user entered values for the range + double minlat = p_minlat->text().toDouble(); + double maxlat = p_maxlat->text().toDouble(); + double minlon = p_minlon->text().toDouble(); + double maxlon = p_maxlon->text().toDouble(); + + // Make sure the lat values are in order + if (minlat > maxlat) { + QString msg = "The minimum latitude value must be less than the maximum latitude value"; + QMessageBox::information((QWidget *)parent(),"Error",msg); + return; + } + // Make sure the lon values are in order + else if (minlon > maxlon) { + QString msg = "The minimum longitude value must be less than the maximum longitude value"; + QMessageBox::information((QWidget *)parent(),"Error",msg); + return; + } + + // Set up a polygon with the range values the user entered + + // Create all the coordinates we will need + vector *coords = new vector; + geos::geom::Coordinate *c1 = new geos::geom::Coordinate(minlat,minlon); + geos::geom::Coordinate *c2 = new geos::geom::Coordinate(maxlat,minlon); + geos::geom::Coordinate *c3 = new geos::geom::Coordinate(maxlat,maxlon); + geos::geom::Coordinate *c4 = new geos::geom::Coordinate(minlat,maxlon); + geos::geom::Coordinate *c5 = new geos::geom::Coordinate(minlat,minlon); + + // create the coordinate sequence + coords->push_back(*c1); + coords->push_back(*c2); + coords->push_back(*c3); + coords->push_back(*c4); + coords->push_back(*c5); + geos::geom::GeometryFactory *factory = new geos::geom::GeometryFactory(); + const geos::geom::CoordinateSequenceFactory *csFact = + factory->getCoordinateSequenceFactory(); + geos::geom::CoordinateSequence *seq = csFact->create(coords); + + // Create the polygon with the coordinate sequence + geos::geom::LinearRing *ring = factory->createLinearRing(seq); + geos::geom::Polygon *poly = factory->createPolygon(ring, + new vector); + + // Loop through each value of the filtered points list + // checking to see if each point is in the polygon we created above + // Loop in reverse order since removal list of elements affects index number + for (int i = g_filteredPoints.size()-1; i >= 0; i--) { + // Get the current control point + Isis::ControlPoint cp = (*g_controlNetwork)[g_filteredPoints[i]]; + + // Create a new point + const geos::geom::Coordinate *coord = + new geos::geom::Coordinate(cp.UniversalLatitude(),cp.UniversalLongitude()); + geos::geom::Point *pt = factory->createPoint(*coord); + + // See if the point is in the polygon & add it if it is + if (poly->contains(pt)) { + continue; + } + else g_filteredPoints.removeAt(i); + } + } + + // Tell the navtool that a list has been filtered and it needs to update + emit filteredListModified(); + return; + } +} diff --git a/isis/src/qisis/apps/qnet/QnetPointRangeFilter.h b/isis/src/qisis/apps/qnet/QnetPointRangeFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..9db597ec9cf158801624d27ed7fd42572b4f1eda --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointRangeFilter.h @@ -0,0 +1,45 @@ +#ifndef QnetPointRangeFilter_h +#define QnetPointRangeFilter_h + +#include +#include +#include +#include +#include +#include +#include "QnetFilter.h" + + +namespace Qisis { + /** + * Defines the Range filter for the QnetNavTool's Points + * section. The user must enter values for Minimum Latitude, + * Maximum Latitude, Minimum Longitude, and Maximum Longitude. + * This class is designed to remove points from the current + * filtered list that lie outside of the given range. + * + * @internal + * @history 2009-01-08 Jeannie Walldren - Modified filter() + * method to remove new filter points + * from the existing filtered list. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null in constructor. Removed + * "std::" in .cpp file. + * + */ + class QnetPointRangeFilter : public QnetFilter { + Q_OBJECT + + public: + QnetPointRangeFilter (QWidget *parent=0); + virtual void filter(); + + private: + QLineEdit *p_minlat; + QLineEdit *p_maxlat; + QLineEdit *p_minlon; + QLineEdit *p_maxlon; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetPointTypeFilter.cpp b/isis/src/qisis/apps/qnet/QnetPointTypeFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f120b99ccfc40184ee2523b71adc7313d2485188 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointTypeFilter.cpp @@ -0,0 +1,118 @@ +#include +#include +#include "QnetPointTypeFilter.h" +#include "QnetNavTool.h" +#include "ControlNet.h" +#include "SerialNumberList.h" +#include "qnet.h" + +using namespace Qisis::Qnet; + +namespace Qisis { + /** + * Contructor for the Point Type filter. It creates the + * Type filter window found in the navtool + * + * @param parent The parent widget for the point type + * filter + * @internal + * @history 2010-06-03 Jeannie Walldren - Initialized pointers + * to null. + * + */ + QnetPointTypeFilter::QnetPointTypeFilter (QWidget *parent) : QnetFilter(parent) { + p_ground = NULL; + p_ignore = NULL; + p_held = NULL; + + // Create the components for the filter window + p_ground = new QRadioButton("Ground"); + p_ground->setChecked(true); + p_ignore = new QRadioButton("Ignored"); + p_held = new QRadioButton("Held"); + QLabel *pad = new QLabel(); + + // Create the layout and add the components to it + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->addWidget(p_ground,0,0,1,4); + gridLayout->addWidget(p_ignore,1,0,1,4); + gridLayout->addWidget(p_held,2,0,1,4); + gridLayout->addWidget(pad,3,0); + gridLayout->setRowStretch(3,50); + this->setLayout(gridLayout); + } + + /** + * Filters a list of points and keeps points that have the + * selected property or in the given range. Note: If a point + * does not have Ignore=True but all measures of the point have + * Ignore=True, this point will be considered "Ignored". The + * filtered list will appear in the navtools point list display. + * + * @internal + * @history 2008-11-26 Jeannie Walldren - Fixed comment. + * @history 2009-01-08 Jeannie Walldren - Modified to remove + * new filter points from the existing + * filtered list. Previously, a new + * filtered list was created from the + * entire control net each time. + * @history 2010-06-02 Jeannie Walldren - Modified to treat + * a point as ignored if all of its + * measures have Ignore=True + * @history 2010-06-03 Jeannie Walldren - Replaced "0" with + * Isis::ControlPoint::Ground in case + * enumeration changes. + */ + void QnetPointTypeFilter::filter() { + // Make sure there is a control net loaded + if (g_controlNetwork == NULL) { + QMessageBox::information((QWidget *)parent(), + "Error","No points to filter"); + return; + } + + // Loop through each value of the filtered points list checking + // the types of each control point + // Loop in reverse order since removal list of elements affects index number + for (int i = g_filteredPoints.size()-1; i >= 0; i--) { + Isis::ControlPoint cp = (*g_controlNetwork)[g_filteredPoints[i]]; + if (p_ground->isChecked()) { + if (cp.Type() == Isis::ControlPoint::Ground) { + continue; + } + else { + g_filteredPoints.removeAt(i); + } + } + else if (p_ignore->isChecked()) { + if (cp.Ignore()) { + continue; + } + else { + for (int j = 0; j < cp.Size(); j++) { + if (!cp[j].Ignore()) { + // if any measure is not ignored, remove from filtered list + g_filteredPoints.removeAt(i); + break; + } + } + // if all measures have Ignore=True, treat point as ignored + // and keep in filtered list + continue; + } + } + else { //if (p_held->isChecked()) { + if (cp.Held()) { + continue; + } + else { + g_filteredPoints.removeAt(i); + } + } + } + + // Tell the navtool that a list has been filtered and it needs to update + emit filteredListModified(); + return; + } +} diff --git a/isis/src/qisis/apps/qnet/QnetPointTypeFilter.h b/isis/src/qisis/apps/qnet/QnetPointTypeFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..85d4bb580ec98a863fc563731abf18c6bdc7f7f3 --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetPointTypeFilter.h @@ -0,0 +1,50 @@ +#ifndef QnetPointTypeFilter_h +#define QnetPointTypeFilter_h + +#include +#include +#include +#include +#include +#include +#include +#include "QnetFilter.h" + + +namespace Qisis { + /** + * Filter for control point type. The user must choose Ground, + * Ignore, or Hold. This class is designed to remove points + * from the current filtered list that are not of the selected + * type. + * + * @internal + * @history 2008-11-26 Jeannie Walldren - Fixed comment in + * filter() method. + * @history 2009-01-08 Jeannie Walldren - Modified filter() + * method to remove new filter points + * from the existing filtered list. + * @history 2010-06-02 Jeannie Walldren - Modified filter() + * method to treat a point as ignored + * if all of its measures have + * Ignore=True. + * @history 2010-06-03 Jeannie Walldren - Replaced "0" with + * "Isis::ControlPoint::Ground" in + * filter(). Initialized pointers to + * null in constructor + */ + class QnetPointTypeFilter : public QnetFilter { + Q_OBJECT + + public: + QnetPointTypeFilter (QWidget *parent=0); + virtual void filter(); + + private: + QRadioButton *p_ground; + QRadioButton *p_ignore; + QRadioButton *p_held; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/QnetTool.cpp b/isis/src/qisis/apps/qnet/QnetTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bca5992f9c844154c3b8bb554bac2c6e7b75f63a --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetTool.cpp @@ -0,0 +1,1471 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include "AutoReg.h" +//#include "AutoRegFactory.h" +#include "ControlMeasure.h" +#include "ControlPoint.h" +#include "ControlPointEdit.h" +#include "Filename.h" +#include "MdiCubeViewport.h" +#include "Pvl.h" +#include "PvlEditDialog.h" +#include "QnetDeletePointDialog.h" +#include "QnetHoldPointDialog.h" +#include "QnetNewMeasureDialog.h" +#include "QnetNewPointDialog.h" +#include "QnetTool.h" +#include "SerialNumber.h" +#include "iException.h" +#include "ToolPad.h" + +#include "qnet.h" +using namespace Qisis::Qnet; +using namespace std; + + +namespace Qisis { + + const int VIEWSIZE = 301; + + /** + * Consructs the Qnet Tool window + * + * @param parent The parent widget for the Qnet tool + * @internal + * @history 2010-06-03 Jeannie Walldren - Initialized pointers to null. + * + */ + QnetTool::QnetTool (QWidget *parent) : Qisis::Tool(parent) { + +#if 0 + p_createPoint = new QAction (parent); + p_createPoint->setShortcut(Qt::Key_C); + connect(p_createPoint,SIGNAL(triggered()),this,SLOT(createPoint())); + + p_modifyPoint = new QAction (parent); + p_modifyPoint->setShortcut(Qt::Key_M); +// connect(p_modifyPoint,SIGNAL(triggered()),this,SLOT(modifyPoint())); + + p_deletePoint = new QAction (parent); + p_deletePoint->setShortcut(Qt::Key_D); + connect(p_deletePoint,SIGNAL(triggered()),this,SLOT(deletePoint())); +#endif + p_leftCube = NULL; + p_rightCube = NULL; + p_controlPoint = NULL; + p_createPoint = NULL; + p_modifyPoint = NULL; + p_deletePoint = NULL; + p_mw = NULL; + p_pointEditor = NULL; + p_ptIdValue = NULL; + p_numMeasures = NULL; + p_ignorePoint = NULL; + p_holdPoint = NULL; + p_groundPoint = NULL; + p_leftMeasureType = NULL; + p_leftSampError = NULL; + p_leftLineError = NULL; + p_leftGoodness = NULL; + p_rightMeasureType = NULL; + p_rightSampError = NULL; + p_rightLineError = NULL; + p_rightGoodness = NULL; + p_ignoreLeftMeasure = NULL; + p_ignoreRightMeasure = NULL; + p_leftCombo = NULL; + p_rightCombo = NULL; + p_leftMeasure = NULL; + p_rightMeasure = NULL; + p_holdPointDialog = NULL; + createQnetTool(parent); + + } + + /** + * @internal + * @history 2008-11-24 Jeannie Walldren - Added "Goodness of Fit" to right + * and left measure info. + * @history 2008-11-26 Jeannie Walldren - Added "Number of Measures" to + * QnetTool point information. Moved setWindowTitle() + * command to updateNet() method. Added connection + * between Ignore checkbox toggle() slot and + * ignoreChanged() signal + * @history 2008-12-29 Jeannie Walldren - Disabled ground point check box and + * commented out connection between check box and + * setGroundPoint() method. + * @history 2008-12-30 Jeannie Walldren - Added connections to toggle + * measures' Ignore check boxes if ignoreLeftChanged() + * and ignoreRightChanged() are emitted. Replaced + * reference to ignoreChanged() with + * ignorePointChanged(). + * @history 2010-06-03 Jeannie Walldren - Removed "std::" since "using + * namespace std" + */ + void QnetTool::createQnetTool(QWidget *parent) { + + // Create dialog with a main window + p_qnetTool = new QMainWindow(parent); + p_qnetTool->layout()->setSizeConstraint(QLayout::SetFixedSize); + + createMenus(); + + // Place everything in a grid + QGridLayout *gridLayout = new QGridLayout(); + //gridLayout->setSizeConstraint(QLayout::SetFixedSize); + // ??? Very tacky-hardcoded to ChipViewport size of ControlPointEdit + xtra. + // Is there a better way to do this? + gridLayout->setColumnMinimumWidth(0,310); + gridLayout->setColumnMinimumWidth(1,310); + // grid row + int row = 0; + + // Point Id, Number of Measures + p_ptIdValue = new QLabel(); + p_numMeasures = new QLabel(); + gridLayout->addWidget(p_ptIdValue,row++,0); + gridLayout->addWidget(p_numMeasures,row++,0); + + // Hold / Ignore / Ground flags + p_ignorePoint = new QCheckBox("Ignore Point"); + gridLayout->addWidget(p_ignorePoint,row++,0); + connect(p_ignorePoint,SIGNAL(toggled(bool)),this,SLOT(setIgnorePoint(bool))); + // this will toggle the point's ignore box if ignorePointChanged() is emitted + connect(this,SIGNAL(ignorePointChanged()),p_ignorePoint,SLOT(toggle())); + p_holdPoint = new QCheckBox("Hold Point"); + gridLayout->addWidget(p_holdPoint,row++,0); + connect(p_holdPoint,SIGNAL(toggled(bool)),this,SLOT(setHoldPoint(bool))); + p_groundPoint = new QCheckBox("Ground Point"); + // disable user's ability to set ground points + p_groundPoint->setEnabled(false); + gridLayout->addWidget(p_groundPoint,row++,0); + // the following connection is commented out since we are currently + // not allowing the user to set ground points + //???? connect(p_groundPoint,SIGNAL(toggled(bool)),this,SLOT(setGroundPoint(bool))); + + // Measure type + p_leftMeasureType = new QLabel(); + gridLayout->addWidget(p_leftMeasureType,row,0); + p_rightMeasureType = new QLabel(); + gridLayout->addWidget(p_rightMeasureType,row++,1); + + // Show if measure ignore flag is set + p_ignoreLeftMeasure = new QCheckBox("Ignore Measure"); + gridLayout->addWidget(p_ignoreLeftMeasure,row,0); + connect(p_ignoreLeftMeasure,SIGNAL(toggled(bool)), + this,SLOT(setIgnoreLeftMeasure(bool))); + connect(this,SIGNAL(ignoreLeftChanged()), + p_ignoreLeftMeasure,SLOT(toggle())); + + p_ignoreRightMeasure = new QCheckBox("Ignore Measure"); + gridLayout->addWidget(p_ignoreRightMeasure,row++,1); + connect(p_ignoreRightMeasure,SIGNAL(toggled(bool)), + this,SLOT(setIgnoreRightMeasure(bool))); + connect(this,SIGNAL(ignoreRightChanged()), + p_ignoreRightMeasure,SLOT(toggle())); + + p_leftSampError = new QLabel(); + gridLayout->addWidget(p_leftSampError,row,0); + p_rightSampError = new QLabel(); + gridLayout->addWidget(p_rightSampError,row++,1); + + p_leftLineError = new QLabel(); + gridLayout->addWidget(p_leftLineError,row,0); + p_rightLineError = new QLabel(); + gridLayout->addWidget(p_rightLineError,row++,1); + + p_leftGoodness = new QLabel(); + gridLayout->addWidget(p_leftGoodness,row,0); + p_rightGoodness = new QLabel(); + gridLayout->addWidget(p_rightGoodness,row++,1); + + // Set up chipViewport and comboBox to select chips + p_leftCombo = new QComboBox (); + p_leftCombo->setFixedWidth(256); + gridLayout->addWidget(p_leftCombo,row,0); + + // Install event filter so that when user moves away + // from combo box the correct measurement info is written back + // out. + p_leftCombo->view()->installEventFilter(this); + connect(p_leftCombo,SIGNAL(activated(int)), + this,SLOT(selectLeftMeasure(int))); + + p_rightCombo = new QComboBox (); + p_rightCombo->setFixedWidth(256); + gridLayout->addWidget(p_rightCombo,row++,1); + p_rightCombo->view()->installEventFilter(this); + connect(p_rightCombo,SIGNAL(activated(int)), + this,SLOT(selectRightMeasure(int))); + + p_pointEditor = new Qisis::ControlPointEdit(parent); + gridLayout->addWidget(p_pointEditor,row++,0,1,3); + connect(p_pointEditor,SIGNAL(pointSaved()),this,SLOT(pointSaved())); + p_pointEditor->show(); +// connect(this,SIGNAL(modifyPoint(Isis::ControlPoint *)), +// p_pointEditor,SLOT(modifyPoint(Isis::ControlPoint *))); + + + QPushButton *addMeasure = new QPushButton ("Add Measure(s) to Point"); + connect(addMeasure,SIGNAL(clicked()),this,SLOT(addMeasure())); + + QHBoxLayout *hlayout = new QHBoxLayout(); + hlayout->addWidget(addMeasure); + hlayout->addStretch(); + gridLayout->addLayout(hlayout,row++,0); + + QWidget *cw = new QWidget(); + cw->setLayout(gridLayout); + p_qnetTool->setCentralWidget(cw); + + connect(this,SIGNAL(editPointChanged(string)), + this,SLOT(paintAllViewports(string))); + + } + + + /** + * This method is connected with the pointSaved() signal from + * ControlPointEdit. + * + * @internal + * @history 2008-11-26 Jeannie Walldren - Added message box to warn the user + * that they are saving an "Ignore" point and ask + * whether they would like to set Ignore=false. This + * emits an ignoreChanged() signal so the "Ignore" box + * in the window is unchecked. + * @history 2008-12-30 Jeannie Walldren - Modified to set measures in + * viewports to Ignore=False if when saving, the user + * chooses to set a point's Ignore=False. Replaced + * reference to ignoreChanged() with + * ignorePointChanged(). + * @history 2008-12-31 Jeannie Walldren - Added question box to ask user + * whether the current reference measure should be + * replaced with the measure in the left viewport. + * @history 2010-01-27 Jeannie Walldren - Added question box to warn the user + * that they are saving an "Ignore" measure and ask + * whether they would like to set Ignore=False. This + * emits an ignoreRightChanged() signal so the "Ignore" + * box in the window is unchecked. Modified Ignore + * Point message for clarity. + */ + void QnetTool::pointSaved() { + if (p_controlPoint->Ignore()) { + switch(QMessageBox::question((QWidget *)parent(), + "Qnet Tool Save Point", + "You are saving changes to an ignored point. Do you want to set Ignore = False on the point and both measures?", + "&Yes", "&No", 0, 0)){ + case 0: // Yes was clicked or Enter was pressed, set Ignore=false for the point and measures and save point + p_controlPoint->SetIgnore(false); + emit ignorePointChanged(); + if (p_leftMeasure->Ignore()) { + p_leftMeasure->SetIgnore(false); + emit ignoreLeftChanged(); + } + if (p_rightMeasure->Ignore()) { + p_rightMeasure->SetIgnore(false); + emit ignoreRightChanged(); + } + case 1: // No was clicked, keep Ignore=true and save point + break; + + } + } + if (p_rightMeasure->Ignore()) { + switch(QMessageBox::question((QWidget *)parent(), + "Qnet Tool Save Point", + "You are saving changes to an ignored measure. Do you want to set Ignore = False on the right measure?", + "&Yes", "&No", 0, 0)){ + case 0: // Yes was clicked, set Ignore=false for the right measure and save point + p_rightMeasure->SetIgnore(false); + emit ignoreRightChanged(); + case 1: // No was clicked, keep Ignore=true and save point + break; + + } + } + // Check if ControlPoint has reference measure, if reference Measure is + // not the same measure that is on the left chip viewport, set left + // measure as reference. + if (p_controlPoint->HasReference()) { + Isis::ControlMeasure *refMeasure = + &(*p_controlPoint)[p_controlPoint->ReferenceIndex()]; + if (refMeasure != p_leftMeasure) { + switch(QMessageBox::question((QWidget *)parent(), + "Qnet Tool Save Point", + "This point already contains a reference measure. Would you like to replace it with the measure on the left?", + "&Yes", "&No", 0, 0)){ + case 0: // Yes was clicked or Enter was pressed, replace reference + refMeasure->SetReference(false); + p_leftMeasure->SetReference(true); + case 1: // No was clicked, keep original reference + break; + + } + } + } + else { + p_leftMeasure->SetReference(true); + } + + emit editPointChanged(p_controlPoint->Id()); + emit netChanged(); + } + + + + /** + * Customize dropdown menus below title bar. + * + * @internal + * @history 2008-11-18 Jeannie Walldren - Added "Close" action to the file + * menu on the qnet tool window. + * @history 2008-12-10 Jeannie Walldren - Added "What's this?" function to + * qnet tool actions. + */ + void QnetTool::createMenus () { + + QAction *saveNet = new QAction(p_qnetTool); + saveNet->setText("Save Control Network &As..."); + QString whatsThis = + "Function: Saves the current control network under chosen filename"; + saveNet->setWhatsThis(whatsThis); + connect (saveNet,SIGNAL(activated()),this,SLOT(saveNet())); + + QAction *closeQnetTool = new QAction(p_qnetTool); + closeQnetTool->setText("&Close"); + closeQnetTool->setShortcut(Qt::ALT+Qt::Key_F4); + whatsThis = + "Function: Closes the Qnet Tool window for this point \ +

    Shortcut: Alt+F4

    "; + closeQnetTool->setWhatsThis(whatsThis); + connect (closeQnetTool,SIGNAL(activated()),p_qnetTool,SLOT(close())); + + QMenu *fileMenu = p_qnetTool->menuBar()->addMenu("&File"); + fileMenu->addAction(saveNet); + fileMenu->addAction(closeQnetTool); + + QAction *templateFile = new QAction(p_qnetTool); + templateFile->setText("&Set registration template"); + whatsThis = + "Function: Allows user to select a new file to set as the registration template"; + templateFile->setWhatsThis(whatsThis); + connect (templateFile,SIGNAL(activated()),this,SLOT(setTemplateFile())); + + QAction *viewTemplate = new QAction(p_qnetTool); + viewTemplate->setText("&View/edit registration template"); + whatsThis = + "Function: Displays the curent registration template. \ + The user may edit and save changes under a chosen filename."; + viewTemplate->setWhatsThis(whatsThis); + connect (viewTemplate,SIGNAL(activated()),this,SLOT(viewTemplateFile())); + + QAction *saveChips = new QAction(p_qnetTool); +// saveChips->setCheckable(true); + saveChips->setText("Save registration chips"); + whatsThis = + "Function: Save registration chips to file. \ + Each chip: pattern, search, fit will be saved to a separate file."; + saveChips->setWhatsThis(whatsThis); + connect (saveChips,SIGNAL(activated()),this,SLOT(saveChips())); + +// QAction *interestOp = new QAction(p_pointEditor); +// interestOp->setText("Choose interest operator"); +// connect (interestOp,SIGNAL(activated()),this,SLOT(setInterestOp())); + + QMenu *optionMenu = p_qnetTool->menuBar()->addMenu("&Options"); + QMenu *regMenu = optionMenu->addMenu("&Registration"); + + regMenu->addAction(templateFile); + regMenu->addAction(viewTemplate); + regMenu->addAction(saveChips); + // registrationMenu->addAction(interestOp); + + } + + + + /** + * Set point's "Ignore" keyword to the value of the input + * parameter. + */ + void QnetTool::setIgnorePoint (bool ignore) { + if (p_controlPoint != NULL) { + p_controlPoint->SetIgnore(ignore); + } + emit netChanged(); + } + + + /** + * Sets the "Held" keyword of the control point to the boolean + * value of the input parameter. + * + * @param hold Boolean value to which "Held" keyword will be + * set. + * @internal + * @history 2008-12-29 Jeannie Walldren - Added dialog box to allow user to + * determine the lat/lon/radius for this point if set + * to Held=True. + */ + void QnetTool::setHoldPoint (bool hold) { + // if control point is already set to value of hold, return + // (currently this is unnecessary since this method is + // only called if the checkbox is toggled) + if (hold == p_controlPoint->Held()) { + return; + } + if (!hold) { + p_controlPoint->SetHeld(false); + } + else{ + p_holdPointDialog = new QnetHoldPointDialog; + p_holdPointDialog->setModal(true); + p_holdPointDialog->setPoint(*p_controlPoint); + connect (p_holdPointDialog,SIGNAL(holdPoint(Isis::ControlPoint &)), + this,SLOT(newHoldPoint(Isis::ControlPoint &))); + connect (p_holdPointDialog,SIGNAL(holdCancelled()), + this,SLOT(cancelHoldPoint())); + p_holdPointDialog->exec(); + } + emit netChanged(); + } + + + /** + * This method sets Held=False and unchecks hold CheckBox if + * the "Cancel" button is clicked in the Hold Point Dialog. + * + * + * @internal + * @history 2010-06-02 Jeannie Walldren - Original version + */ + void QnetTool::cancelHoldPoint () { + p_controlPoint->SetHeld(false); + p_holdPoint->setChecked(false); + return; + } + + + /** + * Sets the "PointType" keyword of the control point. If ground + * is true the point type will be set to "Ground". If ground is + * false, it will be set to "Tie". + * + * @param ground Boolean value that determines value "PointType" + * will be set. + * @author + * @internal + */ + void QnetTool::setGroundPoint (bool ground) { + + // If this slot is called when loading a new point which happens to already be + // a ground point, simply return. I haven't figured out how to set the + // state when loading a new point without emitting the toggled signal. + // Maybe the ground should not be a checkBox??? + if (ground && p_controlPoint->Type() == Isis::ControlPoint::Ground) return; + + // if false, turn back Tie + if (!ground) { + p_controlPoint->SetType(Isis::ControlPoint::Tie); + } + else { + p_controlPoint->SetType(Isis::ControlPoint::Ground); + } + + } + + /** + * + * Makes a new control point identical to input with Held=True. + * + * @param point Control point to be copied + * @author 2008-12-29 Jeannie Walldren + * @internal + * @history 2008-12-29 Jeannie Walldren - Original Version + * @history 2008-12-30 Jeannie Walldren - Replaced reference to + * ignoreChanged() with ignorePointChanged(). + */ + void QnetTool::newHoldPoint(Isis::ControlPoint &point) { + + // If setting as hold or ground point ,make sure point isn't ignored, ground + if (p_controlPoint->Ignore()){ + p_controlPoint->SetIgnore(false); + emit ignorePointChanged(); + } + + p_controlPoint = &point; + p_holdPointDialog->close(); + + } + + /** + * Create a new ground point using input point. + */ + void QnetTool::newGroundPoint(Isis::ControlPoint &point) { + + p_controlPoint = &point; + p_controlPoint->SetType(Isis::ControlPoint::Ground); + + } + + + + /** + * Set the "Ignore" keyword of the measure shown in the left + * viewport to the value of the input parameter. + * @internal + * @history 2010-01-27 Jeannie Walldren - Fixed bug that resulted in segfault. + * Moved the check whether p_rightMeasure is null + * before the check whether p_rightMeasure equals + * p_leftMeasure. + */ + void QnetTool::setIgnoreLeftMeasure (bool ignore) { + if (p_leftMeasure != NULL) p_leftMeasure->SetIgnore(ignore); + emit netChanged(); + + // If the right chip is the same as the left chip , update the right + // ignore box. + if (p_rightMeasure != NULL) { + if (p_rightMeasure->CubeSerialNumber() == p_leftMeasure->CubeSerialNumber()) { + p_rightMeasure->SetIgnore(ignore); + p_ignoreRightMeasure->setChecked(ignore); + } + } + } + + + /** + * Set the "Ignore" keyword of the measure shown in the right + * viewport to the value of the input parameter. + * @internal + * @history 2010-01-27 Jeannie Walldren - Fixed bug that resulted in segfault. + * Moved the check whether p_leftMeasure is null before + * the check whether p_rightMeasure equals + * p_leftMeasure. + */ + void QnetTool::setIgnoreRightMeasure (bool ignore) { + if (p_rightMeasure != NULL) p_rightMeasure->SetIgnore(ignore); + emit netChanged(); + + // If the right chip is the same as the left chip , update the right + // ignore blox. + if (p_leftMeasure != NULL) { + if (p_rightMeasure->CubeSerialNumber() == p_leftMeasure->CubeSerialNumber()) { + p_leftMeasure->SetIgnore(ignore); + p_ignoreLeftMeasure->setChecked(ignore); + } + } + } + + + /** + * Signal to save the control net. + */ + void QnetTool::saveNet () { + emit qnetToolSave(); + } + + + + + /** + * + */ + void QnetTool::updateList() { + + //p_pointEditor->setSerialList (*g_serialNumberList); + + } + + + /** + * Updates the Control Network displayed in the Qnet Tool title + * bar. This slot is connected to QnetFileTool's + * controlNetworkUpdated(QString cNetFilename) signal. + * + * @param cNetFilename Filename of the most recently selected + * control network. + * @see QnetFileTool + * @internal + * @history Tracie Sucharski - Original version + * @history 2008-11-26 Jeannie Walldren - Added cNetFilename input parameter + * in order to show the file path in the window's title + * bar. + */ + void QnetTool::updateNet(QString cNetFilename) { + p_qnetTool->setWindowTitle("Qnet Tool - Control Network File: " + cNetFilename); + //p_pointEditor->setControlNet(*g_controlNetwork); + + } + + + + /** + * Adds the Tie tool action to the tool pad. When the Tie tool is selected, the + * Navigation Tool will automatically open. + * @internal + * @history 2010-07-01 Jeannie Walldren - Added connection between qnet's + * TieTool button and the showNavWindow() method + */ + QAction *QnetTool::toolPadAction(ToolPad *pad) { + QAction *action = new QAction(pad); + action->setIcon(QPixmap(toolIconDir()+"/stock_draw-connector-with-arrows.png")); + action->setToolTip("Tie (T)"); + action->setShortcut(Qt::Key_T); + QObject::connect(action,SIGNAL(activated()),this,SLOT(showNavWindow())); + return action; + } + + + + /** + * Handle mouse events on CubeViewport + * + * @param p[in] (QPoint) Point under cursor in cubeviewport + * @param s[in] (Qt::MouseButton) Which mouse button was pressed + * + * @internal + * @history 2007-06-12 Tracie Sucharski - Swapped left and right mouse + * button actions. + * @history 2009-06-08 Tracie Sucharski - Add error checking for editing + * or deleting points when no point exists. + * @history 2010-06-03 Jeannie Walldren - Removed "std::" since "using + * namespace std" + * + */ + void QnetTool::mouseButtonRelease(QPoint p, Qt::MouseButton s) { + MdiCubeViewport *cvp = cubeViewport(); + if (cvp == NULL) return; + if (cvp->cursorInside()) QPoint p = cvp->cursorPosition(); + + string file = cvp->cube()->Filename(); + string sn = g_serialNumberList->SerialNumber(file); + + double samp,line; + cvp->viewportToCube(p.x(),p.y(),samp,line); + + + if (s == Qt::LeftButton) { + p_leftFile = file; + // Find closest control point in network + Isis::ControlPoint *point = + g_controlNetwork->FindClosest(sn,samp,line); + // TODO: test for errors and reality + if (point == NULL) { + QString message = "No points exist for editing. Create points "; + message += "using the right mouse button."; + QMessageBox::warning((QWidget *)parent(),"Warning",message); + return; + } + modifyPoint(point); + } + else if (s == Qt::MidButton) { + // Find closest control point in network + Isis::ControlPoint *point = + g_controlNetwork->FindClosest(sn,samp,line); + // TODO: test for errors and reality + if (point == NULL) { + QString message = "No points exist for deleting. Create points "; + message += "using the right mouse button."; + QMessageBox::warning((QWidget *)parent(),"Warning",message); + return; + } + deletePoint(point); + } + else if (s == Qt::RightButton) { + p_leftFile = file; + Isis::Camera *cam = cvp->camera(); + cam->SetImage(samp,line); + double lat = cam->UniversalLatitude(); + double lon = cam->UniversalLongitude(); + createPoint(lat,lon); + } + } + + + /** + * @internal + * @history 2010-06-03 Jeannie Walldren - Removed "std::" since "using + * namespace std" + * + */ + vector QnetTool::findPointFiles(double lat,double lon) { + + + // Create list of list box of all files highlighting those that + // contain the point. + vector pointFiles; + + // Initialize camera for all images in control network, + // TODO:: Needs to be moved to QnetFileTool.cpp + Isis::Camera *cam; + for (int i=0; iSize(); i++) { + cam = g_controlNetwork->Camera(i); + if (cam->SetUniversalGround(lat,lon)) { + // Make sure point is within image boundary + double samp = cam->Sample(); + double line = cam->Line(); + if (samp >= 1 && samp <= cam->Samples() && + line >= 1 && line <= cam->Lines()) { + pointFiles.push_back(g_serialNumberList->Filename(i)); + } + } + } + return pointFiles; + } + + + + /** + * Create new control point + * @internal + * @history 2008-11-20 Jeannie Walldren - Added message box if pointID value + * entered already exists for another ControlPoint. + * Previously this resulted in a PROGRAMMER ERROR from + * ControlPoint. Now, the user will be alerted in a + * message box and prompted to enter a new value for + * pointID. + * @history 2008-12-03 Tracie Sucharski - Add error message and cancel + * create new point if the point falls on a single + * image. + * @history 2008-12-15 Jeannie Walldren - Throw and catch error before + * creating QMessageBox + * @history 2009-03-09 Jeannie Walldren - Clear error message stack after it + * is displayed to user in message box. + * @history 2009-04-20 Tracie Sucharski - Set camera for each measure. + * @history 2010-06-03 Jeannie Walldren - Removed "std::" since "using + * namespace std" + * + */ + void QnetTool::createPoint(double lat,double lon) { + + // TODO: ADD AUTOSEED OPTION (CHECKBOX?) + + // Create list of list box of all files highlighting those that + // contain the point. + vector pointFiles; + + // Initialize camera for all images in control network, + // TODO:: Needs to be moved to QnetFileTool.cpp + Isis::Camera *cam; + for (int i=0; iSize(); i++) { + cam = g_controlNetwork->Camera(i); + if (cam->SetUniversalGround(lat,lon)) { + // Make sure point is within image boundary + double samp = cam->Sample(); + double line = cam->Line(); + if (samp >= 1 && samp <= cam->Samples() && + line >= 1 && line <= cam->Lines()) { + pointFiles.push_back(g_serialNumberList->Filename(i)); + } + } + } + + // If point is on a single file, print error and return, do not create + // point. + // ???? Need to allow a point to be created w/single measure. Display + // ???? measure on right or left? + if (pointFiles.size() == 1) { + try{ + throw Isis::iException::Message(Isis::iException::User, + "Cannot add point, it only exists on 1 image. Point will not be added to control network.", + _FILEINFO_); + } + catch (Isis::iException &e){ + QString message = e.Errors().c_str(); + QMessageBox::warning((QWidget *)parent(),"Warning",message); + e.Clear(); + return; + } + } + + QnetNewPointDialog *newPointDialog = new QnetNewPointDialog(); + newPointDialog->SetFiles(pointFiles); + if (newPointDialog->exec()) { + Isis::ControlPoint *newPoint = + new Isis::ControlPoint(newPointDialog->ptIdValue->text().toStdString()); + + + // If this ControlPointId already exists, message box pops up and user is asked to enter a new value. + if (g_controlNetwork->Exists(*newPoint)) { + string message = "A ControlPoint with Point Id = [" + newPoint->Id(); + message += "] already exists. Re-enter Point Id for this ControlPoint."; + QMessageBox::warning((QWidget *)parent(),"New Point Id",message.c_str()); + pointFiles.clear(); + createPoint(lat,lon); + return; + } + for (int i=0; ifileList->count(); i++) { + QListWidgetItem *item = newPointDialog->fileList->item(i); + if (!newPointDialog->fileList->isItemSelected(item)) continue; + // Create measure for any file selected + Isis::ControlMeasure *m = new Isis::ControlMeasure; + // Find serial number for this file + string sn = + g_serialNumberList->SerialNumber(item->text().toStdString()); + m->SetCubeSerialNumber(sn); + int camIndex = + g_serialNumberList->FilenameIndex(item->text().toStdString()); + cam = g_controlNetwork->Camera(camIndex); + cam->SetUniversalGround(lat,lon); + m->SetCoordinate(cam->Sample(),cam->Line()); + m->SetType(Isis::ControlMeasure::Estimated); + m->SetDateTime(); + m->SetChooserName(); + m->SetCamera(cam); + newPoint->Add(*m); + } + // Add new control point to control network + g_controlNetwork->Add(*newPoint); + // Read newly added point + p_controlPoint = + g_controlNetwork->Find(newPointDialog->ptIdValue->text().toStdString()); + // Load new point in QnetTool + //p_controlPoint = newPoint; + loadPoint(); + p_qnetTool->setShown(true); + p_qnetTool->raise(); + + emit netChanged(); + emit refreshNavList(); + emit editPointChanged(p_controlPoint->Id()); + } + } + + + + /** + * Delete control point + * @internal + * @history 2010-06-03 Jeannie Walldren - Removed "std::" since "using + * namespace std" + * + */ + void QnetTool::deletePoint(Isis::ControlPoint *point) { + + // Change point in viewport to red so user can see what point they are + // about to delete. + emit editPointChanged(point->Id()); + + p_controlPoint = point; + loadPoint(); + + QnetDeletePointDialog *deletePointDialog = new QnetDeletePointDialog; + string CPId = p_controlPoint->Id(); + deletePointDialog->pointIdValue->setText(CPId.c_str()); + // Need all files for this point + for (int i=0; iSize(); i++) { + Isis::ControlMeasure &m = (*p_controlPoint)[i]; + string file = g_serialNumberList->Filename(m.CubeSerialNumber()); + deletePointDialog->fileList->addItem(file.c_str()); + } + + if (deletePointDialog->exec()) { + // First see if entire point needs to be deleted + if (deletePointDialog->deleteAllCheckBox->isChecked()) { + // First get rid of deleted point from g_filteredPoints list + // need index in control net for pt + //int i = g_controlNetwork-> + //g_filteredPoints. + p_qnetTool->setShown(false); + g_controlNetwork->Delete(p_controlPoint->Id()); + emit refreshNavList(); + } + // Otherwise, delete measures located on images chosen + else { + for (int i=0; ifileList->count(); i++) { + QListWidgetItem *item = deletePointDialog->fileList->item(i); + if (! deletePointDialog->fileList->isItemSelected(item)) continue; + + // Delete measure from ControlPoint + p_controlPoint->Delete(i); + } + + p_leftFile = ""; + loadPoint(); + p_qnetTool->setShown(true); + p_qnetTool->raise(); + + } + } + + emit netChanged(); + emit editPointChanged(p_controlPoint->Id()); + } + + + + /** + * Modify control point + * + * @history 2009-09-15 Tracie Sucharski - Add error check for points + * with no measures. + */ + void QnetTool::modifyPoint(Isis::ControlPoint *point) { + + // If no measures, print info and return + if (point->Size() == 0) { + QString message = "This point has no measures."; + QMessageBox::warning((QWidget *)parent(),"Warning",message); + // update nav list to re-highlight old point + if (p_controlPoint != NULL) emit editPointChanged(p_controlPoint->Id()); + return; + } + p_controlPoint = point; + + // If navTool modfify button pressed, p_leftFile needs to be reset + // better way - have 2 slots + if (sender() != this) p_leftFile = ""; + loadPoint(); + p_qnetTool->setShown(true); + p_qnetTool->raise(); + emit editPointChanged(p_controlPoint->Id()); + } + + /** + * @brief Load point into QnetTool. + * @internal + * @history 2008-11-26 Jeannie Walldren - Added "Number of Measures" to + * QnetTool point information. + * @history 2010-06-03 Jeannie Walldren - Removed "std::" since "using + * namespace std" + * + */ + void QnetTool::loadPoint () { + + // If Ground point print error +// if (p_controlPoint->Type() == Isis::ControlPoint::Ground) { +// QString message = "Cannot edit ground points with a single measure at this +// } + + // Write pointId + string CPId = p_controlPoint->Id(); + QString ptId = "Point ID: " + + QString::fromStdString(CPId.c_str()); + p_ptIdValue->setText(ptId); + + // Write number of measures + QString ptsize = "Number of Measures: " + + QString::number(p_controlPoint->Size()); + p_numMeasures->setText(ptsize); + + // Set ignore box correctly + p_ignorePoint->setChecked(p_controlPoint->Ignore()); + + // Set hold box correctly + p_holdPoint->setChecked(p_controlPoint->Held()); + + // Set ground box correctly + p_groundPoint->setChecked( + p_controlPoint->Type() == Isis::ControlPoint::Ground); + + // Clear combo boxes + p_leftCombo->clear(); + p_rightCombo->clear(); + p_pointFiles.clear(); + // Need all files for this point + for (int i=0; iSize(); i++) { + Isis::ControlMeasure &m = (*p_controlPoint)[i]; + string file = g_serialNumberList->Filename(m.CubeSerialNumber()); + p_pointFiles.push_back(file); + string tempFilename = Isis::Filename(file).Name(); + p_leftCombo->addItem(tempFilename.c_str()); + p_rightCombo->addItem(tempFilename.c_str()); + } + + + // TODO: WHAT HAPPENS IF THERE IS ONLY ONE MEASURE IN THIS CONTROLPOINT?? + // + // + // Find the file from the cubeViewport that was originally used to select + // the point, this will be displayed on the left ChipViewport. + int leftIndex = 0; + // Check for reference + if (p_controlPoint->HasReference()) { + leftIndex = p_controlPoint->ReferenceIndex(); + } + else { + if (p_leftFile.length() != 0) { + string tempFilename = Isis::Filename(p_leftFile).Name(); + leftIndex = p_leftCombo->findText(QString(tempFilename.c_str())); + } + } + int rightIndex = 0; + + if (leftIndex == 0) { + rightIndex = 1; + } + else { + rightIndex = 0; + } + // Handle pts with a single measure, for now simply put measure on left/right + // Evenutally put on left with black on right?? + if (rightIndex+1 > p_controlPoint->Size()) rightIndex = 0; + p_rightCombo->setCurrentIndex(rightIndex); + p_leftCombo->setCurrentIndex(leftIndex); + + // Initialize pointEditor with measures + selectLeftMeasure(leftIndex); + selectRightMeasure(rightIndex); + } + + /** + * @internal + * @history 2010-06-03 Jeannie Walldren - Removed "std::" since "using + * namespace std" + */ + + void QnetTool::selectLeftMeasure(int index) { + string file = p_pointFiles[index]; + + string serial = g_serialNumberList->SerialNumber(file); + // Find measure for each file + p_leftMeasure = &(*p_controlPoint)[serial]; + + // If p_leftCube is not null, delete before creating new one + if (p_leftCube != NULL) delete p_leftCube; + p_leftCube = new Isis::Cube(); + p_leftCube->Open(file); + + // Update left measure of pointEditor + p_pointEditor->setLeftMeasure (p_leftMeasure,p_leftCube,p_controlPoint->Id()); + updateLeftMeasureInfo (); + + } + + + /** + * @internal + * @history 2010-06-03 Jeannie Walldren - Removed "std::" since "using + * namespace std" + */ + + + void QnetTool::selectRightMeasure(int index) { + + string file = p_pointFiles[index]; + + string serial = g_serialNumberList->SerialNumber(file); + // Find measure for each file + p_rightMeasure = &(*p_controlPoint)[serial]; + + // If p_leftCube is not null, delete before creating new one + if (p_rightCube != NULL) delete p_rightCube; + p_rightCube = new Isis::Cube(); + p_rightCube->Open(file); + + // Update left measure of pointEditor + p_pointEditor->setRightMeasure (p_rightMeasure,p_rightCube,p_controlPoint->Id()); + updateRightMeasureInfo (); + + } + + + + + /** + * @internal + * @history 2008-11-24 Jeannie Walldren - Added "Goodness of Fit" to left + * measure info. + * + */ + void QnetTool::updateLeftMeasureInfo () { + + // Set ignore measure box correctly + p_ignoreLeftMeasure->setChecked(p_leftMeasure->Ignore()); + + QString s = "Measure Type: "; + if (p_leftMeasure->Type() == Isis::ControlMeasure::Unmeasured) s+= "Unmeasured"; + if (p_leftMeasure->Type() == Isis::ControlMeasure::Manual) s+= "Manual"; + if (p_leftMeasure->Type() == Isis::ControlMeasure::Estimated) s+= "Estimated"; + if (p_leftMeasure->Type() == Isis::ControlMeasure::Automatic) s+= "Automatic"; + if (p_leftMeasure->Type() == Isis::ControlMeasure::ValidatedManual) s+= "ValidatedManual"; + if (p_leftMeasure->Type() == Isis::ControlMeasure::ValidatedAutomatic) s+= "ValidatedAutomatic"; + p_leftMeasureType->setText(s); + s = "Sample Error: " + QString::number(p_leftMeasure->SampleError()); + p_leftSampError->setText(s); + s = "Line Error: " + QString::number(p_leftMeasure->LineError()); + p_leftLineError->setText(s); + if (p_leftMeasure->GoodnessOfFit() == Isis::Null) { + s = "Goodness of Fit: Null"; + } + else s = "Goodness of Fit: " + QString::number(p_leftMeasure->GoodnessOfFit()); + p_leftGoodness->setText(s); + + } + + + + /** + * @internal + * @history 2008-11-24 Jeannie Walldren - Added "Goodness of Fit" to right + * measure info. + * @history 2010-06-03 Jeannie Walldren - Removed "std::" since "using + * namespace std" + * + */ + + void QnetTool::updateRightMeasureInfo () { + + // Set ignore measure box correctly + p_ignoreRightMeasure->setChecked(p_rightMeasure->Ignore()); + + QString s = "Measure Type: "; + if (p_rightMeasure->Type() == Isis::ControlMeasure::Unmeasured) s+= "Unmeasured"; + if (p_rightMeasure->Type() == Isis::ControlMeasure::Manual) s+= "Manual"; + if (p_rightMeasure->Type() == Isis::ControlMeasure::Estimated) s+= "Estimated"; + if (p_rightMeasure->Type() == Isis::ControlMeasure::Automatic) s+= "Automatic"; + if (p_rightMeasure->Type() == Isis::ControlMeasure::ValidatedManual) s+= "ValidatedManual"; + if (p_rightMeasure->Type() == Isis::ControlMeasure::ValidatedAutomatic) s+= "ValidatedAutomatic"; + p_rightMeasureType->setText(s); + s = "Sample Error: " + QString::number(p_rightMeasure->SampleError()); + p_rightSampError->setText(s); + s = "Line Error: " + QString::number(p_rightMeasure->LineError()); + p_rightLineError->setText(s); + if (p_rightMeasure->GoodnessOfFit() == Isis::Null) { + s = "Goodness of Fit: Null"; + } + else s = "Goodness of Fit: " + QString::number(p_rightMeasure->GoodnessOfFit()); + p_rightGoodness->setText(s); + } + + + void QnetTool::addMeasure() { + + // Create list of list box of all files highlighting those that + // contain the point, but that do not already have a measure. + vector pointFiles; + + // Initialize camera for all images in control network, + // TODO:: Needs to be moved to QnetFileTool.cpp + Isis::Camera *cam; + + // If no apriori lat/lon for this point, use lat/lon of first measure + double lat = p_controlPoint->UniversalLatitude(); + double lon = p_controlPoint->UniversalLongitude(); + if (lat == Isis::Null || lon == Isis::Null) { + Isis::ControlMeasure m = (*p_controlPoint)[0]; + int camIndex = g_serialNumberList->SerialNumberIndex(m.CubeSerialNumber()); + cam = g_controlNetwork->Camera(camIndex); + //cam = m.Camera(); + cam->SetImage(m.Sample(),m.Line()); + lat = cam->UniversalLatitude(); + lon = cam->UniversalLongitude(); + } + + for (int i=0; iSize(); i++) { + cam = g_controlNetwork->Camera(i); + if (cam->SetUniversalGround(lat,lon)) { + // Make sure point is within image boundary + double samp = cam->Sample(); + double line = cam->Line(); + if (samp >= 1 && samp <= cam->Samples() && + line >= 1 && line <= cam->Lines()) { + pointFiles.push_back(g_serialNumberList->Filename(i)); + } + } + } + + QnetNewMeasureDialog *newMeasureDialog = new QnetNewMeasureDialog(); + newMeasureDialog->SetFiles(*p_controlPoint,pointFiles); + if (newMeasureDialog->exec()) { + for (int i=0; ifileList->count(); i++) { + QListWidgetItem *item = newMeasureDialog->fileList->item(i); + if (!newMeasureDialog->fileList->isItemSelected(item)) continue; + // Create measure for any file selected + Isis::ControlMeasure *m = new Isis::ControlMeasure; + // Find serial number for this file + string sn = + g_serialNumberList->SerialNumber(item->text().toStdString()); + m->SetCubeSerialNumber(sn); + int camIndex = + g_serialNumberList->FilenameIndex(item->text().toStdString()); + cam = g_controlNetwork->Camera(camIndex); + cam->SetUniversalGround(lat,lon); + m->SetCoordinate(cam->Sample(),cam->Line()); + m->SetType(Isis::ControlMeasure::Estimated); + m->SetDateTime(); + m->SetChooserName(); + p_controlPoint->Add(*m); + } + loadPoint(); + p_qnetTool->setShown(true); + p_qnetTool->raise(); + + emit netChanged(); + emit editPointChanged(p_controlPoint->Id()); + } + + } + + + bool QnetTool::eventFilter (QObject *o, QEvent *e) { + if (e->type() != QEvent::Leave) return false; + if (o == p_leftCombo->view()) { + updateLeftMeasureInfo (); + p_leftCombo->hidePopup(); + } + if (o == p_rightCombo->view()) { + updateRightMeasureInfo (); + p_rightCombo->hidePopup(); + } + return true; + } + + + // Take care of drawing things on a viewPort. + // This is overiding the parents paintViewport member. + void QnetTool::paintViewport (MdiCubeViewport *vp,QPainter *painter) { + + drawAllMeasurments (vp,painter); + + } + + + /** + * @internal + * @history 2010-06-03 Jeannie Walldren - Removed "std::" since "using + * namespace std" + */ + void QnetTool::paintAllViewports (string pointId) { + // Take care of drawing things on all viewPorts. + // Calling update will cause the Tool class to call all registered tools + MdiCubeViewport *vp; + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + vp = (*(cubeViewportList()))[i]; + vp->viewport()->update(); + } + + } + + + /** + * Draw all measurments which are on this viewPort + * @internal + * @history 2010-06-03 Jeannie Walldren - Removed "std::" since "using + * namespace std" + * @history 2010-06-08 Jeannie Walldren - Fixed bug that was causing ignored + * measures not be drawn as yellow unless QnetTool was + * open + * @history 2010-07-01 Jeannie Walldren - Modified to draw points selected in + * QnetTool last so they lay on top of all other points + * in the image. + */ + void QnetTool::drawAllMeasurments (MdiCubeViewport *vp,QPainter *painter) { + // Without a controlnetwork there are no points + if (g_controlNetwork == 0) return; + + // Don't show the measurments on cubes not in the serial number list + // TODO: Should we show them anyway + // TODO: Should we add the SN to the viewPort + string serialNumber = Isis::SerialNumber::Compose(*vp->cube()); + if (!g_serialNumberList->HasSerialNumber(serialNumber)) return; + + // loop through all points in the control net + for (int i=0; iSize(); i++) { + Isis::ControlPoint &p = (*g_controlNetwork)[i]; + // loop through the measurements + for (int j=0; jcubeToViewport(samp,line,x,y); + // if the point is ignored, + if (p.Ignore()) { + painter->setPen(QColor(255,255,0)); // set point marker yellow + } + // point is not ignored + // if the measure matching this image is ignored, + else if (p[j].Ignore()){ + painter->setPen(QColor(255,255,0)); // set point marker yellow + } + // Neither point nor measure is not ignored and the measure is ground, + else if (p.Type() == Isis::ControlPoint::Ground) { + painter->setPen(Qt::magenta);// set point marker magenta + } + else { + painter->setPen(Qt::green); // set all other point markers green + } + // draw points + painter->drawLine(x-5,y,x+5,y); + painter->drawLine(x,y-5,x,y+5); + } + // if point is not in the image, go to next point + else continue; + } + } + // if QnetTool is open, + if (p_controlPoint != NULL) { + // and the selected point is in the image, + if (p_controlPoint->HasSerialNumber(serialNumber)) { + // find the measurement + double samp = (*p_controlPoint)[serialNumber].Sample(); + double line = (*p_controlPoint)[serialNumber].Line(); + int x,y; + vp->cubeToViewport(samp,line,x,y); + // set point marker red + QBrush brush(Qt::red); + // set point marker bold - line width 2 + QPen pen(brush, 2); + // draw the selected point in each image last so it's on top of the rest of the points + painter->setPen(pen); + painter->drawLine(x-5,y,x+5,y); + painter->drawLine(x,y-5,x,y+5); + } + } + } + + + /** + * Allows user to set a new template file. + * @author 2008-12-10 Jeannie Walldren + * @internal + * @history 2008-12-10 Jeannie Walldren - Original Version + */ + + void QnetTool::setTemplateFile() { + p_pointEditor->setTemplateFile(); + } + + + + + /** + * Allows the user to view the template file that is currently + * set. + * @author 2008-12-10 Jeannie Walldren + * @internal + * @history 2008-12-10 Jeannie Walldren - Original Version + * @history 2008-12-10 Jeannie Walldren - Added "Isis::" namespace to + * PvlEditDialog reference and changed + * registrationDialog from pointer to object + * @history 2008-12-15 Jeannie Walldren - Added QMessageBox warning in case + * Template File cannot be read. + */ + void QnetTool::viewTemplateFile() { + try{ + // Get the template file from the ControlPointEditor object + Isis::Pvl templatePvl(p_pointEditor->templateFilename()); + // Create registration dialog window using PvlEditDialog class + // to view and/or edit the template + Isis::PvlEditDialog registrationDialog(templatePvl); + registrationDialog.setWindowTitle("View or Edit Template File: " + + QString::fromStdString(templatePvl.Filename())); + registrationDialog.resize(550,360); + registrationDialog.exec(); + } + catch (Isis::iException &e){ + QString message = e.Errors().c_str(); + e.Clear (); + QMessageBox::information((QWidget *)parent(),"Error",message); + } + } + + + + /** + * Slot which calls ControlPointEditor slot to save chips + * @author 2009-03-17 Tracie Sucharski + */ + + void QnetTool::saveChips() { + p_pointEditor->saveChips(); + } + + + + + /** + * Refresh all necessary widgets in QnetTool including the PointEditor and + * CubeViewports. + * + * @author 2008-12-09 Tracie Sucharski + * + */ + void QnetTool::refresh() { + + // Check point being edited, make sure it still exists, if not ??? + // Update ignored checkbox?? + if (p_controlPoint != NULL) { + try { + QString id = p_ptIdValue->text().remove("Point ID: "); + Isis::ControlPoint *pt = + g_controlNetwork->Find(id.toStdString()); + pt = 0; + } catch ( Isis::iException &e ) { + p_controlPoint = NULL; + p_qnetTool->setShown(false); + } + } + + if (p_controlPoint == NULL) { + paintAllViewports(""); + } + else { + paintAllViewports(p_controlPoint->Id()); + } + } + + /** + * Emits a signal to displays the Navigation window. This signal is connected + * to QnetNavTool. + * @internal + * @history 2010-07-01 Jeannie Walldren - Original version + */ + void QnetTool::showNavWindow(){ + emit showNavTool(); + } + + /** + * This method creates the widgets for the tool bar. A "Show Nav Tool" button + * is created so that the navigation tool may be reopened if it has been closed. + * + * @param parent + * @return QWidget* + * + * @internal + * @todo Find a way to enable Show Nav Button even when there are no images open + * in the main window. + * + * @history 2010-07-01 Jeannie Walldren - Original version. + */ + QWidget *QnetTool::createToolBarWidget (QStackedWidget *parent) { + QWidget *hbox = new QWidget(parent); + + QToolButton *showNavToolButton = new QToolButton(); + showNavToolButton->setText("Show Nav Tool"); + showNavToolButton->setToolTip("Shows the Navigation Tool Window"); + QString text = + "Function: This button will bring up the Navigation Tool window that allows \ + the user to view, modify, ignore, delete, or filter points and cubes."; + showNavToolButton->setWhatsThis(text); + connect(showNavToolButton,SIGNAL(clicked()),this,SLOT(showNavWindow())); + + QHBoxLayout *layout = new QHBoxLayout(hbox); + layout->setMargin(0); + layout->addWidget(showNavToolButton); + layout->addStretch(1); + hbox->setLayout(layout); + return hbox; + } +} + diff --git a/isis/src/qisis/apps/qnet/QnetTool.h b/isis/src/qisis/apps/qnet/QnetTool.h new file mode 100644 index 0000000000000000000000000000000000000000..d99ecdfbc95b8ae4181d09ba2c65f2666989ae1e --- /dev/null +++ b/isis/src/qisis/apps/qnet/QnetTool.h @@ -0,0 +1,221 @@ +#ifndef QnetTool_h +#define QnetTool_h + +// name space Isis classes don't work with forward declarations? +#include "ControlMeasure.h" +#include "ControlPoint.h" +#include "Cube.h" +#include "Tool.h" // parent class + +// forward declarations +class QAction; +class QCheckBox; +class QComboBox; +class QLabel; +class QMainWindow; +class QObject; +class QPainter; +class QPoint; +class QStackedWidget; +class QString; +class QWidget; + +using namespace std; + +namespace Qisis { +class ControlPointEdit; +class MdiCubeViewport; +class QnetHoldPointDialog; +class ToolPad; + /** + * @brief Qnet tool operations + * + * @ingroup Visualization Tools + * + * + * @internal + * @history 2008-11-24 Jeannie Walldren - Changed name from TieTool. + * Replace references to PointEdit class with + * ControlPointEdit. Added "Goodness of Fit" to right + * and left measure info. + * @history 2008-11-26 Jeannie Walldren - Added "Number of Measures" to + * QnetTool point information. Defined updateNet() so + * that the QnetTool window's title bar contains the + * name of the control net file. Created + * ignoreChanged() signal, modified pointSaved() and + * createQnetTool() so message box appears if users are + * saving an "Ignore" point and asks whether they would + * like to set Ignore=false. + * @history 2008-12-09 Tracie Sucharski - Cleaned up some + * signal/slot connections between QnetTool and + * QnetNavTool for deleting or adding ControlPoints. + * @history 2008-12-09 Tracie Sucharski - Add new public slot + * refresh to handle the ignorePoints and deletePoints + * from the QnetNavTool. + * @history 2008-12-10 Jeannie Walldren - Added slot methods + * viewTemplateFile() and setTemplateFile() to allow + * user to view, edit or choose a new template file. + * Added "What's this?" descriptions to actions. + * @history 2008-12-15 Jeannie Walldren - Some QMessageBox + * warnings had strings tacked on to the list of + * errors. These strings were changed to iExceptions + * and added to the error stack to conform with Isis + * standards. + * @history 2008-12-15 Jeannie Walldren - Created newHoldPoint() method. + * Replaced references to QnetGroundPointDialog with + * QnetHoldPointDialog. Disabled ground point check box + * so user may see whether the point is ground but may + * not change this. Thus setGroundPoint() and + * newGroundPoint() methods still exist but are not + * currently called. + * @history 2008-12-30 Jeannie Walldren - Modified to set measures in + * viewports to Ignore=False if when saving, the user + * chooses to set a point's Ignore=False. Replaced + * references to ignoreChanged() with + * ignorePointChanged(). Added signals + * ignoreLeftChanged() and ignoreRightChanged(). + * @history 2008-12-31 Jeannie Walldren - Added question box to pointSaved() + * method to ask user whether the reference measure + * should be replaced with the measure in the left + * viewport. Added documentation. + * @history 2009-03-09 Jeannie Walldren - Modified createPoint() method to + * clear the error stack after displaying a QMessageBox + * to the user + * @history 2009-03-17 Tracie Sucharski - Added the ability to save the + * registration chips to the Options menu. + * @history 2010-01-27 Jeannie Walldren - Fixed bug in setIgnoreLeftMeasure() + * and setIgnoreRightMeasure() that caused segmentation + * faults. Added question box to warn user that they + * are saving changes to an ignored measure. + * @history 2010-06-02 Jeannie Walldren - Added cancelHoldPoint() method and + * connected this slot to QnetHoldPointDialog's + * holdCancelled() signal. + * @history 2010-06-03 Jeannie Walldren - Initialized pointers to null in + * constructor. + * @history 2010-06-08 Jeannie Walldren - Fixed bug in drawAllMeasurments() so + * that points with ignored measures matching the image + * shown are drawn as yellow unless the QnetTool is + * open to this point. Changed QMessageBox types for + * consistency with other qnet warnings and errors + * @history 2010-07-01 Jeannie Walldren - Added createToolBarWidget(), + * showNavWindow() methods to reopen NavTool + * (if closed) whenever the Tie tool button on the tool + * pad is clicked. Modified drawAllMeasurments() to + * draw points selected in QnetTool last so they lay on + * top of all other points in the image. Replaced + * #includes with forward class declarations and moved + * #include to .cpp file. + * + */ + class QnetTool : public Tool { + Q_OBJECT + + public: + QnetTool (QWidget *parent); +// void addTo (QMenu *menu); + void paintViewport (MdiCubeViewport *cvp,QPainter *painter); + + signals: + void qnetToolSave(); + void refreshNavList(); + void editPointChanged(string pointId); + void netChanged(); + void ignorePointChanged(); + void ignoreLeftChanged(); + void ignoreRightChanged(); + void showNavTool(); + + public slots: + void updateList(); + void updateNet(QString cNetFilename); + void createPoint(double lat,double lon); + void modifyPoint(Isis::ControlPoint *point); + void deletePoint(Isis::ControlPoint *point); + void refresh(); + + protected: + QAction *toolPadAction(ToolPad *pad); + bool eventFilter(QObject *o,QEvent *e); + + protected slots: + void mouseButtonRelease(QPoint p, Qt::MouseButton s); + QWidget *createToolBarWidget (QStackedWidget *parent); + + private slots: + void paintAllViewports (string pointId); + void saveNet(); + void addMeasure(); + void setIgnorePoint (bool ignore); + void newHoldPoint (Isis::ControlPoint &point); + void setHoldPoint (bool hold); + void cancelHoldPoint (); + void newGroundPoint (Isis::ControlPoint &point); + void setGroundPoint (bool ground); + void setIgnoreLeftMeasure (bool ignore); + void setIgnoreRightMeasure (bool ignore); + void showNavWindow (); + + void selectLeftMeasure (int index); + void selectRightMeasure (int index); + void updateLeftMeasureInfo (); + void updateRightMeasureInfo (); + + void pointSaved (); + + void setTemplateFile(); + void viewTemplateFile(); + void saveChips(); + //void setInterestOp(); + + private: + void createQnetTool(QWidget *parent); + QMainWindow *p_qnetTool; + void createMenus(); + + void loadPoint(); + void drawAllMeasurments (MdiCubeViewport *vp,QPainter *painter); + + + vector findPointFiles(double lat,double lon); + + QAction *p_createPoint; + QAction *p_modifyPoint; + QAction *p_deletePoint; + + QMainWindow *p_mw; + ControlPointEdit *p_pointEditor; + + QLabel *p_ptIdValue; + QLabel *p_numMeasures; + QCheckBox *p_ignorePoint; + QCheckBox *p_holdPoint; + QCheckBox *p_groundPoint; + QLabel *p_leftMeasureType; + QLabel *p_leftSampError; + QLabel *p_leftLineError; + QLabel *p_leftGoodness; + QLabel *p_rightMeasureType; + QLabel *p_rightSampError; + QLabel *p_rightLineError; + QLabel *p_rightGoodness; + QCheckBox *p_ignoreLeftMeasure; + QCheckBox *p_ignoreRightMeasure; + + QComboBox *p_leftCombo; + QComboBox *p_rightCombo; + + Isis::ControlPoint *p_controlPoint; + + vector p_pointFiles; + + string p_leftFile; + Isis::ControlMeasure *p_leftMeasure; + Isis::ControlMeasure *p_rightMeasure; + Isis::Cube *p_leftCube; + Isis::Cube *p_rightCube; + + QnetHoldPointDialog *p_holdPointDialog; + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qnet/qnet.cpp b/isis/src/qisis/apps/qnet/qnet.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0048eeeaf2ed270dfe3db6a200b28928d7451c7f --- /dev/null +++ b/isis/src/qisis/apps/qnet/qnet.cpp @@ -0,0 +1,196 @@ +#include +#include "AdvancedTrackTool.h" +#include "BandTool.h" +#include "Filename.h" +#include "FindTool.h" +#include "HelpTool.h" +#include "HistogramTool.h" +#include "iException.h" +#include "PanTool.h" +#include "Preference.h" +#include "PvlGroup.h" +#include "QnetFileTool.h" +#include "QnetTool.h" +#include "QnetNavTool.h" +#include "RubberBandTool.h" +#include "StatisticsTool.h" +#include "StretchTool.h" +#include "ViewportMainWindow.h" +#include "WindowTool.h" +#include "ZoomTool.h" + +#define IN_QNET +#include "qnet.h" + +using namespace std; + +int main (int argc, char *argv[]) { + Qisis::Qnet::g_controlNetwork = NULL; + Qisis::Qnet::g_serialNumberList = NULL; + + try { + QApplication *app = new QApplication(argc,argv); + QApplication::setApplicationName("qnet"); + + // check for forcing of gui style + Isis::PvlGroup & uiPref = Isis::Preference::Preferences().FindGroup( + "UserInterface"); + if (uiPref.HasKeyword("GuiStyle")) + { + string style = uiPref["GuiStyle"]; + QApplication::setStyle((Isis::iString) style); + } + + // Add the Qt plugin directory to the library path + Isis::Filename qtpluginpath ("$ISISROOT/3rdParty/plugins"); + QCoreApplication::addLibraryPath(qtpluginpath.Expanded().c_str()); + + Qisis::Qnet::g_vpMainWindow = new Qisis::ViewportMainWindow("qnet"); + + Qisis::Tool *rubberBandTool = Qisis::RubberBandTool::getInstance(Qisis::Qnet::g_vpMainWindow); + rubberBandTool->addTo(Qisis::Qnet::g_vpMainWindow); + + /**** ADD FILE TOOL FIRST SO THAT IT APPEARS FIRST IN THE PERMANENT AND MENU TOOLBARS ****/ + // adds file tool buttons and separator on permanent toolbar + // adds to "File" dropdown of Menu toolbar + Qisis::QnetFileTool *ftool = new Qisis::QnetFileTool(Qisis::Qnet::g_vpMainWindow); + ftool->Tool::addTo(Qisis::Qnet::g_vpMainWindow); + Qisis::Qnet::g_vpMainWindow->permanentToolBar()->addSeparator(); + + Qisis::QnetNavTool *ntool = new Qisis::QnetNavTool(Qisis::Qnet::g_vpMainWindow); + ntool->Tool::addTo(Qisis::Qnet::g_vpMainWindow); + + /**** ADD TOOLS TO TOOL PAD ON LEFT/RIGHT ****/ + // adds band tool button to toolpad on left + Qisis::Tool *btool = new Qisis::BandTool(Qisis::Qnet::g_vpMainWindow); + btool->addTo(Qisis::Qnet::g_vpMainWindow); + + // adds zoom tool button to toolpad on left + // adds to "View" dropdown of Menu toolbar with seperator + Qisis::Tool *ztool = new Qisis::ZoomTool(Qisis::Qnet::g_vpMainWindow); + ztool->addTo(Qisis::Qnet::g_vpMainWindow); + Qisis::Qnet::g_vpMainWindow->getMenu("&View")->addSeparator(); + + // adds pan tool button to toolpad on left + // adds to "View" dropdown of Menu toolbar with seperator + Qisis::Tool *ptool = new Qisis::PanTool(Qisis::Qnet::g_vpMainWindow); + ptool->addTo(Qisis::Qnet::g_vpMainWindow); + Qisis::Qnet::g_vpMainWindow->getMenu("&View")->addSeparator(); + + // adds stretch tool button to toolpad on left + Qisis::Tool *stool = new Qisis::StretchTool(Qisis::Qnet::g_vpMainWindow); + stool->addTo(Qisis::Qnet::g_vpMainWindow); + + // adds find tool button to toolpad on left + // adds to "Options" dropdown of Menu toolbar + Qisis::Tool *findTool = new Qisis::FindTool(Qisis::Qnet::g_vpMainWindow); + findTool->addTo(Qisis::Qnet::g_vpMainWindow); + + // adds hist tool button to toolpad on left + // adds PlotTool to "Options" dropdown of Menu toolbar + Qisis::Tool *histtool = new Qisis::HistogramTool(Qisis::Qnet::g_vpMainWindow); + histtool->addTo(Qisis::Qnet::g_vpMainWindow); + + // adds stats tool button to toolpad on left + Qisis::Tool *statstool = new Qisis::StatisticsTool(Qisis::Qnet::g_vpMainWindow); + statstool->addTo(Qisis::Qnet::g_vpMainWindow); + + // adds tie tool button to toolpad on left + // sets tie tool to active button + Qisis::Tool *qnetTool = new Qisis::QnetTool(Qisis::Qnet::g_vpMainWindow); + qnetTool->addTo(Qisis::Qnet::g_vpMainWindow); + qnetTool->activate(true); + + /**** ADD REMAINING TOOLS TO PERMANENT TOOL PAD ON TOP/BOTTOM ****/ + // adds adv track tool button permanent toolbar + // adds to "Options" dropdown of Menu toolbar + Qisis::Tool *ttool = new Qisis::AdvancedTrackTool(Qisis::Qnet::g_vpMainWindow); + ttool->addTo(Qisis::Qnet::g_vpMainWindow); + + // adds window tool (Link viewports) button and seperator to permanent toolbar + // adds "Windows" dropdown of Menu toolbar + Qisis::Tool *wtool = new Qisis::WindowTool(Qisis::Qnet::g_vpMainWindow); + wtool->addTo(Qisis::Qnet::g_vpMainWindow); + Qisis::Qnet::g_vpMainWindow->permanentToolBar()->addSeparator(); + + // adds help tool button to permanent toolbar + // adds "Help" dropdown of Menu toolbar + Qisis::Tool *htool = new Qisis::HelpTool(Qisis::Qnet::g_vpMainWindow); + htool->addTo(Qisis::Qnet::g_vpMainWindow); + + /**** MAKE CONNECTIONS ****/ + /**** LOADING IMAGES ****/ + // The fileTool needs to know when the navTool wants to load images + QObject::connect(ntool,SIGNAL(loadImage(const QString &)), + ftool,SLOT(loadImage(const QString &))); + // The fileTool needs to know when to load the images associated with a point + QObject::connect(ntool,SIGNAL(loadPoint(Isis::ControlPoint *)), + ftool,SLOT(loadPoint(Isis::ControlPoint *))); + + /**** UPDATING LIST ****/ + // The navTool needs to know when the file tool has changed the serialNumberList + QObject::connect(ftool,SIGNAL(serialNumberListUpdated()), + ntool,SLOT(resetList())); + // The navTool cube name filter needs to know when the file tool + // has changed the serialNumberList in order to refresh the list + // Jeannie Walldren 2009-01-26 + QObject::connect(ftool,SIGNAL(serialNumberListUpdated()), + ntool,SLOT(resetCubeList())); + // The QnetTool needs to know when the file tool has changed the + // serialNumberList and the controlnetwork. + // QObject::connect(ftool,SIGNAL(serialNumberListUpdated()), + // qnetTool,SLOT(updateList())); + + /**** MAKE NAV TOOL DIALOG VISIBLE ****/ + // NavigationTool needs to know when the QnetTool (Tie Tool) has been + // acitvated on the tool pad in order to reopen the NavTool, if necessary. + // 2010-07-01 Jeannie Walldren + QObject::connect(qnetTool,SIGNAL(showNavTool()),ntool,SLOT(showNavTool())); + + /**** MODIFYING POINTS ****/ + // Qnet Tool needs to know when navTool modifies/ignores/deletes points + QObject::connect(ntool,SIGNAL(modifyPoint(Isis::ControlPoint *)), + qnetTool,SLOT(modifyPoint(Isis::ControlPoint *))); + QObject::connect(ntool,SIGNAL(ignoredPoints()),qnetTool,SLOT(refresh())); + QObject::connect(ntool,SIGNAL(deletedPoints()),qnetTool,SLOT(refresh())); + + /**** RECORDING POINTS ****/ + // Connect the FindTool to the AdvancedTrackTool to record the point if the + // "record" button is clicked in FindTool's dialog + QObject::connect(findTool, SIGNAL(recordPoint(QPoint)), + ttool, SLOT(record(QPoint))); + + /**** UPDATING CONTROL NETWORK ****/ + // the next command was uncommented to allows the QnetTool to display the name + // of the control network file and update when a new control network is selected + // 2008-11-26 Jeannie Walldren + QObject::connect(ftool,SIGNAL(controlNetworkUpdated(QString)), + qnetTool,SLOT(updateNet(QString))); + QObject::connect(qnetTool,SIGNAL(editPointChanged(string)), + ntool,SLOT(updateEditPoint(string))); + QObject::connect(qnetTool,SIGNAL(refreshNavList()), + ntool,SLOT(refreshList())); + + /**** SAVING CONTROL NET CHANGES ****/ + // The FileTool needs to now if the control network has changed (delete/ + // edit/create/ignore point) so that user can be prompted to save net + QObject::connect(qnetTool,SIGNAL(netChanged()),ftool,SLOT(setSaveNet())); + QObject::connect(ntool,SIGNAL(netChanged()),ftool,SLOT(setSaveNet())); + QObject::connect(qnetTool,SIGNAL(qnetToolSave()),ftool,SLOT(saveAs())); + + + /**** EXITING ****/ + // Connect the viewport's close signal to the file tool's exit method + // Added 2008-12-04 by Jeannie Walldren + QObject::connect(Qisis::Qnet::g_vpMainWindow , + SIGNAL(closeWindow()), ftool, SLOT(exit())); + //----------------------------------------------------------------- + + Qisis::Qnet::g_vpMainWindow->show(); + return app->exec(); + } + catch (Isis::iException &e) { + e.Report(); + } +} + diff --git a/isis/src/qisis/apps/qnet/qnet.h b/isis/src/qisis/apps/qnet/qnet.h new file mode 100644 index 0000000000000000000000000000000000000000..a720eba370278532e2751b2e3e4b4471794a2ed0 --- /dev/null +++ b/isis/src/qisis/apps/qnet/qnet.h @@ -0,0 +1,27 @@ +#ifndef Qnet_h +#define Qnet_h + +#include "SerialNumberList.h" +#include "ControlNet.h" +#include "ViewportMainWindow.h" + +#ifdef IN_QNET +#define EXTERN +#else +#define EXTERN extern +#endif + +namespace Qisis { + namespace Qnet { + EXTERN Isis::SerialNumberList *g_serialNumberList; + EXTERN Isis::ControlNet *g_controlNetwork; + EXTERN Qisis::ViewportMainWindow *g_vpMainWindow; + EXTERN QList g_filteredImages; + EXTERN QList g_filteredOverlaps; + EXTERN QList g_filteredPoints; + EXTERN QList g_loadedImages; + } +} + +#endif + diff --git a/isis/src/qisis/apps/qnet/qnet.xml b/isis/src/qisis/apps/qnet/qnet.xml new file mode 100644 index 0000000000000000000000000000000000000000..1caf4c2834a32731b5eecb4dae373f4e75e432d8 --- /dev/null +++ b/isis/src/qisis/apps/qnet/qnet.xml @@ -0,0 +1,321 @@ + + + + + Create and edit control networks + + + +

    + This program will create and edit control networks. To run qnet, you will + need to create a text file containing a list of all cubes in the control + network. There are 3 core windows used in this application. +

    + +

    qnet window

    + The main qnet window is similar to the qview application. You will see + many of the same tools, such as "Band Selection", "Zoom", "Pan", + "Stretch" and "Find" along the right border. The "Tie" tool is the last + button along the right toolbar. It will be the default tool selected when + "qnet" is launched. +

    + In this window, select the "Open network" button or the open action (from + File menu), and open the file containing the list of cubes in the network. + You will then be prompted for the control network file. If you are editing + an existing one, choose that file. If you are creating a new control + network, choose the "Cancel" button. +

    +

    + Cubes may be opened in the main qnet window selected from the list in + the Control Network Navigator window. Points on these cubes are color + coded as follows: +

    +
    +      green "+" control point 
    +
    +      magenta "+" ground point
    +
    +      yellow "+" ignore point 
    +
    +      red "+" point currently being edited (i.e. in Qnet Tool window) 
    +      
    +      window) 
    +    
    + When the "Tie" tool is activated, the mouse buttons have the following + function in the cube viewports of the main qnet window: +
    +      Left Button:  Modify the closest control point
    +
    +      Middle Button:  Delete the closest control point 
    +
    +      Right Button:  Create new control point
    +    
    + +

    Control Network Navigator window

    +

    + The Control Network Navigator displays a list of cubes or points in the + control network. The user may choose to open cube(s) in the qnet window or + filter the list on different attributes. +

    +

    + Points - default list for the Control Network Navigator. + With this selected, the user may click any of the following buttons: +

    +
    +      "View Cube(s)" to open all cubes containing the selected 
    +      point(s) 
    +
    +      "Modify Point" (or double click list 
    +      item) to edit the point using the Qnet Tool 
    +      
    +      "Ignore Point(s)" to set selected points to "Ignore"
    +      
    +      "Delete Point(s)" to remove selected points from the 
    +      control network 
    +      
    +      "Filter" to list all points from the currently displayed
    +      list that meet the new filtering criteria selected.  **Note** If the 
    +      currently displayed list is already filtered, the new list will only 
    +      display points that meet the criteria of all filters previously chosen
    +      until the user resets the list.
    +      
    +      "Show All" to reset the displayed list to all points in 
    +      the network 
    +    
    + There are 9 filters for the points list which display the following: +
    +      Error: points with bundle adjustment errors within the 
    +      user specified range 
    +      
    +      Point ID: points whose Point Id contains the user 
    +      specified string 
    +      
    +      Number of Measures: points that are contained in (at 
    +      least or no more than) the user specified number of images 
    +      
    +      Point Properties: points that have the user specified 
    +        property.  Note: If all of the measures in a point are ignored, then 
    +        this point will be returned in the ignored point filter.
    +      
    +      Range: points that lie within the user specified 
    +      latitudinal and longitudinal ranges 
    +      
    +      Distance: points that are within the user specified 
    +      distance of some other point in the control network 
    +      
    +      Measure Properties: points that contain at least one 
    +        measure that matches the selected ingore status and one of the selected 
    +        types 
    +      
    +      Goodness of Fit: points that contain at least one measure 
    +      whose Goodness of Fit is within the user specified range 
    +
    +      Cube Name(s): points that contain at a measure whose 
    +      serial number matches that of the user chosen cube filename
    +    
    +

    + Cubes - With this selected, the user may click any of the + following buttons: +

    +
    +      "View Cube(s)" to open all selected cubes  
    +      
    +      "Filter" to list all cubes from the currently displayed
    +      list that meet the new filtering criteria selected.  **Note** If the 
    +      currently displayed list is already filtered, the new list will only 
    +      display cubes that meet the criteria of all filters previously chosen
    +      until the user resets the list.
    +      
    +      "Show All" to reset the list to all images in the network 
    +    
    + There are 3 filters for the cubes list which display the following: +
    +      Cube Name: cubes whose file name contains the user 
    +      specified string 
    +      
    +      Number of Points: cubes containing (at least or no more 
    +      than) the user specified number of points 
    +      
    +      Distance: cubes that contain at least one pair of points 
    +      that are within the user specified distance from each other 
    +    
    + +

    Qnet Tool window

    + This is the point editor window of qnet for modifying or creating a + point. The window will display the cube that is the "Reference" cube + on the left and the next cube in the control point on the right. Only + the control measure on the right hand side can be moved. The measure + can be adjusted by: +
    +      move to the cursor position under the crosshair by clicking the left mouse button
    +
    +      move 1 pixel at a time by using arrow keys on the keyboard 
    +
    +      move 1 pixel at a time by using arrow buttons above the right view
    +    
    + Other point editor functions / options include the following: +
    +      In the Options menu:
    +        Registration: Set or view and save registration 
    +        templates.
    +      
    +      Along the left border of the window:
    +        Geom:  Geom the right view to match the left view 
    +        
    +        Rotate:  Rotate the right view
    +    
    +      Below the left view:
    +        Blink controls:  Blink the left and right view in the
    +        left view window using the "Blink Start" button (with play icon) and 
    +        "Blink Stop" button (with stop icon).  The arrow keys above the right view 
    +        may be used to move the right view in order to update the blinking in real 
    +        time.
    +      
    +        Find:   Center the right view so that the same latitude / 
    +        longitude is under the crosshair as the left view. 
    +        
    +        Add Measure(s) to Point:  Add control measure(s) to the 
    +        current control point. 
    +      
    +      Below the right view:
    +        Register:  Sub-pixel register the the right view to
    +        the left view.
    +        
    +        Save Point:  Save the control measure under the right 
    +        view in the control network. 
    +    
    +
    + + + Control Networks + Display + + + + + Original version + + + Added to Control Networks category + + + Refactor of underlying classes + + + Changed the name of the "Tie Point Tool" window to "Qnet Tool". + + Added "Close" command to the drop down File menu on the "Qnet Tool" + window's menu bar. + + Added Qt's wait cursor (i.e. clock or hourglass) to indicate that there is + background activity when the "Filter" or "View Cube(s)" buttons have been + clicked on the "Control Network Navigator" window. + + Added message box when the user creates a new point and tries to give it a + Point ID that already exists in the Control network. Previously this + resulted in a PROGRAMMER ERROR from ControlPoint. Now, the user will be + alerted in a message box and prompted to enter a new value for the Point + ID. + + Replaced references to PointEdit class with ControlPointEdit. + + Added "Goodness of Fit" to "Qnet Tool" right and left measure info. + + + Added "Goodness of Fit" filter to the tabs for the "Points" section of the + "Control Network Navigator" window. This filter returns all points that + have at least one measure that falls inside the user specified range. + + Added "Number of Measures" to "Qnet Tool" window below "Point ID". + + Modified code to pre-set the Point ID value in the "New Point Dialog" + window to the last Point ID entered in the dialog box. This value is + highlighted so the user may begin typing over the name without needing to + backspace. + + Changed the "Qnet Tool" title bar to display the name of the ControlNet + file open. + + Added message box when saving an "Ignore" point in the "Qnet Tool" to ask + if user wants to set Ignore=false. + + Modified the "Distance" filter in the "Points" section of the "Control + Network Navigator" window to improve efficiency and accuracy. + + + Removed plot tool and all polygon references-this funtionality will be in + qmos. + + + Modified the "Distance" filter in the "Cubes" section of the "Control + Network Navigator" window to improve efficiency and accuracy, and to allow + the user to select a distance in meters or pixels. + + + Added connection from "x" in upper right corner to "Exit" command under + the "File" menu of the main window. + + + Added functionality to "Qnet Tool" can set, view, edit and save changes + for a template file. This is located in the "Options" menu under + "Registration" as the "Set registration template" and "View/edit + registration template" actions. Added "What's this?" descriptions to + "Qnet Tool" window actions. + + + Added "Ignore Points" and "Delete Points" to the Control Navigator tool. + + + Added question boxes when the "Delete Points" or "Ignore Points" buttons + are clicked in the Control Navigator to verify that the user wants to + delete or ignore the selected points. Disabled "Ground Point" checkbox + in Qnet Tool window and added dialog window for determining + lat/lon/radius if user chooses to toggle the "Hold Point" checkbox to + true. + + + Modified Qnet Tool "Save Point" button to set the left and right measures + to Ignore=False if the user chooses to set the point's Ignore=False. + Also, "Save Point" button will now update ChooserName and DateTime + keywords for altered measures. Modified Control Network Navigator points + list to set most recently edited point to the current item so that it may + be easily deleted. + + + Added keyboard shortcuts to buttons in Control Network Navigator window. + Added question box to Qnet Tool "Save Point" button to ask user whether + the reference measure should be replaced with the measure in the left + viewport. + + + Updated user documentation. Modified Control Network Navigator window to + filter on existing filtered list until user selects the "Show All" button, + which will bring up all points in the control net or images in the serial + number list. + + + Added "Cube Name" filter to "Points" tab of Control Network Navigator + window. + + + Discontinued forcing of gui style to windows + + + Connected FindTool's recordPoint signal to AdvancedTrackTool's record slot + + + Modified to uncheck "Held" in the QnetTool window if the "Cancel" button + is clicked in the Hold Point Dialog. Added a filter of Measure Properties + by Ignore Status to the Navigation Tool's Point Filters. Modified + Navigation Tool's Point Type filter to treat points as ignored if all + measures are ignored. Fixed bug that did not show proper colors of points + unless the QnetTool was open. Updated documentation. + + + Modified to reopen the Navigation Tool whenever the Tie Tool on the tool + pad is activated. Modified to draw points selected in the QnetTool last + so they are always visible on top of the other points. Added some + documentation. + + +
    diff --git a/isis/src/qisis/apps/qnet/tsts/Makefile b/isis/src/qisis/apps/qnet/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/qisis/apps/qnet/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/qisis/apps/qnet/tsts/default/Makefile b/isis/src/qisis/apps/qnet/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..af777576c30cbd1d16f9a3e069889ea1d72effc5 --- /dev/null +++ b/isis/src/qisis/apps/qnet/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = qnet + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/qnetTruth.txt $(OUTPUT)/qnetTruth.txt; diff --git a/isis/src/qisis/apps/qtie/Makefile b/isis/src/qisis/apps/qtie/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6df0714bd253866254ac1c9c3ba5958d6b2cc026 --- /dev/null +++ b/isis/src/qisis/apps/qtie/Makefile @@ -0,0 +1,13 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +BINS := $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps + +cleanlocal: diff --git a/isis/src/qisis/apps/qtie/QtieFileTool.cpp b/isis/src/qisis/apps/qtie/QtieFileTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..362478058e1c16eea1526145f0d6b54554de79e2 --- /dev/null +++ b/isis/src/qisis/apps/qtie/QtieFileTool.cpp @@ -0,0 +1,201 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "QtieFileTool.h" +#include "Application.h" +#include "Filename.h" +#include "MainWindow.h" +#include "MdiCubeViewport.h" +#include "Workspace.h" +#include "SerialNumberList.h" + +using namespace Qisis; + +namespace Qisis { + // Constructor + QtieFileTool::QtieFileTool (QWidget *parent) : Qisis::FileTool(parent) { + openAction()->setToolTip("Open images"); + QString whatsThis = + "Function: Open a images \ +

    Shortcut: Ctrl+O\n

    "; + openAction()->setWhatsThis(whatsThis); + + saveAction()->setEnabled(false); + + } + + /** + * Open base image and image to be adjusted + * + * @author 2007-08-13 Tracie Sucharski + * + * @internal + * @history 2009-06-10 Tracie Sucharski - Added error checking and looping + * when opening files. Allow new files to be + * opened. + * @history 2010-05-11 Tracie Sucharski - Added ability to read in control + * network. + * @history 2010-05-13 Tracie Sucharski - Use match cube directory to determine + * default directory for cnet. + * + */ + void QtieFileTool::open () { + + + // If we've already opened files, clear before starting over + if (cubeViewportList()->size() > 0) { + closeAll(); + emit newFiles(); + } + + + QString baseFile,matchFile; + QString dir; + QString filter = "Isis Cubes (*.cub);;"; + filter += "Detached labels (*.lbl);;"; + filter += "All (*)"; + + Isis::Cube *baseCube = new Isis::Cube; + while (!baseCube->IsOpen()) { + baseFile = QFileDialog::getOpenFileName((QWidget*)parent(), + "Select basemap cube (projected)", + ".",filter); + if (baseFile.isEmpty()) { + delete baseCube; + return; + } + + // Find directory and save for use in file dialog for match cube + Isis::Filename fname(baseFile.toStdString()); + dir = fname.absolutePath(); + + // Make sure base is projected + try { + baseCube->Open(baseFile.toStdString()); + try { + baseCube->Projection(); + } catch (Isis::iException &e) { + baseCube->Close(); + QString message = "Base must be projected"; + QMessageBox::critical((QWidget *)parent(),"Error",message); + baseCube->Close(); + } + } catch (Isis::iException &e) { + QString message = "Unable to open base cube"; + QMessageBox::critical((QWidget *)parent(),"Error",message); + } + } + baseCube->Close(); + + + Isis::Cube *matchCube = new Isis::Cube; + + while (!matchCube->IsOpen()) { + // Get match cube + matchFile = QFileDialog::getOpenFileName((QWidget*)parent(), + "Select cube to tie to base", + dir,filter); + if (matchFile.isEmpty()) { + delete baseCube; + delete matchCube; + (*(cubeViewportList()))[0]->close(); + return; + } + + //Make sure match is not projected + try { + matchCube->Open(matchFile.toStdString()); + try { + + if (matchCube->HasGroup("Mapping")) { + QString message = "The match cube cannot be a projected cube."; + QMessageBox::critical((QWidget *)parent(),"Error",message); + matchCube->Close(); + continue; + } + } catch (Isis::iException &e) { + QString message = "Error reading match cube labels."; + QMessageBox::critical((QWidget *)parent(),"Error",message); + matchCube->Close(); + } + } catch (Isis::iException &e) { + QString message = "Unable to open match cube"; + QMessageBox::critical((QWidget *)parent(),"Error",message); + } + } + matchCube->Close(); + + // Find directory and save for use in file dialog for match cube + Isis::Filename fname(matchFile.toStdString()); + dir = fname.absolutePath(); + + //Open control net + filter = "Control net (*.net);;"; + filter += "Text file (*.txt);;"; + filter += "All (*)"; + QString cnetFile = QFileDialog::getOpenFileName((QWidget*)parent(), + "Select a control network", + dir,filter); + QApplication::setOverrideCursor(Qt::WaitCursor); + Isis::ControlNet *cnet; + if (cnetFile.isEmpty()) { + cnet = new Isis::ControlNet(); + cnet->SetType(Isis::ControlNet::ImageToGround); + cnet->SetNetworkId("Qtie"); + cnet->SetUserName(Isis::Application::UserName()); + } + else { + try { + cnet = new Isis::ControlNet(cnetFile.toStdString()); + } + catch (Isis::iException &e) { + QString message = "Invalid control network. \n"; + std::string errors = e.Errors(); + message += errors.c_str(); + e.Clear (); + QMessageBox::information((QWidget *)parent(),"Error",message); + QApplication::restoreOverrideCursor(); + return; + } + } + QApplication::restoreOverrideCursor(); + + QApplication::setOverrideCursor(Qt::WaitCursor); + emit fileSelected(baseFile); + baseCube = (*(cubeViewportList()))[0]->cube(); + QApplication::restoreOverrideCursor(); + + + QApplication::setOverrideCursor(Qt::WaitCursor); + emit fileSelected(matchFile); + matchCube = (*(cubeViewportList()))[1]->cube(); + emit cubesOpened(*baseCube,*matchCube,*cnet); + QApplication::restoreOverrideCursor(); + + return; + } + + + + + +#if 0 + // Exit the program +............................................ + +void QtieFileTool::exit() { + qApp->quit(); + } +#endif +} diff --git a/isis/src/qisis/apps/qtie/QtieFileTool.h b/isis/src/qisis/apps/qtie/QtieFileTool.h new file mode 100644 index 0000000000000000000000000000000000000000..818c54dcc92d1c6fceabdd0b55cb969ab5ba26db --- /dev/null +++ b/isis/src/qisis/apps/qtie/QtieFileTool.h @@ -0,0 +1,73 @@ +#ifndef QtieFileTool_h +#define QtieFileTool_h + +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/05/12 17:22:27 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "Tool.h" +#include "FileTool.h" +#include "SerialNumberList.h" +#include "ControlNet.h" +#include "Projection.h" + +namespace Qisis { + +/** + * @brief Qtie File operations + * + * @ingroup Visualization Tools + * + * @author 2007-08-09 Tracie Sucharski, adapted from QnetFileTool + * + * @internal + * @history 2009-06-10 Tracie Sucharski - Added new signal for opening new + * files. + * + */ + + class QtieFileTool : public FileTool { + Q_OBJECT + + signals: + void cubesOpened(Isis::Cube &baseCube,Isis::Cube &matchCube,Isis::ControlNet &cnet); + void newFiles(); + + public: + QtieFileTool (QWidget *parent); + + public slots: + virtual void open(); + //virtual void exit(); + + private: + + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qtie/QtieTool.cpp b/isis/src/qisis/apps/qtie/QtieTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..75cc55147340037bead78b112b30980c5d66f976 --- /dev/null +++ b/isis/src/qisis/apps/qtie/QtieTool.cpp @@ -0,0 +1,912 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "QtieTool.h" +#include "MainWindow.h" +#include "MdiCubeViewport.h" +#include "Filename.h" +#include "SerialNumber.h" +#include "AutoReg.h" +#include "AutoRegFactory.h" +#include "ControlMeasure.h" +#include "BundleAdjust.h" +#include "History.h" +#include "PvlObject.h" +#include "PvlEditDialog.h" +#include "iTime.h" +#include "Application.h" +#include "BundleAdjust.h" +#include "ToolPad.h" +#include "UniversalGroundMap.h" + +using namespace Qisis; +using namespace std; + + +namespace Qisis { + // initialize static + QString QtieTool::lastPtIdValue = ""; + + /** + * Construct the QtieTool + * + * @author 2008-11-21 Tracie Sucharski + * + * @history 2010-05-11 Tracie Sucharski - Moved the creation of control net + * to the QtieFileTool::open. + */ + QtieTool::QtieTool (QWidget *parent) : Qisis::Tool(parent) { + +#if 0 + p_createPoint = new QAction (parent); + p_createPoint->setShortcut(Qt::Key_C); + connect(p_createPoint,SIGNAL(triggered()),this,SLOT(createPoint())); + + p_modifyPoint = new QAction (parent); + p_modifyPoint->setShortcut(Qt::Key_M); +// connect(p_modifyPoint,SIGNAL(triggered()),this,SLOT(modifyPoint())); + + p_deletePoint = new QAction (parent); + p_deletePoint->setShortcut(Qt::Key_D); + connect(p_deletePoint,SIGNAL(triggered()),this,SLOT(deletePoint())); +#endif + p_serialNumberList = new Isis::SerialNumberList(false); + p_controlNet = NULL; + p_controlPoint = NULL; + + p_twist = true; + p_tolerance = 5; + p_maxIterations = 10; + p_ptIdIndex = 0; + createQtieTool(parent); + + } + + + + /** + * Design the QtieTool widget + * + */ + void QtieTool::createQtieTool(QWidget *parent) { + + // Create dialog with a main window + p_tieTool = new QMainWindow(parent); + p_tieTool->setWindowTitle("Tie Point Tool"); + p_tieTool->layout()->setSizeConstraint(QLayout::SetFixedSize); + + createMenus(); + + // Place everything in a grid + QGridLayout *gridLayout = new QGridLayout(); + //gridLayout->setSizeConstraint(QLayout::SetFixedSize); + // ??? Very tacky-hardcoded to ChipViewport size of ControlPointEdit + xtra. + // Is there a better way to do this? + gridLayout->setColumnMinimumWidth(0,310); + gridLayout->setColumnMinimumWidth(1,310); + // grid row + int row = 0; + + QCheckBox *twist = new QCheckBox("Twist"); + twist->setChecked(p_twist); + connect(twist,SIGNAL(toggled(bool)),this,SLOT(setTwist(bool))); + QLabel *iterationLabel = new QLabel("Maximum Iterations"); + QSpinBox *iteration = new QSpinBox(); + iteration->setRange(1,100); + iteration->setValue(p_maxIterations); + iterationLabel->setBuddy(iteration); + connect(iteration,SIGNAL(valueChanged(int)),this,SLOT(setIterations(int))); + QHBoxLayout *itLayout = new QHBoxLayout(); + itLayout->addWidget(iterationLabel); + itLayout->addWidget(iteration); + + + QLabel *tolLabel = new QLabel("Tolerance"); + p_tolValue = new QLineEdit(); + tolLabel->setBuddy(p_tolValue); + QHBoxLayout *tolLayout = new QHBoxLayout(); + tolLayout->addWidget(tolLabel); + tolLayout->addWidget(p_tolValue); +// QDoubleValidator *dval = new QDoubleValidator + QString tolStr; + tolStr.setNum(p_tolerance); + p_tolValue->setText(tolStr); +// connect(p_tolValue,SIGNAL(valueChanged()),this,SLOT(setTolerance())); + + QHBoxLayout *options = new QHBoxLayout(); + options->addWidget(twist); + options->addLayout(itLayout); + options->addLayout(tolLayout); + + gridLayout->addLayout(options,row++,0); + + p_ptIdValue = new QLabel(); + gridLayout->addWidget(p_ptIdValue,row++,0); + + p_pointEditor = new Qisis::ControlPointEdit(parent,true); + gridLayout->addWidget(p_pointEditor,row++,0,1,3); + connect(p_pointEditor,SIGNAL(pointSaved()),this,SLOT(pointSaved())); + p_pointEditor->show(); + + QPushButton *solve = new QPushButton("Solve"); + connect(solve,SIGNAL(clicked()),this,SLOT(solve())); + gridLayout->addWidget(solve,row++,0); + + QWidget *cw = new QWidget(); + cw->setLayout(gridLayout); + p_tieTool->setCentralWidget(cw); + + connect(this,SIGNAL(editPointChanged()),this,SLOT(drawMeasuresOnViewports())); + connect(this,SIGNAL(newSolution(Isis::Table *)), + this,SLOT(writeNewCmatrix(Isis::Table *))); + + } + + + /** + * Create the menus for QtieTool + * + * + */ + void QtieTool::createMenus () { + + + QAction *saveNet = new QAction(p_tieTool); + saveNet->setText("Save Control Network &As..."); + QString whatsThis = + "Function: Saves the current control network under chosen filename"; + saveNet->setWhatsThis(whatsThis); + connect (saveNet,SIGNAL(activated()),this,SLOT(saveNet())); + + QAction *closeQtieTool = new QAction(p_tieTool); + closeQtieTool->setText("&Close"); + closeQtieTool->setShortcut(Qt::ALT+Qt::Key_F4); + whatsThis = + "Function: Closes the Qtie Tool window for this point \ +

    Shortcut: Alt+F4

    "; + closeQtieTool->setWhatsThis(whatsThis); + connect (closeQtieTool,SIGNAL(activated()),p_tieTool,SLOT(close())); + + QMenu *fileMenu = p_tieTool->menuBar()->addMenu("&File"); + fileMenu->addAction(saveNet); + fileMenu->addAction(closeQtieTool); + + QAction *templateFile = new QAction(p_tieTool); + templateFile->setText("&Set registration template"); + whatsThis = + "Function: Allows user to select a new file to set as the registration template"; + templateFile->setWhatsThis(whatsThis); + connect (templateFile,SIGNAL(activated()),this,SLOT(setTemplateFile())); + + QAction *viewTemplate = new QAction(p_tieTool); + viewTemplate->setText("&View/edit registration template"); + whatsThis = + "Function: Displays the curent registration template. \ + The user may edit and save changes under a chosen filename."; + viewTemplate->setWhatsThis(whatsThis); + connect (viewTemplate,SIGNAL(activated()),this,SLOT(viewTemplateFile())); + + + QMenu *optionMenu = p_tieTool->menuBar()->addMenu("&Options"); + QMenu *regMenu = optionMenu->addMenu("&Registration"); + + regMenu->addAction(templateFile); + regMenu->addAction(viewTemplate); + // registrationMenu->addAction(interestOp); + + } + + + + /** + * Put the QtieTool icon on the main window Toolpad + * + * @param pad Input Toolpad for the main window + * + */ + + QAction *QtieTool::toolPadAction(ToolPad *pad) { + QAction *action = new QAction(pad); + action->setIcon(QPixmap(toolIconDir()+"/stock_draw-connector-with-arrows.png")); + action->setToolTip("Tie (T)"); + action->setShortcut(Qt::Key_T); + return action; + } + + + + + /** + * Setup the base map and match cube + * + * @param baseCube Input Base map cube + * @param matchCube Input Match cube + * + */ + void QtieTool::setFiles(Isis::Cube &baseCube,Isis::Cube &matchCube,Isis::ControlNet &cnet) { + // Save off base map cube, but add matchCube to serial number list + p_baseCube = &baseCube; + p_matchCube = &matchCube; + p_controlNet = &cnet; + p_baseSN = Isis::SerialNumber::Compose(*p_baseCube,true); + p_matchSN = Isis::SerialNumber::Compose(*p_matchCube); + + p_serialNumberList->Add(matchCube.Filename()); + + // Save off universal ground maps + try { + p_baseGM = new Isis::UniversalGroundMap(*p_baseCube); + } catch (Isis::iException &e) { + QString message = "Cannot initialize universal ground map for basemap.\n"; + string errors = e.Errors(); + message += errors.c_str(); + e.Clear(); + QMessageBox::critical((QWidget *)parent(),"Error",message); + return; + } + try { + p_matchGM = new Isis::UniversalGroundMap(matchCube); + } catch (Isis::iException &e) { + QString message = "Cannot initialize universal ground map for match cube.\n"; + string errors = e.Errors(); + message += errors.c_str(); + e.Clear(); + QMessageBox::critical((QWidget *)parent(),"Error",message); + return; + } + + // If Control Net has points, set the basemap measures, since they are not + // saved in the net file. + if (cnet.Size() != 0) { + for (int i=0; iSetUniversalGround(p.UniversalLatitude(),p.UniversalLongitude())) { + // Make sure point on base cube + baseSamp = p_baseGM->Sample(); + baseLine = p_baseGM->Line(); + if (baseSamp < 1 || baseSamp > p_baseCube->Samples() || + baseLine < 1 || baseLine > p_baseCube->Lines()) { + // throw error? point not on base + QString message = "Error parsing input control net. Lat/Lon for Point Id: " + + QString::fromStdString(p.Id()) + " computes to a sample/line off " + + "the edge of the basemap cube."; + QMessageBox::critical((QWidget *)parent(),"Control Net Error",message); + return; + } + } + else { + // throw error? point not on base cube + QString message = "Error parsing input control net. Point Id: " + + QString::fromStdString(p.Id()) + " does not exist on basemap."; + QMessageBox::critical((QWidget *)parent(),"Control Net Error",message); + return; + } + + Isis::ControlMeasure *mB = new Isis::ControlMeasure; + mB->SetCubeSerialNumber(p_baseSN); + mB->SetCoordinate(baseSamp,baseLine); + mB->SetType(Isis::ControlMeasure::Estimated); + mB->SetDateTime(); + mB->SetChooserName(); + mB->SetIgnore(true); + + p.Add(*mB); + } + } + + } + + + + /** + * New files selected, clean up old file info + * + * @internal + * @history 2007-06-12 Tracie Sucharski - Added method to allow user to + * run on new files. + * @history 2010-05-11 Tracie Sucharski - Moved the creation of control net + * to the QtieFileTool::open. + */ + void QtieTool::clearFiles() { + p_tieTool->setShown(false); + // delete p_baseCube; + // delete p_matchCube; + + delete p_serialNumberList; + p_serialNumberList = new Isis::SerialNumberList(false); + + delete p_controlNet; + + delete p_baseGM; + delete p_matchGM; + + } + + + + /** + * Save control point under crosshairs of ChipViewports + * + */ + void QtieTool::pointSaved() { + // Get sample/line from base map and find lat/lon + double samp = (*p_controlPoint)[Base].Sample(); + double line = (*p_controlPoint)[Base].Line(); + + p_baseGM->SetImage(samp,line); + double lat = p_baseGM->UniversalLatitude(); + double lon = p_baseGM->UniversalLongitude(); + double radius = p_baseGM->Projection()->LocalRadius(); + + p_controlPoint->SetUniversalGround(lat,lon,radius); + + emit editPointChanged(); + + } + + + + /** + * Handle mouse events on match CubeViewport + * + * @param p[in] (QPoint) Point under cursor in cubeviewport + * @param s[in] (Qt::MouseButton) Which mouse button was pressed + * + * @internal + * @history 2007-06-12 Tracie Sucharski - Swapped left and right mouse + * button actions. + * @history 2008-11-19 Tracie Sucharski - Only allow mouse events on + * match cube. + * + */ + void QtieTool::mouseButtonRelease(QPoint p, Qt::MouseButton s) { + MdiCubeViewport *cvp = cubeViewport(); + if (cvp == NULL) return; + if (cubeViewportList()->size() != 2) { + QString message = "You must have a basemap and a match cube open."; + QMessageBox::critical((QWidget *)parent(),"Error",message); + return; + } + if (cvp->cube() == p_baseCube) { + QString message = "Select points on match Cube only."; + QMessageBox::information((QWidget *)parent(),"Warning",message); + return; + } + if (cvp->cursorInside()) QPoint p = cvp->cursorPosition(); + + // ??? do we only allow mouse clicks on level1??? + // If we allow on both, need to find samp,line on level1 if + // they clicked on basemap. + std::string file = cvp->cube()->Filename(); + std::string sn = p_serialNumberList->SerialNumber(file); + + double samp,line; + cvp->viewportToCube(p.x(),p.y(),samp,line); + + if (s == Qt::LeftButton) { + // Find closest control point in network + Isis::ControlPoint *point = + p_controlNet->FindClosest(sn,samp,line); + // TODO: test for errors and reality + if (point == NULL) { + QString message = "No points exist for editing. Create points "; + message += "using the right mouse button."; + QMessageBox::information((QWidget *)parent(),"Warning",message); + return; + } + modifyPoint(point); + } + else if (s == Qt::MidButton) { + // Find closest control point in network + Isis::ControlPoint *point = + p_controlNet->FindClosest(sn,samp,line); + // TODO: test for errors and reality + if (point == NULL) { + QString message = "No points exist for deleting. Create points "; + message += "using the right mouse button."; + QMessageBox::information((QWidget *)parent(),"Warning",message); + return; + } + deletePoint(point); + } + else if (s == Qt::RightButton) { + p_matchGM->SetImage(samp,line); + double lat = p_matchGM->UniversalLatitude(); + double lon = p_matchGM->UniversalLongitude(); + + createPoint(lat,lon); + } + } + + + + /** + * Create control point at given lat,lon + * + * @param lat Input Latitude of new point + * @param lon Input Longitude of new point + * + * @internal + * @history 2008-12-06 Tracie Sucharski - Set point type to Ground + * @history 2010-05-18 Jeannie Walldren - Modified Point ID + * QInputDialog to return if "Cancel" + * is clicked. + */ + void QtieTool::createPoint(double lat,double lon) { + + // TODO: ADD AUTOSEED OPTION (CHECKBOX?) + + double baseSamp=0,baseLine=0; + double matchSamp,matchLine; + + // if clicked in match, get samp,line + p_matchGM->SetUniversalGround(lat,lon); + matchSamp = p_matchGM->Sample(); + matchLine = p_matchGM->Line(); + + // Make sure point is on base + if (p_baseGM->SetUniversalGround(lat,lon)) { + // Make sure point on base cube + baseSamp = p_baseGM->Sample(); + baseLine = p_baseGM->Line(); + if (baseSamp < 1 || baseSamp > p_baseCube->Samples() || + baseLine < 1 || baseLine > p_baseCube->Lines()) { + // throw error? point not on base + QString message = "Point does not exist on base map."; + QMessageBox::warning((QWidget *)parent(),"Warning",message); + } + } + else { + // throw error? point not on base cube + // throw error? point not on base + QString message = "Point does not exist on base map."; + QMessageBox::warning((QWidget *)parent(),"Warning",message); + } + + // Get radius + double radius = p_baseGM->Projection()->LocalRadius(); + + // Point is on both base and match, create new control point + Isis::ControlPoint *newPoint=NULL; + // First prompt for pointId + bool goodId = false; + while (!goodId) { + bool ok=false; + QString id = QInputDialog::getText((QWidget *)parent(), + "Point ID","Enter Point ID:", + QLineEdit::Normal,lastPtIdValue, + &ok); + if (!ok) { // user clicked "Cancel" + return; + } + if (ok && id.isEmpty()) { // user clicked "Ok" but did not enter a point ID + QString message = "You must enter a point Id."; + QMessageBox::warning((QWidget *)parent(),"Warning",message); + } + else { + // Make sure Id doesn't already exist + newPoint = new Isis::ControlPoint(id.toStdString()); + if (p_controlNet->Exists(*newPoint)) { + QString message = "A ControlPoint with Point Id = [" + + QString::fromStdString(newPoint->Id()) + + "] already exists. Re-enter unique Point Id."; + QMessageBox::warning((QWidget *)parent(), "Unique Point Id",message); + } + else { + goodId = true; + lastPtIdValue = id; + } + } + } + + + newPoint->SetUniversalGround(lat,lon,radius); + newPoint->SetType(Isis::ControlPoint::Ground); + + // Set first measure to match + Isis::ControlMeasure *mM = new Isis::ControlMeasure; + mM->SetCubeSerialNumber(p_matchSN); + mM->SetCoordinate(matchSamp,matchLine); + mM->SetType(Isis::ControlMeasure::Estimated); + mM->SetDateTime(); + mM->SetChooserName(); + newPoint->Add(*mM); + // Second measure is base measure, set to Ignore=yes + Isis::ControlMeasure *mB = new Isis::ControlMeasure; + mB->SetCubeSerialNumber(p_baseSN); + mB->SetCoordinate(baseSamp,baseLine); + mB->SetType(Isis::ControlMeasure::Estimated); + mB->SetDateTime(); + mB->SetChooserName(); + mB->SetIgnore(true); + newPoint->Add(*mB); + + // Add new control point to control network + p_controlNet->Add(*newPoint); + // Read newly added point + p_controlPoint = p_controlNet->Find(newPoint->Id()); + // Load new point in QtieTool + loadPoint(); + p_tieTool->setShown(true); + p_tieTool->raise(); + + emit editPointChanged(); + + } + + + + /** + * Delete given control point + * + * @param point Input Control Point to delete + * + * @history 2010-05-19 Tracie Sucharski - Fixed bug which was causing a seg + * fault. Set p_controlPoint to NULL, also no sense + * loading point to be deleted. Should this be + * smartened up to load another Point? + * + */ + void QtieTool::deletePoint(Isis::ControlPoint *point) { + + p_controlPoint = point; + // Change point in viewport to red so user can see what point they are + // about to delete. + emit editPointChanged(); + + //loadPoint(); + + p_controlNet->Delete(p_controlPoint->Id()); + p_tieTool->setShown(false); + p_controlPoint = NULL; + + emit editPointChanged(); + } + + + + /** + * Modify given control point + * + * @param point Input Control Point to modify + * + */ + void QtieTool::modifyPoint(Isis::ControlPoint *point) { + + p_controlPoint = point; + loadPoint(); + p_tieTool->setShown(true); + p_tieTool->raise(); + emit editPointChanged(); + } + + + /** + * Load control point into the ControlPointEdit widget + * + * @history 2010-05-18 Tracie Sucharski - Added pointId to the dialog. + */ + void QtieTool::loadPoint () { + + // Initialize pointEditor with measures + p_pointEditor->setLeftMeasure (&(*p_controlPoint)[Base],p_baseCube, + p_controlPoint->Id()); + p_pointEditor->setRightMeasure (&(*p_controlPoint)[Match],p_matchCube, + p_controlPoint->Id()); + + // Write pointId + string CPId = p_controlPoint->Id(); + QString ptId = "Point ID: " + + QString::fromStdString(CPId.c_str()); + p_ptIdValue->setText(ptId); + + + } + + + + /** + * Draw all Control Measures on each viewport + * + */ + void QtieTool::drawMeasuresOnViewports () { + + MdiCubeViewport *vp; + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + vp = (*(cubeViewportList()))[i]; + vp->viewport()->update(); + } + } + + + + /** + * Repaint the given CubeViewport + * + * @param vp Input CubeViewport to repain + * @param painter Input Qt Painter + * + */ + void QtieTool::paintViewport (MdiCubeViewport *vp,QPainter *painter) { + + // Make sure we have points to draw + if (p_controlNet == NULL || p_controlNet->Size() == 0) return; + + // Draw all measures + std::string serialNumber = Isis::SerialNumber::Compose(*vp->cube(),true); + for (int i=0; iSize(); i++) { + Isis::ControlPoint &p = (*p_controlNet)[i]; + if (p_controlPoint != NULL && p.Id() == p_controlPoint->Id()) { + painter->setPen(QColor(200,0,0)); + } + else { + painter->setPen(QColor(0,200,0)); + } + + double samp,line; + if (vp->cube()->Filename() == p_baseCube->Filename()) { + // Draw on left viewport (base) + samp = p[Base].Sample(); + line = p[Base].Line(); + } + else { + // Draw on right viewport (match) + samp = p[Match].Sample(); + line = p[Match].Line(); + } + int x,y; + vp->cubeToViewport(samp,line,x,y); + painter->drawLine(x-5,y,x+5,y); + painter->drawLine(x,y-5,x,y+5); + } + + } + + + + + /** + * Perform the BundleAdjust Solve + * + * + */ + void QtieTool::solve () { + + // First off , get tolerance, NEED to VALIDATE + p_tolerance = p_tolValue->text().toDouble(); + + // Need at least 2 points to solve for twist + if (p_twist) { + if (p_controlNet->Size() < 2) { + QString message = "Need at least 2 points to solve for twist. \n"; + QMessageBox::critical((QWidget *)parent(),"Error",message); + return; + } + } + Isis::ControlNet net; + + // Bundle adjust to solve for new pointing + try { + + // Create new control net for bundle adjust , deleting ignored measures + for (int p=0; pSize(); p++) { + Isis::ControlPoint pt = (*p_controlNet)[p]; + for (int m=0; mReOpen("rw"); + Isis::Table cmatrix = b.Cmatrix(0); + //cmatrix = b.Cmatrix(0); + emit newSolution(&cmatrix); + } + else { + return; + } + + } + catch (Isis::iException &e) { + QString message = "Bundle Solution failed.\n"; + string errors = e.Errors(); + message += errors.c_str(); + e.Clear(); +// message += "\n\nMaximum Error = " + QString::number(net.MaximumResiudal()); +// message += "\nAverage Error = " + QString::number(net.AverageResidual()); + message += "\n\nMaximum Error = " + QString::number(net.MaximumError()); + message += "\nAverage Error = " + QString::number(net.AverageError()); + QMessageBox::warning((QWidget *)parent(),"Error",message); + return; + } + } + + + + + /** + * Write the new cmatrix to the match cube + * + * @param cmatrix Input New adjusted cmatrix + * + */ + void QtieTool::writeNewCmatrix (Isis::Table *cmatrix) { + + //check for existing polygon, if exists delete it + if (p_matchCube->Label()->HasObject("Polygon")) { + p_matchCube->Label()->DeleteObject("Polygon"); + } + + // Update the cube history + p_matchCube->Write(*cmatrix); + Isis::History h("IsisCube"); + try { + p_matchCube->Read(h); + } catch (Isis::iException &e) { + QString message = "Could not read cube history, will not update history.\n"; + string errors = e.Errors(); + message += errors.c_str(); + QMessageBox::warning((QWidget *)parent(),"Warning",message); + e.Clear(); + return; + } + Isis::PvlObject history("qtie"); + history += Isis::PvlKeyword("IsisVersion",Isis::version); + QString path = QCoreApplication::applicationDirPath(); + history += Isis::PvlKeyword("ProgramPath", path); + history += Isis::PvlKeyword("ExecutionDateTime",Isis::Application::DateTime()); + history += Isis::PvlKeyword("HostName",Isis::Application::HostName()); + history += Isis::PvlKeyword("UserName",Isis::Application::UserName()); + Isis::PvlGroup results("Results"); + results += Isis::PvlKeyword("CameraAnglesUpdated","True"); + results += Isis::PvlKeyword("BaseMap",p_baseCube->Filename()); + history += results; + + h.AddEntry(history); + p_matchCube->Write(h); + p_matchCube->ReOpen("r"); + + } + + + + + /** + * Allows user to set a new template file. + * @author 2008-12-10 Jeannie Walldren + * @internal + * @history 2008-12-10 Jeannie Walldren - Original Version + */ + + void QtieTool::setTemplateFile() { + p_pointEditor->setTemplateFile(); + } + + + + + /** + * Allows the user to view the template file that is currently + * set. + * @author 2008-12-10 Jeannie Walldren + * @internal + * @history 2008-12-10 Jeannie Walldren - Original Version + * @history 2008-12-10 Jeannie Walldren - Added "Isis::" + * namespace to PvlEditDialog reference and changed + * registrationDialog from pointer to object + * @history 2008-12-15 Jeannie Walldren - Added QMessageBox + * warning in case Template File cannot be read. + */ + void QtieTool::viewTemplateFile() { + try{ + // Get the template file from the ControlPointEditor object + Isis::Pvl templatePvl(p_pointEditor->templateFilename()); + // Create registration dialog window using PvlEditDialog class + // to view and/or edit the template + Isis::PvlEditDialog registrationDialog(templatePvl); + registrationDialog.setWindowTitle("View or Edit Template File: " + + QString::fromStdString(templatePvl.Filename())); + registrationDialog.resize(550,360); + registrationDialog.exec(); + } + catch (Isis::iException &e){ + QString message = e.Errors().c_str(); + e.Clear (); + QMessageBox::warning((QWidget *)parent(),"Error",message); + } + } + + + + /** + * Save the ground points to a ControlNet. + * + * @author 2008-12-30 Tracie Sucharski + */ + void QtieTool::saveNet () { + + QString filter = "Control net (*.net);;"; + filter += "Text file (*.txt);;"; + filter += "All (*)"; + QString fn=QFileDialog::getSaveFileName((QWidget*)parent(), + "Choose filename to save under", + ".", filter); + if ( !fn.isEmpty() ) { + try { + // Create new control net for bundle adjust , deleting ignored measures + // which are the basemap measures. + Isis::ControlNet net; + for (int p=0; pSize(); p++) { + Isis::ControlPoint pt = (*p_controlNet)[p]; + for (int m=0; mCamera()->Target()); + net.SetNetworkId("Qtie"); + net.SetUserName(Isis::Application::UserName()); + net.SetCreatedDate( Isis::Application::DateTime() ); + net.SetModifiedDate( Isis::iTime::CurrentLocalTime() ); + net.SetDescription("Qtie Ground Points"); + net.Add(pt); + } + + net.Write(fn.toStdString()); + } + catch (Isis::iException &e) { + QString message = "Error saving control network. \n"; + string errors = e.Errors(); + message += errors.c_str(); + e.Clear (); + QMessageBox::information((QWidget *)parent(),"Error",message); + return; + } + } + else { + QMessageBox::information((QWidget *)parent(), + "Error","Saving Aborted"); + } + + } + +} diff --git a/isis/src/qisis/apps/qtie/QtieTool.h b/isis/src/qisis/apps/qtie/QtieTool.h new file mode 100644 index 0000000000000000000000000000000000000000..24e1b6c58e4da90fda4ce00cbf838e4e730d08de --- /dev/null +++ b/isis/src/qisis/apps/qtie/QtieTool.h @@ -0,0 +1,131 @@ +#ifndef QtieTool_h +#define QtieTool_h + +#include +#include +#include +#include + +#include "Tool.h" +#include "Table.h" +#include "Cube.h" +#include "ControlPointEdit.h" +#include "SerialNumber.h" +#include "SerialNumberList.h" +#include "ImageOverlap.h" +#include "ControlNet.h" +#include "ControlPoint.h" +#include "ControlMeasure.h" +#include "ChipViewport.h" +#include "Pvl.h" +#include "AutoRegFactory.h" + +class QLineEdit; +class QMainWindow; + +namespace Qisis { + class MdiCubeViewport; + +/** + * @brief Tool for picking Tie points + * + * @ingroup Visualization Tools + * + * @author 2008-09-09 Tracie Sucharski + * + * @history 2008-11-19 Tracie Sucharski - Addition option to constructor + * to allow mouse events on leftChipViewport. + * @history 2009-06-10 Tracie Sucharski - Added new slot, clearFiles which + * allow new files to be opened. + * @history 2010-05-18 Jeannie Walldren - Modified createPoint() method Point ID + * Dialog to return if "Cancel" is clicked. + * @history 2010-05-18 Tracie Sucharski - Added pointId to the Tie tool + * Dialog. + * + */ + class QtieTool : public Qisis::Tool { + Q_OBJECT + + public: + QtieTool (QWidget *parent); + void paintViewport (MdiCubeViewport *cvp,QPainter *painter); +// void addTo (QMenu *menu); + static QString lastPtIdValue; + + signals: + void tieToolSave(); + void editPointChanged(); + void newSolution(Isis::Table *cmatrix); + + public slots: + void setFiles(Isis::Cube &baseCube,Isis::Cube &matchCube,Isis::ControlNet &cnet); + void clearFiles(); + void createPoint(double lat,double lon); + void modifyPoint(Isis::ControlPoint *point); + void deletePoint(Isis::ControlPoint *point); + + protected: + QAction *toolPadAction(ToolPad *pad); + + protected slots: + void mouseButtonRelease(QPoint p, Qt::MouseButton s); + + private slots: + void drawMeasuresOnViewports(); + void solve(); + void writeNewCmatrix(Isis::Table *cmatrix); + void saveNet(); + + void pointSaved (); + + void setTemplateFile(); + void viewTemplateFile(); + //void setInterestOp(); + void setTwist(bool twist) { p_twist = twist; }; + void setIterations(int maxIterations) { p_maxIterations = maxIterations; }; + //void setTolerance () { p_tolerance = p_tolValue->text().toDouble(); }; + + private: + void createQtieTool(QWidget *parent); + QMainWindow *p_tieTool; + void createMenus(); + + void loadPoint(); + + QAction *p_createPoint; + QAction *p_modifyPoint; + QAction *p_deletePoint; + + QMainWindow *p_mw; + ControlPointEdit *p_pointEditor; + QLineEdit *p_tolValue; + QLabel *p_ptIdValue; + + enum CubeIndex { + Match, + Base + }; + + Isis::SerialNumberList *p_serialNumberList; + Isis::ControlNet *p_controlNet; + + Isis::ControlPoint *p_controlPoint; + int p_ptIdIndex; + + Isis::ControlMeasure *p_baseMeasure; + Isis::ControlMeasure *p_matchMeasure; + Isis::Cube *p_baseCube; + Isis::Cube *p_matchCube; + std::string p_baseSN; + std::string p_matchSN; + Isis::UniversalGroundMap *p_baseGM; + Isis::UniversalGroundMap *p_matchGM; + + bool p_twist; + double p_tolerance; + int p_maxIterations; + + }; +}; + +#endif diff --git a/isis/src/qisis/apps/qtie/qtie.cpp b/isis/src/qisis/apps/qtie/qtie.cpp new file mode 100644 index 0000000000000000000000000000000000000000..579ae13ab98745962698550b9d3d632c172e36a7 --- /dev/null +++ b/isis/src/qisis/apps/qtie/qtie.cpp @@ -0,0 +1,81 @@ +#include +#include +#include "iException.h" +#include "ViewportMainWindow.h" +#include "QtieFileTool.h" +#include "BandTool.h" +#include "ZoomTool.h" +#include "PanTool.h" +#include "StretchTool.h" +#include "FindTool.h" +#include "WindowTool.h" +#include "AdvancedTrackTool.h" +#include "HelpTool.h" +#include "QtieTool.h" +#include "RubberBandTool.h" + +#define IN_QTIE + +int main (int argc, char *argv[]) { + + try { + QApplication *app = new QApplication(argc,argv); + QApplication::setApplicationName("qtie"); + app->setStyle("windows"); + + Qisis::ViewportMainWindow *mw = new Qisis::ViewportMainWindow("Qtie"); + + Qisis::Tool *rubberBandTool = Qisis::RubberBandTool::getInstance(mw); + rubberBandTool->addTo(mw); + + Qisis::QtieFileTool *ftool = new Qisis::QtieFileTool(mw); + ftool->Tool::addTo(mw); + mw->permanentToolBar()->addSeparator(); + + Qisis::Tool *btool = new Qisis::BandTool(mw); + btool->addTo(mw); + + Qisis::Tool *ztool = new Qisis::ZoomTool(mw); + ztool->addTo(mw); + mw->getMenu("&View")->addSeparator(); + + Qisis::Tool *ptool = new Qisis::PanTool(mw); + ptool->addTo(mw); + mw->getMenu("&View")->addSeparator(); + + Qisis::Tool *stool = new Qisis::StretchTool(mw); + stool->addTo(mw); + + Qisis::Tool *findTool = new Qisis::FindTool(mw); + findTool->addTo(mw); + + Qisis::Tool *ttool = new Qisis::AdvancedTrackTool(mw); + ttool->addTo(mw); + + Qisis::Tool *wtool = new Qisis::WindowTool(mw); + wtool->addTo(mw); + + mw->permanentToolBar()->addSeparator(); + Qisis::Tool *htool = new Qisis::HelpTool(mw); + htool->addTo(mw); + + Qisis::Tool *tieTool = new Qisis::QtieTool(mw); + tieTool->addTo(mw); + tieTool->activate(true); + + QObject::connect(ftool,SIGNAL(cubesOpened(Isis::Cube &,Isis::Cube &,Isis::ControlNet &)), + tieTool,SLOT(setFiles(Isis::Cube &,Isis::Cube &,Isis::ControlNet &))); + + QObject::connect(ftool,SIGNAL(newFiles()),tieTool,SLOT(clearFiles())); + + QObject::connect(mw, SIGNAL(closeWindow()), ftool, SLOT(exit())); + + mw->show(); + + return app->exec(); + } + catch (Isis::iException &e) { + e.Report(); + } +} + diff --git a/isis/src/qisis/apps/qtie/qtie.xml b/isis/src/qisis/apps/qtie/qtie.xml new file mode 100644 index 0000000000000000000000000000000000000000..d0f17f1241bdb3104a26e38c9ba29224bd56bb31 --- /dev/null +++ b/isis/src/qisis/apps/qtie/qtie.xml @@ -0,0 +1,123 @@ + + + + + Create and edit control networks + + + +

    + This program will update the camera pointing of a level 1 image matching to a + base map. The camera pointing is updated using an iterative least-squares bundle + adjustment. This is the interactive version of the program, deltack. +

    +

    + To run qtie, you will enter a base map (projected) and a match cube + (unprojected). There are 2 core windows used in this application. +

    +

    qtie window

    + The main qtie window is similar to the qview application. You will see many + of the same tools, such as "Band Selection", "Zoom", "Pan", "Stretch" and + "Find" along the right border. The "Tie" tool is the last button along the + right toolbar. It will be the default tool selected when qtie is launched. +

    + In this window, select the "Open images" button or the Open action (from + File menu). You will be prompted to enter the base map cube first followed + by the level 1 (unprojected) cube to be tied to the base map. +

    + When the "Tie" tool is activated, the mouse buttons have the following + function in the cube viewports of the main qtie window: +
    +      Left Button:  Modify the closest control point
    +
    +      Middle Button:  Delete the closest control point 
    +
    +      Right Button:  Create new control point
    +    
    +

    Qtie Tool window

    + This is the point editor window of qtie for modifying or creating a point. + The window will display the cube that is the base map on the left and + the level 1 cube on the right. Both measures (base map and level 1) may be + moved. The measure can be adjusted by: +
    +      move to the cursor position under the crosshair by clicking the left mouse button
    +
    +      move 1 pixel at a time by using arrow keys on the keyboard 
    +
    +      move 1 pixel at a time by using arrow buttons above the right view
    +    
    + Other point editor functions / options include the following: +
    +      In the File menu:    
    +        Save Control Network As Save the ground points
    +        in a control network.
    +
    +        Close Close the Tie Point Tool.
    +
    +      In the Options menu:
    +        Registration Set or view and save registration 
    +        templates.
    +
    +      Along the top of the window:
    +        Twist Turning off twist will solve for right ascension and
    +        declination only which is a translation of the image.  Solving for twist 
    +        includes both translation and rotation.
    +
    +        Maximum Iterations Maximum number of iterations to try
    +        for convergence to tolerance before stopping.
    +
    +        Tolerance Tolerance in pixels.  When the bundle adjustment
    +        drops below this value, the solution has converged.
    +
    +      Along the right border of the window:
    +        Geom  Geom the right view to match the left view 
    +
    +        Rotate  Rotate the right view
    +
    +      Below the left view:
    +        Blink controls  Blink the left and right view in the
    +        left view window using the "Blink Start" button (with play icon) and 
    +        "Blink Stop" button (with stop icon).  The arrow keys above the right view 
    +        may be used to move the right view in order to update the blinking in real 
    +        time.
    +
    +        Find   Center the right view so that the same latitude / 
    +        longitude is under the crosshair as the left view. 
    +
    +      Below the right view:
    +        Register  Sub-pixel register the the right view to
    +        the left view.
    +
    +        Save Point  Save both left and right measures in a
    +        control point.
    +
    +        Solve Attempt the bundle solution using the points picked with
    +        the given input parameters such as Twist, Maximum Iterations and Tolerance.
    +        If the solution converges, you will be asked whether you want to update
    +        the camera pointing.
    +    
    + +
    + + + Display + + + + + Original version + + + Add option to save ground points to a ControlNet. + + + Correct user documentation in qtie.xml. + + + Added error checking when opening files and allow new files to be opened. + + + Discontinued forcing of gui style to windows + + +
    diff --git a/isis/src/qisis/apps/qtie/tsts/Makefile b/isis/src/qisis/apps/qtie/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/qisis/apps/qtie/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/qisis/apps/qtie/tsts/default/Makefile b/isis/src/qisis/apps/qtie/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5b9c458f6f0f84bb726f01cf6330574cf423982d --- /dev/null +++ b/isis/src/qisis/apps/qtie/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = qtie + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/qtieTruth.txt $(OUTPUT)/qtieTruth.txt; diff --git a/isis/src/qisis/apps/qview/Makefile b/isis/src/qisis/apps/qview/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/qisis/apps/qview/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/qisis/apps/qview/qview.cpp b/isis/src/qisis/apps/qview/qview.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0728c1178a2b11e24086f854902339ccebad7974 --- /dev/null +++ b/isis/src/qisis/apps/qview/qview.cpp @@ -0,0 +1,275 @@ +#include "IsisDebug.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "QIsisApplication.h" +#include "Filename.h" +#include "ViewportMainWindow.h" +#include "Workspace.h" +#include "FileTool.h" +#include "ZoomTool.h" +#include "StretchTool.h" +#include "WindowTool.h" +#include "HelpTool.h" +#include "PanTool.h" +#include "RubberBandTool.h" +#include "BandTool.h" +#include "EditTool.h" +#include "FindTool.h" +#include "BlinkTool.h" +#include "AdvancedTrackTool.h" +#include "Filename.h" +#include "Application.h" +#include "SocketThread.h" +#include "iString.h" +#include "MeasureTool.h" +#include "SpecialPixelTool.h" +#include "PlotTool.h" +#include "HistogramTool.h" +#include "StatisticsTool.h" +#include "Preference.h" +#include "PvlGroup.h" + +void startMonitoringMemory(); +void stopMonitoringMemory(); + +int main (int argc, char *argv[]) { + #ifdef CWDEBUG + startMonitoringMemory(); + #endif + + // Check to see if the user wants to force a new window + int newWindow = -1; + for (int i=1; i= 0) { + std::string temp; + for (int i=1; iaddTo(vw); + + Qisis::Tool *ftool = new Qisis::FileTool(vw); + ftool->addTo(vw); + vw->permanentToolBar()->addSeparator(); + + Qisis::Tool *btool = new Qisis::BandTool(vw); + btool->addTo(vw); + + Qisis::Tool *ztool = new Qisis::ZoomTool(vw); + ztool->addTo(vw); + ztool->activate(true); + vw->getMenu("&View")->addSeparator(); + + Qisis::Tool *ptool = new Qisis::PanTool(vw); + ptool->addTo(vw); + vw->getMenu("&View")->addSeparator(); + + Qisis::Tool *stool = new Qisis::StretchTool(vw); + stool->addTo(vw); + + Qisis::Tool *findtool = new Qisis::FindTool(vw); + findtool->addTo(vw); + + Qisis::Tool *blinktool = new Qisis::BlinkTool(vw); + blinktool->addTo(vw); + + Qisis::Tool *attool = new Qisis::AdvancedTrackTool(vw); + attool->addTo(vw); + + Qisis::Tool *edittool = new Qisis::EditTool(vw); + edittool->addTo(vw); + + Qisis::Tool *wtool = new Qisis::WindowTool(vw); + wtool->addTo(vw); + + Qisis::Tool *mtool = new Qisis::MeasureTool(vw); + mtool->addTo(vw); + + Qisis::Tool *sptool = new Qisis::SpecialPixelTool(vw); + sptool->addTo(vw); + + Qisis::Tool *pltool = new Qisis::PlotTool(vw); + pltool->addTo(vw); + + Qisis::Tool *histtool = new Qisis::HistogramTool(vw); + histtool->addTo(vw); + + Qisis::Tool *statstool = new Qisis::StatisticsTool(vw); + statstool->addTo(vw); + + Qisis::Tool *htool = new Qisis::HelpTool(vw); + htool->addTo(vw); + + // Show the application window & open the cubes + vw->show(); + for (int i=1; iworkspace()->addCubeViewport(QString(argv[i])); + } + } + + Qisis::SocketThread *temp = NULL; +// Doesn't yet work on Mac OS X 10.4 (Tiger) systems for some reason. +#if !defined(__APPLE__) + // We don't want to start a thread if the user is forcing a new window + if (newWindow < 0) { + temp = new Qisis::SocketThread(); + temp->connect(temp, SIGNAL(newImage(const QString &)), + vw->workspace(), SLOT(addCubeViewport(const QString &))); + temp->connect(temp, SIGNAL(focusApp()), vw, SLOT(raise())); + temp->start(); + } +#endif + + //Connect the edittool to the file tool in order to save and discard changes + QObject::connect(edittool, SIGNAL(cubeChanged(bool)), ftool, SLOT(enableSave(bool))); + QObject::connect(ftool, SIGNAL(saveChanges(MdiCubeViewport *)), edittool, SLOT(save(MdiCubeViewport *))); + QObject::connect(ftool, SIGNAL(discardChanges(MdiCubeViewport *)), edittool, SLOT(undoAll(MdiCubeViewport *))); + QObject::connect(edittool, SIGNAL(save()), ftool, SLOT(confirmSave())); + QObject::connect(edittool, SIGNAL(saveAs()), ftool, SLOT(saveAs())); + //Connect the FindTool to the AdvancedTrackTool to record the point if the "record" button is clicked + QObject::connect(findtool, SIGNAL(recordPoint(QPoint)), attool, SLOT(record(QPoint))); + + //Connect the viewport's close signal to the file tool's exit method + QObject::connect(vw , SIGNAL(closeWindow()), ftool, SLOT(exit())); + + int status = app->exec(); + + // If we created a thread for listening to qview connections, then stop the thread and free its memory + if(temp) { + temp->stop(); + temp->wait(); // wait for the stop to finish + delete temp; + } + + delete htool; + delete histtool; + delete pltool; + delete sptool; + delete mtool; + delete wtool; + delete attool; + delete blinktool; + delete findtool; + delete stool; + delete ptool; + delete btool; + delete rubberBandTool; + delete vw; + delete app; + //delete QCoreApplication::instance(); + return status; +} + + +void startMonitoringMemory() { +#ifdef CWDEBUG +#ifndef NOMEMCHECK + MyMutex *mutex = new MyMutex(); + std::fstream *alloc_output = new std::fstream("/dev/null"); + Debug( make_all_allocations_invisible_except(NULL) ); + ForAllDebugChannels( if (debugChannel.is_on()) debugChannel.off() ); + Debug( dc::malloc.on() ); + Debug( libcw_do.on() ); + Debug( libcw_do.set_ostream(alloc_output) ); + Debug( libcw_do.set_ostream(alloc_output, mutex) ); + atexit(stopMonitoringMemory); +#endif +#endif +} + + +void stopMonitoringMemory() { +#ifdef CWDEBUG +#ifndef NOMEMCHECK + Debug( + alloc_filter_ct alloc_filter; + std::vector objmasks; + objmasks.push_back("libc.so*"); + objmasks.push_back("libstdc++*"); + std::vector srcmasks; + srcmasks.push_back("*new_allocator.h*"); + srcmasks.push_back("*set_ostream.inl*"); + alloc_filter.hide_objectfiles_matching(objmasks); + alloc_filter.hide_sourcefiles_matching(srcmasks); + alloc_filter.hide_unknown_locations(); + delete libcw_do.get_ostream(); + libcw_do.set_ostream(&std::cout); + list_allocations_on(libcw_do, alloc_filter); + dc::malloc.off(); + libcw_do.off() + ); +#endif +#endif +} diff --git a/isis/src/qisis/apps/qview/qview.xml b/isis/src/qisis/apps/qview/qview.xml new file mode 100644 index 0000000000000000000000000000000000000000..63f1e3213a68b55b21cf2b7ef21edabd2b2d28e9 --- /dev/null +++ b/isis/src/qisis/apps/qview/qview.xml @@ -0,0 +1,58 @@ + + + + + Display and analyze cubes + + + + This program will display cubes and allow for interactive analysis. + + + + Display + + + + + Original version + + + Port to Qt4 and add blink tool + + + Fixed bug with filename expansion and added the MeasureTool + + + Documentation fixes + + + Added new rubber band functionality + + + Added Mosaic Tracking info like image index, serial number and file name + in the Advanced Tracking window to have the ability to track mosaic + origin. + + + Modified FindTool. If a user enters a line/sample in the Image tab, then + the corresponding lat/lon is displayed in the Ground tab. Added Record + button to FindTool to record clicked or typed point in the + AdvancedTrackTool window. + + + "qview" now has the ability to handle exceptions. The status bar now + displays a default NoWarning icon with "Ready" message. If an + exception is caught, the icon changes to Warning and displays the error + message. Clicking on the Warning icon will display a dialog window with + the details of the most recent error occured. Closing the dialog or any + other mouse activity will reset the Warning status. + + + Discontinued forcing of gui style to windows + + + Enable FindTool for images without camera and/or projection + + + diff --git a/isis/src/qisis/apps/qview/tsts/Makefile b/isis/src/qisis/apps/qview/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/qisis/apps/qview/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/qisis/apps/qview/tsts/default/Makefile b/isis/src/qisis/apps/qview/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1605590f0d7ec07e483ad190fe3de50358fee09c --- /dev/null +++ b/isis/src/qisis/apps/qview/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = qview + +include $(ISISROOT)/make/isismake.tsts + +commands: + cp $(INPUT)/qviewTruth.txt $(OUTPUT)/qviewTruth.txt; diff --git a/isis/src/qisis/objs/AdvancedTrackTool/AdvancedTrackTool.cpp b/isis/src/qisis/objs/AdvancedTrackTool/AdvancedTrackTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a957ef8964c0235e07c07449a39b2b8c94d4def --- /dev/null +++ b/isis/src/qisis/objs/AdvancedTrackTool/AdvancedTrackTool.cpp @@ -0,0 +1,543 @@ +#include "AdvancedTrackTool.h" + +#include +#include + +#include "Camera.h" +#include "iTime.h" +#include "MdiCubeViewport.h" +#include "Projection.h" +#include "SerialNumber.h" +#include "SpecialPixel.h" +#include "TableMainWindow.h" + +using namespace Isis; + +namespace Qisis { + + // For mosaic tracking + #define FLOAT_MIN -16777215 + #define TABLE_MOSAIC_SRC "InputImages" + + /** + * Constructs an AdvancedTrackTool object + * + * @param parent + */ + AdvancedTrackTool::AdvancedTrackTool (QWidget *parent) : Tool(parent) { + p_tableWin = new Qisis::TableMainWindow("Advanced Tracking", parent); + p_tableWin->setTrackListItems(true); + connect(p_tableWin,SIGNAL(fileLoaded()),this,SLOT(updateID())); + + p_action = new QAction(parent); + p_action->setText("Tracking ..."); + p_action->setIcon(QPixmap(toolIconDir()+"/goto.png")); + p_action->setShortcut(Qt::CTRL+Qt::Key_T); + p_action->setWhatsThis("Function: Opens the Advanced Tracking Tool \ + window. This window will track sample/line positions,\ + lat/lon positions, and many other pieces of \ + information. All of the data in the window can be \ + saved to a text file.

    Shortcut: Ctrl+T

    "); + connect(p_action,SIGNAL(triggered()),p_tableWin,SLOT(showTable())); + activate(true); + connect(p_action,SIGNAL(triggered()),p_tableWin,SLOT(raise())); + connect(p_action,SIGNAL(triggered()),p_tableWin,SLOT(syncColumns())); + p_tableWin->installEventFilter(this); + + p_tableWin->addToTable (false,"Id","Id"); + p_tableWin->addToTable (true,"Sample:Line", "Sample:Line", -1, Qt::Horizontal, "Sample and Line"); + p_tableWin->addToTable (false,"Band","Band"); + p_tableWin->addToTable (true,"Pixel","Pixel"); + p_tableWin->addToTable (true,"Planetocentric Latitude","Planetocentric Lat"); + p_tableWin->addToTable (false,"Planetographic Latitude","Planetographic Lat"); + p_tableWin->addToTable (true,"360 Positive East Longitude","360 East Longitude"); + p_tableWin->addToTable (false,"360 Positive West Longitude","360 West Longitude"); + p_tableWin->addToTable (true,"180 Positive East Longitude","180 East Longitude"); + p_tableWin->addToTable (false,"180 Positive West Longitude","180 West Longitude"); + p_tableWin->addToTable (false,"Projected X:Projected Y","Projected X:Projected Y", -1, Qt::Horizontal, "X and Y values for a projected image"); + p_tableWin->addToTable (false,"Local Radius","Radius"); + p_tableWin->addToTable (false,"Point X:Point Y:Point Z","XYZ", -1, Qt::Horizontal, "The X, Y, and Z of surface intersection in body-fixed coordinates"); + p_tableWin->addToTable (false,"Right Ascension:Declination","Ra:Dec", -1, Qt::Horizontal, "Right Ascension and Declination"); + p_tableWin->addToTable (false,"Resolution","Resolution"); + p_tableWin->addToTable (false,"Phase","Phase"); + p_tableWin->addToTable (false,"Incidence","Incidence"); + p_tableWin->addToTable (false,"Emission","Emission"); + p_tableWin->addToTable (false,"North Azimuth","North Azimuth"); + p_tableWin->addToTable (false,"Sun Azimuth","Sun Azimuth"); + p_tableWin->addToTable (false,"Solar Longitude","Solar Longitude"); + p_tableWin->addToTable (false,"Spacecraft X:Spacecraft Y:Spacecraft Z","Spacecraft Position", -1, Qt::Horizontal, "The X, Y, and Z of the spacecraft position"); + p_tableWin->addToTable (false,"Spacecraft Azimuth","Spacecraft Azimuth"); + p_tableWin->addToTable (false,"Slant Distance","Slant Distance"); + p_tableWin->addToTable (false,"Ephemeris Time","Ephemeris iTime"); + p_tableWin->addToTable (false,"Local Solar Time","Local Solar iTime"); + p_tableWin->addToTable (false,"UTC","UTC", -1, Qt::Horizontal, "Internal time in UTC format"); + p_tableWin->addToTable (false,"Path","Path"); + p_tableWin->addToTable (false,"Filename","Filename"); + p_tableWin->addToTable (false,"Serial Number","Serial Number"); + p_tableWin->addToTable (false,"Track Mosaic Index","Track Mosaic Index"); + p_tableWin->addToTable (false,"Track Mosaic FileName","Track Mosaic FileName"); + p_tableWin->addToTable (false,"Track Mosaic Serial Number","Track Mosaic Serial Number"); + p_tableWin->addToTable (false,"Notes","Notes"); + //This variable will keep track of how many times + // the user has issued the 'record' command. + p_id = 0; + + // Setup 10 blank rows in the table + for (int r=0; r<10; r++) { + p_tableWin->table()->insertRow(r); + for (int c=0; ctable()->columnCount(); c++) { + QTableWidgetItem *item = new QTableWidgetItem(""); + p_tableWin->table()->setItem(r,c,item); + } + } + + // Create the action for recording points + QAction *recordAction = new QAction (parent); + recordAction->setShortcut(Qt::Key_R); + parent->addAction(recordAction); + connect(recordAction,SIGNAL(activated()),this,SLOT(record())); + p_tableWin->setStatusMessage("To record press the R key"); + + } + + /** + * An event filter that calls methods on certain events. + * + * @param o + * @param e + * + * @return bool + */ + bool AdvancedTrackTool::eventFilter(QObject *o,QEvent *e) { + if (e->type() == QEvent::Show) { + activate(true); + } + else if (e->type() == QEvent::Hide) { + activate(false); + } + return Tool::eventFilter(o,e); + } + + + /** + * This method adds the action to bring up the track tool to the menu. + * + * @param menu + */ + void AdvancedTrackTool::addTo(QMenu *menu) { + menu->addAction(p_action); + } + + /** + * This method adds the action to bring up the track tool to the permanent tool + * bar. + * + * @param perm + */ + void AdvancedTrackTool::addToPermanent (QToolBar *perm) { + perm->addAction(p_action); + } + + /** + * This method is called when the mouse has moved across the viewport and + * updates the row accordingly. + * + * @param p + */ + void AdvancedTrackTool::mouseMove(QPoint p) { + updateRow(p); + } + + /** + * This method is called when the mouse leaved the viewport and clears any rows + * accordingly. + * + */ + void AdvancedTrackTool::mouseLeave() { + + if (cubeViewport()->isLinked()) { + for (int i = 0; i < p_numRows; i++) { + p_tableWin->clearRow(i + p_tableWin->currentRow()); + } + } else { + p_tableWin->clearRow(p_tableWin->currentRow()); + } + + } + + /** + * This method updates the row with data from the point given. + * + * @param p + */ + void AdvancedTrackTool::updateRow (QPoint p) { + MdiCubeViewport *cvp = cubeViewport(); + if (cvp == NULL) { + p_tableWin->clearRow(p_tableWin->currentRow()); + return; + } + + if(!cubeViewport()->isLinked()) { + updateRow (cvp,p,p_tableWin->currentRow()); + p_numRows = 1; + } + else { + p_numRows = 0; + for (int i = 0; i < (int)cubeViewportList()->size(); i++) { + MdiCubeViewport *d = (*(cubeViewportList()))[i]; + if (d->isLinked()) { + updateRow(d,p,p_tableWin->currentRow()+p_numRows); + p_numRows++; + } + } + } + } + + /** + * This method updates the row given with data from the viewport cvp at point p. + * + * @param cvp CubeViewPort that contains p + * @param p QPoint from which the row will be updated + * @param row Row to be updated + */ + void AdvancedTrackTool::updateRow (MdiCubeViewport *cvp, QPoint p, int row) { + // Get the sample line position to report + double sample,line; + cvp->viewportToCube(p.x(),p.y(),sample,line); + int isample = int (sample + 0.5); + int iline = int (line + 0.5); + + /*if there are linked cvp's then we want to highlight (select) + the row of the active cvp.*/ + if (cvp->isLinked()) { + + if (cvp == cubeViewport()) { + p_tableWin->table()->selectRow(row); + } + + } + + + // Do we need more rows? + if (row+1 > p_tableWin->table()->rowCount()) { + p_tableWin->table()->insertRow(row); + for (int c=0; ctable()->columnCount(); c++) { + QTableWidgetItem *item = new QTableWidgetItem(""); + p_tableWin->table()->setItem(row,c,item); + if (c == 0) p_tableWin->table()->scrollToItem(item); + } + } + + // Blank out the row to remove stuff left over from previous cvps + for (int c=0; ctable()->columnCount(); c++) { + p_tableWin->table()->item(row,c)->setText(""); + } + + // Don't write anything if we are outside the cube + if (sample < 0.5) return; + if (line < 0.5) return; + if (sample > cvp->cubeSamples()+0.5) return; + if (line > cvp->cubeLines() +0.5) return; + + // Write cols 0-2 (id, sample, line) + p_tableWin->table()->item(row,ID)->setText(QString::number(p_id)); + p_tableWin->table()->item(row,SAMPLE)->setText(QString::number(sample)); + p_tableWin->table()->item(row,LINE)->setText(QString::number(line)); + + // Write col 3 (band) + if (cvp->isGray()) { + p_tableWin->table()->item(row,BAND)->setText(QString::number(cvp->grayBand())); + } + else { + p_tableWin->table()->item(row,BAND)->setText(QString::number(cvp->redBand())); + } + + // Write out the path, filename, and serial number + Isis::Filename fname = Isis::Filename(cvp->cube()->Filename()).Expanded(); + std::string fnamePath = fname.Path(); + std::string fnameName = fname.Name(); + p_tableWin->table()->item(row,PATH)->setText(fnamePath.c_str()); + p_tableWin->table()->item(row,FILENAME)->setText(fnameName.c_str()); + //p_tableWin->table()->item(row,34)->setText(Isis::SerialNumber::Compose(*cvp->cube()).c_str()); + + // If we are outside of the image then we are done + if ((sample < 0.5) || (line < 0.5) || + (sample > cvp->cubeSamples()+0.5) || + (line > cvp->cubeLines()+0.5)) { + return; + } + + // Otherwise write out col 4 (Pixel value) + if (cvp->isGray()) { + std::string grayPixel = Isis::PixelToString(cvp->grayPixel(isample,iline)); + QString p = grayPixel.c_str(); + p_tableWin->table()->item(row,PIXEL)->setText(p); + } + else { + std::string redPixel = Isis::PixelToString(cvp->redPixel(isample,iline)); + QString p = redPixel.c_str(); + p_tableWin->table()->item(row,PIXEL)->setText(p); + } + + // Do we have a camera model? + if (cvp->camera() != NULL) { + if (cvp->camera()->SetImage(sample,line)) { + // Write columns 5,7,9 (ocentric lat/lon, and radius) + double lat = cvp->camera()->UniversalLatitude(); + double lon = cvp->camera()->UniversalLongitude(); + + double radius = cvp->camera()->LocalRadius(); + p_tableWin->table()->item(row,PLANETOCENTRIC_LAT)->setText(QString::number(lat,'f',15)); + p_tableWin->table()->item(row,EAST_LON_360)->setText(QString::number(lon,'f',15)); + p_tableWin->table()->item(row,RADIUS)->setText(QString::number(radius,'f',15)); + + /* 180 Positive East Lon. */ + p_tableWin->table()->item(row,EAST_LON_180)->setText(QString::number(Isis::Projection::To180Domain(lon),'f',15)); + + // Write out the planetographic and positive west values + lon = -lon; + while (lon < 0.0) lon += 360.0; + double radii[3]; + cvp->camera()->Radii(radii); + lat = Isis::Projection::ToPlanetographic(lat,radii[0],radii[2]); + p_tableWin->table()->item(row,PLANETOGRAPHIC_LAT)->setText(QString::number(lat,'f',15)); + p_tableWin->table()->item(row,WEST_LON_360)->setText(QString::number(lon,'f',15)); + + /*180 Positive West Lon. */ + p_tableWin->table()->item(row,WEST_LON_180)->setText(QString::number(Isis::Projection::To180Domain(lon),'f',15)); + + // Next write out columns 10-12 (the x/y/z position of the lat/lon) + double pos[3]; + cvp->camera()->Coordinate(pos); + p_tableWin->table()->item(row,POINT_X)->setText(QString::number(pos[0])); + p_tableWin->table()->item(row,POINT_Y)->setText(QString::number(pos[1])); + p_tableWin->table()->item(row,POINT_Z)->setText(QString::number(pos[2])); + + // Write out columns 15 (resolution) + double res = cvp->camera()->PixelResolution(); + p_tableWin->table()->item(row,RESOLUTION)->setText(QString::number(res)); + + // Write out columns 16-18 (phase, incidence, emission) + double phase = cvp->camera()->PhaseAngle(); + double incidence = cvp->camera()->IncidenceAngle(); + double emission = cvp->camera()->EmissionAngle(); + p_tableWin->table()->item(row,PHASE)->setText(QString::number(phase)); + p_tableWin->table()->item(row,INCIDENCE)->setText(QString::number(incidence)); + p_tableWin->table()->item(row,EMISSION)->setText(QString::number(emission)); + + // Write out columns 19-21 (north azimuth, sun azimuth, solar longitude) + double northAzi = cvp->camera()->NorthAzimuth(); + double sunAzi = cvp->camera()->SunAzimuth(); + double solarLon = cvp->camera()->SolarLongitude(); + p_tableWin->table()->item(row,NORTH_AZIMUTH)->setText(QString::number(northAzi)); + p_tableWin->table()->item(row,SUN_AZIMUTH)->setText(QString::number(sunAzi)); + p_tableWin->table()->item(row,SOLAR_LON)->setText(QString::number(solarLon)); + + // Write out columns 25-29 (spacecraft azimuth, slant distance, + // et, local solar time, and UTC) + double spacecraftAzi = cvp->camera()->SpacecraftAzimuth(); + double slantDistance = cvp->camera()->SlantDistance(); + double lst = cvp->camera()->LocalSolarTime(); + p_tableWin->table()->item(row,SPACECRAFT_AZIMUTH)->setText(QString::number(spacecraftAzi)); + p_tableWin->table()->item(row,SLANT)->setText(QString::number(slantDistance)); + p_tableWin->table()->item(row,SOLAR_TIME)->setText(QString::number(lst)); + } + + // Always write out columns 13-14 (ra/dec); + double ra = cvp->camera()->RightAscension(); + double dec = cvp->camera()->Declination(); + p_tableWin->table()->item(row,RIGHT_ASCENSION)->setText(QString::number(ra)); + p_tableWin->table()->item(row,DECLINATION)->setText(QString::number(dec)); + + // Always write out columns 27/29 et and utc + double et = cvp->camera()->EphemerisTime(); + Isis::iTime time(et); + p_tableWin->table()->item(row,EPHEMERIS_TIME)->setText(QString::number(et,'f',15)); + std::string time_utc = time.UTC(); + p_tableWin->table()->item(row,UTC)->setText(time_utc.c_str()); + + // Always out columns 22-24 (spacecraft position) + double pos[3]; + cvp->camera()->InstrumentPosition(pos); + p_tableWin->table()->item(row,SPACECRAFT_X)->setText(QString::number(pos[0])); + p_tableWin->table()->item(row,SPACECRAFT_Y)->setText(QString::number(pos[1])); + p_tableWin->table()->item(row,SPACECRAFT_Z)->setText(QString::number(pos[2])); + } + + else if (cvp->projection() != NULL) { + if (cvp->projection()->SetWorld(sample,line)) { + double lat = cvp->projection()->UniversalLatitude(); + double lon = cvp->projection()->UniversalLongitude(); + + double glat = cvp->projection()->ToPlanetographic(lat); + double wlon = -lon; + while (wlon < 0.0) wlon += 360.0; + if (cvp->projection()->IsSky()) { + lon = cvp->projection()->Longitude(); + p_tableWin->table()->item(row,RIGHT_ASCENSION)->setText(QString::number(lon,'f',15)); + p_tableWin->table()->item(row,DECLINATION)->setText(QString::number(lat,'f',15)); + } + else { + double radius = cvp->projection()->LocalRadius(); + p_tableWin->table()->item(row,PLANETOCENTRIC_LAT)->setText(QString::number(lat,'f',15)); + p_tableWin->table()->item(row,PLANETOGRAPHIC_LAT)->setText(QString::number(glat,'f',15)); + p_tableWin->table()->item(row,EAST_LON_360)->setText(QString::number(lon,'f',15)); + p_tableWin->table()->item(row,EAST_LON_180)->setText(QString::number(Isis::Projection::To180Domain(lon),'f',15)); + p_tableWin->table()->item(row,WEST_LON_360)->setText(QString::number(wlon,'f',15)); + p_tableWin->table()->item(row,WEST_LON_180)->setText(QString::number(Isis::Projection::To180Domain(wlon),'f',15)); + p_tableWin->table()->item(row,RADIUS)->setText(QString::number(radius,'f',15)); + } + } + } + + //If there is a projection add the Projected X and Y coords to the table + if(cvp->projection() != NULL) { + if (cvp->projection()->SetWorld(sample,line)) { + double projX = cvp->projection()->XCoord(); + double projY = cvp->projection()->YCoord(); + p_tableWin->table()->item(row, PROJECTED_X)->setText(QString::number(projX, 'f', 15)); + p_tableWin->table()->item(row, PROJECTED_Y)->setText(QString::number(projY, 'f', 15)); + } + } + + // Track the Mosaic Origin - Index (Zero based) and FileName + int iMosaicOrigin=-1; + std::string sSrcFileName=""; + std::string sSrcSerialNum=""; + TrackMosaicOrigin(cvp, iline, isample, iMosaicOrigin, sSrcFileName, sSrcSerialNum); + p_tableWin->table()->item(row, TRACK_MOSAIC_INDEX)->setText(QString::number(iMosaicOrigin)); + p_tableWin->table()->item(row, TRACK_MOSAIC_FILENAME)->setText(QString(sSrcFileName.c_str())); + p_tableWin->table()->item(row, TRACK_MOSAIC_SERIAL_NUM)->setText(QString(sSrcSerialNum.c_str())); + } + + + /** + * TrackMosaicOrigin - Given the pointer to Cube and line and + * sample index, finds the origin of the mosaic if the TRACKING + * band and Mosaic Origin Table exists. + * + * @author sprasad (11/16/2009) + * + * @param cvp - Points to the CubeViewPort + * @param piLine - Line Index + * @param piSample - Sample Index + * @param piOrigin - Contains the Src Index (zero based) + * @param psSrcFileName - Contains the Src Filename + * @param psSrcSerialNum- Contains the Src Serial Number + * + * @return void + */ + void AdvancedTrackTool::TrackMosaicOrigin(MdiCubeViewport *cvp, int piLine, + int piSample, int & piOrigin, std::string & psSrcFileName, + std::string & psSrcSerialNum) + { + Cube* cCube = cvp->cube(); + int iTrackBand=-1; + + if (cCube->HasTable(TABLE_MOSAIC_SRC)) { + Pvl* cPvl = cCube->Label(); + PvlObject cObjIsisCube = cPvl->FindObject("IsisCube"); + PvlGroup cGrpBandBin = cObjIsisCube.FindGroup("BandBin"); + for (int i=0; i 0 && iTrackBand <= cCube->Bands()) { + Isis::Portal cOrgPortal (cCube->Samples(), 1, cCube->PixelType()); + cOrgPortal.SetPosition (piSample, piLine, iTrackBand+1); // 1 based + cCube->Read(cOrgPortal); + + piOrigin = (int)cOrgPortal[0]; + switch (SizeOf(cCube->PixelType())) { + case 1: + piOrigin -= VALID_MIN1; + break; + + case 2: + piOrigin -= VALID_MIN2; + break; + + case 4: + piOrigin -= FLOAT_MIN; + break; + } + + // Get the input file name and serial number + Table cFileTable(TABLE_MOSAIC_SRC); + cCube->Read(cFileTable); + int iRecs = cFileTable.Records(); + if (piOrigin >=0 && piOrigin < iRecs) { + psSrcFileName = std::string(cFileTable[piOrigin][0]); + psSrcSerialNum = std::string(cFileTable[piOrigin][1]); + } + } + } + } + + /** + * This method records data to the current row. + * + */ + void AdvancedTrackTool::record () { + if (p_tableWin->table()->isHidden()) return; + if (p_tableWin->table()->item(p_tableWin->currentRow(),0)->text() == "") return; + + int row = 0; + p_tableWin->setCurrentRow(p_tableWin->currentRow() + p_numRows); + p_tableWin->setCurrentIndex(p_tableWin->currentIndex() + p_numRows); + while (p_tableWin->currentRow() >= p_tableWin->table()->rowCount()) { + row = p_tableWin->table()->rowCount(); + p_tableWin->table()->insertRow(row); + for (int c=0; ctable()->columnCount(); c++) { + QTableWidgetItem *item = new QTableWidgetItem(""); + p_tableWin->table()->setItem(row,c,item); + } + } + + QApplication::sendPostedEvents(p_tableWin->table(),0); + p_tableWin->table()->scrollToItem(p_tableWin->table()->item(p_tableWin->currentRow(),0),QAbstractItemView::PositionAtBottom); + + //Keep track of number times user presses 'R' (record command) + p_id = p_tableWin->table()->item(p_tableWin->currentRow()-1, 0)->text().toInt() + 1; + } + + + /** + * This slot updates the row with data from the point given and + * records data to the current row. + * + * @param p QPoint from which the row(s) will be updated and + * recorded. + * @return void + * @author Jeannie Walldren + * + * @internal + * @history 2010-03-08 - Jeannie Walldren - This slot was + * added to be connected to the FindTool recordPoint() + * signal in qview. + * @history 2010-05-07 - Eric Hyer - Now shows the table as well + */ + void AdvancedTrackTool::record (QPoint p) { + updateRow(p); + record(); + p_tableWin->showTable(); + } + + /** + * This method updates the record ID. + * + */ + void AdvancedTrackTool::updateID() { + //Check if the current row is 0 + if(p_tableWin->currentRow() == 0) + p_id = 0; + else + p_id = p_tableWin->table()->item(p_tableWin->currentRow()-1, ID)->text().toInt() + 1; + } +} diff --git a/isis/src/qisis/objs/AdvancedTrackTool/AdvancedTrackTool.h b/isis/src/qisis/objs/AdvancedTrackTool/AdvancedTrackTool.h new file mode 100644 index 0000000000000000000000000000000000000000..1d162e631064192275b13505b4d3cd36c7b77f09 --- /dev/null +++ b/isis/src/qisis/objs/AdvancedTrackTool/AdvancedTrackTool.h @@ -0,0 +1,149 @@ +#ifndef Qisis_AdvancedTrackTool_h +#define Qisis_AdvancedTrackTool_h +/** + * @file + * $Revision: 1.18 $ + * $Date: 2010/06/28 08:47:51 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +// The only includes allowed in this file are the direct parents of this class! +#include "Tool.h" + +class QAction; + +namespace Qisis { + class TableMainWindow; + class MdiCubeViewport; + + /** + * @brief Tool to display info for a point on a cube + * + * This tool is part of the Qisis namespace and allows the user to view and + * record information from a point on a cube such as line, sample, band, lats, + * longs, etc. + * + * @ingroup Visualization Tools + * + * @author ?? Unknown + * + * @internal + * @history 2008-06-25 Noah Hilt - Added enumeration for different column + * values. + * @history 2008-10-14 Noah Hilt - Added Projected X and Y values to the table. + * @history 2008-10-17 Noah Hilt - Added tooltips to certain items in the table + * that did not have descriptive names. + * @history 2010-02-17 Sharmila Prasad -Added the attributes + * TRACK_MOSAIC_INDEX, TRACK_MOSAIC_FILENAME, + * TRACK_MOSAIC_SERIAL_NUM to track mosaic origin + * @history 2010-03-08 Jeannie Walldren - Added + * record() slot to be able to record a + * QPoint passed from the FindTool to the current row. + * @history 2010-05-07 Eric Hyer - record() SLOT now shows the table as well + * @history 2010-06-26 Eric Hyer - Class now uses MdiCubeViewport, also fixed + * include issues + */ + class AdvancedTrackTool : public Tool { + Q_OBJECT + + public: + AdvancedTrackTool (QWidget *parent); + void addTo(QMenu *menu); + void addToPermanent (QToolBar *perm); + bool eventFilter(QObject *o,QEvent *e); + + public slots: + virtual void mouseMove(QPoint p); + virtual void mouseLeave(); + void record(QPoint p); + + protected: + /** + * This method returns the menu name associated with this tool. + * + * + * @return QString + */ + QString menuName() const { return "&Options"; }; + + private slots: + void updateRow(QPoint p); + void updateRow(MdiCubeViewport *cvp, QPoint p, int row); + void record(); + void updateID(); + void TrackMosaicOrigin(MdiCubeViewport *cvp, int piLine, int piSample, + int & piOrigin, std::string & psSrcFileName, + std::string & psSrcSerialNum); + + private: + /** + * Enum for column values + */ + enum { + ID, //!< The record ID + SAMPLE, //!< The current sample + LINE, //!< The current line + BAND, //!< The current band + PIXEL, //!< The current pixel + PLANETOCENTRIC_LAT, //!< The planetocentric latitude for this point + PLANETOGRAPHIC_LAT, //!< The planetographic latitude for this point + EAST_LON_360, //!< The 360 east longitude for this point + WEST_LON_360, //!< The 360 west longitude for this point + EAST_LON_180, //!< The 180 east longitude for this point + WEST_LON_180, //!< The 180 west longitude for this point + PROJECTED_X, //!< Projected X value for valid projections + PROJECTED_Y, //!< Projected Y value for valid projections + RADIUS, //!< The radius for this point + POINT_X, //!< The x value for this point + POINT_Y, //!< The y value for this point + POINT_Z, //!< The z value for this point + RIGHT_ASCENSION, //!< The right ascension for this point + DECLINATION, //!< The declination for this point + RESOLUTION, //!< The resoultion for this point + PHASE, //!< The phase for this point + INCIDENCE, //!< The incidence for this point + EMISSION, //!< The emission for this point + NORTH_AZIMUTH, //!< The north azimuth for this cube + SUN_AZIMUTH, //!< The sun azimuth for this cube + SOLAR_LON, //!< The solar longitude for this point + SPACECRAFT_X, //!< The spacecraft x position for this cube + SPACECRAFT_Y, //!< The spacecraft y position for this cube + SPACECRAFT_Z, //!< The spacecraft z position for this cube + SPACECRAFT_AZIMUTH, //!< The spacecraft azimuth for this cube + SLANT, //!< The slant for this cube + EPHEMERIS_TIME, //!< The ephemeris time for this cube + SOLAR_TIME, //!< The local solar time for this cube + UTC, //!< The UTC for this cube + PATH, //!< The path for this cube + FILENAME, //!< The filename for this cube + SERIAL_NUMBER, //!< The serial number for this cube + TRACK_MOSAIC_INDEX, //!< Track the origin of the Mosaic, display the zero based index + TRACK_MOSAIC_FILENAME, //!< Track the origin of the Mosaic, display file name + TRACK_MOSAIC_SERIAL_NUM,//!< Track the origin of the Mosaic, display file name + NOTES //!< Any notes for this record + }; + QAction *p_action; //!< Action to bring up the track tool + int p_numRows; //!< The number of rows in the table + int p_id; //!< The record id + Qisis::TableMainWindow *p_tableWin; //!< The table window + + }; + +}; + +#endif diff --git a/isis/src/qisis/objs/AdvancedTrackTool/Makefile b/isis/src/qisis/objs/AdvancedTrackTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/AdvancedTrackTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/BandSpinBox/BandSpinBox.cpp b/isis/src/qisis/objs/BandSpinBox/BandSpinBox.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da7af8696870e9f350b6bfd8c117bfb17ae5c18c --- /dev/null +++ b/isis/src/qisis/objs/BandSpinBox/BandSpinBox.cpp @@ -0,0 +1,223 @@ +#include + +#include "BandSpinBox.h" +#include "iException.h" + +namespace Qisis { + /** + * BandSpinBox constructor + * + * + * @param parent + */ + BandSpinBox::BandSpinBox (QWidget *parent) : QSpinBox(parent) { + QStringList list; + list.push_back(QString::number(1)); + p_lastKey = "BandNumber"; + p_map[p_lastKey] = list; + p_bands = 1; + + setValue(1); + setMinimum(1); + setMaximum(p_bands); + } + + + /** + * Sets the band bin + * + * + * @param pvl + * @param key + */ + void BandSpinBox::setBandBin (Isis::Pvl &pvl, const QString &key) { + // Remove all connections and clear the keyword map + disconnect (this,0,0,0); + p_map.clear(); + + // Get the number of bands and setup the spin box + Isis::PvlGroup &dim = pvl.FindObject("IsisCube") + .FindObject("Core") + .FindGroup("Dimensions"); + p_bands = dim["Bands"]; + + // Put in the default BandNumber list + QStringList list; + for (int i=1; i<=p_bands; i++) { + list.push_back(QString::number(i)); + } + p_map["BandNumber"] = list; + + // Add any other lists + if (pvl.FindObject("IsisCube").HasGroup("BandBin")) { + Isis::PvlGroup &bandBin = pvl.FindObject("IsisCube") + .FindGroup("BandBin"); + for (int i=0; i= (int) p_map.size())) { + throw Isis::iException::Message(Isis::iException::Programmer, + "Invalid key",_FILEINFO_); + } + else { + setKey(p_keys[key]); + } + } + + + /** + * Gets the text using p_map. + * + * + * @param val + * + * @return QString + */ + QString BandSpinBox::textFromValue (int val) const { + if ((val < 1) || (val > p_bands)) { + std::cout << "BandSpinBox: Bad index in textFromValue" << std::endl; + return QString("Error"); + } + + if (p_map.contains(p_lastKey)) { + return p_map[p_lastKey][val-1]; + } + else { + std::cout << "BandSpinBox: Bad value for p_lastKey in textFromValue" << std::endl; + return QString("Error"); + } + } + + + /** + * gets the value (int) using p_map. + * + * + * @param text + * + * @return int + */ + int BandSpinBox::valueFromText (const QString &text) const { + if (p_map.contains(p_lastKey)) { + for (int i=0; itextFromValue(i))); + } + + QSize s = QSpinBox::sizeHint(); + int neww = s.width() + w; + + int minw = fm.width(((BandSpinBox *) this)->textFromValue(minimum())); + int maxw = fm.width(((BandSpinBox *) this)->textFromValue(maximum())); + + if (minw < maxw) { + neww -= maxw; + } + else { + neww -= minw; + } + s.setWidth(neww+5); + return s; + } + + + /** + * returns how valid the value from the spin box is. + * + * + * @param input + * @param pos + * + * @return QValidator::State + */ + QValidator::State BandSpinBox::validate(QString &input, int &pos) const { + int count = 0; + int exact = false; + for (int i=0; i 0 && exact) return QValidator::Acceptable; + return QValidator::Intermediate; + } +} diff --git a/isis/src/qisis/objs/BandSpinBox/BandSpinBox.h b/isis/src/qisis/objs/BandSpinBox/BandSpinBox.h new file mode 100644 index 0000000000000000000000000000000000000000..e3efe8bdf81a3553a904697b5996e68de74c4661 --- /dev/null +++ b/isis/src/qisis/objs/BandSpinBox/BandSpinBox.h @@ -0,0 +1,37 @@ +#ifndef BandSpinBox_h +#define BandSpinBox_h + +#include +#include + +#include "Pvl.h" + +namespace Qisis { + class BandSpinBox : public QSpinBox { + Q_OBJECT + + public: + BandSpinBox (QWidget *parent = 0); + void setBandBin (Isis::Pvl &pvl, const QString &key = "BandNumber"); + QStringList BandBinKeys (); + QSize sizeHint() const; + QValidator::State validate(QString &input, int &pos) const; + + public slots: + void setKey(QString key); + void setKey(int key); + + protected: + QString textFromValue (int val) const; + int valueFromText (const QString &text) const; + + private: + int p_bands; //!< Number of bands + + QMap p_map; //!< The maps the last key to all the keys + QString p_lastKey; //!< The last key + QStringList p_keys; //!< List of all the keys + }; +} + +#endif diff --git a/isis/src/qisis/objs/BandSpinBox/Makefile b/isis/src/qisis/objs/BandSpinBox/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/BandSpinBox/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/BandTool/BandTool.cpp b/isis/src/qisis/objs/BandTool/BandTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f65a28f7fa71a941aecd3483863bd6c1c9d9656 --- /dev/null +++ b/isis/src/qisis/objs/BandTool/BandTool.cpp @@ -0,0 +1,503 @@ +#include "BandTool.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Cube.h" +#include "MdiCubeViewport.h" +#include "Pvl.h" +#include "ToolPad.h" + +namespace Qisis { + + /** + * BandTool constructor. + * + * + * @param parent + */ + BandTool::BandTool (QWidget *parent) : Qisis::Tool(parent) { + } + + /** + * + * + * @param pad + * + * @return QAction* + */ + QAction *BandTool::toolPadAction(ToolPad *pad) { + QAction *action = new QAction(pad); + action->setIcon(QPixmap(toolIconDir()+"/rgb.png")); + action->setToolTip("Band Selection (B)"); + action->setShortcut(Qt::Key_B); + QString text = + "Function: Change the view of the cube from gray scale to RGB.\ +

    Shortcut: B

    "; + action->setWhatsThis(text); + return action; + } + + /** + * + * + * @param active + * + * @return QWidget* + */ + QWidget *BandTool::createToolBarWidget (QStackedWidget *active) { + QWidget*hbox = new QWidget(active); + + p_rgbButton = new QRadioButton(hbox); + p_blackwhiteButton = new QRadioButton(hbox); + + + QMenu *copyMenu = new QMenu(); + QAction *copyLinked = new QAction(active); + copyLinked->setText("to Linked Viewports"); + connect(copyLinked,SIGNAL(triggered(bool)),this,SLOT(copyLinkedViewports())); + + QAction *copyAll = new QAction(active); + copyAll->setText("to All Viewports"); + connect(copyAll,SIGNAL(triggered(bool)),this,SLOT(copyAllViewports())); + + copyMenu->addAction(copyLinked); + copyMenu->addAction(copyAll); + + QToolButton *copyButton = new QToolButton(hbox); + copyButton->setAutoRaise(true); + copyButton->setIconSize(QSize(22,22)); + copyButton->setPopupMode(QToolButton::MenuButtonPopup); + copyButton->setMenu(copyMenu); + copyButton->setDefaultAction(copyAll); + copyButton->setIcon(QPixmap(toolIconDir() + "/copy_bands.png")); + copyButton->setToolTip("Copy"); + QString text = + "Function:"; + copyButton->setWhatsThis(text); + + QIcon colorIcon; + QIcon grayIcon; + colorIcon.addPixmap(toolIconDir()+"/rgb.png",QIcon::Normal,QIcon::On); + grayIcon.addPixmap(toolIconDir()+"/gray.png",QIcon::Normal,QIcon::Off); + p_rgbButton->setIcon(colorIcon); + p_rgbButton->setText("RGB"); + p_blackwhiteButton->setIcon(grayIcon); + p_blackwhiteButton->setText("Gray"); + p_rgbButton->setCheckable(true); + p_rgbButton->setIconSize(QSize(22,22)); + p_blackwhiteButton->setIconSize(QSize(22,22)); + p_rgbButton->setToolTip("Change to RGB"); + p_blackwhiteButton->setToolTip("Change to grayscale"); + text = + "Function: Toggle the active viewport between color or \ + grayscale display of the cube. Color display is only possible if \ + the cube has two or more bands"; + p_rgbButton->setWhatsThis(text); + p_blackwhiteButton->setWhatsThis(text); + + p_comboBox = new QComboBox(hbox); + p_comboBox->setEditable(false); + p_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + p_comboBox->addItem("Wavelength"); + p_comboBox->setToolTip("Select BandBin keyword"); + text = + "Function: The default option \"Wavelength\" \ + simply shows the current band displayed in the viewport. However, \ + the labels of many cubes contain the BandBin group. \ + Keywords in this group describe the bands in a meaningful way, \ + such as WaveLength, Filter, Temperature, iTime, etc. \ + Selecting an alternative BandBin keyword will cause those values \ + to show in the spin boxes to the right."; + p_comboBox->setWhatsThis(text); + + p_stack = new QStackedWidget(hbox); + + QWidget *stuff1 = new QWidget(p_stack); + p_graySpin = new QSpinBox(stuff1); + p_graySpin->setToolTip("Change gray band"); + p_stack->addWidget(stuff1); + + QWidget *stuff2 = new QWidget(p_stack); + p_redSpin = new QSpinBox(stuff2); + p_redSpin->setToolTip("Change red band"); + p_grnSpin = new QSpinBox(stuff2); + p_grnSpin->setToolTip("Change green band"); + p_bluSpin = new QSpinBox(stuff2); + p_bluSpin->setToolTip("Change blue band"); + p_stack->addWidget(stuff2); + + p_stack2 = new QStackedWidget(hbox); + QWidget *grayWidget = new QWidget(p_stack2); + p_grayDisplay = new QLabel(grayWidget); + p_grayDisplay->setFrameStyle(QFrame::Panel | QFrame::Sunken); + p_stack2->addWidget(grayWidget); + + QWidget *colorWidget = new QWidget(p_stack2); + p_redDisplay = new QLabel(colorWidget); + p_greenDisplay = new QLabel(colorWidget); + p_blueDisplay = new QLabel(colorWidget); + p_redDisplay->setFrameStyle(QFrame::Panel | QFrame::Sunken); + p_greenDisplay->setFrameStyle(QFrame::Panel | QFrame::Sunken); + p_blueDisplay->setFrameStyle(QFrame::Panel | QFrame::Sunken); + p_stack2->addWidget(colorWidget); + + + QHBoxLayout *displayLayout = new QHBoxLayout(grayWidget); + displayLayout->addWidget(p_grayDisplay); + displayLayout->addStretch(1); + grayWidget->setLayout(displayLayout); + + displayLayout = new QHBoxLayout(colorWidget); + displayLayout->addWidget(p_redDisplay); + displayLayout->addWidget(p_greenDisplay); + displayLayout->addWidget(p_blueDisplay); + colorWidget->setLayout(displayLayout); + + QHBoxLayout *layout = new QHBoxLayout(stuff1); + layout->setMargin(0); + layout->addWidget(p_graySpin); + layout->addStretch(1); + stuff1->setLayout(layout); + + layout = new QHBoxLayout(stuff2); + layout->setMargin(0); + layout->addWidget(p_redSpin); + layout->addWidget(p_grnSpin); + layout->addWidget(p_bluSpin); + + stuff2->setLayout(layout); + + p_stack->setCurrentIndex(0); + p_stack2->setCurrentIndex(0); + p_rgbButton->setChecked(false); + p_blackwhiteButton->setChecked(true); + + QFrame *vertLine = new QFrame(); + vertLine->setFrameShape(QFrame::VLine); + vertLine->setFrameShadow(QFrame::Sunken); + + layout = new QHBoxLayout(hbox); + layout->setMargin(0); + layout->addWidget(p_rgbButton); + layout->addWidget(p_blackwhiteButton); + layout->addWidget(copyButton); + layout->addWidget(p_stack); + layout->addWidget(vertLine); + layout->addWidget(p_comboBox); + layout->addWidget(p_stack2); + layout->addStretch(1); + hbox->setLayout(layout); + + return hbox; + } + + + /** + * This method sets the p_lineEditValueList to the proper values + * according to what the user has selected in the p_comboBox. + * These are the values shown in the gray boxes. + */ + void BandTool::setList() { + if (p_pvl.FindObject("IsisCube").HasGroup("BandBin") && + p_comboBox->count() > 0) { + + Isis::PvlGroup &bandBin = p_pvl.FindObject("IsisCube") + .FindGroup("BandBin"); + p_comboBox->setVisible(true); + p_grayDisplay->setVisible(true); + p_redDisplay->setVisible(true); + p_greenDisplay->setVisible(true); + p_blueDisplay->setVisible(true); + + for (int i=0; icurrentText().toStdString()) { + p_lineEditValueList.clear(); + for (int j=0; jsetVisible(false); + p_grayDisplay->setVisible(false); + p_redDisplay->setVisible(false); + p_greenDisplay->setVisible(false); + p_blueDisplay->setVisible(false); + } + } + + + /** + * This method fills the p_comboBox with the keywords from the + * band bin group of the currently selected cube. If there are + * values for 'Center', that is choosen as the default. + * + * @param pvl + */ + void BandTool::setBandBin (Isis::Pvl &pvl) { + + // Get the number of bands and setup the spin box + Isis::PvlGroup &dim = pvl.FindObject("IsisCube") + .FindObject("Core") + .FindGroup("Dimensions"); + p_pvl = pvl; + p_bands = dim["Bands"]; + + p_graySpin->setValue(1); + p_graySpin->adjustSize(); + p_graySpin->setMinimum(1); + p_graySpin->setMaximum(p_bands); + + p_redSpin->setValue(1); + p_redSpin->setMinimum(1); + p_redSpin->setMaximum(p_bands); + + p_bluSpin->setValue(1); + p_bluSpin->setMinimum(1); + p_bluSpin->setMaximum(p_bands); + + p_grnSpin->setValue(1); + p_grnSpin->setMinimum(1); + p_grnSpin->setMaximum(p_bands); + + p_comboBox->clear(); + if (pvl.FindObject("IsisCube").HasGroup("BandBin")) { + Isis::PvlGroup &bandBin = pvl.FindObject("IsisCube") + .FindGroup("BandBin"); + for (int i=0; iaddItem(QString(bandBinName.c_str())); + } + + } + + if (p_comboBox->findText("Center") > 0) { + p_comboBox->setCurrentIndex(p_comboBox->findText("Center")); + } + } + setList(); + } + + + /** + * This method is connected to the qspinboxes. When the user + * selects a new band, the viewport needs to be updated and the + * values display next to the p_comboBox also need to be + * updated. + * + */ + void BandTool::changeView () { + MdiCubeViewport *v = cubeViewport(); + + if (v == NULL) return; + + if (p_rgbButton->isChecked()) { + p_stack->setCurrentIndex(1); + p_stack2->setCurrentIndex(1); + if (v->isGray() || + p_redSpin->value() != v->redBand() || + p_grnSpin->value() != v->greenBand() || + p_bluSpin->value() != v->blueBand()) { + v->viewRGB(p_redSpin->value(),p_grnSpin->value(),p_bluSpin->value()); + } + } + else { + p_stack->setCurrentIndex(0); + p_stack2->setCurrentIndex(0); + if (v->isColor() || p_graySpin->value() != v->grayBand()) { + v->viewGray(p_graySpin->value()); + } + } + + setDisplay(); + + } + + + /** + * This method updates the values displayed in the gray boxes. + * Called from changeView. + */ + void BandTool::setDisplay(){ + //Gray + if(p_graySpin->value()-1 < p_lineEditValueList.size()) { + p_grayDisplay->setText + (p_lineEditValueList[p_graySpin->value()-1]); + } else { + p_grayDisplay->setText("N/A"); + } + p_grayDisplay->adjustSize(); + + //Red + if(p_redSpin->value()-1 < p_lineEditValueList.size()){ + p_redDisplay->setText + (p_lineEditValueList[p_redSpin->value()-1]); + } else { + p_redDisplay->setText("N/A"); + } + p_redDisplay->adjustSize(); + + //Green + if(p_grnSpin->value()-1 < p_lineEditValueList.size()){ + p_greenDisplay->setText + (p_lineEditValueList[p_grnSpin->value()-1]); + } else{ + p_greenDisplay->setText("N/A"); + } + p_greenDisplay->adjustSize(); + + //Blue + if(p_bluSpin->value()-1 < p_lineEditValueList.size()){ + p_blueDisplay->setText + (p_lineEditValueList[p_bluSpin->value()-1]); + } else { + p_blueDisplay->setText("N/A"); + } + p_blueDisplay->adjustSize(); + + } + + /** + * This method copies the selected bands to all linked viewports. + * + */ + void BandTool::copyLinkedViewports() { + if(!cubeViewport()->isLinked()) return; + + for(int i = 0; i < (int)cubeViewportList()->size(); i++) { + MdiCubeViewport *cvp = cubeViewportList()->at(i); + if(!cvp->isLinked() || cvp == cubeViewport()) continue; + + int bands = cvp->cubeBands(); + + if (p_rgbButton->isChecked()) { + if (cvp->isGray() || + p_redSpin->value() != cvp->redBand() || + p_grnSpin->value() != cvp->greenBand() || + p_bluSpin->value() != cvp->blueBand()) { + + if(p_redSpin->value() > bands || + p_grnSpin->value() > bands || + p_bluSpin->value() > bands) continue; + + cvp->viewRGB(p_redSpin->value(),p_grnSpin->value(),p_bluSpin->value()); + } + } + else { + if (cvp->isColor() || p_graySpin->value() != cvp->grayBand()) { + if(p_graySpin->value() > bands) continue; + + cvp->viewGray(p_graySpin->value()); + } + } + } + } + + /** + * This methods copies the selected bands to all viewports. + * + */ + void BandTool::copyAllViewports() { + for(int i = 0; i < (int)cubeViewportList()->size(); i++) { + MdiCubeViewport *cvp = cubeViewportList()->at(i); + + int bands = cvp->cubeBands(); + + if (p_rgbButton->isChecked()) { + if (cvp->isGray() || + p_redSpin->value() != cvp->redBand() || + p_grnSpin->value() != cvp->greenBand() || + p_bluSpin->value() != cvp->blueBand()) { + + if(p_redSpin->value() > bands || + p_grnSpin->value() > bands || + p_bluSpin->value() > bands) continue; + + cvp->viewRGB(p_redSpin->value(),p_grnSpin->value(),p_bluSpin->value()); + } + } + else { + if (cvp->isColor() || p_graySpin->value() != cvp->grayBand()) { + if(p_graySpin->value() > bands) continue; + + cvp->viewGray(p_graySpin->value()); + } + } + } + } + + /** + * updates the band tool + * + */ + void BandTool::updateTool() { + + disconnect (p_comboBox,0,0,0); + disconnect (p_graySpin,0,0,0); + disconnect (p_redSpin,0,0,0); + disconnect (p_grnSpin,0,0,0); + disconnect (p_bluSpin,0,0,0); + disconnect(p_rgbButton,0,0,0); + + MdiCubeViewport *cvp = cubeViewport(); + if (cvp != NULL) { + + setBandBin(*cvp->cube()->Label()); + + if (cvp->isGray()) { + + p_rgbButton->setChecked(false); + p_blackwhiteButton->setChecked(true); + p_stack->setCurrentIndex(0); + p_stack2->setCurrentIndex(0); + + } + else { + p_rgbButton->setChecked(true); + p_blackwhiteButton->setChecked(false); + p_stack->setCurrentIndex(1); + p_stack2->setCurrentIndex(1); + } + + p_graySpin->setValue(cvp->grayBand()); + p_graySpin->updateGeometry(); + + p_redSpin->setValue(cvp->redBand()); + p_redSpin->updateGeometry(); + + p_grnSpin->setValue(cvp->greenBand()); + p_grnSpin->updateGeometry(); + + p_bluSpin->setValue(cvp->blueBand()); + p_bluSpin->updateGeometry(); + + changeView(); + + connect(p_comboBox,SIGNAL(activated(int)),this,SLOT(setList())); + connect(p_comboBox,SIGNAL(activated(int)),this,SLOT(setDisplay())); + + connect(p_graySpin,SIGNAL(valueChanged(int)),this,SLOT(changeView())); + connect(p_redSpin,SIGNAL(valueChanged(int)),this,SLOT(changeView())); + connect(p_grnSpin,SIGNAL(valueChanged(int)),this,SLOT(changeView())); + connect(p_bluSpin,SIGNAL(valueChanged(int)),this,SLOT(changeView())); + + connect(p_rgbButton,SIGNAL(toggled(bool)),this,SLOT(changeView())); + } + } + + +} diff --git a/isis/src/qisis/objs/BandTool/BandTool.h b/isis/src/qisis/objs/BandTool/BandTool.h new file mode 100644 index 0000000000000000000000000000000000000000..6f9fc1d1a51b40b1deb49110484fc7a6495ce81a --- /dev/null +++ b/isis/src/qisis/objs/BandTool/BandTool.h @@ -0,0 +1,76 @@ +#ifndef BandTool_h +#define BandTool_h + +#include "Tool.h" + +// FIXME: remove this include +#include "Pvl.h" + +class QAction; +class QComboBox; +class QHBoxLayout; +class QLabel; +class QRadioButton; +class QSpinBox; +class QStackedWidget; + +namespace Isis { + // FIXME: uncomment this and make p_pvl a Pvl * (make cc and op=, etc) + //class Pvl; +} + +namespace Qisis { + class ToolPad; + /** + * @internal + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport instead of + * CubeViewport + */ + class BandTool : public Qisis::Tool { + Q_OBJECT + + public: + BandTool (QWidget *parent); + + protected: + /** + * returns the name of the menu. + * + * + * @return QString + */ + QString menuName() const { return "&View"; }; + QAction *toolPadAction(ToolPad *pad); + QWidget *createToolBarWidget (QStackedWidget *active); + void updateTool(); + + private slots: + void changeView(); + void setList(); + void setBandBin (Isis::Pvl &pvl); + void setDisplay(); + void copyLinkedViewports(); + void copyAllViewports(); + + private: + QRadioButton *p_rgbButton;//!< RGB radio button + QRadioButton *p_blackwhiteButton;//!< Black and White radio button + QSpinBox *p_graySpin;//!< Gray spin box + QSpinBox *p_redSpin;//!< Red spin box + QSpinBox *p_grnSpin;//!< Green spin box + QSpinBox *p_bluSpin;//!< Blue spin box + QLabel *p_grayDisplay;//!< gray display + QLabel *p_redDisplay;//!< red display + QLabel *p_greenDisplay;//!< green display + QLabel *p_blueDisplay;//!< blue display + QComboBox *p_comboBox;//!< display selection combo box + QStackedWidget *p_stack; //!< Stacked widget for spin boxes + QStackedWidget *p_stack2;//!< Stacked widget for displays and combo box + + int p_bands;//!< Number of possible bands + Isis::Pvl p_pvl;//!< pvl + QStringList p_lineEditValueList;//!< Value list + }; +}; + +#endif diff --git a/isis/src/qisis/objs/BandTool/Makefile b/isis/src/qisis/objs/BandTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/BandTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/BlinkTool/BlinkTool.cpp b/isis/src/qisis/objs/BlinkTool/BlinkTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..24dd089183901169f010ec2aa94e123d274143d2 --- /dev/null +++ b/isis/src/qisis/objs/BlinkTool/BlinkTool.cpp @@ -0,0 +1,382 @@ +#include "BlinkTool.h" + +#include "Filename.h" +#include "MdiCubeViewport.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Qisis { + + /** + * Blink Tool Constructor + * + * + * @param parent + */ + BlinkTool::BlinkTool (QWidget *parent) : Qisis::Tool(parent) { + // Create the blink window + p_dialog = new QDialog(parent); + p_dialog->setWindowTitle("Blink Comparator"); + p_dialog->setSizeGripEnabled(true); + p_blinkWindow = new QWidget(p_dialog); + p_blinkWindow->setMinimumSize(492,492); + p_blinkWindow->setBackgroundRole(QPalette::Shadow); + //p_blinkWindow->installEventFilter(this); + + p_listWidget = new QListWidget(p_dialog); + p_listWidget->setMinimumHeight(100); + connect(p_listWidget,SIGNAL(itemActivated(QListWidgetItem *)), + this,SLOT(toggleLink(QListWidgetItem *))); + connect(p_listWidget,SIGNAL(currentRowChanged(int)), + this,SLOT(updateWindow())); + + QSplitter *splitter = new QSplitter (Qt::Vertical,p_dialog); + splitter->addWidget(p_blinkWindow); + splitter->addWidget(p_listWidget); + splitter->setCollapsible(0,false); + splitter->setCollapsible(1,false); + splitter->setStretchFactor(0,0); + splitter->setStretchFactor(1,1); + + QWidget *buttons = new QWidget (p_dialog); + + QVBoxLayout *layout = new QVBoxLayout(); +// layout->addWidget(p_blinkWindow,2); +// layout->addWidget(p_listWidget,1); + layout->addWidget(splitter,1); + layout->addWidget(buttons,0); + p_dialog->setLayout(layout); + + QToolButton *reverse = new QToolButton(buttons); + reverse->setIcon(QPixmap(toolIconDir()+"/blinkReverse.png")); + reverse->setIconSize(QSize(22,22)); + reverse->setShortcut(Qt::CTRL+Qt::Key_Delete); + reverse->setToolTip("Previous"); + QString text = "Function: Show previous linked viewport and \ + stop automatic timed blinking \ +

    Shortcut: Ctrl+Delete

    "; + reverse->setWhatsThis(text); + connect(reverse,SIGNAL(released()),this,SLOT(reverse())); + + QToolButton *stop = new QToolButton(buttons); + stop->setIcon(QPixmap(toolIconDir()+"/blinkStop.png")); + stop->setIconSize(QSize(22,22)); + stop->setToolTip("Stop"); + text = "Function: Stop automatic timed blinking"; + stop->setWhatsThis(text); + connect(stop,SIGNAL(released()),this,SLOT(stop())); + + QToolButton *start = new QToolButton(buttons); + start->setIcon(QPixmap(toolIconDir()+"/blinkStart.png")); + start->setIconSize(QSize(22,22)); + start->setToolTip("Start"); + text = "Function: Start automatic timed blinking. Cycles \ + through linked viewports at variable rate"; + start->setWhatsThis(text); + connect(start,SIGNAL(released()),this,SLOT(start())); + + QToolButton *forward = new QToolButton(buttons); + forward->setIcon(QPixmap(toolIconDir()+"/blinkAdvance.png")); + forward->setIconSize(QSize(22,22)); + forward->setToolTip("Next"); + forward->setShortcut(Qt::Key_Delete); + text = "Function: Show next linked viewport and stop \ + automatic timed blinking \ +

    Shortcut: Delete

    "; + forward->setWhatsThis(text); + connect(forward,SIGNAL(released()),this,SLOT(advance())); + + p_timeBox = new QDoubleSpinBox(buttons); + p_timeBox->setMinimum(0.1); + p_timeBox->setMaximum(5.0); + p_timeBox->setDecimals(1); + p_timeBox->setSingleStep(0.1); + p_timeBox->setValue(0.5); + p_timeBox->setToolTip("iTime Delay"); + text = "Function: Change automatic blink rate between " + + QString::number(p_timeBox->minimum()) + " and " + + QString::number(p_timeBox->maximum()) + " seconds"; + p_timeBox->setWhatsThis(text); + + QPushButton *close = new QPushButton("Close",buttons); + close->setDefault(false); + close->setAutoDefault(false); + connect(close,SIGNAL(released()),p_dialog,SLOT(hide())); + connect(close,SIGNAL(released()),this,SLOT(stop())); + + QHBoxLayout *hlayout = new QHBoxLayout(); + hlayout->addWidget(reverse); + hlayout->addWidget(stop); + hlayout->addWidget(start); + hlayout->addWidget(forward); + hlayout->addWidget(p_timeBox); + hlayout->addStretch(1); + hlayout->addWidget(close); + buttons->setLayout(hlayout); + + // Create the action to bring up the blink window + p_action = new QAction(parent); + p_action->setShortcut(Qt::Key_K); + p_action->setText("&Blink ..."); + p_action->setIcon(QPixmap(toolIconDir()+"/blink.png")); + p_action->setToolTip("Blink"); + text = + "Function: Opens a blink comparator for linked viewports. \ +

    Shortcut:K

    "; + p_action->setWhatsThis(text); + p_action->setEnabled(false); + connect(p_action,SIGNAL(triggered()),p_dialog,SLOT(show())); + + p_timerOn = false; + readSettings(); + p_blinkWindow->installEventFilter(this); + } + + + /** + * Adds this action to the given menu. + * + * + * @param menu + */ + void BlinkTool::addTo (QMenu *menu) { + menu->addAction(p_action); + } + + + /** + * Adds this action to the permanent tool bar. + * + * + * @param perm + */ + void BlinkTool::addToPermanent (QToolBar *perm) { + perm->addAction(p_action); + } + + + /** + * Updates the blink tool. + * + */ + void BlinkTool::updateTool() { + std::string unlinkedIcon = Isis::Filename("$base/icons/unlinked.png").Expanded(); + static QIcon unlinked(unlinkedIcon.c_str()); + std::string linkedIcon = Isis::Filename("$base/icons/linked.png").Expanded(); + static QIcon linked(linkedIcon.c_str()); + p_listWidget->clear(); + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + MdiCubeViewport *d = (*(cubeViewportList()))[i]; + disconnect(d,SIGNAL(linkChanging(bool)),this,0); + disconnect(d,SIGNAL(windowTitleChanged()),this,0); + QListWidgetItem *item = new QListWidgetItem(p_listWidget); + item->setText(d->parentWidget()->windowTitle()); + if (d->isLinked()) { + item->setIcon(linked); + } + else { + item->setIcon(unlinked); + } + connect(d,SIGNAL(linkChanging(bool)),this,SLOT(updateTool())); + connect(d,SIGNAL(windowTitleChanged()),this,SLOT(updateTool())); + } + + if (cubeViewport() == NULL) { + p_action->setEnabled(false); + } + else if (cubeViewportList()->size() <= 1) { + p_action->setEnabled(false); + } + else { + p_action->setEnabled(true); + } + } + + + /** + * Links/unlinks viewports + * + * + * @param item + */ + void BlinkTool::toggleLink(QListWidgetItem *item) { + for (int i=0; icount(); i++) { + if (p_listWidget->item(i) == item) { + MdiCubeViewport *d = (*(cubeViewportList()))[i]; + d->setLinked(!d->isLinked()); + return; + } + } + } + + + /** + * Reverses the order of the blinking. + * + */ + void BlinkTool::reverse() { + p_timerOn = false; + + int row = p_listWidget->currentRow() - 1; + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + if (row < 0) row = (int)cubeViewportList()->size()-1; + MdiCubeViewport *d = (*(cubeViewportList()))[row]; + if (d->isLinked()) { + p_listWidget->setCurrentRow(row); + p_listWidget->scrollToItem(p_listWidget->currentItem()); + break; + } + row--; + } + } + + + /** + * Stops the blinking. + * + */ + void BlinkTool::stop() { + p_timerOn = false; + } + + + /** + * Starts the blinking. + * + */ + void BlinkTool::start() { + if (p_timerOn) return; + p_timerOn = true; + int msec = (int) (p_timeBox->value() * 1000.0); + QTimer::singleShot(msec,this,SLOT(timeout())); + } + + /** + * Manual blinking. + * + */ + void BlinkTool::advance() { + p_timerOn = false; + + int row = p_listWidget->currentRow() + 1; + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + if (row >= (int) cubeViewportList()->size()) row = 0; + MdiCubeViewport *d = (*(cubeViewportList()))[row]; + if (d->isLinked()) { + p_listWidget->setCurrentRow(row); + p_listWidget->scrollToItem(p_listWidget->currentItem()); + break; + } + row++; + } + } + + + /** + * The blink tool's timer. + * + */ + void BlinkTool::timeout() { + if (p_timerOn) { + advance(); + start(); + } + } + + + /** + * Repaints the blink tool window. + * + */ + void BlinkTool::updateWindow() { + p_blinkWindow->repaint(); + } + + + /** + * Writes the current settings of this window so the next time + * this tool is used, certain user prefs. are remembered. + * + */ + void BlinkTool::writeSettings() { + std::string instanceName = p_dialog->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/qview/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()),QSettings::NativeFormat); + settings.setValue("rate", p_timeBox->value()); + settings.setValue("size", p_dialog->size()); + } + + + /** + * Reads the settings saved from the last time this tool was + * used. + * + */ + void BlinkTool::readSettings(){ + + std::string instanceName = p_dialog->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/qview/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()),QSettings::NativeFormat); + double rate = settings.value("rate", 0.5).toDouble(); + QSize size = settings.value("size", QSize(492, 492)).toSize(); + p_dialog->resize(size); + p_timeBox->setValue(rate); + } + + + /** + * Catches the events happening so we can make this tool do what + * we want. + * + * + * @param o + * @param e + * + * @return bool + */ + bool BlinkTool::eventFilter (QObject *o, QEvent *e) { + if (o != p_blinkWindow) return false; + if (e->type() == QEvent::Hide) writeSettings(); + if (e->type() != QEvent::Paint) return false; + + static QPixmap lastPixmap; + int row = p_listWidget->currentRow(); + if (row != -1) { + MdiCubeViewport *d = (*(cubeViewportList()))[row]; + lastPixmap = d->pixmap(); + } + + int dx = lastPixmap.width() - p_blinkWindow->width(); + int x = 0; + int sx = dx / 2; + if (dx < 0) { + x = -dx / 2; + sx = 0; + } + int dy = lastPixmap.height() - p_blinkWindow->height(); + int y = 0; + int sy = dy / 2; + if (dy < 0) { + y = -dy / 2; + sy = 0; + } + + QPainter p(p_blinkWindow); + p.drawPixmap(x,y,lastPixmap,sx,sy, -1, -1); + + return true; + } +} diff --git a/isis/src/qisis/objs/BlinkTool/BlinkTool.h b/isis/src/qisis/objs/BlinkTool/BlinkTool.h new file mode 100644 index 0000000000000000000000000000000000000000..3674ce491ef04f9f621af13dce0d6b395f8b96f9 --- /dev/null +++ b/isis/src/qisis/objs/BlinkTool/BlinkTool.h @@ -0,0 +1,67 @@ +#ifndef BlinkTool_h +#define BlinkTool_h + +// This is the only include allowed in this file! +#include "Tool.h" + +class QDoubleSpinBox; +class QDialog; +class QToolButton; +class QSplitter; +class QMenu; +class QVBoxLayout; +class QHBoxLayout; +class QPushButton; +class QAction; +class QListWidget; +class QListWidgetItem; + +namespace Qisis { + /** + * @internal + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport instead of + * CubeViewport. Fixed misuse of includes. + */ + class BlinkTool : public Qisis::Tool { + Q_OBJECT + + public: + BlinkTool (QWidget *parent); + void addTo (QMenu *menu); + void addToPermanent (QToolBar *perm); + void writeSettings(); + void readSettings(); + + + protected: + /** + * Returns the menu name. + * + * + * @return QString + */ + QString menuName() const { return "&Options"; }; + void updateTool(); + bool eventFilter (QObject *o, QEvent *e); + + private slots: + void toggleLink(QListWidgetItem *item); + void reverse(); + void stop(); + void start(); + void advance(); + void timeout(); + void updateWindow(); + + private: + QAction *p_action; //!< The action associated with this tool + QWidget *p_blinkWindow;//!< The blink tool widget + QListWidget *p_listWidget;//!< The list widget with the blink tool + QDoubleSpinBox *p_timeBox;//!< Time selection box + bool p_timerOn;//!< Is the timer on? + QDialog *p_dialog;//!< Dialog widget + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/BlinkTool/Makefile b/isis/src/qisis/objs/BlinkTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/BlinkTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/BrowseDialog/BrowseDialog.cpp b/isis/src/qisis/objs/BrowseDialog/BrowseDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4e13c6772596a86933f5f82ad846d5b68716b99d --- /dev/null +++ b/isis/src/qisis/objs/BrowseDialog/BrowseDialog.cpp @@ -0,0 +1,72 @@ +#include "BrowseDialog.h" + +#include +#include + +namespace Qisis { + + /** + * BrowseDialog constructor + * + * + * @param title + * @param filterList + * @param directory + * @param parent + */ + BrowseDialog::BrowseDialog(QString title, QStringList &filterList, QDir &directory, QWidget *parent) : + FileDialog(title, filterList, directory, parent), p_dir(directory) { + + /*This returns a list of all the buttons in QFileDialog. This way I can + disconnect the buttons from the old signals and substitue my own. The + text on the buttons can also be changed*/ + QList allPButtons = this->findChildren(); + /*Do stuff to the first (Open) button.*/ + allPButtons[0]->setText("View"); + disconnect(allPButtons[0],0,0,0); + connect(allPButtons[0],SIGNAL(pressed()),this,SLOT(displayCube())); + /*Do stuff to the second (Cancel) button.*/ + allPButtons[1]->setText("Close"); + + this->setFileMode(QFileDialog::ExistingFile); + + } + + + /** + * This method is called after the user has selected a file + * either by double clicking on the file name or by pressing the + * 'view' button. A signal is emitted which eventually calls + * the addBrowseView function from the Workspace object. + * + */ + void BrowseDialog::displayCube(){ + p_dir=this->directory(); + QStringList selectedFiles = this->selectedFiles(); + + /*If the user did not select a file warn them.*/ + if(selectedFiles.size() < 1){ + QString message = tr("\nFile not found.\nPlease verify the " + "correct file name was given"); + QMessageBox::warning(this, "File Not Found", message); + + }else{ + + emit fileSelected(selectedFiles[0]); + } + + } + + /** + * This is an overridden method from QDialog. QDialog closes + * the dialog. We want to leave the box open and display the + * cube in the view port. + * + * @param r + */ + void BrowseDialog::done(int r) { + displayCube(); + } + +} + diff --git a/isis/src/qisis/objs/BrowseDialog/BrowseDialog.h b/isis/src/qisis/objs/BrowseDialog/BrowseDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..93acd94286bbea5ce281e2f15fb4b94941cefe00 --- /dev/null +++ b/isis/src/qisis/objs/BrowseDialog/BrowseDialog.h @@ -0,0 +1,43 @@ +#ifndef BrowseDialog_h +#define BrowseDialog_h + +#include "FileDialog.h" + +namespace Qisis { + /** + * @brief Class for browsing cubes. + * + * @ingroup Visualization Tools + * + * @author Stacy Alley + * + * @internal + * + * @history 2008-01-18 Stacy Alley - Changed the constructor to + * accept a QStringList which serves as the default filters + * for the file dialog boxes. + * + * @history 2008-01-28 Stacy Alley - Changed the constructor + * again to accept a QDir which is the default directory + * the file dialog box should point to. When the user + * changes directories, the dir variable which is passed + * by reference set to that new directory. + */ + + + class BrowseDialog : public FileDialog { + Q_OBJECT + public: + BrowseDialog (QString title, QStringList &filterList, QDir &dir, QWidget *parent=0); + + public slots: + void displayCube(); + void done(int r); + + private: + QDir &p_dir;//! +#include + +namespace Qisis { + + //! Construct an empty viewport + ChipViewport::ChipViewport (int width, int height, QWidget *parent) : + QWidget(parent) { + + setFixedSize(width,height); + setBackgroundRole(QPalette::Dark); +// setFocusPolicy(Qt::StrongFocus); + + p_width = width; + p_height = height; + p_zoomFactor = 1.0; + p_rotation = 0; + p_geomIt = false; + p_tempView = NULL; + p_cross = true; + p_circle = false; + p_chip = NULL; + p_chipCube = NULL; + p_matchChip = NULL; + p_matchChipCube = NULL; + p_image = NULL; + } + + + /** + * Destructor + * + */ + ChipViewport::~ChipViewport() { + + } + + + /** + * Set the chip for this ChipViewport + * + * @author Tracie Sucharski + * @internal + * @history 2009-14-2009 Tracie Sucharski - Make sure the p_image is clear + * before allocating new. + */ + + void ChipViewport::setChip (Isis::Chip *chip, Isis::Cube *chipCube) { + // Is the chip usable? + if (chip == NULL || chipCube == NULL) { + throw Isis::iException::Message(Isis::iException::Programmer, + "Can not view NULL chip pointer", + _FILEINFO_); + } + + p_zoomFactor = 1.0; + p_rotation = 0; + + p_chip = chip; + p_chipCube = chipCube; + if (p_image != NULL) delete p_image; + p_image = new QImage(chip->Samples(),chip->Lines(),QImage::Format_RGB32); + + autoStretch(); + + emit tackPointChanged(p_zoomFactor); + } + + + //! Apply automatic stretch using data from entire chip + void ChipViewport::autoStretch () { + computeStretch(p_gray.stretch); + paintImage(); + update(); + } + + + //! Compute automatic stretch for a portion of the cube + void ChipViewport::computeStretch(Isis::Stretch &stretch) { + Isis::Statistics stats; + for (int line=1; lineLines(); line++) { + for (int samp=1; sampSamples(); samp++) { + double value = p_chip->GetValue(samp,line); + stats.AddData(&value,1); + } + } + + Isis::Histogram hist(stats.BestMinimum(),stats.BestMaximum()); + for (int line=1; line<=p_chip->Lines(); line++) { + for (int samp=1; samp<=p_chip->Samples(); samp++) { + double value = p_chip->GetValue(samp,line); + hist.AddData(&value,1); + } + } + + stretch.ClearPairs(); + if (hist.Percent(0.5) != hist.Percent(99.5)) { + stretch.AddPair(hist.Percent(0.5),0.0); + stretch.AddPair(hist.Percent(99.5),255.0); + } + else { + stretch.AddPair(-DBL_MAX,0.0); + stretch.AddPair(DBL_MAX,255.0); + } + } + + + //! Paint QImage + void ChipViewport::paintImage () { + // TODO: ??? Need something similar to CubeViewport clipping, so that + // at edge of image, fill viewport w/ black + for (int y=0; yLines(); y++) { + QRgb *rgb = (QRgb *) p_image->scanLine(y); + int r,g,b; + for (int x=0; xSamples(); x++) { + r = g = b = (int) p_gray.stretch.Map(p_chip->GetValue(x+1,y+1)); + rgb[x] = qRgb(r,g,b); + } + } + repaint(); + + } + + + //! Repaint the viewport + void ChipViewport::paintEvent (QPaintEvent *e) { + QPainter painter(this); + + if (p_tempView != NULL) { + painter.drawImage(0,0,*(p_tempView->p_image)); + } + else { + painter.drawImage(0,0,*p_image); + } + + if (p_cross == true) { + painter.setPen(Qt::red); + painter.drawLine(0,(p_height-1)/2,p_width-1,(p_height-1)/2); + painter.drawLine((p_width-1)/2,0,(p_width-1)/2,p_height-1); + } + + if (p_circle == true) { + painter.setPen(Qt::red); + painter.drawEllipse((p_height-1)/2-p_circleSize/2,(p_width-1)/2-p_circleSize/2, + p_circleSize,p_circleSize); + } + p_tempView = NULL; + //painter.end(); + + } + + + //! Load with info from given ChipViewport + void ChipViewport::loadView(ChipViewport &newView) { + p_tempView = &newView; + update (); + } + + + /** + * Returns tack sample + * + * + * @return double + */ + double ChipViewport::tackSample () { + p_chip->SetChipPosition(p_chip->TackSample(),p_chip->TackLine()); + return p_chip->CubeSample(); + } + + + /** + * returns tack Line + * + * + * @return double + */ + double ChipViewport::tackLine () { + p_chip->SetChipPosition(p_chip->TackSample(),p_chip->TackLine()); + return p_chip->CubeLine(); + } + + + //!< Pan up + void ChipViewport::panUp() { + int x,y; + x = p_chip->TackSample(); + y = p_chip->TackLine() - 1; + // Reload with new cube position + p_chip->SetChipPosition((double)x,(double)y); + reloadChip(p_chip->CubeSample(),p_chip->CubeLine()); + } + + + //!< Pan down + void ChipViewport::panDown() { + int x,y; + x = p_chip->TackSample(); + y = p_chip->TackLine() + 1; + // Reload with new cube position + p_chip->SetChipPosition((double)x,(double)y); + reloadChip(p_chip->CubeSample(),p_chip->CubeLine()); + } + + + //!< Pan left + void ChipViewport::panLeft() { + int x,y; + x = p_chip->TackSample() - 1; + y = p_chip->TackLine(); + // Reload with new cube position + p_chip->SetChipPosition((double)x,(double)y); + reloadChip(p_chip->CubeSample(),p_chip->CubeLine()); + } + + + //!< Pan right + void ChipViewport::panRight() { + int x,y; + x = p_chip->TackSample() + 1; + y = p_chip->TackLine(); + // Reload with new cube position + p_chip->SetChipPosition((double)x,(double)y); + reloadChip(p_chip->CubeSample(),p_chip->CubeLine()); + } + + + /** + * Zoom in + * + */ + void ChipViewport::zoomIn() { + + p_zoomFactor /= 2.0; + reloadChip(); + } + + + /** + * Zoom out + * + */ + void ChipViewport::zoomOut() { + + p_zoomFactor *= 2.0; + reloadChip(); + } + + + /** + * Zoom by a factor of one. + * + */ + void ChipViewport::zoom1() { + + p_zoomFactor = 1.0; + reloadChip(); + } + + + //!< Slot to refresh viewport , point has changed + void ChipViewport::refreshView(double tackSample,double tackLine) { + + reloadChip(tackSample,tackLine); + + } + + + //!< If mouse enters, make sure key events are processed w/o clicking + void ChipViewport::enterEvent(QEvent *e) { + setFocus(); + } + + + //!< Process arrow keystrokes on cube + void ChipViewport::keyPressEvent(QKeyEvent *e) { + + int x,y; + x = p_chip->TackSample(); + y = p_chip->TackLine(); + if (e->key() == Qt::Key_Up) { + y--; + } + else if (e->key() == Qt::Key_Down) { + y++; + } + else if (e->key() == Qt::Key_Left) { + x--; + } + else if (e->key() == Qt::Key_Right) { + x++; + } + else { + QWidget::keyPressEvent(e); + return; + } + + // Reload with new cube position + p_chip->SetChipPosition((double)x,(double)y); + reloadChip(p_chip->CubeSample(),p_chip->CubeLine()); + + } + + + + //!< Process mouse events + void ChipViewport::mousePressEvent(QMouseEvent *event) { + + QPoint p = event->pos(); + if (event->button() == Qt::LeftButton) { + // Reload with new cube position + p_chip->SetChipPosition((double)p.x(),(double)p.y()); + reloadChip(p_chip->CubeSample(),p_chip->CubeLine()); + } + } + + + //!< Slot to change state of crosshair + void ChipViewport::setCross(bool checked) { + + if (checked == p_cross) return; + + p_cross = checked; + repaint(); + + } + + + void ChipViewport::setCircle(bool checked) { + + if (checked == p_circle) return; + + p_circle = checked; + repaint(); + } + + + void ChipViewport::setCircleSize(int size) { + + p_circleSize = size; + repaint(); + + } + + + + /** + * Slot to geom chip + * @internal + * @history 2010-06-16 Jeannie Walldren - Catch possible iException from Chip's + * Load() method and display in QMessageBox + */ + void ChipViewport::geomChip (Isis::Chip *matchChip, Isis::Cube *matchChipCube) { + + p_geomIt = true; + p_matchChip = matchChip; + p_matchChipCube = matchChipCube; + try{ + p_chip->Load(*p_chipCube,*matchChip,*matchChipCube); +// p_chip->ReLoad(*matchChip,p_zoomFactor); + } + catch (Isis::iException &e){ + QString msg = "Cannot geom chip.\n"; + msg += e.Errors().c_str(); + QMessageBox::information((QWidget *)parent(),"Error",msg); + e.Clear(); + return; + } + + // TODO: ??? Can these be added to paintEvent method ??? + autoStretch(); + } + + /** + * Slot to geom chip + * @internal + * @history 2010-06-16 Jeannie Walldren - Catch possible iException from Chip's + * Load() method and display in QMessageBox + */ + void ChipViewport::nogeomChip () { + + p_geomIt = false; + try{ + p_chip->Load(*p_chipCube,p_rotation,p_zoomFactor); + } + catch (Isis::iException &e){ + QString msg = "Cannot load no geom chip.\n"; + msg += e.Errors().c_str(); + QMessageBox::information((QWidget *)parent(),"Error",msg); + e.Clear(); + return; + } + + // TODO: ??? Can these be added to paintEvent method ??? + autoStretch(); + } + + + /** + * Slot to rotate chip + * + * + * + * @param rotation + * @internal + * @history 2010-06-16 Jeannie Walldren - Catch possible iException from Chip's + * Load() method and display in QMessageBox + */ + + void ChipViewport::rotateChip(int rotation) { + + p_rotation = -rotation; + try{ + p_chip->Load(*p_chipCube,-rotation,p_zoomFactor); + } + catch (Isis::iException &e){ + QString msg = "Cannot load rotated chip.\n"; + msg += e.Errors().c_str(); + QMessageBox::information((QWidget *)parent(),"Error",msg); + e.Clear(); + return; + } + + // TODO: ??? Can these be added to paintEvent method ??? + autoStretch(); + } + + + /** + * Reloads the chip. + * + * + * @param tackSample + * @param tackLine + * @history 2010-06-16 Jeannie Walldren - Catch possible iException from Chip's + * Load() method and display in QMessageBox + */ + void ChipViewport::reloadChip(double tackSample,double tackLine) { + + // Is the chip usable? + if (p_chip == NULL) { + throw Isis::iException::Message(Isis::iException::Programmer, + "Can not view NULL chip pointer", + _FILEINFO_); + } + + if (tackSample != 0. && tackLine != 0.) + p_chip->TackCube(tackSample,tackLine); + if (p_geomIt) { + if (p_matchChip == NULL) { + throw Isis::iException::Message(Isis::iException::User, + "Invalid match chip",_FILEINFO_); + } + try{ + p_chip->Load(*p_chipCube,*p_matchChip,*p_matchChipCube); + } + catch (Isis::iException &e){ + QString msg = "Cannot reload chip.\n"; + msg += e.Errors().c_str(); + QMessageBox::information((QWidget *)parent(),"Error",msg); + e.Clear(); + return; + } +// p_chip->ReLoad(*p_matchChip,p_zoomFactor); + } + else { + try{ + p_chip->Load(*p_chipCube,p_rotation,p_zoomFactor); + } + catch (Isis::iException &e){ + QString msg = "Cannot reload chip.\n"; + msg += e.Errors().c_str(); + QMessageBox::information((QWidget *)parent(),"Error",msg); + e.Clear(); + return; + } + } + + + // TODO: ??? Can these be added to paintEvent method ??? + autoStretch(); + + // emit signal indicating tack point changed so that the TieTool + // can update the sample/line label. + emit tackPointChanged(p_zoomFactor); + } + +} diff --git a/isis/src/qisis/objs/ChipViewport/ChipViewport.h b/isis/src/qisis/objs/ChipViewport/ChipViewport.h new file mode 100644 index 0000000000000000000000000000000000000000..92f675bc7ee598781771a5c2768130c959333e5f --- /dev/null +++ b/isis/src/qisis/objs/ChipViewport/ChipViewport.h @@ -0,0 +1,171 @@ +#ifndef ChipViewport_h +#define ChipViewport_h + +/** + * @file + * $Revision: 1.6 $ + * $Date: 2010/06/17 00:08:45 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "Chip.h" +#include "Stretch.h" +#include "iException.h" +#include "Histogram.h" + +class QImage; + +namespace Qisis { +/** + * @brief Viewport for Isis Chips + * + * @ingroup Visualization Tools + * + * @author 2007-05-01 Tracie Sucharski + * + * @internal + * @history 2008-09-09 Tracie Sucharski - Added setCircle and setCircleSize + * methods. + * @history 2010-06-16 Jeannie Walldren - Modified geomChip(), nogeomChip(), + * rotateChip() and reloadChip() to catch possible + * iExceptions from Chip's Load() method and display + * Error in QMessageBox + * + */ + + class ChipViewport : public QWidget { + Q_OBJECT + + + public: + ChipViewport (int width, int height, QWidget *parent=0); + ~ChipViewport (); + + //! Set chip + void setChip (Isis::Chip *chip, Isis::Cube *chipCube); + + //! Load with another ChipViewport + void loadView(ChipViewport &newView); + + //! Return chip + Isis::Chip *chip() const { return p_chip; }; + + //! Return the number of samples in the chip + int chipSamples() const { return p_chip->Samples(); }; + + //! Return the number of lines in the chip + int chipLines() const { return p_chip->Lines(); }; + + //! Return the gray band currently viewed + int grayBand() const { return p_gray.band; }; + + //! Return the position of cube under cross hair + double tackSample (); + double tackLine (); + + //! Draw X on point + //void markPoint (double sample, double line); + + + //! Return the gray band stretch + Isis::Stretch grayStretch () const { return p_gray.stretch; }; + + signals: + //!< Signal sent when tack point changes + void tackPointChanged(double); + + public slots: + + void autoStretch (); + void setCross (bool checked); + void rotateChip (int rotation); + void setCircle (bool checked); + void setCircleSize (int size); + + void geomChip (Isis::Chip *matchChip, Isis::Cube *matchChipCube); + void nogeomChip (); + + void panUp(); + void panDown(); + void panLeft(); + void panRight(); + + void zoomIn(); + void zoomOut(); + void zoom1(); + + void refreshView(double tackSample,double tackLine); + + protected: + void paintEvent (QPaintEvent *e); + void enterEvent(QEvent *e); + void keyPressEvent(QKeyEvent *e); + void mousePressEvent(QMouseEvent *event); + + protected slots: + + private: + void reloadChip (double tackSample=0.,double tackLine=0.); + + void computeStretch(Isis::Stretch &stretch); + void paintImage(); + + class BandInfo { + public: + int band; + Isis::Stretch stretch; + BandInfo() { + band = 1; + stretch.SetNull(0.0); + stretch.SetLis(0.0); + stretch.SetLrs(0.0); + stretch.SetHis(255.0); + stretch.SetHrs(255.0); + }; + }; + + BandInfo p_gray;//!< info for the gray bands. + Isis::Chip *p_chip;//!< The chip + Isis::Cube *p_chipCube;//!< The chip's cube + + int p_width;//!< Chip width + int p_height;//!< Chip height + + bool p_geomIt;//!< geomIt? + Isis::Chip *p_matchChip;//!< The matching chip. + Isis::Cube *p_matchChipCube;//!< The matching chip's cube + + double p_zoomFactor;//!< Zoom Factor + int p_rotation;//!< Rotation + + QImage *p_image;//!< The image + bool p_paintImage;//!< Paint Image? + bool p_cross;//!< Draw crosshair + bool p_circle;//!< Draw circle + int p_circleSize;//! +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Application.h" +#include "AutoReg.h" +#include "AutoRegFactory.h" +#include "ChipViewport.h" +#include "ControlMeasure.h" +#include "Filename.h" +#include "iString.h" +#include "Pvl.h" +#include "System.h" +#include "UniversalGroundMap.h" + +namespace Qisis { + + const int VIEWSIZE = 301; + + /** + * Constructs a ControlPointEdit widget + * + * @param parent Input Parent of widget + * @param allowLeftMouse Input Allow/Disallow mouse events on Left + * ChipViewport + * @author Tracie Sucharski + * @internal + * @history 2008-15-2008 Jeannie Walldren - Added error + * string to Isis::iException::Message before + * creating QMessageBox + */ + ControlPointEdit::ControlPointEdit (QWidget *parent,bool allowLeftMouse) : QWidget(parent) { + + p_rotation = 0; + p_timerOn = false; + p_autoRegFact = NULL; + p_allowLeftMouse = allowLeftMouse; + + // Initialize some pointers + p_leftCube = 0; + p_rightCube = 0; + p_leftGroundMap = 0; + p_rightGroundMap = 0; + + try { + p_templateFilename = "$base/templates/autoreg/qnetReg.def"; + Isis::Pvl pvl(p_templateFilename); + p_autoRegFact = Isis::AutoRegFactory::Create(pvl); + } + catch ( Isis::iException &e ) { + p_autoRegFact = NULL; + e.Message(Isis::iException::Io, + "Cannot create AutoRegFactory. As a result, sub-pixel registration will not work.", + _FILEINFO_); + QString message = e.Errors().c_str(); + e.Clear (); + QMessageBox::information((QWidget *)parent,"Error",message); + } + + createPointEditor(parent); + } + + + + /** + * Design the PointEdit widget + * + * @author Tracie Sucharski + * @internal + * @history 2008-11-19 Tracie Sucharski - Added left pan buttons, but + * default to hidden. + * @history 2008-12-02 Jeannie Walldren - Allow connection + * between updateLeftView and refreshView for all + * objects. Previously this was only done if + * allowLeftMouse = true. + * @history 2008-12-02 Tracie Sucharski - Another bug fix due to change + * on 2008-11-19, The leftView tackPointChanged + * connection needs to always be made whether mouse + * button events are allowed or not. + * @history 2008-12-10 Jeannie Walldren - Set the default + * value of the new private variable, + * p_templateFilename, to the previously hard-coded + * template filename. + */ + void ControlPointEdit::createPointEditor(QWidget *parent) { + // Place everything in a grid + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->setSizeConstraint(QLayout::SetFixedSize); + // grid row + int row = 0; + + std::string tempFilename = Isis::Filename("$base/icons").Expanded(); + QString toolIconDir = tempFilename.c_str(); + + QSize isize(27,27); + // Add zoom buttons + QToolButton *leftZoomIn = new QToolButton(); + leftZoomIn->setIcon(QPixmap(toolIconDir+"/viewmag+.png")); + leftZoomIn->setIconSize(isize); + leftZoomIn->setToolTip("Zoom In"); + + QToolButton *leftZoomOut = new QToolButton(); + leftZoomOut->setIcon(QPixmap(toolIconDir+"/viewmag-.png")); + leftZoomOut->setIconSize(isize); + leftZoomOut->setToolTip("Zoom Out"); + + QToolButton *leftZoom1 = new QToolButton(); + leftZoom1->setIcon(QPixmap(toolIconDir+"/viewmag1.png")); + leftZoom1->setIconSize(isize); + leftZoom1->setToolTip("Zoom 1:1"); + + QHBoxLayout *leftZoomPan = new QHBoxLayout; + leftZoomPan->addWidget(leftZoomIn); + leftZoomPan->addWidget(leftZoomOut); + leftZoomPan->addWidget(leftZoom1); + + // These buttons only used if allow mouse events in leftViewport + QToolButton *leftPanUp = 0; + QToolButton *leftPanDown = 0; + QToolButton *leftPanLeft = 0; + QToolButton *leftPanRight = 0; + if (p_allowLeftMouse) { + // Add arrows for panning + leftPanUp = new QToolButton(parent); + leftPanUp->setIcon(QIcon(Isis::Filename("$base/icons/up.png"). + Expanded().c_str())); + leftPanUp->setIconSize(isize); + leftPanUp->setToolTip("Move up 1 screen pixel"); + + leftPanDown = new QToolButton(parent); + leftPanDown->setIcon(QIcon(Isis::Filename("$base/icons/down.png"). + Expanded().c_str())); + leftPanDown->setIconSize(isize); + leftPanDown->setToolTip("Move down 1 screen pixel"); + + leftPanLeft = new QToolButton(parent); + leftPanLeft->setIcon(QIcon(Isis::Filename("$base/icons/back.png"). + Expanded().c_str())); + leftPanLeft->setIconSize(isize); + leftPanLeft->setToolTip("Move left 1 screen pixel"); + + leftPanRight = new QToolButton(parent); + leftPanRight->setIcon(QIcon(Isis::Filename("$base/icons/forward.png"). + Expanded().c_str())); + leftPanRight->setIconSize(isize); + leftPanRight->setToolTip("Move right 1 screen pixel"); + + leftZoomPan->addWidget(leftPanUp); + leftZoomPan->addWidget(leftPanDown); + leftZoomPan->addWidget(leftPanLeft); + leftZoomPan->addWidget(leftPanRight); + } + + leftZoomPan->addStretch(); + gridLayout->addLayout(leftZoomPan,row,0); + + p_rightZoomIn = new QToolButton(); + p_rightZoomIn->setIcon(QPixmap(toolIconDir+"/viewmag+.png")); + p_rightZoomIn->setIconSize(isize); + p_rightZoomIn->setToolTip("Zoom In"); + QString text = "Zoom in 2X"; + p_rightZoomIn->setWhatsThis(text); + + p_rightZoomOut = new QToolButton(); + p_rightZoomOut->setIcon(QIcon(Isis::Filename("$base/icons/viewmag-.png"). + Expanded().c_str())); + p_rightZoomOut->setIconSize(isize); + p_rightZoomOut->setToolTip("Zoom Out"); + text = "Zoom out 2X"; + p_rightZoomOut->setWhatsThis(text); + + p_rightZoom1 = new QToolButton(); + p_rightZoom1->setIcon(QPixmap(toolIconDir+"/viewmag1.png")); + p_rightZoom1->setIconSize(isize); + p_rightZoom1->setToolTip("Zoom 1:1"); + text = "Zoom 1:1"; + p_rightZoom1->setWhatsThis(text); + + QHBoxLayout *rightZoomPan = new QHBoxLayout; + rightZoomPan->addWidget(p_rightZoomIn); + rightZoomPan->addWidget(p_rightZoomOut); + rightZoomPan->addWidget(p_rightZoom1); + + // Add arrows for panning + QToolButton *rightPanUp = new QToolButton(parent); + rightPanUp->setIcon(QIcon(Isis::Filename("$base/icons/up.png"). + Expanded().c_str())); + rightPanUp->setIconSize(isize); + rightPanUp->setToolTip("Move up 1 screen pixel"); + + QToolButton *rightPanDown = new QToolButton(parent); + rightPanDown->setIcon(QIcon(Isis::Filename("$base/icons/down.png"). + Expanded().c_str())); + rightPanDown->setIconSize(isize); + rightPanDown->setToolTip("Move down 1 screen pixel"); + + QToolButton *rightPanLeft = new QToolButton(parent); + rightPanLeft->setIcon(QIcon(Isis::Filename("$base/icons/back.png"). + Expanded().c_str())); + rightPanLeft->setIconSize(isize); + rightPanLeft->setToolTip("Move left 1 screen pixel"); + + QToolButton *rightPanRight = new QToolButton(parent); + rightPanRight->setIcon(QIcon(Isis::Filename("$base/icons/forward.png"). + Expanded().c_str())); + rightPanRight->setIconSize(isize); + rightPanRight->setToolTip("Move right 1 screen pixel"); + + rightZoomPan->addWidget(rightPanUp); + rightZoomPan->addWidget(rightPanDown); + rightZoomPan->addWidget(rightPanLeft); + rightZoomPan->addWidget(rightPanRight); + rightZoomPan->addStretch(); + + gridLayout->addLayout(rightZoomPan,row++,1); + + // Add zoom factor label + p_leftZoomFactor = new QLabel(); + gridLayout->addWidget(p_leftZoomFactor,row,0); + p_rightZoomFactor = new QLabel(); + gridLayout->addWidget(p_rightZoomFactor,row++,1); + + + p_leftView = new ChipViewport(VIEWSIZE,VIEWSIZE,this); + // Do not want to accept mouse/keyboard events + if (!p_allowLeftMouse) p_leftView->setDisabled(true); + + gridLayout->addWidget(p_leftView,row,0); + + // Connect left zoom buttons to ChipViewport's zoom slots + connect(leftZoomIn,SIGNAL(clicked()),p_leftView,SLOT(zoomIn())); + connect(leftZoomOut,SIGNAL(clicked()),p_leftView,SLOT(zoomOut())); + connect(leftZoom1,SIGNAL(clicked()),p_leftView,SLOT(zoom1())); + + // If zoom on left, need to re-geom right + connect(leftZoomIn,SIGNAL(clicked()),this,SLOT(updateRightGeom())); + connect(leftZoomOut,SIGNAL(clicked()),this,SLOT(updateRightGeom())); + connect(leftZoom1,SIGNAL(clicked()),this,SLOT(updateRightGeom())); + + // Connect the ChipViewport tackPointChanged signal to + // the update sample/line label + connect(p_leftView,SIGNAL(tackPointChanged(double)), + this,SLOT(updateLeftPositionLabel(double))); + // we want to allow this connection so that if a changed point is saved + // and the same image is showing in both viewports, the left will refresh. + connect(this,SIGNAL(updateLeftView(double,double)), + p_leftView,SLOT(refreshView(double,double))); + + if (p_allowLeftMouse) { + // Connect pan buttons to ChipViewport + connect(leftPanUp,SIGNAL(clicked()),p_leftView,SLOT(panUp())); + connect(leftPanDown,SIGNAL(clicked()),p_leftView,SLOT(panDown())); + connect(leftPanLeft,SIGNAL(clicked()),p_leftView,SLOT(panLeft())); + connect(leftPanRight,SIGNAL(clicked()),p_leftView,SLOT(panRight())); + } + + p_rightView = new ChipViewport(VIEWSIZE,VIEWSIZE,this); + gridLayout->addWidget(p_rightView,row,1); + // Connect the ChipViewport tackPointChanged signal to + // the update sample/line label + connect(p_rightView,SIGNAL(tackPointChanged(double)), + this,SLOT(updateRightPositionLabel(double))); + connect(this,SIGNAL(updateRightView(double,double)), + p_rightView,SLOT(refreshView(double,double))); + + + connect(p_rightZoomIn,SIGNAL(clicked()),p_rightView,SLOT(zoomIn())); + connect(p_rightZoomOut,SIGNAL(clicked()),p_rightView,SLOT(zoomOut())); + connect(p_rightZoom1,SIGNAL(clicked()),p_rightView,SLOT(zoom1())); + + // Connect pan buttons to ChipViewport + connect(rightPanUp,SIGNAL(clicked()),p_rightView,SLOT(panUp())); + connect(rightPanDown,SIGNAL(clicked()),p_rightView,SLOT(panDown())); + connect(rightPanLeft,SIGNAL(clicked()),p_rightView,SLOT(panLeft())); + connect(rightPanRight,SIGNAL(clicked()),p_rightView,SLOT(panRight())); + + // Create chips for left and right + p_leftChip = new Isis::Chip(VIEWSIZE,VIEWSIZE); + p_rightChip = new Isis::Chip(VIEWSIZE,VIEWSIZE); + + p_nogeom = new QRadioButton ("No geom"); + p_nogeom->setChecked(true); + p_geom = new QRadioButton ("Geom"); + QRadioButton *rotate = new QRadioButton ("Rotate"); + QButtonGroup *bgroup = new QButtonGroup (); + bgroup->addButton(p_nogeom); + bgroup->addButton(p_geom); + bgroup->addButton(rotate); + + connect(p_nogeom,SIGNAL(clicked()),this,SLOT(setNoGeom())); + connect(p_geom,SIGNAL(clicked()),this,SLOT(setGeom())); + + // TODO: ?? Don't think we need this connection + connect(rotate,SIGNAL(clicked()),this,SLOT(setRotate())); + + // Set some defaults + p_geomIt = false; + p_rotation = 0; + + p_dial = new QDial(); + p_dial->setRange(0,360); + p_dial->setWrapping(false); + p_dial->setNotchesVisible(true); + p_dial->setNotchTarget(5.); + p_dial->setEnabled(false); + + p_dialNumber = new QLCDNumber(); + p_dialNumber->setEnabled(false); + connect(p_dial,SIGNAL(valueChanged(int)),p_dialNumber,SLOT(display(int))); + connect(p_dial,SIGNAL(valueChanged(int)),p_rightView,SLOT(rotateChip(int))); + + QCheckBox *cross = new QCheckBox("Show crosshair"); + connect(cross,SIGNAL(toggled(bool)),p_leftView,SLOT(setCross(bool))); + connect(cross,SIGNAL(toggled(bool)),p_rightView,SLOT(setCross(bool))); + cross->setChecked(true); + + QCheckBox *circle = new QCheckBox("Circle"); + circle->setChecked(false); + connect(circle,SIGNAL(toggled(bool)),this,SLOT(setCircle(bool))); + + p_slider = new QScrollBar(Qt::Horizontal); + p_slider->setRange(1,100); + p_slider->setSingleStep(1); + connect(p_slider,SIGNAL(valueChanged(int)),p_leftView,SLOT(setCircleSize(int))); + connect(p_slider,SIGNAL(valueChanged(int)),p_rightView,SLOT(setCircleSize(int))); + p_slider->setValue(20); + p_slider->setDisabled(true); + p_slider->hide(); + + QVBoxLayout *vlayout = new QVBoxLayout(); + vlayout->addWidget(p_nogeom); + vlayout->addWidget(p_geom); + vlayout->addWidget(rotate); + vlayout->addWidget(p_dial); + vlayout->addWidget(p_dialNumber); + vlayout->addWidget(cross); + vlayout->addWidget(circle); + vlayout->addWidget(p_slider); + gridLayout->addLayout(vlayout,row++,2); + + // Show sample / line for measure of chips shown + p_leftSampLinePosition = new QLabel(); + gridLayout->addWidget(p_leftSampLinePosition,row,0); + p_rightSampLinePosition = new QLabel(); + gridLayout->addWidget(p_rightSampLinePosition,row++,1); + + // Show lat / lon for measure of chips shown + p_leftLatLonPosition = new QLabel(); + gridLayout->addWidget(p_leftLatLonPosition,row,0); + p_rightLatLonPosition = new QLabel(); + gridLayout->addWidget(p_rightLatLonPosition,row++,1); + + + // Add auto registration extension + p_autoRegExtension = new QWidget; + p_oldPosition = new QLabel; + p_goodFit = new QLabel; + QVBoxLayout *autoRegLayout = new QVBoxLayout; + autoRegLayout->setMargin(0); + autoRegLayout->addWidget(p_oldPosition); + autoRegLayout->addWidget(p_goodFit); + p_autoRegExtension->setLayout(autoRegLayout); + p_autoRegShown = false; + p_autoRegAttempted = false; + gridLayout->addWidget(p_autoRegExtension,row++,1); + + + QHBoxLayout *leftLayout = new QHBoxLayout(); + QToolButton *stop = new QToolButton(); + stop->setIcon(QPixmap(toolIconDir+"/blinkStop.png")); + stop->setIconSize(QSize(22,22)); + stop->setToolTip("Blink Stop"); + text = "Function: Stop automatic timed blinking"; + stop->setWhatsThis(text); + connect(stop,SIGNAL(released()),this,SLOT(blinkStop())); + + QToolButton *start = new QToolButton(); + start->setIcon(QPixmap(toolIconDir+"/blinkStart.png")); + start->setIconSize(QSize(22,22)); + start->setToolTip("Blink Start"); + text = "Function: Start automatic timed blinking. Cycles \ + through linked viewports at variable rate"; + start->setWhatsThis(text); + connect(start,SIGNAL(released()),this,SLOT(blinkStart())); + + p_blinkTimeBox = new QDoubleSpinBox(); + p_blinkTimeBox->setMinimum(0.1); + p_blinkTimeBox->setMaximum(5.0); + p_blinkTimeBox->setDecimals(1); + p_blinkTimeBox->setSingleStep(0.1); + p_blinkTimeBox->setValue(0.5); + p_blinkTimeBox->setToolTip("Blink Time Delay"); + text = "Function: Change automatic blink rate between " + + QString::number(p_blinkTimeBox->minimum()) + " and " + + QString::number(p_blinkTimeBox->maximum()) + " seconds"; + p_blinkTimeBox->setWhatsThis(text); + connect(p_blinkTimeBox,SIGNAL(valueChanged(double)), + this,SLOT(changeBlinkTime(double))); + + QPushButton *find = new QPushButton ("Find"); + + leftLayout->addWidget(stop); + leftLayout->addWidget(start); + leftLayout->addWidget(p_blinkTimeBox); + leftLayout->addWidget(find); + leftLayout->addStretch(); + // TODO: Move AutoPick to NewPointDialog +// QPushButton *autopick = new QPushButton ("AutoPick"); +// autopick->setFocusPolicy(Qt::NoFocus); +// QPushButton *blink = new QPushButton ("Blink"); +// blink->setFocusPolicy(Qt::NoFocus); +// leftLayout->addWidget(autopick); +// leftLayout->addWidget(blink); + gridLayout->addLayout(leftLayout,row,0); + + + QHBoxLayout *rightLayout = new QHBoxLayout(); + p_autoReg = new QPushButton ("Register"); + QPushButton *save = new QPushButton ("Save Point"); + + rightLayout->addWidget(p_autoReg); + rightLayout->addWidget(save); + rightLayout->addStretch(); + gridLayout->addLayout(rightLayout,row,1); + + connect(find,SIGNAL(clicked()),this,SLOT(findPoint())); + connect(p_autoReg,SIGNAL(clicked()),this,SLOT(registerPoint())); + connect(save,SIGNAL(clicked()),this,SLOT(savePoint())); + + setLayout(gridLayout); + + //p_pointEditor->setCentralWidget(cw); + p_autoRegExtension->hide(); + + //p_pointEditor->setShown(true); + //p_pointEditor->raise(); + } + + + + + /** + * Set the measure displayed in the left ChipViewport + * + * @param leftMeasure Input Measure displayed in left ChipViewport + * @param leftCube Input Cube of measure displayed in left ChipViewport + * + * @author Tracie Sucharski + * @internal + * @history 2008-11-19 Tracie Sucharski - If left cube changes, get new + * universalGroundMap. + */ + void ControlPointEdit::setLeftMeasure(Isis::ControlMeasure *leftMeasure, + Isis::Cube *leftCube,std::string pointId) { + + // Make sure registration is turned off + if (p_autoRegShown) { + // Undo Registration + p_autoRegShown = false; + p_autoRegExtension->hide(); + p_autoReg->setText("Register"); + } + + p_leftMeasure = leftMeasure; + p_pointId = pointId; + + // get new ground map + if (p_leftGroundMap != 0) delete p_leftGroundMap; + p_leftGroundMap = new Isis::UniversalGroundMap(*leftCube); + p_leftCube = leftCube; + + p_leftChip->TackCube(p_leftMeasure->Sample(),p_leftMeasure->Line()); + p_leftChip->Load(*p_leftCube); + + // Dump into left chipViewport + p_leftView->setChip(p_leftChip,p_leftCube); + + } + + + /** + * Set the measure displayed in the right ChipViewport + * + * + * @param rightMeasure Input Measure displayed in right ChipViewport + * @param rightCube Input Cube of measure displayed in right ChipViewport + * + * @author Tracie Sucharski + * @internal + * @history 2008-11-19 Tracie Sucharski - If right cube changes, get new + * universalGroundMap. + * @history 2008-15-2008 Jeannie Walldren - Added error string to + * Isis::iException::Message before + * creating QMessageBox + * @history 2009-09-14 Tracie Sucharski - Call geomChip to make + * sure left chip is initialized in the + * ChipViewport. This was done for the changes + * made to the Chip class and the ChipViewport + * class where the Cube info is no longer stored. + * + */ + void ControlPointEdit::setRightMeasure(Isis::ControlMeasure *rightMeasure, + Isis::Cube *rightCube,std::string pointId) { + + // Make sure registration is turned off + if (p_autoRegShown) { + // Undo Registration + p_autoRegShown = false; + p_autoRegExtension->hide(); + p_autoReg->setText("Register"); + } + p_autoRegAttempted = false; + + p_rightMeasure = rightMeasure; + p_pointId = pointId; + + // get new ground map + if (p_rightGroundMap != 0) delete p_rightGroundMap; + p_rightGroundMap = new Isis::UniversalGroundMap(*rightCube); + p_rightCube = rightCube; + + p_rightChip->TackCube(p_rightMeasure->Sample(),p_rightMeasure->Line()); + if (p_geomIt == false) { + p_rightChip->Load(*p_rightCube); + } + else { + try { + p_rightChip->Load(*p_rightCube,*p_leftChip,*p_leftCube); + + } + catch (Isis::iException &e) { + e.Message(Isis::iException::User,"Geom failed.",_FILEINFO_); + QString message = e.Errors().c_str(); + e.Clear (); + QMessageBox::information((QWidget *)parent(),"Error",message); + p_rightChip->Load(*p_rightCube); + p_geomIt = false; + p_nogeom->setChecked(true); + p_geom->setChecked(false); + } + } + + // Dump into left chipViewport + p_rightView->setChip(p_rightChip,p_rightCube); + updateRightGeom(); + //p_rightView->geomChip(p_leftChip,p_leftCube); + + } + + + /** + * Update sample/line, lat/lon and zoom factor of left measure + * + * @param zoomFactor Input zoom factor + * + * @author Tracie Sucharski + */ + void ControlPointEdit::updateLeftPositionLabel(double zoomFactor) { + QString pos = "Sample: " + QString::number(p_leftView->tackSample()) + + " Line: " + QString::number(p_leftView->tackLine()); + p_leftSampLinePosition->setText(pos); + + // Get lat/lon from point in left + p_leftGroundMap->SetImage(p_leftView->tackSample(),p_leftView->tackLine()); + double lat = p_leftGroundMap->UniversalLatitude(); + double lon = p_leftGroundMap->UniversalLongitude(); + + pos = "Latitude: " + QString::number(lat) + + " Longitude: " + QString::number(lon); + p_leftLatLonPosition->setText(pos); + + // Print zoom scale factor + pos = "Zoom Factor: " + QString::number(zoomFactor); + p_leftZoomFactor->setText(pos); + + } + + + /** + * Update sample/line, lat/lon and zoom factor of right measure + * + * @param zoomFactor Input zoom factor + * + * @author Tracie Sucharski + */ + void ControlPointEdit::updateRightPositionLabel(double zoomFactor) { + QString pos = "Sample: " + QString::number(p_rightView->tackSample()) + + " Line: " + QString::number(p_rightView->tackLine()); + p_rightSampLinePosition->setText(pos); + + // Get lat/lon from point in right + p_rightGroundMap->SetImage(p_rightView->tackSample(),p_rightView->tackLine()); + double lat = p_rightGroundMap->UniversalLatitude(); + double lon = p_rightGroundMap->UniversalLongitude(); + + pos = "Latitude: " + QString::number(lat) + + " Longitude: " + QString::number(lon); + p_rightLatLonPosition->setText(pos); + + // Print zoom scale factor + pos = "Zoom Factor: " + QString::number(zoomFactor); + p_rightZoomFactor->setText(pos); + + } + + + //! Find point from left ChipViewport in the right ChipViewport + void ControlPointEdit::findPoint() { + + // Get lat/lon from point in left + p_leftGroundMap->SetImage(p_leftView->tackSample(),p_leftView->tackLine()); + double lat = p_leftGroundMap->UniversalLatitude(); + double lon = p_leftGroundMap->UniversalLongitude(); + + // Reload right chipViewport with this new tack point. + if (p_rightGroundMap->SetUniversalGround(lat,lon)) + emit updateRightView(p_rightGroundMap->Sample(),p_rightGroundMap->Line()); + + } + + /** + * Sub-pixel register point in right chipViewport with point in + * left. + * @internal + * @history 2008-15-2008 Jeannie Walldren - Throw and catch + * error before creating QMessageBox + * @history 2009-03-23 Tracie Sucharski - Added private p_autoRegAttempted + * for the SaveChips method. + * @history 2010-02-16 Tracie Sucharski- If autoreg fails, + * print registration stats. + * @history 2010-02-18 Tracie Sucharski - Registration stats wasn't the + * correct info to print. Instead, check + * registrationStatus and print separate errors + * for each possibility. + * @history 2010-02-22 Tracie Sucharski - Added more info for registration + * failures. + * @history 2010-06-08 Jeannie Walldren - Catch error and + * warn user if unable to load + * pattern (left) or search (right) + * chip + * + */ + + void ControlPointEdit::registerPoint() { + + if (p_autoRegShown) { + // Undo Registration + p_autoRegShown = false; + p_autoRegExtension->hide(); + p_autoReg->setText("Register"); + + // Reload chip with original measure + emit updateRightView(p_rightMeasure->Sample(),p_rightMeasure->Line()); + return; + + } + p_autoRegAttempted = true; + + try{ + p_autoRegFact->PatternChip()->TackCube( + p_leftMeasure->Sample(),p_leftMeasure->Line()); + p_autoRegFact->PatternChip()->Load(*p_leftCube); + p_autoRegFact->SearchChip()->TackCube( + p_rightMeasure->Sample(),p_rightMeasure->Line()); + p_autoRegFact->SearchChip()->Load(*p_rightCube,*(p_autoRegFact->PatternChip()),*p_leftCube); + Isis::AutoReg::RegisterStatus status = p_autoRegFact->Register(); + if (status != Isis::AutoReg::Success) { + throw Isis::iException::Message(Isis::iException::User,"Autoregistration failed",_FILEINFO_); + } + } + catch (Isis::iException &e){ + Isis::AutoReg::RegisterStatus status = p_autoRegFact->Register(); + QString msg = "Cannot sub-pixel register this point.\n"; + msg += e.Errors().c_str(); + if (status != Isis::AutoReg::Success) { + if (status == Isis::AutoReg::PatternChipNotEnoughValidData) { + msg += "\n\nNot enough valid data in Pattern Chip.\n"; + msg += " PatternValidPercent = "; + msg += QString::number(p_autoRegFact->PatternValidPercent()) + "%"; + } + else if (status == Isis::AutoReg::FitChipNoData) { + msg += "\n\nNo valid data in Fit Chip."; + } + else if (status == Isis::AutoReg::FitChipToleranceNotMet) { + msg += "\n\nGoodness of Fit Tolerance not met.\n"; + msg += "\nGoodnessOfFit = " + QString::number(p_autoRegFact->GoodnessOfFit()); + msg += "\nGoodnessOfFitTolerance = "; + msg += QString::number(p_autoRegFact->Tolerance()); + } + else if (status == Isis::AutoReg::SurfaceModelNotEnoughValidData) { + msg += "\n\nNot enough points to fit a surface model for sub-pixel "; + msg += "accuracy. Probably too close to edge.\n"; + } + else if (status == Isis::AutoReg::SurfaceModelSolutionInvalid) { + msg += "\n\nCould not model surface for sub-pixel accuracy.\n"; + } + else if (status == Isis::AutoReg::SurfaceModelDistanceInvalid) { + double sampDist,lineDist; + p_autoRegFact->Distance(sampDist,lineDist); + msg += "\n\nSurface model moves registartion more than tolerance.\n"; + msg += "\nSampleMovement = " + QString::number(sampDist) + + " LineMovement = " + QString::number(lineDist); + msg += "\nDistanceTolerance = " + + QString::number(p_autoRegFact->DistanceTolerance()); + } + else if (status == Isis::AutoReg::PatternZScoreNotMet) { + double score1,score2; + p_autoRegFact->ZScores(score1,score2); + msg += "\n\nPattern data max or min does not pass z-score test.\n"; + msg += "\nMinimumZScore = " + QString::number(p_autoRegFact->MinimumZScore()); + msg += "\nCalculatedZscores = " + QString::number(score1) + ", " + QString::number(score2); + } + else if (status == Isis::AutoReg::SurfaceModelEccentricityRatioNotMet) { + msg += "\n\nEccentricity of surface model exceeds tolerance."; + QString calcEccentricity = QString::number(p_autoRegFact->EccentricityRatio(), 'f', 5); + msg += "\nCalculated Eccentricity Ratio = " + + calcEccentricity + " (" + calcEccentricity + ":1)"; + QString tolEccentricity = QString::number(p_autoRegFact->EccentricityRatioTolerance(), 'f', 5); + msg += "\nEccentricity Ratio Tolerance (i.e., EccentricityRatio) = " + + tolEccentricity + " (" + tolEccentricity + ":1)"; + } + else if (status == Isis::AutoReg::AdaptiveAlgorithmFailed) { + msg += "\n\nError occured in Adaptive algorithm."; + } + else { + msg += "\n\nUnknown registration error."; + } + } + + QMessageBox::information((QWidget *)parent(),"Error",msg); + e.Clear(); + return; + } + + + + // Load chip with new registered point + emit updateRightView(p_autoRegFact->CubeSample(),p_autoRegFact->CubeLine()); + + + QString oldPos = "Original Sample: " + + QString::number(p_rightMeasure->Sample()) + " Original Line: " + + QString::number(p_rightMeasure->Line()); + p_oldPosition->setText(oldPos); + + QString goodFit = "Goodness of Fit: " + + QString::number(p_autoRegFact->GoodnessOfFit()); + p_goodFit->setText(goodFit); + + p_autoRegExtension->show(); + p_autoRegShown = true; + p_autoReg->setText("Undo Registration"); + } + + /** + * Save point under the crosshair in right ChipViewport + * @internal + * @history 2008-12-30 Jeannie Walldren - Modified to update + * user (chooser) name and date when + * point is saved + */ + void ControlPointEdit::savePoint() { + // Get cube position at right chipViewport crosshair + if (p_rightMeasure != NULL){ + p_rightMeasure->SetCoordinate(p_rightView->tackSample(), + p_rightView->tackLine()); + p_rightMeasure->SetDateTime(); + p_rightMeasure->SetChooserName(); + } + if (p_allowLeftMouse) { + if (p_leftMeasure != NULL) + p_leftMeasure->SetCoordinate(p_leftView->tackSample(),p_leftView->tackLine()); + p_leftMeasure->SetDateTime(); + p_leftMeasure->SetChooserName(); + } + + // If the right chip is the same as the left chip , update the left + // chipViewport. + if (p_rightMeasure->CubeSerialNumber() == p_leftMeasure->CubeSerialNumber()) { + p_leftMeasure->SetCoordinate(p_rightView->tackSample(), + p_rightView->tackLine()); + p_leftMeasure->SetDateTime(); + p_leftMeasure->SetChooserName(); + emit updateLeftView(p_rightView->tackSample(),p_rightView->tackLine()); + } + + + // If autoReg is shown + if (p_autoRegShown) { + p_autoRegShown = false; + p_autoRegExtension->hide(); + p_autoReg->setText("Register"); + } + + + // Redraw measures and overlaps on viewports + emit pointSaved(); + } + + + + /** + * Slot to update the geomed right ChipViewport for zoom + * operations + * @internal + * @history 2008-15-2008 Jeannie Walldren - Added error string to + * Isis::iException::Message before + * creating QMessageBox + */ + void ControlPointEdit::updateRightGeom() { + + if (p_geomIt) { + try { + p_rightView->geomChip(p_leftChip,p_leftCube); + + } + catch (Isis::iException &e) { + e.Message(Isis::iException::User,"Geom failed.",_FILEINFO_); + QString message = e.Errors().c_str(); + e.Clear (); + QMessageBox::information((QWidget *)parent(),"Error",message); + p_geomIt = false; + p_nogeom->setChecked(true); + p_geom->setChecked(false); + } + } + + } + + + //! Slot to enable the rotate dial + void ControlPointEdit::setRotate() { + p_dial->setEnabled(true); + p_dialNumber->setEnabled(true); + p_dial->setNotchesVisible(true); + + } + + + + /** + * Turn geom on + * + * @internal + * @history 2007-06-15 Tracie Sucharski - Grey out zoom buttons + * @history 2008-15-2008 Jeannie Walldren - Added error string to + * Isis::iException::Message before + * creating QMessageBox + **/ + void ControlPointEdit::setGeom() { + + if (p_geomIt == true) return; + + QApplication::setOverrideCursor(Qt::WaitCursor); + + // Grey right view zoom buttons + QString text = "Zoom functions disabled when Geom is set"; + p_rightZoomIn->setEnabled(false); + p_rightZoomIn->setWhatsThis(text); + p_rightZoomIn->setToolTip(text); + p_rightZoomOut->setEnabled(false); + p_rightZoomOut->setWhatsThis(text); + p_rightZoomOut->setToolTip(text); + p_rightZoom1->setEnabled(false); + p_rightZoom1->setWhatsThis(text); + p_rightZoom1->setToolTip(text); + + + // Reset dial to 0 before disabling + p_dial->setValue(0); + p_dial->setEnabled(false); + p_dialNumber->setEnabled(false); + + p_geomIt = true; + + try { + p_rightView->geomChip(p_leftChip,p_leftCube); + + } + catch (Isis::iException &e) { + e.Message(Isis::iException::User,"Geom failed.",_FILEINFO_); + QString message = e.Errors().c_str(); + e.Clear (); + QMessageBox::information((QWidget *)parent(),"Error",message); + p_geomIt = false; + p_nogeom->setChecked(true); + p_geom->setChecked(false); + } + + QApplication::restoreOverrideCursor(); + } + + + //! Slot to turn off geom + void ControlPointEdit::setNoGeom() { + + if (p_geomIt == false) return; + + QApplication::setOverrideCursor(Qt::WaitCursor); + + QString text = "Zoom in 2X"; + p_rightZoomIn->setEnabled(true); + p_rightZoomIn->setWhatsThis(text); + p_rightZoomIn->setToolTip("Zoom In"); + text = "Zoom out 2X"; + p_rightZoomOut->setEnabled(true); + p_rightZoomOut->setWhatsThis(text); + p_rightZoomOut->setToolTip("Zoom Out"); + text = "Zoom 1:1"; + p_rightZoom1->setEnabled(true); + p_rightZoom1->setWhatsThis(text); + p_rightZoom1->setToolTip("Zoom 1:1"); + + // Reset dial to 0 before disabling + p_dial->setValue(0); + p_dial->setEnabled(false); + p_dialNumber->setEnabled(false); + + p_geomIt = false; + p_rightView->nogeomChip(); + + QApplication::restoreOverrideCursor(); + } + + + + + /** + * Turn circle widgets on/off + * + * @param checked Input Turn cirle on or off + * + * @author 2008-09-09 Tracie Sucharski + */ + void ControlPointEdit::setCircle(bool checked) { + + if (checked == p_circle) return; + + p_circle = checked; + if (p_circle) { + // Turn on slider bar + p_slider->setDisabled(false); + p_slider->show(); + p_slider->setValue(20); + p_leftView->setCircle(true); + p_rightView->setCircle(true); + } + else { + p_slider->setDisabled(true); + p_slider->hide(); + p_leftView->setCircle(false); + p_rightView->setCircle(false); + } + + + } + + + + //! Slot to start blink function + void ControlPointEdit::blinkStart() { + if (p_timerOn) return; + + // Set up blink list + p_blinkList.push_back(p_leftView); + p_blinkList.push_back(p_rightView); + p_blinkIndex = 0; + + p_timerOn = true; + int msec = (int) (p_blinkTimeBox->value() * 1000.0); + p_timer = new QTimer(this); + connect(p_timer, SIGNAL(timeout()), this, SLOT(updateBlink())); + p_timer->start(msec); + } + + + //! Slot to stop blink function + void ControlPointEdit::blinkStop() { + p_timer->stop(); + p_timerOn = false; + p_blinkList.clear(); + + // Reload left chipViewport with original chip + p_leftView->repaint(); + + } + + + + /** + * Set blink rate + * + * @param interval Input Blink rate in seconds + * @author Tracie Sucharski + */ + void ControlPointEdit::changeBlinkTime(double interval) { + if (p_timerOn) p_timer->setInterval((int)(interval*1000.)); + } + + + //! Slot to cause the blink to happen coinciding with the timer + void ControlPointEdit::updateBlink() { + + p_blinkIndex = !p_blinkIndex; + p_leftView->loadView(*(p_blinkList)[p_blinkIndex]); + } + + + + + /** + * Allows user to choose a new template file by opening a window + * from which to select a filename. This file is then + * registered and set as the new template. + * + * @author Tracie Sucharski + * @internal + * @history 2008-12-10 Jeannie Walldren - Changed name from + * openTemplateFile() and added functionality to set + * new template filename to the private variable, + * p_templateFilename + * @history 2008-12-15 Jeannie Walldren - Modified code to + * only allow the template file to be modified if + * registration is successfull, otherwise the + * original template file is kept. + */ + void ControlPointEdit::setTemplateFile() { + + QString filter = "Select registration template (*.def *.pvl);;"; + filter += "All (*)"; + QString regDef = QFileDialog::getOpenFileName((QWidget*)parent(), + "Select a registration template", + ".", + filter); + if (regDef.isEmpty()) return; + Isis::AutoReg *reg=NULL; + // save original template filename + std::string temp = p_templateFilename; + try { + // set template filename to user chosen pvl file + p_templateFilename = regDef.toStdString(); + // Create PVL object with this file + Isis::Pvl pvl(regDef.toStdString()); + // try to register file + reg = Isis::AutoRegFactory::Create(pvl); + if (p_autoRegFact != NULL) delete p_autoRegFact; + p_autoRegFact = reg; + } + catch ( Isis::iException &e ) { + // set templateFilename back to its original value + p_templateFilename = temp; + e.Message(Isis::iException::Io,"Cannot create AutoRegFactory for " + + regDef.toStdString() + ". As a result, current template file will remain set to " + + p_templateFilename,_FILEINFO_); + QString message = e.Errors().c_str(); + e.Clear (); + QMessageBox::information((QWidget *)parent(),"Error",message); + } + } + + + /** + * Set the option that allows mouse movements in the left ChipViewport. + * + * @author Tracie Sucharski + * @internal + */ + void ControlPointEdit::allowLeftMouse(bool allowMouse) { + p_allowLeftMouse = allowMouse; + } + + + + + /** + * Slot to save registration chips to files and fire off qview. + * + * @author 2009-03-18 Tracie Sucharski + * @internal + * @history 2009-03-23 Tracie Sucharski - Use p_autoRegAttempted to see + * if chips exist. + */ + void ControlPointEdit::saveChips () { + +// if (!p_autoRegShown) { + if (!p_autoRegAttempted) { + QString message = "Point must be Registered before chips can be saved."; + QMessageBox::warning((QWidget *)parent(),"Warning",message); + return; + } + + // Save chips - pattern, search and fit + std::string baseFile = p_pointId + "_" + + Isis::iString((int)(p_leftMeasure->Sample())) + "_" + + Isis::iString((int)(p_leftMeasure->Line())) + "_" + + Isis::iString((int)(p_rightMeasure->Sample())) + "_" + + Isis::iString((int)(p_rightMeasure->Line())) + "_"; + std::string fname = baseFile + "Search.cub"; + std::string command = "$ISISROOT/bin/qview " + fname; + p_autoRegFact->SearchChip()->Write(fname); + fname = baseFile + "Pattern.cub"; + command += " " + fname; + p_autoRegFact->PatternChip()->Write(fname); + fname = baseFile + "Fit.cub"; + command += " " + fname + "&"; + p_autoRegFact->FitChip()->Write(fname); + Isis::System(command); + } + +#if 0 + void ControlPointEdit::setInterestOp() { + + + + } +#endif + +} + diff --git a/isis/src/qisis/objs/ControlPointEdit/ControlPointEdit.h b/isis/src/qisis/objs/ControlPointEdit/ControlPointEdit.h new file mode 100644 index 0000000000000000000000000000000000000000..d943a1fabde1fe4f0c5eec7c482593e3d271878d --- /dev/null +++ b/isis/src/qisis/objs/ControlPointEdit/ControlPointEdit.h @@ -0,0 +1,180 @@ +#ifndef ControlPointEdit_h +#define ControlPointEdit_h + +// This is the only include allowed in this file! +#include + + +class QCheckBox; +class QDial; +class QDoubleSpinBox; +class QHBoxLayout; +class QLabel; +class QLCDNumber; +class QPushButton; +class QRadioButton; +class QScrollBar; +class QTimer; +class QToolButton; +class QVBoxLayout; + +namespace Isis { + class AutoReg; + class Chip; + class ControlMeasure; + class Cube; + class UniversalGroundMap; +} + +namespace Qisis { + class ChipViewport; + class Tool; + + +/** + * @brief Point Editor Widget + * + * @ingroup Visualization Tools + * + * @author 2008-09-09 Tracie Sucharski + * + * @internal + * @history 2008-11-19 Tracie Sucharski - Addition option to + * constructor to allow mouse events + * on leftChipViewport. + * @history 2008-11-24 Tracie Sucharski - Changed class name + * from PointEdit + * @history 2008-12-02 Jeannie Walldren - Modified + * createPointEditor() to allow the + * leftChipViewport to refresh even if + * allowLeftMouse = false. + * @history 2008-12-10 Jeannie Walldren - Added a private + * variable for the template filename. + * Set the default value of this + * variable to the previously + * hard-coded template filename. Added + * setTemplateFile() method derived + * from previously unused and + * commented out method called + * openTemplateFile(). + * @history 2008-12-15 Jeannie Walldren - Some QMessageBox + * warnings had strings tacked on to + * the list of errors. These strings + * were changed to iExceptions and + * added to the error stack to conform + * with Isis standards. + * @history 2008-12-30 Jeannie Walldren - Modified + * savePoint() method to update user + * (chooser) name and date when point + * is saved + * @history 2009-03-17 Tracie Sucharski - Add slot to set a + * boolean to indicate whether the + * registration chips should be saved. + * @history 2010-06-08 Jeannie Walldren - Added warning box + * in registerPoint() if unable to + * load left or right chip + * @history 2010-06-26 Eric Hyer - now uses MdiCubeViewport instead of + * CubeViewport. Fixed multiple include problems. + */ + class ControlPointEdit : public QWidget { + Q_OBJECT + + public: + ControlPointEdit (QWidget *parent=0,bool allowLeftMouse=false); + std::string templateFilename() { return p_templateFilename; }; + void setTemplateFile(); + void allowLeftMouse (bool allowMouse); + + signals: + void updateLeftView(double sample,double line); + void updateRightView(double sample,double line); + void pointSaved(); + + public slots: + void setLeftMeasure (Isis::ControlMeasure *leftMeasure, + Isis::Cube *leftCube,std::string pointId); + void setRightMeasure (Isis::ControlMeasure *rightMeasure, + Isis::Cube *rightCube,std::string pointId); + void saveChips (); + + protected slots: + + private slots: + + void setNoGeom(); + void setGeom(); + void setRotate(); + void setCircle(bool); + + void findPoint(); + void registerPoint(); + void savePoint(); + void updateLeftPositionLabel (double zoomFactor); + void updateRightGeom(); + void updateRightPositionLabel (double zoomFactor); + + void blinkStart(); + void blinkStop(); + void changeBlinkTime(double interval); + void updateBlink(); + + private: + void createPointEditor(QWidget *parent); + + bool p_allowLeftMouse; + + std::string p_templateFilename; + QLabel *p_leftZoomFactor; + QLabel *p_rightZoomFactor; + QLabel *p_leftSampLinePosition; + QLabel *p_rightSampLinePosition; + QLabel *p_leftLatLonPosition; + QLabel *p_rightLatLonPosition; + QRadioButton *p_nogeom; + QRadioButton *p_geom; + QToolButton *p_rightZoomIn; + QToolButton *p_rightZoomOut; + QToolButton *p_rightZoom1; + + + bool p_timerOn; + QTimer *p_timer; + std::vector p_blinkList; + unsigned char p_blinkIndex; + + QDial *p_dial; + QLCDNumber *p_dialNumber; + QDoubleSpinBox *p_blinkTimeBox; + + bool p_circle; + QScrollBar *p_slider; + + QPushButton *p_autoReg; + QWidget *p_autoRegExtension; + QLabel *p_oldPosition; + QLabel *p_goodFit; + bool p_autoRegShown; + bool p_autoRegAttempted; + + + ChipViewport *p_leftView; + ChipViewport *p_rightView; + + Isis::Cube *p_leftCube; + Isis::Cube *p_rightCube; + Isis::ControlMeasure *p_leftMeasure; + Isis::ControlMeasure *p_rightMeasure; + Isis::Chip *p_leftChip; + Isis::Chip *p_rightChip; + Isis::UniversalGroundMap *p_leftGroundMap; + Isis::UniversalGroundMap *p_rightGroundMap; + + Isis::AutoReg *p_autoRegFact; + std::string p_pointId; + + int p_rotation; + bool p_geomIt; + }; +}; + +#endif diff --git a/isis/src/qisis/objs/ControlPointEdit/Makefile b/isis/src/qisis/objs/ControlPointEdit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/ControlPointEdit/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/CubeViewport/CubeViewport.cpp b/isis/src/qisis/objs/CubeViewport/CubeViewport.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2c9cc70913b83c8d270c1625b2243adbf011dbc0 --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/CubeViewport.cpp @@ -0,0 +1,2068 @@ +/** + * @file + * $Date: 2010/06/30 03:38:12 $ + * $Revision: 1.46 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "IsisDebug.h" +#include "CubeViewport.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Camera.h" +#include "CubeDataThread.h" +#include "iException.h" +#include "Filename.h" +#include "Histogram.h" +#include "Stretch.h" +#include "StretchTool.h" +#include "Tool.h" +#include "UniversalGroundMap.h" +#include "ViewportBuffer.h" + + +using namespace Isis; +using namespace std; + + +namespace Qisis { + /** + * Construct a cube viewport + * + * + * @param cube + * @param parent + */ + CubeViewport::CubeViewport(Isis::Cube *cube, QWidget *parent) : + QAbstractScrollArea(parent) { + // Is the cube usable? + if (cube == NULL) { + throw iException::Message(iException::Programmer, + "Can not view NULL cube pointer", + _FILEINFO_); + } + else if (!cube->IsOpen()) { + throw iException::Message(iException::Programmer, + "Can not view unopened cube", + _FILEINFO_); + } + + p_cube = cube; + p_cubeData = NULL; + p_cubeData = new CubeDataThread(); + p_cubeId = p_cubeData->AddCube(p_cube); + + connect(p_cubeData, SIGNAL(BrickChanged(int, const Isis::Brick *)), + this, SLOT(cubeDataChanged(int, const Isis::Brick *))); + connect(this, SIGNAL(doneWithData(int, const Isis::Brick *)), + p_cubeData, SLOT(DoneWithData(int, const Isis::Brick *))); + + p_cubeData->AddChangeListener(); + + void doneWithData(int, const Isis::Brick *); + + // Set up the scroll area + setAttribute(Qt::WA_DeleteOnClose); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + viewport()->setCursor(QCursor(Qt::CrossCursor)); + viewport()->installEventFilter(this); + viewport()->setAttribute(Qt::WA_OpaquePaintEvent); + +// viewport()->setAttribute(Qt::WA_NoSystemBackground); +// viewport()->setAttribute(Qt::WA_PaintOnScreen,false); + + p_saveEnabled = false; + // Save off info about the cube + p_scale = -1.0; + p_color = false; + + + setCaption(); + + p_redBrick = new Brick(4, 1, 1, cube->PixelType()); + p_grnBrick = new Brick(4, 1, 1, cube->PixelType()); + p_bluBrick = new Brick(4, 1, 1, cube->PixelType()); + p_gryBrick = new Brick(4, 1, 1, cube->PixelType()); + p_pntBrick = new Brick(4, 1, 1, cube->PixelType()); + + p_paintPixmap = false; + p_image = NULL; + p_cubeShown = true; + p_updatingBuffers = false; + + //updateScrollBars(1,1); + + p_groundMap = NULL; + p_projection = NULL; + p_camera = NULL; + + // Setup a universal ground map + try { + p_groundMap = new UniversalGroundMap(*p_cube); + } + catch (iException &e) { + e.Clear(); + } + + if (p_groundMap != NULL) { + // Setup the camera or the projection + if (p_groundMap->Camera() != NULL) { + p_camera = p_groundMap->Camera(); + if (p_camera->HasProjection()) { + try { + p_projection = cube->Projection(); + } + catch (iException &e) { + e.Clear(); + } + } + } + else { + p_projection = p_groundMap->Projection(); + } + } + + + // Setup context sensitive help + string cubeFileName = p_cube->Filename(); + p_whatsThisText = QString("Function: Viewport to ") + cubeFileName.c_str(); + + p_cubeWhatsThisText = + "

    Cube Dimensions: \ +

    Samples = " + + QString::number(cube->Samples()) + "
    " + + "Lines = " + + QString::number(cube->Lines()) + "
    " + + "Bands = " + + QString::number(cube->Bands()) + "

    "; + + /*setting up the qlist of CubeBandsStretch objs. + for( int b = 0; b < p_cube->Bands(); b++) { + CubeBandsStretch *stretch = new CubeBandsStretch(); + p_bandsStretchList.push_back(stretch); + }*/ + + p_grayBuffer = new ViewportBuffer(this, p_cubeData, p_cubeId); + p_grayBuffer->enable(false); + p_grayBuffer->setBand(1); + + p_redBuffer = NULL; + p_greenBuffer = NULL; + p_blueBuffer = NULL; + p_pixmapPaintRects = NULL; + + p_pixmapPaintRects = new QList(); + p_progressTimer = new QTimer(); + p_progressTimer->setInterval(250); + + p_knownStretches = new QVector< Isis::Stretch * >(); + p_globalStretches = new QVector< Isis::Stretch * >(); + + while (p_cube->Bands() > p_knownStretches->size()) { + p_knownStretches->push_back(NULL); + p_globalStretches->push_back(NULL); + } + + connect(p_progressTimer, SIGNAL(timeout()), this, SLOT(onProgressTimer())); + + p_bgColor = Qt::black; + } + + + /** + * This method is called to initially show the viewport. It will set the + * scale to show the entire cube and enable the gray buffer. + * + */ + void CubeViewport::showEvent(QShowEvent *event) { + if (p_scale == -1) { + double sampScale = (double) sizeHint().width() / (double) cubeSamples(); + double lineScale = (double) sizeHint().height() / (double) cubeLines(); + double scale = sampScale < lineScale ? sampScale : lineScale; + + setScale(scale, cubeSamples() / 2.0, cubeLines() / 2.0); + } + + if (p_grayBuffer && !p_grayBuffer->enabled()) { + p_grayBuffer->enable(true); + + // gives a proper initial stretch (entire cube) + p_grayBuffer->addStretchAction(); + } + + QAbstractScrollArea::show(); + + p_paintPixmap = true; + + paintPixmap(); + } + + + /** + * This updates the progress bar visually. Conceptually it emits + * the progressChanged signal with the current progress. + */ + void CubeViewport::onProgressTimer() { + double progress = 0.0; + bool completed = false; + + if (p_grayBuffer) { + progress += p_grayBuffer->currentProgress(); + completed = !p_grayBuffer->working(); + } + + if (p_redBuffer) { + progress += p_redBuffer->currentProgress() / 3.0; + completed = !p_redBuffer->working(); + } + + if (p_greenBuffer) { + progress += p_greenBuffer->currentProgress() / 3.0; + completed = completed && !p_greenBuffer->working(); + } + + if (p_blueBuffer) { + progress += p_blueBuffer->currentProgress() / 3.0; + completed = completed && !p_blueBuffer->working(); + } + + int realProgress = (int)(progress * 100.0); + + if (completed) { + realProgress = 100; + p_progressTimer->stop(); + emit screenPixelsChanged(); + } + else if (realProgress == 100) { + realProgress = 99; + } + + emit progressChanged(realProgress); + } + + + /** + * Destructor + * + */ + CubeViewport::~CubeViewport() { + if (p_redBrick) { + delete p_redBrick; + p_redBrick = NULL; + } + + if (p_grnBrick) { + delete p_grnBrick; + p_grnBrick = NULL; + } + + if (p_bluBrick) { + delete p_bluBrick; + p_bluBrick = NULL; + } + + if (p_gryBrick) { + delete p_gryBrick; + p_gryBrick = NULL; + } + + if (p_pntBrick) { + delete p_pntBrick; + p_pntBrick = NULL; + } + + if (p_groundMap) { + delete p_groundMap; + p_groundMap = NULL; + } + + if (p_grayBuffer) { + delete p_grayBuffer; + p_grayBuffer = NULL; + } + + if (p_redBuffer) { + delete p_redBuffer; + p_redBuffer = NULL; + } + + if (p_greenBuffer) { + delete p_greenBuffer; + p_greenBuffer = NULL; + } + + if (p_blueBuffer) { + delete p_blueBuffer; + p_blueBuffer = NULL; + } + + // p_cubeData MUST be deleted AFTER all viewport buffers!!! + if (p_cubeData) { + p_cubeData->RemoveChangeListener(); + delete p_cubeData; + p_cubeData = NULL; + } + + // p_cube MUST be deleted AFTER all viewport buffers!!! + if (p_cube) { + delete p_cube; + p_cube = NULL; + } + + if (p_progressTimer) { + delete p_progressTimer; + p_progressTimer = NULL; + } + + if (p_image) { + delete p_image; + p_image = NULL; + } + + if (p_pixmapPaintRects) { + for (int rect = 0; rect < p_pixmapPaintRects->size(); rect++) { + delete(*p_pixmapPaintRects)[rect]; + } + + delete p_pixmapPaintRects; + p_pixmapPaintRects = NULL; + } + + if (p_knownStretches) { + for (int stretch = 0; stretch < p_knownStretches->size(); stretch ++) { + if ((*p_knownStretches)[stretch] != NULL) { + delete(*p_knownStretches)[stretch]; + (*p_knownStretches)[stretch] = NULL; + } + } + + p_knownStretches->clear(); + + delete p_knownStretches; + p_knownStretches = NULL; + } + + if (p_globalStretches) { + for (int stretch = 0; stretch < p_globalStretches->size(); stretch ++) { + if ((*p_globalStretches)[stretch] != NULL) { + delete(*p_globalStretches)[stretch]; + (*p_globalStretches)[stretch] = NULL; + } + } + + p_globalStretches->clear(); + + delete p_globalStretches; + p_globalStretches = NULL; + } + } + + /** + * This method sets the viewports cube. + * + * @param cube + */ + void CubeViewport::setCube(Isis::Cube *cube) { + p_cube = cube; + setCaption(); + } + + + //! Return the number of samples in the cube + int CubeViewport::cubeSamples() const { + return p_cube->Samples(); + } + + + //! Return the number of lines in the cube + int CubeViewport::cubeLines() const { + return p_cube->Lines(); + } + + + //! Return the number of bands in the cube + int CubeViewport::cubeBands() const { + return p_cube->Bands(); + } + + + /** + * This method updates the internal viewport buffer based on + * changes in cube DN values. + * + * @param cubeId Cube that the changed brick belongs to + * @param data New data + */ + void CubeViewport::cubeDataChanged(int cubeId, const Isis::Brick *data) { + if (cubeId == p_cubeId) { + double ss, sl, es, el; + ss = data->Sample(); + sl = data->Line(); + es = data->Sample() + data->SampleDimension(); + el = data->Line() + data->LineDimension(); + if (ss < 0.5) + ss = 0.5; + if (sl < 0.5) + sl = 0.5; + if (es > cube()->Samples() + 0.5) + es = cube()->Samples() + 0.5; + if (el > cube()->Lines() + 0.5) + el = cube()->Lines() + 0.5; + + int sx, sy, ex, ey; + + cubeToViewport(ss, sl, sx, sy); + cubeToViewport(es, el, ex, ey); + if (sx < 0) + sx = 0; + if (sy < 0) + sy = 0; + if (ex > viewport()->width()) + ex = viewport()->width(); + if (ey > viewport()->height()) + ey = viewport()->height(); + QRect vpRect(sx, sy, ex - sx + 1, ey - sy + 1); + + p_updatingBuffers = true; + if (p_grayBuffer) + p_grayBuffer->fillBuffer(vpRect, data); + if (p_redBuffer) + p_redBuffer->fillBuffer(vpRect, data); + if (p_greenBuffer) + p_greenBuffer->fillBuffer(vpRect, data); + if (p_blueBuffer) + p_blueBuffer->fillBuffer(vpRect, data); + p_updatingBuffers = false; + + paintPixmapRects(); + } + + emit doneWithData(cubeId, data); + } + + + /** + * This method is called when the viewport recieves a close + * event. If changes have been made to this viewport it opens an + * information dialog that asks the user if they want to save, + * discard changes, or cancel. + * + * @param event + */ + void CubeViewport::closeEvent(QCloseEvent *event) { + if (p_saveEnabled) { + switch (QMessageBox::information(this, "Qview", + "The document contains unsaved changes\n" + "Do you want to save the changes before exiting?", + "&Save", "&Discard", "Cancel", + 0, // Enter == button 0 + 2)) + // Escape == button 2 + { + //Save changes and close viewport + case 0: + emit saveChanges(); + event->accept(); + break; + //Discard changes and close viewport + case 1: + emit discardChanges(); + event->accept(); + break; + //Cancel, don't close viewport + case 2: + event->ignore(); + break; + } + } + } + + /** + * This method is called when the cube has changed or changes + * have been finalized. + * + * @param changed + */ + void CubeViewport::cubeChanged(bool changed) { + p_saveEnabled = changed; + } + + /** + * Make viewports show up as 512 by 512 + * + * + * @return QSize + */ + QSize CubeViewport::sizeHint() const { + QSize s(512, 512); + return s; + } + + + /** + * Change the scale of the cube + * + * @param scale + */ + void CubeViewport::setScale(double scale) { + // Sanitize the scale value + if (scale == p_scale) + return; + if (scale > 16.0) + scale = 16.0; + //if (scale < 1.0/16.0) scale = 1.0/16.0; + + // Resize the scrollbars to reflect the new scale + double samp, line; + contentsToCube(horizontalScrollBar()->value(), verticalScrollBar()->value(), + samp, line); + p_scale = scale; + updateScrollBars(1, 1); // Setting to 1,1 make sure we don't have bad values + + // Now update the scroll bar value to the old line/sample + int x, y; + cubeToContents(samp, line, x, y); + updateScrollBars(x, y); + + p_updatingBuffers = true; + if (p_grayBuffer) + p_grayBuffer->scaleChanged(); + if (p_redBuffer) + p_redBuffer->scaleChanged(); + if (p_greenBuffer) + p_greenBuffer->scaleChanged(); + if (p_blueBuffer) + p_blueBuffer->scaleChanged(); + p_updatingBuffers = false; + + paintPixmapRects(); + + // Notify other tools about the scale change + emit scaleChanged(); + + // Update the display + setCaption(); + paintPixmap(); // Will get rid of old data in the display + + viewport()->repaint(); + emit screenPixelsChanged(); + } + + /** + * Change the scale of the cube after moving x,y to the center + * + * + * @param scale + * @param x + * @param y + */ + void CubeViewport::setScale(double scale, int x, int y) { + double samp, line; + viewportToCube(x, y, samp, line); + setScale(scale, samp, line); + } + + + /** + * Change the scale of the cube after moving samp/line to the + * center + * + * + * @param scale + * @param sample + * @param line + */ + void CubeViewport::setScale(double scale, double sample, double line) { + viewport()->setUpdatesEnabled(false); + + bool wasEnabled = false; + + if ((p_grayBuffer && p_grayBuffer->enabled()) || + (p_redBuffer && p_redBuffer->enabled())) { + wasEnabled = true; + } + + if (p_grayBuffer) + p_grayBuffer->enable(false); + if (p_redBuffer) + p_redBuffer->enable(false); + if (p_greenBuffer) + p_greenBuffer->enable(false); + if (p_blueBuffer) + p_blueBuffer->enable(false); + + if (p_paintPixmap) { + p_paintPixmap = false; + setScale(scale); + p_paintPixmap = true; + } + else { + setScale(scale); + } + + center(sample, line); + + if (p_grayBuffer) + p_grayBuffer->enable(wasEnabled); + if (p_redBuffer) + p_redBuffer->enable(wasEnabled); + if (p_greenBuffer) + p_greenBuffer->enable(wasEnabled); + if (p_blueBuffer) + p_blueBuffer->enable(wasEnabled); + + paintPixmap(); + viewport()->setUpdatesEnabled(true); + viewport()->update(); + emit screenPixelsChanged(); + } + + + /** + * Bring the cube pixel under viewport x/y to the center + * + * + * @param x + * @param y + */ + void CubeViewport::center(int x, int y) { + double sample, line; + viewportToCube(x, y, sample, line); + center(sample, line); + } + + + /** + * Bring the cube sample/line the center + * + * + * @param sample + * @param line + */ + void CubeViewport::center(double sample, double line) { + // TODO: If the x/y is close to the scrollbar values then + // we should use the scrollBy routine to make the display faster + int x, y; + cubeToContents(sample, line, x, y); + + int panX = horizontalScrollBar()->value() - x; + int panY = verticalScrollBar()->value() - y; + + updateScrollBars(x, y); + + p_updatingBuffers = true; + if (p_grayBuffer) + p_grayBuffer->pan(panX, panY); + if (p_redBuffer) + p_redBuffer->pan(panX, panY); + if (p_greenBuffer) + p_greenBuffer->pan(panX, panY); + if (p_blueBuffer) + p_blueBuffer->pan(panX, panY); + p_updatingBuffers = false; + + paintPixmapRects(); + + shiftPixmap(panX, panY); + + emit screenPixelsChanged(); + } + + + /** + * Goes through the list of requested paints, from the viewport + * buffer, and paints them. + */ + void CubeViewport::paintPixmapRects() { + for (int rect = 0; rect < p_pixmapPaintRects->size(); rect++) { + paintPixmap(*(*p_pixmapPaintRects)[rect]); + } + + p_pixmapPaintRects->clear(); + } + + + /** + * Convert a contents x/y to a cube sample/line (may be outside + * the cube) + * + * + * @param x + * @param y + * @param sample + * @param line + */ + void CubeViewport::contentsToCube(int x, int y, + double &sample, double &line) const { + sample = x / p_scale; + line = y / p_scale; + } + + + /** + * Convert a viewport x/y to a cube sample/line (may be outside + * the cube) + * + * + * @param x + * @param y + * @param sample + * @param line + */ + void CubeViewport::viewportToCube(int x, int y, + double &sample, double &line) const { + x += horizontalScrollBar()->value(); + x -= viewport()->width() / 2; + y += verticalScrollBar()->value(); + y -= viewport()->height() / 2; + contentsToCube(x, y, sample, line); + } + + + /** + * Convert a cube sample/line to a contents x/y (should not be + * outside) + * + * + * @param sample + * @param line + * @param x + * @param y + */ + void CubeViewport::cubeToContents(double sample, double line, + int &x, int &y) const { + x = (int)(sample * p_scale + 0.5); + y = (int)(line * p_scale + 0.5); + } + + + /** + * Convert a cube sample/line to a viewport x/y (may be outside + * the viewport) + * + * + * @param sample + * @param line + * @param x + * @param y + */ + void CubeViewport::cubeToViewport(double sample, double line, + int &x, int &y) const { + cubeToContents(sample, line, x, y); + x -= horizontalScrollBar()->value(); + x += viewport()->width() / 2; + y -= verticalScrollBar()->value(); + y += viewport()->height() / 2; + } + + + /** + * Move the scrollbars by dx/dy screen pixels + * + * + * @param dx + * @param dy + */ + void CubeViewport::scrollBy(int dx, int dy) { + // Make sure we don't generate bad values outside of the scroll range + int x = horizontalScrollBar()->value() + dx; + if (x <= 1) { + dx = 1 - horizontalScrollBar()->value(); + } + else if (x >= horizontalScrollBar()->maximum()) { + dx = horizontalScrollBar()->maximum() - horizontalScrollBar()->value(); + } + + // Make sure we don't generate bad values outside of the scroll range + int y = verticalScrollBar()->value() + dy; + if (y <= 1) { + dy = 1 - verticalScrollBar()->value(); + } + else if (y >= verticalScrollBar()->maximum()) { + dy = verticalScrollBar()->maximum() - verticalScrollBar()->value(); + } + + // Do we do anything? + if ((dx == 0) && (dy == 0)) + return; + + // We do so update the scroll bars + updateScrollBars(horizontalScrollBar()->value() + dx, + verticalScrollBar()->value() + dy); + + // Scroll the the pixmap + scrollContentsBy(-dx, -dy); + } + + + /** + * Scroll the viewport contents by dx/dy screen pixels + * + * + * @param dx + * @param dy + */ + void CubeViewport::scrollContentsBy(int dx, int dy) { + + // We shouldn't do anything if scrollbars are being updated + if (viewport()->signalsBlocked()) { + return; + } + + // Tell the buffers to update appropriate for the pan and upon completion + // they will call bufferUpdated. We don't want bufferUpdated to happen + // until afterwards. If only shrinking and no new data then the viewport + // buffers will complete immediately. When all buffers don't have their + // appropriate actions queued bufferUpdated can't succeed. + + // Also block paints because we'll repaint it all when we're done + // telling each buffer about the pan. + bool panQueued = false; + QRect bufferXYRect; + + p_updatingBuffers = true; + + if (p_grayBuffer) { + p_grayBuffer->pan(dx, dy); + panQueued |= p_grayBuffer->working(); + bufferXYRect = p_grayBuffer->bufferXYRect(); + } + + if (p_redBuffer) { + p_redBuffer->pan(dx, dy); + panQueued |= p_redBuffer->working(); + bufferXYRect = p_redBuffer->bufferXYRect(); + } + + if (p_greenBuffer) { + p_greenBuffer->pan(dx, dy); + panQueued |= p_greenBuffer->working(); + } + + if (p_blueBuffer) { + p_blueBuffer->pan(dx, dy); + panQueued |= p_blueBuffer->working(); + } + + p_updatingBuffers = false; + + // shift the pixmap by x,y if the viewport buffer didn't do it immediately + if (panQueued) { + shiftPixmap(dx, dy); + } + else { + // Need to do this to clear area outside of cube + p_pixmapPaintRects->clear(); + paintPixmap(); + } + + viewport()->update(); + emit screenPixelsChanged(); + } + + + /** + * This restarts the progress bar. Does nothing if already + * loading. + */ + void CubeViewport::enableProgress() { + if (!p_progressTimer->isActive()) { + p_progressTimer->start(); + + emit progressChanged(0); + } + } + + + /** + * Change the caption on the viewport title bar + * + */ + void CubeViewport::setCaption() { + string cubeFilename = p_cube->Filename(); + QString str = QFileInfo(cubeFilename.c_str()).fileName(); + str += QString(" @ "); + str += QString::number(p_scale * 100.0); + str += QString("% "); + + if (p_color) { + str += QString("(RGB = "); + str += QString::number(p_red.band); + str += QString(","); + str += QString::number(p_green.band); + str += QString(","); + str += QString::number(p_blue.band); + str += QString(")"); + } + else { + str += QString("(Gray = "); + str += QString::number(p_gray.band); + str += QString(")"); + } + + //If changes have been made make sure to add '*' to the end + if (p_saveEnabled) { + str += "*"; + } + + parentWidget()->setWindowTitle(str); + emit windowTitleChanged(); + } + + + /** + * The viewport is being resized + * + * + * @param e + */ + void CubeViewport::resizeEvent(QResizeEvent *e) { + p_paintPixmap = false; + + // Tell the buffers to update their coefficients to reinitialize + // and have their immediate paint events happen afterwards. Should not + // happen, but if buffers have actions complete immediately and call + // bufferUpdated. We don't want to have bufferUpdated ever when all + // buffers don't have their appropriate actions queued. It can't succeed. + p_updatingBuffers = true; + if (p_grayBuffer) + p_grayBuffer->resizedViewport(); + if (p_redBuffer) + p_redBuffer->resizedViewport(); + if (p_greenBuffer) + p_greenBuffer->resizedViewport(); + if (p_blueBuffer) + p_blueBuffer->resizedViewport(); + p_updatingBuffers = false; + + paintPixmapRects(); + + // Change the size of the image and pixmap + if (p_image) { + delete p_image; + p_image = NULL; + } + + p_image = new QImage(viewport()->size(), QImage::Format_RGB32); + p_pixmap = QPixmap(viewport()->size()); + + p_paintPixmap = true; + + // Fixup the scroll bars + updateScrollBars(horizontalScrollBar()->value(), + verticalScrollBar()->value()); + + p_viewportWhatsThisText = + "

    Viewport Dimensions: \ +

    Samples = " + + QString::number(viewport()->width()) + "
    " + + "Lines = " + + QString::number(viewport()->height()) + "

    "; + + // Repaint the pixmap + paintPixmap(); + + // Repaint the internal viewport and scroll bars + viewport()->update(); + } + + + /** + * Repaint the viewport + * + * @param e [in] (QPaintEvent *) event + * + * @internal + * + * @history 2007-04-30 Tracie Sucharski - Add the QPainter to the call to + * Tool::paintViewport. + */ + void CubeViewport::paintEvent(QPaintEvent *e) { + if (!p_cubeShown || !viewport()->isVisible()) + return; + } + + + /** + * This method is called by ViewportBuffer upon successful + * completion of all operations and gives the appropriate rect + * to be repainted. This is intended to update the screen once + * all data is done and ready to be displayed. + * + * @param rect Area to update screen + */ + void CubeViewport::bufferUpdated(QRect rect) { + paintPixmap(rect); + + // Don't repaint from buffer updates if any buffers are working... + // This set of statements fixes a flash of black when in RGB mode + // and a pan (or other operation?) completes. What would happen is + // the first would reset to black then other buffers still working so + // not restored to DN values. + if (p_grayBuffer && p_grayBuffer->working()) + return; + if (p_redBuffer && p_redBuffer->working()) + return; + if (p_greenBuffer && p_greenBuffer->working()) + return; + if (p_blueBuffer && p_blueBuffer->working()) + return; + + viewport()->repaint(rect); + } + +//! Paint the whole pixmap + void CubeViewport::paintPixmap() { + QRect rect(0, 0, p_image->width(), p_image->height()); + paintPixmap(rect); + } + + + /** + * Paint a region of the pixmap + * + * + * @param rect + */ + void CubeViewport::paintPixmap(QRect rect) { + if (!p_paintPixmap) + return; + + if (p_updatingBuffers) { + p_pixmapPaintRects->push_back(new QRect(rect)); + return; + } + + if (p_pixmap.isNull()) + return; + + QPainter p(&p_pixmap); + + p.fillRect(rect, QBrush(p_bgColor)); + + QRect dataArea; + + if (p_grayBuffer && p_grayBuffer->enabled()) { + if (p_grayBuffer->working()) + return; + + dataArea = QRect(p_grayBuffer->bufferXYRect().intersected(rect)); + + for (int y = dataArea.top(); + !dataArea.isNull() && y <= dataArea.bottom(); + y++) { + const vector< double > & line = + p_grayBuffer->getLine(y - p_grayBuffer->bufferXYRect().top()); + + if (line.size() == 0) + break; + + QRgb *rgb = (QRgb *) p_image->scanLine(y); + + for (int x = dataArea.left(); x <= dataArea.right(); x++) { + int bufferLeft = p_grayBuffer->bufferXYRect().left(); + int bufferX = x - bufferLeft; + + if (bufferX >= (int)line.size()) + break; + + if (bufferX < 0) { + throw iException::Message(iException::Programmer, "bufferX < 0", + _FILEINFO_); + } + + if (x >= p_image->width()) { + throw iException::Message(iException::Programmer, "bufferX too big", + _FILEINFO_); + } + + double bufferVal = line.at(bufferX); + + // This is still RGB; the pairs are identical but the boundary + // conditions are different. Display saturations cause this. + int redPix = (int)(p_red.getStretch().Map(bufferVal) + 0.5); + int greenPix = (int)(p_green.getStretch().Map(bufferVal) + 0.5); + int bluePix = (int)(p_blue.getStretch().Map(bufferVal) + 0.5); + rgb[x] = qRgb(redPix, greenPix, bluePix); + } + } + } + else { + if (p_redBuffer && p_redBuffer->enabled()) { + if (p_redBuffer->working() || p_greenBuffer->working() || + p_blueBuffer->working()) { + return; + } + + + if ((p_greenBuffer->bufferXYRect().top() != + p_redBuffer->bufferXYRect().top()) || + (p_greenBuffer->bufferXYRect().top() != + p_blueBuffer->bufferXYRect().top())) { + throw iException::Message(iException::Programmer, + "Buffer rects mismatched", _FILEINFO_); + } + + if ((p_greenBuffer->bufferXYRect().left() != + p_redBuffer->bufferXYRect().left()) || + (p_greenBuffer->bufferXYRect().left() != + p_blueBuffer->bufferXYRect().left())) { + throw iException::Message(iException::Programmer, + "Buffer rects mismatched", _FILEINFO_); + } + + dataArea = QRect(p_redBuffer->bufferXYRect().intersected(rect)); + + for (int y = dataArea.top(); + !dataArea.isNull() && y <= dataArea.bottom(); + y++) { + int bufferLine = y - p_redBuffer->bufferXYRect().top(); + + const vector &redLine = p_redBuffer->getLine(bufferLine); + const vector &greenLine = p_greenBuffer->getLine(bufferLine); + const vector &blueLine = p_blueBuffer->getLine(bufferLine); + + if ((int)redLine.size() < dataArea.width() || + (int)greenLine.size() < dataArea.width() || + (int)blueLine.size() < dataArea.width()) { + throw iException::Message(iException::Programmer, + "Empty buffer line", _FILEINFO_); + } + + QRgb *rgb = (QRgb *) p_image->scanLine(y); + + for (int x = dataArea.left(); x <= dataArea.right(); x++) { + int redPix = (int)(p_red.getStretch().Map(redLine[ x - p_redBuffer->bufferXYRect().left()]) + 0.5); + int greenPix = (int)(p_green.getStretch().Map(greenLine[ x - p_greenBuffer->bufferXYRect().left()]) + 0.5); + int bluePix = (int)(p_blue.getStretch().Map(blueLine[ x - p_blueBuffer->bufferXYRect().left()]) + 0.5); + + rgb[x] = qRgb(redPix, greenPix, bluePix); + } + } + } + } + + if (!dataArea.isNull()) + p.drawImage(dataArea.topLeft(), *p_image, dataArea); + + // Change whats this info + updateWhatsThis(); + } + + + /** + * Shifts the pixels on the pixmap without reading new data. + * + * @param dx + * @param dy + */ + void CubeViewport::shiftPixmap(int dx, int dy) { + if (!p_paintPixmap || !p_pixmap) + return; + + // Prep to scroll the pixmap + int drawStartX = dx; + int pixmapStartX = 0; + if (drawStartX < 0) { + drawStartX = 0; + pixmapStartX = -dx; + } + + int drawStartY = dy; + int pixmapStartY = 0; + if (dy < 0) { + drawStartY = 0; + pixmapStartY = -dy; + } + + // Ok we can shift the pixmap and filling + int pixmapDrawWidth = p_pixmap.width() - pixmapStartX + 1; + int pixmapDrawHeight = p_pixmap.height() - pixmapStartY + 1; + QRect rect(0, 0, p_pixmap.width(), p_pixmap.height()); + QPixmap pixmapCopy = p_pixmap.copy(); + + QPainter painter(&p_pixmap); + painter.fillRect(rect, QBrush(p_bgColor)); + painter.drawPixmap(drawStartX, drawStartY, + pixmapCopy, + pixmapStartX, pixmapStartY, + pixmapDrawWidth, pixmapDrawHeight); + painter.end(); + + // Now fill in the left or right side + QRect xFillRect; + QRect yFillRect; + + if (dx > 0) { + xFillRect = QRect(QPoint(0, 0), + QPoint(dx, p_pixmap.height())); + } + else { + if (dx < 0) + xFillRect = QRect(QPoint(p_pixmap.width() + dx, 0), + QPoint(p_pixmap.width(), p_pixmap.height())); + } + + // Fill in the top or bottom side + if (dy > 0) { + yFillRect = QRect(QPoint(0, 0), + QPoint(p_pixmap.width(), dy)); + } + else { + if (dy < 0) + yFillRect = QRect(QPoint(0, p_pixmap.height() + dy), + QPoint(p_pixmap.width(), p_pixmap.height())); + } + + if (dx != 0) { + paintPixmap(xFillRect); + } + + if (dy != 0) { + paintPixmap(yFillRect); + } + + viewport()->update(); + } + + + /** + * Update the What's This text. + * + */ + void CubeViewport::updateWhatsThis() { + double sl, ss; + viewportToCube(0, 0, ss, sl); + if (ss < 1.0) + ss = 1.0; + if (sl < 1.0) + sl = 1.0; + + double el, es; + viewportToCube(viewport()->width() - 1, viewport()->height() - 1, es, el); + if (es > cubeSamples()) + es = cubeSamples(); + if (el > cubeLines()) + el = cubeLines(); + + QString area = + "

    Visible Cube Area:

    \ + Samples = " + QString::number(int(ss + 0.5)) + "-" + + QString::number(int(es + 0.5)) + "
    \ + Lines = " + QString::number(int(sl + 0.5)) + "-" + + QString::number(int(el + 0.5)) + "

    "; + viewport()->setWhatsThis(p_whatsThisText + + area + + p_cubeWhatsThisText + + p_viewportWhatsThisText); + } + + /** + * Return the red pixel value at a sample/line + * + * + * @param sample + * @param line + * + * @return double + */ + double CubeViewport::redPixel(int sample, int line) { + p_pntBrick->SetBasePosition(sample, line, p_red.band); + p_cube->Read(*p_pntBrick); + return (*p_pntBrick)[0]; + } + + + /** + * Return the green pixel value at a sample/line + * + * + * @param sample + * @param line + * + * @return double + */ + double CubeViewport::greenPixel(int sample, int line) { + p_pntBrick->SetBasePosition(sample, line, p_green.band); + p_cube->Read(*p_pntBrick); + return (*p_pntBrick)[0]; + } + + + /** + * Return the blue pixel value at a sample/line + * + * + * @param sample + * @param line + * + * @return double + */ + double CubeViewport::bluePixel(int sample, int line) { + p_pntBrick->SetBasePosition(sample, line, p_blue.band); + p_cube->Read(*p_pntBrick); + return (*p_pntBrick)[0]; + } + + + /** + * Return the gray pixel value at a sample/line + * + * + * @param sample + * @param line + * + * @return double + */ + double CubeViewport::grayPixel(int sample, int line) { + p_pntBrick->SetBasePosition(sample, line, p_gray.band); + p_cube->Read(*p_pntBrick); + return (*p_pntBrick)[0]; + } + + + //! Return the gray band stretch + Stretch CubeViewport::grayStretch() const { + return p_gray.getStretch(); + } + + + //! Return the red band stretch + Isis::Stretch CubeViewport::redStretch() const { + return p_red.getStretch(); + }; + + + //! Return the green band stretch + Isis::Stretch CubeViewport::greenStretch() const { + return p_green.getStretch(); + }; + + + //! Return the blue band stretch + Isis::Stretch CubeViewport::blueStretch() const { + return p_blue.getStretch(); + }; + + + /** + * Event filter to watch for mouse events on viewport + * + * + * @param o + * @param e + * + * @return bool + */ + bool CubeViewport::eventFilter(QObject *o, QEvent *e) { + // Handle standard mouse tracking on the viewport + if (o == viewport()) { + switch (e->type()) { + case QEvent::Enter: { + viewport()->setMouseTracking(true); + emit mouseEnter(); + return true; + } + + case QEvent::MouseMove: { + QMouseEvent *m = (QMouseEvent *) e; + emit mouseMove(m->pos()); + return true; + } + + case QEvent::Leave: { + viewport()->setMouseTracking(false); + emit mouseLeave(); + return true; + } + + case QEvent::MouseButtonPress: { + QMouseEvent *m = (QMouseEvent *) e; + emit mouseButtonPress(m->pos(), + (Qt::MouseButton)(m->button() + m->modifiers())); + return true; + } + + case QEvent::MouseButtonRelease: { + QMouseEvent *m = (QMouseEvent *) e; + emit mouseButtonRelease(m->pos(), + (Qt::MouseButton)(m->button() + m->modifiers())); + return true; + } + + case QEvent::MouseButtonDblClick: { + QMouseEvent *m = (QMouseEvent *) e; + emit mouseDoubleClick(m->pos()); + return true; + } + + default: { + return false; + } + } + } + else { + return QAbstractScrollArea::eventFilter(o, e); + } + } + + + /** + * Process arrow keystrokes on cube + * + * + * @param e + */ + void CubeViewport::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Plus) { + double scale = p_scale * 2.0; + setScale(scale); + e->accept(); + } + else if (e->key() == Qt::Key_Minus) { + double scale = p_scale / 2.0; + setScale(scale); + e->accept(); + } + else if (e->key() == Qt::Key_Up) { + moveCursor(0, -1); + e->accept(); + } + else if (e->key() == Qt::Key_Down) { + moveCursor(0, 1); + e->accept(); + } + else if (e->key() == Qt::Key_Left) { + moveCursor(-1, 0); + e->accept(); + } + else if (e->key() == Qt::Key_Right) { + moveCursor(1, 0); + e->accept(); + } + else { + QAbstractScrollArea::keyPressEvent(e); + } + } + + + /** + * Is cursor inside viewport + * + * + * @return bool + */ + bool CubeViewport::cursorInside() const { + QPoint g = QCursor::pos(); + QPoint v = viewport()->mapFromGlobal(g); + if (v.x() < 0) + return false; + if (v.y() < 0) + return false; + if (v.x() >= viewport()->width()) + return false; + if (v.y() >= viewport()->height()) + return false; + return true; + } + + + /** + * Return the cursor position in the viewport + * + * + * @return QPoint + */ + QPoint CubeViewport::cursorPosition() const { + QPoint g = QCursor::pos(); + return viewport()->mapFromGlobal(g); + } + + + /** + * Move the cursor by x,y if possible + * + * + * @param x + * @param y + */ + void CubeViewport::moveCursor(int x, int y) { + QPoint g = QCursor::pos(); + g += QPoint(x, y); + QPoint v = viewport()->mapFromGlobal(g); + if (v.x() < 0) + return; + if (v.y() < 0) + return; + if (v.x() >= viewport()->width()) + return; + if (v.y() >= viewport()->height()) + return; + QCursor::setPos(g); + } + + + /** + * Set the cursor position to x/y in the viewport + * + * + * @param x + * @param y + */ + void CubeViewport::setCursorPosition(int x, int y) { + QPoint g(x, y); + QPoint v = viewport()->mapToGlobal(g); + QCursor::setPos(v); + } + + + /** + * Update the scroll bar + * + * + * @param x + * @param y + */ + void CubeViewport::updateScrollBars(int x, int y) { + viewport()->blockSignals(true); + + verticalScrollBar()->setValue(1); + verticalScrollBar()->setMinimum(1); + verticalScrollBar()->setMaximum((int)(ceil(cubeLines() * p_scale) + 0.5)); + verticalScrollBar()->setPageStep(viewport()->height() / 2); + + horizontalScrollBar()->setValue(1); + horizontalScrollBar()->setMinimum(1); + horizontalScrollBar()->setMaximum((int)(ceil(cubeSamples() * p_scale) + 0.5)); + horizontalScrollBar()->setPageStep(viewport()->width() / 2); + + if (horizontalScrollBar()->value() != x || verticalScrollBar()->value() != y) { + horizontalScrollBar()->setValue(x); + verticalScrollBar()->setValue(y); + emit scaleChanged(); + } + + QApplication::sendPostedEvents(viewport(), 0); + viewport()->blockSignals(false); + } + + + /** + * View cube as gray + * + * + * @param band + */ + void CubeViewport::viewGray(int band) { + p_gray.band = band; + p_color = false; + setCaption(); + + if (!p_grayBuffer) + p_grayBuffer = new ViewportBuffer(this, p_cubeData, + p_cubeId); + + if (p_redBuffer) + delete p_redBuffer; + p_redBuffer = NULL; + + if (p_greenBuffer) + delete p_greenBuffer; + p_greenBuffer = NULL; + + if (p_blueBuffer) + delete p_blueBuffer; + p_blueBuffer = NULL; + + if (p_grayBuffer->getBand() != band) { + int oldBand = p_grayBuffer->getBand(); + + if (oldBand >= 0) { + if ((*p_knownStretches)[oldBand - 1]) { + delete(*p_knownStretches)[oldBand - 1]; + } + + (*p_knownStretches)[oldBand - 1] = new Stretch(p_gray.getStretch()); + } + + p_grayBuffer->setBand(band); + p_gray.band = band; + + if ((*p_knownStretches)[band - 1]) { + stretchGray(*(*p_knownStretches)[band - 1]); + } + else { + p_grayBuffer->addStretchAction(); + } + } + + + if (p_camera) { + p_camera->SetBand(band); + } + + viewport()->repaint(); + } + + void CubeViewport::forgetStretches() { + for (int stretch = 0; stretch < p_knownStretches->size(); stretch++) { + if ((*p_knownStretches)[stretch]) { + delete(*p_knownStretches)[stretch]; + (*p_knownStretches)[stretch] = NULL; + } + } + } + + + void CubeViewport::setAllBandStretches(Isis::Stretch stretch) { + for (int index = 0; index < p_knownStretches->size(); index ++) { + if ((*p_knownStretches)[index]) { + delete(*p_knownStretches)[index]; + } + + (*p_knownStretches)[index] = new Stretch(stretch); + } + } + + + /** + * View cube as color + * + * + * @param rband + * @param gband + * @param bband + */ + void CubeViewport::viewRGB(int rband, int gband, int bband) { + p_red.band = rband; + p_green.band = gband; + p_blue.band = bband; + p_color = true; + setCaption(); + + if (!p_redBuffer) { + p_redBuffer = new ViewportBuffer(this, p_cubeData, p_cubeId); + } + + if (!p_greenBuffer) { + p_greenBuffer = new ViewportBuffer(this, p_cubeData, p_cubeId); + } + + if (!p_blueBuffer) { + p_blueBuffer = new ViewportBuffer(this, p_cubeData, p_cubeId); + } + + if (p_redBuffer->getBand() != rband) { + int oldBand = p_redBuffer->getBand(); + + // Remember current stretch for future band changes + if (oldBand >= 0) { + if ((*p_knownStretches)[oldBand - 1]) { + delete(*p_knownStretches)[oldBand - 1]; + } + + (*p_knownStretches)[oldBand - 1] = new Stretch(p_red.getStretch()); + } + + p_redBuffer->setBand(rband); + p_red.band = rband; + + if ((*p_knownStretches)[rband - 1]) { + p_red.setStretch(*(*p_knownStretches)[rband - 1]); + } + else { + p_redBuffer->addStretchAction(); + } + } + + if (p_greenBuffer->getBand() != gband) { + int oldBand = p_greenBuffer->getBand(); + + // Remember current stretch for future band changes + if (oldBand >= 0) { + if ((*p_knownStretches)[oldBand - 1]) { + delete(*p_knownStretches)[oldBand - 1]; + } + + (*p_knownStretches)[oldBand - 1] = new Stretch(p_green.getStretch()); + } + + p_greenBuffer->setBand(gband); + p_green.band = gband; + + if ((*p_knownStretches)[gband - 1]) { + p_green.setStretch(*(*p_knownStretches)[gband - 1]); + } + else { + p_greenBuffer->addStretchAction(); + } + } + + if (p_blueBuffer->getBand() != bband) { + int oldBand = p_blueBuffer->getBand(); + + // Remember current stretch for future band changes + if (oldBand >= 0) { + if ((*p_knownStretches)[oldBand - 1]) { + delete(*p_knownStretches)[oldBand - 1]; + } + + (*p_knownStretches)[oldBand - 1] = new Stretch(p_blue.getStretch()); + } + + p_blueBuffer->setBand(bband); + p_blue.band = bband; + + if ((*p_knownStretches)[bband - 1]) { + p_blue.setStretch(*(*p_knownStretches)[bband - 1]); + } + else { + p_blueBuffer->addStretchAction(); + } + } + + if (p_grayBuffer) + delete p_grayBuffer; + p_grayBuffer = NULL; + + if (p_camera) { + p_camera->SetBand(rband); + } + } + + + /** + * Apply stretch pairs to gray band + * + * + * @param string + */ + void CubeViewport::stretchGray(const QString &string) { + Stretch stretch; + stretch.Parse(string.toStdString()); + stretchGray(stretch); + } + + + /** + * Apply stretch pairs to red bands + * + * @param stretch + */ + void CubeViewport::stretchRed(const QString &string) { + Stretch stretch; + stretch.Parse(string.toStdString()); + stretchRed(stretch); + } + + + /** + * Apply stretch pairs to green bands + * + * @param stretch + */ + void CubeViewport::stretchGreen(const QString &string) { + Stretch stretch; + stretch.Parse(string.toStdString()); + stretchGreen(stretch); + } + + + /** + * Apply stretch pairs to blue bands + * + * @param stretch + */ + void CubeViewport::stretchBlue(const QString &string) { + Stretch stretch; + stretch.Parse(string.toStdString()); + stretchBlue(stretch); + } + + + /**List p + * This stretches to the global stretch + */ + void CubeViewport::stretchKnownGlobal() { + if (!p_globalStretches) + return; + + if (isGray()) { + if ((*p_globalStretches)[grayBand() - 1]) { + stretchGray(*(*p_globalStretches)[grayBand() - 1]); + } + } + else { + if ((*p_globalStretches)[redBand() - 1]) { + stretchRed(*(*p_globalStretches)[redBand() - 1]); + } + + if ((*p_globalStretches)[greenBand() - 1]) { + stretchGreen(*(*p_globalStretches)[greenBand() - 1]); + } + + if ((*p_globalStretches)[blueBand() - 1]) { + stretchBlue(*(*p_globalStretches)[blueBand() - 1]); + } + } + } + + + /** + * Sets the stretch for gray mode + * + * @param stretch + */ + void CubeViewport::stretchGray(const Isis::Stretch &stretch) { + p_gray.setStretch(stretch); + p_red.setStretch(stretch); + p_green.setStretch(stretch); + p_blue.setStretch(stretch); + + // Assume first stretch is always the global stretch (and it should be) + if ((*p_globalStretches)[grayBand() - 1] == NULL) { + (*p_globalStretches)[grayBand() - 1] = new Stretch(p_gray.getStretch()); + } + + paintPixmap(); + viewport()->update(); + } + + + /** + * Sets the stretch for red in rgb mode + * + * @param stretch + */ + void CubeViewport::stretchRed(const Isis::Stretch &stretch) { + p_red.setStretch(stretch); + + // Assume first stretch is always the global stretch (and it should be) + if ((*p_globalStretches)[redBand() - 1] == NULL) { + (*p_globalStretches)[redBand() - 1] = new Stretch(p_red.getStretch()); + } + + paintPixmap(); + viewport()->update(); + } + + + /** + * Sets the stretch for green in rgb mode + * + * @param stretch + */ + void CubeViewport::stretchGreen(const Isis::Stretch &stretch) { + p_green.setStretch(stretch); + + // Assume first stretch is always the global stretch (and it should be) + if ((*p_globalStretches)[greenBand() - 1] == NULL) { + (*p_globalStretches)[greenBand() - 1] = new Stretch(p_green.getStretch()); + } + + paintPixmap(); + viewport()->update(); + } + + + /** + * Sets the stretch for blue in rgb mode + * + * @param stretch + */ + void CubeViewport::stretchBlue(const Isis::Stretch &stretch) { + p_blue.setStretch(stretch); + + // Assume first stretch is always the global stretch (and it should be) + if ((*p_globalStretches)[blueBand() - 1] == NULL) { + (*p_globalStretches)[blueBand() - 1] = new Stretch(p_blue.getStretch()); + } + + paintPixmap(); + viewport()->update(); + } + + + /** + * Determine the scale that causes the full cube to fit in the viewport. + * + * @return The scale + * + * @internal + */ + double CubeViewport::fitScale() const { + double sampScale = (double) viewport()->width() / (double) cubeSamples(); + double lineScale = (double) viewport()->height() / (double) cubeLines(); + double scale = sampScale < lineScale ? sampScale : lineScale; +// scale = floor(scale * 100.0) / 100.0; + return scale; + } + + + /** + * Determine the scale of cube in the width to fit in the viewport + * + * @return The scale for width + * + */ + double CubeViewport::fitScaleWidth() const { + double scale = (double) viewport()->width() / (double) cubeSamples(); + +// scale = floor(scale * 100.0) / 100.0; + return scale; + } + + /** + * Determine the scale of cube in heighth to fit in the viewport + * + * @return The scale for heighth + * + */ + double CubeViewport::fitScaleHeight() const { + double scale = (double) viewport()->height() / (double) cubeLines(); + +// scale = floor(scale * 100.0) / 100.0; + return scale; + } + + /** + * Cube changed, repaint given area + * + * @param[in] cubeRect (QRect rect) Rectange containing portion of cube + * (sample/line) that changed. + * + */ + void CubeViewport::cubeContentsChanged(QRect cubeRect) { + double ss, sl, es, el; + ss = (double)(cubeRect.left()) - 1.; + sl = (double)(cubeRect.top()) - 1.; + es = (double)(cubeRect.right()) + 1.; + el = (double)(cubeRect.bottom()) + 1.; + if (ss < 1) + ss = 0.5; + if (sl < 1) + sl = 0.5; + if (es > cube()->Samples()) + es = cube()->Samples() + 0.5; + if (el > cube()->Lines()) + el = cube()->Lines() + 0.5; + + int sx, sy, ex, ey; + + cubeToViewport(ss, sl, sx, sy); + cubeToViewport(es, el, ex, ey); + if (sx < 0) + sx = 0; + if (sy < 0) + sy = 0; + if (ex > viewport()->width()) + ex = viewport()->width(); + if (ey > viewport()->height()) + ey = viewport()->height(); + QRect vpRect(sx, sy, ex - sx + 1, ey - sy + 1); + + p_updatingBuffers = true; + if (p_grayBuffer) + p_grayBuffer->fillBuffer(vpRect); + if (p_redBuffer) + p_redBuffer->fillBuffer(vpRect); + if (p_greenBuffer) + p_greenBuffer->fillBuffer(vpRect); + if (p_blueBuffer) + p_blueBuffer->fillBuffer(vpRect); + p_updatingBuffers = false; + + paintPixmapRects(); + } + + + /** + * Allows users to change the cursor type on the viewport. + * + * + * @param cursor + */ + void CubeViewport::changeCursor(QCursor cursor) { + viewport()->setCursor(cursor); + } + + + CubeViewport::BandInfo::BandInfo() : band(1), stretch(NULL) { + stretch = new Stretch; + stretch->SetNull(0.0); + stretch->SetLis(0.0); + stretch->SetLrs(0.0); + stretch->SetHis(255.0); + stretch->SetHrs(255.0); + stretch->SetMinimum(0.0); + stretch->SetMaximum(255.0); + }; + + + CubeViewport::BandInfo::BandInfo(const CubeViewport::BandInfo &other) : + band(other.band) { + stretch = NULL; + stretch = new Stretch(*other.stretch); + } + + + CubeViewport::BandInfo::~BandInfo() { + if (stretch) { + delete stretch; + stretch = NULL; + } + } + + + Stretch CubeViewport::BandInfo::getStretch() const { + ASSERT_PTR(stretch); + + return *stretch; + } + + + void CubeViewport::BandInfo::setStretch(const Stretch &newStretch) { + *stretch = newStretch; + } + + + const CubeViewport::BandInfo &CubeViewport::BandInfo::operator=( + CubeViewport::BandInfo other) { + ASSERT_PTR(other.stretch); + + stretch = NULL; + stretch = new Stretch; + *stretch = *other.stretch; + band = other.band; + + return *this; + } + +} diff --git a/isis/src/qisis/objs/CubeViewport/CubeViewport.h b/isis/src/qisis/objs/CubeViewport/CubeViewport.h new file mode 100644 index 0000000000000000000000000000000000000000..58ce9fdbb594d6961b8641b87e078c258e25b659 --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/CubeViewport.h @@ -0,0 +1,448 @@ +#ifndef CubeViewport_h +#define CubeViewport_h + +/** + * @file + * $Date: 2010/06/30 03:38:12 $ + * $Revision: 1.30 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +// The only includes allowed in this file are the direct parents of this class! +#include +// There are absolutely no exceptions to this. + + +class QPaintEvent; + +namespace Isis { + class Brick; + class Camera; + class Cube; + class CubeDataThread; + class Projection; + class Stretch; + class UniversalGroundMap; +} + +namespace Qisis { + class ViewportBuffer; + + + /** + * @brief Widget to display Isis cubes for qt apps + * + * @ingroup Visualization Tools + * + * @author ??? Jeff Anderson + * + * @internal + * @history 2007-01-30 Tracie Sucharski, Add information + * message if spice not found. + * @history 2007-02-07 Tracie Sucharski, Remove error message, decided it + * was more of a hassle to click ok when displaying + * many images without spice. + * @history 2007-03-20 Tracie Sucharski, Add fitScaleMinDimension, + * fitScaleWidth and fitScaleHeight methods. Change + * cursor to wait cursor in paintPixmap. + * @history 2007-04-13 Tracie Sucharski, Remove fitScaleMinDimension, turns + * out it was not needed. + * @history 2007-09-11 Steven Lambright, Added double click signal + * @history 2007-12-11 Steven Lambright, Added 1x1xn cube auto stretch support + * @history 2008-06-19 Noah Hilt, Added a close event for saving and discarding + * changes and a method to set the cube. + * @history 2008-12-04 Jeannie Walldren, Fixed a bug in + * computeStretch() method for comparing precision + * difference on 32 bit Linux system. Added try/catch + * in showCube() to set p_cubeShown = false if this + * fails. + * @history 2009-03-09 Steven Lambright - Changed the way we do floating point + * math in autoStretch to work better in order to allow more cubes to + * open. + * @history 2009-03-27 Noah Hilt/Steven Lambright - Removed old rubber band + * methods and variables. Added new ViewportBuffer to read and store + * visible dn values in the viewport. + * @history 2009-10-23 Steven Lambright - Camera::SetBand is now called when + * switching the band being shown. + * @history 2010-04-08 Steven Lambright and Eric Hyer - + * Now supports ViewportBuffer using threaded cube I/O + * @history 2010-04-30 Steven Lambright - Bug fixes and better + * support for threaded cube I/O + * @history 2010-05-20 Steven Lambright - Added memory of global + * stretches + * @history 2010-05-24 Eric Hyer - Fixed bug where QPainter construction was + * being attempted with a potentially null pixmap + * @history 2010-06-26 Eric Hyer - Moved MDI specific code to new child class + * called MdiCubeViewport. Fixed many include mistakes. + */ + + class Tool; + + class CubeViewport : public QAbstractScrollArea { + Q_OBJECT + + + public: + CubeViewport(Isis::Cube *cube, QWidget *parent = 0); + virtual ~CubeViewport(); + + + class BandInfo { + public: + BandInfo(); + BandInfo(const BandInfo &other); + ~BandInfo(); + const BandInfo &operator=(BandInfo other); + Isis::Stretch getStretch() const; + void setStretch(const Isis::Stretch &newStretch); + int band; + private: + Isis::Stretch *stretch; + }; + + void setCube(Isis::Cube *cube); + int cubeSamples() const; + int cubeLines() const; + int cubeBands() const; + + //! Is the viewport shown in 3-band color + bool isColor() const { + return p_color; + }; + + //! Is the viewport shown in gray / b&w + bool isGray() const { + return !p_color; + }; + + //! Return the gray band currently viewed + int grayBand() const { + return p_gray.band; + }; + + //! Return the red band currently viewed + int redBand() const { + return p_red.band; + }; + + //! Return the green band currently viewed + int greenBand() const { + return p_green.band; + }; + + //! Return the blue band currently viewed + int blueBand() const { + return p_blue.band; + }; + + //! Return the scale + double scale() const { + return p_scale; + }; + + //! Return if the cube is visible + bool cubeShown() const { + return p_cubeShown; + }; + + void cubeContentsChanged(QRect rect); + + double fitScale() const; + double fitScaleWidth() const; + double fitScaleHeight() const; + + void viewportToCube(int x, int y, + double &sample, double &line) const; + void cubeToViewport(double sample, double line, + int &x, int &y) const; + void contentsToCube(int x, int y, + double &sample, double &line) const; + void cubeToContents(double sample, double line, + int &x, int &y) const; + + double redPixel(int sample, int line); + double greenPixel(int sample, int line); + double bluePixel(int sample, int line); + double grayPixel(int sample, int line); + + Isis::Stretch grayStretch() const; + Isis::Stretch redStretch() const; + Isis::Stretch greenStretch() const; + Isis::Stretch blueStretch() const; + + //! Return the cube associated with viewport + Isis::Cube *cube() const { + return p_cube; + }; + + //! Return the projection associated with cube (NULL implies none) + Isis::Projection *projection() const { + return p_projection; + }; + + //! Return the camera associated with the cube (NULL implies none) + Isis::Camera *camera() const { + return p_camera; + }; + + //! Return the universal ground map associated with the cube (NULL implies none) + Isis::UniversalGroundMap *universalGroundMap() const { + return p_groundMap; + }; + + void moveCursor(int x, int y); + bool cursorInside() const; + QPoint cursorPosition() const; + void setCursorPosition(int x, int y); + void setCaption(); + + /** + * Sets the background color + * + * @param color + */ + void setBackground(QColor color) { + p_bgColor = color; + } + + /** + * Returns the pixmap + * + * + * @return QPixmap + */ + QPixmap pixmap() { + return p_pixmap; + } + + /** + * Returns the gray viewport buffer (Will be NULL if in RGB mode.) + * + * + * @return ViewportBuffer* + */ + ViewportBuffer *grayBuffer() { + return p_grayBuffer; + } + + /** + * Returns the red viewport buffer (Will be NULL if in Gray mode.) + * + * + * @return ViewportBuffer* + */ + ViewportBuffer *redBuffer() { + return p_redBuffer; + } + + /** + * Returns the green viewport buffer (Will be NULL if in Gray mode.) + * + * + * @return ViewportBuffer* + */ + ViewportBuffer *greenBuffer() { + return p_greenBuffer; + } + + /** + * Returns the blue viewport buffer (Will be NULL if in Gray mode.) + * + * + * @return ViewportBuffer* + */ + ViewportBuffer *blueBuffer() { + return p_blueBuffer; + } + + void bufferUpdated(QRect rect); + + /** + * This is called by internal viewport buffers when a stretch + * action should be performed. The buffer passes itself as the + * argument. + * + * @param buffer + */ + virtual void restretch(ViewportBuffer *buffer) = 0; + void paintPixmap(); + + /** + * Resets all remembered stretches + */ + void forgetStretches(); + + /** + * Sets a stretch for all bands + * + * @param stretch + */ + void setAllBandStretches(Isis::Stretch stretch); + + + signals: + void viewportUpdated();//!< Emitted when viewport updated. + void mouseEnter();//!< Emitted when the mouse enters the viewport + void mouseMove(QPoint);//!< Emitted when the mouse moves. + void mouseLeave();//!< Emitted when the mouse leaves the viewport. + void mouseButtonPress(QPoint, Qt::MouseButton);//!< Emitted when mouse button pressed + void mouseButtonRelease(QPoint, Qt::MouseButton);//!< Emitted when mouse button released + void mouseDoubleClick(QPoint);//!< Emitted when double click happens + void windowTitleChanged();//!< Emitted when window title changes + void scaleChanged(); //!< Emitted when zoom factor changed just before the repaint event + void saveChanges(); //!< Emitted when changes should be saved + void discardChanges(); //!< Emitted when changes should be discarded + void screenPixelsChanged(); //!< Emitted when cube pixels that should be on the screen change + + /** + * Emitted with current progress (0 to 100) when working + */ + void progressChanged(int); + + /** + * Emitted when a brick is no longer needed, should only be sent + * to cube data thread + */ + void doneWithData(int, const Isis::Brick *); + + + public slots: + QSize sizeHint() const; + void setScale(double scale); + void setScale(double scale, double sample, double line); + void setScale(double scale, int x, int y); + void center(int x, int y); + void center(double sample, double line); + + virtual void viewRGB(int redBand, int greenBand, int blueBand); + virtual void viewGray(int band); + + void stretchGray(const QString &string); + void stretchRed(const QString &string); + void stretchGreen(const QString &string); + void stretchBlue(const QString &string); + + void stretchGray(const Isis::Stretch &stretch); + void stretchRed(const Isis::Stretch &stretch); + void stretchGreen(const Isis::Stretch &stretch); + void stretchBlue(const Isis::Stretch &stretch); + + void stretchKnownGlobal(); + + void cubeChanged(bool changed); + void showEvent(QShowEvent *); + + void scrollBy(int dx, int dy); + + void changeCursor(QCursor cursor); + + void onProgressTimer(); + void enableProgress(); + + + protected: + virtual void closeEvent(QCloseEvent *event); + void scrollContentsBy(int dx, int dy); + virtual void resizeEvent(QResizeEvent *e); + virtual bool eventFilter(QObject *o, QEvent *e); + virtual void keyPressEvent(QKeyEvent *e); + virtual void paintEvent(QPaintEvent *e); + + + + private slots: + void cubeDataChanged(int cubeId, const Isis::Brick *); + + + private: + + void paintPixmap(QRect rect); + void shiftPixmap(int dx, int dy); + + void updateScrollBars(int x, int y); + void paintPixmapRects(); + + //void computeStretch(Isis::Brick *brick, int band, + // int ssamp, int esamp, + // int sline, int eline, int linerate, + // Isis::Stretch &stretch); + + + + protected: // data + QPixmap p_pixmap;//!< The qpixmap. + + + + private: // data + ViewportBuffer *p_grayBuffer; //!< Viewport Buffer to manage gray band + ViewportBuffer *p_redBuffer; //!< Viewport Buffer to manage red band + ViewportBuffer *p_greenBuffer; //!< Viewport Buffer to manage green band + ViewportBuffer *p_blueBuffer; //!< Viewport Buffer to manage blue band + + QColor p_bgColor; //!< The color to paint the background of the viewport + + Isis::Cube *p_cube; //!< The cube associated with the viewport. + Isis::Camera *p_camera; //!< The camera from the cube. + Isis::Projection *p_projection; //!< The projection from the cube. + Isis::UniversalGroundMap *p_groundMap; //!< The universal ground map from the cube. + + //! Activated to update progress bar + QTimer *p_progressTimer; + + double p_scale;//!< The scale number. + + bool p_color;//!< Is the viewport in color? + BandInfo p_gray;//!< Gray band info + BandInfo p_red;//!< Red band info + BandInfo p_green;//!< Green band info + BandInfo p_blue;//!< Blue band info + + //! Stretches for each previously stretched band + QVector< Isis::Stretch * > * p_knownStretches; + + //! Global stretches for each stretched band + QVector< Isis::Stretch * > * p_globalStretches; + + Isis::Brick *p_redBrick; //!< Bricks for every color. + Isis::Brick *p_grnBrick; //!< Bricks for every color. + Isis::Brick *p_bluBrick; //!< Bricks for every color. + Isis::Brick *p_gryBrick; //!< Bricks for every color. + Isis::Brick *p_pntBrick; //!< Bricks for every color. + bool p_saveEnabled; //!< Has the cube changed? + bool p_cubeShown;//!< Is the cube visible? + QImage *p_image; //!< The qimage. + bool p_paintPixmap;//!< Paint the pixmap? + bool p_updatingBuffers; //!< Changing RGB and need to not repaint pixmap? + + QString p_whatsThisText;//!< The text for What's this. + QString p_cubeWhatsThisText;//!< The text for the cube's What's this. + QString p_viewportWhatsThisText;//!< The text for the viewport's what's this. + void updateWhatsThis(); + + //! A list of rects that the viewport buffers have requested painted + QList< QRect * > *p_pixmapPaintRects; + + Isis::CubeDataThread *p_cubeData; //!< Does all the cube I/O + int p_cubeId; //!< Cube ID given from cube data thread for I/O + + }; +} + +#endif diff --git a/isis/src/qisis/objs/CubeViewport/Makefile b/isis/src/qisis/objs/CubeViewport/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/CubeViewport/ViewportBuffer.cpp b/isis/src/qisis/objs/CubeViewport/ViewportBuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eade16f4218c8e05cdafd4583403e5b60ed238e1 --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/ViewportBuffer.cpp @@ -0,0 +1,1290 @@ +#include "IsisDebug.h" + +#include "ViewportBuffer.h" +#include "ViewportBufferAction.h" +#include "ViewportBufferStretch.h" +#include "ViewportBufferFill.h" +#include "ViewportBufferTransform.h" + +#include +#include +#include +#include + +#include "CubeDataThread.h" +#include "CubeViewport.h" +#include "SpecialPixel.h" +#include "PixelType.h" + + +#define round(x) ((x) > 0.0 ? (x) + 0.5 : (x) - 0.5) + + +using namespace std; +using namespace Isis; + + +namespace Qisis { + /** + * ViewportBuffer constructor. Viewport and Cube can not be null. + * Band is not initialized + * + * @param viewport viewport that will use the buffer + * @param cubeData cube to read from + * @param cubeId The identifier for the cube in the data thread + */ + ViewportBuffer::ViewportBuffer(CubeViewport *viewport, + Isis::CubeDataThread *cubeData, + int cubeId) { + p_dataThread = cubeData; + p_cubeId = cubeId; + + p_actions = 0; + + p_actions = new QQueue< ViewportBufferAction * >(); + p_viewport = viewport; + p_bufferInitialized = false; + p_band = -1; + p_enabled = true; + p_initialStretchDone = false; + p_viewportHeight = p_viewport->viewport()->height(); + p_oldViewportHeight = p_viewport->viewport()->height(); + p_vertScrollBarPos = p_viewport->verticalScrollBar()->value(); + p_oldVertScrollBarPos = p_viewport->verticalScrollBar()->value(); + + p_requestedFillArea = 0.0; + + connect(this, SIGNAL(ReadCube(int, int, int, int, int, int, void *)), + p_dataThread, SLOT(ReadCube(int, int, int, int, int, int, void *))); + + connect(p_dataThread, SIGNAL(ReadReady(void *, int, const Isis::Brick *)), + this, SLOT(DataReady(void *, int, const Isis::Brick *))); + + connect(this, SIGNAL(DoneWithData(int, const Isis::Brick *)), p_dataThread, + SLOT(DoneWithData(int, const Isis::Brick *))); + } + + /** + * Updates total buffer size on destruction. + * + */ + ViewportBuffer::~ViewportBuffer() { + disconnect(this, SIGNAL(ReadCube(int, int, int, int, int, int, void *)), + p_dataThread, SLOT(ReadCube(int, int, int, int, int, int, void *))); + + disconnect(p_dataThread, SIGNAL(ReadReady(void *, int, const Isis::Brick *)), + this, SLOT(DataReady(void *, int, const Isis::Brick *))); + + disconnect(this, SIGNAL(DoneWithData(int, const Isis::Brick *)), + p_dataThread, SLOT(DoneWithData(int, const Isis::Brick *))); + + p_dataThread = NULL; + + if(p_actions) { + while(!p_actions->empty()) { + ViewportBufferAction *action = p_actions->dequeue(); + if(action) { + delete action; + action = NULL; + } + } + delete p_actions; + p_actions = NULL; + } + + emptyBuffer(true); + } + + + /** + * This method will convert the rect to sample/line positions and read from + * the cube into the buffer. The rect is in viewport pixels. + * + * @param rect + */ + void ViewportBuffer::fillBuffer(QRect rect) { + if(p_band == -1) { + throw iException::Message(iException::Programmer, "invalid band", + _FILEINFO_); + } + + ViewportBufferFill *newFill = createViewportBufferFill( + rect.intersected(bufferXYRect()), false); + enqueueAction(newFill); + doQueuedActions(); + } + + + /** + * This method will convert the rect to sample/line positions and read from + * the cube into the buffer. The rect is in viewport pixels. + * + * @param rect + * @param data + */ + void ViewportBuffer::fillBuffer(QRect rect, const Isis::Brick *data) { + if(p_band == -1) { + throw iException::Message(iException::Programmer, "invalid band", + _FILEINFO_); + } + + ViewportBufferFill *fill = createViewportBufferFill(rect, false); + + while(fill->shouldRequestMore()) { + fill->incRequestPosition(); + fill->incReadPosition(); + + for(int x = rect.left(); x <= rect.right(); x ++) { + // Index into internal buffer is minus leftmost/topmost pixel + int xIndex = x - fill->getLeftmostPixelPosition(); + int yIndex = fill->getRequestPosition() - fill->getTopmostPixelPosition(); + + double samp = fill->viewportToSample(x); + double line = fill->viewportToLine(fill->getRequestPosition()); + + // Index into buffer is current sample - start sample + // *Brick indices are in units of cube pixels, not screen pixels + int brickIndex = data->Index((int)(samp + 0.5), (int)(line + 0.5), p_band); + + if(brickIndex < 0) { + p_buffer.at(yIndex).at(xIndex) = data->at(0); + } + else if(brickIndex >= data->size()) { + p_buffer.at(yIndex).at(xIndex) = data->at(data->size() - 1); + } + else { + if(yIndex < 0 || xIndex < 0 || yIndex >= (int) p_buffer.size() || + xIndex >= (int) p_buffer.at(yIndex).size()) { + throw iException::Message(iException::Programmer, + "index out of range", _FILEINFO_); + } + else { + p_buffer.at(yIndex).at(xIndex) = data->at(brickIndex); + } + } + } + } + } + + + /** + * This method is called when requested bricks become available. + * This processes the new cube data and requests more if + * necessary. + * + * @param requester + * @param cubeId + * @param brick + */ + void ViewportBuffer::DataReady(void *requester, int cubeId, + const Isis::Brick *brick) { + if(this != requester) + return; + + if(p_actions->empty()) { + throw iException::Message(iException::Programmer, "no actions", + _FILEINFO_); + } + + ViewportBufferAction *curAction = p_actions->head(); + + if(curAction->getActionType() != ViewportBufferAction::fill || + !curAction->started()) { + throw iException::Message(iException::Programmer, "not a fill action", + _FILEINFO_); + } + + ViewportBufferFill *fill = (ViewportBufferFill *) curAction; + + const QRect *rect = fill->getRect(); + + int y = fill->getReadPosition(); + + double samp, line; + + // Loop through x values of rect on screen that we want to fill + for(int x = rect->left(); x <= rect->right(); x++) { + // Index into internal buffer is minus leftmost/topmost pixel + int xIndex = x - fill->getLeftmostPixelPosition(); + int yIndex = y - fill->getTopmostPixelPosition(); + + samp = fill->viewportToSample(x); + line = fill->viewportToLine(y); + + // Index into buffer is current sample - start sample + // *Brick indices are in units of cube pixels, not screen pixels + int brickIndex = (int)(samp + 0.5) - brick->Sample(); + + if(brickIndex < 0) { + p_buffer.at(yIndex).at(xIndex) = brick->at(0); + } + else if(brickIndex >= brick->size()) { + p_buffer.at(yIndex).at(xIndex) = brick->at(brick->size() - 1); + } + else { + if(yIndex < 0 || xIndex < 0 || yIndex >= (int) p_buffer.size() || + xIndex >= (int) p_buffer.at(yIndex).size()) { + throw iException::Message(iException::Programmer, + "index out of range", _FILEINFO_); + } + else { + p_buffer.at(yIndex).at(xIndex) = brick->at(brickIndex); + } + } + } + fill->incReadPosition(); + + if(fill->shouldRequestMore()) { + requestCubeLine(fill); + } + else if(fill->doneReading()) { + delete fill; + fill = NULL; + p_actions->dequeue(); + doQueuedActions(); + } + + emit DoneWithData(cubeId, brick); + } + + + /** + * This enqueues the given action. Please use this and don't put + * actions directly into p_actions. Calling this method can be + * thought of as equivalent to calling + * "p_actions->push_back(action)" + * + * @param action + */ + void ViewportBuffer::enqueueAction(ViewportBufferAction *action) { + if(action->getActionType() == ViewportBufferAction::fill) { + QRect *fillRect = ((ViewportBufferFill *)action)->getRect(); + p_requestedFillArea += fillRect->width() * fillRect->height(); + } + + if(p_actions->empty()) { + p_viewport->enableProgress(); + } + + p_actions->enqueue(action); + } + + + /** + * Retrieves a line from the buffer. Line is relative to the top of the + * visible area of the cube in the viewport. + * + * @param line + * + * @return const vector & + */ + const vector &ViewportBuffer::getLine(int line) { + if(!p_bufferInitialized || !p_enabled) { + throw iException::Message(iException::Programmer, "no data", + _FILEINFO_); + } + + if(line < 0 || line >= (int)p_buffer.size()) { + throw iException::Message(iException::Programmer, + "Invalid call to getLine", _FILEINFO_); + } + + return p_buffer.at(line); + } + + + /** + * Retrieves the current bounding rect in viewport pixels of the visible cube + * area. + * + * + * @return QRect + */ + QRect ViewportBuffer::getXYBoundingRect() { + int startx, starty, endx, endy; + p_viewport->cubeToViewport(0.5, 0.5, startx, starty); + p_viewport->cubeToViewport(p_viewport->cubeSamples() + 0.5, + p_viewport->cubeLines() + 0.5, endx, endy); + + if(startx < 0) { + startx = 0; + } + + if(starty < 0) { + starty = 0; + } + + if(endx > p_viewport->viewport()->width()) { + endx = p_viewport->viewport()->width(); + } + + if(endy > p_viewport->viewport()->height()) { + endy = p_viewport->viewport()->height(); + } + + return QRect(startx, starty, endx - startx, endy - starty); + } + + + /** + * Method to see if the entire cube is in the buffer. + * + * + * @return bool + */ + bool ViewportBuffer::hasEntireCube() { + double sampTolerance = 0.05 * p_viewport->cubeSamples(); + double lineTolerance = 0.05 * p_viewport->cubeLines(); + + bool hasCube = true; + + hasCube &= !working(); + hasCube &= p_sampLineBoundingRect[rectLeft] <= (1 + sampTolerance); + hasCube &= p_sampLineBoundingRect[rectTop] <= (1 + lineTolerance); + hasCube &= p_sampLineBoundingRect[rectRight] >= (p_viewport->cubeSamples() - + sampTolerance); + hasCube &= p_sampLineBoundingRect[rectBottom] >= (p_viewport->cubeLines() - + lineTolerance); + return hasCube; + } + + + /** + * Retrieves the current bounding rect in sample/line coordinates of the + * visible cube area. + * + * + * @return QList + */ + QList ViewportBuffer::getSampLineBoundingRect() { + QRect xyRect = getXYBoundingRect(); + double ssamp, esamp, sline, eline; + p_viewport->viewportToCube(xyRect.left(), xyRect.top(), ssamp, sline); + p_viewport->viewportToCube(xyRect.right(), xyRect.bottom(), esamp, eline); + + QList boundingRect; + + boundingRect.insert(rectLeft, ssamp); + boundingRect.insert(rectTop, sline); + boundingRect.insert(rectRight, esamp); + boundingRect.insert(rectBottom, eline); + + return boundingRect; + } + + + /** + * Sets the old and new bounding rects. + * + */ + void ViewportBuffer::updateBoundingRects() { + p_oldXYBoundingRect = p_XYBoundingRect; + p_XYBoundingRect = getXYBoundingRect(); + + p_oldSampLineBoundingRect = p_sampLineBoundingRect; + p_sampLineBoundingRect = getSampLineBoundingRect(); + + p_oldViewportHeight = p_viewportHeight; + p_viewportHeight = p_viewport->viewport()->height(); + + p_oldVertScrollBarPos = p_vertScrollBarPos; + p_vertScrollBarPos = p_viewport->verticalScrollBar()->value(); + } + + + /** + * This method creates a fill action based on a rect and using + * new versus old Y values. The use of old Y values is so we can + * think of X and Y independently in complicated transforms - do + * X first (with old Y values), then do Y. This does not enqueue + * the created action. + * + * @param someRect + * @param useOldY + * + * @return ViewportBufferFill* + */ + ViewportBufferFill *ViewportBuffer::createViewportBufferFill( + QRect someRect, bool useOldY) { + QScrollBar *hsb = p_viewport->horizontalScrollBar(); + int xConstCoef = hsb->value(); + xConstCoef -= p_viewport->viewport()->width() / 2; + + // If panning over a full screen, it will try to create a fill rect that + // isn't actually valid. So, in the case of any bad fill rects we will + // fill everything. + if(!someRect.isValid()) { + throw iException::Message(iException::Programmer, + "Fill rect invalid", + _FILEINFO_); + } + + double xScale = p_viewport->scale(); + + int yConstCoef = 0; + + if(!useOldY) + yConstCoef = p_vertScrollBarPos - p_viewportHeight / 2; + else + yConstCoef = p_oldVertScrollBarPos - p_oldViewportHeight / 2; + + double yScale = xScale; + + QPoint topLeft; + + if(!useOldY) { + topLeft = p_XYBoundingRect.topLeft(); + } + else { + topLeft = QPoint(p_XYBoundingRect.left(), p_oldXYBoundingRect.top()); + } + + ViewportBufferFill *newFill = new ViewportBufferFill(someRect, xConstCoef, + xScale, yConstCoef, yScale, topLeft); + + return newFill; + } + + + /** + * This requests the next line in a fill action. + * + * @param fill + */ + void ViewportBuffer::requestCubeLine(ViewportBufferFill *fill) { + if(p_band == -1) { + throw iException::Message(iException::Programmer, "invalid band", + _FILEINFO_); + } + + // Prep to create minimal buffer(s) to read the cube + QRect &rect = *fill->getRect(); + + double ssamp = fill->viewportToSample(rect.left()); + + double esamp = fill->viewportToSample(rect.right()); + + int brickWidth = (int)(ceil(esamp) - floor(ssamp)) + 1; + + if(brickWidth <= 0) + return; + + double line = fill->viewportToLine(fill->getRequestPosition()); + int roundedSamp = (int)(ssamp + 0.5); + int roundedLine = (int)(line + 0.5); + + emit ReadCube(p_cubeId, roundedSamp, roundedLine, roundedSamp + brickWidth, + roundedLine, p_band, this); + + fill->incRequestPosition(); + } + + + /** + * This processes the next available action, or starts + * processing it, if possible. This method keeps the buffer + * alive until the actions queue is empty. + * + * Any time the actions queue is modified this method should be + * called, it doesn't hurt to call this too much. A side effect + * of not calling this is qview never completing a + * read/displaying new pixels. + */ + void ViewportBuffer::doQueuedActions() { + bool doNextAction = false; + + ViewportBufferAction *curAction = NULL; + + // if we aren't preserving data, and we don't still need the initial + // stretch (on startup), let's reset the buffer. + if(!reinitializeActionExists() && !actionsPreserveData() && + p_initialStretchDone) { + // Actions don't preserve data - call reinitialize! + reinitialize(); + } + + if(!working()) { + p_requestedFillArea = 0.0; + } + + if(!p_actions->empty()) { + curAction = p_actions->head(); + doNextAction = !curAction->started(); + } + + while(doNextAction) { + if(curAction->getActionType() == ViewportBufferAction::transform) { + doTransformAction((ViewportBufferTransform *) curAction); + } + else if(curAction->getActionType() == ViewportBufferAction::fill) { + startFillAction((ViewportBufferFill *) curAction); + } + else { + doStretchAction((ViewportBufferStretch *) curAction); + p_initialStretchDone = true; + } + + doNextAction = !p_actions->empty(); + + if(doNextAction) { + curAction = p_actions->head(); + doNextAction = !curAction->started(); + } + } + + if(p_actions->empty()) { + // Buffer Updated - Giving it BufferXYRect + p_viewport->bufferUpdated(bufferXYRect()); + } + } + + + /** + * Returns the viewport buffer's loading progress + * + * @return 0 to 1 where 1 is 100% + */ + double ViewportBuffer::currentProgress() { + if(!working()) + return 1.0; + if(p_requestedFillArea <= 0.0) + return 0.0; + + return 1.0 - totalUnfilledArea() / p_requestedFillArea; + } + + + /** + * This returns the amount of area in the queue that needs new + * cube data/will be filled by fill actions. + * + * @return double + */ + double ViewportBuffer::totalUnfilledArea() { + double totalFillArea = 0.0; + + // If at any time the total X or Y shift exceeds the buffer size, we aren't + // preserving data. Check to see if this is the case! + for(int actionIndex = 0; actionIndex < p_actions->size(); actionIndex ++) { + ViewportBufferAction *action = (*p_actions)[actionIndex]; + + if(action->getActionType() == ViewportBufferAction::fill) { + ViewportBufferFill *fill = (ViewportBufferFill *)action; + + QRect unfilledRect(*fill->getRect()); + unfilledRect.setTop(fill->getReadPosition()); + totalFillArea += unfilledRect.width() * unfilledRect.height(); + } + } + + return totalFillArea; + } + + + /** + * This returns true if any data currently in the buffer would be preserved if + * all of the queued actions are executed. + */ + bool ViewportBuffer::actionsPreserveData() { + int totalXShift = 0; + int totalYShift = 0; + + QRect currentBufferRect(bufferXYRect()); + + int bufferWidth = currentBufferRect.width(); + int bufferHeight = currentBufferRect.height(); + + // If at any time the total X or Y shift exceeds the buffer size, we aren't + // preserving data. Check to see if this is the case! + for(int actionIndex = 0; actionIndex < p_actions->size(); actionIndex ++) { + ViewportBufferAction *action = (*p_actions)[actionIndex]; + + if(action->getActionType() == ViewportBufferAction::transform) { + ViewportBufferTransform *transform = (ViewportBufferTransform *)action; + + if(transform->resizeFirst()) { + bufferWidth = transform->getBufferWidth(); + bufferHeight = transform->getBufferHeight(); + } + + if(abs(totalXShift) >= bufferWidth) + return false; + if(abs(totalYShift) >= bufferHeight) + return false; + + // Without the absolute value this will calculate + // if any data on the screen is preserved, however + // a better method is to see if its quicker to reread + // it all which happens when we use abs + totalXShift += abs(transform->getXTranslation()); + totalYShift += abs(transform->getYTranslation()); + + if(!transform->resizeFirst()) { + bufferWidth = transform->getBufferWidth(); + bufferHeight = transform->getBufferHeight(); + } + + if(abs(totalXShift) >= bufferWidth) + return false; + if(abs(totalYShift) >= bufferHeight) + return false; + } + } + + return true; + } + + + /** + * This searches for actions that will reset the entire buffer's + * contents. + * + * @return bool True if a transform to size 0,0 exists + */ + bool ViewportBuffer::reinitializeActionExists() { + QRect currentBufferRect(bufferXYRect()); + + if(currentBufferRect.width() == 0 || currentBufferRect.height() == 0) { + return true; + } + + for(int actionIndex = 0; actionIndex < p_actions->size(); actionIndex ++) { + ViewportBufferAction *action = (*p_actions)[actionIndex]; + + if(action->getActionType() == ViewportBufferAction::transform) { + ViewportBufferTransform *transform = (ViewportBufferTransform *)action; + + if(transform->getBufferWidth() == 0) + return true; + if(transform->getBufferHeight() == 0) + return true; + } + } + + return false; + } + + + /** + * This tests if queued actions exist in the viewport buffer. + * + * @return bool + */ + bool ViewportBuffer::working() { + return !p_actions->empty() || !p_bufferInitialized || !p_enabled; + } + + + /** + * Does a transformation on the internal viewport buffer + * + * @param action + */ + void ViewportBuffer::doTransformAction(ViewportBufferTransform *action) { + bool needResize = action->getBufferWidth() > -1 && + action->getBufferHeight() > -1; + + if(action->resizeFirst() && needResize) { + resizeBuffer(action->getBufferWidth(), action->getBufferHeight()); + } + + shiftBuffer(action->getXTranslation(), action->getYTranslation()); + + if(!action->resizeFirst() && needResize) { + resizeBuffer(action->getBufferWidth(), action->getBufferHeight()); + } + + delete action; + action = NULL; + p_actions->dequeue(); + } + + + /** + * Initializes a fill action by requesting the initial cube + * data. + * + * @param action + */ + void ViewportBuffer::startFillAction(ViewportBufferFill *action) { + if(action->started()) + return; + + action->started(true); + + requestCubeLine(action); + + if(action->shouldRequestMore()) { + requestCubeLine(action); + } + } + + + /** + * Tells the cube viewport to restretch. + * + * @param action + */ + void ViewportBuffer::doStretchAction(ViewportBufferStretch *action) { + delete action; + action = NULL; + p_actions->dequeue(); + + p_viewport->restretch(this); + } + + + /** + * Enlarges or shrinks the buffer and fills with nulls if necessary. + * + * @param width + * @param height + */ + void ViewportBuffer::resizeBuffer(unsigned int width, unsigned int height) { + p_buffer.resize(height); + + for(unsigned int i = 0; i < p_buffer.size(); i++) { + p_buffer[i].resize(width, Null); + } + } + + + /** + * Shifts the DN values in the buffer by deltaX and deltaY. Does not fill from + * outside the buffer. + * + * @param deltaX + * @param deltaY + */ + void ViewportBuffer::shiftBuffer(int deltaX, int deltaY) { + if(deltaY >= 0) { + for(int i = p_buffer.size() - 1; i >= deltaY; i--) { + p_buffer[i] = p_buffer[i - deltaY]; + + // If we have y shift, null out original data (keep only moved data) + if(deltaY != 0) { + for(unsigned int x = 0; x < p_buffer[i - deltaY].size(); x++) { + p_buffer[i - deltaY][x] = Null; + } + } + + if(deltaX > 0) { + for(int j = p_buffer[i].size() - 1; j >= deltaX; j--) { + p_buffer[i][j] = p_buffer[i][j - deltaX]; + p_buffer[i][j - deltaX] = Null; + } + } + else if(deltaX < 0) { + for(int j = 0; j < (int)p_buffer[i].size() + deltaX; j++) { + p_buffer[i][j] = p_buffer[i][j - deltaX]; + p_buffer[i][j - deltaX] = Null; + } + } + } + } + else if(deltaY < 0) { + for(int i = 0; i < (int)p_buffer.size() + deltaY; i++) { + p_buffer[i] = p_buffer[i - deltaY]; + + // null out original data (keep only moved data) + for(unsigned int x = 0; x < p_buffer[i - deltaY].size(); x++) { + p_buffer[i - deltaY][x] = Null; + } + + if(deltaX > 0) { + for(int j = p_buffer[i].size() - 1; j >= deltaX; j--) { + p_buffer[i][j] = p_buffer[i][j - deltaX]; + p_buffer[i][j - deltaX] = Null; + } + } + else if(deltaX < 0) { + for(int j = 0; j < (int)p_buffer[i].size() + deltaX; j++) { + p_buffer[i][j] = p_buffer[i][j - deltaX]; + p_buffer[i][j - deltaX] = Null; + } + } + } + } + } + + + /** + * Call this when the viewport is resized (not zoomed). + * + */ + void ViewportBuffer::resizedViewport() { + updateBoundingRects(); + + if(!p_bufferInitialized || !p_enabled) + return; + + // ensure we have a valid bounding rect! For example, If the cube viewport + // is hidden and then shown again this could happen. + if(!p_XYBoundingRect.isValid()) + return; + + if(!p_oldXYBoundingRect.isValid()) { + reinitialize(); + return; + } + + //We need to know how much data was gained/lost on each side of the cube + double deltaLeftSamples = p_sampLineBoundingRect[rectLeft] - + p_oldSampLineBoundingRect[rectLeft]; + //The input to round should be close to an integer + int deltaLeftPixels = (int)round(deltaLeftSamples * p_viewport->scale()); + + double deltaRightSamples = p_sampLineBoundingRect[rectRight] - + p_oldSampLineBoundingRect[rectRight]; + int deltaRightPixels = (int)round(deltaRightSamples * p_viewport->scale()); + + double deltaTopSamples = p_sampLineBoundingRect[rectTop] - + p_oldSampLineBoundingRect[rectTop]; + int deltaTopPixels = (int)round(deltaTopSamples * p_viewport->scale()); + + double deltaBottomSamples = p_sampLineBoundingRect[rectBottom] - + p_oldSampLineBoundingRect[rectBottom]; + int deltaBottomPixels = (int)round(deltaBottomSamples * + p_viewport->scale()); + + //deltaW is the change in width in the visible area of the cube + int deltaW = - deltaLeftPixels + deltaRightPixels; + + //deltaH is the change in height in the visible area of the cube + int deltaH = - deltaTopPixels + deltaBottomPixels; + + //If the new visible width has changed (resized in the horizontal direction) + if(p_XYBoundingRect.width() != p_oldXYBoundingRect.width()) { + //Resized larger in the horizontal direction + if(deltaW > 0) { + //Using old height because we might lose data if new height is smaller + ViewportBufferTransform *transform = new ViewportBufferTransform(); + transform->setTranslation(-deltaLeftPixels, 0); + transform->setResize(p_XYBoundingRect.width(), + p_oldXYBoundingRect.height()); + transform->resizeFirst(true); + + enqueueAction(transform); + + // left side that needs filled + QPoint topLeftOfLeftRect(p_XYBoundingRect.left(), + p_oldXYBoundingRect.top()); + + QPoint bottomRightOfLeftRect(p_XYBoundingRect.left() - deltaLeftPixels, + p_oldXYBoundingRect.bottom()); + + QRect leftRect(topLeftOfLeftRect, bottomRightOfLeftRect); + + ViewportBufferFill *leftFill = createViewportBufferFill(leftRect, + true); + enqueueAction(leftFill); + + // right side that needs filled + QPoint topLeftOfRightRect(p_XYBoundingRect.right() - deltaRightPixels, + p_oldXYBoundingRect.top()); + + QPoint bottomRightOfRightRect(p_XYBoundingRect.right(), + p_oldXYBoundingRect.bottom()); + + QRect rightRect(topLeftOfRightRect, bottomRightOfRightRect); + + ViewportBufferFill *rightFill = createViewportBufferFill(rightRect, + true); + enqueueAction(rightFill); + } + //Resized smaller in the horizontal direction + else if(deltaW < 0) { + ViewportBufferTransform *transform = new ViewportBufferTransform(); + transform->setTranslation(-deltaLeftPixels, 0); + transform->setResize(p_XYBoundingRect.width(), + p_oldXYBoundingRect.height()); + transform->resizeFirst(false); + enqueueAction(transform); + } + } + + //If the new visible height has changed (resized in the vertical direction) + if(p_XYBoundingRect.height() != p_oldXYBoundingRect.height()) { + //Resized larger in the vertical direction + if(deltaH > 0) { + ViewportBufferTransform *transform = new ViewportBufferTransform(); + transform->setTranslation(0, -deltaTopPixels); + transform->setResize(p_XYBoundingRect.width(), + p_XYBoundingRect.height()); + transform->resizeFirst(true); + + enqueueAction(transform); + + QPoint bottomRightOfTopSide(p_XYBoundingRect.right(), + p_XYBoundingRect.top() - deltaTopPixels); + + QRect topSideToFill(p_XYBoundingRect.topLeft(), bottomRightOfTopSide); + + + QPoint topLeftOfbottomSide(p_XYBoundingRect.left(), + p_XYBoundingRect.bottom() - + deltaBottomPixels); + + QRect bottomSideToFill(topLeftOfbottomSide, + p_XYBoundingRect.bottomRight()); + + ViewportBufferFill *topFill = createViewportBufferFill(topSideToFill, + false); + enqueueAction(topFill); + + ViewportBufferFill *bottomFill = + createViewportBufferFill(bottomSideToFill, false); + enqueueAction(bottomFill); + } + //Resized smaller in the vertical direction + else if(deltaH < 0) { + ViewportBufferTransform *transform = new ViewportBufferTransform(); + + transform->setTranslation(0, -deltaTopPixels); + transform->setResize(p_XYBoundingRect.width(), + p_oldXYBoundingRect.height()); + + enqueueAction(transform); + } + } + + doQueuedActions(); + } + + + /** + * Call this when the viewport is panned. DeltaX and deltaY are relative to + * the direction the buffer needs to shift. + * + * @param deltaX + * @param deltaY + */ + void ViewportBuffer::pan(int deltaX, int deltaY) { + updateBoundingRects(); + + if(!p_bufferInitialized || !p_enabled) { + return; + } + + + if(p_sampLineBoundingRect == p_oldSampLineBoundingRect) { + //The sample line bounding rect contains the bounds of the + //screen pixels to the cube sample/line bounds. If the cube + //bounds do not change, then we do not need to do anything to + //the buffer. + return; + } + + double deltaLeftSamples = p_sampLineBoundingRect[rectLeft] - + p_oldSampLineBoundingRect[rectLeft]; + int deltaLeftPixels = (int)round(deltaLeftSamples * p_viewport->scale()); + + double deltaTopLines = p_sampLineBoundingRect[rectTop] - + p_oldSampLineBoundingRect[rectTop]; + int deltaTopPixels = (int)round(deltaTopLines * p_viewport->scale()); + + // Don't try to figure out panning beyond a full screen, + // even though data could very well be preserved. + if(abs(deltaY) > p_XYBoundingRect.height() || + abs(deltaX) > p_XYBoundingRect.width()) { + reinitialize(); + return; + } + + //Left side of the visible area changed (start sample is different) + if(p_sampLineBoundingRect[rectLeft] != p_oldSampLineBoundingRect[rectLeft]) { + //Shifting data to the right + if(deltaX > 0) { + // The buffer is getting bigger + ViewportBufferTransform *transform = new ViewportBufferTransform(); + transform->setResize(p_XYBoundingRect.width(), + p_oldXYBoundingRect.height()); + transform->setTranslation(-deltaLeftPixels, 0); + transform->resizeFirst(true); + + enqueueAction(transform); + + QPoint topLeftOfRefill(p_XYBoundingRect.left(), + p_oldXYBoundingRect.top()); + + QPoint bottomRightOfRefill(p_XYBoundingRect.left() + deltaX, + p_oldXYBoundingRect.bottom()); + QRect fillArea(topLeftOfRefill, bottomRightOfRefill); + + ViewportBufferFill *fill = createViewportBufferFill(fillArea, true); + enqueueAction(fill); + } + //Shifting data to the left + else if(deltaX < 0) { + //The buffer is getting smaller - no new data + ViewportBufferTransform *transform = new ViewportBufferTransform(); + transform->setTranslation(-deltaLeftPixels, 0); + transform->setResize(p_XYBoundingRect.width(), + p_oldXYBoundingRect.height()); + transform->resizeFirst(false); + enqueueAction(transform); + + // if new samples on the screen at all, mark it for reading + if(p_sampLineBoundingRect[rectRight] != + p_oldSampLineBoundingRect[rectRight]) { + QPoint topLeftOfRefill(p_XYBoundingRect.right() + deltaX, + p_oldXYBoundingRect.top()); + QPoint bottomRightOfRefill(p_XYBoundingRect.right(), + p_oldXYBoundingRect.bottom()); + + QRect refillArea(topLeftOfRefill, bottomRightOfRefill); + + ViewportBufferFill *fill = createViewportBufferFill(refillArea, + true); + enqueueAction(fill); + } + } + } + // Left side of the visible area is the same (start sample has not changed, + // but end sample may be different) + else { + ViewportBufferTransform *transform = new ViewportBufferTransform(); + transform->setResize(p_XYBoundingRect.width(), + p_oldXYBoundingRect.height()); + enqueueAction(transform); + + if(deltaX < 0) { + QPoint topLeftOfFillArea(p_XYBoundingRect.right() + deltaX, + p_oldXYBoundingRect.top()); + + QPoint bottomRightOfFillArea(p_XYBoundingRect.right(), + p_oldXYBoundingRect.bottom()); + + QRect fillArea(topLeftOfFillArea, bottomRightOfFillArea); + ViewportBufferFill *fill = createViewportBufferFill(fillArea, true); + + enqueueAction(fill); + } + } + + //Top side of the visible area changed (start line is different) + if(p_sampLineBoundingRect[rectTop] != p_oldSampLineBoundingRect[rectTop]) { + //Shifting data down + if(deltaY > 0) { + ViewportBufferTransform *transform = new ViewportBufferTransform(); + transform->setTranslation(0, -deltaTopPixels); + transform->setResize(p_XYBoundingRect.width(), + p_XYBoundingRect.height()); + transform->resizeFirst(true); + enqueueAction(transform); + + QPoint topLeftOfFillArea(p_XYBoundingRect.left(), + p_XYBoundingRect.top()); + QPoint bottomRightOfFillArea(p_XYBoundingRect.right(), + p_XYBoundingRect.top() + deltaY); + QRect fillArea(topLeftOfFillArea, bottomRightOfFillArea); + ViewportBufferFill *fill = createViewportBufferFill(fillArea, false); + enqueueAction(fill); + } + //Shifting data up + else if(deltaY < 0) { + ViewportBufferTransform *transform = new ViewportBufferTransform(); + transform->setTranslation(0, -deltaTopPixels); + transform->setResize(p_XYBoundingRect.width(), + p_XYBoundingRect.height()); + transform->resizeFirst(false); + enqueueAction(transform); + + // if new lines on the screen at all, mark it for reading + if(p_sampLineBoundingRect[rectBottom] != + p_oldSampLineBoundingRect[rectBottom]) { + QPoint topLeftOfFillArea(p_XYBoundingRect.left(), + p_oldXYBoundingRect.bottom() + deltaY); + QPoint bottomRightOfFillArea(p_XYBoundingRect.right(), + p_XYBoundingRect.bottom()); + QRect fillArea(topLeftOfFillArea, bottomRightOfFillArea); + ViewportBufferFill *fill = createViewportBufferFill(fillArea, false); + enqueueAction(fill); + } + } + } + // Top side of the visible area is the same (start line has not changed, but + // end line may be different) + else { + ViewportBufferTransform *transform = new ViewportBufferTransform(); + transform->setResize(p_XYBoundingRect.width(), + p_XYBoundingRect.height()); + enqueueAction(transform); + + if(deltaY < 0) { + QPoint topLeftOfFillArea(p_XYBoundingRect.left(), + p_XYBoundingRect.bottom() + deltaY); + QPoint bottomRightOfFillArea(p_XYBoundingRect.right(), + p_XYBoundingRect.bottom()); + QRect fillArea(topLeftOfFillArea, bottomRightOfFillArea); + ViewportBufferFill *fill = createViewportBufferFill(fillArea, false); + enqueueAction(fill); + } + } + + doQueuedActions(); + } + + + /** + * When all current operations finish the cube viewport will be + * asked to do a stretch if you call this. Existing requests + * will be removed. + */ + void ViewportBuffer::addStretchAction() { + for(int i = 0; i < p_actions->size(); i++) { + if((*p_actions)[i]->getActionType() == ViewportBufferAction::stretch) { + p_actions->removeAt(i); + i --; + } + } + + enqueueAction(new ViewportBufferStretch()); + doQueuedActions(); + } + + /** + * This is meant to clear up ram on non-active viewports. + * + * cubeViewport is supposed to call this method on viewports + * buffers that are not related to the active viewport. + * + * @param force If true, memory will be freed regardless of current total + * buffer size (b/w -> rgb for example). + */ + void ViewportBuffer::emptyBuffer(bool force) { + if(force) { + p_buffer.clear(); + p_bufferInitialized = false; + } + } + + + /** + * Returns a rect, in screen pixels, of the area this buffer + * covers. + * + * @author slambright (4/30/2010) + * + * @return QRect + */ + QRect ViewportBuffer::bufferXYRect() { + QRect rect = p_XYBoundingRect; + + if(!rect.height() || !p_buffer.size()) + return QRect(); + + if(rect.height() > (int) p_buffer.size()) + rect.setBottom(rect.top() + p_buffer.size() - 1); + + if(rect.width() > (int) p_buffer[0].size()) + rect.setRight(rect.left() + p_buffer[0].size() - 1); + + + return rect; + } + + + /** + * Call this when zoomed, re-reads visible area. + * + */ + void ViewportBuffer::scaleChanged() { + if(!p_enabled) + return; + + updateBoundingRects(); + reinitialize(); + } + + + /** + * This turns on or off reading from the cube. If enabled is true the buffer + * will be re-read. + * + * @param enabled + */ + void ViewportBuffer::enable(bool enabled) { + bool wasEnabled = p_enabled; + + p_enabled = enabled; + + if(!wasEnabled && p_enabled) { + updateBoundingRects(); + reinitialize(); + } + } + + + /** + * Sets the band to read from, the buffer will be re-read if the band changes. + * + * @param band + */ + void ViewportBuffer::setBand(int band) { + if(p_band == band) + return; + p_band = band; + + updateBoundingRects(); + + if(!p_enabled) + return; + + reinitialize(); + } + + + /** + * This resizes and fills entire buffer. + * + */ + void ViewportBuffer::reinitialize() { + // If we're in the middle of a process, we got an okay stretch on startup, + // then we can stop what we're doing. + if(working() && p_initialStretchDone) { + // We only need to handle the current action, can ignore others + ViewportBufferAction *curAction = p_actions->head(); + + // Delete older actions + for(int i = p_actions->size() - 1; i > 0; i--) { + delete(*p_actions)[i]; + p_actions->pop_back(); + } + + // Deal with current action + if(curAction->started()) { + if(curAction->getActionType() == ViewportBufferAction::fill) { + ViewportBufferFill *fill = (ViewportBufferFill *)curAction; + + fill->stop(); + + p_requestedFillArea = fill->getRect()->height() * + fill->getRect()->width(); + } + } + else { + delete curAction; + p_actions->clear(); + p_requestedFillArea = 0.0; + } + } + + + p_bufferInitialized = true; + + ViewportBufferTransform *reset = new ViewportBufferTransform(); + reset->setResize(0, 0); + enqueueAction(reset); + + ViewportBufferTransform *transform = new ViewportBufferTransform(); + transform->setResize(p_XYBoundingRect.width(), p_XYBoundingRect.height()); + enqueueAction(transform); + + ViewportBufferFill *fill = createViewportBufferFill(p_XYBoundingRect, + false); + enqueueAction(fill); + + doQueuedActions(); + } +} // of namespace Qisis diff --git a/isis/src/qisis/objs/CubeViewport/ViewportBuffer.h b/isis/src/qisis/objs/CubeViewport/ViewportBuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..65db8e8d877a9a8698643911c736c7b2419b3569 --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/ViewportBuffer.h @@ -0,0 +1,213 @@ +#ifndef ViewportBuffer_h +#define ViewportBuffer_h + +/** + * @file + * $Date: 2010/06/03 18:36:14 $ + * $Revision: 1.14 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include + +#include + +#include "Cube.h" +#include "Brick.h" + +// parent +#include + +template class QQueue; +class QRect; + +namespace Isis { + class CubeDataThread; + class Brick; +} + +namespace Qisis { + class CubeViewport; + class ViewportBufferAction; + class ViewportBufferFill; + class ViewportBufferStretch; + class ViewportBufferTransform; + + /** + * @brief Reads and stores visible DN values + * + * This class manages visible pixels in a CubeViewport. This class is responsible + * for reading from the Cube only what is necessary and gives fast access to + * visible DNs. + * + * @ingroup Visualization Tools + * + * @author 2009-03-26 Steven Lambright and Noah Hilt + * + * @internal + * @history 2009-04-21 Steven Lambright - Fixed problem with only half of the + * side pixels being loaded in + * @history 2010-04-08 Steven Lambright and Eric Hyer - Added support for + * using CubeDataThread for reads. + * @history 2010-05-11 Eric Hyer - Fixed issue with invalid bounding rects + * in resizedViewport() + * @history 2010-05-24 Eric Hyer - Fixed bug in previous bug fix (checks + * were in wrong order) + */ + class ViewportBuffer : public QObject { + Q_OBJECT + + public: + ViewportBuffer(CubeViewport *viewport, Isis::CubeDataThread *cubeData, + int cubeId); + virtual ~ViewportBuffer(); + + const std::vector &getLine(int line); + + void resizedViewport(); + void pan(int deltaX, int deltaY); + + void scaleChanged(); + + void fillBuffer(QRect rect); + void fillBuffer(QRect rect, const Isis::Brick *data); + + void emptyBuffer(bool force = false); + + QRect bufferXYRect(); + + void setBand(int band); + + //! Return the band associated with this viewport buffer + int getBand() { + return p_band; + } + + void enable(bool enabled); + + void addStretchAction(); + + double currentProgress(); + double totalUnfilledArea(); + + /** + * Returns whether the buffer is enabled (reading data) or not. + * + * + * @return bool + */ + bool enabled() { + return p_enabled; + } + bool working(); + + bool hasEntireCube(); + + public slots: + void DataReady(void *requester, int cubeId, const Isis::Brick *brick); + + signals: + /** + * Ask the cube data thread for data + * + * @param cubeId + * @param startSample + * @param startLine + * @param endSample + * @param endLine + * @param band + * @param caller + */ + void ReadCube(int cubeId, int startSample, int startLine, + int endSample, int endLine, int band, void *caller); + + //! Tell cube data thread we're done with a brick + void DoneWithData(int, const Isis::Brick *); + + private: + QRect getXYBoundingRect(); + QList getSampLineBoundingRect(); + void updateBoundingRects(); + void doQueuedActions(); + void doTransformAction(ViewportBufferTransform *action); + void doStretchAction(ViewportBufferStretch *action); + void startFillAction(Qisis::ViewportBufferFill *action); + + ViewportBufferFill *createViewportBufferFill(QRect, bool); + + void requestCubeLine(ViewportBufferFill *fill); + + void resizeBuffer(unsigned int width, unsigned int height); + void shiftBuffer(int deltaX, int deltaY); + void reinitialize(); + bool actionsPreserveData(); + bool reinitializeActionExists(); + void enqueueAction(ViewportBufferAction *); + + CubeViewport *p_viewport; //!< The CubeViewport which created this buffer + int p_cubeId; //!< Id associated with the cube in this viewport buffer + Isis::CubeDataThread *p_dataThread; //!< manages cube io + + int p_band; //!< The band to read from + + bool p_enabled; //!< True if reading from cube (active) + std::vector< std::vector > p_buffer; //!< The buffer to hold cube dn values + bool p_bufferInitialized; //!< True if the buffer has been initialized + + /** + * This rect is in viewport pixels and represents the area that + * this viewport buffer defines in the viewport. + */ + QRect p_XYBoundingRect; + QRect p_oldXYBoundingRect; //!< The previous bounding rect + + /** + * This rect is in cube pixels and represents the area that + * this viewport buffer defines in the viewport. To get a + * particular corner use the sampLineRectPosition enumeration as + * indices for a particular corner. + */ + QList< double > p_sampLineBoundingRect; + QList< double > p_oldSampLineBoundingRect; //!< Previous bounding rect + int p_viewportHeight; //!< Current viewport height + int p_oldViewportHeight; //!< Previous viewport height + int p_vertScrollBarPos; //!< Current vertical scroll bar position + int p_oldVertScrollBarPos; //!< Previous vertical scroll bar position + bool p_initialStretchDone; //!< True if a stretch action has occurred + double p_requestedFillArea; //!< Sum of the requested area to be filled + + /** + * Enumeration for accessing sample/line bounding rectangles + */ + enum sampLineRectPosition { + rectLeft = 0, //!< QRect.left() + rectTop, //!< QRect.top() + rectRight, //!< QRect.right() + rectBottom //!< QRect.bottom() + }; + + /** + * This is the set of actions we wish to perform on the buffer. + * This is queued because we need to wait for other threads to + * give us cube data before we progress through the queue. + */ + QQueue< ViewportBufferAction * > * p_actions; + }; +} + +#endif diff --git a/isis/src/qisis/objs/CubeViewport/ViewportBufferAction.cpp b/isis/src/qisis/objs/CubeViewport/ViewportBufferAction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aaad06404f06e142426fc6de42af3ba325be1983 --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/ViewportBufferAction.cpp @@ -0,0 +1,16 @@ +#include "ViewportBufferAction.h" + +namespace Qisis { + /** + * Creates a new viewport buffer action + */ + ViewportBufferAction::ViewportBufferAction() { + p_started = false; + } + + /** + * Destructor + */ + ViewportBufferAction::~ViewportBufferAction() { + } +} diff --git a/isis/src/qisis/objs/CubeViewport/ViewportBufferAction.h b/isis/src/qisis/objs/CubeViewport/ViewportBufferAction.h new file mode 100644 index 0000000000000000000000000000000000000000..1c82e03b39c5b4fa8e812020ee6890c51df42c0c --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/ViewportBufferAction.h @@ -0,0 +1,65 @@ +#ifndef ViewportBufferAction_h +#define ViewportBufferAction_h + + +namespace Qisis { + class ViewportBufferAction { + public: + ViewportBufferAction(); + virtual ~ViewportBufferAction(); + + /** + * This uniquely identifies which child is instantiated. + */ + enum ActionType { + none, //!< Parent was instantiated + transform, //!< ViewportBufferTransform + fill, //!< ViewportBufferFill + stretch //!< ViewportBufferStretch + }; + + //! Returns the instantiated type + virtual ActionType getActionType() { + return none; + } + + //! Returns true if this is an action that takes time and has begun + bool started() { + return p_started; + }; + + /** + * Sets started + * + * @param started True if starting + */ + void started(bool started) { + p_started = started; + }; + + //! Cancels the process, used if reinitialize requested for example + virtual void stop() {}; + + private: + /** + * No copying these. + * + * @param other + */ + ViewportBufferAction(const ViewportBufferAction &other); + + /** + * No assigning these. + * + * @param other + * + * @return ViewportBufferAction& + */ + ViewportBufferAction &operator=(const ViewportBufferAction &other); + + private: + bool p_started; //!< True if this action has begun + }; +} + +#endif diff --git a/isis/src/qisis/objs/CubeViewport/ViewportBufferFill.cpp b/isis/src/qisis/objs/CubeViewport/ViewportBufferFill.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9bd4e5425c6074045801edc4ac4a7a2427122988 --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/ViewportBufferFill.cpp @@ -0,0 +1,120 @@ + +#include "ViewportBufferFill.h" + +#include +#include + +#include +#include + +using namespace std; + +namespace Qisis { + /** + * Constructor. + * + * @param rect + * @param xCoef + * @param xScale + * @param yCoef + * @param yScale + * @param topLeftPixel + */ + ViewportBufferFill::ViewportBufferFill(const QRect &rect, + const int &xCoef, const double &xScale, const int &yCoef, + const double &yScale, const QPoint &topLeftPixel) + : ViewportBufferAction() { + p_rect = NULL; + p_topLeftPixel = NULL; + + p_rect = new QRect(rect); + p_topLeftPixel = new QPoint(topLeftPixel); + + p_requestPosition = rect.top(); + p_readPosition = rect.top(); + p_xCoef = xCoef; + p_xScale = xScale; + p_yCoef = yCoef; + p_yScale = yScale; + } + + /** + * Destructor + */ + ViewportBufferFill::~ViewportBufferFill() { + if(p_rect) { + delete p_rect; + p_rect = NULL; + } + + if(p_topLeftPixel) { + delete p_topLeftPixel; + p_topLeftPixel = NULL; + } + } + + /** + * Returns the top of the X/Y bounding rect for this fill + * + * @return int + */ + int ViewportBufferFill::getTopmostPixelPosition() { + return p_topLeftPixel->y(); + } + + + /** + * Returns the left of the X/Y bounding rect for this fill + * + * @return int + */ + int ViewportBufferFill::getLeftmostPixelPosition() { + return p_topLeftPixel->x(); + } + + + /** + * Returns true if read position is past the end of the fill + * + * @return bool + */ + bool ViewportBufferFill::doneReading() { + return p_readPosition >= (unsigned)(p_rect->top() + p_rect->height() - 1); + } + + + /** + * Returns true if request position is past the end of the fill + * + * @return bool + */ + bool ViewportBufferFill::shouldRequestMore() { + return p_requestPosition < (unsigned)(p_rect->top() + p_rect->height() - 1); + } + + + /** + * Cancels the current operation. Stops filling ASAP. + */ + void ViewportBufferFill::stop() { + p_rect->setBottom(p_requestPosition); + } + + + /** + * Returns true if it is recommended to paint the fill area so + * far. + * + * @param linesToPaint + * + * @return bool + */ + bool ViewportBufferFill::shouldPaint(int &linesToPaint) { + if(p_rect->height() < STEPSIZE) + linesToPaint = p_rect->height(); + else + linesToPaint = STEPSIZE; + + return p_readPosition % STEPSIZE == 0 || doneReading(); + } +} diff --git a/isis/src/qisis/objs/CubeViewport/ViewportBufferFill.h b/isis/src/qisis/objs/CubeViewport/ViewportBufferFill.h new file mode 100644 index 0000000000000000000000000000000000000000..8e86d9a09ac81126ab088c277decedfd04a43853 --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/ViewportBufferFill.h @@ -0,0 +1,119 @@ +#ifndef VieportBufferFill_h +#define VieportBufferFill_h + +#include "ViewportBufferAction.h" + +class QRect; +class QPoint; + +namespace Qisis { + class ViewportBufferFill : public ViewportBufferAction { + public: + ViewportBufferFill(const QRect &rect, const int &xCoef, + const double &xScale, const int &yCoef, + const double &yScale, const QPoint &topLeftPixel); + ~ViewportBufferFill(); + + + /** + * Returns the type of this class + * + * @return ViewportBufferAction::ActionType + */ + virtual ViewportBufferAction::ActionType getActionType() { + return ViewportBufferAction::fill; + }; + + /** + * Converts screen x position to cube sample position + * + * @param x + * + * @return double + */ + double viewportToSample(int x) { + return (x + p_xCoef) / p_xScale; + } + + /** + * Converts screen y position to cube line position + * + * @param y + * + * @return double + */ + double viewportToLine(int y) { + return (y + p_yCoef) / p_yScale; + } + + /** + * Returns the current request position (>= read position) + * + * @return int + */ + int getRequestPosition() const { + return p_requestPosition; + } + + /** + * Returns the current read position + * + * @return int + */ + int getReadPosition() const { + return p_readPosition; + } + + //! Increment read position + void incReadPosition() { + p_readPosition++; + } + + //! Increment request position + void incRequestPosition() { + p_requestPosition++; + } + + /** + * Returns the rect that this action is filling in screen pixels + * + * @return QRect* + */ + QRect *getRect() { + return p_rect; + } + + int getTopmostPixelPosition(); + int getLeftmostPixelPosition(); + + bool doneReading(); + bool shouldRequestMore(); + bool shouldPaint(int &linesToPaint); + + void stop(); + + + private: + //! Position of the cube reads + unsigned int p_readPosition; + //! Position of the cube requests + unsigned int p_requestPosition; + //! Rect this fill represents + QRect *p_rect; + //! Top left of the viewport for this fill + QPoint *p_topLeftPixel; + //! viewport to sample/line x coef + int p_xCoef; + //! viewport to sample/line x scalar + double p_xScale; + //! viewport to sample/line y coef + int p_yCoef; + //! viewport to sample/line y scalar + double p_yScale; + + //! how many cube lines per paint if painting inbetween gets re-enabled + const static int STEPSIZE = 20; + }; +} + +#endif diff --git a/isis/src/qisis/objs/CubeViewport/ViewportBufferStretch.cpp b/isis/src/qisis/objs/CubeViewport/ViewportBufferStretch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c419b8aa5a5658a48aed924541d87bfbc4b0ddc5 --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/ViewportBufferStretch.cpp @@ -0,0 +1,16 @@ +#include "ViewportBufferStretch.h" + + +namespace Qisis { + /** + * Constructor + */ + ViewportBufferStretch::ViewportBufferStretch() : ViewportBufferAction() { + } + + /** + * Destructor + */ + ViewportBufferStretch::~ViewportBufferStretch() { + } +} diff --git a/isis/src/qisis/objs/CubeViewport/ViewportBufferStretch.h b/isis/src/qisis/objs/CubeViewport/ViewportBufferStretch.h new file mode 100644 index 0000000000000000000000000000000000000000..b44c0ab36e6e1efd153ecb3bb8a44693a0c74508 --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/ViewportBufferStretch.h @@ -0,0 +1,20 @@ +#ifndef VieportBufferStretch_h +#define VieportBufferStretch_h + +#include "ViewportBufferAction.h" + +class QRect; + +namespace Qisis { + class ViewportBufferStretch : public ViewportBufferAction { + public: + ViewportBufferStretch(); + ~ViewportBufferStretch(); + + virtual ViewportBufferAction::ActionType getActionType() { + return ViewportBufferAction::stretch; + }; + }; +} + +#endif diff --git a/isis/src/qisis/objs/CubeViewport/ViewportBufferTransform.cpp b/isis/src/qisis/objs/CubeViewport/ViewportBufferTransform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c6a0b9e364a2854c4f2270e310dbbc214a97709 --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/ViewportBufferTransform.cpp @@ -0,0 +1,40 @@ + +#include "ViewportBufferTransform.h" + +#include + +namespace Qisis { + /** + * Constructor + */ + ViewportBufferTransform::ViewportBufferTransform() { + p_xTranslation = 0; + p_yTranslation = 0; + p_newBufferWidth = -1; + p_newBufferHeight = -1; + p_resizeFirst = false; + } + + /** + * Sets the translation amount in x and y + * + * @param x + * @param y + */ + void ViewportBufferTransform::setTranslation(int x, int y) { + p_xTranslation = x; + p_yTranslation = y; + } + + + /** + * Sets the size the buffer should be resized to + * + * @param width + * @param height + */ + void ViewportBufferTransform::setResize(int width, int height) { + p_newBufferWidth = width; + p_newBufferHeight = height; + } +} diff --git a/isis/src/qisis/objs/CubeViewport/ViewportBufferTransform.h b/isis/src/qisis/objs/CubeViewport/ViewportBufferTransform.h new file mode 100644 index 0000000000000000000000000000000000000000..2f52e509035efd0c533916fdb853ac9f0c2e87a1 --- /dev/null +++ b/isis/src/qisis/objs/CubeViewport/ViewportBufferTransform.h @@ -0,0 +1,87 @@ + +#ifndef ViewportBufferTransform_h +#define ViewportBufferTransform_h + +#include "ViewportBufferAction.h" + + +namespace Qisis { + class ViewportBufferTransform : public ViewportBufferAction { + public: + ViewportBufferTransform(); + + //! Returns the instance type + virtual ActionType getActionType() { + return transform; + } + void setTranslation(int x, int y); + + + /** + * Gets the amount the buffer should be translated in X + * + * @return int + */ + int getXTranslation() { + return p_xTranslation; + } + + + /** + * Gets the amount the buffer should be translated in Y + * + * @return int + */ + int getYTranslation() { + return p_yTranslation; + } + + void setResize(int width, int height); + + /** + * Returns the new buffer width + * + * @return const int& + */ + const int &getBufferWidth() { + return p_newBufferWidth; + } + + /** + * Returns the new buffer height + * + * @return const int& + */ + const int &getBufferHeight() { + return p_newBufferHeight; + } + + /** + * Returns true if the resize should happen before the + * translation + * + * @return bool + */ + bool resizeFirst() { + return p_resizeFirst; + } + + /** + * Sets whether the resize should happen before the translation + * + * @param resizeFirst + */ + void resizeFirst(bool resizeFirst) { + p_resizeFirst = resizeFirst; + } + + + private: + int p_xTranslation; //!< How far to translate in X + int p_yTranslation; //!< How far to translate in Y + int p_newBufferWidth; //!< New width + int p_newBufferHeight; //!< New height + bool p_resizeFirst; //!< Do the resize before the translation? + }; +} +#endif diff --git a/isis/src/qisis/objs/EditTool/EditTool.cpp b/isis/src/qisis/objs/EditTool/EditTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..558a9eaa592a8099e1edb6b1bb9b821cb57f9fad --- /dev/null +++ b/isis/src/qisis/objs/EditTool/EditTool.cpp @@ -0,0 +1,907 @@ +/** + * @file + * $Revision: 1.11 $ + * $Date: 2010/06/28 09:00:39 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "EditTool.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Brick.h" +#include "Cube.h" +#include "MdiCubeViewport.h" +#include "RubberBandTool.h" +#include "SpecialPixel.h" +#include "ToolPad.h" + + +namespace Qisis { + /** + * Constructs and EditTool object. + * + * @param parent Parent widget + * + * + */ + EditTool::EditTool (QWidget *parent) : Qisis::Tool(parent) { + p_dn = Isis::Null; + } + + /** + * Adds the EditTool to the tool pad. + * + * @param pad input The tool pad that EditTool is to be added to + * + * @return QAction* + */ + QAction * EditTool::toolPadAction(ToolPad * pad) { + QAction * action = new QAction(pad); + action->setIcon(QPixmap(toolIconDir()+"/color_line.png")); + action->setToolTip("Image Edit (E)"); + action->setShortcut(Qt::Key_E); + + QString text = + "Function: Edit active viewport \ +

    Shortcut: E

    "; + action->setWhatsThis(text); + + return action; + } + + /** + * Creates the toolbar containing the edit tool widgets + * + * @param active input The widget that will contain the edit tool + * specific widgets + * + * @history 2007-08-31 Tracie Sucharski - Changed signal on dn line edit + * from returnPressed to editingFinished. + * + * @return QWidget* + */ + QWidget *EditTool::createToolBarWidget (QStackedWidget *active) { + QWidget *hbox = new QWidget(active); + + p_shapeComboBox = new QComboBox(hbox); + p_shapeComboBox->setEditable(false); + p_shapeComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + p_shapeComboBox->addItem("Point"); + p_shapeComboBox->addItem("Horizontal Line"); + p_shapeComboBox->addItem("Vertical Line"); + p_shapeComboBox->addItem("Start/End Line"); + p_shapeComboBox->addItem("Rectangle"); + p_shapeComboBox->setToolTip("Select shape to edit"); + QString text = + "Function: The shape in the image that will be replaced with \ + a new value. If Horizontal line is chosen, clicking anywhere on the \ + image will cause all samples on that line of the cube to be replaced \ + with the replacement value. If Vertical Line is chosen, a v ..."; + p_shapeComboBox->setWhatsThis(text); + p_shapeComboBox->setCurrentIndex(1); + connect(p_shapeComboBox,SIGNAL(activated(int)),this,SLOT(enableRubberBandTool())); + + p_valTypeComboBox = new QComboBox(hbox); + p_valTypeComboBox->setEditable(false); + p_valTypeComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + p_valTypeComboBox->addItem("Dn"); + p_valTypeComboBox->addItem("Null"); + p_valTypeComboBox->addItem("Hrs"); + p_valTypeComboBox->addItem("Lrs"); + p_valTypeComboBox->addItem("His"); + p_valTypeComboBox->addItem("Lis"); + p_valTypeComboBox->setToolTip("Value used to replace image data"); + text = + "Function: The value which will be used to replace image data. "; + p_valTypeComboBox->setWhatsThis(text); + p_valTypeComboBox->setCurrentIndex(1); + connect(p_valTypeComboBox,SIGNAL(activated(int)),this, + SLOT(selectValType(int))); + + // TODO:: Add validator??? + //QValidator *valid = new QValidator (hbox); + + p_dnLineEdit = new QLineEdit(hbox); + p_dnLineEdit->setToolTip("Dn value"); + text = + "Function: This is the dn used to replace image data"; + p_dnLineEdit->setWhatsThis(text); + p_dnLineEdit->setEnabled(false); + connect(p_dnLineEdit,SIGNAL(editingFinished()),this,SLOT(changeDn())); + + p_undoButton = new QToolButton(hbox); + p_undoButton->setIcon(QPixmap(toolIconDir()+"/undo.png")); + p_undoButton->setToolTip("Undo"); + text = + "Function: Undo last edit operation"; + p_undoButton->setWhatsThis(text); + connect(p_undoButton,SIGNAL(clicked()),this,SLOT(undoEdit())); + p_undoButton->setAutoRaise(true); + p_undoButton->setIconSize(QSize(22,22)); + + p_redoButton = new QToolButton(hbox); + p_redoButton->setIcon(QPixmap(toolIconDir()+"/redo.png")); + p_redoButton->setToolTip("Redo"); + text = + "Function: Redo last undo operation"; + p_redoButton->setWhatsThis(text); + p_redoButton->setEnabled(false); + connect(p_redoButton,SIGNAL(clicked()),this,SLOT(redoEdit())); + p_redoButton->setAutoRaise(true); + p_redoButton->setIconSize(QSize(22,22)); + + p_saveButton = new QToolButton(hbox); + p_saveButton->setIcon(QPixmap(toolIconDir()+"/filesave.png")); + p_saveButton->setToolTip("Save"); + text = + "Function: Save any changes made, these changes are finalized"; + p_saveButton->setWhatsThis(text); + p_saveButton->setEnabled(false); + connect(p_saveButton,SIGNAL(clicked()),this,SIGNAL(save())); + p_saveButton->setAutoRaise(true); + p_saveButton->setIconSize(QSize(22,22)); + + p_saveAsButton = new QToolButton(hbox); + p_saveAsButton->setIcon(QPixmap(toolIconDir()+"/filesaveas.png")); + p_saveAsButton->setToolTip("Save As"); + text = + "Function: Save any changes made to the file specified, these changes are finalized"; + p_saveAsButton->setWhatsThis(text); + connect(p_saveAsButton,SIGNAL(clicked()),this,SIGNAL(saveAs())); + p_saveAsButton->setAutoRaise(true); + p_saveAsButton->setIconSize(QSize(22,22)); + + QHBoxLayout *layout = new QHBoxLayout(hbox); + layout->setMargin(0); + layout->addWidget(p_shapeComboBox); + layout->addWidget(p_valTypeComboBox); + layout->addWidget(p_dnLineEdit); + layout->addWidget(p_undoButton); + layout->addWidget(p_redoButton); + layout->addWidget(p_saveButton); + layout->addWidget(p_saveAsButton); + layout->addStretch(1); + hbox->setLayout(layout); + + + return hbox; + } + + /** + * This is a private slot which is called when the user selects a new dn + * type + * + * @param index input This is the index selected in the valType combo box + * + */ + void EditTool::selectValType(int index) { + + if (index == 0) { + p_dnLineEdit->setEnabled(true); + } + else { + p_dnLineEdit->setEnabled(false); + + if (index == 1) p_dn = Isis::Null; + if (index == 2) p_dn = Isis::Hrs; + if (index == 3) p_dn = Isis::Lrs; + if (index == 4) p_dn = Isis::His; + if (index == 5) p_dn = Isis::Lis; + } + } + + /** + * This is a private slot called when the user hits the enter key after + * typing a value in the dnLineEdit field. + * + */ + void EditTool::changeDn () { + p_dn = p_dnLineEdit->text().toDouble(); + } + + /** + * This is a virtual function belonging to the Tool class which is called + * when the user selects a different viewport. This sets up the + * signal/slot for destruction of a viewport so the viewport is removed + * from the undoEdit hash. + * + * @internal + */ + void EditTool::updateTool () { + MdiCubeViewport *vp = cubeViewport(); + if (vp != NULL) { + //If the current viewport has no undo history + if (!p_undoEdit.contains(cubeViewport()) || p_undoEdit.value(vp)->empty()) { + p_undoButton->setEnabled(false); + p_saveButton->setEnabled(false); + connect(vp,SIGNAL(destroyed(QObject *)), + this,SLOT(removeViewport(QObject *))); + } + //Otherwise enable the undo button and save button + else { + p_undoButton->setEnabled(true); + p_saveButton->setEnabled(true); + } + //If the current viewport has no redo history + if (!p_redoEdit.contains(cubeViewport()) || p_redoEdit.value(vp)->empty()) { + p_redoButton->setEnabled(false); + connect(vp,SIGNAL(destroyed(QObject *)), + this,SLOT(removeViewport(QObject *))); + } + //Otherwise enable the redo button and save button + else { + p_redoButton->setEnabled(true); + p_saveButton->setEnabled(true); + } + } + } + + /** + * This method is called any time the RubberBandTool is + * complete. It checks if the viewport is writable, checks which + * mode it is in, either line or rectangle, and if + * RubberBandTool is valid. It then writes the data from the + * RubberBandTool to the cube. + * + */ + void EditTool::rubberBandComplete() { + MdiCubeViewport *vp = cubeViewport(); + if (vp == NULL) return; + + if (vp->cube()->IsReadOnly()) { + // ReOpen cube as read/write + // If cube readonly print error + try { + vp->cube()->ReOpen("rw"); + } + catch ( Isis::iException &e ) { + QMessageBox::information((QWidget *)parent(),"Error","Cannot open cube read/write"); + return; + } + } + if (vp->isColor()) { + QMessageBox::information((QWidget *)parent(), + "Error","Cannot edit in color mode"); + return; + } + + int issamp,isline,iesamp,ieline; + double ssamp,sline,esamp,eline; + QList *linePts = NULL; + + // Rectangle is selected + if (p_shapeComboBox->currentIndex() == Rectangle) { + if(!RubberBandTool::isValid()) return; + QRect r = RubberBandTool::rectangle(); + if ((r.width() < 5) || (r.height() < 5)) return; + vp->viewportToCube(r.left(),r.top(),ssamp,sline); + vp->viewportToCube(r.right(),r.bottom(),esamp,eline); + + issamp = (int) (ssamp + 0.5); + isline = (int) (sline + 0.5); + iesamp = (int) (esamp + 0.5); + ieline = (int) (eline + 0.5); + + //Clamp the rectangles coordinates to within the cube's dimensions + if (issamp < 0) issamp = 0; + if (iesamp < 0) iesamp = 0; + if (isline < 0) isline = 0; + if (ieline < 0) ieline = 0; + + if (issamp > vp->cubeSamples()) issamp = vp->cubeSamples(); + if (iesamp > vp->cubeSamples()) iesamp = vp->cubeSamples(); + if (isline > vp->cubeLines()) isline = vp->cubeLines(); + if (ieline > vp->cubeLines()) ieline = vp->cubeLines(); + + //If the rectangle is completely out of bounds on either side, display an error and return + if(issamp == iesamp || isline == ieline) { + QMessageBox::information((QWidget *)parent(), + "Error","Rectangle is out of bounds"); + return; + } + } + // Line is selected + else if (p_shapeComboBox->currentIndex() == StartEndLine) { + // Convert rubber band line to cube coordinates + if(!RubberBandTool::isValid()) return; + vp->viewportToCube(RubberBandTool::getVertices()[0].rx(),RubberBandTool::getVertices()[0].ry(), + ssamp,sline); + vp->viewportToCube(RubberBandTool::getVertices()[1].rx(),RubberBandTool::getVertices()[1].ry(), + esamp,eline); + + QLine l((int)ssamp,(int)sline,(int)esamp,(int)eline); + + linePts = EditTool::LineToPoints(l); + + //If the line is completely out of bounds, display an error and return + if (linePts->empty()) { + QMessageBox::information((QWidget *)parent(), + "Error","No points in edit line"); + return; + } + + // Find bounding rectangle for the line + issamp = std::min(linePts->front()->x(),linePts->back()->x()); + isline = std::min(linePts->front()->y(),linePts->back()->y()); + iesamp = std::max(linePts->front()->x(),linePts->back()->x()); + ieline = std::max(linePts->front()->y(),linePts->back()->y()); + } + // Neither mode is selected, so this is an incorrect mode for this RubberBandTool + else { + return; + } + + // Write the data to the cube + writeToCube(iesamp, issamp, ieline, isline, linePts); + if(linePts) delete linePts; + } + /** + * This is a slot called when any mouse button is released inside of a + * viewport. + * + * @param p input The point under the cursor + * + * @param m input Mouse button released (left,middle,right) + * + * @history 2007-03-02 Tracie Sucharski - Reopen cube read/write + * Workspace::addCubeViewport was opening cube + * read/write, changed to open read only so that + * the cube date was not changed unless EditTool + * is invoked. + * @history 2007-02-26 Tracie Sucharski - Remove test for off image editing. + * It is no longer needed since the bug in the + * Cube class is fixed. + * @history 2008-05-23 Noah Hilt - Removed the rectangle and + * start/end line functionality from + * the mouseButtonRelease and moved + * it to the rubberBandComplete + * method. + */ + void EditTool::mouseButtonRelease(QPoint p, Qt::MouseButton m) { + MdiCubeViewport *vp = cubeViewport(); + if (vp == NULL) return; + if(p_valTypeComboBox->currentIndex() == UserDn && p_dnLineEdit->text() == "" && m != Qt::RightButton) return; + // If cube readonly try to open read/write + if (vp->cube()->IsReadOnly()) { + // ReOpen cube as read/write + // If cube readonly print error + try { + vp->cube()->ReOpen("rw"); + } + catch ( Isis::iException &e ) { + QMessageBox::information((QWidget *)parent(),"Error","Cannot open cube read/write"); + return; + } + } + if (vp->isColor()) { + QMessageBox::information((QWidget *)parent(), + "Error","Cannot edit in color mode"); + return; + } + + int issamp,isline,iesamp,ieline; + double ssamp,sline,esamp,eline; + + // If right mouse button, pick up dn value under the cursor which will be + // used as the edit value. + if (m == Qt::RightButton && p_valTypeComboBox->currentIndex() == UserDn) { + vp->viewportToCube(p.x(),p.y(),ssamp,sline); + issamp = (int) (ssamp + 0.5); + isline = (int) (sline + 0.5); + Isis::Brick *pntBrick = new Isis::Brick(1,1,1,vp->cube()->PixelType()); + pntBrick->SetBasePosition(issamp,isline,vp->grayBand()); + vp->cube()->Read(*pntBrick); + p_dn = (*pntBrick)[0]; + p_dnLineEdit->setText(QString::number(p_dn)); + delete pntBrick; + return; + } + + else if (p_shapeComboBox->currentIndex() == Point || p_shapeComboBox->currentIndex() == HorizLine || + p_shapeComboBox->currentIndex() == VertLine){ + vp->viewportToCube(p.x(),p.y(),ssamp,sline); + esamp = ssamp; + eline = sline; + if ((ssamp < 0.5) || (sline < 0.5) || + (ssamp > vp->cubeSamples()+0.5) || (sline > vp->cubeLines()+0.5)) { + QApplication::beep(); + return; + } + issamp = (int) (ssamp + 0.5); + isline = (int) (sline + 0.5); + iesamp = issamp; + ieline = isline; + if (p_shapeComboBox->currentIndex() == HorizLine) { + issamp = 1; + iesamp = vp->cube()->Samples(); + } + if (p_shapeComboBox->currentIndex() == VertLine) { + isline = 1; + ieline = vp->cube()->Lines(); + } + // Write the changes to the cube. + writeToCube(iesamp, issamp, ieline, isline, NULL); + } + } + + /** + * + * + * @param iesamp input + * @param issamp input + * @param ieline input + * @param isline input + * @param linePts input If the input data is a line, this + * will be the list of points in the + * line. + */ + void EditTool::writeToCube(int iesamp, int issamp, int ieline, int isline, QList *linePts) { + Isis::Brick *brick = NULL; + try { + MdiCubeViewport *vp = cubeViewport(); + + int nsamps = iesamp - issamp + 1; + int nlines = ieline - isline + 1; + + brick = new Isis::Brick(nsamps,nlines,1,vp->cube()->PixelType()); + brick->SetBasePosition(issamp,isline,vp->grayBand()); + vp->cube()->Read(*brick); + + // Save for Undo operation, See if viewport has undo entry. If it + // does, get Stack, push new undo and put stack back in hash. If not, + // create stack, push new undo and add to hash. + QStack *s; + if (p_undoEdit.contains(vp)) { + s = p_undoEdit.value(vp); + } + else { + s = new QStack; + } + s->push(brick); + p_undoEdit[vp] = s; + + //Remove any redo stack if it exists + if (p_redoEdit.contains(vp)) { + QStack *temp = p_redoEdit.value(vp); + while(!temp->isEmpty()) { + delete temp->pop(); + } + p_redoEdit.remove(vp); + p_redoButton->setEnabled(false); + } + + // no deep copy constructor so re-read brick for editing.... + brick = new Isis::Brick(nsamps,nlines,1,vp->cube()->PixelType()); + brick->SetBasePosition(issamp,isline,vp->grayBand()); + vp->cube()->Read(*brick); + + // Now that we have where, do the actual edits + if (p_shapeComboBox->currentIndex() == StartEndLine) { + for (int i=0; linePts && i<(int)linePts->size(); i++) { + QPoint *pt = (*linePts)[i]; + int is = pt->x(); + int il = pt->y(); + int brickIndex = (il - isline) * nsamps + (is - issamp); + (*brick)[brickIndex] = (double)p_dn; + } + } + else { + for (int i=0; isize(); i++) (*brick)[i] = (double)p_dn; + } + + //Signal that this cube has been changed, enable the undo and save buttons + emit cubeChanged(true); + p_undoButton->setEnabled(true); + p_saveButton->setEnabled(true); + vp->cube()->Write(*brick); + vp->cubeChanged(true); + vp->setCaption(); + + // QRect r(issamp,isline,nsamps,nlines); + QRect r(brick->Sample(),brick->Line(), + brick->SampleDimension(),brick->LineDimension()); + vp->cubeContentsChanged(r); + delete brick; + } catch(...) { + if(brick) { + delete brick; + } + //If the brick failed to initialize due to insufficient memory + QMessageBox::information((QWidget *)parent(),"Error","Not enough memory to complete this operation."); + return; + } + } + + /** + * This is a private slot called when the user selects the undo button. + * With each call, another edit is reversed. + * + */ + void EditTool::undoEdit () { + Isis::Brick *redoBrick = NULL; + try { + MdiCubeViewport *vp = cubeViewport(); + if (vp == NULL) return; + + // If viewport not in hash, beep + if (p_undoEdit.empty() || p_undoEdit.count(vp) == 0) { + QApplication::beep(); + return; + } + + // If cube readonly print error + if (vp->cube()->IsReadOnly()) { + QMessageBox::information((QWidget *)parent(),"Error","Cube is Read Only"); + return; + } + + + QStack *s = p_undoEdit.value(vp); + Isis::Brick *brick = s->top(); + + //Write the current cube to the a brick and add it to the redo stack + redoBrick = new Isis::Brick(brick->SampleDimension(),brick->LineDimension(),1,vp->cube()->PixelType()); + redoBrick->SetBasePosition(brick->Sample(),brick->Line(),vp->grayBand()); + vp->cube()->Read(*(redoBrick)); + + QStack *redo; + if (p_redoEdit.contains(vp)) { + redo = p_redoEdit.value(vp); + } + else { + redo = new QStack; + } + redo->push(redoBrick); + p_redoEdit[vp] = redo; + + // Write the saved brick to the cube + vp->cube()->Write(*(brick)); + + // Update the viewport + QRect r(brick->Sample(),brick->Line(), + brick->SampleDimension(),brick->LineDimension()); + vp->cubeContentsChanged(r); + + //Enable the redo button since we have made an undo + p_redoButton->setEnabled(true); + p_saveButton->setEnabled(true); + emit cubeChanged(true); + vp->cubeChanged(true); + vp->setCaption(); + + //Pop this element off the stack, if the undo stack is empty, disable the undo button + s->pop(); + if (s->empty()) { + p_undoButton->setEnabled(false); + } + delete brick; + } catch (...) { + if(redoBrick) { + delete redoBrick; + } + //If the brick failed to initialize due to insufficient memory + QMessageBox::information((QWidget *)parent(),"Error","Not enough memory to complete this operation."); + return; + } + } + + /** + * This method is used to discard any changes made to this viewport. If the + * viewport has been saved, then it will only discard changes to that save + * point. + * + * @param vp + */ + void EditTool::undoAll(MdiCubeViewport *vp) { + try{ + if (vp == NULL) return; + + // If cube readonly print error + if (vp->cube()->IsReadOnly()) { + QMessageBox::information((QWidget *)parent(),"Error","Cube is Read Only"); + return; + } + + QStack *undo; + QStack *redo; + int marker = 0; + //If edits have been made + if (p_undoEdit.contains(vp)) { + undo = p_undoEdit.value(vp); + + //If a save has been made + if(p_saveMarker.contains(vp)) { + marker = p_saveMarker.value(vp); + } + + //Undo up to the save point + for(int i = undo->count()-1; i >= marker; i--) { + Isis::Brick *brick = undo->at(i); + + // Write the saved brick to the cube + vp->cube()->Write(*(brick)); + } + + //If undos have been made past the save point, we need to redo them + //Set the marker to the correct index + marker = marker - undo->count(); + } + + //If undos have been made + if (p_redoEdit.contains(vp)) { + redo = p_redoEdit.value(vp); + + //If undos have been made past a save point, we need to redo them + for(int i = redo->count()-1; i >= redo->count() - marker; i--) { + Isis::Brick *brick = redo->at(i); + + // Write the saved brick to the cube + vp->cube()->Write(*(brick)); + } + } + } catch(...) { + //If the brick failed to initialize due to insufficient memory + QMessageBox::information((QWidget *)parent(),"Error","Not enough memory to complete this operation."); + return; + } + } + + /** + * This method is called to redo any edit operations that have been undone. + * + */ + void EditTool::redoEdit() { + Isis::Brick *undoBrick = NULL; + try { + MdiCubeViewport *vp = cubeViewport(); + if (vp == NULL) return; + + // If viewport not in hash, beep + if (p_redoEdit.empty() || p_redoEdit.count(vp) == 0) { + QApplication::beep(); + return; + } + + // If cube readonly print error + if (vp->cube()->IsReadOnly()) { + QMessageBox::information((QWidget *)parent(),"Error","Cube is Read Only"); + return; + } + + QStack *s = p_redoEdit.value(vp); + Isis::Brick *brick = s->top(); + + //Write the current cube to the a brick and add it to the undo stack + undoBrick = new Isis::Brick(brick->SampleDimension(),brick->LineDimension(),1,vp->cube()->PixelType()); + undoBrick->SetBasePosition(brick->Sample(),brick->Line(),vp->grayBand()); + vp->cube()->Read(*(undoBrick)); + + QStack *undo; + if (p_undoEdit.contains(vp)) { + undo = p_undoEdit.value(vp); + } + else { + undo = new QStack; + } + undo->push(undoBrick); + p_undoEdit[vp] = undo; + + // Write the saved brick to the cube + vp->cube()->Write(*(brick)); + // Update the viewport + + QRect r(brick->Sample(),brick->Line(), + brick->SampleDimension(),brick->LineDimension()); + vp->cubeContentsChanged(r); + + p_undoButton->setEnabled(true); + p_saveButton->setEnabled(true); + vp->cubeChanged(true); + vp->setCaption(); + emit cubeChanged(true); + + //Pop this element off the stack, if the redo stack is empty, disable the redo button + s->pop(); + if (s->empty()) { + p_redoButton->setEnabled(false); + } + delete brick; + } catch(...) { + if(undoBrick) { + delete undoBrick; + } + //If the brick failed to initialize due to insufficient memory + QMessageBox::information((QWidget *)parent(),"Error","Not enough memory to complete this operation."); + return; + } + } + + /** + * This method saves by removing any undo history for the + * viewport vp and reopening the cube. These changes are + * finalized! There is no undoing after a save has been made. + * + * @param vp + */ + void EditTool::save(MdiCubeViewport *vp) { + if (vp == NULL) return; + //Set the 'save point' for this viewport, if we undo discard any changes + //We will only discard to this point + int marker; + if(p_undoEdit.contains(vp)) { + marker = p_undoEdit.value(vp)->count(); + } + else { + marker = 0; + } + p_saveMarker[vp] = marker; + + p_saveButton->setEnabled(false); + vp->cubeChanged(false); + vp->setCaption(); + } + + + /** + * This is a private slot called to clean up when a viewport is destroyed. + * This viewport is removed from the undoEdit hash. + * + * @param vp input Viewport to be removed from the undo edit hash + * + */ + void EditTool::removeViewport (QObject *vp) { + // Connect destruction of CubeViewport to Remove slot to remove viewport + // from the undo and redo Hashes. + if (p_undoEdit.contains((MdiCubeViewport *) vp)) { + QStack *temp = p_undoEdit.value((MdiCubeViewport *) vp); + while(!temp->isEmpty()) { + delete temp->pop(); + } + p_undoEdit.remove((MdiCubeViewport *) vp); + } + if (p_redoEdit.contains((MdiCubeViewport *) vp)) { + QStack *temp = p_redoEdit.value((MdiCubeViewport *) vp); + while(!temp->isEmpty()) { + delete temp->pop(); + } + p_redoEdit.remove((MdiCubeViewport *) vp); + } + } + + + + + /** + * Convert rubber band line to points + * + * This routine takes two points (sx,sy) and (ex,ey) and determines all + * the points which make up that line segment. This is useful + * for drawing graphic on a display or image + * + * @author Jan 1 1996 Jeff Anderson, Original version + * + * @param line input Line to be converted to points + * + * @return QList* A pointer to a QList of points representing + * line + */ + QList *EditTool::LineToPoints (const QLine &line) { + MdiCubeViewport *vp = cubeViewport(); + if (vp == NULL) return new QList(); + double slope; + int i; + int x,y,xinc,yinc; + int xsize,ysize; + + + QList *points = new QList; + + int sx = line.p1().x(); + int ex = line.p2().x(); + int sy = line.p1().y(); + int ey = line.p2().y(); + if (sx > ex) { + xsize = sx - ex + 1; + xinc = -1; + } else { + xsize = ex - sx + 1; + xinc = 1; + } + + if (sy > ey) { + ysize = sy - ey + 1; + yinc = -1; + } else { + ysize = ey - sy + 1; + yinc = 1; + } + + if (ysize > xsize) { + slope = (double) (ex - sx) / (double) (ey - sy); + y = sy; + for (i=0; i= 0 && y >= 0 && x <= vp->cubeSamples() && y <= vp->cubeLines()) { + QPoint *pt = new QPoint; + pt->setX(x); + pt->setY(y); + points->push_back(pt); + } + y += yinc; + } + } + else if (xsize == 1) { + //If the x or y coordinates are not within the cube dimensions, don't add them + if(sx >= 0 && sy >= 0 && sx <= vp->cubeSamples() && sy <= vp->cubeLines()) { + QPoint *pt = new QPoint; + pt->setX(sx); + pt->setY(sy); + points->push_back(pt); + } + } + else { + slope = (double) (ey - sy) / (double) (ex - sx); + x = sx; + for (i=0; i= 0 && y >= 0 && x <= vp->cubeSamples() && y <= vp->cubeLines()) { + QPoint *pt = new QPoint; + pt->setX(x); + pt->setY(y); + points->push_back(pt); + } + x += xinc; + } + } + + return points; + } + + /** + * This method sets up the RubberBandTool depending on which + * mode is enabled. If a valid RubberBandTool mode is not + * enabled the RubberBandTool is disabled. + * + */ + + void EditTool::enableRubberBandTool() { + int index = p_shapeComboBox->currentIndex(); + if (index == 3) { + RubberBandTool::enable(RubberBandTool::Line); + } else if (index == 4) { + RubberBandTool::enable(RubberBandTool::Rectangle); + } else { + RubberBandTool::disable(); + } + } +} diff --git a/isis/src/qisis/objs/EditTool/EditTool.h b/isis/src/qisis/objs/EditTool/EditTool.h new file mode 100644 index 0000000000000000000000000000000000000000..db3cfce63ae4c4553e07ad73f7544a5e1d8dd0b7 --- /dev/null +++ b/isis/src/qisis/objs/EditTool/EditTool.h @@ -0,0 +1,151 @@ +#ifndef EditTool_h +#define EditTool_h + +/** + * @file + * $Revision: 1.8 $ + * $Date: 2010/06/28 09:00:39 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "Tool.h" + + +// FIXME: remove these two includes! +#include +#include + + +class QToolButton; +class QLine; +class QLineEdit; +class QComboBox; + +namespace Isis { + class Brick; + class Cube; +} + +namespace Qisis { + class MdiCubeViewport; + + /** + * @brief Interactive image edit tool + * + * This tool is part of the Qisis namespace and allows interactive editing + * of displayed images. + * + * @ingroup Visualization Tools + * + * @author 2006-06-09 Tracie Sucharski + * + * @internal + * @todo The following fix is a bandaid- there is probably a bug in + * tiling class, buffer class? The following fix is for rectangle + * option only, the start/end line still has a problem when going + * off the right side of image. + * @history 2006-10-20 Tracie Sucharski - If rubberband for rectangle + * option goes off the right side + * or bottom of image, set + * esamp/eline to image + * nsamps/nlines. + * @history 2008-05-23 Noah Hilt - Added RubberBandToolfunctionality and + * changed the mouseButtonReleased method. Also added a writeToCube + * method that is used by both the rubberBandComplete and + * mouseButtonRelease methods. + * @history 2008-06-19 Noah Hilt - Added methods and signals for saving and + * discarding changes to the current cube. + * @history 2010-06-26 Eric Hyer - uses MdiCubeViewport instead of + * CubeViewport. Fixed many include issues but some still remain! + * + */ + class EditTool : public Qisis::Tool { + Q_OBJECT + + signals: + void cubeChanged(bool); //!< Emitted when cube changed + void save(); //!< Emitted when cube should be saved + void saveAs(); //!< Emitted when cube should be saved as another file + + public: + EditTool (QWidget *parent); + + /** + * Enum for possible shapes + */ + enum EditShape { + Point, //!< point + HorizLine,//!< horizontal line + VertLine,//!< vertical line + StartEndLine,//!< start-end line + Rectangle//!< rectangle + }; + + + /** + * Enum for DN values + */ + enum ReplacementValue { + UserDn,//!< User Selected DN value + Null,//!< Null DN value + Hrs,//!< High representation saturation DN value + Lrs,//!< Low representation saturation DN value + His,//!< High instrument saturation DN value + Lis//!< Low instrument satruation DN value + }; + + protected: +// QString menuName() const { return "&Options"; }; + QAction *toolPadAction(ToolPad *pad); + QWidget *createToolBarWidget (QStackedWidget *active); + void updateTool(); + + protected slots: + void mouseButtonRelease(QPoint p, Qt::MouseButton m); + virtual void enableRubberBandTool(); + void rubberBandComplete(); + + private slots: + void selectValType(int index); + void changeDn(); + void undoEdit(); + void undoAll(MdiCubeViewport *vp); + void redoEdit(); + void save(MdiCubeViewport *vp); + void removeViewport(QObject *vp); + + private: + QList *LineToPoints(const QLine & line); + void writeToCube(int iesamp, int issamp, int ieline, int isline, QList *linePts); + QComboBox *p_shapeComboBox; //!< Shape combobox + QComboBox *p_valTypeComboBox; //!< Value type combobox + QLineEdit *p_dnLineEdit; //!< DN edit line + QToolButton *p_undoButton; //!< Undo button + QToolButton *p_redoButton; //!< Redo button + QToolButton *p_saveButton; //!< Save button + QToolButton *p_saveAsButton; //!< Save as button + + double p_dn; //!< DN value + + QMap *> p_undoEdit; //!< Viewport to brick map for undo + QMap *> p_redoEdit; //!< Viewport to brick map for redo + QMap p_saveMarker; //!< Marker for last save + }; +}; + +#endif diff --git a/isis/src/qisis/objs/EditTool/Makefile b/isis/src/qisis/objs/EditTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/EditTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/FileDialog/FileDialog.cpp b/isis/src/qisis/objs/FileDialog/FileDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4df4257230b2dc739f4555ac1890abbcab118219 --- /dev/null +++ b/isis/src/qisis/objs/FileDialog/FileDialog.cpp @@ -0,0 +1,197 @@ +#include "FileDialog.h" +#include +#include + +namespace Qisis { + FileDialog::FileDialog(QString title, QStringList &filterList, QDir &directory, QWidget *parent) : + QFileDialog(parent), p_filterList(filterList), p_dir(directory) { + + p_parent = parent; + + this->setWindowTitle(title); + this->setFileMode(QFileDialog::ExistingFiles); + if(parent != 0){ + parent->installEventFilter(this); + p_appName = parent->windowTitle().toStdString(); + } + connect(this,SIGNAL(accepted()),this,SLOT(sendSignal())); + + //this->setFilters(p_filterList); + this->setNameFilters(p_filterList); + + this->setViewMode(QFileDialog::Detail); + if(directory.exists()) { + this->setDirectory(directory); + } else { + this->setDirectory(QDir::current()); + } + + p_comboBoxes = this->findChildren(); + p_comboBoxes[0]->setEditable(true); + p_comboBoxes[1]->setEditable(true); + + QLineEdit *lineEdit = p_comboBoxes[1]->lineEdit(); + //p_comboBoxes[1]->setEditText("Choose a filter or create your own."); + disconnect(lineEdit,0,0,0); + connect(lineEdit,SIGNAL(textChanged(const QString &)),p_comboBoxes[1], + SIGNAL(activated(const QString &))); + connect(lineEdit,SIGNAL(editingFinished()),this, + SLOT(saveFilter())); + + + p_allPButtons = this->findChildren(); + for(int i = 0; itext().contains("Open", Qt::CaseInsensitive)) { + connect(p_allPButtons[i],SIGNAL(pressed()),this,SLOT(done())); + } + if(p_allPButtons[i]->text()== "Cancel") { + ///I had to disconnect this buttons signal because I overwrote the + //done method from QDialog which is what this used to be connected to. + connect(p_allPButtons[i],SIGNAL(pressed()),this,SLOT(cancel())); + } + } + + readSettings(); + } + + + /** + * This is where we actually set the user editable filters and + * remember them + * + */ + void FileDialog::saveFilter(){ + p_allPButtons[0]->setDefault(false); + if(!p_filterList.contains(p_comboBoxes[1]->currentText())) { + p_filterList.insert(0, p_comboBoxes[1]->currentText()); + this->setNameFilters(p_filterList); + } + + } + + + /** + * This saves the directory that the user selected the file from + * so it can open to this directory next time. + * Also, emits the signal to open the selected file. + */ + void FileDialog::sendSignal(){ + p_dir=this->directory(); + QStringList fileList = this->selectedFiles(); + QStringList::const_iterator it = fileList.begin(); + while (it != fileList.end()) { + if (!(*it).isEmpty()) { + emit fileSelected(*it); + ++it; + } + } + //p_fileList = fileList; + } + + + /** + * This method is overridden so that we can be sure to write the + * current settings of the Main window. + * + * @param event + */ + void FileDialog::closeEvent(QCloseEvent *event) { + writeSettings(); + + } + + + /** + * Called when the user presses OK. + * + */ + void FileDialog::done(){ + close(); + sendSignal(); + + } + + + /** + * Called when user presses cancel. + * + */ + void FileDialog::cancel(){ + close(); + p_dir=this->directory(); + } + + /** + * This method is called from the constructor so that when the + * Main window is created, it know's it's size and location. + * + */ + void FileDialog::readSettings(){ + if(p_appName == "") { + p_appName = this->windowTitle().toStdString(); + } + + std::string instanceName = this->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/"+ p_appName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()),QSettings::NativeFormat); + QPoint pos = settings.value("pos", QPoint(300, 100)).toPoint(); + QSize size = settings.value("size", QSize(355, 350)).toSize(); + resize(size); + move(pos); + } + + /** + * This method is called when the File Dialog is closed or + * hidden to write the size and location settings to a config + * file in the user's home directory. + * + */ + void FileDialog::writeSettings() { + /*We do not want to write the settings unless the window is + visible at the time of closing the application*/ + if(!this->isVisible()) return; + + if(p_appName == "") { + p_appName = this->windowTitle().toStdString(); + } + + std::string instanceName = this->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/"+ p_appName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()),QSettings::NativeFormat); + settings.setValue("pos", pos()); + settings.setValue("size", size()); + + } + + /** + * This event filter is installed on the parent of this window. + * When the user closes the main window of the application, the + * FileDialog will write their settings even though they did not + * receive the close event themselves. + * + * @param o + * @param e + * + * @return bool + */ + bool FileDialog::eventFilter(QObject *o,QEvent *e) { + + switch (e->type()) { + case QEvent::Close:{ + writeSettings(); + + } + case QEvent::Hide:{ + writeSettings(); + + } + default: { + return false; + } + } + } + +} + diff --git a/isis/src/qisis/objs/FileDialog/FileDialog.h b/isis/src/qisis/objs/FileDialog/FileDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..395317f5689a9b4caa02fd859206cebc52a3a380 --- /dev/null +++ b/isis/src/qisis/objs/FileDialog/FileDialog.h @@ -0,0 +1,65 @@ +#ifndef FileDialog_h +#define FileDialog_h +#include +#include +#include +#include "Filename.h" +#include "FileTool.h" + +namespace Qisis { + /** + * @brief Class for browsing cubes. + * + * @ingroup Visualization Tools + * + * @author Stacy Alley + * + * @internal + * + * @history 2008-01-18 Stacy Alley - Changed the constructor to + * accept a QStringList which serves as the default filters for + * the file dialog boxes. + * + * @history 2008-01-28 Stacy Alley - Changed the constructor + * again to accept a QDir which is the default directory + * the file dialog box should point to. + */ + + + class FileDialog : public QFileDialog { + Q_OBJECT + public: + FileDialog (QString title, QStringList &filterList, QDir &directory, QWidget *parent=0); + void closeEvent(QCloseEvent *event); + void readSettings(); + void writeSettings(); + + protected: + bool eventFilter(QObject *o,QEvent *e); + + protected slots: + void sendSignal(); + void done(); + void cancel(); + void saveFilter(); + + signals: + void fileSelected(QString); + void filterSelected(QString); + + private: + QList p_comboBoxes; + QList p_allPButtons; + std::string p_appName; + QDialog *p_mainDialog; + QWidget *p_parent; + QPushButton *p_filterButton; + QLineEdit *p_filterLine; + QStringList &p_filterList; + QDir &p_dir; + //QStringList &p_fileList; + + }; +}; + +#endif diff --git a/isis/src/qisis/objs/FileDialog/Makefile b/isis/src/qisis/objs/FileDialog/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/FileDialog/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/FileTool/FileTool.cpp b/isis/src/qisis/objs/FileTool/FileTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..946a83e81dcf263877871f69948a2bbb8938ca79 --- /dev/null +++ b/isis/src/qisis/objs/FileTool/FileTool.cpp @@ -0,0 +1,620 @@ +#include "FileTool.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Brick.h" +#include "BrowseDialog.h" +#include "CubeAttribute.h" +#include "FileDialog.h" +#include "MainWindow.h" +#include "MdiCubeViewport.h" +#include "OriginalLabel.h" +#include "Workspace.h" + +namespace Qisis { + /** + * Constructs a FileTool object. + * + * @param parent + * @internal + * @history 2008-12-10 Jeannie Walldren - Added "What's this?" + * and shortcut to "Save" action + */ + FileTool::FileTool (QWidget *parent) : Qisis::Tool(parent) { + p_parent = parent; + p_dir = "/thisDirDoesNotExist!"; + p_open = new QAction(parent); + p_open->setShortcut(Qt::CTRL+Qt::Key_O); + p_open->setText("&Open..."); + p_open->setIcon(QPixmap(toolIconDir()+"/fileopen.png")); + p_open->setToolTip("Open cube"); + QString whatsThis = + "Function: Open an Isis cube in new viewport \ +

    Shortcut: Ctrl+O\n

    \ +

    Hint: Use Ctrl or Shift in file dialog to open \ + multiple cubes

    "; + p_open->setWhatsThis(whatsThis); + connect(p_open,SIGNAL(activated()),this,SLOT(open())); + + p_browse = new QAction(parent); + p_browse->setShortcut(Qt::CTRL+Qt::Key_B); + p_browse->setText("&Browse..."); + p_browse->setToolTip("Browse cubes"); + whatsThis = + "Function: Browse a Isis cubes in new viewport \ +

    Shortcut: Ctrl+B\n

    "; + p_browse->setWhatsThis(whatsThis); + connect(p_browse,SIGNAL(activated()),this,SLOT(browse())); + + p_save = new QAction(parent); + p_save->setShortcut(Qt::CTRL+Qt::Key_S); + p_save->setText("&Save"); + p_save->setIcon(QPixmap(toolIconDir()+"/filesave.png")); + p_save->setToolTip("Save"); + whatsThis = + "Function: Save changes to the current Cube \ +

    Shortcut: Ctrl+S

    "; + p_save->setWhatsThis(whatsThis); + connect(p_save,SIGNAL(activated()),this,SLOT(confirmSave())); + p_save->setEnabled(false); + + p_saveAs = new QAction(parent); + p_saveAs->setText("Save &As..."); + p_saveAs->setIcon(QPixmap(toolIconDir()+"/filesaveas.png")); + p_saveAs->setToolTip("Save As"); + whatsThis = + "Function: Save the current Cube to the specified location"; + p_saveAs->setWhatsThis(whatsThis); + connect(p_saveAs,SIGNAL(activated()),this,SLOT(saveAs())); + + p_exportView = new QAction(parent); + p_exportView->setText("Export View"); + p_exportView->setIcon(QPixmap(toolIconDir()+"/fileexport.png")); + p_exportView->setToolTip("Export View"); + whatsThis = + "Function: Save visible contents of the active \ + viewport as a png, jpg, tiff \ +

    Hint: Your local installation of Qt may not support \ + all formats. Reinstall Qt if necessary

    "; + p_exportView->setWhatsThis(whatsThis); + connect(p_exportView,SIGNAL(activated()),this,SLOT(exportView())); + p_exportView->setEnabled(false); + + p_print = new QAction(parent); + p_print->setText("&Print..."); + p_print->setShortcut(Qt::CTRL+Qt::Key_P); + p_print->setIcon(QPixmap(toolIconDir()+"/fileprint.png")); + p_print->setToolTip("Print"); + whatsThis = + "Function: Print visible contents of the active viewport \ +

    Shortcut: Ctrl+P"; + p_print->setWhatsThis(whatsThis); + connect(p_print,SIGNAL(activated()),this,SLOT(print())); + p_print->setEnabled(false); + + p_closeAll = new QAction(parent); + p_closeAll->setText("&Close All..."); + p_closeAll->setToolTip("Close All"); + whatsThis = + "Function: Close all cube viewports."; + p_closeAll->setWhatsThis(whatsThis); + + p_exit = new QAction(parent); + p_exit->setShortcut(Qt::CTRL+Qt::Key_Q); + p_exit->setText("E&xit"); + p_exit->setIcon(QPixmap(toolIconDir() + "/fileclose.png")); + whatsThis = + "Function: Quit qview \ +

    Shortcut: Ctrl+Q

    "; + p_exit->setWhatsThis(whatsThis); + connect(p_exit,SIGNAL(activated()),this,SLOT(exit())); + + p_lastDir.clear(); + p_lastViewport = NULL; + + activate(true); + } + + /** + * Adds the file tool's actions to the menu + * + * @param menu + */ + void FileTool::addTo (QMenu *menu) { + menu->addAction(p_open); + menu->addAction(p_browse); + menu->addAction(p_save); + menu->addAction(p_saveAs); + menu->addAction(p_exportView); + menu->addAction(p_print); + menu->addAction(p_closeAll); + menu->addAction(p_exit); + } + + /** + * Connects the fileSelected signal to the workspace's addCubeViewport slot + * + * @param ws + */ + void FileTool::addTo (Workspace *ws) { + p_workSpace = ws; + Tool::addTo(ws); + connect (this,SIGNAL(fileSelected(QString)), + ws,SLOT(addCubeViewport(QString))); + + connect(p_closeAll,SIGNAL(activated()),ws,SLOT(closeAllSubWindows())); + } + + /** + * Adds the file tool's actions to the permanent toolbar + * + * @param perm + */ + void FileTool::addToPermanent (QToolBar *perm) { + perm->addAction(p_open); + perm->addAction(p_exportView); + perm->addAction(p_print); + perm->addAction(p_exit); + } + + /** + * This method allows the user to navigate and open a cube with a file dialog. + * + */ + void FileTool::open () { + //Set up the list of filters that are default with this dialog. + if(!p_filterList.contains("Isis cubes (*.cub)")) { + p_filterList.append("Isis cubes (*.cub)"); + p_filterList.append("All files (*)"); + } + if(!p_dir.exists()) { + p_dir = QDir::current(); + } + + FileDialog *fileDialog = new FileDialog("Open", p_filterList, p_dir, (QWidget *)parent()); + fileDialog->show(); + connect (fileDialog,SIGNAL(fileSelected(QString)), + p_workSpace,SLOT(addCubeViewport(QString))); + } + + /** + * This method allows the user to navigate and browse cubes with a file dialog . + * + */ + void FileTool::browse(){ + //Set up the list of filters that are default with this dialog. + if(!p_filterList.contains("Isis cubes (*.cub)")) { + p_filterList.append("Isis cubes (*.cub)"); + p_filterList.append("All files (*)"); + } + if(!p_dir.exists()) { + p_dir = QDir::current(); + } + BrowseDialog *browser = new BrowseDialog("Browse", p_filterList, p_dir, (QWidget *)parent()); + browser->show(); + connect (browser,SIGNAL(fileSelected(QString)), + p_workSpace,SLOT(addBrowseView(QString))); + } + + /** + * This method asks the user to confirm if they want to finalize their saved + * changes. + * + */ + void FileTool::confirmSave() { + if(QMessageBox::question( + p_parent, + tr("Save File?"), + tr("Are you sure you want to save this file?"), + tr("&Save"), tr("&Cancel"), + QString(), 0, 1)) { + return; + } + else { + save(); + } + } + + /** + * This method saves any changes made to the current cube, these + * changes are finalized! There is no undoing once a save has + * been made. + * + */ + void FileTool::save() { + //If the current viewport is null (safety check), return from this method + if (cubeViewport() == NULL) { + QMessageBox::information((QWidget *)parent(),"Error","No active cube to save"); + return; + } + //Emit a signal to notify other objects that this cube has been saved + emit saveChanges(cubeViewport()); + //Disable the save action + p_save->setEnabled(false); + + //Essentially, closing the cube saves it's changes, and we want to keep it open, + //so reopen the current cube! + cubeViewport()->cube()->ReOpen("rw"); + } + + /** + * This method essentially creates a new cube, copies the + * current cube (and any changes made to it) to the new cube, + * reverses all changes NOT saved to the current cube and closes + * it. Finally it sets the cubeviewport's cube to the new saved + * cube. + * + */ + void FileTool::saveAs() { + //If the current viewport is null (safety check), return from this method + if (cubeViewport() == NULL) { + QMessageBox::information((QWidget *)parent(),"Error","No active cube to save"); + return; + } + //Get the new cube's filename + QString output = + QFileDialog::getSaveFileName((QWidget *)parent(), + "Choose output file", + p_lastDir, + QString("Cubes (*.cub)")); + //If the filename is empty, return + if (output.isEmpty()) return; + + //If the filename is the same as the current cube's filename, just save it + if(output.toStdString().compare(cubeViewport()->cube()->Filename()) == 0) { + save(); + return; + } + + //Save the current cube's changes by reopening it, and open an input cube + //from the current cube's location + Isis::Cube *icube = new Isis::Cube(); + cubeViewport()->cube()->ReOpen(); + icube->Open(cubeViewport()->cube()->Filename(), "rw"); + + //Create the output cube and default output attribute with the output filename + Isis::CubeAttributeOutput outAtt(output.toStdString()); + Isis::Cube *ocube = new Isis::Cube(); + //Propogate all labels, tables, blobs, etc from the input to output cube + try { + ocube->SetDimensions(icube->Samples(),icube->Lines(),icube->Bands()); + ocube->SetByteOrder(outAtt.ByteOrder()); + ocube->SetCubeFormat(outAtt.FileFormat()); + if (outAtt.DetachedLabel()) ocube->SetDetached(); + if (outAtt.AttachedLabel()) ocube->SetAttached(); + + if (outAtt.PropagatePixelType()) { + ocube->SetPixelType(icube->PixelType()); + } + else { + ocube->SetPixelType(outAtt.PixelType()); + } + + if (outAtt.PropagateMinimumMaximum()) { + if (ocube->PixelType() == Isis::Real) { + ocube->SetBaseMultiplier(0.0, 1.0); + } + else if (ocube->PixelType() >= icube->PixelType()) { + double base = icube->Base(); + double mult = icube->Multiplier(); + ocube->SetBaseMultiplier(base, mult); + } + else if ((ocube->PixelType() != Isis::Real) && + (ocube->PixelType() != Isis::UnsignedByte) && + (ocube->PixelType() != Isis::SignedWord)) { + std::string msg = "Looks like your refactoring to add different pixel types"; + msg += " you'll need to make changes here"; + throw Isis::iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + else { + std::string msg = "You've chosen to reduce your output PixelType for [" + + output.toStdString() + "] you must specify the output pixel range too"; + throw Isis::iException::Message(Isis::iException::User,msg,_FILEINFO_); + } + } + else { + // Not propagating so either the user entered or the programmer did + ocube->SetMinMax(outAtt.Minimum(), outAtt.Maximum()); + } + + int needLabBytes = icube->LabelBytesUsed() + (1024 * 6); + if (needLabBytes > ocube->LabelBytes()) { + ocube->SetLabelBytes(needLabBytes); + } + + // Allocate the cube + ocube->Create (output.toStdString()); + + // Transfer labels from the first input cube + Isis::PvlObject &incube = icube->Label()->FindObject("IsisCube"); + Isis::PvlObject &outcube = ocube->Label()->FindObject("IsisCube"); + for (int i=0; iLabel(); + for (int i=0; iRead(t); + ocube->Write(t); + } + } + + // Transfer blobs from the first input cube + inlab = *icube->Label(); + for (int i=0; iRead(t); + ocube->Write(t); + } + } + + // Transfer tables from the first input cube + inlab = *icube->Label(); + for (int i=0; iRead(ol); + ocube->Write(ol); + } + } + } + catch (Isis::iException &e) { + delete ocube; + throw; + } + // Everything was propagated okay! + + + //Start the copy process line by line + Isis::Brick ibrick(*icube,icube->Samples(),1, 1); + Isis::Brick obrick(*ocube,ocube->Samples(),1, 1); + + int numBricks; + if (ibrick.Bricks() > obrick.Bricks()) numBricks = ibrick.Bricks(); + else numBricks = obrick.Bricks(); + + // Loop and let the app programmer work with the bricks + ibrick.begin(); + obrick.begin(); + for (int i=0; iRead(ibrick); + //Copy the contents to the output cube + copy(ibrick, obrick); + ocube->Write(obrick); + ibrick++; + obrick++; + } + + //End the process and cleanup the cubes + icube->Close(); + delete icube; + ocube->Close(); + delete ocube; + + + //Reopen the input cube and discard all of the changes made to it + //and save it to it's original state + cubeViewport()->cube()->ReOpen("rw"); + emit discardChanges(cubeViewport()); + cubeViewport()->cube()->Close(); + //Open the output cube and set it to the cubeviewport + ocube = new Isis::Cube(); + ocube->Open(output.toStdString(), "rw"); + cubeViewport()->setCube(ocube); + + //Emit a signal to other objects that a save has been made + emit saveChanges(cubeViewport()); + //Disable the save action + p_save->setEnabled(false); + + p_lastDir = output; + + } + + /** + * This method copies from the input buffer to the output buffer + * + * @param in + * @param out + */ + void FileTool::copy(Isis::Buffer &in, Isis::Buffer &out) { + out.Copy(in); + } + + /** + * This slot emits a signal to discard all changes to the + * current viewport + * + */ + void FileTool::discard() { + emit discardChanges(cubeViewport()); + } + + /** + * This method allows the user to export the current view as an image file. + * + */ + void FileTool::exportView () { + if (cubeViewport() == NULL) { + QMessageBox::information((QWidget *)parent(),"Error","No active cube to export"); + return; + } + + QString output = + QFileDialog::getSaveFileName((QWidget *)parent(), + QString("Choose output file"), + p_lastDir, + QString("PNG (*.png);;JPG (*.jpg);;TIF (*.tif)")); + if (output.isEmpty()) return; + + p_lastDir = output; + + QString format = QFileInfo(output).suffix(); + + if(format.isEmpty()) { + if(output.endsWith('.')) { + output.append(QString("png")); + } + else { + output.append(QString(".png")); + } + } + else if(format.compare("png", Qt::CaseInsensitive) && + format.compare("jpg", Qt::CaseInsensitive) && + format.compare("tif", Qt::CaseInsensitive)) { + + QMessageBox::information((QWidget *)parent(),"Error", format + " is an invalid extension."); + return; + } + + QPixmap pm = QPixmap::grabWidget(cubeViewport()->viewport()); + + //if (!cubeViewport()->pixmap().save(output,format.toStdString().c_str())) { + + if (!pm.save(output)) { + QMessageBox::information((QWidget *)parent(),"Error","Unable to save " + output); + return; + } + } + + /** + * This method allows the user to print the current viewport. + * + */ + void FileTool::print () { + // Is there anything to print + if (cubeViewport() == NULL) { + QMessageBox::information((QWidget *)parent(),"Error","No active cube to print"); + return; + } + + // Initialize a printer + static QPrinter *printer = NULL; + if (printer == NULL) printer = new QPrinter; + printer->setPageSize(QPrinter::Letter); + printer->setColorMode(QPrinter::GrayScale); + if (cubeViewport()->isColor()) printer->setColorMode(QPrinter::Color); + + QPrintDialog printDialog(printer,(QWidget *)parent()); + if (printDialog.exec() == QDialog::Accepted) { + // Get display widget as a pixmap and convert to an image + QPixmap pixmap = QPixmap::grabWidget(cubeViewport()->viewport()); + QImage img = pixmap.toImage(); + + // C++ Gui Programmign with Qt, page 201 + QPainter painter(printer); + QRect rect = painter.viewport(); + QSize size = img.size(); + size.scale(rect.size(),Qt::KeepAspectRatio); + painter.setViewport(rect.x(),rect.y(), + size.width(),size.height()); + painter.setWindow(img.rect()); + painter.drawImage(0,0,img); + } + } + + /** + * Try to close all open cubes and save/discard if necessary. + */ + bool FileTool::closeAll() { + // Close all cubes + // We must create a temporary list. If not the actual + // list size gets modified when a close occurs and not all + // windows were being closed. + MdiCubeViewport *d; + QVector< Qisis::MdiCubeViewport * > tempList(*cubeViewportList()); + for (int i = 0; i < (int)tempList.size(); i++) { + d = tempList.at(i); + //Set the current viewport to the one being closed + setCubeViewport(d); + + //If the user cancels the close operation, delete any viewports + //that WERE closed and set the viewportlist to the temp list and return + if(!d->parentWidget()->close()) { + //tempList.erase(tempList.begin(), tempList.begin() + i); + //cubeViewportList()->assign(tempList.begin(), tempList.end()); + return false; + } + } + return true; + } + + /** + * Exit the program, this slot called when the exit is chosen from the File menu + * + * @internal + * @history 2007-02-13 Tracie Sucharski, Close all cubes before exiting + */ + void FileTool::exit() { + if(closeAll()) { + /*This is OK to cast the p_parent because we know it's sub-subclassed from + *Qisis::MainWindow and we know that Qisis::MainWindow has a close method*/ + ((MainWindow*)p_parent)->close(); + qApp->quit(); + } + } + + /** + * This slot enables or disables save and save as. + * + * @param enable + */ + void FileTool::enableSave(bool enable) { + p_save->setEnabled(enable); + } + + /** + * This method is called when the tool is updated. + * + */ + void FileTool::updateTool() { + if (cubeViewport() == NULL) { + if(p_lastViewport != NULL) { + p_lastViewport = NULL; + } + p_print->setEnabled(false); + p_save->setEnabled(false); + p_exportView->setEnabled(false); + } + else { + if(p_lastViewport == NULL) { + //Set the last viewport to the current viewport and connect signals to save and discard + p_lastViewport = cubeViewport(); + connect(p_lastViewport, SIGNAL(saveChanges()), this, SLOT(save())); + connect(p_lastViewport, SIGNAL(discardChanges()), this, SLOT(discard())); + } + else { + if (p_lastViewport != cubeViewport()) { + //If the viewport has changes made to it enable the save action + if(cubeViewport()->windowTitle().endsWith("*")) { + p_save->setEnabled(true); + } + //Else disable it + else { + p_save->setEnabled(false); + } + //disconnect signals from the old viewport and connect them to the new viewport + disconnect(p_lastViewport, SIGNAL(saveChanges()), this, SLOT(save())); + disconnect(p_lastViewport, SIGNAL(discardChanges()), this, SLOT(discard())); + p_lastViewport = cubeViewport(); + connect(p_lastViewport, SIGNAL(saveChanges()), this, SLOT(save())); + connect(p_lastViewport, SIGNAL(discardChanges()), this, SLOT(discard())); + } + } + p_print->setEnabled(true); + p_exportView->setEnabled(true); + } + } +} diff --git a/isis/src/qisis/objs/FileTool/FileTool.h b/isis/src/qisis/objs/FileTool/FileTool.h new file mode 100644 index 0000000000000000000000000000000000000000..4bb00fb1457454ccfe7e33719c044280c16f8bad --- /dev/null +++ b/isis/src/qisis/objs/FileTool/FileTool.h @@ -0,0 +1,95 @@ +#ifndef FileTool_h +#define FileTool_h + +#include "Tool.h" + +#include +#include + +class QAction; + + +namespace Isis { + class Brick; + class Buffer; +} + + +namespace Qisis { + class MdiCubeViewport; + + /** + * + * @internal + * @history 2008-12-10 Jeannie Walldren - Added "What's this?" + * and shortcut to "Save" action + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport + */ + class FileTool : public Tool { + Q_OBJECT + + signals: + void fileSelected(QString); //!< This signal is called when a file is selected + /** + * This signal is called when changes should be saved + * + * @param vp + */ + void saveChanges(MdiCubeViewport *vp); + /** + * This signal is called when changes should be discarded + * + * @param vp + */ + void discardChanges(MdiCubeViewport *vp); + + public: + FileTool (QWidget *parent); + void addTo (QMenu *menu); + void addTo (Workspace *ws); + void addToPermanent (QToolBar *perm); + //! Returns the open action + QAction *openAction() { return p_open; }; + //! Returns the save as action + QAction *saveAction() { return p_saveAs; }; + QStringList p_filterList; //!< Filter List + QDir p_dir; //!< Directory + QStringList p_fileList; //!< File list + + public slots: + virtual void open(); + virtual void browse(); + void print(); + void confirmSave(); + virtual void save(); + virtual void saveAs(); + virtual void exportView(); + virtual bool closeAll(); + virtual void exit(); + void enableSave(bool enable); + void discard(); + + protected: + //! Returns the menu name for the file tool + QString menuName() const { return "&File"; }; + //! Updates the tool + void updateTool(); + + private: + static void copy(Isis::Buffer &in, Isis::Buffer &out); + QAction *p_open; //!< Action to open a file + QAction *p_browse; //!< Action to browse and open files + QAction *p_print; //!< Action to print the current view + QAction *p_save; //!< Action to save the current cube + QAction *p_saveAs; //!< Action save the current cube as a user specified file + QAction *p_exportView; //!< Action to export the view as a picture + QAction *p_closeAll; + QAction *p_exit; //!< Action to exit qview + QWidget *p_parent; //!< The parent widget of this object + QString p_lastDir; //!< The last directory opened + Workspace *p_workSpace; //!< The workspace being used + MdiCubeViewport *p_lastViewport; //!< The last cubeviewport that was used + }; +}; + +#endif diff --git a/isis/src/qisis/objs/FileTool/Makefile b/isis/src/qisis/objs/FileTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/FileTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/FindTool/FindTool.cpp b/isis/src/qisis/objs/FindTool/FindTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3ffbea21c192b432653c10b263ab49e42a304bc --- /dev/null +++ b/isis/src/qisis/objs/FindTool/FindTool.cpp @@ -0,0 +1,625 @@ +#include "FindTool.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "Camera.h" +#include "MainWindow.h" +#include "MdiCubeViewport.h" +#include "Workspace.h" +#include "Projection.h" +#include "ToolPad.h" +#include "UniversalGroundMap.h" + + +using namespace Isis; + + +namespace Qisis +{ + /** + * Constructs a FindTool object + * + * @param parent + */ + FindTool::FindTool(QWidget * parent) : Qisis::Tool(parent) + { + p_dialog = NULL; + p_findPoint = NULL; + p_showDialogButton = NULL; + p_linkViewportsButton = NULL; + p_syncScale = NULL; + p_statusEdit = NULL; + p_tabWidget = NULL; + p_groundTab = NULL; + p_imageTab = NULL; + + p_lat = DBL_MAX; + p_lon = DBL_MAX; + p_samp = DBL_MAX; + p_line = DBL_MAX; + p_pointVisible = true; + + //Set up dialog box + createDialog(parent); + + // Set up find point action + p_findPoint = new QAction(parent); + p_findPoint->setShortcut(Qt::CTRL + Qt::Key_F); + p_findPoint->setText("&Find Point"); + p_findPoint->setIcon(QPixmap(toolIconDir() + "/find.png")); + p_findPoint->setEnabled(false); + } + + FindTool::~FindTool() + { + delete p_groundTab->p_latLineEdit->validator(); + delete p_groundTab->p_lonLineEdit->validator(); + } + + /** + * Creates the dialog used by this tool + * + * @param parent + */ + void FindTool::createDialog(QWidget * parent) + { + p_dialog = new QDialog(parent); + p_tabWidget = new QTabWidget(p_dialog); + p_dialog->setWindowTitle("Find Latitude/Longitude Coordinate"); + + p_groundTab = new GroundTab(); + p_imageTab = new ImageTab(); + p_tabWidget->addTab(p_imageTab, "Image"); + p_tabWidget->addTab(p_groundTab, "Ground"); + + // Create the action buttons + QPushButton * okButton = new QPushButton("Ok"); + connect(okButton, SIGNAL(clicked()), this, SLOT(handleOkClicked())); + + QPushButton * recordButton = new QPushButton("Record Point"); + connect(recordButton, SIGNAL(clicked()), this, SLOT(handleRecordClicked())); + + QPushButton * closeButton = new QPushButton("Close"); + connect(closeButton, SIGNAL(clicked()), p_dialog, SLOT(hide())); + + // Put the buttons in a horizontal orientation + QHBoxLayout * actionLayout = new QHBoxLayout(); + actionLayout->addWidget(okButton); + actionLayout->addWidget(recordButton); + actionLayout->addWidget(closeButton); + + QVBoxLayout * dialogLayout = new QVBoxLayout; + dialogLayout->addWidget(p_tabWidget); + dialogLayout->addLayout(actionLayout); + p_dialog->setLayout(dialogLayout); + } + + + /** + * The ground tab used by the dialog in the FindTool + * + * @param parent + */ + GroundTab::GroundTab(QWidget * parent) : QWidget(parent) + { + p_latLineEdit = new QLineEdit(); + p_latLineEdit->setText(""); + p_latLineEdit->setValidator(new QDoubleValidator(-90.0, 90.0, 99, parent)); + p_lonLineEdit = new QLineEdit(); + p_lonLineEdit->setText(""); + p_lonLineEdit->setValidator(new QDoubleValidator(parent)); + QLabel * latLabel = new QLabel("Latitude"); + QLabel * lonLabel = new QLabel("Longitude"); + + // Put the buttons and text field in a gridlayout + QGridLayout * gridLayout = new QGridLayout(); + gridLayout->addWidget(latLabel, 0, 0); + gridLayout->addWidget(p_latLineEdit, 0, 1); + gridLayout->addWidget(lonLabel, 1, 0); + gridLayout->addWidget(p_lonLineEdit, 1, 1); + setLayout(gridLayout); + } + + /** + * The image tab used by the dialog in the FindTool + * + * @param parent + */ + ImageTab::ImageTab(QWidget * parent) : QWidget(parent) + { + p_sampLineEdit = new QLineEdit(); + p_sampLineEdit->setText(""); + p_lineLineEdit = new QLineEdit(); + p_lineLineEdit->setText(""); + QLabel * sampleLabel = new QLabel("Sample"); + QLabel * lineLabel = new QLabel("Line"); + + // Put the buttons and text field in a gridlayout + QGridLayout * gridLayout = new QGridLayout(); + gridLayout->addWidget(sampleLabel, 0, 0); + gridLayout->addWidget(p_sampLineEdit, 0, 1); + gridLayout->addWidget(lineLabel, 1, 0); + gridLayout->addWidget(p_lineLineEdit, 1, 1); + setLayout(gridLayout); + + } + + /** + * Adds the find tool to the toolpad + * + * @param toolpad + * + * @return QAction* + */ + QAction * FindTool::toolPadAction(ToolPad * toolpad) + { + QAction * action = new QAction(toolpad); + action->setIcon(QPixmap(toolIconDir() + "/find.png")); + action->setToolTip("Find (F)"); + action->setShortcut(Qt::Key_F); + QString text = + "Function: Find a lat/lon or line/sample coordinate in this cube. \ +

    Shortcut:F

    "; + action->setWhatsThis(text); + return action; + } + + /** + * Adds the find tool to the menu + * + * @param menu + */ + void FindTool::addTo(QMenu * menu) + { + menu->addAction(p_findPoint); + } + + /** + * Creates the tool bar for the find tool + * + * @param parent + * + * @return QWidget* + */ + QWidget * FindTool::createToolBarWidget(QStackedWidget * parent) + { + QWidget * hbox = new QWidget(parent); + + p_showDialogButton = new QToolButton(hbox); + p_showDialogButton->setIcon(QPixmap(toolIconDir() + "/find.png")); + p_showDialogButton->setToolTip("Find Point"); + QString text = + "Function: Centers all linked viewports to the selected lat/lon. \ + The user can click anywhere on the image to have that point centered, or \ + they can use the shortcut or button to bring up a window that they can \ + enter a specific lat/lon position into. \ +

    Shortcut: Ctrl+F

    \ +

    Hint: This option will only work if the image has a camera \ + model or is projected, and will only center the point on images \ + where the selected lat/lon position exists.

    "; + p_showDialogButton->setWhatsThis(text); + connect(p_showDialogButton, SIGNAL(clicked()), p_dialog, SLOT(show())); + p_showDialogButton->setAutoRaise(true); + p_showDialogButton->setIconSize(QSize(22, 22)); + + p_syncScale = new QCheckBox("Sync Scale"); + p_syncScale->setToolTip("Synchronize Scale"); + text = "Function: Syncronizes the scale of all linked viewports."; + p_syncScale->setWhatsThis(text); + + p_linkViewportsButton = new QToolButton(hbox); + p_linkViewportsButton->setIcon(QPixmap(toolIconDir() + "/link_valid.png")); + p_linkViewportsButton->setToolTip("Link Georeferenced Images"); + p_linkViewportsButton->setWhatsThis("Function: Links all open images that have\ + a camera model or are map projections"); + connect(p_linkViewportsButton, SIGNAL(clicked()), this, + SLOT(handleLinkClicked())); + p_linkViewportsButton->setAutoRaise(true); + p_linkViewportsButton->setIconSize(QSize(22, 22)); + + p_togglePointVisibleButton = new QToolButton(hbox); + p_togglePointVisibleButton->setIcon(QPixmap(toolIconDir() + "/redDot.png")); + p_togglePointVisibleButton->setToolTip("Hide red dot"); + p_togglePointVisibleButton->setCheckable(true); + p_togglePointVisibleButton->setChecked(true); + connect(p_togglePointVisibleButton, SIGNAL(clicked()), this, + SLOT(togglePointVisible())); + + p_statusEdit = new QLineEdit(); + p_statusEdit->setReadOnly(true); + p_statusEdit->setToolTip("Cube Type"); + p_statusEdit->setWhatsThis("Function: Displays whether the active cube \ + is a camera model, projection, both, or none.

    \ + Hint: If the cube is 'None' the find tool \ + will not be active

    "); + + QHBoxLayout * layout = new QHBoxLayout(hbox); + layout->setMargin(0); + layout->addWidget(p_statusEdit); + layout->addWidget(p_showDialogButton); + layout->addWidget(p_linkViewportsButton); + layout->addWidget(p_togglePointVisibleButton); + layout->addWidget(p_syncScale); + layout->addStretch(1); + hbox->setLayout(layout); + + return hbox; + } + + /** + * Overriden method to update this tool - Checks if cube is open and + * checks if the image has camera and/or projection or none and sets + * the flags accordingly. Also checks whether the images are linked. + * + * @history 2010-03-24 Sharmila Prasad - Enable FindTool for no camera image + * & display status as "None" + * + * @history 2010-05-06 Eric Hyer - This method now also updates the line edits + * within the dialog. + */ + void FindTool::updateTool() + { + MdiCubeViewport * activeViewport = cubeViewport(); + + if (activeViewport == NULL) + { + p_linkViewportsButton->setEnabled(false); + p_findPoint->setEnabled(false); + p_showDialogButton->setEnabled(false); + p_syncScale->setEnabled(false); + p_statusEdit->setText("None"); + if (p_dialog->isVisible()) + { + p_dialog->close(); + } + } + else + { + p_findPoint->setEnabled(true); + p_showDialogButton->setEnabled(true); + p_statusEdit->setText("None"); + + if (cubeViewportList()->size() > 1) + { + p_linkViewportsButton->setEnabled(true); + p_syncScale->setEnabled(true); + } + else + { + p_linkViewportsButton->setEnabled(false); + p_syncScale->setEnabled(false); + } + + if (activeViewport->camera() != NULL) + { + p_statusEdit->setText("Camera"); + if (cubeViewport()->camera()->HasProjection()) + { + p_statusEdit->setText("Both"); + } + } + else + if (activeViewport->projection() != NULL) + { + p_statusEdit->setText("Projection"); + } + + // from here until the rest of this method we are just updating the + // line edits within the dialog + + UniversalGroundMap * groundMap = activeViewport->universalGroundMap(); + + if (p_samp != DBL_MAX && p_line != DBL_MAX) + { + if (groundMap && groundMap->SetImage(p_samp, p_line)) + { + QString latStr = QString::number(groundMap->UniversalLatitude()); + QString lonStr = QString::number(groundMap->UniversalLongitude()); + p_groundTab->p_latLineEdit->setText(latStr); + p_groundTab->p_lonLineEdit->setText(lonStr); + } + else + { + p_groundTab->p_latLineEdit->setText(""); + p_groundTab->p_lonLineEdit->setText(""); + } + + p_imageTab->p_sampLineEdit->setText(QString::number(p_samp)); + p_imageTab->p_lineLineEdit->setText(QString::number(p_line)); + } + else + if (p_lat != DBL_MAX && p_lon != DBL_MAX) + { + if (groundMap && groundMap->SetUniversalGround(p_lat, p_lon)) + { + QString lineStr = QString::number(groundMap->Line()); + QString sampStr = QString::number(groundMap->Sample()); + p_imageTab->p_lineLineEdit->setText(lineStr); + p_imageTab->p_sampLineEdit->setText(sampStr); + } + else + { + p_imageTab->p_lineLineEdit->setText(""); + p_imageTab->p_sampLineEdit->setText(""); + } + + p_groundTab->p_latLineEdit->setText(QString::number(p_lat)); + p_groundTab->p_lonLineEdit->setText(QString::number(p_lon)); + } + } // of if activeViewport != NULL + } + + + /** + * Actions to take when the dialog's ok button is clicked. + * + * - gets numerical info from the line edits in the dialog + * - centers and repaints the viewports (see refresh for the painting) + * - updateTool (see updateTool) + */ + void FindTool::handleOkClicked() + { + p_samp = DBL_MAX; + p_line = DBL_MAX; + p_lat = DBL_MAX; + p_lon = DBL_MAX; + + + if (p_tabWidget->tabText(p_tabWidget->currentIndex()) == "Ground") + { + p_lat = p_groundTab->p_latLineEdit->text().toDouble(); + p_lon = p_groundTab->p_lonLineEdit->text().toDouble(); + } + else + if (p_tabWidget->tabText(p_tabWidget->currentIndex()) == "Image") + { + p_line = p_imageTab->p_lineLineEdit->text().toDouble(); + p_samp = p_imageTab->p_sampLineEdit->text().toDouble(); + } + + centerLinkedViewports(); + refresh(); + updateTool(); + } + + /** + * Slot called when the record button is clicked. It creates a + * QPoint from the current line/sample in the active cube + * viewport and emits the recordPoint() signal. + * + * @return void + * @author Jeannie Walldren + * + * @internal + * @history 2010-03-08 - Jeannie Walldren - This slot was + * created to connect the recordPoint() signal to the + * AdvancedTrackTool record() slot in qview. + * @history 2010-05-06 - Eric Hyer - Modified to work with new design of this + * class + */ + void FindTool::handleRecordClicked() + { + double line = p_line; + double samp = p_samp; + + if (p_lat != DBL_MAX && p_lon != DBL_MAX) + { + MdiCubeViewport * cvp = cubeViewport(); + UniversalGroundMap * groundMap = cvp->universalGroundMap(); + + if (groundMap) + { + if (groundMap->SetUniversalGround(p_lat, p_lon)) + { + line = groundMap->Line(); + samp = groundMap->Sample(); + } + } + } + + if (line != DBL_MAX && samp != DBL_MAX) + { + int x, y; + MdiCubeViewport * cvp = cubeViewport(); + cvp->cubeToViewport(samp, line, x, y); + QPoint p(x, y); + emit recordPoint(p); + } + } + + + /** + * Handles mouse clickes in the CubeViewport. Uses the point where click + * occurred to calculate line/samp or lat/lon (if there is a camera). + * + * @param p + * @param s + */ + void FindTool::mouseButtonRelease(QPoint p, Qt::MouseButton s) + { + MdiCubeViewport * activeViewport = cubeViewport(); + UniversalGroundMap * groundMap = activeViewport->universalGroundMap(); + + double samp, line; + activeViewport->viewportToCube(p.x(), p.y(), samp, line); + + p_samp = DBL_MAX; + p_line = DBL_MAX; + p_lat = DBL_MAX; + p_lon = DBL_MAX; + + if (groundMap) + { + if (groundMap->SetImage(samp, line)) + { + p_lat = groundMap->UniversalLatitude(); + p_lon = groundMap->UniversalLongitude(); + } + } + else + { + p_samp = samp; + p_line = line; + } + + centerLinkedViewports(); + refresh(); + updateTool(); + } + + + /** + * This method paints the viewport + * + * @param vp + * @param painter + * + * @history 2010-03-24 Sharmila Prasad - Enable FindTool for no camera image + * only for Image Point (lines and Samples) + * @history 2010-05-06 Eric Hyer - points now calculated here for every + * repaint. This method is now used for all + * images, whether they have a cam or not + */ + void FindTool::paintViewport(MdiCubeViewport * vp, QPainter * painter) + { + if ((vp == cubeViewport() || (cubeViewport()->isLinked() && vp->isLinked())) + && p_pointVisible) + { + double samp = p_samp; + double line = p_line; + + UniversalGroundMap * groundMap = vp->universalGroundMap(); + + if (p_lat != DBL_MAX && p_lon != DBL_MAX && groundMap) + { + if (groundMap->SetUniversalGround(p_lat, p_lon)) + { + samp = groundMap->Sample(); + line = groundMap->Line(); + } + } + + if (samp != DBL_MAX && line != DBL_MAX) + { + // first find the point + int x, y; + vp->cubeToViewport(samp, line, x, y); + + // now that we have the point draw it! + QPen pen(Qt::red); + pen.setWidth(3); + pen.setStyle(Qt::SolidLine); + painter->setPen(pen); + painter->drawRoundRect(x - 2, y - 2, 4, 4); + } + } + } + + //! toggles visibility of the red circle + void FindTool::togglePointVisible() + { + // toggle the member boolean that specifies visibility + p_pointVisible = !p_pointVisible; + + // update the buttons text + if (p_pointVisible) + { + p_togglePointVisibleButton->setChecked(true); + p_togglePointVisibleButton->setToolTip("Hide red dot"); + } + else + { + p_togglePointVisibleButton->setChecked(false); + p_togglePointVisibleButton->setToolTip("Show red dot"); + } + + refresh(); + } + + + //! Links all cubes that have camera models or are map projections + void FindTool::handleLinkClicked() + { + MdiCubeViewport * d; + for(int i = 0; i < (int)cubeViewportList()->size(); i++) + { + d = (*(cubeViewportList()))[i]; + if(d->universalGroundMap() != NULL) + { + d->setLinked(true); + } + else + { + d->setLinked(false); + } + } + } + + + //! centers all linked viewports + void FindTool::centerLinkedViewports() + { + MdiCubeViewport * activeViewport = cubeViewport(); + bool syncScale = p_syncScale->isChecked(); + double scale = DBL_MAX; + UniversalGroundMap * groundMap = activeViewport->universalGroundMap(); + + if (syncScale && groundMap) + { + scale = activeViewport->scale() * groundMap->Resolution(); + } + + for (int i = 0; i < cubeViewportList()->size(); i++) + { + MdiCubeViewport * viewport = (*(cubeViewportList()))[i]; + groundMap = viewport->universalGroundMap(); + if (viewport == activeViewport || + (activeViewport->isLinked() && viewport->isLinked())) + { + double newScale = viewport->scale(); + + if (syncScale && groundMap) + newScale = scale / groundMap->Resolution(); + + if (p_line != DBL_MAX && p_samp != DBL_MAX) + { + viewport->setScale(newScale, p_samp, p_line); + } + else + if (p_lat != DBL_MAX && p_lon != DBL_MAX && groundMap) + { + if (groundMap->SetUniversalGround(p_lat, p_lon)) + { + double samp = groundMap->Sample(); + double line = groundMap->Line(); + viewport->setScale(newScale, samp, line); + } + } + } + } + } + + //! does a repaint for active viewport and also for any linked viewports + void FindTool::refresh() + { + MdiCubeViewport * activeVp = cubeViewport(); + for (int i = 0; i < cubeViewportList()->size(); i++) + { + MdiCubeViewport * vp = (*(cubeViewportList()))[i]; + + if (vp == activeVp || (activeVp->isLinked() && vp->isLinked())) + vp->viewport()->repaint(); + } + } +} diff --git a/isis/src/qisis/objs/FindTool/FindTool.h b/isis/src/qisis/objs/FindTool/FindTool.h new file mode 100644 index 0000000000000000000000000000000000000000..b64c210d770cd3ee9acc41ceac5a551441511799 --- /dev/null +++ b/isis/src/qisis/objs/FindTool/FindTool.h @@ -0,0 +1,164 @@ +#ifndef FindTool_h +#define FindTool_h +/** + * @file + * $Revision: 1.13 $ + * $Date: 2010/06/28 09:06:59 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +// The only includes allowed in this file are parents of classes defined here. +#include +#include "Tool.h" + +class QAction; +class QCheckBox; +class QLineEdit; +class QTabWidget; +class QToolButton; + +namespace Qisis +{ + class MdiCubeViewport; + + /** + * @brief Tool to locate a point on a cube that is projected and/or has a camera + * model + * + * This tool is part of the Qisis namespace and allows the user to locate a + * point on a cube that has been projected and/or has a camera model. It also + * allows the user to link viewports and sync scales. + * + * @ingroup Visualization Tools + * + * @author ?? Unknown + * + * @internal + + * @history 2008-06-25 Noah Hilt - Switched positions of the sample/line line + * edits and labels. + * + * @history 2008-08 Stacy Alley - Added red dot which is draw + * at the specified lat/lon or line/sample. Also, the + * red dot is draw in the corresponding spot of a + * linked image, if there is overlap in the two + * images. + * @history 2010-03-08 - Jeannie Walldren - The recordAction() + * slot and recordPoint() signal were created to + * connect in qview to the AdvancedTrackTool record() + * slot. + * @history 2010-03-24 Sharmila Prasad - Enable FindTool for no camera and/or + * projection image + * @history 2010-05-06 Eric Hyer - Class redesigned to work with new + * CubeViewport + * @history 2010-05-18 Eric Hyer - Moved button for showing/hiding the red + * dot from the dialog to the toolbar + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport instead of + * CubeViewport. Also fixed include issues. + */ + class GroundTab : public QWidget + { + Q_OBJECT + + public: + GroundTab(QWidget * parent = 0); + + QLineEdit * p_lonLineEdit; //!< Input for longitude + QLineEdit * p_latLineEdit; //!< Input for latitude + }; + + class ImageTab : public QWidget + { + Q_OBJECT + + public: + ImageTab(QWidget * parent = 0); + + QLineEdit * p_sampLineEdit; //!< Input for sample + QLineEdit * p_lineLineEdit; //!< Input for line + }; + + class FindTool : public Qisis::Tool + { + Q_OBJECT + + public: + FindTool(QWidget * parent); + ~FindTool(); + void addTo(QMenu * menu); + void paintViewport(MdiCubeViewport * vp, QPainter * painter); + signals: + void recordPoint(QPoint p); //!< Emitted when point should be recorded + + protected: + QAction * toolPadAction(ToolPad * toolpad); + /** + * This method returns the menu name associated with this tool. + * + * + * @return QString + */ + QString menuName() const + { + return "&Options"; + }; + QWidget * createToolBarWidget(QStackedWidget * parent); + void updateTool(); + void createDialog(QWidget * parent); + + protected slots: + void mouseButtonRelease(QPoint p, Qt::MouseButton s); + + private slots: + void handleOkClicked(); + void handleLinkClicked(); + void handleRecordClicked(); + void togglePointVisible(); + + private: // methods + void centerLinkedViewports(); + void refresh(); + + private: + QDialog * p_dialog; + QAction * p_findPoint; + QToolButton * p_showDialogButton; + QToolButton * p_linkViewportsButton; + QToolButton * p_togglePointVisibleButton; + QCheckBox * p_syncScale; + QLineEdit * p_statusEdit; + QTabWidget * p_tabWidget; + GroundTab * p_groundTab; + ImageTab * p_imageTab; + + + private: + double p_line; + double p_samp; + + double p_lat; + double p_lon; + + bool p_pointVisible; + }; + + + +}; + +#endif diff --git a/isis/src/qisis/objs/FindTool/Makefile b/isis/src/qisis/objs/FindTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/FindTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/HelpTool/HelpTool.cpp b/isis/src/qisis/objs/HelpTool/HelpTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a11a8df4be5dbaaf88f00380943f17e6556f49e1 --- /dev/null +++ b/isis/src/qisis/objs/HelpTool/HelpTool.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +#include "HelpTool.h" +#include "MainWindow.h" +#include "Workspace.h" +#include "Application.h" +#include "Preference.h" + +namespace Qisis { + // Constructor + HelpTool::HelpTool (QWidget *parent) : Qisis::Tool(parent) { + p_whatsThis = new QAction(parent); + p_whatsThis->setShortcut(Qt::SHIFT+Qt::Key_F1); + p_whatsThis->setText("&What's This?"); + p_whatsThis->setIcon(QPixmap(toolIconDir()+"/contexthelp.png")); + p_whatsThis->setToolTip("What's This"); + QString whatsThis = + "Function: Use this to get longer descriptions of button \ + functions \ +

    Shortcut: Shift+F1

    "; + p_whatsThis->setWhatsThis(whatsThis); + connect(p_whatsThis,SIGNAL(activated()),this,SLOT(whatsThis())); + + p_aboutProgram = new QAction(parent); + p_aboutProgram->setShortcut(Qt::CTRL+Qt::Key_H); + QString s = "About "; + s += QApplication::applicationName(); + p_aboutProgram->setText(s); + connect(p_aboutProgram,SIGNAL(activated()),this,SLOT(aboutProgram())); + + } + + // Add actions to the Help menu + void HelpTool::addTo (QMenu *menu) { + menu->addAction(p_whatsThis); + menu->addAction(p_aboutProgram); + } + + //! Add actions to the permanent toolbar + void HelpTool::addToPermanent (QToolBar *perm) { + perm->addAction(p_whatsThis); + } + + // The user pressed the whatsThis button so do something + void HelpTool::whatsThis () { + QWhatsThis::enterWhatsThisMode(); + } + + + /** + * Slot to print program information + * + * @author 2007-06-12 Tracie Sucharski + */ + void HelpTool::aboutProgram () { + Isis::Filename file((std::string) + "$ISISROOT/doc/Application/presentation/PrinterFriendly/" + + QApplication::applicationName().toStdString() + "/" + + QApplication::applicationName().toStdString() + ".html"); + + Isis::PvlGroup &uig = Isis::Preference::Preferences().FindGroup("UserInterface"); + std::string command = (std::string) uig["GuiHelpBrowser"] + + (std::string)" file:" + file.Expanded() + " &"; + system (command.c_str()); + + } +} diff --git a/isis/src/qisis/objs/HelpTool/HelpTool.h b/isis/src/qisis/objs/HelpTool/HelpTool.h new file mode 100644 index 0000000000000000000000000000000000000000..630d7a4fdfcf1f14a93daa6ef013d5a696d56d23 --- /dev/null +++ b/isis/src/qisis/objs/HelpTool/HelpTool.h @@ -0,0 +1,60 @@ +#ifndef HelpTool_h +#define HelpTool_h + +/** + * @file + * $Date: 2007/06/14 23:57:15 $ $Revision: 1.2 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "Tool.h" + +namespace Qisis { + /** + * @brief Qisis Help Tool + * + * @ingroup Visualization Tools + * + * @author Jeff Anderson + * + * @internal @history 2007-06-12 Tracie Sucharski - Added aboutProgram method + * + */ + class HelpTool : public Tool { + Q_OBJECT + + public: + HelpTool (QWidget *parent); + void addTo (QMenu *menu); + void addToPermanent (QToolBar *perm); + + public slots: + void whatsThis(); + + protected: + QString menuName() const { return "&Help"; }; + + private: + QAction *p_whatsThis; + QAction *p_aboutProgram; + + private slots: + void aboutProgram(); + }; +}; + +#endif diff --git a/isis/src/qisis/objs/HelpTool/Makefile b/isis/src/qisis/objs/HelpTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/HelpTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/HistogramTool/HistogramItem.cpp b/isis/src/qisis/objs/HistogramTool/HistogramItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eff49b5e5d50b605febd775363922057fcf3b194 --- /dev/null +++ b/isis/src/qisis/objs/HistogramTool/HistogramItem.cpp @@ -0,0 +1,438 @@ +#include "HistogramItem.h" + +#include +#include + +#include +#include +#include +#include + +#include + +namespace Qisis { + + class HistogramItem::PrivateData { + public: + int attributes; + QwtIntervalData data; + QColor color; + double reference; + }; + + /** + * Constructor 1 + * + * + * @param title + */ + HistogramItem::HistogramItem(const QwtText &title):QwtPlotItem(){ + init(); + } + + + /** + * Constructor 2 + * + * + * @param title + */ + HistogramItem::HistogramItem(const QString &title):QwtPlotItem(QwtText(title)){ + init(); + } + + + /** + * Destructor + * + */ + HistogramItem::~HistogramItem(){ + delete d_data; + } + + + /** + * Initialization method + * + */ + void HistogramItem::init(){ + d_data = new PrivateData(); + d_data->reference = 0.0; + d_data->attributes = HistogramItem::Auto; + + setItemAttribute(QwtPlotItem::AutoScale, true); + setItemAttribute(QwtPlotItem::Legend, true); + + setZ(20.0); + } + + + /** + * + * + * + * @param reference + */ + void HistogramItem::setBaseline(double reference){ + if ( d_data->reference != reference ) { + d_data->reference = reference; + itemChanged(); + } + } + + + /** + * Returns the baseline. + * + * + * @return double + */ + double HistogramItem::baseline() const{ + return d_data->reference; + } + + + /** + * Overridden method to set the data in the histogram. + * + * + * @param data + */ + void HistogramItem::setData(const QwtIntervalData &data){ + d_data->data = data; + itemChanged(); + } + + + /** + * Returns this item's data + * + * + * @return const QwtIntervalData& + */ + const QwtIntervalData &HistogramItem::data() const{ + return d_data->data; + } + + + /** + * Set the color of the hist. item. + * + * + * @param color + */ + void HistogramItem::setColor(const QColor &color){ + if ( d_data->color != color ) { + d_data->color = color; + itemChanged(); + } + } + + + /** + * Return the color of the item. + * + * + * @return QColor + */ + QColor HistogramItem::color() const{ + return d_data->color; + } + + + /** + * Returns the bounding rectangle of the item. + * + * + * @return QwtDoubleRect + */ + QwtDoubleRect HistogramItem::boundingRect() const{ + QwtDoubleRect rect = d_data->data.boundingRect(); + if ( !rect.isValid() ) + return rect; + + if ( d_data->attributes & Xfy ) { + rect = QwtDoubleRect( rect.y(), rect.x(), + rect.height(), rect.width() ); + + if ( rect.left() > d_data->reference ) + rect.setLeft( d_data->reference ); + else if ( rect.right() < d_data->reference ) + rect.setRight( d_data->reference ); + } else { + if ( rect.bottom() < d_data->reference ) + rect.setBottom( d_data->reference ); + else if ( rect.top() > d_data->reference ) + rect.setTop( d_data->reference ); + } + + return rect; + } + + + /** + * + * + * + * @return int + */ + int HistogramItem::rtti() const{ + return QwtPlotItem::Rtti_PlotHistogram; + } + + + /** + * + * + * + * @param attribute + * @param on + */ + void HistogramItem::setHistogramAttribute(HistogramAttribute attribute, bool on){ + if ( bool(d_data->attributes & attribute) == on ) + return; + + if ( on ) + d_data->attributes |= attribute; + else + d_data->attributes &= ~attribute; + + itemChanged(); + } + + + /** + * + * + * + * @param attribute + * + * @return bool + */ + bool HistogramItem::testHistogramAttribute(HistogramAttribute attribute) const{ + return d_data->attributes & attribute; + } + + + /** + * + * + * + * @param painter + * @param xMap + * @param yMap + */ + void HistogramItem::draw(QPainter *painter, const QwtScaleMap &xMap, + const QwtScaleMap &yMap, const QRect &) const{ + const QwtIntervalData &iData = d_data->data; + + painter->setPen(QPen(d_data->color)); + + const int x0 = xMap.transform(baseline()); + const int y0 = yMap.transform(baseline()); + + for ( int i = 0; i < (int)iData.size(); i++ ) { + if ( d_data->attributes & HistogramItem::Xfy ) { + const int x2 = xMap.transform(iData.value(i)); + if ( x2 == x0 ) + continue; + + int y1 = yMap.transform( iData.interval(i).minValue()); + int y2 = yMap.transform( iData.interval(i).maxValue()); + if ( y1 > y2 ) + qSwap(y1, y2); + + if ( i < (int)iData.size() - 2 ) { + const int yy1 = yMap.transform(iData.interval(i+1).minValue()); + const int yy2 = yMap.transform(iData.interval(i+1).maxValue()); + + if ( y2 == qwtMin(yy1, yy2) ) { + const int xx2 = xMap.transform( + iData.interval(i+1).minValue()); + if ( xx2 != x0 && ( (xx2 < x0 && x2 < x0) || + (xx2 > x0 && x2 > x0) ) ) { + // One pixel distance between neighboured bars + y2++; + } + } + } + + drawBar(painter, Qt::Horizontal, + QRect(x0, y1, x2 - x0, y2 - y1)); + } else { + const int y2 = yMap.transform(iData.value(i)); + if ( y2 == y0 ) + continue; + + int x1 = xMap.transform(iData.interval(i).minValue()); + int x2 = xMap.transform(iData.interval(i).maxValue()); + if ( x1 > x2 ) + qSwap(x1, x2); + + if ( i < (int)iData.size() - 2 ) { + const int xx1 = xMap.transform(iData.interval(i+1).minValue()); + const int xx2 = xMap.transform(iData.interval(i+1).maxValue()); + + if ( x2 == qwtMin(xx1, xx2) ) { + const int yy2 = yMap.transform(iData.value(i+1)); + if ( yy2 != y0 && ( (yy2 < y0 && y2 < y0) || + (yy2 > y0 && y2 > y0) ) ) { + // One pixel distance between neighboured bars + x2--; + } + } + } + drawBar(painter, Qt::Vertical, + QRect(x1, y0, x2 - x1, y2 - y0) ); + } + } + } + + + /** + * This method draws the bars of the bar graph. + * + * + * @param painter + * @param rect + */ + void HistogramItem::drawBar(QPainter *painter, + Qt::Orientation, const QRect& rect) const{ + painter->save(); + + const QColor color(painter->pen().color()); +#if QT_VERSION >= 0x040000 + const QRect r = rect.normalized(); +#else + const QRect r = rect.normalize(); +#endif + + const int factor = 125; + const QColor light(color.light(factor)); + const QColor dark(color.dark(factor)); + + painter->setBrush(color); + painter->setPen(Qt::NoPen); + QwtPainter::drawRect(painter, r.x() + 1, r.y() + 1, + r.width() - 2, r.height() - 2); + painter->setBrush(Qt::NoBrush); + + painter->setPen(QPen(light, 2)); +#if QT_VERSION >= 0x040000 + QwtPainter::drawLine(painter, + r.left() + 1, r.top() + 2, r.right() + 1, r.top() + 2); +#else + QwtPainter::drawLine(painter, + r.left(), r.top() + 2, r.right() + 1, r.top() + 2); +#endif + + painter->setPen(QPen(dark, 2)); +#if QT_VERSION >= 0x040000 + QwtPainter::drawLine(painter, + r.left() + 1, r.bottom(), r.right() + 1, r.bottom()); +#else + QwtPainter::drawLine(painter, + r.left(), r.bottom(), r.right() + 1, r.bottom()); +#endif + + painter->setPen(QPen(light, 1)); + +#if QT_VERSION >= 0x040000 + QwtPainter::drawLine(painter, + r.left(), r.top() + 1, r.left(), r.bottom()); + QwtPainter::drawLine(painter, + r.left() + 1, r.top() + 2, r.left() + 1, r.bottom() - 1); +#else + QwtPainter::drawLine(painter, + r.left(), r.top() + 1, r.left(), r.bottom() + 1); + QwtPainter::drawLine(painter, + r.left() + 1, r.top() + 2, r.left() + 1, r.bottom()); +#endif + + painter->setPen(QPen(dark, 1)); + +#if QT_VERSION >= 0x040000 + QwtPainter::drawLine(painter, + r.right() + 1, r.top() + 1, r.right() + 1, r.bottom()); + QwtPainter::drawLine(painter, + r.right(), r.top() + 2, r.right(), r.bottom() - 1); +#else + QwtPainter::drawLine(painter, + r.right() + 1, r.top() + 1, r.right() + 1, r.bottom() + 1); + QwtPainter::drawLine(painter, + r.right(), r.top() + 2, r.right(), r.bottom()); +#endif + + painter->restore(); + } + + + /** + * This method returns a list of points which are the vertices + * of the selected area (by the rubberband) on the cvp. + * + * @return QList + */ + QList HistogramItem::getVertices() const { + return p_pointList; + } + + + /** + * This method sets the vertices of the selected area on the + * cvp. + * @param points + */ + void HistogramItem::setVertices(const QList &points){ + double sample, line; + p_pointList.clear(); + if(this->getViewPort() == NULL){ + std::cout << "Please be sure to set the view port first!" << std::endl; + } + for(int i = 0; igetViewPort()->viewportToCube(points[i].x(),points[i].y(),sample,line); + p_pointList.push_back(QPointF((sample), ( line))); + } + } + + + /** + * This method returns the cube view port associated with the + * curve. + * + * @return CubeViewport* + */ + CubeViewport* HistogramItem::getViewPort() const { + return p_cvp; + } + + + /** + * This method sets the view port. + * @param cvp + */ + void HistogramItem::setViewPort(CubeViewport *cvp){ + p_cvp = cvp; + } + + + /** + * This method allows the users to copy all of the given curves + * properties into the current curve. This is an overriden + * function from the PlotCurve class. + * + * @param pc + */ + void HistogramItem::copyCurveProperties(HistogramItem *hi){ + this->setAxis(hi->xAxis(), hi->yAxis()); + this->setVisible(hi->isVisible()); + //this->setPen(hi->pen()); + this->setTitle(hi->title().text()); + this->setData(hi->data()); + this->setColor(hi->color()); + + p_cvp = hi->getViewPort(); + p_pointList = hi->getVertices(); + } + +} diff --git a/isis/src/qisis/objs/HistogramTool/HistogramItem.h b/isis/src/qisis/objs/HistogramTool/HistogramItem.h new file mode 100644 index 0000000000000000000000000000000000000000..70de98f3b4e72ae4406d5820fc37569c1d786ec8 --- /dev/null +++ b/isis/src/qisis/objs/HistogramTool/HistogramItem.h @@ -0,0 +1,67 @@ + +#ifndef HISTOGRAM_ITEM_H +#define HISTOGRAM_ITEM_H + +#include +#include + +#include "qwt_plot_item.h" +#include "CubeViewport.h" + +class QwtIntervalData; +class QString; + +namespace Qisis { + + class HistogramItem: public QwtPlotItem{ + public: + explicit HistogramItem(const QString &title = QString::null); + explicit HistogramItem(const QwtText &title); + virtual ~HistogramItem(); + + void setData(const QwtIntervalData &data); + const QwtIntervalData &data() const; + void copyCurveProperties(HistogramItem *hi); + QList getVertices() const; + void setVertices(const QList &points); + CubeViewport* getViewPort() const; + void setViewPort(CubeViewport *cvp); + + void setColor(const QColor &); + QColor color() const; + + virtual QwtDoubleRect boundingRect() const; + + virtual int rtti() const; + + virtual void draw(QPainter *, const QwtScaleMap &xMap, + const QwtScaleMap &yMap, const QRect &) const; + + void setBaseline(double reference); + double baseline() const; + + enum HistogramAttribute + { + Auto = 0, + Xfy = 1 + }; + + void setHistogramAttribute(HistogramAttribute, bool on = true); + bool testHistogramAttribute(HistogramAttribute) const; + + protected: + virtual void drawBar(QPainter *, + Qt::Orientation o, const QRect &) const; + + private: + void init(); + + class PrivateData; + PrivateData *d_data; + QList p_pointList;//!< List of data points + CubeViewport *p_cvp;//!< Viewport the data is from + }; + +}; + +#endif diff --git a/isis/src/qisis/objs/HistogramTool/HistogramTool.cpp b/isis/src/qisis/objs/HistogramTool/HistogramTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e4b9e26e64353bba8b4ac09fc80c825c572b1a3a --- /dev/null +++ b/isis/src/qisis/objs/HistogramTool/HistogramTool.cpp @@ -0,0 +1,736 @@ +#include "HistogramTool.h" + +#include + +#include "Brick.h" +#include "HistogramToolWindow.h" +#include "MdiCubeViewport.h" +#include "PolygonTools.h" +#include "RubberBandComboBox.h" +#include "ToolPad.h" + + +namespace Qisis +{ + + /** + * Constructor creates a new HistogramTool object. + * + * @param parent + */ + HistogramTool::HistogramTool(QWidget *parent) : Qisis::PlotTool(parent) + { + p_rubberBand = NULL; + RubberBandTool::allowPoints(1); + p_parent = parent; + createWindow(); + setupPlotCurves(); + p_scaled = false; + p_action = new QAction(p_histToolWindow); + p_action->setText("HistogramTool"); + p_action->setIcon(QPixmap(toolIconDir() + "/histogram.png")); + QObject::connect(p_action, SIGNAL(activated()), this, SLOT(showPlotWindow())); + QObject::connect(this, SIGNAL(viewportChanged()), this, SLOT(viewportSelected())); + p_color = 0; + } + + + + /** + * This method is called when the tool is activated by the + * parent, or when the plot mode is changed. It's used to + * activate or change the rubber banding mode to be either + * rectangle or line, depending on the current plot type. + */ + void HistogramTool::enableRubberBandTool() + { + if (p_rubberBand) + { + p_rubberBand->reset(); + p_rubberBand->setEnabled(true); + } + } + + /** + * This method adds the histogram tool to the tool pad. + * + * @param toolpad + * + * @return QAction* + */ + QAction *HistogramTool::toolPadAction(ToolPad *toolpad) + { + QAction *action = new QAction(toolpad); + action->setIcon(QPixmap(toolIconDir() + "/histogram.png")); + action->setToolTip("Histogram (H)"); + action->setShortcut(Qt::Key_H); + QObject::connect(action, SIGNAL(activated()), this, SLOT(showPlotWindow())); + + p_histToolWindow->addViewMenu(); + + QString text = + "Function: Plot histogram in active viewport \ +

    Shortcut: H

    "; + action->setWhatsThis(text); + return action; + } + + + /** + * This method creates the widgets for the tool bar. + * + * + * @param parent + * + * @return QWidget* + */ + QWidget *HistogramTool::createToolBarWidget(QStackedWidget *parent) + { + QWidget *hbox = new QWidget(parent); + + p_rubberBand = new RubberBandComboBox( + RubberBandComboBox::Rectangle | + RubberBandComboBox::Line, + RubberBandComboBox::Rectangle + ); + + QToolButton *newWindowButton = new QToolButton(); + newWindowButton->setText("New"); + newWindowButton->setToolTip("Opens a new blank plot window"); + QString windowText = + "Function: This button will bring up a blank plot window that allows \ + the user to copy and paste curves from the active plot window to other windows \ +

    Shortcut: CTRL+W

    "; + newWindowButton->setWhatsThis(windowText); + newWindowButton->setShortcut(Qt::CTRL + Qt::Key_W); + connect(newWindowButton, SIGNAL(clicked()), this, SLOT(newPlotWindow())); + + QToolButton *plotButton = new QToolButton(); + plotButton->setText("Show"); + plotButton->setToolTip("Shows the active the plot window"); + QString text = + "Function: This button will bring up the plot window that allows \ + the user to view the min, max, and average values of each band in a \ + selected range of the image.

    Shortcut: CTRL+L

    "; + plotButton->setWhatsThis(text); + plotButton->setShortcut(Qt::CTRL + Qt::Key_L); + connect(plotButton, SIGNAL(clicked()), this, SLOT(showPlotWindow())); + + QHBoxLayout *layout = new QHBoxLayout(hbox); + layout->setMargin(0); + layout->addWidget(p_rubberBand); + layout->addWidget(newWindowButton); + layout->addWidget(plotButton); + layout->addStretch(1); + hbox->setLayout(layout); + return hbox; + } + + + + + /** + * This method updates the histogram tool. + * + */ + void HistogramTool::updateTool() + { + //If there is no viewport, disable the action + if (cubeViewport() == NULL) + { + p_action->setEnabled(false); + } + //Else enable it and set the window's viewport to + //the current viewport + else + { + p_action->setEnabled(true); + + MdiCubeViewport *cvp = cubeViewport(); + p_histToolWindow->setViewport(cvp); + } + } + + + /** + * displays the plot window + * + */ + void HistogramTool::showPlotWindow() + { + p_histToolWindow->showWindow(); + } + + + /** + * This method creates the default histogram plot window. + * + */ + void HistogramTool::createWindow() + { + p_histToolWindow = new HistogramToolWindow("Active Histogram Window", p_parent); + p_histToolWindow->setDestroyOnClose(false); + p_histToolWindow->setDeletable(false); + p_histToolWindow->setPasteable(false); + //connect(p_histToolWindow, SIGNAL(curveCopied(Qisis::HistogramItem *)), this, + //SLOT(copyCurve(Qisis::HistogramItem *))); + + QList menu; + QList actionButtons; + + /* menu is the QMenu's at the top of the plot window, while + actionButtons are the buttons directly below.*/ + p_histToolWindow->getDefaultMenus(menu, actionButtons); + + for (int i = 0; i < menu.size(); i++) + { + if (menu[i]->title() == "&Options") + { + p_autoScale = new QAction(p_histToolWindow); + p_autoScale->setText("AutoScale"); + p_autoScale->setCheckable(true); + p_autoScale->setChecked(true); + QString text = + "Function: Turn on/off the auto scale option on the plot."; + p_autoScale->setWhatsThis(text); + menu[i]->addAction(p_autoScale); + actionButtons.push_back(p_autoScale); + } + } + + p_histToolWindow->setCustomMenu(menu, actionButtons); + p_histToolWindow->clearPlotCurves(false); + p_histToolWindow->hideAllSymbols(); + p_histToolWindow->hideAllCurves(); + } + + + /** + * Called when the user has finished drawing with the rubber + * band. ChangePlot is called to plot the data within the + * rubber band. + * + */ + void HistogramTool::rubberBandComplete() + { + p_histToolWindow->raise(); + if (RubberBandTool::isValid()) + { + changePlot(); + } + else + { + QMessageBox::information(p_histToolWindow, "Error", + "The selected Area contains no valid pixels", + QMessageBox::Ok); + } + } + + + /** + * This method creates and displays a blank plot window in which + * users can paste curves to and copy curves from. + */ + void HistogramTool::newPlotWindow() + { + HistogramToolWindow *blankWindow = new HistogramToolWindow("Histogram Window", p_parent); + blankWindow->setDestroyOnClose(true); + connect(blankWindow, SIGNAL(curvePaste(Qisis::PlotWindow *)), this, + SLOT(pasteCurve(Qisis::PlotWindow *))); + connect(blankWindow, SIGNAL(curvePasteSpecial(Qisis::PlotWindow *)), this, + SLOT(pasteCurveSpecial(Qisis::PlotWindow *))); + connect(blankWindow, SIGNAL(curveCopied(Qisis::PlotCurve *)), this, + SLOT(copyCurve(Qisis::PlotCurve *))); + connect(blankWindow, SIGNAL(destroyed(QObject *)), this, + SLOT(removeWindow(QObject *))); + connect(blankWindow, SIGNAL(plotChanged()), this, SLOT(updateViewPort())); + blankWindow->setScale(QwtPlot::xBottom, p_histToolWindow->p_xMin, + p_histToolWindow->p_xMax); + blankWindow->setScale(QwtPlot::yLeft, p_histToolWindow->p_yMin, + p_histToolWindow->p_yMax); + blankWindow->setPlotTitle(p_histToolWindow->getPlotTitle().text()); + blankWindow->setDeletable(true); + blankWindow->setPasteable(true); + blankWindow->setCopyEnable(false); + blankWindow->setupDefaultMenu(); + blankWindow->hideAllSymbols(); + blankWindow->hideAllCurves(); + blankWindow->showWindow(); + + p_plotWindows.push_back(blankWindow); + } + + + /** + * This method plots the selected data in a histogram window. + */ + void HistogramTool::changePlot() + { + MdiCubeViewport *cvp = cubeViewport(); + /* Delete any current curves*/ + p_histToolWindow->clearPlotCurves(); + + QList vertices; + + if (RubberBandTool::getMode() == RubberBandTool::Circle) + { + geos::geom::Geometry *p = RubberBandTool::geometry(); + geos::geom::CoordinateSequence *c = p->getCoordinates(); + for (int i = 0; i < (int)c->getSize(); i++) + { + QPoint point((int)(c->getX(i) + 0.5), (int)(c->getY(i) + 0.5)); + vertices.append(point); + } + delete p; + } + else + { + vertices = RubberBandTool::getVertices(); + } + + p_histCurve->setViewPort(cvp); + p_histCurve->setVertices(vertices); + + p_cdfCurve->setViewPort(cvp); + p_cdfCurve->setVertices(vertices); + + if (vertices.size() < 1) return; + + Isis::Cube *cube = cvp->cube(); + int band = cvp->grayBand(); + Isis::Histogram hist(*cube, 1); + + //If the rubber band is a line + if (RubberBandTool::getMode() == RubberBandTool::Line) + { + double ssamp, sline, esamp, eline; + cvp->viewportToCube(vertices[0].rx(), vertices[0].ry(), + ssamp, sline); + + cvp->viewportToCube(vertices[1].rx(), vertices[1].ry(), + esamp, eline); + + QLine line((int)ssamp, (int)sline, (int)esamp, (int)eline); + + double slope; + int i; + int x, y, xinc, yinc; + int xsize, ysize; + + //Get all of the points out of the line + QList *linePts = new QList; + + int sx = line.p1().x(); + int ex = line.p2().x(); + int sy = line.p1().y(); + int ey = line.p2().y(); + if (sx > ex) + { + xsize = sx - ex + 1; + xinc = -1; + } + else + { + xsize = ex - sx + 1; + xinc = 1; + } + + if (sy > ey) + { + ysize = sy - ey + 1; + yinc = -1; + } + else + { + ysize = ey - sy + 1; + yinc = 1; + } + + if (ysize > xsize) + { + slope = (double)(ex - sx) / (double)(ey - sy); + y = sy; + for (i = 0; i < ysize; i++) + { + x = (int)(slope * (double)(y - sy) + (double) sx + 0.5); + + QPoint *pt = new QPoint; + pt->setX(x); + pt->setY(y); + linePts->push_back(pt); + y += yinc; + } + } + else if (xsize == 1) + { + QPoint *pt = new QPoint; + pt->setX(sx); + pt->setY(sy); + linePts->push_back(pt); + } + else + { + slope = (double)(ey - sy) / (double)(ex - sx); + x = sx; + for (i = 0; i < xsize; i++) + { + y = (int)(slope * (double)(x - sx) + (double) sy + 0.5); + + QPoint *pt = new QPoint; + pt->setX(x); + pt->setY(y); + linePts->push_back(pt); + x += xinc; + } + } + + if (linePts->empty()) + { + QMessageBox::information((QWidget *)parent(), + "Error", "No points in edit line"); + return; + } + + Isis::Brick *brick = new Isis::Brick(*cube, 1, 1, 1); + + //For each point read that value from the cube and add it to the histogram + for (int i = 0; linePts && i < (int)linePts->size(); i++) + { + QPoint *pt = (*linePts)[i]; + int is = pt->x(); + int il = pt->y(); + brick->SetBasePosition(is, il, band); + cube->Read(*brick); + hist.AddData(brick->DoubleBuffer(), 1); + } + delete brick; + + delete linePts; + + } + //If rubber band is a rectangle + else if (RubberBandTool::getMode() == RubberBandTool::Rectangle) + { + double ssamp, sline, esamp, eline; + + // Convert them to line sample values + cvp->viewportToCube(vertices[0].x(), vertices[0].y(), ssamp, sline); + cvp->viewportToCube(vertices[2].x(), vertices[2].y(), esamp, eline); + + ssamp = ssamp + 0.5; + sline = sline + 0.5; + esamp = esamp + 0.5; + eline = eline + 0.5; + + int nsamps = (int)(esamp - ssamp + 1); + if (nsamps < 1) nsamps = -nsamps; + + Isis::Brick *brick = new Isis::Brick(*cube, nsamps, 1, 1); + + //For each line read nsamps and add it to the histogram + for (int line = (int)std::min(sline, eline); line <= (int)std::max(sline, eline); line++) + { + brick->SetBasePosition((int)ssamp, line, band); + cube->Read(*brick); + hist.AddData(brick->DoubleBuffer(), nsamps); + } + delete brick; + } + //If rubber band is a polygon or circle + else + { + geos::geom::Geometry *polygon = RubberBandTool::geometry(); + + std::vector x_contained, y_contained; + if (polygon != NULL) + { + const geos::geom::Envelope *envelope = polygon->getEnvelopeInternal(); + double ssamp, esamp, sline, eline; + cvp->viewportToCube((int)floor(envelope->getMinX()), (int)floor(envelope->getMinY()), ssamp, sline); + cvp->viewportToCube((int)ceil(envelope->getMaxX()), (int)ceil(envelope->getMaxY()), esamp, eline); + + + for (int y = (int)sline; y <= (int)eline; y++) + { + for (int x = (int)ssamp; x <= (int)esamp; x++) + { + int x1, y1; + cvp->cubeToViewport(x, y, x1, y1); + geos::geom::Coordinate c(x1, y1); + geos::geom::Point *p = Isis::globalFactory.createPoint(c); + bool contains = p->within(polygon); + delete p; + + if (contains) + { + x_contained.push_back(x); + y_contained.push_back(y); + } + } + } + + delete polygon; + + Isis::Brick *brick = new Isis::Brick(*cube, 1, 1, 1); + + //Read each point from the cube and add it to the histogram + for (unsigned int j = 0; j < x_contained.size(); j++) + { + brick->SetBasePosition(x_contained[j], y_contained[j], band); + cube->Read(*brick); + hist.AddData(brick->DoubleBuffer(), 1); + } + delete brick; + } + } + + + //Transfer data from histogram to the plotcurve + std::vector xarray, yarray, y2array; + double cumpct = 0.0; + for (int i = 0; i < hist.Bins(); i++) + { + if (hist.BinCount(i) > 0) + { + xarray.push_back(hist.BinMiddle(i)); + yarray.push_back(hist.BinCount(i)); + + double pct = (double)hist.BinCount(i) / hist.ValidPixels() * 100.; + cumpct += pct; + y2array.push_back(cumpct); + } + } + + //p_histCurve->setData(&xarray[0],&yarray[0],xarray.size()); + + + //These are all variables needed in the following for loop. + //---------------------------------------------- + QwtArray intervals(xarray.size()); + QwtValueList majorTicks; + QwtArray values(yarray.size()); + double maxYValue = DBL_MIN; + double minYValue = DBL_MAX; + // --------------------------------------------- + + for (unsigned int y = 0; y < yarray.size(); y++) + { + + intervals[y] = QwtDoubleInterval(xarray[y], xarray[y] + hist.BinSize()); + + majorTicks.push_back(xarray[y]); + //std::cout << "\nmajor tick " << xarray[y] << std::endl; + majorTicks.push_back(xarray[y] + hist.BinSize()); + //std::cout << "& " << xarray[y] + hist.BinSize() << std::endl; + + values[y] = yarray[y]; + if (values[y] > maxYValue) maxYValue = values[y]; + if (values[y] < minYValue) minYValue = values[y]; + } + + QwtScaleDiv scaleDiv; + scaleDiv.setTicks(QwtScaleDiv::MajorTick, majorTicks); + + p_histCurve->setData(QwtIntervalData(intervals, values)); + p_cdfCurve->setData(&xarray[0], &y2array[0], xarray.size()); + p_cdfCurve->setVisible(true); + p_cdfCurve->setSymbolVisible(false); + + p_histToolWindow->add(p_histCurve); + p_histToolWindow->add(p_cdfCurve); + p_histToolWindow->fillTable(); + + if (p_autoScale->isChecked()) + { + p_histToolWindow->setScale(QwtPlot::yLeft, 0, maxYValue); + p_histToolWindow->setScale(QwtPlot::xBottom, hist.Minimum(), hist.Maximum()); + //p_histToolWindow->setScale(QwtPlot::xBottom,0,hist.Maximum()); + //std::cout << "hist.Minimum() = " << hist.Minimum() << " xarray[0] = " << xarray[0] << std::endl; + //This line causes a seg. fault if the xarray has no data! + //p_histToolWindow->setScale(QwtPlot::xBottom,xarray[0],hist.Maximum()); + //p_histToolWindow->setScaleDiv(QwtPlot::xBottom, scaleDiv); + } + + copyCurve(); + p_histToolWindow->p_curveCopied = true; + p_histToolWindow->showWindow(); + updateTool(); + + + QLabel *label = new QLabel(" Average = " + QString::number(hist.Average()) + '\n' + + "\n Minimum = " + QString::number(hist.Minimum()) + '\n' + + "\n Maximum = " + QString::number(hist.Maximum()) + '\n' + + "\n Stand. Dev.= " + QString::number(hist.StandardDeviation()) + '\n' + + "\n Variance = " + QString::number(hist.Variance()) + '\n' + + "\n Median = " + QString::number(hist.Median()) + '\n' + + "\n Mode = " + QString::number(hist.Mode()) + '\n' + + "\n Skew = " + QString::number(hist.Skew()), p_histToolWindow); + p_histToolWindow->getDockWidget()->setWidget(label); + } + + + /** + * This method creates a new HistogramItem and copies the + * properties of the curve the user clicked on into the new + * curve. The plotWindow class emits a signal when a curve has + * been requested to be copied. + * + * @param pc + */ + void HistogramTool::copyCurve(Qisis::PlotCurve *pc) + { + p_copyCurve = new HistogramItem(); + p_copyCurve->copyCurveProperties(p_histCurve); + } + + void HistogramTool::copyCurve() + { + p_copyCurve = new HistogramItem(); + p_copyCurve->copyCurveProperties(p_histCurve); + } + + + /** + * This method pastes the copied curve into the given plot + * window. The plotWindow class emits a signal when a paste + * command has taken place inside the window. + * @param pw + */ + void HistogramTool::pasteCurve(Qisis::PlotWindow *pw) + { + p_cvp = cubeViewport(); + ((HistogramToolWindow *)pw)->add(p_copyCurve); + updateViewPort(p_cvp); + + } + + + /** + * This method does the same as the above method but gives the + * curve a different color than the copied curve. + * @param pw + */ + void HistogramTool::pasteCurveSpecial(Qisis::PlotWindow *pw) + { + p_cvp = cubeViewport(); + if (p_color < p_colors.size()) + { + p_copyCurve->setColor(p_colors[p_color]); + } + else + { + QColor c = QColorDialog::getColor(Qt::white, p_histToolWindow); + if (c.isValid()) + { + p_copyCurve->setColor(c); + } + } + + ((HistogramToolWindow *)pw)->add(p_copyCurve); + updateViewPort(p_cvp); + p_color++; + + } + + + + /** + * This method sets up the names, line style, and color of the + * all the plot items that will be used in this class. This + * method also fills the p_colors QList with the colors that + * will be used when the user copies and pastes (special) into + * another plot window. + */ + void HistogramTool::setupPlotCurves() + { + p_histCurve = new HistogramItem(); + p_histCurve->setColor(Qt::darkCyan); + //If we give the curve a title, it will show up on the legend. + //p_histCurve->setTitle("Frequency"); + + p_cdfCurve = new PlotToolCurve(); + p_cdfCurve->setStyle(QwtPlotCurve::Lines); + p_cdfCurve->setTitle("Percentage"); + + QPen *pen = new QPen(Qt::darkCyan); + pen->setWidth(2); + p_histCurve->setYAxis(QwtPlot::yLeft); + //p_histCurve->setPen(*pen); + pen->setColor(Qt::red); + + p_cdfCurve->setYAxis(QwtPlot::yRight); + p_cdfCurve->setPen(*pen); + + p_colors.push_back(Qt::cyan); + p_colors.push_back(Qt::magenta); + p_colors.push_back(Qt::yellow); + p_colors.push_back(QColor(255, 170, 255)); + p_colors.push_back(Qt::green); + p_colors.push_back(Qt::white); + p_colors.push_back(Qt::blue); + p_colors.push_back(Qt::red); + p_colors.push_back(QColor(134, 66, 176)); + p_colors.push_back(QColor(255, 152, 0)); + + } + + + /** + * This method paints the polygons of the copied hist. items + * onto the cubeviewport + * + * @param vp + * @param painter + */ + void HistogramTool::paintViewport(MdiCubeViewport *vp, QPainter *painter) + { + + int sample1, line1, sample2, line2; + + for (int i = 0; i < p_plotWindows.size(); i++) + { + for (int c = 0; c < p_plotWindows[i]->getNumItems(); c++) + { + HistogramItem *histItem = p_plotWindows[i]->getHistItem(c); + + if (histItem->getViewPort() == vp) + { + QPen pen(histItem->color()); + pen.setWidth(2); + pen.setStyle(Qt::SolidLine); + painter->setPen(pen); + QList points = histItem->getVertices(); + + for (int p = 1; p < points.size(); p++) + { + vp->cubeToViewport(points[p-1].x(), points[p-1].y(), sample1, line1); + vp->cubeToViewport(points[p].x(), points[p].y(), sample2, line2); + painter->drawLine(QPoint(sample1, line1), QPoint(sample2, line2)); + } + + vp->cubeToViewport(points[points.size()-1].x(), + points[points.size()-1].y(), sample1, line1); + vp->cubeToViewport(points[0].x(), points[0].y(), sample2, line2); + painter->drawLine(QPoint(sample1, line1), QPoint(sample2, line2)); + } + + } + + } + } + + + /** + * This method causes the view port corresponding with the given PlotToolCurve + * to be repainted with all of the area's of interest associated with the + * PlotToolCurve's plotwindow. The paintViewport() method is called. + * + * @param cvp + */ + void HistogramTool::updateViewPort(MdiCubeViewport * cvp) + { + cvp->repaint(); + } + +} + diff --git a/isis/src/qisis/objs/HistogramTool/HistogramTool.h b/isis/src/qisis/objs/HistogramTool/HistogramTool.h new file mode 100644 index 0000000000000000000000000000000000000000..b3969b342455ea0da6e980bfa3a68ff421b18131 --- /dev/null +++ b/isis/src/qisis/objs/HistogramTool/HistogramTool.h @@ -0,0 +1,94 @@ +#ifndef HistogramTool_h +#define HistogramTool_h + +#include "PlotTool.h" + + +// FIXME: remove this include +#include "RubberBandTool.h" + + +class QAction; +class QWidget; + +namespace Isis +{ + class Brick; +} + + +namespace Qisis +{ + class HistogramItem; + class HistogramToolWindow; + class MdiCubeViewport; + + /** + * @brief Tool for histograms + * + * @ingroup Visualization Tools + * + * @author Noah Hilt + * + * @internal + * @history 2008-08-18 Christopher Austin - Upgraded to geos3.0.0 + */ + class HistogramTool : public PlotTool + { + Q_OBJECT + + public: + HistogramTool(QWidget *parent); + void paintViewport(MdiCubeViewport *vp, QPainter *painter); + + protected: + //!< Returns the menu name. + QString menuName() const + { + return "&Options"; + }; + QWidget *createToolBarWidget(QStackedWidget *parent); + QAction *toolPadAction(ToolPad *pad); + QAction *p_autoScale;//!< Auto scale the plot + void enableRubberBandTool(); + void updateTool(); + + protected slots: + void createWindow(); + void rubberBandComplete(); + + public slots: + void changePlot(); + void updateViewPort(Qisis::MdiCubeViewport *); + void copyCurve(Qisis::PlotCurve *); + void copyCurve(); + void pasteCurve(Qisis::PlotWindow *); + void pasteCurveSpecial(Qisis::PlotWindow *); + void showPlotWindow(); + + private slots: + void newPlotWindow(); + + private: + void setupPlotCurves(); + + QWidget *p_parent; //!< parent widget + HistogramToolWindow *p_histToolWindow;//!< Plot Tool Window Widget + + HistogramItem *p_copyCurve;//!< Plot curve for copying curves + HistogramItem *p_histCurve;//!< Histogram Item + PlotToolCurve *p_cdfCurve;//!< Plot curve for + // + QAction *p_action;//!< Plot tool's action + + bool p_scaled;//!< Has the plot been scaled? + + QList p_colors;//!< List of colors + QList p_plotWindows;//!< List of all plot windows + RubberBandComboBox *p_rubberBand;//!< Rubber band combo box + + int p_color;//!< Keeps track of which color we are at + }; +}; + +#endif diff --git a/isis/src/qisis/objs/HistogramTool/Makefile b/isis/src/qisis/objs/HistogramTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/HistogramTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/HistogramToolWindow/HistogramToolWindow.cpp b/isis/src/qisis/objs/HistogramToolWindow/HistogramToolWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..26e937d682633eae27d595740787a03995b789dc --- /dev/null +++ b/isis/src/qisis/objs/HistogramToolWindow/HistogramToolWindow.cpp @@ -0,0 +1,95 @@ +#include "HistogramToolWindow.h" + +#include + +namespace Qisis { + /** + * Constructor, creates a new HistogramToolWindow + * + * @param title + * @param parent + */ + HistogramToolWindow::HistogramToolWindow(QString title,QWidget *parent) : PlotWindow(title, parent) { + p_plot->enableAxis(QwtPlot::yRight); + QwtText *leftLabel = new QwtText("Frequency", + QwtText::PlainText); + + leftLabel->setColor(Qt::darkCyan); + QFont font = leftLabel->font(); + font.setPointSize(13); + font.setBold(true); + leftLabel->setFont(font); + p_plot->setAxisTitle(QwtPlot::yLeft, *leftLabel); + + p_dock = new QDockWidget("Histogram Info",this); + p_dock->setAllowedAreas(Qt::AllDockWidgetAreas); + p_dock->setFloating(false); + p_dock->setObjectName("DockWidget"); + p_dock->setMinimumWidth(130); + p_mainWindow->addDockWidget(Qt::LeftDockWidgetArea, p_dock, Qt::Vertical); + + QwtText *rtLabel = new QwtText("Percentage", + QwtText::PlainText); + rtLabel->setColor(Qt::red); + font = rtLabel->font(); + font.setPointSize(13); + font.setBold(true); + rtLabel->setFont(font); + p_plot->setAxisTitle(QwtPlot::yRight,*rtLabel); + + setAxisLabel(QwtPlot::xBottom,"Pixel Value (DN)"); + + setScale(QwtPlot::yRight,0,100); + + setPlotBackground(Qt::white); + } + + + /** + * This method adds a PlotToolCurve to the window. + * + * @param pc + */ + void HistogramToolWindow::add(PlotToolCurve *pc){ + PlotWindow::add(pc); + p_plot->replot(); + } + + + /** + * Add a HistogramItem to the plot. + * + * + * @param hi + */ + void HistogramToolWindow::add(HistogramItem *hi){ + hi->attach(p_plot); + p_plot->replot(); + p_histItems.push_back(hi); + } + + + /** + * + * + */ + void HistogramToolWindow::addViewMenu(){ + QMenu *viewMenu = new QMenu("&View"); + QAction *viewInfo = new QAction("View Info", this); + connect(viewInfo, SIGNAL(activated()), p_dock, SLOT(show())); + viewMenu->addAction(viewInfo); + p_mainWindow->menuBar()->addMenu(viewMenu); + } + + /** + * This class needs to know which viewport the user is looking + * at so it can appropriately draw in the band lines. + * + * @param cvp + */ + void HistogramToolWindow::setViewport(CubeViewport *cvp){ + if(cvp == NULL) return; + p_cvp = cvp; + } + +} diff --git a/isis/src/qisis/objs/HistogramToolWindow/HistogramToolWindow.h b/isis/src/qisis/objs/HistogramToolWindow/HistogramToolWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..78e321dff83eeb2d594be1cc5d7a18a13491f615 --- /dev/null +++ b/isis/src/qisis/objs/HistogramToolWindow/HistogramToolWindow.h @@ -0,0 +1,35 @@ +#ifndef HistogramToolWindow_h +#define HistogramToolWindow_h + +#include "PlotWindow.h" +#include "PlotToolCurve.h" +#include "HistogramItem.h" +#include "Histogram.h" + +#include + +namespace Qisis { + class HistogramToolWindow : public Qisis::PlotWindow { + Q_OBJECT + + public: + HistogramToolWindow(QString title,QWidget *parent); + void add(PlotToolCurve *pc); + void add(HistogramItem *hi); + void addViewMenu(); + void setViewport(CubeViewport *cvp); + int getNumItems() { return p_histItems.size(); } + HistogramItem *getHistItem(int index) { return p_histItems[index]; } + QDockWidget *getDockWidget() { return p_dock; } + + public slots: + + + private: + CubeViewport *p_cvp; //!< The current viewport + QList p_histItems; + QDockWidget *p_dock; + }; +}; + +#endif diff --git a/isis/src/qisis/objs/HistogramToolWindow/Makefile b/isis/src/qisis/objs/HistogramToolWindow/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/HistogramToolWindow/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MainWindow/MainWindow.cpp b/isis/src/qisis/objs/MainWindow/MainWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..21ca3548a2959077c3eff3660daced7b2a4ec74a --- /dev/null +++ b/isis/src/qisis/objs/MainWindow/MainWindow.cpp @@ -0,0 +1,119 @@ +#include "MainWindow.h" +#include + +namespace Qisis { + /** + * Mainwindow constructor + * + * + * @param title + * @param parent + * @param flags + */ + MainWindow::MainWindow(QString title, QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) { + this->setWindowTitle(title); + if(parent){ + p_appName = parent->windowTitle().toStdString(); + } + + readSettings(); + } + + + /** + * + * + */ + MainWindow::~MainWindow(){ + } + + + /** + * This method is overridden so that we can be sure to write the + * current settings of the Main window. + * + * @param event + */ + void MainWindow::closeEvent(QCloseEvent *event) { + writeSettings(); + } + + + /** + * This method ensure that the settings get written even if the + * Main window was only hidden, not closed. + * + * @param event + */ + void MainWindow::hideEvent(QHideEvent *event) { + writeSettings(); + } + + + /** + * This method is called from the constructor so that when the + * Main window is created, it know's it's size and location. + * + */ + void MainWindow::readSettings(){ + if(p_appName == "") { + p_appName = this->windowTitle().toStdString(); + } + + std::string instanceName = this->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/"+ p_appName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()),QSettings::NativeFormat); + QPoint pos = settings.value("pos", QPoint(300, 100)).toPoint(); + QSize size = settings.value("size", QSize(900, 500)).toSize(); + resize(size); + move(pos); + } + + + /** + * This method is called when the Main window is closed or + * hidden to write the size and location settings to a config + * file in the user's home directory. + * + */ + void MainWindow::writeSettings() { + /*We do not want to write the settings unless the window is + visible at the time of closing the application*/ + if(!this->isVisible()) return; + + if(p_appName == "") { + p_appName = this->windowTitle().toStdString(); + } + + std::string instanceName = this->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/"+ p_appName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()),QSettings::NativeFormat); + settings.setValue("pos", pos()); + settings.setValue("size", size()); + } + + + /** + * This event filter is installed on the parent of this window. + * When the user closes the main window of the application, the + * Mainwindow will write their settings even though they did not + * receive the close event themselves. + * + * @param o + * @param e + * + * @return bool + */ + bool MainWindow::eventFilter(QObject *o,QEvent *e) { + switch (e->type()) { + case QEvent::Close:{ + writeSettings(); + } + + default: { + return false; + } + } + } +} + diff --git a/isis/src/qisis/objs/MainWindow/MainWindow.h b/isis/src/qisis/objs/MainWindow/MainWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..b276ec5c2b40e0ea7739b979acdd057d75aee514 --- /dev/null +++ b/isis/src/qisis/objs/MainWindow/MainWindow.h @@ -0,0 +1,39 @@ +#ifndef MainWindow_h +#define MainWindow_h +#include +#include +#include +#include "Filename.h" + +namespace Qisis { + /** + * @brief Base class for the Qisis main windows + * + * @ingroup Visualization Tools + * + * @author Stacy Alley + * + */ + + + class MainWindow : public QMainWindow { + Q_OBJECT + public: + MainWindow (QString title, QWidget *parent=0, Qt::WFlags flags=0); + virtual ~MainWindow(); + virtual void closeEvent(QCloseEvent *event); + + virtual void hideEvent(QHideEvent *event); + virtual void readSettings(); + virtual void writeSettings(); + + protected: + virtual bool eventFilter(QObject *o,QEvent *e); + + private: + std::string p_appName; //!< Application name. + + }; +}; + +#endif diff --git a/isis/src/qisis/objs/MainWindow/Makefile b/isis/src/qisis/objs/MainWindow/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MainWindow/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/Makefile b/isis/src/qisis/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/qisis/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/qisis/objs/MdiCubeViewport/Makefile b/isis/src/qisis/objs/MdiCubeViewport/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MdiCubeViewport/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MdiCubeViewport/MdiCubeViewport.cpp b/isis/src/qisis/objs/MdiCubeViewport/MdiCubeViewport.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8a283137c23034bffbbec58e4419f242e691275b --- /dev/null +++ b/isis/src/qisis/objs/MdiCubeViewport/MdiCubeViewport.cpp @@ -0,0 +1,169 @@ +/** + * @file + * $Date: 2010/06/30 03:42:28 $ + * $Revision: 1.2 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "MdiCubeViewport.h" + +#include +#include + +#include +#include + +#include "Filename.h" +#include "Tool.h" +#include "RubberBandTool.h" +#include "StretchTool.h" + + +using namespace Isis; +using namespace std; + + +namespace Qisis +{ + MdiCubeViewport::MdiCubeViewport(Cube * cube, QWidget * parent) : + CubeViewport(cube, parent) + { + p_linked = false; + + string unlinkedIcon = Filename("$base/icons/unlinked.png").Expanded(); + static QIcon unlinked(unlinkedIcon.c_str()); + parentWidget()->setWindowIcon(unlinked); + + } + + MdiCubeViewport::~MdiCubeViewport() + { + + } + + + /** + * Registers the tool given tool. + * + * @param tool + */ + void MdiCubeViewport::registerTool(Tool * tool) + { + p_toolList.push_back(tool); + } + + + /** + * Change the linked state of the viewport + * + * + * @param b + */ + void MdiCubeViewport::setLinked(bool b) + { + if (!parentWidget() || !parentWidget()->parentWidget()) + return; + + string unlinkedIcon = Filename("$base/icons/unlinked.png").Expanded(); + static QIcon unlinked(unlinkedIcon.c_str()); + string linkedIcon = Filename("$base/icons/linked.png").Expanded(); + static QIcon linked(linkedIcon.c_str()); + + bool notify = false; + if (b != p_linked) + notify = true; + + p_linked = b; + if (p_linked) + { + parentWidget()->parentWidget()->setWindowIcon(linked); + } + else + { + parentWidget()->parentWidget()->setWindowIcon(unlinked); + } + + if (notify) + emit linkChanging(b); + } + + + /** + * Repaint the viewport + * + * @param e [in] (QPaintEvent *) event + * + * @internal + * + * @history 2007-04-30 Tracie Sucharski - Add the QPainter to the call to + * Tool::paintViewport. + */ + void MdiCubeViewport::paintEvent(QPaintEvent * e) + { + CubeViewport::paintEvent(e); + + QPainter painter(viewport()); + painter.drawPixmap(0, 0, p_pixmap); + emit viewportUpdated(); + + // Draw anything the tools might need + for (int i = 0; i < p_toolList.size(); i++) + { + p_toolList[i]->paintViewport(this, &painter); + } + + painter.end(); + } + + + void MdiCubeViewport::viewGray(int band) + { + CubeViewport::viewGray(band); + + for (int i = 0; i < p_toolList.size(); i++) + p_toolList[i]->updateTool(); + } + + + void MdiCubeViewport::viewRGB(int rband, int gband, int bband) + { + CubeViewport::viewRGB(rband, gband, bband); + + for (int i = 0; i < p_toolList.size(); i++) + p_toolList[i]->updateTool(); + } + + + void MdiCubeViewport::restretch(ViewportBuffer *buffer) + { + if (buffer == grayBuffer()) + { + emit requestRestretch(this, (int)StretchTool::Gray); + } + else if (buffer == redBuffer()) + { + emit requestRestretch(this, (int)StretchTool::Red); + } + else if (buffer == greenBuffer()) + { + emit requestRestretch(this, (int)StretchTool::Green); + } + else if (buffer == blueBuffer()) + { + emit requestRestretch(this, (int)StretchTool::Blue); + } + } +} diff --git a/isis/src/qisis/objs/MdiCubeViewport/MdiCubeViewport.h b/isis/src/qisis/objs/MdiCubeViewport/MdiCubeViewport.h new file mode 100644 index 0000000000000000000000000000000000000000..33d79121ac8a96bdcc07856f4465070c27677414 --- /dev/null +++ b/isis/src/qisis/objs/MdiCubeViewport/MdiCubeViewport.h @@ -0,0 +1,95 @@ +#ifndef MdiCubeViewport_h +#define MdiCubeViewport_h + +/** + * @file + * $Date: 2010/06/30 03:42:28 $ + * $Revision: 1.2 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +// The only includes allowed in this file are the direct parents of this class! +#include "CubeViewport.h" +// There are absolutely no exceptions to this. + + + +class QPaintEvent; +template < class T > class QList; + +namespace Isis +{ + class Cube; +} + +namespace Qisis +{ + class Tool; + class ViewportBuffer; + + /** + * @brief Cube display widget for certain Isis MDI applications + * + * @ingroup Visualization Tools + * + * @author Eric Hyer - Moved MDI specific code here from CubeViewport + * + * @internal + * + * @see Workspace CubeViewport + */ + class MdiCubeViewport : public CubeViewport + { + Q_OBJECT + + public: + MdiCubeViewport(Isis::Cube * cube, QWidget * parent = 0); + ~MdiCubeViewport(); + + void forceAbstract() {} + + //! Is the viewport linked with other viewports + bool isLinked() const + { + return p_linked; + }; + + void registerTool(Tool * tool); + void paintEvent(QPaintEvent * e); + void restretch(ViewportBuffer * buffer); + + + signals: + void linkChanging(bool); + void requestRestretch(MdiCubeViewport *, int); + + + public slots: + void setLinked(bool b); + void viewGray(int band); + void viewRGB(int red, int green, int blue); + + + private: + bool p_linked; + QList p_toolList; + + }; +} + +#endif diff --git a/isis/src/qisis/objs/MeasureTool/Makefile b/isis/src/qisis/objs/MeasureTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MeasureTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MeasureTool/MeasureTool.cpp b/isis/src/qisis/objs/MeasureTool/MeasureTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2327d112f8dea2788cfee7f49cfaf53de981936c --- /dev/null +++ b/isis/src/qisis/objs/MeasureTool/MeasureTool.cpp @@ -0,0 +1,774 @@ +#include "MeasureTool.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "geos/geom/Geometry.h" +#include "geos/geom/Point.h" + +#include "Camera.h" +#include "Filename.h" +#include "MdiCubeViewport.h" +#include "ToolPad.h" + + +namespace Qisis { + /** + * MeasureTool constructor + * + * + * @param parent + */ + MeasureTool::MeasureTool (QWidget *parent) : Qisis::Tool(parent) { + p_rubberBand = NULL; + p_tableWin = new TableMainWindow ("Measurements", parent); + p_tableWin->setTrackListItems(true); + + // Create the action for showing the table + p_action = new QAction(parent); + p_action->setText("Measuring ..."); + + connect(p_action,SIGNAL(triggered()),p_tableWin,SLOT(showTable())); + connect(p_action,SIGNAL(triggered()),p_tableWin,SLOT(raise())); + connect(p_action,SIGNAL(triggered()),p_tableWin,SLOT(syncColumns())); + p_tableWin->installEventFilter(this); + + p_tableWin->addToTable (false,"Feature\nName","Feature Name"); + p_tableWin->addToTable (false,"Feature\nType","Feature Type"); + p_tableWin->addToTable (true, + "Start\nLatitude:Start\nLongitude:End\nLatitude:End\nLongitude", + "Ground Range", -1, Qt::Horizontal, "Start Latitude/Longitude to End Latitude/Longitude"); + p_tableWin->addToTable (false,"Start\nSample:Start\nLine:End\nSample:End\nLine", + "Pixel Range", -1, Qt::Horizontal, "Start Sample/Line to End Sample/Line"); + p_tableWin->addToTable(true,"Kilometer\nDistance","Kilometer Distance"); + p_tableWin->addToTable (false,"Meter\nDistance","Meter Distance"); + p_tableWin->addToTable (false,"Pixel\nDistance","Pixel Distance"); + p_tableWin->addToTable (false,"Degree\nAngle","Degree Angle"); + p_tableWin->addToTable (false,"Radian\nAngle","Radian Angle"); + p_tableWin->addToTable (false,"Kilometer\nArea","Kilometer Area"); + p_tableWin->addToTable (false,"Meter\nArea","Meter Area"); + p_tableWin->addToTable (false,"Pixel\nArea","Pixel Area"); + p_tableWin->addToTable (false,"Segments Sum\nkm","Segments Sum", -1, Qt::Horizontal, "Sum of Segment lengths in kilometers"); + p_tableWin->addToTable (false,"Segment Number","Segment Number", -1, Qt::Horizontal, "Segment number of a segmented line"); + p_tableWin->addToTable (false,"Path","Path"); + p_tableWin->addToTable (false,"Filename","Filename"); + p_tableWin->addToTable (false,"Notes","Notes"); + + // Setup 10 blank rows in the table + for (int r=0; r<4; r++) { + p_tableWin->table()->insertRow(r); + for (int c=0; ctable()->columnCount(); c++) { + QTableWidgetItem *item = new QTableWidgetItem(""); + p_tableWin->table()->setItem(r,c,item); + } + } + + p_tableWin->setStatusMessage("Click, Drag, and Release to Measure a Line"); + } + + + /** + * Add the measure tool action to the toolpad. + * + * + * @param toolpad + * + * @return QAction* + */ + QAction *MeasureTool::toolPadAction(ToolPad *toolpad) { + QAction *action = new QAction(toolpad); + action->setIcon(QPixmap(toolIconDir()+"/measure.png")); + action->setToolTip("Measure (M)"); + action->setShortcut(Qt::Key_M); + + QString text = + "Function: Measure features in active viewport \ +

    Shortcut: M

    "; + action->setWhatsThis(text); + + return action; + } + + + /** + * Creates the widget (button) that goes on the tool bar + * + * + * @param parent + * + * @return QWidget* + */ + QWidget *MeasureTool::createToolBarWidget (QStackedWidget *parent) { + QWidget *hbox = new QWidget(parent); + QToolButton *measureButton = new QToolButton(hbox); + measureButton->setText("Table"); + measureButton->setToolTip("Record Measurement Data in Table"); + QString text = + "Function: This button will bring up a table that will record the \ + starting and ending points of the line, along with the distance between \ + the two points on the image. To measure the distance between two points, \ + click on the first point and releasing the mouse at the second point. \ +

    Shortcut: CTRL+M

    "; + measureButton->setWhatsThis(text); + measureButton->setShortcut(Qt::CTRL+Qt::Key_M); + connect(measureButton,SIGNAL(clicked()),p_tableWin,SLOT(showTable())); + connect(measureButton,SIGNAL(clicked()),p_tableWin,SLOT(syncColumns())); + connect(measureButton,SIGNAL(clicked()),p_tableWin,SLOT(raise())); + measureButton->setEnabled(true); + + p_rubberBand = new RubberBandComboBox( + RubberBandComboBox::Angle | + RubberBandComboBox::Circle | + RubberBandComboBox::Ellipse | + RubberBandComboBox::Line | + RubberBandComboBox::Rectangle | + RubberBandComboBox::RotatedRectangle | + RubberBandComboBox::Polygon | + RubberBandComboBox::SegmentedLine, // options + RubberBandComboBox::Line // default + ); + + p_distLineEdit = new QLineEdit(hbox); + p_distLineEdit->setText(""); + p_distLineEdit->setMaxLength(12); + p_distLineEdit->setToolTip("Line Length"); + QString text2 = "Function: Shows the length of the line drawn on \ + the image."; + p_distLineEdit->setWhatsThis(text2); + p_distLineEdit->setReadOnly(true); + + p_showAllSegments = new QCheckBox(hbox); + p_showAllSegments->setText("Show All Segments"); + + p_unitsComboBox = new QComboBox(hbox); + p_unitsComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + + updateUnitsCombo(); + connect(p_unitsComboBox,SIGNAL(activated(int)),this,SLOT(updateDistEdit())); + connect(RubberBandTool::getInstance(),SIGNAL(modeChanged()),this,SLOT(updateUnitsCombo())); + + miComboUnit=-1; + + QHBoxLayout *layout = new QHBoxLayout(hbox); + layout->setMargin(0); + layout->addWidget(p_rubberBand); + layout->addWidget(p_distLineEdit); + layout->addWidget(p_unitsComboBox); + layout->addWidget(measureButton); + layout->addWidget(p_showAllSegments); + layout->addStretch(1); + hbox->setLayout(layout); + return hbox; + } + + + /** + * Updates the units combo box. + * + */ + void MeasureTool::updateUnitsCombo(void) { + // get the previous index if not initializing + if (miComboUnit >= 0) { + miComboUnit = p_unitsComboBox->currentIndex(); + } + + p_unitsComboBox->clear(); + p_showAllSegments->setEnabled(false); + + if(RubberBandTool::getMode() == RubberBandTool::Line || + RubberBandTool::getMode() == RubberBandTool::SegmentedLine) { + + if(RubberBandTool::getMode() == RubberBandTool::SegmentedLine) { + p_showAllSegments->setEnabled(true); + } + + p_unitsComboBox->addItem("km"); + p_unitsComboBox->addItem("m"); + p_unitsComboBox->addItem("pixels"); + if (miComboUnit < 0 || miComboUnit > 2) { // default && error checking + miComboUnit = 2; + } + } + else if(RubberBandTool::getMode() == RubberBandTool::Angle) { + p_unitsComboBox->addItem("degrees"); + p_unitsComboBox->addItem("radians"); + if (miComboUnit > 1 || miComboUnit < 0) { // default && error checking + miComboUnit = 0; + } + } + else { + p_unitsComboBox->addItem("km^2"); + p_unitsComboBox->addItem("m^2"); + p_unitsComboBox->addItem("pix^2"); + if (miComboUnit < 0 || miComboUnit > 2) { // default && error checking + miComboUnit = 2; + } + } + + p_unitsComboBox->setCurrentIndex(miComboUnit); + } + + + /** + * Adds the measure action to the given menu. + * + * + * @param menu + */ + void MeasureTool::addTo(QMenu *menu) { + menu->addAction(p_action); + } + + + /** + * Updates the Measure specifications. + * + */ + void MeasureTool::updateMeasure() { + MdiCubeViewport *cvp = cubeViewport(); + MdiCubeViewport *d; + p_numLinked = 0; + + if (cvp == NULL) { + p_tableWin->clearRow(p_tableWin->currentRow()); + return; + } + + updateDist(cvp, p_tableWin->currentRow()); + + p_tableWin->table()->selectRow(p_tableWin->currentRow()); + + if(cvp->isLinked()) { + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + d = (*(cubeViewportList()))[i]; + + if (d->isLinked() && d != cvp) { + p_numLinked++; + updateDist(d, p_tableWin->currentRow()+p_numLinked); + } + } + } + } + + + /** + * Called when the rubberBanding by the user is finished. + * + */ + void MeasureTool::rubberBandComplete() { + updateMeasure(); + + if (RubberBandTool::getMode() != RubberBandTool::Angle && p_unitsComboBox->currentIndex() != 2) { + if (p_cvp->camera() == NULL && p_cvp->projection() == NULL) { + QMessageBox::information((QWidget *)parent(), "Error", + "File must have a Camera Model or Projection to measure in km or m"); + return; + } + } + + if (!p_tableWin->table()->isVisible()) return; + if (p_tableWin->table()->item(p_tableWin->currentRow(),StartLineIndex)->text() == "N/A" && + p_tableWin->table()->item(p_tableWin->currentRow(),AngleDegIndex)->text() == "N/A" && + p_tableWin->table()->item(p_tableWin->currentRow(),AreaPixIndex)->text() == "N/A") return; + + if(!p_cvp->isLinked())p_tableWin->setCurrentRow(p_tableWin->currentRow() + 1); + if(p_cvp->isLinked()){ + p_tableWin->setCurrentRow(p_tableWin->currentRow() + p_numLinked + 1); + } + p_tableWin->setCurrentIndex(p_tableWin->currentIndex() + 1); + while (p_tableWin->currentRow() >= p_tableWin->table()->rowCount()) { + int row = p_tableWin->table()->rowCount(); + p_tableWin->table()->insertRow(row); + for (int c=0; ctable()->columnCount(); c++) { + QTableWidgetItem *item = new QTableWidgetItem(""); + p_tableWin->table()->setItem(row,c,item); + } + } + + QApplication::sendPostedEvents(p_tableWin->table(),0); + p_tableWin->table()->scrollToItem(p_tableWin->table()->item(p_tableWin->currentRow(),0),QAbstractItemView::PositionAtBottom); + } + + + /** + * Mouse leave event. + * + */ + void MeasureTool::mouseLeave() { + //p_tableWin->clearRow(p_tableWin->currentRow()); + } + + + /** + * Enables/resets the rubberband tool. + * + */ + void MeasureTool::enableRubberBandTool() { + if(p_rubberBand) { + p_rubberBand->reset(); + } + } + + + /** + * This method updates the row in the table window with the + * current measure information. + * + * + * @param row + */ + void MeasureTool::updateRow(int row) { + if (row+1 > p_tableWin->table()->rowCount()) { + p_tableWin->table()->insertRow(row); + for (int c=0; ctable()->columnCount(); c++) { + QTableWidgetItem *item = new QTableWidgetItem(""); + p_tableWin->table()->setItem(row,c,item); + if (c == 0) p_tableWin->table()->scrollToItem(item); + } + } + + // Blank out the row to remove stuff left over from previous cvps + for (int c=0; ctable()->columnCount(); c++) { + p_tableWin->table()->item(row,c)->setText(""); + } + + // Write all the new info to the current row + if (p_startLat != Isis::Null && p_startLon != Isis::Null) { + p_tableWin->table()->item(row,StartLatIndex)->setText(QString::number(p_startLat)); + p_tableWin->table()->item(row,StartLonIndex)->setText(QString::number(p_startLon)); + } else { + p_tableWin->table()->item(row,StartLatIndex)->setText("N/A"); + p_tableWin->table()->item(row,StartLonIndex)->setText("N/A"); + } + + if (p_endLat != Isis::Null && p_endLon != Isis::Null) { + p_tableWin->table()->item(row,EndLatIndex)->setText(QString::number(p_endLat)); + p_tableWin->table()->item(row,EndLonIndex)->setText(QString::number(p_endLon)); + p_tableWin->table()->item(row,DistanceKmIndex)->setText(QString::number(p_kmDist)); + p_tableWin->table()->item(row,DistanceMIndex)->setText(QString::number(p_mDist)); + } else { + p_tableWin->table()->item(row,EndLatIndex)->setText("N/A"); + p_tableWin->table()->item(row,EndLonIndex)->setText("N/A"); + p_tableWin->table()->item(row,DistanceKmIndex)->setText("N/A"); + p_tableWin->table()->item(row,DistanceMIndex)->setText("N/A"); + } + + if (p_degAngle != Isis::Null && p_radAngle != Isis::Null) { + p_tableWin->table()->item(row,AngleDegIndex)->setText(QString::number(p_degAngle)); + p_tableWin->table()->item(row,AngleRadIndex)->setText(QString::number(p_radAngle)); + } else { + p_tableWin->table()->item(row,AngleDegIndex)->setText("N/A"); + p_tableWin->table()->item(row,AngleRadIndex)->setText("N/A"); + } + + if (p_startSamp != Isis::Null && p_startLine != Isis::Null) { + p_tableWin->table()->item(row,StartSampIndex)->setText(QString::number(p_startSamp)); + p_tableWin->table()->item(row,StartLineIndex)->setText(QString::number(p_startLine)); + } else { + p_tableWin->table()->item(row,StartSampIndex)->setText("N/A"); + p_tableWin->table()->item(row,StartLineIndex)->setText("N/A"); + } + + if (p_endSamp != Isis::Null && p_endLine != Isis::Null) { + p_tableWin->table()->item(row,EndSampIndex)->setText(QString::number(p_endSamp)); + p_tableWin->table()->item(row,EndLineIndex)->setText(QString::number(p_endLine)); + p_tableWin->table()->item(row,DistancePixIndex)->setText(QString::number(p_pixDist)); + } else { + p_tableWin->table()->item(row,EndSampIndex)->setText("N/A"); + p_tableWin->table()->item(row,EndLineIndex)->setText("N/A"); + p_tableWin->table()->item(row,DistancePixIndex)->setText("N/A"); + } + + if (p_pixArea != Isis::Null) { + p_tableWin->table()->item(row,AreaPixIndex)->setText(QString::number(p_pixArea)); + } else { + p_tableWin->table()->item(row,AreaPixIndex)->setText("N/A"); + } + + if (p_mArea != Isis::Null) { + p_tableWin->table()->item(row,AreaKmIndex)->setText(QString::number(p_kmArea)); + p_tableWin->table()->item(row,AreaMIndex)->setText(QString::number(p_mArea)); + } else { + p_tableWin->table()->item(row,AreaKmIndex)->setText("N/A"); + p_tableWin->table()->item(row,AreaMIndex)->setText("N/A"); + } + + p_tableWin->table()->item(row,PathIndex)->setText(p_path.c_str()); + p_tableWin->table()->item(row,FilenameIndex)->setText(p_fname.c_str()); + + } + + + + /** + * This method is called instead of updateRows if the + * 'Show All Segment' checkbox is checked. + * + * + * @param row + */ + void MeasureTool::updateRows(int row){ + if (p_distanceSegments.size() < 2) { + updateRow(row); + return; + } + + int requiredRows = p_distanceSegments.size() + row + 2; + int rowDiff = (int)(requiredRows - p_tableWin->table()->rowCount()); + + //Make sure we have all the necessary rows and items in each table cell. + if (requiredRows > p_tableWin->table()->rowCount()) { + for (int r = 0; r < rowDiff; r++) { + p_tableWin->table()->insertRow(row + r); + for (int c = 0; c < p_tableWin->table()->columnCount(); c++) { + QTableWidgetItem *item = new QTableWidgetItem(""); + p_tableWin->table()->setItem(row + r,c,item); + if (c == 0) p_tableWin->table()->scrollToItem(item); + } + } + } + + if (RubberBandTool::getMode() == RubberBandTool::SegmentedLine && p_distanceSegments.size() > 0) { + double distanceSum = 0; + for (int i = 0; i < p_distanceSegments.size(); i++) { + //write a new row for each segment... + p_tableWin->table()->item(row+i,StartLatIndex)->setText(QString::number(p_startLatSegments[i])); + p_tableWin->table()->item(row+i,StartLonIndex)->setText(QString::number(p_startLonSegments[i])); + + p_tableWin->table()->item(row+i,EndLatIndex)->setText(QString::number(p_endLatSegments[i])); + p_tableWin->table()->item(row+i,EndLonIndex)->setText(QString::number(p_endLonSegments[i])); + + p_tableWin->table()->item(row+i,StartSampIndex)->setText(QString::number(p_startSampSegments[i])); + p_tableWin->table()->item(row+i,StartLineIndex)->setText(QString::number(p_startLineSegments[i])); + + p_tableWin->table()->item(row+i,EndSampIndex)->setText(QString::number(p_endSampSegments[i])); + p_tableWin->table()->item(row+i,EndLineIndex)->setText(QString::number(p_endLineSegments[i])); + + p_tableWin->table()->item(row+i,DistancePixIndex)->setText(QString::number(p_pixDistSegments[i])); + + p_tableWin->table()->item(row+i,DistanceKmIndex)->setText(QString::number(p_distanceSegments[i])); + p_tableWin->table()->item(row+i,DistanceMIndex)->setText(QString::number(p_distanceSegments[i]*1000)); + + p_tableWin->table()->item(row+i,PathIndex)->setText(p_path.c_str()); + p_tableWin->table()->item(row+i,FilenameIndex)->setText(p_fname.c_str()); + + distanceSum += p_distanceSegments[i]; + + p_tableWin->table()->item(row+i,SegmentsSumIndex)->setText(QString::number(distanceSum)); + p_tableWin->table()->item(row+i,SegmentNumberIndex)->setText(QString::number(i+1)); + } + + //update the current row + p_tableWin->setCurrentRow(row + p_distanceSegments.size()-1); + p_distanceSegments.clear(); + p_pixDistSegments.clear(); + p_startSampSegments.clear(); + p_endSampSegments.clear(); + p_startLineSegments.clear(); + p_endLineSegments.clear(); + p_startLatSegments.clear(); + p_endLatSegments.clear(); + p_startLonSegments.clear(); + p_endLonSegments.clear(); + + } + } + + /** + * Initialize Class data + * + * @author sprasad (10/23/2009) + */ + void MeasureTool::initData(void) + { + // Initialize the class data + p_startSamp = Isis::Null; + p_endSamp = Isis::Null; + p_startLine = Isis::Null; + p_endLine = Isis::Null; + p_kmDist = Isis::Null; + p_mDist = Isis::Null; + p_pixDist = Isis::Null; + p_startLon = Isis::Null; + p_startLat = Isis::Null; + p_endLon = Isis::Null; + p_endLat = Isis::Null; + p_radAngle = Isis::Null; + p_degAngle = Isis::Null; + p_pixArea = Isis::Null; + p_kmArea = Isis::Null; + p_mArea = Isis::Null; + } + + /** + * This method updates the distance variables + * + * + * @param cvp - Pointer to CubeViewPort + * @param row - row index + * + * @returns void + */ + void MeasureTool::updateDist (MdiCubeViewport *cvp, int row) + { + // Initialize class data + initData(); + + // Write out col 8 (the file name) + Isis::Filename fname = Isis::Filename(cvp->cube()->Filename()).Expanded(); + p_path = fname.Path(); + p_fname = fname.Name(); + + // reset the distnace gui + p_distLineEdit->setText(""); + + if (RubberBandTool::getMode() == RubberBandTool::Line || + RubberBandTool::getMode() == RubberBandTool::SegmentedLine) { + + p_pixDist = 0; + p_mDist = 0; + p_kmDist = 0; + + // Flag to indicate whether distance was calculated + bool bDistance=false; + double radius = 0; + double mDist = 0; + + for(int startIndex = 0; startIndex < RubberBandTool::getVertices().size()-1; startIndex++) { + QPoint start = RubberBandTool::getVertices()[startIndex]; + QPoint end = RubberBandTool::getVertices()[startIndex+1]; + + // Convert rubber band line to cube coordinates + cvp->viewportToCube(start.x(), start.y(), p_startSamp, p_startLine); + cvp->viewportToCube(end.x(), end.y(), p_endSamp, p_endLine); + + // Don't write anything if we are outside the cube + if ((p_startSamp < 0.5) || (p_endSamp < 0.5) || + (p_startLine < 0.5) || (p_endLine < 0.5) || + (p_startSamp > cvp->cubeSamples() + 0.5) || + (p_endSamp > cvp->cubeSamples() + 0.5) || + (p_startLine > cvp->cubeLines() + 0.5) || + (p_endLine > cvp->cubeLines() + 0.5)) { + p_mDist = Isis::Null; + p_kmDist = Isis::Null; + p_pixDist = 0; + return; + } + + // Check if the image is projected (Projected Images also have camera except for mosaics) + if (cvp->projection() != NULL) { + if (cvp->projection()->SetWorld(p_startSamp,p_startLine)) { + // If our projection is sky, the lat & lons are switched + if (cvp->projection()->IsSky()) { + p_startLat = cvp->projection()->UniversalLongitude(); + p_startLon = cvp->projection()->UniversalLatitude(); + } + else { + p_startLat = cvp->projection()->UniversalLatitude(); + p_startLon = cvp->projection()->UniversalLongitude(); + } + + if (cvp->projection()->SetWorld(p_endSamp,p_endLine)) { + // If our projection is sky, the lat & lons are switched + if (cvp->projection()->IsSky()) { + p_endLat = cvp->projection()->UniversalLongitude(); + p_endLon = cvp->projection()->UniversalLatitude(); + } + else { + p_endLat = cvp->projection()->UniversalLatitude(); + p_endLon = cvp->projection()->UniversalLongitude(); + } + } + // Calculate and write out the distance between the two points + radius = cvp->projection()->LocalRadius(); + + // distance is calculated + bDistance = true; + } + } + // Do we have a camera model? + else if (cvp->camera() != NULL) { + if (cvp->camera()->SetImage(p_startSamp,p_startLine)) { + + // Write columns 2-3 (Start lat/lon) + p_startLat = cvp->camera()->UniversalLatitude(); + p_startLon = cvp->camera()->UniversalLongitude(); + + if (cvp->camera()->SetImage(p_endSamp,p_endLine)) { + // Write columns 4-5 (End lat/lon) + p_endLat = cvp->camera()->UniversalLatitude(); + p_endLon = cvp->camera()->UniversalLongitude(); + + radius = cvp->camera()->LocalRadius(); + + // distance is calculated + bDistance = true; + } + } + } + + // Calculate the pixel difference + double lineDif = p_startLine - p_endLine; + double sampDif = p_startSamp - p_endSamp; + double pixDist = sqrt(lineDif * lineDif + sampDif * sampDif); + p_pixDist = pixDist; + + if (bDistance){ + mDist = Isis::Camera::Distance(p_startLat, p_startLon, p_endLat, p_endLon, radius); + p_mDist += mDist; + p_kmDist = p_mDist / 1000.0; + + if (RubberBandTool::getMode() == RubberBandTool::SegmentedLine) { + if(pixDist > 16/cvp->scale() && p_distanceSegments.size() < 75) { + p_distanceSegments.append(mDist / 1000.0); + p_pixDistSegments.append(pixDist); + p_startSampSegments.append(p_startSamp); + p_endSampSegments.append(p_endSamp); + p_startLineSegments.append(p_startLine); + p_endLineSegments.append(p_endLine); + p_startLatSegments.append(p_startLat); + p_endLatSegments.append(p_endLat); + p_startLonSegments.append(p_startLon); + p_endLonSegments.append(p_endLon); + } + } + } + bDistance=false; + } + // Distance was not calculated + if (!p_mDist) { + p_mDist = Isis::Null; + p_kmDist = Isis::Null; + } + } + else if(RubberBandTool::getMode() == RubberBandTool::Angle) { + p_radAngle = RubberBandTool::getAngle(); + p_degAngle = p_radAngle * 180.0 / Isis::PI; + } + else { + geos::geom::Geometry *polygon = RubberBandTool::geometry(); + if(polygon != NULL) { + // pix area = screenpix^2 / scale^2 + p_pixArea = polygon->getArea() / pow(cvp->scale(), 2); + geos::geom::Point *center = polygon->getCentroid(); + double line, sample; + cvp->viewportToCube((int)center->getX(), (int)center->getY(), sample,line); + + if(cvp->camera() != NULL) { + cvp->camera()->SetImage(sample,line); + // pix^2 * (m/pix)^2 = m^2 + p_mArea = p_pixArea * pow(cvp->camera()->PixelResolution(), 2); + // m^2 * (km/m)^2 = km^2 + p_kmArea = p_mArea * pow(1 / 1000.0, 2); + } + + if(cvp->projection() != NULL) { + cvp->projection()->SetWorld(sample,line); + // pix^2 * (m/pix)^2 = m^2 + p_mArea = p_pixArea * pow(cvp->projection()->Resolution(), 2); + // m^2 * (km/m)^2 = km^2 + p_kmArea = p_mArea * pow(1 / 1000.0, 2); + } + } + } + + updateDistEdit(); + + if(p_showAllSegments->isChecked()) { + updateRows(row); + } + else { + updateRow(row); + } + } + + + //! Change the value in the distance edit to match the units + void MeasureTool::updateDistEdit() { + if(RubberBandTool::getMode() == RubberBandTool::Line || + RubberBandTool::getMode() == RubberBandTool::SegmentedLine) { + if (p_unitsComboBox->currentIndex() == 0) { + if (p_kmDist == Isis::Null) { + p_distLineEdit->setText("N/A"); + } + else { + p_distLineEdit->setText(QString::number(p_kmDist)); + } + } + else if (p_unitsComboBox->currentIndex() == 1) { + if (p_mDist == Isis::Null) { + p_distLineEdit->setText("N/A"); + } + else { + p_distLineEdit->setText(QString::number(p_mDist)); + } + } + else { + p_distLineEdit->setText(QString::number(p_pixDist)); + } + } + else if(RubberBandTool::getMode() == RubberBandTool::Angle) { + if (p_unitsComboBox->currentIndex() == 0) { + p_distLineEdit->setText(QString::number(p_degAngle)); + } + else { + p_distLineEdit->setText(QString::number(p_radAngle)); + } + } + else { + if (p_unitsComboBox->currentIndex() == 0) { + if (p_kmArea == Isis::Null) { + p_distLineEdit->setText("N/A"); + } + else { + p_distLineEdit->setText(QString::number(p_kmArea)); + } + } + else if (p_unitsComboBox->currentIndex() == 1) { + if (p_mArea == Isis::Null) { + p_distLineEdit->setText("N/A"); + } + else { + p_distLineEdit->setText(QString::number(p_mArea)); + } + } + else { + if(p_pixArea != Isis::Null) { + p_distLineEdit->setText(QString::number(p_pixArea)); + } + else { + p_distLineEdit->setText("N/A"); + } + } + } + } + + + /** + * Removes the connection on the given cube viewport. + * + * + * @param cvp + */ + void MeasureTool::removeConnections(MdiCubeViewport *cvp) { + // cvp->repaint(); + cvp->update(); + } + + + /** + * Updates the measure tool. + * + */ + void MeasureTool::updateTool() { + p_distLineEdit->clear(); + } + +} + diff --git a/isis/src/qisis/objs/MeasureTool/MeasureTool.h b/isis/src/qisis/objs/MeasureTool/MeasureTool.h new file mode 100644 index 0000000000000000000000000000000000000000..0fec868d2bb078c11812befcdb6ce67ffc9ec599 --- /dev/null +++ b/isis/src/qisis/objs/MeasureTool/MeasureTool.h @@ -0,0 +1,178 @@ +#ifndef Qisis_MeasureTool_h +#define Qisis_MeasureTool_h + +#include "Tool.h" + +// FIXME: remove these includes +#include +#include "RubberBandComboBox.h" +#include "TableMainWindow.h" +#include "iString.h" + + +class QDialog; +class QMenu; +class QLineEdit; +class QComboBox; + +namespace Isis { + class iString; +} + +namespace Qisis { + class MdiCubeViewport; + + /** + * @brief Tool for measuring distances + * + * @ingroup Visualization Tools + * + * @author Unknown + * + * @internal + * @history 2007-11-19 Stacy Alley + * added the capability of the qisis + * windows to remember size and location + * @history 2007-11-29 Stacy Alley + * replaced all the table stuff with the new + * TableMainWindow class. + * @history 2008-08-18 Christopher Austin + * Upgraded to geos3.0.0 + * @history 2008-09-26 Steven Lambright Added Segmented line + * @history 2009-02-12 Steven Lambright Fixed bug where measure tool would + * not measure pixels for non-camera, non-projection + * cubes. + * @history 2010-02-17 Sharmila Prasad Fixed bug where the + * distance was calculated twice for a cube with both + * camera and projection + * Also made changes to save the most recent selection + * (km,m,pixels) when different tool is selected + * @history 2010-06-26 - Eric Hyer - Now uses MdiCubeViewport instead of + * CubeViewport. Fixed some include issues (some still remain!) + */ + class MeasureTool : public Tool { + Q_OBJECT + + public: + MeasureTool (QWidget *parent); + void addTo(QMenu *menu); + + protected slots: + virtual void rubberBandComplete(); + virtual void updateMeasure(); + virtual void mouseLeave(); + + protected: + //! Returns the menu name. + QString menuName() const { return "&Options"; }; + QWidget *createToolBarWidget (QStackedWidget *parent); + QAction *toolPadAction(ToolPad *pad); + void updateTool(); + void removeConnections(MdiCubeViewport *cvp); + void enableRubberBandTool(); + + private slots: + + void updateUnitsCombo(); + void updateDistEdit(); + + private: + QAction *p_action; //!< Measure tool's action + QLineEdit *p_distLineEdit; //!< Distance line edit + QComboBox *p_unitsComboBox; //!< Units selection + int miComboUnit; // Store the previous unit chosen + + void updateDist(MdiCubeViewport *cvp, int row); + void updateRow(int row); + void updateRows(int row); + void initData(void); + + /** + * Enum for all possible table columns. + */ + enum TableColumnsMap { + FeatureName, //!< Feature name. + FeatureType, //!< Feature type. + LatitudeLongitude, //!< Latitude Longitude. + SampleLine, //!< Sample Line + DistanceKm, //!< Distance in kilometers. + DistanceM, //!< Distance in meters. + DistancePix, //!< Distance in pixels. + AngleDeg, //!< Angle in degrees. + AngleRad, //!< Angle in radians. + AreaKm, //!< Area in kilometers. + AreaM, //!< Area in meters. + AreaPix, //!< Area in pixels. + Segments, //!< Segment lengths in kilometers. + Path, //!< Filename path + Filename, //!< Filename + Notes //!< User input + }; + + /** + * Enum for storing all the indexes. + */ + enum TableColumnIndex { + StartLatIndex = 2,//!< Starting latitude index + StartLonIndex,//!< Starting longitude index + EndLatIndex,//!< Ending latitude index + EndLonIndex,//!< Ending longitude index + StartSampIndex,//!< Starting sample index + StartLineIndex,//!< Starting line index + EndSampIndex,//!< Ending sample index + EndLineIndex,//!< Ending line index + DistanceKmIndex,//!< Distance in kilometers index + DistanceMIndex,//!< Distance in meters index + DistancePixIndex,//!< Distance in pixels index + AngleDegIndex,//!< Angle in degrees index + AngleRadIndex,//!< Angle in radians index + AreaKmIndex,//!< Area in kilometers index + AreaMIndex,//!< Area in meters index + AreaPixIndex,//!< Area in pixels index + SegmentsSumIndex,//!< Segment lengths in kilometers + SegmentNumberIndex, //!< Segment number + PathIndex,//!< Filename path index + FilenameIndex//!< Filename index + }; + + double p_startSamp;//!< starting sample + double p_endSamp;//!< ending sample + double p_startLine;//!< starting line + double p_endLine;//!< ending line + double p_startLat;//!< starting latitude + double p_endLat;//!< ending latitude + double p_startLon;//!< starting longitude + double p_endLon;//!< ending longitude + double p_kmDist;//!< distance in kilometers + double p_mDist;//!< distance in meters + double p_pixDist;//!< distance in pixels + double p_radAngle;//!< angle in radians + double p_degAngle;//!< angle in degrees + double p_kmArea;//!< area in kilometers + double p_mArea;//!< area in meters + double p_pixArea;//!< area in pixels + + QList p_distanceSegments; + QListp_pixDistSegments; + QListp_startSampSegments; + QListp_endSampSegments; + QListp_startLineSegments; + QListp_endLineSegments; + QListp_startLatSegments; + QListp_endLatSegments; + QListp_startLonSegments; + QListp_endLonSegments; + + + int p_numLinked;//!< number of linked viewports + Isis::iString p_path;//!< filename path + Isis::iString p_fname;//!< filename + + Qisis::TableMainWindow *p_tableWin;//!< table window + RubberBandComboBox *p_rubberBand;//!< rubberband combo box + QCheckBox *p_showAllSegments; + }; + +}; + +#endif diff --git a/isis/src/qisis/objs/MosaicControlNetTool/Makefile b/isis/src/qisis/objs/MosaicControlNetTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MosaicControlNetTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MosaicControlNetTool/MosaicControlNetTool.cpp b/isis/src/qisis/objs/MosaicControlNetTool/MosaicControlNetTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..122b9a7d800bed9579410b9e54f35db87222e451 --- /dev/null +++ b/isis/src/qisis/objs/MosaicControlNetTool/MosaicControlNetTool.cpp @@ -0,0 +1,239 @@ +#include "FileDialog.h" +#include "MosaicControlNetTool.h" + +#include + +namespace Qisis { + + /** + * MosaicControlNetTool constructor + * + * @param parent + */ + MosaicControlNetTool::MosaicControlNetTool (MosaicWidget *parent) : Qisis::MosaicTool(parent) { + connect(this,SIGNAL(activated(bool)),this,SLOT(updateTool())); + p_parent = parent; +//setParent(parent); //The way it SHOULD be done + + p_connectivity = new QAction(parent); + p_connectivity->setShortcut(Qt::Key_I); + p_connectivity->setText("Show Islands (I)"); + p_connectivity->setIcon(QPixmap(toolIconDir()+"/viewmag+.png")); + connect(p_connectivity,SIGNAL(activated()),this,SLOT(displayConnectivity())); + + createDialog(parent); + } + + + /** + * Creates the dialog used by this tool + * + * @param parent + */ + void MosaicControlNetTool::createDialog(QWidget *parent) { + + p_dialog = new QDialog(parent); + p_dialog->setWindowTitle("Control Net"); + + + // Put the buttons and text field in a gridlayout + //QGridLayout *gridLayout = new QGridLayout (); + /*gridLayout->addWidget(latLabel,0,0); + gridLayout->addWidget(p_latLineEdit,0,1); + gridLayout->addWidget(lonLabel,1,0); + gridLayout->addWidget(p_lonLineEdit, 1, 1);*/ + + // Create the action buttons + p_loadControlNetButton = new QPushButton (); + p_loadControlNetButton->setIcon(QPixmap((QString::fromStdString(Isis::Filename("$base/icons").Expanded().c_str()) + "/HILLBLU_molecola.png"))); + connect(p_loadControlNetButton, SIGNAL(clicked()), this, SLOT(loadControlNet())); + + p_displayControlNetButton = new QPushButton ("Display"); + p_displayControlNetButton->setCheckable(true); + connect(p_displayControlNetButton, SIGNAL(clicked()), this, SLOT(displayControlNet())); + + p_displayConnectivity = new QPushButton ("Connectivity"); + p_displayConnectivity->setCheckable(true); + connect(p_displayConnectivity, SIGNAL(clicked()), this, SLOT(displayConnectivity())); + + QPushButton* cancelButton = new QPushButton ("Done"); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(hideTool())); + + // Make |X| button close properly + connect(p_dialog, SIGNAL(finished(int)), this, SLOT(hideTool())); + + // Put the buttons in a horizontal orientation + QHBoxLayout *actionLayout = new QHBoxLayout(); + actionLayout->addWidget(p_loadControlNetButton); + actionLayout->addWidget(p_displayControlNetButton); + actionLayout->addWidget(p_displayConnectivity); + actionLayout->addWidget(cancelButton); + + QVBoxLayout *dialogLayout = new QVBoxLayout; + //dialogLayout->addLayout(gridLayout); + dialogLayout->addLayout(actionLayout); + p_dialog->setLayout(dialogLayout); + } + + + /** + * Adds the control net action to the given menu. + * + * @param menu + */ + void MosaicControlNetTool::addToMenu(QMenu *menu) { + menu->addAction(p_connectivity); + } + + + /** + * Adds the action to the toolpad. + * + * @param toolpad + * + * @return QAction* + */ + QAction *MosaicControlNetTool::toolPadAction(ToolPad *toolpad) { + p_action = new QAction(toolpad); + //p_action->setIcon(QPixmap(toolIconDir()+"/find.png")); + p_action->setIcon(QPixmap((QString::fromStdString(Isis::Filename("$base/icons").Expanded().c_str()) + "/HILLBLU_molecola.png"))); + p_action->setToolTip("Control Net (C)"); + p_action->setShortcut(Qt::Key_C); + QString text = + "Function: Utilize a Control Network \ +

    Shortcut: C

    "; + p_action->setWhatsThis(text); + return p_action; + } + + + /** + * Creates the widget to add to the tool bar. + * + * @param parent + * + * @return QWidget* + */ + QWidget *MosaicControlNetTool::createToolBarWidget (QStackedWidget *parent) { + QWidget *hbox = new QWidget(parent); + return hbox; + } + + + /** + * This slot opens and reopens this tool properly + */ + void MosaicControlNetTool::updateTool() { + if(isActive()) { + p_dialog->show(); + + p_displayControlNetButton->setCheckable(true); + if(p_parent->controlNet() != NULL) { + p_displayControlNetButton->setChecked(true); + displayControlNet(); + } + + p_displayConnectivity->setCheckable(true); + p_displayConnectivity->setChecked(false); + + p_action->setChecked(false); + } + } + + + /** + * This slot closes this tool properly + */ + void MosaicControlNetTool::hideTool() { + // Hide the control net + if( p_displayControlNetButton->isChecked() ) { + p_displayControlNetButton->setCheckable(false); + displayControlNet(); + } + + // Revert to individual colors + if( p_displayConnectivity->isChecked() ) { + p_displayConnectivity->setCheckable(false); + displayConnectivity(); + } + + p_dialog->hide(); + //p_action->setChecked(false); + } + + + /** + * Displays the connectivity of Control Points + * + */ + void MosaicControlNetTool::displayConnectivity(){ + p_parent->displayConnectivity(p_displayConnectivity->isChecked()); + } + + + /** + * Loads a control net from a file + * + */ + void MosaicControlNetTool::loadControlNet() { + + // Bring up a file dialog for user to select their cnet file. + QString netFile = FileDialog::getOpenFileName(p_parent, + "Select Control Net. File", + QDir::current().dirName(), + "*.net"); + + //-------------------------------------------------------------- + // if the file is not empty attempt to load in the control points + // for each mosaic item + //--------------------------------------------------------------- + if(!netFile.isEmpty()) { + + try { + Isis::Filename controlNetFile(netFile.toStdString()); + p_parent->setControlNet( controlNetFile ); + } + catch (Isis::iException &e) { + QString message = "Invalid control network. \n"; + std::string errors = e.Errors(); + message += errors.c_str(); + e.Clear (); + QMessageBox::information(p_parent,"Error",message); + QApplication::restoreOverrideCursor(); + p_loadControlNetButton->setChecked(false); + return; + } + + //-------------------------------------------------------------- + // for each mosaic item, display its control points + //-------------------------------------------------------------- + QList mosaicItems = p_parent->mosaicItems(); + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->displayControlPoints(p_parent->controlNet()); + } + + p_displayControlNetButton->setChecked(true); + + } else { + //--------------------------------------------------- + // this means the user canceled out of the dialog box + //--------------------------------------------------- + p_loadControlNetButton->setChecked(false); + } + + } + + + void MosaicControlNetTool::displayControlNet() { + if(p_parent->controlNet() != NULL) { + QList mosaicItems = p_parent->mosaicItems(); + + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setControlPointsVisible(p_displayControlNetButton->isChecked()); + } + } + } + + + +} diff --git a/isis/src/qisis/objs/MosaicControlNetTool/MosaicControlNetTool.h b/isis/src/qisis/objs/MosaicControlNetTool/MosaicControlNetTool.h new file mode 100644 index 0000000000000000000000000000000000000000..30ebf10df9899b6cde381927c6959a901cfb3317 --- /dev/null +++ b/isis/src/qisis/objs/MosaicControlNetTool/MosaicControlNetTool.h @@ -0,0 +1,55 @@ +#ifndef MosaicControlNetTool_h +#define MosaicControlNetTool_h + +#include "MosaicTool.h" +#include + +namespace Qisis { + /** + * @brief Handles Control Net displays + * + * @ingroup Visualization Tools + * + * @author Christopher Austin + * + * @internal + * @history 2010-06-24 Christopher Austin - Added |x| functionality and fixed + * control net loading + */ + class MosaicControlNetTool : public Qisis::MosaicTool { + Q_OBJECT + + public: + MosaicControlNetTool (MosaicWidget *parent); + void addToMenu(QMenu *menu); + + public slots: + + protected: + QAction *toolPadAction(ToolPad *toolpad); + //! Returns the name of the menu. + QString menuName() const { return "&View"; }; + QWidget *createToolBarWidget(QStackedWidget *parent); + + protected slots: + void updateTool(); + void hideTool(); + void loadControlNet(); + void displayControlNet(); + void displayConnectivity(); + + private: + void createDialog(QWidget *parent); + QDialog *p_dialog; + MosaicWidget *p_parent; + QAction *p_action; + + QPushButton *p_loadControlNetButton; + QPushButton *p_displayControlNetButton; + QPushButton *p_displayConnectivity; + QAction *p_connectivity; + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/MosaicFindTool/Makefile b/isis/src/qisis/objs/MosaicFindTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MosaicFindTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MosaicFindTool/MosaicFindTool.cpp b/isis/src/qisis/objs/MosaicFindTool/MosaicFindTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c2c70e85447b48114f01e71f33c7d0b01e3b1a89 --- /dev/null +++ b/isis/src/qisis/objs/MosaicFindTool/MosaicFindTool.cpp @@ -0,0 +1,212 @@ +#include "MosaicFindTool.h" + +#include + +namespace Qisis { + /** + * MosaicFindTool constructor + * + * + * @param parent + */ + MosaicFindTool::MosaicFindTool (QWidget *parent) : Qisis::MosaicTool(parent) { + connect(this,SIGNAL(activated(bool)),this,SLOT(updateTool())); + p_parent = (MosaicWidget *) parent; + p_findSpot = NULL; + createDialog(parent); + } + + + /** + * Creates the dialog used by this tool + * + * @param parent + */ + void MosaicFindTool::createDialog(QWidget *parent) { + + p_dialog = new QDialog(parent); + p_dialog->setWindowTitle("Find Latitude/Longitude Coordinate"); + + p_latLineEdit = new QLineEdit(); + p_latLineEdit->setText("0"); + p_latLineEdit->setValidator(new QDoubleValidator(-90.0,90.0,99,parent)); + p_lonLineEdit = new QLineEdit(); + p_lonLineEdit->setText("0"); + p_lonLineEdit->setValidator(new QDoubleValidator(parent)); + QLabel *latLabel = new QLabel("Latitude"); + QLabel *lonLabel = new QLabel("Longitude"); + + // Put the buttons and text field in a gridlayout + QGridLayout *gridLayout = new QGridLayout (); + gridLayout->addWidget(latLabel,0,0); + gridLayout->addWidget(p_latLineEdit,0,1); + gridLayout->addWidget(lonLabel,1,0); + gridLayout->addWidget(p_lonLineEdit, 1, 1); + + // Create the action buttons + QPushButton *okButton = new QPushButton ("Ok"); + connect(okButton, SIGNAL(clicked()), this, SLOT(getUserGroundPoint())); + + QPushButton *clearButton = new QPushButton("Clear Dot"); + connect(clearButton, SIGNAL(clicked()), this, SLOT(clearPoint())); + + QPushButton* cancelButton = new QPushButton ("Cancel"); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(clearPoint())); + connect(cancelButton, SIGNAL(clicked()), p_dialog, SLOT(hide())); + + // Put the buttons in a horizontal orientation + QHBoxLayout *actionLayout = new QHBoxLayout(); + actionLayout->addWidget(okButton); + actionLayout->addWidget(clearButton); + actionLayout->addWidget(cancelButton); + + QVBoxLayout *dialogLayout = new QVBoxLayout; + dialogLayout->addLayout(gridLayout); + dialogLayout->addLayout(actionLayout); + p_dialog->setLayout(dialogLayout); + + } + + + /** + * + * + */ + void MosaicFindTool::getUserGroundPoint() { + + //Validate latitude value + QString latitude = p_latLineEdit->text(); + int cursorPos = 0; + QValidator::State validLat = + p_latLineEdit->validator()->validate(latitude,cursorPos); + if (validLat != QValidator::Acceptable) { + QMessageBox::warning(p_dialog, "Error", + "Latitude value must be in the range -90 to 90", + QMessageBox::Ok,QMessageBox::NoButton,QMessageBox::NoButton); + return; + } + + //Validate longitude value + QString longitude = p_lonLineEdit->text(); + QValidator::State validLon = + p_lonLineEdit->validator()->validate(longitude,cursorPos); + if (validLon != QValidator::Acceptable) { + QMessageBox::warning(p_dialog, "Error", + "Longitude value must be a double", + QMessageBox::Ok,QMessageBox::NoButton,QMessageBox::NoButton); + return; + } + + double lat = Isis::iString(latitude.toStdString()).ToDouble(); + double lon = Isis::iString(longitude.toStdString()).ToDouble(); + + Isis::Projection *projection = p_parent->projection(); + + if(projection->Has180Domain()){ + lon = projection->To180Domain(lon); + if(projection->IsPositiveWest()) lon = projection->ToPositiveWest(lon, 180); + }else if(projection->IsPositiveWest()){ + lon = projection->ToPositiveWest(lon, 360); + } + // convert lat. if necessary + if(projection->IsPlanetographic()) { + lat = projection->ToPlanetographic(lat, projection->EquatorialRadius(), projection->PolarRadius()); + } + + if (projection->SetGround(lat, lon)) { + double x = projection->XCoord(); + double y = -1 *(projection->YCoord()); + + //get the graphics scene + QGraphicsScene *graphicsScene = p_parent->scene(); + + if(graphicsScene->sceneRect().contains(QPointF(x,y))){ + QTransform m = graphicsScene->views().last()->transform(); + double size = (8.0 / m.m11()); + //double size = (p_parent->screenResolution()) * 2; + QRectF rect = QRectF(x-(size/2),y-(size/2), size, size); + if(p_findSpot != NULL) { + clearPoint(); + } + p_findSpot = graphicsScene->addEllipse(rect, QPen(Qt::red), QBrush(Qt::red, Qt::SolidPattern)); + graphicsScene->views().last()->centerOn(x,y); + } else { + QString message = "Lat/Lon not within this view."; + QMessageBox::information(p_parent, "Point Not Found", message, QMessageBox::Ok); + } + } + } + + + /** + * Adds the action to the toolpad. + * + * + * @param toolpad + * + * @return QAction* + */ + QAction *MosaicFindTool::toolPadAction(ToolPad *toolpad) { + p_action = new QAction(toolpad); + p_action->setIcon(QPixmap(toolIconDir()+"/find.png")); + p_action->setToolTip("Find (F)"); + p_action->setShortcut(Qt::Key_F); + QString text = + "Function: Find the specified lat/lon. \ +

    Shortcut: F

    "; + p_action->setWhatsThis(text); + return p_action; + } + + + /** + * Adds the pan action to the given menu. + * + * + * @param menu + */ + void MosaicFindTool::addToMenu(QMenu *menu) { + + } + + + /** + * Creates the widget to add to the tool bar. + * + * + * @param parent + * + * @return QWidget* + */ + QWidget *MosaicFindTool::createToolBarWidget (QStackedWidget *parent) { + QWidget *hbox = new QWidget(parent); + return hbox; + } + + + /** + * + * + */ + void MosaicFindTool::clearPoint() { + if(p_findSpot != NULL) { + p_parent->scene()->removeItem(p_findSpot); + p_findSpot = NULL; + } + + } + + + /** + * This method sets the QGraphicsView to allow the user to select + * mosaic items by dragging a rubber band. + * + */ + void MosaicFindTool::updateTool() { + if(isActive()) { + p_dialog->show(); + p_action->setChecked(false); + } + } + +} diff --git a/isis/src/qisis/objs/MosaicFindTool/MosaicFindTool.h b/isis/src/qisis/objs/MosaicFindTool/MosaicFindTool.h new file mode 100644 index 0000000000000000000000000000000000000000..9451e52c73c535e11b674404b2ad38964daa8368 --- /dev/null +++ b/isis/src/qisis/objs/MosaicFindTool/MosaicFindTool.h @@ -0,0 +1,59 @@ +#ifndef MosaicFindTool_h +#define MosaicFindTool_h + +#include "MosaicTool.h" +#include + +namespace Qisis { + /** + * @brief Handles selection operations for Isis qt apps + * + * @ingroup Visualization Tools + * + * @author Stacy Alley + * + * @internal + * @history + */ + class MosaicFindTool : public Qisis::MosaicTool { + Q_OBJECT + + public: + MosaicFindTool (QWidget *parent); + void addToMenu(QMenu *menu); + + protected slots: + void updateTool(); + + protected: + QAction *toolPadAction(ToolPad *toolpad); + //! Returns the name of the menu. + QString menuName() const { return "&View"; }; + QWidget *createToolBarWidget(QStackedWidget *parent); + + public slots: + void getUserGroundPoint(); + void clearPoint(); + + private: + void createDialog(QWidget *parent); + QDialog *p_dialog; + QAction *p_findPoint; + QToolButton *p_findPtButton; + QLineEdit *p_status; + bool p_released; + bool p_pressed; + QPoint p_point; + QPen p_pen; + bool p_paint; + QLineEdit *p_lonLineEdit; //!< Input for longitude + QLineEdit *p_latLineEdit; //!< Input for latitude + MosaicWidget *p_parent; + QGraphicsEllipseItem *p_findSpot; + QAction *p_action; + + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/MosaicItem/Makefile b/isis/src/qisis/objs/MosaicItem/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MosaicItem/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MosaicItem/MosaicItem.cpp b/isis/src/qisis/objs/MosaicItem/MosaicItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b6c4cbb36d638a717ded597bce720138ff448be4 --- /dev/null +++ b/isis/src/qisis/objs/MosaicItem/MosaicItem.cpp @@ -0,0 +1,1787 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "MosaicItem.h" +#include "ImagePolygon.h" +#include "SerialNumber.h" +#include "Table.h" +#include "iString.h" +#include "Histogram.h" +#include "Statistics.h" +#include "PolygonTools.h" +#include "FileDialog.h" + + +namespace Qisis { + /** + * MosaicItem constructor + * + * + * @param cubeFilename + * @param parent + */ + MosaicItem::MosaicItem(const QString &cubeFilename, MosaicWidget *parent, Isis::PvlGroup *group) + : QGraphicsPolygonItem() { + + if(parent->projection() == 0) { + std::string msg = "Parent does not have projection in MosaicWidget"; + throw Isis::iException::Message(Isis::iException::User, msg, _FILEINFO_); + } + + p_filename = cubeFilename.trimmed().toStdString(); + //p_levelOfDetail = 0.025; + p_imageTransparency = 180; + p_pixRes = 0; + p_emissionAngle = 0; + p_incidenceAngle = 0; + p_mp = NULL; + p_secondItem = NULL; + p_groundMap = NULL; + p_label = new QGraphicsSimpleTextItem(QString::fromStdString(p_filename.Name())); + p_label->setFlag(QGraphicsItem::ItemIsMovable); + p_labelFont = QFont("Helvetica", 10); + p_label->setFont(p_labelFont); + p_levelOfDetail = 0; + p_updateFont = false; + p_enablePaint = true; + p_crossesBoundry = false; + p_controlPointsVisible = false; + p_lastExposedRect = QRectF(QPoint(0, 0), QPoint(0, 0)); + + p_parent = parent; + p_xmin = DBL_MAX; + p_xmax = -DBL_MAX; + p_ymin = DBL_MAX; + p_ymax = -DBL_MAX; + p_color = randomColor(); + + p_treeItem = new QTreeWidgetItem(); + p_treeItem->setText(0, p_filename.Basename().c_str()); + p_treeItem->setBackground(0, QBrush(p_color)); + p_treeItem->setCheckState(1, Qt::Checked); + p_treeItem->setCheckState(2, Qt::Checked); + p_treeItem->setCheckState(3, Qt::Unchecked); + p_treeItem->setCheckState(4, Qt::Unchecked); + p_treeItem->setCheckState(5, Qt::Unchecked); + + createFootprint(); + + //If this item was constructed with a PvlGroup + //call setUpItem so set all the item's attributes + //to the last state they were in. + if(group != 0) { + setUpItem(group); + } + + setAcceptHoverEvents(true); + } + + + /** + * 2nd MosaicItem constructor. + * Private constructor only called from within this class if a + * cube has >1 polygons. i.e. The image crosses the longitude + * boundry. + * + * + * @param parent + */ + MosaicItem::MosaicItem(MosaicItem *parent) : QGraphicsPolygonItem() { + setParentItem(parent); + //This is what was cause the text label to not be moveable when + // there were 2 polygon items!!! + //parent->setHandlesChildEvents(true); + + p_proj = parent->getProj(); + if(p_groundMap != NULL) p_groundMap = parent->getGroundMap(); + + p_filename = parent->p_filename; + //p_levelOfDetail = 0.025; + p_imageTransparency = 180; + p_pixRes = parent->p_pixRes; + p_incidenceAngle = parent->p_incidenceAngle; + p_emissionAngle = parent->p_emissionAngle; + p_mp = NULL; + p_secondItem = NULL; + p_levelOfDetail = 0; + p_updateFont = false; + p_enablePaint = true; + p_label = parent->p_label; + //p_label = new QGraphicsSimpleTextItem(QString::fromStdString(p_filename.Name())); + //p_label->setFlag(QGraphicsItem::ItemIsMovable); + //p_labelFont = QFont("Helvetica", 10); + // p_label->setFont(p_labelFont); + + p_parent = parent->p_parent; + p_xmin = parent->p_xmin; + p_xmax = parent->p_xmax; + p_ymin = parent->p_ymin; + p_ymax = parent->p_ymax; + p_color = parent->p_color; + + p_treeItem = NULL; + } + + + /** + * Mosaic Item destructor + * + */ + MosaicItem::~MosaicItem() { + if(p_mp == NULL) { + delete p_mp; + } + if(p_treeItem == NULL) { + delete p_treeItem; + } + if(p_secondItem == NULL) { + delete p_secondItem; + } + if(p_camera == NULL) { + delete p_camera; + } + if(p_proj == NULL) { + delete p_proj; + } + } + + + /** + * This method is called from the constructor when there is a + * group passed as one of the header args. + * When this method is called it means a saved project file has + * been read in and this sets up the item back to the way the + * user had set it up before the save project command. + * + * @param grp + */ + void MosaicItem::setUpItem(Isis::PvlGroup *grp) { + + //Set the item's color + QString colorStr = grp->FindKeyword("Color")[0].ToQt(); + QColor color = QColor(colorStr); + int alpha = grp->FindKeyword("Alpha")[0]; + color.setAlpha(alpha); + this->setColor(color); + + //Set item state + Isis::iString state = grp->FindKeyword("Item")[0]; + bool checked = state.Equal("Yes"); + this->setItemVisible(checked ? true : false); + + //Set footprint state + state = grp->FindKeyword("Footprint")[0]; + checked = state.Equal("Yes"); + this->setFootprintVisible(checked ? true : false); + + //Set outline state + state = grp->FindKeyword("Outline")[0]; + checked = state.Equal("Yes"); + this->setOutlineVisible(checked ? true : false); + + //Set image state + state = grp->FindKeyword("Image")[0]; + checked = state.Equal("Yes"); + this->setImageVisible(checked ? true : false); + + //Set label state + state = grp->FindKeyword("Label")[0]; + checked = state.Equal("Yes"); + this->setLabelVisible(checked ? true : false); + + //Look for the control points + if(grp->HasKeyword("ControlPoints")) { + p_controlPoints.clear(); + Isis::PvlKeyword points = grp->FindKeyword("ControlPoints"); + if(points[0].compare("Null") != 0) { + for(int i = 0; i < points.Size(); i++) { + Isis::iString point = points[i]; + double x = point.Token(":").ToDouble(); + double y = point.ToDouble(); + p_controlPoints.push_back(QPointF(x, y)); + //p_sceneToPointMap.insert(QString::fromStdString(point.Id()), mapToScene(x,y)); + } + } + + //Set control points visible state + if(grp->HasKeyword("ControlPointsVisible")) { + state = grp->FindKeyword("ControlPointsVisible")[0]; + checked = state.Equal("Yes"); + this->setControlPointsVisible(checked); + } + } + + } + + /** + * Re-paints the item + * + * @param painter + * @param option + * @param widget + */ + void MosaicItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { + double itemLevelOfDetail = option->levelOfDetail * p_pixRes; + QColor tempColor = p_color; + + // ------------------------------------------------------------------- + // If the level of detail is low, we do not want to allow the polygon + // colors to have any transparency because it causes the application + // to slow down significantly + // ------------------------------------------------------------------- + if(itemLevelOfDetail < p_levelOfDetail) { + tempColor.setAlpha(255); + } + + // ------------------------------------------------------------------ + // If this item is a child item, then we need to check it's parent's + // check state to see if we need to draw the OUTLINE. + // ------------------------------------------------------------------ + if(p_treeItem == NULL) { + if(((MosaicItem *)parentItem())->p_treeItem->checkState(3) == Qt::Checked) { + paintOutline(painter); + } + } + else if(p_treeItem->checkState(3) == Qt::Checked) { + paintOutline(painter); + } + + // ------------------------------------------------------------------ + // If this item is a child item, then we need th check it's parent's + // check state for the FOOTPRINT. + // ------------------------------------------------------------------ + if(p_treeItem == NULL) { + if(((MosaicItem *)parentItem())->p_treeItem->checkState(2) == Qt::Checked) { + paintFootprint(painter); + } + } + else if(p_treeItem->checkState(2) == Qt::Checked) { + paintFootprint(painter); + } + + // ------------------------------------------------------------------ + // If this item is a child item, then we need th check it's parent's + // check state for the IMAGE. + // ------------------------------------------------------------------ + if(scene() != 0 && p_treeItem == NULL) { + if(((MosaicItem *)parentItem())->p_treeItem->checkState(4) == Qt::Checked) { + drawImage(painter, option); + } + } + else if(scene() != 0 && p_treeItem->checkState(4) == Qt::Checked) { + drawImage(painter, option); + } + + // ---------------------------------------------------------------------- + // If this item is a PARENT item, then we need th check it's check state + // for column 5 to know if we need to add the LABEL item. + // ---------------------------------------------------------------------- + if(p_treeItem != NULL) { + if(p_treeItem->checkState(5) == Qt::Checked) { + // ---------------------------------------------- + // If this item has not child, then you know to + // call paintLabel immediately. + // --------------------------------------------- + if(p_secondItem == NULL) { + // ---------------------------------------------------------- + // The following if statement prevent you from getting into + // an endless paint cycle. + // ----------------------------------------------------------- + if(!scene()->items().contains(p_label) || !p_label->isVisible() || + (p_lastLevelOfDetail != option->levelOfDetail)) { + paintLabel(option); + } + } + // -------------------------------------------------- + // if this item does have a child and it's polygon + // is smaller than this one, then call this paintLabel + // --------------------------------------------------- + if(p_secondItem != NULL && p_secondItem->boundingRect().width() < this->boundingRect().width()) { + // ---------------------------------------------------------- + // The following if statement prevent you from getting into + // an endless paint cycle. + // ----------------------------------------------------------- + if(!scene()->items().contains(p_label) || !p_label->isVisible() || + (p_lastLevelOfDetail != option->levelOfDetail)) { + paintLabel(option); + } + } + + } + else { + // User does not want the label item on the scene. + if(scene()->items().contains(p_label)) { + p_label->setVisible(false); + } + } + } + + // ---------------------------------------------------------------------- + // If this item is a CHILD item, then we need th check it's parent's check + // state for column 5 to know if we need to add the LABEL item. + // ---------------------------------------------------------------------- + if(p_treeItem == NULL) { + if(((MosaicItem *)parentItem())->p_treeItem->checkState(5) == Qt::Checked) { + // -------------------------------------------------- + // If the parent item is smaller than this item then + // we know we can the child item to paint the label. + // --------------------------------------------------- + if(parentItem()->boundingRect().width() < this->boundingRect().width()) { + // ---------------------------------------------------------- + // The following if statement prevent you from getting into + // an endless paint cycle. + // ----------------------------------------------------------- + if(!scene()->items().contains(p_label) || !p_label->isVisible() || + (p_lastLevelOfDetail != option->levelOfDetail)) { + paintLabel(option); + } + } + } + else { + // User does not want the label item on the scene. + if(scene()->items().contains(p_label)) { + p_label->setVisible(false); + } + } + } + + // ---------------------------------------------------- + // Display the CONTROL POINTS if they've been read in. + // ---------------------------------------------------- + if(p_controlPoints.size() > 0 && p_controlPointsVisible) { + paintControlPoints(painter, option); + } + + // ---------------------------------------------------------------------- + // if the item is selected then we draw the dotted line around it + // to signify that it's selected. see qt_graphicsItem_highlightSelected() + // ---------------------------------------------------------------------- + if(option->state & QStyle::State_Selected) + qt_graphicsItem_highlightSelected(this, painter, option); + + p_lastLevelOfDetail = option->levelOfDetail; + } + + + /** + * Called from the paint() function to paint the outline. + * + * + * @param painter + */ + void MosaicItem::paintOutline(QPainter *painter) { + QColor tempColor = p_color; + + tempColor.setAlpha(255); + painter->setPen(tempColor); + painter->setBrush(Qt::NoBrush); + painter->drawPolygon(polygon(), fillRule()); + } + + + /** + * Called from the paint() function to paint the footprint. + * + * + * @param painter + */ + void MosaicItem::paintFootprint(QPainter *painter) { + QColor tempColor = p_color; + + tempColor.setAlpha(p_imageTransparency); + painter->setPen(tempColor); + painter->setBrush(tempColor); + painter->drawPolygon(polygon(), fillRule()); + } + + /** + * Called from the paint() function to paint the control points. + * + * + * @param painter + */ + void MosaicItem::paintControlPoints(QPainter *painter, + const QStyleOptionGraphicsItem *option) { + QColor tempColor = p_color; + tempColor.setAlpha(255); + + for(int i = 0; i < p_controlPoints.size(); i++) { + if(p_controlPoints[i] == p_selectedPoint) { + //We only need this threshold if we are going to display all control point measures. + //if(p_controlPoints[i].x() <= p_selectedPoint.x()+.1 && p_controlPoints[i].x() >= p_selectedPoint.x()-.1 + // && p_controlPoints[i].y() <= p_selectedPoint.y()+.1 && p_controlPoints[i].y() >= p_selectedPoint.y()-.1) { + painter->setPen(Qt::red); + } + else { + painter->setPen(Qt::green); + } + + //Now draw the points + double lod = option->levelOfDetailFromTransform(painter->worldTransform()); + painter->drawLine(QPointF(p_controlPoints[i].x() - 5 / lod, p_controlPoints[i].y()), + QPointF(p_controlPoints[i].x() + 5 / lod, p_controlPoints[i].y())); + painter->drawLine(QPointF(p_controlPoints[i].x(), p_controlPoints[i].y() - 5 / lod), + QPointF(p_controlPoints[i].x(), p_controlPoints[i].y() + 5 / lod)); + } + + setSelectedPoint(QPointF(0, 0)); + } + + /** + * Called from the paint() function to add the label. + * + * + * @param levelOfDetail + */ + void MosaicItem::paintLabel(const QStyleOptionGraphicsItem *option) { + // ------------------------------------------------------ + // Position the label in the center of it's parent item. + // If there are two polygons, we need to union them to get + // the center of the total size. + // ------------------------------------------------------ + QPolygonF poly2 = mapToScene(this->polygon()); + if(p_secondItem != NULL) { + poly2 = mapToScene(p_secondItem->polygon().united(this->polygon())); + } + QPolygonF poly3 = mapToScene(option->exposedRect.toRect()); + QPolygon poly4 = poly2.toPolygon().intersected(poly3.toPolygon()); + //std::cout << "Painting label and set position to the center of poly 4" << std::endl; + p_label->setPos(QPointF(poly4.boundingRect().center())); + + // ---------------------------------------------------- + // This part ensures that the label font size is always + // reasonable now matter what the current zoom is. + // ---------------------------------------------------- + QTransform m = scene()->views().last()->transform(); + p_label->resetTransform(); + p_label->scale(1.0 / m.m11(), 1.0 / m.m22()); + + // ---------------------------------------------------------------- + // if this item has children, then we need to use the sum of the + // height vs. the sum of double the width. + // ---------------------------------------------------------------- + QRectF totalRect; + if(p_crossesBoundry && p_secondItem != NULL) { + totalRect = p_secondItem->boundingRect().united(polygon().boundingRect()); + } + else { + totalRect = polygon().boundingRect(); + } + + // -------------------------------------------------------------------- + // now we have the totalRectangle bounding the item even if it crosses + // the lat/lon boundry. + // -------------------------------------------------------------------- + if(totalRect.height() > 1.5 * (totalRect.width())) { + p_label->rotate(90); + } + + p_label->setZValue(zValue() + 1); + p_label->setVisible(true); + //TODO: check into why This causes problems + //p_label->setParentItem(this); + + + // ------------------------------------------------------- + // if this is the first time the label has been requested, + // we need to add it to the scene + // ------------------------------------------------------- + if(!scene()->items().contains(p_label)) { + scene()->addItem(p_label); + p_label->installSceneEventFilter(this); + } + } + + /** + * + * + */ + /*void MosaicItem::screenResolution(){ + // Using these two points we can calculated the scene's width. + QPointF point1 = getGraphicsView()->mapToScene(0,0); + QPointF point2 = getGraphicsView()->mapToScene((int) getGraphicsView()->width(),0); + double newWidth = point2.x() - point1.x(); + // The scene width divided by the viewport's width gives us the screen res. + p_screenResolution = newWidth/getGraphicsView()->viewport()->width(); + }*/ + + + /** + * This lets the item know which point has been selected. We + * need to know this for the paint function to know which point + * to color red instead of green. + * + * + * @param p + */ + void MosaicItem::setSelectedPoint(QPointF p) { + p_selectedPoint = p; + } + + + /** + * Allows the programmer to set the level of detail at which the + * paint function will not allow transparent footprint colors. + * + * + * @param detail + */ + void MosaicItem::setLevelOfDetail(double detail) { + p_levelOfDetail = detail; + if(children().size() > 0)((MosaicItem *)children()[0])->p_levelOfDetail = detail; + if(parentItem() != 0)((MosaicItem *)parentItem())->p_levelOfDetail = detail; + } + + + /** + * This method gets the footprint polygon of the cube + * + */ + void MosaicItem::createFootprint() { + Isis::Cube cube; + QString qstring; + + try { + cube.Open(p_filename.Expanded()); + //cube.Open(p_filename.Name()); + } + catch(Isis::iException &e) { + std::string msg = e.Errors(); + QMessageBox::information(p_parent, "Error", QString::fromStdString(msg), QMessageBox::Ok); + return; + } + + // The Archive group should never be searched for anything ever! + //Get the product ID and set the label text to that. + //Isis::PvlKeyword keyword = cube.Label()->FindObject("IsisCube").FindGroup("Archive").FindKeyword("ProductId"); + //p_label->setPlainText(keyword[0].ToQt()); + //p_label->setText(keyword[0].ToQt()); + + //Get the camera stats table from the cube. + //This is how we know the cube's resolution. + //This is the reason we need to run camstats + //with the attach option set to yes. + try { + Isis::Table table("CameraStatistics", p_filename.Expanded()); + //Isis::Table table("CameraStatistics", p_filename.Name()); + for(int i = 0; i < table.Records(); i++) { + for(int j = 0; j < table[i].Fields(); j++) { + if(table[i][j].IsText()) { + qstring = QString::fromStdString((std::string)table[i][j]); + qstring.truncate(10); + } + + // Get the average resolution for this mosaic item. + if(table[i][j].IsText() && qstring.compare("Resolution") == 0) { + if(j + 3 < table[i].Fields()) { + if(table[i][j+3].IsInteger()) { + } + else if(table[i][j+3].IsDouble()) { + p_pixRes = (double)table[i][j+3]; + } + else if(table[i][j+3].IsText()) { + } + } + } + + // Get the average emission angle for this mosaic item. + if(table[i][j].IsText() && qstring.compare("EmissionAn") == 0) { + if(j + 3 < table[i].Fields()) { + if(table[i][j+3].IsInteger()) { + } + else if(table[i][j+3].IsDouble()) { + p_emissionAngle = (double)table[i][j+3]; + } + else if(table[i][j+3].IsText()) { + } + } + } + + // Get the average incidence angle for this mosaic item. + if(table[i][j].IsText() && qstring.compare("IncidenceA") == 0) { + if(j + 3 < table[i].Fields()) { + if(table[i][j+3].IsInteger()) { + } + else if(table[i][j+3].IsDouble()) { + p_incidenceAngle = (double)table[i][j+3]; + } + else if(table[i][j+3].IsText()) { + } + } + } + + } // end for table[i].Fields + } // end for table.Records + + } + catch(Isis::iException &e) { + std::string msg = "Could not find the CameraStatistics Table. Please run camerastats with the 'attach' option"; + QMessageBox::information(p_parent, "Error", QString::fromStdString(msg), QMessageBox::Ok); + return; + } + + //Construct a polygon object and set the name to the cube's serial number. + + Isis::ImagePolygon *poly; + try { + poly = new Isis::ImagePolygon(); + cube.Read(*poly); + + } + catch(Isis::iException &e) { + cube.Close(); + std::string msg = "footprintinit must be run before reading the polygon."; + QMessageBox::information(p_parent, "Error", QString::fromStdString(msg), QMessageBox::Ok); + return; + } + + cube.Close(); + + //Get the footprint polygon(s) of this cube. All polys will + //be in 0-360 longitude domain because footprintinit make 'em that way. + //So if the user wants a -180-180 longitude domain, then we have to have + //the polygon ready to for that domain too. + p_mp = (geos::geom::MultiPolygon *)poly->Polys()->clone(); + delete poly; + + reproject(); + } + + + /** + * Called anytime the user reprojects the cube. (Selects a new + * map file.) And everytime a mosaic item is created. + */ + void MosaicItem::reproject() { + double xmin = DBL_MAX; + double xmax = -DBL_MAX; + double ymin = DBL_MAX; + double ymax = -DBL_MAX; + + geos::geom::MultiPolygon *mp; + p_proj = p_parent->projection(); + + if(p_proj->Has180Domain()) { + p_180mp = Isis::PolygonTools::To180(p_mp); + mp = p_180mp; + } + else { + mp = p_mp; + } + + //---------------------------------------------------------- + // We need to loop thru the num. geom. because some of the + // cubes will have more than one geom. if it crosses lat/lon + // boundries. + //---------------------------------------------------------- + for(unsigned int i = 0; i < mp->getNumGeometries(); i++) { + const geos::geom::Geometry *geom = mp->getGeometryN(i); + geos::geom::CoordinateSequence *pts; + + pts = geom->getCoordinates(); + double lat, lon; + QVector polyPoints; + + //-------------------------------------------------------------- + // We need to convert the footprint polygons from lat/lon to x/y + // in order to display them in the QGraphicsScene + //-------------------------------------------------------------- + for(unsigned int j = 0; j < pts->getSize(); j++) { + lat = pts->getY(j); + lon = pts->getX(j); + if(p_proj->SetUniversalGround(lat, lon)) { + double x = p_proj->XCoord(); + double y = -1 * (p_proj->YCoord()); + + //----------------------------------------------- + // determine x/y min/max for the polygons(s) + // so we know how big to make the QGraphicsScene + //----------------------------------------------- + if(x < xmin) xmin = x; + if(y < ymin) ymin = y; + if(x > xmax) xmax = x; + if(y > ymax) ymax = y; + + polyPoints.push_back(QPointF(x, y)); + } + } + + p_xmin = xmin; + p_xmax = xmax; + p_ymin = ymin; + p_ymax = ymax; + + if(i == 0) { + p_footprintPoly = QPolygonF(polyPoints); + setPolygon(p_footprintPoly); + setFlag(QGraphicsItem::ItemIsSelectable); + setBrush(p_color); + setPen(p_color); + } + else { + //---------------------------------------------------- + // This means we have a second polygon, so we need to + // create a new MosaicItem for it. (i.e. this cube + // crosses a lat/lon boundry.) + //--------------------------------------------------- + if(p_secondItem == NULL) { + p_secondItem = new MosaicItem(this); + } + p_footprintPoly = QPolygonF(polyPoints); + p_secondItem->setPolygon(p_footprintPoly); + p_secondItem->setFlag(QGraphicsItem::ItemIsSelectable); + p_secondItem->setBrush(p_color); + p_secondItem->setPen(p_color); + p_crossesBoundry = true; + } + delete pts; + } + if(p_controlPoints.size() > 0 && p_controlPointsVisible) { + displayControlPoints(p_controlNet); + } + } + + + /** + * Translates the screen coordinates(x,y) to camera coordinates. + * + * + * @param x + * @param y + * + * @return QPointF + */ + QPointF MosaicItem::screenToCam(int x, int y) { + QPointF camPoints; + QPointF scenePoint = scene()->views().last()->mapToScene(QPoint(x, y)); + + if(!p_proj->SetWorld(scenePoint.x(), -scenePoint.y())) { + camPoints.setX(-1); + camPoints.setY(-1); + return camPoints; + } + + double lat = p_proj->UniversalLatitude(); + double lon = p_proj->UniversalLongitude(); + if(!p_groundMap->SetUniversalGround(lat, lon)) { + camPoints.setX(-1); + camPoints.setY(-1); + return camPoints; + } + + camPoints.setX(p_groundMap->Sample() + 0.5); + camPoints.setY(p_groundMap->Line() + 0.5); + + return camPoints; + } + + + /** + * Translates the screen coordinates(x,y) to line/sample. + * + * + * @param x + * @param y + * + * @return QPointF + */ + QPointF MosaicItem::screenToCam(QPointF p) { + QPointF camPoints; + + if(!p_proj->SetWorld(p.x(), -p.y())) { + camPoints.setX(-1); + camPoints.setY(-1); + return camPoints; + } + + double lat = p_proj->UniversalLatitude(); + double lon = p_proj->UniversalLongitude(); + if(!p_groundMap->SetUniversalGround(lat, lon)) { + camPoints.setX(-1); + camPoints.setY(-1); + return camPoints; + } + + camPoints.setX(p_groundMap->Sample()); + camPoints.setY(p_groundMap->Line()); + + return camPoints; + } + + + /** + * Translates screen points to lat/lon for reporting in the + * lower right corner of the qmos window. + * + * + * @param point + * + * @return QPointF + */ + QPointF MosaicItem::screenToGround(QPointF point) { + QPointF groundPoints; + if(!p_proj->SetWorld(point.x(), -point.y())) { + groundPoints.setX(-1); + groundPoints.setY(-1); + return groundPoints; + } + + double lat = p_proj->Latitude(); + double lon = p_proj->Longitude(); + groundPoints.setX(lat); + groundPoints.setY(lon); + + return groundPoints; + } + + + /** + * Returns true if the distance between two points is less than + * .5, otherwise returns false. + * + * + * @param trueMidX + * @param trueMidY + * @param testMidX + * @param testMidY + * + * @return bool + */ + bool MosaicItem::midTest(double trueMidX, double trueMidY, + double testMidX, double testMidY) { + //since sqrt is expensive, we will just compare dist to .5^2. + //double dist = sqrt(pow(testMidX - trueMidX,2) + pow(testMidY - trueMidY,2)); + double dist = (testMidX - trueMidX) * (testMidX - trueMidX) + + (testMidY - trueMidY) * (testMidY - trueMidY); + if(dist < .5 * .5) { + return true; + } + else { + return false; + } + } + + + /** + * Returns the pixel value at the given sample/line. + * + * + * @param sample + * @param line + * + * @return int + */ + double MosaicItem::getPixelValue(int sample, int line) { + Isis::Brick gryBrick(1, 1, 1, p_cube.PixelType()); + gryBrick.SetBasePosition((int)(sample + 0.5), (int)(line + 0.5), 1); + p_cube.Read(gryBrick); + + double pixelValue = gryBrick[0]; + if(pixelValue == Isis::Null) { + return Isis::Null; + } + if(pixelValue < 0) pixelValue = 0; + if(pixelValue > 255) pixelValue = 255; + return pixelValue; + } + + + /** + * This method reads in and draws the image associated with this + * item. + * @param painter + */ + void MosaicItem::drawImage(QPainter *painter, const QStyleOptionGraphicsItem *option) { + //std::cout << "\nTop drawImage for " << filename().Name() << std::endl; + //if paint is not enabled, then just draw the last image and return + //the paint is only disable when in zoom mode and the mouse button is down. + if(!p_enablePaint) { + painter->drawImage(this->polygon().boundingRect(), p_lastImage); + return; + } + + //If the exposed rect is the same as the last exposed rect, then don't draw again. + //just draw the last image and return + /*if(option->exposedRect == p_lastExposedRect) { + std::cout << "This is the same exposed rect, just drawing the last image and returning." << std::endl; + painter->drawImage(this->polygon().boundingRect(), p_lastImage); + return; + } + p_lastExposedRect = option->exposedRect;*/ + + try { + p_cube.Open(p_filename.Expanded()); + //p_cube.Open(p_filename.Name()); + } + catch(Isis::iException &e) { + std::string msg = "Can not open this cube!"; + QMessageBox::information(p_parent, "Error", QString::fromStdString(msg), QMessageBox::Ok); + return; + } + + if(p_groundMap == NULL) { + try { + Isis::Pvl pvl(p_filename.Expanded()); + //Isis::Pvl pvl(p_filename.Name()); + p_groundMap = new Isis::UniversalGroundMap(pvl); + } + catch(Isis::iException &e) { + std::string msg = "Could not get a ground map for this cube."; + QMessageBox::information(p_parent, "Error", QString::fromStdString(msg), QMessageBox::Ok); + return; + } + } + + getStretch(); + + try { + QApplication::setOverrideCursor(Qt::WaitCursor); + QPolygon poly2 = scene()->views().last()->mapFromScene(this->polygon()); + //QPolygon poly3 = scene()->views().last()->mapFromScene(option->exposedRect.toRect()); + //QPolygon poly4 = poly2.intersected(poly3); + //QRect boundingBox = poly4.boundingRect(); + QRect boundingBox = poly2.boundingRect(); + //QRect boundingBox = poly3.boundingRect(); + //std::cout << "x Top right of bounding Rect = " << poly2.boundingRect().topRight().x() << " , " << poly2.boundingRect().topRight().y() << std::endl; + //std::cout << "x Top right of exposed Rect = " << boundingBox.topRight().x() << " , " << boundingBox.topRight().y()<< std::endl; + + int bbWidth = (int)boundingBox.width(); + int bbHeight = (int)boundingBox.height(); + + int bbx = boundingBox.x(); + int bby = boundingBox.y(); + + + //create a QImage the size of the polygon's bounding box. + QImage image(bbWidth, bbHeight, QImage::Format_ARGB32); + + // Looping through the height of the bounding box. + for(int h = bby; h <= (const int)(bby + bbHeight - 1); h++) { + //check to make sure we are not outside the viewport's height. + if(h < 0)continue; + if(h > scene()->views().last()->viewport()->height())continue; + + QRgb *rgb = (QRgb *)image.scanLine(h - bby); + + //Fill the bounding Box with a white, transparent color. + for(int w = bbx; w <= (const int)(bbx + bbWidth - 1); w++) { + rgb[w - bbx] = qRgba(255, 255, 255, 0); + } + + //-------------------------------------------------------- + // Get a list of x values where the polygon intersects with + // the bounding box at the current line (h). + //--------------------------------------------------------- + QList inter = scanLineIntersections(poly2, h, bbWidth); + + //Check to see if the number of x values returned for that line is even. + //if (inter.size() % 2 != 0) continue; + + //---------------------------------------------- + // now loop thru the x values and fill in the + // pixels between the two points. + //--------------------------------------------- + + while(inter.size() > 1) { + + //------------------------------------------ + // set starting x to the second to last value + //------------------------------------------ + int sX = inter[inter.size() - 2]; + + //--------------------------------------------- + // set ending x to the last value and remove it + // so that inter.size shrinks by 1 + //--------------------------------------------- + int eX = inter.takeLast(); + + // the way it was before 2/6/09 SLA + //int eX = inter.takeLast(); + //int sX = inter.takeLast(); + + + //------------------------------------------------- + // when I comment out this if statement, it gets + // rid or the problem with the verticle lines + // ------------------------------------------------ + //if (eX - sX < 10) { + for(int i = sX; i < eX; i++) { + QPointF cameraCoords = screenToCam(i, h); + double samp = cameraCoords.x(); + double line = cameraCoords.y(); + if(samp < 0.5) continue; + if(line < 0.5) continue; + if(line > p_cube.Lines() + 0.5) continue; + if(samp > p_cube.Samples() + 0.5) continue; + + double pixelValue = getPixelValue((int)(samp + 0.5), (int)(line + 0.5)); + int strValue = (int)p_stretch.Map(pixelValue); + + rgb[i - bbx] = qRgba(strValue, strValue, strValue, 255); + } + //---------------- Just a test + } + } + + + //---------------- End test + /* continue; + //} + + // Starting line/sample + QPointF cameraCoords = screenToCam(sX,h); + double sSamp = cameraCoords.x(); + double sLine = cameraCoords.y(); + + // Ending line/sample + cameraCoords = screenToCam(eX,h); + double eSamp = cameraCoords.x(); + double eLine = cameraCoords.y(); + + // Midpoint + int trueMidX = (sX + eX) / 2; + cameraCoords = screenToCam(trueMidX,h); + double trueSamp = cameraCoords.x(); + double trueLine = cameraCoords.y(); + + if (sSamp == -1 || eSamp == -1 || trueSamp == -1) { + inter.push_back(sX); + inter.push_back(trueMidX); + inter.push_back(trueMidX+1); + inter.push_back(eX); + continue; + } + + // Calculate the slopes + double lineSlope = (eLine - sLine) / (eX - sX); + double sampSlope = (eSamp - sSamp) / (eX - sX); + + // Test to see if trueMidX is within 1/2 a pixel of samp midX + double testSamp = sSamp + sampSlope * (trueMidX - sX); + double testLine = sLine + lineSlope * (trueMidX - sX); + if (!midTest(trueSamp, trueLine, testSamp, testLine)) { + inter.push_back(sX); + inter.push_back(trueMidX); + inter.push_back(trueMidX+1); + inter.push_back(eX); + continue; + } + + // start the loop here. + double line = sLine; + double samp = sSamp; + for (int x = sX; x <= eX; x++, samp+=sampSlope, line+=lineSlope) { + + if (samp < 0.5) continue; + if (line < 0.5) continue; + if (line > p_cube.Lines() + 0.5) continue; + if (samp > p_cube.Samples() + 0.5) continue; + + double pixelValue = getPixelValue((int)(samp+0.5), (int)(line+0.5)); + int strValue = (int)p_stretch.Map(pixelValue); + + + std::cout << "eX -sX > 10 drawing at Height = " << h << std::endl; + rgb[x - bbx] = qRgba(strValue, strValue, strValue, 255); + + } //end inter loop + } // end while + } // end for height loop*/ + + // Paint the image on the scene. + //std::cout << "Painting image" << std::endl; + painter->drawImage(this->polygon().boundingRect(), image); + p_lastImage = image; + QApplication::restoreOverrideCursor(); + + } + catch(Isis::iException &e) { + std::cout << e.Errors() << std::endl; + } + + p_cube.Close(); + //if (p_groundMap != NULL) delete p_groundMap; + //std::cout << "Bottom drawImage" << std::endl; + } + + + /** + * This method returns a list of x values where the polygon + * intersects with the bounding box. + * + * @param poly + * @param line + * @param boxWidth + * + * @return QList + */ + QList MosaicItem::scanLineIntersections(QPolygon poly, int y, int boxWidth) { + QList inter; + for(int i = 0; i < poly.size() - 1; i++) { + int n = i + 1; + + int yMax = qMax(poly.point(i).y(), poly.point(n).y()); + int yMin = qMin(poly.point(i).y(), poly.point(n).y()); + + if(y < yMin) continue; + if(y > yMax) continue; + if(yMin == yMax) continue; + + if((poly.point(n).x() - poly.point(i).x()) == 0) { + inter.push_back(poly.point(n).x()); + } + else { + double slope = (double)(poly.point(n).y() - poly.point(i).y()) / (poly.point(n).x() - poly.point(i).x()); + double x = (y - poly.point(i).y()) / slope + poly.point(i).x(); + inter.push_back((int)(x + 0.5)); + } + } + + qSort(inter.begin(), inter.end()); + + QList uniqueList; + for(int i = 0; i < inter.size(); i++) { + if(uniqueList.size() == 0) { + uniqueList.push_back(inter[i]); + } + else if(inter[i] != uniqueList.last()) { + uniqueList.push_back(inter[i]); + } + } + if(uniqueList.size() == 3) { + uniqueList.removeAt(1); + } + + return uniqueList; + } + + + /** + * Creates and returns a random color for the intial color of + * the footprint polygon. + */ + QColor MosaicItem::randomColor() { + static bool firstTime = true; + // This seeds the random number. + if(firstTime) srand(5390); + + // Gives a random number between 0 and 255 + int red = rand() % 256; + int green = rand() % 256; + int blue = rand() % 256; + + firstTime = false; + return QColor(red, green, blue, 180); + } + + + /** + * Sets the color of the footprint + * @param color + */ + void MosaicItem::setColor(QColor color) { + this->setBrush(color); + this->setPen(color); + if(children().size() > 0) { + //if(children()[0]->isSelected()) { + ((MosaicItem *)children()[0])->setPen(color); + ((MosaicItem *)children()[0])->setBrush(color); + ((MosaicItem *)children()[0])->p_color = color; + ((MosaicItem *)children()[0])->setTransparency(color.alpha()); + //} + } + if(parentItem() != 0) { + ((MosaicItem *)parentItem())->setPen(color); + ((MosaicItem *)parentItem())->setBrush(color); + } + p_treeItem->setBackground(0, color); + + //ensure good contrast against bgcolor. + const QColor bgcolor = color; + if(bgcolor.red() > 127 || bgcolor.green() > 127 || bgcolor.blue() > 127 + || bgcolor.alpha() < 127) { + // black text + const QColor fgcolor(0, 0, 0); + p_treeItem->setForeground(0, fgcolor); + } + else { + // white text + const QColor fgcolor(255, 255, 255); + p_treeItem->setForeground(0, fgcolor); + } + + p_color = color; + + setTransparency(color.alpha()); + + } + + + /** + * Sets the alpha channel of the footprint. + * + * + * @param alpha + */ + void MosaicItem::setTransparency(int alpha) { + p_imageTransparency = alpha; + p_color.setAlpha(alpha); + + if(p_treeItem != NULL) { + p_treeItem->setBackground(0, p_color); + } + + update(); + + // if(p_treeItem == NULL) { + // return; + //} + + //if(children().size() > 0) { + //((MosaicItem *) children()[0])->setTransparency(alpha); + //} + /* update();*/ + } + + + /** + * Hides/shows footprint + * @param visible + */ + void MosaicItem::setItemVisible(bool visible) { + setVisible(visible); + if(p_treeItem != NULL) p_treeItem->setCheckState(1, visible ? Qt::Checked : Qt::Unchecked); + if(p_label != NULL) p_label->setVisible(visible); + if(p_secondItem != NULL) p_secondItem->setItemVisible(visible); + } + + + /** + * Hide/show the image associated with this item. + * @param visible + */ + void MosaicItem::setImageVisible(bool visible) { + p_treeItem->setCheckState(4, visible ? Qt::Checked : Qt::Unchecked); + update(); + } + + + /** + * Selects/Unselects the tree item associated with this item. + * @param selected + */ + void MosaicItem::setTreeItemSelected(bool selected) { + if(p_treeItem->isSelected() != selected) { + p_treeItem->setSelected(selected); + } + } + + + /** + * This method draws a dashed line around the item representing + * the item's bounding box. + * Called from the paint method. + * + * @param item + * @param painter + * @param option + */ + void MosaicItem::qt_graphicsItem_highlightSelected( + QGraphicsItem *item, QPainter *painter, const QStyleOptionGraphicsItem *option) { + + const QRectF murect = painter->transform().mapRect(QRectF(0, 0, 1, 1)); + if(qFuzzyCompare(qMax(murect.width(), murect.height()), qreal(0.0))) + return; + + const QRectF mbrect = painter->transform().mapRect(item->boundingRect()); + if(qMin(mbrect.width(), mbrect.height()) < qreal(1.0)) + return; + + qreal itemPenWidth; + switch(item->type()) { + + case QGraphicsPolygonItem::Type: + itemPenWidth = static_cast(item)->pen().widthF(); + break; + default: + itemPenWidth = 1.0; + } + const qreal pad = itemPenWidth / 2; + + const qreal penWidth = 0; // cosmetic pen + + const QColor fgcolor = option->palette.windowText().color(); + const QColor bgcolor( // ensure good contrast against fgcolor + fgcolor.red() > 127 ? 0 : 255, + fgcolor.green() > 127 ? 0 : 255, + fgcolor.blue() > 127 ? 0 : 255); + + painter->setPen(QPen(bgcolor, penWidth, Qt::SolidLine)); + painter->setBrush(Qt::NoBrush); + painter->drawRect(item->boundingRect().adjusted(pad, pad, -pad, -pad)); + + painter->setPen(QPen(option->palette.windowText(), 0, Qt::DashLine)); + painter->setBrush(Qt::NoBrush); + painter->drawRect(item->boundingRect().adjusted(pad, pad, -pad, -pad)); + + // Ensure that the children of this item are selected whenever the parent is. + QListchildren = item->children(); + for(int j = 0; j < children.size(); j++) { + children[j]->setSelected(true); + } + // If the child was the item selected, make sure that the parent is also selected + if(item->parentItem() != 0) item->parentItem()->setSelected(true); + } + + + /** + * This method sets the z values for this item and gives it's + * children, if there are any, the same z value. + * + * + * @param z + */ + void MosaicItem::setZValue(qreal z) { + QGraphicsItem::setZValue(z); + if(children().size() > 0) children()[0]->QGraphicsItem::setZValue(z); + if(parentItem() != 0) parentItem()->QGraphicsItem::setZValue(z); + + } + + + /** + * This method makes sure that when this item is selected, so + * are its children if there are any. + * + * @param selected + */ + void MosaicItem::setSelected(bool selected) { + QGraphicsItem::setSelected(selected); + if(children().size() > 0) children()[0]->QGraphicsItem::setSelected(selected); + if(parentItem() != 0) parentItem()->QGraphicsItem::setSelected(selected); + + } + + + /** + * This method calculates the stretch for the image associated + * with this mosaic item. + */ + void MosaicItem::getStretch() { + if(p_stretch.Pairs() != 0) return; + //Isis::Histogram hist(p_cube,1); + Isis::Histogram hist = *p_cube.Histogram(1); + double bestMin = hist.BestMinimum(); + double bestMax = hist.BestMaximum(); + + p_stretch.AddPair(bestMin, 0.0); + p_stretch.AddPair(bestMax, 255.0); + + p_stretch.SetNull(0.0); + p_stretch.SetLis(0.0); + p_stretch.SetLrs(0.0); + p_stretch.SetHis(255.0); + p_stretch.SetHrs(255.0); + p_stretch.SetMinimum(0.0); + p_stretch.SetMaximum(255.0); + + } + + + /** + * Display or hide the product ID on the footprint. + * + * @param visible + */ + void MosaicItem::setLabelVisible(bool visible) { + if(visible) { + p_treeItem->setCheckState(5, Qt::Checked); + } + else { + p_treeItem->setCheckState(5, Qt::Unchecked); + } + } + + + /** + * Display or hide the outline of the image footprint. + * + * @param visible + */ + void MosaicItem::setOutlineVisible(bool visible) { + if(visible) { + p_treeItem->setCheckState(3, Qt::Checked); + } + else { + p_treeItem->setCheckState(3, Qt::Unchecked); + } + } + + + /** + * Display or hide the outline of the image footprint. + * + * @param visible + */ + void MosaicItem::setFootprintVisible(bool visible) { + if(visible) { + p_treeItem->setCheckState(2, Qt::Checked); + } + else { + p_treeItem->setCheckState(2, Qt::Unchecked); + } + + } + + + /** + * Supplies the user with a font dialog box where they can + * select the font size of their choice. + */ + void MosaicItem::setFontSize() { + bool ok; + const QString caption = "Qmos rules! Select your font size"; + QFont font = QFontDialog::getFont(&ok, QFont("Helvetica", 10), p_parent, caption); + if(ok) { + // font is set to the font the user selected + p_label->setFont(font); + if(p_secondItem != NULL) setFontSize(font); + p_updateFont = true; + update(); + } + + } + + + /** + * Overloaded methoded for convenience. + * Set the font size of the item's label. + * + * + * @param font + */ + void MosaicItem::setFontSize(QFont font) { + p_label->setFont(font); + p_updateFont = true; + update(); + } + + + /** + * This is a way to allow the programmer to disable + * the paint routine if need be. + * + * @param paint + */ + void MosaicItem::setEnableRepaint(bool paint) { + p_enablePaint = paint; + } + + + /** + * This event filter catches all the events that happen to the + * p_label (QGraphicTextItem). + * + * + * @param watched + * @param event + * + * @return bool + */ + bool MosaicItem::sceneEventFilter(QGraphicsItem *watched, QEvent *event) { + + // if the item is not in the movable mode, then just need to return. + if(watched->flags() != QGraphicsItem::ItemIsMovable)return false; + + switch(event->type()) { + //----------------------------------------------------------------------- + // We need to make sure the user does not drag the label beyond the area + // of the bounding rectangle of the parent item's polygon. + //----------------------------------------------------------------------- + case QEvent::UngrabMouse: { + QRectF totalRect; + if(((QMouseEvent *) event)->button() == Qt::RightButton) return false; + + if(watched->parentItem() != 0) { + // This give us the coordinates at which the label was dropped. + QPointF dropPoint = p_label->mapToParent(((QGraphicsSceneMouseEvent *)event)->scenePos()); + + //--------------------------------------------------------- + // If there are two polygon items (i.e. the item crosses + // the lat/lon boundry then we need to combine the two + // polygons boundingboxes together before we check if + // the user droped the label within the correct area + // for this item. + //------------------------------------------------------- + if(p_crossesBoundry) { + totalRect = p_secondItem->boundingRect().united(watched->parentItem()->boundingRect()); + } + else { + totalRect = watched->parentItem()->boundingRect(); + } + + //----------------------------------------------------------------- + // Check to make sure the point at which the label was dropped is + // within the parent's bounding rectangle. If the drop point is + // outside of the bounding rect, then we put the label right + // back in the center + //----------------------------------------------------------------- + if(!totalRect.contains(dropPoint)) { + p_label->setPos(watched->parentItem()->boundingRect().center()); + } + + } + break; + } + + default: { + } + } + return false; + } + + + /** + * This method takes all the points in the passed in control + * network and decides if the point is within this item. + * If so, the point is then converted to projects space and then + * converted to GraphicsScene space and pushed back in to a + * QList of QPointF which is then used in the paint() method to + * paint the plus symbols to represent the points. + * + * + * @param netFile + */ + void MosaicItem::displayControlPoints(Isis::ControlNet *cn) { + p_controlPointsVisible = true; + p_controlNet = cn; + p_sceneToPointMap.clear(); + p_proj = p_parent->projection(); + + QApplication::setOverrideCursor(Qt::WaitCursor); + + Isis::Cube cube; + try { + cube.Open(p_filename.Expanded()); + //cube.Open(p_filename.Name()); + } + catch(Isis::iException &e) { + std::string msg = e.Errors(); + QMessageBox::information(p_parent, "Error", QString::fromStdString(msg), QMessageBox::Ok); + return; + } + + if(p_groundMap == NULL) { + try { + Isis::Pvl pvl(p_filename.Expanded()); + //Isis::Pvl pvl(p_filename.Name()); + p_groundMap = new Isis::UniversalGroundMap(pvl); + } + catch(Isis::iException &e) { + std::string msg = e.Errors(); + QMessageBox::information(p_parent, "Error", QString::fromStdString(msg), QMessageBox::Ok); + return; + } + } + + if(p_serialNumber.empty()) p_serialNumber = Isis::SerialNumber::Compose(cube); + + // Remove the old control points + p_controlPoints.clear(); + + for(int i = 0; i < cn->Size(); i++) { + Isis::ControlPoint p = (*cn)[i]; + //------------------------------------------------------------ + // we are now looping thru all the measures, so therefore all + // measures are being drawn to the scene. + // TODO: Allow user to see all control point measures, as an + // option. + //------------------------------------------------------------ + //for (int j = 0; j < p.Size(); j++) { + // This is how we decide if this point is in this item. + if(p[0].CubeSerialNumber().compare(p_serialNumber)) continue; + //if (p[j].CubeSerialNumber().compare(p_serialNumber)) continue; + + //---------------------------------------------- + // only use the first measure for all items. + // because that is usually the reference point. + //---------------------------------------------- + p_groundMap->SetImage(p[0].Sample(), p[0].Line()); + //------------------------------------------------------- + // the following commented out line causes us to display + // all the measures in each control point. + //--------------------------------------------------- + //p_groundMap->SetImage(p[j].Sample(),p[j].Line()); + double lat = p_groundMap->UniversalLatitude(); + double lon = p_groundMap->UniversalLongitude(); + // convert long. if necessary + if(p_proj->Has180Domain()) { + lon = p_proj->To180Domain(lon); + if(p_proj->IsPositiveWest()) lon = p_proj->ToPositiveWest(lon, 180); + } + else if(p_proj->IsPositiveWest()) { + lon = p_proj->ToPositiveWest(lon, 360); + } + // convert lat. if necessary + if(p_proj->IsPlanetographic()) { + lat = p_proj->ToPlanetographic(lat, p_proj->EquatorialRadius(), p_proj->PolarRadius()); + } + + if(p_proj->SetGround(lat, lon)) { + double x = p_proj->XCoord(); + double y = -1 * (p_proj->YCoord()); + + //--------------------------------------------------------------- + // check here so see if the point is within the bounding + // box of this polygon. This way we know if the point + // is in the parent or the child polygon if there are two polys. + //--------------------------------------------------------------- + if(this->polygon().boundingRect().contains(QPointF(x, y))) { + p_controlPoints.push_back(mapToScene(x, y)); + p_sceneToPointMap.insert(QString::fromStdString(p.Id()), mapToScene(x, y)); + } + + } + //} + } + + cube.Close(); + update(); + QApplication::restoreOverrideCursor(); + + // Now take care of the children + QListchildren = this->children(); + for(int j = 0; j < children.size(); j++) { + ((MosaicItem *)children[j])->displayControlPoints(cn); + } + } + + + /** + * When the control points are visislbe, then the paint() method + * knows to paint the points on the item. + * + * + * @param visible + */ + void MosaicItem::setControlPointsVisible(bool visible) { + p_controlPointsVisible = visible; + + // If we do not have the points for this item yet, we need to get them! + if(p_controlPoints.size() == 0 && p_controlPointsVisible) { + displayControlPoints(p_parent->controlNet()); + } + + update(); + + // Now take care of the children + QListchildren = this->children(); + for(int j = 0; j < children.size(); j++) { + ((MosaicItem *)children[j])->setControlPointsVisible(visible); + } + } + + + + /** + * This method saves all the item's current attributes to a pvl + * group which is returned. + * + * + * @return Isis::PvlGroup + */ + Isis::PvlGroup MosaicItem::saveState() { + Isis::PvlGroup grp("test"); + grp += Isis::PvlKeyword("Filename", this->filename().Expanded()); + grp += Isis::PvlKeyword("Color", this->color().name()); + grp += Isis::PvlKeyword("Alpha", this->color().alpha()); + grp += Isis::PvlKeyword("Group_Name", this->treeItem()->parent()->text(0).toStdString()); + + // Check item state + if(this->treeItem()->checkState(1) == Qt::Checked) { + grp += Isis::PvlKeyword("Item", "Yes"); + } + else { + grp += Isis::PvlKeyword("Item", "No"); + } + + // Check footprint state + if(this->treeItem()->checkState(2) == Qt::Checked) { + grp += Isis::PvlKeyword("Footprint", "Yes"); + } + else { + grp += Isis::PvlKeyword("Footprint", "No"); + } + + // Check outline state + if(this->treeItem()->checkState(3) == Qt::Checked) { + grp += Isis::PvlKeyword("Outline", "Yes"); + } + else { + grp += Isis::PvlKeyword("Outline", "No"); + } + + // Check image state + if(this->treeItem()->checkState(4) == Qt::Checked) { + grp += Isis::PvlKeyword("Image", "Yes"); + } + else { + grp += Isis::PvlKeyword("Image", "No"); + } + + // Check label state + if(this->treeItem()->checkState(5) == Qt::Checked) { + grp += Isis::PvlKeyword("Label", "Yes"); + } + else { + grp += Isis::PvlKeyword("Label", "No"); + } + + // Save control points + Isis::PvlKeyword keyword("ControlPoints"); + if(p_controlPointsVisible) { + for(int i = 0; i < p_controlPoints.size(); i++) { + Isis::iString controlPoint = p_controlPoints[i].x(); + controlPoint.append(":"); + Isis::iString temp = p_controlPoints[i].y(); + controlPoint.append(temp); + keyword.AddValue(controlPoint); + } + grp.AddKeyword(keyword); + } + + // Check control points visible state + if(p_controlPointsVisible) { + grp += Isis::PvlKeyword("ControlPointsVisible", "Yes"); + } + else { + grp += Isis::PvlKeyword("ControlPointsVisible", "No"); + } + + return grp; + } + + /*void MosaicItem::resizeEvent(QGraphicsSceneResizeEvent*){ + // Centre the contained text item + QTransform m = sceneTransform(); + p_label->resetTransform(); + p_label->scale( 1.0 / m.m11(), 1.0 / m.m22() ); + QRectF m_textRect = p_label->boundingRect(); + QPolygonF itemTextPoly = p_label->mapToItem( this, m_textRect ); + QRectF itemTextRect = itemTextPoly.boundingRect(); + double dx = 0.5 * m.m11() * ( rect().width() - itemTextRect.width() ); + double dy = 0.5 * m.m22() * ( rect().height() - itemTextRect.height() ); + p_label->translate( dx, dy ); + }*/ + + +} + diff --git a/isis/src/qisis/objs/MosaicItem/MosaicItem.h b/isis/src/qisis/objs/MosaicItem/MosaicItem.h new file mode 100644 index 0000000000000000000000000000000000000000..123c413e9dfea0e58b98024ce65b01058058d91c --- /dev/null +++ b/isis/src/qisis/objs/MosaicItem/MosaicItem.h @@ -0,0 +1,361 @@ +#ifndef MosaicItem_H +#define MosaicItem_H + +#include +#include + +#include "ControlNet.h" +#include "ControlMeasure.h" +#include "geos/geom/MultiPolygon.h" +#include "geos/geom/CoordinateSequence.h" +#include "Filename.h" +#include "Projection.h" +#include "MosaicWidget.h" +#include "Cube.h" +#include "Stretch.h" +#include "Brick.h" +#include "PvlGroup.h" +#include "UniversalGroundMap.h" + +namespace Qisis { + class MosaicWidget; + + class MosaicItem : public QGraphicsPolygonItem { + + public: + MosaicItem(const QString &cubeFilename, MosaicWidget *parent, Isis::PvlGroup *group = 0); + ~MosaicItem(); + + virtual void paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget = 0); + void qt_graphicsItem_highlightSelected(QGraphicsItem *item, QPainter + *painter, const + QStyleOptionGraphicsItem *option); + + + + /** + * Returns the cube filename. + * + * + * @return Isis::Filename + */ + Isis::Filename filename() const { + return p_filename; + }; + + + /** + * + * + * + * @return std::string + */ + std::string serialNumber() { + return p_serialNumber; + }; + + + /** + * + * + * + * @return QList + */ + QList controlPoints() { + return p_controlPoints; + }; + QMap pointsMap() { + return p_sceneToPointMap; + }; + + + /** + * Returns this item's maximum y value. + * + * + * @return double + */ + double YMaximum() const { + return p_ymax; + }; + + + /** + * Returns this items' maximum x value. + * + * + * @return double + */ + double XMaximum() const { + return p_xmax; + }; + + + /** + * Returns this item's minimum y value. + * + * + * @return double + */ + double YMinimum() const { + return p_ymin; + }; + + + /** + * Returns this item's minimum x value. + * + * + * @return double + */ + double XMinimum() const { + return p_xmin; + }; + + + /** + * Returns this item's pixel resolution. + * + * + * @return double + */ + double pixelResolution() const { + return p_pixRes; + }; + + + /** + * + * + * + * @return double + */ + double levelOfDetail() const { + return p_lastLevelOfDetail; + }; + + /** + * Returns this item's emission angle. + * + * + * @return double + */ + double emissionAngle() const { + return p_emissionAngle; + }; + + /** + * Returns this item's incidence angle. + * + * + * @return double + */ + double incidenceAngle() const { + return p_incidenceAngle; + }; + + + + /** + * Returns this item's footprint color. + * + * + * @return QColor + */ + QColor color() const { + return p_color; + }; + + + /** + * + * + * + * @return Isis::Projection* + */ + Isis::Projection *getProj() const { + return p_proj; + } + Isis::Cube *cube() { + return &p_cube; + } + + + /** + * + * + * + * @return Isis::UniversalGroundMap* + */ + Isis::UniversalGroundMap *getGroundMap() const { + return p_groundMap; + } + + + /** + * + * + * + * @return QGraphicsTextItem* + */ + QGraphicsSimpleTextItem *getLabel() const { + return p_label; + } + + + /** + * + * + * + * @return int + */ + int getImageTrans() const { + return p_imageTransparency; + } + + + /** + * + * + * + * @return bool + */ + bool crossBoundry() const { + return p_crossesBoundry; + } + + + /** + * + * + * + * @return MosaicItem* + */ + MosaicItem *getSecondItem() const { + return p_secondItem; + } + + /** + * Returns a bool indicating whether or not the tree item for + * this mosaic item is selected. + * + * + * @return bool + */ + bool isTreeItemSelected() { + return p_treeItem->isSelected(); + }; + + QTreeWidgetItem *treeWidgetItem() { + return p_treeItem; + }; + + void setLabelVisible(bool visible); + void setOutlineVisible(bool visible); + void setFootprintVisible(bool visible); + void displayControlPoints(Isis::ControlNet *cn); + void setControlPointsVisible(bool visible); + + void reproject(); + Isis::PvlGroup saveState(); + void setColor(QColor color); + void setTransparency(int alpha); + void setItemVisible(bool visible); + void setImageVisible(bool visible); + void setTreeItemSelected(bool selected); + void setLevelOfDetail(double detail); + void setZValue(qreal z); + void setSelected(bool selected); + QPointF screenToGround(QPointF point); + QPointF screenToCam(int x, int y); + QPointF screenToCam(QPointF p); + void setSelectedPoint(QPointF p); + protected: + /** + * Returns the tree item associated with this item. + * + * + * @return QTreeWidgetItem* + */ + QTreeWidgetItem *treeItem() { + return p_treeItem; + }; + bool sceneEventFilter(QGraphicsItem *watched, QEvent *event); + + private: + MosaicItem(MosaicItem *parent); //!< Private constructor + geos::geom::MultiPolygon *p_mp; //!< This item's multipolygon in the 0/360 longitude domain + geos::geom::MultiPolygon *p_180mp; //!< This item's multipolygon in the -180/180 longitude domain + QTreeWidgetItem *p_treeItem; //!< Tree item associated with this mosaic item + Isis::Filename p_filename; //!< Cube filename + + void createFootprint(); //!< Creates the footprint of this image. + void drawImage(QPainter *painter, const QStyleOptionGraphicsItem *option); + QList scanLineIntersections(QPolygon poly, int y, int boxWidth); + + bool midTest(double trueMidX, double trueMidY, double testMidX, double testMidY); + double getPixelValue(int sample, int line); + void getStretch(); + void setFontSize(); + void setFontSize(QFont font); + void setEnableRepaint(bool paint); + void setUpItem(Isis::PvlGroup *grp); + + void paintOutline(QPainter *painter); + void paintFootprint(QPainter *painter); + void paintControlPoints(QPainter *painter, const QStyleOptionGraphicsItem *option); + void paintLabel(const QStyleOptionGraphicsItem *option); + //Isis::Brick *p_gryBrick;//!< Bricks for gray band + + static QColor randomColor(); //!< Selects a color for the footprint polygon + QColor p_color; //!< This item's footprint color + QPolygonF p_footprintPoly; + + double p_xmin; //!< min x value of item + double p_xmax; //!< max x value of item + double p_ymin; //!< min y value of item + double p_ymax; //!< max y value of item + double p_pixRes; //!< Pixel Resolution of the cube + double p_emissionAngle; + double p_incidenceAngle; + double p_levelOfDetail; //!< Level of detail + + MosaicWidget *p_parent; //!< Parent widget + friend class MosaicWidget; //!< Made friends so parent has access to private members + MosaicItem *p_secondItem; + + Isis::Camera *p_camera; + Isis::Projection *p_proj; + Isis::UniversalGroundMap *p_groundMap; + double p_maxPixelValue; + int p_imageTransparency; + Isis::Cube p_cube; + Isis::Stretch p_stretch; + + QImage p_image; + + QImage p_lastImage; + QRectF p_lastExposedRect; + + //QGraphicsTextItem *p_label; + QGraphicsSimpleTextItem *p_label; + QFont p_labelFont; + //QFont p_font; + double p_lastLevelOfDetail; + double p_screenResolution; + bool p_updateFont; + bool p_enablePaint; + bool p_crossesBoundry; + bool p_controlPointsVisible; + QList p_controlPoints; + std::string p_serialNumber; + QMap p_sceneToPointMap; + QPointF p_selectedPoint; + Isis::ControlNet *p_controlNet; + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/MosaicMainWindow/Makefile b/isis/src/qisis/objs/MosaicMainWindow/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MosaicMainWindow/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MosaicMainWindow/MosaicMainWindow.cpp b/isis/src/qisis/objs/MosaicMainWindow/MosaicMainWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92605e8ae9c6ddec21df61c2161c53da6994d68b --- /dev/null +++ b/isis/src/qisis/objs/MosaicMainWindow/MosaicMainWindow.cpp @@ -0,0 +1,415 @@ +#include "MosaicMainWindow.h" + +#include +#include + +#include "FileDialog.h" +#include "ToolPad.h" + + +namespace Qisis { + MosaicMainWindow::MosaicMainWindow (QString title, QWidget *parent) : + Qisis::MainWindow(title, parent) { + + p_filename = ""; + installEventFilter(this); + + this->setWindowTitle(title); + + p_permToolbar = new QToolBar("Standard Tools",this); + p_permToolbar->setObjectName("perm"); + p_permToolbar->setAllowedAreas(Qt::TopToolBarArea|Qt::BottomToolBarArea); + p_permToolbar->setIconSize(QSize(22,22)); + this->addToolBar(p_permToolbar); + + p_activeToolbar = new QToolBar("Active Tool",this); + p_activeToolbar->setObjectName("Active"); + p_activeToolbar->setAllowedAreas(Qt::TopToolBarArea|Qt::BottomToolBarArea); + p_activeToolbar->setIconSize(QSize(22,22)); + this->addToolBar(p_activeToolbar); + + QStatusBar *sbar = statusBar(); + sbar->showMessage("Ready"); + + p_toolpad = new ToolPad("Tool Pad",this); + p_toolpad->setObjectName("MosaicMainWindow"); + p_toolpad->setAllowedAreas(Qt::LeftToolBarArea|Qt::RightToolBarArea); + this->addToolBar(Qt::RightToolBarArea,p_toolpad); + + p_progressBar = new QProgressBar(parent); + p_progressBar->setOrientation(Qt::Horizontal); + sbar->addWidget(p_progressBar); + + setupMenus(); + readSettings(); + } + + + /** + * Sets up the menus on the menu bar for the qmos window. + */ + void MosaicMainWindow::setupMenus(){ + // Create the file menu + QMenu *fileMenu = menuBar()->addMenu("&File"); + + QAction *open = new QAction(this); + open->setText("Open..."); + open->setIcon(QPixmap(QString::fromStdString(Isis::Filename("$base/icons").Expanded().c_str()) + "/fileopen.png")); + connect(open,SIGNAL(activated()),this,SLOT(open())); + + QAction *openList = new QAction(this); + openList->setText("Import List..."); + openList->setIcon(QPixmap(QString::fromStdString(Isis::Filename("$base/icons").Expanded().c_str())+"/mActionHelpContents.png")); + connect(openList,SIGNAL(activated()),this,SLOT(openList())); + + QAction *saveList = new QAction(this); + saveList->setText("Export List..."); + //saveList->setIcon(QPixmap(QString::fromStdString(Isis::Filename("$base/icons").Expanded().c_str())+"/filesaveas.png")); + connect(saveList,SIGNAL(activated()),this,SLOT(saveList())); + + QAction *exportView = new QAction(this); + exportView->setText("Export View..."); + //exportView->setIcon(QPixmap(QString::fromStdString(Isis::Filename("$base/icons").Expanded().c_str())+"/fileexport.png")); + connect(exportView,SIGNAL(activated()),this,SLOT(exportView())); + + QAction *saveProject = new QAction(this); + saveProject->setText("Save Project..."); + saveProject->setShortcut(Qt::CTRL+Qt::Key_S); + saveProject->setIcon(QPixmap(QString::fromStdString(Isis::Filename("$base/icons").Expanded().c_str()) + "/mActionFileSave.png")); + connect(saveProject,SIGNAL(activated()),this,SLOT(saveProject())); + + QAction *saveProjectAs = new QAction(this); + saveProjectAs->setText("Save Project As..."); + saveProjectAs->setIcon(QPixmap(QString::fromStdString(Isis::Filename("$base/icons").Expanded().c_str()) + "/mActionFileSaveAs.png")); + connect(saveProjectAs,SIGNAL(activated()),this,SLOT(saveProjectAs())); + + QAction *loadProject = new QAction(this); + loadProject->setText("Load Project..."); //linguist-editpaste + loadProject->setIcon(QPixmap(QString::fromStdString(Isis::Filename("$base/icons").Expanded().c_str()) + "/mActionExportMapServer.png")); + connect(loadProject,SIGNAL(activated()),this,SLOT(loadProject())); + + QAction *close = new QAction(this); + close->setText("Close"); + connect(close,SIGNAL(activated()),this,SLOT(close())); + + fileMenu->addAction(open); + fileMenu->addAction(openList); + fileMenu->addAction(saveList); + fileMenu->addAction(exportView); + fileMenu->addSeparator(); + fileMenu->addAction(saveProject); + fileMenu->addAction(loadProject); + fileMenu->addSeparator(); + fileMenu->addAction(close); + + permanentToolBar()->addAction(loadProject); + permanentToolBar()->addAction(saveProject); + permanentToolBar()->addAction(saveProjectAs); + permanentToolBar()->addSeparator(); + permanentToolBar()->addAction(open); + permanentToolBar()->addAction(openList); + permanentToolBar()->addSeparator(); + + p_viewMenu = menuBar()->addMenu("View"); + p_viewMenu->setTearOffEnabled(true); + connect(p_viewMenu, SIGNAL(triggered(QAction *)), this, SLOT(hideShowColumns(QAction *))); + + p_itemColumn = new QAction(this); + p_itemColumn->setText("Item Column"); + p_itemColumn->setCheckable(true); + p_itemColumn->setChecked(true); + + p_footprintColumn = new QAction(this); + p_footprintColumn->setText("Footprint Column"); + p_footprintColumn->setCheckable(true); + p_footprintColumn->setChecked(true); + + p_outlineColumn = new QAction(this); + p_outlineColumn->setText("Outline Column"); + p_outlineColumn->setCheckable(true); + p_outlineColumn->setChecked(true); + + p_imageColumn = new QAction(this); + p_imageColumn->setText("Image Column"); + p_imageColumn->setCheckable(true); + p_imageColumn->setChecked(true); + + p_labelColumn = new QAction(this); + p_labelColumn->setText("Label Column"); + p_labelColumn->setCheckable(true); + p_labelColumn->setChecked(true); + + p_resolutionColumn = new QAction(this); + p_resolutionColumn->setText("Resolution Column"); + p_resolutionColumn->setCheckable(true); + p_resolutionColumn->setChecked(true); + + p_emissionAngleColumn = new QAction(this); + p_emissionAngleColumn->setText("Emission Angle Column"); + p_emissionAngleColumn->setCheckable(true); + p_emissionAngleColumn->setChecked(true); + + p_incidenceAngleColumn = new QAction(this); + p_incidenceAngleColumn->setText("Incidence Angle Column"); + p_incidenceAngleColumn->setCheckable(true); + p_incidenceAngleColumn->setChecked(true); + + p_islandColumn = new QAction(this); + p_islandColumn->setText("Island Column"); + p_islandColumn->setCheckable(true); + p_islandColumn->setChecked(true); + + p_notesColumn = new QAction(this); + p_notesColumn->setText("Notes Column"); + p_notesColumn->setCheckable(true); + p_notesColumn->setChecked(true); + + p_referenceFootprint = new QAction(this); + p_referenceFootprint->setText("Show Reference Footprint"); + p_referenceFootprint->setCheckable(true); + p_referenceFootprint->setChecked(false); + + p_viewMenu->addSeparator(); + p_viewMenu->addAction(p_itemColumn); + p_viewMenu->addAction(p_footprintColumn); + p_viewMenu->addAction(p_outlineColumn); + p_viewMenu->addAction(p_imageColumn); + p_viewMenu->addAction(p_labelColumn); + p_viewMenu->addAction(p_resolutionColumn); + p_viewMenu->addAction(p_emissionAngleColumn); + p_viewMenu->addAction(p_incidenceAngleColumn); + p_viewMenu->addAction(p_islandColumn); + p_viewMenu->addAction(p_notesColumn); + p_viewMenu->addSeparator(); + p_viewMenu->addAction(p_referenceFootprint); + + } + + + /** + * Allows users to decide which columns in the tree widget they + * would like to have visible. + * + * + * @param action + */ + void MosaicMainWindow::hideShowColumns(QAction *action){ + ((MosaicWidget *)centralWidget())->viewMenuAction(action); + } + + + /** + * Calles MosaicWidget's open method which opens a cube file and + * displays the footprint in the graphics view. + * + */ + void MosaicMainWindow::open () { + ((MosaicWidget *)centralWidget())->open(); + } + + + /** + * Opens a list of cube files instead of one at a time. + * + */ + void MosaicMainWindow::openList () { + ((MosaicWidget *)centralWidget())->openList(); + } + + + /** + * This overriden method is called from the constructor so that + * when the Mosaicmainwindow is created, it know's it's size + * and location and the tool bar location. + * + */ + void MosaicMainWindow::readSettings(){ + // Call the base class function to read the size and location + this->MainWindow::readSettings(); + // Now read the settings that are specific to this window. + std::string instanceName = this->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/" + instanceName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()), QSettings::NativeFormat); + QByteArray state = settings.value("state", QByteArray("0")).toByteArray(); + restoreState(state); + QList actionList = p_viewMenu->actions(); + for(int i = 0; i < actionList.size(); i++){ + QString itemTitle = actionList[i]->text(); + bool state = (bool)settings.value(itemTitle, 0).toBool(); + actionList[i]->setChecked(state); + } + p_referenceFootprint->setChecked(false); + } + + + /** + * This overriden method is called when the Mosaicmainwindow + * is closed or hidden to write the size and location settings + * (and tool bar location) to a config file in the user's home + * directory. + * + */ + void MosaicMainWindow::writeSettings(){ + // Call the base class function to write the size and location + this->MainWindow::writeSettings(); + // Now write the settings that are specific to this window. + std::string instanceName = this->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/" + instanceName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()), QSettings::NativeFormat); + settings.setValue("state", this->saveState()); + + //----------------------------------------------------------- + // Save the check state of all the actions in the view menu. + //----------------------------------------------------------- + QList actionList = p_viewMenu->actions(); + for(int i = 0; i < actionList.size(); i++){ + QString itemTitle = actionList[i]->text(); + settings.setValue(itemTitle, actionList[i]->isChecked()); + } + /* settings.setValue("nameColumn", p_nameColumn->isChecked()); + settings.setValue("itemColumn", p_itemColumn->isChecked()); + settings.setValue("footprintColumn", p_footprintColumn->isChecked()); + settings.setValue("outlineColumn", p_outlineColumn->isChecked()); + settings.setValue("imageColumn", p_imageColumn->isChecked()); + settings.setValue("labelColumn", p_labelColumn->isChecked()); + settings.setValue("resolutionColumn", p_resolutionColumn->isChecked()); + settings.setValue("emissionColumn", p_emissionAngleColumn->isChecked()); + settings.setValue("incidenceAngleColumn", p_incidenceAngleColumn->isChecked()); + settings.setValue("islandColumn", p_islandColumn->isChecked()); + settings.setValue("notesColumn", p_notesColumn->isChecked()); + settings.setValue("referenceFootprint", p_referenceFootprint->isChecked());*/ + } + + + /** + * Saves the list of cubes to a text file. + * + */ + void MosaicMainWindow::saveList(){ + QString fn = QFileDialog::getSaveFileName(this, "Save File", + QDir::currentPath() + "/untitled.lis", + "List (*.lis)"); + if (fn.isEmpty()) return; + QString filename; + + if(!fn.endsWith(".lis")) { + filename = fn + ".lis"; + } else { + filename = fn; + } + ((MosaicWidget *)centralWidget())->saveList(filename); + } + + + /** + * Allows the user to save a project file. + * + */ + void MosaicMainWindow::saveProjectAs(){ + QString fn = QFileDialog::getSaveFileName(this, "Save Project", + QDir::currentPath() + "/untitled.mos", + "Mosaic (*.mos)"); + if (fn.isEmpty()) return; + QString filename; + + if(!fn.endsWith(".mos")) { + filename = fn + ".mos"; + } else { + filename = fn; + } + ((MosaicWidget *)centralWidget())->saveProject(filename); + p_filename = filename; + } + + + /** + * Called from the file menu to save a project file. + * + */ + void MosaicMainWindow::saveProject(){ + //-------------------------------------- + // If the project does not already have + // a name, call saveProjectAs + //-------------------------------------- + if(p_filename == "" ) { + saveProjectAs(); + return; + } + ((MosaicWidget *)centralWidget())->saveProject(p_filename); + } + + + /** + * Allows users to select a project which is then read in and + * displayed in the qmos window. + * + */ + void MosaicMainWindow::loadProject(){ + QString fn = QFileDialog::getOpenFileName(this, "Load Project", + QDir::currentPath(), + "Mosaic (*.mos)"); + if (fn.isEmpty()) return; + QString filename; + + if(!fn.endsWith(".mos")) { + filename = fn + ".mos"; + } else { + filename = fn; + } + ((MosaicWidget *)centralWidget())->readProject(filename); + p_filename = filename; + } + + + /** + * Saves the graphics view as a png, jpg, of tif file. + * + */ + void MosaicMainWindow::exportView () { + + QString output = + QFileDialog::getSaveFileName((QWidget *)parent(), + "Choose output file", + QDir::currentPath() + "/untitled.png", + QString("Images (*.png *.jpg *.tif)")); + if (output.isEmpty()) return; + + // Use png format is the user did not add a suffix to their output filename. + if(QFileInfo(output).suffix().isEmpty()){ + output = output + ".png"; + } + + QString format = QFileInfo(output).suffix(); + QPixmap pm = QPixmap::grabWidget(((MosaicWidget *)centralWidget())->scene()->views().last()); + + std::string formatString = format.toStdString(); + if (!pm.save(output,formatString.c_str())) { + QMessageBox::information((QWidget *)parent(),"Error","Unable to save "+output); + return; + } + } + + + /** + * This event filter is installed in the constructor. + * @param o + * @param e + * + * @return bool + */ + bool MosaicMainWindow::eventFilter(QObject *o,QEvent *e) { + + switch (e->type()) { + case QEvent::Close:{ + writeSettings(); + break; + } + + default: { + return false; + } + } + return false; + } +} + diff --git a/isis/src/qisis/objs/MosaicMainWindow/MosaicMainWindow.h b/isis/src/qisis/objs/MosaicMainWindow/MosaicMainWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..8c6689d76621322b2139521a1534f1251edd9e1e --- /dev/null +++ b/isis/src/qisis/objs/MosaicMainWindow/MosaicMainWindow.h @@ -0,0 +1,91 @@ +#ifndef MosaicMainWindow_h +#define MosaicMainWindow_h + +#include +#include +#include + +#include "Filename.h" +#include "MainWindow.h" +#include "MosaicWidget.h" +#include "MosaicItem.h" + + +namespace Qisis { + /** + * @brief + * + * @ingroup Visualization Tools + * + * @author Stacy Alley + * + * @internal + * + * @history 2010-05-10 Christopher Austin - added cnet connectivity + * functionality + */ + class ToolPad; + + class MosaicMainWindow : public Qisis::MainWindow { + Q_OBJECT + public: + MosaicMainWindow (QString title, QWidget *parent=0); + QToolBar *permanentToolBar () { return p_permToolbar; }; + QToolBar *activeToolBar () { return p_activeToolbar; }; + Qisis::ToolPad *toolPad() { return p_toolpad; }; + QProgressBar *progressBar() { return p_progressBar; }; + /** + * Returns the View menu. + * + * + * @return QMenu* + */ + QMenu *viewMenu() const { return p_viewMenu; }; + + protected: + bool eventFilter(QObject *o,QEvent *e); + void readSettings(); + void writeSettings(); + + public slots: + void open(); + void openList(); + void saveList(); + void saveProject(); + void saveProjectAs(); + void loadProject(); + void exportView(); + void hideShowColumns(QAction *action); + + private: + void setupMenus(); + void setupPvlToolBar(); + + QToolBar *p_permToolbar; //!< Tool bar attached to mainwindow + Qisis::ToolPad *p_toolpad; //!< Tool pad on this mainwindow + QToolBar *p_activeToolbar; //!< The active toolbar + std::map p_menus; //!< Maps Menus to string names + std::string p_appName; //!< The main application + QString p_filename; + + QProgressBar *p_progressBar; //!< The mainwindow's progress bar. + + QAction *p_nameColumn; + QAction *p_itemColumn; + QAction *p_footprintColumn; + QAction *p_outlineColumn; + QAction *p_imageColumn; + QAction *p_labelColumn; + QAction *p_resolutionColumn; + QAction *p_emissionAngleColumn; + QAction *p_incidenceAngleColumn; +QAction *p_islandColumn; + QAction *p_notesColumn; + QAction *p_referenceFootprint; + + QMenu *p_viewMenu; + + }; +}; + +#endif diff --git a/isis/src/qisis/objs/MosaicPanTool/Makefile b/isis/src/qisis/objs/MosaicPanTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MosaicPanTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MosaicPanTool/MosaicPanTool.cpp b/isis/src/qisis/objs/MosaicPanTool/MosaicPanTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d652ae421ae54384047b3afb983f2a798c145fd0 --- /dev/null +++ b/isis/src/qisis/objs/MosaicPanTool/MosaicPanTool.cpp @@ -0,0 +1,88 @@ +#include "MosaicPanTool.h" +#include "MosaicMainWindow.h" + +#include + +namespace Qisis { + /** + * MosaicPanTool constructor + * + * + * @param parent + */ + MosaicPanTool::MosaicPanTool (QWidget *parent) : Qisis::MosaicTool(parent) { + p_parent = (MosaicWidget *)parent; + connect(this,SIGNAL(activated(bool)),this,SLOT(updateTool())); + + } + + + /** + * Adds the action to the toolpad. + * + * + * @param toolpad + * + * @return QAction* + */ + QAction *MosaicPanTool::toolPadAction(ToolPad *toolpad) { + QAction *action = new QAction(toolpad); + action->setIcon(QPixmap(toolIconDir()+"/move.png")); + //action->setIcon(QPixmap("/work1/salley/icons/mActionMoveVertex.png")); + action->setToolTip("Pan (P)"); + action->setShortcut(Qt::Key_P); + QString text = + "Function: View different areas of the mosaic. \ +

    Shortcut: P

    "; + action->setWhatsThis(text); + return action; + } + + + /** + * Adds the pan action to the given menu. + * + * + * @param menu + */ + void MosaicPanTool::addToMenu(QMenu *menu) { + + } + + + /** + * Creates the widget to add to the tool bar. + * + * + * @param parent + * + * @return QWidget* + */ + QWidget *MosaicPanTool::createToolBarWidget (QStackedWidget *parent) { + QWidget *hbox = new QWidget(parent); + return hbox; + } + + + /** + * + * + */ + void MosaicPanTool::updateTool() { + + const QList items = p_parent->allMosaicItems(); + //const QList &items = p_parent->mosaicItems(); + if(isActive()) { + for(int i = 0; i < items.size(); i++) { + items[i]->setFlag(QGraphicsItem::ItemIsSelectable, false); + } + getGraphicsView()->setDragMode(QGraphicsView::ScrollHandDrag); + } else { + for(int i = 0; i < items.size(); i++) { + items[i]->setFlag(QGraphicsItem::ItemIsSelectable, true); + } + getGraphicsView()->setDragMode(QGraphicsView::NoDrag); + } + } + +} diff --git a/isis/src/qisis/objs/MosaicPanTool/MosaicPanTool.h b/isis/src/qisis/objs/MosaicPanTool/MosaicPanTool.h new file mode 100644 index 0000000000000000000000000000000000000000..79364e24651e3a2e25edab13ce944cfc1e5e2733 --- /dev/null +++ b/isis/src/qisis/objs/MosaicPanTool/MosaicPanTool.h @@ -0,0 +1,43 @@ +#ifndef MosaicPanTool_h +#define MosaicPanTool_h + +#include "MosaicTool.h" + +#include + +namespace Qisis { + /** + * @brief Handles panning operations for Isis qt apps + * + * @ingroup Visualization Tools + * + * @author Stacy Alley + * + * @internal + * @history + */ + class MosaicPanTool : public Qisis::MosaicTool { + Q_OBJECT + + public: + MosaicPanTool (QWidget *parent); + void addToMenu(QMenu *menu); + + protected slots: + void updateTool(); + + protected: + QAction *toolPadAction(ToolPad *toolpad); + //! Returns the name of the menu. + QString menuName() const { return "&View"; }; + QWidget *createToolBarWidget(QStackedWidget *parent); + + public slots: + + private: + MosaicWidget *p_parent; + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/MosaicPointTool/Makefile b/isis/src/qisis/objs/MosaicPointTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MosaicPointTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MosaicPointTool/MosaicPointTool.cpp b/isis/src/qisis/objs/MosaicPointTool/MosaicPointTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6ab704333c19e0fa6fe8bc867f2a7aa07a7b6665 --- /dev/null +++ b/isis/src/qisis/objs/MosaicPointTool/MosaicPointTool.cpp @@ -0,0 +1,169 @@ +#include "MosaicPointTool.h" + +namespace Qisis { + /** + * MosaicPointTool constructor + * + * + * @param parent + */ + MosaicPointTool::MosaicPointTool(QWidget *parent) : Qisis::MosaicTool(parent) { + p_parent = (MosaicWidget *)parent; + p_pointInfoDialog = new QMessageBox(QMessageBox::Information, + "Control Point Information", + "Empty String", QMessageBox::Ok); + } + + + /** + * Adds the action to the toolpad. + * + * + * @param toolpad + * + * @return QAction* + */ + QAction *MosaicPointTool::toolPadAction(ToolPad *toolpad) { + QAction *action = new QAction(toolpad); + action->setIcon(QPixmap(toolIconDir() + "/stock_draw-connector-with-arrows.png")); + action->setToolTip("Point (T)"); + action->setShortcut(Qt::Key_T); + QString text = + "Function: Set mode to Point selection mode. \ +

    Shortcut: O

    "; + action->setWhatsThis(text); + return action; + } + + + /** + * Adds the pan action to the given menu. + * + * + * @param menu + */ + void MosaicPointTool::addToMenu(QMenu *menu) { + + } + + + /** + * Creates the widget to add to the tool bar. + * + * + * @param parent + * + * @return QWidget* + */ + QWidget *MosaicPointTool::createToolBarWidget(QStackedWidget *parent) { + QWidget *hbox = new QWidget(parent); + return hbox; + } + + + /** + * Finds the given point in the control net, then dipslays an + * information message box about the choosen control point. + * + * + * @param p + */ + void MosaicPointTool::findPoint(QPointF p, Isis::ControlNet *cn) { + double minDistance = DBL_MAX; + QPointF closestPoint; + QString pointId = "No Point"; + + // The allMosiacItem method returns all items including the item's children. + QList items = getWidget()->allMosaicItems(); + for(int i = 0; i < items.size(); i++) { + QMap pointsMap = items[i]->pointsMap(); + QList controlPoints = items[i]->controlPoints(); + double distance; + for(int j = 0; j < controlPoints.size(); j++) { + distance = sqrt(pow(p.x() - controlPoints[j].x(), 2) + + pow(p.y() - controlPoints[j].y(), 2)); + if(distance < minDistance) { + minDistance = distance; + closestPoint = controlPoints[j]; + pointId = pointsMap.key(closestPoint); + } + + } + + }// End for i < items.size() + + //------------------------------------------------------------------ + // Make sure each item knows which point was selected so that it can + // be painted red if the item contains that points. + //------------------------------------------------------------------ + for(int k = 0; k < items.size(); k++) { + items[k]->setSelectedPoint(closestPoint); + //items[k]->update(); + } + + Isis::ControlPoint *controlPoint = cn->Find(pointId.toStdString()); + QString type = "no type"; + if(controlPoint->Type() == Isis::ControlPoint::Ground) { + type = "Ground"; + } + else if(controlPoint->Type() == Isis::ControlPoint::Tie) { + type = "Tie"; + } + + QString serialNumbers; + QList measureItems; + for(int m = 0; m < controlPoint->Size(); m++) { + serialNumbers.append("\nControl Measure "); + serialNumbers.append(QString::number(m + 1)); + serialNumbers.append(" Serial #: "); + serialNumbers.append(QString::fromStdString((*controlPoint)[m].CubeSerialNumber())); + + //------------------------------------------------------------------------ + // If the Mosaic Item is one of the control point's measures, then we want + // to set that item's transparency to 255 and the others to 120. + //------------------------------------------------------------------------ + for(int n = 0; n < items.size(); n++) { + if((*controlPoint)[m].CubeSerialNumber().compare(items[n]->serialNumber()) == 0) { + measureItems.push_back(items[n]); + } + } + } + + QList originalTrans; + for(int p = 0; p < items.size(); p++) { + // Save the original transparency values. + originalTrans.push_back(items[p]->color().alpha()); + if(measureItems.contains(items[p])) { + items[p]->setTransparency(255); + } + else { + items[p]->setTransparency(20); + } + } + + p_pointInfoDialog->setText("Point ID: " + pointId + + "\nNumber of Measures: " + QString::number(controlPoint->Size()) + + serialNumbers + + + "\nPoint Type: " + type); + + int ret = p_pointInfoDialog->exec(); + switch(ret) { + case QMessageBox::Ok: + //-------------------------------------------------------- + // This is where we need to reset the original transparency + // values for all the items. + //------------------------------------------------------- + for(int q = 0; q < items.size(); q++) { + items[q]->setTransparency(originalTrans[q]); + } + break; + + default: + break; + } + + } + +} + + diff --git a/isis/src/qisis/objs/MosaicPointTool/MosaicPointTool.h b/isis/src/qisis/objs/MosaicPointTool/MosaicPointTool.h new file mode 100644 index 0000000000000000000000000000000000000000..2a899d7c5c91e38f6b1e34bdfbade48b89522697 --- /dev/null +++ b/isis/src/qisis/objs/MosaicPointTool/MosaicPointTool.h @@ -0,0 +1,39 @@ +#ifndef Qisis_MosaicPointTool_h +#define Qisis_MosaicPointTool_h + +#include "MosaicTool.h" +#include "ControlNet.h" + +class QLabel; + +namespace Qisis { + class MosaicPointTool : public Qisis::MosaicTool { + Q_OBJECT + + public: + MosaicPointTool(QWidget *parent); + void addToMenu(QMenu *menu); + + public slots: + void findPoint(QPointF p, Isis::ControlNet *cn); + + protected: + QAction *toolPadAction(ToolPad *toolpad); + //! Returns the name of the menu. + QString menuName() const { + return "&View"; + }; + QWidget *createToolBarWidget(QStackedWidget *parent); + + private: + + MosaicWidget *p_parent; + QMessageBox *p_pointInfoDialog; + QVBoxLayout *p_vLayout; + QLabel *p_pointIdLabel; + QLabel *p_numMeasuresLabel; + QLabel *p_pointTypeLabel; + }; +}; + +#endif diff --git a/isis/src/qisis/objs/MosaicSelectTool/Makefile b/isis/src/qisis/objs/MosaicSelectTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MosaicSelectTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MosaicSelectTool/MosaicSelectTool.cpp b/isis/src/qisis/objs/MosaicSelectTool/MosaicSelectTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eba45d3b0fd404f31033ccb5463837d590cc8dd4 --- /dev/null +++ b/isis/src/qisis/objs/MosaicSelectTool/MosaicSelectTool.cpp @@ -0,0 +1,77 @@ +#include "MosaicSelectTool.h" + +#include + +namespace Qisis { + /** + * MosaicSelectTool constructor + * + * + * @param parent + */ + MosaicSelectTool::MosaicSelectTool (QWidget *parent) : Qisis::MosaicTool(parent) { + connect(this,SIGNAL(activated(bool)),this,SLOT(updateTool())); + } + + + /** + * Adds the action to the toolpad. + * + * + * @param toolpad + * + * @return QAction* + */ + QAction *MosaicSelectTool::toolPadAction(ToolPad *toolpad) { + QAction *action = new QAction(toolpad); + action->setIcon(QPixmap(toolIconDir()+"/mActionSelect.png")); + action->setToolTip("Select (S)"); + action->setShortcut(Qt::Key_S); + QString text = + "Function: View different areas of the mosaic. \ +

    Shortcut: S

    "; + action->setWhatsThis(text); + return action; + } + + + /** + * Adds the pan action to the given menu. + * + * + * @param menu + */ + void MosaicSelectTool::addToMenu(QMenu *menu) { + + } + + + /** + * Creates the widget to add to the tool bar. + * + * + * @param parent + * + * @return QWidget* + */ + QWidget *MosaicSelectTool::createToolBarWidget (QStackedWidget *parent) { + QWidget *hbox = new QWidget(parent); + return hbox; + } + + + + /** + * This method sets the QGraphicsView to allow the user to select + * mosaic items by dragging a rubber band. + * + */ + void MosaicSelectTool::updateTool() { + if(isActive()) { + getGraphicsView()->setDragMode(QGraphicsView::RubberBandDrag); + } else { + getGraphicsView()->setDragMode(QGraphicsView::NoDrag); + } + } + +} diff --git a/isis/src/qisis/objs/MosaicSelectTool/MosaicSelectTool.h b/isis/src/qisis/objs/MosaicSelectTool/MosaicSelectTool.h new file mode 100644 index 0000000000000000000000000000000000000000..8e725203bb0467390c5e356f9a0ced55e8e27688 --- /dev/null +++ b/isis/src/qisis/objs/MosaicSelectTool/MosaicSelectTool.h @@ -0,0 +1,42 @@ +#ifndef MosaicSelectTool_h +#define MosaicSelectTool_h + +#include "MosaicTool.h" +#include + +namespace Qisis { + /** + * @brief Handles selection operations for Isis qt apps + * + * @ingroup Visualization Tools + * + * @author Stacy Alley + * + * @internal + * @history + */ + class MosaicSelectTool : public Qisis::MosaicTool { + Q_OBJECT + + public: + MosaicSelectTool (QWidget *parent); + void addToMenu(QMenu *menu); + + protected slots: + void updateTool(); + + protected: + QAction *toolPadAction(ToolPad *toolpad); + //! Returns the name of the menu. + QString menuName() const { return "&View"; }; + QWidget *createToolBarWidget(QStackedWidget *parent); + + public slots: + + private: + + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/MosaicTool/Makefile b/isis/src/qisis/objs/MosaicTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MosaicTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MosaicTool/MosaicTool.cpp b/isis/src/qisis/objs/MosaicTool/MosaicTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c7ec40dc3dca7aed99a11154d1df929947aca751 --- /dev/null +++ b/isis/src/qisis/objs/MosaicTool/MosaicTool.cpp @@ -0,0 +1,133 @@ +#include "MosaicTool.h" + +#include "ToolPad.h" +#include "Filename.h" + +namespace Qisis { + QStackedWidget *MosaicTool::p_activeToolBarStack = NULL; + /** + * Tool constructor + * + * @param parent + */ + MosaicTool::MosaicTool (QWidget *parent) : QObject(parent) { + p_toolPadAction = NULL; + p_toolBarWidget = NULL; + p_active = false; + std::string tempFilename = Isis::Filename("$base/icons").Expanded(); + p_toolIconDir = tempFilename.c_str(); + + } + + + /** + * Adds the tool to the qmos application + * + * + * @param mmw + */ + void MosaicTool::addTo (Qisis::MosaicMainWindow *mmw) { + addToPermanent(mmw->permanentToolBar()); + addToActive(mmw->activeToolBar()); + addTo(mmw->toolPad()); + //if (!menuName().isEmpty()) { + //QMenu *menu = mmw->getMenu(menuName()); + //addTo(menu); + //} + } + + + /** + * Adds the MosaicTool to the toolpad + * + * @param toolpad + */ + void MosaicTool::addTo (Qisis::ToolPad *toolpad) { + p_toolPadAction = toolPadAction(toolpad); + if (p_toolPadAction != NULL) { + toolpad->addAction(p_toolPadAction); + connect (p_toolPadAction,SIGNAL(toggled(bool)),this,SLOT(activate(bool))); + } + } + + + /** + * + * + * @param toolbar + */ + void MosaicTool::addToActive (QToolBar *toolbar) { + if (p_activeToolBarStack == NULL) { + p_activeToolBarStack = new QStackedWidget(toolbar); + toolbar->addWidget(p_activeToolBarStack); + } + + p_toolBarWidget = createToolBarWidget(p_activeToolBarStack); + if (p_toolBarWidget != NULL) { + p_activeToolBarStack->addWidget(p_toolBarWidget); + } + disableToolBar(); + } + + + /** + * Activates the tool. + * + * @param on + */ + void MosaicTool::activate (bool on) { + if (p_active) { + if (on) return; + disableToolBar(); + if (p_toolPadAction != NULL) p_toolPadAction->setChecked(false); + p_active = false; + } + else { + if (!on) return; + if (p_toolPadAction != NULL) p_toolPadAction->setChecked(true); + enableToolBar(); + p_active = true; + } + //----------------------------------------------------- + // Let the tools know when they have been activated or + // de-activated. + //----------------------------------------------------- + emit activated(p_active); + } + + + /** + * Disables entire tool bar. + * + */ + void MosaicTool::disableToolBar() { + if (p_toolBarWidget == NULL) return; +// if (p_toolBarWidget->isVisible()) p_toolBarWidget->hide(); + p_toolBarWidget->setEnabled(false); + } + + + /** + * Enables entire tool bar. + * + */ + void MosaicTool::enableToolBar() { + if(p_toolBarWidget == NULL) return; + p_toolBarWidget->setEnabled(true); + p_activeToolBarStack->setCurrentWidget(p_toolBarWidget); + updateTool(); + } + + + /** + * This allows the programmer to access which widget created + * a tool, since the parent of this tool is a tool bar. + * + * + * @param widget + */ + void MosaicTool::setWidget(MosaicWidget *widget){ + p_widget = widget; + } + +} diff --git a/isis/src/qisis/objs/MosaicTool/MosaicTool.h b/isis/src/qisis/objs/MosaicTool/MosaicTool.h new file mode 100644 index 0000000000000000000000000000000000000000..d4925292a38fdd058b525be4afc03ae1c953bb8f --- /dev/null +++ b/isis/src/qisis/objs/MosaicTool/MosaicTool.h @@ -0,0 +1,185 @@ +#ifndef Qisis_MosaicTool_h +#define Qisis_MosaicTool_h + +#include +#include +#include +#include +#include + +#include "ToolPad.h" +#include "MosaicMainWindow.h" + +namespace Qisis { + /** + * @brief Base class for the MosaicTools + * + * @ingroup Visualization Tools + * + * @author Stacy Alley + * + * @internal + */ + + class MosaicTool : public QObject { + Q_OBJECT + + public: + MosaicTool (QWidget *parent); + void addTo (Qisis::ToolPad *toolpad); + virtual void rubberBandComplete(QRect r){}; + + + /** + * Returns the activeness of this toool + * + * + * @return bool + */ + bool isActive() const { return p_active; }; + + /** + * requires the programmer to have this member + * + * @param menu + */ + virtual void addTo (QMenu *menu) {}; + + + /** + * requires the programmer to have this member + * + * @param toolbar + */ + virtual void addToPermanent (QToolBar *toolbar) {}; + + void addToActive (QToolBar *toolbar); + + /** + * requires the programmer to have this member + * + * @param mmw + */ + virtual void addTo (MosaicMainWindow *mmw); + + + /** + * returns the path to the icon directory. + * + * + * @return QString + */ + QString toolIconDir () const { return p_toolIconDir; }; + + void setGraphicsView(QGraphicsView *view) {p_graphicsView = view; }; + QGraphicsView *getGraphicsView() { return p_graphicsView; }; + + void setWidget(MosaicWidget *widget); + MosaicWidget *getWidget() { return p_widget; }; + + virtual void updateTool(){}; + + signals: + void activated(bool); + + public slots: + void activate (bool); + + protected slots: + /** + * requires the programmer to have this member + * + */ + virtual void mouseEnter() {}; + + + /** + * requires the programmer to have this member + * + * @param p + */ + virtual void mouseMove(QPoint p) {}; + + + /** + * requires the programmer to have this member + * + */ + virtual void mouseLeave() {}; + + + /** + * requires the programmer to have this member + * + * @param p + */ + virtual void mouseDoubleClick(QPoint p) {}; + + + /** + * requires the programmer to have this member + * + * @param p + * @param s + */ + virtual void mouseButtonPress(QPoint p, Qt::MouseButton s) {}; + + + /** + * requires the programmer to have this member + * + * @param p + * @param s + */ + virtual void mouseButtonRelease(QPoint p, Qt::MouseButton s) {}; + + signals: + + + protected: + + /** + * Anytime a tool is created, you must setup a tool pad action with it. + * + * @param toolpad + * + * @return QAction* + */ + virtual QAction *toolPadAction (ToolPad *toolpad) { return NULL; }; + + + /** + * Anytime a tool is created, you must give it a name for the + * menu. + * + * @return QString + */ + virtual QString menuName () const { return ""; }; + + + /** + * Anytime a tool is created, you must add it to the tool bar. + * + * @param parent + * + * @return QWidget* + */ + virtual QWidget *createToolBarWidget (QStackedWidget *parent) { return NULL; }; + + private: + void enableToolBar (); + void disableToolBar(); + + bool p_active; //!< Is the tool acitve? + QWidget *p_toolBarWidget; //!< The tool bar on which this tool resides. + QAction *p_toolPadAction; //!< The tool pad on which this tool resides. + + QString p_toolIconDir; //!< The pathway to the icon directory. + + static QStackedWidget *p_activeToolBarStack; //!< Active tool bars + QGraphicsView *p_graphicsView; + MosaicWidget *p_widget; + }; +}; + +#endif diff --git a/isis/src/qisis/objs/MosaicTrackTool/Makefile b/isis/src/qisis/objs/MosaicTrackTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MosaicTrackTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MosaicTrackTool/MosaicTrackTool.cpp b/isis/src/qisis/objs/MosaicTrackTool/MosaicTrackTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b07f40d19dbcd193231b01de3a095fc1a390ab98 --- /dev/null +++ b/isis/src/qisis/objs/MosaicTrackTool/MosaicTrackTool.cpp @@ -0,0 +1,104 @@ +#include "MosaicTrackTool.h" + +namespace Qisis { + /** + * MosaicTrackTool constructor + * + * + * @param parent + */ + MosaicTrackTool::MosaicTrackTool (QStatusBar *parent) : Qisis::MosaicTool(parent) { + p_sbar = parent; + + p_latLabel = new QLabel(p_sbar); + p_latLabel->setText("W 999999"); + p_latLabel->setMinimumSize(p_latLabel->sizeHint()); + p_latLabel->setToolTip("Latitude"); + p_sbar->addPermanentWidget(p_latLabel); + + p_lonLabel = new QLabel(p_sbar); + p_lonLabel->setText("W 999999"); + p_lonLabel->setMinimumSize(p_lonLabel->sizeHint()); + p_lonLabel->setToolTip("Longitude"); + p_sbar->addPermanentWidget(p_lonLabel); + + clearLabels(); + + activate(true); + } + + + /** + * Updates the labels anytime the mouse moves. + * SLA - does nothing right now. it's not even called + * when the mosue moves. + * + * @param p + */ + void MosaicTrackTool::mouseMove(QPoint p) { + } + + + /** + * Clears the labels if the mouse leaves the application. + * + */ + void MosaicTrackTool::mouseLeave() { + } + + + /** + * Updates the tracking labels. + * Displays the Planetocentric Latitude and 360 Positive East + * Longitude in the lower right corner of the window. + * + * + * @param p + */ + void MosaicTrackTool::updateLabels (QPointF p) { + bool inChildItem = false; + //---------------------------------------------------------------------- + // we need to find out if the point given is over an item, if not, call + // clearLables() if so, then we need to get the item and figure out the + // lat/lon that corresponds with the given point. + //---------------------------------------------------------------------- + QList items = getWidget()->mosaicItems(); + for(int i = 0; i < items.size(); i++) { + //if(inChildItem) break; + if(items[i]->contains(p)) { + // now we need to get the translation from screen coords. to lat/lon. + QPointF groundPoints = items[i]->screenToGround(p); + p_lonLabel->setText("LON " + QString::number(groundPoints.y())); + p_latLabel->setText("LAT " + QString::number(groundPoints.x())); + break; + } else { + QListchildren = items[i]->children(); + for(int j= 0; j < children.size(); j++) { + if(children[j]->contains(p)){ + QPointF groundPoints = items[i]->screenToGround(p); + p_lonLabel->setText("LON " + QString::number(groundPoints.y())); + p_latLabel->setText("LAT " + QString::number(groundPoints.x())); + inChildItem = true; + break; + } + } + } + if(inChildItem) break; + clearLabels(); + } + } + + + /** + * Clears the labels. + * + */ + void MosaicTrackTool::clearLabels () { + p_lonLabel->setText("LON n/a"); + p_latLabel->setText("LAT n/a"); + + } + +} + + diff --git a/isis/src/qisis/objs/MosaicTrackTool/MosaicTrackTool.h b/isis/src/qisis/objs/MosaicTrackTool/MosaicTrackTool.h new file mode 100644 index 0000000000000000000000000000000000000000..e27f54a6c434adaf685f4e3ec8a1daed143ee2c2 --- /dev/null +++ b/isis/src/qisis/objs/MosaicTrackTool/MosaicTrackTool.h @@ -0,0 +1,32 @@ +#ifndef Qisis_MosaicTrackTool_h +#define Qisis_MosaicTrackTool_h + +#include "MosaicTool.h" + +class QLabel; +class QStatusBar; + +namespace Qisis { + class MosaicTrackTool : public Qisis::MosaicTool { + Q_OBJECT + + public: + MosaicTrackTool (QStatusBar *parent); + void updateLabels(QPointF p); + + public slots: + virtual void mouseMove(QPoint p); + virtual void mouseLeave(); + + private: + + void clearLabels(); + QStatusBar *p_sbar; //!< Status bar + QLabel *p_latLabel; //!< Latitude label + QLabel *p_lonLabel; //!< Longitude label + MosaicWidget *p_parentWidget; + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/MosaicTreeWidget/Makefile b/isis/src/qisis/objs/MosaicTreeWidget/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MosaicTreeWidget/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MosaicTreeWidget/MosaicTreeWidget.cpp b/isis/src/qisis/objs/MosaicTreeWidget/MosaicTreeWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30baf83bd5e83287a79f93bd6bb6b2a81a4336b9 --- /dev/null +++ b/isis/src/qisis/objs/MosaicTreeWidget/MosaicTreeWidget.cpp @@ -0,0 +1,28 @@ +#include + +#include "MosaicTreeWidget.h" +#include "MosaicMainWindow.h" + +namespace Qisis { + + /** + * MosaicTreeWidget constructor. + * MosaicTreeWidget is derived from QTreeWidget + * + * + * @param parent + */ + MosaicTreeWidget::MosaicTreeWidget (QWidget *parent) : QTreeWidget(parent) { + + } + + /** + * This is why we needed to subclass the QTreeWidget class. + * We needed our own dropEvent for the dragging and dropping + * of the tree widget items. + */ + void MosaicTreeWidget::dropEvent(QDropEvent *event) { + emit itemDropped(event->pos()); + } + +} diff --git a/isis/src/qisis/objs/MosaicTreeWidget/MosaicTreeWidget.h b/isis/src/qisis/objs/MosaicTreeWidget/MosaicTreeWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..65e481aa30d88bffae10a41286f60e466d90d2af --- /dev/null +++ b/isis/src/qisis/objs/MosaicTreeWidget/MosaicTreeWidget.h @@ -0,0 +1,32 @@ +#ifndef MosaicTreeWidget_H +#define MosaicTreeWidget_H + +#include + +namespace Qisis { + + class MosaicTreeWidget : public QTreeWidget { + Q_OBJECT + + public: + MosaicTreeWidget(QWidget *parent = 0); + + public slots: + + signals: + void itemDropped(QPoint point); + + protected: + void dropEvent(QDropEvent *event); + //QMimeData *mimeData(const QList items) const; + //QStringList mimeTypes() const; + + private slots: + + + private: + + }; +}; + +#endif diff --git a/isis/src/qisis/objs/MosaicWidget/Makefile b/isis/src/qisis/objs/MosaicWidget/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MosaicWidget/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MosaicWidget/MosaicWidget.cpp b/isis/src/qisis/objs/MosaicWidget/MosaicWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46949eaccef693435c58fbf34450e737bbfa3cdb --- /dev/null +++ b/isis/src/qisis/objs/MosaicWidget/MosaicWidget.cpp @@ -0,0 +1,2807 @@ +#include +#include +#include +#include + +#include "MosaicWidget.h" +#include "MosaicItem.h" +#include "MosaicMainWindow.h" +#include "FileDialog.h" +#include "MosaicZoomTool.h" +#include "MosaicPanTool.h" +#include "MosaicSelectTool.h" +#include "MosaicTrackTool.h" +#include "MosaicPointTool.h" +#include "MosaicControlNetTool.h" +#include "MosaicFindTool.h" + +#include "Pvl.h" +#include "PvlGroup.h" +#include "ControlGraph.h" +#include "iString.h" + + +namespace Qisis { + + /** + * MosaicWidget constructor. + * MosaicWidget is derived from QSplitter, the left side of the + * splitter is a QTreeWidget and the right side of the splitter + * is a QGraphicsView. + * + * + * @param parent + */ + MosaicWidget::MosaicWidget (QWidget *parent) : QSplitter(Qt::Horizontal, parent) { + + p_projection = 0; + p_insertItemAt = -1; + p_parent = (MosaicMainWindow *)parent; + p_textItem = NULL; + p_rubberBand = NULL; + p_cn = NULL; + p_footprintItem = new QGraphicsPolygonItem(); + p_footprintItem->hide(); + + QFont font("Helvetica", 10, QFont::Normal); + setFont(font); + installEventFilter(this); + initWidget(); + } + + /** + * Initializes all the parts required for the MosaicWidget. + * + */ + void MosaicWidget::initWidget(){ + + p_mapFileButton = new QToolButton(); + p_mapFileButton->setToolTip("Select Map File"); + p_mapFileButton->setText("Select Map File"); + p_mapFileButton->setIcon(QPixmap + (QString::fromStdString(Isis::Filename("$base/icons").Expanded().c_str()) + "/mIconProjectionEnabled.png")); + p_parent->permanentToolBar()->addWidget(p_mapFileButton); + connect(p_mapFileButton, SIGNAL(pressed()), this, SLOT(setMapFile())); + + p_mapDisplay = new QLabel(p_parent); + p_mapDisplay->setText("Select a map file."); + p_parent->permanentToolBar()->addWidget(p_mapDisplay); + + p_parent->permanentToolBar()->addSeparator(); + + p_controlPointButton = new QToolButton(); + p_controlPointButton->setToolTip("Display Control Points"); + p_controlPointButton->setCheckable(true); + p_controlPointButton->setIcon(QPixmap + (QString::fromStdString(Isis::Filename("$base/icons").Expanded().c_str()) + "/HILLBLU_molecola.png")); + //p_parent->permanentToolBar()->addWidget(p_controlPointButton); + //connect(p_controlPointButton, SIGNAL(pressed()), this, SLOT(displayControlPoints())); + + p_connectivityButton = new QToolButton(); + p_connectivityButton->setToolTip("Display Network Connectivity"); + p_connectivityButton->setCheckable(true); + //p_parent->permanentToolBar()->addWidget(p_connectivityButton); + //connect(p_connectivityButton, SIGNAL(pressed()), this, SLOT(displayConnectivity())); + + p_treeWidget = new MosaicTreeWidget(this); + connect(p_treeWidget, SIGNAL(itemDropped(QPoint)), this, SLOT(dropAction(QPoint))); + //connect(p_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(itemChanged(QTreeWidgetItem *, int))); + connect(p_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(groupChanged(QTreeWidgetItem *, int))); + p_treeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); + p_treeWidget->setDragDropMode(QAbstractItemView::InternalMove); + p_treeWidget->setDragDropOverwriteMode(false); + p_treeWidget->setColumnCount(6); + p_treeWidget->installEventFilter(this); + + p_graphicsScene = new QGraphicsScene(this); + p_graphicsScene->installEventFilter(this); + p_graphicsView = new QGraphicsView(p_graphicsScene, this); + p_graphicsView->setScene(p_graphicsScene); + p_graphicsView->setContextMenuPolicy(Qt::NoContextMenu); + p_graphicsView->setOptimizationFlag(QGraphicsView::DontSavePainterState, true); + p_graphicsView->setInteractive(true); + + addWidget(p_treeWidget); + addWidget(p_graphicsView); + + QSizePolicy treePolicy = p_treeWidget->sizePolicy(); + treePolicy.setHorizontalStretch(2); + p_treeWidget->setSizePolicy(treePolicy); + QSizePolicy graphicsViewPolicy = p_graphicsView->sizePolicy(); + graphicsViewPolicy.setHorizontalStretch(255); + p_graphicsView->setSizePolicy(graphicsViewPolicy); + + addGroup("Group1"); + + QStringList header; + header << "Name" << "Item" << "Footprint" << "Outline" << "Image" + << "Label" << "Resolution"<< "Emission Angle" + << "Incidence Angle" << "Island" << "Notes"; + p_treeWidget->setHeaderLabels(header); + p_treeWidget->setColumnWidth(NameColumn,160); //Name + p_treeWidget->setColumnWidth(ItemColumn,35); //Item + p_treeWidget->setColumnWidth(FootprintColumn,60); //Footprint + p_treeWidget->setColumnWidth(OutlineColumn,50); //Outline + p_treeWidget->setColumnWidth(ImageColumn,45); //Image + p_treeWidget->setColumnWidth(LabelColumn,40); //Label + p_treeWidget->setColumnWidth(ResolutionColumn,70); //Resolution + p_treeWidget->setColumnWidth(EmissionColumn,100); //Emission Angle + p_treeWidget->setColumnWidth(IncidenceColumn,110); //Incidence Angle + p_treeWidget->setColumnWidth(IslandColumn,45); //Island Number + + p_xmin = DBL_MAX; + p_xmax = -DBL_MAX; + p_ymin = DBL_MAX; + p_ymax = -DBL_MAX; + + //Adding the select tool + p_stool = new MosaicSelectTool(this); + p_stool->setGraphicsView(p_graphicsView); + p_stool->addTo(p_parent); + p_stool->activate(true); + + //Adding the zoom tool. + p_ztool = new MosaicZoomTool(this); + p_ztool->setGraphicsView(p_graphicsView); + p_ztool->addTo(p_parent); + + //Adding the pan tool. + p_ptool = new MosaicPanTool(this); + p_ptool->setGraphicsView(p_graphicsView); + p_ptool->addTo(p_parent); + + //Adding the track tool. + p_ttool = new MosaicTrackTool(p_parent->statusBar()); + p_ttool->setGraphicsView(p_graphicsView); + p_ttool->setWidget(this); + p_ttool->addTo(p_parent); + + //Adding the point tool. + p_pntool = new MosaicPointTool(this); + p_pntool->setGraphicsView(p_graphicsView); + p_pntool->setWidget(this); + p_pntool->addTo(p_parent); + + //Adding the control net tool. + p_cntool = new MosaicControlNetTool(this); + p_cntool->setGraphicsView(p_graphicsView); + p_cntool->setWidget(this); + p_cntool->addTo(p_parent); + + //Adding the find tool. + p_ftool = new MosaicFindTool(this); + p_ftool->setGraphicsView(p_graphicsView); + p_ftool->setWidget(this); + p_ftool->addTo(p_parent); + + connect(p_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), + this, SLOT(updateGraphicsView(QTreeWidgetItem *, int))); + + connect(p_treeWidget, SIGNAL(itemSelectionChanged()), + this, SLOT(updateGraphicsView())); + + connect(p_graphicsScene, SIGNAL(selectionChanged()), + this, SLOT(updateTreeWidget())); + + //------------------------------------------------------ + // This sets up the columns the user wants visible + // in the tree widget. These settings were remembered + // from the last time the user ran qmos. + //------------------------------------------------------ + QMenu *viewMenu = p_parent->viewMenu(); + QList actions = viewMenu->actions(); + for(int i = 0; i < actions.size(); i++) { + viewMenuAction(actions[i]); + } + } + + + /** + * Adds a new Top Level Item to the tree widget. + * + * @param groupName + */ + void MosaicWidget::addGroup(const QString &groupName){ + //Test to see if we already have a group with the same name + if(p_groupToTreeMap.contains(groupName)) return; + + QTreeWidgetItem *group = new QTreeWidgetItem(); + group->setText(0, groupName); + p_treeWidget->addTopLevelItem(group); + group->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); + group->setExpanded(true); + p_groupToTreeMap.insert(groupName, group); + } + + + /** + * Adds a new topLevelItem to the tree widget + * + */ + void MosaicWidget::addGroup(){ + QString newGroupName("Group" + QString::number(p_treeWidget->topLevelItemCount()+1)); + addGroup(newGroupName); + } + + /** + * Deletes the group with the name passed in as 'groupName'. + * + * @param groupName + */ + void MosaicWidget::deleteGroup(const QString &groupName){ + QList groupItems = p_treeWidget->findItems(groupName, Qt::MatchExactly); + if(groupItems.size() == 0)return; + QTreeWidgetItem *group = groupItems.last(); + for(int j = 0; j < group->childCount(); j++) { + int childIndex = group->indexOfChild(group->child(j)); + group->takeChild(childIndex); + } + int index = p_treeWidget->indexOfTopLevelItem(group); + p_treeWidget->takeTopLevelItem(index); + p_groupToTreeMap.erase(p_groupToTreeMap.find(groupName)); + + } + + + /** + * Gets rid of an entire group and it's items, then will + * refit the remaining items to the graphics scene. + */ + void MosaicWidget::deleteGroup(){ + QList groupItems = selectedGroups(); + hideItem(); + if(groupItems.isEmpty()) return; + for(int i = 0; i < groupItems.size(); i++) { + QTreeWidgetItem *currentGroup = groupItems[i]; + for(int j = 0; j < currentGroup->childCount(); j++) { + int childIndex = currentGroup->indexOfChild(currentGroup->child(j)); + currentGroup->takeChild(childIndex); + } + int index = p_treeWidget->indexOfTopLevelItem(currentGroup); + p_treeWidget->takeTopLevelItem(index); + p_groupToTreeMap.erase(p_groupToTreeMap.find(currentGroup->text(0))); + } + refit(); + } + + + /** + * Adds the mosaicItem to the graphicsScene. + * + * @param mosaicItem + * @param groupName + */ + void MosaicWidget::addItem(MosaicItem *mosaicItem, QString groupName){ + // check if this mosaicItem has already been added to the scene. + for(int i = 0; i < p_mosaicItems.size(); i++) { + + if(mosaicItem->filename() == p_mosaicItems[i]->filename()&& !p_pasteItems.contains(mosaicItem)) { + std::cout << "WARNING: This cube is already in the scene!" << std::endl; + return; + } + } + + // If the groupName does not already exist then add it. + if(!p_groupToTreeMap.contains(groupName)) { + addGroup(groupName); + } + + // Get the x/y min/max of the item so the numbers can be used in fitInView + if(mosaicItem->XMinimum() < p_xmin) p_xmin = mosaicItem->XMinimum(); + if(mosaicItem->YMinimum() < p_ymin) p_ymin = mosaicItem->YMinimum(); + if(mosaicItem->XMaximum() > p_xmax) p_xmax = mosaicItem->XMaximum(); + if(mosaicItem->YMaximum() > p_ymax) p_ymax = mosaicItem->YMaximum(); + + QTreeWidgetItem *groupItem = p_groupToTreeMap[groupName]; + if(p_insertItemAt == -1) { + groupItem->addChild(mosaicItem->treeItem()); + mosaicItem->treeItem()->setText(ResolutionColumn, QString::number(mosaicItem->pixelResolution())); + mosaicItem->treeItem()->setText(EmissionColumn, QString::number(mosaicItem->emissionAngle())); + mosaicItem->treeItem()->setText(IncidenceColumn, QString::number(mosaicItem->incidenceAngle())); + } else{ + groupItem->insertChild(p_insertItemAt, mosaicItem->treeItem()); + mosaicItem->treeItem()->setText(ResolutionColumn, QString::number(mosaicItem->pixelResolution())); + mosaicItem->treeItem()->setText(EmissionColumn, QString::number(mosaicItem->emissionAngle())); + mosaicItem->treeItem()->setText(IncidenceColumn, QString::number(mosaicItem->incidenceAngle())); + } + p_treeToMosaicMap.insert(mosaicItem->treeItem(), mosaicItem); + mosaicItem->setZValue(-FLT_MAX); + setInitialZValue(groupItem); + p_graphicsScene->addItem(mosaicItem); + if(mosaicItem->children().size() > 0) { + mosaicItem->children().first()->installSceneEventFilter(mosaicItem); + mosaicItem->installSceneEventFilter(mosaicItem->children().first()); + } + + //-------------------------------------------------------------------------- + // Everytime we add an item we want to make sure everything fits in the view + // Unless we are cutting and pasting. + //-------------------------------------------------------------------------- + if(p_pasteItems.size() < 1) + p_graphicsView->fitInView(p_xmin-5, p_ymin-5, (p_xmax-p_xmin)+5, (p_ymax-p_ymin)+5, Qt::KeepAspectRatio); + + // If this items is not already in our list, then we need to add it. + if(!p_mosaicItems.contains(mosaicItem)){ + if(p_insertItemAt == -1) { + p_mosaicItems.push_back(mosaicItem); + } else { + p_mosaicItems.insert(p_insertItemAt, mosaicItem); + } + } + + // reset p_insertItemAt + p_insertItemAt = -1; + + // display the screen resolution in the zoom tool's p_scaleBox + p_screenResolution = p_graphicsScene->width()/p_graphicsView->viewport()->width(); + if(p_ztool->isActive()) { + p_ztool->updateResolutionBox(); + } + + //----------------------------------------------------------------------- + // if this item has some control points in it from the control net, and + // the points are visible, then we need to make sure they get displayed. + //----------------------------------------------------------------------- + if(p_cn != NULL) { + if(p_controlPointButton->isChecked()){ + mosaicItem->displayControlPoints(p_cn); + } + } + + //if(p_showReference->checkState() == Qt::Checked) { + // if(!p_graphicsScene->items().contains(p_footprintItem)) { + // createReferenceFootprint(); + //} + //} + + return; + //TODO: Throw error if group not found. + } + + + /** + * This is an overloaded method for the one above. + * This is called from the open method. + * + * @param itemName + */ + void MosaicWidget::addItem(QString itemName){ + Qisis::MosaicItem *mosItem = new Qisis::MosaicItem(itemName, this); + // If a group was not selected, just add the item to the bottom group. + if(selectedGroups().isEmpty()) { + int numGroups = p_treeWidget->topLevelItemCount(); + addItem(mosItem, p_treeWidget->topLevelItem(numGroups -1)->text(0)); + } else { + addItem(mosItem, selectedGroups().first()->text(0)); + } + } + + + /** + * This method creates the reference footprint if defined in the map file. + * + */ + void MosaicWidget::createReferenceFootprint(){ + double x = 0; + double y = 0; + + QVector footprintPoints; + QPolygonF footprintPoly; + + // need to create a polygon from the min/max lat/long numbers in the map file. + try{ + Isis::Pvl pvl; + pvl.Read(p_mapfile.toStdString()); + Isis::PvlKeyword minLatKeyword = pvl.FindKeyword("MinimumLatitude", Isis::Pvl::Traverse); + QString minLat = QString::fromStdString(minLatKeyword[0]); + Isis::PvlKeyword minLongKeyword = pvl.FindKeyword("MinimumLongitude", Isis::Pvl::Traverse); + QString minLon = QString::fromStdString(minLongKeyword[0]); + Isis::PvlKeyword maxLatKeyword = pvl.FindKeyword("MaximumLatitude", Isis::Pvl::Traverse); + QString maxLat = QString::fromStdString(maxLatKeyword[0]); + Isis::PvlKeyword maxLongKeyword = pvl.FindKeyword("MaximumLongitude", Isis::Pvl::Traverse); + QString maxLon = QString::fromStdString(maxLongKeyword[0]); + + if(p_projection->SetUniversalGround(minLat.toDouble(), minLon.toDouble())) { + x = p_projection->XCoord(); + y = -1 *(p_projection->YCoord()); + footprintPoints.push_back(QPointF(x,y)); + } + + for(double lat = minLat.toDouble()+1; lat < maxLat.toDouble(); lat++) { + if(p_projection->SetUniversalGround(lat, minLon.toDouble())) { + x = p_projection->XCoord(); + y = -1 *(p_projection->YCoord()); + footprintPoints.push_back(QPointF(x,y)); + } + } + for(double lon = minLon.toDouble()+1; lon < maxLon.toDouble(); lon++) { + if(p_projection->SetUniversalGround(maxLat.toDouble(), lon)) { + x = p_projection->XCoord(); + y = -1 *(p_projection->YCoord()); + footprintPoints.push_back(QPointF(x,y)); + } + } + for(double lat = maxLat.toDouble(); lat > minLat.toDouble()+1; lat--) { + if(p_projection->SetUniversalGround(lat, maxLon.toDouble())) { + x = p_projection->XCoord(); + y = -1 *(p_projection->YCoord()); + footprintPoints.push_back(QPointF(x,y)); + } + } + for(double lon = maxLon.toDouble(); lon > minLon.toDouble()+1; lon--) { + if(p_projection->SetUniversalGround(minLat.toDouble(), lon)) { + x = p_projection->XCoord(); + y = -1 *(p_projection->YCoord()); + footprintPoints.push_back(QPointF(x,y)); + } + } + + //Now close the polygon. + if(p_projection->SetUniversalGround(minLat.toDouble(), minLon.toDouble())) { + x = p_projection->XCoord(); + y = -1 *(p_projection->YCoord()); + footprintPoints.push_back(QPointF(x,y)); + } + footprintPoly = QPolygonF(footprintPoints); + p_footprintItem->setPolygon(footprintPoly); + p_footprintItem->setBrush(QBrush(QColor(255,255,0,100))); + p_footprintItem->setPen(QColor(Qt::black)); + p_footprintItem->setZValue(-FLT_MAX); + p_footprintItem->setFlag(QGraphicsItem::ItemIsSelectable, false); + p_graphicsScene->addItem(p_footprintItem); + //p_graphicsView->fitInView(p_footprintItem, Qt::KeepAspectRatio); + p_footprintItem->show(); + + }catch(Isis::iException &e){ + std::string msg = e.Errors(); + QMessageBox::information(this, "Error", QString::fromStdString(msg), QMessageBox::Ok); + //p_showReference->setChecked(Qt::Unchecked); + return; + } + } + + + /** + * hides or shows the reference footprint + * + */ + void MosaicWidget::setReferenceItemVisible(bool show){ + if(show) { + if(!p_graphicsScene->items().contains(p_footprintItem)) { + createReferenceFootprint(); + } else { + p_footprintItem->show(); + } + } else { + p_footprintItem->hide(); + } + } + + + /** + * This method assigns the initial zValue to a mosaic item + * which is determined by it's child index number in it's parent + * group. + * + * @param groupItem + */ + void MosaicWidget::setInitialZValue(QTreeWidgetItem *groupItem){ + int index = p_treeWidget->indexOfTopLevelItem(groupItem)*-10000; + MosaicItem *mosItem; + + for(int i = 0; i < groupItem->childCount(); i++) { + mosItem = p_treeToMosaicMap[groupItem->child(i)]; + if(mosItem->zValue() == -FLT_MAX) { + mosItem->setZValue(index - i); + } + } + } + + + /** + * When a treeWidget item is moved to a new position on the + * tree, the zValue for that items is set to -FLT_MAX. This + * method assigns the correct new zValue to the item. + * + * @param groupItem + */ + void MosaicWidget::fixZValue(QTreeWidgetItem *groupItem){ + if(groupItem->childCount() < 2) return; + qreal zValue = -FLT_MAX; + + MosaicItem *mosItem; + qreal topZValue = -FLT_MAX; + qreal bottomZValue = -FLT_MAX; + for(int i = 0; i < groupItem->childCount(); i++) { + mosItem = p_treeToMosaicMap[groupItem->child(i)]; + + if(mosItem->zValue() == -FLT_MAX) { + + // Check to see if mosItem is at the top + if(mosItem == p_treeToMosaicMap[groupItem->child(0)]) { + zValue = p_treeToMosaicMap[groupItem->child(1)]->zValue() + 1; + } + // Check to see if the mosItem is at the bottom + else if(mosItem == p_treeToMosaicMap[groupItem->child(groupItem->childCount()-1)]) { + zValue = p_treeToMosaicMap[groupItem->child(groupItem->childCount()-2)]->zValue() - 1; + } + else{ + //------------------------------------------------------------- + // mosItem is not the top item OR the bottom item. + // get the zvalue of the item above and the item below this one + //------------------------------------------------------------- + if( i > 0) { + topZValue = p_treeToMosaicMap[groupItem->child(i-1)]->zValue(); + } + if( i < groupItem->childCount()-1) { + bottomZValue = p_treeToMosaicMap[groupItem->child(i+1)]->zValue(); + } + zValue = (topZValue + bottomZValue) / 2; + } + + //TODO: check to see if the zValue is within the range of the zValues of + // the previous or next group. IF so, then call reorderAllZValues. + + if(zValue != -FLT_MAX) mosItem->setZValue(zValue); + }// end if mosItem->zValue == -FLT_MAX + } + } + + + /** + * This is a slot connected to the tree widgets signal + * "itemChanged(QTreeWidgetItem *, int)" + * Sets the mosaicItem visible or not depending on the tree + * widget item's check state. + * + * @param item + * @param column + */ + void MosaicWidget::updateGraphicsView(QTreeWidgetItem *item, int column){ + if(!p_treeToMosaicMap.contains(item)) return; + + if(column == 1) { + p_treeToMosaicMap[item]->setItemVisible( + (item->checkState(column) == Qt::Checked)?true:false); + p_treeToMosaicMap[item]->setSelected( + (item->checkState(column) == Qt::Checked)?true:false); + } + + if(column == FootprintColumn || + column == OutlineColumn || + column == ImageColumn || + column == LabelColumn ){ + updateGraphicsView(); + p_treeToMosaicMap[item]->update(); + } + + } + + + /** + * This is a slot connected to the tree widget's signal + * "itemSelectionChanged()" + * + */ + void MosaicWidget::updateGraphicsView(){ + //----------------------------------------------------- + // We must disconnect the signals of the graphics scene + // to avoid getting into an endless loop + //----------------------------------------------------- + disconnect(p_graphicsScene, SIGNAL(selectionChanged()), + this, SLOT(updateTreeWidget())); + p_graphicsScene->clearSelection(); + for(int i = 0; i < p_mosaicItems.size(); i++) { + if((!p_mosaicItems[i]->isSelected() && p_mosaicItems[i]->isTreeItemSelected()) || + (p_mosaicItems[i]->isSelected() && !p_mosaicItems[i]->isTreeItemSelected())) { + p_mosaicItems[i]->setSelected(p_mosaicItems[i]->isTreeItemSelected()); + } + } + // Re-connect the graphics scene + connect(p_graphicsScene, SIGNAL(selectionChanged()), + this, SLOT(updateTreeWidget())); + } + + + /** + * This is a slot connect to the graphics scene's signal + * "selectionChanged()" + * + */ + void MosaicWidget::updateTreeWidget(){ + //------------------------------------------------- + // We must disconnect the signals of the tree widget + // to avoid getting into an endless loop + //------------------------------------------------ + disconnect(p_treeWidget, SIGNAL(itemSelectionChanged()), + this, SLOT(updateGraphicsView())); + + p_treeWidget->clearSelection(); + for(int i = 0; i < p_mosaicItems.size(); i++) { + p_mosaicItems[i]->setTreeItemSelected(p_mosaicItems[i]->isSelected()); + } + // Re-connect the tree widget + connect(p_treeWidget, SIGNAL(itemSelectionChanged()), + this, SLOT(updateGraphicsView())); + } + + + /** + * This method determines which menu action items should be + * displayed on the menu depending on what the user right + * clicked on the obtain the context menu. + * + * @return QMenu + */ + QMenu* MosaicWidget::contextMenu() { + static QMenu *mainContextMenu = 0; + static QMenu *sortMenu; + static QAction *insertCube; + static QAction *insertList; + static QAction *deleteCube; + static QAction *addGroup; + static QAction *mergeGroups; + static QAction *deleteGroup; + static QAction *renameGroup; + static QAction *toFront; + static QAction *sendBack; + static QAction *moveUpOne; + static QAction *moveDownOne; + static QAction *changeColor; + static QAction *changeTransparency; + static QAction *hideImageAction; + static QAction *showImageAction; + static QAction *hideItemAction; + static QAction *showItemAction; + static QAction *hideLabelAction; + static QAction *showLabelAction; + static QAction *hideOutlineAction; + static QAction *showOutlineAction; + static QAction *hideFootprintAction; + static QAction *showFootprintAction; + static QAction *zoomToItemAction; + static QAction *resolutionSort; + static QAction *emissionAngleSort; + static QAction *incidenceAngleSort; + static QAction *islandSort; + static QAction *cut; + static QAction *paste; + static QAction *setLabelFont; + + if(mainContextMenu == 0){ + insertCube = new QAction("Insert Cube", this); + connect(insertCube, SIGNAL(triggered()), + this, SLOT(insertCube())); + + insertList = new QAction("Import List", this); + connect(insertList, SIGNAL(triggered()), + this, SLOT(openList())); + + deleteCube = new QAction("Delete Cube", this); + deleteCube->setShortcut(Qt::Key_Delete); + connect(deleteCube, SIGNAL(triggered()), + this, SLOT(deleteCube())); + + resolutionSort = new QAction("Resolution", this); + connect(resolutionSort, SIGNAL(triggered()), + this, SLOT(sortByResolution())); + + emissionAngleSort = new QAction("Emission Angle", this); + connect(emissionAngleSort, SIGNAL(triggered()), + this, SLOT(sortByEmission())); + + incidenceAngleSort = new QAction("Incidence Angle", this); + connect(incidenceAngleSort, SIGNAL(triggered()), + this, SLOT(sortByIncidence())); + + islandSort = new QAction("Island", this); + connect(islandSort, SIGNAL(triggered()), + this, SLOT(sortByIsland())); + + addGroup = new QAction("Add Group", this); + connect(addGroup, SIGNAL(triggered()), + this, SLOT(addGroup())); + + mergeGroups = new QAction("Merge Groups", this); + connect(mergeGroups, SIGNAL(triggered()), + this, SLOT(mergeGroups())); + + deleteGroup = new QAction("Delete Group", this); + connect(deleteGroup, SIGNAL(triggered()), + this, SLOT(deleteGroup())); + + renameGroup = new QAction("Rename Group", this); + connect(renameGroup, SIGNAL(triggered()), + this, SLOT(renameGroup())); + + toFront = new QAction("Bring to Front", this); + connect(toFront, SIGNAL(triggered()), + this, SLOT(bringToFront())); + + sendBack = new QAction("Send to Back", this); + connect(sendBack, SIGNAL(triggered()), + this, SLOT(sendToBack())); + + moveUpOne = new QAction("Move Up One", this); + connect(moveUpOne, SIGNAL(triggered()), + this, SLOT(moveUpOne())); + + moveDownOne = new QAction("Move Down One", this); + connect(moveDownOne, SIGNAL(triggered()), + this, SLOT(moveDownOne())); + + changeColor = new QAction("Change Footprint Color/Opacity", this); + connect(changeColor, SIGNAL(triggered()), + this, SLOT(changeColor())); + + changeTransparency = new QAction("Change Image Opacity", this); + connect(changeTransparency, SIGNAL(triggered()), + this, SLOT(changeTransparency())); + + hideItemAction = new QAction("Hide Item(s)", this); + connect(hideItemAction, SIGNAL(triggered()), + this, SLOT(hideItem())); + + showItemAction = new QAction("Show Item(s)", this); + connect(showItemAction, SIGNAL(triggered()), + this, SLOT(showItem())); + + hideImageAction = new QAction("Hide Image(s)", this); + connect(hideImageAction, SIGNAL(triggered()), + this, SLOT(hideImage())); + + showImageAction = new QAction("Show Image(s)", this); + connect(showImageAction, SIGNAL(triggered()), + this, SLOT(showImage())); + + hideLabelAction = new QAction("Hide Label(s)", this); + connect(hideLabelAction, SIGNAL(triggered()), + this, SLOT(hideLabel())); + + showLabelAction = new QAction("Show Label(s)", this); + connect(showLabelAction, SIGNAL(triggered()), + this, SLOT(showLabel())); + + hideOutlineAction = new QAction("Hide Outline(s)", this); + connect(hideOutlineAction, SIGNAL(triggered()), + this, SLOT(hideOutline())); + + showOutlineAction = new QAction("Show Outline(s)", this); + connect(showOutlineAction, SIGNAL(triggered()), + this, SLOT(showOutline())); + + hideFootprintAction = new QAction("Hide Footprint(s)", this); + connect(hideFootprintAction, SIGNAL(triggered()), + this, SLOT(hideFootprint())); + + showFootprintAction = new QAction("Show Footprint(s)", this); + connect(showFootprintAction, SIGNAL(triggered()), + this, SLOT(showFootprint())); + + zoomToItemAction = new QAction("Zoom To Item", this); + connect(zoomToItemAction, SIGNAL(triggered()), + this, SLOT(zoomToItem())); + + cut = new QAction("Cut", this); + connect(cut, SIGNAL(triggered()), + this, SLOT(cut())); + + paste = new QAction("Paste", this); + connect(paste, SIGNAL(triggered()), + this, SLOT(paste())); + + setLabelFont = new QAction("Set Label Font", this); + connect(setLabelFont, SIGNAL(triggered()), + this, SLOT(setLabelFont())); + + mainContextMenu = new QMenu("Context Menu"); + sortMenu = new QMenu("Sort by:"); + + sortMenu->addAction(resolutionSort); + sortMenu->addAction(emissionAngleSort); + sortMenu->addAction(incidenceAngleSort); + sortMenu->addAction(islandSort); + + mainContextMenu->addAction(insertCube); + mainContextMenu->addAction(insertList); + mainContextMenu->addAction(deleteCube); + mainContextMenu->addAction(cut); + mainContextMenu->addAction(paste); + + mainContextMenu->addSeparator(); + + mainContextMenu->addAction(toFront); + mainContextMenu->addAction(sendBack); + mainContextMenu->addAction(moveUpOne); + mainContextMenu->addAction(moveDownOne); + mainContextMenu->addAction(zoomToItemAction); + + mainContextMenu->addSeparator(); + + mainContextMenu->addAction(changeColor); + mainContextMenu->addAction(changeTransparency); + mainContextMenu->addAction(hideItemAction); + mainContextMenu->addAction(showItemAction); + + mainContextMenu->addSeparator(); + + mainContextMenu->addAction(hideImageAction); + mainContextMenu->addAction(showImageAction); + + mainContextMenu->addSeparator(); + + mainContextMenu->addAction(hideFootprintAction); + mainContextMenu->addAction(showFootprintAction); + + mainContextMenu->addSeparator(); + + mainContextMenu->addAction(hideLabelAction); + mainContextMenu->addAction(showLabelAction); + + mainContextMenu->addSeparator(); + + mainContextMenu->addAction(setLabelFont); + + mainContextMenu->addSeparator(); + + mainContextMenu->addAction(hideOutlineAction); + mainContextMenu->addAction(showOutlineAction); + + mainContextMenu->addSeparator(); + + mainContextMenu->addMenu(sortMenu); + mainContextMenu->addAction(addGroup); + mainContextMenu->addAction(mergeGroups); + mainContextMenu->addAction(deleteGroup); + mainContextMenu->addAction(renameGroup); + } + + sortMenu->setEnabled(false); + addGroup->setEnabled(false); + mergeGroups->setEnabled(false); + deleteGroup->setEnabled(false); + renameGroup->setEnabled(false); + insertCube->setEnabled(false); + insertList->setEnabled(false); + deleteCube->setEnabled(false); + changeColor->setEnabled(false); + changeTransparency->setEnabled(false); + toFront->setEnabled(false); + sendBack->setEnabled(false); + moveUpOne->setEnabled(false); + moveDownOne->setEnabled(false); + zoomToItemAction->setEnabled(false); + hideItemAction->setEnabled(false); + showItemAction->setEnabled(false); + hideImageAction->setEnabled(false); + showImageAction->setEnabled(false); + hideLabelAction->setEnabled(false); + showLabelAction->setEnabled(false); + hideOutlineAction->setEnabled(false); + showOutlineAction->setEnabled(false); + hideFootprintAction->setEnabled(false); + showFootprintAction->setEnabled(false); + cut->setEnabled(false); + paste->setEnabled(false); + setLabelFont->setEnabled(false); + + // User has selected a group tree item + if(!selectedGroups().isEmpty()) { + addGroup->setEnabled(true); + if(selectedGroups().size() > 1) mergeGroups->setEnabled(true); + deleteGroup->setEnabled(true); + sortMenu->setEnabled(true); + insertCube->setEnabled(true); + insertList->setEnabled(true); + //if(selectedGroups().size() == 1) renameGroup->setEnabled(true); + renameGroup->setEnabled(true); + changeColor->setEnabled(true); + changeTransparency->setEnabled(true); + hideItemAction->setEnabled(true); + showItemAction->setEnabled(true); + hideImageAction->setEnabled(true); + showImageAction->setEnabled(true); + hideLabelAction->setEnabled(true); + showLabelAction->setEnabled(true); + hideOutlineAction->setEnabled(true); + showOutlineAction->setEnabled(true); + hideFootprintAction->setEnabled(true); + showFootprintAction->setEnabled(true); + setLabelFont->setEnabled(true); + // Only allow a paste option if there has been a cut performed. + if(p_pasteItems.size() > 0) paste->setEnabled(true); + } + + // User has selected a mosaic tree item + if(!selectedMosaicItems().isEmpty()) { + changeColor->setEnabled(true); + changeTransparency->setEnabled(true); + hideItemAction->setEnabled(true); + showItemAction->setEnabled(true); + hideImageAction->setEnabled(true); + showImageAction->setEnabled(true); + hideLabelAction->setEnabled(true); + showLabelAction->setEnabled(true); + hideOutlineAction->setEnabled(true); + showOutlineAction->setEnabled(true); + hideFootprintAction->setEnabled(true); + showFootprintAction->setEnabled(true); + deleteCube->setEnabled(true); + insertCube->setEnabled(true); + insertList->setEnabled(true); + cut->setEnabled(true); + setLabelFont->setEnabled(true); + } + + //--------------------------------------------------------------------- + // User has selected one and only one mosaic item or one and only one + // tree item. + //-------------------------------------------------------------------- + if((selectedMosaicItems().size() == 1 && selectedGroups().size() == 0) || + (selectedMosaicItems().size() == 0 && selectedGroups().size() == 1)){ + toFront->setEnabled(true); + sendBack->setEnabled(true); + moveUpOne->setEnabled(true); + moveDownOne->setEnabled(true); + if(selectedGroups().size() == 0) zoomToItemAction->setEnabled(true); + } + return mainContextMenu; + } + + + /** + * When a contextMenuEvent (right click) takes place on the + * widget, the context menu is popped up with the correct + * options depending on what widget the event took place. + * + * @param event + */ + void MosaicWidget::contextMenuEvent(QContextMenuEvent * event){ + if(p_ztool->isActive()) return; + + if(p_projection == NULL) { + p_textItem = p_graphicsScene->addText("Please select a map file first!"); + return; + } + // determine if the right click happened in the tree widget + if(p_treeWidget->rect().contains(p_treeWidget->mapFromGlobal(event->globalPos()))) { + contextMenu()->popup(event->globalPos()); + event->accept(); + } + + // determine if the right click happened in the graphics scene + if(p_graphicsView->rect().contains(p_graphicsView->mapFromGlobal(event->globalPos()))) { + QGraphicsItem *item = p_graphicsView->itemAt(p_graphicsView->mapFromGlobal(event->globalPos())); + p_treeWidget->clearSelection(); + if(item != 0){ + item->setSelected(true); + contextMenu()->popup(event->globalPos()); + } + event->accept(); + } + } + + + /** + * Hides the selected footprint and removes the filename from + * the tree widget. Then refit() fits the remaining footprints + * into the scene properly. + */ + void MosaicWidget::deleteCube(){ + QList mosaicItems = selectedMosaicItems(); + hideItem(); + for(int i = 0; i < mosaicItems.size(); i++) { + MosaicItem *item = mosaicItems[i]; + p_mosaicItems.removeAt(p_mosaicItems.indexOf(mosaicItems[i])); + QTreeWidgetItem *group = item->treeItem()->parent(); + if(group != 0) { + int index = group->indexOfChild(item->treeItem()); + group->takeChild(index); + } + } + } + + + /** + * Deletes all the mosaic items out of qmos. + * This is useful when the user opens a new project + * when there already mosaic items open. + */ + void MosaicWidget::deleteAllCubes(){ + if(p_mosaicItems.size() > 0){ + for(int i = 0; i < p_mosaicItems.size(); i++){ + p_mosaicItems[i]->setItemVisible(false); + QTreeWidgetItem *group = p_mosaicItems[i]->treeItem()->parent(); + if(group != 0) { + int index = group->indexOfChild(p_mosaicItems[i]->treeItem()); + group->takeChild(index); + p_treeWidget->takeTopLevelItem(p_treeWidget->indexOfTopLevelItem(group)); + p_groupToTreeMap.take(group->text(0)); + } + } + p_mosaicItems.clear(); + } + } + + + /** + * Allows the user to insert a cube in the order of their + * choice. + * + */ + void MosaicWidget::insertCube(){ + QList mosaicItems = selectedMosaicItems(); + QList groupItems = selectedGroups(); + if(!mosaicItems.isEmpty()){ + insertCube(selectedMosaicItems().first()); + } + else{ + open(); + } + } + + + /** + * Allows the user to insert a cube in the order of their + * choice. + * + * @param item + */ + void MosaicWidget::insertCube(MosaicItem *item){ + // calculate what to set p_insertItemAt; + int index = item->treeItem()->parent()->indexOfChild(item->treeItem()); + item->treeItem()->parent()->setSelected(true); + p_insertItemAt = index+1; + open(); + } + + + /** + * This method opens a cube + * + */ + void MosaicWidget::open(){ + if(p_projection == NULL) { + p_textItem = p_graphicsScene->addText("Please select a map file first!"); + return; + } + if(p_treeWidget->selectedItems().size() < 1) { + int numGroups = p_treeWidget->topLevelItemCount(); + p_treeWidget->topLevelItem(numGroups-1)->setSelected(true); + } + if(!p_filterList.contains("Isis cubes (*.cub)")) { + p_filterList.append("Isis cubes (*.cub)"); + } + p_filterList.append("All Files (*)"); + if(!p_dir.exists()) { + p_dir = QDir::current(); + } + + FileDialog *fileDialog = new FileDialog("Open", p_filterList, p_dir, + (QWidget *)parent()); + fileDialog->show(); + + connect (fileDialog,SIGNAL(fileSelected(QString)), + this,SLOT(addItem(QString))); + } + + + /** + * Opens a list of cubes + * + */ + void MosaicWidget::openList () { + if(p_projection == NULL) { + p_textItem = p_graphicsScene->addText("Please select a map file first!"); + return; + } + if(p_treeWidget->selectedItems().size() < 1) { + int numGroups = p_treeWidget->topLevelItemCount(); + p_treeWidget->topLevelItem(numGroups-1)->setSelected(true); + } + // Set up the list of filters that are default with this dialog. + if(!p_filterList2.contains("List Files (*.lis)")) { + p_filterList2.append("List Files (*.lis)"); + p_filterList2.append("Text Files (*.txt)"); + p_filterList2.append("All files (*)"); + } + if(!p_dir.exists()) { + p_dir = QDir::current(); + } + FileDialog *fileDialog = new FileDialog("Import List", p_filterList2, p_dir, + (QWidget *)parent()); + fileDialog->show(); + + connect (fileDialog,SIGNAL(fileSelected(QString)), + this,SLOT(readFile(QString))); + } + + + /** + * This method reads a file containing a list a cube filenames + * and opens each one. + * + * @param listFile + */ + void MosaicWidget::readFile(QString listFile){ + QFile f(listFile); + Isis::Filename fn(listFile.toStdString()); + + f.open(QIODevice::ReadOnly); + QString str = f.readLine(); + while (str.length() != 0) { + if(!str.startsWith("#")) { + if(str.endsWith("-group\n")) { + //------------------------------------------ + // Chop off the -group part that gets added + // in the saveList method. + //------------------------------------------ + str.chop(7); + addGroup(str); + } else { + //------------------------------------------------ + // Be sure to only select the last group so that + // the new item gets added to the correct group. + //------------------------------------------------ + int numGroups = p_treeWidget->topLevelItemCount(); + for(int i = 0; i < numGroups; i++) { + p_treeWidget->topLevelItem(i)->setSelected(false); + } + p_treeWidget->topLevelItem(numGroups -1)->setSelected(true); + addItem(str); + } + } + str = f.readLine(); + + } + f.close(); + } + + + /** + * This slot is called when a mosaicItem or tree widget group + * has been requested to bring to front. This slot figures out + * which kind of bringToFront needs to happen, then called the + * appropriate method. + * + */ + void MosaicWidget::bringToFront(){ + QList mosaicItems = selectedMosaicItems(); + QList groupItems = selectedGroups(); + if(!mosaicItems.isEmpty()){ + bringToFront(selectedMosaicItems().first()); + } + else{ + bringToFront(selectedGroups().first()); + } + + //---------------------------------------------------------- + // Need to re-order the items in the p_mosaicItems list + // so that when the project gets saved, it will be saved in + // the correct order. + //----------------------------------------------------------- + reorderMosaicItemsList(); + } + + + /** + * This method is called from the bringToFront slot. a mosaic + * item has been requested to bring to the front. The item is + * brought to the front of it's group. fixZvalue is called to + * change the z value of all the items in that group. + * + * @param item + */ + void MosaicWidget::bringToFront(MosaicItem *item){ + QTreeWidgetItem *group = item->treeItem()->parent(); + int index = group->indexOfChild(item->treeItem()); + + // This re-orders the tree widget. + group->takeChild(index); + group->insertChild(0,item->treeItem()); + + // This will set the z-values of the items. + item->setZValue(-FLT_MAX); + fixZValue(group); + } + + + /** + * This method is called from the brintToFront slot. a tree + * widget group has been requested to be brought to the front. + * reorderAllZValues is then called to change the z value of all + * the items in the view. + * + * @param group + */ + void MosaicWidget::bringToFront(QTreeWidgetItem *group){ + int index = p_treeWidget->indexOfTopLevelItem(group); + bool expanded = group->isExpanded(); + p_treeWidget->takeTopLevelItem(index); + p_treeWidget->insertTopLevelItem(0,group); + group->setExpanded(expanded); + reorderAllZValues(); + } + + + /** + * This method re-sets all the z-values for all the items in the + * view. + * + */ + void MosaicWidget::reorderAllZValues(){ + for(int i = 0; i < p_treeWidget->topLevelItemCount(); i++) { + reorderGroupZValues(p_treeWidget->topLevelItem(i)); + } + } + + + /** + * This method re-sets the the z-values for all the items within + * the group. + * + * @param groupItem + */ + void MosaicWidget::reorderGroupZValues(QTreeWidgetItem *groupItem){ + for(int j = 0; j < groupItem->childCount(); j++) { + p_treeToMosaicMap[groupItem->child(j)]->setZValue(-FLT_MAX); + } + setInitialZValue(groupItem); + } + + + /** + * This method reorders the p_mosaicItems QList so that it + * always matches what the user has arranged in the QTreeWidget. + * (i.e. the list on the left side of the qmos window.) + * + */ + void MosaicWidget::reorderMosaicItemsList(){ + // copy all the mosaic items into a temp. hold area. + QList tempItems = p_mosaicItems; + int insertAt = 0; + int totalChildCount = 0; + + for(int i = 0; i < p_treeWidget->topLevelItemCount(); i++) { + for(int k = 0; k < tempItems.size(); k++) { + for(int j = 0; j < p_treeWidget->topLevelItem(i)->childCount(); j++) { + if(tempItems[k]->treeWidgetItem() == p_treeWidget->topLevelItem(i)->child(j)) { + insertAt = j + totalChildCount; + p_mosaicItems.replace(insertAt, tempItems[k]); + } + } + } + //-------------------------------------------------------------- + // After the first topLevelItem (or group) we need to keep track + // of how many children the groups above the current group have + // so we can insert the item at the right spot in the QList + //-------------------------------------------------------------- + totalChildCount += p_treeWidget->topLevelItem(i)->childCount(); + } + + } + + + /** + * This slot is changes the level of detail at which mosaic + * footprints will be allowed to have transparency. This is + * adjustable because it affects the speed of the re-paint + * calls. + * + * @param detail + */ + void MosaicWidget::changeLevelOfDetail(int detail){ + for(int i = 0; i < p_mosaicItems.size(); i++) { + p_mosaicItems[i]->setLevelOfDetail(detail*0.005); + p_mosaicItems[i]->update(); + } + + } + + + /** + * This method refits the items in the graphics view. + * + */ + void MosaicWidget::refit(){ + p_xmin = DBL_MAX; + p_xmax = -DBL_MAX; + p_ymin = DBL_MAX; + p_ymax = -DBL_MAX; + + for(int i = 0; i < p_treeWidget->topLevelItemCount(); i++) { + for(int j = 0; j < p_treeWidget->topLevelItem(i)->childCount(); j++) { + MosaicItem *mosaicItem = p_treeToMosaicMap[p_treeWidget->topLevelItem(i)->child(j)]; + if(mosaicItem->XMinimum() < p_xmin) p_xmin = mosaicItem->XMinimum(); + if(mosaicItem->YMinimum() < p_ymin) p_ymin = mosaicItem->YMinimum(); + if(mosaicItem->XMaximum() > p_xmax) p_xmax = mosaicItem->XMaximum(); + if(mosaicItem->YMaximum() > p_ymax) p_ymax = mosaicItem->YMaximum(); + } + } + p_graphicsView->setSceneRect(p_xmin-5, p_ymin-5, (p_xmax-p_xmin), (p_ymax-p_ymin)); + p_graphicsView->fitInView(p_xmin-5, p_ymin-5, (p_xmax-p_xmin), (p_ymax-p_ymin), Qt::KeepAspectRatio); + + } + + + /** + * This slot is called when a mosaicItem or tree widget group + * has been requested to send to back. This slot figures out + * which kind of sendToBack needs to happen, then called the + * appropriate method. + * + */ + void MosaicWidget::sendToBack(){ + QList mosaicItems = selectedMosaicItems(); + QList groupItems = selectedGroups(); + if(!mosaicItems.isEmpty()){ + sendToBack(selectedMosaicItems().first()); + } + else{ + sendToBack(selectedGroups().first()); + } + + //--------------------------------------------------------- + // Need to re-order the items in the p_mosaicItems list + // so that when the project gets saved, it will be saved in + // the correct order. + //--------------------------------------------------------- + reorderMosaicItemsList(); + } + + + /** + * This method is called from the sendToBack slot. + * a mosaic item has been requested to send to the back. The + * item is sent to the back of it's group. fixZvalue is called + * to change the z value of all the items in that group. + * + * @param item + */ + void MosaicWidget::sendToBack(MosaicItem *item){ + QTreeWidgetItem *group = item->treeItem()->parent(); + int index = group->indexOfChild(item->treeItem()); + + // This moves the item in the tree widget. + group->takeChild(index); + group->insertChild(group->childCount(),item->treeItem()); + + // This will reset the z-value for this item + item->setZValue(-FLT_MAX); + fixZValue(group); + } + + + /** + * This method is called from the sendToBack slot. a tree widget + * group has been requested to be sent to the back. + * reorderAllZValues is then called to change the z value of all + * the items in the view. + * + * @param group*/ + void MosaicWidget::sendToBack(QTreeWidgetItem *group){ + int index = p_treeWidget->indexOfTopLevelItem(group); + bool expanded = group->isExpanded(); + p_treeWidget->takeTopLevelItem(index); + p_treeWidget->insertTopLevelItem(p_treeWidget->topLevelItemCount(),group); + group->setExpanded(expanded); + reorderAllZValues(); + } + + + /** + * This slot is called when the 'Move Up One' option is chosen + * from the context menu. This method looks at which kind of + * item was chosen and calls the appropriate method. + * + */ + void MosaicWidget::moveUpOne(){ + QList mosaicItems = selectedMosaicItems(); + QList groupItems = selectedGroups(); + if(!mosaicItems.isEmpty()){ + moveUpOne(selectedMosaicItems().first()); + } + else{ + moveUpOne(selectedGroups().first()); + } + + } + + + /** + * This slot is called when the 'Move Down One' option is chosen + * from the context menu. This method looks at which kind of + * item was chosen and calls the appropriate method. + * + */ + void MosaicWidget::moveDownOne(){ + QList mosaicItems = selectedMosaicItems(); + QList groupItems = selectedGroups(); + if(!mosaicItems.isEmpty()){ + moveDownOne(selectedMosaicItems().first()); + } + else{ + moveDownOne(selectedGroups().first()); + } + + } + + + /** + * Moves the selected mosaic item up. + * + * @param item + */ + void MosaicWidget::moveUpOne(MosaicItem *item){ + QTreeWidgetItem *group = item->treeItem()->parent(); + int index = group->indexOfChild(item->treeItem()); + if(index == 0) return; + item->setZValue(-FLT_MAX); + group->takeChild(index); + group->insertChild(index - 1,item->treeItem()); + fixZValue(group); + reorderMosaicItemsList(); + + } + + + /** + * Moves the selected group up. + * + * @param group + */ + void MosaicWidget::moveUpOne(QTreeWidgetItem *group){ + int index = p_treeWidget->indexOfTopLevelItem(group); + bool expanded = group->isExpanded(); + if(index == 0) return; + p_treeWidget->takeTopLevelItem(index); + p_treeWidget->insertTopLevelItem(index - 1, group); + group->setExpanded(expanded); + reorderAllZValues(); + reorderMosaicItemsList(); + + } + + + /** + * Move the selected mosaic item down. + * + * @param item + */ + void MosaicWidget::moveDownOne(MosaicItem *item){ + QTreeWidgetItem *group = item->treeItem()->parent(); + int index = group->indexOfChild(item->treeItem()); + if(index == (group->childCount()-1)) return; + item->setZValue(-FLT_MAX); + group->takeChild(index); + group->insertChild(index + 1,item->treeItem()); + fixZValue(group); + reorderMosaicItemsList(); + + } + + + /** + * Moves the selected group in the Tree Widget down. + * + * @param group + */ + void MosaicWidget::moveDownOne(QTreeWidgetItem *group){ + int index = p_treeWidget->indexOfTopLevelItem(group); + bool expanded = group->isExpanded(); + if(index == p_treeWidget->topLevelItemCount()-1) return; + p_treeWidget->takeTopLevelItem(index); + p_treeWidget->insertTopLevelItem(index + 1, group); + group->setExpanded(expanded); + reorderAllZValues(); + reorderMosaicItemsList(); + } + + + /** + * This slot is called when a mosaicItem or tree widget group + * has been requested to cut. This slot figures out + * which kind of cut needs to happen, then called the appropriate + * method. + * + */ + void MosaicWidget::cut(){ + QList items = selectedMosaicItems(); + p_pasteItems.clear(); + for(int i = 0; i < items.size(); i++) { + QTreeWidgetItem *group = items[i]->treeItem()->parent(); + int index = group->indexOfChild(items[i]->treeItem()); + group->takeChild(index); + p_graphicsScene->removeItem(items[i]); + p_pasteItems.push_back(items[i]); + p_mosaicItems.removeAt(p_mosaicItems.indexOf(items[i])); + } + + } + + /** + * This slot is called when a mosaicItem or tree widget group + * has been requested to paste. This slot figures out + * which kind of paste needs to happen, then called the + * appropriate method. + * + */ + void MosaicWidget::paste(){ + for(int i = 0; i < p_pasteItems.size(); i++) { + QTreeWidgetItem *group = p_treeWidget->selectedItems().last()->parent(); + if(group != 0) { + addItem(p_pasteItems[i], group->text(0)); + } else { + addItem(p_pasteItems[i], p_treeWidget->selectedItems().last()->text(0)); + } + showItem(p_pasteItems[i]); + } + p_pasteItems.clear(); + + } + + + /** + * This paste method is called from the drop action. + * i.e. when there is a drop of a tree widget item this paste is + * called + * + * @param point + */ + void MosaicWidget::paste(QPoint point){ + if(p_dropItem) { + for(int i = 0; i < p_pasteItems.size(); i++) { + if(p_treeToMosaicMap.contains(p_dropItem)) { + // before we call additem we need to set the insert value to something. + int index = p_dropItem->parent()->indexOfChild(p_dropItem); + p_dropItem->parent()->setSelected(true); + p_insertItemAt = index+1; + addItem(p_pasteItems[i], p_dropItem->parent()->text(0)); + showItem(p_pasteItems[i]); + } else { + addItem(p_pasteItems[i], p_dropItem->text(0)); + showItem(p_pasteItems[i]); + } + + } + } + + p_pasteItems.clear(); + + } + + + /** + * Allows the user to rename the group item. + * + */ + void MosaicWidget::renameGroup(){ + p_treeWidget->editItem(selectedGroups().first()); + } + + + /** + * This is basically only used for when a group is added or if a + * group's name has been changed. + * + * + * @param item + * @param column + */ + void MosaicWidget::groupChanged(QTreeWidgetItem * item, int column){ + // if it's not a group item then return + if(p_treeWidget->indexOfTopLevelItem(item) == -1) return; + //----------------------------------------- + // insert the new name into the map so that + // all group names are accounted for. + //---------------------------------------- + p_groupToTreeMap.insert(item->text(0), item); + } + + + /** + * This method merges the selected groups in the Tree Widget. + * + */ + void MosaicWidget::mergeGroups(){ + QList groupItems = selectedGroups(); + for(int i = 0; i < groupItems.size(); i++) { + if(i != 0) { + int index = p_treeWidget->indexOfTopLevelItem(groupItems[i]); + groupItems[0]->addChildren(groupItems[i]->takeChildren()); + p_treeWidget->takeTopLevelItem(index); + } + } + reorderGroupZValues(groupItems[0]); + + } + + + /** + * Changes the color of the footprint for the mosaic item. + * + */ + void MosaicWidget::changeColor(){ + QList mosaicItems = selectedMosaicItems(); + QList groupItems = selectedGroups(); + if(groupItems.isEmpty() && mosaicItems.isEmpty()) return; + + QColor initialColor; + if(!mosaicItems.isEmpty()){ + initialColor = mosaicItems.first()->color(); + } + else { + initialColor = MosaicItem::randomColor(); + } + + QRgb rgb = QColorDialog::getRgba(initialColor.rgba()); + QColor color = QColor(qRed(rgb), qGreen(rgb), qBlue(rgb), qAlpha(rgb)); + + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setColor(color); + } + } + + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setColor(color); + } + } + + + /** + * Set the transparency of the image + * + */ + void MosaicWidget::changeTransparency(){ + QList mosaicItems = selectedMosaicItems(); + QList groupItems = selectedGroups(); + if(groupItems.isEmpty() && mosaicItems.isEmpty()) return; + + int initialAlpha; + if(!mosaicItems.isEmpty()){ + initialAlpha = mosaicItems.first()->getImageTrans(); + } + else { + initialAlpha = 255; + } + + QColor initialColor = QColor(255, 255, 0, initialAlpha); + QRgb rgb = QColorDialog::getRgba(initialColor.rgba()); + QColor color = QColor(qRed(rgb), qGreen(rgb), qBlue(rgb), qAlpha(rgb)); + int newAlpha = color.alpha(); + + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setTransparency(newAlpha); + } + } + + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setTransparency(newAlpha); + } + } + + + /** + * Show the item label. + * + */ + void MosaicWidget::showLabel(){ + QList groupItems = selectedGroups(); + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setLabelVisible(true); + } + } + + QList mosaicItems = selectedMosaicItems(); + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setLabelVisible(true); + } + + } + + + /** + * Hide the item label. + * + */ + void MosaicWidget::hideLabel(){ + QList groupItems = selectedGroups(); + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setLabelVisible(false); + } + } + + QList mosaicItems = selectedMosaicItems(); + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setLabelVisible(false); + } + + } + + + /** + * Show the item outline only. + * + */ + void MosaicWidget::showOutline(){ + QList groupItems = selectedGroups(); + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setOutlineVisible(true); + } + } + + QList mosaicItems = selectedMosaicItems(); + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setOutlineVisible(true); + } + + } + + + /** + * Don't show the item outline. + * + */ + void MosaicWidget::hideOutline(){ + QList groupItems = selectedGroups(); + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setOutlineVisible(false); + } + } + + QList mosaicItems = selectedMosaicItems(); + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setOutlineVisible(false); + } + + } + + + /** + * Hides the item's footprint + * + */ + void MosaicWidget::hideFootprint(){ + QList groupItems = selectedGroups(); + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setFootprintVisible(false); + } + } + + QList mosaicItems = selectedMosaicItems(); + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setFootprintVisible(false); + } + + } + + + /** + * Shows the item's footprint + * + */ + void MosaicWidget::showFootprint(){ + QList groupItems = selectedGroups(); + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setFootprintVisible(true); + } + } + + QList mosaicItems = selectedMosaicItems(); + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setFootprintVisible(true); + } + + } + + + /** + * Bring up a font dialog box to allow the user to change the + * font size of the item labels. + * + */ + void MosaicWidget::setLabelFont(){ + // This section is for groups + QList groupItems = selectedGroups(); + if(groupItems.size() > 0) { + bool ok; + const QString caption = "Qmos rules! Select your font size"; + QFont font = QFontDialog::getFont(&ok, QFont("Helvetica", 10), p_parent, caption); + if(ok) { + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setFontSize(font); + } + } + } + + } + + // This section is for when just a mosaic item is selected. + QList mosaicItems = selectedMosaicItems(); + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setFontSize(); + } + + } + + + /** + * Hides the footprint for all currently selected items. + * + */ + void MosaicWidget::hideItem(){ + QList groupItems = selectedGroups(); + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setItemVisible(false); + } + } + + QList mosaicItems = selectedMosaicItems(); + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setItemVisible(false); + } + } + + + /** + * shows the passed in item. + * + * @param item + */ + void MosaicWidget::showItem(MosaicItem *item){ + item->setItemVisible(true); + } + + + /** + * Sets all the currently selected items to visible. + * + */ + void MosaicWidget::showItem(){ + QList groupItems = selectedGroups(); + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setItemVisible(true); + } + } + + QList mosaicItems = selectedMosaicItems(); + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setItemVisible(true); + } + } + + + /** + * Hides the currently selected items images + * + */ + void MosaicWidget::hideImage(){ + QList groupItems = selectedGroups(); + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setImageVisible(false); + } + } + + QList mosaicItems = selectedMosaicItems(); + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setImageVisible(false); + } + } + + + /** + * Hides the item's image. + * + * @param item + */ + void MosaicWidget::hideImage(MosaicItem *item){ + item->setImageVisible(false); + } + + + /** + * Shows the item's image. + * + * @param item + */ + void MosaicWidget::showImage(MosaicItem *item){ + item->setImageVisible(true); + } + + + /** + * Sets the currently selected items images to visible. + * + */ + void MosaicWidget::showImage(){ + QList groupItems = selectedGroups(); + for(int i = 0; i < groupItems.size(); i++) { + for(int j = 0; j < groupItems[i]->childCount(); j++) { + MosaicItem *mosItem = p_treeToMosaicMap[groupItems[i]->child(j)]; + mosItem->setImageVisible(true); + } + } + + QList mosaicItems = selectedMosaicItems(); + for(int i = 0; i < mosaicItems.size(); i++) { + mosaicItems[i]->setImageVisible(true); + } + } + + + /** + * Returns a list of all the selected groups in the Tree Widget. + * + * @return QList + */ + QList MosaicWidget::selectedGroups(){ + QList list; + QMap::const_iterator it = p_groupToTreeMap.constBegin(); + while(it != p_groupToTreeMap.constEnd()) { + if (it.value()->isSelected()) list.push_back(it.value()); + ++it; + } + return list; + } + + + /** + * Returns a list of all the mosaic items selected in the Tree + * Widget. + * + * @return QList + */ + QList MosaicWidget::selectedMosaicItems(){ + QList list; + for(int i = 0; i < p_mosaicItems.size(); i++) { + if(p_mosaicItems[i]->isSelected()) { + list.push_back(p_mosaicItems[i]); + } + QListchildren = p_mosaicItems[i]->children(); + for(int j= 0; j < children.size(); j++) { + if(children[j]->isSelected()){ + //--------------------------------------------------------------- + // If the child of an item has been selected, but the item itself + // has not been added to the list, then we need to add it. + //--------------------------------------------------------------- + if(!list.contains(p_mosaicItems[i])){ + list.push_back(p_mosaicItems[i]); + } + } + } + } + return list; + } + + + /** + * Sets the current projection. + * + * @param proj + */ + void MosaicWidget::setProjection(Isis::Projection *proj) { + if(p_textItem != NULL) p_graphicsScene->removeItem(p_textItem); + p_projection = proj; + } + + + /** + * + * + * + * @param domain + */ + void MosaicWidget::setLonDomain(QString domain){ + p_lonDomain = domain; + } + + + /** + * Reprojects all the items in the view. + * Also makes sure to resize the view rectangle to fit the newly + * projected footprints. + * + */ + void MosaicWidget::reprojectItems(){ + for(int i = 0; i < p_mosaicItems.size(); i++) { + p_mosaicItems[i]->reproject(); + } + p_graphicsView->update(); + if(p_mosaicItems.size() > 0) refit(); + } + + + /** + * When the user selects a map file, we need to set the + * projection and reproject all the items in the view. + * + */ + void MosaicWidget::setMapFile(){ + p_mapfile=QFileDialog::getOpenFileName((QWidget*)parent(), + "Select file to load", + ".", + "All Files (*.map)"); + if (p_mapfile.isEmpty()) return; + + try{ + Isis::Pvl pvl; + pvl.Read(p_mapfile.toStdString()); + Isis::Projection *proj = Isis::ProjectionFactory::Create(pvl); + //TODO: how does the old projection get deleted? + setProjection(proj); + Isis::PvlKeyword projectionKeyword = pvl.FindKeyword("ProjectionName", Isis::Pvl::Traverse); + Isis::PvlKeyword longDomainKeyword = pvl.FindKeyword("LongitudeDomain", Isis::Pvl::Traverse); + QString projName = QString::fromStdString(projectionKeyword[0]); + setLonDomain(QString::fromStdString(longDomainKeyword[0])); + p_mapDisplay->setText(projName); + reprojectItems(); + }catch(Isis::iException &e){ + std::string msg = e.Errors(); + QMessageBox::information(this, "Error", QString::fromStdString(msg), QMessageBox::Ok); + return; + } + } + + + /** + * Sets the map file (and projection) to the user specified file. + * + * @param mapFile + */ + void MosaicWidget::setMapFile(QString mapfile){ + p_mapfile = mapfile; + + try{ + Isis::Pvl pvl; + pvl.Read(p_mapfile.toStdString()); + Isis::Projection *proj = Isis::ProjectionFactory::Create(pvl); + //TODO: how does the old projection get deleted? + setProjection(proj); + Isis::PvlKeyword projectionKeyword = pvl.FindKeyword("ProjectionName", Isis::Pvl::Traverse); + Isis::PvlKeyword longDomainKeyword = pvl.FindKeyword("LongitudeDomain", Isis::Pvl::Traverse); + QString projName = QString::fromStdString(projectionKeyword[0]); + setLonDomain(QString::fromStdString(longDomainKeyword[0])); + p_mapDisplay->setText(projName); + reprojectItems(); + }catch(Isis::iException &e){ + std::string msg = e.Errors(); + QMessageBox::information(this, "Error", QString::fromStdString(msg), QMessageBox::Ok); + return; + } + } + + + /** + * Saves the list of filenames in the tree widget to a text + * file. + * + * @param filename + */ + void MosaicWidget::saveList(QString filename){ + QFile file(filename); + file.open(QIODevice::WriteOnly | QIODevice::Text); + QTextStream out(&file); + for(int i = 0; i < p_treeWidget->topLevelItemCount(); i++) { + out << p_treeWidget->topLevelItem(i)->text(0) << "-group"<< "\n"; + for(int j = 0; j < p_treeWidget->topLevelItem(i)->childCount(); j ++){ + out << p_treeWidget->topLevelItem(i)->child(j)->text(0) << ".cub\n"; + } + } + file.close(); + } + + + /** + * This method reads in the user selects file which was written + * in a pvl format by the method below. + * A mosaic item is created, then all the characteristics of + * the item are set to what they were saved as, then the item + * is added to the scene, in the group that was saved. + * + * @param filename + */ + void MosaicWidget::readProject(QString filename){ + Isis::Pvl pvl; + pvl.Read(filename.toStdString()); + if(pvl.Groups() < 1) return; + //--------------------------------------------------------- + // If there are already items open in qmos, we need to clear + // out everything that is open and 'clear the slate' for the + // new project. + //---------------------------------------------------------- + deleteAllCubes(); + + //---------------------------------------------------------- + // When we read in a project, we need to delete the default + // group added in the constructor. + //---------------------------------------------------------- + deleteGroup("Group1"); + + //---------------------------------------------------- + // if the control points are visible, then we need to + // check the control points button. + //---------------------------------------------------- + if(pvl.HasGroup("Control Points")) { + Isis::PvlGroup pointsGroup = pvl.FindGroup("Control Points"); + Isis::iString visible = pointsGroup.FindKeyword("Visible")[0]; + bool checked = visible.Equal("True"); + p_controlPointButton->setChecked(checked); + } + + // setup map file + if(pvl.HasGroup("Map File")) { + Isis::PvlGroup mapGroup = pvl.FindGroup("Map File"); + QString mapFile = mapGroup.FindKeyword("Filename")[0].ToQt(); + if(mapFile.compare("Null") != 0) setMapFile(mapFile); + } + + // setup control net if necessary + if(pvl.HasGroup("Control Net File")) { + Isis::PvlGroup grp = pvl.FindGroup("Control Net File"); + std::string netFile = grp.FindKeyword("Filename")[0]; + p_controlnetfile = QString::fromStdString(netFile); + if(netFile.compare("Null") != 0) p_cn = new Isis::ControlNet(netFile); + } + + // Now create each mosaic item. + for(int i = 0; i < pvl.Groups()-1; i++){ + QString item = "Item #" + QString::number(i); + if(pvl.HasGroup(item.toStdString())) { + Isis::PvlGroup grp = pvl.FindGroup(item.toStdString()); + QString groupName = grp.FindKeyword("Group_Name")[0].ToQt(); + QString itemFileName = grp.FindKeyword("Filename")[0].ToQt(); + + //------------------------------------------------------------------- + // Create a mosaic item for every group in the project file. + // The item is create with the pvl group as a arg. for the constructor + //------------------------------------------------------------------- + MosaicItem *mosItem = new MosaicItem(itemFileName, this, &grp); + // Add the item to the scene. + addItem(mosItem, groupName); + + //---------------------------------------------------- + // If the control points are set to visible, then call + // displayControlPoints() for each item being created. + //---------------------------------------------------- + if(pvl.FindGroup("Control Points").FindKeyword("Visible")[0].compare("True") + == 0 && p_cn != NULL) { + mosItem->displayControlPoints(p_cn); + } + } + } + + } + + + /** + * This method writes the current state of all the mosaic items + * to a pvl file so it can be read in by the method above + * when the user selects it. + * + * @param filename + */ + void MosaicWidget::saveProject(QString filename){ + Isis::Pvl pvl; + Isis::PvlGroup controlGroup("Control Points"); + + if(p_controlPointButton->isChecked() ) { + controlGroup += Isis::PvlKeyword("Visible", "True"); + } else { + controlGroup += Isis::PvlKeyword("Visible", "False"); + } + pvl.AddGroup(controlGroup); + + // Write out the control net file to the pvl. + Isis::PvlGroup controlNetGroup("Control Net File"); + if(p_controlPointButton->isChecked() ) { + controlNetGroup += Isis::PvlKeyword("Filename", p_controlnetfile); + } else { + controlNetGroup += Isis::PvlKeyword("Filename", "Null"); + } + pvl.AddGroup(controlNetGroup); + + // Write out the map file to the pvl. + Isis::PvlGroup mapGroup("Map File"); + mapGroup += Isis::PvlKeyword("Filename", p_mapfile); + pvl.AddGroup(mapGroup); + + //---------------------------------------------------------------- + // Loop thru all the items and have them write out their current + // state to a pvl group, then add the group to this pvl. + //---------------------------------------------------------------- + for(int i = 0; i < p_mosaicItems.size(); i++) { + Isis::PvlGroup grp = p_mosaicItems[i]->saveState(); + QString item = "Item #" + QString::number(i); + grp.SetName(item.toStdString()); + pvl.AddGroup(grp); + } + + pvl.Write(filename.toStdString()); + } + + + /** + * This event filter is installed on both the QSplitter and the + * QGraphicsscene. + * + * @param o + * @param e + * + * @return bool + */ + bool MosaicWidget::eventFilter(QObject *o,QEvent *e) { + switch (e->type()) { + //----------------------------------------------------- + // This event is caught from the QSplitter to decide + // that we need to zoom in and zoom out due to the +/- + // keys being pressed. + //----------------------------------------------------- + case QEvent::KeyPress:{ + if(((QKeyEvent *)e)->key() == Qt::Key_Plus) { + p_ztool->zoomIn2X(); + } else if(((QKeyEvent *)e)->key() == Qt::Key_Minus) { + p_ztool->zoomOut2X(); + } + + if(((QKeyEvent *)e)->key() == Qt::Key_Delete) { + deleteCube(); + } + + break; + } + + //------------------------------------------------------------- + // The user had pressed the mouse button in the graphics scene. + // If the rubberband mode is on, we need to create a rubberband + // whos parent is the graphics view and set the geometry to the + // point at which the user click and size = 0. + //------------------------------------------------------------ + case QMouseEvent::GraphicsSceneMousePress:{ + + //------------------------------------------------------------------- + // Since the rubberband's parent is the graphics view, we need to map + // the mouse coordinates from the scene coords. to the view's coords. + //------------------------------------------------------------------- + p_origin = p_graphicsView->mapFromScene(((QGraphicsSceneMouseEvent *)e)->scenePos()); + + if(p_ztool->isActive()) { + //---------------------------------------------------- + // This makes it so that the image doesn't + // try the redraw the entire time the user is dragging + // the rubberband for a zoom in/out + //---------------------------------------------------- + for(int i = 0; i < p_mosaicItems.size(); i++) { + p_mosaicItems[i]->setEnableRepaint(false); + } + + if(((QGraphicsSceneMouseEvent *)e)->button() == Qt::RightButton) { + p_graphicsView->viewport()->setCursor(QCursor(QPixmap("/usgs/cpkgs/isis3/data/base/icons/viewmag-.png"))); + }else if(((QGraphicsSceneMouseEvent *)e)->button() == Qt::LeftButton) { + p_graphicsView->viewport()->setCursor(QCursor(QPixmap("/usgs/cpkgs/isis3/data/base/icons/viewmag+.png"))); + } + + if(p_rubberBand == NULL) { + p_rubberBand = new QRubberBand(QRubberBand::Rectangle, p_graphicsView); + } + p_rubberBand->setGeometry(QRect(p_origin, QSize())); + p_rubberBand->show(); + } + + //----------------------------------------------------------------------- + // if the select tool is active, then we will allow the user to move the + // item's label around (by dragging). But ONLY when the select tool + // is active. + //----------------------------------------------------------------------- + for(int i = 0; i < p_mosaicItems.size(); i++) { + p_mosaicItems[i]->getLabel()->setFlag(QGraphicsItem::ItemIsMovable, (p_stool->isActive())?true:false); + } + + break; + } + + //-------------------------------------------------------------------------- + // As the user moves the mouse around we reset the geometry of the rubberband + // such that they upper left corner is the original point at which they + // clicked and the lower right corner is where the mouse currently is located. + //-------------------------------------------------------------------------- + case QMouseEvent::GraphicsSceneMouseMove:{ + // update the labels in the lower right corner of the qmos window. + if(p_mosaicItems.size() > 0) { + p_ttool->updateLabels(((QGraphicsSceneMouseEvent *)e)->scenePos()); + } + + if(p_ztool->isActive() && p_rubberBand != NULL) { + QPoint newPoint = p_graphicsView->mapFromScene(((QGraphicsSceneMouseEvent *)e)->scenePos()); + p_rubberBand->setGeometry(QRect(p_origin, newPoint).normalized()); + } + break; + } + + //------------------------------------------------------------------- + // Once the user releases the mouse button we need to do the work to + // zoom in, then hide the rubberband. + //------------------------------------------------------------------- + case QMouseEvent::GraphicsSceneMouseRelease:{ + if(p_rubberBand != NULL) { + // Do Zoom tool stuff if Zoom tool is active + if(p_ztool->isActive()) { + // re-enable paint when the mouse button is released. + for(int i = 0; i < p_mosaicItems.size(); i++) { + p_mosaicItems[i]->setEnableRepaint(true); + } + p_graphicsView->viewport()->setCursor(QCursor(Qt::ArrowCursor)); + p_ztool->rubberBandComplete(p_rubberBand->geometry(), (QGraphicsSceneMouseEvent *)e); + } + p_rubberBand->hide(); + } + // Do Point tool stuff if Point tool is active + if(p_pntool->isActive() && p_cn != NULL) { + p_pntool->findPoint(((QGraphicsSceneMouseEvent *)e)->scenePos(), p_cn); + } + + break; + } + + default: { + } + } + + return false; + } + + /** + * When the user drags and drop items around in the tree widget, + * this method handles the movement of the item. + * + * @param point + */ + void MosaicWidget::dropAction(QPoint point){ + if(p_treeWidget->itemAt(point)) { + p_dropItem = p_treeWidget->itemAt(point); + cut(); + paste(point); + } + } + + + /** + * Handles the actions from the view menu. + * + * + * @param action + */ + void MosaicWidget::viewMenuAction(QAction *action){ + + if(action->text() == "Item Column") { + if(action->isChecked()) { + p_treeWidget->showColumn(ItemColumn); + } else { + p_treeWidget->hideColumn(ItemColumn); + } + } + if(action->text() == "Footprint Column") { + if(action->isChecked()) { + p_treeWidget->showColumn(FootprintColumn); + } else { + p_treeWidget->hideColumn(FootprintColumn); + } + } + + if(action->text() == "Outline Column") { + if(action->isChecked()) { + p_treeWidget->showColumn(OutlineColumn); + } else { + p_treeWidget->hideColumn(OutlineColumn); + } + } + + if(action->text() == "Image Column") { + if(action->isChecked()) { + p_treeWidget->showColumn(ImageColumn); + } else { + p_treeWidget->hideColumn(ImageColumn); + } + } + + + if(action->text() == "Label Column") { + if(action->isChecked()) { + p_treeWidget->showColumn(LabelColumn); + } else { + p_treeWidget->hideColumn(LabelColumn); + } + } + + + if(action->text() == "Resolution Column") { + if(action->isChecked()) { + p_treeWidget->showColumn(ResolutionColumn); + } else { + p_treeWidget->hideColumn(ResolutionColumn); + } + } + + if(action->text() == "Emission Angle Column") { + if(action->isChecked()) { + p_treeWidget->showColumn(EmissionColumn); + } else { + p_treeWidget->hideColumn(EmissionColumn); + } + } + + if(action->text() == "Incidence Angle Column") { + if(action->isChecked()) { + p_treeWidget->showColumn(IncidenceColumn); + } else { + p_treeWidget->hideColumn(IncidenceColumn); + } + } + + if(action->text() == "Island Column") { + if(action->isChecked()) { + p_treeWidget->showColumn(IslandColumn); + } else { + p_treeWidget->hideColumn(IslandColumn); + } + } + + if(action->text() == "Notes Column") { + if(action->isChecked()) { + p_treeWidget->showColumn(NotesColumn); + } else { + p_treeWidget->hideColumn(NotesColumn); + } + } + + if(action->text() == "Show Reference Footprint") { + setReferenceItemVisible(action->isChecked()); + } + + } + + + /** + * Provides the user with a file open dialog box so they can select a .net + * file which contains all the points in their control net which we need + * to display. Each mosaic item displays it's own control points, so we + * loop through all the mosaic items and call it's + * displayControlPoints function. + * + */ + void MosaicWidget::displayControlPoints(){ + // If the tool tip says hide, then call the hide method and return. + if(p_controlPointButton->isChecked() ) { + hideControlPoints(); + return; + } + + //--------------------------------------------------------------- + // if the control net file has already been read in once, then + // we don't want to do that again, just set the points to visible + // for each mosaic item and return. + // This wasn't such a welcome feature. + //--------------------------------------------------------------- + //###WAS COMMENTED OUT### + if(p_cn != NULL) { + for(int i = 0; i < p_mosaicItems.size(); i++) { + p_mosaicItems[i]->setControlPointsVisible(true); + } + return; + } + //###END COMMENT### + + // Bring up a file dialog for user to select their cnet file. + QString netFile = FileDialog::getOpenFileName(p_parent, + "Select Control Net. File", + QDir::current().dirName(), + "*.net"); + + //-------------------------------------------------------------- + // if the file is not empty attempt to load in the control points + // for each mosaic item + //--------------------------------------------------------------- + if(!netFile.isEmpty()) { + + try { + Isis::Filename controlnetfile(netFile.toStdString()); + p_controlnetfile = QString::fromStdString(controlnetfile.Expanded()); + p_cn = new Isis::ControlNet(netFile.toStdString()); + } + catch (Isis::iException &e) { + QString message = "Invalid control network. \n"; + std::string errors = e.Errors(); + message += errors.c_str(); + e.Clear (); + QMessageBox::information(p_parent,"Error",message); + QApplication::restoreOverrideCursor(); + p_controlPointButton->setChecked(false); + return; + } + + //-------------------------------------------------------------- + // for each mosaic item, we setup a QList that contains + // the control points within that item. + //-------------------------------------------------------------- + for(int i = 0; i < p_mosaicItems.size(); i++) { + p_mosaicItems[i]->displayControlPoints(p_cn); + } + + + } else { + //--------------------------------------------------- + // this means the user canceled out of the dialog box + //--------------------------------------------------- + p_controlPointButton->setChecked(false); + } + + //------------------------------------------------------ + // Set the tool tip text to what will happen if the user + // presses the button again. + //----------------------------------------------------- + p_controlPointButton->setToolTip("Hide Control Points"); + } + + +/** + * Displays the connectivity of Control Points + * + */ +void MosaicWidget::displayConnectivity( bool connected ){ + if(p_cn == NULL) { + //p_connectivityButton->setChecked(true); + return; + } + //if(p_connectivityButton->isChecked() ) { //###Can the colors be reverted to the same as on load?### + if( !connected ) { //###Can the colors be reverted to the same as on load?### + for(int i = 0; i < p_mosaicItems.size(); i++) { + p_mosaicItems[i]->setColor(MosaicItem::randomColor()); + } + //p_connectivityButton->setToolTip("Display Network Connectivity"); + return; + } + + // Color and label islands + Isis::ControlGraph * graph = new Isis::ControlGraph( p_cn ); + + if( graph->GetIslandCount() == 0 ) { + QColor islandColor = MosaicItem::randomColor(); + for(int cube = 0; cube < p_mosaicItems.size(); cube ++) { + p_mosaicItems[cube]->treeItem()->setText(IslandColumn, QString::number(1)); + p_mosaicItems[cube]->setColor( islandColor ); + } + } + else { + for( int island = 0; island < graph->GetIslandCount(); island ++ ) { + QColor islandColor = MosaicItem::randomColor(); + + const QVector< QString > snList = graph->GetCubesOnIsland(island); + + for( int sn = 0; sn < snList.size(); sn ++ ) { + for(int cube = 0; cube < p_mosaicItems.size(); cube ++) { + if( snList[sn] == p_mosaicItems[cube]->serialNumber().c_str() ) { + p_mosaicItems[cube]->treeItem()->setText(IslandColumn, QString::number(island+1)); + p_mosaicItems[cube]->setColor( islandColor ); + } + } + } + } + } + delete graph; + graph = NULL; + + // Sort on Islands + //sortByIsland(); //###This should be removed and placed into a sort button### + + p_connectivityButton->setToolTip("Reset Colors"); +} + + + +void MosaicWidget::setControlNet( Isis::Filename cnet ) { + p_controlnetfile = QString::fromStdString(cnet.Expanded()); + p_cn = new Isis::ControlNet(cnet.Expanded()); +} + + + /** + * Calls setControlPointsVisible(false) for each mosaic item and + * change the control point button back to "Display". + * + */ + void MosaicWidget::hideControlPoints(){ + for(int i = 0; i < p_mosaicItems.size(); i++) { + p_mosaicItems[i]->setControlPointsVisible(false); + } + p_controlPointButton->setToolTip("Display Control Points"); + } + + + /** + * Returns a list of all the mosaic items in the scene including + * all of the children + * + * + * @return QList + */ + QList MosaicWidget::allMosaicItems(){ + QList allItems; + for(int i = 0; i < p_mosaicItems.size(); i++) { + allItems.push_back(p_mosaicItems[i]); + QListchildren = p_mosaicItems[i]->children(); + for(int j= 0; j < children.size(); j++) { + allItems.push_back((MosaicItem *)children[j]); + } + } + return allItems; + } + + + /** + * The next three methods are private slots called from the + * context menu. This allows the user to sort the items in a + * group base on resolution, emission angle, or incidence angle. + * + */ + void MosaicWidget::sortByResolution(){ + sortBy( ResolutionColumn ); + } + void MosaicWidget::sortByEmission(){ + sortBy( EmissionColumn ); + } + void MosaicWidget::sortByIncidence(){ + sortBy( IncidenceColumn ); + } + void MosaicWidget::sortByIsland(){ + sortBy( IslandColumn ); + } + + + /** + * This method loops through all the items in the selected + * group(s) and sorts them based on the requested sort type. + * + */ + void MosaicWidget::sortBy( ColumnIndex index ){ + //------------------------------------------ + // Get make a QList of the selected group(s). + //------------------------------------------ + QList groupItems = selectedGroups(); + if(groupItems.isEmpty()) return; + + for(int i = 0; i < groupItems.size(); i++) { + QListchildren = groupItems[i]->takeChildren(); + + if( index == ResolutionColumn ) { + std::sort(children.begin(), children.end(), sortResolution); + } + if( index == EmissionColumn ) { + std::sort(children.begin(), children.end(), sortEmission); + } + if( index == IncidenceColumn ) { + std::sort(children.begin(), children.end(), sortIncidence); + } + if( index == IslandColumn ) { + std::sort(children.begin(), children.end(), sortIsland); + } + + groupItems[i]->insertChildren(0, children); + //--------------------------- + // Get the Z-ordering correct. + //--------------------------- + reorderGroupZValues(groupItems[i]); + } + //--------------------------------------------------- + // Get the p_mosaicItems list in the right order too. + //--------------------------------------------------- + reorderMosaicItemsList(); + } + + + /** + * + * + * + * @param resolution + */ + void MosaicWidget::updateScreenResolution(double resolution){ + p_screenResolution = resolution; + } + + + /** + * This method is called from the context menu. + * It allows the user to select which item they would like + * to zoom to, and that item is then fit in the view. + * + */ + void MosaicWidget::zoomToItem(){ + MosaicItem *mosaicItem = selectedMosaicItems().last(); + double ymin = mosaicItem->YMinimum(); + double xmin = mosaicItem->XMinimum(); + double xmax = mosaicItem->XMaximum(); + double ymax = mosaicItem->YMaximum(); + p_graphicsView->fitInView(xmin-5, ymin-5, (xmax-xmin), (ymax-ymin), Qt::KeepAspectRatio); + } + + + /** + * This is called from the std::sort method if the requested + * sort is a resolution sort. + * + * + * @param a + * @param b + * + * @return bool + */ + bool sortResolution(QTreeWidgetItem *a,QTreeWidgetItem *b){ + return a->text(MosaicWidget::ResolutionColumn).toDouble() < b->text(MosaicWidget::ResolutionColumn).toDouble(); + } + + + /** + * This is called from the std::sort method if the requested + * sort is an emission angle sort. + * + * + * @param a + * @param b + * + * @return bool + */ + bool sortEmission(QTreeWidgetItem *a,QTreeWidgetItem *b){ + return a->text(MosaicWidget::EmissionColumn).toDouble() < b->text(MosaicWidget::EmissionColumn).toDouble(); + } + + /** + * This is called from the std::sort method if the requested + * sort is an incidence sort. + * + * + * @param a + * @param b + * + * @return bool + */ + bool sortIncidence(QTreeWidgetItem *a,QTreeWidgetItem *b){ + return a->text(MosaicWidget::IncidenceColumn).toDouble() < b->text(MosaicWidget::IncidenceColumn).toDouble(); + } + + /** + * This is called from the std::sort method if the requested sort is an island + * sort + * + * @param a + * @param b + * + * @return bool + */ + bool sortIsland(QTreeWidgetItem *a,QTreeWidgetItem *b){ + return a->text(MosaicWidget::IslandColumn).toInt() < b->text(MosaicWidget::IslandColumn).toInt(); + } + +} diff --git a/isis/src/qisis/objs/MosaicWidget/MosaicWidget.h b/isis/src/qisis/objs/MosaicWidget/MosaicWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..eaaa5cf015b58b2d0d7f6526cc71b57e1bca5cb2 --- /dev/null +++ b/isis/src/qisis/objs/MosaicWidget/MosaicWidget.h @@ -0,0 +1,286 @@ +#ifndef MosaicWidget_H +#define MosaicWidget_H + +#include +#include +#include +#include +#include + +#include +class QToolButton; + +#include "ControlNet.h" +#include "Filename.h" +#include "MosaicTreeWidget.h" +#include "Projection.h" + +namespace Qisis { +class MosaicItem; +class MosaicMainWindow; +class MosaicZoomTool; +class MosaicPanTool; +class MosaicSelectTool; +class MosaicTrackTool; +class MosaicPointTool; +class MosaicControlNetTool; +class MosaicFindTool; + + class MosaicWidget : public QSplitter { + /** + * @brief + * + * @ingroup Visualization Tools + * + * @author Stacy Alley + * + * @internal + * + * @history 2010-05-10 Christopher Austin - added cnet connectivity + * functionality and fixed a few design issues + */ + Q_OBJECT + + public: + MosaicWidget(QWidget *parent = 0); + + /** + * Returns the selected projection type. + * + * + * @return Isis::Projection* + */ + Isis::Projection *projection() const { return p_projection; }; + + /** + * + * + * + * @return Isis::ControlNet* + */ + Isis::ControlNet *controlNet() const { return p_cn; }; + void setControlNet( Isis::Filename cnet ); + + void hideControlPoints(); + void displayConnectivity( bool connected ); + + /** + * Returns the graphics scene. + * + * + * @return QGraphicsScene* + */ + QGraphicsScene *scene() const { return p_graphicsScene; }; + + /** + * + * + * + * @return double + */ + double screenResolution() { return p_screenResolution; }; + + /** + * Returns a list of all the mosaic items. + * + * + * @return QList* + */ + const QList &mosaicItems() const { return p_mosaicItems; }; + + + QList allMosaicItems(); + void updateScreenResolution(double resolution); + + // This is the column number for each column + enum ColumnIndex { + NameColumn = 0, + ItemColumn = 1, + FootprintColumn = 2, + OutlineColumn = 3, + ImageColumn = 4, + LabelColumn = 5, + ResolutionColumn = 6, + EmissionColumn = 7, + IncidenceColumn = 8, + IslandColumn = 9, + NotesColumn = 10 + }; + + public slots: + void addGroup(const QString &groupName); + void deleteGroup(const QString &groupName); + + void addItem(MosaicItem *item, QString groupName = "Group1"); + void addItem(QString itemName); + + void open(); + void openList(); + + void setProjection(Isis::Projection *proj); + void setLonDomain(QString domain); + + void updateGraphicsView(QTreeWidgetItem *item, int column); + void updateGraphicsView(); + void updateTreeWidget(); + + void refit(); + + void viewMenuAction(QAction *action); + + /** + * Returns the number of items currently in the scene. + * + * + * @return int + */ + int numItems() const { return p_graphicsScene->items().size(); }; + void setLabelText(QString text){p_mapDisplay->setText(text);} + + void reprojectItems(); + void saveList(QString filename); + void saveProject(QString filename); + void readProject(QString filename); + void setMapFile(QString mapfile); + void setMapFile(); + + protected: + + private slots: + //void itemChanged(QTreeWidgetItem * item, int column); + void groupChanged(QTreeWidgetItem * item, int column); + void dropAction(QPoint point); + void bringToFront(); + void sendToBack(); + void moveUpOne(); + void moveDownOne(); + void cut(); + void paste(); + void paste(QPoint point); + void changeColor(); + void changeTransparency(); + void renameGroup(); + void hideItem(); + void showItem(); + void showItem(MosaicItem *item); + void hideImage(); + void hideImage(MosaicItem *item); + void setReferenceItemVisible(bool show); + void showImage(); + void showImage(MosaicItem *item); + void hideLabel(); + void showLabel(); + void hideOutline(); + void showOutline(); + void hideFootprint(); + void showFootprint(); + void setLabelFont(); + void contextMenuEvent(QContextMenuEvent * event); + void changeLevelOfDetail(int detail); + void deleteCube(); + void deleteAllCubes(); + void insertCube(); + void addGroup(); + void deleteGroup(); + void mergeGroups(); + void readFile(QString listFile); + void displayControlPoints(); + void sortByResolution(); + void sortByEmission(); + void sortByIncidence(); + void sortByIsland(); + void zoomToItem(); + + private: + void initWidget(); + void insertCube(MosaicItem *item); + bool eventFilter(QObject *o,QEvent *e); + + void bringToFront(MosaicItem *item); + void bringToFront(QTreeWidgetItem *group); + + void sendToBack(MosaicItem *item); + void sendToBack(QTreeWidgetItem *group); + + void moveUpOne(MosaicItem *item); + void moveUpOne(QTreeWidgetItem *group); + + void moveDownOne(MosaicItem *item); + void moveDownOne(QTreeWidgetItem *group); + + void fixZValue(QTreeWidgetItem *groupItem); + void setInitialZValue(QTreeWidgetItem *groupItem); + + void reorderAllZValues(); + void reorderGroupZValues(QTreeWidgetItem *groupItem); + void reorderMosaicItemsList(); + + void createReferenceFootprint(); + void findPoint(QPointF p); + + void sortBy( ColumnIndex index ); + + QList selectedGroups(); //!< List of the selected groups in the tree widget. + QList selectedMosaicItems(); //!< List of the selected items in the tree widget. + + MosaicMainWindow *p_parent; //!< This object's parent + + QMenu* contextMenu();//!< The menu that pops up with a right mouse click. + Isis::Projection *p_projection; //!< The current projection type. + QGraphicsScene *p_graphicsScene; //!< The graphics scene that makes up this widget. + QGraphicsView *p_graphicsView; //!< The graphics view + MosaicTreeWidget *p_treeWidget; //!< The tree widget that makes up this widget. + QList p_pasteItems; //!< A list of items that can be pasted into a new group. + QTreeWidgetItem *p_pasteGroup; //!< The group at which the paste items would like to be pasted in. + QGraphicsTextItem *p_textItem; // !< A graphics items used to display messages in the graphics scene. + + QMap p_groupToTreeMap;//!< + QList p_mosaicItems; //!< A list of all the currently display mosaic items. + QMap p_treeToMosaicMap; + + double p_xmin; //!< The graphics view's min x value. + double p_xmax; //!< The graphics view's max x value. + double p_ymin; //!< The graphics view's min y value. + double p_ymax; //!< The graphics view's max y value. + + QStringList p_filterList;//!< Filter list for the open cube dialog. + QStringList p_filterList2;//!< Filter list for the open list dialog. + QDir p_dir;//!< Directory for the open and open list dialog boxes. + + int p_insertItemAt;//!< Insert item value. + + QLabel *p_mapDisplay; + QToolButton *p_mapFileButton; + QToolButton *p_controlPointButton; + QToolButton *p_connectivityButton; + QToolButton *p_stopProcessButton; + QGraphicsPolygonItem *p_footprintItem; + + QAction *p_pan; + double p_screenResolution; + QRubberBand *p_rubberBand; + QPoint p_origin; + + MosaicZoomTool *p_ztool; + MosaicPanTool *p_ptool; + MosaicSelectTool *p_stool; + MosaicTrackTool *p_ttool; + MosaicPointTool *p_pntool; + MosaicControlNetTool *p_cntool; + MosaicFindTool *p_ftool; + + QString p_mapfile; + QString p_controlnetfile; + QString p_lonDomain; + QTreeWidgetItem *p_dropItem; + Isis::ControlNet *p_cn; + + }; + + bool sortResolution(QTreeWidgetItem *a,QTreeWidgetItem *b); + bool sortEmission(QTreeWidgetItem *a,QTreeWidgetItem *b); + bool sortIncidence(QTreeWidgetItem *a,QTreeWidgetItem *b); + bool sortIsland(QTreeWidgetItem *a,QTreeWidgetItem *b); +}; + +#endif diff --git a/isis/src/qisis/objs/MosaicZoomTool/Makefile b/isis/src/qisis/objs/MosaicZoomTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/MosaicZoomTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/MosaicZoomTool/MosaicZoomTool.cpp b/isis/src/qisis/objs/MosaicZoomTool/MosaicZoomTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3dd3db67c27ffcab29975feb03d35a12637d8da8 --- /dev/null +++ b/isis/src/qisis/objs/MosaicZoomTool/MosaicZoomTool.cpp @@ -0,0 +1,348 @@ +#include "MosaicZoomTool.h" + +#include + +class QHBoxLayout; +class QLabel; + +namespace Qisis { + /** + * MosaicZoomTool constructor + * + * + * @param parent + */ + MosaicZoomTool::MosaicZoomTool (MosaicWidget *parent) : Qisis::MosaicTool(parent) { + p_parent = parent; + connect(this,SIGNAL(activated(bool)),this,SLOT(updateTool())); + + p_zoomIn2X = new QAction(parent); + p_zoomIn2X->setShortcut(Qt::Key_Plus); + p_zoomIn2X->setText("Zoom In"); + p_zoomIn2X->setIcon(QPixmap(toolIconDir()+"/viewmag+.png")); + connect(p_zoomIn2X,SIGNAL(activated()),this,SLOT(zoomIn2X())); + + p_zoomOut2X = new QAction(parent); + p_zoomOut2X->setShortcut(Qt::Key_Minus); + p_zoomOut2X->setText("Zoom Out"); + p_zoomOut2X->setIcon(QPixmap(toolIconDir()+"/viewmag-.png")); + connect(p_zoomOut2X,SIGNAL(activated()),this,SLOT(zoomOut2X())); + + p_zoomActual = new QAction (parent); + p_zoomActual->setShortcut(Qt::Key_Plus); + p_zoomActual->setText("&Actual Pixels"); + p_zoomActual->setIcon(QPixmap(toolIconDir()+"/viewmag1.png")); + connect(p_zoomActual,SIGNAL(activated()),this,SLOT(zoomActual())); + + p_zoomFit = new QAction (parent); + p_zoomFit->setShortcut(Qt::Key_Asterisk); + p_zoomFit->setText("&Fit in Window"); + p_zoomFit->setIcon(QPixmap(toolIconDir()+"/viewmagfit.png")); + connect(p_zoomFit,SIGNAL(activated()),this,SLOT(zoomFit())); + + } + + /** + * Adds the action to the toolpad. + * + * + * @param toolpad + * + * @return QAction* + */ + QAction *MosaicZoomTool::toolPadAction(ToolPad *toolpad) { + QAction *action = new QAction(toolpad); + action->setIcon(QPixmap(toolIconDir()+"/viewmag.png")); + action->setToolTip("Zoom (Z)"); + action->setShortcut(Qt::Key_Z); + QString text = + "Function: Zoom in or out of the current cube. \ +

    Shortcut: Z

    "; + action->setWhatsThis(text); + return action; + } + + + /** + * Adds the zoom action to the given menu. + * + * + * @param menu + */ + void MosaicZoomTool::addToMenu(QMenu *menu) { + menu->addAction(p_zoomFit); + menu->addAction(p_zoomActual); + menu->addAction(p_zoomIn2X); + menu->addAction(p_zoomOut2X); + } + + + /** + * Creates the widget to add to the tool bar. + * + * + * @param parent + * + * @return QWidget* + */ + QWidget *MosaicZoomTool::createToolBarWidget (QStackedWidget *parent) { + QWidget *hbox = new QWidget(parent); + + QToolButton *zoomInButton = new QToolButton(hbox); + zoomInButton->setIcon(QPixmap(toolIconDir()+"/viewmag+.png")); + zoomInButton->setToolTip("Zoom In"); + QString text = + "Function: Zoom in 2X at the center of the active viewport \ +

    Shortcut: +

    \ +

    Mouse: LeftButton zooms in 2X under pointer

    \ +

    Modifiers: Shortcuts and mouse clicks can be augmented \ + using the Ctrl or Alt key for 4X and 8X zooms, respectively

    \ +

    Hint: Left click and drag for a local zoom which scales data \ + in the marquee to the view

    "; + zoomInButton->setWhatsThis(text); + connect(zoomInButton,SIGNAL(clicked()),this,SLOT(zoomIn2X())); + zoomInButton->setAutoRaise(true); + zoomInButton->setIconSize(QSize(22,22)); + + QToolButton *zoomOutButton = new QToolButton(hbox); + zoomOutButton->setIcon(QPixmap(toolIconDir()+"/viewmag-.png")); + zoomOutButton->setToolTip("Zoom Out"); + text = + "Function: Zoom out 2X at the center of the view \ +

    Shortcut: +

    \ +

    Mouse: RightButton zooms out 2X under pointer

    \ +

    Modifiers: Shortcuts and mouse clicks can be augmented \ + using the Ctrl or Alt key for 4X and 8X zooms, respectively

    \ +

    Hint: Left click and drag for a local zoom which scales data \ + in the marquee to the view

    "; + zoomOutButton->setWhatsThis(text); + connect(zoomOutButton,SIGNAL(clicked()),this,SLOT(zoomOut2X())); + zoomOutButton->setAutoRaise(true); + zoomOutButton->setIconSize(QSize(22,22)); + + QToolButton *zoomFitButton = new QToolButton(hbox); + zoomFitButton->setIcon(QPixmap(toolIconDir()+"/viewmagfit.png")); + //zoomFitButton->setMenu(zoomFitMenu); + //zoomFitButton->setPopupMode(QToolButton::MenuButtonPopup); + zoomFitButton->setToolTip("Fit in view"); + text = + "Function: Fit the entire mosaic inside the view. \ +

    Shortcut: *

    \ +

    Hint: Many shortcuts for the zoom tool and other tools \ + are easily available on the numeric keypad

    "; + zoomFitButton->setWhatsThis(text); + connect(zoomFitButton,SIGNAL(clicked()),this,SLOT(zoomFit())); + zoomFitButton->setAutoRaise(true); + zoomFitButton->setIconSize(QSize(22,22)); + + p_scaleBox = new QDoubleSpinBox(); + p_scaleBox->setRange(DBL_MIN, DBL_MAX); + connect(p_scaleBox,SIGNAL(editingFinished()),this,SLOT(zoomManual())); + + QLabel *resolutionLabel = new QLabel("Meters per pixel"); + + QHBoxLayout *layout = new QHBoxLayout(hbox); + layout->setMargin(0); + layout->addWidget(zoomInButton); + layout->addWidget(zoomOutButton); + + //------------------------------------------- + // These two actions are not quite ready yet. + // layout->addWidget(zoomActButton); + //------------------------------------------- + layout->addWidget(zoomFitButton); + layout->addWidget(p_scaleBox); + layout->addWidget(resolutionLabel); + layout->addStretch(1); + hbox->setLayout(layout); + return hbox; + } + + + /** + * Zooms in 2 times. + * + */ + void MosaicZoomTool::zoomIn2X() { + zoomBy(2.0); + } + + + /** + * Zoom out 2 times. + * + */ + void MosaicZoomTool::zoomOut2X() { + zoomBy(1.0/2.0); + } + + + /** + * Zoom back to 1 to 1. + * + */ + void MosaicZoomTool::zoomActual () { + std::cout << "zooming to 1 to 1" << std::endl; + zoomBy(1.1); + } + + + /** + * Zoom IN by the given factor. + * + * + * @param factor + */ + void MosaicZoomTool::zoomBy (double factor) { + //if(isActive()) { + getGraphicsView()->scale(factor, factor); + updateResolutionBox(); + //} + + } + + + /** + * Fits the in the graphics view. + * + */ + void MosaicZoomTool::zoomFit () { + ((MosaicWidget *)p_parent)->refit(); + updateResolutionBox(); + + } + + + /** + * Slot for the "Fit to Width" menu item on the Fit button. + * + */ + void MosaicZoomTool::zoomFitWidth () { + + } + + + /** + * Slot for the "Fit to Heighth" menu item on the Fit button. This will display + * the cube so that the entire cube heighth is displayed. + * + */ + void MosaicZoomTool::zoomFitHeight () { + + } + + + /** + * This method zooms by the value input in the line edit next to + * the zoom tools. + * This method is called when the double spin box value has been + * changed. First we figure out what we need to scale the + * graphics view in order to achive the user's desired screen + * resolution. + * + */ + void MosaicZoomTool::zoomManual () { + double x = p_screenResolution/p_scaleBox->value(); + zoomBy(x); + } + + + /** + * This method updates the line edits text to the correct zoom + * value. + * + */ + void MosaicZoomTool::updateTool() { + //if(isActive()) { + //QList items = getGraphicsView()->scene()->items(); + //for(int i = 0; i < items.size(); i++) { + // items[i]->setFlag(QGraphicsItem::ItemIsSelectable, false); + //} + //} + + updateResolutionBox(); + + } + + + /** + * This method is called when the RubberBandTool is complete. + * The view is centered on the center point of the rubberband's + * rectangle, then zoomed based on the largest side of the + * rectange. (Width or height.) + * + */ + void MosaicZoomTool::rubberBandComplete(QRect r, QGraphicsSceneMouseEvent *mouseEvent) { + double meters_pixel = 0.0; + // The RubberBandTool has a geometry (rectangle) + QRectF s(getGraphicsView()->mapToScene(r.topLeft()), getGraphicsView()->mapToScene(r.bottomRight())); + + //---------------------------------------------------------------- + // If the user does a single click, then we will center where the + // clicked and return. No zooming! + //---------------------------------------------------------------- + if(abs((int)r.bottomRight().x() - (int)r.topLeft().x()) < 6){ + if(mouseEvent->button() == Qt::LeftButton) { + zoomIn2X(); + } + if(mouseEvent->button() == Qt::RightButton) { + zoomOut2X(); + } + getGraphicsView()->centerOn(s.center()); + return; + } + + //-------------------------------------------------------------------- + // We only user width or height to determine the desired meters/pixel. + // Which ever is larger. + //-------------------------------------------------------------------- + if(s.width() > s.height()) { + meters_pixel = s.width() / getGraphicsView()->viewport()->width(); + } else { + meters_pixel = s.height()/ getGraphicsView()->viewport()->height(); + } + + // calculate the scale. + double scale = p_screenResolution / meters_pixel; + + // center the view + getGraphicsView()->centerOn(s.center()); + + // zooming in. + if(mouseEvent->button() == Qt::LeftButton) { + zoomBy(scale); + } + // zooming out. + if(mouseEvent->button() == Qt::RightButton) { + zoomBy(1/scale); + } + //getGraphicsView()->scale(scale,scale); + + updateResolutionBox(); + + } + + + /** + * Updates the text in the screen resolution display box to the + * current screen resolution, in meters per pixel. + * + */ + void MosaicZoomTool::updateResolutionBox(){ + // Using these two points we can calculated the scene's width. + QPointF point1 = getGraphicsView()->mapToScene(0,0); + QPointF point2 = getGraphicsView()->mapToScene((int) getGraphicsView()->width(),0); + double newWidth = point2.x() - point1.x(); + // The scene width divided by the viewport's width gives us the screen res. + p_screenResolution = newWidth/getGraphicsView()->viewport()->width(); + // Update the text box display + p_scaleBox->setValue(p_screenResolution); + //------------------------------------------------------------------------ + // This sets the up and down arrows (on the text box) so that each time a + // user clicks them, a resonable amount of zoom happens. + //------------------------------------------------------------------------ + p_scaleBox->setSingleStep(p_screenResolution*.05); + p_parent->updateScreenResolution(p_screenResolution); + } + +} diff --git a/isis/src/qisis/objs/MosaicZoomTool/MosaicZoomTool.h b/isis/src/qisis/objs/MosaicZoomTool/MosaicZoomTool.h new file mode 100644 index 0000000000000000000000000000000000000000..66210ca1010ddb95a62cb4a32a5b24a1fda9d1b2 --- /dev/null +++ b/isis/src/qisis/objs/MosaicZoomTool/MosaicZoomTool.h @@ -0,0 +1,62 @@ +#ifndef MosaicZoomTool_h +#define MosaicZoomTool_h + +#include "MosaicTool.h" + +class QAction; +class QLineEdit; + +namespace Qisis { + /** + * @brief Handles zoom operations for Isis qt apps + * + * @ingroup Visualization Tools + * + * @author Stacy Alley + * + * @internal + * @history + */ + class MosaicZoomTool : public Qisis::MosaicTool { + Q_OBJECT + + public: + MosaicZoomTool (MosaicWidget *parent); + void addToMenu(QMenu *menu); + void rubberBandComplete(QRect r, QGraphicsSceneMouseEvent *mouseEvent); + void updateResolutionBox(); + + protected slots: + void updateTool(); + + protected: + QAction *toolPadAction(ToolPad *toolpad); + //! Returns the name of the menu. + QString menuName() const { return "&View"; }; + QWidget *createToolBarWidget(QStackedWidget *parent); + + public slots: + void zoomIn2X(); + void zoomOut2X(); + + void zoomActual (); + void zoomFit (); + void zoomFitWidth (); + void zoomFitHeight (); + void zoomManual (); + + private: + void zoomBy (double factor); + QAction *p_zoomIn2X; //!< Zoom in 2 times. + QAction *p_zoomOut2X; //!< Zoom out 2 times. + QAction *p_zoomActual; //!< Zoom to actual size action. + QAction *p_zoomFit; //!< Fit the cube in the viewport action. + QLineEdit *p_zoomLineEdit; //!< Line edit for manual zoom factor. + QDoubleSpinBox *p_scaleBox; + double p_screenResolution; + MosaicWidget *p_parent; + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/PaletteWindow/Makefile b/isis/src/qisis/objs/PaletteWindow/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/PaletteWindow/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/PaletteWindow/PaletteWindow.cpp b/isis/src/qisis/objs/PaletteWindow/PaletteWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ce413e911c4f4e3c135495205e497e701e45b26 --- /dev/null +++ b/isis/src/qisis/objs/PaletteWindow/PaletteWindow.cpp @@ -0,0 +1,98 @@ +#include "PaletteWindow.h" + +namespace Qisis { + /** + * PaletteWindow constructor + * + * + * @param parent + */ + PaletteWindow::PaletteWindow(QWidget *parent) : QMainWindow(parent) { + readSettings(); + parent->installEventFilter(this); + p_appName = parent->windowTitle().toStdString(); + } + + + /** + * This method is overridden so that we can be sure to write the + * current settings of the Palette window. + * + * @param event + */ + void PaletteWindow::closeEvent(QCloseEvent *event) { + writeSettings(); + } + + + /** + * This method ensure that the settings get written even if the + * Palette window was only hidden, not closed. + * + * @param event + */ + void PaletteWindow::hideEvent(QHideEvent *event) { + writeSettings(); + } + + + /** + * This method is called from the constructor so that when the + * Palette window is created, it know's it's size and location. + * + */ + void PaletteWindow::readSettings(){ + std::string instanceName = this->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/"+ p_appName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()),QSettings::NativeFormat); + QPoint pos = settings.value("pos", QPoint(300, 100)).toPoint(); + QSize size = settings.value("size", QSize(900, 500)).toSize(); + resize(size); + move(pos); + } + + + /** + * This method is called when the Palette window is closed or + * hidden to write the size and location settings to a config + * file in the user's home directory. + * + */ + void PaletteWindow::writeSettings() { + /*We do not want to write the settings unless the window is + visible at the time of closing the application*/ + if(!this->isVisible()) return; + + std::string instanceName = this->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/"+ p_appName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()),QSettings::NativeFormat); + settings.setValue("pos", pos()); + settings.setValue("size", size()); + } + + + /** + * This event filter is installed on the parent of this window. + * When the user closes the main window of the application, the + * Palette windows will write their settings even though they did + * not receive the close event themselves. + * + * @param o + * @param e + * + * @return bool + */ + bool PaletteWindow::eventFilter(QObject *o,QEvent *e) { + switch (e->type()) { + case QEvent::Close:{ + writeSettings(); + } + + default: { + return false; + } + } + } + +} + diff --git a/isis/src/qisis/objs/PaletteWindow/PaletteWindow.h b/isis/src/qisis/objs/PaletteWindow/PaletteWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..5a8f174a75e4688b643ee8628d24df4a592743fb --- /dev/null +++ b/isis/src/qisis/objs/PaletteWindow/PaletteWindow.h @@ -0,0 +1,30 @@ +#ifndef PaletteWindow_h +#define PaletteWindow_h +#include +#include +#include +#include "Filename.h" + +namespace Qisis { + + + class PaletteWindow : public QMainWindow { + Q_OBJECT + public: + PaletteWindow (QWidget *parent=0); + void closeEvent(QCloseEvent *event); + void hideEvent(QHideEvent *event); + void readSettings(); + void writeSettings(); + + protected: + bool eventFilter(QObject *o,QEvent *e); + + private: + std::string p_appName; //!< Application name. + + + }; +}; + +#endif diff --git a/isis/src/qisis/objs/PanTool/Makefile b/isis/src/qisis/objs/PanTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/PanTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/PanTool/PanTool.cpp b/isis/src/qisis/objs/PanTool/PanTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aaa58e7c3fd07d37bc71f3fc03c38862f71e1068 --- /dev/null +++ b/isis/src/qisis/objs/PanTool/PanTool.cpp @@ -0,0 +1,276 @@ +#include "PanTool.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MainWindow.h" +#include "MdiCubeViewport.h" +#include "ToolPad.h" + +namespace Qisis { + PanTool::PanTool (QWidget *parent) : Qisis::Tool(parent) { + p_panRight = new QAction (parent); + p_panRight->setShortcut(Qt::CTRL+Qt::Key_Right); + p_panRight->setText("&Pan Right"); + p_panRight->setIcon(QPixmap(toolIconDir()+"/forward.png")); + connect(p_panRight,SIGNAL(activated()),this,SLOT(panRight())); + + p_panLeft = new QAction (parent); + p_panLeft->setShortcut(Qt::CTRL+Qt::Key_Left); + p_panLeft->setText("&Pan Left"); + p_panLeft->setIcon(QPixmap(toolIconDir()+"/back.png")); + connect(p_panLeft,SIGNAL(activated()),this,SLOT(panLeft())); + + p_panUp = new QAction (parent); + p_panUp->setShortcut(Qt::CTRL+Qt::Key_Up); + p_panUp->setText("&Pan Up"); + p_panUp->setIcon(QPixmap(toolIconDir()+"/up.png")); + connect(p_panUp,SIGNAL(activated()),this,SLOT(panUp())); + + p_panDown = new QAction (parent); + p_panDown->setShortcut(Qt::CTRL+Qt::Key_Down); + p_panDown->setText("&Pan Down"); + p_panDown->setIcon(QPixmap(toolIconDir()+"/down.png")); + connect(p_panDown,SIGNAL(activated()),this,SLOT(panDown())); + + p_dragPan = false; + } + + QAction *PanTool::toolPadAction(ToolPad *pad) { + QAction *action = new QAction(pad); + action->setIcon(QPixmap(toolIconDir()+"/move.png")); + action->setToolTip("Pan (P)"); + action->setShortcut(Qt::Key_P); + QString text = + "Function: View different areas of the cube. \ +

    Shortcut: P

    "; + action->setWhatsThis(text); + return action; + } + + void PanTool::addTo (QMenu *menu) { + menu->addAction(p_panLeft); + menu->addAction(p_panRight); + menu->addAction(p_panUp); + menu->addAction(p_panDown); + } + + QWidget *PanTool::createToolBarWidget (QStackedWidget *parent) { + QWidget *hbox = new QWidget(parent); + + QToolButton *leftButton = new QToolButton(hbox); + leftButton->setIcon(QPixmap(toolIconDir()+"/back.png")); + leftButton->setToolTip("Pan Left"); + QString text = + "Function: Pan cube in the active viewport to the left \ +

    Shortcut: Ctrl+LeftArrow

    \ +

    Mouse: Hold LeftButton and drag pointer to the right

    \ +

    Hint: Arrow keys without Ctrl modifier moves \ + the mouse pointer

    "; + + leftButton->setWhatsThis(text); + leftButton->setAutoRaise(true); + leftButton->setIconSize(QSize(22,22)); + connect(leftButton,SIGNAL(clicked()),this,SLOT(panLeft())); + + QToolButton *rightButton = new QToolButton(hbox); + rightButton->setIcon(QPixmap(toolIconDir()+"/forward.png")); + rightButton->setToolTip("Pan Right"); + text = + "Function: Pan cube in the active viewport to the right \ +

    Shortcut: Ctrl+RightArrow

    \ +

    Mouse: Hold LeftButton and drag pointer to the left

    \ +

    Hint: Arrow keys without Ctrl modifier moves \ + the mouse pointer

    "; + rightButton->setWhatsThis(text); + rightButton->setAutoRaise(true); + rightButton->setIconSize(QSize(22,22)); + connect(rightButton,SIGNAL(clicked()),this,SLOT(panRight())); + + QToolButton *upButton = new QToolButton(hbox); + upButton->setIcon(QPixmap(toolIconDir()+"/up.png")); + upButton->setToolTip("Pan Up"); + text = + "Function: Pan cube in the active viewport up \ +

    Shortcut: Ctrl+UpArrow

    \ +

    Mouse: Hold LeftButton and drag pointer down

    \ +

    Hint: Arrow keys without Ctrl modifier moves \ + the mouse pointer

    "; + upButton->setWhatsThis(text); + upButton->setAutoRaise(true); + upButton->setIconSize(QSize(22,22)); + connect(upButton,SIGNAL(clicked()),this,SLOT(panUp())); + + QToolButton *downButton = new QToolButton(hbox); + downButton->setIcon(QPixmap(toolIconDir()+"/down.png")); + downButton->setToolTip("Pan Down"); + text = + "Function: Pan cube in the active viewport down \ +

    Shortcut: Ctrl+DownArrow

    \ +

    Mouse: Hold LeftButton and drag pointer up

    \ +

    Hint: Arrow keys without Ctrl modifier moves \ + the mouse pointer

    "; + downButton->setWhatsThis(text); + downButton->setAutoRaise(true); + downButton->setIconSize(QSize(22,22)); + connect(downButton,SIGNAL(clicked()),this,SLOT(panDown())); + + p_panRateBox = new QComboBox(hbox); + p_panRateBox->addItem("1/4 Screen"); + p_panRateBox->addItem("1/2 Screen"); + p_panRateBox->addItem("3/4 Screen"); + p_panRateBox->addItem("Full Screen"); + p_panRateBox->addItem("Custom"); + p_panRateBox->setToolTip("Pan Rate"); + text = + "Function: Change the rate of panning when using the pan buttons \ + or Ctrl+ArrowKeys"; + p_panRateBox->setWhatsThis(text); + //p_panRateBox->setCurrentIndex(4); + connect(p_panRateBox,SIGNAL(activated(int)), + this,SLOT(updateLineEdit())); + + p_lineEdit = new QLineEdit(); + p_lineEdit->setFixedWidth(50); + p_lineEdit->setToolTip("Custom Pan Rate"); + text = "Function: Enter a custom percentage pan rate"; + p_lineEdit->setWhatsThis(text); + //p_lineEdit->setText("75"); + connect(p_lineEdit,SIGNAL(returnPressed()), + this,SLOT(writeSettings())); + + QIntValidator *ival = new QIntValidator(hbox); + ival->setRange(1,100); + p_lineEdit->setValidator(ival); + QLabel *percent = new QLabel("%"); + + QHBoxLayout *layout = new QHBoxLayout(hbox); + layout->setMargin(0); + layout->addWidget(leftButton); + layout->addWidget(rightButton); + layout->addWidget(upButton); + layout->addWidget(downButton); + layout->addWidget(p_panRateBox); + layout->addWidget(p_lineEdit); + layout->addWidget(percent); + layout->addStretch(1); + hbox->setLayout(layout); + + readSettings(); + + return hbox; + } + + int PanTool::panRate (bool horz) { + MdiCubeViewport *d = cubeViewport(); + if (d == NULL) return 0; + if (p_lineEdit->text() == "") { + QString text = "You must enter a value in the text box \n " + "to use the Custom pan percentage option"; + QMessageBox::information(p_panRateBox,"Invalid Value", + text,QMessageBox::Ok); + return -1; + } + else { + int percent = p_lineEdit->text().toInt(); + if (horz) { + return(int)(d->viewport()->width() * (percent * 0.01)); + } + else { + return(int)(d->viewport()->height() * (percent * 0.01)); + } + } + } + + void PanTool::pan (int x, int y) { + MdiCubeViewport *d = cubeViewport(); + if (d == NULL) return; + if (x == -1 || y == -1) return; + d->scrollBy(x,y); + + if (d->isLinked()) { + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + d = (*(cubeViewportList()))[i]; + if (d == cubeViewport()) continue; + if (d->isLinked()) d->scrollBy(x,y); + } + } + } + + void PanTool::mouseButtonPress(QPoint p, Qt::MouseButton s) { + if (s == Qt::LeftButton) { + p_dragPan = true; + p_lastPoint = p; + } + } + + void PanTool::mouseMove(QPoint p) { + if (p_dragPan) { + QPoint diff = p_lastPoint - p; + pan(diff.x(),diff.y()); + p_lastPoint = p; + } + } + + void PanTool::mouseButtonRelease(QPoint p, Qt::MouseButton s) { + p_dragPan = false; + if (s != Qt::RightButton) return; + + MdiCubeViewport *d = cubeViewport(); + if (d == NULL) return; + double cx,cy; + d->viewportToCube(p.x(),p.y(),cx,cy); + d->center(cx,cy); + + if (d->isLinked()) { + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + d = (*(cubeViewportList()))[i]; + if (d == cubeViewport()) continue; + if (d->isLinked()) { + d->viewportToCube(p.x(),p.y(),cx,cy); + d->center(cx,cy); + } + } + } + } + + + void PanTool::setCustom() { p_panRateBox->setCurrentIndex(4); } + + + void PanTool::updateLineEdit() { + if (p_panRateBox->currentIndex() == 0) p_lineEdit->setText("25"); + else if (p_panRateBox->currentIndex() == 1) p_lineEdit->setText("50"); + else if (p_panRateBox->currentIndex() == 2) p_lineEdit->setText("75"); + else if (p_panRateBox->currentIndex() == 3) p_lineEdit->setText("100"); + else if (p_panRateBox->currentIndex() == 4) p_lineEdit->setText(""); + } + + void PanTool::writeSettings() { + Isis::Filename config("$HOME/.Isis/qview/Pan Tool.config"); + QSettings settings(QString::fromStdString(config.Expanded()), + QSettings::NativeFormat); + settings.setValue("rate", p_lineEdit->text()); + } + + void PanTool::readSettings(){ + Isis::Filename config("$HOME/.Isis/qview/Pan Tool.config"); + QSettings settings(QString::fromStdString(config.Expanded()), + QSettings::NativeFormat); + QString rate = settings.value("rate", "75").toString(); + + p_lineEdit->setText(rate); + if(rate == "100") p_panRateBox->setCurrentIndex(3); + else if(rate == "75") p_panRateBox->setCurrentIndex(2); + else if(rate == "50") p_panRateBox->setCurrentIndex(1); + else if(rate == "25") p_panRateBox->setCurrentIndex(0); + else p_panRateBox->setCurrentIndex(4); + } + +} diff --git a/isis/src/qisis/objs/PanTool/PanTool.h b/isis/src/qisis/objs/PanTool/PanTool.h new file mode 100644 index 0000000000000000000000000000000000000000..d9b6e451015847277355b86e3413b15c246eed4d --- /dev/null +++ b/isis/src/qisis/objs/PanTool/PanTool.h @@ -0,0 +1,60 @@ +#ifndef PanTool_h +#define PanTool_h + +#include "Tool.h" + + +class QComboBox; +class QLineEdit; + +namespace Qisis { + /** + * @internal + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport + * - Fixed multiple include problems + */ + class PanTool : public Qisis::Tool { + Q_OBJECT + + public: + PanTool (QWidget *parent); + void addTo (QMenu *); + + protected: + QString menuName() const { return "&View"; }; + QAction *toolPadAction(ToolPad *pad); + QWidget *createToolBarWidget (QStackedWidget *parent); + + protected slots: + void mouseButtonPress(QPoint p, Qt::MouseButton s); + void mouseMove(QPoint p); + void mouseButtonRelease(QPoint p, Qt::MouseButton s); + + private slots: + void panRight() { pan(panRate(true),0); }; + void panLeft() { pan(-panRate(true),0); }; + void panUp() { pan(0,-panRate(false)); }; + void panDown() { pan(0,panRate(false)); }; + void setCustom(); + void updateLineEdit(); + void writeSettings(); + void readSettings(); + + private: + void pan(int x, int y); + int panRate(bool horz); + + QAction *p_panRight; + QAction *p_panLeft; + QAction *p_panUp; + QAction *p_panDown; + + QComboBox *p_panRateBox; + QLineEdit *p_lineEdit; + + bool p_dragPan; + QPoint p_lastPoint; + }; +}; + +#endif diff --git a/isis/src/qisis/objs/PlotCurve/Makefile b/isis/src/qisis/objs/PlotCurve/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/PlotCurve/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/PlotCurve/PlotCurve.cpp b/isis/src/qisis/objs/PlotCurve/PlotCurve.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b540c7710847a510f0dda430db932a099cbf5dcf --- /dev/null +++ b/isis/src/qisis/objs/PlotCurve/PlotCurve.cpp @@ -0,0 +1,218 @@ +#include "PlotCurve.h" + +#include +#include +#include +#include +#include + +#include "PlotTool.h" +#include "SpecialPixel.h" + +namespace Qisis { + /** + * Constructs and instance of a PlotCurve with some default + * properties. + */ + PlotCurve::PlotCurve () : QwtPlotCurve() { + //The default is to show the symbols but not the curves. + setVisible(false); + setSymbolVisible(true); + + p_symbolStyle.setStyle(QwtSymbol::XCross); + p_symbolStyle.setSize(6,6); + p_markerPen.setColor(this->pen().color()); + } + + + /** + * This method sets the data for the curve, then sets the value + * for the markers associated with the curve. + * @param data + */ + void PlotCurve::setData(const QwtData &data){ + //set the data for the curve + this->QwtPlotCurve::setData(data); + //now we can set up the marker list and set the data for them. + for(int i = 0; isetValue(data.x(i), data.y(i)); + marker->setAxis(this->xAxis(), this->yAxis()); + p_plotMarkers.push_back( marker); + + } + + } + } + + + /** + * This method sets the data for the curve, then sets the value + * for the markers associated with the curve. + * @param xData + * @param yData + * @param size + */ + void PlotCurve::setData(const double *xData, const double *yData, int size){ + /*set the data for the curve*/ + this->QwtPlotCurve::setData(xData, yData, size); + /*now we can set up the marker list and set the data for them.*/ + for(int i = 0; isetValue(xData[i], yData[i]); + marker->setAxis(this->xAxis(), this->yAxis()); + //marker->setVisible(true); + //setSymbolVisible(true); + p_plotMarkers.push_back( marker); + } + } + + } + + + /** + * This method allows the user to set the color of the curve and + * it's markers. + * @param c + */ + void PlotCurve::setColor(QColor c){ + this->setPen(QPen(c)); + } + + + /** + * This method removes all the curves and markers from the plot. + */ + void PlotCurve::detach(){ + QwtPlotCurve::detach(); + for(int i = 0; idetach(); + } + } + + + /** + * This method allows the users to copy all of the given curves + * properties into the current curve. + * @param pc + */ + void PlotCurve::copyCurveProperties(const PlotCurve *pc){ + this->setVisible(pc->isVisible()); + this->setPen(pc->pen()); + this->setTitle(pc->title().text()); + this->setData(pc->data()); + this->setSymbolColor(pc->symbolColor()); + this->setSymbolStyle(pc->symbolStyle().style()); + this->setSymbolVisible(pc->isSymbolVisible()); + } + + + /** + * This method returns the shape of the markers. + * + * @return QwtSymbol + */ + QwtSymbol PlotCurve::symbolStyle() const { + return p_symbolStyle; + } + + + /** + * This method sets the shape of the markers. + * @param style + */ + void PlotCurve::setSymbolStyle(QwtSymbol::Style style){ + p_symbolStyle.setStyle(style); + for(int i = 0; isetSymbol(p_symbolStyle); + p_plotMarkers[i]->setVisible(p_markerIsVisible); + } + } + + + /** + * This method returns the color of the curve's markers. + * + * @return QColor + */ + QColor PlotCurve::symbolColor() const { + return p_markerPen.color(); + } + + + /** + * This method sets the color of the curve's markers. + * @param c + */ + void PlotCurve::setSymbolColor(const QColor &c){ + p_markerPen.setColor(c); + } + + + /** + * This methods hides/shows the curve's markers. + * @param visible + */ + void PlotCurve::setSymbolVisible(bool visible){ + p_markerIsVisible = visible; + for(int i = 0; isetSymbol(p_symbolStyle); + p_plotMarkers[i]->setVisible(p_markerIsVisible); + } + } + + + /** + * Sets the plot pen to the passed-in pen. + * + * + * @param pen + */ + void PlotCurve::setPen(const QPen &pen){ + this->QwtPlotCurve::setPen(pen); + + setSymbolColor(pen.color()); + p_symbolStyle.setPen(p_markerPen); + for(int i = 0; isetSymbol(p_symbolStyle); + p_plotMarkers[i]->setVisible(p_markerIsVisible); + } + + } + + + /** + * This method returns a bool indicating if the curve's markers + * are visible. + * + * @return bool + */ + bool PlotCurve::isSymbolVisible() const { + return p_markerIsVisible; + } + + + /** + * This method attachs the curves's markers to the plot. + * @param plot + */ + void PlotCurve::attachSymbols(QwtPlot *plot){ + p_symbolStyle.setPen(p_markerPen); + for(int i = 0; isetSymbol(p_symbolStyle); + p_plotMarkers[i]->setVisible(p_markerIsVisible); + p_plotMarkers[i]->attach(plot); + } + } + +} diff --git a/isis/src/qisis/objs/PlotCurve/PlotCurve.h b/isis/src/qisis/objs/PlotCurve/PlotCurve.h new file mode 100644 index 0000000000000000000000000000000000000000..4493217691d12cd19b2e47590e6639f9982e8c3d --- /dev/null +++ b/isis/src/qisis/objs/PlotCurve/PlotCurve.h @@ -0,0 +1,64 @@ + +#ifndef PlotCurve_h +#define PlotCurve_h + + +/** + * @file + * $Revision: 1.4 $ + * $Date: 2008/10/07 16:30:34 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include + +namespace Qisis { + class PlotCurve : public QwtPlotCurve { + + public: + PlotCurve(); + void attachSymbols(QwtPlot *plot); + void copyCurveProperties(const PlotCurve *pc); + void detach(); + bool isSymbolVisible() const; + QColor symbolColor() const; + QwtSymbol symbolStyle() const; + + void setColor(QColor c); + void setData(const QwtData &data); + void setData(const double *xData, const double *yData, int size); + void setPen(const QPen &pen); + void setSymbolColor(const QColor &c); + void setSymbolStyle(QwtSymbol::Style style); + void setSymbolVisible(bool visible); + + bool p_markerIsVisible;//!< Are the markers visible? + + protected: + QwtSymbol p_symbolStyle; //!< Plot symbols + QList p_plotMarkers;//!< List of the plot markers + QPen p_markerPen;//!< Pen used to draw plot line and markers + + }; +}; +#endif diff --git a/isis/src/qisis/objs/PlotTool/Makefile b/isis/src/qisis/objs/PlotTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/PlotTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/PlotTool/PlotTool.cpp b/isis/src/qisis/objs/PlotTool/PlotTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..49588aac1d7a41bce49940d24cc83f6a54bc0d75 --- /dev/null +++ b/isis/src/qisis/objs/PlotTool/PlotTool.cpp @@ -0,0 +1,1146 @@ +#include "PlotTool.h" + +#include "geos/geom/Polygon.h" +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/geom/Point.h" + +#include "Brick.h" +#include "Cube.h" +#include "InterestOperator.h" +#include "MdiCubeViewport.h" +#include "PlotTool.h" +#include "PlotToolWindow.h" +#include "PlotWindow.h" +#include "PolygonTools.h" +#include "Pvl.h" +#include "RubberBandComboBox.h" +#include "RubberBandTool.h" +#include "Statistics.h" +#include "ToolPad.h" + +using namespace Isis; + +namespace Qisis { + + /** + * This constructs a plot tool. The plot tool graphs either DN values across a + * line, or statistics across a spectrum (bands). + * + * + * @param parent + */ + PlotTool::PlotTool (QWidget *parent) : Qisis::Tool(parent) { + p_spectralRubberBand = NULL; + p_spacialRubberBand = NULL; + RubberBandTool::allowPoints(1); + p_parent = parent; + createWindow(); + setupPlotCurves(); + p_scaled = false; + p_changingInterp = false; + p_action = new QAction(p_plotToolWindow); + p_plotToolWindow->setPlotType("Band"); + p_action->setText("PlotTool"); + p_action->setIcon(QPixmap(toolIconDir()+"/plot.png")); + QObject::connect(p_action,SIGNAL(activated()),this,SLOT(showPlotWindow())); + QObject::connect(this,SIGNAL(viewportChanged()),this,SLOT(viewportSelected())); + p_color = 0; + } + + + /** + * This protected slot is called when user selects a viewport. + * + */ + void PlotTool::viewportSelected(){ + //p_autoScale->setChecked(true); + } + + + /** + * This method is called when the tool is activated by the + * parent, or when the plot mode is changed. It's used to + * activate or change the rubber banding mode to be either + * rectangle or line, depending on the current plot type. + */ + void PlotTool::enableRubberBandTool() { + if(p_spectralRubberBand) { + if (p_currentPlotType == SpatialPlot) { + p_spacialRubberBand->reset(); + + p_spacialRubberBand->setVisible(true); + p_spacialRubberBand->setEnabled(true); + + p_spectralRubberBand->setEnabled(false); + p_spectralRubberBand->setVisible(false); + + plotType->setEnabled(false); + } + else { + p_spectralRubberBand->reset(); + + p_spectralRubberBand->setEnabled(true); + p_spectralRubberBand->setVisible(true); + + p_spacialRubberBand->setVisible(false); + p_spacialRubberBand->setEnabled(false); + + plotType->setEnabled(true); + } + } + } + + + /** + * Changes the text for the hide/show band lines action in the + * Options menu. + * + */ + void PlotTool::showHideLines(){ + if(p_plotToolWindow->p_markersVisible) { + p_showHideLines->setText("Hide Band Line(s)"); + } else{ + p_showHideLines->setText("Show Band Line(s)"); + } + } + + + /** + * This method is connected to the plot type combo box. When the + * user changes it's value, this changes the plot mode. The + * first thing we do is set the new rubber banding for the new + * plot type. Then, we update the plot window's menus. Finally, + * we clear the old plotted lines and reset the plot scale. + * + * + * @param newType + */ + void PlotTool::changePlotType(int newType) { + p_currentPlotType = (PlotType)p_plotTypeCombo->itemData(newType).toInt(); + enableRubberBandTool(); + + QList menu; + QList actionButtons; + + /* menu is the QMenu's at the top of the plot window, while + actionButtons are the buttons directly below.*/ + p_plotToolWindow->getDefaultMenus(menu, actionButtons); + + for(int i = 0; i < menu.size(); i++) { + if(menu[i]->title() == "&Options") { + p_showHideLines = new QAction(p_plotToolWindow); + p_showHideLines->setText("Hide Band Line(s)"); + p_showHideLines->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/camera.png")); + QObject::connect(p_showHideLines,SIGNAL(activated()),p_plotToolWindow, + SLOT(showHideLines())); + QObject::connect(p_showHideLines,SIGNAL(activated()),this, + SLOT(showHideLines())); + menu[i]->addAction(p_showHideLines); + + p_autoScale = new QAction(p_plotToolWindow); + p_autoScale->setText("AutoScale"); + p_autoScale->setCheckable(true); + p_autoScale->setChecked(true); + QString text = + "Function: Turn on/off the auto scale option on the plot."; + p_autoScale->setWhatsThis(text); + menu[i]->addAction(p_autoScale); + actionButtons.push_back(p_autoScale); + + } + } + + if (p_currentPlotType == SpectralPlot) { + p_plotToolWindow->setAxisLabel(QwtPlot::xBottom, "Band"); + p_plotToolWindow->setAxisLabel(QwtPlot::yLeft,"Value"); + + // QAction *example = new QAction(p_plotToolWindow); + // example->setText("Example"); + //example->setIcon(QPixmap("")); + //connect(clear,SIGNAL(activated()),this,SLOT(someSlot())); + QMenu *spectralOptions = new QMenu("&Spectral Options"); + //spectralOptions->addAction(example); + + // -1 is in order to insert before "Help" + menu.insert(menu.size()-1, spectralOptions); + //actionButtons.push_back(example); + } + else if (p_currentPlotType == SpatialPlot) { + // Spatial plot plots value versus pixel (distance). + p_plotToolWindow->setAxisLabel(QwtPlot::xBottom, "Pixel"); + p_plotToolWindow->setAxisLabel(QwtPlot::yLeft, "Value"); + + p_cubicInterp = new QAction(p_plotToolWindow); + p_bilinearInterp = new QAction(p_plotToolWindow); + p_nearestNeighborInterp = new QAction(p_plotToolWindow); + + p_cubicInterp->setText("&Cubic Interpolation"); + p_bilinearInterp->setText("&BiLinear Interpolation"); + p_nearestNeighborInterp->setText("&Nearest Neighbor Interpolation"); + + p_cubicInterp->setCheckable(true); + p_bilinearInterp->setCheckable(true); + p_bilinearInterp->setChecked(true); + p_nearestNeighborInterp->setCheckable(true); + + connect(p_cubicInterp,SIGNAL(activated()),this, + SLOT(cubicInterpolationChanged())); + connect(p_bilinearInterp,SIGNAL(activated()),this, + SLOT(bilinearInterpolationChanged())); + connect(p_nearestNeighborInterp,SIGNAL(activated()),this, + SLOT(nearestInterpolationChanged())); + + QMenu *interpolation = new QMenu("&Interpolation"); + interpolation->addAction(p_cubicInterp); + interpolation->addAction(p_bilinearInterp); + interpolation->addAction(p_nearestNeighborInterp); + + QMenu *spatialOptions = new QMenu("&Spatial Options"); + spatialOptions->addMenu(interpolation); + + // -1 is in order to insert before "Help" + menu.insert(menu.size()-1, spatialOptions); + } + + p_plotToolWindow->setCustomMenu(menu, actionButtons); + p_plotToolWindow->clearPlotCurves(false); + } + + + /** + * + * + * @param toolpad + * + * @return QAction* + */ + QAction *PlotTool::toolPadAction(ToolPad *toolpad) { + QAction *action = new QAction(toolpad); + action->setIcon(QPixmap(toolIconDir()+"/plot.png")); + action->setToolTip("Plot (L)"); + action->setShortcut(Qt::Key_L); + QObject::connect(action,SIGNAL(activated()),this,SLOT(showPlotWindow())); + + QString text = + "Function: Plot values in active viewport \ +

    Shortcut: L

    "; + action->setWhatsThis(text); + return action; + } + + + /** + * Creates the widgets for the tool bar. + * + * + * @param parent + * + * @return QWidget* + */ + QWidget *PlotTool::createToolBarWidget (QStackedWidget *parent) { + QWidget *hbox = new QWidget(parent); + + p_spectralRubberBand = new RubberBandComboBox( + RubberBandComboBox::Polygon | + RubberBandComboBox::Rectangle, + RubberBandComboBox::Rectangle + ); + + p_spacialRubberBand = new RubberBandComboBox( + RubberBandComboBox::Line | + RubberBandComboBox::RotatedRectangle, + RubberBandComboBox::Line, + true + ); + + + QToolButton *newWindowButton = new QToolButton(); + newWindowButton->setText("New"); + newWindowButton->setToolTip("Opens a new blank plot window"); + QString windowText = + "Function: This button will bring up a blank plot window that allows \ + the user to copy and paste curves from the active plot window to other windows \ +

    Shortcut: CTRL+W

    "; + newWindowButton->setWhatsThis(windowText); + newWindowButton->setShortcut(Qt::CTRL+Qt::Key_W); + connect(newWindowButton,SIGNAL(clicked()),this,SLOT(newPlotWindow())); + + QToolButton *plotButton = new QToolButton(); + plotButton->setText("Show"); + plotButton->setToolTip("Shows the active the plot window"); + QString text = + "Function: This button will bring up the plot window that allows \ + the user to view the min, max, and average values of each band in a \ + selected range of the image.

    Shortcut: CTRL+L

    "; + plotButton->setWhatsThis(text); + plotButton->setShortcut(Qt::CTRL+Qt::Key_L); + connect(plotButton,SIGNAL(clicked()),this,SLOT(showPlotWindow())); + + plotType = new QComboBox(hbox); + plotType->addItem("Band Number"); + //plotType->addItem("Wavelength"); + connect(plotType,SIGNAL(activated(int)),this,SLOT(changePlot())); + connect(plotType,SIGNAL(activated(int)),this,SLOT(setPlotType())); + + QHBoxLayout *layout = new QHBoxLayout(hbox); + layout->setMargin(0); + layout->addWidget(p_spectralRubberBand); + layout->addWidget(p_spacialRubberBand); + layout->addWidget(p_plotTypeCombo); + layout->addWidget(plotType); + layout->addWidget(newWindowButton); + layout->addWidget(plotButton); + layout->addStretch(1); + hbox->setLayout(layout); + return hbox; + } + + + /** + * Changes the x axis to band number of wavelength values. + * + */ + void PlotTool::setPlotType(){ + if (plotType->currentText() == "Band Number") { + p_plotToolWindow->setPlotType("Band"); + }else{ + p_plotToolWindow->setPlotType("Wavelength"); + } + + } + + + /** + * Adds the plot tool to the menu. + * + * + * @param menu + */ + void PlotTool::addTo (QMenu *menu) { + menu->addAction(p_action); + } + + + /** + * Updates plot tool. + * + */ + void PlotTool::updateTool() { + + if (cubeViewport() == NULL) { + p_action->setEnabled(false); + } + else { + p_action->setEnabled(true); + + MdiCubeViewport *cvp = cubeViewport(); + p_plotToolWindow->setViewport(cvp); + connect(cvp,SIGNAL(viewportUpdated()),p_plotToolWindow,SLOT(drawBandMarkers())); + + Pvl &pvl = *cvp->cube()->Label(); + PvlGroup &dim = pvl.FindObject("IsisCube") + .FindObject("Core") + .FindGroup("Dimensions"); + int bands = dim["Bands"]; + + if (!pvl.FindObject("IsisCube").HasGroup("BandBin")) { + plotType->removeItem(1); + } + else { + PvlGroup &bandBin = pvl.FindObject("IsisCube") + .FindGroup("BandBin"); + + if (plotType->findText("Wavelength", Qt::MatchExactly) == -1) { + for (int i=0; i < bandBin.Keywords(); i++) { + + if (bandBin[i].Name()== "Center" && bandBin[i].Size() == bands){ + + /*This little chunk of code will be used later when we add the + option to allow plotting by any keyword in the BandBin group. + -------------------------------------------------------------*/ + //if (bandBin[i].Size() == bands && + //plotType->findText(QString(bandBin[i].Name().c_str())) == -1){ + //plotType->addItem(QString(bandBin[i].Name().c_str())); + + plotType->addItem("Wavelength"); + + } + } // end for bandBin.Keywords() + + } else{ + for (int i=0; i < bandBin.Keywords(); i++) { + if (bandBin[i].Name()== "Center" && bandBin[i].Size() != bands){ + + plotType->removeItem(1); + + } + } // end for bandBin.Keywords() + + }// if wavelength is not in drop down already + } + } + } + + + /** + * Creates the active plot window + * + */ + void PlotTool::createWindow() { + p_plotToolWindow = new PlotToolWindow("Active Plot Window", p_parent); + p_plotToolWindow->setBandMarkersVisible(true); + p_plotToolWindow->setDestroyOnClose(false); + p_plotToolWindow->setPlotBackground(Qt::black); + p_plotToolWindow->setDeletable(false); + p_plotToolWindow->setPasteable(false); + connect(p_plotToolWindow, SIGNAL(curveCopied(Qisis::PlotCurve *)), this, + SLOT(copyCurve(Qisis::PlotCurve *))); + + + /* Our configuring the plot window depends on this combo box*/ + p_plotTypeCombo = new QComboBox(); + p_plotTypeCombo->addItem("Spectral Plot", QVariant(SpectralPlot)); + p_plotTypeCombo->addItem("Spatial Plot", QVariant(SpatialPlot)); + connect(p_plotTypeCombo,SIGNAL(activated(int)),this, + SLOT(changePlotType(int))); + changePlotType(0); /* first element is default*/ + } + + + /** + * displays the plot window + * + */ + void PlotTool::showPlotWindow(){ + p_plotToolWindow->showWindow(); + + } + + + /** + * Called when the user has finished drawing with the rubber + * band. ChangePlot is called to plot the data within the + * rubber band. + * + */ + void PlotTool::rubberBandComplete() { + p_plotToolWindow->raise(); + if (RubberBandTool::isValid()) { + changePlot(); + } + else { + QMessageBox::information(p_plotToolWindow,"Error", + "The selected Area contains no valid pixels", + QMessageBox::Ok); + } + } + + + /** + * This method creates and displays a blank plot window in which + * users can paste curves to and copy curves from. + */ + void PlotTool::newPlotWindow(){ + PlotToolWindow *blankWindow = new PlotToolWindow("Plot Window",p_parent); + blankWindow->setDestroyOnClose(true); + connect(blankWindow, SIGNAL(curvePaste(Qisis::PlotWindow *)), this, + SLOT(pasteCurve(Qisis::PlotWindow *))); + connect(blankWindow, SIGNAL(curvePasteSpecial(Qisis::PlotWindow *)), this, + SLOT(pasteCurveSpecial(Qisis::PlotWindow *))); + connect(blankWindow, SIGNAL(curveCopied(Qisis::PlotCurve *)), this, + SLOT(copyCurve(Qisis::PlotCurve *))); + connect(blankWindow, SIGNAL(destroyed(QObject *)), this, + SLOT(removeWindow(QObject *))); + connect(blankWindow, SIGNAL(plotChanged()), this, SLOT(updateViewPort())); + blankWindow->setAxisLabel(QwtPlot::xBottom, p_plotToolWindow->getAxisLabel + (QwtPlot::xBottom).text()); + blankWindow->setAxisLabel(QwtPlot::yLeft, p_plotToolWindow->getAxisLabel + (QwtPlot::yLeft).text()); + blankWindow->setPlotBackground(p_plotToolWindow->getPlotBackground()); + blankWindow->setScale(QwtPlot::xBottom, p_plotToolWindow->p_xMin, + p_plotToolWindow->p_xMax); + blankWindow->setScale(QwtPlot::yLeft, p_plotToolWindow->p_yMin, + p_plotToolWindow->p_yMax); + blankWindow->setPlotTitle(p_plotToolWindow->getPlotTitle().text()); + blankWindow->setDeletable(true); + blankWindow->setPasteable(true); + blankWindow->setCopyEnable(false); + blankWindow->setupDefaultMenu(); + blankWindow->showWindow(); + + p_plotWindows.push_back(blankWindow); + + } + + + /** + * This method replots the data, with current settings and rubber band, in the plot window. + */ + void PlotTool::changePlot() { + MdiCubeViewport *cvp = cubeViewport(); + + /* Delete any current curves*/ + p_plotToolWindow->clearPlotCurves(); + + /* We'll need X-Axis labels and a xMax to scale to.*/ + std::vector labels; + double xMax = 10.0; + Statistics wavelengthStats; + + QString plotTitle = cvp->windowTitle(); + plotTitle.truncate(cvp->windowTitle().lastIndexOf('@')); + + if (p_currentPlotType == SpectralPlot) { + std::vector avgarray,minarray,maxarray,std1array,std2array, + wavelengtharray; + QVector< double > stddevarray; + std::vector plotStats; + + getSpectralStatistics(labels, plotStats); + xMax = labels.size(); + Cube *cube = cvp->cube(); + + Pvl &pvl = *cube->Label(); + + Statistics scalingStats; + for (unsigned int index = 0; index < labels.size(); index++) { + scalingStats.AddData(plotStats[index].Minimum()); + scalingStats.AddData(plotStats[index].Maximum()); + + avgarray.push_back(plotStats[index].Average()); + minarray.push_back(plotStats[index].Minimum()); + maxarray.push_back(plotStats[index].Maximum()); + std1array.push_back(plotStats[index].Average() + + plotStats[index].StandardDeviation()); + std2array.push_back(plotStats[index].Average() - + plotStats[index].StandardDeviation()); + stddevarray.push_back(plotStats[index].StandardDeviation()); + + + if (pvl.FindObject("IsisCube").HasGroup("BandBin")) { + PvlGroup &bandBin = pvl.FindObject("IsisCube").FindGroup("BandBin"); + if (bandBin.HasKeyword("Center")) { + PvlKeyword &wavelength = bandBin.FindKeyword("Center"); + if((unsigned)wavelength.Size()> index) { + wavelengtharray.push_back(wavelength[index]); + wavelengthStats.AddData(wavelength[index]); + } + } + } + } /*end for loop*/ + + double border = (scalingStats.Maximum() - scalingStats.Minimum()) * 0.25; + if(p_autoScale->isChecked()) + p_plotToolWindow->setScale(QwtPlot::yLeft, scalingStats.Minimum() - + border,scalingStats.Maximum() + border); + + if (labels.size() > 0) { + p_avgCurve->setData(&labels[0],&avgarray[0],labels.size()); + p_minCurve->setData(&labels[0],&minarray[0],labels.size()); + p_maxCurve->setData(&labels[0],&maxarray[0],labels.size()); + p_stdDev1Curve->setData(&labels[0],&std1array[0],labels.size()); + p_stdDev2Curve->setData(&labels[0],&std2array[0],labels.size()); + } + + p_plotToolWindow->setStdDev(stddevarray); + p_plotToolWindow->add(p_stdDev1Curve); + p_plotToolWindow->add(p_stdDev2Curve); + p_plotToolWindow->add(p_minCurve); + p_plotToolWindow->add(p_maxCurve); + p_plotToolWindow->add(p_avgCurve); + p_plotToolWindow->setViewport(p_minCurve->getViewPort()); + p_plotToolWindow->drawBandMarkers(); + + /*copy the average curve each time the user re-plots data*/ + copyCurve(p_avgCurve); + p_plotToolWindow->p_curveCopied = true; + + if (plotType->currentText() == "Band Number") { + if(p_autoScale->isChecked()) + p_plotToolWindow->setScale(QwtPlot::xBottom, 1, xMax); + } + else { + if(p_autoScale->isChecked()) + p_plotToolWindow->setScale(QwtPlot::xBottom, wavelengthStats.Minimum(), + wavelengthStats.Maximum()); + } + + if(cvp->isGray()) { + plotTitle.append(QString("- Band %1").arg(cvp->grayBand())); + } + else { + plotTitle.append(QString("- Bands %1, %2, %3").arg(cvp->redBand()).arg(cvp->greenBand()).arg(cvp->blueBand())); + } + } + else if (p_currentPlotType == SpatialPlot) { + std::vector dnValues; + + getSpatialStatistics(labels, dnValues, xMax); + + Statistics scalingStats; + scalingStats.AddData(&dnValues[0], dnValues.size()); + + double border = (scalingStats.Maximum() - scalingStats.Minimum()) * 0.25; + if(p_autoScale->isChecked()) + p_plotToolWindow->setScale(QwtPlot::yLeft, scalingStats.Minimum() - + border, scalingStats.Maximum() + border); + + + + if (labels.size() > 0) { + p_dnCurve->setData(&labels[0],&dnValues[0],labels.size()); + } + + p_plotToolWindow->add(p_dnCurve); + p_plotToolWindow->setViewport(p_minCurve->getViewPort()); + p_plotToolWindow->drawBandMarkers(); + /*copy the dn curve each time the user re-plots data*/ + copyCurve(p_dnCurve); + p_plotToolWindow->p_curveCopied = true; + p_plotToolWindow->fillTable(); + + if(p_autoScale->isChecked()) + p_plotToolWindow->setScale(QwtPlot::xBottom, 1, xMax); + + if(cvp->isGray()) { + plotTitle.append(QString("- Band %1").arg(cvp->grayBand())); + } + else { + plotTitle.append(QString("- Band %1").arg(cvp->redBand())); + } + } + + p_plotToolWindow->setPlotTitle(plotTitle); + p_plotToolWindow->showWindow(); + updateTool(); + } + + + /** + * This method creates a new PlotToolCurve and copies the + * properties of the curve the user clicked on into the new + * curve. The plotWindow class emits a signal when a curve has + * been requested to be copied. + * @param pc + */ + void PlotTool::copyCurve(Qisis::PlotCurve *pc){ + p_copyCurve = new PlotToolCurve(); + p_copyCurve->copyCurveProperties((PlotToolCurve*)pc); + } + + + /** + * This method pastes the copied curve into the given plot + * window. The plotWindow class emits a signal when a paste + * command has taken place inside the window. + * @param pw + */ + void PlotTool::pasteCurve(Qisis::PlotWindow *pw){ + p_cvp = cubeViewport(); + pw->add(p_copyCurve); + updateViewPort(p_copyCurve); + + } + + + /** + * This method does the same as the above method but gives the + * curve a differenet color than the copied curve. + * @param pw + */ + void PlotTool::pasteCurveSpecial(Qisis::PlotWindow *pw){ + p_cvp = cubeViewport(); + if (p_color < p_colors.size()) { + p_copyCurve->setColor(p_colors[p_color]); + } + else { + QColor c = QColorDialog::getColor(Qt::white, p_plotToolWindow); + if (c.isValid()) { + p_copyCurve->setColor(c); + } + } + pw->add(p_copyCurve); + updateViewPort(p_copyCurve); + p_color++; + + } + + + /** + * This class keeps a list of how many plot windows it has + * created (in a QList). When a user closes a window, we want + * to remove that window from our QList. The PlotWindow class + * emits a signal when the window has been destroyed so we can + * call this slot when that signal has been sent. + * @param window + */ + void PlotTool::removeWindow(QObject *window){ + for (int i = 0; i < p_plotWindows.size(); i++) { + + if (p_plotWindows[i] == window) { + p_plotWindows.removeAt(i); + + } + } + updateViewPort(); + + } + + + /** + * This method sets up the names, line style, and color of the + * all the PlotToolCurves that will be used in this class. This + * method also fills the p_colors QList with the colors that + * will be used when the user copies and pastes (special) into + * another plot window. + */ + void PlotTool::setupPlotCurves(){ + p_maxCurve = new PlotToolCurve(); + p_maxCurve->setTitle("Maximum"); + p_minCurve = new PlotToolCurve(); + p_minCurve->setTitle("Minimum"); + p_avgCurve = new PlotToolCurve(); + p_avgCurve->setTitle("Average"); + p_stdDev1Curve = new PlotToolCurve(); + p_stdDev1Curve->setTitle("+ Sigma"); + p_stdDev2Curve = new PlotToolCurve(); + p_stdDev2Curve->setTitle("- Sigma"); + + QPen *pen = new QPen(Qt::white); + pen->setWidth(2); + p_avgCurve->setPen(*pen); + + pen->setColor(Qt::cyan); + pen->setStyle(Qt::DashLine); + p_maxCurve->setPen(*pen); + p_minCurve->setPen(*pen); + + pen->setColor(Qt::red); + pen->setStyle(Qt::DotLine); + p_stdDev1Curve->setPen(*pen); + p_stdDev2Curve->setPen(*pen); + + /*This is for the spatial plot*/ + p_dnCurve = new PlotToolCurve(); + p_dnCurve->setTitle("DN Values"); + pen->setColor(Qt::white); + pen->setWidth(2); + p_dnCurve->setPen(*pen); + + /*Setup colors for paste special*/ + p_colors.push_back(Qt::cyan); + p_colors.push_back(Qt::magenta); + p_colors.push_back(Qt::yellow); + p_colors.push_back(QColor(255,170,255)); + p_colors.push_back(Qt::green); + p_colors.push_back(Qt::white); + p_colors.push_back(Qt::blue); + p_colors.push_back(Qt::red); + p_colors.push_back(QColor(134,66,176)); + p_colors.push_back(QColor(255,152,0)); + + + + } + + + /** + * + * + * @param labels + * @param data + */ + void PlotTool::getSpectralStatistics(std::vector &labels, + std::vector &data) { + MdiCubeViewport *cvp = cubeViewport(); + + if (plotType->currentText() == "Band Number") { + p_plotToolWindow->setAxisLabel(QwtPlot::xBottom,"Band"); + } + else { + p_plotToolWindow->setAxisLabel(QwtPlot::xBottom,"Wavelength"); + } + + QList vertices = RubberBandTool::getVertices(); + + p_avgCurve->setViewPort(cvp); + p_avgCurve->setVertices(vertices); + + p_minCurve->setViewPort(cvp); + p_minCurve->setVertices(vertices); + + p_maxCurve->setViewPort(cvp); + p_maxCurve->setVertices(vertices); + + p_stdDev1Curve->setViewPort(cvp); + p_stdDev1Curve->setVertices(vertices); + + p_stdDev2Curve->setViewPort(cvp); + p_stdDev2Curve->setVertices(vertices); + + if (vertices.size() < 1) return; + + double ss,sl,es,el, x, y; + std::vector x_contained, y_contained; + + // Convert them to line sample values + cvp->viewportToCube(vertices[0].x(),vertices[0].y(),ss,sl); + cvp->viewportToCube(vertices[2].x(),vertices[2].y(),es,el); + + ss = ss + 0.5; + sl = sl + 0.5; + es = es + 0.5; + el = el + 0.5; + + int samps = (int)(es - ss + 1); + if (samps < 1) samps = 1; + Cube *cube = cvp->cube(); + Brick *brick = new Brick(*cube,samps,1,1); + Pvl &pvl = *cvp->cube()->Label(); + + if (RubberBandTool::getMode() == RubberBandTool::Polygon) { + samps = 1; + geos::geom::CoordinateSequence *pts = new geos::geom::CoordinateArraySequence(); + for (int i = 0; i < vertices.size(); i++) { + cvp->viewportToCube(vertices[i].x(),vertices[i].y(),x,y); + pts->add(geos::geom::Coordinate((int)x, (int)y)); + }/*end for*/ + + /*Add the first point again in order to make a closed line string*/ + cvp->viewportToCube(vertices[0].x(),vertices[0].y(),x,y); + pts->add(geos::geom::Coordinate((int)x, (int)y)); + + p_poly = globalFactory.createPolygon + (globalFactory.createLinearRing(pts),NULL); + + p_envelope = p_poly->getEnvelopeInternal(); + + for (int y = (int)floor(p_envelope->getMinY()); y <= (int)ceil(p_envelope->getMaxY()); y++) { + for (int x = (int)floor(p_envelope->getMinX()); x <= (int)ceil(p_envelope->getMaxX()); x++) { + geos::geom::Coordinate c(x,y); + geos::geom::Point *p = globalFactory.createPoint(c); + bool contains = p->within(p_poly); + delete p; + + if(contains) { + x_contained.push_back(x); + y_contained.push_back(y); + } + + } /*end x*/ + }/*end y*/ + } + + + for (int band = 1; band <= cube->Bands(); band++) { + Statistics stats; + + /*Rectangle*/ + if(RubberBandTool::getMode() == RubberBandTool::Rectangle) { + for (int line=(int)std::min(sl,el); line<=(int)std::max(sl,el); line++) { + brick->SetBasePosition((int)ss,line,band); + cube->Read(*brick); + stats.AddData(brick->DoubleBuffer(),samps); + //if(*brick->DoubleBuffer() == Null) { + //if(*brick->DoubleBuffer() == NULL) { + //if(*brick->DoubleBuffer() < 0) { + // std::cout << "band = " << band << " here" << std::endl; + // stats.AddData(0); + //} else { + //stats.AddData(brick->DoubleBuffer(),samps); + // } + + } /*end for*/ + } /*end if Rectangle*/ + + + /*Polygon*/ + if(RubberBandTool::getMode() == RubberBandTool::Polygon) { + + for (unsigned int j = 0; j < x_contained.size(); j++) { + + brick->SetBasePosition(x_contained[j], y_contained[j], band); + cube->Read(*brick); + stats.AddData(*brick->DoubleBuffer()); + + } + + }/*end if Polygon*/ + + if (plotType->currentText() == "Band Number") { + labels.push_back(band); + } + else { + if (pvl.FindObject("IsisCube").HasGroup("BandBin")) { + PvlGroup &bandBin = pvl.FindObject("IsisCube").FindGroup("BandBin"); + if (bandBin.HasKeyword("Center")) { + PvlKeyword &wavelength = bandBin.FindKeyword("Center"); + if(wavelength.Size()> (band-1)) { + labels.push_back(wavelength[band-1]); + } + } + } + } + + if (stats.Average() == Null) { + //stats.Reset(); + //stats.AddData(0); + data.push_back(stats); + + /*if (QMessageBox::information(p_plotToolWindow,"Error", + "The selected Area contains no valid pixels", + QMessageBox::Ok) == QMessageBox::Ok) { + + delete brick; + labels.clear(); + data.clear(); + return; + + }*/ + } else { // end if stats.Average() == null + + data.push_back(stats); + } + } /*end for bands*/ + + if(RubberBandTool::getMode() == RubberBandTool::Polygon) delete p_poly; + delete brick; + + } + + + /** + * + * + * @param labels + * @param data + * @param xmax + */ + void PlotTool::getSpatialStatistics(std::vector &labels, + std::vector &data, double &xmax) { + MdiCubeViewport *cvp = cubeViewport(); + QList vertices = RubberBandTool::getVertices(); + double ss,sl,es,el; + + if (!cvp) return; + + // Convert them to line sample values + cvp->viewportToCube(vertices[0].x(),vertices[0].y(),ss,sl); + cvp->viewportToCube(vertices[1].x(),vertices[1].y(),es,el); + + p_dnCurve->setViewPort(cvp); + p_dnCurve->setVertices(vertices); + + ss = ss + 0.5; + sl = sl + 0.5; + es = es + 0.5; + el = el + 0.5; + + Interpolator interp; + + if (p_cubicInterp->isChecked()) { + interp.SetType(Interpolator::CubicConvolutionType); + } + else if (p_bilinearInterp->isChecked()) { + interp.SetType(Interpolator::BiLinearType); + } + else { + interp.SetType(Interpolator::NearestNeighborType); + } + + Portal dataReader(interp.Samples(), interp.Lines(), cvp->cube()->PixelType()); + + int lineLength = (int)(sqrt(pow(ss-es,2)+pow(sl-el,2)) + 0.5); //round to the nearest pixel increment + int band = ((cvp->isGray())? cvp->grayBand() : cvp->redBand()); + p_plotToolWindow->setAxisLabel(QwtPlot::xBottom, "Data Point"); + xmax = lineLength; + + if(RubberBandTool::getMode() == RubberBandTool::Line) { + for (int index = 0; index < lineLength; index++) { + double x = (index / (double)lineLength) * (es - ss) + ss; // % across * delta x + initial = x position of point + x -= (interp.Samples() / 2.0); // move back for interpolation + double y = (index / (double)lineLength) * (el - sl) + sl; + y -= (interp.Lines() / 2.0); // move back for interpolation + + dataReader.SetPosition(x,y,band); + cvp->cube()->Read(dataReader); + double result = interp.Interpolate(x,y,dataReader.DoubleBuffer()); + + if (!IsSpecial(result)) { + labels.push_back(index+1); + data.push_back(result); + } + } + } + // If its not a line, it must be a rotated rect... + else { + double es2, el2; + + // Convert them to line sample values + cvp->viewportToCube(vertices[3].x(),vertices[3].y(),es2,el2); + + es2 = es2 + 0.5; + el2 = el2 + 0.5; + + // these are for walking across the rotated rect + int numStepsAcross = (int)(sqrt(pow(ss-es2,2)+pow(sl-el2,2)) + 0.5); //round to the nearest pixel increment; + double deltaX = (1.0 / (double)numStepsAcross) * (es2 - ss); + double deltaY = (1.0 / (double)numStepsAcross) * (el2 - sl); + + // walk the "green" line on the screen + for (int index = 0; index < lineLength; index++) { + Statistics lineStats; + double x = (index / (double)lineLength) * (es - ss) + ss; // % across * delta x + initial = x position of point + x -= (interp.Samples() / 2.0); // move back for interpolation + double y = (index / (double)lineLength) * (el - sl) + sl; + y -= (interp.Lines() / 2.0); // move back for interpolation + + // x/y are now the centered on the appropriate place of the green line, i.e. the start of our walk across the rectangle + for(int walkIndex = 0; walkIndex < numStepsAcross; walkIndex++) { + dataReader.SetPosition(x,y,band); + cvp->cube()->Read(dataReader); + double result = interp.Interpolate(x,y,dataReader.DoubleBuffer()); + + if (!IsSpecial(result)) { + lineStats.AddData(result); + } + + x += deltaX; + y += deltaY; + } + + if(!IsSpecial(lineStats.Average())) { + labels.push_back(index+1); + data.push_back(lineStats.Average()); + } + } + } + } + + + /** + * This triggers when cubic interpolation is enabled or disabled + * Since enabling another interpolation will cause cubic to + * become unchecked, if p_changingInterp is true then we'll + * simply exit. Replot the data if we can. + */ + void PlotTool::cubicInterpolationChanged() { + if (p_changingInterp && p_cubicInterp) return; + + p_changingInterp = true; + p_cubicInterp->setChecked(true); + p_bilinearInterp->setChecked(false); + p_nearestNeighborInterp->setChecked(false); + p_changingInterp = false; + + if (RubberBandTool::isValid()) { + changePlot(); + } + } + + + /** + * This triggers when bilinear interpolation is enabled or disabled. + * Since enabling another interpolation will cause bilinear to become + * unchecked, if p_changingInterp is true then we'll simply exit. Replot the + * data if we can. + */ + void PlotTool::bilinearInterpolationChanged() { + if (p_changingInterp && p_cubicInterp) return; + p_changingInterp = true; + p_cubicInterp->setChecked(false); + p_bilinearInterp->setChecked(true); + p_nearestNeighborInterp->setChecked(false); + p_changingInterp = false; + + if (RubberBandTool::isValid()) { + changePlot(); + } + } + + + /** + * This triggers when nearest neighbor interpolation is enabled + * or disabled. Since enabling another interpolation will + * cause nearest neighbor to become unchecked, if + * p_changingInterp is true then we'll simply exit. Replot the + * data if we can. + */ + void PlotTool::nearestInterpolationChanged() { + if (p_changingInterp && p_cubicInterp) return; + + p_changingInterp = true; + p_cubicInterp->setChecked(false); + p_bilinearInterp->setChecked(false); + p_nearestNeighborInterp->setChecked(true); + p_changingInterp = false; + + if (RubberBandTool::isValid()) { + changePlot(); + } + } + + + /** + * This method paints the polygons of the copied curves + * onto the cubeviewport + * + * @param vp + * @param painter + */ + void PlotTool::paintViewport(MdiCubeViewport *vp, QPainter *painter) { + int sample1, line1, sample2, line2; + + // loop thru the window list + for (int i = 0; i < p_plotWindows.size(); i++) { + + for (int c = 0; c < p_plotWindows[i]->getNumCurves(); c++) { + /*get all curves in current window*/ + PlotToolCurve *curve = (PlotToolCurve *)p_plotWindows[i]->getPlotCurve(c); + if (curve->getViewPort() == vp) { + QPen pen(curve->pen().color()); + pen.setWidth(curve->pen().width()); + pen.setStyle(curve->pen().style()); + painter->setPen(pen); + QList points = curve->getVertices(); + + for(int p = 1; p < points.size(); p++) { + vp->cubeToViewport(points[p-1].x(),points[p-1].y(), sample1,line1); + vp->cubeToViewport(points[p].x(),points[p].y(), sample2,line2); + painter->drawLine(QPoint(sample1,line1), QPoint(sample2, line2)); + } + + vp->cubeToViewport(points[points.size()-1].x(), + points[points.size()-1].y(), sample1,line1); + vp->cubeToViewport(points[0].x(),points[0].y(), sample2,line2); + painter->drawLine(QPoint(sample1,line1), QPoint(sample2, line2)); + + } + } + } + + } + + + /** + * This method causes the view port corresponding with the given + * PlotToolCurve to be repainted with all of the area's of + * interest associated with the PlotToolCurve's plotwindow. + * The paintViewport() method is called. + * @param pc + */ + void PlotTool::updateViewPort(Qisis::PlotToolCurve *pc){ + pc->getViewPort()->repaint(); + } + + /** + * This overloaded method is called to repaint the current view + * port. The paintViewport() method is called. + */ + void PlotTool::updateViewPort(){ + p_cvp->viewport()->repaint(); + + } + +} + diff --git a/isis/src/qisis/objs/PlotTool/PlotTool.h b/isis/src/qisis/objs/PlotTool/PlotTool.h new file mode 100644 index 0000000000000000000000000000000000000000..dedf1884c7ba8c99162f2e7aa1f40a80660bd15e --- /dev/null +++ b/isis/src/qisis/objs/PlotTool/PlotTool.h @@ -0,0 +1,145 @@ +#ifndef PlotTool_h +#define PlotTool_h + +// this should be the only include in this file! +#include "Tool.h" + + +// FIXME: remove these includes +#include +#include +#include "geos/geom/Polygon.h" +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/geom/Point.h" +#include +#include "PlotCurve.h" + + +class QComboBox; +class QMainWindow; + +// FIXME: uncomment this +//template< class A, class B > class QMap; + + +namespace Isis { + class Statistics; +} + +namespace Qisis { + class PlotToolCurve; + class PlotToolWindow; + class PlotWindow; + class RubberBandComboBox; + + /** + * @brief plot tool + * + * This class is a plot tool. + * + * @author Stacy Alley + * + * @history 2008-08-18 Christopher Austin - Upgraded to geos3.0.0 + * @history 2008-09-05 Stacy Alley allowed spectral plotting of + * a single point. + * @history 2009-01-29 Steven Lambright - Added RotatedRectangle to the spatial + * plot + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport instead of + * CubeViewport. Fixed some include issues (many still remain!). + */ + class PlotTool : public Tool { + Q_OBJECT + + public: + PlotTool (QWidget *parent); + virtual void paintViewport(MdiCubeViewport *vp,QPainter *painter); + + protected: + //!< Returns the menu name. + QString menuName() const { return "&Options"; }; + QWidget *createToolBarWidget (QStackedWidget *parent); + QAction *toolPadAction(ToolPad *pad); + QAction *p_showHideLines;//!< Hide/show lines action + QAction *p_autoScale;//!< Auto scale the plot + QComboBox *plotType;//!< Plot type combobox + void addTo (QMenu *menu); + void enableRubberBandTool(); + void updateTool(); + + protected slots: + void createWindow(); + virtual void rubberBandComplete(); + void updateViewPort(); + void viewportSelected(); + + public slots: + void changePlot(); + void showPlotWindow(); + void updateViewPort(Qisis::PlotToolCurve *); + void copyCurve(Qisis::PlotCurve *); + void pasteCurve(Qisis::PlotWindow *); + void pasteCurveSpecial(Qisis::PlotWindow *); + void removeWindow(QObject *); + + private slots: + void bilinearInterpolationChanged(); + void changePlotType(int newType); + void cubicInterpolationChanged(); + void nearestInterpolationChanged(); + void newPlotWindow(); + void showHideLines(); + void setPlotType(); + + private: + void getSpectralStatistics(std::vector< double > & labels, + std::vector< Isis::Statistics > & data); + void getSpatialStatistics(std::vector< double > & labels, + std::vector< double > & data, double & xmax); + void setupPlotCurves(); + + /** + * Enum for the different plot types + */ + enum PlotType { + SpectralPlot, //!< Spectral plot + SpatialPlot //!< Spatial plot + }; + + PlotType p_currentPlotType; //!< current plot type + QWidget *p_parent; //!< parent widget + PlotToolWindow *p_plotToolWindow;//!< Plot Tool Window Widget + QMainWindow *p_tableWin; //!< Window for the table + QComboBox *p_plotTypeCombo;//!< Plot type combobox + + QMap p_headerToMenu;//!< Head to menu map + + QAction *p_cubicInterp; //!< Cubic interpolation action + QAction *p_bilinearInterp;//!< Bilinear interpolation action + QAction *p_nearestNeighborInterp;//!< Nearest neighbor interpolation action + QAction *p_action;//!< Plot tool's action + + bool p_changingInterp;//!< Do user change interpolation type? + bool p_scaled;//!< Has the plot been scaled? + + PlotToolCurve *p_maxCurve;//!< Plot curve for max values + PlotToolCurve *p_minCurve;//!< Plot curve for min values + PlotToolCurve *p_avgCurve;//!< Plot curve for average values + PlotToolCurve *p_stdDev1Curve;//!< Plot curve for avg. + std. dev + PlotToolCurve *p_stdDev2Curve;//!< Plot curve for avg. - std. dev + PlotToolCurve *p_copyCurve;//!< Plot curve for copying curves + PlotToolCurve *p_paintCurve;//!< Plot curve for painting + PlotToolCurve *p_dnCurve;//!< Plot curve for DN values + + QList p_colors;//!< List of colors + QList p_plotWindows;//!< List of all plot windows + RubberBandComboBox *p_spectralRubberBand;//!< Spectral plot rubber band combo box + RubberBandComboBox *p_spacialRubberBand;//!< Spacial plot rubber band combo box + + geos::geom::Polygon *p_poly;//!< For plotting/drawing polygons + const geos::geom::Envelope *p_envelope;//!< Bounding box of polygon + int p_color;//!< Keeps track of which color we are at + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/PlotTool/PlotToolCurve.cpp b/isis/src/qisis/objs/PlotTool/PlotToolCurve.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d15ccd39fb5aa65fe4f3a672e23797e9a7e22579 --- /dev/null +++ b/isis/src/qisis/objs/PlotTool/PlotToolCurve.cpp @@ -0,0 +1,82 @@ +#include "PlotToolCurve.h" + +#include + + +namespace Qisis { + /** + * This constructs a PlotToolCurve... a subclass of PlotCurve. + * This class was created specifically for use withthe plot + * tool. With this class the programmer can set the cube view + * port that the curve is associated with along with the + * vertices on the cvp of which the curve gets it data. + */ + PlotToolCurve::PlotToolCurve () : PlotCurve() { + p_cvp = NULL; + } + + + /** + * This method returns a list of points which are the vertices + * of the selected area (by the rubberband) on the cvp. + * + * @return QList + */ + QList PlotToolCurve::getVertices() const { + return p_pointList; + } + + + /** + * This method sets the vertices of the selected area on the + * cvp. + * @param points + */ + void PlotToolCurve::setVertices(const QList &points){ + double sample, line; + p_pointList.clear(); + if(this->getViewPort() == NULL){ + std::cout << "Please be sure to set the view port first!" << std::endl; + } + for(int i = 0; igetViewPort()->viewportToCube(points[i].x(),points[i].y(),sample,line); + p_pointList.push_back(QPointF((sample), ( line))); + } + } + + + /** + * This method returns the cube view port associated with the + * curve. + * + * @return CubeViewport* + */ + CubeViewport* PlotToolCurve::getViewPort() const { + return p_cvp; + } + + + /** + * This method sets the view port. + * @param cvp + */ + void PlotToolCurve::setViewPort(CubeViewport *cvp){ + p_cvp = cvp; + } + + + /** + * This method allows the users to copy all of the given curves + * properties into the current curve. This is an overriden + * function from the PlotCurve class. + * @param pc + */ + void PlotToolCurve::copyCurveProperties(PlotToolCurve *pc){ + PlotCurve::copyCurveProperties(pc); + + p_cvp = pc->getViewPort(); + p_pointList = pc->getVertices(); + } + +} + diff --git a/isis/src/qisis/objs/PlotTool/PlotToolCurve.h b/isis/src/qisis/objs/PlotTool/PlotToolCurve.h new file mode 100644 index 0000000000000000000000000000000000000000..35626303570fdbee0eca71a9af76ed0450b76dcc --- /dev/null +++ b/isis/src/qisis/objs/PlotTool/PlotToolCurve.h @@ -0,0 +1,53 @@ + +#ifndef PlotToolCurve_h +#define PlotToolCurve_h + +#include "PlotCurve.h" +#include "CubeViewport.h" + + +/** + * @file + * $Revision: 1.5 $ + * $Date: 2008/06/19 15:54:03 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +namespace Qisis { + class PlotToolCurve : public PlotCurve{ + + public: + PlotToolCurve(); + + void copyCurveProperties(PlotToolCurve *pc); + QList getVertices() const; + void setVertices(const QList &points); + CubeViewport* getViewPort() const; + void setViewPort(CubeViewport *cvp); + + private: + QList p_pointList;//!< List of data points + CubeViewport *p_cvp;//!< Viewport the data is from + + + }; +}; +#endif + diff --git a/isis/src/qisis/objs/PlotToolWindow/Makefile b/isis/src/qisis/objs/PlotToolWindow/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/PlotToolWindow/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/PlotToolWindow/PlotToolWindow.cpp b/isis/src/qisis/objs/PlotToolWindow/PlotToolWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..118cc01367219e0f761b80b91dfe47254a55f605 --- /dev/null +++ b/isis/src/qisis/objs/PlotToolWindow/PlotToolWindow.cpp @@ -0,0 +1,279 @@ +#include "PlotToolWindow.h" + +#include + +#include "Cube.h" +#include "Pvl.h" +#include "PvlGroup.h" + + + +using namespace Isis; + +namespace Qisis { + + + /** + * This class was developed specifically to be used in conjuntion + * with the PlotTool. i.e. this is the PlotWindow for the + * PlotTool. This class handles items on the PlotWindow unique + * to the PlotTool such as the vertical lines drawn on the plot + * area called the band lines. + */ + PlotToolWindow::PlotToolWindow (QString title,QWidget *parent) : + Qisis::PlotWindow(title, parent) { + + p_grayBandLine = NULL; + p_redBandLine = NULL; + p_greenBandLine = NULL; + p_blueBandLine = NULL; + p_cvp = NULL; + p_plotType = NULL; + p_wavelengths = NULL; + p_stdDevArray = NULL; + + p_plotType = new QString; + p_wavelengths = new PvlKeyword; + p_stdDevArray = new QVector< double >; + + /*Plot line draws the vertical line(s) to indicate + which band(s) the user is looking at in the cube viewport*/ + p_grayBandLine = new QwtPlotMarker(); + p_redBandLine = new QwtPlotMarker(); + p_greenBandLine = new QwtPlotMarker(); + p_blueBandLine = new QwtPlotMarker(); + + p_grayBandLine->setLineStyle(QwtPlotMarker::LineStyle(2)); + p_redBandLine->setLineStyle(QwtPlotMarker::LineStyle(2)); + p_greenBandLine->setLineStyle(QwtPlotMarker::LineStyle(2)); + p_blueBandLine->setLineStyle(QwtPlotMarker::LineStyle(2)); + + QPen *pen = new QPen(Qt::white); + pen->setWidth(1); + p_grayBandLine->setLinePen(*pen); + pen->setColor(Qt::red); + p_redBandLine->setLinePen(*pen); + pen->setColor(Qt::green); + p_greenBandLine->setLinePen(*pen); + pen->setColor(Qt::blue); + p_blueBandLine->setLinePen(*pen); + + p_grayBandLine->hide(); + p_redBandLine->hide(); + p_greenBandLine->hide(); + p_blueBandLine->hide(); + + p_grayBandLine->attach(this->p_plot); + p_redBandLine->attach(this->p_plot); + p_greenBandLine->attach(this->p_plot); + p_blueBandLine->attach(this->p_plot); + + /*Setting the default to all lines hidden and all symbols visible.*/ + this->hideAllCurves(); + } + + + PlotToolWindow::~PlotToolWindow() + { + if (p_plotType) + { + delete p_plotType; + p_plotType = NULL; + } + + if (p_wavelengths) + { + delete p_wavelengths; + p_wavelengths = NULL; + } + + if (p_stdDevArray) + { + delete p_stdDevArray; + p_stdDevArray = NULL; + } + + } + + + /** + * This class needs to know which viewport the user is looking + * at so it can appropriately draw in the band lines. + * + * @param cvp + */ + void PlotToolWindow::setViewport(CubeViewport *cvp){ + if(cvp == NULL) return; + p_cvp = cvp; + + } + + /** + * This method actually draws in the vertical band line(s) on + * the plot area. + * + */ + void PlotToolWindow::drawBandMarkers(){ + if (p_cvp == NULL) return; + if(!p_markersVisible) return; + + int redBand=0, greenBand=0, blueBand=0, grayBand=0; + + Cube *cube = p_cvp->cube(); + Pvl &pvl = *cube->Label(); + + if (pvl.FindObject("IsisCube").HasGroup("BandBin")) { + PvlGroup &bandBin = pvl.FindObject("IsisCube").FindGroup("BandBin"); + if (bandBin.HasKeyword("Center")) { + *p_wavelengths = bandBin.FindKeyword("Center"); + } + } + + if(p_cvp->isColor()) { + redBand = p_cvp->redBand(); + greenBand = p_cvp->greenBand(); + blueBand = p_cvp->blueBand(); + } else { + grayBand = p_cvp->grayBand(); + } + + + /*This is were we need to set the x value to the band number.*/ + if(grayBand > 0) { + if(*p_plotType == "Wavelength") { + p_grayBandLine->setXValue((*p_wavelengths)[grayBand-1]); + + }else{ + p_grayBandLine->setXValue(grayBand); + } + p_grayBandLine->show(); + } else { + p_grayBandLine->hide(); + } + + if(redBand > 0) { + + if(*p_plotType == "Wavelength") { + p_redBandLine->setXValue((*p_wavelengths)[redBand-1]); + }else{ + p_redBandLine->setXValue(redBand); + } + p_redBandLine->show(); + + }else { + p_redBandLine->hide(); + } + + if(greenBand > 0) { + + if(*p_plotType == "Wavelength") { + p_greenBandLine->setXValue((*p_wavelengths)[greenBand-1]); + }else{ + p_greenBandLine->setXValue(greenBand); + } + p_greenBandLine->show(); + + }else { + p_greenBandLine->hide(); + } + + if(blueBand > 0) { + + if(*p_plotType == "Wavelength") { + p_blueBandLine->setXValue((*p_wavelengths)[blueBand-1]); + }else{ + p_blueBandLine->setXValue(blueBand); + } + p_blueBandLine->show(); + + }else { + p_blueBandLine->hide(); + } + + this->p_plot->replot(); + + } + + /** + * + * + * @param visible + */ + void PlotToolWindow::setBandMarkersVisible(bool visible){ + p_markersVisible = visible; + } + + /** + * + * + * + * @return bool + */ + bool PlotToolWindow::bandMarkersVisible(){ + return p_markersVisible; + } + + /** + * This method is called from PlotTool. This enables the users + * to hide or show the vertical line(s) on the plot which + * represent the color bands or the black/white band. + * + */ + void PlotToolWindow::showHideLines(){ + if(p_cvp->isColor()) { + p_blueBandLine->setVisible(!p_markersVisible); + p_redBandLine->setVisible(!p_markersVisible); + p_greenBandLine->setVisible(!p_markersVisible); + }else { + p_grayBandLine->setVisible(!p_markersVisible); + } + + p_markersVisible = !p_markersVisible; + + this->p_plot->replot(); + } + + /** + * + * + * @param plotType + */ + void PlotToolWindow::setPlotType(QString plotType){ + *p_plotType = plotType; + + } + + /** + * + * + * @param autoScale + */ + void PlotToolWindow::setAutoScaleOption(bool autoScale){ + p_autoScale = autoScale; + } + + /** + * Fills in the table with the data from the current curves + * in the plotWindow -- overridden function from PlotWindow + */ + void PlotToolWindow::fillTable(){ + if(p_tableWindow == NULL) return; + PlotWindow::fillTable(); + } + + + /** + * Gives us access to the standard deviation array so we can + * display it in the table. + * + * @param stdDevArray + */ + void PlotToolWindow::setStdDev (QVector< double > stdDevArray){ + *p_stdDevArray = stdDevArray; + } + +} + + + + diff --git a/isis/src/qisis/objs/PlotToolWindow/PlotToolWindow.h b/isis/src/qisis/objs/PlotToolWindow/PlotToolWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..9214455938fee0da397f0d45369db8f004a13135 --- /dev/null +++ b/isis/src/qisis/objs/PlotToolWindow/PlotToolWindow.h @@ -0,0 +1,90 @@ +#ifndef PlotToolWindow_h +#define PlotToolWindow_h + +/** + * @file + * $Date: 2010/06/28 09:07:50 $ + * $Revision: 1.8 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "PlotWindow.h" + + +class QString; +template< class T > class QVector; + +class QwtPlotMarker; + +namespace Isis +{ + class PvlKeyword; +} + +namespace Qisis +{ + /** + * @brief Widget to display Isis cubes for qt apps + * + * @ingroup Visualization Tools + * + * @author ??? + * + * @internal + * @history 2010-06-26 - Eric Hyer - Now uses MdiCubeViewport instead of + * CubeViewport. Fixed multiple include problems. + */ + class PlotToolWindow : public PlotWindow + { + Q_OBJECT + + public: + PlotToolWindow(QString title, QWidget * parent); + PlotToolWindow(const PlotToolWindow & other); + virtual ~PlotToolWindow(); + bool bandMarkersVisible(); + void setViewport(CubeViewport *cvp); + void setPlotType(QString plotType); + bool p_markersVisible; + const PlotToolWindow & operator=(PlotToolWindow other); + + + public slots: + void drawBandMarkers(); + void setBandMarkersVisible(bool visible); + void showHideLines(); + void fillTable(); + void setStdDev(QVector< double > stdDevArray); + + + private: + void setAutoScaleOption(bool autoScale = false); + QwtPlotMarker * p_grayBandLine; + QwtPlotMarker * p_redBandLine; + QwtPlotMarker * p_greenBandLine; + QwtPlotMarker * p_blueBandLine; + CubeViewport * p_cvp; + QString * p_plotType; + Isis::PvlKeyword * p_wavelengths; + bool p_autoScale; + QVector< double > * p_stdDevArray; + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/PlotWindow/Makefile b/isis/src/qisis/objs/PlotWindow/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/PlotWindow/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/PlotWindow/PlotWindow.cpp b/isis/src/qisis/objs/PlotWindow/PlotWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a0125d0431dc8f79d389b71c96c2f2d49de0840 --- /dev/null +++ b/isis/src/qisis/objs/PlotWindow/PlotWindow.cpp @@ -0,0 +1,1677 @@ +#include "PlotWindow.h" +#include "MainWindow.h" +#include "Stretch.h" +#include "Filename.h" +#include "QHistogram.h" +#include "Interpolator.h" +#include +#include +#include + +namespace Qisis { + /*Static variables*/ + PlotCurve *PlotWindow::p_dragCurve = NULL; + bool PlotWindow::p_curveCopied = false; + + /** + * This constructs a plot window. The plot window graphs any + * curve sent to it via the addPlotCurve() method. + * + * + * @param title + * @param parent + */ + PlotWindow::PlotWindow (QString title,QWidget *parent) : Qisis::MainWindow(title, parent) { + p_selected = -1; + p_toolBar = NULL; + p_menubar = NULL; + p_tableWindow = NULL; + p_parent = parent; + createWindow(); + createConfigDialog(); + createLegendMenu(); + p_scaled = false; + p_curvePropsSaved = false; + p_xLogScale = false; + p_yLogScale = false; + p_plotCurves.clear(); + setWindowTitle(title); + readSettings(); + } + + +/** + * This method is called by the constructor to create the + * plot, legend. zoomer, and main window + */ + void PlotWindow::createWindow() { + /*Create plot*/ + p_plot = new QwtPlot(); + p_plot->installEventFilter(this); + p_plot->setAxisMaxMinor(QwtPlot::yLeft, 5); + p_plot->setAxisMaxMajor(QwtPlot::xBottom, 30); + p_plot->setAxisMaxMinor(QwtPlot::xBottom, 5); + p_plot->setAxisLabelRotation(QwtPlot::xBottom, 45); + p_plot->setAxisLabelAlignment(QwtPlot::xBottom, Qt::AlignRight); + + /*Plot Legend*/ + p_legend = new QwtLegend(); + p_legend->setItemMode(QwtLegend::ClickableItem); + p_legend->setWhatsThis("Right Click on a legend item to display the context menu."); + p_plot->insertLegend(p_legend, QwtPlot::RightLegend, 1.0); + + /*Plot Grid*/ + p_grid = new QwtPlotGrid; + p_grid->enableXMin(true); + p_grid->setMajPen(QPen(Qt::white, 1, Qt::DotLine)); + p_grid->setMinPen(QPen(Qt::gray, 1, Qt::DotLine)); + p_grid->attach(p_plot); + p_grid->setVisible(false); + + /*Plot Zoomer*/ + p_zoomer = new QwtPlotZoomer(p_plot->canvas()); + p_zoomer->setRubberBandPen(QPen(Qt::lightGray)); + p_zoomer->setTrackerPen(QPen(Qt::lightGray)); + + /* Create the Plot window*/ + p_mainWindow = new Qisis::MainWindow(this->windowTitle(), p_parent); + p_mainWindow->installEventFilter(this); + p_mainWindow->setCentralWidget(p_plot); + setupDefaultMenu(); + + /*set max and min*/ + p_xMin = 0; + p_yMin = 0; + p_xMax = 1000; + p_yMax = 1000; + } + + + /** + * Shows the plot window, and raises it to the front of any + * overlapping sibling widgets. + */ + void PlotWindow::showWindow(){ + p_mainWindow->raise(); + p_mainWindow->show(); + } + + /** + * Sets the plot to auto scale the given axis. + * + * + * @param axisId + */ + void PlotWindow::setAutoScaleAxis(int axisId){ + p_plot->setAxisAutoScale(axisId); + } + + + /** + * Sets the plots given axis title to the given string. + * + * + * @param axisId + * @param title + */ + void PlotWindow::setAxisLabel(int axisId, QString title){ + p_plot->setAxisTitle(axisId, title); + } + + + /** + * Returns the axis title of the given axis. + * + * + * @param axisId + * + * @return QwtText + */ + QwtText PlotWindow::getAxisLabel(int axisId){ + return p_plot->axisTitle(axisId); + } + + + /** + * Sets the plot title to the given string. + * + * + * @param pt + */ + void PlotWindow::setPlotTitle(QString pt){ + p_plot->setTitle(pt); + } + + + /** + * Returns the plot title. + * + * + * @return QwtText + */ + QwtText PlotWindow::getPlotTitle(){ + return p_plot->title(); + } + + + /** + * Sets the plot background color to the given color. + * + * + * @param c + */ + void PlotWindow::setPlotBackground(QColor c){ + p_plot->setCanvasBackground(c); + } + + + /** + * Returns the plot's background color. + * + * + * @return QColor + */ + QColor PlotWindow::getPlotBackground(){ + return p_plot->canvasBackground(); + } + + + /** + * This method adds the curves to the plot. + * + * + * @param pc + */ + void PlotWindow::add(PlotCurve *pc){ + p_plotCurves.push_back(pc); + pc->attach(p_plot); + fillTable(); + pc->attachSymbols(p_plot); + //check to see if the curve is visible. + if(pc->isVisible()) { + pc->setVisible(true); + } else { + pc->setVisible(false); + } + //check to see if the symbols are visible. + if(pc->isSymbolVisible()) { + pc->setSymbolVisible(true); + } else { + pc->setSymbolVisible(false); + } + p_plot->replot(); + /*The zoomer base needs to reset after the replot in order for the y-axis + scale to adjust after a zoom action*/ + p_zoomer->setZoomBase(); + /*Installing the event filter is what enables the user to cut and paste + curves from one plot window to another*/ + p_legend->find(pc)->installEventFilter(this); + } + + + /** + * This method completely clears the plot of all plot items. + * i.e. curves and markers, which also deletes the legend also + * calls the necessary method to delete the table stuff + */ + void PlotWindow::clearPlot() { + + for (int i = 0; i < p_plotCurves.size(); i++) { + p_plotCurves[i]->detach(); + } + /*Need to clear all the qlists associated with the plot items.*/ + p_plotCurves.clear(); + p_plot->replot(); + + /*Table Stuff if table is open*/ + if(p_tableWindow != NULL && p_tableWindow->isVisible()) { + p_tableWindow->table()->setColumnCount(1); + p_tableWindow->table()->setRowCount(0); + deleteFromTable(); + } + + emit plotChanged(); + } + + + /** + * This method also clears the plot of all plot items, but does + * not call the table delete stuff This method is called from + * plotTool each time the changePlot() method is called. + * + * + * @param keepScale + */ + void PlotWindow::clearPlotCurves(bool keepScale) { + + //clearPlot(); + for (int i = 0; idetach(); + } + + /*Need to clear all the qlists associated with the plot items.*/ + p_plotCurves.clear(); + p_plot->replot(); + + if(!keepScale) { + setScale(QwtPlot::xBottom, 0, 10); + setScale(QwtPlot::yLeft, 0, 10); + } + } + + + /** + * Enables the plot mouse tracker. + * + */ + void PlotWindow::trackerEnabled() { + if (p_zoomer->trackerMode() == QwtPicker::ActiveOnly) { + p_zoomer->setTrackerMode(QwtPicker::AlwaysOn); + } else { + p_zoomer->setTrackerMode(QwtPicker::ActiveOnly); + } + } + + + /** + * Provids printing support of the plot image. + * + */ + void PlotWindow::printPlot() { + QPixmap pixmap; + /* Initialize a printer*/ + static QPrinter *printer = NULL; + if (printer == NULL) printer = new QPrinter; + printer->setPageSize(QPrinter::Letter); + printer->setColorMode(QPrinter::Color); + + QPrintDialog printDialog(printer,(QWidget *)parent()); + + if (printDialog.exec() == QDialog::Accepted) { + /* Get display widget as a pixmap and convert to an image*/ + pixmap = QPixmap::grabWidget(p_plot); + QImage img = pixmap.toImage(); + /* C++ Gui Programming with Qt, page 201*/ + QPainter painter(printer); + QRect rect = painter.viewport(); + QSize size = img.size(); + size.scale(rect.size(),Qt::KeepAspectRatio); + painter.setViewport(rect.x(),rect.y(), + size.width(),size.height()); + painter.setWindow(img.rect()); + painter.drawImage(0,0,img); + } + + } + + + /** + * This method allows the user to save the plot as a png, + * jpg, or tif image file. + */ + void PlotWindow::savePlot() { + QPixmap pixmap; + QString output = + QFileDialog::getSaveFileName((QWidget *)parent(), + "Choose output file", + "./", + QString("Images (*.png *.jpg *.tif)")); + if (output.isEmpty()) return; + //Make sure the filename is valid + if (!output.isEmpty()) { + if(!output.endsWith(".png") && !output.endsWith(".jpg") && !output.endsWith(".tif")) { + output = output + ".png"; + } + } + + QString format = QFileInfo(output).suffix(); + pixmap = QPixmap::grabWidget(p_plot); + + std::string formatString = format.toStdString(); + if (!pixmap.save(output,formatString.c_str())) { + QMessageBox::information((QWidget *)parent(),"Error","Unable to save "+ output); + return; + } + } + + + /** + * This method toggles the plot background color between + * black and white. + */ + void PlotWindow::switchBackground() { + QPen *pen = new QPen(Qt::white); + + if (p_plot->canvasBackground() == Qt::white) { + p_plot->setCanvasBackground(Qt::black); + p_grid->setMajPen(QPen(Qt::white, 1, Qt::DotLine)); + } else { + p_plot->setCanvasBackground(Qt::white); + pen->setColor(Qt::black); + p_grid->setMajPen(QPen(Qt::black, 1, Qt::DotLine)); + } + + p_zoomer->setRubberBandPen(*pen); + p_zoomer->setTrackerPen(*pen); + pen->setWidth(2); + /*Replot with the new background and pen colors*/ + p_plot->replot(); + } + + + /** + * Sets plot scale back to the defaults. + * + */ + void PlotWindow::resetScale(){ + setScale(QwtPlot::xBottom, p_xMin, p_xMax); + setScale(QwtPlot::yLeft, p_yMin, p_yMax); + } + + + /** + * This method sets the scale of the axis on the plot + * + * + * @param axisId + * @param minimum + * @param maximum + */ + void PlotWindow::setScale(int axisId, double minimum, double maximum, double stepSize) { + if(axisId == QwtPlot::xBottom){ + p_xMax = maximum; + p_xMin = minimum; + } + + if(axisId == QwtPlot::yLeft){ + p_yMax = maximum; + p_yMin = minimum; + } + + p_plot->setAxisScale(axisId,minimum,maximum, stepSize); + + p_plot->replot(); + p_zoomer->setZoomBase(); + p_scaled = true; + } + + /** + * + * + * + * @param axisId + * @param scaleDiv + */ + void PlotWindow::setScaleDiv(int axisId, QwtScaleDiv scaleDiv){ + p_plot->setAxisScaleDiv(axisId, scaleDiv); + p_plot->replot(); + } + + + /** + * This method sets the scale for the axis according to the + * user specified numbers. + */ + void PlotWindow::setUserValues() { + p_xMin = p_xMinEdit->text().toDouble(); + p_xMax = p_xMaxEdit->text().toDouble(); + p_yMin = p_yMinEdit->text().toDouble(); + p_yMax = p_yMaxEdit->text().toDouble(); + setScale(QwtPlot::xBottom, p_xMin, p_xMax); + setScale(QwtPlot::yLeft, p_yMin, p_yMax); + + if(p_xLogCheckBox->isChecked()) { + p_plot->setAxisScaleEngine(QwtPlot::xBottom, new QwtLog10ScaleEngine); + p_xLogScale = true; + } else { + p_plot->setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine); + p_xLogScale = false; + } + + if(p_yLogCheckBox->isChecked()) { + p_plot->setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10ScaleEngine); + p_yLogScale = true; + } else { + p_plot->setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine); + p_yLogScale = false; + } + + } + + + /** + * This method is called when the user activates the curve title + * drop down menu. When a curve is selected, then the rest of + * the dialog box needs to be filled in with the information + * specific to that curve + * + * + * @param title + */ + void PlotWindow::fillInValues(int title){ + p_selected = title; + + if(p_selected > p_plotCurves.size() || p_selected < 0){ + return; + } + + /*save dragCurve with all the properties before the change.*/ + p_dragCurve = new PlotCurve(); + p_dragCurve->copyCurveProperties(p_plotCurves[p_selected]); + + p_titleBox->setCurrentIndex(p_selected); + p_titleLineEdit->setText(p_plotCurves[p_selected]->title().text()); + p_styleBox->setCurrentIndex(p_plotCurves[p_selected]->pen().style()-1); + p_sizeBox->setCurrentIndex(p_plotCurves[p_selected]->pen().width()); + QPalette *palette = new QPalette(); + palette->setColor(QPalette::Button,p_plotCurves[p_selected]->pen().color()); + p_colorButton->setPalette(*palette); + p_symbolBox->setCurrentIndex(p_plotCurves[p_selected]->symbolStyle().style()); + + if(p_plotCurves[p_selected]->isVisible()) p_hideButton->setText("Hide Curve"); + if(!p_plotCurves[p_selected]->isVisible()) p_hideButton->setText("Show Curve"); + + if(p_plotCurves[p_selected]->p_markerIsVisible) p_symbolsButton->setText("Hide Symbols"); + if(!p_plotCurves[p_selected]->p_markerIsVisible) p_symbolsButton->setText("Show Symbols"); + + } + + + + /** + * Method called from the configDialog box when the user + * changes the line edit box for the curve title + * + * + * @param s + */ + void PlotWindow::changeTitle(QString s){ + p_plotCurves[p_selected]->setTitle(p_titleLineEdit->text()); + p_legend->find(p_plotCurves[p_selected])->updateGeometry(); + p_plot->updateLayout(); + + /*We need to change the title on the table.*/ + if(p_tableWindow != NULL && p_tableWindow->isVisible()) + p_tableWindow->table()->horizontalHeaderItem(p_selected)->setText(p_titleLineEdit->text()); + + if(p_tableWindow != NULL && p_tableWindow->isVisible()) + p_tableWindow->listWidget()->item(p_selected)->setText(p_titleLineEdit->text()); + } + + + /** + * Each time the user makes a change to the curve (and/or it's + * respective markers) we need to emit a signal for programmers + * who are using this class know when something has been changed + * in the plot window. + */ + void PlotWindow::saveProperties(){ + emit plotChanged(); + + } + + + /** + * This is called from the constructor. It creates the dialog + * box and all the widgets in it but the dialog box is not show + * until the user selects the config Plot action + */ + void PlotWindow::createConfigDialog(){ + configDialog = new QDialog(p_mainWindow); + configDialog->setWindowTitle("Configure Plot Curves"); + configDialog->setModal(true); + + QWidget *labels = new QWidget(configDialog); + QWidget *textBoxes = new QWidget(configDialog); + QWidget *buttons = new QWidget(configDialog); + QWidget *mainButtons = new QWidget(configDialog); + QWidget *main = new QWidget(configDialog); + + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(main); + layout->addWidget(buttons); + + configDialog->setLayout(layout); + + p_titleBox = new QComboBox(configDialog); + p_titleBox->setDuplicatesEnabled(true); + connect(p_titleBox,SIGNAL(activated(int)),this,SLOT(fillInValues(int))); + + QVBoxLayout *labelLayout = new QVBoxLayout(); + QLabel *selectLabel = new QLabel("Select Curve: "); + QLabel *titleLabel = new QLabel("Title: "); + QLabel *colorLabel = new QLabel("Color: "); + QLabel *styleLabel = new QLabel("Style:" ); + QLabel *sizeLabel = new QLabel("Size:" ); + QLabel *symbolLabel = new QLabel("Symbol:" ); + labelLayout->addWidget(selectLabel); + labelLayout->addWidget(titleLabel); + labelLayout->addWidget(colorLabel); + labelLayout->addWidget(styleLabel); + labelLayout->addWidget(sizeLabel); + labelLayout->addWidget(symbolLabel); + + labels->setLayout(labelLayout); + + QVBoxLayout *textBoxLayout = new QVBoxLayout(); + p_titleLineEdit = new QLineEdit(configDialog); + connect(p_titleLineEdit,SIGNAL(textChanged(QString)),this,SLOT(changeTitle(QString))); + p_colorButton = new QPushButton(configDialog); + connect(p_colorButton,SIGNAL(clicked()),this,SLOT(colorSelect())); + p_colorButton->setFixedWidth(25); + p_styleBox = new QComboBox(configDialog); + connect(p_styleBox,SIGNAL(activated(int)),this,SLOT(changeCurveStyle(int))); + p_styleBox->addItem("SolidLine"); + p_styleBox->addItem("DashLine"); + p_styleBox->addItem("DotLine"); + p_styleBox->addItem("DashDotLine"); + p_styleBox->addItem("DashDotDot Line"); + p_symbolBox = new QComboBox(configDialog); + connect(p_symbolBox,SIGNAL(activated(int)),this,SLOT(changeMarkerStyle(int))); + p_symbolBox->addItem("Ellipse"); + p_symbolBox->addItem("Rect"); + p_symbolBox->addItem("Diamond"); + p_symbolBox->addItem("Triangle"); + p_symbolBox->addItem("DTriangle"); + p_symbolBox->addItem("UTriangle"); + p_symbolBox->addItem("LTriangle"); + p_symbolBox->addItem("RTriangle"); + p_symbolBox->addItem("Cross"); + p_symbolBox->addItem("XCross"); + p_symbolBox->addItem("HLine"); + p_symbolBox->addItem("VLine"); + p_symbolBox->addItem("Star1"); + p_symbolBox->addItem("Star2"); + p_symbolBox->addItem("Hexagon"); + p_sizeBox = new QComboBox(configDialog); + connect(p_sizeBox,SIGNAL(activated(int)),this,SLOT(changeCurveSize(int))); + p_sizeBox->addItem("1"); + p_sizeBox->addItem("2"); + p_sizeBox->addItem("3"); + p_sizeBox->addItem("4"); + + textBoxLayout->addWidget(p_titleBox); + textBoxLayout->addWidget(p_titleLineEdit); + textBoxLayout->addWidget(p_colorButton); + textBoxLayout->addWidget(p_styleBox); + textBoxLayout->addWidget(p_sizeBox); + textBoxLayout->addWidget(p_symbolBox); + + textBoxes->setLayout(textBoxLayout); + + QVBoxLayout *mainButtonsLayout = new QVBoxLayout(); + p_deleteButton = new QPushButton(configDialog); + p_deleteButton->setText("Delete Curve"); + connect(p_deleteButton,SIGNAL(clicked()),this,SLOT(deleteCurve())); + mainButtonsLayout->addWidget(p_deleteButton); + if (!p_deletable) p_deleteButton->setVisible(false); + + p_hideButton = new QPushButton(configDialog); + p_hideButton->setText("Show Curve"); + connect(p_hideButton,SIGNAL(clicked()),this,SLOT(showCurve())); + mainButtonsLayout->addWidget(p_hideButton); + + p_symbolsButton = new QPushButton(configDialog); + p_symbolsButton->setText("Hide Symbols"); + connect(p_symbolsButton,SIGNAL(clicked()),this,SLOT(showSymbols())); + mainButtonsLayout->addWidget(p_symbolsButton); + + mainButtons->setLayout(mainButtonsLayout); + + QHBoxLayout *mainLayout = new QHBoxLayout(); + mainLayout->addWidget(labels); + mainLayout->addWidget(textBoxes); + mainLayout->addWidget(mainButtons); + + main->setLayout(mainLayout); + + QHBoxLayout *buttonsLayout = new QHBoxLayout(); + QPushButton *okButton = new QPushButton(configDialog); + connect(okButton,SIGNAL(clicked()),this,SLOT(saveProperties())); + connect(okButton,SIGNAL(clicked()),configDialog,SLOT(hide())); + okButton->setText("OK"); + QPushButton *cancelButton = new QPushButton(configDialog); + connect(cancelButton,SIGNAL(clicked()),this,SLOT(cancelConfig())); + cancelButton->setText("Cancel"); + + buttonsLayout->addWidget(okButton); + buttonsLayout->addWidget(cancelButton); + + buttons->setLayout(buttonsLayout); + + } + + + /** + * This method is called when the user selects the config plot + * action on the tool bar or the option menu + */ + void PlotWindow::configPlot(){ + + if (p_plotCurves.size() < 1) return; + + p_curveTitleList.clear(); + p_titleBox->clear(); + + /*add all the current curves to the drop down menu*/ + for (int i = 0; ititle().text()); + } + + p_titleBox->addItems(p_curveTitleList); + + /*fill in the dialog box's values according to which curve is selected.*/ + if (p_selected >= 0) { + fillInValues(p_selected); + } else { + fillInValues(0); + } + + /*check to see if this plotWindow allows the user to delete curves.*/ + if (!p_deletable) { + p_deleteButton->setVisible(false); + } else { + p_deleteButton->setVisible(true); + } + + /*now show the dialog box.*/ + configDialog->show(); + } + + + + /** + * This method allows the programmer to set a property of the + * plot window which determines if a window will allow the + * pasting of curves. If paste is false, the paste option on + * the context menu is disabled. + * + * + * @param paste + */ + void PlotWindow::setPasteable(bool paste){ + p_pasteable= paste; + } + + + /** + * This method allows a programmer to set a property of the plot + * window which determines whether the user is allowed to delete + * a curve from the plotWindow or not. If set to false, the + * delete button is not visible on the configDialog box + * and the delete option on the context menu is disabled. + * + * + * @param d + */ + void PlotWindow::setDeletable(bool d){ + p_deletable = d; + } + + + /** + * This method allows the programmer to set the property which + * allows the user to copy a curve from the window. If c is + * false, the copy option on the context menu is disabled. + * + * @param c + */ + void PlotWindow::setCopyEnable(bool c){ + p_copyable = c; + } + + + /** + * This method allows the programmer set the property to destroy + * the window upon a close event. When this is set to true, the + * class will emit a destroyed(this) signal. See the + * eventFilter method. p_destroyOnClose is set to false by + * + * default. + * @param destroy + */ + void PlotWindow::setDestroyOnClose(bool destroy){ + p_destroyOnClose = destroy; + } + + + /** + * When the user deletes a curve, there is a table column and a + * QList of markers associated with the that curve that also need + * to be deleted. + */ + void PlotWindow::deleteCurve(){ + p_plotCurves[p_selected]->detach(); + delete p_plotCurves[p_selected]; + p_curveTitleList.removeAt(p_selected); + p_plotCurves.removeAt(p_selected); + + + /*Replot with the p_selected curve deleted.*/ + p_plot->replot(); + + /*deletes the column from the table if the table has been created.*/ + if (p_tableWindow != NULL) deleteFromTable(); + configDialog->hide(); + } + + + /** + * This method is called when user presses the p_colorButton on + * the config plot dialog the color of the button itself is then + * set to the selected color for visual feedback + */ + void PlotWindow::colorSelect(){ + QColor c = QColorDialog::getColor(Qt::white,configDialog); + + if (c.isValid()) { + QPalette *palette = new QPalette(); + palette->setColor(QPalette::Button, c); + p_colorButton->setPalette(*palette); + QPen *pen = new QPen(c); + pen->setWidth(p_plotCurves[p_selected]->pen().width()); + pen->setStyle(p_plotCurves[p_selected]->pen().style()); + p_plotCurves[p_selected]->setPen(*pen); + + /*Replot with new color.*/ + p_plot->replot(); + } + + } + + + /** + * Called from the "Size:" drop down menu on the configDialog + * box. Changes the width of the line + * + * + * @param size + */ + void PlotWindow::changeCurveSize(int size){ + QPen *pen = new QPen(p_colorButton->palette().color(QPalette::Button)); + pen->setWidth(size); + pen->setStyle(p_plotCurves[p_selected]->pen().style()); + p_plotCurves[p_selected]->setPen(*pen); + /*Replot with the new size.*/ + p_plot->replot(); + + } + + + /** + * Called from the "Style:" drop down menu on the + * configDialog box. + * + * + * @param style + */ + void PlotWindow::changeCurveStyle(int style){ + QPen *pen = new QPen(p_colorButton->palette().color(QPalette::Button)); + pen->setWidth(p_plotCurves[p_selected]->pen().width()); + pen->setStyle(Qt::PenStyle(style+1)); + p_plotCurves[p_selected]->setPen(*pen); + /*Replot with the new style*/ + p_plot->replot(); + } + + + /** + * Called from the "Symbol:" drop down menu on the + * configDialog box + * + * + * @param style + */ + void PlotWindow::changeMarkerStyle(int style){ + p_plotCurves[p_selected]->setSymbolStyle(QwtSymbol::Style(style)); + + /*Replot with the new marker style.*/ + p_plot->replot(); + + } + + + /** + * Resets the x/y min/max to the defaults. + * + */ + void PlotWindow::setDefaultRange() { + QDialog *dialog = new QDialog(p_mainWindow); + dialog->setWindowTitle("Set Display Range"); + + QWidget *buttons = new QWidget (dialog); + QWidget *textAreas = new QWidget (dialog); + QWidget *labels = new QWidget (dialog); + QWidget *main = new QWidget (dialog); + + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(main,0); + layout->addWidget(buttons,0); + dialog->setLayout(layout); + + QToolButton *okButton = new QToolButton(dialog); + connect(okButton,SIGNAL(released()),this,SLOT(setUserValues())); + connect(okButton,SIGNAL(released()),dialog,SLOT(hide())); + okButton->setShortcut(Qt::Key_Enter); + okButton->setText("Ok"); + + QToolButton *cancelButton = new QToolButton(dialog); + connect(cancelButton,SIGNAL(released()),dialog,SLOT(hide())); + cancelButton->setText("Cancel"); + + QLabel *xLabel = new QLabel("X-Axis: "); + QLabel *xMinLabel = new QLabel("Minimum: "); + QLabel *xMaxLabel = new QLabel("Maximum: "); + QLabel *yLabel = new QLabel("Y-Axis: "); + QLabel *yMinLabel = new QLabel("Minimum: "); + QLabel *yMaxLabel = new QLabel("Maximum: "); + + p_xLogCheckBox = new QCheckBox("x - Log Scale"); + p_xLogCheckBox->setChecked(p_xLogScale); + p_yLogCheckBox = new QCheckBox("y - Log Scale"); + p_yLogCheckBox->setChecked(p_yLogScale); + + QVBoxLayout *vlayout = new QVBoxLayout(); + vlayout->addWidget(xLabel); + vlayout->addWidget(xMinLabel); + vlayout->addWidget(xMaxLabel); + vlayout->addWidget(p_xLogCheckBox); + vlayout->addWidget(yLabel); + vlayout->addWidget(yMinLabel); + vlayout->addWidget(yMaxLabel); + vlayout->addWidget(p_yLogCheckBox); + labels->setLayout(vlayout); + + p_xMinEdit = new QLineEdit(QString::number(p_xMin),dialog); + p_xMaxEdit = new QLineEdit(QString::number(p_xMax),dialog); + p_yMinEdit = new QLineEdit(QString::number(p_yMin),dialog); + p_yMaxEdit = new QLineEdit(QString::number(p_yMax),dialog); + + QVBoxLayout *v2layout = new QVBoxLayout(); + v2layout->addWidget(new QLabel("")); + v2layout->addWidget(p_xMinEdit); + v2layout->addWidget(p_xMaxEdit); + v2layout->addWidget(new QLabel("")); + v2layout->addWidget(new QLabel("")); + v2layout->addWidget(p_yMinEdit); + v2layout->addWidget(p_yMaxEdit); + v2layout->addWidget(new QLabel("")); + textAreas->setLayout(v2layout); + + + QHBoxLayout *mainLayout = new QHBoxLayout(); + mainLayout->addWidget(labels); + mainLayout->addWidget(textAreas); + main->setLayout(mainLayout); + + QHBoxLayout *hlayout = new QHBoxLayout(); + hlayout->addWidget(okButton); + hlayout->addWidget(cancelButton); + buttons->setLayout(hlayout); + + dialog->setFixedSize(400,250); + dialog->show(); + } + + + /** + * This method creates the dialog box which allows the user + * to relabel the plot window + */ + void PlotWindow::reLabel() { + QDialog *dialog = new QDialog(p_mainWindow); + dialog->setWindowTitle("Name Plot Labels"); + + QWidget *buttons = new QWidget (dialog); + QWidget *textAreas = new QWidget (dialog); + QWidget *labels = new QWidget (dialog); + QWidget *main = new QWidget (dialog); + + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(main,0); + layout->addWidget(buttons,0); + dialog->setLayout(layout); + + QToolButton *okButton = new QToolButton(dialog); + connect(okButton,SIGNAL(released()),this,SLOT(setLabels())); + connect(okButton,SIGNAL(released()),dialog,SLOT(hide())); + okButton->setShortcut(Qt::Key_Enter); + okButton->setText("Ok"); + + QToolButton *cancelButton = new QToolButton(dialog); + connect(cancelButton,SIGNAL(released()),dialog,SLOT(hide())); + cancelButton->setText("Cancel"); + + QLabel *plotLabel = new QLabel("Plot Title: "); + QLabel *xAxisLabel = new QLabel("X-Axis Label: "); + QLabel *yAxisLabel = new QLabel("Y-Axis Label: "); + + QVBoxLayout *vlayout = new QVBoxLayout(); + vlayout->addWidget(plotLabel); + vlayout->addWidget(xAxisLabel); + vlayout->addWidget(yAxisLabel); + labels->setLayout(vlayout); + + p_plotTitleText = new QLineEdit(p_plot->title().text(),dialog); + p_xAxisText = new QLineEdit(p_plot->axisTitle(QwtPlot::xBottom).text(),dialog); + p_yAxisText = new QLineEdit(p_plot->axisTitle(QwtPlot::yLeft).text(),dialog); + + QVBoxLayout *v2layout = new QVBoxLayout(); + v2layout->addWidget(p_plotTitleText); + v2layout->addWidget(p_xAxisText); + v2layout->addWidget(p_yAxisText); + textAreas->setLayout(v2layout); + + QHBoxLayout *mainLayout = new QHBoxLayout(); + mainLayout->addWidget(labels); + mainLayout->addWidget(textAreas); + main->setLayout(mainLayout); + + QHBoxLayout *hlayout = new QHBoxLayout(); + hlayout->addWidget(okButton); + hlayout->addWidget(cancelButton); + buttons->setLayout(hlayout); + + dialog->setFixedSize(400,190); + dialog->show(); + } + + + /** + * Makes the user specified changes to the plot labels. + */ + void PlotWindow::setLabels() { + p_plot->setTitle(p_plotTitleText->text()); + p_plot->setAxisTitle(QwtPlot::xBottom,p_xAxisText->text()); + p_plot->setAxisTitle(QwtPlot::yLeft,p_yAxisText->text()); + /*Replot with new labels.*/ + p_plot->replot(); + } + + + /** + * This method hides/shows the grid on the plotWindow and + * changes the text for the action + */ + void PlotWindow::showGrid(){ + p_grid->setVisible(!p_grid->isVisible()); + + if(p_grid->isVisible()){ + p_gridShow->setText("Hide Grid"); + } else{ + p_gridShow->setText("Show Grid"); + } + p_plot->replot(); + } + + + /** + * Called from the configDialog box to Hide/Show selected + * curve. + */ + void PlotWindow::showCurve() { + if(p_selected < 0) return; + /*shows/hides item on the plot*/ + p_plotCurves[p_selected]->setVisible(!p_plotCurves[p_selected]->isVisible()); + /*Replot with selected curve showing or hidden*/ + p_plot->replot(); + /*Change the text on the button according to what this method will do next time it is pressed.*/ + if(p_plotCurves[p_selected]->isVisible()) p_hideButton->setText("Hide Curve"); + if(!p_plotCurves[p_selected]->isVisible()) p_hideButton->setText("Show Curve"); + + } + + + /** + * This method hides/shows the symbols for the selected + * curve. + */ + void PlotWindow::showSymbols(){ + + if (p_plotCurves[p_selected]->p_markerIsVisible) { + p_symbolsButton->setText("Show Symbols"); + + p_plotCurves[p_selected]->setSymbolVisible(false); + } else { + p_symbolsButton->setText("Hide Symbols"); + p_plotCurves[p_selected]->setSymbolVisible(true); + } + + /*Replot with selected curve's symbols visible*/ + p_plot->replot(); + + } + + + /** + *Shows/Hides all the markers(symbols) + */ + void PlotWindow::hideAllSymbols(){ + if (p_hideAllMarkers->text() == "Hide All Symbols") { + + for (int i = 0; isetSymbolVisible(false); + } + + p_hideAllMarkers->setText("Show All Symbols"); + + } else { + + for (int i = 0; isetSymbolVisible(true); + } + + p_hideAllMarkers->setText("Hide All Symbols"); + } + + /*Replot with all symbols hidden*/ + p_plot->replot(); + } + + + /** + * This method shows or hides all of the curves in the + * plotWindow + */ + void PlotWindow::hideAllCurves(){ + if (p_hideAllCurves->text() == "Hide All Curves") { + + for (int i = 0; ihide(); + } + + p_hideButton->setText("Show Curve"); + p_hideAllCurves->setText("Show All Curves"); + p_hideAllCurves->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_showCurves.png")); + + } else { + + for (int i = 0; ishow(); + } + + p_hideButton->setText("Hide Curve"); + p_hideAllCurves->setText("Hide All Curves"); + p_hideAllCurves->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_hideCurves.png")); + + } + + /*Replot with all curves hidden*/ + p_plot->replot(); + } + + + /** + * This method cancels out any of the changes made on the config + * dialog box, and copies in the old curve properties. + * + */ + void PlotWindow::cancelConfig(){ + if(p_dragCurve != NULL) p_plotCurves[p_selected]->copyCurveProperties(p_dragCurve); + + configDialog->hide(); + p_plot->replot(); + /*We need to change the title on the table.*/ + if(p_tableWindow != NULL && p_tableWindow->isVisible()) + p_tableWindow->table()->horizontalHeaderItem(p_selected)->setText(p_plotCurves[p_selected]->title().text()); + + if(p_tableWindow != NULL && p_tableWindow->isVisible()) + p_tableWindow->listWidget()->item(p_selected)->setText(p_plotCurves[p_selected]->title().text()); + } + + + /** + * This method creates and shows the help dialog box for the + * plot window. this is called from the Help-->Basic Help menu. + */ + void PlotWindow::showHelp() { + QDialog *d = new QDialog(p_plot); + d->setWindowTitle("Basic Help"); + + QLabel *zoomLabel = new QLabel("Zoom Options:"); + QLabel *zoomIn = new + QLabel(" Left click on the mouse, drag, and release to select an area to zoom in on"); + QLabel *zoomOut = new + QLabel(" Middle click on the mouse to zoom out one level"); + QLabel *zoomReset = new + QLabel(" Right click on the mouse and select Reset Scale to clear the zoom and return to the original plot"); + + QLabel *curveConfigLabel = new QLabel("
    Curve Configuration:"); + QLabel *configDirections = new + QLabel(" To configure the curve properties Right click on the legend and select Configure from
    the menu" + " or click on the configure icon in the tool bar."); + QLabel *config = new QLabel(); + config->setPixmap(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_configure.png")); + + QLabel *tableLabel = new QLabel("
    Table Options:"); + QLabel *tableDirections = new + QLabel(" To view the table Click on the File menu and select Show Table or click on the table icon in the
    tool bar."); + QLabel *table = new QLabel(); + table->setPixmap(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_table.png")); + + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(zoomLabel); + layout->addWidget(zoomIn); + layout->addWidget(zoomOut); + layout->addWidget(zoomReset); + layout->addWidget(curveConfigLabel); + layout->addWidget(config); + layout->addWidget(configDirections); + layout->addWidget(tableLabel); + layout->addWidget(table); + layout->addWidget(tableDirections); + + d->setLayout(layout); + d->show(); + } + + + /** + * The user can add menu items from parent classes, but there are + * some menu items required (default) for the plotWindow + */ + void PlotWindow::setupDefaultMenu(){ + QList menu; + QList actionButtons; + getDefaultMenus(menu, actionButtons); + setCustomMenu(menu, actionButtons); + } + + + /** + * Sets up the menus added from a parent object. + * + * + * @param menu + * @param actions + */ + void PlotWindow::setCustomMenu(QList &menu, QList &actions) { + if (p_toolBar == NULL) { + p_toolBar = new QToolBar(p_mainWindow); + p_toolBar->setObjectName("PlotWindow"); + p_toolBar->setAllowedAreas(Qt::LeftToolBarArea|Qt::RightToolBarArea | Qt::TopToolBarArea); + p_mainWindow->addToolBar(Qt::TopToolBarArea,p_toolBar); + } else { + p_toolBar->clear(); + } + + p_menubar = p_mainWindow->menuBar(); + p_menubar->clear(); + + for (int i = 0; i < menu.size(); i++) { + p_menubar->addMenu(menu[i]); + } + + for (int i = 0; i < actions.size(); i++) { + p_toolBar->addAction(actions[i]); + } + + } + + + /** + * Sets up the default menus + * + * + * @param menu + * @param actions + */ + void PlotWindow::getDefaultMenus(QList &menu, QList &actions) { + /*setup actions*/ + p_hideAllMarkers = new QAction(p_plot); + p_hideAllMarkers->setText("Hide All Symbols"); + p_hideAllMarkers->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_markers.png")); + QString text = + "Function: Displays or hides a symbol for each data point plotted on a plot."; + p_hideAllMarkers->setWhatsThis(text); + QObject::connect(p_hideAllMarkers,SIGNAL(activated()),this,SLOT(hideAllSymbols())); + + p_hideAllCurves = new QAction(p_plot); + p_hideAllCurves->setText("Show All Curves"); + p_hideAllCurves->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_showCurves.png")); + text = + "Function: Displays or hides all the curves currently displayed on the plot."; + p_hideAllCurves->setWhatsThis(text); + QObject::connect(p_hideAllCurves,SIGNAL(activated()),this,SLOT(hideAllCurves())); + + QAction *table = new QAction(p_plot); + table->setText("Show Table"); + table->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_table.png")); + text = + "Function: Activates the table which displays the data of the \ + current plot"; + table->setWhatsThis(text); + QObject::connect(table,SIGNAL(activated()),this,SLOT(showTable())); + + QAction *configPlot = new QAction(p_plot); + configPlot->setText("Configure Plot Curves"); + configPlot->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_configure.png")); + text = + "Function: Brings up a dialog box in which the plot curves can be \ + uniquely configured."; + configPlot->setWhatsThis(text); + QObject::connect(configPlot,SIGNAL(activated()),this,SLOT(configPlot())); + + QAction *save = new QAction(p_plot); + save->setText("&Save Plot As"); + save->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/filesaveas.png")); + text = + "Function: Save the plot as a png, jpg, or tif file."; + save->setWhatsThis(text); + QObject::connect(save,SIGNAL(activated()),this,SLOT(savePlot())); + + QAction *prt = new QAction(p_plot); + prt->setText("&Print Plot"); + prt->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/fileprint.png")); + text = + "Function: Sends the plot image to the printer"; + prt->setWhatsThis(text); + QObject::connect(prt,SIGNAL(activated()),this,SLOT(printPlot())); + + QAction *track = new QAction(p_plot); + track->setText("Show Mouse &Tracking"); + track->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/goto.png")); + track->setCheckable(true); + text = + "Function: Displays the x,y coordinates as the cursor moves \ + around on the plot."; + track->setWhatsThis(text); + QObject::connect(track,SIGNAL(activated()),this,SLOT(trackerEnabled())); + + QAction *backgrdSwitch = new QAction(p_plot); + backgrdSwitch->setText("White/Black &Background"); + backgrdSwitch->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_switchBackgrd.png")); + text = + "Function: Switch the background color between black and white."; + backgrdSwitch->setWhatsThis(text); + QObject::connect(backgrdSwitch,SIGNAL(activated()),this,SLOT(switchBackground())); + + p_gridShow = new QAction(p_plot); + p_gridShow->setText("Show Grid"); + p_gridShow->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_grid.png")); + text = + "Function: Display grid lines on the plot."; + p_gridShow->setWhatsThis(text); + QObject::connect(p_gridShow, SIGNAL(activated()), this, SLOT(showGrid())); + + QAction *changeLabels = new QAction(p_plot); + changeLabels->setText("Rename Plot &Labels"); + changeLabels->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_renameLabels.png")); + text = + "Function: Edit the plot title, x and y axis labels."; + changeLabels->setWhatsThis(text); + QObject::connect(changeLabels,SIGNAL(activated()),this,SLOT(reLabel())); + + QAction *changeScale = new QAction(p_plot); + changeScale->setText("Set &Display Range"); + changeScale->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_setScale.png")); + text = + "Function: Adjust the scale for the x and y axis on the plot."; + changeScale->setWhatsThis(text); + QObject::connect(changeScale,SIGNAL(activated()),this, SLOT(setDefaultRange())); + + QAction *resetScaleButton = new QAction(p_plot); + resetScaleButton->setText("Reset Scale"); + resetScaleButton->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_resetscale.png")); + text = + "Function: Reset the plot's scale."; + resetScaleButton->setWhatsThis(text); + QObject::connect(resetScaleButton, SIGNAL(activated()),this, SLOT(resetScale())); + + QAction *clear = new QAction(p_plot); + clear->setText("Clear Plot"); + clear->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_clear.png")); + text = + "Function: Removes all the curves from the plot."; + clear->setWhatsThis(text); + connect(clear,SIGNAL(activated()),this,SLOT(clearPlot())); + + QAction *getHelp = new QAction(p_plot); + getHelp->setText("Basic Help"); + QObject::connect(getHelp,SIGNAL(activated()),this, SLOT(showHelp())); + + QAction *close = new QAction(p_plot); + close->setText("Close"); + QObject::connect(close,SIGNAL(activated()),p_mainWindow, SLOT(close())); + + /*setup menus*/ + QMenu *options = new QMenu("&Options"); + options->addAction(configPlot); + options->addAction(track); + options->addAction(backgrdSwitch); + options->addAction(p_gridShow); + options->addAction(changeLabels); + options->addAction(changeScale); + options->addAction(p_hideAllCurves); + options->addAction(p_hideAllMarkers); + + QMenu *help = new QMenu("&Help"); + help->addAction(getHelp); + + QMenu *file = new QMenu("&File"); + file->addAction(save); + file->addAction(prt); + file->addAction(table); + file->addAction(close); + + actions.push_back(save); + actions.push_back(prt); + actions.push_back(table); + actions.push_back(clear); + actions.push_back(configPlot); + actions.push_back(p_hideAllMarkers); + actions.push_back(p_hideAllCurves); + actions.push_back(backgrdSwitch); + actions.push_back(changeLabels); + actions.push_back(changeScale); + actions.push_back(p_gridShow); + actions.push_back(resetScaleButton); + + menu.push_back(file); + menu.push_back(options); + menu.push_back(help); + + } + + + /** + * Returns the number of curves in the plotWindow + */ + int PlotWindow::getNumCurves(){ + return p_plotCurves.size(); + } + + + /** + * Fills in the table with the data from the current curves + * in the plotWindow + */ + void PlotWindow::fillTable(){ + if (p_tableWindow == NULL) return; + p_tableWindow->listWidget()->clear(); + p_tableWindow->table()->clear(); + p_tableWindow->table()->setRowCount(0); + p_tableWindow->table()->setColumnCount(0); + + /*resize rows if needed*/ + unsigned int rows = p_tableWindow->table()->rowCount(); + + if (rows != p_plotCurves[p_plotCurves.size()-1]->data().size()) { + int diff = p_plotCurves[p_plotCurves.size()-1]->data().size() - rows; + for (int i = 0; i <= abs(diff); i++) { + + if (diff > 0) { + p_tableWindow->table()->insertRow(rows + i); + } else { + p_tableWindow->table()->removeRow(rows - i); + } + + } + } + + p_axisTitle = p_plot->axisTitle(QwtPlot::xBottom).text().toStdString(); + + //write X axis + if (p_tableWindow->table()->columnCount() == 0) { + p_tableWindow->addToTable (true,p_plot->axisTitle(QwtPlot::xBottom).text() + ,p_plot->axisTitle(QwtPlot::xBottom).text(),0); + p_header = p_tableWindow->table()->horizontalHeaderItem(0)->text().toStdString(); + + } else if (p_header.compare(p_axisTitle)) { + + p_tableWindow->table()->removeColumn(0); + p_tableWindow->listWidget()->takeItem(0); + p_tableWindow->addToTable (true,p_plot->axisTitle(QwtPlot::xBottom).text() + ,p_plot->axisTitle(QwtPlot::xBottom).text(), 0); + p_header = p_tableWindow->table()->horizontalHeaderItem(0)->text().toStdString(); + + } + + for (int c = 0; c < p_plotCurves.size(); c++) { + //adding columns to the table if more curves had been added to the plotWindow + //columns + if (c > p_tableWindow->table()->columnCount()-2 ) { + p_tableWindow->addToTable (true,p_plotCurves[c]->title().text(), + p_plotCurves[c]->title().text()); + } + //rows + for (unsigned int r = 0; r < p_plotCurves[c]->data().size(); r++) { + //creates a widget item with the data from the curves. + QTableWidgetItem *item = new QTableWidgetItem + (Isis::iString(p_plotCurves[c]->data().y(r)).ToQt()); + p_tableWindow->table()->setItem(r, c+1, item); + //p_tableWindow->table()->resizeColumnToContents(c-1); + + QTableWidgetItem *xAxisItem = new QTableWidgetItem + (Isis::iString(p_plotCurves[c]->data().x(r)).ToQt()); + p_tableWindow->table()->setItem(r, 0, xAxisItem); + //p_tableWindow->table()->resizeColumnToContents(0); + }//end rows + }//end columns + } + + + /** + * This method is called when the user deletes a curve(s) + * from the plot window. + */ + void PlotWindow::deleteFromTable(){ + if(p_tableWindow == NULL) return; + p_tableWindow->TableMainWindow::deleteColumn(p_selected); + fillTable(); + } + + + /** + * This method is called from the showTable action on the tool + * bar There are some checks done to make sure there are data to + * fill the table + */ + void PlotWindow::showTable(){ + if(p_plotCurves.size() < 1) return; + + if(p_tableWindow == NULL){ + //p_tableWindow = new Qisis::TableMainWindow("Plot Table", this); + p_tableWindow = new Qisis::TableMainWindow("Plot Table", p_parent); + p_tableWindow->setTrackListItems(false); + } + fillTable(); + p_tableWindow->show(); + p_tableWindow->syncColumns(); + } + + + /** + * This method is called from the context menu which is shown on + * the plot legend with a right mouse click. It creates a new + * curve, which is a static curve, then loads all of the + * properties of the curve that was clicked into the new curve. + * Now the new curve can be pasted into another plot window. + */ + void PlotWindow::copyCurve(){ + if(p_selected < 0) return; + emit curveCopied(p_plotCurves[p_selected]); + p_curveCopied = true; + } + + + /** + * This method is called from the context menu which is shown on + * the plot legend with a right mouse click. (Only shown when + * p_curveCopied is true.) Sets the p_curveCopied flag to false, so we know to + * disable the paste option in the context menu. + */ + void PlotWindow::pasteCurve(){ + emit curvePaste(this); + p_curveCopied = false; + } + + + /** + * Emits the curvePasteSpecial signal + * + */ + void PlotWindow::pasteCurveSpecial(){ + emit curvePasteSpecial(this); + p_curveCopied = false; + } + + + /** + * This method creates the context menu which pops up when the + * user right clicks on a legend item. + */ + void PlotWindow::createLegendMenu(){ + p_legendMenu = new QMenu(p_mainWindow); + QAction *configure = new QAction(p_plot); + configure->setText("Configure"); + QObject::connect(configure,SIGNAL(activated()),this,SLOT(configPlot())); + p_legendMenu->addAction(configure); + + p_copyCurveAction = new QAction(p_plot); + p_copyCurveAction->setText("Copy Curve"); + QObject::connect(p_copyCurveAction,SIGNAL(activated()),this,SLOT(copyCurve())); + p_legendMenu->addAction(p_copyCurveAction); + + p_pasteCurve = new QAction(p_plot); + p_pasteCurve->setText("Paste Curve"); + QObject::connect(p_pasteCurve,SIGNAL(activated()),this,SLOT(pasteCurve())); + p_legendMenu->addAction(p_pasteCurve); + + p_pasteSpecial = new QAction(p_plot); + p_pasteSpecial->setText("Paste Special"); + QObject::connect(p_pasteSpecial,SIGNAL(activated()),this,SLOT(pasteCurveSpecial())); + p_legendMenu->addAction(p_pasteSpecial); + + p_deleteCurve = new QAction(p_plot); + p_deleteCurve->setText("Delete Curve"); + QObject::connect(p_deleteCurve,SIGNAL(activated()),this,SLOT(deleteCurve())); + p_legendMenu->addAction(p_deleteCurve); + + QAction *resetScaleAction = new QAction(p_plot); + resetScaleAction->setText("Reset Scale"); + QObject::connect(resetScaleAction, SIGNAL(activated()), this, SLOT(resetScale())); + p_legendMenu->addAction(resetScaleAction); + + p_hideShowCurve = new QAction(p_plot); + p_hideShowCurve->setText("Hide Curve"); + QObject::connect(p_hideShowCurve, SIGNAL(activated()), this, SLOT(showCurve())); + p_legendMenu->addAction(p_hideShowCurve); + } + + + /** + * This method filters the events of the objects it is connected + * to. In this case, the eventFilter has been installed on the + * p_mainWindow, p_plot, and p_legend. + * @param o + * @param e + * + * @return bool + */ + bool PlotWindow::eventFilter(QObject *o,QEvent *e) { + switch (e->type()) { + case QEvent::ContextMenu:{ + p_eventObject = o; + + for (int i = 0; ifind((QWidget *)p_eventObject) == p_plotCurves[i]) { + p_selected = i; + } + } + + QPoint *contextMenuPos = new QPoint(((QContextMenuEvent *)e)->globalPos()); + p_legendMenu->setGeometry(contextMenuPos->x(), contextMenuPos->y(), 110,80); + p_legendMenu->adjustSize(); + + /*disable/enable menu items depending on the state of the window.*/ + if (!p_curveCopied) { + p_pasteCurve->setEnabled(false); + p_pasteSpecial->setEnabled(false); + } else { + p_pasteCurve->setEnabled(true); + p_pasteSpecial->setEnabled(true); + } + + if (!p_pasteable)p_pasteCurve->setEnabled(false); + if (!p_pasteable)p_pasteSpecial->setEnabled(false); + + if (o->inherits("QwtPlot")) { + p_copyCurveAction->setEnabled(false); + p_hideShowCurve->setEnabled(false); + } + if (o->inherits("QwtLegendItem")) { + p_copyCurveAction->setEnabled(true); + p_hideShowCurve->setEnabled(true); + } + + if (p_selected > 0 && p_selected < p_plotCurves.size()) { + if (p_plotCurves[p_selected]->isVisible()) p_hideShowCurve->setText("Hide Curve"); + if (!p_plotCurves[p_selected]->isVisible())p_hideShowCurve->setText("Show Curve"); + } + + if (!p_deletable || o->inherits("QwtPlot") || p_plotCurves.size() < 1) { + p_deleteCurve->setEnabled(false); + } else { + p_deleteCurve->setEnabled(true); + } + p_legendMenu->show(); + + return true; + } + + case QEvent::Close:{ + writeSettings(); + if (p_destroyOnClose) { + emit destroyed(this); + } + } + default: { + return FALSE; + } + } + } + + + /** + * This overridden method is called from the constructor so that + * when the mainwindow is created, it knows it's size + * and location and the tool bar location. + * + */ + void PlotWindow::readSettings(){ + /*Call the base class function to read the size and location*/ + this->MainWindow::readSettings(); + std::string appName = p_parent->windowTitle().toStdString(); + /*Now read the settings that are specific to this window.*/ + std::string instanceName = this->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/" + appName + "/" + instanceName + ".config"); + + QSettings settings(QString::fromStdString(config.Expanded()), QSettings::NativeFormat); + QByteArray state = settings.value("state", QByteArray("0")).toByteArray(); + p_mainWindow->restoreState(state); + } + + + /** + * This overridden method is called when the mainwindow + * is closed or hidden to write the size and location settings + * (and tool bar location) to a config file in the user's home + * directory. + * + */ + void PlotWindow::writeSettings(){ + /*Call the base class function to write the size and location*/ + this->MainWindow::writeSettings(); + std::string appName = p_parent->windowTitle().toStdString(); + /*Now write the settings that are specific to this window.*/ + std::string instanceName = this->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/" + appName + "/" + instanceName + ".config"); + + QSettings settings(QString::fromStdString(config.Expanded()), QSettings::NativeFormat); + settings.setValue("state", p_mainWindow->saveState()); + } + +} + diff --git a/isis/src/qisis/objs/PlotWindow/PlotWindow.h b/isis/src/qisis/objs/PlotWindow/PlotWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..c2c887a1f9e5d4b099a5a553ae1024dfe274c7cc --- /dev/null +++ b/isis/src/qisis/objs/PlotWindow/PlotWindow.h @@ -0,0 +1,235 @@ +#ifndef PlotWindow_h +#define PlotWindow_h + +/** + * @file + * $Revision: 1.17 $ + * $Date: 2009/04/07 16:19:40 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "Workspace.h" +#include "Tool.h" +#include "PlotCurve.h" +#include "PlotToolCurve.h" +#include "MainWindow.h" +#include "TableMainWindow.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class QDockWidget; +class QListWidgetItem; + +namespace Qisis { + class PlotWindow : public Qisis::MainWindow { + Q_OBJECT + + public: + PlotWindow(QString title,QWidget *parent); + void add(PlotCurve *pc); + void clearPlotCurves(bool keepScale = true); + QwtText getAxisLabel(int axisId); + int getNumCurves(); + QColor getPlotBackground(); + QwtText getPlotTitle(); + void setAxisLabel(int axisId, QString title); + void setAutoScaleAxis(int axisId); + void setPlotBackground(QColor c); + void setPlotTitle(QString pt); + void setScale(int axisId, double minimum, double maximum, double stepSize = 0); + void setScaleDiv(int axisId, QwtScaleDiv scaleDiv); + void showWindow(); + void setupDefaultMenu(); + void setCustomMenu(QList &menu, QList &actions); + void getDefaultMenus(QList &menu, QList &actions); + + /** + * + * + * + * @return int + */ + int getPlotCurveCount() { return p_plotCurves.size(); } + /** + * Reuturns the plot curve at the given index. + * + * @param index + * + * @return QwtPlotCurve* + */ + QwtPlotCurve *getPlotCurve(int index) { return p_plotCurves[index]; } + + double p_xMin;//!< X minimum + double p_xMax;//!< X maximum + double p_yMin;//!< Y minimum + double p_yMax;//!< Y maximum + static bool p_curveCopied;//!< Has a curve been copied? + + protected: + QwtPlot *p_plot;//!< The plot in this window + //! Returns the name of the menu. + QString menuName() const { return "&Options"; }; + bool eventFilter(QObject *o, QEvent *e); + Qisis::TableMainWindow *p_tableWindow;//!< Table window + QList p_plotCurves; //!< List of the plot curves in this window + QToolBar *p_toolBar;//!< Tool bar on the plot window + std::string p_header;//!< Header name + std::string p_axisTitle;//!< Header name and axis title + Qisis::MainWindow *p_mainWindow; + + protected slots: + void cancelConfig(); + void copyCurve(); + void pasteCurve(); + void pasteCurveSpecial(); + void createWindow(); + void createConfigDialog(); + void createLegendMenu(); + void deleteFromTable(); + void fillInValues(int title); + void saveProperties(); + void colorSelect(); + void deleteCurve(); + void writeSettings(); + void readSettings(); + + signals: + /** + * Emitted when a curve has been copied. + * + * @param pc + */ + void curveCopied(Qisis::PlotCurve *pc); + /** + * Emitted when a curve has been requested to be pasted. + * + * @param pw + */ + void curvePaste(Qisis::PlotWindow *pw); + /** + * Emitted when a curve needs to be pasted with a new random + * color. + * + * @param pw + */ + void curvePasteSpecial(Qisis::PlotWindow *pw); + //! Emitted every time there is a change to the plot window. + void plotChanged(); + + public slots: + void clearPlot(); + void configPlot(); + void setDeletable(bool d=true); + void setPasteable(bool paste=true); + void setCopyEnable(bool c = true); + void setDestroyOnClose(bool destroy = false); + virtual void fillTable(); + void printPlot(); + void reLabel(); + void savePlot(); + void setDefaultRange(); + void setLabels(); + void setUserValues(); + void changeTitle(QString s); + void changeCurveSize(int size); + void changeCurveStyle(int style); + void changeMarkerStyle(int style); + void hideAllSymbols(); + void showCurve(); + void hideAllCurves(); + void resetScale(); + void showGrid(); + void showHelp(); + void showSymbols(); + void showTable(); + void switchBackground(); + void trackerEnabled(); + + private: + QWidget *p_parent;//!< Parent widget + QDialog *configDialog;//! +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +namespace Qisis { + + + /** + * Constructs a QHistogram object with default titles + * + * + * @param parent + */ + QHistogram::QHistogram (QWidget *parent) : QwtPlot(parent){ + p_zoomer = new QwtPlotZoomer(this->canvas()); + setTitle("Histogram Plot"); + + QwtText *leftLabel = new QwtText("Frequency",QwtText::PlainText); + leftLabel->setColor(Qt::red); + QFont font = leftLabel->font(); + font.setPointSize(13); + font.setBold(true); + leftLabel->setFont(font); + setAxisTitle(QwtPlot::yLeft,*leftLabel); + + QwtText *rtLabel = new QwtText("Percentage"); + rtLabel->setColor(Qt::blue); + rtLabel->setFont(font); + setAxisTitle(QwtPlot::yRight,*rtLabel); + + setAxisTitle(QwtPlot::xBottom,"Pixel Value (DN)"); + + setAxisScale(QwtPlot::yRight,0,100); + enableAxis(QwtPlot::yRight,true); + setCanvasBackground(Qt::white); + } + + + /** + * Plots the given Isis Histogram in the plot window + * + * @param hist The Isis Histogram to plot + */ + void QHistogram::Load (Isis::Histogram &hist) { + p_histCurve = new QwtPlotCurve(); + p_histCurve->setStyle(QwtPlotCurve::Lines); + + p_cdfCurve = new QwtPlotCurve(); + p_cdfCurve->setStyle(QwtPlotCurve::Lines); + + //Transfer data from histogram to the plotcurve + vector xarray,yarray,y2array; + double cumpct = 0.0; + for (int i=0; i 0) { + xarray.push_back(hist.BinMiddle(i)); + yarray.push_back(hist.BinCount(i)); + + double pct = (double)hist.BinCount(i) / hist.ValidPixels() * 100.; + cumpct += pct; + y2array.push_back(cumpct); + } + } + QPen *pen = new QPen(Qt::red); + pen->setWidth(2); + p_histCurve->setData(&xarray[0],&yarray[0],xarray.size()); + p_histCurve->setYAxis(QwtPlot::yLeft); + p_histCurve->setPen(*pen); + p_histCurve->attach(this); + + pen->setColor(Qt::blue); + p_cdfCurve->setData(&xarray[0],&y2array[0],xarray.size()); + p_cdfCurve->setYAxis(QwtPlot::yRight); + p_cdfCurve->setPen(*pen); + p_cdfCurve->attach(this); + + this->replot(); + p_zoomer->setZoomBase(); + } + + + /** + * Enables mouse tracking on the plot. + * + */ + void QHistogram::trackerEnabled() { + if (p_zoomer->trackerMode() == QwtPicker::ActiveOnly) { + p_zoomer->setTrackerMode(QwtPicker::AlwaysOn); + } + else { + p_zoomer->setTrackerMode(QwtPicker::ActiveOnly); + } + } + + + /** + * Hide/show the cdf curve. + * + */ + void QHistogram::cdfCurveVisible() { + p_cdfCurve->setVisible(!p_cdfCurve->isVisible()); + this->replot(); + } + + + /** + * Provide printing capabilities. + * + */ + void QHistogram::printPlot() { + // Initialize a printer + static QPrinter *printer = NULL; + if (printer == NULL) printer = new QPrinter; + printer->setPageSize(QPrinter::Letter); + printer->setColorMode(QPrinter::Color); + + QPrintDialog printDialog(printer,(QWidget *)parent()); + if (printDialog.exec() == QDialog::Accepted) { + // Get display widget as a pixmap and convert to an image + QPixmap pixmap = QPixmap::grabWidget(this); + QImage img = pixmap.toImage(); + + // C++ Gui Programmign with Qt, page 201 + QPainter painter(printer); + QRect rect = painter.viewport(); + QSize size = img.size(); + size.scale(rect.size(),Qt::KeepAspectRatio); + painter.setViewport(rect.x(),rect.y(), + size.width(),size.height()); + painter.setWindow(img.rect()); + painter.drawImage(0,0,img); + } + + } + + + /** + * Allows user to save the plot to an image file. + * + */ + void QHistogram::savePlot() { + QString output = + QFileDialog::getSaveFileName((QWidget *)parent(), + "Choose output file", + "./", + QString("Images (*.png *.jpg *.tif)")); + if (output.isEmpty()) return; + + QString format = QFileInfo(output).suffix(); + QPixmap pixmap = QPixmap::grabWidget(this); + std::string formatString = format.toStdString(); + if (!pixmap.save(output,formatString.c_str())) { + QMessageBox::information((QWidget *)parent(),"Error","Unable to save"+output); + return; + } + } + + + /** + * Switches the plot background color between black and white. + * + */ + void QHistogram::switchBackground() { + QPen *pen = new QPen(Qt::white); + if (canvasBackground() == Qt::white) { + setCanvasBackground(Qt::black); + p_zoomer->setRubberBandPen(*pen); + p_zoomer->setTrackerPen(*pen); + } + else { + setCanvasBackground(Qt::white); + pen->setColor(Qt::black); + p_zoomer->setRubberBandPen(*pen); + p_zoomer->setTrackerPen(*pen); + } + replot(); + } + + + /** + * Provides help text in a dialog box. + * + */ + void QHistogram::showHelp() { + QDialog *d = new QDialog(this); + d->setWindowTitle("Basic Help"); + + QLabel *zoomLabel = new QLabel("Zoom Options:"); + QLabel *zoomIn = new + QLabel(" Left click on the mouse, drag, and release to select an area to zoom in on"); + QLabel *zoomOut = new + QLabel(" Middle click on the mouse to zoom out one level"); + QLabel *zoomReset = new + QLabel(" Right click on the mouse to clear the zoom and return to the original plot"); + + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(zoomLabel); + layout->addWidget(zoomIn); + layout->addWidget(zoomOut); + layout->addWidget(zoomReset); + + d->setLayout(layout); + d->show(); + } + +} // end namespace isis + diff --git a/isis/src/qisis/objs/QHistogram/QHistogram.h b/isis/src/qisis/objs/QHistogram/QHistogram.h new file mode 100644 index 0000000000000000000000000000000000000000..e3ca57efb5edcf563d2022e0b6bab4d255307faf --- /dev/null +++ b/isis/src/qisis/objs/QHistogram/QHistogram.h @@ -0,0 +1,71 @@ +#ifndef QHistogram_h +#define QHistogram_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2008/06/19 18:43:47 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + #include "Histogram.h" + #include + #include + #include + #include + #include + +namespace Qisis { +/** + * @brief Plot Histograms + * + * This class is used to plot histograms. It is a utility class for the hist + * application. + * + * @ingroup Utility + * + * @author 2006-12-21 Elizabeth Miller + * + * @internal + */ + class QHistogram: public QwtPlot { + Q_OBJECT + + public: + QHistogram (QWidget *parent=NULL); + + //! Destroys the QHistogram object + ~QHistogram () {}; + + void Load(Isis::Histogram &hist); + + public slots: + void trackerEnabled(); + void cdfCurveVisible(); + void printPlot(); + void savePlot(); + void switchBackground(); + void showHelp(); + + private: + QwtPlotZoomer *p_zoomer; //!< Plot Zoomer + QwtPlotCurve *p_histCurve; //!< Historgram plot curve + QwtPlotCurve *p_cdfCurve; //!< CDF plot curve + }; +}; + +#endif diff --git a/isis/src/qisis/objs/QIsisApplication/Makefile b/isis/src/qisis/objs/QIsisApplication/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/QIsisApplication/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/QIsisApplication/QIsisApplication.cpp b/isis/src/qisis/objs/QIsisApplication/QIsisApplication.cpp new file mode 100644 index 0000000000000000000000000000000000000000..75d9383f02eef2fd24148d76fa5403402794c36c --- /dev/null +++ b/isis/src/qisis/objs/QIsisApplication/QIsisApplication.cpp @@ -0,0 +1,43 @@ +#include "QIsisApplication.h" + +#include + +#include + +namespace Qisis { + /** + * Constructor + * + * @param argc Pass this in from main(argc, argv) + * @param argv Pass this in from main(argc, argv) + */ + QIsisApplication::QIsisApplication(int &argc, char *argv[]) : + QApplication(argc, argv) { + // try to use US locale for numbers so we don't end up printing "," instead + // of "." where it might count. + setlocale(LC_NUMERIC, "en_US"); + } + + /** + * notify - this function overrides the QApplication notify as + * QT event handlers do not handle exceptions. QIsisApplication + * handles the exception by catching it and displaying the + * MessageBox Warning. + * + * @author Sharmila Prasad (11/24/2009) + * + * @param rec - QObject where the exception occured + * @param ev - Event where the exception occured + * + * @return bool + */ + bool QIsisApplication::notify(QObject *rec, QEvent *ev) { + try { + return QApplication::notify(rec, ev); + } + catch(Isis::iException &e) { + e.Clear(); + } + return false; + } +} diff --git a/isis/src/qisis/objs/QIsisApplication/QIsisApplication.h b/isis/src/qisis/objs/QIsisApplication/QIsisApplication.h new file mode 100644 index 0000000000000000000000000000000000000000..143143c9cfb0b6b2c9218ad0a1af4c8b216a9d2c --- /dev/null +++ b/isis/src/qisis/objs/QIsisApplication/QIsisApplication.h @@ -0,0 +1,64 @@ +#ifndef _QISISAPPLICATION_H_ +#define _QISISAPPLICATION_H_ + +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/06/29 23:46:35 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "IsisDebug.h" + +#include +#include +#include + +#include "WarningWidget.h" +#include "iException.h" +#include "iString.h" + +namespace Qisis { + /** + * @brief Handles exceptions which the QT event handlers and + * QApplication do not handle. + * + * This class is derived of QApplication and handles the + * exception on handled by QT event handlers and QApplication. + * This class overrides QApplication's notify(). + * + * @ingroup Qisis + * + * @author 2009-11-24 Sharmila Prasad + * + * @internal + * @history 2010-06-29 Steven Lambright - Added a setlocale to english for + * numeric values + * + * + * @todo + */ + class QIsisApplication : public QApplication { + + public: + QIsisApplication(int &argc, char *argv[]); + virtual bool notify(QObject *rec, QEvent *ev); + }; +}; + +#endif diff --git a/isis/src/qisis/objs/RubberBandComboBox/Makefile b/isis/src/qisis/objs/RubberBandComboBox/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/RubberBandComboBox/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/RubberBandComboBox/RubberBandComboBox.cpp b/isis/src/qisis/objs/RubberBandComboBox/RubberBandComboBox.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d0f1caae2ae3a921b7400326ba2ed5eb5149046 --- /dev/null +++ b/isis/src/qisis/objs/RubberBandComboBox/RubberBandComboBox.cpp @@ -0,0 +1,245 @@ +#include "RubberBandComboBox.h" + +#include + +#include "Tool.h" + +namespace Qisis { + /** + * RubberBandComboBox constructor + * + * + * @param bandingOptions + * @param defaultOption + * @param showIndicatorColors + */ + RubberBandComboBox::RubberBandComboBox(unsigned int bandingOptions, unsigned int defaultOption, bool showIndicatorColors) : + QComboBox() { + + p_showIndicatorColors = showIndicatorColors; + setDuplicatesEnabled(false); + setEditable(false); + setIconSize(QSize(24,24)); + + // We must call setCurrentIndex with the default, or the banding mode won't be set properly. Thus, + // we do need a default even if they pass in zero, which means default. + defaultOption = getDefault(defaultOption, bandingOptions); + + QAction *escapeKeyHit = new QAction(this); + escapeKeyHit->setShortcut(Qt::Key_Escape); + connect(escapeKeyHit,SIGNAL(activated()), RubberBandTool::getInstance(),SLOT(escapeKeyPress())); + addAction(escapeKeyHit); + + // The tool tip and what's this need to be set. The tool tip won't change, but the what's this should detail how to use the + // tools. So, set the tool tip and start the what's this. The what's this should only have the available tools, so create it as + // we add the tools. + setToolTip("Select Measurement Type"); + QString whatsThis = + "Function: This drop down will enable you to switch between drawing various shapes."; + + p_bandingOptionStrings.push_back("Circle"); + if((bandingOptions & Circle) == Circle) { + QIcon circleIcon(toolIconDir()+"/qview_circle.png"); + circleIcon.addFile(toolIconDir()+"/qview_circle_active.png", QSize(24,24), QIcon::Active); + + addItem(circleIcon, p_bandingOptionStrings[p_bandingOptionStrings.size()-1], QVariant((int)Circle)); + + whatsThis += "

    When Circle is selected, you can draw a perfect circle. To draw a circle, \ + click at a corner of the circle, drag the mouse until the circle is the correct shape, and release the mouse \ + to complete the circle."; + + if((defaultOption & Circle) == Circle) { + setCurrentIndex( findText(p_bandingOptionStrings[ p_bandingOptionStrings.size()-1 ]) ); + } + } + + p_bandingOptionStrings.push_back("Ellipse"); + if((bandingOptions & Ellipse) == Ellipse) { + QIcon ellipseIcon(toolIconDir()+"/qview_ellipse.png"); + ellipseIcon.addFile(toolIconDir()+"/qview_ellipse_active.png", QSize(24,24), QIcon::Active); + + addItem(ellipseIcon, p_bandingOptionStrings[p_bandingOptionStrings.size()-1], QVariant((int)Ellipse)); + + whatsThis += "

    When Ellipse is selected, you can draw an ellipse. To draw an ellipse, \ + click at a corner of the ellipse, drag the mouse until the ellipse is the correct shape, and release the mouse \ + to complete the ellipse."; + + if((defaultOption & Ellipse) == Ellipse) { + setCurrentIndex( findText(p_bandingOptionStrings[ p_bandingOptionStrings.size()-1 ]) ); + } + } + + p_bandingOptionStrings.push_back("Rectangle"); + if((bandingOptions & Rectangle) == Rectangle) { + QIcon rectangleIcon(toolIconDir()+"/qview_rectangle.png"); + rectangleIcon.addFile(toolIconDir()+"/qview_rectangle_active.png", QSize(24,24), QIcon::Active); + + addItem(rectangleIcon, p_bandingOptionStrings[p_bandingOptionStrings.size()-1], QVariant((int)Rectangle)); + + whatsThis += "

    When Rectangle is selected, you can draw a rectangle. To draw a rectangle, \ + click a corner of the rectangle, drag the mouse until the rectangle is the correct size and shape, and release the mouse \ + to complete the rectangle."; + + if((defaultOption & Rectangle) == Rectangle) { + setCurrentIndex( findText(p_bandingOptionStrings[ p_bandingOptionStrings.size()-1 ]) ); + } + } + + p_bandingOptionStrings.push_back("Rotated Rectangle"); + if((bandingOptions & RotatedRectangle) == RotatedRectangle) { + QIcon rotatedRectangleIcon(toolIconDir()+"/qview_rotated_rectangle.png"); + + addItem(rotatedRectangleIcon, p_bandingOptionStrings[p_bandingOptionStrings.size()-1], QVariant((int)RotatedRectangle)); + + whatsThis += "

    When Rotated Rectangle is selected, you can draw a rectangle rotated about its center. To draw a rotated rectangle, \ + click, drag the mouse to form the first side of the rectangle and determine it's rotation, and release the mouse. \ + Now, the final side of the rotated rectangle should follow the mouse. \ + Click again when the rotated rectangle is the correct size to complete the rotated rectangle."; + + if(p_showIndicatorColors) { + whatsThis += " The data will be calculated starting from the initial (GREEN) side of the rotated rectangle and ending at the opposite \ + side of the rotated rectangle."; + } + + if((defaultOption & RotatedRectangle) == RotatedRectangle) { + setCurrentIndex( findText(p_bandingOptionStrings[ p_bandingOptionStrings.size()-1 ]) ); + } + } + + p_bandingOptionStrings.push_back("Polygon"); + if((bandingOptions & Polygon) == Polygon) { + QIcon polygonIcon(toolIconDir()+"/qview_polygon.png"); + + addItem(polygonIcon, p_bandingOptionStrings[p_bandingOptionStrings.size()-1], QVariant((int)Polygon)); + + whatsThis += "

    When Polygon is selected, you can draw any closed polygon. To begin drawing a polygon, \ + click where you want the start point. Now, click for any new vertices or click and drag the mouse to form irregular shapes. \ + When completed, double click the final vertex and the figure will close."; + + if((defaultOption & Polygon) == Polygon) { + setCurrentIndex( findText(p_bandingOptionStrings[ p_bandingOptionStrings.size()-1 ]) ); + } + } + + p_bandingOptionStrings.push_back("Line"); + if((bandingOptions & Line) == Line) { + QIcon lineIcon(toolIconDir()+"/qview_line.png"); + lineIcon.addFile(toolIconDir()+"/qview_line_active.png", QSize(24,24), QIcon::Active); + + addItem(lineIcon, p_bandingOptionStrings[p_bandingOptionStrings.size()-1], QVariant((int)Line)); + + whatsThis += "

    When Line is selected, you can draw a line. To draw a line, \ + click the starting point of the line, drag the mouse until the line is the correct length in the correct direction, \ + and release the mouse."; + + if((defaultOption & Line) == Line) { + setCurrentIndex( findText(p_bandingOptionStrings[ p_bandingOptionStrings.size()-1 ]) ); + } + } + + p_bandingOptionStrings.push_back("Segmented Line"); + if((bandingOptions & SegmentedLine) == SegmentedLine) { + QIcon segmentedLineIcon(toolIconDir()+"/qview_segmentedline.png"); + + addItem(segmentedLineIcon, p_bandingOptionStrings[p_bandingOptionStrings.size()-1], QVariant((int)SegmentedLine)); + + whatsThis += "

    When Segmented Line is selected, you can draw any open polygon. To begin drawing a segmented line, \ + click where you want the start point. Now, click for any new vertices or click and drag the mouse to form irregular shapes. \ + When completed, double click the final vertex."; + + if((defaultOption & SegmentedLine) == SegmentedLine) { + setCurrentIndex( findText(p_bandingOptionStrings[ p_bandingOptionStrings.size()-1 ]) ); + } + } + + p_bandingOptionStrings.push_back("Angle"); + if((bandingOptions & Angle) == Angle) { + QIcon angleIcon; + angleIcon.addFile(toolIconDir()+"/qview_angle.png", QSize(24,24), QIcon::Normal); + //angleIcon.addFile(toolIconDir()+"/qview_angle_active.png", QSize(24,24), QIcon::Active); + + addItem(angleIcon, p_bandingOptionStrings[p_bandingOptionStrings.size()-1], QVariant((int)Angle)); + + whatsThis += "

    When Angle is selected, you can draw an angle from zero to 180 degrees. To draw an angle, \ + click where the first corner should go, then click where the vertex should go. Finally, click where the final \ + side of the angle should end to complete the angle."; + + if((defaultOption & Angle) == Angle) { + setCurrentIndex( findText(p_bandingOptionStrings[ p_bandingOptionStrings.size()-1 ]) ); + } + } + + connect(this,SIGNAL(currentIndexChanged(int)),this,SLOT(selectionChanged(int))); + connect(this,SIGNAL(activated(int)),this,SLOT(selectionChanged(int))); + + setWhatsThis(whatsThis); + } + + + /** + * This slot is called whenever the rubberband shape selection + * has changed. + * + * + * @param index + */ + void RubberBandComboBox::selectionChanged(int index) { + switch( itemData(index).toInt() ) { + case Angle: showAngle(); break; + case Circle: showCircle(); break; + case Ellipse: showEllipse(); break; + case Line: showLine(); break; + case Rectangle: showRectangle(); break; + case RotatedRectangle: showRotatedRectangle(); break; + case Polygon: showPolygon(); break; + case SegmentedLine: showSegmentedLine(); break; + default: + // This shouldn't happen + RubberBandTool::disable(); + break; + } + } + + /** + * Resets the selection. + * + */ + void RubberBandComboBox::reset() { + selectionChanged( currentIndex() ); + } + + + /** + * Returns the default option. + * + * + * @param defaultOption + * @param bandingOptions + * + * @return unsigned int + */ + unsigned int RubberBandComboBox::getDefault(unsigned int defaultOption, unsigned int bandingOptions) { + // The default will always be to set + // the default selection to the first, and thus the least significant bit in bandingOptions. + // We're going to find the least significant bit by shifting left and right the same amount of times, + // causing the bits to be truncated, until we see the result isn't the same as the beginning which means + // a bit was truncated. When we see this, we know where the least significant bit is so shift a '1' left by + // the appropriate amount. + if(defaultOption == 0) { + defaultOption = bandingOptions; + } + + // Find the least significant bit, that's our default. + int power = 0; + + // While cuting off the next significant bit does nothing, keep going. + while(((defaultOption >> (power+1)) << (power+1)) == defaultOption) { + power ++; + } + + defaultOption = 1 << power; + + // We are done figuring out the default option. + return defaultOption; + } +} diff --git a/isis/src/qisis/objs/RubberBandComboBox/RubberBandComboBox.h b/isis/src/qisis/objs/RubberBandComboBox/RubberBandComboBox.h new file mode 100644 index 0000000000000000000000000000000000000000..63a9ee7b045948b491380a1c994f8e7e2cefd6de --- /dev/null +++ b/isis/src/qisis/objs/RubberBandComboBox/RubberBandComboBox.h @@ -0,0 +1,78 @@ +#ifndef RubberBandComboBox_h +#define RubberBandComboBox_h + +#include + +// FIXME: Remove this include! +#include "RubberBandTool.h" + +namespace Qisis { + /** + * @brief Combo box for choosing a rubber band type + * + * @ingroup Visualization Tools + * + * @author 2007-09-11 Steven Lambright + * + * @internal + * @history 2008-09-26 Steven Lambright Added Segmented line, reordered banding + * options at Stuart's Request + * @history 2008-10-01 Steven Lambright Fixed bug with segmented line, if + * polygon was enabled then segmented line was + * @history 2010-06-26 Eric Hyer - Fixed one include issue + */ + + class RubberBandComboBox : public QComboBox { + Q_OBJECT + + public: + RubberBandComboBox(unsigned int bandingOptions, unsigned int defaultOption, bool showIndicatorColors = false); + + /** + * Enum to store rubber band shapes. + */ + enum RubberBandOptions { + Circle = 1, //!< Circle + Ellipse = 2, //!< Ellipse + Rectangle = 4, //!< Rectangle + RotatedRectangle = 8, //!< RotatedRectangle + Polygon = 16, //!< Polygon + Line = 32, //!< Line + SegmentedLine = 64, //!< Segmented Line + Angle = 128 //!< Angle + }; + + //! Returns the icon directory. + QString toolIconDir() const { return RubberBandTool::getInstance()->toolIconDir(); } + void reset(); + + protected slots: + void selectionChanged(int index); + + private: + //! This is used to figure out which option should be defaulted + unsigned int getDefault(unsigned int defaultOption, unsigned int bandingOptions); + + //! Enables the angle shape + void showAngle() { RubberBandTool::enable(RubberBandTool::Angle, p_showIndicatorColors); }; + //! Enables the circle shape + void showCircle() { RubberBandTool::enable(RubberBandTool::Circle, p_showIndicatorColors); }; + //! Enables the ellipse shape + void showEllipse() { RubberBandTool::enable(RubberBandTool::Ellipse, p_showIndicatorColors); }; + //! Enables the line + void showLine() { RubberBandTool::enable(RubberBandTool::Line, p_showIndicatorColors); }; + //! Enables the rectangle shape + void showRectangle() { RubberBandTool::enable(RubberBandTool::Rectangle, p_showIndicatorColors); }; + //! Enables the rotated rectangle shape + void showRotatedRectangle() { RubberBandTool::enable(RubberBandTool::RotatedRectangle, p_showIndicatorColors); }; + //! Enables the polygon shape + void showPolygon() { RubberBandTool::enable(RubberBandTool::Polygon, p_showIndicatorColors); }; + //! Enables the segmented line shape + void showSegmentedLine() { RubberBandTool::enable(RubberBandTool::SegmentedLine, p_showIndicatorColors); }; + + QStringList p_bandingOptionStrings; //!< List of rubberband options + bool p_showIndicatorColors; //!< Show colors? + }; +}; + +#endif diff --git a/isis/src/qisis/objs/RubberBandTool/Makefile b/isis/src/qisis/objs/RubberBandTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/RubberBandTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/RubberBandTool/RubberBandTool.cpp b/isis/src/qisis/objs/RubberBandTool/RubberBandTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d84f16e468261eb57cd13f4c300da7801d9d8d8 --- /dev/null +++ b/isis/src/qisis/objs/RubberBandTool/RubberBandTool.cpp @@ -0,0 +1,1202 @@ +#include "RubberBandTool.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "geos/geom/CoordinateArraySequence.h" +#include "geos/geom/CoordinateSequence.h" +#include "geos/geom/Coordinate.h" +#include "geos/geom/LineString.h" +#include "geos/geom/MultiLineString.h" +#include "geos/geom/Polygon.h" + +#include "Constants.h" +#include "MdiCubeViewport.h" +#include "PolygonTools.h" +#include "SerialNumberList.h" + + +namespace Qisis { + RubberBandTool *RubberBandTool::p_instance = NULL; + + + /** + * This method returns the singleton instance of the rubber band tool. + * The first call to this method must have the optional argument *parent so + * the tool can properly initialize. After this tool is created, *parent is ignored. + * + * @param parent A pointer to the main window for the tool to properly initialize + * + * @return RubberBandTool* An instance of the rubber band tool + */ + RubberBandTool *RubberBandTool::getInstance(QWidget *parent) { + if(p_instance == NULL) { + p_instance = new RubberBandTool(parent); + } + + return p_instance; + } + + + void RubberBandTool::enable(RubberBandTool::RubberBandMode mode, + bool showIndicatorColors) { + getInstance()->enableBanding(mode, showIndicatorColors); + } + + + + /** + * This is the constructor. It's private because this class is a singleton. + * + * @param parent + */ + RubberBandTool::RubberBandTool(QWidget *parent) : Qisis::Tool(parent) { + p_mouseLoc = NULL; + p_vertices = NULL; + + p_mouseLoc = new QPoint; + p_vertices = new QList< QPoint >; + + activate(false); + repaint(); + } + + RubberBandTool::~RubberBandTool() { + if(p_mouseLoc) { + delete p_mouseLoc; + p_mouseLoc = NULL; + } + + if(p_vertices) { + delete p_vertices; + p_vertices = NULL; + } + } + + /** + * This is the main paint method for the rubber bands. + * + * For angles and lines, simply connect the known vertices.vertices[0].x() + * For polygons, paint the vertices & close if completed the shape. + * For circles, figure out the circle's square and draw the circle inside of it. + * For Ellipses, figure out the Ellipse's rectangle and draw the circle inside of it. + * For rectangles, paint the rectangle either to the mouse or back to the start depending on if the shape is complete. + * For rotated rectangles, if we can interpolate extra sides draw them and draw all known sides. + * + * @param vp + * @param painter + */ + void RubberBandTool::paintViewport(MdiCubeViewport *vp, QPainter *painter) { + QPen pen(QColor(255, 0, 0)); + QPen greenPen(QColor(0, 255, 0)); + pen.setStyle(Qt::SolidLine); + greenPen.setStyle(Qt::SolidLine); + painter->setPen(pen); + + if(vp != cubeViewport()) { + return; + } + + switch(p_bandingMode) { + case Angle: + paintVerticesConnected(painter); + break; + + case Line: + // if point needed, draw an X + if(figureIsPoint() && !p_tracking) { + painter->drawLine((*p_vertices)[0].x() - 10, (*p_vertices)[0].y() - 10, + (*p_vertices)[0].x() + 10, (*p_vertices)[0].y() + 10); + painter->drawLine((*p_vertices)[0].x() - 10, (*p_vertices)[0].y() + 10, + (*p_vertices)[0].x() + 10, (*p_vertices)[0].y() - 10); + } + else { + paintVerticesConnected(painter); + } + + break; + + case Polygon: + paintVerticesConnected(painter); + + if(!p_tracking && p_vertices->size() > 0) { + painter->drawLine((*p_vertices)[0], (*p_vertices)[ p_vertices->size() - 1 ]); + } + break; + + case Circle: + case Ellipse: { + if(p_vertices->size() != 0) { + QList vertices = getFoundVertices(); + int width = 2 * (vertices[1].x() - vertices[0].x()); + int height = 2 * (vertices[1].y() - vertices[0].y()); + + // upper left x,y,width,height + painter->drawEllipse(vertices[0].x() - width / 2, vertices[0].y() - height / 2, + width, + height + ); + } + } + break; + + case Rectangle: { + if(figureIsPoint() && !p_tracking) { + painter->drawLine((*p_vertices)[0].x() - 10, (*p_vertices)[0].y() - 10, + (*p_vertices)[0].x() + 10, (*p_vertices)[0].y() + 10); + painter->drawLine((*p_vertices)[0].x() - 10, (*p_vertices)[0].y() + 10, + (*p_vertices)[0].x() + 10, (*p_vertices)[0].y() - 10); + } + else { + if(p_tracking && p_vertices->size() > 0) { + paintRectangle((*p_vertices)[0], *p_mouseLoc, painter); + } + else if(p_vertices->size() > 0) { + paintVerticesConnected(painter); + painter->drawLine((*p_vertices)[0], (*p_vertices)[ p_vertices->size() - 1 ]); + } + } + } + break; + + case RotatedRectangle: { + if(p_vertices->size() == 2) { + QPoint missingVertex; + calcRectCorners((*p_vertices)[0], (*p_vertices)[1], *p_mouseLoc, missingVertex); + painter->drawLine(*p_mouseLoc, missingVertex); + painter->drawLine(missingVertex, (*p_vertices)[0]); + } + else if(p_vertices->size() == 4) { + painter->drawLine((*p_vertices)[0], (*p_vertices)[ 3 ]); + } + + paintVerticesConnected(painter); + + // Draw indicator on top of original lines if applicable + if(p_indicatorColors) { + painter->setPen(greenPen); + if(p_vertices->size() > 1) { + painter->drawLine((*p_vertices)[0], (*p_vertices)[1]); + } + else if(p_vertices->size() == 1) { + painter->drawLine((*p_vertices)[0], *p_mouseLoc); + } + + painter->setPen(pen); + } + } + break; + + case SegmentedLine: + paintVerticesConnected(painter); + break; + } + } + + /** + * Given two set corners, and the mouse location, this method will interpolate the last two corners. + * + * @param corner1 Known point + * @param corner2 Known point + * @param corner3 Guessed corner (point to interpolate to). + * @param corner4 Unknown corner. + */ + void RubberBandTool::calcRectCorners(QPoint corner1, QPoint corner2, QPoint &corner3, QPoint &corner4) { + double slope = ((double)corner2.y() - (double)corner1.y()) / ((double)corner2.x() - (double)corner1.x()); + int delta_x; + int delta_y; + + if((fabs(slope) > DBL_EPSILON) && (slope < DBL_MAX) && (slope > -DBL_MAX)) { + // corner1,corner2 make up y=m(x-x1)+y1 + // corner3,corner4 must make up || line crossing corner3. + // b (y-intercept) is what differs from the original line and our parallel line. + // Go ahead and figure out our new b by using b = -mx1+y1 from the point-slope formula. + double parallelB = -1 * slope * corner3.x() + corner3.y(); + + // Now we have our equation for a parallel line, which our new points lie on. Let's find the perpendicular lines + // which cross corner1,corner2 in order to figure out where they cross it. Use -1/slope = perpendicular slope and + // now we have y=m(x-x1)+y1. What we care about is b in y=mx+b, so figure it out using b = m*(-x1)+y1 + double perpSlope = -1.0 / slope; + double perpLine1b = perpSlope * (-1 * corner1.x()) + corner1.y(); + double perpLine2b = perpSlope * (-1 * corner2.x()) + corner2.y(); + + // Now let's find the perpendicular lines' intercepts on the parallel line. + // y = mx+b = y = mx+b => mx+b(perpendicular) = mx+b(parallel) for the perp. lines and the parallel line. + // Combine the b's on the left to make y= m(perp)x+k = m(par)x. + double perpLine1k = perpLine1b - parallelB; + double perpLine2k = perpLine2b - parallelB; + + // Now we have mx + k = mx (parallel). Divive the parallel slope out to get + // (m(perp)x+k)/m(parallel) = x. Move the x over from the left side of the equation by subtracting... + // k/m(parallel) = x - m(perp)x/m(parallel). Factor out the x's... k/m(par) = x(1-m(per)/m(par)) and divive + // both sides by "(1-m(per)/m(par))". So we end up with: (k/m(par)) / (1 - m(per) / m(par) ) = + // k/m(par) / ( (m(par)-m(per)) / m(par) ) = k / m(par) * m(par) / (m(par) - m(per)) = k / (m(par) - m(per)) + double perpLine1IntersectX = perpLine1k / (slope - perpSlope); + double perpLine2IntersectX = perpLine2k / (slope - perpSlope); + + // The intersecting X values are now known, and the equation of the parallel line, so let's roll with it and + // get our two corners set. perpLine1 => corner1 => corner4, perpLine2 => corner2 => corner3 + corner3.setX((int)perpLine2IntersectX); + corner3.setY((int)(perpLine2IntersectX * slope + parallelB)); //mx+b + corner4.setX((int)perpLine1IntersectX); + corner4.setY((int)(perpLine1IntersectX * slope + parallelB)); //mx+b + } + else if(fabs(slope) < DBL_EPSILON) { + delta_x = 0; + delta_y = corner3.y() - corner2.y(); + corner3.setX(corner2.x()); + corner3.setY(corner3.y()); + corner4.setX(corner1.x()); + corner4.setY(corner3.y()); + } + else { + delta_x = corner3.x() - corner2.x(); + corner3.setX(corner3.x()); + corner3.setY(corner2.y()); + corner4.setX(corner3.x()); + corner4.setY(corner1.y()); + } + } + + /** + * This paints connecting lines to p_vertices. If tracking, a line is also drawn to + * the mouse location. + * + * @param painter + */ + void RubberBandTool::paintVerticesConnected(QPainter *painter) { + for(int vertex = 1; vertex < p_vertices->size(); vertex++) { + QPoint start = (*p_vertices)[vertex - 1]; + QPoint end = (*p_vertices)[vertex]; + + painter->drawLine(start, end); + } + + if(p_tracking && (p_vertices->size() > 0)) { + QPoint start = (*p_vertices)[p_vertices->size() - 1]; + QPoint end = *p_mouseLoc; + + painter->drawLine(start, end); + } + } + + /** + * Given opposite corners, the other two are interpolated and the rectangle is drawn. + * + * @param upperLeft Corner opposite of lowerRight + * @param lowerRight Corner opposite of upperLeft + * @param painter + */ + void RubberBandTool::paintRectangle(QPoint upperLeft, QPoint lowerRight, QPainter *painter) { + QPoint upperRight = QPoint(lowerRight.x(), upperLeft.y()); + QPoint lowerLeft = QPoint(upperLeft.x(), lowerRight.y()); + + paintRectangle(upperLeft, upperRight, lowerLeft, lowerRight, painter); + } + + /** + * This draws a box around the 4 points using the painter. + * + * @param upperLeft Initial corner + * @param upperRight Corner connected to upperLeft, lowerRight + * @param lowerLeft Corner connected to lowerRight, upperLeft + * @param lowerRight Corner connected to lowerLeft, upperRight + * @param painter + */ + void RubberBandTool::paintRectangle(QPoint upperLeft, QPoint upperRight, + QPoint lowerLeft, QPoint lowerRight, QPainter *painter) { + painter->drawLine(upperLeft, upperRight); + painter->drawLine(upperRight, lowerRight); + painter->drawLine(lowerRight, lowerLeft); + painter->drawLine(lowerLeft, upperLeft); + } + + /** + * This is called when changing modes or turning on. So, set the mode, reset, and activate + * our event handlers. + * + * @param mode + * @param showIndicatorColors Color the first side of figures differently + */ + void RubberBandTool::enableBanding(RubberBandMode mode, bool showIndicatorColors) { + RubberBandMode oldMode = p_bandingMode; + p_bandingMode = mode; + p_indicatorColors = showIndicatorColors; + //Took this out because it was reseting and not letting us plot single points. + //p_pointTolerance = 0; + p_allClicks = false; + reset(); + activate(true); + + if(oldMode != mode) { + emit modeChanged(); + } + } + + /** + * This is called when something is not using me, so + * turn off events, reset & repaint to clear the clear. + */ + void RubberBandTool::disableBanding() { + + activate(false); + reset(); + repaint(); + } + + /** + * This triggers on a second mouse press. Only polygons care about this, and it signifies an end of + * shape. So, if we're in polygon mode, stop tracking the mouse and emit a complete. + * @param p + */ + void RubberBandTool::mouseDoubleClick(QPoint p) { + p_doubleClicking = true; + *p_mouseLoc = p; + + switch(p_bandingMode) { + case Angle: + case Circle: + case Ellipse: + case Line: + case Rectangle: + case RotatedRectangle: + break; + + case SegmentedLine: + case Polygon: + p_tracking = false; + repaint(); + emit bandingComplete(); + break; + } + } + + /** + * If the click is not the left mouse button, this does nothing. + * + * This will set mouseDown as true. When the calculations are complete, + * p_mouseDown is set to true. + * + * For drag-only, + * A press means starting a new rubber band so reset & record the point. This applies to + * Circles, Eliipsoids, Lines and Rectangles. + * + * For Rotated Rectangles, + * A mount press means we're starting over, setting the first point, or completing. + * For the first two, simply reset and record the point. For the latter, figure out the + * corners and store those points. + * + * For polygons, + * A press means record the current point. Reset first if we're not currently drawing. + * + * @param p + * @param s + */ + void RubberBandTool::mouseButtonPress(QPoint p, Qt::MouseButton s) { + *p_mouseLoc = p; + + if((s & Qt::LeftButton) != Qt::LeftButton && !p_allClicks) { + return; + } + + switch(p_bandingMode) { + case Angle: + break; + + case Circle: + case Ellipse: + case Line: + case Rectangle: + reset(); + p_tracking = true; + p_vertices->push_back(p); + break; + + case RotatedRectangle: + if(p_vertices->size() == 4) { + reset(); + } + + if(p_vertices->size() == 0) { + p_vertices->push_back(p); + p_tracking = true; + } + break; + + case SegmentedLine: + case Polygon: + if(!p_tracking) { + reset(); + p_tracking = true; + } + + if(p_vertices->size() == 0 || (*p_vertices)[ p_vertices->size() - 1 ] != p) { + p_vertices->push_back(p); + } + + break; + } + + p_mouseDown = true; + } + + /** + * If this is not the left mouse button, this does nothing. + * + * This will set mouseDown as false. When the calculations are complete, + * p_doubleClicking is + * set to false. The double click event occurs with + * `the press event so it's safe to set that flag here. + * + * The implementation differs, based on the mode, as follows: + * + * For angles, + * This signifies a click. We're always setting one of the + * three vertexes, but if there is an already + * complete vertex go ahead and reset first to start a new angle. + * + * For circles, + * Since this is a drag-only rubber band, a release signifies a complete. Figure out the corner, based + * on the mouse location, and push it onto the back of the vertex list and emit a complete. + * + * For Ellipses, + * Since this is a drag-only rubber band, a release signifies a complete. We know the corner, it's the mouse loc, + * push it onto the back of the vertex list and emit a complete. + * + * For lines, + * Since this is a drag-only rubber band, a release signifies a complete. We know the end point, + * push it onto the back of the vertex list and emit a complete. + * + * For rectangles, + * Since this is a drag-only rubber band, a release signifies a complete. We know the opposite corner, + * figure out the others and push them onto the back of the vertex list and emit a complete. + * + * For rotated rectangles, + * If we're finishing dragging the first side, store the end point. + * + * For polygons, + * Do nothing, this is taken care of on press. + * + * @param p Current mouse Location + * @param s Which mouse button was released + */ + void RubberBandTool::mouseButtonRelease(QPoint p, Qt::MouseButton s) { + *p_mouseLoc = p; + p_mouseButton = s; + + if((s & Qt::LeftButton) == Qt::LeftButton || p_allClicks) { + p_mouseDown = false; + } + else { + return; + } + + switch(p_bandingMode) { + case Angle: { + if(p_vertices->size() == 3) { + reset(); + } + + p_vertices->push_back(p); + p_tracking = true; + + if(p_vertices->size() == 3) { + p_tracking = false; + emit bandingComplete(); + } + } + break; + + case Line: + case Circle: + case Ellipse: + case Rectangle: { + *p_vertices = getFoundVertices(); + p_tracking = false; + repaint(); + emit bandingComplete(); + } + break; + + case RotatedRectangle: { + if(p_vertices->size() == 1) { + p_vertices->push_back(p); + } + else if(p_vertices->size() == 2) { + *p_vertices = getFoundVertices(); + p_tracking = false; + emit bandingComplete(); + } + } + break; + + case SegmentedLine: + case Polygon: + break; + } + + p_doubleClicking = false; // If we were in a double click, it's over now. + } + + /** + * If tracking is not enabled, this does nothing. + * + * This will first update the mouse location for painting purposes. + * + * Most of the implementation is a matter of emitting measureChanges: + * For angles, if the first two vertices are specified a measureChange will be emitted. + * For circles, if the center of the circle is known a measureChange will be emitted. + * For Ellipses, if the center of the Ellipse is known a measureChange will be emitted. + * For lines, if the first point of the line is known a measureChange will be emitted. + * For rectangles, if the starting point is known a measureChange will be emitted. + * For rotated rectangles, if the first side is specified a measureChange will be emitted. + * + * However, there is one exception: + * For polygons, if the mouse button is pressed the mouse location is recorded as a valid vertex. + * + * @param p Current mouse Location + */ + void RubberBandTool::mouseMove(QPoint p) { + if(!p_tracking) { + return; + } + + // Store the mouse location for painting the polygons + QPoint oldMouseLoc = *p_mouseLoc; + *p_mouseLoc = p; + + switch(p_bandingMode) { + case Angle: + case RotatedRectangle: + if(p_vertices->size() == 2) { + emit measureChange(); + } + break; + + case Circle: + case Ellipse: + case Rectangle: + if(p_vertices->size() == 1) { + emit measureChange(); + } + break; + + case Line: + emit measureChange(); + break; + + case SegmentedLine: + case Polygon: { + if(p_mouseDown && p != (*p_vertices)[ p_vertices->size() - 1 ]) { + p_vertices->push_back(p); + } + } + break; + } + + // Repaint because tracking is enabled, meaning we're drawing to the mouse loc + repaint(); + } + + /** + * This method returns the vertices. The return value is mode-specific, and the return will be + * consistent whether in a measureChange or bandingComplete slot. + * + * The return values are always in pixels. + * + * The return values are as follows: + * For angles, the return will always be of size 3. The elements at 0 and 2 are the edges of the angle, + * while the element at 1 is the vertex of the angle. + * + * For circles, the return will always be of size 2. The element at 0 is the center of the circle, and the + * element at 1 is offset by the radius in both directions. + * + * For Ellipses, the return will always be of size 2. The element at 0 is the center of the circle, and the + * element at 1 is offset by the radius in both directions. + * + * For lines, the return will always be of size 2. The elements are the start and end points. + * + * For rectangles, the return will always be of size 4. The elements will be the corners, + * in either a clockwise or counter-clockwise direction. + * + * For rotated rectangles, the same applies. + * + * For polygons, the return will be a list of vertices in the order that the user drew them. + * + * **It is NOT valid to call this unless you're in a measureChange or bandingComplete slot. + * + * @return QList + */ + QList RubberBandTool::getFoundVertices() { + QList vertices = *p_vertices; + + if(!figureComplete()) + return vertices; + + if(p_tracking) { + switch(p_bandingMode) { + case Angle: + case Line: + vertices.push_back(*p_mouseLoc); + break; + + case Rectangle: { + QPoint corner1 = QPoint(p_mouseLoc->x(), vertices[0].y()); + QPoint corner2 = QPoint(p_mouseLoc->x(), p_mouseLoc->y()); + QPoint corner3 = QPoint(vertices[0].x(), p_mouseLoc->y()); + vertices.push_back(corner1); + vertices.push_back(corner2); + vertices.push_back(corner3); + } + break; + + case RotatedRectangle: { + QPoint missingVertex; + calcRectCorners((*p_vertices)[0], (*p_vertices)[1], *p_mouseLoc, missingVertex); + vertices.push_back(*p_mouseLoc); + vertices.push_back(missingVertex); + } + break; + + + case Circle: { + int xradius = abs(p_mouseLoc->x() - vertices[0].x()) / 2; + int yradius = xradius; + + if(p_mouseLoc->x() - vertices[0].x() < 0) { + xradius *= -1; + } + + if(p_mouseLoc->y() - vertices[0].y() < 0) { + yradius *= -1; + } + + // Adjust p_vertices[0] from upper left to center + vertices[0].setX(vertices[0].x() + xradius); + vertices[0].setY(vertices[0].y() + yradius); + + vertices.push_back(*p_mouseLoc); + + vertices[1].setX(vertices[0].x() + xradius); + vertices[1].setY(vertices[0].y() + yradius); + } + break; + + case Ellipse: { + // Adjust p_vertices[0] from upper left to center + double xradius = (p_mouseLoc->x() - vertices[0].x()) / 2.0; + double yradius = (p_mouseLoc->y() - vertices[0].y()) / 2.0; + vertices[0].setX((int)(vertices[0].x() + xradius)); + vertices[0].setY((int)(vertices[0].y() + yradius)); + + vertices.push_back(*p_mouseLoc); + } + break; + + case SegmentedLine: + case Polygon: + break; + } + } + + return vertices; + } + + /** + * This initializes the class except for the current mode, which is + * set on enable. + * + */ + void RubberBandTool::reset() { + p_vertices->clear(); + p_tracking = false; + p_mouseDown = false; + p_doubleClicking = false; + repaint(); + } + + double RubberBandTool::getAngleMeasure() { + double angle = 0; + + if(getCurrentMode() == Angle) { + // We cancluate the angle by considering each line an angle itself, with respect to the + // X-Axis, and then differencing them. + // + // theta1 = arctan((point0Y - point1Y) / (point0X - point1X)) + // theta2 = arctan((point2Y - point1Y) / (point2X - point1X)) + // | + // | / <-- point0 + // | / | + // | / | + // theta1 | / | + // --> |/ | <-- 90 degrees + // point1 --> ------|--------------------------- + //(vertex) --> |\ | <-- 90 degrees + // theta2 | \ | + // | \ | + // | \ | + // | \ | + // | \| + // | | <-- point 2 + // + // angle = theta1 - theta2; ** + QList vertices = getFoundVertices(); + double theta1 = atan2((double)(vertices[0].y() - vertices[1].y()), (double)(vertices[0].x() - vertices[1].x())); + double theta2 = atan2((double)(vertices[2].y() - vertices[1].y()), (double)(vertices[2].x() - vertices[1].x())); + angle = (theta1 - theta2); + + // Force the angle into [0,2PI] + while(angle < 0.0) { + angle += Isis::PI * 2; + } + while(angle > Isis::PI * 2) { + angle -= Isis::PI * 2; + } + + // With our [0,2PI] angle, let's make it [0,PI] to get the interior angle. + if(angle > Isis::PI) { + angle = (Isis::PI * 2.0) - angle; + } + } + + return angle; + } + + /** + * This method will call the viewport's repaint if there is a current cube viewport. + */ + void RubberBandTool::repaint() { + if(p_cvp != NULL) { + p_cvp->viewport()->repaint(); + } + } + + /** + * + * + * @return geos::Geometry* + */ + geos::geom::Geometry *RubberBandTool::getGeometry() { + geos::geom::Geometry *geometry = NULL; + QList vertices = getFoundVertices(); + + switch(p_bandingMode) { + case Angle: { + if(vertices.size() != 3) + break; + + geos::geom::CoordinateSequence *points1 = new geos::geom::CoordinateArraySequence(); + geos::geom::CoordinateSequence *points2 = new geos::geom::CoordinateArraySequence(); + + points1->add(geos::geom::Coordinate(vertices[0].x(), vertices[0].y())); + points1->add(geos::geom::Coordinate(vertices[1].x(), vertices[1].y())); + points2->add(geos::geom::Coordinate(vertices[1].x(), vertices[1].y())); + points2->add(geos::geom::Coordinate(vertices[2].x(), vertices[2].y())); + + geos::geom::LineString *line1 = Isis::globalFactory.createLineString(points1); + geos::geom::LineString *line2 = Isis::globalFactory.createLineString(points2); + std::vector *lines = new std::vector; + lines->push_back(line1); + lines->push_back(line2); + + geos::geom::MultiLineString *angle = Isis::globalFactory.createMultiLineString(lines); + geometry = angle; + } + break; + + case Circle: + case Ellipse: { + if(vertices.size() != 2) + break; + // A circle is an ellipse, so it gets no special case + // Equation of an ellipse: (x-h)^2/a^2 + (y-k)^2/b^2 = 1 where + // h is the X-location of the center, k is the Y-location of the center + // a is the x-radius and b is the y-radius. + // Solving for y, we get + // y = +-sqrt(b^2(1-(x-h)^2/a^2)) + k + // and our domain is [h-a,h+a] + // We need the equation of this ellipse! + double h = vertices[0].x(); + double k = vertices[0].y(); + double a = abs(vertices[0].x() - vertices[1].x()); + double b = abs(vertices[0].y() - vertices[1].y()); + if(a == 0) + break; // Return null, we can't make an ellipse from this. + if(b == 0) + break; // Return null, we can't make an ellipse from this. + + // We're ready to try to solve + double originalX = 0.0, originalY = 0.0; + geos::geom::CoordinateSequence *points = new geos::geom::CoordinateArraySequence(); + + // Now iterate through our domain, solving for y positive, using 1/5th of a pixel increments + for(double x = h - a; x <= h + a; x += 0.2) { + double y = sqrt(pow(b, 2) * (1.0 - pow((x - h), 2) / pow(a, 2))) + k; + points->add(geos::geom::Coordinate(x, y)); + + if(x == h - a) { + originalX = x; + originalY = y; + } + } + + // Iterate through our domain backwards, solving for y negative, using 1/5th of a pixel decrements + for(double x = h + a; x >= h - a; x -= 0.2) { + double y = -1.0 * sqrt(pow(b, 2) * (1.0 - pow((x - h), 2) / pow(a, 2))) + k; + points->add(geos::geom::Coordinate(x, y)); + } + + points->add(geos::geom::Coordinate(originalX, originalY)); + + geometry = Isis::globalFactory.createPolygon( + Isis::globalFactory.createLinearRing(points), NULL + ); + } + break; + + case Rectangle: + case RotatedRectangle: + case Polygon: { + if(vertices.size() < 3) + break; + + geos::geom::CoordinateSequence *points = new geos::geom::CoordinateArraySequence(); + + for(int vertex = 0; vertex < vertices.size(); vertex++) { + points->add(geos::geom::Coordinate(vertices[vertex].x(), vertices[vertex].y())); + } + + points->add(geos::geom::Coordinate(vertices[0].x(), vertices[0].y())); + + geometry = Isis::globalFactory.createPolygon(Isis::globalFactory.createLinearRing(points), NULL); + + } + break; + + case Line: { + if(vertices.size() != 2) + break; + geos::geom::CoordinateSequence *points = new geos::geom::CoordinateArraySequence(); + points->add(geos::geom::Coordinate(vertices[0].x(), vertices[0].y())); + points->add(geos::geom::Coordinate(vertices[1].x(), vertices[1].y())); + geos::geom::LineString *line = Isis::globalFactory.createLineString(points); + geometry = line; + } + break; + + case SegmentedLine: { + if(vertices.size() < 2) + break; + geos::geom::CoordinateSequence *points = new geos::geom::CoordinateArraySequence(); + + for(int vertex = 0; vertex < vertices.size(); vertex++) { + points->add(geos::geom::Coordinate(vertices[vertex].x(), vertices[vertex].y())); + } + + geos::geom::LineString *line = Isis::globalFactory.createLineString(points); + geometry = line; + } + break; + } + + if(geometry != NULL && !geometry->isValid()) { + geometry = NULL; + } + + return geometry; + } + + /** + * This method returns a rectangle from the vertices set by the + * RubberBandTool. It calculates the upper left and bottom right + * points for the rectangle and properly initializes a QRect + * object with these vertices. If the RubberBandTool is in the + * incorrect mode, or the rectangle is not valid it will return + * an error message. + * + * + * @return QRect The QRect the user selected on the viewport in + * pixels + */ + QRect RubberBandTool::getRectangle() { + QRect rect; + + if(getCurrentMode() == Rectangle && figureValid()) { + QList vertices = getFoundVertices(); + + //Check the corners for upper left and lower right. + int x1, x2, y1, y2; + //Point 1 is in the left, make point1.x upperleft.x + if(vertices[0].x() < vertices[2].x()) { + x1 = vertices[0].x(); + x2 = vertices[2].x(); + } + //Otherwise Point1 is in the right, make point1.x lowerright.x + else { + x1 = vertices[2].x(); + x2 = vertices[0].x(); + } + + //Point 1 is in the top, make point1.y upperleft.y + if(vertices[0].y() < vertices[2].y()) { + y1 = vertices[0].y(); + y2 = vertices[2].y(); + } + //Otherwise Point1 is in the bottom, make point1.y lowerright.y + else { + y1 = vertices[2].y(); + y2 = vertices[0].y(); + } + + rect = QRect(x1, y1, x2 - x1, y2 - y1); + } + //Rectangle is not valid, or RubberBandTool is in the wrong mode, return error + else { + QMessageBox::information((QWidget *)parent(), + "Error", "**PROGRAMMER ERROR** Invalid Rectangle"); + } + + return rect; + } + + /** + * This method returns the mouse button modifier + * + * @return MouseButton Mouse button modifier on last release + */ + Qt::MouseButton RubberBandTool::getMouseButton() { + return p_mouseButton; + } + + bool RubberBandTool::figureComplete() { + bool complete = false; + + switch(p_bandingMode) { + case Angle: + complete = (p_vertices->size() == 2 && p_tracking) || (p_vertices->size() == 3); + break; + case Line: + complete = (p_vertices->size() == 1 && p_tracking) || (p_vertices->size() == 2); + break; + + case Rectangle: + complete = (p_vertices->size() == 1 && p_tracking) || (p_vertices->size() == 4); + break; + + case RotatedRectangle: + complete = (p_vertices->size() == 2 && p_tracking) || (p_vertices->size() == 4); + break; + + case Circle: + case Ellipse: + complete = (p_vertices->size() == 1 && p_tracking) || (p_vertices->size() == 2); + break; + + case SegmentedLine: + complete = (p_vertices->size() > 1 && !p_tracking); + break; + + case Polygon: + complete = (p_vertices->size() > 2 && !p_tracking); + break; + } + return complete; + } + + bool RubberBandTool::figureValid() { + if(!figureComplete()) + return false; + bool valid = true; + QList vertices = getFoundVertices(); + + switch(p_bandingMode) { + case Angle: { + // Just make sure the vertex and an angle side don't lie on the same point + // No point tolerance allowed + valid = vertices[0].x() != vertices[1].x() || vertices[0].y() != vertices[1].y(); + valid &= vertices[2].x() != vertices[1].x() || vertices[2].y() != vertices[1].y(); + } + break; + case Line: { + // Just make sure the line doesnt start/end at same point if point not allowed + if(p_pointTolerance == 0) { + valid = vertices[0].x() != vertices[1].x() || vertices[0].y() != vertices[1].y(); + } + } + break; + + case Rectangle: { + // Make sure there's a height and width if point not allowed + if(p_pointTolerance == 0) { + valid = vertices[0].x() != vertices[2].x() && vertices[0].y() != vertices[2].y(); + } + } + break; + + case RotatedRectangle: { + // Make sure there's a height and width once again, point tolerance not allowed + valid = vertices[0].x() != vertices[1].x() || vertices[0].y() != vertices[1].y(); + valid &= vertices[1].x() != vertices[2].x() || vertices[1].y() != vertices[2].y(); + } + break; + + case Circle: + case Ellipse: { + // Make sure there's a height and width, point tolerance not allowed + valid = vertices[0].x() != vertices[1].x() && vertices[0].y() != vertices[1].y(); + } + break; + + case SegmentedLine: { + valid = vertices.size() > 1; + } + break; + + case Polygon: { + // For polygons, we must revert back to using geos + geos::geom::Geometry *poly = getGeometry(); + valid = poly && poly->isValid(); + delete poly; + } + break; + } + + return valid; + } + + void RubberBandTool::enablePoints(unsigned int pixTolerance) { + p_pointTolerance = pixTolerance; + } + + bool RubberBandTool::figureIsPoint() { + if(!figureValid()) + return false; + bool isPoint = true; + QList vertices = getFoundVertices(); + + switch(p_bandingMode) { + case Angle: + case RotatedRectangle: + case Circle: + case Ellipse: + case Polygon: + case SegmentedLine: + isPoint = false; + break; + + case Line: { + isPoint = (abs(vertices[0].x() - vertices[1].x()) + + abs(vertices[0].y() - vertices[1].y()) < (int)p_pointTolerance); + } + break; + + case Rectangle: { + isPoint = (abs(vertices[0].x() - vertices[2].x()) + + abs(vertices[0].y() - vertices[2].y()) < (int)p_pointTolerance); + } + break; + } + + return isPoint; + } + + + //! clears the rubber band! + void RubberBandTool::clear() { + getInstance()->reset(); + getInstance()->repaint(); + } + + QRect RubberBandTool::rectangle() { + return getInstance()->getRectangle(); + } + + + void RubberBandTool::disable() { + getInstance()->disableBanding(); + } + + + QList RubberBandTool::getVertices() { + return getInstance()->getFoundVertices(); + } + + + RubberBandTool::RubberBandMode RubberBandTool::getMode() { + return getInstance()->getCurrentMode(); + } + + + RubberBandTool::RubberBandMode RubberBandTool::getCurrentMode() { + return p_bandingMode; + }; + + + double RubberBandTool::getArea() { + return getInstance()->getAreaMeasure(); + } + + + double RubberBandTool::getAreaMeasure() { + return 0.0; //getAngleMeasure(); + } + + + geos::geom::Geometry *RubberBandTool::geometry() { + return getInstance()->getGeometry(); + } + + + Qt::MouseButton RubberBandTool::mouseButton() { + return getInstance()->getMouseButton(); + } + + + //figureValid(); + } + + + bool RubberBandTool::isPoint() { + return getInstance()->figureIsPoint(); + } + + + void RubberBandTool::allowPoints(unsigned int pixTolerance) { + getInstance()->enablePoints(pixTolerance); + } + + + void RubberBandTool::allowAllClicks() { + getInstance()->enableAllClicks(); + } + + + void RubberBandTool::enableAllClicks() { + p_allClicks = true; + } + + + void RubberBandTool::escapeKeyPress() { + reset(); + } + + + void RubberBandTool::scaleChanged() { + reset(); + } + + +} diff --git a/isis/src/qisis/objs/RubberBandTool/RubberBandTool.h b/isis/src/qisis/objs/RubberBandTool/RubberBandTool.h new file mode 100644 index 0000000000000000000000000000000000000000..73fb3c94b5ae4453099150cf90a305564291af60 --- /dev/null +++ b/isis/src/qisis/objs/RubberBandTool/RubberBandTool.h @@ -0,0 +1,143 @@ +#ifndef RubberBandTool_h +#define RubberBandTool_h + +#include "Tool.h" + +class QRect; +class QPoint; + +template class QList; + +namespace geos { + namespace geom { + class Geometry; + } +} + + +namespace Qisis { + class MdiCubeViewport; + + /** + * @brief Rubber banding tool + * + * @ingroup Visualization Tools + * + * @author 2007-09-11 Steven Lambright + * + * @internal + * @history 2006-01-01 Jeff Anderson Original version + * @history 2008-01-03 Steven Lambright bug fix on the polygons + * @history 2008-05-23 Noah Hilt added getRectangle method + * @history 2008-08-18 Steven Koechle updated to work with Geos 3.0.0 + * @history 2008-09-26 Steven Lambright Added Segmented line + * @history 2010-05-24 Eric Hyer - Added clear() method + * @history 2010-06-03 Eric Hyer - Fixed bug in getInstance method + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport + */ + class RubberBandTool : public Tool { + Q_OBJECT + + public: + static RubberBandTool *getInstance(QWidget *parent = NULL); + virtual ~RubberBandTool(); + + enum RubberBandMode { + Angle, // getVertices(); + QList getFoundVertices(); + + static RubberBandMode getMode(); + RubberBandMode getCurrentMode(); + static double getArea(); + double getAreaMeasure(); + static double getAngle(); + double getAngleMeasure(); // * p_vertices; //cube(); + p_cube2 = cube2->cube(); + + p_cube1Viewport = cube1; + p_cube2Viewport = cube2; + + p_band1 = band1; + p_band2 = band2; + p_numBins1 = numBins1; + p_numBins2 = numBins2; + + //initializing the 2D vector + for(unsigned int i = 0; i < 257; i++) { + p_counts.push_back(std::vector()); + for(unsigned int j = 0; j < 257; j++) { + p_counts[i].push_back(0); + } + } + + //------------------------------- + // stretch cube one / band one + //------------------------------- + double ssamp,esamp,sline,eline; + p_cube1Viewport->viewportToCube(0,0,ssamp,sline); + p_cube1Viewport->viewportToCube(p_cube1Viewport->viewport()->width()-1, + p_cube1Viewport->viewport()->height()-1, + esamp,eline); + + + Isis::Statistics stats; + Isis::Brick brick(1,1,1, p_cube1->PixelType()); + + int bufns1 = (int)esamp - (int)ssamp + 1; + brick.Resize(bufns1,1,1); + + //for (int line=(int)sline; line <= (int)eline; line+=lineRate) { + for (int line=(int)sline; line <= (int)eline; line++) { + brick.SetBasePosition((int)ssamp,line,band1); + p_cube1->Read(brick); + stats.AddData(brick.DoubleBuffer(),bufns1); + } + + p_min1 = stats.Minimum(); + p_max1 = stats.Maximum(); + p_str1.AddPair(p_min1, 0); + p_str1.AddPair(p_max1, numBins1 - 1); + + //---------------------------- + // stretch cube two / band two + //----------------------------- + p_cube2Viewport->viewportToCube(0,0,ssamp,sline); + p_cube2Viewport->viewportToCube(p_cube2Viewport->viewport()->width()-1, + p_cube2Viewport->viewport()->height()-1, + esamp,eline); + + stats.Reset(); + int bufns2 = (int)esamp - (int)ssamp + 1; + brick.Resize(bufns2,1,1); + + //for (int line=(int)sline; line <=(int) eline; line+=lineRate) { + for (int line=(int)sline; line <= (int)eline; line++) { + brick.SetBasePosition((int)ssamp,line,band2); + p_cube2->Read(brick); + stats.AddData(brick.DoubleBuffer(),bufns2); + } + + p_min2 = stats.Minimum(); + + p_max2 = stats.Maximum(); + p_str2.AddPair(p_min2, 0); + p_str2.AddPair(p_max2, numBins2 - 1); + + // ------------------------------------- + // Done getting min max for both cubes! + // ------------------------------------- + + setBoundingRect(QwtDoubleRect(p_min1, p_min2, p_max1, p_max2)); + + Isis::Brick brick1(1,1,1, p_cube1->PixelType()); + Isis::Brick brick2(1,1,1, p_cube2->PixelType()); + + // ----------------------------------------------- + // If the actual cube size is smaller than the + // visible cube viewport area, we don't need + // to loop through all the access lines/samples. + // ----------------------------------------------- + if((esamp-ssamp) > p_cube1->Samples()) { + ssamp = 0; + esamp = p_cube1->Samples(); + } + if((eline-sline) > p_cube1->Lines()) { + sline = 0; + eline = p_cube1->Lines(); + } + + for(int s = (int)ssamp; s < (int)esamp; s++) { + for (int l=(int)sline; l <= (int)eline; l++) { + brick1.SetBasePosition(s,l, band1); + p_cube1->Read(brick1); + + unsigned int x = (int)(p_str1.Map(brick1[0])); + + brick2.SetBasePosition(s,l, band2); + p_cube2->Read(brick2); + + unsigned int y = (int)(p_str2.Map(brick2[0])); + if(x < p_counts.size() && y < p_counts.size()) { + p_counts[x][y] = p_counts[x][y]+1; + } + } + } + } //end SpectrogramData contstructor + + + /** + * Destructor + * + */ + ScatterPlotData::~ScatterPlotData(){ + p_cube1->Close(); + p_cube2->Close(); + } + + + /** + * Returns a copy of the ScatterPlotData object. + * + */ + QwtRasterData *ScatterPlotData::copy() const{ + return new ScatterPlotData(p_cube1Viewport, p_band1, p_numBins1, p_cube1Viewport, + p_band2, p_numBins2); + } + + + /** + * Returns the range of the counts. + * + */ + QwtDoubleInterval ScatterPlotData::range() const{ + int max = 0; + for(unsigned int i = 0; i < p_counts.size(); i++) { + for(unsigned int j = 0; j < p_counts.size(); j++) { + if(p_counts[i][j] > max) max = p_counts[i][j]; + } + } + return QwtDoubleInterval(0.0, max); + } + + + /** + * This gets called every time the scatter plot is re-drawn. + * It returns the counts for each DN (x), DN (y). + */ + double ScatterPlotData::value(double x, double y) const{ + unsigned int iX = (int)(p_str1.Map(x)); + unsigned int iY = (int)(p_str2.Map(y)); + + if(iX >= p_counts.size() || iY >= p_counts.size()) { + return 0; + } + return p_counts[iX][iY]; + } + +} diff --git a/isis/src/qisis/objs/ScatterPlotTool/ScatterPlotData.h b/isis/src/qisis/objs/ScatterPlotTool/ScatterPlotData.h new file mode 100644 index 0000000000000000000000000000000000000000..b227ff5e821347c708b8d229b5a2723ba2e1ef82 --- /dev/null +++ b/isis/src/qisis/objs/ScatterPlotTool/ScatterPlotData.h @@ -0,0 +1,64 @@ +#ifndef ScatterPlotData_h +#define ScatterPlotData_h + +#include +#include +#include + +#include "Cube.h" +#include "Stretch.h" +#include "Histogram.h" +#include "Brick.h" +#include "CubeViewport.h" + +#include + +namespace Qisis { + + class ScatterPlotData: public QwtRasterData { + + public: + ScatterPlotData(CubeViewport *cube1, int band1, int numbBins1, CubeViewport *cube2, int band2, int numBins2); + ~ScatterPlotData(); + virtual QwtRasterData *copy() const; + virtual QwtDoubleInterval range() const; + virtual double value(double x, double y) const; + + int bandOne() const { return p_band1; }; + int bandTwo() const { return p_band2; }; + + int numberOfBins() const { return p_numBins1; }; + + double minOne() const { return p_min1; }; + double minTwo() const { return p_min2; }; + + double maxOne() const { return p_max1; }; + double maxTwo() const { return p_max2; }; + + Isis::Cube * cubeOne() const { return p_cube1; }; + Isis::Cube * cubeTwo() const { return p_cube2; }; + + + private: + Isis::Cube *p_cube1; //!< Cube 1 + Isis::Cube *p_cube2; //!< Cube 2 + CubeViewport *p_cube1Viewport; //!< CubeViewport 1 + CubeViewport *p_cube2Viewport; //!< CubeViewport 2 + Isis::Stretch p_str1; //!< Stretch 1 + Isis::Stretch p_str2; //!< Stretch 2 + std::vector< std::vector > p_counts; //!< 2D Vector of ints. + double p_min1; //!< Minimum for cube 1 + double p_min2; //!< Minimum for cube 2 + double p_max1; //!< Maximum for cube 1 + double p_max2; //!< Maximum for cube 2 + + int p_band1; //!< Band for cube 1 + int p_band2; //!< Band for cube 2 + int p_numBins1; //!< Number of Bins + int p_numBins2; + + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/ScatterPlotTool/ScatterPlotTool.cpp b/isis/src/qisis/objs/ScatterPlotTool/ScatterPlotTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1aff011c8de7d4534f766e51c302326ff9fccc8 --- /dev/null +++ b/isis/src/qisis/objs/ScatterPlotTool/ScatterPlotTool.cpp @@ -0,0 +1,79 @@ +#include "ScatterPlotTool.h" + + +#include "MdiCubeViewport.h" +#include "ScatterPlotWindow.h" +#include "ToolPad.h" + +namespace Qisis { + + /** + * ScatterPlotTool constructor. + * + * @param parent + */ + ScatterPlotTool::ScatterPlotTool (QWidget *parent): Qisis::Tool(parent){ + p_parent = parent; + createWindow(); + } + + + /** + * Instantiates the scatter plot window. + * + */ + void ScatterPlotTool::createWindow(){ + + p_mainWindow = new ScatterPlotWindow("Scatter Plot Window", this, p_parent); + + } + + + /** + * Gives the programmer more flexibility on when the action + * button for this tool is checked or not. + * + * + * @param checked + */ + void ScatterPlotTool::setActionChecked(bool checked){ + p_action->setChecked(checked); + } + + + /** + * Configure the QAction for this tool. + * + * @param toolpad + * + * @return QAction* + */ + QAction *ScatterPlotTool::toolPadAction(ToolPad *toolpad) { + p_action = new QAction(toolpad); + p_action->setIcon(QPixmap(toolIconDir()+"/scatterplot.png")); + p_action->setToolTip("Scatter Plot"); + //action->setShortcut(Qt::Key_C); + QObject::connect(p_action,SIGNAL(activated()),p_mainWindow,SLOT(showConfig())); + + QString text = + "Function: Compare two bands of same image or of a different image. \ +

    Shortcut:nonexsistant right now

    "; + p_action->setWhatsThis(text); + return p_action; + } + + + /** + * Returns the list of cube viewports currently open in Qview. + * + * + * @return CubeViewportList* + */ + ScatterPlotTool::CubeViewportList * ScatterPlotTool::getCubeViewportList() + const + { + return cubeViewportList(); + } + +} + diff --git a/isis/src/qisis/objs/ScatterPlotTool/ScatterPlotTool.h b/isis/src/qisis/objs/ScatterPlotTool/ScatterPlotTool.h new file mode 100644 index 0000000000000000000000000000000000000000..1172851eb37154ecfdee90a0d250cafdb7d40e71 --- /dev/null +++ b/isis/src/qisis/objs/ScatterPlotTool/ScatterPlotTool.h @@ -0,0 +1,60 @@ +#ifndef ScatterPlotTool_h +#define ScatterPlotTool_h + +// this is the only include allowed in this file! +#include "Tool.h" + + +class QAction; +template< class T > class QVector; +class QWidget; + +namespace Qisis { + class MdiCubeViewport; + class ScatterPlotWindow; + + /** + * @brief Scatter Plot Tool + * + * @author Stacy Alley + * @internal + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport instead of + * CubeViewport. Also fixed some include issues. + */ + class ScatterPlotTool : public Tool { + Q_OBJECT + + public: + ScatterPlotTool (QWidget * parent); + void setActionChecked(bool checked); + + typedef QVector< MdiCubeViewport * > CubeViewportList; + CubeViewportList * getCubeViewportList() const; + + protected: + void createWindow(); + QAction *toolPadAction(ToolPad * pad); + + + /** + * Returns this tool's action + * + * + * @return QAction* + */ + QAction * toolAction() { return p_action; }; + + private: + ScatterPlotWindow * p_mainWindow; //! + +#include +#include +#include +#include +#include +#include +#include + + +#include "MdiCubeViewport.h" +#include "ScatterPlotData.h" +#include "ScatterPlotTool.h" +#include "ViewportMainWindow.h" +#include "Workspace.h" + +namespace Qisis { + + + /** + * ScatterPlotToolWindow constructor. + * + * + * @param title + * @param tool + * @param parent + */ + ScatterPlotWindow::ScatterPlotWindow (QString title, ScatterPlotTool *tool, QWidget *parent): Qisis::MainWindow(title, parent){ + p_parent = parent; + p_tool = tool; + + p_scatterPlotWindow = new MainWindow(title); + p_scatterPlotWindow->setFixedSize(QSize(700,700)); + p_plot = new QwtPlot(); + p_plot->plotLayout()->setAlignCanvasToScales(true); + p_zoomer = new MyZoomer(p_plot->canvas()); + + p_scatterPlotWindow->setCentralWidget(p_plot); + + setupMenus(); + createDialogs(); + } + + + /** + * This method creates all the dialog boxes required for the + * scatter plot window. Called from the ScatterPlotWindow + * constructor. + * + */ + void ScatterPlotWindow::createDialogs(){ + QDialogButtonBox *configButtonBox; + QLabel *label; + QLabel *label2; + QLabel *label3; + + p_configDialog = new QDialog(); + p_configDialog->setWindowTitle("Setup Scatter Plot"); + p_configDialog->setModal(true); + + configButtonBox = new QDialogButtonBox(p_configDialog); + configButtonBox->setGeometry(QRect(30, 200, 341, 32)); + configButtonBox->setOrientation(Qt::Horizontal); + configButtonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok); + + p_cube1Label = new QLabel(p_configDialog); + p_cube1Label->setText("Cube 1:"); + p_cube1Label->setGeometry(QRect(10, 70, 75, 27)); + + p_cube1BandComboBox = new QComboBox(p_configDialog); + p_cube1BandComboBox->setGeometry(QRect(250, 70, 60, 22)); + + p_numBinsOne = new QLineEdit(p_configDialog); + p_numBinsOne->setGeometry(QRect(320, 70, 40, 22)); + p_numBinsOne->setText("255"); + + p_numBinsTwo = new QLineEdit(p_configDialog); + p_numBinsTwo->setGeometry(QRect(320, 130, 40, 22)); + p_numBinsTwo->setText("255"); + + p_cube2BandComboBox = new QComboBox(p_configDialog); + p_cube2BandComboBox->setGeometry(QRect(250, 130, 60, 22)); + + p_cube1ComboBox = new QComboBox(p_configDialog); + p_cube1ComboBox->setGeometry(QRect(55, 70, 181, 25)); + QObject::connect(p_cube1ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(fillBands())); + + p_cube2ComboBox = new QComboBox(p_configDialog); + p_cube2ComboBox->setGeometry(QRect(55, 130, 181, 25)); + QObject::connect(p_cube2ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(fillBands())); + + p_cube2Label = new QLabel(p_configDialog); + p_cube2Label->setText("Cube 2:"); + p_cube2Label->setGeometry(QRect(10, 130, 75, 27)); + + label = new QLabel(p_configDialog); + label->setObjectName(QString::fromUtf8("label")); + label->setText("Band"); + label->setGeometry(QRect(260, 40, 81, 20)); + + label2 = new QLabel(p_configDialog); + label2->setObjectName(QString::fromUtf8("label2")); + label2->setText("Select 2 Cubes (may be the same cube.)"); + label2->setGeometry(QRect(10, 40, 230, 20)); + + label3 = new QLabel(p_configDialog); + label3->setText("# Bins"); + label3->setGeometry(QRect(320,40,70,20)); + + + QObject::connect(configButtonBox, SIGNAL(accepted()), this, SLOT(showScatterPlot())); + QObject::connect(configButtonBox, SIGNAL(accepted()), p_configDialog, SLOT(accept())); + QObject::connect(configButtonBox, SIGNAL(rejected()), this, SLOT(cancel())); + + // -------- End of p_configDialog + + QDialogButtonBox *minMaxButtonBox; + QLabel *label_5; + QLabel *label_4; + QLabel *label_6; + QLabel *label_2; + QLabel *label_3; + QLabel *label_0; + p_minMaxDialog = new QDialog(); + + p_minMaxDialog->resize(283, 300); + minMaxButtonBox = new QDialogButtonBox(p_minMaxDialog); + minMaxButtonBox->setGeometry(QRect(20, 250, 211, 32)); + minMaxButtonBox->setOrientation(Qt::Horizontal); + minMaxButtonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok); + + p_yMaxEdit = new QLineEdit(p_minMaxDialog); + p_yMaxEdit->setGeometry(QRect(100, 200, 113, 25)); + p_yMaxEdit->setText(QString::number(p_MaxTwo)); + p_yMinEdit = new QLineEdit(p_minMaxDialog); + p_yMinEdit->setGeometry(QRect(100, 160, 113, 25)); + p_yMinEdit->setText(QString::number(p_MinTwo)); + p_xMaxEdit = new QLineEdit(p_minMaxDialog); + p_xMaxEdit->setGeometry(QRect(100, 90, 113, 25)); + p_xMaxEdit->setText(QString::number(p_MaxOne)); + p_xMinEdit = new QLineEdit(p_minMaxDialog); + p_xMinEdit->setGeometry(QRect(100, 50, 113, 25)); + p_xMinEdit->setText(QString::number(p_MinOne)); + label_5 = new QLabel(p_minMaxDialog); + label_5->setGeometry(QRect(25, 170, 56, 17)); + label_4 = new QLabel(p_minMaxDialog); + label_4->setGeometry(QRect(120, 130, 56, 17)); + + label_6 = new QLabel(p_minMaxDialog); + label_6->setGeometry(QRect(25, 210, 56, 17)); + label_2 = new QLabel(p_minMaxDialog); + label_2->setGeometry(QRect(25, 60, 56, 17)); + label_3 = new QLabel(p_minMaxDialog); + label_3->setGeometry(QRect(25, 100, 56, 17)); + label_0 = new QLabel(p_minMaxDialog); + label_0->setGeometry(QRect(120, 20, 56, 17)); + + p_minMaxDialog->setWindowTitle("Set Display Range"); + label_5->setText("Minimum"); + label_6->setText( "Maximum"); + label_2->setText("Minimum"); + label_3->setText("Maximum"); + label_0->setText("X-Axis"); + label_4->setText("Y-Axis"); + + QObject::connect(minMaxButtonBox, SIGNAL(accepted()), this, SLOT(setUserValues())); + QObject::connect(minMaxButtonBox, SIGNAL(accepted()), p_minMaxDialog, SLOT(accept())); + QObject::connect(minMaxButtonBox, SIGNAL(rejected()), p_minMaxDialog, SLOT(reject())); + + // -------- End of p_minMaxDialog + } + + + /** + * Displays the p_configDialog box. + * + */ + void ScatterPlotWindow::showConfig(){ + // ---------------------------------------------------- + // Populate the combo box with the filenames currently + // open in Qview + // ---------------------------------------------------- + QVector< MdiCubeViewport * > * cubeList = ((ViewportMainWindow *)(p_parent))->workspace()->cubeViewportList(); + for(int i = 0; i < cubeList->size(); i++) { + std::string cubeFilename= cubeList->at(i)->cube()->Filename(); + QString str = QFileInfo(cubeFilename.c_str()).fileName(); + // --------------------------------------------------------- + // Make sure we are not adding the same text more than once. + // --------------------------------------------------------- + if(p_cube1ComboBox->findText(str) == -1) { + p_cube1ComboBox->addItem(str); + } + } + + cubeList = ((ViewportMainWindow *)(p_parent))->workspace()->cubeViewportList(); + for(int i = 0; i < cubeList->size(); i++) { + std::string cubeFilename= cubeList->at(i)->cube()->Filename(); + QString str = QFileInfo(cubeFilename.c_str()).fileName(); + // --------------------------------------------------------- + // Make sure we are not adding the same text more than once. + // --------------------------------------------------------- + if(p_cube2ComboBox->findText(str) == -1) { + p_cube2ComboBox->addItem(str); + } + } + + fillBands(); + + // ------------------------------------------------ + // Make sure the band combo boxes are already filled + // with the last bands the user selected + // ----------------------------------------------- + if(p_band1 > 0) { + p_cube1BandComboBox->setCurrentIndex(p_band1 - 1); + p_cube2BandComboBox->setCurrentIndex(p_band2 - 1); + } + + p_configDialog->show(); + } + + + /** + * Fills the p_cubeXComboBox with the correct number of bands + * based on the selected cube. + * + */ + void ScatterPlotWindow::fillBands(){ + int numBands1 = 0; + int numBands2 = 0; + QVector< MdiCubeViewport * > * cubeList = ((ViewportMainWindow *)(p_parent))->workspace()->cubeViewportList(); + for(int i = 0; i < cubeList->size(); i++) { + std::string cubeFilename= cubeList->at(i)->cube()->Filename(); + QString str = QFileInfo(cubeFilename.c_str()).fileName(); + if(str.compare(p_cube1ComboBox->currentText()) == 0) { + numBands1 = cubeList->at(i)->cubeBands(); + } + if(str.compare(p_cube2ComboBox->currentText()) == 0) { + numBands2 = cubeList->at(i)->cubeBands(); + } + } + p_cube1BandComboBox->clear(); + for(int j = 0; j < numBands1; j++) { + p_cube1BandComboBox->addItem(QString::number(j+1)); + } + + p_cube2BandComboBox->clear(); + for(int j = 0; j < numBands2; j++) { + p_cube2BandComboBox->addItem(QString::number(j+1)); + } + } + + + /** + * Get the cubes from the config dialog box and figures out + * which viewportmainwindow the cube is associated with and then + * creates the ScatterPlotData and the QwtSpectrogram and + * attaches it to the plot. Once the plot is configured the + * scatter plot window is shown. + * + */ + void ScatterPlotWindow::showScatterPlot(){ + QString cube1 = p_cube1ComboBox->currentText(); + QString cube2 = p_cube2ComboBox->currentText(); + if(cube1 == "" || cube2 == ""){ + p_tool->setActionChecked(false); + return; + } + + p_plot->setTitle(cube1 + " VS " + cube2); + + //------------------------------------------------------ + // Now we need the viewportmainwindow associated with + // each cube. + //------------------------------------------------------ + MdiCubeViewport *cube1Viewport = NULL; + MdiCubeViewport *cube2Viewport = NULL; + QVector< MdiCubeViewport * > * cubeList = ((ViewportMainWindow *)(p_parent))->workspace()->cubeViewportList(); + for(int i = 0; i < cubeList->size(); i++) { + std::string cubeFilename= cubeList->at(i)->cube()->Filename(); + QString str = QFileInfo(cubeFilename.c_str()).fileName(); + if(str.compare(cube1) == 0){ + cube1Viewport = cubeList->at(i); + } + if(str.compare(cube2) == 0){ + cube2Viewport = cubeList->at(i); + } + } + + // ----------------------------------------------- + // Check to make sure the two cubes have the same + // number of lines and samples + // ----------------------------------------------- + double ssamp1,esamp1,sline1,eline1; + double ssamp2,esamp2,sline2,eline2; + cube1Viewport->viewportToCube(0,0,ssamp1,sline1); + cube1Viewport->viewportToCube(cube1Viewport->viewport()->width()-1, + cube1Viewport->viewport()->height()-1, + esamp1,eline1); + + cube2Viewport->viewportToCube(0,0,ssamp2,sline2); + cube2Viewport->viewportToCube(cube2Viewport->viewport()->width()-1, + cube2Viewport->viewport()->height()-1, + esamp2,eline2); + + if((int)(esamp1 - ssamp1) != (int)(esamp2 - ssamp2) || (int)(eline1 - sline1) != (int)(eline2 - sline2)) { + QMessageBox::critical(p_configDialog, "Size Issue", "The visible area of the cubes must be the same size!",QMessageBox::Ok); + p_tool->setActionChecked(false); + return; + } + + p_configDialog->setCursor(Qt::WaitCursor); + + //---------------------------------------------- + // Get the band the user selected for each cube + // to call with the ScatterPlotData constructor + //--------------------------------------------- + p_band1 = p_cube1BandComboBox->currentIndex()+1; + p_band2 = p_cube2BandComboBox->currentIndex()+1; + + //------------------------------------------------------------ + // Instantiate the QwtPlotSpectrogram and the ScatterPlotData + // then attach to the plot. + //---------------------------------------------------------- + p_spectrogram = new QwtPlotSpectrogram(); + int numbins1 = p_numBinsOne->text().toInt(); + int numbins2 = p_numBinsTwo->text().toInt(); + ScatterPlotData *data = new ScatterPlotData(cube1Viewport, p_band1, numbins1, cube2Viewport, p_band2, numbins2); + p_spectrogram->setData(*data); + p_spectrogram->attach(p_plot); + + QwtValueList contourLevels; + QwtDoubleInterval range = data->range(); + + // ----------------------------------------------------- + // Setup the contour levels for the contour lines + // on the spectrogram. + // ------------------------------------------------------ + for ( double level = 0.5; level < range.maxValue(); level += (range.maxValue() / 6) ) + contourLevels += level; + p_spectrogram->setContourLevels(contourLevels); + + if(p_colorize->text().compare("Colorize") == 0) { + QwtLinearColorMap colorMap(Qt::black, Qt::white); + p_spectrogram->setColorMap(colorMap); + } else { + QwtLinearColorMap colorMap(Qt::darkCyan, Qt::red); + colorMap.addColorStop(0.05, Qt::cyan); + colorMap.addColorStop(0.3, Qt::green); + colorMap.addColorStop(0.50, Qt::yellow); + p_spectrogram->setColorMap(colorMap); + } + + // ------------------------------------------- + // Setup a color bar on the right axis + // using the color map created above. + // ------------------------------------------- + p_rightAxis = p_plot->axisWidget(QwtPlot::yRight); + p_rightAxis->setTitle("Counts"); + p_rightAxis->setColorBarEnabled(true); + p_rightAxis->setColorMap(p_spectrogram->data().range(), + p_spectrogram->colorMap()); + + p_plot->setAxisScale(QwtPlot::yRight, + p_spectrogram->data().range().minValue(), + p_spectrogram->data().range().maxValue() ); + p_plot->enableAxis(QwtPlot::yRight); + + // ---------------------------------------------------------------- + // Setup the plots min/max and both axes to be the min/max for the + // data associated with those axes. + // Also set the axes titles to the cube name and which band on that + // cube. + // ----------------------------------------------------------------- + p_MinOne = data->minOne(); + p_MaxOne = data->maxOne(); + p_MinTwo = data->minTwo(); + p_MaxTwo = data->maxTwo(); + p_plot->setAxisScale(QwtPlot::yLeft, p_MinTwo, p_MaxTwo); + p_plot->setAxisScale(QwtPlot::xBottom, p_MinOne, p_MaxOne); + p_plot->setAxisTitle(QwtPlot::xBottom, cube1 + " Band "+ QString::number(p_band1)); + p_plot->setAxisTitle(QwtPlot::yLeft, cube2 + " Band " + QString::number(p_band2)); + p_plot->replot(); + p_zoomer->setZoomBase(); + + p_scatterPlotWindow->show(); + p_configDialog->setCursor(Qt::ArrowCursor); + p_tool->setActionChecked(false); + } + + /** + * Called when user clicks the cancel button on the + * p_configdialog box. + * + */ + void ScatterPlotWindow::cancel(){ + p_configDialog->hide(); + p_tool->setActionChecked(false); + } + + + /** + * Set up the menus for the ScatterPlotWindow. + * Called from the constructor. + */ + void ScatterPlotWindow::setupMenus(){ + p_menubar = p_scatterPlotWindow->menuBar(); + p_toolBar = new QToolBar(p_scatterPlotWindow); + + p_scatterPlotWindow->addToolBar(Qt::TopToolBarArea,p_toolBar); + + QAction *fitLine = new QAction(p_plot); + fitLine->setText("Line Fit"); + fitLine->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/linefit.png")); + QObject::connect(fitLine, SIGNAL(activated()), this, SLOT(showContour())); + + p_colorize = new QAction(p_plot); + p_colorize->setText("Colorize"); + p_colorize->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/rgb.png")); + QString text = + "Colorize"; + p_colorize->setWhatsThis(text); + QObject::connect(p_colorize,SIGNAL(activated()),this,SLOT(colorPlot())); + + QAction *save = new QAction(p_plot); + save->setText("&Save Plot As"); + save->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/filesaveas.png")); + text = + "Function: Save the plot as a png, jpg, or tif file."; + save->setWhatsThis(text); + QObject::connect(save,SIGNAL(activated()),this,SLOT(savePlot())); + + QAction *prt = new QAction(p_plot); + prt->setText("&Print Plot"); + prt->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/fileprint.png")); + text = + "Function: Sends the plot image to the printer"; + prt->setWhatsThis(text); + QObject::connect(prt,SIGNAL(activated()),this,SLOT(printPlot())); + + QAction *track = new QAction(p_plot); + track->setText("Show Mouse &Tracking"); + track->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/goto.png")); + track->setCheckable(true); + text = + "Function: Displays the x,y coordinates as the cursor moves \ + around on the plot."; + track->setWhatsThis(text); + QObject::connect(track,SIGNAL(activated()),this,SLOT(trackerEnabled())); + + QAction *changeLabels = new QAction(p_plot); + changeLabels->setText("Rename Plot &Labels"); + changeLabels->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_renameLabels.png")); + text = + "Function: Edit the plot title, x and y axis labels."; + changeLabels->setWhatsThis(text); + QObject::connect(changeLabels,SIGNAL(activated()),this,SLOT(reLabel())); + + QAction *changeScale = new QAction(p_plot); + changeScale->setText("Set &Display Range"); + changeScale->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_setScale.png")); + text = + "Function: Adjust the scale for the x and y axis on the plot."; + changeScale->setWhatsThis(text); + QObject::connect(changeScale,SIGNAL(activated()),this, SLOT(setDisplayRange())); + + QAction *resetScaleButton = new QAction(p_plot); + resetScaleButton->setText("Reset Scale"); + resetScaleButton->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/plot_resetscale.png")); + text = + "Function: Reset the plot's scale."; + resetScaleButton->setWhatsThis(text); + QObject::connect(resetScaleButton, SIGNAL(activated()),this, SLOT(resetScale())); + + QAction *close = new QAction(p_plot); + close->setText("Close"); + QObject::connect(close,SIGNAL(activated()),p_scatterPlotWindow, SLOT(close())); + + /*setup menus*/ + QMenu *options = new QMenu("&Options"); + options->addAction(track); + options->addAction(changeLabels); + options->addAction(changeScale); + + QMenu *file = new QMenu("&File"); + file->addAction(save); + file->addAction(prt); + file->addAction(close); + + p_menubar->addMenu(file); + p_menubar->addMenu(options); + + p_toolBar->addAction(track); + p_toolBar->addAction(changeLabels); + p_toolBar->addAction(changeScale); + p_toolBar->addAction(p_colorize); + p_toolBar->addAction(fitLine); + } + + + /** + * This method allows the user to save the plot as a png, + * jpg, or tif image file. + */ + void ScatterPlotWindow::savePlot() { + QPixmap pixmap; + QString output = + QFileDialog::getSaveFileName((QWidget *)parent(), + "Choose output file", + "./", + QString("Images (*.png *.jpg *.tif)")); + if (output.isEmpty()) return; + //Make sure the filename is valid + if (!output.isEmpty()) { + if(!output.endsWith(".png") && !output.endsWith(".jpg") && !output.endsWith(".tif")) { + output = output + ".png"; + } + } + + QString format = QFileInfo(output).suffix(); + pixmap = QPixmap::grabWidget(p_plot); + + std::string formatString = format.toStdString(); + if (!pixmap.save(output,formatString.c_str())) { + QMessageBox::information((QWidget *)parent(),"Error","Unable to save "+ output); + return; + } + } + + + /** + * Provides printing support of the plot image. + * + */ + void ScatterPlotWindow::printPlot() { + QPixmap pixmap; + /* Initialize a printer*/ + static QPrinter *printer = NULL; + if (printer == NULL) printer = new QPrinter; + printer->setPageSize(QPrinter::Letter); + printer->setColorMode(QPrinter::Color); + + QPrintDialog printDialog(printer,(QWidget *)parent()); + + if (printDialog.exec() == QDialog::Accepted) { + /* Get display widget as a pixmap and convert to an image*/ + pixmap = QPixmap::grabWidget(p_plot); + QImage img = pixmap.toImage(); + /* C++ Gui Programming with Qt, page 201*/ + QPainter painter(printer); + QRect rect = painter.viewport(); + QSize size = img.size(); + size.scale(rect.size(),Qt::KeepAspectRatio); + painter.setViewport(rect.x(),rect.y(), + size.width(),size.height()); + painter.setWindow(img.rect()); + painter.drawImage(0,0,img); + } + } + + + /** + * Sets plot scale back to the defaults. + * + */ + void ScatterPlotWindow::resetScale(){ + setScale(QwtPlot::xBottom, p_MinOne, p_MaxOne); + setScale(QwtPlot::yLeft, p_MinTwo, p_MaxTwo); + } + + + /** + * This method sets the scale of the axis on the plot + * + * + * @param axisId + * @param minimum + * @param maximum + */ + void ScatterPlotWindow::setScale(int axisId, double minimum, double maximum, double stepSize) { + if(axisId == QwtPlot::xBottom){ + p_MaxOne = maximum; + p_MinOne = minimum; + } + + if(axisId == QwtPlot::yLeft){ + p_MaxTwo = maximum; + p_MinTwo = minimum; + } + + p_plot->setAxisScale(axisId,minimum,maximum, stepSize); + p_plot->replot(); + p_zoomer->setZoomBase(); + p_scaled = true; + } + + + /** + * Creates and brings up the dialog box which allows the user to + * re-label the plot various labes. + * + */ + void ScatterPlotWindow::reLabel() { + QDialog *dialog = new QDialog(p_scatterPlotWindow); + dialog->setWindowTitle("Name Plot Labels"); + + QWidget *buttons = new QWidget (dialog); + QWidget *textAreas = new QWidget (dialog); + QWidget *labels = new QWidget (dialog); + QWidget *main = new QWidget (dialog); + + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(main,0); + layout->addWidget(buttons,0); + dialog->setLayout(layout); + + QToolButton *okButton = new QToolButton(dialog); + connect(okButton,SIGNAL(released()),this,SLOT(setLabels())); + connect(okButton,SIGNAL(released()),dialog,SLOT(hide())); + okButton->setShortcut(Qt::Key_Enter); + okButton->setText("Ok"); + + QToolButton *cancelButton = new QToolButton(dialog); + connect(cancelButton,SIGNAL(released()),dialog,SLOT(hide())); + cancelButton->setText("Cancel"); + + QLabel *plotLabel = new QLabel("Plot Title: "); + QLabel *xAxisLabel = new QLabel("X-Axis Label: "); + QLabel *yAxisLabel = new QLabel("Y-Axis Label: "); + + QVBoxLayout *vlayout = new QVBoxLayout(); + vlayout->addWidget(plotLabel); + vlayout->addWidget(xAxisLabel); + vlayout->addWidget(yAxisLabel); + labels->setLayout(vlayout); + + p_plotTitleText = new QLineEdit(p_plot->title().text(),dialog); + p_xAxisText = new QLineEdit(p_plot->axisTitle(QwtPlot::xBottom).text(),dialog); + p_yAxisText = new QLineEdit(p_plot->axisTitle(QwtPlot::yLeft).text(),dialog); + + QVBoxLayout *v2layout = new QVBoxLayout(); + v2layout->addWidget(p_plotTitleText); + v2layout->addWidget(p_xAxisText); + v2layout->addWidget(p_yAxisText); + textAreas->setLayout(v2layout); + + QHBoxLayout *mainLayout = new QHBoxLayout(); + mainLayout->addWidget(labels); + mainLayout->addWidget(textAreas); + main->setLayout(mainLayout); + + QHBoxLayout *hlayout = new QHBoxLayout(); + hlayout->addWidget(okButton); + hlayout->addWidget(cancelButton); + buttons->setLayout(hlayout); + + dialog->setFixedSize(400,190); + dialog->show(); + } + + + /** + * This method actually sets the plot's labels to the user + * specified labels. + * + */ + void ScatterPlotWindow::setLabels() { + p_plot->setTitle(p_plotTitleText->text()); + p_plot->setAxisTitle(QwtPlot::xBottom,p_xAxisText->text()); + p_plot->setAxisTitle(QwtPlot::yLeft,p_yAxisText->text()); + /*Replot with new labels.*/ + p_plot->replot(); + } + + + /** + * This method switches the color mode of the scatter plot from + * black and white to color and visa versa. + * + */ + void ScatterPlotWindow::colorPlot(){ + if(p_colorize->text().compare("Colorize") == 0) { + p_colorize->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/gray.png")); + p_colorize->setText("Gray"); + QwtLinearColorMap colorMap(Qt::darkCyan, Qt::red); + colorMap.addColorStop(0.05, Qt::cyan); + colorMap.addColorStop(0.3, Qt::green); + colorMap.addColorStop(0.50, Qt::yellow); + p_spectrogram->setColorMap(colorMap); + + } else { + p_colorize->setIcon(QPixmap("/usgs/cpkgs/isis3/data/base/icons/rgb.png")); + p_colorize->setText("Colorize"); + QwtLinearColorMap colorMap(Qt::black, Qt::white); + p_spectrogram->setColorMap(colorMap); + } + + p_rightAxis->setColorMap(p_spectrogram->data().range(), + p_spectrogram->colorMap()); + + p_plot->replot(); + } + + + /** + * Enables x,y tracking on the plot canvas. + * + */ + void ScatterPlotWindow::trackerEnabled(){ + if (p_zoomer->trackerMode() == QwtPicker::ActiveOnly) { + p_zoomer->setTrackerMode(QwtPicker::AlwaysOn); + } else { + p_zoomer->setTrackerMode(QwtPicker::ActiveOnly); + } + } + + + /** + * Sets the line edit boxes in the p_minMaxDialog to the current + * x/y min/max then shows the dialog box. + * + */ + void ScatterPlotWindow::setDisplayRange() { + p_yMaxEdit->setText(QString::number(p_MaxTwo)); + p_yMinEdit->setText(QString::number(p_MinTwo)); + p_xMaxEdit->setText(QString::number(p_MaxOne)); + p_xMinEdit->setText(QString::number(p_MinOne)); + p_minMaxDialog->show(); + } + + + /** + * This method sets the scale for the axis according to the + * user specified numbers. + */ + void ScatterPlotWindow::setUserValues() { + p_MinOne = p_xMinEdit->text().toDouble(); + p_MaxOne = p_xMaxEdit->text().toDouble(); + p_MinTwo = p_yMinEdit->text().toDouble(); + p_MaxTwo = p_yMaxEdit->text().toDouble(); + setScale(QwtPlot::xBottom, p_MinOne, p_MaxOne); + setScale(QwtPlot::yLeft, p_MinTwo, p_MaxTwo); + } + + + /** + * This method hides or displays the contour lines on the + * spectrogram. + * + */ + void ScatterPlotWindow::showContour(){ + if(p_colorize->text() == "Gray") { + p_spectrogram->setDefaultContourPen(QPen()); + } else { + p_spectrogram->setDefaultContourPen(QPen(QColor("white"))); + } + + p_spectrogram->setDisplayMode + (QwtPlotSpectrogram::ContourMode, + !p_spectrogram->testDisplayMode(QwtPlotSpectrogram::ContourMode)); + p_plot->replot(); + } + + +} + diff --git a/isis/src/qisis/objs/ScatterPlotWindow/ScatterPlotWindow.h b/isis/src/qisis/objs/ScatterPlotWindow/ScatterPlotWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..997f60d3b8353f3781147acd17ec3ab116010f39 --- /dev/null +++ b/isis/src/qisis/objs/ScatterPlotWindow/ScatterPlotWindow.h @@ -0,0 +1,127 @@ +#ifndef ScatterPlotWindow_h +#define ScatterPlotWindow_h + +// Only Parents of classes defined in this file should be included in this file! +#include "MainWindow.h" +#include + + +// FIXME: remove these includes +#include +#include + + +namespace Qisis { + + class MyZoomer: public QwtPlotZoomer { + public: + MyZoomer(QwtPlotCanvas *canvas):QwtPlotZoomer(canvas){ + setRubberBandPen(QPen(Qt::red)); + } + + virtual QwtText trackerText(const QwtDoublePoint &pos) const{ + QColor bg(Qt::white); + bg.setAlpha(160); + + QwtText text = QwtPlotZoomer::trackerText(pos); + text.setBackgroundBrush( QBrush( bg )); + return text; + } + +}; + + + /** + * @brief Scatter Plot Tool + * + * @author Stacy Alley + */ + class ScatterPlotTool; + + class ScatterPlotWindow : public Qisis::MainWindow{ + Q_OBJECT + + public: + ScatterPlotWindow (QString title, ScatterPlotTool *tool, QWidget *parent); + + protected slots: + void cancel(); + void colorPlot(); + void fillBands(); + void printPlot(); + void reLabel(); + void resetScale(); + void savePlot(); + void setDisplayRange(); + void setLabels(); + void setUserValues(); + void showConfig(); + void showScatterPlot(); + void trackerEnabled(); + void showContour(); + + private: + void createDialogs(); + void setupMenus(); + void setScale(int axisId, double minimum, double maximum, double stepSize = 0); + + ScatterPlotTool *p_tool; //!< Pointer to the scatter plot tool + MainWindow *p_scatterPlotWindow;//!< Plot Tool Window Widget + + QwtPlotSpectrogram *p_spectrogram;//!< Our spectrogram + QwtPlot *p_plot; //!< Our plot + QwtScaleWidget *p_rightAxis; //!< The color code axis + + QAction *p_colorize;//!< The action for switching the scatter plot from B/W to color. + QWidget *p_parent; //!< parent widget + + QDialog *p_configDialog; //! +#include +#include +#include +#include +#include + +#include +#include + +namespace Qisis { + + /** + * Constructor for the SocketThread + * + * + * @param parent + */ + SocketThread::SocketThread(QObject *parent): QThread(parent){ + } + + //! Destroys the SocketThread object + SocketThread::~SocketThread(){ + // wait(); + } + + //! Starts the socket thread + void SocketThread::run() { + std::string p_socketFile = "/tmp/isis_qview_" + Isis::Application::UserName(); + struct sockaddr_un p_socketName; + p_socketName.sun_family = AF_UNIX; + strcpy(p_socketName.sun_path,p_socketFile.c_str()); + int p_socket; + + // Create a socket + if ((p_socket = socket(PF_UNIX,SOCK_STREAM,0)) < 0) { + std::string msg = "Unable to create socket"; + std::cerr << msg << std::endl; + return; + } + + //const long unsigned int timeout = 1; + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100000; + if(setsockopt(p_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)) != 0) { + std::string msg = "Unable set socket timeout"; + std::cerr << msg << std::endl; + return; + } + + // Bind the file to the socket + int status = bind(p_socket,(struct sockaddr *)&p_socketName, sizeof(p_socketName)); + if (status < 0) { + std::string msg = "Unable to bind to socket [" + p_socketFile + "]"; + std::cerr << msg << std::endl; + return; + } + + // Set up to listen to the socket + if (listen(p_socket,5) < 0) { + std::string msg = "Unable to listen to socket [" + p_socketFile + "]"; + std::cerr << msg << std::endl; + return; + } + + p_done = false; + + while(!p_done) { + // Accept Socket + socklen_t len; + int childSocket = accept(p_socket, (struct sockaddr *)&p_socketName, &len); + if (childSocket < 0) { + continue; // probably timed out, we cant do anything about this anyways + } + + // Receive Data + int bytes; + char buf[1024*1024]; + if ((bytes = recv(childSocket,&buf,1024*1024,0)) < 0) { + std::string msg = "Unable to read from socket [" + p_socketFile + "]"; + std::cerr << msg << std::endl; + return; + } + + // Push everything onto our string buffer + Isis::iString buffer; + for (int i=0; i 0) { + Isis::iString token = buffer.Token(" "); + if (token == "raise") { + emit focusApp(); + } + else emit newImage(token.c_str()); + } + + }; + } +} diff --git a/isis/src/qisis/objs/SocketThread/SocketThread.h b/isis/src/qisis/objs/SocketThread/SocketThread.h new file mode 100644 index 0000000000000000000000000000000000000000..4757f7df4997558c2519b6a5bb4deea29fa8fd92 --- /dev/null +++ b/isis/src/qisis/objs/SocketThread/SocketThread.h @@ -0,0 +1,34 @@ +#ifndef Qisis_SocketThread_h +#define Qisis_SocketThread_h + +#include + +namespace Qisis { + class SocketThread : public QThread { + Q_OBJECT + + public: + SocketThread(QObject *parent = 0); + ~SocketThread(); + + void run(); + void stop() { p_done = true;}; + + signals: + /** + * New image signal. + * + * @param image + */ + void newImage(const QString &image); + //! Application has focus signal. + void focusApp(); + + private: + bool p_done; + }; +}; + +#endif + + diff --git a/isis/src/qisis/objs/SpecialPixelTool/Makefile b/isis/src/qisis/objs/SpecialPixelTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/SpecialPixelTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/SpecialPixelTool/SpecialPixelTool.cpp b/isis/src/qisis/objs/SpecialPixelTool/SpecialPixelTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..426b94f766e528c93b3bb2f83b48cf171da357ae --- /dev/null +++ b/isis/src/qisis/objs/SpecialPixelTool/SpecialPixelTool.cpp @@ -0,0 +1,549 @@ +#include "SpecialPixelTool.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Filename.h" +#include "MainWindow.h" +#include "MdiCubeViewport.h" +#include "Stretch.h" +#include "Workspace.h" + +namespace Qisis { + /** + * SpecialPixelTool constructor + * + * + * @param parent + */ + SpecialPixelTool::SpecialPixelTool (QWidget *parent) : Qisis::Tool(parent) { + // Create the SpecialPixel window + p_parent = parent; + + p_dialog = new QDialog(parent); + p_dialog->setWindowTitle("Special Pixel Tool"); + p_dialog->setSizeGripEnabled(true); + p_spWindow = new QWidget(p_dialog); + p_spWindow->setMinimumSize(492,492); + p_spWindow->installEventFilter(this); + + QWidget *buttons = new QWidget (p_dialog); + QWidget *colors = new QWidget (p_dialog); + QWidget *labels = new QWidget (p_dialog); + QWidget *defaults = new QWidget (p_dialog); + QWidget *main = new QWidget (p_dialog); + + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(defaults,0); + layout->addWidget(main,0); + layout->addWidget(buttons,0); + p_dialog->setLayout(layout); + + QPushButton *ok = new QPushButton("Ok",buttons); + ok->setShortcut(Qt::Key_Enter); + connect(ok,SIGNAL(released()),this,SLOT(apply())); + connect(ok,SIGNAL(released()),p_dialog,SLOT(hide())); + + QPushButton *apply = new QPushButton("Apply",buttons); + connect(apply,SIGNAL(released()),this,SLOT(apply())); + + QPushButton *cancel = new QPushButton("Cancel",buttons); + connect(cancel,SIGNAL(released()),p_dialog,SLOT(hide())); + + QPushButton *defaultBlackWhite = new QPushButton("Default B&W",defaults); + connect(defaultBlackWhite,SIGNAL(released()),this,SLOT(defaultBW())); + + QPushButton *defaultColor = new QPushButton("Default Color",defaults); + connect(defaultColor,SIGNAL(released()),this,SLOT(defaultColor())); + + QHBoxLayout *hlayout = new QHBoxLayout(); + hlayout->addWidget(ok); + hlayout->addWidget(apply); + hlayout->addWidget(cancel); + // hlayout->addStretch(1); + buttons->setLayout(hlayout); + + QHBoxLayout *h2layout = new QHBoxLayout(); + h2layout->addWidget(defaultBlackWhite); + h2layout->addWidget(defaultColor); + defaults->setLayout(h2layout); + + p_nullColor = new QToolButton(p_dialog); + connect(p_nullColor,SIGNAL(released()),this,SLOT(setNullColor())); + QSize *size = new QSize(25,25); + QLabel *nullLabel = new QLabel("Null"); + p_nullColor->setFixedSize(*size); + + p_lisColor = new QToolButton(p_dialog); + connect(p_lisColor,SIGNAL(released()),this,SLOT(setLisColor())); + QLabel *lisLabel = new QLabel("Low Instrument Saturation"); + p_lisColor->setFixedSize(*size); + + p_lrsColor = new QToolButton(p_dialog); + connect(p_lrsColor,SIGNAL(released()),this,SLOT(setLrsColor())); + QLabel *lrsLabel = new QLabel("Low Representation Saturation"); + p_lrsColor->setFixedSize(*size); + + p_ldsColor = new QToolButton(p_dialog); + connect(p_ldsColor,SIGNAL(released()),this,SLOT(setLdsColor())); + QLabel *ldsLabel = new QLabel("Low Display Saturation"); + p_ldsColor->setFixedSize(*size); + + p_hisColor = new QToolButton(p_dialog); + connect(p_hisColor,SIGNAL(released()),this,SLOT(setHisColor())); + QLabel *hisLabel = new QLabel("High Instrument Saturation"); + p_hisColor->setFixedSize(*size); + + p_hrsColor = new QToolButton(p_dialog); + connect(p_hrsColor,SIGNAL(released()),this,SLOT(setHrsColor())); + QLabel *hrsLabel = new QLabel("High Representation Saturation"); + p_hrsColor->setFixedSize(*size); + + p_hdsColor = new QToolButton(p_dialog); + connect(p_hdsColor,SIGNAL(released()),this,SLOT(setHdsColor())); + QLabel *hdsLabel = new QLabel("High Display Saturation"); + p_hdsColor->setFixedSize(*size); + + p_bgColor = new QToolButton(p_dialog); + connect(p_bgColor,SIGNAL(released()),this,SLOT(setBgColor())); + QLabel *bgLabel = new QLabel("Background"); + p_bgColor->setFixedSize(*size); + + connect(this,SIGNAL(setDefaultColors()),this,SLOT(defaultBW())); + emit setDefaultColors(); + + QVBoxLayout *vlayout = new QVBoxLayout(); + vlayout->addWidget(nullLabel); + vlayout->addWidget(lisLabel); + vlayout->addWidget(hisLabel); + vlayout->addWidget(lrsLabel); + vlayout->addWidget(hrsLabel); + vlayout->addWidget(ldsLabel); + vlayout->addWidget(hdsLabel); + vlayout->addWidget(bgLabel); + labels->setLayout(vlayout); + + QVBoxLayout *v2layout = new QVBoxLayout(); + v2layout->addWidget(p_nullColor); + v2layout->addWidget(p_lisColor); + v2layout->addWidget(p_hisColor); + v2layout->addWidget(p_lrsColor); + v2layout->addWidget(p_hrsColor); + v2layout->addWidget(p_ldsColor); + v2layout->addWidget(p_hdsColor); + v2layout->addWidget(p_bgColor); + colors->setLayout(v2layout); + + QHBoxLayout *mainlayout = new QHBoxLayout(); + mainlayout->addWidget(colors); + mainlayout->addWidget(labels); + main->setLayout(mainlayout); + + // Create the action to bring up the SpecialPixel window + p_action = new QAction(parent); + //p_action->setShortcut(Qt::CTRL+Qt::Key_C); + p_action->setText("&Special Pixel Tool ..."); + p_action->setIcon(QPixmap(toolIconDir()+"/colorize.png")); + p_action->setToolTip("SpecialPixelTool"); + QString text = + "Function: Opens a window that allows you to chose what color to \ + display each different type of special pixel \ +

    Shortcut: Ctrl+C

    "; + p_action->setWhatsThis(text); + p_action->setEnabled(false); + connect(p_action,SIGNAL(triggered()),p_dialog,SLOT(show())); + + readSettings(); + } + + + /** + * Adds the tool to the given menu. + * + * + * @param menu + */ + void SpecialPixelTool::addTo (QMenu *menu) { + menu->addAction(p_action); + } + + + /** + * Adds the tool to the permanent tool bar. + * + * + * @param perm + */ + void SpecialPixelTool::addToPermanent (QToolBar *perm) { + perm->addAction(p_action); + } + + + /** + * Applies the colors picked for the special pixels. + * + */ + void SpecialPixelTool::apply() { + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + MdiCubeViewport *cvp = (*(cubeViewportList()))[i]; + + // Get the Stretch objects from the cubeViewport + Isis::Stretch redStretch = cvp->redStretch(); + Isis::Stretch greenStretch = cvp->greenStretch(); + Isis::Stretch blueStretch = cvp->blueStretch(); + + // Apply selected null color + QPalette palette = p_nullColor->palette(); + QColor nullColor = palette.color(QPalette::Button); + int r,g,b; + nullColor.getRgb(&r,&g,&b); + redStretch.SetNull(r); + greenStretch.SetNull(g); + blueStretch.SetNull(b); + + // Apply selected lis + palette = p_lisColor->palette(); + QColor lisColor = palette.color(QPalette::Button); + lisColor.getRgb(&r,&g,&b); + redStretch.SetLis(r); + greenStretch.SetLis(g); + blueStretch.SetLis(b); + + // Apply selected lrs + palette = p_lrsColor->palette(); + QColor lrsColor = palette.color(QPalette::Button); + lrsColor.getRgb(&r,&g,&b); + redStretch.SetLrs(r); + greenStretch.SetLrs(g); + blueStretch.SetLrs(b); + + // Apply selected lds + palette = p_ldsColor->palette(); + QColor ldsColor = palette.color(QPalette::Button); + ldsColor.getRgb(&r,&g,&b); + redStretch.SetMinimum(r); + greenStretch.SetMinimum(g); + blueStretch.SetMinimum(b); + + // Apply selected his + palette = p_hisColor->palette(); + QColor hisColor = palette.color(QPalette::Button); + hisColor.getRgb(&r,&g,&b); + redStretch.SetHis(r); + greenStretch.SetHis(g); + blueStretch.SetHis(b); + + // Apply selected hrs + palette = p_hrsColor->palette(); + QColor hrsColor = palette.color(QPalette::Button); + hrsColor.getRgb(&r,&g,&b); + redStretch.SetHrs(r); + greenStretch.SetHrs(g); + blueStretch.SetHrs(b); + + // Apply selected hds + palette = p_hdsColor->palette(); + QColor hdsColor = palette.color(QPalette::Button); + hdsColor.getRgb(&r,&g,&b); + redStretch.SetMaximum(r); + greenStretch.SetMaximum(g); + blueStretch.SetMaximum(b); + + // Apply selected background + palette = p_bgColor->palette(); + QColor bgColor = palette.color(QPalette::Button); + bgColor.getRgb(&r,&g,&b); + + cvp->setBackground(bgColor); + cvp->stretchRed(redStretch); + cvp->stretchGreen(greenStretch); + cvp->stretchBlue(blueStretch); + + //If any of the defaults changed, make sure to write them + if(p_color) { + p_nullDefault = nullColor; + p_lisDefault = lisColor; + p_lrsDefault = lrsColor; + p_ldsDefault = ldsColor; + p_hisDefault = hisColor; + p_hrsDefault = hrsColor; + p_hdsDefault = hdsColor; + p_bgDefault = bgColor; + writeSettings(); + } + } + } + + + /** + * Sets the color for null pixels. + * + */ + void SpecialPixelTool::setNullColor() { + setColor(p_nullColor); + } + + + /** + * Sets the color for Lis pixels. + * + */ + void SpecialPixelTool::setLisColor() { + setColor(p_lisColor); + } + + + /** + * Sets the color for Lrs pixels. + * + */ + void SpecialPixelTool::setLrsColor() { + setColor(p_lrsColor); + } + + + /** + * Sets the color for Lds pixels. + * + */ + void SpecialPixelTool::setLdsColor() { + setColor(p_ldsColor); + } + + + /** + * Sets the color for His pixels. + * + */ + void SpecialPixelTool::setHisColor() { + setColor(p_hisColor); + } + + + /** + * Sets the color for Hrs pixels. + * + */ + void SpecialPixelTool::setHrsColor() { + setColor(p_hrsColor); + } + + + /** + * Sets the color for Hds pixels. + * + */ + void SpecialPixelTool::setHdsColor() { + setColor(p_hdsColor); + } + + void SpecialPixelTool::setBgColor() { + setColor(p_bgColor); + } + + /** + * Gets the selected color from the color dialog. + * + * + * @param button + */ + void SpecialPixelTool::setColor(QToolButton *button) { + // Let the user pick a color + QColor color = QColorDialog::getColor(); + + // Set the color if they didnt cancel out of the window + if (color.isValid()) { + QPalette *palette = new QPalette(); + palette->setColor(QPalette::Button,color); + button->setPalette(*palette); + } + + } + + + /** + * Reset the default black/white colors. + * + */ + void SpecialPixelTool::defaultBW() { + p_color = false; + QPalette *palette = new QPalette(); + palette->setColor(QPalette::Button,Qt::black); + p_nullColor->setPalette(*palette); + p_lisColor->setPalette(*palette); + p_lrsColor->setPalette(*palette); + p_ldsColor->setPalette(*palette); + p_bgColor->setPalette(*palette); + + palette->setColor(QPalette::Button,Qt::white); + p_hisColor->setPalette(*palette); + p_hrsColor->setPalette(*palette); + p_hdsColor->setPalette(*palette); + } + + + /** + * Reset the default color colors. + * + */ + void SpecialPixelTool::defaultColor() { + p_color = true; + QPalette *palette = new QPalette(); + palette->setColor(QPalette::Button,p_nullDefault); + p_nullColor->setPalette(*palette); + + palette->setColor(QPalette::Button,p_lisDefault); + p_lisColor->setPalette(*palette); + + palette->setColor(QPalette::Button,p_lrsDefault); + p_lrsColor->setPalette(*palette); + + palette->setColor(QPalette::Button,p_ldsDefault); + p_ldsColor->setPalette(*palette); + + palette->setColor(QPalette::Button,p_hisDefault); + p_hisColor->setPalette(*palette); + + palette->setColor(QPalette::Button,p_hrsDefault); + p_hrsColor->setPalette(*palette); + + palette->setColor(QPalette::Button,p_hdsDefault); + p_hdsColor->setPalette(*palette); + + palette->setColor(QPalette::Button,p_bgDefault); + p_bgColor->setPalette(*palette); + } + + + /** + * Updates special pixel tool. + * + */ + void SpecialPixelTool::updateTool() { + if (cubeViewport() == NULL) { + p_action->setEnabled(false); + } + else { + p_action->setEnabled(true); + } + } + + + /** + * This method reads in the default special pixel value colors + * from a config file. + * + */ + void SpecialPixelTool::readSettings(){ + /*Now read the settings that are specific to this window.*/ + std::string appName = p_parent->windowTitle().toStdString(); + + /*Now read the settings that are specific to this window.*/ + std::string instanceName = p_dialog->windowTitle().toStdString(); + + Isis::Filename config("$HOME/.Isis/" + appName + "/" + instanceName + ".config"); + p_settings = new QSettings(QString::fromStdString(config.Expanded()), QSettings::NativeFormat); + + //For each special pixel value, if it exists set it, otherwise set + //it to the system defaults. + + //Default value for Null + if(p_settings->value("defaultNull", 1).toInt() == 0) { + p_nullDefault = p_settings->value("defaultNull", 1).value(); + } + else { + p_nullDefault = Qt::blue; + } + + //Default value for Lis + if(p_settings->value("defaultLis", 1).toInt() == 0) { + p_lisDefault = p_settings->value("defaultLis", 1).value(); + } + else { + p_lisDefault = Qt::cyan; + } + + //Default value for Lrs + if(p_settings->value("defaultLrs", 1).toInt() == 0) { + p_lrsDefault = p_settings->value("defaultLrs", 1).value(); + } + else { + p_lrsDefault = Qt::yellow; + } + + //Default value for Lds + if(p_settings->value("defaultLds", 1).toInt() == 0) { + p_ldsDefault = p_settings->value("defaultLds", 1).value(); + } + else { + p_ldsDefault = Qt::black; + } + + //Default value for His + if(p_settings->value("defaultHis", 1).toInt() == 0) { + p_hisDefault = p_settings->value("defaultHis", 1).value(); + } + else { + p_hisDefault = Qt::magenta; + } + + //Default value for Hrs + if(p_settings->value("defaultHrs", 1).toInt() == 0) { + p_hrsDefault = p_settings->value("defaultHrs", 1).value(); + } + else { + p_hrsDefault = Qt::green; + } + + //Default value for Hds + if(p_settings->value("defaultHds", 1).toInt() == 0) { + p_hdsDefault = p_settings->value("defaultHds", 1).value(); + } + else { + p_hdsDefault = Qt::white; + } + + //Default value for Bg + if(p_settings->value("defaultBg", 1).toInt() == 0) { + p_bgDefault = p_settings->value("defaultBg", 1).value(); + } + else { + p_bgDefault = Qt::black; + } + } + + + /** + * This methods writes the default special pixel values to a + * config file that will be read by the readSettings() method. + * + */ + void SpecialPixelTool::writeSettings() { + std::string appName = p_parent->windowTitle().toStdString(); + + /*Now read the settings that are specific to this window.*/ + std::string instanceName = p_dialog->windowTitle().toStdString(); + + //Write all of the special pixel value colors + Isis::Filename config("$HOME/.Isis/" + appName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()), QSettings::NativeFormat); + settings.setValue("defaultNull", p_nullDefault); + settings.setValue("defaultLis", p_lisDefault); + settings.setValue("defaultLrs", p_lrsDefault); + settings.setValue("defaultLds", p_ldsDefault); + settings.setValue("defaultHis", p_hisDefault); + settings.setValue("defaultHrs", p_hrsDefault); + settings.setValue("defaultHds", p_hdsDefault); + settings.setValue("defaultBg", p_bgDefault); + } +} diff --git a/isis/src/qisis/objs/SpecialPixelTool/SpecialPixelTool.h b/isis/src/qisis/objs/SpecialPixelTool/SpecialPixelTool.h new file mode 100644 index 0000000000000000000000000000000000000000..b690f64bc6036baf6e660146b45c13a2d56df1dc --- /dev/null +++ b/isis/src/qisis/objs/SpecialPixelTool/SpecialPixelTool.h @@ -0,0 +1,96 @@ +#ifndef SpecialPixelTool_h +#define SpecialPixelTool_h + + +// This should be the only include in this file! +#include "Tool.h" + +// FIXME: remove this include +#include + + +class QDialog; +class QSettings; +class QToolButton; + +namespace Isis { + class Workspace; +} + +namespace Qisis { + /** + * @brief Sets the colors for the special pixel values + * + * @ingroup Visualization Tools + * + * @author Jeff Anderson - ??? + * + * @internal + * @history 2008-06-09 Noah Hilt - Added settings to read and + * write default colors for special pixel values. + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport instead of + * CubeViewport. Also fixed some include issues. + */ + class SpecialPixelTool : public Qisis::Tool { + Q_OBJECT + + public: + SpecialPixelTool (QWidget *parent); + void addTo (QMenu *menu); + void addToPermanent (QToolBar *perm); + + protected: + //! Returns the menu name. + QString menuName() const { return "&Options"; }; + void updateTool(); + void setColor(QToolButton *button); + void readSettings(); + void writeSettings(); + + signals: + //! Emitted when the default colors are reset. + void setDefaultColors(); + + private slots: + void apply(); + void setNullColor(); + void setLisColor(); + void setLrsColor(); + void setLdsColor(); + void setHisColor(); + void setHrsColor(); + void setHdsColor(); + void setBgColor(); + void defaultBW(); + void defaultColor(); + + private: + QAction *p_action; //!< Special Pixel Tool's action + QWidget *p_parent; //!< Parent widget + QWidget *p_spWindow;//!< Window widget + QDialog *p_dialog; //!< Dialog box + QColor p_nullDefault;//!< Color chosen for null pixels + QColor p_lisDefault; //!< Color chosen for low instrument saturation pixels + QColor p_lrsDefault; //!< Color chosen for Low representation saturation pixels + QColor p_ldsDefault; //!< Color chosen for pixels + QColor p_hisDefault; //!< Color chosen for high instrument saturation pixels + QColor p_hrsDefault; //!< Color chosen for high representation saturation pixels + QColor p_hdsDefault; //!< Color chosen for pixels + QColor p_bgDefault; //!< Color chosen for pixels + QToolButton *p_nullColor;//!< Null Button + QToolButton *p_lisColor; //!< Low instrument saturation Button + QToolButton *p_lrsColor; //!< Low representation saturation Button + QToolButton *p_ldsColor; //!< Low Button + QToolButton *p_hisColor; //!< High instrument saturation Button + QToolButton *p_hrsColor; //!< High representation saturation Button + QToolButton *p_hdsColor; //!< High Button + QToolButton *p_bgColor; //!< Background color Button + QSettings *p_settings; //!<< Settings + bool p_color; //!< Color Mode? + + + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/StatisticsTool/Makefile b/isis/src/qisis/objs/StatisticsTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/StatisticsTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/StatisticsTool/StatisticsTool.cpp b/isis/src/qisis/objs/StatisticsTool/StatisticsTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..981fd2fa3bf5c9ab45da416bd124719a9447623c --- /dev/null +++ b/isis/src/qisis/objs/StatisticsTool/StatisticsTool.cpp @@ -0,0 +1,732 @@ +#include "StatisticsTool.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Brick.h" +#include "MdiCubeViewport.h" +#include "ToolPad.h" + +namespace Qisis { + + /** + * Constructor, creates and sets up widgets for this tool. + * + * @param parent + */ + StatisticsTool::StatisticsTool (QWidget *parent) : Qisis::Tool(parent) { + p_boxSamps = 3; + p_boxLines = 3; + + p_ulSamp = -1; + p_ulLine = -1; + + p_set = false; + + p_dialog = new QDialog(parent); + p_dialog->setWindowTitle("Statistics"); + + p_visualBox = new QGroupBox("Visual Display"); + + p_visualDisplay = new VisualDisplay; + + QCheckBox *checkBox = new QCheckBox("Hide Display"); + connect(checkBox, SIGNAL(toggled(bool)), this, SLOT(hideDisplay(bool))); + + QLabel *boxLabel = new QLabel("Box Size:"); + p_boxLabel = new QLabel; + QString samps, lines; + samps.setNum(p_boxSamps); + lines.setNum(p_boxLines); + p_boxLabel->setText(samps + "x" + lines); + + QHBoxLayout *boxLabelLayout = new QHBoxLayout; + + boxLabelLayout->addWidget(checkBox); + boxLabelLayout->addStretch(1); + boxLabelLayout->addWidget(boxLabel); + boxLabelLayout->addWidget(p_boxLabel); + + QSlider *slider = new QSlider(Qt::Vertical); + slider->setRange(2, 18); + slider->setSliderPosition(10); + slider->setSingleStep(1); + slider->setTickInterval(1); + slider->setTickPosition(QSlider::TicksBelow); + connect(slider, SIGNAL(valueChanged(int)), p_visualDisplay, SLOT(setBoxSize(int))); + connect(slider, SIGNAL(valueChanged(int)), this, SLOT(resizeScrollbars())); + p_visualScroll = new QScrollArea; + p_visualScroll->setBackgroundRole(QPalette::Dark); + p_visualScroll->setWidget(p_visualDisplay); + + QGroupBox *displayMode = new QGroupBox("Display Mode"); + QRadioButton *displayText = new QRadioButton("Show Text"); + displayText->setToolTip("Display the pixels of a region as text"); + QRadioButton *displayPixels = new QRadioButton("Show Pixel Values"); + displayPixels->setToolTip("Display the pixels of a region"); + QRadioButton *displayDeviation = new QRadioButton("Show Deviation"); + displayDeviation->setToolTip("Display standard deviation over a region,\n where red denotes a larger deviation"); + + QHBoxLayout *displayModeLayout = new QHBoxLayout; + displayModeLayout->addWidget(displayText); + displayModeLayout->addWidget(displayPixels); + displayModeLayout->addWidget(displayDeviation); + + displayMode->setLayout(displayModeLayout); + + connect(displayText, SIGNAL(toggled(bool)), p_visualDisplay, SLOT(showText(bool))); + connect(displayText, SIGNAL(toggled(bool)), slider, SLOT(setDisabled(bool))); + connect(displayPixels, SIGNAL(toggled(bool)), p_visualDisplay, SLOT(showPixels(bool))); + connect(displayDeviation, SIGNAL(toggled(bool)), p_visualDisplay, SLOT(showDeviation(bool))); + + displayText->setChecked(true); + + QHBoxLayout *visualHBoxLayout = new QHBoxLayout; + visualHBoxLayout->addWidget(p_visualScroll); + visualHBoxLayout->addWidget(slider); + + QVBoxLayout *visualVBoxLayout = new QVBoxLayout; + visualVBoxLayout->addLayout(visualHBoxLayout); + visualVBoxLayout->addWidget(displayMode); + + p_visualBox->setLayout(visualVBoxLayout); + + QGroupBox *statsBox = new QGroupBox("Statistics"); + + p_minLabel = new QLabel("Minimum: n/a"); + p_minLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken); + p_minLabel->setLineWidth(1); + p_minLabel->setMargin(10); + p_minLabel->setAlignment(Qt::AlignLeft); + + p_maxLabel = new QLabel("Maximum: n/a"); + p_maxLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken); + p_maxLabel->setLineWidth(1); + p_maxLabel->setMargin(10); + p_maxLabel->setAlignment(Qt::AlignLeft); + + p_avgLabel = new QLabel("Average: n/a"); + p_avgLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken); + p_avgLabel->setLineWidth(1); + p_avgLabel->setMargin(10); + p_avgLabel->setAlignment(Qt::AlignLeft); + + p_stdevLabel = new QLabel("Standard Dev: n/a"); + p_stdevLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken); + p_stdevLabel->setLineWidth(1); + p_stdevLabel->setMargin(10); + p_stdevLabel->setAlignment(Qt::AlignLeft); + + p_dnLabel = new QLabel("DN: n/a"); + QFont labelFont = p_dnLabel->font(); + labelFont.setPointSize(8); + p_dnLabel->setFont(labelFont); + p_dnLabel->setAlignment(Qt::AlignRight); + connect(p_visualDisplay, SIGNAL(setDn(QString)), p_dnLabel, SLOT(setText(QString))); + + p_sampLabel = new QLabel("Sample: n/a"); + p_sampLabel->setFont(labelFont); + p_sampLabel->setAlignment(Qt::AlignLeft); + connect(p_visualDisplay, SIGNAL(setSample(QString)), p_sampLabel, SLOT(setText(QString))); + + p_lineLabel = new QLabel("Line: n/a"); + p_lineLabel->setFont(labelFont); + p_lineLabel->setAlignment(Qt::AlignCenter); + connect(p_visualDisplay, SIGNAL(setLine(QString)), p_lineLabel, SLOT(setText(QString))); + + QGridLayout *statsLayout = new QGridLayout; + statsLayout->addWidget(p_minLabel, 0, 0, 1, 2); + statsLayout->addWidget(p_maxLabel, 1, 0, 1, 2); + statsLayout->addWidget(p_avgLabel, 0, 2, 1, 2); + statsLayout->addWidget(p_stdevLabel, 1, 2, 1, 2); + statsLayout->addWidget(p_sampLabel, 2, 0); + statsLayout->addWidget(p_lineLabel, 2, 1, 1, 2); + statsLayout->addWidget(p_dnLabel, 2, 3); + + statsBox->setLayout(statsLayout); + + QVBoxLayout *dialogLayout = new QVBoxLayout; + dialogLayout->addLayout(boxLabelLayout); + dialogLayout->addWidget(p_visualBox); + dialogLayout->addWidget(statsBox); + + p_dialog->setLayout(dialogLayout); + + checkBox->setChecked(true); + } + + /** + * Attaches this tool to the toolpad + * + * @param toolpad + * + * @return QAction* + */ + QAction *StatisticsTool::toolPadAction(ToolPad *toolpad) { + QAction *action = new QAction(toolpad); + action->setIcon(QPixmap(toolIconDir()+"/statistics.png")); + action->setToolTip("Statistics"); + QObject::connect(action,SIGNAL(activated()),p_dialog,SLOT(show())); + + QString text = ""; + + action->setWhatsThis(text); + return action; + } + + /** + * Attaches this tool to the toolbar + * + * @param parent + * + * @return QWidget* + */ + QWidget *StatisticsTool::createToolBarWidget (QStackedWidget *parent) { + QWidget *hbox = new QWidget(parent); + + QIntValidator *ival = new QIntValidator(hbox); + ival->setRange(1, 100); + + QLabel *sampleLabel = new QLabel("Box Samples:"); + p_sampsEdit = new QLineEdit(hbox); + p_sampsEdit->setValidator(ival); + p_sampsEdit->setMaximumWidth(50); + + QString samps; + samps.setNum(p_boxSamps); + + p_sampsEdit->setText(samps); + connect(p_sampsEdit,SIGNAL(editingFinished()),this,SLOT(changeBoxSamples())); + + QLabel *lineLabel = new QLabel("Box Lines:"); + p_linesEdit = new QLineEdit(hbox); + p_linesEdit->setValidator(ival); + p_linesEdit->setMaximumWidth(50); + + QString lines; + lines.setNum(p_boxLines); + + p_linesEdit->setText(lines); + connect(p_linesEdit,SIGNAL(editingFinished()),this,SLOT(changeBoxLines())); + + QToolButton *showButton = new QToolButton(); + showButton->setText("Show"); + showButton->setToolTip(""); + QString text = ""; + showButton->setWhatsThis(text); + + connect(showButton,SIGNAL(clicked()),p_dialog,SLOT(show())); + + QHBoxLayout *layout = new QHBoxLayout; + layout->setMargin(0); + layout->addWidget(sampleLabel); + layout->addWidget(p_sampsEdit); + layout->addWidget(lineLabel); + layout->addWidget(p_linesEdit); + layout->addWidget(showButton); + layout->addStretch(1); + hbox->setLayout(layout); + return hbox; + } + + /** + * Called when a mouse button is released + * + * @param p + * @param s + */ + void StatisticsTool::mouseButtonRelease(QPoint p, Qt::MouseButton s) { + if(s == Qt::LeftButton) { + getStatistics(p); + } + } + + /** + * Hide/Show the visual display + * + * @param hide + */ + void StatisticsTool::hideDisplay(bool hide) { + if(hide) { + p_visualBox->hide(); + p_sampLabel->hide(); + p_lineLabel->hide(); + p_dnLabel->hide(); + + p_dialog->setMinimumSize(350, 165); + p_dialog->resize(350, 165); + } + else { + p_visualBox->show(); + p_sampLabel->show(); + p_lineLabel->show(); + p_dnLabel->show(); + + p_dialog->setMinimumSize(565, 765); + p_dialog->resize(565, 765); + } + } + + /** + * Retrieve the statistics based on the box size + * and point on the cube. + * + * @param p + */ + void StatisticsTool::getStatistics(QPoint p) { + MdiCubeViewport *cvp = cubeViewport(); + if(cvp == NULL) return; + + double sample,line; + cvp->viewportToCube(p.x(),p.y(),sample,line); + + // If we are outside of the cube, do nothing + if ((sample < 0.5) || (line < 0.5) || + (sample > cvp->cubeSamples()+0.5) || (line > cvp->cubeLines()+0.5)) { + return; + } + + int isamp = (int)(sample + 0.5); + int iline = (int)(line + 0.5); + + Isis::Statistics stats; + Isis::Brick *brick = new Isis::Brick(1,1,1,cvp->cube()->PixelType()); + + + QVector > pixelData(p_boxLines, QVector(p_boxSamps, 0)); + + double lineDiff = p_boxLines/2.0; + double sampDiff = p_boxSamps/2.0; + + p_ulSamp = isamp - (int)floor(sampDiff); + p_ulLine = iline - (int)floor(lineDiff); + + int x, y; + + y = p_ulLine; + + for(int i = 0; i < p_boxLines; i++) { + x = p_ulSamp; + if(y < 1 || y > cvp->cubeLines()) { + y++; + continue; + } + for(int j = 0; j < p_boxSamps; j++) { + if(x < 1 || x > cvp->cubeSamples()) { + x++; + continue; + } + brick->SetBasePosition(x, y, cvp->grayBand()); + cvp->cube()->Read(*brick); + stats.AddData(brick->at(0)); + pixelData[i][j] = brick->at(0); + + x++; + } + y++; + } + + p_visualDisplay->setPixelData(pixelData, p_ulSamp, p_ulLine); + + p_minLabel->setText(QString("Minimum: %1").arg(stats.Minimum())); + p_maxLabel->setText(QString("Maximum: %1").arg(stats.Maximum())); + p_avgLabel->setText(QString("Average: %1").arg(stats.Average())); + p_stdevLabel->setText(QString("Standard Dev: %1").arg(stats.StandardDeviation(), 0, 'f', 6)); + + p_set = true; + + resizeScrollbars(); + } + + /** + * Change the box sample size. + * + */ + void StatisticsTool::changeBoxSamples() { + QString samps = p_sampsEdit->text(); + if(samps != "" && samps.toInt() != p_boxSamps && samps.toInt() > 0) { + p_boxSamps = samps.toInt(); + QString lines; + lines.setNum(p_boxLines); + p_boxLabel->setText(samps + "x" + lines); + + p_visualDisplay->setSamples(p_boxSamps); + + p_set = false; + + resizeScrollbars(); + } + } + + /** + * Change the box line size. + * + */ + void StatisticsTool::changeBoxLines() { + QString lines = p_linesEdit->text(); + if(lines != "" && lines.toInt() != p_boxLines && lines.toInt() > 0) { + p_boxLines = lines.toInt(); + QString samps; + samps.setNum(p_boxSamps); + p_boxLabel->setText(samps + "x" + lines); + + p_visualDisplay->setLines(p_boxLines); + + p_set = false; + + resizeScrollbars(); + } + } + + /** + * Resize the scroll bars and center the point clicked. + * + */ + void StatisticsTool::resizeScrollbars() { + QScrollBar *hbar = p_visualScroll->horizontalScrollBar(); + QScrollBar *vbar = p_visualScroll->verticalScrollBar(); + hbar->setSliderPosition((hbar->maximum() + hbar->minimum()) / 2); + vbar->setSliderPosition((vbar->maximum() + vbar->minimum()) / 2); + } + + /** + * Constructor for visual display. + * + * @param parent + */ + VisualDisplay::VisualDisplay(QWidget *parent) : QWidget(parent), + p_boxSamps(3), + p_boxLines(3), + p_boxWidth(20), + p_boxHeight(20), + p_oldWidth(20), + p_oldHeight(20), + p_ulSamp(-1), + p_ulLine(-1), + p_set(false), + p_showText(true), + p_showPixels(false), + p_showDeviation(false) { + + p_stretch.SetNull(0.0); + p_stretch.SetLis(0.0); + p_stretch.SetLrs(0.0); + p_stretch.SetHis(255.0); + p_stretch.SetHrs(255.0); + p_stretch.SetMinimum(0.0); + p_stretch.SetMaximum(255.0); + p_pixelData = QVector >(p_boxLines, QVector(p_boxSamps, 0)); + paintPixmap(); + setMouseTracking(true); + setBackgroundRole(QPalette::Dark); + setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + } + + /** + * Size hint for this widget + * + * + * @return QSize + */ + QSize VisualDisplay::sizeHint() const { + return QSize(460, 460); + } + + /** + * Set box sample size + * + * @param samps + */ + void VisualDisplay::setSamples(int samps) { + p_boxSamps = samps; + p_pixelData = QVector >(p_boxLines, QVector(p_boxSamps, 0)); + p_stats.Reset(); + + p_set = false; + updateSize(); + } + + /** + * Set box line size + * + * @param lines + */ + void VisualDisplay::setLines(int lines) { + p_boxLines = lines; + p_pixelData = QVector >(p_boxLines, QVector(p_boxSamps, 0)); + p_stats.Reset(); + + p_set = false; + updateSize(); + } + + /** + * Set box size in pixels + * + * @param size + */ + void VisualDisplay::setBoxSize(int size) { + p_boxWidth = 2 * size; + p_boxHeight = 2 * size; + p_oldWidth = p_boxWidth; + p_oldHeight = p_boxHeight; + updateSize(); + } + + /** + * Update the size of the box + * + */ + void VisualDisplay::updateSize() { + if(p_boxSamps > this->sizeHint().width() / p_boxWidth) { + resize(this->sizeHint().width() + (p_boxWidth * (p_boxSamps - this->sizeHint().width() / p_boxWidth)), this->size().height()); + } + else { + resize(this->sizeHint().width(), this->size().height()); + } + + if(p_boxLines > this->sizeHint().height() / p_boxHeight) { + resize(this->size().width(), this->sizeHint().height() + (p_boxHeight * (p_boxLines - this->sizeHint().height() / p_boxHeight))); + } + else { + resize(this->size().width(), this->sizeHint().height()); + } + + paintPixmap(); + update(); + } + + /** + * Show/Hide text + * + * @param b + */ + void VisualDisplay::showText(bool b) { + p_showText = b; + if(b) { + p_oldWidth = p_boxWidth; + p_oldHeight = p_boxHeight; + p_boxWidth = 100; + p_boxHeight = 20; + updateSize(); + } + } + + + /** + * Show/Hide pixels + * + * @param b + */ + void VisualDisplay::showPixels(bool b) { + p_showPixels = b; + if(b) { + if(p_boxWidth != p_oldWidth || p_boxHeight != p_oldHeight) { + p_boxWidth = p_oldWidth; + p_boxHeight = p_oldHeight; + } + updateSize(); + } + } + + /** + * Show/Hide deviation + * + * @param b + */ + void VisualDisplay::showDeviation(bool b) { + p_showDeviation = b; + if(b) { + if(p_boxWidth != p_oldWidth || p_boxHeight != p_oldHeight) { + p_boxWidth = p_oldWidth; + p_boxHeight = p_oldHeight; + } + updateSize(); + } + } + + /** + * Set pixel data and upper left sample/line + * + * @param data + * @param samp + * @param line + */ + void VisualDisplay::setPixelData(QVector > data, int samp, int line) { + p_pixelData = data; + p_ulSamp = samp; + p_ulLine = line; + + p_stats.Reset(); + + for (int i=0; i < data.size(); i++) { + for(int j=0; j < data[i].size(); j++) { + if(p_ulSamp + j < 0 || p_ulLine + i < 0) continue; + p_stats.AddData(data[i][j]); + } + } + + if(fabs(p_stats.BestMinimum()) < DBL_MAX && fabs(p_stats.BestMaximum()) < DBL_MAX) { + Isis::Histogram hist(p_stats.BestMinimum(),p_stats.BestMaximum()); + for (int i=0; i < data.size(); i++) { + hist.AddData(data[i].data(), data[i].size()); + } + + p_stretch.ClearPairs(); + if (hist.Percent(0.5) != hist.Percent(99.5)) { + p_stretch.AddPair(hist.Percent(0.5),0.0); + p_stretch.AddPair(hist.Percent(99.5),255.0); + } + else { + p_stretch.AddPair(-DBL_MAX,0.0); + p_stretch.AddPair(DBL_MAX,255.0); + } + } + else { + p_stretch.ClearPairs(); + p_stretch.AddPair(-DBL_MAX,0.0); + p_stretch.AddPair(DBL_MAX,255.0); + } + + p_set = true; + paintPixmap(); + } + + /** + * Paint the pixmap + * + */ + void VisualDisplay::paintPixmap() { + p_pixmap = QPixmap(p_boxSamps * p_boxWidth, p_boxLines * p_boxHeight); + p_pixmap.fill(); + QPainter p(&p_pixmap); + QRect rect(0, 0, p_boxWidth, p_boxHeight); + + int midX = p_pixmap.width()/2 - ((p_boxWidth/2) * (p_boxSamps % 2)); + int midY = p_pixmap.height()/2 - ((p_boxHeight/2) * (p_boxLines % 2)); + + int x, y; + y = 0; + + for(int i = 0; i < p_boxLines; i++) { + x = 0; + for(int j = 0; j < p_boxSamps; j++) { + double dn = p_pixelData[i][j]; + QColor c; + if(p_showPixels || p_showDeviation) { + if(p_showDeviation) { + if(!Isis::IsSpecial(dn) && p_stats.TotalPixels() > 0 && p_stats.StandardDeviation() != 0) { + double diff; + + if(dn < p_stats.Average()) { + diff = p_stats.Average() - dn; + diff /= p_stats.Average() - p_stats.Minimum(); + } + else { + diff = dn - p_stats.Average(); + diff /= p_stats.Maximum() - p_stats.Average(); + } + + int i = (int)(diff * 255.0); + c = QColor(i, 255 - i, 0); + } + else { + c = QColor(0, 0, 0); + } + } + else { + c = QColor((int)p_stretch.Map(dn), (int)p_stretch.Map(dn), (int)p_stretch.Map(dn)); + } + } + p.save(); + p.translate(x, y); + + if(p_showText) { + p.drawRect(rect); + p.drawText(rect, Qt::AlignCenter, QString("%1").arg(dn)); + } + else { + p.fillRect(rect, c); + } + + p.restore(); + x += p_boxWidth; + } + y += p_boxHeight; + } + + p.setPen(QPen(Qt::red, 1)); + p.save(); + p.translate(midX, midY); + p.drawRect(rect); + p.restore(); + update(); + } + + /** + * Paint pixmap to the widget + * + * @param event + */ + void VisualDisplay::paintEvent(QPaintEvent *event) { + + QPainter painter(this); + + int midX = width()/2 - (p_boxWidth * (int)floor(p_boxSamps/2) + (p_boxWidth/2)); + int midY = height()/2 - (p_boxHeight * (int)floor(p_boxLines/2) + (p_boxHeight/2)); + + painter.drawPixmap(midX, midY, p_pixmap); + } + + /** + * Called when the mouse moves over this widget + * + * @param event + */ + void VisualDisplay::mouseMoveEvent(QMouseEvent *event) { + double startX = width()/2 - (p_boxWidth * (int)floor(p_boxSamps/2) + (p_boxWidth/2)); + double startY = height()/2 - (p_boxHeight * (int)floor(p_boxLines/2) + (p_boxHeight/2)); + + int x = (int)ceil((event->x() - startX) / p_boxWidth); + int y = (int)ceil((event->y() - startY) / p_boxHeight); + + if(!p_set || x < 1 || y < 1 || x > p_boxSamps || y > p_boxLines) { + emit setSample("Sample: n/a"); + emit setLine("Line: n/a"); + emit setDn("DN: n/a"); + } + else { + emit setSample(QString("Sample: %1").arg(p_ulSamp + x-1)); + emit setLine(QString("Line: %1").arg(p_ulLine + y-1)); + double dn = p_pixelData[y-1][x-1]; + if(Isis::IsSpecial(dn)) + emit setDn(QString("DN: %1").arg(Isis::PixelToString(dn).c_str())); + else + emit setDn(QString("DN: %1").arg(dn)); + } + } + + /** + * Mouse left widget, update labels + * + * @param event + */ + void VisualDisplay::leaveEvent(QEvent *event) { + emit setSample("Sample: n/a"); + emit setLine("Line: n/a"); + emit setDn("DN: n/a"); + } +} diff --git a/isis/src/qisis/objs/StatisticsTool/StatisticsTool.h b/isis/src/qisis/objs/StatisticsTool/StatisticsTool.h new file mode 100644 index 0000000000000000000000000000000000000000..0c45989e10b074638e1e94bc8bece66202b105eb --- /dev/null +++ b/isis/src/qisis/objs/StatisticsTool/StatisticsTool.h @@ -0,0 +1,174 @@ +#ifndef StatisticsTool_h +#define StatisticsTool_h + +/** + * @file + * $Date: 2010/06/28 09:21:33 $ $Revision: 1.3 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +// Only includes for Parents of classes defined in this file are allowed here! +#include "Tool.h" +#include + + +// FIXME: remove these includes +#include "Stretch.h" +#include + +class QScrollArea; +class QLabel; +class QLineEdit; +class QCheckBox; +class QGroupBox; + +namespace Qisis { + /** + * @brief Tool to visualize statistics in an n * m box. + * + * This tool is used to visualize statistics in an n * m box specified + * by the user. It allows for textual and visual representation of the + * DN values in the region as well as the standard deviation over the box. + * + * @ingroup Visualization Tools + * + * @author Noah Hilt + * + * @internal + + * @history 2009-10-07 Noah Hilt - Original version. + * + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport + */ + class VisualDisplay : public QWidget { + Q_OBJECT + + public: + VisualDisplay(QWidget *parent = 0); + + QSize sizeHint() const; + + void setSamples(int samps); + void setLines(int lines); + + void updateSize(); + + void setPixelData(QVector > data, int samp, int line); + + protected: + void paintPixmap(); + void paintEvent(QPaintEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void leaveEvent(QEvent *event); + + signals: + /** + * Signal to set the DN label to st. + * + * @param st + */ + void setDn(const QString st); + /** + * Signal to set the Sample label to st. + * + * @param st + */ + void setSample(const QString st); + /** + * Signal to set the Line label to st. + * + * @param st + */ + void setLine(const QString st); + + protected slots: + void setBoxSize(int size); + void showText(bool b); + void showPixels(bool b); + void showDeviation(bool b); + + private: + int p_boxSamps; //!< Sample size for box + int p_boxLines; //!< Line size for box + int p_boxWidth; //!< Box width in pixels + int p_boxHeight; //!< Box height in pixels + int p_oldWidth; //!< Previous box width in pixels + int p_oldHeight; //!< Previous box height in pixels + int p_ulSamp; //!< Upper left sample of region captured + int p_ulLine; //!< Upper left line of region captured + bool p_set; //!< Boolean to see if data is set + bool p_showText; //!< Display text? + bool p_showPixels; //!< Display pixels? + bool p_showDeviation; //!< Display deviation? + + QPixmap p_pixmap; //!< Pixmap used for drawing + Isis::Stretch p_stretch; //!< Stretch used to display pixels + Isis::Statistics p_stats; //!< Stats used for calculating stretch and deviation + QVector > p_pixelData; //!< Stored pixel values + }; + + class StatisticsTool : public Tool { + Q_OBJECT + + public: + StatisticsTool (QWidget *parent); + + protected: + QAction *toolPadAction(ToolPad *toolpad); + QWidget *createToolBarWidget(QStackedWidget *parent); + + protected slots: + void mouseButtonRelease(QPoint p, Qt::MouseButton s); + void hideDisplay(bool hide); + void resizeScrollbars(); + + private: + void getStatistics(QPoint p); + + QAction *p_action; //!< Action associated with this tool + QDialog *p_dialog; //!< Dialog to show pixel data and statistics + QScrollArea *p_visualScroll; //!< Scroll area to house visual display + QGroupBox *p_visualBox; //!< Visual group box to hold visual display + VisualDisplay *p_visualDisplay; //!< Visual display + QLabel *p_boxLabel; //!< Box label + QLabel *p_minLabel; //!< Minimum label + QLabel *p_maxLabel; //!< Maximum label + QLabel *p_avgLabel; //!< Average label + QLabel *p_stdevLabel; //!< Std Dev label + QLabel *p_sampLabel; //!< Sample label + QLabel *p_lineLabel; //!< Line label + QLabel *p_dnLabel; //!< DN label + QLineEdit *p_sampsEdit; //!< Sample size line edit + QLineEdit *p_linesEdit; //!< Line size line edit + + int p_boxSamps; //!< Sample size for box + int p_boxLines; //!< Line size for box + + int p_ulSamp; //!< Upper left sample of region + int p_ulLine; //!< Upper left line of region + + bool p_set; //!< Boolean to see if data is set + + private slots: + void changeBoxSamples(); + void changeBoxLines(); + }; +}; + +#endif diff --git a/isis/src/qisis/objs/StretchTool/AdvancedStretch.cpp b/isis/src/qisis/objs/StretchTool/AdvancedStretch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..33dcd52ec1595c9b0c0b5469f1cdae4f1c7d510c --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/AdvancedStretch.cpp @@ -0,0 +1,123 @@ +#include "AdvancedStretch.h" + +#include +#include +#include +#include +#include + +#include "Stretch.h" +#include "iString.h" +#include "iException.h" +#include "StretchType.h" +#include "LinearStretchType.h" +#include "SawtoothStretchType.h" +#include "BinaryStretchType.h" +#include "ManualStretchType.h" + +using namespace Isis; + +namespace Qisis { + /** + * This constructs an advanced stretch. + * + * @param hist Current histogram of visible area + * @param curStretch Current stretch + * @param name Graph name + * @param color Graph color + */ + AdvancedStretch::AdvancedStretch(Isis::Histogram &hist, + const Isis::Stretch &curStretch, + const QString &name, const QColor &color) { + setLayout(new QVBoxLayout()); + + QWidget *typeSelectionArea = new QWidget(); + typeSelectionArea->setLayout(new QHBoxLayout()); + typeSelectionArea->layout()->addWidget(new QLabel("Stretch Type")); + + QComboBox *stretchTypeSelection = new QComboBox(); + stretchTypeSelection->addItem("Linear", 0); + stretchTypeSelection->addItem("Sawtooth", 1); + stretchTypeSelection->addItem("Binary", 2); + stretchTypeSelection->addItem("Manual", 3); + + typeSelectionArea->layout()->addWidget(stretchTypeSelection); + layout()->addWidget(typeSelectionArea); + + p_stretchTypeStack = new QStackedWidget(); + LinearStretchType *linear = new LinearStretchType(hist, curStretch, + name, color); + connect(linear, SIGNAL(stretchChanged()), this, SIGNAL(stretchChanged())); + p_stretchTypeStack->addWidget(linear); + + SawtoothStretchType *sawtooth = new SawtoothStretchType(hist, curStretch, + name, color); + connect(sawtooth, SIGNAL(stretchChanged()), this, SIGNAL(stretchChanged())); + p_stretchTypeStack->addWidget(sawtooth); + + BinaryStretchType *binary = new BinaryStretchType(hist, curStretch, + name, color); + connect(binary, SIGNAL(stretchChanged()), this, SIGNAL(stretchChanged())); + p_stretchTypeStack->addWidget(binary); + + ManualStretchType *manual = new ManualStretchType(hist, curStretch, + name, color); + connect(manual, SIGNAL(stretchChanged()), this, SIGNAL(stretchChanged())); + p_stretchTypeStack->addWidget(manual); + + layout()->addWidget(p_stretchTypeStack); + connect(stretchTypeSelection, SIGNAL(currentIndexChanged(int)), + p_stretchTypeStack, SLOT(setCurrentIndex(int))); + connect(stretchTypeSelection, SIGNAL(currentIndexChanged(int)), + this, SIGNAL(stretchChanged())); + } + + + /** + * Destructor + */ + AdvancedStretch::~AdvancedStretch() { + } + + + /** + * This returns the current stretch type's stretch. + * + * @return Isis::Stretch + */ + Isis::Stretch AdvancedStretch::getStretch() { + return ((StretchType *)p_stretchTypeStack->currentWidget())->getStretch(); + } + + + /** + * This is called when the user creates a stretch outside of the + * advanced stretch. For example, they do a global stretch. The + * advanced stretch will be given this stretch and a chance to + * re-interpret it. + * + * @param newStretch + */ + void AdvancedStretch::setStretch(Isis::Stretch newStretch) { + StretchType *stretchType = (StretchType *) + p_stretchTypeStack->currentWidget(); + stretchType->setStretch(newStretch); + } + + + /** + * This is called when the visible area changes, so that the + * histogram can be updated. It is essential that the stretch + * doesn't really change in this, or zooming will affect the + * stretch. + * + * @param newHist + */ + void AdvancedStretch::setHistogram(const Isis::Histogram &newHist) { + for(int stretch = 0; stretch < p_stretchTypeStack->count(); stretch ++) { + StretchType *stretchType = (StretchType *) + p_stretchTypeStack->widget(stretch); + stretchType->setHistogram(newHist); + } + } +}; diff --git a/isis/src/qisis/objs/StretchTool/AdvancedStretch.h b/isis/src/qisis/objs/StretchTool/AdvancedStretch.h new file mode 100644 index 0000000000000000000000000000000000000000..3a72af30e98141c6a23254cca42209cd0d0556ac --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/AdvancedStretch.h @@ -0,0 +1,57 @@ +#ifndef ADVANCEDSTRETCH_H +#define ADVANCEDSTRETCH_H + +#include + +class QStackedWidget; +class QLayout; +class QString; +class QColor; + +namespace Isis { + class Stretch; + class Histogram; +}; + +namespace Qisis { + class AdvancedStretch; + class CubeViewport; + + /** + * @brief Advanced Stretch Dialog + * + * This class is one of the panes on the advanced stretch dialog + * (gray, red, green or blue). This contains advanced stretch + * types of each kind and a selection between them. + * + * @ingroup Visualization Tools + * + * @author 2010-05-20 Steven Lambright + * + */ + + class AdvancedStretch : public QWidget { + Q_OBJECT + + public: + AdvancedStretch(Isis::Histogram &, const Isis::Stretch &, + const QString &, const QColor &); + ~AdvancedStretch(); + Isis::Stretch getStretch(); + void setStretch(Isis::Stretch newStretch); + void setHistogram(const Isis::Histogram &newHist); + + signals: + //! Emitted when a new stretch is available + void stretchChanged(); + + protected: + + private: + QStackedWidget *p_stretchTypeStack; //!< StretchType's + }; +}; + + +#endif + diff --git a/isis/src/qisis/objs/StretchTool/AdvancedStretchDialog.cpp b/isis/src/qisis/objs/StretchTool/AdvancedStretchDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7006edb3b726b1f6d0f16f711267e94e01e9fa9b --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/AdvancedStretchDialog.cpp @@ -0,0 +1,278 @@ +#include "AdvancedStretchDialog.h" + +#include + +#include "CubeViewport.h" +#include "Stretch.h" +#include "AdvancedStretch.h" + +using namespace Isis; + +namespace Qisis { + /** + * This constructs an advanced stretch. + * + * @param parent the parent widget + */ + AdvancedStretchDialog::AdvancedStretchDialog(QWidget *parent) : + QDialog(parent) { + p_grayStretch = NULL; + p_redStretch = NULL; + p_grnStretch = NULL; + p_bluStretch = NULL; + p_enabled = false; + + QHBoxLayout *layout = new QHBoxLayout(); + setLayout(layout); + } + + + /** + * This destroys the advanced stretch dialog + */ + AdvancedStretchDialog::~AdvancedStretchDialog() { + destroyCurrentStretches(); + } + + + /** + * This displays RGB advanced stretches. + * + * @param redStretch + * @param redHist + * @param grnStretch + * @param grnHist + * @param bluStretch + * @param bluHist + */ + void AdvancedStretchDialog::enableRgbMode(Isis::Stretch &redStretch, + Isis::Histogram &redHist, + Isis::Stretch &grnStretch, Isis::Histogram &grnHist, + Isis::Stretch &bluStretch, Isis::Histogram &bluHist) { + destroyCurrentStretches(); + + p_redStretch = new AdvancedStretch(redHist, redStretch, + "Red", QColor(Qt::red)); + layout()->addWidget(p_redStretch); + + p_grnStretch = new AdvancedStretch(grnHist, grnStretch, + "Green", QColor(Qt::green)); + layout()->addWidget(p_grnStretch); + + p_bluStretch = new AdvancedStretch(bluHist, bluStretch, + "Blue", QColor(Qt::blue)); + layout()->addWidget(p_bluStretch); + + connect(p_redStretch, SIGNAL(stretchChanged()), + this, SIGNAL(stretchChanged())); + connect(p_grnStretch, SIGNAL(stretchChanged()), + this, SIGNAL(stretchChanged())); + connect(p_bluStretch, SIGNAL(stretchChanged()), + this, SIGNAL(stretchChanged())); + } + + + /** + * This displays a gray advanced stretch. + * + * @param grayStretch + * @param grayHist + */ + void AdvancedStretchDialog::enableGrayMode(Isis::Stretch &grayStretch, + Isis::Histogram &grayHist) { + destroyCurrentStretches(); + + p_grayStretch = new AdvancedStretch(grayHist, grayStretch, + "Gray", QColor(Qt::gray)); + layout()->addWidget(p_grayStretch); + + connect(p_grayStretch, SIGNAL(stretchChanged()), + this, SIGNAL(stretchChanged())); + } + + + /** + * This cleans up memory from currently displayed advanced + * stretches. No stretches are visible after this is called. + */ + void AdvancedStretchDialog::destroyCurrentStretches() { + if(p_redStretch) { + layout()->removeWidget(p_redStretch); + disconnect(p_redStretch, SIGNAL(stretchChanged()), + this, SIGNAL(stretchChanged())); + delete p_redStretch; + p_redStretch = NULL; + } + + if(p_grnStretch) { + layout()->removeWidget(p_grnStretch); + disconnect(p_grnStretch, SIGNAL(stretchChanged()), + this, SIGNAL(stretchChanged())); + delete p_grnStretch; + p_grnStretch = NULL; + } + + if(p_bluStretch) { + layout()->removeWidget(p_bluStretch); + disconnect(p_bluStretch, SIGNAL(stretchChanged()), + this, SIGNAL(stretchChanged())); + delete p_bluStretch; + p_bluStretch = NULL; + } + + if(p_grayStretch) { + layout()->removeWidget(p_grayStretch); + disconnect(p_grayStretch, SIGNAL(stretchChanged()), + this, SIGNAL(stretchChanged())); + delete p_grayStretch; + p_grayStretch = NULL; + } + } + + + /** + * This calls setStretch on all applicable advanced stretches. + * This should be called any time the cube viewport changes. + * + * @param cvp + */ + void AdvancedStretchDialog::updateStretch(CubeViewport *cvp) { + if(p_grayStretch) + p_grayStretch->setStretch(cvp->grayStretch()); + if(p_redStretch) + p_redStretch->setStretch(cvp->redStretch()); + if(p_grnStretch) + p_grnStretch->setStretch(cvp->greenStretch()); + if(p_bluStretch) + p_bluStretch->setStretch(cvp->blueStretch()); + } + + + /** + * This calls setHistogram on all of the advanced stretches. + * This should be called every time the visible area changes. + * + * @param redHist Histogram of visible area on red band + * @param grnHist Histogram of visible area on green band + * @param bluHist Histogram of visible area on blue band + */ + void AdvancedStretchDialog::updateHistograms(const Isis::Histogram &redHist, + const Isis::Histogram &grnHist, + const Isis::Histogram &bluHist) { + if(p_redStretch) + p_redStretch->setHistogram(redHist); + if(p_grnStretch) + p_grnStretch->setHistogram(grnHist); + if(p_bluStretch) + p_bluStretch->setHistogram(bluHist); + } + + + /** + * This calls setHistogram on the gray advanced stretche. This + * should be called every time the visible area changes. + * + * @param grayHist Histogram of visible area on gray band + */ + void AdvancedStretchDialog::updateHistogram(const Isis::Histogram &grayHist) { + if(p_grayStretch) + p_grayStretch->setHistogram(grayHist); + } + + + /** + * This is implemented to send a signal when visibility changes + * + * @param event + */ + void AdvancedStretchDialog::showEvent(QShowEvent *event) { + QDialog::showEvent(event); + emit visibilityChanged(); + } + + + /** + * This is implemented to send a signal when visibility changes + * + * @param event + */ + void AdvancedStretchDialog::hideEvent(QHideEvent *event) { + QDialog::hideEvent(event); + emit visibilityChanged(); + } + + + /** + * Returns true if the dialog is displaying the RGB advanced + * stretches. + * + * @return bool + */ + bool AdvancedStretchDialog::isRgbMode() const { + return (p_redStretch && p_grnStretch && p_bluStretch); + } + + + /** + * This returns the advanced stretch's stretch for gray. + * + * @return Isis::Stretch + */ + Isis::Stretch AdvancedStretchDialog::getGrayStretch() { + if(p_grayStretch) { + return p_grayStretch->getStretch(); + } + else { + iString msg = "Gray mode not enabled, cannot get gray stretch"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + /** + * This returns the advanced stretch's stretch for red. + * + * @return Isis::Stretch + */ + Isis::Stretch AdvancedStretchDialog::getRedStretch() { + if(p_redStretch) { + return p_redStretch->getStretch(); + } + else { + iString msg = "RGB mode not enabled, cannot get red stretch"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + /** + * This returns the advanced stretch's stretch for green. + * + * @return Isis::Stretch + */ + Isis::Stretch AdvancedStretchDialog::getGrnStretch() { + if(p_grnStretch) { + return p_grnStretch->getStretch(); + } + else { + iString msg = "RGB mode not enabled, cannot get green stretch"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } + + + /** + * This returns the advanced stretch's stretch for blue. + * + * @return Isis::Stretch + */ + Isis::Stretch AdvancedStretchDialog::getBluStretch() { + if(p_redStretch) { + return p_bluStretch->getStretch(); + } + else { + iString msg = "RGB mode not enabled, cannot get blue stretch"; + throw iException::Message(iException::Programmer, msg, _FILEINFO_); + } + } +}; diff --git a/isis/src/qisis/objs/StretchTool/AdvancedStretchDialog.h b/isis/src/qisis/objs/StretchTool/AdvancedStretchDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..8be30a120af57c5854419738c5bf3824db8b9e2e --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/AdvancedStretchDialog.h @@ -0,0 +1,97 @@ +#ifndef ADVANCEDSTRETCHDIALOG_H +#define ADVANCEDSTRETCHDIALOG_H + +#include + +class QShowEvent; +class QWidget; + +namespace Isis { + class Stretch; + class Histogram; +}; + +namespace Qisis { + class AdvancedStretch; + class CubeViewport; + + /** + * @brief Advanced Stretch Dialog + * + * @ingroup Visualization Tools + * + * @author Steven Lambright 2010-05-20 + * + * @internal + */ + + class AdvancedStretchDialog : public QDialog { + Q_OBJECT + + public: + AdvancedStretchDialog(QWidget *parent); + ~AdvancedStretchDialog(); + + void enableRgbMode(Isis::Stretch &redStretch, Isis::Histogram &redHist, + Isis::Stretch &grnStretch, Isis::Histogram &grnHist, + Isis::Stretch &bluStretch, Isis::Histogram &bluHist); + void updateHistograms(const Isis::Histogram &redHist, + const Isis::Histogram &grnHist, + const Isis::Histogram &bluHist); + + void enableGrayMode(Isis::Stretch &grayStretch, + Isis::Histogram &grayHist); + void updateHistogram(const Isis::Histogram &grayHist); + bool isRgbMode() const; + + Isis::Stretch getGrayStretch(); + Isis::Stretch getRedStretch(); + Isis::Stretch getGrnStretch(); + Isis::Stretch getBluStretch(); + + /** + * Returns true if the advanced stretch is enabled + * + * @return + */ + bool enabled() { + return p_enabled; + } + + /** + * Sets the enabled state to enable + * + * @param enable + */ + void enable(bool enable) { + p_enabled = enable; + } + + signals: + //! Emitted when an advanced stretch has changed + void stretchChanged(); + //! Emitted when this dialog is shown or hidden + void visibilityChanged(); + + public slots: + void updateStretch(CubeViewport *); + + protected slots: + void showEvent(QShowEvent *); + void hideEvent(QHideEvent *); + + private: + void destroyCurrentStretches(); + + private: + bool p_enabled; //!< True if advanced stretch should be used + AdvancedStretch *p_grayStretch; //!< Gray stretch pane + AdvancedStretch *p_redStretch; //!< Red stretch pane + AdvancedStretch *p_grnStretch; //!< Green stretch pane + AdvancedStretch *p_bluStretch; //!< Blue stretch pane + + }; +}; + + +#endif diff --git a/isis/src/qisis/objs/StretchTool/BinaryStretchType.cpp b/isis/src/qisis/objs/StretchTool/BinaryStretchType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..748b436d2190243ad08349f62b3b371ed9c90768 --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/BinaryStretchType.cpp @@ -0,0 +1,379 @@ +#include "BinaryStretchType.h" + +#include +#include +#include +#include +#include + +#include "CubeViewport.h" +#include "HistogramWidget.h" +#include "Statistics.h" +#include "Stretch.h" + +using namespace Isis; + +namespace Qisis { + /** + * This constructs a binary stretch type. + * + * @param hist + * @param stretch + * @param name + * @param color + */ + BinaryStretchType::BinaryStretchType(const Isis::Histogram &hist, + const Isis::Stretch &stretch, + const QString &name, const QColor &color) + : StretchType(hist, stretch, name, color) { + p_startSlider = NULL; + p_startEdit = NULL; + p_endSlider = NULL; + p_endEdit = NULL; + p_sliderOverride = false; + p_editOverride = false; + + QWidget *sliderWidget = new QWidget(); + QGridLayout *sliderLayout = new QGridLayout(); + sliderLayout->setColumnStretch(1, 10); + + QLabel *startLabel = new QLabel("Start"); + p_startSlider = new QSlider(Qt::Horizontal); + p_startSlider->setTickPosition(QSlider::NoTicks); + p_startSlider->setMinimum(0); + p_startSlider->setMaximum(1000); + p_startSlider->setPageStep(50); + connect(p_startSlider, SIGNAL(valueChanged(int)), + this, SLOT(startSliderMoved(int))); + p_startEdit = new QLineEdit(); + p_startEdit->setMaximumWidth(75); + p_startEdit->setText(QString::number(p_cubeHist->Percent(25))); + connect(p_startEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(startEditChanged(const QString &))); + sliderLayout->addWidget(startLabel, 0, 0); + sliderLayout->addWidget(p_startSlider, 0, 1); + sliderLayout->addWidget(p_startEdit, 0, 2); + + QLabel *endLabel = new QLabel("End"); + p_endSlider = new QSlider(Qt::Horizontal); + p_endSlider->setTickPosition(QSlider::NoTicks); + p_endSlider->setMinimum(0); + p_endSlider->setMaximum(1000); + p_endSlider->setValue(1000); + p_endSlider->setPageStep(50); + connect(p_endSlider, SIGNAL(valueChanged(int)), + this, SLOT(endSliderMoved(int))); + p_endEdit = new QLineEdit(); + p_endEdit->setMaximumWidth(75); + p_endEdit->setText(QString::number(p_cubeHist->Percent(75))); + connect(p_endEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(endEditChanged(const QString &))); + sliderLayout->addWidget(endLabel, 1, 0); + sliderLayout->addWidget(p_endSlider, 1, 1); + sliderLayout->addWidget(p_endEdit, 1, 2); + + sliderWidget->setLayout(sliderLayout); + p_mainLayout->addWidget(sliderWidget, 1, 0); + + setLayout(p_mainLayout); + setStretch(calculateNewStretch()); + } + + + /** + * Destroys the binary stretch + */ + BinaryStretchType::~BinaryStretchType() { + } + + + /** + * Given an arbitrary stretch, this will re-interpret it, as + * best as possible, into a binary stretch. It is required that + * a stretch that represents a binary stretch always translate + * into itself and does not cause a stretchChanged(). + * + * It is necessary to always update slider positions in this + * method even if the stretch did not change. + * + * @param newStretch Stretch to interpret + */ + void BinaryStretchType::setStretch(Isis::Stretch newStretch) { + double epsilon = p_cubeHist->BinSize(); + + Stretch interpretted; + + double switch1 = 0.0; + double switch2 = 1.0; + + if(newStretch.Pairs() == 2) { + // given a flat line? + if(newStretch.Output(0) == newStretch.Output(1)) { + // assume its binary all white + interpretted.AddPair(p_cubeHist->Minimum(), 255); + interpretted.AddPair(p_cubeHist->Maximum(), 255); + } + else { + // probably linear, figure out something reasonable + interpretted.AddPair(p_cubeHist->Minimum(), 0); + + switch1 = newStretch.Input(0); + if(switch1 < p_cubeHist->Minimum()) + switch1 = p_cubeHist->Minimum() + epsilon; + + interpretted.AddPair(switch1, 0); + interpretted.AddPair(switch1 + epsilon, 255); + + switch2 = newStretch.Input(1); + if(switch2 <= switch1 + epsilon) + switch2 = switch1 + epsilon + epsilon; + + interpretted.AddPair(switch2, 255); + interpretted.AddPair(switch2 + epsilon, 0); + + double end = p_cubeHist->Maximum(); + if(end <= switch2 + epsilon) + end = switch2 + epsilon + epsilon; + + interpretted.AddPair(end, 0); + } + } + else if(newStretch.Pairs() == 4) { + if(newStretch.Output(0) > 127) { + interpretted.AddPair(p_cubeHist->Minimum(), 255); + + switch1 = newStretch.Input(1); + if(switch1 <= p_cubeHist->Minimum()) + switch1 = p_cubeHist->Minimum() + epsilon; + + interpretted.AddPair(switch1, 255); + interpretted.AddPair(switch1 + epsilon, 0); + + double end = p_cubeHist->Maximum(); + if(end <= switch1 + epsilon) + end = switch1 + epsilon + epsilon; + + switch2 = end; + + interpretted.AddPair(end, 0); + } + else { + interpretted.AddPair(p_cubeHist->Minimum(), 0); + + switch1 = newStretch.Input(1); + if(switch1 < p_cubeHist->Minimum()) + switch1 = p_cubeHist->Minimum() + epsilon; + + interpretted.AddPair(switch1, 0); + interpretted.AddPair(switch1 + epsilon, 255); + + double end = p_cubeHist->Maximum(); + if(end <= switch1 + epsilon) + end = switch1 + epsilon + epsilon; + switch2 = end; + + interpretted.AddPair(end, 255); + } + } + // 6 pairs means the 255 values are in the middle (typical) + else if(newStretch.Pairs() == 6) { + interpretted.AddPair(p_cubeHist->Minimum(), 0); + + switch1 = newStretch.Input(1); + if(switch1 <= p_cubeHist->Minimum()) + switch1 = p_cubeHist->Minimum() + epsilon; + + interpretted.AddPair(switch1, 0); + interpretted.AddPair(switch1 + epsilon, 255); + + + switch2 = newStretch.Input(3); + if(switch2 <= switch1 + epsilon) + switch2 = switch1 + epsilon + epsilon; + + interpretted.AddPair(switch2, 255); + interpretted.AddPair(switch2 + epsilon, 0); + + double end = p_cubeHist->Maximum(); + if(end <= switch2 + epsilon) + end = switch2 + epsilon + epsilon; + + interpretted.AddPair(end, 0); + } + + if(!interpretted.Pairs()) { + interpretted.CopyPairs(calculateNewStretch()); + switch1 = p_startEdit->text().toDouble(); + switch2 = p_endEdit->text().toDouble(); + } + + bool changed = (interpretted.Text() != p_stretch->Text()); + + p_editOverride = true; + if(changed) { + p_stretch->CopyPairs(interpretted); + p_startEdit->setText(QString::number(switch1)); + p_endEdit->setText(QString::number(switch2)); + } + + // regardless of it all, slider positions could need changed... + startEditChanged(QString()); + endEditChanged(QString()); + p_editOverride = false; + + if(changed) { + emit stretchChanged(); + } + } + + + /** + * This is called when the start point slider moves. It ensures + * a valid state and updates the stretch pairs. + */ + void BinaryStretchType::startSliderMoved(int) { + if(p_sliderOverride) + return; + + if(p_startSlider->value() >= p_endSlider->value()) { + p_startSlider->setValue(p_endSlider->value() - 1); + return; + } + + double value = p_cubeHist->Minimum(); + value += p_startSlider->value() * + (p_cubeHist->Maximum() - p_cubeHist->Minimum()) / 1000.0; + p_startEdit->setText(QString::number(value)); + } + + + /** + * A new start point was typed in. Update the slider and + * calculate a new stretch. + */ + void BinaryStretchType::startEditChanged(const QString &) { + double value = p_startEdit->text().toDouble(); + + if(value >= p_endEdit->text().toDouble()) { + return; + } + + double percentage = value - p_cubeHist->Minimum(); + percentage /= (p_cubeHist->Maximum() - p_cubeHist->Minimum()); + int valuePos = (int)(percentage * 1000.0); + + p_sliderOverride = true; + p_startSlider->setValue(valuePos); + p_sliderOverride = false; + + if(p_editOverride) return; + + Stretch newStretch = calculateNewStretch(); + + if(newStretch.Text() != p_stretch->Text()) { + p_stretch->CopyPairs(newStretch); + emit stretchChanged(); + } + } + + + /** + * This is called when the end point slider moves. It ensures + * a valid state and updates the stretch pairs. + */ + void BinaryStretchType::endSliderMoved(int) { + if(p_sliderOverride) + return; + + if(p_endSlider->value() <= p_startSlider->value()) { + p_endSlider->setValue(p_startSlider->value() + 1); + return; + } + + double value = p_cubeHist->Minimum(); + value += p_endSlider->value() * + (p_cubeHist->Maximum() - p_cubeHist->Minimum()) / 1000.0; + p_endEdit->setText(QString::number(value)); + } + + + /** + * A new end point was typed in. Update the slider and calclate + * a new stretch. + */ + void BinaryStretchType::endEditChanged(const QString &) { + double value = p_endEdit->text().toDouble(); + + if(value <= p_startEdit->text().toDouble()) { + return; + } + + double percentage = value - p_cubeHist->Minimum(); + percentage /= (p_cubeHist->Maximum() - p_cubeHist->Minimum()); + int valuePos = (int)(percentage * 1000.0); + + p_sliderOverride = true; + p_endSlider->setValue(valuePos); + p_sliderOverride = false; + + if(p_editOverride) return; + + Stretch newStretch = calculateNewStretch(); + + if(newStretch.Text() != p_stretch->Text()) { + p_stretch->CopyPairs(newStretch);; + emit stretchChanged(); + } + } + + + /** + * This uses the GUI elements to calculate the current binary + * stretch. + * + * @return Isis::Stretch + */ + Isis::Stretch BinaryStretchType::calculateNewStretch() { + double epsilon = p_cubeHist->BinSize(); + + if(epsilon == 0) { + epsilon = (p_cubeHist->Maximum() - p_cubeHist->Minimum()) / 65536; + } + + Stretch newStretch; + + if(epsilon == 0) { + return newStretch; + } + // Start high? + double startPt = p_startEdit->text().toDouble(); + if(fabs(startPt - p_cubeHist->Minimum()) < epsilon || + startPt <= p_cubeHist->Minimum()) { + newStretch.AddPair(p_cubeHist->Minimum(), 255); + startPt = p_cubeHist->Minimum() - epsilon; + } + else { + newStretch.AddPair(p_cubeHist->Minimum(), 0); + newStretch.AddPair(startPt, 0); + newStretch.AddPair(startPt + epsilon, 255); + } + + // End high? + double endPt = p_endEdit->text().toDouble(); + if(endPt <= startPt + epsilon) { + endPt = startPt + 2 * epsilon; + } + + if(fabs(endPt + epsilon - p_cubeHist->Maximum()) < epsilon || + endPt + epsilon >= p_cubeHist->Maximum()) { + newStretch.AddPair(p_cubeHist->Maximum(), 255); + } + else { + newStretch.AddPair(endPt, 255); + newStretch.AddPair(endPt + epsilon, 0); + newStretch.AddPair(p_cubeHist->Maximum(), 0); + } + + return newStretch; + } +} diff --git a/isis/src/qisis/objs/StretchTool/BinaryStretchType.h b/isis/src/qisis/objs/StretchTool/BinaryStretchType.h new file mode 100644 index 0000000000000000000000000000000000000000..ed6c161b7cfd970c11d3349f45c1d498d8d3871d --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/BinaryStretchType.h @@ -0,0 +1,50 @@ +#ifndef BinaryStretchType_H +#define BinaryStretchType_H + +#include "StretchType.h" + +namespace Isis { + class Stretch; + class Histogram; +} + +class QSlider; +class QLineEdit; +class QString; +class QColor; + +namespace Qisis { + class BinaryStretchType : public StretchType { + Q_OBJECT + + public: + BinaryStretchType(const Isis::Histogram &, const Isis::Stretch &, + const QString &name, const QColor &color); + ~BinaryStretchType(); + + virtual void setStretch(Isis::Stretch); + + private slots: + void startSliderMoved(int); + void startEditChanged(const QString &); + void endSliderMoved(int); + void endEditChanged(const QString &); + + private: + Isis::Stretch calculateNewStretch(); + + private: + QSlider *p_startSlider; //!< Start point slider + QLineEdit *p_startEdit; //!< Start point edit + QSlider *p_endSlider; //!< End point slider + QLineEdit *p_endEdit; //!< End point edit + + //! This is used to let the edits be changed to where sliders cant go + bool p_sliderOverride; + + //! This is used to let the edits be changed without updating the stretch + bool p_editOverride; + }; +} + +#endif diff --git a/isis/src/qisis/objs/StretchTool/HistogramWidget.cpp b/isis/src/qisis/objs/StretchTool/HistogramWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..438f251b181968315e6c5dc902d828410ab5c4f9 --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/HistogramWidget.cpp @@ -0,0 +1,142 @@ +#include "HistogramWidget.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace Qisis { + /** + * HistogramWidget constructor. Initializes all of the widgets and sets the plot + * title, histogram curve's color and stretch curve's color. + * + * @param title + * @param histColor + * @param stretchColor + */ + HistogramWidget::HistogramWidget(const QString title, const QColor histColor, const QColor stretchColor) : + QwtPlot(QwtText(title)) { + setCanvasBackground(Qt::white); + enableAxis(QwtPlot::yRight); + setAxisScale(QwtPlot::xBottom, 0, 255); + setAxisLabelRotation(QwtPlot::xBottom, 45); + setAxisScale(QwtPlot::yRight, 0, 255); + + QwtText axisTitle; + QFont axisFont; + axisFont.setBold(true); + axisTitle.setFont(axisFont); + axisTitle.setText("Frequency"); + setAxisTitle(QwtPlot::yLeft, axisTitle); + axisTitle.setText("Input (Cube DN)"); + setAxisTitle(QwtPlot::xBottom, axisTitle); + axisTitle.setText("Output"); + setAxisTitle(QwtPlot::yRight, axisTitle); + + p_histCurve = new HistogramItem(); + p_histCurve->setColor(histColor); + + p_stretchCurve = new QwtPlotCurve(); + p_stretchCurve->setYAxis(QwtPlot::yRight); + p_stretchCurve->setPen(QPen(QBrush(stretchColor), 2, Qt::DashLine)); + p_stretchCurve->setSymbol(QwtSymbol(QwtSymbol::Ellipse, QBrush(stretchColor), QPen(stretchColor), QSize(5, 5))); + + p_histCurve->attach(this); + p_stretchCurve->attach(this); + + p_zoomer = new QwtPlotZoomer(canvas()); + p_zoomer->setZoomBase(); + } + + + /** + * Creates a histogram curve from the given histogram and plots it. + * + * @param hist + */ + void HistogramWidget::setHistogram(const Isis::Histogram &hist) { + std::vector xarray, yarray; + for(int i = 0; i < hist.Bins(); i++) { + if(hist.BinCount(i) > 0) { + xarray.push_back(hist.BinMiddle(i)); + + double freq = (double)hist.BinCount(i) / (double)hist.MaxBinCount(); + yarray.push_back(freq * 100.0); + } + } + + //These are all variables needed in the following for loop. + //---------------------------------------------- + QwtArray intervals(xarray.size()); + QwtValueList majorTicks; + QwtArray values(yarray.size()); + double maxYValue = DBL_MIN; + double minYValue = DBL_MAX; + // --------------------------------------------- + + for(unsigned int y = 0; y < yarray.size(); y++) { + intervals[y] = QwtDoubleInterval(xarray[y], xarray[y] + hist.BinSize()); + + majorTicks.push_back(xarray[y]); + majorTicks.push_back(xarray[y] + hist.BinSize()); + + values[y] = yarray[y]; + if(values[y] > maxYValue) + maxYValue = values[y]; + if(values[y] < minYValue) + minYValue = values[y]; + } + + QwtScaleDiv scaleDiv; + scaleDiv.setTicks(QwtScaleDiv::MajorTick, majorTicks); + + p_histCurve->setData(QwtIntervalData(intervals, values)); + + double min = hist.Minimum(); + double max = hist.Maximum(); + int maxMajor = 5; + int maxMinor = 20; + + // Find a good, fixed, axis scale + QwtScaleEngine *engine = axisScaleEngine(QwtPlot::xBottom); + QwtScaleDiv scale = engine->divideScale(min, max, maxMajor, maxMinor); + QwtDoubleInterval interval = scale.interval(); + setAxisScale(QwtPlot::xBottom, + interval.minValue() - hist.BinSize(), + interval.maxValue() + hist.BinSize()); + p_zoomer->setZoomBase(); + } + + /** + * Creates a stretch curbe from the given stretch and plots it. + * + * @param stretch + */ + void HistogramWidget::setStretch(Isis::Stretch stretch) { + std::vector xarray, yarray; + for(int i = 0; i < stretch.Pairs(); i++) { + xarray.push_back(stretch.Input(i)); + yarray.push_back(stretch.Output(i)); + } + + p_stretchCurve->setData(&xarray[0], &yarray[0], xarray.size()); + replot(); + } + + /** + * Clears the stretch curve from the plot. + * + */ + void HistogramWidget::clearStretch() { + p_stretchCurve->setData(NULL, NULL, 0); + replot(); + } +} diff --git a/isis/src/qisis/objs/StretchTool/HistogramWidget.h b/isis/src/qisis/objs/StretchTool/HistogramWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..a76eeac82cad281d92d9d929896ba680b2578316 --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/HistogramWidget.h @@ -0,0 +1,71 @@ +#ifndef HistogramWidget_h +#define HistogramWidget_h + +#include "Cube.h" +#include "Stretch.h" +#include "Histogram.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "HistogramItem.h" + +class QwtPlotZoomer; + +namespace Qisis { + /** + * @brief Histogram widget used by AdvancedStretchTool + * + * + * The HistogramWidget displays a given histogram and stretch in a graph and + * contains inputs for changing the min/max of the histogram. + * + * @ingroup Visualization Tools + * + * @author 2009-05-01 Noah Hilt + * + */ + class HistogramWidget : public QwtPlot { + Q_OBJECT + + public: + HistogramWidget(const QString title, const QColor histColor = Qt::gray, const QColor stretchColor = Qt::darkGray); + void setHistogram(const Isis::Histogram &hist); + void setStretch(Isis::Stretch stretch); + + void clearStretch(); + + /** + * Histograms have preferred sizes that keeps them all the same + * regardless of the contained data. This causes that. + * + * Prefer 1:1 + * + * @param w + * + * @return int + */ + int heightForWidth(int w) const { + return w; + } + + private slots: + + private: + HistogramItem *p_histCurve; //!< The histogram curve + QwtPlotCurve *p_stretchCurve; //!< The stretch curve + QwtPlotZoomer *p_zoomer; //!< This allows for zooming in/out + + double p_min; //!< The minimum value the histogram's minimum can be set to + double p_max; //!< The maximum value the histogram's maximum can be set to + }; +}; + +#endif diff --git a/isis/src/qisis/objs/StretchTool/LinearStretchType.cpp b/isis/src/qisis/objs/StretchTool/LinearStretchType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a7048362577ae7dc1b49ddd4d20ba9b52432ee5f --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/LinearStretchType.cpp @@ -0,0 +1,257 @@ +#include "LinearStretchType.h" + +#include +#include +#include +#include +#include + +#include "CubeViewport.h" +#include "HistogramWidget.h" +#include "Statistics.h" +#include "Stretch.h" + +using namespace Isis; + +namespace Qisis { + /** + * This constructs a linear stretch type. + * + * @param hist + * @param stretch + * @param name + * @param color + */ + LinearStretchType::LinearStretchType(const Isis::Histogram &hist, + const Isis::Stretch &stretch, + const QString &name, const QColor &color) + : StretchType(hist, stretch, name, color) { + p_startSlider = NULL; + p_endSlider = NULL; + p_startEdit = NULL; + p_endEdit = NULL; + p_sliderOverride = false; + p_editOverride = false; + + QWidget *sliderWidget = new QWidget(); + QGridLayout *sliderLayout = new QGridLayout(); + sliderLayout->setColumnStretch(1, 10); + + QLabel *minHistLabel = new QLabel("Min DN"); + p_startSlider = new QSlider(Qt::Horizontal); + p_startSlider->setTickPosition(QSlider::NoTicks); + p_startSlider->setMinimum(0); + p_startSlider->setMaximum(1000); + p_startSlider->setPageStep(50); + connect(p_startSlider, SIGNAL(valueChanged(int)), + this, SLOT(startSliderMoved(int))); + p_startEdit = new QLineEdit(); + p_startEdit->setMaximumWidth(75); + connect(p_startEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(startEditChanged(const QString &))); + sliderLayout->addWidget(minHistLabel, 0, 0); + sliderLayout->addWidget(p_startSlider, 0, 1); + sliderLayout->addWidget(p_startEdit, 0, 2); + + QLabel *maxHistLabel = new QLabel("Max DN"); + p_endSlider = new QSlider(Qt::Horizontal); + p_endSlider->setTickPosition(QSlider::NoTicks); + p_endSlider->setMinimum(0); + p_endSlider->setMaximum(1000); + p_endSlider->setValue(1000); + p_endSlider->setPageStep(50); + connect(p_endSlider, SIGNAL(valueChanged(int)), + this, SLOT(endSliderMoved(int))); + p_endEdit = new QLineEdit(); + p_endEdit->setMaximumWidth(75); + connect(p_endEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(endEditChanged(const QString &))); + sliderLayout->addWidget(maxHistLabel, 1, 0); + sliderLayout->addWidget(p_endSlider, 1, 1); + sliderLayout->addWidget(p_endEdit, 1, 2); + + sliderWidget->setLayout(sliderLayout); + p_mainLayout->addWidget(sliderWidget, 1, 0); + + setLayout(p_mainLayout); + + setStretch(stretch); + } + + + /** + * Destructor + */ + LinearStretchType::~LinearStretchType() { + } + + + /** + * Given an arbitrary stretch, this will re-interpret it, as + * best as possible, into a linear stretch. It is required that + * a stretch that represents a linear stretch always translate + * into itself and does not cause a stretchChanged(). + * + * It is necessary to always update slider positions in this + * method even if the stretch did not change. + * + * @param newStretch Stretch to interpret + */ + void LinearStretchType::setStretch(Isis::Stretch newStretch) { + Stretch interpretted; + + if(newStretch.Pairs() >= 2) { + double inMin = newStretch.Input(0); + double inMax = newStretch.Input(1); + + if(inMax < inMin) { + double tmp = inMax; + inMax = inMin; + inMin = tmp; + } + + interpretted.AddPair(inMin, 0); + interpretted.AddPair(inMax, 255); + } + else { + double inMin = p_cubeHist->BestMinimum(); + double inMax = p_cubeHist->BestMaximum(); + + if(inMin >= inMax) { + inMin -= p_cubeHist->BinSize(); + inMax += p_cubeHist->BinSize(); + } + + interpretted.AddPair(inMin, 0); + interpretted.AddPair(inMax, 255); + } + + bool changed = (interpretted.Text() != p_stretch->Text()); + + p_editOverride = true; + + if(changed) { + p_stretch->CopyPairs(interpretted); + p_startEdit->setText(QString::number(p_stretch->Input(0))); + p_endEdit->setText(QString::number(p_stretch->Input(1))); + } + + // regardless of it all, slider positions could need changed... + startEditChanged(QString()); + endEditChanged(QString()); + p_editOverride = false; + + if(changed) { + emit stretchChanged(); + } + } + + + /** + * This is called when the start point slider moves. It ensures + * a valid state and updates the stretch pairs. + */ + void LinearStretchType::startSliderMoved(int) { + if(p_sliderOverride) + return; + + if(p_startSlider->value() >= p_endSlider->value()) { + p_startSlider->setValue(p_endSlider->value() - 1); + return; + } + + double value = p_cubeHist->Minimum(); + value += p_startSlider->value() * + (p_cubeHist->Maximum() - p_cubeHist->Minimum()) / 1000.0; + p_startEdit->setText(QString::number(value)); + } + + + /** + * A new start point was typed in. Update the slider and + * calculate a new stretch. + */ + void LinearStretchType::startEditChanged(const QString &) { + double value = p_startEdit->text().toDouble(); + + if(value >= p_endEdit->text().toDouble()) { + return; + } + + double percentage = value - p_cubeHist->Minimum(); + percentage /= (p_cubeHist->Maximum() - p_cubeHist->Minimum()); + int valuePos = (int)(percentage * 1000.0); + + p_sliderOverride = true; + p_startSlider->setValue(valuePos); + p_sliderOverride = false; + + if(p_editOverride) return; + + Stretch newStretch; + newStretch.AddPair(value, 0); + newStretch.AddPair(p_stretch->Input(1), 255); + + if(newStretch.Text() != p_stretch->Text()) { + p_stretch->CopyPairs(newStretch); + emit stretchChanged(); + } + } + + + /** + * This is called when the end point slider moves. It ensures + * a valid state and updates the stretch pairs. + */ + void LinearStretchType::endSliderMoved(int) { + if(p_sliderOverride) + return; + + if(p_endSlider->value() <= p_startSlider->value()) { + p_endSlider->setValue(p_startSlider->value() + 1); + return; + } + + double value = p_cubeHist->Minimum(); + value += p_endSlider->value() * + (p_cubeHist->Maximum() - p_cubeHist->Minimum()) / 1000.0; + p_endEdit->setText(QString::number(value)); + } + + + /** + * A new end point was typed in. Update the slider and + * calculate a new stretch. + */ + void LinearStretchType::endEditChanged(const QString &) { + double value = p_endEdit->text().toDouble(); + + if(value <= p_startEdit->text().toDouble()) { + return; + } + + double percentage = value - p_cubeHist->Minimum(); + percentage /= (p_cubeHist->Maximum() - p_cubeHist->Minimum()); + int valuePos = (int)(percentage * 1000.0); + + p_sliderOverride = true; + p_endSlider->setValue(valuePos); + p_sliderOverride = false; + + if(p_editOverride) return; + + Stretch newStretch; + newStretch.AddPair(p_stretch->Input(0), 0); + newStretch.AddPair(value, 255); + + if(newStretch.Text() != p_stretch->Text()) { + p_stretch->CopyPairs(newStretch); + emit stretchChanged(); + } + } + + + Isis::Stretch LinearStretchType::getStretch() { + return *p_stretch; + } +} diff --git a/isis/src/qisis/objs/StretchTool/LinearStretchType.h b/isis/src/qisis/objs/StretchTool/LinearStretchType.h new file mode 100644 index 0000000000000000000000000000000000000000..6350416c13295a5f4113b3d2f1654518d0e4d7f4 --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/LinearStretchType.h @@ -0,0 +1,49 @@ +#ifndef LinearStretchType_H +#define LinearStretchType_H + +#include "StretchType.h" + +namespace Isis { + class Stretch; + class Histogram; +} + +class QSlider; +class QLineEdit; +class QString; +class QColor; + +namespace Qisis { + class LinearStretchType : public StretchType { + Q_OBJECT + + public: + LinearStretchType(const Isis::Histogram &, const Isis::Stretch &, + const QString &name, const QColor &color); + ~LinearStretchType(); + + virtual Isis::Stretch getStretch(); + virtual void setStretch(Isis::Stretch); + + + private slots: + void startSliderMoved(int); + void startEditChanged(const QString &); + void endSliderMoved(int); + void endEditChanged(const QString &); + + private: + QSlider *p_startSlider; //!< Line start pt slider + QLineEdit *p_startEdit; //!< Line start pt edit + QSlider *p_endSlider; //!< Line end pt slider + QLineEdit *p_endEdit; //!< Line end pt edit + + //! This is used to let the edits be changed to where sliders cant go + bool p_sliderOverride; + + //! This is used to let the edits be changed without updating the stretch + bool p_editOverride; + }; +} + +#endif diff --git a/isis/src/qisis/objs/StretchTool/Makefile b/isis/src/qisis/objs/StretchTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/StretchTool/ManualStretchType.cpp b/isis/src/qisis/objs/StretchTool/ManualStretchType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f711f17fdce26ecad1ac4acce1c6d316bbf97e21 --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/ManualStretchType.cpp @@ -0,0 +1,169 @@ +#include "ManualStretchType.h" + +#include +#include +#include +#include +#include +#include + +#include "CubeViewport.h" +#include "HistogramWidget.h" +#include "Statistics.h" +#include "Stretch.h" + +using namespace Isis; + +namespace Qisis { + /** + * This constructs a manual stretch type. + * + * @param hist + * @param stretch + * @param name + * @param color + */ + ManualStretchType::ManualStretchType(const Isis::Histogram &hist, + const Isis::Stretch &stretch, + const QString &name, const QColor &color) + : StretchType(hist, stretch, name, color) { + p_inputEdit = NULL; + p_outputEdit = NULL; + + QWidget *sliderWidget = new QWidget(); + QGridLayout *sliderLayout = new QGridLayout(); + + QLabel *inputLabel = new QLabel("Input"); + p_inputEdit = new QLineEdit(); + + sliderLayout->addWidget(inputLabel, 0, 0); + sliderLayout->addWidget(p_inputEdit, 0, 1); + + QLabel *outputLabel = new QLabel("Output"); + p_outputEdit = new QLineEdit(); + + sliderLayout->addWidget(outputLabel, 1, 0); + sliderLayout->addWidget(p_outputEdit, 1, 1); + + QWidget *buttonContainer = new QWidget(); + QHBoxLayout *buttonLayout = new QHBoxLayout(); + + QPushButton *addButton = new QPushButton("Add / Edit"); + connect(addButton, SIGNAL(clicked(bool)), + this, SLOT(addButtonPressed(bool))); + buttonLayout->addWidget(addButton); + + QPushButton *deleteButton = new QPushButton("Delete"); + connect(deleteButton, SIGNAL(clicked(bool)), + this, SLOT(deleteButtonPressed(bool))); + buttonLayout->addWidget(deleteButton); + + buttonContainer->setLayout(buttonLayout); + sliderLayout->addWidget(buttonContainer, 2, 0, 1, 2); + + sliderWidget->setLayout(sliderLayout); + p_mainLayout->addWidget(sliderWidget, 1, 0); + + setLayout(p_mainLayout); + setStretch(stretch); + } + + + /** + * Destructor + */ + ManualStretchType::~ManualStretchType() { + } + + + /** + * Given an arbitrary stretch, this will re-interpret it, as + * best as possible, into a manual stretch. It is required that + * a stretch that represents a manual stretch always translate + * into itself and does not cause a stretchChanged(). + * + * It is necessary to always update slider positions in this + * method even if the stretch did not change. + * + * Good thing this is a manual stretch so no interpretation is + * really needed. + * + * @param newStretch Stretch to interpret + */ + void ManualStretchType::setStretch(Isis::Stretch newStretch) { + if(newStretch.Text() != p_stretch->Text()) { + p_stretch->CopyPairs(newStretch); + emit stretchChanged(); + } + } + + + /** + * This is called when a user clicks "Add / Edit" and is + * responsible for adding the pair into the correct location or + * editing the pair at that location (input value). + */ + void ManualStretchType::addButtonPressed(bool) { + double input = p_inputEdit->text().toDouble(); + double output = p_outputEdit->text().toDouble(); + + Stretch newStretch; + bool added = false; + + for(int stretchPair = 0; + stretchPair < p_stretch->Pairs(); + stretchPair ++) { + if(input < p_stretch->Input(stretchPair)) { + if(!added) { + newStretch.AddPair(input, output); + added = true; + } + + newStretch.AddPair(p_stretch->Input(stretchPair), + p_stretch->Output(stretchPair)); + } + else if(!added && input == p_stretch->Input(stretchPair)) { + newStretch.AddPair(input, output); + added = true; + } + else { + newStretch.AddPair(p_stretch->Input(stretchPair), + p_stretch->Output(stretchPair)); + } + } + + if(!added) { + newStretch.AddPair(input, output); + added = true; + } + + p_stretch->CopyPairs(newStretch); + emit stretchChanged(); + } + + + /** + * This is called when a user clicks "Delete" and is + * responsible for removing the pair with the given input value. + */ + void ManualStretchType::deleteButtonPressed(bool) { + double input = p_inputEdit->text().toDouble(); + + Stretch newStretch; + + for(int stretchPair = 0; + stretchPair < p_stretch->Pairs(); + stretchPair ++) { + if(input == p_stretch->Input(stretchPair)) { + continue; + } + else { + newStretch.AddPair(p_stretch->Input(stretchPair), + p_stretch->Output(stretchPair)); + } + } + + p_stretch->CopyPairs(newStretch); + emit stretchChanged(); + } +} diff --git a/isis/src/qisis/objs/StretchTool/ManualStretchType.h b/isis/src/qisis/objs/StretchTool/ManualStretchType.h new file mode 100644 index 0000000000000000000000000000000000000000..ce2ac1bae1498afb6d6c8d05e4b3b418c11074e9 --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/ManualStretchType.h @@ -0,0 +1,37 @@ +#ifndef ManualStretchType_H +#define ManualStretchType_H + +#include "StretchType.h" + +namespace Isis { + class Stretch; + class Histogram; +} + +class QSlider; +class QLineEdit; +class QString; +class QColor; + +namespace Qisis { + class ManualStretchType : public StretchType { + Q_OBJECT + + public: + ManualStretchType(const Isis::Histogram &, const Isis::Stretch &, + const QString &name, const QColor &color); + ~ManualStretchType(); + + virtual void setStretch(Isis::Stretch); + + private slots: + void addButtonPressed(bool); + void deleteButtonPressed(bool); + + private: + QLineEdit *p_inputEdit; //!< Input Stretch Value + QLineEdit *p_outputEdit; //!< Output Stretch Value + }; +} + +#endif diff --git a/isis/src/qisis/objs/StretchTool/QStretch.h b/isis/src/qisis/objs/StretchTool/QStretch.h new file mode 100644 index 0000000000000000000000000000000000000000..2a9db7caa8cf11d82930dd0dbf759cc9129162b4 --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/QStretch.h @@ -0,0 +1,139 @@ +#ifndef QStretch_h +#define QStretch_h + +#include +#include + +#include "Stretch.h" + +namespace Qisis { + /** + * @brief Abstract class for complex stretch objects + * + * This class serves as the parent class to complex stretch objects that + * are used by the AdvancedStretchTool. It must define parameters to + * manipulate its stretch pairs that will be used by the AdvancedStretchTool's + * 'Advanced' dialog. + * + * @ingroup Visualization Tools + * + * @author 2009-05-01 Noah hilt + * + * + */ + + class StretchTool; + + class QStretch : public QObject { + Q_OBJECT + + public: + /** + * QStretch Constructor. StretchTool can not be null. + * + * Initializes the stretch and sets its special pixel values + * to their defaults. + * + * @param stretchTool + * @param name + */ + QStretch(const StretchTool *stretchTool, QString name) + : p_stretchTool(stretchTool), + p_name(name), + p_min(0.0), + p_max(255.0), + p_parametersBox(NULL) { + p_stretch.SetNull(0.0); + p_stretch.SetLis(0.0); + p_stretch.SetLrs(0.0); + p_stretch.SetHis(255.0); + p_stretch.SetHrs(255.0); + p_stretch.SetMinimum(0.0); + p_stretch.SetMaximum(255.0); + }; + + + /** + * Abstract method to clone a QStretch in order to retain its parameters and + * stretch pairs. This method must be overridden. + * + * + * @return QStretch* + */ + virtual QStretch *clone() = 0; + + /** + * Abstract method to connect the AdvancedStretchTool's table of stretch pairs + * in order to modify it if necessary. The default implementation is to do + * nothing. + * + * @param widget + */ + virtual void connectTable(QTableWidget *widget) {}; + + /** + * Abstract method to disconnect the AdvancedStretchTool's table of stretch + * pairs. The default implementation is to do nothing. + * + * @param widget + */ + virtual void disconnectTable(QTableWidget *widget) {}; + + /** + * Abstract method to return a QGroupBox of this QStretch's parameters. This + * method must be overridden. + * + * + * @return QGroupBox* + */ + virtual QGroupBox *getParameters() = 0; + + /** + * This method returns the name of this QStretch. + * + * + * @return QString + */ + QString name() { + return p_name; + } + + /** + * + * This method returns the stretch. + * + * @return Isis::Stretch + */ + Isis::Stretch stretch() { + return p_stretch; + } + + /** + * Abstract method to set the minimum and maximum values that stretch input + * pairs can be set to. + * + * @param min + * @param max + */ + virtual void setMinMax(double min, double max) { + p_min = min; + p_max = max; + } + + signals: + /** + * Signal to emit when this QStretch has been updated. + */ + void update(); + + protected: + const StretchTool *p_stretchTool; //!< The StretchTool that created this QStretch + QString p_name; //!< The name of this QStretch + double p_min; //!< The minimum value a stretch input pair can be set to + double p_max; //!< The maximum value a stretch input pair can be set to + QGroupBox *p_parametersBox; //!< The QGroupBox that holds this QStretch's parameters + Isis::Stretch p_stretch; //!< The stretch that this QStretch modifies + }; +}; + +#endif diff --git a/isis/src/qisis/objs/StretchTool/SawtoothStretchType.cpp b/isis/src/qisis/objs/StretchTool/SawtoothStretchType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63469914e55b419d76554477f494150e33a14fdc --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/SawtoothStretchType.cpp @@ -0,0 +1,317 @@ +#include "SawtoothStretchType.h" + +#include +#include +#include +#include +#include + +#include "CubeViewport.h" +#include "HistogramWidget.h" +#include "Statistics.h" +#include "Stretch.h" + +using namespace Isis; + +namespace Qisis { + /** + * This initializes a sawtooth stretch type + * + * @param hist + * @param stretch + * @param name + * @param color + */ + SawtoothStretchType::SawtoothStretchType(const Isis::Histogram &hist, + const Isis::Stretch &stretch, const QString &name, const QColor &color) : + StretchType(hist, stretch, name, color) { + p_offsetSlider = NULL; + p_widthSlider = NULL; + p_offsetEdit = NULL; + p_widthEdit = NULL; + p_sliderOverride = false; + + QWidget *sliderWidget = new QWidget(); + QGridLayout *sliderLayout = new QGridLayout(); + sliderLayout->setColumnStretch(1, 10); + + QLabel *startLabel = new QLabel("Offset"); + p_offsetSlider = new QSlider(Qt::Horizontal); + p_offsetSlider->setTickPosition(QSlider::NoTicks); + p_offsetSlider->setMinimum(0); + p_offsetSlider->setMaximum(1000); + p_offsetSlider->setPageStep(50); + connect(p_offsetSlider, SIGNAL(valueChanged(int)), + this, SLOT(offsetSliderMoved(int))); + p_offsetEdit = new QLineEdit(); + p_offsetEdit->setMaximumWidth(75); + p_offsetEdit->setText(QString::number( + p_cubeHist->Maximum() - p_cubeHist->Minimum() + )); + connect(p_offsetEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(offsetEditChanged(const QString &))); + sliderLayout->addWidget(startLabel, 0, 0); + sliderLayout->addWidget(p_offsetSlider, 0, 1); + sliderLayout->addWidget(p_offsetEdit, 0, 2); + + QLabel *widthLabel = new QLabel("Width"); + p_widthSlider = new QSlider(Qt::Horizontal); + p_widthSlider->setTickPosition(QSlider::NoTicks); + p_widthSlider->setMinimum(0); + p_widthSlider->setMaximum(1000); + p_widthSlider->setPageStep(50); + connect(p_widthSlider, SIGNAL(valueChanged(int)), + this, SLOT(widthSliderMoved(int))); + p_widthEdit = new QLineEdit(); + p_widthEdit->setMaximumWidth(75); + connect(p_widthEdit, SIGNAL(textChanged(const QString &)), + this, SLOT(widthEditChanged(const QString &))); + sliderLayout->addWidget(widthLabel, 1, 0); + sliderLayout->addWidget(p_widthSlider, 1, 1); + sliderLayout->addWidget(p_widthEdit, 1, 2); + + sliderWidget->setLayout(sliderLayout); + p_mainLayout->addWidget(sliderWidget, 1, 0); + + setLayout(p_mainLayout); + + p_widthEdit->setText(QString::number( + p_cubeHist->Median() - p_cubeHist->Minimum() + )); + setStretch(calculateNewStretch()); + } + + + /** + * Destructor + */ + SawtoothStretchType::~SawtoothStretchType() { + } + + + /** + * Given an arbitrary stretch, this will re-interpret it, as + * best as possible, into a sawtooth stretch. It is required + * that a stretch that represents a sawtooth stretch always + * translate into itself and does not cause a stretchChanged(). + * To ensure this the sliders have been restricted to not be + * ambiguous. + * + * It is necessary to always update slider positions in this + * method even if the stretch did not change. + * + * @param newStretch Stretch to interpret + */ + void SawtoothStretchType::setStretch(const Isis::Stretch newStretch) { + Stretch interpretted; + double offset = 0.0; + double width = 0.0; + bool changed = false; + + if(newStretch.Pairs() < 3) { + // Disable all interpretation of linear stretches + interpretted.CopyPairs(calculateNewStretch()); + offset = p_offsetEdit->text().toDouble(); + width = p_widthEdit->text().toDouble(); + changed = true; + } + else { + // find an offset... should be the second or third point + offset = newStretch.Input(1); + + // offset should always be a low point + if(newStretch.Output(1) > 127) + offset = newStretch.Input(2); + + width = (newStretch.Input(2) - newStretch.Input(0)) / 2; + + interpretted.CopyPairs(calculateNewStretch(offset, width)); + + double deltaOffset = fabs(p_offsetEdit->text().toDouble() - offset); + changed = (changed || (deltaOffset > p_cubeHist->BinSize())); + + double deltaWidth = fabs(p_widthEdit->text().toDouble() - width); + changed = (changed || (deltaWidth > p_cubeHist->BinSize())); + } + + if(changed) { + p_stretch->CopyPairs(interpretted); + p_offsetEdit->setText(QString::number(offset)); + p_widthEdit->setText(QString::number(width)); + } + + // regardless of it all, slider positions could need changed... + offsetEditChanged(QString()); + widthEditChanged(QString()); + + if(changed) { + emit stretchChanged(); + } + } + + + /** + * This is called when the sawtooth offset slider moves. It + * updates the edit. + */ + void SawtoothStretchType::offsetSliderMoved(int) { + if(p_offsetSlider->value() >= p_widthSlider->value()) + p_offsetSlider->setValue(p_widthSlider->value() - 1); + + if(p_sliderOverride) + return; + + double value = p_cubeHist->Minimum(); + value += p_offsetSlider->value() * 2 * + (p_cubeHist->Maximum() - p_cubeHist->Minimum()) / 1000.0; + p_offsetEdit->setText(QString::number(value)); + } + + + /** + * This is called when the the sawtooth offset edit changes. It + * updates the slider (while blocking the slider from calling + * this method again) and calculates a new stretch. + */ + void SawtoothStretchType::offsetEditChanged(const QString &) { + double value = p_offsetEdit->text().toDouble(); + + double percentage = value - p_cubeHist->Minimum(); + percentage /= (p_cubeHist->Maximum() - p_cubeHist->Minimum()) * 2; + int valuePos = (int)(percentage * 1000.0); + + p_sliderOverride = true; + p_offsetSlider->setValue(valuePos); + p_sliderOverride = false; + + Stretch newStretch = calculateNewStretch(); + + if(newStretch.Text() != p_stretch->Text()) { + p_stretch->CopyPairs(newStretch); + emit stretchChanged(); + } + + } + + + /** + * This is called when the sawtooth width slider moves. It + * updates the edit. + */ + void SawtoothStretchType::widthSliderMoved(int) { + if(p_widthSlider->value() <= p_offsetSlider->value()) + p_widthSlider->setValue(p_offsetSlider->value() + 1); + + if(p_sliderOverride) + return; + + double highVal = p_cubeHist->Maximum() - p_cubeHist->Minimum(); + double lowVal = p_cubeHist->BinSize(); + double value = lowVal + p_widthSlider->value() * + (highVal - lowVal) / 1000.0; + p_widthEdit->setText(QString::number(value)); + } + + + /** + * This is called when the the sawtooth width edit changes. It + * updates the slider (while blocking the slider from calling + * this method again) and calculates a new stretch. + */ + void SawtoothStretchType::widthEditChanged(const QString &) { + double value = p_widthEdit->text().toDouble(); + + double highVal = p_cubeHist->Maximum() - p_cubeHist->Minimum(); + double lowVal = p_cubeHist->BinSize(); + + double percentage = value - lowVal; + percentage /= (highVal - lowVal); + int valuePos = (int)(percentage * 1000.0); + + p_sliderOverride = true; + p_widthSlider->setValue(valuePos); + p_sliderOverride = false; + + Stretch newStretch = calculateNewStretch(); + + if(newStretch.Text() != p_stretch->Text()) { + p_stretch->CopyPairs(newStretch); + emit stretchChanged(); + } + } + + + /** + * This uses the parameters offset, width to create a sawtooth + * stretch. + * + * @param offset A pair mapping (offset, 0) will be created (or + * would if the histogram had the appropriate + * range) + * @param width How wide the sawtooth is + * + * @return Isis::Stretch + */ + Isis::Stretch SawtoothStretchType::calculateNewStretch(double offset, + double width) { + Isis::Stretch stretch; + width = fabs(width); + + if(width < p_cubeHist->BinSize()) + width = p_cubeHist->BinSize(); + + // Still can't do it? Give up + if(width <= 0) return Stretch(); + + bool high = false; + + // We want leftPoint to be our starting point for the sawtooth, one left of + // the minimum + double leftPoint = offset; + + // If leftPoint is too far left, move it right + while(leftPoint < p_cubeHist->Minimum() - width) { + leftPoint += width; + high = !high; + } + + // If leftPoint is too far fight, move it left + while(leftPoint >= p_cubeHist->Minimum()) { + leftPoint -= width; + high = !high; + } + + double currPoint = leftPoint; + + bool terminated = false; + while(!terminated) { + int outValue = (high) ? 255 : 0; + + // This conversion to a string & back prevents infinite loops due to + // rounding errors and disagreements betweeen double to string + // conversions later on (in setStretch) + stretch.AddPair(QString::number(currPoint).toDouble(), outValue); + + if(currPoint > p_cubeHist->Maximum()) { + terminated = true; + } + + high = !high; + currPoint += width; + } + + return stretch; + } + + + /** + * This calculates a new stretch using the GUI edits. + * + * @return Isis::Stretch + */ + Isis::Stretch SawtoothStretchType::calculateNewStretch() { + return calculateNewStretch(p_offsetEdit->text().toDouble(), + p_widthEdit->text().toDouble()); + } +} + diff --git a/isis/src/qisis/objs/StretchTool/SawtoothStretchType.h b/isis/src/qisis/objs/StretchTool/SawtoothStretchType.h new file mode 100644 index 0000000000000000000000000000000000000000..a5f750603b3282d7b1550d243c06c8e7cba7efd3 --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/SawtoothStretchType.h @@ -0,0 +1,49 @@ +#ifndef SAWTOOTHSTRETCHTYPE_H +#define SAWTOOTHSTRETCHTYPE_H + +#include "StretchType.h" + +namespace Isis { + class Stretch; + class Histogram; +} + +class QSlider; +class QLineEdit; +class QColor; +class QString; + +namespace Qisis { + class SawtoothStretchType : public StretchType { + Q_OBJECT + + public: + SawtoothStretchType(const Isis::Histogram &, const Isis::Stretch &, + const QString &name, const QColor &color); + ~SawtoothStretchType(); + + virtual void setStretch(Isis::Stretch); + + + private slots: + void offsetSliderMoved(int); + void offsetEditChanged(const QString &); + void widthSliderMoved(int); + void widthEditChanged(const QString &); + + private: + Isis::Stretch calculateNewStretch(); + Isis::Stretch calculateNewStretch(double, double); + + private: + QSlider *p_offsetSlider; //!< Offset slider + QLineEdit *p_offsetEdit; //!< Offset edit + QSlider *p_widthSlider; //!< Width slider + QLineEdit *p_widthEdit; //!< Width edit + + //! This is used to let the edits be changed to where sliders cant go + bool p_sliderOverride; + }; +} + +#endif diff --git a/isis/src/qisis/objs/StretchTool/StretchTool.cpp b/isis/src/qisis/objs/StretchTool/StretchTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a63c22975f40aaba4d72a7e51865f09aef9ef307 --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/StretchTool.cpp @@ -0,0 +1,1363 @@ +#include "StretchTool.h" + +#include +#include +#include +#include +#include +#include + +#include "AdvancedStretchDialog.h" +#include "Brick.h" +#include "CubeViewport.h" +#include "Histogram.h" +#include "iException.h" +#include "iString.h" +#include "MainWindow.h" +#include "MdiCubeViewport.h" +#include "RubberBandTool.h" +#include "Statistics.h" +#include "Stretch.h" +#include "ToolPad.h" +#include "ViewportBuffer.h" +#include "ViewportMainWindow.h" +#include "Workspace.h" + + +using namespace Isis; +using namespace std; + +namespace Qisis +{ + /** + * StretchTool constructor + * + * + * @param parent + */ + StretchTool::StretchTool(QWidget *parent) : Tool::Tool(parent) + { + p_preGlobalStretches = NULL; + p_advancedStretch = NULL; + p_advancedStretch = new AdvancedStretchDialog(parent); + connect(p_advancedStretch, SIGNAL(stretchChanged()), + this, SLOT(advancedStretchChanged())); + connect(p_advancedStretch, SIGNAL(visibilityChanged()), + this, SLOT(updateTool())); + + QPushButton *hiddenButton = new QPushButton(); + hiddenButton->setVisible(false); + hiddenButton->setDefault(true); + + p_stretchGlobal = new QAction(parent); + p_stretchGlobal->setShortcut(Qt::CTRL + Qt::Key_G); + p_stretchGlobal->setText("Global Stretch"); + connect(p_stretchGlobal, SIGNAL(activated()), this, SLOT(stretchGlobal())); + + p_stretchRegional = new QAction(parent); + p_stretchRegional->setShortcut(Qt::CTRL + Qt::Key_R); + p_stretchRegional->setText("Regional Stretch"); + connect(p_stretchRegional, SIGNAL(activated()), this, SLOT(stretchRegional())); + + // Emit a signal when an exception and connect o the Warning object to display Warning icon and the message + connect(this, SIGNAL(warningSignal(std::string &, const std::string)), + (Qisis::ViewportMainWindow *)parent, + SLOT(displayWarning(std::string &, const std::string &))); + } + + + /** + * Destructor + */ + StretchTool::~StretchTool() + { + if (p_preGlobalStretches) + { + delete [] p_preGlobalStretches; + p_preGlobalStretches = NULL; + } + } + + + /** + * Adds the stretch action to the toolpad. + * + * + * @param pad + * + * @return QAction* + */ + QAction *StretchTool::toolPadAction(ToolPad *pad) + { + QAction *action = new QAction(pad); + action->setIcon(QPixmap(toolIconDir() + "/stretch_global.png")); + action->setToolTip("Stretch (S)"); + action->setShortcut(Qt::Key_S); + QString text = + "Function: Change the stretch range of the cube.\ +

    Shortcut: S

    "; + action->setWhatsThis(text); + + return action; + } + + + /** + * Adds the stretch action to the given menu. + * + * + * @param menu + */ + void StretchTool::addTo(QMenu *menu) + { + menu->addAction(p_stretchGlobal); + menu->addAction(p_stretchRegional); + } + + + /** + * Creates the widget to add to the tool bar. + * + * + * @param parent + * + * @return QWidget* + */ + QWidget *StretchTool::createToolBarWidget(QStackedWidget *parent) + { + QWidget *hbox = new QWidget(parent); + + QToolButton *butt = new QToolButton(hbox); + butt->setAutoRaise(true); + butt->setIconSize(QSize(22, 22)); + butt->setIcon(QPixmap(toolIconDir() + "/regional_stretch-2.png")); + butt->setToolTip("Stretch"); + QString text = + "Function: Automatically compute min/max stretch using viewed \ + pixels in the band(s) of the active viewport. That is, only pixels \ + that are visible in the viewport are used. \ + If the viewport is in RGB color all three bands will be stretched. \ +

    Shortcut: Ctrl+R

    \ +

    Mouse: Left click \ +

    Hint: Left click and drag for a local stretch. Uses only \ + pixels in the red marquee

    "; + butt->setWhatsThis(text); + connect(butt, SIGNAL(clicked()), this, SLOT(stretchRegional())); + p_stretchRegionalButton = butt; + + p_stretchBandComboBox = new QComboBox(hbox); + p_stretchBandComboBox->setEditable(false); + p_stretchBandComboBox->addItem("Red Band", Red); + p_stretchBandComboBox->addItem("Green Band", Green); + p_stretchBandComboBox->addItem("Blue Band", Blue); + p_stretchBandComboBox->setToolTip("Select Color"); + text = + "Function: Selecting the color will allow the appropriate \ + min/max to be seen and/or edited in text fields to the right."; + +// The All option implies the same min/max will be applied +// to all three colors (RGB) if either text field is edited"; + p_stretchBandComboBox->setWhatsThis(text); + p_stretchBandComboBox->setCurrentIndex(p_stretchBandComboBox->findData(Red)); + p_stretchBand = Red; + connect(p_stretchBandComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(stretchBandChanged(int))); + + QDoubleValidator *dval = new QDoubleValidator(hbox); + p_stretchMinEdit = new QLineEdit(hbox); + p_stretchMinEdit->setValidator(dval); + p_stretchMinEdit->setToolTip("Minimum"); + text = + "Function: Shows the current minimum pixel value. Pixel values \ + below minimum are shown as black. Pixel values above the maximum \ + are shown as white or the highest intensity of red/green/blue \ + if in color. Pixel values between the minimum and maximum are stretched \ + linearly between black and white (or color component). \ +

    Hint: You can manually edit the minimum but it must be \ + less than the maximum."; + p_stretchMinEdit->setWhatsThis(text); + p_stretchMinEdit->setMaximumWidth(100); + connect(p_stretchMinEdit, SIGNAL(returnPressed()), this, SLOT(changeStretch())); + + p_stretchMaxEdit = new QLineEdit(hbox); + p_stretchMaxEdit->setValidator(dval); + p_stretchMaxEdit->setToolTip("Maximum"); + text = + "Function: Shows the current maximum pixel value. Pixel values \ + below minimum are shown as black. Pixel values above the maximum \ + are shown as white or the highest intensity of red/green/blue \ + if in color. Pixel values between the minimum and maximum are stretched \ + linearly between black and white (or color component). \ +

    Hint: You can manually edit the maximum but it must be \ + greater than the minimum"; + p_stretchMaxEdit->setWhatsThis(text); + p_stretchMaxEdit->setMaximumWidth(100); + connect(p_stretchMaxEdit, SIGNAL(returnPressed()), this, SLOT(changeStretch())); + + // Create the two menus that drop down from the buttons + QMenu *copyMenu = new QMenu(); + QMenu *globalMenu = new QMenu(); + + p_copyBands = new QAction(parent); + p_copyBands->setText("to All Bands"); + connect(p_copyBands, SIGNAL(triggered(bool)), this, SLOT(setStretchAcrossBands())); + + QAction *copyAll = new QAction(parent); + copyAll->setIcon(QPixmap(toolIconDir() + "/copy_stretch.png")); + copyAll->setText("to All Viewports"); + connect(copyAll, SIGNAL(triggered(bool)), this, SLOT(setStretchAllViewports())); + + copyMenu->addAction(copyAll); + copyMenu->addAction(p_copyBands); + + p_copyButton = new QToolButton(); + p_copyButton->setAutoRaise(true); + p_copyButton->setIconSize(QSize(22, 22)); + p_copyButton->setIcon(QPixmap(toolIconDir() + "/copy_stretch.png")); + p_copyButton->setPopupMode(QToolButton::MenuButtonPopup); + p_copyButton->setMenu(copyMenu); + p_copyButton->setDefaultAction(copyAll); + p_copyButton->setToolTip("Copy"); + text = + "Function: Copy the current stretch to all the \ + active viewports. Or use the drop down menu to copy the current stretch \ + to all the bands in the active viewport. \ +

    Hint: Can reset the stretch to an automaticaly computed \ + stretch by using the 'Reset' stretch button option.

    "; + p_copyButton->setWhatsThis(text); + + QAction *currentView = new QAction(parent); + currentView->setText("Active Viewport"); + currentView->setIcon(QPixmap(toolIconDir() + "/global_stretch.png")); + globalMenu->addAction(currentView); + connect(currentView, SIGNAL(triggered(bool)), this, SLOT(stretchGlobal())); + + QAction *globalAll = new QAction(parent); + globalAll->setText("All Viewports"); + globalMenu->addAction(globalAll); + connect(globalAll, SIGNAL(triggered(bool)), this, SLOT(stretchGlobalAllViewports())); + + QAction *globalBands = new QAction(parent); + globalBands->setText("All Bands"); + globalMenu->addAction(globalBands); + connect(globalBands, SIGNAL(triggered(bool)), this, SLOT(stretchGlobalAllBands())); + + p_globalButton = new QToolButton(); //basically acts as a 'reset' + p_globalButton->setAutoRaise(true); + p_globalButton->setIconSize(QSize(22, 22)); + p_globalButton->setPopupMode(QToolButton::MenuButtonPopup); + p_globalButton->setMenu(globalMenu); + p_globalButton->setDefaultAction(currentView); + p_globalButton->setToolTip("Reset"); + text = + "Function: Reset the stretch to be automatically computed \ + using the statisics from the entire image. Use the drop down menu \ + to reset the stretch for all the bands in the active viewport or \ + to reset the stretch for all the viewports.

    "; + p_globalButton->setWhatsThis(text); + + QPushButton *advancedButton = new QPushButton("Advanced"); + connect(advancedButton, SIGNAL(clicked()), this, SLOT(showAdvancedDialog())); + + p_flashButton = new QPushButton("Show Global"); + connect(p_flashButton, SIGNAL(pressed()), this, SLOT(stretchChanged())); + connect(p_flashButton, SIGNAL(released()), this, SLOT(stretchChanged())); + + QHBoxLayout *layout = new QHBoxLayout(hbox); + layout->setMargin(0); + layout->addWidget(p_copyButton, Qt::AlignLeft); + layout->addWidget(p_globalButton, Qt::AlignLeft); + layout->addWidget(p_stretchRegionalButton, Qt::AlignLeft); + layout->addWidget(p_stretchBandComboBox, Qt::AlignLeft); + layout->addWidget(p_stretchMinEdit, Qt::AlignLeft); + layout->addWidget(p_stretchMaxEdit, Qt::AlignLeft); + layout->addWidget(advancedButton, Qt::AlignLeft); + layout->addWidget(p_flashButton, Qt::AlignLeft); + layout->addStretch(1); // Pushes everything else left in the menu bar + hbox->setLayout(layout); + + return hbox; + } + + + /** + * This updates the visible histograms in the advanced stretch, + * if present. + */ + void StretchTool::updateHistograms() + { + if (p_advancedStretch->isVisible()) + { + MdiCubeViewport *cvp = cubeViewport(); + + if (!cvp) return; + + if (cvp->isGray() && !cvp->grayBuffer()->working()) + { + if (p_advancedStretch->isRgbMode()) + { + updateTool(); + } + else + { + Isis::Histogram hist(histFromBuffer(cvp->grayBuffer())); + + if (hist.ValidPixels() > 0) + { + p_advancedStretch->updateHistogram(hist); + } + } + } + //Otherwise it is in color mode + else if (!cvp->isGray() && + !cvp->redBuffer()->working() && + !cvp->greenBuffer()->working() && + !cvp->blueBuffer()->working()) + { + if (!p_advancedStretch->isRgbMode()) + { + updateTool(); + } + else + { + Isis::Histogram redHist(histFromBuffer(cvp->redBuffer())); + Isis::Histogram grnHist(histFromBuffer(cvp->greenBuffer())); + Isis::Histogram bluHist(histFromBuffer(cvp->blueBuffer())); + + if (redHist.ValidPixels() > 0 && + grnHist.ValidPixels() > 0 && + bluHist.ValidPixels() > 0) + { + p_advancedStretch->updateHistograms(redHist, grnHist, bluHist); + } + } + } + } + } + + + /** + * This is called when the visible area changes. + */ + void StretchTool::screenPixelsChanged() + { + updateHistograms(); + } + + + /** + * This updates the advanced stretch to use the given viewport + * + * @param cvp + */ + void StretchTool::setCubeViewport(CubeViewport *cvp) + { + if (p_advancedStretch->isVisible()) + { + p_advancedStretch->enable(true); + + //If the viewport is in gray mode + if (cvp->isGray() && !cvp->grayBuffer()->working()) + { + Isis::Histogram hist(histFromBuffer(cvp->grayBuffer())); + Isis::Stretch stretch(cvp->grayStretch()); + + p_advancedStretch->enableGrayMode(stretch, hist); + } + //Otherwise it is in color mode + else if (!cvp->isGray() && + !cvp->redBuffer()->working() && + !cvp->greenBuffer()->working() && + !cvp->blueBuffer()->working()) + { + Isis::Histogram redHist(histFromBuffer(cvp->redBuffer())); + Isis::Histogram grnHist(histFromBuffer(cvp->greenBuffer())); + Isis::Histogram bluHist(histFromBuffer(cvp->blueBuffer())); + Isis::Stretch redStretch(cvp->redStretch()); + Isis::Stretch grnStretch(cvp->greenStretch()); + Isis::Stretch bluStretch(cvp->blueStretch()); + + p_advancedStretch->enableRgbMode(redStretch, redHist, + grnStretch, grnHist, + bluStretch, bluHist); + } + else + { + p_advancedStretch->enable(false); + } + } + else + { + p_advancedStretch->enable(false); + } + } + + + /** + * Updates the stretch tool. + * + */ + void StretchTool::updateTool() + { + CubeViewport *cvp = cubeViewport(); + + if (cvp == NULL) + { + //If the current viewport is NULL and the advanced dialog is visible, hide it + if (p_advancedStretch->isVisible()) + { + p_advancedStretch->hide(); + } + } + else + { + if (!p_advancedStretch->enabled() || + p_advancedStretch->isRgbMode() != !cvp->isGray()) + { + setCubeViewport(cvp); + } + } + + if (cvp && cvp->isGray()) + { + p_copyBands->setEnabled(true); + p_stretchBandComboBox->setShown(false); + } + else if (cvp) + { + p_copyBands->setEnabled(false); + p_stretchBandComboBox->setShown(true); + } + else + { + p_copyBands->setEnabled(false); + p_stretchBandComboBox->setShown(false); + } + + if (p_advancedStretch->isVisible()) + { + p_stretchMinEdit->setEnabled(false); + p_stretchMaxEdit->setEnabled(false); + } + else + { + p_stretchMinEdit->setEnabled(true); + p_stretchMaxEdit->setEnabled(true); + } + + updateHistograms(); + stretchChanged(); + } + + + /** + * The cube viewport requested a stretch at this time, give it + * to the viewport + * + * @param cvp + * @param bandId + */ + void StretchTool::stretchRequested(MdiCubeViewport *cvp, int bandId) + { + // Yeah this is a hack... but it's necessary to make this tool + // do anything while its not the active tool. + connect(cvp, SIGNAL(screenPixelsChanged()), this, SLOT(updateHistograms())); + + QRect rect(0, 0, cvp->viewport()->width(), cvp->viewport()->height()); + + if (bandId == (int)Gray) + { + if (cvp->grayBuffer() && cvp->grayBuffer()->hasEntireCube()) + { + Stretch newStretch = cvp->grayStretch(); + newStretch.CopyPairs(stretchBuffer(cvp->grayBuffer(), rect)); + cvp->stretchGray(newStretch); + } + else + { + Stretch newStretch = stretchBand(cvp, (StretchBand)bandId); + cvp->stretchGray(newStretch); + } + } + else if (bandId == (int)Red) + { + if (cvp->redBuffer() && cvp->redBuffer()->hasEntireCube()) + { + Stretch newStretch = cvp->redStretch(); + newStretch.CopyPairs(stretchBuffer(cvp->redBuffer(), rect)); + cvp->stretchRed(newStretch); + } + else + { + Stretch newStretch = stretchBand(cvp, (StretchBand)bandId); + cvp->stretchRed(newStretch); + } + } + else if (bandId == (int)Green) + { + if (cvp->greenBuffer() && cvp->greenBuffer()->hasEntireCube()) + { + Stretch newStretch = cvp->greenStretch(); + newStretch.CopyPairs(stretchBuffer(cvp->greenBuffer(), rect)); + cvp->stretchGreen(newStretch); + } + else + { + Stretch newStretch = stretchBand(cvp, (StretchBand)bandId); + cvp->stretchGreen(newStretch); + } + } + else if (bandId == (int)Blue) + { + if (cvp->blueBuffer() && cvp->blueBuffer()->hasEntireCube()) + { + Stretch newStretch = cvp->blueStretch(); + newStretch.CopyPairs(stretchBuffer(cvp->blueBuffer(), rect)); + cvp->stretchBlue(newStretch); + } + else + { + Stretch newStretch = stretchBand(cvp, (StretchBand)bandId); + cvp->stretchBlue(newStretch); + } + } + + stretchChanged(); + } + + + /** + * This method is called when the stretch has changed and sets the min/max + * text fields to the correct values. + * + */ + void StretchTool::stretchChanged() + { + MdiCubeViewport *cvp = cubeViewport(); + if (cvp == NULL) return; + + if (p_flashButton->isDown()) + { + if (!p_preGlobalStretches) + { + p_preGlobalStretches = new Stretch[4]; + p_preGlobalStretches[0] = cvp->grayStretch(); + p_preGlobalStretches[1] = cvp->redStretch(); + p_preGlobalStretches[2] = cvp->greenStretch(); + p_preGlobalStretches[3] = cvp->blueStretch(); + } + + cvp->stretchKnownGlobal(); + return; + } + else if (p_preGlobalStretches) + { + if (cvp->isGray()) + { + cvp->stretchGray(p_preGlobalStretches[0]); + } + else + { + cvp->stretchRed(p_preGlobalStretches[1]); + cvp->stretchGreen(p_preGlobalStretches[2]); + cvp->stretchBlue(p_preGlobalStretches[3]); + } + + delete [] p_preGlobalStretches; + p_preGlobalStretches = NULL; + } + + double min = 0, max = 0; + //If the viewport is in gray mode + if (cvp->isGray()) + { + //Get the min/max from the current stretch + Isis::Stretch stretch = cvp->grayStretch(); + min = stretch.Input(0); + max = stretch.Input(stretch.Pairs() - 1); + } + + //Otherwise it is in color mode + else + { + Isis::Stretch rstretch = cvp->redStretch(); + Isis::Stretch gstretch = cvp->greenStretch(); + Isis::Stretch bstretch = cvp->blueStretch(); + + //Get the min/max from the current stretch + if (p_stretchBand == Red) + { + min = rstretch.Input(0); + max = rstretch.Input(rstretch.Pairs() - 1); + } + else if (p_stretchBand == Green) + { + min = gstretch.Input(0); + max = gstretch.Input(gstretch.Pairs() - 1); + } + else if (p_stretchBand == Blue) + { + min = bstretch.Input(0); + max = bstretch.Input(bstretch.Pairs() - 1); + } + } + + //Set the min/max text fields + QString strMin; + strMin.setNum(min); + p_stretchMinEdit->setText(strMin); + + QString strMax; + strMax.setNum(max); + p_stretchMaxEdit->setText(strMax); + + if (p_advancedStretch->isVisible()) + { + p_advancedStretch->updateStretch(cvp); + } + } + + + /** + * This is called when one of the advanced stretches changed. + * Give the stretch to the viewport. + */ + void StretchTool::advancedStretchChanged() + { + CubeViewport *cvp = cubeViewport(); + if (cvp == NULL) return; + + if (!p_advancedStretch->isRgbMode()) + { + Stretch grayStretch = cvp->grayStretch(); + grayStretch.ClearPairs(); + grayStretch.CopyPairs(p_advancedStretch->getGrayStretch()); + cvp->stretchGray(grayStretch); + } + else + { + Stretch redStretch = cvp->redStretch(); + redStretch.ClearPairs(); + redStretch.CopyPairs(p_advancedStretch->getRedStretch()); + cvp->stretchRed(redStretch); + + Stretch grnStretch = cvp->greenStretch(); + grnStretch.ClearPairs(); + grnStretch.CopyPairs(p_advancedStretch->getGrnStretch()); + cvp->stretchGreen(grnStretch); + + Stretch bluStretch = cvp->blueStretch(); + bluStretch.ClearPairs(); + bluStretch.CopyPairs(p_advancedStretch->getBluStretch()); + cvp->stretchBlue(bluStretch); + } + + stretchChanged(); + } + + + /** + * This method is called when the stretch has changed and sets the min/max + * text fields to the correct values. + * + */ + void StretchTool::changeStretch() + { + MdiCubeViewport *cvp = cubeViewport(); + if (cvp == NULL) return; + + // Make sure the user didn't enter bad min/max and if so fix it + double min = p_stretchMinEdit->text().toDouble(); + double max = p_stretchMaxEdit->text().toDouble(); + + if (min >= max || p_stretchMinEdit->text() == "" || + p_stretchMaxEdit->text() == "") + { + updateTool(); + return; + } + + //The viewport is in gray mode + if (cvp->isGray()) + { + Isis::Stretch stretch = cvp->grayStretch(); + stretch.ClearPairs(); + stretch.AddPair(min, 0.0); + stretch.AddPair(max, 255.0); + + cvp->stretchGray(stretch); + } + //Otherwise the viewport is in color mode + else + { + Isis::Stretch redStretch = cvp->redStretch(); + Isis::Stretch greenStretch = cvp->greenStretch(); + Isis::Stretch blueStretch = cvp->blueStretch(); + + if (p_stretchBand == Red) + { + redStretch.ClearPairs(); + redStretch.AddPair(min, 0.0); + redStretch.AddPair(max, 255.0); + } + if (p_stretchBand == Green) + { + greenStretch.ClearPairs(); + greenStretch.AddPair(min, 0.0); + greenStretch.AddPair(max, 255.0); + } + if (p_stretchBand == Blue) + { + blueStretch.ClearPairs(); + blueStretch.AddPair(min, 0.0); + blueStretch.AddPair(max, 255.0); + } + + cvp->stretchRed(redStretch); + cvp->stretchGreen(greenStretch); + cvp->stretchBlue(blueStretch); + } + + stretchChanged(); + } + + + /** + * This methods shows and updates the advanced dialog. + * + */ + void StretchTool::showAdvancedDialog() + { + if (p_advancedStretch->isVisible()) return; + + if (cubeViewport()) + { + p_advancedStretch->updateStretch(cubeViewport()); + p_advancedStretch->show(); + } + + + updateTool(); + } + + + /** + * Does a global stretch for the active viewport. + * + */ + void StretchTool::stretchGlobal() + { + CubeViewport *cvp = cubeViewport(); + if (cvp == NULL) return; + + stretchGlobal(cvp); + } + + + /** + * This resets the stretch across all bands + */ + void StretchTool::stretchGlobalAllBands() + { + CubeViewport *cvp = cubeViewport(); + if (cvp == NULL) return; + + cvp->forgetStretches(); + stretchGlobal(cvp); + } + + + /** + * Does a global stretch for the specified viewport. + * + */ + void StretchTool::stretchGlobal(CubeViewport *cvp) + { + cvp->stretchKnownGlobal(); + stretchChanged(); + } + + + /** + * Does a global stretch for all the viewports. + * + */ + void StretchTool::stretchGlobalAllViewports() + { + for (int i = 0; i < (int)cubeViewportList()->size(); i++) + { + CubeViewport *cvp = cubeViewportList()->at(i); + + stretchGlobal(cvp); + } + } + + + /** + * Does a regional stretch for the active viewport. + * + */ + void StretchTool::stretchRegional() + { + CubeViewport *cvp = cubeViewport(); + if (cvp == NULL) return; + + stretchRegional(cvp); + } + + /** + * Does a regional stretch for the specified viewport. + * + */ + void StretchTool::stretchRegional(CubeViewport *cvp) + { + QRect rect(0, 0, cvp->viewport()->width(), cvp->viewport()->height()); + + Stretch newStretch = cvp->grayStretch(); + newStretch.ClearPairs(); + newStretch.CopyPairs(stretchBuffer(cvp->grayBuffer(), rect)); + cvp->stretchGray(newStretch); + stretchChanged(); + } + + + /** + * This method is called when the RubberBandTool is complete. It + * will get a rectangle from the RubberBandTool and stretch + * accordingly. + * + */ + void StretchTool::rubberBandComplete() + { + CubeViewport *cvp = cubeViewport(); + if (cvp == NULL) return; + if (!RubberBandTool::isValid()) return; + + QRect rubberBandRect = RubberBandTool::rectangle(); + //Return if the width or height is zero + if (rubberBandRect.width() == 0 || rubberBandRect.height() == 0) return; + + Stretch newStretch; + + if (cvp->isGray()) + { + newStretch = cvp->grayStretch(); + newStretch.ClearPairs(); + newStretch.CopyPairs(stretchBuffer(cvp->grayBuffer(), rubberBandRect)); + cvp->stretchGray(newStretch); + } + else + { + if (p_stretchBand == Red) + { + newStretch = cvp->redStretch(); + newStretch.ClearPairs(); + newStretch.CopyPairs(stretchBuffer(cvp->redBuffer(), rubberBandRect)); + cvp->stretchRed(newStretch); + } + else if (p_stretchBand == Green) + { + newStretch = cvp->greenStretch(); + newStretch.ClearPairs(); + newStretch.CopyPairs(stretchBuffer(cvp->greenBuffer(), rubberBandRect)); + cvp->stretchGreen(newStretch); + } + else if (p_stretchBand == Blue) + { + newStretch = cvp->blueStretch(); + newStretch.ClearPairs(); + newStretch.CopyPairs(stretchBuffer(cvp->blueBuffer(), rubberBandRect)); + cvp->stretchBlue(newStretch); + } + else + { + throw iException::Message(iException::Programmer, + "Unknown stretch band", _FILEINFO_); + } + } + + stretchChanged(); + } + + + /** + * This method will call a global stretch if the right mouse + * button is released. + * + * @param start + * @param s + */ + void StretchTool::mouseButtonRelease(QPoint start, Qt::MouseButton s) + { + CubeViewport *cvp = cubeViewport(); + if (cvp == NULL) return; + + // Call the parent Tool function to reset the Warning as different activity is + // taking place + Qisis::Tool::mouseButtonRelease(start, s); + + if (s == Qt::RightButton) + { + stretchGlobal(cvp); + + // Resets the RubberBandTool on screen. + enableRubberBandTool(); + } + } + + /** + * This method enables the RubberBandTool. + * + */ + void StretchTool::enableRubberBandTool() + { + RubberBandTool::enable(RubberBandTool::Rectangle); + } + + + /** + * Sets the stretch for all the bands in the active viewport to + * the current stretch + * + */ + void StretchTool::setStretchAcrossBands() + { + CubeViewport *cvp = cubeViewport(); + if (cvp == NULL) return; + + double min = p_stretchMinEdit->text().toDouble(); + double max = p_stretchMaxEdit->text().toDouble(); + + Isis::Stretch stretch = cvp->grayStretch(); + stretch.ClearPairs(); + stretch.AddPair(min, 0.0); + stretch.AddPair(max, 255.0); + + cvp->setAllBandStretches(stretch); + } + + + /** + * Sets the stretch for all the viewports to the current + * stretch in the active viewport. + * + */ + void StretchTool::setStretchAllViewports() + { + for (int i = 0; i < (int)cubeViewportList()->size(); i++) + { + CubeViewport *cvp = cubeViewportList()->at(i); + double min = p_stretchMinEdit->text().toDouble(); + double max = p_stretchMaxEdit->text().toDouble(); + + //The viewport is in gray mode + if (cvp->isGray()) + { + Isis::Stretch stretch = cvp->grayStretch(); + stretch.ClearPairs(); + stretch.AddPair(min, 0.0); + stretch.AddPair(max, 255.0); + cvp->stretchGray(stretch); + } + //Otherwise the viewport is in color mode + else + { + + Isis::Stretch greenStretch = cvp->greenStretch(); + Isis::Stretch blueStretch = cvp->blueStretch(); + + if (p_stretchBand == Red) + { + Isis::Stretch redStretch = cvp->redStretch(); + + redStretch.ClearPairs(); + redStretch.AddPair(min, 0.0); + redStretch.AddPair(max, 255.0); + + cvp->stretchRed(redStretch); + } + else if (p_stretchBand == Green) + { + Isis::Stretch greenStretch = cvp->redStretch(); + + greenStretch.ClearPairs(); + greenStretch.AddPair(min, 0.0); + greenStretch.AddPair(max, 255.0); + + cvp->stretchGreen(greenStretch); + } + else if (p_stretchBand == Blue) + { + Isis::Stretch blueStretch = cvp->blueStretch(); + + blueStretch.ClearPairs(); + blueStretch.AddPair(min, 0.0); + blueStretch.AddPair(max, 255.0); + + cvp->stretchBlue(blueStretch); + } + } + } + + stretchChanged(); + } + + + /** + * This method computes the stretch over a region using the viewport buffer. + * + * @param buffer + * @param rect + */ + Isis::Stretch StretchTool::stretchBuffer(ViewportBuffer *buffer, QRect rect) + { + //Get the statistics and histogram from the region + Isis::Statistics stats = statsFromBuffer(buffer, rect); + Isis::Stretch stretch; + + if (stats.ValidPixels() > 1 && + fabs(stats.Minimum() - stats.Maximum()) > DBL_EPSILON) + { + Isis::Histogram hist = histFromBuffer(buffer, rect, + stats.BestMinimum(), stats.BestMaximum()); + + if (fabs(hist.Percent(0.5) - hist.Percent(99.5)) > DBL_EPSILON) + { + stretch.AddPair(hist.Percent(0.5), 0.0); + stretch.AddPair(hist.Percent(99.5), 255.0); + } + } + + if (stretch.Pairs() == 0) + { + stretch.AddPair(-DBL_MAX, 0.0); + stretch.AddPair(DBL_MAX, 255.0); + } + + return stretch; + } + + + /** + * This method computes the stretch over the entire cube. + * + * @param cvp + * @param band Band to stretch + */ + Isis::Stretch StretchTool::stretchBand(CubeViewport *cvp, StretchBand band) + { + int bandNum = cvp->grayBand(); + Isis::Stretch stretch = cvp->grayStretch(); + + if (band == Red) + { + bandNum = cvp->redBand(); + stretch = cvp->redStretch(); + } + else if (band == Green) + { + bandNum = cvp->greenBand(); + stretch = cvp->greenStretch(); + } + else if (band == Blue) + { + bandNum = cvp->blueBand(); + stretch = cvp->blueStretch(); + } + + Isis::Statistics stats = statsFromCube(cvp->cube(), bandNum); + Isis::Histogram hist = histFromCube(cvp->cube(), bandNum, + stats.BestMinimum(), stats.BestMaximum()); + + stretch.ClearPairs(); + if (fabs(hist.Percent(0.5) - hist.Percent(99.5)) > DBL_EPSILON) + { + stretch.AddPair(hist.Percent(0.5), 0.0); + stretch.AddPair(hist.Percent(99.5), 255.0); + } + else + { + stretch.AddPair(-DBL_MAX, 0.0); + stretch.AddPair(DBL_MAX, 255.0); + } + + return stretch; + } + + /** + * This method will calculate and return the statistics for a given cube and + * band. + * + * @param cube + * @param band + * + * @return Isis::Statistics + */ + Isis::Statistics StretchTool::statsFromCube(Isis::Cube *cube, int band) + { + Isis::Statistics stats; + Isis::Brick brick(cube->Samples(), 1, 1, cube->PixelType()); + + for (int line = 0; line < cube->Lines(); line++) + { + brick.SetBasePosition(0, line, band); + cube->Read(brick); + stats.AddData(brick.DoubleBuffer(), cube->Samples()); + } + + return stats; + } + + + /** + * This method will calculate and return the statistics for a given region and + * viewport buffer. + * + * @param buffer + * @param rect + * + * @return Isis::Statistics + */ + Isis::Statistics StretchTool::statsFromBuffer(ViewportBuffer *buffer, + QRect rect) + { + if (buffer->working()) + { + throw iException::Message(iException::User, + "Cannot stretch while the cube is still loading", _FILEINFO_); + } + + QRect dataArea = QRect(buffer->bufferXYRect().intersected(rect)); + Isis::Statistics stats; + + for (int y = dataArea.top(); + !dataArea.isNull() && y <= dataArea.bottom(); + y++) + { + const std::vector &line = buffer->getLine(y - buffer->bufferXYRect().top()); + + for (int x = dataArea.left(); x < dataArea.right(); x++) + { + stats.AddData(line[x - buffer->bufferXYRect().left()]); + } + } + + return stats; + } + + /** + * This method will calculate and return the histogram for a given cube and + * band. + * + * @param cube + * @param band + * @param min + * @param max + * + * @return Isis::Histogram + */ + Isis::Histogram StretchTool::histFromCube(Isis::Cube *cube, int band, + double min, double max) + { + Isis::Histogram hist(min, max); + Isis::Brick brick(cube->Samples(), 1, 1, cube->PixelType()); + + for (int line = 0; line < cube->Lines(); line++) + { + brick.SetBasePosition(0, line, band); + cube->Read(brick); + hist.AddData(brick.DoubleBuffer(), cube->Samples()); + } + + return hist; + } + + + /** + * Given a viewport buffer, this calculates a histogram + * + * @param buffer + * + * @return Isis::Histogram + */ + Isis::Histogram StretchTool::histFromBuffer(ViewportBuffer *buffer) + { + Isis::Statistics stats = statsFromBuffer(buffer, buffer->bufferXYRect()); + return histFromBuffer(buffer, buffer->bufferXYRect(), + stats.BestMinimum(), stats.BestMaximum()); + + } + + + /** + * This method will calculate and return the histogram for a given region and + * viewport buffer. + * + * @param buffer + * @param rect + * @param min + * @param max + * + * @return Isis::Histogram + */ + Isis::Histogram StretchTool::histFromBuffer(ViewportBuffer *buffer, + QRect rect, double min, double max) + { + QRect dataArea = QRect(buffer->bufferXYRect().intersected(rect)); + + try + { + Isis::Histogram hist(min, max); + + for (int y = dataArea.top(); !dataArea.isNull() && y <= dataArea.bottom(); y++) + { + const std::vector &line = buffer->getLine(y - buffer->bufferXYRect().top()); + hist.AddData(&line.front() + (dataArea.left() - buffer->bufferXYRect().left()), dataArea.width()); + } + + return hist; + } + catch (Isis::iException &e) + { + // get the min and max DN values of the data area + Isis::iString sMin(min); + Isis::iString sMax(max); + std::string msg = "Insufficient data Min [" + sMin + "], Max [" + sMax + "]"; + msg += " in the stretch area."; + + // Emit signal to the parent tool to display Warning object with the warning message + //emit warningSignal(msg, e.Errors()); + + throw Isis::iException::Message(Isis::iException::None, msg, _FILEINFO_); + } + } + + + + /** + * The selected band for stretching changed. + */ + void StretchTool::stretchBandChanged(int) + { + p_stretchBand = (StretchBand) p_stretchBandComboBox->itemData( + p_stretchBandComboBox->currentIndex() + ).toInt(); + + stretchChanged(); + } + + + /** + * This method is called when the flash button is pressed on the advanced dialog + * and sets the viewport's stretch to the global stretch. + * + * + void StretchTool::flash() + { + CubeViewport *cvp = cubeViewport(); if(cvp != NULL) { + if(cvp->isGray()) { + p_viewportMap[cvp][cvp->grayBand()-1]->currentStretch = p_viewportMap[cvp][cvp->grayBand()-1]->stretch->stretch(); + } + else { + p_viewportMap[cvp][cvp->redBand()-1]->currentStretch = p_viewportMap[cvp][cvp->redBand()-1]->stretch->stretch(); + p_viewportMap[cvp][cvp->greenBand()-1]->currentStretch = p_viewportMap[cvp][cvp->greenBand()-1]->stretch->stretch(); + p_viewportMap[cvp][cvp->blueBand()-1]->currentStretch = p_viewportMap[cvp][cvp->blueBand()-1]->stretch->stretch(); + } + + //Update the stretch + stretchChanged(); + } + }*/ + + + /** + * This method will save the current stretch's stretch pairs to the specified + * file name. + * + * + void StretchTool::savePairsAs() + { + QString fn = QFileDialog::getSaveFileName((QWidget *)parent(), + "Choose filename to save under", + ".", + "Text Files (*.txt)"); + QString filename; + + //Make sure the filename is valid + if(!fn.isEmpty()) + { + if(!fn.endsWith(".txt")) + { + filename = fn + ".txt"; + } + else + { + filename = fn; + } + } + //The user cancelled, or the filename is empty + else + { + return; + } + + if(p_advancedStretch->isRgbMode()) + { + Filename redFilename(filename.toStdString()); + Filename grnFilename(filename.toStdString()); + Filename bluFilename(filename.toStdString()); + + redFilename.AddExtension("red"); + grnFilename.AddExtension("grn"); + bluFilename.AddExtension("blu"); + + QFile redFile(QString::fromStdString(redFilename.Expanded())); + QFile grnFile(QString::fromStdString(grnFilename.Expanded())); + QFile bluFile(QString::fromStdString(bluFilename.Expanded())); + bool success = redFile.open(QIODevice::WriteOnly) && + grnFile.open(QIODevice::WriteOnly) && + bluFile.open(QIODevice::WriteOnly); + if(!success) + { + QMessageBox::critical((QWidget *)parent(), + "Error", "Cannot open file, please check permissions"); + return; + } + + QTextStream redStream(&redFile); + QTextStream grnStream(&grnFile); + QTextStream bluStream(&bluFile); + + Isis::Stretch red = p_advancedStretch->getRedStretch(); + Isis::Stretch grn = p_advancedStretch->getGrnStretch(); + Isis::Stretch blu = p_advancedStretch->getBluStretch(); + + redStream << red.Text().c_str() << endl; + grnStream << grn.Text().c_str() << endl; + bluStream << blu.Text().c_str() << endl; + + redFile.close(); + grnFile.close(); + bluFile.close(); + } + else + { + QFile file; + bool success = file.open(QIODevice::WriteOnly); + if(!success) + { + QMessageBox::critical((QWidget *)parent(), + "Error", "Cannot open file, please check permissions"); + return; + } + + QTextStream stream(&file); + + Isis::Stretch stretch = p_advancedStretch->getGrayStretch(); + + //Add the pairs to the file + stream << stretch.Text().c_str() << endl; + + file.close(); + } + }*/ +} diff --git a/isis/src/qisis/objs/StretchTool/StretchTool.h b/isis/src/qisis/objs/StretchTool/StretchTool.h new file mode 100644 index 0000000000000000000000000000000000000000..36ca6421939df31263fa90e607d1a28e365a350a --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/StretchTool.h @@ -0,0 +1,185 @@ +#ifndef StretchTool_h +#define StretchTool_h + +// This is the only include allowed in this file! +#include "Tool.h" + + +class QComboBox; +class QPushButton; +class QLineEdit; +class QRect; +class QToolButton; + +namespace Isis +{ + class Cube; + class Histogram; + class Statistics; + class Stretch; +} + +/** + * @file + * $Revision: 1.16 $ + * $Date: 2010/06/30 03:45:09 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Qisis +{ + class CubeViewport; + class AdvancedStretchDialog; + class ViewportBuffer; + + /** + * @brief Stretch image edit tool + * + * This tool is part of the Qisis namespace and allows interactive editing + * of displayed images. + * + * @ingroup Visualization Tools + * + * @author + * + * @internal + * @history 2008-05-23 Noah Hilt - Added RubberBandTool + * @history 2010-03-18 Sharmila Prasad - Exception handling and emit warning signal + * to the Viewportwindow to display warning status on the status bar(Track Tool) + * @history 2010-04-08 Steven Lambright - Made to work with threaded + * viewportbuffer and also removed map to viewport stretches due to + * synchronization problems. + * @history 2010-04-08 Steven Lambright - Fixed access of + * viewport data for statistics + * @history 2010-05-20 Steven Lambright - Re-enabled the + * advanced stretch... without a viewport map! + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport + * - Fixed all include abuses + */ + class StretchTool : public Qisis::Tool + { + Q_OBJECT + + public: + StretchTool(QWidget *parent); + ~StretchTool(); + void addTo(QMenu *menu); + + /** + * Enum to store the bands. + */ + enum StretchBand + { + Gray, //!< Gray Band + Red, //!< Red Band + Green, //!< Green Band + Blue, //!< Blue Band + //All //!< All Bands + }; + + static Isis::Stretch stretchBuffer(ViewportBuffer *buffer, QRect rect); + static Isis::Stretch stretchBand(CubeViewport *cvp, StretchBand band); + + static Isis::Statistics statsFromCube(Isis::Cube *cube, int band); + static Isis::Statistics statsFromBuffer(ViewportBuffer *buffer, QRect rect); + static Isis::Histogram histFromCube(Isis::Cube *cube, int band, + double min, double max); + static Isis::Histogram histFromBuffer(ViewportBuffer *buffer); + static Isis::Histogram histFromBuffer(ViewportBuffer *buffer, QRect rect, + double min, double max); + + public slots: + void stretchGlobal(); + void stretchGlobal(CubeViewport *); + void stretchGlobalAllBands(); + void stretchGlobalAllViewports(); + void stretchRegional(); + void stretchRegional(CubeViewport *); + + protected: + /** + * This let's Tool know which Menu the actions this class has + * should be added to. Removal of this results in "Ctrl+R" and "Ctrl+G" + * not working. + * + * @return Name of the Menu + */ + QString menuName() const + { + return "&View"; + }; + QAction *toolPadAction(ToolPad *pad); + QWidget *createToolBarWidget(QStackedWidget *parent); + void updateTool(); + void stretchRequested(MdiCubeViewport *cvp, int bandId); + + protected slots: + void mouseButtonRelease(QPoint p, Qt::MouseButton s); + void enableRubberBandTool(); + void screenPixelsChanged(); + void updateHistograms(); + void rubberBandComplete(); + void setCubeViewport(CubeViewport *); + + private slots: + void stretchChanged(); + void advancedStretchChanged(); + void changeStretch(); + void showAdvancedDialog(); + void setStretchAcrossBands(); + void setStretchAllViewports(); + void stretchBandChanged(int); + + signals: + /** + * Shows a warning. This sends a signal (meant for when an + * exception occurs) to display the error using the warning + * object + * + * @param pStr + * @param pExStr + */ + void warningSignal(std::string &pStr, const std::string pExStr); + + private: + AdvancedStretchDialog *p_advancedStretch; //!< The advanced dialog + + QToolButton *p_copyButton; //!< Copy Button + QToolButton *p_globalButton; //!< Global Button + QToolButton *p_stretchRegionalButton; //!< Regional Stretch Button + QPushButton *p_flashButton; //!< Button to press for global stretch + + QAction *p_stretchGlobal; //!< Global stretch action + QAction *p_stretchRegional; //!< Regional stretch action + QAction *p_stretchManual; //!< Manual stretch action + QAction *p_copyBands; //!< Copy band stretch action + + QComboBox *p_stretchBandComboBox; //!< Stretch combo box + + QLineEdit *p_stretchMinEdit; //!< Min. line edit + QLineEdit *p_stretchMaxEdit; //!< Max. line edit + + StretchBand p_stretchBand; //!< Current stretch band + + //! Stretches before global button pressed + Isis::Stretch *p_preGlobalStretches; + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/StretchTool/StretchType.cpp b/isis/src/qisis/objs/StretchTool/StretchType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60e52c3f09eb2037b9a68f7625d9551d25be45bb --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/StretchType.cpp @@ -0,0 +1,181 @@ +#include "StretchType.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Stretch.h" +#include "Histogram.h" +#include "HistogramWidget.h" + +using namespace Isis; + +namespace Qisis { + /** + * This constructs a stretch type. It provides a main layout, + * sizing policies, and a few widgets. Children should insert + * themselves at the main layout grid row 1 column 0. + * + * @param hist + * @param stretch + * @param name + * @param color + */ + StretchType::StretchType(const Isis::Histogram &hist, + const Isis::Stretch &stretch, + const QString &name, const QColor &color) { + p_stretch = NULL; + p_table = NULL; + p_cubeHist = NULL; + p_graph = NULL; + p_mainLayout = NULL; + + p_cubeHist = new Histogram(hist); + + p_stretch = new Stretch(); + + p_graph = new HistogramWidget(QString("Visible ") + name + QString(" Hist"), + color.lighter(110), color.darker(110)); + p_graph->setHistogram(*p_cubeHist); + p_graph->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, + QSizePolicy::Minimum)); + p_graph->setMinimumSize(QSize(250, 200)); + + p_mainLayout = new QGridLayout(); + p_mainLayout->addWidget(p_graph, 0, 0); + + p_table = createStretchTable(); + connect(this, SIGNAL(stretchChanged()), this, SLOT(updateTable())); + p_mainLayout->addWidget(p_table, 2, 0); + + QPushButton *saveAsButton = new QPushButton("Save Stretch Pairs..."); + connect(saveAsButton, SIGNAL(clicked(bool)), this, SLOT(savePairs())); + p_mainLayout->addWidget(saveAsButton, 3, 0); + + QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + sizePolicy.setHeightForWidth(true); + p_graph->setSizePolicy(sizePolicy); + } + + + /** + * Destructor + */ + StretchType::~StretchType() { + if(p_cubeHist) { + delete p_cubeHist; + p_cubeHist = NULL; + } + + if(p_stretch) { + delete p_stretch; + p_stretch = NULL; + } + } + + + /** + * This should be called when the visible area changes. It + * updates the graph and calls setStretch() so that the children + * have a chance to update their GUI elements too. + * + * @param hist + */ + void StretchType::setHistogram(const Isis::Histogram &hist) { + p_graph->setHistogram(hist); + *p_cubeHist = hist; + setStretch(*p_stretch); + } + + + /** + * This creates the stretch pairs table. + * + * @return QTableWidget* + */ + QTableWidget *StretchType::createStretchTable() { + QTableWidget *table = new QTableWidget(0, 2); + + QStringList labels; + labels << "Input" << "Output"; + table->setHorizontalHeaderLabels(labels); + + table->horizontalHeader()->setResizeMode(QHeaderView::Stretch); + table->setEditTriggers(QAbstractItemView::NoEditTriggers); + table->setSelectionMode(QAbstractItemView::NoSelection); + + return table; + } + + + /** + * This updates the table with the current stretch pairs. + */ + void StretchType::updateTable() { + p_graph->setStretch(*p_stretch); + + Stretch stretch = getStretch(); + p_table->setRowCount(stretch.Pairs()); + + for(int i = 0; i < stretch.Pairs(); i++) { + QTableWidgetItem *inputItem = new QTableWidgetItem(QString("%1").arg( + stretch.Input(i))); + inputItem->setTextAlignment(Qt::AlignCenter); + QTableWidgetItem *outputItem = new QTableWidgetItem(QString("%1").arg( + stretch.Output(i))); + outputItem->setTextAlignment(Qt::AlignCenter); + + p_table->setItem(i, 0, inputItem); + p_table->setItem(i, 1, outputItem); + p_table->setMinimumSize(QSize(200, 100)); + } + } + + + /** + * This asks the user for a file and saves the current stretch + * pairs to that file. + */ + void StretchType::savePairs() { + QString filename = QFileDialog::getSaveFileName((QWidget *)parent(), + "Choose filename to save under", ".", "Text Files (*.txt)"); + if(filename.isEmpty()) return; + + QFile outfile(filename); + bool success = outfile.open(QIODevice::WriteOnly); + + if(!success) { + QMessageBox::critical((QWidget *)parent(), + "Error", "Cannot open file, please check permissions"); + return; + } + + QString currentText; + QTextStream stream(&outfile); + + Isis::Stretch stretch = getStretch(); + + //Add the pairs to the file + stream << stretch.Text().c_str() << endl; + + outfile.close(); + } + + + /** + * Returns the current stretch object + * + * @return Isis::Stretch + */ + Isis::Stretch StretchType::getStretch() { + return *p_stretch; + } +} diff --git a/isis/src/qisis/objs/StretchTool/StretchType.h b/isis/src/qisis/objs/StretchTool/StretchType.h new file mode 100644 index 0000000000000000000000000000000000000000..ee06155d32b60843fa05a831c85a82e0426f3b7a --- /dev/null +++ b/isis/src/qisis/objs/StretchTool/StretchType.h @@ -0,0 +1,63 @@ +#ifndef STRETCHTYPE_H +#define STRETCHTYPE_H + +#include + +namespace Isis { + class Stretch; + class Cube; + class Histogram; +} + +class QTableWidget; +class QGridLayout; + + +namespace Qisis { + class HistogramWidget; + + class StretchType : public QWidget { + Q_OBJECT + + public: + StretchType(const Isis::Histogram &hist, const Isis::Stretch &stretch, + const QString &name, const QColor &color); + + virtual ~StretchType(); + + virtual Isis::Stretch getStretch(); + /** + * Children must re-implement this to update their stretch pairs and GUI + * elements appropriately. This could be called with a + * different histogram but not a different stretch. + */ + virtual void setStretch(Isis::Stretch) = 0; + + virtual void setHistogram(const Isis::Histogram &); + + + protected: // methods + QTableWidget *createStretchTable(); + + + protected: // data + QGridLayout *p_mainLayout; //!< Main layout + Isis::Histogram *p_cubeHist; //!< Visible area histogram + QTableWidget *p_table; //!< Pairs table + Qisis::HistogramWidget *p_graph; //!< Histogram graph + Isis::Stretch *p_stretch; //!< Current stretch pairs stored here + + + signals: + //! Emitted when a new Stretch object is available + void stretchChanged(); + + + private slots: + void updateTable(); + void savePairs(); + }; +}; + + +#endif diff --git a/isis/src/qisis/objs/Tab/Makefile b/isis/src/qisis/objs/Tab/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/Tab/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/Tab/Tab.cpp b/isis/src/qisis/objs/Tab/Tab.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f69174369a64d82679db1eff035495e88fd1d1d --- /dev/null +++ b/isis/src/qisis/objs/Tab/Tab.cpp @@ -0,0 +1,120 @@ +#include "Tab.h" + +#include + +#include +#include + +using namespace Qisis; + + +//! constructs a Tab +Tab::Tab(QWidget * associatedWidget, QWidget * parent) : + QToolButton(parent) +{ + this->associatedWidget = NULL; + this->associatedWidget = associatedWidget; + + position = 0; + radioGroup = 0; + selectedStatus = false; + + connect(this, SIGNAL(clicked()), this, SLOT(handleTriggered())); +} + + +//! copy constructs a Tab +Tab::Tab(const Tab & other) +{ + associatedWidget = NULL; + + associatedWidget = other.associatedWidget; + position = other.position; + radioGroup = other.radioGroup; + selectedStatus = other.selectedStatus; +} + + +//! destructs a Tab +Tab::~Tab() +{ + associatedWidget = NULL; +} + + +//! set the position of the Tab within a TabBar +void Tab::setPosition(const int & newPosition) +{ + position = newPosition; +} + + +//! get the position of the Tab within a TabBar +const int & Tab::getPosition() const +{ + return position; +} + + +/** + * Tabs which share a radio group have the property that only only one Tab + * in the group can be selected at a time. + * + * @param newRadioGroup The new radio group to which the Tab should belong + */ +void Tab::setRadioGroup(const int & newRadioGroup) +{ + radioGroup = newRadioGroup; +} + + +/** + * Tabs which share a radio group have the property that only only one Tab + * in the group can be selected at a time. + * + * @returns The radio group which this Tab belongs to + */ +const int & Tab::getRadioGroup() const +{ + return radioGroup; +} + + +/** + * A selected Tab will look visually pressed and have its associatedWidget + * visible. A Tab which is not selected will look like a normal button and its + * associatedWidget will be hidden. + * + * @param newStatus True if the Tab should be selected, false otherwise + */ +void Tab::setSelected(bool newStatus) +{ + setDown(newStatus); + newStatus ? associatedWidget->show() : associatedWidget->hide(); + selectedStatus = newStatus; +} + + +/** + * A selected Tab will look visually pressed and have its associatedWidget + * visible. A Tab which is not selected will look like a normal button and its + * associatedWidget will be hidden. + * + * @returns True if the Tab is selected, false otherwise + */ +bool Tab::isSelected() +{ + return selectedStatus; +} + + +/** + * This SLOT is executed when the Tab is clicked, and emits its own clicked + * SIGNAL (which contains its index) to the TabBar. The TabBar can then + * use this index to determine which Tab was clicked (TabBars store their Tabs + * in a QVector). + */ +void Tab::handleTriggered() +{ + emit clicked(position); +} diff --git a/isis/src/qisis/objs/Tab/Tab.h b/isis/src/qisis/objs/Tab/Tab.h new file mode 100644 index 0000000000000000000000000000000000000000..759ef1009d86d33410e2943f15be5e834054579f --- /dev/null +++ b/isis/src/qisis/objs/Tab/Tab.h @@ -0,0 +1,91 @@ +#ifndef Tab_H +#define Tab_H + +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/05/07 20:39:19 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +// QToolButton is the parent of this class, and should be the ONLY include +// in this file. Do not add any other includes to this header file! +#include + +class QWidget; +class QPaintEvent; + +namespace Qisis +{ + /** + * A Tab is simply a QToolButton which shows or hides some other QWidget, + * which we call associatedWidget. The Tab does not own this widget, it + * just stores a pointer so that it can set the widget to be visible or + * invisible. Tabs are toggle buttons which stay down when clicked, and then + * come back up if clicked again. If a Tab is down then its associatedWidget + * is visible. If a Tab is up then its associatedWidget is invisible. Tabs + * are designed to be added to TabBars, which are special QToolBars that can + * handle the management and storing of Tabs. Tabs have a "radioGroup" to + * which they belong, which is just an int. Tabs in the same TabBar which + * have the same radioGroup number have the property such that only one of the + * Tabs can be selected at a time. Note that the radioGroup value is only + * used if the TabBar for which the Tab resides has a radioStyle() of true, + * which is false by default. See TabBar for more details about radioStyle. + * + * @author Eric Hyer + * + * @internal + * @history 2010-05-06 Eric Hyer - Original Version + */ + class Tab : public QToolButton + { + Q_OBJECT + + public: + Tab(QWidget * associatedWidget, QWidget * parent = 0); + Tab(const Tab & other); + + virtual ~Tab(); + + void setPosition(const int & newPosition); + const int & getPosition() const; + void setRadioGroup(const int & newRadioGroup); + const int & getRadioGroup() const; + void setSelected(bool newStatus); + bool isSelected(); + + + signals: + void clicked(const int &); + + + private slots: + void handleTriggered(); + + + private: + QWidget * associatedWidget; + int position; + int radioGroup; + int location; + bool selectedStatus; + }; +} + +#endif diff --git a/isis/src/qisis/objs/TabBar/Makefile b/isis/src/qisis/objs/TabBar/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/TabBar/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/TabBar/TabBar.cpp b/isis/src/qisis/objs/TabBar/TabBar.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9ec61537c44feb8ca23a58bbe8d9f106cd6191f --- /dev/null +++ b/isis/src/qisis/objs/TabBar/TabBar.cpp @@ -0,0 +1,219 @@ +#include "TabBar.h" + +#include +//#include + +#include + +#include "Tab.h" + + +using namespace Qisis; + + +/** + * construct a TabBar + * + * @param useDefaultViewSettings If true then the initial state of the Tabs in + * the TabBar will be such that the first Tab is + * selected and that all other Tabs are not + * selected. If false then all Tabs will start + * out not selected, leaving it up to you to + * select the ones you want to be selected for the + * initial setup (usually done when reading + * QSettings at program startup). This is usefull + * to have set to true if it is the first time + * your program is being ran and there are no + * QSettings available. + * + * @param parent Optionally specify the parent of this TabBar + */ +TabBar::TabBar(const bool & useDefaultViewSettings, + QWidget * parent) : QToolBar(parent) +{ + tabs = NULL; + + tabs = new QVector< Tab * >(); + radioStyleTabs = false; + useDefaults = useDefaultViewSettings; +} + + +//! destruct a TabBar +TabBar::~TabBar() +{ + if (tabs) + { + delete tabs; + tabs = NULL; + } +} + + +/** + * Adds a Tab to the TabBar. Note that The TabBar takes ownership of the Tabs + * once they are added! + * + * @param newTab New Tab to be added + */ +void TabBar::addTab(Tab * newTab) +{ + const int & tabCountBeforeAddition = tabs->size(); + newTab->setPosition(tabCountBeforeAddition); + connect(newTab, SIGNAL(clicked(const int &)), this, + SLOT(tabClicked(const int &))); + tabs->push_back(newTab); + + if (useDefaults) + newTab->setSelected(!tabCountBeforeAddition); + else + newTab->setSelected(false); + + addWidget(newTab); +} + + +/** + * If set to true then the effect is that Tabs in the same radio group can only + * be selected one at a time. When a Tab is selected all other Tabs in the same + * radio group would automatically be deselected. If set to false then all Tabs + * in the TabBar will behave independent from eachother regardless of how their + * radio groups are set. + * + * @param radioStyle True if radio style should be used, false otherwise + */ +void TabBar::setRadioStyle(const bool & radioStyle) +{ + radioStyleTabs = radioStyle; +} + + +/** + * @returns The current radio style being used + */ +bool TabBar::radioStyle() +{ + return radioStyleTabs; +} + + +/** + * @returns The number of Tabs currently in the TabBar + */ +const int TabBar::size() const { return tabs->size(); } + + +/** + * Sets whether the Tab at the specified index is selected or not + * + * @param index Index of the Tab. The first Tab added to the bar has an index + * of 0. The last Tab added has an index of size() - 1 + * + * @param status True if the Tab should be selected, false otherwise + */ +void TabBar::setSelected(const int & index, const bool & status) +{ + if (index >= 0 && index < tabs->size()) + (*tabs)[index]->setSelected(status); +} + + +/** + * @param index Index of the Tab. The first Tab added to the bar has an index + * of 0. The last Tab added has an index of size() - 1. + * + * @returns True if the Tab at the given index is selected, false otherwise + */ +bool TabBar::isSelected(const int & index) +{ + if (index >= 0 && index < tabs->size() && (*tabs)[index]->isSelected()) + return true; + + return false; +} + + +/** + * @returns True if no Tabs are currently selected, false otherwise + */ +bool TabBar::noneSelected() +{ + for (int i = 0; i < tabs->size(); i++) + if ((*tabs)[i]->isSelected()) + return false; + + return true; +} + + +/** + * SLOT which performs actions that need to be done when we get a SIGNAL from + * a Tab telling us that it has been clicked. What happens is that first the + * Tab is clicked. The Tab catches this signal and then emits its own clicked + * SIGNAL which contains its index. This SIGNAL is connected to this SLOT which + * then takes the appropriate action depending on a couple things. If + * radioStyle is not being used or if it is but there are no other Tabs in this + * Tab's radio group then we simply want to toggle the state of the Tab. If + * radio style is being used and there are others in this Tab's radio group + * which are selected then the other Tabs are first deselected before the Tab + * is set to be selected (We know it was not selected before since there was + * another Tab in its group which was). + * + * @param index Index of the Tab which emitted the clicked SIGNAL. + */ +void TabBar::tabClicked(const int & index) +{ + if (!radioStyleTabs || noOthersInGrpSelected(index)) + { + (*tabs)[index]->setSelected(!(*tabs)[index]->isSelected()); + } + else + { + deselectOthersInGrp(index); + (*tabs)[index]->setSelected(true); + } +} + + +/** + * @param index Index of the Tab. The first Tab added to the bar has an index + * of 0. The last Tab added has an index of size() - 1. + * + * @returns True if there are no other Tabs in the given Tab's radio group which + * are selected, false otherwise. + */ +bool TabBar::noOthersInGrpSelected(const int & index) const +{ + const int & thisGrp = tabs->at(index)->getRadioGroup(); + for (int i = 0; i < tabs->size(); i++) + { + if (index != i) + { + const int & otherGrp = tabs->at(i)->getRadioGroup(); + if (otherGrp == thisGrp && tabs->at(i)->isSelected()) + return false; + } + } + return true; +} + + +/** + * @param index Index of the Tab. The first Tab added to the bar has an index + * of 0. The last Tab added has an index of size() - 1. + * + * Deselects any other selected Tabs in the given Tab's radio group + */ +void TabBar::deselectOthersInGrp(const int & index) +{ + const int & thisGrp = tabs->at(index)->getRadioGroup(); + for (int i = 0; i < tabs->size(); i++) + { + if (index != i) + { + const int & otherGrp = tabs->at(i)->getRadioGroup(); + if (otherGrp == thisGrp) + (*tabs)[i]->setSelected(false); + } + } +} diff --git a/isis/src/qisis/objs/TabBar/TabBar.h b/isis/src/qisis/objs/TabBar/TabBar.h new file mode 100644 index 0000000000000000000000000000000000000000..31b0c7bf6bd3b00d9c01386015cd692abde1b8b1 --- /dev/null +++ b/isis/src/qisis/objs/TabBar/TabBar.h @@ -0,0 +1,87 @@ +#ifndef TabBar_H +#define TabBar_H + +/** + * @file + * $Revision: 1.2 $ + * $Date: 2010/06/04 03:20:32 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +// QToolBar is the parent of this class, and should be the ONLY include +// in this file. Do not add any other includes to this header file! +#include + +class QWidget; +template< class A > class QVector; + + +namespace Qisis +{ + class Tab; + + /** + * A TabBar is a QToolBar which is specifically designed to store and manage + * Tabs, which are specialized QToolButtons that can hide and show other + * QWidgets (see Tab). + * + * @author Eric Hyer + * + * @see Tab + * + * @internal + * @history 2010-05-07 Eric Hyer - Original Version + * @history 2010-06-03 Eric Hyer - Added noneSelected method + */ + class TabBar : public QToolBar + { + Q_OBJECT + + public: + TabBar(const bool & useDefaultViewSettings = false, QWidget * parent = 0); + virtual ~TabBar(); + + virtual void addTab(Tab * newTab); + const int curSelectedTab() const; + void setRadioStyle(const bool & radioStyle); + bool radioStyle(); + const int size() const; + + void setSelected(const int & index, const bool & status); + bool isSelected(const int & index); + bool noneSelected(); + + + private slots: + void tabClicked(const int & index); + + + private: // functions + bool noOthersInGrpSelected(const int & index) const; + void deselectOthersInGrp(const int & index); + + + private: // data + QVector< Tab * > * tabs; + bool radioStyleTabs; + bool useDefaults; + }; +} + +#endif diff --git a/isis/src/qisis/objs/TableMainWindow/Makefile b/isis/src/qisis/objs/TableMainWindow/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/TableMainWindow/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/TableMainWindow/TableMainWindow.cpp b/isis/src/qisis/objs/TableMainWindow/TableMainWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..17371b85d97e7cd6794ea2228aa48699aaf3c259 --- /dev/null +++ b/isis/src/qisis/objs/TableMainWindow/TableMainWindow.cpp @@ -0,0 +1,852 @@ +#include +#include +#include +#include +#include +#include "TableMainWindow.h" + +namespace Qisis { + /** + * Constructs a new TableMainWindow object + * + * @param title + * @param parent + */ + TableMainWindow::TableMainWindow (QString title, QWidget *parent) : Qisis::MainWindow(title, parent) { + p_parent = parent; + connect(p_parent,SIGNAL(closeWindow()),this,SLOT(writeSettings())); + p_title = title; + p_table = NULL; + p_visibleColumns = -1; + p_currentRow = 0; + p_currentIndex = 0; + createTable(); + readSettings(); + } + + + /** + * This creates the table main window. The table and docking + * area are created here. It also adds the two default menus to + * the menu bar. Programmers can add more menus to the menu bar + * once an instance of this class is established. + */ + void TableMainWindow::createTable() { + #if defined(__APPLE__) + setWindowFlags(Qt::Tool); + #endif + + #if !defined(__APPLE__) + setWindowFlags(Qt::Dialog); + #endif + + statusBar()->setSizeGripEnabled(true); + // Create the table widget + p_table = new QTableWidget(this); + p_table->setAlternatingRowColors(true); + setCentralWidget(p_table); + + // Create the dock area + p_dock = new QDockWidget("Columns",this); + p_dock->setObjectName("dock"); + p_dock->setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea); + p_dock->setMinimumWidth(190); + p_listWidget = new QListWidget(p_dock); + p_dock->setWidget(p_listWidget); + addDockWidget(Qt::LeftDockWidgetArea,p_dock,Qt::Vertical); + connect(p_listWidget,SIGNAL(itemChanged(QListWidgetItem *)), + this,SLOT(syncColumns())); + + // Create the file menu + QMenuBar *menuBar = this->menuBar(); + QMenu *fileMenu = menuBar->addMenu("&File"); + + p_save = new QAction(this); + p_save->setText("Save..."); + p_save->setShortcut(Qt::CTRL + Qt::Key_S); + connect(p_save,SIGNAL(activated()),this,SLOT(saveTable())); + p_save->setDisabled(true); + + QAction *saveas = new QAction(this); + saveas->setText("Save As..."); + connect(saveas,SIGNAL(activated()),this,SLOT(saveAsTable())); + + QAction *load = new QAction(this); + load->setText("Load..."); + connect(load,SIGNAL(activated()),this,SLOT(loadTable())); + + QAction *del = new QAction(this); + del->setText("Delete Selected Row(s)"); + del->setShortcut(Qt::Key_Delete); + connect(del,SIGNAL(activated()),this,SLOT(deleteRows())); + + QAction *clear = new QAction(this); + clear->setText("Clear table"); + connect(clear,SIGNAL(activated()),this,SLOT(clearTable())); + + QAction *close = new QAction(this); + close->setText("Close"); + connect(close,SIGNAL(activated()),this,SLOT(hide())); + + fileMenu->addAction(p_save); + fileMenu->addAction(saveas); + fileMenu->addAction(load); + fileMenu->addAction(del); + fileMenu->addAction(clear); + fileMenu->addAction(close); + + //2009-01-12 + //If we have the Mainwindow flag set to Qt::Tool so that on Macs the + //table window always stays on top, then we can not access the + //menu bar to the table window, so we need to add the file options + //for the table to the tool bar. + #if defined(__APPLE__) + QToolBar *toolBar = new QToolBar(); + toolBar->addAction(p_save); + toolBar->addAction(saveas); + toolBar->addAction(load); + toolBar->addAction(del); + toolBar->addAction(clear); + toolBar->addAction(close); + this->addToolBar(toolBar); + #endif + + // Create the view menu + QMenu *viewMenu = menuBar->addMenu("&View"); + QAction *cols = new QAction(this); + cols->setText("Columns"); + connect(cols,SIGNAL(activated()),p_dock,SLOT(show())); + viewMenu->addAction(cols); + + this->setMenuBar(menuBar); + installEventFilter(this); + } + + + /** + * sets the status message in the lower lefthand corner of the + * window. + * + * @param message + */ + void TableMainWindow::setStatusMessage(QString message){ + this->statusBar()->showMessage(message); + } + + + /** + * + * Adds a new column to the table when a new curve is added to the plot. Also + * adds the item to the dock area. + * + * @param setOn + * @param heading + * @param menuText + * @param insertAt + * @param o + * @param toolTip + */ + void TableMainWindow::addToTable (bool setOn, const QString &heading, + const QString &menuText, int insertAt, + Qt::Orientation o, QString toolTip) { + // Insert the new column + int startCol = p_table->columnCount(); + + for (int i=0; !heading.section(":",i,i).isEmpty(); i++) { + QString htext = heading.section(":",i,i); + + //if (!htext.contains("\n")) htext = "\n" + htext; + if(insertAt >= 0) { + p_table->insertColumn(insertAt); + int width = p_settings->value("Col" + QString::number(insertAt), 100).toInt(); + p_table->setColumnWidth(insertAt, width); + } else{ + p_table->insertColumn(startCol+i); + int width = p_settings->value("Col" + QString::number(startCol+i), 100).toInt(); + p_table->setColumnWidth(startCol+i, width); + } + QTableWidgetItem *header = new QTableWidgetItem(htext); + if(insertAt >= 0) { + + if(o == Qt::Horizontal) { + p_table->setHorizontalHeaderItem(insertAt,header); + } else{ + p_table->setVerticalHeaderItem(insertAt,header); + } + }else{ + + if(o == Qt::Horizontal) { + p_table->setHorizontalHeaderItem(startCol+i,header); + }else{ + p_table->setVerticalHeaderItem(startCol+i,header); + } + } + + } + + int endCol = p_table->columnCount() - 1; + + // Insert the column name into the columns dock area + if (!menuText.isEmpty()) { + QListWidgetItem *item = new QListWidgetItem(); + + item->setText(menuText); + if(toolTip.isEmpty()) { + item->setToolTip(heading); + } + else { + item->setToolTip(toolTip); + } + + if(insertAt >=0) { + p_listWidget->insertItem(insertAt, item); + }else{ + p_listWidget->insertItem(endCol, item); + } + + item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); + + if(p_trackItems) { + readItemSettings(menuText, item); + } else{ + item->setCheckState(setOn?Qt::Checked:Qt::Unchecked); + } + + p_itemList.push_back(item); + p_startColumn.push_back(startCol); + p_endColumn.push_back(endCol); + } + } + + + /** + * This method hides and shows the columns according to which + * items the user has selected to be view-able on the left hand + * side list. (dock area) + */ + void TableMainWindow::syncColumns() { + if (this->isHidden()) { return; } + + p_visibleColumns = 0; + for (int i=0; icount(); i++) { + QListWidgetItem *item = p_listWidget->item(i); + int index = p_itemList.indexOf(item); + + if (index != -1) { + + for (int col = p_startColumn[index]; col <= p_endColumn[index]; col++) { + + if (item->checkState() == Qt::Checked) { + p_table->setColumnHidden(col,false); + p_visibleColumns++; + } + else { + p_table->setColumnHidden(col,true); + } + + } + } + } + } + + + /** + * Use this method to sync the table with the dock widget list + * if the table orientation is horizontal. + * + */ + void TableMainWindow::syncRows() { + if (this->isHidden()) return; + + p_visibleColumns = 0; + for (int i=0; icount(); i++) { + QListWidgetItem *item = p_listWidget->item(i); + int index = p_itemList.indexOf(item); + + if (index != -1) { + + for (int col=p_startColumn[index]; col<=p_endColumn[index]; col++) { + + if (item->checkState() == Qt::Checked) { + p_table->setRowHidden(col,false); + p_visibleColumns++; + } + else { + p_table->setRowHidden(col,true); + } + + } + } + } + } + + + /** + * This method deletes a column from the table + * + * @param item + */ + void TableMainWindow::deleteColumn(int item){ + if(p_table == NULL) { std::cout << "deleteColumn err" << std::endl; return; } + p_itemList.removeAt(item); + p_table->setColumnCount(p_table->columnCount() -1); + p_itemList.clear(); + bool vis = p_table->isVisible(); + p_table = NULL; + p_listWidget = NULL; + this->close(); + + if(vis) showTable(); + + } + + + /** + * This method checks to see if the table has been created. If + * not it calls the createTable method before calling show. + * + */ + void TableMainWindow::showTable(){ + syncColumns(); + if(p_table == NULL) createTable(); + this->show(); + } + + + /** + * This method clears all items from each row and column. + * + */ + void TableMainWindow::clearTable () { + if(p_table->rowCount() == 0) return; + for (int r=0; rrowCount(); r++) { + for (int c=0; ccolumnCount(); c++) { + p_table->item(r,c)->setText(""); + } + } + + p_table->scrollToItem(p_table->item(0,0),QAbstractItemView::PositionAtTop); + p_currentRow = 0; + p_currentIndex = 0; + } + + + /** + * This method is called when the user selects a row or rows + * uses the delete button or selects the delete row menu item + * from the file menu. + * + */ + void TableMainWindow::deleteRows () { + QList list = p_table->selectedItems(); + QList selectedRows; + + for(int i = 0; i < list.size(); i++) { + if(selectedRows.size() == 0) { + selectedRows.push_back(p_table->row(list[i])); + } else if(!selectedRows.contains(p_table->row(list[i]))){ + selectedRows.push_back(p_table->row(list[i])); + } + } + + qSort(selectedRows.begin(), selectedRows.end()); + for(int d = selectedRows.size(); d > 0; d--) { + p_table->removeRow(selectedRows[d-1]); + } + + // get the number of rows that are filled in + int filledRows = 0; + for(int r = 0; r < p_table->rowCount(); r++ ) { + for(int c =0; c < p_table->columnCount(); c++) { + if(!p_table->item(r,c) || p_table->item(r,c)->text() != "") { + filledRows++; + break; + } + } + } + + p_currentRow = filledRows; + } + + + /** + * This method clears the text of the given row. + * + * @param row + */ + void TableMainWindow::clearRow (int row){ + if(!this->isVisible()) return; + + for (int c=0; ccolumnCount(); c++) { + p_table->item(row,c)->setText(""); + } + } + + /** + * This method will select a file, set it as the current file and save the + * table. + * + */ + void TableMainWindow::saveAsTable() { + QString fn = QFileDialog::getSaveFileName((QWidget*)parent(), + "Choose filename to save under", + ".", + "Text Files (*.txt)"); + QString filename; + + //Make sure the filename is valid + if (!fn.isEmpty()) { + if(!fn.endsWith(".txt")) { + filename = fn + ".txt"; + } else { + filename = fn; + } + } + //The user cancelled, or the filename is empty + else { + return; + } + + p_currentFile.setFileName( filename ); + + p_save->setEnabled(true); + saveTable(); + } + + /** + * This method allows the user to save the data from the + * table to the current file. + */ + void TableMainWindow::saveTable () { + if(p_currentFile.fileName().isEmpty()) return; + + //if(p_currentFile.exists()) p_currentFile.remove(); + bool success = p_currentFile.open(QIODevice::WriteOnly); + if(!success) { + QMessageBox::critical((QWidget *)parent(), + "Error", "Cannot open file, please check permissions"); + p_currentFile.setFileName(""); + p_save->setDisabled(true); + return; + } + + QString currentText; + QTextStream t( &p_currentFile ); + QString line = ""; + bool first = true; + + //Write each column's header to the first line in CSV format + for (int i = 0; i < p_table->columnCount(); i++) { + if (!p_table->isColumnHidden(i)) { + QTableWidgetItem *header = p_table->horizontalHeaderItem(i); + QString temp = header->text(); + temp.replace("\n"," "); + if(first) { + line = line + "\"" + temp + "\""; + first = false; + } else { + line = line + ",\"" + temp + "\""; + } + } + } + //Add the headers to the file + t << line << endl; + + //Add each row to the file + for (int i=0; i < p_table->rowCount(); i++) { + bool first = true; + line = ""; + + //Add each column to the line + for (int j=0; jcolumnCount(); j++) { + + if (!p_table->isColumnHidden(j)) { + if(p_table->item(i,j) == 0) break; + currentText = p_table->item(i,j)->text(); + + if (first) { + line = line + currentText; + first = false; + } + else { + line = line + "," + currentText; + } + } + } + //If the line is not empty, add it to the file + if (line.split(",", QString::SkipEmptyParts).count() != 0) + t << line << endl; + } + p_currentFile.close(); + this->setWindowTitle(p_title + " : " + p_currentFile.fileName()); + } + + + /** + * This overriden method is called from the constructor so that + * when the Tablemainwindow is created, it know's it's size + * and location and the dock widget settings. + * + */ + void TableMainWindow::readSettings(){ + //Call the base class function to read the size and location + this->MainWindow::readSettings(); + + //Now read the settings that are specific to this window. + std::string appName = p_parent->windowTitle().toStdString(); + + //Now read the settings that are specific to this window. + std::string instanceName = this->windowTitle().toStdString(); + + Isis::Filename config("$HOME/.Isis/" + appName + "/" + instanceName + ".config"); + //if(p_settings != 0) delete p_settings; + p_settings = new QSettings(QString::fromStdString(config.Expanded()), QSettings::NativeFormat); + bool docFloats = p_settings->value("docFloat", false).toBool(); + p_dock->setFloating(docFloats); + + if(docFloats) { + QPoint docPos = p_settings->value("docPos", QPoint(300, 100)).toPoint(); + QSize docSize = p_settings->value("docSize", QSize(300, 200)).toSize(); + p_dock->resize(docSize); + p_dock->move(docPos); + p_dock->setFocus(); + p_dock->setVisible(true); + } + + } + + + /** + * This method reads the 'checked' settings on the items listed + * in the dock area which determine which table columns are + * visible. This method is only called if p_trackItems is set + * to true. + * + * @param heading + * @param item + */ + void TableMainWindow::readItemSettings(QString heading, QListWidgetItem *item ){ + //Now read the settings that are specific to this window. + std::string appName = p_parent->windowTitle().toStdString(); + + //Now read the settings that are specific to this window. + std::string instanceName = this->windowTitle().toStdString(); + + Isis::Filename config("$HOME/.Isis/" + appName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()), QSettings::NativeFormat); + + QString itemTitle = "item-" + item->text(); + Qt::CheckState state = (Qt::CheckState)settings.value(itemTitle, 0).toInt(); + item->setCheckState(state); + + } + + + /** + * This overriden method is called when the Tablemainwindow + * is closed or hidden to write the size and location settings + * (and dock widget settings) to a config file in the user's + * home directory. + * + */ + void TableMainWindow::writeSettings(){ + /*Call the base class function to write the size and location*/ + this->MainWindow::writeSettings(); + //if(!this->isVisible()) return; + + /*Now read the settings that are specific to this window.*/ + std::string appName = p_parent->windowTitle().toStdString(); + + /*Now read the settings that are specific to this window.*/ + std::string instanceName = this->windowTitle().toStdString(); + + Isis::Filename config("$HOME/.Isis/" + appName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()), QSettings::NativeFormat); + + settings.setValue("docFloat", p_dock->isFloating()); + settings.setValue("docPos", p_dock->pos()); + settings.setValue("docSize", p_dock->size()); + + /*Save the column width for the table*/ + for (int c = 0; c < p_table->columnCount(); c++) { + QString colWidth = "Col" + QString::number(c); + int width = 0; + + if(p_table->columnWidth(c) == 0) { + width = 100; + }else { + width = p_table->columnWidth(c); + } + settings.setValue(colWidth , width); + + } + + /*This writes the settings for the 'checked' property for the list items + in the dock area which determines which columns are visible.*/ + + if(p_trackItems) { + for(int i = 0; itext(); + settings.setValue(itemTitle, p_itemList[i]->checkState()); + } + } + } + + + /** + * This method loads a text file into the table. + * + */ + void TableMainWindow::loadTable () { + QString fn = QFileDialog::getOpenFileName((QWidget*)parent(), + "Select file to load", + ".", + "Text Files (*.txt)"); + + //If the user cancelled or the filename is empty return + if (fn.isEmpty()) return; + + p_currentFile.setFileName( fn ); + p_save->setEnabled(true); + + bool success = p_currentFile.open(QIODevice::ReadOnly); + if(!success) { + QMessageBox::critical((QWidget *)parent(), + "Error", "Cannot open file, please check permissions"); + p_currentFile.setFileName(""); + p_save->setDisabled(true); + return; + } + + clearTable(); + + QList column = QList(); + + //Set all headers to be hidden + for (int i=0; i < p_listWidget->count() ; i++) { + p_listWidget->item(i)->setCheckState(Qt::Unchecked); + } + + // Strip headers off the table into the temp string + QString temp = p_currentFile.readLine(); + temp.remove("Positive "); + temp.remove("\""); + temp.remove("\n"); + QStringList list = temp.split(","); + + // Loop through checking header names and setting relevant columns visible + for (int i = 0; i < list.count(); i++) { + for(int j = 0; j < p_itemList.size(); j++){ + + //Special cases + if(p_itemList[j]->text() == "Ground Range" && (list[i] == "Start Latitude" || list[i] == "Start Longitude" || + list[i] == "End Latitude" || list[i] == "End Longitude")) { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "Pixel Range" && (list[i] == "Start Sample" || list[i] == "Start Line" || + list[i] == "End Sample" || list[i] == "End Line")) { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "Pixel Range" && (list[i] == "Sample" || list[i] == "Line")) { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "Sample:Line" && (list[i] == "Sample" || list[i] == "Line")) { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "Planetocentric Lat" && list[i] == "Planetocentric Latitude") { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "Planetographic Lat" && list[i] == "Planetographic Latitude") { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "Projected X:Projected Y" && (list[i] == "Projected X" || list[i] == "Projected Y")) { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "Radius" && list[i] == "Local Radius") { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "XYZ" && (list[i] == "Point X" || list[i] == "Point Y" || list[i] == "Point Z")) { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "Ra:Dec" && (list[i] == "Right Ascension" || list[i] == "Declination")) { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "Spacecraft Position" && (list[i] == "Spacecraft X" || list[i] == "Spacecraft Y" || list[i] == "Spacecraft Z")) { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "Ephemeris iTime" && list[i] == "Ephemeris Time") { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "Local Solar iTime" && list[i] == "Local Solar Time") { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + if(p_itemList[j]->text() == "Segments Sum" && list[i] == "Segments Sum km") { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + //End special cases + + + if(p_itemList[j]->text() == list[i]) { + p_itemList[j]->setCheckState(Qt::Checked); + break; + } + } + + // Loop through column headers to try to find a match + bool match = false; + for (int cols=0; cols < p_table->columnCount(); cols++) { + QString header = p_table->horizontalHeaderItem(cols)->text(); + + header.remove("Positive"); + header.remove("\n"); + header.remove(" "); + + list[i].remove(" "); + + if(header == list[i]) { + column.push_back(cols); + match = true; + break; + + } + } + if (!match) column.push_back(-1); + } + + // Read data into table + QString str = p_currentFile.readLine(); + + while (str.count() != 0) { + // Do we need more rows? + if (p_currentRow+1 > p_table->rowCount()) { + p_table->insertRow(p_currentRow); + for (int c=0; ccolumnCount(); c++) { + QTableWidgetItem *item = new QTableWidgetItem(""); + p_table->setItem(p_currentRow,c,item); + if (c == 0) p_table->scrollToItem(item); + } + } + + str.remove("\n"); + + QStringList list = str.split(","); + + for (int i=0; i < column.size(); i++) { + QTableWidgetItem *newItem = new QTableWidgetItem(list[i]); + if (column[i] != -1) { + p_table->setItem(p_currentRow, column[i], newItem); + } + } + p_currentRow++; + p_currentIndex++; + + + str = p_currentFile.readLine(); + } + + p_currentFile.close(); + this->setWindowTitle(p_title + " : " + fn); + emit fileLoaded(); + } + + + /** + * This event filter is installed in the constructor. + * @param o + * @param e + * + * @return bool + */ + bool TableMainWindow::eventFilter(QObject *o,QEvent *e) { + switch (e->type()) { + case QEvent::Close:{ + this->writeSettings(); + } + + default: { + return false; + } + } + } + + + /** + * + * + * + * @param event + */ + void TableMainWindow::closeEvent(QCloseEvent *event) { + this->writeSettings(); + } + + + /** + * + * + * + * @param event + */ + void TableMainWindow::hideEvent(QHideEvent *event) { + this->writeSettings(); + } + + + /** + * If this property is true, the class will keep track of the + * checked/unchecked items in the dock area which determines + * which columns are visible in the table. + * + * @param track + */ + void TableMainWindow::setTrackListItems(bool track){ + p_trackItems = track; + } + + + /** + * Returns whether or not we should track items + * + * + * @return bool + */ + bool TableMainWindow::trackListItems(){ + return p_trackItems; + } + + + /** + * Sets the current row to row + * + * @param row + */ + void TableMainWindow::setCurrentRow(int row){ + p_currentRow = row; + } + + + /** + * Sets the current index to currentIndex + * + * @param currentIndex + */ + void TableMainWindow::setCurrentIndex(int currentIndex){ + p_currentIndex = currentIndex; + } + +} + diff --git a/isis/src/qisis/objs/TableMainWindow/TableMainWindow.h b/isis/src/qisis/objs/TableMainWindow/TableMainWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..753aa57f6830d66c0b9b5db635ead09794088976 --- /dev/null +++ b/isis/src/qisis/objs/TableMainWindow/TableMainWindow.h @@ -0,0 +1,145 @@ +#ifndef TableMainWindow_h +#define TableMainWindow_h +#include +#include "Filename.h" +#include "MainWindow.h" + + +namespace Qisis { + /** + * @brief a subclass of the qisis mainwindow, tablemainwindow + * handles all of the table tasks. + * + * @ingroup Visualization Tools + * + * @author Stacy Alley + * + * @internal + * @history 2008-06-12 Noah Hilt - Changed the save/load + * functions to work with blank entries. + * @history 2008-06-25 Noah Hilt - Fixed the delete rows method to search the + * entire row for values, rather than just the first column. + * @history 2008-10-17 Noah Hilt - Added an optional tooltip parameter to the + * addToTable method. This tooltip will be displayed over the checkbox + * that is to be added to the dock area. + * @history 2008-11-25 Noah Hilt - Added an action to save the table to a file + * that has been loaded or set with the save as action. This way the + * user does not have to reselect the file to save the table to. + */ + + + class TableMainWindow : public Qisis::MainWindow { + Q_OBJECT + public: + /** + * Returns the table + * + * @return QTableWidget* + */ + QTableWidget *table() const { return p_table; }; + + /** + * + * Returns the item list + * + * @return QList + */ + QList itemList() const { return p_itemList;}; + + /** + * + * Returns the list widget + * + * @return QListWidget* + */ + QListWidget *listWidget() const { return p_listWidget; }; + + /** + * + * Returns the selected rows + * + * @return int + */ + int selectedRows() const { return p_selectedRows; }; + + /** + * + * Returns the current index + * + * @return int + */ + int currentIndex() const { return p_currentIndex; }; + + /** + * + * Returns the current row + * + * @return int + */ + int currentRow() const { return p_currentRow; }; + + TableMainWindow (QString title, QWidget *parent=0); + void addToTable (bool setOn, const QString &heading, + const QString &menuText = "", int insertAt = -1, + Qt::Orientation o = Qt::Horizontal, QString toolTip = ""); + void deleteColumn(int item); + void setStatusMessage(QString message); + void closeEvent(QCloseEvent *event); + void hideEvent(QHideEvent *event); + + public slots: + void showTable(); + void syncColumns(); + void syncRows(); + void saveAsTable(); + void saveTable (); + void clearTable (); + void deleteRows(); + void clearRow(int row); + void setCurrentRow(int row); + void setCurrentIndex(int currentIndex); + void setTrackListItems(bool track = false); + bool trackListItems(); + void loadTable (); + void writeSettings(); + + signals: + /** + * Signal emitted when a file has loaded + * + */ + void fileLoaded(); + + protected: + bool eventFilter(QObject *o,QEvent *e); + void createTable(); + void readSettings(); + void readItemSettings(QString heading, QListWidgetItem *item ); + + private: + std::string p_appName; //!< The application name + QWidget *p_parent; //!< The parent widget + QString p_title; //!< The title string + QDockWidget *p_dock; //!< The dock widget + + QAction *p_save; //!< Action to save the table to the current file + QFile p_currentFile; //!< The current file + + QTableWidget *p_table; //!< The table + QList p_itemList; //!< List of widget items + QListWidget *p_listWidget; //!< List widget + int p_selectedRows; //!< Number of selected rows + int p_currentIndex; //!< Current index + int p_currentRow; //!< Current row + + int p_visibleColumns; //!< Number of visible columns + QListp_startColumn; //!< List of start columns + QListp_endColumn; //!< List of end columns + bool p_trackItems; //!< Boolean to track items + + QSettings *p_settings; //!< Settings associated with this object + + }; +}; + +#endif diff --git a/isis/src/qisis/objs/Tool/Makefile b/isis/src/qisis/objs/Tool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/Tool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/Tool/Tool.cpp b/isis/src/qisis/objs/Tool/Tool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..df5cfb839b08b4bc8b0fadbe8800871182341380 --- /dev/null +++ b/isis/src/qisis/objs/Tool/Tool.cpp @@ -0,0 +1,355 @@ +#include "Tool.h" + +#include +#include +#include + +#include "CubeViewport.h" +#include "MdiCubeViewport.h" +#include "Filename.h" +#include "RubberBandTool.h" +#include "ToolPad.h" +#include "Workspace.h" +#include "ViewportMainWindow.h" + + +namespace Qisis { + QStackedWidget *Tool::p_activeToolBarStack = NULL; + + /** + * Tool constructor + * + * @param parent + */ + Tool::Tool(QWidget *parent) : QObject(parent) { + p_cvp = NULL; + p_workspace = NULL; + p_active = false; + p_toolPadAction = NULL; + p_toolBarWidget = NULL; + std::string tempFilename = Isis::Filename("$base/icons").Expanded(); + p_toolIconDir = tempFilename.c_str(); + } + + + /** + * Adds the given workspace to the cubeviewport list. + * + * @param ws + */ + void Tool::addTo(Qisis::Workspace *ws) { + p_workspace = ws; + + connect(ws, SIGNAL(cubeViewportAdded(Qisis::MdiCubeViewport *)), + this, SLOT(setCubeViewport(Qisis::MdiCubeViewport *))); + connect(ws, SIGNAL(cubeViewportActivated(Qisis::MdiCubeViewport *)), + this, SLOT(setCubeViewport(Qisis::MdiCubeViewport *))); + connect(ws, SIGNAL(cubeViewportAdded(Qisis::MdiCubeViewport *)), + this, SLOT(registerTool(Qisis::MdiCubeViewport *))); + } + + /** + * Adds the tool to the application + * + * @param pViewPortMnWin + */ + void Tool::addTo(Qisis::ViewportMainWindow *pViewPortMnWin) { + addTo(pViewPortMnWin->workspace()); + addToPermanent(pViewPortMnWin->permanentToolBar()); + addToActive(pViewPortMnWin->activeToolBar()); + addTo(pViewPortMnWin->toolPad()); + if (!menuName().isEmpty()) { + QMenu *menu = pViewPortMnWin->getMenu(menuName()); +// if (menu->actions().size() > 0) menu->addSeparator(); + addTo(menu); + } + + //connect(this, SIGNAL(clearWarningSignal ()), pViewPortMnWin, SLOT(resetWarning ())); + } + + + /** + * Adds the tool to the toolpad + * + * @param toolpad + */ + void Tool::addTo(Qisis::ToolPad *toolpad) { + p_toolPadAction = toolPadAction(toolpad); + if (p_toolPadAction != NULL) { + toolpad->addAction(p_toolPadAction); + connect(p_toolPadAction, SIGNAL(toggled(bool)), this, SLOT(activate(bool))); + } + } + + + /** + * + * + * @param toolbar + */ + void Tool::addToActive(QToolBar *toolbar) { + if (p_activeToolBarStack == NULL) { + p_activeToolBarStack = new QStackedWidget(toolbar); + toolbar->addWidget(p_activeToolBarStack); + } + + p_toolBarWidget = createToolBarWidget(p_activeToolBarStack); + if (p_toolBarWidget != NULL) { + p_activeToolBarStack->addWidget(p_toolBarWidget); + } + disableToolBar(); + } + + + /** + * Activates the tool. + * + * @param on + */ + void Tool::activate(bool on) { + if (p_active) { + emit clearWarningSignal(); + if (on) + return; + removeViewportConnections(); + disableToolBar(); + if (p_toolPadAction != NULL) + p_toolPadAction->setChecked(false); + p_active = false; + } + else { + if (!on) + return; + if (p_toolPadAction != NULL) + p_toolPadAction->setChecked(true); + addViewportConnections(); + enableToolBar(); + p_active = true; + } + } + + + /** + * Sets the current viewport to the given cvp + * + * @param cvp + */ + void Tool::setCubeViewport(Qisis::MdiCubeViewport *cvp) { + if (cvp == p_cvp) { + updateTool(); + return; + } + + if (p_active) + removeViewportConnections(); + + p_cvp = cvp; + + if (p_active) { + addViewportConnections(); + enableToolBar(); + } + else { + updateTool(); + } + + emit viewportChanged(); + } + + + /** + * Makes all the connections for the tool. + * + */ + void Tool::addViewportConnections() { + if (p_cvp == NULL) + return; + + connect(p_cvp, SIGNAL(scaleChanged()), + this, SLOT(scaleChanged())); + + connect(RubberBandTool::getInstance(), SIGNAL(measureChange()), + this, SLOT(updateMeasure())); + + connect(RubberBandTool::getInstance(), SIGNAL(bandingComplete()), + this, SLOT(rubberBandComplete())); + + connect(p_cvp, SIGNAL(mouseEnter()), + this, SLOT(mouseEnter())); + + connect(p_cvp, SIGNAL(screenPixelsChanged()), + this, SLOT(screenPixelsChanged())); + + connect(p_cvp, SIGNAL(mouseMove(QPoint)), + this, SLOT(mouseMove(QPoint)), Qt::DirectConnection); + + connect(p_cvp, SIGNAL(mouseLeave()), + this, SLOT(mouseLeave())); + + connect(p_cvp, SIGNAL(mouseDoubleClick(QPoint)), + this, SLOT(mouseDoubleClick(QPoint))); + + connect(p_cvp, SIGNAL(mouseButtonPress(QPoint, Qt::MouseButton)), + this, SLOT(mouseButtonPress(QPoint, Qt::MouseButton))); + + connect(p_cvp, SIGNAL(mouseButtonRelease(QPoint, Qt::MouseButton)), + this, SLOT(mouseButtonRelease(QPoint, Qt::MouseButton))); + + addConnections(p_cvp); + + if (p_toolPadAction != NULL) { + enableRubberBandTool(); + } + } + + + /** + * Removes all the connections from the tool. + * + */ + void Tool::removeViewportConnections() { + if (p_cvp == NULL) + return; + + disconnect(p_cvp, SIGNAL(scaleChanged()), + this, SLOT(scaleChanged())); + + disconnect(RubberBandTool::getInstance(), SIGNAL(measureChange()), + this, SLOT(updateMeasure())); + + disconnect(RubberBandTool::getInstance(), SIGNAL(bandingComplete()), + this, SLOT(rubberBandComplete())); + + disconnect(p_cvp, SIGNAL(mouseEnter()), + this, SLOT(mouseEnter())); + + disconnect(p_cvp, SIGNAL(screenPixelsChanged()), + this, SLOT(screenPixelsChanged())); + + disconnect(p_cvp, SIGNAL(mouseMove(QPoint)), + this, SLOT(mouseMove(QPoint))); + + disconnect(p_cvp, SIGNAL(mouseLeave()), + this, SLOT(mouseLeave())); + + disconnect(p_cvp, SIGNAL(mouseDoubleClick(QPoint)), + this, SLOT(mouseDoubleClick(QPoint))); + + disconnect(p_cvp, SIGNAL(mouseButtonPress(QPoint, Qt::MouseButton)), + this, SLOT(mouseButtonPress(QPoint, Qt::MouseButton))); + + disconnect(p_cvp, SIGNAL(mouseButtonRelease(QPoint, Qt::MouseButton)), + this, SLOT(mouseButtonRelease(QPoint, Qt::MouseButton))); + + removeConnections(p_cvp); + } + + + /** + * Disables entire tool bar. + * + */ + void Tool::disableToolBar() { + if (p_toolBarWidget == NULL) + return; +// if (p_toolBarWidget->isVisible()) p_toolBarWidget->hide(); + p_toolBarWidget->setEnabled(false); + } + + + /** + * Enables entire tool bar. + * + */ + void Tool::enableToolBar() { + updateTool(); + if (p_toolBarWidget == NULL) + return; + if (cubeViewport() == NULL) { + p_toolBarWidget->setEnabled(false); + } + else { + p_toolBarWidget->setEnabled(true); + } + p_activeToolBarStack->setCurrentWidget(p_toolBarWidget); + } + + + /** + * Updates the tool. + * + */ + void Tool::updateTool() { + } + + + /** + * Registers the tool to the viewport. + * + * @param viewport + */ + void Tool::registerTool(Qisis::MdiCubeViewport *viewport) { + viewport->registerTool(this); + + connect(p_cvp, SIGNAL(requestRestretch(MdiCubeViewport *, int)), + this, SLOT(stretchRequested(MdiCubeViewport *, int))); + } + + + /** + * Enable the use of the rubberband tool. + * + */ + void Tool::enableRubberBandTool() { + RubberBandTool::disable(); + } + + + /** + * @param p + */ + void Tool::mouseMove(QPoint p) {}; + + + /** + * @param p + */ + void Tool::mouseDoubleClick(QPoint p) { + emit clearWarningSignal(); + } + + + /** + * @param p + * @param s + */ + void Tool::mouseButtonPress(QPoint p, Qt::MouseButton s) { + emit clearWarningSignal(); + } + + + /** + * Resets the Warning to Nowarning when a different activity + * occurs on the application. This is called by all the + * mouseButtonRelease events in all the tools. + * + * @param p + * @param s + */ + void Tool::mouseButtonRelease(QPoint p, Qt::MouseButton s) { + emit clearWarningSignal(); + } + + + /** + * Return the list of cubeviewports. + * + * @return CubeViewportList* + */ + Tool::CubeViewportList *Tool::cubeViewportList() const { + return p_workspace->cubeViewportList(); + } +} + + + diff --git a/isis/src/qisis/objs/Tool/Tool.h b/isis/src/qisis/objs/Tool/Tool.h new file mode 100644 index 0000000000000000000000000000000000000000..0e2aa052abd83dcbd87197ea4ff00c9724f8b1d0 --- /dev/null +++ b/isis/src/qisis/objs/Tool/Tool.h @@ -0,0 +1,282 @@ +#ifndef Qisis_Tool_h +#define Qisis_Tool_h + +/** + * @file + * $Date: 2010/07/01 22:52:23 $ + * $Revision: 1.21 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +#include + +// FIXME: remove this include! +#include + + +class QAction; +class QMenu; +class QPainter; +//class QPoint; +class QStackedWidget; +class QToolBar; + +template< class T > class QVector; + + +namespace Qisis { + class CubeViewport; + class MdiCubeViewport; + class ToolPad; + class ViewportMainWindow; + class Workspace; + + /** + * @brief Base class for the Qisis tools + * + * @ingroup Visualization Tools + * + * @author ??? Jeff Anderson + * + * @internal + * @history 2007-04-30 Tracie Sucharski, Added Qpainter to parameters + * for the paintViewport method. This will allow + * the tools to use the CubeViewport painter rather + * than creating a new one which causes warnings + * in Qt4. + * @history 2007-09-11 Steven Lambright - Added code to handle the rubber band tool + * @history 2007-11-19 Stacy Alley - Added code for the new ViewportMainWindow + * class which is used to keep track of the size and + * location of the qisis windows. + * @history 2009-03-27 Noah Hilt, Steven Lambright - Removed old rubber band + * and changed cubeViewportList to call the Workspace viewport list. + * @history 2010-03-18 Sharmila Prasad - Reset warning status when a different tool is chosen, done + * on mouse double click, press or release + * @history 2010-05-24 Eric Hyer - setCubeViewport is now public + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport + */ + + class Tool : public QObject { + Q_OBJECT + + public: + Tool(QWidget *parent); + + void addTo(Qisis::ViewportMainWindow *mw); + + void addTo(Qisis::ToolPad *toolpad); + + /** + * requires the programmer to have this member + * + * @param menu + */ + virtual void addTo(QMenu *menu) {}; + + + /** + * requires the programmer to have this member + * + * @param toolbar + */ + virtual void addToPermanent(QToolBar *toolbar) {}; + + void addToActive(QToolBar *toolbar); + + /** + * requires the programmer to have this member + * + * @param ws + */ + virtual void addTo(Qisis::Workspace *ws); + + + /** + * returns the path to the icon directory. + * + * + * @return QString + */ + QString toolIconDir() const { + return p_toolIconDir; + }; + + + /** + * requires the programmer to have this member + * + * @param vp + * @param painter + */ + virtual void paintViewport(MdiCubeViewport *vp, QPainter *painter) {}; + + + public slots: + void activate(bool); + virtual void updateTool(); + void setCubeViewport(Qisis::MdiCubeViewport *cvp); + + + signals: + void clearWarningSignal(); + + protected slots: + + /** + */ + virtual void rubberBandComplete() {}; + + + /** + * This is called when actions change which pixels from the cube + * are displayed. + */ + virtual void screenPixelsChanged() {}; + + /** + */ + virtual void mouseEnter() {}; + + virtual void mouseMove(QPoint p); + + /** + */ + virtual void mouseLeave() {}; + + virtual void mouseDoubleClick(QPoint p); + virtual void mouseButtonPress(QPoint p, Qt::MouseButton s); + virtual void mouseButtonRelease(QPoint p, Qt::MouseButton s); + + /** + */ + virtual void updateMeasure() {}; + + + /** + */ + virtual void scaleChanged() {}; + + + /** + */ + virtual void stretchRequested(MdiCubeViewport *, int) {}; + + + /** + * @param viewport + */ + void registerTool(Qisis::MdiCubeViewport *viewport); + + + signals: + /** + */ + void viewportChanged(); + + protected: + /** + * Return the current cubeviewport + * + * @return Qisis::CubeViewport* + */ + inline Qisis::MdiCubeViewport *cubeViewport() const { + return p_cvp; + }; + + + /** + * A list of cubeviewports. + */ + typedef QVector< Qisis::MdiCubeViewport * > CubeViewportList; + + CubeViewportList *cubeViewportList() const; + + + /** + * Anytime a tool is created, you must setup a tool pad action with it. + * + * @param toolpad + * + * @return QAction* + */ + virtual QAction *toolPadAction(ToolPad *toolpad) { + return NULL; + }; + + + /** + * Anytime a tool is created, you must give it a name for the + * menu. + * + * @return QString + */ + virtual QString menuName() const { + return ""; + }; + + + /** + * Anytime a tool is created, you must add it to the tool bar. + * + * @param parent + * + * @return QWidget* + */ + virtual QWidget *createToolBarWidget(QStackedWidget *parent) { + return NULL; + }; + + + /** + * Anytime a tool is created, you must add the connections for it. + * + * @param cvp + */ + virtual void addConnections(MdiCubeViewport *cvp) {}; + + + /** + * Anytime a tool is created, you must be able to remove it's connections. + * + * @param cvp + */ + virtual void removeConnections(MdiCubeViewport *cvp) {}; + + + //! Anytime a tool is created, you may use the rubber band tool. + virtual void enableRubberBandTool(); + + Qisis::MdiCubeViewport *p_cvp; //!< current cubeviewport + Workspace *p_workspace; + + private: + void addViewportConnections(); + void removeViewportConnections(); + void enableToolBar(); + void disableToolBar(); + + bool p_active; //!< Is the tool acitve? + QWidget *p_toolBarWidget; //!< The tool bar on which this tool resides. + QAction *p_toolPadAction; //!< The tool pad on which this tool resides. + QString p_toolIconDir; //!< The pathway to the icon directory. + static QStackedWidget *p_activeToolBarStack; //!< Active tool bars + }; +}; + +#endif diff --git a/isis/src/qisis/objs/ToolPad/Makefile b/isis/src/qisis/objs/ToolPad/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/ToolPad/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/ToolPad/ToolPad.h b/isis/src/qisis/objs/ToolPad/ToolPad.h new file mode 100644 index 0000000000000000000000000000000000000000..1c117033032ebef1b15fdd10bd4f6769c2007b10 --- /dev/null +++ b/isis/src/qisis/objs/ToolPad/ToolPad.h @@ -0,0 +1,43 @@ +#ifndef Qisis_ToolPad_h +#define Qisis_ToolPad_h + +#include +#include + +namespace Qisis { + class ToolPad : public QToolBar { + Q_OBJECT + + public: + /** + * Toolpad constructor. + * + * + * @param label + * @param parent + */ + ToolPad (const QString &label, QWidget *parent) : QToolBar(label,parent) { + p_actionGroup = new QActionGroup(parent); + p_actionGroup->setExclusive(true); + setIconSize(QSize(22,22)); + } + + + /** + * Adds an action to the action group and tool bar. + * + * + * @param action + */ + void addAction (QAction *action) { + action->setCheckable(true); + p_actionGroup->addAction(action); + QToolBar::addAction(action); + } + + private: + QActionGroup *p_actionGroup;//!< Group of actions. + }; +}; + +#endif diff --git a/isis/src/qisis/objs/TrackTool/Makefile b/isis/src/qisis/objs/TrackTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/TrackTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/TrackTool/TrackTool.cpp b/isis/src/qisis/objs/TrackTool/TrackTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d41974d55abb65caacc963f4253e0cfbda7f7843 --- /dev/null +++ b/isis/src/qisis/objs/TrackTool/TrackTool.cpp @@ -0,0 +1,361 @@ +#include "TrackTool.h" + +#include +#include +#include + +#include "Camera.h" +#include "Projection.h" +#include "MdiCubeViewport.h" +#include "SpecialPixel.h" +#include "ViewportBuffer.h" +#include "WarningWidget.h" + + +namespace Qisis { + /** + * TrackTool constructor + * + * + * @param parent + */ + TrackTool::TrackTool (QStatusBar *parent) : Tool(parent) { + p_sbar = parent; + + p_sampLabel = new QLabel(p_sbar); + p_sampLabel->setText("W 999999"); + p_sampLabel->setMinimumSize(p_sampLabel->sizeHint()); + p_sampLabel->setToolTip("Sample Position"); + p_sbar->addPermanentWidget(p_sampLabel); + + p_lineLabel = new QLabel(p_sbar); + p_lineLabel->setText("W 999999"); + p_lineLabel->setMinimumSize(p_lineLabel->sizeHint()); + p_lineLabel->setToolTip("Line Position"); + p_sbar->addPermanentWidget(p_lineLabel); + + p_latLabel = new QLabel(p_sbar); + p_latLabel->setText("9.999999E-99"); + p_latLabel->setMinimumSize(p_latLabel->sizeHint()); + p_latLabel->hide(); + p_latLabel->setToolTip("Latitude Position"); + p_sbar->addPermanentWidget(p_latLabel); + + p_lonLabel = new QLabel(p_sbar); + p_lonLabel->setText("9.999999E-99"); + p_lonLabel->setMinimumSize(p_lonLabel->sizeHint()); + p_lonLabel->hide(); + p_lonLabel->setToolTip("Longitude Position"); + p_sbar->addPermanentWidget(p_lonLabel); + + p_grayLabel = new QLabel(p_sbar); + p_grayLabel->setText("9.999999E-99"); + p_grayLabel->setMinimumSize(p_grayLabel->sizeHint()); + p_grayLabel->setToolTip("Gray Pixel Value"); + p_sbar->addPermanentWidget(p_grayLabel); + + p_redLabel = new QLabel(p_sbar); + p_redLabel->setText("W 9.999999E-99"); + p_redLabel->setMinimumSize(p_redLabel->sizeHint()); + p_redLabel->hide(); + p_redLabel->setToolTip("Red Pixel Value"); + p_sbar->addPermanentWidget(p_redLabel); + + p_grnLabel = new QLabel(p_sbar); + p_grnLabel->setText("W 9.999999E-99"); + p_grnLabel->setMinimumSize(p_grnLabel->sizeHint()); + p_grnLabel->hide(); + p_grnLabel->setToolTip("Green Pixel Value"); + p_sbar->addPermanentWidget(p_grnLabel); + + p_bluLabel = new QLabel(p_sbar); + p_bluLabel->setText("W 9.999999E-99"); + p_bluLabel->setMinimumSize(p_bluLabel->sizeHint()); + p_bluLabel->hide(); + p_bluLabel->setToolTip("Blue Pixel Value"); + p_sbar->addPermanentWidget(p_bluLabel); + + mWarningWidget = new Qisis::WarningWidget(p_sbar); + connect(p_sbar, SIGNAL(messageChanged (const QString &)),mWarningWidget, SLOT(checkMessage())); + + clearLabels(); + + activate(true); + } + + /** + * Display the Warning icon in case of an exception, sent from + * the tool where the exception occured + * + * @param pStr - Topmost Exception Message String + * @param pExStr - Propagated exception message string + */ + void TrackTool::displayWarning(std::string & pStr, const std::string & pExStr) + { + mWarningWidget->viewWarningWidgetIcon(pStr, pExStr); + } + + /** + * Resets the warning status on the status bar to default + */ + void TrackTool::resetStatusWarning(void) + { + if (mWarningWidget != NULL) { + mWarningWidget->resetWarning(); + } + } + + /** + * Updates the labels anytime the mouse moves. + * + * + * @param p + */ + void TrackTool::mouseMove(QPoint p) { + MdiCubeViewport *cvp = cubeViewport(); + if (cvp == NULL) return; + + if(p.x() > 0 && p.x() < cvp->width() && + p.y() > 0 && p.y() < cvp->height()) + { + updateLabels(p); + } + } + + + /** + * Clears the labels if the mouse leaves the application. + * + */ + void TrackTool::mouseLeave() { + clearLabels(); + } + + + /** + * Updates the tracking labels. + * + * + * @param p + */ + void TrackTool::updateLabels (QPoint p) { + MdiCubeViewport *cvp = cubeViewport(); + if (cvp == NULL) { + clearLabels(); + return; + } + + double sample,line; + cvp->viewportToCube(p.x(),p.y(),sample,line); + if ((sample < 0.5) || (line < 0.5) || + (sample > cvp->cubeSamples()+0.5) || + (line > cvp->cubeLines()+0.5)) { + clearLabels(); + return; + } + + int isamp = (int) (sample + 0.5); + QString text; + text.setNum(isamp); + text = "S " + text; + p_sampLabel->setText(text); + + int iline = (int) (line + 0.5); + text.setNum(iline); + text = "L " + text; + p_lineLabel->setText(text); + + + // Do we have a projection? + if (cvp->projection() != NULL) { + p_latLabel->show(); + p_lonLabel->show(); + + if (cvp->projection()->SetWorld(sample,line)) { + double lat = cvp->projection()->Latitude(); + double lon = cvp->projection()->Longitude(); + p_latLabel->setText(QString("Lat %1").arg(lat)); + p_lonLabel->setText(QString("Lon %1").arg(lon)); + } + else { + p_latLabel->setText("Lat n/a"); + p_lonLabel->setText("Lon n/a"); + } + } + // Do we have a camera model? + else if (cvp->camera() != NULL) { + p_latLabel->show(); + p_lonLabel->show(); + + if (cvp->camera()->SetImage(sample,line)) { + double lat = cvp->camera()->UniversalLatitude(); + double lon = cvp->camera()->UniversalLongitude(); + p_latLabel->setText(QString("Lat %1").arg(lat)); + p_lonLabel->setText(QString("Lon %1").arg(lon)); + } + else { + p_latLabel->setText("Lat n/a"); + p_lonLabel->setText("Lon n/a"); + } + } + + else { + p_latLabel->hide(); + p_lonLabel->hide(); + } + + if (cvp->isGray()) { + p_grayLabel->show(); + p_redLabel->hide(); + p_grnLabel->hide(); + p_bluLabel->hide(); + + ViewportBuffer * grayBuf = cvp->grayBuffer(); + + if(grayBuf->working()) { + p_grayLabel->setText("BUSY"); + } + else { + const QRect rect(grayBuf->bufferXYRect()); + + if(p.x() >= 0 && p.x() < rect.right() && + p.y() >= 0 && p.y() < rect.bottom()) + { + const int bufX = p.x() - rect.left(); + const int bufY = p.y() - rect.top(); + QString pixelString = Isis::iString(Isis::PixelToString( + grayBuf->getLine(bufY)[bufX])).ToQt(); + p_grayLabel->setText(pixelString); + } + } + } + else { + p_grayLabel->hide(); + p_redLabel->show(); + p_grnLabel->show(); + p_bluLabel->show(); + + ViewportBuffer * redBuf = cvp->redBuffer(); + + if(redBuf->working()) { + p_grayLabel->setText("BUSY"); + } + else { + const QRect rRect = redBuf->bufferXYRect(); + + if(p.x() >= 0 && p.x() < rRect.right() && + p.y() >= 0 && p.y() < rRect.bottom()) + { + const int rBufX = p.x() - rRect.left(); + const int rBufY = p.y() - rRect.top(); + QString rLab = "R "; + rLab += Isis::iString(Isis::PixelToString( + redBuf->getLine(rBufY)[rBufX])).ToQt(); + p_redLabel->setText(rLab); + } + } + + ViewportBuffer * greenBuf = cvp->greenBuffer(); + + if(greenBuf->working()) { + p_grayLabel->setText("BUSY"); + } + else { + const QRect gRect = greenBuf->bufferXYRect(); + + if(p.x() >= 0 && p.x() < gRect.right() && + p.y() >= 0 && p.y() < gRect.bottom()) + { + const int gBufX = p.x() - gRect.left(); + const int gBufY = p.y() - gRect.top(); + QString gLab = "G "; + gLab += Isis::iString(Isis::PixelToString( + greenBuf->getLine(gBufY)[gBufX])).ToQt(); + p_grnLabel->setText(gLab); + } + } + + ViewportBuffer * blueBuf = cvp->blueBuffer(); + + if(blueBuf->working()) { + p_grayLabel->setText("BUSY"); + } + else { + const QRect bRect = blueBuf->bufferXYRect(); + + if(p.x() >= 0 && p.x() < bRect.right() && + p.y() >= 0 && p.y() < bRect.bottom()) + { + const int bBufX = p.x() - bRect.left(); + const int bBufY = p.y() - bRect.top(); + QString bLab = "B "; + bLab += Isis::iString(Isis::PixelToString( + blueBuf->getLine(bBufY)[bBufX])).ToQt(); + p_bluLabel->setText(bLab); + } + } + } + } + + + /** + * Clears the labels. + * + */ + void TrackTool::clearLabels () { + p_sampLabel->setText("S n/a"); + p_lineLabel->setText("L n/a"); + p_latLabel->setText("Lat n/a"); + p_lonLabel->setText("Lon n/a"); + p_grayLabel->setText("n/a"); + p_redLabel->setText("R n/a"); + p_grnLabel->setText("G n/a"); + p_bluLabel->setText("B n/a"); + } + + + /** + * Finds the cursor position. + * + */ + void TrackTool::locateCursor () { + if (cubeViewport() == NULL) return; + QPoint p = cubeViewport()->viewport()->mapFromGlobal(QCursor::pos()); + if (p.x() < 0) return; + if (p.y() < 0) return; + if (p.x() >= cubeViewport()->viewport()->width()) return; + if (p.y() >= cubeViewport()->viewport()->height()) return; + updateLabels(p); + } + + + /** + * Adds the connections to the given viewport. + * + * + * @param cvp + */ + void TrackTool::addConnections (MdiCubeViewport *cvp) { + connect(cubeViewport(),SIGNAL(viewportUpdated()), + this,SLOT(locateCursor())); + } + + + /** + * Removes the connections from the given viewport. + * + * + * @param cvp + */ + void TrackTool::removeConnections (MdiCubeViewport *cvp) { + disconnect(cubeViewport(),SIGNAL(viewportUpdated()), + this,SLOT(locateCursor())); + } + + + QStatusBar * TrackTool::getStatusBar(void) + { + return p_sbar; + } +} + diff --git a/isis/src/qisis/objs/TrackTool/TrackTool.h b/isis/src/qisis/objs/TrackTool/TrackTool.h new file mode 100644 index 0000000000000000000000000000000000000000..7faaff876d9355dcfb102d76e7ee47fe1d6090b3 --- /dev/null +++ b/isis/src/qisis/objs/TrackTool/TrackTool.h @@ -0,0 +1,71 @@ +#ifndef Qisis_TrackTool_h +#define Qisis_TrackTool_h + +// This is the only include allowed in this file! +#include "Tool.h" + + +class QLabel; +class QStatusBar; + +namespace Qisis +{ + class MdiCubeViewport; + class WarningWidget; + + /** + * @brief This tool is part of the Qisis namespace and displays the statusbar of the window. + * The status bar tracks the line, sample, lat ,lon and pixel values. Also displays Warning + * status for any application activity. + * + * @ingroup Visualization Tools + * + * @author + * + * @internal + * + * @history 2010-03-18 Sharmila Prasad - Added the Warning widget to the + * status bar to display the error status both icon and message for + * any application activity + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport instead of + * CubeViewport. Fixed include issues. + */ + class TrackTool : public Tool + { + Q_OBJECT + + public: + TrackTool(QStatusBar *parent); + void displayWarning(std::string & pStr, const std::string & pExStr); + void resetStatusWarning(void); + QStatusBar * getStatusBar(void); + + public slots: + virtual void mouseMove(QPoint p); + virtual void mouseLeave(); + + protected: + void addConnections(MdiCubeViewport *cvp); + void removeConnections(MdiCubeViewport *cvp); + + private slots: + void locateCursor(); + + private: + void updateLabels(QPoint p); + void clearLabels(); + + QStatusBar *p_sbar; //!< Status bar + QLabel *p_sampLabel; //!< Sample label + QLabel *p_lineLabel; //!< Line label + QLabel *p_latLabel; //!< Lat label + QLabel *p_lonLabel; //!< Lon label + QLabel *p_grayLabel; //!< Gray label + QLabel *p_redLabel; //!< Red label + QLabel *p_grnLabel; //!< Green label + QLabel *p_bluLabel; //!< Blue label + WarningWidget * mWarningWidget; //!< Warning Widget + }; +}; + +#endif diff --git a/isis/src/qisis/objs/ViewportMainWindow/Makefile b/isis/src/qisis/objs/ViewportMainWindow/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/ViewportMainWindow/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/ViewportMainWindow/ViewportMainWindow.cpp b/isis/src/qisis/objs/ViewportMainWindow/ViewportMainWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9ec00bf0831c368b441fdf14653ffcd1ad38c0d7 --- /dev/null +++ b/isis/src/qisis/objs/ViewportMainWindow/ViewportMainWindow.cpp @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include +#include "ViewportMainWindow.h" +#include "Workspace.h" +#include "TrackTool.h" +#include "ToolPad.h" + +namespace Qisis { + /** + * Constructs a ViewportMainWindow object with windowTitle = title. + * + * @param title + * @param parent + */ + ViewportMainWindow::ViewportMainWindow (QString title, QWidget *parent) : Qisis::MainWindow(title, parent) { + installEventFilter(this); + p_workspace = new Qisis::Workspace(this); + setCentralWidget(p_workspace); + this->setWindowTitle(title); + + p_permToolbar = new QToolBar("Standard Tools",this); + p_permToolbar->setObjectName("perm"); + p_permToolbar->setAllowedAreas(Qt::TopToolBarArea|Qt::BottomToolBarArea); + p_permToolbar->setIconSize(QSize(22,22)); + this->addToolBar(p_permToolbar); + + p_activeToolbar = new QToolBar("Active Tool",this); + p_activeToolbar->setObjectName("Active"); + p_activeToolbar->setAllowedAreas(Qt::TopToolBarArea|Qt::BottomToolBarArea); + p_activeToolbar->setIconSize(QSize(22,22)); + this->addToolBar(p_activeToolbar); + + QStatusBar *sbar = statusBar(); + sbar->showMessage("Ready"); + + mTrackTool = new TrackTool(sbar); + mTrackTool->addTo(this); + + p_toolpad = new ToolPad("Tool Pad",this); + p_toolpad->setObjectName("ViewportMainWindow"); + p_toolpad->setAllowedAreas(Qt::LeftToolBarArea|Qt::RightToolBarArea); + this->addToolBar(Qt::RightToolBarArea,p_toolpad); + + readSettings(); + } + + + /** + * + * + */ + ViewportMainWindow::~ViewportMainWindow(){ + } + + /** + * Slot which receives the warning signal. Calls the Track Tool + * to display the warning status + * + * @param pStr - Warning message + * @param pExStr - Propagated exception message + */ + void ViewportMainWindow::displayWarning(std::string & pStr, const std::string & pExStr) + { + if (mTrackTool != NULL) { + mTrackTool->displayWarning(pStr, pExStr); + } + } + + /** + * Slot which receives the message to reset warning status + */ + void ViewportMainWindow::resetWarning(void) + { + if (mTrackTool != NULL) { + mTrackTool->resetStatusWarning(); + } + } + + /** + * Returns the menu with menu name = name. + * + * @param name + * + * @return QMenu* + */ + QMenu *ViewportMainWindow::getMenu(const QString &name) { + std::map::iterator pos; + pos = p_menus.find(name); + if (pos != p_menus.end()) { + return pos->second; + } + else { + QMenu *menu = menuBar()->addMenu(name); + p_menus[name] = menu; + return menu; + } + } + + + /** + * This overriden method is called from the constructor so that + * when the viewportmainwindow is created, it know's it's size + * and location and the tool bar location. + * + */ + void ViewportMainWindow::readSettings(){ + /*Call the base class function to read the size and location*/ + this->MainWindow::readSettings(); + /*Now read the settings that are specific to this window.*/ + std::string instanceName = this->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/" + instanceName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()), QSettings::NativeFormat); + QByteArray state = settings.value("state", QByteArray("0")).toByteArray(); + restoreState(state); + } + + + /** + * This overriden method is called when the viewportmainwindow + * is closed or hidden to write the size and location settings + * (and tool bar location) to a config file in the user's home + * directory. + * + */ + void ViewportMainWindow::writeSettings() { + /*Call the base class function to write the size and location*/ + this->MainWindow::writeSettings(); + /*Now write the settings that are specific to this window.*/ + std::string instanceName = this->windowTitle().toStdString(); + Isis::Filename config("$HOME/.Isis/" + instanceName + "/" + instanceName + ".config"); + QSettings settings(QString::fromStdString(config.Expanded()), QSettings::NativeFormat); + settings.setValue("state", this->saveState()); + } + + + /** + * This class is called when a close event occurs, it emits a + * signal and ignores the close event. + * + * @param event + */ + void ViewportMainWindow::closeEvent(QCloseEvent *event) { + emit closeWindow(); + event->ignore(); + } + + + /** + * This event filter is installed in the constructor. + * @param o + * @param e + * + * @return bool + */ + bool ViewportMainWindow::eventFilter(QObject *o,QEvent *e) { + switch (e->type()) { + case QEvent::Close:{ + writeSettings(); + } + + default: { + return false; + } + } + } + +} + diff --git a/isis/src/qisis/objs/ViewportMainWindow/ViewportMainWindow.h b/isis/src/qisis/objs/ViewportMainWindow/ViewportMainWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..6c787f3f5bb6473250072c3e18a55d6f4db9d392 --- /dev/null +++ b/isis/src/qisis/objs/ViewportMainWindow/ViewportMainWindow.h @@ -0,0 +1,84 @@ +#ifndef ViewportMainWindow_h +#define ViewportMainWindow_h + +#include +#include +#include +#include "Filename.h" +#include "MainWindow.h" + +namespace Isis{ + class Preference; +} + +namespace Qisis { + /** + * @brief This was called the Qisis MainWindow. Now this is + * being subclassed from the mainwindow class which keeps + * track of the size and location of the qisis windows. + * qview and qnet are two applications that use + * WiewportMainWindow. + * + * @ingroup Visualization Tools + * + * @author Stacy Alley + * + * @internal + * + * @history 2008-06-19 Noah Hilt - Added a method for sending a signal to qview + * when this window recieves a close event. This signal calls the file + * tool's exit method and ignores this class's close method. + * @history 2010-18-03 Sharmila Prasad - Added ability to handle exception and display warning status + * when exception occured + */ + class Workspace; + class ToolPad; + class TrackTool; + + class ViewportMainWindow : public Qisis::MainWindow { + Q_OBJECT + + signals: + void closeWindow(); //!< Signal called when the window receives a close event + + public slots: + void displayWarning(std::string & pStr, const std::string & pExStr); + void resetWarning(void); + + public: + ViewportMainWindow (QString title, QWidget *parent=0); + virtual ~ViewportMainWindow (); + + //! Returns the current workspace + Qisis::Workspace *workspace() { return p_workspace; }; + + //! Returns the permanent toolbar + QToolBar *permanentToolBar () { return p_permToolbar; }; + + //! Returns the active toolbar + QToolBar *activeToolBar () { return p_activeToolbar; }; + + //! Returns the toolpad + Qisis::ToolPad *toolPad() { return p_toolpad; }; + + QMenu *getMenu(const QString &name); + Qisis::TrackTool* getTrackTool() { return mTrackTool; }; + + protected: + bool eventFilter(QObject *o,QEvent *e); + void readSettings(); + void writeSettings(); + virtual void closeEvent(QCloseEvent *event); + + private: + Qisis::Workspace *p_workspace; //!< The current workspace + QToolBar *p_permToolbar; //!< The permanent toolbar + QToolBar *p_activeToolbar; //!< The active toolbar + Qisis::ToolPad *p_toolpad; //!< The toolpad + std::map p_menus; //!< Map of qstrings to menus + std::string p_appName; //!< The app name + Qisis::TrackTool *mTrackTool; //!< Pointer to application's Status bar + }; +}; + +#endif diff --git a/isis/src/qisis/objs/WarningWidget/Makefile b/isis/src/qisis/objs/WarningWidget/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/WarningWidget/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/WarningWidget/WarningWidget.cpp b/isis/src/qisis/objs/WarningWidget/WarningWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed70348285583303c297e427ccfb1c6ecf8558a4 --- /dev/null +++ b/isis/src/qisis/objs/WarningWidget/WarningWidget.cpp @@ -0,0 +1,159 @@ +#include "WarningWidget.h" +#include "iString.h" +#include "Filename.h" + +#include +#include +#include +#include +#include + +namespace Qisis { + /** + * Warning widget constructor, initializes and creates the + * Nowarning, Warning objects and objects associated with them + * + * @author sprasad (12/11/2009) + * + * @param parent - parent of this object + */ + WarningWidget::WarningWidget(QStatusBar *pParent): QObject(pParent) { + mSBar = pParent; + + std::string sToolIconDir = Isis::Filename("$base/icons").Expanded(); + QString qsIconFile(sToolIconDir.c_str()); + + // default Action - No warning + mNoWarning = new QPushButton(mSBar); + mNoWarning->setFixedSize(22, 22) ; + mNoWarning->setFlat(true); + mNoWarning->setIconSize(QSize(15, 15)); + mNoWarning->setIcon(QPixmap(qsIconFile + "/qview_NoWarning.png")); + mNoWarning->setToolTip("No Warning"); + mNoWarning->setVisible(true); + // Add Nowarning object to the layout of the active tool bar of the Tool + mSBar->insertPermanentWidget(0, mNoWarning); + + mSBar->showMessage("Ready"); + mMsgStr = QString("Ready"); + + // Warning is not set + mbWarningFlag = false; + + // Dialog box displayed when the Warning Icon is clicked + mDialog = new QDialog(mSBar); + mDialog->setWindowTitle("Warning"); + mDialog->setSizeGripEnabled(true); + mWindow = new QWidget(mDialog); + mWindow->installEventFilter(this); //receive events directed to this object + + mTextEdit = new QTextEdit(mDialog); + mTextEdit->setReadOnly(true); + QFont font("Helvetica", 11); + mTextEdit->setFont(font); + + // OK button for the dialog window + QPushButton *okButton = new QPushButton("Ok", mDialog); + okButton->setShortcut(Qt::Key_Enter); + connect(okButton, SIGNAL(clicked()), this, SLOT(resetWarning())); //when clicked close dialog and display Nowarning icon + + QGridLayout *layout = new QGridLayout(); + layout->addWidget(mTextEdit, 0, 0, 1, 3); + layout->addWidget(okButton, 1, 1, 1, 1); + mDialog->setLayout(layout); + + // Warning object + mWarning = new QPushButton(mSBar); + mWarning->setFixedSize(22, 22) ; + mWarning->setFlat(false); + mWarning->setIconSize(QSize(15, 15)); + mWarning->setIcon(QPixmap(qsIconFile + "/qview_Warning.png")); + mWarning->setToolTip("Warning"); + mWarning->setVisible(false); + mSBar->insertPermanentWidget(0, mWarning); + + connect(mWarning, SIGNAL(clicked()), mDialog, SLOT(show())); // display the dialog window when this button is clicked + mDialog->resize(800, 250); + mTextEdit->setBaseSize(750, 200) ; + + QSize qs = mSBar->baseSize(); + } + + /** + * Destructor for the Warning widget + * + * Delete all the dynamically created class members + * + * @author sprasad (12/11/2009) + */ + WarningWidget::~WarningWidget() { + + } + + /** + * Set the message for the status bar and the dialog window. Highlight + * the text within "[..]" in red + * + * @author sprasad (12/11/2009) + * + * @param pStr - error message + */ + void WarningWidget::setWarningText(std::string pStr) { + int findChar1 = pStr.find('[', 0); + std::string redStr = pStr.substr(0, findChar1 + 1); + redStr += ""; + int findChar2 = pStr.find(']', 0); + redStr += pStr.substr(findChar1 + 1, findChar2 - findChar1 - 1); + redStr += ""; + redStr += pStr.substr(findChar2, pStr.length() - findChar2); + mSBar->showMessage(QString(redStr.c_str())); + mTextEdit->setText(QString(redStr.c_str())); + } + + /** + * When the dialog "OK" button is clicked or when the mouse is + * released on some other area or tool the Warning is reset and + * Nowarning object is displayed. + * + * @author sprasad (12/11/2009) + */ + void WarningWidget::resetWarning(void) { + if(mbWarningFlag == true) { + mWarning->setVisible(false); + mNoWarning->setVisible(true); + mDialog->setVisible(false); + mbWarningFlag = false; + mSBar->showMessage("Ready"); + mMsgStr = "Ready"; + } + } + + /** + * Verify that the right message is displayed in the status bar + * + * @author sprasad (3/18/2010) + */ + void WarningWidget::checkMessage(void) { + if(mbWarningFlag == true && mMsgStr.length()) { + if(mSBar->currentMessage() != mMsgStr) + mSBar->showMessage(mMsgStr); + } + } + /** + * View Warning icon when there is an exception. Usually called + * when an exception occurs. + * + * @author sprasad (12/11/2009) + * + * @param pStr - Warning message sent from the exception handler + * @param pExStr - Propagated Exception message + */ + void WarningWidget::viewWarningWidgetIcon(std:: string &pStr, const std::string &pExStr) { + mbWarningFlag = true; + mWarning->setVisible(true); + mNoWarning->setVisible(false); + std::string sStr = "**PROGRAMMER ERROR** " + pStr; + mMsgStr = sStr.c_str(); + setWarningText(sStr + "
    " + pExStr); + } +} diff --git a/isis/src/qisis/objs/WarningWidget/WarningWidget.h b/isis/src/qisis/objs/WarningWidget/WarningWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..fd18f5176581bafdf6f77b7631987796ce5e3ae2 --- /dev/null +++ b/isis/src/qisis/objs/WarningWidget/WarningWidget.h @@ -0,0 +1,74 @@ +#ifndef _WarningWidget_h_ +#define _WarningWidget_h_ + +#include +#include +#include +#include +#include +#include + +#include "CubeViewport.h" +/** + * @file + * $Revision: 1.3 $ + * $Date: 2010/06/24 17:17:49 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +namespace Qisis { + /** + * @brief Displays the NoWarning icon as default and the Warning + * icon in case of exception and also pops up a a menu + * when an exception occurs. Clicking on the Warning icon + * will display a dialog with the Exception details. With + * the next mouse press event, the Warning icon + * disappears and the default NoWarning icon appears. + * + * @ingroup Part of active tool bar of all the Tools + * + * @author Sharmila Prasad + * + * @internal + * @history 2009/12/11 Sharmila Prasad - Initial Version + * @history 2010/03/22 Sharmila Prasad - Point the warning icons to right path + */ + class WarningWidget : public QObject { + Q_OBJECT + public: + WarningWidget(QStatusBar *pParent); + ~WarningWidget(); + void viewWarningWidgetIcon(std::string &pStr, const std::string &pExStr); + void setWarningText(std::string pStr); + QString setValuesToRed(std::string psMessage); + + public slots: + void resetWarning(void); + void checkMessage(void); + + private: + QDialog *mDialog; // Dialog that pops up when Warning icon is clicked + QWidget *mWindow; // Dialog Window + QPushButton *mNoWarning, *mWarning; // Tool buttons displaying Warning and Nowarning icons + bool mbWarningFlag; // Flag to indicate Warning or Nowarning status + QStatusBar *mSBar; // Pointer to application's Status Bar + QString mMsgStr; // Message displayed on the status bar + QTextEdit *mTextEdit; // Textedit which contains detailed error message in the Dialog window + }; +}; +#endif diff --git a/isis/src/qisis/objs/WindowTool/Makefile b/isis/src/qisis/objs/WindowTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/WindowTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/WindowTool/WindowTool.cpp b/isis/src/qisis/objs/WindowTool/WindowTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..82eaed00d206ed033dc4583737ec99c8965e9a9b --- /dev/null +++ b/isis/src/qisis/objs/WindowTool/WindowTool.cpp @@ -0,0 +1,317 @@ +#include "WindowTool.h" + +#include + +#include "MdiCubeViewport.h" +#include "MainWindow.h" +#include "Workspace.h" + +namespace Qisis +{ + /** + * WindowTool constructor. + * + * + * @param parent + */ + WindowTool::WindowTool(QWidget *parent) : Qisis::Tool(parent) + { + p_cascadeWindows = new QAction(parent); + p_cascadeWindows->setText("&Cascade"); + p_cascadeWindows->setEnabled(false); + + p_tileWindows = new QAction(parent); + p_tileWindows->setText("&Tile"); + p_tileWindows->setEnabled(false); + + p_resizeWindows = new QAction(parent); + p_resizeWindows->setText("Resize"); + p_resizeWindows->setEnabled(true); + connect(p_resizeWindows, SIGNAL(activated()), this, SLOT(resizeWindows())); + QString text = "Function: Resize all linked viewports to the same \ + size as the active viewport."; + p_resizeWindows->setWhatsThis(text); + + p_closeWindow = new QAction(parent); + p_closeWindow->setText("Close"); + p_closeWindow->setShortcut(Qt::Key_F3); + p_closeWindow->setEnabled(false); + + p_closeAllWindows = new QAction(parent); + p_closeAllWindows->setText("Close All"); + p_closeAllWindows->setShortcut(Qt::CTRL + Qt::Key_F3); + p_closeAllWindows->setEnabled(false); + + p_nextWindow = new QAction(parent); + p_nextWindow->setText("&Next"); + p_nextWindow->setShortcut(Qt::Key_F5); + p_nextWindow->setEnabled(false); + + p_prevWindow = new QAction(parent); + p_prevWindow->setText("&Prev"); + p_prevWindow->setShortcut(Qt::Key_F6); + p_prevWindow->setEnabled(false); + + QIcon icon; + icon.addPixmap(toolIconDir() + "/linked.png", QIcon::Normal, QIcon::On); + icon.addPixmap(toolIconDir() + "/unlinked.png", QIcon::Normal, QIcon::Off); + p_linkWindow = new QAction(parent); + p_linkWindow->setIcon(icon); + p_linkWindow->setText("&Link"); + p_linkWindow->setToolTip("Link viewports"); + text = + "Function: Used to link viewports. Some tools apply their \ + functions to all linked viewports. For example, when the zoom tool \ + is used on a linked viewport then all other linked viewports will zoom \ + as well. \ +

    Shortcut: Ctrl+L

    \ +

    Hint: The icons and at the left edge \ + of each viewport titlebar indicate the current link state

    \ +

    Tools using Link: Zoom, Pan, Blink, and Advanced Tracking

    "; + p_linkWindow->setWhatsThis(text); + p_linkWindow->setShortcut(Qt::CTRL + Qt::Key_L); + p_linkWindow->setCheckable(true); + p_linkWindow->setEnabled(false); + + p_linkAllWindows = new QAction(parent); + p_linkAllWindows->setText("&Link All"); + p_linkAllWindows->setToolTip("Link all viewports"); + p_linkAllWindows->setWhatsThis("Function: Links all open viewports \ + together.

    Shortcut: Ctrl+Shift+L"); + p_linkAllWindows->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_L); + p_linkAllWindows->setEnabled(false); + connect(p_linkAllWindows, SIGNAL(activated()), this, SLOT(linkWindows())); + + p_unlinkAllWindows = new QAction(parent); + p_unlinkAllWindows->setText("&Unlink All"); + p_unlinkAllWindows->setToolTip("Unlink all viewports"); + p_unlinkAllWindows->setWhatsThis("Function: Unlinks all open viewports. \ +

    Shortcut: Ctrl+Shift+U"); + p_unlinkAllWindows->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_U); + p_unlinkAllWindows->setEnabled(false); + connect(p_unlinkAllWindows, SIGNAL(activated()), this, SLOT(unlinkWindows())); + + p_changeCursor = new QAction(parent); + p_changeCursor->setText("Change cursor to arrow."); + p_changeCursor->setWhatsThis("Function: Toggles the cursor shape between \ + and arrow and crosshair cursor when cursor is over the \ + viewport window."); + p_changeCursor->setEnabled(false); + connect(p_changeCursor, SIGNAL(activated()), this, SLOT(changeCursor())); + + + activate(true); + } + + + /** + * Adds the window to the workspace. + * + * + * @param ws + */ + void WindowTool::addTo(Workspace *ws) + { + Tool::addTo(ws); + connect(p_cascadeWindows, SIGNAL(activated()), ws, SLOT(cascadeSubWindows())); + connect(p_tileWindows, SIGNAL(activated()), ws, SLOT(tileSubWindows())); + connect(p_prevWindow, SIGNAL(activated()), ws, SLOT(activatePreviousSubWindow())); + connect(p_nextWindow, SIGNAL(activated()), ws, SLOT(activateNextSubWindow())); + connect(p_closeWindow, SIGNAL(activated()), ws, SLOT(closeActiveSubWindow())); + connect(p_closeAllWindows, SIGNAL(activated()), ws, SLOT(closeAllSubWindows())); + } + + + /** + * Adds the link window action to the tool bar. + * + * + * @param perm + */ + void WindowTool::addToPermanent(QToolBar *perm) + { + perm->addAction(p_linkWindow); + } + + + /** + * Adds the cascade windows, tile windows, resize windows, next + * window, previous window, close window, and close all windows + * actions to the menu. + * + * + * @param menu + */ + void WindowTool::addTo(QMenu *menu) + { + menu->addAction(p_cascadeWindows); + menu->addAction(p_tileWindows); + menu->addAction(p_resizeWindows); + menu->addSeparator(); + + menu->addAction(p_changeCursor); + menu->addSeparator(); + + menu->addAction(p_nextWindow); + menu->addAction(p_prevWindow); + menu->addAction(p_closeWindow); + menu->addAction(p_closeAllWindows); + menu->addSeparator(); + + menu->addAction(p_linkWindow); + menu->addAction(p_linkAllWindows); + menu->addAction(p_unlinkAllWindows); + } + + + /** + * Adds the connections to the cube viewport. + * + * + * @param cvp + */ + void WindowTool::addConnections(MdiCubeViewport *cvp) + { + connect(p_linkWindow, SIGNAL(toggled(bool)), + cubeViewport(), SLOT(setLinked(bool))); + connect(cvp, SIGNAL(linkChanging(bool)), p_linkWindow, SLOT(setChecked(bool))); + } + + + /** + * Removes the connections from the cube viewport. + * + * + * @param cvp + */ + void WindowTool::removeConnections(MdiCubeViewport *cvp) + { + disconnect(p_linkWindow, SIGNAL(toggled(bool)), + cubeViewport(), SLOT(setLinked(bool))); + disconnect(cvp, SIGNAL(linkChanging(bool)), p_linkWindow, SLOT(setChecked(bool))); + } + + + /** + * Links all viewport windows in the workspace. + * + */ + void WindowTool::linkWindows() + { + MdiCubeViewport *d; + for (int i = 0; i < (int)cubeViewportList()->size(); i++) + { + d = (*(cubeViewportList()))[i]; + d->setLinked(true); + } + } + + + /** + * Unlinks all the viewport windows in the workspace. + * + */ + void WindowTool::unlinkWindows() + { + MdiCubeViewport *d; + for (int i = 0; i < (int)cubeViewportList()->size(); i++) + { + d = (*(cubeViewportList()))[i]; + d->setLinked(false); + } + } + + /** + * toggles the cursor from an arrow to a crosshair. + * + */ + void WindowTool::changeCursor() + { + MdiCubeViewport *d; + for (int i = 0; i < (int)cubeViewportList()->size(); i++) + { + d = (*(cubeViewportList()))[i]; + if (d->viewport()->cursor().shape() == Qt::CrossCursor) + { + d->changeCursor(QCursor(Qt::ArrowCursor)); + p_changeCursor->setText("Change cursor to crosshair."); + } + else + { + d->changeCursor(QCursor(Qt::CrossCursor)); + p_changeCursor->setText("Change cursor to arrow."); + } + } + } + + + /** + * Resizes all the viewport windows to the active viewport + * window size. + * + */ + void WindowTool::resizeWindows() + { + MdiCubeViewport *d; + QSize size = cubeViewport()->parentWidget()->size(); + + for (int i = 0; i < (int)cubeViewportList()->size(); i++) + { + d = (*(cubeViewportList()))[i]; + if (d->isLinked()) d->parentWidget()->parentWidget()->resize(size); + } + } + + + /** + * Updates the WindowTool. + * + */ + void WindowTool::updateTool() + { + if (cubeViewport() == NULL) + { + p_linkWindow->setChecked(false); + p_linkWindow->setEnabled(false); + p_linkAllWindows->setEnabled(false); + p_unlinkAllWindows->setEnabled(false); + p_cascadeWindows->setEnabled(false); + p_tileWindows->setEnabled(false); + p_resizeWindows->setEnabled(false); + p_closeWindow->setEnabled(false); + p_closeAllWindows->setEnabled(false); + p_nextWindow->setEnabled(false); + p_prevWindow->setEnabled(false); + p_changeCursor->setEnabled(false); + } + else + { + p_cascadeWindows->setEnabled(true); + p_tileWindows->setEnabled(true); + p_resizeWindows->setEnabled(true); + p_closeWindow->setEnabled(true); + p_closeAllWindows->setEnabled(true); + p_changeCursor->setEnabled(true); + + if (cubeViewportList()->size() > 1) + { + p_linkWindow->setEnabled(true); + p_linkAllWindows->setEnabled(true); + p_unlinkAllWindows->setEnabled(true); + p_nextWindow->setEnabled(true); + p_prevWindow->setEnabled(true); + p_linkWindow->setChecked(cubeViewport()->isLinked()); + } + else + { + p_linkWindow->setEnabled(false); + p_linkAllWindows->setEnabled(false); + p_unlinkAllWindows->setEnabled(false); + p_nextWindow->setEnabled(false); + p_prevWindow->setEnabled(false); + } + } + } +} diff --git a/isis/src/qisis/objs/WindowTool/WindowTool.h b/isis/src/qisis/objs/WindowTool/WindowTool.h new file mode 100644 index 0000000000000000000000000000000000000000..970643016abb47a2b836244f470f0ef99d5e75ff --- /dev/null +++ b/isis/src/qisis/objs/WindowTool/WindowTool.h @@ -0,0 +1,59 @@ +#ifndef WindowTool_h +#define WindowTool_h + +#include "Tool.h" + +class QAction; + +namespace Qisis +{ + class MdiCubeViewport; + + /** + * @internal + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport instead of + * CubeViewPort. Fixed include issues + */ + class WindowTool : public Qisis::Tool + { + Q_OBJECT + + public: + WindowTool(QWidget * parent); + void addTo(QMenu * menu); + void addTo(Workspace *ws); + void addToPermanent(QToolBar * toolbar); + + protected: + //! Returns the menu name. + QString menuName() const + { + return "&Window"; + }; + void updateTool(); + void addConnections(MdiCubeViewport * cvp); + void removeConnections(MdiCubeViewport * cvp); + + private slots: + void linkWindows(); + void unlinkWindows(); + void resizeWindows(); + void changeCursor(); + + private: + QAction *p_cascadeWindows; //!< cascade windows action + QAction *p_tileWindows; //!< tile windows action + QAction *p_resizeWindows; //!< resize windows action + QAction *p_prevWindow; //!< previous window action + QAction *p_nextWindow; //!< next window action + QAction *p_closeWindow; //!< close window action + QAction *p_closeAllWindows; //!< close all action + QAction *p_linkWindow; //!< link window action + QAction *p_linkAllWindows; //!< link all windows action + QAction *p_unlinkAllWindows; //!< unlink all windows action + QAction *p_changeCursor; //!< changes the cursor when it moves over the viewport + }; +}; + +#endif + diff --git a/isis/src/qisis/objs/Workspace/Makefile b/isis/src/qisis/objs/Workspace/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/Workspace/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/Workspace/Workspace.cpp b/isis/src/qisis/objs/Workspace/Workspace.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38cdc25440dc2bf297112cd03d58d36bd20cbc03 --- /dev/null +++ b/isis/src/qisis/objs/Workspace/Workspace.cpp @@ -0,0 +1,224 @@ +#include "Workspace.h" + +#include +#include +#include +#include + +#include "Cube.h" +#include "CubeAttribute.h" +#include "iString.h" +#include "MdiCubeViewport.h" + + + +namespace Qisis +{ + + /** + * Workspace constructor + * + * @param parent + */ + Workspace::Workspace(QWidget *parent) : QMdiArea(parent) + { + p_cubeViewportList = NULL; + p_cubeViewportList = new QVector< MdiCubeViewport * >; + + connect(this, SIGNAL(subWindowActivated(QMdiSubWindow *)), + this, SLOT(activateViewport(QMdiSubWindow *))); + setActivationOrder(ActivationHistoryOrder); + } + + + Workspace::Workspace(const Workspace & other) : p_cubeViewportList(NULL) + { + p_cubeViewportList = + new QVector< MdiCubeViewport * >(*other.p_cubeViewportList); + } + + + Workspace::~Workspace() + { + if (p_cubeViewportList) + { + delete p_cubeViewportList; + p_cubeViewportList = NULL; + } + } + + + /** + * This gets called when a window is activated or the workspace loses focus. + * + * @param w + */ + void Workspace::activateViewport(QMdiSubWindow *w) + { + if (w) + { + emit cubeViewportActivated((Qisis::MdiCubeViewport *) w->widget()->layout()->itemAt(0)->widget()); + } + //Check if there is no current window (on close) + else if (!currentSubWindow()) + { + emit cubeViewportActivated((Qisis::MdiCubeViewport *)NULL); + } + } + + /** + * Repopulates the list of MdiCubeViewports and returns a pointer to this list. + * Ownership is not given to the caller. + * + * @return std::vector* + */ + QVector< MdiCubeViewport * > * Workspace::cubeViewportList() + { + p_cubeViewportList->clear(); + + for (int i = 0; i < subWindowList().size(); i++) + { + p_cubeViewportList->push_back((MdiCubeViewport *) + subWindowList()[i]->widget()->layout()->itemAt(0)->widget()); + } + + return p_cubeViewportList; + } + + /** + * Add a cubeViewport to the workspace, open the cube. + * + * @param cubename[in] (QString) cube name + * + * @internal + * @history 2006-06-12 Tracie Sucharski, Clear errors after catching when + * attempting to open cube. + * @history 2007-02-13 Tracie Sucharski, Open cube read, not read/write. + * Opening read/write was done to accomodate the + * EditTool. EditTool will now reopen the cube + * read/write. + * @history 2008-05-27 Noah Hilt, When opening a cube now if a + * user specifies extra arguments to the cube name, + * the cube will be opened using a CubeAttributeInput + * specifically for the number and index of bands to + * be opened. Additionally, if a cube is opened with 3 + * bands it will be opened in RGB mode with red, + * green, and blue set to the 3 bands respectively. + * @history 2008-12-04 Jeannie Walldren - Removed "delete cube" + * since this was causing a segfault and this + * deallocation is already taking place in + * addCubeViewport(cube). + * + */ + void Workspace::addCubeViewport(QString cubename) + { + Isis::Cube *cube = new Isis::Cube; + + //Read in the CubeAttribueInput from the cube name + Isis::CubeAttributeInput inAtt(cubename.toStdString()); + std::vector bands = inAtt.Bands(); + //Set the virtual bands to the bands specified by the input + cube->SetVirtualBands(bands); + cube->Open(cubename.toStdString()); + + MdiCubeViewport *cvp = addCubeViewport(cube); + + // Check for RGB format (#R,#G,#B) + if (bands.size() == 3) + { + Isis::iString st = Isis::iString(bands.at(0)); + int index_red = st.ToInteger(); + st = Isis::iString(bands.at(1)); + int index_green = st.ToInteger(); + st = Isis::iString(bands.at(2)); + int index_blue = st.ToInteger(); + cvp->viewRGB(index_red, index_green, index_blue); + } + } + + /** + * Add a cubeViewport to the workspace. + * + * @param cube[in] (Isis::Cube *) cube information + * + * @internal + * + * @history 2007-04-13 Tracie Sucharski - Load entire image instead of + * fitting smallest dimension. + * @history 2008-05-27 Noah Hilt - Now returns a MdiCubeViewport + * in order for the addCubeViewport(QString cubename) + * method to modify the MdiCubeViewport. + * @history 2008-08-20 Stacy Alley - Changed the setScale call + * to match the zoomTool's fit in view + * @history 2008-12-04 Jeannie Walldren - Added try/catch to + * close the MdiCubeViewport if showCube() is not + * successful. + */ + MdiCubeViewport* Workspace::addCubeViewport(Isis::Cube *cube) + { + Qisis::MdiCubeViewport *cvp = NULL; + + QMdiSubWindow *window = new QMdiSubWindow; + window->setOption(QMdiSubWindow::RubberBandResize, true); + window->setOption(QMdiSubWindow::RubberBandMove, true); + + try + { + QWidget *centralWidget = new QWidget(this); + QVBoxLayout *layout = new QVBoxLayout(); + + cvp = new Qisis::MdiCubeViewport(cube, centralWidget); + QProgressBar *progress = new QProgressBar(); + connect(cvp, SIGNAL(progressChanged(int)), progress, SLOT(setValue(int))); + progress->setRange(0, 100); + + layout->addWidget(cvp); + layout->addWidget(progress); + + centralWidget->setLayout(layout); + + window->setWidget(centralWidget); + + window->setAttribute(Qt::WA_DeleteOnClose); + addSubWindow(window); + + window->show(); + } + catch (Isis::iException &e) + { + // close MdiCubeViewport window + cvp->close(); + // add a new message to the caught exception and throw + throw e.Message(Isis::iException::Programmer, + "Exception caught when attempting to show cube " + + cube->Filename(), + _FILEINFO_); + } + + emit cubeViewportAdded(cvp); + + return cvp; + } + + void Workspace::addBrowseView(QString cubename) + { + /* Close the last browse window if necessary. */ + if (subWindowList().size() > 0) + { + removeSubWindow(subWindowList()[0]); + } + + addCubeViewport(cubename); + } + + + const Workspace & Workspace::operator=(Workspace other) + { + delete p_cubeViewportList; + p_cubeViewportList = NULL; + + p_cubeViewportList = new QVector< MdiCubeViewport * >; + *p_cubeViewportList = *other.p_cubeViewportList; + return *this; + } +} diff --git a/isis/src/qisis/objs/Workspace/Workspace.h b/isis/src/qisis/objs/Workspace/Workspace.h new file mode 100644 index 0000000000000000000000000000000000000000..7e281ea75c555ae4cb94918c9e3a1af0a8f6da84 --- /dev/null +++ b/isis/src/qisis/objs/Workspace/Workspace.h @@ -0,0 +1,94 @@ +#ifndef Workspace_h +#define Workspace_h +/** + * @file + * $Revision: 1.9 $ + * $Date: 2010/06/28 08:36:36 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +#include + +template< class T > class QVector; + +namespace Isis +{ + class Cube; +} + +namespace Qisis +{ + class MdiCubeViewport; + + /** + * @brief + * + * @ingroup Visualization Tools + * + * @author ??? Jeff Anderson + * + * @internal + * @history 2007-03-21 Tracie Sucharski - Changed call from fitScale to + * fitScaleMinDimension so that the minimum cube + * dimension is displayed in its entirety. + * @history 2008-05-27 Noah Hilt - Now allows cubes to be + * opened with additional arguments read by the + * CubeAttributeInput class, specifically to open + * certain bands as well as open 3 bands in RGB mode. + * @history 2008-12-04 Jeannie Walldren - Fixed bug in + * addCubeViewport(cubename). Added exception catch to + * addCubeViewport(cube) to close the CubeViewport from + * the ViewportMainWindow if it cannot be shown. + * @history 2009-03-27 Noah Hilt, Steven Lambright - Changed parent class from + * QWorkspace to QMdiArea since QWorkspace is now an obsolete class. + * Also changed how CubeViewports are created. + * @history 2010-04-08 Steven Lambright and Eric Hyer - Added progress bar + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport instead of + * CubeViewport. Also fixed include issues. + */ + class Workspace : public QMdiArea + { + Q_OBJECT + + public: + Workspace(QWidget * parent = 0); + Workspace(const Workspace & other); + virtual ~Workspace(); + QVector< MdiCubeViewport * > * cubeViewportList(); + const Workspace & operator=(Workspace other); + + signals: + void cubeViewportAdded(Qisis::MdiCubeViewport *); + void cubeViewportActivated(Qisis::MdiCubeViewport *); + + public slots: + void addCubeViewport(QString cube); + MdiCubeViewport * addCubeViewport(Isis::Cube *cube); + + void addBrowseView(QString cube); + + protected slots: + void activateViewport(QMdiSubWindow * w); + + private: + QVector< MdiCubeViewport * > * p_cubeViewportList; + }; +}; + +#endif diff --git a/isis/src/qisis/objs/ZoomTool/Makefile b/isis/src/qisis/objs/ZoomTool/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..08a92efe72f7296e5204a1843dd1a6663b85bd7b --- /dev/null +++ b/isis/src/qisis/objs/ZoomTool/Makefile @@ -0,0 +1,9 @@ +INCS := $(wildcard *.h) +QOBJ := $(shell grep -HIE -m1 'Q_OBJECT' $(INCS)) #get all header files with 'Q_OBJECT' Output=%.h: QOBJECT +QCOLN := $(filter-out Q_OBJECT, $(QOBJ)) #filter out 'Q_OBJECT from the Output +QINC := $(subst :, , $(QCOLN)) #substitute ':' with '' +CPPS := $(filter-out moc_%.cpp, $(wildcard *.cpp))#all the non moc cpp files +SRCS := $(CPPS) $(QINC:%.h=moc_%.cpp) +OBJS := $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/qisis/objs/ZoomTool/ZoomTool.cpp b/isis/src/qisis/objs/ZoomTool/ZoomTool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70f3f16d3391efe36b4fadfa3f2cf6bc1dc6daca --- /dev/null +++ b/isis/src/qisis/objs/ZoomTool/ZoomTool.cpp @@ -0,0 +1,563 @@ +/** + * @file + * $Date: 2010/06/28 09:24:10 $ + * $Revision: 1.9 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "MdiCubeViewport.h" +#include "RubberBandTool.h" +#include "MainWindow.h" +#include "ToolPad.h" +#include "Workspace.h" +#include "ZoomTool.h" + +namespace Qisis { + /** + * ZoomTool constructor + * + * + * @param parent + */ + ZoomTool::ZoomTool (QWidget *parent) : Qisis::Tool(parent) { + p_userCursor = QCursor(); + + p_zoomIn2X = new QAction(parent); + p_zoomIn2X->setShortcut(Qt::Key_Plus); + p_zoomIn2X->setText("Zoom In"); + p_zoomIn2X->setIcon(QPixmap(toolIconDir()+"/viewmag+.png")); + connect(p_zoomIn2X,SIGNAL(activated()),this,SLOT(zoomIn2X())); + + p_zoomIn4X = new QAction(parent); + p_zoomIn4X->setText("Zoom In 4X"); + p_zoomIn4X->setShortcut(Qt::CTRL+Qt::Key_Plus); + connect(p_zoomIn4X,SIGNAL(activated()),this,SLOT(zoomIn4X())); + + p_zoomIn8X = new QAction(parent); + p_zoomIn8X->setShortcut(Qt::ALT+Qt::Key_Plus); + p_zoomIn8X->setText("Zoom In 8X"); + connect(p_zoomIn8X,SIGNAL(activated()),this,SLOT(zoomIn8X())); + + p_zoomOut2X = new QAction(parent); + p_zoomOut2X->setShortcut(Qt::Key_Minus); + p_zoomOut2X->setText("Zoom Out"); + p_zoomOut2X->setIcon(QPixmap(toolIconDir()+"/viewmag-.png")); + connect(p_zoomOut2X,SIGNAL(activated()),this,SLOT(zoomOut2X())); + + p_zoomOut4X = new QAction(parent); + p_zoomOut4X->setShortcut(Qt::CTRL+Qt::Key_Minus); + p_zoomOut4X->setText("Zoom Out 4X"); + connect(p_zoomOut4X,SIGNAL(activated()),this,SLOT(zoomOut4X())); + + p_zoomOut8X = new QAction(parent); + p_zoomOut8X->setShortcut(Qt::ALT+Qt::Key_Minus); + p_zoomOut8X->setText("Zoom Out 8X"); + connect(p_zoomOut8X,SIGNAL(activated()),this,SLOT(zoomOut8X())); + + p_zoomActual = new QAction (parent); + p_zoomActual->setShortcut(Qt::Key_Slash); + p_zoomActual->setText("&Actual Pixels"); + p_zoomActual->setIcon(QPixmap(toolIconDir()+"/viewmag1.png")); + connect(p_zoomActual,SIGNAL(activated()),this,SLOT(zoomActual())); + + p_zoomFit = new QAction (parent); + p_zoomFit->setShortcut(Qt::Key_Asterisk); + p_zoomFit->setText("&Fit in Window"); + p_zoomFit->setIcon(QPixmap(toolIconDir()+"/viewmagfit.png")); + connect(p_zoomFit,SIGNAL(activated()),this,SLOT(zoomFit())); + + } + + /** + * Adds the action to the toolpad. + * + * + * @param toolpad + * + * @return QAction* + */ + QAction *ZoomTool::toolPadAction(ToolPad *toolpad) { + QAction *action = new QAction(toolpad); + action->setIcon(QPixmap(toolIconDir()+"/viewmag.png")); + action->setToolTip("Zoom (Z)"); + action->setShortcut(Qt::Key_Z); + QString text = + "Function: Zoom in or out of the current cube. \ +

    Shortcut: Z

    "; + action->setWhatsThis(text); + return action; + } + + + /** + * Adds the zoom action to the given menu. + * + * + * @param menu + */ + void ZoomTool::addTo(QMenu *menu) { + menu->addAction(p_zoomFit); + menu->addAction(p_zoomActual); + menu->addAction(p_zoomIn2X); + menu->addAction(p_zoomOut2X); + } + + + /** + * Creates the widget to add to the tool bar. + * + * + * @param parent + * + * @return QWidget* + */ + QWidget *ZoomTool::createToolBarWidget (QStackedWidget *parent) { + QWidget *hbox = new QWidget(parent); + + QToolButton *zoomInButton = new QToolButton(hbox); + zoomInButton->setIcon(QPixmap(toolIconDir()+"/viewmag+.png")); + zoomInButton->setToolTip("Zoom In"); + QString text = + "Function: Zoom in 2X at the center of the active viewport \ +

    Shortcut: +

    \ +

    Mouse: LeftButton zooms in 2X under pointer

    \ +

    Modifiers: Shortcuts and mouse clicks can be augmented \ + using the Ctrl or Alt key for 4X and 8X zooms, respectively

    \ +

    Hint: Left click and drag for a local zoom which scales data \ + in the red marquee to the viewport

    "; + zoomInButton->setWhatsThis(text); + connect(zoomInButton,SIGNAL(clicked()),this,SLOT(zoomIn2X())); + zoomInButton->setAutoRaise(true); + zoomInButton->setIconSize(QSize(22,22)); + + QToolButton *zoomOutButton = new QToolButton(hbox); + zoomOutButton->setIcon(QPixmap(toolIconDir()+"/viewmag-.png")); + zoomOutButton->setToolTip("Zoom Out"); + text = + "Function: Zoom out 2X at the center of the active viewport \ +

    Shortcut: +

    \ +

    Mouse: RightButton zooms out 2X under pointer

    \ +

    Modifiers: Shortcuts and mouse clicks can be augmented \ + using the Ctrl or Alt key for 4X and 8X zooms, respectively

    \ +

    Hint: Left click and drag for a local zoom which scales data \ + in the red marquee to the viewport

    "; + zoomOutButton->setWhatsThis(text); + connect(zoomOutButton,SIGNAL(clicked()),this,SLOT(zoomOut2X())); + zoomOutButton->setAutoRaise(true); + zoomOutButton->setIconSize(QSize(22,22)); + + QToolButton *zoomActButton = new QToolButton(hbox); + zoomActButton->setIcon(QPixmap(toolIconDir()+"/viewmag1.png")); + zoomActButton->setToolTip("Zoom 1:1"); + text = + "Function: Zoom the active viewport to 1:1 such that one \ + viewport pixel represents one cube pixel. That is, 100% scale. \ +

    Shortcut: /

    \ +

    Mouse: Ctrl+MiddleButton zooms 1:1 under pointer

    \ +

    Hint: MiddleButton (without Ctrl) retains current \ + scale but moves the pixel under the pointer to the center of the \ + viewport

    "; + zoomActButton->setWhatsThis(text); + connect(zoomActButton,SIGNAL(clicked()),this,SLOT(zoomActual())); + zoomActButton->setAutoRaise(true); + zoomActButton->setIconSize(QSize(22,22)); + + // Create menu on the zoomFit button to select fitting the cube for + // width or height. + QMenu *zoomFitMenu = new QMenu(); + QAction *fitWidth = new QAction(this); + fitWidth->setText("Fit Width"); + connect (fitWidth,SIGNAL(triggered(bool)),this,SLOT(zoomFitWidth())); + zoomFitMenu->addAction(fitWidth); + + QAction *fitHeight = new QAction(this); + fitHeight->setText("Fit Height"); + connect (fitHeight,SIGNAL(triggered(bool)),this,SLOT(zoomFitHeight())); + zoomFitMenu->addAction(fitHeight); + + QToolButton *zoomFitButton = new QToolButton(hbox); + zoomFitButton->setIcon(QPixmap(toolIconDir()+"/viewmagfit.png")); + zoomFitButton->setMenu(zoomFitMenu); + zoomFitButton->setPopupMode(QToolButton::MenuButtonPopup); + zoomFitButton->setToolTip("Fit in viewport"); + text = + "Function: Fit the entire cube inside the active viewport. For \ + extremely large cubes, this may not be possible. \ +

    Shortcut: *

    \ +

    Hint: Many shortcuts for the zoom tool and other tools \ + are easily available on the numeric keypad

    "; + zoomFitButton->setWhatsThis(text); + connect(zoomFitButton,SIGNAL(clicked()),this,SLOT(zoomFit())); + zoomFitButton->setAutoRaise(true); + zoomFitButton->setIconSize(QSize(22,22)); + + p_zoomLineEdit = new QLineEdit(hbox); + p_zoomLineEdit->setText(""); + p_zoomLineEdit->setMaxLength(8); + p_zoomLineEdit->setMaximumWidth(80); + + QDoubleValidator *dval = new QDoubleValidator(hbox); + p_zoomLineEdit->setValidator(dval); + + QSizePolicy policy = p_zoomLineEdit->sizePolicy(); + policy.setHorizontalPolicy(QSizePolicy::Fixed); + p_zoomLineEdit->setSizePolicy(policy); + + p_zoomLineEdit->setToolTip("Scale"); + text = + "Function: Shows the scale of the active viewport. Additionally, \ + you can manually enter the scale."; + p_zoomLineEdit->setWhatsThis(text); + connect(p_zoomLineEdit,SIGNAL(returnPressed()),this,SLOT(zoomManual())); + + QHBoxLayout *layout = new QHBoxLayout(hbox); + layout->setMargin(0); + layout->addWidget(zoomInButton); + layout->addWidget(zoomOutButton); + layout->addWidget(zoomActButton); + layout->addWidget(zoomFitButton); + layout->addWidget(p_zoomLineEdit); + layout->addStretch(1); + hbox->setLayout(layout); + return hbox; + } + + /** + * Zooms in 2 times. + * + */ + void ZoomTool::zoomIn2X() { + zoomBy(2.0); + } + + + /** + * Zooms in 4 times. + * + */ + void ZoomTool::zoomIn4X() { + zoomBy(4.0); + } + + + /** + * Zooms in 8 times. + * + */ + void ZoomTool::zoomIn8X() { + zoomBy(8.0); + } + + + /** + * Zoom out 2 times. + * + */ + void ZoomTool::zoomOut2X() { + zoomBy(1.0/2.0); + } + + + /** + * Zoom out 4 times. + * + */ + void ZoomTool::zoomOut4X() { + zoomBy(1.0/4.0); + } + + + /** + * Zoom out 8 times. + * + */ + void ZoomTool::zoomOut8X() { + zoomBy(1.0/8.0); + } + + + /** + * Zoom back to 1 to 1. + * + */ + void ZoomTool::zoomActual () { + zoomBy(0.0); + } + + + /** + * Zoom by the given factor. + * + * + * @param factor + */ + void ZoomTool::zoomBy (double factor) { + MdiCubeViewport *d = cubeViewport(); + if (d == NULL) return; + double newScale = d->scale() * factor; + if (newScale == 0.0) newScale = 1.0; + d->setScale(newScale); + updateTool(); + + if (cubeViewport()->isLinked()) { + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + d = (*(cubeViewportList()))[i]; + if (d == cubeViewport()) continue; + if (d->isLinked()) { + newScale = d->scale() * factor; + if (newScale == 0.0) newScale = 1.0; + d->setScale(newScale); + } + } + } + } + + + /** + * Fits the cube in the viewport. + * + */ + void ZoomTool::zoomFit () { + MdiCubeViewport *d = cubeViewport(); + if (d == NULL) return; + d->setScale (d->fitScale(),d->cubeSamples()/2.0,d->cubeLines()/2.0); + updateTool(); + + if (d->isLinked()) { + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + d = (*(cubeViewportList()))[i]; + if (d == cubeViewport()) continue; + if (d->isLinked()) { + d->setScale (d->fitScale(),d->cubeSamples()/2.0,d->cubeLines()/2.0); + } + } + } + } + + + + /** + * Slot for the "Fit to Width" menu item on the Fit button. This will + * display the cube so that the entire cube width is displayed. + * + */ + void ZoomTool::zoomFitWidth () { + MdiCubeViewport *d = cubeViewport(); + if (d == NULL) return; + d->setScale (d->fitScaleWidth(),d->cubeSamples()/2.0,d->cubeLines()/2.0); + updateTool(); + + if (d->isLinked()) { + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + d = (*(cubeViewportList()))[i]; + if (d == cubeViewport()) continue; + if (d->isLinked()) { + d->setScale (d->fitScaleWidth(),d->cubeSamples()/2.0,d->cubeLines()/2.0); + } + } + } + } + + + /** + * Slot for the "Fit to Heighth" menu item on the Fit button. This will display + * the cube so that the entire cube heighth is displayed. + * + */ + void ZoomTool::zoomFitHeight () { + MdiCubeViewport *d = cubeViewport(); + if (d == NULL) return; + d->setScale (d->fitScaleHeight(),d->cubeSamples()/2.0,d->cubeLines()/2.0); + updateTool(); + + if (d->isLinked()) { + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + d = (*(cubeViewportList()))[i]; + if (d == cubeViewport()) continue; + if (d->isLinked()) { + d->setScale (d->fitScaleHeight(),d->cubeSamples()/2.0,d->cubeLines()/2.0); + } + } + } + } + + + /** + * This method zooms by the value input in the line edit next to + * the zoom tools. + * + */ + void ZoomTool::zoomManual () { + MdiCubeViewport *d = cubeViewport(); + if (d == NULL) return; + QString strScale = p_zoomLineEdit->text(); + double scale = strScale.toDouble() / 100.; + d->setScale(scale); + d->setFocus(); + updateTool(); + + if (d->isLinked()) { + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + d = (*(cubeViewportList()))[i]; + if (d == cubeViewport()) continue; + if (d->isLinked()) d->setScale(scale); + } + } + } + + + /** + * This method updates the line edits text to the correct zoom + * value. + * + */ + void ZoomTool::updateTool() { + if (cubeViewport() == NULL) { + p_zoomLineEdit->setText(""); + } + else { + double scale = cubeViewport()->scale() * 100.0; + QString strScale; + strScale.setNum(scale); + p_zoomLineEdit->setText(strScale); + } + } + + + /** + * This method is called when the RubberBandTool is complete. It + * will either zoom the CubeViewport to the rectangle specified + * by the RubberBandTool or will handle different zoom methods + * specified by the last RubberBandTool's mouse button. + * + */ + void ZoomTool::rubberBandComplete() { + QApplication::processEvents(); + MdiCubeViewport *d = cubeViewport(); + if (!RubberBandTool::isValid()) return; + + // The RubberBandTool has a rectangle + if (!RubberBandTool::isPoint()) { + QRect r = RubberBandTool::rectangle(); + if ((r.width() >= 5) && (r.height() >= 5)) { + int x = r.x() + r.width() / 2; + int y = r.y() + r.height() / 2; + double xscale = (double) d->viewport()->width() / r.width(); + double yscale = (double) d->viewport()->height() / r.height(); + double scale = xscale < yscale ? xscale : yscale; + if (RubberBandTool::mouseButton() & Qt::RightButton) scale = 1.0 / scale; + scale *= d->scale(); + d->setScale(scale,x,y); + updateTool(); + if (d->isLinked()) { + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + d = (*(cubeViewportList()))[i]; + if (d == cubeViewport()) continue; + if (d->isLinked()) { + int x = r.x() + r.width() / 2; + int y = r.y() + r.height() / 2; + double xscale = (double) d->viewport()->width() / r.width(); + double yscale = (double) d->viewport()->height() / r.height(); + double scale = xscale < yscale ? xscale : yscale; + if (RubberBandTool::mouseButton() & Qt::RightButton) scale = 1.0 / scale; + scale *= d->scale(); + d->setScale(scale,x,y); + } + } + } + } + } + // The RubberBandTool has a point (mouse click) + else { + double factor = 2.0; + if (RubberBandTool::mouseButton() & Qt::ControlModifier) factor = 4.0; + if (RubberBandTool::mouseButton() & Qt::ShiftModifier) factor = 8.0; + if (RubberBandTool::mouseButton() & Qt::RightButton) factor = 1.0 / factor; + if (RubberBandTool::mouseButton() & Qt::MidButton) factor = 1.0; + if (RubberBandTool::mouseButton() == Qt::MidButton+Qt::ControlModifier) factor = 0.0; + MdiCubeViewport *d = cubeViewport(); + double scale = d->scale() * factor; + if (scale == 0.0) scale = 1.0; + QPoint p = RubberBandTool::getVertices()[0]; + d->setScale(scale,p.x(),p.y()); + updateTool(); + + if (d->isLinked()) { + for (int i=0; i<(int)cubeViewportList()->size(); i++) { + d = (*(cubeViewportList()))[i]; + if (d == cubeViewport()) continue; + if (d->isLinked()) { + scale = d->scale() * factor; + if (scale == 0.0) scale = 1.0; + d->setScale(scale,p.x(),p.y()); + } + } + } + p_lastScale = scale; + } + + } + + + /** + * This methods enables the RubberBandTool, it also sets the + * RubberBandTool to allow points and to allow all clicks. + * + */ + void ZoomTool::enableRubberBandTool() { + RubberBandTool::enable(RubberBandTool::Rectangle); + RubberBandTool::allowPoints(); + RubberBandTool::allowAllClicks(); + } + + + /** + * + * + * + * @param p + * @param s + */ + void ZoomTool::mouseButtonPress(QPoint p, Qt::MouseButton s) { + if(s == Qt::RightButton) { + cubeViewport()->viewport()->setCursor(QCursor(QPixmap(toolIconDir()+"/viewmag-.png"))); + } else if (s == Qt::LeftButton) { + cubeViewport()->viewport()->setCursor(QCursor(QPixmap(toolIconDir()+"/viewmag+.png"))); + } + } + + + /** + * + * + * + * @param p + * @param s + */ + void ZoomTool::mouseButtonRelease(QPoint p, Qt::MouseButton s) { + //set the cursor back to the original cursor shape. + cubeViewport()->viewport()->setCursor(p_userCursor); + } + +} diff --git a/isis/src/qisis/objs/ZoomTool/ZoomTool.h b/isis/src/qisis/objs/ZoomTool/ZoomTool.h new file mode 100644 index 0000000000000000000000000000000000000000..b874e6c821b7d02c29d9a6c244733d48f957a8a4 --- /dev/null +++ b/isis/src/qisis/objs/ZoomTool/ZoomTool.h @@ -0,0 +1,113 @@ +#ifndef ZoomTool_h +#define ZoomTool_h + +/** + * @file + * $Date: 2010/06/28 09:24:10 $ + * $Revision: 1.7 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public domain. See + * individual third-party library and package descriptions for intellectual property information, + * user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, is made by the + * USGS as to the accuracy and functioning of such software and related material nor shall the + * fact of distribution constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + + +// This should be the only include in this file! +#include "Tool.h" + +// FIXME: remove this include +#include + +class QAction; +class QLineEdit; + +namespace Qisis { + /** + * @brief Handles zoom operations for Isis qt apps + * + * @ingroup Visualization Tools + * + * @author Jeff Anderson - ??? + * + * @internal + * @history 2007-03-21 Tracie Sucharski - Added zoomFitWidth + * and zoomFitHeight slots and changed + * the zoomFit button to contain a popup + * menu for "Fit to Width" & "Fit to + * Height". + * @history 2008-05-23 Noah Hilt - Added RubberBandTool + * functionality and changed the mouseButtonReleased + * Method. + * @history 2009-02-12 Steven Lambright - Fixed zooming in/out + * with rectangle rubber band + * @history 2010-06-26 Eric Hyer - Now uses MdiCubeViewport instead of + * CubeViewport. Fixed some include issues. + */ + class ZoomTool : public Tool { + Q_OBJECT + + public: + ZoomTool (QWidget *parent); + void addTo(QMenu *menu); + + protected slots: + void rubberBandComplete(); + + protected: + QAction *toolPadAction(ToolPad *toolpad); + //! Returns the name of the menu. + QString menuName() const { return "&View"; }; + void updateTool(); + QWidget *createToolBarWidget(QStackedWidget *parent); + void enableRubberBandTool(); + + private slots: + void zoomIn2X(); + void zoomIn4X(); + void zoomIn8X(); + + void zoomOut2X(); + void zoomOut4X(); + void zoomOut8X(); + + void zoomActual (); + void zoomFit (); + void zoomFitWidth (); + void zoomFitHeight (); + void zoomManual (); + + void mouseButtonPress(QPoint p, Qt::MouseButton s); + void mouseButtonRelease(QPoint p, Qt::MouseButton s); + + private: + void zoomBy (double factor); + + QAction *p_zoomIn2X; //!< Zoom in 2 times. + QAction *p_zoomIn4X; //!< Zoom in 4 times. + QAction *p_zoomIn8X; //!< Zoom in 8 times. + + QAction *p_zoomOut2X; //!< Zoom out 2 times. + QAction *p_zoomOut4X; //!< Zoom out 4 times. + QAction *p_zoomOut8X; //!< Zoom out 8 times. + + QAction *p_zoomActual; //!< Zoom to actual size action. + QAction *p_zoomFit; //!< Fit the cube in the viewport action. + + QLineEdit *p_zoomLineEdit; //!< Line edit for manual zoom factor. + double p_lastScale; + QCursor p_userCursor; + }; +}; + +#endif + diff --git a/isis/src/rolo/Makefile b/isis/src/rolo/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/rolo/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/rolo/apps/Makefile b/isis/src/rolo/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/rolo/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/rolo/apps/rolo2isis/Makefile b/isis/src/rolo/apps/rolo2isis/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/rolo/apps/rolo2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/rolo/apps/rolo2isis/assets/images/roloExampleGUI.png b/isis/src/rolo/apps/rolo2isis/assets/images/roloExampleGUI.png new file mode 100644 index 0000000000000000000000000000000000000000..71a29f78cd0118f4a5dc3eef028240c5b1a529ad Binary files /dev/null and b/isis/src/rolo/apps/rolo2isis/assets/images/roloExampleGUI.png differ diff --git a/isis/src/rolo/apps/rolo2isis/assets/thumbs/roloExampleThumbGUI.png b/isis/src/rolo/apps/rolo2isis/assets/thumbs/roloExampleThumbGUI.png new file mode 100644 index 0000000000000000000000000000000000000000..4cc4eb83bee905180c86f37e196e5514f1e466bb Binary files /dev/null and b/isis/src/rolo/apps/rolo2isis/assets/thumbs/roloExampleThumbGUI.png differ diff --git a/isis/src/rolo/apps/rolo2isis/rolo2isis.cpp b/isis/src/rolo/apps/rolo2isis/rolo2isis.cpp new file mode 100755 index 0000000000000000000000000000000000000000..b4e4131d6dd19a8dd19087f9a1146a8ebae2e37f --- /dev/null +++ b/isis/src/rolo/apps/rolo2isis/rolo2isis.cpp @@ -0,0 +1,87 @@ +#include "Isis.h" +#include "ProcessImportPds.h" +#include "UserInterface.h" +#include "Filename.h" +#include "Pvl.h" +#include "PvlTranslationManager.h" + +using namespace std; +using namespace Isis; + +void IsisMain () +{ + UserInterface &ui = Application::GetUserInterface(); + string labelFile = ui.GetFilename("FROM"); + + ProcessImportPds p; + Pvl label; + p.SetPdsFile (labelFile, "", label); + Cube * ocube = p.SetOutputCube("TO"); + p.StartProcess (); + + PvlGroup & dataDir = Preference::Preferences().FindGroup("DataDirectory"); + iString transDir = (string) dataDir["Rolo"]; + + Filename transFile; + Pvl inputLabel(labelFile); + Pvl outputLabel; + PvlTranslationManager * translator; + + // translate Mapping group + transFile = transDir + "/" + "translations/roloMapping.trn"; + translator = new PvlTranslationManager(inputLabel, transFile.Expanded()); + translator->Auto(outputLabel); + delete translator; + translator = NULL; + + // translate Instrument group + transFile = transDir + "/" + "translations/roloInstrument.trn"; + translator = new PvlTranslationManager(inputLabel, transFile.Expanded()); + translator->Auto(outputLabel); + delete translator; + translator = NULL; + + // translate BandBin group + transFile = transDir + "/" + "translations/roloBandBin.trn"; + translator = new PvlTranslationManager(inputLabel, transFile.Expanded()); + translator->Auto(outputLabel); + outputLabel.FindGroup("BandBin").FindKeyword("OriginalBand").SetUnits( + translator->Translate("BandBinUnit")); + outputLabel.FindGroup("BandBin").FindKeyword("Center").SetUnits(translator-> + Translate("BandBinUnit")); + outputLabel.FindGroup("BandBin").FindKeyword("Width").SetUnits(translator-> + Translate("BandBinUnit")); + outputLabel.FindGroup("BandBin").FindKeyword("Exposure").SetUnits(translator-> + Translate("ExposureUnit")); + delete translator; + translator = NULL; + + // translate Archive group + transFile = transDir + "/" + "translations/roloArchive.trn"; + translator = new PvlTranslationManager(inputLabel, transFile.Expanded()); + translator->Auto(outputLabel); + delete translator; + translator = NULL; + + // add outputLabel to cube + if (outputLabel.HasGroup("Mapping") && + (outputLabel.FindGroup("Mapping").Keywords() > 0)) { + ocube->PutGroup(outputLabel.FindGroup("Mapping")); + } + if (outputLabel.HasGroup("Instrument") && + (outputLabel.FindGroup("Instrument").Keywords() > 0)) { + ocube->PutGroup(outputLabel.FindGroup("Instrument")); + } + if (outputLabel.HasGroup("BandBin") && + (outputLabel.FindGroup("BandBin").Keywords() > 0)) { + ocube->PutGroup(outputLabel.FindGroup("BandBin")); + } + if (outputLabel.HasGroup("Archive") && + (outputLabel.FindGroup("Archive").Keywords() > 0)) { + ocube->PutGroup(outputLabel.FindGroup("Archive")); + } + + p.EndProcess (); + + return; +} diff --git a/isis/src/rolo/apps/rolo2isis/rolo2isis.xml b/isis/src/rolo/apps/rolo2isis/rolo2isis.xml new file mode 100755 index 0000000000000000000000000000000000000000..422c151104e00b09f88034bfec8dadb40e7296f5 --- /dev/null +++ b/isis/src/rolo/apps/rolo2isis/rolo2isis.xml @@ -0,0 +1,93 @@ + + + + + Import isis2 rolo image into isis3 + + + This program will import an isis2 rolo image into an isis3 cube. + + + + + Original version + + + + + Import and Export + + + + + + + + filename + input + + Input rolo isis2 file + + + Use this parameter to select the isis2 filename. + + + *.alx *.cub + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + + + + + + + + Using rolo2isis + + + The use of rolo2isis to ingest rolo isis2 data and output isis3 cubes + + + + from=mm185801.alx + to=mm185801.cub + + + This example shows the use of rolo2isis to create an Isis3 cube + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters + + + + + + + + + + diff --git a/isis/src/rolo/apps/rolo2isis/tsts/Makefile b/isis/src/rolo/apps/rolo2isis/tsts/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/rolo/apps/rolo2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/rolo/apps/rolo2isis/tsts/default/Makefile b/isis/src/rolo/apps/rolo2isis/tsts/default/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..6d3d4c2243459f9054c40fa0cedc78f8e5c72bf9 --- /dev/null +++ b/isis/src/rolo/apps/rolo2isis/tsts/default/Makefile @@ -0,0 +1,8 @@ +APPNAME = rolo2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/mm185801.alx \ + to=$(OUTPUT)/mm185801.cub > /dev/null; + catlab from=$(OUTPUT)/mm185801.cub >& $(OUTPUT)/labels.pvl; diff --git a/isis/src/rolo/objs/Makefile b/isis/src/rolo/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/rolo/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/system/Makefile b/isis/src/system/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6d2b3727025ae72c62fe568187d8340cba50a233 --- /dev/null +++ b/isis/src/system/Makefile @@ -0,0 +1,2 @@ +include $(ISISROOT)/make/isismake.cat + diff --git a/isis/src/system/apps/Makefile b/isis/src/system/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/system/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/system/apps/blobdump/Makefile b/isis/src/system/apps/blobdump/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/system/apps/blobdump/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/system/apps/blobdump/blobdump.cpp b/isis/src/system/apps/blobdump/blobdump.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8365347fec593932086e802fc4b8af9207a66dc --- /dev/null +++ b/isis/src/system/apps/blobdump/blobdump.cpp @@ -0,0 +1,92 @@ +#define GUIHELPERS + +#include "Isis.h" + +#include + +#include "Blob.h" +#include "Table.h" +#include "Filename.h" +#include "iString.h" +#include + +using namespace std; +using namespace Isis; + +int pos = 0; +string previousFile = ""; + +void helperButtonGetBlobList(); + +map GuiHelpers(){ + map helper; + helper ["helperButtonGetBlobList"] = (void*) helperButtonGetBlobList; + return helper; +} + +void IsisMain(){ + UserInterface &ui = Application::GetUserInterface(); + Filename file = ui.GetFilename("FROM"); + string blobname = ui.GetString("NAME"); + string blobtype = ui.GetString("TYPE"); + Blob blob( blobname, blobtype, file.Expanded()); + Filename outfname = ui.GetFilename("TO"); + blob.Write(outfname.Expanded()); +} + +// Function to find the available blob names/types and put them into the GUI +void helperButtonGetBlobList() { + string name, type; + bool match = false; + + UserInterface &ui = Application::GetUserInterface(); + string currentFile = ui.GetFilename("FROM"); + const Pvl label (Filename(currentFile).Expanded()); + + // Check to see if the "FILE" parameter has changed since last press + if (currentFile != previousFile) { + ui.Clear("NAME"); + ui.Clear("TYPE"); + pos = 0; + previousFile = currentFile; + } + + // Look for blobs + int cnt = 0; + while (!match) { + // If we've gone through all objects and found nothing, throw an exception + if (cnt >= label.Objects()) { + pos = 0; + string msg = "Parameter [FROM] has no blobs."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + // When the end of the objects is hit, + // display "NAME" and "TYPE" parameters as blank + if (pos >= label.Objects()) { + name = ""; + type = ""; + match = true; + pos = 0; // Prepare to start over again + } + // When we find a blob, fetch its name and type to stick in the parameters + else if (label.Object(pos).Type() == "Object" && + label.Object(pos).HasKeyword("Name") && + label.Object(pos).HasKeyword("StartByte") && + label.Object(pos).HasKeyword("Bytes")) { + name = label.Object(pos)["Name"][0].c_str(); + type = label.Object(pos).Name(); + match = true; + pos++; + } + // Nothing's been found yet, keep looking for blobs + else { + pos++; + cnt++; + } + } + + ui.Clear("NAME"); + ui.PutString("NAME",name); + ui.Clear("TYPE"); + ui.PutString("TYPE", type); +} diff --git a/isis/src/system/apps/blobdump/blobdump.xml b/isis/src/system/apps/blobdump/blobdump.xml new file mode 100644 index 0000000000000000000000000000000000000000..35f4eb178c9f136036e833b11bc304a32bd6c023 --- /dev/null +++ b/isis/src/system/apps/blobdump/blobdump.xml @@ -0,0 +1,107 @@ + + + + + Program to output a selected blob out to a file + + + +

    + This program takes a cube with a blob in it, and strings to identify which + blob, and reads that blob out to a file specified by the user. +

    + +

    + Helper button has been provided in the GUI mode for the NAME and TYPE + parameters. The helper button will sequentially fill in the name and + type of each blob when pressed, clear the field to blank after the + last blob has been reached, and then wrap back to the + beginning. +

    +
    + + + Import and Export + + + + + Original version + + + + Changed category from Utility to Import and Export + + + + Added helper button to sequentially place one blob into the NAME and + TYPE parameters each time it is pressed + + + + + + + cube + input + + Input Cube + + + This is the cube containing the blob to be output. + + *.cub + + + + filename + output + + Output file + + + This is the output file the blob will be written as + + + + + + + string + + The name of the blob + + + This is the name of the blob to be output. It is generally mission-specific, and + does not refer to which subclass of blob created it. In the cube's labels, this + will be the information to the right of the equals sign after the keyword "Name" + + + + helperButtonGetBlobList + Retrieve Blob names + + This button will, each time it is pressed, generate the + name and type of a blob in the input cube and put it in + the appropriate field in the GUI, clear to blank after the + last blob is hit, and then wrap back to the beginning. + + $ISIS3DATA/base/icons/exec.png + + + + + + string + + The type of blob to be grabbed + + + This is the blob type, and generally refers to the subclass of Blob that created the + blob, for example, "OriginalLabel", "Polygon", "Table", or "History". This appears in + the cube label as the information to the right of the "Object" entry. + + + + +
    diff --git a/isis/src/system/apps/blobdump/tsts/Makefile b/isis/src/system/apps/blobdump/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/system/apps/blobdump/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/system/apps/blobdump/tsts/case01/Makefile b/isis/src/system/apps/blobdump/tsts/case01/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3480695e1559c392a2850d7412c39058c0d4bd63 --- /dev/null +++ b/isis/src/system/apps/blobdump/tsts/case01/Makefile @@ -0,0 +1,9 @@ +APPNAME = blobdump + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/blobTruth.cub \ + to=$(OUTPUT)/blobdump1.txt \ + name=IsisCube \ + type=History > /dev/null; diff --git a/isis/src/system/apps/blobdump/tsts/case02/Makefile b/isis/src/system/apps/blobdump/tsts/case02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f4a139272f8a258a464d40fceee8e184b4281eb9 --- /dev/null +++ b/isis/src/system/apps/blobdump/tsts/case02/Makefile @@ -0,0 +1,9 @@ +APPNAME = blobdump + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/blobTruth.cub \ + to=$(OUTPUT)/blobdump2.txt \ + name="HiRISE Calibration Image" \ + type=Table > /dev/null; diff --git a/isis/src/system/apps/csspck2spk/Makefile b/isis/src/system/apps/csspck2spk/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/system/apps/csspck2spk/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/system/apps/csspck2spk/csspck2spk.cpp b/isis/src/system/apps/csspck2spk/csspck2spk.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3c2533fee7420c9d850209b2321cd9df62852fb --- /dev/null +++ b/isis/src/system/apps/csspck2spk/csspck2spk.cpp @@ -0,0 +1,108 @@ +//_VER $Id: csspck2spk.cpp,v 1.8 2009/12/04 21:58:45 caustin Exp $ +#include "Isis.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "Filename.h" +#include "TextFile.h" +#include +#include +#include + +using namespace Isis; +using namespace std; + +void IsisMain(){ + /* Ingesting the pck2spk into mapped key/values; first grap latest file name, + and then the individual lines for parsing into the map */ + string pckfile("$cassini/kernels/pck/pck2spk_????.map"); + Filename pckFilenm(pckfile); + pckFilenm.HighestVersion(); + TextFile txt(pckFilenm.Expanded()); + iString line; + map< string, string> lookuparray; + while (txt.GetLine(line)) { + iString pck = line.Token(","); + pck.Trim("\n\r\t\v\f "); // stripping the extraneous characters + iString spk = line; + spk.Trim("\n\r\t\v\f "); + pair pckspk(spk,pck); + lookuparray.insert(pckspk); + } + + /* Open the input file from the guior find + the latest version of the db file */ + UserInterface &ui = Application::GetUserInterface(); + string inDBfile; + if(ui.WasEntered("FROM")) { + inDBfile = ui.GetFilename("FROM"); + } + else { + string exDBfile("$cassini/kernels/spk/kernels.????.db"); + Filename exDBfilenm(exDBfile); + exDBfilenm.HighestVersion(); // stores highest version and returns a void + inDBfile = exDBfilenm.Expanded(); + } + + Filename basepckPath("$base/kernels/pck/kernels.????.db"); + basepckPath.HighestVersion(); + + // Read SPK db file into a PVL + Pvl spkdb (inDBfile); + Pvl basepck (basepckPath.Expanded()); + PvlKeyword basefile = basepck.FindObject("TargetAttitudeShape").Group(0)["File"]; + + //Search PVL for main object + PvlObject &mainob = spkdb.FindObject("SpacecraftPosition"); + mainob.SetName("TargetAttitudeShape"); + + /* Search for the Selection Groups, and the based on the File Keyword, add + the appropriate pck file keyword. First check to see if the input file has + already been updated from an old version of the program. */ + for (int grpIndex =0; grpIndex < mainob.Groups(); grpIndex ++) { + PvlGroup &grp = mainob.Group(grpIndex); + if (grp.IsNamed("Selection")) { + + int count = 0; + for (int keyIndex = 0; keyIndex < grp.Keywords(); keyIndex ++) { + if ( grp[keyIndex].IsNamed("File")){ + count ++; + + // Older versions of this program added the file to the SPK kernels DB file instead + // of creating a new one in the PCK directory. Check for this. + if (count > 1) { + string msg = "This file has already been updated ["; + msg += iString(inDBfile) + "] by an old version of this program."; + msg += " This is not a valid input."; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + } + } + + string value = (string)grp["File"]; + Filename fnm(value); + string filename = fnm.Basename(); + if ( lookuparray[filename] == "" ) { + std::string msg = "Spk [" + filename + "] does not exist in [" + pckFilenm.Name() + "]"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + else { + PvlKeyword newfile("File", "$cassini/kernels/pck/"+lookuparray[filename]); + grp.AddKeyword(basefile, Pvl::Replace); + grp.AddKeyword(newfile); + grp.DeleteKeyword("Type"); + } + } + } + + // Create new db file with the updated contents of the Pvl + Filename outDBfile; + if(ui.WasEntered("TO")) { + outDBfile = ui.GetFilename("TO"); + } + else{ + outDBfile = "$cassini/kernels/pck/kernels.????.db"; + outDBfile.NewVersion(); + } + + spkdb.Write(outDBfile.Expanded()); +} diff --git a/isis/src/system/apps/csspck2spk/csspck2spk.xml b/isis/src/system/apps/csspck2spk/csspck2spk.xml new file mode 100644 index 0000000000000000000000000000000000000000..541cce3938b9dae3811a4e583aab279aab387a04 --- /dev/null +++ b/isis/src/system/apps/csspck2spk/csspck2spk.xml @@ -0,0 +1,100 @@ + + + + + Matches CASSINI SPK and PCK SPICE files + + + + The CASSINI mission requires that specific PCK SPICE files be matched to + each SPK SPICE file. This program will do the matching. + + The reference table used for the matching is generated by JPL, generally on a monthly + basis, and is located at https://cassini.jpl.nasa.gov/io/spice/pcktospk_mapping.htm. + Each time this table is updated, it should be downloaded and converted from html + to a text table (using your favorite converter, maybe lynx), and then named + pck2spk_????.map. The "Last Updated..." line and title header should be saved + and commented out with the "#" character, and each PCK/SPK pair should occupy + one line with a comma delimeter. Do not leave blank lines. When you are done, mv + the file to the $ISIS3DATA/cassini/kernels/pck directory. The file should look + something like this: + +
    +            # Last Updated: 27-August-2006
    +            # PCK to SPK File Compatibility Table
    +            #
    +            cpck11Aug2006.tpc,060810R_SCPSE_06162_06193
    +            cpck20Jul2006.tpc,060719R_SCPSE_06130_06162
    +            cpck14Jun2006.tpc,060614R_SCPSE_06099_06130
    +    
    + + Next, update the SPK directory with new position files, and the PCK + directory with the new ehemeris files. Then run makedb to generate a + db file located in the SPK directory and a db file located in the PCK directory. +
    + + + + Original version + + + Fixed typo in .xml that caused gui to fail; added the program to the System category. + + + Added "TO" parameter. Added default to "FROM" parameter. + + + Bug fix: the output kernel DB file lacked the base PCK that was necessary. + + + Bug fix: flipped the order that the TargetAttitudeShape kernels were furnished. + + + Added an error when an spk file does not exist inside the latest mapping file. + + + + + System + + + + + + filename + input + + Input SPK kernel.xxxx.db file + + + The SPK PVL group db file used to generate the new db + file. Defaulted to use $ISIS3DATA/cassini/kernels/spk/kernels.????.db + + + Automatic + + + *.db + + + + + filename + output + + Output PCK kernel.xxxx.db file + + + The new db file that is the matching PCK file. + Defaulted to use $ISIS3DATA/cassini/kernels/pck/kernels.????.db + + + Automatic + + + *.db + + + + +
    diff --git a/isis/src/system/apps/csspck2spk/tsts/Makefile b/isis/src/system/apps/csspck2spk/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/system/apps/csspck2spk/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/system/apps/csspck2spk/tsts/caseRightFile/Makefile b/isis/src/system/apps/csspck2spk/tsts/caseRightFile/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d897a347a4999bb8028d1bd1fab53242b99d36f5 --- /dev/null +++ b/isis/src/system/apps/csspck2spk/tsts/caseRightFile/Makefile @@ -0,0 +1,8 @@ +APPNAME = csspck2spk + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) \ + from=$(INPUT)/kernels.0023.custom.db \ + to=$(OUTPUT)/kernels.0023.txt > /dev/null; diff --git a/isis/src/system/apps/isiscomplete/Makefile b/isis/src/system/apps/isiscomplete/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/system/apps/isiscomplete/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/system/apps/isiscomplete/isiscomplete.cpp b/isis/src/system/apps/isiscomplete/isiscomplete.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b24dfa6648ac4158a56061a7f463766e86a98969 --- /dev/null +++ b/isis/src/system/apps/isiscomplete/isiscomplete.cpp @@ -0,0 +1,153 @@ +#include "Application.h" +#include "UserInterface.h" +#include "System.h" +#include "FileList.h" +#include "iString.h" + +using namespace std; +using namespace Isis; + +void MakeCompletion(const string &appName); +string GetParamCompletion(int grp, int param); +string BuildStaticCompletes(std::string paramList); +void PrintHelp(); + +int main (int argc, char *argv[]) { + if(argc < 2) { + PrintHelp(); + return 0; + } + + // Too slow if in debug mode +#ifndef CWDEBUG + for(int i = 1; i < argc; i++) { + MakeCompletion(argv[i]); + } +#endif + + return 0; +} + +void PrintHelp() { + cout << "This program is used to set up the isis tab-completion for the tcsh shell. "; + cout << "The output of this program is a list of commands for the isis setup script to execute." << endl; + cout << "Usage: isiscomplete isisappname [isisappname2 isisappname3 ...]" << endl; +} + +void MakeCompletion(const string &appName) { + static char *argv[2]; + static int argc(2); + argv[0] = (char*)appName.c_str(); + argv[1] = "-nogui"; + + // Do not complete image-viewer applications + if(appName.compare("qview") == 0) { + cout << "complete qview 'c/-/(new)/'; "; + return; + } + + if(appName.compare("qnet") == 0) return; + + if(appName.compare("isisui") == 0) { + string binPath = Filename("$ISISROOT/bin").Expanded(); + cout << "complete isisui 'n@*@F:" << binPath << "/@'; "; + return; + } + + // Do not complete self + if(appName.compare("isiscomplete") == 0) return; + + Application app(argc,argv); + UserInterface &ui = Application::GetUserInterface(); + string paramList = ""; + string completeCommand; + vector paramDetails; + + for(int grp = 0; grp < ui.NumGroups(); grp++) { + for(int param = 0; param < ui.NumParams(grp); param++) { + paramList += " " + iString(ui.ParamName(grp, param)).DownCase(); + paramDetails.push_back(GetParamCompletion(grp, param)); + } + } + + for(unsigned int param = 0; param < paramDetails.size(); param ++) { + completeCommand += "'" + paramDetails[param] + "' "; + } + + completeCommand += " " + BuildStaticCompletes(paramList) + " "; + completeCommand += "'n/*/(-" + paramList + ")/='"; + completeCommand = "complete " + appName + " " + completeCommand + "; "; + cout << completeCommand; +} + +string BuildStaticCompletes(std::string paramList) { + string completion = ""; + + // Batchlist + completion += " 'c/-[bB][aA][tT][cC][hH][lL][iI][sS][tT]=/f/'"; + + // Errlist + completion += " 'c/-[eE][rR][rR][lL][iI][sS][tT]=/f/'"; + + // Help + completion += " 'c/-[hH][eE][lL][pP]=/(" + paramList + ")/'"; + + // Info + completion += " 'c/-[iI][nN][fF][oO]=/f/'"; + + // Log + completion += " 'c/-[lL][oO][gG]=/f/'"; + + // Onerror + completion += " 'c/-[oO][nN][eE][rR][rR][oO][rR]=/(abort continue)/'"; + + // Preference + completion += " 'c/-[pP][rR][eE][fF][eE][rR][eE][nN][cC][eE]=/f/'"; + + // Restore + completion += " 'c/-[rR][eE][sS][tT][oO][rR][eE]=/f:*/'"; + + // Save + completion += " 'c/-[sS][aA][vV][eE]=/f/'"; + + completion += " 'c/-/(batchlist= errlist= gui nogui help help= info info= last log log="; + completion += " onerror= preference= restore= save save= verbose webhelp)//'"; + + return completion; +} + +string GetParamCompletion(int grp, int param) { + string completion = "c/"; + UserInterface &ui = Application::GetUserInterface(); + + + string paramName = ui.ParamName(grp, param); + for(unsigned int curIndex = 0; curIndex < paramName.length(); curIndex++) { + if(isalpha(paramName[curIndex])) { + completion += "["; + completion += toupper(paramName[curIndex]); + completion += tolower(paramName[curIndex]); + completion += "]"; + } + else { + completion += paramName[curIndex]; + } + } + completion += "=/"; + + string type = ui.ParamType(grp, param); + + if(type == "cube") { + completion += "f:*.[cC][uU][bB]"; + } + else if(type == "filename") { + completion += "f"; + } + else { + completion += "(" + ui.ParamDefault(grp,param) + ")"; + } + + completion += "/"; + + return completion; +} diff --git a/isis/src/system/apps/isiscomplete/isiscomplete.xml b/isis/src/system/apps/isiscomplete/isiscomplete.xml new file mode 100644 index 0000000000000000000000000000000000000000..5f10a996a220a4054e80993c479ddebd7ea5b4af --- /dev/null +++ b/isis/src/system/apps/isiscomplete/isiscomplete.xml @@ -0,0 +1,39 @@ + + + + + Outputs the completion command for any Isis application + + + +

    + This program is used to load tcsh tab-completion settings for all Isis applications. This + program will NOT run in GUI mode! Call this program like this: + eval `isiscomplete isisapp [isisapp2 isisapp3 ...]` +

    +
    + + + Scripting + + + + + Original version + + + isiscomplete now does not complete itself and does not complete when isis is in debug mode + + + This program now handles qview properly + + + This program now handles isisui properly + + + Changed the call to Application to provide compatability withg Qt + startup requirements. + + +
    + diff --git a/isis/src/system/apps/isiscomplete/tsts/Makefile b/isis/src/system/apps/isiscomplete/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/system/apps/isiscomplete/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/system/apps/isiscomplete/tsts/default/Makefile b/isis/src/system/apps/isiscomplete/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d951270d67ba969995adbf6048416c4322204c67 --- /dev/null +++ b/isis/src/system/apps/isiscomplete/tsts/default/Makefile @@ -0,0 +1,12 @@ +APPNAME = isiscomplete + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) isiscomplete > $(OUTPUT)/self_completion.txt; + $(APPNAME) mirror > $(OUTPUT)/mirror_completion.txt; + $(ECHO) `$(APPNAME) isisui` | $(SED) s/\\\/.\*\\\/// > $(OUTPUT)/isisui_completion.txt; + $(APPNAME) qview > $(OUTPUT)/qview_completion.txt; + $(APPNAME) fx > $(OUTPUT)/fx_completion.txt; + $(APPNAME) isiscomplete mirror qview fx \ + > $(OUTPUT)/combined_completion.txt; diff --git a/isis/src/system/apps/kerneldbgen/Makefile b/isis/src/system/apps/kerneldbgen/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/system/apps/kerneldbgen/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/system/apps/kerneldbgen/SpiceDbGen.cpp b/isis/src/system/apps/kerneldbgen/SpiceDbGen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8e5ca7e177b9ac5772fb6e9d9a4906a55e8f18a --- /dev/null +++ b/isis/src/system/apps/kerneldbgen/SpiceDbGen.cpp @@ -0,0 +1,275 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2010/05/02 18:39:28 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include "SpiceDbGen.h" +#include "NaifStatus.h" + +using namespace std; +using namespace Isis; + +/** + * Constructs a new SpiceDbGen. + * + * @param type The type of kernel to be processed. Either, "SPK" or "CK. +*/ +SpiceDbGen::SpiceDbGen(iString type){ + p_type = type; + calForm = "YYYY MON DD HR:MN:SC.### TDB ::TDB"; +} + + +/** + * Creates a Pvl object that stores all of the kernels under the condition + * specified by the filter. + * + * @param quality The quality of the kernels that are being filtered into + * the database. For example, "Reconstructed". + * + * @param location The directory in which the method searches for kernels. + * + * @param filter Vector of strings containing regular expression used to + * match kernels of a particular quality. This parameter is + * used to distinguish between kernels of different qualities + * and/or different missions that may be placed in the same + * directory. + * + * @return PvlObject + * + * @internal + * @history 2010-04-27 Stuart Sides Changed to work with vector of filters + * instead of a single filter + * + * @throws Isis::iException::Message +*/ +PvlObject SpiceDbGen::Direct(iString quality, iString location, + std::vector &filter) { + PvlObject result; + iString type = "none"; + + for (unsigned int i=0; iName() == "No coverage" || grp->Name() == "Null"){ + result.DeleteGroup(grp->Name()); + } + // This is used for the first time thru the while loop + // DO NOT increment grp here + else if (type == "none"){ + type = grp->Name(); + } + else if (grp->Name() == type){ + grp->SetName("Selection"); + grp++; + } + else{ + string message = "A kernel of type [" + grp->Name() +"] has been found in a directory for type [" + type +"]" ; + throw Isis::iException::Message(Isis::iException::Programmer,message,_FILEINFO_); + break; + } + } + + if (type == "SPK") { + result.SetName("SpacecraftPosition"); + } + else if (type == "CK") { + result.SetName("SpacecraftPointing"); + } + + return result; +} + +/** + * Essenetially a method call to the underlying QDir class which will filter + * the files needed by Direct(). Files are returned in order of the time they + * were most recently modified, the oldest file being first and the most + * recently modified being last. + * + * @param location The directory in which the method searches for files. + * + * @param filter The regular expression used to match files of a + * particular quality. This parameter is important, since it + * is necessary to distinguish between kernels of different + * qualities and/or different missions that may be placed in + * the same directory. + * + * @return QStringList + * + */ +QStringList SpiceDbGen::GetFiles(Filename location, iString filter){ + filter.Remove("\\"); + QDir dir(location.Expanded().c_str(), filter.c_str(), + QDir::Name, QDir::Files); + return dir.entryList(); +} + + +/** + * Format a single kernel file to include the file. + * + * @param fileIn The file name being added + * + * @return PvlGroup + * + * @throws Isis::iException::Message + */ +PvlGroup SpiceDbGen::AddSelection(Filename fileIn) { + NaifStatus::CheckErrors(); + + //finalize the filename so that it may be used in spice routines + std::string tmp = fileIn.Expanded(); +// const char* file = fileIn.Expanded().c_str(); + furnsh_c(tmp.c_str()); + SpiceChar fileType[32], source[2048]; + SpiceInt handle; + + SpiceBoolean found; + kinfo_c(tmp.c_str(), 32, 2048, fileType, source, &handle, &found); + iString currFile = fileType; + + //create a spice cell capable of containing all the objects in the kernel. + SPICEINT_CELL (currCell, 1000); + //this resizing is done because otherwise a spice cell will append new data + //to the last "currCell" + ssize_c(0, &currCell); + ssize_c(1000, &currCell); + + //select which spice coverage routine to use. If a text kernel is detected, it + //will be returned here and weeded out at the end of Direct(). This helps + //to protect the user from inadvertently adding "." and ".." to their filters + if (currFile == "SPK") { + spkobj_c(tmp.c_str(), &currCell); + } + else if (currFile == "CK") { + ckobj_c(tmp.c_str(), &currCell); + } + else if (currFile == "TEXT") { + return PvlGroup("No coverage"); + } + + PvlGroup result; + //iterate through every body in the kernel + for (int bodyCount = 0 ; bodyCount < card_c(&currCell) ; bodyCount++){ + //get the NAIF body code + int body = SPICE_CELL_ELEM_I(&currCell, bodyCount); + + //only provide coverage for negative NAIF codes + //(Positive codes indicate planetary bodies, negatives indicate + // spacecraft and instruments) + if (body < 0){ + NaifStatus::CheckErrors(); + + //find the correct coverage window + if (currFile == "SPK") { + // 2000 is the max coverage window size for an SPK kernel + SPICEDOUBLE_CELL (cover, 2000); + ssize_c(0, &cover); + ssize_c(2000, &cover); + spkcov_c(tmp.c_str(), body, &cover); + + NaifStatus::CheckErrors(); + + result = FormatIntervals(cover, currFile); + } + else if (currFile == "CK") { + // 200,000 is the max coverage window size for a CK kernel + SPICEDOUBLE_CELL (cover, 200000); + ssize_c(0, &cover); + ssize_c(200000, &cover); + ckcov_c(tmp.c_str(), body, SPICEFALSE, "SEGMENT", 0.0, "TDB", &cover); + + NaifStatus::CheckErrors(); + + result = FormatIntervals(cover, currFile); + } + } + } + + iString outFile = fileIn.OriginalPath(); + result += PvlKeyword("File", outFile + "/" + fileIn.Name()); + + NaifStatus::CheckErrors(); + return result; +} + + +PvlGroup SpiceDbGen::FormatIntervals(SpiceCell &coverage, string type){ + NaifStatus::CheckErrors(); + + PvlGroup result(type); + SpiceChar begStr[32], endStr[32]; + //Get the number of intervals in the object. + int niv = card_c ( &coverage ) / 2; + //Convert the coverage interval start and stop times to TDB + double begin, end; + for (int j = 0; j < niv; j++ ){ + //Get the endpoints of the jth interval. + wnfetd_c ( &coverage, j, &begin, &end ); + //Convert the endpoints to TDB calendar + timout_c ( begin, calForm, 32, begStr); + timout_c ( end, calForm, 32, endStr); + result += PvlKeyword("Time", "(\"" + (string)begStr + + "\", \"" + (string)endStr + "\")"); + } + + NaifStatus::CheckErrors(); + + return result; +} + + +void SpiceDbGen::FurnishDependencies(string sclk, string lsk){ + NaifStatus::CheckErrors(); + + //furnish the lsk file + furnsh_c(lsk.c_str()); + + //get the sclk, if such a file was specified + if (sclk != ""){ + furnsh_c(sclk.c_str()); + } + + NaifStatus::CheckErrors(); +} diff --git a/isis/src/system/apps/kerneldbgen/SpiceDbGen.h b/isis/src/system/apps/kerneldbgen/SpiceDbGen.h new file mode 100644 index 0000000000000000000000000000000000000000..79c96c6b9157dab10fe6aadd714c490177f06889 --- /dev/null +++ b/isis/src/system/apps/kerneldbgen/SpiceDbGen.h @@ -0,0 +1,68 @@ +#ifndef SpiceDbGen_h +#define SpiceDbGen_h + +/** + * @file + * $Revision: 1.4 $ + * $Date: 2010/05/02 18:39:28 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "Filename.h" +#include "Pvl.h" +#include "iString.h" +#include "naif/SpiceUsr.h" +#include "qstringlist.h" +#include "KernelDb.h" +#include "iException.h" + +using namespace std; +using namespace Isis; + +class SpiceDbGen{ + + /** + * @brief Utility for SPICE kernel interrogation and kerneldb generation + * + * @author Unknown + * + * @internal + * @history 2010-04-27 Stuart Sides - Modified Direct member to use a + * vector of filters instead of a single string + * + */ + + +public: + SpiceDbGen(iString type); + PvlObject Direct(iString quality, iString location, + std::vector & filter); + void FurnishDependencies(string sclk, string fk); +private: + QStringList GetFiles(Filename location, iString filter); + PvlGroup AddSelection(Filename fileIn); + PvlGroup FormatIntervals(SpiceCell &coverage, string type); + PvlGroup GetIntervals(SpiceCell &cover); + //private instance variables + iString p_type; + char* calForm; +}; + +#endif diff --git a/isis/src/system/apps/kerneldbgen/assets/images/messengerCk.jpg b/isis/src/system/apps/kerneldbgen/assets/images/messengerCk.jpg new file mode 100755 index 0000000000000000000000000000000000000000..67475acae9ae1f8e762b1d673434a8013b71808f Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/images/messengerCk.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/images/odysseyAfter.jpg b/isis/src/system/apps/kerneldbgen/assets/images/odysseyAfter.jpg new file mode 100755 index 0000000000000000000000000000000000000000..08bca15e998f28ee6e29792b5704f75449755ed8 Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/images/odysseyAfter.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/images/odysseyBefore.jpg b/isis/src/system/apps/kerneldbgen/assets/images/odysseyBefore.jpg new file mode 100755 index 0000000000000000000000000000000000000000..1b35486030f5403a5d023bdbe319da8083888a5e Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/images/odysseyBefore.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/images/odysseyCk.jpg b/isis/src/system/apps/kerneldbgen/assets/images/odysseyCk.jpg new file mode 100755 index 0000000000000000000000000000000000000000..ed6b9179175f1aa9b857869a84ba72a117cf3f6d Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/images/odysseyCk.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/images/pivotDb.jpg b/isis/src/system/apps/kerneldbgen/assets/images/pivotDb.jpg new file mode 100755 index 0000000000000000000000000000000000000000..8571d8b1633c893b2ee5143852425c2100e8853b Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/images/pivotDb.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/images/terminalAfter.jpg b/isis/src/system/apps/kerneldbgen/assets/images/terminalAfter.jpg new file mode 100755 index 0000000000000000000000000000000000000000..877625de89d1598ca0b5e55caf2ec28875cd03f2 Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/images/terminalAfter.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/images/terminalBefore.jpg b/isis/src/system/apps/kerneldbgen/assets/images/terminalBefore.jpg new file mode 100755 index 0000000000000000000000000000000000000000..83e51269803aef6bc54a7ccecae1f268fc99f1ae Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/images/terminalBefore.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/kernels.0001.db b/isis/src/system/apps/kerneldbgen/assets/kernels.0001.db new file mode 100644 index 0000000000000000000000000000000000000000..6054605b1e49dba736c4c8b194de9f418c7b3140 --- /dev/null +++ b/isis/src/system/apps/kerneldbgen/assets/kernels.0001.db @@ -0,0 +1,233 @@ +Object = SpacecraftPointing + RunTime = 2005-08-05T15:46:38 + + Group = Dependencies + Spacecraft Clock Kernel = $Odyssey/kernels/sclk/ORB1_SCLKSCET.00113.tsc + Leapsecond Kernel = $base/kernels/lsk/naif0008.tls + End_Group + + Group = Selection + Time = ("2003 JUL 01 00:29:59.999 TDB", "2003 OCT 01 16:29:59.989 TDB") + File = $Odyssey/kernels/ck/m01_sc_map_rec_nadir.bc + Type = Nadir + End_Group + + Group = Selection + Time = ("2003 JUL 01 00:29:59.999 TDB", "2003 OCT 26 23:29:59.952 TDB") + File = $Odyssey/kernels/ck/m01_sc_map_nadir.bc + Type = Nadir + End_Group + + Group = Selection + Time = ("2002 FEB 19 00:29:59.999 TDB", "2002 APR 01 00:59:59.999 TDB") + File = $Odyssey/kernels/ck/m01_sc_map1_rec_nadir.bc + Type = Nadir + End_Group + + Group = Selection + Time = ("2002 APR 01 00:29:59.998 TDB", "2002 JUL 01 00:59:59.998 TDB") + File = $Odyssey/kernels/ck/m01_sc_map2_rec_nadir.bc + Type = Nadir + End_Group + + Group = Selection + Time = ("2002 JUL 01 00:30:00.001 TDB", "2002 OCT 01 00:59:59.999 TDB") + File = $Odyssey/kernels/ck/m01_sc_map3_rec_nadir.bc + Type = Nadir + End_Group + + Group = Selection + Time = ("2002 OCT 01 00:29:59.999 TDB", "2003 JAN 01 01:00:00.000 TDB") + File = $Odyssey/kernels/ck/m01_sc_map4_rec_nadir.bc + Type = Nadir + End_Group + + Group = Selection + Time = ("2003 JAN 01 00:29:59.999 TDB", "2003 APR 01 01:01:04.187 TDB") + File = $Odyssey/kernels/ck/m01_sc_map5_rec_nadir.bc + Type = Nadir + End_Group + + Group = Selection + Time = ("2003 APR 01 00:29:59.998 TDB", "2003 JUL 01 01:01:04.183 TDB") + File = $Odyssey/kernels/ck/m01_sc_map6_rec_nadir.bc + Type = Nadir + End_Group + + Group = Selection + Time = ("2003 JUL 26 00:01:08.957 TDB", "2003 JUL 27 00:00:59.685 TDB") + Time = ("2003 AUG 04 00:01:08.730 TDB", "2003 AUG 05 00:01:01.755 TDB") + Time = ("2003 AUG 05 00:01:07.755 TDB", "2003 AUG 06 00:00:58.475 TDB") + Time = ("2003 AUG 06 00:01:04.475 TDB", "2003 AUG 07 00:01:04.097 TDB") + Time = ("2003 AUG 07 00:01:10.097 TDB", "2003 AUG 08 00:01:02.610 TDB") + Time = ("2003 AUG 08 00:01:08.610 TDB", "2003 AUG 09 00:01:00.627 TDB") + Time = ("2003 AUG 09 00:01:06.627 TDB", "2003 AUG 10 00:01:04.042 TDB") + Time = ("2003 AUG 10 00:01:10.042 TDB", "2003 AUG 11 00:01:01.948 TDB") + Time = ("2003 AUG 11 00:01:07.948 TDB", "2003 AUG 12 00:01:03.753 TDB") + Time = ("2003 AUG 12 00:01:09.757 TDB", "2003 AUG 13 00:01:01.042 TDB") + Time = ("2003 AUG 13 00:01:07.042 TDB", "2003 AUG 14 00:00:58.729 TDB") + Time = ("2003 AUG 14 00:01:04.729 TDB", "2003 AUG 15 00:01:04.124 TDB") + Time = ("2003 AUG 15 00:01:10.124 TDB", "2003 AUG 16 00:01:01.860 TDB") + Time = ("2003 AUG 16 00:01:07.860 TDB", "2003 AUG 17 00:01:02.291 TDB") + Time = ("2003 AUG 17 00:01:08.291 TDB", "2003 AUG 18 00:01:02.320 TDB") + Time = ("2003 AUG 18 00:01:08.320 TDB", "2003 AUG 20 00:01:02.858 TDB") + Time = ("2003 AUG 20 00:01:08.858 TDB", "2003 AUG 21 00:01:00.476 TDB") + Time = ("2003 AUG 21 00:01:06.476 TDB", "2003 AUG 22 00:01:01.888 TDB") + Time = ("2003 AUG 22 00:01:07.888 TDB", "2003 AUG 23 00:00:59.502 TDB") + Time = ("2003 AUG 23 00:01:05.502 TDB", "2003 AUG 24 00:00:59.412 TDB") + Time = ("2003 AUG 24 00:01:05.412 TDB", "2003 AUG 25 00:01:03.021 TDB") + Time = ("2003 AUG 25 00:01:09.017 TDB", "2003 AUG 26 00:01:02.299 TDB") + Time = ("2003 AUG 26 00:01:08.299 TDB", "2003 AUG 27 00:00:39.006 TDB") + Time = ("2003 AUG 27 00:01:10.904 TDB", "2003 AUG 28 00:01:02.599 TDB") + Time = ("2003 AUG 28 00:01:08.599 TDB", "2003 AUG 29 00:01:01.299 TDB") + Time = ("2003 AUG 29 00:01:05.299 TDB", "2003 AUG 30 00:00:58.509 TDB") + Time = ("2003 AUG 30 00:01:04.509 TDB", "2003 AUG 31 00:01:03.209 TDB") + Time = ("2003 AUG 31 00:01:08.908 TDB", "2003 SEP 01 00:01:04.107 TDB") + Time = ("2003 SEP 01 00:01:08.408 TDB", "2003 SEP 02 00:01:00.509 TDB") + Time = ("2003 SEP 02 00:01:06.509 TDB", "2003 SEP 03 00:01:01.908 TDB") + Time = ("2003 SEP 03 00:01:04.506 TDB", "2003 SEP 04 00:01:00.990 TDB") + Time = ("2003 SEP 04 00:01:04.689 TDB", "2003 SEP 05 00:00:59.884 TDB") + Time = ("2003 SEP 05 00:01:05.884 TDB", "2003 SEP 06 00:01:03.381 TDB") + Time = ("2003 SEP 06 00:01:05.881 TDB", "2003 SEP 07 00:01:03.677 TDB") + Time = ("2003 SEP 07 00:01:05.377 TDB", "2003 SEP 08 00:00:58.763 TDB") + Time = ("2003 SEP 08 00:01:04.767 TDB", "2003 SEP 09 00:01:01.260 TDB") + Time = ("2003 SEP 09 00:01:04.357 TDB", "2003 SEP 10 00:01:03.845 TDB") + Time = ("2003 SEP 10 00:01:08.345 TDB", "2003 SEP 11 00:01:03.334 TDB") + Time = ("2003 SEP 11 00:01:07.135 TDB", "2003 SEP 12 00:01:03.623 TDB") + Time = ("2003 SEP 12 00:01:09.623 TDB", "2003 SEP 13 00:01:02.705 TDB") + Time = ("2003 SEP 13 00:01:08.705 TDB", "2003 SEP 14 00:01:01.783 TDB") + Time = ("2003 SEP 14 00:01:04.885 TDB", "2003 SEP 14 18:58:32.772 TDB") + Time = ("2003 SEP 15 00:01:08.662 TDB", "2003 SEP 16 00:01:04.137 TDB") + Time = ("2003 SEP 16 00:01:05.137 TDB", "2003 SEP 17 00:01:03.218 TDB") + Time = ("2003 SEP 17 00:01:04.218 TDB", "2003 SEP 18 00:01:03.595 TDB") + Time = ("2003 SEP 18 00:01:09.595 TDB", "2003 SEP 19 00:01:00.867 TDB") + Time = ("2003 SEP 19 00:01:06.867 TDB", "2003 SEP 20 00:01:04.041 TDB") + Time = ("2003 SEP 20 00:01:06.041 TDB", "2003 SEP 21 00:01:00.915 TDB") + Time = ("2003 SEP 21 00:01:05.516 TDB", "2003 SEP 22 00:01:01.491 TDB") + Time = ("2003 SEP 22 00:01:07.491 TDB", "2003 SEP 23 00:01:03.857 TDB") + Time = ("2003 SEP 23 00:01:06.959 TDB", "2003 SEP 24 00:01:03.723 TDB") + Time = ("2003 SEP 24 00:01:06.023 TDB", "2003 SEP 25 00:01:01.401 TDB") + Time = ("2003 SEP 25 00:01:07.401 TDB", "2003 SEP 26 00:00:59.263 TDB") + Time = ("2003 SEP 26 00:01:05.263 TDB", "2003 SEP 27 00:01:01.128 TDB") + Time = ("2003 SEP 27 00:01:07.128 TDB", "2003 SEP 28 00:01:00.990 TDB") + Time = ("2003 SEP 28 00:01:06.990 TDB", "2003 SEP 29 00:01:01.051 TDB") + Time = ("2003 SEP 29 00:01:07.051 TDB", "2003 SEP 30 00:01:00.811 TDB") + Time = ("2003 SEP 30 00:01:06.811 TDB", "2003 OCT 01 00:00:58.672 TDB") + Time = ("2003 OCT 01 00:01:04.672 TDB", "2003 OCT 02 00:01:01.525 TDB") + Time = ("2003 OCT 02 00:01:07.525 TDB", "2003 OCT 03 00:01:00.183 TDB") + Time = ("2003 OCT 03 00:01:06.183 TDB", "2003 OCT 04 00:01:00.935 TDB") + Time = ("2003 OCT 04 00:01:06.935 TDB", "2003 OCT 05 00:00:59.991 TDB") + Time = ("2003 OCT 05 00:01:05.991 TDB", "2003 OCT 06 00:01:01.145 TDB") + File = $Odyssey/kernels/ck/m01_sc_map.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2002 FEB 19 03:40:51.593 TDB", "2002 APR 01 00:01:04.184 TDB") + File = $Odyssey/kernels/ck/m01_sc_map1_v2.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2002 APR 01 01:54:10.680 TDB", "2002 JUL 01 00:01:00.313 TDB") + File = $Odyssey/kernels/ck/m01_sc_map2.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2002 JUL 01 00:01:06.313 TDB", "2002 OCT 01 00:01:03.869 TDB") + File = $Odyssey/kernels/ck/m01_sc_map3.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2002 OCT 01 00:01:09.572 TDB", "2003 JAN 01 00:01:02.295 TDB") + File = $Odyssey/kernels/ck/m01_sc_map4.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2003 JAN 01 00:01:08.295 TDB", "2003 APR 01 00:01:03.872 TDB") + File = $Odyssey/kernels/ck/m01_sc_map5.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2003 APR 01 00:01:09.872 TDB", "2003 JUL 01 00:01:00.232 TDB") + File = $Odyssey/kernels/ck/m01_sc_map6.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2003 JUL 01 00:01:06.232 TDB", "2003 OCT 01 00:00:58.672 TDB") + File = $Odyssey/kernels/ck/m01_sc_map7.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2003 OCT 01 00:01:04.672 TDB", "2003 DEC 31 23:58:15.246 TDB") + File = $Odyssey/kernels/ck/m01_sc_map8.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2004 JAN 01 00:06:03.245 TDB", "2004 APR 01 00:00:59.732 TDB") + File = $Odyssey/kernels/ck/m01_sc_map9.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2004 APR 01 00:01:05.626 TDB", "2004 JUL 01 00:01:04.111 TDB") + File = $Odyssey/kernels/ck/m01_sc_map10.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2004 JUL 01 00:01:07.912 TDB", "2004 OCT 01 00:01:03.147 TDB") + File = $Odyssey/kernels/ck/m01_sc_map11.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2001 OCT 24 00:01:05.116 TDB", "2001 NOV 01 00:01:03.760 TDB") + File = $Odyssey/kernels/ck/m01_sc_ab0110.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2001 NOV 01 00:01:05.963 TDB", "2001 DEC 01 00:01:03.909 TDB") + File = $Odyssey/kernels/ck/m01_sc_ab0111.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2001 DEC 01 00:01:07.909 TDB", "2002 JAN 01 00:01:01.552 TDB") + File = $Odyssey/kernels/ck/m01_sc_ab0112.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2002 JAN 01 00:01:05.352 TDB", "2002 FEB 01 00:01:01.675 TDB") + File = $Odyssey/kernels/ck/m01_sc_ab0201.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2002 FEB 01 00:01:05.675 TDB", "2002 FEB 18 22:37:39.733 TDB") + File = $Odyssey/kernels/ck/m01_sc_ab0202.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2004 OCT 01 00:01:05.347 TDB", "2005 JAN 01 00:01:03.251 TDB") + File = $Odyssey/kernels/ck/m01_sc_ext1.bc + Type = Reconstructed + End_Group + + Group = Selection + Time = ("2005 JAN 01 00:01:07.853 TDB", "2005 APR 01 00:01:03.821 TDB") + File = $Odyssey/kernels/ck/m01_sc_ext2.bc + Type = Reconstructed + End_Group +End_Object +End \ No newline at end of file diff --git a/isis/src/system/apps/kerneldbgen/assets/thumbs/messengerCk.jpg b/isis/src/system/apps/kerneldbgen/assets/thumbs/messengerCk.jpg new file mode 100755 index 0000000000000000000000000000000000000000..361ac98d2c559d753e0cde158e79f853dd1eb28b Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/thumbs/messengerCk.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/thumbs/odysseyAfter.jpg b/isis/src/system/apps/kerneldbgen/assets/thumbs/odysseyAfter.jpg new file mode 100755 index 0000000000000000000000000000000000000000..10103a347fb6b59019302d82fbf022ae7ae54e0c Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/thumbs/odysseyAfter.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/thumbs/odysseyBefore.jpg b/isis/src/system/apps/kerneldbgen/assets/thumbs/odysseyBefore.jpg new file mode 100755 index 0000000000000000000000000000000000000000..269266c2a770f9a8ee1616e888325b2d63479e99 Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/thumbs/odysseyBefore.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/thumbs/odysseyCk.jpg b/isis/src/system/apps/kerneldbgen/assets/thumbs/odysseyCk.jpg new file mode 100755 index 0000000000000000000000000000000000000000..9906e8b3ad17d29b030fa1f791284034f3d4d28e Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/thumbs/odysseyCk.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/thumbs/pivotDb.jpg b/isis/src/system/apps/kerneldbgen/assets/thumbs/pivotDb.jpg new file mode 100755 index 0000000000000000000000000000000000000000..1135b5126c0c0d668b704d74fbbafa8bb4ab0784 Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/thumbs/pivotDb.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/thumbs/terminalAfter.jpg b/isis/src/system/apps/kerneldbgen/assets/thumbs/terminalAfter.jpg new file mode 100755 index 0000000000000000000000000000000000000000..18a33b46a4e600775b6ec9f74ceb6a4be73538ab Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/thumbs/terminalAfter.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/assets/thumbs/terminalBefore.jpg b/isis/src/system/apps/kerneldbgen/assets/thumbs/terminalBefore.jpg new file mode 100755 index 0000000000000000000000000000000000000000..5378248e9ea1a1dadfab2ccd251fd0398be00f64 Binary files /dev/null and b/isis/src/system/apps/kerneldbgen/assets/thumbs/terminalBefore.jpg differ diff --git a/isis/src/system/apps/kerneldbgen/kerneldbgen.cpp b/isis/src/system/apps/kerneldbgen/kerneldbgen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d71d39b99a33eb71927b182bd47bcb5044ee170e --- /dev/null +++ b/isis/src/system/apps/kerneldbgen/kerneldbgen.cpp @@ -0,0 +1,120 @@ +#include "Isis.h" +#include "SpiceDbGen.h" +#include "iTime.h" + +using namespace Isis; +void IsisMain(){ + + UserInterface &ui = Application::GetUserInterface(); + PvlGroup dependency("Dependencies"); + + //create the database writer based on the kernel type + SpiceDbGen sdg(ui.GetString("TYPE")); + + //Load the SCLK. If it exists, add its location to the dependency group + //If there is none, set a flag so that no file is searched for + bool needSclk = false; + Filename sclkFile(""); + if (ui.WasEntered("SCLK")){ + iString sclkString = ui.GetAsString("SCLK"); + if (sclkString.length() != 0){ + sclkString.Trim("\\"); + sclkFile = Filename(sclkString); + if (sclkFile.Expanded().find_first_of("?") != string::npos){ + sclkFile.HighestVersion(); + sclkString = sclkFile.OriginalPath() + "/" + sclkFile.Name(); + } + dependency += PvlKeyword("SpacecraftClockKernel", sclkString); + needSclk = true; + } + } + + iString lskString = ui.GetAsString("LSK"); + lskString.Trim("\\"); + Filename lskFile(lskString); + if (lskFile.Expanded().find_first_of("?") != string::npos){ + lskFile.HighestVersion(); + lskString = lskFile.OriginalPath() + "/" + lskFile.Name(); + } + dependency += PvlKeyword("LeapsecondKernel", lskString); + //furnish dependencies with an SCLK + if (needSclk){sdg.FurnishDependencies(sclkFile.Expanded(), lskFile.Expanded());} + //Furnish dependencies without an SCLK + else {sdg.FurnishDependencies("", lskFile.Expanded());} + + //Determine the type of kernel that the user wants a database for. This will + //eventually become the name of the object in the output PVL + string kernelType; + if (ui.GetString("TYPE") == "CK"){kernelType = "SpacecraftPointing";} + else if (ui.GetString("TYPE") == "SPK"){kernelType = "SpacecraftPosition";} + PvlObject selections(kernelType); + + selections += PvlKeyword("RunTime", iTime::CurrentLocalTime()); + selections.AddGroup(dependency); + + /* Removed because Nadir is not done using this*/ + //if (ui.GetString("NADIRFILTER") != "none" && + // ui.GetString("NADIRDIR") != "none"){ + // iString location = ""; + // location = ui.GetString("NADIRDIR"); + // location.Trim("\\"); + // std::vector filter; + // ui.GetString("NADIRFILTER", filter); + // PvlObject result = sdg.Direct("Nadir",location, filter); + // PvlObject::PvlGroupIterator grp = result.BeginGroup(); + // while(grp != result.EndGroup()){ selections.AddGroup(*grp);grp++;} + //} + if (ui.GetString("PREDICTFILTER") != "none" && + ui.GetString("PREDICTDIR") != "none"){ + iString location = ""; + location = ui.GetString("PREDICTDIR"); + location.Trim("\\"); + std::vector filter; + ui.GetString("PREDICTFILTER", filter); + PvlObject result = sdg.Direct("Predicted",location, filter); + PvlObject::PvlGroupIterator grp = result.BeginGroup(); + while(grp != result.EndGroup()){selections.AddGroup(*grp);grp++;} + } + + if (ui.GetString("RECONDIR") != "none" && + ui.GetString("RECONFILTER") != "none"){ + iString location = ""; + location = ui.GetString("RECONDIR"); + location.Trim("\\"); + std::vector filter; + ui.GetString("RECONFILTER", filter); + PvlObject result = sdg.Direct("Reconstructed",location, filter); + PvlObject::PvlGroupIterator grp = result.BeginGroup(); + while(grp != result.EndGroup()){selections.AddGroup(*grp);grp++;} + } + + if (ui.GetString("SMITHEDDIR") != "none" && + ui.GetString("SMITHEDFILTER") != "none"){ + iString location = ""; + location = ui.GetString("SMITHEDDIR"); + location.Trim("\\"); + std::vector filter; + ui.GetString("SMITHEDFILTER", filter); + PvlObject result = sdg.Direct("Smithed",location, filter); + PvlObject::PvlGroupIterator grp = result.BeginGroup(); + while(grp != result.EndGroup()){selections.AddGroup(*grp);grp++;} + } + + //if (filter == ""){ + if (!ui.WasEntered("PREDICTFILTER") && !ui.WasEntered("RECONFILTER") && + !ui.WasEntered("SMITHEDFILTER")) { + string message = + "You must enter a filter AND directory for at least one type of kernel"; + throw Isis::iException::Message(Isis::iException::User,message,_FILEINFO_); + } + + //specify a name for the output file + Filename to("./kernels.????.db"); + if (ui.WasEntered("TO")){to = ui.GetFilename("TO");} + //create a new output version if the user specified any version sequence + if (to.Expanded().find_first_of("?") != string::npos){to.NewVersion();} + + Pvl writer; + writer.AddObject(selections); + writer.Write(to.Expanded()); +} diff --git a/isis/src/system/apps/kerneldbgen/kerneldbgen.xml b/isis/src/system/apps/kerneldbgen/kerneldbgen.xml new file mode 100644 index 0000000000000000000000000000000000000000..8043d952ccc0e02eabc1f6092e674422476d550a --- /dev/null +++ b/isis/src/system/apps/kerneldbgen/kerneldbgen.xml @@ -0,0 +1,559 @@ + + + + + Creates a database of kernels + + + +

    + This program is used to give the programmer and ISIS programs a database + with which they can reference coverage times for ck and spk kernels. Output + will thus be to a pvl file specified in the TO parameter. It should be noted + that the user is encouraged to use system preferences when defining pathnames, + for example $mgs or $base. If this is not possible, for example kernels are + being referenced that are located in a user's development area, absolute + pathnames should be used. Relative pathnames using ".", "..", or user-defined + environment variables are highly discouraged. +

    +

    + Kernels have different qualities. The lowest quality is nadir, which supplies + what may be considered "placeholder" values. Generally, nadir kernels exist + to fill in gaps and mimic the instrument pointing at -90 degrees. Since they + only mimic pointing data, they cannot be used for SPKs, since these kernels + specify positions rather than pointing. +

    +

    + The second lowest quality kernel is predict. Predict kernels are based on + the predicted location of spacecraft and thus are subject to error. +

    +

    + Reconstructed kernels are of higher quality than predicts. They are + supplemented with information as to the actual position of bodies and + spacecraft. +

    +

    + The highest quality kernels are smithed. These generally come from reconstructed + kernels that have been corrected even further by an individual institution. +

    +

    + The four levels of kernels listed above are the only ones that will be + listed in the database. Kernels are ordered from the lowest quality at the + top of the output file to the highest quality at the bottom of the output + file within individual kernel qualities, kernels are listed from earliest to + latest created file. This is done in anticipation of programs such as spiceinit + which read from the bottom of the file for the best kernel. +

    +
    + + + System + + + + + spiceinit + + + + + + Original version + + + Added relative pathnames to output database + + + Added examples + + + Moved from Geometry category to System + + + Added application test + + + Fixed constriction on filename size and fixed bug in appTest + + + Made changes to SpiceDbGen to comply with changes in KernelDb + + + Modified call to retrieve current time to refer to Time class, instead + of Application class + + + Removed spaces between Spacecraft Clock Count and Leapsecond Kernel + keywords + + + Fixed bug where spk and ck kernel files were flagged as "Predict" instead + of "Predicted" + + + Fixed bug where some ck kernels could not be loaded due to their size. + Also added naif status calls, which will provide easy to read iExceptions to the + user instead of a dump to the terminal window when a problem occurs. + + + Modified to use a vector of filters for each quality of kernel instead of + a single string + + + + + + + filename + + ./kernels.????.db + + + Location of the output file + + + This parameter may be used as a relative pathname to specify the + location of an output PVL database containing data on all of kernels + matched by kerneldbgen. It should be noted that version sequences + may be included in the pathname, in which case a new version will be + created. + + + + + + string + + CK + + + Kernel type + + + The kernel type specifies what sort of information the kernel contains. + Since kerneldbgen is intended for use only in situations where the most + recent kernel does not eclipse the content of previous kernels, there + are only two options: Spacecraft pointing kernels (CK) and Spacecraft + position kernels (SPK). + + + + + + + + + + string + + Directory where the predict quality kernels are located + + + This parameter specifies the path upon which the regular expression in + "PREDICTFILTER" will operate. Since this parameter will be used + explicitly in the "File" keyword of the generated database, it is + recommended that only shortcuts known to the ISIS system and absolute + pathnames are used. If left as "none" no predicted kernels will be + included in the database + + + none + + + + string + + Filter to identify predict quality kernels + + + none + + + This parameter is used to specify the kernel or kernels to be + identified as predicted. Any combination of kernel file names or + regular expression may be specified. The value of "PREDICTDIR" is + prepended to each element before being expanded. Each regular + expression is evaluated then the results are sorted according + to ASCII order and added to the list of available kernels. + + + + + + string + + Directory where the reconstructed quality kernels are located + + + This parameter specifies the path upon which the regular expression in + "RECONFILTER" will operate. Since this parameter will be used + explicitly in the "File" keyword of the generated database, it is + recommended that only shortcuts known to the ISIS system and absolute + pathnames are used. If left as "none" no reconstructed kernels will be + included in the database. + + + none + + + + string + + Filter to identify reconstructed quality kernels + + + This parameter is used to specify the kernel or kernels to be + identified as reconstructed. Any combination of kernel file names or + regular expression may be specified. The value of "RECONDIR" is + prepended to each element before being expanded. Each regular + expression is evaluated then the results are sorted according to ASCII + order and added to the list of available kernels. + + + none + + + + + + string + + Directory where the smithed quality kernels are located + + + This parameter specifies the path upon which the regular expression in + "SMITHEDFILTER" will operate. Since this parameter will be used + explicitly in the "File" keyword of the generated database, it is + recommended that only shortcuts known to the ISIS system and absolute + pathnames are used. If left as "none" no smithed kernels will be + included in the database + + + none + + + + string + + Filter to identify smithed quality kernels + + + This parameter is used to specify the kernel or kernels to be + identified as smithed. Any combination of kernel file names or regular + expression may be specified. The value of "SMITHED"DIR" is prepended + to each element before being expanded. Each regular expression is + evaluated then the results are sorted according to ASCII order and + added to the list of available kernels. + + + none + + + + + + + filename + + Spacecraft clock kernel + + + This parameter specifies a spacecraft clock kernel for use in + determining spacecraft pointing data. An actual kernel may be used, or + a pvl file of the form kernels.????.db that specifies SCLK data may + be used, where ???? is the version sequence. + + + + filename + + Leapsecond kernel + + + This parameter specifies a leapsecond kernel for use in + determining spacecraft data. An actual kernel may be used, or + a pvl file of the form kernels.????.db that specifies LSK data may + be used, where ???? is the version sequence. + + + + + + + + Messenger ck kernels + + + Use the ck option to create a database of spacecraft pointing kernels. + In this example, a database is being created for the pivot kernels + pertaining to the Messenger spacecraft. + + + + 'to=pivot_kernels.????.db + type = ck + recondir = $Messenger/kernels/ck + reconfilter= *_mdis_pivot.bc + lsk = $Base/kernels/lsk/naif0008.tls + sclk = $Messenger/kernels/sclk/messenger_167.tsc' + + + This command line argument will create the database pivot_kernels.0002.db, + assuming "0001" is the highest version in the target directory. Note the + use of single quotes around the invocation of kerneldbgen. This is + done because this particular run uses several characters such as the + wildcard (*) that would be interpreted by the shell. + + + + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to create a kernel database + of Messenger pivot kernels. Unlike running from the command line, the + program need not go through the shell. Consequently, the input does + not need to include escape sequences or quotes. + + + + + + + + + + + + + List of files before kerneldbgen has been run + + + As seen in this terminal snapshot, there are a number of files that will + match the reconfilter in the directory specified by the recondir. The + highest pivot_kernels version is 0001. + + + RECONDIR + + + + + + + + + + List of files after kerneldbgen has been run + + + None of the original files have been altered, but the versioning system + has created a new version of the pivot_kernels database named + pivot_kernels.0002.db. The content of this file is listed below. + + + TO + + + + The database created by kerneldbgen + + + As seen here, the database has picked up all of the files that match the + filter specified. Each time coverage interval is listed as a selection, + and the dependency kernels is listed in a "dependency" group. Note that + since the only type of filter specified was for Reconstructed kernels, + that is the only type of kernel to appear in the database. + + + TO + + + + + + MGS CK kernels + + + Use the ck option to create a database of pointing kernels. In + this example, kernels are being created for Mars Odyssey, both predict + and reconstructed quality. This example should be of interest because it shows + both the creation of a database with multiple levels of quality, and it also + shows the use of several different filters used in conjunction to pick up a + variety of reconstructed kernel names + + + + 'to=kernels.????.db + type = ck + + reconfilter= *_nadir.bc + recondir = $Odyssey/kernels/ck + reconfilter= m01_sc_ab*.bc;m01_sc_ext?.bc;m01_sc_map.bc;m01_sc_map?.bc;m01_sc_map??.bc;m01_sc_map?_v2.bc' + lsk = $Base/kernels/lsk/naif0008.tls + sclk = $Odyssey/kernels/sclk/ORB1_SCLKSCET.00113.tsc' + + + This command line argument will create the database kernels.0001.db, + assuming that file does not already exist in the target directory. As in the + previous example, the command line argument is surrounded by single quotes + in order to escape characters that would otherwise be considered special by + the shell. + + + + + + + + + + + Example GUI + + + Screenshot of the GUI with parameters set to create a kernel database + mixed with nadir kernels and reconstructed kernels. + + + + + + + + + + + + + List of files before kerneldbgen has been run + + + As seen in this terminal snapshot, there are a number of files that will + match the reconfilter in the directory specified by the recondir. The + highest pivot_kernels version is 0001. + + + RECONDIR + + + + + + + + + + List of files after kerneldbgen has been run + + + None of the original files have been altered, but the versioning system + has created the first version of the kernel database, kernels.0001.db. + The content of this file is listed as well. + + + TO + + + + + + kernels.0001.db + + + Here one can examine the results of the datafile. Note the ascending + order of kernel quality. + + TO + + + + + + + + + +
    diff --git a/isis/src/system/apps/kerneldbgen/tsts/Makefile b/isis/src/system/apps/kerneldbgen/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/system/apps/kerneldbgen/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/system/apps/kerneldbgen/tsts/ck/Makefile b/isis/src/system/apps/kerneldbgen/tsts/ck/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..22d27e64aa89bb707cf03300f713034856345190 --- /dev/null +++ b/isis/src/system/apps/kerneldbgen/tsts/ck/Makefile @@ -0,0 +1,16 @@ +APPNAME = kerneldbgen + +# grep -v RunTime testTmp/temp01.db > temp1.db 2>&1; +# head -n 19 testTmp/temp1.db > temp.1.db 2>&1; + +temp.db.txt.IGNORELINES = RunTime + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) to=$(OUTPUT)/temp.db.txt \ + type=CK \ + recondir=\$$mro/kernels/ck \ + reconfilter=mro_sc_2005-12-*.bc \ + sclk=\$$mro/kernels/sclk/MRO_SCLKSCET.00006.tsc \ + lsk=\$$base/kernels/lsk/naif0008.tls > /dev/null; diff --git a/isis/src/system/objs/KernelDb/KernelDb.cpp b/isis/src/system/objs/KernelDb/KernelDb.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4555301bef83bd66b8d63bf780c87ece030e6202 --- /dev/null +++ b/isis/src/system/objs/KernelDb/KernelDb.cpp @@ -0,0 +1,400 @@ +/** + * @file + * $Revision: 1.5 $ + * $Date: 2009/05/12 20:11:20 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include "iException.h" +#include "CameraFactory.h" +#include "Preference.h" +#include "Filename.h" +#include "iString.h" +#include "KernelDb.h" + +using namespace std; +using namespace Isis; + +// Create a new empty KernelDb +KernelDb::KernelDb(const unsigned int kernelTypes) { + p_filename = "None"; + p_kernelTypes = kernelTypes; +} + + +// Create a new KernelDb object using a filename +KernelDb::KernelDb(const std::string &dbName, const unsigned int kernelTypes) : + p_kernelData (dbName) { + p_filename = dbName; + p_kernelTypes = kernelTypes; +} + + +// Create a new KernelDb object using a stream +KernelDb::KernelDb(std::istream &dbStream, const unsigned int kernelTypes) { + dbStream >> p_kernelData; + p_filename = "internal stream"; + p_kernelTypes = kernelTypes; +} + + +// Return the highest version of all LeapSecond kernels identified by the DB +Kernel KernelDb::LeapSecond (Pvl &lab) { + return FindLast("LeapSecond", lab); +} + + +// Return the highest version of all TargetAttitudeShape kernels identified +// by the DB +Kernel KernelDb::TargetAttitudeShape (Pvl &lab) { + return FindLast("TargetAttitudeShape", lab); +} + + +// Return the highest version of all TargetPosition kernels identified +// by the DB +Kernel KernelDb::TargetPosition (Pvl &lab) { + return FindLast("TargetPosition", lab); +} + + +// Return the last matching time of all SpacecraftPointing kernels identified +// by the DB +std::priority_queue< Kernel > KernelDb::SpacecraftPointing (Pvl &lab) { + return FindAll("SpacecraftPointing", lab); +} + + +// Return the highest version of all SpaceCraftClock kernels identified +// by the DB +Kernel KernelDb::SpacecraftClock (Pvl &lab) { + return FindLast("SpacecraftClock", lab); +} + + +// Return the last matching time of all SpacecraftPosition kernels identified +// by the DB +Kernel KernelDb::SpacecraftPosition (Pvl &lab) { + return FindLast("SpacecraftPosition", lab); +} + + +// Return the last Instrument kernal found which matches the criteria in the DB +Kernel KernelDb::Instrument (Pvl &lab) { + return FindLast("Instrument", lab); +} + + +// Return the highest version of all Frame kernels identified +// by the DB +Kernel KernelDb::Frame (Pvl &lab) { + return FindLast("Frame", lab); +} + + +// Return the last InstrumentAddendum kernal found which matches the +// criteria in the DB +Kernel KernelDb::InstrumentAddendum (Pvl &lab) { + return FindLast("InstrumentAddendum", lab); +} + + +// Return the highest version DEM found which matches the criteria in the DB +Kernel KernelDb::Dem (Pvl &lab) { + return FindLast("Dem", lab); +} + +Kernel KernelDb::FindLast(const std::string &entry, Isis::Pvl &lab) { + std::priority_queue< Kernel > all = FindAll(entry, lab); + Kernel last; + + if(all.size() > 0) { + last = all.top(); + } + + return last; +} + +std::priority_queue< Kernel > KernelDb::FindAll(const std::string &entry, Isis::Pvl &lab) { + std::priority_queue< Kernel > filesFound; + int cameraVersion = CameraFactory::CameraVersion(lab); + Isis::PvlObject &cube = lab.FindObject("IsisCube"); + + // Make sure the entry has been loaded into memory + if (!p_kernelData.HasObject(entry)) { + return filesFound; + } + + // Get the start and end time for the cube + iTime start(((string) cube.FindGroup("Instrument")["StartTime"])); + iTime end; + if (cube.FindGroup("Instrument").HasKeyword("StopTime")) { + end = ((string) cube.FindGroup("Instrument")["StopTime"]); + } + else { + end = ((string) cube.FindGroup("Instrument")["StartTime"]); + } + + // lastType will be used to check if the new group's type is better/worse than the last match + string lastType; + lastType.clear(); + + // Get the object and search through it's groups + PvlObject &obj = p_kernelData.FindObject(entry); + for (int group = obj.Groups()-1; group >= 0; group--) { + // Get the group and start testing the cases in the keywords to see if they all match this cube + PvlGroup &grp = obj.Group(group); + + // These are the conditions that make this test pass: + // 1) No time OR At least one matching time + // 2) All keyword matches are true OR No keyword matches present + // + // In order to accomplish this, matchTime is initialized to true and remains as such if and only if + // there are no time conditionals. If Time keywords exist, one of them has to set matchTime to true. + // The matchKeywords is true until a mismatch is found. + bool matchTime = !grp.HasKeyword("Time"); + bool matchKeywords = true; + + // If the group name isn't selection, skip it. + if (!grp.IsNamed("Selection")) { + continue; + } + + iString type = ""; + + // Make sure the type is better + if(grp.HasKeyword("Type")) { + type = (string) grp["Type"]; + if (!(spiceInit::kernelTypeEnum(type) & p_kernelTypes)) { + continue; + } + } + + // First, the time search. Loop through the keywords, if the name isn't Time then + // skip it. If it is, then get the start/end times and keep looking until one is found. + for (int keyword = 0; keyword < grp.Keywords(); keyword ++) { + PvlKeyword key = grp[keyword]; + + if (key.IsNamed("Time")) { + // Pull the selections start and end time out + iTime kernelStart = (string) key[0]; + iTime kernelEnd = (string) key[1]; + + // If the kernel times inside of the requested times we + // set the matchTime to be true. + if ((kernelStart <= start) && (kernelEnd >= end)) { + matchTime = true; + } + } + else if (key.IsNamed("Match")) { + try { + iString matchGroup = key[0]; + iString matchKey = key[1]; + iString matchValue = key[2]; + + iString cubeValue = (string)cube.FindGroup(matchGroup)[matchKey]; + cubeValue.ConvertWhiteSpace(); + cubeValue.Compress(); + cubeValue.Trim(" "); + cubeValue.UpCase(); + + matchValue.ConvertWhiteSpace(); + matchValue.Compress(); + matchValue.Trim(" "); + matchValue.UpCase(); + + // If strings are not the same, match automatically fails + if (cubeValue.compare(matchValue) != 0) { + matchKeywords = false; + } + } catch (Isis::iException &e) { + // This error is thrown if the group or keyword do not exist in 'lab' + matchKeywords = false; + } + } + else if(key.IsNamed("CameraVersion")) { + try { + for(int camVersionKeyIndex = 0; camVersionKeyIndex < key.Size(); camVersionKeyIndex++) { + bool versionMatch = false; + iString val = (std::string)key[camVersionKeyIndex]; + iString commaTok; + + while ((commaTok = val.Token(",")).length() > 0) { + if (commaTok.find('-') != std::string::npos) { + iString dashTok; + int start = commaTok.Token("-").ToInteger(); + int end = commaTok.Token("-").ToInteger(); + int direction; + direction = (start<=end) ? 1 : -1; + // Save the entire range of bands + for (int version = start; version != end+direction; version+=direction) { + if(version == cameraVersion) { + versionMatch = true; + } + } + } + // This token is a single band specification + else { + if(commaTok.ToInteger() == cameraVersion) { + versionMatch = true; + } + } + } + + if(!versionMatch) { + matchKeywords = false; + } + + } + } catch (Isis::iException &e) { + matchKeywords = false; + } + } + } + + if(matchKeywords && matchTime) { + lastType = type; + filesFound.push(Kernel(spiceInit::kernelTypeEnum(type), GetFile(grp))); + } + } + + return filesFound; +} + +// Load the DB with the defined BASE and MISSION info for each type of kernel +void KernelDb::LoadSystemDb (const std::string &mission) { + + // Get the base DataDirectory + PvlGroup &datadir = Preference::Preferences().FindGroup("DataDirectory"); + string baseDir = datadir["Base"]; + + // Get the mission DataDirectory + string missionDir = datadir[mission]; + + // Load the leapsecond DB + Isis::Filename lsDb(baseDir + "/" + "kernels/lsk/kernels.????.db"); + lsDb.HighestVersion(); + p_kernelData.Read (lsDb.Expanded()); + + // Load the target attitude shape DB + Isis::Filename tasDbPath(missionDir + "/" + "kernels/pck"); + if( tasDbPath.Exists()) { + Isis::Filename tasDb(missionDir + "/" + "kernels/pck/kernels.????.db"); + tasDb.HighestVersion(); + p_kernelData.Read (tasDb.Expanded()); + } + else { + Isis::Filename baseTasDb(baseDir + "/" + "kernels/pck/kernels.????.db"); + baseTasDb.HighestVersion(); + p_kernelData.Read (baseTasDb.Expanded()); + } + + // Load the target position DB + Isis::Filename tpDbPath(missionDir + "/" + "kernels/tspk"); + if( tpDbPath.Exists()) { + Isis::Filename tpDb(missionDir + "/" + "kernels/tspk/kernels.????.db"); + tpDb.HighestVersion(); + p_kernelData.Read (tpDb.Expanded()); + } + else { + Isis::Filename baseTpDb(baseDir + "/" + "kernels/spk/kernels.????.db"); + baseTpDb.HighestVersion(); + p_kernelData.Read (baseTpDb.Expanded()); + } + + // Load the DEM DB + Isis::Filename demDb(baseDir + "/" + "dems/kernels.????.db"); + demDb.HighestVersion(); + p_kernelData.Read (demDb.Expanded()); + + // Load the mission specific spacecraft pointing DB + Isis::Filename spDb(missionDir + "/" + "kernels/ck/kernels.????.db"); + spDb.HighestVersion(); + p_kernelData.Read (spDb.Expanded()); + + // Load the mission specific frame DB + Isis::Filename fDb(missionDir + "/" + "kernels/fk/kernels.????.db"); + fDb.HighestVersion(); + p_kernelData.Read (fDb.Expanded()); + + // Load the mission specific instrument DB + Isis::Filename iDb(missionDir + "/" + "kernels/ik/kernels.????.db"); + iDb.HighestVersion(); + p_kernelData.Read (iDb.Expanded()); + + // Load the mission specific spacecraft clock DB + Isis::Filename scDb(missionDir + "/" + "kernels/sclk/kernels.????.db"); + scDb.HighestVersion(); + p_kernelData.Read (scDb.Expanded()); + + // Load the mission specific spacecraft position DB + Isis::Filename sposDb(missionDir + "/" + "kernels/spk/kernels.????.db"); + sposDb.HighestVersion(); + p_kernelData.Read (sposDb.Expanded()); + + // Load the mission specific instrument addendum DB + Isis::Filename iakDb(missionDir + "/" + "kernels/iak/kernels.????.db"); + iakDb.HighestVersion(); + p_kernelData.Read (iakDb.Expanded()); +} + +std::vector KernelDb::GetFile (PvlGroup &grp) { + std::vector files; + //PvlKeyword kfile = grp["File"]; + + for (int i=0; i= oType)) return true; + + return false; +} + diff --git a/isis/src/system/objs/KernelDb/KernelDb.h b/isis/src/system/objs/KernelDb/KernelDb.h new file mode 100644 index 0000000000000000000000000000000000000000..f553f7805b5c8b4504f4489d9225f2a7704f8a2f --- /dev/null +++ b/isis/src/system/objs/KernelDb/KernelDb.h @@ -0,0 +1,155 @@ +#ifndef KernelDb_h +#define KernelDb_h + +/** + * @file + * $Revision: 1.7 $ + * $Date: 2009/07/28 21:01:18 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include +#include + +#include "Pvl.h" +#include "iTime.h" +#include "iString.h" + +namespace spiceInit { + + enum kernelTypes { + Predicted = 1, + Nadir = 2, + Reconstructed = 4, + Smithed = 8 + }; + + inline kernelTypes kernelTypeEnum (const std::string &type) { + Isis::iString strng = type; + strng.ConvertWhiteSpace(); + strng.Compress(); + strng.Trim(" "); + strng.UpCase(); + if (strng == "PREDICTED") return Predicted; + if (strng == "NADIR") return Nadir; + if (strng == "RECONSTRUCTED") return Reconstructed; + if (strng == "SMITHED") return Smithed; + + return (kernelTypes)0; + } + + inline const char* kernelTypeEnum (const kernelTypes &type) { + if(type == Predicted) return "Predicted"; + if(type == Nadir) return "Nadir"; + if(type == Reconstructed) return "Reconstructed"; + if(type == Smithed) return "Smithed"; + + return "Unknown"; + } +}; + +class Kernel; + + /** + * @brief KernelDb class + * + * If you would like to see KernelDb being used + * in implementation, see spiceinit. + * + * @ingroup System + * + * @internal + * @history 2005-12-27 Jacob Danton - Added support for multiple + * files and fixed a bug in SearchMatch. + * @history 2007-07-09 Steven Lambright - Removed inheritance from PVL + * @history 2007-10-25 Steven Koechle - Corrected Smithed Enum + * fixed search methods. + * @history 2007-07-09 Steven Lambright - Added Kernel class and multiple-ck return + * @history 2009-05-12 Steven Lambright - Added Camera Version Checking + */ +class KernelDb { + + public: + // constructor + KernelDb (const unsigned int kernelTypes); + KernelDb (const std::string &dbName, const unsigned int kernelTypes); + KernelDb (std::istream &dbStream, const unsigned int kernelTypes); + + // destructor + ~KernelDb () {}; + + // Members for getting kernels + Kernel LeapSecond (Isis::Pvl &lab); + Kernel TargetAttitudeShape (Isis::Pvl &lab); + Kernel TargetPosition (Isis::Pvl &lab); + std::priority_queue< Kernel > SpacecraftPointing (Isis::Pvl &lab); + Kernel SpacecraftClock (Isis::Pvl &lab); + Kernel SpacecraftPosition (Isis::Pvl &lab); + Kernel Instrument (Isis::Pvl &lab); + Kernel Frame (Isis::Pvl &lab); + Kernel InstrumentAddendum (Isis::Pvl &lab); + Kernel Dem (Isis::Pvl &lab); + + Kernel FindLast(const std::string &entry, Isis::Pvl &lab); + std::priority_queue< Kernel > FindAll(const std::string &entry, Isis::Pvl &lab); + + void LoadSystemDb (const std::string &mission); + + // Returns true if the newType is allowed and better than + // the oldType + const bool Better (const std::string newType, const std::string oldType); + const bool Better (const spiceInit::kernelTypes newType, const spiceInit::kernelTypes oldType); + + protected: + std::string p_filename; + + private: + std::vector GetFile (Isis::PvlGroup &grp); + unsigned int p_kernelTypes; + Isis::Pvl p_kernelData; +}; + +class Kernel { + public: + Kernel() { + kernelType = (spiceInit::kernelTypes)0; + } + + Kernel(spiceInit::kernelTypes type, const std::vector &data) { + kernelType = type; + kernels = data; + } + + bool operator<(const Kernel &other) const { + return (this->kernelType < other.kernelType); + } + + const int size() { return kernels.size(); } + void push_back(const std::string &str) { kernels.push_back(str); } + + std::string &operator[](const int index) { return kernels[index]; } + std::string operator[](const int index) const { return kernels[index]; } + + spiceInit::kernelTypes kernelType; + std::vector kernels; +}; + +#endif + + diff --git a/isis/src/system/objs/KernelDb/KernelDb.truth b/isis/src/system/objs/KernelDb/KernelDb.truth new file mode 100644 index 0000000000000000000000000000000000000000..cf16bcb003b24da305e65610b8f6b02680f8683b --- /dev/null +++ b/isis/src/system/objs/KernelDb/KernelDb.truth @@ -0,0 +1,33 @@ +LeapSecond: +$base/lsTest + +TargetAttitudeShape: +$base/pckTest + +TargetPosition: +$base/spkTest1 +$base/spkTest2 + +SpacecraftPointing: +$base/ckTest + +Instrument: +$base/ikTest3 +$base/ikTest4 + +SpacecraftClock: +$base/sclkTest + +SpacecraftPosition: +$base/spkTest1 +$base/spkTest2 + +Frame: +$base/fkTest + +InstrumentAddendum: +$base/iakTest + +Dem: +$base/demTest1 +$base/demTest2 diff --git a/isis/src/system/objs/KernelDb/Makefile b/isis/src/system/objs/KernelDb/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0ff1a6c081a2a34c38bdfc7c85a007d0dc44394d --- /dev/null +++ b/isis/src/system/objs/KernelDb/Makefile @@ -0,0 +1,5 @@ +INCS = KernelDb.h +SRCS = KernelDb.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/system/objs/KernelDb/test.db b/isis/src/system/objs/KernelDb/test.db new file mode 100644 index 0000000000000000000000000000000000000000..3106e7668bfede1275cd98c02c20abfaa3b3a7e3 --- /dev/null +++ b/isis/src/system/objs/KernelDb/test.db @@ -0,0 +1,114 @@ +Object = LeapSecond + Group = Selection + File = ("base", "lsTest") + EndGroup +EndObject + +Object = TargetAttitudeShape + Group = Selection + File = ("base", "pckIncorrect") + EndGroup + Group = Selection + File = ("base", "pckTest") + EndGroup +EndObject + +Object = TargetPosition + Group = Selection + File = ("base", "spkTest1") + File = ("base", "spkTest2") + EndGroup +EndObject + +Object = SpacecraftPointing + Group = Selection + Time = ("2005 JAN 01 01:00:00.000 TDB", "2006 JAN 01 01:00:00.000 TDB") + File = ("base", "ckIncorrect") + Type = Reconstructed + EndGroup + Group = Selection + Time = ("2005 JAN 01 01:00:00.000 TDB", "2006 JAN 01 01:00:00.000 TDB") + File = ("base", "ckTest") + Type = Reconstructed + EndGroup + + Group = Selection + Time = ("2004 JAN 01 01:00:00.000 TDB", "2005 JAN 01 01:00:00.000 TDB") + File = ("base", "ckIncorrect") + Type = Reconstructed + EndGroup +EndObject + +Object = Instrument + Group = Selection + Match = ("TestGroup","TestKeyword","TestValue") + File = ("base", "ikTest1") + File = ("base", "ikTest2") + CameraVersion = "2" + EndGroup + + Group = Selection + Match = ("TestGroup","TestKeyword","TestValue") + File = ("base", "ikTest3") + File = ("base", "ikTest4") + CameraVersion = "1" + EndGroup + + Group = Selection + Match = ("TestGroup","TestKeyword","TestValue") + File = ("base", "ikTest5") + File = ("base", "ikTest6") + CameraVersion = "3" + EndGroup +EndObject + +Object = SpacecraftClock + Group = Selection + File = ("base", "sclkTest") + EndGroup +EndObject + +Object = SpacecraftPosition + Group = Selection + Time = ("2005 JAN 01 01:00:00.000 TDB", "2006 JAN 01 01:00:00.000 TDB") + File = ("base", "spkTest1") + File = ("base", "spkTest2") + Type = Reconstructed + EndGroup +EndObject + +Object = Frame + Group = Selection + File = ("base", "fkTest") + EndGroup +EndObject + +Object = InstrumentAddendum + Group = Selection + Match = ("TestGroup","TestKeyword","TestValue") + File = ("base", "iakTest") + EndGroup + + Group = Selection + Match = ("TestGroup","TestKeyword","IncorrectValue") + File = ("base", "iakIncorrect") + EndGroup + + Group = Selection + Match = ("TestGroup","IncorrectKeyword","TestValue") + File = ("base", "iakIncorrect") + EndGroup + + Group = Selection + Match = ("IncorrectGroup","TestKeyword","TestValue") + File = ("base", "iakIncorrect") + EndGroup +EndObject + +Object = Dem + Group = Selection + Match = ("TestGroup","TestKeyword","TestValue") + File = ("base", "demTest1") + File = ("base", "demTest2") + EndGroup +EndObject diff --git a/isis/src/system/objs/KernelDb/unitTest.cpp b/isis/src/system/objs/KernelDb/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d3ed22547a1db4f08a741566c3b27fd2e226ed4 --- /dev/null +++ b/isis/src/system/objs/KernelDb/unitTest.cpp @@ -0,0 +1,102 @@ +#include +#include "iException.h" +#include "KernelDb.h" +#include "Preference.h" + +using namespace std; + +int main(int argc, char *argv[]) +{ + Isis::Preference::Preferences(true); + + KernelDb kdb("test.db", 15); + + Isis::Pvl lab; + Isis::PvlObject obj("IsisCube"); + Isis::PvlGroup group("Instrument"); + Isis::PvlGroup group2("TestGroup"); + Isis::PvlKeyword keyword("TestKeyword","TestValue"); + Isis::PvlKeyword startKey("StartTime","2005 JUN 15 12:00:00.000 TDB"); + Isis::PvlKeyword spacecraft("SpacecraftName", "IdealSpacecraft"); + Isis::PvlKeyword instrument("InstrumentId", "IdealCamera"); + Isis::PvlKeyword endKey("EndTime","2005 DEC 15 12:00:00.000 TDB"); + group2.AddKeyword(keyword); + group.AddKeyword(startKey); + group.AddKeyword(endKey); + group.AddKeyword(spacecraft); + group.AddKeyword(instrument); + obj.AddGroup(group); + obj.AddGroup(group2); + lab.AddObject(obj); + std::vector temp; + + temp.clear(); + temp = kdb.LeapSecond(lab).kernels; + cout << "LeapSecond: " << endl; + for (unsigned int i=0; i /dev/null; + vik2isis from=$(OUTPUT)/f387a06.img to=$(OUTPUT)/f387a06.cub > /dev/null; diff --git a/isis/src/viking/apps/vdcomp/vdcomp.c b/isis/src/viking/apps/vdcomp/vdcomp.c new file mode 100644 index 0000000000000000000000000000000000000000..85836109a018349bd9ae039f1e9c3017234038e8 --- /dev/null +++ b/isis/src/viking/apps/vdcomp/vdcomp.c @@ -0,0 +1,1504 @@ +/** +* Modified by Jeff Anderson, May 19, 2005 +* 64-bit Solaris port required replacing long with int and +* adding malloc.h +* +* Modified by Jeannie Walldren, March 23, 2009 +* Allow string length of 1024 characters for input and output +* filenames, inname[] and outname[] +*/ + +/********************************************************************/ +/* Image Decompression Program - C Version for PC, VAX, Unix */ +/* and Macintosh systems. */ +/* */ +/* Decompresses images using Kris Becker's subroutine DECOMP.C */ +/* which is included in this program in a shortened version. */ +/* */ +/* Reads a variable length compressed PDS image and outputs a */ +/* fixed length uncompressed image file in PDS format with */ +/* labels, image histogram, engineering table, line header table */ +/* and an image with PDS, FITS, VICAR or no labels. If used on */ +/* a non-byte-swapped machine the image histogram is un-swapped. */ +/* */ +/********************************************************************/ +/* */ +/* Use the following commands to compile and link to produce an */ +/* executable file: */ +/* */ +/* On an IBM PC (using Microsoft C Version 5.x) */ +/* */ +/* cl /c vdcomp.c */ +/* link vdcomp/stack:10000; */ +/* */ +/* On a VAX: */ +/* */ +/* cc vdcomp */ +/* $define lnk$library sys$library:vaxcrtl.olb */ +/* link vdcomp */ +/* */ +/* On a Unix host (Sun, Masscomp) */ +/* */ +/* cc -o vdcomp vdcomp.c */ +/* */ +/* On a Macintosh (using Lightspeed C) */ +/* */ +/* link with the following libraries: */ +/* stdio, storage, strings, unix and MacTraps, with MacTraps */ +/* and vdcomp in a separate segment. */ +/* */ +/********************************************************************/ +/* */ +/* Use the following command to run the program: */ +/* */ +/* VDCOMP [infile] [outfile] [output format] */ +/* */ +/* infile - name of compressed image file. */ +/* outfile - name of uncompressed output file. */ +/* output format - selected from the following list: */ +/* */ +/* 1 SFDU/PDS format [DEFAULT]. */ +/* 2 FITS format. */ +/* 3 VICAR format. */ +/* 4 Unlabelled binary array. */ +/* */ +/* On the VAX computer you will need to 'install' the program to */ +/* be able to use command line arguments using the following */ +/* command: */ +/* */ +/* $ vdcomp :== $DISKNAME:[DIRECTORY]vdcomp.exe */ +/* */ +/* where DISKNAME is the disk drive and DIRECTORY is the */ +/* directory where VDCOMP.EXE is stored. */ +/* */ +/********************************************************************/ +/* */ +/* LIMS */ +/* This program has been tested on a VAX 780 (VMS 4.6), SUN */ +/* Workstation (UNIX 4.2, release 3.4), an IBM PC */ +/* (MICROSOFT 5.1 compiler) and Macintosh IIx using Lightspeed C */ +/* version 3.0. When converting to other systems, check for */ +/* portability conflicts. */ +/* */ +/* HIST */ +/* datri@convex.com, 11-15-91 added recognition of - as stdout for */ +/* output filename; disabled various messages; directed */ +/* messages to stderr; added exit status */ +/* JUN04 Jeff Anderson - Removed compiler warnings */ +/* DEC89 Modified program to handle both Voyager and Viking images.*/ +/* OCT89 Converted Voyager decompression program to handle Viking */ +/* compressed images. Changed obuf to 'unsigned' to simplify */ +/* computation of checksum. */ +/* AUG89 Added code to get command line arguments for filenames */ +/* and output format; routines to free memory used by the Huffman */ +/* tree); fixed the SFDU label output length; and modified the */ +/* I/O routines so that the open for Host type 2 uses binary I/O. */ +/* JUN89 Fixed READVAR, to get length on 16-bit unswapped hosts. */ +/* JUL88 C driver to decompress standard Voyager Compressed images */ +/* by Mike Martin 1989/12/02 */ +/* */ +/* Inputs - Input file to be decompressed. */ +/* */ +/* Outputs - Output file containing decompressed image. */ +/* */ +/********************************************************************/ +/* */ +/* Return Value Codes: */ +/* */ +/* 0: Success */ +/* 1: Help mode triggered */ +/* 2: Could not write output file */ +/* 3: Could not open input file */ +/* 4: Could not open output file */ +/* 5: Out of memory in half_tree */ +/* 6: Out of memory in new_node */ +/* 7: Invalid byte count in dcmprs */ +/* 42: Input file has invalid or corrupted line header table */ +/* */ +/********************************************************************/ + +#include +#include +#include + +#define TRUE 1 +#define FALSE 0 + + /* pc i/o defines */ +#define O_RDONLY 0x0000 /* open for reading only */ +#define O_BINARY 0x8000 /* file mode is binary */ + + /* vax i/o defines */ +#define RECORD_TYPE "rfm=fix" /* VAX fixed length output */ +#define CTX "ctx=bin" /* no translation of \n */ +#define FOP "fop=cif,sup" /* file processing ops */ + +typedef struct leaf + { + struct leaf *right; + short int dn; + struct leaf *left; + } NODE; + +/************************************************************************* + Declare the tree pointer. This pointer will hold the root of the tree + once the tree is created by the accompanying routine huff_tree. +**************************************************************************/ + + NODE *tree; + +/* subroutine definitions */ + +void pds_labels(); +void fits_labels(); +void vicar_labels(); +void no_labels(); +int check_host(); +int get_files(); +void open_files(); +int swap_long(); +void decompress(); +void decmpinit(); +void free_tree(); + +/* global variables */ + +int infile; +FILE *outfile; +char inname[1025],outname[1025]; +int output_format; +int record_bytes, max_lines; +int line_samples, fits_pad; +int label_checksum = 0L, checksum = 0L; + + +/*************************************************/ +int main(argc,argv) + int argc; + char **argv; +{ + unsigned char ibuf[65536],obuf[65536]; + unsigned char blank=32; + short host,total_bytes,line,i; + int length,x,long_length,hist[511]; + int count; + + /*********************************************************************/ + /* */ + /* get host information and input and output files */ + /* */ + /*********************************************************************/ + + strcpy(inname," "); + strcpy(outname," "); + output_format = 0; + + if (argc == 1); /* prompt user for parameters */ + else if (argc == 2 && (strncmp(argv[1],"help",4) == 0 || + strncmp(argv[1],"HELP",4) == 0 || + strncmp(argv[1],"?",1) == 0)) { + fprintf(stderr, + "PDS Image Decompression Program. Command line format:\n\n"); + fprintf(stderr,"VDCOMP [infile] [outfile] [format code]\n"); + fprintf(stderr," infile - name of compressed image file. \n"); + fprintf(stderr," outfile - name of uncompressed output file.\n"); + fprintf(stderr," output format - selected from the following list:\n"); + fprintf(stderr,"\n"); + fprintf(stderr," 1 SFDU/PDS format [DEFAULT].\n"); + fprintf(stderr," 2 FITS format. \n"); + fprintf(stderr," 3 VICAR format. \n"); + fprintf(stderr," 4 Unlabelled binary array. \n\n"); + exit(1); + } + else { + strcpy(inname,argv[1]); + if (argc >= 3) strcpy(outname,argv[2]); + if (argc == 3) output_format = 1; + if (argc == 4) sscanf(argv[3],"%d",&output_format); + } + + host = check_host(); + host = get_files(host); /* may change host if VAX */ + + /*********************************************************************/ + /* */ + /* read and edit compressed file labels */ + /* */ + /*********************************************************************/ + + switch (output_format) { + case 1: pds_labels(host); break; + case 2: fits_labels(host); break; + case 3: vicar_labels(host); break; + case 4: no_labels(host); break; + } + + if (record_bytes == 836) { /* set up values for image sizes */ + max_lines = 800; + fits_pad = 2240; + line_samples = 800; + } + else { + max_lines = 1056; + fits_pad = 1536; + line_samples = 1204; + } + + /*********************************************************************/ + /* */ + /* process the image histogram */ + /* */ + /*********************************************************************/ + + /* need to know record_bytes,hist_count,hist_item_type,item_count.*/ + total_bytes = 0; + length = read_var((char *)hist,host); + total_bytes = total_bytes + length; + + if (record_bytes == 836) { /* read one more time for Voyager image */ + length = read_var((char *)hist+record_bytes,host); + total_bytes = total_bytes + length; + } + + if (host == 2 || host == 5) /* If non-byte swapped */ + for (i=0; i<256; i++) /* host, swap bytes in */ + hist[i] = swap_long(hist[i]); /* the output histogram */ + + if (output_format == 1) { + if (record_bytes == 836) { + fwrite((char *)hist, record_bytes,1,outfile); + fwrite((char *)hist+record_bytes,length,1,outfile); + } + else { + fwrite((char *)hist, 1024,1,outfile); + total_bytes = 1024; + } + + /* pad out the histogram to a multiple of record bytes */ + if (record_bytes == 836) + for (i=total_bytes; i 0 && line < max_lines); + + if (record_bytes == 1204 && (outfile != stdout)) + /* print checksum for viking */ +/* + fprintf(stderr,"\n Image label checksum = %ld computed checksum = %ld\n", + label_checksum,checksum); +*/ + + /* pad out FITS file to a multiple of 2880 */ + if (output_format == 2) + for (i=0;i 0 && shortint < 80) { + host = 4; /* change host to 4 */ +// printf("This is not a VAX variable length file."); + } +// else printf("This is a VAX variable length file."); + lseek(infile, (off_t) 0, SEEK_SET); /* reposition to beginning of file */ + } + } + + if (output_format == 0) + do { + printf("\nEnter a number for the output format desired:\n"); + printf("\n 1. SFDU/PDS format."); + printf("\n 2. FITS format."); + printf("\n 3. VICAR format."); + printf("\n 4. Unlabelled binary array.\n"); + printf("\n Enter format number:"); + // gets(inname); - JAA replaced with scanf + scanf ("%s",inname); + output_format = atoi(inname); + } while (output_format < 1 || output_format > 4); + + if (outname[0] == ' ') { + printf("\nEnter name of uncompressed output file: "); + // gets (outname); - JAA replaced with scanf + scanf ("%s",outname); + } + + return(host); +} + + +/*********************************************************************/ +/* */ +/* subroutine open_files - open the output file after we get */ +/* its record size by reading the input file labels. */ +/* */ +/*********************************************************************/ + +void open_files(host) +int *host; +{ + if (*host == 1 || *host == 2 || *host == 5) { + if (outname[0] == '-') outfile=stdout; + else if ((outfile = fopen(outname,"wb"))==NULL) { + fprintf(stderr,"\ncan't open output file: %s\n",outname); + exit(4); + } + } + + else if (*host == 3 || *host == 4) { + if (output_format == 1) { /* write PDS format blocks */ + if (record_bytes == 836) { + if ((outfile=fopen(outname,"w" +#ifdef VMS + ,"mrs=836",FOP,CTX,RECORD_TYPE +#endif + ))==NULL) { + fprintf(stderr,"\ncan't open output file: %s\n",outname); + exit(4); + } + } + else { + if ((outfile=fopen(outname,"w" +#ifdef VMS + ,"mrs=1204",FOP,CTX,RECORD_TYPE +#endif + ))==NULL) { + fprintf(stderr,"\ncan't open output file: %s\n",outname); + exit(4); + } + } + } + else if (output_format == 2) { /* write FITS format blocks */ + if ((outfile=fopen(outname,"w" +#ifdef VMS + ,"mrs=2880",FOP,CTX,RECORD_TYPE +#endif + ))==NULL) { + fprintf(stderr,"\ncan't open output file: %s\n",outname); + exit(4); + } + } + + else { /* write fixed length records */ + if (record_bytes == 836) { + if ((outfile=fopen(outname,"w" +#ifdef VMS + ,"mrs=800",FOP,CTX,RECORD_TYPE +#endif + ))==NULL) { + fprintf(stderr,"\ncan't open output file: %s\n",outname); + exit(4); + } + } + else { + if ((outfile=fopen(outname,"w" +#ifdef VMS + ,"mrs=1204",FOP,CTX,RECORD_TYPE +#endif + ))==NULL) { + fprintf(stderr,"\ncan't open output file: %s\n",outname); + exit(4); + } + } + } + } +} + + +/*********************************************************************/ +/* */ +/* subroutine pds_labels - edit PDS labels and write to output file */ +/* */ +/*********************************************************************/ + +void pds_labels(host) + int host; +{ + char outstring[80],ibuf[2048]; + unsigned char cr=13,lf=10,blank=32; + short length,nlen,total_bytes,line,i; + + + total_bytes = 0; + do { + length = read_var(ibuf,host); +#ifdef VMS + ibuf[length] = 0; +#else + // FIXED 2008/10/29, "NULL" was improper, \0 needed to be the specifier for a null terminator. + // - Steven Lambright, pointed out by "novas0x2a" (Support Forum Member) + ibuf[length] = '\0'; +#endif + + /******************************************************************/ + /* edit labels which need to be changed */ + /******************************************************************/ + + if ((i = strncmp(ibuf,"NJPL1I00PDS1",12)) == 0); + else if ((i = strncmp(ibuf,"CCSD3ZF00001",12)) == 0); + else if ((i = strncmp(ibuf,"/* FILE",16)) == 0); + else if ((i = strncmp(ibuf,"RECORD_TYPE",11)) == 0); + + /*****************************************************************/ + /* don't write any of these labels out until we get the record */ + /* bytes parameter. */ + /*****************************************************************/ + + else if ((i = strncmp(ibuf,"RECORD_BYTES",12)) == 0) { + /*****************************************************************/ + /* get the record_bytes value */ + /*****************************************************************/ + + sscanf(ibuf+35,"%d",&record_bytes); + if (record_bytes != 836) record_bytes = 1204; + open_files(&host); + + /* now we can write out the SFDU, comment and Record Type labels. */ + if (record_bytes == 836) + fwrite("CCSD3ZF0000100000001NJPL3IF0PDS200000001 = SFDU_LABEL", + 53,1,outfile); + else + fwrite("CCSD3ZF0000100000001NJPL3IF0PDS200000001 = SFDU_LABEL", + 53,1,outfile); + + fprintf(outfile,"%c%c",cr,lf); + fwrite("/* FILE FORMAT AND LENGTH */",37,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + fwrite("RECORD_TYPE = FIXED_LENGTH",47,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + + /* fix record_bytes parameter for Viking images */ + if (record_bytes == 1204) strcpy(ibuf+35,"1204"); + fwrite(ibuf,length,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + length + 57 + 39 + 49; + } + + else if ((i = strncmp(ibuf,"FILE_RECORDS",12)) == 0) { + /*****************************************************************/ + /* change the file_records count */ + /*****************************************************************/ + + if (record_bytes == 836) strcpy(ibuf+35,"806"); + else strcpy(ibuf+35,"1115"); + fwrite(ibuf,length,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + length + 2; + } + + else if ((i = strncmp(ibuf,"LABEL_RECORDS",13)) == 0) { + /*****************************************************************/ + /* change the label_records count from 56 to 3 */ + /*****************************************************************/ + + if (record_bytes == 836) strcpy(ibuf+35,"3"); + else strcpy(ibuf+35,"2"); + length -= 1; + fwrite(ibuf,length,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + length + 2; + } + + else if ((i = strncmp(ibuf,"^IMAGE_HISTOGRAM",16)) == 0) { + /*****************************************************************/ + /* change the location pointer of image_histogram to record 4 */ + /*****************************************************************/ + + if (record_bytes == 836) strcpy(ibuf+35,"4"); + else strcpy(ibuf+35,"3"); + length -= 1; + fwrite(ibuf,length,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + length + 2; + } + + else if ((i = strncmp(ibuf,"^ENCODING_HISTOGRAM)",19)) == 0); + + /*****************************************************************/ + /* delete the encoding_histogram location pointer */ + /*****************************************************************/ + + else if ((i = strncmp(ibuf,"^ENGINEERING_TABLE",18)) == 0) { + /*****************************************************************/ + /* change the location pointer of engineering_summary to record 6*/ + /*****************************************************************/ + + if (record_bytes == 836) strcpy(ibuf+35,"6"); + else strcpy(ibuf+35,"4"); + length -= 1; + fwrite(ibuf,length,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + length + 2; + } + + else if ((i = strncmp(ibuf,"^LINE_HEADER_TABLE",18)) == 0) { + /*****************************************************************/ + /* change the location pointer of line header table to record 5 */ + /*****************************************************************/ + + strcpy(ibuf+35,"5"); + length -= 1; + fwrite(ibuf,length,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + length + 2; + } + + else if ((i = strncmp(ibuf,"^IMAGE",6)) == 0) { + /*****************************************************************/ + /* change the location pointer of image to record 7 */ + /*****************************************************************/ + + if (record_bytes == 836) { + strcpy(ibuf+35,"7"); + length=length-1; + } + else { + strcpy(ibuf+35,"60"); + length = length - 2; + } + + fwrite(ibuf,length,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + length + 2; + } + else if ((i = strncmp(ibuf,"OBJECT = ENCODING", + 43)) == 0) { + + /*****************************************************************/ + /* delete the 4 encoding histogram labels */ + /*****************************************************************/ + + for (i=0; i<4; i++) { /* ignore these labels */ + length = read_var(ibuf,host); + } + } + + else if ((i = strncmp(ibuf," ENCODING",9)) == 0); + + /*****************************************************************/ + /* delete the encoding type label in the image object */ + /*****************************************************************/ + + else if ((host == 2 || host == 5) && (i = strncmp(ibuf, + " ITEM_TYPE = VAX_INTEGER",46)) == 0) { + /*****************************************************************/ + /* change the record_type value from variable to fixed */ + /*****************************************************************/ + + strcpy(ibuf+35,"INTEGER"); + length = length - 4; + fwrite(ibuf,length,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + length + 2; + } + + /*****************************************************************/ + /* find the checksum and store in label_checksum */ + /*****************************************************************/ + else if ((i = strncmp(ibuf," CHECKSUM",9)) == 0) { + ibuf[length] = '\0'; + label_checksum = atol(ibuf+35); + } + + /*****************************************************************/ + /* if none of above write out the label to the output file */ + /*****************************************************************/ + else { + fwrite(ibuf,length,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + length + 2; + } + + /*****************************************************************/ + /* test for the end of the PDS labels */ + /*****************************************************************/ + if ((i = strncmp(ibuf,"END",3)) == 0 && length == 3) break; + } while (length > 0); + + /* pad out the labels with blanks to multiple of record_bytes */ + if (record_bytes == 836) + for (i=total_bytes; i 0); + + open_files(&host); + total_bytes = 0; + + strcpy(outstring,"SIMPLE = T"); + strcat(outstring," "); + fwrite(outstring,78,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + 80; + + strcpy(outstring,"BITPIX = 8"); + strcat(outstring," "); + fwrite(outstring,78,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + 80; + + strcpy(outstring,"NAXIS = 2"); + strcat(outstring," "); + fwrite(outstring,78,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + 80; + + if (record_bytes == 836) + strcpy(outstring,"NAXIS1 = 800"); + else + strcpy(outstring,"NAXIS1 = 1204"); + + strcat(outstring," "); + fwrite(outstring,78,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + 80; + + if (record_bytes == 836) + strcpy(outstring,"NAXIS2 = 800"); + else + strcpy(outstring,"NAXIS2 = 1056"); + + strcat(outstring," "); + fwrite(outstring,78,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + 80; + + strcpy(outstring,"END "); + strcat(outstring," "); + + fwrite(outstring,78,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + 80; + + /* pad out the labels with blanks to multiple of 2880 for FITS */ + for (i=total_bytes; i<2880; i++) fputc(blank,outfile); +} + +/*********************************************************************/ +/* */ +/* subroutine vicar_labels - write vicar labels to output file */ +/* */ +/*********************************************************************/ + +void vicar_labels(host) +int host; + +{ + char ibuf[2048],outstring[80]; + short length,nlen,total_bytes,line,i; + unsigned char cr=13,lf=10,blank=32; + + do { + length = read_var(ibuf,host); + /*****************************************************************/ + /* find the checksum and store in label_checksum */ + /*****************************************************************/ + if ((i = strncmp(ibuf," CHECKSUM",9)) == 0) { + ibuf[length] = '\0'; + label_checksum = atol(ibuf+35); + } + + else if ((i = strncmp(ibuf,"RECORD_BYTES",12)) == 0) { + /*****************************************************************/ + /* get the record_bytes value */ + /*****************************************************************/ + + sscanf(ibuf+35,"%d",&record_bytes); + if (record_bytes != 836) record_bytes = 1204; + } + + /*****************************************************************/ + /* read to the end of the PDS labels */ + /*****************************************************************/ + if ((i = strncmp(ibuf,"END",3)) == 0 && length == 3) break; + } while (length > 0); + + open_files(&host); + total_bytes = 0; + + if (record_bytes == 836) + strcpy(outstring, + "LBLSIZE=800 FORMAT='BYTE' TYPE='IMAGE' BUFSIZ=800 DIM=2 "); + + else + strcpy(outstring, + "LBLSIZE=1204 FORMAT='BYTE' TYPE='IMAGE' BUFSIZ=1204 DIM=2 "); + + fwrite(outstring,72,1,outfile); + total_bytes = total_bytes + 72; + + if (record_bytes == 836) + strcpy(outstring, + "EOL=0 RECSIZE=800 ORG='BSQ' NL=800 NS=800 NB=1 N1=0 N2=0 N3=0 "); + else + strcpy(outstring, + "EOL=0 RECSIZE=1204 ORG='BSQ' NL=1056 NS=1204 NB=1 N1=0 N2=0 N3=0 "); + + total_bytes = total_bytes + 71; + fwrite(outstring,71,1,outfile); + strcpy(outstring,"N4=0 NBB=0 NLB=0"); + fwrite(outstring,18,1,outfile); + fprintf(outfile,"%c%c",cr,lf); + total_bytes = total_bytes + 20; + + /* pad out the labels with blanks to multiple of record_bytes */ + for (i=total_bytes;i 0); + + open_files(&host); +} + +/*********************************************************************/ +/* */ +/* subroutine read_var - read variable length records from input file*/ +/* */ +/*********************************************************************/ + +read_var(ibuf,host) +char *ibuf; +int host; +{ + int length,result,nlen; + char temp; + union /* this union is used to swap 16 and 32 bit integers */ + { + char ichar[4]; + short slen; + int llen; + } onion; + + switch (host) { + case 1: /*******************************************************/ + /* IBM PC host */ + /*******************************************************/ + length = 0; + result = read(infile, &length, (size_t) 2); + nlen = read(infile, ibuf, (size_t) (length + (length % 2))); + return (length); + + case 2: /*******************************************************/ + /* Macintosh host */ + /*******************************************************/ + + length = 0; + result = read(infile, onion.ichar, (size_t) 2); + /* byte swap the length field */ + temp = onion.ichar[0]; + onion.ichar[0]=onion.ichar[1]; + onion.ichar[1]=temp; + length = onion.slen; /* left out of earlier versions */ + nlen = read(infile, ibuf, (size_t) (length + (length % 2))); + return (length); + + case 3: /*******************************************************/ + /* VAX host with variable length support */ + /*******************************************************/ + length = read(infile, ibuf, (size_t) 2048); /* 2048 is upper bound */ + return (length); + + case 4: /*******************************************************/ + /* VAX host, but not a variable length file */ + /*******************************************************/ + length = 0; + result = read(infile, &length, (size_t) 2); + nlen = read(infile, ibuf, (size_t) (length + (length % 2))); + + /* check to see if we crossed a vax record boundary */ + while (nlen < length) + nlen += read(infile, ibuf + nlen, (size_t) (length + (length % 2) - nlen)); + + return (length); + + case 5: /*******************************************************/ + /* Unix workstation host (non-byte-swapped 32 bit host)*/ + /*******************************************************/ + length = 0; + result = read(infile, onion.ichar, (size_t) 2); + /* byte swap the length field */ + temp = onion.ichar[0]; + onion.ichar[0]=onion.ichar[1]; + onion.ichar[1]=temp; + length = onion.slen; + nlen = read(infile, ibuf, (size_t) (length + (length % 2))); + return (length); + } +} + +/*********************************************************************/ +/* */ +/* subroutine check_host - find out what kind of machine we are on */ +/* */ +/*********************************************************************/ + +int check_host() +{ + /* This subroutine checks the attributes of the host computer and + returns a host code number. + */ + char hostname[80]; + + int swap,host,bits,var; + union + { + char ichar[2]; + short ilen; + } onion; + + if (sizeof(var) == 4) bits = 32; + else bits = 16; + + onion.ichar[0] = 1; + onion.ichar[1] = 0; + + if (onion.ilen == 1) swap = TRUE; + else swap = FALSE; + + if (bits == 16 && swap == TRUE ) { + host = 1; /* IBM PC host */ + strcpy(hostname, + "Host 1 - 16 bit integers with swapping, no var len support."); + } + + if (bits == 16 && swap == FALSE ) { + host = 2; /* Non byte swapped 16 bit host */ + strcpy(hostname, + "Host 2 - 16 bit integers without swapping, no var len support."); + } + + if (bits == 32 && swap == TRUE ) { + host = 3; /* VAX host with var length support */ + strcpy(hostname,"Host 3,4 - 32 bit integers with swapping."); + } + + if (bits == 32 && swap == FALSE ) { + host = 5; /* OTHER 32-bit host */ + strcpy(hostname, + "Host 5 - 32 bit integers without swapping, no var len support."); + } + +// if ((*outname)!='-') fprintf(stderr,"%s\n",hostname); + return(host); +} + +int swap_long(inval) /* swap 4 byte integer */ + int inval; +{ + union /* this union is used to swap 16 and 32 bit integers */ + { + char ichar[4]; + short slen; + int llen; + } onion; + char temp; + + /* byte swap the input field */ + onion.llen = inval; + temp = onion.ichar[0]; + onion.ichar[0]=onion.ichar[3]; + onion.ichar[3]=temp; + temp = onion.ichar[1]; + onion.ichar[1]=onion.ichar[2]; + onion.ichar[2]=temp; + return (onion.llen); +} + +void decompress(ibuf,obuf,nin,nout) +/**************************************************************************** +*_TITLE decompress - decompresses image lines stored in compressed format * +*_ARGS TYPE NAME I/O DESCRIPTION */ + char *ibuf; /* I Compressed data buffer */ + char *obuf; /* O Decompressed image line */ + int *nin; /* I Number of bytes on input buffer */ + int *nout; /* I Number of bytes in output buffer */ + +{ + /* The external root pointer to tree */ + extern NODE *tree; + + /* Declare functions called from this routine */ + void dcmprs(); + + /************************************************************************* + This routine is fairly simple as it's only function is to call the + routine dcmprs. + **************************************************************************/ + + dcmprs(ibuf,obuf,nin,nout,tree); + + return; +} + + +void decmpinit(hist) +/*************************************************************************** +*_TITLE decmpinit - initializes the Huffman tree * +*_ARGS TYPE NAME I/O DESCRIPTION */ + int *hist; /* I First-difference histogram. */ + +{ + extern NODE *tree; /* Huffman tree root pointer */ + + /* Specify the calling function to initialize the tree */ + NODE *huff_tree(); + + /************************************************************************** + Simply call the huff_tree routine and return. + **************************************************************************/ + + tree = huff_tree(hist); + + return; +} + + +NODE *huff_tree(hist) +/**************************************************************************** +*_TITLE huff_tree - constructs the Huffman tree; returns pointer to root * +*_ARGS TYPE NAME I/O DESCRIPTION */ + int *hist; /* I First difference histogram */ + +{ + /* Local variables used */ + int freq_list[512]; /* Histogram frequency list */ + NODE **node_list; /* DN pointer array list */ + + register int *fp; /* Frequency list pointer */ + register NODE **np; /* Node list pointer */ + + register int num_freq; /* Number non-zero frequencies in histogram */ + int sum; /* Sum of all frequencies */ + + register short int num_nodes; /* Counter for DN initialization */ + register short int cnt; /* Miscellaneous counter */ + + short int znull = -1; /* Null node value */ + + register NODE *temp; /* Temporary node pointer */ + + /* Functions called */ + void sort_freq(); + NODE *new_node(); + + /************************************************************************** + Allocate the array of nodes from memory and initialize these with numbers + corresponding with the frequency list. There are only 511 possible + permutations of first difference histograms. There are 512 allocated + here to adhere to the FORTRAN version. + **************************************************************************/ + + fp = freq_list; + node_list = (NODE **) malloc(sizeof(temp)*512); + if (node_list == NULL) { + fprintf(stderr,"\nOut of memory in huff_tree!\n"); + exit(5); + } + np = node_list; + + for (num_nodes=1, cnt=512 ; cnt-- ; num_nodes++) { + + /*********************************************************************** + The following code has been added to standardize the VAX byte order + for the "int" type. This code is intended to make the routine + as machine independant as possible. + **********************************************************************/ + + unsigned char *cp = (unsigned char *) hist++; + unsigned int j; + short int i; + for (i=4 ; --i >= 0 ; j = (j << 8) | *(cp+i)); + + /* Now make the assignment */ + *fp++ = j; + temp = new_node(num_nodes); + *np++ = temp; + } + + (*--fp) = 0; /* Ensure the last element is zeroed out. */ + + /************************************************************************* + Now, sort the frequency list and eliminate all frequencies of zero. + *************************************************************************/ + + num_freq = 512; + sort_freq(freq_list,node_list,num_freq); + + fp = freq_list; + np = node_list; + + for (num_freq=512 ; (*fp) == 0 && (num_freq) ; fp++, np++, num_freq--); + + /************************************************************************* + Now create the tree. Note that if there is only one difference value, + it is returned as the root. On each interation, a new node is created + and the least frequently occurring difference is assigned to the right + pointer and the next least frequency to the left pointer. The node + assigned to the left pointer now becomes the combination of the two + nodes and it's frequency is the sum of the two combining nodes. + *************************************************************************/ + + for (temp=(*np) ; (num_freq--) > 1 ; ) { + temp = new_node(znull); + temp->right = (*np++); + temp->left = (*np); + *np = temp; + *(fp+1) = *(fp+1) + *fp; + *fp++ = 0; + sort_freq(fp,np,num_freq); + } + + return temp; +} + + +NODE *new_node(value) +/**************************************************************************** +*_TITLE new_node - allocates a NODE structure and returns a pointer to it * +*_ARGS TYPE NAME I/O DESCRIPTION */ + short int value; /* I Value to assign to DN field */ + +{ + NODE *temp; /* Pointer to the memory block */ +#ifdef VMS + char *malloc(); +#endif + + /************************************************************************ + Allocate the memory and intialize the fields. + ************************************************************************/ + + temp = (NODE *) malloc(sizeof(NODE)); + + if (temp != NULL) { + temp->right = NULL; + temp->dn = value; + temp->left = NULL; + } + else { + fprintf(stderr,"\nOut of memory in new_node!\n"); + exit(6); + } + + return temp; +} + +void sort_freq(freq_list,node_list,num_freq) +/**************************************************************************** +*_TITLE sort_freq - sorts frequency and node lists in increasing freq. order* +*_ARGS TYPE NAME I/O DESCRIPTION */ + int *freq_list; /* I Pointer to frequency list */ + NODE **node_list; /* I Pointer to array of node pointers */ + int num_freq; /* I Number of values in freq list */ + +{ + /* Local Variables */ + register int *i; /* primary pointer into freq_list */ + register int *j; /* secondary pointer into freq_list */ + + register NODE **k; /* primary pointer to node_list */ + register NODE **l; /* secondary pointer into node_list */ + + int temp1; /* temporary storage for freq_list */ + NODE *temp2; /* temporary storage for node_list */ + + register int cnt; /* count of list elements */ + + /********************************************************************* + Save the current element - starting with the second - in temporary + storage. Compare with all elements in first part of list moving + each up one element until the element is larger. Insert current + element at this point in list. + *********************************************************************/ + + if (num_freq <= 0) return; /* If no elements or invalid, return */ + + for (i=freq_list, k=node_list, cnt=num_freq ; --cnt ; *j=temp1, *l=temp2) { + temp1 = *(++i); + temp2 = *(++k); + + for (j = i, l = k ; *(j-1) > temp1 ; ) { + *j = *(j-1); + *l = *(l-1); + j--; + l--; + if ( j <= freq_list) break; + } + + } + return; +} + + +void dcmprs(ibuf,obuf,nin,nout,root) +/**************************************************************************** +*_TITLE dcmprs - decompresses Huffman coded compressed image lines * +*_ARGS TYPE NAME I/O DESCRIPTION */ + char *ibuf; /* I Compressed data buffer */ + char *obuf; /* O Decompressed image line */ + int *nin; /* I Number of bytes on input buffer */ + int *nout; /* I Number of bytes in output buffer */ + NODE *root; /* I Huffman coded tree */ + +{ + /* Local Variables */ + register NODE *ptr = root; /* pointer to position in tree */ + register unsigned char test; /* test byte for bit set */ + register unsigned char idn; /* input compressed byte */ + + register char odn; /* last dn value decompressed */ + + char *ilim = ibuf + *nin; /* end of compressed bytes */ + char *olim = obuf + *nout; /* end of output buffer */ + + /************************************************************************** + Check for valid input values for nin, nout and make initial assignments. + **************************************************************************/ + + if (ilim > ibuf && olim > obuf) + odn = *obuf++ = *ibuf++; + else { + fprintf(stderr,"\nInvalid byte count in dcmprs!\n"); + exit(7); + } + + /************************************************************************ + Decompress the input buffer. Assign the first byte to the working + variable, idn. An arithmatic and (&) is performed using the variable + 'test' that is bit shifted to the right. If the result is 0, then + go to right else go to left. + ************************************************************************/ + + for (idn=(*ibuf) ; ibuf < ilim ; idn =(*++ibuf)) { + for (test=0x80 ; test ; test >>= 1) { + ptr = (test & idn) ? ptr->left : ptr->right; + + if (ptr->dn != -1) { + if (obuf >= olim) return; + odn -= ptr->dn + 256; + *obuf++ = odn; + ptr = root; + } + } + } + return; +} + + +void free_tree(nfreed) +/**************************************************************************** +*_TITLE free_tree - free memory of all allocated nodes * +*_ARGS TYPE NAME I/O DESCRIPTION */ + int *nfreed; /* O Return of total count of nodes * +* freed. */ + +/* +*_DESCR This routine is supplied to the programmer to free up all the * +* allocated memory required to build the huffman tree. The count * +* of the nodes freed is returned in the parameter 'nfreed'. The * +* purpose of the routine is so if the user wishes to decompress more * +* than one file per run, the program will not keep allocating new * +* memory without first deallocating all previous nodes associated * +* with the previous file decompression. * + +*_HIST 16-AUG-89 Kris Becker USGS, Flagstaff Original Version * +*_END * +****************************************************************************/ + +{ + int total_free = 0; + + extern NODE *tree; /* Huffman tree root pointer */ + + /* Specify the function to free the tree */ + int free_node(); + + /**************************************************************** + Simply call the free_node routine and return the result. + ****************************************************************/ + + *nfreed = free_node(tree,total_free); + + return; +} + + +int free_node(pnode,total_free) +/*************************************************************************** +*_TITLE free_node - deallocates an allocated NODE pointer +*_ARGS TYPE NAME I/O DESCRIPTION */ + NODE *pnode; /* I Pointer to node to free */ + int total_free; /* I Total number of freed nodes */ + +/* +*_DESCR free_node will check both right and left pointers of a node * +* and then free the current node using the free() C utility. * +* Note that all nodes attached to the node via right or left * +* pointers area also freed, so be sure that this is the desired * +* result when calling this routine. * + +* This routine is supplied to allow successive calls to the * +* decmpinit routine. It will free up the memory allocated * +* by previous calls to the decmpinit routine. The call to free * +* a previous huffman tree is: total = free_node(tree,(int) 0); * +* This call must be done by the programmer application routine * +* and is not done by any of these routines. * +*_HIST 16-AUG-89 Kris Becker U.S.G.S Flagstaff Original Version */ +{ + if (pnode == (NODE *) NULL) return(total_free); + + if (pnode->right != (NODE *) NULL) + total_free = free_node(pnode->right,total_free); + if (pnode->left != (NODE *) NULL) + total_free = free_node(pnode->left,total_free); + + free((char *) pnode); + return(total_free + 1); +} diff --git a/isis/src/viking/apps/vdcomp/vdcomp.xml b/isis/src/viking/apps/vdcomp/vdcomp.xml new file mode 100644 index 0000000000000000000000000000000000000000..62b83a2033c21b090a1ad91f2621e55c114aa674 --- /dev/null +++ b/isis/src/viking/apps/vdcomp/vdcomp.xml @@ -0,0 +1,44 @@ + + + + + + Uncompresses Voyager and Viking PDS files + + + + This program will decompress Voyager and Viking EDR imq files in PDS + format. It is not a standard Isis program but is used internally within + "vik2isis" and "voy2isis" when decompression of the EDR is necessary. + + + + + Original Version + + + Removed compilation warnings under Linux + + + Removed extraneous output to terminal + + + Added appTest + + + 64-bit Solaris port required replacing long with int and adding malloc.h + + + Modified code to allow string length of 1024 characters for input and + output filenames. + + + Increased buffer sizes for ibuf and obuf. Also added some error checking. + + + + + Viking + Voyager + + diff --git a/isis/src/viking/apps/vik2isis/Makefile b/isis/src/viking/apps/vik2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/viking/apps/vik2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/viking/apps/vik2isis/tsts/Makefile b/isis/src/viking/apps/vik2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/viking/apps/vik2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/viking/apps/vik2isis/tsts/img/Makefile b/isis/src/viking/apps/vik2isis/tsts/img/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..89060ce4ea5b0a75aaa17fc4b1babd09ac6ddc2a --- /dev/null +++ b/isis/src/viking/apps/vik2isis/tsts/img/Makefile @@ -0,0 +1,6 @@ +APPNAME = vik2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/f319b18.imq to=$(OUTPUT)/vik2isis-imgTruth.cub > /dev/null; diff --git a/isis/src/viking/apps/vik2isis/tsts/imq/Makefile b/isis/src/viking/apps/vik2isis/tsts/imq/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3a45f8027c45fcf2e9a4cfc81fbc33cc41e953e0 --- /dev/null +++ b/isis/src/viking/apps/vik2isis/tsts/imq/Makefile @@ -0,0 +1,6 @@ +APPNAME = vik2isis + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/f319b18.imq to=$(OUTPUT)/vik2isis-imqTruth.cub > /dev/null; diff --git a/isis/src/viking/apps/vik2isis/vik2isis.cpp b/isis/src/viking/apps/vik2isis/vik2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6cddbbb2ce1156e078fafbb7a32a428d1633543 --- /dev/null +++ b/isis/src/viking/apps/vik2isis/vik2isis.cpp @@ -0,0 +1,226 @@ +#include "Isis.h" + +#include +#include +#include "stdlib.h" + +#include "ProcessImportPds.h" +#include "UserInterface.h" +#include "Filename.h" +#include "iException.h" +#include "Pvl.h" +#include "iString.h" + +using namespace std; +using namespace Isis; + +void TranslateVikingLabels(Pvl &pdsLabel, Cube *ocube); + +void IsisMain() { + // We should be processing a PDS file + ProcessImportPds p; + UserInterface &ui = Application::GetUserInterface(); + Filename in = ui.GetFilename("FROM"); + + string tempName = "$TEMPORARY/" + in.Name() + ".img"; + Filename temp(tempName); + bool tempFile = false; + + // This program handles both compressed and decompressed files. + // To discover if a file is compressed attempt to create a Pvl + // object. If this fails then the file must be compressed, so + // decompress the file using vdcomp. + try { + Pvl compressionTest(in.Expanded()); + + if(compressionTest.Groups() == 0 && compressionTest.Objects() == 0 && + compressionTest.Keywords() < 2) { + throw iException::Message(iException::Programmer, "", _FILEINFO_); + } + } + catch(iException &e) { + e.Clear(); + tempFile = true; + string command = "$ISISROOT/bin/vdcomp " + in.Expanded() + " " + + temp.Expanded() + " &> /dev/null"; + int returnValue = system(command.c_str()) >> 8; + if(returnValue) { + string msg = "Error running vdcomp"; + Isis::iException::errType msgTarget = Isis::iException::Programmer; + switch(returnValue) { + case 1: + msg = "Vik2Isis called vdcomp and help mode was triggered.\n"; + msg += "Were any parameters passed?"; + break; + case 2: + msg = "vdcomp could not write its output file.\n" + + msg += "Check disk space or for duplicate filename."; + break; + case 3: + msg = "vdcomp could not open the input file!"; + break; + case 4: + msg = "vdcomp could not open its output file!"; + break; + case 5: + msg = "vdcomp: Out of memory in half_tree!"; + break; + case 6: + msg = "vdcomp: Out of memory in new_node"; + break; + case 7: + msg = "vdcomp: Invalid byte count in dcmprs"; + break; + case 42: + msg = "Input file [" + in.Name() + "] has\ninvalid or" + + " corrupted line header table!"; + msgTarget = Isis::iException::User; + break; + } + throw iException::Message(msgTarget, msg, _FILEINFO_); + } + in = temp.Expanded(); + } + + // Convert the pds file to a cube + Pvl pdsLabel; + try { + p.SetPdsFile(in.Expanded(), "", pdsLabel); + } + catch(iException &e) { + string msg = "Input file [" + in.Name() + + "] does not appear to be a Viking PDS product"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + Cube *ocube = p.SetOutputCube("TO"); + p.StartProcess(); + TranslateVikingLabels(pdsLabel, ocube); + p.EndProcess(); + + if(tempFile) remove(temp.Expanded().c_str()); + return; +} + +void TranslateVikingLabels(Pvl &pdsLabel, Cube *ocube) { + // Setup the archive group + PvlGroup arch("Archive"); + arch += PvlKeyword("DataSetId", (string)pdsLabel["DATA_SET_ID"]); + arch += PvlKeyword("ProductId", (string)pdsLabel["IMAGE_ID"]); + arch += PvlKeyword("MissonPhaseName", (string)pdsLabel["MISSION_PHASE_NAME"]); + arch += PvlKeyword("ImageNumber", (string)pdsLabel["IMAGE_NUMBER"]); + arch += PvlKeyword("OrbitNumber", (string)pdsLabel["ORBIT_NUMBER"]); + ocube->PutGroup(arch); + + // Setup the instrument group + // Note SpacecraftClockCount used to be FDS_COUNT + PvlGroup inst("Instrument"); + inst += PvlKeyword("SpacecraftName", (string)pdsLabel["SPACECRAFT_NAME"]); + inst += PvlKeyword("InstrumentId", (string)pdsLabel["INSTRUMENT_NAME"]); + inst += PvlKeyword("TargetName", (string)pdsLabel["TARGET_NAME"]); + + iString stime = (string) pdsLabel["IMAGE_TIME"]; + stime.Trim("Z"); + inst += PvlKeyword("StartTime", stime); + + inst += PvlKeyword("ExposureDuration", + (string)pdsLabel["EXPOSURE_DURATION"], "seconds"); + inst += PvlKeyword("SpacecraftClockCount", (string)pdsLabel["IMAGE_NUMBER"]); + inst += PvlKeyword("FloodModeId", (string)pdsLabel["FLOOD_MODE_ID"]); + inst += PvlKeyword("GainModeId", (string)pdsLabel["GAIN_MODE_ID"]); + inst += PvlKeyword("OffsetModeId", (string)pdsLabel["OFFSET_MODE_ID"]); + ocube->PutGroup(inst); + + // Setup the band bin group + PvlGroup bandBin("BandBin"); + string filterName = pdsLabel["FILTER_NAME"]; + bandBin += PvlKeyword("FilterName", filterName); + + int filterId; + if(filterName == "BLUE") filterId = 1; + if(filterName == "MINUS_BLUE") filterId = 2; + if(filterName == "VIOLET") filterId = 3; + if(filterName == "CLEAR") filterId = 4; + if(filterName == "GREEN") filterId = 5; + if(filterName == "RED") filterId = 6; + bandBin += PvlKeyword("FilterId", filterId); + ocube->PutGroup(bandBin); + + // Setup the kernel group + PvlGroup kern("Kernels"); + int spn; + if((string) pdsLabel["SPACECRAFT_NAME"] == "VIKING_ORBITER_1") { + if((string) pdsLabel["INSTRUMENT_NAME"] == + "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A") { + kern += PvlKeyword("NaifFrameCode", -27001); + } + else { + kern += PvlKeyword("NaifFrameCode", -27002); + } + spn = 1; + } + else { + if((string) pdsLabel["INSTRUMENT_NAME"] == + "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A") { + kern += PvlKeyword("NaifFrameCode", -30001); + } + else { + kern += PvlKeyword("NaifFrameCode", -30002); + } + spn = 2; + } + ocube->PutGroup(kern); + + // Set up the nominal reseaus group + PvlGroup res("Reseaus"); + Pvl nomRes("$viking" + iString(spn) + "/reseaus/nominal.pvl"); + PvlKeyword samps, lines, type, valid; + lines = PvlKeyword("Line"); + samps = PvlKeyword("Sample"); + type = PvlKeyword("Type"); + valid = PvlKeyword("Valid"); + string prefix; + if((string) pdsLabel["SPACECRAFT_NAME"] == "VIKING_ORBITER_1") { + if((string) pdsLabel["INSTRUMENT_NAME"] == + "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A") { + prefix = "VO1_VISA_"; + } + else { + prefix = "VO1_VISB_"; + } + } + else { + if((string) pdsLabel["INSTRUMENT_NAME"] == + "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A") { + prefix = "VO2_VISA_"; + } + else { + prefix = "VO2_VISB_"; + } + } + PvlKeyword key = nomRes.FindKeyword(prefix + "RESEAUS"); + int numRes = nomRes[prefix + "NUMBER_RESEAUS"]; + for(int i = 0; i < numRes * 3; i += 3) { + lines += key[i]; + samps += key[i+1]; + type += key[i+2]; + valid += 0; + } + res += lines; + res += samps; + res += type; + res += valid; + if(prefix == "VO1_VISA_") { + res += PvlKeyword("Template", "$viking1/reseaus/vo1.visa.template.cub"); + } + else if(prefix == "VO1_VISB_") { + res += PvlKeyword("Template", "$viking1/reseaus/vo1.visb.template.cub"); + } + else if(prefix == "VO2_VISA_") { + res += PvlKeyword("Template", "$viking2/reseaus/vo2.visa.template.cub"); + } + else res += PvlKeyword("Template", "$viking2/reseaus/vo2.visb.template.cub"); + res += PvlKeyword("Status", "Nominal"); + ocube->PutGroup(res); +} + diff --git a/isis/src/viking/apps/vik2isis/vik2isis.xml b/isis/src/viking/apps/vik2isis/vik2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..9a9c611aa6347f85bb02e321bd5ee0f9a3cb2f6f --- /dev/null +++ b/isis/src/viking/apps/vik2isis/vik2isis.xml @@ -0,0 +1,78 @@ + + + + + + Import PDS formatted Viking EDR into Isis format cube + + + + This program will import a PDS formatted Viking EDR into an Isis cube. + The input file can be in compressed or decompressed form. + + + + + Original version + + + Added nominal reseau values to the label. + + + Altered application to accept compressed or uncompressed files. + + + Fixed problems caused by split of viking data area + + + Removed references to CubeInfo + + + Changed to use the Isis::Filename class and use the temporary preferences + + + Replaced file extention checking with file data checking for determining + whether the file is decompressed already or not. Also added ability to + handle vdcomp error codes and throw meaningful iExceptions. + + + Updated check for PVL labels to reflect changes in PvlKeyword + + + + + Viking + + + + + + filename + input + + Input PDS formatted Viking Orbiter EDR image file + + + Use this parameter to select the Viking PDS EDR filename. + + + *.imq *.img + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename + + + *.cub + + + + + diff --git a/isis/src/viking/apps/vikcal/CalParameters.cpp b/isis/src/viking/apps/vikcal/CalParameters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b922a7e5712cb7c8465041b72bf610a275a334b --- /dev/null +++ b/isis/src/viking/apps/vikcal/CalParameters.cpp @@ -0,0 +1,438 @@ +/** + * @file + * $Revision: 1.4 $ + * $Date: 2009/12/29 23:03:54 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "CalParameters.h" +#include "iString.h" +#include "TextFile.h" +#include "Filename.h" +#include "iException.h" +#include "LeastSquares.h" +#include "Pvl.h" +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" +#include +#include + +using namespace std; +namespace Isis { + + CalParameters::CalParameters(const string &fname) { + try { + // Extract Pvl Information from the file + Pvl pvl(fname); + + // Get keywords from input cube label + PvlGroup &instrument = pvl.FindGroup("INSTRUMENT",Pvl::Traverse); + + // Make sure it is a viking mission + iString spacecraft = (string)instrument["SPACECRAFTNAME"]; + iString mission = spacecraft.Token("_"); + if (mission != "VIKING") { + string msg = "Invalid Keyword [SpacecraftName]. " + spacecraft + + "must start with 'VIKING'"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + int spn = 0; + if ((char)spacecraft[spacecraft.size() - 1] == '1') spn = 1; + if ((char)spacecraft[spacecraft.size() - 1] == '2') spn = 2; + if (spn == 0) { + string msg = "Invalid Keyword [SpacecraftName]. " + spacecraft + + "must terminate with '1' or '2'"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + double clock = instrument["SPACECRAFTCLOCKCOUNT"]; + iString instId = (string)instrument["INSTRUMENTID"]; + int cam; + // Camera State 4 is used to indicate an extended mission. This is + // necessary because the dust spot changed position during the extended + // mission, requiring a new set of calibration files. + int cs4 = 0; + if ((char)instId[instId.size() - 1] == 'A') { + if (spn == 1) cam = 7; + else cam = 8; + } + else if ((char)instId[instId.size() - 1] == 'B') { + if (spn == 1) { + cam = 4; + if (clock > 44800000) cs4 = 1; + } + else cam = 6; + } + else { + string msg = "Invalid Keyword [InstrumentID]. " + instId; + msg += "must terminate with an 'A' or 'B'"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + string startTime = instrument["STARTTIME"]; + CalcSunDist(startTime); + p_labexp = (double)instrument["EXPOSUREDURATION"] * 1000.0; // convert to msec + string target = " "; + PvlKeyword cs1 = instrument["FLOODMODEID"]; + if ((string)cs1 == "ON") cs1 = 1; + else if ((string)cs1 == "OFF") cs1 = 0; + PvlKeyword cs2 = instrument["GAINMODEID"]; + if ((string)cs2 == "LOW") cs2 = 0; + else if ((string)cs2 == "HIGH") cs2 = 1; + PvlKeyword cs3 = instrument["OFFSETMODEID"]; + if ((string)cs3 == "ON") cs3 = 1; + else if ((string)cs3 == "OFF") cs3 = 0; + PvlKeyword wav = pvl.FindGroup("BANDBIN",Pvl::Traverse)["FILTERID"]; + + // Set up calibration, linearity, and offset variables for the input file + vikcalSetup(mission, spn, target, cam, wav, (int)cs1, (int)cs2, (int)cs3, (int)cs4); + viklinSetup(mission, spn, target, cam, wav, (int)cs1, (int)cs2, (int)cs3, (int)cs4); + vikoffSetup(mission, spn, target, cam, clock, (int)cs3); + } + catch (iException e) { + string msg = "Input file [" + fname + "] does not appear to be a viking image"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + } + + /** + * Finds the correct calibration data values for the input cube in the + * vikcal.sav file + * + * @param mission The mission name found in the input cube label + * @param spn The spacecraft number found in the input cube label + * @param target The target name found in the input cube label (this value is + * not used in the vikcal.sav file, and is overriden with a space) + * @param cam The camera number found in the input cube label + * @param cs1 The state of camera 1 found in the input cube label + * (Light Flood Mode) + * @param cs2 The state of camera 2 found in the input cube label (Gain Mode) + * @param cs3 The state of camera 3 found in the input cube label (Offset Mode) + * @param cs4 The state of camera 4, set only if camera is 4, and it is an + * extended mission + * + * @throws Isis::iException::Programmer - Could not find match in vikcal.sav + */ + void CalParameters::vikcalSetup(string mission, int spn, string target, + int cam, string wav, int cs1, int cs2, int cs3, int cs4) { + vector line; + + // Read in vikcal.sav calibration file + TextFile cal("$viking" + iString(spn) + "/calibration/vikcal.sav", + "input",line,0,true); + + // Search for a line in the vikcal.sav file that matches our data from the + // input label + for (int i = 0; i < (int)line.size(); i++) { + iString temp = line[i]; + temp.ConvertWhiteSpace(); + iString token = temp.Token(" "); + temp.TrimHead(" "); + if (token != mission) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (int(token) != spn) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (int(token) != cam) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (token != wav) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (int(token) != cs1) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (int(token) != cs2) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (int(token) != cs3) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (int(token) != cs4) continue; + + + // The line is a match for our data, so set all the + // Calibration variables to their correct values + p_w0 = temp.Token(" "); + temp.TrimHead(" "); + p_dist = temp.Token(" "); + temp.TrimHead(" "); + p_gain = temp.Token(" "); + temp.TrimHead(" "); + p_offset = temp.Token(" "); + temp.TrimHead(" "); + p_exp = temp.Token(" "); + temp.TrimHead(" "); + p_gainFile = "$viking" + iString(spn) + "/calibration/" + temp.Token(" ") + + ".cub"; + temp.TrimHead(" "); + p_offsetFile = "$viking" + iString(spn) + "/calibration/" + + temp.Token(" ") + ".cub"; + return; + } + string msg = "Could not find match in [vikcal.sav] calibration file"; + throw iException::Message(iException::Programmer,msg, _FILEINFO_); + } + + /** + * Finds the correct linearization values for the input image. This option is + * in the Isis2 version of vikcal, but due to the values of B in the viklin.sav + * file it is never actually used. If this option is necessary for some reason, + * place the following code in the vikcal.xml file. + * @code + * + * + * boolean + * + * Linearizer option + * + * + * Flag to indicate if LINEARIZER option is desired. LINEAR=TRUE + * indicates linear correction to be applied if there is an entry in the + * viklin.sav file for the mission and camera to be processed. + * LINEAR=FALSE indicates that no linear correction is to be applied. + * Defaults to TRUE. + * + * TRUE + * + * + * @endcode + * + * @param mission The mission name found in the input cube label + * @param spn The spacecraft number found in the input cube label + * @param target The target found in the input cube (this option is not used, + * and the actual target is overriden with a space) + * @param cam The camera number found in the input cube + * @param wav The wave length found in the input cube + * @param cs1 The state of camera 1 found in the input cube label + * (Light Flood Mode) + * @param cs2 The state of camera 2 found in the input cube label (Gain Mode) + * @param cs3 The state of camera 3 found in the input cube label (Offset Mode) + * @param cs4 The state of camera 4, set only if the camera is 4, and it is an + * extended mission + * + * @throws Isis::iException::Programmer - Could not find match in viklin.sav + */ + void CalParameters::viklinSetup(string mission, int spn, string target, + int cam, string wav, int cs1, int cs2, int cs3, int cs4) { + + vector line; + TextFile lin("$viking" + iString(spn) + "/calibration/viklin.sav", + "input",line,0,true); + + for (int i = 0; i < (int)line.size(); i++) { + iString temp = line[i]; + temp.ConvertWhiteSpace(); + iString token = temp.Token(" "); + temp.TrimHead(" "); + if (token != mission) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (int(token) != spn) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (int(token) != cam) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (token != wav) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (int(token) != cs1) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (int(token) != cs2) continue; + token = temp.Token(" "); + temp.TrimHead(" "); + if (int(token) != cs3) continue; + + // Set all Linearity variables to the correct values + p_b = temp.Token(" "); + temp.TrimHead(" "); + p_k = temp.Token(" "); + temp.TrimHead(" "); + p_normpow = temp.Token(" "); + return; + } + string msg = "Could not find match in [viklin.sav] calibration file"; + throw iException::Message(iException::Programmer,msg, _FILEINFO_); + } + + /** + * Finds the correct offset data values for the input cube in the + * vikoff.sav file + * + * @param mission The mission name found in the input cube label + * @param spn The spacecraft number found in the input cube label + * @param target The target found in the input cube (this option is not used, + * and the actual target is overriden with a space) + * @param cam The camera number found in the input cube + * @param clock The spacecraft clock count found in the input cube label + * @param cs3 The state of camera 3 found in the input cube label (Offset Mode) + * + * @throws Isis::iException::Programmer - Could not find match in vikoff.sav + */ + void CalParameters::vikoffSetup(string mission, int spn, string target, + int cam, double clock, int cs3) { + vector line; + + // Get the correct offset file - depends on which camera the input image is + // from + string fname = "$viking" + iString(spn) + "/calibration/vikoffcam" + + iString(cam) + ".sav"; + TextFile off(fname,"input",line,0,true); + vector pp[5], off3; + double pp1_off[5], pp2_off[5], pp_off[5]; + double rise, run, xm, xb; + double frm1 = -1.0; + double frm2 = -1.0; + for (int i = 0; i < (int)line.size(); i++) { + iString temp = line[i]; + temp.ConvertWhiteSpace(); + temp.TrimHead(" "); + iString token = temp.Token(" "); + temp.TrimHead(" "); + + // Go through the first line of the offset file and set all the principle + // point locations + if (token == "VIKING") { + if (int(temp.Token(" ")) == spn) { } + temp.TrimHead(" "); + if (int(temp.Token(" ")) == cam) { } + temp.TrimHead(" "); + pp[0].push_back((double)temp.Token(" ")); + temp.TrimHead(" "); + pp[0].push_back((double)temp.Token(" ")); + temp.TrimHead(" "); + pp[1].push_back((double)temp.Token(" ")); + temp.TrimHead(" "); + pp[1].push_back((double)temp.Token(" ")); + temp.TrimHead(" "); + pp[2].push_back((double)temp.Token(" ")); + temp.TrimHead(" "); + pp[2].push_back((double)temp.Token(" ")); + temp.TrimHead(" "); + pp[3].push_back((double)temp.Token(" ")); + temp.TrimHead(" "); + pp[3].push_back((double)temp.Token(" ")); + temp.TrimHead(" "); + pp[4].push_back((double)temp.Token(" ")); + temp.TrimHead(" "); + pp[4].push_back((double)temp.Token(" ")); + temp.TrimHead(" "); + continue; + } + if (double(token) < clock) { + frm1 = token; + off3.push_back((double)temp.Token(" ")); + temp.TrimHead(" "); + pp1_off[2] = temp.Token(" "); + temp.TrimHead(" "); + pp1_off[0] = pp1_off[2] + (double)temp.Token(" "); + temp.TrimHead(" "); + pp1_off[1] = pp1_off[2] + (double)temp.Token(" "); + temp.TrimHead(" "); + pp1_off[3] = pp1_off[2] + (double)temp.Token(" "); + temp.TrimHead(" "); + pp1_off[4] = pp1_off[2] + (double)temp.Token(" "); + continue; + } + else { + frm2 = token; + off3.push_back((double)temp.Token(" ")); + temp.TrimHead(" "); + pp2_off[2] = temp.Token(" "); + temp.TrimHead(" "); + pp2_off[0] = pp2_off[2] + (double)temp.Token(" "); + temp.TrimHead(" "); + pp2_off[1] = pp2_off[2] + (double)temp.Token(" "); + temp.TrimHead(" "); + pp2_off[3] = pp2_off[2] + (double)temp.Token(" "); + temp.TrimHead(" "); + pp2_off[4] = pp2_off[2] + (double)temp.Token(" "); + } + if (frm1 == -1.0 || frm2 == -1.0) { + string msg = "Could not find match in [vikoff.sav] calibration file"; + throw iException::Message(iException::Programmer,msg, _FILEINFO_); + } + + // Calculate the offset at each point + run = frm2 - frm1; + for (int i = 0; i < 5; i++) { + rise = pp2_off[i] - pp1_off[i]; + xm = rise / run; + xb = pp1_off[i] - xm * frm1; + pp_off[i] = xm * clock + xb; + } + p_constOff = 0; + p_off_off = 0.0; + + // Calculate the constant offset + if (cs3 == 0) { + p_constOff = 1; + rise = off3[1] - off3[0]; + xm = rise / run; + xb = off3[0] - xm * frm1; + p_off_off = xm * clock + xb; + } + + // Found correct clock time, set offset values + BasisFunction bilinearInterp("leastSquares",5,5); + LeastSquares lsq(bilinearInterp); + vector known(5); + for (int i=0; i<5;i++) { + known[0] = pp[i][0]; + known[1] = pp[i][0] * pp[i][0]; + known[2] = pp[i][1]; + known[3] = pp[i][0] * pp[i][1]; + known[4] = 1.0; + lsq.AddKnown(known, pp_off[i], 1.0); + } + lsq.Solve(); + p_A = bilinearInterp.Coefficient(0); + p_B = bilinearInterp.Coefficient(1); + p_C = bilinearInterp.Coefficient(2); + p_D = bilinearInterp.Coefficient(3); + p_E = bilinearInterp.Coefficient(4); + + return; + } + string msg = "Could not find match in [vikoff.sav] calibration file"; + throw iException::Message(iException::Programmer,msg, _FILEINFO_); + } + + /** + * Calculates the distance from the sun at the specified time + * + * @param t iTime + */ + void CalParameters::CalcSunDist(string t) { + double sunv[3]; + SpiceDouble lt, et; + Filename fname1 = (Filename)"$base/kernels/lsk/naif0007.tls"; + Filename fname2 = (Filename)"$base/kernels/spk/de405.bsp"; + string tempfname1 = fname1.Expanded(); + string tempfname2 = fname2.Expanded(); + furnsh_c(tempfname1.c_str()); + furnsh_c(tempfname2.c_str()); + utc2et_c(t.c_str(),&et); + spkezp_c(10,et,"J2000","LT+S",499,sunv,<); + p_dist1 = sqrt(sunv[0] * sunv[0] + sunv[1] * sunv[1] + sunv[2] * sunv[2]); + } + +} // end namespace isis diff --git a/isis/src/viking/apps/vikcal/CalParameters.h b/isis/src/viking/apps/vikcal/CalParameters.h new file mode 100644 index 0000000000000000000000000000000000000000..f950cf23fc7bc9db1bdb344c7f02f6bcf6bd2fb5 --- /dev/null +++ b/isis/src/viking/apps/vikcal/CalParameters.h @@ -0,0 +1,224 @@ +#ifndef CalParameters_h +#define CalParameters_h +/** + * @file + * $Revision: 1.2 $ + * $Date: 2007/01/30 22:12:24 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include +#include + +/** + * @brief Sets up calibration parameters for Viking images + * + * This class sets up necessary calibration parameters for a given Viking input + * image. It is a helper class for the vikcal application. + * + * If you would like to see CalParameters + * being used in implementation, see vikcal.cpp + * + * @ingroup Viking + * + * @author 2005-05-18 Elizabeth Ribelin + * + * @internal + * @history 2005-11-15 Elizabeth Miller - Fixed problems caused by the split + * of the viking data area + * + */ +namespace Isis { + class CalParameters { + public: + // Constructor + CalParameters(const std::string &fname); + + /** + * Calculates and returns time based offset at specified line and sample + * location + * + * @return double iTime Based Offset + */ + inline double TimeBasedOffset(int l, int s) { + double off = p_A * l + p_B * l * l + p_C * s + p_D * l * s + p_E; + off += p_off_off; + return off; + } + + /** + * Returns the w0 value found in the vikcal.sav file + * + * @return double w0 + */ + inline double Omega0() { return p_w0; } + + /** + * Returns distance value found in the vikcal.sav file + * + * @return double Approximate distance from the sun + */ + inline double Distance() { return p_dist; } + + /** + * Returns the gain value found in the vikcal.sav file + * + * @return double Gain + */ + inline double Gain() { return p_gain; } + + /** + * Returns the offset value found in the vikcal.sav file + * + * @return double Offset + */ + inline double Offset() { return p_off_off; } + + /** + * Returns the exposure value found in the vikcal.sav file added to the + * exposure value found in the input files label + * + * @return double Exposure + */ + inline double Exposure() { return p_exp + p_labexp; } + + /** + * Returns the gain file found in the vikcal.sav file + * + * @return string Gain file + */ + inline std::string GainFile() { return p_gainFile; } + + /** + * Returns the offset file found in the vikcal.sav file + * + * @return string Offset file + */ + inline std::string OffsetFile() { return p_offsetFile; } + + /** + * Returns the linearity correction value found in the viklin.sav file + * + * @return double Linearity Correction (sometimes refered to as B) + */ + inline double LinearityCorrection() { return p_b; } + + /** + * Returns the linearity power value found in the viklin.sav file + * + * @return double Linearity Power (sometimes refered to as K) + */ + inline int LinearityPower() { return p_k; } + + /** + * Returns the normalizing power value found in the viklin.sav file + * (usually 128) + * + * @return double Normalizing Power + */ + inline double NormalizingPower() { return p_normpow; } + + /** + * Returns the A coefficient value calculated from data found in the + * vikoff.sav file + * + * @return double A Coefficient + */ + inline double Acoeff() { return p_A; } + + /** + * Returns the B coefficient value calculated from data found in the + * vikoff.sav file + * + * @return double B Coefficient + */ + inline double Bcoeff() { return p_B; } + + /** + * Returns the C coefficient value calculated from data found in the + * vikoff.sav file + * + * @return double C Coefficient + */ + inline double Ccoeff() { return p_C; } + + /** + * Returns the D coefficient value calculated from data found in the + * vikoff.sav file + * + * @return double D Coefficient + */ + inline double Dcoeff() { return p_D; } + + /** + * Returns the E coefficient value calculated from data found in the + * vikoff.sav file + * + * @return double E Coefficient + */ + inline double Ecoeff() { return p_E; } + + /** + * Calculates and returns Omega1 from the estimated and calculated + * distances from the sun + * + * @return double w1 + */ + inline double Omega1() { + double w1 = p_w0 * ((p_dist * p_dist)/(p_dist1 * p_dist1)); + return w1; + } + + /** + * Returns the calculated distance of the planet from the sun + * + * @return double Distance from the planet to the Sun + */ + inline double Dist1() { return p_dist1; } + + private: + void vikcalSetup(std::string mission, int spn, std::string target, + int cam, std::string wav, int cs1, int cs2, int cs3, int cs4); + void viklinSetup(std::string mission, int spn, std::string target, + int cam, std::string wav, int cs1, int cs2, int cs3, int cs4); + void vikoffSetup(std::string mission, int spn, std::string target, + int cam, double clock, int cs3); + void CalcSunDist(std::string t); + + double p_labexp; //! /dev/null; diff --git a/isis/src/viking/apps/vikcal/vikcal.cpp b/isis/src/viking/apps/vikcal/vikcal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9fb367cdd0ab1981f0c211c944860e363dd995d7 --- /dev/null +++ b/isis/src/viking/apps/vikcal/vikcal.cpp @@ -0,0 +1,132 @@ +#include "Isis.h" +#include "SpecialPixel.h" +#include "ProcessByLine.h" +#include "UserInterface.h" +#include "Pvl.h" +#include "CalParameters.h" +#include "CubeAttribute.h" + + +using namespace std; +using namespace Isis; + +void cal (vector &in, + vector &out); + +CalParameters* calParam; +static bool linear; + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Get the user interface and from filename + UserInterface &ui = Application::GetUserInterface(); + + // The linear option can never be true in Isis2, if it is needed, comment out + // the following line, and uncomment the line below it. Also, add the code + // segment found in the CalParameters documentation to the vikcal.xml file + linear = false; + // linear = ui.GetBoolean("LINEAR"); + const string in = ui.GetFilename("FROM"); + + calParam = new CalParameters(in); + + // Open the input cube + Cube icube; + icube.Open(in, "r"); + Progress prog; + + // If the file has already been calibrated, throw an error + if (icube.HasGroup("Radiometry")) { + string msg = "The Viking image [" + icube.Filename() + "] has already been "; + msg += "radiometrically calibrated"; + throw iException::Message(iException::User,msg,_FILEINFO_); + } + + CubeAttributeInput dcf; + CubeAttributeInput fff; + const string gainFile = (string)Filename(calParam->GainFile()).Expanded(); + const string offsetFile = (string)Filename(calParam->OffsetFile()).Expanded(); + + // Setup the input cubes + p.SetInputCube("FROM"); + p.SetInputCube(offsetFile, dcf); + p.SetInputCube(gainFile, fff); + + // Setup the output cube + Cube *ocube = p.SetOutputCube("TO"); + + // Set up and add the radiometry group to the output cube label + PvlGroup calgrp("Radiometry"); + + calgrp.AddComment("Calibration equation in vikcal"); + calgrp.AddComment("DI(l,s) = (1.0/(exp*w1))*G(l,s)*(gain*DR(l,s)+DC(l,s)+offt+offc)"); + calgrp.AddComment("with w1 = w0*((dist0*dist0) / (dist1*dist1))"); + calgrp.AddComment("and offt(l,s) = A*l + B*l*l + C*s + D*l*s + E"); + calgrp += PvlKeyword("offc",calParam->Offset()); + calgrp += PvlKeyword("exp",calParam->Exposure()); + calgrp += PvlKeyword("gain",calParam->Gain()); + calgrp += PvlKeyword("DR", in); + calgrp += PvlKeyword("DC",calParam->OffsetFile()); + calgrp += PvlKeyword("G",calParam->GainFile()); + + calgrp += PvlKeyword("w0",calParam->Omega0()); + calgrp += PvlKeyword("w1",calParam->Omega1()); + calgrp += PvlKeyword("dist0",calParam->Distance()); + calgrp += PvlKeyword("dist1",calParam->Dist1()); + calgrp += PvlKeyword("1.0/exp*w1",1.0 / (calParam->Exposure() * calParam->Omega1())); + + calgrp += PvlKeyword("Acoeff",calParam->Acoeff()); + calgrp += PvlKeyword("Bcoeff",calParam->Bcoeff()); + calgrp += PvlKeyword("Ccoeff",calParam->Ccoeff()); + calgrp += PvlKeyword("Dcoeff",calParam->Dcoeff()); + calgrp += PvlKeyword("Ecoeff",calParam->Ecoeff()); + + ocube->PutGroup(calgrp); + + // Start the calibration process + p.StartProcess(cal); + p.EndProcess(); +} + +void cal (vector &in, + vector &out) { + + Buffer &inp = *in[0]; // Input Cube + Buffer &dcf = *in[1]; // Dark Current File + Buffer &fff = *in[2]; // Flat Field File + Buffer &outp = *out[0]; // Output Cube + + + // Loop for each pixel in the line. + for (int i=0; iTimeBasedOffset(inp.Line(),i+1); + double dnraw = (inp[i] * calParam->Gain()) + dcf[i] + offc; + + // The linear option can never be true in isis2, and therefore, this + // section of the code has not been tested. + if (linear == true) { + double temp = (dnraw/calParam->NormalizingPower()); + for (int i = 1; i < calParam->LinearityPower(); i++) { + temp *= (dnraw/calParam->NormalizingPower()); + } + dnraw = calParam->Acoeff() * dnraw + calParam->Bcoeff() * temp; + } + + double xmlt = 1.0 / (calParam->Exposure() * calParam->Omega1()); + outp[i] = xmlt * fff[i] * dnraw; + } + } + +} + + + diff --git a/isis/src/viking/apps/vikcal/vikcal.xml b/isis/src/viking/apps/vikcal/vikcal.xml new file mode 100644 index 0000000000000000000000000000000000000000..9c38b7bb37150c7ba47c796caedf5469f7c95f0c --- /dev/null +++ b/isis/src/viking/apps/vikcal/vikcal.xml @@ -0,0 +1,84 @@ + + + + + Radiometric correction of VIKING Planetary images + + + + VIKCAL performs radiometric corrections to planetary images acquired by + the Viking orbiter cameras. VIKCAL performs a radiometric correction in + two steps. First, VIKCAL corrects for the varying response of the + vidicon across the field of view of the camera. Multiplicative and + additive correction coefficients, as a function of line and sample + position, are applied to an image array to produce the results of an + 'ideal' camera. VIKCAL converts the image data to radiance factor + values. The radiance factor is defined as the ratio of the observed + radiance and the radiance of a white screen, normal to the incident rays + of the Sun. + + + + Viking + + + + + viknosalt + viknopepper + vikfixtrx + + + + + + Original version - Converted from Isis2 + + + Fixed problems caused by the split of the viking data area + + + Fixed poutput pvl to not have spaces in the keyword names + + + Removed references to CubeInfo + + + Fixed pvl comments + + + + + + + cube + input + + Input cube file name + + + The cube to be calibrated. + + + *.cub + + + + + cube + real + output + + Output cube + + + The resultant cube containing the calibrated data. + + + *.cub + + + + + + diff --git a/isis/src/viking/apps/vikclean/Makefile b/isis/src/viking/apps/vikclean/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/viking/apps/vikclean/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/viking/apps/vikclean/assets/image/inputImage.jpg b/isis/src/viking/apps/vikclean/assets/image/inputImage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f66fd85df233fe4e1152562f12cda1d98b9505c7 Binary files /dev/null and b/isis/src/viking/apps/vikclean/assets/image/inputImage.jpg differ diff --git a/isis/src/viking/apps/vikclean/assets/image/outputImage.jpg b/isis/src/viking/apps/vikclean/assets/image/outputImage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..30f15b9e4b27c0ab53093fca5577d8240a061396 Binary files /dev/null and b/isis/src/viking/apps/vikclean/assets/image/outputImage.jpg differ diff --git a/isis/src/viking/apps/vikclean/assets/thumb/inputImage.jpg b/isis/src/viking/apps/vikclean/assets/thumb/inputImage.jpg new file mode 100755 index 0000000000000000000000000000000000000000..12687f3777ead576f426c52570feca6983e5a06c Binary files /dev/null and b/isis/src/viking/apps/vikclean/assets/thumb/inputImage.jpg differ diff --git a/isis/src/viking/apps/vikclean/assets/thumb/outputImage.jpg b/isis/src/viking/apps/vikclean/assets/thumb/outputImage.jpg new file mode 100755 index 0000000000000000000000000000000000000000..b40f088d010eb8d530ee7f0130e2b7b77733b6b4 Binary files /dev/null and b/isis/src/viking/apps/vikclean/assets/thumb/outputImage.jpg differ diff --git a/isis/src/viking/apps/vikclean/tsts/Makefile b/isis/src/viking/apps/vikclean/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/viking/apps/vikclean/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/viking/apps/vikclean/tsts/default/Makefile b/isis/src/viking/apps/vikclean/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0a316e8ae68b00604cac4b75c32ffd76d177652b --- /dev/null +++ b/isis/src/viking/apps/vikclean/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = vikclean + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/f348b26.cub to=$(OUTPUT)/vikcleanTruth.cub \ + remove=yes > /dev/null; diff --git a/isis/src/viking/apps/vikclean/vikclean.cpp b/isis/src/viking/apps/vikclean/vikclean.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc3b64e4d20527001a07363e0a92875a71054319 --- /dev/null +++ b/isis/src/viking/apps/vikclean/vikclean.cpp @@ -0,0 +1,49 @@ +#include "Isis.h" +#include "Pipeline.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + + // Open the input cube + UserInterface &ui = Application::GetUserInterface(); + Pipeline p("vikclean"); + p.SetInputFile("FROM"); + p.SetOutputFile("TO"); + p.KeepTemporaryFiles(!ui.GetBoolean("REMOVE")); + + // Run viknosalt on the cube to remove the salt + p.AddToPipeline("viknosalt"); + p.Application("viknosalt").SetInputParameter("FROM", true); + p.Application("viknosalt").SetOutputParameter("TO", "nosalt"); + + // Run vikfixtrx on the cube to remove the tracks + p.AddToPipeline("vikfixtrx"); + p.Application("vikfixtrx").SetInputParameter("FROM", true); + p.Application("vikfixtrx").SetOutputParameter("TO", "fixtrx"); + + // Run findrx on the cube to find the nominal position of the reseaus + p.AddToPipeline("findrx"); + p.Application("findrx").SetInputParameter("FROM", true); + + // Run viknopepper on the cube to remove the pepper + p.AddToPipeline("viknopepper"); + p.Application("viknopepper").SetInputParameter("FROM", true); + p.Application("viknopepper").SetOutputParameter("TO", "nopepper"); + + // Run remrx on the cube to remove the reseaus + p.AddToPipeline("remrx"); + p.Application("remrx").SetInputParameter("FROM", true); + p.Application("remrx").SetOutputParameter("TO", "remrx"); + p.Application("remrx").AddParameter("LDIM", "LDIM"); + p.Application("remrx").AddParameter("SDIM", "SDIM"); + + // Run vikfixfly on the cube + p.AddToPipeline("viknobutter"); + p.Application("viknobutter").SetInputParameter("FROM", true); + p.Application("viknobutter").SetOutputParameter("TO", ""); + + p.Run(); +} + diff --git a/isis/src/viking/apps/vikclean/vikclean.xml b/isis/src/viking/apps/vikclean/vikclean.xml new file mode 100644 index 0000000000000000000000000000000000000000..d920ce647415b88df0a4411d9b88b5c7c8398921 --- /dev/null +++ b/isis/src/viking/apps/vikclean/vikclean.xml @@ -0,0 +1,149 @@ + + + + + Clean-up of Viking Orbiter Level 1 images + + + + This program will perform the level 1 processing sequence on a Viking + Orbiter PDS image, including the cleanup of salt and pepper noise, the removal of + reseaus and tracks, and the removal of butterflies from the image. + + + + Viking + + + + + vikfixtrx + findrx + remrx + viknosalt + viknopepper + viknobutter + + + + + + Original version + + + Added example + + + Refactored application to use Pipelines + + + + + + + cube + input + + Input file to be cleaned + + + The cube to be cleaned. The cube will be run through a series of + filters to remove salt and pepper noise, tracks, and reseaus. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the clean data. + + + *.cub + + + + + + boolean + + Remove intermediate files + + + Option to remove or leave intermediate cube files made by the application + + TRUE + + + integer + + Number of Lines to Remove around each Reseau + + + This number will be used in the remrx step of the clean up. It is the number of + lines to remove around each reseau. + + 9 + + + integer + + Number of Samples to Remove around each Reseau + + + This number will be used in the remrx step of the clean up. It is the number of + samples to remove around each reseau. + + 9 + + + + + + + Input Viking Image to be cleaned + + This example shows the vikclean application in action. It removes all salt and pepper noise, along with reseaus, + tracks, and butterfiles. + + + from=../IN/temp.cub to=OUT/out.cub + + + Input a viking image to clean and give it an output file name. + + + + + + Viking Image to Clean + + This is the input viking image prior to cleaning. + + + FROM + + + + + + Cleaned Viking Image + + This is the viking image after the cleaning sequence has taken place. + + + TO + + + + + + + + diff --git a/isis/src/viking/apps/vikfixtrx/Makefile b/isis/src/viking/apps/vikfixtrx/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/viking/apps/vikfixtrx/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/viking/apps/vikfixtrx/assets/image/VikfixtrxGui.JPG b/isis/src/viking/apps/vikfixtrx/assets/image/VikfixtrxGui.JPG new file mode 100755 index 0000000000000000000000000000000000000000..f84e931daa463083a2432e03be6796e8f360f9e0 Binary files /dev/null and b/isis/src/viking/apps/vikfixtrx/assets/image/VikfixtrxGui.JPG differ diff --git a/isis/src/viking/apps/vikfixtrx/assets/image/f387a06.jpg b/isis/src/viking/apps/vikfixtrx/assets/image/f387a06.jpg new file mode 100644 index 0000000000000000000000000000000000000000..95de7a3c154355fdfc0f8fed942057633039cfb6 Binary files /dev/null and b/isis/src/viking/apps/vikfixtrx/assets/image/f387a06.jpg differ diff --git a/isis/src/viking/apps/vikfixtrx/assets/image/vikfixtrx-out.jpg b/isis/src/viking/apps/vikfixtrx/assets/image/vikfixtrx-out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..96e1f1cf6ff6fa38ee90de378ad631957373996e Binary files /dev/null and b/isis/src/viking/apps/vikfixtrx/assets/image/vikfixtrx-out.jpg differ diff --git a/isis/src/viking/apps/vikfixtrx/assets/thumb/VikfixtrxGui.JPG b/isis/src/viking/apps/vikfixtrx/assets/thumb/VikfixtrxGui.JPG new file mode 100755 index 0000000000000000000000000000000000000000..f84e931daa463083a2432e03be6796e8f360f9e0 Binary files /dev/null and b/isis/src/viking/apps/vikfixtrx/assets/thumb/VikfixtrxGui.JPG differ diff --git a/isis/src/viking/apps/vikfixtrx/assets/thumb/f387a06.jpg b/isis/src/viking/apps/vikfixtrx/assets/thumb/f387a06.jpg new file mode 100644 index 0000000000000000000000000000000000000000..95de7a3c154355fdfc0f8fed942057633039cfb6 Binary files /dev/null and b/isis/src/viking/apps/vikfixtrx/assets/thumb/f387a06.jpg differ diff --git a/isis/src/viking/apps/vikfixtrx/assets/thumb/vikfixtrx-out.jpg b/isis/src/viking/apps/vikfixtrx/assets/thumb/vikfixtrx-out.jpg new file mode 100644 index 0000000000000000000000000000000000000000..96e1f1cf6ff6fa38ee90de378ad631957373996e Binary files /dev/null and b/isis/src/viking/apps/vikfixtrx/assets/thumb/vikfixtrx-out.jpg differ diff --git a/isis/src/viking/apps/vikfixtrx/tsts/Makefile b/isis/src/viking/apps/vikfixtrx/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/viking/apps/vikfixtrx/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/viking/apps/vikfixtrx/tsts/default/Makefile b/isis/src/viking/apps/vikfixtrx/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..de7a1f1be6f00e134f4cda1dd8e1f745f71718b0 --- /dev/null +++ b/isis/src/viking/apps/vikfixtrx/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = vikfixtrx + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/f387a06.cub \ + to=$(OUTPUT)/vikfixtrxTruth.cub > /dev/null; diff --git a/isis/src/viking/apps/vikfixtrx/vikfixtrx.cpp b/isis/src/viking/apps/vikfixtrx/vikfixtrx.cpp new file mode 100644 index 0000000000000000000000000000000000000000..826ef0d67f28130b7db47c61e06df9302f272faa --- /dev/null +++ b/isis/src/viking/apps/vikfixtrx/vikfixtrx.cpp @@ -0,0 +1,101 @@ +#include "Isis.h" +#include "ProcessByLine.h" +#include "SpecialPixel.h" +#include + +using namespace std; +using namespace Isis; + +void fixtrx (Buffer &in, Buffer &out); +static float threshhold; + +void IsisMain() { + // We will be processing by line + ProcessByLine p; + + // Get the user entered threshhold value + UserInterface &ui = Application::GetUserInterface(); + threshhold = ui.GetDouble("THRESHLD"); + + // Setup the input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube ("TO"); + + // Start the processing + p.StartProcess(fixtrx); + p.EndProcess(); + +} + +void fixtrx (Buffer &in, Buffer &out) { + + static int nsamps = in.SampleDimension(); + + // Initialize bad tracks to false + int trk,badtrx[7]; + for (trk = 0; trk < 7; trk++) { + badtrx[trk] = false; + } + + // Copy input line to output line + for (int samp = 0; samp < nsamps; samp++) { + out[samp] = in[samp]; + } + + // Check for bad tracks in this line + int isamp,nbad,ntrx; + for (trk = 0; trk < 7; trk++) { + for (isamp = trk, nbad = 0, ntrx = 0; isamp < nsamps; + isamp+=7, ntrx++) { + if (in[isamp] <= 0) nbad++; + } + float pcbad = (float) nbad / (float) ntrx * 100.0; + if (pcbad >= threshhold) { + badtrx[trk] = true; + } + } + + // Go fix the bad tracks + int trxflag = 0; + for (trk = 0; trk < 7; trxflag += badtrx[trk++]); + for (trk = 0; trk < 7; trk++) { + if (badtrx[trk] == true) { + for (isamp = trk; isamp < nsamps; isamp+=7) { + if (in[isamp] <= 0) { + + // Get the left sample to average + int lsamp = isamp; + while (in[lsamp] <= 0 || in[lsamp] >= 255) { + lsamp--; + if (lsamp < isamp - 3 || lsamp < 0) { + lsamp = -1; + break; + } + } + + // Get the right sample to average + int rsamp = isamp; + while (in[rsamp] <= 0 || in[rsamp] >= 255) { + rsamp++; + if (rsamp > isamp + 3 || rsamp > nsamps - 1) { + rsamp = -1; + break; + } + } + + // Calculate the output pixel value + double lweight,rweight,value,weight; + if (lsamp >=0 && rsamp >=0) { + lweight = rsamp - isamp; + rweight = isamp - lsamp; + weight = rsamp - lsamp; + value = (in[lsamp] * lweight + in[rsamp] * rweight) + / weight + 0.5; + out[isamp] = (unsigned char) value; + } + } + } + } + } +} + diff --git a/isis/src/viking/apps/vikfixtrx/vikfixtrx.xml b/isis/src/viking/apps/vikfixtrx/vikfixtrx.xml new file mode 100644 index 0000000000000000000000000000000000000000..79dec6865efa1823983f3905068ad944f1b078fe --- /dev/null +++ b/isis/src/viking/apps/vikfixtrx/vikfixtrx.xml @@ -0,0 +1,135 @@ + + + + + Fix null tracks in a Viking image plane + + + This program checks for NULL tracks in the seven tracks of + a Viking image cube. If the percentage of pixels in a + line of a track meets or exceeds the THRESHLD value, then that + track is considered bad and the program will replace all + NULL values in that track. It does this replacement by using + valid pixels from each side of the track to perform an interpolation + to calculate the new pixel value. + + + + Viking + + + + + vikclean + + + + + + Original version + + + Made changes to appTest.xml (viking data area split into viking1 and viking2) + + + Modified documentation to be more accurate + + + + + + + cube + input + + Input file null tracks will be removed from + + + The cube to be filtered. All null tracks in each line of the cube will be + filled in using a 5x5 low pass filter. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the filtered data. + + + *.cub + + + + + + + double + + Threshhold Percentage + + + The threshhold percentage value for determining a bad track. + If the percentage of pixels in a line of a track meets or exceeds + the THRESHLD value, then that track is considered bad. Defaults to 90.0. + + 90.0 + + + + + + + Viking image filtered + + This example shows the vikfixtrx application. The threshhold percentage value is defaulted to 90.0. + + + f=../f387a06.cub t=vikfixtrx-out.cub + + + Just filter a Viking image. + + + + + + Input image for mirror + This is the input image for the vikfixtrx example. + + + FROM + + + + + + Output image for mirror + This is the output image that results. + + + TO + + + + + + + Example Gui + Screenshot of GUI with parameters filled in to perform + a vikfixtrx operation on the input image. + + + + + + + + + diff --git a/isis/src/viking/apps/viknobutter/Makefile b/isis/src/viking/apps/viknobutter/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/viking/apps/viknobutter/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/viking/apps/viknobutter/assets/image/inputImage.jpg b/isis/src/viking/apps/viknobutter/assets/image/inputImage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f66fd85df233fe4e1152562f12cda1d98b9505c7 Binary files /dev/null and b/isis/src/viking/apps/viknobutter/assets/image/inputImage.jpg differ diff --git a/isis/src/viking/apps/viknobutter/assets/image/outputImage.jpg b/isis/src/viking/apps/viknobutter/assets/image/outputImage.jpg new file mode 100755 index 0000000000000000000000000000000000000000..dd0408736f7739c1c67e9d6589e61ae771b23086 Binary files /dev/null and b/isis/src/viking/apps/viknobutter/assets/image/outputImage.jpg differ diff --git a/isis/src/viking/apps/viknobutter/assets/thumb/inputImage.jpg b/isis/src/viking/apps/viknobutter/assets/thumb/inputImage.jpg new file mode 100755 index 0000000000000000000000000000000000000000..12687f3777ead576f426c52570feca6983e5a06c Binary files /dev/null and b/isis/src/viking/apps/viknobutter/assets/thumb/inputImage.jpg differ diff --git a/isis/src/viking/apps/viknobutter/assets/thumb/outputImage.jpg b/isis/src/viking/apps/viknobutter/assets/thumb/outputImage.jpg new file mode 100755 index 0000000000000000000000000000000000000000..acf40a625804d6341d2328fc6d897fac9b3a22a2 Binary files /dev/null and b/isis/src/viking/apps/viknobutter/assets/thumb/outputImage.jpg differ diff --git a/isis/src/viking/apps/viknobutter/tsts/Makefile b/isis/src/viking/apps/viknobutter/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/viking/apps/viknobutter/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/viking/apps/viknobutter/tsts/default/Makefile b/isis/src/viking/apps/viknobutter/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..dfc6638703a06d7a4474098074b270c855b48900 --- /dev/null +++ b/isis/src/viking/apps/viknobutter/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = viknobutter + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/f348b26.cub to=$(OUTPUT)/viknobutterTruth.cub > /dev/null; diff --git a/isis/src/viking/apps/viknobutter/viknobutter.cpp b/isis/src/viking/apps/viknobutter/viknobutter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aaec20e2b36a2fa14dfb1c5edf9e7096c6cb5379 --- /dev/null +++ b/isis/src/viking/apps/viknobutter/viknobutter.cpp @@ -0,0 +1,90 @@ +#include "Isis.h" +#include "Application.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + + // Open the input cube + UserInterface &ui = Application::GetUserInterface(); + Filename fname = ui.GetFilename("FROM"); + string name = fname.Basename(); + bool rmv = ui.GetBoolean("REMOVE"); + + // Figure out which masking cube to use + Pvl p(ui.GetFilename("FROM")); + PvlGroup &inst = p.FindGroup("Instrument",Pvl::Traverse); + int spn; + string scn = (string)inst["SpacecraftName"]; + if (scn == "VIKING_ORBITER_1") spn = 1; + else if (scn == "VIKING_ORBITER_2") spn = 2; + else { + string msg = "Invalid spacecraftname [" + scn + "]"; + throw iException::Message(Isis::iException::Programmer,msg,_FILEINFO_); + } + // determine if # of cols is even or odd + bool even = true; + PvlGroup &arch = p.FindGroup("Archive",Pvl::Traverse); + string id = (string)arch["ProductId"]; + int num = iString(id.substr(5,1)).ToInteger(); + if (num == 1 || num == 3 || num == 5 || num == 7 || num == 9) even = false; + + // Run a standard deviation filter on the cube + string inFile = ui.GetFilename("FROM"); + string outFile = name + ".step1.cub"; + string parameters = "FROM=" + inFile + " TO=" + outFile + + " toldef=stddev flattol=10 samp=3 line=3 minimum=5 tolmin=2.5 tolmax=2.5" + + " replace=null"; + Isis::iApp ->Exec("noisefilter",parameters); + + // Run a lowpass filter on the cube + inFile = outFile; + outFile = name + ".step2.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " filter=outside line=3 samp=3 minimum=5"; + Isis::iApp ->Exec("lowpass",parameters); + if (rmv) remove(inFile.c_str()); + + // Run mask on the cube with the correct masking cube + inFile = outFile; + outFile = name + ".step3.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " MASK=$ISIS3DATA/viking" + iString(spn) + "/calibration/vik" + iString(spn); + if (even) parameters += "evenMask.cub"; + else parameters += "oddMask.cub"; + Isis::iApp ->Exec("mask",parameters); + if (rmv) remove(inFile.c_str()); + + // Run a low pass filter on the invalid data in the cube + inFile = outFile; + outFile = name + ".step4.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " samp=3 line=3 filter=outside replace=null"; + Isis::iApp ->Exec("lowpass",parameters); + if (rmv) remove(inFile.c_str()); + + // Run a lowpass filter on the cube + inFile = outFile; + outFile = name + ".step5.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " filter=outside samp=7 line=7 replace=null"; + Isis::iApp ->Exec("lowpass",parameters); + if (rmv) remove(inFile.c_str()); + + // Run a lowpass filter on the cube + inFile = outFile; + outFile = name + ".step6.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " filter=outside line=11 samp=11 replace=null"; + Isis::iApp ->Exec("lowpass",parameters); + if (rmv) remove(inFile.c_str()); + + inFile = outFile; + outFile = ui.GetFilename("TO"); + parameters = "FROM=" + inFile + " TO=" + outFile + + " bottom=20 top=25 left=30 right=30"; + Isis::iApp ->Exec("trim",parameters); + if (rmv) remove(inFile.c_str()); +} + diff --git a/isis/src/viking/apps/viknobutter/viknobutter.xml b/isis/src/viking/apps/viknobutter/viknobutter.xml new file mode 100644 index 0000000000000000000000000000000000000000..0b7b940a310c33280081f0e07f08fa1c7227321c --- /dev/null +++ b/isis/src/viking/apps/viknobutter/viknobutter.xml @@ -0,0 +1,120 @@ + + + + + Final step of Viking Orbiter Level 1 image clean-up + + + + This program will perform the final level 1 clean up processing sequence + on a Viking Orbiter PDS image to remove butterflies from the image. + + + + Viking + + + + + vikfixtrx + findrx + remrx + vikclean + + + + + + Original version + + + Added Examples + + + + + + + cube + input + + Input file to be cleaned + + + The cube to be cleaned. The cube will be ran through a series of filters to + remove butterflies from the image. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the cleaned data. + + + *.cub + + + + + + boolean + + Remove intermediate files + + + Option to remove or leave intermediate cube files made by the application + + TRUE + + + + + + + Input Viking Image to have butterflies removed + + This example shows the viknobutter application in action. It removes all butterflies from the image. + + + from=../IN/temp.cub to=OUT/out.cub + + + Input a viking image to remove butterflies from and give it an output file name. + + + + + + Viking Image to Remove Butterflies from + + This is the input viking image prior to the removal of butterflies. + + + FROM + + + + + + Output Image + + This is the viking image after the viknobutter application has been run. + + + TO + + + + + + + diff --git a/isis/src/viking/apps/viknonoodle/Makefile b/isis/src/viking/apps/viknonoodle/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/viking/apps/viknonoodle/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/viking/apps/viknonoodle/tsts/Makefile b/isis/src/viking/apps/viknonoodle/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/viking/apps/viknonoodle/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/viking/apps/viknonoodle/tsts/default/Makefile b/isis/src/viking/apps/viknonoodle/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..739bc0b7d1bf4aec11ddebfa5a0e8ddbd3074e2d --- /dev/null +++ b/isis/src/viking/apps/viknonoodle/tsts/default/Makefile @@ -0,0 +1,7 @@ +APPNAME = viknonoodle + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/test.cub \ + to=$(OUTPUT)/viknonoodleTruth.cub > /dev/null; diff --git a/isis/src/viking/apps/viknonoodle/viknonoodle.cpp b/isis/src/viking/apps/viknonoodle/viknonoodle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..41f73c9bd9efe09abe46f953f0ad145913f05ed5 --- /dev/null +++ b/isis/src/viking/apps/viknonoodle/viknonoodle.cpp @@ -0,0 +1,161 @@ +#include "Isis.h" +#include +#include "FourierTransform.h" +#include "ProcessByLine.h" +#include "Statistics.h" + +using namespace std; +using namespace Isis; + +void removeNoise (Buffer &in, Buffer &out); +void clean(std::vector< std::complex > &transformed); +int findExtreme(std::vector< std::complex > data); + +FourierTransform fft; + +double tolerance = 0.5; + +void IsisMain() +{ + ProcessByLine p; + + // Setup the input and output cubes + p.SetInputCube("FROM"); + p.SetOutputCube("TO"); + + tolerance = Isis::Application::GetUserInterface().GetDouble("TOLERANCE"); + + // Start the sample processing + p.StartProcess( removeNoise ); + p.EndProcess(); +} + +void removeNoise (Buffer &in, Buffer &out) { + // if we are not near the location of the noise, + // copy the input data over to the output cube + if((in.Line() > 100 && in.Line() < 900) || in.Line() >1100){ + for (int i=0; i > line(length); + + // the last pixel of the second interval + index2 = index2-line.size() + 1; + + // copy the input cube's data into the complex vector + // for the first interval + for (int i=0; i(in[i+index1]-average); + } + + // run a fourier transform on it + std::vector< std::complex > transform1 = fft.Transform(line); + + // copy the input cube's data into the complex vector + for (int i=0; i(in[i+index2]-average); + } + + // run a fourier transform on it + std::vector< std::complex > transform2 = fft.Transform(line); + + // and clean up the noise + clean(transform1); + clean(transform2); + + // now invert the transformed data + std::vector< std::complex > inverse1 = fft.Inverse(transform1); + std::vector< std::complex > inverse2 = fft.Inverse(transform2); + + // copy the data + for (int i=0; i index1 + length - 1) { + out[i] = inverse2[i-index2].real() + average; + } + // otherwise, use the average of both inverse arrays + else { + out[i] = ((index1+length-i)*real(inverse1[i-index1]) + (i-index2)*real(inverse2[i-index2]))/(index1+length-index2) + average; + } + } +} + +// clean the transformed data +void clean(std::vector< std::complex > &transformed) { + int n = transformed.size(); + + // find highest frequency + int index = findExtreme(transformed); + + // if noise is found, use a butterworth bandstop + // filter to remove it + if (abs( transformed[index] ) > tolerance) { + double d = index; // The cutoff + double dw = 10.0; // The bandwidth + int g = 1; // The order + double B; + + for (int i=0; i (polar(B*abs(transformed[i]), arg(transformed[i]))); + transformed[n-i-1] = std::complex (polar(B*abs(transformed[n-i-1]), arg(transformed[n-i-1]))); + } + } +} + +// Finds the largest or smallest value in the array +// not including the first value +int findExtreme(std::vector< std::complex > data) { + int index = 0; + double extreme = 0.0; + // the frequency we are looking for is around 10 + for (unsigned int i=8; i<13; i++) { + double value = abs(data[i]); + if (value > extreme) { + extreme = value; + index = i; + } + } + return index; +} diff --git a/isis/src/viking/apps/viknonoodle/viknonoodle.xml b/isis/src/viking/apps/viknonoodle/viknonoodle.xml new file mode 100644 index 0000000000000000000000000000000000000000..52408bf5494ce06210dea8192cc38bee4a4067a1 --- /dev/null +++ b/isis/src/viking/apps/viknonoodle/viknonoodle.xml @@ -0,0 +1,90 @@ + + + + Remove periodic noise from a Viking image + + + + VIKNONOODLE removes periodic noise, in the sample direction, from VIKING + images. The images should be run through LEVEL1 before VIKNONOODLE is + run on the images. This program is to be run before any cropping. For + best results, use trim to remove unwanted data from the sides first. No data + that lies between the two noise locations will be affected. + + + + Viking + + + + + fft + ifft + + + + + + Original version + + + Moved from base to viking area + + + Documentation fixes + + + Fixed boundary condition where vectors went out of bounds + + + + + + + cube + input + + Input file to apply VIKNONOODLE to. + + + The input cube with periodic noise in the sample direction. + + + *.cub + + + + + cube + real + output + + Output cube + + + The resultant cube with the noise removed. + + + *.cub + + + + + + + double + + Frequency magnitude tolerance level. + + + The tolerance parameter is used to specify how strong the frequency + must be to count as noise. The higher the tolerance level, the less likely + the frequency will be cleaned. However, if the tolerance is too low, it may + wipe out good data and some banding may occur around the noise location. + (Note: most noise frequencies have a magnitude greater than 1.0). + + 0.5 + + + + diff --git a/isis/src/viking/apps/viknopepper/Makefile b/isis/src/viking/apps/viknopepper/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/viking/apps/viknopepper/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/viking/apps/viknopepper/assets/image/inputImage.jpg b/isis/src/viking/apps/viknopepper/assets/image/inputImage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f66fd85df233fe4e1152562f12cda1d98b9505c7 Binary files /dev/null and b/isis/src/viking/apps/viknopepper/assets/image/inputImage.jpg differ diff --git a/isis/src/viking/apps/viknopepper/assets/image/outputImage.jpg b/isis/src/viking/apps/viknopepper/assets/image/outputImage.jpg new file mode 100755 index 0000000000000000000000000000000000000000..2ebfef76f03c6366a7e4574e74865cefb004567c Binary files /dev/null and b/isis/src/viking/apps/viknopepper/assets/image/outputImage.jpg differ diff --git a/isis/src/viking/apps/viknopepper/assets/thumb/inputImage.jpg b/isis/src/viking/apps/viknopepper/assets/thumb/inputImage.jpg new file mode 100755 index 0000000000000000000000000000000000000000..12687f3777ead576f426c52570feca6983e5a06c Binary files /dev/null and b/isis/src/viking/apps/viknopepper/assets/thumb/inputImage.jpg differ diff --git a/isis/src/viking/apps/viknopepper/assets/thumb/outputImage.jpg b/isis/src/viking/apps/viknopepper/assets/thumb/outputImage.jpg new file mode 100755 index 0000000000000000000000000000000000000000..ada1958f74a4773071154680c85d8ef9c5c08519 Binary files /dev/null and b/isis/src/viking/apps/viknopepper/assets/thumb/outputImage.jpg differ diff --git a/isis/src/viking/apps/viknopepper/tsts/Makefile b/isis/src/viking/apps/viknopepper/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/viking/apps/viknopepper/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/viking/apps/viknopepper/tsts/default/Makefile b/isis/src/viking/apps/viknopepper/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e1c5ceb79e3b02f7d97ac12ec51f3501165dca9f --- /dev/null +++ b/isis/src/viking/apps/viknopepper/tsts/default/Makefile @@ -0,0 +1,6 @@ +APPNAME = viknopepper + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/f348b26.cub to=$(OUTPUT)/viknopepperTruth.cub > /dev/null; diff --git a/isis/src/viking/apps/viknopepper/viknopepper.cpp b/isis/src/viking/apps/viknopepper/viknopepper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4f72a80afcaf8925d2c0ff5c81aae5db8da4d57f --- /dev/null +++ b/isis/src/viking/apps/viknopepper/viknopepper.cpp @@ -0,0 +1,55 @@ +#include "Isis.h" +#include "Application.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + + // Open the input cube + UserInterface &ui = Application::GetUserInterface(); + Filename fname = ui.GetFilename("FROM"); + string name = fname.Basename(); + bool rmv = ui.GetBoolean("REMOVE"); + + // Run a standard deviation filter on the cube + string inFile = ui.GetFilename("FROM"); + string outFile = name + ".step1.cub"; + string parameters = "FROM=" + inFile + " TO=" + outFile + + " toldef=stddev flattol=10 line=9 samp=9 minimum=9 tolmin=4.0 tolmax=4.0" + + " replace=null"; + Isis::iApp ->Exec("noisefilter",parameters); + + // Run a standard deviation filter on the cube + inFile = outFile; + outFile = name + ".step2.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " toldef=stddev flattol=10 line=3 samp=3 minimum=3 tolmin=3.5 tolmax=3.5"; + Isis::iApp ->Exec("noisefilter",parameters); + if (rmv) remove(inFile.c_str()); + + // Run a standard deviation filter on the cube + inFile = outFile; + outFile = name + ".step3.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " toldef=stddev flattol=10 samp=9 line=9 minimum=9 tolmin=4.0 tolmax=4.0" + + " replace=null"; + Isis::iApp ->Exec("noisefilter",parameters); + if (rmv) remove(inFile.c_str()); + + // Run a standard deviation filter on the cube + inFile = outFile; + outFile = name + ".step4.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " toldef=stddev samp=3 line=3 minimum=3 tolmin=3.5 tolmax=3.5"; + Isis::iApp ->Exec("noisefilter",parameters); + if (rmv) remove(inFile.c_str()); + + // Run a lowpass filter on the cube + inFile = outFile; + outFile = ui.GetFilename("TO"); + parameters = "FROM=" + inFile + " TO=" + outFile + + " filter=outside samp=3 line=3 minimum=5 replacement=null"; + Isis::iApp ->Exec("lowpass",parameters); + if (rmv) remove(inFile.c_str()); +} diff --git a/isis/src/viking/apps/viknopepper/viknopepper.xml b/isis/src/viking/apps/viknopepper/viknopepper.xml new file mode 100644 index 0000000000000000000000000000000000000000..59e5d07aed549e9ebe15874e81a5fb5862e992e7 --- /dev/null +++ b/isis/src/viking/apps/viknopepper/viknopepper.xml @@ -0,0 +1,121 @@ + + + + + Pepper noise Clean-up of Viking Orbiter Level 1 images + + + + This program will perform the middle portion of the level 1 processing sequence on a Viking + Orbiter PDS image, the cleanup of pepper noise in the image. + + + + Viking + + + + + vikfixtrx + viknosalt + viknobutter + remrx + findrx + + + + + + Original version + + + Added examples + + + + + + + cube + input + + Input file to be cleaned + + + The cube to be cleaned. The cube will be ran through a series of filters to + remove pepper noise. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the cleaned data. + + + *.cub + + + + + + boolean + + Remove intermediate files + + + Option to remove or leave intermediate cube files made by the application + + TRUE + + + + + + + Input Viking Image to have pepper noise removed + + This example shows the viknopepper application in action. It removes all pepper noise. + + + from=../IN/temp.cub to=OUT/out.cub + + + Input a viking image to remove the pepper noise from and give it an output file name. + + + + + + Viking Image to Remove Pepper Noise from + + This is the input viking image prior to the removal of black noise. + + + FROM + + + + + + Output Image + + This is the viking image after the viknopepper application has been run. + + + TO + + + + + + + + diff --git a/isis/src/viking/apps/viknosalt/Makefile b/isis/src/viking/apps/viknosalt/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/viking/apps/viknosalt/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/viking/apps/viknosalt/assets/image/inputImage.jpg b/isis/src/viking/apps/viknosalt/assets/image/inputImage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f66fd85df233fe4e1152562f12cda1d98b9505c7 Binary files /dev/null and b/isis/src/viking/apps/viknosalt/assets/image/inputImage.jpg differ diff --git a/isis/src/viking/apps/viknosalt/assets/image/outputImage.jpg b/isis/src/viking/apps/viknosalt/assets/image/outputImage.jpg new file mode 100755 index 0000000000000000000000000000000000000000..4827a78be1c567c1974005639a93c0aedb67f834 Binary files /dev/null and b/isis/src/viking/apps/viknosalt/assets/image/outputImage.jpg differ diff --git a/isis/src/viking/apps/viknosalt/assets/thumb/inputImage.jpg b/isis/src/viking/apps/viknosalt/assets/thumb/inputImage.jpg new file mode 100755 index 0000000000000000000000000000000000000000..12687f3777ead576f426c52570feca6983e5a06c Binary files /dev/null and b/isis/src/viking/apps/viknosalt/assets/thumb/inputImage.jpg differ diff --git a/isis/src/viking/apps/viknosalt/assets/thumb/outputImage.jpg b/isis/src/viking/apps/viknosalt/assets/thumb/outputImage.jpg new file mode 100755 index 0000000000000000000000000000000000000000..4b4c1fecb32615dd9b977be3c85ab347f0d15953 Binary files /dev/null and b/isis/src/viking/apps/viknosalt/assets/thumb/outputImage.jpg differ diff --git a/isis/src/viking/apps/viknosalt/tsts/Makefile b/isis/src/viking/apps/viknosalt/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/viking/apps/viknosalt/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/viking/apps/viknosalt/tsts/default/Makefile b/isis/src/viking/apps/viknosalt/tsts/default/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6bee9c74a4fde13461c60a7c9ac0a17aa2c490e1 --- /dev/null +++ b/isis/src/viking/apps/viknosalt/tsts/default/Makefile @@ -0,0 +1,9 @@ +APPNAME = viknosalt + +# 3.0 +viknosaltTruth.cub.TOLERANCE = 3.1 + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/f387a06.cub to=$(OUTPUT)/viknosaltTruth.cub > /dev/null; diff --git a/isis/src/viking/apps/viknosalt/viknosalt.cpp b/isis/src/viking/apps/viknosalt/viknosalt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..59ef8a4a777e4bd010d7e78e478d3000af4b94a9 --- /dev/null +++ b/isis/src/viking/apps/viknosalt/viknosalt.cpp @@ -0,0 +1,77 @@ +#include "Isis.h" +#include "Application.h" + +using namespace std; +using namespace Isis; + +void IsisMain() { + + // Open the input cube + UserInterface &ui = Application::GetUserInterface(); + Filename fname = ui.GetFilename("FROM"); + string name = fname.Basename(); + bool rmv = ui.GetBoolean("REMOVE"); + + // Trim the edges of the cube + string inFile = ui.GetFilename("FROM"); + string outFile = name + ".step1.cub"; + string parameters = "FROM=" + inFile + " TO=" + outFile + + " top=1 left=1 right=1"; + Isis::iApp ->Exec("trim",parameters); + + // Run a trimfilter on the cube + inFile = outFile; + outFile = name + ".step2.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + " samp=3 line=3 minimum=3"; + Isis::iApp ->Exec("trimfilter",parameters); + if (rmv) remove(inFile.c_str()); + + // Run a standard deviation filter on the cube + inFile = outFile; + outFile = name + ".step3.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " toldef=stddev samp=3 line=3 minimum=3 tolmin=100 tolmax=3.0"; + Isis::iApp ->Exec("noisefilter",parameters); + if (rmv) remove(inFile.c_str()); + + // Run a noise filter on the cube + inFile = outFile; + outFile = name + ".step4.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " samp=3 line=3 minimum=2 tolmin=300 tolmax=100"; + Isis::iApp ->Exec("noisefilter",parameters); + if (rmv) remove(inFile.c_str()); + + // Run a second noise filter on the cube + inFile = outFile; + outFile = name + ".step5.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " samp=3 line=3 minimum=2 tolmin=300 tolmax=60"; + Isis::iApp ->Exec("noisefilter",parameters); + if (rmv) remove(inFile.c_str()); + + // Run a second standard deviation filter on the cube + inFile = outFile; + outFile = name + ".step6.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " toldef=stddev samp=3 line=3 minimum=7 tolmin=100 tolmax=2.0"; + Isis::iApp ->Exec("noisefilter",parameters); + if (rmv) remove(inFile.c_str()); + + // Run a third noise filter on the cube + inFile = outFile; + outFile = name + ".step7.cub"; + parameters = "FROM=" + inFile + " TO=" + outFile + + " samp=3 line=3 minimum=7 tolmin=300 tolmax=46"; + Isis::iApp ->Exec("noisefilter",parameters); + if (rmv) remove(inFile.c_str()); + + // Run a low pass filter on the invalid data in the cube + inFile = outFile; + outFile = ui.GetFilename("TO"); + parameters = "FROM=" + inFile + " TO=" + outFile + + " samp=3 line=3 minimum=2 filter=outside null=true lis=true his=true lrs=true"; + Isis::iApp ->Exec("lowpass",parameters); + if (rmv) remove(inFile.c_str()); +} + diff --git a/isis/src/viking/apps/viknosalt/viknosalt.xml b/isis/src/viking/apps/viknosalt/viknosalt.xml new file mode 100644 index 0000000000000000000000000000000000000000..c87ed36f37c5ea5c675045745f546579c6fba3b6 --- /dev/null +++ b/isis/src/viking/apps/viknosalt/viknosalt.xml @@ -0,0 +1,120 @@ + + + + + Initial Clean-up of Viking Orbiter Level 1 images + + + + This program will perform the first portion of the level 1 processing sequence on a Viking + Orbiter PDS image, the cleanup of salt noise in the image. + + + + Viking + + + + + vikfixtrx + viknopepper + + + + + + Original version + + + Fixed lowpass command (parameters were modified) + + + Added example + + + + + + + cube + input + + Input file to be cleaned + + + The cube to be cleaned. The cube will be ran through a series of filters to + remove salt noise. + + + *.cub + + + + + cube + output + + Output cube + + + The resultant cube containing the cleaned data. + + + *.cub + + + + + + boolean + + Remove intermediate files + + + Option to remove or leave intermediate cube files made by the application + + TRUE + + + + + + + Input Viking Image to have salt noise removed + + This example shows the viknosalt application in action. It removes all salt noise from the image. + + + from=../IN/temp.cub to=OUT/out.cub + + + Input a viking image to remove salt noise from and give it an output file name. + + + + + + Viking Image to Remove Salt Noise from + + This is the input viking image prior to the removal of white noise. + + + FROM + + + + + + Output Image + + This is the viking image after the viknosalt application has been run. + + + TO + + + + + + + diff --git a/isis/src/viking/objs/Makefile b/isis/src/viking/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/viking/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/src/viking/objs/VikingCamera/Camera.plugin b/isis/src/viking/objs/VikingCamera/Camera.plugin new file mode 100644 index 0000000000000000000000000000000000000000..3aa2ab29728fbc0134289dc78f0379e87bad37f1 --- /dev/null +++ b/isis/src/viking/objs/VikingCamera/Camera.plugin @@ -0,0 +1,21 @@ +Group = VIKING_ORBITER_1/VISUAL_IMAGING_SUBSYSTEM_CAMERA_A + Version = 1 + Library = VikingCamera + Routine = VikingCameraPlugin +EndGroup +Group = VIKING_ORBITER_1/VISUAL_IMAGING_SUBSYSTEM_CAMERA_B + Version = 1 + Library = VikingCamera + Routine = VikingCameraPlugin +EndGroup +Group = VIKING_ORBITER_2/VISUAL_IMAGING_SUBSYSTEM_CAMERA_A + Version = 1 + Library = VikingCamera + Routine = VikingCameraPlugin +EndGroup +Group = VIKING_ORBITER_2/VISUAL_IMAGING_SUBSYSTEM_CAMERA_B + Version = 1 + Library = VikingCamera + Routine = VikingCameraPlugin +EndGroup + diff --git a/isis/src/viking/objs/VikingCamera/Makefile b/isis/src/viking/objs/VikingCamera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2d33efd23c1b76b6fb9a3db44659340ee872a9fa --- /dev/null +++ b/isis/src/viking/objs/VikingCamera/Makefile @@ -0,0 +1,5 @@ +INCS = VikingCamera.h +SRCS = VikingCamera.cpp +OBJS = $(SRCS:%.cpp=%.o) + +include $(ISISROOT)/make/isismake.objs diff --git a/isis/src/viking/objs/VikingCamera/VikingCamera.cpp b/isis/src/viking/objs/VikingCamera/VikingCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..14a080fb37c43850bbb62fe36d2f6cb0c9800680 --- /dev/null +++ b/isis/src/viking/objs/VikingCamera/VikingCamera.cpp @@ -0,0 +1,155 @@ +/** + * @file + * $Revision: 1.6 $ + * $Date: 2009/12/28 21:37:00 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "VikingCamera.h" +#include "CameraDetectorMap.h" +#include "CameraFocalPlaneMap.h" +#include "ReseauDistortionMap.h" +#include "CameraGroundMap.h" +#include "CameraSkyMap.h" +#include "iString.h" +#include "naif/SpiceUsr.h" +#include "naif/SpiceZfc.h" +#include "naif/SpiceZmc.h" +#include "Filename.h" + + +using namespace std; +namespace Isis { + /** + * Creates a Viking Camera Model + * + * @param lab Pvl Label from the image + * + * @throws Isis::iException::User - The file does not appear to be a viking image + */ + VikingCamera::VikingCamera (Pvl &lab) : FramingCamera(lab) { + // Set the pixel pitch + SetPixelPitch (1.0 / 85.0); + + // Find out what camera is being used, and set the focal length, altinstcode, + // raster orientation, cone, crosscone, and camera + PvlGroup inst = lab.FindGroup ("Instrument",Pvl::Traverse); + iString spacecraft = (string)inst["SPACECRAFTNAME"]; + iString instId = (string)inst["INSTRUMENTID"]; + string cam; + int spn; + double raster, cone, crosscone; + int altinstcode = 0; + if (spacecraft == "VIKING_ORBITER_1") { + spn=1; + altinstcode = -27999; + if (instId == "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A") { + cam = "1a"; + SetFocalLength(474.398); + crosscone = -0.707350; + cone = -0.007580; + raster = 89.735690; + } + else if (instId == "VISUAL_IMAGING_SUBSYSTEM_CAMERA_B") { + cam = "1b"; + SetFocalLength(474.448); + crosscone = 0.681000; + cone = -0.032000; + raster = 90.022800; + } + else { + string msg = "File does not appear to be a viking image"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + } + else if (spacecraft == "VIKING_ORBITER_2") { + spn=2; + altinstcode = -30999; + if (instId == "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A") { + cam = "2a"; + SetFocalLength(474.610); + crosscone = -0.679330; + cone = -0.023270; + raster = 89.880691; + } + else if (instId == "VISUAL_IMAGING_SUBSYSTEM_CAMERA_B") { + cam = "2b"; + SetFocalLength(474.101); + crosscone = 0.663000; + cone = -0.044000; + raster = 89.663790; + } + else { + string msg = "File does not appear to be a viking image"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + } + else { + string msg = "File does not appear to be a viking image"; + throw iException::Message(iException::User,msg, _FILEINFO_); + } + + // Get clock count and convert it to a time + string spacecraftClock = inst["SpacecraftClockCount"]; + double et, offset1; + scs2e_c(altinstcode, spacecraftClock.c_str(), &et); + + // Calculate and load the euler angles + SpiceDouble CP[3][3]; + eul2m_c ((SpiceDouble)raster*rpd_c(), (SpiceDouble)cone*rpd_c(), + (SpiceDouble)-crosscone*rpd_c(), 3, 2, 1, CP); + +// LoadEulerMounting(CP); + + double exposure_duration = inst["ExposureDuration"]; + if (exposure_duration <= .420) { + offset1 = 7.0 / 8.0 * 4.48; //4.48 seconds + } + else offset1 = 3.0 / 8.0 * 4.48; + double offset2 = 1.0 / 64.0 * 4.48; + + et += offset1 + offset2 + exposure_duration / 2.0; + + char timepds[25]; + et2utc_c(et,"ISOC",3,25,timepds); + utc2et_c(timepds,&et); + + // Setup detector map + new CameraDetectorMap(this); + + // Setup focal plane map, and detector origin + CameraFocalPlaneMap *focalMap = new CameraFocalPlaneMap(this,NaifIkCode()); + focalMap->SetDetectorOrigin(602.0,528.0); + + // Setup distortion map + const string fname = Filename("$viking" + iString(spn) + "/reseaus/vik" + cam + + "MasterReseaus.pvl").Expanded(); + new ReseauDistortionMap(this, lab, fname); + + // Setup the ground and sky map + new CameraGroundMap(this); + new CameraSkyMap(this); + + SetEphemerisTime(et); + LoadCache(); + } +} // end namespace isis + +extern "C" Isis::Camera *VikingCameraPlugin(Isis::Pvl &lab) { + return new Isis::VikingCamera(lab); +} diff --git a/isis/src/viking/objs/VikingCamera/VikingCamera.h b/isis/src/viking/objs/VikingCamera/VikingCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..8fec396e46f7641abcc2a8d0cdbb7710904b4754 --- /dev/null +++ b/isis/src/viking/objs/VikingCamera/VikingCamera.h @@ -0,0 +1,61 @@ +#ifndef VikingCamera_h +#define VikingCamera_h +/** + * @file + * $Revision: 1.3 $ + * $Date: 2009/08/31 15:12:32 $ + * + * Unless noted otherwise, the portions of Isis written by the USGS are public + * domain. See individual third-party library and package descriptions for + * intellectual property information,user agreements, and related information. + * + * Although Isis has been used by the USGS, no warranty, expressed or implied, + * is made by the USGS as to the accuracy and functioning of such software + * and related material nor shall the fact of distribution constitute any such + * warranty, and no responsibility is assumed by the USGS in connection + * therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see + * the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ + +#include "FramingCamera.h" + +namespace Isis { + /** + * @brief Viking Camera Model + * + * This is the camera model for both viking orbiter 1 and viking orbiter 2, + * both cameras A and B. + * + * @ingroup SpiceInstrumentsAndCameras + * @ingroup Viking + * + * @author 2005-06-09 Elizabeth Ribelin + * + * @internal + * @history 2005-11-15 Elizabeth Miller - Fixed problems caused by viking + * data area split + * @history 2006-05-17 Elizabeth Miller - Depricated CameraManager to + * CameraFactory + * @history 2006-06-14 Elizabeth Miller - Changed format of unitTest to + * fix problems with minor naif + * changes + * @history 2008-08-08 Steven Lambright Now using the new LoadCache(...) + * method instead of CreateCache(...). + * @history 2009-08-28 Steven Lambright - Changed inheritance to no + * longer inherit directly from Camera + */ + class VikingCamera : public Isis::FramingCamera { + public: + VikingCamera (Isis::Pvl &lab); + + //! Destroys the VikingCamera Object + ~VikingCamera () {}; + }; +}; +#endif + diff --git a/isis/src/viking/objs/VikingCamera/VikingCamera.truth b/isis/src/viking/objs/VikingCamera/VikingCamera.truth new file mode 100644 index 0000000000000000000000000000000000000000..1ec323242120533f8cafb4a5f010f56457e00388 --- /dev/null +++ b/isis/src/viking/objs/VikingCamera/VikingCamera.truth @@ -0,0 +1,20 @@ +Unit Test for VikingCamera... +For upper left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For upper right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower left corner ... +DeltaSample = 0 +DeltaLine = 0 + +For lower right corner ... +DeltaSample = 0 +DeltaLine = 0 + +For center pixel position ... +Latitude OK +Longitude OK diff --git a/isis/src/viking/objs/VikingCamera/unitTest.cpp b/isis/src/viking/objs/VikingCamera/unitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e94002946ddb0681bbda27e10df3f0f19a02c582 --- /dev/null +++ b/isis/src/viking/objs/VikingCamera/unitTest.cpp @@ -0,0 +1,98 @@ +using namespace std; + +#include +#include +#include "Camera.h" +#include "CameraFactory.h" +#include "iException.h" +#include "Preference.h" + +void TestLineSamp(Isis::Camera *cam, double samp, double line); + +int main (void) +{ + Isis::Preference::Preferences(true); + + cout << "Unit Test for VikingCamera..." << endl; + /* VIKING: The lon difference tolerance was increased for this + * camera model test in order for it to pass on Gala. + */ + try{ + // These should be lat/lon at center of image. To obtain these numbers for a new cube/camera, + // set both the known lat and known lon to zero and copy the unit test output "Latitude off by: " + // and "Longitude off by: " values directly into these variables. + // double knownLat = -24.27445959155795; + // double knownLon = 180.6234165504677; + // new lat/lon values used due to change in LeastSquares class (this changes ReseauDistortionMap + double knownLat = -24.2744713106319; + double knownLon = 180.6234120834806; + + //Isis::Pvl p("$mgs/testData/lub0428b.cub"); + Isis::Pvl p("$viking2/testData/f348b26.cub"); + Isis::Camera *cam = Isis::CameraFactory::Create(p); + cout << setprecision(9); + + // Test all four corners to make sure the conversions are right + cout << "For upper left corner ..." << endl; + TestLineSamp(cam, 1.0, 1.0); + + cout << "For upper right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), 1.0); + + cout << "For lower left corner ..." << endl; + TestLineSamp(cam, 1.0, cam->Lines()); + + cout << "For lower right corner ..." << endl; + TestLineSamp(cam, cam->Samples(), cam->Lines()); + + double samp = cam->Samples() / 2; + double line = cam->Lines() / 2; + cout << "For center pixel position ..." << endl; + + if(!cam->SetImage(samp,line)) { + std::cout << "ERROR" << std::endl; + return 0; + } + + // changed tolerance to allow hiclops to pass + if(abs(cam->UniversalLatitude() - knownLat) < 1.18E-05) { + cout << "Latitude OK" << endl; + } + else { + cout << setprecision(16) << "Latitude off by: " << cam->UniversalLatitude() - knownLat << endl; + } + + // changed tolerance to allow hiclops to pass + if(abs(cam->UniversalLongitude() - knownLon) < 4.47E-6) { + cout << "Longitude OK" << endl; + } + else { + cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl; + } + } + catch (Isis::iException &e) { + e.Report(); + } +} + +void TestLineSamp(Isis::Camera *cam, double samp, double line) { + bool success = cam->SetImage(samp,line); + + if(success) { + success = cam->SetUniversalGround(cam->UniversalLatitude(), cam->UniversalLongitude()); + } + + if(success) { + double deltaSamp = samp - cam->Sample(); + double deltaLine = line - cam->Line(); + if (fabs(deltaSamp) < 0.001) deltaSamp = 0; + if (fabs(deltaLine) < 0.001) deltaLine = 0; + cout << "DeltaSample = " << deltaSamp << endl; + cout << "DeltaLine = " << deltaLine << endl << endl; + } + else { + cout << "DeltaSample = ERROR" << endl; + cout << "DeltaLine = ERROR" << endl << endl; + } +} + diff --git a/isis/src/voyager/Makefile b/isis/src/voyager/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c6e21c5da5bce6b5e64b59d61881a7689c12decd --- /dev/null +++ b/isis/src/voyager/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.cat diff --git a/isis/src/voyager/apps/Makefile b/isis/src/voyager/apps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..381219893122eb5737084b3de80de2bd2d298df6 --- /dev/null +++ b/isis/src/voyager/apps/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.appstree diff --git a/isis/src/voyager/apps/voy2isis/Makefile b/isis/src/voyager/apps/voy2isis/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/src/voyager/apps/voy2isis/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/src/voyager/apps/voy2isis/assets/images/output.jpg b/isis/src/voyager/apps/voy2isis/assets/images/output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68c25cd9e02981b6af1b4551d99a445ab94fa6c1 Binary files /dev/null and b/isis/src/voyager/apps/voy2isis/assets/images/output.jpg differ diff --git a/isis/src/voyager/apps/voy2isis/assets/images/voy2isisGUI.jpg b/isis/src/voyager/apps/voy2isis/assets/images/voy2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6f1e10e617b7a12a1a0736de8a800699ddc7a0ae Binary files /dev/null and b/isis/src/voyager/apps/voy2isis/assets/images/voy2isisGUI.jpg differ diff --git a/isis/src/voyager/apps/voy2isis/assets/output.pvl b/isis/src/voyager/apps/voy2isis/assets/output.pvl new file mode 100644 index 0000000000000000000000000000000000000000..956df470e978c515a07b00eb51cbcbaaeafd003d --- /dev/null +++ b/isis/src/voyager/apps/voy2isis/assets/output.pvl @@ -0,0 +1,139 @@ +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 128 + TileLines = 128 + + Group = Dimensions + Samples = 800 + Lines = 800 + Bands = 1 + End_Group + + Group = Pixels + Type = UnsignedByte + ByteOrder = Lsb + Base = 0.0 + Multiplier = 1.0 + End_Group + End_Object + + Group = Instrument + SpacecraftClockCount = 18563.06 + SpacecraftName = VOYAGER_2 + TargetName = Jupiter + StartTime = 1979-05-01T01:23:16Z + InstrumentId = NARROW_ANGLE_CAMERA + ScanModeId = 1:1 + ShutterModeId = NAONLY + GainModeId = LOW + EditModeId = 1:1 + ExposureDuration = 0.24 + End_Group + + Group = Archive + MissionPhaseName = JUPITER_ENCOUNTER + ProductId = 0219J2-070 + End_Group + + Group = BandBin + FilterName = GREEN + FilterNumber = 5 + End_Group + + Group = Kernels + NaifFrameCode = -32001 + End_Group + + Group = Reseaus + Line = (12.6, 7.0, 4.0, -1.2, -4.6, -6.3, -8.0, -8.6, -8.9, -8.2, + -10.0, -3.2, 22.9, 26.0, 22.0, 18.0, 17.0, 15.0, 14.0, 13.0, + 13.0, 14.0, 8.0, 58.0, 55.1, 51.0, 48.0, 46.0, 44.0, 43.0, + 42.0, 41.0, 41.0, 43.0, 44.0, 94.0, 90.0, 88.0, 85.0, 84.0, + 82.0, 81.0, 81.0, 80.0, 81.0, 81.0, 131.9, 130.0, 118.7, + 120.0, 169.9, 167.1, 164.8, 164.0, 161.8, 160.7, 159.9, + 160.0, 158.5, 159.0, 159.0, 208.5, 208.0, 197.6, 197.6, + 247.6, 245.5, 243.8, 242.6, 241.6, 240.6, 239.9, 239.2, + 238.4, 237.7, 237.3, 286.8, 286.0, 277.2, 276.7, 326.4, + 324.7, 323.3, 322.3, 321.5, 320.6, 320.0, 319.3, 318.5, + 317.5, 316.9, 366.0, 365.2, 357.0, 356.5, 405.6, 404.2, + 403.0, 402.1, 401.3, 400.6, 399.9, 399.1, 398.3, 397.4, + 396.4, 445.2, 444.6, 436.4, 435.6, 485.0, 483.7, 482.8, + 481.9, 481.1, 480.4, 479.6, 478.9, 478.0, 476.8, 475.5, + 524.4, 524.2, 515.6, 514.6, 564.4, 563.3, 562.4, 561.6, + 560.8, 560.0, 559.3, 558.4, 557.4, 556.0, 554.3, 603.5, + 603.5, 593.0, 592.6, 643.1, 642.5, 641.0, 641.0, 640.2, + 638.0, 637.0, 636.0, 635.0, 634.4, 630.0, 682.0, 682.0, + 671.0, 669.3, 720.6, 720.9, 720.0, 719.0, 718.0, 717.0, + 716.0, 714.0, 712.0, 710.0, 706.0, 757.7, 759.1, 758.0, + 758.0, 757.0, 756.0, 755.0, 753.0, 752.0, 750.0, 746.0, + 743.4, 795.4, 787.0, 787.0, 786.0, 785.0, 784.0, 783.0, + 782.0, 780.0, 776.0, 778.0, 804.0, 810.7, 808.5, 808.5, + 808.0, 807.4, 806.1, 805.0, 801.0, 798.0, 798.5, 787.0, 120.0) + Sample = (0.4, 44.0, 119.0, 199.9, 278.0, 356.1, 433.9, 511.6, 588.5, + 664.1, 737.1, 784.4, 6.0, 81.0, 158.0, 236.0, 314.0, 393.0, + 471.0, 549.9, 626.3, 702.0, 772.0, -5.8, 43.0, 120.0, 199.0, + 276.0, 355.0, 433.0, 512.0, 589.0, 666.0, 740.0, 792.0, 15.0, + 81.0, 159.0, 238.0, 317.0, 395.0, 474.0, 551.0, 629.0, 705.0, + 769.0, -4.6, 43.0, 744.1, 793.0, 15.3, 82.3, 159.0, 238.0, + 318.1, 396.7, 475.2, 553.3, 631.0, 707.7, 773.5, -5.3, 43.0, + 746.8, 795.7, 15.3, 82.4, 160.8, 239.0, 318.0, 397.4, 475.9, + 554.3, 632.3, 709.6, 775.7, -5.1, 43.9, 748.7, 797.8, 15.6, + 82.9, 161.3, 240.1, 319.0, 397.8, 476.4, 555.0, 633.2, 710.9, + 777.5, -4.6, 44.4, 749.8, 799.3, 16.4, 83.4, 161.7, 240.4, + 319.3, 398.1, 476.9, 555.5, 633.8, 711.7, 778.5, -3.8, 45.3, + 750.4, 801.8, 17.5, 84.4, 162.3, 240.9, 319.7, 398.4, 477.2, + 555.9, 634.3, 712.3, 779.2, -2.3, 46.4, 751.0, 799.8, 19.0, + 85.4, 163.0, 241.4, 320.0, 398.9, 477.5, 556.4, 634.7, 712.7, + 779.4, -0.5, 48.0, 752.0, 800.0, 21.3, 86.9, 163.9, 242.0, + 320.6, 401.0, 479.0, 558.0, 636.0, 712.7, 778.0, 2.6, 50.4, + 752.0, 799.5, 26.0, 89.2, 166.0, 243.0, 322.0, 401.0, 480.0, + 559.0, 637.0, 714.0, 778.0, 4.5, 54.0, 129.0, 206.0, 284.0, + 362.0, 441.0, 519.0, 598.0, 675.0, 751.0, 800.0, 22.2, 93.0, + 168.0, 245.0, 323.0, 402.0, 481.0, 559.0, 637.0, 713.0, + 785.0, 11.0, 56.6, 129.6, 205.8, 283.3, 361.5, 439.8, 518.3, + 599.0, 675.6, 748.7, 794.0, 591.0) + Type = (5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 0, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, + 5, 5) + Valid = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0) + Template = $voyager2/reseaus/vg2.issna.template.cub + Status = Nominal + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = History + Name = IsisCube + StartByte = 868353 + Bytes = 475 +End_Object + +Object = OriginalLabel + Name = IsisCube + StartByte = 868828 + Bytes = 2039 +End_Object +End diff --git a/isis/src/voyager/apps/voy2isis/assets/thumbs/output.jpg b/isis/src/voyager/apps/voy2isis/assets/thumbs/output.jpg new file mode 100644 index 0000000000000000000000000000000000000000..137845d183085a962f72ad6bde112f528b9f878f Binary files /dev/null and b/isis/src/voyager/apps/voy2isis/assets/thumbs/output.jpg differ diff --git a/isis/src/voyager/apps/voy2isis/assets/thumbs/voy2isisGUI.jpg b/isis/src/voyager/apps/voy2isis/assets/thumbs/voy2isisGUI.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1cdbce7ad4064f4632d696c1cbc71796b24916b0 Binary files /dev/null and b/isis/src/voyager/apps/voy2isis/assets/thumbs/voy2isisGUI.jpg differ diff --git a/isis/src/voyager/apps/voy2isis/tsts/Makefile b/isis/src/voyager/apps/voy2isis/tsts/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46d84c74c297304e943452a44e06b111f179a92b --- /dev/null +++ b/isis/src/voyager/apps/voy2isis/tsts/Makefile @@ -0,0 +1,4 @@ +BLANKS = "%-6s" +LENGTH = "%-40s" + +include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/voyager/apps/voy2isis/tsts/importIMQ/Makefile b/isis/src/voyager/apps/voy2isis/tsts/importIMQ/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d3cbf89e141b5901c27d8fc1ac6575dd8045efa9 --- /dev/null +++ b/isis/src/voyager/apps/voy2isis/tsts/importIMQ/Makefile @@ -0,0 +1,10 @@ +APPNAME = voy2isis + +c1856306.labels.txt.IGNORELINES = Bytes StartByte ByteOrder + +include $(ISISROOT)/make/isismake.tsts + +commands: + $(APPNAME) from=$(INPUT)/c1856306.imq \ + to=$(OUTPUT)/c1856306.truth.cub > /dev/null; + catlab from=$(OUTPUT)/c1856306.truth.cub >& $(OUTPUT)/c1856306.labels.pvl; diff --git a/isis/src/voyager/apps/voy2isis/voy2isis.cpp b/isis/src/voyager/apps/voy2isis/voy2isis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a26e91a9cf5fe060ba9e60b412c3529867248b3e --- /dev/null +++ b/isis/src/voyager/apps/voy2isis/voy2isis.cpp @@ -0,0 +1,365 @@ +#include "Isis.h" + +#include +#include +#include + +#include "Filename.h" +#include "iException.h" +#include "iString.h" +#include "NaifStatus.h" +#include "ProcessImportPds.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "PvlTranslationManager.h" +#include "System.h" +#include "UserInterface.h" + +#include "naif/SpiceUsr.h" + +#include +#include + +using namespace std; +using namespace Isis; + +void TranslateVoyagerLabels(Pvl &inputLabel, Cube *ocube); +void ConvertComments(Filename file); + +void IsisMain() { + // We should be processing a PDS file + ProcessImportPds p; + UserInterface &ui = Application::GetUserInterface(); + Filename in = ui.GetFilename("FROM"); + + string tempName = "$TEMPORARY/" + in.Basename() + ".img"; + Filename temp(tempName); + + bool tempFile = false; + + // input files are compressed, use vdcomp to decompress + iString ext = iString(in.Extension()).UpCase(); + if(ext == "IMQ") { + try { + string command = "$ISISROOT/bin/vdcomp " + in.Expanded() + " " + temp.Expanded(); + System(command); + in = temp.Expanded(); + ConvertComments(in); + tempFile = true; + } + catch(iException &e) { + throw iException::Message(iException::Io, + "Unable to decompress input file [" + + in.Name() + "].", _FILEINFO_); + } + } + else { + string msg = "Input file [" + in.Name() + + "] does not appear to be a Voyager EDR"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + // Convert the pds file to a cube + Pvl pdsLabel; + try { + p.SetPdsFile(in.Expanded(), "", pdsLabel); + } + catch(iException &e) { + string msg = "Unable to set PDS file. Decompressed input file [" + + in.Name() + "] does not appear to be a PDS product"; + throw iException::Message(iException::User, msg, _FILEINFO_); + } + + Cube *ocube = p.SetOutputCube("TO"); + p.StartProcess(); + TranslateVoyagerLabels(pdsLabel, ocube); + p.EndProcess(); + + if(tempFile) remove(temp.Expanded().c_str()); +} + +/** + * Converts / * Some comment + * to # Some comment + * without the extra space. + */ +void ConvertComments(Filename file) { + char tmp[10240]; + + for(unsigned int i = 0; i < sizeof(tmp) / sizeof(char); i++) + tmp[i] = '\0'; + + unsigned int lineStartPos = 0; + fstream stream; + iString filename = file.Expanded(); + stream.open(filename.c_str(), fstream::in | fstream::out | fstream::binary); + + lineStartPos = stream.tellg(); + stream.getline(tmp, sizeof(tmp) / sizeof(char)); + while(iString(tmp).find("END") != 0 && stream.good()) { + iString lineOfData(tmp); + + if(lineOfData.find("/*") != string::npos && + lineOfData.find("*/") == string::npos) { + lineOfData = lineOfData.substr(0, lineOfData.find("/*")) + "# " + + lineOfData.substr(lineOfData.find("/*") + 2); + stream.seekp(lineStartPos); + stream.write(lineOfData.c_str(), lineOfData.length()); + } + + lineStartPos = stream.tellg(); + stream.getline(tmp, sizeof(tmp) / sizeof(char)); + } + + stream.close(); +} + + +/** + * @brief Translate labels into Isis3 + * + * @param inputLabel Reference to pvl label from the input image + * @param ocube Pointer to output cube + * @internal + * @history 2009-03-11 Jeannie Walldren - Original Version + */ +void TranslateVoyagerLabels(Pvl &inputLabel, Cube *ocube) { + // Get the directory where the Voyager translation tables are + PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory"); + iString missionDir = (string) dataDir[(string)inputLabel["SpacecraftName"]]; + Filename transFile = (missionDir + "/translations/voyager.trn"); + + // Get the translation manager ready + PvlTranslationManager labelXlater(inputLabel, transFile.Expanded()); + + // Pvl output label + Pvl *outputLabel = ocube->Label(); + labelXlater.Auto(*(outputLabel)); + + // Add needed keywords that are not in the translation table + PvlGroup &inst = outputLabel->FindGroup("Instrument", Pvl::Traverse); + + + // Add units of measurement to keywords from translation table + double exposureDuration = inst.FindKeyword("ExposureDuration"); + inst.FindKeyword("ExposureDuration").SetValue(exposureDuration, "seconds"); + + // Setup the kernel group + PvlGroup kern("Kernels"); + iString spacecraftNumber; + int spacecraftCode = 0; + iString instId = (string) inst.FindKeyword("InstrumentId"); + if((string) inst.FindKeyword("SpacecraftName") == "VOYAGER_1") { + spacecraftNumber = "1"; + if(instId == "NARROW_ANGLE_CAMERA") { + spacecraftCode = -31101; + kern += PvlKeyword("NaifFrameCode", spacecraftCode); + instId = "issna"; + } + else { //if (instId == "WIDE_ANGLE_CAMERA") { + spacecraftCode = -31102; + kern += PvlKeyword("NaifFrameCode", spacecraftCode); + instId = "isswa"; + } + //else { + // string msg = "Instrument ID [" + instId + "] does not match Narrow or" + + // "Wide angle camera"; + // iException::Message(iException::User, msg, _FILEINFO_); + //} + } + else if((string) inst.FindKeyword("SpacecraftName") == "VOYAGER_2") { + spacecraftNumber = "2"; + if(instId == "NARROW_ANGLE_CAMERA") { + spacecraftCode = -32101; + kern += PvlKeyword("NaifFrameCode", spacecraftCode); + instId = "issna"; + } + else { //if (instId == "WIDE_ANGLE_CAMERA") { + spacecraftCode = -32102; + kern += PvlKeyword("NaifFrameCode", spacecraftCode); + instId = "isswa"; + } + //else { + // string msg = "Instrument ID [" + instId + "] does not match Narrow or" + + // "Wide angle camera"; + // iException::Message(iException::User, msg, _FILEINFO_); + //} + } + //else { + // string msg = "Spacecraft name [" + (string)inst.FindKeyword("SpacecraftName") + + // "] does not match Voyager1 or Voyager2 spacecraft"; + // iException::Message(iException::User, msg, _FILEINFO_); + //} + ocube->PutGroup(kern); + + // Modify time to remove Z from end + iString time = inst.FindKeyword("StartTime")[0]; + time.Remove("Z"); + inst.FindKeyword("StartTime").SetValue(time); + + // Fix image number - remove the period, if Wide angle camera and one of two + // shutter modes, we must fix the wide angle image number for use below. + // Before #####.## After ####### + iString imgNumber = inst["SpacecraftClockCount"][0]; + imgNumber.Replace(".", ""); + // Save this change + inst["SpacecraftClockCount"] = imgNumber; + + // From vgrfixlabel documentation in Isis2. + // Wide Angle (WA) images off of CD's will have a fake image + // number (NA image_number + scan_mode_id) written over the + // image_number label, which would have gotten the FSC count + // rather than the FSD count if a Narrow Angle was shuttered + // simultaneously. What I want is to figure out the NA image- + // number, which will allow me to find the shutter time (same + // for both NA & WA). So run backward, WA image_number - scan_ + // mode_id. + // If BSIMAN or BOTSIM and WA, go ahead. + if((inst["ShutterModeId"][0] == "BSIMAN" || + inst["ShutterModeId"][0] == "BOTSIM") && + inst["InstrumentId"][0] == "WIDE_ANGLE_CAMERA") { + iString scanId = inst["ScanModeId"][0]; + int scanNum = iString(scanId.substr(0, 1)).ToInteger(); + int imgNum = imgNumber.ToInteger(); + + // We'll use this later, however, we do not write it to the labels. + // if we didn't get in here, we'll be using the original image number, + // otherwise, we'll use this modified image number. + imgNumber = iString((imgNum - scanNum)); + } + + // This next section handles modifying the starttime slightly and requires + // the leapsecond kernel, the spacecraft clock kernel, and a correct + // spacecraft clock. + // This functionality was copied from Isis2 by Mackenzie Boyd, the + // documentation from Isis2 is here: (from vgrfixlabel.c) + /******************************************************************* + Get spacecraftClock from image FSC. + + Calculate the START_TIME keyword value from FSC to get fractional + seconds (PDS START_TIME provided is only to the nearest whole + second). The algorithm below was extracted from the NAIF + document Viking Orbiter Time Tag Analysis and Restoration by + Boris Semenov and Chuck Acton and was modified for Voyager by + Debbie Cook and K Teal Thompson. + + 1. Determine instCode, spacecraftCode. + Get FSC (FDS_COUNT) from IMAGE_NUMBER to use as + spacecraftClock. This was already done above when the + IMAGE_NUMBER was read into imagenum. + //Already accomplished above + + 2. Need to calc the image number for wide Angle images when + SHUTTER_MODE_ID = BOTSIM or BSIMAN because the IMAGE_NUMBER + on the labels is set to the readout count instead of the FDS + (FLIGHT DATA SUBSYSTEM) count. In the old code, SCAN_MODE_ID + is used to add to the image_number to get a new image_number + for WA. In this code, take WA image number and subtract + scan_mode id to get the narrow angle image_number. + // This is also accomplished above + + 3. Load a leap second kernel and the appropriate FSC spacecraft + clock kernel based on the spacecraft (Voyager 1 or Voyager + 2). Then convert image_number/spacecraftClock to et. + + + 4. Convert et to UTC calendar format and write to labels as + START_TIME + + + ********************************************************************/ + + // We've already handled a couple of the steps mentioned above. + NaifStatus::CheckErrors(); + //* 3 *// + // Leapsecond kernel + string lsk = "$ISIS3DATA/base/kernels/lsk/naif????.tls"; + Filename lskName(lsk); + lskName.HighestVersion(); + furnsh_c(lskName.Expanded().c_str()); + + // Spacecraft clock kernel + string sclk = "$ISIS3DATA/voyager"; + sclk.append(spacecraftNumber); + sclk.append("/kernels/sclk/vg"); + sclk.append(spacecraftNumber); + sclk.append("?????.tsc"); + Filename sclkName(sclk); + sclkName.HighestVersion(); + furnsh_c(sclkName.Expanded().c_str()); + + // The purpose of the next two steps, getting the spacecraft clock count, + // are simply to get get the partition, the very first number 1/... + double approxEphemeris = 0.0; + utc2et_c(inst["StartTime"][0].c_str(), &approxEphemeris); + char approxSpacecraftClock[80]; + + // sce2s_c requires the spacecraft number, not the instrument number as + // we've found elsewhere, either -31 or -32 in this case. + int spacecraftClockNumber = -30; + spacecraftClockNumber -= spacecraftNumber.ToInteger(); + sce2s_c(spacecraftClockNumber, approxEphemeris, 80, approxSpacecraftClock); + + /* + * For our next trick, we will substitute the image number we got earlier + * into this image number. The image number is in the format #######, + * 7 digits, our freshly gotten image number is in the form #/#####:##:## + * We want to save the first digit, before the /, and then substitute + * the previously found image number into the next 7 digits, keeping the colon, + * and then removing the last :## colon and two digits. Here goes. + * BTW, our imageNumber from above and this number may be identical, + * in which case this won't change anything in it. However, since the + * conversion from ET to spacecraftClock is a range of ETs all mapping to one + * clock count, even if we don't modifiy the spacecraft clock count, we'll + * come out with a slightly different starttime which is, in theory, more accurate. + * To rephrase, ETs are continuous, Spacecraft clock is discrete. For later + * we will use the Starttime, the ET, so we want it to match the spacecraft clock + * exactly. But, the original starttime holds valuable information... enough. + */ + + // Get first digit and the / + iString newClockCount = string(approxSpacecraftClock).substr(0, 2); + // Get first five digits of imgNumber and append + newClockCount.append(imgNumber.substr(0, 5)); + // I'll stop commenting now, you can read code as well as me + newClockCount.append(":"); + // I lied ;) get the last two digits. + newClockCount.append(imgNumber.substr(5, 2)); + + scs2e_c(spacecraftClockNumber, newClockCount.c_str(), &approxEphemeris); + + //* 4 *// + char utcOut[25]; + et2utc_c(approxEphemeris, "ISOC", 3, 26, utcOut); + NaifStatus::CheckErrors(); + inst["StartTime"].SetValue(iString(utcOut)); + + // Set up the nominal reseaus group + PvlGroup res("Reseaus"); + Pvl nomRes("$voyager" + spacecraftNumber + "/reseaus/nominal.pvl"); + PvlKeyword samps, lines, type, valid; + lines = PvlKeyword("Line"); + samps = PvlKeyword("Sample"); + type = PvlKeyword("Type"); + valid = PvlKeyword("Valid"); + + PvlKeyword key = nomRes.FindKeyword("VG" + spacecraftNumber + "_" + + instId.UpCase() + "_RESEAUS"); + int numRes = nomRes["VG" + spacecraftNumber + "_" + instId.UpCase() + + "_NUMBER_RESEAUS"]; + for(int i = 0; i < numRes * 3; i += 3) { + lines += key[i]; + samps += key[i+1]; + type += key[i+2]; + valid += 0; + } + res += lines; + res += samps; + res += type; + res += valid; + res += PvlKeyword("Template", "$voyager" + spacecraftNumber + "/reseaus/vg" + + spacecraftNumber + "." + instId.DownCase() + + ".template.cub"); + res += PvlKeyword("Status", "Nominal"); + ocube->PutGroup(res); +} + diff --git a/isis/src/voyager/apps/voy2isis/voy2isis.xml b/isis/src/voyager/apps/voy2isis/voy2isis.xml new file mode 100644 index 0000000000000000000000000000000000000000..4cd72ccb8f86aa6f1897bedd21d7f6d141b873e0 --- /dev/null +++ b/isis/src/voyager/apps/voy2isis/voy2isis.xml @@ -0,0 +1,161 @@ + + + + + + Import PDS formatted Voyager EDR into Isis format cube + + + + This program will take in raw image files from the Voyager spacecraft + mission and import them into Isis formatted cubes. The input files are + compressed Planetary Data System (PDS) formatted Voyager Experiment + Data Record (EDR) files. The output cube will contain tranlated labels in + pvl format with instrument, archive, bandbin, kernel, and nominal reseau + information. + + + + + Original version + + + Modified the Makefile in the app test to ignore particular lines when + comparing labels. Removed the orginal extension from the name of the + temporary decompressed file output by a call to vdcomp. Modified error + message for accuracy. + + + Modified StartTime in labels to remove Z from end. Modified naif frame + code for all cameras to be -100 (-32001 -> -32101) from what they were + previously to match updated ck and fk kernels. Added significant changes + which affect the start time and image number for improved accuracy. + + + Updated to make input IMQ's PVL labels parsable by our PVL classes + + + + + Voyager + + + + + + pds2isis + + + + + + Voyager ISS Main Page + + + + http://pds-rings.seti.org/voyager/iss/ + + Planetary Data System Rings Node + + + + Voyager ISS Raw Images + + + + http://pds-rings.seti.org/voyager/iss/raw_images.html/ + + Planetary Data System Rings Node + + + + + + + + + filename + input + + Input Voyager EDR image file + + + Use this parameter to select the Voyager PDS EDR file to be imported. + These files are in compressed format and have the form cnnnnnnn.imq + where "nnnnnnn" is the FDS count. + + + *.imq + + + + + cube + output + + Output Isis cube + + + Use this parameter to select the output filename for the imported + image. + + + *.cub + + + + + + + Using voy2isis + + This example shows the use of voy2isis to ingest Voyager EDRs and output + Isis3 cubes. + + + + from=input/voyagerEdr.imq to=isisImage.cub + + + This example shows how to import with voy2isis. Both parameters must + be used. + + + + + + + Example GUI + + + Screenshot of the GUI + + + + + + + + Output cube label + + This is the label from the output cube showing the Instrument, + BandBin, Kernels and Reseaus groups imported. + + TO + + + + + + Output after ingestion + + + Screenshot of the image in the Isis qview application after it has + been ingested. + + + + + + + diff --git a/isis/src/voyager/objs/Makefile b/isis/src/voyager/objs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..59557620183f7dd7697fa322e68819e8bad1884a --- /dev/null +++ b/isis/src/voyager/objs/Makefile @@ -0,0 +1 @@ +include $(ISISROOT)/make/isismake.objstree diff --git a/isis/templates/gui/Makefile b/isis/templates/gui/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1073858b3049adf5aa098730ca52ce1b59a45500 --- /dev/null +++ b/isis/templates/gui/Makefile @@ -0,0 +1,5 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:%.cpp=%.o) +BINS = $(shell basename `pwd`) + +include $(ISISROOT)/make/isismake.apps diff --git a/isis/templates/gui/basictemplate.xml b/isis/templates/gui/basictemplate.xml new file mode 100644 index 0000000000000000000000000000000000000000..de0db4af8bc4263dc896eefd62d3117cb2cf58ce --- /dev/null +++ b/isis/templates/gui/basictemplate.xml @@ -0,0 +1,40 @@ + + + + + A template xml file for basic tags + + + This is a template for the basic layout of the xml file. It contains no + parameters, only the necessary tags prior to the parameters. + + + + CategoryName + MissionName + + + + name in isis2 + + + + + related application name + typetemplate + listtemplate + + + + + + Original Version + + + Description of change made + + + + diff --git a/isis/templates/gui/comparisontemplate.xml b/isis/templates/gui/comparisontemplate.xml new file mode 100644 index 0000000000000000000000000000000000000000..d1043597d698131bdc77657d8ae6831d4c811915 --- /dev/null +++ b/isis/templates/gui/comparisontemplate.xml @@ -0,0 +1,97 @@ + + + + + A template gui for lists and inclusions/exclusions + + + The template gui illustrates the functionality of lists and inclusions and + exclusions. + + + + Utility + + + + + Original Version + + + + + + + + integer + + Value to take the square root of + + + The value to take the square root of. The value must be non-negative. + + 0 + + + + integer + + Value to take the factorial of + + + The value to compute the factorial of. The value must be smaller than + 65 in order to be computed. + + 65 + + + + + + + integer + + Minimum Pixel Value + + + The minimum value a pixel can have. It must be less than the maximum + pixel value. + + + MAXDN + + + + + integer + + Maximum Pixel Value + + + The maximum value a pixel can have. It must be greater than the + minimum pixel value. + + + MINDN + + + + + + + + integer + + Odd Number + + + This value must be an odd number. If an even number is entered, an + error will be returned. + + + + + + diff --git a/isis/templates/gui/defaulttemplate.cpp b/isis/templates/gui/defaulttemplate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..843b646f0211270b7e259498c711bbf09fb30cdd --- /dev/null +++ b/isis/templates/gui/defaulttemplate.cpp @@ -0,0 +1,24 @@ +... + +Isis::UserInterface &ui = Isis::Application::GetUserInterface(); + +std::cout << ui.GetInteger("INTEGER") << std::endl; + +if (ui.WasEntered("DOUBLE")) { + std::cout << ui.GetDouble("DOUBLE") << std::endl; +} +else { + double computed = 3.14; +} + +std::cout << ui.GetString("STRING") << std::endl; + +std::cout << ui.GetFilename("FILE") << std::endl; + +std::cout << ui.GetFilename("INPUTCUBE") << std::endl; + +if (ui.WasEntered("OUTPUTCUBE")) { + std::cout << ui.GetDouble("OUTPUTCUBE") << std::endl; +} + +... diff --git a/isis/templates/gui/defaulttemplate.xml b/isis/templates/gui/defaulttemplate.xml new file mode 100644 index 0000000000000000000000000000000000000000..da5f237c271a14fc4a19a08b19ece44c30e8bce7 --- /dev/null +++ b/isis/templates/gui/defaulttemplate.xml @@ -0,0 +1,126 @@ + + + + + A template gui of all types of defaults + + + The gui has an input area for each kind of input type with different types + of defaults. + + + + Utility + + + + + Original Version + + + + + + + + integer + + Input integer value + + + Input integer value for the application + + + 5 + + + + + double + + Input double value + + + Input double value for the application + + Computed + + + + string + + Input string parameter + + + Input string parameter for the application + + + String + + + + + boolean + + Boolean Option + + + Boolean input option + + + TRUE + + + + + + + + filename + input + + Input Filename + + + Input filename for the application + + + tempList.txt + + + + + cube + input + $base/testData/ + + Input Cube + + + Input cube parameter for the application + + + *.cub + + real + + + + cube + output + + Output Cube + + + Output cube parameter for the application + + + *.cub *.lbl + + None + + + + diff --git a/isis/templates/gui/listtemplate.xml b/isis/templates/gui/listtemplate.xml new file mode 100644 index 0000000000000000000000000000000000000000..2dd6044e4b0c10778dfaad0e9ce22061fc7de6fe --- /dev/null +++ b/isis/templates/gui/listtemplate.xml @@ -0,0 +1,108 @@ + + + + + A template gui for lists and inclusions/exclusions + + + The template gui illustrates the functionality of lists and inclusions and + exclusions. + + + + Utility + + + + + Original Version + + + + + + + + string + + List of possible options + + + List of possible options for the parameter + + + + + + + + NONE + + + + + + string + + Parameter needed for first option and both option + + + This parameter is only used for the first option and the both option. + + + + + double + + Parameter needed for second and both options + + + This parameter is used with the second and both options. + + + + + + diff --git a/isis/templates/gui/typetemplate.xml b/isis/templates/gui/typetemplate.xml new file mode 100644 index 0000000000000000000000000000000000000000..3b333a8434aff9d82754a73c666ba81ae16a041b --- /dev/null +++ b/isis/templates/gui/typetemplate.xml @@ -0,0 +1,107 @@ + + + + A template gui of all types of inputs + + + The gui has an input area for each kind of input type. + + + + Utility + + + + + Original Version + + + + + + + + integer + + Input + integer value + + + Input integer value for the application + + + + + double + + Input double value + + + Input double value for the application + + + + + string + + Input string parameter + + + Input string parameter for the application + + + + + boolean + + Boolean Option + + + Boolean input option + + + + + + + + filename + input + + Input Filename + + + Input filename for the application + + + + + cube + input + + Input Cube + + + Input cube parameter for the application + + + *.cub + + + + + cube + output + + Output Cube + + + Output cube parameter for the application + + + *.cub *.lbl + + + + +